diff --git a/Documentation/ABI/obsolete/proc-sys-vm-nr_pdflush_threads b/Documentation/ABI/obsolete/proc-sys-vm-nr_pdflush_threads
new file mode 100644
index 0000000..b0b0eeb
--- /dev/null
+++ b/Documentation/ABI/obsolete/proc-sys-vm-nr_pdflush_threads
@@ -0,0 +1,5 @@
+What:		/proc/sys/vm/nr_pdflush_threads
+Date:		June 2012
+Contact:	Wanpeng Li <liwp@linux.vnet.ibm.com>
+Description: Since pdflush is replaced by per-BDI flusher, the interface of old pdflush
+             exported in /proc/sys/vm/ should be removed.
diff --git a/Documentation/ABI/stable/sysfs-driver-w1_ds28e04 b/Documentation/ABI/stable/sysfs-driver-w1_ds28e04
new file mode 100644
index 0000000..26579ee
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-driver-w1_ds28e04
@@ -0,0 +1,15 @@
+What:		/sys/bus/w1/devices/.../pio
+Date:		May 2012
+Contact:	Markus Franke <franm@hrz.tu-chemnitz.de>
+Description:	read/write the contents of the two PIO's of the DS28E04-100
+		see Documentation/w1/slaves/w1_ds28e04 for detailed information
+Users:		any user space application which wants to communicate with DS28E04-100
+
+
+
+What:		/sys/bus/w1/devices/.../eeprom
+Date:		May 2012
+Contact:	Markus Franke <franm@hrz.tu-chemnitz.de>
+Description:	read/write the contents of the EEPROM memory of the DS28E04-100
+		see Documentation/w1/slaves/w1_ds28e04 for detailed information
+Users:		any user space application which wants to communicate with DS28E04-100
diff --git a/Documentation/ABI/testing/sysfs-block-rssd b/Documentation/ABI/testing/sysfs-block-rssd
index 679ce35..beef30c 100644
--- a/Documentation/ABI/testing/sysfs-block-rssd
+++ b/Documentation/ABI/testing/sysfs-block-rssd
@@ -1,26 +1,5 @@
-What:           /sys/block/rssd*/registers
-Date:           March 2012
-KernelVersion:  3.3
-Contact:        Asai Thambi S P <asamymuthupa@micron.com>
-Description:    This is a read-only file. Dumps below driver information and
-                hardware registers.
-                    - S ACTive
-                    - Command Issue
-                    - Completed
-                    - PORT IRQ STAT
-                    - HOST IRQ STAT
-                    - Allocated
-                    - Commands in Q
-
 What:           /sys/block/rssd*/status
 Date:           April 2012
 KernelVersion:  3.4
 Contact:        Asai Thambi S P <asamymuthupa@micron.com>
 Description:    This is a read-only file. Indicates the status of the device.
-
-What:           /sys/block/rssd*/flags
-Date:           May 2012
-KernelVersion:  3.5
-Contact:        Asai Thambi S P <asamymuthupa@micron.com>
-Description:    This is a read-only file. Dumps the flags in port and driver
-                data structure
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index cfedf63..a3774a7 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -40,9 +40,9 @@ Contact:	linux-iio@vger.kernel.org
 Description:
 		Some devices have internal clocks.  This parameter sets the
 		resulting sampling frequency.  In many devices this
-		parameter has an effect on input filters etc rather than
+		parameter has an effect on input filters etc. rather than
 		simply controlling when the input is sampled.  As this
-		effects datardy triggers, hardware buffers and the sysfs
+		effects data ready triggers, hardware buffers and the sysfs
 		direct access interfaces, it may be found in any of the
 		relevant directories.  If it effects all of the above
 		then it is to be found in the base device directory.
@@ -74,7 +74,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_raw
 KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
 Description:
-		Raw (unscaled no bias removal etc) voltage measurement from
+		Raw (unscaled no bias removal etc.) voltage measurement from
 		channel Y. In special cases where the channel does not
 		correspond to externally available input one of the named
 		versions may be used. The number must always be specified and
@@ -118,11 +118,11 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_temp_z_raw
 KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
 Description:
-		Raw (unscaled no bias removal etc) temperature measurement.
+		Raw (unscaled no bias removal etc.) temperature measurement.
 		If an axis is specified it generally means that the temperature
 		sensor is associated with one part of a compound device (e.g.
 		a gyroscope axis). Units after application of scale and offset
-		are milli degrees Celsuis.
+		are milli degrees Celsius.
 
 What:		/sys/bus/iio/devices/iio:deviceX/in_tempX_input
 KernelVersion:	2.6.38
@@ -148,10 +148,9 @@ KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
 Description:
 		Angular velocity about axis x, y or z (may be arbitrarily
-		assigned) Data converted by application of offset then scale to
-		radians per second. Has all the equivalent parameters as
-		per voltageY. Units after application of scale and offset are
-		radians per second.
+		assigned). Has all the equivalent parameters as	per voltageY.
+		Units after application of scale and offset are	radians per
+		second.
 
 What:		/sys/bus/iio/devices/iio:deviceX/in_incli_x_raw
 What:		/sys/bus/iio/devices/iio:deviceX/in_incli_y_raw
@@ -161,7 +160,7 @@ Contact:	linux-iio@vger.kernel.org
 Description:
 		Inclination raw reading about axis x, y or z (may be
 		arbitrarily assigned). Data converted by application of offset
-		and scale to Degrees.
+		and scale to degrees.
 
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_raw
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_raw
@@ -203,7 +202,7 @@ Contact:	linux-iio@vger.kernel.org
 Description:
 		If known for a device, offset to be added to <type>[Y]_raw prior
 		to scaling by <type>[Y]_scale in order to obtain value in the
-		<type> units as specified in <type>[y]_raw documentation.
+		<type> units as specified in <type>[Y]_raw documentation.
 		Not present if the offset is always 0 or unknown. If Y or
 		axis <x|y|z> is not present, then the offset applies to all
 		in channels of <type>.
@@ -249,7 +248,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_proximity0_calibbias
 KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
 Description:
-		Hardware applied calibration offset. (assumed to fix production
+		Hardware applied calibration offset (assumed to fix production
 		inaccuracies).
 
 What		/sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
@@ -266,7 +265,7 @@ what		/sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale
 KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
 Description:
-		Hardware applied calibration scale factor. (assumed to fix
+		Hardware applied calibration scale factor (assumed to fix
 		production inaccuracies).  If shared across all channels,
 		<type>_calibscale is used.
 
@@ -279,7 +278,7 @@ What:		/sys/.../iio:deviceX/in_capacitance_scale_available
 KernelVersion:	2.635
 Contact:	linux-iio@vger.kernel.org
 Description:
-		If a discrete set of scale values are available, they
+		If a discrete set of scale values is available, they
 		are listed in this attribute.
 
 What		/sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain
@@ -330,9 +329,11 @@ Contact:	linux-iio@vger.kernel.org
 Description:
 		Specifies the output powerdown mode.
 		DAC output stage is disconnected from the amplifier and
-		1kohm_to_gnd: connected to ground via an 1kOhm resistor
-		100kohm_to_gnd: connected to ground via an 100kOhm resistor
-		three_state: left floating
+		1kohm_to_gnd: connected	to ground via an 1kOhm resistor,
+		6kohm_to_gnd: connected to ground via a 6kOhm resistor,
+		20kohm_to_gnd: connected to ground via a 20kOhm resistor,
+		100kohm_to_gnd: connected to ground via an 100kOhm resistor,
+		three_state: left floating.
 		For a list of available output power down options read
 		outX_powerdown_mode_available. If Y is not present the
 		mode is shared across all outputs.
@@ -355,9 +356,10 @@ KernelVersion:	2.6.38
 Contact:	linux-iio@vger.kernel.org
 Description:
 		Writing 1 causes output Y to enter the power down mode specified
-		by the corresponding outY_powerdown_mode. Clearing returns to
-		normal operation. Y may be suppressed if all outputs are
-		controlled together.
+		by the corresponding outY_powerdown_mode. DAC output stage is
+		disconnected from the amplifier. Clearing returns to normal
+		operation. Y may be suppressed if all outputs are controlled
+		together.
 
 What:		/sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency
 KernelVersion:	3.4.0
@@ -421,12 +423,12 @@ Description:
 		different values, but the device can only enable both thresholds
 		or neither.
 		Note the driver will assume the last p events requested are
-		to be enabled where p is however many it supports (which may
-		vary depending on the exact set requested. So if you want to be
+		to be enabled where p is how many it supports (which may vary
+		depending on the exact set requested. So if you want to be
 		sure you have set what you think you have, check the contents of
 		these attributes after everything is configured. Drivers may
 		have to buffer any parameters so that they are consistent when
-		a given event type is enabled a future point (and not those for
+		a given event type is enabled at a future point (and not those for
 		whatever event was previously enabled).
 
 What:		/sys/.../iio:deviceX/events/in_accel_x_roc_rising_en
@@ -702,7 +704,7 @@ What:		/sys/.../buffer/scan_elements/in_anglvel_type
 What:		/sys/.../buffer/scan_elements/in_magn_type
 What:		/sys/.../buffer/scan_elements/in_incli_type
 What:		/sys/.../buffer/scan_elements/in_voltageY_type
-What:		/sys/.../buffer/scan_elements/in_voltage-in_type
+What:		/sys/.../buffer/scan_elements/in_voltage_type
 What:		/sys/.../buffer/scan_elements/in_voltageY_supply_type
 What:		/sys/.../buffer/scan_elements/in_timestamp_type
 KernelVersion:	2.6.37
@@ -723,7 +725,7 @@ Description:
 		the buffer output value appropriately.  The storagebits value
 		also specifies the data alignment.  So s48/64>>2 will be a
 		signed 48 bit integer stored in a 64 bit location aligned to
-		a a64 bit boundary. To obtain the clean value, shift right 2
+		a 64 bit boundary. To obtain the clean value, shift right 2
 		and apply a mask to zero the top 16 bits of the result.
 		For other storage combinations this attribute will be extended
 		appropriately.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
new file mode 100644
index 0000000..2ce9c3f
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
@@ -0,0 +1,37 @@
+What:		/sys/bus/iio/devices/iio:deviceX/pll2_feedback_clk_present
+What:		/sys/bus/iio/devices/iio:deviceX/pll2_reference_clk_present
+What:		/sys/bus/iio/devices/iio:deviceX/pll1_reference_clk_a_present
+What:		/sys/bus/iio/devices/iio:deviceX/pll1_reference_clk_b_present
+What:		/sys/bus/iio/devices/iio:deviceX/pll1_reference_clk_test_present
+What:		/sys/bus/iio/devices/iio:deviceX/vcxo_clk_present
+KernelVersion:	3.4.0
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Reading returns either '1' or '0'.
+		'1' means that the clock in question is present.
+		'0' means that the clock is missing.
+
+What:		/sys/bus/iio/devices/iio:deviceX/pllY_locked
+KernelVersion:	3.4.0
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Reading returns either '1' or '0'. '1' means that the
+		pllY is locked.
+
+What:		/sys/bus/iio/devices/iio:deviceX/store_eeprom
+KernelVersion:	3.4.0
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Writing '1' stores the current device configuration into
+		on-chip EEPROM. After power-up or chip reset the device will
+		automatically load the saved configuration.
+
+What:		/sys/bus/iio/devices/iio:deviceX/sync_dividers
+KernelVersion:	3.4.0
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Writing '1' triggers the clock distribution synchronization
+		functionality. All dividers are reset and the channels start
+		with their predefined phase offsets (out_altvoltageY_phase).
+		Writing this file has the effect as driving the external
+		/SYNC pin low.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
new file mode 100644
index 0000000..d89aded
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
@@ -0,0 +1,21 @@
+What:		/sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_resolution
+KernelVersion:	3.4.0
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Stores channel Y frequency resolution/channel spacing in Hz.
+		The value given directly influences the MODULUS used by
+		the fractional-N PLL. It is assumed that the algorithm
+		that is used to compute the various dividers, is able to
+		generate proper values for multiples of channel spacing.
+
+What:		/sys/bus/iio/devices/iio:deviceX/out_altvoltageY_refin_frequency
+KernelVersion:	3.4.0
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Sets channel Y REFin frequency in Hz. In some clock chained
+		applications, the reference frequency used by the PLL may
+		change during runtime. This attribute allows the user to
+		adjust the reference frequency accordingly.
+		The value written has no effect until out_altvoltageY_frequency
+		is updated. Consider to use out_altvoltageY_powerdown to power
+		down the PLL and it's RFOut buffers during REFin changes.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-light-lm3533-als b/Documentation/ABI/testing/sysfs-bus-iio-light-lm3533-als
new file mode 100644
index 0000000..22c5ea6
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-light-lm3533-als
@@ -0,0 +1,61 @@
+What:		/sys/.../events/in_illuminance0_thresh_either_en
+Date:		April 2012
+KernelVersion:	3.5
+Contact:	Johan Hovold <jhovold@gmail.com>
+Description:
+		Event generated when channel passes one of the four thresholds
+		in each direction (rising|falling) and a zone change occurs.
+		The corresponding light zone can be read from
+		in_illuminance0_zone.
+
+What:		/sys/.../events/in_illuminance0_threshY_hysteresis
+Date:		May 2012
+KernelVersion:	3.5
+Contact:	Johan Hovold <jhovold@gmail.com>
+Description:
+		Get the hysteresis for thresholds Y, that is,
+		threshY_hysteresis = threshY_raising - threshY_falling
+
+What:		/sys/.../events/illuminance_threshY_falling_value
+What:		/sys/.../events/illuminance_threshY_raising_value
+Date:		April 2012
+KernelVersion:	3.5
+Contact:	Johan Hovold <jhovold@gmail.com>
+Description:
+		Specifies the value of threshold that the device is comparing
+		against for the events enabled by
+		in_illuminance0_thresh_either_en (0..255), where Y in 0..3.
+
+		Note that threshY_falling must be less than or equal to
+		threshY_raising.
+
+		These thresholds correspond to the eight zone-boundary
+		registers (boundaryY_{low,high}) and define the five light
+		zones.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_illuminance0_zone
+Date:		April 2012
+KernelVersion:	3.5
+Contact:	Johan Hovold <jhovold@gmail.com>
+Description:
+		Get the current light zone (0..4) as defined by the
+		in_illuminance0_threshY_{falling,rising} thresholds.
+
+What:		/sys/bus/iio/devices/iio:deviceX/out_currentY_raw
+Date:		May 2012
+KernelVersion:	3.5
+Contact:	Johan Hovold <jhovold@gmail.com>
+Description:
+		Get output current for channel Y (0..255), that is,
+		out_currentY_currentZ_raw, where Z is the current zone.
+
+What:		/sys/bus/iio/devices/iio:deviceX/out_currentY_currentZ_raw
+Date:		May 2012
+KernelVersion:	3.5
+Contact:	Johan Hovold <jhovold@gmail.com>
+Description:
+		Set the output current for channel out_currentY when in zone
+		Z (0..255), where Y in 0..2 and Z in 0..4.
+
+		These values correspond to the ALS-mapper target registers for
+		ALS-mapper Y + 1.
diff --git a/Documentation/ABI/testing/sysfs-class-mtd b/Documentation/ABI/testing/sysfs-class-mtd
index db1ad7e..938ef71 100644
--- a/Documentation/ABI/testing/sysfs-class-mtd
+++ b/Documentation/ABI/testing/sysfs-class-mtd
@@ -142,13 +142,14 @@ KernelVersion:	3.4
 Contact:	linux-mtd@lists.infradead.org
 Description:
 		This allows the user to examine and adjust the criteria by which
-		mtd returns -EUCLEAN from mtd_read().  If the maximum number of
-		bit errors that were corrected on any single region comprising
-		an ecc step (as reported by the driver) equals or exceeds this
-		value, -EUCLEAN is returned.  Otherwise, absent an error, 0 is
-		returned.  Higher layers (e.g., UBI) use this return code as an
-		indication that an erase block may be degrading and should be
-		scrutinized as a candidate for being marked as bad.
+		mtd returns -EUCLEAN from mtd_read() and mtd_read_oob().  If the
+		maximum number of bit errors that were corrected on any single
+		region comprising an ecc step (as reported by the driver) equals
+		or exceeds this value, -EUCLEAN is returned.  Otherwise, absent
+		an error, 0 is returned.  Higher layers (e.g., UBI) use this
+		return code as an indication that an erase block may be
+		degrading and should be scrutinized as a candidate for being
+		marked as bad.
 
 		The initial value may be specified by the flash device driver.
 		If not, then the default value is ecc_strength.
@@ -167,7 +168,7 @@ Description:
 		block degradation, but high enough to avoid the consequences of
 		a persistent return value of -EUCLEAN on devices where sticky
 		bitflips occur.  Note that if bitflip_threshold exceeds
-		ecc_strength, -EUCLEAN is never returned by mtd_read().
+		ecc_strength, -EUCLEAN is never returned by the read operations.
 		Conversely, if bitflip_threshold is zero, -EUCLEAN is always
 		returned, absent a hard error.
 
diff --git a/Documentation/ABI/testing/sysfs-devices-edac b/Documentation/ABI/testing/sysfs-devices-edac
new file mode 100644
index 0000000..30ee78a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-edac
@@ -0,0 +1,140 @@
+What:		/sys/devices/system/edac/mc/mc*/reset_counters
+Date:		January 2006
+Contact:	linux-edac@vger.kernel.org
+Description:	This write-only control file will zero all the statistical
+		counters for UE and CE errors on the given memory controller.
+		Zeroing the counters will also reset the timer indicating how
+		long since the last counter were reset. This is useful for
+		computing errors/time.  Since the counters are always reset
+		at driver initialization time, no module/kernel parameter
+		is available.
+
+What:		/sys/devices/system/edac/mc/mc*/seconds_since_reset
+Date:		January 2006
+Contact:	linux-edac@vger.kernel.org
+Description:	This attribute file displays how many seconds have elapsed
+		since the last counter reset. This can be used with the error
+		counters to measure error rates.
+
+What:		/sys/devices/system/edac/mc/mc*/mc_name
+Date:		January 2006
+Contact:	linux-edac@vger.kernel.org
+Description:	This attribute file displays the type of memory controller
+		that is being utilized.
+
+What:		/sys/devices/system/edac/mc/mc*/size_mb
+Date:		January 2006
+Contact:	linux-edac@vger.kernel.org
+Description:	This attribute file displays, in count of megabytes, of memory
+		that this memory controller manages.
+
+What:		/sys/devices/system/edac/mc/mc*/ue_count
+Date:		January 2006
+Contact:	linux-edac@vger.kernel.org
+Description:	This attribute file displays the total count of uncorrectable
+		errors that have occurred on this memory controller. If
+		panic_on_ue is set, this counter will not have a chance to
+		increment, since EDAC will panic the system
+
+What:		/sys/devices/system/edac/mc/mc*/ue_noinfo_count
+Date:		January 2006
+Contact:	linux-edac@vger.kernel.org
+Description:	This attribute file displays the number of UEs that have
+		occurred on this memory controller with no information as to
+		which DIMM slot is having errors.
+
+What:		/sys/devices/system/edac/mc/mc*/ce_count
+Date:		January 2006
+Contact:	linux-edac@vger.kernel.org
+Description:	This attribute file displays the total count of correctable
+		errors that have occurred on this memory controller. This
+		count is very important to examine. CEs provide early
+		indications that a DIMM is beginning to fail. This count
+		field should be monitored for non-zero values and report
+		such information to the system administrator.
+
+What:		/sys/devices/system/edac/mc/mc*/ce_noinfo_count
+Date:		January 2006
+Contact:	linux-edac@vger.kernel.org
+Description:	This attribute file displays the number of CEs that
+		have occurred on this memory controller wherewith no
+		information as to which DIMM slot is having errors. Memory is
+		handicapped, but operational, yet no information is available
+		to indicate which slot the failing memory is in. This count
+		field should be also be monitored for non-zero values.
+
+What:		/sys/devices/system/edac/mc/mc*/sdram_scrub_rate
+Date:		February 2007
+Contact:	linux-edac@vger.kernel.org
+Description:	Read/Write attribute file that controls memory scrubbing.
+		The scrubbing rate used by the memory controller is set by
+		writing a minimum bandwidth in bytes/sec to the attribute file.
+		The rate will be translated to an internal value that gives at
+		least the specified rate.
+		Reading the file will return the actual scrubbing rate employed.
+		If configuration fails or memory scrubbing is not implemented,
+		the value of the attribute file will be -1.
+
+What:		/sys/devices/system/edac/mc/mc*/max_location
+Date:		April 2012
+Contact:	Mauro Carvalho Chehab <mchehab@redhat.com>
+		linux-edac@vger.kernel.org
+Description:	This attribute file displays the information about the last
+		available memory slot in this memory controller. It is used by
+		userspace tools in order to display the memory filling layout.
+
+What:		/sys/devices/system/edac/mc/mc*/(dimm|rank)*/size
+Date:		April 2012
+Contact:	Mauro Carvalho Chehab <mchehab@redhat.com>
+		linux-edac@vger.kernel.org
+Description:	This attribute file will display the size of dimm or rank.
+		For dimm*/size, this is the size, in MB of the DIMM memory
+		stick. For rank*/size, this is the size, in MB for one rank
+		of the DIMM memory stick. On single rank memories (1R), this
+		is also the total size of the dimm. On dual rank (2R) memories,
+		this is half the size of the total DIMM memories.
+
+What:		/sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_dev_type
+Date:		April 2012
+Contact:	Mauro Carvalho Chehab <mchehab@redhat.com>
+		linux-edac@vger.kernel.org
+Description:	This attribute file will display what type of DRAM device is
+		being utilized on this DIMM (x1, x2, x4, x8, ...).
+
+What:		/sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_edac_mode
+Date:		April 2012
+Contact:	Mauro Carvalho Chehab <mchehab@redhat.com>
+		linux-edac@vger.kernel.org
+Description:	This attribute file will display what type of Error detection
+		and correction is being utilized. For example: S4ECD4ED would
+		mean a Chipkill with x4 DRAM.
+
+What:		/sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_label
+Date:		April 2012
+Contact:	Mauro Carvalho Chehab <mchehab@redhat.com>
+		linux-edac@vger.kernel.org
+Description:	This control file allows this DIMM to have a label assigned
+		to it. With this label in the module, when errors occur
+		the output can provide the DIMM label in the system log.
+		This becomes vital for panic events to isolate the
+		cause of the UE event.
+		DIMM Labels must be assigned after booting, with information
+		that correctly identifies the physical slot with its
+		silk screen label. This information is currently very
+		motherboard specific and determination of this information
+		must occur in userland at this time.
+
+What:		/sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_location
+Date:		April 2012
+Contact:	Mauro Carvalho Chehab <mchehab@redhat.com>
+		linux-edac@vger.kernel.org
+Description:	This attribute file will display the location (csrow/channel,
+		branch/channel/slot or channel/slot) of the dimm or rank.
+
+What:		/sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_mem_type
+Date:		April 2012
+Contact:	Mauro Carvalho Chehab <mchehab@redhat.com>
+		linux-edac@vger.kernel.org
+Description:	This attribute file will display what type of memory is
+		currently on this csrow. Normally, either buffered or
+		unbuffered memory (for example, Unbuffered-DDR3).
diff --git a/Documentation/ABI/testing/sysfs-devices-platform-sh_mobile_lcdc_fb b/Documentation/ABI/testing/sysfs-devices-platform-sh_mobile_lcdc_fb
new file mode 100644
index 0000000..2107082
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-platform-sh_mobile_lcdc_fb
@@ -0,0 +1,44 @@
+What:		/sys/devices/platform/sh_mobile_lcdc_fb.[0-3]/graphics/fb[0-9]/ovl_alpha
+Date:		May 2012
+Contact:	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Description:
+		This file is only available on fb[0-9] devices corresponding
+		to overlay planes.
+
+		Stores the alpha blending value for the overlay. Values range
+		from 0 (transparent) to 255 (opaque). The value is ignored if
+		the mode is not set to Alpha Blending.
+
+What:		/sys/devices/platform/sh_mobile_lcdc_fb.[0-3]/graphics/fb[0-9]/ovl_mode
+Date:		May 2012
+Contact:	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Description:
+		This file is only available on fb[0-9] devices corresponding
+		to overlay planes.
+
+		Selects the composition mode for the overlay. Possible values
+		are
+
+		0 - Alpha Blending
+		1 - ROP3
+
+What:		/sys/devices/platform/sh_mobile_lcdc_fb.[0-3]/graphics/fb[0-9]/ovl_position
+Date:		May 2012
+Contact:	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Description:
+		This file is only available on fb[0-9] devices corresponding
+		to overlay planes.
+
+		Stores the x,y overlay position on the display in pixels. The
+		position format is `[0-9]+,[0-9]+'.
+
+What:		/sys/devices/platform/sh_mobile_lcdc_fb.[0-3]/graphics/fb[0-9]/ovl_rop3
+Date:		May 2012
+Contact:	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Description:
+		This file is only available on fb[0-9] devices corresponding
+		to overlay planes.
+
+		Stores the raster operation (ROP3) for the overlay. Values
+		range from 0 to 255. The value is ignored if the mode is not
+		set to ROP3.
diff --git a/Documentation/ABI/testing/sysfs-devices-system-xen_cpu b/Documentation/ABI/testing/sysfs-devices-system-xen_cpu
new file mode 100644
index 0000000..9ca02fb
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-system-xen_cpu
@@ -0,0 +1,20 @@
+What:		/sys/devices/system/xen_cpu/
+Date:		May 2012
+Contact:	Liu, Jinsong <jinsong.liu@intel.com>
+Description:
+		A collection of global/individual Xen physical cpu attributes
+
+		Individual physical cpu attributes are contained in
+		subdirectories named by the Xen's logical cpu number, e.g.:
+		/sys/devices/system/xen_cpu/xen_cpu#/
+
+
+What:		/sys/devices/system/xen_cpu/xen_cpu#/online
+Date:		May 2012
+Contact:	Liu, Jinsong <jinsong.liu@intel.com>
+Description:
+		Interface to online/offline Xen physical cpus
+
+		When running under Xen platform, it provide user interface
+		to online/offline physical cpus, except cpu0 due to several
+		logic restrictions and assumptions.
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-lenovo-tpkbd b/Documentation/ABI/testing/sysfs-driver-hid-lenovo-tpkbd
new file mode 100644
index 0000000..57b92cb
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-lenovo-tpkbd
@@ -0,0 +1,38 @@
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/press_to_select
+Date:		July 2011
+Contact:	linux-input@vger.kernel.org
+Description:	This controls if mouse clicks should be generated if the trackpoint is quickly pressed. How fast this press has to be
+		is being controlled by press_speed.
+		Values are 0 or 1.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/dragging
+Date:		July 2011
+Contact:	linux-input@vger.kernel.org
+Description:	If this setting is enabled, it is possible to do dragging by pressing the trackpoint. This requires press_to_select to be enabled.
+		Values are 0 or 1.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/release_to_select
+Date:		July 2011
+Contact:	linux-input@vger.kernel.org
+Description:	For details regarding this setting please refer to http://www.pc.ibm.com/ww/healthycomputing/trkpntb.html
+		Values are 0 or 1.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/select_right
+Date:		July 2011
+Contact:	linux-input@vger.kernel.org
+Description:	This setting controls if the mouse click events generated by pressing the trackpoint (if press_to_select is enabled) generate
+		a left or right mouse button click.
+		Values are 0 or 1.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/sensitivity
+Date:		July 2011
+Contact:	linux-input@vger.kernel.org
+Description:	This file contains the trackpoint sensitivity.
+		Values are decimal integers from 1 (lowest sensitivity) to 255 (highest sensitivity).
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/press_speed
+Date:		July 2011
+Contact:	linux-input@vger.kernel.org
+Description:	This setting controls how fast the trackpoint needs to be pressed to generate a mouse click if press_to_select is enabled.
+		Values are decimal integers from 1 (slowest) to 255 (fastest).
+
diff --git a/Documentation/ABI/testing/sysfs-kernel-iommu_groups b/Documentation/ABI/testing/sysfs-kernel-iommu_groups
new file mode 100644
index 0000000..9b31556
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-kernel-iommu_groups
@@ -0,0 +1,14 @@
+What:		/sys/kernel/iommu_groups/
+Date:		May 2012
+KernelVersion:	v3.5
+Contact:	Alex Williamson <alex.williamson@redhat.com>
+Description:	/sys/kernel/iommu_groups/ contains a number of sub-
+		directories, each representing an IOMMU group.  The
+		name of the sub-directory matches the iommu_group_id()
+		for the group, which is an integer value.  Within each
+		subdirectory is another directory named "devices" with
+		links to the sysfs devices contained in this group.
+		The group directory also optionally contains a "name"
+		file if the IOMMU driver has chosen to register a more
+		common name for the group.
+Users:
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index 31725ff..2177726 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -231,3 +231,16 @@ Description:
 		Reads from this file return a string consisting of the names of
 		wakeup sources created with the help of /sys/power/wake_lock
 		that are inactive at the moment, separated with spaces.
+
+What:		/sys/power/pm_print_times
+Date:		May 2012
+Contact:	Sameer Nanda <snanda@chromium.org>
+Description:
+		The /sys/power/pm_print_times file allows user space to
+		control whether the time taken by devices to suspend and
+		resume is printed.  These prints are useful for hunting down
+		devices that take too long to suspend or resume.
+
+		Writing a "1" enables this printing while writing a "0"
+		disables it.  The default value is "0".  Reading from this file
+		will display the current value.
diff --git a/Documentation/DMA-attributes.txt b/Documentation/DMA-attributes.txt
index 5c72eed..f503090 100644
--- a/Documentation/DMA-attributes.txt
+++ b/Documentation/DMA-attributes.txt
@@ -49,3 +49,45 @@ DMA_ATTR_NON_CONSISTENT lets the platform to choose to return either
 consistent or non-consistent memory as it sees fit.  By using this API,
 you are guaranteeing to the platform that you have all the correct and
 necessary sync points for this memory in the driver.
+
+DMA_ATTR_NO_KERNEL_MAPPING
+--------------------------
+
+DMA_ATTR_NO_KERNEL_MAPPING lets the platform to avoid creating a kernel
+virtual mapping for the allocated buffer. On some architectures creating
+such mapping is non-trivial task and consumes very limited resources
+(like kernel virtual address space or dma consistent address space).
+Buffers allocated with this attribute can be only passed to user space
+by calling dma_mmap_attrs(). By using this API, you are guaranteeing
+that you won't dereference the pointer returned by dma_alloc_attr(). You
+can threat it as a cookie that must be passed to dma_mmap_attrs() and
+dma_free_attrs(). Make sure that both of these also get this attribute
+set on each call.
+
+Since it is optional for platforms to implement
+DMA_ATTR_NO_KERNEL_MAPPING, those that do not will simply ignore the
+attribute and exhibit default behavior.
+
+DMA_ATTR_SKIP_CPU_SYNC
+----------------------
+
+By default dma_map_{single,page,sg} functions family transfer a given
+buffer from CPU domain to device domain. Some advanced use cases might
+require sharing a buffer between more than one device. This requires
+having a mapping created separately for each device and is usually
+performed by calling dma_map_{single,page,sg} function more than once
+for the given buffer with device pointer to each device taking part in
+the buffer sharing. The first call transfers a buffer from 'CPU' domain
+to 'device' domain, what synchronizes CPU caches for the given region
+(usually it means that the cache has been flushed or invalidated
+depending on the dma direction). However, next calls to
+dma_map_{single,page,sg}() for other devices will perform exactly the
+same sychronization operation on the CPU cache. CPU cache sychronization
+might be a time consuming operation, especially if the buffers are
+large, so it is highly recommended to avoid it if possible.
+DMA_ATTR_SKIP_CPU_SYNC allows platform code to skip synchronization of
+the CPU cache for the given buffer assuming that it has been already
+transferred to 'device' domain. This attribute can be also used for
+dma_unmap_{single,page,sg} functions family to force buffer to stay in
+device domain after releasing a mapping for it. Use this attribute with
+care!
diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml
index 7c49fac..1078e45 100644
--- a/Documentation/DocBook/media/v4l/biblio.xml
+++ b/Documentation/DocBook/media/v4l/biblio.xml
@@ -194,7 +194,7 @@ in the frequency range from 87,5 to 108,0 MHz</title>
 	<corpauthor>National Radio Systems Committee
 (<ulink url="http://www.nrscstandards.org">http://www.nrscstandards.org</ulink>)</corpauthor>
       </authorgroup>
-      <title>NTSC-4: United States RBDS Standard</title>
+      <title>NRSC-4: United States RBDS Standard</title>
     </biblioentry>
 
     <biblioentry id="iso12232">
diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
index 4101aeb..b91d253 100644
--- a/Documentation/DocBook/media/v4l/common.xml
+++ b/Documentation/DocBook/media/v4l/common.xml
@@ -464,14 +464,14 @@ The <structfield>type</structfield> field of the respective
 <structfield>tuner</structfield> field contains the index number of
 the tuner.</para>
 
-      <para>Radio devices have exactly one tuner with index zero, no
+      <para>Radio input devices have exactly one tuner with index zero, no
 video inputs.</para>
 
       <para>To query and change tuner properties applications use the
 &VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; ioctl, respectively. The
 &v4l2-tuner; returned by <constant>VIDIOC_G_TUNER</constant> also
 contains signal status information applicable when the tuner of the
-current video input, or a radio tuner is queried. Note that
+current video or radio input is queried. Note that
 <constant>VIDIOC_S_TUNER</constant> does not switch the current tuner,
 when there is more than one at all. The tuner is solely determined by
 the current video input. Drivers must support both ioctls and set the
@@ -491,8 +491,17 @@ the modulator. The <structfield>type</structfield> field of the
 respective &v4l2-output; returned by the &VIDIOC-ENUMOUTPUT; ioctl is
 set to <constant>V4L2_OUTPUT_TYPE_MODULATOR</constant> and its
 <structfield>modulator</structfield> field contains the index number
-of the modulator. This specification does not define radio output
-devices.</para>
+of the modulator.</para>
+
+      <para>Radio output devices have exactly one modulator with index
+zero, no video outputs.</para>
+
+      <para>A video or radio device cannot support both a tuner and a
+modulator. Two separate device nodes will have to be used for such
+hardware, one that supports the tuner functionality and one that supports
+the modulator functionality. The reason is a limitation with the
+&VIDIOC-S-FREQUENCY; ioctl where you cannot specify whether the frequency
+is for a tuner or a modulator.</para>
 
       <para>To query and change modulator properties applications use
 the &VIDIOC-G-MODULATOR; and &VIDIOC-S-MODULATOR; ioctl. Note that
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
index f5ac15e..e58934c 100644
--- a/Documentation/DocBook/media/v4l/pixfmt.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt.xml
@@ -986,13 +986,13 @@ http://www.thedirks.org/winnov/</ulink></para></entry>
 	  <row id="V4L2-PIX-FMT-Y4">
 	    <entry><constant>V4L2_PIX_FMT_Y4</constant></entry>
 	    <entry>'Y04 '</entry>
-	    <entry>Old 4-bit greyscale format. Only the least significant 4 bits of each byte are used,
+	    <entry>Old 4-bit greyscale format. Only the most significant 4 bits of each byte are used,
 the other bits are set to 0.</entry>
 	  </row>
 	  <row id="V4L2-PIX-FMT-Y6">
 	    <entry><constant>V4L2_PIX_FMT_Y6</constant></entry>
 	    <entry>'Y06 '</entry>
-	    <entry>Old 6-bit greyscale format. Only the least significant 6 bits of each byte are used,
+	    <entry>Old 6-bit greyscale format. Only the most significant 6 bits of each byte are used,
 the other bits are set to 0.</entry>
 	  </row>
 	</tbody>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index 015c561..008c2d7 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -560,6 +560,7 @@ and discussions on the V4L mailing list.</revremark>
     &sub-g-tuner;
     &sub-log-status;
     &sub-overlay;
+    &sub-prepare-buf;
     &sub-qbuf;
     &sub-querybuf;
     &sub-querycap;
@@ -567,7 +568,6 @@ and discussions on the V4L mailing list.</revremark>
     &sub-query-dv-preset;
     &sub-query-dv-timings;
     &sub-querystd;
-    &sub-prepare-buf;
     &sub-reqbufs;
     &sub-s-hw-freq-seek;
     &sub-streamon;
diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
index 765549f..a2474ec 100644
--- a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
@@ -108,10 +108,9 @@ information.</para>
 /></entry>
 	  </row>
 	  <row>
-	    <entry>__u32</entry>
+	    <entry>struct&nbsp;v4l2_format</entry>
 	    <entry><structfield>format</structfield></entry>
-	    <entry>Filled in by the application, preserved by the driver.
-	    See <xref linkend="v4l2-format" />.</entry>
+	    <entry>Filled in by the application, preserved by the driver.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
index e8714aa..98a856f 100644
--- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
@@ -89,7 +89,7 @@
 	  <row>
 	    <entry></entry>
 	    <entry>&v4l2-event-frame-sync;</entry>
-            <entry><structfield>frame</structfield></entry>
+            <entry><structfield>frame_sync</structfield></entry>
 	    <entry>Event data for event V4L2_EVENT_FRAME_SYNC.</entry>
 	  </row>
 	  <row>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
index 69c178a..40e58a4 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
@@ -135,6 +135,12 @@ bounds or the value in the <structfield>type</structfield> field is
 wrong.</para>
 	</listitem>
       </varlistentry>
+      <varlistentry>
+	<term><errorcode>EBUSY</errorcode></term>
+	<listitem>
+	  <para>A hardware seek is in progress.</para>
+	</listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
index 62a1aa2..95d5371 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
@@ -276,6 +276,18 @@ can or must be switched. (B/G PAL tuners for example are typically not
       <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
 	  </row>
 	  <row>
+	    <entry><constant>V4L2_TUNER_CAP_HWSEEK_BOUNDED</constant></entry>
+	    <entry>0x0004</entry>
+	    <entry>If set, then this tuner supports the hardware seek functionality
+	    where the seek stops when it reaches the end of the frequency range.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_TUNER_CAP_HWSEEK_WRAP</constant></entry>
+	    <entry>0x0008</entry>
+	    <entry>If set, then this tuner supports the hardware seek functionality
+	    where the seek wraps around when it reaches the end of the frequency range.</entry>
+	  </row>
+	  <row>
 	<entry><constant>V4L2_TUNER_CAP_STEREO</constant></entry>
 	<entry>0x0010</entry>
 	<entry>Stereo audio reception is supported.</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
index 407dfce..f4db44d 100644
--- a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
@@ -58,6 +58,9 @@ To do this applications initialize the <structfield>tuner</structfield>,
 call the <constant>VIDIOC_S_HW_FREQ_SEEK</constant> ioctl with a pointer
 to this structure.</para>
 
+    <para>If an error is returned, then the original frequency will
+    be restored.</para>
+
     <para>This ioctl is supported if the <constant>V4L2_CAP_HW_FREQ_SEEK</constant> capability is set.</para>
 
     <table pgwide="1" frame="none" id="v4l2-hw-freq-seek">
@@ -87,7 +90,10 @@ field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>wrap_around</structfield></entry>
-	    <entry>If non-zero, wrap around when at the end of the frequency range, else stop seeking.</entry>
+	    <entry>If non-zero, wrap around when at the end of the frequency range, else stop seeking.
+	    The &v4l2-tuner; <structfield>capability</structfield> field will tell you what the
+	    hardware supports.
+	    </entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
@@ -118,9 +124,15 @@ wrong.</para>
 	</listitem>
       </varlistentry>
       <varlistentry>
-	<term><errorcode>EAGAIN</errorcode></term>
+	<term><errorcode>ENODATA</errorcode></term>
+	<listitem>
+	  <para>The hardware seek found no channels.</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><errorcode>EBUSY</errorcode></term>
 	<listitem>
-	  <para>The ioctl timed-out. Try again.</para>
+	  <para>Another hardware seek is already in progress.</para>
 	</listitem>
       </varlistentry>
     </variablelist>
diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
index e0aedb7..fe122d6 100644
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -1216,8 +1216,6 @@ in this page</entry>
 #define	NAND_BBT_LASTBLOCK	0x00000010
 /* The bbt is at the given page, else we must scan for the bbt */
 #define NAND_BBT_ABSPAGE	0x00000020
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_SEARCH		0x00000040
 /* bbt is stored per chip on multichip devices */
 #define NAND_BBT_PERCHIP	0x00000080
 /* bbt has a version counter at offset veroffs */
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index 5c8d749..fc103d7 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -162,9 +162,9 @@ over a rather long period of time, but improvements are always welcome!
 		when publicizing a pointer to a structure that can
 		be traversed by an RCU read-side critical section.
 
-5.	If call_rcu(), or a related primitive such as call_rcu_bh() or
-	call_rcu_sched(), is used, the callback function must be
-	written to be called from softirq context.  In particular,
+5.	If call_rcu(), or a related primitive such as call_rcu_bh(),
+	call_rcu_sched(), or call_srcu() is used, the callback function
+	must be written to be called from softirq context.  In particular,
 	it cannot block.
 
 6.	Since synchronize_rcu() can block, it cannot be called from
@@ -202,11 +202,12 @@ over a rather long period of time, but improvements are always welcome!
 	updater uses call_rcu_sched() or synchronize_sched(), then
 	the corresponding readers must disable preemption, possibly
 	by calling rcu_read_lock_sched() and rcu_read_unlock_sched().
-	If the updater uses synchronize_srcu(), the the corresponding
-	readers must use srcu_read_lock() and srcu_read_unlock(),
-	and with the same srcu_struct.	The rules for the expedited
-	primitives are the same as for their non-expedited counterparts.
-	Mixing things up will result in confusion and broken kernels.
+	If the updater uses synchronize_srcu() or call_srcu(),
+	the the corresponding readers must use srcu_read_lock() and
+	srcu_read_unlock(), and with the same srcu_struct.  The rules for
+	the expedited primitives are the same as for their non-expedited
+	counterparts.  Mixing things up will result in confusion and
+	broken kernels.
 
 	One exception to this rule: rcu_read_lock() and rcu_read_unlock()
 	may be substituted for rcu_read_lock_bh() and rcu_read_unlock_bh()
@@ -333,14 +334,14 @@ over a rather long period of time, but improvements are always welcome!
 	victim CPU from ever going offline.)
 
 14.	SRCU (srcu_read_lock(), srcu_read_unlock(), srcu_dereference(),
-	synchronize_srcu(), and synchronize_srcu_expedited()) may only
-	be invoked from process context.  Unlike other forms of RCU, it
-	-is- permissible to block in an SRCU read-side critical section
-	(demarked by srcu_read_lock() and srcu_read_unlock()), hence the
-	"SRCU": "sleepable RCU".  Please note that if you don't need
-	to sleep in read-side critical sections, you should be using
-	RCU rather than SRCU, because RCU is almost always faster and
-	easier to use than is SRCU.
+	synchronize_srcu(), synchronize_srcu_expedited(), and call_srcu())
+	may only be invoked from process context.  Unlike other forms of
+	RCU, it -is- permissible to block in an SRCU read-side critical
+	section (demarked by srcu_read_lock() and srcu_read_unlock()),
+	hence the "SRCU": "sleepable RCU".  Please note that if you
+	don't need to sleep in read-side critical sections, you should be
+	using RCU rather than SRCU, because RCU is almost always faster
+	and easier to use than is SRCU.
 
 	If you need to enter your read-side critical section in a
 	hardirq or exception handler, and then exit that same read-side
@@ -353,8 +354,8 @@ over a rather long period of time, but improvements are always welcome!
 	cleanup_srcu_struct().	These are passed a "struct srcu_struct"
 	that defines the scope of a given SRCU domain.	Once initialized,
 	the srcu_struct is passed to srcu_read_lock(), srcu_read_unlock()
-	synchronize_srcu(), and synchronize_srcu_expedited().  A given
-	synchronize_srcu() waits only for SRCU read-side critical
+	synchronize_srcu(), synchronize_srcu_expedited(), and call_srcu().
+	A given synchronize_srcu() waits only for SRCU read-side critical
 	sections governed by srcu_read_lock() and srcu_read_unlock()
 	calls that have been passed the same srcu_struct.  This property
 	is what makes sleeping read-side critical sections tolerable --
@@ -374,7 +375,7 @@ over a rather long period of time, but improvements are always welcome!
 	requiring SRCU's read-side deadlock immunity or low read-side
 	realtime latency.
 
-	Note that, rcu_assign_pointer() relates to SRCU just as they do
+	Note that, rcu_assign_pointer() relates to SRCU just as it does
 	to other forms of RCU.
 
 15.	The whole point of call_rcu(), synchronize_rcu(), and friends
diff --git a/Documentation/RCU/rcubarrier.txt b/Documentation/RCU/rcubarrier.txt
index e439a0e..38428c1 100644
--- a/Documentation/RCU/rcubarrier.txt
+++ b/Documentation/RCU/rcubarrier.txt
@@ -79,8 +79,6 @@ complete. Pseudo-code using rcu_barrier() is as follows:
    2. Execute rcu_barrier().
    3. Allow the module to be unloaded.
 
-Quick Quiz #1: Why is there no srcu_barrier()?
-
 The rcutorture module makes use of rcu_barrier in its exit function
 as follows:
 
@@ -162,7 +160,7 @@ for any pre-existing callbacks to complete.
 Then lines 55-62 print status and do operation-specific cleanup, and
 then return, permitting the module-unload operation to be completed.
 
-Quick Quiz #2: Is there any other situation where rcu_barrier() might
+Quick Quiz #1: Is there any other situation where rcu_barrier() might
 	be required?
 
 Your module might have additional complications. For example, if your
@@ -242,7 +240,7 @@ reaches zero, as follows:
  4 complete(&rcu_barrier_completion);
  5 }
 
-Quick Quiz #3: What happens if CPU 0's rcu_barrier_func() executes
+Quick Quiz #2: What happens if CPU 0's rcu_barrier_func() executes
 	immediately (thus incrementing rcu_barrier_cpu_count to the
 	value one), but the other CPU's rcu_barrier_func() invocations
 	are delayed for a full grace period? Couldn't this result in
@@ -259,12 +257,7 @@ so that your module may be safely unloaded.
 
 Answers to Quick Quizzes
 
-Quick Quiz #1: Why is there no srcu_barrier()?
-
-Answer: Since there is no call_srcu(), there can be no outstanding SRCU
-	callbacks. Therefore, there is no need to wait for them.
-
-Quick Quiz #2: Is there any other situation where rcu_barrier() might
+Quick Quiz #1: Is there any other situation where rcu_barrier() might
 	be required?
 
 Answer: Interestingly enough, rcu_barrier() was not originally
@@ -278,7 +271,7 @@ Answer: Interestingly enough, rcu_barrier() was not originally
 	implementing rcutorture, and found that rcu_barrier() solves
 	this problem as well.
 
-Quick Quiz #3: What happens if CPU 0's rcu_barrier_func() executes
+Quick Quiz #2: What happens if CPU 0's rcu_barrier_func() executes
 	immediately (thus incrementing rcu_barrier_cpu_count to the
 	value one), but the other CPU's rcu_barrier_func() invocations
 	are delayed for a full grace period? Couldn't this result in
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt
index 4ddf391..7dce8a1 100644
--- a/Documentation/RCU/torture.txt
+++ b/Documentation/RCU/torture.txt
@@ -174,11 +174,20 @@ torture_type	The type of RCU to test, with string values as follows:
 			and synchronize_rcu_bh_expedited().
 
 		"srcu": srcu_read_lock(), srcu_read_unlock() and
+			call_srcu().
+
+		"srcu_sync": srcu_read_lock(), srcu_read_unlock() and
 			synchronize_srcu().
 
 		"srcu_expedited": srcu_read_lock(), srcu_read_unlock() and
 			synchronize_srcu_expedited().
 
+		"srcu_raw": srcu_read_lock_raw(), srcu_read_unlock_raw(),
+			and call_srcu().
+
+		"srcu_raw_sync": srcu_read_lock_raw(), srcu_read_unlock_raw(),
+			and synchronize_srcu().
+
 		"sched": preempt_disable(), preempt_enable(), and
 			call_rcu_sched().
 
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index 6bbe8dc..69ee188 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -833,9 +833,9 @@ sched:	Critical sections	Grace period		Barrier
 
 SRCU:	Critical sections	Grace period		Barrier
 
-	srcu_read_lock		synchronize_srcu	N/A
-	srcu_read_unlock	synchronize_srcu_expedited
-	srcu_read_lock_raw
+	srcu_read_lock		synchronize_srcu	srcu_barrier
+	srcu_read_unlock	call_srcu
+	srcu_read_lock_raw	synchronize_srcu_expedited
 	srcu_read_unlock_raw
 	srcu_dereference
 
diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt
index 8e74980..e86faae 100644
--- a/Documentation/cgroups/cgroups.txt
+++ b/Documentation/cgroups/cgroups.txt
@@ -656,7 +656,7 @@ example in cpusets, no task may attach before 'cpus' and 'mems' are set
 up.
 
 void bind(struct cgroup *root)
-(cgroup_mutex and ss->hierarchy_mutex held by caller)
+(cgroup_mutex held by caller)
 
 Called when a cgroup subsystem is rebound to a different hierarchy
 and root cgroup. Currently this will only involve movement between
diff --git a/Documentation/cgroups/hugetlb.txt b/Documentation/cgroups/hugetlb.txt
new file mode 100644
index 0000000..a9faaca
--- /dev/null
+++ b/Documentation/cgroups/hugetlb.txt
@@ -0,0 +1,45 @@
+HugeTLB Controller
+-------------------
+
+The HugeTLB controller allows to limit the HugeTLB usage per control group and
+enforces the controller limit during page fault. Since HugeTLB doesn't
+support page reclaim, enforcing the limit at page fault time implies that,
+the application will get SIGBUS signal if it tries to access HugeTLB pages
+beyond its limit. This requires the application to know beforehand how much
+HugeTLB pages it would require for its use.
+
+HugeTLB controller can be created by first mounting the cgroup filesystem.
+
+# mount -t cgroup -o hugetlb none /sys/fs/cgroup
+
+With the above step, the initial or the parent HugeTLB group becomes
+visible at /sys/fs/cgroup. At bootup, this group includes all the tasks in
+the system. /sys/fs/cgroup/tasks lists the tasks in this cgroup.
+
+New groups can be created under the parent group /sys/fs/cgroup.
+
+# cd /sys/fs/cgroup
+# mkdir g1
+# echo $$ > g1/tasks
+
+The above steps create a new group g1 and move the current shell
+process (bash) into it.
+
+Brief summary of control files
+
+ hugetlb.<hugepagesize>.limit_in_bytes     # set/show limit of "hugepagesize" hugetlb usage
+ hugetlb.<hugepagesize>.max_usage_in_bytes # show max "hugepagesize" hugetlb  usage recorded
+ hugetlb.<hugepagesize>.usage_in_bytes     # show current res_counter usage for "hugepagesize" hugetlb
+ hugetlb.<hugepagesize>.failcnt		   # show the number of allocation failure due to HugeTLB limit
+
+For a system supporting two hugepage size (16M and 16G) the control
+files include:
+
+hugetlb.16GB.limit_in_bytes
+hugetlb.16GB.max_usage_in_bytes
+hugetlb.16GB.usage_in_bytes
+hugetlb.16GB.failcnt
+hugetlb.16MB.limit_in_bytes
+hugetlb.16MB.max_usage_in_bytes
+hugetlb.16MB.usage_in_bytes
+hugetlb.16MB.failcnt
diff --git a/Documentation/device-mapper/striped.txt b/Documentation/device-mapper/striped.txt
index f34d323..45f3b91 100644
--- a/Documentation/device-mapper/striped.txt
+++ b/Documentation/device-mapper/striped.txt
@@ -9,15 +9,14 @@ devices in parallel.
 
 Parameters: <num devs> <chunk size> [<dev path> <offset>]+
     <num devs>: Number of underlying devices.
-    <chunk size>: Size of each chunk of data. Must be a power-of-2 and at
-                  least as large as the system's PAGE_SIZE.
+    <chunk size>: Size of each chunk of data. Must be at least as
+                  large as the system's PAGE_SIZE.
     <dev path>: Full pathname to the underlying block-device, or a
                 "major:minor" device-number.
     <offset>: Starting sector within the device.
 
 One or more underlying devices can be specified. The striped device size must
-be a multiple of the chunk size and a multiple of the number of underlying
-devices.
+be a multiple of the chunk size multiplied by the number of underlying devices.
 
 
 Example scripts
diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt
index 32e4879..9884681 100644
--- a/Documentation/device-mapper/verity.txt
+++ b/Documentation/device-mapper/verity.txt
@@ -7,39 +7,39 @@ This target is read-only.
 
 Construction Parameters
 =======================
-    <version> <dev> <hash_dev> <hash_start>
+    <version> <dev> <hash_dev>
     <data_block_size> <hash_block_size>
     <num_data_blocks> <hash_start_block>
     <algorithm> <digest> <salt>
 
 <version>
-    This is the version number of the on-disk format.
+    This is the type of the on-disk hash format.
 
     0 is the original format used in the Chromium OS.
-	The salt is appended when hashing, digests are stored continuously and
-	the rest of the block is padded with zeros.
+      The salt is appended when hashing, digests are stored continuously and
+      the rest of the block is padded with zeros.
 
     1 is the current format that should be used for new devices.
-	The salt is prepended when hashing and each digest is
-	padded with zeros to the power of two.
+      The salt is prepended when hashing and each digest is
+      padded with zeros to the power of two.
 
 <dev>
-    This is the device containing the data the integrity of which needs to be
+    This is the device containing data, the integrity of which needs to be
     checked.  It may be specified as a path, like /dev/sdaX, or a device number,
     <major>:<minor>.
 
 <hash_dev>
-    This is the device that that supplies the hash tree data.  It may be
+    This is the device that supplies the hash tree data.  It may be
     specified similarly to the device path and may be the same device.  If the
-    same device is used, the hash_start should be outside of the dm-verity
-    configured device size.
+    same device is used, the hash_start should be outside the configured
+    dm-verity device.
 
 <data_block_size>
-    The block size on a data device.  Each block corresponds to one digest on
-    the hash device.
+    The block size on a data device in bytes.
+    Each block corresponds to one digest on the hash device.
 
 <hash_block_size>
-    The size of a hash block.
+    The size of a hash block in bytes.
 
 <num_data_blocks>
     The number of data blocks on the data device.  Additional blocks are
@@ -65,7 +65,7 @@ Construction Parameters
 Theory of operation
 ===================
 
-dm-verity is meant to be setup as part of a verified boot path.  This
+dm-verity is meant to be set up as part of a verified boot path.  This
 may be anything ranging from a boot using tboot or trustedgrub to just
 booting from a known-good device (like a USB drive or CD).
 
@@ -73,20 +73,20 @@ When a dm-verity device is configured, it is expected that the caller
 has been authenticated in some way (cryptographic signatures, etc).
 After instantiation, all hashes will be verified on-demand during
 disk access.  If they cannot be verified up to the root node of the
-tree, the root hash, then the I/O will fail.  This should identify
+tree, the root hash, then the I/O will fail.  This should detect
 tampering with any data on the device and the hash data.
 
 Cryptographic hashes are used to assert the integrity of the device on a
-per-block basis.  This allows for a lightweight hash computation on first read
-into the page cache.  Block hashes are stored linearly-aligned to the nearest
-block the size of a page.
+per-block basis. This allows for a lightweight hash computation on first read
+into the page cache. Block hashes are stored linearly, aligned to the nearest
+block size.
 
 Hash Tree
 ---------
 
 Each node in the tree is a cryptographic hash.  If it is a leaf node, the hash
-is of some block data on disk.  If it is an intermediary node, then the hash is
-of a number of child nodes.
+of some data block on disk is calculated. If it is an intermediary node,
+the hash of a number of child nodes is calculated.
 
 Each entry in the tree is a collection of neighboring nodes that fit in one
 block.  The number is determined based on block_size and the size of the
@@ -110,63 +110,23 @@ alg = sha256, num_blocks = 32768, block_size = 4096
 On-disk format
 ==============
 
-Below is the recommended on-disk format. The verity kernel code does not
-read the on-disk header. It only reads the hash blocks which directly
-follow the header. It is expected that a user-space tool will verify the
-integrity of the verity_header and then call dmsetup with the correct
-parameters. Alternatively, the header can be omitted and the dmsetup
-parameters can be passed via the kernel command-line in a rooted chain
-of trust where the command-line is verified.
+The verity kernel code does not read the verity metadata on-disk header.
+It only reads the hash blocks which directly follow the header.
+It is expected that a user-space tool will verify the integrity of the
+verity header.
 
-The on-disk format is especially useful in cases where the hash blocks
-are on a separate partition. The magic number allows easy identification
-of the partition contents. Alternatively, the hash blocks can be stored
-in the same partition as the data to be verified. In such a configuration
-the filesystem on the partition would be sized a little smaller than
-the full-partition, leaving room for the hash blocks.
-
-struct superblock {
-	uint8_t signature[8]
-		"verity\0\0";
-
-	uint8_t version;
-		1 - current format
-
-	uint8_t data_block_bits;
-		log2(data block size)
-
-	uint8_t hash_block_bits;
-		log2(hash block size)
-
-	uint8_t pad1[1];
-		zero padding
-
-	uint16_t salt_size;
-		big-endian salt size
-
-	uint8_t pad2[2];
-		zero padding
-
-	uint32_t data_blocks_hi;
-		big-endian high 32 bits of the 64-bit number of data blocks
-
-	uint32_t data_blocks_lo;
-		big-endian low 32 bits of the 64-bit number of data blocks
-
-	uint8_t algorithm[16];
-		cryptographic algorithm
-
-	uint8_t salt[384];
-		salt (the salt size is specified above)
-
-	uint8_t pad3[88];
-		zero padding to 512-byte boundary
-}
+Alternatively, the header can be omitted and the dmsetup parameters can
+be passed via the kernel command-line in a rooted chain of trust where
+the command-line is verified.
 
 Directly following the header (and with sector number padded to the next hash
 block boundary) are the hash blocks which are stored a depth at a time
 (starting from the root), sorted in order of increasing index.
 
+The full specification of kernel parameters and on-disk metadata format
+is available at the cryptsetup project's wiki page
+  http://code.google.com/p/cryptsetup/wiki/DMVerity
+
 Status
 ======
 V (for Valid) is returned if every check performed so far was valid.
@@ -174,21 +134,22 @@ If any check failed, C (for Corruption) is returned.
 
 Example
 =======
-
-Setup a device:
-  dmsetup create vroot --table \
-    "0 2097152 "\
-    "verity 1 /dev/sda1 /dev/sda2 4096 4096 2097152 1 "\
+Set up a device:
+  # dmsetup create vroot --readonly --table \
+    "0 2097152 verity 1 /dev/sda1 /dev/sda2 4096 4096 262144 1 sha256 "\
     "4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 "\
     "1234000000000000000000000000000000000000000000000000000000000000"
 
 A command line tool veritysetup is available to compute or verify
-the hash tree or activate the kernel driver.  This is available from
-the LVM2 upstream repository and may be supplied as a package called
-device-mapper-verity-tools:
-    git://sources.redhat.com/git/lvm2
-    http://sourceware.org/git/?p=lvm2.git
-    http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/verity?cvsroot=lvm2
-
-veritysetup -a vroot /dev/sda1 /dev/sda2 \
-	4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
+the hash tree or activate the kernel device. This is available from
+the cryptsetup upstream repository http://code.google.com/p/cryptsetup/
+(as a libcryptsetup extension).
+
+Create hash on the device:
+  # veritysetup format /dev/sda1 /dev/sda2
+  ...
+  Root hash: 4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
+
+Activate the device:
+  # veritysetup create vroot /dev/sda1 /dev/sda2 \
+    4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index 47a154f..b6251cc 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -2416,6 +2416,8 @@ Your cooperation is appreciated.
 		  1 = /dev/raw/raw1	First raw I/O device
 		  2 = /dev/raw/raw2	Second raw I/O device
 		    ...
+                 max minor number of raw device is set by kernel config
+                 MAX_RAW_DEVS or raw module parameter 'max_raw_devs'
 
 163 char
 
diff --git a/Documentation/devicetree/bindings/arm/calxeda/l2ecc.txt b/Documentation/devicetree/bindings/arm/calxeda/l2ecc.txt
new file mode 100644
index 0000000..94e642a
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/calxeda/l2ecc.txt
@@ -0,0 +1,15 @@
+Calxeda Highbank L2 cache ECC
+
+Properties:
+- compatible : Should be "calxeda,hb-sregs-l2-ecc"
+- reg : Address and size for ECC error interrupt clear registers.
+- interrupts : Should be single bit error interrupt, then double bit error
+	interrupt.
+
+Example:
+
+	sregs@fff3c200 {
+		compatible = "calxeda,hb-sregs-l2-ecc";
+		reg = <0xfff3c200 0x100>;
+		interrupts = <0 71 4  0 72 4>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt b/Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt
new file mode 100644
index 0000000..f770ac0
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt
@@ -0,0 +1,14 @@
+Calxeda DDR memory controller
+
+Properties:
+- compatible : Should be "calxeda,hb-ddr-ctrl"
+- reg : Address and size for DDR controller registers.
+- interrupts : Interrupt for DDR controller.
+
+Example:
+
+	memory-controller@fff00000 {
+		compatible = "calxeda,hb-ddr-ctrl";
+		reg = <0xfff00000 0x1000>;
+		interrupts = <0 91 4>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/tegra/emc.txt b/Documentation/devicetree/bindings/arm/tegra/emc.txt
deleted file mode 100644
index 09335f8..0000000
--- a/Documentation/devicetree/bindings/arm/tegra/emc.txt
+++ /dev/null
@@ -1,100 +0,0 @@
-Embedded Memory Controller
-
-Properties:
-- name : Should be emc
-- #address-cells : Should be 1
-- #size-cells : Should be 0
-- compatible : Should contain "nvidia,tegra20-emc".
-- reg : Offset and length of the register set for the device
-- nvidia,use-ram-code : If present, the sub-nodes will be addressed
-  and chosen using the ramcode board selector. If omitted, only one
-  set of tables can be present and said tables will be used
-  irrespective of ram-code configuration.
-
-Child device nodes describe the memory settings for different configurations and clock rates.
-
-Example:
-
-	emc@7000f400 {
-		#address-cells = < 1 >;
-		#size-cells = < 0 >;
-		compatible = "nvidia,tegra20-emc";
-		reg = <0x7000f4000 0x200>;
-	}
-
-
-Embedded Memory Controller ram-code table
-
-If the emc node has the nvidia,use-ram-code property present, then the
-next level of nodes below the emc table are used to specify which settings
-apply for which ram-code settings.
-
-If the emc node lacks the nvidia,use-ram-code property, this level is omitted
-and the tables are stored directly under the emc node (see below).
-
-Properties:
-
-- name : Should be emc-tables
-- nvidia,ram-code : the binary representation of the ram-code board strappings
-  for which this node (and children) are valid.
-
-
-
-Embedded Memory Controller configuration table
-
-This is a table containing the EMC register settings for the various
-operating speeds of the memory controller. They are always located as
-subnodes of the emc controller node.
-
-There are two ways of specifying which tables to use:
-
-* The simplest is if there is just one set of tables in the device tree,
-  and they will always be used (based on which frequency is used).
-  This is the preferred method, especially when firmware can fill in
-  this information based on the specific system information and just
-  pass it on to the kernel.
-
-* The slightly more complex one is when more than one memory configuration
-  might exist on the system.  The Tegra20 platform handles this during
-  early boot by selecting one out of possible 4 memory settings based
-  on a 2-pin "ram code" bootstrap setting on the board. The values of
-  these strappings can be read through a register in the SoC, and thus
-  used to select which tables to use.
-
-Properties:
-- name : Should be emc-table
-- compatible : Should contain "nvidia,tegra20-emc-table".
-- reg : either an opaque enumerator to tell different tables apart, or
-  the valid frequency for which the table should be used (in kHz).
-- clock-frequency : the clock frequency for the EMC at which this
-  table should be used (in kHz).
-- nvidia,emc-registers : a 46 word array of EMC registers to be programmed
-  for operation at the 'clock-frequency' setting.
-  The order and contents of the registers are:
-    RC, RFC, RAS, RP, R2W, W2R, R2P, W2P, RD_RCD, WR_RCD, RRD, REXT,
-    WDV, QUSE, QRST, QSAFE, RDV, REFRESH, BURST_REFRESH_NUM, PDEX2WR,
-    PDEX2RD, PCHG2PDEN, ACT2PDEN, AR2PDEN, RW2PDEN, TXSR, TCKE, TFAW,
-    TRPAB, TCLKSTABLE, TCLKSTOP, TREFBW, QUSE_EXTRA, FBIO_CFG6, ODT_WRITE,
-    ODT_READ, FBIO_CFG5, CFG_DIG_DLL, DLL_XFORM_DQS, DLL_XFORM_QUSE,
-    ZCAL_REF_CNT, ZCAL_WAIT_CNT, AUTO_CAL_INTERVAL, CFG_CLKTRIM_0,
-    CFG_CLKTRIM_1, CFG_CLKTRIM_2
-
-		emc-table@166000 {
-			reg = <166000>;
-			compatible = "nvidia,tegra20-emc-table";
-			clock-frequency = < 166000 >;
-			nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-						 0 0 0 0 >;
-		};
-
-		emc-table@333000 {
-			reg = <333000>;
-			compatible = "nvidia,tegra20-emc-table";
-			clock-frequency = < 333000 >;
-			nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-						 0 0 0 0 >;
-		};
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-emc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-emc.txt
new file mode 100644
index 0000000..4c33b29
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-emc.txt
@@ -0,0 +1,100 @@
+Embedded Memory Controller
+
+Properties:
+- name : Should be emc
+- #address-cells : Should be 1
+- #size-cells : Should be 0
+- compatible : Should contain "nvidia,tegra20-emc".
+- reg : Offset and length of the register set for the device
+- nvidia,use-ram-code : If present, the sub-nodes will be addressed
+  and chosen using the ramcode board selector. If omitted, only one
+  set of tables can be present and said tables will be used
+  irrespective of ram-code configuration.
+
+Child device nodes describe the memory settings for different configurations and clock rates.
+
+Example:
+
+	memory-controller@7000f400 {
+		#address-cells = < 1 >;
+		#size-cells = < 0 >;
+		compatible = "nvidia,tegra20-emc";
+		reg = <0x7000f4000 0x200>;
+	}
+
+
+Embedded Memory Controller ram-code table
+
+If the emc node has the nvidia,use-ram-code property present, then the
+next level of nodes below the emc table are used to specify which settings
+apply for which ram-code settings.
+
+If the emc node lacks the nvidia,use-ram-code property, this level is omitted
+and the tables are stored directly under the emc node (see below).
+
+Properties:
+
+- name : Should be emc-tables
+- nvidia,ram-code : the binary representation of the ram-code board strappings
+  for which this node (and children) are valid.
+
+
+
+Embedded Memory Controller configuration table
+
+This is a table containing the EMC register settings for the various
+operating speeds of the memory controller. They are always located as
+subnodes of the emc controller node.
+
+There are two ways of specifying which tables to use:
+
+* The simplest is if there is just one set of tables in the device tree,
+  and they will always be used (based on which frequency is used).
+  This is the preferred method, especially when firmware can fill in
+  this information based on the specific system information and just
+  pass it on to the kernel.
+
+* The slightly more complex one is when more than one memory configuration
+  might exist on the system.  The Tegra20 platform handles this during
+  early boot by selecting one out of possible 4 memory settings based
+  on a 2-pin "ram code" bootstrap setting on the board. The values of
+  these strappings can be read through a register in the SoC, and thus
+  used to select which tables to use.
+
+Properties:
+- name : Should be emc-table
+- compatible : Should contain "nvidia,tegra20-emc-table".
+- reg : either an opaque enumerator to tell different tables apart, or
+  the valid frequency for which the table should be used (in kHz).
+- clock-frequency : the clock frequency for the EMC at which this
+  table should be used (in kHz).
+- nvidia,emc-registers : a 46 word array of EMC registers to be programmed
+  for operation at the 'clock-frequency' setting.
+  The order and contents of the registers are:
+    RC, RFC, RAS, RP, R2W, W2R, R2P, W2P, RD_RCD, WR_RCD, RRD, REXT,
+    WDV, QUSE, QRST, QSAFE, RDV, REFRESH, BURST_REFRESH_NUM, PDEX2WR,
+    PDEX2RD, PCHG2PDEN, ACT2PDEN, AR2PDEN, RW2PDEN, TXSR, TCKE, TFAW,
+    TRPAB, TCLKSTABLE, TCLKSTOP, TREFBW, QUSE_EXTRA, FBIO_CFG6, ODT_WRITE,
+    ODT_READ, FBIO_CFG5, CFG_DIG_DLL, DLL_XFORM_DQS, DLL_XFORM_QUSE,
+    ZCAL_REF_CNT, ZCAL_WAIT_CNT, AUTO_CAL_INTERVAL, CFG_CLKTRIM_0,
+    CFG_CLKTRIM_1, CFG_CLKTRIM_2
+
+		emc-table@166000 {
+			reg = <166000>;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = < 166000 >;
+			nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 >;
+		};
+
+		emc-table@333000 {
+			reg = <333000>;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = < 333000 >;
+			nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 >;
+		};
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt
index c25a0a5..866d934 100644
--- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt
@@ -8,7 +8,7 @@ Required properties:
 - interrupts : Should contain MC General interrupt.
 
 Example:
-	mc {
+	memory-controller@0x7000f000 {
 		compatible = "nvidia,tegra20-mc";
 		reg = <0x7000f000 0x024
 		       0x7000f03c 0x3c4>;
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt
index e47e73f..bdf1a61 100644
--- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt
@@ -8,7 +8,7 @@ Required properties:
 - interrupts : Should contain MC General interrupt.
 
 Example:
-	mc {
+	memory-controller {
 		compatible = "nvidia,tegra30-mc";
 		reg = <0x7000f000 0x010
 		       0x7000f03c 0x1b4
diff --git a/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt b/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt
new file mode 100644
index 0000000..93986a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt
@@ -0,0 +1,30 @@
+* Compact Flash
+
+The Cavium Compact Flash device is connected to the Octeon Boot Bus,
+and is thus a child of the Boot Bus device.  It can read and write
+industry standard compact flash devices.
+
+Properties:
+- compatible: "cavium,ebt3000-compact-flash";
+
+  Compatibility with many Cavium evaluation boards.
+
+- reg: The base address of the the CF chip select banks.  Depending on
+  the device configuration, there may be one or two banks.
+
+- cavium,bus-width: The width of the connection to the CF devices.  Valid
+  values are 8 and 16.
+
+- cavium,true-ide: Optional, if present the CF connection is in True IDE mode.
+
+- cavium,dma-engine-handle: Optional, a phandle for the DMA Engine connected
+  to this device.
+
+Example:
+	compact-flash@5,0 {
+		compatible = "cavium,ebt3000-compact-flash";
+		reg = <5 0 0x10000>, <6 0 0x10000>;
+		cavium,bus-width = <16>;
+		cavium,true-ide;
+		cavium,dma-engine-handle = <&dma0>;
+	};
diff --git a/Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt b/Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt
new file mode 100644
index 0000000..9d6dcd3
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt
@@ -0,0 +1,49 @@
+* General Purpose Input Output (GPIO) bus.
+
+Properties:
+- compatible: "cavium,octeon-3860-gpio"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the GPIO unit's register bank.
+
+- gpio-controller: This is a GPIO controller.
+
+- #gpio-cells: Must be <2>.  The first cell is the GPIO pin.
+
+- interrupt-controller: The GPIO controller is also an interrupt
+  controller, many of its pins may be configured as an interrupt
+  source.
+
+- #interrupt-cells: Must be <2>.  The first cell is the GPIO pin
+   connected to the interrupt source.  The second cell is the interrupt
+   triggering protocol and may have one of four values:
+   1 - edge triggered on the rising edge.
+   2 - edge triggered on the falling edge
+   4 - level triggered active high.
+   8 - level triggered active low.
+
+- interrupts: Interrupt routing for each pin.
+
+Example:
+
+	gpio-controller@1070000000800 {
+		#gpio-cells = <2>;
+		compatible = "cavium,octeon-3860-gpio";
+		reg = <0x10700 0x00000800 0x0 0x100>;
+		gpio-controller;
+		/* Interrupts are specified by two parts:
+		 * 1) GPIO pin number (0..15)
+		 * 2) Triggering (1 - edge rising
+		 *		  2 - edge falling
+		 *		  4 - level active high
+		 *		  8 - level active low)
+		 */
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		/* The GPIO pin connect to 16 consecutive CUI bits */
+		interrupts = <0 16>, <0 17>, <0 18>, <0 19>,
+			     <0 20>, <0 21>, <0 22>, <0 23>,
+			     <0 24>, <0 25>, <0 26>, <0 27>,
+			     <0 28>, <0 29>, <0 30>, <0 31>;
+	};
diff --git a/Documentation/devicetree/bindings/gpio/gpio_i2c.txt b/Documentation/devicetree/bindings/gpio/gpio_i2c.txt
deleted file mode 100644
index 4f8ec94..0000000
--- a/Documentation/devicetree/bindings/gpio/gpio_i2c.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-Device-Tree bindings for i2c gpio driver
-
-Required properties:
-	- compatible = "i2c-gpio";
-	- gpios: sda and scl gpio
-
-
-Optional properties:
-	- i2c-gpio,sda-open-drain: sda as open drain
-	- i2c-gpio,scl-open-drain: scl as open drain
-	- i2c-gpio,scl-output-only: scl as output only
-	- i2c-gpio,delay-us: delay between GPIO operations (may depend on each platform)
-	- i2c-gpio,timeout-ms: timeout to get data
-
-Example nodes:
-
-i2c@0 {
-	compatible = "i2c-gpio";
-	gpios = <&pioA 23 0 /* sda */
-		 &pioA 24 0 /* scl */
-		>;
-	i2c-gpio,sda-open-drain;
-	i2c-gpio,scl-open-drain;
-	i2c-gpio,delay-us = <2>;	/* ~100 kHz */
-	#address-cells = <1>;
-	#size-cells = <0>;
-
-	rv3029c2@56 {
-		compatible = "rv3029c2";
-		reg = <0x56>;
-	};
-};
diff --git a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt
deleted file mode 100644
index 023c952..0000000
--- a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-NVIDIA Tegra GPIO controller
-
-Required properties:
-- compatible : "nvidia,tegra<chip>-gpio"
-- reg : Physical base address and length of the controller's registers.
-- interrupts : The interrupt outputs from the controller. For Tegra20,
-  there should be 7 interrupts specified, and for Tegra30, there should
-  be 8 interrupts specified.
-- #gpio-cells : Should be two. The first cell is the pin number and the
-  second cell is used to specify optional parameters:
-  - bit 0 specifies polarity (0 for normal, 1 for inverted)
-- gpio-controller : Marks the device node as a GPIO controller.
-- #interrupt-cells : Should be 2.
-  The first cell is the GPIO number.
-  The second cell is used to specify flags:
-    bits[3:0] trigger type and level flags:
-      1 = low-to-high edge triggered.
-      2 = high-to-low edge triggered.
-      4 = active high level-sensitive.
-      8 = active low level-sensitive.
-      Valid combinations are 1, 2, 3, 4, 8.
-- interrupt-controller : Marks the device node as an interrupt controller.
-
-Example:
-
-gpio: gpio@6000d000 {
-	compatible = "nvidia,tegra20-gpio";
-	reg = < 0x6000d000 0x1000 >;
-	interrupts = < 0 32 0x04
-		       0 33 0x04
-		       0 34 0x04
-		       0 35 0x04
-		       0 55 0x04
-		       0 87 0x04
-		       0 89 0x04 >;
-	#gpio-cells = <2>;
-	gpio-controller;
-	#interrupt-cells = <2>;
-	interrupt-controller;
-};
diff --git a/Documentation/devicetree/bindings/gpio/nvidia,tegra20-gpio.txt b/Documentation/devicetree/bindings/gpio/nvidia,tegra20-gpio.txt
new file mode 100644
index 0000000..023c952
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/nvidia,tegra20-gpio.txt
@@ -0,0 +1,40 @@
+NVIDIA Tegra GPIO controller
+
+Required properties:
+- compatible : "nvidia,tegra<chip>-gpio"
+- reg : Physical base address and length of the controller's registers.
+- interrupts : The interrupt outputs from the controller. For Tegra20,
+  there should be 7 interrupts specified, and for Tegra30, there should
+  be 8 interrupts specified.
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters:
+  - bit 0 specifies polarity (0 for normal, 1 for inverted)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+  The first cell is the GPIO number.
+  The second cell is used to specify flags:
+    bits[3:0] trigger type and level flags:
+      1 = low-to-high edge triggered.
+      2 = high-to-low edge triggered.
+      4 = active high level-sensitive.
+      8 = active low level-sensitive.
+      Valid combinations are 1, 2, 3, 4, 8.
+- interrupt-controller : Marks the device node as an interrupt controller.
+
+Example:
+
+gpio: gpio@6000d000 {
+	compatible = "nvidia,tegra20-gpio";
+	reg = < 0x6000d000 0x1000 >;
+	interrupts = < 0 32 0x04
+		       0 33 0x04
+		       0 34 0x04
+		       0 35 0x04
+		       0 55 0x04
+		       0 87 0x04
+		       0 89 0x04 >;
+	#gpio-cells = <2>;
+	gpio-controller;
+	#interrupt-cells = <2>;
+	interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/i2c/cavium-i2c.txt b/Documentation/devicetree/bindings/i2c/cavium-i2c.txt
new file mode 100644
index 0000000..dced82e
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/cavium-i2c.txt
@@ -0,0 +1,34 @@
+* Two Wire Serial Interface (TWSI) / I2C
+
+- compatible: "cavium,octeon-3860-twsi"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the TWSI/I2C bus controller register bank.
+
+- #address-cells: Must be <1>.
+
+- #size-cells: Must be <0>.  I2C addresses have no size component.
+
+- interrupts: A single interrupt specifier.
+
+- clock-frequency: The I2C bus clock rate in Hz.
+
+Example:
+	twsi0: i2c@1180000001000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "cavium,octeon-3860-twsi";
+		reg = <0x11800 0x00001000 0x0 0x200>;
+		interrupts = <0 45>;
+		clock-frequency = <100000>;
+
+		rtc@68 {
+			compatible = "dallas,ds1337";
+			reg = <0x68>;
+		};
+		tmp@4c {
+			compatible = "ti,tmp421";
+			reg = <0x4c>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/i2c/gpio-i2c.txt b/Documentation/devicetree/bindings/i2c/gpio-i2c.txt
new file mode 100644
index 0000000..4f8ec94
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/gpio-i2c.txt
@@ -0,0 +1,32 @@
+Device-Tree bindings for i2c gpio driver
+
+Required properties:
+	- compatible = "i2c-gpio";
+	- gpios: sda and scl gpio
+
+
+Optional properties:
+	- i2c-gpio,sda-open-drain: sda as open drain
+	- i2c-gpio,scl-open-drain: scl as open drain
+	- i2c-gpio,scl-output-only: scl as output only
+	- i2c-gpio,delay-us: delay between GPIO operations (may depend on each platform)
+	- i2c-gpio,timeout-ms: timeout to get data
+
+Example nodes:
+
+i2c@0 {
+	compatible = "i2c-gpio";
+	gpios = <&pioA 23 0 /* sda */
+		 &pioA 24 0 /* scl */
+		>;
+	i2c-gpio,sda-open-drain;
+	i2c-gpio,scl-open-drain;
+	i2c-gpio,delay-us = <2>;	/* ~100 kHz */
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	rv3029c2@56 {
+		compatible = "rv3029c2";
+		reg = <0x56>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt b/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
new file mode 100644
index 0000000..72683be
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
@@ -0,0 +1,23 @@
+* Tegra keyboard controller
+
+Required properties:
+- compatible: "nvidia,tegra20-kbc"
+
+Optional properties, in addition to those specified by the shared
+matrix-keyboard bindings:
+
+- linux,fn-keymap: a second keymap, same specification as the
+  matrix-keyboard-controller spec but to be used when the KEY_FN modifier
+  key is pressed.
+- nvidia,debounce-delay-ms: delay in milliseconds per row scan for debouncing
+- nvidia,repeat-delay-ms: delay in milliseconds before repeat starts
+- nvidia,ghost-filter: enable ghost filtering for this device
+- nvidia,wakeup-source: configure keyboard as a wakeup source for suspend/resume
+
+Example:
+
+keyboard: keyboard {
+	compatible = "nvidia,tegra20-kbc";
+	reg = <0x7000e200 0x100>;
+	nvidia,ghost-filter;
+};
diff --git a/Documentation/devicetree/bindings/input/tegra-kbc.txt b/Documentation/devicetree/bindings/input/tegra-kbc.txt
deleted file mode 100644
index 72683be..0000000
--- a/Documentation/devicetree/bindings/input/tegra-kbc.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-* Tegra keyboard controller
-
-Required properties:
-- compatible: "nvidia,tegra20-kbc"
-
-Optional properties, in addition to those specified by the shared
-matrix-keyboard bindings:
-
-- linux,fn-keymap: a second keymap, same specification as the
-  matrix-keyboard-controller spec but to be used when the KEY_FN modifier
-  key is pressed.
-- nvidia,debounce-delay-ms: delay in milliseconds per row scan for debouncing
-- nvidia,repeat-delay-ms: delay in milliseconds before repeat starts
-- nvidia,ghost-filter: enable ghost filtering for this device
-- nvidia,wakeup-source: configure keyboard as a wakeup source for suspend/resume
-
-Example:
-
-keyboard: keyboard {
-	compatible = "nvidia,tegra20-kbc";
-	reg = <0x7000e200 0x100>;
-	nvidia,ghost-filter;
-};
diff --git a/Documentation/devicetree/bindings/input/twl6040-vibra.txt b/Documentation/devicetree/bindings/input/twl6040-vibra.txt
deleted file mode 100644
index 5b1918b..0000000
--- a/Documentation/devicetree/bindings/input/twl6040-vibra.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-Vibra driver for the twl6040 family
-
-The vibra driver is a child of the twl6040 MFD dirver.
-Documentation/devicetree/bindings/mfd/twl6040.txt
-
-Required properties:
-- compatible : Must be "ti,twl6040-vibra";
-- interrupts: 4, Vibra overcurrent interrupt
-- vddvibl-supply: Regulator supplying the left vibra motor
-- vddvibr-supply: Regulator supplying the right vibra motor
-- vibldrv_res: Board specific left driver resistance
-- vibrdrv_res: Board specific right driver resistance
-- viblmotor_res: Board specific left motor resistance
-- vibrmotor_res: Board specific right motor resistance
-
-Optional properties:
-- vddvibl_uV: If the vddvibl default voltage need to be changed
-- vddvibr_uV: If the vddvibr default voltage need to be changed
-
-Example:
-/*
- * 8-channel high quality low-power audio codec
- * http://www.ti.com/lit/ds/symlink/twl6040.pdf
- */
-twl6040: twl6040@4b {
-	...
-	twl6040_vibra: twl6040@1 {
-		compatible = "ti,twl6040-vibra";
-		interrupts = <4>;
-		vddvibl-supply = <&vbat>;
-		vddvibr-supply = <&vbat>;
-		vibldrv_res = <8>;
-		vibrdrv_res = <3>;
-		viblmotor_res = <10>;
-		vibrmotor_res = <10>;
-	};
-};
diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
new file mode 100644
index 0000000..89fb543
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
@@ -0,0 +1,21 @@
+NVIDIA Tegra 30 IOMMU H/W, SMMU (System Memory Management Unit)
+
+Required properties:
+- compatible : "nvidia,tegra30-smmu"
+- reg : Should contain 3 register banks(address and length) for each
+  of the SMMU register blocks.
+- interrupts : Should contain MC General interrupt.
+- nvidia,#asids : # of ASIDs
+- dma-window : IOVA start address and length.
+- nvidia,ahb : phandle to the ahb bus connected to SMMU.
+
+Example:
+	smmu {
+		compatible = "nvidia,tegra30-smmu";
+		reg = <0x7000f010 0x02c
+		       0x7000f1f0 0x010
+		       0x7000f228 0x05c>;
+		nvidia,#asids = <4>;		/* # of ASIDs */
+		dma-window = <0 0x40000000>;	/* IOVA start & length */
+		nvidia,ahb = <&ahb>;
+	};
diff --git a/Documentation/devicetree/bindings/mips/cavium/bootbus.txt b/Documentation/devicetree/bindings/mips/cavium/bootbus.txt
new file mode 100644
index 0000000..6581478
--- /dev/null
+++ b/Documentation/devicetree/bindings/mips/cavium/bootbus.txt
@@ -0,0 +1,126 @@
+* Boot Bus
+
+The Octeon Boot Bus is a configurable parallel bus with 8 chip
+selects.  Each chip select is independently configurable.
+
+Properties:
+- compatible: "cavium,octeon-3860-bootbus"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the Boot Bus' register bank.
+
+- #address-cells: Must be <2>.  The first cell is the chip select
+   within the bootbus.  The second cell is the offset from the chip select.
+
+- #size-cells: Must be <1>.
+
+- ranges: There must be one one triplet of (child-bus-address,
+  parent-bus-address, length) for each active chip select.  If the
+  length element for any triplet is zero, the chip select is disabled,
+  making it inactive.
+
+The configuration parameters for each chip select are stored in child
+nodes.
+
+Configuration Properties:
+- compatible:  "cavium,octeon-3860-bootbus-config"
+
+- cavium,cs-index: A single cell indicating the chip select that
+  corresponds to this configuration.
+
+- cavium,t-adr: A cell specifying the ADR timing (in nS).
+
+- cavium,t-ce: A cell specifying the CE timing (in nS).
+
+- cavium,t-oe: A cell specifying the OE timing (in nS).
+
+- cavium,t-we: A cell specifying the WE timing (in nS).
+
+- cavium,t-rd-hld: A cell specifying the RD_HLD timing (in nS).
+
+- cavium,t-wr-hld: A cell specifying the WR_HLD timing (in nS).
+
+- cavium,t-pause: A cell specifying the PAUSE timing (in nS).
+
+- cavium,t-wait: A cell specifying the WAIT timing (in nS).
+
+- cavium,t-page: A cell specifying the PAGE timing (in nS).
+
+- cavium,t-rd-dly: A cell specifying the RD_DLY timing (in nS).
+
+- cavium,pages: A cell specifying the PAGES parameter (0 = 8 bytes, 1
+  = 2 bytes, 2 = 4 bytes, 3 = 8 bytes).
+
+- cavium,wait-mode: Optional.  If present, wait mode (WAITM) is selected.
+
+- cavium,page-mode: Optional.  If present, page mode (PAGEM) is selected.
+
+- cavium,bus-width: A cell specifying the WIDTH parameter (in bits) of
+  the bus for this chip select.
+
+- cavium,ale-mode: Optional.  If present, ALE mode is selected.
+
+- cavium,sam-mode: Optional.  If present, SAM mode is selected.
+
+- cavium,or-mode: Optional.  If present, OR mode is selected.
+
+Example:
+	bootbus: bootbus@1180000000000 {
+		compatible = "cavium,octeon-3860-bootbus";
+		reg = <0x11800 0x00000000 0x0 0x200>;
+		/* The chip select number and offset */
+		#address-cells = <2>;
+		/* The size of the chip select region */
+		#size-cells = <1>;
+		ranges = <0 0  0x0 0x1f400000  0xc00000>,
+			 <1 0  0x10000 0x30000000  0>,
+			 <2 0  0x10000 0x40000000  0>,
+			 <3 0  0x10000 0x50000000  0>,
+			 <4 0  0x0 0x1d020000  0x10000>,
+			 <5 0  0x0 0x1d040000  0x10000>,
+			 <6 0  0x0 0x1d050000  0x10000>,
+			 <7 0  0x10000 0x90000000  0>;
+
+			cavium,cs-config@0 {
+			compatible = "cavium,octeon-3860-bootbus-config";
+			cavium,cs-index = <0>;
+			cavium,t-adr  = <20>;
+			cavium,t-ce   = <60>;
+			cavium,t-oe   = <60>;
+			cavium,t-we   = <45>;
+			cavium,t-rd-hld = <35>;
+			cavium,t-wr-hld = <45>;
+			cavium,t-pause  = <0>;
+			cavium,t-wait   = <0>;
+			cavium,t-page   = <35>;
+			cavium,t-rd-dly = <0>;
+
+			cavium,pages     = <0>;
+			cavium,bus-width = <8>;
+		};
+		.
+		.
+		.
+		cavium,cs-config@6 {
+			compatible = "cavium,octeon-3860-bootbus-config";
+			cavium,cs-index = <6>;
+			cavium,t-adr  = <5>;
+			cavium,t-ce   = <300>;
+			cavium,t-oe   = <270>;
+			cavium,t-we   = <150>;
+			cavium,t-rd-hld = <100>;
+			cavium,t-wr-hld = <70>;
+			cavium,t-pause  = <0>;
+			cavium,t-wait   = <0>;
+			cavium,t-page   = <320>;
+			cavium,t-rd-dly = <0>;
+
+			cavium,pages     = <0>;
+			cavium,wait-mode;
+			cavium,bus-width = <16>;
+		};
+		.
+		.
+		.
+	};
diff --git a/Documentation/devicetree/bindings/mips/cavium/ciu.txt b/Documentation/devicetree/bindings/mips/cavium/ciu.txt
new file mode 100644
index 0000000..2c2d074
--- /dev/null
+++ b/Documentation/devicetree/bindings/mips/cavium/ciu.txt
@@ -0,0 +1,26 @@
+* Central Interrupt Unit
+
+Properties:
+- compatible: "cavium,octeon-3860-ciu"
+
+  Compatibility with all cn3XXX, cn5XXX and cn63XX SOCs.
+
+- interrupt-controller:  This is an interrupt controller.
+
+- reg: The base address of the CIU's register bank.
+
+- #interrupt-cells: Must be <2>.  The first cell is the bank within
+   the CIU and may have a value of 0 or 1.  The second cell is the bit
+   within the bank and may have a value between 0 and 63.
+
+Example:
+	interrupt-controller@1070000000000 {
+		compatible = "cavium,octeon-3860-ciu";
+		interrupt-controller;
+		/* Interrupts are specified by two parts:
+		 * 1) Controller register (0 or 1)
+		 * 2) Bit within the register (0..63)
+		 */
+		#interrupt-cells = <2>;
+		reg = <0x10700 0x00000000 0x0 0x7000>;
+	};
diff --git a/Documentation/devicetree/bindings/mips/cavium/ciu2.txt b/Documentation/devicetree/bindings/mips/cavium/ciu2.txt
new file mode 100644
index 0000000..0ec7ba8
--- /dev/null
+++ b/Documentation/devicetree/bindings/mips/cavium/ciu2.txt
@@ -0,0 +1,27 @@
+* Central Interrupt Unit
+
+Properties:
+- compatible: "cavium,octeon-6880-ciu2"
+
+  Compatibility with 68XX SOCs.
+
+- interrupt-controller:  This is an interrupt controller.
+
+- reg: The base address of the CIU's register bank.
+
+- #interrupt-cells: Must be <2>.  The first cell is the bank within
+  the CIU and may have a value between 0 and 63.  The second cell is
+  the bit within the bank and may also have a value between 0 and 63.
+
+Example:
+	interrupt-controller@1070100000000 {
+		compatible = "cavium,octeon-6880-ciu2";
+		interrupt-controller;
+		/* Interrupts are specified by two parts:
+		 * 1) Controller register (0..63)
+		 * 2) Bit within the register (0..63)
+		 */
+		#address-cells = <0>;
+		#interrupt-cells = <2>;
+		reg = <0x10701 0x00000000 0x0 0x4000000>;
+	};
diff --git a/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt b/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt
new file mode 100644
index 0000000..cb4291e
--- /dev/null
+++ b/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt
@@ -0,0 +1,21 @@
+* DMA Engine.
+
+The Octeon DMA Engine transfers between the Boot Bus and main memory.
+The DMA Engine will be refered to by phandle by any device that is
+connected to it.
+
+Properties:
+- compatible: "cavium,octeon-5750-bootbus-dma"
+
+  Compatibility with all cn52XX, cn56XX and cn6XXX SOCs.
+
+- reg: The base address of the DMA Engine's register bank.
+
+- interrupts: A single interrupt specifier.
+
+Example:
+	dma0: dma-engine@1180000000100 {
+		compatible = "cavium,octeon-5750-bootbus-dma";
+		reg = <0x11800 0x00000100 0x0 0x8>;
+		interrupts = <0 63>;
+	};
diff --git a/Documentation/devicetree/bindings/mips/cavium/uctl.txt b/Documentation/devicetree/bindings/mips/cavium/uctl.txt
new file mode 100644
index 0000000..aa66b9b
--- /dev/null
+++ b/Documentation/devicetree/bindings/mips/cavium/uctl.txt
@@ -0,0 +1,46 @@
+* UCTL USB controller glue
+
+Properties:
+- compatible: "cavium,octeon-6335-uctl"
+
+  Compatibility with all cn6XXX SOCs.
+
+- reg: The base address of the UCTL register bank.
+
+- #address-cells: Must be <2>.
+
+- #size-cells: Must be <2>.
+
+- ranges: Empty to signify direct mapping of the children.
+
+- refclk-frequency: A single cell containing the reference clock
+  frequency in Hz.
+
+- refclk-type: A string describing the reference clock connection
+  either "crystal" or "external".
+
+Example:
+	uctl@118006f000000 {
+		compatible = "cavium,octeon-6335-uctl";
+		reg = <0x11800 0x6f000000 0x0 0x100>;
+		ranges; /* Direct mapping */
+		#address-cells = <2>;
+		#size-cells = <2>;
+		/* 12MHz, 24MHz and 48MHz allowed */
+		refclk-frequency = <24000000>;
+		/* Either "crystal" or "external" */
+		refclk-type = "crystal";
+
+		ehci@16f0000000000 {
+			compatible = "cavium,octeon-6335-ehci","usb-ehci";
+			reg = <0x16f00 0x00000000 0x0 0x100>;
+			interrupts = <0 56>;
+			big-endian-regs;
+		};
+		ohci@16f0000000400 {
+			compatible = "cavium,octeon-6335-ohci","usb-ohci";
+			reg = <0x16f00 0x00000400 0x0 0x100>;
+			interrupts = <0 56>;
+			big-endian-regs;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/misc/at25.txt b/Documentation/devicetree/bindings/misc/at25.txt
new file mode 100644
index 0000000..ab3c327
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/at25.txt
@@ -0,0 +1,21 @@
+Atmel AT25 eeprom
+
+Required properties:
+- compatible : "atmel,at25".
+- reg : chip select number
+- spi-max-frequency : max spi frequency to use
+
+- at25,byte-len : total eeprom size in bytes
+- at25,addr-mode : addr-mode flags, as defined in include/linux/spi/eeprom.h
+- at25,page-size : size of the eeprom page
+
+Examples:
+at25@0 {
+	compatible = "atmel,at25";
+	reg = <0>
+	spi-max-frequency = <5000000>;
+
+	at25,byte-len = <0x8000>;
+	at25,addr-mode = <2>;
+	at25,page-size = <64>;
+};
diff --git a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt
index 0d93b4b..bd9be0b 100644
--- a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt
+++ b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt
@@ -3,21 +3,22 @@
 The Enhanced Secure Digital Host Controller provides an interface
 for MMC, SD, and SDIO types of memory cards.
 
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the sdhci-esdhc driver.
+
 Required properties:
-  - compatible : should be
-    "fsl,<chip>-esdhc", "fsl,esdhc"
-  - reg : should contain eSDHC registers location and length.
-  - interrupts : should contain eSDHC interrupt.
   - interrupt-parent : interrupt source phandle.
   - clock-frequency : specifies eSDHC base clock frequency.
-  - sdhci,wp-inverted : (optional) specifies that eSDHC controller
-    reports inverted write-protect state; New devices should use
-    the generic "wp-inverted" property.
-  - sdhci,1-bit-only : (optional) specifies that a controller can
-    only handle 1-bit data transfers. New devices should use the
-    generic "bus-width = <1>" property.
-  - sdhci,auto-cmd12: (optional) specifies that a controller can
-    only handle auto CMD12.
+
+Optional properties:
+  - sdhci,wp-inverted : specifies that eSDHC controller reports
+    inverted write-protect state; New devices should use the generic
+    "wp-inverted" property.
+  - sdhci,1-bit-only : specifies that a controller can only handle
+    1-bit data transfers. New devices should use the generic
+    "bus-width = <1>" property.
+  - sdhci,auto-cmd12: specifies that a controller can only handle auto
+    CMD12.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
index c7e404b..485e497 100644
--- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
+++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
@@ -3,17 +3,15 @@
 The Enhanced Secure Digital Host Controller on Freescale i.MX family
 provides an interface for MMC, SD, and SDIO types of memory cards.
 
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the sdhci-esdhc-imx driver.
+
 Required properties:
 - compatible : Should be "fsl,<chip>-esdhc"
-- reg : Should contain eSDHC registers location and length
-- interrupts : Should contain eSDHC interrupt
 
 Optional properties:
-- non-removable : Indicate the card is wired to host permanently
 - fsl,cd-internal : Indicate to use controller internal card detection
 - fsl,wp-internal : Indicate to use controller internal write protection
-- cd-gpios : Specify GPIOs for card detection
-- wp-gpios : Specify GPIOs for write protection
 
 Examples:
 
diff --git a/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt b/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt
index d64aea5..0e5e2ec 100644
--- a/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt
@@ -1,8 +1,9 @@
 MMC/SD/SDIO slot directly connected to a SPI bus
 
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the mmc_spi driver.
+
 Required properties:
-- compatible : should be "mmc-spi-slot".
-- reg : should specify SPI address (chip-select number).
 - spi-max-frequency : maximum frequency for this device (Hz).
 - voltage-ranges : two cells are required, first cell specifies minimum
   slot voltage (mV), second cell specifies maximum slot voltage (mV).
@@ -11,8 +12,7 @@ Required properties:
 Optional properties:
 - gpios : may specify GPIOs in this order: Card-Detect GPIO,
   Write-Protect GPIO. Note that this does not follow the
-  binding from mmc.txt, for historic reasons.
-- interrupts : the interrupt of a card detect interrupt.
+  binding from mmc.txt, for historical reasons.
 - interrupt-parent : the phandle for the interrupt controller that
   services interrupts for this device.
 
diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 6e70dcd..8a6811f 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -2,13 +2,17 @@ These properties are common to multiple MMC host controllers. Any host
 that requires the respective functionality should implement them using
 these definitions.
 
+Interpreted by the OF core:
+- reg: Registers location and length.
+- interrupts: Interrupts used by the MMC controller.
+
 Required properties:
 - bus-width: Number of data lines, can be <1>, <4>, or <8>
 
 Optional properties:
-- cd-gpios : Specify GPIOs for card detection, see gpio binding
-- wp-gpios : Specify GPIOs for write protection, see gpio binding
-- cd-inverted: when present, polarity on the wp gpio line is inverted
+- cd-gpios: Specify GPIOs for card detection, see gpio binding
+- wp-gpios: Specify GPIOs for write protection, see gpio binding
+- cd-inverted: when present, polarity on the cd gpio line is inverted
 - wp-inverted: when present, polarity on the wp gpio line is inverted
 - non-removable: non-removable slot (like eMMC)
 - max-frequency: maximum operating clock frequency
diff --git a/Documentation/devicetree/bindings/mmc/mmci.txt b/Documentation/devicetree/bindings/mmc/mmci.txt
index 14a81d5..2b584ca 100644
--- a/Documentation/devicetree/bindings/mmc/mmci.txt
+++ b/Documentation/devicetree/bindings/mmc/mmci.txt
@@ -1,19 +1,15 @@
 * ARM PrimeCell MultiMedia Card Interface (MMCI) PL180/1
 
-The ARM PrimeCell MMCI PL180 and PL181 provides and interface for
+The ARM PrimeCell MMCI PL180 and PL181 provides an interface for
 reading and writing to MultiMedia and SD cards alike.
 
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the mmci driver.
+
 Required properties:
 - compatible             : contains "arm,pl18x", "arm,primecell".
-- reg                    : contains pl18x registers and length.
-- interrupts             : contains the device IRQ(s).
 - arm,primecell-periphid : contains the PrimeCell Peripheral ID.
 
 Optional properties:
-- wp-gpios               : contains any write protect (ro) gpios
-- cd-gpios               : contains any card detection gpios
-- cd-inverted            : indicates whether the cd gpio is inverted
-- max-frequency          : contains the maximum operating frequency
-- bus-width              : number of data lines, can be <1>, <4>, or <8>
 - mmc-cap-mmc-highspeed  : indicates whether MMC is high speed capable
 - mmc-cap-sd-highspeed   : indicates whether SD is high speed capable
diff --git a/Documentation/devicetree/bindings/mmc/mxs-mmc.txt b/Documentation/devicetree/bindings/mmc/mxs-mmc.txt
index 14d870a..54949f6 100644
--- a/Documentation/devicetree/bindings/mmc/mxs-mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mxs-mmc.txt
@@ -3,16 +3,14 @@
 The Freescale MXS Synchronous Serial Ports (SSP) can act as a MMC controller
 to support MMC, SD, and SDIO types of memory cards.
 
+This file documents differences between the core properties in mmc.txt
+and the properties used by the mxsmmc driver.
+
 Required properties:
 - compatible: Should be "fsl,<chip>-mmc".  The supported chips include
   imx23 and imx28.
-- reg: Should contain registers location and length
 - interrupts: Should contain ERROR and DMA interrupts
 - fsl,ssp-dma-channel: APBH DMA channel for the SSP
-- bus-width: Number of data lines, can be <1>, <4>, or <8>
-
-Optional properties:
-- wp-gpios: Specify GPIOs for write protection
 
 Examples:
 
diff --git a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt
new file mode 100644
index 0000000..c6d7b11
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt
@@ -0,0 +1,25 @@
+* NVIDIA Tegra Secure Digital Host Controller
+
+This controller on Tegra family SoCs provides an interface for MMC, SD,
+and SDIO types of memory cards.
+
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the sdhci-tegra driver.
+
+Required properties:
+- compatible : Should be "nvidia,<chip>-sdhci"
+
+Optional properties:
+- power-gpios : Specify GPIOs for power control
+
+Example:
+
+sdhci@c8000200 {
+	compatible = "nvidia,tegra20-sdhci";
+	reg = <0xc8000200 0x200>;
+	interrupts = <47>;
+	cd-gpios = <&gpio 69 0>; /* gpio PI5 */
+	wp-gpios = <&gpio 57 0>; /* gpio PH1 */
+	power-gpios = <&gpio 155 0>; /* gpio PT3 */
+	bus-width = <8>;
+};
diff --git a/Documentation/devicetree/bindings/mmc/nvidia-sdhci.txt b/Documentation/devicetree/bindings/mmc/nvidia-sdhci.txt
deleted file mode 100644
index f77c303..0000000
--- a/Documentation/devicetree/bindings/mmc/nvidia-sdhci.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-* NVIDIA Tegra Secure Digital Host Controller
-
-This controller on Tegra family SoCs provides an interface for MMC, SD,
-and SDIO types of memory cards.
-
-Required properties:
-- compatible : Should be "nvidia,<chip>-sdhci"
-- reg : Should contain SD/MMC registers location and length
-- interrupts : Should contain SD/MMC interrupt
-- bus-width : Number of data lines, can be <1>, <4>, or <8>
-
-Optional properties:
-- cd-gpios : Specify GPIOs for card detection
-- wp-gpios : Specify GPIOs for write protection
-- power-gpios : Specify GPIOs for power control
-
-Example:
-
-sdhci@c8000200 {
-	compatible = "nvidia,tegra20-sdhci";
-	reg = <0xc8000200 0x200>;
-	interrupts = <47>;
-	cd-gpios = <&gpio 69 0>; /* gpio PI5 */
-	wp-gpios = <&gpio 57 0>; /* gpio PH1 */
-	power-gpios = <&gpio 155 0>; /* gpio PT3 */
-	bus-width = <8>;
-};
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
new file mode 100644
index 0000000..dbe98a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
@@ -0,0 +1,21 @@
+* Marvell sdhci-pxa v2/v3 controller
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
+
+Required properties:
+- compatible: Should be "mrvl,pxav2-mmc" or "mrvl,pxav3-mmc".
+
+Optional properties:
+- mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
+
+Example:
+
+sdhci@d4280800 {
+	compatible = "mrvl,pxav3-mmc";
+	reg = <0xd4280800 0x800>;
+	bus-width = <8>;
+	interrupts = <27>;
+	non-removable;
+	mrvl,clk-delay-cycles = <31>;
+};
diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
index 8a53958..be76a23 100644
--- a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
+++ b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
@@ -3,21 +3,20 @@
 The Highspeed MMC Host Controller on TI OMAP family
 provides an interface for MMC, SD, and SDIO types of memory cards.
 
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the omap_hsmmc driver.
+
 Required properties:
 - compatible:
  Should be "ti,omap2-hsmmc", for OMAP2 controllers
  Should be "ti,omap3-hsmmc", for OMAP3 controllers
  Should be "ti,omap4-hsmmc", for OMAP4 controllers
 - ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
-- reg : should contain hsmmc registers location and length
 
 Optional properties:
 ti,dual-volt: boolean, supports dual voltage cards
 <supply-name>-supply: phandle to the regulator device tree node
 "supply-name" examples are "vmmc", "vmmc_aux" etc
-bus-width: Number of data lines, default assumed is 1 if the property is missing.
-cd-gpios: GPIOs for card detection
-wp-gpios: GPIOs for write protection
 ti,non-removable: non-removable slot (like eMMC)
 ti,needs-special-reset: Requires a special softreset sequence
 
diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
new file mode 100644
index 0000000..d94edc0
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
@@ -0,0 +1,52 @@
+NXP LPC32xx SoC NAND SLC controller
+
+Required properties:
+- compatible: "nxp,lpc3220-slc"
+- reg: Address and size of the controller
+- nand-on-flash-bbt: Use bad block table on flash
+- gpios: GPIO specification for NAND write protect
+
+The following required properties are very controller specific. See the LPC32xx
+User Manual:
+- nxp,wdr-clks: Delay before Ready signal is tested on write (W_RDY)
+- nxp,rdr-clks: Delay before Ready signal is tested on read (R_RDY)
+(The following values are specified in Hz, to make them independent of actual
+clock speed:)
+- nxp,wwidth: Write pulse width (W_WIDTH)
+- nxp,whold: Write hold time (W_HOLD)
+- nxp,wsetup: Write setup time (W_SETUP)
+- nxp,rwidth: Read pulse width (R_WIDTH)
+- nxp,rhold: Read hold time (R_HOLD)
+- nxp,rsetup: Read setup time (R_SETUP)
+
+Optional subnodes:
+- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
+
+Example:
+
+	slc: flash@20020000 {
+		compatible = "nxp,lpc3220-slc";
+		reg = <0x20020000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		nxp,wdr-clks = <14>;
+		nxp,wwidth = <40000000>;
+		nxp,whold = <100000000>;
+		nxp,wsetup = <100000000>;
+		nxp,rdr-clks = <14>;
+		nxp,rwidth = <40000000>;
+		nxp,rhold = <66666666>;
+		nxp,rsetup = <100000000>;
+		nand-on-flash-bbt;
+		gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */
+
+		mtd0@00000000 {
+			label = "phy3250-boot";
+			reg = <0x00000000 0x00064000>;
+			read-only;
+		};
+
+		...
+
+	};
diff --git a/Documentation/devicetree/bindings/net/cavium-mdio.txt b/Documentation/devicetree/bindings/net/cavium-mdio.txt
new file mode 100644
index 0000000..04cb749
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/cavium-mdio.txt
@@ -0,0 +1,27 @@
+* System Management Interface (SMI) / MDIO
+
+Properties:
+- compatible: "cavium,octeon-3860-mdio"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the MDIO bus controller register bank.
+
+- #address-cells: Must be <1>.
+
+- #size-cells: Must be <0>.  MDIO addresses have no size component.
+
+Typically an MDIO bus might have several children.
+
+Example:
+	mdio@1180000001800 {
+		compatible = "cavium,octeon-3860-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x11800 0x00001800 0x0 0x40>;
+
+		ethernet-phy@0 {
+			...
+			reg = <0>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/net/cavium-mix.txt b/Documentation/devicetree/bindings/net/cavium-mix.txt
new file mode 100644
index 0000000..5da628d
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/cavium-mix.txt
@@ -0,0 +1,39 @@
+* MIX Ethernet controller.
+
+Properties:
+- compatible: "cavium,octeon-5750-mix"
+
+  Compatibility with all cn5XXX and cn6XXX SOCs populated with MIX
+  devices.
+
+- reg: The base addresses of four separate register banks.  The first
+  bank contains the MIX registers.  The second bank the corresponding
+  AGL registers.  The third bank are the AGL registers shared by all
+  MIX devices present.  The fourth bank is the AGL_PRT_CTL shared by
+  all MIX devices present.
+
+- cell-index: A single cell specifying which portion of the shared
+  register banks corresponds to this MIX device.
+
+- interrupts: Two interrupt specifiers.  The first is the MIX
+  interrupt routing and the second the routing for the AGL interrupts.
+
+- mac-address: Optional, the MAC address to assign to the device.
+
+- local-mac-address: Optional, the MAC address to assign to the device
+  if mac-address is not specified.
+
+- phy-handle: Optional, a phandle for the PHY device connected to this device.
+
+Example:
+	ethernet@1070000100800 {
+		compatible = "cavium,octeon-5750-mix";
+		reg = <0x10700 0x00100800 0x0 0x100>, /* MIX */
+		      <0x11800 0xE0000800 0x0 0x300>, /* AGL */
+		      <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED  */
+		      <0x11800 0xE0002008 0x0 0x8>;   /* AGL_PRT_CTL */
+		cell-index = <1>;
+		interrupts = <1 18>, < 1 46>;
+		local-mac-address = [ 00 0f b7 10 63 54 ];
+		phy-handle = <&phy1>;
+	};
diff --git a/Documentation/devicetree/bindings/net/cavium-pip.txt b/Documentation/devicetree/bindings/net/cavium-pip.txt
new file mode 100644
index 0000000..d4c53ba
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/cavium-pip.txt
@@ -0,0 +1,98 @@
+* PIP Ethernet nexus.
+
+The PIP Ethernet nexus can control several data packet input/output
+devices.  The devices have a two level grouping scheme.  There may be
+several interfaces, and each interface may have several ports.  These
+ports might be an individual Ethernet PHY.
+
+
+Properties for the PIP nexus:
+- compatible: "cavium,octeon-3860-pip"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the PIP's register bank.
+
+- #address-cells: Must be <1>.
+
+- #size-cells: Must be <0>.
+
+Properties for PIP interfaces which is a child the PIP nexus:
+- compatible: "cavium,octeon-3860-pip-interface"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The interface number.
+
+- #address-cells: Must be <1>.
+
+- #size-cells: Must be <0>.
+
+Properties for PIP port which is a child the PIP interface:
+- compatible: "cavium,octeon-3860-pip-port"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The port number within the interface group.
+
+- mac-address: Optional, the MAC address to assign to the device.
+
+- local-mac-address: Optional, the MAC address to assign to the device
+  if mac-address is not specified.
+
+- phy-handle: Optional, a phandle for the PHY device connected to this device.
+
+Example:
+
+	pip@11800a0000000 {
+		compatible = "cavium,octeon-3860-pip";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x11800 0xa0000000 0x0 0x2000>;
+
+		interface@0 {
+			compatible = "cavium,octeon-3860-pip-interface";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>; /* interface */
+
+			ethernet@0 {
+				compatible = "cavium,octeon-3860-pip-port";
+				reg = <0x0>; /* Port */
+				local-mac-address = [ 00 0f b7 10 63 60 ];
+				phy-handle = <&phy2>;
+			};
+			ethernet@1 {
+				compatible = "cavium,octeon-3860-pip-port";
+				reg = <0x1>; /* Port */
+				local-mac-address = [ 00 0f b7 10 63 61 ];
+				phy-handle = <&phy3>;
+			};
+			ethernet@2 {
+				compatible = "cavium,octeon-3860-pip-port";
+				reg = <0x2>; /* Port */
+				local-mac-address = [ 00 0f b7 10 63 62 ];
+				phy-handle = <&phy4>;
+			};
+			ethernet@3 {
+				compatible = "cavium,octeon-3860-pip-port";
+				reg = <0x3>; /* Port */
+				local-mac-address = [ 00 0f b7 10 63 63 ];
+				phy-handle = <&phy5>;
+			};
+		};
+
+		interface@1 {
+			compatible = "cavium,octeon-3860-pip-interface";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>; /* interface */
+
+			ethernet@0 {
+				compatible = "cavium,octeon-3860-pip-port";
+				reg = <0x0>; /* Port */
+				local-mac-address = [ 00 0f b7 10 63 64 ];
+				phy-handle = <&phy6>;
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/nvec/nvec_nvidia.txt b/Documentation/devicetree/bindings/nvec/nvec_nvidia.txt
deleted file mode 100644
index 5aeee53..0000000
--- a/Documentation/devicetree/bindings/nvec/nvec_nvidia.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-NVIDIA compliant embedded controller
-
-Required properties:
-- compatible : should be "nvidia,nvec".
-- reg : the iomem of the i2c slave controller
-- interrupts : the interrupt line of the i2c slave controller
-- clock-frequency : the frequency of the i2c bus
-- gpios : the gpio used for ec request
-- slave-addr: the i2c address of the slave controller
diff --git a/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt b/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt
new file mode 100644
index 0000000..5aeee53
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt
@@ -0,0 +1,9 @@
+NVIDIA compliant embedded controller
+
+Required properties:
+- compatible : should be "nvidia,nvec".
+- reg : the iomem of the i2c slave controller
+- interrupts : the interrupt line of the i2c slave controller
+- clock-frequency : the frequency of the i2c bus
+- gpios : the gpio used for ec request
+- slave-addr: the i2c address of the slave controller
diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index 5b7a408..bec5d57 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -10,6 +10,7 @@ Optional properties:
 - regulator-always-on: boolean, regulator should never be disabled
 - regulator-boot-on: bootloader/firmware enabled regulator
 - <name>-supply: phandle to the parent supply/regulator node
+- regulator-ramp-delay: ramp delay for regulator(in uV/uS)
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/regulator/twl-regulator.txt b/Documentation/devicetree/bindings/regulator/twl-regulator.txt
index 0c3395d..658749b 100644
--- a/Documentation/devicetree/bindings/regulator/twl-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/twl-regulator.txt
@@ -15,7 +15,6 @@ For twl6030 regulators/LDOs
   - "ti,twl6030-vusb" for VUSB LDO
   - "ti,twl6030-v1v8" for V1V8 LDO
   - "ti,twl6030-v2v1" for V2V1 LDO
-  - "ti,twl6030-clk32kg" for CLK32KG RESOURCE
   - "ti,twl6030-vdd1" for VDD1 SMPS
   - "ti,twl6030-vdd2" for VDD2 SMPS
   - "ti,twl6030-vdd3" for VDD3 SMPS
diff --git a/Documentation/devicetree/bindings/serial/cavium-uart.txt b/Documentation/devicetree/bindings/serial/cavium-uart.txt
new file mode 100644
index 0000000..87a6c37
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/cavium-uart.txt
@@ -0,0 +1,19 @@
+* Universal Asynchronous Receiver/Transmitter (UART)
+
+- compatible: "cavium,octeon-3860-uart"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the UART register bank.
+
+- interrupts: A single interrupt specifier.
+
+- current-speed: Optional, the current bit rate in bits per second.
+
+Example:
+	uart1: serial@1180000000c00 {
+		compatible = "cavium,octeon-3860-uart","ns16550";
+		reg = <0x11800 0x00000c00 0x0 0x400>;
+		current-speed = <115200>;
+		interrupts = <0 35>;
+	};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt
new file mode 100644
index 0000000..b77a97c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt
@@ -0,0 +1,59 @@
+NVIDIA Tegra audio complex
+
+Required properties:
+- compatible : "nvidia,tegra-audio-alc5632"
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the ALC5632's pins:
+
+  ALC5632 pins:
+
+  * SPK_OUTP
+  * SPK_OUTN
+  * HP_OUT_L
+  * HP_OUT_R
+  * AUX_OUT_P
+  * AUX_OUT_N
+  * LINE_IN_L
+  * LINE_IN_R
+  * PHONE_P
+  * PHONE_N
+  * MIC1_P
+  * MIC1_N
+  * MIC2_P
+  * MIC2_N
+  * MICBIAS1
+  * DMICDAT
+
+  Board connectors:
+
+  * Headset Stereophone
+  * Int Spk
+  * Headset Mic
+  * Digital Mic
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S controller
+- nvidia,audio-codec : The phandle of the ALC5632 audio codec
+
+Example:
+
+sound {
+	compatible = "nvidia,tegra-audio-alc5632-paz00",
+				 "nvidia,tegra-audio-alc5632";
+
+	nvidia,model = "Compal PAZ00";
+
+	nvidia,audio-routing =
+				"Int Spk", "SPK_OUTP",
+				"Int Spk", "SPK_OUTN",
+				"Headset Mic","MICBIAS1",
+				"MIC1_N", "Headset Mic",
+				"MIC1_P", "Headset Mic",
+				"Headset Stereophone", "HP_OUT_R",
+				"Headset Stereophone", "HP_OUT_L";
+
+	nvidia,i2s-controller = <&tegra_i2s1>;
+	nvidia,audio-codec = <&alc5632>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.txt
new file mode 100644
index 0000000..04b14cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.txt
@@ -0,0 +1,14 @@
+NVIDIA Tegra audio complex for TrimSlice
+
+Required properties:
+- compatible : "nvidia,tegra-audio-trimslice"
+- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
+- nvidia,audio-codec : The phandle of the WM8903 audio codec
+
+Example:
+
+sound {
+	compatible = "nvidia,tegra-audio-trimslice";
+	nvidia,i2s-controller = <&tegra_i2s1>;
+	nvidia,audio-codec = <&codec>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt
new file mode 100644
index 0000000..c4dd39c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt
@@ -0,0 +1,54 @@
+NVIDIA Tegra audio complex
+
+Required properties:
+- compatible : "nvidia,tegra-audio-wm8753"
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the WM8753's pins, and the jacks on the board:
+
+  WM8753 pins:
+
+  * LOUT1
+  * LOUT2
+  * ROUT1
+  * ROUT2
+  * MONO1
+  * MONO2
+  * OUT3
+  * OUT4
+  * LINE1
+  * LINE2
+  * RXP
+  * RXN
+  * ACIN
+  * ACOP
+  * MIC1N
+  * MIC1
+  * MIC2N
+  * MIC2
+  * Mic Bias
+
+  Board connectors:
+
+  * Headphone Jack
+  * Mic Jack
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
+- nvidia,audio-codec : The phandle of the WM8753 audio codec
+Example:
+
+sound {
+	compatible = "nvidia,tegra-audio-wm8753-whistler",
+		     "nvidia,tegra-audio-wm8753"
+	nvidia,model = "tegra-wm8753-harmony";
+
+	nvidia,audio-routing =
+		"Headphone Jack", "LOUT1",
+		"Headphone Jack", "ROUT1";
+
+	nvidia,i2s-controller = <&i2s1>;
+	nvidia,audio-codec = <&wm8753>;
+};
+
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt
new file mode 100644
index 0000000..d5b0da8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt
@@ -0,0 +1,71 @@
+NVIDIA Tegra audio complex
+
+Required properties:
+- compatible : "nvidia,tegra-audio-wm8903"
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the WM8903's pins, and the jacks on the board:
+
+  WM8903 pins:
+
+  * IN1L
+  * IN1R
+  * IN2L
+  * IN2R
+  * IN3L
+  * IN3R
+  * DMICDAT
+  * HPOUTL
+  * HPOUTR
+  * LINEOUTL
+  * LINEOUTR
+  * LOP
+  * LON
+  * ROP
+  * RON
+  * MICBIAS
+
+  Board connectors:
+
+  * Headphone Jack
+  * Int Spk
+  * Mic Jack
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
+- nvidia,audio-codec : The phandle of the WM8903 audio codec
+
+Optional properties:
+- nvidia,spkr-en-gpios : The GPIO that enables the speakers
+- nvidia,hp-mute-gpios : The GPIO that mutes the headphones
+- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in
+- nvidia,int-mic-en-gpios : The GPIO that enables the internal microphone
+- nvidia,ext-mic-en-gpios : The GPIO that enables the external microphone
+
+Example:
+
+sound {
+	compatible = "nvidia,tegra-audio-wm8903-harmony",
+		     "nvidia,tegra-audio-wm8903"
+	nvidia,model = "tegra-wm8903-harmony";
+
+	nvidia,audio-routing =
+		"Headphone Jack", "HPOUTR",
+		"Headphone Jack", "HPOUTL",
+		"Int Spk", "ROP",
+		"Int Spk", "RON",
+		"Int Spk", "LOP",
+		"Int Spk", "LON",
+		"Mic Jack", "MICBIAS",
+		"IN1L", "Mic Jack";
+
+	nvidia,i2s-controller = <&i2s1>;
+	nvidia,audio-codec = <&wm8903>;
+
+	nvidia,spkr-en-gpios = <&codec 2 0>;
+	nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+	nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
+	nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
+};
+
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-das.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-das.txt
new file mode 100644
index 0000000..6de3a7e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-das.txt
@@ -0,0 +1,12 @@
+NVIDIA Tegra 20 DAS (Digital Audio Switch) controller
+
+Required properties:
+- compatible : "nvidia,tegra20-das"
+- reg : Should contain DAS registers location and length
+
+Example:
+
+das@70000c00 {
+	compatible = "nvidia,tegra20-das";
+	reg = <0x70000c00 0x80>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt
new file mode 100644
index 0000000..0df2b5c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt
@@ -0,0 +1,17 @@
+NVIDIA Tegra 20 I2S controller
+
+Required properties:
+- compatible : "nvidia,tegra20-i2s"
+- reg : Should contain I2S registers location and length
+- interrupts : Should contain I2S interrupt
+- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
+  request selector for this I2S controller
+
+Example:
+
+i2s@70002800 {
+	compatible = "nvidia,tegra20-i2s";
+	reg = <0x70002800 0x200>;
+	interrupts = < 45 >;
+	nvidia,dma-request-selector = < &apbdma 2 >;
+};
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-alc5632.txt b/Documentation/devicetree/bindings/sound/tegra-audio-alc5632.txt
deleted file mode 100644
index b77a97c..0000000
--- a/Documentation/devicetree/bindings/sound/tegra-audio-alc5632.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-NVIDIA Tegra audio complex
-
-Required properties:
-- compatible : "nvidia,tegra-audio-alc5632"
-- nvidia,model : The user-visible name of this sound complex.
-- nvidia,audio-routing : A list of the connections between audio components.
-  Each entry is a pair of strings, the first being the connection's sink,
-  the second being the connection's source. Valid names for sources and
-  sinks are the ALC5632's pins:
-
-  ALC5632 pins:
-
-  * SPK_OUTP
-  * SPK_OUTN
-  * HP_OUT_L
-  * HP_OUT_R
-  * AUX_OUT_P
-  * AUX_OUT_N
-  * LINE_IN_L
-  * LINE_IN_R
-  * PHONE_P
-  * PHONE_N
-  * MIC1_P
-  * MIC1_N
-  * MIC2_P
-  * MIC2_N
-  * MICBIAS1
-  * DMICDAT
-
-  Board connectors:
-
-  * Headset Stereophone
-  * Int Spk
-  * Headset Mic
-  * Digital Mic
-
-- nvidia,i2s-controller : The phandle of the Tegra I2S controller
-- nvidia,audio-codec : The phandle of the ALC5632 audio codec
-
-Example:
-
-sound {
-	compatible = "nvidia,tegra-audio-alc5632-paz00",
-				 "nvidia,tegra-audio-alc5632";
-
-	nvidia,model = "Compal PAZ00";
-
-	nvidia,audio-routing =
-				"Int Spk", "SPK_OUTP",
-				"Int Spk", "SPK_OUTN",
-				"Headset Mic","MICBIAS1",
-				"MIC1_N", "Headset Mic",
-				"MIC1_P", "Headset Mic",
-				"Headset Stereophone", "HP_OUT_R",
-				"Headset Stereophone", "HP_OUT_L";
-
-	nvidia,i2s-controller = <&tegra_i2s1>;
-	nvidia,audio-codec = <&alc5632>;
-};
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt b/Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt
deleted file mode 100644
index 04b14cf..0000000
--- a/Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-NVIDIA Tegra audio complex for TrimSlice
-
-Required properties:
-- compatible : "nvidia,tegra-audio-trimslice"
-- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
-- nvidia,audio-codec : The phandle of the WM8903 audio codec
-
-Example:
-
-sound {
-	compatible = "nvidia,tegra-audio-trimslice";
-	nvidia,i2s-controller = <&tegra_i2s1>;
-	nvidia,audio-codec = <&codec>;
-};
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt b/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt
deleted file mode 100644
index c4dd39c..0000000
--- a/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-NVIDIA Tegra audio complex
-
-Required properties:
-- compatible : "nvidia,tegra-audio-wm8753"
-- nvidia,model : The user-visible name of this sound complex.
-- nvidia,audio-routing : A list of the connections between audio components.
-  Each entry is a pair of strings, the first being the connection's sink,
-  the second being the connection's source. Valid names for sources and
-  sinks are the WM8753's pins, and the jacks on the board:
-
-  WM8753 pins:
-
-  * LOUT1
-  * LOUT2
-  * ROUT1
-  * ROUT2
-  * MONO1
-  * MONO2
-  * OUT3
-  * OUT4
-  * LINE1
-  * LINE2
-  * RXP
-  * RXN
-  * ACIN
-  * ACOP
-  * MIC1N
-  * MIC1
-  * MIC2N
-  * MIC2
-  * Mic Bias
-
-  Board connectors:
-
-  * Headphone Jack
-  * Mic Jack
-
-- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
-- nvidia,audio-codec : The phandle of the WM8753 audio codec
-Example:
-
-sound {
-	compatible = "nvidia,tegra-audio-wm8753-whistler",
-		     "nvidia,tegra-audio-wm8753"
-	nvidia,model = "tegra-wm8753-harmony";
-
-	nvidia,audio-routing =
-		"Headphone Jack", "LOUT1",
-		"Headphone Jack", "ROUT1";
-
-	nvidia,i2s-controller = <&i2s1>;
-	nvidia,audio-codec = <&wm8753>;
-};
-
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt b/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt
deleted file mode 100644
index d5b0da8..0000000
--- a/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-NVIDIA Tegra audio complex
-
-Required properties:
-- compatible : "nvidia,tegra-audio-wm8903"
-- nvidia,model : The user-visible name of this sound complex.
-- nvidia,audio-routing : A list of the connections between audio components.
-  Each entry is a pair of strings, the first being the connection's sink,
-  the second being the connection's source. Valid names for sources and
-  sinks are the WM8903's pins, and the jacks on the board:
-
-  WM8903 pins:
-
-  * IN1L
-  * IN1R
-  * IN2L
-  * IN2R
-  * IN3L
-  * IN3R
-  * DMICDAT
-  * HPOUTL
-  * HPOUTR
-  * LINEOUTL
-  * LINEOUTR
-  * LOP
-  * LON
-  * ROP
-  * RON
-  * MICBIAS
-
-  Board connectors:
-
-  * Headphone Jack
-  * Int Spk
-  * Mic Jack
-
-- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
-- nvidia,audio-codec : The phandle of the WM8903 audio codec
-
-Optional properties:
-- nvidia,spkr-en-gpios : The GPIO that enables the speakers
-- nvidia,hp-mute-gpios : The GPIO that mutes the headphones
-- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in
-- nvidia,int-mic-en-gpios : The GPIO that enables the internal microphone
-- nvidia,ext-mic-en-gpios : The GPIO that enables the external microphone
-
-Example:
-
-sound {
-	compatible = "nvidia,tegra-audio-wm8903-harmony",
-		     "nvidia,tegra-audio-wm8903"
-	nvidia,model = "tegra-wm8903-harmony";
-
-	nvidia,audio-routing =
-		"Headphone Jack", "HPOUTR",
-		"Headphone Jack", "HPOUTL",
-		"Int Spk", "ROP",
-		"Int Spk", "RON",
-		"Int Spk", "LOP",
-		"Int Spk", "LON",
-		"Mic Jack", "MICBIAS",
-		"IN1L", "Mic Jack";
-
-	nvidia,i2s-controller = <&i2s1>;
-	nvidia,audio-codec = <&wm8903>;
-
-	nvidia,spkr-en-gpios = <&codec 2 0>;
-	nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
-	nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
-	nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
-};
-
diff --git a/Documentation/devicetree/bindings/sound/tegra20-das.txt b/Documentation/devicetree/bindings/sound/tegra20-das.txt
deleted file mode 100644
index 6de3a7e..0000000
--- a/Documentation/devicetree/bindings/sound/tegra20-das.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-NVIDIA Tegra 20 DAS (Digital Audio Switch) controller
-
-Required properties:
-- compatible : "nvidia,tegra20-das"
-- reg : Should contain DAS registers location and length
-
-Example:
-
-das@70000c00 {
-	compatible = "nvidia,tegra20-das";
-	reg = <0x70000c00 0x80>;
-};
diff --git a/Documentation/devicetree/bindings/sound/tegra20-i2s.txt b/Documentation/devicetree/bindings/sound/tegra20-i2s.txt
deleted file mode 100644
index 0df2b5c..0000000
--- a/Documentation/devicetree/bindings/sound/tegra20-i2s.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-NVIDIA Tegra 20 I2S controller
-
-Required properties:
-- compatible : "nvidia,tegra20-i2s"
-- reg : Should contain I2S registers location and length
-- interrupts : Should contain I2S interrupt
-- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
-  request selector for this I2S controller
-
-Example:
-
-i2s@70002800 {
-	compatible = "nvidia,tegra20-i2s";
-	reg = <0x70002800 0x200>;
-	interrupts = < 45 >;
-	nvidia,dma-request-selector = < &apbdma 2 >;
-};
diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra20-spi.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra20-spi.txt
new file mode 100644
index 0000000..6b9e518
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/nvidia,tegra20-spi.txt
@@ -0,0 +1,5 @@
+NVIDIA Tegra 2 SPI device
+
+Required properties:
+- compatible : should be "nvidia,tegra20-spi".
+- gpios : should specify GPIOs used for chipselect.
diff --git a/Documentation/devicetree/bindings/spi/spi_nvidia.txt b/Documentation/devicetree/bindings/spi/spi_nvidia.txt
deleted file mode 100644
index 6b9e518..0000000
--- a/Documentation/devicetree/bindings/spi/spi_nvidia.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-NVIDIA Tegra 2 SPI device
-
-Required properties:
-- compatible : should be "nvidia,tegra20-spi".
-- gpios : should specify GPIOs used for chipselect.
diff --git a/Documentation/devicetree/bindings/thermal/spear-thermal.txt b/Documentation/devicetree/bindings/thermal/spear-thermal.txt
new file mode 100644
index 0000000..93e3b67
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/spear-thermal.txt
@@ -0,0 +1,14 @@
+* SPEAr Thermal
+
+Required properties:
+- compatible : "st,thermal-spear1340"
+- reg : Address range of the thermal registers
+- st,thermal-flags: flags used to enable thermal sensor
+
+Example:
+
+	thermal@fc000000 {
+		compatible = "st,thermal-spear1340";
+		reg = <0xfc000000 0x1000>;
+		st,thermal-flags = <0x7000>;
+	};
diff --git a/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt b/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
new file mode 100644
index 0000000..0d439df
--- /dev/null
+++ b/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
@@ -0,0 +1,14 @@
+* NXP LPC32xx SoC High Speed UART
+
+Required properties:
+- compatible: Should be "nxp,lpc3220-hsuart"
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt
+
+Example:
+
+	uart1: serial@40014000 {
+		compatible = "nxp,lpc3220-hsuart";
+		reg = <0x40014000 0x1000>;
+		interrupts = <26 0>;
+	};
diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
index b8b27b0..0847fde 100644
--- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt
+++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
@@ -9,6 +9,7 @@ Required properties:
 	- "ns16750"
 	- "ns16850"
 	- "nvidia,tegra20-uart"
+	- "nxp,lpc3220-uart"
 	- "ibm,qpace-nwp-serial"
 	- "serial" if the port type is unknown.
 - reg : offset and length of the register set for the device.
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt
new file mode 100644
index 0000000..e9b005d
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt
@@ -0,0 +1,29 @@
+Tegra SOC USB controllers
+
+The device node for a USB controller that is part of a Tegra
+SOC is as described in the document "Open Firmware Recommended
+Practice : Universal Serial Bus" with the following modifications
+and additions :
+
+Required properties :
+ - compatible : Should be "nvidia,tegra20-ehci" for USB controllers
+   used in host mode.
+ - phy_type : Should be one of "ulpi" or "utmi".
+ - nvidia,vbus-gpio : If present, specifies a gpio that needs to be
+   activated for the bus to be powered.
+
+Required properties for phy_type == ulpi:
+  - nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
+
+Optional properties:
+  - dr_mode : dual role mode. Indicates the working mode for
+   nvidia,tegra20-ehci compatible controllers.  Can be "host", "peripheral",
+   or "otg".  Default to "host" if not defined for backward compatibility.
+      host means this is a host controller
+      peripheral means it is device controller
+      otg means it can operate as either ("on the go")
+  - nvidia,has-legacy-mode : boolean indicates whether this controller can
+    operate in legacy mode (as APX 2500 / 2600). In legacy mode some
+    registers are accessed through the APB_MISC base address instead of
+    the USB controller. Since this is a legacy issue it probably does not
+    warrant a compatible string of its own.
diff --git a/Documentation/devicetree/bindings/usb/tegra-usb.txt b/Documentation/devicetree/bindings/usb/tegra-usb.txt
deleted file mode 100644
index e9b005d..0000000
--- a/Documentation/devicetree/bindings/usb/tegra-usb.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-Tegra SOC USB controllers
-
-The device node for a USB controller that is part of a Tegra
-SOC is as described in the document "Open Firmware Recommended
-Practice : Universal Serial Bus" with the following modifications
-and additions :
-
-Required properties :
- - compatible : Should be "nvidia,tegra20-ehci" for USB controllers
-   used in host mode.
- - phy_type : Should be one of "ulpi" or "utmi".
- - nvidia,vbus-gpio : If present, specifies a gpio that needs to be
-   activated for the bus to be powered.
-
-Required properties for phy_type == ulpi:
-  - nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
-
-Optional properties:
-  - dr_mode : dual role mode. Indicates the working mode for
-   nvidia,tegra20-ehci compatible controllers.  Can be "host", "peripheral",
-   or "otg".  Default to "host" if not defined for backward compatibility.
-      host means this is a host controller
-      peripheral means it is device controller
-      otg means it can operate as either ("on the go")
-  - nvidia,has-legacy-mode : boolean indicates whether this controller can
-    operate in legacy mode (as APX 2500 / 2600). In legacy mode some
-    registers are accessed through the APB_MISC base address instead of
-    the USB controller. Since this is a legacy issue it probably does not
-    warrant a compatible string of its own.
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index fbb2411..94b0168 100755
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -29,7 +29,7 @@ use IO::Handle;
 		"af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
 		"lme2510c_s7395_old", "drxk", "drxk_terratec_h5",
 		"drxk_hauppauge_hvr930c", "tda10071", "it9135", "it9137",
-		"drxk_pctv");
+		"drxk_pctv", "drxk_terratec_htc_stick");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -676,6 +676,24 @@ sub drxk_terratec_h5 {
     "$fwfile"
 }
 
+sub drxk_terratec_htc_stick {
+    my $url = "http://ftp.terratec.de/Receiver/Cinergy_HTC_Stick/Updates/";
+    my $zipfile = "Cinergy_HTC_Stick_Drv_5.09.1202.00_XP_Vista_7.exe";
+    my $hash = "6722a2442a05423b781721fbc069ed5e";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
+    my $drvfile = "Cinergy HTC Stick/BDA Driver 5.09.1202.00/Windows 32 Bit/emOEM.sys";
+    my $fwfile = "dvb-usb-terratec-htc-stick-drxk.fw";
+
+    checkstandard();
+
+    wgetfile($zipfile, $url . $zipfile);
+    verify($zipfile, $hash);
+    unzip($zipfile, $tmpdir);
+    extract("$tmpdir/$drvfile", 0x4e5c0, 42692, "$fwfile");
+
+    "$fwfile"
+}
+
 sub it9135 {
 	my $sourcefile = "dvb-usb-it9135.zip";
 	my $url = "http://www.ite.com.tw/uploads/firmware/v3.6.0.0/$sourcefile";
diff --git a/Documentation/edac.txt b/Documentation/edac.txt
index 03df2b0..56c7e93 100644
--- a/Documentation/edac.txt
+++ b/Documentation/edac.txt
@@ -232,116 +232,20 @@ EDAC control and attribute files.
 
 
 In 'mcX' directories are EDAC control and attribute files for
-this 'X' instance of the memory controllers:
-
-
-Counter reset control file:
-
-	'reset_counters'
-
-	This write-only control file will zero all the statistical counters
-	for UE and CE errors.  Zeroing the counters will also reset the timer
-	indicating how long since the last counter zero.  This is useful
-	for computing errors/time.  Since the counters are always reset at
-	driver initialization time, no module/kernel parameter is available.
-
-	RUN TIME: echo "anything" >/sys/devices/system/edac/mc/mc0/counter_reset
-
-		This resets the counters on memory controller 0
-
-
-Seconds since last counter reset control file:
-
-	'seconds_since_reset'
-
-	This attribute file displays how many seconds have elapsed since the
-	last counter reset. This can be used with the error counters to
-	measure error rates.
-
-
-
-Memory Controller name attribute file:
-
-	'mc_name'
-
-	This attribute file displays the type of memory controller
-	that is being utilized.
-
-
-Total memory managed by this memory controller attribute file:
-
-	'size_mb'
-
-	This attribute file displays, in count of megabytes, of memory
-	that this instance of memory controller manages.
-
-
-Total Uncorrectable Errors count attribute file:
-
-	'ue_count'
-
-	This attribute file displays the total count of uncorrectable
-	errors that have occurred on this memory controller. If panic_on_ue
-	is set this counter will not have a chance to increment,
-	since EDAC will panic the system.
-
-
-Total UE count that had no information attribute fileY:
-
-	'ue_noinfo_count'
-
-	This attribute file displays the number of UEs that have occurred
-	with no information as to which DIMM slot is having errors.
-
-
-Total Correctable Errors count attribute file:
-
-	'ce_count'
-
-	This attribute file displays the total count of correctable
-	errors that have occurred on this memory controller. This
-	count is very important to examine. CEs provide early
-	indications that a DIMM is beginning to fail. This count
-	field should be monitored for non-zero values and report
-	such information to the system administrator.
-
-
-Total Correctable Errors count attribute file:
-
-	'ce_noinfo_count'
-
-	This attribute file displays the number of CEs that
-	have occurred wherewith no information as to which DIMM slot
-	is having errors. Memory is handicapped, but operational,
-	yet no information is available to indicate which slot
-	the failing memory is in. This count field should be also
-	be monitored for non-zero values.
-
-Device Symlink:
-
-	'device'
-
-	Symlink to the memory controller device.
-
-Sdram memory scrubbing rate:
-
-	'sdram_scrub_rate'
-
-	Read/Write attribute file that controls memory scrubbing. The scrubbing
-	rate is set by writing a minimum bandwidth in bytes/sec to the attribute
-	file. The rate will be translated to an internal value that gives at
-	least the specified rate.
-
-	Reading the file will return the actual scrubbing rate employed.
-
-	If configuration fails or memory scrubbing is not implemented, accessing
-	that attribute will fail.
+this 'X' instance of the memory controllers.
 
+For a description of the sysfs API, please see:
+	Documentation/ABI/testing/sysfs/devices-edac
 
 
 ============================================================================
 'csrowX' DIRECTORIES
 
+When CONFIG_EDAC_LEGACY_SYSFS is enabled, the sysfs will contain the
+csrowX directories. As this API doesn't work properly for Rambus, FB-DIMMs
+and modern Intel Memory Controllers, this is being deprecated in favor
+of dimmX directories.
+
 In the 'csrowX' directories are EDAC control and attribute files for
 this 'X' instance of csrow:
 
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 56000b3..5979c3e 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -13,6 +13,14 @@ Who:	Jim Cromie <jim.cromie@gmail.com>, Jason Baron <jbaron@redhat.com>
 
 ---------------------------
 
+What: /proc/sys/vm/nr_pdflush_threads
+When: 2012
+Why: Since pdflush is deprecated, the interface exported in /proc/sys/vm/
+     should be removed.
+Who: Wanpeng Li <liwp@linux.vnet.ibm.com>
+
+---------------------------
+
 What:	CONFIG_APM_CPU_IDLE, and its ability to call APM BIOS in idle
 When:	2012
 Why:	This optional sub-feature of APM is of dubious reliability,
@@ -249,15 +257,6 @@ Who:	Ravikiran Thirumalai <kiran@scalex86.org>
 
 ---------------------------
 
-What:	Code that is now under CONFIG_WIRELESS_EXT_SYSFS
-	(in net/core/net-sysfs.c)
-When:	3.5
-Why:	Over 1K .text/.data size reduction, data is available in other
-	ways (ioctls)
-Who:	Johannes Berg <johannes@sipsolutions.net>
-
----------------------------
-
 What:	sysfs ui for changing p4-clockmod parameters
 When:	September 2009
 Why:	See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and
@@ -414,21 +413,6 @@ Who:	Jean Delvare <khali@linux-fr.org>
 
 ----------------------------
 
-What:	xt_connlimit rev 0
-When:	2012
-Who:	Jan Engelhardt <jengelh@medozas.de>
-Files:	net/netfilter/xt_connlimit.c
-
-----------------------------
-
-What:	ipt_addrtype match include file
-When:	2012
-Why:	superseded by xt_addrtype
-Who:	Florian Westphal <fw@strlen.de>
-Files:	include/linux/netfilter_ipv4/ipt_addrtype.h
-
-----------------------------
-
 What:	i2c_driver.attach_adapter
 	i2c_driver.detach_adapter
 When:	September 2011
@@ -449,6 +433,19 @@ Who:	Hans Verkuil <hans.verkuil@cisco.com>
 
 ----------------------------
 
+What:	CONFIG_CFG80211_WEXT
+When:	as soon as distributions ship new wireless tools, ie. wpa_supplicant 1.0
+	and NetworkManager/connman/etc. that are able to use nl80211
+Why:	Wireless extensions are deprecated, and userland tools are moving to
+	using nl80211. New drivers are no longer using wireless extensions,
+	and while there might still be old drivers, both new drivers and new
+	userland no longer needs them and they can't be used for an feature
+	developed in the past couple of years. As such, compatibility with
+	wireless extensions in new drivers will be removed.
+Who:	Johannes Berg <johannes@sipsolutions.net>
+
+----------------------------
+
 What:	g_file_storage driver
 When:	3.8
 Why:	This driver has been superseded by g_mass_storage.
@@ -523,14 +520,6 @@ Who:	Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
 
 ----------------------------
 
-What:	kmap_atomic(page, km_type)
-When:	3.5
-Why:	The old kmap_atomic() with two arguments is deprecated, we only
-	keep it for backward compatibility for few cycles and then drop it.
-Who:	Cong Wang <amwang@redhat.com>
-
-----------------------------
-
 What:	get_robust_list syscall
 When:	2013
 Why:	There appear to be no production users of the get_robust_list syscall,
@@ -589,6 +578,13 @@ Why:	Remount currently allows changing bound subsystems and
 
 ----------------------------
 
+What:  xt_recent rev 0
+When:  2013
+Who:   Pablo Neira Ayuso <pablo@netfilter.org>
+Files: net/netfilter/xt_recent.c
+
+----------------------------
+
 What:	KVM debugfs statistics
 When:	2013
 Why:	KVM tracepoints provide mostly equivalent information in a much more
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 8e2da1e..e0cce2a 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -9,7 +9,7 @@ be able to use diff(1).
 
 --------------------------- dentry_operations --------------------------
 prototypes:
-	int (*d_revalidate)(struct dentry *, struct nameidata *);
+	int (*d_revalidate)(struct dentry *, unsigned int);
 	int (*d_hash)(const struct dentry *, const struct inode *,
 			struct qstr *);
 	int (*d_compare)(const struct dentry *, const struct inode *,
@@ -37,9 +37,8 @@ d_manage:	no		no		yes (ref-walk)	maybe
 
 --------------------------- inode_operations --------------------------- 
 prototypes:
-	int (*create) (struct inode *,struct dentry *,umode_t, struct nameidata *);
-	struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameid
-ata *);
+	int (*create) (struct inode *,struct dentry *,umode_t, bool);
+	struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
 	int (*link) (struct dentry *,struct inode *,struct dentry *);
 	int (*unlink) (struct inode *,struct dentry *);
 	int (*symlink) (struct inode *,struct dentry *,const char *);
@@ -62,6 +61,9 @@ ata *);
 	int (*removexattr) (struct dentry *, const char *);
 	int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
 	void (*update_time)(struct inode *, struct timespec *, int);
+	int (*atomic_open)(struct inode *, struct dentry *,
+				struct file *, unsigned open_flag,
+				umode_t create_mode, int *opened);
 
 locking rules:
 	all may block
@@ -89,6 +91,7 @@ listxattr:	no
 removexattr:	yes
 fiemap:		no
 update_time:	no
+atomic_open:	yes
 
 	Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 victim.
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 8c91d10..2bef2b3 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -355,12 +355,10 @@ protects *all* the dcache state of a given dentry.
 via rcu-walk path walk (basically, if the file can have had a path name in the
 vfs namespace).
 
-	i_dentry and i_rcu share storage in a union, and the vfs expects
-i_dentry to be reinitialized before it is freed, so an:
-
-  INIT_LIST_HEAD(&inode->i_dentry);
-
-must be done in the RCU callback.
+	Even though i_dentry and i_rcu share storage in a union, we will
+initialize the former in inode_init_always(), so just leave it alone in
+the callback.  It used to be necessary to clean it there, but not anymore
+(starting at 3.2).
 
 --
 [recommended]
@@ -433,3 +431,14 @@ release it yourself.
 	d_alloc_root() is gone, along with a lot of bugs caused by code
 misusing it.  Replacement: d_make_root(inode).  The difference is,
 d_make_root() drops the reference to inode if dentry allocation fails.  
+
+--
+[mandatory]
+	The witch is dead!  Well, 2/3 of it, anyway.  ->d_revalidate() and
+->lookup() do *not* take struct nameidata anymore; just the flags.
+--
+[mandatory]
+	->create() doesn't take struct nameidata *; unlike the previous
+two, it gets "is it an O_EXCL or equivalent?" boolean argument.  Note that
+local filesystems can ignore tha argument - they are guaranteed that the
+object doesn't exist.  It's remote/distributed ones that might care...
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index efd23f4..aa754e0 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -341,8 +341,8 @@ This describes how the VFS can manipulate an inode in your
 filesystem. As of kernel 2.6.22, the following members are defined:
 
 struct inode_operations {
-	int (*create) (struct inode *,struct dentry *, umode_t, struct nameidata *);
-	struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
+	int (*create) (struct inode *,struct dentry *, umode_t, bool);
+	struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
 	int (*link) (struct dentry *,struct inode *,struct dentry *);
 	int (*unlink) (struct inode *,struct dentry *);
 	int (*symlink) (struct inode *,struct dentry *,const char *);
@@ -364,6 +364,9 @@ struct inode_operations {
 	ssize_t (*listxattr) (struct dentry *, char *, size_t);
 	int (*removexattr) (struct dentry *, const char *);
 	void (*update_time)(struct inode *, struct timespec *, int);
+	int (*atomic_open)(struct inode *, struct dentry *,
+				struct file *, unsigned open_flag,
+				umode_t create_mode, int *opened);
 };
 
 Again, all methods are called without any locks being held, unless
@@ -476,6 +479,14 @@ otherwise noted.
   	an inode.  If this is not defined the VFS will update the inode itself
   	and call mark_inode_dirty_sync.
 
+  atomic_open: called on the last component of an open.  Using this optional
+  	method the filesystem can look up, possibly create and open the file in
+  	one atomic operation.  If it cannot perform this (e.g. the file type
+  	turned out to be wrong) it may signal this by returning 1 instead of
+  	usual 0 or -ve .  This method is only called if the last
+  	component is negative or needs lookup.  Cached positive dentries are
+  	still handled by f_op->open().
+
 The Address Space Object
 ========================
 
@@ -891,7 +902,7 @@ the VFS uses a default. As of kernel 2.6.22, the following members are
 defined:
 
 struct dentry_operations {
-	int (*d_revalidate)(struct dentry *, struct nameidata *);
+	int (*d_revalidate)(struct dentry *, unsigned int);
 	int (*d_hash)(const struct dentry *, const struct inode *,
 			struct qstr *);
 	int (*d_compare)(const struct dentry *, const struct inode *,
@@ -910,11 +921,11 @@ struct dentry_operations {
 	dcache. Most filesystems leave this as NULL, because all their
 	dentries in the dcache are valid
 
-	d_revalidate may be called in rcu-walk mode (nd->flags & LOOKUP_RCU).
+	d_revalidate may be called in rcu-walk mode (flags & LOOKUP_RCU).
 	If in rcu-walk mode, the filesystem must revalidate the dentry without
 	blocking or storing to the dentry, d_parent and d_inode should not be
-	used without care (because they can go NULL), instead nd->inode should
-	be used.
+	used without care (because they can change and, in d_inode case, even
+	become NULL under us).
 
 	If a situation is encountered that rcu-walk cannot handle, return
 	-ECHILD and it will be called again in ref-walk mode.
diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt
new file mode 100644
index 0000000..4627c42
--- /dev/null
+++ b/Documentation/hid/uhid.txt
@@ -0,0 +1,169 @@
+      UHID - User-space I/O driver support for HID subsystem
+     ========================================================
+
+The HID subsystem needs two kinds of drivers. In this document we call them:
+
+ 1. The "HID I/O Driver" is the driver that performs raw data I/O to the
+    low-level device. Internally, they register an hid_ll_driver structure with
+    the HID core. They perform device setup, read raw data from the device and
+    push it into the HID subsystem and they provide a callback so the HID
+    subsystem can send data to the device.
+
+ 2. The "HID Device Driver" is the driver that parses HID reports and reacts on
+    them. There are generic drivers like "generic-usb" and "generic-bluetooth"
+    which adhere to the HID specification and provide the standardizes features.
+    But there may be special drivers and quirks for each non-standard device out
+    there. Internally, they use the hid_driver structure.
+
+Historically, the USB stack was the first subsystem to provide an HID I/O
+Driver. However, other standards like Bluetooth have adopted the HID specs and
+may provide HID I/O Drivers, too. The UHID driver allows to implement HID I/O
+Drivers in user-space and feed the data into the kernel HID-subsystem.
+
+This allows user-space to operate on the same level as USB-HID, Bluetooth-HID
+and similar. It does not provide a way to write HID Device Drivers, though. Use
+hidraw for this purpose.
+
+There is an example user-space application in ./samples/uhid/uhid-example.c
+
+The UHID API
+------------
+
+UHID is accessed through a character misc-device. The minor-number is allocated
+dynamically so you need to rely on udev (or similar) to create the device node.
+This is /dev/uhid by default.
+
+If a new device is detected by your HID I/O Driver and you want to register this
+device with the HID subsystem, then you need to open /dev/uhid once for each
+device you want to register. All further communication is done by read()'ing or
+write()'ing "struct uhid_event" objects. Non-blocking operations are supported
+by setting O_NONBLOCK.
+
+struct uhid_event {
+        __u32 type;
+        union {
+                struct uhid_create_req create;
+                struct uhid_data_req data;
+                ...
+        } u;
+};
+
+The "type" field contains the ID of the event. Depending on the ID different
+payloads are sent. You must not split a single event across multiple read()'s or
+multiple write()'s. A single event must always be sent as a whole. Furthermore,
+only a single event can be sent per read() or write(). Pending data is ignored.
+If you want to handle multiple events in a single syscall, then use vectored
+I/O with readv()/writev().
+
+The first thing you should do is sending an UHID_CREATE event. This will
+register the device. UHID will respond with an UHID_START event. You can now
+start sending data to and reading data from UHID. However, unless UHID sends the
+UHID_OPEN event, the internally attached HID Device Driver has no user attached.
+That is, you might put your device asleep unless you receive the UHID_OPEN
+event. If you receive the UHID_OPEN event, you should start I/O. If the last
+user closes the HID device, you will receive an UHID_CLOSE event. This may be
+followed by an UHID_OPEN event again and so on. There is no need to perform
+reference-counting in user-space. That is, you will never receive multiple
+UHID_OPEN events without an UHID_CLOSE event. The HID subsystem performs
+ref-counting for you.
+You may decide to ignore UHID_OPEN/UHID_CLOSE, though. I/O is allowed even
+though the device may have no users.
+
+If you want to send data to the HID subsystem, you send an HID_INPUT event with
+your raw data payload. If the kernel wants to send data to the device, you will
+read an UHID_OUTPUT or UHID_OUTPUT_EV event.
+
+If your device disconnects, you should send an UHID_DESTROY event. This will
+unregister the device. You can now send UHID_CREATE again to register a new
+device.
+If you close() the fd, the device is automatically unregistered and destroyed
+internally.
+
+write()
+-------
+write() allows you to modify the state of the device and feed input data into
+the kernel. The following types are supported: UHID_CREATE, UHID_DESTROY and
+UHID_INPUT. The kernel will parse the event immediately and if the event ID is
+not supported, it will return -EOPNOTSUPP. If the payload is invalid, then
+-EINVAL is returned, otherwise, the amount of data that was read is returned and
+the request was handled successfully.
+
+  UHID_CREATE:
+  This creates the internal HID device. No I/O is possible until you send this
+  event to the kernel. The payload is of type struct uhid_create_req and
+  contains information about your device. You can start I/O now.
+
+  UHID_DESTROY:
+  This destroys the internal HID device. No further I/O will be accepted. There
+  may still be pending messages that you can receive with read() but no further
+  UHID_INPUT events can be sent to the kernel.
+  You can create a new device by sending UHID_CREATE again. There is no need to
+  reopen the character device.
+
+  UHID_INPUT:
+  You must send UHID_CREATE before sending input to the kernel! This event
+  contains a data-payload. This is the raw data that you read from your device.
+  The kernel will parse the HID reports and react on it.
+
+  UHID_FEATURE_ANSWER:
+  If you receive a UHID_FEATURE request you must answer with this request. You
+  must copy the "id" field from the request into the answer. Set the "err" field
+  to 0 if no error occured or to EIO if an I/O error occurred.
+  If "err" is 0 then you should fill the buffer of the answer with the results
+  of the feature request and set "size" correspondingly.
+
+read()
+------
+read() will return a queued ouput report. These output reports can be of type
+UHID_START, UHID_STOP, UHID_OPEN, UHID_CLOSE, UHID_OUTPUT or UHID_OUTPUT_EV. No
+reaction is required to any of them but you should handle them according to your
+needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads.
+
+  UHID_START:
+  This is sent when the HID device is started. Consider this as an answer to
+  UHID_CREATE. This is always the first event that is sent.
+
+  UHID_STOP:
+  This is sent when the HID device is stopped. Consider this as an answer to
+  UHID_DESTROY.
+  If the kernel HID device driver closes the device manually (that is, you
+  didn't send UHID_DESTROY) then you should consider this device closed and send
+  an UHID_DESTROY event. You may want to reregister your device, though. This is
+  always the last message that is sent to you unless you reopen the device with
+  UHID_CREATE.
+
+  UHID_OPEN:
+  This is sent when the HID device is opened. That is, the data that the HID
+  device provides is read by some other process. You may ignore this event but
+  it is useful for power-management. As long as you haven't received this event
+  there is actually no other process that reads your data so there is no need to
+  send UHID_INPUT events to the kernel.
+
+  UHID_CLOSE:
+  This is sent when there are no more processes which read the HID data. It is
+  the counterpart of UHID_OPEN and you may as well ignore this event.
+
+  UHID_OUTPUT:
+  This is sent if the HID device driver wants to send raw data to the I/O
+  device. You should read the payload and forward it to the device. The payload
+  is of type "struct uhid_data_req".
+  This may be received even though you haven't received UHID_OPEN, yet.
+
+  UHID_OUTPUT_EV:
+  Same as UHID_OUTPUT but this contains a "struct input_event" as payload. This
+  is called for force-feedback, LED or similar events which are received through
+  an input device by the HID subsystem. You should convert this into raw reports
+  and send them to your device similar to events of type UHID_OUTPUT.
+
+  UHID_FEATURE:
+  This event is sent if the kernel driver wants to perform a feature request as
+  described in the HID specs. The report-type and report-number are available in
+  the payload.
+  The kernel serializes feature requests so there will never be two in parallel.
+  However, if you fail to respond with a UHID_FEATURE_ANSWER in a time-span of 5
+  seconds, then the requests will be dropped and a new one might be sent.
+  Therefore, the payload also contains an "id" field that identifies every
+  request.
+
+Document by:
+  David Herrmann <dh.herrmann@googlemail.com>
diff --git a/Documentation/hwmon/da9052 b/Documentation/hwmon/da9052
new file mode 100644
index 0000000..ef89855
--- /dev/null
+++ b/Documentation/hwmon/da9052
@@ -0,0 +1,61 @@
+Supported chips:
+  * Dialog Semiconductors DA9052-BC and DA9053-AA/Bx PMICs
+    Prefix: 'da9052'
+    Datasheet: Datasheet is not publicly available.
+
+Authors: David Dajun Chen <dchen@diasemi.com>
+
+Description
+-----------
+
+The DA9052/53 provides an Analogue to Digital Converter (ADC) with 10 bits
+resolution and track and hold circuitry combined with an analogue input
+multiplexer. The analogue input multiplexer will allow conversion of up to 10
+different inputs. The track and hold circuit ensures stable input voltages at
+the input of the ADC during the conversion.
+
+The ADC is used to measure the following inputs:
+Channel 0: VDDOUT - measurement of the system voltage
+Channel 1: ICH - internal battery charger current measurement
+Channel 2: TBAT - output from the battery NTC
+Channel 3: VBAT - measurement of the battery voltage
+Channel 4: ADC_IN4 - high impedance input (0 - 2.5V)
+Channel 5: ADC_IN5 - high impedance input (0 - 2.5V)
+Channel 6: ADC_IN6 - high impedance input (0 - 2.5V)
+Channel 7: XY - TSI interface to measure the X and Y voltage of the touch
+	   screen resistive potentiometers
+Channel 8: Internal Tjunc. - sense (internal temp. sensor)
+Channel 9: VBBAT - measurement of the backup battery voltage
+
+By using sysfs attributes we can measure the system voltage VDDOUT, the battery
+charging current ICH, battery temperature TBAT, battery junction temperature
+TJUNC, battery voltage VBAT and the back up battery voltage VBBAT.
+
+Voltage Monitoring
+------------------
+
+Voltages are sampled by a 10 bit ADC.
+
+The battery voltage is calculated as:
+	Milli volt = ((ADC value * 1000) / 512) + 2500
+
+The backup battery voltage is calculated as:
+	Milli volt = (ADC value * 2500) / 512;
+
+The voltages on ADC channels 4, 5 and 6 are calculated as:
+	Milli volt = (ADC value * 2500) / 1023
+
+Temperature Monitoring
+----------------------
+
+Temperatures are sampled by a 10 bit ADC.  Junction and battery temperatures
+are monitored by the ADC channels.
+
+The junction temperature is calculated:
+	Degrees celsius = 1.708 * (TJUNC_RES - T_OFFSET) - 108.8
+The junction temperature attribute is supported by the driver.
+
+The battery temperature is calculated:
+	Degree Celcius = 1 / (t1 + 1/298)- 273
+where t1 = (1/B)* ln(( ADCval * 2.5)/(R25*ITBAT*255))
+Default values of R25, B, ITBAT are 10e3, 3380 and 50e-6 respectively.
diff --git a/Documentation/hwmon/submitting-patches b/Documentation/hwmon/submitting-patches
index 86f42e8..790f774 100644
--- a/Documentation/hwmon/submitting-patches
+++ b/Documentation/hwmon/submitting-patches
@@ -70,6 +70,9 @@ increase the chances of your change being accepted.
   review more difficult. It may also result in code which is more complicated
   than necessary. Use inline functions or just regular functions instead.
 
+* Use devres functions whenever possible to allocate resources. For rationale
+  and supported functions, please see Documentation/driver-model/devres.txt.
+
 * If the driver has a detect function, make sure it is silent. Debug messages
   and messages printed after a successful detection are acceptable, but it
   must not print messages such as "Chip XXX not found/supported".
diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4
index 475bb4a..1e6634f 100644
--- a/Documentation/i2c/busses/i2c-piix4
+++ b/Documentation/i2c/busses/i2c-piix4
@@ -8,6 +8,11 @@ Supported adapters:
     Datasheet: Only available via NDA from ServerWorks
   * ATI IXP200, IXP300, IXP400, SB600, SB700 and SB800 southbridges
     Datasheet: Not publicly available
+    SB700 register reference available at:
+    http://support.amd.com/us/Embedded_TechDocs/43009_sb7xx_rrg_pub_1.00.pdf
+  * AMD SP5100 (SB700 derivative found on some server mainboards)
+    Datasheet: Publicly available at the AMD website
+    http://support.amd.com/us/Embedded_TechDocs/44413.pdf
   * AMD Hudson-2
     Datasheet: Not publicly available
   * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
@@ -68,6 +73,10 @@ this driver on those mainboards.
 The ServerWorks Southbridges, the Intel 440MX, and the Victory66 are
 identical to the PIIX4 in I2C/SMBus support.
 
+The AMD SB700 and SP5100 chipsets implement two PIIX4-compatible SMBus
+controllers. If your BIOS initializes the secondary controller, it will
+be detected by this driver as an "Auxiliary SMBus Host Controller".
+
 If you own Force CPCI735 motherboard or other OSB4 based systems you may need
 to change the SMBus Interrupt Select register so the SMBus controller uses
 the SMI mode.
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index 5aa5337..3a94b0e 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -245,21 +245,17 @@ static int __init foo_init(void)
 {
 	return i2c_add_driver(&foo_driver);
 }
+module_init(foo_init);
 
 static void __exit foo_cleanup(void)
 {
 	i2c_del_driver(&foo_driver);
 }
+module_exit(foo_cleanup);
 
-/* Substitute your own name and email address */
-MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"
-MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices");
-
-/* a few non-GPL license types are also allowed */
-MODULE_LICENSE("GPL");
+The module_i2c_driver() macro can be used to reduce above code.
 
-module_init(foo_init);
-module_exit(foo_cleanup);
+module_i2c_driver(foo_driver);
 
 Note that some functions are marked by `__init'.  These functions can
 be removed after kernel booting (or module loading) is completed.
@@ -267,6 +263,17 @@ Likewise, functions marked by `__exit' are dropped by the compiler when
 the code is built into the kernel, as they would never be called.
 
 
+Driver Information
+==================
+
+/* Substitute your own name and email address */
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"
+MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices");
+
+/* a few non-GPL license types are also allowed */
+MODULE_LICENSE("GPL");
+
+
 Power Management
 ================
 
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 915f28c..170d838 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -88,6 +88,7 @@ Code  Seq#(hex)	Include File		Comments
 		and kernel/power/user.c
 '8'	all				SNP8023 advanced NIC card
 					<mailto:mcr@solidum.com>
+';'	64-72	linux/vfio.h
 '@'	00-0F	linux/radeonfb.h	conflict!
 '@'	00-0F	drivers/video/aty/aty128fb.c	conflict!
 'A'	00-1F	linux/apm_bios.h	conflict!
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index a92c5eb..de8d60c 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -526,7 +526,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
 	coherent_pool=nn[KMG]	[ARM,KNL]
 			Sets the size of memory pool for coherent, atomic dma
-			allocations if Contiguous Memory Allocator (CMA) is used.
+			allocations.
 
 	code_bytes	[X86] How many bytes of object code to print
 			in an oops report.
@@ -1134,7 +1134,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 		forcesac
 		soft
 		pt		[x86, IA-64]
-		group_mf	[x86, IA-64]
 
 
 	io7=		[HW] IO7 for Marvel based alpha systems
@@ -1351,6 +1350,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			* nohrst, nosrst, norst: suppress hard, soft
                           and both resets.
 
+			* rstonce: only attempt one reset during
+			  hot-unplug link recovery
+
 			* dump_id: dump IDENTIFY data.
 
 			If there are multiple matching configurations changing
@@ -2367,6 +2369,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			Set maximum number of finished RCU callbacks to process
 			in one batch.
 
+	rcutree.fanout_leaf=	[KNL,BOOT]
+			Increase the number of CPUs assigned to each
+			leaf rcu_node structure.  Useful for very large
+			systems.
+
 	rcutree.qhimark=	[KNL,BOOT]
 			Set threshold of queued
 			RCU callbacks over which batch limiting is disabled.
diff --git a/Documentation/leds/00-INDEX b/Documentation/leds/00-INDEX
index 29f481d..5fefe37 100644
--- a/Documentation/leds/00-INDEX
+++ b/Documentation/leds/00-INDEX
@@ -6,3 +6,5 @@ leds-lp5521.txt
 	- notes on how to use the leds-lp5521 driver.
 leds-lp5523.txt
 	- notes on how to use the leds-lp5523 driver.
+leds-lm3556.txt
+	- notes on how to use the leds-lm3556 driver.
diff --git a/Documentation/leds/leds-lm3556.txt b/Documentation/leds/leds-lm3556.txt
new file mode 100644
index 0000000..d9eb91b
--- /dev/null
+++ b/Documentation/leds/leds-lm3556.txt
@@ -0,0 +1,85 @@
+Kernel driver for lm3556
+========================
+
+*Texas Instrument:
+ 1.5 A Synchronous Boost LED Flash Driver w/ High-Side Current Source
+* Datasheet: http://www.national.com/ds/LM/LM3556.pdf
+
+Authors:
+	Daniel Jeong
+	Contact:Daniel Jeong(daniel.jeong-at-ti.com, gshark.jeong-at-gmail.com)
+
+Description
+-----------
+There are 3 functions in LM3556, Flash, Torch and Indicator.
+
+FLASH MODE
+In Flash Mode, the LED current source(LED) provides 16 target current levels
+from 93.75 mA to 1500 mA.The Flash currents are adjusted via the CURRENT
+CONTROL REGISTER(0x09).Flash mode is activated by the ENABLE REGISTER(0x0A),
+or by pulling the STROBE pin HIGH.
+LM3556 Flash can be controlled through sys/class/leds/flash/brightness file
+* if STROBE pin is enabled, below example control brightness only, and
+ON / OFF will be controlled by STROBE pin.
+
+Flash Example:
+OFF     : #echo 0 > sys/class/leds/flash/brightness
+93.75 mA: #echo 1 > sys/class/leds/flash/brightness
+... .....
+1500  mA: #echo 16 > sys/class/leds/flash/brightness
+
+TORCH MODE
+In Torch Mode, the current source(LED) is programmed via the CURRENT CONTROL
+REGISTER(0x09).Torch Mode is activated by the ENABLE REGISTER(0x0A) or by the
+hardware TORCH input.
+LM3556 torch can be controlled through sys/class/leds/torch/brightness file.
+* if TORCH pin is enabled, below example control brightness only,
+and ON / OFF will be controlled by TORCH pin.
+
+Torch Example:
+OFF     : #echo 0 > sys/class/leds/torch/brightness
+46.88 mA: #echo 1 > sys/class/leds/torch/brightness
+... .....
+375 mA  : #echo 8 > sys/class/leds/torch/brightness
+
+INDICATOR MODE
+Indicator pattern can be set through sys/class/leds/indicator/pattern file,
+and 4 patterns are pre-defined in indicator_pattern array.
+According to N-lank, Pulse time and N Period values, different pattern wiill
+be generated.If you want new patterns for your own device, change
+indicator_pattern array with your own values and INDIC_PATTERN_SIZE.
+Please refer datasheet for more detail about N-Blank, Pulse time and N Period.
+
+Indicator pattern example:
+pattern 0: #echo 0 > sys/class/leds/indicator/pattern
+....
+pattern 3: #echo 3 > sys/class/leds/indicator/pattern
+
+Indicator brightness can be controlled through
+sys/class/leds/indicator/brightness file.
+
+Example:
+OFF      : #echo 0 > sys/class/leds/indicator/brightness
+5.86 mA  : #echo 1 > sys/class/leds/indicator/brightness
+........
+46.875mA : #echo 8 > sys/class/leds/indicator/brightness
+
+Notes
+-----
+Driver expects it is registered using the i2c_board_info mechanism.
+To register the chip at address 0x63 on specific adapter, set the platform data
+according to include/linux/platform_data/leds-lm3556.h, set the i2c board info
+
+Example:
+	static struct i2c_board_info __initdata board_i2c_ch4[]	= {
+		{
+			 I2C_BOARD_INFO(LM3556_NAME, 0x63),
+			 .platform_data = &lm3556_pdata,
+		 },
+	};
+
+and register it in the platform init function
+
+Example:
+	board_register_i2c_bus(4, 400,
+				board_i2c_ch4, ARRAY_SIZE(board_i2c_ch4));
diff --git a/Documentation/leds/ledtrig-oneshot.txt b/Documentation/leds/ledtrig-oneshot.txt
new file mode 100644
index 0000000..07cd1fa
--- /dev/null
+++ b/Documentation/leds/ledtrig-oneshot.txt
@@ -0,0 +1,59 @@
+One-shot LED Trigger
+====================
+
+This is a LED trigger useful for signaling the user of an event where there are
+no clear trap points to put standard led-on and led-off settings.  Using this
+trigger, the application needs only to signal the trigger when an event has
+happened, than the trigger turns the LED on and than keeps it off for a
+specified amount of time.
+
+This trigger is meant to be usable both for sporadic and dense events.  In the
+first case, the trigger produces a clear single controlled blink for each
+event, while in the latter it keeps blinking at constant rate, as to signal
+that the events are arriving continuously.
+
+A one-shot LED only stays in a constant state when there are no events.  An
+additional "invert" property specifies if the LED has to stay off (normal) or
+on (inverted) when not rearmed.
+
+The trigger can be activated from user space on led class devices as shown
+below:
+
+  echo oneshot > trigger
+
+This adds the following sysfs attributes to the LED:
+
+  delay_on - specifies for how many milliseconds the LED has to stay at
+             LED_FULL brightness after it has been armed.
+             Default to 100 ms.
+
+  delay_off - specifies for how many milliseconds the LED has to stay at
+              LED_OFF brightness after it has been armed.
+              Default to 100 ms.
+
+  invert - reverse the blink logic.  If set to 0 (default) blink on for delay_on
+           ms, then blink off for delay_off ms, leaving the LED normally off.  If
+           set to 1, blink off for delay_off ms, then blink on for delay_on ms,
+           leaving the LED normally on.
+           Setting this value also immediately change the LED state.
+
+  shot - write any non-empty string to signal an events, this starts a blink
+         sequence if not already running.
+
+Example use-case: network devices, initialization:
+
+  echo oneshot > trigger # set trigger for this led
+  echo 33 > delay_on     # blink at 1 / (33 + 33) Hz on continuous traffic
+  echo 33 > delay_off
+
+interface goes up:
+
+  echo 1 > invert # set led as normally-on, turn the led on
+
+packet received/transmitted:
+
+  echo 1 > shot # led starts blinking, ignored if already blinking
+
+interface goes down
+
+  echo 0 > invert # set led as normally-off, turn the led off
diff --git a/Documentation/misc-devices/mei/mei.txt b/Documentation/misc-devices/mei/mei.txt
index 2785697..6ec7029 100644
--- a/Documentation/misc-devices/mei/mei.txt
+++ b/Documentation/misc-devices/mei/mei.txt
@@ -50,25 +50,25 @@ Intel MEI Driver
 The driver exposes a misc device called /dev/mei.
 
 An application maintains communication with an Intel ME feature while
-/dev/mei is open. The binding to a specific features is performed by calling
+/dev/mei is open. The binding to a specific feature is performed by calling
 MEI_CONNECT_CLIENT_IOCTL, which passes the desired UUID.
 The number of instances of an Intel ME feature that can be opened
 at the same time depends on the Intel ME feature, but most of the
 features allow only a single instance.
 
 The Intel AMT Host Interface (Intel AMTHI) feature supports multiple
-simultaneous user applications. Therefore, the Intel MEI driver handles
-this internally by maintaining request queues for the applications.
+simultaneous user connected applications. The Intel MEI driver
+handles this internally by maintaining request queues for the applications.
 
-The driver is oblivious to data that is passed between firmware feature
+The driver is transparent to data that are passed between firmware feature
 and host application.
 
 Because some of the Intel ME features can change the system
 configuration, the driver by default allows only a privileged
 user to access it.
 
-A code snippet for an application communicating with
-Intel AMTHI client:
+A code snippet for an application communicating with Intel AMTHI client:
+
 	struct mei_connect_client_data data;
 	fd = open(MEI_DEVICE);
 
@@ -185,7 +185,7 @@ The Intel AMT Watchdog is composed of two parts:
 	2) Intel MEI driver - connects to the watchdog feature, configures the
 	   watchdog and sends the heartbeats.
 
-The Intel MEI driver uses the kernel watchdog to configure the Intel AMT
+The Intel MEI driver uses the kernel watchdog API to configure the Intel AMT
 Watchdog and to send heartbeats to it. The default timeout of the
 watchdog is 120 seconds.
 
diff --git a/Documentation/networking/batman-adv.txt b/Documentation/networking/batman-adv.txt
index 75a5923..8f3ae4a 100644
--- a/Documentation/networking/batman-adv.txt
+++ b/Documentation/networking/batman-adv.txt
@@ -211,6 +211,11 @@ The debug output can be changed at runtime  using  the  file
 
 will enable debug messages for when routes change.
 
+Counters for different types of packets entering and leaving the
+batman-adv module are available through ethtool:
+
+# ethtool --statistics bat0
+
 
 BATCTL
 ------
diff --git a/Documentation/networking/caif/Linux-CAIF.txt b/Documentation/networking/caif/Linux-CAIF.txt
index e52fd62..0aa4bd3 100644
--- a/Documentation/networking/caif/Linux-CAIF.txt
+++ b/Documentation/networking/caif/Linux-CAIF.txt
@@ -19,60 +19,36 @@ and host. Currently, UART and Loopback are available for Linux.
 Architecture:
 ------------
 The implementation of CAIF is divided into:
-* CAIF Socket Layer, Kernel API, and  Net Device.
+* CAIF Socket Layer and GPRS IP Interface.
 * CAIF Core Protocol Implementation
 * CAIF Link Layer, implemented as NET devices.
 
 
   RTNL
    !
-   !	 +------+   +------+   +------+
-   !	+------+!  +------+!  +------+!
-   !	! Sock !!  !Kernel!!  ! Net  !!
-   !	! API  !+  ! API  !+  ! Dev  !+	  <- CAIF Client APIs
-   !	+------+   +------!   +------+
-   !	   !	      !		 !
-   !	   +----------!----------+
-   !		   +------+		  <- CAIF Protocol Implementation
-   +------->	   ! CAIF !
-		   ! Core !
-		   +------+
-	     +--------!--------+
-	     !		       !
-	  +------+	    +-----+
-	  !    	 !	    ! TTY !	  <- Link Layer (Net Devices)
-	  +------+	    +-----+
-
-
-Using the Kernel API
-----------------------
-The Kernel API is used for accessing CAIF channels from the
-kernel.
-The user of the API has to implement two callbacks for receive
-and control.
-The receive callback gives a CAIF packet as a SKB. The control
-callback will
-notify of channel initialization complete, and flow-on/flow-
-off.
-
-
-  struct caif_device caif_dev = {
-    .caif_config = {
-     .name = "MYDEV"
-     .type = CAIF_CHTY_AT
-    }
-   .receive_cb = my_receive,
-   .control_cb = my_control,
-  };
-  caif_add_device(&caif_dev);
-  caif_transmit(&caif_dev, skb);
-
-See the caif_kernel.h for details about the CAIF kernel API.
+   !	      +------+	 +------+
+   !	     +------+!	+------+!
+   !	     !	IP  !!	!Socket!!
+   +-------> !interf!+	! API  !+	<- CAIF Client APIs
+   !	     +------+	+------!
+   !		!	    !
+   !		+-----------+
+   !		      !
+   !		   +------+		<- CAIF Core Protocol
+   !		   ! CAIF !
+   !		   ! Core !
+   !		   +------+
+   !	   +----------!---------+
+   !	   !	      !		!
+   !	+------+   +-----+   +------+
+   +--> ! HSI  !   ! TTY !   ! USB  !	<- Link Layer (Net Devices)
+	+------+   +-----+   +------+
+
 
 
 I M P L E M E N T A T I O N
 ===========================
-===========================
+
 
 CAIF Core Protocol Layer
 =========================================
@@ -88,17 +64,13 @@ The Core CAIF implementation contains:
       -	Simple implementation of CAIF.
       -	Layered architecture (a la Streams), each layer in the CAIF
 	specification is implemented in a separate c-file.
-      -	Clients must implement PHY layer to access physical HW
-	with receive and transmit functions.
       -	Clients must call configuration function to add PHY layer.
       -	Clients must implement CAIF layer to consume/produce
 	CAIF payload with receive and transmit functions.
       -	Clients must call configuration function to add and connect the
 	Client layer.
       - When receiving / transmitting CAIF Packets (cfpkt), ownership is passed
-	to the called function (except for framing layers' receive functions
-	or if a transmit function returns an error, in which case the caller
-	must free the packet).
+	to the called function (except for framing layers' receive function)
 
 Layered Architecture
 --------------------
@@ -109,11 +81,6 @@ Implementation. The support functions include:
 	CAIF Packet has functions for creating, destroying and adding content
 	and for adding/extracting header and trailers to protocol packets.
 
-      - CFLST CAIF list implementation.
-
-      - CFGLUE CAIF Glue. Contains OS Specifics, such as memory
-	allocation, endianness, etc.
-
 The CAIF Protocol implementation contains:
 
       - CFCNFG CAIF Configuration layer. Configures the CAIF Protocol
@@ -128,7 +95,7 @@ The CAIF Protocol implementation contains:
 	control and remote shutdown requests.
 
       - CFVEI CAIF VEI layer. Handles CAIF AT Channels on VEI (Virtual
-        External Interface). This layer encodes/decodes VEI frames.
+	External Interface). This layer encodes/decodes VEI frames.
 
       - CFDGML CAIF Datagram layer. Handles CAIF Datagram layer (IP
 	traffic), encodes/decodes Datagram frames.
@@ -170,7 +137,7 @@ The CAIF Protocol implementation contains:
 	    +---------+	    +---------+
 		 !		!
 	    +---------+	    +---------+
-	    |         |	    | Serial  |
+	    |	      |	    | Serial  |
 	    |	      |	    | CFSERL  |
 	    +---------+	    +---------+
 
@@ -186,24 +153,20 @@ In this layered approach the following "rules" apply.
 		 layer->dn->transmit(layer->dn, packet);
 
 
-Linux Driver Implementation
+CAIF Socket and IP interface
 ===========================
 
-Linux GPRS Net Device and CAIF socket are implemented on top of the
-CAIF Core protocol. The Net device and CAIF socket have an instance of
+The IP interface and CAIF socket API are implemented on top of the
+CAIF Core protocol. The IP Interface and CAIF socket have an instance of
 'struct cflayer', just like the CAIF Core protocol stack.
 Net device and Socket implement the 'receive()' function defined by
 'struct cflayer', just like the rest of the CAIF stack. In this way, transmit and
 receive of packets is handled as by the rest of the layers: the 'dn->transmit()'
 function is called in order to transmit data.
 
-The layer on top of the CAIF Core implementation is
-sometimes referred to as the "Client layer".
-
-
 Configuration of Link Layer
 ---------------------------
-The Link Layer is implemented as Linux net devices (struct net_device).
+The Link Layer is implemented as Linux network devices (struct net_device).
 Payload handling and registration is done using standard Linux mechanisms.
 
 The CAIF Protocol relies on a loss-less link layer without implementing
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index ac29539..820f553 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -22,7 +22,8 @@ This file contains
       4.1.2 RAW socket option CAN_RAW_ERR_FILTER
       4.1.3 RAW socket option CAN_RAW_LOOPBACK
       4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS
-      4.1.5 RAW socket returned message flags
+      4.1.5 RAW socket option CAN_RAW_FD_FRAMES
+      4.1.6 RAW socket returned message flags
     4.2 Broadcast Manager protocol sockets (SOCK_DGRAM)
     4.3 connected transport protocols (SOCK_SEQPACKET)
     4.4 unconnected transport protocols (SOCK_DGRAM)
@@ -41,7 +42,8 @@ This file contains
       6.5.1 Netlink interface to set/get devices properties
       6.5.2 Setting the CAN bit-timing
       6.5.3 Starting and stopping the CAN network device
-    6.6 supported CAN hardware
+    6.6 CAN FD (flexible data rate) driver support
+    6.7 supported CAN hardware
 
   7 Socket CAN resources
 
@@ -232,16 +234,16 @@ solution for a couple of reasons:
   arbitration problems and error frames caused by the different
   ECUs. The occurrence of detected errors are important for diagnosis
   and have to be logged together with the exact timestamp. For this
-  reason the CAN interface driver can generate so called Error Frames
-  that can optionally be passed to the user application in the same
-  way as other CAN frames. Whenever an error on the physical layer
+  reason the CAN interface driver can generate so called Error Message
+  Frames that can optionally be passed to the user application in the
+  same way as other CAN frames. Whenever an error on the physical layer
   or the MAC layer is detected (e.g. by the CAN controller) the driver
-  creates an appropriate error frame. Error frames can be requested by
-  the user application using the common CAN filter mechanisms. Inside
-  this filter definition the (interested) type of errors may be
-  selected. The reception of error frames is disabled by default.
-  The format of the CAN error frame is briefly described in the Linux
-  header file "include/linux/can/error.h".
+  creates an appropriate error message frame. Error messages frames can
+  be requested by the user application using the common CAN filter
+  mechanisms. Inside this filter definition the (interested) type of
+  errors may be selected. The reception of error messages is disabled
+  by default. The format of the CAN error message frame is briefly
+  described in the Linux header file "include/linux/can/error.h".
 
 4. How to use Socket CAN
 ------------------------
@@ -273,7 +275,7 @@ solution for a couple of reasons:
 
     struct can_frame {
             canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
-            __u8    can_dlc; /* data length code: 0 .. 8 */
+            __u8    can_dlc; /* frame payload length in byte (0 .. 8) */
             __u8    data[8] __attribute__((aligned(8)));
     };
 
@@ -375,6 +377,51 @@ solution for a couple of reasons:
     nbytes = sendto(s, &frame, sizeof(struct can_frame),
                     0, (struct sockaddr*)&addr, sizeof(addr));
 
+  Remark about CAN FD (flexible data rate) support:
+
+  Generally the handling of CAN FD is very similar to the formerly described
+  examples. The new CAN FD capable CAN controllers support two different
+  bitrates for the arbitration phase and the payload phase of the CAN FD frame
+  and up to 64 bytes of payload. This extended payload length breaks all the
+  kernel interfaces (ABI) which heavily rely on the CAN frame with fixed eight
+  bytes of payload (struct can_frame) like the CAN_RAW socket. Therefore e.g.
+  the CAN_RAW socket supports a new socket option CAN_RAW_FD_FRAMES that
+  switches the socket into a mode that allows the handling of CAN FD frames
+  and (legacy) CAN frames simultaneously (see section 4.1.5).
+
+  The struct canfd_frame is defined in include/linux/can.h:
+
+    struct canfd_frame {
+            canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+            __u8    len;     /* frame payload length in byte (0 .. 64) */
+            __u8    flags;   /* additional flags for CAN FD */
+            __u8    __res0;  /* reserved / padding */
+            __u8    __res1;  /* reserved / padding */
+            __u8    data[64] __attribute__((aligned(8)));
+    };
+
+  The struct canfd_frame and the existing struct can_frame have the can_id,
+  the payload length and the payload data at the same offset inside their
+  structures. This allows to handle the different structures very similar.
+  When the content of a struct can_frame is copied into a struct canfd_frame
+  all structure elements can be used as-is - only the data[] becomes extended.
+
+  When introducing the struct canfd_frame it turned out that the data length
+  code (DLC) of the struct can_frame was used as a length information as the
+  length and the DLC has a 1:1 mapping in the range of 0 .. 8. To preserve
+  the easy handling of the length information the canfd_frame.len element
+  contains a plain length value from 0 .. 64. So both canfd_frame.len and
+  can_frame.can_dlc are equal and contain a length information and no DLC.
+  For details about the distinction of CAN and CAN FD capable devices and
+  the mapping to the bus-relevant data length code (DLC), see chapter 6.6.
+
+  The length of the two CAN(FD) frame structures define the maximum transfer
+  unit (MTU) of the CAN(FD) network interface and skbuff data length. Two
+  definitions are specified for CAN specific MTUs in include/linux/can.h :
+
+  #define CAN_MTU   (sizeof(struct can_frame))   == 16  => 'legacy' CAN frame
+  #define CANFD_MTU (sizeof(struct canfd_frame)) == 72  => CAN FD frame
+
   4.1 RAW protocol sockets with can_filters (SOCK_RAW)
 
   Using CAN_RAW sockets is extensively comparable to the commonly
@@ -383,7 +430,7 @@ solution for a couple of reasons:
   defaults are set at RAW socket binding time:
 
   - The filters are set to exactly one filter receiving everything
-  - The socket only receives valid data frames (=> no error frames)
+  - The socket only receives valid data frames (=> no error message frames)
   - The loopback of sent CAN frames is enabled (see chapter 3.2)
   - The socket does not receive its own sent frames (in loopback mode)
 
@@ -434,7 +481,7 @@ solution for a couple of reasons:
   4.1.2 RAW socket option CAN_RAW_ERR_FILTER
 
   As described in chapter 3.4 the CAN interface driver can generate so
-  called Error Frames that can optionally be passed to the user
+  called Error Message Frames that can optionally be passed to the user
   application in the same way as other CAN frames. The possible
   errors are divided into different error classes that may be filtered
   using the appropriate error mask. To register for every possible
@@ -472,7 +519,69 @@ solution for a couple of reasons:
     setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
                &recv_own_msgs, sizeof(recv_own_msgs));
 
-  4.1.5 RAW socket returned message flags
+  4.1.5 RAW socket option CAN_RAW_FD_FRAMES
+
+  CAN FD support in CAN_RAW sockets can be enabled with a new socket option
+  CAN_RAW_FD_FRAMES which is off by default. When the new socket option is
+  not supported by the CAN_RAW socket (e.g. on older kernels), switching the
+  CAN_RAW_FD_FRAMES option returns the error -ENOPROTOOPT.
+
+  Once CAN_RAW_FD_FRAMES is enabled the application can send both CAN frames
+  and CAN FD frames. OTOH the application has to handle CAN and CAN FD frames
+  when reading from the socket.
+
+    CAN_RAW_FD_FRAMES enabled:  CAN_MTU and CANFD_MTU are allowed
+    CAN_RAW_FD_FRAMES disabled: only CAN_MTU is allowed (default)
+
+  Example:
+    [ remember: CANFD_MTU == sizeof(struct canfd_frame) ]
+
+    struct canfd_frame cfd;
+
+    nbytes = read(s, &cfd, CANFD_MTU);
+
+    if (nbytes == CANFD_MTU) {
+            printf("got CAN FD frame with length %d\n", cfd.len);
+	    /* cfd.flags contains valid data */
+    } else if (nbytes == CAN_MTU) {
+            printf("got legacy CAN frame with length %d\n", cfd.len);
+	    /* cfd.flags is undefined */
+    } else {
+            fprintf(stderr, "read: invalid CAN(FD) frame\n");
+            return 1;
+    }
+
+    /* the content can be handled independently from the received MTU size */
+
+    printf("can_id: %X data length: %d data: ", cfd.can_id, cfd.len);
+    for (i = 0; i < cfd.len; i++)
+            printf("%02X ", cfd.data[i]);
+
+  When reading with size CANFD_MTU only returns CAN_MTU bytes that have
+  been received from the socket a legacy CAN frame has been read into the
+  provided CAN FD structure. Note that the canfd_frame.flags data field is
+  not specified in the struct can_frame and therefore it is only valid in
+  CANFD_MTU sized CAN FD frames.
+
+  As long as the payload length is <=8 the received CAN frames from CAN FD
+  capable CAN devices can be received and read by legacy sockets too. When
+  user-generated CAN FD frames have a payload length <=8 these can be send
+  by legacy CAN network interfaces too. Sending CAN FD frames with payload
+  length > 8 to a legacy CAN network interface returns an -EMSGSIZE error.
+
+  Implementation hint for new CAN applications:
+
+  To build a CAN FD aware application use struct canfd_frame as basic CAN
+  data structure for CAN_RAW based applications. When the application is
+  executed on an older Linux kernel and switching the CAN_RAW_FD_FRAMES
+  socket option returns an error: No problem. You'll get legacy CAN frames
+  or CAN FD frames and can process them the same way.
+
+  When sending to CAN devices make sure that the device is capable to handle
+  CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU.
+  The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall.
+
+  4.1.6 RAW socket returned message flags
 
   When using recvmsg() call, the msg->msg_flags may contain following flags:
 
@@ -527,7 +636,7 @@ solution for a couple of reasons:
 
     rcvlist_all - list for unfiltered entries (no filter operations)
     rcvlist_eff - list for single extended frame (EFF) entries
-    rcvlist_err - list for error frames masks
+    rcvlist_err - list for error message frames masks
     rcvlist_fil - list for mask/value filters
     rcvlist_inv - list for mask/value filters (inverse semantic)
     rcvlist_sff - list for single standard frame (SFF) entries
@@ -573,10 +682,13 @@ solution for a couple of reasons:
     dev->type  = ARPHRD_CAN; /* the netdevice hardware type */
     dev->flags = IFF_NOARP;  /* CAN has no arp */
 
-    dev->mtu   = sizeof(struct can_frame);
+    dev->mtu = CAN_MTU; /* sizeof(struct can_frame) -> legacy CAN interface */
 
-  The struct can_frame is the payload of each socket buffer in the
-  protocol family PF_CAN.
+    or alternative, when the controller supports CAN with flexible data rate:
+    dev->mtu = CANFD_MTU; /* sizeof(struct canfd_frame) -> CAN FD interface */
+
+  The struct can_frame or struct canfd_frame is the payload of each socket
+  buffer (skbuff) in the protocol family PF_CAN.
 
   6.2 local loopback of sent frames
 
@@ -784,15 +896,41 @@ solution for a couple of reasons:
     $ ip link set canX type can restart-ms 100
 
   Alternatively, the application may realize the "bus-off" condition
-  by monitoring CAN error frames and do a restart when appropriate with
-  the command:
+  by monitoring CAN error message frames and do a restart when
+  appropriate with the command:
 
     $ ip link set canX type can restart
 
-  Note that a restart will also create a CAN error frame (see also
-  chapter 3.4).
+  Note that a restart will also create a CAN error message frame (see
+  also chapter 3.4).
+
+  6.6 CAN FD (flexible data rate) driver support
+
+  CAN FD capable CAN controllers support two different bitrates for the
+  arbitration phase and the payload phase of the CAN FD frame. Therefore a
+  second bittiming has to be specified in order to enable the CAN FD bitrate.
+
+  Additionally CAN FD capable CAN controllers support up to 64 bytes of
+  payload. The representation of this length in can_frame.can_dlc and
+  canfd_frame.len for userspace applications and inside the Linux network
+  layer is a plain value from 0 .. 64 instead of the CAN 'data length code'.
+  The data length code was a 1:1 mapping to the payload length in the legacy
+  CAN frames anyway. The payload length to the bus-relevant DLC mapping is
+  only performed inside the CAN drivers, preferably with the helper
+  functions can_dlc2len() and can_len2dlc().
+
+  The CAN netdevice driver capabilities can be distinguished by the network
+  devices maximum transfer unit (MTU):
+
+  MTU = 16 (CAN_MTU)   => sizeof(struct can_frame)   => 'legacy' CAN device
+  MTU = 72 (CANFD_MTU) => sizeof(struct canfd_frame) => CAN FD capable device
+
+  The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall.
+  N.B. CAN FD capable devices can also handle and send legacy CAN frames.
+
+  FIXME: Add details about the CAN FD controller configuration when available.
 
-  6.6 Supported CAN hardware
+  6.7 Supported CAN hardware
 
   Please check the "Kconfig" file in "drivers/net/can" to get an actual
   list of the support CAN hardware. On the Socket CAN project website
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 6f896b9..99d0e05 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -862,6 +862,11 @@ accept_local - BOOLEAN
 	local interfaces over the wire and have them accepted properly.
 	default FALSE
 
+route_localnet - BOOLEAN
+	Do not consider loopback addresses as martian source or destination
+	while routing. This enables the use of 127/8 for local routing purposes.
+	default FALSE
+
 rp_filter - INTEGER
 	0 - No source validation.
 	1 - Strict mode as defined in RFC3704 Strict Reverse Path
diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt
index 211831d..c0f62ae 100644
--- a/Documentation/power/power_supply_class.txt
+++ b/Documentation/power/power_supply_class.txt
@@ -112,6 +112,10 @@ CHARGE_COUNTER - the current charge counter (in µAh).  This could easily
 be negative; there is no empty or full value.  It is only useful for
 relative, time-based measurements.
 
+CONSTANT_CHARGE_CURRENT - constant charge current programmed by charger.
+
+CONSTANT_CHARGE_VOLTAGE - constant charge voltage programmed by charger.
+
 ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.
 
 CAPACITY - capacity in percents.
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt
index ac190cf..92341b8 100644
--- a/Documentation/power/swsusp.txt
+++ b/Documentation/power/swsusp.txt
@@ -33,6 +33,11 @@ echo shutdown > /sys/power/disk; echo disk > /sys/power/state
 
 echo platform > /sys/power/disk; echo disk > /sys/power/state
 
+. If you would like to write hibernation image to swap and then suspend
+to RAM (provided your platform supports it), you can try
+
+echo suspend > /sys/power/disk; echo disk > /sys/power/state
+
 . If you have SATA disks, you'll need recent kernels with SATA suspend
 support. For suspend and resume to work, make sure your disk drivers
 are built into kernel -- not modules. [There's way to make
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index 5df176e..d8d168f 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -56,6 +56,7 @@ Struct Resources:
 MAC/FDDI addresses:
 
 	%pM	00:01:02:03:04:05
+	%pMR	05:04:03:02:01:00
 	%pMF	00-01-02-03-04-05
 	%pm	000102030405
 
@@ -67,6 +68,10 @@ MAC/FDDI addresses:
 	the 'M' specifier to use dash ('-') separators instead of the default
 	separator.
 
+	For Bluetooth addresses the 'R' specifier shall be used after the 'M'
+	specifier to use reversed byte order suitable for visual interpretation
+	of Bluetooth addresses which are in the little endian order.
+
 IPv4 addresses:
 
 	%pI4	1.2.3.4
diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt
index 4ba7db2..59a74a8 100644
--- a/Documentation/ramoops.txt
+++ b/Documentation/ramoops.txt
@@ -40,6 +40,12 @@ corrupt, but usually it is restorable.
 Setting the ramoops parameters can be done in 2 different manners:
  1. Use the module parameters (which have the names of the variables described
  as before).
+ For quick debugging, you can also reserve parts of memory during boot
+ and then use the reserved memory for ramoops. For example, assuming a machine
+ with > 128 MB of memory, the following kernel command line will tell the
+ kernel to use only the first 128 MB of memory, and place ECC-protected ramoops
+ region at 128 MB boundary:
+ "mem=128M ramoops.mem_address=0x8000000 ramoops.ecc=1"
  2. Use a platform device and set the platform data. The parameters can then
  be set through that platform data. An example of doing that is:
 
@@ -70,6 +76,14 @@ if (ret) {
 	return ret;
 }
 
+You can specify either RAM memory or peripheral devices' memory. However, when
+specifying RAM, be sure to reserve the memory by issuing memblock_reserve()
+very early in the architecture code, e.g.:
+
+#include <linux/memblock.h>
+
+memblock_reserve(ramoops_data.mem_address, ramoops_data.mem_size);
+
 3. Dump format
 
 The data dump begins with a header, currently defined as "====" followed by a
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 03f7897..2ea8cf2 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -15,19 +15,23 @@ ALC260
 
 ALC262
 ======
-  N/A
+  inv-dmic	Inverted internal mic workaround
 
 ALC267/268
 ==========
-  N/A
+  inv-dmic	Inverted internal mic workaround
 
 ALC269
 ======
   laptop-amic	Laptops with analog-mic input
   laptop-dmic	Laptops with digital-mic input
+  alc269-dmic	Enable ALC269(VA) digital mic workaround
+  alc271-dmic	Enable ALC271X digital mic workaround
+  inv-dmic	Inverted internal mic workaround
 
 ALC662/663/272
 ==============
+  mario		Chromebook mario model fixup
   asus-mode1	ASUS
   asus-mode2	ASUS
   asus-mode3	ASUS
@@ -36,6 +40,7 @@ ALC662/663/272
   asus-mode6	ASUS
   asus-mode7	ASUS
   asus-mode8	ASUS
+  inv-dmic	Inverted internal mic workaround
 
 ALC680
 ======
@@ -46,6 +51,7 @@ ALC882/883/885/888/889
   acer-aspire-4930g	Acer Aspire 4930G/5930G/6530G/6930G/7730G
   acer-aspire-8930g	Acer Aspire 8330G/6935G
   acer-aspire		Acer Aspire others
+  inv-dmic	Inverted internal mic workaround
 
 ALC861/660
 ==========
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
index f0ab5cf..b0714d8 100644
--- a/Documentation/stable_kernel_rules.txt
+++ b/Documentation/stable_kernel_rules.txt
@@ -1,4 +1,4 @@
-Everything you ever wanted to know about Linux 2.6 -stable releases.
+Everything you ever wanted to know about Linux -stable releases.
 
 Rules on what kind of patches are accepted, and which ones are not, into the
 "-stable" tree:
@@ -12,6 +12,12 @@ Rules on what kind of patches are accepted, and which ones are not, into the
    marked CONFIG_BROKEN), an oops, a hang, data corruption, a real
    security issue, or some "oh, that's not good" issue.  In short, something
    critical.
+ - Serious issues as reported by a user of a distribution kernel may also
+   be considered if they fix a notable performance or interactivity issue.
+   As these fixes are not as obvious and have a higher risk of a subtle
+   regression they should only be submitted by a distribution kernel
+   maintainer and include an addendum linking to a bugzilla entry if it
+   exists and additional information on the user-visible impact.
  - New device IDs and quirks are also accepted.
  - No "theoretical race condition" issues, unless an explanation of how the
    race can be exploited is also provided.
@@ -36,10 +42,10 @@ Procedure for submitting patches to the -stable tree:
    cherry-picked than this can be specified in the following format in
    the sign-off area:
 
-     Cc: <stable@vger.kernel.org> # .32.x: a1f84a3: sched: Check for idle
-     Cc: <stable@vger.kernel.org> # .32.x: 1b9508f: sched: Rate-limit newidle
-     Cc: <stable@vger.kernel.org> # .32.x: fd21073: sched: Fix affinity logic
-     Cc: <stable@vger.kernel.org> # .32.x
+     Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle
+     Cc: <stable@vger.kernel.org> # 3.3.x: 1b9508f: sched: Rate-limit newidle
+     Cc: <stable@vger.kernel.org> # 3.3.x: fd21073: sched: Fix affinity logic
+     Cc: <stable@vger.kernel.org> # 3.3.x
     Signed-off-by: Ingo Molnar <mingo@elte.hu>
 
    The tag sequence has the meaning of:
@@ -73,6 +79,15 @@ Review cycle:
    security kernel team, and not go through the normal review cycle.
    Contact the kernel security team for more details on this procedure.
 
+Trees:
+
+ - The queues of patches, for both completed versions and in progress
+   versions can be found at:
+	http://git.kernel.org/?p=linux/kernel/git/stable/stable-queue.git
+ - The finalized and tagged releases of all stable kernels can be found
+   in separate branches per version at:
+	http://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git
+
 
 Review committee:
 
diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
index 13d6166..d4a372e 100644
--- a/Documentation/sysctl/fs.txt
+++ b/Documentation/sysctl/fs.txt
@@ -32,6 +32,8 @@ Currently, these files are in /proc/sys/fs:
 - nr_open
 - overflowuid
 - overflowgid
+- protected_hardlinks
+- protected_symlinks
 - suid_dumpable
 - super-max
 - super-nr
@@ -157,6 +159,46 @@ The default is 65534.
 
 ==============================================================
 
+protected_hardlinks:
+
+A long-standing class of security issues is the hardlink-based
+time-of-check-time-of-use race, most commonly seen in world-writable
+directories like /tmp. The common method of exploitation of this flaw
+is to cross privilege boundaries when following a given hardlink (i.e. a
+root process follows a hardlink created by another user). Additionally,
+on systems without separated partitions, this stops unauthorized users
+from "pinning" vulnerable setuid/setgid files against being upgraded by
+the administrator, or linking to special files.
+
+When set to "0", hardlink creation behavior is unrestricted.
+
+When set to "1" hardlinks cannot be created by users if they do not
+already own the source file, or do not have read/write access to it.
+
+This protection is based on the restrictions in Openwall and grsecurity.
+
+==============================================================
+
+protected_symlinks:
+
+A long-standing class of security issues is the symlink-based
+time-of-check-time-of-use race, most commonly seen in world-writable
+directories like /tmp. The common method of exploitation of this flaw
+is to cross privilege boundaries when following a given symlink (i.e. a
+root process follows a symlink belonging to another user). For a likely
+incomplete list of hundreds of examples across the years, please see:
+http://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=/tmp
+
+When set to "0", symlink following behavior is unrestricted.
+
+When set to "1" symlinks are permitted to be followed only when outside
+a sticky world-writable directory, or when the uid of the symlink and
+follower match, or when the directory owner matches the symlink's owner.
+
+This protection is based on the restrictions in Openwall and grsecurity.
+
+==============================================================
+
 suid_dumpable:
 
 This value can be used to query and set the core dump mode for setuid
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index 96f0ee8..06d662b 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -42,7 +42,6 @@ Currently, these files are in /proc/sys/vm:
 - mmap_min_addr
 - nr_hugepages
 - nr_overcommit_hugepages
-- nr_pdflush_threads
 - nr_trim_pages         (only if CONFIG_MMU=n)
 - numa_zonelist_order
 - oom_dump_tasks
@@ -426,16 +425,6 @@ See Documentation/vm/hugetlbpage.txt
 
 ==============================================================
 
-nr_pdflush_threads
-
-The current number of pdflush threads.  This value is read-only.
-The value changes according to the number of dirty pages in the system.
-
-When necessary, additional pdflush threads are created, one per second, up to
-nr_pdflush_threads_max.
-
-==============================================================
-
 nr_trim_pages
 
 This is available only on NOMMU kernels.
@@ -574,16 +563,24 @@ of physical RAM.  See above.
 
 page-cluster
 
-page-cluster controls the number of pages which are written to swap in
-a single attempt.  The swap I/O size.
+page-cluster controls the number of pages up to which consecutive pages
+are read in from swap in a single attempt. This is the swap counterpart
+to page cache readahead.
+The mentioned consecutivity is not in terms of virtual/physical addresses,
+but consecutive on swap space - that means they were swapped out together.
 
 It is a logarithmic value - setting it to zero means "1 page", setting
 it to 1 means "2 pages", setting it to 2 means "4 pages", etc.
+Zero disables swap readahead completely.
 
 The default value is three (eight pages at a time).  There may be some
 small benefits in tuning this to a different value if your workload is
 swap-intensive.
 
+Lower values mean lower latencies for initial faults, but at the same time
+extra faults and I/O delays for following faults if they would have been part of
+that consecutive pages readahead would have brought in.
+
 =============================================================
 
 panic_on_oom
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index 1733ab9..3c8c2f8 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -32,7 +32,8 @@ temperature) and throttle appropriate devices.
 
 1.1 thermal zone device interface
 1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *name,
-		int trips, void *devdata, struct thermal_zone_device_ops *ops)
+		int trips, int flag, void *devdata,
+		struct thermal_zone_device_ops *ops)
 
     This interface function adds a new thermal zone device (sensor) to
     /sys/class/thermal folder as thermal_zone[0-*]. It tries to bind all the
@@ -40,6 +41,7 @@ temperature) and throttle appropriate devices.
 
     name: the thermal zone name.
     trips: the total number of trip points this thermal zone supports.
+    flag: Bit string: If 'n'th bit is set, then trip point 'n' is writeable.
     devdata: device private data
     ops: thermal zone device call-backs.
 	.bind: bind the thermal zone device with a thermal cooling device.
@@ -119,6 +121,7 @@ Thermal zone device sys I/F, created once it's registered:
     |---mode:			Working mode of the thermal zone
     |---trip_point_[0-*]_temp:	Trip point temperature
     |---trip_point_[0-*]_type:	Trip point type
+    |---trip_point_[0-*]_hyst:	Hysteresis value for this trip point
 
 Thermal cooling device sys I/F, created once it's registered:
 /sys/class/thermal/cooling_device[0-*]:
@@ -188,6 +191,11 @@ trip_point_[0-*]_type
 	thermal zone.
 	RO, Optional
 
+trip_point_[0-*]_hyst
+	The hysteresis value for a trip point, represented as an integer
+	Unit: Celsius
+	RW, Optional
+
 cdev[0-*]
 	Sysfs link to the thermal cooling device node where the sys I/F
 	for cooling device throttling control represents.
diff --git a/Documentation/vfio.txt b/Documentation/vfio.txt
new file mode 100644
index 0000000..1240874
--- /dev/null
+++ b/Documentation/vfio.txt
@@ -0,0 +1,315 @@
+VFIO - "Virtual Function I/O"[1]
+-------------------------------------------------------------------------------
+Many modern system now provide DMA and interrupt remapping facilities
+to help ensure I/O devices behave within the boundaries they've been
+allotted.  This includes x86 hardware with AMD-Vi and Intel VT-d,
+POWER systems with Partitionable Endpoints (PEs) and embedded PowerPC
+systems such as Freescale PAMU.  The VFIO driver is an IOMMU/device
+agnostic framework for exposing direct device access to userspace, in
+a secure, IOMMU protected environment.  In other words, this allows
+safe[2], non-privileged, userspace drivers.
+
+Why do we want that?  Virtual machines often make use of direct device
+access ("device assignment") when configured for the highest possible
+I/O performance.  From a device and host perspective, this simply
+turns the VM into a userspace driver, with the benefits of
+significantly reduced latency, higher bandwidth, and direct use of
+bare-metal device drivers[3].
+
+Some applications, particularly in the high performance computing
+field, also benefit from low-overhead, direct device access from
+userspace.  Examples include network adapters (often non-TCP/IP based)
+and compute accelerators.  Prior to VFIO, these drivers had to either
+go through the full development cycle to become proper upstream
+driver, be maintained out of tree, or make use of the UIO framework,
+which has no notion of IOMMU protection, limited interrupt support,
+and requires root privileges to access things like PCI configuration
+space.
+
+The VFIO driver framework intends to unify these, replacing both the
+KVM PCI specific device assignment code as well as provide a more
+secure, more featureful userspace driver environment than UIO.
+
+Groups, Devices, and IOMMUs
+-------------------------------------------------------------------------------
+
+Devices are the main target of any I/O driver.  Devices typically
+create a programming interface made up of I/O access, interrupts,
+and DMA.  Without going into the details of each of these, DMA is
+by far the most critical aspect for maintaining a secure environment
+as allowing a device read-write access to system memory imposes the
+greatest risk to the overall system integrity.
+
+To help mitigate this risk, many modern IOMMUs now incorporate
+isolation properties into what was, in many cases, an interface only
+meant for translation (ie. solving the addressing problems of devices
+with limited address spaces).  With this, devices can now be isolated
+from each other and from arbitrary memory access, thus allowing
+things like secure direct assignment of devices into virtual machines.
+
+This isolation is not always at the granularity of a single device
+though.  Even when an IOMMU is capable of this, properties of devices,
+interconnects, and IOMMU topologies can each reduce this isolation.
+For instance, an individual device may be part of a larger multi-
+function enclosure.  While the IOMMU may be able to distinguish
+between devices within the enclosure, the enclosure may not require
+transactions between devices to reach the IOMMU.  Examples of this
+could be anything from a multi-function PCI device with backdoors
+between functions to a non-PCI-ACS (Access Control Services) capable
+bridge allowing redirection without reaching the IOMMU.  Topology
+can also play a factor in terms of hiding devices.  A PCIe-to-PCI
+bridge masks the devices behind it, making transaction appear as if
+from the bridge itself.  Obviously IOMMU design plays a major factor
+as well.
+
+Therefore, while for the most part an IOMMU may have device level
+granularity, any system is susceptible to reduced granularity.  The
+IOMMU API therefore supports a notion of IOMMU groups.  A group is
+a set of devices which is isolatable from all other devices in the
+system.  Groups are therefore the unit of ownership used by VFIO.
+
+While the group is the minimum granularity that must be used to
+ensure secure user access, it's not necessarily the preferred
+granularity.  In IOMMUs which make use of page tables, it may be
+possible to share a set of page tables between different groups,
+reducing the overhead both to the platform (reduced TLB thrashing,
+reduced duplicate page tables), and to the user (programming only
+a single set of translations).  For this reason, VFIO makes use of
+a container class, which may hold one or more groups.  A container
+is created by simply opening the /dev/vfio/vfio character device.
+
+On its own, the container provides little functionality, with all
+but a couple version and extension query interfaces locked away.
+The user needs to add a group into the container for the next level
+of functionality.  To do this, the user first needs to identify the
+group associated with the desired device.  This can be done using
+the sysfs links described in the example below.  By unbinding the
+device from the host driver and binding it to a VFIO driver, a new
+VFIO group will appear for the group as /dev/vfio/$GROUP, where
+$GROUP is the IOMMU group number of which the device is a member.
+If the IOMMU group contains multiple devices, each will need to
+be bound to a VFIO driver before operations on the VFIO group
+are allowed (it's also sufficient to only unbind the device from
+host drivers if a VFIO driver is unavailable; this will make the
+group available, but not that particular device).  TBD - interface
+for disabling driver probing/locking a device.
+
+Once the group is ready, it may be added to the container by opening
+the VFIO group character device (/dev/vfio/$GROUP) and using the
+VFIO_GROUP_SET_CONTAINER ioctl, passing the file descriptor of the
+previously opened container file.  If desired and if the IOMMU driver
+supports sharing the IOMMU context between groups, multiple groups may
+be set to the same container.  If a group fails to set to a container
+with existing groups, a new empty container will need to be used
+instead.
+
+With a group (or groups) attached to a container, the remaining
+ioctls become available, enabling access to the VFIO IOMMU interfaces.
+Additionally, it now becomes possible to get file descriptors for each
+device within a group using an ioctl on the VFIO group file descriptor.
+
+The VFIO device API includes ioctls for describing the device, the I/O
+regions and their read/write/mmap offsets on the device descriptor, as
+well as mechanisms for describing and registering interrupt
+notifications.
+
+VFIO Usage Example
+-------------------------------------------------------------------------------
+
+Assume user wants to access PCI device 0000:06:0d.0
+
+$ readlink /sys/bus/pci/devices/0000:06:0d.0/iommu_group
+../../../../kernel/iommu_groups/26
+
+This device is therefore in IOMMU group 26.  This device is on the
+pci bus, therefore the user will make use of vfio-pci to manage the
+group:
+
+# modprobe vfio-pci
+
+Binding this device to the vfio-pci driver creates the VFIO group
+character devices for this group:
+
+$ lspci -n -s 0000:06:0d.0
+06:0d.0 0401: 1102:0002 (rev 08)
+# echo 0000:06:0d.0 > /sys/bus/pci/devices/0000:06:0d.0/driver/unbind
+# echo 1102 0002 > /sys/bus/pci/drivers/vfio/new_id
+# echo 0000:06:0d.0 > /sys/bus/pci/drivers/vfio/bind
+
+Now we need to look at what other devices are in the group to free
+it for use by VFIO:
+
+$ ls -l /sys/bus/pci/devices/0000:06:0d.0/iommu_group/devices
+total 0
+lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:00:1e.0 ->
+	../../../../devices/pci0000:00/0000:00:1e.0
+lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:06:0d.0 ->
+	../../../../devices/pci0000:00/0000:00:1e.0/0000:06:0d.0
+lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:06:0d.1 ->
+	../../../../devices/pci0000:00/0000:00:1e.0/0000:06:0d.1
+
+This device is behind a PCIe-to-PCI bridge[4], therefore we also
+need to add device 0000:06:0d.1 to the group following the same
+procedure as above.  Device 0000:00:1e.0 is a bridge that does
+not currently have a host driver, therefore it's not required to
+bind this device to the vfio-pci driver (vfio-pci does not currently
+support PCI bridges).
+
+The final step is to provide the user with access to the group if
+unprivileged operation is desired (note that /dev/vfio/vfio provides
+no capabilities on its own and is therefore expected to be set to
+mode 0666 by the system).
+
+# chown user:user /dev/vfio/26
+
+The user now has full access to all the devices and the iommu for this
+group and can access them as follows:
+
+	int container, group, device, i;
+	struct vfio_group_status group_status =
+					{ .argsz = sizeof(group_status) };
+	struct vfio_iommu_x86_info iommu_info = { .argsz = sizeof(iommu_info) };
+	struct vfio_iommu_x86_dma_map dma_map = { .argsz = sizeof(dma_map) };
+	struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
+
+	/* Create a new container */
+	container = open("/dev/vfio/vfio, O_RDWR);
+
+	if (ioctl(container, VFIO_GET_API_VERSION) != VFIO_API_VERSION)
+		/* Unknown API version */
+
+	if (!ioctl(container, VFIO_CHECK_EXTENSION, VFIO_X86_IOMMU))
+		/* Doesn't support the IOMMU driver we want. */
+
+	/* Open the group */
+	group = open("/dev/vfio/26", O_RDWR);
+
+	/* Test the group is viable and available */
+	ioctl(group, VFIO_GROUP_GET_STATUS, &group_status);
+
+	if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE))
+		/* Group is not viable (ie, not all devices bound for vfio) */
+
+	/* Add the group to the container */
+	ioctl(group, VFIO_GROUP_SET_CONTAINER, &container);
+
+	/* Enable the IOMMU model we want */
+	ioctl(container, VFIO_SET_IOMMU, VFIO_X86_IOMMU)
+
+	/* Get addition IOMMU info */
+	ioctl(container, VFIO_IOMMU_GET_INFO, &iommu_info);
+
+	/* Allocate some space and setup a DMA mapping */
+	dma_map.vaddr = mmap(0, 1024 * 1024, PROT_READ | PROT_WRITE,
+			     MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+	dma_map.size = 1024 * 1024;
+	dma_map.iova = 0; /* 1MB starting at 0x0 from device view */
+	dma_map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
+
+	ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map);
+
+	/* Get a file descriptor for the device */
+	device = ioctl(group, VFIO_GROUP_GET_DEVICE_FD, "0000:06:0d.0");
+
+	/* Test and setup the device */
+	ioctl(device, VFIO_DEVICE_GET_INFO, &device_info);
+
+	for (i = 0; i < device_info.num_regions; i++) {
+		struct vfio_region_info reg = { .argsz = sizeof(reg) };
+
+		reg.index = i;
+
+		ioctl(device, VFIO_DEVICE_GET_REGION_INFO, &reg);
+
+		/* Setup mappings... read/write offsets, mmaps
+		 * For PCI devices, config space is a region */
+	}
+
+	for (i = 0; i < device_info.num_irqs; i++) {
+		struct vfio_irq_info irq = { .argsz = sizeof(irq) };
+
+		irq.index = i;
+
+		ioctl(device, VFIO_DEVICE_GET_IRQ_INFO, &reg);
+
+		/* Setup IRQs... eventfds, VFIO_DEVICE_SET_IRQS */
+	}
+
+	/* Gratuitous device reset and go... */
+	ioctl(device, VFIO_DEVICE_RESET);
+
+VFIO User API
+-------------------------------------------------------------------------------
+
+Please see include/linux/vfio.h for complete API documentation.
+
+VFIO bus driver API
+-------------------------------------------------------------------------------
+
+VFIO bus drivers, such as vfio-pci make use of only a few interfaces
+into VFIO core.  When devices are bound and unbound to the driver,
+the driver should call vfio_add_group_dev() and vfio_del_group_dev()
+respectively:
+
+extern int vfio_add_group_dev(struct iommu_group *iommu_group,
+                              struct device *dev,
+                              const struct vfio_device_ops *ops,
+                              void *device_data);
+
+extern void *vfio_del_group_dev(struct device *dev);
+
+vfio_add_group_dev() indicates to the core to begin tracking the
+specified iommu_group and register the specified dev as owned by
+a VFIO bus driver.  The driver provides an ops structure for callbacks
+similar to a file operations structure:
+
+struct vfio_device_ops {
+	int	(*open)(void *device_data);
+	void	(*release)(void *device_data);
+	ssize_t	(*read)(void *device_data, char __user *buf,
+			size_t count, loff_t *ppos);
+	ssize_t	(*write)(void *device_data, const char __user *buf,
+			 size_t size, loff_t *ppos);
+	long	(*ioctl)(void *device_data, unsigned int cmd,
+			 unsigned long arg);
+	int	(*mmap)(void *device_data, struct vm_area_struct *vma);
+};
+
+Each function is passed the device_data that was originally registered
+in the vfio_add_group_dev() call above.  This allows the bus driver
+an easy place to store its opaque, private data.  The open/release
+callbacks are issued when a new file descriptor is created for a
+device (via VFIO_GROUP_GET_DEVICE_FD).  The ioctl interface provides
+a direct pass through for VFIO_DEVICE_* ioctls.  The read/write/mmap
+interfaces implement the device region access defined by the device's
+own VFIO_DEVICE_GET_REGION_INFO ioctl.
+
+-------------------------------------------------------------------------------
+
+[1] VFIO was originally an acronym for "Virtual Function I/O" in its
+initial implementation by Tom Lyon while as Cisco.  We've since
+outgrown the acronym, but it's catchy.
+
+[2] "safe" also depends upon a device being "well behaved".  It's
+possible for multi-function devices to have backdoors between
+functions and even for single function devices to have alternative
+access to things like PCI config space through MMIO registers.  To
+guard against the former we can include additional precautions in the
+IOMMU driver to group multi-function PCI devices together
+(iommu=group_mf).  The latter we can't prevent, but the IOMMU should
+still provide isolation.  For PCI, SR-IOV Virtual Functions are the
+best indicator of "well behaved", as these are designed for
+virtualization usage models.
+
+[3] As always there are trade-offs to virtual machine device
+assignment that are beyond the scope of VFIO.  It's expected that
+future IOMMU technologies will reduce some, but maybe not all, of
+these trade-offs.
+
+[4] In this case the device is below a PCI bridge, so transactions
+from either function of the device are indistinguishable to the iommu:
+
+-[0000:00]-+-1e.0-[06]--+-0d.0
+                        \-0d.1
+
+00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev 90)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 9301266..310fe50 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1930,6 +1930,42 @@ The "pte_enc" field provides a value that can OR'ed into the hash
 PTE's RPN field (ie, it needs to be shifted left by 12 to OR it
 into the hash PTE second double word).
 
+
+4.75 KVM_PPC_ALLOCATE_HTAB
+
+Capability: KVM_CAP_PPC_ALLOC_HTAB
+Architectures: powerpc
+Type: vm ioctl
+Parameters: Pointer to u32 containing hash table order (in/out)
+Returns: 0 on success, -1 on error
+
+This requests the host kernel to allocate an MMU hash table for a
+guest using the PAPR paravirtualization interface.  This only does
+anything if the kernel is configured to use the Book 3S HV style of
+virtualization.  Otherwise the capability doesn't exist and the ioctl
+returns an ENOTTY error.  The rest of this description assumes Book 3S
+HV.
+
+There must be no vcpus running when this ioctl is called; if there
+are, it will do nothing and return an EBUSY error.
+
+The parameter is a pointer to a 32-bit unsigned integer variable
+containing the order (log base 2) of the desired size of the hash
+table, which must be between 18 and 46.  On successful return from the
+ioctl, it will have been updated with the order of the hash table that
+was allocated.
+
+If no hash table has been allocated when any vcpu is asked to run
+(with the KVM_RUN ioctl), the host kernel will allocate a
+default-sized hash table (16 MB).
+
+If this ioctl is called when a hash table has already been allocated,
+the kernel will clear out the existing hash table (zero all HPTEs) and
+return the hash table order in the parameter.  (If the guest is using
+the virtualized real-mode area (VRMA) facility, the kernel will
+re-create the VMRA HPTEs on the next KVM_RUN of any vcpu.)
+
+
 5. The kvm_run structure
 ------------------------
 
diff --git a/Documentation/virtual/kvm/ppc-pv.txt b/Documentation/virtual/kvm/ppc-pv.txt
index 6e7c370..4911cf9 100644
--- a/Documentation/virtual/kvm/ppc-pv.txt
+++ b/Documentation/virtual/kvm/ppc-pv.txt
@@ -109,8 +109,6 @@ The following bits are safe to be set inside the guest:
 
   MSR_EE
   MSR_RI
-  MSR_CR
-  MSR_ME
 
 If any other bit changes in the MSR, please still use mtmsr(d).
 
diff --git a/Documentation/vm/frontswap.txt b/Documentation/vm/frontswap.txt
index 37067cf..5ef2d13 100644
--- a/Documentation/vm/frontswap.txt
+++ b/Documentation/vm/frontswap.txt
@@ -25,7 +25,7 @@ with the specified swap device number (aka "type").  A "store" will
 copy the page to transcendent memory and associate it with the type and
 offset associated with the page. A "load" will copy the page, if found,
 from transcendent memory into kernel memory, but will NOT remove the page
-from from transcendent memory.  An "invalidate_page" will remove the page
+from transcendent memory.  An "invalidate_page" will remove the page
 from transcendent memory and an "invalidate_area" will remove ALL pages
 associated with the swap type (e.g., like swapoff) and notify the "device"
 to refuse further stores with that swap type.
@@ -99,7 +99,7 @@ server configured with a large amount of RAM... without pre-configuring
 how much of the RAM is available for each of the clients!
 
 In the virtual case, the whole point of virtualization is to statistically
-multiplex physical resources acrosst the varying demands of multiple
+multiplex physical resources across the varying demands of multiple
 virtual machines.  This is really hard to do with RAM and efforts to do
 it well with no kernel changes have essentially failed (except in some
 well-publicized special-case workloads).
diff --git a/Documentation/w1/slaves/w1_ds28e04 b/Documentation/w1/slaves/w1_ds28e04
new file mode 100644
index 0000000..85bc9a7
--- /dev/null
+++ b/Documentation/w1/slaves/w1_ds28e04
@@ -0,0 +1,36 @@
+Kernel driver w1_ds28e04
+========================
+
+Supported chips:
+  * Maxim DS28E04-100 4096-Bit Addressable 1-Wire EEPROM with PIO
+
+supported family codes:
+	W1_FAMILY_DS28E04	0x1C
+
+Author: Markus Franke, <franke.m@sebakmt.com> <franm@hrz.tu-chemnitz.de>
+
+Description
+-----------
+
+Support is provided through the sysfs files "eeprom" and "pio". CRC checking
+during memory accesses can optionally be enabled/disabled via the device
+attribute "crccheck". The strong pull-up can optionally be enabled/disabled
+via the module parameter "w1_strong_pullup".
+
+Memory Access
+
+	A read operation on the "eeprom" file reads the given amount of bytes
+	from the EEPROM of the DS28E04.
+
+	A write operation on the "eeprom" file writes the given byte sequence
+	to the EEPROM of the DS28E04. If CRC checking mode is enabled only
+	fully alligned blocks of 32 bytes with valid CRC16 values (in bytes 30
+	and 31) are allowed to be written.
+
+PIO Access
+
+	The 2 PIOs of the DS28E04-100 are accessible via the "pio" sysfs file.
+
+	The current status of the PIO's is returned as an 8 bit value. Bit 0/1
+	represent the state of PIO_0/PIO_1. Bits 2..7 do not care. The PIO's are
+	driven low-active, i.e. the driver delivers/expects low-active values.
diff --git a/MAINTAINERS b/MAINTAINERS
index eb22272..b6421bc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -242,13 +242,6 @@ W:	http://www.lesswatts.org/projects/acpi/
 S:	Supported
 F:	drivers/acpi/fan.c
 
-ACPI PROCESSOR AGGREGATOR DRIVER
-M:	Shaohua Li <shaohua.li@intel.com>
-L:	linux-acpi@vger.kernel.org
-W:	http://www.lesswatts.org/projects/acpi/
-S:	Supported
-F:	drivers/acpi/acpi_pad.c
-
 ACPI THERMAL DRIVER
 M:	Zhang Rui <rui.zhang@intel.com>
 L:	linux-acpi@vger.kernel.org
@@ -329,7 +322,7 @@ F:	drivers/hwmon/adm1029.c
 
 ADM8211 WIRELESS DRIVER
 L:	linux-wireless@vger.kernel.org
-W:	http://linuxwireless.org/
+W:	http://wireless.kernel.org/
 S:	Orphan
 F:	drivers/net/wireless/adm8211.*
 
@@ -1423,7 +1416,7 @@ B43 WIRELESS DRIVER
 M:	Stefano Brivio <stefano.brivio@polimi.it>
 L:	linux-wireless@vger.kernel.org
 L:	b43-dev@lists.infradead.org
-W:	http://linuxwireless.org/en/users/Drivers/b43
+W:	http://wireless.kernel.org/en/users/Drivers/b43
 S:	Maintained
 F:	drivers/net/wireless/b43/
 
@@ -1432,7 +1425,7 @@ M:	Larry Finger <Larry.Finger@lwfinger.net>
 M:	Stefano Brivio <stefano.brivio@polimi.it>
 L:	linux-wireless@vger.kernel.org
 L:	b43-dev@lists.infradead.org
-W:	http://linuxwireless.org/en/users/Drivers/b43
+W:	http://wireless.kernel.org/en/users/Drivers/b43
 S:	Maintained
 F:	drivers/net/wireless/b43legacy/
 
@@ -1595,6 +1588,7 @@ M:	Arend van Spriel <arend@broadcom.com>
 M:	Franky (Zhenhui) Lin <frankyl@broadcom.com>
 M:	Kan Yan	<kanyan@broadcom.com>
 L:	linux-wireless@vger.kernel.org
+L:	brcm80211-dev-list@broadcom.com
 S:	Supported
 F:	drivers/net/wireless/brcm80211/
 
@@ -2709,6 +2703,14 @@ M:	Mimi Zohar <zohar@us.ibm.com>
 S:	Supported
 F:	security/integrity/evm/
 
+EXTERNAL CONNECTOR SUBSYSTEM (EXTCON)
+M:	MyungJoo Ham <myungjoo.ham@samsung.com>
+M:	Chanwoo Choi <cw00.choi@samsung.com>
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+F:	drivers/extcon/
+F:	Documentation/extcon/
+
 EXYNOS DP DRIVER
 M:	Jingoo Han <jg1.han@samsung.com>
 L:	linux-fbdev@vger.kernel.org
@@ -3119,8 +3121,7 @@ S:	Maintained
 F:	drivers/media/video/gspca/t613.c
 
 GSPCA USB WEBCAM DRIVER
-M:	Jean-Francois Moine <moinejf@free.fr>
-W:	http://moinejf.free.fr
+M:	Hans de Goede <hdegoede@redhat.com>
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
@@ -3990,8 +3991,8 @@ F:	arch/ia64/include/asm/kvm*
 F:	arch/ia64/kvm/
 
 KERNEL VIRTUAL MACHINE for s390 (KVM/s390)
-M:	Carsten Otte <cotte@de.ibm.com>
 M:	Christian Borntraeger <borntraeger@de.ibm.com>
+M:	Cornelia Huck <cornelia.huck@de.ibm.com>
 M:	linux390@de.ibm.com
 L:	linux-s390@vger.kernel.org
 W:	http://www.ibm.com/developerworks/linux/linux390/
@@ -4351,7 +4352,7 @@ F:	arch/m68k/hp300/
 MAC80211
 M:	Johannes Berg <johannes@sipsolutions.net>
 L:	linux-wireless@vger.kernel.org
-W:	http://linuxwireless.org/
+W:	http://wireless.kernel.org/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
 S:	Maintained
@@ -4363,7 +4364,7 @@ MAC80211 PID RATE CONTROL
 M:	Stefano Brivio <stefano.brivio@polimi.it>
 M:	Mattias Nissler <mattias.nissler@gmx.de>
 L:	linux-wireless@vger.kernel.org
-W:	http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/PID
+W:	http://wireless.kernel.org/en/developers/Documentation/mac80211/RateControl/PID
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
 S:	Maintained
@@ -4610,6 +4611,14 @@ L:	alsa-devel@alsa-project.org
 W:	http://www.native-instruments.com
 F:	sound/usb/caiaq/
 
+NATIVE LINUX KVM TOOL
+M:	Pekka Enberg <penberg@kernel.org>
+M:	Sasha Levin <levinsasha928@gmail.com>
+M:	Asias He <asias.hejun@gmail.com>
+L:	kvm@vger.kernel.org
+S:	Maintained
+F:	tools/kvm/
+
 NCP FILESYSTEM
 M:	Petr Vandrovec <petr@vandrovec.name>
 S:	Odd Fixes
@@ -5048,7 +5057,7 @@ F:	fs/ocfs2/
 
 ORINOCO DRIVER
 L:	linux-wireless@vger.kernel.org
-W:	http://linuxwireless.org/en/users/Drivers/orinoco
+W:	http://wireless.kernel.org/en/users/Drivers/orinoco
 W:	http://www.nongnu.org/orinoco/
 S:	Orphan
 F:	drivers/net/wireless/orinoco/
@@ -5200,7 +5209,7 @@ PCI SUBSYSTEM
 M:	Bjorn Helgaas <bhelgaas@google.com>
 L:	linux-pci@vger.kernel.org
 Q:	http://patchwork.ozlabs.org/project/linux-pci/list/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/linux.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
 S:	Supported
 F:	Documentation/PCI/
 F:	drivers/pci/
@@ -5708,6 +5717,7 @@ F:	include/linux/regmap.h
 
 REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM
 M:	Ohad Ben-Cohen <ohad@wizery.com>
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc.git
 S:	Maintained
 F:	drivers/remoteproc/
 F:	Documentation/remoteproc.txt
@@ -5753,7 +5763,7 @@ F:	net/rose/
 RTL8180 WIRELESS DRIVER
 M:	"John W. Linville" <linville@tuxdriver.com>
 L:	linux-wireless@vger.kernel.org
-W:	http://linuxwireless.org/
+W:	http://wireless.kernel.org/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
 S:	Maintained
 F:	drivers/net/wireless/rtl818x/rtl8180/
@@ -5763,7 +5773,7 @@ M:	Herton Ronaldo Krzesinski <herton@canonical.com>
 M:	Hin-Tak Leung <htl10@users.sourceforge.net>
 M:	Larry Finger <Larry.Finger@lwfinger.net>
 L:	linux-wireless@vger.kernel.org
-W:	http://linuxwireless.org/
+W:	http://wireless.kernel.org/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
 S:	Maintained
 F:	drivers/net/wireless/rtl818x/rtl8187/
@@ -5772,7 +5782,7 @@ RTL8192CE WIRELESS DRIVER
 M:	Larry Finger <Larry.Finger@lwfinger.net>
 M:	Chaoming Li <chaoming_li@realsil.com.cn>
 L:	linux-wireless@vger.kernel.org
-W:	http://linuxwireless.org/
+W:	http://wireless.kernel.org/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
 S:	Maintained
 F:	drivers/net/wireless/rtlwifi/
@@ -6747,9 +6757,11 @@ F:	include/linux/tifm.h
 
 TI LM49xxx FAMILY ASoC CODEC DRIVERS
 M:	M R Swami Reddy <mr.swami.reddy@ti.com>
+M:	Vishwas A Deshpande <vishwas.a.deshpande@ti.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:	Maintained
 F:	sound/soc/codecs/lm49453*
+F:	sound/soc/codecs/isabelle*
 
 TI TWL4030 SERIES SOC CODEC DRIVER
 M:	Peter Ujfalusi <peter.ujfalusi@ti.com>
@@ -6843,10 +6855,11 @@ F:	include/linux/shmem_fs.h
 F:	mm/shmem.c
 
 TPM DEVICE DRIVER
-M:	Debora Velarde <debora@linux.vnet.ibm.com>
-M:	Rajiv Andrade <srajiv@linux.vnet.ibm.com>
+M:	Kent Yoder <key@linux.vnet.ibm.com>
+M:	Rajiv Andrade <mail@srajiv.net>
 W:	http://tpmdd.sourceforge.net
-M:	Marcel Selhorst <m.selhorst@sirrix.com>
+M:	Marcel Selhorst <tpmdd@selhorst.net>
+M:	Sirrix AG <tpmdd@sirrix.com>
 W:	http://www.sirrix.com
 L:	tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
 S:	Maintained
@@ -6946,6 +6959,13 @@ S:	Maintained
 F:	Documentation/filesystems/ufs.txt
 F:	fs/ufs/
 
+UHID USERSPACE HID IO DRIVER:
+M:	David Herrmann <dh.herrmann@googlemail.com>
+L:	linux-input@vger.kernel.org
+S:	Maintained
+F:	drivers/hid/uhid.c
+F:	include/linux/uhid.h
+
 ULTRA-WIDEBAND (UWB) SUBSYSTEM:
 L:	linux-usb@vger.kernel.org
 S:	Orphan
@@ -7336,6 +7356,14 @@ S:	Maintained
 F:	Documentation/filesystems/vfat.txt
 F:	fs/fat/
 
+VFIO DRIVER
+M:	Alex Williamson <alex.williamson@redhat.com>
+L:	kvm@vger.kernel.org
+S:	Maintained
+F:	Documentation/vfio.txt
+F:	drivers/vfio/
+F:	include/linux/vfio.h
+
 VIDEOBUF2 FRAMEWORK
 M:	Pawel Osciak <pawel@osciak.com>
 M:	Marek Szyprowski <m.szyprowski@samsung.com>
diff --git a/Next/SHA1s b/Next/SHA1s
new file mode 100644
index 0000000..55bcd27
--- /dev/null
+++ b/Next/SHA1s
@@ -0,0 +1,193 @@
+Name		SHA1
+----		----
+origin		d1346a6cbabf6d377d753f1adc16cb0b305830cc
+fixes		9023a4093d6594040fb8142cdd2615d3461caa7a
+kbuild-current	464076bbc6371a43228c625718d10df2dba83646
+arm-current	10aa5a35e34fb00a2dd814447199f08756eb307b
+m68k-current	d8ce7263e1bc3b6b2b906fec0c5037bc27d21d6a
+powerpc-merge	7c0482e3d055e5de056d3c693b821e39205b99ae
+sparc		39a50b42f7026027b54131291ad0f350100eac95
+net		8a8e28b8e2c27362f24cf06513c05d5e3a304e03
+sound-current	6e1c39c6b00d9141a82c231ba7c5e5b1716974b2
+pci-current	314489bd4c7780fde6a069783d5128f6cef52919
+wireless	161ae88744bdcef15058a38f101b06308d8824d4
+driver-core.current	116e90b23f74d303e8d607c7a7d54f60f14ab9f2
+tty.current	6b16351acbd415e66ba16bf7d473ece1574cf0bc
+usb.current	3fcc8f96829776cf181918461923d1e3bbb831a2
+staging.current	6b16351acbd415e66ba16bf7d473ece1574cf0bc
+char-misc.current	6b16351acbd415e66ba16bf7d473ece1574cf0bc
+input-current	2177905ca7419c49910d47e38e44790affd918cc
+md-current	aba336bd1d46d6b0404b06f6915ed76150739057
+audit-current	c158a35c8a681cf68d36f22f058f9f5466386c71
+crypto-current	c475c06f4bb689d6ad87d7512e036d6dface3160
+ide		39a50b42f7026027b54131291ad0f350100eac95
+dwmw2		244dc4e54b73567fae7f8fd9ba56584be9375442
+sh-current	790b9d4bb7614252e133d4a99ef18c1734d69163
+irqdomain-current	15e06bf64f686befd2030da867a3dad965b96cc0
+devicetree-current	4e8383b6b06b275999f51337adf7064b2c135a04
+spi-current	d1c185bcb15184ebcbc1b2e003e9a6c4658985c4
+gpio-current	96b70641b937e99c1579cb6ebbcdb7b0af98cdd0
+arm		4d0d790e914e85c62bfc099e82eb034222b05837
+arm-perf	dee8c1be71cfca1f8c8b96ee45c6d72799bf81ce
+davinci		fe0d42203cb5616eeff68b14576a0f7e2dd56625
+samsung		9edb240696bacd53f4331119d2dfd13d4cd4852f
+xilinx		b85a3ef4ac65169b65fd2fe9bec7912bbf475ba4
+blackfin	672552adb3197c5db3acc8800c7917bcff180461
+c6x		485802a6c524e62b5924849dd727ddbb1497cc71
+cris		2608747768e9a1b039b365a460ebe306fc73d9e1
+hexagon		5042ab91c4272e158748180ae70a2e097f9e90e3
+ia64		f28fa729149c8b39699f7995ce5fff34c5145a9d
+m68k		4fa0cffb139100c865fc15956bf6e27d6aa2383b
+m68knommu	cec069ec85f6b2429dc08f112b726a0260a8b020
+microblaze	a01ee165a132fadb57659d26246e340d6ac53265
+mips		1f04189a6d8fa812fa0b988799f6848c3f134881
+openrisc	207e715ff17b42e022df107210dc8c736a703eb3
+parisc		4c01acc01d77e8df5727247aa5ef5912c00256bf
+powerpc		2074b1d9d53ae696dd3f49482bad43254f40f01d
+4xx		2074b1d9d53ae696dd3f49482bad43254f40f01d
+mpc5xxx		f8d5842d4e40bec8f6ccc5d2d69032bc3a44e1b1
+galak		fa1b42b45a9c96da77f3ddabf715f49525a87209
+s390		fbe765680d1fe9d08187ea4dad5041a7955a2c3a
+sh		7b98cf0cf4e8798b9e7435f966ed0d90a2a925de
+sparc-next	31a67102f4762df5544bc2dfb34a931233d2a5b2
+tile		7a9349b7b5e594e9a51d6109bc9d9d31a4401ca0
+unicore32	e4baa56a9a94a75580cffc657c7fad8e1d92e9a6
+ceph		26ce171915f348abd1f41da1ed139d93750d987f
+cifs		4d0b178429348ef8ec229a0c1c4aa761dc9a5dd3
+configfs	b930c26416c4ea6855726fd977145ccea9afbdda
+ecryptfs	5a52c0d70bca6179e4e039469401ba552449006e
+ext3		7d5a4b02911c3b4ccb8ebf9cf02831f4debfa714
+ext4		b22b1f178f6799278d3178d894f37facb2085765
+fuse		203627bbc90377c509e32450c67c5d957ba2d989
+gfs2		666d1d8ad201803862514317c17695925e61316b
+logfs		cd8bfa9c8a13cf3facc5731da17e10188b3795d1
+nfs		d4c28981f070e60e008bddb79aeac9aa29c3395d
+nfsd		7df302f75ee28a6a87436e93b625ef60d37d098e
+ocfs2		939255798a468e1a92f03546de6e87be7b491e57
+omfs		976d167615b64e14bc1491ca51d424e2ba9a5e84
+squashfs	4b0180a49f08dd1c681cdc99edc9e0cec0a833fa
+v9fs		5fcb08befaf57faa1b00e514915c1660252b8c26
+ubifs		1cfb7271076a265b7c2cbbf9cf5c2ae060a24385
+xfs		9a8d2fdbb47aaa1eaa136b89da5e5e6b60015c78
+vfs		01aa470e9e3680c6f5fb0a52b71609dc7003236b
+pci		35e7f73c32ad44a931d918d04e317a7fb0c63e6e
+hid		f79185b32ecbb1f12ba4ac39ef04439fd81975ac
+i2c		d170f6ce3c80749beae101c3e46a28c5572bbd28
+bjdooks-i2c	fc84fe19ffb9eee7e6b3301bc6cd45b22f187bd7
+i2c-embedded	0f009a914b40be8786fa67b1f4345cacc263b48c
+jdelvare-hwmon	3c1aae21b09dc28ce26b9aa3660951ddaae9ff04
+hwmon-staging	56e42ea9b54b22572ccc5d931c428af9d2028ca8
+v4l-dvb		db04b6c44fada19665328dc0bc40e98df7610fc6
+kbuild		c6ff25b8ddc17aad5ce88d02955c5d4cd5b065de
+kconfig		4503379cb811809470ebefb58c943fe605bc3e29
+libata		2fff27512600f9ad91335577e485a8552edb0abf
+infiniband	a323e3fbd73e48cf14d178b0f212e1a7d5d84408
+acpi		4e86d6d9d668db422a5ad585d82b44f16756e900
+cpuidle		1cdb80c1ee460aed4ebf92343a4764d6278c4318
+cpupowerutils	f16603386b38c28979f4df1cafdc2fe73fa87d37
+ieee1394	e18907cc8a3cd6e09510632b753b8b6fefa1752a
+ubi		f8f5701bdaf9134b1f90e5044a82c66324d2073f
+dlm		aefee5620414ce999490ffdb5b3ca646c071522c
+scsi		6ef2448cb2ede2c953765fe9b67383ec59955fbf
+target-updates	4318efc84f3d66fb3c3eb94e776a7bded1a1541a
+target-merge	cfaf025112d3856637ff34a767ef785ef5cf2ca9
+ibft		935a9fee51c945b8942be2d7b4bae069167b4886
+isci		6df8ea38f18cf694f289cf423ada0257dd1b4eab
+slave-dma	49d57b5e588ce511bd826f5759aa2aebf322626b
+dmaengine	a2bd1140a264b561e38d99e656cd843c2d840e86
+net-next	251da4130115b29403a57096fa0988249f31fc55
+wireless-next	6bcfe67f9865fb51ec78fc9b09887375db7e08b5
+bluetooth	b82c29d81df0ead8b66041702d1dd88e778ab806
+mtd		ea3b2ea24ef0f2ef9c6795b19cff456195b6728a
+l2-mtd		b27ebae5d3a595de4bdf60ff692272893a6d2bf8
+crypto		398710379f516012c52d2ae396a9ba919bd6a7ab
+drm		9c19415c233499c26081798b880910ec0e1d7bad
+sound		df8b79cce45d7af1c60d70b0d386844f5871bfa6
+sound-asoc	747706dfbe48ccc039f4b1742d44b54fb7a9df11
+rr		231e4d6b695e215e5ca162f0c9d1b451f919cc76
+input		84b63ad8477c822edbeb1e310b201609f33522ec
+input-mt	27c347d64f5e4a7e141f6bdb85bbf59e0f1dcde6
+cgroup		f9b6023f219c365829c621ecaa966bdebb1e38bc
+block		f45d342e164a5278c6c322c7eaeaad3ad18e8d6e
+device-mapper	4e66fde1d9b086a70e201d8b46c9105cfe825014
+embedded	4744b43431e8613f920c5cba88346756f53c5165
+firmware	6e03a201bbe8137487f340d26aa662110e324b20
+pcmcia		80af9e6d7ae633309cc5bca96aee6a45117e7c98
+mmc		ed99260f748d4c1894a23a4519fd59156a27a308
+kgdb		3751d3e85cf693e10e2c47c03c8caa65e171099b
+slab		43d77867a4f333de4e4189114c480dd365133c09
+uclinux		5e442a493fc59fa536c76db1fff5b49ca36a88c5
+md		aba336bd1d46d6b0404b06f6915ed76150739057
+mfd		58eec73eb100b922545d36184a8138667b5f880d
+battery		85a392d47cac8fa9258c5609a7b02adade961076
+fbdev		0f90fa539dff47e65fe859de2a9089e53231e0da
+viafb		838ac785d521e091bd8b5f6a2b545166f5f32b77
+omap_dss2	05dd0f5308213e169b02458a7f3a61362e581e14
+regulator	6f3c468e2012f682b2ca2ebb48cabe4e15c73fac
+security	3072928ff2457642af0da745b88f0420b4596c48
+selinux		c737f8284cac91428f8fcc8281e69117fa16e887
+lblnet		7e27d6e778cd87b6f2415515d7127eba53fe5d02
+watchdog	e68261cb6b488a754b52023d4c40dfc5a95b41f4
+dwmw2-iommu	c3b92c8787367a8bb53d57d9789b558f1295cc96
+iommu		af4d900ffd9a2289abf12229a26fa32a94dd873b
+vfio		d9016a40caf64c0312d457e4cd26f7c2a09b78b8
+osd		8b56a30caaf9bc1850784f196636c5f550cc7577
+jc_docs		5c050fb96380a87a85aad9084b68fdcd2b84c193
+trivial		c224071e28e2bbd213cce2e6e9dde26e78542ca8
+audit		dcd6c92267155e70a94b3927bce681ce74b80d1f
+pm		6f5b7ab2af13201fc257ca2af7d40708f23526c0
+apm		f283d22713b0bdc147097c92c9b45855339cf1c8
+fsnotify	1aec9c0d718693553543349e92138033b0bcea4c
+edac		2d9531a438c7949a8d6a662178551fa1356a15a6
+edac-amd	305f1c3cfd7eef63bef2128b6934a9054d902976
+devicetree	efd68e7254503f3207805f674a1ea1d743f5dfe2
+spi		d8e328b3bd65fdefc9c49a27ee80c28e0a44b653
+tip		b0b7208a4db49038b2e931237795a268b69bdee9
+rcu		f0fd40c7d92ac7115023ebbe4ab34e35d8016c6b
+cputime		c3e0ef9a298e028a82ada28101ccd5cf64d209ee
+uprobes		0326f5a94ddea33fa331b2519f4172f4fb387baa
+kmemleak	48786770bf3b3a47bda766ba5f711199e7f24d8f
+kvm		dcce0489477f07ac1331aee71f18d6274e19a9c1
+kvm-ppc		5e5054caeb2b3e4d36a5f2448e829dc5ab4dc002
+oprofile	c16fa4f2ad19908a47c63d8fa436a1178438c7e7
+xen		af3a3ab2966112c0d0a44df7eeb1e95fe32d4495
+xen-two		e4e7b8208dc123f9fc0286d208079be5bfcbc454
+xen-pvhvm	b056b6a0144de90707cd22cf7b4f60bf69c86d59
+percpu		6101167727932a929e37fb8a6eeb68bdbf54d58e
+workqueues	6101167727932a929e37fb8a6eeb68bdbf54d58e
+drivers-x86	6ae3a0876185d0c4ddca1e9b5e3c750ccf2cc075
+hwpoison	46e387bbd82d438b9131e237e6e2cb55a825da49
+sysctl		4e474a00d7ff746ed177ddae14fa8b2d4bad7a00
+regmap		dabefce71b5b711880eb341759723d25b201a32e
+hsi		43139a61fc68f4b0af7327a0e63f340a7c81c69a
+leds		e15ca58f16cd660838819f30ba0e7e6a1f18701b
+driver-core	f2c32a882d2c1cde6fc552a5a3d34b4c1330edb8
+tty		fc915c8b930c3114f2a838f7e2cd8789ad6fedc3
+usb		023b515e5b304122f3802abaa68d1da46fdf48b8
+staging		2da049bd5f9b0dbd688519fdb6688a4895fe8395
+char-misc	726917f052e62d8012f63a763884957610399afb
+tmem		3bebf5b15aaae511be22fc8964f36d8a0763c918
+writeback	331cbdeedeb2f4ef01ccb761513708af0fe77098
+arm-dt		ede338f4ce2fb5ee99d18751df32fbd3b10df268
+hwspinlock	8b37fcfc9b3400b647748783a2cafff67793e0ad
+pinctrl		8df6653766eba7d3c255cc630603bf5966ca26fd
+moduleh		f9e1b2bd47664cf9838a6aa438578b3936e65d09
+vhost		e0953c8b85baaa38d77ebd5dc4051bc3837c1191
+kmap_atomic	cf43378e317840bf3c93d351bc6eacd15bb7a8a9
+memblock	7bd0b0f0da3b1ec11cbcc798eb0ef747a1184077
+remoteproc	5414687e1fde12b5bc8f77af79e766290900a228
+irqdomain	aed98048bd1c83469d96932c1901e867d9ba519a
+gpio		3e11f7b840b4671213c66817294ad7dd0b572756
+arm-soc		513bd7253904635343e3cd06cefaa90151fa7dea
+ep93xx		9b6a3592bd7a08b91a5eb5c34fa0d3093662e964
+renesas		386213b27ba8547df667da2f080439ed0c3ef5fd
+s5p		99f9f4c76878ae1b503b24173390dcb8018f2933
+tegra		1412fcf458b12fc6095afff982c57abd3487e16a
+kvmtool		5fffd63db1260fb56a3ed37cf2bbc5f901fcbad4
+dma-mapping	17f449ac0eff6cf38d01e583c46658d138548559
+dma-buf		b48b2c3e50433ff6f7e46186daa7f986bd960215
+userns		491fa9e96019ddd7d544a2f3c154b27bfd645d08
+ktest		648a182c615272f01b5cda01dc87a16de9f695bb
+signal		2c956058a990d439a5cd983ef906e2b07f51c116
+scsi-post-merge	65112dccf8a113737684366349d7f9ec373ddc47
+akpm		0021853ed55b38b6a1213b187a5e2064a88fec10
diff --git a/Next/Trees b/Next/Trees
new file mode 100644
index 0000000..78a9e93
--- /dev/null
+++ b/Next/Trees
@@ -0,0 +1,195 @@
+Trees included into this release:
+
+Name		Type	URL
+----		----	---
+origin		git	git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git#master
+fixes		git	git://git.kernel.org/pub/scm/linux/kernel/git/sfr/next-fixes.git#master
+kbuild-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git#rc-fixes
+arm-current	git	git://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur/linux-arm.git#fixes
+m68k-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git#for-linus
+powerpc-merge	git	git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git#merge
+sparc		git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc.git#master
+net		git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git#master
+sound-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git#for-linus
+pci-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git#for-linus
+wireless	git	git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git#master
+driver-core.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git#driver-core-linus
+tty.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git#tty-linus
+usb.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git#usb-linus
+staging.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git#staging-linus
+char-misc.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git#char-misc-linus
+input-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git#for-linus
+md-current	git	git://neil.brown.name/md#for-linus
+audit-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit.git#for-linus
+crypto-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6.git#master
+ide		git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide.git#master
+dwmw2		git	git://git.infradead.org/users/dwmw2/random-2.6.git#master
+sh-current	git	git://github.com/pmundt/linux-sh.git#sh-fixes-for-linus
+irqdomain-current	git	git://git.secretlab.ca/git/linux-2.6.git#irqdomain/merge
+devicetree-current	git	git://git.secretlab.ca/git/linux-2.6#devicetree/merge
+spi-current	git	git://git.secretlab.ca/git/linux-2.6#spi/merge
+gpio-current	git	git://git.secretlab.ca/git/linux-2.6#gpio/merge
+arm		git	git://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur/linux-arm.git#for-next
+arm-perf	git	git://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git#for-next/perf
+davinci		git	git://gitorious.org/linux-davinci/linux-davinci.git#davinci-next
+samsung		git	git://git.fluff.org/bjdooks/linux.git#next-samsung
+xilinx		git	git://git.xilinx.com/linux-2.6-xlnx.git#arm-next
+blackfin	git	git://git.kernel.org/pub/scm/linux/kernel/git/lliubbo/blackfin.git#for-linus
+c6x		git	git://linux-c6x.org/git/projects/linux-c6x-upstreaming.git#for-linux-next
+cris		git	git://www.jni.nu/cris.git#for-next
+hexagon		git	git://git.kernel.org/pub/scm/linux/kernel/git/rkuo/linux-hexagon-kernel.git#linux-next
+ia64		git	git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git#next
+m68k		git	git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git#for-next
+m68knommu	git	git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu.git#for-next
+microblaze	git	git://git.monstr.eu/linux-2.6-microblaze.git#next
+mips		git	git://git.linux-mips.org/pub/scm/ralf/upstream-sfr.git#mips-for-linux-next
+openrisc	git	git://openrisc.net/jonas/linux#for-upstream
+parisc		git	git://git.kernel.org/pub/scm/linux/kernel/git/jejb/parisc-2.6.git#for-next
+powerpc		git	git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git#next
+4xx		git	git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git#next
+mpc5xxx		git	git://git.denx.de/linux-2.6-agust.git#next
+galak		git	git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git#next
+s390		git	git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git#features
+sh		git	git://github.com/pmundt/linux-sh.git#sh-latest
+sparc-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next.git#master
+tile		git	git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile.git#master
+unicore32	git	git://github.com/gxt/linux.git#unicore32
+ceph		git	git://github.com/ceph/ceph-client.git#master
+cifs		git	git://git.samba.org/sfrench/cifs-2.6.git#for-next
+configfs	git	git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/configfs.git#linux-next
+ecryptfs	git	git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs.git#next
+ext3		git	git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git#for_next
+ext4		git	git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git#dev
+fuse		git	git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git#for-next
+gfs2		git	git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw.git#master
+logfs		git	git://github.com/prasad-joshi/logfs_upstream.git#master
+nfs		git	git://git.linux-nfs.org/projects/trondmy/nfs-2.6.git#linux-next
+nfsd		git	git://git.linux-nfs.org/~bfields/linux.git#nfsd-next
+ocfs2		git	git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2.git#linux-next
+omfs		git	git://github.com/bcopeland/omfs.git#for-next
+squashfs	git	git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-next.git#master
+v9fs		git	git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git#for-next
+ubifs		git	git://git.infradead.org/ubifs-2.6.git#linux-next
+xfs		git	git://oss.sgi.com/xfs/xfs.git#for-next
+vfs		git	git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6.git#for-next
+pci		git	git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git#next
+hid		git	git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git#for-next
+i2c		quilt	http://khali.linux-fr.org/devel/linux-3/jdelvare-i2c/
+bjdooks-i2c	git	git://git.fluff.org/bjdooks/linux.git#next-i2c
+i2c-embedded	git	git://git.pengutronix.de/git/wsa/linux.git#i2c-embedded/for-next
+jdelvare-hwmon	quilt	http://khali.linux-fr.org/devel/linux-3/jdelvare-hwmon/
+hwmon-staging	git	git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git#hwmon-next
+v4l-dvb		git	git://linuxtv.org/mchehab/media-next.git#master
+kbuild		git	git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git#for-next
+kconfig		git	git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-kconfig.git#for-next
+libata		git	git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev.git#NEXT
+infiniband	git	git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git#for-next
+acpi		git	git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git#next
+cpuidle		git	git://git.linaro.org/people/dlezcano/cpuidle-next.git#cpuidle-next
+cpupowerutils	git	git://git.kernel.org/pub/scm/linux/kernel/git/brodo/cpupowerutils.git#master
+ieee1394	git	git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git#for-next
+ubi		git	git://git.infradead.org/ubi-2.6.git#linux-next
+dlm		git	git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm.git#next
+scsi		git	git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git#for-next
+target-updates	git	git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git#for-next
+target-merge	git	git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git#for-next-merge
+ibft		git	git://git.kernel.org/pub/scm/linux/kernel/git/konrad/ibft.git#linux-next
+isci		git	git://git.kernel.org/pub/scm/linux/kernel/git/djbw/isci.git#all
+slave-dma	git	git://git.infradead.org/users/vkoul/slave-dma.git#next
+dmaengine	git	git://git.kernel.org/pub/scm/linux/kernel/git/djbw/dmaengine.git#next
+net-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git#master
+wireless-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next.git#master
+bluetooth	git	git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git#master
+mtd		git	git://git.infradead.org/mtd-2.6.git#master
+l2-mtd		git	git://git.infradead.org/users/dedekind/l2-mtd-2.6.git#master
+crypto		git	git://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git#master
+drm		git	git://people.freedesktop.org/~airlied/linux.git#drm-next
+sound		git	git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git#for-next
+sound-asoc	git	git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git#for-next
+rr		quilt	http://ozlabs.org/~rusty/kernel/rr-latest/
+input		git	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git#next
+input-mt	git	git://github.com/rydberg/linux.git#for-next
+cgroup		git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git#for-next
+block		git	git://git.kernel.dk/linux-block.git#for-next
+device-mapper	quilt	http://people.redhat.com/agk/patches/linux/editing/
+embedded	git	git://git.infradead.org/embedded-2.6.git#master
+firmware	git	git://git.infradead.org/users/dwmw2/firmware-2.6.git#master
+pcmcia		git	git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia.git#master
+mmc		git	git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git#mmc-next
+kgdb		git	git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb.git#kgdb-next
+slab		git	git://github.com/penberg/linux.git#for-next
+uclinux		git	git://git.kernel.org/pub/scm/linux/kernel/git/gerg/uclinux.git#for-next
+md		git	git://neil.brown.name/md#for-next
+mfd		git	git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6.git#for-next
+battery		git	git://git.infradead.org/battery-2.6.git#master
+fbdev		git	git://github.com/schandinat/linux-2.6.git#fbdev-next
+viafb		git	git://github.com/schandinat/linux-2.6.git#viafb-next
+omap_dss2	git	git://gitorious.org/linux-omap-dss2/linux.git#for-next
+regulator	git	git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git#for-next
+security	git	git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git#next
+selinux		git	git://git.infradead.org/users/eparis/selinux.git#master
+lblnet		git	git://git.infradead.org/users/pcmoore/lblnet-2.6_next#master
+watchdog	git	git://www.linux-watchdog.org/linux-watchdog-next.git#master
+dwmw2-iommu	git	git://git.infradead.org/iommu-2.6.git#master
+iommu		git	git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git#next
+vfio		git	git://github.com/awilliam/linux-vfio.git#next
+osd		git	git://git.open-osd.org/linux-open-osd.git#linux-next
+jc_docs		git	git://git.lwn.net/linux-2.6.git#docs-next
+trivial		git	git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git#for-next
+audit		git	git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit.git#for-next
+pm		git	git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git#linux-next
+apm		git	git://git.kernel.org/pub/scm/linux/kernel/git/jikos/apm.git#for-next
+fsnotify	git	git://git.infradead.org/users/eparis/notify.git#for-next
+edac		git	git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git#linux_next
+edac-amd	git	git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git#for-next
+devicetree	git	git://git.secretlab.ca/git/linux-2.6#devicetree/next
+spi		git	git://git.secretlab.ca/git/linux-2.6#spi/next
+tip		git	git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git#auto-latest
+rcu		git	git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git#rcu/next
+cputime		git	git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git#cputime
+uprobes		git	git://github.com/srikard/linux.git#for-next
+kmemleak	git	git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/linux.git#kmemleak
+kvm		git	git://git.kernel.org/pub/scm/virt/kvm/kvm.git#linux-next
+kvm-ppc		git	git://github.com/agraf/linux-2.6.git#kvm-ppc-next
+oprofile	git	git://git.kernel.org/pub/scm/linux/kernel/git/rric/oprofile.git#for-next
+xen		git	git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git#upstream/xen
+xen-two		git	git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen.git#linux-next
+xen-pvhvm	git	git://xenbits.xen.org/people/sstabellini/linux-pvhvm.git#linux-next
+percpu		git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu.git#for-next
+workqueues	git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git#for-next
+drivers-x86	git	git://cavan.codon.org.uk/platform-drivers-x86.git#linux-next
+hwpoison	git	git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git#hwpoison
+sysctl		git	git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/sysctl.git#master
+regmap		git	git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git#for-next
+hsi		git	git://gitorious.org/kernel-hsi/kernel-hsi.git#for-next
+leds		git	git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git#for-next
+driver-core	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git#driver-core-next
+tty		git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git#tty-next
+usb		git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git#usb-next
+staging		git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git#staging-next
+char-misc	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git#char-misc-next
+tmem		git	git://git.kernel.org/pub/scm/linux/kernel/git/konrad/mm.git#linux-next
+writeback	git	git://git.kernel.org/pub/scm/linux/kernel/git/wfg/linux.git#writeback-for-next
+arm-dt		git	git://git.secretlab.ca/git/linux-2.6#devicetree/arm-next
+hwspinlock	git	git://github.com/ohadbc/hwspinlock-next.git#linux-next
+pinctrl		git	git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git#for-next
+moduleh		git	git://openlinux.windriver.com/people/paulg/linux-next#for-sfr
+vhost		git	git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git#linux-next
+kmap_atomic	git	git://github.com/congwang/linux.git#kmap_atomic
+memblock	git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/misc.git#memblock-kill-early_node_map
+remoteproc	git	git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc.git#for-next
+irqdomain	git	git://git.secretlab.ca/git/linux-2.6.git#irqdomain/next
+gpio		git	git://git.secretlab.ca/git/linux-2.6#gpio/next
+arm-soc		git	git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git#for-next
+ep93xx		git	git://github.com/RyanMallon/linux-ep93xx.git#ep93xx-for-next
+renesas		git	git://git.kernel.org/pub/scm/linux/kernel/git/rafael/renesas.git#next
+s5p		git	git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git#for-next
+tegra		git	git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra.git#for-next
+kvmtool		git	git://github.com/penberg/linux-kvm.git#master
+dma-mapping	git	git://git.linaro.org/people/mszyprowski/linux-dma-mapping.git#dma-mapping-next
+dma-buf		git	git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git#for-next
+userns		git	git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git#for-next
+ktest		git	git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-ktest.git#for-next
+signal		git	git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal.git#for-next
+scsi-post-merge	git	git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-post-merge-2.6.git#master
+akpm		mmotm	http://www.ozlabs.org/~akpm/mmotm/
diff --git a/Next/merge.log b/Next/merge.log
new file mode 100644
index 0000000..e480aad
--- /dev/null
+++ b/Next/merge.log
@@ -0,0 +1,6626 @@
+$ date
+Wednesday 27 June  10:10:07 EST 2012
+$ git checkout master
+Already on 'master'
+$ git reset --hard stable
+HEAD is now at aace99e Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
+Merging origin/master (d1346a6 Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux)
+$ git merge origin/master
+Updating aace99e..d1346a6
+Fast-forward
+ drivers/gpu/drm/nouveau/nouveau_fbcon.c |    2 +-
+ drivers/gpu/drm/udl/udl_main.c          |    2 +-
+ drivers/hid/Kconfig                     |   43 ++++++++++++++-----------------
+ drivers/hid/hid-logitech-dj.c           |   38 +++++++++++++++++----------
+ drivers/hid/hid-magicmouse.c            |    6 +++--
+ drivers/hid/usbhid/Kconfig              |    8 +++---
+ net/bluetooth/hidp/Kconfig              |    2 +-
+ 7 files changed, 55 insertions(+), 46 deletions(-)
+Merging fixes/master (9023a40 Merge tag 'mmc-fixes-for-3.5-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc)
+$ git merge fixes/master
+Already up-to-date.
+Merging kbuild-current/rc-fixes (464076b Makefile: Do not call cc-option before including the arch's Makefile)
+$ git merge kbuild-current/rc-fixes
+Merge made by the 'recursive' strategy.
+Merging arm-current/fixes (10aa5a3 SPI: fix over-eager devm_xxx() conversion)
+$ git merge arm-current/fixes
+Already up-to-date.
+Merging m68k-current/for-linus (d8ce726 m68k: Use generic strncpy_from_user(), strlen_user(), and strnlen_user())
+$ git merge m68k-current/for-linus
+Already up-to-date.
+Merging powerpc-merge/merge (7c0482e powerpc/irq: Fix another case of lazy IRQ state getting out of sync)
+$ git merge powerpc-merge/merge
+Already up-to-date.
+Merging sparc/master (39a50b4 Merge branch 'hfsplus')
+$ git merge sparc/master
+Already up-to-date.
+Merging net/master (8a8e28b mac802154: add missed braces)
+$ git merge net/master
+Merge made by the 'recursive' strategy.
+ drivers/bluetooth/ath3k.c                        |    3 +
+ drivers/bluetooth/btmrvl_drv.h                   |    2 +-
+ drivers/bluetooth/btmrvl_main.c                  |   14 +++-
+ drivers/bluetooth/btmrvl_sdio.c                  |    8 ++-
+ drivers/bluetooth/btusb.c                        |    2 +
+ drivers/net/bonding/bond_procfs.c                |   15 +++-
+ drivers/net/caif/caif_hsi.c                      |    5 +-
+ drivers/net/can/c_can/c_can.c                    |    4 +-
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c  |    8 +--
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c |   54 +++++++-------
+ drivers/net/ethernet/emulex/benet/be_cmds.c      |   12 ++--
+ drivers/net/ethernet/emulex/benet/be_cmds.h      |    2 +-
+ drivers/net/ethernet/emulex/benet/be_main.c      |    2 +-
+ drivers/net/ethernet/intel/Kconfig               |   10 ++-
+ drivers/net/ethernet/intel/igb/e1000_82575.c     |    2 -
+ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c    |    2 +-
+ drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c     |   13 +++-
+ drivers/net/ethernet/mellanox/mlx4/en_netdev.c   |   18 +++--
+ drivers/net/ethernet/mellanox/mlx4/main.c        |    2 +
+ drivers/net/ethernet/mellanox/mlx4/mlx4_en.h     |    1 +
+ drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c |    2 +-
+ drivers/net/ethernet/realtek/r8169.c             |    1 +
+ drivers/net/ethernet/renesas/sh_eth.c            |   12 ++--
+ drivers/net/phy/micrel.c                         |    8 +--
+ drivers/net/usb/ipheth.c                         |    5 ++
+ drivers/net/usb/qmi_wwan.c                       |   83 +++++++++++-----------
+ drivers/net/usb/usbnet.c                         |   53 ++++++++------
+ drivers/net/wireless/airo.c                      |    4 +-
+ drivers/net/wireless/ath/ath5k/base.c            |    4 +-
+ drivers/net/wireless/ath/ath9k/ath9k.h           |    1 +
+ drivers/net/wireless/ath/ath9k/htc_drv_main.c    |    5 +-
+ drivers/net/wireless/ath/ath9k/hw.c              |   14 +++-
+ drivers/net/wireless/ath/ath9k/main.c            |   27 +++----
+ drivers/net/wireless/ath/ath9k/xmit.c            |   31 ++++----
+ drivers/net/wireless/iwlwifi/iwl-debugfs.c       |    6 ++
+ drivers/net/wireless/mwifiex/cfg80211.c          |   25 +++----
+ drivers/net/wireless/mwifiex/txrx.c              |   10 +--
+ drivers/net/wireless/mwifiex/uap_cmd.c           |   11 +++
+ drivers/net/wireless/rndis_wlan.c                |    2 +-
+ drivers/net/wireless/ti/wl1251/acx.c             |    2 +-
+ drivers/net/wireless/ti/wl1251/event.c           |    3 +-
+ drivers/net/wireless/ti/wl1251/spi.c             |    4 ++
+ include/linux/skbuff.h                           |    7 +-
+ include/net/bluetooth/hci.h                      |    6 ++
+ include/net/mac80211.h                           |    6 ++
+ include/net/phonet/gprs.h                        |    2 +-
+ net/batman-adv/routing.c                         |    2 +
+ net/batman-adv/translation-table.c               |   12 ++--
+ net/bluetooth/hci_event.c                        |   48 +++++++++++++
+ net/bluetooth/l2cap_core.c                       |   21 ++++--
+ net/bluetooth/mgmt.c                             |   20 +++++-
+ net/bluetooth/smp.c                              |   11 +--
+ net/caif/caif_dev.c                              |    3 +-
+ net/caif/caif_socket.c                           |    1 +
+ net/can/raw.c                                    |    3 -
+ net/core/dev.c                                   |   23 +-----
+ net/ipv6/ip6_fib.c                               |    4 +-
+ net/ipv6/route.c                                 |   41 ++++++++---
+ net/ipv6/tcp_ipv6.c                              |    3 +-
+ net/iucv/af_iucv.c                               |    1 -
+ net/l2tp/l2tp_eth.c                              |    6 +-
+ net/mac80211/cfg.c                               |    3 +
+ net/mac80211/mlme.c                              |    4 +-
+ net/mac80211/sta_info.h                          |    5 ++
+ net/mac802154/tx.c                               |    3 +-
+ net/phonet/af_phonet.c                           |    4 +-
+ net/phonet/datagram.c                            |    4 +-
+ net/phonet/pep-gprs.c                            |    2 +-
+ net/phonet/pep.c                                 |    2 +-
+ net/phonet/pn_dev.c                              |    4 +-
+ net/phonet/pn_netlink.c                          |    4 +-
+ net/phonet/socket.c                              |    4 +-
+ net/phonet/sysctl.c                              |    2 +-
+ net/sctp/protocol.c                              |    2 +
+ net/wireless/reg.c                               |    2 +-
+ net/wireless/util.c                              |    2 +-
+ 76 files changed, 473 insertions(+), 286 deletions(-)
+Merging sound-current/for-linus (6e1c39c ALSA: hda - Fix power-map regression for HP dv6 & co)
+$ git merge sound-current/for-linus
+Merge made by the 'recursive' strategy.
+ sound/pci/hda/Kconfig           |   13 -------------
+ sound/pci/hda/hda_auto_parser.c |    1 -
+ sound/pci/hda/hda_auto_parser.h |   10 ++++++++++
+ sound/pci/hda/hda_codec.c       |    4 ++++
+ sound/pci/hda/patch_conexant.c  |    6 +++++-
+ sound/pci/hda/patch_realtek.c   |   15 +++++++++------
+ sound/pci/hda/patch_sigmatel.c  |    7 ++++++-
+ sound/soc/codecs/wm8994.c       |    3 ---
+ sound/usb/mixer_maps.c          |    8 ++++++++
+ sound/usb/quirks-table.h        |   30 ++++++++++++++++++++++++++++++
+ 10 files changed, 72 insertions(+), 25 deletions(-)
+Merging pci-current/for-linus (314489b Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc)
+$ git merge pci-current/for-linus
+Already up-to-date.
+Merging wireless/master (161ae88 Merge branch 'for-wireless' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-3.0)
+$ git merge wireless/master
+Merge made by the 'recursive' strategy.
+ drivers/net/wireless/ath/ath.h               |    1 +
+ drivers/net/wireless/ath/ath9k/recv.c        |    3 ++-
+ drivers/net/wireless/ath/key.c               |    4 ++++
+ drivers/net/wireless/iwlwifi/iwl-mac80211.c  |   12 +++++++++++
+ drivers/net/wireless/mwifiex/11n_rxreorder.c |    5 +++--
+ drivers/net/wireless/mwifiex/11n_rxreorder.h |    7 +++++++
+ drivers/net/wireless/mwifiex/sdio.c          |    6 +++---
+ drivers/net/wireless/mwifiex/sta_event.c     |    9 ++++-----
+ drivers/net/wireless/mwifiex/usb.c           |   28 ++++++++++++++++++--------
+ drivers/net/wireless/mwifiex/wmm.c           |    3 +++
+ drivers/net/wireless/ti/wlcore/Kconfig       |    1 -
+ net/mac80211/mlme.c                          |   13 ++++++------
+ net/nfc/nci/ntf.c                            |   10 ++++-----
+ net/nfc/rawsock.c                            |    5 ++++-
+ 14 files changed, 74 insertions(+), 33 deletions(-)
+Merging driver-core.current/driver-core-linus (116e90b syslog: fill buffer with more than a single message for SYSLOG_ACTION_READ)
+$ git merge driver-core.current/driver-core-linus
+Merge made by the 'recursive' strategy.
+ Documentation/stable_kernel_rules.txt |    6 ++++
+ kernel/printk.c                       |   54 +++++++++++++++++++++++----------
+ 2 files changed, 44 insertions(+), 16 deletions(-)
+Merging tty.current/tty-linus (6b16351 Linux 3.5-rc4)
+$ git merge tty.current/tty-linus
+Already up-to-date.
+Merging usb.current/usb-linus (3fcc8f9 USB: CP210x Add 10 Device IDs)
+$ git merge usb.current/usb-linus
+Merge made by the 'recursive' strategy.
+ drivers/scsi/sd.c                  |    2 ++
+ drivers/usb/Makefile               |    2 +-
+ drivers/usb/dwc3/gadget.c          |    3 ++-
+ drivers/usb/gadget/fsl_qe_udc.h    |    4 ++--
+ drivers/usb/gadget/lpc32xx_udc.c   |    1 +
+ drivers/usb/musb/musb_host.c       |   14 ++++++++++++--
+ drivers/usb/otg/twl6030-usb.c      |   15 ++++++---------
+ drivers/usb/phy/Kconfig            |    4 ++--
+ drivers/usb/serial/cp210x.c        |   11 +++++++++++
+ drivers/usb/serial/option.c        |    8 ++++++++
+ drivers/usb/storage/scsiglue.c     |    6 ++++++
+ drivers/usb/storage/unusual_devs.h |    7 -------
+ include/scsi/scsi_device.h         |    1 +
+ 13 files changed, 54 insertions(+), 24 deletions(-)
+Merging staging.current/staging-linus (6b16351 Linux 3.5-rc4)
+$ git merge staging.current/staging-linus
+Already up-to-date.
+Merging char-misc.current/char-misc-linus (6b16351 Linux 3.5-rc4)
+$ git merge char-misc.current/char-misc-linus
+Already up-to-date.
+Merging input-current/for-linus (2177905 Input: fix input.h kernel-doc warning)
+$ git merge input-current/for-linus
+Merge made by the 'recursive' strategy.
+ include/linux/input.h |    1 +
+ 1 file changed, 1 insertion(+)
+Merging md-current/for-linus (aba336b md: raid1/raid10: fix problem with merge_bvec_fn)
+$ git merge md-current/for-linus
+Already up-to-date.
+Merging audit-current/for-linus (c158a35 audit: no leading space in audit_log_d_path prefix)
+$ git merge audit-current/for-linus
+Already up-to-date.
+Merging crypto-current/master (c475c06 hwrng: atmel-rng - fix data valid check)
+$ git merge crypto-current/master
+Already up-to-date.
+Merging ide/master (39a50b4 Merge branch 'hfsplus')
+$ git merge ide/master
+Already up-to-date.
+Merging dwmw2/master (244dc4e Merge git://git.infradead.org/users/dwmw2/random-2.6)
+$ git merge dwmw2/master
+Already up-to-date.
+Merging sh-current/sh-fixes-for-linus (790b9d4 Merge tag 'sh-for-linus' of git://github.com/pmundt/linux-sh)
+$ git merge sh-current/sh-fixes-for-linus
+Already up-to-date.
+Merging irqdomain-current/irqdomain/merge (15e06bf irqdomain: Fix debugfs formatting)
+$ git merge irqdomain-current/irqdomain/merge
+Already up-to-date.
+Merging devicetree-current/devicetree/merge (4e8383b of: release node fix for of_parse_phandle_with_args)
+$ git merge devicetree-current/devicetree/merge
+Merge made by the 'recursive' strategy.
+ drivers/of/base.c |    2 ++
+ 1 file changed, 2 insertions(+)
+Merging spi-current/spi/merge (d1c185b of/spi: Fix SPI module loading by using proper "spi:" modalias prefixes.)
+$ git merge spi-current/spi/merge
+Merge made by the 'recursive' strategy.
+ drivers/spi/spi-bcm63xx.c |   16 ++++++----------
+ drivers/spi/spi-s3c64xx.c |   10 ++++------
+ drivers/spi/spi.c         |    7 +++++--
+ 3 files changed, 15 insertions(+), 18 deletions(-)
+Merging gpio-current/gpio/merge (96b7064 gpio/tca6424: merge I2C transactions, remove cast)
+$ git merge gpio-current/gpio/merge
+Merge made by the 'recursive' strategy.
+ drivers/gpio/gpio-pca953x.c |   28 ++++++++++++++++------------
+ drivers/gpio/gpiolib-of.c   |    2 +-
+ 2 files changed, 17 insertions(+), 13 deletions(-)
+Merging arm/for-next (4d0d790 Merge branches 'fixes' and 'misc' into for-next)
+$ git merge arm/for-next
+Merge made by the 'recursive' strategy.
+ arch/arm/Makefile                              |    3 ++
+ arch/arm/mach-msm/platsmp.c                    |    2 +-
+ arch/arm/mach-omap2/omap-smp.c                 |    2 +-
+ arch/arm/mach-pxa/include/mach/regs-ost.h      |   22 +++++-----
+ arch/arm/mach-pxa/reset.c                      |    7 ++--
+ arch/arm/mach-pxa/time.c                       |   52 ++++++++++++------------
+ arch/arm/mach-sa1100/assabet.c                 |    2 +-
+ arch/arm/mach-sa1100/cpu-sa1110.c              |    1 +
+ arch/arm/mach-sa1100/include/mach/SA-1100.h    |   16 ++++----
+ arch/arm/mach-sa1100/include/mach/gpio.h       |    1 +
+ arch/arm/mach-sa1100/include/mach/hardware.h   |    6 ++-
+ arch/arm/mach-sa1100/include/mach/uncompress.h |    2 +
+ arch/arm/mach-sa1100/irq.c                     |    1 +
+ arch/arm/mach-sa1100/pm.c                      |    1 +
+ arch/arm/mach-sa1100/time.c                    |   48 +++++++++++-----------
+ arch/arm/plat-versatile/platsmp.c              |    2 +-
+ drivers/watchdog/sa1100_wdt.c                  |   14 +++----
+ 17 files changed, 97 insertions(+), 85 deletions(-)
+Merging arm-perf/for-next/perf (dee8c1b ARM: perf: remove arm_perf_pmu_ids global enumeration)
+$ git merge arm-perf/for-next/perf
+Merge made by the 'recursive' strategy.
+ arch/arm/include/asm/perf_event.h   |   17 +------------
+ arch/arm/include/asm/pmu.h          |    3 +--
+ arch/arm/kernel/perf_event.c        |   15 +++++-------
+ arch/arm/kernel/perf_event_v6.c     |    2 --
+ arch/arm/kernel/perf_event_v7.c     |    5 ----
+ arch/arm/kernel/perf_event_xscale.c |    2 --
+ arch/arm/oprofile/common.c          |   45 ++++++++++++++++++++++-------------
+ 7 files changed, 36 insertions(+), 53 deletions(-)
+Merging davinci/davinci-next (fe0d422 Linux 3.0-rc6)
+$ git merge davinci/davinci-next
+Already up-to-date.
+Merging samsung/next-samsung (9edb240 ARM: H1940/RX1950: Change default LED triggers)
+$ git merge samsung/next-samsung
+Already up-to-date.
+Merging xilinx/arm-next (b85a3ef ARM: Xilinx: Adding Xilinx board support)
+$ git merge xilinx/arm-next
+Already up-to-date.
+Merging blackfin/for-linus (672552a blackfin: fix build after add bf60x mach/pm.h)
+$ git merge blackfin/for-linus
+Already up-to-date.
+Merging c6x/for-linux-next (485802a Linux 3.5-rc3)
+$ git merge c6x/for-linux-next
+Already up-to-date.
+Merging cris/for-next (2608747 CRIS: Remove VCS simulator specific code)
+$ git merge cris/for-next
+Removing arch/cris/arch-v32/mach-fs/vcs_hook.h
+Removing arch/cris/arch-v32/mach-fs/vcs_hook.c
+Removing arch/cris/arch-v32/mach-a3/vcs_hook.h
+Removing arch/cris/arch-v32/mach-a3/vcs_hook.c
+Merge made by the 'recursive' strategy.
+ arch/cris/Kconfig                                  |    5 -
+ arch/cris/arch-v32/drivers/axisflashmap.c          |   29 ------
+ arch/cris/arch-v32/drivers/pci/bios.c              |   25 -----
+ arch/cris/arch-v32/kernel/head.S                   |   58 +----------
+ arch/cris/arch-v32/kernel/kgdb.c                   |   14 ---
+ arch/cris/arch-v32/mach-a3/Makefile                |    2 -
+ arch/cris/arch-v32/mach-a3/vcs_hook.c              |  103 --------------------
+ arch/cris/arch-v32/mach-a3/vcs_hook.h              |   58 -----------
+ arch/cris/arch-v32/mach-fs/Makefile                |    2 -
+ arch/cris/arch-v32/mach-fs/vcs_hook.c              |  100 -------------------
+ arch/cris/arch-v32/mach-fs/vcs_hook.h              |   42 --------
+ arch/cris/arch-v32/mm/init.c                       |    8 --
+ arch/cris/include/arch-v32/arch/page.h             |    5 -
+ arch/cris/include/arch-v32/arch/processor.h        |    6 +-
+ .../cris/include/arch-v32/mach-fs/mach/startup.inc |    6 --
+ arch/cris/include/asm/pci.h                        |    1 -
+ 16 files changed, 3 insertions(+), 461 deletions(-)
+ delete mode 100644 arch/cris/arch-v32/mach-a3/vcs_hook.c
+ delete mode 100644 arch/cris/arch-v32/mach-a3/vcs_hook.h
+ delete mode 100644 arch/cris/arch-v32/mach-fs/vcs_hook.c
+ delete mode 100644 arch/cris/arch-v32/mach-fs/vcs_hook.h
+Merging hexagon/linux-next (5042ab9 various Kconfig cleanup and old platform build code removal)
+$ git merge hexagon/linux-next
+Already up-to-date.
+Merging ia64/next (f28fa72 [IA64] Port OOM changes to ia64_do_page_fault)
+$ git merge ia64/next
+Merge made by the 'recursive' strategy.
+ arch/ia64/mm/fault.c |   46 ++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 34 insertions(+), 12 deletions(-)
+Merging m68k/for-next (4fa0cff m68knommu: Allow ColdFire CPUs to use unaligned accesses)
+$ git merge m68k/for-next
+Removing arch/m68k/include/asm/xor.h
+Removing arch/m68k/include/asm/types.h
+Removing arch/m68k/include/asm/topology.h
+Removing arch/m68k/include/asm/statfs.h
+Removing arch/m68k/include/asm/siginfo.h
+Removing arch/m68k/include/asm/scatterlist.h
+Removing arch/m68k/include/asm/sbus.h
+Removing arch/m68k/include/asm/resource.h
+Removing arch/m68k/include/asm/percpu.h
+Removing arch/m68k/include/asm/mutex.h
+Removing arch/m68k/include/asm/mman.h
+Removing arch/m68k/include/asm/mcfne.h
+Removing arch/m68k/include/asm/mcfmbus.h
+Removing arch/m68k/include/asm/mac_mouse.h
+Removing arch/m68k/include/asm/local64.h
+Removing arch/m68k/include/asm/local.h
+Removing arch/m68k/include/asm/kvm_para.h
+Removing arch/m68k/include/asm/kmap_types.h
+Removing arch/m68k/include/asm/kdebug.h
+Removing arch/m68k/include/asm/irq_regs.h
+Removing arch/m68k/include/asm/ipcbuf.h
+Removing arch/m68k/include/asm/ioctl.h
+Removing arch/m68k/include/asm/futex.h
+Removing arch/m68k/include/asm/errno.h
+Removing arch/m68k/include/asm/emergency-restart.h
+Removing arch/m68k/include/asm/device.h
+Removing arch/m68k/include/asm/cputime.h
+Removing arch/m68k/include/asm/bitsperlong.h
+Removing arch/m68k/include/asm/apollodma.h
+Removing arch/m68k/include/asm/MC68332.h
+Merge made by the 'recursive' strategy.
+ arch/m68k/Kconfig                         |   12 --
+ arch/m68k/Kconfig.cpu                     |   14 ++
+ arch/m68k/include/asm/Kbuild              |   24 +++
+ arch/m68k/include/asm/MC68332.h           |  152 ------------------
+ arch/m68k/include/asm/apollodma.h         |  248 -----------------------------
+ arch/m68k/include/asm/bitsperlong.h       |    1 -
+ arch/m68k/include/asm/cputime.h           |    6 -
+ arch/m68k/include/asm/delay.h             |    2 +-
+ arch/m68k/include/asm/device.h            |    7 -
+ arch/m68k/include/asm/emergency-restart.h |    6 -
+ arch/m68k/include/asm/errno.h             |    6 -
+ arch/m68k/include/asm/futex.h             |    6 -
+ arch/m68k/include/asm/ioctl.h             |    1 -
+ arch/m68k/include/asm/ipcbuf.h            |    1 -
+ arch/m68k/include/asm/irq_regs.h          |    1 -
+ arch/m68k/include/asm/kdebug.h            |    1 -
+ arch/m68k/include/asm/kmap_types.h        |    6 -
+ arch/m68k/include/asm/kvm_para.h          |    1 -
+ arch/m68k/include/asm/local.h             |    6 -
+ arch/m68k/include/asm/local64.h           |    1 -
+ arch/m68k/include/asm/mac_mouse.h         |   23 ---
+ arch/m68k/include/asm/mcfmbus.h           |   77 ---------
+ arch/m68k/include/asm/mcfne.h             |  242 ----------------------------
+ arch/m68k/include/asm/mman.h              |    1 -
+ arch/m68k/include/asm/mutex.h             |    9 --
+ arch/m68k/include/asm/percpu.h            |    6 -
+ arch/m68k/include/asm/resource.h          |    6 -
+ arch/m68k/include/asm/sbus.h              |   45 ------
+ arch/m68k/include/asm/scatterlist.h       |    6 -
+ arch/m68k/include/asm/siginfo.h           |    6 -
+ arch/m68k/include/asm/statfs.h            |    6 -
+ arch/m68k/include/asm/topology.h          |    6 -
+ arch/m68k/include/asm/types.h             |   22 ---
+ arch/m68k/include/asm/unaligned.h         |    4 +-
+ arch/m68k/include/asm/xor.h               |    1 -
+ arch/m68k/kernel/setup_no.c               |   11 +-
+ arch/m68k/lib/muldi3.c                    |    2 +-
+ 37 files changed, 46 insertions(+), 929 deletions(-)
+ delete mode 100644 arch/m68k/include/asm/MC68332.h
+ delete mode 100644 arch/m68k/include/asm/apollodma.h
+ delete mode 100644 arch/m68k/include/asm/bitsperlong.h
+ delete mode 100644 arch/m68k/include/asm/cputime.h
+ delete mode 100644 arch/m68k/include/asm/device.h
+ delete mode 100644 arch/m68k/include/asm/emergency-restart.h
+ delete mode 100644 arch/m68k/include/asm/errno.h
+ delete mode 100644 arch/m68k/include/asm/futex.h
+ delete mode 100644 arch/m68k/include/asm/ioctl.h
+ delete mode 100644 arch/m68k/include/asm/ipcbuf.h
+ delete mode 100644 arch/m68k/include/asm/irq_regs.h
+ delete mode 100644 arch/m68k/include/asm/kdebug.h
+ delete mode 100644 arch/m68k/include/asm/kmap_types.h
+ delete mode 100644 arch/m68k/include/asm/kvm_para.h
+ delete mode 100644 arch/m68k/include/asm/local.h
+ delete mode 100644 arch/m68k/include/asm/local64.h
+ delete mode 100644 arch/m68k/include/asm/mac_mouse.h
+ delete mode 100644 arch/m68k/include/asm/mcfmbus.h
+ delete mode 100644 arch/m68k/include/asm/mcfne.h
+ delete mode 100644 arch/m68k/include/asm/mman.h
+ delete mode 100644 arch/m68k/include/asm/mutex.h
+ delete mode 100644 arch/m68k/include/asm/percpu.h
+ delete mode 100644 arch/m68k/include/asm/resource.h
+ delete mode 100644 arch/m68k/include/asm/sbus.h
+ delete mode 100644 arch/m68k/include/asm/scatterlist.h
+ delete mode 100644 arch/m68k/include/asm/siginfo.h
+ delete mode 100644 arch/m68k/include/asm/statfs.h
+ delete mode 100644 arch/m68k/include/asm/topology.h
+ delete mode 100644 arch/m68k/include/asm/types.h
+ delete mode 100644 arch/m68k/include/asm/xor.h
+Merging m68knommu/for-next (cec069e m68knommu: Add clk definitions for m532x.)
+$ git merge m68knommu/for-next
+Removing arch/m68k/platform/coldfire/pinmux.c
+Removing arch/m68k/kernel/entry_no.S
+Removing arch/m68k/kernel/entry_mm.S
+Removing arch/m68k/include/asm/pinmux.h
+Auto-merging arch/m68k/Kconfig.cpu
+Merge made by the 'recursive' strategy.
+ arch/m68k/Kconfig.cpu                   |   18 +-
+ arch/m68k/Makefile                      |    2 +
+ arch/m68k/include/asm/dma.h             |    4 +-
+ arch/m68k/include/asm/gpio.h            |  179 +-----------
+ arch/m68k/include/asm/m520xsim.h        |   14 +
+ arch/m68k/include/asm/m523xsim.h        |    1 +
+ arch/m68k/include/asm/m525xsim.h        |  194 +++++++++++++
+ arch/m68k/include/asm/m527xsim.h        |    1 +
+ arch/m68k/include/asm/m528xsim.h        |    2 +-
+ arch/m68k/include/asm/m532xsim.h        |   17 ++
+ arch/m68k/include/asm/m5441xsim.h       |  276 +++++++++++++++++++
+ arch/m68k/include/asm/m54xxacr.h        |    4 +
+ arch/m68k/include/asm/mcfclk.h          |   43 +++
+ arch/m68k/include/asm/mcfgpio.h         |  343 ++++++++++++++++++-----
+ arch/m68k/include/asm/mcfsim.h          |    5 +
+ arch/m68k/include/asm/mcftimer.h        |    2 +-
+ arch/m68k/include/asm/mcfuart.h         |    4 +-
+ arch/m68k/include/asm/pinmux.h          |   30 --
+ arch/m68k/kernel/entry.S                |  452 ++++++++++++++++++++++++++++++-
+ arch/m68k/kernel/entry_mm.S             |  419 ----------------------------
+ arch/m68k/kernel/entry_no.S             |  130 ---------
+ arch/m68k/platform/coldfire/Makefile    |    4 +-
+ arch/m68k/platform/coldfire/clk.c       |  107 +++++++-
+ arch/m68k/platform/coldfire/device.c    |   57 +++-
+ arch/m68k/platform/coldfire/gpio.c      |  172 +++++++-----
+ arch/m68k/platform/coldfire/head.S      |    6 +-
+ arch/m68k/platform/coldfire/intc-525x.c |   91 +++++++
+ arch/m68k/platform/coldfire/intc-simr.c |   26 +-
+ arch/m68k/platform/coldfire/m5206.c     |    9 -
+ arch/m68k/platform/coldfire/m520x.c     |  103 ++++++-
+ arch/m68k/platform/coldfire/m523x.c     |   22 --
+ arch/m68k/platform/coldfire/m5249.c     |   10 -
+ arch/m68k/platform/coldfire/m525x.c     |   66 +++++
+ arch/m68k/platform/coldfire/m5272.c     |   11 -
+ arch/m68k/platform/coldfire/m527x.c     |   43 ---
+ arch/m68k/platform/coldfire/m528x.c     |   33 +--
+ arch/m68k/platform/coldfire/m5307.c     |    9 -
+ arch/m68k/platform/coldfire/m532x.c     |  154 +++++++++--
+ arch/m68k/platform/coldfire/m5407.c     |    9 -
+ arch/m68k/platform/coldfire/m5441x.c    |  261 ++++++++++++++++++
+ arch/m68k/platform/coldfire/m54xx.c     |    7 -
+ arch/m68k/platform/coldfire/pinmux.c    |   28 --
+ arch/m68k/platform/coldfire/pit.c       |    4 +-
+ arch/m68k/platform/coldfire/timers.c    |    2 +-
+ drivers/spi/Kconfig                     |    2 +-
+ 45 files changed, 2256 insertions(+), 1120 deletions(-)
+ create mode 100644 arch/m68k/include/asm/m525xsim.h
+ create mode 100644 arch/m68k/include/asm/m5441xsim.h
+ create mode 100644 arch/m68k/include/asm/mcfclk.h
+ delete mode 100644 arch/m68k/include/asm/pinmux.h
+ delete mode 100644 arch/m68k/kernel/entry_mm.S
+ delete mode 100644 arch/m68k/kernel/entry_no.S
+ create mode 100644 arch/m68k/platform/coldfire/intc-525x.c
+ create mode 100644 arch/m68k/platform/coldfire/m525x.c
+ create mode 100644 arch/m68k/platform/coldfire/m5441x.c
+ delete mode 100644 arch/m68k/platform/coldfire/pinmux.c
+Merging microblaze/next (a01ee16 Merge branch 'for-linus' of git://git.open-osd.org/linux-open-osd)
+$ git merge microblaze/next
+Already up-to-date.
+Merging mips/mips-for-linux-next (1f04189 Merge branch 'next/loongson1b' into mips-for-linux-next)
+$ git merge mips/mips-for-linux-next
+Auto-merging drivers/spi/Kconfig
+Removing arch/mips/lib/memcpy-inatomic.S
+Removing arch/mips/include/asm/octeon/cvmx-helper-fpa.h
+Removing arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c
+Removing arch/mips/cavium-octeon/executive/cvmx-fpa.c
+Removing arch/mips/alchemy/devboards/prom.c
+Merge made by the 'recursive' strategy.
+ .../bindings/ata/cavium-compact-flash.txt          |   30 +
+ .../bindings/gpio/cavium-octeon-gpio.txt           |   49 ++
+ .../devicetree/bindings/i2c/cavium-i2c.txt         |   34 ++
+ .../devicetree/bindings/mips/cavium/bootbus.txt    |  126 ++++
+ .../devicetree/bindings/mips/cavium/ciu.txt        |   26 +
+ .../devicetree/bindings/mips/cavium/ciu2.txt       |   27 +
+ .../devicetree/bindings/mips/cavium/dma-engine.txt |   21 +
+ .../devicetree/bindings/mips/cavium/uctl.txt       |   46 ++
+ .../devicetree/bindings/net/cavium-mdio.txt        |   27 +
+ .../devicetree/bindings/net/cavium-mix.txt         |   39 ++
+ .../devicetree/bindings/net/cavium-pip.txt         |   98 +++
+ .../devicetree/bindings/serial/cavium-uart.txt     |   19 +
+ arch/mips/Kbuild.platforms                         |    1 +
+ arch/mips/Kconfig                                  |   41 +-
+ arch/mips/alchemy/board-mtx1.c                     |    4 +-
+ arch/mips/alchemy/common/platform.c                |   10 +-
+ arch/mips/alchemy/devboards/Makefile               |    2 +-
+ arch/mips/alchemy/devboards/bcsr.c                 |    5 +-
+ arch/mips/alchemy/devboards/pb1100.c               |    4 +-
+ arch/mips/alchemy/devboards/pb1500.c               |    4 +-
+ arch/mips/alchemy/devboards/platform.c             |   30 +
+ arch/mips/alchemy/devboards/prom.c                 |   69 ---
+ arch/mips/bcm47xx/Kconfig                          |    1 +
+ arch/mips/bcm63xx/Kconfig                          |    4 +
+ arch/mips/bcm63xx/Makefile                         |    3 +-
+ arch/mips/bcm63xx/boards/board_bcm963xx.c          |  107 ++--
+ arch/mips/bcm63xx/clk.c                            |   26 +-
+ arch/mips/bcm63xx/cpu.c                            |   63 +-
+ arch/mips/bcm63xx/dev-dsp.c                        |    2 +-
+ arch/mips/bcm63xx/dev-flash.c                      |  123 ++++
+ arch/mips/bcm63xx/dev-pcmcia.c                     |    4 +-
+ arch/mips/bcm63xx/dev-rng.c                        |   40 ++
+ arch/mips/bcm63xx/dev-spi.c                        |  119 ++++
+ arch/mips/bcm63xx/dev-wdt.c                        |    2 +-
+ arch/mips/bcm63xx/irq.c                            |   21 +
+ arch/mips/bcm63xx/prom.c                           |    4 +-
+ arch/mips/bcm63xx/setup.c                          |   13 +-
+ arch/mips/boot/compressed/Makefile                 |    4 +
+ arch/mips/boot/compressed/uart-16550.c             |    5 +
+ arch/mips/cavium-octeon/.gitignore                 |    2 +
+ arch/mips/cavium-octeon/Kconfig                    |    4 -
+ arch/mips/cavium-octeon/Makefile                   |   16 +
+ arch/mips/cavium-octeon/executive/cvmx-fpa.c       |  183 ------
+ .../mips/cavium-octeon/executive/cvmx-helper-fpa.c |  243 --------
+ arch/mips/cavium-octeon/octeon-irq.c               |  184 +++---
+ arch/mips/cavium-octeon/octeon-memcpy.S            |   16 +-
+ arch/mips/cavium-octeon/octeon-platform.c          |  523 +++++++++++++++-
+ arch/mips/cavium-octeon/octeon_3xxx.dts            |  571 ++++++++++++++++++
+ arch/mips/cavium-octeon/octeon_68xx.dts            |  625 ++++++++++++++++++++
+ arch/mips/cavium-octeon/setup.c                    |   45 ++
+ arch/mips/cavium-octeon/smp.c                      |    2 +-
+ arch/mips/configs/ls1b_defconfig                   |  108 ++++
+ arch/mips/configs/nlm_xlr_defconfig                |    4 +
+ arch/mips/dec/prom/memory.c                        |    2 +-
+ arch/mips/include/asm/cmpxchg.h                    |    1 +
+ arch/mips/include/asm/cpu.h                        |    8 +-
+ arch/mips/include/asm/gic.h                        |   15 +-
+ arch/mips/include/asm/inst.h                       |    4 +-
+ arch/mips/include/asm/irq.h                        |    1 +
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h   |  150 ++++-
+ .../include/asm/mach-bcm63xx/bcm63xx_dev_flash.h   |   12 +
+ .../include/asm/mach-bcm63xx/bcm63xx_dev_spi.h     |   89 +++
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h  |    2 +
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h    |    8 +
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h  |  286 ++++++++-
+ arch/mips/include/asm/mach-bcm63xx/ioremap.h       |    1 +
+ arch/mips/include/asm/mach-cavium-octeon/irq.h     |   45 +-
+ arch/mips/include/asm/mach-jz4740/jz4740_nand.h    |    4 +
+ arch/mips/include/asm/mach-loongson/loongson.h     |    3 +-
+ arch/mips/include/asm/mach-loongson1/irq.h         |   73 +++
+ arch/mips/include/asm/mach-loongson1/loongson1.h   |   44 ++
+ arch/mips/include/asm/mach-loongson1/platform.h    |   23 +
+ arch/mips/include/asm/mach-loongson1/prom.h        |   24 +
+ arch/mips/include/asm/mach-loongson1/regs-clk.h    |   33 ++
+ arch/mips/include/asm/mach-loongson1/regs-wdt.h    |   22 +
+ arch/mips/include/asm/mach-loongson1/war.h         |   25 +
+ arch/mips/include/asm/mach-tx49xx/mangle-port.h    |    2 +-
+ arch/mips/include/asm/mips-boards/maltaint.h       |   10 +
+ arch/mips/include/asm/mipsmtregs.h                 |   15 +-
+ arch/mips/include/asm/module.h                     |    2 +
+ .../mips/include/asm/netlogic/xlp-hal/cpucontrol.h |    4 +-
+ arch/mips/include/asm/netlogic/xlp-hal/iomap.h     |    5 +-
+ arch/mips/include/asm/netlogic/xlp-hal/pcibus.h    |   76 +++
+ arch/mips/include/asm/netlogic/xlp-hal/pic.h       |    4 +
+ arch/mips/include/asm/netlogic/xlp-hal/usb.h       |   64 ++
+ arch/mips/include/asm/netlogic/xlp-hal/xlp.h       |   17 +-
+ arch/mips/include/asm/netlogic/xlr/bridge.h        |  104 ++++
+ arch/mips/include/asm/netlogic/xlr/flash.h         |   55 ++
+ arch/mips/include/asm/netlogic/xlr/gpio.h          |   59 +-
+ arch/mips/include/asm/octeon/cvmx-helper-fpa.h     |   64 --
+ arch/mips/include/asm/octeon/cvmx-helper.h         |    2 -
+ arch/mips/include/asm/smtc.h                       |    6 +
+ arch/mips/include/asm/switch_to.h                  |    6 +-
+ arch/mips/include/asm/thread_info.h                |    4 +-
+ arch/mips/include/asm/uaccess.h                    |    6 +-
+ arch/mips/include/asm/uasm.h                       |  100 ++--
+ arch/mips/jz4740/board-qi_lb60.c                   |    1 +
+ arch/mips/jz4740/platform.c                        |   20 +-
+ arch/mips/jz4740/reset.c                           |   49 +-
+ arch/mips/kernel/cpu-probe.c                       |  310 +++++-----
+ arch/mips/kernel/mips_ksyms.c                      |    8 +-
+ arch/mips/kernel/octeon_switch.S                   |    2 +-
+ arch/mips/kernel/perf_event_mipsxx.c               |   10 +-
+ arch/mips/kernel/r2300_switch.S                    |   15 +-
+ arch/mips/kernel/r4k_switch.S                      |   12 +-
+ arch/mips/kernel/smp-bmips.c                       |   15 +-
+ arch/mips/kernel/smp.c                             |   16 +-
+ arch/mips/kernel/smtc.c                            |   87 ++-
+ arch/mips/kernel/sync-r4k.c                        |    5 -
+ arch/mips/kernel/traps.c                           |    8 +-
+ arch/mips/kernel/vmlinux.lds.S                     |    3 +-
+ arch/mips/lib/Makefile                             |    2 +-
+ arch/mips/lib/memcpy-inatomic.S                    |  451 --------------
+ arch/mips/lib/memcpy.S                             |   11 +
+ arch/mips/loongson1/Kconfig                        |   21 +
+ arch/mips/loongson1/Makefile                       |   11 +
+ arch/mips/loongson1/Platform                       |    7 +
+ arch/mips/loongson1/common/Makefile                |    5 +
+ arch/mips/loongson1/common/clock.c                 |  165 ++++++
+ arch/mips/loongson1/common/irq.c                   |  147 +++++
+ arch/mips/loongson1/common/platform.c              |  130 ++++
+ arch/mips/loongson1/common/prom.c                  |   87 +++
+ arch/mips/loongson1/common/reset.c                 |   45 ++
+ arch/mips/loongson1/common/setup.c                 |   29 +
+ arch/mips/loongson1/ls1b/Makefile                  |    5 +
+ arch/mips/loongson1/ls1b/board.c                   |   39 ++
+ arch/mips/mm/Makefile                              |    4 +-
+ arch/mips/mm/c-r4k.c                               |    5 +-
+ arch/mips/mm/page-funcs.S                          |   50 ++
+ arch/mips/mm/page.c                                |   67 +--
+ arch/mips/mm/tlbex.c                               |    2 +
+ arch/mips/mm/uasm.c                                |   62 +-
+ arch/mips/mti-malta/malta-pci.c                    |    7 +-
+ arch/mips/mti-malta/malta-setup.c                  |    2 +-
+ arch/mips/netlogic/common/smpboot.S                |  147 +++--
+ arch/mips/netlogic/xlp/Makefile                    |    1 +
+ arch/mips/netlogic/xlp/nlm_hal.c                   |   52 ++
+ arch/mips/netlogic/xlp/platform.c                  |    2 +-
+ arch/mips/netlogic/xlp/setup.c                     |   24 +-
+ arch/mips/netlogic/xlp/usb-init.c                  |  124 ++++
+ arch/mips/netlogic/xlr/Makefile                    |    2 +-
+ arch/mips/netlogic/xlr/platform-flash.c            |  220 +++++++
+ arch/mips/netlogic/xlr/platform.c                  |  140 +++++
+ arch/mips/netlogic/xlr/setup.c                     |    2 +-
+ arch/mips/oprofile/common.c                        |    2 +
+ arch/mips/oprofile/op_model_mipsxx.c               |   14 +-
+ arch/mips/pci/Makefile                             |    1 +
+ arch/mips/pci/fixup-cobalt.c                       |    8 +-
+ arch/mips/pci/fixup-fuloong2e.c                    |   12 +-
+ arch/mips/pci/fixup-lemote2f.c                     |   12 +-
+ arch/mips/pci/fixup-malta.c                        |   18 +-
+ arch/mips/pci/fixup-mpc30x.c                       |    4 +-
+ arch/mips/pci/fixup-rc32434.c                      |    2 +-
+ arch/mips/pci/fixup-sb1250.c                       |    6 +-
+ arch/mips/pci/ops-bcm63xx.c                        |   63 +-
+ arch/mips/pci/ops-tx4927.c                         |    2 +-
+ arch/mips/pci/pci-bcm63xx.c                        |  133 ++++-
+ arch/mips/pci/pci-bcm63xx.h                        |    5 +
+ arch/mips/pci/pci-ip27.c                           |    2 +-
+ arch/mips/pci/pci-xlp.c                            |  247 ++++++++
+ arch/mips/pci/pci-xlr.c                            |   65 +-
+ arch/mips/pmc-sierra/yosemite/smp.c                |    2 +-
+ arch/mips/pnx833x/stb22x/board.c                   |    4 +-
+ arch/mips/powertv/asic/asic-calliope.c             |    2 +-
+ arch/mips/powertv/asic/asic-cronus.c               |    2 +-
+ arch/mips/powertv/asic/asic-gaia.c                 |    2 +-
+ arch/mips/powertv/asic/asic-zeus.c                 |    2 +-
+ arch/mips/txx9/generic/pci.c                       |    8 +-
+ arch/mips/txx9/generic/setup.c                     |   12 +-
+ arch/mips/txx9/generic/setup_tx4939.c              |    2 +-
+ arch/mips/txx9/rbtx4939/setup.c                    |   11 +-
+ drivers/char/hw_random/Kconfig                     |   14 +
+ drivers/char/hw_random/Makefile                    |    1 +
+ drivers/char/hw_random/bcm63xx-rng.c               |  175 ++++++
+ drivers/mtd/nand/jz4740_nand.c                     |  228 +++++--
+ drivers/spi/Kconfig                                |    9 +
+ drivers/spi/Makefile                               |    1 +
+ drivers/spi/spi-falcon.c                           |  469 +++++++++++++++
+ include/linux/libfdt.h                             |    8 +
+ include/linux/libfdt_env.h                         |   13 +
+ lib/Kconfig                                        |    6 +
+ lib/Makefile                                       |    5 +
+ lib/fdt.c                                          |    2 +
+ lib/fdt_ro.c                                       |    2 +
+ lib/fdt_rw.c                                       |    2 +
+ lib/fdt_strerror.c                                 |    2 +
+ lib/fdt_sw.c                                       |    2 +
+ lib/fdt_wip.c                                      |    2 +
+ 188 files changed, 7653 insertions(+), 1819 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/ata/cavium-compact-flash.txt
+ create mode 100644 Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt
+ create mode 100644 Documentation/devicetree/bindings/i2c/cavium-i2c.txt
+ create mode 100644 Documentation/devicetree/bindings/mips/cavium/bootbus.txt
+ create mode 100644 Documentation/devicetree/bindings/mips/cavium/ciu.txt
+ create mode 100644 Documentation/devicetree/bindings/mips/cavium/ciu2.txt
+ create mode 100644 Documentation/devicetree/bindings/mips/cavium/dma-engine.txt
+ create mode 100644 Documentation/devicetree/bindings/mips/cavium/uctl.txt
+ create mode 100644 Documentation/devicetree/bindings/net/cavium-mdio.txt
+ create mode 100644 Documentation/devicetree/bindings/net/cavium-mix.txt
+ create mode 100644 Documentation/devicetree/bindings/net/cavium-pip.txt
+ create mode 100644 Documentation/devicetree/bindings/serial/cavium-uart.txt
+ delete mode 100644 arch/mips/alchemy/devboards/prom.c
+ create mode 100644 arch/mips/bcm63xx/dev-flash.c
+ create mode 100644 arch/mips/bcm63xx/dev-rng.c
+ create mode 100644 arch/mips/bcm63xx/dev-spi.c
+ create mode 100644 arch/mips/cavium-octeon/.gitignore
+ delete mode 100644 arch/mips/cavium-octeon/executive/cvmx-fpa.c
+ delete mode 100644 arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c
+ create mode 100644 arch/mips/cavium-octeon/octeon_3xxx.dts
+ create mode 100644 arch/mips/cavium-octeon/octeon_68xx.dts
+ create mode 100644 arch/mips/configs/ls1b_defconfig
+ create mode 100644 arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h
+ create mode 100644 arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
+ create mode 100644 arch/mips/include/asm/mach-loongson1/irq.h
+ create mode 100644 arch/mips/include/asm/mach-loongson1/loongson1.h
+ create mode 100644 arch/mips/include/asm/mach-loongson1/platform.h
+ create mode 100644 arch/mips/include/asm/mach-loongson1/prom.h
+ create mode 100644 arch/mips/include/asm/mach-loongson1/regs-clk.h
+ create mode 100644 arch/mips/include/asm/mach-loongson1/regs-wdt.h
+ create mode 100644 arch/mips/include/asm/mach-loongson1/war.h
+ create mode 100644 arch/mips/include/asm/netlogic/xlp-hal/pcibus.h
+ create mode 100644 arch/mips/include/asm/netlogic/xlp-hal/usb.h
+ create mode 100644 arch/mips/include/asm/netlogic/xlr/bridge.h
+ create mode 100644 arch/mips/include/asm/netlogic/xlr/flash.h
+ delete mode 100644 arch/mips/include/asm/octeon/cvmx-helper-fpa.h
+ delete mode 100644 arch/mips/lib/memcpy-inatomic.S
+ create mode 100644 arch/mips/loongson1/Kconfig
+ create mode 100644 arch/mips/loongson1/Makefile
+ create mode 100644 arch/mips/loongson1/Platform
+ create mode 100644 arch/mips/loongson1/common/Makefile
+ create mode 100644 arch/mips/loongson1/common/clock.c
+ create mode 100644 arch/mips/loongson1/common/irq.c
+ create mode 100644 arch/mips/loongson1/common/platform.c
+ create mode 100644 arch/mips/loongson1/common/prom.c
+ create mode 100644 arch/mips/loongson1/common/reset.c
+ create mode 100644 arch/mips/loongson1/common/setup.c
+ create mode 100644 arch/mips/loongson1/ls1b/Makefile
+ create mode 100644 arch/mips/loongson1/ls1b/board.c
+ create mode 100644 arch/mips/mm/page-funcs.S
+ create mode 100644 arch/mips/netlogic/xlp/usb-init.c
+ create mode 100644 arch/mips/netlogic/xlr/platform-flash.c
+ create mode 100644 arch/mips/pci/pci-xlp.c
+ create mode 100644 drivers/char/hw_random/bcm63xx-rng.c
+ create mode 100644 drivers/spi/spi-falcon.c
+ create mode 100644 include/linux/libfdt.h
+ create mode 100644 include/linux/libfdt_env.h
+ create mode 100644 lib/fdt.c
+ create mode 100644 lib/fdt_ro.c
+ create mode 100644 lib/fdt_rw.c
+ create mode 100644 lib/fdt_strerror.c
+ create mode 100644 lib/fdt_sw.c
+ create mode 100644 lib/fdt_wip.c
+Merging openrisc/for-upstream (207e715 openrisc: use scratch regs in atomic syscall)
+$ git merge openrisc/for-upstream
+Already up-to-date.
+Merging parisc/for-next (4c01acc [PARISC] fix code to find libgcc)
+$ git merge parisc/for-next
+Already up-to-date.
+Merging powerpc/next (2074b1d powerpc: Fix irq distribution)
+$ git merge powerpc/next
+Already up-to-date.
+Merging 4xx/next (2074b1d powerpc: Fix irq distribution)
+$ git merge 4xx/next
+Already up-to-date.
+Merging mpc5xxx/next (f8d5842 powerpc: Option FB_FSL_DIU is not really optional for mpc512x)
+$ git merge mpc5xxx/next
+Merge made by the 'recursive' strategy.
+ arch/powerpc/platforms/512x/Kconfig          |    1 +
+ arch/powerpc/platforms/512x/clock.c          |    6 ++++--
+ arch/powerpc/platforms/512x/mpc512x_shared.c |    6 ------
+ 3 files changed, 5 insertions(+), 8 deletions(-)
+Merging galak/next (fa1b42b powerpc/qe: Update the SNUM table for MPC8569 Rev2.0)
+$ git merge galak/next
+Already up-to-date.
+Merging s390/features (fbe7656 s390/smp: make absolute lowcore / cpu restart parameter accesses more robust)
+$ git merge s390/features
+Merge made by the 'recursive' strategy.
+ arch/s390/include/asm/ccwgroup.h     |    2 -
+ arch/s390/include/asm/lowcore.h      |    7 +--
+ arch/s390/include/asm/processor.h    |   10 ++++
+ arch/s390/include/asm/sigp.h         |   31 +++++++++++
+ arch/s390/include/asm/uaccess.h      |    2 -
+ arch/s390/kernel/asm-offsets.c       |    2 +
+ arch/s390/kernel/base.S              |    3 +-
+ arch/s390/kernel/entry.S             |    9 ++-
+ arch/s390/kernel/entry64.S           |   10 ++--
+ arch/s390/kernel/head_kdump.S        |    6 +-
+ arch/s390/kernel/ipl.c               |   15 ++---
+ arch/s390/kernel/os_info.c           |    2 +-
+ arch/s390/kernel/reipl.S             |    3 +-
+ arch/s390/kernel/reipl64.S           |    3 +-
+ arch/s390/kernel/relocate_kernel.S   |    3 +-
+ arch/s390/kernel/relocate_kernel64.S |    5 +-
+ arch/s390/kernel/setup.c             |   13 ++---
+ arch/s390/kernel/smp.c               |  101 +++++++++++++---------------------
+ arch/s390/kernel/swsusp_asm64.S      |   13 +++--
+ arch/s390/kvm/sigp.c                 |   46 +++-------------
+ drivers/s390/char/vmlogrdr.c         |   44 +++++++--------
+ drivers/s390/cio/chp.c               |   12 ++--
+ 22 files changed, 164 insertions(+), 178 deletions(-)
+ create mode 100644 arch/s390/include/asm/sigp.h
+Merging sh/sh-latest (7b98cf0 Merge branch 'common/pfc' into sh-latest)
+$ git merge sh/sh-latest
+Removing drivers/sh/intc/dynamic.c
+Removing arch/sh/lib64/dbg.c
+Merge made by the 'recursive' strategy.
+ arch/sh/Kconfig                       |    1 +
+ arch/sh/boards/Kconfig                |    5 +
+ arch/sh/boards/mach-dreamcast/irq.c   |   32 +-
+ arch/sh/boards/mach-se/7343/irq.c     |  129 +++++---
+ arch/sh/boards/mach-se/7343/setup.c   |   10 +-
+ arch/sh/boards/mach-se/7722/irq.c     |  131 +++++---
+ arch/sh/boards/mach-se/7722/setup.c   |    6 +-
+ arch/sh/boards/mach-se/7724/irq.c     |   36 +-
+ arch/sh/boards/mach-x3proto/gpio.c    |   57 ++--
+ arch/sh/cchips/hd6446x/hd64461.c      |   33 +-
+ arch/sh/include/asm/bug.h             |    4 +
+ arch/sh/include/asm/kdebug.h          |    2 +
+ arch/sh/include/mach-se/mach/se7343.h |    7 +-
+ arch/sh/include/mach-se/mach/se7722.h |   10 +-
+ arch/sh/kernel/cpu/sh5/unwind.c       |   63 ++--
+ arch/sh/kernel/dumpstack.c            |   58 ++++
+ arch/sh/kernel/irq.c                  |   10 -
+ arch/sh/kernel/traps.c                |   71 ++++
+ arch/sh/kernel/traps_32.c             |  121 -------
+ arch/sh/kernel/traps_64.c             |  589 +++++++++++++--------------------
+ arch/sh/lib64/Makefile                |    2 +-
+ arch/sh/lib64/dbg.c                   |  248 --------------
+ arch/sh/mm/tlb-sh5.c                  |    2 +-
+ drivers/sh/Kconfig                    |   15 +
+ drivers/sh/Makefile                   |    3 +-
+ drivers/sh/clk/cpg.c                  |  333 ++++++++-----------
+ drivers/sh/intc/Makefile              |    2 +-
+ drivers/sh/intc/dynamic.c             |   57 ----
+ drivers/sh/intc/virq.c                |    4 +-
+ drivers/sh/pfc-gpio.c                 |  309 +++++++++++++++++
+ drivers/sh/pfc.c                      |  379 ++++++---------------
+ include/linux/sh_clk.h                |   21 +-
+ include/linux/sh_pfc.h                |   64 +++-
+ 33 files changed, 1304 insertions(+), 1510 deletions(-)
+ delete mode 100644 arch/sh/lib64/dbg.c
+ delete mode 100644 drivers/sh/intc/dynamic.c
+ create mode 100644 drivers/sh/pfc-gpio.c
+Merging sparc-next/master (31a6710 Fix blocking allocations called very early during bootup)
+$ git merge sparc-next/master
+Already up-to-date.
+Merging tile/master (7a9349b bounce: allow use of bounce pool via config option)
+$ git merge tile/master
+Auto-merging drivers/usb/host/ehci-hcd.c
+Auto-merging drivers/pci/quirks.c
+Removing arch/tile/include/asm/memprof.h
+Merge made by the 'recursive' strategy.
+ arch/tile/Kconfig                            |   42 +
+ arch/tile/Makefile                           |    2 +
+ arch/tile/gxio/Kconfig                       |   28 +
+ arch/tile/gxio/Makefile                      |    9 +
+ arch/tile/gxio/dma_queue.c                   |  176 +++
+ arch/tile/gxio/iorpc_globals.c               |   89 ++
+ arch/tile/gxio/iorpc_mpipe.c                 |  529 ++++++++
+ arch/tile/gxio/iorpc_mpipe_info.c            |   85 ++
+ arch/tile/gxio/iorpc_trio.c                  |  327 +++++
+ arch/tile/gxio/iorpc_usb_host.c              |   99 ++
+ arch/tile/gxio/kiorpc.c                      |   61 +
+ arch/tile/gxio/mpipe.c                       |  545 ++++++++
+ arch/tile/gxio/trio.c                        |   49 +
+ arch/tile/gxio/usb_host.c                    |   91 ++
+ arch/tile/include/arch/mpipe.h               |  359 ++++++
+ arch/tile/include/arch/mpipe_constants.h     |   42 +
+ arch/tile/include/arch/mpipe_def.h           |   39 +
+ arch/tile/include/arch/mpipe_shm.h           |  509 ++++++++
+ arch/tile/include/arch/mpipe_shm_def.h       |   23 +
+ arch/tile/include/arch/trio.h                |   72 ++
+ arch/tile/include/arch/trio_constants.h      |   36 +
+ arch/tile/include/arch/trio_def.h            |   41 +
+ arch/tile/include/arch/trio_pcie_intfc.h     |  229 ++++
+ arch/tile/include/arch/trio_pcie_intfc_def.h |   32 +
+ arch/tile/include/arch/trio_pcie_rc.h        |  156 +++
+ arch/tile/include/arch/trio_pcie_rc_def.h    |   24 +
+ arch/tile/include/arch/trio_shm.h            |  125 ++
+ arch/tile/include/arch/trio_shm_def.h        |   19 +
+ arch/tile/include/arch/usb_host.h            |   26 +
+ arch/tile/include/arch/usb_host_def.h        |   19 +
+ arch/tile/include/asm/Kbuild                 |    1 -
+ arch/tile/include/asm/cache.h                |   12 +-
+ arch/tile/include/asm/checksum.h             |   18 +
+ arch/tile/include/asm/device.h               |   33 +
+ arch/tile/include/asm/dma-mapping.h          |  146 ++-
+ arch/tile/include/asm/fixmap.h               |   14 +-
+ arch/tile/include/asm/homecache.h            |   19 +-
+ arch/tile/include/asm/io.h                   |  144 ++-
+ arch/tile/include/asm/memprof.h              |   33 -
+ arch/tile/include/asm/page.h                 |    7 +-
+ arch/tile/include/asm/pci.h                  |  162 ++-
+ arch/tile/include/gxio/common.h              |   40 +
+ arch/tile/include/gxio/dma_queue.h           |  161 +++
+ arch/tile/include/gxio/iorpc_globals.h       |   38 +
+ arch/tile/include/gxio/iorpc_mpipe.h         |  136 ++
+ arch/tile/include/gxio/iorpc_mpipe_info.h    |   46 +
+ arch/tile/include/gxio/iorpc_trio.h          |   97 ++
+ arch/tile/include/gxio/iorpc_usb_host.h      |   46 +
+ arch/tile/include/gxio/kiorpc.h              |   29 +
+ arch/tile/include/gxio/mpipe.h               | 1736 ++++++++++++++++++++++++++
+ arch/tile/include/gxio/trio.h                |  298 +++++
+ arch/tile/include/gxio/usb_host.h            |   87 ++
+ arch/tile/include/hv/drv_mpipe_intf.h        |  602 +++++++++
+ arch/tile/include/hv/drv_trio_intf.h         |  195 +++
+ arch/tile/include/hv/drv_usb_host_intf.h     |   39 +
+ arch/tile/include/hv/iorpc.h                 |  714 +++++++++++
+ arch/tile/kernel/Makefile                    |    5 +
+ arch/tile/kernel/pci-dma.c                   |  536 ++++++--
+ arch/tile/kernel/pci_gx.c                    | 1547 +++++++++++++++++++++++
+ arch/tile/kernel/setup.c                     |   41 +-
+ arch/tile/kernel/usb.c                       |   69 +
+ arch/tile/lib/checksum.c                     |   15 +-
+ arch/tile/mm/homecache.c                     |  156 ++-
+ arch/tile/mm/init.c                          |   70 +-
+ arch/tile/mm/pgtable.c                       |    7 -
+ drivers/pci/quirks.c                         |    6 +-
+ drivers/usb/host/ehci-hcd.c                  |    5 +
+ drivers/usb/host/ehci-tilegx.c               |  214 ++++
+ drivers/usb/host/ohci-hcd.c                  |    5 +
+ drivers/usb/host/ohci-tilegx.c               |  203 +++
+ include/linux/usb/tilegx.h                   |   34 +
+ mm/bounce.c                                  |    8 +-
+ 72 files changed, 11254 insertions(+), 403 deletions(-)
+ create mode 100644 arch/tile/gxio/Kconfig
+ create mode 100644 arch/tile/gxio/Makefile
+ create mode 100644 arch/tile/gxio/dma_queue.c
+ create mode 100644 arch/tile/gxio/iorpc_globals.c
+ create mode 100644 arch/tile/gxio/iorpc_mpipe.c
+ create mode 100644 arch/tile/gxio/iorpc_mpipe_info.c
+ create mode 100644 arch/tile/gxio/iorpc_trio.c
+ create mode 100644 arch/tile/gxio/iorpc_usb_host.c
+ create mode 100644 arch/tile/gxio/kiorpc.c
+ create mode 100644 arch/tile/gxio/mpipe.c
+ create mode 100644 arch/tile/gxio/trio.c
+ create mode 100644 arch/tile/gxio/usb_host.c
+ create mode 100644 arch/tile/include/arch/mpipe.h
+ create mode 100644 arch/tile/include/arch/mpipe_constants.h
+ create mode 100644 arch/tile/include/arch/mpipe_def.h
+ create mode 100644 arch/tile/include/arch/mpipe_shm.h
+ create mode 100644 arch/tile/include/arch/mpipe_shm_def.h
+ create mode 100644 arch/tile/include/arch/trio.h
+ create mode 100644 arch/tile/include/arch/trio_constants.h
+ create mode 100644 arch/tile/include/arch/trio_def.h
+ create mode 100644 arch/tile/include/arch/trio_pcie_intfc.h
+ create mode 100644 arch/tile/include/arch/trio_pcie_intfc_def.h
+ create mode 100644 arch/tile/include/arch/trio_pcie_rc.h
+ create mode 100644 arch/tile/include/arch/trio_pcie_rc_def.h
+ create mode 100644 arch/tile/include/arch/trio_shm.h
+ create mode 100644 arch/tile/include/arch/trio_shm_def.h
+ create mode 100644 arch/tile/include/arch/usb_host.h
+ create mode 100644 arch/tile/include/arch/usb_host_def.h
+ create mode 100644 arch/tile/include/asm/device.h
+ delete mode 100644 arch/tile/include/asm/memprof.h
+ create mode 100644 arch/tile/include/gxio/common.h
+ create mode 100644 arch/tile/include/gxio/dma_queue.h
+ create mode 100644 arch/tile/include/gxio/iorpc_globals.h
+ create mode 100644 arch/tile/include/gxio/iorpc_mpipe.h
+ create mode 100644 arch/tile/include/gxio/iorpc_mpipe_info.h
+ create mode 100644 arch/tile/include/gxio/iorpc_trio.h
+ create mode 100644 arch/tile/include/gxio/iorpc_usb_host.h
+ create mode 100644 arch/tile/include/gxio/kiorpc.h
+ create mode 100644 arch/tile/include/gxio/mpipe.h
+ create mode 100644 arch/tile/include/gxio/trio.h
+ create mode 100644 arch/tile/include/gxio/usb_host.h
+ create mode 100644 arch/tile/include/hv/drv_mpipe_intf.h
+ create mode 100644 arch/tile/include/hv/drv_trio_intf.h
+ create mode 100644 arch/tile/include/hv/drv_usb_host_intf.h
+ create mode 100644 arch/tile/include/hv/iorpc.h
+ create mode 100644 arch/tile/kernel/pci_gx.c
+ create mode 100644 arch/tile/kernel/usb.c
+ create mode 100644 drivers/usb/host/ehci-tilegx.c
+ create mode 100644 drivers/usb/host/ohci-tilegx.c
+ create mode 100644 include/linux/usb/tilegx.h
+Merging unicore32/unicore32 (e4baa56 UniCore32-bugfix: Remove definitions in asm/bug.h to solve difference between native and cross compiler)
+$ git merge unicore32/unicore32
+Merge made by the 'recursive' strategy.
+ arch/unicore32/Kconfig               |    3 +++
+ arch/unicore32/include/asm/bug.h     |    5 -----
+ arch/unicore32/include/asm/cmpxchg.h |    2 +-
+ arch/unicore32/kernel/setup.h        |    6 ++++++
+ arch/unicore32/mm/fault.c            |   37 +++++++++++++++++++++++++---------
+ 5 files changed, 37 insertions(+), 16 deletions(-)
+Merging ceph/master (26ce171 libceph: fix NULL dereference in reset_connection())
+$ git merge ceph/master
+Resolved 'net/ceph/osd_client.c' using previous resolution.
+Auto-merging net/ceph/osd_client.c
+CONFLICT (content): Merge conflict in net/ceph/osd_client.c
+Auto-merging net/ceph/mon_client.c
+Auto-merging net/ceph/messenger.c
+Auto-merging net/ceph/ceph_common.c
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 2657911] Merge remote-tracking branch 'ceph/master'
+$ git diff -M --stat --summary HEAD^..
+ drivers/block/rbd.c             |    4 +-
+ fs/ceph/mds_client.c            |    7 +-
+ include/linux/ceph/libceph.h    |    2 +-
+ include/linux/ceph/messenger.h  |   55 +++---
+ include/linux/ceph/mon_client.h |    2 +-
+ net/ceph/ceph_common.c          |   18 +-
+ net/ceph/messenger.c            |  389 +++++++++++++++++++++++++--------------
+ net/ceph/mon_client.c           |   73 ++++----
+ net/ceph/osd_client.c           |   29 ++-
+ net/ceph/osdmap.c               |   20 +-
+ 10 files changed, 362 insertions(+), 237 deletions(-)
+Merging cifs/for-next (4d0b178 CIFS: Add SMB2 credits support)
+$ git merge cifs/for-next
+Merge made by the 'recursive' strategy.
+ fs/cifs/Makefile        |    2 +-
+ fs/cifs/cifs_dfs_ref.c  |    7 +-
+ fs/cifs/cifsacl.c       |   21 +-
+ fs/cifs/cifsfs.c        |    6 +-
+ fs/cifs/cifsglob.h      |   48 +-
+ fs/cifs/cifsproto.h     |  201 ++--
+ fs/cifs/cifssmb.c       |  175 ++--
+ fs/cifs/connect.c       |  348 ++-----
+ fs/cifs/dir.c           |   24 +-
+ fs/cifs/file.c          |  133 +--
+ fs/cifs/inode.c         |   87 +-
+ fs/cifs/ioctl.c         |    6 +-
+ fs/cifs/link.c          |   24 +-
+ fs/cifs/misc.c          |    4 +-
+ fs/cifs/nterr.c         |    6 +-
+ fs/cifs/nterr.h         |   22 +-
+ fs/cifs/readdir.c       |   15 +-
+ fs/cifs/sess.c          |    4 +-
+ fs/cifs/smb1ops.c       |  210 +++-
+ fs/cifs/smb2maperror.c  | 2478 +++++++++++++++++++++++++++++++++++++++++++++++
+ fs/cifs/smb2ops.c       |   94 ++
+ fs/cifs/smb2pdu.h       |  115 +++
+ fs/cifs/smb2proto.h     |   42 +
+ fs/cifs/smb2status.h    | 1782 ++++++++++++++++++++++++++++++++++
+ fs/cifs/smb2transport.c |  151 +++
+ fs/cifs/transport.c     |   83 +-
+ fs/cifs/xattr.c         |   24 +-
+ 27 files changed, 5455 insertions(+), 657 deletions(-)
+ create mode 100644 fs/cifs/smb2maperror.c
+ create mode 100644 fs/cifs/smb2pdu.h
+ create mode 100644 fs/cifs/smb2proto.h
+ create mode 100644 fs/cifs/smb2status.h
+ create mode 100644 fs/cifs/smb2transport.c
+Merging configfs/linux-next (b930c26 Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs)
+$ git merge configfs/linux-next
+Already up-to-date.
+Merging ecryptfs/next (5a52c0d eCryptfs: Initialize empty lower files when opening them)
+$ git merge ecryptfs/next
+Merge made by the 'recursive' strategy.
+ fs/ecryptfs/ecryptfs_kernel.h |   24 +++-----
+ fs/ecryptfs/file.c            |   71 +++++++++++++--------
+ fs/ecryptfs/inode.c           |   59 ++++++++++--------
+ fs/ecryptfs/kthread.c         |    2 +-
+ fs/ecryptfs/main.c            |   10 ++-
+ fs/ecryptfs/messaging.c       |  136 +++++------------------------------------
+ fs/ecryptfs/miscdev.c         |  116 ++++++++++++-----------------------
+ 7 files changed, 152 insertions(+), 266 deletions(-)
+Merging ext3/for_next (7d5a4b0 quota: fix checkpatch.pl warning by replacing <asm/uaccess.h> with <linux/uaccess.h>)
+$ git merge ext3/for_next
+Merge made by the 'recursive' strategy.
+ fs/quota/dquot.c |    2 +-
+ fs/quota/quota.c |    2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+Merging ext4/dev (b22b1f1 ext4: don't set i_flags in EXT4_IOC_SETFLAGS)
+$ git merge ext4/dev
+Already up-to-date.
+Merging fuse/for-next (203627b fuse: fix blksize calculation)
+$ git merge fuse/for-next
+Already up-to-date.
+Merging gfs2/master (666d1d8 GFS2: Combine functions get_local_rgrp and gfs2_inplace_reserve)
+$ git merge gfs2/master
+Merge made by the 'recursive' strategy.
+ fs/gfs2/aops.c              |   18 +--
+ fs/gfs2/bmap.c              |   18 +--
+ fs/gfs2/dir.c               |    9 +-
+ fs/gfs2/file.c              |   49 ++++---
+ fs/gfs2/glock.c             |   39 ++++--
+ fs/gfs2/incore.h            |   15 +--
+ fs/gfs2/inode.c             |   67 ++++------
+ fs/gfs2/lops.c              |    9 +-
+ fs/gfs2/main.c              |    1 -
+ fs/gfs2/ops_fstype.c        |   36 +++--
+ fs/gfs2/quota.c             |   72 +++++-----
+ fs/gfs2/rgrp.c              |  312 ++++++++++++++++++++++++++++---------------
+ fs/gfs2/rgrp.h              |   18 +--
+ fs/gfs2/super.c             |   23 ++--
+ fs/gfs2/sys.c               |   21 ++-
+ fs/gfs2/trans.h             |    2 +-
+ fs/gfs2/util.h              |   18 +--
+ fs/gfs2/xattr.c             |   24 +---
+ fs/seq_file.c               |   18 ++-
+ include/linux/gfs2_ondisk.h |   14 +-
+ include/linux/seq_file.h    |    1 +
+ 21 files changed, 457 insertions(+), 327 deletions(-)
+Merging logfs/master (cd8bfa9 logfs: initialize the number of iovecs in bio)
+$ git merge logfs/master
+Auto-merging fs/logfs/readwrite.c
+Merge made by the 'recursive' strategy.
+ fs/logfs/dev_bdev.c  |    1 +
+ fs/logfs/inode.c     |   16 ++++++++++++++++
+ fs/logfs/readwrite.c |    1 -
+ fs/logfs/segment.c   |    2 +-
+ 4 files changed, 18 insertions(+), 2 deletions(-)
+Merging nfs/linux-next (d4c2898 Define ENONAMESERVICE and ENAMEUNKNOWN to indicate name service errors)
+$ git merge nfs/linux-next
+Merge made by the 'recursive' strategy.
+ arch/alpha/include/asm/errno.h  |    4 ++
+ arch/mips/include/asm/errno.h   |    3 ++
+ arch/parisc/include/asm/errno.h |    3 ++
+ arch/sparc/include/asm/errno.h  |    3 ++
+ fs/Kconfig                      |    8 +--
+ fs/nfs/Kconfig                  |   10 ++--
+ fs/nfs/nfs2xdr.c                |   28 ++---------
+ fs/nfs/nfs3xdr.c                |   43 +++++-----------
+ fs/nfs/nfs4filelayout.c         |    6 +--
+ fs/nfs/nfs4filelayoutdev.c      |    2 +-
+ fs/nfs/nfs4proc.c               |    4 +-
+ fs/nfs/nfs4state.c              |  103 ++++++++++++++++++++++++++-------------
+ fs/nfs/nfs4xdr.c                |   82 ++++++++++++-------------------
+ fs/nfs/write.c                  |    4 +-
+ fs/nfsd/Kconfig                 |    1 -
+ include/asm-generic/errno.h     |    3 ++
+ include/linux/nfs_page.h        |    2 +-
+ include/linux/nfs_xdr.h         |    6 ++-
+ include/linux/sunrpc/xdr.h      |    6 +--
+ net/sunrpc/xdr.c                |   91 ++++++++++++++++++----------------
+ 20 files changed, 204 insertions(+), 208 deletions(-)
+Merging nfsd/nfsd-next (7df302f NFSD: TEST_STATEID should not return NFS4ERR_STALE_STATEID)
+$ git merge nfsd/nfsd-next
+Merge made by the 'recursive' strategy.
+ fs/nfsd/nfs4state.c |   27 +++++++++++++++++++++------
+ fs/nfsd/state.h     |    1 -
+ 2 files changed, 21 insertions(+), 7 deletions(-)
+Merging ocfs2/linux-next (9392557 ocfs2: avoid unaligned access to dqc_bitmap)
+$ git merge ocfs2/linux-next
+Already up-to-date.
+Merging omfs/for-next (976d167 Linux 3.1-rc9)
+$ git merge omfs/for-next
+Already up-to-date.
+Merging squashfs/master (4b0180a Squashfs: add mount time sanity check for block_size and block_log match)
+$ git merge squashfs/master
+Already up-to-date.
+Merging v9fs/for-next (5fcb08b 9p: BUG before corrupting memory)
+$ git merge v9fs/for-next
+Already up-to-date.
+Merging ubifs/linux-next (1cfb727 UBIFS: fix assertion)
+$ git merge ubifs/linux-next
+Merge made by the 'recursive' strategy.
+ fs/ubifs/find.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+Merging xfs/for-next (9a8d2fd xfs: remove xlog_t typedef)
+$ git merge xfs/for-next
+Resolved 'fs/xfs/xfs_log.c' using previous resolution.
+Resolved 'fs/xfs/xfs_log_priv.h' using previous resolution.
+Auto-merging fs/xfs/xfs_mount.h
+Auto-merging fs/xfs/xfs_log_recover.c
+Auto-merging fs/xfs/xfs_log_priv.h
+CONFLICT (content): Merge conflict in fs/xfs/xfs_log_priv.h
+Auto-merging fs/xfs/xfs_log.c
+CONFLICT (content): Merge conflict in fs/xfs/xfs_log.c
+Auto-merging fs/xfs/xfs_aops.c
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master e565c22] Merge remote-tracking branch 'xfs/for-next'
+$ git diff -M --stat --summary HEAD^..
+ fs/xfs/xfs_aops.c        |   12 +--
+ fs/xfs/xfs_bmap.c        |    2 +-
+ fs/xfs/xfs_dinode.h      |    2 +-
+ fs/xfs/xfs_file.c        |   19 +---
+ fs/xfs/xfs_inode.c       |    2 +-
+ fs/xfs/xfs_iomap.c       |    6 +-
+ fs/xfs/xfs_log.c         |  223 ++++++++++++++++++++++++++++------------------
+ fs/xfs/xfs_log_priv.h    |   18 ++--
+ fs/xfs/xfs_log_recover.c |  140 +++++++++++++++--------------
+ fs/xfs/xfs_mount.c       |    2 -
+ fs/xfs/xfs_mount.h       |    3 -
+ fs/xfs/xfs_qm.c          |    2 +-
+ fs/xfs/xfs_vnodeops.c    |   10 +--
+ 13 files changed, 246 insertions(+), 195 deletions(-)
+Merging vfs/for-next (01aa470 do_dentry_open(): close the race with mark_files_ro() in failure exit)
+$ git merge vfs/for-next
+Resolved 'fs/cifs/dir.c' using previous resolution.
+Auto-merging kernel/cgroup.c
+Auto-merging include/linux/nfs_xdr.h
+Auto-merging fs/nfs/proc.c
+Auto-merging fs/nfs/nfs4proc.c
+Auto-merging fs/gfs2/inode.c
+Auto-merging fs/ecryptfs/inode.c
+Auto-merging fs/cifs/inode.c
+Auto-merging fs/cifs/dir.c
+CONFLICT (content): Merge conflict in fs/cifs/dir.c
+Auto-merging fs/cifs/cifsfs.c
+Auto-merging fs/btrfs/inode.c
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master d903bc4] Merge remote-tracking branch 'vfs/for-next'
+$ git diff -M --stat --summary HEAD^..
+ Documentation/filesystems/Locking |   11 +-
+ Documentation/filesystems/porting |   21 +-
+ Documentation/filesystems/vfs.txt |   23 +-
+ drivers/base/devtmpfs.c           |   98 +++---
+ fs/9p/v9fs.h                      |    2 +-
+ fs/9p/vfs_dentry.c                |    4 +-
+ fs/9p/vfs_inode.c                 |  170 +++++----
+ fs/9p/vfs_inode_dotl.c            |   59 ++--
+ fs/adfs/dir.c                     |    2 +-
+ fs/adfs/super.c                   |    1 -
+ fs/affs/affs.h                    |   11 +-
+ fs/affs/amigaffs.c                |   22 +-
+ fs/affs/bitmap.c                  |    4 +-
+ fs/affs/namei.c                   |    4 +-
+ fs/affs/super.c                   |   68 ++--
+ fs/afs/dir.c                      |   14 +-
+ fs/afs/mntpt.c                    |    4 +-
+ fs/attr.c                         |    3 +-
+ fs/autofs4/root.c                 |    4 +-
+ fs/bad_inode.c                    |    4 +-
+ fs/befs/linuxvfs.c                |    4 +-
+ fs/bfs/dir.c                      |    4 +-
+ fs/btrfs/inode.c                  |    6 +-
+ fs/cachefiles/namei.c             |    2 +-
+ fs/ceph/dir.c                     |   77 +++--
+ fs/ceph/file.c                    |   26 +-
+ fs/ceph/super.h                   |    6 +-
+ fs/cifs/cifsfs.c                  |    2 +-
+ fs/cifs/cifsfs.h                  |    7 +-
+ fs/cifs/dir.c                     |  448 +++++++++++++-----------
+ fs/cifs/inode.c                   |    5 +-
+ fs/coda/cache.c                   |   10 +-
+ fs/coda/dir.c                     |   14 +-
+ fs/configfs/dir.c                 |    2 +-
+ fs/cramfs/inode.c                 |    2 +-
+ fs/dcache.c                       |   44 +--
+ fs/debugfs/inode.c                |   91 +++--
+ fs/direct-io.c                    |    2 +-
+ fs/ecryptfs/dentry.c              |   20 +-
+ fs/ecryptfs/inode.c               |    7 +-
+ fs/efs/efs.h                      |    2 +-
+ fs/efs/namei.c                    |    3 +-
+ fs/exofs/namei.c                  |    4 +-
+ fs/exportfs/expfs.c               |    3 +-
+ fs/ext2/namei.c                   |    4 +-
+ fs/ext3/namei.c                   |    4 +-
+ fs/ext4/fsync.c                   |   11 +-
+ fs/ext4/namei.c                   |    4 +-
+ fs/fat/namei_msdos.c              |    4 +-
+ fs/fat/namei_vfat.c               |   16 +-
+ fs/file_table.c                   |    9 +-
+ fs/freevxfs/vxfs_lookup.c         |    4 +-
+ fs/fs_struct.c                    |   32 +-
+ fs/fuse/dir.c                     |   99 ++++--
+ fs/gfs2/dentry.c                  |    6 +-
+ fs/gfs2/inode.c                   |    7 +-
+ fs/hfs/dir.c                      |    4 +-
+ fs/hfs/inode.c                    |    2 +-
+ fs/hfs/sysdep.c                   |    4 +-
+ fs/hfsplus/dir.c                  |    4 +-
+ fs/hfsplus/inode.c                |    2 +-
+ fs/hostfs/hostfs_kern.c           |    4 +-
+ fs/hpfs/dir.c                     |    2 +-
+ fs/hpfs/hpfs_fn.h                 |    2 +-
+ fs/hpfs/namei.c                   |    2 +-
+ fs/hppfs/hppfs.c                  |    2 +-
+ fs/hugetlbfs/inode.c              |    2 +-
+ fs/inode.c                        |    2 +-
+ fs/internal.h                     |    5 -
+ fs/isofs/isofs.h                  |    2 +-
+ fs/isofs/namei.c                  |    2 +-
+ fs/jffs2/dir.c                    |    8 +-
+ fs/jfs/namei.c                    |   10 +-
+ fs/libfs.c                        |    2 +-
+ fs/logfs/dir.c                    |    4 +-
+ fs/minix/namei.c                  |    4 +-
+ fs/mount.h                        |   13 +-
+ fs/namei.c                        |  691 +++++++++++++++++++++++++------------
+ fs/namespace.c                    |   59 +---
+ fs/ncpfs/dir.c                    |   14 +-
+ fs/nfs/dir.c                      |  314 +++++++----------
+ fs/nfs/getroot.c                  |    2 +-
+ fs/nfs/nfs3proc.c                 |    2 +-
+ fs/nfs/nfs4proc.c                 |   37 +-
+ fs/nfs/proc.c                     |    2 +-
+ fs/nfsd/vfs.c                     |    4 +-
+ fs/nilfs2/namei.c                 |    4 +-
+ fs/notify/fsnotify.c              |    3 +-
+ fs/ntfs/namei.c                   |    2 +-
+ fs/ocfs2/dcache.c                 |   22 +-
+ fs/ocfs2/dlmfs/dlmfs.c            |    2 +-
+ fs/ocfs2/namei.c                  |    4 +-
+ fs/omfs/dir.c                     |    4 +-
+ fs/open.c                         |  157 +++------
+ fs/openpromfs/inode.c             |    4 +-
+ fs/proc/base.c                    |   51 +--
+ fs/proc/generic.c                 |    2 +-
+ fs/proc/internal.h                |    6 +-
+ fs/proc/namespaces.c              |    4 +-
+ fs/proc/proc_net.c                |    2 +-
+ fs/proc/proc_sysctl.c             |    6 +-
+ fs/proc/root.c                    |    7 +-
+ fs/proc_namespace.c               |    7 +-
+ fs/qnx4/namei.c                   |    2 +-
+ fs/qnx4/qnx4.h                    |    2 +-
+ fs/qnx6/inode.c                   |    1 -
+ fs/qnx6/namei.c                   |    2 +-
+ fs/qnx6/qnx6.h                    |    2 +-
+ fs/ramfs/inode.c                  |    2 +-
+ fs/reiserfs/namei.c               |    4 +-
+ fs/reiserfs/xattr.c               |    4 +-
+ fs/romfs/super.c                  |    2 +-
+ fs/squashfs/namei.c               |    2 +-
+ fs/sysfs/dir.c                    |   31 +-
+ fs/sysfs/mount.c                  |    1 +
+ fs/sysfs/sysfs.h                  |    1 +
+ fs/sysv/namei.c                   |    4 +-
+ fs/ubifs/dir.c                    |    4 +-
+ fs/udf/namei.c                    |    4 +-
+ fs/ufs/namei.c                    |    4 +-
+ fs/xfs/xfs_iops.c                 |    6 +-
+ include/linux/dcache.h            |    4 +-
+ include/linux/fs.h                |   21 +-
+ include/linux/namei.h             |   18 +-
+ include/linux/nfs_xdr.h           |    2 +-
+ ipc/mqueue.c                      |    4 +-
+ kernel/audit_watch.c              |   25 +-
+ kernel/cgroup.c                   |    4 +-
+ mm/shmem.c                        |    2 +-
+ 129 files changed, 1675 insertions(+), 1497 deletions(-)
+Merging pci/next (35e7f73 Merge branch 'topic/huang-d3cold-v7' into next)
+$ git merge pci/next
+Resolved 'drivers/pci/pci.c' using previous resolution.
+Resolved 'drivers/pci/quirks.c' using previous resolution.
+Auto-merging include/linux/pci.h
+Auto-merging drivers/pci/quirks.c
+CONFLICT (content): Merge conflict in drivers/pci/quirks.c
+Auto-merging drivers/pci/pci.c
+CONFLICT (content): Merge conflict in drivers/pci/pci.c
+Auto-merging drivers/net/ethernet/broadcom/tg3.c
+Auto-merging MAINTAINERS
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master e6598ff] Merge remote-tracking branch 'pci/next'
+$ git diff -M --stat --summary HEAD^..
+ MAINTAINERS                                |    2 +-
+ arch/alpha/kernel/pci.c                    |   11 +-
+ arch/arm/kernel/bios32.c                   |    4 +-
+ arch/frv/mb93090-mb00/pci-vdk.c            |    4 +-
+ arch/ia64/pci/pci.c                        |    4 +-
+ arch/microblaze/pci/pci-common.c           |    4 +-
+ arch/mips/pci/pci.c                        |    2 +-
+ arch/powerpc/include/asm/pci-bridge.h      |    1 +
+ arch/powerpc/kernel/pci-common.c           |   17 +-
+ arch/powerpc/kernel/pci_64.c               |    2 +-
+ arch/powerpc/kernel/pci_of_scan.c          |    2 +-
+ arch/powerpc/platforms/85xx/tqm85xx.c      |    2 +-
+ arch/powerpc/platforms/86xx/gef_ppc9a.c    |    2 +-
+ arch/powerpc/platforms/86xx/gef_sbc310.c   |    2 +-
+ arch/powerpc/platforms/86xx/gef_sbc610.c   |    2 +-
+ arch/powerpc/platforms/powernv/pci-ioda.c  |    8 +-
+ arch/powerpc/platforms/pseries/pci_dlpar.c |    2 +-
+ arch/powerpc/sysdev/fsl_pci.c              |    2 +-
+ arch/powerpc/sysdev/mv64x60_pci.c          |    2 +-
+ arch/sh/drivers/pci/fixups-dreamcast.c     |    2 +-
+ arch/sh/drivers/pci/pci.c                  |    2 +-
+ arch/sparc/kernel/pci.c                    |    8 +-
+ arch/sparc/kernel/pci_impl.h               |    1 +
+ arch/sparc/kernel/pcic.c                   |    5 -
+ arch/tile/kernel/pci.c                     |    9 +-
+ arch/x86/include/asm/pci_x86.h             |    7 +
+ arch/x86/kernel/quirks.c                   |    2 +-
+ arch/x86/pci/acpi.c                        |  109 +++++++-
+ arch/x86/pci/amd_bus.c                     |    7 +-
+ arch/x86/pci/bus_numa.c                    |   22 +-
+ arch/x86/pci/bus_numa.h                    |    3 +-
+ arch/x86/pci/mmconfig-shared.c             |  372 +++++++++++++++++---------
+ arch/x86/pci/mmconfig_32.c                 |   30 ++-
+ arch/x86/pci/mmconfig_64.c                 |   52 ++--
+ arch/x86/pci/mrst.c                        |    2 +-
+ arch/xtensa/kernel/pci.c                   |    2 +-
+ drivers/acpi/pci_root.c                    |    2 +
+ drivers/acpi/sleep.c                       |   24 +-
+ drivers/iommu/intel-iommu.c                |    2 +-
+ drivers/misc/cb710/core.c                  |    2 +-
+ drivers/net/ethernet/broadcom/tg3.c        |    4 +-
+ drivers/parisc/dino.c                      |   16 +-
+ drivers/parisc/iosapic.c                   |    2 +-
+ drivers/parisc/lba_pci.c                   |   26 +-
+ drivers/pci/access.c                       |    6 +-
+ drivers/pci/hotplug-pci.c                  |   30 ++-
+ drivers/pci/hotplug/acpiphp_glue.c         |   64 +++--
+ drivers/pci/hotplug/cpci_hotplug_pci.c     |   35 +--
+ drivers/pci/hotplug/cpqphp_pci.c           |    8 +-
+ drivers/pci/hotplug/ibmphp_core.c          |    8 +-
+ drivers/pci/hotplug/pciehp_pci.c           |   28 +-
+ drivers/pci/hotplug/sgi_hotplug.c          |   12 +-
+ drivers/pci/hotplug/shpchp_ctrl.c          |    3 -
+ drivers/pci/hotplug/shpchp_pci.c           |   45 ++--
+ drivers/pci/hotplug/shpchp_sysfs.c         |    6 +-
+ drivers/pci/iov.c                          |    4 +-
+ drivers/pci/pci-acpi.c                     |   36 ++-
+ drivers/pci/pci-driver.c                   |   10 +-
+ drivers/pci/pci-sysfs.c                    |   31 ++-
+ drivers/pci/pci.c                          |  395 ++++++++++++++++++----------
+ drivers/pci/pci.h                          |   10 +-
+ drivers/pci/pcie/aer/aerdrv_acpi.c         |    2 +-
+ drivers/pci/pcie/portdrv_pci.c             |   60 +++++
+ drivers/pci/probe.c                        |  209 ++++++++++++---
+ drivers/pci/quirks.c                       |  116 +++++++-
+ drivers/pci/remove.c                       |    1 +
+ drivers/pci/search.c                       |    2 +
+ drivers/pci/setup-bus.c                    |   26 +-
+ drivers/pcmcia/cardbus.c                   |    2 +-
+ drivers/pcmcia/yenta_socket.c              |   26 +-
+ drivers/pnp/pnpacpi/core.c                 |    4 +-
+ drivers/xen/xen-pciback/conf_space.c       |    6 +-
+ include/acpi/acnames.h                     |    1 +
+ include/acpi/acpi_bus.h                    |    7 +-
+ include/linux/pci-acpi.h                   |    1 +
+ include/linux/pci.h                        |   80 +++++-
+ include/linux/pci_regs.h                   |  119 ++++++++-
+ include/linux/sfi_acpi.h                   |    4 +-
+ kernel/resource.c                          |   13 +-
+ scripts/mod/modpost.c                      |   11 +
+ 80 files changed, 1570 insertions(+), 639 deletions(-)
+Merging hid/for-next (f79185b Merge branch 'uhid' into for-next)
+$ git merge hid/for-next
+Recorded preimage for 'drivers/hid/Kconfig'
+Auto-merging include/linux/Kbuild
+Auto-merging drivers/hid/hid-ids.h
+Auto-merging drivers/hid/hid-core.c
+Auto-merging drivers/hid/Kconfig
+CONFLICT (content): Merge conflict in drivers/hid/Kconfig
+Auto-merging MAINTAINERS
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+Recorded resolution for 'drivers/hid/Kconfig'.
+[master 904c97ed] Merge remote-tracking branch 'hid/for-next'
+$ git diff -M --stat --summary HEAD^..
+ .../ABI/testing/sysfs-driver-hid-lenovo-tpkbd      |   38 ++
+ Documentation/hid/uhid.txt                         |  169 ++++++
+ MAINTAINERS                                        |    7 +
+ drivers/hid/Kconfig                                |   34 ++
+ drivers/hid/Makefile                               |    2 +
+ drivers/hid/hid-core.c                             |    1 +
+ drivers/hid/hid-ids.h                              |    6 +
+ drivers/hid/hid-lenovo-tpkbd.c                     |  564 +++++++++++++++++++
+ drivers/hid/hid-multitouch.c                       |    5 +
+ drivers/hid/hid-wiimote-ext.c                      |    2 +-
+ drivers/hid/uhid.c                                 |  572 ++++++++++++++++++++
+ include/linux/Kbuild                               |    1 +
+ include/linux/uhid.h                               |  104 ++++
+ samples/uhid/Makefile                              |   10 +
+ samples/uhid/uhid-example.c                        |  381 +++++++++++++
+ 15 files changed, 1895 insertions(+), 1 deletion(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-lenovo-tpkbd
+ create mode 100644 Documentation/hid/uhid.txt
+ create mode 100644 drivers/hid/hid-lenovo-tpkbd.c
+ create mode 100644 drivers/hid/uhid.c
+ create mode 100644 include/linux/uhid.h
+ create mode 100644 samples/uhid/Makefile
+ create mode 100644 samples/uhid/uhid-example.c
+Merging quilt/i2c (d170f6c i2c/writing-clients: Mention module_i2c_driver())
+$ git merge quilt/i2c
+Merge made by the 'recursive' strategy.
+ Documentation/i2c/busses/i2c-piix4         |    9 ++
+ Documentation/i2c/writing-clients          |   23 +--
+ drivers/i2c/busses/Kconfig                 |    6 +-
+ drivers/i2c/busses/i2c-ali1535.c           |   13 +-
+ drivers/i2c/busses/i2c-ali1563.c           |   14 +-
+ drivers/i2c/busses/i2c-ali15x3.c           |   13 +-
+ drivers/i2c/busses/i2c-amd756.c            |   13 +-
+ drivers/i2c/busses/i2c-amd8111.c           |   13 +-
+ drivers/i2c/busses/i2c-designware-pcidrv.c |   12 +-
+ drivers/i2c/busses/i2c-diolan-u2c.c        |    2 +-
+ drivers/i2c/busses/i2c-eg20t.c             |   12 +-
+ drivers/i2c/busses/i2c-hydra.c             |   17 +--
+ drivers/i2c/busses/i2c-intel-mid.c         |   13 +-
+ drivers/i2c/busses/i2c-nforce2.c           |   14 +-
+ drivers/i2c/busses/i2c-pasemi.c            |   13 +-
+ drivers/i2c/busses/i2c-piix4.c             |  209 +++++++++++++++++++++-------
+ drivers/i2c/busses/i2c-pxa-pci.c           |   12 +-
+ drivers/i2c/busses/i2c-sis630.c            |   15 +-
+ drivers/i2c/busses/i2c-sis96x.c            |   15 +-
+ drivers/i2c/busses/i2c-via.c               |   14 +-
+ drivers/i2c/muxes/i2c-mux-pca9541.c        |    2 +-
+ 21 files changed, 202 insertions(+), 252 deletions(-)
+Merging bjdooks-i2c/next-i2c (fc84fe1 Merge branch 'for_3.3/i2c/misc' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm into for-33/i2c/omap)
+$ git merge bjdooks-i2c/next-i2c
+Resolved 'drivers/i2c/busses/i2c-omap.c' using previous resolution.
+Auto-merging drivers/i2c/busses/i2c-omap.c
+CONFLICT (content): Merge conflict in drivers/i2c/busses/i2c-omap.c
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master db4a25e] Merge remote-tracking branch 'bjdooks-i2c/next-i2c'
+$ git diff -M --stat --summary HEAD^..
+Merging i2c-embedded/i2c-embedded/for-next (0f009a9 i2c: tegra: make all resource allocation through devm_*)
+$ git merge i2c-embedded/i2c-embedded/for-next
+Merge made by the 'recursive' strategy.
+ .../{gpio/gpio_i2c.txt => i2c/gpio-i2c.txt}        |    0
+ drivers/i2c/busses/i2c-omap.c                      |  129 ++++++++++----------
+ drivers/i2c/busses/i2c-tegra.c                     |   98 ++++++++-------
+ 3 files changed, 111 insertions(+), 116 deletions(-)
+ rename Documentation/devicetree/bindings/{gpio/gpio_i2c.txt => i2c/gpio-i2c.txt} (100%)
+Merging quilt/jdelvare-hwmon (3c1aae2 hwmon: struct x86_cpu_id arrays can be __initconst)
+$ git merge quilt/jdelvare-hwmon
+Merge made by the 'recursive' strategy.
+ drivers/hwmon/coretemp.c    |    2 +-
+ drivers/hwmon/via-cputemp.c |    2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+Merging hwmon-staging/hwmon-next (56e42ea hwmon: (applesmc) Skip sensor mapping)
+$ git merge hwmon-staging/hwmon-next
+Merge made by the 'recursive' strategy.
+ Documentation/hwmon/da9052             |   61 ++++++
+ Documentation/hwmon/submitting-patches |    3 +
+ drivers/hwmon/Kconfig                  |   10 +
+ drivers/hwmon/Makefile                 |    1 +
+ drivers/hwmon/adm1021.c                |   18 +-
+ drivers/hwmon/adm1025.c                |   15 +-
+ drivers/hwmon/adm1026.c                |   15 +-
+ drivers/hwmon/adm1031.c                |   15 +-
+ drivers/hwmon/adm9240.c                |   14 +-
+ drivers/hwmon/adt7475.c                |    7 +-
+ drivers/hwmon/applesmc.c               |   43 ++--
+ drivers/hwmon/asc7621.c                |    5 +-
+ drivers/hwmon/atxp1.c                  |   16 +-
+ drivers/hwmon/da9052-hwmon.c           |  344 ++++++++++++++++++++++++++++++++
+ drivers/hwmon/ds1621.c                 |   16 +-
+ drivers/hwmon/emc6w201.c               |   15 +-
+ drivers/hwmon/f71805f.c                |   26 +--
+ drivers/hwmon/gl518sm.c                |   15 +-
+ drivers/hwmon/gl520sm.c                |   15 +-
+ drivers/hwmon/gpio-fan.c               |   56 ++----
+ drivers/hwmon/jc42.c                   |    2 +-
+ drivers/hwmon/k8temp.c                 |   25 +--
+ drivers/hwmon/lineage-pem.c            |    2 +-
+ drivers/hwmon/lm63.c                   |   14 +-
+ drivers/hwmon/lm75.c                   |    9 +-
+ drivers/hwmon/lm77.c                   |   73 +++----
+ drivers/hwmon/lm78.c                   |   36 +---
+ drivers/hwmon/lm80.c                   |   14 +-
+ drivers/hwmon/lm83.c                   |   15 +-
+ drivers/hwmon/lm85.c                   |    7 +-
+ drivers/hwmon/lm87.c                   |   15 +-
+ drivers/hwmon/lm90.c                   |   12 +-
+ drivers/hwmon/lm92.c                   |   15 +-
+ drivers/hwmon/lm93.c                   |   14 +-
+ drivers/hwmon/ltc4261.c                |    2 +-
+ drivers/hwmon/max1111.c                |    9 +-
+ drivers/hwmon/max16065.c               |    2 +-
+ drivers/hwmon/max1619.c                |   15 +-
+ drivers/hwmon/max6639.c                |   17 +-
+ drivers/hwmon/max6642.c                |   15 +-
+ drivers/hwmon/max6650.c                |   10 +-
+ drivers/hwmon/mc13783-adc.c            |   12 +-
+ drivers/hwmon/ntc_thermistor.c         |    2 +-
+ drivers/hwmon/pc87360.c                |   41 ++--
+ drivers/hwmon/pc87427.c                |   51 +----
+ drivers/hwmon/pcf8591.c                |   15 +-
+ drivers/hwmon/sis5595.c                |   28 +--
+ drivers/hwmon/smsc47b397.c             |   22 +-
+ drivers/hwmon/smsc47m1.c               |   45 +----
+ drivers/hwmon/smsc47m192.c             |   16 +-
+ drivers/hwmon/thmc50.c                 |   17 +-
+ drivers/hwmon/tmp102.c                 |   14 +-
+ drivers/hwmon/tmp401.c                 |    6 +-
+ drivers/hwmon/tmp421.c                 |   13 +-
+ drivers/hwmon/via686a.c                |   23 +--
+ drivers/hwmon/vt1211.c                 |   22 +-
+ drivers/hwmon/w83627hf.c               |   46 ++---
+ drivers/hwmon/w83781d.c                |   46 ++---
+ drivers/hwmon/w83791d.c                |   15 +-
+ drivers/hwmon/w83792d.c                |   18 +-
+ drivers/hwmon/w83795.c                 |   11 +-
+ drivers/hwmon/w83l785ts.c              |   34 ++--
+ drivers/hwmon/wm831x-hwmon.c           |    9 +-
+ 63 files changed, 776 insertions(+), 763 deletions(-)
+ create mode 100644 Documentation/hwmon/da9052
+ create mode 100644 drivers/hwmon/da9052-hwmon.c
+Merging v4l-dvb/master (db04b6c Merge tag 'v3.5-rc4')
+$ git merge v4l-dvb/master
+Removing drivers/media/video/saa7146reg.h
+Removing drivers/media/video/saa7146.h
+Removing drivers/media/video/saa7121.h
+Removing drivers/media/video/ibmmpeg2.h
+Removing drivers/media/video/cs8420.h
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ Documentation/DocBook/media/v4l/biblio.xml         |    2 +-
+ Documentation/DocBook/media/v4l/common.xml         |   17 +-
+ .../DocBook/media/v4l/vidioc-g-frequency.xml       |    6 +
+ Documentation/DocBook/media/v4l/vidioc-g-tuner.xml |   12 +
+ .../DocBook/media/v4l/vidioc-s-hw-freq-seek.xml    |   18 +-
+ Documentation/dvb/get_dvb_firmware                 |   20 +-
+ MAINTAINERS                                        |    3 +-
+ drivers/media/dvb/frontends/s5h1420.c              |   20 -
+ drivers/media/dvb/frontends/stb0899_drv.c          |   22 +-
+ drivers/media/dvb/frontends/stv0367.c              |    5 +-
+ drivers/media/dvb/frontends/stv090x.c              |    7 +-
+ drivers/media/radio/Kconfig                        |    7 +
+ drivers/media/radio/Makefile                       |    1 +
+ drivers/media/radio/lm7000.c                       |   52 +++
+ drivers/media/radio/lm7000.h                       |   32 ++
+ drivers/media/radio/radio-aimslab.c                |   78 ++--
+ drivers/media/radio/radio-mr800.c                  |    5 +-
+ drivers/media/radio/radio-sf16fmi.c                |    2 +
+ drivers/media/radio/radio-wl1273.c                 |    3 +-
+ drivers/media/radio/si470x/radio-si470x-common.c   |    6 +-
+ drivers/media/radio/wl128x/fmdrv_rx.c              |    2 +-
+ drivers/media/radio/wl128x/fmdrv_v4l2.c            |    4 +-
+ drivers/media/rc/ir-raw.c                          |    4 +-
+ drivers/media/video/bt8xx/bttv-driver.c            |    6 -
+ drivers/media/video/cs8420.h                       |   50 --
+ drivers/media/video/cx231xx/cx231xx-cards.c        |   17 +-
+ drivers/media/video/em28xx/em28xx-audio.c          |   27 +-
+ drivers/media/video/em28xx/em28xx-cards.c          |    1 +
+ drivers/media/video/em28xx/em28xx-core.c           |   33 +-
+ drivers/media/video/em28xx/em28xx-dvb.c            |   91 +++-
+ drivers/media/video/em28xx/em28xx-i2c.c            |    1 +
+ drivers/media/video/em28xx/em28xx-input.c          |    2 +-
+ drivers/media/video/em28xx/em28xx-reg.h            |   51 +--
+ drivers/media/video/ibmmpeg2.h                     |   94 ----
+ drivers/media/video/mt9m001.c                      |    2 +-
+ drivers/media/video/mt9m032.c                      |   13 +-
+ drivers/media/video/mt9p031.c                      |    5 +-
+ drivers/media/video/mt9t001.c                      |   13 +-
+ drivers/media/video/mt9v022.c                      |    2 +-
+ drivers/media/video/pms.c                          |    1 +
+ drivers/media/video/pvrusb2/pvrusb2-v4l2.c         |    8 -
+ drivers/media/video/s5p-fimc/fimc-capture.c        |    2 +-
+ drivers/media/video/s5p-fimc/fimc-core.c           |    2 +-
+ drivers/media/video/s5p-fimc/fimc-lite-reg.c       |    2 +-
+ drivers/media/video/s5p-fimc/fimc-mdevice.c        |    7 +-
+ drivers/media/video/saa7121.h                      |  132 ------
+ drivers/media/video/saa7146.h                      |  112 -----
+ drivers/media/video/saa7146reg.h                   |  283 ------------
+ drivers/media/video/saa7164/saa7164-api.c          |   14 -
+ drivers/media/video/smiapp/smiapp-core.c           |    1 +
+ drivers/media/video/tvaudio.c                      |  189 ++++----
+ drivers/media/video/videobuf-dma-contig.c          |    2 +-
+ drivers/media/video/zr364xx.c                      |  484 +++++++++-----------
+ drivers/staging/media/lirc/lirc_sir.c              |   60 ++-
+ drivers/staging/media/solo6x10/i2c.c               |    2 +-
+ include/linux/videodev2.h                          |    2 +
+ include/media/mt9t001.h                            |    1 +
+ include/media/videobuf2-dma-contig.h               |    6 +-
+ sound/i2c/other/tea575x-tuner.c                    |    4 +-
+ 59 files changed, 770 insertions(+), 1280 deletions(-)
+ create mode 100644 drivers/media/radio/lm7000.c
+ create mode 100644 drivers/media/radio/lm7000.h
+ delete mode 100644 drivers/media/video/cs8420.h
+ delete mode 100644 drivers/media/video/ibmmpeg2.h
+ delete mode 100644 drivers/media/video/saa7121.h
+ delete mode 100644 drivers/media/video/saa7146.h
+ delete mode 100644 drivers/media/video/saa7146reg.h
+Merging kbuild/for-next (c6ff25b Merge branch 'kbuild/rc-fixes' into kbuild/for-next)
+$ git merge kbuild/for-next
+Already up-to-date!
+Merge made by the 'recursive' strategy.
+Merging kconfig/for-next (4503379 localmodconfig: Add debug environment variable LOCALMODCONFIG_DEBUG)
+$ git merge kconfig/for-next
+Merge made by the 'recursive' strategy.
+ scripts/kconfig/streamline_config.pl |  175 ++++++++++++++++++++++++++++++----
+ 1 file changed, 158 insertions(+), 17 deletions(-)
+Merging libata/NEXT (2fff275 PATA host controller driver for ep93xx)
+$ git merge libata/NEXT
+Already up-to-date.
+Merging infiniband/for-next (a323e3f Merge branch 'cma' into for-next)
+$ git merge infiniband/for-next
+Already up-to-date!
+Merge made by the 'recursive' strategy.
+Merging acpi/next (4e86d6d Merge branch 'turbostat-v2' into next)
+$ git merge acpi/next
+Resolved 'drivers/pci/pci-acpi.c' using previous resolution.
+Removing include/linux/platform_data/spear_thermal.h
+Auto-merging include/acpi/acpi_bus.h
+Auto-merging drivers/pci/pci-acpi.c
+CONFLICT (content): Merge conflict in drivers/pci/pci-acpi.c
+Auto-merging drivers/acpi/sleep.c
+Auto-merging MAINTAINERS
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master d69897c] Merge remote-tracking branch 'acpi/next'
+$ git diff -M --stat --summary HEAD^..
+ .../devicetree/bindings/thermal/spear-thermal.txt  |   14 +
+ Documentation/thermal/sysfs-api.txt                |   10 +-
+ MAINTAINERS                                        |    7 -
+ arch/x86/kernel/acpi/boot.c                        |   27 +-
+ arch/x86/kernel/reboot.c                           |    8 +
+ drivers/acpi/acpi_memhotplug.c                     |   43 +-
+ drivers/acpi/acpi_pad.c                            |   11 +-
+ drivers/acpi/acpica/acglobal.h                     |    3 +-
+ drivers/acpi/acpica/aclocal.h                      |   13 +-
+ drivers/acpi/acpica/acobject.h                     |    9 +-
+ drivers/acpi/acpica/acutils.h                      |    2 +
+ drivers/acpi/acpica/dsfield.c                      |   81 ++
+ drivers/acpi/acpica/evmisc.c                       |  185 +--
+ drivers/acpi/acpica/evxface.c                      |  444 +++----
+ drivers/acpi/acpica/exdump.c                       |   29 +-
+ drivers/acpi/acpica/hwesleep.c                     |    9 +-
+ drivers/acpi/acpica/psargs.c                       |    2 +
+ drivers/acpi/acpica/tbfadt.c                       |   32 +-
+ drivers/acpi/acpica/utdelete.c                     |   24 +-
+ drivers/acpi/acpica/utglobal.c                     |    4 +-
+ drivers/acpi/acpica/utmisc.c                       |   29 +
+ drivers/acpi/apei/apei-base.c                      |   17 +-
+ drivers/acpi/apei/apei-internal.h                  |    9 +
+ drivers/acpi/apei/ghes.c                           |    6 +-
+ drivers/acpi/bus.c                                 |    4 +
+ drivers/acpi/container.c                           |   43 +-
+ drivers/acpi/osl.c                                 |    4 +-
+ drivers/acpi/processor_driver.c                    |   28 +-
+ drivers/acpi/scan.c                                |   58 +-
+ drivers/acpi/sleep.c                               |    2 +-
+ drivers/acpi/sysfs.c                               |    4 +-
+ drivers/acpi/thermal.c                             |    4 +-
+ drivers/acpi/utils.c                               |   42 +
+ drivers/cpuidle/Kconfig                            |    3 +
+ drivers/cpuidle/Makefile                           |    1 +
+ drivers/cpuidle/coupled.c                          |  715 +++++++++++
+ drivers/cpuidle/cpuidle.c                          |   85 +-
+ drivers/cpuidle/cpuidle.h                          |   32 +
+ drivers/idle/intel_idle.c                          |   37 +
+ drivers/platform/x86/acerhdf.c                     |    2 +-
+ drivers/platform/x86/intel_mid_thermal.c           |    2 +-
+ drivers/thermal/Kconfig                            |    1 +
+ drivers/thermal/spear_thermal.c                    |   28 +-
+ drivers/thermal/thermal_sys.c                      |  193 ++-
+ include/acpi/acpi_bus.h                            |   12 +-
+ include/acpi/acpiosxf.h                            |    2 +-
+ include/acpi/acpixf.h                              |    2 +-
+ include/acpi/actypes.h                             |    7 +-
+ include/linux/acpi.h                               |   40 +-
+ include/linux/cpuidle.h                            |   11 +
+ include/linux/platform_data/spear_thermal.h        |   26 -
+ include/linux/thermal.h                            |   15 +-
+ tools/power/x86/turbostat/Makefile                 |    1 +
+ tools/power/x86/turbostat/turbostat.8              |   77 +-
+ tools/power/x86/turbostat/turbostat.c              | 1333 ++++++++++++--------
+ 55 files changed, 2645 insertions(+), 1187 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/thermal/spear-thermal.txt
+ create mode 100644 drivers/cpuidle/coupled.c
+ delete mode 100644 include/linux/platform_data/spear_thermal.h
+Merging cpuidle/cpuidle-next (1cdb80c cpuidle: coupled: add parallel barrier function)
+$ git merge cpuidle/cpuidle-next
+Resolved 'drivers/cpuidle/coupled.c' using previous resolution.
+Auto-merging drivers/cpuidle/coupled.c
+CONFLICT (add/add): Merge conflict in drivers/cpuidle/coupled.c
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 0e24e88] Merge remote-tracking branch 'cpuidle/cpuidle-next'
+$ git diff -M --stat --summary HEAD^..
+Merging cpupowerutils/master (f166033 cpupower tools: add install target to the debug tools' makefiles)
+$ git merge cpupowerutils/master
+Already up-to-date.
+Merging ieee1394/for-next (e18907c firewire: ohci: initialize multiChanMode bits after reset)
+$ git merge ieee1394/for-next
+Auto-merging include/linux/firewire.h
+Auto-merging drivers/firewire/core-transaction.c
+Merge made by the 'recursive' strategy.
+ drivers/firewire/core-iso.c         |    2 +-
+ drivers/firewire/core-transaction.c |   23 +++++++++++++++++++++--
+ drivers/firewire/ohci.c             |   30 ++++++++++++++++++++++++------
+ include/linux/firewire.h            |    2 +-
+ 4 files changed, 47 insertions(+), 10 deletions(-)
+Merging ubi/linux-next (f8f5701 Linux 3.5-rc1)
+$ git merge ubi/linux-next
+Already up-to-date.
+Merging dlm/next (aefee56 dlm: fix missing dir remove)
+$ git merge dlm/next
+Merge made by the 'recursive' strategy.
+ fs/dlm/config.c       |    7 -
+ fs/dlm/config.h       |    1 -
+ fs/dlm/debug_fs.c     |  103 ++++-
+ fs/dlm/dir.c          |  287 +++---------
+ fs/dlm/dir.h          |    7 +-
+ fs/dlm/dlm_internal.h |   62 ++-
+ fs/dlm/lock.c         | 1167 ++++++++++++++++++++++++++++++++++++++++---------
+ fs/dlm/lock.h         |    4 +-
+ fs/dlm/lockspace.c    |   45 +-
+ fs/dlm/rcom.c         |  122 ++++--
+ fs/dlm/recover.c      |  295 ++++++++-----
+ fs/dlm/recover.h      |    2 +-
+ fs/dlm/recoverd.c     |   14 +-
+ 13 files changed, 1483 insertions(+), 633 deletions(-)
+Merging scsi/for-next (6ef2448 [SCSI] qla4xxx: Update driver version to 5.02.00-k18)
+$ git merge scsi/for-next
+Auto-merging include/scsi/scsi_device.h
+Removing drivers/scsi/scsi_wait_scan.c
+Merge made by the 'recursive' strategy.
+ drivers/scsi/Kconfig                       |   17 --
+ drivers/scsi/Makefile                      |    2 -
+ drivers/scsi/arcmsr/arcmsr_hba.c           |    4 +-
+ drivers/scsi/bnx2fc/Makefile               |    3 +-
+ drivers/scsi/bnx2fc/bnx2fc.h               |    9 +-
+ drivers/scsi/bnx2fc/bnx2fc_debug.c         |   70 +++++++++
+ drivers/scsi/bnx2fc/bnx2fc_debug.h         |   73 +++------
+ drivers/scsi/bnx2fc/bnx2fc_fcoe.c          |   56 ++++---
+ drivers/scsi/bnx2fc/bnx2fc_hwi.c           |    4 +-
+ drivers/scsi/bnx2fc/bnx2fc_io.c            |   25 ++-
+ drivers/scsi/bnx2fc/bnx2fc_tgt.c           |   40 +++--
+ drivers/scsi/device_handler/scsi_dh_alua.c |   69 ++++++--
+ drivers/scsi/fcoe/fcoe.c                   |   18 +--
+ drivers/scsi/fcoe/fcoe_ctlr.c              |   13 +-
+ drivers/scsi/fcoe/fcoe_transport.c         |   12 +-
+ drivers/scsi/hptiop.c                      |   10 +-
+ drivers/scsi/hptiop.h                      |    1 +
+ drivers/scsi/libfc/fc_exch.c               |   34 +++-
+ drivers/scsi/libfc/fc_fcp.c                |   16 +-
+ drivers/scsi/libfc/fc_frame.c              |    2 +-
+ drivers/scsi/libfc/fc_lport.c              |   61 ++++----
+ drivers/scsi/lpfc/lpfc.h                   |    4 +
+ drivers/scsi/lpfc/lpfc_attr.c              |   93 ++++++++++-
+ drivers/scsi/lpfc/lpfc_crtn.h              |    4 +-
+ drivers/scsi/lpfc/lpfc_debugfs.h           |   18 ++-
+ drivers/scsi/lpfc/lpfc_hbadisc.c           |    2 +-
+ drivers/scsi/lpfc/lpfc_hw4.h               |   45 ++++++
+ drivers/scsi/lpfc/lpfc_init.c              |  233 ++++++++++++++++++++++------
+ drivers/scsi/lpfc/lpfc_scsi.c              |   32 ++--
+ drivers/scsi/lpfc/lpfc_sli.c               |  131 +++++++++++++---
+ drivers/scsi/lpfc/lpfc_sli4.h              |    1 +
+ drivers/scsi/lpfc/lpfc_version.h           |    2 +-
+ drivers/scsi/mpt2sas/mpt2sas_base.h        |    3 +-
+ drivers/scsi/mpt2sas/mpt2sas_scsih.c       |    4 +-
+ drivers/scsi/qla4xxx/ql4_def.h             |    1 +
+ drivers/scsi/qla4xxx/ql4_glbl.h            |    3 +-
+ drivers/scsi/qla4xxx/ql4_init.c            |    2 +-
+ drivers/scsi/qla4xxx/ql4_os.c              |  156 +++++++++++++++++--
+ drivers/scsi/qla4xxx/ql4_version.h         |    2 +-
+ drivers/scsi/scsi_lib.c                    |   46 +++---
+ drivers/scsi/scsi_priv.h                   |    4 +-
+ drivers/scsi/scsi_sysfs.c                  |    1 +
+ drivers/scsi/scsi_transport_fc.c           |   34 ++--
+ drivers/scsi/scsi_transport_iscsi.c        |    6 +-
+ drivers/scsi/scsi_wait_scan.c              |   42 -----
+ include/scsi/libfc.h                       |   24 +--
+ include/scsi/scsi.h                        |    2 +
+ include/scsi/scsi_device.h                 |    4 +-
+ include/scsi/scsi_transport_fc.h           |   12 ++
+ 49 files changed, 1031 insertions(+), 419 deletions(-)
+ create mode 100644 drivers/scsi/bnx2fc/bnx2fc_debug.c
+ delete mode 100644 drivers/scsi/scsi_wait_scan.c
+Merging target-updates/for-next (4318efc target: move unmap to struct spc_ops)
+$ git merge target-updates/for-next
+Auto-merging drivers/target/target_core_transport.c
+Auto-merging drivers/target/target_core_spc.c
+Merge made by the 'recursive' strategy.
+ drivers/target/Makefile                            |    3 +-
+ drivers/target/iscsi/iscsi_target_configfs.c       |   22 -
+ drivers/target/iscsi/iscsi_target_core.h           |    1 +
+ drivers/target/iscsi/iscsi_target_tmr.c            |   43 +-
+ drivers/target/loopback/tcm_loop.c                 |    9 +-
+ drivers/target/target_core_configfs.c              |   38 -
+ drivers/target/target_core_file.c                  |   25 +-
+ drivers/target/target_core_iblock.c                |  125 +-
+ drivers/target/target_core_iblock.h                |    1 +
+ drivers/target/target_core_internal.h              |   13 +-
+ drivers/target/target_core_pscsi.c                 |   84 +-
+ drivers/target/target_core_rd.c                    |   17 +-
+ drivers/target/target_core_sbc.c                   |  581 ++++++++
+ .../{target_core_cdb.c => target_core_spc.c}       |  434 +++---
+ drivers/target/target_core_tmr.c                   |    3 -
+ drivers/target/target_core_transport.c             | 1541 +++-----------------
+ drivers/target/tcm_fc/tfc_cmd.c                    |    2 +-
+ include/target/target_core_backend.h               |   17 +-
+ include/target/target_core_base.h                  |   39 +-
+ 19 files changed, 1295 insertions(+), 1703 deletions(-)
+ create mode 100644 drivers/target/target_core_sbc.c
+ rename drivers/target/{target_core_cdb.c => target_core_spc.c} (76%)
+Merging target-merge/for-next-merge (cfaf025 Linux 3.5-rc2)
+$ git merge target-merge/for-next-merge
+Already up-to-date.
+Merging ibft/linux-next (935a9fe ibft: Fix finding IBFT ACPI table on UEFI)
+$ git merge ibft/linux-next
+Already up-to-date.
+Merging isci/all (6df8ea3 merge: devel rnc-devel fixes)
+$ git merge isci/all
+Auto-merging include/linux/libata.h
+Auto-merging drivers/scsi/scsi_error.c
+Auto-merging drivers/ata/libata-eh.c
+Auto-merging drivers/ata/libata-core.c
+Auto-merging Documentation/kernel-parameters.txt
+Merge made by the 'recursive' strategy.
+ Documentation/kernel-parameters.txt |    3 +
+ drivers/ata/libata-core.c           |   63 ++++++++---
+ drivers/ata/libata-eh.c             |   59 +++++++++--
+ drivers/scsi/isci/host.c            |    2 +-
+ drivers/scsi/isci/host.h            |    2 +-
+ drivers/scsi/isci/init.c            |   61 ++++++++++-
+ drivers/scsi/libsas/sas_ata.c       |  125 +++++++++++++++++++++-
+ drivers/scsi/libsas/sas_discover.c  |   92 +++++++++++++----
+ drivers/scsi/libsas/sas_dump.c      |    1 +
+ drivers/scsi/libsas/sas_event.c     |   16 +--
+ drivers/scsi/libsas/sas_expander.c  |   35 ++++---
+ drivers/scsi/libsas/sas_init.c      |  129 +++++++++++++++++++++--
+ drivers/scsi/libsas/sas_internal.h  |    1 +
+ drivers/scsi/libsas/sas_phy.c       |   21 ++++
+ drivers/scsi/libsas/sas_port.c      |   52 +++++++++-
+ drivers/scsi/libsas/sas_scsi_host.c |  195 ++++++++++++++++++++++++++++++-----
+ drivers/scsi/mvsas/mv_sas.c         |   21 ++--
+ drivers/scsi/pm8001/pm8001_sas.c    |   37 +++----
+ drivers/scsi/scsi_error.c           |   19 +++-
+ drivers/scsi/scsi_transport_sas.c   |    6 +-
+ include/linux/libata.h              |   16 +++
+ include/scsi/libsas.h               |   50 ++++++---
+ include/scsi/sas_ata.h              |   15 +++
+ 23 files changed, 869 insertions(+), 152 deletions(-)
+Merging slave-dma/next (49d57b5 dmaengine: mmp_tdma: fix the arch dependency)
+$ git merge slave-dma/next
+Auto-merging drivers/dma/dw_dmac.c
+Merge made by the 'recursive' strategy.
+ drivers/dma/Kconfig           |   26 +-
+ drivers/dma/Makefile          |    2 +
+ drivers/dma/at_hdmac.c        |    7 +-
+ drivers/dma/coh901318.c       |   72 +--
+ drivers/dma/dw_dmac.c         |  183 +++---
+ drivers/dma/dw_dmac_regs.h    |    2 +-
+ drivers/dma/mmp_tdma.c        |  610 ++++++++++++++++++
+ drivers/dma/mxs-dma.c         |    1 -
+ drivers/dma/tegra20-apb-dma.c | 1410 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/dmaengine.h     |   10 +
+ 10 files changed, 2169 insertions(+), 154 deletions(-)
+ create mode 100644 drivers/dma/mmp_tdma.c
+ create mode 100644 drivers/dma/tegra20-apb-dma.c
+Merging dmaengine/next (a2bd114 netdma: adding alignment check for NETDMA ops)
+$ git merge dmaengine/next
+Already up-to-date.
+Merging net-next/master (251da41 ipv4: Cache ip_error() routes even when not forwarding.)
+$ git merge net-next/master
+Resolved 'drivers/net/caif/caif_hsi.c' using previous resolution.
+Auto-merging net/netfilter/nfnetlink_queue_core.c
+Removing net/mac80211/work.c
+Auto-merging net/mac80211/mlme.c
+Auto-merging net/ipv6/tcp_ipv6.c
+Removing include/linux/netfilter_ipv4/ipt_addrtype.h
+Auto-merging drivers/net/wireless/ti/wlcore/wlcore_i.h
+Auto-merging drivers/net/wireless/mwifiex/sta_event.c
+Auto-merging drivers/net/wireless/mwifiex/11n_rxreorder.c
+Auto-merging drivers/net/wireless/iwlwifi/pcie/tx.c
+Auto-merging drivers/net/wireless/iwlwifi/pcie/trans.c
+Auto-merging drivers/net/wireless/iwlwifi/pcie/rx.c
+Auto-merging drivers/net/wireless/iwlwifi/pcie/internal.h
+Auto-merging drivers/net/wireless/iwlwifi/pcie/drv.c
+Auto-merging drivers/net/wireless/iwlwifi/pcie/6000.c
+Auto-merging drivers/net/wireless/iwlwifi/pcie/5000.c
+Auto-merging drivers/net/wireless/iwlwifi/pcie/2000.c
+Auto-merging drivers/net/wireless/iwlwifi/pcie/1000.c
+Removing drivers/net/wireless/iwlwifi/iwl-testmode.c
+Removing drivers/net/wireless/iwlwifi/iwl-eeprom.h
+Removing drivers/net/wireless/iwlwifi/iwl-eeprom.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/ucode.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/tx.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/tt.h
+Auto-merging drivers/net/wireless/iwlwifi/dvm/tt.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/sta.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/scan.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/rxon.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/rx.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/rs.h
+Auto-merging drivers/net/wireless/iwlwifi/dvm/rs.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/power.h
+Auto-merging drivers/net/wireless/iwlwifi/dvm/power.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/main.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/mac80211.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/lib.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/led.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/devices.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/dev.h
+Auto-merging drivers/net/wireless/iwlwifi/dvm/debugfs.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/commands.h
+Auto-merging drivers/net/wireless/iwlwifi/dvm/calib.h
+Auto-merging drivers/net/wireless/iwlwifi/dvm/calib.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/agn.h
+Auto-merging drivers/net/wireless/b43legacy/main.c
+Auto-merging drivers/net/wireless/ath/ath9k/recv.c
+Auto-merging drivers/net/caif/caif_hsi.c
+CONFLICT (content): Merge conflict in drivers/net/caif/caif_hsi.c
+Auto-merging MAINTAINERS
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master ab19a2f] Merge remote-tracking branch 'net-next/master'
+$ git diff -M --stat --summary HEAD^..
+ Documentation/feature-removal-schedule.txt         |   44 +-
+ Documentation/networking/batman-adv.txt            |    5 +
+ Documentation/networking/caif/Linux-CAIF.txt       |   91 +-
+ Documentation/networking/can.txt                   |  186 +-
+ Documentation/networking/ip-sysctl.txt             |    5 +
+ MAINTAINERS                                        |   18 +-
+ arch/sparc/net/bpf_jit_comp.c                      |    4 +
+ arch/x86/net/bpf_jit_comp.c                        |    4 +
+ drivers/bluetooth/bluecard_cs.c                    |   10 +-
+ drivers/bluetooth/bpa10x.c                         |    2 +-
+ drivers/bluetooth/bt3c_cs.c                        |    4 +-
+ drivers/bluetooth/btmrvl_sdio.c                    |    3 +
+ drivers/bluetooth/btuart_cs.c                      |    4 +-
+ drivers/bluetooth/btusb.c                          |   14 +-
+ drivers/bluetooth/dtl1_cs.c                        |    4 +-
+ drivers/bluetooth/hci_bcsp.c                       |    2 +-
+ drivers/bluetooth/hci_h4.c                         |    2 +-
+ drivers/bluetooth/hci_ldisc.c                      |    2 +-
+ drivers/bluetooth/hci_ll.c                         |    6 +-
+ drivers/net/appletalk/cops.c                       |    2 +-
+ drivers/net/bonding/bond_3ad.c                     |   13 +-
+ drivers/net/bonding/bond_3ad.h                     |    4 +-
+ drivers/net/bonding/bond_alb.c                     |   26 +-
+ drivers/net/bonding/bond_main.c                    |   55 +-
+ drivers/net/bonding/bonding.h                      |    4 +-
+ drivers/net/caif/caif_hsi.c                        |  548 ++---
+ drivers/net/can/bfin_can.c                         |    2 +-
+ drivers/net/can/c_can/Kconfig                      |   20 +-
+ drivers/net/can/c_can/Makefile                     |    1 +
+ drivers/net/can/c_can/c_can.c                      |  120 +-
+ drivers/net/can/c_can/c_can.h                      |  163 +-
+ drivers/net/can/c_can/c_can_pci.c                  |  221 ++
+ drivers/net/can/c_can/c_can_platform.c             |   76 +-
+ drivers/net/can/dev.c                              |   35 +-
+ drivers/net/can/flexcan.c                          |   38 +
+ drivers/net/can/mcp251x.c                          |    3 +-
+ drivers/net/can/vcan.c                             |   27 +-
+ drivers/net/ethernet/8390/apne.c                   |    2 +-
+ drivers/net/ethernet/aeroflex/greth.c              |    8 +-
+ drivers/net/ethernet/amd/declance.c                |    4 +-
+ drivers/net/ethernet/apple/macmace.c               |    2 +-
+ drivers/net/ethernet/atheros/atl1c/atl1c_hw.c      |    6 +-
+ drivers/net/ethernet/atheros/atl1c/atl1c_main.c    |    9 +-
+ drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c |    2 +-
+ drivers/net/ethernet/atheros/atl1e/atl1e_main.c    |   35 +-
+ drivers/net/ethernet/atheros/atlx/atl1.c           |    2 +-
+ drivers/net/ethernet/broadcom/bnx2.c               |   86 +-
+ drivers/net/ethernet/broadcom/bnx2.h               |   45 +
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x.h        |  154 +-
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c    |  223 +-
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h    |   58 +-
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c    |   30 +-
+ .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c    |  584 +++++-
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h    |   64 +-
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c   | 1230 +++++++----
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h   |   50 +-
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c   |  235 ++-
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h    |  125 ++
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c     |    8 +
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h     |    6 +
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c  |   63 +-
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h  |    2 +
+ drivers/net/ethernet/broadcom/cnic.c               |   12 +-
+ drivers/net/ethernet/brocade/bna/cna_fwimg.c       |    4 +-
+ drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c |    2 +-
+ drivers/net/ethernet/chelsio/cxgb4/sge.c           |    2 +-
+ .../net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c    |    2 +-
+ drivers/net/ethernet/chelsio/cxgb4vf/sge.c         |    5 +-
+ drivers/net/ethernet/dec/tulip/de4x5.c             |    2 +-
+ drivers/net/ethernet/emulex/benet/be.h             |    2 +-
+ drivers/net/ethernet/emulex/benet/be_cmds.c        |   21 +-
+ drivers/net/ethernet/emulex/benet/be_cmds.h        |    8 +-
+ drivers/net/ethernet/emulex/benet/be_hw.h          |    2 -
+ drivers/net/ethernet/emulex/benet/be_main.c        |  152 +-
+ drivers/net/ethernet/freescale/gianfar.c           |  491 ++---
+ drivers/net/ethernet/freescale/gianfar_ethtool.c   |  420 ++--
+ drivers/net/ethernet/freescale/ucc_geth.c          |    2 +-
+ drivers/net/ethernet/hp/hp100.c                    |    6 +-
+ drivers/net/ethernet/i825xx/lp486e.c               |    8 +-
+ drivers/net/ethernet/i825xx/sun3_82586.c           |    4 +-
+ drivers/net/ethernet/intel/e1000/e1000_main.c      |   12 +-
+ drivers/net/ethernet/intel/e1000e/netdev.c         |   11 +-
+ drivers/net/ethernet/intel/e1000e/param.c          |   43 +-
+ drivers/net/ethernet/intel/igb/e1000_regs.h        |    1 +
+ drivers/net/ethernet/intel/igb/igb.h               |   25 +-
+ drivers/net/ethernet/intel/igb/igb_ethtool.c       |   52 +-
+ drivers/net/ethernet/intel/igb/igb_main.c          |  156 +-
+ drivers/net/ethernet/intel/igb/igb_ptp.c           |   12 +-
+ drivers/net/ethernet/intel/ixgbe/Makefile          |    4 +-
+ drivers/net/ethernet/intel/ixgbe/ixgbe.h           |    2 +
+ drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c     |    4 +-
+ drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c   |  147 +-
+ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c      |   20 +-
+ drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c       |   23 +-
+ drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c       |  149 +-
+ drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c     |    2 -
+ drivers/net/ethernet/intel/ixgbe/ixgbe_type.h      |   39 +-
+ drivers/net/ethernet/marvell/mv643xx_eth.c         |    4 +-
+ drivers/net/ethernet/marvell/pxa168_eth.c          |    4 +-
+ .../net/ethernet/mellanox/mlx4/resource_tracker.c  |    4 +-
+ drivers/net/ethernet/micrel/ks8851_mll.c           |   27 +-
+ drivers/net/ethernet/neterion/s2io.c               |   14 +-
+ drivers/net/ethernet/neterion/vxge/vxge-config.c   |    8 +-
+ drivers/net/ethernet/neterion/vxge/vxge-config.h   |    2 +-
+ drivers/net/ethernet/neterion/vxge/vxge-main.c     |    8 +-
+ drivers/net/ethernet/neterion/vxge/vxge-traffic.c  |    5 +-
+ drivers/net/ethernet/nxp/lpc_eth.c                 |   17 +-
+ .../ethernet/qlogic/netxen/netxen_nic_ethtool.c    |    8 +-
+ drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c |    4 +-
+ drivers/net/ethernet/qlogic/qlcnic/qlcnic.h        |   15 +-
+ drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c    |   37 +-
+ drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h    |    1 +
+ drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c   |    3 +
+ drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |   10 +
+ drivers/net/ethernet/renesas/sh_eth.c              |  176 +-
+ drivers/net/ethernet/renesas/sh_eth.h              |    1 +
+ drivers/net/ethernet/sgi/ioc3-eth.c                |    4 +-
+ drivers/net/ethernet/smsc/smsc911x.c               |   17 +-
+ drivers/net/ethernet/smsc/smsc9420.c               |    3 +-
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |    3 +-
+ .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |    2 +-
+ drivers/net/ethernet/sun/sunqe.c                   |    2 +-
+ drivers/net/ethernet/via/via-velocity.c            |    2 +-
+ drivers/net/fddi/defxx.c                           |    4 +-
+ drivers/net/fddi/skfp/pmf.c                        |    8 +-
+ drivers/net/hamradio/mkiss.c                       |    8 +-
+ drivers/net/hyperv/netvsc.c                        |    2 +-
+ drivers/net/irda/ali-ircc.c                        |    6 +-
+ drivers/net/irda/au1k_ir.c                         |    2 +-
+ drivers/net/macvtap.c                              |    8 +-
+ drivers/net/phy/dp83640.c                          |   23 +-
+ drivers/net/phy/fixed.c                            |    4 +-
+ drivers/net/phy/mdio_bus.c                         |    5 +-
+ drivers/net/phy/national.c                         |    8 +-
+ drivers/net/phy/phy.c                              |   35 +-
+ drivers/net/phy/phy_device.c                       |    7 +-
+ drivers/net/phy/spi_ks8995.c                       |    4 +-
+ drivers/net/slip/slip.c                            |    4 +-
+ drivers/net/team/team.c                            |  546 +++--
+ drivers/net/team/team_mode_activebackup.c          |   14 +-
+ drivers/net/team/team_mode_loadbalance.c           |  542 ++++-
+ drivers/net/team/team_mode_roundrobin.c            |    4 +-
+ drivers/net/usb/cdc-phonet.c                       |    4 +-
+ drivers/net/usb/pegasus.c                          |    4 -
+ drivers/net/usb/qmi_wwan.c                         |  310 +--
+ drivers/net/usb/usbnet.c                           |   75 +-
+ drivers/net/vmxnet3/vmxnet3_drv.c                  |    2 +-
+ drivers/net/wan/x25_asy.c                          |    2 +-
+ drivers/net/wimax/i2400m/fw.c                      |    2 +-
+ drivers/net/wireless/adm8211.c                     |    3 +-
+ drivers/net/wireless/airo.c                        |    4 +-
+ drivers/net/wireless/ath/ath6kl/cfg80211.c         |   36 +-
+ drivers/net/wireless/ath/ath6kl/core.h             |    3 -
+ drivers/net/wireless/ath/ath6kl/main.c             |    1 -
+ drivers/net/wireless/ath/ath9k/Makefile            |    4 +-
+ drivers/net/wireless/ath/ath9k/ahb.c               |    2 +-
+ drivers/net/wireless/ath/ath9k/antenna.c           |  776 +++++++
+ drivers/net/wireless/ath/ath9k/ar9003_calib.c      |   20 +-
+ drivers/net/wireless/ath/ath9k/ar9003_eeprom.c     |    9 +-
+ drivers/net/wireless/ath/ath9k/ar9003_mac.c        |    7 +-
+ drivers/net/wireless/ath/ath9k/ar9003_mci.c        |  721 +++----
+ drivers/net/wireless/ath/ath9k/ar9003_mci.h        |   40 +-
+ drivers/net/wireless/ath/ath9k/ar9003_phy.c        |    4 +
+ drivers/net/wireless/ath/ath9k/ar9003_phy.h        |   32 +-
+ .../net/wireless/ath/ath9k/ar9462_2p0_initvals.h   |    7 +-
+ drivers/net/wireless/ath/ath9k/ath9k.h             |   50 +-
+ drivers/net/wireless/ath/ath9k/beacon.c            |   23 +-
+ drivers/net/wireless/ath/ath9k/btcoex.c            |   10 +-
+ drivers/net/wireless/ath/ath9k/btcoex.h            |    4 +
+ drivers/net/wireless/ath/ath9k/debug.c             |    9 +-
+ drivers/net/wireless/ath/ath9k/debug.h             |    1 +
+ drivers/net/wireless/ath/ath9k/eeprom_4k.c         |    5 +-
+ drivers/net/wireless/ath/ath9k/eeprom_9287.c       |    2 +-
+ drivers/net/wireless/ath/ath9k/eeprom_def.c        |    7 +-
+ drivers/net/wireless/ath/ath9k/gpio.c              |   44 +-
+ drivers/net/wireless/ath/ath9k/hw.c                |  223 +-
+ drivers/net/wireless/ath/ath9k/hw.h                |   10 +-
+ drivers/net/wireless/ath/ath9k/init.c              |   18 +-
+ drivers/net/wireless/ath/ath9k/link.c              |  510 +++++
+ drivers/net/wireless/ath/ath9k/main.c              |  705 ++-----
+ drivers/net/wireless/ath/ath9k/mci.c               |  227 ++-
+ drivers/net/wireless/ath/ath9k/mci.h               |   11 +-
+ drivers/net/wireless/ath/ath9k/pci.c               |    7 +-
+ drivers/net/wireless/ath/ath9k/rc.c                |   17 +-
+ drivers/net/wireless/ath/ath9k/recv.c              |  768 +------
+ drivers/net/wireless/ath/ath9k/reg.h               |    6 +-
+ drivers/net/wireless/ath/ath9k/xmit.c              |   51 +-
+ drivers/net/wireless/ath/carl9170/cmd.c            |    2 +-
+ drivers/net/wireless/ath/carl9170/rx.c             |    4 +-
+ drivers/net/wireless/atmel.c                       |    4 +-
+ drivers/net/wireless/b43legacy/dma.c               |    2 +-
+ drivers/net/wireless/b43legacy/main.c              |    2 +-
+ drivers/net/wireless/b43legacy/xmit.c              |    6 +-
+ drivers/net/wireless/brcm80211/brcmfmac/Makefile   |    2 +
+ drivers/net/wireless/brcm80211/brcmfmac/dhd.h      |    3 +
+ drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c  |  126 ++
+ drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h  |   59 +
+ .../net/wireless/brcm80211/brcmfmac/dhd_linux.c    |    7 +
+ drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c |  173 +-
+ drivers/net/wireless/brcm80211/brcmsmac/aiutils.c  |    3 +-
+ drivers/net/wireless/brcm80211/brcmsmac/aiutils.h  |    2 +-
+ drivers/net/wireless/brcm80211/brcmsmac/ampdu.c    |    5 +-
+ drivers/net/wireless/brcm80211/brcmsmac/dma.c      |    2 +-
+ .../net/wireless/brcm80211/brcmsmac/mac80211_if.c  |   14 +-
+ drivers/net/wireless/brcm80211/brcmsmac/main.c     |    2 +-
+ .../net/wireless/brcm80211/brcmsmac/phy/phy_n.c    |    2 +-
+ drivers/net/wireless/brcm80211/brcmutil/utils.c    |    2 +
+ drivers/net/wireless/hostap/hostap_proc.c          |    3 +-
+ drivers/net/wireless/ipw2x00/ipw2200.c             |   27 +-
+ drivers/net/wireless/iwlegacy/4965-mac.c           |   13 +-
+ drivers/net/wireless/iwlwifi/Kconfig               |    5 +
+ drivers/net/wireless/iwlwifi/Makefile              |   32 +-
+ drivers/net/wireless/iwlwifi/dvm/Makefile          |   13 +
+ .../net/wireless/iwlwifi/{iwl-agn.h => dvm/agn.h}  |  111 +-
+ .../iwlwifi/{iwl-agn-calib.c => dvm/calib.c}       |   24 +-
+ .../iwlwifi/{iwl-agn-calib.h => dvm/calib.h}       |    4 +-
+ .../iwlwifi/{iwl-commands.h => dvm/commands.h}     |    7 +-
+ .../iwlwifi/{iwl-debugfs.c => dvm/debugfs.c}       |   31 +-
+ .../net/wireless/iwlwifi/{iwl-dev.h => dvm/dev.h}  |  174 +-
+ .../iwlwifi/{iwl-agn-devices.c => dvm/devices.c}   |  178 +-
+ .../net/wireless/iwlwifi/{iwl-led.c => dvm/led.c}  |    5 +-
+ .../net/wireless/iwlwifi/{iwl-led.h => dvm/led.h}  |    0
+ .../wireless/iwlwifi/{iwl-agn-lib.c => dvm/lib.c}  |   20 +-
+ .../iwlwifi/{iwl-mac80211.c => dvm/mac80211.c}     |  146 +-
+ .../net/wireless/iwlwifi/{iwl-agn.c => dvm/main.c} |  426 ++--
+ .../wireless/iwlwifi/{iwl-power.c => dvm/power.c}  |   11 +-
+ .../wireless/iwlwifi/{iwl-power.h => dvm/power.h}  |    2 +-
+ .../wireless/iwlwifi/{iwl-agn-rs.c => dvm/rs.c}    |   50 +-
+ .../wireless/iwlwifi/{iwl-agn-rs.h => dvm/rs.h}    |    3 +-
+ .../wireless/iwlwifi/{iwl-agn-rx.c => dvm/rx.c}    |   34 +-
+ .../iwlwifi/{iwl-agn-rxon.c => dvm/rxon.c}         |   52 +-
+ .../wireless/iwlwifi/{iwl-scan.c => dvm/scan.c}    |  111 +-
+ .../wireless/iwlwifi/{iwl-agn-sta.c => dvm/sta.c}  |   60 +-
+ drivers/net/wireless/iwlwifi/dvm/testmode.c        |  471 +++++
+ .../wireless/iwlwifi/{iwl-agn-tt.c => dvm/tt.c}    |   13 +-
+ .../wireless/iwlwifi/{iwl-agn-tt.h => dvm/tt.h}    |    2 +-
+ .../wireless/iwlwifi/{iwl-agn-tx.c => dvm/tx.c}    |   62 +-
+ .../wireless/iwlwifi/{iwl-ucode.c => dvm/ucode.c}  |   34 +-
+ drivers/net/wireless/iwlwifi/iwl-config.h          |   28 +-
+ drivers/net/wireless/iwlwifi/iwl-csr.h             |   28 +-
+ drivers/net/wireless/iwlwifi/iwl-debug.c           |    6 +
+ drivers/net/wireless/iwlwifi/iwl-debug.h           |   17 +-
+ drivers/net/wireless/iwlwifi/iwl-devtrace.c        |    5 +
+ drivers/net/wireless/iwlwifi/iwl-devtrace.h        |    1 +
+ drivers/net/wireless/iwlwifi/iwl-drv.c             |  151 +-
+ drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c    |  900 +++++++++
+ drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h    |  138 ++
+ drivers/net/wireless/iwlwifi/iwl-eeprom-read.c     |  463 +++++
+ drivers/net/wireless/iwlwifi/iwl-eeprom-read.h     |   70 +
+ drivers/net/wireless/iwlwifi/iwl-eeprom.c          | 1148 -----------
+ drivers/net/wireless/iwlwifi/iwl-eeprom.h          |  269 ---
+ drivers/net/wireless/iwlwifi/iwl-fh.h              |    2 +
+ drivers/net/wireless/iwlwifi/iwl-io.c              |   53 +-
+ drivers/net/wireless/iwlwifi/iwl-io.h              |   16 +-
+ drivers/net/wireless/iwlwifi/iwl-notif-wait.c      |    8 +-
+ drivers/net/wireless/iwlwifi/iwl-op-mode.h         |    8 +-
+ drivers/net/wireless/iwlwifi/iwl-prph.h            |    2 +-
+ drivers/net/wireless/iwlwifi/iwl-test.c            |  856 ++++++++
+ drivers/net/wireless/iwlwifi/iwl-test.h            |  161 ++
+ drivers/net/wireless/iwlwifi/iwl-testmode.c        | 1114 ----------
+ drivers/net/wireless/iwlwifi/iwl-trans.h           |   56 +-
+ .../wireless/iwlwifi/{iwl-1000.c => pcie/1000.c}   |   19 +-
+ .../wireless/iwlwifi/{iwl-2000.c => pcie/2000.c}   |   22 +-
+ .../wireless/iwlwifi/{iwl-5000.c => pcie/5000.c}   |   20 +-
+ .../wireless/iwlwifi/{iwl-6000.c => pcie/6000.c}   |   25 +-
+ .../net/wireless/iwlwifi/{iwl-cfg.h => pcie/cfg.h} |    0
+ .../net/wireless/iwlwifi/{iwl-pci.c => pcie/drv.c} |    5 +-
+ .../{iwl-trans-pcie-int.h => pcie/internal.h}      |   22 +-
+ .../iwlwifi/{iwl-trans-pcie-rx.c => pcie/rx.c}     |   75 +-
+ .../iwlwifi/{iwl-trans-pcie.c => pcie/trans.c}     |  349 ++--
+ .../iwlwifi/{iwl-trans-pcie-tx.c => pcie/tx.c}     |  200 +-
+ drivers/net/wireless/libertas/cfg.c                |   39 +-
+ drivers/net/wireless/libertas/debugfs.c            |    4 +-
+ drivers/net/wireless/libertas/dev.h                |    1 +
+ drivers/net/wireless/libertas/if_usb.c             |    2 +-
+ drivers/net/wireless/libertas/mesh.c               |    7 +-
+ drivers/net/wireless/libertas_tf/if_usb.c          |    2 +-
+ drivers/net/wireless/mwifiex/11n.c                 |   14 +-
+ drivers/net/wireless/mwifiex/11n.h                 |    3 +-
+ drivers/net/wireless/mwifiex/11n_rxreorder.c       |   18 +-
+ drivers/net/wireless/mwifiex/cfg80211.c            |    2 +-
+ drivers/net/wireless/mwifiex/init.c                |   65 +
+ drivers/net/wireless/mwifiex/join.c                |   20 +-
+ drivers/net/wireless/mwifiex/main.c                |    4 +-
+ drivers/net/wireless/mwifiex/main.h                |   11 +-
+ drivers/net/wireless/mwifiex/scan.c                |   83 +-
+ drivers/net/wireless/mwifiex/sta_cmd.c             |   16 +-
+ drivers/net/wireless/mwifiex/sta_cmdresp.c         |   24 +-
+ drivers/net/wireless/mwifiex/sta_event.c           |    2 +-
+ drivers/net/wireless/orinoco/cfg.c                 |    9 +-
+ drivers/net/wireless/p54/eeprom.c                  |    2 +-
+ drivers/net/wireless/p54/fwio.c                    |    2 +-
+ drivers/net/wireless/prism54/islpci_eth.c          |    2 +-
+ drivers/net/wireless/ray_cs.c                      |    2 +-
+ drivers/net/wireless/rt2x00/rt2800.h               |    8 +
+ drivers/net/wireless/rt2x00/rt2800lib.c            |   27 +-
+ drivers/net/wireless/rt2x00/rt2800pci.c            |    1 +
+ drivers/net/wireless/rt2x00/rt2800usb.c            |    3 +-
+ drivers/net/wireless/rt2x00/rt2x00dev.c            |    2 +
+ drivers/net/wireless/rt2x00/rt2x00mac.c            |   14 +-
+ drivers/net/wireless/rtlwifi/base.c                |    2 +-
+ drivers/net/wireless/rtlwifi/cam.c                 |    2 +-
+ drivers/net/wireless/rtlwifi/core.c                |   14 +-
+ drivers/net/wireless/rtlwifi/efuse.c               |    4 +-
+ drivers/net/wireless/rtlwifi/pci.c                 |   14 +-
+ drivers/net/wireless/rtlwifi/ps.c                  |   10 +-
+ drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c  |    5 +-
+ drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c  |    4 +-
+ drivers/net/wireless/rtlwifi/rtl8192ce/hw.c        |   43 +-
+ drivers/net/wireless/rtlwifi/rtl8192ce/trx.c       |    4 +-
+ drivers/net/wireless/rtlwifi/rtl8192cu/hw.c        |   43 +-
+ drivers/net/wireless/rtlwifi/rtl8192cu/trx.c       |    2 +-
+ drivers/net/wireless/rtlwifi/rtl8192de/dm.c        |    2 +-
+ drivers/net/wireless/rtlwifi/rtl8192de/fw.c        |    6 +-
+ drivers/net/wireless/rtlwifi/rtl8192de/hw.c        |   34 +-
+ drivers/net/wireless/rtlwifi/rtl8192de/trx.c       |    6 +-
+ drivers/net/wireless/rtlwifi/rtl8192se/dm.c        |    2 +-
+ drivers/net/wireless/rtlwifi/rtl8192se/hw.c        |   46 +-
+ drivers/net/wireless/rtlwifi/rtl8192se/trx.c       |    2 +-
+ drivers/net/wireless/ti/Kconfig                    |    1 +
+ drivers/net/wireless/ti/Makefile                   |    1 +
+ drivers/net/wireless/ti/wl12xx/Makefile            |    2 +-
+ drivers/net/wireless/ti/wl12xx/acx.h               |  237 +++
+ drivers/net/wireless/ti/wl12xx/cmd.c               |    8 +-
+ drivers/net/wireless/ti/wl12xx/debugfs.c           |  243 +++
+ drivers/net/wireless/ti/wl12xx/debugfs.h           |   28 +
+ drivers/net/wireless/ti/wl12xx/main.c              |  242 ++-
+ drivers/net/wireless/ti/wl12xx/wl12xx.h            |    8 +
+ drivers/net/wireless/ti/wl18xx/Kconfig             |    7 +
+ drivers/net/wireless/ti/wl18xx/Makefile            |    3 +
+ drivers/net/wireless/ti/wl18xx/acx.c               |  111 +
+ drivers/net/wireless/ti/wl18xx/acx.h               |  291 +++
+ drivers/net/wireless/ti/wl18xx/conf.h              |   92 +
+ drivers/net/wireless/ti/wl18xx/debugfs.c           |  403 ++++
+ drivers/net/wireless/ti/wl18xx/debugfs.h           |   28 +
+ drivers/net/wireless/ti/wl18xx/io.c                |   60 +
+ drivers/net/wireless/ti/wl18xx/io.h                |   28 +
+ drivers/net/wireless/ti/wl18xx/main.c              | 1463 ++++++++++++++
+ drivers/net/wireless/ti/wl18xx/reg.h               |  191 ++
+ drivers/net/wireless/ti/wl18xx/tx.c                |  127 ++
+ drivers/net/wireless/ti/wl18xx/tx.h                |   46 +
+ drivers/net/wireless/ti/wl18xx/wl18xx.h            |   88 +
+ drivers/net/wireless/ti/wlcore/acx.c               |    8 +-
+ drivers/net/wireless/ti/wlcore/acx.h               |  254 +--
+ drivers/net/wireless/ti/wlcore/boot.c              |   57 +-
+ drivers/net/wireless/ti/wlcore/boot.h              |    1 +
+ drivers/net/wireless/ti/wlcore/cmd.c               |   62 +-
+ drivers/net/wireless/ti/wlcore/cmd.h               |   13 +-
+ drivers/net/wireless/ti/wlcore/conf.h              |   93 +-
+ drivers/net/wireless/ti/wlcore/debugfs.c           |  390 ++--
+ drivers/net/wireless/ti/wlcore/debugfs.h           |   87 +
+ drivers/net/wireless/ti/wlcore/event.c             |   24 +-
+ drivers/net/wireless/ti/wlcore/hw_ops.h            |   78 +
+ drivers/net/wireless/ti/wlcore/init.c              |    3 +
+ drivers/net/wireless/ti/wlcore/main.c              |  504 ++---
+ drivers/net/wireless/ti/wlcore/ps.c                |   21 +-
+ drivers/net/wireless/ti/wlcore/rx.c                |   11 +-
+ drivers/net/wireless/ti/wlcore/rx.h                |    7 +-
+ drivers/net/wireless/ti/wlcore/scan.c              |   52 +-
+ drivers/net/wireless/ti/wlcore/scan.h              |   19 +-
+ drivers/net/wireless/ti/wlcore/sdio.c              |   35 +-
+ drivers/net/wireless/ti/wlcore/tx.c                |  188 +-
+ drivers/net/wireless/ti/wlcore/tx.h                |   49 +-
+ drivers/net/wireless/ti/wlcore/wlcore.h            |   70 +-
+ .../wireless/ti/wlcore/{wl12xx.h => wlcore_i.h}    |   44 +-
+ drivers/net/wireless/zd1211rw/zd_chip.h            |    2 +-
+ drivers/net/wireless/zd1211rw/zd_usb.h             |    2 +-
+ drivers/nfc/pn533.c                                |  662 ++++--
+ drivers/nfc/pn544_hci.c                            |   10 +-
+ drivers/ssb/b43_pci_bridge.c                       |    1 +
+ drivers/ssb/scan.c                                 |    2 +
+ include/linux/can.h                                |   67 +-
+ include/linux/can/core.h                           |    4 +-
+ include/linux/can/dev.h                            |   33 +-
+ include/linux/can/error.h                          |    4 +-
+ include/linux/can/raw.h                            |    3 +-
+ include/linux/ethtool.h                            |   35 +
+ include/linux/if_ether.h                           |    3 +-
+ include/linux/if_team.h                            |   22 +-
+ include/linux/inetdevice.h                         |    2 +
+ include/linux/ks8851_mll.h                         |   33 +
+ include/linux/netdevice.h                          |    8 +-
+ include/linux/netfilter.h                          |   26 +
+ include/linux/netfilter/Kbuild                     |    1 +
+ include/linux/netfilter/nf_conntrack_sip.h         |    2 +
+ include/linux/netfilter/nfnetlink.h                |    3 +-
+ include/linux/netfilter/nfnetlink_conntrack.h      |    1 +
+ include/linux/netfilter/nfnetlink_cthelper.h       |   55 +
+ include/linux/netfilter/nfnetlink_queue.h          |    8 +
+ include/linux/netfilter/xt_connlimit.h             |    9 +-
+ include/linux/netfilter/xt_recent.h                |   10 +
+ include/linux/netfilter_ipv4.h                     |    1 +
+ include/linux/netfilter_ipv4/Kbuild                |    1 -
+ include/linux/netfilter_ipv4/ipt_addrtype.h        |   27 -
+ include/linux/netfilter_ipv6.h                     |    1 +
+ include/linux/nfc.h                                |   12 +
+ include/linux/nl80211.h                            |    8 +
+ include/linux/sock_diag.h                          |    1 +
+ include/linux/ssb/ssb.h                            |    1 +
+ include/linux/tcp.h                                |    3 +-
+ include/linux/usb/usbnet.h                         |    5 +-
+ include/net/af_unix.h                              |    3 +-
+ include/net/bluetooth/a2mp.h                       |  126 ++
+ include/net/bluetooth/bluetooth.h                  |   39 +-
+ include/net/bluetooth/hci.h                        |   99 +-
+ include/net/bluetooth/hci_core.h                   |   29 +-
+ include/net/bluetooth/l2cap.h                      |  205 +-
+ include/net/caif/caif_hsi.h                        |   71 +-
+ include/net/cfg80211.h                             |   45 +-
+ include/net/dst.h                                  |   17 +-
+ include/net/flow.h                                 |    1 +
+ include/net/inet_connection_sock.h                 |    5 +-
+ include/net/inet_hashtables.h                      |    4 +-
+ include/net/inetpeer.h                             |   82 +-
+ include/net/ip.h                                   |    3 +
+ include/net/ip6_fib.h                              |   33 +-
+ include/net/ip6_route.h                            |   29 +-
+ include/net/ip_fib.h                               |   12 +-
+ include/net/mac80211.h                             |   44 +-
+ include/net/netfilter/nf_conntrack.h               |   35 +-
+ include/net/netfilter/nf_conntrack_core.h          |    4 +-
+ include/net/netfilter/nf_conntrack_expect.h        |    4 +-
+ include/net/netfilter/nf_conntrack_extend.h        |    9 +-
+ include/net/netfilter/nf_conntrack_helper.h        |   29 +-
+ include/net/netfilter/nf_conntrack_l3proto.h       |   11 +-
+ include/net/netfilter/nf_conntrack_l4proto.h       |   22 +-
+ include/net/netfilter/nf_nat_helper.h              |    4 +
+ include/net/netfilter/nfnetlink_queue.h            |   43 +
+ include/net/netns/conntrack.h                      |   55 +
+ include/net/netns/ipv4.h                           |    2 +-
+ include/net/netns/ipv6.h                           |    1 +
+ include/net/nfc/hci.h                              |    3 +-
+ include/net/nfc/nfc.h                              |   14 +-
+ include/net/nfc/shdlc.h                            |    3 +-
+ include/net/protocol.h                             |    8 +-
+ include/net/route.h                                |   61 +-
+ include/net/sock.h                                 |    5 +-
+ include/net/tcp.h                                  |    4 +-
+ include/net/timewait_sock.h                        |    8 -
+ net/9p/client.c                                    |    2 +-
+ net/atm/lec.c                                      |    8 +-
+ net/atm/pppoatm.c                                  |    2 +-
+ net/ax25/ax25_out.c                                |    2 +-
+ net/ax25/ax25_route.c                              |    2 +-
+ net/batman-adv/bat_algo.h                          |    6 +-
+ net/batman-adv/bat_debugfs.c                       |  185 +-
+ net/batman-adv/bat_debugfs.h                       |   13 +-
+ net/batman-adv/bat_iv_ogm.c                        |  736 +++----
+ net/batman-adv/bat_sysfs.c                         |  334 +--
+ net/batman-adv/bat_sysfs.h                         |   18 +-
+ net/batman-adv/bitarray.c                          |   43 +-
+ net/batman-adv/bitarray.h                          |   20 +-
+ net/batman-adv/bridge_loop_avoidance.c             |  650 +++---
+ net/batman-adv/bridge_loop_avoidance.h             |   71 +-
+ net/batman-adv/gateway_client.c                    |  259 +--
+ net/batman-adv/gateway_client.h                    |   30 +-
+ net/batman-adv/gateway_common.c                    |   31 +-
+ net/batman-adv/gateway_common.h                    |    9 +-
+ net/batman-adv/hard-interface.c                    |  193 +-
+ net/batman-adv/hard-interface.h                    |   33 +-
+ net/batman-adv/hash.c                              |   21 +-
+ net/batman-adv/hash.h                              |   68 +-
+ net/batman-adv/icmp_socket.c                       |  115 +-
+ net/batman-adv/icmp_socket.h                       |   12 +-
+ net/batman-adv/main.c                              |  157 +-
+ net/batman-adv/main.h                              |  130 +-
+ net/batman-adv/originator.c                        |  222 +-
+ net/batman-adv/originator.h                        |   40 +-
+ net/batman-adv/packet.h                            |   37 +-
+ net/batman-adv/ring_buffer.c                       |    9 +-
+ net/batman-adv/ring_buffer.h                       |    9 +-
+ net/batman-adv/routing.c                           |  475 +++--
+ net/batman-adv/routing.h                           |   56 +-
+ net/batman-adv/send.c                              |  180 +-
+ net/batman-adv/send.h                              |   21 +-
+ net/batman-adv/soft-interface.c                    |  235 ++-
+ net/batman-adv/soft-interface.h                    |   17 +-
+ net/batman-adv/translation-table.c                 | 1060 +++++-----
+ net/batman-adv/translation-table.h                 |   74 +-
+ net/batman-adv/types.h                             |   51 +-
+ net/batman-adv/unicast.c                           |   65 +-
+ net/batman-adv/unicast.h                           |   19 +-
+ net/batman-adv/vis.c                               |  170 +-
+ net/batman-adv/vis.h                               |   26 +-
+ net/bluetooth/Makefile                             |    3 +-
+ net/bluetooth/a2mp.c                               |  568 ++++++
+ net/bluetooth/af_bluetooth.c                       |   14 +-
+ net/bluetooth/bnep/core.c                          |   21 +-
+ net/bluetooth/bnep/netdev.c                        |   16 +-
+ net/bluetooth/bnep/sock.c                          |   18 +-
+ net/bluetooth/hci_conn.c                           |   98 +-
+ net/bluetooth/hci_core.c                           |  214 +-
+ net/bluetooth/hci_event.c                          |  309 +--
+ net/bluetooth/hci_sock.c                           |   59 +-
+ net/bluetooth/hci_sysfs.c                          |   99 +-
+ net/bluetooth/hidp/core.c                          |   26 +-
+ net/bluetooth/hidp/sock.c                          |   16 +-
+ net/bluetooth/l2cap_core.c                         | 2125 ++++++++++++--------
+ net/bluetooth/l2cap_sock.c                         |  130 +-
+ net/bluetooth/lib.c                                |    7 +-
+ net/bluetooth/mgmt.c                               |   71 +-
+ net/bluetooth/rfcomm/core.c                        |   32 +-
+ net/bluetooth/rfcomm/sock.c                        |   21 +-
+ net/bluetooth/rfcomm/tty.c                         |    9 +-
+ net/bluetooth/sco.c                                |   43 +-
+ net/bluetooth/smp.c                                |    7 +-
+ net/bridge/br_netfilter.c                          |   28 +-
+ net/caif/caif_dev.c                                |    8 +-
+ net/caif/cfctrl.c                                  |   17 +-
+ net/can/af_can.c                                   |  126 +-
+ net/can/raw.c                                      |   50 +-
+ net/core/dev.c                                     |   17 +
+ net/core/ethtool.c                                 |   45 +
+ net/core/net-sysfs.c                               |   74 -
+ net/core/skbuff.c                                  |    4 +-
+ net/core/sock.c                                    |    5 +
+ net/core/sock_diag.c                               |    1 +
+ net/dcb/dcbnl.c                                    | 1165 ++++-------
+ net/dccp/ipv4.c                                    |    2 +-
+ net/dccp/ipv6.c                                    |    2 +
+ net/decnet/dn_neigh.c                              |    6 +-
+ net/decnet/dn_nsp_out.c                            |    2 +-
+ net/decnet/netfilter/dn_rtmsg.c                    |    2 +-
+ net/ieee802154/6lowpan.c                           |  165 +-
+ net/ipv4/af_inet.c                                 |   46 +-
+ net/ipv4/ah4.c                                     |    1 +
+ net/ipv4/arp.c                                     |    3 +-
+ net/ipv4/devinet.c                                 |    5 +-
+ net/ipv4/esp4.c                                    |    1 +
+ net/ipv4/fib_semantics.c                           |    7 +-
+ net/ipv4/fib_trie.c                                |   16 +-
+ net/ipv4/icmp.c                                    |   18 +-
+ net/ipv4/inet_connection_sock.c                    |    8 +-
+ net/ipv4/inet_fragment.c                           |    2 +-
+ net/ipv4/inetpeer.c                                |   95 +-
+ net/ipv4/ip_fragment.c                             |    6 +-
+ net/ipv4/ip_gre.c                                  |   14 +-
+ net/ipv4/ip_input.c                                |   42 +-
+ net/ipv4/ip_output.c                               |   21 +-
+ net/ipv4/ipcomp.c                                  |    1 +
+ net/ipv4/ipip.c                                    |   15 +-
+ net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c     |  172 +-
+ net/ipv4/netfilter/nf_conntrack_proto_icmp.c       |   52 +-
+ net/ipv4/netfilter/nf_defrag_ipv4.c                |    4 +-
+ net/ipv4/netfilter/nf_nat_amanda.c                 |    4 +-
+ net/ipv4/netfilter/nf_nat_core.c                   |    6 +
+ net/ipv4/netfilter/nf_nat_h323.c                   |    8 +-
+ net/ipv4/netfilter/nf_nat_helper.c                 |   13 +
+ net/ipv4/netfilter/nf_nat_pptp.c                   |    6 +-
+ net/ipv4/netfilter/nf_nat_snmp_basic.c             |    4 +-
+ net/ipv4/netfilter/nf_nat_tftp.c                   |    4 +-
+ net/ipv4/ping.c                                    |    1 +
+ net/ipv4/protocol.c                                |    8 +-
+ net/ipv4/raw.c                                     |    3 +
+ net/ipv4/route.c                                   |  317 +--
+ net/ipv4/sysctl_net_ipv4.c                         |    7 +
+ net/ipv4/tcp_input.c                               |   16 +-
+ net/ipv4/tcp_ipv4.c                                |   96 +-
+ net/ipv4/tcp_minisocks.c                           |   34 +-
+ net/ipv4/tcp_output.c                              |   20 +-
+ net/ipv4/udp.c                                     |    1 +
+ net/ipv4/xfrm4_policy.c                            |   10 +-
+ net/ipv6/ah6.c                                     |    3 +-
+ net/ipv6/esp6.c                                    |    2 +
+ net/ipv6/exthdrs.c                                 |    4 +-
+ net/ipv6/icmp.c                                    |   19 +-
+ net/ipv6/ip6_fib.c                                 |    5 +
+ net/ipv6/ip6_input.c                               |    9 +-
+ net/ipv6/ip6_output.c                              |   26 +-
+ net/ipv6/ipcomp6.c                                 |    2 +
+ net/ipv6/ndisc.c                                   |    6 +-
+ net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c     |  131 +-
+ net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c     |   36 +-
+ net/ipv6/protocol.c                                |    8 +-
+ net/ipv6/raw.c                                     |    9 +-
+ net/ipv6/route.c                                   |  237 +--
+ net/ipv6/sit.c                                     |   15 +-
+ net/ipv6/tcp_ipv6.c                                |   37 +-
+ net/ipv6/udp.c                                     |    3 +
+ net/ipv6/xfrm6_policy.c                            |   10 +-
+ net/irda/irqueue.c                                 |    6 +-
+ net/l2tp/l2tp_ppp.c                                |    8 +-
+ net/mac80211/Makefile                              |    1 -
+ net/mac80211/agg-rx.c                              |   30 +-
+ net/mac80211/agg-tx.c                              |  109 +-
+ net/mac80211/cfg.c                                 |  579 +++---
+ net/mac80211/chan.c                                |    4 +
+ net/mac80211/debugfs_netdev.c                      |    3 +-
+ net/mac80211/ibss.c                                |  114 +-
+ net/mac80211/ieee80211_i.h                         |   92 +-
+ net/mac80211/iface.c                               |   42 +-
+ net/mac80211/main.c                                |   17 +-
+ net/mac80211/mesh.c                                |    3 +-
+ net/mac80211/mesh_hwmp.c                           |    2 +-
+ net/mac80211/mesh_pathtbl.c                        |    2 +-
+ net/mac80211/mesh_plink.c                          |    2 +-
+ net/mac80211/mesh_sync.c                           |    2 +-
+ net/mac80211/mlme.c                                |  189 +-
+ net/mac80211/offchannel.c                          |  280 ++-
+ net/mac80211/pm.c                                  |    1 +
+ net/mac80211/rx.c                                  |   22 +-
+ net/mac80211/scan.c                                |    7 +-
+ net/mac80211/sta_info.c                            |   23 +-
+ net/mac80211/status.c                              |   30 +-
+ net/mac80211/tkip.c                                |   21 +-
+ net/mac80211/tx.c                                  |   14 +-
+ net/mac80211/util.c                                |  117 +-
+ net/mac80211/work.c                                |  370 ----
+ net/netfilter/Kconfig                              |   21 +
+ net/netfilter/Makefile                             |    3 +
+ net/netfilter/core.c                               |    7 +
+ net/netfilter/ipvs/ip_vs_core.c                    |   24 +-
+ net/netfilter/ipvs/ip_vs_xmit.c                    |    4 +-
+ net/netfilter/nf_conntrack_core.c                  |   22 +-
+ net/netfilter/nf_conntrack_extend.c                |   16 +-
+ net/netfilter/nf_conntrack_ftp.c                   |   11 +-
+ net/netfilter/nf_conntrack_h323_main.c             |   16 +-
+ net/netfilter/nf_conntrack_helper.c                |   38 +-
+ net/netfilter/nf_conntrack_irc.c                   |    8 +-
+ net/netfilter/nf_conntrack_netlink.c               |  180 +-
+ net/netfilter/nf_conntrack_pptp.c                  |   17 +-
+ net/netfilter/nf_conntrack_proto.c                 |  273 ++-
+ net/netfilter/nf_conntrack_proto_dccp.c            |  137 +-
+ net/netfilter/nf_conntrack_proto_generic.c         |   52 +-
+ net/netfilter/nf_conntrack_proto_gre.c             |   79 +-
+ net/netfilter/nf_conntrack_proto_sctp.c            |  196 +-
+ net/netfilter/nf_conntrack_proto_tcp.c             |  183 +-
+ net/netfilter/nf_conntrack_proto_udp.c             |  123 +-
+ net/netfilter/nf_conntrack_proto_udplite.c         |  118 +-
+ net/netfilter/nf_conntrack_sane.c                  |   12 +-
+ net/netfilter/nf_conntrack_sip.c                   |   32 +-
+ net/netfilter/nf_conntrack_tftp.c                  |    8 +-
+ net/netfilter/nfnetlink_cthelper.c                 |  672 +++++++
+ net/netfilter/nfnetlink_cttimeout.c                |   13 +-
+ .../{nfnetlink_queue.c => nfnetlink_queue_core.c}  |   68 +-
+ net/netfilter/nfnetlink_queue_ct.c                 |   98 +
+ net/netfilter/xt_CT.c                              |   44 +-
+ net/netfilter/xt_NFQUEUE.c                         |   28 +-
+ net/netfilter/xt_connlimit.c                       |   35 +-
+ net/netfilter/xt_recent.c                          |   62 +-
+ net/nfc/core.c                                     |  119 +-
+ net/nfc/hci/core.c                                 |   13 +-
+ net/nfc/hci/shdlc.c                                |    6 +-
+ net/nfc/llcp/commands.c                            |   54 +-
+ net/nfc/llcp/llcp.c                                |  421 ++--
+ net/nfc/llcp/llcp.h                                |   26 +-
+ net/nfc/llcp/sock.c                                |   47 +-
+ net/nfc/nci/core.c                                 |   15 +-
+ net/nfc/netlink.c                                  |   81 +-
+ net/nfc/nfc.h                                      |   12 +-
+ net/packet/af_packet.c                             |   11 +-
+ net/rfkill/core.c                                  |    2 +-
+ net/rxrpc/ar-error.c                               |    4 -
+ net/tipc/port.c                                    |    9 +-
+ net/tipc/socket.c                                  |    2 +-
+ net/unix/af_unix.c                                 |  110 +-
+ net/unix/diag.c                                    |    6 +-
+ net/wireless/Kconfig                               |   14 -
+ net/wireless/chan.c                                |   55 +-
+ net/wireless/core.h                                |   12 +-
+ net/wireless/mesh.c                                |   91 +-
+ net/wireless/mlme.c                                |    2 -
+ net/wireless/nl80211.c                             |  129 +-
+ net/wireless/wext-compat.c                         |   21 +-
+ net/wireless/wext-sme.c                            |   10 +-
+ security/selinux/hooks.c                           |   10 +-
+ 666 files changed, 30778 insertions(+), 18858 deletions(-)
+ create mode 100644 drivers/net/can/c_can/c_can_pci.c
+ create mode 100644 drivers/net/wireless/ath/ath9k/antenna.c
+ create mode 100644 drivers/net/wireless/ath/ath9k/link.c
+ create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
+ create mode 100644 drivers/net/wireless/iwlwifi/dvm/Makefile
+ rename drivers/net/wireless/iwlwifi/{iwl-agn.h => dvm/agn.h} (80%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-calib.c => dvm/calib.c} (98%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-calib.h => dvm/calib.h} (98%)
+ rename drivers/net/wireless/iwlwifi/{iwl-commands.h => dvm/commands.h} (99%)
+ rename drivers/net/wireless/iwlwifi/{iwl-debugfs.c => dvm/debugfs.c} (99%)
+ rename drivers/net/wireless/iwlwifi/{iwl-dev.h => dvm/dev.h} (83%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-devices.c => dvm/devices.c} (78%)
+ rename drivers/net/wireless/iwlwifi/{iwl-led.c => dvm/led.c} (99%)
+ rename drivers/net/wireless/iwlwifi/{iwl-led.h => dvm/led.h} (100%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-lib.c => dvm/lib.c} (98%)
+ rename drivers/net/wireless/iwlwifi/{iwl-mac80211.c => dvm/mac80211.c} (92%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn.c => dvm/main.c} (86%)
+ rename drivers/net/wireless/iwlwifi/{iwl-power.c => dvm/power.c} (99%)
+ rename drivers/net/wireless/iwlwifi/{iwl-power.h => dvm/power.h} (98%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-rs.c => dvm/rs.c} (98%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-rs.h => dvm/rs.h} (99%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-rx.c => dvm/rx.c} (97%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-rxon.c => dvm/rxon.c} (97%)
+ rename drivers/net/wireless/iwlwifi/{iwl-scan.c => dvm/scan.c} (94%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-sta.c => dvm/sta.c} (97%)
+ create mode 100644 drivers/net/wireless/iwlwifi/dvm/testmode.c
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-tt.c => dvm/tt.c} (99%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-tt.h => dvm/tt.h} (99%)
+ rename drivers/net/wireless/iwlwifi/{iwl-agn-tx.c => dvm/tx.c} (96%)
+ rename drivers/net/wireless/iwlwifi/{iwl-ucode.c => dvm/ucode.c} (93%)
+ create mode 100644 drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
+ create mode 100644 drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
+ create mode 100644 drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
+ create mode 100644 drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
+ delete mode 100644 drivers/net/wireless/iwlwifi/iwl-eeprom.c
+ delete mode 100644 drivers/net/wireless/iwlwifi/iwl-eeprom.h
+ create mode 100644 drivers/net/wireless/iwlwifi/iwl-test.c
+ create mode 100644 drivers/net/wireless/iwlwifi/iwl-test.h
+ delete mode 100644 drivers/net/wireless/iwlwifi/iwl-testmode.c
+ rename drivers/net/wireless/iwlwifi/{iwl-1000.c => pcie/1000.c} (89%)
+ rename drivers/net/wireless/iwlwifi/{iwl-2000.c => pcie/2000.c} (92%)
+ rename drivers/net/wireless/iwlwifi/{iwl-5000.c => pcie/5000.c} (90%)
+ rename drivers/net/wireless/iwlwifi/{iwl-6000.c => pcie/6000.c} (93%)
+ rename drivers/net/wireless/iwlwifi/{iwl-cfg.h => pcie/cfg.h} (100%)
+ rename drivers/net/wireless/iwlwifi/{iwl-pci.c => pcie/drv.c} (99%)
+ rename drivers/net/wireless/iwlwifi/{iwl-trans-pcie-int.h => pcie/internal.h} (95%)
+ rename drivers/net/wireless/iwlwifi/{iwl-trans-pcie-rx.c => pcie/rx.c} (96%)
+ rename drivers/net/wireless/iwlwifi/{iwl-trans-pcie.c => pcie/trans.c} (89%)
+ rename drivers/net/wireless/iwlwifi/{iwl-trans-pcie-tx.c => pcie/tx.c} (84%)
+ create mode 100644 drivers/net/wireless/ti/wl12xx/debugfs.c
+ create mode 100644 drivers/net/wireless/ti/wl12xx/debugfs.h
+ create mode 100644 drivers/net/wireless/ti/wl18xx/Kconfig
+ create mode 100644 drivers/net/wireless/ti/wl18xx/Makefile
+ create mode 100644 drivers/net/wireless/ti/wl18xx/acx.c
+ create mode 100644 drivers/net/wireless/ti/wl18xx/acx.h
+ create mode 100644 drivers/net/wireless/ti/wl18xx/conf.h
+ create mode 100644 drivers/net/wireless/ti/wl18xx/debugfs.c
+ create mode 100644 drivers/net/wireless/ti/wl18xx/debugfs.h
+ create mode 100644 drivers/net/wireless/ti/wl18xx/io.c
+ create mode 100644 drivers/net/wireless/ti/wl18xx/io.h
+ create mode 100644 drivers/net/wireless/ti/wl18xx/main.c
+ create mode 100644 drivers/net/wireless/ti/wl18xx/reg.h
+ create mode 100644 drivers/net/wireless/ti/wl18xx/tx.c
+ create mode 100644 drivers/net/wireless/ti/wl18xx/tx.h
+ create mode 100644 drivers/net/wireless/ti/wl18xx/wl18xx.h
+ rename drivers/net/wireless/ti/wlcore/{wl12xx.h => wlcore_i.h} (95%)
+ create mode 100644 include/linux/ks8851_mll.h
+ create mode 100644 include/linux/netfilter/nfnetlink_cthelper.h
+ delete mode 100644 include/linux/netfilter_ipv4/ipt_addrtype.h
+ create mode 100644 include/net/bluetooth/a2mp.h
+ create mode 100644 include/net/netfilter/nfnetlink_queue.h
+ create mode 100644 net/bluetooth/a2mp.c
+ delete mode 100644 net/mac80211/work.c
+ create mode 100644 net/netfilter/nfnetlink_cthelper.c
+ rename net/netfilter/{nfnetlink_queue.c => nfnetlink_queue_core.c} (93%)
+ create mode 100644 net/netfilter/nfnetlink_queue_ct.c
+Merging wireless-next/master (6bcfe67 ath9k_htc: Fix IDLE power save)
+$ git merge wireless-next/master
+Auto-merging net/mac80211/trace.h
+Auto-merging net/mac80211/mlme.c
+Removing net/mac80211/driver-trace.c
+Auto-merging drivers/net/wireless/ti/wlcore/tx.c
+Auto-merging drivers/net/wireless/rtlwifi/pci.c
+Auto-merging drivers/net/wireless/rtlwifi/cam.c
+Auto-merging drivers/net/wireless/mwifiex/cfg80211.c
+Auto-merging drivers/net/wireless/iwlwifi/pcie/trans.c
+Auto-merging drivers/net/wireless/iwlwifi/dvm/mac80211.c
+Auto-merging drivers/net/wireless/brcm80211/brcmsmac/main.c
+Auto-merging drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+Auto-merging drivers/net/wireless/ath/ath9k/xmit.c
+Auto-merging drivers/net/wireless/ath/ath9k/htc_drv_main.c
+Auto-merging drivers/net/wireless/ath/ath9k/ath9k.h
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS                                        |    1 +
+ drivers/net/wireless/ath/ath6kl/cfg80211.c         |  208 +++-
+ drivers/net/wireless/ath/ath6kl/cfg80211.h         |    2 +
+ drivers/net/wireless/ath/ath6kl/core.h             |   38 +-
+ drivers/net/wireless/ath/ath6kl/htc_mbox.c         |    2 +-
+ drivers/net/wireless/ath/ath6kl/init.c             |   28 +-
+ drivers/net/wireless/ath/ath6kl/main.c             |   27 +-
+ drivers/net/wireless/ath/ath6kl/target.h           |    1 +
+ drivers/net/wireless/ath/ath6kl/txrx.c             |   48 +-
+ drivers/net/wireless/ath/ath6kl/wmi.c              |  148 ++-
+ drivers/net/wireless/ath/ath6kl/wmi.h              |   58 +-
+ drivers/net/wireless/ath/ath9k/ani.c               |  464 +-------
+ drivers/net/wireless/ath/ath9k/ani.h               |   31 +-
+ drivers/net/wireless/ath/ath9k/ar5008_phy.c        |  176 +--
+ drivers/net/wireless/ath/ath9k/ar9002_hw.c         |    4 -
+ drivers/net/wireless/ath/ath9k/ar9003_mci.c        |   21 +-
+ drivers/net/wireless/ath/ath9k/ar9003_phy.c        |   44 +-
+ .../net/wireless/ath/ath9k/ar9462_2p0_initvals.h   |    2 +-
+ drivers/net/wireless/ath/ath9k/ath9k.h             |    1 +
+ drivers/net/wireless/ath/ath9k/debug.c             |    2 -
+ drivers/net/wireless/ath/ath9k/htc.h               |    4 +-
+ drivers/net/wireless/ath/ath9k/htc_drv_beacon.c    |   10 +-
+ drivers/net/wireless/ath/ath9k/htc_drv_gpio.c      |  122 +-
+ drivers/net/wireless/ath/ath9k/htc_drv_init.c      |    4 +-
+ drivers/net/wireless/ath/ath9k/htc_drv_main.c      |   78 +-
+ drivers/net/wireless/ath/ath9k/htc_drv_txrx.c      |    2 +-
+ drivers/net/wireless/ath/ath9k/hw.h                |   13 +-
+ drivers/net/wireless/ath/ath9k/link.c              |    2 +-
+ drivers/net/wireless/ath/ath9k/main.c              |   38 +-
+ drivers/net/wireless/ath/ath9k/mci.c               |   15 +-
+ drivers/net/wireless/ath/ath9k/reg.h               |    4 -
+ drivers/net/wireless/ath/ath9k/xmit.c              |   12 +
+ drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c |  333 +++++-
+ drivers/net/wireless/brcm80211/brcmsmac/channel.c  | 1226 ++++----------------
+ drivers/net/wireless/brcm80211/brcmsmac/channel.h  |    4 +-
+ .../net/wireless/brcm80211/brcmsmac/mac80211_if.c  |    2 +
+ drivers/net/wireless/brcm80211/brcmsmac/main.c     |   36 +-
+ drivers/net/wireless/iwlwifi/dvm/agn.h             |    2 +-
+ drivers/net/wireless/iwlwifi/dvm/dev.h             |    2 -
+ drivers/net/wireless/iwlwifi/dvm/devices.c         |   13 -
+ drivers/net/wireless/iwlwifi/dvm/lib.c             |    2 +-
+ drivers/net/wireless/iwlwifi/dvm/mac80211.c        |   55 +-
+ drivers/net/wireless/iwlwifi/dvm/main.c            |   29 +-
+ drivers/net/wireless/iwlwifi/dvm/scan.c            |   47 +-
+ drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c    |    3 +
+ drivers/net/wireless/iwlwifi/iwl-notif-wait.c      |    5 +-
+ drivers/net/wireless/iwlwifi/iwl-op-mode.h         |   16 +-
+ drivers/net/wireless/iwlwifi/pcie/rx.c             |   30 +-
+ drivers/net/wireless/iwlwifi/pcie/trans.c          |   19 +-
+ drivers/net/wireless/mac80211_hwsim.c              |   10 +-
+ drivers/net/wireless/mwifiex/cfg80211.c            |   55 +-
+ drivers/net/wireless/mwifiex/cmdevt.c              |    6 +-
+ drivers/net/wireless/mwifiex/fw.h                  |   14 +
+ drivers/net/wireless/mwifiex/ie.c                  |   55 +-
+ drivers/net/wireless/mwifiex/init.c                |    1 +
+ drivers/net/wireless/mwifiex/ioctl.h               |   10 +
+ drivers/net/wireless/mwifiex/main.c                |    3 +-
+ drivers/net/wireless/mwifiex/main.h                |    4 +-
+ drivers/net/wireless/mwifiex/uap_cmd.c             |  303 +++--
+ drivers/net/wireless/rt2x00/Kconfig                |    8 +
+ drivers/net/wireless/rt2x00/rt2800.h               |  173 ++-
+ drivers/net/wireless/rt2x00/rt2800lib.c            |  350 +++++-
+ drivers/net/wireless/rt2x00/rt2800pci.c            |   82 +-
+ drivers/net/wireless/rt2x00/rt2800pci.h            |    1 +
+ drivers/net/wireless/rt2x00/rt2800usb.c            |    1 +
+ drivers/net/wireless/rt2x00/rt2x00.h               |    1 +
+ drivers/net/wireless/rt2x00/rt2x00pci.c            |    9 +
+ drivers/net/wireless/rtl818x/rtl8180/dev.c         |    2 +
+ drivers/net/wireless/rtlwifi/cam.c                 |    5 +-
+ drivers/net/wireless/rtlwifi/pci.c                 |   17 +-
+ drivers/net/wireless/rtlwifi/rtl8192se/phy.c       |    3 +
+ drivers/net/wireless/rtlwifi/rtl8192se/sw.c        |    1 -
+ drivers/net/wireless/ti/wl1251/cmd.c               |    9 -
+ drivers/net/wireless/ti/wl1251/main.c              |   67 +-
+ drivers/net/wireless/ti/wl1251/wl1251.h            |    1 -
+ drivers/net/wireless/ti/wl12xx/cmd.c               |   16 +-
+ drivers/net/wireless/ti/wl12xx/main.c              |    7 +-
+ drivers/net/wireless/ti/wl18xx/main.c              |  105 +-
+ drivers/net/wireless/ti/wlcore/acx.c               |    8 +-
+ drivers/net/wireless/ti/wlcore/acx.h               |    5 +
+ drivers/net/wireless/ti/wlcore/cmd.h               |   21 +
+ drivers/net/wireless/ti/wlcore/conf.h              |    8 +-
+ drivers/net/wireless/ti/wlcore/debugfs.c           |   63 +
+ drivers/net/wireless/ti/wlcore/ini.h               |   22 +-
+ drivers/net/wireless/ti/wlcore/init.c              |   43 +-
+ drivers/net/wireless/ti/wlcore/main.c              |   97 +-
+ drivers/net/wireless/ti/wlcore/ps.c                |    2 +-
+ drivers/net/wireless/ti/wlcore/rx.c                |    4 +-
+ drivers/net/wireless/ti/wlcore/rx.h                |    6 +
+ drivers/net/wireless/ti/wlcore/testmode.c          |   14 +
+ drivers/net/wireless/ti/wlcore/tx.c                |   10 +-
+ drivers/net/wireless/ti/wlcore/wlcore.h            |   10 +
+ include/linux/ieee80211.h                          |   52 +-
+ include/linux/nl80211.h                            |  156 ++-
+ include/net/cfg80211.h                             |   94 +-
+ include/net/mac80211.h                             |   29 +-
+ net/mac80211/Kconfig                               |   56 +-
+ net/mac80211/Makefile                              |    6 +-
+ net/mac80211/agg-rx.c                              |   34 +-
+ net/mac80211/agg-tx.c                              |   72 +-
+ net/mac80211/cfg.c                                 |  105 +-
+ net/mac80211/debug.h                               |  170 +++
+ net/mac80211/debugfs_netdev.c                      |   48 +-
+ net/mac80211/driver-ops.h                          |   17 +-
+ net/mac80211/driver-trace.c                        |    9 -
+ net/mac80211/ht.c                                  |   10 +-
+ net/mac80211/ibss.c                                |   91 +-
+ net/mac80211/ieee80211_i.h                         |   20 +-
+ net/mac80211/iface.c                               |   23 +-
+ net/mac80211/key.c                                 |    4 +-
+ net/mac80211/main.c                                |   11 +-
+ net/mac80211/mesh.c                                |   16 +-
+ net/mac80211/mesh.h                                |    4 +-
+ net/mac80211/mesh_hwmp.c                           |  166 ++-
+ net/mac80211/mesh_pathtbl.c                        |   30 +-
+ net/mac80211/mesh_plink.c                          |   61 +-
+ net/mac80211/mesh_sync.c                           |   47 +-
+ net/mac80211/mlme.c                                |  219 ++--
+ net/mac80211/offchannel.c                          |   21 +-
+ net/mac80211/pm.c                                  |   10 +
+ net/mac80211/rx.c                                  |   77 +-
+ net/mac80211/sta_info.c                            |   44 +-
+ net/mac80211/status.c                              |   11 +-
+ net/mac80211/tkip.c                                |   43 +-
+ net/mac80211/trace.c                               |   75 ++
+ net/mac80211/{driver-trace.h => trace.h}           |   67 +-
+ net/mac80211/tx.c                                  |   49 +-
+ net/mac80211/util.c                                |    3 +
+ net/mac80211/wme.c                                 |   11 +-
+ net/mac80211/wme.h                                 |    2 +-
+ net/wireless/core.c                                |   63 -
+ net/wireless/core.h                                |   26 -
+ net/wireless/mesh.c                                |    6 +
+ net/wireless/nl80211.c                             |  282 +++--
+ 134 files changed, 4128 insertions(+), 3278 deletions(-)
+ create mode 100644 net/mac80211/debug.h
+ delete mode 100644 net/mac80211/driver-trace.c
+ create mode 100644 net/mac80211/trace.c
+ rename net/mac80211/{driver-trace.h => trace.h} (96%)
+Merging bluetooth/master (b82c29d Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth)
+$ git merge bluetooth/master
+Merge made by the 'recursive' strategy.
+ include/net/bluetooth/hci.h      |   11 +++---
+ include/net/bluetooth/hci_core.h |    2 +-
+ include/net/bluetooth/mgmt.h     |    2 +-
+ net/bluetooth/hci_core.c         |   69 ++++++++++++++++++--------------------
+ net/bluetooth/mgmt.c             |   21 ++++++------
+ 5 files changed, 51 insertions(+), 54 deletions(-)
+Merging mtd/master (ea3b2ea mtd: nand: initialize bitflip_threshold prior to BBT scanning)
+$ git merge mtd/master
+Merge made by the 'recursive' strategy.
+ drivers/mtd/nand/nand_base.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+Merging l2-mtd/master (b27ebae mtd: m25p80: Add support for n25q064)
+$ git merge l2-mtd/master
+Auto-merging drivers/mtd/nand/nand_base.c
+Auto-merging drivers/mtd/mtdoops.c
+Auto-merging arch/arm/mach-imx/clk-imx51-imx53.c
+Merge made by the 'recursive' strategy.
+ Documentation/ABI/testing/sysfs-class-mtd          |   17 +-
+ Documentation/DocBook/mtdnand.tmpl                 |    2 -
+ .../devicetree/bindings/mtd/lpc32xx-slc.txt        |   52 +
+ arch/arm/boot/dts/imx51.dtsi                       |    7 +
+ arch/arm/boot/dts/imx53.dtsi                       |    7 +
+ arch/arm/mach-imx/clk-imx51-imx53.c                |    2 +
+ arch/arm/plat-mxc/devices/platform-mxc_nand.c      |   11 +-
+ drivers/mtd/devices/m25p80.c                       |    3 +
+ drivers/mtd/maps/Kconfig                           |    2 +-
+ drivers/mtd/maps/uclinux.c                         |   37 +-
+ drivers/mtd/mtdoops.c                              |   14 +-
+ drivers/mtd/nand/Kconfig                           |   11 +
+ drivers/mtd/nand/Makefile                          |    1 +
+ drivers/mtd/nand/cafe_nand.c                       |    4 +-
+ drivers/mtd/nand/fsl_elbc_nand.c                   |   11 +-
+ drivers/mtd/nand/fsl_ifc_nand.c                    |    1 -
+ drivers/mtd/nand/gpmi-nand/gpmi-nand.c             |    3 +
+ drivers/mtd/nand/lpc32xx_slc.c                     | 1060 ++++++++++++++++++++
+ drivers/mtd/nand/mxc_nand.c                        |  141 +--
+ drivers/mtd/nand/nand_base.c                       |   17 -
+ drivers/mtd/nand/nand_bbt.c                        |    2 +-
+ drivers/mtd/nand/nand_ids.c                        |    5 +-
+ drivers/mtd/nand/nandsim.c                         |   12 +-
+ drivers/mtd/nand/pxa3xx_nand.c                     |    1 -
+ drivers/mtd/nand/sh_flctl.c                        |  299 +++---
+ drivers/mtd/tests/mtd_speedtest.c                  |   16 +-
+ drivers/mtd/tests/mtd_stresstest.c                 |   39 +-
+ include/linux/mtd/bbm.h                            |    2 -
+ include/linux/mtd/nand.h                           |    7 +-
+ include/linux/mtd/sh_flctl.h                       |   23 +-
+ 30 files changed, 1471 insertions(+), 338 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
+ create mode 100644 drivers/mtd/nand/lpc32xx_slc.c
+Merging crypto/master (3987103 crypto: algapi - Move larval completion into algboss)
+$ git merge crypto/master
+Auto-merging arch/x86/include/asm/serpent-sse2.h
+Removing arch/s390/crypto/crypto_des.h
+Merge made by the 'recursive' strategy.
+ arch/s390/crypto/crypto_des.h                      |   18 -
+ arch/x86/crypto/Makefile                           |   11 +-
+ arch/x86/crypto/serpent-avx-x86_64-asm_64.S        |  704 +++++++++++++
+ arch/x86/crypto/serpent_avx_glue.c                 |  949 +++++++++++++++++
+ arch/x86/crypto/serpent_sse2_glue.c                |    2 +-
+ arch/x86/crypto/sha1_ssse3_asm.S                   |    2 +-
+ arch/x86/crypto/sha1_ssse3_glue.c                  |    6 +-
+ arch/x86/crypto/twofish-avx-x86_64-asm_64.S        |  301 ++++++
+ arch/x86/crypto/twofish_avx_glue.c                 | 1086 ++++++++++++++++++++
+ arch/x86/crypto/twofish_glue_3way.c                |    2 +
+ arch/x86/include/asm/serpent-avx.h                 |   32 +
+ arch/x86/include/asm/{serpent.h => serpent-sse2.h} |    4 +-
+ crypto/Kconfig                                     |   44 +
+ crypto/algapi.c                                    |   17 -
+ crypto/algboss.c                                   |   17 +-
+ crypto/arc4.c                                      |  115 ++-
+ crypto/internal.h                                  |    1 -
+ crypto/tcrypt.c                                    |   36 +
+ crypto/testmgr.c                                   |  129 +++
+ crypto/testmgr.h                                   | 1018 +++++++++++++++++-
+ drivers/crypto/Kconfig                             |    7 +
+ drivers/crypto/Makefile                            |    3 +-
+ drivers/crypto/bfin_crc.c                          |  780 ++++++++++++++
+ drivers/crypto/mv_cesa.c                           |   61 +-
+ 24 files changed, 5213 insertions(+), 132 deletions(-)
+ delete mode 100644 arch/s390/crypto/crypto_des.h
+ create mode 100644 arch/x86/crypto/serpent-avx-x86_64-asm_64.S
+ create mode 100644 arch/x86/crypto/serpent_avx_glue.c
+ create mode 100644 arch/x86/crypto/twofish-avx-x86_64-asm_64.S
+ create mode 100644 arch/x86/crypto/twofish_avx_glue.c
+ create mode 100644 arch/x86/include/asm/serpent-avx.h
+ rename arch/x86/include/asm/{serpent.h => serpent-sse2.h} (95%)
+ create mode 100644 drivers/crypto/bfin_crc.c
+Merging drm/drm-next (9c19415 Merge tag 'drm-intel-next-2012-06-04' of git://people.freedesktop.org/~danvet/drm-intel into drm-core-next)
+$ git merge drm/drm-next
+Merge made by the 'recursive' strategy.
+ drivers/gpu/drm/i915/i915_debugfs.c     |   66 +++++++
+ drivers/gpu/drm/i915/i915_dma.c         |    1 +
+ drivers/gpu/drm/i915/i915_drv.h         |   11 +-
+ drivers/gpu/drm/i915/i915_gem.c         |  242 +++++++++++++++++++----
+ drivers/gpu/drm/i915/i915_irq.c         |  171 ++++++++++++-----
+ drivers/gpu/drm/i915/i915_reg.h         |   56 +++++-
+ drivers/gpu/drm/i915/i915_sysfs.c       |  127 +++++++++++-
+ drivers/gpu/drm/i915/i915_trace.h       |   28 ++-
+ drivers/gpu/drm/i915/intel_ddi.c        |    3 +-
+ drivers/gpu/drm/i915/intel_display.c    |   47 ++---
+ drivers/gpu/drm/i915/intel_dp.c         |   53 +++---
+ drivers/gpu/drm/i915/intel_drv.h        |    9 +-
+ drivers/gpu/drm/i915/intel_hdmi.c       |  318 +++++++++++++++++++++++++------
+ drivers/gpu/drm/i915/intel_overlay.c    |    4 +-
+ drivers/gpu/drm/i915/intel_panel.c      |    2 +-
+ drivers/gpu/drm/i915/intel_ringbuffer.c |   16 +-
+ drivers/gpu/drm/i915/intel_sdvo.c       |   56 ++++--
+ include/drm/i915_drm.h                  |   10 +
+ 18 files changed, 965 insertions(+), 255 deletions(-)
+Merging sound/for-next (df8b79c Merge branch 'fix/hda' into for-next)
+$ git merge sound/for-next
+Removing include/linux/ac97_codec.h
+Merge made by the 'recursive' strategy.
+ Documentation/sound/alsa/HD-Audio-Models.txt |   10 +-
+ include/linux/ac97_codec.h                   |  362 --------------------------
+ include/sound/pcm.h                          |    1 +
+ include/sound/pcm_params.h                   |    2 +
+ sound/core/pcm_misc.c                        |   18 ++
+ sound/isa/opti9xx/opti92x-ad1848.c           |   17 +-
+ sound/oss/swarm_cs4297a.c                    |   17 +-
+ sound/pci/au88x0/au88x0_mixer.c              |   11 +
+ sound/pci/hda/hda_codec.c                    |   47 +++-
+ sound/pci/hda/hda_codec.h                    |    3 +
+ sound/pci/hda/hda_intel.c                    |   15 +-
+ sound/pci/hda/hda_jack.c                     |   59 +++--
+ sound/pci/hda/hda_jack.h                     |    1 +
+ sound/pci/hda/hda_proc.c                     |   17 +-
+ sound/pci/hda/patch_hdmi.c                   |  294 +++++++++++----------
+ sound/pci/hda/patch_realtek.c                |  191 +++++++++++++-
+ sound/pci/maestro3.c                         |   68 -----
+ sound/pci/pcxhr/pcxhr.c                      |   63 +++++
+ sound/pci/pcxhr/pcxhr.h                      |    1 +
+ sound/pci/pcxhr/pcxhr_core.c                 |   27 +-
+ sound/pci/pcxhr/pcxhr_core.h                 |    4 +-
+ sound/pci/pcxhr/pcxhr_mix22.c                |   11 +
+ sound/pci/pcxhr/pcxhr_mix22.h                |    1 +
+ sound/usb/mixer_quirks.c                     |  159 +++++++----
+ 24 files changed, 710 insertions(+), 689 deletions(-)
+ delete mode 100644 include/linux/ac97_codec.h
+Merging sound-asoc/for-next (747706d Merge branch 'for-3.6' into asoc-next)
+$ git merge sound-asoc/for-next
+Auto-merging sound/soc/codecs/wm8994.c
+Auto-merging include/sound/pcm.h
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS                             |    2 +
+ arch/arm/mach-ux500/board-mop500.c      |   14 +
+ include/linux/mfd/abx500/ab8500-codec.h |   52 +
+ include/linux/mfd/abx500/ab8500.h       |    2 +
+ include/linux/platform_data/mmp_audio.h |   22 +
+ include/sound/designware_i2s.h          |   69 +
+ include/sound/dmaengine_pcm.h           |    1 +
+ include/sound/pcm.h                     |   11 +
+ include/sound/soc-dapm.h                |   10 +
+ include/sound/soc.h                     |   77 +-
+ include/sound/spear_dma.h               |   35 +
+ include/sound/spear_spdif.h             |   29 +
+ sound/soc/Kconfig                       |    1 +
+ sound/soc/Makefile                      |    1 +
+ sound/soc/blackfin/Kconfig              |   21 +-
+ sound/soc/blackfin/Makefile             |    4 +
+ sound/soc/blackfin/bf6xx-i2s.c          |  234 +++
+ sound/soc/blackfin/bf6xx-sport.c        |  422 ++++++
+ sound/soc/blackfin/bf6xx-sport.h        |   82 +
+ sound/soc/codecs/Kconfig                |   21 +
+ sound/soc/codecs/Makefile               |   10 +
+ sound/soc/codecs/ab8500-codec.c         | 2522 +++++++++++++++++++++++++++++++
+ sound/soc/codecs/ab8500-codec.h         |  590 ++++++++
+ sound/soc/codecs/ac97.c                 |    6 -
+ sound/soc/codecs/arizona.c              |  781 ++++++++++
+ sound/soc/codecs/arizona.h              |  149 ++
+ sound/soc/codecs/cs42l52.c              |   19 +-
+ sound/soc/codecs/cs42l73.c              |   20 +-
+ sound/soc/codecs/da732x.c               | 1627 ++++++++++++++++++++
+ sound/soc/codecs/da732x.h               |  133 ++
+ sound/soc/codecs/da732x_reg.h           |  654 ++++++++
+ sound/soc/codecs/isabelle.c             | 1176 ++++++++++++++
+ sound/soc/codecs/isabelle.h             |  143 ++
+ sound/soc/codecs/lm49453.c              |    3 +-
+ sound/soc/codecs/max98095.c             |    5 +-
+ sound/soc/codecs/ml26124.c              |    5 +-
+ sound/soc/codecs/tlv320aic3x.c          |    2 +-
+ sound/soc/codecs/wm2000.c               |   32 +-
+ sound/soc/codecs/wm2200.c               |    1 +
+ sound/soc/codecs/wm5100-tables.c        |    2 +-
+ sound/soc/codecs/wm5100.c               |   11 +-
+ sound/soc/codecs/wm5102.c               |  870 +++++++++++
+ sound/soc/codecs/wm5102.h               |   21 +
+ sound/soc/codecs/wm8350.c               |   22 +-
+ sound/soc/codecs/wm8400.c               |    2 +-
+ sound/soc/codecs/wm8580.c               |    2 +-
+ sound/soc/codecs/wm8731.c               |    1 +
+ sound/soc/codecs/wm8741.c               |    2 +-
+ sound/soc/codecs/wm8753.c               |    2 +-
+ sound/soc/codecs/wm8776.c               |    2 +-
+ sound/soc/codecs/wm8804.c               |    2 +-
+ sound/soc/codecs/wm8903.c               |  316 ++--
+ sound/soc/codecs/wm8904.c               |  272 ++--
+ sound/soc/codecs/wm8960.c               |    2 +
+ sound/soc/codecs/wm8961.c               |    2 +
+ sound/soc/codecs/wm8962.c               |    2 +-
+ sound/soc/codecs/wm8993.c               |    2 +-
+ sound/soc/codecs/wm8994.c               |    2 +-
+ sound/soc/codecs/wm8996.c               |  587 +++----
+ sound/soc/codecs/wm9081.c               |    2 +-
+ sound/soc/codecs/wm9090.c               |    2 +-
+ sound/soc/codecs/wm9712.c               |    2 +-
+ sound/soc/codecs/wm9713.c               |    2 +-
+ sound/soc/codecs/wm_hubs.c              |    2 +-
+ sound/soc/dwc/Kconfig                   |    9 +
+ sound/soc/dwc/Makefile                  |    3 +
+ sound/soc/dwc/designware_i2s.c          |  454 ++++++
+ sound/soc/ep93xx/ep93xx-pcm.c           |    2 +-
+ sound/soc/fsl/imx-pcm-dma.c             |    2 +-
+ sound/soc/mxs/mxs-pcm.c                 |    2 +-
+ sound/soc/mxs/mxs-sgtl5000.c            |    2 +-
+ sound/soc/pxa/Kconfig                   |   42 +
+ sound/soc/pxa/Makefile                  |    8 +
+ sound/soc/pxa/brownstone.c              |  174 +++
+ sound/soc/pxa/mmp-pcm.c                 |  297 ++++
+ sound/soc/pxa/mmp-sspa.c                |  480 ++++++
+ sound/soc/pxa/mmp-sspa.h                |   92 ++
+ sound/soc/pxa/ttc-dkb.c                 |  173 +++
+ sound/soc/sh/fsi.c                      |   48 +-
+ sound/soc/soc-core.c                    |  322 +++-
+ sound/soc/soc-dapm.c                    |   60 +-
+ sound/soc/soc-dmaengine-pcm.c           |   33 +-
+ sound/soc/soc-io.c                      |   15 +-
+ sound/soc/spear/spdif_in.c              |  297 ++++
+ sound/soc/spear/spdif_in_regs.h         |   60 +
+ sound/soc/spear/spear_pcm.c             |  214 +++
+ sound/soc/tegra/tegra20_i2s.c           |   94 +-
+ sound/soc/tegra/tegra20_i2s.h           |    1 -
+ sound/soc/tegra/tegra20_spdif.c         |   36 +-
+ sound/soc/tegra/tegra20_spdif.h         |    1 -
+ sound/soc/tegra/tegra30_i2s.c           |   85 +-
+ sound/soc/tegra/tegra30_i2s.h           |    1 -
+ sound/soc/tegra/tegra_alc5632.c         |   32 +-
+ sound/soc/tegra/tegra_wm8753.c          |    8 +-
+ sound/soc/tegra/tegra_wm8903.c          |  259 ++--
+ sound/soc/tegra/trimslice.c             |   30 +-
+ sound/soc/ux500/Kconfig                 |   18 +
+ sound/soc/ux500/Makefile                |    6 +
+ sound/soc/ux500/mop500.c                |  113 ++
+ sound/soc/ux500/mop500_ab8500.c         |  431 ++++++
+ sound/soc/ux500/mop500_ab8500.h         |   22 +
+ sound/soc/ux500/ux500_msp_dai.c         |    2 +-
+ sound/soc/ux500/ux500_msp_i2s.c         |    2 +-
+ sound/soc/ux500/ux500_pcm.c             |  318 ++++
+ sound/soc/ux500/ux500_pcm.h             |   35 +
+ 105 files changed, 14172 insertions(+), 1233 deletions(-)
+ create mode 100644 include/linux/mfd/abx500/ab8500-codec.h
+ create mode 100644 include/linux/platform_data/mmp_audio.h
+ create mode 100644 include/sound/designware_i2s.h
+ create mode 100644 include/sound/spear_dma.h
+ create mode 100644 include/sound/spear_spdif.h
+ create mode 100644 sound/soc/blackfin/bf6xx-i2s.c
+ create mode 100644 sound/soc/blackfin/bf6xx-sport.c
+ create mode 100644 sound/soc/blackfin/bf6xx-sport.h
+ create mode 100644 sound/soc/codecs/ab8500-codec.c
+ create mode 100644 sound/soc/codecs/ab8500-codec.h
+ create mode 100644 sound/soc/codecs/arizona.c
+ create mode 100644 sound/soc/codecs/arizona.h
+ create mode 100644 sound/soc/codecs/da732x.c
+ create mode 100644 sound/soc/codecs/da732x.h
+ create mode 100644 sound/soc/codecs/da732x_reg.h
+ create mode 100644 sound/soc/codecs/isabelle.c
+ create mode 100644 sound/soc/codecs/isabelle.h
+ create mode 100644 sound/soc/codecs/wm5102.c
+ create mode 100644 sound/soc/codecs/wm5102.h
+ create mode 100644 sound/soc/dwc/Kconfig
+ create mode 100644 sound/soc/dwc/Makefile
+ create mode 100644 sound/soc/dwc/designware_i2s.c
+ create mode 100644 sound/soc/pxa/brownstone.c
+ create mode 100644 sound/soc/pxa/mmp-pcm.c
+ create mode 100644 sound/soc/pxa/mmp-sspa.c
+ create mode 100644 sound/soc/pxa/mmp-sspa.h
+ create mode 100644 sound/soc/pxa/ttc-dkb.c
+ create mode 100644 sound/soc/spear/spdif_in.c
+ create mode 100644 sound/soc/spear/spdif_in_regs.h
+ create mode 100644 sound/soc/spear/spear_pcm.c
+ create mode 100644 sound/soc/ux500/mop500.c
+ create mode 100644 sound/soc/ux500/mop500_ab8500.c
+ create mode 100644 sound/soc/ux500/mop500_ab8500.h
+ create mode 100644 sound/soc/ux500/ux500_pcm.c
+ create mode 100644 sound/soc/ux500/ux500_pcm.h
+Merging quilt/rr (231e4d6 Taint kernel when lve module is loaded)
+$ git merge quilt/rr
+Merge made by the 'recursive' strategy.
+ drivers/block/virtio_blk.c          |   25 ++++++-----------------
+ drivers/char/hw_random/virtio-rng.c |   37 ++++++++++++++++++++++++++++++++---
+ include/linux/cpumask.h             |    6 ++++++
+ include/linux/init.h                |    3 ++-
+ include/linux/virtio_ids.h          |    2 +-
+ init/main.c                         |    1 +
+ kernel/module.c                     |    4 ++++
+ 7 files changed, 54 insertions(+), 24 deletions(-)
+Merging input/next (84b63ad Input: nomadik-ske-keypad - get rid of multiple interrupts)
+$ git merge input/next
+Auto-merging drivers/input/tablet/wacom_sys.c
+Removing Documentation/devicetree/bindings/input/twl6040-vibra.txt
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/input/twl6040-vibra.txt    |   37 --------
+ drivers/input/keyboard/gpio_keys.c                 |    1 -
+ drivers/input/keyboard/nomadik-ske-keypad.c        |   76 +++++++++------
+ drivers/input/misc/ab8500-ponkey.c                 |    9 ++
+ drivers/input/misc/twl6040-vibra.c                 |   42 +++++----
+ drivers/input/tablet/wacom_sys.c                   |   99 ++++++++++++--------
+ drivers/input/tablet/wacom_wac.c                   |   21 +++--
+ drivers/input/tablet/wacom_wac.h                   |    8 +-
+ 8 files changed, 160 insertions(+), 133 deletions(-)
+ delete mode 100644 Documentation/devicetree/bindings/input/twl6040-vibra.txt
+Merging input-mt/for-next (27c347d Input: MT - fix null pointer warning)
+$ git merge input-mt/for-next
+Merge made by the 'recursive' strategy.
+ drivers/input/input-mt.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+Merging cgroup/for-next (f9b6023f Merge branch 'for-3.5-fixes' into for-next)
+$ git merge cgroup/for-next
+Auto-merging kernel/cgroup.c
+Merge made by the 'recursive' strategy.
+ Documentation/cgroups/cgroups.txt |    2 +-
+ include/linux/cgroup.h            |   17 ++------------
+ kernel/cgroup.c                   |   45 -------------------------------------
+ 3 files changed, 3 insertions(+), 61 deletions(-)
+Merging block/for-next (f45d342 Merge branch 'for-linus' into for-next)
+$ git merge block/for-next
+Auto-merging net/core/skbuff.c
+Auto-merging mm/shmem.c
+Auto-merging kernel/trace/trace.c
+Merge made by the 'recursive' strategy.
+ Documentation/ABI/testing/sysfs-block-rssd |   21 ----
+ block/blk-cgroup.c                         |    9 +-
+ block/blk-core.c                           |   25 ++++-
+ block/blk-timeout.c                        |   41 -------
+ block/cfq-iosched.c                        |   30 +++--
+ block/scsi_ioctl.c                         |    5 +-
+ drivers/block/drbd/drbd_bitmap.c           |   11 +-
+ drivers/block/drbd/drbd_req.c              |   66 +++++++----
+ drivers/block/mtip32xx/mtip32xx.c          |  166 ++++++++++++++++++++--------
+ drivers/block/mtip32xx/mtip32xx.h          |    5 +-
+ drivers/block/umem.c                       |   40 +++++++
+ drivers/block/xen-blkback/common.h         |    2 +
+ drivers/block/xen-blkfront.c               |   58 ++++++++--
+ fs/splice.c                                |   35 +++---
+ include/linux/blkdev.h                     |    1 -
+ include/linux/splice.h                     |    8 +-
+ kernel/relay.c                             |    5 +-
+ kernel/trace/trace.c                       |    6 +-
+ mm/shmem.c                                 |    3 +-
+ net/core/skbuff.c                          |    1 +
+ 20 files changed, 338 insertions(+), 200 deletions(-)
+Merging quilt/device-mapper (4e66fde dm-thin will be most likely used with a block size that is a power of two. So it should be optimized for this case.)
+$ git merge quilt/device-mapper
+Merge made by the 'recursive' strategy.
+ Documentation/device-mapper/striped.txt            |    7 +-
+ Documentation/device-mapper/verity.txt             |  131 +++++++-------------
+ drivers/md/dm-raid.c                               |   11 +-
+ drivers/md/dm-raid1.c                              |    6 +-
+ drivers/md/dm-snap.c                               |   27 ++--
+ drivers/md/dm-stripe.c                             |   80 +++++++-----
+ drivers/md/dm-thin-metadata.c                      |    2 +-
+ drivers/md/dm-thin-metadata.h                      |    2 +-
+ drivers/md/dm-thin.c                               |   83 +++++++++----
+ drivers/md/dm.c                                    |   35 ++++--
+ drivers/md/persistent-data/dm-space-map-checker.c  |   53 ++++----
+ drivers/md/persistent-data/dm-space-map-disk.c     |   11 +-
+ .../md/persistent-data/dm-transaction-manager.c    |   11 +-
+ include/linux/device-mapper.h                      |    9 +-
+ include/linux/dm-ioctl.h                           |    4 +-
+ 15 files changed, 264 insertions(+), 208 deletions(-)
+Merging embedded/master (4744b43 embedded: fix vc_translate operator precedence)
+$ git merge embedded/master
+Already up-to-date.
+Merging firmware/master (6e03a20 firmware: speed up request_firmware(), v3)
+$ git merge firmware/master
+Already up-to-date.
+Merging pcmcia/master (80af9e6 pcmcia at91_cf: fix raw gpio number usage)
+$ git merge pcmcia/master
+Already up-to-date.
+Merging mmc/mmc-next (ed99260 mmc: tmio: remove a duplicated comment line)
+$ git merge mmc/mmc-next
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/mmc/fsl-esdhc.txt          |   25 ++--
+ .../devicetree/bindings/mmc/fsl-imx-esdhc.txt      |    8 +-
+ .../devicetree/bindings/mmc/mmc-spi-slot.txt       |    8 +-
+ Documentation/devicetree/bindings/mmc/mmc.txt      |   10 +-
+ Documentation/devicetree/bindings/mmc/mmci.txt     |   12 +-
+ Documentation/devicetree/bindings/mmc/mxs-mmc.txt  |    8 +-
+ .../devicetree/bindings/mmc/nvidia-sdhci.txt       |    8 +-
+ .../devicetree/bindings/mmc/sdhci-pxa.txt          |   21 ++++
+ .../devicetree/bindings/mmc/ti-omap-hsmmc.txt      |    7 +-
+ drivers/mmc/card/block.c                           |   50 ++------
+ drivers/mmc/core/core.c                            |   83 ++++++++++----
+ drivers/mmc/core/mmc_ops.c                         |    1 -
+ drivers/mmc/host/dw_mmc.c                          |   17 ++-
+ drivers/mmc/host/omap_hsmmc.c                      |   15 +--
+ drivers/mmc/host/sdhci-pxav2.c                     |   54 +++++++++
+ drivers/mmc/host/sdhci-pxav3.c                     |   52 +++++++++
+ drivers/mmc/host/sh_mmcif.c                        |   14 +--
+ drivers/mmc/host/sh_mobile_sdhi.c                  |   38 +++++--
+ drivers/mmc/host/tmio_mmc_pio.c                    |  119 ++++++++++++++------
+ include/linux/mfd/tmio.h                           |    3 +
+ include/linux/mmc/host.h                           |   16 ++-
+ 21 files changed, 388 insertions(+), 181 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
+Merging kgdb/kgdb-next (3751d3e x86,kgdb: Fix DEBUG_RODATA limitation using text_poke())
+$ git merge kgdb/kgdb-next
+Already up-to-date.
+Merging slab/for-next (43d7786 slub: refactoring unfreeze_partials())
+$ git merge slab/for-next
+Auto-merging mm/mempolicy.c
+Auto-merging include/linux/mm_types.h
+Merge made by the 'recursive' strategy.
+ include/linux/mempolicy.h |    2 +-
+ include/linux/mm_types.h  |   11 +-
+ include/linux/slab.h      |   24 ++++
+ include/linux/slab_def.h  |   10 +-
+ include/linux/slub_def.h  |    3 +-
+ mm/mempolicy.c            |    8 +-
+ mm/slab.c                 |  197 +++++++++++++---------------
+ mm/slob.c                 |  132 ++++++-------------
+ mm/slub.c                 |  315 ++++++++++++++++++++++-----------------------
+ 9 files changed, 326 insertions(+), 376 deletions(-)
+Merging uclinux/for-next (5e442a4 Revert "proc: fix races against execve() of /proc/PID/fd**")
+$ git merge uclinux/for-next
+Already up-to-date.
+Merging md/for-next (aba336b md: raid1/raid10: fix problem with merge_bvec_fn)
+$ git merge md/for-next
+Already up-to-date.
+Merging mfd/for-next (58eec73 mfd: Add Maxim 77686 driver)
+$ git merge mfd/for-next
+Merge made by the 'recursive' strategy.
+ drivers/mfd/Kconfig                  |   13 ++
+ drivers/mfd/Makefile                 |    1 +
+ drivers/mfd/max77686-irq.c           |  309 ++++++++++++++++++++++++++++++++++
+ drivers/mfd/max77686.c               |  156 +++++++++++++++++
+ include/linux/mfd/max77686-private.h |  247 +++++++++++++++++++++++++++
+ include/linux/mfd/max77686.h         |  117 +++++++++++++
+ 6 files changed, 843 insertions(+)
+ create mode 100644 drivers/mfd/max77686-irq.c
+ create mode 100644 drivers/mfd/max77686.c
+ create mode 100644 include/linux/mfd/max77686-private.h
+ create mode 100644 include/linux/mfd/max77686.h
+Merging battery/master (85a392d test_power: Add VOLTAGE_NOW and BATTERY_TEMP properties)
+$ git merge battery/master
+Merge made by the 'recursive' strategy.
+ Documentation/power/power_supply_class.txt |    4 +
+ drivers/mfd/twl-core.c                     |    9 +-
+ drivers/power/bq27x00_battery.c            |   71 ++++++++++++++++
+ drivers/power/ds2781_battery.c             |    2 +-
+ drivers/power/gpio-charger.c               |    2 +-
+ drivers/power/max17042_battery.c           |    8 ++
+ drivers/power/pda_power.c                  |    4 +-
+ drivers/power/power_supply_core.c          |   65 +++++++++++++++
+ drivers/power/power_supply_sysfs.c         |    2 +
+ drivers/power/sbs-battery.c                |    2 +-
+ drivers/power/smb347-charger.c             |  123 ++++++++++++++++++++++++++--
+ drivers/power/test_power.c                 |   75 +++++++++++++++++
+ drivers/power/twl4030_charger.c            |   80 +++++++++++++++++-
+ include/linux/i2c/twl.h                    |    2 +
+ include/linux/power_supply.h               |    7 ++
+ 15 files changed, 438 insertions(+), 18 deletions(-)
+$ git am -3 ../patches/0001-ACPI-Thermal-fix-for-an-API-change.patch
+Applying: ACPI-Thermal: fix for an API change
+$ git reset HEAD^
+Unstaged changes after reset:
+M	drivers/power/power_supply_core.c
+$ git add .
+$ git commit -v -a --amend
+[master aa2807e] Merge remote-tracking branch 'battery/master'
+Merging fbdev/fbdev-next (0f90fa5 Merge branch 'planes' of git://linuxtv.org/pinchartl/fbdev into fbdev-next)
+$ git merge fbdev/fbdev-next
+Removing drivers/video/exynos/s6e8ax0.h
+Merge made by the 'recursive' strategy.
+ .../sysfs-devices-platform-sh_mobile_lcdc_fb       |   44 +
+ drivers/video/exynos/exynos_dp_core.c              |    3 +
+ drivers/video/exynos/exynos_dp_core.h              |    4 -
+ drivers/video/exynos/s6e8ax0.h                     |   21 -
+ drivers/video/sh_mipi_dsi.c                        |    7 +-
+ drivers/video/sh_mobile_lcdcfb.c                   |  982 ++++++++++++++++++--
+ include/video/sh_mobile_lcdc.h                     |    7 +
+ 7 files changed, 943 insertions(+), 125 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-devices-platform-sh_mobile_lcdc_fb
+ delete mode 100644 drivers/video/exynos/s6e8ax0.h
+Merging viafb/viafb-next (838ac78 viafb: avoid refresh and mode lookup in set_par)
+$ git merge viafb/viafb-next
+Already up-to-date.
+Merging omap_dss2/for-next (05dd0f5 OMAPDSS: DISPC: Update Accumulator configuration for chroma plane)
+$ git merge omap_dss2/for-next
+Already up-to-date.
+Merging regulator/for-next (6f3c468 Merge branches 'regulator-drivers' and 'regulator-core' into regulator-next)
+$ git merge regulator/for-next
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/regulator/regulator.txt    |    1 +
+ .../bindings/regulator/twl-regulator.txt           |    1 -
+ drivers/regulator/Kconfig                          |   23 +
+ drivers/regulator/Makefile                         |    3 +
+ drivers/regulator/ab3100.c                         |   74 +-
+ drivers/regulator/ab8500.c                         |   96 +-
+ drivers/regulator/anatop-regulator.c               |   42 +-
+ drivers/regulator/arizona-ldo1.c                   |  134 +++
+ drivers/regulator/arizona-micsupp.c                |  184 ++++
+ drivers/regulator/core.c                           |  182 ++--
+ drivers/regulator/da903x.c                         |    6 +
+ drivers/regulator/fixed-helper.c                   |   19 +-
+ drivers/regulator/fixed.c                          |    4 +-
+ drivers/regulator/isl6271a-regulator.c             |   13 +-
+ drivers/regulator/lp3971.c                         |   66 +-
+ drivers/regulator/lp3972.c                         |  102 +--
+ drivers/regulator/lp872x.c                         |  957 ++++++++++++++++++++
+ drivers/regulator/max1586.c                        |  108 +--
+ drivers/regulator/max77686.c                       |  332 +++++++
+ drivers/regulator/max8998.c                        |  127 +--
+ drivers/regulator/mc13783-regulator.c              |   38 +-
+ drivers/regulator/mc13892-regulator.c              |   43 +-
+ drivers/regulator/mc13xxx-regulator-core.c         |   36 +-
+ drivers/regulator/mc13xxx.h                        |   10 +-
+ drivers/regulator/of_regulator.c                   |    6 +-
+ drivers/regulator/palmas-regulator.c               |   42 +-
+ drivers/regulator/pcap-regulator.c                 |   95 +-
+ drivers/regulator/pcf50633-regulator.c             |   20 +-
+ drivers/regulator/rc5t583-regulator.c              |   24 +-
+ drivers/regulator/s5m8767.c                        |  232 +++--
+ drivers/regulator/tps6105x-regulator.c             |   14 +-
+ drivers/regulator/tps62360-regulator.c             |   20 +-
+ drivers/regulator/tps65023-regulator.c             |  201 ++--
+ drivers/regulator/tps6507x-regulator.c             |   98 +-
+ drivers/regulator/tps65217-regulator.c             |  114 +--
+ drivers/regulator/tps6586x-regulator.c             |   61 +-
+ drivers/regulator/tps65910-regulator.c             |  180 +---
+ drivers/regulator/twl-regulator.c                  |   15 +-
+ drivers/regulator/wm831x-dcdc.c                    |   78 +-
+ drivers/regulator/wm831x-ldo.c                     |  130 +--
+ drivers/regulator/wm8350-regulator.c               |  426 +++------
+ drivers/regulator/wm8400-regulator.c               |   25 +-
+ drivers/regulator/wm8994-regulator.c               |   14 +-
+ include/linux/mfd/s5m87xx/s5m-core.h               |    5 +
+ include/linux/mfd/tps65217.h                       |    6 -
+ include/linux/regulator/consumer.h                 |    2 +-
+ include/linux/regulator/driver.h                   |   13 +
+ include/linux/regulator/fixed.h                    |   11 +-
+ include/linux/regulator/lp872x.h                   |   90 ++
+ include/linux/regulator/machine.h                  |    3 +
+ 50 files changed, 2729 insertions(+), 1797 deletions(-)
+ create mode 100644 drivers/regulator/arizona-ldo1.c
+ create mode 100644 drivers/regulator/arizona-micsupp.c
+ create mode 100644 drivers/regulator/lp872x.c
+ create mode 100644 drivers/regulator/max77686.c
+ create mode 100644 include/linux/regulator/lp872x.h
+Merging security/next (3072928 tpm: check the chip reference before using it)
+$ git merge security/next
+Removing lib/mpi/mpi-scan.c
+Removing lib/mpi/mpi-mul.c
+Removing lib/mpi/mpi-mpow.c
+Removing lib/mpi/mpi-inv.c
+Removing lib/mpi/mpi-inline.c
+Removing lib/mpi/mpi-gcd.c
+Removing lib/mpi/mpi-div.c
+Removing lib/mpi/mpi-cmp.c
+Removing lib/mpi/mpi-add.c
+Removing lib/mpi/generic_mpi-asm-defs.h
+Auto-merging lib/Kconfig
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS                     |    7 +-
+ drivers/char/tpm/tpm.c          |   27 +++-
+ drivers/char/tpm/tpm_infineon.c |    6 +-
+ lib/Kconfig                     |    8 -
+ lib/mpi/Makefile                |   11 --
+ lib/mpi/generic_mpi-asm-defs.h  |    4 -
+ lib/mpi/mpi-add.c               |  234 ---------------------------
+ lib/mpi/mpi-bit.c               |  162 -------------------
+ lib/mpi/mpi-cmp.c               |   68 --------
+ lib/mpi/mpi-div.c               |  338 ---------------------------------------
+ lib/mpi/mpi-gcd.c               |   59 -------
+ lib/mpi/mpi-inline.c            |   31 ----
+ lib/mpi/mpi-inv.c               |  187 ----------------------
+ lib/mpi/mpi-mpow.c              |  134 ----------------
+ lib/mpi/mpi-mul.c               |  194 ----------------------
+ lib/mpi/mpi-scan.c              |  136 ----------------
+ lib/mpi/mpicoder.c              |   75 ---------
+ lib/mpi/mpih-div.c              |  309 -----------------------------------
+ lib/mpi/mpih-mul.c              |   30 ----
+ lib/mpi/mpiutil.c               |   88 ----------
+ security/keys/compat.c          |    4 +-
+ security/keys/internal.h        |    2 +-
+ security/keys/keyctl.c          |    2 +-
+ security/keys/keyring.c         |    2 +
+ 24 files changed, 33 insertions(+), 2085 deletions(-)
+ delete mode 100644 lib/mpi/generic_mpi-asm-defs.h
+ delete mode 100644 lib/mpi/mpi-add.c
+ delete mode 100644 lib/mpi/mpi-cmp.c
+ delete mode 100644 lib/mpi/mpi-div.c
+ delete mode 100644 lib/mpi/mpi-gcd.c
+ delete mode 100644 lib/mpi/mpi-inline.c
+ delete mode 100644 lib/mpi/mpi-inv.c
+ delete mode 100644 lib/mpi/mpi-mpow.c
+ delete mode 100644 lib/mpi/mpi-mul.c
+ delete mode 100644 lib/mpi/mpi-scan.c
+Merging selinux/master (c737f82 SELinux: remove unused common_audit_data in flush_unauthorized_files)
+$ git merge selinux/master
+Already up-to-date.
+Merging lblnet/master (7e27d6e Linux 2.6.35-rc3)
+$ git merge lblnet/master
+Already up-to-date.
+Merging watchdog/master (e68261c char/ipmi: remove local ioctl defines replaced by generic ones)
+$ git merge watchdog/master
+Merge made by the 'recursive' strategy.
+ drivers/char/ipmi/ipmi_watchdog.c |   13 ---
+ drivers/watchdog/coh901327_wdt.c  |    7 +-
+ drivers/watchdog/f71808e_wdt.c    |    4 +-
+ drivers/watchdog/hpwdt.c          |    4 +-
+ drivers/watchdog/iTCO_wdt.c       |  214 +++++++++----------------------------
+ drivers/watchdog/of_xilinx_wdt.c  |    2 +-
+ drivers/watchdog/watchdog_dev.c   |    2 +-
+ 7 files changed, 61 insertions(+), 185 deletions(-)
+Merging dwmw2-iommu/master (c3b92c8 Linux 3.1)
+$ git merge dwmw2-iommu/master
+Already up-to-date.
+Merging iommu/next (af4d900 Merge branches 'iommu/fixes', 'groups' and 'arm/tegra' into next)
+$ git merge iommu/next
+Auto-merging drivers/iommu/intel-iommu.c
+Auto-merging Documentation/kernel-parameters.txt
+Merge made by the 'recursive' strategy.
+ .../ABI/testing/sysfs-kernel-iommu_groups          |   14 +
+ .../bindings/iommu/nvidia,tegra30-smmu.txt         |   21 +
+ Documentation/kernel-parameters.txt                |    1 -
+ arch/ia64/include/asm/iommu.h                      |    2 -
+ arch/ia64/kernel/pci-dma.c                         |    1 -
+ arch/x86/include/asm/iommu.h                       |    1 -
+ arch/x86/kernel/pci-dma.c                          |   11 -
+ drivers/iommu/Kconfig                              |    6 +-
+ drivers/iommu/Makefile                             |    1 +
+ drivers/iommu/amd_iommu.c                          |   79 ++-
+ drivers/iommu/amd_iommu_init.c                     |    4 +-
+ drivers/iommu/intel-iommu.c                        |   89 +--
+ drivers/iommu/iommu.c                              |  578 +++++++++++++++++++-
+ drivers/iommu/of_iommu.c                           |   90 +++
+ drivers/iommu/tegra-smmu.c                         |  191 +++----
+ include/linux/device.h                             |    2 +
+ include/linux/iommu.h                              |  104 +++-
+ include/linux/of_iommu.h                           |   21 +
+ 18 files changed, 1014 insertions(+), 202 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-kernel-iommu_groups
+ create mode 100644 Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
+ create mode 100644 drivers/iommu/of_iommu.c
+ create mode 100644 include/linux/of_iommu.h
+Merging vfio/next (d9016a4 vfio: Add PCI device driver)
+$ git merge vfio/next
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ Documentation/ioctl/ioctl-number.txt |    1 +
+ Documentation/vfio.txt               |  315 +++++++
+ MAINTAINERS                          |    8 +
+ drivers/Kconfig                      |    2 +
+ drivers/Makefile                     |    1 +
+ drivers/vfio/Kconfig                 |   16 +
+ drivers/vfio/Makefile                |    3 +
+ drivers/vfio/pci/Kconfig             |    8 +
+ drivers/vfio/pci/Makefile            |    4 +
+ drivers/vfio/pci/vfio_pci.c          |  565 +++++++++++++
+ drivers/vfio/pci/vfio_pci_config.c   | 1528 ++++++++++++++++++++++++++++++++++
+ drivers/vfio/pci/vfio_pci_intrs.c    |  727 ++++++++++++++++
+ drivers/vfio/pci/vfio_pci_private.h  |   91 ++
+ drivers/vfio/pci/vfio_pci_rdwr.c     |  269 ++++++
+ drivers/vfio/vfio.c                  | 1420 +++++++++++++++++++++++++++++++
+ drivers/vfio/vfio_iommu_type1.c      |  754 +++++++++++++++++
+ include/linux/vfio.h                 |  445 ++++++++++
+ 17 files changed, 6157 insertions(+)
+ create mode 100644 Documentation/vfio.txt
+ create mode 100644 drivers/vfio/Kconfig
+ create mode 100644 drivers/vfio/Makefile
+ create mode 100644 drivers/vfio/pci/Kconfig
+ create mode 100644 drivers/vfio/pci/Makefile
+ create mode 100644 drivers/vfio/pci/vfio_pci.c
+ create mode 100644 drivers/vfio/pci/vfio_pci_config.c
+ create mode 100644 drivers/vfio/pci/vfio_pci_intrs.c
+ create mode 100644 drivers/vfio/pci/vfio_pci_private.h
+ create mode 100644 drivers/vfio/pci/vfio_pci_rdwr.c
+ create mode 100644 drivers/vfio/vfio.c
+ create mode 100644 drivers/vfio/vfio_iommu_type1.c
+ create mode 100644 include/linux/vfio.h
+Merging osd/linux-next (8b56a30 exofs:  Add SYSFS info for autologin/pNFS export)
+$ git merge osd/linux-next
+Already up-to-date.
+Merging jc_docs/docs-next (5c050fb docs: update the development process document)
+$ git merge jc_docs/docs-next
+Already up-to-date.
+Merging trivial/for-next (c224071 parisc: cleanup quoted include)
+$ git merge trivial/for-next
+Auto-merging drivers/parisc/iosapic.c
+Merge made by the 'recursive' strategy.
+ Documentation/devices.txt          |    2 ++
+ drivers/input/misc/cma3000_d0x.c   |    2 +-
+ drivers/parisc/iosapic.c           |    2 +-
+ drivers/usb/renesas_usbhs/common.c |    2 +-
+ drivers/usb/renesas_usbhs/common.h |    4 ++--
+ drivers/usb/renesas_usbhs/fifo.c   |    4 ++--
+ drivers/usb/renesas_usbhs/mod.c    |    4 ++--
+ drivers/usb/renesas_usbhs/mod.h    |    2 +-
+ drivers/usb/renesas_usbhs/pipe.c   |    4 ++--
+ drivers/usb/renesas_usbhs/pipe.h   |    4 ++--
+ sound/oss/vwsnd.c                  |    2 +-
+ 11 files changed, 17 insertions(+), 15 deletions(-)
+Merging audit/for-next (dcd6c92 Linux 3.3-rc1)
+$ git merge audit/for-next
+Already up-to-date.
+Merging pm/linux-next (6f5b7ab PM / ACPI: Fix suspend/resume regression caused by cpuidle cleanup.)
+$ git merge pm/linux-next
+Auto-merging include/linux/cpuidle.h
+Auto-merging drivers/platform/x86/intel_mid_thermal.c
+Merge made by the 'recursive' strategy.
+ Documentation/ABI/testing/sysfs-power    |   13 +++
+ Documentation/power/swsusp.txt           |    5 +
+ drivers/acpi/processor_idle.c            |   32 +++++-
+ drivers/base/power/domain.c              |  165 ++++++++++++++++++++++++++----
+ drivers/base/power/main.c                |   10 +-
+ drivers/cpuidle/driver.c                 |   29 +++++-
+ drivers/platform/x86/acer-wmi.c          |   10 +-
+ drivers/platform/x86/intel_ips.c         |   17 ---
+ drivers/platform/x86/intel_mid_thermal.c |   16 +--
+ drivers/platform/x86/thinkpad_acpi.c     |   23 +++--
+ include/linux/cpuidle.h                  |    6 +-
+ include/linux/pm_domain.h                |   17 +++
+ include/linux/suspend.h                  |    6 ++
+ kernel/power/Kconfig                     |    4 +-
+ kernel/power/hibernate.c                 |   42 ++++++++
+ kernel/power/main.c                      |   45 ++++++++
+ kernel/power/power.h                     |    3 +
+ kernel/power/suspend.c                   |    3 +
+ kernel/power/swap.c                      |   82 ++++++++++-----
+ 19 files changed, 432 insertions(+), 96 deletions(-)
+Merging apm/for-next (f283d22 APM: fix deadlock in APM_IOC_SUSPEND ioctl)
+$ git merge apm/for-next
+Already up-to-date.
+Merging fsnotify/for-next (1aec9c0 inotify: automatically restart syscalls)
+$ git merge fsnotify/for-next
+Auto-merging kernel/audit_watch.c
+Auto-merging include/linux/fsnotify_backend.h
+Auto-merging fs/notify/notification.c
+Merge made by the 'recursive' strategy.
+ fs/notify/dnotify/dnotify.c          |    4 +-
+ fs/notify/fanotify/fanotify.c        |    6 +++
+ fs/notify/fanotify/fanotify_user.c   |   37 +++++++++-----
+ fs/notify/group.c                    |   47 ++++++++++--------
+ fs/notify/inode_mark.c               |   14 ++++--
+ fs/notify/inotify/inotify_fsnotify.c |    4 +-
+ fs/notify/inotify/inotify_user.c     |   34 ++++++-------
+ fs/notify/mark.c                     |   91 +++++++++++++++++++---------------
+ fs/notify/notification.c             |    1 +
+ fs/notify/vfsmount_mark.c            |   14 ++++--
+ include/linux/fsnotify_backend.h     |   31 ++++++++----
+ kernel/audit_tree.c                  |   10 ++--
+ kernel/audit_watch.c                 |    4 +-
+ 13 files changed, 178 insertions(+), 119 deletions(-)
+Merging edac/linux_next (2d9531a Merge branch 'devel' into next)
+$ git merge edac/linux_next
+Merge made by the 'recursive' strategy.
+ Documentation/ABI/testing/sysfs-devices-edac       |  140 ++
+ .../devicetree/bindings/arm/calxeda/l2ecc.txt      |   15 +
+ .../devicetree/bindings/arm/calxeda/mem-ctrlr.txt  |   14 +
+ Documentation/edac.txt                             |  112 +-
+ arch/arm/boot/dts/highbank.dts                     |   12 +
+ drivers/edac/Kconfig                               |   24 +-
+ drivers/edac/Makefile                              |    3 +
+ drivers/edac/amd64_edac.c                          |  376 +++---
+ drivers/edac/amd64_edac.h                          |   29 +-
+ drivers/edac/amd64_edac_dbg.c                      |   89 +-
+ drivers/edac/amd64_edac_inj.c                      |  134 +-
+ drivers/edac/amd76x_edac.c                         |   34 +-
+ drivers/edac/cell_edac.c                           |   28 +-
+ drivers/edac/cpc925_edac.c                         |   96 +-
+ drivers/edac/e752x_edac.c                          |   92 +-
+ drivers/edac/e7xxx_edac.c                          |   89 +-
+ drivers/edac/edac_core.h                           |   39 +-
+ drivers/edac/edac_device.c                         |   47 +-
+ drivers/edac/edac_device_sysfs.c                   |   71 +-
+ drivers/edac/edac_mc.c                             |  395 +++---
+ drivers/edac/edac_mc_sysfs.c                       | 1355 ++++++++++----------
+ drivers/edac/edac_module.c                         |   20 +-
+ drivers/edac/edac_module.h                         |   26 +-
+ drivers/edac/edac_pci.c                            |   26 +-
+ drivers/edac/edac_pci_sysfs.c                      |   49 +-
+ drivers/edac/highbank_l2_edac.c                    |  149 +++
+ drivers/edac/highbank_mc_edac.c                    |  256 ++++
+ drivers/edac/i3000_edac.c                          |   47 +-
+ drivers/edac/i3200_edac.c                          |   48 +-
+ drivers/edac/i5000_edac.c                          |  195 ++-
+ drivers/edac/i5100_edac.c                          |   14 +-
+ drivers/edac/i5400_edac.c                          |  189 ++-
+ drivers/edac/i7300_edac.c                          |  173 ++-
+ drivers/edac/i7core_edac.c                         |  520 ++++----
+ drivers/edac/i82443bxgx_edac.c                     |   51 +-
+ drivers/edac/i82860_edac.c                         |   45 +-
+ drivers/edac/i82875p_edac.c                        |   53 +-
+ drivers/edac/i82975x_edac.c                        |   55 +-
+ drivers/edac/mpc85xx_edac.c                        |  131 +-
+ drivers/edac/mv64x60_edac.c                        |   40 +-
+ drivers/edac/pasemi_edac.c                         |   22 +-
+ drivers/edac/ppc4xx_edac.c                         |   16 +-
+ drivers/edac/r82600_edac.c                         |   48 +-
+ drivers/edac/sb_edac.c                             |  257 ++--
+ drivers/edac/tile_edac.c                           |   12 +-
+ drivers/edac/x38_edac.c                            |   48 +-
+ include/linux/edac.h                               |  208 +--
+ include/ras/ras_event.h                            |  102 ++
+ 48 files changed, 3445 insertions(+), 2549 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-devices-edac
+ create mode 100644 Documentation/devicetree/bindings/arm/calxeda/l2ecc.txt
+ create mode 100644 Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt
+ create mode 100644 drivers/edac/highbank_l2_edac.c
+ create mode 100644 drivers/edac/highbank_mc_edac.c
+ create mode 100644 include/ras/ras_event.h
+Merging edac-amd/for-next (305f1c3 Merge branch '3.3-pci_device_id' into edac-for-next)
+$ git merge edac-amd/for-next
+Resolved 'Documentation/edac.txt' using previous resolution.
+Resolved 'drivers/edac/amd64_edac.c' using previous resolution.
+Auto-merging drivers/edac/amd64_edac.c
+CONFLICT (content): Merge conflict in drivers/edac/amd64_edac.c
+Auto-merging Documentation/edac.txt
+CONFLICT (content): Merge conflict in Documentation/edac.txt
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master a5a3eb7] Merge remote-tracking branch 'edac-amd/for-next'
+$ git diff -M --stat --summary HEAD^..
+Merging devicetree/devicetree/next (efd68e7 devicetree: add helper inline for retrieving a node's full name)
+$ git merge devicetree/devicetree/next
+Auto-merging drivers/of/base.c
+Auto-merging arch/powerpc/kernel/pci-common.c
+Auto-merging arch/microblaze/pci/pci-common.c
+Merge made by the 'recursive' strategy.
+ arch/microblaze/pci/pci-common.c       |    6 ++----
+ arch/powerpc/kernel/pci-common.c       |    6 ++----
+ arch/powerpc/kernel/vio.c              |    5 ++---
+ arch/powerpc/platforms/cell/iommu.c    |    3 +--
+ arch/powerpc/platforms/pseries/iommu.c |    2 +-
+ arch/sparc/kernel/of_device_64.c       |    2 +-
+ drivers/of/base.c                      |    2 +-
+ drivers/of/irq.c                       |    2 +-
+ include/linux/of.h                     |   10 ++++++++++
+ kernel/irq/irqdomain.c                 |    8 ++++----
+ 10 files changed, 25 insertions(+), 21 deletions(-)
+Merging spi/spi/next (d8e328b spi: Add "spi:" prefix to modalias attribute of spi devices)
+$ git merge spi/spi/next
+Merge made by the 'recursive' strategy.
+Merging tip/auto-latest (b0b7208 Merge branch 'x86/urgent')
+$ git merge tip/auto-latest
+Resolved 'drivers/hwmon/coretemp.c' using previous resolution.
+Resolved 'mm/slab.c' using previous resolution.
+Resolved 'mm/slub.c' using previous resolution.
+Auto-merging mm/slub.c
+CONFLICT (content): Merge conflict in mm/slub.c
+Auto-merging mm/slab.c
+CONFLICT (content): Merge conflict in mm/slab.c
+Auto-merging mm/mempolicy.c
+Auto-merging init/main.c
+Auto-merging include/linux/mm_types.h
+Auto-merging include/linux/mempolicy.h
+Auto-merging drivers/hwmon/coretemp.c
+CONFLICT (content): Merge conflict in drivers/hwmon/coretemp.c
+Auto-merging arch/x86/realmode/rm/reboot.S
+Auto-merging arch/x86/kernel/reboot.c
+Removing arch/x86/kernel/cpu/sched.c
+Auto-merging arch/x86/include/asm/pci_x86.h
+Auto-merging arch/s390/kernel/smp.c
+Auto-merging MAINTAINERS
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master c1c344c] Merge remote-tracking branch 'tip/auto-latest'
+$ git diff -M --stat --summary HEAD^..
+ MAINTAINERS                                    |    8 +
+ arch/hexagon/kernel/smp.c                      |    2 -
+ arch/ia64/kernel/smpboot.c                     |    2 -
+ arch/m32r/include/asm/smp.h                    |    5 -
+ arch/mn10300/kernel/smp.c                      |    2 -
+ arch/parisc/kernel/smp.c                       |    2 -
+ arch/powerpc/kernel/smp.c                      |    2 -
+ arch/s390/kernel/smp.c                         |    2 -
+ arch/sparc/kernel/smp_64.c                     |    7 +-
+ arch/tile/kernel/smpboot.c                     |   10 -
+ arch/x86/Kconfig                               |   31 +
+ arch/x86/Makefile                              |    3 +
+ arch/x86/boot/header.S                         |    7 -
+ arch/x86/ia32/ia32_signal.c                    |    2 +-
+ arch/x86/include/asm/amd_nb.h                  |   21 +
+ arch/x86/include/asm/apic.h                    |   62 +-
+ arch/x86/include/asm/cpufeature.h              |    2 +-
+ arch/x86/include/asm/emergency-restart.h       |    2 -
+ arch/x86/include/asm/floppy.h                  |    2 +-
+ arch/x86/include/asm/msr.h                     |   46 +-
+ arch/x86/include/asm/nmi.h                     |   20 +-
+ arch/x86/include/asm/paravirt.h                |   41 +-
+ arch/x86/include/asm/paravirt_types.h          |    2 -
+ arch/x86/include/asm/pci_x86.h                 |    8 +-
+ arch/x86/include/asm/percpu.h                  |   17 +
+ arch/x86/include/asm/pgtable-2level.h          |    4 +-
+ arch/x86/include/asm/pgtable-3level.h          |    6 +-
+ arch/x86/include/asm/pgtable_64.h              |    8 +-
+ arch/x86/include/asm/realmode.h                |    3 +-
+ arch/x86/include/asm/reboot.h                  |    4 +-
+ arch/x86/include/asm/smp.h                     |   21 +-
+ arch/x86/include/asm/uprobes.h                 |    2 +-
+ arch/x86/include/asm/uv/uv_bau.h               |   28 +-
+ arch/x86/include/asm/x2apic.h                  |   18 -
+ arch/x86/include/asm/x86_init.h                |    4 +-
+ arch/x86/kernel/alternative.c                  |   19 +-
+ arch/x86/kernel/amd_nb.c                       |   11 +-
+ arch/x86/kernel/apic/apic.c                    |   25 +-
+ arch/x86/kernel/apic/apic_flat_64.c            |   76 +-
+ arch/x86/kernel/apic/apic_noop.c               |    9 +-
+ arch/x86/kernel/apic/apic_numachip.c           |   50 +-
+ arch/x86/kernel/apic/bigsmp_32.c               |   48 +-
+ arch/x86/kernel/apic/es7000_32.c               |   51 +-
+ arch/x86/kernel/apic/io_apic.c                 |  326 ++---
+ arch/x86/kernel/apic/numaq_32.c                |   30 +-
+ arch/x86/kernel/apic/probe_32.c                |   23 +-
+ arch/x86/kernel/apic/probe_64.c                |   11 +-
+ arch/x86/kernel/apic/summit_32.c               |   68 +-
+ arch/x86/kernel/apic/x2apic_cluster.c          |   66 +-
+ arch/x86/kernel/apic/x2apic_phys.c             |   39 +-
+ arch/x86/kernel/apic/x2apic_uv_x.c             |   45 +-
+ arch/x86/kernel/apm_32.c                       |   29 +-
+ arch/x86/kernel/cpu/Makefile                   |    6 +-
+ arch/x86/kernel/cpu/amd.c                      |   39 +-
+ arch/x86/kernel/cpu/bugs.c                     |   20 +-
+ arch/x86/kernel/cpu/common.c                   |    2 +-
+ arch/x86/kernel/cpu/mcheck/mce.c               |   22 +-
+ arch/x86/kernel/cpu/mcheck/mce_amd.c           |  264 ++--
+ arch/x86/kernel/cpu/mkcapflags.pl              |   25 +-
+ arch/x86/kernel/cpu/perf_event.c               |   30 +-
+ arch/x86/kernel/cpu/perf_event.h               |   17 +-
+ arch/x86/kernel/cpu/perf_event_intel.c         |   22 +-
+ arch/x86/kernel/cpu/perf_event_intel_ds.c      |    8 +-
+ arch/x86/kernel/cpu/perf_event_intel_uncore.c  | 1703 ++++++++++++++++++++++++
+ arch/x86/kernel/cpu/perf_event_intel_uncore.h  |  406 ++++++
+ arch/x86/kernel/cpu/perf_event_p4.c            |   14 +-
+ arch/x86/kernel/cpu/perf_event_p6.c            |    4 +-
+ arch/x86/kernel/cpu/scattered.c                |    2 +-
+ arch/x86/kernel/cpu/sched.c                    |   55 -
+ arch/x86/kernel/dumpstack.c                    |    5 +-
+ arch/x86/kernel/dumpstack_32.c                 |   25 +-
+ arch/x86/kernel/dumpstack_64.c                 |   21 +-
+ arch/x86/kernel/entry_64.S                     |   20 +
+ arch/x86/kernel/irq.c                          |    4 +-
+ arch/x86/kernel/kgdb.c                         |    8 +-
+ arch/x86/kernel/microcode_core.c               |    2 +-
+ arch/x86/kernel/module.c                       |   32 +-
+ arch/x86/kernel/nmi.c                          |   47 +-
+ arch/x86/kernel/nmi_selftest.c                 |    7 +-
+ arch/x86/kernel/paravirt.c                     |    2 -
+ arch/x86/kernel/pci-calgary_64.c               |   34 +-
+ arch/x86/kernel/process.c                      |   34 +-
+ arch/x86/kernel/process_64.c                   |   12 +-
+ arch/x86/kernel/reboot.c                       |   74 +-
+ arch/x86/kernel/setup.c                        |    2 -
+ arch/x86/kernel/setup_percpu.c                 |    2 +-
+ arch/x86/kernel/signal.c                       |    5 +-
+ arch/x86/kernel/smpboot.c                      |  114 +-
+ arch/x86/kernel/traps.c                        |   19 +-
+ arch/x86/kernel/tsc.c                          |   50 +-
+ arch/x86/kernel/uprobes.c                      |    3 +-
+ arch/x86/kernel/vm86_32.c                      |    6 +-
+ arch/x86/kernel/vsmp_64.c                      |   44 +-
+ arch/x86/kernel/vsyscall_64.c                  |   17 +-
+ arch/x86/kernel/x86_init.c                     |    2 -
+ arch/x86/kernel/xsave.c                        |   12 +-
+ arch/x86/lib/csum-wrappers_64.c                |    2 +-
+ arch/x86/lib/msr-reg-export.c                  |    4 +-
+ arch/x86/lib/msr-reg.S                         |   10 +-
+ arch/x86/mm/init.c                             |    2 +-
+ arch/x86/mm/pageattr.c                         |   10 +-
+ arch/x86/platform/efi/efi.c                    |   30 +-
+ arch/x86/platform/uv/tlb_uv.c                  |  453 ++++---
+ arch/x86/platform/uv/uv_irq.c                  |    9 +-
+ arch/x86/realmode/rm/Makefile                  |    2 +-
+ arch/x86/realmode/rm/header.S                  |    4 +-
+ arch/x86/realmode/rm/{reboot_32.S => reboot.S} |   30 +-
+ arch/x86/vdso/vdso32-setup.c                   |    6 +-
+ arch/x86/xen/enlighten.c                       |    2 -
+ arch/x86/xen/smp.c                             |    2 -
+ drivers/base/node.c                            |    2 +-
+ drivers/hwmon/coretemp.c                       |    4 +-
+ drivers/hwmon/k10temp.c                        |    5 +-
+ drivers/iommu/dmar.c                           |  194 +--
+ drivers/iommu/intel_irq_remapping.c            |   20 +-
+ drivers/iommu/irq_remapping.c                  |    5 +-
+ drivers/iommu/irq_remapping.h                  |    2 -
+ drivers/oprofile/oprofile_perf.c               |    2 +-
+ fs/exec.c                                      |    4 +-
+ include/linux/cpuset.h                         |   31 +-
+ include/linux/efi.h                            |    2 -
+ include/linux/ftrace_event.h                   |    3 +
+ include/linux/init_task.h                      |    8 +
+ include/linux/intel-iommu.h                    |    2 +
+ include/linux/irq.h                            |    2 -
+ include/linux/mempolicy.h                      |   55 +-
+ include/linux/migrate.h                        |   21 +
+ include/linux/migrate_mode.h                   |    3 +
+ include/linux/mm_types.h                       |    9 +
+ include/linux/mmzone.h                         |    1 -
+ include/linux/pci_ids.h                        |   12 +
+ include/linux/perf_event.h                     |    3 +
+ include/linux/rmap.h                           |    5 +-
+ include/linux/sched.h                          |   32 +-
+ include/linux/smp.h                            |    5 -
+ include/linux/swap.h                           |    4 +-
+ include/linux/tick.h                           |    8 +-
+ init/Kconfig                                   |    2 +-
+ init/main.c                                    |    8 +-
+ kernel/cpuset.c                                |  132 +-
+ kernel/events/core.c                           |   49 +-
+ kernel/events/uprobes.c                        |  461 ++++---
+ kernel/fork.c                                  |   20 +-
+ kernel/sched/Makefile                          |    1 +
+ kernel/sched/core.c                            |  148 +-
+ kernel/sched/debug.c                           |    3 +
+ kernel/sched/fair.c                            |  285 +++-
+ kernel/sched/features.h                        |   12 +
+ kernel/sched/numa.c                            |  855 ++++++++++++
+ kernel/sched/sched.h                           |   45 +
+ kernel/smp.c                                   |   20 -
+ kernel/smpboot.h                               |    2 -
+ kernel/time/tick-sched.c                       |  189 +--
+ kernel/time/timekeeping.c                      |    2 +-
+ kernel/time/timer_list.c                       |    4 +-
+ kernel/timer.c                                 |  110 +-
+ kernel/trace/ftrace.c                          |    8 +-
+ kernel/trace/trace_output.c                    |    2 +-
+ mm/filemap.c                                   |    4 +-
+ mm/hugetlb.c                                   |    4 +-
+ mm/init-mm.c                                   |   10 +
+ mm/memory.c                                    |   17 +
+ mm/mempolicy.c                                 |  597 ++++++---
+ mm/migrate.c                                   |  226 +++-
+ mm/mmap.c                                      |   21 +-
+ mm/page_alloc.c                                |    8 +-
+ mm/rmap.c                                      |    6 +-
+ mm/slab.c                                      |    4 +-
+ mm/slub.c                                      |   16 +-
+ mm/swapfile.c                                  |   13 +
+ scripts/kconfig/Makefile                       |    7 +-
+ tools/kvm/.gitignore                           |   12 +
+ tools/kvm/CREDITS-Git                          |   30 +
+ tools/kvm/Documentation/kernel-debugging.txt   |   15 +
+ tools/kvm/Documentation/kvm-balloon.txt        |   24 +
+ tools/kvm/Documentation/kvm-debug.txt          |   16 +
+ tools/kvm/Documentation/kvm-list.txt           |   16 +
+ tools/kvm/Documentation/kvm-pause.txt          |   16 +
+ tools/kvm/Documentation/kvm-resume.txt         |   16 +
+ tools/kvm/Documentation/kvm-run.txt            |   62 +
+ tools/kvm/Documentation/kvm-sandbox.txt        |   16 +
+ tools/kvm/Documentation/kvm-setup.txt          |   15 +
+ tools/kvm/Documentation/kvm-stat.txt           |   19 +
+ tools/kvm/Documentation/kvm-stop.txt           |   16 +
+ tools/kvm/Documentation/kvm-version.txt        |   21 +
+ tools/kvm/Documentation/virtio-console.txt     |   41 +
+ tools/kvm/Makefile                             |  430 ++++++
+ tools/kvm/README                               |  112 ++
+ tools/kvm/builtin-balloon.c                    |   80 ++
+ tools/kvm/builtin-debug.c                      |  103 ++
+ tools/kvm/builtin-help.c                       |   63 +
+ tools/kvm/builtin-list.c                       |  149 +++
+ tools/kvm/builtin-pause.c                      |   88 ++
+ tools/kvm/builtin-resume.c                     |   88 ++
+ tools/kvm/builtin-run.c                        | 1383 +++++++++++++++++++
+ tools/kvm/builtin-sandbox.c                    |    9 +
+ tools/kvm/builtin-setup.c                      |  232 ++++
+ tools/kvm/builtin-stat.c                       |  127 ++
+ tools/kvm/builtin-stop.c                       |   70 +
+ tools/kvm/builtin-version.c                    |   15 +
+ tools/kvm/code16gcc.h                          |   15 +
+ tools/kvm/command-list.txt                     |   15 +
+ tools/kvm/config/feature-tests.mak             |  177 +++
+ tools/kvm/config/utilities.mak                 |  196 +++
+ tools/kvm/disk/blk.c                           |   76 ++
+ tools/kvm/disk/core.c                          |  263 ++++
+ tools/kvm/disk/qcow.c                          | 1529 +++++++++++++++++++++
+ tools/kvm/disk/raw.c                           |  141 ++
+ tools/kvm/framebuffer.c                        |   75 ++
+ tools/kvm/guest/init.c                         |   38 +
+ tools/kvm/guest/init_stage2.c                  |   55 +
+ tools/kvm/guest/passwd                         |    1 +
+ tools/kvm/guest_compat.c                       |   99 ++
+ tools/kvm/hw/i8042.c                           |  348 +++++
+ tools/kvm/hw/pci-shmem.c                       |  268 ++++
+ tools/kvm/hw/rtc.c                             |  137 ++
+ tools/kvm/hw/serial.c                          |  447 +++++++
+ tools/kvm/hw/vesa.c                            |   85 ++
+ tools/kvm/include/asm/hweight.h                |    8 +
+ tools/kvm/include/bios/memcpy.h                |    9 +
+ tools/kvm/include/kvm/8250-serial.h            |   11 +
+ tools/kvm/include/kvm/apic.h                   |   17 +
+ tools/kvm/include/kvm/brlock.h                 |   41 +
+ tools/kvm/include/kvm/builtin-balloon.h        |    9 +
+ tools/kvm/include/kvm/builtin-debug.h          |   18 +
+ tools/kvm/include/kvm/builtin-help.h           |    6 +
+ tools/kvm/include/kvm/builtin-list.h           |   10 +
+ tools/kvm/include/kvm/builtin-pause.h          |    9 +
+ tools/kvm/include/kvm/builtin-resume.h         |    9 +
+ tools/kvm/include/kvm/builtin-run.h            |   11 +
+ tools/kvm/include/kvm/builtin-sandbox.h        |    6 +
+ tools/kvm/include/kvm/builtin-setup.h          |   11 +
+ tools/kvm/include/kvm/builtin-stat.h           |    9 +
+ tools/kvm/include/kvm/builtin-stop.h           |    9 +
+ tools/kvm/include/kvm/builtin-version.h        |    6 +
+ tools/kvm/include/kvm/compiler.h               |   10 +
+ tools/kvm/include/kvm/disk-image.h             |   81 ++
+ tools/kvm/include/kvm/e820.h                   |   13 +
+ tools/kvm/include/kvm/framebuffer.h            |   35 +
+ tools/kvm/include/kvm/guest_compat.h           |    9 +
+ tools/kvm/include/kvm/i8042.h                  |   12 +
+ tools/kvm/include/kvm/ioeventfd.h              |   28 +
+ tools/kvm/include/kvm/ioport.h                 |   69 +
+ tools/kvm/include/kvm/irq.h                    |   33 +
+ tools/kvm/include/kvm/kvm-cmd.h                |   17 +
+ tools/kvm/include/kvm/kvm-cpu.h                |   24 +
+ tools/kvm/include/kvm/kvm-ipc.h                |   24 +
+ tools/kvm/include/kvm/kvm.h                    |   93 ++
+ tools/kvm/include/kvm/msi.h                    |   10 +
+ tools/kvm/include/kvm/mutex.h                  |   33 +
+ tools/kvm/include/kvm/parse-options.h          |  214 +++
+ tools/kvm/include/kvm/pci-shmem.h              |   28 +
+ tools/kvm/include/kvm/pci.h                    |   95 ++
+ tools/kvm/include/kvm/qcow.h                   |  133 ++
+ tools/kvm/include/kvm/rbtree-interval.h        |   28 +
+ tools/kvm/include/kvm/read-write.h             |   43 +
+ tools/kvm/include/kvm/rtc.h                    |    9 +
+ tools/kvm/include/kvm/rwsem.h                  |   39 +
+ tools/kvm/include/kvm/sdl.h                    |   22 +
+ tools/kvm/include/kvm/segment.h                |   21 +
+ tools/kvm/include/kvm/strbuf.h                 |   20 +
+ tools/kvm/include/kvm/symbol.h                 |   30 +
+ tools/kvm/include/kvm/term.h                   |   20 +
+ tools/kvm/include/kvm/threadpool.h             |   37 +
+ tools/kvm/include/kvm/types.h                  |    7 +
+ tools/kvm/include/kvm/uip.h                    |  358 +++++
+ tools/kvm/include/kvm/util.h                   |   95 ++
+ tools/kvm/include/kvm/vesa.h                   |   18 +
+ tools/kvm/include/kvm/virtio-9p.h              |   73 +
+ tools/kvm/include/kvm/virtio-balloon.h         |    8 +
+ tools/kvm/include/kvm/virtio-blk.h             |   12 +
+ tools/kvm/include/kvm/virtio-console.h         |    9 +
+ tools/kvm/include/kvm/virtio-mmio.h            |   58 +
+ tools/kvm/include/kvm/virtio-net.h             |   26 +
+ tools/kvm/include/kvm/virtio-pci-dev.h         |   37 +
+ tools/kvm/include/kvm/virtio-pci.h             |   46 +
+ tools/kvm/include/kvm/virtio-rng.h             |    9 +
+ tools/kvm/include/kvm/virtio.h                 |  102 ++
+ tools/kvm/include/kvm/vnc.h                    |   20 +
+ tools/kvm/include/linux/bitops.h               |   33 +
+ tools/kvm/include/linux/byteorder.h            |    7 +
+ tools/kvm/include/linux/compiler.h             |   19 +
+ tools/kvm/include/linux/kernel.h               |   39 +
+ tools/kvm/include/linux/module.h               |    6 +
+ tools/kvm/include/linux/prefetch.h             |    6 +
+ tools/kvm/include/linux/stddef.h               |   16 +
+ tools/kvm/include/linux/types.h                |   51 +
+ tools/kvm/ioeventfd.c                          |  212 +++
+ tools/kvm/ioport.c                             |  195 +++
+ tools/kvm/kvm-cmd.c                            |   91 ++
+ tools/kvm/kvm-cpu.c                            |  175 +++
+ tools/kvm/kvm-ipc.c                            |  231 ++++
+ tools/kvm/kvm.c                                |  593 +++++++++
+ tools/kvm/main.c                               |   19 +
+ tools/kvm/mmio.c                               |  140 ++
+ tools/kvm/net/uip/arp.c                        |   30 +
+ tools/kvm/net/uip/buf.c                        |  114 ++
+ tools/kvm/net/uip/core.c                       |  190 +++
+ tools/kvm/net/uip/csum.c                       |   92 ++
+ tools/kvm/net/uip/dhcp.c                       |  203 +++
+ tools/kvm/net/uip/icmp.c                       |   29 +
+ tools/kvm/net/uip/ipv4.c                       |   29 +
+ tools/kvm/net/uip/tcp.c                        |  317 +++++
+ tools/kvm/net/uip/udp.c                        |  236 ++++
+ tools/kvm/pci.c                                |  213 +++
+ tools/kvm/powerpc/boot.c                       |    8 +
+ tools/kvm/powerpc/cpu_info.c                   |   83 ++
+ tools/kvm/powerpc/cpu_info.h                   |   43 +
+ tools/kvm/powerpc/include/kvm/barrier.h        |    6 +
+ tools/kvm/powerpc/include/kvm/kvm-arch.h       |   88 ++
+ tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h   |   76 ++
+ tools/kvm/powerpc/ioport.c                     |   18 +
+ tools/kvm/powerpc/irq.c                        |   75 ++
+ tools/kvm/powerpc/kvm-cpu.c                    |  291 ++++
+ tools/kvm/powerpc/kvm.c                        |  460 +++++++
+ tools/kvm/powerpc/spapr.h                      |   93 ++
+ tools/kvm/powerpc/spapr_hcall.c                |  134 ++
+ tools/kvm/powerpc/spapr_hvcons.c               |  102 ++
+ tools/kvm/powerpc/spapr_hvcons.h               |   19 +
+ tools/kvm/powerpc/spapr_pci.c                  |  423 ++++++
+ tools/kvm/powerpc/spapr_pci.h                  |   57 +
+ tools/kvm/powerpc/spapr_rtas.c                 |  229 ++++
+ tools/kvm/powerpc/xics.c                       |  514 +++++++
+ tools/kvm/powerpc/xics.h                       |   23 +
+ tools/kvm/symbol.c                             |  131 ++
+ tools/kvm/term.c                               |  166 +++
+ tools/kvm/tests/Makefile                       |   19 +
+ tools/kvm/tests/boot/Makefile                  |   13 +
+ tools/kvm/tests/boot/init.c                    |   11 +
+ tools/kvm/tests/kernel/.gitignore              |    2 +
+ tools/kvm/tests/kernel/Makefile                |   20 +
+ tools/kvm/tests/kernel/README                  |   16 +
+ tools/kvm/tests/kernel/kernel.S                |    8 +
+ tools/kvm/tests/pit/.gitignore                 |    2 +
+ tools/kvm/tests/pit/Makefile                   |   20 +
+ tools/kvm/tests/pit/README                     |   16 +
+ tools/kvm/tests/pit/tick.S                     |  109 ++
+ tools/kvm/ui/sdl.c                             |  303 +++++
+ tools/kvm/ui/vnc.c                             |  230 ++++
+ tools/kvm/util/KVMTOOLS-VERSION-GEN            |   40 +
+ tools/kvm/util/generate-cmdlist.sh             |   23 +
+ tools/kvm/util/kvm-ifup-vbr0                   |    6 +
+ tools/kvm/util/parse-options.c                 |  577 ++++++++
+ tools/kvm/util/rbtree-interval.c               |   89 ++
+ tools/kvm/util/read-write.c                    |  354 +++++
+ tools/kvm/util/set_private_br.sh               |   51 +
+ tools/kvm/util/strbuf.c                        |   62 +
+ tools/kvm/util/threadpool.c                    |  145 ++
+ tools/kvm/util/util.c                          |  115 ++
+ tools/kvm/virtio/9p-pdu.c                      |  287 ++++
+ tools/kvm/virtio/9p.c                          | 1338 +++++++++++++++++++
+ tools/kvm/virtio/balloon.c                     |  267 ++++
+ tools/kvm/virtio/blk.c                         |  314 +++++
+ tools/kvm/virtio/console.c                     |  193 +++
+ tools/kvm/virtio/core.c                        |  233 ++++
+ tools/kvm/virtio/mmio.c                        |  256 ++++
+ tools/kvm/virtio/net.c                         |  552 ++++++++
+ tools/kvm/virtio/pci.c                         |  369 +++++
+ tools/kvm/virtio/rng.c                         |  194 +++
+ tools/kvm/x86/bios.c                           |  174 +++
+ tools/kvm/x86/bios/.gitignore                  |    3 +
+ tools/kvm/x86/bios/bios-rom.S                  |   12 +
+ tools/kvm/x86/bios/e820.c                      |   72 +
+ tools/kvm/x86/bios/entry.S                     |   92 ++
+ tools/kvm/x86/bios/gen-offsets.sh              |   14 +
+ tools/kvm/x86/bios/int10.c                     |  110 ++
+ tools/kvm/x86/bios/int15.c                     |   18 +
+ tools/kvm/x86/bios/local.S                     |    7 +
+ tools/kvm/x86/bios/macro.S                     |   25 +
+ tools/kvm/x86/bios/memcpy.c                    |   23 +
+ tools/kvm/x86/bios/rom.ld.S                    |   16 +
+ tools/kvm/x86/boot.c                           |   41 +
+ tools/kvm/x86/cpuid.c                          |   60 +
+ tools/kvm/x86/include/kvm/assembly.h           |   24 +
+ tools/kvm/x86/include/kvm/barrier.h            |   20 +
+ tools/kvm/x86/include/kvm/bios-export.h        |   13 +
+ tools/kvm/x86/include/kvm/bios.h               |   93 ++
+ tools/kvm/x86/include/kvm/boot-protocol.h      |   16 +
+ tools/kvm/x86/include/kvm/cpufeature.h         |   41 +
+ tools/kvm/x86/include/kvm/interrupt.h          |   26 +
+ tools/kvm/x86/include/kvm/kvm-arch.h           |   66 +
+ tools/kvm/x86/include/kvm/kvm-cpu-arch.h       |   49 +
+ tools/kvm/x86/include/kvm/mptable.h            |    9 +
+ tools/kvm/x86/interrupt.c                      |   28 +
+ tools/kvm/x86/ioport.c                         |   77 ++
+ tools/kvm/x86/irq.c                            |  222 +++
+ tools/kvm/x86/kvm-cpu.c                        |  425 ++++++
+ tools/kvm/x86/kvm.c                            |  385 ++++++
+ tools/kvm/x86/mptable.c                        |  287 ++++
+ tools/perf/Documentation/perf-report.txt       |    2 +-
+ tools/perf/Documentation/perf-top.txt          |    2 +-
+ tools/perf/Makefile                            |    6 +
+ tools/perf/builtin-evlist.c                    |    2 +-
+ tools/perf/builtin-record.c                    |    4 +-
+ tools/perf/builtin-report.c                    |   10 +-
+ tools/perf/builtin-sched.c                     |    2 +-
+ tools/perf/builtin-script.c                    |   42 +-
+ tools/perf/builtin-stat.c                      |   12 +-
+ tools/perf/builtin-test.c                      |    2 +-
+ tools/perf/builtin-top.c                       |   12 +-
+ tools/perf/config/feature-tests.mak            |   13 +
+ tools/perf/ui/browsers/annotate.c              |    4 +-
+ tools/perf/ui/browsers/hists.c                 |  210 ++-
+ tools/perf/ui/gtk/browser.c                    |   69 +-
+ tools/perf/ui/gtk/gtk.h                        |   31 +
+ tools/perf/ui/gtk/setup.c                      |    5 +
+ tools/perf/ui/gtk/util.c                       |  129 ++
+ tools/perf/ui/tui/setup.c                      |    6 +
+ tools/perf/ui/tui/util.c                       |  243 ++++
+ tools/perf/ui/util.c                           |  277 +---
+ tools/perf/ui/util.h                           |    9 +-
+ tools/perf/util/debug.c                        |    2 +-
+ tools/perf/util/debug.h                        |   23 +-
+ tools/perf/util/evsel.c                        |  196 ++-
+ tools/perf/util/evsel.h                        |   15 +-
+ tools/perf/util/header.c                       |    2 +-
+ tools/perf/util/hist.h                         |    1 +
+ tools/perf/util/map.h                          |    2 +-
+ tools/perf/util/parse-events-test.c            |  126 +-
+ tools/perf/util/parse-events.c                 |  274 ++--
+ tools/perf/util/parse-events.h                 |   17 +-
+ tools/perf/util/parse-events.l                 |  129 +-
+ tools/perf/util/parse-events.y                 |   71 +-
+ tools/perf/util/pmu.c                          |  166 +++
+ tools/perf/util/pmu.h                          |   11 +-
+ tools/perf/util/session.c                      |    9 +-
+ tools/perf/util/session.h                      |    4 +-
+ tools/perf/util/sort.c                         |   49 +
+ tools/perf/util/sort.h                         |    2 +
+ tools/perf/util/string.c                       |   22 +
+ tools/perf/util/top.c                          |    2 +-
+ tools/perf/util/util.h                         |    2 +
+ 432 files changed, 32533 insertions(+), 3122 deletions(-)
+ create mode 100644 arch/x86/kernel/cpu/perf_event_intel_uncore.c
+ create mode 100644 arch/x86/kernel/cpu/perf_event_intel_uncore.h
+ delete mode 100644 arch/x86/kernel/cpu/sched.c
+ rename arch/x86/realmode/rm/{reboot_32.S => reboot.S} (85%)
+ create mode 100644 kernel/sched/numa.c
+ create mode 100644 tools/kvm/.gitignore
+ create mode 100644 tools/kvm/CREDITS-Git
+ create mode 100644 tools/kvm/Documentation/kernel-debugging.txt
+ create mode 100644 tools/kvm/Documentation/kvm-balloon.txt
+ create mode 100644 tools/kvm/Documentation/kvm-debug.txt
+ create mode 100644 tools/kvm/Documentation/kvm-list.txt
+ create mode 100644 tools/kvm/Documentation/kvm-pause.txt
+ create mode 100644 tools/kvm/Documentation/kvm-resume.txt
+ create mode 100644 tools/kvm/Documentation/kvm-run.txt
+ create mode 100644 tools/kvm/Documentation/kvm-sandbox.txt
+ create mode 100644 tools/kvm/Documentation/kvm-setup.txt
+ create mode 100644 tools/kvm/Documentation/kvm-stat.txt
+ create mode 100644 tools/kvm/Documentation/kvm-stop.txt
+ create mode 100644 tools/kvm/Documentation/kvm-version.txt
+ create mode 100644 tools/kvm/Documentation/virtio-console.txt
+ create mode 100644 tools/kvm/Makefile
+ create mode 100644 tools/kvm/README
+ create mode 100644 tools/kvm/builtin-balloon.c
+ create mode 100644 tools/kvm/builtin-debug.c
+ create mode 100644 tools/kvm/builtin-help.c
+ create mode 100644 tools/kvm/builtin-list.c
+ create mode 100644 tools/kvm/builtin-pause.c
+ create mode 100644 tools/kvm/builtin-resume.c
+ create mode 100644 tools/kvm/builtin-run.c
+ create mode 100644 tools/kvm/builtin-sandbox.c
+ create mode 100644 tools/kvm/builtin-setup.c
+ create mode 100644 tools/kvm/builtin-stat.c
+ create mode 100644 tools/kvm/builtin-stop.c
+ create mode 100644 tools/kvm/builtin-version.c
+ create mode 100644 tools/kvm/code16gcc.h
+ create mode 100644 tools/kvm/command-list.txt
+ create mode 100644 tools/kvm/config/feature-tests.mak
+ create mode 100644 tools/kvm/config/utilities.mak
+ create mode 100644 tools/kvm/disk/blk.c
+ create mode 100644 tools/kvm/disk/core.c
+ create mode 100644 tools/kvm/disk/qcow.c
+ create mode 100644 tools/kvm/disk/raw.c
+ create mode 100644 tools/kvm/framebuffer.c
+ create mode 100644 tools/kvm/guest/init.c
+ create mode 100644 tools/kvm/guest/init_stage2.c
+ create mode 100644 tools/kvm/guest/passwd
+ create mode 100644 tools/kvm/guest_compat.c
+ create mode 100644 tools/kvm/hw/i8042.c
+ create mode 100644 tools/kvm/hw/pci-shmem.c
+ create mode 100644 tools/kvm/hw/rtc.c
+ create mode 100644 tools/kvm/hw/serial.c
+ create mode 100644 tools/kvm/hw/vesa.c
+ create mode 100644 tools/kvm/include/asm/hweight.h
+ create mode 100644 tools/kvm/include/bios/memcpy.h
+ create mode 100644 tools/kvm/include/kvm/8250-serial.h
+ create mode 100644 tools/kvm/include/kvm/apic.h
+ create mode 100644 tools/kvm/include/kvm/brlock.h
+ create mode 100644 tools/kvm/include/kvm/builtin-balloon.h
+ create mode 100644 tools/kvm/include/kvm/builtin-debug.h
+ create mode 100644 tools/kvm/include/kvm/builtin-help.h
+ create mode 100644 tools/kvm/include/kvm/builtin-list.h
+ create mode 100644 tools/kvm/include/kvm/builtin-pause.h
+ create mode 100644 tools/kvm/include/kvm/builtin-resume.h
+ create mode 100644 tools/kvm/include/kvm/builtin-run.h
+ create mode 100644 tools/kvm/include/kvm/builtin-sandbox.h
+ create mode 100644 tools/kvm/include/kvm/builtin-setup.h
+ create mode 100644 tools/kvm/include/kvm/builtin-stat.h
+ create mode 100644 tools/kvm/include/kvm/builtin-stop.h
+ create mode 100644 tools/kvm/include/kvm/builtin-version.h
+ create mode 100644 tools/kvm/include/kvm/compiler.h
+ create mode 100644 tools/kvm/include/kvm/disk-image.h
+ create mode 100644 tools/kvm/include/kvm/e820.h
+ create mode 100644 tools/kvm/include/kvm/framebuffer.h
+ create mode 100644 tools/kvm/include/kvm/guest_compat.h
+ create mode 100644 tools/kvm/include/kvm/i8042.h
+ create mode 100644 tools/kvm/include/kvm/ioeventfd.h
+ create mode 100644 tools/kvm/include/kvm/ioport.h
+ create mode 100644 tools/kvm/include/kvm/irq.h
+ create mode 100644 tools/kvm/include/kvm/kvm-cmd.h
+ create mode 100644 tools/kvm/include/kvm/kvm-cpu.h
+ create mode 100644 tools/kvm/include/kvm/kvm-ipc.h
+ create mode 100644 tools/kvm/include/kvm/kvm.h
+ create mode 100644 tools/kvm/include/kvm/msi.h
+ create mode 100644 tools/kvm/include/kvm/mutex.h
+ create mode 100644 tools/kvm/include/kvm/parse-options.h
+ create mode 100644 tools/kvm/include/kvm/pci-shmem.h
+ create mode 100644 tools/kvm/include/kvm/pci.h
+ create mode 100644 tools/kvm/include/kvm/qcow.h
+ create mode 100644 tools/kvm/include/kvm/rbtree-interval.h
+ create mode 100644 tools/kvm/include/kvm/read-write.h
+ create mode 100644 tools/kvm/include/kvm/rtc.h
+ create mode 100644 tools/kvm/include/kvm/rwsem.h
+ create mode 100644 tools/kvm/include/kvm/sdl.h
+ create mode 100644 tools/kvm/include/kvm/segment.h
+ create mode 100644 tools/kvm/include/kvm/strbuf.h
+ create mode 100644 tools/kvm/include/kvm/symbol.h
+ create mode 100644 tools/kvm/include/kvm/term.h
+ create mode 100644 tools/kvm/include/kvm/threadpool.h
+ create mode 100644 tools/kvm/include/kvm/types.h
+ create mode 100644 tools/kvm/include/kvm/uip.h
+ create mode 100644 tools/kvm/include/kvm/util.h
+ create mode 100644 tools/kvm/include/kvm/vesa.h
+ create mode 100644 tools/kvm/include/kvm/virtio-9p.h
+ create mode 100644 tools/kvm/include/kvm/virtio-balloon.h
+ create mode 100644 tools/kvm/include/kvm/virtio-blk.h
+ create mode 100644 tools/kvm/include/kvm/virtio-console.h
+ create mode 100644 tools/kvm/include/kvm/virtio-mmio.h
+ create mode 100644 tools/kvm/include/kvm/virtio-net.h
+ create mode 100644 tools/kvm/include/kvm/virtio-pci-dev.h
+ create mode 100644 tools/kvm/include/kvm/virtio-pci.h
+ create mode 100644 tools/kvm/include/kvm/virtio-rng.h
+ create mode 100644 tools/kvm/include/kvm/virtio.h
+ create mode 100644 tools/kvm/include/kvm/vnc.h
+ create mode 100644 tools/kvm/include/linux/bitops.h
+ create mode 100644 tools/kvm/include/linux/byteorder.h
+ create mode 100644 tools/kvm/include/linux/compiler.h
+ create mode 100644 tools/kvm/include/linux/kernel.h
+ create mode 100644 tools/kvm/include/linux/module.h
+ create mode 100644 tools/kvm/include/linux/prefetch.h
+ create mode 100644 tools/kvm/include/linux/stddef.h
+ create mode 100644 tools/kvm/include/linux/types.h
+ create mode 100644 tools/kvm/ioeventfd.c
+ create mode 100644 tools/kvm/ioport.c
+ create mode 100644 tools/kvm/kvm-cmd.c
+ create mode 100644 tools/kvm/kvm-cpu.c
+ create mode 100644 tools/kvm/kvm-ipc.c
+ create mode 100644 tools/kvm/kvm.c
+ create mode 100644 tools/kvm/main.c
+ create mode 100644 tools/kvm/mmio.c
+ create mode 100644 tools/kvm/net/uip/arp.c
+ create mode 100644 tools/kvm/net/uip/buf.c
+ create mode 100644 tools/kvm/net/uip/core.c
+ create mode 100644 tools/kvm/net/uip/csum.c
+ create mode 100644 tools/kvm/net/uip/dhcp.c
+ create mode 100644 tools/kvm/net/uip/icmp.c
+ create mode 100644 tools/kvm/net/uip/ipv4.c
+ create mode 100644 tools/kvm/net/uip/tcp.c
+ create mode 100644 tools/kvm/net/uip/udp.c
+ create mode 100644 tools/kvm/pci.c
+ create mode 100644 tools/kvm/powerpc/boot.c
+ create mode 100644 tools/kvm/powerpc/cpu_info.c
+ create mode 100644 tools/kvm/powerpc/cpu_info.h
+ create mode 100644 tools/kvm/powerpc/include/kvm/barrier.h
+ create mode 100644 tools/kvm/powerpc/include/kvm/kvm-arch.h
+ create mode 100644 tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h
+ create mode 100644 tools/kvm/powerpc/ioport.c
+ create mode 100644 tools/kvm/powerpc/irq.c
+ create mode 100644 tools/kvm/powerpc/kvm-cpu.c
+ create mode 100644 tools/kvm/powerpc/kvm.c
+ create mode 100644 tools/kvm/powerpc/spapr.h
+ create mode 100644 tools/kvm/powerpc/spapr_hcall.c
+ create mode 100644 tools/kvm/powerpc/spapr_hvcons.c
+ create mode 100644 tools/kvm/powerpc/spapr_hvcons.h
+ create mode 100644 tools/kvm/powerpc/spapr_pci.c
+ create mode 100644 tools/kvm/powerpc/spapr_pci.h
+ create mode 100644 tools/kvm/powerpc/spapr_rtas.c
+ create mode 100644 tools/kvm/powerpc/xics.c
+ create mode 100644 tools/kvm/powerpc/xics.h
+ create mode 100644 tools/kvm/symbol.c
+ create mode 100644 tools/kvm/term.c
+ create mode 100644 tools/kvm/tests/Makefile
+ create mode 100644 tools/kvm/tests/boot/Makefile
+ create mode 100644 tools/kvm/tests/boot/init.c
+ create mode 100644 tools/kvm/tests/kernel/.gitignore
+ create mode 100644 tools/kvm/tests/kernel/Makefile
+ create mode 100644 tools/kvm/tests/kernel/README
+ create mode 100644 tools/kvm/tests/kernel/kernel.S
+ create mode 100644 tools/kvm/tests/pit/.gitignore
+ create mode 100644 tools/kvm/tests/pit/Makefile
+ create mode 100644 tools/kvm/tests/pit/README
+ create mode 100644 tools/kvm/tests/pit/tick.S
+ create mode 100644 tools/kvm/ui/sdl.c
+ create mode 100644 tools/kvm/ui/vnc.c
+ create mode 100755 tools/kvm/util/KVMTOOLS-VERSION-GEN
+ create mode 100755 tools/kvm/util/generate-cmdlist.sh
+ create mode 100755 tools/kvm/util/kvm-ifup-vbr0
+ create mode 100644 tools/kvm/util/parse-options.c
+ create mode 100644 tools/kvm/util/rbtree-interval.c
+ create mode 100644 tools/kvm/util/read-write.c
+ create mode 100755 tools/kvm/util/set_private_br.sh
+ create mode 100644 tools/kvm/util/strbuf.c
+ create mode 100644 tools/kvm/util/threadpool.c
+ create mode 100644 tools/kvm/util/util.c
+ create mode 100644 tools/kvm/virtio/9p-pdu.c
+ create mode 100644 tools/kvm/virtio/9p.c
+ create mode 100644 tools/kvm/virtio/balloon.c
+ create mode 100644 tools/kvm/virtio/blk.c
+ create mode 100644 tools/kvm/virtio/console.c
+ create mode 100644 tools/kvm/virtio/core.c
+ create mode 100644 tools/kvm/virtio/mmio.c
+ create mode 100644 tools/kvm/virtio/net.c
+ create mode 100644 tools/kvm/virtio/pci.c
+ create mode 100644 tools/kvm/virtio/rng.c
+ create mode 100644 tools/kvm/x86/bios.c
+ create mode 100644 tools/kvm/x86/bios/.gitignore
+ create mode 100644 tools/kvm/x86/bios/bios-rom.S
+ create mode 100644 tools/kvm/x86/bios/e820.c
+ create mode 100644 tools/kvm/x86/bios/entry.S
+ create mode 100644 tools/kvm/x86/bios/gen-offsets.sh
+ create mode 100644 tools/kvm/x86/bios/int10.c
+ create mode 100644 tools/kvm/x86/bios/int15.c
+ create mode 100644 tools/kvm/x86/bios/local.S
+ create mode 100644 tools/kvm/x86/bios/macro.S
+ create mode 100644 tools/kvm/x86/bios/memcpy.c
+ create mode 100644 tools/kvm/x86/bios/rom.ld.S
+ create mode 100644 tools/kvm/x86/boot.c
+ create mode 100644 tools/kvm/x86/cpuid.c
+ create mode 100644 tools/kvm/x86/include/kvm/assembly.h
+ create mode 100644 tools/kvm/x86/include/kvm/barrier.h
+ create mode 100644 tools/kvm/x86/include/kvm/bios-export.h
+ create mode 100644 tools/kvm/x86/include/kvm/bios.h
+ create mode 100644 tools/kvm/x86/include/kvm/boot-protocol.h
+ create mode 100644 tools/kvm/x86/include/kvm/cpufeature.h
+ create mode 100644 tools/kvm/x86/include/kvm/interrupt.h
+ create mode 100644 tools/kvm/x86/include/kvm/kvm-arch.h
+ create mode 100644 tools/kvm/x86/include/kvm/kvm-cpu-arch.h
+ create mode 100644 tools/kvm/x86/include/kvm/mptable.h
+ create mode 100644 tools/kvm/x86/interrupt.c
+ create mode 100644 tools/kvm/x86/ioport.c
+ create mode 100644 tools/kvm/x86/irq.c
+ create mode 100644 tools/kvm/x86/kvm-cpu.c
+ create mode 100644 tools/kvm/x86/kvm.c
+ create mode 100644 tools/kvm/x86/mptable.c
+ create mode 100644 tools/perf/ui/gtk/util.c
+ create mode 100644 tools/perf/ui/tui/util.c
+Merging rcu/rcu/next (f0fd40c rcu: Allow RCU quiescent-state forcing to be preempted)
+$ git merge rcu/rcu/next
+Auto-merging kernel/time/tick-sched.c
+Auto-merging include/linux/init_task.h
+Auto-merging Documentation/kernel-parameters.txt
+Merge made by the 'recursive' strategy.
+ Documentation/RCU/checklist.txt     |   39 +-
+ Documentation/RCU/rcubarrier.txt    |   15 +-
+ Documentation/RCU/torture.txt       |    9 +
+ Documentation/RCU/whatisRCU.txt     |    6 +-
+ Documentation/kernel-parameters.txt |    5 +
+ include/linux/init_task.h           |    4 +-
+ include/linux/key.h                 |    4 +-
+ include/linux/rcupdate.h            |   50 +--
+ include/trace/events/rcu.h          |   45 ++
+ kernel/rcupdate.c                   |   44 ++
+ kernel/rcutiny.c                    |    4 +-
+ kernel/rcutiny_plugin.h             |   49 +-
+ kernel/rcutorture.c                 |   36 +-
+ kernel/rcutree.c                    |  843 ++++++++++++++++++++++-------------
+ kernel/rcutree.h                    |   53 ++-
+ kernel/rcutree_plugin.h             |  247 +++-------
+ kernel/rcutree_trace.c              |  125 +++---
+ kernel/time/tick-sched.c            |    2 +-
+ 18 files changed, 880 insertions(+), 700 deletions(-)
+Merging cputime/cputime (c3e0ef9 [S390] fix cputime overflow in uptime_proc_show)
+$ git merge cputime/cputime
+Already up-to-date.
+Merging uprobes/for-next (0326f5a uprobes/core: Handle breakpoint and singlestep exceptions)
+$ git merge uprobes/for-next
+Already up-to-date.
+Merging kmemleak/kmemleak (4878677 kmemleak: do not leak object after tree insertion error)
+$ git merge kmemleak/kmemleak
+Merge made by the 'recursive' strategy.
+ mm/kmemleak.c |    1 +
+ 1 file changed, 1 insertion(+)
+Merging kvm/linux-next (dcce048 KVM: trace events: update list of exit reasons)
+$ git merge kvm/linux-next
+Auto-merging arch/s390/kernel/setup.c
+Auto-merging arch/powerpc/kvm/book3s_hv.c
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ Documentation/virtual/kvm/api.txt        |   36 +++++++++
+ Documentation/virtual/kvm/ppc-pv.txt     |    2 -
+ MAINTAINERS                              |    2 +-
+ arch/ia64/kvm/Kconfig                    |    1 +
+ arch/powerpc/include/asm/epapr_hcalls.h  |    2 +
+ arch/powerpc/include/asm/kvm_book3s_64.h |    7 +-
+ arch/powerpc/include/asm/kvm_host.h      |    6 ++
+ arch/powerpc/include/asm/kvm_ppc.h       |    3 +-
+ arch/powerpc/kernel/Makefile             |    1 +
+ arch/powerpc/kernel/epapr_hcalls.S       |   25 ++++++
+ arch/powerpc/kernel/epapr_paravirt.c     |   52 +++++++++++++
+ arch/powerpc/kernel/kvm.c                |   28 +------
+ arch/powerpc/kernel/kvm_emul.S           |   12 +--
+ arch/powerpc/kvm/book3s_64_mmu_hv.c      |  123 +++++++++++++++++++++++-------
+ arch/powerpc/kvm/book3s_hv.c             |   40 +++++++---
+ arch/powerpc/kvm/book3s_hv_builtin.c     |    5 +-
+ arch/powerpc/kvm/book3s_hv_rm_mmu.c      |   15 ++--
+ arch/powerpc/kvm/booke.c                 |    5 ++
+ arch/powerpc/kvm/booke_emulate.c         |    3 +
+ arch/powerpc/kvm/e500_emulate.c          |    3 +
+ arch/powerpc/kvm/powerpc.c               |   18 +++++
+ arch/powerpc/platforms/Kconfig           |    9 +++
+ arch/s390/include/asm/sclp.h             |    2 +
+ arch/s390/kernel/setup.c                 |   12 ++-
+ arch/s390/kvm/kvm-s390.c                 |    1 +
+ arch/x86/include/asm/vmx.h               |    4 +
+ arch/x86/kvm/mmu.c                       |   59 +++++++-------
+ arch/x86/kvm/svm.c                       |    6 +-
+ arch/x86/kvm/vmx.c                       |   92 ++++++++++++++++++----
+ arch/x86/kvm/x86.c                       |   58 +++++++-------
+ drivers/s390/char/sclp.c                 |   10 ---
+ drivers/s390/char/sclp.h                 |   10 +++
+ drivers/s390/char/sclp_cmd.c             |   38 +++++++++
+ drivers/s390/kvm/kvm_virtio.c            |    3 +-
+ include/linux/kvm.h                      |    3 +
+ include/linux/kvm_host.h                 |   21 +++--
+ include/trace/events/kvm.h               |    3 +-
+ virt/kvm/kvm_main.c                      |   32 +++++---
+ 38 files changed, 554 insertions(+), 198 deletions(-)
+ create mode 100644 arch/powerpc/kernel/epapr_hcalls.S
+ create mode 100644 arch/powerpc/kernel/epapr_paravirt.c
+Merging kvm-ppc/kvm-ppc-next (5e5054c booke: Added crit/mc exception handler for e500v2)
+$ git merge kvm-ppc/kvm-ppc-next
+Auto-merging arch/powerpc/include/asm/hw_irq.h
+Merge made by the 'recursive' strategy.
+ arch/powerpc/include/asm/hw_irq.h   |    2 ++
+ arch/powerpc/kvm/booke.c            |   21 +++++++++++++
+ arch/powerpc/kvm/booke_interrupts.S |   55 +++++++++++++++++------------------
+ 3 files changed, 50 insertions(+), 28 deletions(-)
+Merging oprofile/for-next (c16fa4f Linux 3.3)
+$ git merge oprofile/for-next
+Already up-to-date.
+Merging xen/upstream/xen (af3a3ab Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-fixes)
+$ git merge xen/upstream/xen
+Already up-to-date.
+Merging xen-two/linux-next (e4e7b82 Merge branch 'stable/for-linus-3.6' into linux-next)
+$ git merge xen-two/linux-next
+Auto-merging arch/x86/xen/enlighten.c
+Auto-merging arch/x86/kernel/cpu/mcheck/mce_amd.c
+Auto-merging arch/x86/kernel/cpu/mcheck/mce.c
+Merge made by the 'recursive' strategy.
+ .../ABI/testing/sysfs-devices-system-xen_cpu       |   20 +
+ arch/x86/include/asm/xen/hypercall.h               |    8 +
+ arch/x86/kernel/cpu/mcheck/mce.c                   |    4 +-
+ arch/x86/kernel/cpu/mcheck/mce_amd.c               |   22 +-
+ arch/x86/xen/enlighten.c                           |   23 +-
+ drivers/xen/Kconfig                                |    8 +
+ drivers/xen/Makefile                               |    2 +
+ drivers/xen/events.c                               |    2 -
+ drivers/xen/mcelog.c                               |  414 ++++++++++++++++++++
+ drivers/xen/pcpu.c                                 |  371 ++++++++++++++++++
+ include/linux/miscdevice.h                         |    1 +
+ include/xen/interface/platform.h                   |    8 +
+ include/xen/interface/xen-mca.h                    |  385 ++++++++++++++++++
+ include/xen/interface/xen.h                        |    1 +
+ 14 files changed, 1249 insertions(+), 20 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-devices-system-xen_cpu
+ create mode 100644 drivers/xen/mcelog.c
+ create mode 100644 drivers/xen/pcpu.c
+ create mode 100644 include/xen/interface/xen-mca.h
+Merging xen-pvhvm/linux-next (b056b6a xen: suspend: remove xen_hvm_suspend)
+$ git merge xen-pvhvm/linux-next
+Already up-to-date.
+Merging percpu/for-next (61011677 Merge tag 'dlm-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm)
+$ git merge percpu/for-next
+Already up-to-date.
+Merging workqueues/for-next (61011677 Merge tag 'dlm-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm)
+$ git merge workqueues/for-next
+Already up-to-date.
+Merging drivers-x86/linux-next (6ae3a08 ACER: Add support for accelerometer sensor)
+$ git merge drivers-x86/linux-next
+Auto-merging drivers/platform/x86/thinkpad_acpi.c
+Auto-merging drivers/platform/x86/intel_ips.c
+Auto-merging drivers/platform/x86/acer-wmi.c
+Merge made by the 'recursive' strategy.
+ drivers/platform/x86/acer-wmi.c       |  138 +++++++++++++
+ drivers/platform/x86/asus-wmi.c       |    7 +-
+ drivers/platform/x86/fujitsu-laptop.c |  103 +++++-----
+ drivers/platform/x86/ideapad-laptop.c |    6 +-
+ drivers/platform/x86/intel_ips.c      |   22 ++
+ drivers/platform/x86/sony-laptop.c    |  136 ++++++++-----
+ drivers/platform/x86/thinkpad_acpi.c  |  358 +++++++++++++++------------------
+ 7 files changed, 465 insertions(+), 305 deletions(-)
+Merging hwpoison/hwpoison (46e387b Merge branch 'hwpoison-hugepages' into hwpoison)
+$ git merge hwpoison/hwpoison
+Already up-to-date.
+Merging sysctl/master (4e474a0 sysctl: protect poll() in entries that may go away)
+$ git merge sysctl/master
+Already up-to-date.
+Merging regmap/for-next (dabefce Merge branch 'regmap-page' into regmap-next)
+$ git merge regmap/for-next
+Merge made by the 'recursive' strategy.
+ drivers/base/regmap/internal.h    |   17 ++
+ drivers/base/regmap/regmap-irq.c  |   57 ++++++-
+ drivers/base/regmap/regmap-mmio.c |   28 +++-
+ drivers/base/regmap/regmap.c      |  325 ++++++++++++++++++++++++++++++++++---
+ include/linux/regmap.h            |   69 +++++++-
+ 5 files changed, 458 insertions(+), 38 deletions(-)
+Merging hsi/for-next (43139a6 HSI: hsi_char: Update ioctl-number.txt)
+$ git merge hsi/for-next
+Already up-to-date.
+Merging leds/for-next (e15ca58 leds: Add LED driver for lm3556 chip)
+$ git merge leds/for-next
+Merge made by the 'recursive' strategy.
+ Documentation/leds/00-INDEX               |    2 +
+ Documentation/leds/leds-lm3556.txt        |   85 +++++
+ Documentation/leds/ledtrig-oneshot.txt    |   59 ++++
+ drivers/leds/Kconfig                      |   24 +-
+ drivers/leds/Makefile                     |    2 +
+ drivers/leds/led-class.c                  |   27 +-
+ drivers/leds/led-core.c                   |   66 ++--
+ drivers/leds/led-triggers.c               |  114 ++++---
+ drivers/leds/leds-lm3556.c                |  512 +++++++++++++++++++++++++++++
+ drivers/leds/leds-s3c24xx.c               |    3 +-
+ drivers/leds/leds.h                       |    2 +-
+ drivers/leds/ledtrig-backlight.c          |    8 +-
+ drivers/leds/ledtrig-default-on.c         |    2 +-
+ drivers/leds/ledtrig-gpio.c               |    6 +-
+ drivers/leds/ledtrig-heartbeat.c          |    2 +-
+ drivers/leds/ledtrig-ide-disk.c           |   25 +-
+ drivers/leds/ledtrig-oneshot.c            |  204 ++++++++++++
+ drivers/leds/ledtrig-timer.c              |    2 +-
+ drivers/leds/ledtrig-transient.c          |    8 +-
+ include/linux/leds.h                      |   29 +-
+ include/linux/platform_data/leds-lm3556.h |   50 +++
+ net/mac80211/led.c                        |    2 +-
+ 22 files changed, 1123 insertions(+), 111 deletions(-)
+ create mode 100644 Documentation/leds/leds-lm3556.txt
+ create mode 100644 Documentation/leds/ledtrig-oneshot.txt
+ create mode 100644 drivers/leds/leds-lm3556.c
+ create mode 100644 drivers/leds/ledtrig-oneshot.c
+ create mode 100644 include/linux/platform_data/leds-lm3556.h
+Merging driver-core/driver-core-next (f2c32a8 Extcon: Arizona: Add driver for Wolfson Arizona class devices)
+$ git merge driver-core/driver-core-next
+Resolved 'drivers/extcon/extcon_gpio.c' using previous resolution.
+Auto-merging fs/debugfs/inode.c
+Auto-merging drivers/power/ds2781_battery.c
+Auto-merging drivers/extcon/extcon_gpio.c
+CONFLICT (content): Merge conflict in drivers/extcon/extcon_gpio.c
+Auto-merging drivers/extcon/extcon_class.c
+Auto-merging drivers/base/dd.c
+Auto-merging MAINTAINERS
+Auto-merging Documentation/stable_kernel_rules.txt
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 4d51e50] Merge remote-tracking branch 'driver-core/driver-core-next'
+$ git diff -M --stat --summary HEAD^..
+ Documentation/ABI/stable/sysfs-driver-w1_ds28e04 |   15 +
+ Documentation/stable_kernel_rules.txt            |   19 +-
+ Documentation/w1/slaves/w1_ds28e04               |   36 ++
+ MAINTAINERS                                      |    8 +
+ drivers/base/core.c                              |   36 +-
+ drivers/base/dd.c                                |    2 +
+ drivers/base/dma-buf.c                           |    1 +
+ drivers/base/dma-coherent.c                      |    1 +
+ drivers/extcon/Kconfig                           |    8 +
+ drivers/extcon/Makefile                          |    1 +
+ drivers/extcon/extcon-arizona.c                  |  491 ++++++++++++++++++++++
+ drivers/extcon/extcon_class.c                    |    2 +-
+ drivers/extcon/extcon_gpio.c                     |   17 +-
+ drivers/power/ds2780_battery.c                   |   11 +-
+ drivers/power/ds2781_battery.c                   |   12 +-
+ drivers/w1/masters/ds1wm.c                       |    4 +
+ drivers/w1/masters/omap_hdq.c                    |   30 +-
+ drivers/w1/slaves/Kconfig                        |   13 +
+ drivers/w1/slaves/Makefile                       |    1 +
+ drivers/w1/slaves/w1_bq27000.c                   |    4 +-
+ drivers/w1/slaves/w1_ds2408.c                    |   24 +-
+ drivers/w1/slaves/w1_ds2423.c                    |    4 +-
+ drivers/w1/slaves/w1_ds2431.c                    |    8 +-
+ drivers/w1/slaves/w1_ds2433.c                    |    8 +-
+ drivers/w1/slaves/w1_ds2760.c                    |    8 +-
+ drivers/w1/slaves/w1_ds2780.c                    |   22 +-
+ drivers/w1/slaves/w1_ds2780.h                    |    2 -
+ drivers/w1/slaves/w1_ds2781.c                    |   22 +-
+ drivers/w1/slaves/w1_ds2781.h                    |    2 -
+ drivers/w1/slaves/w1_ds28e04.c                   |  469 +++++++++++++++++++++
+ drivers/w1/slaves/w1_therm.c                     |   10 +-
+ drivers/w1/w1.c                                  |   23 +-
+ drivers/w1/w1.h                                  |    1 +
+ drivers/w1/w1_family.h                           |    1 +
+ drivers/w1/w1_int.c                              |    3 +-
+ fs/debugfs/inode.c                               |    4 +-
+ 36 files changed, 1165 insertions(+), 158 deletions(-)
+ create mode 100644 Documentation/ABI/stable/sysfs-driver-w1_ds28e04
+ create mode 100644 Documentation/w1/slaves/w1_ds28e04
+ create mode 100644 drivers/extcon/extcon-arizona.c
+ create mode 100644 drivers/w1/slaves/w1_ds28e04.c
+Merging tty/tty-next (fc915c8 Merge 3.5-rc4 into tty-next)
+$ git merge tty/tty-next
+Removing include/linux/stallion.h
+Removing include/linux/serial167.h
+Removing include/linux/sc26198.h
+Removing include/linux/istallion.h
+Removing include/linux/generic_serial.h
+Removing include/linux/comstats.h
+Removing include/linux/cdk.h
+Removing include/linux/cd1400.h
+Auto-merging include/linux/Kbuild
+Merge made by the 'recursive' strategy.
+ .../bindings/tty/serial/nxp-lpc32xx-hsuart.txt     |   14 +
+ .../devicetree/bindings/tty/serial/of-serial.txt   |    1 +
+ arch/um/drivers/chan_kern.c                        |    4 +-
+ arch/um/drivers/line.c                             |   32 +-
+ arch/um/drivers/line.h                             |    3 +-
+ drivers/tty/cyclades.c                             |   63 +-
+ drivers/tty/pty.c                                  |  141 ++--
+ drivers/tty/serial/8250/8250.c                     |    8 +
+ drivers/tty/serial/8250/8250_pci.c                 |   10 +-
+ drivers/tty/serial/Kconfig                         |   19 +
+ drivers/tty/serial/Makefile                        |    1 +
+ drivers/tty/serial/amba-pl011.c                    |   34 +-
+ drivers/tty/serial/imx.c                           |    2 +-
+ drivers/tty/serial/lpc32xx_hs.c                    |  823 ++++++++++++++++++++
+ drivers/tty/serial/of_serial.c                     |    1 +
+ drivers/tty/serial/pch_uart.c                      |   38 +-
+ drivers/tty/serial/pxa.c                           |   14 +
+ drivers/tty/serial/samsung.c                       |   28 +-
+ drivers/tty/serial/serial_core.c                   |    6 +-
+ drivers/tty/tty_io.c                               |   34 +-
+ drivers/tty/tty_port.c                             |   17 +
+ drivers/tty/vt/keyboard.c                          |    6 +-
+ drivers/tty/vt/vt.c                                |   62 +-
+ drivers/tty/vt/vt_ioctl.c                          |   47 +-
+ drivers/usb/serial/usb-serial.c                    |    2 +-
+ include/linux/Kbuild                               |    3 -
+ include/linux/cd1400.h                             |  292 -------
+ include/linux/cdk.h                                |  486 ------------
+ include/linux/comstats.h                           |  119 ---
+ include/linux/generic_serial.h                     |   35 -
+ include/linux/istallion.h                          |  123 ---
+ include/linux/kbd_kern.h                           |   12 -
+ include/linux/sc26198.h                            |  533 -------------
+ include/linux/serial167.h                          |  157 ----
+ include/linux/serial_core.h                        |    3 +-
+ include/linux/stallion.h                           |  147 ----
+ include/linux/tty.h                                |    5 +
+ include/linux/tty_driver.h                         |    1 +
+ include/net/irda/ircomm_tty.h                      |   17 +-
+ net/irda/ircomm/ircomm_param.c                     |    5 -
+ net/irda/ircomm/ircomm_tty.c                       |  271 +++----
+ net/irda/ircomm/ircomm_tty_attach.c                |   40 +-
+ net/irda/ircomm/ircomm_tty_ioctl.c                 |   25 +-
+ 43 files changed, 1362 insertions(+), 2322 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
+ create mode 100644 drivers/tty/serial/lpc32xx_hs.c
+ delete mode 100644 include/linux/cd1400.h
+ delete mode 100644 include/linux/cdk.h
+ delete mode 100644 include/linux/comstats.h
+ delete mode 100644 include/linux/generic_serial.h
+ delete mode 100644 include/linux/istallion.h
+ delete mode 100644 include/linux/sc26198.h
+ delete mode 100644 include/linux/serial167.h
+ delete mode 100644 include/linux/stallion.h
+Merging usb/usb-next (023b515 uas: task mgmt & error handling)
+$ git merge usb/usb-next
+Auto-merging drivers/usb/serial/option.c
+Merge made by the 'recursive' strategy.
+ drivers/usb/class/cdc-wdm.c       |   25 ---
+ drivers/usb/core/driver.c         |   10 +-
+ drivers/usb/core/file.c           |    2 +-
+ drivers/usb/core/message.c        |    5 +-
+ drivers/usb/core/sysfs.c          |    5 +-
+ drivers/usb/early/ehci-dbgp.c     |    2 +-
+ drivers/usb/host/Kconfig          |    4 +-
+ drivers/usb/host/ehci-fsl.c       |   21 +-
+ drivers/usb/host/ehci-hub.c       |    2 +-
+ drivers/usb/host/ehci.h           |    4 -
+ drivers/usb/host/ohci-nxp.c       |   88 +++++---
+ drivers/usb/host/ohci-omap.c      |   27 +--
+ drivers/usb/host/ohci.h           |    5 -
+ drivers/usb/serial/keyspan.c      |    5 -
+ drivers/usb/serial/option.c       |   88 +++++---
+ drivers/usb/serial/quatech2.c     |    4 -
+ drivers/usb/storage/protocol.c    |    6 +-
+ drivers/usb/storage/uas.c         |  422 ++++++++++++++++++++++---------------
+ include/linux/mod_devicetable.h   |   10 +-
+ include/linux/usb.h               |   16 ++
+ include/linux/usb/hcd.h           |    6 +
+ include/linux/usb/renesas_usbhs.h |    8 +
+ include/linux/usb/uas.h           |   40 ++++
+ scripts/mod/file2alias.c          |    5 +-
+ tools/usb/testusb.c               |   21 +-
+ 25 files changed, 505 insertions(+), 326 deletions(-)
+Merging staging/staging-next (2da049b staging: gdm72xx: fix an skb memory leak)
+$ git merge staging/staging-next
+Auto-merging include/linux/iio/dac/max517.h
+Auto-merging include/linux/iio/dac/ad5421.h
+Removing include/linux/if_strip.h
+Auto-merging include/linux/Kbuild
+Auto-merging drivers/staging/sm7xxfb/sm7xxfb.c
+Auto-merging drivers/staging/sm7xxfb/sm7xx.h
+Auto-merging drivers/staging/sm7xxfb/TODO
+Removing drivers/staging/sm7xx/Makefile
+Removing drivers/staging/sm7xx/Kconfig
+Auto-merging drivers/staging/nvec/nvec_paz00.c
+Removing drivers/staging/iio/dac/dac.h
+Removing drivers/staging/iio/dac/ad5791.h
+Removing drivers/staging/iio/dac/ad5504.h
+Removing drivers/staging/comedi/drivers/comedi_pci.h
+Auto-merging drivers/staging/comedi/comedi_internal.h
+Removing drivers/staging/comedi/comedi_fops.h
+Removing drivers/staging/android/ram_console.c
+Auto-merging drivers/iio/dac/max517.c
+Auto-merging drivers/iio/dac/ad5791.c
+Auto-merging drivers/iio/dac/ad5764.c
+Auto-merging drivers/iio/dac/ad5686.c
+Auto-merging drivers/iio/dac/ad5624r_spi.c
+Auto-merging drivers/iio/dac/ad5504.c
+Auto-merging drivers/iio/dac/ad5446.h
+Auto-merging drivers/iio/dac/ad5446.c
+Auto-merging drivers/iio/dac/ad5421.c
+Auto-merging drivers/iio/dac/ad5380.c
+Auto-merging drivers/iio/dac/ad5360.c
+Auto-merging drivers/iio/dac/ad5064.c
+Auto-merging drivers/iio/dac/Makefile
+Auto-merging drivers/iio/dac/Kconfig
+Merge made by the 'recursive' strategy.
+ Documentation/ABI/testing/sysfs-bus-iio            |   52 +-
+ .../ABI/testing/sysfs-bus-iio-frequency-ad9523     |   37 +
+ .../ABI/testing/sysfs-bus-iio-frequency-adf4350    |   21 +
+ .../ABI/testing/sysfs-bus-iio-light-lm3533-als     |   61 +
+ Documentation/ramoops.txt                          |   14 +
+ drivers/iio/Kconfig                                |   10 +
+ drivers/iio/Makefile                               |    4 +
+ drivers/iio/adc/Kconfig                            |    3 +-
+ drivers/iio/adc/at91_adc.c                         |   57 +-
+ drivers/{staging => }/iio/dac/Kconfig              |   17 +-
+ drivers/{staging => }/iio/dac/Makefile             |    1 +
+ drivers/{staging => }/iio/dac/ad5064.c             |   66 +-
+ drivers/{staging => }/iio/dac/ad5360.c             |    1 -
+ drivers/{staging => }/iio/dac/ad5380.c             |  262 +-
+ drivers/{staging => }/iio/dac/ad5421.c             |    3 +-
+ drivers/{staging => }/iio/dac/ad5446.c             |   68 +-
+ drivers/{staging => }/iio/dac/ad5446.h             |    2 +
+ drivers/{staging => }/iio/dac/ad5504.c             |  216 +-
+ drivers/{staging => }/iio/dac/ad5624r.h            |    0
+ drivers/{staging => }/iio/dac/ad5624r_spi.c        |  218 +-
+ drivers/{staging => }/iio/dac/ad5686.c             |  197 +-
+ drivers/{staging => }/iio/dac/ad5764.c             |    1 -
+ drivers/{staging => }/iio/dac/ad5791.c             |  222 +-
+ drivers/{staging => }/iio/dac/max517.c             |  182 +-
+ drivers/iio/dac/mcp4725.c                          |  227 +
+ drivers/iio/frequency/Kconfig                      |   41 +
+ drivers/iio/frequency/Makefile                     |    6 +
+ drivers/iio/frequency/ad9523.c                     | 1059 ++++
+ drivers/iio/frequency/adf4350.c                    |  480 ++
+ drivers/iio/industrialio-buffer.c                  |    7 +
+ drivers/iio/industrialio-core.c                    |   63 +
+ drivers/iio/industrialio-trigger.c                 |    3 +-
+ drivers/iio/industrialio-triggered-buffer.c        |  110 +
+ drivers/iio/inkern.c                               |   13 +-
+ drivers/iio/light/Kconfig                          |   33 +
+ drivers/iio/light/Makefile                         |    6 +
+ drivers/iio/light/lm3533-als.c                     |  932 +++
+ drivers/iio/light/vcnl4000.c                       |  217 +
+ drivers/staging/Kconfig                            |    4 +-
+ drivers/staging/Makefile                           |    3 +-
+ drivers/staging/android/Kconfig                    |    5 -
+ drivers/staging/android/Makefile                   |    1 -
+ drivers/staging/android/alarm-dev.c                |   37 +-
+ drivers/staging/android/ashmem.c                   |   14 +-
+ drivers/staging/android/binder.c                   |   54 +-
+ drivers/staging/android/logger.c                   |   10 +-
+ drivers/staging/android/ram_console.c              |  179 -
+ drivers/staging/android/timed_output.c             |    4 +-
+ drivers/staging/bcm/Adapter.h                      |  220 +-
+ drivers/staging/bcm/Bcmchar.c                      |   32 +-
+ drivers/staging/bcm/Bcmnet.c                       |   18 +-
+ drivers/staging/bcm/CmHost.c                       |   66 +-
+ drivers/staging/bcm/CmHost.h                       |   10 +-
+ drivers/staging/bcm/DDRInit.c                      |   66 +-
+ drivers/staging/bcm/DDRInit.h                      |    4 +-
+ drivers/staging/bcm/HandleControlPacket.c          |   10 +-
+ drivers/staging/bcm/IPv6Protocol.c                 |   26 +-
+ drivers/staging/bcm/IPv6ProtocolHdr.h              |   10 +-
+ drivers/staging/bcm/InterfaceAdapter.h             |    2 +-
+ drivers/staging/bcm/InterfaceDld.c                 |   14 +-
+ drivers/staging/bcm/InterfaceIdleMode.c            |   12 +-
+ drivers/staging/bcm/InterfaceIdleMode.h            |   10 +-
+ drivers/staging/bcm/InterfaceInit.c                |    8 +-
+ drivers/staging/bcm/InterfaceIsr.c                 |    2 +-
+ drivers/staging/bcm/InterfaceIsr.h                 |    4 +-
+ drivers/staging/bcm/InterfaceMisc.c                |    2 +-
+ drivers/staging/bcm/InterfaceMisc.h                |    2 +-
+ drivers/staging/bcm/InterfaceRx.c                  |   12 +-
+ drivers/staging/bcm/InterfaceTx.c                  |    6 +-
+ drivers/staging/bcm/LeakyBucket.c                  |   16 +-
+ drivers/staging/bcm/Macros.h                       |   12 +-
+ drivers/staging/bcm/Misc.c                         |  118 +-
+ drivers/staging/bcm/PHSModule.c                    |   68 +-
+ drivers/staging/bcm/PHSModule.h                    |    6 +-
+ drivers/staging/bcm/Protocol.h                     |    8 +-
+ drivers/staging/bcm/Prototypes.h                   |  168 +-
+ drivers/staging/bcm/Qos.c                          |   84 +-
+ drivers/staging/bcm/Transmit.c                     |   14 +-
+ drivers/staging/bcm/cntrl_SignalingInterface.h     |    2 +-
+ drivers/staging/bcm/hostmibs.c                     |    6 +-
+ drivers/staging/bcm/led_control.c                  |   22 +-
+ drivers/staging/bcm/nvm.c                          | 6460 +++++++++----------
+ drivers/staging/bcm/sort.c                         |   16 +-
+ drivers/staging/bcm/vendorspecificextn.c           |    6 +-
+ drivers/staging/bcm/vendorspecificextn.h           |    6 +-
+ drivers/staging/ccg/Kconfig                        |    2 +-
+ drivers/staging/comedi/Kconfig                     |  153 +-
+ drivers/staging/comedi/comedi_compat32.c           |    2 +
+ drivers/staging/comedi/comedi_compat32.h           |    6 +-
+ drivers/staging/comedi/comedi_fops.c               |  431 +-
+ drivers/staging/comedi/comedi_fops.h               |   11 -
+ .../comedi/{internal.h => comedi_internal.h}       |    9 +
+ drivers/staging/comedi/comedidev.h                 |   42 +-
+ drivers/staging/comedi/drivers.c                   |  134 +-
+ drivers/staging/comedi/drivers/8255.c              |  203 +-
+ drivers/staging/comedi/drivers/8255.h              |    8 +-
+ drivers/staging/comedi/drivers/Makefile            |    3 +-
+ drivers/staging/comedi/drivers/acl7225b.c          |   29 +-
+ .../comedi/drivers/addi-data/addi_amcc_s5933.h     |    6 -
+ .../staging/comedi/drivers/addi-data/addi_common.c |    5 +-
+ .../comedi/drivers/addi-data/amcc_s5933_58.h       |    4 -
+ .../comedi/drivers/addi-data/hwdrv_APCI1710.c      |    5 +-
+ drivers/staging/comedi/drivers/adl_pci6208.c       |   10 +-
+ drivers/staging/comedi/drivers/adl_pci7230.c       |   70 +-
+ drivers/staging/comedi/drivers/adl_pci7296.c       |  127 +-
+ drivers/staging/comedi/drivers/adl_pci7432.c       |  129 +-
+ drivers/staging/comedi/drivers/adl_pci8164.c       |  156 +-
+ drivers/staging/comedi/drivers/adl_pci9111.c       |  116 +-
+ drivers/staging/comedi/drivers/adl_pci9118.c       |  112 +-
+ drivers/staging/comedi/drivers/adq12b.c            |   33 +-
+ drivers/staging/comedi/drivers/adv_pci1710.c       |   27 +-
+ drivers/staging/comedi/drivers/adv_pci1723.c       |   10 +-
+ drivers/staging/comedi/drivers/adv_pci_dio.c       |   25 +-
+ drivers/staging/comedi/drivers/aio_aio12_8.c       |   11 +-
+ drivers/staging/comedi/drivers/aio_iiro_16.c       |   21 +-
+ drivers/staging/comedi/drivers/amplc_dio200.c      |  510 +-
+ drivers/staging/comedi/drivers/amplc_pc236.c       |  641 +-
+ drivers/staging/comedi/drivers/amplc_pc263.c       |  529 +-
+ drivers/staging/comedi/drivers/amplc_pci224.c      |  137 +-
+ drivers/staging/comedi/drivers/amplc_pci230.c      | 1734 +++---
+ drivers/staging/comedi/drivers/c6xdigio.c          |    4 +-
+ drivers/staging/comedi/drivers/cb_das16_cs.c       |  579 +-
+ drivers/staging/comedi/drivers/cb_pcidas.c         |   40 +-
+ drivers/staging/comedi/drivers/cb_pcidas64.c       |   39 +-
+ drivers/staging/comedi/drivers/cb_pcidda.c         |   24 +-
+ drivers/staging/comedi/drivers/cb_pcidio.c         |   20 +-
+ drivers/staging/comedi/drivers/cb_pcimdas.c        |   32 +-
+ drivers/staging/comedi/drivers/cb_pcimdda.c        |   11 +-
+ drivers/staging/comedi/drivers/comedi_bond.c       |   12 +-
+ drivers/staging/comedi/drivers/comedi_parport.c    |   16 +-
+ drivers/staging/comedi/drivers/comedi_pci.h        |   60 -
+ drivers/staging/comedi/drivers/comedi_test.c       |   20 +-
+ drivers/staging/comedi/drivers/contec_pci_dio.c    |   28 +-
+ drivers/staging/comedi/drivers/daqboard2000.c      |   36 +-
+ drivers/staging/comedi/drivers/das08.c             |  960 +--
+ drivers/staging/comedi/drivers/das08_cs.c          |    7 +-
+ drivers/staging/comedi/drivers/das16.c             |  114 +-
+ drivers/staging/comedi/drivers/das16m1.c           |   17 +-
+ drivers/staging/comedi/drivers/das1800.c           | 1203 ++--
+ drivers/staging/comedi/drivers/das6402.c           |   14 +-
+ drivers/staging/comedi/drivers/das800.c            |   51 +-
+ drivers/staging/comedi/drivers/dmm32at.c           |   53 +-
+ drivers/staging/comedi/drivers/dt2801.c            |   14 +-
+ drivers/staging/comedi/drivers/dt2811.c            |   25 +-
+ drivers/staging/comedi/drivers/dt2814.c            |    4 +-
+ drivers/staging/comedi/drivers/dt2815.c            |    7 +-
+ drivers/staging/comedi/drivers/dt2817.c            |    6 +-
+ drivers/staging/comedi/drivers/dt282x.c            |   21 +-
+ drivers/staging/comedi/drivers/dt3000.c            |   41 +-
+ drivers/staging/comedi/drivers/dt9812.c            |    7 +-
+ drivers/staging/comedi/drivers/dyna_pci10xx.c      |   21 +-
+ drivers/staging/comedi/drivers/fl512.c             |    6 +-
+ drivers/staging/comedi/drivers/gsc_hpdi.c          |   21 +-
+ drivers/staging/comedi/drivers/icp_multi.c         |   12 +-
+ drivers/staging/comedi/drivers/icp_multi.h         |    1 -
+ drivers/staging/comedi/drivers/ii_pci20kc.c        |   16 +-
+ drivers/staging/comedi/drivers/jr3_pci.c           |   25 +-
+ drivers/staging/comedi/drivers/ke_counter.c        |    7 +-
+ drivers/staging/comedi/drivers/me4000.c            |  405 +-
+ drivers/staging/comedi/drivers/me4000.h            |   37 -
+ drivers/staging/comedi/drivers/me_daq.c            |    9 +-
+ drivers/staging/comedi/drivers/mite.c              |    1 -
+ drivers/staging/comedi/drivers/mpc624.c            |    7 +-
+ drivers/staging/comedi/drivers/mpc8260cpm.c        |    8 +-
+ drivers/staging/comedi/drivers/multiq3.c           |   15 +-
+ drivers/staging/comedi/drivers/ni_6527.c           |   18 +-
+ drivers/staging/comedi/drivers/ni_65xx.c           |   12 +-
+ drivers/staging/comedi/drivers/ni_660x.c           |    9 +-
+ drivers/staging/comedi/drivers/ni_670x.c           |   10 +-
+ drivers/staging/comedi/drivers/ni_at_a2150.c       |    6 +-
+ drivers/staging/comedi/drivers/ni_at_ao.c          |   20 +-
+ drivers/staging/comedi/drivers/ni_atmio16d.c       |   45 +-
+ drivers/staging/comedi/drivers/ni_daq_700.c        |  516 +-
+ drivers/staging/comedi/drivers/ni_daq_dio24.c      |    6 +-
+ drivers/staging/comedi/drivers/ni_labpc.c          |    8 +-
+ drivers/staging/comedi/drivers/ni_mio_common.c     |   23 +-
+ drivers/staging/comedi/drivers/ni_pcidio.c         |    8 +-
+ drivers/staging/comedi/drivers/ni_pcimio.c         |    4 +-
+ drivers/staging/comedi/drivers/pcl711.c            |   39 +-
+ drivers/staging/comedi/drivers/pcl724.c            |   28 +-
+ drivers/staging/comedi/drivers/pcl725.c            |   16 +-
+ drivers/staging/comedi/drivers/pcl726.c            |   49 +-
+ drivers/staging/comedi/drivers/pcl730.c            |   29 +-
+ drivers/staging/comedi/drivers/pcl812.c            |  239 +-
+ drivers/staging/comedi/drivers/pcl816.c            |   94 +-
+ drivers/staging/comedi/drivers/pcl818.c            |  113 +-
+ drivers/staging/comedi/drivers/pcm3724.c           |   20 +-
+ drivers/staging/comedi/drivers/pcm3730.c           |   14 +-
+ drivers/staging/comedi/drivers/pcmad.c             |   14 +-
+ drivers/staging/comedi/drivers/pcmda12.c           |   27 +-
+ drivers/staging/comedi/drivers/pcmmio.c            |   80 +-
+ drivers/staging/comedi/drivers/pcmuio.c            |   81 +-
+ drivers/staging/comedi/drivers/poc.c               |   45 +-
+ drivers/staging/comedi/drivers/quatech_daqp_cs.c   |    4 +-
+ drivers/staging/comedi/drivers/rtd520.c            | 2252 ++++---
+ drivers/staging/comedi/drivers/rti800.c            |   20 +-
+ drivers/staging/comedi/drivers/rti802.c            |    9 +-
+ drivers/staging/comedi/drivers/s526.c              |   36 +-
+ drivers/staging/comedi/drivers/s626.c              | 3092 +++++-----
+ drivers/staging/comedi/drivers/s626.h              |   10 -
+ drivers/staging/comedi/drivers/serial2002.c        |   30 +-
+ drivers/staging/comedi/drivers/skel.c              |   17 +-
+ drivers/staging/comedi/drivers/ssv_dnp.c           |   41 +-
+ drivers/staging/comedi/drivers/unioxx5.c           |    8 +-
+ drivers/staging/comedi/drivers/usbdux.c            |  523 +-
+ drivers/staging/comedi/drivers/usbduxfast.c        |  352 +-
+ drivers/staging/comedi/drivers/usbduxsigma.c       |  466 +-
+ drivers/staging/comedi/drivers/vmk80xx.c           |  193 +-
+ drivers/staging/comedi/proc.c                      |    2 +-
+ drivers/staging/comedi/range.c                     |    2 +-
+ drivers/staging/cptm1217/clearpad_tm1217.c         |    4 +-
+ drivers/staging/csr/Kconfig                        |    9 +
+ drivers/staging/csr/LICENSE.txt                    |   39 +
+ drivers/staging/csr/Makefile                       |   80 +
+ drivers/staging/csr/bh.c                           |  391 ++
+ drivers/staging/csr/csr_formatted_io.c             |   29 +
+ drivers/staging/csr/csr_formatted_io.h             |   25 +
+ drivers/staging/csr/csr_framework_ext.c            |  248 +
+ drivers/staging/csr/csr_framework_ext.h            |  354 ++
+ drivers/staging/csr/csr_framework_ext_types.h      |   65 +
+ drivers/staging/csr/csr_lib.h                      |  189 +
+ drivers/staging/csr/csr_log.h                      |  250 +
+ drivers/staging/csr/csr_log_configure.h            |  135 +
+ drivers/staging/csr/csr_log_text.h                 |  133 +
+ drivers/staging/csr/csr_macro.h                    |  111 +
+ drivers/staging/csr/csr_msg_transport.h            |   25 +
+ drivers/staging/csr/csr_msgconv.c                  |  324 +
+ drivers/staging/csr/csr_msgconv.h                  |  145 +
+ drivers/staging/csr/csr_panic.c                    |   22 +
+ drivers/staging/csr/csr_panic.h                    |   55 +
+ drivers/staging/csr/csr_pmem.c                     |   51 +
+ drivers/staging/csr/csr_pmem.h                     |  143 +
+ drivers/staging/csr/csr_prim_defs.h                |   64 +
+ drivers/staging/csr/csr_result.h                   |   27 +
+ drivers/staging/csr/csr_sched.h                    |  292 +
+ drivers/staging/csr/csr_sdio.h                     |  732 +++
+ .../staging/csr/csr_serialize_primitive_types.c    |  472 ++
+ drivers/staging/csr/csr_time.c                     |   71 +
+ drivers/staging/csr/csr_time.h                     |  205 +
+ drivers/staging/csr/csr_types.h                    |   94 +
+ drivers/staging/csr/csr_unicode.h                  |  190 +
+ drivers/staging/csr/csr_utf16.c                    | 1136 ++++
+ drivers/staging/csr/csr_util.c                     |  443 ++
+ drivers/staging/csr/csr_util.h                     |  102 +
+ drivers/staging/csr/csr_wifi_common.h              |  109 +
+ drivers/staging/csr/csr_wifi_fsm.h                 |  250 +
+ drivers/staging/csr/csr_wifi_fsm_event.h           |   51 +
+ drivers/staging/csr/csr_wifi_fsm_types.h           |  441 ++
+ drivers/staging/csr/csr_wifi_hip_card.h            |  123 +
+ drivers/staging/csr/csr_wifi_hip_card_sdio.c       | 4185 +++++++++++++
+ drivers/staging/csr/csr_wifi_hip_card_sdio.h       |  702 +++
+ drivers/staging/csr/csr_wifi_hip_card_sdio_intr.c  | 2579 ++++++++
+ drivers/staging/csr/csr_wifi_hip_card_sdio_mem.c   | 1713 +++++
+ drivers/staging/csr/csr_wifi_hip_chiphelper.c      |  793 +++
+ drivers/staging/csr/csr_wifi_hip_chiphelper.h      |  471 ++
+ .../staging/csr/csr_wifi_hip_chiphelper_private.h  |  208 +
+ drivers/staging/csr/csr_wifi_hip_conversions.h     |   81 +
+ drivers/staging/csr/csr_wifi_hip_download.c        |  834 +++
+ drivers/staging/csr/csr_wifi_hip_dump.c            |  872 +++
+ drivers/staging/csr/csr_wifi_hip_packing.c         | 4804 +++++++++++++++
+ drivers/staging/csr/csr_wifi_hip_send.c            |  422 ++
+ drivers/staging/csr/csr_wifi_hip_signals.c         | 1313 ++++
+ drivers/staging/csr/csr_wifi_hip_signals.h         |  137 +
+ drivers/staging/csr/csr_wifi_hip_sigs.h            | 1425 +++++
+ drivers/staging/csr/csr_wifi_hip_ta_sampling.c     |  541 ++
+ drivers/staging/csr/csr_wifi_hip_ta_sampling.h     |   75 +
+ drivers/staging/csr/csr_wifi_hip_udi.c             |  268 +
+ drivers/staging/csr/csr_wifi_hip_unifi.h           |  882 +++
+ .../staging/csr/csr_wifi_hip_unifi_signal_names.c  |   46 +
+ drivers/staging/csr/csr_wifi_hip_unifi_udi.h       |   76 +
+ drivers/staging/csr/csr_wifi_hip_unifihw.h         |   67 +
+ drivers/staging/csr/csr_wifi_hip_unifiversion.h    |   38 +
+ drivers/staging/csr/csr_wifi_hip_xbv.c             | 1075 ++++
+ drivers/staging/csr/csr_wifi_hip_xbv.h             |  127 +
+ drivers/staging/csr/csr_wifi_hostio_prim.h         |   27 +
+ drivers/staging/csr/csr_wifi_lib.h                 |  113 +
+ drivers/staging/csr/csr_wifi_msgconv.h             |   60 +
+ .../staging/csr/csr_wifi_nme_ap_converter_init.c   |   91 +
+ .../staging/csr/csr_wifi_nme_ap_converter_init.h   |   49 +
+ .../csr/csr_wifi_nme_ap_free_downstream_contents.c |   85 +
+ .../csr/csr_wifi_nme_ap_free_upstream_contents.c   |   40 +
+ drivers/staging/csr/csr_wifi_nme_ap_lib.h          |  525 ++
+ drivers/staging/csr/csr_wifi_nme_ap_prim.h         |  503 ++
+ drivers/staging/csr/csr_wifi_nme_ap_sef.c          |   30 +
+ drivers/staging/csr/csr_wifi_nme_ap_sef.h          |   31 +
+ drivers/staging/csr/csr_wifi_nme_ap_serialize.c    |  910 +++
+ drivers/staging/csr/csr_wifi_nme_ap_serialize.h    |  105 +
+ drivers/staging/csr/csr_wifi_nme_converter_init.h  |   46 +
+ drivers/staging/csr/csr_wifi_nme_lib.h             | 1056 ++++
+ drivers/staging/csr/csr_wifi_nme_prim.h            | 1666 +++++
+ drivers/staging/csr/csr_wifi_nme_serialize.h       |  177 +
+ drivers/staging/csr/csr_wifi_nme_task.h            |   38 +
+ drivers/staging/csr/csr_wifi_private_common.h      |   91 +
+ drivers/staging/csr/csr_wifi_result.h              |   36 +
+ .../staging/csr/csr_wifi_router_converter_init.c   |   83 +
+ .../staging/csr/csr_wifi_router_converter_init.h   |   42 +
+ .../csr/csr_wifi_router_ctrl_converter_init.c      |  136 +
+ .../csr/csr_wifi_router_ctrl_converter_init.h      |   42 +
+ ...csr_wifi_router_ctrl_free_downstream_contents.c |  109 +
+ .../csr_wifi_router_ctrl_free_upstream_contents.c  |   88 +
+ drivers/staging/csr/csr_wifi_router_ctrl_lib.h     | 2094 +++++++
+ drivers/staging/csr/csr_wifi_router_ctrl_prim.h    | 2122 +++++++
+ drivers/staging/csr/csr_wifi_router_ctrl_sef.c     |   45 +
+ drivers/staging/csr/csr_wifi_router_ctrl_sef.h     |   58 +
+ .../staging/csr/csr_wifi_router_ctrl_serialize.c   | 2594 ++++++++
+ .../staging/csr/csr_wifi_router_ctrl_serialize.h   |  343 +
+ .../csr/csr_wifi_router_free_downstream_contents.c |   54 +
+ .../csr/csr_wifi_router_free_upstream_contents.c   |   54 +
+ drivers/staging/csr/csr_wifi_router_lib.h          |  429 ++
+ drivers/staging/csr/csr_wifi_router_prim.h         |  430 ++
+ drivers/staging/csr/csr_wifi_router_sef.c          |   19 +
+ drivers/staging/csr/csr_wifi_router_sef.h          |   33 +
+ drivers/staging/csr/csr_wifi_router_serialize.c    |  422 ++
+ drivers/staging/csr/csr_wifi_router_serialize.h    |   78 +
+ drivers/staging/csr/csr_wifi_router_task.h         |   34 +
+ drivers/staging/csr/csr_wifi_router_transport.c    |  210 +
+ .../csr/csr_wifi_serialize_primitive_types.c       |  257 +
+ drivers/staging/csr/csr_wifi_sme_ap_lib.h          |  785 +++
+ drivers/staging/csr/csr_wifi_sme_ap_prim.h         | 1039 ++++
+ drivers/staging/csr/csr_wifi_sme_converter_init.c  |  202 +
+ drivers/staging/csr/csr_wifi_sme_converter_init.h  |   42 +
+ .../csr/csr_wifi_sme_free_downstream_contents.c    |  188 +
+ .../csr/csr_wifi_sme_free_upstream_contents.c      |  276 +
+ drivers/staging/csr/csr_wifi_sme_lib.h             | 4315 +++++++++++++
+ drivers/staging/csr/csr_wifi_sme_prim.h            | 6519 ++++++++++++++++++++
+ drivers/staging/csr/csr_wifi_sme_sef.c             |   85 +
+ drivers/staging/csr/csr_wifi_sme_sef.h             |  101 +
+ drivers/staging/csr/csr_wifi_sme_serialize.c       | 5812 +++++++++++++++++
+ drivers/staging/csr/csr_wifi_sme_serialize.h       |  673 ++
+ drivers/staging/csr/csr_wifi_sme_task.h            |   34 +
+ drivers/staging/csr/csr_wifi_vif_utils.h           |  108 +
+ drivers/staging/csr/data_tx.c                      |   57 +
+ drivers/staging/csr/drv.c                          | 2263 +++++++
+ drivers/staging/csr/firmware.c                     |  414 ++
+ drivers/staging/csr/indications.c                  |   18 +
+ drivers/staging/csr/inet.c                         |  106 +
+ drivers/staging/csr/init_hw.c                      |  108 +
+ drivers/staging/csr/io.c                           | 1166 ++++
+ drivers/staging/csr/mlme.c                         |  441 ++
+ drivers/staging/csr/monitor.c                      |  458 ++
+ drivers/staging/csr/netdev.c                       | 3998 ++++++++++++
+ drivers/staging/csr/os.c                           |  483 ++
+ drivers/staging/csr/oska/Makefile                  |   12 +
+ drivers/staging/csr/oska/all.h                     |   61 +
+ drivers/staging/csr/oska/alloc.h                   |   41 +
+ drivers/staging/csr/oska/compat.c                  |   54 +
+ drivers/staging/csr/oska/event.c                   |   82 +
+ drivers/staging/csr/oska/event.h                   |   33 +
+ drivers/staging/csr/oska/io.h                      |   63 +
+ drivers/staging/csr/oska/kernel-compat.h           |  199 +
+ drivers/staging/csr/oska/list.c                    |  103 +
+ drivers/staging/csr/oska/list.h                    |  115 +
+ drivers/staging/csr/oska/mutex.h                   |   42 +
+ drivers/staging/csr/oska/oska_module.c             |   21 +
+ drivers/staging/csr/oska/print.c                   |   44 +
+ drivers/staging/csr/oska/print.h                   |   32 +
+ drivers/staging/csr/oska/refcount.c                |   47 +
+ drivers/staging/csr/oska/refcount.h                |   86 +
+ drivers/staging/csr/oska/semaphore.h               |   70 +
+ drivers/staging/csr/oska/spinlock.h                |   43 +
+ drivers/staging/csr/oska/thread.c                  |   66 +
+ drivers/staging/csr/oska/thread.h                  |   39 +
+ drivers/staging/csr/oska/time.h                    |   34 +
+ drivers/staging/csr/oska/timer.c                   |   28 +
+ drivers/staging/csr/oska/timer.h                   |   40 +
+ drivers/staging/csr/oska/trace.h                   |   23 +
+ drivers/staging/csr/oska/types.h                   |   14 +
+ drivers/staging/csr/oska/util.h                    |   48 +
+ drivers/staging/csr/putest.c                       |  685 ++
+ drivers/staging/csr/sdio_emb.c                     |  891 +++
+ drivers/staging/csr/sdio_events.c                  |  134 +
+ drivers/staging/csr/sdio_mmc.c                     | 1340 ++++
+ drivers/staging/csr/sdio_stubs.c                   |   82 +
+ drivers/staging/csr/sdioemb/cspi.h                 |   62 +
+ drivers/staging/csr/sdioemb/csr_result.h           |   16 +
+ drivers/staging/csr/sdioemb/csr_sdio.h             |  711 +++
+ drivers/staging/csr/sdioemb/csr_sdio_lib.h         |   30 +
+ drivers/staging/csr/sdioemb/csr_sdio_wdf.h         |   22 +
+ drivers/staging/csr/sdioemb/csr_types.h            |   53 +
+ drivers/staging/csr/sdioemb/libsdio.h              |  404 ++
+ drivers/staging/csr/sdioemb/linux.h                |   16 +
+ drivers/staging/csr/sdioemb/sdio.h                 |  117 +
+ drivers/staging/csr/sdioemb/sdio_api.h             |  408 ++
+ drivers/staging/csr/sdioemb/sdio_bt_a.h            |  143 +
+ drivers/staging/csr/sdioemb/sdio_cis.h             |   27 +
+ drivers/staging/csr/sdioemb/sdio_csr.h             |  134 +
+ drivers/staging/csr/sdioemb/slot_api.h             |  313 +
+ drivers/staging/csr/sdioemb/slot_imx27.h           |   86 +
+ drivers/staging/csr/sdioemb/slot_imx31.h           |   86 +
+ drivers/staging/csr/sdioemb/slot_pxa27x.h          |   70 +
+ drivers/staging/csr/sdioemb/slot_shc.h             |  223 +
+ drivers/staging/csr/sdioemb/slot_ushc.h            |  133 +
+ drivers/staging/csr/sdioemb/trace.h                |   19 +
+ drivers/staging/csr/sdioemb/uif.h                  |   41 +
+ drivers/staging/csr/sdioemb/version.h              |   11 +
+ drivers/staging/csr/sme_blocking.c                 | 1535 +++++
+ drivers/staging/csr/sme_mgt.c                      | 1018 +++
+ drivers/staging/csr/sme_native.c                   |  591 ++
+ drivers/staging/csr/sme_sys.c                      | 3268 ++++++++++
+ drivers/staging/csr/sme_userspace.c                |  315 +
+ drivers/staging/csr/sme_userspace.h                |   38 +
+ drivers/staging/csr/sme_wext.c                     | 3396 ++++++++++
+ drivers/staging/csr/ul_int.c                       |  533 ++
+ drivers/staging/csr/unifi_clients.h                |  129 +
+ drivers/staging/csr/unifi_config.h                 |   34 +
+ drivers/staging/csr/unifi_dbg.c                    |  110 +
+ drivers/staging/csr/unifi_event.c                  |  700 +++
+ drivers/staging/csr/unifi_native.h                 |  276 +
+ drivers/staging/csr/unifi_os.h                     |  145 +
+ drivers/staging/csr/unifi_pdu_processing.c         | 3751 +++++++++++
+ drivers/staging/csr/unifi_priv.h                   | 1190 ++++
+ drivers/staging/csr/unifi_sme.c                    | 1244 ++++
+ drivers/staging/csr/unifi_sme.h                    |  245 +
+ drivers/staging/csr/unifi_wext.h                   |  124 +
+ drivers/staging/csr/unifiio.h                      |  399 ++
+ drivers/staging/csr/wext_events.c                  |  285 +
+ drivers/staging/et131x/et131x.c                    |   17 +-
+ drivers/staging/ft1000/ft1000-usb/ft1000_hw.c      |    5 +-
+ drivers/staging/ft1000/ft1000-usb/ft1000_usb.c     |    6 +-
+ drivers/staging/gdm72xx/gdm_qos.c                  |    1 -
+ drivers/staging/gdm72xx/gdm_sdio.c                 |    1 -
+ drivers/staging/gdm72xx/gdm_usb.c                  |   24 +-
+ drivers/staging/gdm72xx/gdm_wimax.c                |    1 -
+ drivers/staging/gdm72xx/gdm_wimax.h                |    1 -
+ drivers/staging/gdm72xx/netlink_k.c                |   11 +-
+ drivers/staging/gdm72xx/sdio_boot.c                |    1 -
+ drivers/staging/gdm72xx/usb_boot.c                 |    1 -
+ drivers/staging/iio/Documentation/device.txt       |   10 +-
+ drivers/staging/iio/Documentation/generic_buffer.c |   71 +-
+ .../staging/iio/Documentation/iio_event_monitor.c  |    2 +
+ drivers/staging/iio/Documentation/iio_utils.h      |    7 +-
+ drivers/staging/iio/Documentation/overview.txt     |    2 +-
+ drivers/staging/iio/Documentation/ring.txt         |    4 +-
+ .../staging/iio/Documentation/sysfs-bus-iio-light  |    2 +-
+ drivers/staging/iio/Kconfig                        |    1 -
+ drivers/staging/iio/Makefile                       |    1 -
+ drivers/staging/iio/accel/adis16209_core.c         |    2 -
+ drivers/staging/iio/accel/adis16220_core.c         |    2 -
+ drivers/staging/iio/accel/adis16240_core.c         |    2 -
+ drivers/staging/iio/adc/Kconfig                    |   19 +-
+ drivers/staging/iio/adc/ad7192.c                   |   49 +-
+ drivers/staging/iio/adc/ad7298.h                   |    5 +
+ drivers/staging/iio/adc/ad7298_core.c              |   15 +-
+ drivers/staging/iio/adc/ad7298_ring.c              |   64 +-
+ drivers/staging/iio/adc/ad7476_core.c              |    9 -
+ drivers/staging/iio/adc/ad7476_ring.c              |   46 +-
+ drivers/staging/iio/adc/ad7606_core.c              |    9 -
+ drivers/staging/iio/adc/ad7606_ring.c              |   46 +-
+ drivers/staging/iio/adc/ad7793.c                   |   49 +-
+ drivers/staging/iio/adc/ad7887_core.c              |    9 -
+ drivers/staging/iio/adc/ad7887_ring.c              |   35 +-
+ drivers/staging/iio/adc/ad799x.h                   |    2 -
+ drivers/staging/iio/adc/ad799x_core.c              |   25 +-
+ drivers/staging/iio/adc/ad799x_ring.c              |   65 +-
+ drivers/staging/iio/dac/ad5504.h                   |   65 -
+ drivers/staging/iio/dac/ad5791.h                   |  112 -
+ drivers/staging/iio/dac/dac.h                      |    6 -
+ drivers/staging/iio/gyro/adis16080_core.c          |    2 +-
+ drivers/staging/iio/gyro/adis16260_core.c          |    2 -
+ drivers/staging/iio/iio_simple_dummy.c             |   10 +-
+ drivers/staging/iio/iio_simple_dummy_buffer.c      |   15 +-
+ drivers/staging/iio/imu/adis16400.h                |    3 +-
+ drivers/staging/iio/imu/adis16400_core.c           |   14 +-
+ drivers/staging/iio/light/isl29018.c               |   16 +-
+ drivers/staging/iio/light/tsl2583.c                |    2 +-
+ drivers/staging/iio/light/tsl2x7x_core.c           |    3 +-
+ drivers/staging/iio/magnetometer/Kconfig           |    2 +-
+ drivers/staging/iio/magnetometer/ak8975.c          |   98 +-
+ drivers/staging/iio/magnetometer/hmc5843.c         |    6 +-
+ drivers/staging/iio/ring_sw.c                      |    4 +-
+ drivers/staging/iio/trigger/iio-trig-bfin-timer.c  |    4 +-
+ .../staging/iio/trigger/iio-trig-periodic-rtc.c    |    4 +-
+ drivers/staging/iio/trigger/iio-trig-sysfs.c       |    2 +-
+ drivers/staging/ipack/TODO                         |    4 -
+ drivers/staging/ipack/bridges/tpci200.c            |  473 +-
+ drivers/staging/ipack/bridges/tpci200.h            |    5 -
+ drivers/staging/ipack/devices/ipoctal.c            |   58 +-
+ drivers/staging/ipack/devices/ipoctal.h            |   39 -
+ drivers/staging/ipack/ipack.c                      |   46 +-
+ drivers/staging/keucr/init.c                       |    3 +-
+ drivers/staging/keucr/scsiglue.c                   |   11 +-
+ drivers/staging/nvec/Kconfig                       |    9 +-
+ drivers/staging/nvec/Makefile                      |    2 +-
+ drivers/staging/nvec/nvec.c                        |   77 +-
+ drivers/staging/nvec/nvec_kbd.c                    |   16 +-
+ drivers/staging/nvec/{nvec_leds.c => nvec_paz00.c} |   46 +-
+ drivers/staging/nvec/nvec_power.c                  |   32 +-
+ drivers/staging/nvec/nvec_ps2.c                    |   35 +-
+ drivers/staging/omapdrm/omap_dmm_priv.h            |    1 -
+ drivers/staging/omapdrm/omap_dmm_tiler.c           |   44 +-
+ drivers/staging/ozwpan/TODO                        |   11 +-
+ drivers/staging/ozwpan/ozappif.h                   |    6 +-
+ drivers/staging/ozwpan/ozcdev.c                    |   28 +-
+ drivers/staging/ozwpan/ozmain.c                    |    2 +-
+ drivers/staging/ozwpan/ozpd.c                      |  182 +-
+ drivers/staging/ozwpan/ozpd.h                      |    3 +-
+ drivers/staging/ozwpan/ozproto.c                   |    6 +-
+ drivers/staging/ozwpan/ozprotocol.h                |    1 +
+ drivers/staging/ramster/r2net.c                    |    4 +-
+ drivers/staging/rtl8187se/r8180_wx.c               |    4 +-
+ drivers/staging/rtl8192e/rtl8192e/rtl_wx.c         |    4 +-
+ drivers/staging/rtl8712/usb_intf.c                 |    4 +-
+ drivers/staging/rts5139/rts51x_chip.c              |    5 +-
+ drivers/staging/rts5139/rts51x_chip.h              |    2 +-
+ drivers/staging/rts5139/rts51x_fop.c               |    1 -
+ drivers/staging/rts5139/rts51x_scsi.h              |    2 +-
+ drivers/staging/rts5139/sd_cprm.c                  |    8 +-
+ drivers/staging/rts_pstor/ms.c                     |    2 +-
+ drivers/staging/rts_pstor/sd.c                     |    2 +-
+ drivers/staging/sbe-2t3e3/dc.c                     |    2 +-
+ drivers/staging/sbe-2t3e3/io.c                     |    2 +-
+ drivers/staging/sep/sep_crypto.c                   |   22 +-
+ drivers/staging/sep/sep_driver_api.h               |    8 +-
+ drivers/staging/sep/sep_driver_config.h            |    4 +-
+ drivers/staging/sep/sep_main.c                     |   73 +-
+ drivers/staging/serqt_usb2/serqt_usb2.c            |    4 +-
+ drivers/staging/slicoss/slicoss.c                  |    2 +-
+ drivers/staging/sm7xx/Kconfig                      |    8 -
+ drivers/staging/sm7xx/Makefile                     |    3 -
+ drivers/staging/sm7xxfb/Kconfig                    |   13 +
+ drivers/staging/sm7xxfb/Makefile                   |    1 +
+ drivers/staging/{sm7xx => sm7xxfb}/TODO            |    2 +-
+ .../staging/{sm7xx/smtcfb.h => sm7xxfb/sm7xx.h}    |    1 -
+ .../staging/{sm7xx/smtcfb.c => sm7xxfb/sm7xxfb.c}  |  129 +-
+ drivers/staging/speakup/main.c                     |    2 +-
+ drivers/staging/speakup/selection.c                |    6 +-
+ drivers/staging/usbip/userspace/src/Makefile.am    |    5 +-
+ drivers/staging/usbip/vhci.h                       |    7 +-
+ drivers/staging/usbip/vhci_hcd.c                   |   39 +-
+ drivers/staging/vt6656/iwctl.c                     | 2038 +++---
+ drivers/staging/vt6656/iwctl.h                     |  262 +-
+ drivers/staging/winbond/mds_s.h                    |    2 +-
+ drivers/staging/winbond/mto.c                      |    2 +-
+ drivers/staging/wlags49_h2/hcf.c                   |    8 +-
+ drivers/staging/wlags49_h2/wl_main.c               |    4 +-
+ drivers/staging/wlan-ng/cfg80211.c                 |   20 +-
+ drivers/staging/wlan-ng/prism2fw.c                 |  134 +-
+ drivers/staging/xgifb/XGI_main.h                   |    8 -
+ drivers/staging/xgifb/XGI_main_26.c                |  289 +-
+ drivers/staging/xgifb/XGIfb.h                      |    3 -
+ drivers/staging/xgifb/vb_def.h                     |   19 +
+ drivers/staging/xgifb/vb_init.c                    |  317 +-
+ drivers/staging/xgifb/vb_setmode.c                 |  158 +-
+ drivers/staging/xgifb/vb_struct.h                  |   74 +-
+ drivers/staging/xgifb/vb_table.h                   |  208 +-
+ drivers/staging/xgifb/vb_util.c                    |    8 -
+ drivers/staging/xgifb/vgatypes.h                   |    1 -
+ drivers/staging/zcache/Kconfig                     |    5 +-
+ drivers/staging/zcache/zcache-main.c               |   50 +-
+ drivers/staging/zram/Kconfig                       |    5 +-
+ drivers/staging/zram/zram_drv.c                    |  127 +-
+ drivers/staging/zram/zram_drv.h                    |   21 +-
+ drivers/staging/zram/zram_sysfs.c                  |    6 +-
+ drivers/staging/zsmalloc/zsmalloc-main.c           |  113 +-
+ drivers/staging/zsmalloc/zsmalloc.h                |    8 +-
+ fs/pstore/Kconfig                                  |    7 +
+ fs/pstore/inode.c                                  |    3 +
+ fs/pstore/platform.c                               |   54 +-
+ fs/pstore/ram.c                                    |  307 +-
+ fs/pstore/ram_core.c                               |  126 +-
+ include/linux/Kbuild                               |    1 -
+ include/linux/if_strip.h                           |   27 -
+ include/linux/iio/buffer.h                         |    2 +-
+ .../staging => include/linux}/iio/dac/ad5421.h     |    4 -
+ include/linux/iio/dac/ad5504.h                     |   16 +
+ include/linux/iio/dac/ad5791.h                     |   25 +
+ .../staging => include/linux}/iio/dac/max517.h     |    4 -
+ include/linux/iio/dac/mcp4725.h                    |   16 +
+ include/linux/iio/events.h                         |    6 +-
+ include/linux/iio/frequency/ad9523.h               |  195 +
+ include/linux/iio/frequency/adf4350.h              |  126 +
+ include/linux/iio/iio.h                            |  104 +-
+ include/linux/iio/machine.h                        |    2 +-
+ include/linux/iio/sysfs.h                          |    2 +-
+ include/linux/iio/triggered_buffer.h               |   15 +
+ include/linux/iio/types.h                          |    1 -
+ include/linux/pstore.h                             |    1 +
+ include/linux/pstore_ram.h                         |   26 +-
+ 578 files changed, 122353 insertions(+), 19550 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
+ create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
+ create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-light-lm3533-als
+ rename drivers/{staging => }/iio/dac/Kconfig (89%)
+ rename drivers/{staging => }/iio/dac/Makefile (92%)
+ rename drivers/{staging => }/iio/dac/ad5064.c (89%)
+ rename drivers/{staging => }/iio/dac/ad5360.c (99%)
+ rename drivers/{staging => }/iio/dac/ad5380.c (86%)
+ rename drivers/{staging => }/iio/dac/ad5421.c (99%)
+ rename drivers/{staging => }/iio/dac/ad5446.c (87%)
+ rename drivers/{staging => }/iio/dac/ad5446.h (99%)
+ rename drivers/{staging => }/iio/dac/ad5504.c (64%)
+ rename drivers/{staging => }/iio/dac/ad5624r.h (100%)
+ rename drivers/{staging => }/iio/dac/ad5624r_spi.c (68%)
+ rename drivers/{staging => }/iio/dac/ad5686.c (72%)
+ rename drivers/{staging => }/iio/dac/ad5764.c (99%)
+ rename drivers/{staging => }/iio/dac/ad5791.c (70%)
+ rename drivers/{staging => }/iio/dac/max517.c (52%)
+ create mode 100644 drivers/iio/dac/mcp4725.c
+ create mode 100644 drivers/iio/frequency/Kconfig
+ create mode 100644 drivers/iio/frequency/Makefile
+ create mode 100644 drivers/iio/frequency/ad9523.c
+ create mode 100644 drivers/iio/frequency/adf4350.c
+ create mode 100644 drivers/iio/industrialio-triggered-buffer.c
+ create mode 100644 drivers/iio/light/Kconfig
+ create mode 100644 drivers/iio/light/Makefile
+ create mode 100644 drivers/iio/light/lm3533-als.c
+ create mode 100644 drivers/iio/light/vcnl4000.c
+ delete mode 100644 drivers/staging/android/ram_console.c
+ delete mode 100644 drivers/staging/comedi/comedi_fops.h
+ rename drivers/staging/comedi/{internal.h => comedi_internal.h} (78%)
+ delete mode 100644 drivers/staging/comedi/drivers/comedi_pci.h
+ create mode 100644 drivers/staging/csr/Kconfig
+ create mode 100644 drivers/staging/csr/LICENSE.txt
+ create mode 100644 drivers/staging/csr/Makefile
+ create mode 100644 drivers/staging/csr/bh.c
+ create mode 100644 drivers/staging/csr/csr_formatted_io.c
+ create mode 100644 drivers/staging/csr/csr_formatted_io.h
+ create mode 100644 drivers/staging/csr/csr_framework_ext.c
+ create mode 100644 drivers/staging/csr/csr_framework_ext.h
+ create mode 100644 drivers/staging/csr/csr_framework_ext_types.h
+ create mode 100644 drivers/staging/csr/csr_lib.h
+ create mode 100644 drivers/staging/csr/csr_log.h
+ create mode 100644 drivers/staging/csr/csr_log_configure.h
+ create mode 100644 drivers/staging/csr/csr_log_text.h
+ create mode 100644 drivers/staging/csr/csr_macro.h
+ create mode 100644 drivers/staging/csr/csr_msg_transport.h
+ create mode 100644 drivers/staging/csr/csr_msgconv.c
+ create mode 100644 drivers/staging/csr/csr_msgconv.h
+ create mode 100644 drivers/staging/csr/csr_panic.c
+ create mode 100644 drivers/staging/csr/csr_panic.h
+ create mode 100644 drivers/staging/csr/csr_pmem.c
+ create mode 100644 drivers/staging/csr/csr_pmem.h
+ create mode 100644 drivers/staging/csr/csr_prim_defs.h
+ create mode 100644 drivers/staging/csr/csr_result.h
+ create mode 100644 drivers/staging/csr/csr_sched.h
+ create mode 100644 drivers/staging/csr/csr_sdio.h
+ create mode 100644 drivers/staging/csr/csr_serialize_primitive_types.c
+ create mode 100644 drivers/staging/csr/csr_time.c
+ create mode 100644 drivers/staging/csr/csr_time.h
+ create mode 100644 drivers/staging/csr/csr_types.h
+ create mode 100644 drivers/staging/csr/csr_unicode.h
+ create mode 100644 drivers/staging/csr/csr_utf16.c
+ create mode 100644 drivers/staging/csr/csr_util.c
+ create mode 100644 drivers/staging/csr/csr_util.h
+ create mode 100644 drivers/staging/csr/csr_wifi_common.h
+ create mode 100644 drivers/staging/csr/csr_wifi_fsm.h
+ create mode 100644 drivers/staging/csr/csr_wifi_fsm_event.h
+ create mode 100644 drivers/staging/csr/csr_wifi_fsm_types.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_card.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_card_sdio.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_card_sdio.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_card_sdio_intr.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_card_sdio_mem.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_chiphelper.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_chiphelper.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_chiphelper_private.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_conversions.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_download.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_dump.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_packing.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_send.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_signals.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_signals.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_sigs.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_ta_sampling.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_ta_sampling.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_udi.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_unifi.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_unifi_signal_names.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_unifi_udi.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_unifihw.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_unifiversion.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_xbv.c
+ create mode 100644 drivers/staging/csr/csr_wifi_hip_xbv.h
+ create mode 100644 drivers/staging/csr/csr_wifi_hostio_prim.h
+ create mode 100644 drivers/staging/csr/csr_wifi_lib.h
+ create mode 100644 drivers/staging/csr/csr_wifi_msgconv.h
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_ap_converter_init.c
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_ap_converter_init.h
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_ap_free_downstream_contents.c
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_ap_free_upstream_contents.c
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_ap_lib.h
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_ap_prim.h
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_ap_sef.c
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_ap_sef.h
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_ap_serialize.c
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_ap_serialize.h
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_converter_init.h
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_lib.h
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_prim.h
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_serialize.h
+ create mode 100644 drivers/staging/csr/csr_wifi_nme_task.h
+ create mode 100644 drivers/staging/csr/csr_wifi_private_common.h
+ create mode 100644 drivers/staging/csr/csr_wifi_result.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_converter_init.c
+ create mode 100644 drivers/staging/csr/csr_wifi_router_converter_init.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_ctrl_converter_init.c
+ create mode 100644 drivers/staging/csr/csr_wifi_router_ctrl_converter_init.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_ctrl_free_downstream_contents.c
+ create mode 100644 drivers/staging/csr/csr_wifi_router_ctrl_free_upstream_contents.c
+ create mode 100644 drivers/staging/csr/csr_wifi_router_ctrl_lib.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_ctrl_prim.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_ctrl_sef.c
+ create mode 100644 drivers/staging/csr/csr_wifi_router_ctrl_sef.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_ctrl_serialize.c
+ create mode 100644 drivers/staging/csr/csr_wifi_router_ctrl_serialize.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_free_downstream_contents.c
+ create mode 100644 drivers/staging/csr/csr_wifi_router_free_upstream_contents.c
+ create mode 100644 drivers/staging/csr/csr_wifi_router_lib.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_prim.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_sef.c
+ create mode 100644 drivers/staging/csr/csr_wifi_router_sef.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_serialize.c
+ create mode 100644 drivers/staging/csr/csr_wifi_router_serialize.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_task.h
+ create mode 100644 drivers/staging/csr/csr_wifi_router_transport.c
+ create mode 100644 drivers/staging/csr/csr_wifi_serialize_primitive_types.c
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_ap_lib.h
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_ap_prim.h
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_converter_init.c
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_converter_init.h
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_free_downstream_contents.c
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_free_upstream_contents.c
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_lib.h
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_prim.h
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_sef.c
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_sef.h
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_serialize.c
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_serialize.h
+ create mode 100644 drivers/staging/csr/csr_wifi_sme_task.h
+ create mode 100644 drivers/staging/csr/csr_wifi_vif_utils.h
+ create mode 100644 drivers/staging/csr/data_tx.c
+ create mode 100644 drivers/staging/csr/drv.c
+ create mode 100644 drivers/staging/csr/firmware.c
+ create mode 100644 drivers/staging/csr/indications.c
+ create mode 100644 drivers/staging/csr/inet.c
+ create mode 100644 drivers/staging/csr/init_hw.c
+ create mode 100644 drivers/staging/csr/io.c
+ create mode 100644 drivers/staging/csr/mlme.c
+ create mode 100644 drivers/staging/csr/monitor.c
+ create mode 100644 drivers/staging/csr/netdev.c
+ create mode 100644 drivers/staging/csr/os.c
+ create mode 100644 drivers/staging/csr/oska/Makefile
+ create mode 100644 drivers/staging/csr/oska/all.h
+ create mode 100644 drivers/staging/csr/oska/alloc.h
+ create mode 100644 drivers/staging/csr/oska/compat.c
+ create mode 100644 drivers/staging/csr/oska/event.c
+ create mode 100644 drivers/staging/csr/oska/event.h
+ create mode 100644 drivers/staging/csr/oska/io.h
+ create mode 100644 drivers/staging/csr/oska/kernel-compat.h
+ create mode 100644 drivers/staging/csr/oska/list.c
+ create mode 100644 drivers/staging/csr/oska/list.h
+ create mode 100644 drivers/staging/csr/oska/mutex.h
+ create mode 100644 drivers/staging/csr/oska/oska_module.c
+ create mode 100644 drivers/staging/csr/oska/print.c
+ create mode 100644 drivers/staging/csr/oska/print.h
+ create mode 100644 drivers/staging/csr/oska/refcount.c
+ create mode 100644 drivers/staging/csr/oska/refcount.h
+ create mode 100644 drivers/staging/csr/oska/semaphore.h
+ create mode 100644 drivers/staging/csr/oska/spinlock.h
+ create mode 100644 drivers/staging/csr/oska/thread.c
+ create mode 100644 drivers/staging/csr/oska/thread.h
+ create mode 100644 drivers/staging/csr/oska/time.h
+ create mode 100644 drivers/staging/csr/oska/timer.c
+ create mode 100644 drivers/staging/csr/oska/timer.h
+ create mode 100644 drivers/staging/csr/oska/trace.h
+ create mode 100644 drivers/staging/csr/oska/types.h
+ create mode 100644 drivers/staging/csr/oska/util.h
+ create mode 100644 drivers/staging/csr/putest.c
+ create mode 100644 drivers/staging/csr/sdio_emb.c
+ create mode 100644 drivers/staging/csr/sdio_events.c
+ create mode 100644 drivers/staging/csr/sdio_mmc.c
+ create mode 100644 drivers/staging/csr/sdio_stubs.c
+ create mode 100644 drivers/staging/csr/sdioemb/cspi.h
+ create mode 100644 drivers/staging/csr/sdioemb/csr_result.h
+ create mode 100644 drivers/staging/csr/sdioemb/csr_sdio.h
+ create mode 100644 drivers/staging/csr/sdioemb/csr_sdio_lib.h
+ create mode 100644 drivers/staging/csr/sdioemb/csr_sdio_wdf.h
+ create mode 100644 drivers/staging/csr/sdioemb/csr_types.h
+ create mode 100644 drivers/staging/csr/sdioemb/libsdio.h
+ create mode 100644 drivers/staging/csr/sdioemb/linux.h
+ create mode 100644 drivers/staging/csr/sdioemb/sdio.h
+ create mode 100644 drivers/staging/csr/sdioemb/sdio_api.h
+ create mode 100644 drivers/staging/csr/sdioemb/sdio_bt_a.h
+ create mode 100644 drivers/staging/csr/sdioemb/sdio_cis.h
+ create mode 100644 drivers/staging/csr/sdioemb/sdio_csr.h
+ create mode 100644 drivers/staging/csr/sdioemb/slot_api.h
+ create mode 100644 drivers/staging/csr/sdioemb/slot_imx27.h
+ create mode 100644 drivers/staging/csr/sdioemb/slot_imx31.h
+ create mode 100644 drivers/staging/csr/sdioemb/slot_pxa27x.h
+ create mode 100644 drivers/staging/csr/sdioemb/slot_shc.h
+ create mode 100644 drivers/staging/csr/sdioemb/slot_ushc.h
+ create mode 100644 drivers/staging/csr/sdioemb/trace.h
+ create mode 100644 drivers/staging/csr/sdioemb/uif.h
+ create mode 100644 drivers/staging/csr/sdioemb/version.h
+ create mode 100644 drivers/staging/csr/sme_blocking.c
+ create mode 100644 drivers/staging/csr/sme_mgt.c
+ create mode 100644 drivers/staging/csr/sme_native.c
+ create mode 100644 drivers/staging/csr/sme_sys.c
+ create mode 100644 drivers/staging/csr/sme_userspace.c
+ create mode 100644 drivers/staging/csr/sme_userspace.h
+ create mode 100644 drivers/staging/csr/sme_wext.c
+ create mode 100644 drivers/staging/csr/ul_int.c
+ create mode 100644 drivers/staging/csr/unifi_clients.h
+ create mode 100644 drivers/staging/csr/unifi_config.h
+ create mode 100644 drivers/staging/csr/unifi_dbg.c
+ create mode 100644 drivers/staging/csr/unifi_event.c
+ create mode 100644 drivers/staging/csr/unifi_native.h
+ create mode 100644 drivers/staging/csr/unifi_os.h
+ create mode 100644 drivers/staging/csr/unifi_pdu_processing.c
+ create mode 100644 drivers/staging/csr/unifi_priv.h
+ create mode 100644 drivers/staging/csr/unifi_sme.c
+ create mode 100644 drivers/staging/csr/unifi_sme.h
+ create mode 100644 drivers/staging/csr/unifi_wext.h
+ create mode 100644 drivers/staging/csr/unifiio.h
+ create mode 100644 drivers/staging/csr/wext_events.c
+ mode change 100755 => 100644 drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583
+ mode change 100755 => 100644 drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x
+ delete mode 100644 drivers/staging/iio/dac/ad5504.h
+ delete mode 100644 drivers/staging/iio/dac/ad5791.h
+ delete mode 100644 drivers/staging/iio/dac/dac.h
+ mode change 100755 => 100644 drivers/staging/iio/light/tsl2x7x.h
+ mode change 100755 => 100644 drivers/staging/iio/light/tsl2x7x_core.c
+ rename drivers/staging/nvec/{nvec_leds.c => nvec_paz00.c} (67%)
+ delete mode 100644 drivers/staging/sm7xx/Kconfig
+ delete mode 100644 drivers/staging/sm7xx/Makefile
+ create mode 100644 drivers/staging/sm7xxfb/Kconfig
+ create mode 100644 drivers/staging/sm7xxfb/Makefile
+ rename drivers/staging/{sm7xx => sm7xxfb}/TODO (76%)
+ rename drivers/staging/{sm7xx/smtcfb.h => sm7xxfb/sm7xx.h} (99%)
+ rename drivers/staging/{sm7xx/smtcfb.c => sm7xxfb/sm7xxfb.c} (92%)
+ delete mode 100644 include/linux/if_strip.h
+ rename {drivers/staging => include/linux}/iio/dac/ad5421.h (92%)
+ create mode 100644 include/linux/iio/dac/ad5504.h
+ create mode 100644 include/linux/iio/dac/ad5791.h
+ rename {drivers/staging => include/linux}/iio/dac/max517.h (76%)
+ create mode 100644 include/linux/iio/dac/mcp4725.h
+ create mode 100644 include/linux/iio/frequency/ad9523.h
+ create mode 100644 include/linux/iio/frequency/adf4350.h
+ create mode 100644 include/linux/iio/triggered_buffer.h
+Merging char-misc/char-misc-next (726917f mei: revamp host buffer interface function)
+$ git merge char-misc/char-misc-next
+Auto-merging drivers/misc/mei/main.c
+Auto-merging drivers/misc/mei/interrupt.c
+Merge made by the 'recursive' strategy.
+ Documentation/devicetree/bindings/misc/at25.txt |   21 ++++++
+ Documentation/misc-devices/mei/mei.txt          |   14 ++--
+ drivers/misc/eeprom/at25.c                      |   61 +++++++++++-----
+ drivers/misc/hpilo.c                            |   33 +++++----
+ drivers/misc/hpilo.h                            |    4 +-
+ drivers/misc/mei/init.c                         |    3 +
+ drivers/misc/mei/interface.c                    |   85 +++++++++--------------
+ drivers/misc/mei/interface.h                    |   12 +++-
+ drivers/misc/mei/interrupt.c                    |   21 +++---
+ drivers/misc/mei/iorw.c                         |    8 +--
+ drivers/misc/mei/main.c                         |    9 +--
+ drivers/misc/mei/mei_dev.h                      |   10 +--
+ 12 files changed, 164 insertions(+), 117 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/misc/at25.txt
+Merging tmem/linux-next (3bebf5b Merge branch 'stable/for-linus-3.6' into linux-next)
+$ git merge tmem/linux-next
+Merge made by the 'recursive' strategy.
+ Documentation/vm/frontswap.txt   |    4 +-
+ include/trace/events/frontswap.h |  167 ++++++++++++++++++++++++++++++++++++++
+ mm/frontswap.c                   |  164 +++++++++++++++++++++++--------------
+ 3 files changed, 273 insertions(+), 62 deletions(-)
+ create mode 100644 include/trace/events/frontswap.h
+Merging writeback/writeback-for-next (331cbde writeback: Fix some comment errors)
+$ git merge writeback/writeback-for-next
+Auto-merging lib/Makefile
+Merge made by the 'recursive' strategy.
+ fs/fs-writeback.c                |    4 +-
+ fs/super.c                       |    2 +-
+ fs/sync.c                        |    2 +-
+ include/linux/backing-dev.h      |    4 +-
+ include/linux/flex_proportions.h |  101 ++++++++++++++
+ lib/Makefile                     |    2 +-
+ lib/flex_proportions.c           |  272 ++++++++++++++++++++++++++++++++++++++
+ mm/backing-dev.c                 |    6 +-
+ mm/page-writeback.c              |  107 +++++++++------
+ 9 files changed, 449 insertions(+), 51 deletions(-)
+ create mode 100644 include/linux/flex_proportions.h
+ create mode 100644 lib/flex_proportions.c
+Merging arm-dt/devicetree/arm-next (ede338f dt: add documentation of ARM dt boot interface)
+$ git merge arm-dt/devicetree/arm-next
+Already up-to-date.
+Merging hwspinlock/linux-next (8b37fcf hwspinlock: add MAINTAINERS entries)
+$ git merge hwspinlock/linux-next
+Already up-to-date.
+Merging pinctrl/for-next (8df6653 pinctrl: pinctrl-imx: fix map setting problem if NO_PAD_CTL is set)
+$ git merge pinctrl/for-next
+Auto-merging drivers/pinctrl/spear/pinctrl-spear.c
+Merge made by the 'recursive' strategy.
+ drivers/pinctrl/Kconfig               |    2 +-
+ drivers/pinctrl/core.c                |   41 +++++++++++++++------------------
+ drivers/pinctrl/pinctrl-coh901.c      |    6 ++---
+ drivers/pinctrl/pinctrl-imx.c         |   13 ++++++-----
+ drivers/pinctrl/pinctrl-tegra.c       |    5 ++--
+ drivers/pinctrl/pinctrl-u300.c        |    6 -----
+ drivers/pinctrl/spear/pinctrl-spear.c |    4 ++--
+ include/linux/pinctrl/pinctrl.h       |    5 ++--
+ 8 files changed, 37 insertions(+), 45 deletions(-)
+Merging moduleh/for-sfr (f9e1b2b tile: fix compile failure on start_kernel in setup.c)
+$ git merge moduleh/for-sfr
+Auto-merging arch/tile/kernel/setup.c
+Merge made by the 'recursive' strategy.
+ arch/tile/kernel/setup.c |    1 +
+ 1 file changed, 1 insertion(+)
+Merging vhost/linux-next (e0953c8 tun: experimental zero copy tx support)
+$ git merge vhost/linux-next
+Auto-merging net/core/skbuff.c
+Auto-merging net/core/dev.c
+Auto-merging include/linux/skbuff.h
+Merge made by the 'recursive' strategy.
+ drivers/net/tun.c      |  134 ++++++++++++++++++++++++++++++++++++++++++++++--
+ include/linux/skbuff.h |   16 ++++++
+ net/core/dev.c         |    2 +
+ net/core/skbuff.c      |   24 ++++-----
+ 4 files changed, 156 insertions(+), 20 deletions(-)
+Merging kmap_atomic/kmap_atomic (cf43378 pipe: remove KM_USER0 from comments)
+$ git merge kmap_atomic/kmap_atomic
+Auto-merging Documentation/feature-removal-schedule.txt
+Merge made by the 'recursive' strategy.
+ Documentation/feature-removal-schedule.txt |    8 ------
+ arch/arm/include/asm/kmap_types.h          |   26 +-----------------
+ arch/avr32/include/asm/kmap_types.h        |   24 ++--------------
+ arch/frv/include/asm/kmap_types.h          |   24 +---------------
+ arch/powerpc/include/asm/kmap_types.h      |   31 +--------------------
+ arch/tile/include/asm/kmap_types.h         |   26 ------------------
+ arch/um/include/asm/kmap_types.h           |   18 +-----------
+ fs/jbd2/commit.c                           |    4 +--
+ fs/pipe.c                                  |    2 +-
+ include/asm-generic/kmap_types.h           |   34 ++---------------------
+ include/linux/highmem.h                    |   41 +---------------------------
+ include/linux/pipe_fs_i.h                  |    8 ++----
+ mm/vmalloc.c                               |    8 ++----
+ 13 files changed, 17 insertions(+), 237 deletions(-)
+Merging memblock/memblock-kill-early_node_map (7bd0b0f memblock: Reimplement memblock allocation using reverse free area iterator)
+$ git merge memblock/memblock-kill-early_node_map
+Already up-to-date.
+Merging remoteproc/for-next (5414687 MAINTAINERS: add remoteproc's git)
+$ git merge remoteproc/for-next
+Resolved 'drivers/remoteproc/remoteproc_core.c' using previous resolution.
+Auto-merging drivers/remoteproc/remoteproc_core.c
+CONFLICT (content): Merge conflict in drivers/remoteproc/remoteproc_core.c
+Auto-merging MAINTAINERS
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master f088a21] Merge remote-tracking branch 'remoteproc/for-next'
+$ git diff -M --stat --summary HEAD^..
+ MAINTAINERS                                |    1 +
+ drivers/remoteproc/Makefile                |    1 +
+ drivers/remoteproc/remoteproc_core.c       |  251 +-----------------------
+ drivers/remoteproc/remoteproc_elf_loader.c |  292 ++++++++++++++++++++++++++++
+ drivers/remoteproc/remoteproc_internal.h   |   40 ++++
+ include/linux/remoteproc.h                 |   20 ++
+ 6 files changed, 363 insertions(+), 242 deletions(-)
+ create mode 100644 drivers/remoteproc/remoteproc_elf_loader.c
+Merging irqdomain/irqdomain/next (aed9804 irqdomain: Make ops->map hook optional)
+$ git merge irqdomain/irqdomain/next
+Merge made by the 'recursive' strategy.
+ include/linux/of.h     |   15 ++++++++++-----
+ kernel/irq/irqdomain.c |   30 +++++++++++++-----------------
+ 2 files changed, 23 insertions(+), 22 deletions(-)
+Merging gpio/gpio/next (3e11f7b gpio/generic: initialize basic_mmio_gpio shadow variables properly)
+$ git merge gpio/gpio/next
+Already up-to-date.
+Merging arm-soc/for-next (513bd72 Merge branch 'fixes' into for-next)
+$ git merge arm-soc/for-next
+Auto-merging include/linux/leds.h
+Auto-merging drivers/leds/Makefile
+Auto-merging drivers/leds/Kconfig
+Removing arch/arm/mach-sa1100/leds.h
+Removing arch/arm/mach-sa1100/leds.c
+Removing arch/arm/mach-sa1100/leds-lart.c
+Removing arch/arm/mach-sa1100/leds-hackkit.c
+Removing arch/arm/mach-sa1100/leds-cerf.c
+Removing arch/arm/mach-sa1100/leds-badge4.c
+Removing arch/arm/mach-sa1100/leds-assabet.c
+Auto-merging arch/arm/mach-sa1100/assabet.c
+Removing arch/arm/mach-pxa/leds.h
+Removing arch/arm/mach-pxa/leds.c
+Removing arch/arm/mach-pxa/leds-mainstone.c
+Removing arch/arm/mach-pxa/leds-lubbock.c
+Removing arch/arm/mach-pxa/leds-idp.c
+Removing arch/arm/mach-omap1/leds.h
+Removing arch/arm/mach-omap1/leds.c
+Removing arch/arm/mach-omap1/leds-osk.c
+Removing arch/arm/mach-omap1/leds-innovator.c
+Removing arch/arm/mach-omap1/leds-h2p2-debug.c
+Removing arch/arm/mach-nomadik/clock.h
+Removing arch/arm/mach-nomadik/clock.c
+Removing arch/arm/mach-ks8695/leds.c
+Removing arch/arm/mach-footbridge/netwinder-leds.c
+Removing arch/arm/mach-footbridge/ebsa285-leds.c
+Removing arch/arm/mach-clps711x/p720t-leds.c
+Removing arch/arm/kernel/leds.c
+Removing arch/arm/include/asm/leds.h
+Merge made by the 'recursive' strategy.
+ arch/arm/Kconfig                               |   55 +----
+ arch/arm/arm-soc-for-next-contents.txt         |   15 ++
+ arch/arm/include/asm/leds.h                    |   50 ----
+ arch/arm/kernel/Makefile                       |    1 -
+ arch/arm/kernel/leds.c                         |  121 ----------
+ arch/arm/kernel/process.c                      |    6 +-
+ arch/arm/kernel/time.c                         |   17 --
+ arch/arm/mach-at91/board-csb337.c              |    2 -
+ arch/arm/mach-at91/board-ecbat91.c             |   18 +-
+ arch/arm/mach-at91/board-eco920.c              |   22 +-
+ arch/arm/mach-at91/board-kafa.c                |   17 +-
+ arch/arm/mach-at91/board-kb9202.c              |   23 +-
+ arch/arm/mach-at91/board-rm9200dk.c            |    3 -
+ arch/arm/mach-at91/board-rm9200ek.c            |    3 -
+ arch/arm/mach-at91/board-rsi-ews.c             |    3 -
+ arch/arm/mach-at91/board-sam9-l9260.c          |   23 +-
+ arch/arm/mach-at91/board-sam9261ek.c           |    3 -
+ arch/arm/mach-at91/board-yl-9200.c             |    3 -
+ arch/arm/mach-at91/include/mach/board.h        |    1 -
+ arch/arm/mach-at91/leds.c                      |  105 ---------
+ arch/arm/mach-clps711x/Makefile                |    2 -
+ arch/arm/mach-clps711x/common.c                |    1 -
+ arch/arm/mach-clps711x/p720t-leds.c            |   63 -----
+ arch/arm/mach-clps711x/p720t.c                 |   61 +++++
+ arch/arm/mach-ebsa110/Makefile                 |    4 +-
+ arch/arm/mach-ebsa110/leds.c                   |   81 ++++---
+ arch/arm/mach-footbridge/Makefile              |    4 -
+ arch/arm/mach-footbridge/ebsa285-leds.c        |  138 -----------
+ arch/arm/mach-footbridge/ebsa285.c             |   81 +++++++
+ arch/arm/mach-footbridge/netwinder-hw.c        |  112 +++++++--
+ arch/arm/mach-footbridge/netwinder-leds.c      |  138 -----------
+ arch/arm/mach-integrator/Makefile              |    3 +-
+ arch/arm/mach-integrator/core.c                |    3 -
+ arch/arm/mach-integrator/include/mach/cm.h     |    2 +
+ arch/arm/mach-integrator/leds.c                |  161 ++++++++-----
+ arch/arm/mach-ks8695/Makefile                  |    3 -
+ arch/arm/mach-ks8695/devices.c                 |   21 --
+ arch/arm/mach-ks8695/include/mach/devices.h    |    5 -
+ arch/arm/mach-ks8695/leds.c                    |   92 --------
+ arch/arm/mach-nomadik/Makefile                 |    2 -
+ arch/arm/mach-nomadik/board-nhk8815.c          |   67 +++++-
+ arch/arm/mach-nomadik/clock.c                  |   75 ------
+ arch/arm/mach-nomadik/clock.h                  |   15 --
+ arch/arm/mach-nomadik/cpu-8815.c               |  126 +++++-----
+ arch/arm/mach-nomadik/i2c-8815nhk.c            |   38 ++-
+ arch/arm/mach-nomadik/include/mach/irqs.h      |   85 ++++---
+ arch/arm/mach-omap1/Makefile                   |    8 -
+ arch/arm/mach-omap1/board-h2.c                 |   32 +++
+ arch/arm/mach-omap1/board-h3.c                 |   32 +++
+ arch/arm/mach-omap1/board-osk.c                |   33 +++
+ arch/arm/mach-omap1/leds-h2p2-debug.c          |  166 --------------
+ arch/arm/mach-omap1/leds-innovator.c           |   98 --------
+ arch/arm/mach-omap1/leds-osk.c                 |  113 ---------
+ arch/arm/mach-omap1/leds.c                     |   69 ------
+ arch/arm/mach-omap1/leds.h                     |    3 -
+ arch/arm/mach-omap1/time.c                     |    1 -
+ arch/arm/mach-omap1/timer32k.c                 |    1 -
+ arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c   |    1 -
+ arch/arm/mach-orion5x/rd88f5181l-ge-setup.c    |    1 -
+ arch/arm/mach-orion5x/rd88f5182-setup.c        |   72 ++----
+ arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c   |    1 -
+ arch/arm/mach-pnx4008/time.c                   |    1 -
+ arch/arm/mach-pxa/Makefile                     |    8 -
+ arch/arm/mach-pxa/idp.c                        |   81 +++++++
+ arch/arm/mach-pxa/leds-idp.c                   |  115 ----------
+ arch/arm/mach-pxa/leds-lubbock.c               |  124 ----------
+ arch/arm/mach-pxa/leds-mainstone.c             |  119 ----------
+ arch/arm/mach-pxa/leds.c                       |   32 ---
+ arch/arm/mach-pxa/leds.h                       |   13 --
+ arch/arm/mach-pxa/lubbock.c                    |   95 ++++++++
+ arch/arm/mach-pxa/mainstone.c                  |   94 ++++++++
+ arch/arm/mach-realview/core.c                  |   39 ----
+ arch/arm/mach-realview/core.h                  |    2 -
+ arch/arm/mach-realview/realview_eb.c           |    5 -
+ arch/arm/mach-realview/realview_pb1176.c       |    5 -
+ arch/arm/mach-realview/realview_pb11mp.c       |    5 -
+ arch/arm/mach-realview/realview_pba8.c         |    5 -
+ arch/arm/mach-realview/realview_pbx.c          |    5 -
+ arch/arm/mach-sa1100/Makefile                  |    9 -
+ arch/arm/mach-sa1100/assabet.c                 |   85 +++++++
+ arch/arm/mach-sa1100/badge4.c                  |   30 +++
+ arch/arm/mach-sa1100/cerf.c                    |   42 ++++
+ arch/arm/mach-sa1100/hackkit.c                 |   32 +++
+ arch/arm/mach-sa1100/lart.c                    |   26 +++
+ arch/arm/mach-sa1100/leds-assabet.c            |  113 ---------
+ arch/arm/mach-sa1100/leds-badge4.c             |  110 ---------
+ arch/arm/mach-sa1100/leds-cerf.c               |  109 ---------
+ arch/arm/mach-sa1100/leds-hackkit.c            |  111 ---------
+ arch/arm/mach-sa1100/leds-lart.c               |  100 --------
+ arch/arm/mach-sa1100/leds.c                    |   50 ----
+ arch/arm/mach-sa1100/leds.h                    |   13 --
+ arch/arm/mach-shark/Makefile                   |    4 +-
+ arch/arm/mach-shark/core.c                     |    1 -
+ arch/arm/mach-shark/leds.c                     |  220 +++++++-----------
+ arch/arm/mach-shmobile/board-armadillo800eva.c |    1 +
+ arch/arm/mach-shmobile/board-kzm9d.c           |    1 +
+ arch/arm/mach-shmobile/board-kzm9g.c           |    1 +
+ arch/arm/mach-shmobile/board-mackerel.c        |    3 +
+ arch/arm/mach-shmobile/clock-sh73a0.c          |    8 +-
+ arch/arm/mach-shmobile/intc-r8a7779.c          |    7 +
+ arch/arm/mach-shmobile/platsmp.c               |    5 +
+ arch/arm/mach-shmobile/setup-sh7372.c          |    2 +-
+ arch/arm/mach-versatile/core.c                 |    5 -
+ arch/arm/plat-omap/Kconfig                     |    3 +-
+ arch/arm/plat-omap/debug-leds.c                |  293 ++++++------------------
+ arch/arm/plat-samsung/time.c                   |    1 -
+ arch/arm/plat-versatile/Kconfig                |    4 +-
+ arch/arm/plat-versatile/leds.c                 |   13 +-
+ drivers/char/nwflash.c                         |   34 ---
+ drivers/clk/Makefile                           |    1 +
+ drivers/clk/clk-nomadik.c                      |   47 ++++
+ drivers/leds/Kconfig                           |   10 +
+ drivers/leds/Makefile                          |    1 +
+ drivers/leds/ledtrig-cpu.c                     |  163 +++++++++++++
+ include/linux/leds.h                           |   16 ++
+ include/linux/platform_data/clk-nomadik.h      |    2 +
+ 116 files changed, 1713 insertions(+), 3216 deletions(-)
+ create mode 100644 arch/arm/arm-soc-for-next-contents.txt
+ delete mode 100644 arch/arm/include/asm/leds.h
+ delete mode 100644 arch/arm/kernel/leds.c
+ delete mode 100644 arch/arm/mach-clps711x/p720t-leds.c
+ delete mode 100644 arch/arm/mach-footbridge/ebsa285-leds.c
+ delete mode 100644 arch/arm/mach-footbridge/netwinder-leds.c
+ delete mode 100644 arch/arm/mach-ks8695/leds.c
+ delete mode 100644 arch/arm/mach-nomadik/clock.c
+ delete mode 100644 arch/arm/mach-nomadik/clock.h
+ delete mode 100644 arch/arm/mach-omap1/leds-h2p2-debug.c
+ delete mode 100644 arch/arm/mach-omap1/leds-innovator.c
+ delete mode 100644 arch/arm/mach-omap1/leds-osk.c
+ delete mode 100644 arch/arm/mach-omap1/leds.c
+ delete mode 100644 arch/arm/mach-omap1/leds.h
+ delete mode 100644 arch/arm/mach-pxa/leds-idp.c
+ delete mode 100644 arch/arm/mach-pxa/leds-lubbock.c
+ delete mode 100644 arch/arm/mach-pxa/leds-mainstone.c
+ delete mode 100644 arch/arm/mach-pxa/leds.c
+ delete mode 100644 arch/arm/mach-pxa/leds.h
+ delete mode 100644 arch/arm/mach-sa1100/leds-assabet.c
+ delete mode 100644 arch/arm/mach-sa1100/leds-badge4.c
+ delete mode 100644 arch/arm/mach-sa1100/leds-cerf.c
+ delete mode 100644 arch/arm/mach-sa1100/leds-hackkit.c
+ delete mode 100644 arch/arm/mach-sa1100/leds-lart.c
+ delete mode 100644 arch/arm/mach-sa1100/leds.c
+ delete mode 100644 arch/arm/mach-sa1100/leds.h
+ create mode 100644 drivers/clk/clk-nomadik.c
+ create mode 100644 drivers/leds/ledtrig-cpu.c
+ create mode 100644 include/linux/platform_data/clk-nomadik.h
+Merging ep93xx/ep93xx-for-next (9b6a359 Merge branch 'ep93xx-fixes' into ep93xx-for-next)
+$ git merge ep93xx/ep93xx-for-next
+Merge made by the 'recursive' strategy.
+ arch/arm/mach-ep93xx/core.c                  |   96 ++++++++++++++++++++++++++
+ arch/arm/mach-ep93xx/edb93xx.c               |   28 +++++++-
+ arch/arm/mach-ep93xx/include/mach/platform.h |    3 +
+ arch/arm/mach-ep93xx/soc.h                   |    1 +
+ 4 files changed, 126 insertions(+), 2 deletions(-)
+Merging renesas/next (386213b Merge branch 'renesas-sh7372' into renesas-next)
+$ git merge renesas/next
+Merge made by the 'recursive' strategy.
+ arch/arm/configs/armadillo800eva_defconfig     |   20 ++-
+ arch/arm/configs/kzm9g_defconfig               |    1 +
+ arch/arm/mach-shmobile/Kconfig                 |    1 +
+ arch/arm/mach-shmobile/board-armadillo800eva.c |  212 +++++++++++++++++++++++-
+ arch/arm/mach-shmobile/board-kzm9g.c           |   82 +++++++++
+ arch/arm/mach-shmobile/clock-r8a7740.c         |  138 ++++++++++++++-
+ arch/arm/mach-shmobile/clock-sh73a0.c          |    4 +-
+ arch/arm/mach-shmobile/include/mach/common.h   |    1 +
+ arch/arm/mach-shmobile/include/mach/r8a7740.h  |    9 +-
+ arch/arm/mach-shmobile/intc-r8a7740.c          |   13 +-
+ arch/arm/mach-shmobile/pfc-r8a7740.c           |   20 ++-
+ arch/arm/mach-shmobile/pm-sh7372.c             |    7 +-
+ arch/arm/mach-shmobile/setup-r8a7740.c         |   18 ++
+ 13 files changed, 501 insertions(+), 25 deletions(-)
+Merging s5p/for-next (99f9f4c Merge branch 'v3.5-samsung-fixes-1' into for-next)
+$ git merge s5p/for-next
+Auto-merging drivers/spi/spi-s3c64xx.c
+Removing arch/arm/mach-s5pv210/include/mach/spi-clocks.h
+Removing arch/arm/mach-s5pc100/include/mach/spi-clocks.h
+Removing arch/arm/mach-s5p64x0/include/mach/spi-clocks.h
+Removing arch/arm/mach-s3c64xx/include/mach/spi-clocks.h
+Removing arch/arm/mach-s3c24xx/include/mach/bast-pmu.h
+Removing arch/arm/mach-exynos/include/mach/spi-clocks.h
+Merge made by the 'recursive' strategy.
+ arch/arm/mach-exynos/Kconfig                       |    2 +
+ arch/arm/mach-exynos/include/mach/regs-usb-phy.h   |   20 +++--
+ arch/arm/mach-exynos/include/mach/spi-clocks.h     |   16 ----
+ arch/arm/mach-exynos/mach-origen.c                 |    6 ++
+ arch/arm/mach-exynos/mach-smdk4x12.c               |   10 ++-
+ arch/arm/mach-exynos/mach-smdkv310.c               |    6 ++
+ arch/arm/mach-exynos/setup-usb-phy.c               |   55 ++++++++++----
+ arch/arm/mach-s3c24xx/common.c                     |    1 -
+ arch/arm/mach-s3c24xx/include/mach/bast-pmu.h      |   40 ----------
+ arch/arm/mach-s3c64xx/include/mach/crag6410.h      |    4 +-
+ arch/arm/mach-s3c64xx/include/mach/spi-clocks.h    |   18 -----
+ arch/arm/mach-s3c64xx/mach-crag6410-module.c       |   10 ++-
+ arch/arm/mach-s3c64xx/mach-crag6410.c              |    1 -
+ arch/arm/mach-s5p64x0/dma.c                        |    2 -
+ arch/arm/mach-s5p64x0/include/mach/spi-clocks.h    |   20 -----
+ arch/arm/mach-s5pc100/dma.c                        |    2 -
+ arch/arm/mach-s5pc100/include/mach/spi-clocks.h    |   18 -----
+ arch/arm/mach-s5pv210/Kconfig                      |    2 +
+ arch/arm/mach-s5pv210/include/mach/spi-clocks.h    |   17 -----
+ arch/arm/mach-s5pv210/mach-smdkv210.c              |    9 +++
+ arch/arm/plat-samsung/dma-ops.c                    |   77 +++++++++++---------
+ arch/arm/plat-samsung/include/plat/cpu.h           |    4 +
+ arch/arm/plat-samsung/include/plat/dma-ops.h       |   20 +++--
+ arch/arm/plat-samsung/include/plat/fb.h            |    1 -
+ arch/arm/plat-samsung/include/plat/map-s3c.h       |    2 +-
+ .../arm/plat-samsung/include/plat/watchdog-reset.h |    2 +-
+ arch/arm/plat-samsung/pwm.c                        |    4 -
+ arch/arm/plat-samsung/s3c-dma-ops.c                |   39 +++++-----
+ drivers/spi/spi-s3c64xx.c                          |   33 +++++----
+ sound/soc/samsung/dma.c                            |   18 +++--
+ 30 files changed, 210 insertions(+), 249 deletions(-)
+ delete mode 100644 arch/arm/mach-exynos/include/mach/spi-clocks.h
+ delete mode 100644 arch/arm/mach-s3c24xx/include/mach/bast-pmu.h
+ delete mode 100644 arch/arm/mach-s3c64xx/include/mach/spi-clocks.h
+ delete mode 100644 arch/arm/mach-s5p64x0/include/mach/spi-clocks.h
+ delete mode 100644 arch/arm/mach-s5pc100/include/mach/spi-clocks.h
+ delete mode 100644 arch/arm/mach-s5pv210/include/mach/spi-clocks.h
+Merging tegra/for-next (1412fcf Merge branch 'for-3.6/defconfig' into for-next)
+$ git merge tegra/for-next
+Auto-merging sound/soc/tegra/tegra30_i2s.c
+Auto-merging sound/soc/tegra/tegra30_ahub.c
+Auto-merging sound/soc/tegra/tegra20_spdif.c
+Auto-merging sound/soc/tegra/tegra20_i2s.c
+Auto-merging drivers/staging/nvec/nvec.c
+Auto-merging drivers/i2c/busses/i2c-tegra.c
+Removing arch/arm/mach-tegra/board-seaboard.h
+Removing arch/arm/mach-tegra/board-seaboard.c
+Removing arch/arm/mach-tegra/board-seaboard-pinmux.c
+Auto-merging arch/arm/boot/dts/tegra30-cardhu.dts
+Auto-merging arch/arm/boot/dts/tegra20-ventana.dts
+Auto-merging arch/arm/boot/dts/tegra20-seaboard.dts
+Auto-merging arch/arm/boot/dts/tegra20-paz00.dts
+Auto-merging arch/arm/boot/dts/tegra20-harmony.dts
+Auto-merging arch/arm/Kconfig
+Auto-merging Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-emc.txt
+Merge made by the 'recursive' strategy.
+ .../arm/tegra/{emc.txt => nvidia,tegra20-emc.txt}  |    2 +-
+ .../bindings/arm/tegra/nvidia,tegra20-mc.txt       |    2 +-
+ .../bindings/arm/tegra/nvidia,tegra30-mc.txt       |    2 +-
+ .../{gpio_nvidia.txt => nvidia,tegra20-gpio.txt}   |    0
+ .../{tegra-kbc.txt => nvidia,tegra20-kbc.txt}      |    0
+ .../{nvidia-sdhci.txt => nvidia,tegra20-sdhci.txt} |    0
+ .../nvec/{nvec_nvidia.txt => nvidia,nvec.txt}      |    0
+ ...-alc5632.txt => nvidia,tegra-audio-alc5632.txt} |    0
+ ...mslice.txt => nvidia,tegra-audio-trimslice.txt} |    0
+ ...io-wm8753.txt => nvidia,tegra-audio-wm8753.txt} |    0
+ ...io-wm8903.txt => nvidia,tegra-audio-wm8903.txt} |    0
+ .../{tegra20-das.txt => nvidia,tegra20-das.txt}    |    0
+ .../{tegra20-i2s.txt => nvidia,tegra20-i2s.txt}    |    0
+ .../spi/{spi_nvidia.txt => nvidia,tegra20-spi.txt} |    0
+ .../usb/{tegra-usb.txt => nvidia,tegra20-ehci.txt} |    0
+ arch/arm/Kconfig                                   |    1 +
+ .../dts/{tegra-harmony.dts => tegra20-harmony.dts} |    1 -
+ .../dts/{tegra-paz00.dts => tegra20-paz00.dts}     |    1 -
+ .../{tegra-seaboard.dts => tegra20-seaboard.dts}   |   88 ++++--
+ .../{tegra-trimslice.dts => tegra20-trimslice.dts} |    0
+ .../dts/{tegra-ventana.dts => tegra20-ventana.dts} |    1 -
+ arch/arm/boot/dts/tegra20-whistler.dts             |  301 +++++++++++++++++++
+ arch/arm/boot/dts/tegra20.dtsi                     |   40 +--
+ .../dts/{tegra-cardhu.dts => tegra30-cardhu.dts}   |    1 -
+ arch/arm/boot/dts/tegra30.dtsi                     |   40 +--
+ arch/arm/configs/tegra_defconfig                   |   13 +-
+ arch/arm/mach-tegra/Kconfig                        |   39 ---
+ arch/arm/mach-tegra/Makefile                       |   18 +-
+ arch/arm/mach-tegra/Makefile.boot                  |   13 +-
+ arch/arm/mach-tegra/apbio.c                        |   59 +++-
+ arch/arm/mach-tegra/apbio.h                        |   19 +-
+ arch/arm/mach-tegra/board-dt-tegra20.c             |   67 ++++-
+ arch/arm/mach-tegra/board-dt-tegra30.c             |    1 +
+ arch/arm/mach-tegra/board-harmony-pcie.c           |   15 +-
+ arch/arm/mach-tegra/board-harmony-power.c          |   25 +-
+ arch/arm/mach-tegra/board-paz00.c                  |    7 +-
+ arch/arm/mach-tegra/board-seaboard-pinmux.c        |  197 -------------
+ arch/arm/mach-tegra/board-seaboard.c               |  306 --------------------
+ arch/arm/mach-tegra/board-seaboard.h               |   47 ---
+ arch/arm/mach-tegra/board.h                        |    9 +
+ arch/arm/mach-tegra/common.c                       |    3 +
+ arch/arm/mach-tegra/cpu-tegra.c                    |    6 +-
+ arch/arm/mach-tegra/cpuidle.c                      |    6 +-
+ arch/arm/mach-tegra/dma.c                          |    4 +-
+ arch/arm/mach-tegra/pcie.c                         |    6 +-
+ arch/arm/mach-tegra/powergate.c                    |    4 +-
+ arch/arm/mach-tegra/sleep.S                        |   29 --
+ arch/arm/mach-tegra/tegra2_clocks.c                |   22 +-
+ arch/arm/mach-tegra/tegra30_clocks.c               |   22 +-
+ arch/arm/mach-tegra/timer.c                        |    4 +-
+ arch/arm/mach-tegra/usb_phy.c                      |   16 +-
+ drivers/amba/tegra-ahb.c                           |    6 -
+ drivers/crypto/tegra-aes.c                         |   12 +-
+ drivers/i2c/busses/i2c-tegra.c                     |   10 +-
+ drivers/input/keyboard/tegra-kbc.c                 |    4 +-
+ drivers/mmc/host/sdhci-tegra.c                     |   11 +-
+ drivers/spi/spi-tegra.c                            |    4 +-
+ drivers/staging/nvec/nvec.c                        |    8 +-
+ drivers/usb/host/ehci-tegra.c                      |   20 +-
+ sound/soc/tegra/Kconfig                            |   10 +-
+ sound/soc/tegra/tegra20_i2s.c                      |    4 +-
+ sound/soc/tegra/tegra20_spdif.c                    |    4 +-
+ sound/soc/tegra/tegra30_ahub.c                     |    8 +-
+ sound/soc/tegra/tegra30_i2s.c                      |    4 +-
+ sound/soc/tegra/tegra_asoc_utils.c                 |   12 +-
+ 65 files changed, 708 insertions(+), 846 deletions(-)
+ rename Documentation/devicetree/bindings/arm/tegra/{emc.txt => nvidia,tegra20-emc.txt} (99%)
+ rename Documentation/devicetree/bindings/gpio/{gpio_nvidia.txt => nvidia,tegra20-gpio.txt} (100%)
+ rename Documentation/devicetree/bindings/input/{tegra-kbc.txt => nvidia,tegra20-kbc.txt} (100%)
+ rename Documentation/devicetree/bindings/mmc/{nvidia-sdhci.txt => nvidia,tegra20-sdhci.txt} (100%)
+ rename Documentation/devicetree/bindings/nvec/{nvec_nvidia.txt => nvidia,nvec.txt} (100%)
+ rename Documentation/devicetree/bindings/sound/{tegra-audio-alc5632.txt => nvidia,tegra-audio-alc5632.txt} (100%)
+ rename Documentation/devicetree/bindings/sound/{tegra-audio-trimslice.txt => nvidia,tegra-audio-trimslice.txt} (100%)
+ rename Documentation/devicetree/bindings/sound/{tegra-audio-wm8753.txt => nvidia,tegra-audio-wm8753.txt} (100%)
+ rename Documentation/devicetree/bindings/sound/{tegra-audio-wm8903.txt => nvidia,tegra-audio-wm8903.txt} (100%)
+ rename Documentation/devicetree/bindings/sound/{tegra20-das.txt => nvidia,tegra20-das.txt} (100%)
+ rename Documentation/devicetree/bindings/sound/{tegra20-i2s.txt => nvidia,tegra20-i2s.txt} (100%)
+ rename Documentation/devicetree/bindings/spi/{spi_nvidia.txt => nvidia,tegra20-spi.txt} (100%)
+ rename Documentation/devicetree/bindings/usb/{tegra-usb.txt => nvidia,tegra20-ehci.txt} (100%)
+ rename arch/arm/boot/dts/{tegra-harmony.dts => tegra20-harmony.dts} (99%)
+ rename arch/arm/boot/dts/{tegra-paz00.dts => tegra20-paz00.dts} (99%)
+ rename arch/arm/boot/dts/{tegra-seaboard.dts => tegra20-seaboard.dts} (88%)
+ rename arch/arm/boot/dts/{tegra-trimslice.dts => tegra20-trimslice.dts} (100%)
+ rename arch/arm/boot/dts/{tegra-ventana.dts => tegra20-ventana.dts} (99%)
+ create mode 100644 arch/arm/boot/dts/tegra20-whistler.dts
+ rename arch/arm/boot/dts/{tegra-cardhu.dts => tegra30-cardhu.dts} (99%)
+ delete mode 100644 arch/arm/mach-tegra/board-seaboard-pinmux.c
+ delete mode 100644 arch/arm/mach-tegra/board-seaboard.c
+ delete mode 100644 arch/arm/mach-tegra/board-seaboard.h
+Merging kvmtool/master (5fffd63 kvm tools: set the HYPERVISOR flag in cpuid)
+$ git merge kvmtool/master
+Already up-to-date.
+Merging dma-mapping/dma-mapping-next (17f449a Merge remote branch 'dma-public/fixes-for-linus' into for-next)
+$ git merge dma-mapping/dma-mapping-next
+Auto-merging mm/vmalloc.c
+Auto-merging arch/powerpc/kernel/vio.c
+Auto-merging Documentation/kernel-parameters.txt
+Merge made by the 'recursive' strategy.
+ Documentation/DMA-attributes.txt         |   42 +++
+ Documentation/kernel-parameters.txt      |    2 +-
+ arch/arm/common/dmabounce.c              |    1 +
+ arch/arm/include/asm/dma-mapping.h       |   24 +-
+ arch/arm/mm/dma-mapping.c                |  554 ++++++++++++------------------
+ arch/arm/mm/mm.h                         |    3 +
+ arch/powerpc/include/asm/dma-mapping.h   |    8 +-
+ arch/powerpc/kernel/dma-iommu.c          |    1 +
+ arch/powerpc/kernel/dma-swiotlb.c        |    1 +
+ arch/powerpc/kernel/dma.c                |   36 +-
+ arch/powerpc/kernel/vio.c                |    1 +
+ drivers/base/dma-mapping.c               |   49 +++
+ include/asm-generic/dma-coherent.h       |    1 +
+ include/asm-generic/dma-mapping-common.h |   55 +++
+ include/linux/dma-attrs.h                |    2 +
+ include/linux/dma-mapping.h              |    3 +
+ include/linux/scatterlist.h              |    4 +
+ include/linux/vmalloc.h                  |    9 +-
+ lib/scatterlist.c                        |   64 ++++
+ mm/vmalloc.c                             |   28 +-
+ 20 files changed, 502 insertions(+), 386 deletions(-)
+Merging dma-buf/for-next (b48b2c3 openrisc: use generic strnlen_user() function)
+$ git merge dma-buf/for-next
+Already up-to-date.
+Merging userns/for-next (491fa9e userns: Allow the usernamespace support to build after the removal of usbfs)
+$ git merge userns/for-next
+Auto-merging init/Kconfig
+Merge made by the 'recursive' strategy.
+ init/Kconfig |    1 -
+ 1 file changed, 1 deletion(-)
+Merging ktest/for-next (648a182 ktest: Allow a test to override REBOOT_ON_SUCCESS)
+$ git merge ktest/for-next
+Already up-to-date.
+Merging signal/for-next (2c95605 Uninclude linux/freezer.h)
+$ git merge signal/for-next
+Auto-merging kernel/timer.c
+Auto-merging kernel/sched/core.c
+Auto-merging arch/xtensa/kernel/signal.c
+Auto-merging arch/x86/kernel/vm86_32.c
+Auto-merging arch/x86/kernel/signal.c
+Auto-merging arch/x86/kernel/process.c
+Auto-merging arch/sh/kernel/cpu/sh5/entry.S
+Auto-merging arch/mips/include/asm/thread_info.h
+Auto-merging arch/frv/kernel/signal.c
+Auto-merging arch/avr32/kernel/signal.c
+Merge made by the 'recursive' strategy.
+ arch/alpha/include/asm/ptrace.h           |    5 +-
+ arch/alpha/include/asm/thread_info.h      |    3 +-
+ arch/alpha/kernel/alpha_ksyms.c           |    1 -
+ arch/alpha/kernel/entry.S                 |  161 -----------------------------
+ arch/alpha/kernel/osf_sys.c               |   49 +++++++++
+ arch/alpha/kernel/process.c               |   29 ++++++
+ arch/alpha/kernel/systbls.S               |    2 +-
+ arch/arm/include/asm/thread_info.h        |    7 +-
+ arch/arm/kernel/entry-common.S            |   21 ++--
+ arch/arm/kernel/ptrace.c                  |    2 -
+ arch/arm/kernel/signal.c                  |   77 ++++++++------
+ arch/avr32/include/asm/thread_info.h      |   17 +--
+ arch/avr32/kernel/signal.c                |    1 -
+ arch/blackfin/include/asm/thread_info.h   |    4 -
+ arch/blackfin/kernel/signal.c             |    1 -
+ arch/c6x/include/asm/thread_info.h        |    1 -
+ arch/c6x/kernel/asm-offsets.c             |    1 -
+ arch/cris/include/asm/thread_info.h       |    3 -
+ arch/frv/include/asm/thread_info.h        |    3 -
+ arch/frv/kernel/signal.c                  |    9 --
+ arch/h8300/include/asm/thread_info.h      |    7 +-
+ arch/h8300/kernel/signal.c                |    1 -
+ arch/hexagon/include/asm/thread_info.h    |    5 -
+ arch/hexagon/kernel/signal.c              |    1 -
+ arch/ia64/include/asm/thread_info.h       |    2 -
+ arch/ia64/kernel/signal.c                 |    8 --
+ arch/m32r/include/asm/thread_info.h       |    9 +-
+ arch/m32r/kernel/signal.c                 |    3 -
+ arch/microblaze/include/asm/thread_info.h |    3 +-
+ arch/microblaze/kernel/entry-nommu.S      |   21 +++-
+ arch/microblaze/kernel/entry.S            |   62 ++++++-----
+ arch/microblaze/kernel/signal.c           |   16 +--
+ arch/mips/include/asm/thread_info.h       |    9 +-
+ arch/mips/kernel/entry.S                  |   15 ++-
+ arch/mips/kernel/scall32-o32.S            |   13 +--
+ arch/mips/kernel/scall64-64.S             |   13 +--
+ arch/mips/kernel/scall64-n32.S            |   13 +--
+ arch/mips/kernel/scall64-o32.S            |   13 +--
+ arch/mips/kernel/signal.c                 |    8 --
+ arch/mn10300/include/asm/thread_info.h    |    3 +-
+ arch/mn10300/kernel/entry.S               |    4 +
+ arch/mn10300/kernel/signal.c              |    9 --
+ arch/openrisc/include/asm/thread_info.h   |    3 +-
+ arch/parisc/hpux/gate.S                   |    2 +-
+ arch/parisc/include/asm/thread_info.h     |    5 +-
+ arch/parisc/kernel/signal.c               |   45 +++-----
+ arch/parisc/kernel/syscall.S              |    9 +-
+ arch/powerpc/include/asm/thread_info.h    |    2 +
+ arch/powerpc/kernel/entry_64.S            |    5 +-
+ arch/powerpc/kernel/signal_32.c           |    1 -
+ arch/s390/include/asm/thread_info.h       |    4 -
+ arch/score/include/asm/thread_info.h      |    4 -
+ arch/score/kernel/signal.c                |    1 +
+ arch/sh/include/asm/thread_info.h         |    3 +
+ arch/sh/kernel/cpu/sh5/entry.S            |    2 +-
+ arch/sh/kernel/entry-common.S             |    2 +-
+ arch/sh/kernel/signal_32.c                |    1 -
+ arch/sh/kernel/signal_64.c                |    1 -
+ arch/sparc/include/asm/thread_info_32.h   |    3 +-
+ arch/sparc/include/asm/thread_info_64.h   |    3 +
+ arch/tile/kernel/compat_signal.c          |    9 --
+ arch/tile/kernel/signal.c                 |   12 +--
+ arch/um/include/asm/thread_info.h         |    3 -
+ arch/unicore32/include/asm/thread_info.h  |    4 +-
+ arch/unicore32/kernel/entry.S             |    2 -
+ arch/unicore32/kernel/signal.c            |    1 -
+ arch/x86/include/asm/thread_info.h        |    2 -
+ arch/x86/kernel/entry_32.S                |   17 ++-
+ arch/x86/kernel/process.c                 |    2 +-
+ arch/x86/kernel/signal.c                  |    4 -
+ arch/x86/kernel/vm86_32.c                 |    2 +-
+ arch/xtensa/include/asm/thread_info.h     |    5 -
+ arch/xtensa/kernel/signal.c               |    4 -
+ kernel/sched/core.c                       |    2 +-
+ kernel/timer.c                            |    9 --
+ 75 files changed, 284 insertions(+), 525 deletions(-)
+Merging scsi-post-merge/merge-base:master ()
+$ git clone -s -l -n -q . ../rebase-tmp
+$ cd ../rebase-tmp
+$ git fetch --no-tags ../next refs/heads/quilt/akpm:akpm
+From ../next
+ * [new branch]      quilt/akpm -> akpm
+$ git fetch --no-tags ../next refs/heads/quilt/akpm-base:akpm-base
+From ../next
+ * [new branch]      quilt/akpm-base -> akpm-base
+$ git checkout akpm
+Switched to branch 'akpm'
+$ git rebase --onto master akpm-base
+First, rewinding head to replay your work on top of it...
+Applying: selinux: fix something
+Applying: memory hotplug: fix invalid memory access caused by stale kswapd pointer
+Applying: memory-hotplug-fix-invalid-memory-access-caused-by-stale-kswapd-pointer-fix
+Applying: drivers/rtc/rtc-spear.c: fix use-after-free in spear_rtc_remove()
+Applying: mn10300: move setup_jiffies_interrupt() to cevt-mn10300.c
+Applying: mn10300: remove duplicate definition of PTRACE_O_TRACESYSGOOD
+Applying: mn10300: kernel/internal.h needs <linux/irqreturn.h>
+Applying: mn10300: kernel/traps.c needs <linux/export.h>
+Applying: mn10300: mm/dma-alloc.c needs <linux/export.h>
+Applying: mn10300: use "#elif defined(CONFIG_*)" instead of "#elif CONFIG_*"
+Applying: ocfs2: fix NULL pointer dereference in __ocfs2_change_file_space()
+Applying: c/r: prctl: less paranoid prctl_set_mm_exe_file()
+Applying: drivers/gpio/devres.c: export devm_gpio_request_one() to modules
+Applying: mm, thp: abort compaction if migration page cannot be charged to memcg
+Applying: cciss: fix incorrect scsi status reporting
+Applying: arch/x86/platform/iris/iris.c: register a platform device and a platform driver
+Applying: arch/x86/include/asm/spinlock.h: fix comment
+Applying: arch/x86/kernel/cpu/perf_event_intel_uncore.h: make UNCORE_PMU_HRTIMER_INTERVAL 64-bit
+Applying: timeconst.pl: remove deprecated defined(@array)
+Applying: time: don't inline EXPORT_SYMBOL functions
+Applying: thermal: fix potential out-of-bounds memory access
+Applying: ocfs2: use find_last_bit()
+Applying: ocfs2: use bitmap_weight()
+Applying: drivers/scsi/ufs: use module_pci_driver
+Applying: drivers/scsi/ufs: reverse the ufshcd_is_device_present logic
+Applying: drivers/scsi/ufs: fix incorrect return value about SUCCESS and FAILED
+Applying: drivers/scsi/atp870u.c: fix bad use of udelay
+Applying: vfs: increment iversion when a file is truncated
+Applying: fs: push rcu_barrier() from deactivate_locked_super() to filesystems
+Applying: hfs: push lock_super down
+Applying: hfs: get rid of lock_super
+Applying: hfs: remove extra mdb write on unmount
+Applying: hfs: simplify a bit checking for R/O
+Applying: hfs: introduce VFS superblock object back-reference
+Applying: hfs: get rid of hfs_sync_super
+Applying: hfs-get-rid-of-hfs_sync_super-checkpatch-fixes
+Applying: fs/xattr.c:getxattr(): improve handling of allocation failures
+Applying: fs: add link restrictions
+Applying: mm/slab: remove duplicate check
+Applying: slab: move FULL state transition to an initcall
+Applying: vmalloc: walk vmap_areas by sorted list instead of rb_next()
+Applying: mm: make vb_alloc() more foolproof
+Applying: mm-make-vb_alloc-more-foolproof-fix
+Applying: memcg: rename MEM_CGROUP_STAT_SWAPOUT as MEM_CGROUP_STAT_SWAP
+Applying: memcg: rename MEM_CGROUP_CHARGE_TYPE_MAPPED as MEM_CGROUP_CHARGE_TYPE_ANON
+Applying: memcg: remove MEM_CGROUP_CHARGE_TYPE_FORCE
+Applying: swap: allow swap readahead to be merged
+Applying: documentation: update how page-cluster affects swap I/O
+Applying: mm: account the total_vm in the vm_stat_account()
+Applying: mm: compaction: handle incorrect MIGRATE_UNMOVABLE type pageblocks
+Applying: mm-compaction-handle-incorrect-migrate_unmovable-type-pageblocks-fix
+Applying: mm/buddy: cleanup on should_fail_alloc_page
+Applying: mm: prepare for removal of obsolete /proc/sys/vm/nr_pdflush_threads
+Applying: hugetlb: rename max_hstate to hugetlb_max_hstate
+Applying: hugetlb: don't use ERR_PTR with VM_FAULT* values
+Applying: hugetlb: add an inline helper for finding hstate index
+Applying: hugetlb: use mmu_gather instead of a temporary linked list for accumulating pages
+Applying: hugetlb: avoid taking i_mmap_mutex in unmap_single_vma() for hugetlb
+Applying: hugetlb: simplify migrate_huge_page()
+Applying: hugetlb: add a list for tracking in-use HugeTLB pages
+Applying: hugetlb: make some static variables global
+Applying: hugeltb: mark hugelb_max_hstate __read_mostly
+Applying: mm/hugetlb: add new HugeTLB cgroup
+Applying: hugetlb/cgroup: Mark root_h_cgroup static
+Applying: hugetlb/cgroup: add the cgroup pointer to page lru
+Applying: hugetlb/cgroup: add charge/uncharge routines for hugetlb cgroup
+Applying: hugetlb/cgroup: add support for cgroup removal
+Applying: hugetlb/cgroup: add hugetlb cgroup control files
+Applying: hugetlb/cgroup: migrate hugetlb cgroup info from oldpage to new page during migration
+Applying: hugetlb/cgroup: add HugeTLB controller documentation
+Applying: hugetlb: move all the in use pages to active list
+Applying: hugetlb/cgroup: assign the page hugetlb cgroup when we move the page to active list.
+Applying: hugetlb/cgroup: remove exclude and wakeup rmdir calls from migrate
+Applying: mm, oom: do not schedule if current has been killed
+Applying: mm/memblock.c:memblock_double_array(): cosmetic cleanups
+Applying: memcg: remove check for signal_pending() during rmdir()
+Applying: memcg: clean up force_empty_list() return value check
+Applying: memcg: mem_cgroup_move_parent() doesn't need gfp_mask
+Applying: memcg: make mem_cgroup_force_empty_list() return bool
+Applying: memcg-make-mem_cgroup_force_empty_list-return-bool-fix
+Applying: mm/compaction: cleanup on compaction_deferred
+Applying: memcg: prevent OOM with too many dirty pages
+Applying: tmpfs: implement NUMA node interleaving
+Applying: tmpfs-implement-numa-node-interleaving-fix
+Applying: avr32/mm/fault.c: port OOM changes to do_page_fault
+Applying: avr32-mm-faultc-port-oom-changes-to-do_page_fault-fix
+Applying: clk: add non CONFIG_HAVE_CLK routines
+Applying: clk: remove redundant depends on from drivers/Kconfig
+Applying: i2c/i2c-pxa: remove conditional compilation of clk code
+Applying: usb/marvell: remove conditional compilation of clk code
+Applying: usb/musb: remove conditional compilation of clk code
+Applying: ata/pata_arasan: remove conditional compilation of clk code
+Applying: net/c_can: remove conditional compilation of clk code
+Applying: net/stmmac: remove conditional compilation of clk code
+Applying: gadget/m66592: remove conditional compilation of clk code
+Applying: gadget/r8a66597: remove conditional compilation of clk code
+Applying: usb/host/r8a66597: remove conditional compilation of clk code
+Applying: clk: validate pointer in __clk_disable()
+Applying: NMI watchdog: fix for lockup detector breakage on resume
+Applying: kmsg: /dev/kmsg - properly return possible copy_from_user() failure
+Applying: printk: add generic functions to find KERN_<LEVEL> headers
+Applying: printk-add-generic-functions-to-find-kern_level-headers-fix
+Applying: printk: add kern_levels.h to make KERN_<LEVEL> available for asm use
+Applying: arch: remove direct definitions of KERN_<LEVEL> uses
+Applying: btrfs: use printk_get_level and printk_skip_level, add __printf, fix fallout
+Applying: btrfs-use-printk_get_level-and-printk_skip_level-add-__printf-fix-fallout-fix
+Applying: btrfs-use-printk_get_level-and-printk_skip_level-add-__printf-fix-fallout-checkpatch-fixes
+Applying: sound: use printk_get_level and printk_skip_level
+Applying: printk: convert the format for KERN_<LEVEL> to a 2 byte pattern
+Applying: printk: only look for prefix levels in kernel messages
+Applying: printk: remove the now unnecessary "C" annotation for KERN_CONT
+Applying: vsprintf: add %pMR for Bluetooth MAC address
+Applying: Documentation/printk-formats.txt: add description for %pMR
+Applying: lib/vsprintf.c: remind people to update Documentation/printk-formats.txt when adding printk formats
+Applying: drivers/video/backlight/atmel-pwm-bl.c: use devm_ functions
+Applying: drivers/video/backlight/ot200_bl.c: use devm_ functions
+Applying: drivers/video/backlight/lm3533_bl.c: use devm_ functions
+Applying: backlight: atmel-pwm-bl: use devm_gpio_request()
+Applying: backlight: ot200_bl: use devm_gpio_request()
+Applying: backlight: tosa_lcd: use devm_gpio_request()
+Applying: backlight: tosa_bl: use devm_gpio_request()
+Applying: backlight: lms283gf05: use devm_gpio_request()
+Applying: backlight: corgi_lcd: use devm_gpio_request()
+Applying: backlight: l4f00242t03: export and use devm_gpio_request_one()
+Applying: string: introduce memweight()
+Applying: string-introduce-memweight-fix
+Applying: string: fix build error caused by memweight() introduction
+Applying: qnx4fs: use memweight()
+Applying: dm: use memweight()
+Applying: affs: use memweight()
+Applying: video/uvc: use memweight()
+Applying: ocfs2: use memweight()
+Applying: ext2: use memweight()
+Applying: ext3: use memweight()
+Applying: ext4: use memweight()
+Applying: checkpatch: Update alignment check
+Applying: checkpatch: test for non-standard signatures
+Applying: checkpatch: check usleep_range() arguments
+Applying: drivers/rtc/rtc-coh901331.c: use clk_prepare/unprepare
+Applying: drivers/rtc/rtc-coh901331.c: use devm allocation
+Applying: drivers/rtc/rtc-ab8500.c: use IRQF_ONESHOT when requesting a threaded IRQ
+Applying: rtc: pl031: encapsulate per-vendor ops
+Applying: rtc: pl031: use per-vendor variables for special init
+Applying: rtc: pl031: fix up IRQ flags
+Applying: drivers/rtc/rtc-ab8500.c: use UIE emulation
+Applying: drivers-rtc-rtc-ab8500c-use-uie-emulation-checkpatch-fixes
+Applying: drivers/rtc/rtc-ab8500.c: remove fix for AB8500 ED version
+Applying: drivers/rtc/rtc-r9701.c: avoid second call to rtc_valid_tm()
+Applying: drivers/rtc/rtc-r9701.c: check that r9701_set_datetime() succeeded
+Applying: hfsplus: use -ENOMEM when kzalloc() fails
+Applying: hfsplus: make hfsplus_sync_fs() static
+Applying: hfsplus: amend debugging print
+Applying: hfsplus: remove useless check
+Applying: hfsplus: get rid of write_super
+Applying: hfsplus-get-rid-of-write_super-checkpatch-fixes
+Applying: kmod: avoid deadlock from recursive kmod call
+Applying: fork: use vma_pages() to simplify the code
+Applying: fork-use-vma_pages-to-simplify-the-code-fix
+Applying: ipc/sem.c: alternatives to preempt_disable()
+Applying: fs: cachefiles: add support for large files in filesystem caching
+Applying: fs-cachefiles-add-support-for-large-files-in-filesystem-caching-fix
+Applying: c/r: fcntl: add F_GETOWNER_UIDS option
+$ cd ../next
+$ git fetch -f ../rebase-tmp akpm:quilt/akpm
+From ../rebase-tmp
+ + 5e84c96...0021853 akpm       -> quilt/akpm  (forced update)
+$ rm -rf ../rebase-tmp
+Merging quilt/akpm (0021853 c/r: fcntl: add F_GETOWNER_UIDS option)
+$ git merge --no-ff quilt/akpm
+Merge made by the 'recursive' strategy.
+ .../ABI/obsolete/proc-sys-vm-nr_pdflush_threads    |    5 +
+ Documentation/cgroups/hugetlb.txt                  |   45 +++
+ Documentation/feature-removal-schedule.txt         |    8 +
+ Documentation/printk-formats.txt                   |    5 +
+ Documentation/sysctl/fs.txt                        |   42 ++
+ Documentation/sysctl/vm.txt                        |   23 +-
+ arch/arm/lib/io-acorn.S                            |    3 +-
+ arch/arm/vfp/vfphw.S                               |    7 +-
+ arch/avr32/mm/fault.c                              |   33 +-
+ arch/frv/kernel/kernel_thread.S                    |    2 +-
+ arch/ia64/kernel/perfmon.c                         |    1 -
+ arch/mn10300/include/asm/ptrace.h                  |    3 -
+ arch/mn10300/include/asm/timex.h                   |   11 -
+ arch/mn10300/kernel/cevt-mn10300.c                 |   10 +
+ arch/mn10300/kernel/internal.h                     |    2 +
+ arch/mn10300/kernel/irq.c                          |    4 +-
+ arch/mn10300/kernel/traps.c                        |    1 +
+ arch/mn10300/mm/dma-alloc.c                        |    1 +
+ arch/mn10300/unit-asb2303/include/unit/timex.h     |    4 -
+ arch/mn10300/unit-asb2303/smc91111.c               |    1 +
+ arch/mn10300/unit-asb2305/include/unit/timex.h     |    4 -
+ arch/mn10300/unit-asb2305/unit-init.c              |    1 +
+ arch/mn10300/unit-asb2364/include/unit/timex.h     |    4 -
+ arch/x86/include/asm/spinlock.h                    |    3 +-
+ arch/x86/kernel/cpu/perf_event_intel_uncore.h      |    2 +-
+ arch/x86/platform/iris/iris.c                      |   67 +++-
+ drivers/ata/pata_arasan_cf.c                       |   14 +-
+ drivers/block/cciss_scsi.c                         |   11 +-
+ drivers/clk/Kconfig                                |    1 -
+ drivers/clk/clk.c                                  |    3 +
+ drivers/gpio/devres.c                              |    1 +
+ drivers/i2c/busses/i2c-pxa.c                       |    7 -
+ drivers/md/dm-log.c                                |   13 +-
+ drivers/media/video/uvc/uvc_ctrl.c                 |    5 +-
+ drivers/net/can/c_can/c_can_platform.c             |    8 -
+ drivers/net/ethernet/stmicro/stmmac/stmmac.h       |   42 --
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   33 +-
+ drivers/rtc/Kconfig                                |    1 +
+ drivers/rtc/rtc-ab8500.c                           |   44 +-
+ drivers/rtc/rtc-coh901331.c                        |   61 ++-
+ drivers/rtc/rtc-pl031.c                            |   95 +++--
+ drivers/rtc/rtc-r9701.c                            |    6 +-
+ drivers/rtc/rtc-spear.c                            |    2 +-
+ drivers/scsi/atp870u.c                             |   11 +-
+ drivers/scsi/ufs/ufshcd.c                          |   35 +-
+ drivers/thermal/thermal_sys.c                      |    5 +-
+ drivers/usb/gadget/m66592-udc.c                    |    9 +-
+ drivers/usb/gadget/m66592-udc.h                    |    5 -
+ drivers/usb/gadget/r8a66597-udc.c                  |   11 +-
+ drivers/usb/gadget/r8a66597-udc.h                  |    5 -
+ drivers/usb/host/r8a66597-hcd.c                    |   12 -
+ drivers/usb/host/r8a66597.h                        |    5 -
+ drivers/usb/musb/musb_core.h                       |    8 -
+ drivers/video/backlight/atmel-pwm-bl.c             |   19 +-
+ drivers/video/backlight/corgi_lcd.c                |   19 +-
+ drivers/video/backlight/l4f00242t03.c              |   29 +-
+ drivers/video/backlight/lm3533_bl.c                |    8 +-
+ drivers/video/backlight/lms283gf05.c               |   24 +-
+ drivers/video/backlight/ot200_bl.c                 |   21 +-
+ drivers/video/backlight/tosa_bl.c                  |    8 +-
+ drivers/video/backlight/tosa_lcd.c                 |    7 +-
+ fs/9p/v9fs.c                                       |    5 +
+ fs/Kconfig                                         |   60 +++
+ fs/adfs/super.c                                    |    5 +
+ fs/affs/bitmap.c                                   |   28 +-
+ fs/affs/super.c                                    |    5 +
+ fs/afs/super.c                                     |    5 +
+ fs/attr.c                                          |    5 +
+ fs/befs/linuxvfs.c                                 |    5 +
+ fs/bfs/inode.c                                     |    5 +
+ fs/btrfs/ctree.h                                   |   13 +
+ fs/btrfs/disk-io.c                                 |    2 +-
+ fs/btrfs/extent_io.c                               |    6 +
+ fs/btrfs/inode.c                                   |    5 +
+ fs/btrfs/relocation.c                              |    2 +-
+ fs/btrfs/super.c                                   |   41 +-
+ fs/cachefiles/rdwr.c                               |    2 +-
+ fs/ceph/super.c                                    |    5 +
+ fs/cifs/cifsfs.c                                   |    5 +
+ fs/coda/inode.c                                    |    5 +
+ fs/ecryptfs/main.c                                 |    6 +
+ fs/efs/super.c                                     |    5 +
+ fs/exofs/super.c                                   |    5 +
+ fs/ext2/balloc.c                                   |   14 +-
+ fs/ext2/ialloc.c                                   |    1 +
+ fs/ext2/super.c                                    |    5 +
+ fs/ext3/balloc.c                                   |    2 +-
+ fs/ext3/bitmap.c                                   |   12 +-
+ fs/ext3/super.c                                    |    5 +
+ fs/ext4/bitmap.c                                   |   11 +-
+ fs/ext4/super.c                                    |    5 +
+ fs/fat/inode.c                                     |    5 +
+ fs/fcntl.c                                         |   29 ++
+ fs/freevxfs/vxfs_super.c                           |    5 +
+ fs/fs-writeback.c                                  |    5 -
+ fs/fuse/inode.c                                    |    6 +
+ fs/hfs/extent.c                                    |    2 +-
+ fs/hfs/hfs_fs.h                                    |   15 +-
+ fs/hfs/inode.c                                     |   14 +-
+ fs/hfs/mdb.c                                       |   15 +
+ fs/hfs/super.c                                     |   79 ++--
+ fs/hfsplus/bitmap.c                                |    4 +-
+ fs/hfsplus/dir.c                                   |    2 +-
+ fs/hfsplus/hfsplus_fs.h                            |    7 +-
+ fs/hfsplus/inode.c                                 |    6 +-
+ fs/hfsplus/super.c                                 |   54 ++-
+ fs/hpfs/super.c                                    |    5 +
+ fs/hugetlbfs/inode.c                               |    9 +-
+ fs/isofs/inode.c                                   |    5 +
+ fs/jffs2/super.c                                   |    6 +
+ fs/jfs/super.c                                     |    6 +
+ fs/logfs/inode.c                                   |    5 +
+ fs/minix/inode.c                                   |    5 +
+ fs/namei.c                                         |  143 +++++++
+ fs/ncpfs/inode.c                                   |    5 +
+ fs/nfs/inode.c                                     |    5 +
+ fs/nilfs2/super.c                                  |    6 +
+ fs/ntfs/super.c                                    |    6 +
+ fs/ocfs2/cluster/heartbeat.c                       |   40 +-
+ fs/ocfs2/dlmfs/dlmfs.c                             |    5 +
+ fs/ocfs2/file.c                                    |    2 +-
+ fs/ocfs2/localalloc.c                              |    8 +-
+ fs/ocfs2/super.c                                   |    5 +
+ fs/openpromfs/inode.c                              |    5 +
+ fs/qnx4/bitmap.c                                   |   24 +-
+ fs/qnx4/inode.c                                    |    5 +
+ fs/qnx6/inode.c                                    |    5 +
+ fs/reiserfs/super.c                                |    5 +
+ fs/romfs/super.c                                   |    5 +
+ fs/squashfs/super.c                                |    5 +
+ fs/super.c                                         |    6 -
+ fs/sysv/inode.c                                    |    5 +
+ fs/ubifs/super.c                                   |    6 +
+ fs/udf/super.c                                     |    5 +
+ fs/ufs/super.c                                     |    5 +
+ fs/xattr.c                                         |   16 +-
+ fs/xfs/xfs_super.c                                 |    5 +
+ include/asm-generic/fcntl.h                        |    4 +
+ include/linux/audit.h                              |    3 +
+ include/linux/backing-dev.h                        |    3 +
+ include/linux/cgroup_subsys.h                      |    6 +
+ include/linux/clk.h                                |  168 +++++---
+ include/linux/compaction.h                         |   23 +-
+ include/linux/fs.h                                 |    2 +
+ include/linux/hugetlb.h                            |   39 +-
+ include/linux/hugetlb_cgroup.h                     |  126 ++++++
+ include/linux/kern_levels.h                        |   25 ++
+ include/linux/migrate.h                            |    4 +-
+ include/linux/mm.h                                 |    1 +
+ include/linux/mmzone.h                             |    2 +-
+ include/linux/platform_data/mv_usb.h               |    9 -
+ include/linux/printk.h                             |   41 +-
+ include/linux/sched.h                              |    8 +
+ include/linux/shmem_fs.h                           |    1 +
+ include/linux/string.h                             |    3 +
+ include/linux/vm_event_item.h                      |    1 +
+ include/linux/writeback.h                          |    5 -
+ init/Kconfig                                       |   15 +
+ ipc/sem.c                                          |  250 ++++++++----
+ kernel/audit.c                                     |   20 +
+ kernel/fork.c                                      |    8 +-
+ kernel/kmod.c                                      |   31 +-
+ kernel/power/suspend.c                             |    3 +
+ kernel/printk.c                                    |   32 +-
+ kernel/sys.c                                       |   16 +-
+ kernel/sysctl.c                                    |   28 +-
+ kernel/sysctl_binary.c                             |    2 +-
+ kernel/time.c                                      |    4 +-
+ kernel/timeconst.pl                                |    2 +-
+ kernel/watchdog.c                                  |   21 +-
+ lib/Makefile                                       |    2 +-
+ lib/memweight.c                                    |   38 ++
+ lib/vsprintf.c                                     |   25 +-
+ mm/Makefile                                        |    1 +
+ mm/backing-dev.c                                   |   20 +
+ mm/compaction.c                                    |  146 +++++--
+ mm/hugetlb.c                                       |  167 +++++---
+ mm/hugetlb_cgroup.c                                |  420 ++++++++++++++++++++
+ mm/internal.h                                      |   11 +-
+ mm/memblock.c                                      |   35 +-
+ mm/memcontrol.c                                    |   57 +--
+ mm/memory-failure.c                                |   13 +-
+ mm/memory.c                                        |    2 +-
+ mm/migrate.c                                       |   70 ++--
+ mm/mmap.c                                          |    5 +-
+ mm/mremap.c                                        |    2 -
+ mm/oom_kill.c                                      |   11 +-
+ mm/page_alloc.c                                    |   50 ++-
+ mm/shmem.c                                         |    8 +-
+ mm/slab.c                                          |    8 +-
+ mm/swap_state.c                                    |    5 +
+ mm/vmalloc.c                                       |   16 +-
+ mm/vmscan.c                                        |   23 +-
+ mm/vmstat.c                                        |    1 +
+ scripts/checkpatch.pl                              |   26 +-
+ security/selinux/hooks.c                           |    3 +-
+ sound/core/misc.c                                  |   13 +-
+ 197 files changed, 2732 insertions(+), 1128 deletions(-)
+ create mode 100644 Documentation/ABI/obsolete/proc-sys-vm-nr_pdflush_threads
+ create mode 100644 Documentation/cgroups/hugetlb.txt
+ create mode 100644 include/linux/hugetlb_cgroup.h
+ create mode 100644 include/linux/kern_levels.h
+ create mode 100644 lib/memweight.c
+ create mode 100644 mm/hugetlb_cgroup.c
+$ git revert 30ebb0baeef5
+[master c9a4037] Revert "If CONFIG_DM_DEBUG_SPACE_MAPS is enabled and memory is fragmented and a"
+ 1 file changed, 11 insertions(+), 18 deletions(-)
diff --git a/Next/quilt-import.log b/Next/quilt-import.log
new file mode 100644
index 0000000..b1123df
--- /dev/null
+++ b/Next/quilt-import.log
@@ -0,0 +1,63 @@
+Importing i2c based on aace99e57c90353a51952e9dd1f6f110eec30d15
+$ git clone -s -l -n -q . ../quilt-tmp
+$ cd ../quilt-tmp
+$ git reset --hard aace99e57c90353a51952e9dd1f6f110eec30d15
+HEAD is now at aace99e Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
+$ git am ../quilt/i2c/i2c-update-Guenter-Roeck-address.patch
+Applying: i2c: Update Guenter's Roeck e-mail address
+$ git am ../quilt/i2c/i2c-use-module_pci_driver.patch
+Applying: i2c/busses: Use module_pci_driver
+$ git am ../quilt/i2c/i2c-piix4-01-eliminate-piix4_smba-global-variable.patch
+Applying: i2c-piix4: Eliminate piix4_smba global variable
+$ git am ../quilt/i2c/i2c-piix4-02-separate-registration-and-probing-code.patch
+Applying: i2c-piix4: Separate registration and probing code
+$ git am ../quilt/i2c/i2c-piix4-03-support-amd-auxiliary-smbus-controller.patch
+Applying: i2c-piix4: Support AMD auxiliary SMBus controller
+$ git am ../quilt/i2c/i2c-writing-clients-mention-module_i2c_driver.patch
+Applying: i2c/writing-clients: Mention module_i2c_driver()
+$ cd ../next
+$ git fetch -f ../quilt-tmp master:quilt/i2c
+From ../quilt-tmp
+ + 7f56c63...d170f6c master     -> quilt/i2c  (forced update)
+Importing jdelvare-hwmon based on 02edf6abe01610a5fb379df442de3c837ad99467
+Unchanged quilt series jdelvare-hwmon
+Importing rr based on v3.5-rc3-93-g02edf6a
+Unchanged quilt series rr
+Importing device-mapper based on v3.5-rc1
+$ cd ../quilt-tmp
+$ git reset --hard f8f5701bdaf9134b1f90e5044a82c66324d2073f
+HEAD is now at f8f5701 Linux 3.5-rc1
+$ git am ../quilt/device-mapper/dm-thin-commit-metadata-before-creating-metadata-snapshot.patch
+Applying: Userland sometimes sees a corrupt metadata block if metadata is changing
+$ git am ../quilt/device-mapper/dm-persistent-data-fix-shadow_info_leak-on-dm_tm_destroy.patch
+Applying: Cleanup the shadow table before destroying the transaction manager.
+$ git am ../quilt/device-mapper/dm-persistent-data-handle-space-map-checker-creation-failure.patch
+Applying: If CONFIG_DM_DEBUG_SPACE_MAPS is enabled and dm_sm_checker_create()
+$ git am ../quilt/device-mapper/dm-persistent-data-fix-allocation-failure-in-space-map-checker-init.patch
+Applying: If CONFIG_DM_DEBUG_SPACE_MAPS is enabled and memory is fragmented and a
+$ git am ../quilt/device-mapper/dm-verity-fix-documentation.patch
+Applying: Fix target line specification.
+$ git am ../quilt/device-mapper/dm-thin-clean-up-compiler-warning.patch
+Applying: Clean up "warning: dubious: !x & y".  Also make it clear that
+$ git am ../quilt/device-mapper/dm-thin-provide-specific-errors-for-two-table-load-failure-cases.patch
+Applying: Provide specific error message strings for two pool_ctr() failure cases
+$ git am ../quilt/device-mapper/dm-stripe-fix-size-test.patch
+Applying: dm-stripe is supposed to ensure that all the space allocated to the
+$ git am ../quilt/device-mapper/dm-stripe-remove-stripes_mask.patch
+Applying: The structure stripe_c contains a stripes_mask field. This field is
+$ git am ../quilt/device-mapper/dm-support-non-power-of-two-target-max_io_len.patch
+Applying: Remove the restriction that limits a target's specified maximum incoming
+$ git am ../quilt/device-mapper/dm-stripe-support-for-non-power-of-2-chunksize.patch
+Applying: Non power of 2 chunksize support is needed to properly align stripe IO
+$ git am ../quilt/device-mapper/dm-stripe-remove-minimum-stripe-size.patch
+Applying: There is no technical limitation in device mapper that would prevent the
+$ git am ../quilt/device-mapper/dm-stripe-optimize-chunk_size-calculations.patch
+Applying: dm-stripe is usually used with a chunk size that is a power of two.
+$ git am ../quilt/device-mapper/dm-thin-support-for-non-power-of-2-pool-blocksize.patch
+Applying: Non power of 2 blocksize support is needed to properly align thinp IO
+$ git am ../quilt/device-mapper/dm-thin-optimize-power-of-two-block-size.patch
+Applying: dm-thin will be most likely used with a block size that is a power of
+$ cd ../next
+$ git fetch -f ../quilt-tmp master:quilt/device-mapper
+From ../quilt-tmp
+ + f87f942...4e66fde master     -> quilt/device-mapper  (forced update)
diff --git a/arch/alpha/include/asm/errno.h b/arch/alpha/include/asm/errno.h
index e5f29ca..a4fc77e 100644
--- a/arch/alpha/include/asm/errno.h
+++ b/arch/alpha/include/asm/errno.h
@@ -124,4 +124,8 @@
 
 #define EHWPOISON	139	/* Memory page has hardware error */
 
+#define	ENOAUTHSERVICE	140	/* Authentication service not available */
+#define	ENONAMESERVICE	141	/* Network name service unavailable */
+#define	ENAMEUNKNOWN	142	/* Network name unknown */
+
 #endif
diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrace.h
index fd698a1..b87755a 100644
--- a/arch/alpha/include/asm/ptrace.h
+++ b/arch/alpha/include/asm/ptrace.h
@@ -76,7 +76,10 @@ struct switch_stack {
 #define task_pt_regs(task) \
   ((struct pt_regs *) (task_stack_page(task) + 2*PAGE_SIZE) - 1)
 
-#define force_successful_syscall_return() (task_pt_regs(current)->r0 = 0)
+#define current_pt_regs() \
+  ((struct pt_regs *) ((char *)current_thread_info() + 2*PAGE_SIZE) - 1)
+
+#define force_successful_syscall_return() (current_pt_regs()->r0 = 0)
 
 #endif
 
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 28335bd..4554ecb 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -84,7 +84,6 @@ register struct thread_info *__current_thread_info __asm__("$8");
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 
 /* Work to do on interrupt/exception return.  */
@@ -117,5 +116,7 @@ register struct thread_info *__current_thread_info __asm__("$8");
 		 (int __user *)(value));				\
 	})
 
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif /* __KERNEL__ */
 #endif /* _ALPHA_THREAD_INFO_H */
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index d96e742..b77b813 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -52,7 +52,6 @@ EXPORT_SYMBOL(alpha_write_fp_reg_s);
 
 /* entry.S */
 EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(kernel_execve);
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_tcpudp_magic);
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 6d159ce..ec0da05 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -663,58 +663,6 @@ kernel_thread:
 	br	ret_to_kernel
 .end kernel_thread
 
-/*
- * kernel_execve(path, argv, envp)
- */
-	.align	4
-	.globl	kernel_execve
-	.ent	kernel_execve
-kernel_execve:
-	/* We can be called from a module.  */
-	ldgp	$gp, 0($27)
-	lda	$sp, -(32+SIZEOF_PT_REGS+8)($sp)
-	.frame	$sp, 32+SIZEOF_PT_REGS+8, $26, 0
-	stq	$26, 0($sp)
-	stq	$16, 8($sp)
-	stq	$17, 16($sp)
-	stq	$18, 24($sp)
-	.prologue 1
-
-	lda	$16, 32($sp)
-	lda	$17, 0
-	lda	$18, SIZEOF_PT_REGS
-	bsr	$26, memset		!samegp
-
-	/* Avoid the HAE being gratuitously wrong, which would cause us
-	   to do the whole turn off interrupts thing and restore it.  */
-	ldq	$2, alpha_mv+HAE_CACHE
-	stq	$2, 152+32($sp)
-
-	ldq	$16, 8($sp)
-	ldq	$17, 16($sp)
-	ldq	$18, 24($sp)
-	lda	$19, 32($sp)
-	bsr	$26, do_execve		!samegp
-
-	ldq	$26, 0($sp)
-	bne	$0, 1f			/* error! */
-
-	/* Move the temporary pt_regs struct from its current location
-	   to the top of the kernel stack frame.  See copy_thread for
-	   details for a normal process.  */
-	lda	$16, 0x4000 - SIZEOF_PT_REGS($8)
-	lda	$17, 32($sp)
-	lda	$18, SIZEOF_PT_REGS
-	bsr	$26, memmove		!samegp
-
-	/* Take that over as our new stack frame and visit userland!  */
-	lda	$sp, 0x4000 - SIZEOF_PT_REGS($8)
-	br	$31, ret_from_sys_call
-
-1:	lda	$sp, 32+SIZEOF_PT_REGS+8($sp)
-	ret
-.end kernel_execve
-
 
 /*
  * Special system calls.  Most of these are special in that they either
@@ -797,115 +745,6 @@ sys_rt_sigreturn:
 .end sys_rt_sigreturn
 
 	.align	4
-	.globl	sys_sethae
-	.ent	sys_sethae
-sys_sethae:
-	.prologue 0
-	stq	$16, 152($sp)
-	ret
-.end sys_sethae
-
-	.align	4
-	.globl	osf_getpriority
-	.ent	osf_getpriority
-osf_getpriority:
-	lda	$sp, -16($sp)
-	stq	$26, 0($sp)
-	.prologue 0
-
-	jsr	$26, sys_getpriority
-
-	ldq	$26, 0($sp)
-	blt	$0, 1f
-
-	/* Return value is the unbiased priority, i.e. 20 - prio.
-	   This does result in negative return values, so signal
-	   no error by writing into the R0 slot.  */
-	lda	$1, 20
-	stq	$31, 16($sp)
-	subl	$1, $0, $0
-	unop
-
-1:	lda	$sp, 16($sp)
-	ret
-.end osf_getpriority
-
-	.align	4
-	.globl	sys_getxuid
-	.ent	sys_getxuid
-sys_getxuid:
-	.prologue 0
-	ldq	$2, TI_TASK($8)
-	ldq	$3, TASK_CRED($2)
-	ldl	$0, CRED_UID($3)
-	ldl	$1, CRED_EUID($3)
-	stq	$1, 80($sp)
-	ret
-.end sys_getxuid
-
-	.align	4
-	.globl	sys_getxgid
-	.ent	sys_getxgid
-sys_getxgid:
-	.prologue 0
-	ldq	$2, TI_TASK($8)
-	ldq	$3, TASK_CRED($2)
-	ldl	$0, CRED_GID($3)
-	ldl	$1, CRED_EGID($3)
-	stq	$1, 80($sp)
-	ret
-.end sys_getxgid
-
-	.align	4
-	.globl	sys_getxpid
-	.ent	sys_getxpid
-sys_getxpid:
-	.prologue 0
-	ldq	$2, TI_TASK($8)
-
-	/* See linux/kernel/timer.c sys_getppid for discussion
-	   about this loop.  */
-	ldq	$3, TASK_GROUP_LEADER($2)
-	ldq	$4, TASK_REAL_PARENT($3)
-	ldl	$0, TASK_TGID($2)
-1:	ldl	$1, TASK_TGID($4)
-#ifdef CONFIG_SMP
-	mov	$4, $5
-	mb
-	ldq	$3, TASK_GROUP_LEADER($2)
-	ldq	$4, TASK_REAL_PARENT($3)
-	cmpeq	$4, $5, $5
-	beq	$5, 1b
-#endif
-	stq	$1, 80($sp)
-	ret
-.end sys_getxpid
-
-	.align	4
-	.globl	sys_alpha_pipe
-	.ent	sys_alpha_pipe
-sys_alpha_pipe:
-	lda	$sp, -16($sp)
-	stq	$26, 0($sp)
-	.prologue 0
-
-	mov	$31, $17
-	lda	$16, 8($sp)
-	jsr	$26, do_pipe_flags
-
-	ldq	$26, 0($sp)
-	bne	$0, 1f
-
-	/* The return values are in $0 and $20.  */
-	ldl	$1, 12($sp)
-	ldl	$0, 8($sp)
-
-	stq	$1, 80+16($sp)
-1:	lda	$sp, 16($sp)
-	ret
-.end sys_alpha_pipe
-
-	.align	4
 	.globl	sys_execve
 	.ent	sys_execve
 sys_execve:
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 98a1036..bc1acdd 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -1404,3 +1404,52 @@ SYSCALL_DEFINE3(osf_writev, unsigned long, fd,
 }
 
 #endif
+
+SYSCALL_DEFINE2(osf_getpriority, int, which, int, who)
+{
+	int prio = sys_getpriority(which, who);
+	if (prio >= 0) {
+		/* Return value is the unbiased priority, i.e. 20 - prio.
+		   This does result in negative return values, so signal
+		   no error */
+		force_successful_syscall_return();
+		prio = 20 - prio;
+	}
+	return prio;
+}
+
+SYSCALL_DEFINE0(getxuid)
+{
+	current_pt_regs()->r20 = sys_geteuid();
+	return sys_getuid();
+}
+
+SYSCALL_DEFINE0(getxgid)
+{
+	current_pt_regs()->r20 = sys_getegid();
+	return sys_getgid();
+}
+
+SYSCALL_DEFINE0(getxpid)
+{
+	current_pt_regs()->r20 = sys_getppid();
+	return sys_getpid();
+}
+
+SYSCALL_DEFINE0(alpha_pipe)
+{
+	int fd[2];
+	int res = do_pipe_flags(fd, 0);
+	if (!res) {
+		/* The return values are in $0 and $20.  */
+		current_pt_regs()->r20 = fd[1];
+		res = fd[0];
+	}
+	return res;
+}
+
+SYSCALL_DEFINE1(sethae, unsigned long, val)
+{
+	current_pt_regs()->hae = val;
+	return 0;
+}
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 1a62963..71efc1a 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -59,15 +59,13 @@ struct pci_controller *pci_isa_hose;
  * Quirks.
  */
 
-static void __init
-quirk_isa_bridge(struct pci_dev *dev)
+static void __devinit quirk_isa_bridge(struct pci_dev *dev)
 {
 	dev->class = PCI_CLASS_BRIDGE_ISA << 8;
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378, quirk_isa_bridge);
 
-static void __init
-quirk_cypress(struct pci_dev *dev)
+static void __devinit quirk_cypress(struct pci_dev *dev)
 {
 	/* The Notorious Cy82C693 chip.  */
 
@@ -106,8 +104,7 @@ quirk_cypress(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, quirk_cypress);
 
 /* Called for each device after PCI setup is done. */
-static void __init
-pcibios_fixup_final(struct pci_dev *dev)
+static void __devinit pcibios_fixup_final(struct pci_dev *dev)
 {
 	unsigned int class = dev->class >> 8;
 
@@ -359,7 +356,7 @@ common_init_pci(void)
 					hose, &resources);
 		hose->bus = bus;
 		hose->need_domain_info = need_domain_info;
-		next_busno = bus->subordinate + 1;
+		next_busno = bus->busn_res.end + 1;
 		/* Don't allow 8-bit bus number overflow inside the hose -
 		   reserve some space for bridges. */ 
 		if (next_busno > 224) {
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 153d3fc..6251146 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -455,3 +455,32 @@ get_wchan(struct task_struct *p)
 	}
 	return pc;
 }
+
+int kernel_execve(const char *path, const char *const argv[], const char *const envp[])
+{
+	/* Avoid the HAE being gratuitously wrong, which would cause us
+	   to do the whole turn off interrupts thing and restore it.  */
+	struct pt_regs regs = {.hae = alpha_mv.hae_cache};
+	int err = do_execve(path, argv, envp, &regs);
+	if (!err) {
+		/*
+		 * copy regs to normal position and off to userland we go...
+		 * note that we are not guaranteed that we are deep enough
+		 * in stack for current_pt_regs() not to overlap our stack
+		 * frame; memcpy() would not be safe and we _must_ do
+		 * everything starting from that memmove() in assembler.
+		 * And we can't mangle $sp until after the call of memmove()
+		 * either...
+		 */
+		__asm__ __volatile__ (
+			"lda	$16, %0\n"
+			"lda	$17, %1\n"
+			"lda	$18, %2\n"
+			"bsr	$26, memmove\n"
+			"lda	$sp, %0\n"
+			"jsr	$31, ret_from_sys_call\n"
+			: : "m"(*current_pt_regs()), "m"(regs), "Ir"(sizeof(struct pt_regs)));
+	}
+	return err;
+}
+EXPORT_SYMBOL(kernel_execve);
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index 8783523..0cfffdc 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -111,7 +111,7 @@ sys_call_table:
 	.quad sys_socket
 	.quad sys_connect
 	.quad sys_accept
-	.quad osf_getpriority			/* 100 */
+	.quad sys_osf_getpriority			/* 100 */
 	.quad sys_send
 	.quad sys_recv
 	.quad sys_sigreturn
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a91009c..9c0a22d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -647,6 +647,7 @@ config ARCH_TEGRA
 	select MIGHT_HAVE_CACHE_L2X0
 	select NEED_MACH_IO_H if PCI
 	select ARCH_HAS_CPUFREQ
+	select USE_OF
 	help
 	  This enables support for NVIDIA Tegra based systems (Tegra APX,
 	  Tegra 6xx and Tegra 2 series).
@@ -913,7 +914,7 @@ config ARCH_NOMADIK
 	select ARM_AMBA
 	select ARM_VIC
 	select CPU_ARM926T
-	select CLKDEV_LOOKUP
+	select COMMON_CLK
 	select GENERIC_CLOCKEVENTS
 	select PINCTRL
 	select MIGHT_HAVE_CACHE_L2X0
@@ -1739,59 +1740,6 @@ config FORCE_MAX_ZONEORDER
 	  This config option is actually maximum order plus one. For example,
 	  a value of 11 means that the largest free memory block is 2^10 pages.
 
-config LEDS
-	bool "Timer and CPU usage LEDs"
-	depends on ARCH_CDB89712 || ARCH_EBSA110 || \
-		   ARCH_EBSA285 || ARCH_INTEGRATOR || \
-		   ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \
-		   ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
-		   ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \
-		   ARCH_AT91 || ARCH_DAVINCI || \
-		   ARCH_KS8695 || MACH_RD88F5182 || ARCH_REALVIEW
-	help
-	  If you say Y here, the LEDs on your machine will be used
-	  to provide useful information about your current system status.
-
-	  If you are compiling a kernel for a NetWinder or EBSA-285, you will
-	  be able to select which LEDs are active using the options below. If
-	  you are compiling a kernel for the EBSA-110 or the LART however, the
-	  red LED will simply flash regularly to indicate that the system is
-	  still functional. It is safe to say Y here if you have a CATS
-	  system, but the driver will do nothing.
-
-config LEDS_TIMER
-	bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \
-			    OMAP_OSK_MISTRAL || MACH_OMAP_H2 \
-			    || MACH_OMAP_PERSEUS2
-	depends on LEDS
-	depends on !GENERIC_CLOCKEVENTS
-	default y if ARCH_EBSA110
-	help
-	  If you say Y here, one of the system LEDs (the green one on the
-	  NetWinder, the amber one on the EBSA285, or the red one on the LART)
-	  will flash regularly to indicate that the system is still
-	  operational. This is mainly useful to kernel hackers who are
-	  debugging unstable kernels.
-
-	  The LART uses the same LED for both Timer LED and CPU usage LED
-	  functions. You may choose to use both, but the Timer LED function
-	  will overrule the CPU usage LED.
-
-config LEDS_CPU
-	bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110 && \
-			!ARCH_OMAP) \
-			|| OMAP_OSK_MISTRAL || MACH_OMAP_H2 \
-			|| MACH_OMAP_PERSEUS2
-	depends on LEDS
-	help
-	  If you say Y here, the red LED will be used to give a good real
-	  time indication of CPU usage, by lighting whenever the idle task
-	  is not currently executing.
-
-	  The LART uses the same LED for both Timer LED and CPU usage LED
-	  functions. You may choose to use both, but the Timer LED function
-	  will overrule the CPU usage LED.
-
 config ALIGNMENT_TRAP
 	bool
 	depends on CPU_CP15_MMU
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 0298b00..f8ebf1e 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -10,6 +10,9 @@
 #
 # Copyright (C) 1995-2001 by Russell King
 
+# Ensure linker flags are correct
+LDFLAGS		:=
+
 LDFLAGS_vmlinux	:=-p --no-undefined -X
 ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
 LDFLAGS_vmlinux	+= --be8
diff --git a/arch/arm/arm-soc-for-next-contents.txt b/arch/arm/arm-soc-for-next-contents.txt
new file mode 100644
index 0000000..1b2dfb7
--- /dev/null
+++ b/arch/arm/arm-soc-for-next-contents.txt
@@ -0,0 +1,15 @@
+This file lists all branches that are pulled into the for-next branch
+of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
+and their external dependencies.
+
+It also includes a couple of directly applied patches for build breaks with subject
+The next/* branches are kept in the order in which they get applied.
+
+dependencies:
+<none at this time>
+
+next/drivers:
+devel/led-driver	git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git for-arm-soc
+
+next/soc:
+nomadik/drivercfg	git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git nomadik-for-arm-soc
diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 83e7229..4d641ea 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -118,6 +118,12 @@
 			interrupts = <0 90 4>;
 		};
 
+		memory-controller@fff00000 {
+			compatible = "calxeda,hb-ddr-ctrl";
+			reg = <0xfff00000 0x1000>;
+			interrupts = <0 91 4>;
+		};
+
 		ipc@fff20000 {
 			compatible = "arm,pl320", "arm,primecell";
 			reg = <0xfff20000 0x1000>;
@@ -188,6 +194,12 @@
 			reg = <0xfff3c000 0x1000>;
 		};
 
+		sregs@fff3c200 {
+			compatible = "calxeda,hb-sregs-l2-ecc";
+			reg = <0xfff3c200 0x100>;
+			interrupts = <0 71 4  0 72 4>;
+		};
+
 		dma@fff3d000 {
 			compatible = "arm,pl330", "arm,primecell";
 			reg = <0xfff3d000 0x1000>;
diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi
index bfa65ab..39eb88e 100644
--- a/arch/arm/boot/dts/imx51.dtsi
+++ b/arch/arm/boot/dts/imx51.dtsi
@@ -259,6 +259,13 @@
 				status = "disabled";
 			};
 
+			nand@83fdb000 {
+				compatible = "fsl,imx51-nand";
+				reg = <0x83fdb000 0x1000 0xcfff0000 0x10000>;
+				interrupts = <8>;
+				status = "disabled";
+			};
+
 			ssi3: ssi@83fe8000 {
 				compatible = "fsl,imx51-ssi", "fsl,imx21-ssi";
 				reg = <0x83fe8000 0x4000>;
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index e3e8694..2b5caf9 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -314,6 +314,13 @@
 				status = "disabled";
 			};
 
+			nand@63fdb000 {
+				compatible = "fsl,imx53-nand";
+				reg = <0x63fdb000 0x1000 0xf7ff0000 0x10000>;
+				interrupts = <8>;
+				status = "disabled";
+			};
+
 			ssi3: ssi@63fe8000 {
 				compatible = "fsl,imx53-ssi", "fsl,imx21-ssi";
 				reg = <0x63fe8000 0x4000>;
diff --git a/arch/arm/boot/dts/tegra-cardhu.dts b/arch/arm/boot/dts/tegra-cardhu.dts
deleted file mode 100644
index 36321bc..0000000
--- a/arch/arm/boot/dts/tegra-cardhu.dts
+++ /dev/null
@@ -1,172 +0,0 @@
-/dts-v1/;
-
-/include/ "tegra30.dtsi"
-
-/ {
-	model = "NVIDIA Tegra30 Cardhu evaluation board";
-	compatible = "nvidia,cardhu", "nvidia,tegra30";
-
-	memory {
-		reg = <0x80000000 0x40000000>;
-	};
-
-	pinmux {
-		pinctrl-names = "default";
-		pinctrl-0 = <&state_default>;
-
-		state_default: pinmux {
-			sdmmc1_clk_pz0 {
-				nvidia,pins = "sdmmc1_clk_pz0";
-				nvidia,function = "sdmmc1";
-				nvidia,pull = <0>;
-				nvidia,tristate = <0>;
-			};
-			sdmmc1_cmd_pz1 {
-				nvidia,pins =	"sdmmc1_cmd_pz1",
-						"sdmmc1_dat0_py7",
-						"sdmmc1_dat1_py6",
-						"sdmmc1_dat2_py5",
-						"sdmmc1_dat3_py4";
-				nvidia,function = "sdmmc1";
-				nvidia,pull = <2>;
-				nvidia,tristate = <0>;
-			};
-			sdmmc4_clk_pcc4 {
-				nvidia,pins =	"sdmmc4_clk_pcc4",
-						"sdmmc4_rst_n_pcc3";
-				nvidia,function = "sdmmc4";
-				nvidia,pull = <0>;
-				nvidia,tristate = <0>;
-			};
-			sdmmc4_dat0_paa0 {
-				nvidia,pins =	"sdmmc4_dat0_paa0",
-						"sdmmc4_dat1_paa1",
-						"sdmmc4_dat2_paa2",
-						"sdmmc4_dat3_paa3",
-						"sdmmc4_dat4_paa4",
-						"sdmmc4_dat5_paa5",
-						"sdmmc4_dat6_paa6",
-						"sdmmc4_dat7_paa7";
-				nvidia,function = "sdmmc4";
-				nvidia,pull = <2>;
-				nvidia,tristate = <0>;
-			};
-			dap2_fs_pa2 {
-				nvidia,pins =	"dap2_fs_pa2",
-						"dap2_sclk_pa3",
-						"dap2_din_pa4",
-						"dap2_dout_pa5";
-				nvidia,function = "i2s1";
-				nvidia,pull = <0>;
-				nvidia,tristate = <0>;
-			};
-		};
-	};
-
-	serial@70006000 {
-		status = "okay";
-		clock-frequency = <408000000>;
-	};
-
-	i2c@7000c000 {
-		status = "okay";
-		clock-frequency = <100000>;
-	};
-
-	i2c@7000c400 {
-		status = "okay";
-		clock-frequency = <100000>;
-	};
-
-	i2c@7000c500 {
-		status = "okay";
-		clock-frequency = <100000>;
-
-		/* ALS and Proximity sensor */
-		isl29028@44 {
-			compatible = "isil,isl29028";
-			reg = <0x44>;
-			interrupt-parent = <&gpio>;
-			interrupts = <88 0x04>; /*gpio PL0 */
-		};
-	};
-
-	i2c@7000c700 {
-		status = "okay";
-		clock-frequency = <100000>;
-	};
-
-	i2c@7000d000 {
-		status = "okay";
-		clock-frequency = <100000>;
-
-		wm8903: wm8903@1a {
-			compatible = "wlf,wm8903";
-			reg = <0x1a>;
-			interrupt-parent = <&gpio>;
-			interrupts = <179 0x04>; /* gpio PW3 */
-
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			micdet-cfg = <0>;
-			micdet-delay = <100>;
-			gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
-		};
-
-		tps62361 {
-			compatible = "ti,tps62361";
-			reg = <0x60>;
-
-			regulator-name = "tps62361-vout";
-			regulator-min-microvolt = <500000>;
-			regulator-max-microvolt = <1500000>;
-			regulator-boot-on;
-			regulator-always-on;
-			ti,vsel0-state-high;
-			ti,vsel1-state-high;
-		};
-	};
-
-	ahub {
-		i2s@70080400 {
-			status = "okay";
-		};
-	};
-
-	sdhci@78000000 {
-		status = "okay";
-		cd-gpios = <&gpio 69 0>; /* gpio PI5 */
-		wp-gpios = <&gpio 155 0>; /* gpio PT3 */
-		power-gpios = <&gpio 31 0>; /* gpio PD7 */
-		bus-width = <4>;
-	};
-
-	sdhci@78000600 {
-		status = "okay";
-		support-8bit;
-		bus-width = <8>;
-	};
-
-	sound {
-		compatible = "nvidia,tegra-audio-wm8903-cardhu",
-			     "nvidia,tegra-audio-wm8903";
-		nvidia,model = "NVIDIA Tegra Cardhu";
-
-		nvidia,audio-routing =
-			"Headphone Jack", "HPOUTR",
-			"Headphone Jack", "HPOUTL",
-			"Int Spk", "ROP",
-			"Int Spk", "RON",
-			"Int Spk", "LOP",
-			"Int Spk", "LON",
-			"Mic Jack", "MICBIAS",
-			"IN1L", "Mic Jack";
-
-		nvidia,i2s-controller = <&tegra_i2s1>;
-		nvidia,audio-codec = <&wm8903>;
-
-		nvidia,spkr-en-gpios = <&wm8903 2 0>;
-		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
-	};
-};
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts
deleted file mode 100644
index 7de7013..0000000
--- a/arch/arm/boot/dts/tegra-harmony.dts
+++ /dev/null
@@ -1,337 +0,0 @@
-/dts-v1/;
-
-/include/ "tegra20.dtsi"
-
-/ {
-	model = "NVIDIA Tegra2 Harmony evaluation board";
-	compatible = "nvidia,harmony", "nvidia,tegra20";
-
-	memory {
-		reg = <0x00000000 0x40000000>;
-	};
-
-	pinmux {
-		pinctrl-names = "default";
-		pinctrl-0 = <&state_default>;
-
-		state_default: pinmux {
-			ata {
-				nvidia,pins = "ata";
-				nvidia,function = "ide";
-			};
-			atb {
-				nvidia,pins = "atb", "gma", "gme";
-				nvidia,function = "sdio4";
-			};
-			atc {
-				nvidia,pins = "atc";
-				nvidia,function = "nand";
-			};
-			atd {
-				nvidia,pins = "atd", "ate", "gmb", "gmd", "gpu",
-					"spia", "spib", "spic";
-				nvidia,function = "gmi";
-			};
-			cdev1 {
-				nvidia,pins = "cdev1";
-				nvidia,function = "plla_out";
-			};
-			cdev2 {
-				nvidia,pins = "cdev2";
-				nvidia,function = "pllp_out4";
-			};
-			crtp {
-				nvidia,pins = "crtp";
-				nvidia,function = "crt";
-			};
-			csus {
-				nvidia,pins = "csus";
-				nvidia,function = "vi_sensor_clk";
-			};
-			dap1 {
-				nvidia,pins = "dap1";
-				nvidia,function = "dap1";
-			};
-			dap2 {
-				nvidia,pins = "dap2";
-				nvidia,function = "dap2";
-			};
-			dap3 {
-				nvidia,pins = "dap3";
-				nvidia,function = "dap3";
-			};
-			dap4 {
-				nvidia,pins = "dap4";
-				nvidia,function = "dap4";
-			};
-			ddc {
-				nvidia,pins = "ddc";
-				nvidia,function = "i2c2";
-			};
-			dta {
-				nvidia,pins = "dta", "dtd";
-				nvidia,function = "sdio2";
-			};
-			dtb {
-				nvidia,pins = "dtb", "dtc", "dte";
-				nvidia,function = "rsvd1";
-			};
-			dtf {
-				nvidia,pins = "dtf";
-				nvidia,function = "i2c3";
-			};
-			gmc {
-				nvidia,pins = "gmc";
-				nvidia,function = "uartd";
-			};
-			gpu7 {
-				nvidia,pins = "gpu7";
-				nvidia,function = "rtck";
-			};
-			gpv {
-				nvidia,pins = "gpv", "slxa", "slxk";
-				nvidia,function = "pcie";
-			};
-			hdint {
-				nvidia,pins = "hdint", "pta";
-				nvidia,function = "hdmi";
-			};
-			i2cp {
-				nvidia,pins = "i2cp";
-				nvidia,function = "i2cp";
-			};
-			irrx {
-				nvidia,pins = "irrx", "irtx";
-				nvidia,function = "uarta";
-			};
-			kbca {
-				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
-					"kbce", "kbcf";
-				nvidia,function = "kbc";
-			};
-			lcsn {
-				nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
-					"ld3", "ld4", "ld5", "ld6", "ld7",
-					"ld8", "ld9", "ld10", "ld11", "ld12",
-					"ld13", "ld14", "ld15", "ld16", "ld17",
-					"ldc", "ldi", "lhp0", "lhp1", "lhp2",
-					"lhs", "lm0", "lm1", "lpp", "lpw0",
-					"lpw1", "lpw2", "lsc0", "lsc1", "lsck",
-					"lsda", "lsdi", "lspi", "lvp0", "lvp1",
-					"lvs";
-				nvidia,function = "displaya";
-			};
-			owc {
-				nvidia,pins = "owc", "spdi", "spdo", "uac";
-				nvidia,function = "rsvd2";
-			};
-			pmc {
-				nvidia,pins = "pmc";
-				nvidia,function = "pwr_on";
-			};
-			rm {
-				nvidia,pins = "rm";
-				nvidia,function = "i2c1";
-			};
-			sdb {
-				nvidia,pins = "sdb", "sdc", "sdd";
-				nvidia,function = "pwm";
-			};
-			sdio1 {
-				nvidia,pins = "sdio1";
-				nvidia,function = "sdio1";
-			};
-			slxc {
-				nvidia,pins = "slxc", "slxd";
-				nvidia,function = "spdif";
-			};
-			spid {
-				nvidia,pins = "spid", "spie", "spif";
-				nvidia,function = "spi1";
-			};
-			spig {
-				nvidia,pins = "spig", "spih";
-				nvidia,function = "spi2_alt";
-			};
-			uaa {
-				nvidia,pins = "uaa", "uab", "uda";
-				nvidia,function = "ulpi";
-			};
-			uad {
-				nvidia,pins = "uad";
-				nvidia,function = "irda";
-			};
-			uca {
-				nvidia,pins = "uca", "ucb";
-				nvidia,function = "uartc";
-			};
-			conf_ata {
-				nvidia,pins = "ata", "atb", "atc", "atd", "ate",
-					"cdev1", "cdev2", "dap1", "dtb", "gma",
-					"gmb", "gmc", "gmd", "gme", "gpu7",
-					"gpv", "i2cp", "pta", "rm", "slxa",
-					"slxk", "spia", "spib", "uac";
-				nvidia,pull = <0>;
-				nvidia,tristate = <0>;
-			};
-			conf_ck32 {
-				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
-					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
-				nvidia,pull = <0>;
-			};
-			conf_csus {
-				nvidia,pins = "csus", "spid", "spif";
-				nvidia,pull = <1>;
-				nvidia,tristate = <1>;
-			};
-			conf_crtp {
-				nvidia,pins = "crtp", "dap2", "dap3", "dap4",
-					"dtc", "dte", "dtf", "gpu", "sdio1",
-					"slxc", "slxd", "spdi", "spdo", "spig",
-					"uda";
-				nvidia,pull = <0>;
-				nvidia,tristate = <1>;
-			};
-			conf_ddc {
-				nvidia,pins = "ddc", "dta", "dtd", "kbca",
-					"kbcb", "kbcc", "kbcd", "kbce", "kbcf",
-					"sdc";
-				nvidia,pull = <2>;
-				nvidia,tristate = <0>;
-			};
-			conf_hdint {
-				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
-					"lpw1", "lsc1", "lsck", "lsda", "lsdi",
-					"lvp0", "owc", "sdb";
-				nvidia,tristate = <1>;
-			};
-			conf_irrx {
-				nvidia,pins = "irrx", "irtx", "sdd", "spic",
-					"spie", "spih", "uaa", "uab", "uad",
-					"uca", "ucb";
-				nvidia,pull = <2>;
-				nvidia,tristate = <1>;
-			};
-			conf_lc {
-				nvidia,pins = "lc", "ls";
-				nvidia,pull = <2>;
-			};
-			conf_ld0 {
-				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
-					"ld5", "ld6", "ld7", "ld8", "ld9",
-					"ld10", "ld11", "ld12", "ld13", "ld14",
-					"ld15", "ld16", "ld17", "ldi", "lhp0",
-					"lhp1", "lhp2", "lhs", "lm0", "lpp",
-					"lpw0", "lpw2", "lsc0", "lspi", "lvp1",
-					"lvs", "pmc";
-				nvidia,tristate = <0>;
-			};
-			conf_ld17_0 {
-				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
-					"ld23_22";
-				nvidia,pull = <1>;
-			};
-		};
-	};
-
-	i2s@70002800 {
-		status = "okay";
-	};
-
-	serial@70006300 {
-		status = "okay";
-		clock-frequency = <216000000>;
-	};
-
-	i2c@7000c000 {
-		status = "okay";
-		clock-frequency = <400000>;
-
-		wm8903: wm8903@1a {
-			compatible = "wlf,wm8903";
-			reg = <0x1a>;
-			interrupt-parent = <&gpio>;
-			interrupts = <187 0x04>;
-
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			micdet-cfg = <0>;
-			micdet-delay = <100>;
-			gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
-		};
-	};
-
-	i2c@7000c400 {
-		status = "okay";
-		clock-frequency = <400000>;
-	};
-
-	i2c@7000c500 {
-		status = "okay";
-		clock-frequency = <400000>;
-	};
-
-	i2c@7000d000 {
-		status = "okay";
-		clock-frequency = <400000>;
-	};
-
-	pmc {
-		nvidia,invert-interrupt;
-	};
-
-	usb@c5000000 {
-		status = "okay";
-	};
-
-	usb@c5004000 {
-		status = "okay";
-		nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
-	};
-
-	usb@c5008000 {
-		status = "okay";
-	};
-
-	sdhci@c8000200 {
-		status = "okay";
-		cd-gpios = <&gpio 69 0>; /* gpio PI5 */
-		wp-gpios = <&gpio 57 0>; /* gpio PH1 */
-		power-gpios = <&gpio 155 0>; /* gpio PT3 */
-		bus-width = <4>;
-	};
-
-	sdhci@c8000600 {
-		status = "okay";
-		cd-gpios = <&gpio 58 0>; /* gpio PH2 */
-		wp-gpios = <&gpio 59 0>; /* gpio PH3 */
-		power-gpios = <&gpio 70 0>; /* gpio PI6 */
-		support-8bit;
-		bus-width = <8>;
-	};
-
-	sound {
-		compatible = "nvidia,tegra-audio-wm8903-harmony",
-			     "nvidia,tegra-audio-wm8903";
-		nvidia,model = "NVIDIA Tegra Harmony";
-
-		nvidia,audio-routing =
-			"Headphone Jack", "HPOUTR",
-			"Headphone Jack", "HPOUTL",
-			"Int Spk", "ROP",
-			"Int Spk", "RON",
-			"Int Spk", "LOP",
-			"Int Spk", "LON",
-			"Mic Jack", "MICBIAS",
-			"IN1L", "Mic Jack";
-
-		nvidia,i2s-controller = <&tegra_i2s1>;
-		nvidia,audio-codec = <&wm8903>;
-
-		nvidia,spkr-en-gpios = <&wm8903 2 0>;
-		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
-		nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
-		nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
-	};
-};
diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts
deleted file mode 100644
index bfeb117..0000000
--- a/arch/arm/boot/dts/tegra-paz00.dts
+++ /dev/null
@@ -1,348 +0,0 @@
-/dts-v1/;
-
-/include/ "tegra20.dtsi"
-
-/ {
-	model = "Toshiba AC100 / Dynabook AZ";
-	compatible = "compal,paz00", "nvidia,tegra20";
-
-	memory {
-		reg = <0x00000000 0x20000000>;
-	};
-
-	pinmux {
-		pinctrl-names = "default";
-		pinctrl-0 = <&state_default>;
-
-		state_default: pinmux {
-			ata {
-				nvidia,pins = "ata", "atc", "atd", "ate",
-					"dap2", "gmb", "gmc", "gmd", "spia",
-					"spib", "spic", "spid", "spie";
-				nvidia,function = "gmi";
-			};
-			atb {
-				nvidia,pins = "atb", "gma", "gme";
-				nvidia,function = "sdio4";
-			};
-			cdev1 {
-				nvidia,pins = "cdev1";
-				nvidia,function = "plla_out";
-			};
-			cdev2 {
-				nvidia,pins = "cdev2";
-				nvidia,function = "pllp_out4";
-			};
-			crtp {
-				nvidia,pins = "crtp";
-				nvidia,function = "crt";
-			};
-			csus {
-				nvidia,pins = "csus";
-				nvidia,function = "pllc_out1";
-			};
-			dap1 {
-				nvidia,pins = "dap1";
-				nvidia,function = "dap1";
-			};
-			dap3 {
-				nvidia,pins = "dap3";
-				nvidia,function = "dap3";
-			};
-			dap4 {
-				nvidia,pins = "dap4";
-				nvidia,function = "dap4";
-			};
-			ddc {
-				nvidia,pins = "ddc";
-				nvidia,function = "i2c2";
-			};
-			dta {
-				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
-				nvidia,function = "rsvd1";
-			};
-			dtf {
-				nvidia,pins = "dtf";
-				nvidia,function = "i2c3";
-			};
-			gpu {
-				nvidia,pins = "gpu", "sdb", "sdd";
-				nvidia,function = "pwm";
-			};
-			gpu7 {
-				nvidia,pins = "gpu7";
-				nvidia,function = "rtck";
-			};
-			gpv {
-				nvidia,pins = "gpv", "slxa", "slxk";
-				nvidia,function = "pcie";
-			};
-			hdint {
-				nvidia,pins = "hdint", "pta";
-				nvidia,function = "hdmi";
-			};
-			i2cp {
-				nvidia,pins = "i2cp";
-				nvidia,function = "i2cp";
-			};
-			irrx {
-				nvidia,pins = "irrx", "irtx";
-				nvidia,function = "uarta";
-			};
-			kbca {
-				nvidia,pins = "kbca", "kbcc", "kbce", "kbcf";
-				nvidia,function = "kbc";
-			};
-			kbcb {
-				nvidia,pins = "kbcb", "kbcd";
-				nvidia,function = "sdio2";
-			};
-			lcsn {
-				nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
-					"ld3", "ld4", "ld5", "ld6", "ld7",
-					"ld8", "ld9", "ld10", "ld11", "ld12",
-					"ld13", "ld14", "ld15", "ld16", "ld17",
-					"ldc", "ldi", "lhp0", "lhp1", "lhp2",
-					"lhs", "lm0", "lm1", "lpp", "lpw0",
-					"lpw1", "lpw2", "lsc0", "lsc1", "lsck",
-					"lsda", "lsdi", "lspi", "lvp0", "lvp1",
-					"lvs";
-				nvidia,function = "displaya";
-			};
-			owc {
-				nvidia,pins = "owc";
-				nvidia,function = "owr";
-			};
-			pmc {
-				nvidia,pins = "pmc";
-				nvidia,function = "pwr_on";
-			};
-			rm {
-				nvidia,pins = "rm";
-				nvidia,function = "i2c1";
-			};
-			sdc {
-				nvidia,pins = "sdc";
-				nvidia,function = "twc";
-			};
-			sdio1 {
-				nvidia,pins = "sdio1";
-				nvidia,function = "sdio1";
-			};
-			slxc {
-				nvidia,pins = "slxc", "slxd";
-				nvidia,function = "spi4";
-			};
-			spdi {
-				nvidia,pins = "spdi", "spdo";
-				nvidia,function = "rsvd2";
-			};
-			spif {
-				nvidia,pins = "spif", "uac";
-				nvidia,function = "rsvd4";
-			};
-			spig {
-				nvidia,pins = "spig", "spih";
-				nvidia,function = "spi2_alt";
-			};
-			uaa {
-				nvidia,pins = "uaa", "uab", "uda";
-				nvidia,function = "ulpi";
-			};
-			uad {
-				nvidia,pins = "uad";
-				nvidia,function = "spdif";
-			};
-			uca {
-				nvidia,pins = "uca", "ucb";
-				nvidia,function = "uartc";
-			};
-			conf_ata {
-				nvidia,pins = "ata", "atb", "atc", "atd", "ate",
-					"cdev1", "cdev2", "dap1", "dap2", "dtf",
-					"gma", "gmb", "gmc", "gmd", "gme",
-					"gpu", "gpu7", "gpv", "i2cp", "pta",
-					"rm", "sdio1", "slxk", "spdo", "uac",
-					"uda";
-				nvidia,pull = <0>;
-				nvidia,tristate = <0>;
-			};
-			conf_ck32 {
-				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
-					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
-				nvidia,pull = <0>;
-			};
-			conf_crtp {
-				nvidia,pins = "crtp", "dap3", "dap4", "dtb",
-					"dtc", "dte", "slxa", "slxc", "slxd",
-					"spdi";
-				nvidia,pull = <0>;
-				nvidia,tristate = <1>;
-			};
-			conf_csus {
-				nvidia,pins = "csus", "spia", "spib", "spid",
-					"spif";
-				nvidia,pull = <1>;
-				nvidia,tristate = <1>;
-			};
-			conf_ddc {
-				nvidia,pins = "ddc", "irrx", "irtx", "kbca",
-					"kbcb", "kbcc", "kbcd", "kbce", "kbcf",
-					"spic", "spig", "uaa", "uab";
-				nvidia,pull = <2>;
-				nvidia,tristate = <0>;
-			};
-			conf_dta {
-				nvidia,pins = "dta", "dtd", "owc", "sdc", "sdd",
-					"spie", "spih", "uad", "uca", "ucb";
-				nvidia,pull = <2>;
-				nvidia,tristate = <1>;
-			};
-			conf_hdint {
-				nvidia,pins = "hdint", "ld0", "ld1", "ld2",
-					"ld3", "ld4", "ld5", "ld6", "ld7",
-					"ld8", "ld9", "ld10", "ld11", "ld12",
-					"ld13", "ld14", "ld15", "ld16", "ld17",
-					"ldc", "ldi", "lhs", "lsc0", "lspi",
-					"lvs", "pmc";
-				nvidia,tristate = <0>;
-			};
-			conf_lc {
-				nvidia,pins = "lc", "ls";
-				nvidia,pull = <2>;
-			};
-			conf_lcsn {
-				nvidia,pins = "lcsn", "lhp0", "lhp1", "lhp2",
-					"lm0", "lm1", "lpp", "lpw0", "lpw1",
-					"lpw2", "lsc1", "lsck", "lsda", "lsdi",
-					"lvp0", "lvp1", "sdb";
-				nvidia,tristate = <1>;
-			};
-			conf_ld17_0 {
-				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
-					"ld23_22";
-				nvidia,pull = <1>;
-			};
-		};
-	};
-
-	i2s@70002800 {
-		status = "okay";
-	};
-
-	serial@70006000 {
-		status = "okay";
-		clock-frequency = <216000000>;
-	};
-
-	serial@70006200 {
-		status = "okay";
-		clock-frequency = <216000000>;
-	};
-
-	i2c@7000c000 {
-		status = "okay";
-		clock-frequency = <400000>;
-
-		alc5632: alc5632@1e {
-			compatible = "realtek,alc5632";
-			reg = <0x1e>;
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-	};
-
-	i2c@7000c400 {
-		status = "okay";
-		clock-frequency = <400000>;
-	};
-
-	nvec {
-		compatible = "nvidia,nvec";
-		reg = <0x7000c500 0x100>;
-		interrupts = <0 92 0x04>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		clock-frequency = <80000>;
-		request-gpios = <&gpio 170 0>; /* gpio PV2 */
-		slave-addr = <138>;
-	};
-
-	i2c@7000d000 {
-		status = "okay";
-		clock-frequency = <400000>;
-
-		adt7461@4c {
-			compatible = "adi,adt7461";
-			reg = <0x4c>;
-		};
-	};
-
-	usb@c5000000 {
-		status = "okay";
-	};
-
-	usb@c5004000 {
-		status = "okay";
-		nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
-	};
-
-	usb@c5008000 {
-		status = "okay";
-	};
-
-	sdhci@c8000000 {
-		status = "okay";
-		cd-gpios = <&gpio 173 0>; /* gpio PV5 */
-		wp-gpios = <&gpio 57 0>;  /* gpio PH1 */
-		power-gpios = <&gpio 169 0>; /* gpio PV1 */
-		bus-width = <4>;
-	};
-
-	sdhci@c8000600 {
-		status = "okay";
-		support-8bit;
-		bus-width = <8>;
-	};
-
-	gpio-keys {
-		compatible = "gpio-keys";
-
-		power {
-			label = "Power";
-			gpios = <&gpio 79 1>; /* gpio PJ7, active low */
-			linux,code = <116>; /* KEY_POWER */
-			gpio-key,wakeup;
-		};
-	};
-
-	gpio-leds {
-		compatible = "gpio-leds";
-
-		wifi {
-			label = "wifi-led";
-			gpios = <&gpio 24 0>; /* gpio PD0 */
-			linux,default-trigger = "rfkill0";
-		};
-	};
-
-	sound {
-		compatible = "nvidia,tegra-audio-alc5632-paz00",
-			"nvidia,tegra-audio-alc5632";
-
-		nvidia,model = "Compal PAZ00";
-
-		nvidia,audio-routing =
-			"Int Spk", "SPKOUT",
-			"Int Spk", "SPKOUTN",
-			"Headset Mic", "MICBIAS1",
-			"MIC1", "Headset Mic",
-			"Headset Stereophone", "HPR",
-			"Headset Stereophone", "HPL",
-			"DMICDAT", "Digital Mic";
-
-		nvidia,audio-codec = <&alc5632>;
-		nvidia,i2s-controller = <&tegra_i2s1>;
-		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
-	};
-};
diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts
deleted file mode 100644
index 89cb7f2..0000000
--- a/arch/arm/boot/dts/tegra-seaboard.dts
+++ /dev/null
@@ -1,445 +0,0 @@
-/dts-v1/;
-
-/include/ "tegra20.dtsi"
-
-/ {
-	model = "NVIDIA Seaboard";
-	compatible = "nvidia,seaboard", "nvidia,tegra20";
-
-	memory {
-		reg = <0x00000000 0x40000000>;
-	};
-
-	pinmux {
-		pinctrl-names = "default";
-		pinctrl-0 = <&state_default>;
-
-		state_default: pinmux {
-			ata {
-				nvidia,pins = "ata";
-				nvidia,function = "ide";
-			};
-			atb {
-				nvidia,pins = "atb", "gma", "gme";
-				nvidia,function = "sdio4";
-			};
-			atc {
-				nvidia,pins = "atc";
-				nvidia,function = "nand";
-			};
-			atd {
-				nvidia,pins = "atd", "ate", "gmb", "spia",
-					"spib", "spic";
-				nvidia,function = "gmi";
-			};
-			cdev1 {
-				nvidia,pins = "cdev1";
-				nvidia,function = "plla_out";
-			};
-			cdev2 {
-				nvidia,pins = "cdev2";
-				nvidia,function = "pllp_out4";
-			};
-			crtp {
-				nvidia,pins = "crtp", "lm1";
-				nvidia,function = "crt";
-			};
-			csus {
-				nvidia,pins = "csus";
-				nvidia,function = "vi_sensor_clk";
-			};
-			dap1 {
-				nvidia,pins = "dap1";
-				nvidia,function = "dap1";
-			};
-			dap2 {
-				nvidia,pins = "dap2";
-				nvidia,function = "dap2";
-			};
-			dap3 {
-				nvidia,pins = "dap3";
-				nvidia,function = "dap3";
-			};
-			dap4 {
-				nvidia,pins = "dap4";
-				nvidia,function = "dap4";
-			};
-			ddc {
-				nvidia,pins = "ddc", "owc", "spdi", "spdo",
-					"uac";
-				nvidia,function = "rsvd2";
-			};
-			dta {
-				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
-				nvidia,function = "vi";
-			};
-			dtf {
-				nvidia,pins = "dtf";
-				nvidia,function = "i2c3";
-			};
-			gmc {
-				nvidia,pins = "gmc";
-				nvidia,function = "uartd";
-			};
-			gmd {
-				nvidia,pins = "gmd";
-				nvidia,function = "sflash";
-			};
-			gpu {
-				nvidia,pins = "gpu";
-				nvidia,function = "pwm";
-			};
-			gpu7 {
-				nvidia,pins = "gpu7";
-				nvidia,function = "rtck";
-			};
-			gpv {
-				nvidia,pins = "gpv", "slxa", "slxk";
-				nvidia,function = "pcie";
-			};
-			hdint {
-				nvidia,pins = "hdint", "lpw0", "lpw2", "lsc1",
-					"lsck", "lsda";
-				nvidia,function = "hdmi";
-			};
-			i2cp {
-				nvidia,pins = "i2cp";
-				nvidia,function = "i2cp";
-			};
-			irrx {
-				nvidia,pins = "irrx", "irtx";
-				nvidia,function = "uartb";
-			};
-			kbca {
-				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
-					"kbce", "kbcf";
-				nvidia,function = "kbc";
-			};
-			lcsn {
-				nvidia,pins = "lcsn", "ldc", "lm0", "lpw1",
-					"lsdi", "lvp0";
-				nvidia,function = "rsvd4";
-			};
-			ld0 {
-				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
-					"ld5", "ld6", "ld7", "ld8", "ld9",
-					"ld10", "ld11", "ld12", "ld13", "ld14",
-					"ld15", "ld16", "ld17", "ldi", "lhp0",
-					"lhp1", "lhp2", "lhs", "lpp", "lsc0",
-					"lspi", "lvp1", "lvs";
-				nvidia,function = "displaya";
-			};
-			pmc {
-				nvidia,pins = "pmc";
-				nvidia,function = "pwr_on";
-			};
-			pta {
-				nvidia,pins = "pta";
-				nvidia,function = "i2c2";
-			};
-			rm {
-				nvidia,pins = "rm";
-				nvidia,function = "i2c1";
-			};
-			sdb {
-				nvidia,pins = "sdb", "sdc", "sdd";
-				nvidia,function = "sdio3";
-			};
-			sdio1 {
-				nvidia,pins = "sdio1";
-				nvidia,function = "sdio1";
-			};
-			slxc {
-				nvidia,pins = "slxc", "slxd";
-				nvidia,function = "spdif";
-			};
-			spid {
-				nvidia,pins = "spid", "spie", "spif";
-				nvidia,function = "spi1";
-			};
-			spig {
-				nvidia,pins = "spig", "spih";
-				nvidia,function = "spi2_alt";
-			};
-			uaa {
-				nvidia,pins = "uaa", "uab", "uda";
-				nvidia,function = "ulpi";
-			};
-			uad {
-				nvidia,pins = "uad";
-				nvidia,function = "irda";
-			};
-			uca {
-				nvidia,pins = "uca", "ucb";
-				nvidia,function = "uartc";
-			};
-			conf_ata {
-				nvidia,pins = "ata", "atb", "atc", "atd",
-					"cdev1", "cdev2", "dap1", "dap2",
-					"dap4", "dtf", "gma", "gmc", "gmd",
-					"gme", "gpu", "gpu7", "i2cp", "irrx",
-					"irtx", "pta", "rm", "sdc", "sdd",
-					"slxd", "slxk", "spdi", "spdo", "uac",
-					"uad", "uca", "ucb", "uda";
-				nvidia,pull = <0>;
-				nvidia,tristate = <0>;
-			};
-			conf_ate {
-				nvidia,pins = "ate", "csus", "dap3", "ddc",
-					"gpv", "owc", "slxc", "spib", "spid",
-					"spie";
-				nvidia,pull = <0>;
-				nvidia,tristate = <1>;
-			};
-			conf_ck32 {
-				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
-					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
-				nvidia,pull = <0>;
-			};
-			conf_crtp {
-				nvidia,pins = "crtp", "gmb", "slxa", "spia",
-					"spig", "spih";
-				nvidia,pull = <2>;
-				nvidia,tristate = <1>;
-			};
-			conf_dta {
-				nvidia,pins = "dta", "dtb", "dtc", "dtd";
-				nvidia,pull = <1>;
-				nvidia,tristate = <0>;
-			};
-			conf_dte {
-				nvidia,pins = "dte", "spif";
-				nvidia,pull = <1>;
-				nvidia,tristate = <1>;
-			};
-			conf_hdint {
-				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
-					"lpw1", "lsc1", "lsck", "lsda", "lsdi",
-					"lvp0";
-				nvidia,tristate = <1>;
-			};
-			conf_kbca {
-				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
-					"kbce", "kbcf", "sdio1", "spic", "uaa",
-					"uab";
-				nvidia,pull = <2>;
-				nvidia,tristate = <0>;
-			};
-			conf_lc {
-				nvidia,pins = "lc", "ls";
-				nvidia,pull = <2>;
-			};
-			conf_ld0 {
-				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
-					"ld5", "ld6", "ld7", "ld8", "ld9",
-					"ld10", "ld11", "ld12", "ld13", "ld14",
-					"ld15", "ld16", "ld17", "ldi", "lhp0",
-					"lhp1", "lhp2", "lhs", "lm0", "lpp",
-					"lpw0", "lpw2", "lsc0", "lspi", "lvp1",
-					"lvs", "pmc", "sdb";
-				nvidia,tristate = <0>;
-			};
-			conf_ld17_0 {
-				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
-					"ld23_22";
-				nvidia,pull = <1>;
-			};
-			drive_sdio1 {
-				nvidia,pins = "drive_sdio1";
-				nvidia,high-speed-mode = <0>;
-				nvidia,schmitt = <0>;
-				nvidia,low-power-mode = <3>;
-				nvidia,pull-down-strength = <31>;
-				nvidia,pull-up-strength = <31>;
-				nvidia,slew-rate-rising = <3>;
-				nvidia,slew-rate-falling = <3>;
-			};
-		};
-	};
-
-	i2s@70002800 {
-		status = "okay";
-	};
-
-	serial@70006300 {
-		status = "okay";
-		clock-frequency = <216000000>;
-	};
-
-	i2c@7000c000 {
-		status = "okay";
-		clock-frequency = <400000>;
-
-		wm8903: wm8903@1a {
-			compatible = "wlf,wm8903";
-			reg = <0x1a>;
-			interrupt-parent = <&gpio>;
-			interrupts = <187 0x04>;
-
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			micdet-cfg = <0>;
-			micdet-delay = <100>;
-			gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
-		};
-
-		/* ALS and proximity sensor */
-		isl29018@44 {
-			compatible = "isil,isl29018";
-			reg = <0x44>;
-			interrupt-parent = <&gpio>;
-			interrupts = <202 0x04>; /* GPIO PZ2 */
-		};
-
-		gyrometer@68 {
-			compatible = "invn,mpu3050";
-			reg = <0x68>;
-			interrupt-parent = <&gpio>;
-			interrupts = <204 0x04>; /* gpio PZ4 */
-		};
-	};
-
-	i2c@7000c400 {
-		status = "okay";
-		clock-frequency = <100000>;
-
-		smart-battery@b {
-			compatible = "ti,bq20z75", "smart-battery-1.1";
-			reg = <0xb>;
-			ti,i2c-retry-count = <2>;
-			ti,poll-retry-count = <10>;
-		};
-	};
-
-	i2c@7000c500 {
-		status = "okay";
-		clock-frequency = <400000>;
-	};
-
-	i2c@7000d000 {
-		status = "okay";
-		clock-frequency = <400000>;
-
-		temperature-sensor@4c {
-			compatible = "nct1008";
-			reg = <0x4c>;
-		};
-
-		magnetometer@c {
-			compatible = "ak8975";
-			reg = <0xc>;
-			interrupt-parent = <&gpio>;
-			interrupts = <109 0x04>; /* gpio PN5 */
-		};
-	};
-
-	emc {
-		emc-table@190000 {
-			reg = <190000>;
-			compatible = "nvidia,tegra20-emc-table";
-			clock-frequency = <190000>;
-			nvidia,emc-registers = <0x0000000c 0x00000026
-				0x00000009 0x00000003 0x00000004 0x00000004
-				0x00000002 0x0000000c 0x00000003 0x00000003
-				0x00000002 0x00000001 0x00000004 0x00000005
-				0x00000004 0x00000009 0x0000000d 0x0000059f
-				0x00000000 0x00000003 0x00000003 0x00000003
-				0x00000003 0x00000001 0x0000000b 0x000000c8
-				0x00000003 0x00000007 0x00000004 0x0000000f
-				0x00000002 0x00000000 0x00000000 0x00000002
-				0x00000000 0x00000000 0x00000083 0xa06204ae
-				0x007dc010 0x00000000 0x00000000 0x00000000
-				0x00000000 0x00000000 0x00000000 0x00000000>;
-		};
-
-		emc-table@380000 {
-			reg = <380000>;
-			compatible = "nvidia,tegra20-emc-table";
-			clock-frequency = <380000>;
-			nvidia,emc-registers = <0x00000017 0x0000004b
-				0x00000012 0x00000006 0x00000004 0x00000005
-				0x00000003 0x0000000c 0x00000006 0x00000006
-				0x00000003 0x00000001 0x00000004 0x00000005
-				0x00000004 0x00000009 0x0000000d 0x00000b5f
-				0x00000000 0x00000003 0x00000003 0x00000006
-				0x00000006 0x00000001 0x00000011 0x000000c8
-				0x00000003 0x0000000e 0x00000007 0x0000000f
-				0x00000002 0x00000000 0x00000000 0x00000002
-				0x00000000 0x00000000 0x00000083 0xe044048b
-				0x007d8010 0x00000000 0x00000000 0x00000000
-				0x00000000 0x00000000 0x00000000 0x00000000>;
-		};
-	};
-
-	usb@c5000000 {
-		status = "okay";
-		nvidia,vbus-gpio = <&gpio 24 0>; /* PD0 */
-		dr_mode = "otg";
-	};
-
-	usb@c5004000 {
-		status = "okay";
-		nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
-	};
-
-	usb@c5008000 {
-		status = "okay";
-	};
-
-	sdhci@c8000400 {
-		status = "okay";
-		cd-gpios = <&gpio 69 0>; /* gpio PI5 */
-		wp-gpios = <&gpio 57 0>; /* gpio PH1 */
-		power-gpios = <&gpio 70 0>; /* gpio PI6 */
-		bus-width = <4>;
-	};
-
-	sdhci@c8000600 {
-		status = "okay";
-		support-8bit;
-		bus-width = <8>;
-	};
-
-	gpio-keys {
-		compatible = "gpio-keys";
-
-		power {
-			label = "Power";
-			gpios = <&gpio 170 1>; /* gpio PV2, active low */
-			linux,code = <116>; /* KEY_POWER */
-			gpio-key,wakeup;
-		};
-
-		lid {
-			label = "Lid";
-			gpios = <&gpio 23 0>; /* gpio PC7 */
-			linux,input-type = <5>; /* EV_SW */
-			linux,code = <0>; /* SW_LID */
-			debounce-interval = <1>;
-			gpio-key,wakeup;
-		};
-	};
-
-	sound {
-		compatible = "nvidia,tegra-audio-wm8903-seaboard",
-			     "nvidia,tegra-audio-wm8903";
-		nvidia,model = "NVIDIA Tegra Seaboard";
-
-		nvidia,audio-routing =
-			"Headphone Jack", "HPOUTR",
-			"Headphone Jack", "HPOUTL",
-			"Int Spk", "ROP",
-			"Int Spk", "RON",
-			"Int Spk", "LOP",
-			"Int Spk", "LON",
-			"Mic Jack", "MICBIAS",
-			"IN1R", "Mic Jack";
-
-		nvidia,i2s-controller = <&tegra_i2s1>;
-		nvidia,audio-codec = <&wm8903>;
-
-		nvidia,spkr-en-gpios = <&wm8903 2 0>;
-		nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */
-	};
-};
diff --git a/arch/arm/boot/dts/tegra-trimslice.dts b/arch/arm/boot/dts/tegra-trimslice.dts
deleted file mode 100644
index 9de5636..0000000
--- a/arch/arm/boot/dts/tegra-trimslice.dts
+++ /dev/null
@@ -1,306 +0,0 @@
-/dts-v1/;
-
-/include/ "tegra20.dtsi"
-
-/ {
-	model = "Compulab TrimSlice board";
-	compatible = "compulab,trimslice", "nvidia,tegra20";
-
-	memory {
-		reg = <0x00000000 0x40000000>;
-	};
-
-	pinmux {
-		pinctrl-names = "default";
-		pinctrl-0 = <&state_default>;
-
-		state_default: pinmux {
-			ata {
-				nvidia,pins = "ata";
-				nvidia,function = "ide";
-			};
-			atb {
-				nvidia,pins = "atb", "gma";
-				nvidia,function = "sdio4";
-			};
-			atc {
-				nvidia,pins = "atc", "gmb";
-				nvidia,function = "nand";
-			};
-			atd {
-				nvidia,pins = "atd", "ate", "gme", "pta";
-				nvidia,function = "gmi";
-			};
-			cdev1 {
-				nvidia,pins = "cdev1";
-				nvidia,function = "plla_out";
-			};
-			cdev2 {
-				nvidia,pins = "cdev2";
-				nvidia,function = "pllp_out4";
-			};
-			crtp {
-				nvidia,pins = "crtp";
-				nvidia,function = "crt";
-			};
-			csus {
-				nvidia,pins = "csus";
-				nvidia,function = "vi_sensor_clk";
-			};
-			dap1 {
-				nvidia,pins = "dap1";
-				nvidia,function = "dap1";
-			};
-			dap2 {
-				nvidia,pins = "dap2";
-				nvidia,function = "dap2";
-			};
-			dap3 {
-				nvidia,pins = "dap3";
-				nvidia,function = "dap3";
-			};
-			dap4 {
-				nvidia,pins = "dap4";
-				nvidia,function = "dap4";
-			};
-			ddc {
-				nvidia,pins = "ddc";
-				nvidia,function = "i2c2";
-			};
-			dta {
-				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
-				nvidia,function = "vi";
-			};
-			dtf {
-				nvidia,pins = "dtf";
-				nvidia,function = "i2c3";
-			};
-			gmc {
-				nvidia,pins = "gmc", "gmd";
-				nvidia,function = "sflash";
-			};
-			gpu {
-				nvidia,pins = "gpu";
-				nvidia,function = "uarta";
-			};
-			gpu7 {
-				nvidia,pins = "gpu7";
-				nvidia,function = "rtck";
-			};
-			gpv {
-				nvidia,pins = "gpv", "slxa", "slxk";
-				nvidia,function = "pcie";
-			};
-			hdint {
-				nvidia,pins = "hdint";
-				nvidia,function = "hdmi";
-			};
-			i2cp {
-				nvidia,pins = "i2cp";
-				nvidia,function = "i2cp";
-			};
-			irrx {
-				nvidia,pins = "irrx", "irtx";
-				nvidia,function = "uartb";
-			};
-			kbca {
-				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
-					"kbce", "kbcf";
-				nvidia,function = "kbc";
-			};
-			lcsn {
-				nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
-					"ld3", "ld4", "ld5", "ld6", "ld7",
-					"ld8", "ld9", "ld10", "ld11", "ld12",
-					"ld13", "ld14", "ld15", "ld16", "ld17",
-					"ldc", "ldi", "lhp0", "lhp1", "lhp2",
-					"lhs", "lm0", "lm1", "lpp", "lpw0",
-					"lpw1", "lpw2", "lsc0", "lsc1", "lsck",
-					"lsda", "lsdi", "lspi", "lvp0", "lvp1",
-					"lvs";
-				nvidia,function = "displaya";
-			};
-			owc {
-				nvidia,pins = "owc", "uac";
-				nvidia,function = "rsvd2";
-			};
-			pmc {
-				nvidia,pins = "pmc";
-				nvidia,function = "pwr_on";
-			};
-			rm {
-				nvidia,pins = "rm";
-				nvidia,function = "i2c1";
-			};
-			sdb {
-				nvidia,pins = "sdb", "sdc", "sdd";
-				nvidia,function = "pwm";
-			};
-			sdio1 {
-				nvidia,pins = "sdio1";
-				nvidia,function = "sdio1";
-			};
-			slxc {
-				nvidia,pins = "slxc", "slxd";
-				nvidia,function = "sdio3";
-			};
-			spdi {
-				nvidia,pins = "spdi", "spdo";
-				nvidia,function = "spdif";
-			};
-			spia {
-				nvidia,pins = "spia", "spib", "spic";
-				nvidia,function = "spi2";
-			};
-			spid {
-				nvidia,pins = "spid", "spie", "spif";
-				nvidia,function = "spi1";
-			};
-			spig {
-				nvidia,pins = "spig", "spih";
-				nvidia,function = "spi2_alt";
-			};
-			uaa {
-				nvidia,pins = "uaa", "uab", "uda";
-				nvidia,function = "ulpi";
-			};
-			uad {
-				nvidia,pins = "uad";
-				nvidia,function = "irda";
-			};
-			uca {
-				nvidia,pins = "uca", "ucb";
-				nvidia,function = "uartc";
-			};
-			conf_ata {
-				nvidia,pins = "ata", "atc", "atd", "ate",
-					"crtp", "dap2", "dap3", "dap4", "dta",
-					"dtb", "dtc", "dtd", "dte", "gmb",
-					"gme", "i2cp", "pta", "slxc", "slxd",
-					"spdi", "spdo", "uda";
-				nvidia,pull = <0>;
-				nvidia,tristate = <1>;
-			};
-			conf_atb {
-				nvidia,pins = "atb", "cdev1", "cdev2", "dap1",
-					"gma", "gmc", "gmd", "gpu", "gpu7",
-					"gpv", "sdio1", "slxa", "slxk", "uac";
-				nvidia,pull = <0>;
-				nvidia,tristate = <0>;
-			};
-			conf_ck32 {
-				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
-					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
-				nvidia,pull = <0>;
-			};
-			conf_csus {
-				nvidia,pins = "csus", "spia", "spib",
-					"spid", "spif";
-				nvidia,pull = <1>;
-				nvidia,tristate = <1>;
-			};
-			conf_ddc {
-				nvidia,pins = "ddc", "dtf", "rm", "sdc", "sdd";
-				nvidia,pull = <2>;
-				nvidia,tristate = <0>;
-			};
-			conf_hdint {
-				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
-					"lpw1", "lsc1", "lsck", "lsda", "lsdi",
-					"lvp0", "pmc";
-				nvidia,tristate = <1>;
-			};
-			conf_irrx {
-				nvidia,pins = "irrx", "irtx", "kbca", "kbcb",
-					"kbcc", "kbcd", "kbce", "kbcf", "owc",
-					"spic", "spie", "spig", "spih", "uaa",
-					"uab", "uad", "uca", "ucb";
-				nvidia,pull = <2>;
-				nvidia,tristate = <1>;
-			};
-			conf_lc {
-				nvidia,pins = "lc", "ls";
-				nvidia,pull = <2>;
-			};
-			conf_ld0 {
-				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
-					"ld5", "ld6", "ld7", "ld8", "ld9",
-					"ld10", "ld11", "ld12", "ld13", "ld14",
-					"ld15", "ld16", "ld17", "ldi", "lhp0",
-					"lhp1", "lhp2", "lhs", "lm0", "lpp",
-					"lpw0", "lpw2", "lsc0", "lspi", "lvp1",
-					"lvs", "sdb";
-				nvidia,tristate = <0>;
-			};
-			conf_ld17_0 {
-				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
-					"ld23_22";
-				nvidia,pull = <1>;
-			};
-		};
-	};
-
-	i2s@70002800 {
-		status = "okay";
-	};
-
-	serial@70006000 {
-		status = "okay";
-		clock-frequency = <216000000>;
-	};
-
-	i2c@7000c000 {
-		status = "okay";
-		clock-frequency = <400000>;
-	};
-
-	i2c@7000c400 {
-		status = "okay";
-		clock-frequency = <400000>;
-	};
-
-	i2c@7000c500 {
-		status = "okay";
-		clock-frequency = <400000>;
-
-		codec: codec@1a {
-			compatible = "ti,tlv320aic23";
-			reg = <0x1a>;
-		};
-
-		rtc@56 {
-			compatible = "emmicro,em3027";
-			reg = <0x56>;
-		};
-	};
-
-	usb@c5000000 {
-		status = "okay";
-	};
-
-	usb@c5004000 {
-		nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
-	};
-
-	usb@c5008000 {
-		status = "okay";
-	};
-
-	sdhci@c8000000 {
-		status = "okay";
-		bus-width = <4>;
-	};
-
-	sdhci@c8000600 {
-		status = "okay";
-		cd-gpios = <&gpio 121 0>; /* gpio PP1 */
-		wp-gpios = <&gpio 122 0>; /* gpio PP2 */
-		bus-width = <4>;
-	};
-
-	sound {
-		compatible = "nvidia,tegra-audio-trimslice";
-		nvidia,i2s-controller = <&tegra_i2s1>;
-		nvidia,audio-codec = <&codec>;
-	};
-};
diff --git a/arch/arm/boot/dts/tegra-ventana.dts b/arch/arm/boot/dts/tegra-ventana.dts
deleted file mode 100644
index 445343b..0000000
--- a/arch/arm/boot/dts/tegra-ventana.dts
+++ /dev/null
@@ -1,344 +0,0 @@
-/dts-v1/;
-
-/include/ "tegra20.dtsi"
-
-/ {
-	model = "NVIDIA Tegra2 Ventana evaluation board";
-	compatible = "nvidia,ventana", "nvidia,tegra20";
-
-	memory {
-		reg = <0x00000000 0x40000000>;
-	};
-
-	pinmux {
-		pinctrl-names = "default";
-		pinctrl-0 = <&state_default>;
-
-		state_default: pinmux {
-			ata {
-				nvidia,pins = "ata";
-				nvidia,function = "ide";
-			};
-			atb {
-				nvidia,pins = "atb", "gma", "gme";
-				nvidia,function = "sdio4";
-			};
-			atc {
-				nvidia,pins = "atc";
-				nvidia,function = "nand";
-			};
-			atd {
-				nvidia,pins = "atd", "ate", "gmb", "spia",
-					"spib", "spic";
-				nvidia,function = "gmi";
-			};
-			cdev1 {
-				nvidia,pins = "cdev1";
-				nvidia,function = "plla_out";
-			};
-			cdev2 {
-				nvidia,pins = "cdev2";
-				nvidia,function = "pllp_out4";
-			};
-			crtp {
-				nvidia,pins = "crtp", "lm1";
-				nvidia,function = "crt";
-			};
-			csus {
-				nvidia,pins = "csus";
-				nvidia,function = "vi_sensor_clk";
-			};
-			dap1 {
-				nvidia,pins = "dap1";
-				nvidia,function = "dap1";
-			};
-			dap2 {
-				nvidia,pins = "dap2";
-				nvidia,function = "dap2";
-			};
-			dap3 {
-				nvidia,pins = "dap3";
-				nvidia,function = "dap3";
-			};
-			dap4 {
-				nvidia,pins = "dap4";
-				nvidia,function = "dap4";
-			};
-			ddc {
-				nvidia,pins = "ddc", "owc", "spdi", "spdo",
-					"uac";
-				nvidia,function = "rsvd2";
-			};
-			dta {
-				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
-				nvidia,function = "vi";
-			};
-			dtf {
-				nvidia,pins = "dtf";
-				nvidia,function = "i2c3";
-			};
-			gmc {
-				nvidia,pins = "gmc";
-				nvidia,function = "uartd";
-			};
-			gmd {
-				nvidia,pins = "gmd";
-				nvidia,function = "sflash";
-			};
-			gpu {
-				nvidia,pins = "gpu";
-				nvidia,function = "pwm";
-			};
-			gpu7 {
-				nvidia,pins = "gpu7";
-				nvidia,function = "rtck";
-			};
-			gpv {
-				nvidia,pins = "gpv", "slxa", "slxk";
-				nvidia,function = "pcie";
-			};
-			hdint {
-				nvidia,pins = "hdint", "pta";
-				nvidia,function = "hdmi";
-			};
-			i2cp {
-				nvidia,pins = "i2cp";
-				nvidia,function = "i2cp";
-			};
-			irrx {
-				nvidia,pins = "irrx", "irtx";
-				nvidia,function = "uartb";
-			};
-			kbca {
-				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
-					"kbce", "kbcf";
-				nvidia,function = "kbc";
-			};
-			lcsn {
-				nvidia,pins = "lcsn", "ldc", "lm0", "lpw1",
-					"lsdi", "lvp0";
-				nvidia,function = "rsvd4";
-			};
-			ld0 {
-				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
-					"ld5", "ld6", "ld7", "ld8", "ld9",
-					"ld10", "ld11", "ld12", "ld13", "ld14",
-					"ld15", "ld16", "ld17", "ldi", "lhp0",
-					"lhp1", "lhp2", "lhs", "lpp", "lpw0",
-					"lpw2", "lsc0", "lsc1", "lsck", "lsda",
-					"lspi", "lvp1", "lvs";
-				nvidia,function = "displaya";
-			};
-			pmc {
-				nvidia,pins = "pmc";
-				nvidia,function = "pwr_on";
-			};
-			rm {
-				nvidia,pins = "rm";
-				nvidia,function = "i2c1";
-			};
-			sdb {
-				nvidia,pins = "sdb", "sdc", "sdd", "slxc";
-				nvidia,function = "sdio3";
-			};
-			sdio1 {
-				nvidia,pins = "sdio1";
-				nvidia,function = "sdio1";
-			};
-			slxd {
-				nvidia,pins = "slxd";
-				nvidia,function = "spdif";
-			};
-			spid {
-				nvidia,pins = "spid", "spie", "spif";
-				nvidia,function = "spi1";
-			};
-			spig {
-				nvidia,pins = "spig", "spih";
-				nvidia,function = "spi2_alt";
-			};
-			uaa {
-				nvidia,pins = "uaa", "uab", "uda";
-				nvidia,function = "ulpi";
-			};
-			uad {
-				nvidia,pins = "uad";
-				nvidia,function = "irda";
-			};
-			uca {
-				nvidia,pins = "uca", "ucb";
-				nvidia,function = "uartc";
-			};
-			conf_ata {
-				nvidia,pins = "ata", "atb", "atc", "atd",
-					"cdev1", "cdev2", "dap1", "dap2",
-					"dap4", "ddc", "dtf", "gma", "gmc",
-					"gme", "gpu", "gpu7", "i2cp", "irrx",
-					"irtx", "pta", "rm", "sdc", "sdd",
-					"slxc", "slxd", "slxk", "spdi", "spdo",
-					"uac", "uad", "uca", "ucb", "uda";
-				nvidia,pull = <0>;
-				nvidia,tristate = <0>;
-			};
-			conf_ate {
-				nvidia,pins = "ate", "csus", "dap3", "gmd",
-					"gpv", "owc", "spia", "spib", "spic",
-					"spid", "spie", "spig";
-				nvidia,pull = <0>;
-				nvidia,tristate = <1>;
-			};
-			conf_ck32 {
-				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
-					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
-				nvidia,pull = <0>;
-			};
-			conf_crtp {
-				nvidia,pins = "crtp", "gmb", "slxa", "spih";
-				nvidia,pull = <2>;
-				nvidia,tristate = <1>;
-			};
-			conf_dta {
-				nvidia,pins = "dta", "dtb", "dtc", "dtd";
-				nvidia,pull = <1>;
-				nvidia,tristate = <0>;
-			};
-			conf_dte {
-				nvidia,pins = "dte", "spif";
-				nvidia,pull = <1>;
-				nvidia,tristate = <1>;
-			};
-			conf_hdint {
-				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
-					"lpw1", "lsck", "lsda", "lsdi", "lvp0";
-				nvidia,tristate = <1>;
-			};
-			conf_kbca {
-				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
-					"kbce", "kbcf", "sdio1", "uaa", "uab";
-				nvidia,pull = <2>;
-				nvidia,tristate = <0>;
-			};
-			conf_lc {
-				nvidia,pins = "lc", "ls";
-				nvidia,pull = <2>;
-			};
-			conf_ld0 {
-				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
-					"ld5", "ld6", "ld7", "ld8", "ld9",
-					"ld10", "ld11", "ld12", "ld13", "ld14",
-					"ld15", "ld16", "ld17", "ldi", "lhp0",
-					"lhp1", "lhp2", "lhs", "lm0", "lpp",
-					"lpw0", "lpw2", "lsc0", "lsc1", "lspi",
-					"lvp1", "lvs", "pmc", "sdb";
-				nvidia,tristate = <0>;
-			};
-			conf_ld17_0 {
-				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
-					"ld23_22";
-				nvidia,pull = <1>;
-			};
-		};
-	};
-
-	i2s@70002800 {
-		status = "okay";
-	};
-
-	serial@70006300 {
-		status = "okay";
-		clock-frequency = <216000000>;
-	};
-
-	i2c@7000c000 {
-		status = "okay";
-		clock-frequency = <400000>;
-
-		wm8903: wm8903@1a {
-			compatible = "wlf,wm8903";
-			reg = <0x1a>;
-			interrupt-parent = <&gpio>;
-			interrupts = <187 0x04>;
-
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			micdet-cfg = <0>;
-			micdet-delay = <100>;
-			gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
-		};
-
-		/* ALS and proximity sensor */
-		isl29018@44 {
-			compatible = "isil,isl29018";
-			reg = <0x44>;
-			interrupt-parent = <&gpio>;
-			interrupts = <202 0x04>; /*gpio PZ2 */
-		};
-	};
-
-	i2c@7000c400 {
-		status = "okay";
-		clock-frequency = <400000>;
-	};
-
-	i2c@7000c500 {
-		status = "okay";
-		clock-frequency = <400000>;
-	};
-
-	i2c@7000d000 {
-		status = "okay";
-		clock-frequency = <400000>;
-	};
-
-	usb@c5000000 {
-		status = "okay";
-	};
-
-	usb@c5004000 {
-		status = "okay";
-		nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
-	};
-
-	usb@c5008000 {
-		status = "okay";
-	};
-
-	sdhci@c8000400 {
-		status = "okay";
-		cd-gpios = <&gpio 69 0>; /* gpio PI5 */
-		wp-gpios = <&gpio 57 0>; /* gpio PH1 */
-		power-gpios = <&gpio 70 0>; /* gpio PI6 */
-		bus-width = <4>;
-	};
-
-	sdhci@c8000600 {
-		status = "okay";
-		support-8bit;
-		bus-width = <8>;
-	};
-
-	sound {
-		compatible = "nvidia,tegra-audio-wm8903-ventana",
-			     "nvidia,tegra-audio-wm8903";
-		nvidia,model = "NVIDIA Tegra Ventana";
-
-		nvidia,audio-routing =
-			"Headphone Jack", "HPOUTR",
-			"Headphone Jack", "HPOUTL",
-			"Int Spk", "ROP",
-			"Int Spk", "RON",
-			"Int Spk", "LOP",
-			"Int Spk", "LON",
-			"Mic Jack", "MICBIAS",
-			"IN1L", "Mic Jack";
-
-		nvidia,i2s-controller = <&tegra_i2s1>;
-		nvidia,audio-codec = <&wm8903>;
-
-		nvidia,spkr-en-gpios = <&wm8903 2 0>;
-		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
-		nvidia,int-mic-en-gpios = <&gpio 184 0>; /* gpio PX0 */
-		nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
-	};
-};
diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts
new file mode 100644
index 0000000..f146dbf
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-harmony.dts
@@ -0,0 +1,336 @@
+/dts-v1/;
+
+/include/ "tegra20.dtsi"
+
+/ {
+	model = "NVIDIA Tegra2 Harmony evaluation board";
+	compatible = "nvidia,harmony", "nvidia,tegra20";
+
+	memory {
+		reg = <0x00000000 0x40000000>;
+	};
+
+	pinmux {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			ata {
+				nvidia,pins = "ata";
+				nvidia,function = "ide";
+			};
+			atb {
+				nvidia,pins = "atb", "gma", "gme";
+				nvidia,function = "sdio4";
+			};
+			atc {
+				nvidia,pins = "atc";
+				nvidia,function = "nand";
+			};
+			atd {
+				nvidia,pins = "atd", "ate", "gmb", "gmd", "gpu",
+					"spia", "spib", "spic";
+				nvidia,function = "gmi";
+			};
+			cdev1 {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+			};
+			cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,function = "pllp_out4";
+			};
+			crtp {
+				nvidia,pins = "crtp";
+				nvidia,function = "crt";
+			};
+			csus {
+				nvidia,pins = "csus";
+				nvidia,function = "vi_sensor_clk";
+			};
+			dap1 {
+				nvidia,pins = "dap1";
+				nvidia,function = "dap1";
+			};
+			dap2 {
+				nvidia,pins = "dap2";
+				nvidia,function = "dap2";
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+			};
+			dap4 {
+				nvidia,pins = "dap4";
+				nvidia,function = "dap4";
+			};
+			ddc {
+				nvidia,pins = "ddc";
+				nvidia,function = "i2c2";
+			};
+			dta {
+				nvidia,pins = "dta", "dtd";
+				nvidia,function = "sdio2";
+			};
+			dtb {
+				nvidia,pins = "dtb", "dtc", "dte";
+				nvidia,function = "rsvd1";
+			};
+			dtf {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+			};
+			gmc {
+				nvidia,pins = "gmc";
+				nvidia,function = "uartd";
+			};
+			gpu7 {
+				nvidia,pins = "gpu7";
+				nvidia,function = "rtck";
+			};
+			gpv {
+				nvidia,pins = "gpv", "slxa", "slxk";
+				nvidia,function = "pcie";
+			};
+			hdint {
+				nvidia,pins = "hdint", "pta";
+				nvidia,function = "hdmi";
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+			};
+			irrx {
+				nvidia,pins = "irrx", "irtx";
+				nvidia,function = "uarta";
+			};
+			kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf";
+				nvidia,function = "kbc";
+			};
+			lcsn {
+				nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
+					"ld3", "ld4", "ld5", "ld6", "ld7",
+					"ld8", "ld9", "ld10", "ld11", "ld12",
+					"ld13", "ld14", "ld15", "ld16", "ld17",
+					"ldc", "ldi", "lhp0", "lhp1", "lhp2",
+					"lhs", "lm0", "lm1", "lpp", "lpw0",
+					"lpw1", "lpw2", "lsc0", "lsc1", "lsck",
+					"lsda", "lsdi", "lspi", "lvp0", "lvp1",
+					"lvs";
+				nvidia,function = "displaya";
+			};
+			owc {
+				nvidia,pins = "owc", "spdi", "spdo", "uac";
+				nvidia,function = "rsvd2";
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+			};
+			rm {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+			};
+			sdb {
+				nvidia,pins = "sdb", "sdc", "sdd";
+				nvidia,function = "pwm";
+			};
+			sdio1 {
+				nvidia,pins = "sdio1";
+				nvidia,function = "sdio1";
+			};
+			slxc {
+				nvidia,pins = "slxc", "slxd";
+				nvidia,function = "spdif";
+			};
+			spid {
+				nvidia,pins = "spid", "spie", "spif";
+				nvidia,function = "spi1";
+			};
+			spig {
+				nvidia,pins = "spig", "spih";
+				nvidia,function = "spi2_alt";
+			};
+			uaa {
+				nvidia,pins = "uaa", "uab", "uda";
+				nvidia,function = "ulpi";
+			};
+			uad {
+				nvidia,pins = "uad";
+				nvidia,function = "irda";
+			};
+			uca {
+				nvidia,pins = "uca", "ucb";
+				nvidia,function = "uartc";
+			};
+			conf_ata {
+				nvidia,pins = "ata", "atb", "atc", "atd", "ate",
+					"cdev1", "cdev2", "dap1", "dtb", "gma",
+					"gmb", "gmc", "gmd", "gme", "gpu7",
+					"gpv", "i2cp", "pta", "rm", "slxa",
+					"slxk", "spia", "spib", "uac";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			conf_ck32 {
+				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+				nvidia,pull = <0>;
+			};
+			conf_csus {
+				nvidia,pins = "csus", "spid", "spif";
+				nvidia,pull = <1>;
+				nvidia,tristate = <1>;
+			};
+			conf_crtp {
+				nvidia,pins = "crtp", "dap2", "dap3", "dap4",
+					"dtc", "dte", "dtf", "gpu", "sdio1",
+					"slxc", "slxd", "spdi", "spdo", "spig",
+					"uda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			conf_ddc {
+				nvidia,pins = "ddc", "dta", "dtd", "kbca",
+					"kbcb", "kbcc", "kbcd", "kbce", "kbcf",
+					"sdc";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			conf_hdint {
+				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+					"lpw1", "lsc1", "lsck", "lsda", "lsdi",
+					"lvp0", "owc", "sdb";
+				nvidia,tristate = <1>;
+			};
+			conf_irrx {
+				nvidia,pins = "irrx", "irtx", "sdd", "spic",
+					"spie", "spih", "uaa", "uab", "uad",
+					"uca", "ucb";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			conf_lc {
+				nvidia,pins = "lc", "ls";
+				nvidia,pull = <2>;
+			};
+			conf_ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lm0", "lpp",
+					"lpw0", "lpw2", "lsc0", "lspi", "lvp1",
+					"lvs", "pmc";
+				nvidia,tristate = <0>;
+			};
+			conf_ld17_0 {
+				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+					"ld23_22";
+				nvidia,pull = <1>;
+			};
+		};
+	};
+
+	i2s@70002800 {
+		status = "okay";
+	};
+
+	serial@70006300 {
+		status = "okay";
+		clock-frequency = <216000000>;
+	};
+
+	i2c@7000c000 {
+		status = "okay";
+		clock-frequency = <400000>;
+
+		wm8903: wm8903@1a {
+			compatible = "wlf,wm8903";
+			reg = <0x1a>;
+			interrupt-parent = <&gpio>;
+			interrupts = <187 0x04>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			micdet-cfg = <0>;
+			micdet-delay = <100>;
+			gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
+		};
+	};
+
+	i2c@7000c400 {
+		status = "okay";
+		clock-frequency = <400000>;
+	};
+
+	i2c@7000c500 {
+		status = "okay";
+		clock-frequency = <400000>;
+	};
+
+	i2c@7000d000 {
+		status = "okay";
+		clock-frequency = <400000>;
+	};
+
+	pmc {
+		nvidia,invert-interrupt;
+	};
+
+	usb@c5000000 {
+		status = "okay";
+	};
+
+	usb@c5004000 {
+		status = "okay";
+		nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+	};
+
+	usb@c5008000 {
+		status = "okay";
+	};
+
+	sdhci@c8000200 {
+		status = "okay";
+		cd-gpios = <&gpio 69 0>; /* gpio PI5 */
+		wp-gpios = <&gpio 57 0>; /* gpio PH1 */
+		power-gpios = <&gpio 155 0>; /* gpio PT3 */
+		bus-width = <4>;
+	};
+
+	sdhci@c8000600 {
+		status = "okay";
+		cd-gpios = <&gpio 58 0>; /* gpio PH2 */
+		wp-gpios = <&gpio 59 0>; /* gpio PH3 */
+		power-gpios = <&gpio 70 0>; /* gpio PI6 */
+		bus-width = <8>;
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-wm8903-harmony",
+			     "nvidia,tegra-audio-wm8903";
+		nvidia,model = "NVIDIA Tegra Harmony";
+
+		nvidia,audio-routing =
+			"Headphone Jack", "HPOUTR",
+			"Headphone Jack", "HPOUTL",
+			"Int Spk", "ROP",
+			"Int Spk", "RON",
+			"Int Spk", "LOP",
+			"Int Spk", "LON",
+			"Mic Jack", "MICBIAS",
+			"IN1L", "Mic Jack";
+
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,audio-codec = <&wm8903>;
+
+		nvidia,spkr-en-gpios = <&wm8903 2 0>;
+		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+		nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
+		nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
+	};
+};
diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts
new file mode 100644
index 0000000..684a9e1
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-paz00.dts
@@ -0,0 +1,347 @@
+/dts-v1/;
+
+/include/ "tegra20.dtsi"
+
+/ {
+	model = "Toshiba AC100 / Dynabook AZ";
+	compatible = "compal,paz00", "nvidia,tegra20";
+
+	memory {
+		reg = <0x00000000 0x20000000>;
+	};
+
+	pinmux {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			ata {
+				nvidia,pins = "ata", "atc", "atd", "ate",
+					"dap2", "gmb", "gmc", "gmd", "spia",
+					"spib", "spic", "spid", "spie";
+				nvidia,function = "gmi";
+			};
+			atb {
+				nvidia,pins = "atb", "gma", "gme";
+				nvidia,function = "sdio4";
+			};
+			cdev1 {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+			};
+			cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,function = "pllp_out4";
+			};
+			crtp {
+				nvidia,pins = "crtp";
+				nvidia,function = "crt";
+			};
+			csus {
+				nvidia,pins = "csus";
+				nvidia,function = "pllc_out1";
+			};
+			dap1 {
+				nvidia,pins = "dap1";
+				nvidia,function = "dap1";
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+			};
+			dap4 {
+				nvidia,pins = "dap4";
+				nvidia,function = "dap4";
+			};
+			ddc {
+				nvidia,pins = "ddc";
+				nvidia,function = "i2c2";
+			};
+			dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+				nvidia,function = "rsvd1";
+			};
+			dtf {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+			};
+			gpu {
+				nvidia,pins = "gpu", "sdb", "sdd";
+				nvidia,function = "pwm";
+			};
+			gpu7 {
+				nvidia,pins = "gpu7";
+				nvidia,function = "rtck";
+			};
+			gpv {
+				nvidia,pins = "gpv", "slxa", "slxk";
+				nvidia,function = "pcie";
+			};
+			hdint {
+				nvidia,pins = "hdint", "pta";
+				nvidia,function = "hdmi";
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+			};
+			irrx {
+				nvidia,pins = "irrx", "irtx";
+				nvidia,function = "uarta";
+			};
+			kbca {
+				nvidia,pins = "kbca", "kbcc", "kbce", "kbcf";
+				nvidia,function = "kbc";
+			};
+			kbcb {
+				nvidia,pins = "kbcb", "kbcd";
+				nvidia,function = "sdio2";
+			};
+			lcsn {
+				nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
+					"ld3", "ld4", "ld5", "ld6", "ld7",
+					"ld8", "ld9", "ld10", "ld11", "ld12",
+					"ld13", "ld14", "ld15", "ld16", "ld17",
+					"ldc", "ldi", "lhp0", "lhp1", "lhp2",
+					"lhs", "lm0", "lm1", "lpp", "lpw0",
+					"lpw1", "lpw2", "lsc0", "lsc1", "lsck",
+					"lsda", "lsdi", "lspi", "lvp0", "lvp1",
+					"lvs";
+				nvidia,function = "displaya";
+			};
+			owc {
+				nvidia,pins = "owc";
+				nvidia,function = "owr";
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+			};
+			rm {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+			};
+			sdc {
+				nvidia,pins = "sdc";
+				nvidia,function = "twc";
+			};
+			sdio1 {
+				nvidia,pins = "sdio1";
+				nvidia,function = "sdio1";
+			};
+			slxc {
+				nvidia,pins = "slxc", "slxd";
+				nvidia,function = "spi4";
+			};
+			spdi {
+				nvidia,pins = "spdi", "spdo";
+				nvidia,function = "rsvd2";
+			};
+			spif {
+				nvidia,pins = "spif", "uac";
+				nvidia,function = "rsvd4";
+			};
+			spig {
+				nvidia,pins = "spig", "spih";
+				nvidia,function = "spi2_alt";
+			};
+			uaa {
+				nvidia,pins = "uaa", "uab", "uda";
+				nvidia,function = "ulpi";
+			};
+			uad {
+				nvidia,pins = "uad";
+				nvidia,function = "spdif";
+			};
+			uca {
+				nvidia,pins = "uca", "ucb";
+				nvidia,function = "uartc";
+			};
+			conf_ata {
+				nvidia,pins = "ata", "atb", "atc", "atd", "ate",
+					"cdev1", "cdev2", "dap1", "dap2", "dtf",
+					"gma", "gmb", "gmc", "gmd", "gme",
+					"gpu", "gpu7", "gpv", "i2cp", "pta",
+					"rm", "sdio1", "slxk", "spdo", "uac",
+					"uda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			conf_ck32 {
+				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+				nvidia,pull = <0>;
+			};
+			conf_crtp {
+				nvidia,pins = "crtp", "dap3", "dap4", "dtb",
+					"dtc", "dte", "slxa", "slxc", "slxd",
+					"spdi";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			conf_csus {
+				nvidia,pins = "csus", "spia", "spib", "spid",
+					"spif";
+				nvidia,pull = <1>;
+				nvidia,tristate = <1>;
+			};
+			conf_ddc {
+				nvidia,pins = "ddc", "irrx", "irtx", "kbca",
+					"kbcb", "kbcc", "kbcd", "kbce", "kbcf",
+					"spic", "spig", "uaa", "uab";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			conf_dta {
+				nvidia,pins = "dta", "dtd", "owc", "sdc", "sdd",
+					"spie", "spih", "uad", "uca", "ucb";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			conf_hdint {
+				nvidia,pins = "hdint", "ld0", "ld1", "ld2",
+					"ld3", "ld4", "ld5", "ld6", "ld7",
+					"ld8", "ld9", "ld10", "ld11", "ld12",
+					"ld13", "ld14", "ld15", "ld16", "ld17",
+					"ldc", "ldi", "lhs", "lsc0", "lspi",
+					"lvs", "pmc";
+				nvidia,tristate = <0>;
+			};
+			conf_lc {
+				nvidia,pins = "lc", "ls";
+				nvidia,pull = <2>;
+			};
+			conf_lcsn {
+				nvidia,pins = "lcsn", "lhp0", "lhp1", "lhp2",
+					"lm0", "lm1", "lpp", "lpw0", "lpw1",
+					"lpw2", "lsc1", "lsck", "lsda", "lsdi",
+					"lvp0", "lvp1", "sdb";
+				nvidia,tristate = <1>;
+			};
+			conf_ld17_0 {
+				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+					"ld23_22";
+				nvidia,pull = <1>;
+			};
+		};
+	};
+
+	i2s@70002800 {
+		status = "okay";
+	};
+
+	serial@70006000 {
+		status = "okay";
+		clock-frequency = <216000000>;
+	};
+
+	serial@70006200 {
+		status = "okay";
+		clock-frequency = <216000000>;
+	};
+
+	i2c@7000c000 {
+		status = "okay";
+		clock-frequency = <400000>;
+
+		alc5632: alc5632@1e {
+			compatible = "realtek,alc5632";
+			reg = <0x1e>;
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+	};
+
+	i2c@7000c400 {
+		status = "okay";
+		clock-frequency = <400000>;
+	};
+
+	nvec {
+		compatible = "nvidia,nvec";
+		reg = <0x7000c500 0x100>;
+		interrupts = <0 92 0x04>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <80000>;
+		request-gpios = <&gpio 170 0>; /* gpio PV2 */
+		slave-addr = <138>;
+	};
+
+	i2c@7000d000 {
+		status = "okay";
+		clock-frequency = <400000>;
+
+		adt7461@4c {
+			compatible = "adi,adt7461";
+			reg = <0x4c>;
+		};
+	};
+
+	usb@c5000000 {
+		status = "okay";
+	};
+
+	usb@c5004000 {
+		status = "okay";
+		nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
+	};
+
+	usb@c5008000 {
+		status = "okay";
+	};
+
+	sdhci@c8000000 {
+		status = "okay";
+		cd-gpios = <&gpio 173 0>; /* gpio PV5 */
+		wp-gpios = <&gpio 57 0>;  /* gpio PH1 */
+		power-gpios = <&gpio 169 0>; /* gpio PV1 */
+		bus-width = <4>;
+	};
+
+	sdhci@c8000600 {
+		status = "okay";
+		bus-width = <8>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		power {
+			label = "Power";
+			gpios = <&gpio 79 1>; /* gpio PJ7, active low */
+			linux,code = <116>; /* KEY_POWER */
+			gpio-key,wakeup;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		wifi {
+			label = "wifi-led";
+			gpios = <&gpio 24 0>; /* gpio PD0 */
+			linux,default-trigger = "rfkill0";
+		};
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-alc5632-paz00",
+			"nvidia,tegra-audio-alc5632";
+
+		nvidia,model = "Compal PAZ00";
+
+		nvidia,audio-routing =
+			"Int Spk", "SPKOUT",
+			"Int Spk", "SPKOUTN",
+			"Headset Mic", "MICBIAS1",
+			"MIC1", "Headset Mic",
+			"Headset Stereophone", "HPR",
+			"Headset Stereophone", "HPL",
+			"DMICDAT", "Digital Mic";
+
+		nvidia,audio-codec = <&alc5632>;
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+	};
+};
diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
new file mode 100644
index 0000000..85e621a
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -0,0 +1,497 @@
+/dts-v1/;
+
+/include/ "tegra20.dtsi"
+
+/ {
+	model = "NVIDIA Seaboard";
+	compatible = "nvidia,seaboard", "nvidia,tegra20";
+
+	memory {
+		reg = <0x00000000 0x40000000>;
+	};
+
+	pinmux {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			ata {
+				nvidia,pins = "ata";
+				nvidia,function = "ide";
+			};
+			atb {
+				nvidia,pins = "atb", "gma", "gme";
+				nvidia,function = "sdio4";
+			};
+			atc {
+				nvidia,pins = "atc";
+				nvidia,function = "nand";
+			};
+			atd {
+				nvidia,pins = "atd", "ate", "gmb", "spia",
+					"spib", "spic";
+				nvidia,function = "gmi";
+			};
+			cdev1 {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+			};
+			cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,function = "pllp_out4";
+			};
+			crtp {
+				nvidia,pins = "crtp", "lm1";
+				nvidia,function = "crt";
+			};
+			csus {
+				nvidia,pins = "csus";
+				nvidia,function = "vi_sensor_clk";
+			};
+			dap1 {
+				nvidia,pins = "dap1";
+				nvidia,function = "dap1";
+			};
+			dap2 {
+				nvidia,pins = "dap2";
+				nvidia,function = "dap2";
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+			};
+			dap4 {
+				nvidia,pins = "dap4";
+				nvidia,function = "dap4";
+			};
+			dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+				nvidia,function = "vi";
+			};
+			dtf {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+			};
+			gmc {
+				nvidia,pins = "gmc";
+				nvidia,function = "uartd";
+			};
+			gmd {
+				nvidia,pins = "gmd";
+				nvidia,function = "sflash";
+			};
+			gpu {
+				nvidia,pins = "gpu";
+				nvidia,function = "pwm";
+			};
+			gpu7 {
+				nvidia,pins = "gpu7";
+				nvidia,function = "rtck";
+			};
+			gpv {
+				nvidia,pins = "gpv", "slxa", "slxk";
+				nvidia,function = "pcie";
+			};
+			hdint {
+				nvidia,pins = "hdint", "lpw0", "lpw2", "lsc1",
+					"lsck", "lsda";
+				nvidia,function = "hdmi";
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+			};
+			irrx {
+				nvidia,pins = "irrx", "irtx";
+				nvidia,function = "uartb";
+			};
+			kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf";
+				nvidia,function = "kbc";
+			};
+			lcsn {
+				nvidia,pins = "lcsn", "ldc", "lm0", "lpw1",
+					"lsdi", "lvp0";
+				nvidia,function = "rsvd4";
+			};
+			ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lpp", "lsc0",
+					"lspi", "lvp1", "lvs";
+				nvidia,function = "displaya";
+			};
+			owc {
+				nvidia,pins = "owc", "spdi", "spdo", "uac";
+				nvidia,function = "rsvd2";
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+			};
+			rm {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+			};
+			sdb {
+				nvidia,pins = "sdb", "sdc", "sdd";
+				nvidia,function = "sdio3";
+			};
+			sdio1 {
+				nvidia,pins = "sdio1";
+				nvidia,function = "sdio1";
+			};
+			slxc {
+				nvidia,pins = "slxc", "slxd";
+				nvidia,function = "spdif";
+			};
+			spid {
+				nvidia,pins = "spid", "spie", "spif";
+				nvidia,function = "spi1";
+			};
+			spig {
+				nvidia,pins = "spig", "spih";
+				nvidia,function = "spi2_alt";
+			};
+			uaa {
+				nvidia,pins = "uaa", "uab", "uda";
+				nvidia,function = "ulpi";
+			};
+			uad {
+				nvidia,pins = "uad";
+				nvidia,function = "irda";
+			};
+			uca {
+				nvidia,pins = "uca", "ucb";
+				nvidia,function = "uartc";
+			};
+			conf_ata {
+				nvidia,pins = "ata", "atb", "atc", "atd",
+					"cdev1", "cdev2", "dap1", "dap2",
+					"dap4", "ddc", "dtf", "gma", "gmc", "gmd",
+					"gme", "gpu", "gpu7", "i2cp", "irrx",
+					"irtx", "pta", "rm", "sdc", "sdd",
+					"slxd", "slxk", "spdi", "spdo", "uac",
+					"uad", "uca", "ucb", "uda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			conf_ate {
+				nvidia,pins = "ate", "csus", "dap3",
+					"gpv", "owc", "slxc", "spib", "spid",
+					"spie";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			conf_ck32 {
+				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+				nvidia,pull = <0>;
+			};
+			conf_crtp {
+				nvidia,pins = "crtp", "gmb", "slxa", "spia",
+					"spig", "spih";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			conf_dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd";
+				nvidia,pull = <1>;
+				nvidia,tristate = <0>;
+			};
+			conf_dte {
+				nvidia,pins = "dte", "spif";
+				nvidia,pull = <1>;
+				nvidia,tristate = <1>;
+			};
+			conf_hdint {
+				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+					"lpw1", "lsc1", "lsck", "lsda", "lsdi",
+					"lvp0";
+				nvidia,tristate = <1>;
+			};
+			conf_kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf", "sdio1", "spic", "uaa",
+					"uab";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			conf_lc {
+				nvidia,pins = "lc", "ls";
+				nvidia,pull = <2>;
+			};
+			conf_ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lm0", "lpp",
+					"lpw0", "lpw2", "lsc0", "lspi", "lvp1",
+					"lvs", "pmc", "sdb";
+				nvidia,tristate = <0>;
+			};
+			conf_ld17_0 {
+				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+					"ld23_22";
+				nvidia,pull = <1>;
+			};
+			drive_sdio1 {
+				nvidia,pins = "drive_sdio1";
+				nvidia,high-speed-mode = <0>;
+				nvidia,schmitt = <0>;
+				nvidia,low-power-mode = <3>;
+				nvidia,pull-down-strength = <31>;
+				nvidia,pull-up-strength = <31>;
+				nvidia,slew-rate-rising = <3>;
+				nvidia,slew-rate-falling = <3>;
+			};
+		};
+
+		state_i2cmux_ddc: pinmux_i2cmux_ddc {
+			ddc {
+				nvidia,pins = "ddc";
+				nvidia,function = "i2c2";
+			};
+			pta {
+				nvidia,pins = "pta";
+				nvidia,function = "rsvd4";
+			};
+		};
+
+		state_i2cmux_pta: pinmux_i2cmux_pta {
+			ddc {
+				nvidia,pins = "ddc";
+				nvidia,function = "rsvd4";
+			};
+			pta {
+				nvidia,pins = "pta";
+				nvidia,function = "i2c2";
+			};
+		};
+
+		state_i2cmux_idle: pinmux_i2cmux_idle {
+			ddc {
+				nvidia,pins = "ddc";
+				nvidia,function = "rsvd4";
+			};
+			pta {
+				nvidia,pins = "pta";
+				nvidia,function = "rsvd4";
+			};
+		};
+	};
+
+	i2s@70002800 {
+		status = "okay";
+	};
+
+	serial@70006300 {
+		status = "okay";
+		clock-frequency = <216000000>;
+	};
+
+	i2c@7000c000 {
+		status = "okay";
+		clock-frequency = <400000>;
+
+		wm8903: wm8903@1a {
+			compatible = "wlf,wm8903";
+			reg = <0x1a>;
+			interrupt-parent = <&gpio>;
+			interrupts = <187 0x04>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			micdet-cfg = <0>;
+			micdet-delay = <100>;
+			gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
+		};
+
+		/* ALS and proximity sensor */
+		isl29018@44 {
+			compatible = "isil,isl29018";
+			reg = <0x44>;
+			interrupt-parent = <&gpio>;
+			interrupts = <202 0x04>; /* GPIO PZ2 */
+		};
+
+		gyrometer@68 {
+			compatible = "invn,mpu3050";
+			reg = <0x68>;
+			interrupt-parent = <&gpio>;
+			interrupts = <204 0x04>; /* gpio PZ4 */
+		};
+	};
+
+	i2c@7000c400 {
+		status = "okay";
+		clock-frequency = <100000>;
+	};
+
+	i2cmux {
+		compatible = "i2c-mux-pinctrl";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c-parent = <&{/i2c@7000c400}>;
+
+		pinctrl-names = "ddc", "pta", "idle";
+		pinctrl-0 = <&state_i2cmux_ddc>;
+		pinctrl-1 = <&state_i2cmux_pta>;
+		pinctrl-2 = <&state_i2cmux_idle>;
+
+		i2c@0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c@1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			smart-battery@b {
+				compatible = "ti,bq20z75", "smart-battery-1.1";
+				reg = <0xb>;
+				ti,i2c-retry-count = <2>;
+				ti,poll-retry-count = <10>;
+			};
+		};
+	};
+
+	i2c@7000c500 {
+		status = "okay";
+		clock-frequency = <400000>;
+	};
+
+	i2c@7000d000 {
+		status = "okay";
+		clock-frequency = <400000>;
+
+		temperature-sensor@4c {
+			compatible = "nct1008";
+			reg = <0x4c>;
+		};
+
+		magnetometer@c {
+			compatible = "ak8975";
+			reg = <0xc>;
+			interrupt-parent = <&gpio>;
+			interrupts = <109 0x04>; /* gpio PN5 */
+		};
+	};
+
+	memory-controller@0x7000f400 {
+		emc-table@190000 {
+			reg = <190000>;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = <190000>;
+			nvidia,emc-registers = <0x0000000c 0x00000026
+				0x00000009 0x00000003 0x00000004 0x00000004
+				0x00000002 0x0000000c 0x00000003 0x00000003
+				0x00000002 0x00000001 0x00000004 0x00000005
+				0x00000004 0x00000009 0x0000000d 0x0000059f
+				0x00000000 0x00000003 0x00000003 0x00000003
+				0x00000003 0x00000001 0x0000000b 0x000000c8
+				0x00000003 0x00000007 0x00000004 0x0000000f
+				0x00000002 0x00000000 0x00000000 0x00000002
+				0x00000000 0x00000000 0x00000083 0xa06204ae
+				0x007dc010 0x00000000 0x00000000 0x00000000
+				0x00000000 0x00000000 0x00000000 0x00000000>;
+		};
+
+		emc-table@380000 {
+			reg = <380000>;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = <380000>;
+			nvidia,emc-registers = <0x00000017 0x0000004b
+				0x00000012 0x00000006 0x00000004 0x00000005
+				0x00000003 0x0000000c 0x00000006 0x00000006
+				0x00000003 0x00000001 0x00000004 0x00000005
+				0x00000004 0x00000009 0x0000000d 0x00000b5f
+				0x00000000 0x00000003 0x00000003 0x00000006
+				0x00000006 0x00000001 0x00000011 0x000000c8
+				0x00000003 0x0000000e 0x00000007 0x0000000f
+				0x00000002 0x00000000 0x00000000 0x00000002
+				0x00000000 0x00000000 0x00000083 0xe044048b
+				0x007d8010 0x00000000 0x00000000 0x00000000
+				0x00000000 0x00000000 0x00000000 0x00000000>;
+		};
+	};
+
+	usb@c5000000 {
+		status = "okay";
+		nvidia,vbus-gpio = <&gpio 24 0>; /* PD0 */
+		dr_mode = "otg";
+	};
+
+	usb@c5004000 {
+		status = "okay";
+		nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+	};
+
+	usb@c5008000 {
+		status = "okay";
+	};
+
+	sdhci@c8000400 {
+		status = "okay";
+		cd-gpios = <&gpio 69 0>; /* gpio PI5 */
+		wp-gpios = <&gpio 57 0>; /* gpio PH1 */
+		power-gpios = <&gpio 70 0>; /* gpio PI6 */
+		bus-width = <4>;
+	};
+
+	sdhci@c8000600 {
+		status = "okay";
+		bus-width = <8>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		power {
+			label = "Power";
+			gpios = <&gpio 170 1>; /* gpio PV2, active low */
+			linux,code = <116>; /* KEY_POWER */
+			gpio-key,wakeup;
+		};
+
+		lid {
+			label = "Lid";
+			gpios = <&gpio 23 0>; /* gpio PC7 */
+			linux,input-type = <5>; /* EV_SW */
+			linux,code = <0>; /* SW_LID */
+			debounce-interval = <1>;
+			gpio-key,wakeup;
+		};
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-wm8903-seaboard",
+			     "nvidia,tegra-audio-wm8903";
+		nvidia,model = "NVIDIA Tegra Seaboard";
+
+		nvidia,audio-routing =
+			"Headphone Jack", "HPOUTR",
+			"Headphone Jack", "HPOUTL",
+			"Int Spk", "ROP",
+			"Int Spk", "RON",
+			"Int Spk", "LOP",
+			"Int Spk", "LON",
+			"Mic Jack", "MICBIAS",
+			"IN1R", "Mic Jack";
+
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,audio-codec = <&wm8903>;
+
+		nvidia,spkr-en-gpios = <&wm8903 2 0>;
+		nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */
+	};
+};
diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts
new file mode 100644
index 0000000..9de5636
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-trimslice.dts
@@ -0,0 +1,306 @@
+/dts-v1/;
+
+/include/ "tegra20.dtsi"
+
+/ {
+	model = "Compulab TrimSlice board";
+	compatible = "compulab,trimslice", "nvidia,tegra20";
+
+	memory {
+		reg = <0x00000000 0x40000000>;
+	};
+
+	pinmux {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			ata {
+				nvidia,pins = "ata";
+				nvidia,function = "ide";
+			};
+			atb {
+				nvidia,pins = "atb", "gma";
+				nvidia,function = "sdio4";
+			};
+			atc {
+				nvidia,pins = "atc", "gmb";
+				nvidia,function = "nand";
+			};
+			atd {
+				nvidia,pins = "atd", "ate", "gme", "pta";
+				nvidia,function = "gmi";
+			};
+			cdev1 {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+			};
+			cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,function = "pllp_out4";
+			};
+			crtp {
+				nvidia,pins = "crtp";
+				nvidia,function = "crt";
+			};
+			csus {
+				nvidia,pins = "csus";
+				nvidia,function = "vi_sensor_clk";
+			};
+			dap1 {
+				nvidia,pins = "dap1";
+				nvidia,function = "dap1";
+			};
+			dap2 {
+				nvidia,pins = "dap2";
+				nvidia,function = "dap2";
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+			};
+			dap4 {
+				nvidia,pins = "dap4";
+				nvidia,function = "dap4";
+			};
+			ddc {
+				nvidia,pins = "ddc";
+				nvidia,function = "i2c2";
+			};
+			dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+				nvidia,function = "vi";
+			};
+			dtf {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+			};
+			gmc {
+				nvidia,pins = "gmc", "gmd";
+				nvidia,function = "sflash";
+			};
+			gpu {
+				nvidia,pins = "gpu";
+				nvidia,function = "uarta";
+			};
+			gpu7 {
+				nvidia,pins = "gpu7";
+				nvidia,function = "rtck";
+			};
+			gpv {
+				nvidia,pins = "gpv", "slxa", "slxk";
+				nvidia,function = "pcie";
+			};
+			hdint {
+				nvidia,pins = "hdint";
+				nvidia,function = "hdmi";
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+			};
+			irrx {
+				nvidia,pins = "irrx", "irtx";
+				nvidia,function = "uartb";
+			};
+			kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf";
+				nvidia,function = "kbc";
+			};
+			lcsn {
+				nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
+					"ld3", "ld4", "ld5", "ld6", "ld7",
+					"ld8", "ld9", "ld10", "ld11", "ld12",
+					"ld13", "ld14", "ld15", "ld16", "ld17",
+					"ldc", "ldi", "lhp0", "lhp1", "lhp2",
+					"lhs", "lm0", "lm1", "lpp", "lpw0",
+					"lpw1", "lpw2", "lsc0", "lsc1", "lsck",
+					"lsda", "lsdi", "lspi", "lvp0", "lvp1",
+					"lvs";
+				nvidia,function = "displaya";
+			};
+			owc {
+				nvidia,pins = "owc", "uac";
+				nvidia,function = "rsvd2";
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+			};
+			rm {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+			};
+			sdb {
+				nvidia,pins = "sdb", "sdc", "sdd";
+				nvidia,function = "pwm";
+			};
+			sdio1 {
+				nvidia,pins = "sdio1";
+				nvidia,function = "sdio1";
+			};
+			slxc {
+				nvidia,pins = "slxc", "slxd";
+				nvidia,function = "sdio3";
+			};
+			spdi {
+				nvidia,pins = "spdi", "spdo";
+				nvidia,function = "spdif";
+			};
+			spia {
+				nvidia,pins = "spia", "spib", "spic";
+				nvidia,function = "spi2";
+			};
+			spid {
+				nvidia,pins = "spid", "spie", "spif";
+				nvidia,function = "spi1";
+			};
+			spig {
+				nvidia,pins = "spig", "spih";
+				nvidia,function = "spi2_alt";
+			};
+			uaa {
+				nvidia,pins = "uaa", "uab", "uda";
+				nvidia,function = "ulpi";
+			};
+			uad {
+				nvidia,pins = "uad";
+				nvidia,function = "irda";
+			};
+			uca {
+				nvidia,pins = "uca", "ucb";
+				nvidia,function = "uartc";
+			};
+			conf_ata {
+				nvidia,pins = "ata", "atc", "atd", "ate",
+					"crtp", "dap2", "dap3", "dap4", "dta",
+					"dtb", "dtc", "dtd", "dte", "gmb",
+					"gme", "i2cp", "pta", "slxc", "slxd",
+					"spdi", "spdo", "uda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			conf_atb {
+				nvidia,pins = "atb", "cdev1", "cdev2", "dap1",
+					"gma", "gmc", "gmd", "gpu", "gpu7",
+					"gpv", "sdio1", "slxa", "slxk", "uac";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			conf_ck32 {
+				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+				nvidia,pull = <0>;
+			};
+			conf_csus {
+				nvidia,pins = "csus", "spia", "spib",
+					"spid", "spif";
+				nvidia,pull = <1>;
+				nvidia,tristate = <1>;
+			};
+			conf_ddc {
+				nvidia,pins = "ddc", "dtf", "rm", "sdc", "sdd";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			conf_hdint {
+				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+					"lpw1", "lsc1", "lsck", "lsda", "lsdi",
+					"lvp0", "pmc";
+				nvidia,tristate = <1>;
+			};
+			conf_irrx {
+				nvidia,pins = "irrx", "irtx", "kbca", "kbcb",
+					"kbcc", "kbcd", "kbce", "kbcf", "owc",
+					"spic", "spie", "spig", "spih", "uaa",
+					"uab", "uad", "uca", "ucb";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			conf_lc {
+				nvidia,pins = "lc", "ls";
+				nvidia,pull = <2>;
+			};
+			conf_ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lm0", "lpp",
+					"lpw0", "lpw2", "lsc0", "lspi", "lvp1",
+					"lvs", "sdb";
+				nvidia,tristate = <0>;
+			};
+			conf_ld17_0 {
+				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+					"ld23_22";
+				nvidia,pull = <1>;
+			};
+		};
+	};
+
+	i2s@70002800 {
+		status = "okay";
+	};
+
+	serial@70006000 {
+		status = "okay";
+		clock-frequency = <216000000>;
+	};
+
+	i2c@7000c000 {
+		status = "okay";
+		clock-frequency = <400000>;
+	};
+
+	i2c@7000c400 {
+		status = "okay";
+		clock-frequency = <400000>;
+	};
+
+	i2c@7000c500 {
+		status = "okay";
+		clock-frequency = <400000>;
+
+		codec: codec@1a {
+			compatible = "ti,tlv320aic23";
+			reg = <0x1a>;
+		};
+
+		rtc@56 {
+			compatible = "emmicro,em3027";
+			reg = <0x56>;
+		};
+	};
+
+	usb@c5000000 {
+		status = "okay";
+	};
+
+	usb@c5004000 {
+		nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
+	};
+
+	usb@c5008000 {
+		status = "okay";
+	};
+
+	sdhci@c8000000 {
+		status = "okay";
+		bus-width = <4>;
+	};
+
+	sdhci@c8000600 {
+		status = "okay";
+		cd-gpios = <&gpio 121 0>; /* gpio PP1 */
+		wp-gpios = <&gpio 122 0>; /* gpio PP2 */
+		bus-width = <4>;
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-trimslice";
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,audio-codec = <&codec>;
+	};
+};
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
new file mode 100644
index 0000000..be90544
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -0,0 +1,343 @@
+/dts-v1/;
+
+/include/ "tegra20.dtsi"
+
+/ {
+	model = "NVIDIA Tegra2 Ventana evaluation board";
+	compatible = "nvidia,ventana", "nvidia,tegra20";
+
+	memory {
+		reg = <0x00000000 0x40000000>;
+	};
+
+	pinmux {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			ata {
+				nvidia,pins = "ata";
+				nvidia,function = "ide";
+			};
+			atb {
+				nvidia,pins = "atb", "gma", "gme";
+				nvidia,function = "sdio4";
+			};
+			atc {
+				nvidia,pins = "atc";
+				nvidia,function = "nand";
+			};
+			atd {
+				nvidia,pins = "atd", "ate", "gmb", "spia",
+					"spib", "spic";
+				nvidia,function = "gmi";
+			};
+			cdev1 {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+			};
+			cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,function = "pllp_out4";
+			};
+			crtp {
+				nvidia,pins = "crtp", "lm1";
+				nvidia,function = "crt";
+			};
+			csus {
+				nvidia,pins = "csus";
+				nvidia,function = "vi_sensor_clk";
+			};
+			dap1 {
+				nvidia,pins = "dap1";
+				nvidia,function = "dap1";
+			};
+			dap2 {
+				nvidia,pins = "dap2";
+				nvidia,function = "dap2";
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+			};
+			dap4 {
+				nvidia,pins = "dap4";
+				nvidia,function = "dap4";
+			};
+			ddc {
+				nvidia,pins = "ddc", "owc", "spdi", "spdo",
+					"uac";
+				nvidia,function = "rsvd2";
+			};
+			dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+				nvidia,function = "vi";
+			};
+			dtf {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+			};
+			gmc {
+				nvidia,pins = "gmc";
+				nvidia,function = "uartd";
+			};
+			gmd {
+				nvidia,pins = "gmd";
+				nvidia,function = "sflash";
+			};
+			gpu {
+				nvidia,pins = "gpu";
+				nvidia,function = "pwm";
+			};
+			gpu7 {
+				nvidia,pins = "gpu7";
+				nvidia,function = "rtck";
+			};
+			gpv {
+				nvidia,pins = "gpv", "slxa", "slxk";
+				nvidia,function = "pcie";
+			};
+			hdint {
+				nvidia,pins = "hdint", "pta";
+				nvidia,function = "hdmi";
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+			};
+			irrx {
+				nvidia,pins = "irrx", "irtx";
+				nvidia,function = "uartb";
+			};
+			kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf";
+				nvidia,function = "kbc";
+			};
+			lcsn {
+				nvidia,pins = "lcsn", "ldc", "lm0", "lpw1",
+					"lsdi", "lvp0";
+				nvidia,function = "rsvd4";
+			};
+			ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lpp", "lpw0",
+					"lpw2", "lsc0", "lsc1", "lsck", "lsda",
+					"lspi", "lvp1", "lvs";
+				nvidia,function = "displaya";
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+			};
+			rm {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+			};
+			sdb {
+				nvidia,pins = "sdb", "sdc", "sdd", "slxc";
+				nvidia,function = "sdio3";
+			};
+			sdio1 {
+				nvidia,pins = "sdio1";
+				nvidia,function = "sdio1";
+			};
+			slxd {
+				nvidia,pins = "slxd";
+				nvidia,function = "spdif";
+			};
+			spid {
+				nvidia,pins = "spid", "spie", "spif";
+				nvidia,function = "spi1";
+			};
+			spig {
+				nvidia,pins = "spig", "spih";
+				nvidia,function = "spi2_alt";
+			};
+			uaa {
+				nvidia,pins = "uaa", "uab", "uda";
+				nvidia,function = "ulpi";
+			};
+			uad {
+				nvidia,pins = "uad";
+				nvidia,function = "irda";
+			};
+			uca {
+				nvidia,pins = "uca", "ucb";
+				nvidia,function = "uartc";
+			};
+			conf_ata {
+				nvidia,pins = "ata", "atb", "atc", "atd",
+					"cdev1", "cdev2", "dap1", "dap2",
+					"dap4", "ddc", "dtf", "gma", "gmc",
+					"gme", "gpu", "gpu7", "i2cp", "irrx",
+					"irtx", "pta", "rm", "sdc", "sdd",
+					"slxc", "slxd", "slxk", "spdi", "spdo",
+					"uac", "uad", "uca", "ucb", "uda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			conf_ate {
+				nvidia,pins = "ate", "csus", "dap3", "gmd",
+					"gpv", "owc", "spia", "spib", "spic",
+					"spid", "spie", "spig";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			conf_ck32 {
+				nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+					"pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+				nvidia,pull = <0>;
+			};
+			conf_crtp {
+				nvidia,pins = "crtp", "gmb", "slxa", "spih";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			conf_dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd";
+				nvidia,pull = <1>;
+				nvidia,tristate = <0>;
+			};
+			conf_dte {
+				nvidia,pins = "dte", "spif";
+				nvidia,pull = <1>;
+				nvidia,tristate = <1>;
+			};
+			conf_hdint {
+				nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+					"lpw1", "lsck", "lsda", "lsdi", "lvp0";
+				nvidia,tristate = <1>;
+			};
+			conf_kbca {
+				nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+					"kbce", "kbcf", "sdio1", "uaa", "uab";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			conf_lc {
+				nvidia,pins = "lc", "ls";
+				nvidia,pull = <2>;
+			};
+			conf_ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldi", "lhp0",
+					"lhp1", "lhp2", "lhs", "lm0", "lpp",
+					"lpw0", "lpw2", "lsc0", "lsc1", "lspi",
+					"lvp1", "lvs", "pmc", "sdb";
+				nvidia,tristate = <0>;
+			};
+			conf_ld17_0 {
+				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+					"ld23_22";
+				nvidia,pull = <1>;
+			};
+		};
+	};
+
+	i2s@70002800 {
+		status = "okay";
+	};
+
+	serial@70006300 {
+		status = "okay";
+		clock-frequency = <216000000>;
+	};
+
+	i2c@7000c000 {
+		status = "okay";
+		clock-frequency = <400000>;
+
+		wm8903: wm8903@1a {
+			compatible = "wlf,wm8903";
+			reg = <0x1a>;
+			interrupt-parent = <&gpio>;
+			interrupts = <187 0x04>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			micdet-cfg = <0>;
+			micdet-delay = <100>;
+			gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
+		};
+
+		/* ALS and proximity sensor */
+		isl29018@44 {
+			compatible = "isil,isl29018";
+			reg = <0x44>;
+			interrupt-parent = <&gpio>;
+			interrupts = <202 0x04>; /*gpio PZ2 */
+		};
+	};
+
+	i2c@7000c400 {
+		status = "okay";
+		clock-frequency = <400000>;
+	};
+
+	i2c@7000c500 {
+		status = "okay";
+		clock-frequency = <400000>;
+	};
+
+	i2c@7000d000 {
+		status = "okay";
+		clock-frequency = <400000>;
+	};
+
+	usb@c5000000 {
+		status = "okay";
+	};
+
+	usb@c5004000 {
+		status = "okay";
+		nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+	};
+
+	usb@c5008000 {
+		status = "okay";
+	};
+
+	sdhci@c8000400 {
+		status = "okay";
+		cd-gpios = <&gpio 69 0>; /* gpio PI5 */
+		wp-gpios = <&gpio 57 0>; /* gpio PH1 */
+		power-gpios = <&gpio 70 0>; /* gpio PI6 */
+		bus-width = <4>;
+	};
+
+	sdhci@c8000600 {
+		status = "okay";
+		bus-width = <8>;
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-wm8903-ventana",
+			     "nvidia,tegra-audio-wm8903";
+		nvidia,model = "NVIDIA Tegra Ventana";
+
+		nvidia,audio-routing =
+			"Headphone Jack", "HPOUTR",
+			"Headphone Jack", "HPOUTL",
+			"Int Spk", "ROP",
+			"Int Spk", "RON",
+			"Int Spk", "LOP",
+			"Int Spk", "LON",
+			"Mic Jack", "MICBIAS",
+			"IN1L", "Mic Jack";
+
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,audio-codec = <&wm8903>;
+
+		nvidia,spkr-en-gpios = <&wm8903 2 0>;
+		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+		nvidia,int-mic-en-gpios = <&gpio 184 0>; /* gpio PX0 */
+		nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
+	};
+};
diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts
new file mode 100644
index 0000000..6916310
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-whistler.dts
@@ -0,0 +1,301 @@
+/dts-v1/;
+
+/include/ "tegra20.dtsi"
+
+/ {
+	model = "NVIDIA Tegra2 Whistler evaluation board";
+	compatible = "nvidia,whistler", "nvidia,tegra20";
+
+	memory {
+		reg = <0x00000000 0x20000000>;
+	};
+
+	pinmux {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			ata {
+				nvidia,pins = "ata", "atb", "ate", "gma", "gmb",
+					"gmc", "gmd", "gpu";
+				nvidia,function = "gmi";
+			};
+			atc {
+				nvidia,pins = "atc", "atd";
+				nvidia,function = "sdio4";
+			};
+			cdev1 {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+			};
+			cdev2 {
+				nvidia,pins = "cdev2";
+				nvidia,function = "osc";
+			};
+			crtp {
+				nvidia,pins = "crtp";
+				nvidia,function = "crt";
+			};
+			csus {
+				nvidia,pins = "csus";
+				nvidia,function = "vi_sensor_clk";
+			};
+			dap1 {
+				nvidia,pins = "dap1";
+				nvidia,function = "dap1";
+			};
+			dap2 {
+				nvidia,pins = "dap2";
+				nvidia,function = "dap2";
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+			};
+			dap4 {
+				nvidia,pins = "dap4";
+				nvidia,function = "dap4";
+			};
+			ddc {
+				nvidia,pins = "ddc";
+				nvidia,function = "i2c2";
+			};
+			dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd";
+				nvidia,function = "vi";
+			};
+			dte {
+				nvidia,pins = "dte";
+				nvidia,function = "rsvd1";
+			};
+			dtf {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+			};
+			gme {
+				nvidia,pins = "gme";
+				nvidia,function = "dap5";
+			};
+			gpu7 {
+				nvidia,pins = "gpu7";
+				nvidia,function = "rtck";
+			};
+			gpv {
+				nvidia,pins = "gpv";
+				nvidia,function = "pcie";
+			};
+			hdint {
+				nvidia,pins = "hdint", "pta";
+				nvidia,function = "hdmi";
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+			};
+			irrx {
+				nvidia,pins = "irrx", "irtx";
+				nvidia,function = "uartb";
+			};
+			kbca {
+				nvidia,pins = "kbca", "kbcc", "kbce", "kbcf";
+				nvidia,function = "kbc";
+			};
+			kbcb {
+				nvidia,pins = "kbcb", "kbcd";
+				nvidia,function = "sdio2";
+			};
+			lcsn {
+				nvidia,pins = "lcsn", "lsck", "lsda", "lsdi",
+					"spia", "spib", "spic";
+				nvidia,function = "spi3";
+			};
+			ld0 {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+					"ld5", "ld6", "ld7", "ld8", "ld9",
+					"ld10", "ld11", "ld12", "ld13", "ld14",
+					"ld15", "ld16", "ld17", "ldc", "ldi",
+					"lhp0", "lhp1", "lhp2", "lhs", "lm0",
+					"lm1", "lpp", "lpw0", "lpw1", "lpw2",
+					"lsc0", "lsc1", "lspi", "lvp0", "lvp1",
+					"lvs";
+				nvidia,function = "displaya";
+			};
+			owc {
+				nvidia,pins = "owc", "uac";
+				nvidia,function = "owr";
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+			};
+			rm {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+			};
+			sdb {
+				nvidia,pins = "sdb", "sdc", "sdd", "slxa",
+					"slxc", "slxd", "slxk";
+				nvidia,function = "sdio3";
+			};
+			sdio1 {
+				nvidia,pins = "sdio1";
+				nvidia,function = "sdio1";
+			};
+			spdi {
+				nvidia,pins = "spdi", "spdo";
+				nvidia,function = "rsvd2";
+			};
+			spid {
+				nvidia,pins = "spid", "spie", "spig", "spih";
+				nvidia,function = "spi2_alt";
+			};
+			spif {
+				nvidia,pins = "spif";
+				nvidia,function = "spi2";
+			};
+			uaa {
+				nvidia,pins = "uaa", "uab";
+				nvidia,function = "uarta";
+			};
+			uad {
+				nvidia,pins = "uad";
+				nvidia,function = "irda";
+			};
+			uca {
+				nvidia,pins = "uca", "ucb";
+				nvidia,function = "uartc";
+			};
+			uda {
+				nvidia,pins = "uda";
+				nvidia,function = "spi1";
+			};
+			conf_ata {
+				nvidia,pins = "ata", "atb", "atc", "ddc", "gma",
+					"gmb", "gmc", "gmd", "irrx", "irtx",
+					"kbca", "kbcb", "kbcc", "kbcd", "kbce",
+					"kbcf", "sdc", "sdd", "spie", "spig",
+					"spih", "uaa", "uab", "uad", "uca",
+					"ucb";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			conf_atd {
+				nvidia,pins = "atd", "ate", "cdev1", "csus",
+					"dap1", "dap2", "dap3", "dap4", "dte",
+					"dtf", "gpu", "gpu7", "gpv", "i2cp",
+					"rm", "sdio1", "slxa", "slxc", "slxd",
+					"slxk", "spdi", "spdo", "uac", "uda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			conf_cdev2 {
+				nvidia,pins = "cdev2", "spia", "spib";
+				nvidia,pull = <1>;
+				nvidia,tristate = <1>;
+			};
+			conf_ck32 {
+				nvidia,pins = "ck32", "ddrc", "lc", "pmca",
+					"pmcb", "pmcc", "pmcd", "xm2c",
+					"xm2d";
+				nvidia,pull = <0>;
+			};
+			conf_crtp {
+				nvidia,pins = "crtp";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			conf_dta {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd",
+					"spid", "spif";
+				nvidia,pull = <1>;
+				nvidia,tristate = <0>;
+			};
+			conf_gme {
+				nvidia,pins = "gme", "owc", "pta", "spic";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			conf_ld17_0 {
+				nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+					"ld23_22";
+				nvidia,pull = <1>;
+			};
+			conf_ls {
+				nvidia,pins = "ls", "pmce";
+				nvidia,pull = <2>;
+			};
+			drive_dap1 {
+				nvidia,pins = "drive_dap1";
+				nvidia,high-speed-mode = <0>;
+				nvidia,schmitt = <1>;
+				nvidia,low-power-mode = <0>;
+				nvidia,pull-down-strength = <0>;
+				nvidia,pull-up-strength = <0>;
+				nvidia,slew-rate-rising = <0>;
+				nvidia,slew-rate-falling = <0>;
+			};
+		};
+	};
+
+	i2s@70002800 {
+		status = "okay";
+	};
+
+	serial@70006000 {
+		status = "okay";
+		clock-frequency = <216000000>;
+	};
+
+	i2c@7000d000 {
+		status = "okay";
+		clock-frequency = <100000>;
+
+		codec: codec@1a {
+			compatible = "wlf,wm8753";
+			reg = <0x1a>;
+		};
+
+		tca6416: gpio@20 {
+			compatible = "ti,tca6416";
+			reg = <0x20>;
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+	};
+
+	usb@c5000000 {
+		status = "okay";
+		nvidia,vbus-gpio = <&tca6416 0 0>; /* GPIO_PMU0 */
+	};
+
+	usb@c5008000 {
+		status = "okay";
+		nvidia,vbus-gpio = <&tca6416 1 0>; /* GPIO_PMU1 */
+	};
+
+	sdhci@c8000400 {
+		status = "okay";
+		wp-gpios = <&gpio 173 0>; /* gpio PV5 */
+		bus-width = <8>;
+	};
+
+	sdhci@c8000600 {
+		status = "okay";
+		bus-width = <8>;
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-wm8753-whistler",
+			     "nvidia,tegra-audio-wm8753";
+		nvidia,model = "NVIDIA Tegra Whistler";
+
+		nvidia,audio-routing =
+			"Headphone Jack", "LOUT1",
+			"Headphone Jack", "ROUT1",
+			"MIC2", "Mic Jack",
+			"MIC2N", "Mic Jack";
+
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,audio-codec = <&codec>;
+	};
+};
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index c417d67..9f19216 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -72,7 +72,7 @@
 		reg = <0x70002800 0x200>;
 		interrupts = <0 13 0x04>;
 		nvidia,dma-request-selector = <&apbdma 2>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	tegra_i2s2: i2s@70002a00 {
@@ -80,7 +80,7 @@
 		reg = <0x70002a00 0x200>;
 		interrupts = <0 3 0x04>;
 		nvidia,dma-request-selector = <&apbdma 1>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	serial@70006000 {
@@ -88,7 +88,7 @@
 		reg = <0x70006000 0x40>;
 		reg-shift = <2>;
 		interrupts = <0 36 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	serial@70006040 {
@@ -96,7 +96,7 @@
 		reg = <0x70006040 0x40>;
 		reg-shift = <2>;
 		interrupts = <0 37 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	serial@70006200 {
@@ -104,7 +104,7 @@
 		reg = <0x70006200 0x100>;
 		reg-shift = <2>;
 		interrupts = <0 46 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	serial@70006300 {
@@ -112,7 +112,7 @@
 		reg = <0x70006300 0x100>;
 		reg-shift = <2>;
 		interrupts = <0 90 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	serial@70006400 {
@@ -120,7 +120,7 @@
 		reg = <0x70006400 0x100>;
 		reg-shift = <2>;
 		interrupts = <0 91 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	i2c@7000c000 {
@@ -129,7 +129,7 @@
 		interrupts = <0 38 0x04>;
 		#address-cells = <1>;
 		#size-cells = <0>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	i2c@7000c400 {
@@ -138,7 +138,7 @@
 		interrupts = <0 84 0x04>;
 		#address-cells = <1>;
 		#size-cells = <0>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	i2c@7000c500 {
@@ -147,7 +147,7 @@
 		interrupts = <0 92 0x04>;
 		#address-cells = <1>;
 		#size-cells = <0>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	i2c@7000d000 {
@@ -156,7 +156,7 @@
 		interrupts = <0 53 0x04>;
 		#address-cells = <1>;
 		#size-cells = <0>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	pmc {
@@ -164,7 +164,7 @@
 		reg = <0x7000e400 0x400>;
 	};
 
-	mc {
+	memory-controller@0x7000f000 {
 		compatible = "nvidia,tegra20-mc";
 		reg = <0x7000f000 0x024
 		       0x7000f03c 0x3c4>;
@@ -177,7 +177,7 @@
 		       0x58000000 0x02000000>;	/* GART aperture */
 	};
 
-	emc {
+	memory-controller@0x7000f400 {
 		compatible = "nvidia,tegra20-emc";
 		reg = <0x7000f400 0x200>;
 		#address-cells = <1>;
@@ -190,7 +190,7 @@
 		interrupts = <0 20 0x04>;
 		phy_type = "utmi";
 		nvidia,has-legacy-mode;
-		status = "disable";
+		status = "disabled";
 	};
 
 	usb@c5004000 {
@@ -198,7 +198,7 @@
 		reg = <0xc5004000 0x4000>;
 		interrupts = <0 21 0x04>;
 		phy_type = "ulpi";
-		status = "disable";
+		status = "disabled";
 	};
 
 	usb@c5008000 {
@@ -206,35 +206,35 @@
 		reg = <0xc5008000 0x4000>;
 		interrupts = <0 97 0x04>;
 		phy_type = "utmi";
-		status = "disable";
+		status = "disabled";
 	};
 
 	sdhci@c8000000 {
 		compatible = "nvidia,tegra20-sdhci";
 		reg = <0xc8000000 0x200>;
 		interrupts = <0 14 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	sdhci@c8000200 {
 		compatible = "nvidia,tegra20-sdhci";
 		reg = <0xc8000200 0x200>;
 		interrupts = <0 15 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	sdhci@c8000400 {
 		compatible = "nvidia,tegra20-sdhci";
 		reg = <0xc8000400 0x200>;
 		interrupts = <0 19 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	sdhci@c8000600 {
 		compatible = "nvidia,tegra20-sdhci";
 		reg = <0xc8000600 0x200>;
 		interrupts = <0 31 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	pmu {
diff --git a/arch/arm/boot/dts/tegra30-cardhu.dts b/arch/arm/boot/dts/tegra30-cardhu.dts
new file mode 100644
index 0000000..c169bce
--- /dev/null
+++ b/arch/arm/boot/dts/tegra30-cardhu.dts
@@ -0,0 +1,171 @@
+/dts-v1/;
+
+/include/ "tegra30.dtsi"
+
+/ {
+	model = "NVIDIA Tegra30 Cardhu evaluation board";
+	compatible = "nvidia,cardhu", "nvidia,tegra30";
+
+	memory {
+		reg = <0x80000000 0x40000000>;
+	};
+
+	pinmux {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			sdmmc1_clk_pz0 {
+				nvidia,pins = "sdmmc1_clk_pz0";
+				nvidia,function = "sdmmc1";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			sdmmc1_cmd_pz1 {
+				nvidia,pins =	"sdmmc1_cmd_pz1",
+						"sdmmc1_dat0_py7",
+						"sdmmc1_dat1_py6",
+						"sdmmc1_dat2_py5",
+						"sdmmc1_dat3_py4";
+				nvidia,function = "sdmmc1";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			sdmmc4_clk_pcc4 {
+				nvidia,pins =	"sdmmc4_clk_pcc4",
+						"sdmmc4_rst_n_pcc3";
+				nvidia,function = "sdmmc4";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			sdmmc4_dat0_paa0 {
+				nvidia,pins =	"sdmmc4_dat0_paa0",
+						"sdmmc4_dat1_paa1",
+						"sdmmc4_dat2_paa2",
+						"sdmmc4_dat3_paa3",
+						"sdmmc4_dat4_paa4",
+						"sdmmc4_dat5_paa5",
+						"sdmmc4_dat6_paa6",
+						"sdmmc4_dat7_paa7";
+				nvidia,function = "sdmmc4";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			dap2_fs_pa2 {
+				nvidia,pins =	"dap2_fs_pa2",
+						"dap2_sclk_pa3",
+						"dap2_din_pa4",
+						"dap2_dout_pa5";
+				nvidia,function = "i2s1";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+		};
+	};
+
+	serial@70006000 {
+		status = "okay";
+		clock-frequency = <408000000>;
+	};
+
+	i2c@7000c000 {
+		status = "okay";
+		clock-frequency = <100000>;
+	};
+
+	i2c@7000c400 {
+		status = "okay";
+		clock-frequency = <100000>;
+	};
+
+	i2c@7000c500 {
+		status = "okay";
+		clock-frequency = <100000>;
+
+		/* ALS and Proximity sensor */
+		isl29028@44 {
+			compatible = "isil,isl29028";
+			reg = <0x44>;
+			interrupt-parent = <&gpio>;
+			interrupts = <88 0x04>; /*gpio PL0 */
+		};
+	};
+
+	i2c@7000c700 {
+		status = "okay";
+		clock-frequency = <100000>;
+	};
+
+	i2c@7000d000 {
+		status = "okay";
+		clock-frequency = <100000>;
+
+		wm8903: wm8903@1a {
+			compatible = "wlf,wm8903";
+			reg = <0x1a>;
+			interrupt-parent = <&gpio>;
+			interrupts = <179 0x04>; /* gpio PW3 */
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			micdet-cfg = <0>;
+			micdet-delay = <100>;
+			gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
+		};
+
+		tps62361 {
+			compatible = "ti,tps62361";
+			reg = <0x60>;
+
+			regulator-name = "tps62361-vout";
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1500000>;
+			regulator-boot-on;
+			regulator-always-on;
+			ti,vsel0-state-high;
+			ti,vsel1-state-high;
+		};
+	};
+
+	ahub {
+		i2s@70080400 {
+			status = "okay";
+		};
+	};
+
+	sdhci@78000000 {
+		status = "okay";
+		cd-gpios = <&gpio 69 0>; /* gpio PI5 */
+		wp-gpios = <&gpio 155 0>; /* gpio PT3 */
+		power-gpios = <&gpio 31 0>; /* gpio PD7 */
+		bus-width = <4>;
+	};
+
+	sdhci@78000600 {
+		status = "okay";
+		bus-width = <8>;
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-wm8903-cardhu",
+			     "nvidia,tegra-audio-wm8903";
+		nvidia,model = "NVIDIA Tegra Cardhu";
+
+		nvidia,audio-routing =
+			"Headphone Jack", "HPOUTR",
+			"Headphone Jack", "HPOUTL",
+			"Int Spk", "ROP",
+			"Int Spk", "RON",
+			"Int Spk", "LOP",
+			"Int Spk", "LON",
+			"Mic Jack", "MICBIAS",
+			"IN1L", "Mic Jack";
+
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,audio-codec = <&wm8903>;
+
+		nvidia,spkr-en-gpios = <&wm8903 2 0>;
+		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+	};
+};
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index 2dcc09e..da74019 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -82,7 +82,7 @@
 		reg = <0x70006000 0x40>;
 		reg-shift = <2>;
 		interrupts = <0 36 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	serial@70006040 {
@@ -90,7 +90,7 @@
 		reg = <0x70006040 0x40>;
 		reg-shift = <2>;
 		interrupts = <0 37 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	serial@70006200 {
@@ -98,7 +98,7 @@
 		reg = <0x70006200 0x100>;
 		reg-shift = <2>;
 		interrupts = <0 46 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	serial@70006300 {
@@ -106,7 +106,7 @@
 		reg = <0x70006300 0x100>;
 		reg-shift = <2>;
 		interrupts = <0 90 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	serial@70006400 {
@@ -114,7 +114,7 @@
 		reg = <0x70006400 0x100>;
 		reg-shift = <2>;
 		interrupts = <0 91 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	i2c@7000c000 {
@@ -123,7 +123,7 @@
 		interrupts = <0 38 0x04>;
 		#address-cells = <1>;
 		#size-cells = <0>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	i2c@7000c400 {
@@ -132,7 +132,7 @@
 		interrupts = <0 84 0x04>;
 		#address-cells = <1>;
 		#size-cells = <0>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	i2c@7000c500 {
@@ -141,7 +141,7 @@
 		interrupts = <0 92 0x04>;
 		#address-cells = <1>;
 		#size-cells = <0>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	i2c@7000c700 {
@@ -150,7 +150,7 @@
 		interrupts = <0 120 0x04>;
 		#address-cells = <1>;
 		#size-cells = <0>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	i2c@7000d000 {
@@ -159,7 +159,7 @@
 		interrupts = <0 53 0x04>;
 		#address-cells = <1>;
 		#size-cells = <0>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	pmc {
@@ -167,7 +167,7 @@
 		reg = <0x7000e400 0x400>;
 	};
 
-	mc {
+	memory-controller {
 		compatible = "nvidia,tegra30-mc";
 		reg = <0x7000f000 0x010
 		       0x7000f03c 0x1b4
@@ -201,35 +201,35 @@
 			compatible = "nvidia,tegra30-i2s";
 			reg = <0x70080300 0x100>;
 			nvidia,ahub-cif-ids = <4 4>;
-			status = "disable";
+			status = "disabled";
 		};
 
 		tegra_i2s1: i2s@70080400 {
 			compatible = "nvidia,tegra30-i2s";
 			reg = <0x70080400 0x100>;
 			nvidia,ahub-cif-ids = <5 5>;
-			status = "disable";
+			status = "disabled";
 		};
 
 		tegra_i2s2: i2s@70080500 {
 			compatible = "nvidia,tegra30-i2s";
 			reg = <0x70080500 0x100>;
 			nvidia,ahub-cif-ids = <6 6>;
-			status = "disable";
+			status = "disabled";
 		};
 
 		tegra_i2s3: i2s@70080600 {
 			compatible = "nvidia,tegra30-i2s";
 			reg = <0x70080600 0x100>;
 			nvidia,ahub-cif-ids = <7 7>;
-			status = "disable";
+			status = "disabled";
 		};
 
 		tegra_i2s4: i2s@70080700 {
 			compatible = "nvidia,tegra30-i2s";
 			reg = <0x70080700 0x100>;
 			nvidia,ahub-cif-ids = <8 8>;
-			status = "disable";
+			status = "disabled";
 		};
 	};
 
@@ -237,28 +237,28 @@
 		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
 		reg = <0x78000000 0x200>;
 		interrupts = <0 14 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	sdhci@78000200 {
 		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
 		reg = <0x78000200 0x200>;
 		interrupts = <0 15 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	sdhci@78000400 {
 		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
 		reg = <0x78000400 0x200>;
 		interrupts = <0 19 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	sdhci@78000600 {
 		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
 		reg = <0x78000600 0x200>;
 		interrupts = <0 31 0x04>;
-		status = "disable";
+		status = "disabled";
 	};
 
 	pmu {
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index aa07f59..1143c4d 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -452,6 +452,7 @@ static struct dma_map_ops dmabounce_ops = {
 	.alloc			= arm_dma_alloc,
 	.free			= arm_dma_free,
 	.mmap			= arm_dma_mmap,
+	.get_sgtable		= arm_dma_get_sgtable,
 	.map_page		= dmabounce_map_page,
 	.unmap_page		= dmabounce_unmap_page,
 	.sync_single_for_cpu	= dmabounce_sync_for_cpu,
diff --git a/arch/arm/configs/armadillo800eva_defconfig b/arch/arm/configs/armadillo800eva_defconfig
index ddc9fe6..df1ce54 100644
--- a/arch/arm/configs/armadillo800eva_defconfig
+++ b/arch/arm/configs/armadillo800eva_defconfig
@@ -5,10 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_UTS_NS is not set
 # CONFIG_IPC_NS is not set
-# CONFIG_USER_NS is not set
 # CONFIG_PID_NS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
@@ -89,26 +86,32 @@ CONFIG_SERIAL_SH_SCI_CONSOLE=y
 CONFIG_I2C=y
 CONFIG_I2C_SH_MOBILE=y
 # CONFIG_HWMON is not set
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_RC_CORE is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+# CONFIG_V4L_USB_DRIVERS is not set
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_MT9T112=y
+CONFIG_VIDEO_SH_MOBILE_CEU=y
+# CONFIG_RADIO_ADAPTERS is not set
 CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_SH_MOBILE_LCDC=y
+CONFIG_FB_SH_MOBILE_HDMI=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
-CONFIG_SOUND=y
-CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PROCFS is not set
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_ARM is not set
-CONFIG_SND_SOC=y
 CONFIG_SND_SOC_SH4_FSI=y
 # CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
-# CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_RENESAS_USBHS=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_RENESAS_USBHS_UDC=y
@@ -124,7 +127,6 @@ CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_NFS_V4_1=y
diff --git a/arch/arm/configs/kzm9g_defconfig b/arch/arm/configs/kzm9g_defconfig
index e3ebc20..686129f 100644
--- a/arch/arm/configs/kzm9g_defconfig
+++ b/arch/arm/configs/kzm9g_defconfig
@@ -108,6 +108,7 @@ CONFIG_MMC_SH_MMCIF=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_RS5C372=y
 CONFIG_DMADEVICES=y
 CONFIG_SH_DMAE=y
 CONFIG_ASYNC_TX_DMA=y
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index 1198dd6..4be9c1e 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -1,4 +1,6 @@
 CONFIG_EXPERIMENTAL=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_CGROUPS=y
@@ -25,14 +27,9 @@ CONFIG_ARCH_TEGRA=y
 CONFIG_ARCH_TEGRA_2x_SOC=y
 CONFIG_ARCH_TEGRA_3x_SOC=y
 CONFIG_MACH_HARMONY=y
-CONFIG_MACH_KAEN=y
 CONFIG_MACH_PAZ00=y
 CONFIG_MACH_TRIMSLICE=y
-CONFIG_MACH_WARIO=y
-CONFIG_MACH_VENTANA=y
 CONFIG_TEGRA_EMC_SCALING_ENABLE=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
@@ -103,19 +100,24 @@ CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 # CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_MUX=y
+CONFIG_I2C_MUX_PINCTRL=y
 CONFIG_I2C_TEGRA=y
 CONFIG_SPI=y
 CONFIG_SPI_TEGRA=y
+CONFIG_GPIO_TPS65910=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_BATTERY_SBS=y
 CONFIG_SENSORS_LM90=y
 CONFIG_MFD_TPS6586X=y
+CONFIG_MFD_TPS65910=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_REGULATOR_TPS62360=y
 CONFIG_REGULATOR_TPS6586X=y
+CONFIG_REGULATOR_TPS65910=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
@@ -126,6 +128,7 @@ CONFIG_SND=y
 # CONFIG_SND_USB is not set
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_TEGRA=y
+CONFIG_SND_SOC_TEGRA_WM8753=y
 CONFIG_SND_SOC_TEGRA_WM8903=y
 CONFIG_SND_SOC_TEGRA_TRIMSLICE=y
 CONFIG_SND_SOC_TEGRA_ALC5632=y
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index bbef15d..2ae842d 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -186,17 +186,6 @@ extern int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
 			void *cpu_addr, dma_addr_t dma_addr, size_t size,
 			struct dma_attrs *attrs);
 
-#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
-
-static inline int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
-				  void *cpu_addr, dma_addr_t dma_addr,
-				  size_t size, struct dma_attrs *attrs)
-{
-	struct dma_map_ops *ops = get_dma_ops(dev);
-	BUG_ON(!ops);
-	return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
-}
-
 static inline void *dma_alloc_writecombine(struct device *dev, size_t size,
 				       dma_addr_t *dma_handle, gfp_t flag)
 {
@@ -213,20 +202,12 @@ static inline void dma_free_writecombine(struct device *dev, size_t size,
 	return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs);
 }
 
-static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
-		      void *cpu_addr, dma_addr_t dma_addr, size_t size)
-{
-	DEFINE_DMA_ATTRS(attrs);
-	dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
-	return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
-}
-
 /*
  * This can be called during boot to increase the size of the consistent
  * DMA region above it's default value of 2MB. It must be called before the
  * memory allocator is initialised, i.e. before any core_initcall.
  */
-extern void __init init_consistent_dma_size(unsigned long size);
+static inline void init_consistent_dma_size(unsigned long size) { }
 
 /*
  * For SA-1111, IXP425, and ADI systems  the dma-mapping functions are "magic"
@@ -280,6 +261,9 @@ extern void arm_dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
 		enum dma_data_direction);
 extern void arm_dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
 		enum dma_data_direction);
+extern int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+		void *cpu_addr, dma_addr_t dma_addr, size_t size,
+		struct dma_attrs *attrs);
 
 #endif /* __KERNEL__ */
 #endif
diff --git a/arch/arm/include/asm/kmap_types.h b/arch/arm/include/asm/kmap_types.h
index e51b1e8..83eb2f7 100644
--- a/arch/arm/include/asm/kmap_types.h
+++ b/arch/arm/include/asm/kmap_types.h
@@ -4,30 +4,6 @@
 /*
  * This is the "bare minimum".  AIO seems to require this.
  */
-enum km_type {
-	KM_BOUNCE_READ,
-	KM_SKB_SUNRPC_DATA,
-	KM_SKB_DATA_SOFTIRQ,
-	KM_USER0,
-	KM_USER1,
-	KM_BIO_SRC_IRQ,
-	KM_BIO_DST_IRQ,
-	KM_PTE0,
-	KM_PTE1,
-	KM_IRQ0,
-	KM_IRQ1,
-	KM_SOFTIRQ0,
-	KM_SOFTIRQ1,
-	KM_L1_CACHE,
-	KM_L2_CACHE,
-	KM_KDB,
-	KM_TYPE_NR
-};
-
-#ifdef CONFIG_DEBUG_HIGHMEM
-#define KM_NMI		(-1)
-#define KM_NMI_PTE	(-1)
-#define KM_IRQ_PTE	(-1)
-#endif
+#define KM_TYPE_NR 16
 
 #endif
diff --git a/arch/arm/include/asm/leds.h b/arch/arm/include/asm/leds.h
deleted file mode 100644
index c545739..0000000
--- a/arch/arm/include/asm/leds.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *  arch/arm/include/asm/leds.h
- *
- *  Copyright (C) 1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Event-driven interface for LEDs on machines
- *  Added led_start and led_stop- Alex Holden, 28th Dec 1998.
- */
-#ifndef ASM_ARM_LEDS_H
-#define ASM_ARM_LEDS_H
-
-
-typedef enum {
-	led_idle_start,
-	led_idle_end,
-	led_timer,
-	led_start,
-	led_stop,
-	led_claim,		/* override idle & timer leds */
-	led_release,		/* restore idle & timer leds */
-	led_start_timer_mode,
-	led_stop_timer_mode,
-	led_green_on,
-	led_green_off,
-	led_amber_on,
-	led_amber_off,
-	led_red_on,
-	led_red_off,
-	led_blue_on,
-	led_blue_off,
-	/*
-	 * I want this between led_timer and led_start, but
-	 * someone has decided to export this to user space
-	 */
-	led_halted
-} led_event_t;
-
-/* Use this routine to handle LEDs */
-
-#ifdef CONFIG_LEDS
-extern void (*leds_event)(led_event_t);
-#else
-#define leds_event(e)
-#endif
-
-#endif
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index 00cbe10..e074948 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -12,21 +12,6 @@
 #ifndef __ARM_PERF_EVENT_H__
 #define __ARM_PERF_EVENT_H__
 
-/* ARM perf PMU IDs for use by internal perf clients. */
-enum arm_perf_pmu_ids {
-	ARM_PERF_PMU_ID_XSCALE1	= 0,
-	ARM_PERF_PMU_ID_XSCALE2,
-	ARM_PERF_PMU_ID_V6,
-	ARM_PERF_PMU_ID_V6MP,
-	ARM_PERF_PMU_ID_CA8,
-	ARM_PERF_PMU_ID_CA9,
-	ARM_PERF_PMU_ID_CA5,
-	ARM_PERF_PMU_ID_CA15,
-	ARM_PERF_PMU_ID_CA7,
-	ARM_NUM_PMU_IDS,
-};
-
-extern enum arm_perf_pmu_ids
-armpmu_get_pmu_id(void);
+/* Nothing to see here... */
 
 #endif /* __ARM_PERF_EVENT_H__ */
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 90114fa..4432305 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -103,10 +103,9 @@ struct pmu_hw_events {
 
 struct arm_pmu {
 	struct pmu	pmu;
-	enum arm_perf_pmu_ids id;
 	enum arm_pmu_type type;
 	cpumask_t	active_irqs;
-	const char	*name;
+	char		*name;
 	irqreturn_t	(*handle_irq)(int irq_num, void *dev);
 	void		(*enable)(struct hw_perf_event *evt, int idx);
 	void		(*disable)(struct hw_perf_event *evt, int idx);
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index b79f8e9..b2d6b41 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -148,8 +148,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
 #define TIF_NOTIFY_RESUME	2	/* callback before returning to user */
 #define TIF_SYSCALL_TRACE	8
 #define TIF_SYSCALL_AUDIT	9
-#define TIF_SYSCALL_RESTARTSYS	10
-#define TIF_POLLING_NRFLAG	16
 #define TIF_USING_IWMMXT	17
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	20
@@ -161,14 +159,11 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
-#define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_USING_IWMMXT	(1 << TIF_USING_IWMMXT)
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
-#define _TIF_SYSCALL_RESTARTSYS	(1 << TIF_SYSCALL_RESTARTSYS)
 
 /* Checks for any syscall work in entry-common.S */
-#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
-			   _TIF_SYSCALL_RESTARTSYS)
+#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
 
 /*
  * Change these and you break ASM code in entry-common.S
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 7ad2d5c..8951577 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -21,7 +21,6 @@ obj-y		:= elf.o entry-armv.o entry-common.o irq.o opcodes.o \
 
 obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
 
-obj-$(CONFIG_LEDS)		+= leds.o
 obj-$(CONFIG_OC_ETM)		+= etm.o
 obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 obj-$(CONFIG_ISA_DMA_API)	+= dma.o
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 2555250..2b2f25e 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -253,7 +253,7 @@ static void __devinit pci_fixup_cy82c693(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, pci_fixup_cy82c693);
 
-static void __init pci_fixup_it8152(struct pci_dev *dev)
+static void __devinit pci_fixup_it8152(struct pci_dev *dev)
 {
 	int i;
 	/* fixup for ITE 8152 devices */
@@ -461,7 +461,7 @@ static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
 			if (!sys->bus)
 				panic("PCI: unable to scan bus!");
 
-			busnr = sys->bus->subordinate + 1;
+			busnr = sys->bus->busn_res.end + 1;
 
 			list_add(&sys->node, head);
 		} else {
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 4afed88..45046b5 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -51,23 +51,15 @@ ret_fast_syscall:
 fast_work_pending:
 	str	r0, [sp, #S_R0+S_OFF]!		@ returned r0
 work_pending:
-	tst	r1, #_TIF_NEED_RESCHED
-	bne	work_resched
-	/*
-	 * TIF_SIGPENDING or TIF_NOTIFY_RESUME must've been set if we got here
-	 */
-	ldr	r2, [sp, #S_PSR]
 	mov	r0, sp				@ 'regs'
-	tst	r2, #15				@ are we returning to user mode?
-	bne	no_work_pending			@ no?  just leave, then...
 	mov	r2, why				@ 'syscall'
-	tst	r1, #_TIF_SIGPENDING		@ delivering a signal?
-	movne	why, #0				@ prevent further restarts
-	bl	do_notify_resume
-	b	ret_slow_syscall		@ Check work again
+	bl	do_work_pending
+	cmp	r0, #0
+	beq	no_work_pending
+	movlt	scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)
+	ldmia	sp, {r0 - r5}			@ have to reload r0 - r5
+	b	local_restart			@ ... and off we go
 
-work_resched:
-	bl	schedule
 /*
  * "slow" syscall return path.  "why" tells us if this was a real syscall.
  */
@@ -415,6 +407,7 @@ ENTRY(vector_swi)
 	eor	scno, scno, #__NR_SYSCALL_BASE	@ check OS number
 #endif
 
+local_restart:
 	ldr	r10, [tsk, #TI_FLAGS]		@ check for syscall tracing
 	stmdb	sp!, {r4, r5}			@ push fifth and sixth args
 
diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c
deleted file mode 100644
index 1911dae..0000000
--- a/arch/arm/kernel/leds.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * LED support code, ripped out of arch/arm/kernel/time.c
- *
- *  Copyright (C) 1994-2001 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/export.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/string.h>
-
-#include <asm/leds.h>
-
-static void dummy_leds_event(led_event_t evt)
-{
-}
-
-void (*leds_event)(led_event_t) = dummy_leds_event;
-
-struct leds_evt_name {
-	const char	name[8];
-	int		on;
-	int		off;
-};
-
-static const struct leds_evt_name evt_names[] = {
-	{ "amber", led_amber_on, led_amber_off },
-	{ "blue",  led_blue_on,  led_blue_off  },
-	{ "green", led_green_on, led_green_off },
-	{ "red",   led_red_on,   led_red_off   },
-};
-
-static ssize_t leds_store(struct device *dev,
-			struct device_attribute *attr,
-			const char *buf, size_t size)
-{
-	int ret = -EINVAL, len = strcspn(buf, " ");
-
-	if (len > 0 && buf[len] == '\0')
-		len--;
-
-	if (strncmp(buf, "claim", len) == 0) {
-		leds_event(led_claim);
-		ret = size;
-	} else if (strncmp(buf, "release", len) == 0) {
-		leds_event(led_release);
-		ret = size;
-	} else {
-		int i;
-
-		for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
-			if (strlen(evt_names[i].name) != len ||
-			    strncmp(buf, evt_names[i].name, len) != 0)
-				continue;
-			if (strncmp(buf+len, " on", 3) == 0) {
-				leds_event(evt_names[i].on);
-				ret = size;
-			} else if (strncmp(buf+len, " off", 4) == 0) {
-				leds_event(evt_names[i].off);
-				ret = size;
-			}
-			break;
-		}
-	}
-	return ret;
-}
-
-static DEVICE_ATTR(event, 0200, NULL, leds_store);
-
-static struct bus_type leds_subsys = {
-	.name		= "leds",
-	.dev_name	= "leds",
-};
-
-static struct device leds_device = {
-	.id		= 0,
-	.bus		= &leds_subsys,
-};
-
-static int leds_suspend(void)
-{
-	leds_event(led_stop);
-	return 0;
-}
-
-static void leds_resume(void)
-{
-	leds_event(led_start);
-}
-
-static void leds_shutdown(void)
-{
-	leds_event(led_halted);
-}
-
-static struct syscore_ops leds_syscore_ops = {
-	.shutdown	= leds_shutdown,
-	.suspend	= leds_suspend,
-	.resume		= leds_resume,
-};
-
-static int __init leds_init(void)
-{
-	int ret;
-	ret = subsys_system_register(&leds_subsys, NULL);
-	if (ret == 0)
-		ret = device_register(&leds_device);
-	if (ret == 0)
-		ret = device_create_file(&leds_device, &dev_attr_event);
-	if (ret == 0)
-		register_syscore_ops(&leds_syscore_ops);
-	return ret;
-}
-
-device_initcall(leds_init);
-
-EXPORT_SYMBOL(leds_event);
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 186c8cb..df85eda 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -47,17 +47,14 @@ static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
 /* Set at runtime when we know what CPU type we are. */
 static struct arm_pmu *cpu_pmu;
 
-enum arm_perf_pmu_ids
-armpmu_get_pmu_id(void)
+const char *perf_pmu_name(void)
 {
-	int id = -ENODEV;
-
-	if (cpu_pmu != NULL)
-		id = cpu_pmu->id;
+	if (!cpu_pmu)
+		return NULL;
 
-	return id;
+	return cpu_pmu->pmu.name;
 }
-EXPORT_SYMBOL_GPL(armpmu_get_pmu_id);
+EXPORT_SYMBOL_GPL(perf_pmu_name);
 
 int perf_num_counters(void)
 {
@@ -760,7 +757,7 @@ init_hw_perf_events(void)
 			cpu_pmu->name, cpu_pmu->num_events);
 		cpu_pmu_init(cpu_pmu);
 		register_cpu_notifier(&pmu_cpu_notifier);
-		armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW);
+		armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
 	} else {
 		pr_info("no hardware support available\n");
 	}
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index ab627a7..c90fcb2 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -650,7 +650,6 @@ static int armv6_map_event(struct perf_event *event)
 }
 
 static struct arm_pmu armv6pmu = {
-	.id			= ARM_PERF_PMU_ID_V6,
 	.name			= "v6",
 	.handle_irq		= armv6pmu_handle_irq,
 	.enable			= armv6pmu_enable_event,
@@ -685,7 +684,6 @@ static int armv6mpcore_map_event(struct perf_event *event)
 }
 
 static struct arm_pmu armv6mpcore_pmu = {
-	.id			= ARM_PERF_PMU_ID_V6MP,
 	.name			= "v6mpcore",
 	.handle_irq		= armv6pmu_handle_irq,
 	.enable			= armv6pmu_enable_event,
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index d3c5360..f04070b 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1258,7 +1258,6 @@ static u32 __init armv7_read_num_pmnc_events(void)
 
 static struct arm_pmu *__init armv7_a8_pmu_init(void)
 {
-	armv7pmu.id		= ARM_PERF_PMU_ID_CA8;
 	armv7pmu.name		= "ARMv7 Cortex-A8";
 	armv7pmu.map_event	= armv7_a8_map_event;
 	armv7pmu.num_events	= armv7_read_num_pmnc_events();
@@ -1267,7 +1266,6 @@ static struct arm_pmu *__init armv7_a8_pmu_init(void)
 
 static struct arm_pmu *__init armv7_a9_pmu_init(void)
 {
-	armv7pmu.id		= ARM_PERF_PMU_ID_CA9;
 	armv7pmu.name		= "ARMv7 Cortex-A9";
 	armv7pmu.map_event	= armv7_a9_map_event;
 	armv7pmu.num_events	= armv7_read_num_pmnc_events();
@@ -1276,7 +1274,6 @@ static struct arm_pmu *__init armv7_a9_pmu_init(void)
 
 static struct arm_pmu *__init armv7_a5_pmu_init(void)
 {
-	armv7pmu.id		= ARM_PERF_PMU_ID_CA5;
 	armv7pmu.name		= "ARMv7 Cortex-A5";
 	armv7pmu.map_event	= armv7_a5_map_event;
 	armv7pmu.num_events	= armv7_read_num_pmnc_events();
@@ -1285,7 +1282,6 @@ static struct arm_pmu *__init armv7_a5_pmu_init(void)
 
 static struct arm_pmu *__init armv7_a15_pmu_init(void)
 {
-	armv7pmu.id		= ARM_PERF_PMU_ID_CA15;
 	armv7pmu.name		= "ARMv7 Cortex-A15";
 	armv7pmu.map_event	= armv7_a15_map_event;
 	armv7pmu.num_events	= armv7_read_num_pmnc_events();
@@ -1295,7 +1291,6 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void)
 
 static struct arm_pmu *__init armv7_a7_pmu_init(void)
 {
-	armv7pmu.id		= ARM_PERF_PMU_ID_CA7;
 	armv7pmu.name		= "ARMv7 Cortex-A7";
 	armv7pmu.map_event	= armv7_a7_map_event;
 	armv7pmu.num_events	= armv7_read_num_pmnc_events();
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index e34e725..f759fe0 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -435,7 +435,6 @@ static int xscale_map_event(struct perf_event *event)
 }
 
 static struct arm_pmu xscale1pmu = {
-	.id		= ARM_PERF_PMU_ID_XSCALE1,
 	.name		= "xscale1",
 	.handle_irq	= xscale1pmu_handle_irq,
 	.enable		= xscale1pmu_enable_event,
@@ -803,7 +802,6 @@ xscale2pmu_write_counter(int counter, u32 val)
 }
 
 static struct arm_pmu xscale2pmu = {
-	.id		= ARM_PERF_PMU_ID_XSCALE2,
 	.name		= "xscale2",
 	.handle_irq	= xscale2pmu_handle_irq,
 	.enable		= xscale2pmu_enable_event,
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 19c95ea..864580a 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -31,9 +31,9 @@
 #include <linux/random.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/cpuidle.h>
+#include <linux/leds.h>
 
 #include <asm/cacheflush.h>
-#include <asm/leds.h>
 #include <asm/processor.h>
 #include <asm/thread_notify.h>
 #include <asm/stacktrace.h>
@@ -189,7 +189,7 @@ void cpu_idle(void)
 	while (1) {
 		tick_nohz_idle_enter();
 		rcu_idle_enter();
-		leds_event(led_idle_start);
+		ledtrig_cpu(CPU_LED_IDLE_START);
 		while (!need_resched()) {
 #ifdef CONFIG_HOTPLUG_CPU
 			if (cpu_is_offline(smp_processor_id()))
@@ -220,7 +220,7 @@ void cpu_idle(void)
 			} else
 				local_irq_enable();
 		}
-		leds_event(led_idle_end);
+		ledtrig_cpu(CPU_LED_IDLE_END);
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
 		schedule_preempt_disabled();
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 5700a7a..fc86b76 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -918,8 +918,6 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
 		audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0,
 				    regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
 
-	if (why == 0 && test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS))
-		scno = __NR_restart_syscall - __NR_SYSCALL_BASE;
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		return scno;
 
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index fd2392a..56f72d2 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -10,7 +10,6 @@
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/tracehook.h>
 
@@ -569,12 +568,13 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
  * the kernel can handle, and then we build all the user-level signal handling
  * stack-frames in one go after that.
  */
-static void do_signal(struct pt_regs *regs, int syscall)
+static int do_signal(struct pt_regs *regs, int syscall)
 {
 	unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
 	struct k_sigaction ka;
 	siginfo_t info;
 	int signr;
+	int restart = 0;
 
 	/*
 	 * If we were from a system call, check for system call restarting...
@@ -589,10 +589,12 @@ static void do_signal(struct pt_regs *regs, int syscall)
 		 * debugger will see the already changed PSW.
 		 */
 		switch (retval) {
+		case -ERESTART_RESTARTBLOCK:
+			restart -= 2;
 		case -ERESTARTNOHAND:
 		case -ERESTARTSYS:
 		case -ERESTARTNOINTR:
-		case -ERESTART_RESTARTBLOCK:
+			restart++;
 			regs->ARM_r0 = regs->ARM_ORIG_r0;
 			regs->ARM_pc = restart_addr;
 			break;
@@ -604,13 +606,15 @@ static void do_signal(struct pt_regs *regs, int syscall)
 	 * point the debugger may change all our registers ...
 	 */
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	/*
+	 * Depending on the signal settings we may need to revert the
+	 * decision to restart the system call.  But skip this if a
+	 * debugger has chosen to restart at a different PC.
+	 */
+	if (regs->ARM_pc != restart_addr)
+		restart = 0;
 	if (signr > 0) {
-		/*
-		 * Depending on the signal settings we may need to revert the
-		 * decision to restart the system call.  But skip this if a
-		 * debugger has chosen to restart at a different PC.
-		 */
-		if (regs->ARM_pc == restart_addr) {
+		if (unlikely(restart)) {
 			if (retval == -ERESTARTNOHAND ||
 			    retval == -ERESTART_RESTARTBLOCK
 			    || (retval == -ERESTARTSYS
@@ -618,35 +622,46 @@ static void do_signal(struct pt_regs *regs, int syscall)
 				regs->ARM_r0 = -EINTR;
 				regs->ARM_pc = continue_addr;
 			}
-			clear_thread_flag(TIF_SYSCALL_RESTARTSYS);
 		}
 
 		handle_signal(signr, &ka, &info, regs);
-		return;
-	}
-
-	if (syscall) {
-		/*
-		 * Handle restarting a different system call.  As above,
-		 * if a debugger has chosen to restart at a different PC,
-		 * ignore the restart.
-		 */
-		if (retval == -ERESTART_RESTARTBLOCK
-		    && regs->ARM_pc == restart_addr)
-			set_thread_flag(TIF_SYSCALL_RESTARTSYS);
+		return 0;
 	}
 
 	restore_saved_sigmask();
+	if (unlikely(restart))
+		regs->ARM_pc = continue_addr;
+	return restart;
 }
 
-asmlinkage void
-do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
+asmlinkage int
+do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
 {
-	if (thread_flags & _TIF_SIGPENDING)
-		do_signal(regs, syscall);
-
-	if (thread_flags & _TIF_NOTIFY_RESUME) {
-		clear_thread_flag(TIF_NOTIFY_RESUME);
-		tracehook_notify_resume(regs);
-	}
+	do {
+		if (likely(thread_flags & _TIF_NEED_RESCHED)) {
+			schedule();
+		} else {
+			if (unlikely(!user_mode(regs)))
+				return 0;
+			local_irq_enable();
+			if (thread_flags & _TIF_SIGPENDING) {
+				int restart = do_signal(regs, syscall);
+				if (unlikely(restart)) {
+					/*
+					 * Restart without handlers.
+					 * Deal with it without leaving
+					 * the kernel space.
+					 */
+					return restart;
+				}
+				syscall = 0;
+			} else {
+				clear_thread_flag(TIF_NOTIFY_RESUME);
+				tracehook_notify_resume(regs);
+			}
+		}
+		local_irq_disable();
+		thread_flags = current_thread_info()->flags;
+	} while (thread_flags & _TIF_WORK_MASK);
+	return 0;
 }
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index af2afb0..09be0c3 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -25,7 +25,6 @@
 #include <linux/timer.h>
 #include <linux/irq.h>
 
-#include <asm/leds.h>
 #include <asm/thread_info.h>
 #include <asm/sched_clock.h>
 #include <asm/stacktrace.h>
@@ -80,21 +79,6 @@ u32 arch_gettimeoffset(void)
 }
 #endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */
 
-#ifdef CONFIG_LEDS_TIMER
-static inline void do_leds(void)
-{
-	static unsigned int count = HZ/2;
-
-	if (--count == 0) {
-		count = HZ/2;
-		leds_event(led_timer);
-	}
-}
-#else
-#define	do_leds()
-#endif
-
-
 #ifndef CONFIG_GENERIC_CLOCKEVENTS
 /*
  * Kernel system timer support.
@@ -102,7 +86,6 @@ static inline void do_leds(void)
 void timer_tick(void)
 {
 	profile_tick(CPU_PROFILING);
-	do_leds();
 	xtime_update(1);
 #ifndef CONFIG_SMP
 	update_process_times(user_mode(get_irq_regs()));
diff --git a/arch/arm/lib/io-acorn.S b/arch/arm/lib/io-acorn.S
index 1b197ea..69719ba 100644
--- a/arch/arm/lib/io-acorn.S
+++ b/arch/arm/lib/io-acorn.S
@@ -11,13 +11,14 @@
  *
  */
 #include <linux/linkage.h>
+#include <linux/kern_levels.h>
 #include <asm/assembler.h>
 
 		.text
 		.align
 
 .Liosl_warning:
-		.ascii	"<4>insl/outsl not implemented, called from %08lX\0"
+		.ascii	KERN_WARNING "insl/outsl not implemented, called from %08lX\0"
 		.align
 
 /*
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
index cd81336..4993f1b 100644
--- a/arch/arm/mach-at91/board-csb337.c
+++ b/arch/arm/mach-at91/board-csb337.c
@@ -219,8 +219,6 @@ static struct gpio_led csb_leds[] = {
 
 static void __init csb337_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
 	/* Serial */
 	/* DBGU on ttyS0 */
 	at91_register_uart(0, 0, 0);
diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
index 89cc372..f9a4ab9 100644
--- a/arch/arm/mach-at91/board-ecbat91.c
+++ b/arch/arm/mach-at91/board-ecbat91.c
@@ -137,11 +137,20 @@ static struct spi_board_info __initdata ecb_at91spi_devices[] = {
 	},
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led ecb_leds[] = {
+	{	/* D1 */
+		.name			= "led1",
+		.gpio			= AT91_PIN_PC7,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	}
+};
+
 static void __init ecb_at91board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -164,6 +173,9 @@ static void __init ecb_at91board_init(void)
 
 	/* SPI */
 	at91_add_device_spi(ecb_at91spi_devices, ARRAY_SIZE(ecb_at91spi_devices));
+
+	/* LEDs */
+	at91_gpio_leds(ecb_leds, ARRAY_SIZE(ecb_leds));
 }
 
 MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
index 558546c..76cc826 100644
--- a/arch/arm/mach-at91/board-eco920.c
+++ b/arch/arm/mach-at91/board-eco920.c
@@ -92,10 +92,26 @@ static struct spi_board_info eco920_spi_devices[] = {
 	},
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led eco920_leds[] = {
+	{       /* D1 */
+		.name                   = "led1",
+		.gpio                   = AT91_PIN_PB0,
+		.active_low             = 1,
+		.default_trigger        = "heartbeat",
+	},
+	{       /* D2 */
+		.name                   = "led2",
+		.gpio                   = AT91_PIN_PB1,
+		.active_low             = 1,
+		.default_trigger        = "timer",
+	}
+};
+
 static void __init eco920_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
 	/* DBGU on ttyS0. (Rx & Tx only */
 	at91_register_uart(0, 0, 0);
 	at91_add_device_serial();
@@ -126,6 +142,8 @@ static void __init eco920_board_init(void)
 	);
 
 	at91_add_device_spi(eco920_spi_devices, ARRAY_SIZE(eco920_spi_devices));
+	/* LEDs */
+	at91_gpio_leds(eco920_leds, ARRAY_SIZE(eco920_leds));
 }
 
 MACHINE_START(ECO920, "eco920")
diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
index f260657..8db11f4 100644
--- a/arch/arm/mach-at91/board-kafa.c
+++ b/arch/arm/mach-at91/board-kafa.c
@@ -65,11 +65,20 @@ static struct at91_udc_data __initdata kafa_udc_data = {
 	.pullup_pin	= AT91_PIN_PB7,
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led kafa_leds[] = {
+	{	/* D1 */
+		.name			= "led1",
+		.gpio			= AT91_PIN_PB4,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	},
+};
+
 static void __init kafa_board_init(void)
 {
-	/* Set up the LEDs */
-	at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -87,6 +96,8 @@ static void __init kafa_board_init(void)
 	at91_add_device_i2c(NULL, 0);
 	/* SPI */
 	at91_add_device_spi(NULL, 0);
+	/* LEDs */
+	at91_gpio_leds(kafa_leds, ARRAY_SIZE(kafa_leds));
 }
 
 MACHINE_START(KAFA, "Sperry-Sun KAFA")
diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
index ba39db5..4e362b8 100644
--- a/arch/arm/mach-at91/board-kb9202.c
+++ b/arch/arm/mach-at91/board-kb9202.c
@@ -95,11 +95,26 @@ static struct atmel_nand_data __initdata kb9202_nand_data = {
 	.num_parts	= ARRAY_SIZE(kb9202_nand_partition),
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led kb9202_leds[] = {
+	{	/* D1 */
+		.name			= "led1",
+		.gpio			= AT91_PIN_PC19,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	},
+	{	/* D2 */
+		.name			= "led2",
+		.gpio			= AT91_PIN_PC18,
+		.active_low		= 1,
+		.default_trigger	= "timer",
+	}
+};
+
 static void __init kb9202_board_init(void)
 {
-	/* Set up the LEDs */
-	at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -127,6 +142,8 @@ static void __init kb9202_board_init(void)
 	at91_add_device_spi(NULL, 0);
 	/* NAND */
 	at91_add_device_nand(&kb9202_nand_data);
+	/* LEDs */
+	at91_gpio_leds(kb9202_leds, ARRAY_SIZE(kb9202_leds));
 }
 
 MACHINE_START(KB9200, "KB920x")
diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
index afd7a47..7417b7c 100644
--- a/arch/arm/mach-at91/board-rm9200dk.c
+++ b/arch/arm/mach-at91/board-rm9200dk.c
@@ -176,9 +176,6 @@ static struct gpio_led dk_leds[] = {
 
 static void __init dk_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
index 2b15b8a..18b2ec0 100644
--- a/arch/arm/mach-at91/board-rm9200ek.c
+++ b/arch/arm/mach-at91/board-rm9200ek.c
@@ -147,9 +147,6 @@ static struct gpio_led ek_leds[] = {
 
 static void __init ek_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
index 24ab9be..32342b8 100644
--- a/arch/arm/mach-at91/board-rsi-ews.c
+++ b/arch/arm/mach-at91/board-rsi-ews.c
@@ -184,9 +184,6 @@ static struct platform_device rsiews_nor_flash = {
  */
 static void __init rsi_ews_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	/* This one is for debugging */
diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
index cdd21f2..ef982f8 100644
--- a/arch/arm/mach-at91/board-sam9-l9260.c
+++ b/arch/arm/mach-at91/board-sam9-l9260.c
@@ -165,11 +165,26 @@ static struct at91_mmc_data __initdata ek_mmc_data = {
 	.vcc_pin	= -EINVAL,
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led ek_leds[] = {
+	{	/* D1 */
+		.name			= "led1",
+		.gpio			= AT91_PIN_PA9,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	},
+	{	/* D2 */
+		.name			= "led2",
+		.gpio			= AT91_PIN_PA6,
+		.active_low		= 1,
+		.default_trigger	= "timer",
+	}
+};
+
 static void __init ek_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -196,6 +211,8 @@ static void __init ek_board_init(void)
 	at91_add_device_mmc(0, &ek_mmc_data);
 	/* I2C */
 	at91_add_device_i2c(NULL, 0);
+	/* LEDs */
+	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
 }
 
 MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 2736453..0b4501c 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -568,9 +568,6 @@ static struct gpio_led ek_leds[] = {
 
 static void __init ek_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
index d56665e..cc05dd1 100644
--- a/arch/arm/mach-at91/board-yl-9200.c
+++ b/arch/arm/mach-at91/board-yl-9200.c
@@ -540,9 +540,6 @@ void __init yl9200_add_device_video(void) {}
 
 static void __init yl9200_board_init(void)
 {
-	/* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
-	at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index 369afc2..c55a436 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -187,7 +187,6 @@ struct at91_can_data {
 extern void __init at91_add_device_can(struct at91_can_data *data);
 
  /* LEDs */
-extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
 extern void __init at91_gpio_leds(struct gpio_led *leds, int nr);
 extern void __init at91_pwm_leds(struct gpio_led *leds, int nr);
 
diff --git a/arch/arm/mach-at91/leds.c b/arch/arm/mach-at91/leds.c
index 8dfafe7..1b1e62b 100644
--- a/arch/arm/mach-at91/leds.c
+++ b/arch/arm/mach-at91/leds.c
@@ -90,108 +90,3 @@ void __init at91_pwm_leds(struct gpio_led *leds, int nr)
 #else
 void __init at91_pwm_leds(struct gpio_led *leds, int nr){}
 #endif
-
-
-/* ------------------------------------------------------------------------- */
-
-#if defined(CONFIG_LEDS)
-
-#include <asm/leds.h>
-
-/*
- * Old ARM-specific LED framework; not fully functional when generic time is
- * in use.
- */
-
-static u8 at91_leds_cpu;
-static u8 at91_leds_timer;
-
-static inline void at91_led_on(unsigned int led)
-{
-	at91_set_gpio_value(led, 0);
-}
-
-static inline void at91_led_off(unsigned int led)
-{
-	at91_set_gpio_value(led, 1);
-}
-
-static inline void at91_led_toggle(unsigned int led)
-{
-	unsigned long is_off = at91_get_gpio_value(led);
-	if (is_off)
-		at91_led_on(led);
-	else
-		at91_led_off(led);
-}
-
-
-/*
- * Handle LED events.
- */
-static void at91_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch(evt) {
-	case led_start:		/* System startup */
-		at91_led_on(at91_leds_cpu);
-		break;
-
-	case led_stop:		/* System stop / suspend */
-		at91_led_off(at91_leds_cpu);
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:		/* Every 50 timer ticks */
-		at91_led_toggle(at91_leds_timer);
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:	/* Entering idle state */
-		at91_led_off(at91_leds_cpu);
-		break;
-
-	case led_idle_end:	/* Exit idle state */
-		at91_led_on(at91_leds_cpu);
-		break;
-#endif
-
-	default:
-		break;
-	}
-
-	local_irq_restore(flags);
-}
-
-
-static int __init leds_init(void)
-{
-	if (!at91_leds_timer || !at91_leds_cpu)
-		return -ENODEV;
-
-	leds_event = at91_leds_event;
-
-	leds_event(led_start);
-	return 0;
-}
-
-__initcall(leds_init);
-
-
-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
-{
-	/* Enable GPIO to access the LEDs */
-	at91_set_gpio_output(cpu_led, 1);
-	at91_set_gpio_output(timer_led, 1);
-
-	at91_leds_cpu	= cpu_led;
-	at91_leds_timer	= timer_led;
-}
-
-#else
-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
-#endif
diff --git a/arch/arm/mach-clps711x/Makefile b/arch/arm/mach-clps711x/Makefile
index f2f0256..5872b49 100644
--- a/arch/arm/mach-clps711x/Makefile
+++ b/arch/arm/mach-clps711x/Makefile
@@ -16,5 +16,3 @@ obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o
 obj-$(CONFIG_ARCH_EDB7211)  += edb7211-arch.o edb7211-mm.o
 obj-$(CONFIG_ARCH_FORTUNET) += fortunet.o
 obj-$(CONFIG_ARCH_P720T)    += p720t.o
-leds-$(CONFIG_ARCH_P720T)   += p720t-leds.o
-obj-$(CONFIG_LEDS)          += $(leds-y)
diff --git a/arch/arm/mach-clps711x/common.c b/arch/arm/mach-clps711x/common.c
index c965fd8..1e1ae48 100644
--- a/arch/arm/mach-clps711x/common.c
+++ b/arch/arm/mach-clps711x/common.c
@@ -31,7 +31,6 @@
 #include <asm/sizes.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-clps711x/p720t-leds.c b/arch/arm/mach-clps711x/p720t-leds.c
deleted file mode 100644
index bbc449f..0000000
--- a/arch/arm/mach-clps711x/p720t-leds.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *  linux/arch/arm/mach-clps711x/leds.c
- *
- *  Integrator LED control routines
- *
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-static void p720t_leds_event(led_event_t ledevt)
-{
-	unsigned long flags;
-	u32 pddr;
-
-	local_irq_save(flags);
-	switch(ledevt) {
-	case led_idle_start:
-		break;
-
-	case led_idle_end:
-		break;
-
-	case led_timer:
-		pddr = clps_readb(PDDR);
-		clps_writeb(pddr ^ 1, PDDR);
-		break;
-
-	default:
-		break;
-	}
-
-	local_irq_restore(flags);
-}
-
-static int __init leds_init(void)
-{
-	if (machine_is_p720t())
-		leds_event = p720t_leds_event;
-
-	return 0;
-}
-
-arch_initcall(leds_init);
diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c
index 42ee8f3..09113a9 100644
--- a/arch/arm/mach-clps711x/p720t.c
+++ b/arch/arm/mach-clps711x/p720t.c
@@ -23,6 +23,8 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <mach/hardware.h>
 #include <asm/pgtable.h>
@@ -34,6 +36,8 @@
 #include <asm/mach/map.h>
 #include <mach/syspld.h>
 
+#include <asm/hardware/clps7111.h>
+
 #include "common.h"
 
 /*
@@ -121,3 +125,60 @@ static int p720t_hw_init(void)
 
 __initcall(p720t_hw_init);
 
+/*
+ * LED controled by CPLD
+ */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+static void p720t_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
+{
+	u8 reg = clps_readb(PDDR);
+
+	if (b != LED_OFF)
+		reg |= 0x1;
+	else
+		reg &= ~0x1;
+
+	clps_writeb(reg, PDDR);
+}
+
+static enum led_brightness p720t_led_get(struct led_classdev *cdev)
+{
+	u8 reg = clps_readb(PDDR);
+
+	return (reg & 0x1) ? LED_FULL : LED_OFF;
+}
+
+static int __init p720t_leds_init(void)
+{
+
+	struct led_classdev *cdev;
+	int ret;
+
+	if (!machine_is_p720t())
+		return -ENODEV;
+
+	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+	if (!cdev)
+		return -ENOMEM;
+
+	cdev->name = "p720t:0";
+	cdev->brightness_set = p720t_led_set;
+	cdev->brightness_get = p720t_led_get;
+	cdev->default_trigger = "heartbeat";
+
+	ret = led_classdev_register(NULL, cdev);
+	if (ret	< 0) {
+		kfree(cdev);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(p720t_leds_init);
+#endif
diff --git a/arch/arm/mach-ebsa110/Makefile b/arch/arm/mach-ebsa110/Makefile
index 6520ac8..935e4af 100644
--- a/arch/arm/mach-ebsa110/Makefile
+++ b/arch/arm/mach-ebsa110/Makefile
@@ -4,9 +4,7 @@
 
 # Object file lists.
 
-obj-y			:= core.o io.o
+obj-y			:= core.o io.o leds.o
 obj-m			:=
 obj-n			:=
 obj-			:=
-
-obj-$(CONFIG_LEDS)	+= leds.o
diff --git a/arch/arm/mach-ebsa110/leds.c b/arch/arm/mach-ebsa110/leds.c
index 99e14e3..0398258 100644
--- a/arch/arm/mach-ebsa110/leds.c
+++ b/arch/arm/mach-ebsa110/leds.c
@@ -1,52 +1,71 @@
 /*
- *  linux/arch/arm/mach-ebsa110/leds.c
+ * Driver for the LED found on the EBSA110 machine
+ * Based on Versatile and RealView machine LED code
  *
- *  Copyright (C) 1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  EBSA-110 LED control routines.  We use the led as follows:
- *
- *   - Red - toggles state every 50 timer interrupts
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Bryan Wu <bryan.wu@canonical.com>
  */
-#include <linux/module.h>
-#include <linux/spinlock.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
-#include <mach/hardware.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 
 #include "core.h"
 
-static spinlock_t leds_lock;
-
-static void ebsa110_leds_event(led_event_t ledevt)
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+static void ebsa110_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
 {
-	unsigned long flags;
+	u8 reg = __raw_readb(SOFT_BASE);
 
-	spin_lock_irqsave(&leds_lock, flags);
+	if (b != LED_OFF)
+		reg |= 0x80;
+	else
+		reg &= ~0x80;
 
-	switch(ledevt) {
-	case led_timer:
-		*(volatile unsigned char *)SOFT_BASE ^= 128;
-		break;
+	__raw_writeb(reg, SOFT_BASE);
+}
 
-	default:
-		break;
-	}
+static enum led_brightness ebsa110_led_get(struct led_classdev *cdev)
+{
+	u8 reg = __raw_readb(SOFT_BASE);
 
-	spin_unlock_irqrestore(&leds_lock, flags);
+	return (reg & 0x80) ? LED_FULL : LED_OFF;
 }
 
-static int __init leds_init(void)
+static int __init ebsa110_leds_init(void)
 {
-	if (machine_is_ebsa110())
-		leds_event = ebsa110_leds_event;
+
+	struct led_classdev *cdev;
+	int ret;
+
+	if (!machine_is_ebsa110())
+		return -ENODEV;
+
+	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+	if (!cdev)
+		return -ENOMEM;
+
+	cdev->name = "ebsa110:0";
+	cdev->brightness_set = ebsa110_led_set;
+	cdev->brightness_get = ebsa110_led_get;
+	cdev->default_trigger = "heartbeat";
+
+	ret = led_classdev_register(NULL, cdev);
+	if (ret	< 0) {
+		kfree(cdev);
+		return ret;
+	}
 
 	return 0;
 }
 
-__initcall(leds_init);
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(ebsa110_leds_init);
+#endif
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 4dd07a0..4afe52a 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -797,6 +797,102 @@ static struct platform_device ep93xx_wdt_device = {
 	.resource	= ep93xx_wdt_resources,
 };
 
+/*************************************************************************
+ * EP93xx IDE
+ *************************************************************************/
+static struct resource ep93xx_ide_resources[] = {
+	DEFINE_RES_MEM(EP93XX_IDE_PHYS_BASE, 0x38),
+	DEFINE_RES_IRQ(IRQ_EP93XX_EXT3),
+};
+
+static struct platform_device ep93xx_ide_device = {
+	.name		= "ep93xx-ide",
+	.id		= -1,
+	.dev		= {
+		.dma_mask		= &ep93xx_ide_device.dev.coherent_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(ep93xx_ide_resources),
+	.resource	= ep93xx_ide_resources,
+};
+
+void __init ep93xx_register_ide(void)
+{
+	platform_device_register(&ep93xx_ide_device);
+}
+
+int ep93xx_ide_acquire_gpio(struct platform_device *pdev)
+{
+	int err;
+	int i;
+
+	err = gpio_request(EP93XX_GPIO_LINE_EGPIO2, dev_name(&pdev->dev));
+	if (err)
+		return err;
+	err = gpio_request(EP93XX_GPIO_LINE_EGPIO15, dev_name(&pdev->dev));
+	if (err)
+		goto fail_egpio15;
+	for (i = 2; i < 8; i++) {
+		err = gpio_request(EP93XX_GPIO_LINE_E(i), dev_name(&pdev->dev));
+		if (err)
+			goto fail_gpio_e;
+	}
+	for (i = 4; i < 8; i++) {
+		err = gpio_request(EP93XX_GPIO_LINE_G(i), dev_name(&pdev->dev));
+		if (err)
+			goto fail_gpio_g;
+	}
+	for (i = 0; i < 8; i++) {
+		err = gpio_request(EP93XX_GPIO_LINE_H(i), dev_name(&pdev->dev));
+		if (err)
+			goto fail_gpio_h;
+	}
+
+	/* GPIO ports E[7:2], G[7:4] and H used by IDE */
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_EONIDE |
+				 EP93XX_SYSCON_DEVCFG_GONIDE |
+				 EP93XX_SYSCON_DEVCFG_HONIDE);
+	return 0;
+
+fail_gpio_h:
+	for (--i; i >= 0; --i)
+		gpio_free(EP93XX_GPIO_LINE_H(i));
+	i = 8;
+fail_gpio_g:
+	for (--i; i >= 4; --i)
+		gpio_free(EP93XX_GPIO_LINE_G(i));
+	i = 8;
+fail_gpio_e:
+	for (--i; i >= 2; --i)
+		gpio_free(EP93XX_GPIO_LINE_E(i));
+	gpio_free(EP93XX_GPIO_LINE_EGPIO15);
+fail_egpio15:
+	gpio_free(EP93XX_GPIO_LINE_EGPIO2);
+	return err;
+}
+EXPORT_SYMBOL(ep93xx_ide_acquire_gpio);
+
+void ep93xx_ide_release_gpio(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 2; i < 8; i++)
+		gpio_free(EP93XX_GPIO_LINE_E(i));
+	for (i = 4; i < 8; i++)
+		gpio_free(EP93XX_GPIO_LINE_G(i));
+	for (i = 0; i < 8; i++)
+		gpio_free(EP93XX_GPIO_LINE_H(i));
+	gpio_free(EP93XX_GPIO_LINE_EGPIO15);
+	gpio_free(EP93XX_GPIO_LINE_EGPIO2);
+
+
+	/* GPIO ports E[7:2], G[7:4] and H used by GPIO */
+	ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_EONIDE |
+			       EP93XX_SYSCON_DEVCFG_GONIDE |
+			       EP93XX_SYSCON_DEVCFG_HONIDE);
+}
+EXPORT_SYMBOL(ep93xx_ide_release_gpio);
+
 void __init ep93xx_init_devices(void)
 {
 	/* Disallow access to MaverickCrunch initially */
diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
index d74c5cd..337ab7c 100644
--- a/arch/arm/mach-ep93xx/edb93xx.c
+++ b/arch/arm/mach-ep93xx/edb93xx.c
@@ -91,8 +91,8 @@ static void __init edb93xx_register_i2c(void)
 		ep93xx_register_i2c(&edb93xx_i2c_gpio_data,
 				    edb93xxa_i2c_board_info,
 				    ARRAY_SIZE(edb93xxa_i2c_board_info));
-	} else if (machine_is_edb9307() || machine_is_edb9312() ||
-		   machine_is_edb9315()) {
+	} else if (machine_is_edb9302() || machine_is_edb9307()
+		|| machine_is_edb9312() || machine_is_edb9315()) {
 		ep93xx_register_i2c(&edb93xx_i2c_gpio_data,
 				    edb93xx_i2c_board_info,
 				    ARRAY_SIZE(edb93xx_i2c_board_info));
@@ -233,6 +233,29 @@ static void __init edb93xx_register_fb(void)
 }
 
 
+/*************************************************************************
+ * EDB93xx IDE
+ *************************************************************************/
+static int __init edb93xx_has_ide(void)
+{
+	/*
+	 * Although EDB9312 and EDB9315 do have IDE capability, they have
+	 * INTRQ line wired as pull-up, which makes using IDE interface
+	 * problematic.
+	 */
+	return machine_is_edb9312() || machine_is_edb9315() ||
+	       machine_is_edb9315a();
+}
+
+static void __init edb93xx_register_ide(void)
+{
+	if (!edb93xx_has_ide())
+		return;
+
+	ep93xx_register_ide();
+}
+
+
 static void __init edb93xx_init_machine(void)
 {
 	ep93xx_init_devices();
@@ -243,6 +266,7 @@ static void __init edb93xx_init_machine(void)
 	edb93xx_register_i2s();
 	edb93xx_register_pwm();
 	edb93xx_register_fb();
+	edb93xx_register_ide();
 }
 
 
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index 1ecb040..33a5122 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -48,6 +48,9 @@ void ep93xx_register_i2s(void);
 int ep93xx_i2s_acquire(void);
 void ep93xx_i2s_release(void);
 void ep93xx_register_ac97(void);
+void ep93xx_register_ide(void);
+int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
+void ep93xx_ide_release_gpio(struct platform_device *pdev);
 
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;
diff --git a/arch/arm/mach-ep93xx/soc.h b/arch/arm/mach-ep93xx/soc.h
index 979fba7..7bf7ff8 100644
--- a/arch/arm/mach-ep93xx/soc.h
+++ b/arch/arm/mach-ep93xx/soc.h
@@ -69,6 +69,7 @@
 
 #define EP93XX_BOOT_ROM_BASE		EP93XX_AHB_IOMEM(0x00090000)
 
+#define EP93XX_IDE_PHYS_BASE		EP93XX_AHB_PHYS(0x000a0000)
 #define EP93XX_IDE_BASE			EP93XX_AHB_IOMEM(0x000a0000)
 
 #define EP93XX_VIC1_BASE		EP93XX_AHB_IOMEM(0x000b0000)
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 573be57..f5fb6ea 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -207,6 +207,7 @@ config MACH_SMDKV310
 	select S3C_DEV_HSMMC1
 	select S3C_DEV_HSMMC2
 	select S3C_DEV_HSMMC3
+	select S3C_DEV_USB_HSOTG
 	select SAMSUNG_DEV_BACKLIGHT
 	select EXYNOS_DEV_DRM
 	select EXYNOS_DEV_SYSMMU
@@ -326,6 +327,7 @@ config MACH_ORIGEN
 	select S3C_DEV_WDT
 	select S3C_DEV_HSMMC
 	select S3C_DEV_HSMMC2
+	select S3C_DEV_USB_HSOTG
 	select S5P_DEV_FIMC0
 	select S5P_DEV_FIMC1
 	select S5P_DEV_FIMC2
diff --git a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
index c337cf3..0727773 100644
--- a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
+++ b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
@@ -35,11 +35,21 @@
 #define PHY1_COMMON_ON_N		(1 << 7)
 #define PHY0_COMMON_ON_N		(1 << 4)
 #define PHY0_ID_PULLUP			(1 << 2)
-#define CLKSEL_MASK			(0x3 << 0)
-#define CLKSEL_SHIFT			(0)
-#define CLKSEL_48M			(0x0 << 0)
-#define CLKSEL_12M			(0x2 << 0)
-#define CLKSEL_24M			(0x3 << 0)
+
+#define EXYNOS4_CLKSEL_SHIFT		(0)
+
+#define EXYNOS4210_CLKSEL_MASK		(0x3 << 0)
+#define EXYNOS4210_CLKSEL_48M		(0x0 << 0)
+#define EXYNOS4210_CLKSEL_12M		(0x2 << 0)
+#define EXYNOS4210_CLKSEL_24M		(0x3 << 0)
+
+#define EXYNOS4X12_CLKSEL_MASK		(0x7 << 0)
+#define EXYNOS4X12_CLKSEL_9600K		(0x0 << 0)
+#define EXYNOS4X12_CLKSEL_10M		(0x1 << 0)
+#define EXYNOS4X12_CLKSEL_12M		(0x2 << 0)
+#define EXYNOS4X12_CLKSEL_19200K	(0x3 << 0)
+#define EXYNOS4X12_CLKSEL_20M		(0x4 << 0)
+#define EXYNOS4X12_CLKSEL_24M		(0x5 << 0)
 
 #define EXYNOS4_RSTCON			EXYNOS4_HSOTG_PHYREG(0x08)
 #define HOST_LINK_PORT_SWRST_MASK	(0xf << 6)
diff --git a/arch/arm/mach-exynos/include/mach/spi-clocks.h b/arch/arm/mach-exynos/include/mach/spi-clocks.h
deleted file mode 100644
index c71a5fb..0000000
--- a/arch/arm/mach-exynos/include/mach/spi-clocks.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* linux/arch/arm/mach-exynos4/include/mach/spi-clocks.h
- *
- * Copyright (C) 2011 Samsung Electronics Co. Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_SPI_CLKS_H
-#define __ASM_ARCH_SPI_CLKS_H __FILE__
-
-/* Must source from SCLK_SPI */
-#define EXYNOS_SPI_SRCCLK_SCLK		0
-
-#endif /* __ASM_ARCH_SPI_CLKS_H */
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index f5572be..9ed0229 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -21,6 +21,7 @@
 #include <linux/mfd/max8997.h>
 #include <linux/lcd.h>
 #include <linux/rfkill-gpio.h>
+#include <linux/platform_data/s3c-hsotg.h>
 
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
@@ -499,6 +500,9 @@ static void __init origen_ohci_init(void)
 	exynos4_ohci_set_platdata(pdata);
 }
 
+/* USB OTG */
+static struct s3c_hsotg_plat origen_hsotg_pdata;
+
 static struct gpio_keys_button origen_gpio_keys_table[] = {
 	{
 		.code			= KEY_MENU,
@@ -655,6 +659,7 @@ static struct platform_device *origen_devices[] __initdata = {
 	&s3c_device_hsmmc0,
 	&s3c_device_i2c0,
 	&s3c_device_rtc,
+	&s3c_device_usb_hsotg,
 	&s3c_device_wdt,
 	&s5p_device_ehci,
 	&s5p_device_fimc0,
@@ -744,6 +749,7 @@ static void __init origen_machine_init(void)
 
 	origen_ehci_init();
 	origen_ohci_init();
+	s3c_hsotg_set_platdata(&origen_hsotg_pdata);
 	clk_xusbxti.rate = 24000000;
 
 	s5p_tv_setup();
diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c
index fb09c70..e134c95 100644
--- a/arch/arm/mach-exynos/mach-smdk4x12.c
+++ b/arch/arm/mach-exynos/mach-smdk4x12.c
@@ -219,8 +219,10 @@ static struct platform_pwm_backlight_data smdk4x12_bl_data = {
 
 static uint32_t smdk4x12_keymap[] __initdata = {
 	/* KEY(row, col, keycode) */
-	KEY(1, 0, KEY_D), KEY(1, 1, KEY_A), KEY(1, 2, KEY_B),
-	KEY(1, 3, KEY_E), KEY(1, 4, KEY_C)
+	KEY(1, 3, KEY_1), KEY(1, 4, KEY_2), KEY(1, 5, KEY_3),
+	KEY(1, 6, KEY_4), KEY(1, 7, KEY_5),
+	KEY(2, 5, KEY_D), KEY(2, 6, KEY_A), KEY(2, 7, KEY_B),
+	KEY(0, 7, KEY_E), KEY(0, 5, KEY_C)
 };
 
 static struct matrix_keymap_data smdk4x12_keymap_data __initdata = {
@@ -230,8 +232,8 @@ static struct matrix_keymap_data smdk4x12_keymap_data __initdata = {
 
 static struct samsung_keypad_platdata smdk4x12_keypad_data __initdata = {
 	.keymap_data	= &smdk4x12_keymap_data,
-	.rows		= 2,
-	.cols		= 5,
+	.rows		= 3,
+	.cols		= 8,
 };
 
 static struct platform_device *smdk4x12_devices[] __initdata = {
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index 262e9e4..7b1b866 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -19,6 +19,7 @@
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/pwm_backlight.h>
+#include <linux/platform_data/s3c-hsotg.h>
 
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
@@ -271,6 +272,9 @@ static void __init smdkv310_ohci_init(void)
 	exynos4_ohci_set_platdata(pdata);
 }
 
+/* USB OTG */
+static struct s3c_hsotg_plat smdkv310_hsotg_pdata;
+
 static struct platform_device *smdkv310_devices[] __initdata = {
 	&s3c_device_hsmmc0,
 	&s3c_device_hsmmc1,
@@ -279,6 +283,7 @@ static struct platform_device *smdkv310_devices[] __initdata = {
 	&s3c_device_i2c1,
 	&s5p_device_i2c_hdmiphy,
 	&s3c_device_rtc,
+	&s3c_device_usb_hsotg,
 	&s3c_device_wdt,
 	&s5p_device_ehci,
 	&s5p_device_fimc0,
@@ -390,6 +395,7 @@ static void __init smdkv310_machine_init(void)
 
 	smdkv310_ehci_init();
 	smdkv310_ohci_init();
+	s3c_hsotg_set_platdata(&smdkv310_hsotg_pdata);
 	clk_xusbxti.rate = 24000000;
 
 	platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices));
diff --git a/arch/arm/mach-exynos/setup-usb-phy.c b/arch/arm/mach-exynos/setup-usb-phy.c
index 1af0a7f..d26deb7 100644
--- a/arch/arm/mach-exynos/setup-usb-phy.c
+++ b/arch/arm/mach-exynos/setup-usb-phy.c
@@ -31,22 +31,51 @@ static void exynos4210_usb_phy_clkset(struct platform_device *pdev)
 	struct clk *xusbxti_clk;
 	u32 phyclk;
 
-	/* set clock frequency for PLL */
-	phyclk = readl(EXYNOS4_PHYCLK) & ~CLKSEL_MASK;
 
 	xusbxti_clk = clk_get(&pdev->dev, "xusbxti");
 	if (xusbxti_clk && !IS_ERR(xusbxti_clk)) {
-		switch (clk_get_rate(xusbxti_clk)) {
-		case 12 * MHZ:
-			phyclk |= CLKSEL_12M;
-			break;
-		case 24 * MHZ:
-			phyclk |= CLKSEL_24M;
-			break;
-		default:
-		case 48 * MHZ:
-			/* default reference clock */
-			break;
+		if (soc_is_exynos4210()) {
+			/* set clock frequency for PLL */
+			phyclk = readl(EXYNOS4_PHYCLK) & ~EXYNOS4210_CLKSEL_MASK;
+
+			switch (clk_get_rate(xusbxti_clk)) {
+			case 12 * MHZ:
+				phyclk |= EXYNOS4210_CLKSEL_12M;
+				break;
+			default:
+			case 24 * MHZ:
+				phyclk |= EXYNOS4210_CLKSEL_24M;
+				break;
+			case 48 * MHZ:
+				phyclk |= EXYNOS4210_CLKSEL_48M;
+				break;
+			}
+		} else if (soc_is_exynos4212() || soc_is_exynos4412()) {
+			/* set clock frequency for PLL */
+			phyclk = readl(EXYNOS4_PHYCLK) & ~EXYNOS4X12_CLKSEL_MASK;
+
+			switch (clk_get_rate(xusbxti_clk)) {
+			case 9600 * KHZ:
+				phyclk |= EXYNOS4X12_CLKSEL_9600K;
+				break;
+			case 10 * MHZ:
+				phyclk |= EXYNOS4X12_CLKSEL_10M;
+				break;
+			case 12 * MHZ:
+				phyclk |= EXYNOS4X12_CLKSEL_12M;
+				break;
+			case 19200 * KHZ:
+				phyclk |= EXYNOS4X12_CLKSEL_19200K;
+				break;
+			case 20 * MHZ:
+				phyclk |= EXYNOS4X12_CLKSEL_20M;
+				break;
+			default:
+			case 24 * MHZ:
+				/* default reference clock */
+				phyclk |= EXYNOS4X12_CLKSEL_24M;
+				break;
+			}
 		}
 		clk_put(xusbxti_clk);
 	}
diff --git a/arch/arm/mach-footbridge/Makefile b/arch/arm/mach-footbridge/Makefile
index 3afb1b2..0b64dd4 100644
--- a/arch/arm/mach-footbridge/Makefile
+++ b/arch/arm/mach-footbridge/Makefile
@@ -14,15 +14,11 @@ pci-$(CONFIG_ARCH_EBSA285_HOST) += ebsa285-pci.o
 pci-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o
 pci-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o
 
-leds-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o
-leds-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o
-
 obj-$(CONFIG_ARCH_CATS) += cats-hw.o isa-timer.o
 obj-$(CONFIG_ARCH_EBSA285) += ebsa285.o dc21285-timer.o
 obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o isa-timer.o
 obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal.o dc21285-timer.o
 
 obj-$(CONFIG_PCI)	+=$(pci-y)
-obj-$(CONFIG_LEDS)	+=$(leds-y)
 
 obj-$(CONFIG_ISA)	+= isa.o isa-rtc.o
diff --git a/arch/arm/mach-footbridge/ebsa285-leds.c b/arch/arm/mach-footbridge/ebsa285-leds.c
deleted file mode 100644
index 5bd2667..0000000
--- a/arch/arm/mach-footbridge/ebsa285-leds.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- *  linux/arch/arm/mach-footbridge/ebsa285-leds.c
- *
- *  Copyright (C) 1998-1999 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- * EBSA-285 control routines.
- *
- * The EBSA-285 uses the leds as follows:
- *  - Green - toggles state every 50 timer interrupts
- *  - Amber - On if system is not idle
- *  - Red   - currently unused
- *
- * Changelog:
- *   02-05-1999	RMK	Various cleanups
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-static char led_state;
-static char hw_led_state;
-
-static DEFINE_SPINLOCK(leds_lock);
-
-static void ebsa285_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&leds_lock, flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN;
-#ifndef CONFIG_LEDS_CPU
-		hw_led_state |= XBUS_LED_AMBER;
-#endif
-		led_state |= LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= XBUS_LED_GREEN;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= XBUS_LED_AMBER;
-		break;
-
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~XBUS_LED_AMBER;
-		break;
-#endif
-
-	case led_halted:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~XBUS_LED_RED;
-		break;
-
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~XBUS_LED_GREEN;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= XBUS_LED_GREEN;
-		break;
-
-	case led_amber_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~XBUS_LED_AMBER;
-		break;
-
-	case led_amber_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= XBUS_LED_AMBER;
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~XBUS_LED_RED;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= XBUS_LED_RED;
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED)
-		*XBUS_LEDS = hw_led_state;
-
-	spin_unlock_irqrestore(&leds_lock, flags);
-}
-
-static int __init leds_init(void)
-{
-	if (machine_is_ebsa285())
-		leds_event = ebsa285_leds_event;
-
-	leds_event(led_start);
-
-	return 0;
-}
-
-__initcall(leds_init);
diff --git a/arch/arm/mach-footbridge/ebsa285.c b/arch/arm/mach-footbridge/ebsa285.c
index 27716a7..b09551e 100644
--- a/arch/arm/mach-footbridge/ebsa285.c
+++ b/arch/arm/mach-footbridge/ebsa285.c
@@ -5,6 +5,8 @@
  */
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <asm/hardware/dec21285.h>
 #include <asm/mach-types.h>
@@ -13,6 +15,85 @@
 
 #include "common.h"
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct ebsa285_led {
+	struct led_classdev     cdev;
+	u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} ebsa285_leds[] = {
+	{ "ebsa285:amber", "heartbeat", },
+	{ "ebsa285:green", "cpu0", },
+	{ "ebsa285:red",},
+};
+
+static void ebsa285_led_set(struct led_classdev *cdev,
+		enum led_brightness b)
+{
+	struct ebsa285_led *led = container_of(cdev,
+			struct ebsa285_led, cdev);
+
+	if (b != LED_OFF)
+		*XBUS_LEDS |= led->mask;
+	else
+		*XBUS_LEDS &= ~led->mask;
+}
+
+static enum led_brightness ebsa285_led_get(struct led_classdev *cdev)
+{
+	struct ebsa285_led *led = container_of(cdev,
+			struct ebsa285_led, cdev);
+
+	return (*XBUS_LEDS & led->mask) ? LED_FULL : LED_OFF;
+}
+
+static int __init ebsa285_leds_init(void)
+{
+	int i;
+
+	if (machine_is_ebsa285())
+		return -ENODEV;
+
+	/* 3 LEDS All ON */
+	*XBUS_LEDS |= XBUS_LED_AMBER | XBUS_LED_GREEN | XBUS_LED_RED;
+
+	for (i = 0; i < ARRAY_SIZE(ebsa285_leds); i++) {
+		struct ebsa285_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = ebsa285_leds[i].name;
+		led->cdev.brightness_set = ebsa285_led_set;
+		led->cdev.brightness_get = ebsa285_led_get;
+		led->cdev.default_trigger = ebsa285_leds[i].trigger;
+		led->mask = BIT(i);
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(ebsa285_leds_init);
+#endif
+
 MACHINE_START(EBSA285, "EBSA285")
 	/* Maintainer: Russell King */
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index cac9f67..d2d1433 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -12,9 +12,10 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <asm/hardware/dec21285.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
 #include <asm/system_misc.h>
@@ -27,13 +28,6 @@
 #define GP1_IO_BASE		0x338
 #define GP2_IO_BASE		0x33a
 
-
-#ifdef CONFIG_LEDS
-#define DEFAULT_LEDS	0
-#else
-#define DEFAULT_LEDS	GPIO_GREEN_LED
-#endif
-
 /*
  * Winbond WB83977F accessibility stuff
  */
@@ -611,15 +605,9 @@ static void __init rwa010_init(void)
 static int __init nw_hw_init(void)
 {
 	if (machine_is_netwinder()) {
-		unsigned long flags;
-
 		wb977_init();
 		cpld_init();
 		rwa010_init();
-
-		raw_spin_lock_irqsave(&nw_gpio_lock, flags);
-		nw_gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS);
-		raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
 	}
 	return 0;
 }
@@ -672,6 +660,102 @@ static void netwinder_restart(char mode, const char *cmd)
 	}
 }
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct netwinder_led {
+	struct led_classdev     cdev;
+	u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} netwinder_leds[] = {
+	{ "netwinder:green", "heartbeat", },
+	{ "netwinder:red", "cpu0", },
+};
+
+/*
+ * The LED control in Netwinder is reversed:
+ *  - setting bit means turn off LED
+ *  - clearing bit means turn on LED
+ */
+static void netwinder_led_set(struct led_classdev *cdev,
+		enum led_brightness b)
+{
+	struct netwinder_led *led = container_of(cdev,
+			struct netwinder_led, cdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&nw_gpio_lock, flags);
+	reg = nw_gpio_read();
+	if (b != LED_OFF)
+		reg &= ~led->mask;
+	else
+		reg |= led->mask;
+	nw_gpio_modify_op(led->mask, reg);
+	spin_unlock_irqrestore(&nw_gpio_lock, flags);
+}
+
+static enum led_brightness netwinder_led_get(struct led_classdev *cdev)
+{
+	struct netwinder_led *led = container_of(cdev,
+			struct netwinder_led, cdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&nw_gpio_lock, flags);
+	reg = nw_gpio_read();
+	spin_unlock_irqrestore(&nw_gpio_lock, flags);
+
+	return (reg & led->mask) ? LED_OFF : LED_FULL;
+}
+
+static int __init netwinder_leds_init(void)
+{
+	int i;
+
+	if (!machine_is_netwinder())
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(netwinder_leds); i++) {
+		struct netwinder_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = netwinder_leds[i].name;
+		led->cdev.brightness_set = netwinder_led_set;
+		led->cdev.brightness_get = netwinder_led_get;
+		led->cdev.default_trigger = netwinder_leds[i].trigger;
+
+		if (i == 0)
+			led->mask = GPIO_GREEN_LED;
+		else
+			led->mask = GPIO_RED_LED;
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(netwinder_leds_init);
+#endif
+
 MACHINE_START(NETWINDER, "Rebel-NetWinder")
 	/* Maintainer: Russell King/Rebel.com */
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-footbridge/netwinder-leds.c b/arch/arm/mach-footbridge/netwinder-leds.c
deleted file mode 100644
index 5a2bd89..0000000
--- a/arch/arm/mach-footbridge/netwinder-leds.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- *  linux/arch/arm/mach-footbridge/netwinder-leds.c
- *
- *  Copyright (C) 1998-1999 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * NetWinder LED control routines.
- *
- * The Netwinder uses the leds as follows:
- *  - Green - toggles state every 50 timer interrupts
- *  - Red   - On if the system is not idle
- *
- * Changelog:
- *   02-05-1999	RMK	Various cleanups
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-static char led_state;
-static char hw_led_state;
-
-static DEFINE_RAW_SPINLOCK(leds_lock);
-
-static void netwinder_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&leds_lock, flags);
-
-	switch (evt) {
-	case led_start:
-		led_state |= LED_STATE_ENABLED;
-		hw_led_state = GPIO_GREEN_LED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= GPIO_GREEN_LED;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~GPIO_RED_LED;
-		break;
-
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= GPIO_RED_LED;
-		break;
-#endif
-
-	case led_halted:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= GPIO_RED_LED;
-		break;
-
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= GPIO_GREEN_LED;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~GPIO_GREEN_LED;
-		break;
-
-	case led_amber_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= GPIO_GREEN_LED | GPIO_RED_LED;
-		break;
-
-	case led_amber_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~(GPIO_GREEN_LED | GPIO_RED_LED);
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= GPIO_RED_LED;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~GPIO_RED_LED;
-		break;
-
-	default:
-		break;
-	}
-
-	raw_spin_unlock_irqrestore(&leds_lock, flags);
-
-	if  (led_state & LED_STATE_ENABLED) {
-		raw_spin_lock_irqsave(&nw_gpio_lock, flags);
-		nw_gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state);
-		raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
-	}
-}
-
-static int __init leds_init(void)
-{
-	if (machine_is_netwinder())
-		leds_event = netwinder_leds_event;
-
-	leds_event(led_start);
-
-	return 0;
-}
-
-__initcall(leds_init);
diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c
index a2200c7..20964ce 100644
--- a/arch/arm/mach-imx/clk-imx51-imx53.c
+++ b/arch/arm/mach-imx/clk-imx51-imx53.c
@@ -357,6 +357,7 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
 	clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "83fcc000.ssi");
 	clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "70014000.ssi");
 	clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "83fe8000.ssi");
+	clk_register_clkdev(clk[nfc_gate], NULL, "83fdb000.nand");
 
 	/* set the usboh3 parent to pll2_sw */
 	clk_set_parent(clk[usboh3_sel], clk[pll2_sw]);
@@ -445,6 +446,7 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
 	clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "63fcc000.ssi");
 	clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "50014000.ssi");
 	clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "63fd0000.ssi");
+	clk_register_clkdev(clk[nfc_gate], NULL, "63fdb000.nand");
 
 	/* set SDHC root clock to 200MHZ*/
 	clk_set_rate(clk[esdhc_a_podf], 200000000);
diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile
index ebeef96..5521d18 100644
--- a/arch/arm/mach-integrator/Makefile
+++ b/arch/arm/mach-integrator/Makefile
@@ -4,11 +4,10 @@
 
 # Object file lists.
 
-obj-y					:= core.o lm.o
+obj-y					:= core.o lm.o leds.o
 obj-$(CONFIG_ARCH_INTEGRATOR_AP)	+= integrator_ap.o
 obj-$(CONFIG_ARCH_INTEGRATOR_CP)	+= integrator_cp.o
 
-obj-$(CONFIG_LEDS)			+= leds.o
 obj-$(CONFIG_PCI)			+= pci_v3.o pci.o
 obj-$(CONFIG_CPU_FREQ_INTEGRATOR)	+= cpu.o
 obj-$(CONFIG_INTEGRATOR_IMPD1)		+= impd1.o
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index eaf6c63..0c7c4ef 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -28,7 +28,6 @@
 #include <mach/cm.h>
 #include <mach/irqs.h>
 
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/mach/time.h>
 #include <asm/pgtable.h>
@@ -172,8 +171,6 @@ static struct amba_pl010_data integrator_uart_data = {
 	.set_mctrl = integrator_uart_set_mctrl,
 };
 
-#define CM_CTRL	IO_ADDRESS(INTEGRATOR_HDR_CTRL)
-
 static DEFINE_RAW_SPINLOCK(cm_lock);
 
 /**
diff --git a/arch/arm/mach-integrator/include/mach/cm.h b/arch/arm/mach-integrator/include/mach/cm.h
index 445d57a..1a78692e 100644
--- a/arch/arm/mach-integrator/include/mach/cm.h
+++ b/arch/arm/mach-integrator/include/mach/cm.h
@@ -3,6 +3,8 @@
  */
 void cm_control(u32, u32);
 
+#define CM_CTRL	IO_ADDRESS(INTEGRATOR_HDR_CTRL)
+
 #define CM_CTRL_LED			(1 << 0)
 #define CM_CTRL_nMBDET			(1 << 1)
 #define CM_CTRL_REMAP			(1 << 2)
diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c
index 466defa..7a7f6d3 100644
--- a/arch/arm/mach-integrator/leds.c
+++ b/arch/arm/mach-integrator/leds.c
@@ -1,90 +1,125 @@
 /*
- *  linux/arch/arm/mach-integrator/leds.c
+ * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard
+ * Based on Versatile and RealView machine LED code
  *
- *  Integrator/AP and Integrator/CP LED control routines
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Bryan Wu <bryan.wu@canonical.com>
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/spinlock.h>
 #include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
+#include <mach/cm.h>
 #include <mach/hardware.h>
 #include <mach/platform.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-#include <mach/cm.h>
 
-static int saved_leds;
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+
+#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE)
+#define LEDREG	(__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET)
 
-static void integrator_leds_event(led_event_t ledevt)
+struct integrator_led {
+	struct led_classdev	cdev;
+	u8			mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} integrator_leds[] = {
+	{ "integrator:green0", "heartbeat", },
+	{ "integrator:yellow", },
+	{ "integrator:red", },
+	{ "integrator:green1", },
+	{ "integrator:core_module", "cpu0", },
+};
+
+static void integrator_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
 {
-	unsigned long flags;
-	const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE);
-	unsigned int update_alpha_leds;
+	struct integrator_led *led = container_of(cdev,
+						 struct integrator_led, cdev);
+	u32 reg = __raw_readl(LEDREG);
 
-	// yup, change the LEDs
-	local_irq_save(flags);
-	update_alpha_leds = 0;
+	if (b != LED_OFF)
+		reg |= led->mask;
+	else
+		reg &= ~led->mask;
 
-	switch(ledevt) {
-	case led_idle_start:
-		cm_control(CM_CTRL_LED, 0);
-		break;
+	while (__raw_readl(ALPHA_REG) & 1)
+		cpu_relax();
 
-	case led_idle_end:
-		cm_control(CM_CTRL_LED, CM_CTRL_LED);
-		break;
+	__raw_writel(reg, LEDREG);
+}
 
-	case led_timer:
-		saved_leds ^= GREEN_LED;
-		update_alpha_leds = 1;
-		break;
+static enum led_brightness integrator_led_get(struct led_classdev *cdev)
+{
+	struct integrator_led *led = container_of(cdev,
+						 struct integrator_led, cdev);
+	u32 reg = __raw_readl(LEDREG);
 
-	case led_red_on:
-		saved_leds |= RED_LED;
-		update_alpha_leds = 1;
-		break;
+	return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
 
-	case led_red_off:
-		saved_leds &= ~RED_LED;
-		update_alpha_leds = 1;
-		break;
+static void cm_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
+{
+	if (b != LED_OFF)
+		cm_control(CM_CTRL_LED, CM_CTRL_LED);
+	else
+		cm_control(CM_CTRL_LED, 0);
+}
 
-	default:
-		break;
-	}
+static enum led_brightness cm_led_get(struct led_classdev *cdev)
+{
+	u32 reg = readl(CM_CTRL);
 
-	if (update_alpha_leds) {
-		while (__raw_readl(dbg_base + INTEGRATOR_DBG_ALPHA_OFFSET) & 1);
-		__raw_writel(saved_leds, dbg_base + INTEGRATOR_DBG_LEDS_OFFSET);
-	}
-	local_irq_restore(flags);
+	return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF;
 }
 
-static int __init leds_init(void)
+static int __init integrator_leds_init(void)
 {
-	if (machine_is_integrator() || machine_is_cintegrator())
-		leds_event = integrator_leds_event;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) {
+		struct integrator_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+
+		led->cdev.name = integrator_leds[i].name;
+
+		if (i == 4) { /* Setting for LED in core module */
+			led->cdev.brightness_set = cm_led_set;
+			led->cdev.brightness_get = cm_led_get;
+		} else {
+			led->cdev.brightness_set = integrator_led_set;
+			led->cdev.brightness_get = integrator_led_get;
+		}
+
+		led->cdev.default_trigger = integrator_leds[i].trigger;
+		led->mask = BIT(i);
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
 
 	return 0;
 }
 
-core_initcall(leds_init);
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(integrator_leds_init);
+#endif
diff --git a/arch/arm/mach-ks8695/Makefile b/arch/arm/mach-ks8695/Makefile
index 853efd9..9324ef9 100644
--- a/arch/arm/mach-ks8695/Makefile
+++ b/arch/arm/mach-ks8695/Makefile
@@ -11,9 +11,6 @@ obj-				:=
 # PCI support is optional
 obj-$(CONFIG_PCI)		+= pci.o
 
-# LEDs
-obj-$(CONFIG_LEDS)		+= leds.o
-
 # Board-specific support
 obj-$(CONFIG_MACH_KS8695)	+= board-micrel.o
 obj-$(CONFIG_MACH_DSM320)	+= board-dsm320.o
diff --git a/arch/arm/mach-ks8695/devices.c b/arch/arm/mach-ks8695/devices.c
index 73bd638..47399bc 100644
--- a/arch/arm/mach-ks8695/devices.c
+++ b/arch/arm/mach-ks8695/devices.c
@@ -182,27 +182,6 @@ static void __init ks8695_add_device_watchdog(void)
 }
 
 
-/* --------------------------------------------------------------------
- *  LEDs
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_LEDS)
-short ks8695_leds_cpu = -1;
-short ks8695_leds_timer = -1;
-
-void __init ks8695_init_leds(u8 cpu_led, u8 timer_led)
-{
-	/* Enable GPIO to access the LEDs */
-	gpio_direction_output(cpu_led, 1);
-	gpio_direction_output(timer_led, 1);
-
-	ks8695_leds_cpu	  = cpu_led;
-	ks8695_leds_timer = timer_led;
-}
-#else
-void __init ks8695_init_leds(u8 cpu_led, u8 timer_led) {}
-#endif
-
 /* -------------------------------------------------------------------- */
 
 /*
diff --git a/arch/arm/mach-ks8695/include/mach/devices.h b/arch/arm/mach-ks8695/include/mach/devices.h
index 85a3c9a..1e6594a 100644
--- a/arch/arm/mach-ks8695/include/mach/devices.h
+++ b/arch/arm/mach-ks8695/include/mach/devices.h
@@ -18,11 +18,6 @@ extern void __init ks8695_add_device_wan(void);
 extern void __init ks8695_add_device_lan(void);
 extern void __init ks8695_add_device_hpna(void);
 
- /* LEDs */
-extern short ks8695_leds_cpu;
-extern short ks8695_leds_timer;
-extern void __init ks8695_init_leds(u8 cpu_led, u8 timer_led);
-
  /* PCI */
 #define KS8695_MODE_PCI		0
 #define KS8695_MODE_MINIPCI	1
diff --git a/arch/arm/mach-ks8695/leds.c b/arch/arm/mach-ks8695/leds.c
deleted file mode 100644
index 4bd7075..0000000
--- a/arch/arm/mach-ks8695/leds.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * LED driver for KS8695-based boards.
- *
- * Copyright (C) Andrew Victor
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/gpio.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <mach/devices.h>
-
-
-static inline void ks8695_led_on(unsigned int led)
-{
-	gpio_set_value(led, 0);
-}
-
-static inline void ks8695_led_off(unsigned int led)
-{
-	gpio_set_value(led, 1);
-}
-
-static inline void ks8695_led_toggle(unsigned int led)
-{
-	unsigned long is_off = gpio_get_value(led);
-	if (is_off)
-		ks8695_led_on(led);
-	else
-		ks8695_led_off(led);
-}
-
-
-/*
- * Handle LED events.
- */
-static void ks8695_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch(evt) {
-	case led_start:		/* System startup */
-		ks8695_led_on(ks8695_leds_cpu);
-		break;
-
-	case led_stop:		/* System stop / suspend */
-		ks8695_led_off(ks8695_leds_cpu);
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:		/* Every 50 timer ticks */
-		ks8695_led_toggle(ks8695_leds_timer);
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:	/* Entering idle state */
-		ks8695_led_off(ks8695_leds_cpu);
-		break;
-
-	case led_idle_end:	/* Exit idle state */
-		ks8695_led_on(ks8695_leds_cpu);
-		break;
-#endif
-
-	default:
-		break;
-	}
-
-	local_irq_restore(flags);
-}
-
-
-static int __init leds_init(void)
-{
-	if ((ks8695_leds_timer == -1) || (ks8695_leds_cpu == -1))
-		return -ENODEV;
-
-	leds_event = ks8695_leds_event;
-
-	leds_event(led_start);
-	return 0;
-}
-
-__initcall(leds_init);
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index db0117e..e012dc8 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -127,7 +127,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 	 * the boot monitor to read the system wide flags register,
 	 * and branch to the address found there.
 	 */
-	gic_raise_softirq(cpumask_of(cpu), 1);
+	gic_raise_softirq(cpumask_of(cpu), 0);
 
 	timeout = jiffies + (1 * HZ);
 	while (time_before(jiffies, timeout)) {
diff --git a/arch/arm/mach-nomadik/Makefile b/arch/arm/mach-nomadik/Makefile
index a6bbd1a..a42c9a3 100644
--- a/arch/arm/mach-nomadik/Makefile
+++ b/arch/arm/mach-nomadik/Makefile
@@ -7,8 +7,6 @@
 
 # Object file lists.
 
-obj-y			+= clock.o
-
 # Cpu revision
 obj-$(CONFIG_NOMADIK_8815) += cpu-8815.o
 
diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
index 2e8d3e1..f4535a7 100644
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -14,12 +14,14 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/amba/bus.h>
+#include <linux/amba/mmci.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/i2c.h>
 #include <linux/io.h>
 #include <asm/hardware/vic.h>
 #include <asm/sizes.h>
@@ -185,16 +187,28 @@ static void __init nhk8815_onenand_init(void)
 #endif
 }
 
-static AMBA_APB_DEVICE(uart0, "uart0", 0, NOMADIK_UART0_BASE,
-	{ IRQ_UART0 }, NULL);
+static struct mmci_platform_data mmcsd_plat_data = {
+	.ocr_mask = MMC_VDD_29_30,
+	.f_max = 48000000,
+	.gpio_wp = -1,
+	.gpio_cd = 111,
+	.cd_invert = true,
+	.capabilities = MMC_CAP_MMC_HIGHSPEED |
+	MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA,
+};
 
-static AMBA_APB_DEVICE(uart1, "uart1", 0, NOMADIK_UART1_BASE,
-	{ IRQ_UART1 }, NULL);
+static int __init nhk8815_mmcsd_init(void)
+{
+	int ret;
 
-static struct amba_device *amba_devs[] __initdata = {
-	&uart0_device,
-	&uart1_device,
-};
+	ret = gpio_request(112, "card detect bias");
+	if (ret)
+		return ret;
+	gpio_direction_output(112, 0);
+	amba_apb_device_add(NULL, "mmci", NOMADIK_SDI_BASE, SZ_4K, IRQ_SDMMC, 0, &mmcsd_plat_data, 0x10180180);
+	return 0;
+}
+module_init(nhk8815_mmcsd_init);
 
 static struct resource nhk8815_eth_resources[] = {
 	{
@@ -253,17 +267,46 @@ static struct sys_timer nomadik_timer = {
 	.init	= nomadik_timer_init,
 };
 
+static struct i2c_board_info __initdata nhk8815_i2c0_devices[] = {
+	{
+		I2C_BOARD_INFO("stw4811", 0x2d),
+	},
+};
+
+static struct i2c_board_info __initdata nhk8815_i2c1_devices[] = {
+	{
+		I2C_BOARD_INFO("camera", 0x10),
+	},
+	{
+		I2C_BOARD_INFO("stw5095", 0x1a),
+	},
+	{
+		I2C_BOARD_INFO("lis3lv02dl", 0x1d),
+	},
+};
+
+static struct i2c_board_info __initdata nhk8815_i2c2_devices[] = {
+	{
+		I2C_BOARD_INFO("stw4811-usb", 0x2d),
+	},
+};
+
 static void __init nhk8815_platform_init(void)
 {
-	int i;
-
 	cpu8815_platform_init();
 	nhk8815_onenand_init();
 	platform_add_devices(nhk8815_platform_devices,
 			     ARRAY_SIZE(nhk8815_platform_devices));
 
-	for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
-		amba_device_register(amba_devs[i], &iomem_resource);
+	amba_apb_device_add(NULL, "uart0", NOMADIK_UART0_BASE, SZ_4K, IRQ_UART0, 0, NULL, 0);
+	amba_apb_device_add(NULL, "uart1", NOMADIK_UART1_BASE, SZ_4K, IRQ_UART1, 0, NULL, 0);
+
+	i2c_register_board_info(0, nhk8815_i2c0_devices,
+				ARRAY_SIZE(nhk8815_i2c0_devices));
+	i2c_register_board_info(1, nhk8815_i2c1_devices,
+				ARRAY_SIZE(nhk8815_i2c1_devices));
+	i2c_register_board_info(2, nhk8815_i2c2_devices,
+				ARRAY_SIZE(nhk8815_i2c2_devices));
 }
 
 MACHINE_START(NOMADIK, "NHK8815")
diff --git a/arch/arm/mach-nomadik/clock.c b/arch/arm/mach-nomadik/clock.c
deleted file mode 100644
index 48a59f2..0000000
--- a/arch/arm/mach-nomadik/clock.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *  linux/arch/arm/mach-nomadik/clock.c
- *
- *  Copyright (C) 2009 Alessandro Rubini
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
-#include "clock.h"
-
-/*
- * The nomadik board uses generic clocks, but the serial pl011 file
- * calls clk_enable(), clk_disable(), clk_get_rate(), so we provide them
- */
-unsigned long clk_get_rate(struct clk *clk)
-{
-	return clk->rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-/* enable and disable do nothing */
-int clk_enable(struct clk *clk)
-{
-	return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_disable);
-
-static struct clk clk_24 = {
-	.rate = 2400000,
-};
-
-static struct clk clk_48 = {
-	.rate = 48 * 1000 * 1000,
-};
-
-/*
- * Catch-all default clock to satisfy drivers using the clk API.  We don't
- * model the actual hardware clocks yet.
- */
-static struct clk clk_default;
-
-#define CLK(_clk, dev)				\
-	{					\
-		.clk		= _clk,		\
-		.dev_id		= dev,		\
-	}
-
-static struct clk_lookup lookups[] = {
-	{
-		.con_id		= "apb_pclk",
-		.clk		= &clk_default,
-	},
-	CLK(&clk_24, "mtu0"),
-	CLK(&clk_24, "mtu1"),
-	CLK(&clk_48, "uart0"),
-	CLK(&clk_48, "uart1"),
-	CLK(&clk_default, "gpio.0"),
-	CLK(&clk_default, "gpio.1"),
-	CLK(&clk_default, "gpio.2"),
-	CLK(&clk_default, "gpio.3"),
-	CLK(&clk_default, "rng"),
-};
-
-int __init clk_init(void)
-{
-	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-	return 0;
-}
diff --git a/arch/arm/mach-nomadik/clock.h b/arch/arm/mach-nomadik/clock.h
deleted file mode 100644
index 78da2e7..0000000
--- a/arch/arm/mach-nomadik/clock.h
+++ /dev/null
@@ -1,15 +0,0 @@
-
-/*
- *  linux/arch/arm/mach-nomadik/clock.h
- *
- *  Copyright (C) 2009 Alessandro Rubini
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-struct clk {
-	unsigned long		rate;
-};
-
-int __init clk_init(void);
diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c
index 27f43a4..6fd8e46 100644
--- a/arch/arm/mach-nomadik/cpu-8815.c
+++ b/arch/arm/mach-nomadik/cpu-8815.c
@@ -22,6 +22,10 @@
 #include <linux/amba/bus.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/clk-nomadik.h>
 
 #include <plat/gpio-nomadik.h>
 #include <mach/hardware.h>
@@ -32,91 +36,63 @@
 #include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
 
-#include "clock.h"
 #include "cpu-8815.h"
 
-#define __MEM_4K_RESOURCE(x) \
-	.res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
-
 /* The 8815 has 4 GPIO blocks, let's register them immediately */
-
-#define GPIO_RESOURCE(block)						\
-	{								\
-		.start	= NOMADIK_GPIO##block##_BASE,			\
-		.end	= NOMADIK_GPIO##block##_BASE + SZ_4K - 1,	\
-		.flags	= IORESOURCE_MEM,				\
-	},								\
-	{								\
-		.start	= IRQ_GPIO##block,				\
-		.end	= IRQ_GPIO##block,				\
-		.flags	= IORESOURCE_IRQ,				\
-	}
-
-#define GPIO_DEVICE(block)						\
-	{								\
-		.name 		= "gpio",				\
-		.id		= block,				\
-		.num_resources 	= 2,					\
-		.resource	= &cpu8815_gpio_resources[block * 2],	\
-		.dev = {						\
-			.platform_data = &cpu8815_gpio[block],		\
-		},							\
-	}
-
-static struct nmk_gpio_platform_data cpu8815_gpio[] = {
-	{
-		.name = "GPIO-0-31",
-		.first_gpio = 0,
-		.first_irq = NOMADIK_GPIO_TO_IRQ(0),
-	}, {
-		.name = "GPIO-32-63",
-		.first_gpio = 32,
-		.first_irq = NOMADIK_GPIO_TO_IRQ(32),
-	}, {
-		.name = "GPIO-64-95",
-		.first_gpio = 64,
-		.first_irq = NOMADIK_GPIO_TO_IRQ(64),
-	}, {
-		.name = "GPIO-96-127", /* 124..127 not routed to pin */
-		.first_gpio = 96,
-		.first_irq = NOMADIK_GPIO_TO_IRQ(96),
-	}
+static resource_size_t __initdata cpu8815_gpio_base[] = {
+	NOMADIK_GPIO0_BASE,
+	NOMADIK_GPIO1_BASE,
+	NOMADIK_GPIO2_BASE,
+	NOMADIK_GPIO3_BASE,
 };
 
-static struct resource cpu8815_gpio_resources[] = {
-	GPIO_RESOURCE(0),
-	GPIO_RESOURCE(1),
-	GPIO_RESOURCE(2),
-	GPIO_RESOURCE(3),
-};
-
-static struct platform_device cpu8815_platform_gpio[] = {
-	GPIO_DEVICE(0),
-	GPIO_DEVICE(1),
-	GPIO_DEVICE(2),
-	GPIO_DEVICE(3),
-};
+static struct platform_device *
+cpu8815_add_gpio(int id, resource_size_t addr, int irq,
+		 struct nmk_gpio_platform_data *pdata)
+{
+	struct resource resources[] = {
+		{
+			.start	= addr,
+			.end	= addr + 127,
+			.flags	= IORESOURCE_MEM,
+		},
+		{
+			.start	= irq,
+			.end	= irq,
+			.flags	= IORESOURCE_IRQ,
+		}
+	};
+
+	return platform_device_register_resndata(NULL, "gpio", id,
+				resources, ARRAY_SIZE(resources),
+				pdata, sizeof(*pdata));
+}
 
-static AMBA_APB_DEVICE(cpu8815_amba_rng, "rng", 0, NOMADIK_RNG_BASE, { }, NULL);
+void cpu8815_add_gpios(resource_size_t *base, int num, int irq,
+		       struct nmk_gpio_platform_data *pdata)
+{
+	int first = 0;
+	int i;
 
-static struct platform_device *platform_devs[] __initdata = {
-	cpu8815_platform_gpio + 0,
-	cpu8815_platform_gpio + 1,
-	cpu8815_platform_gpio + 2,
-	cpu8815_platform_gpio + 3,
-};
+	for (i = 0; i < num; i++, first += 32, irq++) {
+		pdata->first_gpio = first;
+		pdata->first_irq = NOMADIK_GPIO_TO_IRQ(first);
+		pdata->num_gpio = 32;
 
-static struct amba_device *amba_devs[] __initdata = {
-	&cpu8815_amba_rng_device
-};
+		cpu8815_add_gpio(i, base[i], irq, pdata);
+	}
+}
 
 static int __init cpu8815_init(void)
 {
-	int i;
-
-	platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
-	for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
-		amba_device_register(amba_devs[i], &iomem_resource);
+	struct nmk_gpio_platform_data pdata = {
+		/* No custom data yet */
+	};
+
+	cpu8815_add_gpios(cpu8815_gpio_base, ARRAY_SIZE(cpu8815_gpio_base),
+			  IRQ_GPIO0, &pdata);
+	amba_apb_device_add(NULL, "rng", NOMADIK_RNG_BASE, SZ_4K, 0, 0, NULL, 0);
+	amba_apb_device_add(NULL, "rtc-pl031", NOMADIK_RTC_BASE, SZ_4K, IRQ_RTC_RTT, 0, NULL, 0);
 	return 0;
 }
 arch_initcall(cpu8815_init);
@@ -147,7 +123,7 @@ void __init cpu8815_init_irq(void)
 	 * Init clocks here so that they are available for system timer
 	 * initialization.
 	 */
-	clk_init();
+	nomadik_clk_init();
 }
 
 /*
diff --git a/arch/arm/mach-nomadik/i2c-8815nhk.c b/arch/arm/mach-nomadik/i2c-8815nhk.c
index 0fc2f6f..6d14454 100644
--- a/arch/arm/mach-nomadik/i2c-8815nhk.c
+++ b/arch/arm/mach-nomadik/i2c-8815nhk.c
@@ -5,6 +5,7 @@
 #include <linux/i2c-gpio.h>
 #include <linux/platform_device.h>
 #include <plat/gpio-nomadik.h>
+#include <plat/pincfg.h>
 
 /*
  * There are two busses in the 8815NHK.
@@ -12,19 +13,27 @@
  * use bit-bang through GPIO by now, to keep things simple
  */
 
+/* I2C0 connected to the STw4811 power management chip */
 static struct i2c_gpio_platform_data nhk8815_i2c_data0 = {
 	/* keep defaults for timeouts; pins are push-pull bidirectional */
 	.scl_pin = 62,
 	.sda_pin = 63,
 };
 
+/* I2C1 connected to various sensors */
 static struct i2c_gpio_platform_data nhk8815_i2c_data1 = {
 	/* keep defaults for timeouts; pins are push-pull bidirectional */
 	.scl_pin = 53,
 	.sda_pin = 54,
 };
 
-/* first bus: GPIO XX and YY */
+/* I2C2 connected to the USB portions of the STw4811 only */
+static struct i2c_gpio_platform_data nhk8815_i2c_data2 = {
+	/* keep defaults for timeouts; pins are push-pull bidirectional */
+	.scl_pin = 73,
+	.sda_pin = 74,
+};
+
 static struct platform_device nhk8815_i2c_dev0 = {
 	.name	= "i2c-gpio",
 	.id	= 0,
@@ -32,7 +41,7 @@ static struct platform_device nhk8815_i2c_dev0 = {
 		.platform_data = &nhk8815_i2c_data0,
 	},
 };
-/* second bus: GPIO XX and YY */
+
 static struct platform_device nhk8815_i2c_dev1 = {
 	.name	= "i2c-gpio",
 	.id	= 1,
@@ -41,15 +50,29 @@ static struct platform_device nhk8815_i2c_dev1 = {
 	},
 };
 
+static struct platform_device nhk8815_i2c_dev2 = {
+	.name	= "i2c-gpio",
+	.id	= 2,
+	.dev	= {
+		.platform_data = &nhk8815_i2c_data2,
+	},
+};
+
+static pin_cfg_t cpu8815_pins_i2c[] = {
+	PIN_CFG_INPUT(62, GPIO, PULLUP),
+	PIN_CFG_INPUT(63, GPIO, PULLUP),
+	PIN_CFG_INPUT(53, GPIO, PULLUP),
+	PIN_CFG_INPUT(54, GPIO, PULLUP),
+	PIN_CFG_INPUT(73, GPIO, PULLUP),
+	PIN_CFG_INPUT(74, GPIO, PULLUP),
+};
+
 static int __init nhk8815_i2c_init(void)
 {
-	nmk_gpio_set_mode(nhk8815_i2c_data0.scl_pin, NMK_GPIO_ALT_GPIO);
-	nmk_gpio_set_mode(nhk8815_i2c_data0.sda_pin, NMK_GPIO_ALT_GPIO);
+	nmk_config_pins(cpu8815_pins_i2c, ARRAY_SIZE(cpu8815_pins_i2c));
 	platform_device_register(&nhk8815_i2c_dev0);
-
-	nmk_gpio_set_mode(nhk8815_i2c_data1.scl_pin, NMK_GPIO_ALT_GPIO);
-	nmk_gpio_set_mode(nhk8815_i2c_data1.sda_pin, NMK_GPIO_ALT_GPIO);
 	platform_device_register(&nhk8815_i2c_dev1);
+	platform_device_register(&nhk8815_i2c_dev2);
 
 	return 0;
 }
@@ -58,6 +81,7 @@ static void __exit nhk8815_i2c_exit(void)
 {
 	platform_device_unregister(&nhk8815_i2c_dev0);
 	platform_device_unregister(&nhk8815_i2c_dev1);
+	platform_device_unregister(&nhk8815_i2c_dev2);
 	return;
 }
 
diff --git a/arch/arm/mach-nomadik/include/mach/irqs.h b/arch/arm/mach-nomadik/include/mach/irqs.h
index 8faabc5..a118e61 100644
--- a/arch/arm/mach-nomadik/include/mach/irqs.h
+++ b/arch/arm/mach-nomadik/include/mach/irqs.h
@@ -22,56 +22,56 @@
 
 #include <mach/hardware.h>
 
-#define IRQ_VIC_START		0	/* first VIC interrupt is 0 */
+#define IRQ_VIC_START		1	/* first VIC interrupt is 1 */
 
 /*
  * Interrupt numbers generic for all Nomadik Chip cuts
  */
-#define IRQ_WATCHDOG			0
-#define IRQ_SOFTINT			1
-#define IRQ_CRYPTO			2
-#define IRQ_OWM				3
-#define IRQ_MTU0			4
-#define IRQ_MTU1			5
-#define IRQ_GPIO0			6
-#define IRQ_GPIO1			7
-#define IRQ_GPIO2			8
-#define IRQ_GPIO3			9
-#define IRQ_RTC_RTT			10
-#define IRQ_SSP				11
-#define IRQ_UART0			12
-#define IRQ_DMA1			13
-#define IRQ_CLCD_MDIF			14
-#define IRQ_DMA0			15
-#define IRQ_PWRFAIL			16
-#define IRQ_UART1			17
-#define IRQ_FIRDA			18
-#define IRQ_MSP0			19
-#define IRQ_I2C0			20
-#define IRQ_I2C1			21
-#define IRQ_SDMMC			22
-#define IRQ_USBOTG			23
-#define IRQ_SVA_IT0			24
-#define IRQ_SVA_IT1			25
-#define IRQ_SAA_IT0			26
-#define IRQ_SAA_IT1			27
-#define IRQ_UART2			28
-#define IRQ_MSP2			31
-#define IRQ_L2CC			48
-#define IRQ_HPI				49
-#define IRQ_SKE				50
-#define IRQ_KP				51
-#define IRQ_MEMST			54
-#define IRQ_SGA_IT			58
-#define IRQ_USBM			60
-#define IRQ_MSP1			62
+#define IRQ_WATCHDOG			1
+#define IRQ_SOFTINT			2
+#define IRQ_CRYPTO			3
+#define IRQ_OWM				4
+#define IRQ_MTU0			5
+#define IRQ_MTU1			6
+#define IRQ_GPIO0			7
+#define IRQ_GPIO1			8
+#define IRQ_GPIO2			9
+#define IRQ_GPIO3			10
+#define IRQ_RTC_RTT			11
+#define IRQ_SSP				12
+#define IRQ_UART0			13
+#define IRQ_DMA1			14
+#define IRQ_CLCD_MDIF			15
+#define IRQ_DMA0			16
+#define IRQ_PWRFAIL			17
+#define IRQ_UART1			18
+#define IRQ_FIRDA			19
+#define IRQ_MSP0			20
+#define IRQ_I2C0			21
+#define IRQ_I2C1			22
+#define IRQ_SDMMC			23
+#define IRQ_USBOTG			24
+#define IRQ_SVA_IT0			25
+#define IRQ_SVA_IT1			26
+#define IRQ_SAA_IT0			27
+#define IRQ_SAA_IT1			28
+#define IRQ_UART2			29
+#define IRQ_MSP2			30
+#define IRQ_L2CC			49
+#define IRQ_HPI				50
+#define IRQ_SKE				51
+#define IRQ_KP				52
+#define IRQ_MEMST			55
+#define IRQ_SGA_IT			59
+#define IRQ_USBM			61
+#define IRQ_MSP1			63
 
-#define NOMADIK_SOC_NR_IRQS		64
+#define NOMADIK_GPIO_OFFSET		(IRQ_VIC_START+64)
 
 /* After chip-specific IRQ numbers we have the GPIO ones */
 #define NOMADIK_NR_GPIO			128 /* last 4 not wired to pins */
-#define NOMADIK_GPIO_TO_IRQ(gpio)	((gpio) + NOMADIK_SOC_NR_IRQS)
-#define NOMADIK_IRQ_TO_GPIO(irq)	((irq) - NOMADIK_SOC_NR_IRQS)
+#define NOMADIK_GPIO_TO_IRQ(gpio)	((gpio) + NOMADIK_GPIO_OFFSET)
+#define NOMADIK_IRQ_TO_GPIO(irq)	((irq) - NOMADIK_GPIO_OFFSET)
 #define NR_IRQS				NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
 
 /* Following two are used by entry_macro.S, to access our dual-vic */
@@ -79,4 +79,3 @@
 #define VIC_REG_IRQSR1		0x20
 
 #endif /* __ASM_ARCH_IRQS_H */
-
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 398e9e5..cd169c3 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -61,14 +61,6 @@ obj-$(CONFIG_ARCH_OMAP850)		+= gpio7xx.o
 obj-$(CONFIG_ARCH_OMAP15XX)		+= gpio15xx.o
 obj-$(CONFIG_ARCH_OMAP16XX)		+= gpio16xx.o
 
-# LEDs support
-led-$(CONFIG_MACH_OMAP_H2)		+= leds-h2p2-debug.o
-led-$(CONFIG_MACH_OMAP_H3)		+= leds-h2p2-debug.o
-led-$(CONFIG_MACH_OMAP_INNOVATOR)	+= leds-innovator.o
-led-$(CONFIG_MACH_OMAP_PERSEUS2)	+= leds-h2p2-debug.o
-led-$(CONFIG_MACH_OMAP_OSK)		+= leds-osk.o
-obj-$(CONFIG_LEDS)			+= $(led-y)
-
 ifneq ($(CONFIG_FB_OMAP),)
 obj-y += lcd_dma.o
 endif
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index a28e989..bf88046 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -31,6 +31,7 @@
 #include <linux/i2c/tps65010.h>
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
+#include <linux/leds.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -306,12 +307,39 @@ static struct platform_device h2_irda_device = {
 	.resource	= h2_irda_resources,
 };
 
+static struct gpio_led h2_gpio_led_pins[] = {
+	{
+		.name		= "h2:red",
+		.default_trigger = "heartbeat",
+		.gpio		= 3,
+	},
+	{
+		.name		= "h2:green",
+		.default_trigger = "cpu0",
+		.gpio		= OMAP_MPUIO(4),
+	},
+};
+
+static struct gpio_led_platform_data h2_gpio_led_data = {
+	.leds		= h2_gpio_led_pins,
+	.num_leds	= ARRAY_SIZE(h2_gpio_led_pins),
+};
+
+static struct platform_device h2_gpio_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &h2_gpio_led_data,
+	},
+};
+
 static struct platform_device *h2_devices[] __initdata = {
 	&h2_nor_device,
 	&h2_nand_device,
 	&h2_smc91x_device,
 	&h2_irda_device,
 	&h2_kp_device,
+	&h2_gpio_leds,
 };
 
 static void __init h2_init_smc91x(void)
@@ -406,6 +434,10 @@ static void __init h2_init(void)
 	omap_cfg_reg(E19_1610_KBR4);
 	omap_cfg_reg(N19_1610_KBR5);
 
+	/* GPIO based LEDs */
+	omap_cfg_reg(P18_1610_GPIO3);
+	omap_cfg_reg(MPUIO4);
+
 	h2_smc91x_resources[1].start = gpio_to_irq(0);
 	h2_smc91x_resources[1].end = gpio_to_irq(0);
 	platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 108a864..c6ec9b4 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -31,6 +31,7 @@
 #include <linux/i2c/tps65010.h>
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
+#include <linux/leds.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -324,6 +325,32 @@ static struct spi_board_info h3_spi_board_info[] __initdata = {
 	},
 };
 
+static struct gpio_led h3_gpio_led_pins[] = {
+	{
+		.name		= "h3:red",
+		.default_trigger = "heartbeat",
+		.gpio		= 3,
+	},
+	{
+		.name		= "h3:green",
+		.default_trigger = "cpu0",
+		.gpio		= OMAP_MPUIO(4),
+	},
+};
+
+static struct gpio_led_platform_data h3_gpio_led_data = {
+	.leds		= h3_gpio_led_pins,
+	.num_leds	= ARRAY_SIZE(h3_gpio_led_pins),
+};
+
+static struct platform_device h3_gpio_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &h3_gpio_led_data,
+	},
+};
+
 static struct platform_device *devices[] __initdata = {
 	&nor_device,
 	&nand_device,
@@ -331,6 +358,7 @@ static struct platform_device *devices[] __initdata = {
 	&intlat_device,
 	&h3_kp_device,
 	&h3_lcd_device,
+	&h3_gpio_leds,
 };
 
 static struct omap_usb_config h3_usb_config __initdata = {
@@ -398,6 +426,10 @@ static void __init h3_init(void)
 	omap_cfg_reg(E19_1610_KBR4);
 	omap_cfg_reg(N19_1610_KBR5);
 
+	/* GPIO based LEDs */
+	omap_cfg_reg(P18_1610_GPIO3);
+	omap_cfg_reg(MPUIO4);
+
 	smc91x_resources[1].start = gpio_to_irq(40);
 	smc91x_resources[1].end = gpio_to_irq(40);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index da8d872..043412c 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -380,10 +380,37 @@ static struct platform_device osk5912_lcd_device = {
 	.id		= -1,
 };
 
+static struct gpio_led mistral_gpio_led_pins[] = {
+	{
+		.name		= "mistral:red",
+		.default_trigger = "heartbeat",
+		.gpio		= 3,
+	},
+	{
+		.name		= "mistral:green",
+		.default_trigger = "cpu0",
+		.gpio		= OMAP_MPUIO(4),
+	},
+};
+
+static struct gpio_led_platform_data mistral_gpio_led_data = {
+	.leds		= mistral_gpio_led_pins,
+	.num_leds	= ARRAY_SIZE(mistral_gpio_led_pins),
+};
+
+static struct platform_device mistral_gpio_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &mistral_gpio_led_data,
+	},
+};
+
 static struct platform_device *mistral_devices[] __initdata = {
 	&osk5912_kp_device,
 	&mistral_bl_device,
 	&osk5912_lcd_device,
+	&mistral_gpio_leds,
 };
 
 static int mistral_get_pendown_state(void)
@@ -508,6 +535,12 @@ static void __init osk_mistral_init(void)
 	if (gpio_request(2, "lcd_pwr") == 0)
 		gpio_direction_output(2, 1);
 
+	/*
+	 * GPIO based LEDs
+	 */
+	omap_cfg_reg(P18_1610_GPIO3);
+	omap_cfg_reg(MPUIO4);
+
 	i2c_register_board_info(1, mistral_i2c_board_info,
 			ARRAY_SIZE(mistral_i2c_board_info));
 
diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
deleted file mode 100644
index f6b14a1..0000000
--- a/arch/arm/mach-omap1/leds-h2p2-debug.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds-h2p2-debug.c
- *
- * Copyright 2003 by Texas Instruments Incorporated
- *
- * There are 16 LEDs on the debug board (all green); four may be used
- * for logical 'green', 'amber', 'red', and 'blue' (after "claiming").
- *
- * The "surfer" expansion board and H2 sample board also have two-color
- * green+red LEDs (in parallel), used here for timer and idle indicators.
- */
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/sched.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include <plat/fpga.h>
-
-#include "leds.h"
-
-
-#define GPIO_LED_RED		3
-#define GPIO_LED_GREEN		OMAP_MPUIO(4)
-
-
-#define LED_STATE_ENABLED	0x01
-#define LED_STATE_CLAIMED	0x02
-#define LED_TIMER_ON		0x04
-
-#define GPIO_IDLE		GPIO_LED_GREEN
-#define GPIO_TIMER		GPIO_LED_RED
-
-
-void h2p2_dbg_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	static struct h2p2_dbg_fpga __iomem *fpga;
-	static u16 led_state, hw_led_state;
-
-	local_irq_save(flags);
-
-	if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
-		goto done;
-
-	switch (evt) {
-	case led_start:
-		if (!fpga)
-			fpga = ioremap(H2P2_DBG_FPGA_START,
-						H2P2_DBG_FPGA_SIZE);
-		if (fpga) {
-			led_state |= LED_STATE_ENABLED;
-			__raw_writew(~0, &fpga->leds);
-		}
-		break;
-
-	case led_stop:
-	case led_halted:
-		/* all leds off during suspend or shutdown */
-
-		if (! machine_is_omap_perseus2()) {
-			gpio_set_value(GPIO_TIMER, 0);
-			gpio_set_value(GPIO_IDLE, 0);
-		}
-
-		__raw_writew(~0, &fpga->leds);
-		led_state &= ~LED_STATE_ENABLED;
-		if (evt == led_halted) {
-			iounmap(fpga);
-			fpga = NULL;
-		}
-
-		goto done;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		led_state ^= LED_TIMER_ON;
-
-		if (machine_is_omap_perseus2())
-			hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
-		else {
-			gpio_set_value(GPIO_TIMER, led_state & LED_TIMER_ON);
-			goto done;
-		}
-
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (machine_is_omap_perseus2())
-			hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
-		else {
-			gpio_set_value(GPIO_IDLE, 1);
-			goto done;
-		}
-
-		break;
-
-	case led_idle_end:
-		if (machine_is_omap_perseus2())
-			hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
-		else {
-			gpio_set_value(GPIO_IDLE, 0);
-			goto done;
-		}
-
-		break;
-#endif
-
-	case led_green_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
-		break;
-	case led_green_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
-		break;
-
-	case led_amber_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
-		break;
-	case led_amber_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
-		break;
-
-	case led_red_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_RED;
-		break;
-	case led_red_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
-		break;
-
-	case led_blue_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
-		break;
-	case led_blue_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
-		break;
-
-	default:
-		break;
-	}
-
-
-	/*
-	 *  Actually burn the LEDs
-	 */
-	if (led_state & LED_STATE_ENABLED)
-		__raw_writew(~hw_led_state, &fpga->leds);
-
-done:
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-omap1/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c
deleted file mode 100644
index 3a066ee..0000000
--- a/arch/arm/mach-omap1/leds-innovator.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds-innovator.c
- */
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void innovator_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = 0;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		hw_led_state = 0;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= 0;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= 0;
-		break;
-
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~0;
-		break;
-#endif
-
-	case led_halted:
-		break;
-
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~0;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= 0;
-		break;
-
-	case led_amber_on:
-		break;
-
-	case led_amber_off:
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~0;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= 0;
-		break;
-
-	default:
-		break;
-	}
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c
deleted file mode 100644
index 936ed42..0000000
--- a/arch/arm/mach-omap1/leds-osk.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds-osk.c
- *
- * LED driver for OSK with optional Mistral QVGA board
- */
-#include <linux/gpio.h>
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	(1 << 0)
-#define LED_STATE_CLAIMED	(1 << 1)
-static u8 led_state;
-
-#define	TIMER_LED		(1 << 3)	/* Mistral board */
-#define	IDLE_LED		(1 << 4)	/* Mistral board */
-static u8 hw_led_state;
-
-
-#ifdef	CONFIG_OMAP_OSK_MISTRAL
-
-/* For now, all system indicators require the Mistral board, since that
- * LED can be manipulated without a task context.  This LED is either red,
- * or green, but not both; it can't give the full "disco led" effect.
- */
-
-#define GPIO_LED_RED		3
-#define GPIO_LED_GREEN		OMAP_MPUIO(4)
-
-static void mistral_setled(void)
-{
-	int	red = 0;
-	int	green = 0;
-
-	if (hw_led_state & TIMER_LED)
-		red = 1;
-	else if (hw_led_state & IDLE_LED)
-		green = 1;
-	/* else both sides are disabled */
-
-	gpio_set_value(GPIO_LED_GREEN, green);
-	gpio_set_value(GPIO_LED_RED, red);
-}
-
-#endif
-
-void osk_leds_event(led_event_t evt)
-{
-	unsigned long	flags;
-	u16		leds;
-
-	local_irq_save(flags);
-
-	if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
-		goto done;
-
-	leds = hw_led_state;
-	switch (evt) {
-	case led_start:
-		led_state |= LED_STATE_ENABLED;
-		hw_led_state = 0;
-		leds = ~0;
-		break;
-
-	case led_halted:
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		hw_led_state = 0;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		leds = ~0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-#ifdef	CONFIG_OMAP_OSK_MISTRAL
-
-	case led_timer:
-		hw_led_state ^= TIMER_LED;
-		mistral_setled();
-		break;
-
-	case led_idle_start:	/* idle == off */
-		hw_led_state &= ~IDLE_LED;
-		mistral_setled();
-		break;
-
-	case led_idle_end:
-		hw_led_state |= IDLE_LED;
-		mistral_setled();
-		break;
-
-#endif	/* CONFIG_OMAP_OSK_MISTRAL */
-
-	default:
-		break;
-	}
-
-	leds ^= hw_led_state;
-
-done:
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c
deleted file mode 100644
index ae6dd93..0000000
--- a/arch/arm/mach-omap1/leds.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds.c
- *
- * OMAP LEDs dispatcher
- */
-#include <linux/gpio.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include <plat/mux.h>
-
-#include "leds.h"
-
-static int __init
-omap_leds_init(void)
-{
-	if (!cpu_class_is_omap1())
-		return -ENODEV;
-
-	if (machine_is_omap_innovator())
-		leds_event = innovator_leds_event;
-
-	else if (machine_is_omap_h2()
-			|| machine_is_omap_h3()
-			|| machine_is_omap_perseus2())
-		leds_event = h2p2_dbg_leds_event;
-
-	else if (machine_is_omap_osk())
-		leds_event = osk_leds_event;
-
-	else
-		return -1;
-
-	if (machine_is_omap_h2()
-			|| machine_is_omap_h3()
-#ifdef	CONFIG_OMAP_OSK_MISTRAL
-			|| machine_is_omap_osk()
-#endif
-			) {
-
-		/* LED1/LED2 pins can be used as GPIO (as done here), or by
-		 * the LPG (works even in deep sleep!), to drive a bicolor
-		 * LED on the H2 sample board, and another on the H2/P2
-		 * "surfer" expansion board.
-		 *
-		 * The same pins drive a LED on the OSK Mistral board, but
-		 * that's a different kind of LED (just one color at a time).
-		 */
-		omap_cfg_reg(P18_1610_GPIO3);
-		if (gpio_request(3, "LED red") == 0)
-			gpio_direction_output(3, 1);
-		else
-			printk(KERN_WARNING "LED: can't get GPIO3/red?\n");
-
-		omap_cfg_reg(MPUIO4);
-		if (gpio_request(OMAP_MPUIO(4), "LED green") == 0)
-			gpio_direction_output(OMAP_MPUIO(4), 1);
-		else
-			printk(KERN_WARNING "LED: can't get MPUIO4/green?\n");
-	}
-
-	leds_event(led_start);
-	return 0;
-}
-
-__initcall(omap_leds_init);
diff --git a/arch/arm/mach-omap1/leds.h b/arch/arm/mach-omap1/leds.h
deleted file mode 100644
index a1e9fed..0000000
--- a/arch/arm/mach-omap1/leds.h
+++ /dev/null
@@ -1,3 +0,0 @@
-extern void innovator_leds_event(led_event_t evt);
-extern void h2p2_dbg_leds_event(led_event_t evt);
-extern void osk_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 4062480..4d4816f 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -44,7 +44,6 @@
 #include <linux/clockchips.h>
 #include <linux/io.h>
 
-#include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/sched_clock.h>
 
diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c
index eae49c3..7452954 100644
--- a/arch/arm/mach-omap1/timer32k.c
+++ b/arch/arm/mach-omap1/timer32k.c
@@ -46,7 +46,6 @@
 #include <linux/clockchips.h>
 #include <linux/io.h>
 
-#include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index deffbf1..596eb70 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -111,7 +111,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 		booted = true;
 	}
 
-	gic_raise_softirq(cpumask_of(cpu), 1);
+	gic_raise_softirq(cpumask_of(cpu), 0);
 
 	/*
 	 * Now the secondary core is starting up let it run its
diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
index 78a6a11..9b1c953 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
@@ -18,7 +18,6 @@
 #include <linux/ethtool.h>
 #include <net/dsa.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
index 2f5dc54..51ba2b8 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
@@ -19,7 +19,6 @@
 #include <linux/i2c.h>
 #include <net/dsa.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c
index 399130f..0a56b94 100644
--- a/arch/arm/mach-orion5x/rd88f5182-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5182-setup.c
@@ -19,8 +19,8 @@
 #include <linux/mv643xx_eth.h>
 #include <linux/ata_platform.h>
 #include <linux/i2c.h>
+#include <linux/leds.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
@@ -53,12 +53,6 @@
 #define RD88F5182_PCI_SLOT0_IRQ_A_PIN	7
 #define RD88F5182_PCI_SLOT0_IRQ_B_PIN	6
 
-/*
- * GPIO Debug LED
- */
-
-#define RD88F5182_GPIO_DBG_LED		0
-
 /*****************************************************************************
  * 16M NOR Flash on Device bus CS1
  ****************************************************************************/
@@ -83,55 +77,32 @@ static struct platform_device rd88f5182_nor_flash = {
 	.resource		= &rd88f5182_nor_flash_resource,
 };
 
-#ifdef CONFIG_LEDS
-
 /*****************************************************************************
- * Use GPIO debug led as CPU active indication
+ * Use GPIO LED as CPU active indication
  ****************************************************************************/
 
-static void rd88f5182_dbgled_event(led_event_t evt)
-{
-	int val;
-
-	if (evt == led_idle_end)
-		val = 1;
-	else if (evt == led_idle_start)
-		val = 0;
-	else
-		return;
-
-	gpio_set_value(RD88F5182_GPIO_DBG_LED, val);
-}
-
-static int __init rd88f5182_dbgled_init(void)
-{
-	int pin;
-
-	if (machine_is_rd88f5182()) {
-		pin = RD88F5182_GPIO_DBG_LED;
+#define RD88F5182_GPIO_LED		0
 
-		if (gpio_request(pin, "DBGLED") == 0) {
-			if (gpio_direction_output(pin, 0) != 0) {
-				printk(KERN_ERR "rd88f5182_dbgled_init failed "
-						"to set output pin %d\n", pin);
-				gpio_free(pin);
-				return 0;
-			}
-		} else {
-			printk(KERN_ERR "rd88f5182_dbgled_init failed "
-					"to request gpio %d\n", pin);
-			return 0;
-		}
-
-		leds_event = rd88f5182_dbgled_event;
-	}
-
-	return 0;
-}
+static struct gpio_led rd88f5182_gpio_led_pins[] = {
+	{
+		.name		= "rd88f5182:cpu",
+		.default_trigger = "cpu0",
+		.gpio		= RD88F5182_GPIO_LED,
+	},
+};
 
-__initcall(rd88f5182_dbgled_init);
+static struct gpio_led_platform_data rd88f5182_gpio_led_data = {
+	.leds		= rd88f5182_gpio_led_pins,
+	.num_leds	= ARRAY_SIZE(rd88f5182_gpio_led_pins),
+};
 
-#endif
+static struct platform_device rd88f5182_gpio_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &rd88f5182_gpio_led_data,
+	},
+};
 
 /*****************************************************************************
  * PCI
@@ -298,6 +269,7 @@ static void __init rd88f5182_init(void)
 
 	orion5x_setup_dev1_win(RD88F5182_NOR_BASE, RD88F5182_NOR_SIZE);
 	platform_device_register(&rd88f5182_nor_flash);
+	platform_device_register(&rd88f5182_gpio_leds);
 
 	i2c_register_board_info(0, &rd88f5182_i2c_rtc, 1);
 }
diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
index 92df49c..ed50910 100644
--- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
@@ -20,7 +20,6 @@
 #include <linux/ethtool.h>
 #include <net/dsa.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index 0cfe8af..47a7ae9 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -25,7 +25,6 @@
 #include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/leds.h>
 #include <asm/mach/time.h>
 #include <asm/errno.h>
 
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index be0f7df..d4337e3 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -95,12 +95,4 @@ obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR)	+= raumfeld.o
 obj-$(CONFIG_MACH_RAUMFELD_SPEAKER)	+= raumfeld.o
 obj-$(CONFIG_MACH_ZIPIT2)	+= z2.o
 
-# Support for blinky lights
-led-y := leds.o
-led-$(CONFIG_ARCH_LUBBOCK)	+= leds-lubbock.o
-led-$(CONFIG_MACH_MAINSTONE)	+= leds-mainstone.o
-led-$(CONFIG_ARCH_PXA_IDP)	+= leds-idp.o
-
-obj-$(CONFIG_LEDS)		+= $(led-y)
-
 obj-$(CONFIG_TOSA_BT)		+= tosa-bt.o
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index 6ff466b..ae1e997 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -191,6 +191,87 @@ static void __init idp_map_io(void)
 	iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc));
 }
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct idp_led {
+	struct led_classdev     cdev;
+	u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} idp_leds[] = {
+	{ "idp:green", "heartbeat", },
+	{ "idp:red", "cpu0", },
+};
+
+static void idp_led_set(struct led_classdev *cdev,
+		enum led_brightness b)
+{
+	struct idp_led *led = container_of(cdev,
+			struct idp_led, cdev);
+	u32 reg = IDP_CPLD_LED_CONTROL;
+
+	if (b != LED_OFF)
+		reg &= ~led->mask;
+	else
+		reg |= led->mask;
+
+	IDP_CPLD_LED_CONTROL = reg;
+}
+
+static enum led_brightness idp_led_get(struct led_classdev *cdev)
+{
+	struct idp_led *led = container_of(cdev,
+			struct idp_led, cdev);
+
+	return (IDP_CPLD_LED_CONTROL & led->mask) ? LED_OFF : LED_FULL;
+}
+
+static int __init idp_leds_init(void)
+{
+	int i;
+
+	if (!machine_is_pxa_idp())
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(idp_leds); i++) {
+		struct idp_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = idp_leds[i].name;
+		led->cdev.brightness_set = idp_led_set;
+		led->cdev.brightness_get = idp_led_get;
+		led->cdev.default_trigger = idp_leds[i].trigger;
+
+		if (i == 0)
+			led->mask = IDP_HB_LED;
+		else
+			led->mask = IDP_BUSY_LED;
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(idp_leds_init);
+#endif
 
 MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
 	/* Maintainer: Vibren Technologies */
diff --git a/arch/arm/mach-pxa/include/mach/regs-ost.h b/arch/arm/mach-pxa/include/mach/regs-ost.h
index a3e5f86..6288199 100644
--- a/arch/arm/mach-pxa/include/mach/regs-ost.h
+++ b/arch/arm/mach-pxa/include/mach/regs-ost.h
@@ -7,17 +7,17 @@
  * OS Timer & Match Registers
  */
 
-#define OSMR0		__REG(0x40A00000)  /* */
-#define OSMR1		__REG(0x40A00004)  /* */
-#define OSMR2		__REG(0x40A00008)  /* */
-#define OSMR3		__REG(0x40A0000C)  /* */
-#define OSMR4		__REG(0x40A00080)  /* */
-#define OSCR		__REG(0x40A00010)  /* OS Timer Counter Register */
-#define OSCR4		__REG(0x40A00040)  /* OS Timer Counter Register */
-#define OMCR4		__REG(0x40A000C0)  /* */
-#define OSSR		__REG(0x40A00014)  /* OS Timer Status Register */
-#define OWER		__REG(0x40A00018)  /* OS Timer Watchdog Enable Register */
-#define OIER		__REG(0x40A0001C)  /* OS Timer Interrupt Enable Register */
+#define OSMR0		io_p2v(0x40A00000)  /* */
+#define OSMR1		io_p2v(0x40A00004)  /* */
+#define OSMR2		io_p2v(0x40A00008)  /* */
+#define OSMR3		io_p2v(0x40A0000C)  /* */
+#define OSMR4		io_p2v(0x40A00080)  /* */
+#define OSCR		io_p2v(0x40A00010)  /* OS Timer Counter Register */
+#define OSCR4		io_p2v(0x40A00040)  /* OS Timer Counter Register */
+#define OMCR4		io_p2v(0x40A000C0)  /* */
+#define OSSR		io_p2v(0x40A00014)  /* OS Timer Status Register */
+#define OWER		io_p2v(0x40A00018)  /* OS Timer Watchdog Enable Register */
+#define OIER		io_p2v(0x40A0001C)  /* OS Timer Interrupt Enable Register */
 
 #define OSSR_M3		(1 << 3)	/* Match status channel 3 */
 #define OSSR_M2		(1 << 2)	/* Match status channel 2 */
diff --git a/arch/arm/mach-pxa/leds-idp.c b/arch/arm/mach-pxa/leds-idp.c
deleted file mode 100644
index 06b0600..0000000
--- a/arch/arm/mach-pxa/leds-idp.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds-idp.c
- *
- * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
- *
- * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
- *
- * Original (leds-footbridge.c) by Russell King
- *
- * Macros for actual LED manipulation should be in machine specific
- * files in this 'mach' directory.
- */
-
-
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include <mach/pxa25x.h>
-#include <mach/idp.h>
-
-#include "leds.h"
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void idp_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= IDP_HB_LED;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~IDP_BUSY_LED;
-		break;
-
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= IDP_BUSY_LED;
-		break;
-#endif
-
-	case led_halted:
-		break;
-
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= IDP_HB_LED;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~IDP_HB_LED;
-		break;
-
-	case led_amber_on:
-		break;
-
-	case led_amber_off:
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= IDP_BUSY_LED;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~IDP_BUSY_LED;
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED)
-		IDP_CPLD_LED_CONTROL = ( (IDP_CPLD_LED_CONTROL | IDP_LEDS_MASK) & ~hw_led_state);
-	else
-		IDP_CPLD_LED_CONTROL |= IDP_LEDS_MASK;
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c
deleted file mode 100644
index 0bd85c8..0000000
--- a/arch/arm/mach-pxa/leds-lubbock.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds-lubbock.c
- *
- * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
- *
- * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
- *
- * Original (leds-footbridge.c) by Russell King
- *
- * Major surgery on April 2004 by Nicolas Pitre for less global
- * namespace collision.  Mostly adapted the Mainstone version.
- */
-
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <mach/pxa25x.h>
-#include <mach/lubbock.h>
-
-#include "leds.h"
-
-/*
- * 8 discrete leds available for general use:
- *
- * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays
- * so be sure to not monkey with them here.
- */
-
-#define D28			(1 << 0)
-#define D27			(1 << 1)
-#define D26			(1 << 2)
-#define D25			(1 << 3)
-#define D24			(1 << 4)
-#define D23			(1 << 5)
-#define D22			(1 << 6)
-#define D21			(1 << 7)
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void lubbock_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = 0;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		hw_led_state ^= D26;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		hw_led_state &= ~D27;
-		break;
-
-	case led_idle_end:
-		hw_led_state |= D27;
-		break;
-#endif
-
-	case led_halted:
-		break;
-
-	case led_green_on:
-		hw_led_state |= D21;
-		break;
-
-	case led_green_off:
-		hw_led_state &= ~D21;
-		break;
-
-	case led_amber_on:
-		hw_led_state |= D22;
-		break;
-
-	case led_amber_off:
-		hw_led_state &= ~D22;
-		break;
-
-	case led_red_on:
-		hw_led_state |= D23;
-		break;
-
-	case led_red_off:
-		hw_led_state &= ~D23;
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED)
-		LUB_DISC_BLNK_LED = (LUB_DISC_BLNK_LED | 0xff) & ~hw_led_state;
-	else
-		LUB_DISC_BLNK_LED |= 0xff;
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c
deleted file mode 100644
index 4058ab3..0000000
--- a/arch/arm/mach-pxa/leds-mainstone.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds-mainstone.c
- *
- * Author:     Nicolas Pitre
- * Created:    Nov 05, 2002
- * Copyright:  MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include <mach/pxa27x.h>
-#include <mach/mainstone.h>
-
-#include "leds.h"
-
-
-/* 8 discrete leds available for general use: */
-#define D28			(1 << 0)
-#define D27			(1 << 1)
-#define D26			(1 << 2)
-#define D25			(1 << 3)
-#define D24			(1 << 4)
-#define D23			(1 << 5)
-#define D22			(1 << 6)
-#define D21			(1 << 7)
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void mainstone_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = 0;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		hw_led_state ^= D26;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		hw_led_state &= ~D27;
-		break;
-
-	case led_idle_end:
-		hw_led_state |= D27;
-		break;
-#endif
-
-	case led_halted:
-		break;
-
-	case led_green_on:
-		hw_led_state |= D21;
-		break;
-
-	case led_green_off:
-		hw_led_state &= ~D21;
-		break;
-
-	case led_amber_on:
-		hw_led_state |= D22;
-		break;
-
-	case led_amber_off:
-		hw_led_state &= ~D22;
-		break;
-
-	case led_red_on:
-		hw_led_state |= D23;
-		break;
-
-	case led_red_off:
-		hw_led_state &= ~D23;
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED)
-		MST_LEDCTRL = (MST_LEDCTRL | 0xff) & ~hw_led_state;
-	else
-		MST_LEDCTRL |= 0xff;
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-pxa/leds.c b/arch/arm/mach-pxa/leds.c
deleted file mode 100644
index bbe4d5f..0000000
--- a/arch/arm/mach-pxa/leds.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds.c
- *
- * xscale LEDs dispatcher
- *
- * Copyright (C) 2001 Nicolas Pitre
- *
- * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
- */
-#include <linux/compiler.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include "leds.h"
-
-static int __init
-pxa_leds_init(void)
-{
-	if (machine_is_lubbock())
-		leds_event = lubbock_leds_event;
-	if (machine_is_mainstone())
-		leds_event = mainstone_leds_event;
-	if (machine_is_pxa_idp())
-		leds_event = idp_leds_event;
-
-	leds_event(led_start);
-	return 0;
-}
-
-core_initcall(pxa_leds_init);
diff --git a/arch/arm/mach-pxa/leds.h b/arch/arm/mach-pxa/leds.h
deleted file mode 100644
index 7f0dfe0..0000000
--- a/arch/arm/mach-pxa/leds.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-pxa/leds.h
- *
- * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
- *
- * blinky lights for various PXA-based systems:
- *
- */
-
-extern void idp_leds_event(led_event_t evt);
-extern void lubbock_leds_event(led_event_t evt);
-extern void mainstone_leds_event(led_event_t evt);
-extern void trizeps4_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 6bb3f47..4350283 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/syscore_ops.h>
 #include <linux/major.h>
@@ -23,6 +24,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/smc91x.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
@@ -549,6 +552,98 @@ static void __init lubbock_map_io(void)
 	PCFR |= PCFR_OPDE;
 }
 
+/*
+ * Driver for the 8 discrete LEDs available for general use:
+ * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays
+ * so be sure to not monkey with them here.
+ */
+
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct lubbock_led {
+	struct led_classdev	cdev;
+	u8			mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} lubbock_leds[] = {
+	{ "lubbock:D28", "default-on", },
+	{ "lubbock:D27", "cpu0", },
+	{ "lubbock:D26", "heartbeat" },
+	{ "lubbock:D25", },
+	{ "lubbock:D24", },
+	{ "lubbock:D23", },
+	{ "lubbock:D22", },
+	{ "lubbock:D21", },
+};
+
+static void lubbock_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
+{
+	struct lubbock_led *led = container_of(cdev,
+					 struct lubbock_led, cdev);
+	u32 reg = LUB_DISC_BLNK_LED;
+
+	if (b != LED_OFF)
+		reg |= led->mask;
+	else
+		reg &= ~led->mask;
+
+	LUB_DISC_BLNK_LED = reg;
+}
+
+static enum led_brightness lubbock_led_get(struct led_classdev *cdev)
+{
+	struct lubbock_led *led = container_of(cdev,
+					 struct lubbock_led, cdev);
+	u32 reg = LUB_DISC_BLNK_LED;
+
+	return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
+
+static int __init lubbock_leds_init(void)
+{
+	int i;
+
+	if (!machine_is_lubbock())
+		return -ENODEV;
+
+	/* All ON */
+	LUB_DISC_BLNK_LED |= 0xff;
+	for (i = 0; i < ARRAY_SIZE(lubbock_leds); i++) {
+		struct lubbock_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = lubbock_leds[i].name;
+		led->cdev.brightness_set = lubbock_led_set;
+		led->cdev.brightness_get = lubbock_led_get;
+		led->cdev.default_trigger = lubbock_leds[i].trigger;
+		led->mask = BIT(i);
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(lubbock_leds_init);
+#endif
+
 MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
 	/* Maintainer: MontaVista Software Inc. */
 	.map_io		= lubbock_map_io,
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 1aebaf7..bdc6c33 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -28,6 +28,8 @@
 #include <linux/pwm_backlight.h>
 #include <linux/smc91x.h>
 #include <linux/i2c/pxa-i2c.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -613,6 +615,98 @@ static void __init mainstone_map_io(void)
  	PCFR = 0x66;
 }
 
+/*
+ * Driver for the 8 discrete LEDs available for general use:
+ * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays
+ * so be sure to not monkey with them here.
+ */
+
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct mainstone_led {
+	struct led_classdev	cdev;
+	u8			mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} mainstone_leds[] = {
+	{ "mainstone:D28", "default-on", },
+	{ "mainstone:D27", "cpu0", },
+	{ "mainstone:D26", "heartbeat" },
+	{ "mainstone:D25", },
+	{ "mainstone:D24", },
+	{ "mainstone:D23", },
+	{ "mainstone:D22", },
+	{ "mainstone:D21", },
+};
+
+static void mainstone_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
+{
+	struct mainstone_led *led = container_of(cdev,
+					 struct mainstone_led, cdev);
+	u32 reg = MST_LEDCTRL;
+
+	if (b != LED_OFF)
+		reg |= led->mask;
+	else
+		reg &= ~led->mask;
+
+	MST_LEDCTRL = reg;
+}
+
+static enum led_brightness mainstone_led_get(struct led_classdev *cdev)
+{
+	struct mainstone_led *led = container_of(cdev,
+					 struct mainstone_led, cdev);
+	u32 reg = MST_LEDCTRL;
+
+	return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
+
+static int __init mainstone_leds_init(void)
+{
+	int i;
+
+	if (!machine_is_mainstone())
+		return -ENODEV;
+
+	/* All ON */
+	MST_LEDCTRL |= 0xff;
+	for (i = 0; i < ARRAY_SIZE(mainstone_leds); i++) {
+		struct mainstone_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = mainstone_leds[i].name;
+		led->cdev.brightness_set = mainstone_led_set;
+		led->cdev.brightness_get = mainstone_led_get;
+		led->cdev.default_trigger = mainstone_leds[i].trigger;
+		led->mask = BIT(i);
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(mainstone_leds_init);
+#endif
+
 MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
 	/* Maintainer: MontaVista Software Inc. */
 	.atag_offset	= 0x100,	/* BLOB boot parameter setting */
diff --git a/arch/arm/mach-pxa/reset.c b/arch/arm/mach-pxa/reset.c
index b452889..3fab583 100644
--- a/arch/arm/mach-pxa/reset.c
+++ b/arch/arm/mach-pxa/reset.c
@@ -77,9 +77,10 @@ static void do_gpio_reset(void)
 static void do_hw_reset(void)
 {
 	/* Initialize the watchdog and let it fire */
-	OWER = OWER_WME;
-	OSSR = OSSR_M3;
-	OSMR3 = OSCR + 368640;	/* ... in 100 ms */
+	writel_relaxed(OWER_WME, OWER);
+	writel_relaxed(OSSR_M3, OSSR);
+	/* ... in 100 ms */
+	writel_relaxed(readl_relaxed(OSCR) + 368640, OSMR3);
 }
 
 void pxa_restart(char mode, const char *cmd)
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 3d6c9bd..4bc47d6 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -35,7 +35,7 @@
 
 static u32 notrace pxa_read_sched_clock(void)
 {
-	return OSCR;
+	return readl_relaxed(OSCR);
 }
 
 
@@ -47,8 +47,8 @@ pxa_ost0_interrupt(int irq, void *dev_id)
 	struct clock_event_device *c = dev_id;
 
 	/* Disarm the compare/match, signal the event. */
-	OIER &= ~OIER_E0;
-	OSSR = OSSR_M0;
+	writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
+	writel_relaxed(OSSR_M0, OSSR);
 	c->event_handler(c);
 
 	return IRQ_HANDLED;
@@ -59,10 +59,10 @@ pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
 {
 	unsigned long next, oscr;
 
-	OIER |= OIER_E0;
-	next = OSCR + delta;
-	OSMR0 = next;
-	oscr = OSCR;
+	writel_relaxed(readl_relaxed(OIER) | OIER_E0, OIER);
+	next = readl_relaxed(OSCR) + delta;
+	writel_relaxed(next, OSMR0);
+	oscr = readl_relaxed(OSCR);
 
 	return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
 }
@@ -72,15 +72,15 @@ pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
 {
 	switch (mode) {
 	case CLOCK_EVT_MODE_ONESHOT:
-		OIER &= ~OIER_E0;
-		OSSR = OSSR_M0;
+		writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
+		writel_relaxed(OSSR_M0, OSSR);
 		break;
 
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
 		/* initializing, released, or preparing for suspend */
-		OIER &= ~OIER_E0;
-		OSSR = OSSR_M0;
+		writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
+		writel_relaxed(OSSR_M0, OSSR);
 		break;
 
 	case CLOCK_EVT_MODE_RESUME:
@@ -108,8 +108,8 @@ static void __init pxa_timer_init(void)
 {
 	unsigned long clock_tick_rate = get_clock_tick_rate();
 
-	OIER = 0;
-	OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
+	writel_relaxed(0, OIER);
+	writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
 
 	setup_sched_clock(pxa_read_sched_clock, 32, clock_tick_rate);
 
@@ -122,7 +122,7 @@ static void __init pxa_timer_init(void)
 
 	setup_irq(IRQ_OST0, &pxa_ost0_irq);
 
-	clocksource_mmio_init(&OSCR, "oscr0", clock_tick_rate, 200, 32,
+	clocksource_mmio_init(OSCR, "oscr0", clock_tick_rate, 200, 32,
 		clocksource_mmio_readl_up);
 	clockevents_register_device(&ckevt_pxa_osmr0);
 }
@@ -132,12 +132,12 @@ static unsigned long osmr[4], oier, oscr;
 
 static void pxa_timer_suspend(void)
 {
-	osmr[0] = OSMR0;
-	osmr[1] = OSMR1;
-	osmr[2] = OSMR2;
-	osmr[3] = OSMR3;
-	oier = OIER;
-	oscr = OSCR;
+	osmr[0] = readl_relaxed(OSMR0);
+	osmr[1] = readl_relaxed(OSMR1);
+	osmr[2] = readl_relaxed(OSMR2);
+	osmr[3] = readl_relaxed(OSMR3);
+	oier = readl_relaxed(OIER);
+	oscr = readl_relaxed(OSCR);
 }
 
 static void pxa_timer_resume(void)
@@ -151,12 +151,12 @@ static void pxa_timer_resume(void)
 	if (osmr[0] - oscr < MIN_OSCR_DELTA)
 		osmr[0] += MIN_OSCR_DELTA;
 
-	OSMR0 = osmr[0];
-	OSMR1 = osmr[1];
-	OSMR2 = osmr[2];
-	OSMR3 = osmr[3];
-	OIER = oier;
-	OSCR = oscr;
+	writel_relaxed(osmr[0], OSMR0);
+	writel_relaxed(osmr[1], OSMR1);
+	writel_relaxed(osmr[2], OSMR2);
+	writel_relaxed(osmr[3], OSMR3);
+	writel_relaxed(oier, OIER);
+	writel_relaxed(oscr, OSCR);
 }
 #else
 #define pxa_timer_suspend NULL
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 45868bb..d22dee9 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -35,7 +35,6 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst.h>
@@ -436,44 +435,6 @@ struct clcd_board clcd_plat_data = {
 	.remove		= versatile_clcd_remove_dma,
 };
 
-#ifdef CONFIG_LEDS
-#define VA_LEDS_BASE (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET)
-
-void realview_leds_event(led_event_t ledevt)
-{
-	unsigned long flags;
-	u32 val;
-	u32 led = 1 << smp_processor_id();
-
-	local_irq_save(flags);
-	val = readl(VA_LEDS_BASE);
-
-	switch (ledevt) {
-	case led_idle_start:
-		val = val & ~led;
-		break;
-
-	case led_idle_end:
-		val = val | led;
-		break;
-
-	case led_timer:
-		val = val ^ REALVIEW_SYS_LED7;
-		break;
-
-	case led_halted:
-		val = 0;
-		break;
-
-	default:
-		break;
-	}
-
-	writel(val, VA_LEDS_BASE);
-	local_irq_restore(flags);
-}
-#endif	/* CONFIG_LEDS */
-
 /*
  * Where is the timer (VA)?
  */
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index f8f2c0a..f2141ae 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -26,7 +26,6 @@
 #include <linux/io.h>
 
 #include <asm/setup.h>
-#include <asm/leds.h>
 
 #define APB_DEVICE(name, busid, base, plat)			\
 static AMBA_APB_DEVICE(name, busid, 0, REALVIEW_##base##_BASE, base##_IRQ, plat)
@@ -47,7 +46,6 @@ extern void __iomem *timer1_va_base;
 extern void __iomem *timer2_va_base;
 extern void __iomem *timer3_va_base;
 
-extern void realview_leds_event(led_event_t ledevt);
 extern void realview_timer_init(unsigned int timer_irq);
 extern int realview_flash_register(struct resource *res, u32 num);
 extern int realview_eth_register(const char *name, struct resource *res);
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index baf382c..21661ad 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -30,7 +30,6 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/pmu.h>
 #include <asm/pgtable.h>
@@ -462,10 +461,6 @@ static void __init realview_eb_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index b1d7caf..c0ff882 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -32,7 +32,6 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/pmu.h>
 #include <asm/pgtable.h>
@@ -375,10 +374,6 @@ static void __init realview_pb1176_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index a98c536..30779ae 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -30,7 +30,6 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/pmu.h>
 #include <asm/pgtable.h>
@@ -357,10 +356,6 @@ static void __init realview_pb11mp_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index 5965017..081cd72 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -29,7 +29,6 @@
 #include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/pmu.h>
 #include <asm/pgtable.h>
@@ -299,10 +298,6 @@ static void __init realview_pba8_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 3f2f605..1ce62b9 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -28,7 +28,6 @@
 #include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/pmu.h>
 #include <asm/smp_twd.h>
@@ -394,10 +393,6 @@ static void __init realview_pbx_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
diff --git a/arch/arm/mach-s3c24xx/common.c b/arch/arm/mach-s3c24xx/common.c
index 56cdd34..0c9e9a7 100644
--- a/arch/arm/mach-s3c24xx/common.c
+++ b/arch/arm/mach-s3c24xx/common.c
@@ -41,7 +41,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 #include <plat/regs-serial.h>
 
diff --git a/arch/arm/mach-s3c24xx/include/mach/bast-pmu.h b/arch/arm/mach-s3c24xx/include/mach/bast-pmu.h
deleted file mode 100644
index 4c38b39..0000000
--- a/arch/arm/mach-s3c24xx/include/mach/bast-pmu.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/bast-pmu.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *	Vincent Sanders <vince@simtec.co.uk>
- *
- * Machine BAST - Power Management chip
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_BASTPMU_H
-#define __ASM_ARCH_BASTPMU_H "08_OCT_2004"
-
-#define BASTPMU_REG_IDENT	(0x00)
-#define BASTPMU_REG_VERSION	(0x01)
-#define BASTPMU_REG_DDCCTRL	(0x02)
-#define BASTPMU_REG_POWER	(0x03)
-#define BASTPMU_REG_RESET	(0x04)
-#define BASTPMU_REG_GWO		(0x05)
-#define BASTPMU_REG_WOL		(0x06)
-#define BASTPMU_REG_WOR		(0x07)
-#define BASTPMU_REG_UID		(0x09)
-
-#define BASTPMU_EEPROM		(0xC0)
-
-#define BASTPMU_EEP_UID		(BASTPMU_EEPROM + 0)
-#define BASTPMU_EEP_WOL		(BASTPMU_EEPROM + 8)
-#define BASTPMU_EEP_WOR		(BASTPMU_EEPROM + 9)
-
-#define BASTPMU_IDENT_0		0x53
-#define BASTPMU_IDENT_1		0x42
-#define BASTPMU_IDENT_2		0x50
-#define BASTPMU_IDENT_3		0x4d
-
-#define BASTPMU_RESET_GUARD	(0x55)
-
-#endif /* __ASM_ARCH_BASTPMU_H */
diff --git a/arch/arm/mach-s3c64xx/include/mach/crag6410.h b/arch/arm/mach-s3c64xx/include/mach/crag6410.h
index 4cb2f951..4c3c999 100644
--- a/arch/arm/mach-s3c64xx/include/mach/crag6410.h
+++ b/arch/arm/mach-s3c64xx/include/mach/crag6410.h
@@ -13,9 +13,7 @@
 
 #include <linux/gpio.h>
 
-#define BANFF_PMIC_IRQ_BASE		IRQ_BOARD_START
-#define GLENFARCLAS_PMIC_IRQ_BASE	(IRQ_BOARD_START + 64)
-#define CODEC_IRQ_BASE			(IRQ_BOARD_START + 128)
+#define GLENFARCLAS_PMIC_IRQ_BASE	IRQ_BOARD_START
 
 #define PCA935X_GPIO_BASE		GPIO_BOARD_START
 #define CODEC_GPIO_BASE			(GPIO_BOARD_START + 8)
diff --git a/arch/arm/mach-s3c64xx/include/mach/spi-clocks.h b/arch/arm/mach-s3c64xx/include/mach/spi-clocks.h
deleted file mode 100644
index 9d0c43b..0000000
--- a/arch/arm/mach-s3c64xx/include/mach/spi-clocks.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/spi-clocks.h
- *
- * Copyright (C) 2009 Samsung Electronics Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S3C64XX_PLAT_SPI_CLKS_H
-#define __S3C64XX_PLAT_SPI_CLKS_H __FILE__
-
-#define S3C64XX_SPI_SRCCLK_PCLK		0
-#define S3C64XX_SPI_SRCCLK_SPIBUS	1
-#define S3C64XX_SPI_SRCCLK_48M		2
-
-#endif /* __S3C64XX_PLAT_SPI_CLKS_H */
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
index 7a27f56..4645aa1 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
@@ -39,6 +39,7 @@ static struct spi_board_info wm1253_devs[] = {
 		.bus_num	= 0,
 		.chip_select	= 0,
 		.mode		= SPI_MODE_0,
+		.irq		= S3C_EINT(5),
 		.controller_data = &wm0010_spi_csinfo,
 	},
 };
@@ -168,7 +169,6 @@ static struct wm8994_pdata wm8994_pdata = {
 	.gpio_defaults = {
 		0x3,          /* IRQ out, active high, CMOS */
 	},
-	.irq_base = CODEC_IRQ_BASE,
 	.ldo = {
 		 { .init_data = &wm8994_ldo1, },
 		 { .init_data = &wm8994_ldo2, },
@@ -182,6 +182,11 @@ static const struct i2c_board_info wm1277_devs[] = {
 	},
 };
 
+static const struct i2c_board_info wm5102_devs[] = {
+	{ I2C_BOARD_INFO("wm5102", 0x1a),
+	  .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, },
+};
+
 static const struct i2c_board_info wm6230_i2c_devs[] = {
 	{ I2C_BOARD_INFO("wm9081", 0x6c),
 	  .platform_data = &wm9081_pdata, },
@@ -209,6 +214,7 @@ static __devinitdata const struct {
 	  .spi_devs = wm1253_devs, .num_spi_devs = ARRAY_SIZE(wm1253_devs) },
 	{ .id = 0x32, .name = "XXXX-EV1 Caol Illa" },
 	{ .id = 0x33, .name = "XXXX-EV1 Oban" },
+	{ .id = 0x34, .name = "WM0010-6320-CS42 Balblair" },
 	{ .id = 0x39, .name = "1254-EV1 Dallas Dhu",
 	  .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs) },
 	{ .id = 0x3a, .name = "1259-EV1 Tobermory",
@@ -218,6 +224,8 @@ static __devinitdata const struct {
 	{ .id = 0x3c, .name = "1273-EV1 Longmorn" },
 	{ .id = 0x3d, .name = "1277-EV1 Littlemill",
 	  .i2c_devs = wm1277_devs, .num_i2c_devs = ARRAY_SIZE(wm1277_devs) },
+	{ .id = 0x3e, .name = "WM5102-6271-EV1-CS127",
+	  .i2c_devs = wm5102_devs, .num_i2c_devs = ARRAY_SIZE(wm5102_devs) },
 };
 
 static __devinit int wlf_gf_module_probe(struct i2c_client *i2c,
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index d0c352d..161c3b6 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -525,7 +525,6 @@ static struct wm831x_touch_pdata touch_pdata __initdata = {
 
 static struct wm831x_pdata crag_pmic_pdata __initdata = {
 	.wm831x_num = 1,
-	.irq_base = BANFF_PMIC_IRQ_BASE,
 	.gpio_base = BANFF_PMIC_GPIO_BASE,
 	.soft_shutdown = true,
 
diff --git a/arch/arm/mach-s5p64x0/dma.c b/arch/arm/mach-s5p64x0/dma.c
index 2ee5dc0..9c4ce08 100644
--- a/arch/arm/mach-s5p64x0/dma.c
+++ b/arch/arm/mach-s5p64x0/dma.c
@@ -36,8 +36,6 @@
 #include <plat/devs.h>
 #include <plat/irqs.h>
 
-static u64 dma_dmamask = DMA_BIT_MASK(32);
-
 static u8 s5p6440_pdma_peri[] = {
 	DMACH_UART0_RX,
 	DMACH_UART0_TX,
diff --git a/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h b/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h
deleted file mode 100644
index 170a20a..0000000
--- a/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* linux/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_SPI_CLKS_H
-#define __ASM_ARCH_SPI_CLKS_H __FILE__
-
-#define S5P64X0_SPI_SRCCLK_PCLK		0
-#define S5P64X0_SPI_SRCCLK_SCLK		1
-
-#endif /* __ASM_ARCH_SPI_CLKS_H */
diff --git a/arch/arm/mach-s5pc100/dma.c b/arch/arm/mach-s5pc100/dma.c
index afd8db2..b141840 100644
--- a/arch/arm/mach-s5pc100/dma.c
+++ b/arch/arm/mach-s5pc100/dma.c
@@ -33,8 +33,6 @@
 #include <mach/irqs.h>
 #include <mach/dma.h>
 
-static u64 dma_dmamask = DMA_BIT_MASK(32);
-
 static u8 pdma0_peri[] = {
 	DMACH_UART0_RX,
 	DMACH_UART0_TX,
diff --git a/arch/arm/mach-s5pc100/include/mach/spi-clocks.h b/arch/arm/mach-s5pc100/include/mach/spi-clocks.h
deleted file mode 100644
index 65e4263..0000000
--- a/arch/arm/mach-s5pc100/include/mach/spi-clocks.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* linux/arch/arm/mach-s5pc100/include/mach/spi-clocks.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S5PC100_PLAT_SPI_CLKS_H
-#define __S5PC100_PLAT_SPI_CLKS_H __FILE__
-
-#define S5PC100_SPI_SRCCLK_PCLK		0
-#define S5PC100_SPI_SRCCLK_48M		1
-#define S5PC100_SPI_SRCCLK_SPIBUS	2
-
-#endif /* __S5PC100_PLAT_SPI_CLKS_H */
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 88e983b..77185c3 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -152,6 +152,7 @@ config MACH_SMDKV210
 	select S3C_DEV_I2C1
 	select S3C_DEV_I2C2
 	select S3C_DEV_RTC
+	select S3C_DEV_USB_HSOTG
 	select S3C_DEV_WDT
 	select S5P_DEV_FIMC0
 	select S5P_DEV_FIMC1
@@ -170,6 +171,7 @@ config MACH_SMDKV210
 	select S5PV210_SETUP_IDE
 	select S5PV210_SETUP_KEYPAD
 	select S5PV210_SETUP_SDHCI
+	select S5PV210_SETUP_USB_PHY
 	help
 	  Machine support for Samsung SMDKV210
 
diff --git a/arch/arm/mach-s5pv210/include/mach/spi-clocks.h b/arch/arm/mach-s5pv210/include/mach/spi-clocks.h
deleted file mode 100644
index 02acded..0000000
--- a/arch/arm/mach-s5pv210/include/mach/spi-clocks.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* linux/arch/arm/mach-s5pv210/include/mach/spi-clocks.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S5PV210_PLAT_SPI_CLKS_H
-#define __S5PV210_PLAT_SPI_CLKS_H __FILE__
-
-#define S5PV210_SPI_SRCCLK_PCLK		0
-#define S5PV210_SPI_SRCCLK_SCLK		1
-
-#endif /* __S5PV210_PLAT_SPI_CLKS_H */
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c
index 0d7ddec..c8997bc 100644
--- a/arch/arm/mach-s5pv210/mach-smdkv210.c
+++ b/arch/arm/mach-s5pv210/mach-smdkv210.c
@@ -19,6 +19,7 @@
 #include <linux/gpio.h>
 #include <linux/delay.h>
 #include <linux/pwm_backlight.h>
+#include <linux/platform_data/s3c-hsotg.h>
 
 #include <asm/hardware/vic.h>
 #include <asm/mach/arch.h>
@@ -47,6 +48,7 @@
 #include <plat/backlight.h>
 #include <plat/regs-fb-v4.h>
 #include <plat/mfc.h>
+#include <plat/clock.h>
 
 #include "common.h"
 
@@ -203,6 +205,9 @@ static struct s3c_fb_platdata smdkv210_lcd0_pdata __initdata = {
 	.setup_gpio	= s5pv210_fb_gpio_setup_24bpp,
 };
 
+/* USB OTG */
+static struct s3c_hsotg_plat smdkv210_hsotg_pdata;
+
 static struct platform_device *smdkv210_devices[] __initdata = {
 	&s3c_device_adc,
 	&s3c_device_cfcon,
@@ -216,6 +221,7 @@ static struct platform_device *smdkv210_devices[] __initdata = {
 	&s3c_device_i2c2,
 	&s3c_device_rtc,
 	&s3c_device_ts,
+	&s3c_device_usb_hsotg,
 	&s3c_device_wdt,
 	&s5p_device_fimc0,
 	&s5p_device_fimc1,
@@ -314,6 +320,9 @@ static void __init smdkv210_machine_init(void)
 
 	samsung_bl_set(&smdkv210_bl_gpio_info, &smdkv210_bl_data);
 
+	s3c_hsotg_set_platdata(&smdkv210_hsotg_pdata);
+	clk_xusbxti.rate = 24000000;
+
 	platform_add_devices(smdkv210_devices, ARRAY_SIZE(smdkv210_devices));
 }
 
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
index 60b97ec..1aed9e7 100644
--- a/arch/arm/mach-sa1100/Makefile
+++ b/arch/arm/mach-sa1100/Makefile
@@ -7,21 +7,17 @@ obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o
 obj-m :=
 obj-n :=
 obj-  :=
-led-y := leds.o
 
 obj-$(CONFIG_CPU_FREQ_SA1100)		+= cpu-sa1100.o
 obj-$(CONFIG_CPU_FREQ_SA1110)		+= cpu-sa1110.o
 
 # Specific board support
 obj-$(CONFIG_SA1100_ASSABET)		+= assabet.o
-led-$(CONFIG_SA1100_ASSABET)		+= leds-assabet.o
 obj-$(CONFIG_ASSABET_NEPONSET)		+= neponset.o
 
 obj-$(CONFIG_SA1100_BADGE4)		+= badge4.o
-led-$(CONFIG_SA1100_BADGE4)		+= leds-badge4.o
 
 obj-$(CONFIG_SA1100_CERF)		+= cerf.o
-led-$(CONFIG_SA1100_CERF)		+= leds-cerf.o
 
 obj-$(CONFIG_SA1100_COLLIE)		+= collie.o
 
@@ -29,13 +25,11 @@ obj-$(CONFIG_SA1100_H3100)		+= h3100.o h3xxx.o
 obj-$(CONFIG_SA1100_H3600)		+= h3600.o h3xxx.o
 
 obj-$(CONFIG_SA1100_HACKKIT)		+= hackkit.o
-led-$(CONFIG_SA1100_HACKKIT)		+= leds-hackkit.o
 
 obj-$(CONFIG_SA1100_JORNADA720)		+= jornada720.o
 obj-$(CONFIG_SA1100_JORNADA720_SSP)	+= jornada720_ssp.o
 
 obj-$(CONFIG_SA1100_LART)		+= lart.o
-led-$(CONFIG_SA1100_LART)		+= leds-lart.o
 
 obj-$(CONFIG_SA1100_NANOENGINE)		+= nanoengine.o
 obj-$(CONFIG_PCI_NANOENGINE)		+= pci-nanoengine.o
@@ -46,9 +40,6 @@ obj-$(CONFIG_SA1100_SHANNON)		+= shannon.o
 
 obj-$(CONFIG_SA1100_SIMPAD)		+= simpad.o
 
-# LEDs support
-obj-$(CONFIG_LEDS) += $(led-y)
-
 # Miscellaneous functions
 obj-$(CONFIG_PM)			+= pm.o sleep.o
 obj-$(CONFIG_SA1100_SSP)		+= ssp.o
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index d1dc7f1..1710ed1 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -20,6 +20,8 @@
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
 
 #include <video/sa1100fb.h>
 
@@ -362,7 +364,7 @@ static void __init assabet_init(void)
 static void __init map_sa1100_gpio_regs( void )
 {
 	unsigned long phys = __PREG(GPLR) & PMD_MASK;
-	unsigned long virt = io_p2v(phys);
+	unsigned long virt = (unsigned long)io_p2v(phys);
 	int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO);
 	pmd_t *pmd;
 
@@ -529,6 +531,89 @@ static void __init assabet_map_io(void)
 	sa1100_register_uart(2, 3);
 }
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct assabet_led {
+	struct led_classdev cdev;
+	u32 mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} assabet_leds[] = {
+	{ "assabet:red", "cpu0",},
+	{ "assabet:green", "heartbeat", },
+};
+
+/*
+ * The LED control in Assabet is reversed:
+ *  - setting bit means turn off LED
+ *  - clearing bit means turn on LED
+ */
+static void assabet_led_set(struct led_classdev *cdev,
+		enum led_brightness b)
+{
+	struct assabet_led *led = container_of(cdev,
+			struct assabet_led, cdev);
+
+	if (b != LED_OFF)
+		ASSABET_BCR_clear(led->mask);
+	else
+		ASSABET_BCR_set(led->mask);
+}
+
+static enum led_brightness assabet_led_get(struct led_classdev *cdev)
+{
+	struct assabet_led *led = container_of(cdev,
+			struct assabet_led, cdev);
+
+	return (ASSABET_BCR & led->mask) ? LED_OFF : LED_FULL;
+}
+
+static int __init assabet_leds_init(void)
+{
+	int i;
+
+	if (!machine_is_assabet())
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(assabet_leds); i++) {
+		struct assabet_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = assabet_leds[i].name;
+		led->cdev.brightness_set = assabet_led_set;
+		led->cdev.brightness_get = assabet_led_get;
+		led->cdev.default_trigger = assabet_leds[i].trigger;
+
+		if (!i)
+			led->mask = ASSABET_BCR_LED_RED;
+		else
+			led->mask = ASSABET_BCR_LED_GREEN;
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(assabet_leds_init);
+#endif
 
 MACHINE_START(ASSABET, "Intel-Assabet")
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index b30fb99..038df48 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -22,6 +22,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -76,8 +78,36 @@ static struct platform_device sa1111_device = {
 	.resource	= sa1111_resources,
 };
 
+/* LEDs */
+struct gpio_led badge4_gpio_leds[] = {
+	{
+		.name			= "badge4:red",
+		.default_trigger	= "heartbeat",
+		.gpio			= 7,
+	},
+	{
+		.name			= "badge4:green",
+		.default_trigger	= "cpu0",
+		.gpio			= 9,
+	},
+};
+
+static struct gpio_led_platform_data badge4_gpio_led_info = {
+	.leds		= badge4_gpio_leds,
+	.num_leds	= ARRAY_SIZE(badge4_gpio_leds),
+};
+
+static struct platform_device badge4_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &badge4_gpio_led_info,
+	}
+};
+
 static struct platform_device *devices[] __initdata = {
 	&sa1111_device,
+	&badge4_leds,
 };
 
 static int __init badge4_sa1111_init(void)
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index 09d7f4b..5240f10 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -17,6 +17,8 @@
 #include <linux/irq.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
 
 #include <mach/hardware.h>
 #include <asm/setup.h>
@@ -43,8 +45,48 @@ static struct platform_device cerfuart2_device = {
 	.resource	= cerfuart2_resources,
 };
 
+/* LEDs */
+struct gpio_led cerf_gpio_leds[] = {
+	{
+		.name			= "cerf:d0",
+		.default_trigger	= "heartbeat",
+		.gpio			= 0,
+	},
+	{
+		.name			= "cerf:d1",
+		.default_trigger	= "cpu0",
+		.gpio			= 1,
+	},
+	{
+		.name			= "cerf:d2",
+		.default_trigger	= "default-on",
+		.gpio			= 2,
+	},
+	{
+		.name			= "cerf:d3",
+		.default_trigger	= "default-on",
+		.gpio			= 3,
+	},
+
+};
+
+static struct gpio_led_platform_data cerf_gpio_led_info = {
+	.leds		= cerf_gpio_leds,
+	.num_leds	= ARRAY_SIZE(cerf_gpio_leds),
+};
+
+static struct platform_device cerf_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &cerf_gpio_led_info,
+	}
+};
+
+
 static struct platform_device *cerf_devices[] __initdata = {
 	&cerfuart2_device,
+	&cerf_leds,
 };
 
 #ifdef CONFIG_SA1100_CERF_FLASH_32MB
diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c
index 675bf8e..48c45b0 100644
--- a/arch/arm/mach-sa1100/cpu-sa1110.c
+++ b/arch/arm/mach-sa1100/cpu-sa1110.c
@@ -19,6 +19,7 @@
 #include <linux/cpufreq.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
index 7f86bd9..fc106aa 100644
--- a/arch/arm/mach-sa1100/hackkit.c
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -21,6 +21,10 @@
 #include <linux/serial_core.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/tty.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach-types.h>
 #include <asm/setup.h>
@@ -183,9 +187,37 @@ static struct flash_platform_data hackkit_flash_data = {
 static struct resource hackkit_flash_resource =
 	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
+/* LEDs */
+struct gpio_led hackkit_gpio_leds[] = {
+	{
+		.name			= "hackkit:red",
+		.default_trigger	= "cpu0",
+		.gpio			= 22,
+	},
+	{
+		.name			= "hackkit:green",
+		.default_trigger	= "heartbeat",
+		.gpio			= 23,
+	},
+};
+
+static struct gpio_led_platform_data hackkit_gpio_led_info = {
+	.leds		= hackkit_gpio_leds,
+	.num_leds	= ARRAY_SIZE(hackkit_gpio_leds),
+};
+
+static struct platform_device hackkit_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &hackkit_gpio_led_info,
+	}
+};
+
 static void __init hackkit_init(void)
 {
 	sa11x0_register_mtd(&hackkit_flash_data, &hackkit_flash_resource, 1);
+	platform_device_register(&hackkit_leds);
 }
 
 /**********************************************************************
diff --git a/arch/arm/mach-sa1100/include/mach/SA-1100.h b/arch/arm/mach-sa1100/include/mach/SA-1100.h
index 3f2d1b6..0ac6cc0 100644
--- a/arch/arm/mach-sa1100/include/mach/SA-1100.h
+++ b/arch/arm/mach-sa1100/include/mach/SA-1100.h
@@ -830,14 +830,14 @@
  *              	(read/write).
  */
 
-#define OSMR0  		__REG(0x90000000)  /* OS timer Match Reg. 0 */
-#define OSMR1  		__REG(0x90000004)  /* OS timer Match Reg. 1 */
-#define OSMR2  		__REG(0x90000008)  /* OS timer Match Reg. 2 */
-#define OSMR3  		__REG(0x9000000c)  /* OS timer Match Reg. 3 */
-#define OSCR   	__REG(0x90000010)  /* OS timer Counter Reg. */
-#define OSSR   	__REG(0x90000014	)  /* OS timer Status Reg. */
-#define OWER   	__REG(0x90000018	)  /* OS timer Watch-dog Enable Reg. */
-#define OIER   	__REG(0x9000001C	)  /* OS timer Interrupt Enable Reg. */
+#define OSMR0  		io_p2v(0x90000000)  /* OS timer Match Reg. 0 */
+#define OSMR1  		io_p2v(0x90000004)  /* OS timer Match Reg. 1 */
+#define OSMR2  		io_p2v(0x90000008)  /* OS timer Match Reg. 2 */
+#define OSMR3  		io_p2v(0x9000000c)  /* OS timer Match Reg. 3 */
+#define OSCR   		io_p2v(0x90000010)  /* OS timer Counter Reg. */
+#define OSSR   		io_p2v(0x90000014)  /* OS timer Status Reg. */
+#define OWER   		io_p2v(0x90000018)  /* OS timer Watch-dog Enable Reg. */
+#define OIER  	 	io_p2v(0x9000001C)  /* OS timer Interrupt Enable Reg. */
 
 #define OSSR_M(Nb)	        	/* Match detected [0..3]           */ \
                 	(0x00000001 << (Nb))
diff --git a/arch/arm/mach-sa1100/include/mach/gpio.h b/arch/arm/mach-sa1100/include/mach/gpio.h
index a38fc4f..6a9eecf 100644
--- a/arch/arm/mach-sa1100/include/mach/gpio.h
+++ b/arch/arm/mach-sa1100/include/mach/gpio.h
@@ -24,6 +24,7 @@
 #ifndef __ASM_ARCH_SA1100_GPIO_H
 #define __ASM_ARCH_SA1100_GPIO_H
 
+#include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm-generic/gpio.h>
diff --git a/arch/arm/mach-sa1100/include/mach/hardware.h b/arch/arm/mach-sa1100/include/mach/hardware.h
index 99f5856..cbedd75 100644
--- a/arch/arm/mach-sa1100/include/mach/hardware.h
+++ b/arch/arm/mach-sa1100/include/mach/hardware.h
@@ -32,7 +32,7 @@
 #define PIO_START       0x80000000	/* physical start of IO space */
 
 #define io_p2v( x )             \
-   ( (((x)&0x00ffffff) | (((x)&0x30000000)>>VIO_SHIFT)) + VIO_BASE )
+   IOMEM( (((x)&0x00ffffff) | (((x)&0x30000000)>>VIO_SHIFT)) + VIO_BASE )
 #define io_v2p( x )             \
    ( (((x)&0x00ffffff) | (((x)&(0x30000000>>VIO_SHIFT))<<VIO_SHIFT)) + PIO_START )
 
@@ -47,6 +47,8 @@
 #define CPU_SA1110_ID	(0x6901b110)
 #define CPU_SA1110_MASK	(0xfffffff0)
 
+#define __MREG(x)	IOMEM(io_p2v(x))
+
 #ifndef __ASSEMBLY__
 
 #include <asm/cputype.h>
@@ -56,7 +58,7 @@
 #define cpu_is_sa1100()	((read_cpuid_id() & CPU_SA1100_MASK) == CPU_SA1100_ID)
 #define cpu_is_sa1110()	((read_cpuid_id() & CPU_SA1110_MASK) == CPU_SA1110_ID)
 
-# define __REG(x)	(*((volatile unsigned long *)io_p2v(x)))
+# define __REG(x)	(*((volatile unsigned long __iomem *)io_p2v(x)))
 # define __PREG(x)	(io_v2p((unsigned long)&(x)))
 
 static inline unsigned long get_clock_tick_rate(void)
diff --git a/arch/arm/mach-sa1100/include/mach/uncompress.h b/arch/arm/mach-sa1100/include/mach/uncompress.h
index 6cb39dd..5cf71da 100644
--- a/arch/arm/mach-sa1100/include/mach/uncompress.h
+++ b/arch/arm/mach-sa1100/include/mach/uncompress.h
@@ -8,6 +8,8 @@
 
 #include "hardware.h"
 
+#define IOMEM(x)	(x)
+
 /*
  * The following code assumes the serial port has already been
  * initialized by the bootloader.  We search for the first enabled
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
index 516ccc2..2124f1fc 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/ioport.h>
 #include <linux/syscore_ops.h>
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index b775a0a..b2ce04b 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -5,6 +5,9 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/tty.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
 
 #include <video/sa1100fb.h>
 
@@ -126,6 +129,27 @@ static struct map_desc lart_io_desc[] __initdata = {
 	}
 };
 
+/* LEDs */
+struct gpio_led lart_gpio_leds[] = {
+	{
+		.name			= "lart:red",
+		.default_trigger	= "cpu0",
+		.gpio			= 23,
+	},
+};
+
+static struct gpio_led_platform_data lart_gpio_led_info = {
+	.leds		= lart_gpio_leds,
+	.num_leds	= ARRAY_SIZE(lart_gpio_leds),
+};
+
+static struct platform_device lart_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &lart_gpio_led_info,
+	}
+};
 static void __init lart_map_io(void)
 {
 	sa1100_map_io();
@@ -139,6 +163,8 @@ static void __init lart_map_io(void)
 	GPDR |= GPIO_UART_TXD;
 	GPDR &= ~GPIO_UART_RXD;
 	PPAR |= PPAR_UPR;
+
+	platform_device_register(&lart_leds);
 }
 
 MACHINE_START(LART, "LART")
diff --git a/arch/arm/mach-sa1100/leds-assabet.c b/arch/arm/mach-sa1100/leds-assabet.c
deleted file mode 100644
index 3699176..0000000
--- a/arch/arm/mach-sa1100/leds-assabet.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-assabet.c
- *
- * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
- *
- * Original (leds-footbridge.c) by Russell King
- *
- * Assabet uses the LEDs as follows:
- *   - Green - toggles state every 50 timer interrupts
- *   - Red   - on if system is not idle
- */
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <mach/assabet.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define ASSABET_BCR_LED_MASK	(ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED)
-
-void assabet_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-		ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state);
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= ASSABET_BCR_LED_GREEN;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= ASSABET_BCR_LED_RED;
-		break;
-
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~ASSABET_BCR_LED_RED;
-		break;
-#endif
-
-	case led_halted:
-		break;
-
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~ASSABET_BCR_LED_GREEN;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= ASSABET_BCR_LED_GREEN;
-		break;
-
-	case led_amber_on:
-		break;
-
-	case led_amber_off:
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~ASSABET_BCR_LED_RED;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= ASSABET_BCR_LED_RED;
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED)
-		ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state);
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-badge4.c b/arch/arm/mach-sa1100/leds-badge4.c
deleted file mode 100644
index f99fac3..0000000
--- a/arch/arm/mach-sa1100/leds-badge4.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-badge4.c
- *
- * Author: Christopher Hoover <ch@hpl.hp.com>
- * Copyright (C) 2002 Hewlett-Packard Company
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_RED		GPIO_GPIO(7)
-#define LED_GREEN       GPIO_GPIO(9)
-#define LED_MASK	(LED_RED|LED_GREEN)
-
-#define LED_IDLE	LED_GREEN
-#define LED_TIMER	LED_RED
-
-void badge4_leds_event(led_event_t evt)
-{
-        unsigned long flags;
-
-	local_irq_save(flags);
-
-        switch (evt) {
-        case led_start:
-		GPDR |= LED_MASK;
-                hw_led_state = LED_MASK;
-                led_state = LED_STATE_ENABLED;
-                break;
-
-        case led_stop:
-                led_state &= ~LED_STATE_ENABLED;
-                break;
-
-        case led_claim:
-                led_state |= LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-
-        case led_release:
-                led_state &= ~LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-
-#ifdef CONFIG_LEDS_TIMER
-        case led_timer:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state ^= LED_TIMER;
-                break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-        case led_idle_start:
-		/* LED off when system is idle */
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_IDLE;
-                break;
-
-        case led_idle_end:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_IDLE;
-                break;
-#endif
-
-        case led_red_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_RED;
-                break;
-
-        case led_red_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_RED;
-                break;
-
-        case led_green_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_GREEN;
-                break;
-
-        case led_green_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_GREEN;
-                break;
-
-	default:
-		break;
-        }
-
-        if  (led_state & LED_STATE_ENABLED) {
-                GPSR = hw_led_state;
-                GPCR = hw_led_state ^ LED_MASK;
-        }
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-cerf.c b/arch/arm/mach-sa1100/leds-cerf.c
deleted file mode 100644
index 040540f..0000000
--- a/arch/arm/mach-sa1100/leds-cerf.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-cerf.c
- *
- * Author: ???
- */
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_D0          GPIO_GPIO(0)
-#define LED_D1          GPIO_GPIO(1)
-#define LED_D2          GPIO_GPIO(2)
-#define LED_D3          GPIO_GPIO(3)
-#define LED_MASK        (LED_D0|LED_D1|LED_D2|LED_D3)
-
-void cerf_leds_event(led_event_t evt)
-{
-        unsigned long flags;
-
-	local_irq_save(flags);
-
-        switch (evt) {
-        case led_start:
-                hw_led_state = LED_MASK;
-                led_state = LED_STATE_ENABLED;
-                break;
-
-        case led_stop:
-                led_state &= ~LED_STATE_ENABLED;
-                break;
-
-        case led_claim:
-                led_state |= LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-        case led_release:
-                led_state &= ~LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-
-#ifdef CONFIG_LEDS_TIMER
-        case led_timer:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state ^= LED_D0;
-                break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-        case led_idle_start:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D1;
-                break;
-
-        case led_idle_end:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D1;
-                break;
-#endif
-        case led_green_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D2;
-                break;
-
-        case led_green_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D2;
-                break;
-
-        case led_amber_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D3;
-                break;
-
-        case led_amber_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D3;
-                break;
-
-        case led_red_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D1;
-                break;
-
-        case led_red_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D1;
-                break;
-
-        default:
-                break;
-        }
-
-        if  (led_state & LED_STATE_ENABLED) {
-                GPSR = hw_led_state;
-                GPCR = hw_led_state ^ LED_MASK;
-        }
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-hackkit.c b/arch/arm/mach-sa1100/leds-hackkit.c
deleted file mode 100644
index 6a23524..0000000
--- a/arch/arm/mach-sa1100/leds-hackkit.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-hackkit.c
- *
- * based on leds-lart.c
- *
- * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000
- * (C) Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>, 2002
- *
- * The HackKit has two leds (GPIO 22/23). The red led (gpio 22) is used
- * as cpu led, the green one is used as timer led.
- */
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_GREEN    GPIO_GPIO23
-#define LED_RED    GPIO_GPIO22
-#define LED_MASK  (LED_RED | LED_GREEN)
-
-void hackkit_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch(evt) {
-		case led_start:
-			/* pin 22/23 are outputs */
-			GPDR |= LED_MASK;
-			hw_led_state = LED_MASK;
-			led_state = LED_STATE_ENABLED;
-			break;
-
-		case led_stop:
-			led_state &= ~LED_STATE_ENABLED;
-			break;
-
-		case led_claim:
-			led_state |= LED_STATE_CLAIMED;
-			hw_led_state = LED_MASK;
-			break;
-
-		case led_release:
-			led_state &= ~LED_STATE_CLAIMED;
-			hw_led_state = LED_MASK;
-			break;
-
-#ifdef CONFIG_LEDS_TIMER
-		case led_timer:
-			if (!(led_state & LED_STATE_CLAIMED))
-				hw_led_state ^= LED_GREEN;
-			break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-		case led_idle_start:
-			/* The LART people like the LED to be off when the
-			   system is idle... */
-			if (!(led_state & LED_STATE_CLAIMED))
-				hw_led_state &= ~LED_RED;
-			break;
-
-		case led_idle_end:
-			/* ... and on if the system is not idle */
-			if (!(led_state & LED_STATE_CLAIMED))
-				hw_led_state |= LED_RED;
-			break;
-#endif
-
-		case led_red_on:
-			if (led_state & LED_STATE_CLAIMED)
-				hw_led_state &= ~LED_RED;
-			break;
-
-		case led_red_off:
-			if (led_state & LED_STATE_CLAIMED)
-				hw_led_state |= LED_RED;
-			break;
-
-		case led_green_on:
-			if (led_state & LED_STATE_CLAIMED)
-				hw_led_state &= ~LED_GREEN;
-			break;
-
-		case led_green_off:
-			if (led_state & LED_STATE_CLAIMED)
-				hw_led_state |= LED_GREEN;
-			break;
-
-		default:
-			break;
-	}
-
-	/* Now set the GPIO state, or nothing will happen at all */
-	if (led_state & LED_STATE_ENABLED) {
-		GPSR = hw_led_state;
-		GPCR = hw_led_state ^ LED_MASK;
-	}
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-lart.c b/arch/arm/mach-sa1100/leds-lart.c
deleted file mode 100644
index a51830c..0000000
--- a/arch/arm/mach-sa1100/leds-lart.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-lart.c
- *
- * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000
- *
- * LART uses the LED as follows:
- *   - GPIO23 is the LED, on if system is not idle
- *  You can use both CONFIG_LEDS_CPU and CONFIG_LEDS_TIMER at the same
- *  time, but in that case the timer events will still dictate the
- *  pace of the LED.
- */
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_23    GPIO_GPIO23
-#define LED_MASK  (LED_23)
-
-void lart_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch(evt) {
-	case led_start:
-		/* pin 23 is output pin */
-		GPDR |= LED_23;
-		hw_led_state = LED_MASK;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = LED_MASK;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = LED_MASK;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= LED_23;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		/* The LART people like the LED to be off when the
-                   system is idle... */
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~LED_23;
-		break;
-
-	case led_idle_end:
-		/* ... and on if the system is not idle */
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= LED_23;
-		break;
-#endif
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~LED_23;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= LED_23;
-		break;
-
-	default:
-		break;
-	}
-
-	/* Now set the GPIO state, or nothing will happen at all */
-	if (led_state & LED_STATE_ENABLED) {
-		GPSR = hw_led_state;
-		GPCR = hw_led_state ^ LED_MASK;
-	}
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds.c b/arch/arm/mach-sa1100/leds.c
deleted file mode 100644
index 5fe71a0..0000000
--- a/arch/arm/mach-sa1100/leds.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds.c
- *
- * SA1100 LEDs dispatcher
- *
- * Copyright (C) 2001 Nicolas Pitre
- */
-#include <linux/compiler.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include "leds.h"
-
-static int __init
-sa1100_leds_init(void)
-{
-	if (machine_is_assabet())
-		leds_event = assabet_leds_event;
-	if (machine_is_consus())
-		leds_event = consus_leds_event;
-	if (machine_is_badge4())
-		leds_event = badge4_leds_event;
-	if (machine_is_brutus())
-		leds_event = brutus_leds_event;
-	if (machine_is_cerf())
-		leds_event = cerf_leds_event;
-	if (machine_is_flexanet())
-		leds_event = flexanet_leds_event;
-	if (machine_is_graphicsclient())
-		leds_event = graphicsclient_leds_event;
-	if (machine_is_hackkit())
-		leds_event = hackkit_leds_event;
-	if (machine_is_lart())
-		leds_event = lart_leds_event;
-	if (machine_is_pfs168())
-		leds_event = pfs168_leds_event;
-	if (machine_is_graphicsmaster())
-		leds_event = graphicsmaster_leds_event;
-	if (machine_is_adsbitsy())
-		leds_event = adsbitsy_leds_event;
-	if (machine_is_pt_system3())
-		leds_event = system3_leds_event;
-
-	leds_event(led_start);
-	return 0;
-}
-
-core_initcall(sa1100_leds_init);
diff --git a/arch/arm/mach-sa1100/leds.h b/arch/arm/mach-sa1100/leds.h
deleted file mode 100644
index 776b602..0000000
--- a/arch/arm/mach-sa1100/leds.h
+++ /dev/null
@@ -1,13 +0,0 @@
-extern void assabet_leds_event(led_event_t evt);
-extern void badge4_leds_event(led_event_t evt);
-extern void consus_leds_event(led_event_t evt);
-extern void brutus_leds_event(led_event_t evt);
-extern void cerf_leds_event(led_event_t evt);
-extern void flexanet_leds_event(led_event_t evt);
-extern void graphicsclient_leds_event(led_event_t evt);
-extern void hackkit_leds_event(led_event_t evt);
-extern void lart_leds_event(led_event_t evt);
-extern void pfs168_leds_event(led_event_t evt);
-extern void graphicsmaster_leds_event(led_event_t evt);
-extern void adsbitsy_leds_event(led_event_t evt);
-extern void system3_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c
index 690cf0c..6645d1e 100644
--- a/arch/arm/mach-sa1100/pm.c
+++ b/arch/arm/mach-sa1100/pm.c
@@ -23,6 +23,7 @@
  * 				Storage is local on the stack now.
  */
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/suspend.h>
 #include <linux/errno.h>
 #include <linux/time.h>
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 6af26e8..80702c9 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -22,7 +22,7 @@
 
 static u32 notrace sa1100_read_sched_clock(void)
 {
-	return OSCR;
+	return readl_relaxed(OSCR);
 }
 
 #define MIN_OSCR_DELTA 2
@@ -32,8 +32,8 @@ static irqreturn_t sa1100_ost0_interrupt(int irq, void *dev_id)
 	struct clock_event_device *c = dev_id;
 
 	/* Disarm the compare/match, signal the event. */
-	OIER &= ~OIER_E0;
-	OSSR = OSSR_M0;
+	writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
+	writel_relaxed(OSSR_M0, OSSR);
 	c->event_handler(c);
 
 	return IRQ_HANDLED;
@@ -44,10 +44,10 @@ sa1100_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c)
 {
 	unsigned long next, oscr;
 
-	OIER |= OIER_E0;
-	next = OSCR + delta;
-	OSMR0 = next;
-	oscr = OSCR;
+	writel_relaxed(readl_relaxed(OIER) | OIER_E0, OIER);
+	next = readl_relaxed(OSCR) + delta;
+	writel_relaxed(next, OSMR0);
+	oscr = readl_relaxed(OSCR);
 
 	return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
 }
@@ -59,8 +59,8 @@ sa1100_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c)
 	case CLOCK_EVT_MODE_ONESHOT:
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
-		OIER &= ~OIER_E0;
-		OSSR = OSSR_M0;
+		writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
+		writel_relaxed(OSSR_M0, OSSR);
 		break;
 
 	case CLOCK_EVT_MODE_RESUME:
@@ -86,8 +86,8 @@ static struct irqaction sa1100_timer_irq = {
 
 static void __init sa1100_timer_init(void)
 {
-	OIER = 0;
-	OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
+	writel_relaxed(0, OIER);
+	writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
 
 	setup_sched_clock(sa1100_read_sched_clock, 32, 3686400);
 
@@ -100,7 +100,7 @@ static void __init sa1100_timer_init(void)
 
 	setup_irq(IRQ_OST0, &sa1100_timer_irq);
 
-	clocksource_mmio_init(&OSCR, "oscr", CLOCK_TICK_RATE, 200, 32,
+	clocksource_mmio_init(OSCR, "oscr", CLOCK_TICK_RATE, 200, 32,
 		clocksource_mmio_readl_up);
 	clockevents_register_device(&ckevt_sa1100_osmr0);
 }
@@ -110,26 +110,26 @@ unsigned long osmr[4], oier;
 
 static void sa1100_timer_suspend(void)
 {
-	osmr[0] = OSMR0;
-	osmr[1] = OSMR1;
-	osmr[2] = OSMR2;
-	osmr[3] = OSMR3;
-	oier = OIER;
+	osmr[0] = readl_relaxed(OSMR0);
+	osmr[1] = readl_relaxed(OSMR1);
+	osmr[2] = readl_relaxed(OSMR2);
+	osmr[3] = readl_relaxed(OSMR3);
+	oier = readl_relaxed(OIER);
 }
 
 static void sa1100_timer_resume(void)
 {
-	OSSR = 0x0f;
-	OSMR0 = osmr[0];
-	OSMR1 = osmr[1];
-	OSMR2 = osmr[2];
-	OSMR3 = osmr[3];
-	OIER = oier;
+	writel_relaxed(0x0f, OSSR);
+	writel_relaxed(osmr[0], OSMR0);
+	writel_relaxed(osmr[1], OSMR1);
+	writel_relaxed(osmr[2], OSMR2);
+	writel_relaxed(osmr[3], OSMR3);
+	writel_relaxed(oier, OIER);
 
 	/*
 	 * OSMR0 is the system timer: make sure OSCR is sufficiently behind
 	 */
-	OSCR = OSMR0 - LATCH;
+	writel_relaxed(OSMR0 - LATCH, OSCR);
 }
 #else
 #define sa1100_timer_suspend NULL
diff --git a/arch/arm/mach-shark/Makefile b/arch/arm/mach-shark/Makefile
index 45be9b0..2965718 100644
--- a/arch/arm/mach-shark/Makefile
+++ b/arch/arm/mach-shark/Makefile
@@ -4,9 +4,7 @@
 
 # Object file lists.
 
-obj-y			:= core.o dma.o irq.o pci.o
+obj-y			:= core.o dma.o irq.o pci.o leds.o
 obj-m			:=
 obj-n			:=
 obj-			:=
-
-obj-$(CONFIG_LEDS)	+= leds.o
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index 2704bcd..c709979 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -13,7 +13,6 @@
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/param.h>
 #include <asm/system_misc.h>
 
diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c
index 2560907..081c778 100644
--- a/arch/arm/mach-shark/leds.c
+++ b/arch/arm/mach-shark/leds.c
@@ -1,165 +1,117 @@
 /*
- * arch/arm/mach-shark/leds.c
- * by Alexander Schulz
- *
- * derived from:
- * arch/arm/kernel/leds-footbridge.c
- * Copyright (C) 1998-1999 Russell King
- *
  * DIGITAL Shark LED control routines.
  *
- * The leds use is as follows:
- *  - Green front - toggles state every 50 timer interrupts
- *  - Amber front - Unused, this is a dual color led (Amber/Green)
- *  - Amber back  - On if system is not idle
+ * Driver for the 3 user LEDs found on the Shark
+ * Based on Versatile and RealView machine LED code
  *
- * Changelog:
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Bryan Wu <bryan.wu@canonical.com>
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
 #include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
-#include <asm/leds.h>
+#include <asm/mach-types.h>
 
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct shark_led {
+	struct led_classdev cdev;
+	u8 mask;
+};
 
-#define SEQUOIA_LED_GREEN       (1<<6)
-#define SEQUOIA_LED_AMBER       (1<<5)
-#define SEQUOIA_LED_BACK        (1<<7)
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} shark_leds[] = {
+	{ "shark:amber0", "default-on", },	/* Bit 5 */
+	{ "shark:green", "heartbeat", },	/* Bit 6 */
+	{ "shark:amber1", "cpu0" },		/* Bit 7 */
+};
+
+static u16 led_reg_read(void)
+{
+	outw(0x09, 0x24);
+	return inw(0x26);
+}
 
-static char led_state;
-static short hw_led_state;
-static short saved_state;
+static void led_reg_write(u16 value)
+{
+	outw(0x09, 0x24);
+	outw(value, 0x26);
+}
 
-static DEFINE_RAW_SPINLOCK(leds_lock);
+static void shark_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
+{
+	struct shark_led *led = container_of(cdev,
+						 struct shark_led, cdev);
+	u16 reg = led_reg_read();
 
-short sequoia_read(int addr) {
-  outw(addr,0x24);
-  return inw(0x26);
-}
+	if (b != LED_OFF)
+		reg |= led->mask;
+	else
+		reg &= ~led->mask;
 
-void sequoia_write(short value,short addr) {
-  outw(addr,0x24);
-  outw(value,0x26);
+	led_reg_write(reg);
 }
 
-static void sequoia_leds_event(led_event_t evt)
+static enum led_brightness shark_led_get(struct led_classdev *cdev)
 {
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&leds_lock, flags);
+	struct shark_led *led = container_of(cdev,
+						 struct shark_led, cdev);
+	u16 reg = led_reg_read();
 
-	hw_led_state = sequoia_read(0x09);
+	return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
 
-	switch (evt) {
-	case led_start:
-		hw_led_state |= SEQUOIA_LED_GREEN;
-		hw_led_state |= SEQUOIA_LED_AMBER;
-#ifdef CONFIG_LEDS_CPU
-		hw_led_state |= SEQUOIA_LED_BACK;
-#else
-		hw_led_state &= ~SEQUOIA_LED_BACK;
-#endif
-		led_state |= LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		hw_led_state &= ~SEQUOIA_LED_BACK;
-		hw_led_state |= SEQUOIA_LED_GREEN;
-		hw_led_state |= SEQUOIA_LED_AMBER;
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		saved_state = hw_led_state;
-		hw_led_state &= ~SEQUOIA_LED_BACK;
-		hw_led_state |= SEQUOIA_LED_GREEN;
-		hw_led_state |= SEQUOIA_LED_AMBER;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = saved_state;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= SEQUOIA_LED_GREEN;
-		break;
-#endif
+static int __init shark_leds_init(void)
+{
+	int i;
+	u16 reg;
 
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~SEQUOIA_LED_BACK;
-		break;
+	if (!machine_is_shark())
+		return -ENODEV;
 
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= SEQUOIA_LED_BACK;
-		break;
-#endif
+	for (i = 0; i < ARRAY_SIZE(shark_leds); i++) {
+		struct shark_led *led;
 
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~SEQUOIA_LED_GREEN;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= SEQUOIA_LED_GREEN;
-		break;
-
-	case led_amber_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~SEQUOIA_LED_AMBER;
-		break;
-
-	case led_amber_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= SEQUOIA_LED_AMBER;
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= SEQUOIA_LED_BACK;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~SEQUOIA_LED_BACK;
-		break;
-
-	default:
-		break;
-	}
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
 
-	if  (led_state & LED_STATE_ENABLED)
-		sequoia_write(hw_led_state,0x09);
+		led->cdev.name = shark_leds[i].name;
+		led->cdev.brightness_set = shark_led_set;
+		led->cdev.brightness_get = shark_led_get;
+		led->cdev.default_trigger = shark_leds[i].trigger;
 
-	raw_spin_unlock_irqrestore(&leds_lock, flags);
-}
+		/* Count in 5 bits offset */
+		led->mask = BIT(i + 5);
 
-static int __init leds_init(void)
-{
-	extern void (*leds_event)(led_event_t);
-	short temp;
-	
-	leds_event = sequoia_leds_event;
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
 
 	/* Make LEDs independent of power-state */
-	request_region(0x24,4,"sequoia");
-	temp = sequoia_read(0x09);
-	temp |= 1<<10;
-	sequoia_write(temp,0x09);
-	leds_event(led_start);
+	request_region(0x24, 4, "led_reg");
+	reg = led_reg_read();
+	reg |= 1 << 10;
+	led_reg_write(reg);
+
 	return 0;
 }
 
-__initcall(leds_init);
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(shark_leds_init);
+#endif
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index df33909..4c3b031 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -122,6 +122,7 @@ config MACH_KZM9G
 	depends on ARCH_SH73A0
 	select ARCH_REQUIRE_GPIOLIB
 	select USE_OF
+	select SND_SOC_AK4642 if SND_SIMPLE_CARD
 
 comment "SH-Mobile System Configuration"
 
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index 9e37026..a513ebe 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -37,14 +37,18 @@
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <mach/common.h>
 #include <mach/irqs.h>
+#include <mach/r8a7740.h>
+#include <media/mt9t112.h>
+#include <media/sh_mobile_ceu.h>
+#include <media/soc_camera.h>
 #include <asm/page.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 #include <asm/hardware/cache-l2x0.h>
-#include <mach/r8a7740.h>
 #include <video/sh_mobile_lcdc.h>
+#include <video/sh_mobile_hdmi.h>
 
 /*
  * CON1		Camera Module
@@ -384,6 +388,103 @@ static struct platform_device lcdc0_device = {
 	},
 };
 
+/*
+ * LCDC1/HDMI
+ */
+static struct sh_mobile_hdmi_info hdmi_info = {
+	.flags		= HDMI_OUTPUT_PUSH_PULL |
+			  HDMI_OUTPUT_POLARITY_HI |
+			  HDMI_32BIT_REG |
+			  HDMI_HAS_HTOP1 |
+			  HDMI_SND_SRC_SPDIF,
+};
+
+static struct resource hdmi_resources[] = {
+	[0] = {
+		.name	= "HDMI",
+		.start	= 0xe6be0000,
+		.end	= 0xe6be03ff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x1700),
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.name	= "HDMI emma3pf",
+		.start	= 0xe6be4000,
+		.end	= 0xe6be43ff,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device hdmi_device = {
+	.name		= "sh-mobile-hdmi",
+	.num_resources	= ARRAY_SIZE(hdmi_resources),
+	.resource	= hdmi_resources,
+	.id             = -1,
+	.dev	= {
+		.platform_data	= &hdmi_info,
+	},
+};
+
+static const struct fb_videomode lcdc1_mode = {
+	.name		= "HDMI 720p",
+	.xres		= 1280,
+	.yres		= 720,
+	.pixclock	= 13468,
+	.left_margin	= 220,
+	.right_margin	= 110,
+	.hsync_len	= 40,
+	.upper_margin	= 20,
+	.lower_margin	= 5,
+	.vsync_len	= 5,
+	.refresh	= 60,
+	.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+};
+
+static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
+	.clock_source	= LCDC_CLK_PERIPHERAL, /* HDMI clock */
+	.ch[0] = {
+		.chan			= LCDC_CHAN_MAINLCD,
+		.fourcc			= V4L2_PIX_FMT_RGB565,
+		.interface_type		= RGB24,
+		.clock_divider		= 1,
+		.flags			= LCDC_FLAGS_DWPOL,
+		.lcd_modes		= &lcdc1_mode,
+		.num_modes		= 1,
+		.tx_dev			= &hdmi_device,
+		.panel_cfg = {
+			.width	= 1280,
+			.height = 720,
+		},
+	},
+};
+
+static struct resource hdmi_lcdc_resources[] = {
+	[0] = {
+		.name	= "LCDC1",
+		.start	= 0xfe944000,
+		.end	= 0xfe948000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x1780),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device hdmi_lcdc_device = {
+	.name		= "sh_mobile_lcdc_fb",
+	.num_resources	= ARRAY_SIZE(hdmi_lcdc_resources),
+	.resource	= hdmi_lcdc_resources,
+	.id		= 1,
+	.dev	= {
+		.platform_data	= &hdmi_lcdc_info,
+		.coherent_dma_mask = ~0,
+	},
+};
+
 /* GPIO KEY */
 #define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 }
 
@@ -532,6 +633,87 @@ static struct platform_device sh_mmcif_device = {
 	.resource	= sh_mmcif_resources,
 };
 
+/* Camera */
+static int mt9t111_power(struct device *dev, int mode)
+{
+	struct clk *mclk = clk_get(NULL, "video1");
+
+	if (IS_ERR(mclk)) {
+		dev_err(dev, "can't get video1 clock\n");
+		return -EINVAL;
+	}
+
+	if (mode) {
+		/* video1 (= CON1 camera) expect 24MHz */
+		clk_set_rate(mclk, clk_round_rate(mclk, 24000000));
+		clk_enable(mclk);
+		gpio_direction_output(GPIO_PORT158, 1);
+	} else {
+		gpio_direction_output(GPIO_PORT158, 0);
+		clk_disable(mclk);
+	}
+
+	clk_put(mclk);
+
+	return 0;
+}
+
+static struct i2c_board_info i2c_camera_mt9t111 = {
+	I2C_BOARD_INFO("mt9t112", 0x3d),
+};
+
+static struct mt9t112_camera_info mt9t111_info = {
+	.divider = { 16, 0, 0, 7, 0, 10, 14, 7, 7 },
+};
+
+static struct soc_camera_link mt9t111_link = {
+	.i2c_adapter_id	= 0,
+	.bus_id		= 0,
+	.board_info	= &i2c_camera_mt9t111,
+	.power		= mt9t111_power,
+	.priv		= &mt9t111_info,
+};
+
+static struct platform_device camera_device = {
+	.name	= "soc-camera-pdrv",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &mt9t111_link,
+	},
+};
+
+/* CEU0 */
+static struct sh_mobile_ceu_info sh_mobile_ceu0_info = {
+	.flags = SH_CEU_FLAG_LOWER_8BIT,
+};
+
+static struct resource ceu0_resources[] = {
+	[0] = {
+		.name	= "CEU",
+		.start	= 0xfe910000,
+		.end	= 0xfe91009f,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = intcs_evt2irq(0x0500),
+		.flags  = IORESOURCE_IRQ,
+	},
+	[2] = {
+		/* place holder for contiguous memory */
+	},
+};
+
+static struct platform_device ceu0_device = {
+	.name		= "sh_mobile_ceu",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(ceu0_resources),
+	.resource	= ceu0_resources,
+	.dev	= {
+		.platform_data		= &sh_mobile_ceu0_info,
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
 /* I2C */
 static struct i2c_board_info i2c0_devices[] = {
 	{
@@ -549,6 +731,10 @@ static struct platform_device *eva_devices[] __initdata = {
 	&sh_eth_device,
 	&sdhi0_device,
 	&sh_mmcif_device,
+	&hdmi_device,
+	&hdmi_lcdc_device,
+	&camera_device,
+	&ceu0_device,
 };
 
 static void __init eva_clock_init(void)
@@ -587,6 +773,7 @@ static void __init eva_init(void)
 	eva_clock_init();
 
 	r8a7740_pinmux_init();
+	r8a7740_meram_workaround();
 
 	/* SCIFA1 */
 	gpio_request(GPIO_FN_SCIFA1_RXD, NULL);
@@ -706,6 +893,29 @@ static void __init eva_init(void)
 	gpio_request(GPIO_FN_MMC1_D6_PORT143,	NULL);
 	gpio_request(GPIO_FN_MMC1_D7_PORT142,	NULL);
 
+	/* CEU0 */
+	gpio_request(GPIO_FN_VIO0_D7,		NULL);
+	gpio_request(GPIO_FN_VIO0_D6,		NULL);
+	gpio_request(GPIO_FN_VIO0_D5,		NULL);
+	gpio_request(GPIO_FN_VIO0_D4,		NULL);
+	gpio_request(GPIO_FN_VIO0_D3,		NULL);
+	gpio_request(GPIO_FN_VIO0_D2,		NULL);
+	gpio_request(GPIO_FN_VIO0_D1,		NULL);
+	gpio_request(GPIO_FN_VIO0_D0,		NULL);
+	gpio_request(GPIO_FN_VIO0_CLK,		NULL);
+	gpio_request(GPIO_FN_VIO0_HD,		NULL);
+	gpio_request(GPIO_FN_VIO0_VD,		NULL);
+	gpio_request(GPIO_FN_VIO0_FIELD,	NULL);
+	gpio_request(GPIO_FN_VIO_CKO,		NULL);
+
+	/* CON1/CON15 Camera */
+	gpio_request(GPIO_PORT173, NULL); /* STANDBY */
+	gpio_request(GPIO_PORT172, NULL); /* RST */
+	gpio_request(GPIO_PORT158, NULL); /* CAM_PON */
+	gpio_direction_output(GPIO_PORT173, 0);
+	gpio_direction_output(GPIO_PORT172, 1);
+	gpio_direction_output(GPIO_PORT158, 0); /* see mt9t111_power() */
+
 	/*
 	 * CAUTION
 	 *
@@ -779,6 +989,7 @@ DT_MACHINE_START(ARMADILLO800EVA_DT, "armadillo800eva")
 	.init_irq	= r8a7740_init_irq,
 	.handle_irq	= shmobile_handle_irq_intc,
 	.init_machine	= eva_init,
+	.init_late	= shmobile_init_late,
 	.timer		= &shmobile_timer,
 	.dt_compat	= eva_boards_compat_dt,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c
index 7bc5e7d..6a33cf3 100644
--- a/arch/arm/mach-shmobile/board-kzm9d.c
+++ b/arch/arm/mach-shmobile/board-kzm9d.c
@@ -80,6 +80,7 @@ DT_MACHINE_START(KZM9D_DT, "kzm9d")
 	.init_irq	= emev2_init_irq,
 	.handle_irq	= gic_handle_irq,
 	.init_machine	= kzm9d_add_standard_devices,
+	.init_late	= shmobile_init_late,
 	.timer		= &shmobile_timer,
 	.dt_compat	= kzm9d_boards_compat_dt,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index d8e33b6..c06d04b 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -33,6 +33,8 @@
 #include <linux/smsc911x.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/videodev2.h>
+#include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
 #include <mach/irqs.h>
 #include <mach/sh73a0.h>
 #include <mach/common.h>
@@ -54,6 +56,14 @@
 #define GPIO_PCF8575_PORT15	(GPIO_NR + 13)
 #define GPIO_PCF8575_PORT16	(GPIO_NR + 14)
 
+/*
+ * FSI-AK4648
+ *
+ * this command is required when playback.
+ *
+ * # amixer set "LINEOUT Mixer DACL" on
+ */
+
 /* SMSC 9221 */
 static struct resource smsc9221_resources[] = {
 	[0] = {
@@ -267,11 +277,73 @@ static struct platform_device gpio_keys_device = {
 	},
 };
 
+/* FSI-AK4648 */
+static struct sh_fsi_platform_info fsi_info = {
+	.port_a = {
+	},
+};
+
+static struct resource fsi_resources[] = {
+	[0] = {
+		.name	= "FSI",
+		.start	= 0xEC230000,
+		.end	= 0xEC230400 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = gic_spi(146),
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device fsi_device = {
+	.name		= "sh_fsi2",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(fsi_resources),
+	.resource	= fsi_resources,
+	.dev	= {
+		.platform_data	= &fsi_info,
+	},
+};
+
+static struct asoc_simple_dai_init_info fsi2_ak4648_init_info = {
+	.fmt		= SND_SOC_DAIFMT_LEFT_J,
+	.codec_daifmt	= SND_SOC_DAIFMT_CBM_CFM,
+	.cpu_daifmt	= SND_SOC_DAIFMT_CBS_CFS,
+	.sysclk		= 11289600,
+};
+
+static struct asoc_simple_card_info fsi2_ak4648_info = {
+	.name		= "AK4648",
+	.card		= "FSI2A-AK4648",
+	.cpu_dai	= "fsia-dai",
+	.codec		= "ak4642-codec.0-0012",
+	.platform	= "sh_fsi2",
+	.codec_dai	= "ak4642-hifi",
+	.init		= &fsi2_ak4648_init_info,
+};
+
+static struct platform_device fsi_ak4648_device = {
+	.name	= "asoc-simple-card",
+	.dev	= {
+		.platform_data	= &fsi2_ak4648_info,
+	},
+};
+
 /* I2C */
 static struct pcf857x_platform_data pcf8575_pdata = {
 	.gpio_base	= GPIO_PCF8575_BASE,
 };
 
+static struct i2c_board_info i2c0_devices[] = {
+	{
+		I2C_BOARD_INFO("ak4648", 0x12),
+	},
+	{
+		I2C_BOARD_INFO("r2025sd", 0x32),
+	}
+};
+
 static struct i2c_board_info i2c1_devices[] = {
 	{
 		I2C_BOARD_INFO("st1232-ts", 0x55),
@@ -293,6 +365,8 @@ static struct platform_device *kzm_devices[] __initdata = {
 	&mmc_device,
 	&sdhi0_device,
 	&gpio_keys_device,
+	&fsi_device,
+	&fsi_ak4648_device,
 };
 
 /*
@@ -431,11 +505,19 @@ static void __init kzm_init(void)
 	gpio_request(GPIO_FN_PORT27_I2C_SCL3, NULL);
 	gpio_request(GPIO_FN_PORT28_I2C_SDA3, NULL);
 
+	/* enable FSI2 port A (ak4648) */
+	gpio_request(GPIO_FN_FSIACK,	NULL);
+	gpio_request(GPIO_FN_FSIAILR,	NULL);
+	gpio_request(GPIO_FN_FSIAIBT,	NULL);
+	gpio_request(GPIO_FN_FSIAISLD,	NULL);
+	gpio_request(GPIO_FN_FSIAOSLD,	NULL);
+
 #ifdef CONFIG_CACHE_L2X0
 	/* Early BRESP enable, Shared attribute override enable, 64K*8way */
 	l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff);
 #endif
 
+	i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices));
 	i2c_register_board_info(1, i2c1_devices, ARRAY_SIZE(i2c1_devices));
 	i2c_register_board_info(3, i2c3_devices, ARRAY_SIZE(i2c3_devices));
 
@@ -455,6 +537,7 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g")
 	.init_irq	= sh73a0_init_irq,
 	.handle_irq	= gic_handle_irq,
 	.init_machine	= kzm_init,
+	.init_late	= shmobile_init_late,
 	.timer		= &shmobile_timer,
 	.dt_compat	= kzm9g_boards_compat_dt,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index b577f7c..150122a 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -1512,6 +1512,9 @@ static void __init mackerel_init(void)
 	gpio_request(GPIO_FN_SDHID0_1, NULL);
 	gpio_request(GPIO_FN_SDHID0_0, NULL);
 
+	/* SDHI0 PORT172 card-detect IRQ26 */
+	gpio_request(GPIO_FN_IRQ26_172, NULL);
+
 #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
 	/* enable SDHI1 */
 	gpio_request(GPIO_FN_SDHICMD1, NULL);
diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c
index 26eea5f..7b9e4ab 100644
--- a/arch/arm/mach-shmobile/clock-r8a7740.c
+++ b/arch/arm/mach-shmobile/clock-r8a7740.c
@@ -43,7 +43,10 @@
 /* CPG registers */
 #define FRQCRA		0xe6150000
 #define FRQCRB		0xe6150004
+#define VCLKCR1		0xE6150008
+#define VCLKCR2		0xE615000c
 #define FRQCRC		0xe61500e0
+#define FSIACKCR	0xe6150018
 #define PLLC01CR	0xe6150028
 
 #define SUBCKCR		0xe6150080
@@ -54,6 +57,8 @@
 #define MSTPSR2		0xe6150040
 #define MSTPSR3		0xe6150048
 #define MSTPSR4		0xe615004c
+#define FSIBCKCR	0xe6150090
+#define HDMICKCR	0xe6150094
 #define SMSTPCR0	0xe6150130
 #define SMSTPCR1	0xe6150134
 #define SMSTPCR2	0xe6150138
@@ -271,6 +276,13 @@ static struct clk usb24_clk = {
 	.parent		= &usb24s_clk,
 };
 
+/* External FSIACK/FSIBCK clock */
+static struct clk fsiack_clk = {
+};
+
+static struct clk fsibck_clk = {
+};
+
 struct clk *main_clks[] = {
 	&extalr_clk,
 	&extal1_clk,
@@ -288,6 +300,8 @@ struct clk *main_clks[] = {
 	&pllc1_div2_clk,
 	&usb24s_clk,
 	&usb24_clk,
+	&fsiack_clk,
+	&fsibck_clk,
 };
 
 static void div4_kick(struct clk *clk)
@@ -313,6 +327,107 @@ static struct clk_div4_table div4_table = {
 	.kick = div4_kick,
 };
 
+/* DIV6 reparent */
+enum {
+	DIV6_HDMI,
+	DIV6_VCLK1, DIV6_VCLK2,
+	DIV6_FSIA, DIV6_FSIB,
+	DIV6_REPARENT_NR,
+};
+
+static struct clk *hdmi_parent[] = {
+	[0] = &pllc1_div2_clk,
+	[1] = &system_clk,
+	[2] = &dv_clk
+};
+
+static struct clk *vclk_parents[8] = {
+	[0] = &pllc1_div2_clk,
+	[2] = &dv_clk,
+	[3] = &usb24s_clk,
+	[4] = &extal1_div2_clk,
+	[5] = &extalr_clk,
+};
+
+static struct clk *fsia_parents[] = {
+	[0] = &pllc1_div2_clk,
+	[1] = &fsiack_clk, /* external clock */
+};
+
+static struct clk *fsib_parents[] = {
+	[0] = &pllc1_div2_clk,
+	[1] = &fsibck_clk, /* external clock */
+};
+
+static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
+	[DIV6_HDMI] = SH_CLK_DIV6_EXT(HDMICKCR, 0,
+				      hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2),
+	[DIV6_VCLK1] = SH_CLK_DIV6_EXT(VCLKCR1, 0,
+				       vclk_parents, ARRAY_SIZE(vclk_parents), 12, 3),
+	[DIV6_VCLK2] = SH_CLK_DIV6_EXT(VCLKCR2, 0,
+				       vclk_parents, ARRAY_SIZE(vclk_parents), 12, 3),
+	[DIV6_FSIA] = SH_CLK_DIV6_EXT(FSIACKCR, 0,
+				      fsia_parents, ARRAY_SIZE(fsia_parents), 6, 2),
+	[DIV6_FSIB] = SH_CLK_DIV6_EXT(FSIBCKCR, 0,
+				      fsib_parents, ARRAY_SIZE(fsib_parents), 6, 2),
+};
+
+/* HDMI1/2 clock */
+static unsigned long hdmi12_recalc(struct clk *clk)
+{
+	u32 val = __raw_readl(HDMICKCR);
+	int shift = (int)clk->priv;
+
+	val >>= shift;
+	val &= 0x3;
+
+	return clk->parent->rate / (1 << val);
+};
+
+static int hdmi12_set_rate(struct clk *clk, unsigned long rate)
+{
+	u32 val, mask;
+	int i, shift;
+
+	for (i = 0; i < 3; i++)
+		if (rate == clk->parent->rate / (1 << i))
+			goto find;
+	return -ENODEV;
+
+find:
+	shift = (int)clk->priv;
+
+	val = __raw_readl(HDMICKCR);
+	mask = ~(0x3 << shift);
+	val = (val & mask) | i << shift;
+	__raw_writel(val, HDMICKCR);
+
+	return 0;
+};
+
+static struct sh_clk_ops hdmi12_clk_ops = {
+	.recalc		= hdmi12_recalc,
+	.set_rate	= hdmi12_set_rate,
+};
+
+static struct clk hdmi1_clk = {
+	.ops		= &hdmi12_clk_ops,
+	.priv		= (void *)9,
+	.parent		= &div6_reparent_clks[DIV6_HDMI],  /* late install */
+};
+
+static struct clk hdmi2_clk = {
+	.ops		= &hdmi12_clk_ops,
+	.priv		= (void *)11,
+	.parent		= &div6_reparent_clks[DIV6_HDMI], /* late install */
+};
+
+static struct clk *late_main_clks[] = {
+	&hdmi1_clk,
+	&hdmi2_clk,
+};
+
+/* MSTP */
 enum {
 	DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_HP,
 	DIV4_HPP, DIV4_USBP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
@@ -343,7 +458,7 @@ static struct clk div6_clks[DIV6_NR] = {
 };
 
 enum {
-	MSTP125,
+	MSTP128, MSTP127, MSTP125,
 	MSTP116, MSTP111, MSTP100, MSTP117,
 
 	MSTP230,
@@ -360,6 +475,8 @@ enum {
 };
 
 static struct clk mstp_clks[MSTP_NR] = {
+	[MSTP128] = SH_CLK_MSTP32(&div4_clks[DIV4_S],	SMSTPCR1, 28, 0), /* CEU21 */
+	[MSTP127] = SH_CLK_MSTP32(&div4_clks[DIV4_S],	SMSTPCR1, 27, 0), /* CEU20 */
 	[MSTP125] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR1, 25, 0), /* TMU0 */
 	[MSTP117] = SH_CLK_MSTP32(&div4_clks[DIV4_B],	SMSTPCR1, 17, 0), /* LCDC1 */
 	[MSTP116] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR1, 16, 0), /* IIC0 */
@@ -408,6 +525,12 @@ static struct clk_lookup lookups[] = {
 	CLKDEV_CON_ID("pllc1_clk",		&pllc1_clk),
 	CLKDEV_CON_ID("pllc1_div2_clk",		&pllc1_div2_clk),
 	CLKDEV_CON_ID("usb24s",			&usb24s_clk),
+	CLKDEV_CON_ID("hdmi1",			&hdmi1_clk),
+	CLKDEV_CON_ID("hdmi2",			&hdmi2_clk),
+	CLKDEV_CON_ID("video1",			&div6_reparent_clks[DIV6_VCLK1]),
+	CLKDEV_CON_ID("video2",			&div6_reparent_clks[DIV6_VCLK2]),
+	CLKDEV_CON_ID("fsiack",			&fsiack_clk),
+	CLKDEV_CON_ID("fsibck",			&fsibck_clk),
 
 	/* DIV4 clocks */
 	CLKDEV_CON_ID("i_clk",			&div4_clks[DIV4_I]),
@@ -430,6 +553,8 @@ static struct clk_lookup lookups[] = {
 	CLKDEV_DEV_ID("i2c-sh_mobile.0",	&mstp_clks[MSTP116]),
 	CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1",	&mstp_clks[MSTP117]),
 	CLKDEV_DEV_ID("sh_tmu.0",		&mstp_clks[MSTP125]),
+	CLKDEV_DEV_ID("sh_mobile_ceu.0",	&mstp_clks[MSTP127]),
+	CLKDEV_DEV_ID("sh_mobile_ceu.1",	&mstp_clks[MSTP128]),
 
 	CLKDEV_DEV_ID("sh-sci.4",		&mstp_clks[MSTP200]),
 	CLKDEV_DEV_ID("sh-sci.3",		&mstp_clks[MSTP201]),
@@ -459,6 +584,10 @@ static struct clk_lookup lookups[] = {
 	CLKDEV_ICK_ID("phy",	"renesas_usbhs",	&mstp_clks[MSTP406]),
 	CLKDEV_ICK_ID("pci",	"renesas_usbhs",	&div4_clks[DIV4_USBP]),
 	CLKDEV_ICK_ID("usb24",	"renesas_usbhs",	&usb24_clk),
+	CLKDEV_ICK_ID("ick",	"sh-mobile-hdmi",	&div6_reparent_clks[DIV6_HDMI]),
+
+	CLKDEV_ICK_ID("icka", "sh_fsi2",	&div6_reparent_clks[DIV6_FSIA]),
+	CLKDEV_ICK_ID("ickb", "sh_fsi2",	&div6_reparent_clks[DIV6_FSIB]),
 };
 
 void __init r8a7740_clock_init(u8 md_ck)
@@ -495,8 +624,15 @@ void __init r8a7740_clock_init(u8 md_ck)
 		ret = sh_clk_div6_register(div6_clks, DIV6_NR);
 
 	if (!ret)
+		ret = sh_clk_div6_reparent_register(div6_reparent_clks,
+						    DIV6_REPARENT_NR);
+
+	if (!ret)
 		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
 
+	for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++)
+		ret = clk_register(late_main_clks[k]);
+
 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
 	if (!ret)
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index 472d1f5..ad6f9ad 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -475,9 +475,9 @@ static struct clk *late_main_clks[] = {
 
 enum { MSTP001,
 	MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, MSTP118, MSTP116, MSTP100,
-	MSTP219,
+	MSTP219, MSTP218,
 	MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
-	MSTP331, MSTP329, MSTP325, MSTP323, MSTP318,
+	MSTP331, MSTP329, MSTP328, MSTP325, MSTP323,
 	MSTP314, MSTP313, MSTP312, MSTP311,
 	MSTP303, MSTP302, MSTP301, MSTP300,
 	MSTP411, MSTP410, MSTP403,
@@ -497,6 +497,7 @@ static struct clk mstp_clks[MSTP_NR] = {
 	[MSTP116] = MSTP(&div4_clks[DIV4_HP], SMSTPCR1, 16, 0), /* IIC0 */
 	[MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */
 	[MSTP219] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 19, 0), /* SCIFA7 */
+	[MSTP218] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* SY-DMAC */
 	[MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
 	[MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
 	[MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */
@@ -506,9 +507,9 @@ static struct clk mstp_clks[MSTP_NR] = {
 	[MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
 	[MSTP331] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 31, 0), /* SCIFA6 */
 	[MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
+	[MSTP328] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 28, 0), /*FSI*/
 	[MSTP325] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 25, 0), /* IrDA */
 	[MSTP323] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 23, 0), /* IIC1 */
-	[MSTP318] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 18, 0), /* SY-DMAC */
 	[MSTP314] = MSTP(&div6_clks[DIV6_SDHI0], SMSTPCR3, 14, 0), /* SDHI0 */
 	[MSTP313] = MSTP(&div6_clks[DIV6_SDHI1], SMSTPCR3, 13, 0), /* SDHI1 */
 	[MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMCIF0 */
@@ -552,6 +553,7 @@ static struct clk_lookup lookups[] = {
 	CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* I2C0 */
 	CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */
 	CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP219]), /* SCIFA7 */
+	CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), /* SY-DMAC */
 	CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
 	CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP206]), /* SCIFB */
 	CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
@@ -561,9 +563,9 @@ static struct clk_lookup lookups[] = {
 	CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
 	CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */
 	CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
+	CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI */
 	CLKDEV_DEV_ID("sh_irda.0", &mstp_clks[MSTP325]), /* IrDA */
 	CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* I2C1 */
-	CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP318]), /* SY-DMAC */
 	CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
 	CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
 	CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMCIF0 */
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index 01e2bc0..45e61da 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -77,6 +77,7 @@ extern void r8a7779_add_standard_devices(void);
 extern void r8a7779_clock_init(void);
 extern void r8a7779_pinmux_init(void);
 extern void r8a7779_pm_init(void);
+extern void r8a7740_meram_workaround(void);
 
 extern unsigned int r8a7779_get_core_count(void);
 extern int r8a7779_platform_cpu_kill(unsigned int cpu);
diff --git a/arch/arm/mach-shmobile/include/mach/r8a7740.h b/arch/arm/mach-shmobile/include/mach/r8a7740.h
index 9d447ab..6468fcc 100644
--- a/arch/arm/mach-shmobile/include/mach/r8a7740.h
+++ b/arch/arm/mach-shmobile/include/mach/r8a7740.h
@@ -139,7 +139,7 @@ enum {
 	GPIO_FN_DBGMD10,	GPIO_FN_DBGMD11,	GPIO_FN_DBGMD20,
 	GPIO_FN_DBGMD21,
 
-	/* FSI */
+	/* FSI-A */
 	GPIO_FN_FSIAISLD_PORT0,		/* FSIAISLD Port 0/5 */
 	GPIO_FN_FSIAISLD_PORT5,
 	GPIO_FN_FSIASPDIF_PORT9,	/* FSIASPDIF Port 9/18 */
@@ -150,6 +150,9 @@ enum {
 	GPIO_FN_FSIACK,		GPIO_FN_FSIAILR,
 	GPIO_FN_FSIAIBT,
 
+	/* FSI-B */
+	GPIO_FN_FSIBCK,
+
 	/* FMSI */
 	GPIO_FN_FMSISLD_PORT1, /* FMSISLD Port 1/6 */
 	GPIO_FN_FMSISLD_PORT6,
@@ -565,6 +568,10 @@ enum {
 	GPIO_FN_RESETP_PULLUP,
 	GPIO_FN_RESETP_PLAIN,
 
+	/* HDMI */
+	GPIO_FN_HDMI_HPD,
+	GPIO_FN_HDMI_CEC,
+
 	/* SDENC */
 	GPIO_FN_SDENC_CPG,
 	GPIO_FN_SDENC_DV_CLKI,
diff --git a/arch/arm/mach-shmobile/intc-r8a7740.c b/arch/arm/mach-shmobile/intc-r8a7740.c
index 09c42af..9a69a31 100644
--- a/arch/arm/mach-shmobile/intc-r8a7740.c
+++ b/arch/arm/mach-shmobile/intc-r8a7740.c
@@ -71,10 +71,12 @@ enum {
 	DMAC3_1_DEI0, DMAC3_1_DEI1, DMAC3_1_DEI2, DMAC3_1_DEI3,
 	DMAC3_2_DEI4, DMAC3_2_DEI5, DMAC3_2_DADERR,
 	SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM,
+	HDMI,
 	USBH_INT, USBH_OHCI, USBH_EHCI, USBH_PME, USBH_BIND,
 	RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF,
 	SPU2_0, SPU2_1,
 	FSI, FMSI,
+	HDMI_SSS, HDMI_KEY,
 	IPMMU,
 	AP_ARM_CTIIRQ, AP_ARM_PMURQ,
 	MFIS2,
@@ -182,6 +184,7 @@ static struct intc_vect intca_vectors[] __initdata = {
 	INTC_VECT(USBH_EHCI,		0x1580),
 	INTC_VECT(USBH_PME,		0x15A0),
 	INTC_VECT(USBH_BIND,		0x15C0),
+	INTC_VECT(HDMI,			0x1700),
 	INTC_VECT(RSPI_OVRF,		0x1780),
 	INTC_VECT(RSPI_SPTEF,		0x17A0),
 	INTC_VECT(RSPI_SPRF,		0x17C0),
@@ -189,6 +192,8 @@ static struct intc_vect intca_vectors[] __initdata = {
 	INTC_VECT(SPU2_1,		0x1820),
 	INTC_VECT(FSI,			0x1840),
 	INTC_VECT(FMSI,			0x1860),
+	INTC_VECT(HDMI_SSS,		0x18A0),
+	INTC_VECT(HDMI_KEY,		0x18C0),
 	INTC_VECT(IPMMU,		0x1920),
 	INTC_VECT(AP_ARM_CTIIRQ,	0x1980),
 	INTC_VECT(AP_ARM_PMURQ,		0x19A0),
@@ -304,11 +309,11 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = {
 	    USBH_EHCI, USBH_PME, USBH_BIND, 0 } },
 	  /* IMR3A3 / IMCR3A3 */
 	{ /* IMR4A3 / IMCR4A3 */ 0xe6950090, 0xe69500d0, 8,
-	  { 0, 0, 0, 0,
+	  { HDMI, 0, 0, 0,
 	    RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF, 0 } },
 	{ /* IMR5A3 / IMCR5A3 */ 0xe6950094, 0xe69500d4, 8,
 	  { SPU2_0, SPU2_1, FSI, FMSI,
-	    0, 0, 0, 0 } },
+	    0, HDMI_SSS, HDMI_KEY, 0 } },
 	{ /* IMR6A3 / IMCR6A3 */ 0xe6950098, 0xe69500d8, 8,
 	  { 0, IPMMU, 0, 0,
 	    AP_ARM_CTIIRQ, AP_ARM_PMURQ, 0, 0 } },
@@ -353,10 +358,10 @@ static struct intc_prio_reg intca_prio_registers[] __initdata = {
 	{ 0xe6950014, 0, 16, 4, /* IPRFA3 */ { USBH2, 0, 0, 0 } },
 				/* IPRGA3 */
 				/* IPRHA3 */
-				/* IPRIA3 */
+	{ 0xe6950020, 0, 16, 4, /* IPRIA3 */ { HDMI, 0, 0, 0 } },
 	{ 0xe6950024, 0, 16, 4, /* IPRJA3 */ { RSPI, 0, 0, 0 } },
 	{ 0xe6950028, 0, 16, 4, /* IPRKA3 */ { SPU2, 0, FSI, FMSI } },
-				/* IPRLA3 */
+	{ 0xe695002c, 0, 16, 4, /* IPRLA3 */ { 0, HDMI_SSS, HDMI_KEY, 0 } },
 	{ 0xe6950030, 0, 16, 4, /* IPRMA3 */ { IPMMU, 0, 0, 0 } },
 	{ 0xe6950034, 0, 16, 4, /* IPRNA3 */ { AP_ARM2, 0, 0, 0 } },
 	{ 0xe6950038, 0, 16, 4, /* IPROA3 */ { MFIS2, CPORTR2S,
diff --git a/arch/arm/mach-shmobile/intc-r8a7779.c b/arch/arm/mach-shmobile/intc-r8a7779.c
index 550b23d..f04fad4 100644
--- a/arch/arm/mach-shmobile/intc-r8a7779.c
+++ b/arch/arm/mach-shmobile/intc-r8a7779.c
@@ -35,6 +35,9 @@
 #define INT2SMSKCR3 0xfe7822ac
 #define INT2SMSKCR4 0xfe7822b0
 
+#define INT2NTSR0 0xfe700060
+#define INT2NTSR1 0xfe700064
+
 static int r8a7779_set_wake(struct irq_data *data, unsigned int on)
 {
 	return 0; /* always allow wakeup */
@@ -49,6 +52,10 @@ void __init r8a7779_init_irq(void)
 	gic_init(0, 29, gic_dist_base, gic_cpu_base);
 	gic_arch_extn.irq_set_wake = r8a7779_set_wake;
 
+	/* route all interrupts to ARM */
+	__raw_writel(0xffffffff, INT2NTSR0);
+	__raw_writel(0x3fffffff, INT2NTSR1);
+
 	/* unmask all known interrupts in INTCS2 */
 	__raw_writel(0xfffffff0, INT2SMSKCR0);
 	__raw_writel(0xfff7ffff, INT2SMSKCR1);
diff --git a/arch/arm/mach-shmobile/pfc-r8a7740.c b/arch/arm/mach-shmobile/pfc-r8a7740.c
index 670fe18..03def0f 100644
--- a/arch/arm/mach-shmobile/pfc-r8a7740.c
+++ b/arch/arm/mach-shmobile/pfc-r8a7740.c
@@ -169,7 +169,7 @@ enum {
 	DBGMD10_MARK,	DBGMD11_MARK,	DBGMD20_MARK,
 	DBGMD21_MARK,
 
-	/* FSI */
+	/* FSI-A */
 	FSIAISLD_PORT0_MARK,	/* FSIAISLD Port 0/5 */
 	FSIAISLD_PORT5_MARK,
 	FSIASPDIF_PORT9_MARK,	/* FSIASPDIF Port 9/18 */
@@ -178,6 +178,9 @@ enum {
 	FSIAOBT_MARK,	FSIAOSLD_MARK,	FSIAOMC_MARK,
 	FSIACK_MARK,	FSIAILR_MARK,	FSIAIBT_MARK,
 
+	/* FSI-B */
+	FSIBCK_MARK,
+
 	/* FMSI */
 	FMSISLD_PORT1_MARK, /* FMSISLD Port 1/6 */
 	FMSISLD_PORT6_MARK,
@@ -560,6 +563,9 @@ enum {
 	/* SDENC */
 	SDENC_CPG_MARK,		SDENC_DV_CLKI_MARK,
 
+	/* HDMI */
+	HDMI_HPD_MARK, HDMI_CEC_MARK,
+
 	/* DEBUG */
 	EDEBGREQ_PULLUP_MARK,	/* for JTAG */
 	EDEBGREQ_PULLDOWN_MARK,
@@ -771,6 +777,7 @@ static pinmux_enum_t pinmux_data[] = {
 
 	/* Port11 */
 	PINMUX_DATA(FSIACK_MARK,		PORT11_FN1),
+	PINMUX_DATA(FSIBCK_MARK,		PORT11_FN2),
 	PINMUX_DATA(IRQ2_PORT11_MARK,		PORT11_FN0,	MSEL1CR_2_0),
 
 	/* Port12 */
@@ -1620,9 +1627,11 @@ static pinmux_enum_t pinmux_data[] = {
 
 	/* Port210 */
 	PINMUX_DATA(IRQ9_PORT210_MARK,		PORT210_FN0,	MSEL1CR_9_1),
+	PINMUX_DATA(HDMI_HPD_MARK,		PORT210_FN1),
 
 	/* Port211 */
 	PINMUX_DATA(IRQ16_PORT211_MARK,		PORT211_FN0,	MSEL1CR_16_1),
+	PINMUX_DATA(HDMI_CEC_MARK,		PORT211_FN1),
 
 	/* LCDC select */
 	PINMUX_DATA(LCDC0_SELECT_MARK,				MSEL3CR_6_0),
@@ -1691,7 +1700,7 @@ static struct pinmux_gpio pinmux_gpios[] = {
 	GPIO_FN(DBGMD10),	GPIO_FN(DBGMD11),	GPIO_FN(DBGMD20),
 	GPIO_FN(DBGMD21),
 
-	/* FSI */
+	/* FSI-A */
 	GPIO_FN(FSIAISLD_PORT0),	/* FSIAISLD Port 0/5 */
 	GPIO_FN(FSIAISLD_PORT5),
 	GPIO_FN(FSIASPDIF_PORT9),	/* FSIASPDIF Port 9/18 */
@@ -1700,6 +1709,9 @@ static struct pinmux_gpio pinmux_gpios[] = {
 	GPIO_FN(FSIAOBT),	GPIO_FN(FSIAOSLD),	GPIO_FN(FSIAOMC),
 	GPIO_FN(FSIACK),	GPIO_FN(FSIAILR),	GPIO_FN(FSIAIBT),
 
+	/* FSI-B */
+	GPIO_FN(FSIBCK),
+
 	/* FMSI */
 	GPIO_FN(FMSISLD_PORT1), /* FMSISLD Port 1/6 */
 	GPIO_FN(FMSISLD_PORT6),
@@ -2097,6 +2109,10 @@ static struct pinmux_gpio pinmux_gpios[] = {
 	GPIO_FN(SDENC_CPG),
 	GPIO_FN(SDENC_DV_CLKI),
 
+	/* HDMI */
+	GPIO_FN(HDMI_HPD),
+	GPIO_FN(HDMI_CEC),
+
 	/* SYSC */
 	GPIO_FN(RESETP_PULLUP),
 	GPIO_FN(RESETP_PLAIN),
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c
index bacdd66..e859fcd 100644
--- a/arch/arm/mach-shmobile/platsmp.c
+++ b/arch/arm/mach-shmobile/platsmp.c
@@ -25,7 +25,12 @@
 #define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2() || \
 			of_machine_is_compatible("renesas,sh73a0"))
 #define is_r8a7779() machine_is_marzen()
+
+#ifdef CONFIG_ARCH_EMEV2
 #define is_emev2() of_machine_is_compatible("renesas,emev2")
+#else
+#define is_emev2() (0)
+#endif
 
 static unsigned int __init shmobile_smp_get_core_count(void)
 {
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index a3bdb12..44daaee 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -290,12 +290,7 @@ struct sh7372_pm_domain sh7372_a3sg = {
 	.genpd.name = "A3SG",
 	.bit_shift = 13,
 };
-
-#else /* !CONFIG_PM */
-
-static inline void sh7372_a3sp_init(void) {}
-
-#endif /* !CONFIG_PM */
+#endif /* CONFIG_PM */
 
 #if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
 static int sh7372_do_idle_core_standby(unsigned long unused)
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
index ec4eb49..366311b 100644
--- a/arch/arm/mach-shmobile/setup-r8a7740.c
+++ b/arch/arm/mach-shmobile/setup-r8a7740.c
@@ -324,6 +324,24 @@ static struct platform_device *r8a7740_late_devices[] __initdata = {
 	&i2c1_device,
 };
 
+/*
+ * r8a7740 chip has lasting errata on MERAM buffer.
+ * this is work-around for it.
+ * see
+ *	"Media RAM (MERAM)" on r8a7740 documentation
+ */
+#define MEBUFCNTR	0xFE950098
+void r8a7740_meram_workaround(void)
+{
+	void __iomem *reg;
+
+	reg = ioremap_nocache(MEBUFCNTR, 4);
+	if (reg) {
+		iowrite32(0x01600164, reg);
+		iounmap(reg);
+	}
+}
+
 #define ICCR	0x0004
 #define ICSTART	0x0070
 
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index 6a4bd58..fafce9c 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -484,7 +484,7 @@ static const struct sh_dmae_slave_config sh7372_dmae_slaves[] = {
 	},
 };
 
-#define SH7372_CHCLR 0x220
+#define SH7372_CHCLR (0x220 - 0x20)
 
 static const struct sh_dmae_channel sh7372_dmae_channels[] = {
 	{
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 6a113a9..9077aaa 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -63,40 +63,15 @@ comment "Tegra board type"
 config MACH_HARMONY
        bool "Harmony board"
        depends on ARCH_TEGRA_2x_SOC
-       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
        help
          Support for nVidia Harmony development platform
 
-config MACH_KAEN
-       bool "Kaen board"
-       depends on ARCH_TEGRA_2x_SOC
-       select MACH_SEABOARD
-       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
-       help
-         Support for the Kaen version of Seaboard
-
 config MACH_PAZ00
        bool "Paz00 board"
        depends on ARCH_TEGRA_2x_SOC
        help
          Support for the Toshiba AC100/Dynabook AZ netbook
 
-config MACH_SEABOARD
-       bool "Seaboard board"
-       depends on ARCH_TEGRA_2x_SOC
-       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
-       help
-         Support for nVidia Seaboard development platform. It will
-	 also be included for some of the derivative boards that
-	 have large similarities with the seaboard design.
-
-config MACH_TEGRA_DT
-	bool "Generic Tegra20 board (FDT support)"
-	depends on ARCH_TEGRA_2x_SOC
-	select USE_OF
-	help
-	  Support for generic NVIDIA Tegra20 boards using Flattened Device Tree
-
 config MACH_TRIMSLICE
        bool "TrimSlice board"
        depends on ARCH_TEGRA_2x_SOC
@@ -104,20 +79,6 @@ config MACH_TRIMSLICE
        help
          Support for CompuLab TrimSlice platform
 
-config MACH_WARIO
-       bool "Wario board"
-       depends on ARCH_TEGRA_2x_SOC
-       select MACH_SEABOARD
-       help
-         Support for the Wario version of Seaboard
-
-config MACH_VENTANA
-       bool "Ventana board"
-       depends on ARCH_TEGRA_2x_SOC
-       select MACH_TEGRA_DT
-       help
-         Support for the nVidia Ventana development platform
-
 choice
         prompt "Default low-level debug console UART"
         default TEGRA_DEBUG_UART_NONE
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 2eb4445..c3d7303 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -8,21 +8,24 @@ obj-y                                   += timer.o
 obj-y					+= fuse.o
 obj-y					+= pmc.o
 obj-y					+= flowctrl.o
+obj-y					+= powergate.o
+obj-y					+= apbio.o
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_CPU_IDLE)			+= sleep.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= powergate.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_clocks.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra2_emc.o
-obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= board-dt-tegra30.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks.o
 obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
 obj-$(CONFIG_SMP)                       += reset.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
-obj-$(CONFIG_TEGRA_SYSTEM_DMA)		+= dma.o apbio.o
+obj-$(CONFIG_TEGRA_SYSTEM_DMA)		+= dma.o
 obj-$(CONFIG_CPU_FREQ)                  += cpu-tegra.o
 obj-$(CONFIG_TEGRA_PCI)			+= pcie.o
 obj-$(CONFIG_USB_SUPPORT)		+= usb_phy.o
 
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= board-dt-tegra20.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= board-dt-tegra30.o
+
 obj-$(CONFIG_MACH_HARMONY)              += board-harmony.o
 obj-$(CONFIG_MACH_HARMONY)              += board-harmony-pinmux.o
 obj-$(CONFIG_MACH_HARMONY)              += board-harmony-pcie.o
@@ -31,14 +34,5 @@ obj-$(CONFIG_MACH_HARMONY)              += board-harmony-power.o
 obj-$(CONFIG_MACH_PAZ00)		+= board-paz00.o
 obj-$(CONFIG_MACH_PAZ00)		+= board-paz00-pinmux.o
 
-obj-$(CONFIG_MACH_SEABOARD)             += board-seaboard.o
-obj-$(CONFIG_MACH_SEABOARD)             += board-seaboard-pinmux.o
-
-obj-$(CONFIG_MACH_TEGRA_DT)             += board-dt-tegra20.o
-obj-$(CONFIG_MACH_TEGRA_DT)             += board-harmony-pinmux.o
-obj-$(CONFIG_MACH_TEGRA_DT)             += board-seaboard-pinmux.o
-obj-$(CONFIG_MACH_TEGRA_DT)             += board-paz00-pinmux.o
-obj-$(CONFIG_MACH_TEGRA_DT)             += board-trimslice-pinmux.o
-
 obj-$(CONFIG_MACH_TRIMSLICE)            += board-trimslice.o
 obj-$(CONFIG_MACH_TRIMSLICE)            += board-trimslice-pinmux.o
diff --git a/arch/arm/mach-tegra/Makefile.boot b/arch/arm/mach-tegra/Makefile.boot
index 9a82094..7a1bb62 100644
--- a/arch/arm/mach-tegra/Makefile.boot
+++ b/arch/arm/mach-tegra/Makefile.boot
@@ -2,9 +2,10 @@ zreladdr-$(CONFIG_ARCH_TEGRA_2x_SOC)	+= 0x00008000
 params_phys-$(CONFIG_ARCH_TEGRA_2x_SOC)	:= 0x00000100
 initrd_phys-$(CONFIG_ARCH_TEGRA_2x_SOC)	:= 0x00800000
 
-dtb-$(CONFIG_MACH_HARMONY) += tegra-harmony.dtb
-dtb-$(CONFIG_MACH_PAZ00) += tegra-paz00.dtb
-dtb-$(CONFIG_MACH_SEABOARD) += tegra-seaboard.dtb
-dtb-$(CONFIG_MACH_TRIMSLICE) += tegra-trimslice.dtb
-dtb-$(CONFIG_MACH_VENTANA) += tegra-ventana.dtb
-dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra-cardhu.dtb
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-harmony.dtb
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-paz00.dtb
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-seaboard.dtb
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-trimslice.dtb
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-ventana.dtb
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-whistler.dtb
+dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30-cardhu.dtb
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
index e75451e..74ac0db 100644
--- a/arch/arm/mach-tegra/apbio.c
+++ b/arch/arm/mach-tegra/apbio.c
@@ -15,6 +15,10 @@
 
 #include <linux/kernel.h>
 #include <linux/io.h>
+#include <mach/iomap.h>
+#include <linux/of.h>
+
+#ifdef CONFIG_TEGRA_SYSTEM_DMA
 #include <linux/dma-mapping.h>
 #include <linux/spinlock.h>
 #include <linux/completion.h>
@@ -22,7 +26,6 @@
 #include <linux/mutex.h>
 
 #include <mach/dma.h>
-#include <mach/iomap.h>
 
 #include "apbio.h"
 
@@ -33,6 +36,9 @@ static u32 *tegra_apb_bb;
 static dma_addr_t tegra_apb_bb_phys;
 static DECLARE_COMPLETION(tegra_apb_wait);
 
+static u32 tegra_apb_readl_direct(unsigned long offset);
+static void tegra_apb_writel_direct(u32 value, unsigned long offset);
+
 bool tegra_apb_init(void)
 {
 	struct tegra_dma_channel *ch;
@@ -72,13 +78,13 @@ static void apb_dma_complete(struct tegra_dma_req *req)
 	complete(&tegra_apb_wait);
 }
 
-u32 tegra_apb_readl(unsigned long offset)
+static u32 tegra_apb_readl_using_dma(unsigned long offset)
 {
 	struct tegra_dma_req req;
 	int ret;
 
 	if (!tegra_apb_dma && !tegra_apb_init())
-		return readl(IO_TO_VIRT(offset));
+		return tegra_apb_readl_direct(offset);
 
 	mutex_lock(&tegra_apb_dma_lock);
 	req.complete = apb_dma_complete;
@@ -108,13 +114,13 @@ u32 tegra_apb_readl(unsigned long offset)
 	return *((u32 *)tegra_apb_bb);
 }
 
-void tegra_apb_writel(u32 value, unsigned long offset)
+static void tegra_apb_writel_using_dma(u32 value, unsigned long offset)
 {
 	struct tegra_dma_req req;
 	int ret;
 
 	if (!tegra_apb_dma && !tegra_apb_init()) {
-		writel(value, IO_TO_VIRT(offset));
+		tegra_apb_writel_direct(value, offset);
 		return;
 	}
 
@@ -143,3 +149,46 @@ void tegra_apb_writel(u32 value, unsigned long offset)
 
 	mutex_unlock(&tegra_apb_dma_lock);
 }
+#else
+#define tegra_apb_readl_using_dma tegra_apb_readl_direct
+#define tegra_apb_writel_using_dma tegra_apb_writel_direct
+#endif
+
+typedef u32 (*apbio_read_fptr)(unsigned long offset);
+typedef void (*apbio_write_fptr)(u32 value, unsigned long offset);
+
+static apbio_read_fptr apbio_read;
+static apbio_write_fptr apbio_write;
+
+static u32 tegra_apb_readl_direct(unsigned long offset)
+{
+	return readl(IO_TO_VIRT(offset));
+}
+
+static void tegra_apb_writel_direct(u32 value, unsigned long offset)
+{
+	writel(value, IO_TO_VIRT(offset));
+}
+
+void tegra_apb_io_init(void)
+{
+	/* Need to use dma only when it is Tegra20 based platform */
+	if (of_machine_is_compatible("nvidia,tegra20") ||
+			!of_have_populated_dt()) {
+		apbio_read = tegra_apb_readl_using_dma;
+		apbio_write = tegra_apb_writel_using_dma;
+	} else {
+		apbio_read = tegra_apb_readl_direct;
+		apbio_write = tegra_apb_writel_direct;
+	}
+}
+
+u32 tegra_apb_readl(unsigned long offset)
+{
+	return apbio_read(offset);
+}
+
+void tegra_apb_writel(u32 value, unsigned long offset)
+{
+	apbio_write(value, offset);
+}
diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h
index 8b49e8c..f05d71c 100644
--- a/arch/arm/mach-tegra/apbio.h
+++ b/arch/arm/mach-tegra/apbio.h
@@ -16,24 +16,7 @@
 #ifndef __MACH_TEGRA_APBIO_H
 #define __MACH_TEGRA_APBIO_H
 
-#ifdef CONFIG_TEGRA_SYSTEM_DMA
-
+void tegra_apb_io_init(void);
 u32 tegra_apb_readl(unsigned long offset);
 void tegra_apb_writel(u32 value, unsigned long offset);
-
-#else
-#include <asm/io.h>
-#include <mach/io.h>
-
-static inline u32 tegra_apb_readl(unsigned long offset)
-{
-        return readl(IO_TO_VIRT(offset));
-}
-
-static inline void tegra_apb_writel(u32 value, unsigned long offset)
-{
-        writel(value, IO_TO_VIRT(offset));
-}
-#endif
-
 #endif
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index eb7249d..1b43c33 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -64,6 +64,7 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
 		       &tegra_ehci2_pdata),
 	OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2",
 		       &tegra_ehci3_pdata),
+	OF_DEV_AUXDATA("nvidia,tegra20-apbdma", 0x6000a000, "tegra-apbdma", NULL),
 	{}
 };
 
@@ -98,6 +99,70 @@ static void __init tegra_dt_init(void)
 				tegra20_auxdata_lookup, NULL);
 }
 
+#ifdef CONFIG_MACH_TRIMSLICE
+static void __init trimslice_init(void)
+{
+	int ret;
+
+	ret = tegra_pcie_init(true, true);
+	if (ret)
+		pr_err("tegra_pci_init() failed: %d\n", ret);
+}
+#endif
+
+#ifdef CONFIG_MACH_HARMONY
+static void __init harmony_init(void)
+{
+	int ret;
+
+	ret = harmony_regulator_init();
+	if (ret) {
+		pr_err("harmony_regulator_init() failed: %d\n", ret);
+		return;
+	}
+
+	ret = harmony_pcie_init();
+	if (ret)
+		pr_err("harmony_pcie_init() failed: %d\n", ret);
+}
+#endif
+
+#ifdef CONFIG_MACH_PAZ00
+static void __init paz00_init(void)
+{
+	tegra_paz00_wifikill_init();
+}
+#endif
+
+static struct {
+	char *machine;
+	void (*init)(void);
+} board_init_funcs[] = {
+#ifdef CONFIG_MACH_TRIMSLICE
+	{ "compulab,trimslice", trimslice_init },
+#endif
+#ifdef CONFIG_MACH_HARMONY
+	{ "nvidia,harmony", harmony_init },
+#endif
+#ifdef CONFIG_MACH_PAZ00
+	{ "compal,paz00", paz00_init },
+#endif
+};
+
+static void __init tegra_dt_init_late(void)
+{
+	int i;
+
+	tegra_init_late();
+
+	for (i = 0; i < ARRAY_SIZE(board_init_funcs); i++) {
+		if (of_machine_is_compatible(board_init_funcs[i].machine)) {
+			board_init_funcs[i].init();
+			break;
+		}
+	}
+}
+
 static const char *tegra20_dt_board_compat[] = {
 	"nvidia,tegra20",
 	NULL
@@ -110,7 +175,7 @@ DT_MACHINE_START(TEGRA_DT, "nVidia Tegra20 (Flattened Device Tree)")
 	.handle_irq	= gic_handle_irq,
 	.timer		= &tegra_timer,
 	.init_machine	= tegra_dt_init,
-	.init_late	= tegra_init_late,
+	.init_late	= tegra_dt_init_late,
 	.restart	= tegra_assert_system_reset,
 	.dt_compat	= tegra20_dt_board_compat,
 MACHINE_END
diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c
index 4f76fa7..4a40986 100644
--- a/arch/arm/mach-tegra/board-dt-tegra30.c
+++ b/arch/arm/mach-tegra/board-dt-tegra30.c
@@ -52,6 +52,7 @@ struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL),
 	{}
 };
 
diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c b/arch/arm/mach-tegra/board-harmony-pcie.c
index 33c4fed..e8c3fda 100644
--- a/arch/arm/mach-tegra/board-harmony-pcie.c
+++ b/arch/arm/mach-tegra/board-harmony-pcie.c
@@ -27,14 +27,11 @@
 
 #ifdef CONFIG_TEGRA_PCI
 
-static int __init harmony_pcie_init(void)
+int __init harmony_pcie_init(void)
 {
 	struct regulator *regulator = NULL;
 	int err;
 
-	if (!machine_is_harmony())
-		return 0;
-
 	err = gpio_request(TEGRA_GPIO_EN_VDD_1V05_GPIO, "EN_VDD_1V05");
 	if (err)
 		return err;
@@ -62,7 +59,15 @@ err_reg:
 	return err;
 }
 
+static int __init harmony_pcie_initcall(void)
+{
+	if (!machine_is_harmony())
+		return 0;
+
+	return harmony_pcie_init();
+}
+
 /* PCI should be initialized after I2C, mfd and regulators */
-subsys_initcall_sync(harmony_pcie_init);
+subsys_initcall_sync(harmony_pcie_initcall);
 
 #endif
diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c
index 82f32300..44dcb2e 100644
--- a/arch/arm/mach-tegra/board-harmony-power.c
+++ b/arch/arm/mach-tegra/board-harmony-power.c
@@ -20,6 +20,10 @@
 #include <linux/gpio.h>
 #include <linux/regulator/machine.h>
 #include <linux/mfd/tps6586x.h>
+#include <linux/of.h>
+#include <linux/of_i2c.h>
+
+#include <asm/mach-types.h>
 
 #include <mach/irqs.h>
 
@@ -110,7 +114,26 @@ static struct i2c_board_info __initdata harmony_regulators[] = {
 
 int __init harmony_regulator_init(void)
 {
-	i2c_register_board_info(3, harmony_regulators, 1);
+	if (machine_is_harmony()) {
+		i2c_register_board_info(3, harmony_regulators, 1);
+	} else { /* Harmony, booted using device tree */
+		struct device_node *np;
+		struct i2c_adapter *adapter;
+
+		np = of_find_node_by_path("/i2c@7000d000");
+		if (np == NULL) {
+			pr_err("Could not find device_node for DVC I2C\n");
+			return -ENODEV;
+		}
+
+		adapter = of_find_i2c_adapter_by_node(np);
+		if (!adapter) {
+			pr_err("Could not find i2c_adapter for DVC I2C\n");
+			return -ENODEV;
+		}
+
+		i2c_new_device(adapter, harmony_regulators);
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c
index bbc1907..4b64af5 100644
--- a/arch/arm/mach-tegra/board-paz00.c
+++ b/arch/arm/mach-tegra/board-paz00.c
@@ -148,7 +148,6 @@ static struct platform_device *paz00_devices[] __initdata = {
 	&debug_uart,
 	&tegra_sdhci_device4,
 	&tegra_sdhci_device1,
-	&wifi_rfkill_device,
 	&leds_gpio,
 	&gpio_keys_device,
 };
@@ -201,6 +200,11 @@ static struct tegra_sdhci_platform_data sdhci_pdata4 = {
 	.is_8bit	= 1,
 };
 
+void __init tegra_paz00_wifikill_init(void)
+{
+	platform_device_register(&wifi_rfkill_device);
+}
+
 static void __init tegra_paz00_init(void)
 {
 	tegra_clk_init_from_table(paz00_clk_init_table);
@@ -211,6 +215,7 @@ static void __init tegra_paz00_init(void)
 	tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
 
 	platform_add_devices(paz00_devices, ARRAY_SIZE(paz00_devices));
+	tegra_paz00_wifikill_init();
 
 	paz00_i2c_init();
 	paz00_usb_init();
diff --git a/arch/arm/mach-tegra/board-seaboard-pinmux.c b/arch/arm/mach-tegra/board-seaboard-pinmux.c
deleted file mode 100644
index 11fc8a5..0000000
--- a/arch/arm/mach-tegra/board-seaboard-pinmux.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2010-2012 NVIDIA Corporation
- * Copyright (C) 2011 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-
-#include "board-seaboard.h"
-#include "board-pinmux.h"
-
-static unsigned long seaboard_pincfg_drive_sdio1[] = {
-	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE, 0),
-	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_SCHMITT, 0),
-	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_LOW_POWER_MODE, 3),
-	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH, 31),
-	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH, 31),
-	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING, 3),
-	TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_SLEW_RATE_RISING, 3),
-};
-
-static struct pinctrl_map common_map[] = {
-	TEGRA_MAP_MUXCONF("ata",   "ide",           none, driven),
-	TEGRA_MAP_MUXCONF("atb",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("atc",   "nand",          none, driven),
-	TEGRA_MAP_MUXCONF("atd",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("ate",   "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("cdev1", "plla_out",      none, driven),
-	TEGRA_MAP_MUXCONF("cdev2", "pllp_out4",     none, driven),
-	TEGRA_MAP_MUXCONF("crtp",  "crt",           up,   tristate),
-	TEGRA_MAP_MUXCONF("csus",  "vi_sensor_clk", none, tristate),
-	TEGRA_MAP_MUXCONF("dap1",  "dap1",          none, driven),
-	TEGRA_MAP_MUXCONF("dap2",  "dap2",          none, driven),
-	TEGRA_MAP_MUXCONF("dap3",  "dap3",          none, tristate),
-	TEGRA_MAP_MUXCONF("dap4",  "dap4",          none, driven),
-	TEGRA_MAP_MUXCONF("dta",   "vi",            down, driven),
-	TEGRA_MAP_MUXCONF("dtb",   "vi",            down, driven),
-	TEGRA_MAP_MUXCONF("dtc",   "vi",            down, driven),
-	TEGRA_MAP_MUXCONF("dtd",   "vi",            down, driven),
-	TEGRA_MAP_MUXCONF("dte",   "vi",            down, tristate),
-	TEGRA_MAP_MUXCONF("dtf",   "i2c3",          none, driven),
-	TEGRA_MAP_MUXCONF("gma",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("gmb",   "gmi",           up,   tristate),
-	TEGRA_MAP_MUXCONF("gmc",   "uartd",         none, driven),
-	TEGRA_MAP_MUXCONF("gme",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("gpu",   "pwm",           none, driven),
-	TEGRA_MAP_MUXCONF("gpu7",  "rtck",          none, driven),
-	TEGRA_MAP_MUXCONF("gpv",   "pcie",          none, tristate),
-	TEGRA_MAP_MUXCONF("hdint", "hdmi",          na,   tristate),
-	TEGRA_MAP_MUXCONF("i2cp",  "i2cp",          none, driven),
-	TEGRA_MAP_MUXCONF("irrx",  "uartb",         none, driven),
-	TEGRA_MAP_MUXCONF("irtx",  "uartb",         none, driven),
-	TEGRA_MAP_MUXCONF("kbca",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcb",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcc",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcd",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbce",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcf",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("lcsn",  "rsvd4",         na,   tristate),
-	TEGRA_MAP_MUXCONF("ld0",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld1",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld10",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld11",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld12",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld13",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld14",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld15",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld16",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld17",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld2",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld3",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld4",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld5",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld6",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld7",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld8",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld9",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ldc",   "rsvd4",         na,   tristate),
-	TEGRA_MAP_MUXCONF("ldi",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp1",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp2",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lm0",   "rsvd4",         na,   driven),
-	TEGRA_MAP_MUXCONF("lm1",   "crt",           na,   tristate),
-	TEGRA_MAP_MUXCONF("lpp",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lpw1",  "rsvd4",         na,   tristate),
-	TEGRA_MAP_MUXCONF("lsc0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lsdi",  "rsvd4",         na,   tristate),
-	TEGRA_MAP_MUXCONF("lspi",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lvp0",  "rsvd4",         na,   tristate),
-	TEGRA_MAP_MUXCONF("lvp1",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lvs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("owc",   "rsvd2",         none, tristate),
-	TEGRA_MAP_MUXCONF("pmc",   "pwr_on",        na,   driven),
-	TEGRA_MAP_MUXCONF("pta",   "hdmi",          none, driven),
-	TEGRA_MAP_MUXCONF("rm",    "i2c1",          none, driven),
-	TEGRA_MAP_MUXCONF("sdb",   "sdio3",         na,   driven),
-	TEGRA_MAP_MUXCONF("sdc",   "sdio3",         none, driven),
-	TEGRA_MAP_MUXCONF("sdd",   "sdio3",         none, driven),
-	TEGRA_MAP_MUXCONF("sdio1", "sdio1",         up,   driven),
-	TEGRA_MAP_MUXCONF("slxa",  "pcie",          up,   tristate),
-	TEGRA_MAP_MUXCONF("slxd",  "spdif",         none, driven),
-	TEGRA_MAP_MUXCONF("slxk",  "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("spdi",  "rsvd2",         none, driven),
-	TEGRA_MAP_MUXCONF("spdo",  "rsvd2",         none, driven),
-	TEGRA_MAP_MUXCONF("spib",  "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("spid",  "spi1",          none, tristate),
-	TEGRA_MAP_MUXCONF("spie",  "spi1",          none, tristate),
-	TEGRA_MAP_MUXCONF("spif",  "spi1",          down, tristate),
-	TEGRA_MAP_MUXCONF("spih",  "spi2_alt",      up,   tristate),
-	TEGRA_MAP_MUXCONF("uaa",   "ulpi",          up,   driven),
-	TEGRA_MAP_MUXCONF("uab",   "ulpi",          up,   driven),
-	TEGRA_MAP_MUXCONF("uac",   "rsvd2",         none, driven),
-	TEGRA_MAP_MUXCONF("uad",   "irda",          none, driven),
-	TEGRA_MAP_MUXCONF("uca",   "uartc",         none, driven),
-	TEGRA_MAP_MUXCONF("ucb",   "uartc",         none, driven),
-	TEGRA_MAP_MUXCONF("uda",   "ulpi",          none, driven),
-	TEGRA_MAP_CONF("ck32",    none, na),
-	TEGRA_MAP_CONF("ddrc",    none, na),
-	TEGRA_MAP_CONF("pmca",    none, na),
-	TEGRA_MAP_CONF("pmcb",    none, na),
-	TEGRA_MAP_CONF("pmcc",    none, na),
-	TEGRA_MAP_CONF("pmcd",    none, na),
-	TEGRA_MAP_CONF("pmce",    none, na),
-	TEGRA_MAP_CONF("xm2c",    none, na),
-	TEGRA_MAP_CONF("xm2d",    none, na),
-	TEGRA_MAP_CONF("ls",      up,   na),
-	TEGRA_MAP_CONF("lc",      up,   na),
-	TEGRA_MAP_CONF("ld17_0",  down, na),
-	TEGRA_MAP_CONF("ld19_18", down, na),
-	TEGRA_MAP_CONF("ld21_20", down, na),
-	TEGRA_MAP_CONF("ld23_22", down, na),
-};
-
-static struct pinctrl_map seaboard_map[] = {
-	TEGRA_MAP_MUXCONF("ddc",   "rsvd2",         none, tristate),
-	TEGRA_MAP_MUXCONF("gmd",   "sflash",        none, driven),
-	TEGRA_MAP_MUXCONF("lpw0",  "hdmi",          na,   driven),
-	TEGRA_MAP_MUXCONF("lpw2",  "hdmi",          na,   driven),
-	TEGRA_MAP_MUXCONF("lsc1",  "hdmi",          na,   tristate),
-	TEGRA_MAP_MUXCONF("lsck",  "hdmi",          na,   tristate),
-	TEGRA_MAP_MUXCONF("lsda",  "hdmi",          na,   tristate),
-	TEGRA_MAP_MUXCONF("slxc",  "spdif",         none, tristate),
-	TEGRA_MAP_MUXCONF("spia",  "gmi",           up,   tristate),
-	TEGRA_MAP_MUXCONF("spic",  "gmi",           up,   driven),
-	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      up,   tristate),
-	PIN_MAP_CONFIGS_GROUP_HOG_DEFAULT(PINMUX_DEV, "drive_sdio1", seaboard_pincfg_drive_sdio1),
-};
-
-static struct pinctrl_map ventana_map[] = {
-	TEGRA_MAP_MUXCONF("ddc",   "rsvd2",         none, driven),
-	TEGRA_MAP_MUXCONF("gmd",   "sflash",        none, tristate),
-	TEGRA_MAP_MUXCONF("lpw0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lpw2",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lsc1",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lsck",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsda",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("slxc",  "sdio3",         none, driven),
-	TEGRA_MAP_MUXCONF("spia",  "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("spic",  "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      none, tristate),
-};
-
-static struct tegra_board_pinmux_conf common_conf = {
-	.maps = common_map,
-	.map_count = ARRAY_SIZE(common_map),
-};
-
-static struct tegra_board_pinmux_conf seaboard_conf = {
-	.maps = seaboard_map,
-	.map_count = ARRAY_SIZE(seaboard_map),
-};
-
-static struct tegra_board_pinmux_conf ventana_conf = {
-	.maps = ventana_map,
-	.map_count = ARRAY_SIZE(ventana_map),
-};
-
-void seaboard_pinmux_init(void)
-{
-	tegra_board_pinmux_init(&common_conf, &seaboard_conf);
-}
-
-void ventana_pinmux_init(void)
-{
-	tegra_board_pinmux_init(&common_conf, &ventana_conf);
-}
diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c
deleted file mode 100644
index 71e9f3f..0000000
--- a/arch/arm/mach-tegra/board-seaboard.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (c) 2010, 2011 NVIDIA Corporation.
- * Copyright (C) 2010, 2011 Google, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/of_serial.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/gpio_keys.h>
-#include <linux/platform_data/tegra_usb.h>
-
-#include <sound/wm8903.h>
-
-#include <mach/iomap.h>
-#include <mach/irqs.h>
-#include <mach/sdhci.h>
-#include <mach/tegra_wm8903_pdata.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
-
-#include "board.h"
-#include "board-seaboard.h"
-#include "clock.h"
-#include "devices.h"
-#include "gpio-names.h"
-
-static struct plat_serial8250_port debug_uart_platform_data[] = {
-	{
-		/* Memory and IRQ filled in before registration */
-		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
-		.type		= PORT_TEGRA,
-		.handle_break	= tegra_serial_handle_break,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= 216000000,
-	}, {
-		.flags		= 0,
-	}
-};
-
-static struct platform_device debug_uart = {
-	.name = "serial8250",
-	.id = PLAT8250_DEV_PLATFORM,
-	.dev = {
-		.platform_data = debug_uart_platform_data,
-	},
-};
-
-static __initdata struct tegra_clk_init_table seaboard_clk_init_table[] = {
-	/* name		parent		rate		enabled */
-	{ "uartb",	"pll_p",	216000000,	true},
-	{ "uartd",	"pll_p",	216000000,	true},
-	{ "pll_a",	"pll_p_out1",	56448000,	true },
-	{ "pll_a_out0",	"pll_a",	11289600,	true },
-	{ "cdev1",	NULL,		0,		true },
-	{ "i2s1",	"pll_a_out0",	11289600,	false},
-	{ "usbd",	"clk_m",	12000000,	true},
-	{ "usb3",	"clk_m",	12000000,	true},
-	{ NULL,		NULL,		0,		0},
-};
-
-static struct gpio_keys_button seaboard_gpio_keys_buttons[] = {
-	{
-		.code		= SW_LID,
-		.gpio		= TEGRA_GPIO_LIDSWITCH,
-		.active_low	= 0,
-		.desc		= "Lid",
-		.type		= EV_SW,
-		.wakeup		= 1,
-		.debounce_interval = 1,
-	},
-	{
-		.code		= KEY_POWER,
-		.gpio		= TEGRA_GPIO_POWERKEY,
-		.active_low	= 1,
-		.desc		= "Power",
-		.type		= EV_KEY,
-		.wakeup		= 1,
-	},
-};
-
-static struct gpio_keys_platform_data seaboard_gpio_keys = {
-	.buttons	= seaboard_gpio_keys_buttons,
-	.nbuttons	= ARRAY_SIZE(seaboard_gpio_keys_buttons),
-};
-
-static struct platform_device seaboard_gpio_keys_device = {
-	.name		= "gpio-keys",
-	.id		= -1,
-	.dev		= {
-		.platform_data = &seaboard_gpio_keys,
-	}
-};
-
-static struct tegra_sdhci_platform_data sdhci_pdata1 = {
-	.cd_gpio	= -1,
-	.wp_gpio	= -1,
-	.power_gpio	= -1,
-};
-
-static struct tegra_sdhci_platform_data sdhci_pdata3 = {
-	.cd_gpio	= TEGRA_GPIO_SD2_CD,
-	.wp_gpio	= TEGRA_GPIO_SD2_WP,
-	.power_gpio	= TEGRA_GPIO_SD2_POWER,
-};
-
-static struct tegra_sdhci_platform_data sdhci_pdata4 = {
-	.cd_gpio	= -1,
-	.wp_gpio	= -1,
-	.power_gpio	= -1,
-	.is_8bit	= 1,
-};
-
-static struct tegra_wm8903_platform_data seaboard_audio_pdata = {
-	.gpio_spkr_en		= TEGRA_GPIO_SPKR_EN,
-	.gpio_hp_det		= TEGRA_GPIO_HP_DET,
-	.gpio_hp_mute		= -1,
-	.gpio_int_mic_en	= -1,
-	.gpio_ext_mic_en	= -1,
-};
-
-static struct platform_device seaboard_audio_device = {
-	.name	= "tegra-snd-wm8903",
-	.id	= 0,
-	.dev	= {
-		.platform_data  = &seaboard_audio_pdata,
-	},
-};
-
-static struct platform_device *seaboard_devices[] __initdata = {
-	&debug_uart,
-	&tegra_pmu_device,
-	&tegra_sdhci_device4,
-	&tegra_sdhci_device3,
-	&tegra_sdhci_device1,
-	&seaboard_gpio_keys_device,
-	&tegra_i2s_device1,
-	&tegra_das_device,
-	&seaboard_audio_device,
-};
-
-static struct i2c_board_info __initdata isl29018_device = {
-	I2C_BOARD_INFO("isl29018", 0x44),
-};
-
-static struct i2c_board_info __initdata adt7461_device = {
-	I2C_BOARD_INFO("adt7461", 0x4c),
-};
-
-static struct wm8903_platform_data wm8903_pdata = {
-	.irq_active_low = 0,
-	.micdet_cfg = 0,
-	.micdet_delay = 100,
-	.gpio_base = SEABOARD_GPIO_WM8903(0),
-	.gpio_cfg = {
-		0,
-		0,
-		WM8903_GPIO_CONFIG_ZERO,
-		0,
-		0,
-	},
-};
-
-static struct i2c_board_info __initdata wm8903_device = {
-	I2C_BOARD_INFO("wm8903", 0x1a),
-	.platform_data = &wm8903_pdata,
-};
-
-static int seaboard_ehci_init(void)
-{
-	struct tegra_ehci_platform_data *pdata;
-
-	pdata = tegra_ehci1_device.dev.platform_data;
-	pdata->vbus_gpio = TEGRA_GPIO_USB1;
-
-	platform_device_register(&tegra_ehci1_device);
-	platform_device_register(&tegra_ehci3_device);
-
-	return 0;
-}
-
-static void __init seaboard_i2c_init(void)
-{
-	isl29018_device.irq = gpio_to_irq(TEGRA_GPIO_ISL29018_IRQ);
-	i2c_register_board_info(0, &isl29018_device, 1);
-
-	wm8903_device.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
-	i2c_register_board_info(0, &wm8903_device, 1);
-
-	i2c_register_board_info(3, &adt7461_device, 1);
-
-	platform_device_register(&tegra_i2c_device1);
-	platform_device_register(&tegra_i2c_device2);
-	platform_device_register(&tegra_i2c_device3);
-	platform_device_register(&tegra_i2c_device4);
-}
-
-static void __init seaboard_common_init(void)
-{
-	seaboard_pinmux_init();
-
-	tegra_clk_init_from_table(seaboard_clk_init_table);
-
-	tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
-	tegra_sdhci_device3.dev.platform_data = &sdhci_pdata3;
-	tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
-
-	platform_add_devices(seaboard_devices, ARRAY_SIZE(seaboard_devices));
-
-	seaboard_ehci_init();
-}
-
-static void __init tegra_seaboard_init(void)
-{
-	/* Seaboard uses UARTD for the debug port. */
-	debug_uart_platform_data[0].membase = IO_ADDRESS(TEGRA_UARTD_BASE);
-	debug_uart_platform_data[0].mapbase = TEGRA_UARTD_BASE;
-	debug_uart_platform_data[0].irq = INT_UARTD;
-
-	seaboard_common_init();
-
-	seaboard_i2c_init();
-}
-
-static void __init tegra_kaen_init(void)
-{
-	/* Kaen uses UARTB for the debug port. */
-	debug_uart_platform_data[0].membase = IO_ADDRESS(TEGRA_UARTB_BASE);
-	debug_uart_platform_data[0].mapbase = TEGRA_UARTB_BASE;
-	debug_uart_platform_data[0].irq = INT_UARTB;
-
-	seaboard_audio_pdata.gpio_hp_mute = TEGRA_GPIO_KAEN_HP_MUTE;
-
-	seaboard_common_init();
-
-	seaboard_i2c_init();
-}
-
-static void __init tegra_wario_init(void)
-{
-	/* Wario uses UARTB for the debug port. */
-	debug_uart_platform_data[0].membase = IO_ADDRESS(TEGRA_UARTB_BASE);
-	debug_uart_platform_data[0].mapbase = TEGRA_UARTB_BASE;
-	debug_uart_platform_data[0].irq = INT_UARTB;
-
-	seaboard_common_init();
-
-	seaboard_i2c_init();
-}
-
-
-MACHINE_START(SEABOARD, "seaboard")
-	.atag_offset    = 0x100,
-	.map_io         = tegra_map_common_io,
-	.init_early     = tegra20_init_early,
-	.init_irq       = tegra_init_irq,
-	.handle_irq	= gic_handle_irq,
-	.timer          = &tegra_timer,
-	.init_machine   = tegra_seaboard_init,
-	.init_late	= tegra_init_late,
-	.restart	= tegra_assert_system_reset,
-MACHINE_END
-
-MACHINE_START(KAEN, "kaen")
-	.atag_offset    = 0x100,
-	.map_io         = tegra_map_common_io,
-	.init_early     = tegra20_init_early,
-	.init_irq       = tegra_init_irq,
-	.handle_irq	= gic_handle_irq,
-	.timer          = &tegra_timer,
-	.init_machine   = tegra_kaen_init,
-	.init_late	= tegra_init_late,
-	.restart	= tegra_assert_system_reset,
-MACHINE_END
-
-MACHINE_START(WARIO, "wario")
-	.atag_offset    = 0x100,
-	.map_io         = tegra_map_common_io,
-	.init_early     = tegra20_init_early,
-	.init_irq       = tegra_init_irq,
-	.handle_irq	= gic_handle_irq,
-	.timer          = &tegra_timer,
-	.init_machine   = tegra_wario_init,
-	.init_late	= tegra_init_late,
-	.restart	= tegra_assert_system_reset,
-MACHINE_END
diff --git a/arch/arm/mach-tegra/board-seaboard.h b/arch/arm/mach-tegra/board-seaboard.h
deleted file mode 100644
index 4c45d4c..0000000
--- a/arch/arm/mach-tegra/board-seaboard.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-seaboard.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef _MACH_TEGRA_BOARD_SEABOARD_H
-#define _MACH_TEGRA_BOARD_SEABOARD_H
-
-#include <mach/gpio-tegra.h>
-
-#define SEABOARD_GPIO_TPS6586X(_x_)	(TEGRA_NR_GPIOS + (_x_))
-#define SEABOARD_GPIO_WM8903(_x_)	(SEABOARD_GPIO_TPS6586X(4) + (_x_))
-
-#define TEGRA_GPIO_SD2_CD		TEGRA_GPIO_PI5
-#define TEGRA_GPIO_SD2_WP		TEGRA_GPIO_PH1
-#define TEGRA_GPIO_SD2_POWER		TEGRA_GPIO_PI6
-#define TEGRA_GPIO_LIDSWITCH		TEGRA_GPIO_PC7
-#define TEGRA_GPIO_USB1			TEGRA_GPIO_PD0
-#define TEGRA_GPIO_POWERKEY		TEGRA_GPIO_PV2
-#define TEGRA_GPIO_BACKLIGHT		TEGRA_GPIO_PD4
-#define TEGRA_GPIO_LVDS_SHUTDOWN	TEGRA_GPIO_PB2
-#define TEGRA_GPIO_BACKLIGHT_PWM	TEGRA_GPIO_PU5
-#define TEGRA_GPIO_BACKLIGHT_VDD	TEGRA_GPIO_PW0
-#define TEGRA_GPIO_EN_VDD_PNL		TEGRA_GPIO_PC6
-#define TEGRA_GPIO_MAGNETOMETER		TEGRA_GPIO_PN5
-#define TEGRA_GPIO_ISL29018_IRQ		TEGRA_GPIO_PZ2
-#define TEGRA_GPIO_AC_ONLINE		TEGRA_GPIO_PV3
-#define TEGRA_GPIO_WWAN_PWR		SEABOARD_GPIO_TPS6586X(2)
-#define TEGRA_GPIO_CDC_IRQ		TEGRA_GPIO_PX3
-#define TEGRA_GPIO_SPKR_EN		SEABOARD_GPIO_WM8903(2)
-#define TEGRA_GPIO_HP_DET		TEGRA_GPIO_PX1
-#define TEGRA_GPIO_KAEN_HP_MUTE		TEGRA_GPIO_PA5
-
-void seaboard_pinmux_init(void);
-
-#endif
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index 6501496..f88e514 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -46,5 +46,14 @@ int __init tegra_powergate_debugfs_init(void);
 static inline int tegra_powergate_debugfs_init(void) { return 0; }
 #endif
 
+int __init harmony_regulator_init(void);
+#ifdef CONFIG_TEGRA_PCI
+int __init harmony_pcie_init(void);
+#else
+static inline int harmony_pcie_init(void) { return 0; }
+#endif
+
+void __init tegra_paz00_wifikill_init(void);
+
 extern struct sys_timer tegra_timer;
 #endif
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 204a5c8..96fef6b 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -33,6 +33,7 @@
 #include "clock.h"
 #include "fuse.h"
 #include "pmc.h"
+#include "apbio.h"
 
 /*
  * Storage for debug-macro.S's state.
@@ -127,6 +128,7 @@ static void __init tegra_init_cache(u32 tag_latency, u32 data_latency)
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
 void __init tegra20_init_early(void)
 {
+	tegra_apb_io_init();
 	tegra_init_fuse();
 	tegra2_init_clocks();
 	tegra_clk_init_from_table(tegra20_clk_init_table);
@@ -138,6 +140,7 @@ void __init tegra20_init_early(void)
 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
 void __init tegra30_init_early(void)
 {
+	tegra_apb_io_init();
 	tegra_init_fuse();
 	tegra30_init_clocks();
 	tegra_clk_init_from_table(tegra30_clk_init_table);
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index 7a065f0..ceb52db 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -189,8 +189,8 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
 		return PTR_ERR(emc_clk);
 	}
 
-	clk_enable(emc_clk);
-	clk_enable(cpu_clk);
+	clk_prepare_enable(emc_clk);
+	clk_prepare_enable(cpu_clk);
 
 	cpufreq_frequency_table_cpuinfo(policy, freq_table);
 	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
@@ -212,7 +212,7 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
 static int tegra_cpu_exit(struct cpufreq_policy *policy)
 {
 	cpufreq_frequency_table_cpuinfo(policy, freq_table);
-	clk_disable(emc_clk);
+	clk_disable_unprepare(emc_clk);
 	clk_put(emc_clk);
 	clk_put(cpu_clk);
 	return 0;
diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
index d83a8c0..566e2f8 100644
--- a/arch/arm/mach-tegra/cpuidle.c
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -27,9 +27,9 @@
 #include <linux/cpuidle.h>
 #include <linux/hrtimer.h>
 
-#include <mach/iomap.h>
+#include <asm/proc-fns.h>
 
-extern void tegra_cpu_wfi(void);
+#include <mach/iomap.h>
 
 static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
 				struct cpuidle_driver *drv, int index);
@@ -64,7 +64,7 @@ static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
 
 	enter = ktime_get();
 
-	tegra_cpu_wfi();
+	cpu_do_idle();
 
 	exit = ktime_sub(ktime_get(), enter);
 	us = ktime_to_us(exit);
diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c
index abea4f6..29c5114 100644
--- a/arch/arm/mach-tegra/dma.c
+++ b/arch/arm/mach-tegra/dma.c
@@ -714,13 +714,13 @@ int __init tegra_dma_init(void)
 
 	bitmap_fill(channel_usage, NV_DMA_MAX_CHANNELS);
 
-	c = clk_get_sys("tegra-dma", NULL);
+	c = clk_get_sys("tegra-apbdma", NULL);
 	if (IS_ERR(c)) {
 		pr_err("Unable to get clock for APB DMA\n");
 		ret = PTR_ERR(c);
 		goto fail;
 	}
-	ret = clk_enable(c);
+	ret = clk_prepare_enable(c);
 	if (ret != 0) {
 		pr_err("Unable to enable clock for APB DMA\n");
 		goto fail;
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index 0e09137..d3ad515 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -723,9 +723,9 @@ static int tegra_pcie_power_regate(void)
 
 	tegra_pcie_xclk_clamp(false);
 
-	clk_enable(tegra_pcie.afi_clk);
-	clk_enable(tegra_pcie.pex_clk);
-	return clk_enable(tegra_pcie.pll_e);
+	clk_prepare_enable(tegra_pcie.afi_clk);
+	clk_prepare_enable(tegra_pcie.pex_clk);
+	return clk_prepare_enable(tegra_pcie.pll_e);
 }
 
 static int tegra_pcie_clocks_get(void)
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index f5b12fb..15d5065 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -146,7 +146,7 @@ int tegra_powergate_sequence_power_up(int id, struct clk *clk)
 	if (ret)
 		goto err_power;
 
-	ret = clk_enable(clk);
+	ret = clk_prepare_enable(clk);
 	if (ret)
 		goto err_clk;
 
@@ -162,7 +162,7 @@ int tegra_powergate_sequence_power_up(int id, struct clk *clk)
 	return 0;
 
 err_clamp:
-	clk_disable(clk);
+	clk_disable_unprepare(clk);
 err_clk:
 	tegra_powergate_power_off(id);
 err_power:
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
index 5b20197..d29b156 100644
--- a/arch/arm/mach-tegra/sleep.S
+++ b/arch/arm/mach-tegra/sleep.S
@@ -62,32 +62,3 @@
 	movw	\reg, #:lower16:\val
 	movt	\reg, #:upper16:\val
 .endm
-
-/*
- * tegra_cpu_wfi
- *
- * puts current CPU in clock-gated wfi using the flow controller
- *
- * corrupts r0-r3
- * must be called with MMU on
- */
-
-ENTRY(tegra_cpu_wfi)
-	cpu_id	r0
-	cpu_to_halt_reg r1, r0
-	cpu_to_csr_reg r2, r0
-	mov32	r0, TEGRA_FLOW_CTRL_VIRT
-	mov	r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
-	str	r3, [r0, r2]	@ clear event & interrupt status
-	mov	r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT | FLOW_CTRL_JTAG_RESUME
-	str	r3, [r0, r1]	@ put flow controller in wait irq mode
-	dsb
-	wfi
-	mov	r3, #0
-	str	r3, [r0, r1]	@ clear flow controller halt status
-	mov	r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
-	str	r3, [r0, r2]	@ clear event & interrupt status
-	dsb
-	mov	pc, lr
-ENDPROC(tegra_cpu_wfi)
-
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index b59315c..b79cb93 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -2149,7 +2149,7 @@ static struct clk tegra_clk_emc = {
 	}
 
 static struct clk tegra_list_clks[] = {
-	PERIPH_CLK("apbdma",	"tegra-dma",		NULL,	34,	0,	108000000, mux_pclk,			0),
+	PERIPH_CLK("apbdma",	"tegra-apbdma",		NULL,	34,	0,	108000000, mux_pclk,			0),
 	PERIPH_CLK("rtc",	"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET),
 	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0),
 	PERIPH_CLK("i2s1",	"tegra20-i2s.0",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
@@ -2189,11 +2189,11 @@ static struct clk tegra_list_clks[] = {
 	PERIPH_CLK("i2c2_i2c",	"tegra-i2c.1",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
 	PERIPH_CLK("i2c3_i2c",	"tegra-i2c.2",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
 	PERIPH_CLK("dvc_i2c",	"tegra-i2c.3",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
-	PERIPH_CLK("uarta",	"uart.0",		NULL,	6,	0x178,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uartb",	"uart.1",		NULL,	7,	0x17c,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uartc",	"uart.2",		NULL,	55,	0x1a0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uartd",	"uart.3",		NULL,	65,	0x1c0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uarte",	"uart.4",		NULL,	66,	0x1c4,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
+	PERIPH_CLK("uarta",	"tegra-uart.0",		NULL,	6,	0x178,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
+	PERIPH_CLK("uartb",	"tegra-uart.1",		NULL,	7,	0x17c,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
+	PERIPH_CLK("uartc",	"tegra-uart.2",		NULL,	55,	0x1a0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
+	PERIPH_CLK("uartd",	"tegra-uart.3",		NULL,	65,	0x1c0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
+	PERIPH_CLK("uarte",	"tegra-uart.4",		NULL,	66,	0x1c4,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
 	PERIPH_CLK("3d",	"3d",			NULL,	24,	0x158,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */
 	PERIPH_CLK("2d",	"2d",			NULL,	21,	0x15c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
 	PERIPH_CLK("vi",	"tegra_camera",		"vi",	20,	0x148,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
@@ -2245,11 +2245,11 @@ static struct clk tegra_list_clks[] = {
  * table under two names.
  */
 static struct clk_duplicate tegra_clk_duplicates[] = {
-	CLK_DUPLICATE("uarta",	"tegra_uart.0",	NULL),
-	CLK_DUPLICATE("uartb",	"tegra_uart.1",	NULL),
-	CLK_DUPLICATE("uartc",	"tegra_uart.2",	NULL),
-	CLK_DUPLICATE("uartd",	"tegra_uart.3",	NULL),
-	CLK_DUPLICATE("uarte",	"tegra_uart.4",	NULL),
+	CLK_DUPLICATE("uarta",  "serial8250.0", NULL),
+	CLK_DUPLICATE("uartb",  "serial8250.1", NULL),
+	CLK_DUPLICATE("uartc",  "serial8250.2", NULL),
+	CLK_DUPLICATE("uartd",  "serial8250.3", NULL),
+	CLK_DUPLICATE("uarte",  "serial8250.4", NULL),
 	CLK_DUPLICATE("usbd", "utmip-pad", NULL),
 	CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
 	CLK_DUPLICATE("usbd", "tegra-otg", NULL),
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
index e33fe4b..2ba948e 100644
--- a/arch/arm/mach-tegra/tegra30_clocks.c
+++ b/arch/arm/mach-tegra/tegra30_clocks.c
@@ -2871,7 +2871,7 @@ static struct clk tegra30_clk_twd = {
 		},					\
 	}
 struct clk tegra_list_clks[] = {
-	PERIPH_CLK("apbdma",	"tegra-dma",		NULL,	34,	0,	26000000,  mux_clk_m,			0),
+	PERIPH_CLK("apbdma",	"tegra-apbdma",		NULL,	34,	0,	26000000,  mux_clk_m,			0),
 	PERIPH_CLK("rtc",	"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB),
 	PERIPH_CLK("kbc",	"tegra-kbc",		NULL,	36,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB),
 	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0),
@@ -2924,16 +2924,11 @@ struct clk tegra_list_clks[] = {
 	PERIPH_CLK("i2c3",	"tegra-i2c.2",		NULL,	67,	0x1b8,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
 	PERIPH_CLK("i2c4",	"tegra-i2c.3",		NULL,	103,	0x3c4,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
 	PERIPH_CLK("i2c5",	"tegra-i2c.4",		NULL,	47,	0x128,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
-	PERIPH_CLK("uarta",	"tegra_uart.0",		NULL,	6,	0x178,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartb",	"tegra_uart.1",		NULL,	7,	0x17c,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartc",	"tegra_uart.2",		NULL,	55,	0x1a0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartd",	"tegra_uart.3",		NULL,	65,	0x1c0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uarte",	"tegra_uart.4",		NULL,	66,	0x1c4,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uarta_dbg",	"serial8250.0",		"uarta", 6,	0x178,	800000000, mux_pllp_clkm,		MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartb_dbg",	"serial8250.0",		"uartb", 7,	0x17c,	800000000, mux_pllp_clkm,		MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartc_dbg",	"serial8250.0",		"uartc", 55,	0x1a0,	800000000, mux_pllp_clkm,		MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartd_dbg",	"serial8250.0",		"uartd", 65,	0x1c0,	800000000, mux_pllp_clkm,		MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uarte_dbg",	"serial8250.0",		"uarte", 66,	0x1c4,	800000000, mux_pllp_clkm,		MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uarta",	"tegra-uart.0",		NULL,	6,	0x178,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uartb",	"tegra-uart.1",		NULL,	7,	0x17c,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uartc",	"tegra-uart.2",		NULL,	55,	0x1a0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uartd",	"tegra-uart.3",		NULL,	65,	0x1c0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uarte",	"tegra-uart.4",		NULL,	66,	0x1c4,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
 	PERIPH_CLK_EX("vi",	"tegra_camera",		"vi",	20,	0x148,	425000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT,	&tegra_vi_clk_ops),
 	PERIPH_CLK("3d",	"3d",			NULL,	24,	0x158,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
 	PERIPH_CLK("3d2",       "3d2",			NULL,	98,	0x3b0,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
@@ -2983,6 +2978,11 @@ struct clk tegra_list_clks[] = {
  * table under two names.
  */
 struct clk_duplicate tegra_clk_duplicates[] = {
+	CLK_DUPLICATE("uarta",  "serial8250.0", NULL),
+	CLK_DUPLICATE("uartb",  "serial8250.1", NULL),
+	CLK_DUPLICATE("uartc",  "serial8250.2", NULL),
+	CLK_DUPLICATE("uartd",  "serial8250.3", NULL),
+	CLK_DUPLICATE("uarte",  "serial8250.4", NULL),
 	CLK_DUPLICATE("usbd", "utmip-pad", NULL),
 	CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
 	CLK_DUPLICATE("usbd", "tegra-otg", NULL),
diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c
index 315672c..57b5bdc 100644
--- a/arch/arm/mach-tegra/timer.c
+++ b/arch/arm/mach-tegra/timer.c
@@ -189,7 +189,7 @@ static void __init tegra_init_timer(void)
 			" Assuming 12Mhz input clock.\n");
 		rate = 12000000;
 	} else {
-		clk_enable(clk);
+		clk_prepare_enable(clk);
 		rate = clk_get_rate(clk);
 	}
 
@@ -201,7 +201,7 @@ static void __init tegra_init_timer(void)
 	if (IS_ERR(clk))
 		pr_warn("Unable to get rtc-tegra clock\n");
 	else
-		clk_enable(clk);
+		clk_prepare_enable(clk);
 
 	switch (rate) {
 	case 12000000:
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index 54e353c..022b33a 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -247,7 +247,7 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy)
 	unsigned long val, flags;
 	void __iomem *base = phy->pad_regs;
 
-	clk_enable(phy->pad_clk);
+	clk_prepare_enable(phy->pad_clk);
 
 	spin_lock_irqsave(&utmip_pad_lock, flags);
 
@@ -259,7 +259,7 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy)
 
 	spin_unlock_irqrestore(&utmip_pad_lock, flags);
 
-	clk_disable(phy->pad_clk);
+	clk_disable_unprepare(phy->pad_clk);
 }
 
 static int utmip_pad_power_off(struct tegra_usb_phy *phy)
@@ -272,7 +272,7 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy)
 		return -EINVAL;
 	}
 
-	clk_enable(phy->pad_clk);
+	clk_prepare_enable(phy->pad_clk);
 
 	spin_lock_irqsave(&utmip_pad_lock, flags);
 
@@ -284,7 +284,7 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy)
 
 	spin_unlock_irqrestore(&utmip_pad_lock, flags);
 
-	clk_disable(phy->pad_clk);
+	clk_disable_unprepare(phy->pad_clk);
 
 	return 0;
 }
@@ -580,7 +580,7 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
 	msleep(5);
 	gpio_direction_output(config->reset_gpio, 1);
 
-	clk_enable(phy->clk);
+	clk_prepare_enable(phy->clk);
 	msleep(1);
 
 	val = readl(base + USB_SUSP_CTRL);
@@ -689,7 +689,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
 		err = PTR_ERR(phy->pll_u);
 		goto err0;
 	}
-	clk_enable(phy->pll_u);
+	clk_prepare_enable(phy->pll_u);
 
 	parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
 	for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
@@ -735,7 +735,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
 	return phy;
 
 err1:
-	clk_disable(phy->pll_u);
+	clk_disable_unprepare(phy->pll_u);
 	clk_put(phy->pll_u);
 err0:
 	kfree(phy);
@@ -810,7 +810,7 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy)
 		clk_put(phy->clk);
 	else
 		utmip_pad_close(phy);
-	clk_disable(phy->pll_u);
+	clk_disable_unprepare(phy->pll_u);
 	clk_put(phy->pll_u);
 	kfree(phy);
 }
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index 1509a3c..10ddfaf 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -25,6 +25,7 @@
 #include <linux/mfd/tc3589x.h>
 #include <linux/mfd/tps6105x.h>
 #include <linux/mfd/abx500/ab8500-gpio.h>
+#include <linux/mfd/abx500/ab8500-codec.h>
 #include <linux/leds-lp5521.h>
 #include <linux/input.h>
 #include <linux/smsc911x.h>
@@ -97,6 +98,18 @@ static struct ab8500_gpio_platform_data ab8500_gpio_pdata = {
 					0x7A, 0x00, 0x00},
 };
 
+/* ab8500-codec */
+static struct ab8500_codec_platform_data ab8500_codec_pdata = {
+	.amics =  {
+		.mic1_type = AMIC_TYPE_DIFFERENTIAL,
+		.mic2_type = AMIC_TYPE_DIFFERENTIAL,
+		.mic1a_micbias = AMIC_MICBIAS_VAMIC1,
+		.mic1b_micbias = AMIC_MICBIAS_VAMIC1,
+		.mic2_micbias = AMIC_MICBIAS_VAMIC2
+	},
+	.ear_cmv = EAR_CMV_0_95V
+};
+
 static struct gpio_keys_button snowball_key_array[] = {
 	{
 		.gpio           = 32,
@@ -195,6 +208,7 @@ static struct ab8500_platform_data ab8500_platdata = {
 	.regulator	= ab8500_regulators,
 	.num_regulator	= ARRAY_SIZE(ab8500_regulators),
 	.gpio		= &ab8500_gpio_pdata,
+	.codec		= &ab8500_codec_pdata,
 };
 
 static struct resource ab8500_resources[] = {
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index cd8ea35..855ca02 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -37,7 +37,6 @@
 #include <linux/mtd/physmap.h>
 
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst.h>
 #include <asm/hardware/vic.h>
@@ -763,10 +762,6 @@ void __init versatile_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = versatile_leds_event;
-#endif
 }
 
 /*
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index d766e42..c10dab8 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -22,6 +22,7 @@
 #include <linux/memblock.h>
 #include <linux/slab.h>
 #include <linux/iommu.h>
+#include <linux/io.h>
 #include <linux/vmalloc.h>
 
 #include <asm/memory.h>
@@ -72,7 +73,7 @@ static dma_addr_t arm_dma_map_page(struct device *dev, struct page *page,
 	     unsigned long offset, size_t size, enum dma_data_direction dir,
 	     struct dma_attrs *attrs)
 {
-	if (!arch_is_coherent())
+	if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
 		__dma_page_cpu_to_dev(page, offset, size, dir);
 	return pfn_to_dma(dev, page_to_pfn(page)) + offset;
 }
@@ -95,7 +96,7 @@ static void arm_dma_unmap_page(struct device *dev, dma_addr_t handle,
 		size_t size, enum dma_data_direction dir,
 		struct dma_attrs *attrs)
 {
-	if (!arch_is_coherent())
+	if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
 		__dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)),
 				      handle & ~PAGE_MASK, size, dir);
 }
@@ -124,6 +125,7 @@ struct dma_map_ops arm_dma_ops = {
 	.alloc			= arm_dma_alloc,
 	.free			= arm_dma_free,
 	.mmap			= arm_dma_mmap,
+	.get_sgtable		= arm_dma_get_sgtable,
 	.map_page		= arm_dma_map_page,
 	.unmap_page		= arm_dma_unmap_page,
 	.map_sg			= arm_dma_map_sg,
@@ -217,115 +219,67 @@ static void __dma_free_buffer(struct page *page, size_t size)
 }
 
 #ifdef CONFIG_MMU
+#ifdef CONFIG_HUGETLB_PAGE
+#error ARM Coherent DMA allocator does not (yet) support huge TLB
+#endif
 
-#define CONSISTENT_OFFSET(x)	(((unsigned long)(x) - consistent_base) >> PAGE_SHIFT)
-#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - consistent_base) >> PMD_SHIFT)
-
-/*
- * These are the page tables (2MB each) covering uncached, DMA consistent allocations
- */
-static pte_t **consistent_pte;
-
-#define DEFAULT_CONSISTENT_DMA_SIZE SZ_2M
+static void *__alloc_from_contiguous(struct device *dev, size_t size,
+				     pgprot_t prot, struct page **ret_page);
 
-static unsigned long consistent_base = CONSISTENT_END - DEFAULT_CONSISTENT_DMA_SIZE;
+static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
+				 pgprot_t prot, struct page **ret_page,
+				 const void *caller);
 
-void __init init_consistent_dma_size(unsigned long size)
+static void *
+__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
+	const void *caller)
 {
-	unsigned long base = CONSISTENT_END - ALIGN(size, SZ_2M);
+	struct vm_struct *area;
+	unsigned long addr;
 
-	BUG_ON(consistent_pte); /* Check we're called before DMA region init */
-	BUG_ON(base < VMALLOC_END);
+	area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
+				  caller);
+	if (!area)
+		return NULL;
+	addr = (unsigned long)area->addr;
+	area->phys_addr = __pfn_to_phys(page_to_pfn(page));
 
-	/* Grow region to accommodate specified size  */
-	if (base < consistent_base)
-		consistent_base = base;
+	if (ioremap_page_range(addr, addr + size, area->phys_addr, prot)) {
+		vunmap((void *)addr);
+		return NULL;
+	}
+	return (void *)addr;
 }
 
-#include "vmregion.h"
-
-static struct arm_vmregion_head consistent_head = {
-	.vm_lock	= __SPIN_LOCK_UNLOCKED(&consistent_head.vm_lock),
-	.vm_list	= LIST_HEAD_INIT(consistent_head.vm_list),
-	.vm_end		= CONSISTENT_END,
-};
-
-#ifdef CONFIG_HUGETLB_PAGE
-#error ARM Coherent DMA allocator does not (yet) support huge TLB
-#endif
-
-/*
- * Initialise the consistent memory allocation.
- */
-static int __init consistent_init(void)
+static void __dma_free_remap(void *cpu_addr, size_t size)
 {
-	int ret = 0;
-	pgd_t *pgd;
-	pud_t *pud;
-	pmd_t *pmd;
-	pte_t *pte;
-	int i = 0;
-	unsigned long base = consistent_base;
-	unsigned long num_ptes = (CONSISTENT_END - base) >> PMD_SHIFT;
-
-	if (IS_ENABLED(CONFIG_CMA) && !IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
-		return 0;
-
-	consistent_pte = kmalloc(num_ptes * sizeof(pte_t), GFP_KERNEL);
-	if (!consistent_pte) {
-		pr_err("%s: no memory\n", __func__);
-		return -ENOMEM;
+	struct vm_struct *area = find_vm_area(cpu_addr);
+	if (!area || !(area->flags & VM_ARM_DMA_CONSISTENT)) {
+		pr_err("%s: trying to free invalid coherent area: %p\n",
+		       __func__, cpu_addr);
+		dump_stack();
+		return;
 	}
-
-	pr_debug("DMA memory: 0x%08lx - 0x%08lx:\n", base, CONSISTENT_END);
-	consistent_head.vm_start = base;
-
-	do {
-		pgd = pgd_offset(&init_mm, base);
-
-		pud = pud_alloc(&init_mm, pgd, base);
-		if (!pud) {
-			pr_err("%s: no pud tables\n", __func__);
-			ret = -ENOMEM;
-			break;
-		}
-
-		pmd = pmd_alloc(&init_mm, pud, base);
-		if (!pmd) {
-			pr_err("%s: no pmd tables\n", __func__);
-			ret = -ENOMEM;
-			break;
-		}
-		WARN_ON(!pmd_none(*pmd));
-
-		pte = pte_alloc_kernel(pmd, base);
-		if (!pte) {
-			pr_err("%s: no pte tables\n", __func__);
-			ret = -ENOMEM;
-			break;
-		}
-
-		consistent_pte[i++] = pte;
-		base += PMD_SIZE;
-	} while (base < CONSISTENT_END);
-
-	return ret;
+	unmap_kernel_range((unsigned long)cpu_addr, size);
+	vunmap(cpu_addr);
 }
-core_initcall(consistent_init);
-
-static void *__alloc_from_contiguous(struct device *dev, size_t size,
-				     pgprot_t prot, struct page **ret_page);
 
-static struct arm_vmregion_head coherent_head = {
-	.vm_lock	= __SPIN_LOCK_UNLOCKED(&coherent_head.vm_lock),
-	.vm_list	= LIST_HEAD_INIT(coherent_head.vm_list),
+struct dma_pool {
+	size_t size;
+	spinlock_t lock;
+	unsigned long *bitmap;
+	unsigned long nr_pages;
+	void *vaddr;
+	struct page *page;
 };
 
-static size_t coherent_pool_size = DEFAULT_CONSISTENT_DMA_SIZE / 8;
+static struct dma_pool atomic_pool = {
+	.size = SZ_256K,
+};
 
 static int __init early_coherent_pool(char *p)
 {
-	coherent_pool_size = memparse(p, &p);
+	atomic_pool.size = memparse(p, &p);
 	return 0;
 }
 early_param("coherent_pool", early_coherent_pool);
@@ -333,32 +287,45 @@ early_param("coherent_pool", early_coherent_pool);
 /*
  * Initialise the coherent pool for atomic allocations.
  */
-static int __init coherent_init(void)
+static int __init atomic_pool_init(void)
 {
+	struct dma_pool *pool = &atomic_pool;
 	pgprot_t prot = pgprot_dmacoherent(pgprot_kernel);
-	size_t size = coherent_pool_size;
+	unsigned long nr_pages = pool->size >> PAGE_SHIFT;
+	unsigned long *bitmap;
 	struct page *page;
 	void *ptr;
+	int bitmap_size = BITS_TO_LONGS(nr_pages) * sizeof(long);
 
-	if (!IS_ENABLED(CONFIG_CMA))
-		return 0;
+	bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+	if (!bitmap)
+		goto no_bitmap;
 
-	ptr = __alloc_from_contiguous(NULL, size, prot, &page);
+	if (IS_ENABLED(CONFIG_CMA))
+		ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page);
+	else
+		ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot,
+					   &page, NULL);
 	if (ptr) {
-		coherent_head.vm_start = (unsigned long) ptr;
-		coherent_head.vm_end = (unsigned long) ptr + size;
-		printk(KERN_INFO "DMA: preallocated %u KiB pool for atomic coherent allocations\n",
-		       (unsigned)size / 1024);
+		spin_lock_init(&pool->lock);
+		pool->vaddr = ptr;
+		pool->page = page;
+		pool->bitmap = bitmap;
+		pool->nr_pages = nr_pages;
+		pr_info("DMA: preallocated %u KiB pool for atomic coherent allocations\n",
+		       (unsigned)pool->size / 1024);
 		return 0;
 	}
-	printk(KERN_ERR "DMA: failed to allocate %u KiB pool for atomic coherent allocation\n",
-	       (unsigned)size / 1024);
+	kfree(bitmap);
+no_bitmap:
+	pr_err("DMA: failed to allocate %u KiB pool for atomic coherent allocation\n",
+	       (unsigned)pool->size / 1024);
 	return -ENOMEM;
 }
 /*
  * CMA is activated by core_initcall, so we must be called after it.
  */
-postcore_initcall(coherent_init);
+postcore_initcall(atomic_pool_init);
 
 struct dma_contig_early_reserve {
 	phys_addr_t base;
@@ -406,112 +373,6 @@ void __init dma_contiguous_remap(void)
 	}
 }
 
-static void *
-__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
-	const void *caller)
-{
-	struct arm_vmregion *c;
-	size_t align;
-	int bit;
-
-	if (!consistent_pte) {
-		pr_err("%s: not initialised\n", __func__);
-		dump_stack();
-		return NULL;
-	}
-
-	/*
-	 * Align the virtual region allocation - maximum alignment is
-	 * a section size, minimum is a page size.  This helps reduce
-	 * fragmentation of the DMA space, and also prevents allocations
-	 * smaller than a section from crossing a section boundary.
-	 */
-	bit = fls(size - 1);
-	if (bit > SECTION_SHIFT)
-		bit = SECTION_SHIFT;
-	align = 1 << bit;
-
-	/*
-	 * Allocate a virtual address in the consistent mapping region.
-	 */
-	c = arm_vmregion_alloc(&consistent_head, align, size,
-			    gfp & ~(__GFP_DMA | __GFP_HIGHMEM), caller);
-	if (c) {
-		pte_t *pte;
-		int idx = CONSISTENT_PTE_INDEX(c->vm_start);
-		u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
-
-		pte = consistent_pte[idx] + off;
-		c->priv = page;
-
-		do {
-			BUG_ON(!pte_none(*pte));
-
-			set_pte_ext(pte, mk_pte(page, prot), 0);
-			page++;
-			pte++;
-			off++;
-			if (off >= PTRS_PER_PTE) {
-				off = 0;
-				pte = consistent_pte[++idx];
-			}
-		} while (size -= PAGE_SIZE);
-
-		dsb();
-
-		return (void *)c->vm_start;
-	}
-	return NULL;
-}
-
-static void __dma_free_remap(void *cpu_addr, size_t size)
-{
-	struct arm_vmregion *c;
-	unsigned long addr;
-	pte_t *ptep;
-	int idx;
-	u32 off;
-
-	c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr);
-	if (!c) {
-		pr_err("%s: trying to free invalid coherent area: %p\n",
-		       __func__, cpu_addr);
-		dump_stack();
-		return;
-	}
-
-	if ((c->vm_end - c->vm_start) != size) {
-		pr_err("%s: freeing wrong coherent size (%ld != %d)\n",
-		       __func__, c->vm_end - c->vm_start, size);
-		dump_stack();
-		size = c->vm_end - c->vm_start;
-	}
-
-	idx = CONSISTENT_PTE_INDEX(c->vm_start);
-	off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
-	ptep = consistent_pte[idx] + off;
-	addr = c->vm_start;
-	do {
-		pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
-
-		ptep++;
-		addr += PAGE_SIZE;
-		off++;
-		if (off >= PTRS_PER_PTE) {
-			off = 0;
-			ptep = consistent_pte[++idx];
-		}
-
-		if (pte_none(pte) || !pte_present(pte))
-			pr_crit("%s: bad page in kernel page table\n",
-				__func__);
-	} while (size -= PAGE_SIZE);
-
-	flush_tlb_kernel_range(c->vm_start, c->vm_end);
-
-	arm_vmregion_free(&consistent_head, c);
-}
-
 static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr,
 			    void *data)
 {
@@ -552,15 +413,17 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
 	return ptr;
 }
 
-static void *__alloc_from_pool(struct device *dev, size_t size,
-			       struct page **ret_page, const void *caller)
+static void *__alloc_from_pool(size_t size, struct page **ret_page)
 {
-	struct arm_vmregion *c;
+	struct dma_pool *pool = &atomic_pool;
+	unsigned int count = size >> PAGE_SHIFT;
+	unsigned int pageno;
+	unsigned long flags;
+	void *ptr = NULL;
 	size_t align;
 
-	if (!coherent_head.vm_start) {
-		printk(KERN_ERR "%s: coherent pool not initialised!\n",
-		       __func__);
+	if (!pool->vaddr) {
+		pr_err("%s: coherent pool not initialised!\n", __func__);
 		dump_stack();
 		return NULL;
 	}
@@ -571,35 +434,42 @@ static void *__alloc_from_pool(struct device *dev, size_t size,
 	 * size. This helps reduce fragmentation of the DMA space.
 	 */
 	align = PAGE_SIZE << get_order(size);
-	c = arm_vmregion_alloc(&coherent_head, align, size, 0, caller);
-	if (c) {
-		void *ptr = (void *)c->vm_start;
-		struct page *page = virt_to_page(ptr);
-		*ret_page = page;
-		return ptr;
+
+	spin_lock_irqsave(&pool->lock, flags);
+	pageno = bitmap_find_next_zero_area(pool->bitmap, pool->nr_pages,
+					    0, count, (1 << align) - 1);
+	if (pageno < pool->nr_pages) {
+		bitmap_set(pool->bitmap, pageno, count);
+		ptr = pool->vaddr + PAGE_SIZE * pageno;
+		*ret_page = pool->page + pageno;
 	}
-	return NULL;
+	spin_unlock_irqrestore(&pool->lock, flags);
+
+	return ptr;
 }
 
-static int __free_from_pool(void *cpu_addr, size_t size)
+static int __free_from_pool(void *start, size_t size)
 {
-	unsigned long start = (unsigned long)cpu_addr;
-	unsigned long end = start + size;
-	struct arm_vmregion *c;
+	struct dma_pool *pool = &atomic_pool;
+	unsigned long pageno, count;
+	unsigned long flags;
 
-	if (start < coherent_head.vm_start || end > coherent_head.vm_end)
+	if (start < pool->vaddr || start > pool->vaddr + pool->size)
 		return 0;
 
-	c = arm_vmregion_find_remove(&coherent_head, (unsigned long)start);
-
-	if ((c->vm_end - c->vm_start) != size) {
-		printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
-		       __func__, c->vm_end - c->vm_start, size);
+	if (start + size > pool->vaddr + pool->size) {
+		pr_err("%s: freeing wrong coherent size from pool\n", __func__);
 		dump_stack();
-		size = c->vm_end - c->vm_start;
+		return 0;
 	}
 
-	arm_vmregion_free(&coherent_head, c);
+	pageno = (start - pool->vaddr) >> PAGE_SHIFT;
+	count = size >> PAGE_SHIFT;
+
+	spin_lock_irqsave(&pool->lock, flags);
+	bitmap_clear(pool->bitmap, pageno, count);
+	spin_unlock_irqrestore(&pool->lock, flags);
+
 	return 1;
 }
 
@@ -702,10 +572,10 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
 
 	if (arch_is_coherent() || nommu())
 		addr = __alloc_simple_buffer(dev, size, gfp, &page);
+	else if (gfp & GFP_ATOMIC)
+		addr = __alloc_from_pool(size, &page);
 	else if (!IS_ENABLED(CONFIG_CMA))
 		addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller);
-	else if (gfp & GFP_ATOMIC)
-		addr = __alloc_from_pool(dev, size, &page, caller);
 	else
 		addr = __alloc_from_contiguous(dev, size, prot, &page);
 
@@ -741,16 +611,22 @@ int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
 {
 	int ret = -ENXIO;
 #ifdef CONFIG_MMU
+	unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
 	unsigned long pfn = dma_to_pfn(dev, dma_addr);
+	unsigned long off = vma->vm_pgoff;
+
 	vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
 
 	if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
 		return ret;
 
-	ret = remap_pfn_range(vma, vma->vm_start,
-			      pfn + vma->vm_pgoff,
-			      vma->vm_end - vma->vm_start,
-			      vma->vm_page_prot);
+	if (off < count && user_count <= (count - off)) {
+		ret = remap_pfn_range(vma, vma->vm_start,
+				      pfn + off,
+				      user_count << PAGE_SHIFT,
+				      vma->vm_page_prot);
+	}
 #endif	/* CONFIG_MMU */
 
 	return ret;
@@ -785,6 +661,21 @@ void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
 	}
 }
 
+int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+		 void *cpu_addr, dma_addr_t handle, size_t size,
+		 struct dma_attrs *attrs)
+{
+	struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
+	int ret;
+
+	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
+	if (unlikely(ret))
+		return ret;
+
+	sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
+	return 0;
+}
+
 static void dma_cache_maint_page(struct page *page, unsigned long offset,
 	size_t size, enum dma_data_direction dir,
 	void (*op)(const void *, size_t, int))
@@ -998,9 +889,6 @@ static int arm_dma_set_mask(struct device *dev, u64 dma_mask)
 
 static int __init dma_debug_do_init(void)
 {
-#ifdef CONFIG_MMU
-	arm_vmregion_create_proc("dma-mappings", &consistent_head);
-#endif
 	dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
 	return 0;
 }
@@ -1067,7 +955,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t
 		return NULL;
 
 	while (count) {
-		int j, order = __ffs(count);
+		int j, order = __fls(count);
 
 		pages[i] = alloc_pages(gfp | __GFP_NOWARN, order);
 		while (!pages[i] && order)
@@ -1117,61 +1005,32 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t s
  * Create a CPU mapping for a specified pages
  */
 static void *
-__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot)
+__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot,
+		    const void *caller)
 {
-	struct arm_vmregion *c;
-	size_t align;
-	size_t count = size >> PAGE_SHIFT;
-	int bit;
+	unsigned int i, nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+	struct vm_struct *area;
+	unsigned long p;
 
-	if (!consistent_pte[0]) {
-		pr_err("%s: not initialised\n", __func__);
-		dump_stack();
+	area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
+				  caller);
+	if (!area)
 		return NULL;
-	}
 
-	/*
-	 * Align the virtual region allocation - maximum alignment is
-	 * a section size, minimum is a page size.  This helps reduce
-	 * fragmentation of the DMA space, and also prevents allocations
-	 * smaller than a section from crossing a section boundary.
-	 */
-	bit = fls(size - 1);
-	if (bit > SECTION_SHIFT)
-		bit = SECTION_SHIFT;
-	align = 1 << bit;
+	area->pages = pages;
+	area->nr_pages = nr_pages;
+	p = (unsigned long)area->addr;
 
-	/*
-	 * Allocate a virtual address in the consistent mapping region.
-	 */
-	c = arm_vmregion_alloc(&consistent_head, align, size,
-			    gfp & ~(__GFP_DMA | __GFP_HIGHMEM), NULL);
-	if (c) {
-		pte_t *pte;
-		int idx = CONSISTENT_PTE_INDEX(c->vm_start);
-		int i = 0;
-		u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
-
-		pte = consistent_pte[idx] + off;
-		c->priv = pages;
-
-		do {
-			BUG_ON(!pte_none(*pte));
-
-			set_pte_ext(pte, mk_pte(pages[i], prot), 0);
-			pte++;
-			off++;
-			i++;
-			if (off >= PTRS_PER_PTE) {
-				off = 0;
-				pte = consistent_pte[++idx];
-			}
-		} while (i < count);
-
-		dsb();
-
-		return (void *)c->vm_start;
+	for (i = 0; i < nr_pages; i++) {
+		phys_addr_t phys = __pfn_to_phys(page_to_pfn(pages[i]));
+		if (ioremap_page_range(p, p + PAGE_SIZE, phys, prot))
+			goto err;
+		p += PAGE_SIZE;
 	}
+	return area->addr;
+err:
+	unmap_kernel_range((unsigned long)area->addr, size);
+	vunmap(area->addr);
 	return NULL;
 }
 
@@ -1230,6 +1089,19 @@ static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t si
 	return 0;
 }
 
+static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs)
+{
+	struct vm_struct *area;
+
+	if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
+		return cpu_addr;
+
+	area = find_vm_area(cpu_addr);
+	if (area && (area->flags & VM_ARM_DMA_CONSISTENT))
+		return area->pages;
+	return NULL;
+}
+
 static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
 	    dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
 {
@@ -1248,7 +1120,11 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
 	if (*handle == DMA_ERROR_CODE)
 		goto err_buffer;
 
-	addr = __iommu_alloc_remap(pages, size, gfp, prot);
+	if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
+		return pages;
+
+	addr = __iommu_alloc_remap(pages, size, gfp, prot,
+				   __builtin_return_address(0));
 	if (!addr)
 		goto err_mapping;
 
@@ -1265,31 +1141,25 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
 		    void *cpu_addr, dma_addr_t dma_addr, size_t size,
 		    struct dma_attrs *attrs)
 {
-	struct arm_vmregion *c;
+	unsigned long uaddr = vma->vm_start;
+	unsigned long usize = vma->vm_end - vma->vm_start;
+	struct page **pages = __iommu_get_pages(cpu_addr, attrs);
 
 	vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
-	c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
-
-	if (c) {
-		struct page **pages = c->priv;
 
-		unsigned long uaddr = vma->vm_start;
-		unsigned long usize = vma->vm_end - vma->vm_start;
-		int i = 0;
-
-		do {
-			int ret;
+	if (!pages)
+		return -ENXIO;
 
-			ret = vm_insert_page(vma, uaddr, pages[i++]);
-			if (ret) {
-				pr_err("Remapping memory, error: %d\n", ret);
-				return ret;
-			}
+	do {
+		int ret = vm_insert_page(vma, uaddr, *pages++);
+		if (ret) {
+			pr_err("Remapping memory failed: %d\n", ret);
+			return ret;
+		}
+		uaddr += PAGE_SIZE;
+		usize -= PAGE_SIZE;
+	} while (usize > 0);
 
-			uaddr += PAGE_SIZE;
-			usize -= PAGE_SIZE;
-		} while (usize > 0);
-	}
 	return 0;
 }
 
@@ -1300,16 +1170,37 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
 void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
 			  dma_addr_t handle, struct dma_attrs *attrs)
 {
-	struct arm_vmregion *c;
+	struct page **pages = __iommu_get_pages(cpu_addr, attrs);
 	size = PAGE_ALIGN(size);
 
-	c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
-	if (c) {
-		struct page **pages = c->priv;
-		__dma_free_remap(cpu_addr, size);
-		__iommu_remove_mapping(dev, handle, size);
-		__iommu_free_buffer(dev, pages, size);
+	if (!pages) {
+		pr_err("%s: trying to free invalid coherent area: %p\n",
+		       __func__, cpu_addr);
+		dump_stack();
+		return;
 	}
+
+	if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) {
+		unmap_kernel_range((unsigned long)cpu_addr, size);
+		vunmap(cpu_addr);
+	}
+
+	__iommu_remove_mapping(dev, handle, size);
+	__iommu_free_buffer(dev, pages, size);
+}
+
+static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
+				 void *cpu_addr, dma_addr_t dma_addr,
+				 size_t size, struct dma_attrs *attrs)
+{
+	unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+	struct page **pages = __iommu_get_pages(cpu_addr, attrs);
+
+	if (!pages)
+		return -ENXIO;
+
+	return sg_alloc_table_from_pages(sgt, pages, count, 0, size,
+					 GFP_KERNEL);
 }
 
 /*
@@ -1317,7 +1208,7 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
  */
 static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
 			  size_t size, dma_addr_t *handle,
-			  enum dma_data_direction dir)
+			  enum dma_data_direction dir, struct dma_attrs *attrs)
 {
 	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
 	dma_addr_t iova, iova_base;
@@ -1336,7 +1227,8 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
 		phys_addr_t phys = page_to_phys(sg_page(s));
 		unsigned int len = PAGE_ALIGN(s->offset + s->length);
 
-		if (!arch_is_coherent())
+		if (!arch_is_coherent() &&
+		    !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
 			__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
 
 		ret = iommu_map(mapping->domain, iova, phys, len, 0);
@@ -1383,7 +1275,7 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 
 		if (s->offset || (size & ~PAGE_MASK) || size + s->length > max) {
 			if (__map_sg_chunk(dev, start, size, &dma->dma_address,
-			    dir) < 0)
+			    dir, attrs) < 0)
 				goto bad_mapping;
 
 			dma->dma_address += offset;
@@ -1396,7 +1288,7 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 		}
 		size += s->length;
 	}
-	if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir) < 0)
+	if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir, attrs) < 0)
 		goto bad_mapping;
 
 	dma->dma_address += offset;
@@ -1430,7 +1322,8 @@ void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
 		if (sg_dma_len(s))
 			__iommu_remove_mapping(dev, sg_dma_address(s),
 					       sg_dma_len(s));
-		if (!arch_is_coherent())
+		if (!arch_is_coherent() &&
+		    !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
 			__dma_page_dev_to_cpu(sg_page(s), s->offset,
 					      s->length, dir);
 	}
@@ -1492,7 +1385,7 @@ static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
 	dma_addr_t dma_addr;
 	int ret, len = PAGE_ALIGN(size + offset);
 
-	if (!arch_is_coherent())
+	if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
 		__dma_page_cpu_to_dev(page, offset, size, dir);
 
 	dma_addr = __alloc_iova(mapping, len);
@@ -1531,7 +1424,7 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
 	if (!iova)
 		return;
 
-	if (!arch_is_coherent())
+	if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
 		__dma_page_dev_to_cpu(page, offset, size, dir);
 
 	iommu_unmap(mapping->domain, iova, len);
@@ -1571,6 +1464,7 @@ struct dma_map_ops iommu_ops = {
 	.alloc		= arm_iommu_alloc_attrs,
 	.free		= arm_iommu_free_attrs,
 	.mmap		= arm_iommu_mmap_attrs,
+	.get_sgtable	= arm_iommu_get_sgtable,
 
 	.map_page		= arm_iommu_map_page,
 	.unmap_page		= arm_iommu_unmap_page,
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index c471436..d9b47a1 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -59,6 +59,9 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page
 #define VM_ARM_MTYPE(mt)		((mt) << 20)
 #define VM_ARM_MTYPE_MASK	(0x1f << 20)
 
+/* consistent regions used by dma_alloc_attrs() */
+#define VM_ARM_DMA_CONSISTENT	0x20000000
+
 #endif
 
 #ifdef CONFIG_ZONE_DMA
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 4e0a371..99c63d4b 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -23,26 +23,37 @@
 #include <asm/ptrace.h>
 
 #ifdef CONFIG_HW_PERF_EVENTS
+
+/*
+ * OProfile has a curious naming scheme for the ARM PMUs, but they are
+ * part of the user ABI so we need to map from the perf PMU name for
+ * supported PMUs.
+ */
+static struct op_perf_name {
+	char *perf_name;
+	char *op_name;
+} op_perf_name_map[] = {
+	{ "xscale1",		"arm/xscale1"	},
+	{ "xscale1",		"arm/xscale2"	},
+	{ "v6",			"arm/armv6"	},
+	{ "v6mpcore",		"arm/mpcore"	},
+	{ "ARMv7 Cortex-A8",	"arm/armv7"	},
+	{ "ARMv7 Cortex-A9",	"arm/armv7-ca9"	},
+};
+
 char *op_name_from_perf_id(void)
 {
-	enum arm_perf_pmu_ids id = armpmu_get_pmu_id();
-
-	switch (id) {
-	case ARM_PERF_PMU_ID_XSCALE1:
-		return "arm/xscale1";
-	case ARM_PERF_PMU_ID_XSCALE2:
-		return "arm/xscale2";
-	case ARM_PERF_PMU_ID_V6:
-		return "arm/armv6";
-	case ARM_PERF_PMU_ID_V6MP:
-		return "arm/mpcore";
-	case ARM_PERF_PMU_ID_CA8:
-		return "arm/armv7";
-	case ARM_PERF_PMU_ID_CA9:
-		return "arm/armv7-ca9";
-	default:
-		return NULL;
+	int i;
+	struct op_perf_name names;
+	const char *perf_name = perf_pmu_name();
+
+	for (i = 0; i < ARRAY_SIZE(op_perf_name_map); ++i) {
+		names = op_perf_name_map[i];
+		if (!strcmp(names.perf_name, perf_name))
+			return names.op_name;
 	}
+
+	return NULL;
 }
 #endif
 
diff --git a/arch/arm/plat-mxc/devices/platform-mxc_nand.c b/arch/arm/plat-mxc/devices/platform-mxc_nand.c
index 1568f39..95b75cc 100644
--- a/arch/arm/plat-mxc/devices/platform-mxc_nand.c
+++ b/arch/arm/plat-mxc/devices/platform-mxc_nand.c
@@ -63,10 +63,6 @@ struct platform_device *__init imx_add_mxc_nand(
 	/* AXI has to come first, that's how the mxc_nand driver expect it */
 	struct resource res[] = {
 		{
-			.start = data->axibase,
-			.end = data->axibase + SZ_16K - 1,
-			.flags = IORESOURCE_MEM,
-		}, {
 			.start = data->iobase,
 			.end = data->iobase + data->iosize - 1,
 			.flags = IORESOURCE_MEM,
@@ -74,10 +70,13 @@ struct platform_device *__init imx_add_mxc_nand(
 			.start = data->irq,
 			.end = data->irq,
 			.flags = IORESOURCE_IRQ,
+		}, {
+			.start = data->axibase,
+			.end = data->axibase + SZ_16K - 1,
+			.flags = IORESOURCE_MEM,
 		},
 	};
 	return imx_add_platform_device("mxc_nand", data->id,
-			res + !data->axibase,
-			ARRAY_SIZE(res) - !data->axibase,
+			res, ARRAY_SIZE(res) - !data->axibase,
 			pdata, sizeof(*pdata));
 }
diff --git a/arch/arm/plat-mxc/include/mach/mx2_cam.h b/arch/arm/plat-mxc/include/mach/mx2_cam.h
index 7ded6f1..3c080a3 100644
--- a/arch/arm/plat-mxc/include/mach/mx2_cam.h
+++ b/arch/arm/plat-mxc/include/mach/mx2_cam.h
@@ -23,6 +23,7 @@
 #ifndef __MACH_MX2_CAM_H_
 #define __MACH_MX2_CAM_H_
 
+#define MX2_CAMERA_SWAP16		(1 << 0)
 #define MX2_CAMERA_EXT_VSYNC		(1 << 1)
 #define MX2_CAMERA_CCIR			(1 << 2)
 #define MX2_CAMERA_CCIR_INTERLACE	(1 << 3)
@@ -30,6 +31,7 @@
 #define MX2_CAMERA_GATED_CLOCK		(1 << 5)
 #define MX2_CAMERA_INV_DATA		(1 << 6)
 #define MX2_CAMERA_PCLK_SAMPLE_RISING	(1 << 7)
+#define MX2_CAMERA_PACK_DIR_MSB		(1 << 8)
 
 /**
  * struct mx2_camera_platform_data - optional platform data for mx2_camera
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index ad95c7a..aa8e668 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -41,9 +41,8 @@ config OMAP_DEBUG_DEVICES
 	  For debug cards on TI reference boards.
 
 config OMAP_DEBUG_LEDS
-	bool
+	def_bool y if NEW_LEDS
 	depends on OMAP_DEBUG_DEVICES
-	default y if LEDS_CLASS
 
 config OMAP_SMARTREFLEX
 	bool "SmartReflex support"
diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c
index 39407cb..24e23f3 100644
--- a/arch/arm/plat-omap/debug-leds.c
+++ b/arch/arm/plat-omap/debug-leds.c
@@ -1,279 +1,118 @@
 /*
  * linux/arch/arm/plat-omap/debug-leds.c
  *
+ * Copyright 2011 by Bryan Wu <bryan.wu@canonical.com>
  * Copyright 2003 by Texas Instruments Incorporated
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/gpio.h>
+
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/io.h>
+#include <linux/slab.h>
 
 #include <mach/hardware.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 
 #include <plat/fpga.h>
 
-
 /* Many OMAP development platforms reuse the same "debug board"; these
  * platforms include H2, H3, H4, and Perseus2.  There are 16 LEDs on the
  * debug board (all green), accessed through FPGA registers.
- *
- * The "surfer" expansion board and H2 sample board also have two-color
- * green+red LEDs (in parallel), used here for timer and idle indicators
- * in preference to the ones on the debug board, for a "Disco LED" effect.
- *
- * This driver exports either the original ARM LED API, the new generic
- * one, or both.
- */
-
-static spinlock_t			lock;
-static struct h2p2_dbg_fpga __iomem	*fpga;
-static u16				led_state, hw_led_state;
-
-
-#ifdef	CONFIG_OMAP_DEBUG_LEDS
-#define new_led_api()	1
-#else
-#define new_led_api()	0
-#endif
-
-
-/*-------------------------------------------------------------------------*/
-
-/* original ARM debug LED API:
- *  - timer and idle leds (some boards use non-FPGA leds here);
- *  - up to 4 generic leds, easily accessed in-kernel (any context)
  */
 
-#define GPIO_LED_RED		3
-#define GPIO_LED_GREEN		OMAP_MPUIO(4)
-
-#define LED_STATE_ENABLED	0x01
-#define LED_STATE_CLAIMED	0x02
-#define LED_TIMER_ON		0x04
-
-#define GPIO_IDLE		GPIO_LED_GREEN
-#define GPIO_TIMER		GPIO_LED_RED
-
-static void h2p2_dbg_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&lock, flags);
-
-	if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
-		goto done;
-
-	switch (evt) {
-	case led_start:
-		if (fpga)
-			led_state |= LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-	case led_halted:
-		/* all leds off during suspend or shutdown */
-
-		if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) {
-			gpio_set_value(GPIO_TIMER, 0);
-			gpio_set_value(GPIO_IDLE, 0);
-		}
-
-		__raw_writew(~0, &fpga->leds);
-		led_state &= ~LED_STATE_ENABLED;
-		goto done;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		led_state ^= LED_TIMER_ON;
-
-		if (machine_is_omap_perseus2() || machine_is_omap_h4())
-			hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
-		else {
-			gpio_set_value(GPIO_TIMER,
-					led_state & LED_TIMER_ON);
-			goto done;
-		}
-
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	/* LED lit iff busy */
-	case led_idle_start:
-		if (machine_is_omap_perseus2() || machine_is_omap_h4())
-			hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
-		else {
-			gpio_set_value(GPIO_IDLE, 1);
-			goto done;
-		}
-
-		break;
+static struct h2p2_dbg_fpga __iomem *fpga;
 
-	case led_idle_end:
-		if (machine_is_omap_perseus2() || machine_is_omap_h4())
-			hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
-		else {
-			gpio_set_value(GPIO_IDLE, 0);
-			goto done;
-		}
-
-		break;
-#endif
-
-	case led_green_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
-		break;
-	case led_green_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
-		break;
-
-	case led_amber_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
-		break;
-	case led_amber_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
-		break;
-
-	case led_red_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_RED;
-		break;
-	case led_red_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
-		break;
-
-	case led_blue_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
-		break;
-	case led_blue_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
-		break;
-
-	default:
-		break;
-	}
-
-
-	/*
-	 *  Actually burn the LEDs
-	 */
-	if (led_state & LED_STATE_ENABLED)
-		__raw_writew(~hw_led_state, &fpga->leds);
-
-done:
-	spin_unlock_irqrestore(&lock, flags);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* "new" LED API
- *  - with syfs access and generic triggering
- *  - not readily accessible to in-kernel drivers
- */
+static u16 fpga_led_state;
 
 struct dbg_led {
 	struct led_classdev	cdev;
 	u16			mask;
 };
 
-static struct dbg_led dbg_leds[] = {
-	/* REVISIT at least H2 uses different timer & cpu leds... */
-#ifndef CONFIG_LEDS_TIMER
-	{ .mask = 1 << 0,  .cdev.name =  "d4:green",
-		.cdev.default_trigger = "heartbeat", },
-#endif
-#ifndef CONFIG_LEDS_CPU
-	{ .mask = 1 << 1,  .cdev.name =  "d5:green", },		/* !idle */
-#endif
-	{ .mask = 1 << 2,  .cdev.name =  "d6:green", },
-	{ .mask = 1 << 3,  .cdev.name =  "d7:green", },
-
-	{ .mask = 1 << 4,  .cdev.name =  "d8:green", },
-	{ .mask = 1 << 5,  .cdev.name =  "d9:green", },
-	{ .mask = 1 << 6,  .cdev.name = "d10:green", },
-	{ .mask = 1 << 7,  .cdev.name = "d11:green", },
-
-	{ .mask = 1 << 8,  .cdev.name = "d12:green", },
-	{ .mask = 1 << 9,  .cdev.name = "d13:green", },
-	{ .mask = 1 << 10, .cdev.name = "d14:green", },
-	{ .mask = 1 << 11, .cdev.name = "d15:green", },
-
-#ifndef	CONFIG_LEDS
-	{ .mask = 1 << 12, .cdev.name = "d16:green", },
-	{ .mask = 1 << 13, .cdev.name = "d17:green", },
-	{ .mask = 1 << 14, .cdev.name = "d18:green", },
-	{ .mask = 1 << 15, .cdev.name = "d19:green", },
-#endif
+static const struct {
+	const char *name;
+	const char *trigger;
+} dbg_leds[] = {
+	{ "dbg:d4", "heartbeat", },
+	{ "dbg:d5", "cpu0", },
+	{ "dbg:d6", "default-on", },
+	{ "dbg:d7", },
+	{ "dbg:d8", },
+	{ "dbg:d9", },
+	{ "dbg:d10", },
+	{ "dbg:d11", },
+	{ "dbg:d12", },
+	{ "dbg:d13", },
+	{ "dbg:d14", },
+	{ "dbg:d15", },
+	{ "dbg:d16", },
+	{ "dbg:d17", },
+	{ "dbg:d18", },
+	{ "dbg:d19", },
 };
 
-static void
-fpga_led_set(struct led_classdev *cdev, enum led_brightness value)
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static void dbg_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
 {
-	struct dbg_led	*led = container_of(cdev, struct dbg_led, cdev);
-	unsigned long	flags;
+	struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
+	u16 reg;
 
-	spin_lock_irqsave(&lock, flags);
-	if (value == LED_OFF)
-		hw_led_state &= ~led->mask;
+	reg = __raw_readw(&fpga->leds);
+	if (b != LED_OFF)
+		reg |= led->mask;
 	else
-		hw_led_state |= led->mask;
-	__raw_writew(~hw_led_state, &fpga->leds);
-	spin_unlock_irqrestore(&lock, flags);
+		reg &= ~led->mask;
+	__raw_writew(reg, &fpga->leds);
 }
 
-static void __init newled_init(struct device *dev)
+static enum led_brightness dbg_led_get(struct led_classdev *cdev)
 {
-	unsigned	i;
-	struct dbg_led	*led;
-	int		status;
+	struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
+	u16 reg;
 
-	for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) {
-		led->cdev.brightness_set = fpga_led_set;
-		status = led_classdev_register(dev, &led->cdev);
-		if (status < 0)
-			break;
-	}
-	return;
+	reg = __raw_readw(&fpga->leds);
+	return (reg & led->mask) ? LED_FULL : LED_OFF;
 }
 
-
-/*-------------------------------------------------------------------------*/
-
-static int /* __init */ fpga_probe(struct platform_device *pdev)
+static int fpga_probe(struct platform_device *pdev)
 {
 	struct resource	*iomem;
-
-	spin_lock_init(&lock);
+	int i;
 
 	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!iomem)
 		return -ENODEV;
 
 	fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
-	__raw_writew(~0, &fpga->leds);
+	__raw_writew(0xff, &fpga->leds);
+
+	for (i = 0; i < ARRAY_SIZE(dbg_leds); i++) {
+		struct dbg_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
 
-#ifdef	CONFIG_LEDS
-	leds_event = h2p2_dbg_leds_event;
-	leds_event(led_start);
-#endif
+		led->cdev.name = dbg_leds[i].name;
+		led->cdev.brightness_set = dbg_led_set;
+		led->cdev.brightness_get = dbg_led_get;
+		led->cdev.default_trigger = dbg_leds[i].trigger;
+		led->mask = BIT(i);
 
-	if (new_led_api()) {
-		newled_init(&pdev->dev);
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
 	}
 
 	return 0;
@@ -281,13 +120,15 @@ static int /* __init */ fpga_probe(struct platform_device *pdev)
 
 static int fpga_suspend_noirq(struct device *dev)
 {
-	__raw_writew(~0, &fpga->leds);
+	fpga_led_state = __raw_readw(&fpga->leds);
+	__raw_writew(0xff, &fpga->leds);
+
 	return 0;
 }
 
 static int fpga_resume_noirq(struct device *dev)
 {
-	__raw_writew(~hw_led_state, &fpga->leds);
+	__raw_writew(~fpga_led_state, &fpga->leds);
 	return 0;
 }
 
diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c
index eb9f4f5..f9eb353 100644
--- a/arch/arm/plat-samsung/dma-ops.c
+++ b/arch/arm/plat-samsung/dma-ops.c
@@ -19,72 +19,80 @@
 #include <mach/dma.h>
 
 static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
-				struct samsung_dma_info *info)
+				struct samsung_dma_req *param)
 {
-	struct dma_chan *chan;
 	dma_cap_mask_t mask;
-	struct dma_slave_config slave_config;
 	void *filter_param;
 
 	dma_cap_zero(mask);
-	dma_cap_set(info->cap, mask);
+	dma_cap_set(param->cap, mask);
 
 	/*
 	 * If a dma channel property of a device node from device tree is
 	 * specified, use that as the fliter parameter.
 	 */
-	filter_param = (dma_ch == DMACH_DT_PROP) ? (void *)info->dt_dmach_prop :
-				(void *)dma_ch;
-	chan = dma_request_channel(mask, pl330_filter, filter_param);
+	filter_param = (dma_ch == DMACH_DT_PROP) ?
+		(void *)param->dt_dmach_prop : (void *)dma_ch;
+	return (unsigned)dma_request_channel(mask, pl330_filter, filter_param);
+}
 
-	if (info->direction == DMA_DEV_TO_MEM) {
+static int samsung_dmadev_release(unsigned ch,
+			struct s3c2410_dma_client *client)
+{
+	dma_release_channel((struct dma_chan *)ch);
+
+	return 0;
+}
+
+static int samsung_dmadev_config(unsigned ch,
+				struct samsung_dma_config *param)
+{
+	struct dma_chan *chan = (struct dma_chan *)ch;
+	struct dma_slave_config slave_config;
+
+	if (param->direction == DMA_DEV_TO_MEM) {
 		memset(&slave_config, 0, sizeof(struct dma_slave_config));
-		slave_config.direction = info->direction;
-		slave_config.src_addr = info->fifo;
-		slave_config.src_addr_width = info->width;
+		slave_config.direction = param->direction;
+		slave_config.src_addr = param->fifo;
+		slave_config.src_addr_width = param->width;
 		slave_config.src_maxburst = 1;
 		dmaengine_slave_config(chan, &slave_config);
-	} else if (info->direction == DMA_MEM_TO_DEV) {
+	} else if (param->direction == DMA_MEM_TO_DEV) {
 		memset(&slave_config, 0, sizeof(struct dma_slave_config));
-		slave_config.direction = info->direction;
-		slave_config.dst_addr = info->fifo;
-		slave_config.dst_addr_width = info->width;
+		slave_config.direction = param->direction;
+		slave_config.dst_addr = param->fifo;
+		slave_config.dst_addr_width = param->width;
 		slave_config.dst_maxburst = 1;
 		dmaengine_slave_config(chan, &slave_config);
+	} else {
+		pr_warn("unsupported direction\n");
+		return -EINVAL;
 	}
 
-	return (unsigned)chan;
-}
-
-static int samsung_dmadev_release(unsigned ch,
-			struct s3c2410_dma_client *client)
-{
-	dma_release_channel((struct dma_chan *)ch);
-
 	return 0;
 }
 
 static int samsung_dmadev_prepare(unsigned ch,
-			struct samsung_dma_prep_info *info)
+			struct samsung_dma_prep *param)
 {
 	struct scatterlist sg;
 	struct dma_chan *chan = (struct dma_chan *)ch;
 	struct dma_async_tx_descriptor *desc;
 
-	switch (info->cap) {
+	switch (param->cap) {
 	case DMA_SLAVE:
 		sg_init_table(&sg, 1);
-		sg_dma_len(&sg) = info->len;
-		sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)),
-			    info->len, offset_in_page(info->buf));
-		sg_dma_address(&sg) = info->buf;
+		sg_dma_len(&sg) = param->len;
+		sg_set_page(&sg, pfn_to_page(PFN_DOWN(param->buf)),
+			    param->len, offset_in_page(param->buf));
+		sg_dma_address(&sg) = param->buf;
 
 		desc = dmaengine_prep_slave_sg(chan,
-			&sg, 1, info->direction, DMA_PREP_INTERRUPT);
+			&sg, 1, param->direction, DMA_PREP_INTERRUPT);
 		break;
 	case DMA_CYCLIC:
-		desc = dmaengine_prep_dma_cyclic(chan,
-			info->buf, info->len, info->period, info->direction);
+		desc = dmaengine_prep_dma_cyclic(chan, param->buf,
+			param->len, param->period, param->direction);
 		break;
 	default:
 		dev_err(&chan->dev->device, "unsupported format\n");
@@ -96,8 +104,8 @@ static int samsung_dmadev_prepare(unsigned ch,
 		return -EFAULT;
 	}
 
-	desc->callback = info->fp;
-	desc->callback_param = info->fp_param;
+	desc->callback = param->fp;
+	desc->callback_param = param->fp_param;
 
 	dmaengine_submit((struct dma_async_tx_descriptor *)desc);
 
@@ -119,6 +127,7 @@ static inline int samsung_dmadev_flush(unsigned ch)
 static struct samsung_dma_ops dmadev_ops = {
 	.request	= samsung_dmadev_request,
 	.release	= samsung_dmadev_release,
+	.config		= samsung_dmadev_config,
 	.prepare	= samsung_dmadev_prepare,
 	.trigger	= samsung_dmadev_trigger,
 	.started	= NULL,
diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h
index 0721293..ace4451 100644
--- a/arch/arm/plat-samsung/include/plat/cpu.h
+++ b/arch/arm/plat-samsung/include/plat/cpu.h
@@ -132,6 +132,10 @@ IS_SAMSUNG_CPU(exynos5250, EXYNOS5250_SOC_ID, EXYNOS5_SOC_MASK)
 
 #define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
 
+#ifndef KHZ
+#define KHZ (1000)
+#endif
+
 #ifndef MHZ
 #define MHZ (1000*1000)
 #endif
diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h
index 71a6827..f5144cd 100644
--- a/arch/arm/plat-samsung/include/plat/dma-ops.h
+++ b/arch/arm/plat-samsung/include/plat/dma-ops.h
@@ -16,7 +16,13 @@
 #include <linux/dmaengine.h>
 #include <mach/dma.h>
 
-struct samsung_dma_prep_info {
+struct samsung_dma_req {
+	enum dma_transaction_type cap;
+	struct property *dt_dmach_prop;
+	struct s3c2410_dma_client *client;
+};
+
+struct samsung_dma_prep {
 	enum dma_transaction_type cap;
 	enum dma_transfer_direction direction;
 	dma_addr_t buf;
@@ -26,19 +32,17 @@ struct samsung_dma_prep_info {
 	void *fp_param;
 };
 
-struct samsung_dma_info {
-	enum dma_transaction_type cap;
+struct samsung_dma_config {
 	enum dma_transfer_direction direction;
 	enum dma_slave_buswidth width;
 	dma_addr_t fifo;
-	struct s3c2410_dma_client *client;
-	struct property *dt_dmach_prop;
 };
 
 struct samsung_dma_ops {
-	unsigned (*request)(enum dma_ch ch, struct samsung_dma_info *info);
-	int (*release)(unsigned ch, struct s3c2410_dma_client *client);
-	int (*prepare)(unsigned ch, struct samsung_dma_prep_info *info);
+	unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param);
+	int (*release)(unsigned ch, void *param);
+	int (*config)(unsigned ch, struct samsung_dma_config *param);
+	int (*prepare)(unsigned ch, struct samsung_dma_prep *param);
 	int (*trigger)(unsigned ch);
 	int (*started)(unsigned ch);
 	int (*flush)(unsigned ch);
diff --git a/arch/arm/plat-samsung/include/plat/fb.h b/arch/arm/plat-samsung/include/plat/fb.h
index 536002f..b885322 100644
--- a/arch/arm/plat-samsung/include/plat/fb.h
+++ b/arch/arm/plat-samsung/include/plat/fb.h
@@ -43,7 +43,6 @@ struct s3c_fb_pd_win {
  * @setup_gpio: Setup the external GPIO pins to the right state to transfer
  *		the data from the display system to the connected display
  *		device.
- * @default_win: default window layer number to be used for UI layer.
  * @vidcon0: The base vidcon0 values to control the panel data format.
  * @vidcon1: The base vidcon1 values to control the panel data output.
  * @vtiming: Video timing when connected to a RGB type panel.
diff --git a/arch/arm/plat-samsung/include/plat/map-s3c.h b/arch/arm/plat-samsung/include/plat/map-s3c.h
index 7d04875..c0c70a8 100644
--- a/arch/arm/plat-samsung/include/plat/map-s3c.h
+++ b/arch/arm/plat-samsung/include/plat/map-s3c.h
@@ -22,7 +22,7 @@
 #define S3C24XX_VA_WATCHDOG	S3C_VA_WATCHDOG
 
 #define S3C2412_VA_SSMC		S3C_ADDR_CPU(0x00000000)
-#define S3C2412_VA_EBI		S3C_ADDR_CPU(0x00010000)
+#define S3C2412_VA_EBI		S3C_ADDR_CPU(0x00100000)
 
 #define S3C2410_PA_UART		(0x50000000)
 #define S3C24XX_PA_UART		S3C2410_PA_UART
diff --git a/arch/arm/plat-samsung/include/plat/watchdog-reset.h b/arch/arm/plat-samsung/include/plat/watchdog-reset.h
index f19aff1..bc4db9b 100644
--- a/arch/arm/plat-samsung/include/plat/watchdog-reset.h
+++ b/arch/arm/plat-samsung/include/plat/watchdog-reset.h
@@ -25,7 +25,7 @@ static inline void arch_wdt_reset(void)
 
 	__raw_writel(0, S3C2410_WTCON);	  /* disable watchdog, to be safe  */
 
-	if (s3c2410_wdtclk)
+	if (!IS_ERR(s3c2410_wdtclk))
 		clk_enable(s3c2410_wdtclk);
 
 	/* put initial values into count and data */
diff --git a/arch/arm/plat-samsung/pwm.c b/arch/arm/plat-samsung/pwm.c
index c559d84..d358305 100644
--- a/arch/arm/plat-samsung/pwm.c
+++ b/arch/arm/plat-samsung/pwm.c
@@ -36,7 +36,6 @@ struct pwm_device {
 	unsigned int		 duty_ns;
 
 	unsigned char		 tcon_base;
-	unsigned char		 running;
 	unsigned char		 use_count;
 	unsigned char		 pwm_id;
 };
@@ -116,7 +115,6 @@ int pwm_enable(struct pwm_device *pwm)
 
 	local_irq_restore(flags);
 
-	pwm->running = 1;
 	return 0;
 }
 
@@ -134,8 +132,6 @@ void pwm_disable(struct pwm_device *pwm)
 	__raw_writel(tcon, S3C2410_TCON);
 
 	local_irq_restore(flags);
-
-	pwm->running = 0;
 }
 
 EXPORT_SYMBOL(pwm_disable);
diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c
index 7814949..f99448c 100644
--- a/arch/arm/plat-samsung/s3c-dma-ops.c
+++ b/arch/arm/plat-samsung/s3c-dma-ops.c
@@ -36,30 +36,26 @@ static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param,
 }
 
 static unsigned s3c_dma_request(enum dma_ch dma_ch,
-				 struct samsung_dma_info *info)
+					struct samsung_dma_req *param)
 {
 	struct cb_data *data;
 
-	if (s3c2410_dma_request(dma_ch, info->client, NULL) < 0) {
-		s3c2410_dma_free(dma_ch, info->client);
+	if (s3c2410_dma_request(dma_ch, param->client, NULL) < 0) {
+		s3c2410_dma_free(dma_ch, param->client);
 		return 0;
 	}
 
+	if (param->cap == DMA_CYCLIC)
+		s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
+
 	data = kzalloc(sizeof(struct cb_data), GFP_KERNEL);
 	data->ch = dma_ch;
 	list_add_tail(&data->node, &dma_list);
 
-	s3c2410_dma_devconfig(dma_ch, info->direction, info->fifo);
-
-	if (info->cap == DMA_CYCLIC)
-		s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
-
-	s3c2410_dma_config(dma_ch, info->width);
-
 	return (unsigned)dma_ch;
 }
 
-static int s3c_dma_release(unsigned ch, struct s3c2410_dma_client *client)
+static int s3c_dma_release(unsigned ch, void *param)
 {
 	struct cb_data *data;
 
@@ -68,16 +64,24 @@ static int s3c_dma_release(unsigned ch, struct s3c2410_dma_client *client)
 			break;
 	list_del(&data->node);
 
-	s3c2410_dma_free(ch, client);
+	s3c2410_dma_free(ch, param);
 	kfree(data);
 
 	return 0;
 }
 
-static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
+static int s3c_dma_config(unsigned ch, struct samsung_dma_config *param)
+{
+	s3c2410_dma_devconfig(ch, param->direction, param->fifo);
+	s3c2410_dma_config(ch, param->width);
+
+	return 0;
+}
+
+static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
 {
 	struct cb_data *data;
-	int len = (info->cap == DMA_CYCLIC) ? info->period : info->len;
+	int len = (param->cap == DMA_CYCLIC) ? param->period : param->len;
 
 	list_for_each_entry(data, &dma_list, node)
 		if (data->ch == ch)
@@ -85,11 +89,11 @@ static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
 
 	if (!data->fp) {
 		s3c2410_dma_set_buffdone_fn(ch, s3c_dma_cb);
-		data->fp = info->fp;
-		data->fp_param = info->fp_param;
+		data->fp = param->fp;
+		data->fp_param = param->fp_param;
 	}
 
-	s3c2410_dma_enqueue(ch, (void *)data, info->buf, len);
+	s3c2410_dma_enqueue(ch, (void *)data, param->buf, len);
 
 	return 0;
 }
@@ -117,6 +121,7 @@ static inline int s3c_dma_stop(unsigned ch)
 static struct samsung_dma_ops s3c_dma_ops = {
 	.request	= s3c_dma_request,
 	.release	= s3c_dma_release,
+	.config		= s3c_dma_config,
 	.prepare	= s3c_dma_prepare,
 	.trigger	= s3c_dma_trigger,
 	.started	= s3c_dma_started,
diff --git a/arch/arm/plat-samsung/time.c b/arch/arm/plat-samsung/time.c
index 4dcb11c..60552e2 100644
--- a/arch/arm/plat-samsung/time.c
+++ b/arch/arm/plat-samsung/time.c
@@ -28,7 +28,6 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 
 #include <asm/irq.h>
diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig
index 81ee7cc..5c73e31 100644
--- a/arch/arm/plat-versatile/Kconfig
+++ b/arch/arm/plat-versatile/Kconfig
@@ -13,8 +13,10 @@ config PLAT_VERSATILE_FPGA_IRQ_NR
        depends on PLAT_VERSATILE_FPGA_IRQ
 
 config PLAT_VERSATILE_LEDS
-	def_bool y if LEDS_CLASS
+	def_bool y if NEW_LEDS
 	depends on ARCH_REALVIEW || ARCH_VERSATILE
+	select LEDS_CLASS
+	select LEDS_TRIGGER
 
 config PLAT_VERSATILE_SCHED_CLOCK
 	def_bool y
diff --git a/arch/arm/plat-versatile/leds.c b/arch/arm/plat-versatile/leds.c
index 3169fa5..50090c4 100644
--- a/arch/arm/plat-versatile/leds.c
+++ b/arch/arm/plat-versatile/leds.c
@@ -37,10 +37,10 @@ static const struct {
 } versatile_leds[] = {
 	{ "versatile:0", "heartbeat", },
 	{ "versatile:1", "mmc0", },
-	{ "versatile:2", },
-	{ "versatile:3", },
-	{ "versatile:4", },
-	{ "versatile:5", },
+	{ "versatile:2", "cpu0" },
+	{ "versatile:3", "cpu1" },
+	{ "versatile:4", "cpu2" },
+	{ "versatile:5", "cpu3" },
 	{ "versatile:6", },
 	{ "versatile:7", },
 };
@@ -85,6 +85,11 @@ static int __init versatile_leds_init(void)
 		led->cdev.brightness_set = versatile_led_set;
 		led->cdev.brightness_get = versatile_led_get;
 		led->cdev.default_trigger = versatile_leds[i].trigger;
+		/* Some trigger data for CPU LEDs */
+		if (i >= 2 && i <= 5) {
+			/* This is the CPU number actually */
+			led->cdev.trigger_data = (void *) i - 2;
+		}
 		led->mask = BIT(i);
 
 		if (led_classdev_register(NULL, &led->cdev) < 0) {
diff --git a/arch/arm/plat-versatile/platsmp.c b/arch/arm/plat-versatile/platsmp.c
index 49c7db4..d7c5c17 100644
--- a/arch/arm/plat-versatile/platsmp.c
+++ b/arch/arm/plat-versatile/platsmp.c
@@ -85,7 +85,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 	 * the boot monitor to read the system wide flags register,
 	 * and branch to the address found there.
 	 */
-	gic_raise_softirq(cpumask_of(cpu), 1);
+	gic_raise_softirq(cpumask_of(cpu), 0);
 
 	timeout = jiffies + (1 * HZ);
 	while (time_before(jiffies, timeout)) {
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 2d30c7f..d50f0e4 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -16,6 +16,7 @@
  */
 #include <asm/thread_info.h>
 #include <asm/vfpmacros.h>
+#include <linux/kern_levels.h>
 #include "../kernel/entry-header.S"
 
 	.macro	DBGSTR, str
@@ -24,7 +25,7 @@
 	add	r0, pc, #4
 	bl	printk
 	b	1f
-	.asciz  "<7>VFP: \str\n"
+	.asciz  KERN_DEBUG "VFP: \str\n"
 	.balign 4
 1:	ldmfd	sp!, {r0-r3, ip, lr}
 #endif
@@ -37,7 +38,7 @@
 	add	r0, pc, #4
 	bl	printk
 	b	1f
-	.asciz  "<7>VFP: \str\n"
+	.asciz  KERN_DEBUG "VFP: \str\n"
 	.balign 4
 1:	ldmfd	sp!, {r0-r3, ip, lr}
 #endif
@@ -52,7 +53,7 @@
 	add	r0, pc, #4
 	bl	printk
 	b	1f
-	.asciz  "<7>VFP: \str\n"
+	.asciz  KERN_DEBUG "VFP: \str\n"
 	.balign 4
 1:	ldmfd	sp!, {r0-r3, ip, lr}
 #endif
diff --git a/arch/avr32/include/asm/kmap_types.h b/arch/avr32/include/asm/kmap_types.h
index b7f5c68..479330b 100644
--- a/arch/avr32/include/asm/kmap_types.h
+++ b/arch/avr32/include/asm/kmap_types.h
@@ -2,29 +2,9 @@
 #define __ASM_AVR32_KMAP_TYPES_H
 
 #ifdef CONFIG_DEBUG_HIGHMEM
-# define D(n) __KM_FENCE_##n ,
+# define KM_TYPE_NR 29
 #else
-# define D(n)
+# define KM_TYPE_NR 14
 #endif
 
-enum km_type {
-D(0)	KM_BOUNCE_READ,
-D(1)	KM_SKB_SUNRPC_DATA,
-D(2)	KM_SKB_DATA_SOFTIRQ,
-D(3)	KM_USER0,
-D(4)	KM_USER1,
-D(5)	KM_BIO_SRC_IRQ,
-D(6)	KM_BIO_DST_IRQ,
-D(7)	KM_PTE0,
-D(8)	KM_PTE1,
-D(9)	KM_PTE2,
-D(10)	KM_IRQ0,
-D(11)	KM_IRQ1,
-D(12)	KM_SOFTIRQ0,
-D(13)	KM_SOFTIRQ1,
-D(14)	KM_TYPE_NR
-};
-
-#undef D
-
 #endif /* __ASM_AVR32_KMAP_TYPES_H */
diff --git a/arch/avr32/include/asm/thread_info.h b/arch/avr32/include/asm/thread_info.h
index e5deda4..2f0c412 100644
--- a/arch/avr32/include/asm/thread_info.h
+++ b/arch/avr32/include/asm/thread_info.h
@@ -77,8 +77,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_TRACE       0       /* syscall trace active */
 #define TIF_SIGPENDING          1       /* signal pending */
 #define TIF_NEED_RESCHED        2       /* rescheduling necessary */
-#define TIF_POLLING_NRFLAG      3       /* true if poll_idle() is polling
-					   TIF_NEED_RESCHED */
 #define TIF_BREAKPOINT		4	/* enter monitor mode on return */
 #define TIF_SINGLE_STEP		5	/* single step in progress */
 #define TIF_MEMDIE		6	/* is terminating due to OOM killer */
@@ -91,10 +89,8 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_SINGLE_STEP	(1 << TIF_SINGLE_STEP)
 #define _TIF_MEMDIE		(1 << TIF_MEMDIE)
-#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 #define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 
@@ -102,17 +98,14 @@ static inline struct thread_info *current_thread_info(void)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK				\
-	((1 << TIF_SIGPENDING)			\
+	(_TIF_SIGPENDING			\
 	 | _TIF_NOTIFY_RESUME			\
-	 | (1 << TIF_NEED_RESCHED)		\
-	 | (1 << TIF_POLLING_NRFLAG)		\
-	 | (1 << TIF_BREAKPOINT)		\
-	 | (1 << TIF_RESTORE_SIGMASK))
+	 | _TIF_NEED_RESCHED			\
+	 | _TIF_BREAKPOINT)
 
 /* work to do on any return to userspace */
-#define _TIF_ALLWORK_MASK	(_TIF_WORK_MASK | (1 << TIF_SYSCALL_TRACE) | \
-				 _TIF_NOTIFY_RESUME)
+#define _TIF_ALLWORK_MASK	(_TIF_WORK_MASK | _TIF_SYSCALL_TRACE)
 /* work to do on return from debug mode */
-#define _TIF_DBGWORK_MASK	(_TIF_WORK_MASK & ~(1 << TIF_BREAKPOINT))
+#define _TIF_DBGWORK_MASK	(_TIF_WORK_MASK & ~_TIF_BREAKPOINT)
 
 #endif /* __ASM_AVR32_THREAD_INFO_H */
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
index d552a85..5e01c3a 100644
--- a/arch/avr32/kernel/signal.c
+++ b/arch/avr32/kernel/signal.c
@@ -15,7 +15,6 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 
 #include <asm/uaccess.h>
diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c
index f7040a1..b92e609 100644
--- a/arch/avr32/mm/fault.c
+++ b/arch/avr32/mm/fault.c
@@ -61,10 +61,10 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
 	const struct exception_table_entry *fixup;
 	unsigned long address;
 	unsigned long page;
-	int writeaccess;
 	long signr;
 	int code;
 	int fault;
+	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
 	if (notify_page_fault(regs, ecr))
 		return;
@@ -86,6 +86,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
 
 	local_irq_enable();
 
+retry:
 	down_read(&mm->mmap_sem);
 
 	vma = find_vma(mm, address);
@@ -104,7 +105,6 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
 	 */
 good_area:
 	code = SEGV_ACCERR;
-	writeaccess = 0;
 
 	switch (ecr) {
 	case ECR_PROTECTION_X:
@@ -121,7 +121,7 @@ good_area:
 	case ECR_TLB_MISS_W:
 		if (!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
-		writeaccess = 1;
+		flags |= FAULT_FLAG_WRITE;
 		break;
 	default:
 		panic("Unhandled case %lu in do_page_fault!", ecr);
@@ -132,7 +132,11 @@ good_area:
 	 * sure we exit gracefully rather than endlessly redo the
 	 * fault.
 	 */
-	fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0);
+	fault = handle_mm_fault(mm, vma, address, flags);
+
+	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+		return;
+
 	if (unlikely(fault & VM_FAULT_ERROR)) {
 		if (fault & VM_FAULT_OOM)
 			goto out_of_memory;
@@ -140,10 +144,23 @@ good_area:
 			goto do_sigbus;
 		BUG();
 	}
-	if (fault & VM_FAULT_MAJOR)
-		tsk->maj_flt++;
-	else
-		tsk->min_flt++;
+
+	if (flags & FAULT_FLAG_ALLOW_RETRY) {
+		if (fault & VM_FAULT_MAJOR)
+			tsk->maj_flt++;
+		else
+			tsk->min_flt++;
+		if (fault & VM_FAULT_RETRY) {
+			flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+			/*
+			 * No need to up_read(&mm->mmap_sem) as we would have
+			 * already released it in __lock_page_or_retry() in
+			 * mm/filemap.c.
+			 */
+			goto retry;
+		}
+	}
 
 	up_read(&mm->mmap_sem);
 	return;
diff --git a/arch/blackfin/include/asm/thread_info.h b/arch/blackfin/include/asm/thread_info.h
index 53ad100..3894005 100644
--- a/arch/blackfin/include/asm/thread_info.h
+++ b/arch/blackfin/include/asm/thread_info.h
@@ -96,8 +96,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 #define TIF_SIGPENDING		1	/* signal pending */
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
-#define TIF_POLLING_NRFLAG	3	/* true if poll_idle() is polling
-					   TIF_NEED_RESCHED */
 #define TIF_MEMDIE		4	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	5	/* restore signal mask in do_signal() */
 #define TIF_IRQ_SYNC		7	/* sync pipeline stage */
@@ -108,8 +106,6 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_IRQ_SYNC		(1<<TIF_IRQ_SYNC)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index 6682b73..6ed20a1 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -10,7 +10,6 @@
 #include <linux/tty.h>
 #include <linux/personality.h>
 #include <linux/binfmts.h>
-#include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/tracehook.h>
 
diff --git a/arch/c6x/include/asm/thread_info.h b/arch/c6x/include/asm/thread_info.h
index 1710bcb..4c8dc56 100644
--- a/arch/c6x/include/asm/thread_info.h
+++ b/arch/c6x/include/asm/thread_info.h
@@ -97,7 +97,6 @@ struct thread_info *current_thread_info(void)
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_RESTORE_SIGMASK	4	/* restore signal mask in do_signal() */
 
-#define TIF_POLLING_NRFLAG	16	/* true if polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17	/* OOM killer killed process */
 
 #define TIF_WORK_MASK		0x00007FFE /* work on irq/exception return */
diff --git a/arch/c6x/kernel/asm-offsets.c b/arch/c6x/kernel/asm-offsets.c
index 759ad6d..60f1e43 100644
--- a/arch/c6x/kernel/asm-offsets.c
+++ b/arch/c6x/kernel/asm-offsets.c
@@ -116,7 +116,6 @@ void foo(void)
 	DEFINE(_TIF_NOTIFY_RESUME, (1<<TIF_NOTIFY_RESUME));
 	DEFINE(_TIF_SIGPENDING, (1<<TIF_SIGPENDING));
 	DEFINE(_TIF_NEED_RESCHED, (1<<TIF_NEED_RESCHED));
-	DEFINE(_TIF_POLLING_NRFLAG, (1<<TIF_POLLING_NRFLAG));
 
 	DEFINE(_TIF_ALLWORK_MASK, TIF_ALLWORK_MASK);
 	DEFINE(_TIF_WORK_MASK, TIF_WORK_MASK);
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index bb34465..ca038af 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -137,11 +137,6 @@ config CRIS_MACH_ARTPEC3
 
 endchoice
 
-config ETRAX_VCS_SIM
-	bool "VCS Simulator"
-	help
-	  Setup hardware to be run in the VCS simulator.
-
 config ETRAX_ARCH_V10
        bool
        default y if ETRAX100LX || ETRAX100LX_V2
diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c
index b34438e..1b6ad62 100644
--- a/arch/cris/arch-v32/drivers/axisflashmap.c
+++ b/arch/cris/arch-v32/drivers/axisflashmap.c
@@ -329,7 +329,6 @@ static int __init init_axis_flash(void)
 	}
 #endif
 
-#ifndef CONFIG_ETRAX_VCS_SIM
 	main_mtd = flash_probe();
 	if (main_mtd)
 		printk(KERN_INFO "%s: 0x%08x bytes of NOR flash memory.\n",
@@ -603,34 +602,7 @@ static int __init init_axis_flash(void)
 					"partition %d\n", part);
 		}
 	}
-#endif /* CONFIG_EXTRAX_VCS_SIM */
 
-#ifdef CONFIG_ETRAX_VCS_SIM
-	/* For simulator, always use a RAM partition.
-	 * The rootfs will be found after the kernel in RAM,
-	 * with romfs_start and romfs_end indicating location and size.
-	 */
-	struct mtd_info *mtd_ram;
-
-	mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-	if (!mtd_ram) {
-		panic("axisflashmap: Couldn't allocate memory for "
-		      "mtd_info!\n");
-	}
-
-	printk(KERN_INFO "axisflashmap: Adding RAM partition for romfs, "
-	       "at %u, size %u\n",
-	       (unsigned) romfs_start, (unsigned) romfs_length);
-
-	err = mtdram_init_device(mtd_ram, (void *)romfs_start,
-				 romfs_length, "romfs");
-	if (err) {
-		panic("axisflashmap: Could not initialize MTD RAM "
-		      "device!\n");
-	}
-#endif /* CONFIG_EXTRAX_VCS_SIM */
-
-#ifndef CONFIG_ETRAX_VCS_SIM
 	if (aux_mtd) {
 		aux_partition.size = aux_mtd->size;
 		err = mtd_device_register(aux_mtd, &aux_partition, 1);
@@ -639,7 +611,6 @@ static int __init init_axis_flash(void)
 			      "aux mtd device!\n");
 
 	}
-#endif /* CONFIG_EXTRAX_VCS_SIM */
 
 	return err;
 }
diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c
index bc0cfda..f748ced 100644
--- a/arch/cris/arch-v32/drivers/pci/bios.c
+++ b/arch/cris/arch-v32/drivers/pci/bios.c
@@ -102,28 +102,3 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 		pcibios_enable_irq(dev);
 	return 0;
 }
-
-int pcibios_assign_resources(void)
-{
-	struct pci_dev *dev = NULL;
-	int idx;
-	struct resource *r;
-
-	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-		int class = dev->class >> 8;
-
-		/* Don't touch classless devices and host bridges */
-		if (!class || class == PCI_CLASS_BRIDGE_HOST)
-			continue;
-
-		for(idx=0; idx<6; idx++) {
-			r = &dev->resource[idx];
-
-			if (!r->start && r->end)
-				pci_assign_resource(dev, idx);
-		}
-	}
-	return 0;
-}
-
-EXPORT_SYMBOL(pcibios_assign_resources);
diff --git a/arch/cris/arch-v32/kernel/head.S b/arch/cris/arch-v32/kernel/head.S
index 5d502b9..51e3416 100644
--- a/arch/cris/arch-v32/kernel/head.S
+++ b/arch/cris/arch-v32/kernel/head.S
@@ -36,13 +36,6 @@
 	.global nand_boot
 	.global swapper_pg_dir
 
-	;; Dummy section to make it bootable with current VCS simulator
-#ifdef CONFIG_ETRAX_VCS_SIM
-	.section ".boot", "ax"
-	ba tstart
-	nop
-#endif
-
 	.text
 tstart:
 	;; This is the entry point of the kernel. The CPU is currently in
@@ -75,17 +68,10 @@ secondary_cpu_entry: /* Entry point for secondary CPUs */
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)	\
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 5)     \
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
-#elif !defined(CONFIG_ETRAX_VCS_SIM)
-	move.d	REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)	\
-		| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)	\
-		| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
 #else
-	;; Map the virtual DRAM to the RW eprom area at address 0.
-	;; Also map 0xa for the hook calls,
 	move.d	REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)	\
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)	\
-		| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb)   \
-		| REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0
+		| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
 #endif
 
 	;; Temporary map of 0x40 -> 0x40 and 0x00 -> 0x00.
@@ -126,27 +112,6 @@ secondary_cpu_entry: /* Entry point for secondary CPUs */
 		| REG_STATE(mmu, rw_mm_cfg, seg_2, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_1, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2
-#elif !defined(CONFIG_ETRAX_VCS_SIM)
-	move.d	REG_STATE(mmu, rw_mm_cfg, we, on)		\
-		| REG_STATE(mmu, rw_mm_cfg, acc, on)		\
-		| REG_STATE(mmu, rw_mm_cfg, ex, on)		\
-		| REG_STATE(mmu, rw_mm_cfg, inv, on)		\
-		| REG_STATE(mmu, rw_mm_cfg, seg_f, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_e, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_d, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_c, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_b, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_a, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_9, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_8, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_7, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_6, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_5, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_4, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_3, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_2, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_1, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2
 #else
 	move.d	REG_STATE(mmu, rw_mm_cfg, we, on)		\
 		| REG_STATE(mmu, rw_mm_cfg, acc, on)		\
@@ -157,7 +122,7 @@ secondary_cpu_entry: /* Entry point for secondary CPUs */
 		| REG_STATE(mmu, rw_mm_cfg, seg_d, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_c, linear)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_b, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_a, linear)	\
+		| REG_STATE(mmu, rw_mm_cfg, seg_a, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_9, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_8, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_7, page)	\
@@ -226,7 +191,6 @@ master_cpu:
 	move.d secondary_cpu_entry, $r1
 	move.d $r1, [$r0]
 #endif
-#ifndef CONFIG_ETRAX_VCS_SIM
 	; Check if starting from DRAM (network->RAM boot or unpacked
 	; compressed kernel), or directly from flash.
 	lapcq	., $r0
@@ -234,7 +198,6 @@ master_cpu:
 	cmp.d	0x10000, $r0	; Arbitrary, something above this code.
 	blo	_inflash0
 	nop
-#endif
 
 	jump	_inram		; Jump to cached RAM.
 	nop
@@ -326,7 +289,6 @@ move_cramfs:
 	move.d	romfs_length, $r1
 	move.d	$r0, [$r1]
 
-#ifndef CONFIG_ETRAX_VCS_SIM
 	;; The kernel could have been unpacked to DRAM by the loader, but
 	;; the cramfs image could still be in the flash immediately
 	;; following the compressed kernel image. The loader passes the address
@@ -335,10 +297,6 @@ move_cramfs:
 	cmp.d	0x0ffffff8, $r9
 	bhs	_no_romfs_in_flash ; R9 points outside the flash area.
 	nop
-#else
-	ba _no_romfs_in_flash
-	nop
-#endif
 	;; cramfs rootfs might to be in flash. Check for it.
 	move.d	[$r9], $r0	; cramfs_super.magic
 	cmp.d	CRAMFS_MAGIC, $r0
@@ -396,7 +354,6 @@ _no_romfs_in_flash:
 	move.d	romfs_length, $r3
 	move.d	$r2, [$r3]	; store size at romfs_length
 
-#ifndef CONFIG_ETRAX_VCS_SIM
 	add.d	$r2, $r0	; copy from end and downwards
 	add.d	$r2, $r1
 
@@ -410,7 +367,6 @@ _no_romfs_in_flash:
 	subq	1, $r2
 	bne	1b
 	nop
-#endif
 
 4:
 	;; BSS move done.
@@ -455,7 +411,6 @@ no_command_line:
 	move.d	etrax_irv, $r1	; Set the exception base register and pointer.
 	move.d	$r0, [$r1]
 
-#ifndef CONFIG_ETRAX_VCS_SIM
 	;; Clear the BSS region from _bss_start to _end.
 	move.d	__bss_start, $r0
 	move.d	_end, $r1
@@ -463,15 +418,6 @@ no_command_line:
 	cmp.d	$r1, $r0
 	blo 1b
 	nop
-#endif
-
-#ifdef CONFIG_ETRAX_VCS_SIM
-	/* Set the watchdog timeout to something big. Will be removed when */
-	/* watchdog can be disabled with command line option */
-	move.d  0x7fffffff, $r10
-	jsr     CPU_WATCHDOG_TIMEOUT
-	nop
-#endif
 
 	; Initialize registers to increase determinism
 	move.d __bss_start, $r0
diff --git a/arch/cris/arch-v32/kernel/kgdb.c b/arch/cris/arch-v32/kernel/kgdb.c
index 8c1d35c..b06813a 100644
--- a/arch/cris/arch-v32/kernel/kgdb.c
+++ b/arch/cris/arch-v32/kernel/kgdb.c
@@ -381,23 +381,9 @@ static int read_register(char regno, unsigned int *valptr);
 /* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
 int getDebugChar(void);
 
-#ifdef CONFIG_ETRAX_VCS_SIM
-int getDebugChar(void)
-{
-  return socketread();
-}
-#endif
-
 /* Serial port, writes one character. ETRAX 100 specific. from debugport.c */
 void putDebugChar(int val);
 
-#ifdef CONFIG_ETRAX_VCS_SIM
-void putDebugChar(int val)
-{
-  socketwrite((char *)&val, 1);
-}
-#endif
-
 /* Returns the integer equivalent of a hexadecimal character. */
 static int hex(char ch);
 
diff --git a/arch/cris/arch-v32/mach-a3/Makefile b/arch/cris/arch-v32/mach-a3/Makefile
index 41fa6a6..d366e08 100644
--- a/arch/cris/arch-v32/mach-a3/Makefile
+++ b/arch/cris/arch-v32/mach-a3/Makefile
@@ -1,10 +1,8 @@
-# $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $
 #
 # Makefile for the linux kernel.
 #
 
 obj-y   := dma.o pinmux.o io.o arbiter.o
-obj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
 obj-$(CONFIG_CPU_FREQ)   += cpufreq.o
 
 clean:
diff --git a/arch/cris/arch-v32/mach-a3/vcs_hook.c b/arch/cris/arch-v32/mach-a3/vcs_hook.c
deleted file mode 100644
index 58b1a54..0000000
--- a/arch/cris/arch-v32/mach-a3/vcs_hook.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Simulator hook mechanism
- */
-
-#include "vcs_hook.h"
-#include <asm/io.h>
-#include <stdarg.h>
-
-#define HOOK_TRIG_ADDR      0xb7000000
-#define HOOK_MEM_BASE_ADDR  0xce000000
-
-static volatile unsigned *hook_base;
-
-#define HOOK_DATA(offset) hook_base[offset]
-#define VHOOK_DATA(offset) hook_base[offset]
-#define HOOK_TRIG(funcid) \
-	do { \
-		*((unsigned *) HOOK_TRIG_ADDR) = funcid; \
-	} while (0)
-#define HOOK_DATA_BYTE(offset) ((unsigned char *)hook_base)[offset]
-
-static void hook_init(void)
-{
-	static int first = 1;
-	if (first) {
-		first = 0;
-		hook_base = ioremap(HOOK_MEM_BASE_ADDR, 8192);
-	}
-}
-
-static unsigned hook_trig(unsigned id)
-{
-	unsigned ret;
-
-	/* preempt_disable(); */
-
-	/* Dummy read from mem to make sure data has propagated to memory
-	 * before trigging */
-	ret = *hook_base;
-
-	/* trigger hook */
-	HOOK_TRIG(id);
-
-	/* wait for call to finish */
-	while (VHOOK_DATA(0) > 0) ;
-
-	/* extract return value */
-
-	ret = VHOOK_DATA(1);
-
-	return ret;
-}
-
-int hook_call(unsigned id, unsigned pcnt, ...)
-{
-	va_list ap;
-	int i;
-	unsigned ret;
-
-	hook_init();
-
-	HOOK_DATA(0) = id;
-
-	va_start(ap, pcnt);
-	for (i = 1; i <= pcnt; i++)
-		HOOK_DATA(i) = va_arg(ap, unsigned);
-	va_end(ap);
-
-	ret = hook_trig(id);
-
-	return ret;
-}
-
-int hook_call_str(unsigned id, unsigned size, const char *str)
-{
-	int i;
-	unsigned ret;
-
-	hook_init();
-
-	HOOK_DATA(0) = id;
-	HOOK_DATA(1) = size;
-
-	for (i = 0; i < size; i++)
-		HOOK_DATA_BYTE(8 + i) = str[i];
-	HOOK_DATA_BYTE(8 + i) = 0;
-
-	ret = hook_trig(id);
-
-	return ret;
-}
-
-void print_str(const char *str)
-{
-	int i;
-	/* find null at end of string */
-	for (i = 1; str[i]; i++) ;
-	hook_call(hook_print_str, i, str);
-}
-
-void CPU_WATCHDOG_TIMEOUT(unsigned t)
-{
-}
diff --git a/arch/cris/arch-v32/mach-a3/vcs_hook.h b/arch/cris/arch-v32/mach-a3/vcs_hook.h
deleted file mode 100644
index 8b73d0e..0000000
--- a/arch/cris/arch-v32/mach-a3/vcs_hook.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Simulator hook call mechanism
- */
-
-#ifndef __hook_h__
-#define __hook_h__
-
-int hook_call(unsigned id, unsigned pcnt, ...);
-int hook_call_str(unsigned id, unsigned size, const char *str);
-
-enum hook_ids {
-  hook_debug_on = 1,
-  hook_debug_off,
-  hook_stop_sim_ok,
-  hook_stop_sim_fail,
-  hook_alloc_shared,
-  hook_ptr_shared,
-  hook_free_shared,
-  hook_file2shared,
-  hook_cmp_shared,
-  hook_print_params,
-  hook_sim_time,
-  hook_stop_sim,
-  hook_kick_dog,
-  hook_dog_timeout,
-  hook_rand,
-  hook_srand,
-  hook_rand_range,
-  hook_print_str,
-  hook_print_hex,
-  hook_cmp_offset_shared,
-  hook_fill_random_shared,
-  hook_alloc_random_data,
-  hook_calloc_random_data,
-  hook_print_int,
-  hook_print_uint,
-  hook_fputc,
-  hook_init_fd,
-  hook_sbrk,
-  hook_print_context_descr,
-  hook_print_data_descr,
-  hook_print_group_descr,
-  hook_fill_shared,
-  hook_sl_srand,
-  hook_sl_rand_irange,
-  hook_sl_rand_urange,
-  hook_sl_sh_malloc_aligned,
-  hook_sl_sh_calloc_aligned,
-  hook_sl_sh_alloc_random_data,
-  hook_sl_sh_file2mem,
-  hook_sl_vera_mbox_handle,
-  hook_sl_vera_mbox_put,
-  hook_sl_vera_mbox_get,
-  hook_sl_system,
-  hook_sl_sh_hexdump
-};
-
-#endif
diff --git a/arch/cris/arch-v32/mach-fs/Makefile b/arch/cris/arch-v32/mach-fs/Makefile
index 41fa6a6..d366e08 100644
--- a/arch/cris/arch-v32/mach-fs/Makefile
+++ b/arch/cris/arch-v32/mach-fs/Makefile
@@ -1,10 +1,8 @@
-# $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $
 #
 # Makefile for the linux kernel.
 #
 
 obj-y   := dma.o pinmux.o io.o arbiter.o
-obj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
 obj-$(CONFIG_CPU_FREQ)   += cpufreq.o
 
 clean:
diff --git a/arch/cris/arch-v32/mach-fs/vcs_hook.c b/arch/cris/arch-v32/mach-fs/vcs_hook.c
deleted file mode 100644
index b11594a..0000000
--- a/arch/cris/arch-v32/mach-fs/vcs_hook.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Call simulator hook. This is the part running in the
- * simulated program.
- */
-
-#include "vcs_hook.h"
-#include <stdarg.h>
-#include <arch-v32/hwregs/reg_map.h>
-#include <arch-v32/hwregs/intr_vect_defs.h>
-
-#define HOOK_TRIG_ADDR     0xb7000000	/* hook cvlog model reg address */
-#define HOOK_MEM_BASE_ADDR 0xa0000000	/* csp4 (shared mem) base addr */
-
-#define HOOK_DATA(offset) ((unsigned *)HOOK_MEM_BASE_ADDR)[offset]
-#define VHOOK_DATA(offset) ((volatile unsigned *)HOOK_MEM_BASE_ADDR)[offset]
-#define HOOK_TRIG(funcid) \
-	do { \
-		*((unsigned *) HOOK_TRIG_ADDR) = funcid; \
-	} while (0)
-#define HOOK_DATA_BYTE(offset) ((unsigned char *)HOOK_MEM_BASE_ADDR)[offset]
-
-int hook_call(unsigned id, unsigned pcnt, ...)
-{
-	va_list ap;
-	unsigned i;
-	unsigned ret;
-#ifdef USING_SOS
-	PREEMPT_OFF_SAVE();
-#endif
-
-	/* pass parameters */
-	HOOK_DATA(0) = id;
-
-	/* Have to make hook_print_str a special case since we call with a
-	 * parameter of byte type. Should perhaps be a separate
-	 * hook_call. */
-
-	if (id == hook_print_str) {
-		int i;
-		char *str;
-
-		HOOK_DATA(1) = pcnt;
-
-		va_start(ap, pcnt);
-		str = (char *)va_arg(ap, unsigned);
-
-		for (i = 0; i != pcnt; i++)
-			HOOK_DATA_BYTE(8 + i) = str[i];
-
-		HOOK_DATA_BYTE(8 + i) = 0;	/* null byte */
-	} else {
-		va_start(ap, pcnt);
-		for (i = 1; i <= pcnt; i++)
-			HOOK_DATA(i) = va_arg(ap, unsigned);
-		va_end(ap);
-	}
-
-	/* read from mem to make sure data has propagated to memory before
-	 * trigging */
-	ret = *((volatile unsigned *)HOOK_MEM_BASE_ADDR);
-
-	/* trigger hook */
-	HOOK_TRIG(id);
-
-	/* wait for call to finish */
-	while (VHOOK_DATA(0) > 0) ;
-
-	/* extract return value */
-
-	ret = VHOOK_DATA(1);
-
-#ifdef USING_SOS
-	PREEMPT_RESTORE();
-#endif
-	return ret;
-}
-
-unsigned hook_buf(unsigned i)
-{
-	return (HOOK_DATA(i));
-}
-
-void print_str(const char *str)
-{
-	int i;
-	/* find null at end of string */
-	for (i = 1; str[i]; i++) ;
-	hook_call(hook_print_str, i, str);
-}
-
-void CPU_KICK_DOG(void)
-{
-	(void)hook_call(hook_kick_dog, 0);
-}
-
-void CPU_WATCHDOG_TIMEOUT(unsigned t)
-{
-	(void)hook_call(hook_dog_timeout, 1, t);
-}
-
diff --git a/arch/cris/arch-v32/mach-fs/vcs_hook.h b/arch/cris/arch-v32/mach-fs/vcs_hook.h
deleted file mode 100644
index c000b9f..0000000
--- a/arch/cris/arch-v32/mach-fs/vcs_hook.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Call simulator hook functions
- */
-
-#ifndef HOOK_H
-#define HOOK_H
-
-int hook_call(unsigned id, unsigned pcnt, ...);
-
-enum hook_ids {
-  hook_debug_on = 1,
-  hook_debug_off,
-  hook_stop_sim_ok,
-  hook_stop_sim_fail,
-  hook_alloc_shared,
-  hook_ptr_shared,
-  hook_free_shared,
-  hook_file2shared,
-  hook_cmp_shared,
-  hook_print_params,
-  hook_sim_time,
-  hook_stop_sim,
-  hook_kick_dog,
-  hook_dog_timeout,
-  hook_rand,
-  hook_srand,
-  hook_rand_range,
-  hook_print_str,
-  hook_print_hex,
-  hook_cmp_offset_shared,
-  hook_fill_random_shared,
-  hook_alloc_random_data,
-  hook_calloc_random_data,
-  hook_print_int,
-  hook_print_uint,
-  hook_fputc,
-  hook_init_fd,
-  hook_sbrk
-
-};
-
-#endif
diff --git a/arch/cris/arch-v32/mm/init.c b/arch/cris/arch-v32/mm/init.c
index 0768bc4..3deca52 100644
--- a/arch/cris/arch-v32/mm/init.c
+++ b/arch/cris/arch-v32/mm/init.c
@@ -73,11 +73,7 @@ void __init cris_mmu_init(void)
 #endif
 		       REG_STATE(mmu, rw_mm_cfg, seg_c, linear) |
 		       REG_STATE(mmu, rw_mm_cfg, seg_b, linear) |
-#ifndef CONFIG_ETRAX_VCS_SIM
                        REG_STATE(mmu, rw_mm_cfg, seg_a, page)   |
-#else
-		       REG_STATE(mmu, rw_mm_cfg, seg_a, linear) |
-#endif
 		       REG_STATE(mmu, rw_mm_cfg, seg_9, page)   |
 		       REG_STATE(mmu, rw_mm_cfg, seg_8, page)   |
 		       REG_STATE(mmu, rw_mm_cfg, seg_7, page)   |
@@ -100,11 +96,7 @@ void __init cris_mmu_init(void)
 #endif
                          REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x4) |
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) |
-#ifndef CONFIG_ETRAX_VCS_SIM
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0x0) |
-#else
-                         REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa) |
-#endif
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_9, 0x0) |
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_8, 0x0));
 
diff --git a/arch/cris/include/arch-v32/arch/page.h b/arch/cris/include/arch-v32/arch/page.h
index 20f1b48..e5b5aab 100644
--- a/arch/cris/include/arch-v32/arch/page.h
+++ b/arch/cris/include/arch-v32/arch/page.h
@@ -11,13 +11,8 @@
  * selected bit it's possible to convert between KSEG_x and 0x40000000 where the
  * DRAM really resides. DRAM is virtually at 0xc.
  */
-#ifndef CONFIG_ETRAX_VCS_SIM
 #define __pa(x) ((unsigned long)(x) & 0x7fffffff)
 #define __va(x) ((void *)((unsigned long)(x) | 0x80000000))
-#else
-#define __pa(x) ((unsigned long)(x) & 0x3fffffff)
-#define __va(x) ((void *)((unsigned long)(x) | 0xc0000000))
-#endif
 
 #define VM_STACK_DEFAULT_FLAGS	(VM_READ | VM_WRITE | \
 				 VM_MAYREAD | VM_MAYWRITE)
diff --git a/arch/cris/include/arch-v32/arch/processor.h b/arch/cris/include/arch-v32/arch/processor.h
index 9603c90..a024b7d 100644
--- a/arch/cris/include/arch-v32/arch/processor.h
+++ b/arch/cris/include/arch-v32/arch/processor.h
@@ -21,13 +21,9 @@ struct thread_struct {
 
 /*
  * User-space process size. This is hardcoded into a few places, so don't
- * changed it unless everything's clear!
+ * change it unless everything's clear!
  */
-#ifndef CONFIG_ETRAX_VCS_SIM
 #define TASK_SIZE	(0xB0000000UL)
-#else
-#define TASK_SIZE	(0xA0000000UL)
-#endif
 
 /* CCS I=1, enable interrupts. */
 #define INIT_THREAD { 0, 0, (1 << I_CCS_BITNR) }
diff --git a/arch/cris/include/arch-v32/mach-fs/mach/startup.inc b/arch/cris/include/arch-v32/mach-fs/mach/startup.inc
index dd1abbd..96c3b0f 100644
--- a/arch/cris/include/arch-v32/mach-fs/mach/startup.inc
+++ b/arch/cris/include/arch-v32/mach-fs/mach/startup.inc
@@ -71,12 +71,6 @@
 	move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg), $r0
 	move.d   CONFIG_ETRAX_MEM_GRP4_CONFIG, $r1
 	move.d   $r1, [$r0]
-#ifdef CONFIG_ETRAX_VCS_SIM
-	;; Set up minimal flash waitstates
-	move.d 0, $r10
-	move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r11
-	move.d $r10, [$r11]
-#endif
 	.endm
 
 #endif
diff --git a/arch/cris/include/asm/pci.h b/arch/cris/include/asm/pci.h
index 9f1cd56..146da90 100644
--- a/arch/cris/include/asm/pci.h
+++ b/arch/cris/include/asm/pci.h
@@ -19,7 +19,6 @@ extern unsigned long pci_mem_start;
 
 void pcibios_config_init(void);
 struct pci_bus * pcibios_scan_root(int bus);
-int pcibios_assign_resources(void);
 
 void pcibios_set_master(struct pci_dev *dev);
 void pcibios_penalize_isa_irq(int irq);
diff --git a/arch/cris/include/asm/thread_info.h b/arch/cris/include/asm/thread_info.h
index 5b1c448..07c8c40 100644
--- a/arch/cris/include/asm/thread_info.h
+++ b/arch/cris/include/asm/thread_info.h
@@ -78,15 +78,12 @@ struct thread_info {
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal() */
-#define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17	/* is terminating due to OOM killer */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
diff --git a/arch/frv/include/asm/kmap_types.h b/arch/frv/include/asm/kmap_types.h
index f8e16b2..43901f2 100644
--- a/arch/frv/include/asm/kmap_types.h
+++ b/arch/frv/include/asm/kmap_types.h
@@ -2,28 +2,6 @@
 #ifndef _ASM_KMAP_TYPES_H
 #define _ASM_KMAP_TYPES_H
 
-enum km_type {
-	/* arch specific kmaps - change the numbers attached to these at your peril */
-	__KM_CACHE,		/* cache flush page attachment point */
-	__KM_PGD,		/* current page directory */
-	__KM_ITLB_PTD,		/* current instruction TLB miss page table lookup */
-	__KM_DTLB_PTD,		/* current data TLB miss page table lookup */
-
-	/* general kmaps */
-        KM_BOUNCE_READ,
-        KM_SKB_SUNRPC_DATA,
-        KM_SKB_DATA_SOFTIRQ,
-        KM_USER0,
-        KM_USER1,
-	KM_BIO_SRC_IRQ,
-	KM_BIO_DST_IRQ,
-	KM_PTE0,
-	KM_PTE1,
-	KM_IRQ0,
-	KM_IRQ1,
-	KM_SOFTIRQ0,
-	KM_SOFTIRQ1,
-	KM_TYPE_NR
-};
+#define KM_TYPE_NR 17
 
 #endif
diff --git a/arch/frv/include/asm/thread_info.h b/arch/frv/include/asm/thread_info.h
index 0ff03a3..bebd7ea 100644
--- a/arch/frv/include/asm/thread_info.h
+++ b/arch/frv/include/asm/thread_info.h
@@ -94,7 +94,6 @@ register struct thread_info *__current_thread_info asm("gr15");
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
 #define TIF_RESTORE_SIGMASK	5	/* restore signal mask in do_signal() */
-#define TIF_POLLING_NRFLAG	6	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		7	/* is terminating due to OOM killer */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
@@ -102,8 +101,6 @@ register struct thread_info *__current_thread_info asm("gr15");
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK		\
diff --git a/arch/frv/kernel/kernel_thread.S b/arch/frv/kernel/kernel_thread.S
index 4531c83..f0e5294 100644
--- a/arch/frv/kernel/kernel_thread.S
+++ b/arch/frv/kernel/kernel_thread.S
@@ -10,10 +10,10 @@
  */
 
 #include <linux/linkage.h>
+#include <linux/kern_levels.h>
 #include <asm/unistd.h>
 
 #define CLONE_VM	0x00000100	/* set if VM shared between processes */
-#define	KERN_ERR	"<3>"
 
 	.section .rodata
 kernel_thread_emsg:
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 864c2f0..535810a 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -20,7 +20,6 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
@@ -298,10 +297,6 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set)
 	__frame->lr   = (unsigned long) &frame->retcode;
 	__frame->gr8  = sig;
 
-	/* the tracer may want to single-step inside the handler */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 #if DEBUG_SIG
 	printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
 	       sig, current->comm, current->pid, frame, __frame->pc,
@@ -400,10 +395,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	__frame->gr8 = sig;
 	__frame->gr9 = (unsigned long) &frame->info;
 
-	/* the tracer may want to single-step inside the handler */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 #if DEBUG_SIG
 	printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
 	       sig, current->comm, current->pid, frame, __frame->pc,
diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c
index 6b0b82f..d04ed14 100644
--- a/arch/frv/mb93090-mb00/pci-vdk.c
+++ b/arch/frv/mb93090-mb00/pci-vdk.c
@@ -268,7 +268,7 @@ static void __init pci_fixup_umc_ide(struct pci_dev *d)
 		d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
 }
 
-static void __init pci_fixup_ide_bases(struct pci_dev *d)
+static void __devinit pci_fixup_ide_bases(struct pci_dev *d)
 {
 	int i;
 
@@ -287,7 +287,7 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d)
 	}
 }
 
-static void __init pci_fixup_ide_trash(struct pci_dev *d)
+static void __devinit pci_fixup_ide_trash(struct pci_dev *d)
 {
 	int i;
 
diff --git a/arch/h8300/include/asm/thread_info.h b/arch/h8300/include/asm/thread_info.h
index 9c126e0..ec2f777 100644
--- a/arch/h8300/include/asm/thread_info.h
+++ b/arch/h8300/include/asm/thread_info.h
@@ -85,8 +85,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 #define TIF_SIGPENDING		1	/* signal pending */
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
-#define TIF_POLLING_NRFLAG	3	/* true if poll_idle() is polling
-					   TIF_NEED_RESCHED */
 #define TIF_MEMDIE		4	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	5	/* restore signal mask in do_signal() */
 #define TIF_NOTIFY_RESUME	6	/* callback before returning to user */
@@ -95,11 +93,10 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 
-#define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
+#define _TIF_WORK_MASK		(_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+				 _TIF_NOTIFY_RESUME)
 
 #endif /* __KERNEL__ */
 
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
index fca1037..d6c8630 100644
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -38,7 +38,6 @@
 #include <linux/personality.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 
 #include <asm/setup.h>
diff --git a/arch/hexagon/include/asm/thread_info.h b/arch/hexagon/include/asm/thread_info.h
index 4f936a7..e4a0aad 100644
--- a/arch/hexagon/include/asm/thread_info.h
+++ b/arch/hexagon/include/asm/thread_info.h
@@ -120,10 +120,8 @@ register struct thread_info *__current_thread_info asm(QUOTED_THREADINFO_REG);
 #define TIF_SIGPENDING          2       /* signal pending */
 #define TIF_NEED_RESCHED        3       /* rescheduling necessary */
 #define TIF_SINGLESTEP          4       /* restore ss @ return to usr mode */
-#define TIF_IRET                5       /* return with iret */
 #define TIF_RESTORE_SIGMASK     6       /* restore sig mask in do_signal() */
 /* true if poll_idle() is polling TIF_NEED_RESCHED */
-#define TIF_POLLING_NRFLAG      16
 #define TIF_MEMDIE              17      /* OOM killer killed process */
 
 #define _TIF_SYSCALL_TRACE      (1 << TIF_SYSCALL_TRACE)
@@ -131,9 +129,6 @@ register struct thread_info *__current_thread_info asm(QUOTED_THREADINFO_REG);
 #define _TIF_SIGPENDING         (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED       (1 << TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP         (1 << TIF_SINGLESTEP)
-#define _TIF_IRET               (1 << TIF_IRET)
-#define _TIF_RESTORE_SIGMASK    (1 << TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG     (1 << TIF_POLLING_NRFLAG)
 
 /* work to do on interrupt/exception return - All but TIF_SYSCALL_TRACE */
 #define _TIF_WORK_MASK          (0x0000FFFF & ~_TIF_SYSCALL_TRACE)
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c
index 304b0808..1ea16be 100644
--- a/arch/hexagon/kernel/signal.c
+++ b/arch/hexagon/kernel/signal.c
@@ -20,7 +20,6 @@
 
 #include <linux/linkage.h>
 #include <linux/syscalls.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 #include <asm/registers.h>
 #include <asm/thread_info.h>
diff --git a/arch/hexagon/kernel/smp.c b/arch/hexagon/kernel/smp.c
index f726462..149fbef 100644
--- a/arch/hexagon/kernel/smp.c
+++ b/arch/hexagon/kernel/smp.c
@@ -180,9 +180,7 @@ void __cpuinit start_secondary(void)
 
 	notify_cpu_starting(cpu);
 
-	ipi_call_lock();
 	set_cpu_online(cpu, true);
-	ipi_call_unlock();
 
 	local_irq_enable();
 
diff --git a/arch/ia64/include/asm/iommu.h b/arch/ia64/include/asm/iommu.h
index b6a809f..105c93b 100644
--- a/arch/ia64/include/asm/iommu.h
+++ b/arch/ia64/include/asm/iommu.h
@@ -11,12 +11,10 @@ extern void no_iommu_init(void);
 extern int force_iommu, no_iommu;
 extern int iommu_pass_through;
 extern int iommu_detected;
-extern int iommu_group_mf;
 #else
 #define iommu_pass_through	(0)
 #define no_iommu		(1)
 #define iommu_detected		(0)
-#define iommu_group_mf		(0)
 #endif
 extern void iommu_dma_init(void);
 extern void machvec_init(const char *name);
diff --git a/arch/ia64/include/asm/thread_info.h b/arch/ia64/include/asm/thread_info.h
index f7ee853..ff2ae41 100644
--- a/arch/ia64/include/asm/thread_info.h
+++ b/arch/ia64/include/asm/thread_info.h
@@ -106,7 +106,6 @@ struct thread_info {
 #define TIF_SYSCALL_AUDIT	3	/* syscall auditing active */
 #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
 #define TIF_NOTIFY_RESUME	6	/* resumption notification requested */
-#define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17	/* is terminating due to OOM killer */
 #define TIF_MCA_INIT		18	/* this task is processing MCA or INIT */
 #define TIF_DB_DISABLED		19	/* debug trap disabled for fsyscall */
@@ -119,7 +118,6 @@ struct thread_info {
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_MCA_INIT		(1 << TIF_MCA_INIT)
 #define _TIF_DB_DISABLED	(1 << TIF_DB_DISABLED)
 #define _TIF_RESTORE_RSE	(1 << TIF_RESTORE_RSE)
diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c
index 7cdc89b..1ddcfe5 100644
--- a/arch/ia64/kernel/pci-dma.c
+++ b/arch/ia64/kernel/pci-dma.c
@@ -32,7 +32,6 @@ int force_iommu __read_mostly;
 #endif
 
 int iommu_pass_through;
-int iommu_group_mf;
 
 /* Dummy device used for NULL arguments (normally ISA). Better would
    be probably a smaller DMA mask, but this is bug-to-bug compatible
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index d7f558c..3fa4bc5 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2353,7 +2353,6 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t
 	 */
 	insert_vm_struct(mm, vma);
 
-	mm->total_vm  += size >> PAGE_SHIFT;
 	vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file,
 							vma_pages(vma));
 	up_write(&task->mm->mmap_sem);
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index a199be1..19f89c0 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -438,14 +438,6 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
 	long errno = scr->pt.r8;
 
 	/*
-	 * In the ia64_leave_kernel code path, we want the common case to go fast, which
-	 * is why we may in certain cases get here from kernel mode. Just return without
-	 * doing anything if so.
-	 */
-	if (!user_mode(&scr->pt))
-		return;
-
-	/*
 	 * This only loops in the rare cases of handle_signal() failing, in which case we
 	 * need to push through a forced SIGSEGV.
 	 */
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 1113b8a..963d2db 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -382,7 +382,6 @@ smp_callin (void)
 	set_numa_node(cpu_to_node_map[cpuid]);
 	set_numa_mem(local_memory_node(cpu_to_node_map[cpuid]));
 
-	ipi_call_lock_irq();
 	spin_lock(&vector_lock);
 	/* Setup the per cpu irq handling data structures */
 	__setup_vector_irq(cpuid);
@@ -390,7 +389,6 @@ smp_callin (void)
 	set_cpu_online(cpuid, true);
 	per_cpu(cpu_state, cpuid) = CPU_ONLINE;
 	spin_unlock(&vector_lock);
-	ipi_call_unlock_irq();
 
 	smp_setup_percpu_timer();
 
diff --git a/arch/ia64/kvm/Kconfig b/arch/ia64/kvm/Kconfig
index 9806e55..df5351e 100644
--- a/arch/ia64/kvm/Kconfig
+++ b/arch/ia64/kvm/Kconfig
@@ -19,6 +19,7 @@ if VIRTUALIZATION
 
 config KVM
 	tristate "Kernel-based Virtual Machine (KVM) support"
+	depends on BROKEN
 	depends on HAVE_KVM && MODULES && EXPERIMENTAL
 	# for device assignment:
 	depends on PCI
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index 02d29c2..8443daf 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -72,6 +72,10 @@ mapped_kernel_page_is_present (unsigned long address)
 	return pte_present(pte);
 }
 
+#	define VM_READ_BIT	0
+#	define VM_WRITE_BIT	1
+#	define VM_EXEC_BIT	2
+
 void __kprobes
 ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs)
 {
@@ -81,6 +85,12 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
 	struct siginfo si;
 	unsigned long mask;
 	int fault;
+	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
+
+	mask = ((((isr >> IA64_ISR_X_BIT) & 1UL) << VM_EXEC_BIT)
+		| (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT));
+
+	flags |= ((mask & VM_WRITE) ? FAULT_FLAG_WRITE : 0);
 
 	/* mmap_sem is performance critical.... */
 	prefetchw(&mm->mmap_sem);
@@ -109,6 +119,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
 	if (notify_page_fault(regs, TRAP_BRKPT))
 		return;
 
+retry:
 	down_read(&mm->mmap_sem);
 
 	vma = find_vma_prev(mm, address, &prev_vma);
@@ -130,10 +141,6 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
 
 	/* OK, we've got a good vm_area for this memory area.  Check the access permissions: */
 
-#	define VM_READ_BIT	0
-#	define VM_WRITE_BIT	1
-#	define VM_EXEC_BIT	2
-
 #	if (((1 << VM_READ_BIT) != VM_READ || (1 << VM_WRITE_BIT) != VM_WRITE) \
 	    || (1 << VM_EXEC_BIT) != VM_EXEC)
 #		error File is out of sync with <linux/mm.h>.  Please update.
@@ -142,9 +149,6 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
 	if (((isr >> IA64_ISR_R_BIT) & 1UL) && (!(vma->vm_flags & (VM_READ | VM_WRITE))))
 		goto bad_area;
 
-	mask = (  (((isr >> IA64_ISR_X_BIT) & 1UL) << VM_EXEC_BIT)
-		| (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT));
-
 	if ((vma->vm_flags & mask) != mask)
 		goto bad_area;
 
@@ -153,7 +157,11 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
 	 * sure we exit gracefully rather than endlessly redo the
 	 * fault.
 	 */
-	fault = handle_mm_fault(mm, vma, address, (mask & VM_WRITE) ? FAULT_FLAG_WRITE : 0);
+	fault = handle_mm_fault(mm, vma, address, flags);
+
+	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+		return;
+
 	if (unlikely(fault & VM_FAULT_ERROR)) {
 		/*
 		 * We ran out of memory, or some other thing happened
@@ -168,10 +176,24 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
 		}
 		BUG();
 	}
-	if (fault & VM_FAULT_MAJOR)
-		current->maj_flt++;
-	else
-		current->min_flt++;
+
+	if (flags & FAULT_FLAG_ALLOW_RETRY) {
+		if (fault & VM_FAULT_MAJOR)
+			current->maj_flt++;
+		else
+			current->min_flt++;
+		if (fault & VM_FAULT_RETRY) {
+			flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+			 /* No need to up_read(&mm->mmap_sem) as we would
+			 * have already released it in __lock_page_or_retry
+			 * in mm/filemap.c.
+			 */
+
+			goto retry;
+		}
+	}
+
 	up_read(&mm->mmap_sem);
 	return;
 
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 524df42..d173a88 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -351,6 +351,8 @@ pci_acpi_scan_root(struct acpi_pci_root *root)
 #endif
 
 	INIT_LIST_HEAD(&info.resources);
+	/* insert busn resource at first */
+	pci_add_resource(&info.resources, &root->secondary);
 	acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
 			&windows);
 	if (windows) {
@@ -384,7 +386,7 @@ pci_acpi_scan_root(struct acpi_pci_root *root)
 		return NULL;
 	}
 
-	pbus->subordinate = pci_scan_child_bus(pbus);
+	pci_scan_child_bus(pbus);
 	return pbus;
 
 out3:
diff --git a/arch/m32r/include/asm/smp.h b/arch/m32r/include/asm/smp.h
index cf7829a..c689b82 100644
--- a/arch/m32r/include/asm/smp.h
+++ b/arch/m32r/include/asm/smp.h
@@ -79,11 +79,6 @@ static __inline__ int cpu_number_map(int cpu)
 	return cpu;
 }
 
-static __inline__ unsigned int num_booting_cpus(void)
-{
-	return cpumask_weight(&cpu_callout_map);
-}
-
 extern void smp_send_timer(void);
 extern unsigned long send_IPI_mask_phys(const cpumask_t*, int, int);
 
diff --git a/arch/m32r/include/asm/thread_info.h b/arch/m32r/include/asm/thread_info.h
index c083f60..c074f4c 100644
--- a/arch/m32r/include/asm/thread_info.h
+++ b/arch/m32r/include/asm/thread_info.h
@@ -119,25 +119,20 @@ static inline unsigned int get_thread_fault_code(void)
 #define TIF_SIGPENDING		1	/* signal pending */
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
 #define TIF_SINGLESTEP		3	/* restore singlestep on return to user mode */
-#define TIF_IRET		4	/* return with iret */
 #define TIF_NOTIFY_RESUME	5	/* callback before returning to user */
 #define TIF_RESTORE_SIGMASK	8	/* restore signal mask in do_signal() */
 #define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
-#define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
-#define _TIF_IRET		(1<<TIF_IRET)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
-#define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
-#define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
+#define _TIF_WORK_MASK		(_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME)
+#define _TIF_ALLWORK_MASK	(_TIF_WORK_MASK | _TIF_SYSCALL_TRACE)
 
 /*
  * Thread-synchronous status.
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index f3fb2c0..397fe86 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -20,7 +20,6 @@
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 #include <asm/cacheflush.h>
 #include <asm/ucontext.h>
@@ -366,6 +365,4 @@ void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags)
 		clear_thread_flag(TIF_NOTIFY_RESUME);
 		tracehook_notify_resume(regs);
 	}
-
-	clear_thread_flag(TIF_IRET);
 }
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 1471201..87b504c 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -53,18 +53,6 @@ config ZONE_DMA
 	bool
 	default y
 
-config CPU_HAS_NO_BITFIELDS
-	bool
-
-config CPU_HAS_NO_MULDIV64
-	bool
-
-config CPU_HAS_ADDRESS_SPACES
-	bool
-
-config FPU
-	bool
-
 config HZ
 	int
 	default 1000 if CLEOPATRA
diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu
index 2b53254..8206834 100644
--- a/arch/m68k/Kconfig.cpu
+++ b/arch/m68k/Kconfig.cpu
@@ -23,7 +23,7 @@ config M68KCLASSIC
 config COLDFIRE
 	bool "Coldfire CPU family support"
 	select GENERIC_GPIO
-	select ARCH_REQUIRE_GPIOLIB
+	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARCH_HAVE_CUSTOM_GPIO_H
 	select CPU_HAS_NO_BITFIELDS
 	select CPU_HAS_NO_MULDIV64
@@ -37,6 +37,7 @@ config M68000
 	bool
 	select CPU_HAS_NO_BITFIELDS
 	select CPU_HAS_NO_MULDIV64
+	select CPU_HAS_NO_UNALIGNED
 	select GENERIC_CSUM
 	help
 	  The Freescale (was Motorola) 68000 CPU is the first generation of
@@ -48,6 +49,7 @@ config M68000
 config MCPU32
 	bool
 	select CPU_HAS_NO_BITFIELDS
+	select CPU_HAS_NO_UNALIGNED
 	help
 	  The Freescale (was then Motorola) CPU32 is a CPU core that is
 	  based on the 68020 processor. For the most part it is used in
@@ -167,6 +169,14 @@ config M5249
 	help
 	  Motorola ColdFire 5249 processor support.
 
+config M525x
+	bool "MCF525x"
+	depends on !MMU
+	select COLDFIRE_SW_A7
+	select HAVE_MBAR
+	help
+	  Freescale (Motorola) Coldfire 5251/5253 processor support.
+
 config M527x
 	bool
 
@@ -253,6 +263,14 @@ config M548x
 	help
 	  Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support.
 
+config M5441x
+	bool "MCF5441x"
+	depends on !MMU
+	select GENERIC_CLOCKEVENTS
+	select HAVE_CACHE_CB
+	help
+	  Freescale Coldfire 54410/54415/54416/54417/54418 processor support.
+
 endif # COLDFIRE
 
 
@@ -360,6 +378,18 @@ config NODES_SHIFT
 	default "3"
 	depends on !SINGLE_MEMORY_CHUNK
 
+config CPU_HAS_NO_BITFIELDS
+	bool
+
+config CPU_HAS_NO_MULDIV64
+	bool
+
+config CPU_HAS_NO_UNALIGNED
+	bool
+
+config CPU_HAS_ADDRESS_SPACES
+	bool
+
 config FPU
 	bool
 
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index b7f2e2d..7636751 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -41,6 +41,7 @@ cpuflags-$(CONFIG_M68030)	:=
 cpuflags-$(CONFIG_M68020)	:=
 cpuflags-$(CONFIG_M68360)	:= -m68332
 cpuflags-$(CONFIG_M68000)	:= -m68000
+cpuflags-$(CONFIG_M5441x)	:= $(call cc-option,-mcpu=54455,-mcfv4e)
 cpuflags-$(CONFIG_M54xx)	:= $(call cc-option,-mcpu=5475,-m5200)
 cpuflags-$(CONFIG_M5407)	:= $(call cc-option,-mcpu=5407,-m5200)
 cpuflags-$(CONFIG_M532x)	:= $(call cc-option,-mcpu=532x,-m5307)
@@ -50,6 +51,7 @@ cpuflags-$(CONFIG_M5275)	:= $(call cc-option,-mcpu=5275,-m5307)
 cpuflags-$(CONFIG_M5272)	:= $(call cc-option,-mcpu=5272,-m5307)
 cpuflags-$(CONFIG_M5271)	:= $(call cc-option,-mcpu=5271,-m5307)
 cpuflags-$(CONFIG_M523x)	:= $(call cc-option,-mcpu=523x,-m5307)
+cpuflags-$(CONFIG_M525x)	:= $(call cc-option,-mcpu=5253,-m5200)
 cpuflags-$(CONFIG_M5249)	:= $(call cc-option,-mcpu=5249,-m5200)
 cpuflags-$(CONFIG_M520x)	:= $(call cc-option,-mcpu=5208,-m5200)
 cpuflags-$(CONFIG_M5206e)	:= $(call cc-option,-mcpu=5206e,-m5200)
diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild
index eafa253..064f867 100644
--- a/arch/m68k/include/asm/Kbuild
+++ b/arch/m68k/include/asm/Kbuild
@@ -1,4 +1,28 @@
 include include/asm-generic/Kbuild.asm
 header-y += cachectl.h
 
+generic-y += bitsperlong.h
+generic-y += cputime.h
+generic-y += device.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += futex.h
+generic-y += ioctl.h
+generic-y += ipcbuf.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += kvm_para.h
+generic-y += local64.h
+generic-y += local.h
+generic-y += mman.h
+generic-y += mutex.h
+generic-y += percpu.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += siginfo.h
+generic-y += statfs.h
+generic-y += topology.h
+generic-y += types.h
 generic-y += word-at-a-time.h
+generic-y += xor.h
diff --git a/arch/m68k/include/asm/MC68332.h b/arch/m68k/include/asm/MC68332.h
deleted file mode 100644
index 6bb8f02..0000000
--- a/arch/m68k/include/asm/MC68332.h
+++ /dev/null
@@ -1,152 +0,0 @@
-
-/* include/asm-m68knommu/MC68332.h: '332 control registers
- *
- * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
- *
- */
-
-#ifndef _MC68332_H_
-#define _MC68332_H_
-
-#define BYTE_REF(addr) (*((volatile unsigned char*)addr))
-#define WORD_REF(addr) (*((volatile unsigned short*)addr))
-
-#define PORTE_ADDR	0xfffa11
-#define PORTE	BYTE_REF(PORTE_ADDR)
-#define DDRE_ADDR	0xfffa15
-#define DDRE	BYTE_REF(DDRE_ADDR)
-#define PEPAR_ADDR	0xfffa17
-#define PEPAR	BYTE_REF(PEPAR_ADDR)
-
-#define PORTF_ADDR	0xfffa19
-#define PORTF	BYTE_REF(PORTF_ADDR)
-#define DDRF_ADDR	0xfffa1d
-#define DDRF	BYTE_REF(DDRF_ADDR)
-#define PFPAR_ADDR	0xfffa1f
-#define PFPAR	BYTE_REF(PFPAR_ADDR)
-
-#define PORTQS_ADDR	0xfffc15
-#define PORTQS	BYTE_REF(PORTQS_ADDR)
-#define DDRQS_ADDR	0xfffc17
-#define DDRQS	BYTE_REF(DDRQS_ADDR)
-#define PQSPAR_ADDR	0xfffc16
-#define PQSPAR	BYTE_REF(PQSPAR_ADDR)
-
-#define CSPAR0_ADDR 0xFFFA44
-#define CSPAR0 WORD_REF(CSPAR0_ADDR)
-#define CSPAR1_ADDR 0xFFFA46
-#define CSPAR1 WORD_REF(CSPAR1_ADDR)
-#define CSARBT_ADDR 0xFFFA48
-#define CSARBT WORD_REF(CSARBT_ADDR)
-#define CSOPBT_ADDR 0xFFFA4A
-#define CSOPBT WORD_REF(CSOPBT_ADDR)
-#define CSBAR0_ADDR 0xFFFA4C
-#define CSBAR0 WORD_REF(CSBAR0_ADDR)
-#define CSOR0_ADDR 0xFFFA4E
-#define CSOR0 WORD_REF(CSOR0_ADDR)
-#define CSBAR1_ADDR 0xFFFA50
-#define CSBAR1 WORD_REF(CSBAR1_ADDR)
-#define CSOR1_ADDR 0xFFFA52
-#define CSOR1 WORD_REF(CSOR1_ADDR)
-#define CSBAR2_ADDR 0xFFFA54
-#define CSBAR2 WORD_REF(CSBAR2_ADDR)
-#define CSOR2_ADDR 0xFFFA56
-#define CSOR2 WORD_REF(CSOR2_ADDR)
-#define CSBAR3_ADDR 0xFFFA58
-#define CSBAR3 WORD_REF(CSBAR3_ADDR)
-#define CSOR3_ADDR 0xFFFA5A
-#define CSOR3 WORD_REF(CSOR3_ADDR)
-#define CSBAR4_ADDR 0xFFFA5C
-#define CSBAR4 WORD_REF(CSBAR4_ADDR)
-#define CSOR4_ADDR 0xFFFA5E
-#define CSOR4 WORD_REF(CSOR4_ADDR)
-#define CSBAR5_ADDR 0xFFFA60
-#define CSBAR5 WORD_REF(CSBAR5_ADDR)
-#define CSOR5_ADDR 0xFFFA62
-#define CSOR5 WORD_REF(CSOR5_ADDR)
-#define CSBAR6_ADDR 0xFFFA64
-#define CSBAR6 WORD_REF(CSBAR6_ADDR)
-#define CSOR6_ADDR 0xFFFA66
-#define CSOR6 WORD_REF(CSOR6_ADDR)
-#define CSBAR7_ADDR 0xFFFA68
-#define CSBAR7 WORD_REF(CSBAR7_ADDR)
-#define CSOR7_ADDR 0xFFFA6A
-#define CSOR7 WORD_REF(CSOR7_ADDR)
-#define CSBAR8_ADDR 0xFFFA6C
-#define CSBAR8 WORD_REF(CSBAR8_ADDR)
-#define CSOR8_ADDR 0xFFFA6E
-#define CSOR8 WORD_REF(CSOR8_ADDR)
-#define CSBAR9_ADDR 0xFFFA70
-#define CSBAR9 WORD_REF(CSBAR9_ADDR)
-#define CSOR9_ADDR 0xFFFA72
-#define CSOR9 WORD_REF(CSOR9_ADDR)
-#define CSBAR10_ADDR 0xFFFA74
-#define CSBAR10 WORD_REF(CSBAR10_ADDR)
-#define CSOR10_ADDR 0xFFFA76
-#define CSOR10 WORD_REF(CSOR10_ADDR)
-
-#define CSOR_MODE_ASYNC	0x0000
-#define CSOR_MODE_SYNC	0x8000
-#define CSOR_MODE_MASK	0x8000
-#define CSOR_BYTE_DISABLE	0x0000
-#define CSOR_BYTE_UPPER		0x4000
-#define CSOR_BYTE_LOWER		0x2000
-#define CSOR_BYTE_BOTH		0x6000
-#define CSOR_BYTE_MASK		0x6000
-#define CSOR_RW_RSVD		0x0000
-#define CSOR_RW_READ		0x0800
-#define CSOR_RW_WRITE		0x1000
-#define CSOR_RW_BOTH		0x1800
-#define CSOR_RW_MASK		0x1800
-#define CSOR_STROBE_DS		0x0400
-#define CSOR_STROBE_AS		0x0000
-#define CSOR_STROBE_MASK	0x0400
-#define CSOR_DSACK_WAIT(x)	(wait << 6)
-#define CSOR_DSACK_FTERM	(14 << 6)
-#define CSOR_DSACK_EXTERNAL	(15 << 6)
-#define CSOR_DSACK_MASK		0x03c0
-#define CSOR_SPACE_CPU		0x0000
-#define CSOR_SPACE_USER		0x0010
-#define CSOR_SPACE_SU		0x0020
-#define CSOR_SPACE_BOTH		0x0030
-#define CSOR_SPACE_MASK		0x0030
-#define CSOR_IPL_ALL		0x0000
-#define CSOR_IPL_PRIORITY(x)	(x << 1)
-#define CSOR_IPL_MASK		0x000e
-#define CSOR_AVEC_ON		0x0001
-#define CSOR_AVEC_OFF		0x0000
-#define CSOR_AVEC_MASK		0x0001
-
-#define CSBAR_ADDR(x)		((addr >> 11) << 3) 
-#define CSBAR_ADDR_MASK		0xfff8
-#define CSBAR_BLKSIZE_2K	0x0000
-#define CSBAR_BLKSIZE_8K	0x0001
-#define CSBAR_BLKSIZE_16K	0x0002
-#define CSBAR_BLKSIZE_64K	0x0003
-#define CSBAR_BLKSIZE_128K	0x0004
-#define CSBAR_BLKSIZE_256K	0x0005
-#define CSBAR_BLKSIZE_512K	0x0006
-#define CSBAR_BLKSIZE_1M	0x0007
-#define CSBAR_BLKSIZE_MASK	0x0007
-
-#define CSPAR_DISC	0
-#define CSPAR_ALT	1
-#define CSPAR_CS8	2
-#define CSPAR_CS16	3
-#define CSPAR_MASK	3
-
-#define CSPAR0_CSBOOT(x) (x << 0)
-#define CSPAR0_CS0(x)	(x << 2)
-#define CSPAR0_CS1(x)	(x << 4)
-#define CSPAR0_CS2(x)	(x << 6)
-#define CSPAR0_CS3(x)	(x << 8)
-#define CSPAR0_CS4(x)	(x << 10)
-#define CSPAR0_CS5(x)	(x << 12)
-
-#define CSPAR1_CS6(x)	(x << 0)
-#define CSPAR1_CS7(x)	(x << 2)
-#define CSPAR1_CS8(x)	(x << 4)
-#define CSPAR1_CS9(x)	(x << 6)
-#define CSPAR1_CS10(x)	(x << 8)
-
-#endif
diff --git a/arch/m68k/include/asm/apollodma.h b/arch/m68k/include/asm/apollodma.h
deleted file mode 100644
index 954adc8..0000000
--- a/arch/m68k/include/asm/apollodma.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * linux/include/asm/dma.h: Defines for using and allocating dma channels.
- * Written by Hennus Bergman, 1992.
- * High DMA channel support & info by Hannu Savolainen
- * and John Boyd, Nov. 1992.
- */
-
-#ifndef _ASM_APOLLO_DMA_H
-#define _ASM_APOLLO_DMA_H
-
-#include <asm/apollohw.h>		/* need byte IO */
-#include <linux/spinlock.h>		/* And spinlocks */
-#include <linux/delay.h>
-
-
-#define dma_outb(val,addr) (*((volatile unsigned char *)(addr+IO_BASE)) = (val))
-#define dma_inb(addr)	   (*((volatile unsigned char *)(addr+IO_BASE)))
-
-/*
- * NOTES about DMA transfers:
- *
- *  controller 1: channels 0-3, byte operations, ports 00-1F
- *  controller 2: channels 4-7, word operations, ports C0-DF
- *
- *  - ALL registers are 8 bits only, regardless of transfer size
- *  - channel 4 is not used - cascades 1 into 2.
- *  - channels 0-3 are byte - addresses/counts are for physical bytes
- *  - channels 5-7 are word - addresses/counts are for physical words
- *  - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries
- *  - transfer count loaded to registers is 1 less than actual count
- *  - controller 2 offsets are all even (2x offsets for controller 1)
- *  - page registers for 5-7 don't use data bit 0, represent 128K pages
- *  - page registers for 0-3 use bit 0, represent 64K pages
- *
- * DMA transfers are limited to the lower 16MB of _physical_ memory.
- * Note that addresses loaded into registers must be _physical_ addresses,
- * not logical addresses (which may differ if paging is active).
- *
- *  Address mapping for channels 0-3:
- *
- *   A23 ... A16 A15 ... A8  A7 ... A0    (Physical addresses)
- *    |  ...  |   |  ... |   |  ... |
- *    |  ...  |   |  ... |   |  ... |
- *    |  ...  |   |  ... |   |  ... |
- *   P7  ...  P0  A7 ... A0  A7 ... A0
- * |    Page    | Addr MSB | Addr LSB |   (DMA registers)
- *
- *  Address mapping for channels 5-7:
- *
- *   A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0    (Physical addresses)
- *    |  ...  |   \   \   ... \  \  \  ... \  \
- *    |  ...  |    \   \   ... \  \  \  ... \  (not used)
- *    |  ...  |     \   \   ... \  \  \  ... \
- *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0
- * |      Page      |  Addr MSB   |  Addr LSB  |   (DMA registers)
- *
- * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
- * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at
- * the hardware level, so odd-byte transfers aren't possible).
- *
- * Transfer count (_not # bytes_) is limited to 64K, represented as actual
- * count - 1 : 64K => 0xFFFF, 1 => 0x0000.  Thus, count is always 1 or more,
- * and up to 128K bytes may be transferred on channels 5-7 in one operation.
- *
- */
-
-#define MAX_DMA_CHANNELS	8
-
-/* The maximum address that we can perform a DMA transfer to on this platform */#define MAX_DMA_ADDRESS      (PAGE_OFFSET+0x1000000)
-
-/* 8237 DMA controllers */
-#define IO_DMA1_BASE	0x10C00	/* 8 bit slave DMA, channels 0..3 */
-#define IO_DMA2_BASE	0x10D00	/* 16 bit master DMA, ch 4(=slave input)..7 */
-
-/* DMA controller registers */
-#define DMA1_CMD_REG		(IO_DMA1_BASE+0x08) /* command register (w) */
-#define DMA1_STAT_REG		(IO_DMA1_BASE+0x08) /* status register (r) */
-#define DMA1_REQ_REG            (IO_DMA1_BASE+0x09) /* request register (w) */
-#define DMA1_MASK_REG		(IO_DMA1_BASE+0x0A) /* single-channel mask (w) */
-#define DMA1_MODE_REG		(IO_DMA1_BASE+0x0B) /* mode register (w) */
-#define DMA1_CLEAR_FF_REG	(IO_DMA1_BASE+0x0C) /* clear pointer flip-flop (w) */
-#define DMA1_TEMP_REG           (IO_DMA1_BASE+0x0D) /* Temporary Register (r) */
-#define DMA1_RESET_REG		(IO_DMA1_BASE+0x0D) /* Master Clear (w) */
-#define DMA1_CLR_MASK_REG       (IO_DMA1_BASE+0x0E) /* Clear Mask */
-#define DMA1_MASK_ALL_REG       (IO_DMA1_BASE+0x0F) /* all-channels mask (w) */
-
-#define DMA2_CMD_REG		(IO_DMA2_BASE+0x10) /* command register (w) */
-#define DMA2_STAT_REG		(IO_DMA2_BASE+0x10) /* status register (r) */
-#define DMA2_REQ_REG            (IO_DMA2_BASE+0x12) /* request register (w) */
-#define DMA2_MASK_REG		(IO_DMA2_BASE+0x14) /* single-channel mask (w) */
-#define DMA2_MODE_REG		(IO_DMA2_BASE+0x16) /* mode register (w) */
-#define DMA2_CLEAR_FF_REG	(IO_DMA2_BASE+0x18) /* clear pointer flip-flop (w) */
-#define DMA2_TEMP_REG           (IO_DMA2_BASE+0x1A) /* Temporary Register (r) */
-#define DMA2_RESET_REG		(IO_DMA2_BASE+0x1A) /* Master Clear (w) */
-#define DMA2_CLR_MASK_REG       (IO_DMA2_BASE+0x1C) /* Clear Mask */
-#define DMA2_MASK_ALL_REG       (IO_DMA2_BASE+0x1E) /* all-channels mask (w) */
-
-#define DMA_ADDR_0              (IO_DMA1_BASE+0x00) /* DMA address registers */
-#define DMA_ADDR_1              (IO_DMA1_BASE+0x02)
-#define DMA_ADDR_2              (IO_DMA1_BASE+0x04)
-#define DMA_ADDR_3              (IO_DMA1_BASE+0x06)
-#define DMA_ADDR_4              (IO_DMA2_BASE+0x00)
-#define DMA_ADDR_5              (IO_DMA2_BASE+0x04)
-#define DMA_ADDR_6              (IO_DMA2_BASE+0x08)
-#define DMA_ADDR_7              (IO_DMA2_BASE+0x0C)
-
-#define DMA_CNT_0               (IO_DMA1_BASE+0x01)   /* DMA count registers */
-#define DMA_CNT_1               (IO_DMA1_BASE+0x03)
-#define DMA_CNT_2               (IO_DMA1_BASE+0x05)
-#define DMA_CNT_3               (IO_DMA1_BASE+0x07)
-#define DMA_CNT_4               (IO_DMA2_BASE+0x02)
-#define DMA_CNT_5               (IO_DMA2_BASE+0x06)
-#define DMA_CNT_6               (IO_DMA2_BASE+0x0A)
-#define DMA_CNT_7               (IO_DMA2_BASE+0x0E)
-
-#define DMA_MODE_READ	0x44	/* I/O to memory, no autoinit, increment, single mode */
-#define DMA_MODE_WRITE	0x48	/* memory to I/O, no autoinit, increment, single mode */
-#define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
-
-#define DMA_AUTOINIT	0x10
-
-#define DMA_8BIT 0
-#define DMA_16BIT 1
-#define DMA_BUSMASTER 2
-
-extern spinlock_t  dma_spin_lock;
-
-static __inline__ unsigned long claim_dma_lock(void)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&dma_spin_lock, flags);
-	return flags;
-}
-
-static __inline__ void release_dma_lock(unsigned long flags)
-{
-	spin_unlock_irqrestore(&dma_spin_lock, flags);
-}
-
-/* enable/disable a specific DMA channel */
-static __inline__ void enable_dma(unsigned int dmanr)
-{
-	if (dmanr<=3)
-		dma_outb(dmanr,  DMA1_MASK_REG);
-	else
-		dma_outb(dmanr & 3,  DMA2_MASK_REG);
-}
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-	if (dmanr<=3)
-		dma_outb(dmanr | 4,  DMA1_MASK_REG);
-	else
-		dma_outb((dmanr & 3) | 4,  DMA2_MASK_REG);
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while holding the DMA lock ! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-	if (dmanr<=3)
-		dma_outb(0,  DMA1_CLEAR_FF_REG);
-	else
-		dma_outb(0,  DMA2_CLEAR_FF_REG);
-}
-
-/* set mode (above) for a specific DMA channel */
-static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
-{
-	if (dmanr<=3)
-		dma_outb(mode | dmanr,  DMA1_MODE_REG);
-	else
-		dma_outb(mode | (dmanr&3),  DMA2_MODE_REG);
-}
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
-{
-	if (dmanr <= 3)  {
-	    dma_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
-            dma_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
-	}  else  {
-	    dma_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
-	    dma_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
-	}
-}
-
-
-/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
- * a specific DMA channel.
- * You must ensure the parameters are valid.
- * NOTE: from a manual: "the number of transfers is one more
- * than the initial word count"! This is taken into account.
- * Assumes dma flip-flop is clear.
- * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
- */
-static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
-{
-        count--;
-	if (dmanr <= 3)  {
-	    dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
-	    dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
-        } else {
-	    dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
-	    dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
-        }
-}
-
-
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-static __inline__ int get_dma_residue(unsigned int dmanr)
-{
-	unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
-					 : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
-
-	/* using short to get 16-bit wrap around */
-	unsigned short count;
-
-	count = 1 + dma_inb(io_port);
-	count += dma_inb(io_port) << 8;
-
-	return (dmanr<=3)? count : (count<<1);
-}
-
-
-/* These are in kernel/dma.c: */
-extern int request_dma(unsigned int dmanr, const char * device_id);	/* reserve a DMA channel */
-extern void free_dma(unsigned int dmanr);	/* release it again */
-
-/* These are in arch/m68k/apollo/dma.c: */
-extern unsigned short dma_map_page(unsigned long phys_addr,int count,int type);
-extern void dma_unmap_page(unsigned short dma_addr);
-
-#endif /* _ASM_APOLLO_DMA_H */
diff --git a/arch/m68k/include/asm/bitsperlong.h b/arch/m68k/include/asm/bitsperlong.h
deleted file mode 100644
index 6dc0bb0..0000000
--- a/arch/m68k/include/asm/bitsperlong.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/bitsperlong.h>
diff --git a/arch/m68k/include/asm/cputime.h b/arch/m68k/include/asm/cputime.h
deleted file mode 100644
index c79c5e8..0000000
--- a/arch/m68k/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __M68K_CPUTIME_H
-#define __M68K_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __M68K_CPUTIME_H */
diff --git a/arch/m68k/include/asm/delay.h b/arch/m68k/include/asm/delay.h
index 9c09bec..12d8fe4 100644
--- a/arch/m68k/include/asm/delay.h
+++ b/arch/m68k/include/asm/delay.h
@@ -43,7 +43,7 @@ static inline void __delay(unsigned long loops)
 extern void __bad_udelay(void);
 
 
-#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
+#ifdef CONFIG_CPU_HAS_NO_MULDIV64
 /*
  * The simpler m68k and ColdFire processors do not have a 32*32->64
  * multiply instruction. So we need to handle them a little differently.
diff --git a/arch/m68k/include/asm/device.h b/arch/m68k/include/asm/device.h
deleted file mode 100644
index d8f9872..0000000
--- a/arch/m68k/include/asm/device.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Arch specific extensions to struct device
- *
- * This file is released under the GPLv2
- */
-#include <asm-generic/device.h>
-
diff --git a/arch/m68k/include/asm/dma.h b/arch/m68k/include/asm/dma.h
index 6fbdfe8..9470641 100644
--- a/arch/m68k/include/asm/dma.h
+++ b/arch/m68k/include/asm/dma.h
@@ -33,7 +33,9 @@
  * Set number of channels of DMA on ColdFire for different implementations.
  */
 #if defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) || \
-	defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
+	defined(CONFIG_M523x) || defined(CONFIG_M527x) || \
+	defined(CONFIG_M528x) || defined(CONFIG_M525x)
+
 #define MAX_M68K_DMA_CHANNELS 4
 #elif defined(CONFIG_M5272)
 #define MAX_M68K_DMA_CHANNELS 1
diff --git a/arch/m68k/include/asm/emergency-restart.h b/arch/m68k/include/asm/emergency-restart.h
deleted file mode 100644
index 108d8c4..0000000
--- a/arch/m68k/include/asm/emergency-restart.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_EMERGENCY_RESTART_H
-#define _ASM_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* _ASM_EMERGENCY_RESTART_H */
diff --git a/arch/m68k/include/asm/errno.h b/arch/m68k/include/asm/errno.h
deleted file mode 100644
index 0d4e188..0000000
--- a/arch/m68k/include/asm/errno.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_ERRNO_H
-#define _M68K_ERRNO_H
-
-#include <asm-generic/errno.h>
-
-#endif /* _M68K_ERRNO_H */
diff --git a/arch/m68k/include/asm/futex.h b/arch/m68k/include/asm/futex.h
deleted file mode 100644
index 6a332a9..0000000
--- a/arch/m68k/include/asm/futex.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_FUTEX_H
-#define _ASM_FUTEX_H
-
-#include <asm-generic/futex.h>
-
-#endif
diff --git a/arch/m68k/include/asm/gpio.h b/arch/m68k/include/asm/gpio.h
index 00d0071..4395ffc 100644
--- a/arch/m68k/include/asm/gpio.h
+++ b/arch/m68k/include/asm/gpio.h
@@ -17,170 +17,9 @@
 #define coldfire_gpio_h
 
 #include <linux/io.h>
-#include <asm-generic/gpio.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-
-/*
- * The Freescale Coldfire family is quite varied in how they implement GPIO.
- * Some parts have 8 bit ports, some have 16bit and some have 32bit; some have
- * only one port, others have multiple ports; some have a single data latch
- * for both input and output, others have a separate pin data register to read
- * input; some require a read-modify-write access to change an output, others
- * have set and clear registers for some of the outputs; Some have all the
- * GPIOs in a single control area, others have some GPIOs implemented in
- * different modules.
- *
- * This implementation attempts accommodate the differences while presenting
- * a generic interface that will optimize to as few instructions as possible.
- */
-#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
-    defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
-    defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
-    defined(CONFIG_M532x) || defined(CONFIG_M54xx)
-
-/* These parts have GPIO organized by 8 bit ports */
-
-#define MCFGPIO_PORTTYPE		u8
-#define MCFGPIO_PORTSIZE		8
-#define mcfgpio_read(port)		__raw_readb(port)
-#define mcfgpio_write(data, port)	__raw_writeb(data, port)
-
-#elif defined(CONFIG_M5307) || defined(CONFIG_M5407) || defined(CONFIG_M5272)
-
-/* These parts have GPIO organized by 16 bit ports */
-
-#define MCFGPIO_PORTTYPE		u16
-#define MCFGPIO_PORTSIZE		16
-#define mcfgpio_read(port)		__raw_readw(port)
-#define mcfgpio_write(data, port)	__raw_writew(data, port)
-
-#elif defined(CONFIG_M5249)
-
-/* These parts have GPIO organized by 32 bit ports */
-
-#define MCFGPIO_PORTTYPE		u32
-#define MCFGPIO_PORTSIZE		32
-#define mcfgpio_read(port)		__raw_readl(port)
-#define mcfgpio_write(data, port)	__raw_writel(data, port)
-
-#endif
-
-#define mcfgpio_bit(gpio)		(1 << ((gpio) %  MCFGPIO_PORTSIZE))
-#define mcfgpio_port(gpio)		((gpio) / MCFGPIO_PORTSIZE)
-
-#if defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
-    defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
-/*
- * These parts have an 'Edge' Port module (external interrupt/GPIO) which uses
- * read-modify-write to change an output and a GPIO module which has separate
- * set/clr registers to directly change outputs with a single write access.
- */
-#if defined(CONFIG_M528x)
-/*
- * The 528x also has GPIOs in other modules (GPT, QADC) which use
- * read-modify-write as well as those controlled by the EPORT and GPIO modules.
- */
-#define MCFGPIO_SCR_START		40
-#else
-#define MCFGPIO_SCR_START		8
-#endif
-
-#define MCFGPIO_SETR_PORT(gpio)		(MCFGPIO_SETR + \
-					mcfgpio_port(gpio - MCFGPIO_SCR_START))
-
-#define MCFGPIO_CLRR_PORT(gpio)		(MCFGPIO_CLRR + \
-					mcfgpio_port(gpio - MCFGPIO_SCR_START))
-#else
-
-#define MCFGPIO_SCR_START		MCFGPIO_PIN_MAX
-/* with MCFGPIO_SCR == MCFGPIO_PIN_MAX, these will be optimized away */
-#define MCFGPIO_SETR_PORT(gpio)		0
-#define MCFGPIO_CLRR_PORT(gpio)		0
-
-#endif
-/*
- * Coldfire specific helper functions
- */
-
-/* return the port pin data register for a gpio */
-static inline u32 __mcf_gpio_ppdr(unsigned gpio)
-{
-#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
-    defined(CONFIG_M5307) || defined(CONFIG_M5407)
-	return MCFSIM_PADAT;
-#elif defined(CONFIG_M5272)
-	if (gpio < 16)
-		return MCFSIM_PADAT;
-	else if (gpio < 32)
-		return MCFSIM_PBDAT;
-	else
-		return MCFSIM_PCDAT;
-#elif defined(CONFIG_M5249)
-	if (gpio < 32)
-		return MCFSIM2_GPIOREAD;
-	else
-		return MCFSIM2_GPIO1READ;
-#elif defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
-      defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
-	if (gpio < 8)
-		return MCFEPORT_EPPDR;
-#if defined(CONFIG_M528x)
-	else if (gpio < 16)
-		return MCFGPTA_GPTPORT;
-	else if (gpio < 24)
-		return MCFGPTB_GPTPORT;
-	else if (gpio < 32)
-		return MCFQADC_PORTQA;
-	else if (gpio < 40)
-		return MCFQADC_PORTQB;
-#endif
-	else
-		return MCFGPIO_PPDR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
-#else
-	return 0;
-#endif
-}
-
-/* return the port output data register for a gpio */
-static inline u32 __mcf_gpio_podr(unsigned gpio)
-{
-#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
-    defined(CONFIG_M5307) || defined(CONFIG_M5407)
-	return MCFSIM_PADAT;
-#elif defined(CONFIG_M5272)
-	if (gpio < 16)
-		return MCFSIM_PADAT;
-	else if (gpio < 32)
-		return MCFSIM_PBDAT;
-	else
-		return MCFSIM_PCDAT;
-#elif defined(CONFIG_M5249)
-	if (gpio < 32)
-		return MCFSIM2_GPIOWRITE;
-	else
-		return MCFSIM2_GPIO1WRITE;
-#elif defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
-      defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
-	if (gpio < 8)
-		return MCFEPORT_EPDR;
-#if defined(CONFIG_M528x)
-	else if (gpio < 16)
-		return MCFGPTA_GPTPORT;
-	else if (gpio < 24)
-		return MCFGPTB_GPTPORT;
-	else if (gpio < 32)
-		return MCFQADC_PORTQA;
-	else if (gpio < 40)
-		return MCFQADC_PORTQB;
-#endif
-	else
-		return MCFGPIO_PODR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
-#else
-	return 0;
-#endif
-}
-
+#include <asm/mcfgpio.h>
 /*
  * The Generic GPIO functions
  *
@@ -191,7 +30,7 @@ static inline u32 __mcf_gpio_podr(unsigned gpio)
 static inline int gpio_get_value(unsigned gpio)
 {
 	if (__builtin_constant_p(gpio) && gpio < MCFGPIO_PIN_MAX)
-		return mcfgpio_read(__mcf_gpio_ppdr(gpio)) & mcfgpio_bit(gpio);
+		return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio);
 	else
 		return __gpio_get_value(gpio);
 }
@@ -204,12 +43,12 @@ static inline void gpio_set_value(unsigned gpio, int value)
 			MCFGPIO_PORTTYPE data;
 
 			local_irq_save(flags);
-			data = mcfgpio_read(__mcf_gpio_podr(gpio));
+			data = mcfgpio_read(__mcfgpio_podr(gpio));
 			if (value)
 				data |= mcfgpio_bit(gpio);
 			else
 				data &= ~mcfgpio_bit(gpio);
-			mcfgpio_write(data, __mcf_gpio_podr(gpio));
+			mcfgpio_write(data, __mcfgpio_podr(gpio));
 			local_irq_restore(flags);
 		} else {
 			if (value)
@@ -225,8 +64,14 @@ static inline void gpio_set_value(unsigned gpio, int value)
 
 static inline int gpio_to_irq(unsigned gpio)
 {
-	return (gpio < MCFGPIO_IRQ_MAX) ? gpio + MCFGPIO_IRQ_VECBASE
-		: __gpio_to_irq(gpio);
+#if defined(MCFGPIO_IRQ_MIN)
+	if ((gpio >= MCFGPIO_IRQ_MIN) && (gpio < MCFGPIO_IRQ_MAX))
+#else
+	if (gpio < MCFGPIO_IRQ_MAX)
+#endif
+		return gpio + MCFGPIO_IRQ_VECBASE;
+	else
+		return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned irq)
diff --git a/arch/m68k/include/asm/ioctl.h b/arch/m68k/include/asm/ioctl.h
deleted file mode 100644
index b279fe0..0000000
--- a/arch/m68k/include/asm/ioctl.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ioctl.h>
diff --git a/arch/m68k/include/asm/ipcbuf.h b/arch/m68k/include/asm/ipcbuf.h
deleted file mode 100644
index 84c7e51..0000000
--- a/arch/m68k/include/asm/ipcbuf.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ipcbuf.h>
diff --git a/arch/m68k/include/asm/irq_regs.h b/arch/m68k/include/asm/irq_regs.h
deleted file mode 100644
index 3dd9c0b..0000000
--- a/arch/m68k/include/asm/irq_regs.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/irq_regs.h>
diff --git a/arch/m68k/include/asm/kdebug.h b/arch/m68k/include/asm/kdebug.h
deleted file mode 100644
index 6ece1b0..0000000
--- a/arch/m68k/include/asm/kdebug.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kdebug.h>
diff --git a/arch/m68k/include/asm/kmap_types.h b/arch/m68k/include/asm/kmap_types.h
deleted file mode 100644
index 3413cc1..0000000
--- a/arch/m68k/include/asm/kmap_types.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_M68K_KMAP_TYPES_H
-#define __ASM_M68K_KMAP_TYPES_H
-
-#include <asm-generic/kmap_types.h>
-
-#endif	/* __ASM_M68K_KMAP_TYPES_H */
diff --git a/arch/m68k/include/asm/kvm_para.h b/arch/m68k/include/asm/kvm_para.h
deleted file mode 100644
index 14fab8f..0000000
--- a/arch/m68k/include/asm/kvm_para.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kvm_para.h>
diff --git a/arch/m68k/include/asm/local.h b/arch/m68k/include/asm/local.h
deleted file mode 100644
index 6c25926..0000000
--- a/arch/m68k/include/asm/local.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_M68K_LOCAL_H
-#define _ASM_M68K_LOCAL_H
-
-#include <asm-generic/local.h>
-
-#endif /* _ASM_M68K_LOCAL_H */
diff --git a/arch/m68k/include/asm/local64.h b/arch/m68k/include/asm/local64.h
deleted file mode 100644
index 36c93b5..0000000
--- a/arch/m68k/include/asm/local64.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/local64.h>
diff --git a/arch/m68k/include/asm/m520xsim.h b/arch/m68k/include/asm/m520xsim.h
index 17f2aab..db3f8ee 100644
--- a/arch/m68k/include/asm/m520xsim.h
+++ b/arch/m68k/include/asm/m520xsim.h
@@ -42,6 +42,9 @@
 #define MCFINTC1_SIMR       (0)
 #define MCFINTC1_CIMR       (0)
 #define	MCFINTC1_ICR0       (0)
+#define MCFINTC2_SIMR       (0)
+#define MCFINTC2_CIMR       (0)
+#define MCFINTC2_ICR0       (0)
 
 #define MCFINT_VECBASE      64
 #define MCFINT_UART0        26          /* Interrupt number for UART0 */
@@ -62,6 +65,7 @@
 #define MCF_IRQ_FECENTC0    (MCFINT_VECBASE + MCFINT_FECENTC0)
 
 #define	MCF_IRQ_QSPI	    (MCFINT_VECBASE + MCFINT_QSPI)
+#define MCF_IRQ_PIT1        (MCFINT_VECBASE + MCFINT_PIT1)
 
 /*
  *  SDRAM configuration registers.
@@ -186,5 +190,15 @@
 #define	MCF_RCR_SWRESET		0x80		/* Software reset bit */
 #define	MCF_RCR_FRCSTOUT	0x40		/* Force external reset */
 
+/*
+ *  Power Management.
+ */
+#define MCFPM_WCR		0xfc040013
+#define MCFPM_PPMSR0		0xfc04002c
+#define MCFPM_PPMCR0		0xfc04002d
+#define MCFPM_PPMHR0		0xfc040030
+#define MCFPM_PPMLR0		0xfc040034
+#define MCFPM_LPCR		0xfc0a0007
+
 /****************************************************************************/
 #endif  /* m520xsim_h */
diff --git a/arch/m68k/include/asm/m523xsim.h b/arch/m68k/include/asm/m523xsim.h
index 075062d..91d3abc 100644
--- a/arch/m68k/include/asm/m523xsim.h
+++ b/arch/m68k/include/asm/m523xsim.h
@@ -52,6 +52,7 @@
 #define	MCF_IRQ_FECENTC0	(MCFINT_VECBASE + MCFINT_FECENTC0)
 
 #define	MCF_IRQ_QSPI		(MCFINT_VECBASE + MCFINT_QSPI)
+#define MCF_IRQ_PIT1		(MCFINT_VECBASE + MCFINT_PIT1)
 
 /*
  *	SDRAM configuration registers.
diff --git a/arch/m68k/include/asm/m525xsim.h b/arch/m68k/include/asm/m525xsim.h
new file mode 100644
index 0000000..6da24f6
--- /dev/null
+++ b/arch/m68k/include/asm/m525xsim.h
@@ -0,0 +1,194 @@
+/****************************************************************************/
+
+/*
+ *	m525xsim.h -- ColdFire 525x System Integration Module support.
+ *
+ *	(C) Copyright 2012, Steven king <sfking@fdwdc.com>
+ *	(C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/****************************************************************************/
+#ifndef	m525xsim_h
+#define m525xsim_h
+/****************************************************************************/
+
+#define CPU_NAME		"COLDFIRE(m525x)"
+#define CPU_INSTR_PER_JIFFY	3
+#define MCF_BUSCLK		(MCF_CLK / 2)
+
+#include <asm/m52xxacr.h>
+
+/*
+ *	The 525x has a second MBAR region, define its address.
+ */
+#define MCF_MBAR2		0x80000000
+
+/*
+ *	Define the 525x SIM register set addresses.
+ */
+#define MCFSIM_RSR		0x00		/* Reset Status reg (r/w) */
+#define MCFSIM_SYPCR		0x01		/* System Protection reg (r/w)*/
+#define MCFSIM_SWIVR		0x02		/* SW Watchdog intr reg (r/w) */
+#define MCFSIM_SWSR		0x03		/* SW Watchdog service (r/w) */
+#define MCFSIM_MPARK		0x0C		/* BUS Master Control Reg*/
+#define MCFSIM_IPR		0x40		/* Interrupt Pend reg (r/w) */
+#define MCFSIM_IMR		0x44		/* Interrupt Mask reg (r/w) */
+#define MCFSIM_ICR0		0x4c		/* Intr Ctrl reg 0 (r/w) */
+#define MCFSIM_ICR1		0x4d		/* Intr Ctrl reg 1 (r/w) */
+#define MCFSIM_ICR2		0x4e		/* Intr Ctrl reg 2 (r/w) */
+#define MCFSIM_ICR3		0x4f		/* Intr Ctrl reg 3 (r/w) */
+#define MCFSIM_ICR4		0x50		/* Intr Ctrl reg 4 (r/w) */
+#define MCFSIM_ICR5		0x51		/* Intr Ctrl reg 5 (r/w) */
+#define MCFSIM_ICR6		0x52		/* Intr Ctrl reg 6 (r/w) */
+#define MCFSIM_ICR7		0x53		/* Intr Ctrl reg 7 (r/w) */
+#define MCFSIM_ICR8		0x54		/* Intr Ctrl reg 8 (r/w) */
+#define MCFSIM_ICR9		0x55		/* Intr Ctrl reg 9 (r/w) */
+#define MCFSIM_ICR10		0x56		/* Intr Ctrl reg 10 (r/w) */
+#define MCFSIM_ICR11		0x57		/* Intr Ctrl reg 11 (r/w) */
+
+#define MCFSIM_CSAR0		0x80		/* CS 0 Address 0 reg (r/w) */
+#define MCFSIM_CSMR0		0x84		/* CS 0 Mask 0 reg (r/w) */
+#define MCFSIM_CSCR0		0x8a		/* CS 0 Control reg (r/w) */
+#define MCFSIM_CSAR1		0x8c		/* CS 1 Address reg (r/w) */
+#define MCFSIM_CSMR1		0x90		/* CS 1 Mask reg (r/w) */
+#define MCFSIM_CSCR1		0x96		/* CS 1 Control reg (r/w) */
+#define MCFSIM_CSAR2		0x98		/* CS 2 Address reg (r/w) */
+#define MCFSIM_CSMR2		0x9c		/* CS 2 Mask reg (r/w) */
+#define MCFSIM_CSCR2		0xa2		/* CS 2 Control reg (r/w) */
+#define MCFSIM_CSAR3		0xa4		/* CS 3 Address reg (r/w) */
+#define MCFSIM_CSMR3		0xa8		/* CS 3 Mask reg (r/w) */
+#define MCFSIM_CSCR3		0xae		/* CS 3 Control reg (r/w) */
+#define MCFSIM_CSAR4		0xb0		/* CS 4 Address reg (r/w) */
+#define MCFSIM_CSMR4		0xb4		/* CS 4 Mask reg (r/w) */
+#define MCFSIM_CSCR4		0xba		/* CS 4 Control reg (r/w) */
+
+#define MCFSIM_DCR		(MCF_MBAR + 0x100)	/* DRAM Control */
+#define MCFSIM_DACR0		(MCF_MBAR + 0x108)	/* DRAM 0 Addr/Ctrl */
+#define MCFSIM_DMR0		(MCF_MBAR + 0x10c)	/* DRAM 0 Mask */
+
+/*
+ * Secondary Interrupt Controller (in MBAR2)
+*/
+#define MCFINTC2_INTBASE	(MCF_MBAR2 + 0x168)	/* Base Vector Reg */
+#define MCFINTC2_INTPRI1	(MCF_MBAR2 + 0x140)	/* 0-7 priority */
+#define MCFINTC2_INTPRI2	(MCF_MBAR2 + 0x144)	/* 8-15 priority */
+#define MCFINTC2_INTPRI3	(MCF_MBAR2 + 0x148)	/* 16-23 priority */
+#define MCFINTC2_INTPRI4	(MCF_MBAR2 + 0x14c)	/* 24-31 priority */
+#define MCFINTC2_INTPRI5	(MCF_MBAR2 + 0x150)	/* 32-39 priority */
+#define MCFINTC2_INTPRI6	(MCF_MBAR2 + 0x154)	/* 40-47 priority */
+#define MCFINTC2_INTPRI7	(MCF_MBAR2 + 0x158)	/* 48-55 priority */
+#define MCFINTC2_INTPRI8	(MCF_MBAR2 + 0x15c)	/* 56-63 priority */
+
+#define MCFINTC2_INTPRI_REG(i)	(MCFINTC2_INTPRI1 + \
+				((((i) - MCFINTC2_VECBASE) / 8) * 4))
+#define MCFINTC2_INTPRI_BITS(b, i)	((b) << (((i) % 8) * 4))
+
+/*
+ *	Timer module.
+ */
+#define MCFTIMER_BASE1		(MCF_MBAR + 0x140)	/* Base of TIMER1 */
+#define MCFTIMER_BASE2		(MCF_MBAR + 0x180)	/* Base of TIMER2 */
+
+/*
+ *	UART module.
+ */
+#define MCFUART_BASE0		(MCF_MBAR + 0x1c0)	/* Base address UART0 */
+#define MCFUART_BASE1		(MCF_MBAR + 0x200)	/* Base address UART1 */
+
+/*
+ *	QSPI module.
+ */
+#define MCFQSPI_BASE		(MCF_MBAR + 0x300)	/* Base address QSPI */
+#define MCFQSPI_SIZE		0x40			/* Register set size */
+
+
+#define MCFQSPI_CS0		15
+#define MCFQSPI_CS1		16
+#define MCFQSPI_CS2		24
+#define MCFQSPI_CS3		28
+
+/*
+ *	I2C module.
+ */
+#define MCFI2C_BASE0		(MCF_MBAR + 0x280)	/* Base addreess I2C0 */
+#define MCFI2C_SIZE0		0x20			/* Register set size */
+
+#define MCFI2C_BASE1		(MCF_MBAR2 + 0x440)	/* Base addreess I2C1 */
+#define MCFI2C_SIZE1		0x20			/* Register set size */
+/*
+ *	DMA unit base addresses.
+ */
+#define MCFDMA_BASE0		(MCF_MBAR + 0x300)	/* Base address DMA 0 */
+#define MCFDMA_BASE1		(MCF_MBAR + 0x340)	/* Base address DMA 1 */
+#define MCFDMA_BASE2		(MCF_MBAR + 0x380)	/* Base address DMA 2 */
+#define MCFDMA_BASE3		(MCF_MBAR + 0x3C0)	/* Base address DMA 3 */
+
+/*
+ *	Some symbol defines for the above...
+ */
+#define MCFSIM_SWDICR		MCFSIM_ICR0	/* Watchdog timer ICR */
+#define MCFSIM_TIMER1ICR	MCFSIM_ICR1	/* Timer 1 ICR */
+#define MCFSIM_TIMER2ICR	MCFSIM_ICR2	/* Timer 2 ICR */
+#define MCFSIM_I2CICR		MCFSIM_ICR3	/* I2C ICR */
+#define MCFSIM_UART1ICR		MCFSIM_ICR4	/* UART 1 ICR */
+#define MCFSIM_UART2ICR		MCFSIM_ICR5	/* UART 2 ICR */
+#define MCFSIM_DMA0ICR		MCFSIM_ICR6	/* DMA 0 ICR */
+#define MCFSIM_DMA1ICR		MCFSIM_ICR7	/* DMA 1 ICR */
+#define MCFSIM_DMA2ICR		MCFSIM_ICR8	/* DMA 2 ICR */
+#define MCFSIM_DMA3ICR		MCFSIM_ICR9	/* DMA 3 ICR */
+#define MCFSIM_QSPIICR		MCFSIM_ICR10	/* QSPI ICR */
+
+/*
+ *	Define system peripheral IRQ usage.
+ */
+#define MCF_IRQ_QSPI		28		/* QSPI, Level 4 */
+#define MCF_IRQ_I2C0		29
+#define MCF_IRQ_TIMER		30		/* Timer0, Level 6 */
+#define MCF_IRQ_PROFILER	31		/* Timer1, Level 7 */
+
+#define MCF_IRQ_UART0		73		/* UART0 */
+#define MCF_IRQ_UART1		74		/* UART1 */
+
+/*
+ * Define the base interrupt for the second interrupt controller.
+ * We set it to 128, out of the way of the base interrupts, and plenty
+ * of room for its 64 interrupts.
+ */
+#define MCFINTC2_VECBASE	128
+
+#define MCF_IRQ_GPIO0		(MCFINTC2_VECBASE + 32)
+#define MCF_IRQ_GPIO1		(MCFINTC2_VECBASE + 33)
+#define MCF_IRQ_GPIO2		(MCFINTC2_VECBASE + 34)
+#define MCF_IRQ_GPIO3		(MCFINTC2_VECBASE + 35)
+#define MCF_IRQ_GPIO4		(MCFINTC2_VECBASE + 36)
+#define MCF_IRQ_GPIO5		(MCFINTC2_VECBASE + 37)
+#define MCF_IRQ_GPIO6		(MCFINTC2_VECBASE + 38)
+
+#define MCF_IRQ_USBWUP		(MCFINTC2_VECBASE + 40)
+#define MCF_IRQ_I2C1		(MCFINTC2_VECBASE + 62)
+
+/*
+ *	General purpose IO registers (in MBAR2).
+ */
+#define MCFSIM2_GPIOREAD	(MCF_MBAR2 + 0x000)	/* GPIO read values */
+#define MCFSIM2_GPIOWRITE	(MCF_MBAR2 + 0x004)	/* GPIO write values */
+#define MCFSIM2_GPIOENABLE	(MCF_MBAR2 + 0x008)	/* GPIO enabled */
+#define MCFSIM2_GPIOFUNC	(MCF_MBAR2 + 0x00C)	/* GPIO function */
+#define MCFSIM2_GPIO1READ	(MCF_MBAR2 + 0x0B0)	/* GPIO1 read values */
+#define MCFSIM2_GPIO1WRITE	(MCF_MBAR2 + 0x0B4)	/* GPIO1 write values */
+#define MCFSIM2_GPIO1ENABLE	(MCF_MBAR2 + 0x0B8)	/* GPIO1 enabled */
+#define MCFSIM2_GPIO1FUNC	(MCF_MBAR2 + 0x0BC)	/* GPIO1 function */
+
+#define MCFSIM2_GPIOINTSTAT	(MCF_MBAR2 + 0xc0)	/* GPIO intr status */
+#define MCFSIM2_GPIOINTCLEAR	(MCF_MBAR2 + 0xc0)	/* GPIO intr clear */
+#define MCFSIM2_GPIOINTENABLE	(MCF_MBAR2 + 0xc4)	/* GPIO intr enable */
+
+/*
+ * Generic GPIO support
+ */
+#define MCFGPIO_PIN_MAX		64
+#define MCFGPIO_IRQ_MAX		7
+#define MCFGPIO_IRQ_VECBASE	MCF_IRQ_GPIO0
+
+/****************************************************************************/
+#endif	/* m525xsim_h */
diff --git a/arch/m68k/include/asm/m527xsim.h b/arch/m68k/include/asm/m527xsim.h
index 83db810..71aa510 100644
--- a/arch/m68k/include/asm/m527xsim.h
+++ b/arch/m68k/include/asm/m527xsim.h
@@ -60,6 +60,7 @@
 #define	MCF_IRQ_FECENTC1	(MCFINT2_VECBASE + MCFINT2_FECENTC1)
 
 #define	MCF_IRQ_QSPI		(MCFINT_VECBASE + MCFINT_QSPI)
+#define MCF_IRQ_PIT1		(MCFINT_VECBASE + MCFINT_PIT1)
 
 /*
  *	SDRAM configuration registers.
diff --git a/arch/m68k/include/asm/m528xsim.h b/arch/m68k/include/asm/m528xsim.h
index 497c31c..4acb3c0 100644
--- a/arch/m68k/include/asm/m528xsim.h
+++ b/arch/m68k/include/asm/m528xsim.h
@@ -52,7 +52,7 @@
 #define	MCF_IRQ_FECENTC0	(MCFINT_VECBASE + MCFINT_FECENTC0)
 
 #define	MCF_IRQ_QSPI		(MCFINT_VECBASE + MCFINT_QSPI)
-
+#define MCF_IRQ_PIT1		(MCFINT_VECBASE + MCFINT_PIT1)
 /*
  *	SDRAM configuration registers.
  */
diff --git a/arch/m68k/include/asm/m532xsim.h b/arch/m68k/include/asm/m532xsim.h
index 29b66e2..5ca7b29 100644
--- a/arch/m68k/include/asm/m532xsim.h
+++ b/arch/m68k/include/asm/m532xsim.h
@@ -82,6 +82,9 @@
 #define	MCFINTC1_SIMR		0xFC04C01C
 #define	MCFINTC1_CIMR		0xFC04C01D
 #define	MCFINTC1_ICR0		0xFC04C040
+#define MCFINTC2_SIMR		(0)
+#define MCFINTC2_CIMR		(0)
+#define MCFINTC2_ICR0		(0)
 
 #define MCFSIM_ICR_TIMER1	(0xFC048040+32)
 #define MCFSIM_ICR_TIMER2	(0xFC048040+33)
@@ -135,6 +138,20 @@
 #define	MCF_RCR_SWRESET		0x80		/* Software reset bit */
 #define	MCF_RCR_FRCSTOUT	0x40		/* Force external reset */
 
+
+/*
+ * Power Management
+ */
+#define MCFPM_WCR		0xfc040013
+#define MCFPM_PPMSR0		0xfc04002c
+#define MCFPM_PPMCR0		0xfc04002d
+#define MCFPM_PPMSR1		0xfc04002e
+#define MCFPM_PPMCR1		0xfc04002f
+#define MCFPM_PPMHR0		0xfc040030
+#define MCFPM_PPMLR0		0xfc040034
+#define MCFPM_PPMHR1		0xfc040038
+#define MCFPM_LPCR		0xec090007
+
 /*********************************************************************
  *
  * Inter-IC (I2C) Module
diff --git a/arch/m68k/include/asm/m5441xsim.h b/arch/m68k/include/asm/m5441xsim.h
new file mode 100644
index 0000000..cc798ab
--- /dev/null
+++ b/arch/m68k/include/asm/m5441xsim.h
@@ -0,0 +1,276 @@
+/*
+ *	m5441xsim.h -- Coldfire 5441x register definitions
+ *
+ *	(C) Copyright 2012, Steven King <sfking@fdwdc.com>
+*/
+
+#ifndef m5441xsim_h
+#define m5441xsim_h
+
+#define CPU_NAME		"COLDFIRE(m5441x)"
+#define CPU_INSTR_PER_JIFFY	2
+#define MCF_BUSCLK		(MCF_CLK / 2)
+
+#include <asm/m54xxacr.h>
+
+/*
+ *  Reset Controller Module.
+ */
+
+#define	MCF_RCR			0xec090000
+#define	MCF_RSR			0xec090001
+
+#define	MCF_RCR_SWRESET		0x80		/* Software reset bit */
+#define	MCF_RCR_FRCSTOUT	0x40		/* Force external reset */
+
+/*
+ *  Interrupt Controller Modules.
+ */
+/* the 5441x have 3 interrupt controllers, each control 64 interrupts */
+#define MCFINT_VECBASE		64
+#define MCFINT0_VECBASE		MCFINT_VECBASE
+#define MCFINT1_VECBASE		(MCFINT0_VECBASE + 64)
+#define MCFINT2_VECBASE		(MCFINT1_VECBASE + 64)
+
+/* interrupt controller 0 */
+#define MCFINTC0_SIMR		0xfc04801c
+#define MCFINTC0_CIMR		0xfc04801d
+#define	MCFINTC0_ICR0		0xfc048040
+/* interrupt controller 1 */
+#define MCFINTC1_SIMR		0xfc04c01c
+#define MCFINTC1_CIMR		0xfc04c01d
+#define	MCFINTC1_ICR0		0xfc04c040
+/* interrupt controller 2 */
+#define MCFINTC2_SIMR		0xfc05001c
+#define MCFINTC2_CIMR		0xfc05001d
+#define	MCFINTC2_ICR0		0xfc050040
+
+/* on interrupt controller 0 */
+#define MCFINT0_EPORT0		1
+#define MCFINT0_UART0		26
+#define MCFINT0_UART1		27
+#define MCFINT0_UART2		28
+#define MCFINT0_UART3		29
+#define MCFINT0_I2C0		30
+#define MCFINT0_DSPI0		31
+
+#define MCFINT0_TIMER0		32
+#define MCFINT0_TIMER1		33
+#define MCFINT0_TIMER2		34
+#define MCFINT0_TIMER3		35
+
+#define MCFINT0_FECRX0		36
+#define MCFINT0_FECTX0		40
+#define MCFINT0_FECENTC0	42
+
+#define MCFINT0_FECRX1		49
+#define MCFINT0_FECTX1		53
+#define MCFINT0_FECENTC1	55
+
+/* on interrupt controller 1 */
+#define MCFINT1_UART4		48
+#define MCFINT1_UART5		49
+#define MCFINT1_UART6		50
+#define MCFINT1_UART7		51
+#define MCFINT1_UART8		52
+#define MCFINT1_UART9		53
+#define MCFINT1_DSPI1		54
+#define MCFINT1_DSPI2		55
+#define MCFINT1_DSPI3		56
+#define MCFINT1_I2C1		57
+#define MCFINT1_I2C2		58
+#define MCFINT1_I2C3		59
+#define MCFINT1_I2C4		60
+#define MCFINT1_I2C5		61
+
+/* on interrupt controller 2 */
+#define MCFINT2_PIT0		13
+#define MCFINT2_PIT1		14
+#define MCFINT2_PIT2		15
+#define MCFINT2_PIT3		16
+#define MCFINT2_RTC		26
+
+/*
+ *  PIT timer module.
+ */
+#define	MCFPIT_BASE0		0xFC080000	/* Base address of TIMER0 */
+#define	MCFPIT_BASE1		0xFC084000	/* Base address of TIMER1 */
+#define	MCFPIT_BASE2		0xFC088000	/* Base address of TIMER2 */
+#define	MCFPIT_BASE3		0xFC08C000	/* Base address of TIMER3 */
+
+
+#define MCF_IRQ_PIT1		(MCFINT2_VECBASE + MCFINT2_PIT1)
+
+/*
+ * Power Management
+ */
+#define MCFPM_WCR		0xfc040013
+#define MCFPM_PPMSR0		0xfc04002c
+#define MCFPM_PPMCR0		0xfc04002d
+#define MCFPM_PPMSR1		0xfc04002e
+#define MCFPM_PPMCR1		0xfc04002f
+#define MCFPM_PPMHR0		0xfc040030
+#define MCFPM_PPMLR0		0xfc040034
+#define MCFPM_PPMHR1		0xfc040038
+#define MCFPM_PPMLR1		0xfc04003c
+#define MCFPM_LPCR		0xec090007
+/*
+ *  UART module.
+ */
+#define MCFUART_BASE0		0xfc060000	/* Base address of UART0 */
+#define MCFUART_BASE1		0xfc064000	/* Base address of UART1 */
+#define MCFUART_BASE2		0xfc068000	/* Base address of UART2 */
+#define MCFUART_BASE3		0xfc06c000	/* Base address of UART3 */
+#define MCFUART_BASE4		0xec060000	/* Base address of UART4 */
+#define MCFUART_BASE5		0xec064000	/* Base address of UART5 */
+#define MCFUART_BASE6		0xec068000	/* Base address of UART6 */
+#define MCFUART_BASE7		0xec06c000	/* Base address of UART7 */
+#define MCFUART_BASE8		0xec070000	/* Base address of UART8 */
+#define MCFUART_BASE9		0xec074000	/* Base address of UART9 */
+
+#define MCF_IRQ_UART0		(MCFINT0_VECBASE + MCFINT0_UART0)
+#define MCF_IRQ_UART1		(MCFINT0_VECBASE + MCFINT0_UART1)
+#define MCF_IRQ_UART2		(MCFINT0_VECBASE + MCFINT0_UART2)
+#define MCF_IRQ_UART3		(MCFINT0_VECBASE + MCFINT0_UART3)
+#define MCF_IRQ_UART4		(MCFINT1_VECBASE + MCFINT1_UART4)
+#define MCF_IRQ_UART5		(MCFINT1_VECBASE + MCFINT1_UART5)
+#define MCF_IRQ_UART6		(MCFINT1_VECBASE + MCFINT1_UART6)
+#define MCF_IRQ_UART7		(MCFINT1_VECBASE + MCFINT1_UART7)
+#define MCF_IRQ_UART8		(MCFINT1_VECBASE + MCFINT1_UART8)
+#define MCF_IRQ_UART9		(MCFINT1_VECBASE + MCFINT1_UART9)
+/*
+ *  FEC modules.
+ */
+#define MCFFEC_BASE0		0xfc0d4000
+#define MCFFEC_SIZE0		0x800
+#define MCF_IRQ_FECRX0		(MCFINT0_VECBASE + MCFINT0_FECRX0)
+#define MCF_IRQ_FECTX0		(MCFINT0_VECBASE + MCFINT0_FECTX0)
+#define MCF_IRQ_FECENTC0	(MCFINT0_VECBASE + MCFINT0_FECENTC0)
+
+#define MCFFEC_BASE1		0xfc0d8000
+#define MCFFEC_SIZE1		0x800
+#define MCF_IRQ_FECRX1		(MCFINT0_VECBASE + MCFINT0_FECRX1)
+#define MCF_IRQ_FECTX1		(MCFINT0_VECBASE + MCFINT0_FECTX1)
+#define MCF_IRQ_FECENTC1	(MCFINT0_VECBASE + MCFINT0_FECENTC1)
+/*
+ *  I2C modules.
+ */
+#define MCFI2C_BASE0		0xfc058000
+#define MCFI2C_SIZE0		0x20
+#define MCFI2C_BASE1		0xfc038000
+#define MCFI2C_SIZE1		0x20
+#define MCFI2C_BASE2		0xec010000
+#define MCFI2C_SIZE2		0x20
+#define MCFI2C_BASE3		0xec014000
+#define MCFI2C_SIZE3		0x20
+#define MCFI2C_BASE4		0xec018000
+#define MCFI2C_SIZE4		0x20
+#define MCFI2C_BASE5		0xec01c000
+#define MCFI2C_SIZE5		0x20
+
+#define MCF_IRQ_I2C0		(MCFINT0_VECBASE + MCFINT0_I2C0)
+#define MCF_IRQ_I2C1		(MCFINT1_VECBASE + MCFINT1_I2C1)
+#define MCF_IRQ_I2C2		(MCFINT1_VECBASE + MCFINT1_I2C2)
+#define MCF_IRQ_I2C3		(MCFINT1_VECBASE + MCFINT1_I2C3)
+#define MCF_IRQ_I2C4		(MCFINT1_VECBASE + MCFINT1_I2C4)
+#define MCF_IRQ_I2C5		(MCFINT1_VECBASE + MCFINT1_I2C5)
+/*
+ *  EPORT Module.
+ */
+#define MCFEPORT_EPPAR		0xfc090000
+#define MCFEPORT_EPIER		0xfc090003
+#define MCFEPORT_EPFR		0xfc090006
+/*
+ *  RTC Module.
+ */
+#define MCFRTC_BASE		0xfc0a8000
+#define MCFRTC_SIZE		(0xfc0a8840 - 0xfc0a8000)
+#define MCF_IRQ_RTC		(MCFINT2_VECBASE + MCFINT2_RTC)
+
+/*
+ *  GPIO Module.
+ */
+#define MCFGPIO_PODR_A		0xec094000
+#define MCFGPIO_PODR_B		0xec094001
+#define MCFGPIO_PODR_C		0xec094002
+#define MCFGPIO_PODR_D		0xec094003
+#define MCFGPIO_PODR_E		0xec094004
+#define MCFGPIO_PODR_F		0xec094005
+#define MCFGPIO_PODR_G		0xec094006
+#define MCFGPIO_PODR_H		0xec094007
+#define MCFGPIO_PODR_I		0xec094008
+#define MCFGPIO_PODR_J		0xec094009
+#define MCFGPIO_PODR_K		0xec09400a
+
+#define MCFGPIO_PDDR_A		0xec09400c
+#define MCFGPIO_PDDR_B		0xec09400d
+#define MCFGPIO_PDDR_C		0xec09400e
+#define MCFGPIO_PDDR_D		0xec09400f
+#define MCFGPIO_PDDR_E		0xec094010
+#define MCFGPIO_PDDR_F		0xec094011
+#define MCFGPIO_PDDR_G		0xec094012
+#define MCFGPIO_PDDR_H		0xec094013
+#define MCFGPIO_PDDR_I		0xec094014
+#define MCFGPIO_PDDR_J		0xec094015
+#define MCFGPIO_PDDR_K		0xec094016
+
+#define MCFGPIO_PPDSDR_A	0xec094018
+#define MCFGPIO_PPDSDR_B	0xec094019
+#define MCFGPIO_PPDSDR_C	0xec09401a
+#define MCFGPIO_PPDSDR_D	0xec09401b
+#define MCFGPIO_PPDSDR_E	0xec09401c
+#define MCFGPIO_PPDSDR_F	0xec09401d
+#define MCFGPIO_PPDSDR_G	0xec09401e
+#define MCFGPIO_PPDSDR_H	0xec09401f
+#define MCFGPIO_PPDSDR_I	0xec094020
+#define MCFGPIO_PPDSDR_J	0xec094021
+#define MCFGPIO_PPDSDR_K	0xec094022
+
+#define MCFGPIO_PCLRR_A		0xec094024
+#define MCFGPIO_PCLRR_B		0xec094025
+#define MCFGPIO_PCLRR_C		0xec094026
+#define MCFGPIO_PCLRR_D		0xec094027
+#define MCFGPIO_PCLRR_E		0xec094028
+#define MCFGPIO_PCLRR_F		0xec094029
+#define MCFGPIO_PCLRR_G		0xec09402a
+#define MCFGPIO_PCLRR_H		0xec09402b
+#define MCFGPIO_PCLRR_I		0xec09402c
+#define MCFGPIO_PCLRR_J		0xec09402d
+#define MCFGPIO_PCLRR_K		0xec09402e
+
+#define MCFGPIO_PAR_FBCTL	0xec094048
+#define MCFGPIO_PAR_BE		0xec094049
+#define MCFGPIO_PAR_CS		0xec09404a
+#define MCFGPIO_PAR_CANI2C	0xec09404b
+#define MCFGPIO_PAR_IRQ0H	0xec09404c
+#define MCFGPIO_PAR_IRQ0L	0xec09404d
+#define MCFGPIO_PAR_DSPIOWH	0xec09404e
+#define MCFGPIO_PAR_DSPIOWL	0xec09404f
+#define MCFGPIO_PAR_TIMER	0xec094050
+#define MCFGPIO_PAR_UART2	0xec094051
+#define MCFGPIO_PAR_UART1	0xec094052
+#define MCFGPIO_PAR_UART0	0xec094053
+#define MCFGPIO_PAR_SDHCH	0xec094054
+#define MCFGPIO_PAR_SDHCL	0xec094055
+#define MCFGPIO_PAR_SIMP0H	0xec094056
+#define MCFGPIO_PAR_SIMP0L	0xec094057
+#define MCFGPIO_PAR_SSI0H	0xec094058
+#define MCFGPIO_PAR_SSI0L	0xec094059
+#define MCFGPIO_PAR_DEBUGH1	0xec09405a
+#define MCFGPIO_PAR_DEBUGH0	0xec09405b
+#define MCFGPIO_PAR_DEBUGl	0xec09405c
+#define MCFGPIO_PAR_FEC		0xec09405e
+
+/* generalization for generic gpio support */
+#define MCFGPIO_PODR		MCFGPIO_PODR_A
+#define MCFGPIO_PDDR		MCFGPIO_PDDR_A
+#define MCFGPIO_PPDR		MCFGPIO_PPDSDR_A
+#define MCFGPIO_SETR		MCFGPIO_PPDSDR_A
+#define MCFGPIO_CLRR		MCFGPIO_PCLRR_A
+
+#define MCFGPIO_IRQ_MIN		17
+#define MCFGPIO_IRQ_MAX		24
+#define MCFGPIO_IRQ_VECBASE	(MCFINT_VECBASE - MCFGPIO_IRQ_MIN)
+#define MCFGPIO_PIN_MAX		87
+
+#endif /* m5441xsim_h */
diff --git a/arch/m68k/include/asm/m54xxacr.h b/arch/m68k/include/asm/m54xxacr.h
index 47906aa..192bbfe 100644
--- a/arch/m68k/include/asm/m54xxacr.h
+++ b/arch/m68k/include/asm/m54xxacr.h
@@ -55,6 +55,10 @@
 #define ICACHE_SIZE 0x8000	/* instruction - 32k */
 #define DCACHE_SIZE 0x8000	/* data - 32k */
 
+#elif defined(CONFIG_M5441x)
+
+#define ICACHE_SIZE 0x2000	/* instruction - 8k */
+#define DCACHE_SIZE 0x2000	/* data - 8k */
 #endif
 
 #define CACHE_LINE_SIZE 0x0010	/* 16 bytes */
diff --git a/arch/m68k/include/asm/mac_mouse.h b/arch/m68k/include/asm/mac_mouse.h
deleted file mode 100644
index 39a5c29..0000000
--- a/arch/m68k/include/asm/mac_mouse.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _ASM_MAC_MOUSE_H
-#define _ASM_MAC_MOUSE_H
-
-/*
- * linux/include/asm-m68k/mac_mouse.h
- * header file for Macintosh ADB mouse driver
- * 27-10-97 Michael Schmitz
- * copied from:
- * header file for Atari Mouse driver
- * by Robert de Vries (robert@and.nl) on 19Jul93
- */
-
-struct mouse_status {
-	char		buttons;
-	short		dx;
-	short		dy;
-	int		ready;
-	int		active;
-	wait_queue_head_t wait;
-	struct fasync_struct *fasyncptr;
-};
-
-#endif
diff --git a/arch/m68k/include/asm/mcfclk.h b/arch/m68k/include/asm/mcfclk.h
new file mode 100644
index 0000000..b676a02
--- /dev/null
+++ b/arch/m68k/include/asm/mcfclk.h
@@ -0,0 +1,43 @@
+/*
+ * mcfclk.h -- coldfire specific clock structure
+ */
+
+
+#ifndef mcfclk_h
+#define mcfclk_h
+
+struct clk;
+
+#ifdef MCFPM_PPMCR0
+struct clk_ops {
+	void (*enable)(struct clk *);
+	void (*disable)(struct clk *);
+};
+
+struct clk {
+	const char *name;
+	struct clk_ops *clk_ops;
+	unsigned long rate;
+	unsigned long enabled;
+	u8 slot;
+};
+
+extern struct clk *mcf_clks[];
+extern struct clk_ops clk_ops0;
+#ifdef MCFPM_PPMCR1
+extern struct clk_ops clk_ops1;
+#endif /* MCFPM_PPMCR1 */
+
+#define DEFINE_CLK(clk_bank, clk_name, clk_slot, clk_rate) \
+static struct clk __clk_##clk_bank##_##clk_slot = { \
+	.name = clk_name, \
+	.clk_ops = &clk_ops##clk_bank, \
+	.rate = clk_rate, \
+	.slot = clk_slot, \
+}
+
+void __clk_init_enabled(struct clk *);
+void __clk_init_disabled(struct clk *);
+#endif /* MCFPM_PPMCR0 */
+
+#endif /* mcfclk_h */
diff --git a/arch/m68k/include/asm/mcfgpio.h b/arch/m68k/include/asm/mcfgpio.h
index fe468ea..fa1059f 100644
--- a/arch/m68k/include/asm/mcfgpio.h
+++ b/arch/m68k/include/asm/mcfgpio.h
@@ -16,82 +16,289 @@
 #ifndef mcfgpio_h
 #define mcfgpio_h
 
-#include <linux/io.h>
+#ifdef CONFIG_GPIOLIB
 #include <asm-generic/gpio.h>
+#else
+
+int __mcfgpio_get_value(unsigned gpio);
+void __mcfgpio_set_value(unsigned gpio, int value);
+int __mcfgpio_direction_input(unsigned gpio);
+int __mcfgpio_direction_output(unsigned gpio, int value);
+int __mcfgpio_request(unsigned gpio);
+void __mcfgpio_free(unsigned gpio);
+
+/* our alternate 'gpiolib' functions */
+static inline int __gpio_get_value(unsigned gpio)
+{
+	if (gpio < MCFGPIO_PIN_MAX)
+		return __mcfgpio_get_value(gpio);
+	else
+		return -EINVAL;
+}
+
+static inline void __gpio_set_value(unsigned gpio, int value)
+{
+	if (gpio < MCFGPIO_PIN_MAX)
+		__mcfgpio_set_value(gpio, value);
+}
+
+static inline int __gpio_cansleep(unsigned gpio)
+{
+	if (gpio < MCFGPIO_PIN_MAX)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+static inline int __gpio_to_irq(unsigned gpio)
+{
+	return -EINVAL;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+	if (gpio < MCFGPIO_PIN_MAX)
+		return __mcfgpio_direction_input(gpio);
+	else
+		return -EINVAL;
+}
+
+static inline int gpio_direction_output(unsigned gpio, int value)
+{
+	if (gpio < MCFGPIO_PIN_MAX)
+		return __mcfgpio_direction_output(gpio, value);
+	else
+		return -EINVAL;
+}
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+	if (gpio < MCFGPIO_PIN_MAX)
+		return __mcfgpio_request(gpio);
+	else
+		return -EINVAL;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+	if (gpio < MCFGPIO_PIN_MAX)
+		__mcfgpio_free(gpio);
+}
+
+#endif /* CONFIG_GPIOLIB */
 
-struct mcf_gpio_chip {
-	struct gpio_chip gpio_chip;
-	void __iomem *pddr;
-	void __iomem *podr;
-	void __iomem *ppdr;
-	void __iomem *setr;
-	void __iomem *clrr;
-	const u8 *gpio_to_pinmux;
-};
-
-extern struct mcf_gpio_chip mcf_gpio_chips[];
-extern unsigned int mcf_gpio_chips_size;
-
-int mcf_gpio_direction_input(struct gpio_chip *, unsigned);
-int mcf_gpio_get_value(struct gpio_chip *, unsigned);
-int mcf_gpio_direction_output(struct gpio_chip *, unsigned, int);
-void mcf_gpio_set_value(struct gpio_chip *, unsigned, int);
-void mcf_gpio_set_value_fast(struct gpio_chip *, unsigned, int);
-int mcf_gpio_request(struct gpio_chip *, unsigned);
-void mcf_gpio_free(struct gpio_chip *, unsigned);
 
 /*
- *	Define macros to ease the pain of setting up the GPIO tables. There
- *	are two cases we need to deal with here, they cover all currently
- *	available ColdFire GPIO hardware. There are of course minor differences
- *	in the layout and number of bits in each ColdFire part, but the macros
- *	take all that in.
+ * The Freescale Coldfire family is quite varied in how they implement GPIO.
+ * Some parts have 8 bit ports, some have 16bit and some have 32bit; some have
+ * only one port, others have multiple ports; some have a single data latch
+ * for both input and output, others have a separate pin data register to read
+ * input; some require a read-modify-write access to change an output, others
+ * have set and clear registers for some of the outputs; Some have all the
+ * GPIOs in a single control area, others have some GPIOs implemented in
+ * different modules.
  *
- *	Firstly is the conventional GPIO registers where we toggle individual
- *	bits in a register, preserving the other bits in the register. For
- *	lack of a better term I have called this the slow method.
+ * This implementation attempts accommodate the differences while presenting
+ * a generic interface that will optimize to as few instructions as possible.
+ */
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+    defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
+    defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+    defined(CONFIG_M532x) || defined(CONFIG_M54xx) || \
+    defined(CONFIG_M5441x)
+
+/* These parts have GPIO organized by 8 bit ports */
+
+#define MCFGPIO_PORTTYPE		u8
+#define MCFGPIO_PORTSIZE		8
+#define mcfgpio_read(port)		__raw_readb(port)
+#define mcfgpio_write(data, port)	__raw_writeb(data, port)
+
+#elif defined(CONFIG_M5307) || defined(CONFIG_M5407) || defined(CONFIG_M5272)
+
+/* These parts have GPIO organized by 16 bit ports */
+
+#define MCFGPIO_PORTTYPE		u16
+#define MCFGPIO_PORTSIZE		16
+#define mcfgpio_read(port)		__raw_readw(port)
+#define mcfgpio_write(data, port)	__raw_writew(data, port)
+
+#elif defined(CONFIG_M5249) || defined(CONFIG_M525x)
+
+/* These parts have GPIO organized by 32 bit ports */
+
+#define MCFGPIO_PORTTYPE		u32
+#define MCFGPIO_PORTSIZE		32
+#define mcfgpio_read(port)		__raw_readl(port)
+#define mcfgpio_write(data, port)	__raw_writel(data, port)
+
+#endif
+
+#define mcfgpio_bit(gpio)		(1 << ((gpio) %  MCFGPIO_PORTSIZE))
+#define mcfgpio_port(gpio)		((gpio) / MCFGPIO_PORTSIZE)
+
+#if defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
+    defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+    defined(CONFIG_M532x) || defined(CONFIG_M5441x)
+/*
+ * These parts have an 'Edge' Port module (external interrupt/GPIO) which uses
+ * read-modify-write to change an output and a GPIO module which has separate
+ * set/clr registers to directly change outputs with a single write access.
+ */
+#if defined(CONFIG_M528x)
+/*
+ * The 528x also has GPIOs in other modules (GPT, QADC) which use
+ * read-modify-write as well as those controlled by the EPORT and GPIO modules.
  */
-#define	MCFGPS(mlabel, mbase, mngpio, mpddr, mpodr, mppdr)		    \
-	{								    \
-		.gpio_chip			= {			    \
-			.label			= #mlabel,		    \
-			.request		= mcf_gpio_request,	    \
-			.free			= mcf_gpio_free,	    \
-			.direction_input	= mcf_gpio_direction_input, \
-			.direction_output	= mcf_gpio_direction_output,\
-			.get			= mcf_gpio_get_value,	    \
-			.set			= mcf_gpio_set_value,       \
-			.base			= mbase,		    \
-			.ngpio			= mngpio,		    \
-		},							    \
-		.pddr		= (void __iomem *) mpddr,		    \
-		.podr		= (void __iomem *) mpodr,		    \
-		.ppdr		= (void __iomem *) mppdr,		    \
-	}
+#define MCFGPIO_SCR_START		40
+#elif defined(CONFIGM5441x)
+/* The m5441x EPORT doesn't have its own GPIO port, uses PORT C */
+#define MCFGPIO_SCR_START		0
+#else
+#define MCFGPIO_SCR_START		8
+#endif
 
+#define MCFGPIO_SETR_PORT(gpio)		(MCFGPIO_SETR + \
+					mcfgpio_port(gpio - MCFGPIO_SCR_START))
+
+#define MCFGPIO_CLRR_PORT(gpio)		(MCFGPIO_CLRR + \
+					mcfgpio_port(gpio - MCFGPIO_SCR_START))
+#else
+
+#define MCFGPIO_SCR_START		MCFGPIO_PIN_MAX
+/* with MCFGPIO_SCR == MCFGPIO_PIN_MAX, these will be optimized away */
+#define MCFGPIO_SETR_PORT(gpio)		0
+#define MCFGPIO_CLRR_PORT(gpio)		0
+
+#endif
 /*
- *	Secondly is the faster case, where we have set and clear registers
- *	that allow us to set or clear a bit with a single write, not having
- *	to worry about preserving other bits.
+ * Coldfire specific helper functions
  */
-#define	MCFGPF(mlabel, mbase, mngpio)					    \
-	{								    \
-		.gpio_chip			= {			    \
-			.label			= #mlabel,		    \
-			.request		= mcf_gpio_request,	    \
-			.free			= mcf_gpio_free,	    \
-			.direction_input	= mcf_gpio_direction_input, \
-			.direction_output	= mcf_gpio_direction_output,\
-			.get			= mcf_gpio_get_value,	    \
-			.set			= mcf_gpio_set_value_fast,  \
-			.base			= mbase,		    \
-			.ngpio			= mngpio,		    \
-		},							    \
-		.pddr		= (void __iomem *) MCFGPIO_PDDR_##mlabel,   \
-		.podr		= (void __iomem *) MCFGPIO_PODR_##mlabel,   \
-		.ppdr		= (void __iomem *) MCFGPIO_PPDSDR_##mlabel, \
-		.setr		= (void __iomem *) MCFGPIO_PPDSDR_##mlabel, \
-		.clrr		= (void __iomem *) MCFGPIO_PCLRR_##mlabel,  \
-	}
 
+/* return the port pin data register for a gpio */
+static inline u32 __mcfgpio_ppdr(unsigned gpio)
+{
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+    defined(CONFIG_M5307) || defined(CONFIG_M5407)
+	return MCFSIM_PADAT;
+#elif defined(CONFIG_M5272)
+	if (gpio < 16)
+		return MCFSIM_PADAT;
+	else if (gpio < 32)
+		return MCFSIM_PBDAT;
+	else
+		return MCFSIM_PCDAT;
+#elif defined(CONFIG_M5249) || defined(CONFIG_M525x)
+	if (gpio < 32)
+		return MCFSIM2_GPIOREAD;
+	else
+		return MCFSIM2_GPIO1READ;
+#elif defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
+      defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+      defined(CONFIG_M532x) || defined(CONFIG_M5441x)
+#if !defined(CONFIG_M5441x)
+	if (gpio < 8)
+		return MCFEPORT_EPPDR;
+#if defined(CONFIG_M528x)
+	else if (gpio < 16)
+		return MCFGPTA_GPTPORT;
+	else if (gpio < 24)
+		return MCFGPTB_GPTPORT;
+	else if (gpio < 32)
+		return MCFQADC_PORTQA;
+	else if (gpio < 40)
+		return MCFQADC_PORTQB;
+#endif /* defined(CONFIG_M528x) */
+	else
+#endif /* !defined(CONFIG_M5441x) */
+		return MCFGPIO_PPDR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#else
+	return 0;
 #endif
+}
+
+/* return the port output data register for a gpio */
+static inline u32 __mcfgpio_podr(unsigned gpio)
+{
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+    defined(CONFIG_M5307) || defined(CONFIG_M5407)
+	return MCFSIM_PADAT;
+#elif defined(CONFIG_M5272)
+	if (gpio < 16)
+		return MCFSIM_PADAT;
+	else if (gpio < 32)
+		return MCFSIM_PBDAT;
+	else
+		return MCFSIM_PCDAT;
+#elif defined(CONFIG_M5249) || defined(CONFIG_M525x)
+	if (gpio < 32)
+		return MCFSIM2_GPIOWRITE;
+	else
+		return MCFSIM2_GPIO1WRITE;
+#elif defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
+      defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+      defined(CONFIG_M532x) || defined(CONFIG_M5441x)
+#if !defined(CONFIG_M5441x)
+	if (gpio < 8)
+		return MCFEPORT_EPDR;
+#if defined(CONFIG_M528x)
+	else if (gpio < 16)
+		return MCFGPTA_GPTPORT;
+	else if (gpio < 24)
+		return MCFGPTB_GPTPORT;
+	else if (gpio < 32)
+		return MCFQADC_PORTQA;
+	else if (gpio < 40)
+		return MCFQADC_PORTQB;
+#endif /* defined(CONFIG_M528x) */
+	else
+#endif /* !defined(CONFIG_M5441x) */
+		return MCFGPIO_PODR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#else
+	return 0;
+#endif
+}
+
+/* return the port direction data register for a gpio */
+static inline u32 __mcfgpio_pddr(unsigned gpio)
+{
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+    defined(CONFIG_M5307) || defined(CONFIG_M5407)
+	return MCFSIM_PADDR;
+#elif defined(CONFIG_M5272)
+	if (gpio < 16)
+		return MCFSIM_PADDR;
+	else if (gpio < 32)
+		return MCFSIM_PBDDR;
+	else
+		return MCFSIM_PCDDR;
+#elif defined(CONFIG_M5249) || defined(CONFIG_M525x)
+	if (gpio < 32)
+		return MCFSIM2_GPIOENABLE;
+	else
+		return MCFSIM2_GPIO1ENABLE;
+#elif defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
+      defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+      defined(CONFIG_M532x) || defined(CONFIG_M5441x)
+#if !defined(CONFIG_M5441x)
+	if (gpio < 8)
+		return MCFEPORT_EPDDR;
+#if defined(CONFIG_M528x)
+	else if (gpio < 16)
+		return MCFGPTA_GPTDDR;
+	else if (gpio < 24)
+		return MCFGPTB_GPTDDR;
+	else if (gpio < 32)
+		return MCFQADC_DDRQA;
+	else if (gpio < 40)
+		return MCFQADC_DDRQB;
+#endif /* defined(CONFIG_M528x) */
+	else
+#endif /* !defined(CONFIG_M5441x) */
+		return MCFGPIO_PDDR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#else
+	return 0;
+#endif
+}
+
+#endif /* mcfgpio_h */
diff --git a/arch/m68k/include/asm/mcfmbus.h b/arch/m68k/include/asm/mcfmbus.h
deleted file mode 100644
index 319899c..0000000
--- a/arch/m68k/include/asm/mcfmbus.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************/
-
-/*
- *      mcfmbus.h -- Coldfire MBUS support defines.
- *
- *      (C) Copyright 1999, Martin Floeer (mfloeer@axcent.de) 
- */
-
-/****************************************************************************/
-
-
-#ifndef mcfmbus_h
-#define mcfmbus_h
-
-
-#define MCFMBUS_BASE		0x280
-#define MCFMBUS_IRQ_VECTOR	0x19
-#define MCFMBUS_IRQ		0x1
-#define MCFMBUS_CLK		0x3f
-#define MCFMBUS_IRQ_LEVEL	0x07	/*IRQ Level 1*/
-#define MCFMBUS_ADDRESS		0x01
-
-
-/*
-*	Define the 5307 MBUS register set addresses
-*/
-
-#define MCFMBUS_MADR	0x00
-#define MCFMBUS_MFDR	0x04
-#define MCFMBUS_MBCR	0x08
-#define MCFMBUS_MBSR	0x0C
-#define MCFMBUS_MBDR	0x10
-
-
-#define MCFMBUS_MADR_ADDR(a)	(((a)&0x7F)<<0x01) /*Slave Address*/
-
-#define MCFMBUS_MFDR_MBC(a)	((a)&0x3F)	   /*M-Bus Clock*/
-
-/*
-*	Define bit flags in Control Register
-*/
-
-#define MCFMBUS_MBCR_MEN           (0x80)  /* M-Bus Enable                 */
-#define MCFMBUS_MBCR_MIEN          (0x40)  /* M-Bus Interrupt Enable       */
-#define MCFMBUS_MBCR_MSTA          (0x20)  /* Master/Slave Mode Select Bit */
-#define MCFMBUS_MBCR_MTX           (0x10)  /* Transmit/Rcv Mode Select Bit */
-#define MCFMBUS_MBCR_TXAK          (0x08)  /* Transmit Acknowledge Enable  */
-#define MCFMBUS_MBCR_RSTA          (0x04)  /* Repeat Start                 */
-
-/*
-*	Define bit flags in Status Register
-*/
-
-#define MCFMBUS_MBSR_MCF           (0x80)  /* Data Transfer Complete       */
-#define MCFMBUS_MBSR_MAAS          (0x40)  /* Addressed as a Slave         */
-#define MCFMBUS_MBSR_MBB           (0x20)  /* Bus Busy                     */
-#define MCFMBUS_MBSR_MAL           (0x10)  /* Arbitration Lost             */
-#define MCFMBUS_MBSR_SRW           (0x04)  /* Slave Transmit               */
-#define MCFMBUS_MBSR_MIF           (0x02)  /* M-Bus Interrupt              */
-#define MCFMBUS_MBSR_RXAK          (0x01)  /* No Acknowledge Received      */
-
-/*
-*	Define bit flags in DATA I/O Register
-*/
-
-#define MCFMBUS_MBDR_READ          (0x01)  /* 1=read 0=write MBUS */
-
-#define MBUSIOCSCLOCK		1
-#define MBUSIOCGCLOCK		2
-#define MBUSIOCSADDR			3
-#define MBUSIOCGADDR			4
-#define MBUSIOCSSLADDR			5
-#define MBUSIOCGSLADDR			6
-#define MBUSIOCSSUBADDR			7
-#define MBUSIOCGSUBADDR			8
-
-#endif
diff --git a/arch/m68k/include/asm/mcfne.h b/arch/m68k/include/asm/mcfne.h
deleted file mode 100644
index bf638be..0000000
--- a/arch/m68k/include/asm/mcfne.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/****************************************************************************/
-
-/*
- *	mcfne.h -- NE2000 in ColdFire eval boards.
- *
- *	(C) Copyright 1999-2000, Greg Ungerer (gerg@snapgear.com)
- *	(C) Copyright 2000,      Lineo (www.lineo.com)
- *	(C) Copyright 2001,      SnapGear (www.snapgear.com)
- *
- *      19990409 David W. Miller  Converted from m5206ne.h for 5307 eval board
- *
- *      Hacked support for m5206e Cadre III evaluation board
- *      Fred Stevens (fred.stevens@pemstar.com) 13 April 1999
- */
-
-/****************************************************************************/
-#ifndef	mcfne_h
-#define	mcfne_h
-/****************************************************************************/
-
-
-/*
- *	Support for NE2000 clones devices in ColdFire based boards.
- *	Not all boards address these parts the same way, some use a
- *	direct addressing method, others use a side-band address space
- *	to access odd address registers, some require byte swapping
- *	others do not.
- */
-#define	BSWAP(w)	(((w) << 8) | ((w) >> 8))
-#define	RSWAP(w)	(w)
-
-
-/*
- *	Define the basic hardware resources of NE2000 boards.
- */
-
-#if defined(CONFIG_ARN5206)
-#define NE2000_ADDR		0x40000300
-#define NE2000_ODDOFFSET	0x00010000
-#define	NE2000_IRQ_VECTOR	0xf0
-#define	NE2000_IRQ_PRIORITY	2
-#define	NE2000_IRQ_LEVEL	4
-#define	NE2000_BYTE		volatile unsigned short
-#endif
-
-#if defined(CONFIG_M5206eC3)
-#define	NE2000_ADDR		0x40000300
-#define	NE2000_ODDOFFSET	0x00010000
-#define	NE2000_IRQ_VECTOR	0x1c
-#define	NE2000_IRQ_PRIORITY	2
-#define	NE2000_IRQ_LEVEL	4
-#define	NE2000_BYTE		volatile unsigned short
-#endif
-
-#if defined(CONFIG_M5206e) && defined(CONFIG_NETtel)
-#define NE2000_ADDR		0x30000300
-#define NE2000_IRQ_VECTOR	25
-#define NE2000_IRQ_PRIORITY	1
-#define NE2000_IRQ_LEVEL	3
-#define	NE2000_BYTE		volatile unsigned char
-#endif
-
-#if defined(CONFIG_M5307C3)
-#define NE2000_ADDR		0x40000300
-#define NE2000_ODDOFFSET	0x00010000
-#define NE2000_IRQ_VECTOR	0x1b
-#define	NE2000_BYTE		volatile unsigned short
-#endif
-
-#if defined(CONFIG_M5272) && defined(CONFIG_NETtel)
-#define NE2000_ADDR		0x30600300
-#define NE2000_ODDOFFSET	0x00008000
-#define NE2000_IRQ_VECTOR	67
-#undef	BSWAP
-#define	BSWAP(w)		(w)
-#define	NE2000_BYTE		volatile unsigned short
-#undef	RSWAP
-#define	RSWAP(w)		(((w) << 8) | ((w) >> 8))
-#endif
-
-#if defined(CONFIG_M5307) && defined(CONFIG_NETtel)
-#define NE2000_ADDR0		0x30600300
-#define NE2000_ADDR1		0x30800300
-#define NE2000_ODDOFFSET	0x00008000
-#define NE2000_IRQ_VECTOR0	27
-#define NE2000_IRQ_VECTOR1	29
-#undef	BSWAP
-#define	BSWAP(w)		(w)
-#define	NE2000_BYTE		volatile unsigned short
-#undef	RSWAP
-#define	RSWAP(w)		(((w) << 8) | ((w) >> 8))
-#endif
-
-#if defined(CONFIG_M5307) && defined(CONFIG_SECUREEDGEMP3)
-#define NE2000_ADDR		0x30600300
-#define NE2000_ODDOFFSET	0x00008000
-#define NE2000_IRQ_VECTOR	27
-#undef	BSWAP
-#define	BSWAP(w)		(w)
-#define	NE2000_BYTE		volatile unsigned short
-#undef	RSWAP
-#define	RSWAP(w)		(((w) << 8) | ((w) >> 8))
-#endif
-
-#if defined(CONFIG_ARN5307)
-#define NE2000_ADDR		0xfe600300
-#define NE2000_ODDOFFSET	0x00010000
-#define NE2000_IRQ_VECTOR	0x1b
-#define NE2000_IRQ_PRIORITY	2
-#define NE2000_IRQ_LEVEL	3
-#define	NE2000_BYTE		volatile unsigned short
-#endif
-
-#if defined(CONFIG_M5407C3)
-#define NE2000_ADDR		0x40000300
-#define NE2000_ODDOFFSET	0x00010000
-#define NE2000_IRQ_VECTOR	0x1b
-#define	NE2000_BYTE		volatile unsigned short
-#endif
-
-/****************************************************************************/
-
-/*
- *	Side-band address space for odd address requires re-mapping
- *	many of the standard ISA access functions.
- */
-#ifdef NE2000_ODDOFFSET
-
-#undef outb
-#undef outb_p
-#undef inb
-#undef inb_p
-#undef outsb
-#undef outsw
-#undef insb
-#undef insw
-
-#define	outb	ne2000_outb
-#define	inb	ne2000_inb
-#define	outb_p	ne2000_outb
-#define	inb_p	ne2000_inb
-#define	outsb	ne2000_outsb
-#define	outsw	ne2000_outsw
-#define	insb	ne2000_insb
-#define	insw	ne2000_insw
-
-
-#ifndef COLDFIRE_NE2000_FUNCS
-
-void ne2000_outb(unsigned int val, unsigned int addr);
-int  ne2000_inb(unsigned int addr);
-void ne2000_insb(unsigned int addr, void *vbuf, int unsigned long len);
-void ne2000_insw(unsigned int addr, void *vbuf, unsigned long len);
-void ne2000_outsb(unsigned int addr, void *vbuf, unsigned long len);
-void ne2000_outsw(unsigned int addr, void *vbuf, unsigned long len);
-
-#else
-
-/*
- *	This macro converts a conventional register address into the
- *	real memory pointer of the mapped NE2000 device.
- *	On most NE2000 implementations on ColdFire boards the chip is
- *	mapped in kinda funny, due to its ISA heritage.
- */
-#define	NE2000_PTR(addr)	((addr&0x1)?(NE2000_ODDOFFSET+addr-1):(addr))
-#define	NE2000_DATA_PTR(addr)	(addr)
-
-
-void ne2000_outb(unsigned int val, unsigned int addr)
-{
-	NE2000_BYTE	*rp;
-
-	rp = (NE2000_BYTE *) NE2000_PTR(addr);
-	*rp = RSWAP(val);
-}
-
-int ne2000_inb(unsigned int addr)
-{
-	NE2000_BYTE	*rp, val;
-
-	rp = (NE2000_BYTE *) NE2000_PTR(addr);
-	val = *rp;
-	return((int) ((NE2000_BYTE) RSWAP(val)));
-}
-
-void ne2000_insb(unsigned int addr, void *vbuf, int unsigned long len)
-{
-	NE2000_BYTE	*rp, val;
-	unsigned char	*buf;
-
-	buf = (unsigned char *) vbuf;
-	rp = (NE2000_BYTE *) NE2000_DATA_PTR(addr);
-	for (; (len > 0); len--) {
-		val = *rp;
-		*buf++ = RSWAP(val);
-	}
-}
-
-void ne2000_insw(unsigned int addr, void *vbuf, unsigned long len)
-{
-	volatile unsigned short	*rp;
-	unsigned short		w, *buf;
-
-	buf = (unsigned short *) vbuf;
-	rp = (volatile unsigned short *) NE2000_DATA_PTR(addr);
-	for (; (len > 0); len--) {
-		w = *rp;
-		*buf++ = BSWAP(w);
-	}
-}
-
-void ne2000_outsb(unsigned int addr, const void *vbuf, unsigned long len)
-{
-	NE2000_BYTE	*rp, val;
-	unsigned char	*buf;
-
-	buf = (unsigned char *) vbuf;
-	rp = (NE2000_BYTE *) NE2000_DATA_PTR(addr);
-	for (; (len > 0); len--) {
-		val = *buf++;
-		*rp = RSWAP(val);
-	}
-}
-
-void ne2000_outsw(unsigned int addr, const void *vbuf, unsigned long len)
-{
-	volatile unsigned short	*rp;
-	unsigned short		w, *buf;
-
-	buf = (unsigned short *) vbuf;
-	rp = (volatile unsigned short *) NE2000_DATA_PTR(addr);
-	for (; (len > 0); len--) {
-		w = *buf++;
-		*rp = BSWAP(w);
-	}
-}
-
-#endif /* COLDFIRE_NE2000_FUNCS */
-#endif /* NE2000_OFFOFFSET */
-
-/****************************************************************************/
-#endif	/* mcfne_h */
diff --git a/arch/m68k/include/asm/mcfsim.h b/arch/m68k/include/asm/mcfsim.h
index ebd0304..7a83e61 100644
--- a/arch/m68k/include/asm/mcfsim.h
+++ b/arch/m68k/include/asm/mcfsim.h
@@ -27,6 +27,9 @@
 #elif defined(CONFIG_M5249)
 #include <asm/m5249sim.h>
 #include <asm/mcfintc.h>
+#elif defined(CONFIG_M525x)
+#include <asm/m525xsim.h>
+#include <asm/mcfintc.h>
 #elif defined(CONFIG_M527x)
 #include <asm/m527xsim.h>
 #elif defined(CONFIG_M5272)
@@ -43,6 +46,8 @@
 #include <asm/mcfintc.h>
 #elif defined(CONFIG_M54xx)
 #include <asm/m54xxsim.h>
+#elif defined(CONFIG_M5441x)
+#include <asm/m5441xsim.h>
 #endif
 
 /****************************************************************************/
diff --git a/arch/m68k/include/asm/mcftimer.h b/arch/m68k/include/asm/mcftimer.h
index 351c272..da2fa43 100644
--- a/arch/m68k/include/asm/mcftimer.h
+++ b/arch/m68k/include/asm/mcftimer.h
@@ -19,7 +19,7 @@
 #define	MCFTIMER_TRR		0x04		/* Timer Reference (r/w) */
 #define	MCFTIMER_TCR		0x08		/* Timer Capture reg (r/w) */
 #define	MCFTIMER_TCN		0x0C		/* Timer Counter reg (r/w) */
-#if defined(CONFIG_M532x)
+#if defined(CONFIG_M532x) || defined(CONFIG_M5441x)
 #define	MCFTIMER_TER		0x03		/* Timer Event reg (r/w) */
 #else
 #define	MCFTIMER_TER		0x11		/* Timer Event reg (r/w) */
diff --git a/arch/m68k/include/asm/mcfuart.h b/arch/m68k/include/asm/mcfuart.h
index 2d3bc77..b40c20f 100644
--- a/arch/m68k/include/asm/mcfuart.h
+++ b/arch/m68k/include/asm/mcfuart.h
@@ -43,8 +43,8 @@ struct mcf_platform_uart {
 #define	MCFUART_UFPD		0x30		/* Frac Prec. Divider (r/w) */
 #endif
 #if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
-        defined(CONFIG_M5249) || defined(CONFIG_M5307) || \
-        defined(CONFIG_M5407)
+	defined(CONFIG_M5249) || defined(CONFIG_M525x) || \
+	defined(CONFIG_M5307) || defined(CONFIG_M5407)
 #define	MCFUART_UIVR		0x30		/* Interrupt Vector (r/w) */
 #endif
 #define	MCFUART_UIPR		0x34		/* Input Port (r) */
diff --git a/arch/m68k/include/asm/mman.h b/arch/m68k/include/asm/mman.h
deleted file mode 100644
index 8eebf89..0000000
--- a/arch/m68k/include/asm/mman.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/mman.h>
diff --git a/arch/m68k/include/asm/mutex.h b/arch/m68k/include/asm/mutex.h
deleted file mode 100644
index 458c1f7..0000000
--- a/arch/m68k/include/asm/mutex.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Pull in the generic implementation for the mutex fastpath.
- *
- * TODO: implement optimized primitives instead, or leave the generic
- * implementation in place, or pick the atomic_xchg() based generic
- * implementation. (see asm-generic/mutex-xchg.h for details)
- */
-
-#include <asm-generic/mutex-dec.h>
diff --git a/arch/m68k/include/asm/percpu.h b/arch/m68k/include/asm/percpu.h
deleted file mode 100644
index 0859d04..0000000
--- a/arch/m68k/include/asm/percpu.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_M68K_PERCPU_H
-#define __ASM_M68K_PERCPU_H
-
-#include <asm-generic/percpu.h>
-
-#endif	/* __ASM_M68K_PERCPU_H */
diff --git a/arch/m68k/include/asm/pinmux.h b/arch/m68k/include/asm/pinmux.h
deleted file mode 100644
index 119ee68..0000000
--- a/arch/m68k/include/asm/pinmux.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Coldfire generic GPIO pinmux support.
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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.
- */
-
-#ifndef pinmux_h
-#define pinmux_h
-
-#define MCFPINMUX_NONE		-1
-
-extern int mcf_pinmux_request(unsigned, unsigned);
-extern void mcf_pinmux_release(unsigned, unsigned);
-
-static inline int mcf_pinmux_is_valid(unsigned pinmux)
-{
-	return pinmux != MCFPINMUX_NONE;
-}
-
-#endif
-
diff --git a/arch/m68k/include/asm/resource.h b/arch/m68k/include/asm/resource.h
deleted file mode 100644
index e7d3501..0000000
--- a/arch/m68k/include/asm/resource.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_RESOURCE_H
-#define _M68K_RESOURCE_H
-
-#include <asm-generic/resource.h>
-
-#endif /* _M68K_RESOURCE_H */
diff --git a/arch/m68k/include/asm/sbus.h b/arch/m68k/include/asm/sbus.h
deleted file mode 100644
index bfe3ba1..0000000
--- a/arch/m68k/include/asm/sbus.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * some sbus structures and macros to make usage of sbus drivers possible
- */
-
-#ifndef __M68K_SBUS_H
-#define __M68K_SBUS_H
-
-struct sbus_dev {
-	struct {
-		unsigned int which_io;
-		unsigned int phys_addr;
-	} reg_addrs[1];
-};
-
-/* sbus IO functions stolen from include/asm-sparc/io.h for the serial driver */
-/* No SBUS on the Sun3, kludge -- sam */
-
-static inline void _sbus_writeb(unsigned char val, unsigned long addr)
-{
-	*(volatile unsigned char *)addr = val;
-}
-
-static inline unsigned char _sbus_readb(unsigned long addr)
-{
-	return *(volatile unsigned char *)addr;
-}
-
-static inline void _sbus_writel(unsigned long val, unsigned long addr)
-{
-	*(volatile unsigned long *)addr = val;
-
-}
-
-extern inline unsigned long _sbus_readl(unsigned long addr)
-{
-	return *(volatile unsigned long *)addr;
-}
-
-
-#define sbus_readb(a) _sbus_readb((unsigned long)a)
-#define sbus_writeb(v, a) _sbus_writeb(v, (unsigned long)a)
-#define sbus_readl(a) _sbus_readl((unsigned long)a)
-#define sbus_writel(v, a) _sbus_writel(v, (unsigned long)a)
-
-#endif
diff --git a/arch/m68k/include/asm/scatterlist.h b/arch/m68k/include/asm/scatterlist.h
deleted file mode 100644
index 3125054..0000000
--- a/arch/m68k/include/asm/scatterlist.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_SCATTERLIST_H
-#define _M68K_SCATTERLIST_H
-
-#include <asm-generic/scatterlist.h>
-
-#endif /* !(_M68K_SCATTERLIST_H) */
diff --git a/arch/m68k/include/asm/siginfo.h b/arch/m68k/include/asm/siginfo.h
deleted file mode 100644
index 851d3d7..0000000
--- a/arch/m68k/include/asm/siginfo.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_SIGINFO_H
-#define _M68K_SIGINFO_H
-
-#include <asm-generic/siginfo.h>
-
-#endif
diff --git a/arch/m68k/include/asm/statfs.h b/arch/m68k/include/asm/statfs.h
deleted file mode 100644
index 08d93f1..0000000
--- a/arch/m68k/include/asm/statfs.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_STATFS_H
-#define _M68K_STATFS_H
-
-#include <asm-generic/statfs.h>
-
-#endif /* _M68K_STATFS_H */
diff --git a/arch/m68k/include/asm/topology.h b/arch/m68k/include/asm/topology.h
deleted file mode 100644
index ca173e9..0000000
--- a/arch/m68k/include/asm/topology.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_M68K_TOPOLOGY_H
-#define _ASM_M68K_TOPOLOGY_H
-
-#include <asm-generic/topology.h>
-
-#endif /* _ASM_M68K_TOPOLOGY_H */
diff --git a/arch/m68k/include/asm/types.h b/arch/m68k/include/asm/types.h
deleted file mode 100644
index 89705ad..0000000
--- a/arch/m68k/include/asm/types.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _M68K_TYPES_H
-#define _M68K_TYPES_H
-
-/*
- * This file is never included by application software unless
- * explicitly requested (e.g., via linux/types.h) in which case the
- * application is Linux specific so (user-) name space pollution is
- * not a major issue.  However, for interoperability, libraries still
- * need to be careful to avoid a name clashes.
- */
-#include <asm-generic/int-ll64.h>
-
-/*
- * These aren't exported outside the kernel to avoid name space clashes
- */
-#ifdef __KERNEL__
-
-#define BITS_PER_LONG 32
-
-#endif /* __KERNEL__ */
-
-#endif /* _M68K_TYPES_H */
diff --git a/arch/m68k/include/asm/unaligned.h b/arch/m68k/include/asm/unaligned.h
index f4043ae..2b3ca0b 100644
--- a/arch/m68k/include/asm/unaligned.h
+++ b/arch/m68k/include/asm/unaligned.h
@@ -2,7 +2,7 @@
 #define _ASM_M68K_UNALIGNED_H
 
 
-#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68000)
+#ifdef CONFIG_CPU_HAS_NO_UNALIGNED
 #include <linux/unaligned/be_struct.h>
 #include <linux/unaligned/le_byteshift.h>
 #include <linux/unaligned/generic.h>
@@ -12,7 +12,7 @@
 
 #else
 /*
- * The m68k can do unaligned accesses itself. 
+ * The m68k can do unaligned accesses itself.
  */
 #include <linux/unaligned/access_ok.h>
 #include <linux/unaligned/generic.h>
diff --git a/arch/m68k/include/asm/xor.h b/arch/m68k/include/asm/xor.h
deleted file mode 100644
index c82eb12..0000000
--- a/arch/m68k/include/asm/xor.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/xor.h>
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index b8daf64..165ee9f 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -1,5 +1,451 @@
-#if defined(CONFIG_MMU) && !defined(CONFIG_COLDFIRE)
-#include "entry_mm.S"
+/* -*- mode: asm -*-
+ *
+ *  linux/arch/m68k/kernel/entry.S
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * Linux/m68k support by Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
+ *
+ */
+
+/*
+ * entry.S  contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ */
+
+/*
+ * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so
+ *               all pointers that used to be 'current' are now entry
+ *               number 0 in the 'current_set' list.
+ *
+ *  6/05/00 RZ:	 addedd writeback completion after return from sighandler
+ *		 for 68040
+ */
+
+#include <linux/linkage.h>
+#include <asm/errno.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/traps.h>
+#include <asm/unistd.h>
+#include <asm/asm-offsets.h>
+#include <asm/entry.h>
+
+.globl system_call, buserr, trap, resume
+.globl sys_call_table
+.globl sys_fork, sys_clone, sys_vfork
+.globl ret_from_interrupt, bad_interrupt
+.globl auto_irqhandler_fixup
+.globl user_irqvec_fixup
+
+.text
+ENTRY(sys_fork)
+	SAVE_SWITCH_STACK
+	pea	%sp@(SWITCH_STACK_SIZE)
+	jbsr	m68k_fork
+	addql	#4,%sp
+	RESTORE_SWITCH_STACK
+	rts
+
+ENTRY(sys_clone)
+	SAVE_SWITCH_STACK
+	pea	%sp@(SWITCH_STACK_SIZE)
+	jbsr	m68k_clone
+	addql	#4,%sp
+	RESTORE_SWITCH_STACK
+	rts
+
+ENTRY(sys_vfork)
+	SAVE_SWITCH_STACK
+	pea	%sp@(SWITCH_STACK_SIZE)
+	jbsr	m68k_vfork
+	addql	#4,%sp
+	RESTORE_SWITCH_STACK
+	rts
+
+ENTRY(sys_sigreturn)
+	SAVE_SWITCH_STACK
+	jbsr	do_sigreturn
+	RESTORE_SWITCH_STACK
+	rts
+
+ENTRY(sys_rt_sigreturn)
+	SAVE_SWITCH_STACK
+	jbsr	do_rt_sigreturn
+	RESTORE_SWITCH_STACK
+	rts
+
+ENTRY(buserr)
+	SAVE_ALL_INT
+	GET_CURRENT(%d0)
+	movel	%sp,%sp@-		| stack frame pointer argument
+	jbsr	buserr_c
+	addql	#4,%sp
+	jra	ret_from_exception
+
+ENTRY(trap)
+	SAVE_ALL_INT
+	GET_CURRENT(%d0)
+	movel	%sp,%sp@-		| stack frame pointer argument
+	jbsr	trap_c
+	addql	#4,%sp
+	jra	ret_from_exception
+
+	| After a fork we jump here directly from resume,
+	| so that %d1 contains the previous task
+	| schedule_tail now used regardless of CONFIG_SMP
+ENTRY(ret_from_fork)
+	movel	%d1,%sp@-
+	jsr	schedule_tail
+	addql	#4,%sp
+	jra	ret_from_exception
+
+#if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU)
+
+#ifdef TRAP_DBG_INTERRUPT
+
+.globl dbginterrupt
+ENTRY(dbginterrupt)
+	SAVE_ALL_INT
+	GET_CURRENT(%d0)
+	movel	%sp,%sp@- 		/* stack frame pointer argument */
+	jsr	dbginterrupt_c
+	addql	#4,%sp
+	jra	ret_from_exception
+#endif
+
+ENTRY(reschedule)
+	/* save top of frame */
+	pea	%sp@
+	jbsr	set_esp0
+	addql	#4,%sp
+	pea	ret_from_exception
+	jmp	schedule
+
+ENTRY(ret_from_user_signal)
+	moveq #__NR_sigreturn,%d0
+	trap #0
+
+ENTRY(ret_from_user_rt_signal)
+	movel #__NR_rt_sigreturn,%d0
+	trap #0
+
 #else
-#include "entry_no.S"
+
+do_trace_entry:
+	movel	#-ENOSYS,%sp@(PT_OFF_D0)| needed for strace
+	subql	#4,%sp
+	SAVE_SWITCH_STACK
+	jbsr	syscall_trace
+	RESTORE_SWITCH_STACK
+	addql	#4,%sp
+	movel	%sp@(PT_OFF_ORIG_D0),%d0
+	cmpl	#NR_syscalls,%d0
+	jcs	syscall
+badsys:
+	movel	#-ENOSYS,%sp@(PT_OFF_D0)
+	jra	ret_from_syscall
+
+do_trace_exit:
+	subql	#4,%sp
+	SAVE_SWITCH_STACK
+	jbsr	syscall_trace
+	RESTORE_SWITCH_STACK
+	addql	#4,%sp
+	jra	.Lret_from_exception
+
+ENTRY(ret_from_signal)
+	movel	%curptr@(TASK_STACK),%a1
+	tstb	%a1@(TINFO_FLAGS+2)
+	jge	1f
+	jbsr	syscall_trace
+1:	RESTORE_SWITCH_STACK
+	addql	#4,%sp
+/* on 68040 complete pending writebacks if any */
+#ifdef CONFIG_M68040
+	bfextu	%sp@(PT_OFF_FORMATVEC){#0,#4},%d0
+	subql	#7,%d0				| bus error frame ?
+	jbne	1f
+	movel	%sp,%sp@-
+	jbsr	berr_040cleanup
+	addql	#4,%sp
+1:
+#endif
+	jra	.Lret_from_exception
+
+ENTRY(system_call)
+	SAVE_ALL_SYS
+
+	GET_CURRENT(%d1)
+	movel	%d1,%a1
+
+	| save top of frame
+	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
+
+	| syscall trace?
+	tstb	%a1@(TINFO_FLAGS+2)
+	jmi	do_trace_entry
+	cmpl	#NR_syscalls,%d0
+	jcc	badsys
+syscall:
+	jbsr	@(sys_call_table,%d0:l:4)@(0)
+	movel	%d0,%sp@(PT_OFF_D0)	| save the return value
+ret_from_syscall:
+	|oriw	#0x0700,%sr
+	movel	%curptr@(TASK_STACK),%a1
+	movew	%a1@(TINFO_FLAGS+2),%d0
+	jne	syscall_exit_work
+1:	RESTORE_ALL
+
+syscall_exit_work:
+	btst	#5,%sp@(PT_OFF_SR)	| check if returning to kernel
+	bnes	1b			| if so, skip resched, signals
+	lslw	#1,%d0
+	jcs	do_trace_exit
+	jmi	do_delayed_trace
+	lslw	#8,%d0
+	jne	do_signal_return
+	pea	resume_userspace
+	jra	schedule
+
+
+ENTRY(ret_from_exception)
+.Lret_from_exception:
+	btst	#5,%sp@(PT_OFF_SR)	| check if returning to kernel
+	bnes	1f			| if so, skip resched, signals
+	| only allow interrupts when we are really the last one on the
+	| kernel stack, otherwise stack overflow can occur during
+	| heavy interrupt load
+	andw	#ALLOWINT,%sr
+
+resume_userspace:
+	movel	%curptr@(TASK_STACK),%a1
+	moveb	%a1@(TINFO_FLAGS+3),%d0
+	jne	exit_work
+1:	RESTORE_ALL
+
+exit_work:
+	| save top of frame
+	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
+	lslb	#1,%d0
+	jne	do_signal_return
+	pea	resume_userspace
+	jra	schedule
+
+
+do_signal_return:
+	|andw	#ALLOWINT,%sr
+	subql	#4,%sp			| dummy return address
+	SAVE_SWITCH_STACK
+	pea	%sp@(SWITCH_STACK_SIZE)
+	bsrl	do_notify_resume
+	addql	#4,%sp
+	RESTORE_SWITCH_STACK
+	addql	#4,%sp
+	jbra	resume_userspace
+
+do_delayed_trace:
+	bclr	#7,%sp@(PT_OFF_SR)	| clear trace bit in SR
+	pea	1			| send SIGTRAP
+	movel	%curptr,%sp@-
+	pea	LSIGTRAP
+	jbsr	send_sig
+	addql	#8,%sp
+	addql	#4,%sp
+	jbra	resume_userspace
+
+
+/* This is the main interrupt handler for autovector interrupts */
+
+ENTRY(auto_inthandler)
+	SAVE_ALL_INT
+	GET_CURRENT(%d0)
+	movel	%d0,%a1
+	addqb	#1,%a1@(TINFO_PREEMPT+1)
+					|  put exception # in d0
+	bfextu	%sp@(PT_OFF_FORMATVEC){#4,#10},%d0
+	subw	#VEC_SPUR,%d0
+
+	movel	%sp,%sp@-
+	movel	%d0,%sp@-		|  put vector # on stack
+auto_irqhandler_fixup = . + 2
+	jsr	do_IRQ			|  process the IRQ
+	addql	#8,%sp			|  pop parameters off stack
+
+ret_from_interrupt:
+	movel	%curptr@(TASK_STACK),%a1
+	subqb	#1,%a1@(TINFO_PREEMPT+1)
+	jeq	ret_from_last_interrupt
+2:	RESTORE_ALL
+
+	ALIGN
+ret_from_last_interrupt:
+	moveq	#(~ALLOWINT>>8)&0xff,%d0
+	andb	%sp@(PT_OFF_SR),%d0
+	jne	2b
+
+	/* check if we need to do software interrupts */
+	tstl	irq_stat+CPUSTAT_SOFTIRQ_PENDING
+	jeq	.Lret_from_exception
+	pea	ret_from_exception
+	jra	do_softirq
+
+/* Handler for user defined interrupt vectors */
+
+ENTRY(user_inthandler)
+	SAVE_ALL_INT
+	GET_CURRENT(%d0)
+	movel	%d0,%a1
+	addqb	#1,%a1@(TINFO_PREEMPT+1)
+					|  put exception # in d0
+	bfextu	%sp@(PT_OFF_FORMATVEC){#4,#10},%d0
+user_irqvec_fixup = . + 2
+	subw	#VEC_USER,%d0
+
+	movel	%sp,%sp@-
+	movel	%d0,%sp@-		|  put vector # on stack
+	jsr	do_IRQ			|  process the IRQ
+	addql	#8,%sp			|  pop parameters off stack
+
+	movel	%curptr@(TASK_STACK),%a1
+	subqb	#1,%a1@(TINFO_PREEMPT+1)
+	jeq	ret_from_last_interrupt
+	RESTORE_ALL
+
+/* Handler for uninitialized and spurious interrupts */
+
+ENTRY(bad_inthandler)
+	SAVE_ALL_INT
+	GET_CURRENT(%d0)
+	movel	%d0,%a1
+	addqb	#1,%a1@(TINFO_PREEMPT+1)
+
+	movel	%sp,%sp@-
+	jsr	handle_badint
+	addql	#4,%sp
+
+	movel	%curptr@(TASK_STACK),%a1
+	subqb	#1,%a1@(TINFO_PREEMPT+1)
+	jeq	ret_from_last_interrupt
+	RESTORE_ALL
+
+
+resume:
+	/*
+	 * Beware - when entering resume, prev (the current task) is
+	 * in a0, next (the new task) is in a1,so don't change these
+	 * registers until their contents are no longer needed.
+	 */
+
+	/* save sr */
+	movew	%sr,%a0@(TASK_THREAD+THREAD_SR)
+
+	/* save fs (sfc,%dfc) (may be pointing to kernel memory) */
+	movec	%sfc,%d0
+	movew	%d0,%a0@(TASK_THREAD+THREAD_FS)
+
+	/* save usp */
+	/* it is better to use a movel here instead of a movew 8*) */
+	movec	%usp,%d0
+	movel	%d0,%a0@(TASK_THREAD+THREAD_USP)
+
+	/* save non-scratch registers on stack */
+	SAVE_SWITCH_STACK
+
+	/* save current kernel stack pointer */
+	movel	%sp,%a0@(TASK_THREAD+THREAD_KSP)
+
+	/* save floating point context */
+#ifndef CONFIG_M68KFPU_EMU_ONLY
+#ifdef CONFIG_M68KFPU_EMU
+	tstl	m68k_fputype
+	jeq	3f
+#endif
+	fsave	%a0@(TASK_THREAD+THREAD_FPSTATE)
+
+#if defined(CONFIG_M68060)
+#if !defined(CPU_M68060_ONLY)
+	btst	#3,m68k_cputype+3
+	beqs	1f
+#endif
+	/* The 060 FPU keeps status in bits 15-8 of the first longword */
+	tstb	%a0@(TASK_THREAD+THREAD_FPSTATE+2)
+	jeq	3f
+#if !defined(CPU_M68060_ONLY)
+	jra	2f
+#endif
+#endif /* CONFIG_M68060 */
+#if !defined(CPU_M68060_ONLY)
+1:	tstb	%a0@(TASK_THREAD+THREAD_FPSTATE)
+	jeq	3f
+#endif
+2:	fmovemx	%fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
+	fmoveml	%fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
+3:
+#endif	/* CONFIG_M68KFPU_EMU_ONLY */
+	/* Return previous task in %d1 */
+	movel	%curptr,%d1
+
+	/* switch to new task (a1 contains new task) */
+	movel	%a1,%curptr
+
+	/* restore floating point context */
+#ifndef CONFIG_M68KFPU_EMU_ONLY
+#ifdef CONFIG_M68KFPU_EMU
+	tstl	m68k_fputype
+	jeq	4f
+#endif
+#if defined(CONFIG_M68060)
+#if !defined(CPU_M68060_ONLY)
+	btst	#3,m68k_cputype+3
+	beqs	1f
+#endif
+	/* The 060 FPU keeps status in bits 15-8 of the first longword */
+	tstb	%a1@(TASK_THREAD+THREAD_FPSTATE+2)
+	jeq	3f
+#if !defined(CPU_M68060_ONLY)
+	jra	2f
+#endif
+#endif /* CONFIG_M68060 */
+#if !defined(CPU_M68060_ONLY)
+1:	tstb	%a1@(TASK_THREAD+THREAD_FPSTATE)
+	jeq	3f
 #endif
+2:	fmovemx	%a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
+	fmoveml	%a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
+3:	frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
+4:
+#endif	/* CONFIG_M68KFPU_EMU_ONLY */
+
+	/* restore the kernel stack pointer */
+	movel	%a1@(TASK_THREAD+THREAD_KSP),%sp
+
+	/* restore non-scratch registers */
+	RESTORE_SWITCH_STACK
+
+	/* restore user stack pointer */
+	movel	%a1@(TASK_THREAD+THREAD_USP),%a0
+	movel	%a0,%usp
+
+	/* restore fs (sfc,%dfc) */
+	movew	%a1@(TASK_THREAD+THREAD_FS),%a0
+	movec	%a0,%sfc
+	movec	%a0,%dfc
+
+	/* restore status register */
+	movew	%a1@(TASK_THREAD+THREAD_SR),%sr
+
+	rts
+
+#endif /* CONFIG_MMU && !CONFIG_COLDFIRE */
diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S
deleted file mode 100644
index f29e73c..0000000
--- a/arch/m68k/kernel/entry_mm.S
+++ /dev/null
@@ -1,419 +0,0 @@
-/* -*- mode: asm -*-
- *
- *  linux/arch/m68k/kernel/entry.S
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- * Linux/m68k support by Hamish Macdonald
- *
- * 68060 fixes by Jesper Skov
- *
- */
-
-/*
- * entry.S  contains the system-call and fault low-level handling routines.
- * This also contains the timer-interrupt handler, as well as all interrupts
- * and faults that can result in a task-switch.
- *
- * NOTE: This code handles signal-recognition, which happens every time
- * after a timer-interrupt and after each system call.
- *
- */
-
-/*
- * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so
- *               all pointers that used to be 'current' are now entry
- *               number 0 in the 'current_set' list.
- *
- *  6/05/00 RZ:	 addedd writeback completion after return from sighandler
- *		 for 68040
- */
-
-#include <linux/linkage.h>
-#include <asm/entry.h>
-#include <asm/errno.h>
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/traps.h>
-#include <asm/unistd.h>
-
-#include <asm/asm-offsets.h>
-
-.globl system_call, buserr, trap, resume
-.globl sys_call_table
-.globl sys_fork, sys_clone, sys_vfork
-.globl ret_from_interrupt, bad_interrupt
-.globl auto_irqhandler_fixup
-.globl user_irqvec_fixup
-
-.text
-ENTRY(buserr)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@-		| stack frame pointer argument
-	bsrl	buserr_c
-	addql	#4,%sp
-	jra	.Lret_from_exception
-
-ENTRY(trap)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@-		| stack frame pointer argument
-	bsrl	trap_c
-	addql	#4,%sp
-	jra	.Lret_from_exception
-
-	| After a fork we jump here directly from resume,
-	| so that %d1 contains the previous task
-	| schedule_tail now used regardless of CONFIG_SMP
-ENTRY(ret_from_fork)
-	movel	%d1,%sp@-
-	jsr	schedule_tail
-	addql	#4,%sp
-	jra	.Lret_from_exception
-
-do_trace_entry:
-	movel	#-ENOSYS,%sp@(PT_OFF_D0)| needed for strace
-	subql	#4,%sp
-	SAVE_SWITCH_STACK
-	jbsr	syscall_trace
-	RESTORE_SWITCH_STACK
-	addql	#4,%sp
-	movel	%sp@(PT_OFF_ORIG_D0),%d0
-	cmpl	#NR_syscalls,%d0
-	jcs	syscall
-badsys:
-	movel	#-ENOSYS,%sp@(PT_OFF_D0)
-	jra	ret_from_syscall
-
-do_trace_exit:
-	subql	#4,%sp
-	SAVE_SWITCH_STACK
-	jbsr	syscall_trace
-	RESTORE_SWITCH_STACK
-	addql	#4,%sp
-	jra	.Lret_from_exception
-
-ENTRY(ret_from_signal)
-	movel	%curptr@(TASK_STACK),%a1
-	tstb	%a1@(TINFO_FLAGS+2)
-	jge	1f
-	jbsr	syscall_trace
-1:	RESTORE_SWITCH_STACK
-	addql	#4,%sp
-/* on 68040 complete pending writebacks if any */
-#ifdef CONFIG_M68040
-	bfextu	%sp@(PT_OFF_FORMATVEC){#0,#4},%d0
-	subql	#7,%d0				| bus error frame ?
-	jbne	1f
-	movel	%sp,%sp@-
-	jbsr	berr_040cleanup
-	addql	#4,%sp
-1:
-#endif
-	jra	.Lret_from_exception
-
-ENTRY(system_call)
-	SAVE_ALL_SYS
-
-	GET_CURRENT(%d1)
-	movel	%d1,%a1
-
-	| save top of frame
-	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
-
-	| syscall trace?
-	tstb	%a1@(TINFO_FLAGS+2)
-	jmi	do_trace_entry
-	cmpl	#NR_syscalls,%d0
-	jcc	badsys
-syscall:
-	jbsr	@(sys_call_table,%d0:l:4)@(0)
-	movel	%d0,%sp@(PT_OFF_D0)	| save the return value
-ret_from_syscall:
-	|oriw	#0x0700,%sr
-	movel	%curptr@(TASK_STACK),%a1
-	movew	%a1@(TINFO_FLAGS+2),%d0
-	jne	syscall_exit_work
-1:	RESTORE_ALL
-
-syscall_exit_work:
-	btst	#5,%sp@(PT_OFF_SR)	| check if returning to kernel
-	bnes	1b			| if so, skip resched, signals
-	lslw	#1,%d0
-	jcs	do_trace_exit
-	jmi	do_delayed_trace
-	lslw	#8,%d0
-	jne	do_signal_return
-	pea	resume_userspace
-	jra	schedule
-
-
-ENTRY(ret_from_exception)
-.Lret_from_exception:
-	btst	#5,%sp@(PT_OFF_SR)	| check if returning to kernel
-	bnes	1f			| if so, skip resched, signals
-	| only allow interrupts when we are really the last one on the
-	| kernel stack, otherwise stack overflow can occur during
-	| heavy interrupt load
-	andw	#ALLOWINT,%sr
-
-resume_userspace:
-	movel	%curptr@(TASK_STACK),%a1
-	moveb	%a1@(TINFO_FLAGS+3),%d0
-	jne	exit_work
-1:	RESTORE_ALL
-
-exit_work:
-	| save top of frame
-	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
-	lslb	#1,%d0
-	jne	do_signal_return
-	pea	resume_userspace
-	jra	schedule
-
-
-do_signal_return:
-	|andw	#ALLOWINT,%sr
-	subql	#4,%sp			| dummy return address
-	SAVE_SWITCH_STACK
-	pea	%sp@(SWITCH_STACK_SIZE)
-	bsrl	do_notify_resume
-	addql	#4,%sp
-	RESTORE_SWITCH_STACK
-	addql	#4,%sp
-	jbra	resume_userspace
-
-do_delayed_trace:
-	bclr	#7,%sp@(PT_OFF_SR)	| clear trace bit in SR
-	pea	1			| send SIGTRAP
-	movel	%curptr,%sp@-
-	pea	LSIGTRAP
-	jbsr	send_sig
-	addql	#8,%sp
-	addql	#4,%sp
-	jbra	resume_userspace
-
-
-/* This is the main interrupt handler for autovector interrupts */
-
-ENTRY(auto_inthandler)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%d0,%a1
-	addqb	#1,%a1@(TINFO_PREEMPT+1)
-					|  put exception # in d0
-	bfextu	%sp@(PT_OFF_FORMATVEC){#4,#10},%d0
-	subw	#VEC_SPUR,%d0
-
-	movel	%sp,%sp@-
-	movel	%d0,%sp@-		|  put vector # on stack
-auto_irqhandler_fixup = . + 2
-	jsr	do_IRQ			|  process the IRQ
-	addql	#8,%sp			|  pop parameters off stack
-
-ret_from_interrupt:
-	movel	%curptr@(TASK_STACK),%a1
-	subqb	#1,%a1@(TINFO_PREEMPT+1)
-	jeq	ret_from_last_interrupt
-2:	RESTORE_ALL
-
-	ALIGN
-ret_from_last_interrupt:
-	moveq	#(~ALLOWINT>>8)&0xff,%d0
-	andb	%sp@(PT_OFF_SR),%d0
-	jne	2b
-
-	/* check if we need to do software interrupts */
-	tstl	irq_stat+CPUSTAT_SOFTIRQ_PENDING
-	jeq	.Lret_from_exception
-	pea	ret_from_exception
-	jra	do_softirq
-
-/* Handler for user defined interrupt vectors */
-
-ENTRY(user_inthandler)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%d0,%a1
-	addqb	#1,%a1@(TINFO_PREEMPT+1)
-					|  put exception # in d0
-	bfextu	%sp@(PT_OFF_FORMATVEC){#4,#10},%d0
-user_irqvec_fixup = . + 2
-	subw	#VEC_USER,%d0
-
-	movel	%sp,%sp@-
-	movel	%d0,%sp@-		|  put vector # on stack
-	jsr	do_IRQ			|  process the IRQ
-	addql	#8,%sp			|  pop parameters off stack
-
-	movel	%curptr@(TASK_STACK),%a1
-	subqb	#1,%a1@(TINFO_PREEMPT+1)
-	jeq	ret_from_last_interrupt
-	RESTORE_ALL
-
-/* Handler for uninitialized and spurious interrupts */
-
-ENTRY(bad_inthandler)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%d0,%a1
-	addqb	#1,%a1@(TINFO_PREEMPT+1)
-
-	movel	%sp,%sp@-
-	jsr	handle_badint
-	addql	#4,%sp
-
-	movel	%curptr@(TASK_STACK),%a1
-	subqb	#1,%a1@(TINFO_PREEMPT+1)
-	jeq	ret_from_last_interrupt
-	RESTORE_ALL
-
-
-ENTRY(sys_fork)
-	SAVE_SWITCH_STACK
-	pea	%sp@(SWITCH_STACK_SIZE)
-	jbsr	m68k_fork
-	addql	#4,%sp
-	RESTORE_SWITCH_STACK
-	rts
-
-ENTRY(sys_clone)
-	SAVE_SWITCH_STACK
-	pea	%sp@(SWITCH_STACK_SIZE)
-	jbsr	m68k_clone
-	addql	#4,%sp
-	RESTORE_SWITCH_STACK
-	rts
-
-ENTRY(sys_vfork)
-	SAVE_SWITCH_STACK
-	pea	%sp@(SWITCH_STACK_SIZE)
-	jbsr	m68k_vfork
-	addql	#4,%sp
-	RESTORE_SWITCH_STACK
-	rts
-
-ENTRY(sys_sigreturn)
-	SAVE_SWITCH_STACK
-	jbsr	do_sigreturn
-	RESTORE_SWITCH_STACK
-	rts
-
-ENTRY(sys_rt_sigreturn)
-	SAVE_SWITCH_STACK
-	jbsr	do_rt_sigreturn
-	RESTORE_SWITCH_STACK
-	rts
-
-resume:
-	/*
-	 * Beware - when entering resume, prev (the current task) is
-	 * in a0, next (the new task) is in a1,so don't change these
-	 * registers until their contents are no longer needed.
-	 */
-
-	/* save sr */
-	movew	%sr,%a0@(TASK_THREAD+THREAD_SR)
-
-	/* save fs (sfc,%dfc) (may be pointing to kernel memory) */
-	movec	%sfc,%d0
-	movew	%d0,%a0@(TASK_THREAD+THREAD_FS)
-
-	/* save usp */
-	/* it is better to use a movel here instead of a movew 8*) */
-	movec	%usp,%d0
-	movel	%d0,%a0@(TASK_THREAD+THREAD_USP)
-
-	/* save non-scratch registers on stack */
-	SAVE_SWITCH_STACK
-
-	/* save current kernel stack pointer */
-	movel	%sp,%a0@(TASK_THREAD+THREAD_KSP)
-
-	/* save floating point context */
-#ifndef CONFIG_M68KFPU_EMU_ONLY
-#ifdef CONFIG_M68KFPU_EMU
-	tstl	m68k_fputype
-	jeq	3f
-#endif
-	fsave	%a0@(TASK_THREAD+THREAD_FPSTATE)
-
-#if defined(CONFIG_M68060)
-#if !defined(CPU_M68060_ONLY)
-	btst	#3,m68k_cputype+3
-	beqs	1f
-#endif
-	/* The 060 FPU keeps status in bits 15-8 of the first longword */
-	tstb	%a0@(TASK_THREAD+THREAD_FPSTATE+2)
-	jeq	3f
-#if !defined(CPU_M68060_ONLY)
-	jra	2f
-#endif
-#endif /* CONFIG_M68060 */
-#if !defined(CPU_M68060_ONLY)
-1:	tstb	%a0@(TASK_THREAD+THREAD_FPSTATE)
-	jeq	3f
-#endif
-2:	fmovemx	%fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
-	fmoveml	%fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
-3:
-#endif	/* CONFIG_M68KFPU_EMU_ONLY */
-	/* Return previous task in %d1 */
-	movel	%curptr,%d1
-
-	/* switch to new task (a1 contains new task) */
-	movel	%a1,%curptr
-
-	/* restore floating point context */
-#ifndef CONFIG_M68KFPU_EMU_ONLY
-#ifdef CONFIG_M68KFPU_EMU
-	tstl	m68k_fputype
-	jeq	4f
-#endif
-#if defined(CONFIG_M68060)
-#if !defined(CPU_M68060_ONLY)
-	btst	#3,m68k_cputype+3
-	beqs	1f
-#endif
-	/* The 060 FPU keeps status in bits 15-8 of the first longword */
-	tstb	%a1@(TASK_THREAD+THREAD_FPSTATE+2)
-	jeq	3f
-#if !defined(CPU_M68060_ONLY)
-	jra	2f
-#endif
-#endif /* CONFIG_M68060 */
-#if !defined(CPU_M68060_ONLY)
-1:	tstb	%a1@(TASK_THREAD+THREAD_FPSTATE)
-	jeq	3f
-#endif
-2:	fmovemx	%a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
-	fmoveml	%a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
-3:	frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
-4:
-#endif	/* CONFIG_M68KFPU_EMU_ONLY */
-
-	/* restore the kernel stack pointer */
-	movel	%a1@(TASK_THREAD+THREAD_KSP),%sp
-
-	/* restore non-scratch registers */
-	RESTORE_SWITCH_STACK
-
-	/* restore user stack pointer */
-	movel	%a1@(TASK_THREAD+THREAD_USP),%a0
-	movel	%a0,%usp
-
-	/* restore fs (sfc,%dfc) */
-	movew	%a1@(TASK_THREAD+THREAD_FS),%a0
-	movec	%a0,%sfc
-	movec	%a0,%dfc
-
-	/* restore status register */
-	movew	%a1@(TASK_THREAD+THREAD_SR),%sr
-
-	rts
-
diff --git a/arch/m68k/kernel/entry_no.S b/arch/m68k/kernel/entry_no.S
deleted file mode 100644
index d80cba4..0000000
--- a/arch/m68k/kernel/entry_no.S
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/entry.S
- *
- *  Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
- *                      Kenneth Albanowski <kjahds@kjahds.com>,
- *  Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
- *
- * Based on:
- *
- *  linux/arch/m68k/kernel/entry.S
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- * Linux/m68k support by Hamish Macdonald
- *
- * 68060 fixes by Jesper Skov
- * ColdFire support by Greg Ungerer (gerg@snapgear.com)
- * 5307 fixes by David W. Miller
- * linux 2.4 support David McCullough <davidm@snapgear.com>
- */
-
-#include <linux/linkage.h>
-#include <asm/errno.h>
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/asm-offsets.h>
-#include <asm/entry.h>
-#include <asm/unistd.h>
-
-.text
-
-.globl buserr
-.globl trap
-.globl ret_from_exception
-.globl ret_from_signal
-.globl sys_fork
-.globl sys_clone
-.globl sys_vfork
-
-ENTRY(buserr)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		/* stack frame pointer argument */
-	jsr	buserr_c
-	addql	#4,%sp
-	jra	ret_from_exception
-
-ENTRY(trap)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		/* stack frame pointer argument */
-	jsr	trap_c
-	addql	#4,%sp
-	jra	ret_from_exception
-
-#ifdef TRAP_DBG_INTERRUPT
-
-.globl dbginterrupt
-ENTRY(dbginterrupt)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		/* stack frame pointer argument */
-	jsr	dbginterrupt_c
-	addql	#4,%sp
-	jra	ret_from_exception
-#endif
-
-ENTRY(reschedule)
-	/* save top of frame */
-	pea	%sp@
-	jbsr	set_esp0
-	addql	#4,%sp
-	pea	ret_from_exception
-	jmp	schedule
-
-ENTRY(ret_from_fork)
-	movel	%d1,%sp@-
-	jsr	schedule_tail
-	addql	#4,%sp
-	jra	ret_from_exception
-
-ENTRY(sys_fork)
-	SAVE_SWITCH_STACK
-	pea	%sp@(SWITCH_STACK_SIZE)
-	jbsr	m68k_fork
-	addql	#4,%sp
-	RESTORE_SWITCH_STACK
-	rts
-
-ENTRY(sys_vfork)
-	SAVE_SWITCH_STACK
-	pea	%sp@(SWITCH_STACK_SIZE)
-	jbsr	m68k_vfork
-	addql	#4,%sp
-	RESTORE_SWITCH_STACK
-	rts
-
-ENTRY(sys_clone)
-	SAVE_SWITCH_STACK
-	pea	%sp@(SWITCH_STACK_SIZE)
-	jbsr	m68k_clone
-	addql	#4,%sp
-	RESTORE_SWITCH_STACK
-	rts
-
-ENTRY(sys_sigreturn)
-	SAVE_SWITCH_STACK
-	jbsr	do_sigreturn
-	RESTORE_SWITCH_STACK
-	rts
-
-ENTRY(sys_rt_sigreturn)
-	SAVE_SWITCH_STACK
-	jbsr	do_rt_sigreturn
-	RESTORE_SWITCH_STACK
-	rts
-
-ENTRY(ret_from_user_signal)
-	moveq #__NR_sigreturn,%d0
-	trap #0
-
-ENTRY(ret_from_user_rt_signal)
-	movel #__NR_rt_sigreturn,%d0
-	trap #0
-
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
index 7dc186b..8a624ec 100644
--- a/arch/m68k/kernel/setup_no.c
+++ b/arch/m68k/kernel/setup_no.c
@@ -218,13 +218,10 @@ void __init setup_arch(char **cmdline_p)
 	printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)\n");
 #endif
 
-	pr_debug("KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
-		 "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext,
-		 (int) &_sdata, (int) &_edata,
-		 (int) &_sbss, (int) &_ebss);
-	pr_debug("MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ",
-		 (int) &_ebss, (int) memory_start,
-		 (int) memory_start, (int) memory_end);
+	pr_debug("KERNEL -> TEXT=0x%p-0x%p DATA=0x%p-0x%p BSS=0x%p-0x%p\n",
+		 _stext, _etext, _sdata, _edata, _sbss, _ebss);
+	pr_debug("MEMORY -> ROMFS=0x%p-0x%06lx MEM=0x%06lx-0x%06lx\n ",
+		 _ebss, memory_start, memory_start, memory_end);
 
 	/* Keep a copy of command line */
 	*cmdline_p = &command_line[0];
diff --git a/arch/m68k/lib/muldi3.c b/arch/m68k/lib/muldi3.c
index 79e928a..ee5f0b1 100644
--- a/arch/m68k/lib/muldi3.c
+++ b/arch/m68k/lib/muldi3.c
@@ -19,7 +19,7 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
+#ifdef CONFIG_CPU_HAS_NO_MULDIV64
 
 #define SI_TYPE_SIZE 32
 #define __BITS4 (SI_TYPE_SIZE / 4)
diff --git a/arch/m68k/platform/coldfire/Makefile b/arch/m68k/platform/coldfire/Makefile
index 76d389d..b3f8bfd 100644
--- a/arch/m68k/platform/coldfire/Makefile
+++ b/arch/m68k/platform/coldfire/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_M5206e)	+= m5206.o timers.o intc.o reset.o
 obj-$(CONFIG_M520x)	+= m520x.o pit.o intc-simr.o reset.o
 obj-$(CONFIG_M523x)	+= m523x.o pit.o dma_timer.o intc-2.o reset.o
 obj-$(CONFIG_M5249)	+= m5249.o timers.o intc.o intc-5249.o reset.o
+obj-$(CONFIG_M525x)	+= m525x.o timers.o intc.o intc-525x.o reset.o
 obj-$(CONFIG_M527x)	+= m527x.o pit.o intc-2.o reset.o
 obj-$(CONFIG_M5272)	+= m5272.o intc-5272.o timers.o
 obj-$(CONFIG_M528x)	+= m528x.o pit.o intc-2.o reset.o
@@ -27,10 +28,11 @@ obj-$(CONFIG_M5307)	+= m5307.o timers.o intc.o reset.o
 obj-$(CONFIG_M532x)	+= m532x.o timers.o intc-simr.o reset.o
 obj-$(CONFIG_M5407)	+= m5407.o timers.o intc.o reset.o
 obj-$(CONFIG_M54xx)	+= m54xx.o sltimers.o intc-2.o
+obj-$(CONFIG_M5441x)	+= m5441x.o pit.o intc-simr.o reset.o
 
 obj-$(CONFIG_NETtel)	+= nettel.o
 obj-$(CONFIG_CLEOPATRA)	+= nettel.o
 obj-$(CONFIG_FIREBEE)	+= firebee.o
 
-obj-y			+= pinmux.o gpio.o
+obj-y			+= gpio.o
 extra-y := head.o
diff --git a/arch/m68k/platform/coldfire/clk.c b/arch/m68k/platform/coldfire/clk.c
index 9f1260c..d96405c 100644
--- a/arch/m68k/platform/coldfire/clk.c
+++ b/arch/m68k/platform/coldfire/clk.c
@@ -10,11 +10,17 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
 #include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
 #include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfclk.h>
 
 /***************************************************************************/
-
+#ifndef MCFPM_PPMCR0
 struct clk *clk_get(struct device *dev, const char *id)
 {
 	return NULL;
@@ -42,4 +48,103 @@ unsigned long clk_get_rate(struct clk *clk)
 	return MCF_CLK;
 }
 EXPORT_SYMBOL(clk_get_rate);
+
+#else
+static DEFINE_SPINLOCK(clk_lock);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+	const char *clk_name = dev ? dev_name(dev) : id ? id : NULL;
+	struct clk *clk;
+	unsigned i;
+
+	for (i = 0; (clk = mcf_clks[i]) != NULL; ++i)
+		if (!strcmp(clk->name, clk_name))
+			return clk;
+	pr_warn("clk_get: didn't find clock %s\n", clk_name);
+	return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&clk_lock, flags);
+	if ((clk->enabled++ == 0) && clk->clk_ops)
+		clk->clk_ops->enable(clk);
+	spin_unlock_irqrestore(&clk_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&clk_lock, flags);
+	if ((--clk->enabled == 0) && clk->clk_ops)
+		clk->clk_ops->disable(clk);
+	spin_unlock_irqrestore(&clk_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->enabled != 0)
+		pr_warn("clk_put %s still enabled\n", clk->name);
+}
+EXPORT_SYMBOL(clk_put);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+
 /***************************************************************************/
+
+void __clk_init_enabled(struct clk *clk)
+{
+	clk->enabled = 1;
+	clk->clk_ops->enable(clk);
+}
+
+void __clk_init_disabled(struct clk *clk)
+{
+	clk->enabled = 0;
+	clk->clk_ops->disable(clk);
+}
+
+static void __clk_enable0(struct clk *clk)
+{
+	__raw_writeb(clk->slot, MCFPM_PPMCR0);
+}
+
+static void __clk_disable0(struct clk *clk)
+{
+	__raw_writeb(clk->slot, MCFPM_PPMSR0);
+}
+
+struct clk_ops clk_ops0 = {
+	.enable		= __clk_enable0,
+	.disable	= __clk_disable0,
+};
+
+#ifdef MCFPM_PPMCR1
+static void __clk_enable1(struct clk *clk)
+{
+	__raw_writeb(clk->slot, MCFPM_PPMCR1);
+}
+
+static void __clk_disable1(struct clk *clk)
+{
+	__raw_writeb(clk->slot, MCFPM_PPMSR1);
+}
+
+struct clk_ops clk_ops1 = {
+	.enable		= __clk_enable1,
+	.disable	= __clk_disable1,
+};
+#endif /* MCFPM_PPMCR1 */
+#endif /* MCFPM_PPMCR0 */
diff --git a/arch/m68k/platform/coldfire/device.c b/arch/m68k/platform/coldfire/device.c
index 3aa77dd..81f0fb5 100644
--- a/arch/m68k/platform/coldfire/device.c
+++ b/arch/m68k/platform/coldfire/device.c
@@ -13,6 +13,7 @@
 #include <linux/io.h>
 #include <linux/spi/spi.h>
 #include <linux/gpio.h>
+#include <linux/fec.h>
 #include <asm/traps.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
@@ -20,7 +21,7 @@
 #include <asm/mcfqspi.h>
 
 /*
- *	All current ColdFire parts contain from 2, 3 or 4 UARTS.
+ *	All current ColdFire parts contain from 2, 3, 4 or 10 UARTS.
  */
 static struct mcf_platform_uart mcf_uart_platform_data[] = {
 	{
@@ -43,6 +44,42 @@ static struct mcf_platform_uart mcf_uart_platform_data[] = {
 		.irq		= MCF_IRQ_UART3,
 	},
 #endif
+#ifdef MCFUART_BASE4
+	{
+		.mapbase	= MCFUART_BASE4,
+		.irq		= MCF_IRQ_UART4,
+	},
+#endif
+#ifdef MCFUART_BASE5
+	{
+		.mapbase	= MCFUART_BASE5,
+		.irq		= MCF_IRQ_UART5,
+	},
+#endif
+#ifdef MCFUART_BASE6
+	{
+		.mapbase	= MCFUART_BASE6,
+		.irq		= MCF_IRQ_UART6,
+	},
+#endif
+#ifdef MCFUART_BASE7
+	{
+		.mapbase	= MCFUART_BASE7,
+		.irq		= MCF_IRQ_UART7,
+	},
+#endif
+#ifdef MCFUART_BASE8
+	{
+		.mapbase	= MCFUART_BASE8,
+		.irq		= MCF_IRQ_UART8,
+	},
+#endif
+#ifdef MCFUART_BASE9
+	{
+		.mapbase	= MCFUART_BASE9,
+		.irq		= MCF_IRQ_UART9,
+	},
+#endif
 	{ },
 };
 
@@ -53,6 +90,18 @@ static struct platform_device mcf_uart = {
 };
 
 #ifdef CONFIG_FEC
+
+#ifdef CONFIG_M5441x
+#define FEC_NAME	"enet-fec"
+static struct fec_platform_data fec_pdata = {
+	.phy		= PHY_INTERFACE_MODE_RMII,
+};
+#define FEC_PDATA	(&fec_pdata)
+#else
+#define FEC_NAME	"fec"
+#define FEC_PDATA	NULL
+#endif
+
 /*
  *	Some ColdFire cores contain the Fast Ethernet Controller (FEC)
  *	block. It is Freescale's own hardware block. Some ColdFires
@@ -82,10 +131,11 @@ static struct resource mcf_fec0_resources[] = {
 };
 
 static struct platform_device mcf_fec0 = {
-	.name			= "fec",
+	.name			= FEC_NAME,
 	.id			= 0,
 	.num_resources		= ARRAY_SIZE(mcf_fec0_resources),
 	.resource		= mcf_fec0_resources,
+	.dev.platform_data	= FEC_PDATA,
 };
 
 #ifdef MCFFEC_BASE1
@@ -113,10 +163,11 @@ static struct resource mcf_fec1_resources[] = {
 };
 
 static struct platform_device mcf_fec1 = {
-	.name			= "fec",
+	.name			= FEC_NAME,
 	.id			= 1,
 	.num_resources		= ARRAY_SIZE(mcf_fec1_resources),
 	.resource		= mcf_fec1_resources,
+	.dev.platform_data	= FEC_PDATA,
 };
 #endif /* MCFFEC_BASE1 */
 #endif /* CONFIG_FEC */
diff --git a/arch/m68k/platform/coldfire/gpio.c b/arch/m68k/platform/coldfire/gpio.c
index 4c8c424..9cd2b5c 100644
--- a/arch/m68k/platform/coldfire/gpio.c
+++ b/arch/m68k/platform/coldfire/gpio.c
@@ -14,119 +14,161 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
 
-#include <asm/gpio.h>
-#include <asm/pinmux.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
 #include <asm/mcfgpio.h>
 
-#define MCF_CHIP(chip) container_of(chip, struct mcf_gpio_chip, gpio_chip)
+int __mcfgpio_get_value(unsigned gpio)
+{
+	return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio);
+}
+EXPORT_SYMBOL(__mcfgpio_get_value);
+
+void __mcfgpio_set_value(unsigned gpio, int value)
+{
+	if (gpio < MCFGPIO_SCR_START) {
+		unsigned long flags;
+		MCFGPIO_PORTTYPE data;
+
+		local_irq_save(flags);
+		data = mcfgpio_read(__mcfgpio_podr(gpio));
+		if (value)
+			data |= mcfgpio_bit(gpio);
+		else
+			data &= ~mcfgpio_bit(gpio);
+		mcfgpio_write(data, __mcfgpio_podr(gpio));
+		local_irq_restore(flags);
+	} else {
+		if (value)
+			mcfgpio_write(mcfgpio_bit(gpio),
+					MCFGPIO_SETR_PORT(gpio));
+		else
+			mcfgpio_write(~mcfgpio_bit(gpio),
+					MCFGPIO_CLRR_PORT(gpio));
+	}
+}
+EXPORT_SYMBOL(__mcfgpio_set_value);
 
-int mcf_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+int __mcfgpio_direction_input(unsigned gpio)
 {
 	unsigned long flags;
 	MCFGPIO_PORTTYPE dir;
-	struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
 
 	local_irq_save(flags);
-	dir = mcfgpio_read(mcf_chip->pddr);
-	dir &= ~mcfgpio_bit(chip->base + offset);
-	mcfgpio_write(dir, mcf_chip->pddr);
+	dir = mcfgpio_read(__mcfgpio_pddr(gpio));
+	dir &= ~mcfgpio_bit(gpio);
+	mcfgpio_write(dir, __mcfgpio_pddr(gpio));
 	local_irq_restore(flags);
 
 	return 0;
 }
+EXPORT_SYMBOL(__mcfgpio_direction_input);
 
-int mcf_gpio_get_value(struct gpio_chip *chip, unsigned offset)
-{
-	struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
-
-	return mcfgpio_read(mcf_chip->ppdr) & mcfgpio_bit(chip->base + offset);
-}
-
-int mcf_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
-		int value)
+int __mcfgpio_direction_output(unsigned gpio, int value)
 {
 	unsigned long flags;
 	MCFGPIO_PORTTYPE data;
-	struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
 
 	local_irq_save(flags);
-	/* write the value to the output latch */
-	data = mcfgpio_read(mcf_chip->podr);
+	data = mcfgpio_read(__mcfgpio_pddr(gpio));
 	if (value)
-		data |= mcfgpio_bit(chip->base + offset);
+		data |= mcfgpio_bit(gpio);
 	else
-		data &= ~mcfgpio_bit(chip->base + offset);
-	mcfgpio_write(data, mcf_chip->podr);
-
-	/* now set the direction to output */
-	data = mcfgpio_read(mcf_chip->pddr);
-	data |= mcfgpio_bit(chip->base + offset);
-	mcfgpio_write(data, mcf_chip->pddr);
+		data &= mcfgpio_bit(gpio);
+	mcfgpio_write(data, __mcfgpio_pddr(gpio));
+
+	/* now set the data to output */
+	if (gpio < MCFGPIO_SCR_START) {
+		data = mcfgpio_read(__mcfgpio_podr(gpio));
+		if (value)
+			data |= mcfgpio_bit(gpio);
+		else
+			data &= ~mcfgpio_bit(gpio);
+		mcfgpio_write(data, __mcfgpio_podr(gpio));
+	} else {
+		 if (value)
+			mcfgpio_write(mcfgpio_bit(gpio),
+					MCFGPIO_SETR_PORT(gpio));
+		 else
+			 mcfgpio_write(~mcfgpio_bit(gpio),
+					 MCFGPIO_CLRR_PORT(gpio));
+	}
 	local_irq_restore(flags);
+	return 0;
+}
+EXPORT_SYMBOL(__mcfgpio_direction_output);
 
+int __mcfgpio_request(unsigned gpio)
+{
 	return 0;
 }
+EXPORT_SYMBOL(__mcfgpio_request);
 
-void mcf_gpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
+void __mcfgpio_free(unsigned gpio)
 {
-	struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+	__mcfgpio_direction_input(gpio);
+}
+EXPORT_SYMBOL(__mcfgpio_free);
 
-	unsigned long flags;
-	MCFGPIO_PORTTYPE data;
+#ifdef CONFIG_GPIOLIB
 
-	local_irq_save(flags);
-	data = mcfgpio_read(mcf_chip->podr);
-	if (value)
-		data |= mcfgpio_bit(chip->base + offset);
-	else
-		data &= ~mcfgpio_bit(chip->base + offset);
-	mcfgpio_write(data, mcf_chip->podr);
-	local_irq_restore(flags);
+int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	return __mcfgpio_direction_input(offset);
 }
 
-void mcf_gpio_set_value_fast(struct gpio_chip *chip, unsigned offset, int value)
+int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset)
 {
-	struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
-
-	if (value)
-		mcfgpio_write(mcfgpio_bit(chip->base + offset), mcf_chip->setr);
-	else
-		mcfgpio_write(~mcfgpio_bit(chip->base + offset), mcf_chip->clrr);
+	return __mcfgpio_get_value(offset);
 }
 
-int mcf_gpio_request(struct gpio_chip *chip, unsigned offset)
+int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
-
-	return mcf_chip->gpio_to_pinmux ?
-		mcf_pinmux_request(mcf_chip->gpio_to_pinmux[offset], 0) : 0;
+	return __mcfgpio_direction_output(offset, value);
 }
 
-void mcf_gpio_free(struct gpio_chip *chip, unsigned offset)
+void mcfgpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+	__mcfgpio_set_value(offset, value);
+}
 
-	mcf_gpio_direction_input(chip, offset);
+int mcfgpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	return __mcfgpio_request(offset);
+}
 
-	if (mcf_chip->gpio_to_pinmux)
-		mcf_pinmux_release(mcf_chip->gpio_to_pinmux[offset], 0);
+void mcfgpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	__mcfgpio_free(offset);
 }
 
-struct bus_type mcf_gpio_subsys = {
+struct bus_type mcfgpio_subsys = {
 	.name		= "gpio",
 	.dev_name	= "gpio",
 };
 
-static int __init mcf_gpio_sysinit(void)
-{
-	unsigned int i = 0;
+static struct gpio_chip mcfgpio_chip = {
+	.label			= "mcfgpio",
+	.request		= mcfgpio_request,
+	.free			= mcfgpio_free,
+	.direction_input	= mcfgpio_direction_input,
+	.direction_output	= mcfgpio_direction_output,
+	.get			= mcfgpio_get_value,
+	.set			= mcfgpio_set_value,
+	.base			= 0,
+	.ngpio			= MCFGPIO_PIN_MAX,
+};
 
-	while (i < mcf_gpio_chips_size)
-		gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-	return subsys_system_register(&mcf_gpio_subsys, NULL);
+static int __init mcfgpio_sysinit(void)
+{
+	gpiochip_add(&mcfgpio_chip);
+	return subsys_system_register(&mcfgpio_subsys, NULL);
 }
 
-core_initcall(mcf_gpio_sysinit);
+core_initcall(mcfgpio_sysinit);
+#endif
diff --git a/arch/m68k/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S
index c3db70e..4e0c9eb 100644
--- a/arch/m68k/platform/coldfire/head.S
+++ b/arch/m68k/platform/coldfire/head.S
@@ -31,9 +31,9 @@
 .endm
 
 #elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
-      defined(CONFIG_M5249) || defined(CONFIG_M527x) || \
-      defined(CONFIG_M528x) || defined(CONFIG_M5307) || \
-      defined(CONFIG_M5407)
+      defined(CONFIG_M5249) || defined(CONFIG_M525x) || \
+      defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+      defined(CONFIG_M5307) || defined(CONFIG_M5407)
 /*
  *	Not all these devices have exactly the same DRAM controller,
  *	but the DCMR register is virtually identical - give or take
diff --git a/arch/m68k/platform/coldfire/intc-525x.c b/arch/m68k/platform/coldfire/intc-525x.c
new file mode 100644
index 0000000..b23204d
--- /dev/null
+++ b/arch/m68k/platform/coldfire/intc-525x.c
@@ -0,0 +1,91 @@
+/*
+ * intc2.c  -- support for the 2nd INTC controller of the 525x
+ *
+ * (C) Copyright 2012, Steven King <sfking@fdwdc.com>
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+static void intc2_irq_gpio_mask(struct irq_data *d)
+{
+	u32 imr = readl(MCFSIM2_GPIOINTENABLE);
+	u32 type = irqd_get_trigger_type(d);
+	int irq = d->irq - MCF_IRQ_GPIO0;
+
+	if (type & IRQ_TYPE_EDGE_RISING)
+		imr &= ~(0x001 << irq);
+	if (type & IRQ_TYPE_EDGE_FALLING)
+		imr &= ~(0x100 << irq);
+	writel(imr, MCFSIM2_GPIOINTENABLE);
+}
+
+static void intc2_irq_gpio_unmask(struct irq_data *d)
+{
+	u32 imr = readl(MCFSIM2_GPIOINTENABLE);
+	u32 type = irqd_get_trigger_type(d);
+	int irq = d->irq - MCF_IRQ_GPIO0;
+
+	if (type & IRQ_TYPE_EDGE_RISING)
+		imr |= (0x001 << irq);
+	if (type & IRQ_TYPE_EDGE_FALLING)
+		imr |= (0x100 << irq);
+	writel(imr, MCFSIM2_GPIOINTENABLE);
+}
+
+static void intc2_irq_gpio_ack(struct irq_data *d)
+{
+	u32 imr = 0;
+	u32 type = irqd_get_trigger_type(d);
+	int irq = d->irq - MCF_IRQ_GPIO0;
+
+	if (type & IRQ_TYPE_EDGE_RISING)
+		imr |= (0x001 << irq);
+	if (type & IRQ_TYPE_EDGE_FALLING)
+		imr |= (0x100 << irq);
+	writel(imr, MCFSIM2_GPIOINTCLEAR);
+}
+
+static int intc2_irq_gpio_set_type(struct irq_data *d, unsigned int f)
+{
+	if (f & ~IRQ_TYPE_EDGE_BOTH)
+		return -EINVAL;
+	return 0;
+}
+
+static struct irq_chip intc2_irq_gpio_chip = {
+	.name		= "CF-INTC2",
+	.irq_mask	= intc2_irq_gpio_mask,
+	.irq_unmask	= intc2_irq_gpio_unmask,
+	.irq_ack	= intc2_irq_gpio_ack,
+	.irq_set_type	= intc2_irq_gpio_set_type,
+};
+
+static int __init mcf_intc2_init(void)
+{
+	int irq;
+
+	/* set the interrupt base for the second interrupt controller */
+	writel(MCFINTC2_VECBASE, MCFINTC2_INTBASE);
+
+	/* GPIO interrupt sources */
+	for (irq = MCF_IRQ_GPIO0; (irq <= MCF_IRQ_GPIO6); irq++) {
+		irq_set_chip(irq, &intc2_irq_gpio_chip);
+		irq_set_handler(irq, handle_edge_irq);
+	}
+
+	return 0;
+}
+
+arch_initcall(mcf_intc2_init);
diff --git a/arch/m68k/platform/coldfire/intc-simr.c b/arch/m68k/platform/coldfire/intc-simr.c
index 650d52e..7cf2c15 100644
--- a/arch/m68k/platform/coldfire/intc-simr.c
+++ b/arch/m68k/platform/coldfire/intc-simr.c
@@ -59,16 +59,18 @@ static unsigned int inline irq2ebit(unsigned int irq)
 #endif
 
 /*
- *	There maybe one or two interrupt control units, each has 64
- *	interrupts. If there is no second unit then MCFINTC1_* defines
- *	will be 0 (and code for them optimized away).
+ *	There maybe one, two or three interrupt control units, each has 64
+ *	interrupts. If there is no second or third unit then MCFINTC1_* or
+ *	MCFINTC2_* defines will be 0 (and code for them optimized away).
  */
 
 static void intc_irq_mask(struct irq_data *d)
 {
 	unsigned int irq = d->irq - MCFINT_VECBASE;
 
-	if (MCFINTC1_SIMR && (irq > 64))
+	if (MCFINTC2_SIMR && (irq > 128))
+		__raw_writeb(irq - 128, MCFINTC2_SIMR);
+	else if (MCFINTC1_SIMR && (irq > 64))
 		__raw_writeb(irq - 64, MCFINTC1_SIMR);
 	else
 		__raw_writeb(irq, MCFINTC0_SIMR);
@@ -78,7 +80,9 @@ static void intc_irq_unmask(struct irq_data *d)
 {
 	unsigned int irq = d->irq - MCFINT_VECBASE;
 
-	if (MCFINTC1_CIMR && (irq > 64))
+	if (MCFINTC2_CIMR && (irq > 128))
+		__raw_writeb(irq - 128, MCFINTC2_CIMR);
+	else if (MCFINTC1_CIMR && (irq > 64))
 		__raw_writeb(irq - 64, MCFINTC1_CIMR);
 	else
 		__raw_writeb(irq, MCFINTC0_CIMR);
@@ -99,9 +103,11 @@ static unsigned int intc_irq_startup(struct irq_data *d)
 		unsigned int ebit = irq2ebit(irq);
 		u8 v;
 
+#if defined(MCFEPORT_EPDDR)
 		/* Set EPORT line as input */
 		v = __raw_readb(MCFEPORT_EPDDR);
 		__raw_writeb(v & ~(0x1 << ebit), MCFEPORT_EPDDR);
+#endif
 
 		/* Set EPORT line as interrupt source */
 		v = __raw_readb(MCFEPORT_EPIER);
@@ -109,12 +115,13 @@ static unsigned int intc_irq_startup(struct irq_data *d)
 	}
 
 	irq -= MCFINT_VECBASE;
-	if (MCFINTC1_ICR0 && (irq > 64))
+	if (MCFINTC2_ICR0 && (irq > 128))
+		__raw_writeb(5, MCFINTC2_ICR0 + irq - 128);
+	else if (MCFINTC1_ICR0 && (irq > 64))
 		__raw_writeb(5, MCFINTC1_ICR0 + irq - 64);
 	else
 		__raw_writeb(5, MCFINTC0_ICR0 + irq);
 
-
 	intc_irq_unmask(d);
 	return 0;
 }
@@ -175,8 +182,11 @@ void __init init_IRQ(void)
 	__raw_writeb(0xff, MCFINTC0_SIMR);
 	if (MCFINTC1_SIMR)
 		__raw_writeb(0xff, MCFINTC1_SIMR);
+	if (MCFINTC2_SIMR)
+		__raw_writeb(0xff, MCFINTC2_SIMR);
 
-	eirq = MCFINT_VECBASE + 64 + (MCFINTC1_ICR0 ? 64 : 0);
+	eirq = MCFINT_VECBASE + 64 + (MCFINTC1_ICR0 ? 64 : 0) +
+						(MCFINTC2_ICR0 ? 64 : 0);
 	for (irq = MCFINT_VECBASE; (irq < eirq); irq++) {
 		if ((irq >= EINT1) && (irq <= EINT7))
 			irq_set_chip(irq, &intc_irq_chip_edge_port);
diff --git a/arch/m68k/platform/coldfire/m5206.c b/arch/m68k/platform/coldfire/m5206.c
index a8b81df..6bfbeeb 100644
--- a/arch/m68k/platform/coldfire/m5206.c
+++ b/arch/m68k/platform/coldfire/m5206.c
@@ -16,15 +16,6 @@
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-/***************************************************************************/
-
-struct mcf_gpio_chip mcf_gpio_chips[] = {
-	MCFGPS(PP, 0, 8, MCFSIM_PADDR, MCFSIM_PADAT, MCFSIM_PADAT),
-};
-
-unsigned int mcf_gpio_chips_size = ARRAY_SIZE(mcf_gpio_chips);
 
 /***************************************************************************/
 
diff --git a/arch/m68k/platform/coldfire/m520x.c b/arch/m68k/platform/coldfire/m520x.c
index 3264b88..ea1be0e 100644
--- a/arch/m68k/platform/coldfire/m520x.c
+++ b/arch/m68k/platform/coldfire/m520x.c
@@ -19,22 +19,102 @@
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
-#include <asm/mcfgpio.h>
+#include <asm/mcfclk.h>
 
 /***************************************************************************/
 
-struct mcf_gpio_chip mcf_gpio_chips[] = {
-	MCFGPS(PIRQ, 0, 8, MCFEPORT_EPDDR, MCFEPORT_EPDR, MCFEPORT_EPPDR),
-	MCFGPF(CS, 9, 3),
-	MCFGPF(FECI2C, 16, 4),
-	MCFGPF(QSPI, 24, 4),
-	MCFGPF(TIMER, 32, 4),
-	MCFGPF(UART, 40, 8),
-	MCFGPF(FECH, 48, 8),
-	MCFGPF(FECL, 56, 8),
+DEFINE_CLK(0, "flexbus", 2, MCF_CLK);
+DEFINE_CLK(0, "fec.0", 12, MCF_CLK);
+DEFINE_CLK(0, "edma", 17, MCF_CLK);
+DEFINE_CLK(0, "intc.0", 18, MCF_CLK);
+DEFINE_CLK(0, "iack.0", 21, MCF_CLK);
+DEFINE_CLK(0, "mcfi2c.0", 22, MCF_CLK);
+DEFINE_CLK(0, "mcfqspi.0", 23, MCF_CLK);
+DEFINE_CLK(0, "mcfuart.0", 24, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.1", 25, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.2", 26, MCF_BUSCLK);
+DEFINE_CLK(0, "mcftmr.0", 28, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.1", 29, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.2", 30, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.3", 31, MCF_CLK);
+
+DEFINE_CLK(0, "mcfpit.0", 32, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.1", 33, MCF_CLK);
+DEFINE_CLK(0, "mcfeport.0", 34, MCF_CLK);
+DEFINE_CLK(0, "mcfwdt.0", 35, MCF_CLK);
+DEFINE_CLK(0, "pll.0", 36, MCF_CLK);
+DEFINE_CLK(0, "sys.0", 40, MCF_BUSCLK);
+DEFINE_CLK(0, "gpio.0", 41, MCF_BUSCLK);
+DEFINE_CLK(0, "sdram.0", 42, MCF_CLK);
+
+struct clk *mcf_clks[] = {
+	&__clk_0_2, /* flexbus */
+	&__clk_0_12, /* fec.0 */
+	&__clk_0_17, /* edma */
+	&__clk_0_18, /* intc.0 */
+	&__clk_0_21, /* iack.0 */
+	&__clk_0_22, /* mcfi2c.0 */
+	&__clk_0_23, /* mcfqspi.0 */
+	&__clk_0_24, /* mcfuart.0 */
+	&__clk_0_25, /* mcfuart.1 */
+	&__clk_0_26, /* mcfuart.2 */
+	&__clk_0_28, /* mcftmr.0 */
+	&__clk_0_29, /* mcftmr.1 */
+	&__clk_0_30, /* mcftmr.2 */
+	&__clk_0_31, /* mcftmr.3 */
+
+	&__clk_0_32, /* mcfpit.0 */
+	&__clk_0_33, /* mcfpit.1 */
+	&__clk_0_34, /* mcfeport.0 */
+	&__clk_0_35, /* mcfwdt.0 */
+	&__clk_0_36, /* pll.0 */
+	&__clk_0_40, /* sys.0 */
+	&__clk_0_41, /* gpio.0 */
+	&__clk_0_42, /* sdram.0 */
+NULL,
 };
 
-unsigned int mcf_gpio_chips_size = ARRAY_SIZE(mcf_gpio_chips);
+static struct clk * const enable_clks[] __initconst = {
+	&__clk_0_2, /* flexbus */
+	&__clk_0_18, /* intc.0 */
+	&__clk_0_21, /* iack.0 */
+	&__clk_0_24, /* mcfuart.0 */
+	&__clk_0_25, /* mcfuart.1 */
+	&__clk_0_26, /* mcfuart.2 */
+
+	&__clk_0_32, /* mcfpit.0 */
+	&__clk_0_33, /* mcfpit.1 */
+	&__clk_0_34, /* mcfeport.0 */
+	&__clk_0_36, /* pll.0 */
+	&__clk_0_40, /* sys.0 */
+	&__clk_0_41, /* gpio.0 */
+	&__clk_0_42, /* sdram.0 */
+};
+
+static struct clk * const disable_clks[] __initconst = {
+	&__clk_0_12, /* fec.0 */
+	&__clk_0_17, /* edma */
+	&__clk_0_22, /* mcfi2c.0 */
+	&__clk_0_23, /* mcfqspi.0 */
+	&__clk_0_28, /* mcftmr.0 */
+	&__clk_0_29, /* mcftmr.1 */
+	&__clk_0_30, /* mcftmr.2 */
+	&__clk_0_31, /* mcftmr.3 */
+	&__clk_0_35, /* mcfwdt.0 */
+};
+
+
+static void __init m520x_clk_init(void)
+{
+	unsigned i;
+
+	/* make sure these clocks are enabled */
+	for (i = 0; i < ARRAY_SIZE(enable_clks); ++i)
+		__clk_init_enabled(enable_clks[i]);
+	/* make sure these clocks are disabled */
+	for (i = 0; i < ARRAY_SIZE(disable_clks); ++i)
+		__clk_init_disabled(disable_clks[i]);
+}
 
 /***************************************************************************/
 
@@ -93,6 +173,7 @@ static void __init m520x_fec_init(void)
 void __init config_BSP(char *commandp, int size)
 {
 	mach_sched_init = hw_timer_init;
+	m520x_clk_init();
 	m520x_uarts_init();
 	m520x_fec_init();
 #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
diff --git a/arch/m68k/platform/coldfire/m523x.c b/arch/m68k/platform/coldfire/m523x.c
index 5d57a42..d47dfd8 100644
--- a/arch/m68k/platform/coldfire/m523x.c
+++ b/arch/m68k/platform/coldfire/m523x.c
@@ -19,28 +19,6 @@
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-/***************************************************************************/
-
-struct mcf_gpio_chip mcf_gpio_chips[] = {
-	MCFGPS(PIRQ, 1, 7, MCFEPORT_EPDDR, MCFEPORT_EPDR, MCFEPORT_EPPDR),
-	MCFGPF(ADDR, 13, 3),
-	MCFGPF(DATAH, 16, 8),
-	MCFGPF(DATAL, 24, 8),
-	MCFGPF(BUSCTL, 32, 8),
-	MCFGPF(BS, 40, 4),
-	MCFGPF(CS, 49, 7),
-	MCFGPF(SDRAM, 56, 6),
-	MCFGPF(FECI2C, 64, 4),
-	MCFGPF(UARTH, 72, 2),
-	MCFGPF(UARTL, 80, 8),
-	MCFGPF(QSPI, 88, 5),
-	MCFGPF(TIMER, 96, 8),
-	MCFGPF(ETPU, 104, 3),
-};
-
-unsigned int mcf_gpio_chips_size = ARRAY_SIZE(mcf_gpio_chips);
 
 /***************************************************************************/
 
diff --git a/arch/m68k/platform/coldfire/m5249.c b/arch/m68k/platform/coldfire/m5249.c
index fdfa1ed..300e729 100644
--- a/arch/m68k/platform/coldfire/m5249.c
+++ b/arch/m68k/platform/coldfire/m5249.c
@@ -16,16 +16,6 @@
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-/***************************************************************************/
-
-struct mcf_gpio_chip mcf_gpio_chips[] = {
-	MCFGPS(GPIO0, 0, 32, MCFSIM2_GPIOENABLE, MCFSIM2_GPIOWRITE, MCFSIM2_GPIOREAD),
-	MCFGPS(GPIO1, 32, 32, MCFSIM2_GPIO1ENABLE, MCFSIM2_GPIO1WRITE, MCFSIM2_GPIO1READ),
-};
-
-unsigned int mcf_gpio_chips_size = ARRAY_SIZE(mcf_gpio_chips);
 
 /***************************************************************************/
 
diff --git a/arch/m68k/platform/coldfire/m525x.c b/arch/m68k/platform/coldfire/m525x.c
new file mode 100644
index 0000000..8ce905f
--- /dev/null
+++ b/arch/m68k/platform/coldfire/m525x.c
@@ -0,0 +1,66 @@
+/***************************************************************************/
+
+/*
+ *	525x.c
+ *
+ *	Copyright (C) 2012, Steven King <sfking@fdwdc.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+static void __init m525x_qspi_init(void)
+{
+#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
+	/* set the GPIO function for the qspi cs gpios */
+	/* FIXME: replace with pinmux/pinctl support */
+	u32 f = readl(MCFSIM2_GPIOFUNC);
+	f |= (1 << MCFQSPI_CS2) | (1 << MCFQSPI_CS1) | (1 << MCFQSPI_CS0);
+	writel(f, MCFSIM2_GPIOFUNC);
+
+	/* QSPI irq setup */
+	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL4 | MCFSIM_ICR_PRI0,
+	       MCF_MBAR + MCFSIM_QSPIICR);
+	mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI);
+#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
+}
+
+static void __init m525x_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+	u32 r;
+
+	/* first I2C controller uses regular irq setup */
+	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI0,
+			MCF_MBAR + MCFSIM_I2CICR);
+	mcf_mapirq2imr(MCF_IRQ_I2C0, MCFINTC_I2C);
+
+	/* second I2C controller is completely different */
+	r = readl(MCFINTC2_INTPRI_REG(MCF_IRQ_I2C1));
+	r &= ~MCFINTC2_INTPRI_BITS(0xf, MCF_IRQ_I2C1);
+	r |= MCFINTC2_INTPRI_BITS(0x5, MCF_IRQ_I2C1);
+	writel(r, MCFINTC2_INTPRI_REG(MCF_IRQ_I2C1));
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+	mach_sched_init = hw_timer_init;
+
+	m525x_qspi_init();
+	m525x_i2c_init();
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m5272.c b/arch/m68k/platform/coldfire/m5272.c
index 43e3606..e68bc7a 100644
--- a/arch/m68k/platform/coldfire/m5272.c
+++ b/arch/m68k/platform/coldfire/m5272.c
@@ -19,7 +19,6 @@
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
-#include <asm/mcfgpio.h>
 
 /***************************************************************************/
 
@@ -31,16 +30,6 @@ unsigned char ledbank = 0xff;
 
 /***************************************************************************/
 
-struct mcf_gpio_chip mcf_gpio_chips[] = {
-	MCFGPS(PA,  0, 16, MCFSIM_PADDR, MCFSIM_PADAT, MCFSIM_PADAT),
-	MCFGPS(PB, 16, 16, MCFSIM_PBDDR, MCFSIM_PBDAT, MCFSIM_PBDAT),
-	MCFGPS(Pc, 32, 16, MCFSIM_PCDDR, MCFSIM_PCDAT, MCFSIM_PCDAT),
-};
-
-unsigned int mcf_gpio_chips_size = ARRAY_SIZE(mcf_gpio_chips);
-
-/***************************************************************************/
-
 static void __init m5272_uarts_init(void)
 {
 	u32 v;
diff --git a/arch/m68k/platform/coldfire/m527x.c b/arch/m68k/platform/coldfire/m527x.c
index 9b0b66a..b3cb378 100644
--- a/arch/m68k/platform/coldfire/m527x.c
+++ b/arch/m68k/platform/coldfire/m527x.c
@@ -20,49 +20,6 @@
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
-#include <asm/mcfgpio.h>
-
-/***************************************************************************/
-
-struct mcf_gpio_chip mcf_gpio_chips[] = {
-#if defined(CONFIG_M5271)
-	MCFGPS(PIRQ, 1, 7, MCFEPORT_EPDDR, MCFEPORT_EPDR, MCFEPORT_EPPDR),
-	MCFGPF(ADDR, 13, 3),
-	MCFGPF(DATAH, 16, 8),
-	MCFGPF(DATAL, 24, 8),
-	MCFGPF(BUSCTL, 32, 8),
-	MCFGPF(BS, 40, 4),
-	MCFGPF(CS, 49, 7),
-	MCFGPF(SDRAM, 56, 6),
-	MCFGPF(FECI2C, 64, 4),
-	MCFGPF(UARTH, 72, 2),
-	MCFGPF(UARTL, 80, 8),
-	MCFGPF(QSPI, 88, 5),
-	MCFGPF(TIMER, 96, 8),
-#elif defined(CONFIG_M5275)
-	MCFGPS(PIRQ, 1, 7, MCFEPORT_EPDDR, MCFEPORT_EPDR, MCFEPORT_EPPDR),
-	MCFGPF(BUSCTL, 8, 8),
-	MCFGPF(ADDR, 21, 3),
-	MCFGPF(CS, 25, 7),
-	MCFGPF(FEC0H, 32, 8),
-	MCFGPF(FEC0L, 40, 8),
-	MCFGPF(FECI2C, 48, 6),
-	MCFGPF(QSPI, 56, 7),
-	MCFGPF(SDRAM, 64, 8),
-	MCFGPF(TIMERH, 72, 4),
-	MCFGPF(TIMERL, 80, 4),
-	MCFGPF(UARTL, 88, 8),
-	MCFGPF(FEC1H, 96, 8),
-	MCFGPF(FEC1L, 104, 8),
-	MCFGPF(BS, 114, 2),
-	MCFGPF(IRQ, 121, 7),
-	MCFGPF(USBH, 128, 1),
-	MCFGPF(USBL, 136, 8),
-	MCFGPF(UARTH, 144, 4),
-#endif
-};
-
-unsigned int mcf_gpio_chips_size = ARRAY_SIZE(mcf_gpio_chips);
 
 /***************************************************************************/
 
diff --git a/arch/m68k/platform/coldfire/m528x.c b/arch/m68k/platform/coldfire/m528x.c
index 7ed1276b..f1319e5 100644
--- a/arch/m68k/platform/coldfire/m528x.c
+++ b/arch/m68k/platform/coldfire/m528x.c
@@ -21,37 +21,6 @@
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
-#include <asm/mcfgpio.h>
-
-/***************************************************************************/
-
-struct mcf_gpio_chip mcf_gpio_chips[] = {
-	MCFGPS(NQ, 1, 7, MCFEPORT_EPDDR, MCFEPORT_EPDR, MCFEPORT_EPPDR),
-	MCFGPS(TA, 8, 4, MCFGPTA_GPTDDR, MCFGPTA_GPTPORT, MCFGPTB_GPTPORT),
-	MCFGPS(TB, 16, 4, MCFGPTB_GPTDDR, MCFGPTB_GPTPORT, MCFGPTB_GPTPORT),
-	MCFGPS(QA, 24, 4, MCFQADC_DDRQA, MCFQADC_PORTQA, MCFQADC_PORTQA),
-	MCFGPS(QB, 32, 4, MCFQADC_DDRQB, MCFQADC_PORTQB, MCFQADC_PORTQB),
-	MCFGPF(A, 40, 8),
-	MCFGPF(B, 48, 8),
-	MCFGPF(C, 56, 8),
-	MCFGPF(D, 64, 8),
-	MCFGPF(E, 72, 8),
-	MCFGPF(F, 80, 8),
-	MCFGPF(G, 88, 8),
-	MCFGPF(H, 96, 8),
-	MCFGPF(J, 104, 8),
-	MCFGPF(DD, 112, 8),
-	MCFGPF(EH, 120, 8),
-	MCFGPF(EL, 128, 8),
-	MCFGPF(AS, 136, 6),
-	MCFGPF(QS, 144, 7),
-	MCFGPF(SD, 152, 6),
-	MCFGPF(TC, 160, 4),
-	MCFGPF(TD, 168, 4),
-	MCFGPF(UA, 176, 4),
-};
-
-unsigned int mcf_gpio_chips_size = ARRAY_SIZE(mcf_gpio_chips);
 
 /***************************************************************************/
 
@@ -74,7 +43,7 @@ static void __init m528x_uarts_init(void)
 	/* make sure PUAPAR is set for UART0 and UART1 */
 	port = readb(MCF5282_GPIO_PUAPAR);
 	port |= 0x03 | (0x03 << 2);
-	writeb(port, MCF5282_GPIO_PUAPAR);
+	writeb(port, MCFGPIO_PUAPAR);
 }
 
 /***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m5307.c b/arch/m68k/platform/coldfire/m5307.c
index 93b4849..a568d28 100644
--- a/arch/m68k/platform/coldfire/m5307.c
+++ b/arch/m68k/platform/coldfire/m5307.c
@@ -16,7 +16,6 @@
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
 #include <asm/mcfwdebug.h>
 
 /***************************************************************************/
@@ -29,14 +28,6 @@ unsigned char ledbank = 0xff;
 
 /***************************************************************************/
 
-struct mcf_gpio_chip mcf_gpio_chips[] = {
-	MCFGPS(PP, 0, 16, MCFSIM_PADDR, MCFSIM_PADAT, MCFSIM_PADAT),
-};
-
-unsigned int mcf_gpio_chips_size = ARRAY_SIZE(mcf_gpio_chips);
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
 #if defined(CONFIG_NETtel) || \
diff --git a/arch/m68k/platform/coldfire/m532x.c b/arch/m68k/platform/coldfire/m532x.c
index 5394223..4819a44 100644
--- a/arch/m68k/platform/coldfire/m532x.c
+++ b/arch/m68k/platform/coldfire/m532x.c
@@ -26,32 +26,144 @@
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
 #include <asm/mcfdma.h>
-#include <asm/mcfgpio.h>
 #include <asm/mcfwdebug.h>
+#include <asm/mcfclk.h>
 
 /***************************************************************************/
 
-struct mcf_gpio_chip mcf_gpio_chips[] = {
-	MCFGPS(PIRQ, 0, 8, MCFEPORT_EPDDR, MCFEPORT_EPDR, MCFEPORT_EPPDR),
-	MCFGPF(FECH, 8, 8),
-	MCFGPF(FECL, 16, 8),
-	MCFGPF(SSI, 24, 5),
-	MCFGPF(BUSCTL, 32, 4),
-	MCFGPF(BE, 40, 4),
-	MCFGPF(CS, 49, 5),
-	MCFGPF(PWM, 58, 4),
-	MCFGPF(FECI2C, 64, 4),
-	MCFGPF(UART, 72, 8),
-	MCFGPF(QSPI, 80, 6),
-	MCFGPF(TIMER, 88, 4),
-	MCFGPF(LCDDATAH, 96, 2),
-	MCFGPF(LCDDATAM, 104, 8),
-	MCFGPF(LCDDATAL, 112, 8),
-	MCFGPF(LCDCTLH, 120, 1),
-	MCFGPF(LCDCTLL, 128, 8),
+DEFINE_CLK(0, "flexbus", 2, MCF_CLK);
+DEFINE_CLK(0, "mcfcan.0", 8, MCF_CLK);
+DEFINE_CLK(0, "fec.0", 12, MCF_CLK);
+DEFINE_CLK(0, "edma", 17, MCF_CLK);
+DEFINE_CLK(0, "intc.0", 18, MCF_CLK);
+DEFINE_CLK(0, "intc.1", 19, MCF_CLK);
+DEFINE_CLK(0, "iack.0", 21, MCF_CLK);
+DEFINE_CLK(0, "mcfi2c.0", 22, MCF_CLK);
+DEFINE_CLK(0, "mcfqspi.0", 23, MCF_CLK);
+DEFINE_CLK(0, "mcfuart.0", 24, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.1", 25, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.2", 26, MCF_BUSCLK);
+DEFINE_CLK(0, "mcftmr.0", 28, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.1", 29, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.2", 30, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.3", 31, MCF_CLK);
+
+DEFINE_CLK(0, "mcfpit.0", 32, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.1", 33, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.2", 34, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.3", 35, MCF_CLK);
+DEFINE_CLK(0, "mcfpwm.0", 36, MCF_CLK);
+DEFINE_CLK(0, "mcfeport.0", 37, MCF_CLK);
+DEFINE_CLK(0, "mcfwdt.0", 38, MCF_CLK);
+DEFINE_CLK(0, "sys.0", 40, MCF_BUSCLK);
+DEFINE_CLK(0, "gpio.0", 41, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfrtc.0", 42, MCF_CLK);
+DEFINE_CLK(0, "mcflcd.0", 43, MCF_CLK);
+DEFINE_CLK(0, "mcfusb-otg.0", 44, MCF_CLK);
+DEFINE_CLK(0, "mcfusb-host.0", 45, MCF_CLK);
+DEFINE_CLK(0, "sdram.0", 46, MCF_CLK);
+DEFINE_CLK(0, "ssi.0", 47, MCF_CLK);
+DEFINE_CLK(0, "pll.0", 48, MCF_CLK);
+
+DEFINE_CLK(1, "mdha.0", 32, MCF_CLK);
+DEFINE_CLK(1, "skha.0", 33, MCF_CLK);
+DEFINE_CLK(1, "rng.0", 34, MCF_CLK);
+
+struct clk *mcf_clks[] = {
+	&__clk_0_2,	/* flexbus */
+	&__clk_0_8,	/* mcfcan.0 */
+	&__clk_0_12,	/* fec.0 */
+	&__clk_0_17,	/* edma */
+	&__clk_0_18,	/* intc.0 */
+	&__clk_0_19,	/* intc.1 */
+	&__clk_0_21,	/* iack.0 */
+	&__clk_0_22,	/* mcfi2c.0 */
+	&__clk_0_23,	/* mcfqspi.0 */
+	&__clk_0_24,	/* mcfuart.0 */
+	&__clk_0_25,	/* mcfuart.1 */
+	&__clk_0_26,	/* mcfuart.2 */
+	&__clk_0_28,	/* mcftmr.0 */
+	&__clk_0_29,	/* mcftmr.1 */
+	&__clk_0_30,	/* mcftmr.2 */
+	&__clk_0_31,	/* mcftmr.3 */
+
+	&__clk_0_32,	/* mcfpit.0 */
+	&__clk_0_33,	/* mcfpit.1 */
+	&__clk_0_34,	/* mcfpit.2 */
+	&__clk_0_35,	/* mcfpit.3 */
+	&__clk_0_36,	/* mcfpwm.0 */
+	&__clk_0_37,	/* mcfeport.0 */
+	&__clk_0_38,	/* mcfwdt.0 */
+	&__clk_0_40,	/* sys.0 */
+	&__clk_0_41,	/* gpio.0 */
+	&__clk_0_42,	/* mcfrtc.0 */
+	&__clk_0_43,	/* mcflcd.0 */
+	&__clk_0_44,	/* mcfusb-otg.0 */
+	&__clk_0_45,	/* mcfusb-host.0 */
+	&__clk_0_46,	/* sdram.0 */
+	&__clk_0_47,	/* ssi.0 */
+	&__clk_0_48,	/* pll.0 */
+
+	&__clk_1_32,	/* mdha.0 */
+	&__clk_1_33,	/* skha.0 */
+	&__clk_1_34,	/* rng.0 */
+	NULL,
+};
+
+static struct clk * const enable_clks[] __initconst = {
+	&__clk_0_2,	/* flexbus */
+	&__clk_0_18,	/* intc.0 */
+	&__clk_0_19,	/* intc.1 */
+	&__clk_0_21,	/* iack.0 */
+	&__clk_0_24,	/* mcfuart.0 */
+	&__clk_0_25,	/* mcfuart.1 */
+	&__clk_0_26,	/* mcfuart.2 */
+
+	&__clk_0_32,	/* mcfpit.0 */
+	&__clk_0_33,	/* mcfpit.1 */
+	&__clk_0_37,	/* mcfeport.0 */
+	&__clk_0_40,	/* sys.0 */
+	&__clk_0_41,	/* gpio.0 */
+	&__clk_0_46,	/* sdram.0 */
+	&__clk_0_48,	/* pll.0 */
+};
+
+static struct clk * const disable_clks[] __initconst = {
+	&__clk_0_8,	/* mcfcan.0 */
+	&__clk_0_12,	/* fec.0 */
+	&__clk_0_17,	/* edma */
+	&__clk_0_22,	/* mcfi2c.0 */
+	&__clk_0_23,	/* mcfqspi.0 */
+	&__clk_0_28,	/* mcftmr.0 */
+	&__clk_0_29,	/* mcftmr.1 */
+	&__clk_0_30,	/* mcftmr.2 */
+	&__clk_0_31,	/* mcftmr.3 */
+	&__clk_0_34,	/* mcfpit.2 */
+	&__clk_0_35,	/* mcfpit.3 */
+	&__clk_0_36,	/* mcfpwm.0 */
+	&__clk_0_38,	/* mcfwdt.0 */
+	&__clk_0_42,	/* mcfrtc.0 */
+	&__clk_0_43,	/* mcflcd.0 */
+	&__clk_0_44,	/* mcfusb-otg.0 */
+	&__clk_0_45,	/* mcfusb-host.0 */
+	&__clk_0_47,	/* ssi.0 */
+	&__clk_1_32,	/* mdha.0 */
+	&__clk_1_33,	/* skha.0 */
+	&__clk_1_34,	/* rng.0 */
 };
 
-unsigned int mcf_gpio_chips_size = ARRAY_SIZE(mcf_gpio_chips);
+
+static void __init m532x_clk_init(void)
+{
+	unsigned i;
+
+	/* make sure these clocks are enabled */
+	for (i = 0; i < ARRAY_SIZE(enable_clks); ++i)
+		__clk_init_enabled(enable_clks[i]);
+	/* make sure these clocks are disabled */
+	for (i = 0; i < ARRAY_SIZE(disable_clks); ++i)
+		__clk_init_disabled(disable_clks[i]);
+}
 
 /***************************************************************************/
 
@@ -98,8 +210,8 @@ void __init config_BSP(char *commandp, int size)
 		memset(commandp, 0, size);
 	}
 #endif
-
 	mach_sched_init = hw_timer_init;
+	m532x_clk_init();
 	m532x_uarts_init();
 	m532x_fec_init();
 #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
diff --git a/arch/m68k/platform/coldfire/m5407.c b/arch/m68k/platform/coldfire/m5407.c
index faa6680..bb6c746 100644
--- a/arch/m68k/platform/coldfire/m5407.c
+++ b/arch/m68k/platform/coldfire/m5407.c
@@ -16,15 +16,6 @@
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-/***************************************************************************/
-
-struct mcf_gpio_chip mcf_gpio_chips[] = {
-	MCFGPS(PP, 0, 16, MCFSIM_PADDR, MCFSIM_PADAT, MCFSIM_PADAT),
-};
-
-unsigned int mcf_gpio_chips_size = ARRAY_SIZE(mcf_gpio_chips);
 
 /***************************************************************************/
 
diff --git a/arch/m68k/platform/coldfire/m5441x.c b/arch/m68k/platform/coldfire/m5441x.c
new file mode 100644
index 0000000..98a13cc
--- /dev/null
+++ b/arch/m68k/platform/coldfire/m5441x.c
@@ -0,0 +1,261 @@
+/*
+ *	m5441x.c -- support for Coldfire m5441x processors
+ *
+ *	(C) Copyright Steven King <sfking@fdwdc.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfdma.h>
+#include <asm/mcfclk.h>
+
+DEFINE_CLK(0, "flexbus", 2, MCF_CLK);
+DEFINE_CLK(0, "mcfcan.0", 8, MCF_CLK);
+DEFINE_CLK(0, "mcfcan.1", 9, MCF_CLK);
+DEFINE_CLK(0, "mcfi2c.1", 14, MCF_CLK);
+DEFINE_CLK(0, "mcfdspi.1", 15, MCF_CLK);
+DEFINE_CLK(0, "edma", 17, MCF_CLK);
+DEFINE_CLK(0, "intc.0", 18, MCF_CLK);
+DEFINE_CLK(0, "intc.1", 19, MCF_CLK);
+DEFINE_CLK(0, "intc.2", 20, MCF_CLK);
+DEFINE_CLK(0, "mcfi2c.0", 22, MCF_CLK);
+DEFINE_CLK(0, "mcfdspi.0", 23, MCF_CLK);
+DEFINE_CLK(0, "mcfuart.0", 24, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.1", 25, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.2", 26, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.3", 27, MCF_BUSCLK);
+DEFINE_CLK(0, "mcftmr.0", 28, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.1", 29, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.2", 30, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.3", 31, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.0", 32, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.1", 33, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.2", 34, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.3", 35, MCF_CLK);
+DEFINE_CLK(0, "mcfeport.0", 37, MCF_CLK);
+DEFINE_CLK(0, "mcfadc.0", 38, MCF_CLK);
+DEFINE_CLK(0, "mcfdac.0", 39, MCF_CLK);
+DEFINE_CLK(0, "mcfrtc.0", 42, MCF_CLK);
+DEFINE_CLK(0, "mcfsim.0", 43, MCF_CLK);
+DEFINE_CLK(0, "mcfusb-otg.0", 44, MCF_CLK);
+DEFINE_CLK(0, "mcfusb-host.0", 45, MCF_CLK);
+DEFINE_CLK(0, "mcfddr-sram.0", 46, MCF_CLK);
+DEFINE_CLK(0, "mcfssi.0", 47, MCF_CLK);
+DEFINE_CLK(0, "pll.0", 48, MCF_CLK);
+DEFINE_CLK(0, "mcfrng.0", 49, MCF_CLK);
+DEFINE_CLK(0, "mcfssi.1", 50, MCF_CLK);
+DEFINE_CLK(0, "mcfsdhc.0", 51, MCF_CLK);
+DEFINE_CLK(0, "enet-fec.0", 53, MCF_CLK);
+DEFINE_CLK(0, "enet-fec.1", 54, MCF_CLK);
+DEFINE_CLK(0, "switch.0", 55, MCF_CLK);
+DEFINE_CLK(0, "switch.1", 56, MCF_CLK);
+DEFINE_CLK(0, "nand.0", 63, MCF_CLK);
+
+DEFINE_CLK(1, "mcfow.0", 2, MCF_CLK);
+DEFINE_CLK(1, "mcfi2c.2", 4, MCF_CLK);
+DEFINE_CLK(1, "mcfi2c.3", 5, MCF_CLK);
+DEFINE_CLK(1, "mcfi2c.4", 6, MCF_CLK);
+DEFINE_CLK(1, "mcfi2c.5", 7, MCF_CLK);
+DEFINE_CLK(1, "mcfuart.4", 24, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfuart.5", 25, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfuart.6", 26, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfuart.7", 27, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfuart.8", 28, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfuart.9", 29, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfpwm.0", 34, MCF_BUSCLK);
+DEFINE_CLK(1, "sys.0", 36, MCF_BUSCLK);
+DEFINE_CLK(1, "gpio.0", 37, MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+	&__clk_0_2,
+	&__clk_0_8,
+	&__clk_0_9,
+	&__clk_0_14,
+	&__clk_0_15,
+	&__clk_0_17,
+	&__clk_0_18,
+	&__clk_0_19,
+	&__clk_0_20,
+	&__clk_0_22,
+	&__clk_0_23,
+	&__clk_0_24,
+	&__clk_0_25,
+	&__clk_0_26,
+	&__clk_0_27,
+	&__clk_0_28,
+	&__clk_0_29,
+	&__clk_0_30,
+	&__clk_0_31,
+	&__clk_0_32,
+	&__clk_0_33,
+	&__clk_0_34,
+	&__clk_0_35,
+	&__clk_0_37,
+	&__clk_0_38,
+	&__clk_0_39,
+	&__clk_0_42,
+	&__clk_0_43,
+	&__clk_0_44,
+	&__clk_0_45,
+	&__clk_0_46,
+	&__clk_0_47,
+	&__clk_0_48,
+	&__clk_0_49,
+	&__clk_0_50,
+	&__clk_0_51,
+	&__clk_0_53,
+	&__clk_0_54,
+	&__clk_0_55,
+	&__clk_0_56,
+	&__clk_0_63,
+
+	&__clk_1_2,
+	&__clk_1_4,
+	&__clk_1_5,
+	&__clk_1_6,
+	&__clk_1_7,
+	&__clk_1_24,
+	&__clk_1_25,
+	&__clk_1_26,
+	&__clk_1_27,
+	&__clk_1_28,
+	&__clk_1_29,
+	&__clk_1_34,
+	&__clk_1_36,
+	&__clk_1_37,
+	NULL,
+};
+
+
+static struct clk * const enable_clks[] __initconst = {
+	/* make sure these clocks are enabled */
+	&__clk_0_18, /* intc0 */
+	&__clk_0_19, /* intc0 */
+	&__clk_0_20, /* intc0 */
+	&__clk_0_24, /* uart0 */
+	&__clk_0_25, /* uart1 */
+	&__clk_0_26, /* uart2 */
+	&__clk_0_27, /* uart3 */
+
+	&__clk_0_33, /* pit.1 */
+	&__clk_0_37, /* eport */
+	&__clk_0_48, /* pll */
+
+	&__clk_1_36, /* CCM/reset module/Power management */
+	&__clk_1_37, /* gpio */
+};
+static struct clk * const disable_clks[] __initconst = {
+	&__clk_0_8, /* can.0 */
+	&__clk_0_9, /* can.1 */
+	&__clk_0_14, /* i2c.1 */
+	&__clk_0_15, /* dspi.1 */
+	&__clk_0_17, /* eDMA */
+	&__clk_0_22, /* i2c.0 */
+	&__clk_0_23, /* dspi.0 */
+	&__clk_0_28, /* tmr.1 */
+	&__clk_0_29, /* tmr.2 */
+	&__clk_0_30, /* tmr.2 */
+	&__clk_0_31, /* tmr.3 */
+	&__clk_0_32, /* pit.0 */
+	&__clk_0_34, /* pit.2 */
+	&__clk_0_35, /* pit.3 */
+	&__clk_0_38, /* adc */
+	&__clk_0_39, /* dac */
+	&__clk_0_44, /* usb otg */
+	&__clk_0_45, /* usb host */
+	&__clk_0_47, /* ssi.0 */
+	&__clk_0_49, /* rng */
+	&__clk_0_50, /* ssi.1 */
+	&__clk_0_51, /* eSDHC */
+	&__clk_0_53, /* enet-fec */
+	&__clk_0_54, /* enet-fec */
+	&__clk_0_55, /* switch.0 */
+	&__clk_0_56, /* switch.1 */
+
+	&__clk_1_2, /* 1-wire */
+	&__clk_1_4, /* i2c.2 */
+	&__clk_1_5, /* i2c.3 */
+	&__clk_1_6, /* i2c.4 */
+	&__clk_1_7, /* i2c.5 */
+	&__clk_1_24, /* uart 4 */
+	&__clk_1_25, /* uart 5 */
+	&__clk_1_26, /* uart 6 */
+	&__clk_1_27, /* uart 7 */
+	&__clk_1_28, /* uart 8 */
+	&__clk_1_29, /* uart 9 */
+};
+
+static void __init m5441x_clk_init(void)
+{
+	unsigned i;
+
+	for (i = 0; i < ARRAY_SIZE(enable_clks); ++i)
+		__clk_init_enabled(enable_clks[i]);
+	/* make sure these clocks are disabled */
+	for (i = 0; i < ARRAY_SIZE(disable_clks); ++i)
+		__clk_init_disabled(disable_clks[i]);
+}
+
+static void __init m5441x_uarts_init(void)
+{
+	__raw_writeb(0x0f, MCFGPIO_PAR_UART0);
+	__raw_writeb(0x00, MCFGPIO_PAR_UART1);
+	__raw_writeb(0x00, MCFGPIO_PAR_UART2);
+}
+
+static void __init m5441x_fec_init(void)
+{
+	__raw_writeb(0x03, MCFGPIO_PAR_FEC);
+}
+
+void __init config_BSP(char *commandp, int size)
+{
+	m5441x_clk_init();
+	mach_sched_init = hw_timer_init;
+	m5441x_uarts_init();
+	m5441x_fec_init();
+}
+
+
+#if IS_ENABLED(CONFIG_RTC_DRV_M5441x)
+static struct resource m5441x_rtc_resources[] = {
+	{
+		.start		= MCFRTC_BASE,
+		.end		= MCFRTC_BASE + MCFRTC_SIZE - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= MCF_IRQ_RTC,
+		.end		= MCF_IRQ_RTC,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device m5441x_rtc = {
+	.name			= "mcfrtc",
+	.id			= 0,
+	.resource		= m5441x_rtc_resources,
+	.num_resources		= ARRAY_SIZE(m5441x_rtc_resources),
+};
+#endif
+
+static struct platform_device *m5441x_devices[] __initdata = {
+#if IS_ENABLED(CONFIG_RTC_DRV_M5441x)
+	&m5441x_rtc,
+#endif
+};
+
+static int __init init_BSP(void)
+{
+	platform_add_devices(m5441x_devices, ARRAY_SIZE(m5441x_devices));
+	return 0;
+}
+
+arch_initcall(init_BSP);
diff --git a/arch/m68k/platform/coldfire/m54xx.c b/arch/m68k/platform/coldfire/m54xx.c
index 20672da..2081c6c 100644
--- a/arch/m68k/platform/coldfire/m54xx.c
+++ b/arch/m68k/platform/coldfire/m54xx.c
@@ -21,19 +21,12 @@
 #include <asm/m54xxsim.h>
 #include <asm/mcfuart.h>
 #include <asm/m54xxgpt.h>
-#include <asm/mcfgpio.h>
 #ifdef CONFIG_MMU
 #include <asm/mmu_context.h>
 #endif
 
 /***************************************************************************/
 
-struct mcf_gpio_chip mcf_gpio_chips[] = { };
-
-unsigned int mcf_gpio_chips_size = ARRAY_SIZE(mcf_gpio_chips);
-
-/***************************************************************************/
-
 static void __init m54xx_uarts_init(void)
 {
 	/* enable io pins */
diff --git a/arch/m68k/platform/coldfire/pinmux.c b/arch/m68k/platform/coldfire/pinmux.c
deleted file mode 100644
index 8c62b82..0000000
--- a/arch/m68k/platform/coldfire/pinmux.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Coldfire generic GPIO pinmux support.
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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/kernel.h>
-
-#include <asm/pinmux.h>
-
-int mcf_pinmux_request(unsigned pinmux, unsigned func)
-{
-	return 0;
-}
-
-void mcf_pinmux_release(unsigned pinmux, unsigned func)
-{
-}
diff --git a/arch/m68k/platform/coldfire/pit.c b/arch/m68k/platform/coldfire/pit.c
index e62dbbc..e8f3b97 100644
--- a/arch/m68k/platform/coldfire/pit.c
+++ b/arch/m68k/platform/coldfire/pit.c
@@ -93,7 +93,7 @@ struct clock_event_device cf_pit_clockevent = {
 	.set_mode	= init_cf_pit_timer,
 	.set_next_event	= cf_pit_next_event,
 	.shift		= 32,
-	.irq		= MCFINT_VECBASE + MCFINT_PIT1,
+	.irq		= MCF_IRQ_PIT1,
 };
 
 
@@ -159,7 +159,7 @@ void hw_timer_init(irq_handler_t handler)
 		clockevent_delta2ns(0x3f, &cf_pit_clockevent);
 	clockevents_register_device(&cf_pit_clockevent);
 
-	setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq);
+	setup_irq(MCF_IRQ_PIT1, &pit_irq);
 
 	clocksource_register_hz(&pit_clk, FREQ);
 }
diff --git a/arch/m68k/platform/coldfire/timers.c b/arch/m68k/platform/coldfire/timers.c
index ed96ce5..0a273e7 100644
--- a/arch/m68k/platform/coldfire/timers.c
+++ b/arch/m68k/platform/coldfire/timers.c
@@ -36,7 +36,7 @@
  */
 void coldfire_profile_init(void);
 
-#if defined(CONFIG_M532x)
+#if defined(CONFIG_M532x) || defined(CONFIG_M5441x)
 #define	__raw_readtrr	__raw_readl
 #define	__raw_writetrr	__raw_writel
 #else
diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h
index 6c610234..008f304 100644
--- a/arch/microblaze/include/asm/thread_info.h
+++ b/arch/microblaze/include/asm/thread_info.h
@@ -121,7 +121,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_NEED_RESCHED	3 /* rescheduling necessary */
 /* restore singlestep on return to user mode */
 #define TIF_SINGLESTEP		4
-#define TIF_IRET		5 /* return with iret */
 #define TIF_MEMDIE		6	/* is terminating due to OOM killer */
 #define TIF_SYSCALL_AUDIT	9       /* syscall auditing active */
 #define TIF_SECCOMP		10      /* secure computing */
@@ -134,7 +133,6 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
-#define _TIF_IRET		(1 << TIF_IRET)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
@@ -184,6 +182,7 @@ static inline bool test_and_clear_restore_sigmask(void)
 	ti->status &= ~TS_RESTORE_SIGMASK;
 	return true;
 }
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
 #endif
 
 #endif /* __KERNEL__ */
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S
index 75c3ea1..4c3815f 100644
--- a/arch/microblaze/kernel/entry-nommu.S
+++ b/arch/microblaze/kernel/entry-nommu.S
@@ -124,6 +124,7 @@ ret_from_intr:
 	lwi	r11, r1, PT_MODE
 	bneid	r11, no_intr_resched
 
+3:
 	lwi	r6, r31, TS_THREAD_INFO	/* get thread info */
 	lwi	r19, r6, TI_FLAGS	/* get flags in thread info */
 				/* do an extra work if any bits are set */
@@ -132,11 +133,13 @@ ret_from_intr:
 	beqi	r11, 1f
 	bralid	r15, schedule
 	nop
+	bri	3b
 1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
 	beqid	r11, no_intr_resched
 	addk	r5, r1, r0
 	bralid	r15, do_notify_resume
 	addk	r6, r0, r0
+	bri	3b
 
 no_intr_resched:
 	/* Disable interrupts, we are now committed to the state restore */
@@ -280,6 +283,7 @@ ENTRY(_user_exception)
 	/* Figure out which function to use for this system call. */
 	/* Note Microblaze barrel shift is optional, so don't rely on it */
 	add	r12, r12, r12			/* convert num -> ptr */
+	addik	r30, r0, 1			/* restarts allowed */
 	add	r12, r12, r12
 	lwi	r12, r12, sys_call_table	/* Get function pointer */
 	addik	r15, r0, ret_to_user-8		/* set return address */
@@ -369,6 +373,7 @@ ENTRY(_debug_exception)
 	bralid	r15, send_sig
 	add	r7, r0, r0			/* 3rd param zero */
 
+	addik	r30, r0, 1			/* restarts allowed ??? */
 	/* Restore r3/r4 to work around how ret_to_user works */
 	lwi	r3, r1, PT_R3
 	lwi	r4, r1, PT_R4
@@ -475,18 +480,26 @@ ENTRY(ret_from_fork)
 	nop
 
 work_pending:
+	lwi	r11, r1, PT_MODE
+	bneid	r11, 2f
+3:
 	enable_irq
-
 	andi	r11, r19, _TIF_NEED_RESCHED
 	beqi	r11, 1f
 	bralid	r15, schedule
 	nop
+	bri	4f
 1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
 	beqi	r11, no_work_pending
-	addk	r5, r1, r0
+	addk	r5, r30, r0
 	bralid	r15, do_notify_resume
 	addik	r6, r0, 1
-	bri	no_work_pending
+	addk	r30, r0, r0	/* no restarts from now on */
+4:
+	disable_irq
+	lwi	r6, r31, TS_THREAD_INFO /* get thread info */
+	lwi	r19, r6, TI_FLAGS /* get flags in thread info */
+	bri	3b
 
 ENTRY(ret_to_user)
 	disable_irq
@@ -500,6 +513,7 @@ ENTRY(ret_to_user)
 no_work_pending:
 	disable_irq
 
+2:
 	/* save r31 */
 	swi	r31, r0, PER_CPU(CURRENT_SAVE)
 	/* save mode indicator */
@@ -564,6 +578,7 @@ sys_execve:
 	addk	r8, r1, r0
 
 sys_rt_sigreturn_wrapper:
+	addk	r30, r0, r0		/* no restarts for this one */
 	brid	sys_rt_sigreturn
 	addk	r5, r1, r0
 
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
index 03f7b8c..82ed20d 100644
--- a/arch/microblaze/kernel/entry.S
+++ b/arch/microblaze/kernel/entry.S
@@ -371,6 +371,7 @@ C_ENTRY(_user_exception):
 	/* Figure out which function to use for this system call.  */
 	/* Note Microblaze barrel shift is optional, so don't rely on it */
 	add	r12, r12, r12;			/* convert num -> ptr */
+	addi	r30, r0, 1			/* restarts allowed */
 	add	r12, r12, r12;
 
 #ifdef DEBUG
@@ -419,26 +420,27 @@ C_ENTRY(ret_from_trap):
 	 * trigger rescheduling. */
 	/* get thread info from current task */
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
-	lwi	r11, r11, TI_FLAGS;		/* get flags in thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS;		/* get flags in thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f;
 
 	bralid	r15, schedule;	/* Call scheduler */
 	nop;				/* delay slot */
+	bri	1b
 
 	/* Maybe handle a signal */
-5:	/* get thread info from current task*/
-	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
-	beqi	r11, 1f;		/* Signals to handle, handle them */
+5:	
+	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+	beqi	r11, 4f;		/* Signals to handle, handle them */
 
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
-	addi	r6, r0, 1;		/* Arg 2: int in_syscall */
+	add	r6, r30, r0;		/* Arg 2: int in_syscall */
+	add	r30, r0, r0		/* no more restarts */
+	bri	1b
 
 /* Finally, return to user state.  */
-1:	set_bip;			/*  Ints masked for state restore */
+4:	set_bip;			/*  Ints masked for state restore */
 	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	VM_OFF;
 	tophys(r1,r1);
@@ -503,6 +505,7 @@ C_ENTRY(sys_execve):
 	addik	r8, r1, 0;		/* add user context as 4th arg */
 
 C_ENTRY(sys_rt_sigreturn_wrapper):
+	addik	r30, r0, r0		/* no restarts */
 	brid	sys_rt_sigreturn	/* Do real work */
 	addik	r5, r1, 0;		/* add user context as 1st arg */
 
@@ -610,20 +613,20 @@ C_ENTRY(ret_from_exc):
 
 	/* We're returning to user mode, so check for various conditions that
 	   trigger rescheduling. */
+1:
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS;	/* get flags in thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f;
 
 /* Call the scheduler before returning from a syscall/trap. */
 	bralid	r15, schedule;	/* Call scheduler */
 	nop;				/* delay slot */
+	bri	1b
 
 	/* Maybe handle a signal */
-5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
-	beqi	r11, 1f;		/* Signals to handle, handle them */
+5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+	beqi	r11, 4f;		/* Signals to handle, handle them */
 
 	/*
 	 * Handle a signal return; Pending signals should be in r18.
@@ -639,9 +642,10 @@ C_ENTRY(ret_from_exc):
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	addi	r6, r0, 0;		/* Arg 2: int in_syscall */
+	bri	1b
 
 /* Finally, return to user state.  */
-1:	set_bip;			/* Ints masked for state restore */
+4:	set_bip;			/* Ints masked for state restore */
 	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	VM_OFF;
 	tophys(r1,r1);
@@ -721,22 +725,23 @@ ret_from_irq:
 	lwi	r11, r1, PT_MODE;
 	bnei	r11, 2f;
 
+1:
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
-	lwi	r11, r11, TI_FLAGS; /* MS: get flags from thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS; /* MS: get flags from thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f
 	bralid	r15, schedule;
 	nop; /* delay slot */
+	bri	1b
 
     /* Maybe handle a signal */
-5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */
-	lwi	r11, r11, TI_FLAGS; /* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
 	beqid	r11, no_intr_resched
 /* Handle a signal return; Pending signals should be in r18. */
 	addik	r5, r1, 0; /* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	addi	r6, r0, 0; /* Arg 2: int in_syscall */
+	bri	1b
 
 /* Finally, return to user state. */
 no_intr_resched:
@@ -854,28 +859,29 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
 	lwi	r11, r1, PT_MODE;
 	bnei	r11, 2f;
 /* MS: Return to user space - gdb */
+1:
 	/* Get current task ptr into r11 */
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS;	/* get flags in thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f;
 
 	/* Call the scheduler before returning from a syscall/trap. */
 	bralid	r15, schedule;	/* Call scheduler */
 	nop;				/* delay slot */
+	bri	1b
 
 	/* Maybe handle a signal */
-5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
-	beqi	r11, 1f;		/* Signals to handle, handle them */
+5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+	beqi	r11, 4f;		/* Signals to handle, handle them */
 
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	addi  r6, r0, 0;	/* Arg 2: int in_syscall */
+	bri	1b
 
 /* Finally, return to user state.  */
-1:	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
+4:	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	VM_OFF;
 	tophys(r1,r1);
 	/* MS: Restore all regs */
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
index 76b9722..a7a501e 100644
--- a/arch/microblaze/kernel/signal.c
+++ b/arch/microblaze/kernel/signal.c
@@ -254,10 +254,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 
 	set_fs(USER_DS);
 
-	/* the tracer may want to single-step inside the handler */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 #ifdef DEBUG_SIG
 	printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
 		current->comm, current->pid, frame, regs->pc);
@@ -323,7 +319,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
 	if (ret)
 		return;
 
-	signal_delivered(sig, info, ka, regs, 0);
+	signal_delivered(sig, info, ka, regs,
+			test_thread_flag(TIF_SINGLESTEP));
 }
 
 /*
@@ -367,15 +364,6 @@ static void do_signal(struct pt_regs *regs, int in_syscall)
 
 void do_notify_resume(struct pt_regs *regs, int in_syscall)
 {
-	/*
-	 * We want the common case to go fast, which
-	 * is why we may in certain cases get here from
-	 * kernel mode. Just return without doing anything
-	 * if so.
-	 */
-	if (kernel_mode(regs))
-		return;
-
 	if (test_thread_flag(TIF_SIGPENDING))
 		do_signal(regs, in_syscall);
 
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index ed22bfc..d9f5986 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -249,8 +249,7 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
 	} else {
 		pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
 			 oirq.size, oirq.specifier[0], oirq.specifier[1],
-			 oirq.controller ? oirq.controller->full_name :
-			 "<default>");
+			 of_node_full_name(oirq.controller));
 
 		virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
 					     oirq.size);
@@ -1493,8 +1492,7 @@ static void __devinit pcibios_scan_phb(struct pci_controller *hose)
 	struct pci_bus *bus;
 	struct device_node *node = hose->dn;
 
-	pr_debug("PCI: Scanning PHB %s\n",
-		 node ? node->full_name : "<NO NAME>");
+	pr_debug("PCI: Scanning PHB %s\n", of_node_full_name(node));
 
 	pcibios_setup_phb_resources(hose, &resources);
 
@@ -1506,10 +1504,10 @@ static void __devinit pcibios_scan_phb(struct pci_controller *hose)
 		pci_free_resource_list(&resources);
 		return;
 	}
-	bus->secondary = hose->first_busno;
+	bus->busn_res.start = hose->first_busno;
 	hose->bus = bus;
 
-	hose->last_busno = bus->subordinate;
+	hose->last_busno = bus->busn_res.end;
 }
 
 static int __init pcibios_init(void)
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
index 5ce8029..d64786d 100644
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -14,6 +14,7 @@ platforms += jz4740
 platforms += lantiq
 platforms += lasat
 platforms += loongson
+platforms += loongson1
 platforms += mipssim
 platforms += mti-malta
 platforms += netlogic
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 09ab87e..61e1459 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -209,6 +209,7 @@ config MACH_JZ4740
 	select SYS_HAS_CPU_MIPS32_R1
 	select SYS_SUPPORTS_32BIT_KERNEL
 	select SYS_SUPPORTS_LITTLE_ENDIAN
+	select SYS_SUPPORTS_ZBOOT_UART16550
 	select DMA_NONCOHERENT
 	select IRQ_CPU
 	select GENERIC_GPIO
@@ -264,6 +265,17 @@ config MACH_LOONGSON
 	  Chinese Academy of Sciences (CAS) in the People's Republic
 	  of China. The chief architect is Professor Weiwu Hu.
 
+config MACH_LOONGSON1
+	bool "Loongson1 family of machines"
+	select SYS_SUPPORTS_ZBOOT
+	help
+	  This enables the support of Loongson1 family of machines.
+
+	  Loongson1 is a family of 32-bit MIPS-compatible SoCs.
+	  developed at Institute of Computing Technology (ICT),
+	  Chinese Academy of Sciences (CAS) in the People's Republic
+	  of China.
+
 config MIPS_MALTA
 	bool "MIPS Malta board"
 	select ARCH_MAY_HAVE_PC_FDC
@@ -288,6 +300,7 @@ config MIPS_MALTA
 	select SYS_HAS_CPU_MIPS32_R1
 	select SYS_HAS_CPU_MIPS32_R2
 	select SYS_HAS_CPU_MIPS64_R1
+	select SYS_HAS_CPU_MIPS64_R2
 	select SYS_HAS_CPU_NEVADA
 	select SYS_HAS_CPU_RM7000
 	select SYS_HAS_EARLY_PRINTK
@@ -786,6 +799,8 @@ config NLM_XLR_BOARD
 	select ZONE_DMA if 64BIT
 	select SYNC_R4K
 	select SYS_HAS_EARLY_PRINTK
+	select USB_ARCH_HAS_OHCI if USB_SUPPORT
+	select USB_ARCH_HAS_EHCI if USB_SUPPORT
 	help
 	  Support for systems based on Netlogic XLR and XLS processors.
 	  Say Y here if you have a XLR or XLS based board.
@@ -798,7 +813,6 @@ config NLM_XLP_BOARD
 	select SYS_HAS_CPU_XLP
 	select SYS_SUPPORTS_SMP
 	select HW_HAS_PCI
-	select SWAP_IO_SPACE
 	select SYS_SUPPORTS_32BIT_KERNEL
 	select SYS_SUPPORTS_64BIT_KERNEL
 	select 64BIT_PHYS_ADDR
@@ -835,6 +849,7 @@ source "arch/mips/txx9/Kconfig"
 source "arch/mips/vr41xx/Kconfig"
 source "arch/mips/cavium-octeon/Kconfig"
 source "arch/mips/loongson/Kconfig"
+source "arch/mips/loongson1/Kconfig"
 source "arch/mips/netlogic/Kconfig"
 
 endmenu
@@ -1216,6 +1231,14 @@ config CPU_LOONGSON2F
 	  have a similar programming interface with FPGA northbridge used in
 	  Loongson2E.
 
+config CPU_LOONGSON1B
+	bool "Loongson 1B"
+	depends on SYS_HAS_CPU_LOONGSON1B
+	select CPU_LOONGSON1
+	help
+	  The Loongson 1B is a 32-bit SoC, which implements the MIPS32
+	  release 2 instruction set.
+
 config CPU_MIPS32_R1
 	bool "MIPS32 Release 1"
 	depends on SYS_HAS_CPU_MIPS32_R1
@@ -1423,6 +1446,7 @@ config CPU_SB1
 config CPU_CAVIUM_OCTEON
 	bool "Cavium Octeon processor"
 	depends on SYS_HAS_CPU_CAVIUM_OCTEON
+	select ARCH_SPARSEMEM_ENABLE
 	select CPU_HAS_PREFETCH
 	select CPU_SUPPORTS_64BIT_KERNEL
 	select SYS_SUPPORTS_SMP
@@ -1430,6 +1454,8 @@ config CPU_CAVIUM_OCTEON
 	select WEAK_ORDERING
 	select CPU_SUPPORTS_HIGHMEM
 	select CPU_SUPPORTS_HUGEPAGES
+	select LIBFDT
+	select USE_OF
 	help
 	  The Cavium Octeon processor is a highly integrated chip containing
 	  many ethernet hardware widgets for networking tasks. The processor
@@ -1542,6 +1568,14 @@ config CPU_LOONGSON2
 	select CPU_SUPPORTS_64BIT_KERNEL
 	select CPU_SUPPORTS_HIGHMEM
 
+config CPU_LOONGSON1
+	bool
+	select CPU_MIPS32
+	select CPU_MIPSR2
+	select CPU_HAS_PREFETCH
+	select CPU_SUPPORTS_32BIT_KERNEL
+	select CPU_SUPPORTS_HIGHMEM
+
 config CPU_BMIPS
 	bool
 	select CPU_MIPS32
@@ -1560,6 +1594,9 @@ config SYS_HAS_CPU_LOONGSON2F
 	select CPU_SUPPORTS_ADDRWINCFG if 64BIT
 	select CPU_SUPPORTS_UNCACHED_ACCELERATED
 
+config SYS_HAS_CPU_LOONGSON1B
+	bool
+
 config SYS_HAS_CPU_MIPS32_R1
 	bool
 
@@ -2364,6 +2401,8 @@ config PCI_DOMAINS
 
 source "drivers/pci/Kconfig"
 
+source "drivers/pci/pcie/Kconfig"
+
 #
 # ISA support is now enabled via select.  Too many systems still have the one
 # or other ISA chip on the board that users don't know about so don't expect
diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c
index 295f1a9..9996948 100644
--- a/arch/mips/alchemy/board-mtx1.c
+++ b/arch/mips/alchemy/board-mtx1.c
@@ -81,10 +81,10 @@ static void mtx1_power_off(void)
 
 void __init board_setup(void)
 {
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#if IS_ENABLED(CONFIG_USB_OHCI_HCD)
 	/* Enable USB power switch */
 	alchemy_gpio_direction_output(204, 0);
-#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */
+#endif /* IS_ENABLED(CONFIG_USB_OHCI_HCD) */
 
 	/* Initialize sys_pinfunc */
 	au_writel(SYS_PF_NI2, SYS_PINFUNC);
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index 95cb911..c0f3ce6 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -334,13 +334,12 @@ static void __init alchemy_setup_macs(int ctype)
 	if (alchemy_get_macs(ctype) < 1)
 		return;
 
-	macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
+	macres = kmemdup(au1xxx_eth0_resources[ctype],
+			 sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
 	if (!macres) {
 		printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n");
 		return;
 	}
-	memcpy(macres, au1xxx_eth0_resources[ctype],
-	       sizeof(struct resource) * MAC_RES_COUNT);
 	au1xxx_eth0_device.resource = macres;
 
 	i = prom_get_ethernet_addr(ethaddr);
@@ -356,13 +355,12 @@ static void __init alchemy_setup_macs(int ctype)
 	if (alchemy_get_macs(ctype) < 2)
 		return;
 
-	macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
+	macres = kmemdup(au1xxx_eth1_resources[ctype],
+			 sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
 	if (!macres) {
 		printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n");
 		return;
 	}
-	memcpy(macres, au1xxx_eth1_resources[ctype],
-	       sizeof(struct resource) * MAC_RES_COUNT);
 	au1xxx_eth1_device.resource = macres;
 
 	ethaddr[5] += 1;	/* next addr for 2nd MAC */
diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile
index 3c37fb3..c9e747d 100644
--- a/arch/mips/alchemy/devboards/Makefile
+++ b/arch/mips/alchemy/devboards/Makefile
@@ -2,7 +2,7 @@
 # Alchemy Develboards
 #
 
-obj-y += prom.o bcsr.o platform.o
+obj-y += bcsr.o platform.o
 obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_MIPS_PB1100)	+= pb1100.o
 obj-$(CONFIG_MIPS_PB1500)	+= pb1500.o
diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c
index 1e83ce2..f2039ef 100644
--- a/arch/mips/alchemy/devboards/bcsr.c
+++ b/arch/mips/alchemy/devboards/bcsr.c
@@ -90,10 +90,7 @@ static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d)
 	unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT);
 
 	disable_irq_nosync(irq);
-
-	for ( ; bisr; bisr &= bisr - 1)
-		generic_handle_irq(bcsr_csc_base + __ffs(bisr));
-
+	generic_handle_irq(bcsr_csc_base + __ffs(bisr));
 	enable_irq(irq);
 }
 
diff --git a/arch/mips/alchemy/devboards/pb1100.c b/arch/mips/alchemy/devboards/pb1100.c
index cff50d0..78c77a4 100644
--- a/arch/mips/alchemy/devboards/pb1100.c
+++ b/arch/mips/alchemy/devboards/pb1100.c
@@ -46,7 +46,7 @@ void __init board_setup(void)
 	alchemy_gpio1_input_enable();
 	udelay(100);
 
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#if IS_ENABLED(CONFIG_USB_OHCI_HCD)
 	{
 		u32 pin_func, sys_freqctrl, sys_clksrc;
 
@@ -93,7 +93,7 @@ void __init board_setup(void)
 		pin_func |= SYS_PF_USB;
 		au_writel(pin_func, SYS_PINFUNC);
 	}
-#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */
+#endif /* IS_ENABLED(CONFIG_USB_OHCI_HCD) */
 
 	/* Enable sys bus clock divider when IDLE state or no bus activity. */
 	au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
diff --git a/arch/mips/alchemy/devboards/pb1500.c b/arch/mips/alchemy/devboards/pb1500.c
index e7b807b..232fee9 100644
--- a/arch/mips/alchemy/devboards/pb1500.c
+++ b/arch/mips/alchemy/devboards/pb1500.c
@@ -53,7 +53,7 @@ void __init board_setup(void)
 	alchemy_gpio_direction_input(201);
 	alchemy_gpio_direction_input(203);
 
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#if IS_ENABLED(CONFIG_USB_OHCI_HCD)
 
 	/* Zero and disable FREQ2 */
 	sys_freqctrl = au_readl(SYS_FREQCTRL0);
@@ -87,7 +87,7 @@ void __init board_setup(void)
 	/* 2nd USB port is USB host */
 	pin_func |= SYS_PF_USB;
 	au_writel(pin_func, SYS_PINFUNC);
-#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */
+#endif /* IS_ENABLED(CONFIG_USB_OHCI_HCD) */
 
 #ifdef CONFIG_PCI
 	{
diff --git a/arch/mips/alchemy/devboards/platform.c b/arch/mips/alchemy/devboards/platform.c
index 621f70a..f39042e 100644
--- a/arch/mips/alchemy/devboards/platform.c
+++ b/arch/mips/alchemy/devboards/platform.c
@@ -10,9 +10,39 @@
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 
+#include <asm/bootinfo.h>
 #include <asm/reboot.h>
+#include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-db1x00/bcsr.h>
 
+#include <prom.h>
+
+void __init prom_init(void)
+{
+	unsigned char *memsize_str;
+	unsigned long memsize;
+
+	prom_argc = (int)fw_arg0;
+	prom_argv = (char **)fw_arg1;
+	prom_envp = (char **)fw_arg2;
+
+	prom_init_cmdline();
+	memsize_str = prom_getenv("memsize");
+	if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
+		memsize = 64 << 20; /* all devboards have at least 64MB RAM */
+
+	add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+void prom_putchar(unsigned char c)
+{
+#ifdef CONFIG_MIPS_DB1300
+	alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c);
+#else
+	alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
+#endif
+}
+
 
 static struct platform_device db1x00_rtc_dev = {
 	.name	= "rtc-au1xxx",
diff --git a/arch/mips/alchemy/devboards/prom.c b/arch/mips/alchemy/devboards/prom.c
deleted file mode 100644
index 93a2210..0000000
--- a/arch/mips/alchemy/devboards/prom.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Common code used by all Alchemy develboards.
- *
- * Extracted from files which had this to say:
- *
- * Copyright 2000, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/bootinfo.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <prom.h>
-
-#if defined(CONFIG_MIPS_DB1000) || \
-    defined(CONFIG_MIPS_PB1100) || \
-    defined(CONFIG_MIPS_PB1500)
-#define ALCHEMY_BOARD_DEFAULT_MEMSIZE	0x04000000
-
-#else	/* Au1550/Au1200-based develboards */
-#define ALCHEMY_BOARD_DEFAULT_MEMSIZE	0x08000000
-#endif
-
-void __init prom_init(void)
-{
-	unsigned char *memsize_str;
-	unsigned long memsize;
-
-	prom_argc = (int)fw_arg0;
-	prom_argv = (char **)fw_arg1;
-	prom_envp = (char **)fw_arg2;
-
-	prom_init_cmdline();
-	memsize_str = prom_getenv("memsize");
-	if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize))
-		memsize = ALCHEMY_BOARD_DEFAULT_MEMSIZE;
-
-	add_memory_region(0, memsize, BOOT_MEM_RAM);
-}
-
-void prom_putchar(unsigned char c)
-{
-#ifdef CONFIG_MIPS_DB1300
-	alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c);
-#else
-	alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
-#endif
-}
diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
index 6210b8d..b311be4 100644
--- a/arch/mips/bcm47xx/Kconfig
+++ b/arch/mips/bcm47xx/Kconfig
@@ -21,6 +21,7 @@ config BCM47XX_BCMA
 	select BCMA
 	select BCMA_HOST_SOC
 	select BCMA_DRIVER_MIPS
+	select BCMA_HOST_PCI if PCI
 	select BCMA_DRIVER_PCI_HOSTMODE if PCI
 	default y
 	help
diff --git a/arch/mips/bcm63xx/Kconfig b/arch/mips/bcm63xx/Kconfig
index 6b1b9ad..d03e879 100644
--- a/arch/mips/bcm63xx/Kconfig
+++ b/arch/mips/bcm63xx/Kconfig
@@ -1,6 +1,10 @@
 menu "CPU support"
 	depends on BCM63XX
 
+config BCM63XX_CPU_6328
+	bool "support 6328 CPU"
+	select HW_HAS_PCI
+
 config BCM63XX_CPU_6338
 	bool "support 6338 CPU"
 	select HW_HAS_PCI
diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile
index 6dfdc69..833af72 100644
--- a/arch/mips/bcm63xx/Makefile
+++ b/arch/mips/bcm63xx/Makefile
@@ -1,5 +1,6 @@
 obj-y		+= clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \
-		   dev-dsp.o dev-enet.o dev-pcmcia.o dev-uart.o dev-wdt.o
+		   dev-dsp.o dev-enet.o dev-flash.o dev-pcmcia.o dev-rng.o \
+		   dev-spi.o dev-uart.o dev-wdt.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 
 obj-y		+= boards/
diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c
index 2f1773f..feb0525 100644
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -11,9 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
 #include <linux/ssb/ssb.h>
 #include <asm/addrspace.h>
 #include <bcm63xx_board.h>
@@ -24,7 +21,9 @@
 #include <bcm63xx_dev_pci.h>
 #include <bcm63xx_dev_enet.h>
 #include <bcm63xx_dev_dsp.h>
+#include <bcm63xx_dev_flash.h>
 #include <bcm63xx_dev_pcmcia.h>
+#include <bcm63xx_dev_spi.h>
 #include <board_bcm963xx.h>
 
 #define PFX	"board_bcm963xx: "
@@ -34,6 +33,48 @@ static unsigned int mac_addr_used;
 static struct board_info board;
 
 /*
+ * known 6328 boards
+ */
+#ifdef CONFIG_BCM63XX_CPU_6328
+static struct board_info __initdata board_96328avng = {
+	.name				= "96328avng",
+	.expected_cpu_id		= 0x6328,
+
+	.has_uart0			= 1,
+	.has_pci			= 1,
+
+	.leds = {
+		{
+			.name		= "96328avng::ppp-fail",
+			.gpio		= 2,
+			.active_low	= 1,
+		},
+		{
+			.name		= "96328avng::power",
+			.gpio		= 4,
+			.active_low	= 1,
+			.default_trigger = "default-on",
+		},
+		{
+			.name		= "96328avng::power-fail",
+			.gpio		= 8,
+			.active_low	= 1,
+		},
+		{
+			.name		= "96328avng::wps",
+			.gpio		= 9,
+			.active_low	= 1,
+		},
+		{
+			.name		= "96328avng::ppp",
+			.gpio		= 11,
+			.active_low	= 1,
+		},
+	},
+};
+#endif
+
+/*
  * known 6338 boards
  */
 #ifdef CONFIG_BCM63XX_CPU_6338
@@ -592,6 +633,9 @@ static struct board_info __initdata board_DWVS0 = {
  * all boards
  */
 static const struct board_info __initdata *bcm963xx_boards[] = {
+#ifdef CONFIG_BCM63XX_CPU_6328
+	&board_96328avng,
+#endif
 #ifdef CONFIG_BCM63XX_CPU_6338
 	&board_96338gw,
 	&board_96338w,
@@ -709,9 +753,15 @@ void __init board_prom_init(void)
 	char cfe_version[32];
 	u32 val;
 
-	/* read base address of boot chip select (0) */
-	val = bcm_mpi_readl(MPI_CSBASE_REG(0));
-	val &= MPI_CSBASE_BASE_MASK;
+	/* read base address of boot chip select (0)
+	 * 6328 does not have MPI but boots from a fixed address
+	 */
+	if (BCMCPU_IS_6328())
+		val = 0x18000000;
+	else {
+		val = bcm_mpi_readl(MPI_CSBASE_REG(0));
+		val &= MPI_CSBASE_BASE_MASK;
+	}
 	boot_addr = (u8 *)KSEG1ADDR(val);
 
 	/* dump cfe version */
@@ -808,40 +858,6 @@ void __init board_setup(void)
 		panic("unexpected CPU for bcm963xx board");
 }
 
-static struct mtd_partition mtd_partitions[] = {
-	{
-		.name		= "cfe",
-		.offset		= 0x0,
-		.size		= 0x40000,
-	}
-};
-
-static const char *bcm63xx_part_types[] = { "bcm63xxpart", NULL };
-
-static struct physmap_flash_data flash_data = {
-	.width			= 2,
-	.nr_parts		= ARRAY_SIZE(mtd_partitions),
-	.parts			= mtd_partitions,
-	.part_probe_types	= bcm63xx_part_types,
-};
-
-static struct resource mtd_resources[] = {
-	{
-		.start		= 0,	/* filled at runtime */
-		.end		= 0,	/* filled at runtime */
-		.flags		= IORESOURCE_MEM,
-	}
-};
-
-static struct platform_device mtd_dev = {
-	.name			= "physmap-flash",
-	.resource		= mtd_resources,
-	.num_resources		= ARRAY_SIZE(mtd_resources),
-	.dev			= {
-		.platform_data	= &flash_data,
-	},
-};
-
 static struct gpio_led_platform_data bcm63xx_led_data;
 
 static struct platform_device bcm63xx_gpio_leds = {
@@ -855,8 +871,6 @@ static struct platform_device bcm63xx_gpio_leds = {
  */
 int __init board_register_devices(void)
 {
-	u32 val;
-
 	if (board.has_uart0)
 		bcm63xx_uart_register(0);
 
@@ -890,14 +904,9 @@ int __init board_register_devices(void)
 	}
 #endif
 
-	/* read base address of boot chip select (0) */
-	val = bcm_mpi_readl(MPI_CSBASE_REG(0));
-	val &= MPI_CSBASE_BASE_MASK;
-
-	mtd_resources[0].start = val;
-	mtd_resources[0].end = 0x1FFFFFFF;
+	bcm63xx_spi_register();
 
-	platform_device_register(&mtd_dev);
+	bcm63xx_flash_register();
 
 	bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds);
 	bcm63xx_led_data.leds = board.leds;
diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c
index 9d57c71..1db48ad 100644
--- a/arch/mips/bcm63xx/clk.c
+++ b/arch/mips/bcm63xx/clk.c
@@ -120,7 +120,7 @@ static void enetsw_set(struct clk *clk, int enable)
 {
 	if (!BCMCPU_IS_6368())
 		return;
-	bcm_hwclock_set(CKCTL_6368_ROBOSW_CLK_EN |
+	bcm_hwclock_set(CKCTL_6368_ROBOSW_EN |
 			CKCTL_6368_SWPKT_USB_EN |
 			CKCTL_6368_SWPKT_SAR_EN, enable);
 	if (enable) {
@@ -163,7 +163,7 @@ static void usbh_set(struct clk *clk, int enable)
 	if (BCMCPU_IS_6348())
 		bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
 	else if (BCMCPU_IS_6368())
-		bcm_hwclock_set(CKCTL_6368_USBH_CLK_EN, enable);
+		bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
 }
 
 static struct clk clk_usbh = {
@@ -181,9 +181,11 @@ static void spi_set(struct clk *clk, int enable)
 		mask = CKCTL_6338_SPI_EN;
 	else if (BCMCPU_IS_6348())
 		mask = CKCTL_6348_SPI_EN;
-	else
-		/* BCMCPU_IS_6358 */
+	else if (BCMCPU_IS_6358())
 		mask = CKCTL_6358_SPI_EN;
+	else
+		/* BCMCPU_IS_6368 */
+		mask = CKCTL_6368_SPI_EN;
 	bcm_hwclock_set(mask, enable);
 }
 
@@ -199,7 +201,7 @@ static void xtm_set(struct clk *clk, int enable)
 	if (!BCMCPU_IS_6368())
 		return;
 
-	bcm_hwclock_set(CKCTL_6368_SAR_CLK_EN |
+	bcm_hwclock_set(CKCTL_6368_SAR_EN |
 			CKCTL_6368_SWPKT_SAR_EN, enable);
 
 	if (enable) {
@@ -222,6 +224,18 @@ static struct clk clk_xtm = {
 };
 
 /*
+ * IPsec clock
+ */
+static void ipsec_set(struct clk *clk, int enable)
+{
+	bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable);
+}
+
+static struct clk clk_ipsec = {
+	.set	= ipsec_set,
+};
+
+/*
  * Internal peripheral clock
  */
 static struct clk clk_periph = {
@@ -278,6 +292,8 @@ struct clk *clk_get(struct device *dev, const char *id)
 		return &clk_periph;
 	if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
 		return &clk_pcm;
+	if (BCMCPU_IS_6368() && !strcmp(id, "ipsec"))
+		return &clk_ipsec;
 	return ERR_PTR(-ENOENT);
 }
 
diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c
index 8f0d6c7..a7afb28 100644
--- a/arch/mips/bcm63xx/cpu.c
+++ b/arch/mips/bcm63xx/cpu.c
@@ -29,6 +29,14 @@ static u16 bcm63xx_cpu_rev;
 static unsigned int bcm63xx_cpu_freq;
 static unsigned int bcm63xx_memory_size;
 
+static const unsigned long bcm6328_regs_base[] = {
+	__GEN_CPU_REGS_TABLE(6328)
+};
+
+static const int bcm6328_irqs[] = {
+	__GEN_CPU_IRQ_TABLE(6328)
+};
+
 static const unsigned long bcm6338_regs_base[] = {
 	__GEN_CPU_REGS_TABLE(6338)
 };
@@ -99,6 +107,33 @@ unsigned int bcm63xx_get_memory_size(void)
 static unsigned int detect_cpu_clock(void)
 {
 	switch (bcm63xx_get_cpu_id()) {
+	case BCM6328_CPU_ID:
+	{
+		unsigned int tmp, mips_pll_fcvo;
+
+		tmp = bcm_misc_readl(MISC_STRAPBUS_6328_REG);
+		mips_pll_fcvo = (tmp & STRAPBUS_6328_FCVO_MASK)
+				>> STRAPBUS_6328_FCVO_SHIFT;
+
+		switch (mips_pll_fcvo) {
+		case 0x12:
+		case 0x14:
+		case 0x19:
+			return 160000000;
+		case 0x1c:
+			return 192000000;
+		case 0x13:
+		case 0x15:
+			return 200000000;
+		case 0x1a:
+			return 384000000;
+		case 0x16:
+			return 400000000;
+		default:
+			return 320000000;
+		}
+
+	}
 	case BCM6338_CPU_ID:
 		/* BCM6338 has a fixed 240 Mhz frequency */
 		return 240000000;
@@ -170,6 +205,9 @@ static unsigned int detect_memory_size(void)
 	unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0;
 	u32 val;
 
+	if (BCMCPU_IS_6328())
+		return bcm_ddr_readl(DDR_CSEND_REG) << 24;
+
 	if (BCMCPU_IS_6345()) {
 		val = bcm_sdram_readl(SDRAM_MBASE_REG);
 		return (val * 8 * 1024 * 1024);
@@ -228,17 +266,26 @@ void __init bcm63xx_cpu_init(void)
 		bcm63xx_irqs = bcm6345_irqs;
 		break;
 	case CPU_BMIPS4350:
-		switch (read_c0_prid() & 0xf0) {
-		case 0x10:
+		if ((read_c0_prid() & 0xf0) == 0x10) {
 			expected_cpu_id = BCM6358_CPU_ID;
 			bcm63xx_regs_base = bcm6358_regs_base;
 			bcm63xx_irqs = bcm6358_irqs;
-			break;
-		case 0x30:
-			expected_cpu_id = BCM6368_CPU_ID;
-			bcm63xx_regs_base = bcm6368_regs_base;
-			bcm63xx_irqs = bcm6368_irqs;
-			break;
+		} else {
+			/* all newer chips have the same chip id location */
+			u16 chip_id = bcm_readw(BCM_6368_PERF_BASE);
+
+			switch (chip_id) {
+			case BCM6328_CPU_ID:
+				expected_cpu_id = BCM6328_CPU_ID;
+				bcm63xx_regs_base = bcm6328_regs_base;
+				bcm63xx_irqs = bcm6328_irqs;
+				break;
+			case BCM6368_CPU_ID:
+				expected_cpu_id = BCM6368_CPU_ID;
+				bcm63xx_regs_base = bcm6368_regs_base;
+				bcm63xx_irqs = bcm6368_irqs;
+				break;
+			}
 		}
 		break;
 	}
diff --git a/arch/mips/bcm63xx/dev-dsp.c b/arch/mips/bcm63xx/dev-dsp.c
index da46d1d..5bb5b15 100644
--- a/arch/mips/bcm63xx/dev-dsp.c
+++ b/arch/mips/bcm63xx/dev-dsp.c
@@ -31,7 +31,7 @@ static struct resource voip_dsp_resources[] = {
 
 static struct platform_device bcm63xx_voip_dsp_device = {
 	.name		= "bcm63xx-voip-dsp",
-	.id		= 0,
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(voip_dsp_resources),
 	.resource	= voip_dsp_resources,
 };
diff --git a/arch/mips/bcm63xx/dev-flash.c b/arch/mips/bcm63xx/dev-flash.c
new file mode 100644
index 0000000..58371c7
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-flash.c
@@ -0,0 +1,123 @@
+/*
+ * Broadcom BCM63xx flash registration
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+
+#include <bcm63xx_cpu.h>
+#include <bcm63xx_dev_flash.h>
+#include <bcm63xx_regs.h>
+#include <bcm63xx_io.h>
+
+static struct mtd_partition mtd_partitions[] = {
+	{
+		.name		= "cfe",
+		.offset		= 0x0,
+		.size		= 0x40000,
+	}
+};
+
+static const char *bcm63xx_part_types[] = { "bcm63xxpart", NULL };
+
+static struct physmap_flash_data flash_data = {
+	.width			= 2,
+	.parts			= mtd_partitions,
+	.part_probe_types	= bcm63xx_part_types,
+};
+
+static struct resource mtd_resources[] = {
+	{
+		.start		= 0,	/* filled at runtime */
+		.end		= 0,	/* filled at runtime */
+		.flags		= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device mtd_dev = {
+	.name			= "physmap-flash",
+	.resource		= mtd_resources,
+	.num_resources		= ARRAY_SIZE(mtd_resources),
+	.dev			= {
+		.platform_data	= &flash_data,
+	},
+};
+
+static int __init bcm63xx_detect_flash_type(void)
+{
+	u32 val;
+
+	switch (bcm63xx_get_cpu_id()) {
+	case BCM6328_CPU_ID:
+		val = bcm_misc_readl(MISC_STRAPBUS_6328_REG);
+		if (val & STRAPBUS_6328_BOOT_SEL_SERIAL)
+			return BCM63XX_FLASH_TYPE_SERIAL;
+		else
+			return BCM63XX_FLASH_TYPE_NAND;
+	case BCM6338_CPU_ID:
+	case BCM6345_CPU_ID:
+	case BCM6348_CPU_ID:
+		/* no way to auto detect so assume parallel */
+		return BCM63XX_FLASH_TYPE_PARALLEL;
+	case BCM6358_CPU_ID:
+		val = bcm_gpio_readl(GPIO_STRAPBUS_REG);
+		if (val & STRAPBUS_6358_BOOT_SEL_PARALLEL)
+			return BCM63XX_FLASH_TYPE_PARALLEL;
+		else
+			return BCM63XX_FLASH_TYPE_SERIAL;
+	case BCM6368_CPU_ID:
+		val = bcm_gpio_readl(GPIO_STRAPBUS_REG);
+		switch (val & STRAPBUS_6368_BOOT_SEL_MASK) {
+		case STRAPBUS_6368_BOOT_SEL_NAND:
+			return BCM63XX_FLASH_TYPE_NAND;
+		case STRAPBUS_6368_BOOT_SEL_SERIAL:
+			return BCM63XX_FLASH_TYPE_SERIAL;
+		case STRAPBUS_6368_BOOT_SEL_PARALLEL:
+			return BCM63XX_FLASH_TYPE_PARALLEL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+int __init bcm63xx_flash_register(void)
+{
+	int flash_type;
+	u32 val;
+
+	flash_type = bcm63xx_detect_flash_type();
+
+	switch (flash_type) {
+	case BCM63XX_FLASH_TYPE_PARALLEL:
+		/* read base address of boot chip select (0) */
+		val = bcm_mpi_readl(MPI_CSBASE_REG(0));
+		val &= MPI_CSBASE_BASE_MASK;
+
+		mtd_resources[0].start = val;
+		mtd_resources[0].end = 0x1FFFFFFF;
+
+		return platform_device_register(&mtd_dev);
+	case BCM63XX_FLASH_TYPE_SERIAL:
+		pr_warn("unsupported serial flash detected\n");
+		return -ENODEV;
+	case BCM63XX_FLASH_TYPE_NAND:
+		pr_warn("unsupported NAND flash detected\n");
+		return -ENODEV;
+	default:
+		pr_err("flash detection failed for BCM%x: %d\n",
+		       bcm63xx_get_cpu_id(), flash_type);
+		return -ENODEV;
+	}
+}
diff --git a/arch/mips/bcm63xx/dev-pcmcia.c b/arch/mips/bcm63xx/dev-pcmcia.c
index de4d917..a551bab 100644
--- a/arch/mips/bcm63xx/dev-pcmcia.c
+++ b/arch/mips/bcm63xx/dev-pcmcia.c
@@ -79,11 +79,11 @@ static int __init config_pcmcia_cs(unsigned int cs,
 	return ret;
 }
 
-static const __initdata struct {
+static const struct {
 	unsigned int	cs;
 	unsigned int	base;
 	unsigned int	size;
-} pcmcia_cs[3] = {
+} pcmcia_cs[3] __initconst = {
 	{
 		.cs	= MPI_CS_PCMCIA_COMMON,
 		.base	= BCM_PCMCIA_COMMON_BASE_PA,
diff --git a/arch/mips/bcm63xx/dev-rng.c b/arch/mips/bcm63xx/dev-rng.c
new file mode 100644
index 0000000..d277b4d
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-rng.c
@@ -0,0 +1,40 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011 Florian Fainelli <florian@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <bcm63xx_cpu.h>
+
+static struct resource rng_resources[] = {
+	{
+		.start		= -1, /* filled at runtime */
+		.end		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bcm63xx_rng_device = {
+	.name		= "bcm63xx-rng",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(rng_resources),
+	.resource	= rng_resources,
+};
+
+int __init bcm63xx_rng_register(void)
+{
+	if (!BCMCPU_IS_6368())
+		return -ENODEV;
+
+	rng_resources[0].start = bcm63xx_regset_address(RSET_RNG);
+	rng_resources[0].end = rng_resources[0].start;
+	rng_resources[0].end += RSET_RNG_SIZE - 1;
+
+	return platform_device_register(&bcm63xx_rng_device);
+}
+arch_initcall(bcm63xx_rng_register);
diff --git a/arch/mips/bcm63xx/dev-spi.c b/arch/mips/bcm63xx/dev-spi.c
new file mode 100644
index 0000000..e39f730
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-spi.c
@@ -0,0 +1,119 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009-2011 Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <bcm63xx_cpu.h>
+#include <bcm63xx_dev_spi.h>
+#include <bcm63xx_regs.h>
+
+#ifdef BCMCPU_RUNTIME_DETECT
+/*
+ * register offsets
+ */
+static const unsigned long bcm6338_regs_spi[] = {
+	__GEN_SPI_REGS_TABLE(6338)
+};
+
+static const unsigned long bcm6348_regs_spi[] = {
+	__GEN_SPI_REGS_TABLE(6348)
+};
+
+static const unsigned long bcm6358_regs_spi[] = {
+	__GEN_SPI_REGS_TABLE(6358)
+};
+
+static const unsigned long bcm6368_regs_spi[] = {
+	__GEN_SPI_REGS_TABLE(6368)
+};
+
+const unsigned long *bcm63xx_regs_spi;
+EXPORT_SYMBOL(bcm63xx_regs_spi);
+
+static __init void bcm63xx_spi_regs_init(void)
+{
+	if (BCMCPU_IS_6338())
+		bcm63xx_regs_spi = bcm6338_regs_spi;
+	if (BCMCPU_IS_6348())
+		bcm63xx_regs_spi = bcm6348_regs_spi;
+	if (BCMCPU_IS_6358())
+		bcm63xx_regs_spi = bcm6358_regs_spi;
+	if (BCMCPU_IS_6368())
+		bcm63xx_regs_spi = bcm6368_regs_spi;
+}
+#else
+static __init void bcm63xx_spi_regs_init(void) { }
+#endif
+
+static struct resource spi_resources[] = {
+	{
+		.start		= -1, /* filled at runtime */
+		.end		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct bcm63xx_spi_pdata spi_pdata = {
+	.bus_num		= 0,
+	.num_chipselect		= 8,
+};
+
+static struct platform_device bcm63xx_spi_device = {
+	.name		= "bcm63xx-spi",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(spi_resources),
+	.resource	= spi_resources,
+	.dev		= {
+		.platform_data = &spi_pdata,
+	},
+};
+
+int __init bcm63xx_spi_register(void)
+{
+	struct clk *periph_clk;
+
+	if (BCMCPU_IS_6328() || BCMCPU_IS_6345())
+		return -ENODEV;
+
+	periph_clk = clk_get(NULL, "periph");
+	if (IS_ERR(periph_clk)) {
+		pr_err("unable to get periph clock\n");
+		return -ENODEV;
+	}
+
+	/* Set bus frequency */
+	spi_pdata.speed_hz = clk_get_rate(periph_clk);
+
+	spi_resources[0].start = bcm63xx_regset_address(RSET_SPI);
+	spi_resources[0].end = spi_resources[0].start;
+	spi_resources[1].start = bcm63xx_get_irq_number(IRQ_SPI);
+
+	if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {
+		spi_resources[0].end += BCM_6338_RSET_SPI_SIZE - 1;
+		spi_pdata.fifo_size = SPI_6338_MSG_DATA_SIZE;
+	}
+
+	if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
+		spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1;
+		spi_pdata.fifo_size = SPI_6358_MSG_DATA_SIZE;
+	}
+
+	bcm63xx_spi_regs_init();
+
+	return platform_device_register(&bcm63xx_spi_device);
+}
diff --git a/arch/mips/bcm63xx/dev-wdt.c b/arch/mips/bcm63xx/dev-wdt.c
index 3e6c716..2a2346a 100644
--- a/arch/mips/bcm63xx/dev-wdt.c
+++ b/arch/mips/bcm63xx/dev-wdt.c
@@ -21,7 +21,7 @@ static struct resource wdt_resources[] = {
 
 static struct platform_device bcm63xx_wdt_device = {
 	.name		= "bcm63xx-wdt",
-	.id		= 0,
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(wdt_resources),
 	.resource	= wdt_resources,
 };
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c
index 9a216a4..18e051a 100644
--- a/arch/mips/bcm63xx/irq.c
+++ b/arch/mips/bcm63xx/irq.c
@@ -27,6 +27,17 @@ static void __internal_irq_unmask_32(unsigned int irq) __maybe_unused;
 static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused;
 
 #ifndef BCMCPU_RUNTIME_DETECT
+#ifdef CONFIG_BCM63XX_CPU_6328
+#define irq_stat_reg		PERF_IRQSTAT_6328_REG
+#define irq_mask_reg		PERF_IRQMASK_6328_REG
+#define irq_bits		64
+#define is_ext_irq_cascaded	1
+#define ext_irq_start		(BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE)
+#define ext_irq_end		(BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE)
+#define ext_irq_count		4
+#define ext_irq_cfg_reg1	PERF_EXTIRQ_CFG_REG_6328
+#define ext_irq_cfg_reg2	0
+#endif
 #ifdef CONFIG_BCM63XX_CPU_6338
 #define irq_stat_reg		PERF_IRQSTAT_6338_REG
 #define irq_mask_reg		PERF_IRQMASK_6338_REG
@@ -118,6 +129,16 @@ static void bcm63xx_init_irq(void)
 	irq_mask_addr = bcm63xx_regset_address(RSET_PERF);
 
 	switch (bcm63xx_get_cpu_id()) {
+	case BCM6328_CPU_ID:
+		irq_stat_addr += PERF_IRQSTAT_6328_REG;
+		irq_mask_addr += PERF_IRQMASK_6328_REG;
+		irq_bits = 64;
+		ext_irq_count = 4;
+		is_ext_irq_cascaded = 1;
+		ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+		ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE;
+		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328;
+		break;
 	case BCM6338_CPU_ID:
 		irq_stat_addr += PERF_IRQSTAT_6338_REG;
 		irq_mask_addr += PERF_IRQMASK_6338_REG;
diff --git a/arch/mips/bcm63xx/prom.c b/arch/mips/bcm63xx/prom.c
index 99d7f40..10eaff4 100644
--- a/arch/mips/bcm63xx/prom.c
+++ b/arch/mips/bcm63xx/prom.c
@@ -26,7 +26,9 @@ void __init prom_init(void)
 	bcm_wdt_writel(WDT_STOP_2, WDT_CTL_REG);
 
 	/* disable all hardware blocks clock for now */
-	if (BCMCPU_IS_6338())
+	if (BCMCPU_IS_6328())
+		mask = CKCTL_6328_ALL_SAFE_EN;
+	else if (BCMCPU_IS_6338())
 		mask = CKCTL_6338_ALL_SAFE_EN;
 	else if (BCMCPU_IS_6345())
 		mask = CKCTL_6345_ALL_SAFE_EN;
diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c
index 356b055..0e74a13 100644
--- a/arch/mips/bcm63xx/setup.c
+++ b/arch/mips/bcm63xx/setup.c
@@ -68,6 +68,9 @@ void bcm63xx_machine_reboot(void)
 
 	/* mask and clear all external irq */
 	switch (bcm63xx_get_cpu_id()) {
+	case BCM6328_CPU_ID:
+		perf_regs[0] = PERF_EXTIRQ_CFG_REG_6328;
+		break;
 	case BCM6338_CPU_ID:
 		perf_regs[0] = PERF_EXTIRQ_CFG_REG_6338;
 		break;
@@ -95,9 +98,13 @@ void bcm63xx_machine_reboot(void)
 		bcm6348_a1_reboot();
 
 	printk(KERN_INFO "triggering watchdog soft-reset...\n");
-	reg = bcm_perf_readl(PERF_SYS_PLL_CTL_REG);
-	reg |= SYS_PLL_SOFT_RESET;
-	bcm_perf_writel(reg, PERF_SYS_PLL_CTL_REG);
+	if (BCMCPU_IS_6328()) {
+		bcm_wdt_writel(1, WDT_SOFTRESET_REG);
+	} else {
+		reg = bcm_perf_readl(PERF_SYS_PLL_CTL_REG);
+		reg |= SYS_PLL_SOFT_RESET;
+		bcm_perf_writel(reg, PERF_SYS_PLL_CTL_REG);
+	}
 	while (1)
 		;
 }
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
index 5042d51..c2a3fb0 100644
--- a/arch/mips/boot/compressed/Makefile
+++ b/arch/mips/boot/compressed/Makefile
@@ -58,8 +58,12 @@ $(obj)/piggy.o: $(obj)/dummy.o $(obj)/vmlinux.bin.z FORCE
 # Calculate the load address of the compressed kernel image
 hostprogs-y := calc_vmlinuz_load_addr
 
+ifeq ($(CONFIG_MACH_JZ4740),y)
+VMLINUZ_LOAD_ADDRESS := 0x80600000
+else
 VMLINUZ_LOAD_ADDRESS = $(shell $(obj)/calc_vmlinuz_load_addr \
 		$(obj)/vmlinux.bin $(VMLINUX_LOAD_ADDRESS))
+endif
 
 vmlinuzobjs-y += $(obj)/piggy.o
 
diff --git a/arch/mips/boot/compressed/uart-16550.c b/arch/mips/boot/compressed/uart-16550.c
index c9caaf4..1c7b739 100644
--- a/arch/mips/boot/compressed/uart-16550.c
+++ b/arch/mips/boot/compressed/uart-16550.c
@@ -18,6 +18,11 @@
 #define PORT(offset) (CKSEG1ADDR(AR7_REGS_UART0) + (4 * offset))
 #endif
 
+#ifdef CONFIG_MACH_JZ4740
+#define UART0_BASE  0xB0030000
+#define PORT(offset) (UART0_BASE + (4 * offset))
+#endif
+
 #ifndef PORT
 #error please define the serial port address for your own machine
 #endif
diff --git a/arch/mips/cavium-octeon/.gitignore b/arch/mips/cavium-octeon/.gitignore
new file mode 100644
index 0000000..39c9686
--- /dev/null
+++ b/arch/mips/cavium-octeon/.gitignore
@@ -0,0 +1,2 @@
+*.dtb.S
+*.dtb
diff --git a/arch/mips/cavium-octeon/Kconfig b/arch/mips/cavium-octeon/Kconfig
index f9e275a..2f4f6d5 100644
--- a/arch/mips/cavium-octeon/Kconfig
+++ b/arch/mips/cavium-octeon/Kconfig
@@ -82,10 +82,6 @@ config CAVIUM_OCTEON_LOCK_L2_MEMCPY
 	help
 	  Lock the kernel's implementation of memcpy() into L2.
 
-config ARCH_SPARSEMEM_ENABLE
-	def_bool y
-	select SPARSEMEM_STATIC
-
 config IOMMU_HELPER
 	bool
 
diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
index 19eb043..bc96e29 100644
--- a/arch/mips/cavium-octeon/Makefile
+++ b/arch/mips/cavium-octeon/Makefile
@@ -9,9 +9,25 @@
 # Copyright (C) 2005-2009 Cavium Networks
 #
 
+CFLAGS_octeon-platform.o = -I$(src)/../../../scripts/dtc/libfdt
+CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
+
 obj-y := cpu.o setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o
 obj-y += dma-octeon.o flash_setup.o
 obj-y += octeon-memcpy.o
 obj-y += executive/
 
 obj-$(CONFIG_SMP)                     += smp.o
+
+DTS_FILES = octeon_3xxx.dts octeon_68xx.dts
+DTB_FILES = $(patsubst %.dts, %.dtb, $(DTS_FILES))
+
+obj-y += $(patsubst %.dts, %.dtb.o, $(DTS_FILES))
+
+$(obj)/%.dtb: $(src)/%.dts FORCE
+	$(call if_changed_dep,dtc)
+
+# Let's keep the .dtb files around in case we want to look at them.
+.SECONDARY:  $(addprefix $(obj)/, $(DTB_FILES))
+
+clean-files += $(DTB_FILES) $(patsubst %.dtb, %.dtb.S, $(DTB_FILES))
diff --git a/arch/mips/cavium-octeon/executive/cvmx-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-fpa.c
deleted file mode 100644
index ad44b8b..0000000
--- a/arch/mips/cavium-octeon/executive/cvmx-fpa.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/***********************license start***************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2008 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
- ***********************license end**************************************/
-
-/**
- * @file
- *
- * Support library for the hardware Free Pool Allocator.
- *
- *
- */
-
-#include "cvmx-config.h"
-#include "cvmx.h"
-#include "cvmx-fpa.h"
-#include "cvmx-ipd.h"
-
-/**
- * Current state of all the pools. Use access functions
- * instead of using it directly.
- */
-CVMX_SHARED cvmx_fpa_pool_info_t cvmx_fpa_pool_info[CVMX_FPA_NUM_POOLS];
-
-/**
- * Setup a FPA pool to control a new block of memory. The
- * buffer pointer must be a physical address.
- *
- * @pool:       Pool to initialize
- *                   0 <= pool < 8
- * @name:       Constant character string to name this pool.
- *                   String is not copied.
- * @buffer:     Pointer to the block of memory to use. This must be
- *                   accessible by all processors and external hardware.
- * @block_size: Size for each block controlled by the FPA
- * @num_blocks: Number of blocks
- *
- * Returns 0 on Success,
- *         -1 on failure
- */
-int cvmx_fpa_setup_pool(uint64_t pool, const char *name, void *buffer,
-			uint64_t block_size, uint64_t num_blocks)
-{
-	char *ptr;
-	if (!buffer) {
-		cvmx_dprintf
-		    ("ERROR: cvmx_fpa_setup_pool: NULL buffer pointer!\n");
-		return -1;
-	}
-	if (pool >= CVMX_FPA_NUM_POOLS) {
-		cvmx_dprintf("ERROR: cvmx_fpa_setup_pool: Illegal pool!\n");
-		return -1;
-	}
-
-	if (block_size < CVMX_FPA_MIN_BLOCK_SIZE) {
-		cvmx_dprintf
-		    ("ERROR: cvmx_fpa_setup_pool: Block size too small.\n");
-		return -1;
-	}
-
-	if (((unsigned long)buffer & (CVMX_FPA_ALIGNMENT - 1)) != 0) {
-		cvmx_dprintf
-		    ("ERROR: cvmx_fpa_setup_pool: Buffer not aligned properly.\n");
-		return -1;
-	}
-
-	cvmx_fpa_pool_info[pool].name = name;
-	cvmx_fpa_pool_info[pool].size = block_size;
-	cvmx_fpa_pool_info[pool].starting_element_count = num_blocks;
-	cvmx_fpa_pool_info[pool].base = buffer;
-
-	ptr = (char *)buffer;
-	while (num_blocks--) {
-		cvmx_fpa_free(ptr, pool, 0);
-		ptr += block_size;
-	}
-	return 0;
-}
-
-/**
- * Shutdown a Memory pool and validate that it had all of
- * the buffers originally placed in it.
- *
- * @pool:   Pool to shutdown
- * Returns Zero on success
- *         - Positive is count of missing buffers
- *         - Negative is too many buffers or corrupted pointers
- */
-uint64_t cvmx_fpa_shutdown_pool(uint64_t pool)
-{
-	uint64_t errors = 0;
-	uint64_t count = 0;
-	uint64_t base = cvmx_ptr_to_phys(cvmx_fpa_pool_info[pool].base);
-	uint64_t finish =
-	    base +
-	    cvmx_fpa_pool_info[pool].size *
-	    cvmx_fpa_pool_info[pool].starting_element_count;
-	void *ptr;
-	uint64_t address;
-
-	count = 0;
-	do {
-		ptr = cvmx_fpa_alloc(pool);
-		if (ptr)
-			address = cvmx_ptr_to_phys(ptr);
-		else
-			address = 0;
-		if (address) {
-			if ((address >= base) && (address < finish) &&
-			    (((address -
-			       base) % cvmx_fpa_pool_info[pool].size) == 0)) {
-				count++;
-			} else {
-				cvmx_dprintf
-				    ("ERROR: cvmx_fpa_shutdown_pool: Illegal address 0x%llx in pool %s(%d)\n",
-				     (unsigned long long)address,
-				     cvmx_fpa_pool_info[pool].name, (int)pool);
-				errors++;
-			}
-		}
-	} while (address);
-
-#ifdef CVMX_ENABLE_PKO_FUNCTIONS
-	if (pool == 0)
-		cvmx_ipd_free_ptr();
-#endif
-
-	if (errors) {
-		cvmx_dprintf
-		    ("ERROR: cvmx_fpa_shutdown_pool: Pool %s(%d) started at 0x%llx, ended at 0x%llx, with a step of 0x%llx\n",
-		     cvmx_fpa_pool_info[pool].name, (int)pool,
-		     (unsigned long long)base, (unsigned long long)finish,
-		     (unsigned long long)cvmx_fpa_pool_info[pool].size);
-		return -errors;
-	} else
-		return 0;
-}
-
-uint64_t cvmx_fpa_get_block_size(uint64_t pool)
-{
-	switch (pool) {
-	case 0:
-		return CVMX_FPA_POOL_0_SIZE;
-	case 1:
-		return CVMX_FPA_POOL_1_SIZE;
-	case 2:
-		return CVMX_FPA_POOL_2_SIZE;
-	case 3:
-		return CVMX_FPA_POOL_3_SIZE;
-	case 4:
-		return CVMX_FPA_POOL_4_SIZE;
-	case 5:
-		return CVMX_FPA_POOL_5_SIZE;
-	case 6:
-		return CVMX_FPA_POOL_6_SIZE;
-	case 7:
-		return CVMX_FPA_POOL_7_SIZE;
-	default:
-		return 0;
-	}
-}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c
deleted file mode 100644
index c239e5f..0000000
--- a/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/***********************license start***************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2008 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
- ***********************license end**************************************/
-
-/**
- * @file
- *
- * Helper functions for FPA setup.
- *
- */
-#include "executive-config.h"
-#include "cvmx-config.h"
-#include "cvmx.h"
-#include "cvmx-bootmem.h"
-#include "cvmx-fpa.h"
-#include "cvmx-helper-fpa.h"
-
-/**
- * Allocate memory for and initialize a single FPA pool.
- *
- * @pool:    Pool to initialize
- * @buffer_size:  Size of buffers to allocate in bytes
- * @buffers: Number of buffers to put in the pool. Zero is allowed
- * @name:    String name of the pool for debugging purposes
- * Returns Zero on success, non-zero on failure
- */
-static int __cvmx_helper_initialize_fpa_pool(int pool, uint64_t buffer_size,
-					     uint64_t buffers, const char *name)
-{
-	uint64_t current_num;
-	void *memory;
-	uint64_t align = CVMX_CACHE_LINE_SIZE;
-
-	/*
-	 * Align the allocation so that power of 2 size buffers are
-	 * naturally aligned.
-	 */
-	while (align < buffer_size)
-		align = align << 1;
-
-	if (buffers == 0)
-		return 0;
-
-	current_num = cvmx_read_csr(CVMX_FPA_QUEX_AVAILABLE(pool));
-	if (current_num) {
-		cvmx_dprintf("Fpa pool %d(%s) already has %llu buffers. "
-			     "Skipping setup.\n",
-		     pool, name, (unsigned long long)current_num);
-		return 0;
-	}
-
-	memory = cvmx_bootmem_alloc(buffer_size * buffers, align);
-	if (memory == NULL) {
-		cvmx_dprintf("Out of memory initializing fpa pool %d(%s).\n",
-			     pool, name);
-		return -1;
-	}
-	cvmx_fpa_setup_pool(pool, name, memory, buffer_size, buffers);
-	return 0;
-}
-
-/**
- * Allocate memory and initialize the FPA pools using memory
- * from cvmx-bootmem. Specifying zero for the number of
- * buffers will cause that FPA pool to not be setup. This is
- * useful if you aren't using some of the hardware and want
- * to save memory. Use cvmx_helper_initialize_fpa instead of
- * this function directly.
- *
- * @pip_pool: Should always be CVMX_FPA_PACKET_POOL
- * @pip_size: Should always be CVMX_FPA_PACKET_POOL_SIZE
- * @pip_buffers:
- *                 Number of packet buffers.
- * @wqe_pool: Should always be CVMX_FPA_WQE_POOL
- * @wqe_size: Should always be CVMX_FPA_WQE_POOL_SIZE
- * @wqe_entries:
- *                 Number of work queue entries
- * @pko_pool: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL
- * @pko_size: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE
- * @pko_buffers:
- *                 PKO Command buffers. You should at minimum have two per
- *                 each PKO queue.
- * @tim_pool: Should always be CVMX_FPA_TIMER_POOL
- * @tim_size: Should always be CVMX_FPA_TIMER_POOL_SIZE
- * @tim_buffers:
- *                 TIM ring buffer command queues. At least two per timer bucket
- *                 is recommened.
- * @dfa_pool: Should always be CVMX_FPA_DFA_POOL
- * @dfa_size: Should always be CVMX_FPA_DFA_POOL_SIZE
- * @dfa_buffers:
- *                 DFA command buffer. A relatively small (32 for example)
- *                 number should work.
- * Returns Zero on success, non-zero if out of memory
- */
-static int __cvmx_helper_initialize_fpa(int pip_pool, int pip_size,
-					int pip_buffers, int wqe_pool,
-					int wqe_size, int wqe_entries,
-					int pko_pool, int pko_size,
-					int pko_buffers, int tim_pool,
-					int tim_size, int tim_buffers,
-					int dfa_pool, int dfa_size,
-					int dfa_buffers)
-{
-	int status;
-
-	cvmx_fpa_enable();
-
-	if ((pip_buffers > 0) && (pip_buffers <= 64))
-		cvmx_dprintf
-		    ("Warning: %d packet buffers may not be enough for hardware"
-		     " prefetch. 65 or more is recommended.\n", pip_buffers);
-
-	if (pip_pool >= 0) {
-		status =
-		    __cvmx_helper_initialize_fpa_pool(pip_pool, pip_size,
-						      pip_buffers,
-						      "Packet Buffers");
-		if (status)
-			return status;
-	}
-
-	if (wqe_pool >= 0) {
-		status =
-		    __cvmx_helper_initialize_fpa_pool(wqe_pool, wqe_size,
-						      wqe_entries,
-						      "Work Queue Entries");
-		if (status)
-			return status;
-	}
-
-	if (pko_pool >= 0) {
-		status =
-		    __cvmx_helper_initialize_fpa_pool(pko_pool, pko_size,
-						      pko_buffers,
-						      "PKO Command Buffers");
-		if (status)
-			return status;
-	}
-
-	if (tim_pool >= 0) {
-		status =
-		    __cvmx_helper_initialize_fpa_pool(tim_pool, tim_size,
-						      tim_buffers,
-						      "TIM Command Buffers");
-		if (status)
-			return status;
-	}
-
-	if (dfa_pool >= 0) {
-		status =
-		    __cvmx_helper_initialize_fpa_pool(dfa_pool, dfa_size,
-						      dfa_buffers,
-						      "DFA Command Buffers");
-		if (status)
-			return status;
-	}
-
-	return 0;
-}
-
-/**
- * Allocate memory and initialize the FPA pools using memory
- * from cvmx-bootmem. Sizes of each element in the pools is
- * controlled by the cvmx-config.h header file. Specifying
- * zero for any parameter will cause that FPA pool to not be
- * setup. This is useful if you aren't using some of the
- * hardware and want to save memory.
- *
- * @packet_buffers:
- *               Number of packet buffers to allocate
- * @work_queue_entries:
- *               Number of work queue entries
- * @pko_buffers:
- *               PKO Command buffers. You should at minimum have two per
- *               each PKO queue.
- * @tim_buffers:
- *               TIM ring buffer command queues. At least two per timer bucket
- *               is recommened.
- * @dfa_buffers:
- *               DFA command buffer. A relatively small (32 for example)
- *               number should work.
- * Returns Zero on success, non-zero if out of memory
- */
-int cvmx_helper_initialize_fpa(int packet_buffers, int work_queue_entries,
-			       int pko_buffers, int tim_buffers,
-			       int dfa_buffers)
-{
-#ifndef CVMX_FPA_PACKET_POOL
-#define CVMX_FPA_PACKET_POOL -1
-#define CVMX_FPA_PACKET_POOL_SIZE 0
-#endif
-#ifndef CVMX_FPA_WQE_POOL
-#define CVMX_FPA_WQE_POOL -1
-#define CVMX_FPA_WQE_POOL_SIZE 0
-#endif
-#ifndef CVMX_FPA_OUTPUT_BUFFER_POOL
-#define CVMX_FPA_OUTPUT_BUFFER_POOL -1
-#define CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE 0
-#endif
-#ifndef CVMX_FPA_TIMER_POOL
-#define CVMX_FPA_TIMER_POOL -1
-#define CVMX_FPA_TIMER_POOL_SIZE 0
-#endif
-#ifndef CVMX_FPA_DFA_POOL
-#define CVMX_FPA_DFA_POOL -1
-#define CVMX_FPA_DFA_POOL_SIZE 0
-#endif
-	return __cvmx_helper_initialize_fpa(CVMX_FPA_PACKET_POOL,
-					    CVMX_FPA_PACKET_POOL_SIZE,
-					    packet_buffers, CVMX_FPA_WQE_POOL,
-					    CVMX_FPA_WQE_POOL_SIZE,
-					    work_queue_entries,
-					    CVMX_FPA_OUTPUT_BUFFER_POOL,
-					    CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE,
-					    pko_buffers, CVMX_FPA_TIMER_POOL,
-					    CVMX_FPA_TIMER_POOL_SIZE,
-					    tim_buffers, CVMX_FPA_DFA_POOL,
-					    CVMX_FPA_DFA_POOL_SIZE,
-					    dfa_buffers);
-}
diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index ffd4ae6..fac22a8 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -505,6 +505,85 @@ static void octeon_irq_ciu_enable_all_v2(struct irq_data *data)
 	}
 }
 
+static void octeon_irq_gpio_setup(struct irq_data *data)
+{
+	union cvmx_gpio_bit_cfgx cfg;
+	union octeon_ciu_chip_data cd;
+	u32 t = irqd_get_trigger_type(data);
+
+	cd.p = irq_data_get_irq_chip_data(data);
+
+	cfg.u64 = 0;
+	cfg.s.int_en = 1;
+	cfg.s.int_type = (t & IRQ_TYPE_EDGE_BOTH) != 0;
+	cfg.s.rx_xor = (t & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) != 0;
+
+	/* 140 nS glitch filter*/
+	cfg.s.fil_cnt = 7;
+	cfg.s.fil_sel = 3;
+
+	cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd.s.bit - 16), cfg.u64);
+}
+
+static void octeon_irq_ciu_enable_gpio_v2(struct irq_data *data)
+{
+	octeon_irq_gpio_setup(data);
+	octeon_irq_ciu_enable_v2(data);
+}
+
+static void octeon_irq_ciu_enable_gpio(struct irq_data *data)
+{
+	octeon_irq_gpio_setup(data);
+	octeon_irq_ciu_enable(data);
+}
+
+static int octeon_irq_ciu_gpio_set_type(struct irq_data *data, unsigned int t)
+{
+	irqd_set_trigger_type(data, t);
+	octeon_irq_gpio_setup(data);
+
+	return IRQ_SET_MASK_OK;
+}
+
+static void octeon_irq_ciu_disable_gpio_v2(struct irq_data *data)
+{
+	union octeon_ciu_chip_data cd;
+
+	cd.p = irq_data_get_irq_chip_data(data);
+	cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd.s.bit - 16), 0);
+
+	octeon_irq_ciu_disable_all_v2(data);
+}
+
+static void octeon_irq_ciu_disable_gpio(struct irq_data *data)
+{
+	union octeon_ciu_chip_data cd;
+
+	cd.p = irq_data_get_irq_chip_data(data);
+	cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd.s.bit - 16), 0);
+
+	octeon_irq_ciu_disable_all(data);
+}
+
+static void octeon_irq_ciu_gpio_ack(struct irq_data *data)
+{
+	union octeon_ciu_chip_data cd;
+	u64 mask;
+
+	cd.p = irq_data_get_irq_chip_data(data);
+	mask = 1ull << (cd.s.bit - 16);
+
+	cvmx_write_csr(CVMX_GPIO_INT_CLR, mask);
+}
+
+static void octeon_irq_handle_gpio(unsigned int irq, struct irq_desc *desc)
+{
+	if (irqd_get_trigger_type(irq_desc_get_irq_data(desc)) & IRQ_TYPE_EDGE_BOTH)
+		handle_edge_irq(irq, desc);
+	else
+		handle_level_irq(irq, desc);
+}
+
 #ifdef CONFIG_SMP
 
 static void octeon_irq_cpu_offline_ciu(struct irq_data *data)
@@ -650,18 +729,6 @@ static struct irq_chip octeon_irq_chip_ciu_v2 = {
 	.name = "CIU",
 	.irq_enable = octeon_irq_ciu_enable_v2,
 	.irq_disable = octeon_irq_ciu_disable_all_v2,
-	.irq_mask = octeon_irq_ciu_disable_local_v2,
-	.irq_unmask = octeon_irq_ciu_enable_v2,
-#ifdef CONFIG_SMP
-	.irq_set_affinity = octeon_irq_ciu_set_affinity_v2,
-	.irq_cpu_offline = octeon_irq_cpu_offline_ciu,
-#endif
-};
-
-static struct irq_chip octeon_irq_chip_ciu_edge_v2 = {
-	.name = "CIU-E",
-	.irq_enable = octeon_irq_ciu_enable_v2,
-	.irq_disable = octeon_irq_ciu_disable_all_v2,
 	.irq_ack = octeon_irq_ciu_ack,
 	.irq_mask = octeon_irq_ciu_disable_local_v2,
 	.irq_unmask = octeon_irq_ciu_enable_v2,
@@ -675,19 +742,8 @@ static struct irq_chip octeon_irq_chip_ciu = {
 	.name = "CIU",
 	.irq_enable = octeon_irq_ciu_enable,
 	.irq_disable = octeon_irq_ciu_disable_all,
-	.irq_mask = octeon_irq_dummy_mask,
-#ifdef CONFIG_SMP
-	.irq_set_affinity = octeon_irq_ciu_set_affinity,
-	.irq_cpu_offline = octeon_irq_cpu_offline_ciu,
-#endif
-};
-
-static struct irq_chip octeon_irq_chip_ciu_edge = {
-	.name = "CIU-E",
-	.irq_enable = octeon_irq_ciu_enable,
-	.irq_disable = octeon_irq_ciu_disable_all,
-	.irq_mask = octeon_irq_dummy_mask,
 	.irq_ack = octeon_irq_ciu_ack,
+	.irq_mask = octeon_irq_dummy_mask,
 #ifdef CONFIG_SMP
 	.irq_set_affinity = octeon_irq_ciu_set_affinity,
 	.irq_cpu_offline = octeon_irq_cpu_offline_ciu,
@@ -717,6 +773,33 @@ static struct irq_chip octeon_irq_chip_ciu_mbox = {
 	.flags = IRQCHIP_ONOFFLINE_ENABLED,
 };
 
+static struct irq_chip octeon_irq_chip_ciu_gpio_v2 = {
+	.name = "CIU-GPIO",
+	.irq_enable = octeon_irq_ciu_enable_gpio_v2,
+	.irq_disable = octeon_irq_ciu_disable_gpio_v2,
+	.irq_ack = octeon_irq_ciu_gpio_ack,
+	.irq_mask = octeon_irq_ciu_disable_local_v2,
+	.irq_unmask = octeon_irq_ciu_enable_v2,
+	.irq_set_type = octeon_irq_ciu_gpio_set_type,
+#ifdef CONFIG_SMP
+	.irq_set_affinity = octeon_irq_ciu_set_affinity_v2,
+#endif
+	.flags = IRQCHIP_SET_TYPE_MASKED,
+};
+
+static struct irq_chip octeon_irq_chip_ciu_gpio = {
+	.name = "CIU-GPIO",
+	.irq_enable = octeon_irq_ciu_enable_gpio,
+	.irq_disable = octeon_irq_ciu_disable_gpio,
+	.irq_mask = octeon_irq_dummy_mask,
+	.irq_ack = octeon_irq_ciu_gpio_ack,
+	.irq_set_type = octeon_irq_ciu_gpio_set_type,
+#ifdef CONFIG_SMP
+	.irq_set_affinity = octeon_irq_ciu_set_affinity,
+#endif
+	.flags = IRQCHIP_SET_TYPE_MASKED,
+};
+
 /*
  * Watchdog interrupts are special.  They are associated with a single
  * core, so we hardwire the affinity to that core.
@@ -887,9 +970,9 @@ static void __init octeon_irq_init_ciu(void)
 {
 	unsigned int i;
 	struct irq_chip *chip;
-	struct irq_chip *chip_edge;
 	struct irq_chip *chip_mbox;
 	struct irq_chip *chip_wd;
+	struct irq_chip *chip_gpio;
 
 	octeon_irq_init_ciu_percpu();
 	octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu;
@@ -901,16 +984,16 @@ static void __init octeon_irq_init_ciu(void)
 		octeon_irq_ip2 = octeon_irq_ip2_v2;
 		octeon_irq_ip3 = octeon_irq_ip3_v2;
 		chip = &octeon_irq_chip_ciu_v2;
-		chip_edge = &octeon_irq_chip_ciu_edge_v2;
 		chip_mbox = &octeon_irq_chip_ciu_mbox_v2;
 		chip_wd = &octeon_irq_chip_ciu_wd_v2;
+		chip_gpio = &octeon_irq_chip_ciu_gpio_v2;
 	} else {
 		octeon_irq_ip2 = octeon_irq_ip2_v1;
 		octeon_irq_ip3 = octeon_irq_ip3_v1;
 		chip = &octeon_irq_chip_ciu;
-		chip_edge = &octeon_irq_chip_ciu_edge;
 		chip_mbox = &octeon_irq_chip_ciu_mbox;
 		chip_wd = &octeon_irq_chip_ciu_wd;
+		chip_gpio = &octeon_irq_chip_ciu_gpio;
 	}
 	octeon_irq_ip4 = octeon_irq_ip4_mask;
 
@@ -921,7 +1004,7 @@ static void __init octeon_irq_init_ciu(void)
 	for (i = 0; i < 16; i++)
 		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WORKQ0, 0, i + 0, chip, handle_level_irq);
 	for (i = 0; i < 16; i++)
-		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GPIO0, 0, i + 16, chip, handle_level_irq);
+		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GPIO0, 0, i + 16, chip_gpio, octeon_irq_handle_gpio);
 
 	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq);
 	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq);
@@ -936,23 +1019,11 @@ static void __init octeon_irq_init_ciu(void)
 
 	octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI, 0, 45, chip, handle_level_irq);
 	octeon_irq_set_ciu_mapping(OCTEON_IRQ_RML, 0, 46, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_TRACE0, 0, 47, chip, handle_level_irq);
-
-	for (i = 0; i < 2; i++)
-		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GMX_DRP0, 0, i + 48, chip_edge, handle_edge_irq);
-
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_IPD_DRP, 0, 50, chip_edge, handle_edge_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_KEY_ZERO, 0, 51, chip_edge, handle_edge_irq);
-
 	for (i = 0; i < 4; i++)
-		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip_edge, handle_edge_irq);
+		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip, handle_edge_irq);
 
 	octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_PCM, 0, 57, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MPI, 0, 58, chip, handle_level_irq);
 	octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI2, 0, 59, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_POWIQ, 0, 60, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_IPDPPTHR, 0, 61, chip, handle_level_irq);
 	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII0, 0, 62, chip, handle_level_irq);
 	octeon_irq_set_ciu_mapping(OCTEON_IRQ_BOOTDMA, 0, 63, chip, handle_level_irq);
 
@@ -963,37 +1034,6 @@ static void __init octeon_irq_init_ciu(void)
 	octeon_irq_set_ciu_mapping(OCTEON_IRQ_UART2, 1, 16, chip, handle_level_irq);
 	octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq);
 	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII1, 1, 18, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_NAND, 1, 19, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MIO, 1, 20, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_IOB, 1, 21, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_FPA, 1, 22, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_POW, 1, 23, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_L2C, 1, 24, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_IPD, 1, 25, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_PIP, 1, 26, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_PKO, 1, 27, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_ZIP, 1, 28, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_TIM, 1, 29, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_RAD, 1, 30, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_KEY, 1, 31, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_DFA, 1, 32, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_USBCTL, 1, 33, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_SLI, 1, 34, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_DPI, 1, 35, chip, handle_level_irq);
-
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_AGX0, 1, 36, chip, handle_level_irq);
-
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_AGL, 1, 46, chip, handle_level_irq);
-
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_PTP, 1, 47, chip_edge, handle_edge_irq);
-
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_PEM0, 1, 48, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_PEM1, 1, 49, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_SRIO0, 1, 50, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_SRIO1, 1, 51, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_LMC0, 1, 52, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_DFM, 1, 56, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_RST, 1, 63, chip, handle_level_irq);
 
 	/* Enable the CIU lines */
 	set_c0_status(STATUSF_IP3 | STATUSF_IP2);
diff --git a/arch/mips/cavium-octeon/octeon-memcpy.S b/arch/mips/cavium-octeon/octeon-memcpy.S
index 88e0cdd..db478db 100644
--- a/arch/mips/cavium-octeon/octeon-memcpy.S
+++ b/arch/mips/cavium-octeon/octeon-memcpy.S
@@ -164,6 +164,14 @@
 	.set	noat
 
 /*
+ * t7 is used as a flag to note inatomic mode.
+ */
+LEAF(__copy_user_inatomic)
+	b	__copy_user_common
+	 li	t7, 1
+	END(__copy_user_inatomic)
+
+/*
  * A combined memcpy/__copy_user
  * __copy_user sets len to 0 for success; else to an upper bound of
  * the number of uncopied bytes.
@@ -174,6 +182,8 @@ LEAF(memcpy)					/* a0=dst a1=src a2=len */
 	move	v0, dst				/* return value */
 __memcpy:
 FEXPORT(__copy_user)
+	li	t7, 0				/* not inatomic */
+__copy_user_common:
 	/*
 	 * Note: dst & src may be unaligned, len may be 0
 	 * Temps
@@ -412,7 +422,6 @@ l_exc_copy:
 	 * Assumes src < THREAD_BUADDR($28)
 	 */
 	LOAD	t0, TI_TASK($28)
-	 nop
 	LOAD	t0, THREAD_BUADDR(t0)
 1:
 EXC(	lb	t1, 0(src),	l_exc)
@@ -422,10 +431,9 @@ EXC(	lb	t1, 0(src),	l_exc)
 	 ADD	dst, dst, 1
 l_exc:
 	LOAD	t0, TI_TASK($28)
-	 nop
 	LOAD	t0, THREAD_BUADDR(t0)	# t0 is just past last good address
-	 nop
 	SUB	len, AT, t0		# len number of uncopied bytes
+	bnez	t7, 2f		/* Skip the zeroing out part if inatomic */
 	/*
 	 * Here's where we rely on src and dst being incremented in tandem,
 	 *   See (3) above.
@@ -443,7 +451,7 @@ l_exc:
 	ADD	dst, dst, 1
 	bnez	src, 1b
 	 SUB	src, src, 1
-	jr	ra
+2:	jr	ra
 	 nop
 
 
diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c
index cd61d72..2754bc2 100644
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2004-2010 Cavium Networks
+ * Copyright (C) 2004-2011 Cavium Networks
  * Copyright (C) 2008 Wind River Systems
  */
 
@@ -13,10 +13,16 @@
 #include <linux/usb.h>
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt.h>
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-rnm-defs.h>
+#include <asm/octeon/cvmx-helper.h>
+#include <asm/octeon/cvmx-helper-board.h>
 
 static struct octeon_cf_data octeon_cf_data;
 
@@ -440,6 +446,521 @@ device_initcall(octeon_ohci_device_init);
 
 #endif /* CONFIG_USB */
 
+static struct of_device_id __initdata octeon_ids[] = {
+	{ .compatible = "simple-bus", },
+	{ .compatible = "cavium,octeon-6335-uctl", },
+	{ .compatible = "cavium,octeon-3860-bootbus", },
+	{ .compatible = "cavium,mdio-mux", },
+	{ .compatible = "gpio-leds", },
+	{},
+};
+
+static bool __init octeon_has_88e1145(void)
+{
+	return !OCTEON_IS_MODEL(OCTEON_CN52XX) &&
+	       !OCTEON_IS_MODEL(OCTEON_CN6XXX) &&
+	       !OCTEON_IS_MODEL(OCTEON_CN56XX);
+}
+
+static void __init octeon_fdt_set_phy(int eth, int phy_addr)
+{
+	const __be32 *phy_handle;
+	const __be32 *alt_phy_handle;
+	const __be32 *reg;
+	u32 phandle;
+	int phy;
+	int alt_phy;
+	const char *p;
+	int current_len;
+	char new_name[20];
+
+	phy_handle = fdt_getprop(initial_boot_params, eth, "phy-handle", NULL);
+	if (!phy_handle)
+		return;
+
+	phandle = be32_to_cpup(phy_handle);
+	phy = fdt_node_offset_by_phandle(initial_boot_params, phandle);
+
+	alt_phy_handle = fdt_getprop(initial_boot_params, eth, "cavium,alt-phy-handle", NULL);
+	if (alt_phy_handle) {
+		u32 alt_phandle = be32_to_cpup(alt_phy_handle);
+		alt_phy = fdt_node_offset_by_phandle(initial_boot_params, alt_phandle);
+	} else {
+		alt_phy = -1;
+	}
+
+	if (phy_addr < 0 || phy < 0) {
+		/* Delete the PHY things */
+		fdt_nop_property(initial_boot_params, eth, "phy-handle");
+		/* This one may fail */
+		fdt_nop_property(initial_boot_params, eth, "cavium,alt-phy-handle");
+		if (phy >= 0)
+			fdt_nop_node(initial_boot_params, phy);
+		if (alt_phy >= 0)
+			fdt_nop_node(initial_boot_params, alt_phy);
+		return;
+	}
+
+	if (phy_addr >= 256 && alt_phy > 0) {
+		const struct fdt_property *phy_prop;
+		struct fdt_property *alt_prop;
+		u32 phy_handle_name;
+
+		/* Use the alt phy node instead.*/
+		phy_prop = fdt_get_property(initial_boot_params, eth, "phy-handle", NULL);
+		phy_handle_name = phy_prop->nameoff;
+		fdt_nop_node(initial_boot_params, phy);
+		fdt_nop_property(initial_boot_params, eth, "phy-handle");
+		alt_prop = fdt_get_property_w(initial_boot_params, eth, "cavium,alt-phy-handle", NULL);
+		alt_prop->nameoff = phy_handle_name;
+		phy = alt_phy;
+	}
+
+	phy_addr &= 0xff;
+
+	if (octeon_has_88e1145()) {
+		fdt_nop_property(initial_boot_params, phy, "marvell,reg-init");
+		memset(new_name, 0, sizeof(new_name));
+		strcpy(new_name, "marvell,88e1145");
+		p = fdt_getprop(initial_boot_params, phy, "compatible",
+				&current_len);
+		if (p && current_len >= strlen(new_name))
+			fdt_setprop_inplace(initial_boot_params, phy,
+					"compatible", new_name, current_len);
+	}
+
+	reg = fdt_getprop(initial_boot_params, phy, "reg", NULL);
+	if (phy_addr == be32_to_cpup(reg))
+		return;
+
+	fdt_setprop_inplace_cell(initial_boot_params, phy, "reg", phy_addr);
+
+	snprintf(new_name, sizeof(new_name), "ethernet-phy@%x", phy_addr);
+
+	p = fdt_get_name(initial_boot_params, phy, &current_len);
+	if (p && current_len == strlen(new_name))
+		fdt_set_name(initial_boot_params, phy, new_name);
+	else
+		pr_err("Error: could not rename ethernet phy: <%s>", p);
+}
+
+static void __init octeon_fdt_set_mac_addr(int n, u64 *pmac)
+{
+	u8 new_mac[6];
+	u64 mac = *pmac;
+	int r;
+
+	new_mac[0] = (mac >> 40) & 0xff;
+	new_mac[1] = (mac >> 32) & 0xff;
+	new_mac[2] = (mac >> 24) & 0xff;
+	new_mac[3] = (mac >> 16) & 0xff;
+	new_mac[4] = (mac >> 8) & 0xff;
+	new_mac[5] = mac & 0xff;
+
+	r = fdt_setprop_inplace(initial_boot_params, n, "local-mac-address",
+				new_mac, sizeof(new_mac));
+
+	if (r) {
+		pr_err("Setting \"local-mac-address\" failed %d", r);
+		return;
+	}
+	*pmac = mac + 1;
+}
+
+static void __init octeon_fdt_rm_ethernet(int node)
+{
+	const __be32 *phy_handle;
+
+	phy_handle = fdt_getprop(initial_boot_params, node, "phy-handle", NULL);
+	if (phy_handle) {
+		u32 ph = be32_to_cpup(phy_handle);
+		int p = fdt_node_offset_by_phandle(initial_boot_params, ph);
+		if (p >= 0)
+			fdt_nop_node(initial_boot_params, p);
+	}
+	fdt_nop_node(initial_boot_params, node);
+}
+
+static void __init octeon_fdt_pip_port(int iface, int i, int p, int max, u64 *pmac)
+{
+	char name_buffer[20];
+	int eth;
+	int phy_addr;
+	int ipd_port;
+
+	snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", p);
+	eth = fdt_subnode_offset(initial_boot_params, iface, name_buffer);
+	if (eth < 0)
+		return;
+	if (p > max) {
+		pr_debug("Deleting port %x:%x\n", i, p);
+		octeon_fdt_rm_ethernet(eth);
+		return;
+	}
+	if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+		ipd_port = (0x100 * i) + (0x10 * p) + 0x800;
+	else
+		ipd_port = 16 * i + p;
+
+	phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
+	octeon_fdt_set_phy(eth, phy_addr);
+	octeon_fdt_set_mac_addr(eth, pmac);
+}
+
+static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac)
+{
+	char name_buffer[20];
+	int iface;
+	int p;
+	int count;
+
+	count = cvmx_helper_interface_enumerate(idx);
+
+	snprintf(name_buffer, sizeof(name_buffer), "interface@%d", idx);
+	iface = fdt_subnode_offset(initial_boot_params, pip, name_buffer);
+	if (iface < 0)
+		return;
+
+	for (p = 0; p < 16; p++)
+		octeon_fdt_pip_port(iface, idx, p, count - 1, pmac);
+}
+
+int __init octeon_prune_device_tree(void)
+{
+	int i, max_port, uart_mask;
+	const char *pip_path;
+	const char *alias_prop;
+	char name_buffer[20];
+	int aliases;
+	u64 mac_addr_base;
+
+	if (fdt_check_header(initial_boot_params))
+		panic("Corrupt Device Tree.");
+
+	aliases = fdt_path_offset(initial_boot_params, "/aliases");
+	if (aliases < 0) {
+		pr_err("Error: No /aliases node in device tree.");
+		return -EINVAL;
+	}
+
+
+	mac_addr_base =
+		((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 |
+		((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 |
+		((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 |
+		((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 |
+		((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 |
+		(octeon_bootinfo->mac_addr_base[5] & 0xffull);
+
+	if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX))
+		max_port = 2;
+	else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX))
+		max_port = 1;
+	else
+		max_port = 0;
+
+	if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E)
+		max_port = 0;
+
+	for (i = 0; i < 2; i++) {
+		int mgmt;
+		snprintf(name_buffer, sizeof(name_buffer),
+			 "mix%d", i);
+		alias_prop = fdt_getprop(initial_boot_params, aliases,
+					name_buffer, NULL);
+		if (alias_prop) {
+			mgmt = fdt_path_offset(initial_boot_params, alias_prop);
+			if (mgmt < 0)
+				continue;
+			if (i >= max_port) {
+				pr_debug("Deleting mix%d\n", i);
+				octeon_fdt_rm_ethernet(mgmt);
+				fdt_nop_property(initial_boot_params, aliases,
+						 name_buffer);
+			} else {
+				int phy_addr = cvmx_helper_board_get_mii_address(CVMX_HELPER_BOARD_MGMT_IPD_PORT + i);
+				octeon_fdt_set_phy(mgmt, phy_addr);
+				octeon_fdt_set_mac_addr(mgmt, &mac_addr_base);
+			}
+		}
+	}
+
+	pip_path = fdt_getprop(initial_boot_params, aliases, "pip", NULL);
+	if (pip_path) {
+		int pip = fdt_path_offset(initial_boot_params, pip_path);
+		if (pip  >= 0)
+			for (i = 0; i <= 4; i++)
+				octeon_fdt_pip_iface(pip, i, &mac_addr_base);
+	}
+
+	/* I2C */
+	if (OCTEON_IS_MODEL(OCTEON_CN52XX) ||
+	    OCTEON_IS_MODEL(OCTEON_CN63XX) ||
+	    OCTEON_IS_MODEL(OCTEON_CN68XX) ||
+	    OCTEON_IS_MODEL(OCTEON_CN56XX))
+		max_port = 2;
+	else
+		max_port = 1;
+
+	for (i = 0; i < 2; i++) {
+		int i2c;
+		snprintf(name_buffer, sizeof(name_buffer),
+			 "twsi%d", i);
+		alias_prop = fdt_getprop(initial_boot_params, aliases,
+					name_buffer, NULL);
+
+		if (alias_prop) {
+			i2c = fdt_path_offset(initial_boot_params, alias_prop);
+			if (i2c < 0)
+				continue;
+			if (i >= max_port) {
+				pr_debug("Deleting twsi%d\n", i);
+				fdt_nop_node(initial_boot_params, i2c);
+				fdt_nop_property(initial_boot_params, aliases,
+						 name_buffer);
+			}
+		}
+	}
+
+	/* SMI/MDIO */
+	if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+		max_port = 4;
+	else if (OCTEON_IS_MODEL(OCTEON_CN52XX) ||
+		 OCTEON_IS_MODEL(OCTEON_CN63XX) ||
+		 OCTEON_IS_MODEL(OCTEON_CN56XX))
+		max_port = 2;
+	else
+		max_port = 1;
+
+	for (i = 0; i < 2; i++) {
+		int i2c;
+		snprintf(name_buffer, sizeof(name_buffer),
+			 "smi%d", i);
+		alias_prop = fdt_getprop(initial_boot_params, aliases,
+					name_buffer, NULL);
+
+		if (alias_prop) {
+			i2c = fdt_path_offset(initial_boot_params, alias_prop);
+			if (i2c < 0)
+				continue;
+			if (i >= max_port) {
+				pr_debug("Deleting smi%d\n", i);
+				fdt_nop_node(initial_boot_params, i2c);
+				fdt_nop_property(initial_boot_params, aliases,
+						 name_buffer);
+			}
+		}
+	}
+
+	/* Serial */
+	uart_mask = 3;
+
+	/* Right now CN52XX is the only chip with a third uart */
+	if (OCTEON_IS_MODEL(OCTEON_CN52XX))
+		uart_mask |= 4; /* uart2 */
+
+	for (i = 0; i < 3; i++) {
+		int uart;
+		snprintf(name_buffer, sizeof(name_buffer),
+			 "uart%d", i);
+		alias_prop = fdt_getprop(initial_boot_params, aliases,
+					name_buffer, NULL);
+
+		if (alias_prop) {
+			uart = fdt_path_offset(initial_boot_params, alias_prop);
+			if (uart_mask & (1 << i))
+				continue;
+			pr_debug("Deleting uart%d\n", i);
+			fdt_nop_node(initial_boot_params, uart);
+			fdt_nop_property(initial_boot_params, aliases,
+					 name_buffer);
+		}
+	}
+
+	/* Compact Flash */
+	alias_prop = fdt_getprop(initial_boot_params, aliases,
+				 "cf0", NULL);
+	if (alias_prop) {
+		union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg;
+		unsigned long base_ptr, region_base, region_size;
+		unsigned long region1_base = 0;
+		unsigned long region1_size = 0;
+		int cs, bootbus;
+		bool is_16bit = false;
+		bool is_true_ide = false;
+		__be32 new_reg[6];
+		__be32 *ranges;
+		int len;
+
+		int cf = fdt_path_offset(initial_boot_params, alias_prop);
+		base_ptr = 0;
+		if (octeon_bootinfo->major_version == 1
+			&& octeon_bootinfo->minor_version >= 1) {
+			if (octeon_bootinfo->compact_flash_common_base_addr)
+				base_ptr = octeon_bootinfo->compact_flash_common_base_addr;
+		} else {
+			base_ptr = 0x1d000800;
+		}
+
+		if (!base_ptr)
+			goto no_cf;
+
+		/* Find CS0 region. */
+		for (cs = 0; cs < 8; cs++) {
+			mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs));
+			region_base = mio_boot_reg_cfg.s.base << 16;
+			region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
+			if (mio_boot_reg_cfg.s.en && base_ptr >= region_base
+				&& base_ptr < region_base + region_size) {
+				is_16bit = mio_boot_reg_cfg.s.width;
+				break;
+			}
+		}
+		if (cs >= 7) {
+			/* cs and cs + 1 are CS0 and CS1, both must be less than 8. */
+			goto no_cf;
+		}
+
+		if (!(base_ptr & 0xfffful)) {
+			/*
+			 * Boot loader signals availability of DMA (true_ide
+			 * mode) by setting low order bits of base_ptr to
+			 * zero.
+			 */
+
+			/* Asume that CS1 immediately follows. */
+			mio_boot_reg_cfg.u64 =
+				cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs + 1));
+			region1_base = mio_boot_reg_cfg.s.base << 16;
+			region1_size = (mio_boot_reg_cfg.s.size + 1) << 16;
+			if (!mio_boot_reg_cfg.s.en)
+				goto no_cf;
+			is_true_ide = true;
+
+		} else {
+			fdt_nop_property(initial_boot_params, cf, "cavium,true-ide");
+			fdt_nop_property(initial_boot_params, cf, "cavium,dma-engine-handle");
+			if (!is_16bit) {
+				__be32 width = cpu_to_be32(8);
+				fdt_setprop_inplace(initial_boot_params, cf,
+						"cavium,bus-width", &width, sizeof(width));
+			}
+		}
+		new_reg[0] = cpu_to_be32(cs);
+		new_reg[1] = cpu_to_be32(0);
+		new_reg[2] = cpu_to_be32(0x10000);
+		new_reg[3] = cpu_to_be32(cs + 1);
+		new_reg[4] = cpu_to_be32(0);
+		new_reg[5] = cpu_to_be32(0x10000);
+		fdt_setprop_inplace(initial_boot_params, cf,
+				    "reg",  new_reg, sizeof(new_reg));
+
+		bootbus = fdt_parent_offset(initial_boot_params, cf);
+		if (bootbus < 0)
+			goto no_cf;
+		ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len);
+		if (!ranges || len < (5 * 8 * sizeof(__be32)))
+			goto no_cf;
+
+		ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32);
+		ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff);
+		ranges[(cs * 5) + 4] = cpu_to_be32(region_size);
+		if (is_true_ide) {
+			cs++;
+			ranges[(cs * 5) + 2] = cpu_to_be32(region1_base >> 32);
+			ranges[(cs * 5) + 3] = cpu_to_be32(region1_base & 0xffffffff);
+			ranges[(cs * 5) + 4] = cpu_to_be32(region1_size);
+		}
+		goto end_cf;
+no_cf:
+		fdt_nop_node(initial_boot_params, cf);
+
+end_cf:
+		;
+	}
+
+	/* 8 char LED */
+	alias_prop = fdt_getprop(initial_boot_params, aliases,
+				 "led0", NULL);
+	if (alias_prop) {
+		union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg;
+		unsigned long base_ptr, region_base, region_size;
+		int cs, bootbus;
+		__be32 new_reg[6];
+		__be32 *ranges;
+		int len;
+		int led = fdt_path_offset(initial_boot_params, alias_prop);
+
+		base_ptr = octeon_bootinfo->led_display_base_addr;
+		if (base_ptr == 0)
+			goto no_led;
+		/* Find CS0 region. */
+		for (cs = 0; cs < 8; cs++) {
+			mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs));
+			region_base = mio_boot_reg_cfg.s.base << 16;
+			region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
+			if (mio_boot_reg_cfg.s.en && base_ptr >= region_base
+				&& base_ptr < region_base + region_size)
+				break;
+		}
+
+		if (cs > 7)
+			goto no_led;
+
+		new_reg[0] = cpu_to_be32(cs);
+		new_reg[1] = cpu_to_be32(0x20);
+		new_reg[2] = cpu_to_be32(0x20);
+		new_reg[3] = cpu_to_be32(cs);
+		new_reg[4] = cpu_to_be32(0);
+		new_reg[5] = cpu_to_be32(0x20);
+		fdt_setprop_inplace(initial_boot_params, led,
+				    "reg",  new_reg, sizeof(new_reg));
+
+		bootbus = fdt_parent_offset(initial_boot_params, led);
+		if (bootbus < 0)
+			goto no_led;
+		ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len);
+		if (!ranges || len < (5 * 8 * sizeof(__be32)))
+			goto no_led;
+
+		ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32);
+		ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff);
+		ranges[(cs * 5) + 4] = cpu_to_be32(region_size);
+		goto end_led;
+
+no_led:
+		fdt_nop_node(initial_boot_params, led);
+end_led:
+		;
+	}
+
+	/* OHCI/UHCI USB */
+	alias_prop = fdt_getprop(initial_boot_params, aliases,
+				 "uctl", NULL);
+	if (alias_prop) {
+		int uctl = fdt_path_offset(initial_boot_params, alias_prop);
+
+		if (uctl >= 0 && (!OCTEON_IS_MODEL(OCTEON_CN6XXX) ||
+				  octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC2E)) {
+			pr_debug("Deleting uctl\n");
+			fdt_nop_node(initial_boot_params, uctl);
+			fdt_nop_property(initial_boot_params, aliases, "uctl");
+		} else if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E ||
+			   octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC4E) {
+			/* Missing "refclk-type" defaults to crystal. */
+			fdt_nop_property(initial_boot_params, uctl, "refclk-type");
+		}
+	}
+
+	return 0;
+}
+
+static int __init octeon_publish_devices(void)
+{
+	return of_platform_bus_probe(NULL, octeon_ids, NULL);
+}
+device_initcall(octeon_publish_devices);
+
 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Platform driver for Octeon SOC");
diff --git a/arch/mips/cavium-octeon/octeon_3xxx.dts b/arch/mips/cavium-octeon/octeon_3xxx.dts
new file mode 100644
index 0000000..f28b2d0
--- /dev/null
+++ b/arch/mips/cavium-octeon/octeon_3xxx.dts
@@ -0,0 +1,571 @@
+/dts-v1/;
+/*
+ * OCTEON 3XXX, 5XXX, 63XX device tree skeleton.
+ *
+ * This device tree is pruned and patched by early boot code before
+ * use.  Because of this, it contains a super-set of the available
+ * devices and properties.
+ */
+/ {
+	compatible = "cavium,octeon-3860";
+	#address-cells = <2>;
+	#size-cells = <2>;
+	interrupt-parent = <&ciu>;
+
+	soc@0 {
+		compatible = "simple-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges; /* Direct mapping */
+
+		ciu: interrupt-controller@1070000000000 {
+			compatible = "cavium,octeon-3860-ciu";
+			interrupt-controller;
+			/* Interrupts are specified by two parts:
+			 * 1) Controller register (0 or 1)
+			 * 2) Bit within the register (0..63)
+			 */
+			#interrupt-cells = <2>;
+			reg = <0x10700 0x00000000 0x0 0x7000>;
+		};
+
+		gpio: gpio-controller@1070000000800 {
+			#gpio-cells = <2>;
+			compatible = "cavium,octeon-3860-gpio";
+			reg = <0x10700 0x00000800 0x0 0x100>;
+			gpio-controller;
+			/* Interrupts are specified by two parts:
+			 * 1) GPIO pin number (0..15)
+			 * 2) Triggering (1 - edge rising
+			 *		  2 - edge falling
+			 *		  4 - level active high
+			 *		  8 - level active low)
+			 */
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			/* The GPIO pin connect to 16 consecutive CUI bits */
+			interrupts = <0 16>, <0 17>, <0 18>, <0 19>,
+				     <0 20>, <0 21>, <0 22>, <0 23>,
+				     <0 24>, <0 25>, <0 26>, <0 27>,
+				     <0 28>, <0 29>, <0 30>, <0 31>;
+		};
+
+		smi0: mdio@1180000001800 {
+			compatible = "cavium,octeon-3860-mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x11800 0x00001800 0x0 0x40>;
+
+			phy0: ethernet-phy@0 {
+				compatible = "marvell,88e1118";
+				marvell,reg-init =
+					/* Fix rx and tx clock transition timing */
+					<2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */
+					/* Adjust LED drive. */
+					<3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */
+					/* irq, blink-activity, blink-link */
+					<3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */
+				reg = <0>;
+			};
+
+			phy1: ethernet-phy@1 {
+				compatible = "marvell,88e1118";
+				marvell,reg-init =
+					/* Fix rx and tx clock transition timing */
+					<2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */
+					/* Adjust LED drive. */
+					<3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */
+					/* irq, blink-activity, blink-link */
+					<3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */
+				reg = <1>;
+			};
+
+			phy2: ethernet-phy@2 {
+				reg = <2>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy3: ethernet-phy@3 {
+				reg = <3>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy4: ethernet-phy@4 {
+				reg = <4>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy5: ethernet-phy@5 {
+				reg = <5>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+
+			phy6: ethernet-phy@6 {
+				reg = <6>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy7: ethernet-phy@7 {
+				reg = <7>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy8: ethernet-phy@8 {
+				reg = <8>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy9: ethernet-phy@9 {
+				reg = <9>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+		};
+
+		smi1: mdio@1180000001900 {
+			compatible = "cavium,octeon-3860-mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x11800 0x00001900 0x0 0x40>;
+
+			phy100: ethernet-phy@1 {
+				reg = <1>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+				interrupt-parent = <&gpio>;
+				interrupts = <12 8>; /* Pin 12, active low */
+			};
+			phy101: ethernet-phy@2 {
+				reg = <2>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+				interrupt-parent = <&gpio>;
+				interrupts = <12 8>; /* Pin 12, active low */
+			};
+			phy102: ethernet-phy@3 {
+				reg = <3>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+				interrupt-parent = <&gpio>;
+				interrupts = <12 8>; /* Pin 12, active low */
+			};
+			phy103: ethernet-phy@4 {
+				reg = <4>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+				interrupt-parent = <&gpio>;
+				interrupts = <12 8>; /* Pin 12, active low */
+			};
+		};
+
+		mix0: ethernet@1070000100000 {
+			compatible = "cavium,octeon-5750-mix";
+			reg = <0x10700 0x00100000 0x0 0x100>, /* MIX */
+			      <0x11800 0xE0000000 0x0 0x300>, /* AGL */
+			      <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED  */
+			      <0x11800 0xE0002000 0x0 0x8>;   /* AGL_PRT_CTL */
+			cell-index = <0>;
+			interrupts = <0 62>, <1 46>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			phy-handle = <&phy0>;
+		};
+
+		mix1: ethernet@1070000100800 {
+			compatible = "cavium,octeon-5750-mix";
+			reg = <0x10700 0x00100800 0x0 0x100>, /* MIX */
+			      <0x11800 0xE0000800 0x0 0x300>, /* AGL */
+			      <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED  */
+			      <0x11800 0xE0002008 0x0 0x8>;   /* AGL_PRT_CTL */
+			cell-index = <1>;
+			interrupts = <1 18>, < 1 46>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			phy-handle = <&phy1>;
+		};
+
+		pip: pip@11800a0000000 {
+			compatible = "cavium,octeon-3860-pip";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x11800 0xa0000000 0x0 0x2000>;
+
+			interface@0 {
+				compatible = "cavium,octeon-3860-pip-interface";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0>; /* interface */
+
+				ethernet@0 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x0>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy2>;
+					cavium,alt-phy-handle = <&phy100>;
+				};
+				ethernet@1 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x1>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy3>;
+					cavium,alt-phy-handle = <&phy101>;
+				};
+				ethernet@2 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x2>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy4>;
+					cavium,alt-phy-handle = <&phy102>;
+				};
+				ethernet@3 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x3>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy5>;
+					cavium,alt-phy-handle = <&phy103>;
+				};
+				ethernet@4 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x4>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+				ethernet@5 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x5>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+				ethernet@6 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x6>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+				ethernet@7 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x7>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+				ethernet@8 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x8>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+				ethernet@9 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x9>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+				ethernet@a {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0xa>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+				ethernet@b {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0xb>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+				ethernet@c {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0xc>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+				ethernet@d {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0xd>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+				ethernet@e {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0xe>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+				ethernet@f {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0xf>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+			};
+
+			interface@1 {
+				compatible = "cavium,octeon-3860-pip-interface";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <1>; /* interface */
+
+				ethernet@0 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x0>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy6>;
+				};
+				ethernet@1 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x1>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy7>;
+				};
+				ethernet@2 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x2>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy8>;
+				};
+				ethernet@3 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x3>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy9>;
+				};
+			};
+		};
+
+		twsi0: i2c@1180000001000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "cavium,octeon-3860-twsi";
+			reg = <0x11800 0x00001000 0x0 0x200>;
+			interrupts = <0 45>;
+			clock-frequency = <100000>;
+
+			rtc@68 {
+				compatible = "dallas,ds1337";
+				reg = <0x68>;
+			};
+			tmp@4c {
+				compatible = "ti,tmp421";
+				reg = <0x4c>;
+			};
+		};
+
+		twsi1: i2c@1180000001200 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "cavium,octeon-3860-twsi";
+			reg = <0x11800 0x00001200 0x0 0x200>;
+			interrupts = <0 59>;
+			clock-frequency = <100000>;
+		};
+
+		uart0: serial@1180000000800 {
+			compatible = "cavium,octeon-3860-uart","ns16550";
+			reg = <0x11800 0x00000800 0x0 0x400>;
+			clock-frequency = <0>;
+			current-speed = <115200>;
+			reg-shift = <3>;
+			interrupts = <0 34>;
+		};
+
+		uart1: serial@1180000000c00 {
+			compatible = "cavium,octeon-3860-uart","ns16550";
+			reg = <0x11800 0x00000c00 0x0 0x400>;
+			clock-frequency = <0>;
+			current-speed = <115200>;
+			reg-shift = <3>;
+			interrupts = <0 35>;
+		};
+
+		uart2: serial@1180000000400 {
+			compatible = "cavium,octeon-3860-uart","ns16550";
+			reg = <0x11800 0x00000400 0x0 0x400>;
+			clock-frequency = <0>;
+			current-speed = <115200>;
+			reg-shift = <3>;
+			interrupts = <1 16>;
+		};
+
+		bootbus: bootbus@1180000000000 {
+			compatible = "cavium,octeon-3860-bootbus";
+			reg = <0x11800 0x00000000 0x0 0x200>;
+			/* The chip select number and offset */
+			#address-cells = <2>;
+			/* The size of the chip select region */
+			#size-cells = <1>;
+			ranges = <0 0  0x0 0x1f400000  0xc00000>,
+				 <1 0  0x10000 0x30000000  0>,
+				 <2 0  0x10000 0x40000000  0>,
+				 <3 0  0x10000 0x50000000  0>,
+				 <4 0  0x0 0x1d020000  0x10000>,
+				 <5 0  0x0 0x1d040000  0x10000>,
+				 <6 0  0x0 0x1d050000  0x10000>,
+				 <7 0  0x10000 0x90000000  0>;
+
+			cavium,cs-config@0 {
+				compatible = "cavium,octeon-3860-bootbus-config";
+				cavium,cs-index = <0>;
+				cavium,t-adr  = <20>;
+				cavium,t-ce   = <60>;
+				cavium,t-oe   = <60>;
+				cavium,t-we   = <45>;
+				cavium,t-rd-hld = <35>;
+				cavium,t-wr-hld = <45>;
+				cavium,t-pause  = <0>;
+				cavium,t-wait   = <0>;
+				cavium,t-page   = <35>;
+				cavium,t-rd-dly = <0>;
+
+				cavium,pages     = <0>;
+				cavium,bus-width = <8>;
+			};
+			cavium,cs-config@4 {
+				compatible = "cavium,octeon-3860-bootbus-config";
+				cavium,cs-index = <4>;
+				cavium,t-adr  = <320>;
+				cavium,t-ce   = <320>;
+				cavium,t-oe   = <320>;
+				cavium,t-we   = <320>;
+				cavium,t-rd-hld = <320>;
+				cavium,t-wr-hld = <320>;
+				cavium,t-pause  = <320>;
+				cavium,t-wait   = <320>;
+				cavium,t-page   = <320>;
+				cavium,t-rd-dly = <0>;
+
+				cavium,pages     = <0>;
+				cavium,bus-width = <8>;
+			};
+			cavium,cs-config@5 {
+				compatible = "cavium,octeon-3860-bootbus-config";
+				cavium,cs-index = <5>;
+				cavium,t-adr  = <5>;
+				cavium,t-ce   = <300>;
+				cavium,t-oe   = <125>;
+				cavium,t-we   = <150>;
+				cavium,t-rd-hld = <100>;
+				cavium,t-wr-hld = <30>;
+				cavium,t-pause  = <0>;
+				cavium,t-wait   = <30>;
+				cavium,t-page   = <320>;
+				cavium,t-rd-dly = <0>;
+
+				cavium,pages     = <0>;
+				cavium,bus-width = <16>;
+			};
+			cavium,cs-config@6 {
+				compatible = "cavium,octeon-3860-bootbus-config";
+				cavium,cs-index = <6>;
+				cavium,t-adr  = <5>;
+				cavium,t-ce   = <300>;
+				cavium,t-oe   = <270>;
+				cavium,t-we   = <150>;
+				cavium,t-rd-hld = <100>;
+				cavium,t-wr-hld = <70>;
+				cavium,t-pause  = <0>;
+				cavium,t-wait   = <0>;
+				cavium,t-page   = <320>;
+				cavium,t-rd-dly = <0>;
+
+				cavium,pages     = <0>;
+				cavium,wait-mode;
+				cavium,bus-width = <16>;
+			};
+
+			flash0: nor@0,0 {
+				compatible = "cfi-flash";
+				reg = <0 0 0x800000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+			};
+
+			led0: led-display@4,0 {
+				compatible = "avago,hdsp-253x";
+				reg = <4 0x20 0x20>, <4 0 0x20>;
+			};
+
+			cf0: compact-flash@5,0 {
+				compatible = "cavium,ebt3000-compact-flash";
+				reg = <5 0 0x10000>, <6 0 0x10000>;
+				cavium,bus-width = <16>;
+				cavium,true-ide;
+				cavium,dma-engine-handle = <&dma0>;
+			};
+		};
+
+		dma0: dma-engine@1180000000100 {
+			compatible = "cavium,octeon-5750-bootbus-dma";
+			reg = <0x11800 0x00000100 0x0 0x8>;
+			interrupts = <0 63>;
+		};
+		dma1: dma-engine@1180000000108 {
+			compatible = "cavium,octeon-5750-bootbus-dma";
+			reg = <0x11800 0x00000108 0x0 0x8>;
+			interrupts = <0 63>;
+		};
+
+		uctl: uctl@118006f000000 {
+			compatible = "cavium,octeon-6335-uctl";
+			reg = <0x11800 0x6f000000 0x0 0x100>;
+			ranges; /* Direct mapping */
+			#address-cells = <2>;
+			#size-cells = <2>;
+			/* 12MHz, 24MHz and 48MHz allowed */
+			refclk-frequency = <12000000>;
+			/* Either "crystal" or "external" */
+			refclk-type = "crystal";
+
+			ehci@16f0000000000 {
+				compatible = "cavium,octeon-6335-ehci","usb-ehci";
+				reg = <0x16f00 0x00000000 0x0 0x100>;
+				interrupts = <0 56>;
+				big-endian-regs;
+			};
+			ohci@16f0000000400 {
+				compatible = "cavium,octeon-6335-ohci","usb-ohci";
+				reg = <0x16f00 0x00000400 0x0 0x100>;
+				interrupts = <0 56>;
+				big-endian-regs;
+			};
+		};
+	};
+
+	aliases {
+		mix0 = &mix0;
+		mix1 = &mix1;
+		pip = &pip;
+		smi0 = &smi0;
+		smi1 = &smi1;
+		twsi0 = &twsi0;
+		twsi1 = &twsi1;
+		uart0 = &uart0;
+		uart1 = &uart1;
+		uart2 = &uart2;
+		flash0 = &flash0;
+		cf0 = &cf0;
+		uctl = &uctl;
+		led0 = &led0;
+	};
+ };
diff --git a/arch/mips/cavium-octeon/octeon_68xx.dts b/arch/mips/cavium-octeon/octeon_68xx.dts
new file mode 100644
index 0000000..1839468
--- /dev/null
+++ b/arch/mips/cavium-octeon/octeon_68xx.dts
@@ -0,0 +1,625 @@
+/dts-v1/;
+/*
+ * OCTEON 68XX device tree skeleton.
+ *
+ * This device tree is pruned and patched by early boot code before
+ * use.  Because of this, it contains a super-set of the available
+ * devices and properties.
+ */
+/ {
+	compatible = "cavium,octeon-6880";
+	#address-cells = <2>;
+	#size-cells = <2>;
+	interrupt-parent = <&ciu2>;
+
+	soc@0 {
+		compatible = "simple-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges; /* Direct mapping */
+
+		ciu2: interrupt-controller@1070100000000 {
+			compatible = "cavium,octeon-6880-ciu2";
+			interrupt-controller;
+			/* Interrupts are specified by two parts:
+			 * 1) Controller register (0 or 7)
+			 * 2) Bit within the register (0..63)
+			 */
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <0x10701 0x00000000 0x0 0x4000000>;
+		};
+
+		gpio: gpio-controller@1070000000800 {
+			#gpio-cells = <2>;
+			compatible = "cavium,octeon-3860-gpio";
+			reg = <0x10700 0x00000800 0x0 0x100>;
+			gpio-controller;
+			/* Interrupts are specified by two parts:
+			 * 1) GPIO pin number (0..15)
+			 * 2) Triggering (1 - edge rising
+			 *		  2 - edge falling
+			 *		  4 - level active high
+			 *		  8 - level active low)
+			 */
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			/* The GPIO pins connect to 16 consecutive CUI bits */
+			interrupts = <7 0>,  <7 1>,  <7 2>,  <7 3>,
+				     <7 4>,  <7 5>,  <7 6>,  <7 7>,
+				     <7 8>,  <7 9>,  <7 10>, <7 11>,
+				     <7 12>, <7 13>, <7 14>, <7 15>;
+		};
+
+		smi0: mdio@1180000003800 {
+			compatible = "cavium,octeon-3860-mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x11800 0x00003800 0x0 0x40>;
+
+			phy0: ethernet-phy@6 {
+				compatible = "marvell,88e1118";
+				marvell,reg-init =
+					/* Fix rx and tx clock transition timing */
+					<2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */
+					/* Adjust LED drive. */
+					<3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */
+					/* irq, blink-activity, blink-link */
+					<3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */
+				reg = <6>;
+			};
+
+			phy1: ethernet-phy@1 {
+				cavium,qlm-trim = "4,sgmii";
+				reg = <1>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy2: ethernet-phy@2 {
+				cavium,qlm-trim = "4,sgmii";
+				reg = <2>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy3: ethernet-phy@3 {
+				cavium,qlm-trim = "4,sgmii";
+				reg = <3>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy4: ethernet-phy@4 {
+				cavium,qlm-trim = "4,sgmii";
+				reg = <4>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+		};
+
+		smi1: mdio@1180000003880 {
+			compatible = "cavium,octeon-3860-mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x11800 0x00003880 0x0 0x40>;
+
+			phy41: ethernet-phy@1 {
+				cavium,qlm-trim = "0,sgmii";
+				reg = <1>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy42: ethernet-phy@2 {
+				cavium,qlm-trim = "0,sgmii";
+				reg = <2>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy43: ethernet-phy@3 {
+				cavium,qlm-trim = "0,sgmii";
+				reg = <3>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy44: ethernet-phy@4 {
+				cavium,qlm-trim = "0,sgmii";
+				reg = <4>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+		};
+
+		smi2: mdio@1180000003900 {
+			compatible = "cavium,octeon-3860-mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x11800 0x00003900 0x0 0x40>;
+
+			phy21: ethernet-phy@1 {
+				cavium,qlm-trim = "2,sgmii";
+				reg = <1>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy22: ethernet-phy@2 {
+				cavium,qlm-trim = "2,sgmii";
+				reg = <2>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy23: ethernet-phy@3 {
+				cavium,qlm-trim = "2,sgmii";
+				reg = <3>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy24: ethernet-phy@4 {
+				cavium,qlm-trim = "2,sgmii";
+				reg = <4>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+		};
+
+		smi3: mdio@1180000003980 {
+			compatible = "cavium,octeon-3860-mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x11800 0x00003980 0x0 0x40>;
+
+			phy11: ethernet-phy@1 {
+				cavium,qlm-trim = "3,sgmii";
+				reg = <1>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy12: ethernet-phy@2 {
+				cavium,qlm-trim = "3,sgmii";
+				reg = <2>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy13: ethernet-phy@3 {
+				cavium,qlm-trim = "3,sgmii";
+				reg = <3>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+			phy14: ethernet-phy@4 {
+				cavium,qlm-trim = "3,sgmii";
+				reg = <4>;
+				compatible = "marvell,88e1149r";
+				marvell,reg-init = <3 0x10 0 0x5777>,
+					<3 0x11 0 0x00aa>,
+					<3 0x12 0 0x4105>,
+					<3 0x13 0 0x0a60>;
+			};
+		};
+
+		mix0: ethernet@1070000100000 {
+			compatible = "cavium,octeon-5750-mix";
+			reg = <0x10700 0x00100000 0x0 0x100>, /* MIX */
+			      <0x11800 0xE0000000 0x0 0x300>, /* AGL */
+			      <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED  */
+			      <0x11800 0xE0002000 0x0 0x8>;   /* AGL_PRT_CTL */
+			cell-index = <0>;
+			interrupts = <6 40>, <6 32>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			phy-handle = <&phy0>;
+		};
+
+		pip: pip@11800a0000000 {
+			compatible = "cavium,octeon-3860-pip";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x11800 0xa0000000 0x0 0x2000>;
+
+			interface@4 {
+				compatible = "cavium,octeon-3860-pip-interface";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x4>; /* interface */
+
+				ethernet@0 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x0>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy1>;
+				};
+				ethernet@1 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x1>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy2>;
+				};
+				ethernet@2 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x2>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy3>;
+				};
+				ethernet@3 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x3>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy4>;
+				};
+			};
+
+			interface@3 {
+				compatible = "cavium,octeon-3860-pip-interface";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x3>; /* interface */
+
+				ethernet@0 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x0>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy11>;
+				};
+				ethernet@1 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x1>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy12>;
+				};
+				ethernet@2 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x2>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy13>;
+				};
+				ethernet@3 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x3>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy14>;
+				};
+			};
+
+			interface@2 {
+				compatible = "cavium,octeon-3860-pip-interface";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x2>; /* interface */
+
+				ethernet@0 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x0>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy21>;
+				};
+				ethernet@1 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x1>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy22>;
+				};
+				ethernet@2 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x2>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy23>;
+				};
+				ethernet@3 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x3>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy24>;
+				};
+			};
+
+			interface@1 {
+				compatible = "cavium,octeon-3860-pip-interface";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x1>; /* interface */
+
+				ethernet@0 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x0>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+				};
+			};
+
+			interface@0 {
+				compatible = "cavium,octeon-3860-pip-interface";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x0>; /* interface */
+
+				ethernet@0 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x0>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy41>;
+				};
+				ethernet@1 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x1>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy42>;
+				};
+				ethernet@2 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x2>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy43>;
+				};
+				ethernet@3 {
+					compatible = "cavium,octeon-3860-pip-port";
+					reg = <0x3>; /* Port */
+					local-mac-address = [ 00 00 00 00 00 00 ];
+					phy-handle = <&phy44>;
+				};
+			};
+		};
+
+		twsi0: i2c@1180000001000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "cavium,octeon-3860-twsi";
+			reg = <0x11800 0x00001000 0x0 0x200>;
+			interrupts = <3 32>;
+			clock-frequency = <100000>;
+
+			rtc@68 {
+				compatible = "dallas,ds1337";
+				reg = <0x68>;
+			};
+			tmp@4c {
+				compatible = "ti,tmp421";
+				reg = <0x4c>;
+			};
+		};
+
+		twsi1: i2c@1180000001200 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "cavium,octeon-3860-twsi";
+			reg = <0x11800 0x00001200 0x0 0x200>;
+			interrupts = <3 33>;
+			clock-frequency = <100000>;
+		};
+
+		uart0: serial@1180000000800 {
+			compatible = "cavium,octeon-3860-uart","ns16550";
+			reg = <0x11800 0x00000800 0x0 0x400>;
+			clock-frequency = <0>;
+			current-speed = <115200>;
+			reg-shift = <3>;
+			interrupts = <3 36>;
+		};
+
+		uart1: serial@1180000000c00 {
+			compatible = "cavium,octeon-3860-uart","ns16550";
+			reg = <0x11800 0x00000c00 0x0 0x400>;
+			clock-frequency = <0>;
+			current-speed = <115200>;
+			reg-shift = <3>;
+			interrupts = <3 37>;
+		};
+
+		bootbus: bootbus@1180000000000 {
+			compatible = "cavium,octeon-3860-bootbus";
+			reg = <0x11800 0x00000000 0x0 0x200>;
+			/* The chip select number and offset */
+			#address-cells = <2>;
+			/* The size of the chip select region */
+			#size-cells = <1>;
+			ranges = <0 0  0       0x1f400000  0xc00000>,
+				 <1 0  0x10000 0x30000000  0>,
+				 <2 0  0x10000 0x40000000  0>,
+				 <3 0  0x10000 0x50000000  0>,
+				 <4 0  0       0x1d020000  0x10000>,
+				 <5 0  0       0x1d040000  0x10000>,
+				 <6 0  0       0x1d050000  0x10000>,
+				 <7 0  0x10000 0x90000000  0>;
+
+			cavium,cs-config@0 {
+				compatible = "cavium,octeon-3860-bootbus-config";
+				cavium,cs-index = <0>;
+				cavium,t-adr  = <10>;
+				cavium,t-ce   = <50>;
+				cavium,t-oe   = <50>;
+				cavium,t-we   = <35>;
+				cavium,t-rd-hld = <25>;
+				cavium,t-wr-hld = <35>;
+				cavium,t-pause  = <0>;
+				cavium,t-wait   = <300>;
+				cavium,t-page   = <25>;
+				cavium,t-rd-dly = <0>;
+
+				cavium,pages     = <0>;
+				cavium,bus-width = <8>;
+			};
+			cavium,cs-config@4 {
+				compatible = "cavium,octeon-3860-bootbus-config";
+				cavium,cs-index = <4>;
+				cavium,t-adr  = <320>;
+				cavium,t-ce   = <320>;
+				cavium,t-oe   = <320>;
+				cavium,t-we   = <320>;
+				cavium,t-rd-hld = <320>;
+				cavium,t-wr-hld = <320>;
+				cavium,t-pause  = <320>;
+				cavium,t-wait   = <320>;
+				cavium,t-page   = <320>;
+				cavium,t-rd-dly = <0>;
+
+				cavium,pages     = <0>;
+				cavium,bus-width = <8>;
+			};
+			cavium,cs-config@5 {
+				compatible = "cavium,octeon-3860-bootbus-config";
+				cavium,cs-index = <5>;
+				cavium,t-adr  = <0>;
+				cavium,t-ce   = <300>;
+				cavium,t-oe   = <125>;
+				cavium,t-we   = <150>;
+				cavium,t-rd-hld = <100>;
+				cavium,t-wr-hld = <300>;
+				cavium,t-pause  = <0>;
+				cavium,t-wait   = <300>;
+				cavium,t-page   = <310>;
+				cavium,t-rd-dly = <0>;
+
+				cavium,pages     = <0>;
+				cavium,bus-width = <16>;
+			};
+			cavium,cs-config@6 {
+				compatible = "cavium,octeon-3860-bootbus-config";
+				cavium,cs-index = <6>;
+				cavium,t-adr  = <0>;
+				cavium,t-ce   = <30>;
+				cavium,t-oe   = <125>;
+				cavium,t-we   = <150>;
+				cavium,t-rd-hld = <100>;
+				cavium,t-wr-hld = <30>;
+				cavium,t-pause  = <0>;
+				cavium,t-wait   = <30>;
+				cavium,t-page   = <310>;
+				cavium,t-rd-dly = <0>;
+
+				cavium,pages     = <0>;
+				cavium,wait-mode;
+				cavium,bus-width = <16>;
+			};
+
+			flash0: nor@0,0 {
+				compatible = "cfi-flash";
+				reg = <0 0 0x800000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				partition@0 {
+					label = "bootloader";
+					reg = <0 0x200000>;
+					read-only;
+				};
+				partition@200000 {
+					label = "kernel";
+					reg = <0x200000 0x200000>;
+				};
+				partition@400000 {
+					label = "cramfs";
+					reg = <0x400000 0x3fe000>;
+				};
+				partition@7fe000 {
+					label = "environment";
+					reg = <0x7fe000 0x2000>;
+					read-only;
+				};
+			};
+
+			led0: led-display@4,0 {
+				compatible = "avago,hdsp-253x";
+				reg = <4 0x20 0x20>, <4 0 0x20>;
+			};
+
+			compact-flash@5,0 {
+				compatible = "cavium,ebt3000-compact-flash";
+				reg = <5 0 0x10000>, <6 0 0x10000>;
+				cavium,bus-width = <16>;
+				cavium,true-ide;
+				cavium,dma-engine-handle = <&dma0>;
+			};
+		};
+
+		dma0: dma-engine@1180000000100 {
+			compatible = "cavium,octeon-5750-bootbus-dma";
+			reg = <0x11800 0x00000100 0x0 0x8>;
+			interrupts = <0 63>;
+		};
+		dma1: dma-engine@1180000000108 {
+			compatible = "cavium,octeon-5750-bootbus-dma";
+			reg = <0x11800 0x00000108 0x0 0x8>;
+			interrupts = <0 63>;
+		};
+
+		uctl: uctl@118006f000000 {
+			compatible = "cavium,octeon-6335-uctl";
+			reg = <0x11800 0x6f000000 0x0 0x100>;
+			ranges; /* Direct mapping */
+			#address-cells = <2>;
+			#size-cells = <2>;
+			/* 12MHz, 24MHz and 48MHz allowed */
+			refclk-frequency = <12000000>;
+			/* Either "crystal" or "external" */
+			refclk-type = "crystal";
+
+			ehci@16f0000000000 {
+				compatible = "cavium,octeon-6335-ehci","usb-ehci";
+				reg = <0x16f00 0x00000000 0x0 0x100>;
+				interrupts = <3 44>;
+				big-endian-regs;
+			};
+			ohci@16f0000000400 {
+				compatible = "cavium,octeon-6335-ohci","usb-ohci";
+				reg = <0x16f00 0x00000400 0x0 0x100>;
+				interrupts = <3 44>;
+				big-endian-regs;
+			};
+		};
+	};
+
+	aliases {
+		mix0 = &mix0;
+		pip = &pip;
+		smi0 = &smi0;
+		smi1 = &smi1;
+		smi2 = &smi2;
+		smi3 = &smi3;
+		twsi0 = &twsi0;
+		twsi1 = &twsi1;
+		uart0 = &uart0;
+		uart1 = &uart1;
+		uctl = &uctl;
+		led0 = &led0;
+		flash0 = &flash0;
+	};
+ };
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index 260dc24..919b0fb 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -21,6 +21,8 @@
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt.h>
 
 #include <asm/processor.h>
 #include <asm/reboot.h>
@@ -775,3 +777,46 @@ void prom_free_prom_memory(void)
 	}
 #endif
 }
+
+int octeon_prune_device_tree(void);
+
+extern const char __dtb_octeon_3xxx_begin;
+extern const char __dtb_octeon_3xxx_end;
+extern const char __dtb_octeon_68xx_begin;
+extern const char __dtb_octeon_68xx_end;
+void __init device_tree_init(void)
+{
+	int dt_size;
+	struct boot_param_header *fdt;
+	bool do_prune;
+
+	if (octeon_bootinfo->minor_version >= 3 && octeon_bootinfo->fdt_addr) {
+		fdt = phys_to_virt(octeon_bootinfo->fdt_addr);
+		if (fdt_check_header(fdt))
+			panic("Corrupt Device Tree passed to kernel.");
+		dt_size = be32_to_cpu(fdt->totalsize);
+		do_prune = false;
+	} else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
+		fdt = (struct boot_param_header *)&__dtb_octeon_68xx_begin;
+		dt_size = &__dtb_octeon_68xx_end - &__dtb_octeon_68xx_begin;
+		do_prune = true;
+	} else {
+		fdt = (struct boot_param_header *)&__dtb_octeon_3xxx_begin;
+		dt_size = &__dtb_octeon_3xxx_end - &__dtb_octeon_3xxx_begin;
+		do_prune = true;
+	}
+
+	/* Copy the default tree from init memory. */
+	initial_boot_params = early_init_dt_alloc_memory_arch(dt_size, 8);
+	if (initial_boot_params == NULL)
+		panic("Could not allocate initial_boot_params\n");
+	memcpy(initial_boot_params, fdt, dt_size);
+
+	if (do_prune) {
+		octeon_prune_device_tree();
+		pr_info("Using internal Device Tree.\n");
+	} else {
+		pr_info("Using passed Device Tree.\n");
+	}
+	unflatten_device_tree();
+}
diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c
index 4b93048..ee1fb9f 100644
--- a/arch/mips/cavium-octeon/smp.c
+++ b/arch/mips/cavium-octeon/smp.c
@@ -185,7 +185,6 @@ static void __cpuinit octeon_init_secondary(void)
 	octeon_init_cvmcount();
 
 	octeon_irq_setup_secondary();
-	raw_local_irq_enable();
 }
 
 /**
@@ -233,6 +232,7 @@ static void octeon_smp_finish(void)
 
 	/* to generate the first CPU timer interrupt */
 	write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
+	local_irq_enable();
 }
 
 /**
diff --git a/arch/mips/configs/ls1b_defconfig b/arch/mips/configs/ls1b_defconfig
new file mode 100644
index 0000000..5c2c3a1
--- /dev/null
+++ b/arch/mips/configs/ls1b_defconfig
@@ -0,0 +1,108 @@
+CONFIG_MACH_LOONGSON1=y
+CONFIG_PREEMPT=y
+# CONFIG_SECCOMP is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_EXPERT=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_SCSI=m
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=m
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_DA=y
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_WLAN is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_LEGACY_PTY_COUNT=8
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_USB_HID=m
+CONFIG_HID_GENERIC=m
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_STORAGE=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_LOONGSON1=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_FTRACE is not set
+# CONFIG_EARLY_PRINTK is not set
diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig
index d0b857d..138f698 100644
--- a/arch/mips/configs/nlm_xlr_defconfig
+++ b/arch/mips/configs/nlm_xlr_defconfig
@@ -367,6 +367,10 @@ CONFIG_SERIAL_8250_RSA=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_TIMERIOMEM=m
 CONFIG_RAW_DRIVER=m
+CONFIG_I2C=y
+CONFIG_I2C_XLR=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1374=y
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID_SUPPORT is not set
diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c
index e95ff30..8c62316 100644
--- a/arch/mips/dec/prom/memory.c
+++ b/arch/mips/dec/prom/memory.c
@@ -101,7 +101,7 @@ void __init prom_free_prom_memory(void)
 	 * the first page reserved for the exception handlers.
 	 */
 
-#if defined(CONFIG_DECLANCE) || defined(CONFIG_DECLANCE_MODULE)
+#if IS_ENABLED(CONFIG_DECLANCE)
 	/*
 	 * Leave 128 KB reserved for Lance memory for
 	 * IOASIC DECstations.
diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h
index 285a41f..eee10dc 100644
--- a/arch/mips/include/asm/cmpxchg.h
+++ b/arch/mips/include/asm/cmpxchg.h
@@ -8,6 +8,7 @@
 #ifndef __ASM_CMPXCHG_H
 #define __ASM_CMPXCHG_H
 
+#include <linux/bug.h>
 #include <linux/irqflags.h>
 #include <asm/war.h>
 
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index f9fa2a4..f21b7c0 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -94,6 +94,7 @@
 #define PRID_IMP_24KE		0x9600
 #define PRID_IMP_74K		0x9700
 #define PRID_IMP_1004K		0x9900
+#define PRID_IMP_M14KC		0x9c00
 
 /*
  * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE
@@ -196,6 +197,7 @@
 #define PRID_REV_VR4181A	0x0070	/* Same as VR4122 */
 #define PRID_REV_VR4130		0x0080
 #define PRID_REV_34K_V1_0_2	0x0022
+#define PRID_REV_LOONGSON1B	0x0020
 #define PRID_REV_LOONGSON2E	0x0002
 #define PRID_REV_LOONGSON2F	0x0003
 
@@ -260,12 +262,12 @@ enum cpu_type_enum {
 	 */
 	CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
 	CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350,
-	CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC,
+	CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC,
 
 	/*
 	 * MIPS64 class processors
 	 */
-	CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
+	CPU_5KC, CPU_5KE, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
 	CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2,
 	CPU_XLR, CPU_XLP,
 
@@ -288,7 +290,7 @@ enum cpu_type_enum {
 #define MIPS_CPU_ISA_M64R2	0x00000100
 
 #define MIPS_CPU_ISA_32BIT (MIPS_CPU_ISA_I | MIPS_CPU_ISA_II | \
-	MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 )
+	MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2)
 #define MIPS_CPU_ISA_64BIT (MIPS_CPU_ISA_III | MIPS_CPU_ISA_IV | \
 	MIPS_CPU_ISA_V | MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)
 
diff --git a/arch/mips/include/asm/errno.h b/arch/mips/include/asm/errno.h
index 6dcd358..ac95669 100644
--- a/arch/mips/include/asm/errno.h
+++ b/arch/mips/include/asm/errno.h
@@ -122,6 +122,9 @@
 #define	ERFKILL		167	/* Operation not possible due to RF-kill */
 
 #define EHWPOISON	168	/* Memory page has hardware error */
+#define	ENOAUTHSERVICE	169	/* Authentication service not available */
+#define	ENONAMESERVICE	170	/* Network name service unavailable */
+#define	ENAMEUNKNOWN	171	/* Network name unknown */
 
 #define EDQUOT		1133	/* Quota exceeded */
 
diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index 86548da..991b659 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -206,7 +206,7 @@
 
 #define GIC_VPE_EIC_SHADOW_SET_BASE	0x0100
 #define GIC_VPE_EIC_SS(intr) \
-	(GIC_EIC_SHADOW_SET_BASE + (4 * intr))
+	(GIC_VPE_EIC_SHADOW_SET_BASE + (4 * intr))
 
 #define GIC_VPE_EIC_VEC_BASE		0x0800
 #define GIC_VPE_EIC_VEC(intr) \
@@ -330,6 +330,17 @@ struct gic_intr_map {
 #define GIC_FLAG_TRANSPARENT   0x02
 };
 
+/*
+ * This is only used in EIC mode. This helps to figure out which
+ * shared interrupts we need to process when we get a vector interrupt.
+ */
+#define GIC_MAX_SHARED_INTR  0x5
+struct gic_shared_intr_map {
+	unsigned int num_shared_intr;
+	unsigned int intr_list[GIC_MAX_SHARED_INTR];
+	unsigned int local_intr_mask;
+};
+
 extern void gic_init(unsigned long gic_base_addr,
 	unsigned long gic_addrspace_size, struct gic_intr_map *intrmap,
 	unsigned int intrmap_size, unsigned int irqbase);
@@ -338,5 +349,7 @@ extern unsigned int gic_get_int(void);
 extern void gic_send_ipi(unsigned int intr);
 extern unsigned int plat_ipi_call_int_xlate(unsigned int);
 extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
+extern void gic_bind_eic_interrupt(int irq, int set);
+extern unsigned int gic_get_timer_pending(void);
 
 #endif /* _ASM_GICREGS_H */
diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h
index 7ebfc39..ab84064 100644
--- a/arch/mips/include/asm/inst.h
+++ b/arch/mips/include/asm/inst.h
@@ -251,7 +251,7 @@ struct f_format {	/* FPU register format */
 	unsigned int func : 6;
 };
 
-struct ma_format {	/* FPU multipy and add format (MIPS IV) */
+struct ma_format {	/* FPU multiply and add format (MIPS IV) */
 	unsigned int opcode : 6;
 	unsigned int fr : 5;
 	unsigned int ft : 5;
@@ -324,7 +324,7 @@ struct f_format {	/* FPU register format */
 	unsigned int opcode : 6;
 };
 
-struct ma_format {	/* FPU multipy and add format (MIPS IV) */
+struct ma_format {	/* FPU multiply and add format (MIPS IV) */
 	unsigned int fmt : 2;
 	unsigned int func : 4;
 	unsigned int fd : 5;
diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h
index fb698dc..78dbb8a 100644
--- a/arch/mips/include/asm/irq.h
+++ b/arch/mips/include/asm/irq.h
@@ -136,6 +136,7 @@ extern void free_irqno(unsigned int irq);
  * IE7.  Since R2 their number has to be read from the c0_intctl register.
  */
 #define CP0_LEGACY_COMPARE_IRQ 7
+#define CP0_LEGACY_PERFCNT_IRQ 7
 
 extern int cp0_compare_irq;
 extern int cp0_compare_irq_shift;
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
index 5b8d15b..e104ddb 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
@@ -9,6 +9,7 @@
  * compile time if only one CPU support is enabled (idea stolen from
  * arm mach-types)
  */
+#define BCM6328_CPU_ID		0x6328
 #define BCM6338_CPU_ID		0x6338
 #define BCM6345_CPU_ID		0x6345
 #define BCM6348_CPU_ID		0x6348
@@ -20,6 +21,19 @@ u16 __bcm63xx_get_cpu_id(void);
 u16 bcm63xx_get_cpu_rev(void);
 unsigned int bcm63xx_get_cpu_freq(void);
 
+#ifdef CONFIG_BCM63XX_CPU_6328
+# ifdef bcm63xx_get_cpu_id
+#  undef bcm63xx_get_cpu_id
+#  define bcm63xx_get_cpu_id()	__bcm63xx_get_cpu_id()
+#  define BCMCPU_RUNTIME_DETECT
+# else
+#  define bcm63xx_get_cpu_id()	BCM6328_CPU_ID
+# endif
+# define BCMCPU_IS_6328()	(bcm63xx_get_cpu_id() == BCM6328_CPU_ID)
+#else
+# define BCMCPU_IS_6328()	(0)
+#endif
+
 #ifdef CONFIG_BCM63XX_CPU_6338
 # ifdef bcm63xx_get_cpu_id
 #  undef bcm63xx_get_cpu_id
@@ -102,13 +116,13 @@ enum bcm63xx_regs_set {
 	RSET_UART1,
 	RSET_GPIO,
 	RSET_SPI,
-	RSET_SPI2,
 	RSET_UDC0,
 	RSET_OHCI0,
 	RSET_OHCI_PRIV,
 	RSET_USBH_PRIV,
 	RSET_MPI,
 	RSET_PCMCIA,
+	RSET_PCIE,
 	RSET_DSL,
 	RSET_ENET0,
 	RSET_ENET1,
@@ -130,11 +144,17 @@ enum bcm63xx_regs_set {
 	RSET_PCMDMA,
 	RSET_PCMDMAC,
 	RSET_PCMDMAS,
+	RSET_RNG,
+	RSET_MISC
 };
 
 #define RSET_DSL_LMEM_SIZE		(64 * 1024 * 4)
 #define RSET_DSL_SIZE			4096
 #define RSET_WDT_SIZE			12
+#define BCM_6338_RSET_SPI_SIZE		64
+#define BCM_6348_RSET_SPI_SIZE		64
+#define BCM_6358_RSET_SPI_SIZE		1804
+#define BCM_6368_RSET_SPI_SIZE		1804
 #define RSET_ENET_SIZE			2048
 #define RSET_ENETDMA_SIZE		2048
 #define RSET_ENETSW_SIZE		65536
@@ -149,8 +169,53 @@ enum bcm63xx_regs_set {
 #define RSET_XTMDMA_SIZE		256
 #define RSET_XTMDMAC_SIZE(chans)	(16 * (chans))
 #define RSET_XTMDMAS_SIZE(chans)	(16 * (chans))
+#define RSET_RNG_SIZE			20
 
 /*
+ * 6328 register sets base address
+ */
+#define BCM_6328_DSL_LMEM_BASE		(0xdeadbeef)
+#define BCM_6328_PERF_BASE		(0xb0000000)
+#define BCM_6328_TIMER_BASE		(0xb0000040)
+#define BCM_6328_WDT_BASE		(0xb000005c)
+#define BCM_6328_UART0_BASE             (0xb0000100)
+#define BCM_6328_UART1_BASE		(0xb0000120)
+#define BCM_6328_GPIO_BASE		(0xb0000080)
+#define BCM_6328_SPI_BASE		(0xdeadbeef)
+#define BCM_6328_UDC0_BASE		(0xdeadbeef)
+#define BCM_6328_USBDMA_BASE		(0xdeadbeef)
+#define BCM_6328_OHCI0_BASE		(0xdeadbeef)
+#define BCM_6328_OHCI_PRIV_BASE		(0xdeadbeef)
+#define BCM_6328_USBH_PRIV_BASE		(0xdeadbeef)
+#define BCM_6328_MPI_BASE		(0xdeadbeef)
+#define BCM_6328_PCMCIA_BASE		(0xdeadbeef)
+#define BCM_6328_PCIE_BASE		(0xb0e40000)
+#define BCM_6328_SDRAM_REGS_BASE	(0xdeadbeef)
+#define BCM_6328_DSL_BASE		(0xb0001900)
+#define BCM_6328_UBUS_BASE		(0xdeadbeef)
+#define BCM_6328_ENET0_BASE		(0xdeadbeef)
+#define BCM_6328_ENET1_BASE		(0xdeadbeef)
+#define BCM_6328_ENETDMA_BASE		(0xb000d800)
+#define BCM_6328_ENETDMAC_BASE		(0xb000da00)
+#define BCM_6328_ENETDMAS_BASE		(0xb000dc00)
+#define BCM_6328_ENETSW_BASE		(0xb0e00000)
+#define BCM_6328_EHCI0_BASE		(0x10002500)
+#define BCM_6328_SDRAM_BASE		(0xdeadbeef)
+#define BCM_6328_MEMC_BASE		(0xdeadbeef)
+#define BCM_6328_DDR_BASE		(0xb0003000)
+#define BCM_6328_M2M_BASE		(0xdeadbeef)
+#define BCM_6328_ATM_BASE		(0xdeadbeef)
+#define BCM_6328_XTM_BASE		(0xdeadbeef)
+#define BCM_6328_XTMDMA_BASE		(0xb000b800)
+#define BCM_6328_XTMDMAC_BASE		(0xdeadbeef)
+#define BCM_6328_XTMDMAS_BASE		(0xdeadbeef)
+#define BCM_6328_PCM_BASE		(0xb000a800)
+#define BCM_6328_PCMDMA_BASE		(0xdeadbeef)
+#define BCM_6328_PCMDMAC_BASE		(0xdeadbeef)
+#define BCM_6328_PCMDMAS_BASE		(0xdeadbeef)
+#define BCM_6328_RNG_BASE		(0xdeadbeef)
+#define BCM_6328_MISC_BASE		(0xb0001800)
+/*
  * 6338 register sets base address
  */
 #define BCM_6338_DSL_LMEM_BASE		(0xfff00000)
@@ -162,7 +227,6 @@ enum bcm63xx_regs_set {
 #define BCM_6338_UART1_BASE		(0xdeadbeef)
 #define BCM_6338_GPIO_BASE		(0xfffe0400)
 #define BCM_6338_SPI_BASE		(0xfffe0c00)
-#define BCM_6338_SPI2_BASE		(0xdeadbeef)
 #define BCM_6338_UDC0_BASE		(0xdeadbeef)
 #define BCM_6338_USBDMA_BASE		(0xfffe2400)
 #define BCM_6338_OHCI0_BASE		(0xdeadbeef)
@@ -170,6 +234,7 @@ enum bcm63xx_regs_set {
 #define BCM_6338_USBH_PRIV_BASE		(0xdeadbeef)
 #define BCM_6338_MPI_BASE		(0xfffe3160)
 #define BCM_6338_PCMCIA_BASE		(0xdeadbeef)
+#define BCM_6338_PCIE_BASE		(0xdeadbeef)
 #define BCM_6338_SDRAM_REGS_BASE	(0xfffe3100)
 #define BCM_6338_DSL_BASE		(0xfffe1000)
 #define BCM_6338_UBUS_BASE		(0xdeadbeef)
@@ -193,6 +258,8 @@ enum bcm63xx_regs_set {
 #define BCM_6338_PCMDMA_BASE		(0xdeadbeef)
 #define BCM_6338_PCMDMAC_BASE		(0xdeadbeef)
 #define BCM_6338_PCMDMAS_BASE		(0xdeadbeef)
+#define BCM_6338_RNG_BASE		(0xdeadbeef)
+#define BCM_6338_MISC_BASE		(0xdeadbeef)
 
 /*
  * 6345 register sets base address
@@ -206,7 +273,6 @@ enum bcm63xx_regs_set {
 #define BCM_6345_UART1_BASE		(0xdeadbeef)
 #define BCM_6345_GPIO_BASE		(0xfffe0400)
 #define BCM_6345_SPI_BASE		(0xdeadbeef)
-#define BCM_6345_SPI2_BASE		(0xdeadbeef)
 #define BCM_6345_UDC0_BASE		(0xdeadbeef)
 #define BCM_6345_USBDMA_BASE		(0xfffe2800)
 #define BCM_6345_ENET0_BASE		(0xfffe1800)
@@ -216,6 +282,7 @@ enum bcm63xx_regs_set {
 #define BCM_6345_ENETSW_BASE		(0xdeadbeef)
 #define BCM_6345_PCMCIA_BASE		(0xfffe2028)
 #define BCM_6345_MPI_BASE		(0xfffe2000)
+#define BCM_6345_PCIE_BASE		(0xdeadbeef)
 #define BCM_6345_OHCI0_BASE		(0xfffe2100)
 #define BCM_6345_OHCI_PRIV_BASE		(0xfffe2200)
 #define BCM_6345_USBH_PRIV_BASE		(0xdeadbeef)
@@ -237,6 +304,8 @@ enum bcm63xx_regs_set {
 #define BCM_6345_PCMDMA_BASE		(0xdeadbeef)
 #define BCM_6345_PCMDMAC_BASE		(0xdeadbeef)
 #define BCM_6345_PCMDMAS_BASE		(0xdeadbeef)
+#define BCM_6345_RNG_BASE		(0xdeadbeef)
+#define BCM_6345_MISC_BASE		(0xdeadbeef)
 
 /*
  * 6348 register sets base address
@@ -249,13 +318,13 @@ enum bcm63xx_regs_set {
 #define BCM_6348_UART1_BASE		(0xdeadbeef)
 #define BCM_6348_GPIO_BASE		(0xfffe0400)
 #define BCM_6348_SPI_BASE		(0xfffe0c00)
-#define BCM_6348_SPI2_BASE		(0xdeadbeef)
 #define BCM_6348_UDC0_BASE		(0xfffe1000)
 #define BCM_6348_OHCI0_BASE		(0xfffe1b00)
 #define BCM_6348_OHCI_PRIV_BASE		(0xfffe1c00)
 #define BCM_6348_USBH_PRIV_BASE		(0xdeadbeef)
 #define BCM_6348_MPI_BASE		(0xfffe2000)
 #define BCM_6348_PCMCIA_BASE		(0xfffe2054)
+#define BCM_6348_PCIE_BASE		(0xdeadbeef)
 #define BCM_6348_SDRAM_REGS_BASE	(0xfffe2300)
 #define BCM_6348_M2M_BASE		(0xfffe2800)
 #define BCM_6348_DSL_BASE		(0xfffe3000)
@@ -278,6 +347,8 @@ enum bcm63xx_regs_set {
 #define BCM_6348_PCMDMA_BASE		(0xdeadbeef)
 #define BCM_6348_PCMDMAC_BASE		(0xdeadbeef)
 #define BCM_6348_PCMDMAS_BASE		(0xdeadbeef)
+#define BCM_6348_RNG_BASE		(0xdeadbeef)
+#define BCM_6348_MISC_BASE		(0xdeadbeef)
 
 /*
  * 6358 register sets base address
@@ -289,14 +360,14 @@ enum bcm63xx_regs_set {
 #define BCM_6358_UART0_BASE		(0xfffe0100)
 #define BCM_6358_UART1_BASE		(0xfffe0120)
 #define BCM_6358_GPIO_BASE		(0xfffe0080)
-#define BCM_6358_SPI_BASE		(0xdeadbeef)
-#define BCM_6358_SPI2_BASE		(0xfffe0800)
+#define BCM_6358_SPI_BASE		(0xfffe0800)
 #define BCM_6358_UDC0_BASE		(0xfffe0800)
 #define BCM_6358_OHCI0_BASE		(0xfffe1400)
 #define BCM_6358_OHCI_PRIV_BASE		(0xdeadbeef)
 #define BCM_6358_USBH_PRIV_BASE		(0xfffe1500)
 #define BCM_6358_MPI_BASE		(0xfffe1000)
 #define BCM_6358_PCMCIA_BASE		(0xfffe1054)
+#define BCM_6358_PCIE_BASE		(0xdeadbeef)
 #define BCM_6358_SDRAM_REGS_BASE	(0xfffe2300)
 #define BCM_6358_M2M_BASE		(0xdeadbeef)
 #define BCM_6358_DSL_BASE		(0xfffe3000)
@@ -319,6 +390,8 @@ enum bcm63xx_regs_set {
 #define BCM_6358_PCMDMA_BASE		(0xfffe1800)
 #define BCM_6358_PCMDMAC_BASE		(0xfffe1900)
 #define BCM_6358_PCMDMAS_BASE		(0xfffe1a00)
+#define BCM_6358_RNG_BASE		(0xdeadbeef)
+#define BCM_6358_MISC_BASE		(0xdeadbeef)
 
 
 /*
@@ -331,14 +404,14 @@ enum bcm63xx_regs_set {
 #define BCM_6368_UART0_BASE		(0xb0000100)
 #define BCM_6368_UART1_BASE		(0xb0000120)
 #define BCM_6368_GPIO_BASE		(0xb0000080)
-#define BCM_6368_SPI_BASE		(0xdeadbeef)
-#define BCM_6368_SPI2_BASE		(0xb0000800)
+#define BCM_6368_SPI_BASE		(0xb0000800)
 #define BCM_6368_UDC0_BASE		(0xdeadbeef)
 #define BCM_6368_OHCI0_BASE		(0xb0001600)
 #define BCM_6368_OHCI_PRIV_BASE		(0xdeadbeef)
 #define BCM_6368_USBH_PRIV_BASE		(0xb0001700)
 #define BCM_6368_MPI_BASE		(0xb0001000)
 #define BCM_6368_PCMCIA_BASE		(0xb0001054)
+#define BCM_6368_PCIE_BASE		(0xdeadbeef)
 #define BCM_6368_SDRAM_REGS_BASE	(0xdeadbeef)
 #define BCM_6368_M2M_BASE		(0xdeadbeef)
 #define BCM_6368_DSL_BASE		(0xdeadbeef)
@@ -361,6 +434,8 @@ enum bcm63xx_regs_set {
 #define BCM_6368_PCMDMA_BASE		(0xb0005800)
 #define BCM_6368_PCMDMAC_BASE		(0xb0005a00)
 #define BCM_6368_PCMDMAS_BASE		(0xb0005c00)
+#define BCM_6368_RNG_BASE		(0xb0004180)
+#define BCM_6368_MISC_BASE		(0xdeadbeef)
 
 
 extern const unsigned long *bcm63xx_regs_base;
@@ -379,13 +454,13 @@ extern const unsigned long *bcm63xx_regs_base;
 	__GEN_RSET_BASE(__cpu, UART1)					\
 	__GEN_RSET_BASE(__cpu, GPIO)					\
 	__GEN_RSET_BASE(__cpu, SPI)					\
-	__GEN_RSET_BASE(__cpu, SPI2)					\
 	__GEN_RSET_BASE(__cpu, UDC0)					\
 	__GEN_RSET_BASE(__cpu, OHCI0)					\
 	__GEN_RSET_BASE(__cpu, OHCI_PRIV)				\
 	__GEN_RSET_BASE(__cpu, USBH_PRIV)				\
 	__GEN_RSET_BASE(__cpu, MPI)					\
 	__GEN_RSET_BASE(__cpu, PCMCIA)					\
+	__GEN_RSET_BASE(__cpu, PCIE)					\
 	__GEN_RSET_BASE(__cpu, DSL)					\
 	__GEN_RSET_BASE(__cpu, ENET0)					\
 	__GEN_RSET_BASE(__cpu, ENET1)					\
@@ -407,6 +482,8 @@ extern const unsigned long *bcm63xx_regs_base;
 	__GEN_RSET_BASE(__cpu, PCMDMA)					\
 	__GEN_RSET_BASE(__cpu, PCMDMAC)					\
 	__GEN_RSET_BASE(__cpu, PCMDMAS)					\
+	__GEN_RSET_BASE(__cpu, RNG)					\
+	__GEN_RSET_BASE(__cpu, MISC)					\
 	}
 
 #define __GEN_CPU_REGS_TABLE(__cpu)					\
@@ -418,13 +495,13 @@ extern const unsigned long *bcm63xx_regs_base;
 	[RSET_UART1]		= BCM_## __cpu ##_UART1_BASE,		\
 	[RSET_GPIO]		= BCM_## __cpu ##_GPIO_BASE,		\
 	[RSET_SPI]		= BCM_## __cpu ##_SPI_BASE,		\
-	[RSET_SPI2]		= BCM_## __cpu ##_SPI2_BASE,		\
 	[RSET_UDC0]		= BCM_## __cpu ##_UDC0_BASE,		\
 	[RSET_OHCI0]		= BCM_## __cpu ##_OHCI0_BASE,		\
 	[RSET_OHCI_PRIV]	= BCM_## __cpu ##_OHCI_PRIV_BASE,	\
 	[RSET_USBH_PRIV]	= BCM_## __cpu ##_USBH_PRIV_BASE,	\
 	[RSET_MPI]		= BCM_## __cpu ##_MPI_BASE,		\
 	[RSET_PCMCIA]		= BCM_## __cpu ##_PCMCIA_BASE,		\
+	[RSET_PCIE]		= BCM_## __cpu ##_PCIE_BASE,		\
 	[RSET_DSL]		= BCM_## __cpu ##_DSL_BASE,		\
 	[RSET_ENET0]		= BCM_## __cpu ##_ENET0_BASE,		\
 	[RSET_ENET1]		= BCM_## __cpu ##_ENET1_BASE,		\
@@ -446,6 +523,8 @@ extern const unsigned long *bcm63xx_regs_base;
 	[RSET_PCMDMA]		= BCM_## __cpu ##_PCMDMA_BASE,		\
 	[RSET_PCMDMAC]		= BCM_## __cpu ##_PCMDMAC_BASE,		\
 	[RSET_PCMDMAS]		= BCM_## __cpu ##_PCMDMAS_BASE,		\
+	[RSET_RNG]		= BCM_## __cpu ##_RNG_BASE,		\
+	[RSET_MISC]		= BCM_## __cpu ##_MISC_BASE,		\
 
 
 static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set)
@@ -453,6 +532,9 @@ static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set)
 #ifdef BCMCPU_RUNTIME_DETECT
 	return bcm63xx_regs_base[set];
 #else
+#ifdef CONFIG_BCM63XX_CPU_6328
+	__GEN_RSET(6328)
+#endif
 #ifdef CONFIG_BCM63XX_CPU_6338
 	__GEN_RSET(6338)
 #endif
@@ -478,6 +560,7 @@ static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set)
  */
 enum bcm63xx_irq {
 	IRQ_TIMER = 0,
+	IRQ_SPI,
 	IRQ_UART0,
 	IRQ_UART1,
 	IRQ_DSL,
@@ -506,9 +589,51 @@ enum bcm63xx_irq {
 };
 
 /*
+ * 6328 irqs
+ */
+#define BCM_6328_HIGH_IRQ_BASE		(IRQ_INTERNAL_BASE + 32)
+
+#define BCM_6328_TIMER_IRQ		(IRQ_INTERNAL_BASE + 31)
+#define BCM_6328_SPI_IRQ		0
+#define BCM_6328_UART0_IRQ		(IRQ_INTERNAL_BASE + 28)
+#define BCM_6328_UART1_IRQ		(BCM_6328_HIGH_IRQ_BASE + 7)
+#define BCM_6328_DSL_IRQ		(IRQ_INTERNAL_BASE + 4)
+#define BCM_6328_UDC0_IRQ		0
+#define BCM_6328_ENET0_IRQ		0
+#define BCM_6328_ENET1_IRQ		0
+#define BCM_6328_ENET_PHY_IRQ		(IRQ_INTERNAL_BASE + 12)
+#define BCM_6328_OHCI0_IRQ		(IRQ_INTERNAL_BASE + 9)
+#define BCM_6328_EHCI0_IRQ		(IRQ_INTERNAL_BASE + 10)
+#define BCM_6328_PCMCIA_IRQ		0
+#define BCM_6328_ENET0_RXDMA_IRQ	0
+#define BCM_6328_ENET0_TXDMA_IRQ	0
+#define BCM_6328_ENET1_RXDMA_IRQ	0
+#define BCM_6328_ENET1_TXDMA_IRQ	0
+#define BCM_6328_PCI_IRQ		(IRQ_INTERNAL_BASE + 23)
+#define BCM_6328_ATM_IRQ		0
+#define BCM_6328_ENETSW_RXDMA0_IRQ	(BCM_6328_HIGH_IRQ_BASE + 0)
+#define BCM_6328_ENETSW_RXDMA1_IRQ	(BCM_6328_HIGH_IRQ_BASE + 1)
+#define BCM_6328_ENETSW_RXDMA2_IRQ	(BCM_6328_HIGH_IRQ_BASE + 2)
+#define BCM_6328_ENETSW_RXDMA3_IRQ	(BCM_6328_HIGH_IRQ_BASE + 3)
+#define BCM_6328_ENETSW_TXDMA0_IRQ	(BCM_6328_HIGH_IRQ_BASE + 4)
+#define BCM_6328_ENETSW_TXDMA1_IRQ	(BCM_6328_HIGH_IRQ_BASE + 5)
+#define BCM_6328_ENETSW_TXDMA2_IRQ	(BCM_6328_HIGH_IRQ_BASE + 6)
+#define BCM_6328_ENETSW_TXDMA3_IRQ	(BCM_6328_HIGH_IRQ_BASE + 7)
+#define BCM_6328_XTM_IRQ		(BCM_6328_HIGH_IRQ_BASE + 31)
+#define BCM_6328_XTM_DMA0_IRQ		(BCM_6328_HIGH_IRQ_BASE + 11)
+
+#define BCM_6328_PCM_DMA0_IRQ		(IRQ_INTERNAL_BASE + 2)
+#define BCM_6328_PCM_DMA1_IRQ		(IRQ_INTERNAL_BASE + 3)
+#define BCM_6328_EXT_IRQ0		(IRQ_INTERNAL_BASE + 24)
+#define BCM_6328_EXT_IRQ1		(IRQ_INTERNAL_BASE + 25)
+#define BCM_6328_EXT_IRQ2		(IRQ_INTERNAL_BASE + 26)
+#define BCM_6328_EXT_IRQ3		(IRQ_INTERNAL_BASE + 27)
+
+/*
  * 6338 irqs
  */
 #define BCM_6338_TIMER_IRQ		(IRQ_INTERNAL_BASE + 0)
+#define BCM_6338_SPI_IRQ		(IRQ_INTERNAL_BASE + 1)
 #define BCM_6338_UART0_IRQ		(IRQ_INTERNAL_BASE + 2)
 #define BCM_6338_UART1_IRQ		0
 #define BCM_6338_DSL_IRQ		(IRQ_INTERNAL_BASE + 5)
@@ -539,6 +664,7 @@ enum bcm63xx_irq {
  * 6345 irqs
  */
 #define BCM_6345_TIMER_IRQ		(IRQ_INTERNAL_BASE + 0)
+#define BCM_6345_SPI_IRQ		0
 #define BCM_6345_UART0_IRQ		(IRQ_INTERNAL_BASE + 2)
 #define BCM_6345_UART1_IRQ		0
 #define BCM_6345_DSL_IRQ		(IRQ_INTERNAL_BASE + 3)
@@ -569,6 +695,7 @@ enum bcm63xx_irq {
  * 6348 irqs
  */
 #define BCM_6348_TIMER_IRQ		(IRQ_INTERNAL_BASE + 0)
+#define BCM_6348_SPI_IRQ		(IRQ_INTERNAL_BASE + 1)
 #define BCM_6348_UART0_IRQ		(IRQ_INTERNAL_BASE + 2)
 #define BCM_6348_UART1_IRQ		0
 #define BCM_6348_DSL_IRQ		(IRQ_INTERNAL_BASE + 4)
@@ -599,6 +726,7 @@ enum bcm63xx_irq {
  * 6358 irqs
  */
 #define BCM_6358_TIMER_IRQ		(IRQ_INTERNAL_BASE + 0)
+#define BCM_6358_SPI_IRQ		(IRQ_INTERNAL_BASE + 1)
 #define BCM_6358_UART0_IRQ		(IRQ_INTERNAL_BASE + 2)
 #define BCM_6358_UART1_IRQ		(IRQ_INTERNAL_BASE + 3)
 #define BCM_6358_DSL_IRQ		(IRQ_INTERNAL_BASE + 29)
@@ -638,6 +766,7 @@ enum bcm63xx_irq {
 #define BCM_6368_HIGH_IRQ_BASE		(IRQ_INTERNAL_BASE + 32)
 
 #define BCM_6368_TIMER_IRQ		(IRQ_INTERNAL_BASE + 0)
+#define BCM_6368_SPI_IRQ		(IRQ_INTERNAL_BASE + 1)
 #define BCM_6368_UART0_IRQ		(IRQ_INTERNAL_BASE + 2)
 #define BCM_6368_UART1_IRQ		(IRQ_INTERNAL_BASE + 3)
 #define BCM_6368_DSL_IRQ		(IRQ_INTERNAL_BASE + 4)
@@ -677,6 +806,7 @@ extern const int *bcm63xx_irqs;
 
 #define __GEN_CPU_IRQ_TABLE(__cpu)					\
 	[IRQ_TIMER]		= BCM_## __cpu ##_TIMER_IRQ,		\
+	[IRQ_SPI]		= BCM_## __cpu ##_SPI_IRQ,		\
 	[IRQ_UART0]		= BCM_## __cpu ##_UART0_IRQ,		\
 	[IRQ_UART1]		= BCM_## __cpu ##_UART1_IRQ,		\
 	[IRQ_DSL]		= BCM_## __cpu ##_DSL_IRQ,		\
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h
new file mode 100644
index 0000000..354b848
--- /dev/null
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h
@@ -0,0 +1,12 @@
+#ifndef __BCM63XX_FLASH_H
+#define __BCM63XX_FLASH_H
+
+enum {
+	BCM63XX_FLASH_TYPE_PARALLEL,
+	BCM63XX_FLASH_TYPE_SERIAL,
+	BCM63XX_FLASH_TYPE_NAND,
+};
+
+int __init bcm63xx_flash_register(void);
+
+#endif /* __BCM63XX_FLASH_H */
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
new file mode 100644
index 0000000..7d98dbe
--- /dev/null
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
@@ -0,0 +1,89 @@
+#ifndef BCM63XX_DEV_SPI_H
+#define BCM63XX_DEV_SPI_H
+
+#include <linux/types.h>
+#include <bcm63xx_io.h>
+#include <bcm63xx_regs.h>
+
+int __init bcm63xx_spi_register(void);
+
+struct bcm63xx_spi_pdata {
+	unsigned int	fifo_size;
+	int		bus_num;
+	int		num_chipselect;
+	u32		speed_hz;
+};
+
+enum bcm63xx_regs_spi {
+	SPI_CMD,
+	SPI_INT_STATUS,
+	SPI_INT_MASK_ST,
+	SPI_INT_MASK,
+	SPI_ST,
+	SPI_CLK_CFG,
+	SPI_FILL_BYTE,
+	SPI_MSG_TAIL,
+	SPI_RX_TAIL,
+	SPI_MSG_CTL,
+	SPI_MSG_DATA,
+	SPI_RX_DATA,
+};
+
+#define __GEN_SPI_RSET_BASE(__cpu, __rset)				\
+	case SPI_## __rset:						\
+		return SPI_## __cpu ##_## __rset;
+
+#define __GEN_SPI_RSET(__cpu)						\
+	switch (reg) {							\
+	__GEN_SPI_RSET_BASE(__cpu, CMD)					\
+	__GEN_SPI_RSET_BASE(__cpu, INT_STATUS)				\
+	__GEN_SPI_RSET_BASE(__cpu, INT_MASK_ST)				\
+	__GEN_SPI_RSET_BASE(__cpu, INT_MASK)				\
+	__GEN_SPI_RSET_BASE(__cpu, ST)					\
+	__GEN_SPI_RSET_BASE(__cpu, CLK_CFG)				\
+	__GEN_SPI_RSET_BASE(__cpu, FILL_BYTE)				\
+	__GEN_SPI_RSET_BASE(__cpu, MSG_TAIL)				\
+	__GEN_SPI_RSET_BASE(__cpu, RX_TAIL)				\
+	__GEN_SPI_RSET_BASE(__cpu, MSG_CTL)				\
+	__GEN_SPI_RSET_BASE(__cpu, MSG_DATA)				\
+	__GEN_SPI_RSET_BASE(__cpu, RX_DATA)				\
+	}
+
+#define __GEN_SPI_REGS_TABLE(__cpu)					\
+	[SPI_CMD]		= SPI_## __cpu ##_CMD,			\
+	[SPI_INT_STATUS]	= SPI_## __cpu ##_INT_STATUS,		\
+	[SPI_INT_MASK_ST]	= SPI_## __cpu ##_INT_MASK_ST,		\
+	[SPI_INT_MASK]		= SPI_## __cpu ##_INT_MASK,		\
+	[SPI_ST]		= SPI_## __cpu ##_ST,			\
+	[SPI_CLK_CFG]		= SPI_## __cpu ##_CLK_CFG,		\
+	[SPI_FILL_BYTE]		= SPI_## __cpu ##_FILL_BYTE,		\
+	[SPI_MSG_TAIL]		= SPI_## __cpu ##_MSG_TAIL,		\
+	[SPI_RX_TAIL]		= SPI_## __cpu ##_RX_TAIL,		\
+	[SPI_MSG_CTL]		= SPI_## __cpu ##_MSG_CTL,		\
+	[SPI_MSG_DATA]		= SPI_## __cpu ##_MSG_DATA,		\
+	[SPI_RX_DATA]		= SPI_## __cpu ##_RX_DATA,
+
+static inline unsigned long bcm63xx_spireg(enum bcm63xx_regs_spi reg)
+{
+#ifdef BCMCPU_RUNTIME_DETECT
+	extern const unsigned long *bcm63xx_regs_spi;
+
+	return bcm63xx_regs_spi[reg];
+#else
+#ifdef CONFIG_BCM63XX_CPU_6338
+	__GEN_SPI_RSET(6338)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6348
+	__GEN_SPI_RSET(6348)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6358
+	__GEN_SPI_RSET(6358)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6368
+	__GEN_SPI_RSET(6368)
+#endif
+#endif
+	return 0;
+}
+
+#endif /* BCM63XX_DEV_SPI_H */
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h
index 1d7dd96..0a9891f 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h
@@ -9,6 +9,8 @@ int __init bcm63xx_gpio_init(void);
 static inline unsigned long bcm63xx_gpio_count(void)
 {
 	switch (bcm63xx_get_cpu_id()) {
+	case BCM6328_CPU_ID:
+		return 32;
 	case BCM6358_CPU_ID:
 		return 40;
 	case BCM6338_CPU_ID:
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
index 72477a6..9203d90 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
@@ -40,6 +40,10 @@
 #define BCM_CB_MEM_END_PA		(BCM_CB_MEM_BASE_PA +		\
 					BCM_CB_MEM_SIZE - 1)
 
+#define BCM_PCIE_MEM_BASE_PA		0x10f00000
+#define BCM_PCIE_MEM_SIZE		(16 * 1024 * 1024)
+#define BCM_PCIE_MEM_END_PA		(BCM_PCIE_MEM_BASE_PA +		\
+					BCM_PCIE_MEM_SIZE - 1)
 
 /*
  * Internal registers are accessed through KSEG3
@@ -85,11 +89,15 @@
 #define bcm_mpi_writel(v, o)	bcm_rset_writel(RSET_MPI, (v), (o))
 #define bcm_pcmcia_readl(o)	bcm_rset_readl(RSET_PCMCIA, (o))
 #define bcm_pcmcia_writel(v, o)	bcm_rset_writel(RSET_PCMCIA, (v), (o))
+#define bcm_pcie_readl(o)	bcm_rset_readl(RSET_PCIE, (o))
+#define bcm_pcie_writel(v, o)	bcm_rset_writel(RSET_PCIE, (v), (o))
 #define bcm_sdram_readl(o)	bcm_rset_readl(RSET_SDRAM, (o))
 #define bcm_sdram_writel(v, o)	bcm_rset_writel(RSET_SDRAM, (v), (o))
 #define bcm_memc_readl(o)	bcm_rset_readl(RSET_MEMC, (o))
 #define bcm_memc_writel(v, o)	bcm_rset_writel(RSET_MEMC, (v), (o))
 #define bcm_ddr_readl(o)	bcm_rset_readl(RSET_DDR, (o))
 #define bcm_ddr_writel(v, o)	bcm_rset_writel(RSET_DDR, (v), (o))
+#define bcm_misc_readl(o)	bcm_rset_readl(RSET_MISC, (o))
+#define bcm_misc_writel(v, o)	bcm_rset_writel(RSET_MISC, (v), (o))
 
 #endif /* ! BCM63XX_IO_H_ */
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
index 94d4faa..4ccc2a7 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -15,6 +15,30 @@
 /* Clock Control register */
 #define PERF_CKCTL_REG			0x4
 
+#define CKCTL_6328_PHYMIPS_EN		(1 << 0)
+#define CKCTL_6328_ADSL_QPROC_EN	(1 << 1)
+#define CKCTL_6328_ADSL_AFE_EN		(1 << 2)
+#define CKCTL_6328_ADSL_EN		(1 << 3)
+#define CKCTL_6328_MIPS_EN		(1 << 4)
+#define CKCTL_6328_SAR_EN		(1 << 5)
+#define CKCTL_6328_PCM_EN		(1 << 6)
+#define CKCTL_6328_USBD_EN		(1 << 7)
+#define CKCTL_6328_USBH_EN		(1 << 8)
+#define CKCTL_6328_HSSPI_EN		(1 << 9)
+#define CKCTL_6328_PCIE_EN		(1 << 10)
+#define CKCTL_6328_ROBOSW_EN		(1 << 11)
+
+#define CKCTL_6328_ALL_SAFE_EN		(CKCTL_6328_PHYMIPS_EN |	\
+					CKCTL_6328_ADSL_QPROC_EN |	\
+					CKCTL_6328_ADSL_AFE_EN |	\
+					CKCTL_6328_ADSL_EN |		\
+					CKCTL_6328_SAR_EN  |		\
+					CKCTL_6328_PCM_EN  |		\
+					CKCTL_6328_USBD_EN |		\
+					CKCTL_6328_USBH_EN |		\
+					CKCTL_6328_ROBOSW_EN |		\
+					CKCTL_6328_PCIE_EN)
+
 #define CKCTL_6338_ADSLPHY_EN		(1 << 0)
 #define CKCTL_6338_MPI_EN		(1 << 1)
 #define CKCTL_6338_DRAM_EN		(1 << 2)
@@ -90,35 +114,36 @@
 #define CKCTL_6368_PHYMIPS_EN		(1 << 6)
 #define CKCTL_6368_SWPKT_USB_EN		(1 << 7)
 #define CKCTL_6368_SWPKT_SAR_EN		(1 << 8)
-#define CKCTL_6368_SPI_CLK_EN		(1 << 9)
-#define CKCTL_6368_USBD_CLK_EN		(1 << 10)
-#define CKCTL_6368_SAR_CLK_EN		(1 << 11)
-#define CKCTL_6368_ROBOSW_CLK_EN	(1 << 12)
-#define CKCTL_6368_UTOPIA_CLK_EN	(1 << 13)
-#define CKCTL_6368_PCM_CLK_EN		(1 << 14)
-#define CKCTL_6368_USBH_CLK_EN		(1 << 15)
+#define CKCTL_6368_SPI_EN		(1 << 9)
+#define CKCTL_6368_USBD_EN		(1 << 10)
+#define CKCTL_6368_SAR_EN		(1 << 11)
+#define CKCTL_6368_ROBOSW_EN		(1 << 12)
+#define CKCTL_6368_UTOPIA_EN		(1 << 13)
+#define CKCTL_6368_PCM_EN		(1 << 14)
+#define CKCTL_6368_USBH_EN		(1 << 15)
 #define CKCTL_6368_DISABLE_GLESS_EN	(1 << 16)
-#define CKCTL_6368_NAND_CLK_EN		(1 << 17)
-#define CKCTL_6368_IPSEC_CLK_EN		(1 << 17)
+#define CKCTL_6368_NAND_EN		(1 << 17)
+#define CKCTL_6368_IPSEC_EN		(1 << 18)
 
 #define CKCTL_6368_ALL_SAFE_EN		(CKCTL_6368_SWPKT_USB_EN |	\
 					CKCTL_6368_SWPKT_SAR_EN |	\
-					CKCTL_6368_SPI_CLK_EN |		\
-					CKCTL_6368_USBD_CLK_EN |	\
-					CKCTL_6368_SAR_CLK_EN |		\
-					CKCTL_6368_ROBOSW_CLK_EN |	\
-					CKCTL_6368_UTOPIA_CLK_EN |	\
-					CKCTL_6368_PCM_CLK_EN |		\
-					CKCTL_6368_USBH_CLK_EN |	\
+					CKCTL_6368_SPI_EN |		\
+					CKCTL_6368_USBD_EN |		\
+					CKCTL_6368_SAR_EN |		\
+					CKCTL_6368_ROBOSW_EN |		\
+					CKCTL_6368_UTOPIA_EN |		\
+					CKCTL_6368_PCM_EN |		\
+					CKCTL_6368_USBH_EN |		\
 					CKCTL_6368_DISABLE_GLESS_EN |	\
-					CKCTL_6368_NAND_CLK_EN |	\
-					CKCTL_6368_IPSEC_CLK_EN)
+					CKCTL_6368_NAND_EN |		\
+					CKCTL_6368_IPSEC_EN)
 
 /* System PLL Control register  */
 #define PERF_SYS_PLL_CTL_REG		0x8
 #define SYS_PLL_SOFT_RESET		0x1
 
 /* Interrupt Mask register */
+#define PERF_IRQMASK_6328_REG		0x20
 #define PERF_IRQMASK_6338_REG		0xc
 #define PERF_IRQMASK_6345_REG		0xc
 #define PERF_IRQMASK_6348_REG		0xc
@@ -126,6 +151,7 @@
 #define PERF_IRQMASK_6368_REG		0x20
 
 /* Interrupt Status register */
+#define PERF_IRQSTAT_6328_REG		0x28
 #define PERF_IRQSTAT_6338_REG		0x10
 #define PERF_IRQSTAT_6345_REG		0x10
 #define PERF_IRQSTAT_6348_REG		0x10
@@ -133,6 +159,7 @@
 #define PERF_IRQSTAT_6368_REG		0x28
 
 /* External Interrupt Configuration register */
+#define PERF_EXTIRQ_CFG_REG_6328	0x18
 #define PERF_EXTIRQ_CFG_REG_6338	0x14
 #define PERF_EXTIRQ_CFG_REG_6348	0x14
 #define PERF_EXTIRQ_CFG_REG_6358	0x14
@@ -162,8 +189,21 @@
 
 /* Soft Reset register */
 #define PERF_SOFTRESET_REG		0x28
+#define PERF_SOFTRESET_6328_REG		0x10
 #define PERF_SOFTRESET_6368_REG		0x10
 
+#define SOFTRESET_6328_SPI_MASK		(1 << 0)
+#define SOFTRESET_6328_EPHY_MASK	(1 << 1)
+#define SOFTRESET_6328_SAR_MASK		(1 << 2)
+#define SOFTRESET_6328_ENETSW_MASK	(1 << 3)
+#define SOFTRESET_6328_USBS_MASK	(1 << 4)
+#define SOFTRESET_6328_USBH_MASK	(1 << 5)
+#define SOFTRESET_6328_PCM_MASK		(1 << 6)
+#define SOFTRESET_6328_PCIE_CORE_MASK	(1 << 7)
+#define SOFTRESET_6328_PCIE_MASK	(1 << 8)
+#define SOFTRESET_6328_PCIE_EXT_MASK	(1 << 9)
+#define SOFTRESET_6328_PCIE_HARD_MASK	(1 << 10)
+
 #define SOFTRESET_6338_SPI_MASK		(1 << 0)
 #define SOFTRESET_6338_ENET_MASK	(1 << 2)
 #define SOFTRESET_6338_USBH_MASK	(1 << 3)
@@ -307,6 +347,8 @@
 /* Watchdog reset length register */
 #define WDT_RSTLEN_REG			0x8
 
+/* Watchdog soft reset register (BCM6328 only) */
+#define WDT_SOFTRESET_REG		0xc
 
 /*************************************************************************
  * _REG relative to RSET_UARTx
@@ -507,6 +549,15 @@
 #define GPIO_BASEMODE_6368_MASK		0x7
 /* those bits must be kept as read in gpio basemode register*/
 
+#define GPIO_STRAPBUS_REG		0x40
+#define STRAPBUS_6358_BOOT_SEL_PARALLEL	(1 << 1)
+#define STRAPBUS_6358_BOOT_SEL_SERIAL	(0 << 1)
+#define STRAPBUS_6368_BOOT_SEL_MASK	0x3
+#define STRAPBUS_6368_BOOT_SEL_NAND	0
+#define STRAPBUS_6368_BOOT_SEL_SERIAL	1
+#define STRAPBUS_6368_BOOT_SEL_PARALLEL	3
+
+
 /*************************************************************************
  * _REG relative to RSET_ENET
  *************************************************************************/
@@ -924,6 +975,8 @@
  * _REG relative to RSET_DDR
  *************************************************************************/
 
+#define DDR_CSEND_REG			0x8
+
 #define DDR_DMIPSPLLCFG_REG		0x18
 #define DMIPSPLLCFG_M1_SHIFT		0
 #define DMIPSPLLCFG_M1_MASK		(0xff << DMIPSPLLCFG_M1_SHIFT)
@@ -973,4 +1026,201 @@
 #define M2M_SRCID_REG(x)		((x) * 0x40 + 0x14)
 #define M2M_DSTID_REG(x)		((x) * 0x40 + 0x18)
 
+/*************************************************************************
+ * _REG relative to RSET_RNG
+ *************************************************************************/
+
+#define RNG_CTRL			0x00
+#define RNG_EN				(1 << 0)
+
+#define RNG_STAT			0x04
+#define RNG_AVAIL_MASK			(0xff000000)
+
+#define RNG_DATA			0x08
+#define RNG_THRES			0x0c
+#define RNG_MASK			0x10
+
+/*************************************************************************
+ * _REG relative to RSET_SPI
+ *************************************************************************/
+
+/* BCM 6338 SPI core */
+#define SPI_6338_CMD			0x00	/* 16-bits register */
+#define SPI_6338_INT_STATUS		0x02
+#define SPI_6338_INT_MASK_ST		0x03
+#define SPI_6338_INT_MASK		0x04
+#define SPI_6338_ST			0x05
+#define SPI_6338_CLK_CFG		0x06
+#define SPI_6338_FILL_BYTE		0x07
+#define SPI_6338_MSG_TAIL		0x09
+#define SPI_6338_RX_TAIL		0x0b
+#define SPI_6338_MSG_CTL		0x40
+#define SPI_6338_MSG_DATA		0x41
+#define SPI_6338_MSG_DATA_SIZE		0x3f
+#define SPI_6338_RX_DATA		0x80
+#define SPI_6338_RX_DATA_SIZE		0x3f
+
+/* BCM 6348 SPI core */
+#define SPI_6348_CMD			0x00	/* 16-bits register */
+#define SPI_6348_INT_STATUS		0x02
+#define SPI_6348_INT_MASK_ST		0x03
+#define SPI_6348_INT_MASK		0x04
+#define SPI_6348_ST			0x05
+#define SPI_6348_CLK_CFG		0x06
+#define SPI_6348_FILL_BYTE		0x07
+#define SPI_6348_MSG_TAIL		0x09
+#define SPI_6348_RX_TAIL		0x0b
+#define SPI_6348_MSG_CTL		0x40
+#define SPI_6348_MSG_DATA		0x41
+#define SPI_6348_MSG_DATA_SIZE		0x3f
+#define SPI_6348_RX_DATA		0x80
+#define SPI_6348_RX_DATA_SIZE		0x3f
+
+/* BCM 6358 SPI core */
+#define SPI_6358_MSG_CTL		0x00	/* 16-bits register */
+#define SPI_6358_MSG_DATA		0x02
+#define SPI_6358_MSG_DATA_SIZE		0x21e
+#define SPI_6358_RX_DATA		0x400
+#define SPI_6358_RX_DATA_SIZE		0x220
+#define SPI_6358_CMD			0x700	/* 16-bits register */
+#define SPI_6358_INT_STATUS		0x702
+#define SPI_6358_INT_MASK_ST		0x703
+#define SPI_6358_INT_MASK		0x704
+#define SPI_6358_ST			0x705
+#define SPI_6358_CLK_CFG		0x706
+#define SPI_6358_FILL_BYTE		0x707
+#define SPI_6358_MSG_TAIL		0x709
+#define SPI_6358_RX_TAIL		0x70B
+
+/* BCM 6358 SPI core */
+#define SPI_6368_MSG_CTL		0x00	/* 16-bits register */
+#define SPI_6368_MSG_DATA		0x02
+#define SPI_6368_MSG_DATA_SIZE		0x21e
+#define SPI_6368_RX_DATA		0x400
+#define SPI_6368_RX_DATA_SIZE		0x220
+#define SPI_6368_CMD			0x700	/* 16-bits register */
+#define SPI_6368_INT_STATUS		0x702
+#define SPI_6368_INT_MASK_ST		0x703
+#define SPI_6368_INT_MASK		0x704
+#define SPI_6368_ST			0x705
+#define SPI_6368_CLK_CFG		0x706
+#define SPI_6368_FILL_BYTE		0x707
+#define SPI_6368_MSG_TAIL		0x709
+#define SPI_6368_RX_TAIL		0x70B
+
+/* Shared SPI definitions */
+
+/* Message configuration */
+#define SPI_FD_RW			0x00
+#define SPI_HD_W			0x01
+#define SPI_HD_R			0x02
+#define SPI_BYTE_CNT_SHIFT		0
+#define SPI_MSG_TYPE_SHIFT		14
+
+/* Command */
+#define SPI_CMD_NOOP			0x00
+#define SPI_CMD_SOFT_RESET		0x01
+#define SPI_CMD_HARD_RESET		0x02
+#define SPI_CMD_START_IMMEDIATE		0x03
+#define SPI_CMD_COMMAND_SHIFT		0
+#define SPI_CMD_COMMAND_MASK		0x000f
+#define SPI_CMD_DEVICE_ID_SHIFT		4
+#define SPI_CMD_PREPEND_BYTE_CNT_SHIFT	8
+#define SPI_CMD_ONE_BYTE_SHIFT		11
+#define SPI_CMD_ONE_WIRE_SHIFT		12
+#define SPI_DEV_ID_0			0
+#define SPI_DEV_ID_1			1
+#define SPI_DEV_ID_2			2
+#define SPI_DEV_ID_3			3
+
+/* Interrupt mask */
+#define SPI_INTR_CMD_DONE		0x01
+#define SPI_INTR_RX_OVERFLOW		0x02
+#define SPI_INTR_TX_UNDERFLOW		0x04
+#define SPI_INTR_TX_OVERFLOW		0x08
+#define SPI_INTR_RX_UNDERFLOW		0x10
+#define SPI_INTR_CLEAR_ALL		0x1f
+
+/* Status */
+#define SPI_RX_EMPTY			0x02
+#define SPI_CMD_BUSY			0x04
+#define SPI_SERIAL_BUSY			0x08
+
+/* Clock configuration */
+#define SPI_CLK_20MHZ			0x00
+#define SPI_CLK_0_391MHZ		0x01
+#define SPI_CLK_0_781MHZ		0x02 /* default */
+#define SPI_CLK_1_563MHZ		0x03
+#define SPI_CLK_3_125MHZ		0x04
+#define SPI_CLK_6_250MHZ		0x05
+#define SPI_CLK_12_50MHZ		0x06
+#define SPI_CLK_MASK			0x07
+#define SPI_SSOFFTIME_MASK		0x38
+#define SPI_SSOFFTIME_SHIFT		3
+#define SPI_BYTE_SWAP			0x80
+
+/*************************************************************************
+ * _REG relative to RSET_MISC
+ *************************************************************************/
+#define MISC_SERDES_CTRL_REG		0x0
+#define SERDES_PCIE_EN			(1 << 0)
+#define SERDES_PCIE_EXD_EN		(1 << 15)
+
+#define MISC_STRAPBUS_6328_REG		0x240
+#define STRAPBUS_6328_FCVO_SHIFT	7
+#define STRAPBUS_6328_FCVO_MASK		(0x1f << STRAPBUS_6328_FCVO_SHIFT)
+#define STRAPBUS_6328_BOOT_SEL_SERIAL	(1 << 28)
+#define STRAPBUS_6328_BOOT_SEL_NAND	(0 << 28)
+
+/*************************************************************************
+ * _REG relative to RSET_PCIE
+ *************************************************************************/
+
+#define PCIE_CONFIG2_REG		0x408
+#define CONFIG2_BAR1_SIZE_EN		1
+#define CONFIG2_BAR1_SIZE_MASK		0xf
+
+#define PCIE_IDVAL3_REG			0x43c
+#define IDVAL3_CLASS_CODE_MASK		0xffffff
+#define IDVAL3_SUBCLASS_SHIFT		8
+#define IDVAL3_CLASS_SHIFT		16
+
+#define PCIE_DLSTATUS_REG		0x1048
+#define DLSTATUS_PHYLINKUP		(1 << 13)
+
+#define PCIE_BRIDGE_OPT1_REG		0x2820
+#define OPT1_RD_BE_OPT_EN		(1 << 7)
+#define OPT1_RD_REPLY_BE_FIX_EN		(1 << 9)
+#define OPT1_PCIE_BRIDGE_HOLE_DET_EN	(1 << 11)
+#define OPT1_L1_INT_STATUS_MASK_POL	(1 << 12)
+
+#define PCIE_BRIDGE_OPT2_REG		0x2824
+#define OPT2_UBUS_UR_DECODE_DIS		(1 << 2)
+#define OPT2_TX_CREDIT_CHK_EN		(1 << 4)
+#define OPT2_CFG_TYPE1_BD_SEL		(1 << 7)
+#define OPT2_CFG_TYPE1_BUS_NO_SHIFT	16
+#define OPT2_CFG_TYPE1_BUS_NO_MASK	(0xff << OPT2_CFG_TYPE1_BUS_NO_SHIFT)
+
+#define PCIE_BRIDGE_BAR0_BASEMASK_REG	0x2828
+#define PCIE_BRIDGE_BAR1_BASEMASK_REG	0x2830
+#define BASEMASK_REMAP_EN		(1 << 0)
+#define BASEMASK_SWAP_EN		(1 << 1)
+#define BASEMASK_MASK_SHIFT		4
+#define BASEMASK_MASK_MASK		(0xfff << BASEMASK_MASK_SHIFT)
+#define BASEMASK_BASE_SHIFT		20
+#define BASEMASK_BASE_MASK		(0xfff << BASEMASK_BASE_SHIFT)
+
+#define PCIE_BRIDGE_BAR0_REBASE_ADDR_REG 0x282c
+#define PCIE_BRIDGE_BAR1_REBASE_ADDR_REG 0x2834
+#define REBASE_ADDR_BASE_SHIFT		20
+#define REBASE_ADDR_BASE_MASK		(0xfff << REBASE_ADDR_BASE_SHIFT)
+
+#define PCIE_BRIDGE_RC_INT_MASK_REG	0x2854
+#define PCIE_RC_INT_A			(1 << 0)
+#define PCIE_RC_INT_B			(1 << 1)
+#define PCIE_RC_INT_C			(1 << 2)
+#define PCIE_RC_INT_D			(1 << 3)
+
+#define PCIE_DEVICE_OFFSET		0x8000
+
 #endif /* BCM63XX_REGS_H_ */
diff --git a/arch/mips/include/asm/mach-bcm63xx/ioremap.h b/arch/mips/include/asm/mach-bcm63xx/ioremap.h
index ef94ba7..30931c4 100644
--- a/arch/mips/include/asm/mach-bcm63xx/ioremap.h
+++ b/arch/mips/include/asm/mach-bcm63xx/ioremap.h
@@ -18,6 +18,7 @@ static inline int is_bcm63xx_internal_registers(phys_t offset)
 		if (offset >= 0xfff00000)
 			return 1;
 		break;
+	case BCM6328_CPU_ID:
 	case BCM6368_CPU_ID:
 		if (offset >= 0xb0000000 && offset < 0xb1000000)
 			return 1;
diff --git a/arch/mips/include/asm/mach-cavium-octeon/irq.h b/arch/mips/include/asm/mach-cavium-octeon/irq.h
index 5b05f18..4189920 100644
--- a/arch/mips/include/asm/mach-cavium-octeon/irq.h
+++ b/arch/mips/include/asm/mach-cavium-octeon/irq.h
@@ -41,61 +41,26 @@ enum octeon_irq {
 	OCTEON_IRQ_TWSI,
 	OCTEON_IRQ_TWSI2,
 	OCTEON_IRQ_RML,
-	OCTEON_IRQ_TRACE0,
-	OCTEON_IRQ_GMX_DRP0 = OCTEON_IRQ_TRACE0 + 4,
-	OCTEON_IRQ_IPD_DRP = OCTEON_IRQ_GMX_DRP0 + 5,
-	OCTEON_IRQ_KEY_ZERO,
 	OCTEON_IRQ_TIMER0,
 	OCTEON_IRQ_TIMER1,
 	OCTEON_IRQ_TIMER2,
 	OCTEON_IRQ_TIMER3,
 	OCTEON_IRQ_USB0,
 	OCTEON_IRQ_USB1,
-	OCTEON_IRQ_PCM,
-	OCTEON_IRQ_MPI,
-	OCTEON_IRQ_POWIQ,
-	OCTEON_IRQ_IPDPPTHR,
 	OCTEON_IRQ_MII0,
 	OCTEON_IRQ_MII1,
 	OCTEON_IRQ_BOOTDMA,
-
-	OCTEON_IRQ_NAND,
-	OCTEON_IRQ_MIO,		/* Summary of MIO_BOOT_ERR */
-	OCTEON_IRQ_IOB,		/* Summary of IOB_INT_SUM */
-	OCTEON_IRQ_FPA,		/* Summary of FPA_INT_SUM */
-	OCTEON_IRQ_POW,		/* Summary of POW_ECC_ERR */
-	OCTEON_IRQ_L2C,		/* Summary of L2C_INT_STAT */
-	OCTEON_IRQ_IPD,		/* Summary of IPD_INT_SUM */
-	OCTEON_IRQ_PIP,		/* Summary of PIP_INT_REG */
-	OCTEON_IRQ_PKO,		/* Summary of PKO_REG_ERROR */
-	OCTEON_IRQ_ZIP,		/* Summary of ZIP_ERROR */
-	OCTEON_IRQ_TIM,		/* Summary of TIM_REG_ERROR */
-	OCTEON_IRQ_RAD,		/* Summary of RAD_REG_ERROR */
-	OCTEON_IRQ_KEY,		/* Summary of KEY_INT_SUM */
-	OCTEON_IRQ_DFA,		/* Summary of DFA */
-	OCTEON_IRQ_USBCTL,	/* Summary of USBN0_INT_SUM */
-	OCTEON_IRQ_SLI,		/* Summary of SLI_INT_SUM */
-	OCTEON_IRQ_DPI,		/* Summary of DPI_INT_SUM */
-	OCTEON_IRQ_AGX0,	/* Summary of GMX0*+PCS0_INT*_REG */
-	OCTEON_IRQ_AGL  = OCTEON_IRQ_AGX0 + 5,
-	OCTEON_IRQ_PTP,
-	OCTEON_IRQ_PEM0,
-	OCTEON_IRQ_PEM1,
-	OCTEON_IRQ_SRIO0,
-	OCTEON_IRQ_SRIO1,
-	OCTEON_IRQ_LMC0,
-	OCTEON_IRQ_DFM = OCTEON_IRQ_LMC0 + 4,		/* Summary of DFM */
-	OCTEON_IRQ_RST,
+#ifndef CONFIG_PCI_MSI
+	OCTEON_IRQ_LAST = 127
+#endif
 };
 
 #ifdef CONFIG_PCI_MSI
-/* 152 - 407 represent the MSI interrupts 0-255 */
-#define OCTEON_IRQ_MSI_BIT0	(OCTEON_IRQ_RST + 1)
+/* 256 - 511 represent the MSI interrupts 0-255 */
+#define OCTEON_IRQ_MSI_BIT0	(256)
 
 #define OCTEON_IRQ_MSI_LAST      (OCTEON_IRQ_MSI_BIT0 + 255)
 #define OCTEON_IRQ_LAST          (OCTEON_IRQ_MSI_LAST + 1)
-#else
-#define OCTEON_IRQ_LAST         (OCTEON_IRQ_RST + 1)
 #endif
 
 #endif
diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
index bb5b9a4..986982d 100644
--- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
+++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
@@ -19,6 +19,8 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
+#define JZ_NAND_NUM_BANKS 4
+
 struct jz_nand_platform_data {
 	int			num_partitions;
 	struct mtd_partition	*partitions;
@@ -27,6 +29,8 @@ struct jz_nand_platform_data {
 
 	unsigned int busy_gpio;
 
+	unsigned char banks[JZ_NAND_NUM_BANKS];
+
 	void (*ident_callback)(struct platform_device *, struct nand_chip *,
 				struct mtd_partition **, int *num_partitions);
 };
diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
index 1e29b9d..06367c3 100644
--- a/arch/mips/include/asm/mach-loongson/loongson.h
+++ b/arch/mips/include/asm/mach-loongson/loongson.h
@@ -14,6 +14,7 @@
 #include <linux/io.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/kconfig.h>
 
 /* loongson internal northbridge initialization */
 extern void bonito_irq_init(void);
@@ -66,7 +67,7 @@ extern int mach_i8259_irq(void);
 #include <linux/interrupt.h>
 static inline void do_perfcnt_IRQ(void)
 {
-#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE)
+#if IS_ENABLED(CONFIG_OPROFILE)
 	do_IRQ(LOONGSON2_PERFCNT_IRQ);
 #endif
 }
diff --git a/arch/mips/include/asm/mach-loongson1/irq.h b/arch/mips/include/asm/mach-loongson1/irq.h
new file mode 100644
index 0000000..ccc42cc
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson1/irq.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * IRQ mappings for Loongson1.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+#ifndef __ASM_MACH_LOONGSON1_IRQ_H
+#define __ASM_MACH_LOONGSON1_IRQ_H
+
+/*
+ * CPU core Interrupt Numbers
+ */
+#define MIPS_CPU_IRQ_BASE		0
+#define MIPS_CPU_IRQ(x)			(MIPS_CPU_IRQ_BASE + (x))
+
+#define SOFTINT0_IRQ			MIPS_CPU_IRQ(0)
+#define SOFTINT1_IRQ			MIPS_CPU_IRQ(1)
+#define INT0_IRQ			MIPS_CPU_IRQ(2)
+#define INT1_IRQ			MIPS_CPU_IRQ(3)
+#define INT2_IRQ			MIPS_CPU_IRQ(4)
+#define INT3_IRQ			MIPS_CPU_IRQ(5)
+#define INT4_IRQ			MIPS_CPU_IRQ(6)
+#define TIMER_IRQ			MIPS_CPU_IRQ(7)		/* cpu timer */
+
+#define MIPS_CPU_IRQS		(MIPS_CPU_IRQ(7) + 1 - MIPS_CPU_IRQ_BASE)
+
+/*
+ * INT0~3 Interrupt Numbers
+ */
+#define LS1X_IRQ_BASE			MIPS_CPU_IRQS
+#define LS1X_IRQ(n, x)			(LS1X_IRQ_BASE + (n << 5) + (x))
+
+#define LS1X_UART0_IRQ			LS1X_IRQ(0, 2)
+#define LS1X_UART1_IRQ			LS1X_IRQ(0, 3)
+#define LS1X_UART2_IRQ			LS1X_IRQ(0, 4)
+#define LS1X_UART3_IRQ			LS1X_IRQ(0, 5)
+#define LS1X_CAN0_IRQ			LS1X_IRQ(0, 6)
+#define LS1X_CAN1_IRQ			LS1X_IRQ(0, 7)
+#define LS1X_SPI0_IRQ			LS1X_IRQ(0, 8)
+#define LS1X_SPI1_IRQ			LS1X_IRQ(0, 9)
+#define LS1X_AC97_IRQ			LS1X_IRQ(0, 10)
+#define LS1X_DMA0_IRQ			LS1X_IRQ(0, 13)
+#define LS1X_DMA1_IRQ			LS1X_IRQ(0, 14)
+#define LS1X_DMA2_IRQ			LS1X_IRQ(0, 15)
+#define LS1X_PWM0_IRQ			LS1X_IRQ(0, 17)
+#define LS1X_PWM1_IRQ			LS1X_IRQ(0, 18)
+#define LS1X_PWM2_IRQ			LS1X_IRQ(0, 19)
+#define LS1X_PWM3_IRQ			LS1X_IRQ(0, 20)
+#define LS1X_RTC_INT0_IRQ		LS1X_IRQ(0, 21)
+#define LS1X_RTC_INT1_IRQ		LS1X_IRQ(0, 22)
+#define LS1X_RTC_INT2_IRQ		LS1X_IRQ(0, 23)
+#define LS1X_TOY_INT0_IRQ		LS1X_IRQ(0, 24)
+#define LS1X_TOY_INT1_IRQ		LS1X_IRQ(0, 25)
+#define LS1X_TOY_INT2_IRQ		LS1X_IRQ(0, 26)
+#define LS1X_RTC_TICK_IRQ		LS1X_IRQ(0, 27)
+#define LS1X_TOY_TICK_IRQ		LS1X_IRQ(0, 28)
+
+#define LS1X_EHCI_IRQ			LS1X_IRQ(1, 0)
+#define LS1X_OHCI_IRQ			LS1X_IRQ(1, 1)
+#define LS1X_GMAC0_IRQ			LS1X_IRQ(1, 2)
+#define LS1X_GMAC1_IRQ			LS1X_IRQ(1, 3)
+
+#define LS1X_IRQS		(LS1X_IRQ(4, 31) + 1 - LS1X_IRQ_BASE)
+
+#define NR_IRQS			(MIPS_CPU_IRQS + LS1X_IRQS)
+
+#endif /* __ASM_MACH_LOONGSON1_IRQ_H */
diff --git a/arch/mips/include/asm/mach-loongson1/loongson1.h b/arch/mips/include/asm/mach-loongson1/loongson1.h
new file mode 100644
index 0000000..0440627
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson1/loongson1.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * Register mappings for Loongson1.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+#ifndef __ASM_MACH_LOONGSON1_LOONGSON1_H
+#define __ASM_MACH_LOONGSON1_LOONGSON1_H
+
+#define DEFAULT_MEMSIZE			256	/* If no memsize provided */
+
+/* Loongson1 Register Bases */
+#define LS1X_INTC_BASE			0x1fd01040
+#define LS1X_EHCI_BASE			0x1fe00000
+#define LS1X_OHCI_BASE			0x1fe08000
+#define LS1X_GMAC0_BASE			0x1fe10000
+#define LS1X_GMAC1_BASE			0x1fe20000
+
+#define LS1X_UART0_BASE			0x1fe40000
+#define LS1X_UART1_BASE			0x1fe44000
+#define LS1X_UART2_BASE			0x1fe48000
+#define LS1X_UART3_BASE			0x1fe4c000
+#define LS1X_CAN0_BASE			0x1fe50000
+#define LS1X_CAN1_BASE			0x1fe54000
+#define LS1X_I2C0_BASE			0x1fe58000
+#define LS1X_I2C1_BASE			0x1fe68000
+#define LS1X_I2C2_BASE			0x1fe70000
+#define LS1X_PWM_BASE			0x1fe5c000
+#define LS1X_WDT_BASE			0x1fe5c060
+#define LS1X_RTC_BASE			0x1fe64000
+#define LS1X_AC97_BASE			0x1fe74000
+#define LS1X_NAND_BASE			0x1fe78000
+#define LS1X_CLK_BASE			0x1fe78030
+
+#include <regs-clk.h>
+#include <regs-wdt.h>
+
+#endif /* __ASM_MACH_LOONGSON1_LOONGSON1_H */
diff --git a/arch/mips/include/asm/mach-loongson1/platform.h b/arch/mips/include/asm/mach-loongson1/platform.h
new file mode 100644
index 0000000..2f17161
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson1/platform.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+#ifndef __ASM_MACH_LOONGSON1_PLATFORM_H
+#define __ASM_MACH_LOONGSON1_PLATFORM_H
+
+#include <linux/platform_device.h>
+
+extern struct platform_device ls1x_uart_device;
+extern struct platform_device ls1x_eth0_device;
+extern struct platform_device ls1x_ehci_device;
+extern struct platform_device ls1x_rtc_device;
+
+void ls1x_serial_setup(void);
+
+#endif /* __ASM_MACH_LOONGSON1_PLATFORM_H */
diff --git a/arch/mips/include/asm/mach-loongson1/prom.h b/arch/mips/include/asm/mach-loongson1/prom.h
new file mode 100644
index 0000000..b871dc4
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson1/prom.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_MACH_LOONGSON1_PROM_H
+#define __ASM_MACH_LOONGSON1_PROM_H
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+/* environment arguments from bootloader */
+extern unsigned long memsize, highmemsize;
+
+/* loongson-specific command line, env and memory initialization */
+extern char *prom_getenv(char *name);
+extern void __init prom_init_cmdline(void);
+
+#endif /* __ASM_MACH_LOONGSON1_PROM_H */
diff --git a/arch/mips/include/asm/mach-loongson1/regs-clk.h b/arch/mips/include/asm/mach-loongson1/regs-clk.h
new file mode 100644
index 0000000..5b9635a
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson1/regs-clk.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * Loongson1 Clock Register Definitions.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_MACH_LOONGSON1_REGS_CLK_H
+#define __ASM_MACH_LOONGSON1_REGS_CLK_H
+
+#define LS1X_CLK_REG(x) \
+		((void __iomem *)KSEG1ADDR(LS1X_CLK_BASE + (x)))
+
+#define LS1X_CLK_PLL_FREQ		LS1X_CLK_REG(0x0)
+#define LS1X_CLK_PLL_DIV		LS1X_CLK_REG(0x4)
+
+/* Clock PLL Divisor Register Bits */
+#define DIV_DC_EN			(0x1 << 31)
+#define DIV_DC				(0x1f << 26)
+#define DIV_CPU_EN			(0x1 << 25)
+#define DIV_CPU				(0x1f << 20)
+#define DIV_DDR_EN			(0x1 << 19)
+#define DIV_DDR				(0x1f << 14)
+
+#define DIV_DC_SHIFT			26
+#define DIV_CPU_SHIFT			20
+#define DIV_DDR_SHIFT			14
+
+#endif /* __ASM_MACH_LOONGSON1_REGS_CLK_H */
diff --git a/arch/mips/include/asm/mach-loongson1/regs-wdt.h b/arch/mips/include/asm/mach-loongson1/regs-wdt.h
new file mode 100644
index 0000000..d339fe7
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson1/regs-wdt.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * Loongson1 Watchdog register definitions.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_MACH_LOONGSON1_REGS_WDT_H
+#define __ASM_MACH_LOONGSON1_REGS_WDT_H
+
+#define LS1X_WDT_REG(x) \
+		((void __iomem *)KSEG1ADDR(LS1X_WDT_BASE + (x)))
+
+#define LS1X_WDT_EN			LS1X_WDT_REG(0x0)
+#define LS1X_WDT_SET			LS1X_WDT_REG(0x4)
+#define LS1X_WDT_TIMER			LS1X_WDT_REG(0x8)
+
+#endif /* __ASM_MACH_LOONGSON1_REGS_WDT_H */
diff --git a/arch/mips/include/asm/mach-loongson1/war.h b/arch/mips/include/asm/mach-loongson1/war.h
new file mode 100644
index 0000000..e3680a8
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson1/war.h
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MACH_LOONGSON1_WAR_H
+#define __ASM_MACH_LOONGSON1_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR	0
+#define R4600_V1_HIT_CACHEOP_WAR	0
+#define R4600_V2_HIT_CACHEOP_WAR	0
+#define R5432_CP0_INTERRUPT_WAR		0
+#define BCM1250_M3_WAR			0
+#define SIBYTE_1956_WAR			0
+#define MIPS4K_ICACHE_REFILL_WAR	0
+#define MIPS_CACHE_SYNC_WAR		0
+#define TX49XX_ICACHE_INDEX_INV_WAR	0
+#define RM9000_CDEX_SMP_WAR		0
+#define ICACHE_REFILLS_WORKAROUND_WAR	0
+#define R10000_LLSC_WAR			0
+#define MIPS34K_MISSED_ITLB_WAR		0
+
+#endif /* __ASM_MACH_LOONGSON1_WAR_H */
diff --git a/arch/mips/include/asm/mach-tx49xx/mangle-port.h b/arch/mips/include/asm/mach-tx49xx/mangle-port.h
index 5e6912f..490867b 100644
--- a/arch/mips/include/asm/mach-tx49xx/mangle-port.h
+++ b/arch/mips/include/asm/mach-tx49xx/mangle-port.h
@@ -9,7 +9,7 @@
 #define ioswabb(a, x)		(x)
 #define __mem_ioswabb(a, x)	(x)
 #if defined(CONFIG_TOSHIBA_RBTX4939) && \
-	(defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)) && \
+	IS_ENABLED(CONFIG_SMC91X) && \
 	defined(__BIG_ENDIAN)
 #define NEEDS_TXX9_IOSWABW
 extern u16 (*ioswabw)(volatile u16 *a, u16 x);
diff --git a/arch/mips/include/asm/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h
index d11aa02..5447d9f 100644
--- a/arch/mips/include/asm/mips-boards/maltaint.h
+++ b/arch/mips/include/asm/mips-boards/maltaint.h
@@ -86,6 +86,16 @@
 #define GIC_CPU_INT4		4 /* .			*/
 #define GIC_CPU_INT5		5 /* Core Interrupt 5   */
 
+/* MALTA GIC local interrupts */
+#define GIC_INT_TMR             (GIC_CPU_INT5)
+#define GIC_INT_PERFCTR         (GIC_CPU_INT5)
+
+/* GIC constants */
+/* Add 2 to convert non-eic hw int # to eic vector # */
+#define GIC_CPU_TO_VEC_OFFSET   (2)
+/* If we map an intr to pin X, GIC will actually generate vector X+1 */
+#define GIC_PIN_TO_VEC_OFFSET   (1)
+
 #define GIC_EXT_INTR(x)		x
 
 /* External Interrupts used for IPI */
diff --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h
index c9420aa..5b3cb85 100644
--- a/arch/mips/include/asm/mipsmtregs.h
+++ b/arch/mips/include/asm/mipsmtregs.h
@@ -28,6 +28,9 @@
 #define read_c0_vpeconf0()		__read_32bit_c0_register($1, 2)
 #define write_c0_vpeconf0(val)		__write_32bit_c0_register($1, 2, val)
 
+#define read_c0_vpeconf1()		__read_32bit_c0_register($1, 3)
+#define write_c0_vpeconf1(val)		__write_32bit_c0_register($1, 3, val)
+
 #define read_c0_tcstatus()		__read_32bit_c0_register($2, 1)
 #define write_c0_tcstatus(val)		__write_32bit_c0_register($2, 1, val)
 
@@ -48,7 +51,7 @@
 #define CP0_VPECONF0		$1, 2
 #define CP0_VPECONF1		$1, 3
 #define CP0_YQMASK		$1, 4
-#define CP0_VPESCHEDULE	$1, 5
+#define CP0_VPESCHEDULE		$1, 5
 #define CP0_VPESCHEFBK		$1, 6
 #define CP0_TCSTATUS		$2, 1
 #define CP0_TCBIND		$2, 2
@@ -124,6 +127,14 @@
 #define VPECONF0_XTC_SHIFT	21
 #define VPECONF0_XTC		(_ULCAST_(0xff) << VPECONF0_XTC_SHIFT)
 
+/* VPEConf1 fields (per VPE) */
+#define VPECONF1_NCP1_SHIFT	0
+#define VPECONF1_NCP1		(_ULCAST_(0xff) << VPECONF1_NCP1_SHIFT)
+#define VPECONF1_NCP2_SHIFT	10
+#define VPECONF1_NCP2		(_ULCAST_(0xff) << VPECONF1_NCP2_SHIFT)
+#define VPECONF1_NCX_SHIFT	20
+#define VPECONF1_NCX		(_ULCAST_(0xff) << VPECONF1_NCX_SHIFT)
+
 /* TCStatus fields (per TC) */
 #define TCSTATUS_TASID		(_ULCAST_(0xff))
 #define TCSTATUS_IXMT_SHIFT	10
@@ -350,6 +361,8 @@ do {									\
 #define write_vpe_c0_vpecontrol(val)	mttc0(1, 1, val)
 #define read_vpe_c0_vpeconf0()		mftc0(1, 2)
 #define write_vpe_c0_vpeconf0(val)	mttc0(1, 2, val)
+#define read_vpe_c0_vpeconf1()		mftc0(1, 3)
+#define write_vpe_c0_vpeconf1(val)	mttc0(1, 3, val)
 #define read_vpe_c0_count()		mftc0(9, 0)
 #define write_vpe_c0_count(val)		mttc0(9, 0, val)
 #define read_vpe_c0_status()		mftc0(12, 0)
diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h
index 5300080..7531ecd 100644
--- a/arch/mips/include/asm/module.h
+++ b/arch/mips/include/asm/module.h
@@ -117,6 +117,8 @@ search_module_dbetables(unsigned long addr)
 #define MODULE_PROC_FAMILY "RM9000 "
 #elif defined CONFIG_CPU_SB1
 #define MODULE_PROC_FAMILY "SB1 "
+#elif defined CONFIG_CPU_LOONGSON1
+#define MODULE_PROC_FAMILY "LOONGSON1 "
 #elif defined CONFIG_CPU_LOONGSON2
 #define MODULE_PROC_FAMILY "LOONGSON2 "
 #elif defined CONFIG_CPU_CAVIUM_OCTEON
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h b/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h
index bf7d41d..7b63a6b 100644
--- a/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h
+++ b/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h
@@ -47,7 +47,9 @@
 #define CPU_BLOCKID_MAP		10
 
 #define LSU_DEFEATURE		0x304
-#define LSU_CERRLOG_REGID	0x09
+#define LSU_DEBUG_ADDR		0x305
+#define LSU_DEBUG_DATA0		0x306
+#define LSU_CERRLOG_REGID	0x309
 #define SCHED_DEFEATURE		0x700
 
 /* Offsets of interest from the 'MAP' Block */
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h
index 86cc339..2c63f97 100644
--- a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h
+++ b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h
@@ -36,6 +36,9 @@
 #define __NLM_HAL_IOMAP_H__
 
 #define XLP_DEFAULT_IO_BASE             0x18000000
+#define XLP_DEFAULT_PCI_ECFG_BASE	XLP_DEFAULT_IO_BASE
+#define XLP_DEFAULT_PCI_CFG_BASE	0x1c000000
+
 #define NMI_BASE			0xbfc00000
 #define	XLP_IO_CLK			133333333
 
@@ -129,7 +132,7 @@
 #define	PCI_DEVICE_ID_NLM_PIC		0x1003
 #define	PCI_DEVICE_ID_NLM_PCIE		0x1004
 #define	PCI_DEVICE_ID_NLM_EHCI		0x1007
-#define	PCI_DEVICE_ID_NLM_ILK		0x1008
+#define	PCI_DEVICE_ID_NLM_OHCI		0x1008
 #define	PCI_DEVICE_ID_NLM_NAE		0x1009
 #define	PCI_DEVICE_ID_NLM_POE		0x100A
 #define	PCI_DEVICE_ID_NLM_FMN		0x100B
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h b/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h
new file mode 100644
index 0000000..66c323d
--- /dev/null
+++ b/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * 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 Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __NLM_HAL_PCIBUS_H__
+#define	__NLM_HAL_PCIBUS_H__
+
+/* PCIE Memory and IO regions */
+#define	PCIE_MEM_BASE			0xd0000000ULL
+#define	PCIE_MEM_LIMIT			0xdfffffffULL
+#define	PCIE_IO_BASE			0x14000000ULL
+#define	PCIE_IO_LIMIT			0x15ffffffULL
+
+#define	PCIE_BRIDGE_CMD			0x1
+#define	PCIE_BRIDGE_MSI_CAP		0x14
+#define	PCIE_BRIDGE_MSI_ADDRL		0x15
+#define	PCIE_BRIDGE_MSI_ADDRH		0x16
+#define	PCIE_BRIDGE_MSI_DATA		0x17
+
+/* XLP Global PCIE configuration space registers */
+#define	PCIE_BYTE_SWAP_MEM_BASE		0x247
+#define	PCIE_BYTE_SWAP_MEM_LIM		0x248
+#define	PCIE_BYTE_SWAP_IO_BASE		0x249
+#define	PCIE_BYTE_SWAP_IO_LIM		0x24A
+#define	PCIE_MSI_STATUS			0x25A
+#define	PCIE_MSI_EN			0x25B
+#define	PCIE_INT_EN0			0x261
+
+/* PCIE_MSI_EN */
+#define	PCIE_MSI_VECTOR_INT_EN		0xFFFFFFFF
+
+/* PCIE_INT_EN0 */
+#define	PCIE_MSI_INT_EN			(1 << 9)
+
+#ifndef __ASSEMBLY__
+
+#define	nlm_read_pcie_reg(b, r)		nlm_read_reg(b, r)
+#define	nlm_write_pcie_reg(b, r, v)	nlm_write_reg(b, r, v)
+#define	nlm_get_pcie_base(node, inst)	\
+			nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst))
+#define	nlm_get_pcie_regbase(node, inst)	\
+			(nlm_get_pcie_base(node, inst) + XLP_IO_PCI_HDRSZ)
+
+int xlp_pcie_link_irt(int link);
+#endif
+#endif /* __NLM_HAL_PCIBUS_H__ */
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pic.h b/arch/mips/include/asm/netlogic/xlp-hal/pic.h
index b6628f7..ad8b802 100644
--- a/arch/mips/include/asm/netlogic/xlp-hal/pic.h
+++ b/arch/mips/include/asm/netlogic/xlp-hal/pic.h
@@ -201,7 +201,11 @@
 #define PIC_NUM_USB_IRTS		6
 #define PIC_IRT_USB_0_INDEX		115
 #define PIC_IRT_EHCI_0_INDEX		115
+#define PIC_IRT_OHCI_0_INDEX		116
+#define PIC_IRT_OHCI_1_INDEX		117
 #define PIC_IRT_EHCI_1_INDEX		118
+#define PIC_IRT_OHCI_2_INDEX		119
+#define PIC_IRT_OHCI_3_INDEX		120
 #define PIC_IRT_USB_INDEX(num)		((num) + PIC_IRT_USB_0_INDEX)
 /* 115 to 120 */
 #define PIC_IRT_GDX_INDEX		121
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/usb.h b/arch/mips/include/asm/netlogic/xlp-hal/usb.h
new file mode 100644
index 0000000..a9cd350
--- /dev/null
+++ b/arch/mips/include/asm/netlogic/xlp-hal/usb.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * 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 Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __NLM_HAL_USB_H__
+#define __NLM_HAL_USB_H__
+
+#define USB_CTL_0			0x01
+#define USB_PHY_0			0x0A
+#define USB_PHY_RESET			0x01
+#define USB_PHY_PORT_RESET_0		0x10
+#define USB_PHY_PORT_RESET_1		0x20
+#define USB_CONTROLLER_RESET		0x01
+#define USB_INT_STATUS			0x0E
+#define USB_INT_EN			0x0F
+#define USB_PHY_INTERRUPT_EN		0x01
+#define USB_OHCI_INTERRUPT_EN		0x02
+#define USB_OHCI_INTERRUPT1_EN		0x04
+#define USB_OHCI_INTERRUPT2_EN		0x08
+#define USB_CTRL_INTERRUPT_EN		0x10
+
+#ifndef __ASSEMBLY__
+
+#define nlm_read_usb_reg(b, r)			nlm_read_reg(b, r)
+#define nlm_write_usb_reg(b, r, v)		nlm_write_reg(b, r, v)
+#define nlm_get_usb_pcibase(node, inst)		\
+	nlm_pcicfg_base(XLP_IO_USB_OFFSET(node, inst))
+#define nlm_get_usb_hcd_base(node, inst)	\
+	nlm_xkphys_map_pcibar0(nlm_get_usb_pcibase(node, inst))
+#define nlm_get_usb_regbase(node, inst)		\
+	(nlm_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ)
+
+#endif
+#endif /* __NLM_HAL_USB_H__ */
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h
index 1540588..7e47209 100644
--- a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h
+++ b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h
@@ -35,8 +35,21 @@
 #ifndef _NLM_HAL_XLP_H
 #define _NLM_HAL_XLP_H
 
-#define PIC_UART_0_IRQ           17
-#define PIC_UART_1_IRQ           18
+#define PIC_UART_0_IRQ			17
+#define PIC_UART_1_IRQ			18
+#define PIC_PCIE_LINK_0_IRQ		19
+#define PIC_PCIE_LINK_1_IRQ		20
+#define PIC_PCIE_LINK_2_IRQ		21
+#define PIC_PCIE_LINK_3_IRQ		22
+#define PIC_EHCI_0_IRQ			23
+#define PIC_EHCI_1_IRQ			24
+#define PIC_OHCI_0_IRQ			25
+#define PIC_OHCI_1_IRQ			26
+#define PIC_OHCI_2_IRQ			27
+#define PIC_OHCI_3_IRQ			28
+#define PIC_MMC_IRQ			29
+#define PIC_I2C_0_IRQ			30
+#define PIC_I2C_1_IRQ			31
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/mips/include/asm/netlogic/xlr/bridge.h b/arch/mips/include/asm/netlogic/xlr/bridge.h
new file mode 100644
index 0000000..2d02428
--- /dev/null
+++ b/arch/mips/include/asm/netlogic/xlr/bridge.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * 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 Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _ASM_NLM_BRIDGE_H_
+#define _ASM_NLM_BRIDGE_H_
+
+#define BRIDGE_DRAM_0_BAR		0
+#define BRIDGE_DRAM_1_BAR		1
+#define BRIDGE_DRAM_2_BAR		2
+#define BRIDGE_DRAM_3_BAR		3
+#define BRIDGE_DRAM_4_BAR		4
+#define BRIDGE_DRAM_5_BAR		5
+#define BRIDGE_DRAM_6_BAR		6
+#define BRIDGE_DRAM_7_BAR		7
+#define BRIDGE_DRAM_CHN_0_MTR_0_BAR	8
+#define BRIDGE_DRAM_CHN_0_MTR_1_BAR	9
+#define BRIDGE_DRAM_CHN_0_MTR_2_BAR	10
+#define BRIDGE_DRAM_CHN_0_MTR_3_BAR	11
+#define BRIDGE_DRAM_CHN_0_MTR_4_BAR	12
+#define BRIDGE_DRAM_CHN_0_MTR_5_BAR	13
+#define BRIDGE_DRAM_CHN_0_MTR_6_BAR	14
+#define BRIDGE_DRAM_CHN_0_MTR_7_BAR	15
+#define BRIDGE_DRAM_CHN_1_MTR_0_BAR	16
+#define BRIDGE_DRAM_CHN_1_MTR_1_BAR	17
+#define BRIDGE_DRAM_CHN_1_MTR_2_BAR	18
+#define BRIDGE_DRAM_CHN_1_MTR_3_BAR	19
+#define BRIDGE_DRAM_CHN_1_MTR_4_BAR	20
+#define BRIDGE_DRAM_CHN_1_MTR_5_BAR	21
+#define BRIDGE_DRAM_CHN_1_MTR_6_BAR	22
+#define BRIDGE_DRAM_CHN_1_MTR_7_BAR	23
+#define BRIDGE_CFG_BAR			24
+#define BRIDGE_PHNX_IO_BAR		25
+#define BRIDGE_FLASH_BAR		26
+#define BRIDGE_SRAM_BAR			27
+#define BRIDGE_HTMEM_BAR		28
+#define BRIDGE_HTINT_BAR		29
+#define BRIDGE_HTPIC_BAR		30
+#define BRIDGE_HTSM_BAR			31
+#define BRIDGE_HTIO_BAR			32
+#define BRIDGE_HTCFG_BAR		33
+#define BRIDGE_PCIXCFG_BAR		34
+#define BRIDGE_PCIXMEM_BAR		35
+#define BRIDGE_PCIXIO_BAR		36
+#define BRIDGE_DEVICE_MASK		37
+#define BRIDGE_AERR_INTR_LOG1		38
+#define BRIDGE_AERR_INTR_LOG2		39
+#define BRIDGE_AERR_INTR_LOG3		40
+#define BRIDGE_AERR_DEV_STAT		41
+#define BRIDGE_AERR1_LOG1		42
+#define BRIDGE_AERR1_LOG2		43
+#define BRIDGE_AERR1_LOG3		44
+#define BRIDGE_AERR1_DEV_STAT		45
+#define BRIDGE_AERR_INTR_EN		46
+#define BRIDGE_AERR_UPG			47
+#define BRIDGE_AERR_CLEAR		48
+#define BRIDGE_AERR1_CLEAR		49
+#define BRIDGE_SBE_COUNTS		50
+#define BRIDGE_DBE_COUNTS		51
+#define BRIDGE_BITERR_INT_EN		52
+
+#define BRIDGE_SYS2IO_CREDITS		53
+#define BRIDGE_EVNT_CNT_CTRL1		54
+#define BRIDGE_EVNT_COUNTER1		55
+#define BRIDGE_EVNT_CNT_CTRL2		56
+#define BRIDGE_EVNT_COUNTER2		57
+#define BRIDGE_RESERVED1		58
+
+#define BRIDGE_DEFEATURE		59
+#define BRIDGE_SCRATCH0			60
+#define BRIDGE_SCRATCH1			61
+#define BRIDGE_SCRATCH2			62
+#define BRIDGE_SCRATCH3			63
+
+#endif
diff --git a/arch/mips/include/asm/netlogic/xlr/flash.h b/arch/mips/include/asm/netlogic/xlr/flash.h
new file mode 100644
index 0000000..f8aca54
--- /dev/null
+++ b/arch/mips/include/asm/netlogic/xlr/flash.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * 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 Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _ASM_NLM_FLASH_H_
+#define _ASM_NLM_FLASH_H_
+
+#define FLASH_CSBASE_ADDR(cs)		(cs)
+#define FLASH_CSADDR_MASK(cs)		(0x10 + (cs))
+#define FLASH_CSDEV_PARM(cs)		(0x20 + (cs))
+#define FLASH_CSTIME_PARMA(cs)		(0x30 + (cs))
+#define FLASH_CSTIME_PARMB(cs)		(0x40 + (cs))
+
+#define FLASH_INT_MASK			0x50
+#define FLASH_INT_STATUS		0x60
+#define FLASH_ERROR_STATUS		0x70
+#define FLASH_ERROR_ADDR		0x80
+
+#define FLASH_NAND_CLE(cs)		(0x90 + (cs))
+#define FLASH_NAND_ALE(cs)		(0xa0 + (cs))
+
+#define FLASH_NAND_CSDEV_PARAM		0x000041e6
+#define FLASH_NAND_CSTIME_PARAMA	0x4f400e22
+#define FLASH_NAND_CSTIME_PARAMB	0x000083cf
+
+#endif
diff --git a/arch/mips/include/asm/netlogic/xlr/gpio.h b/arch/mips/include/asm/netlogic/xlr/gpio.h
index 51f6ad4..8492e83 100644
--- a/arch/mips/include/asm/netlogic/xlr/gpio.h
+++ b/arch/mips/include/asm/netlogic/xlr/gpio.h
@@ -35,39 +35,40 @@
 #ifndef _ASM_NLM_GPIO_H
 #define _ASM_NLM_GPIO_H
 
-#define NETLOGIC_GPIO_INT_EN_REG		0
-#define NETLOGIC_GPIO_INPUT_INVERSION_REG	1
-#define NETLOGIC_GPIO_IO_DIR_REG		2
-#define NETLOGIC_GPIO_IO_DATA_WR_REG		3
-#define NETLOGIC_GPIO_IO_DATA_RD_REG		4
+#define GPIO_INT_EN_REG			0
+#define GPIO_INPUT_INVERSION_REG	1
+#define GPIO_IO_DIR_REG			2
+#define GPIO_IO_DATA_WR_REG		3
+#define GPIO_IO_DATA_RD_REG		4
 
-#define NETLOGIC_GPIO_SWRESET_REG		8
-#define NETLOGIC_GPIO_DRAM1_CNTRL_REG		9
-#define NETLOGIC_GPIO_DRAM1_RATIO_REG		10
-#define NETLOGIC_GPIO_DRAM1_RESET_REG		11
-#define NETLOGIC_GPIO_DRAM1_STATUS_REG		12
-#define NETLOGIC_GPIO_DRAM2_CNTRL_REG		13
-#define NETLOGIC_GPIO_DRAM2_RATIO_REG		14
-#define NETLOGIC_GPIO_DRAM2_RESET_REG		15
-#define NETLOGIC_GPIO_DRAM2_STATUS_REG		16
+#define GPIO_SWRESET_REG		8
+#define GPIO_DRAM1_CNTRL_REG		9
+#define GPIO_DRAM1_RATIO_REG		10
+#define GPIO_DRAM1_RESET_REG		11
+#define GPIO_DRAM1_STATUS_REG		12
+#define GPIO_DRAM2_CNTRL_REG		13
+#define GPIO_DRAM2_RATIO_REG		14
+#define GPIO_DRAM2_RESET_REG		15
+#define GPIO_DRAM2_STATUS_REG		16
 
-#define NETLOGIC_GPIO_PWRON_RESET_CFG_REG	21
-#define NETLOGIC_GPIO_BIST_ALL_GO_STATUS_REG	24
-#define NETLOGIC_GPIO_BIST_CPU_GO_STATUS_REG	25
-#define NETLOGIC_GPIO_BIST_DEV_GO_STATUS_REG	26
+#define GPIO_PWRON_RESET_CFG_REG	21
+#define GPIO_BIST_ALL_GO_STATUS_REG	24
+#define GPIO_BIST_CPU_GO_STATUS_REG	25
+#define GPIO_BIST_DEV_GO_STATUS_REG	26
 
-#define NETLOGIC_GPIO_FUSE_BANK_REG		35
-#define NETLOGIC_GPIO_CPU_RESET_REG		40
-#define NETLOGIC_GPIO_RNG_REG			43
+#define GPIO_FUSE_BANK_REG		35
+#define GPIO_CPU_RESET_REG		40
+#define GPIO_RNG_REG			43
 
-#define NETLOGIC_PWRON_RESET_PCMCIA_BOOT	17
-#define NETLOGIC_GPIO_LED_BITMAP	0x1700000
-#define NETLOGIC_GPIO_LED_0_SHIFT		20
-#define NETLOGIC_GPIO_LED_1_SHIFT		24
+#define PWRON_RESET_PCMCIA_BOOT		17
 
-#define NETLOGIC_GPIO_LED_OUTPUT_CODE_RESET	0x01
-#define NETLOGIC_GPIO_LED_OUTPUT_CODE_HARD_RESET 0x02
-#define NETLOGIC_GPIO_LED_OUTPUT_CODE_SOFT_RESET 0x03
-#define NETLOGIC_GPIO_LED_OUTPUT_CODE_MAIN	0x04
+#define GPIO_LED_BITMAP			0x1700000
+#define GPIO_LED_0_SHIFT		20
+#define GPIO_LED_1_SHIFT		24
+
+#define GPIO_LED_OUTPUT_CODE_RESET	0x01
+#define GPIO_LED_OUTPUT_CODE_HARD_RESET 0x02
+#define GPIO_LED_OUTPUT_CODE_SOFT_RESET 0x03
+#define GPIO_LED_OUTPUT_CODE_MAIN	0x04
 
 #endif
diff --git a/arch/mips/include/asm/octeon/cvmx-helper-fpa.h b/arch/mips/include/asm/octeon/cvmx-helper-fpa.h
deleted file mode 100644
index 5ff8c93..0000000
--- a/arch/mips/include/asm/octeon/cvmx-helper-fpa.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/***********************license start***************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2008 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
- ***********************license end**************************************/
-
-/**
- * @file
- *
- * Helper functions for FPA setup.
- *
- */
-#ifndef __CVMX_HELPER_H_FPA__
-#define __CVMX_HELPER_H_FPA__
-
-/**
- * Allocate memory and initialize the FPA pools using memory
- * from cvmx-bootmem. Sizes of each element in the pools is
- * controlled by the cvmx-config.h header file. Specifying
- * zero for any parameter will cause that FPA pool to not be
- * setup. This is useful if you aren't using some of the
- * hardware and want to save memory.
- *
- * @packet_buffers:
- *               Number of packet buffers to allocate
- * @work_queue_entries:
- *               Number of work queue entries
- * @pko_buffers:
- *               PKO Command buffers. You should at minimum have two per
- *               each PKO queue.
- * @tim_buffers:
- *               TIM ring buffer command queues. At least two per timer bucket
- *               is recommened.
- * @dfa_buffers:
- *               DFA command buffer. A relatively small (32 for example)
- *               number should work.
- * Returns Zero on success, non-zero if out of memory
- */
-extern int cvmx_helper_initialize_fpa(int packet_buffers,
-				      int work_queue_entries, int pko_buffers,
-				      int tim_buffers, int dfa_buffers);
-
-#endif /* __CVMX_HELPER_H__ */
diff --git a/arch/mips/include/asm/octeon/cvmx-helper.h b/arch/mips/include/asm/octeon/cvmx-helper.h
index 3169cd7..0ac6b9f 100644
--- a/arch/mips/include/asm/octeon/cvmx-helper.h
+++ b/arch/mips/include/asm/octeon/cvmx-helper.h
@@ -61,8 +61,6 @@ typedef union {
 	} s;
 } cvmx_helper_link_info_t;
 
-#include "cvmx-helper-fpa.h"
-
 #include <asm/octeon/cvmx-helper-errata.h>
 #include "cvmx-helper-loop.h"
 #include "cvmx-helper-npi.h"
diff --git a/arch/mips/include/asm/smtc.h b/arch/mips/include/asm/smtc.h
index c9736fc..8935426 100644
--- a/arch/mips/include/asm/smtc.h
+++ b/arch/mips/include/asm/smtc.h
@@ -33,6 +33,12 @@ typedef long asiduse;
 #endif
 #endif
 
+/*
+ * VPE Management information
+ */
+
+#define MAX_SMTC_VPES	MAX_SMTC_TLBS	/* FIXME: May not always be true. */
+
 extern asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS];
 
 struct mm_struct;
diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h
index 5d33621..4f8ddba8 100644
--- a/arch/mips/include/asm/switch_to.h
+++ b/arch/mips/include/asm/switch_to.h
@@ -22,7 +22,7 @@ struct task_struct;
  * switch_to(n) should switch tasks to task nr n, first
  * checking that n isn't the current task, in which case it does nothing.
  */
-extern asmlinkage void *resume(void *last, void *next, void *next_ti);
+extern asmlinkage void *resume(void *last, void *next, void *next_ti, u32 __usedfpu);
 
 extern unsigned int ll_bit;
 extern struct task_struct *ll_task;
@@ -66,11 +66,13 @@ do {									\
 
 #define switch_to(prev, next, last)					\
 do {									\
+	u32 __usedfpu;							\
 	__mips_mt_fpaff_switch_to(prev);				\
 	if (cpu_has_dsp)						\
 		__save_dsp(prev);					\
 	__clear_software_ll_bit();					\
-	(last) = resume(prev, next, task_thread_info(next));		\
+	__usedfpu = test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU);	\
+	(last) = resume(prev, next, task_thread_info(next), __usedfpu);	\
 } while (0)
 
 #define finish_arch_switch(prev)					\
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index e2eca7d..8debe9e 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -60,6 +60,8 @@ struct thread_info {
 register struct thread_info *__current_thread_info __asm__("$28");
 #define current_thread_info()  __current_thread_info
 
+#endif /* !__ASSEMBLY__ */
+
 /* thread information allocation */
 #if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_32BIT)
 #define THREAD_SIZE_ORDER (1)
@@ -85,8 +87,6 @@ register struct thread_info *__current_thread_info __asm__("$28");
 
 #define STACK_WARN	(THREAD_SIZE / 8)
 
-#endif /* !__ASSEMBLY__ */
-
 #define PREEMPT_ACTIVE		0x10000000
 
 /*
@@ -103,7 +103,6 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define TIF_NOTIFY_RESUME	5	/* callback before returning to user */
 #define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal() */
 #define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
-#define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 #define TIF_FIXADE		20	/* Fix address errors in software */
 #define TIF_LOGADE		21	/* Log address errors to syslog */
@@ -125,9 +124,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_FIXADE		(1<<TIF_FIXADE)
 #define _TIF_LOGADE		(1<<TIF_LOGADE)
 #define _TIF_32BIT_REGS		(1<<TIF_32BIT_REGS)
@@ -139,10 +136,10 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define _TIF_WORK_SYSCALL_EXIT	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
 
 /* work to do on interrupt/exception return */
-#define _TIF_WORK_MASK		(0x0000ffef &				\
-					~(_TIF_SECCOMP | _TIF_SYSCALL_AUDIT))
+#define _TIF_WORK_MASK		\
+	(_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME)
 /* work to do on any return to u-space */
-#define _TIF_ALLWORK_MASK	(0x8000ffff & ~_TIF_SECCOMP)
+#define _TIF_ALLWORK_MASK	(_TIF_WORK_MASK | _TIF_WORK_SYSCALL_EXIT)
 
 #endif /* __KERNEL__ */
 
diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index 653a412..3b92efe 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -687,7 +687,7 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n);
 	__MODULE_JAL(__copy_user)					\
 	: "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)	\
 	:								\
-	: "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",		\
+	: "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31",	\
 	  DADDI_SCRATCH, "memory");					\
 	__cu_len_r;							\
 })
@@ -797,7 +797,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
 	".set\treorder"							\
 	: "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)	\
 	:								\
-	: "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",		\
+	: "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31",	\
 	  DADDI_SCRATCH, "memory");					\
 	__cu_len_r;							\
 })
@@ -820,7 +820,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
 	".set\treorder"							\
 	: "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)	\
 	:								\
-	: "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",		\
+	: "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31",	\
 	  DADDI_SCRATCH, "memory");					\
 	__cu_len_r;							\
 })
diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h
index 440a21d..3d9f75f 100644
--- a/arch/mips/include/asm/uasm.h
+++ b/arch/mips/include/asm/uasm.h
@@ -6,6 +6,7 @@
  * Copyright (C) 2004, 2005, 2006, 2008  Thiemo Seufer
  * Copyright (C) 2005  Maciej W. Rozycki
  * Copyright (C) 2006  Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2012  MIPS Technologies, Inc.
  */
 
 #include <linux/types.h>
@@ -62,8 +63,10 @@ void __uasminit uasm_i##op(u32 **buf, unsigned int a, signed int b)
 
 Ip_u2u1s3(_addiu);
 Ip_u3u1u2(_addu);
-Ip_u2u1u3(_andi);
 Ip_u3u1u2(_and);
+Ip_u2u1u3(_andi);
+Ip_u1u2s3(_bbit0);
+Ip_u1u2s3(_bbit1);
 Ip_u1u2s3(_beq);
 Ip_u1u2s3(_beql);
 Ip_u1s2(_bgez);
@@ -72,55 +75,54 @@ Ip_u1s2(_bltz);
 Ip_u1s2(_bltzl);
 Ip_u1u2s3(_bne);
 Ip_u2s3u1(_cache);
-Ip_u1u2u3(_dmfc0);
-Ip_u1u2u3(_dmtc0);
 Ip_u2u1s3(_daddiu);
 Ip_u3u1u2(_daddu);
+Ip_u2u1msbu3(_dins);
+Ip_u2u1msbu3(_dinsm);
+Ip_u1u2u3(_dmfc0);
+Ip_u1u2u3(_dmtc0);
+Ip_u2u1u3(_drotr);
+Ip_u2u1u3(_drotr32);
 Ip_u2u1u3(_dsll);
 Ip_u2u1u3(_dsll32);
 Ip_u2u1u3(_dsra);
 Ip_u2u1u3(_dsrl);
 Ip_u2u1u3(_dsrl32);
-Ip_u2u1u3(_drotr);
-Ip_u2u1u3(_drotr32);
 Ip_u3u1u2(_dsubu);
 Ip_0(_eret);
 Ip_u1(_j);
 Ip_u1(_jal);
 Ip_u1(_jr);
 Ip_u2s3u1(_ld);
+Ip_u3u1u2(_ldx);
 Ip_u2s3u1(_ll);
 Ip_u2s3u1(_lld);
 Ip_u1s2(_lui);
 Ip_u2s3u1(_lw);
+Ip_u3u1u2(_lwx);
 Ip_u1u2u3(_mfc0);
 Ip_u1u2u3(_mtc0);
-Ip_u2u1u3(_ori);
 Ip_u3u1u2(_or);
+Ip_u2u1u3(_ori);
 Ip_u2s3u1(_pref);
 Ip_0(_rfe);
+Ip_u2u1u3(_rotr);
 Ip_u2s3u1(_sc);
 Ip_u2s3u1(_scd);
 Ip_u2s3u1(_sd);
 Ip_u2u1u3(_sll);
 Ip_u2u1u3(_sra);
 Ip_u2u1u3(_srl);
-Ip_u2u1u3(_rotr);
 Ip_u3u1u2(_subu);
 Ip_u2s3u1(_sw);
+Ip_u1(_syscall);
 Ip_0(_tlbp);
 Ip_0(_tlbr);
 Ip_0(_tlbwi);
 Ip_0(_tlbwr);
 Ip_u3u1u2(_xor);
 Ip_u2u1u3(_xori);
-Ip_u2u1msbu3(_dins);
-Ip_u2u1msbu3(_dinsm);
-Ip_u1(_syscall);
-Ip_u1u2s3(_bbit0);
-Ip_u1u2s3(_bbit1);
-Ip_u3u1u2(_lwx);
-Ip_u3u1u2(_ldx);
+
 
 /* Handle labels. */
 struct uasm_label {
@@ -145,37 +147,37 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
 
 /* convenience macros for instructions */
 #ifdef CONFIG_64BIT
+# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_daddiu(buf, rs, rt, val)
+# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_daddu(buf, rs, rt, rd)
+# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off)
 # define UASM_i_LW(buf, rs, rt, off) uasm_i_ld(buf, rs, rt, off)
-# define UASM_i_SW(buf, rs, rt, off) uasm_i_sd(buf, rs, rt, off)
+# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_ldx(buf, rs, rt, rd)
+# define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd)
+# define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd)
+# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_drotr(buf, rs, rt, sh)
+# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off)
 # define UASM_i_SLL(buf, rs, rt, sh) uasm_i_dsll(buf, rs, rt, sh)
 # define UASM_i_SRA(buf, rs, rt, sh) uasm_i_dsra(buf, rs, rt, sh)
 # define UASM_i_SRL(buf, rs, rt, sh) uasm_i_dsrl(buf, rs, rt, sh)
 # define UASM_i_SRL_SAFE(buf, rs, rt, sh) uasm_i_dsrl_safe(buf, rs, rt, sh)
-# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_drotr(buf, rs, rt, sh)
-# define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd)
-# define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd)
-# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_daddiu(buf, rs, rt, val)
-# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_daddu(buf, rs, rt, rd)
 # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd)
-# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off)
-# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off)
-# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_ldx(buf, rs, rt, rd)
+# define UASM_i_SW(buf, rs, rt, off) uasm_i_sd(buf, rs, rt, off)
 #else
+# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_addiu(buf, rs, rt, val)
+# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_addu(buf, rs, rt, rd)
+# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off)
 # define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off)
-# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off)
+# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_lwx(buf, rs, rt, rd)
+# define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd)
+# define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd)
+# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_rotr(buf, rs, rt, sh)
+# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off)
 # define UASM_i_SLL(buf, rs, rt, sh) uasm_i_sll(buf, rs, rt, sh)
 # define UASM_i_SRA(buf, rs, rt, sh) uasm_i_sra(buf, rs, rt, sh)
 # define UASM_i_SRL(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh)
 # define UASM_i_SRL_SAFE(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh)
-# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_rotr(buf, rs, rt, sh)
-# define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd)
-# define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd)
-# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_addiu(buf, rs, rt, val)
-# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_addu(buf, rs, rt, rd)
 # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd)
-# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off)
-# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off)
-# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_lwx(buf, rs, rt, rd)
+# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off)
 #endif
 
 #define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off)
@@ -183,19 +185,10 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
 #define uasm_i_beqzl(buf, rs, off) uasm_i_beql(buf, rs, 0, off)
 #define uasm_i_bnez(buf, rs, off) uasm_i_bne(buf, rs, 0, off)
 #define uasm_i_bnezl(buf, rs, off) uasm_i_bnel(buf, rs, 0, off)
+#define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3)
 #define uasm_i_move(buf, a, b) UASM_i_ADDU(buf, a, 0, b)
 #define uasm_i_nop(buf) uasm_i_sll(buf, 0, 0, 0)
 #define uasm_i_ssnop(buf) uasm_i_sll(buf, 0, 0, 1)
-#define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3)
-
-static inline void uasm_i_dsrl_safe(u32 **p, unsigned int a1,
-				    unsigned int a2, unsigned int a3)
-{
-	if (a3 < 32)
-		uasm_i_dsrl(p, a1, a2, a3);
-	else
-		uasm_i_dsrl32(p, a1, a2, a3 - 32);
-}
 
 static inline void uasm_i_drotr_safe(u32 **p, unsigned int a1,
 				     unsigned int a2, unsigned int a3)
@@ -215,6 +208,15 @@ static inline void uasm_i_dsll_safe(u32 **p, unsigned int a1,
 		uasm_i_dsll32(p, a1, a2, a3 - 32);
 }
 
+static inline void uasm_i_dsrl_safe(u32 **p, unsigned int a1,
+				    unsigned int a2, unsigned int a3)
+{
+	if (a3 < 32)
+		uasm_i_dsrl(p, a1, a2, a3);
+	else
+		uasm_i_dsrl32(p, a1, a2, a3 - 32);
+}
+
 /* Handle relocations. */
 struct uasm_reloc {
 	u32 *addr;
@@ -234,16 +236,16 @@ void uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab,
 int uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr);
 
 /* Convenience functions for labeled branches. */
-void uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
 void uasm_il_b(u32 **p, struct uasm_reloc **r, int lid);
+void uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg,
+		   unsigned int bit, int lid);
+void uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg,
+		   unsigned int bit, int lid);
 void uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
 void uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
 void uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1,
 		 unsigned int reg2, int lid);
 void uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
-void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
-void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
-void uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg,
-		   unsigned int bit, int lid);
-void uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg,
-		   unsigned int bit, int lid);
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 9a91fe9..9a3d9de 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -140,6 +140,7 @@ static void qi_lb60_nand_ident(struct platform_device *pdev,
 static struct jz_nand_platform_data qi_lb60_nand_pdata = {
 	.ident_callback = qi_lb60_nand_ident,
 	.busy_gpio = 94,
+	.banks = { 1 },
 };
 
 /* Keyboard*/
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
index 10929e2..e342ed4 100644
--- a/arch/mips/jz4740/platform.c
+++ b/arch/mips/jz4740/platform.c
@@ -157,11 +157,29 @@ static struct resource jz4740_nand_resources[] = {
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name	= "bank",
+		.name	= "bank1",
 		.start	= 0x18000000,
 		.end	= 0x180C0000 - 1,
 		.flags = IORESOURCE_MEM,
 	},
+	{
+		.name	= "bank2",
+		.start	= 0x14000000,
+		.end	= 0x140C0000 - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name	= "bank3",
+		.start	= 0x0C000000,
+		.end	= 0x0C0C0000 - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name	= "bank4",
+		.start	= 0x08000000,
+		.end	= 0x080C0000 - 1,
+		.flags = IORESOURCE_MEM,
+	},
 };
 
 struct platform_device jz4740_nand_device = {
diff --git a/arch/mips/jz4740/reset.c b/arch/mips/jz4740/reset.c
index 5f1fb95..6c0da5a 100644
--- a/arch/mips/jz4740/reset.c
+++ b/arch/mips/jz4740/reset.c
@@ -21,6 +21,9 @@
 #include <asm/mach-jz4740/base.h>
 #include <asm/mach-jz4740/timer.h>
 
+#include "reset.h"
+#include "clock.h"
+
 static void jz4740_halt(void)
 {
 	while (1) {
@@ -53,21 +56,57 @@ static void jz4740_restart(char *command)
 	jz4740_halt();
 }
 
-#define JZ_REG_RTC_CTRL		0x00
-#define JZ_REG_RTC_HIBERNATE	0x20
+#define JZ_REG_RTC_CTRL			0x00
+#define JZ_REG_RTC_HIBERNATE		0x20
+#define JZ_REG_RTC_WAKEUP_FILTER	0x24
+#define JZ_REG_RTC_RESET_COUNTER	0x28
 
-#define JZ_RTC_CTRL_WRDY	BIT(7)
+#define JZ_RTC_CTRL_WRDY		BIT(7)
+#define JZ_RTC_WAKEUP_FILTER_MASK	0x0000FFE0
+#define JZ_RTC_RESET_COUNTER_MASK	0x00000FE0
 
-static void jz4740_power_off(void)
+static inline void jz4740_rtc_wait_ready(void __iomem *rtc_base)
 {
-	void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x24);
 	uint32_t ctrl;
 
 	do {
 		ctrl = readl(rtc_base + JZ_REG_RTC_CTRL);
 	} while (!(ctrl & JZ_RTC_CTRL_WRDY));
+}
 
+static void jz4740_power_off(void)
+{
+	void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x38);
+	unsigned long wakeup_filter_ticks;
+	unsigned long reset_counter_ticks;
+
+	/*
+	 * Set minimum wakeup pin assertion time: 100 ms.
+	 * Range is 0 to 2 sec if RTC is clocked at 32 kHz.
+	 */
+	wakeup_filter_ticks = (100 * jz4740_clock_bdata.rtc_rate) / 1000;
+	if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK)
+		wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK;
+	else
+		wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK;
+	jz4740_rtc_wait_ready(rtc_base);
+	writel(wakeup_filter_ticks, rtc_base + JZ_REG_RTC_WAKEUP_FILTER);
+
+	/*
+	 * Set reset pin low-level assertion time after wakeup: 60 ms.
+	 * Range is 0 to 125 ms if RTC is clocked at 32 kHz.
+	 */
+	reset_counter_ticks = (60 * jz4740_clock_bdata.rtc_rate) / 1000;
+	if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK)
+		reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK;
+	else
+		reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK;
+	jz4740_rtc_wait_ready(rtc_base);
+	writel(reset_counter_ticks, rtc_base + JZ_REG_RTC_RESET_COUNTER);
+
+	jz4740_rtc_wait_ready(rtc_base);
 	writel(1, rtc_base + JZ_REG_RTC_HIBERNATE);
+
 	jz4740_halt();
 }
 
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 6ae7ce4..1b51046 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -4,7 +4,7 @@
  * Copyright (C) xxxx  the Anonymous
  * Copyright (C) 1994 - 2006 Ralf Baechle
  * Copyright (C) 2003, 2004  Maciej W. Rozycki
- * Copyright (C) 2001, 2004  MIPS Inc.
+ * Copyright (C) 2001, 2004, 2011, 2012  MIPS Technologies, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -190,6 +190,7 @@ void __init check_wait(void)
 	case CPU_CAVIUM_OCTEON_PLUS:
 	case CPU_CAVIUM_OCTEON2:
 	case CPU_JZRISC:
+	case CPU_LOONGSON1:
 	case CPU_XLR:
 	case CPU_XLP:
 		cpu_wait = r4k_wait;
@@ -199,6 +200,7 @@ void __init check_wait(void)
 		cpu_wait = rm7k_wait_irqoff;
 		break;
 
+	case CPU_M14KC:
 	case CPU_24K:
 	case CPU_34K:
 	case CPU_1004K:
@@ -329,6 +331,154 @@ static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
 #endif
 }
 
+static char unknown_isa[] __cpuinitdata = KERN_ERR \
+	"Unsupported ISA type, c0.config0: %d.";
+
+static inline unsigned int decode_config0(struct cpuinfo_mips *c)
+{
+	unsigned int config0;
+	int isa;
+
+	config0 = read_c0_config();
+
+	if (((config0 & MIPS_CONF_MT) >> 7) == 1)
+		c->options |= MIPS_CPU_TLB;
+	isa = (config0 & MIPS_CONF_AT) >> 13;
+	switch (isa) {
+	case 0:
+		switch ((config0 & MIPS_CONF_AR) >> 10) {
+		case 0:
+			c->isa_level = MIPS_CPU_ISA_M32R1;
+			break;
+		case 1:
+			c->isa_level = MIPS_CPU_ISA_M32R2;
+			break;
+		default:
+			goto unknown;
+		}
+		break;
+	case 2:
+		switch ((config0 & MIPS_CONF_AR) >> 10) {
+		case 0:
+			c->isa_level = MIPS_CPU_ISA_M64R1;
+			break;
+		case 1:
+			c->isa_level = MIPS_CPU_ISA_M64R2;
+			break;
+		default:
+			goto unknown;
+		}
+		break;
+	default:
+		goto unknown;
+	}
+
+	return config0 & MIPS_CONF_M;
+
+unknown:
+	panic(unknown_isa, config0);
+}
+
+static inline unsigned int decode_config1(struct cpuinfo_mips *c)
+{
+	unsigned int config1;
+
+	config1 = read_c0_config1();
+
+	if (config1 & MIPS_CONF1_MD)
+		c->ases |= MIPS_ASE_MDMX;
+	if (config1 & MIPS_CONF1_WR)
+		c->options |= MIPS_CPU_WATCH;
+	if (config1 & MIPS_CONF1_CA)
+		c->ases |= MIPS_ASE_MIPS16;
+	if (config1 & MIPS_CONF1_EP)
+		c->options |= MIPS_CPU_EJTAG;
+	if (config1 & MIPS_CONF1_FP) {
+		c->options |= MIPS_CPU_FPU;
+		c->options |= MIPS_CPU_32FPR;
+	}
+	if (cpu_has_tlb)
+		c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1;
+
+	return config1 & MIPS_CONF_M;
+}
+
+static inline unsigned int decode_config2(struct cpuinfo_mips *c)
+{
+	unsigned int config2;
+
+	config2 = read_c0_config2();
+
+	if (config2 & MIPS_CONF2_SL)
+		c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
+
+	return config2 & MIPS_CONF_M;
+}
+
+static inline unsigned int decode_config3(struct cpuinfo_mips *c)
+{
+	unsigned int config3;
+
+	config3 = read_c0_config3();
+
+	if (config3 & MIPS_CONF3_SM)
+		c->ases |= MIPS_ASE_SMARTMIPS;
+	if (config3 & MIPS_CONF3_DSP)
+		c->ases |= MIPS_ASE_DSP;
+	if (config3 & MIPS_CONF3_VINT)
+		c->options |= MIPS_CPU_VINT;
+	if (config3 & MIPS_CONF3_VEIC)
+		c->options |= MIPS_CPU_VEIC;
+	if (config3 & MIPS_CONF3_MT)
+		c->ases |= MIPS_ASE_MIPSMT;
+	if (config3 & MIPS_CONF3_ULRI)
+		c->options |= MIPS_CPU_ULRI;
+
+	return config3 & MIPS_CONF_M;
+}
+
+static inline unsigned int decode_config4(struct cpuinfo_mips *c)
+{
+	unsigned int config4;
+
+	config4 = read_c0_config4();
+
+	if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT
+	    && cpu_has_tlb)
+		c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
+
+	c->kscratch_mask = (config4 >> 16) & 0xff;
+
+	return config4 & MIPS_CONF_M;
+}
+
+static void __cpuinit decode_configs(struct cpuinfo_mips *c)
+{
+	int ok;
+
+	/* MIPS32 or MIPS64 compliant CPU.  */
+	c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER |
+		     MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK;
+
+	c->scache.flags = MIPS_CACHE_NOT_PRESENT;
+
+	ok = decode_config0(c);			/* Read Config registers.  */
+	BUG_ON(!ok);				/* Arch spec violation!  */
+	if (ok)
+		ok = decode_config1(c);
+	if (ok)
+		ok = decode_config2(c);
+	if (ok)
+		ok = decode_config3(c);
+	if (ok)
+		ok = decode_config4(c);
+
+	mips_probe_watch_registers(c);
+
+	if (cpu_has_mips_r2)
+		c->core = read_c0_ebase() & 0x3ff;
+}
+
 #define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \
 		| MIPS_CPU_COUNTER)
 
@@ -637,155 +787,19 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
 			     MIPS_CPU_32FPR;
 		c->tlbsize = 64;
 		break;
-	}
-}
-
-static char unknown_isa[] __cpuinitdata = KERN_ERR \
-	"Unsupported ISA type, c0.config0: %d.";
+	case PRID_IMP_LOONGSON1:
+		decode_configs(c);
 
-static inline unsigned int decode_config0(struct cpuinfo_mips *c)
-{
-	unsigned int config0;
-	int isa;
+		c->cputype = CPU_LOONGSON1;
 
-	config0 = read_c0_config();
-
-	if (((config0 & MIPS_CONF_MT) >> 7) == 1)
-		c->options |= MIPS_CPU_TLB;
-	isa = (config0 & MIPS_CONF_AT) >> 13;
-	switch (isa) {
-	case 0:
-		switch ((config0 & MIPS_CONF_AR) >> 10) {
-		case 0:
-			c->isa_level = MIPS_CPU_ISA_M32R1;
-			break;
-		case 1:
-			c->isa_level = MIPS_CPU_ISA_M32R2;
-			break;
-		default:
-			goto unknown;
-		}
-		break;
-	case 2:
-		switch ((config0 & MIPS_CONF_AR) >> 10) {
-		case 0:
-			c->isa_level = MIPS_CPU_ISA_M64R1;
-			break;
-		case 1:
-			c->isa_level = MIPS_CPU_ISA_M64R2;
+		switch (c->processor_id & PRID_REV_MASK) {
+		case PRID_REV_LOONGSON1B:
+			__cpu_name[cpu] = "Loongson 1B";
 			break;
-		default:
-			goto unknown;
 		}
-		break;
-	default:
-		goto unknown;
-	}
-
-	return config0 & MIPS_CONF_M;
-
-unknown:
-	panic(unknown_isa, config0);
-}
 
-static inline unsigned int decode_config1(struct cpuinfo_mips *c)
-{
-	unsigned int config1;
-
-	config1 = read_c0_config1();
-
-	if (config1 & MIPS_CONF1_MD)
-		c->ases |= MIPS_ASE_MDMX;
-	if (config1 & MIPS_CONF1_WR)
-		c->options |= MIPS_CPU_WATCH;
-	if (config1 & MIPS_CONF1_CA)
-		c->ases |= MIPS_ASE_MIPS16;
-	if (config1 & MIPS_CONF1_EP)
-		c->options |= MIPS_CPU_EJTAG;
-	if (config1 & MIPS_CONF1_FP) {
-		c->options |= MIPS_CPU_FPU;
-		c->options |= MIPS_CPU_32FPR;
+		break;
 	}
-	if (cpu_has_tlb)
-		c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1;
-
-	return config1 & MIPS_CONF_M;
-}
-
-static inline unsigned int decode_config2(struct cpuinfo_mips *c)
-{
-	unsigned int config2;
-
-	config2 = read_c0_config2();
-
-	if (config2 & MIPS_CONF2_SL)
-		c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
-
-	return config2 & MIPS_CONF_M;
-}
-
-static inline unsigned int decode_config3(struct cpuinfo_mips *c)
-{
-	unsigned int config3;
-
-	config3 = read_c0_config3();
-
-	if (config3 & MIPS_CONF3_SM)
-		c->ases |= MIPS_ASE_SMARTMIPS;
-	if (config3 & MIPS_CONF3_DSP)
-		c->ases |= MIPS_ASE_DSP;
-	if (config3 & MIPS_CONF3_VINT)
-		c->options |= MIPS_CPU_VINT;
-	if (config3 & MIPS_CONF3_VEIC)
-		c->options |= MIPS_CPU_VEIC;
-	if (config3 & MIPS_CONF3_MT)
-		c->ases |= MIPS_ASE_MIPSMT;
-	if (config3 & MIPS_CONF3_ULRI)
-		c->options |= MIPS_CPU_ULRI;
-
-	return config3 & MIPS_CONF_M;
-}
-
-static inline unsigned int decode_config4(struct cpuinfo_mips *c)
-{
-	unsigned int config4;
-
-	config4 = read_c0_config4();
-
-	if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT
-	    && cpu_has_tlb)
-		c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
-
-	c->kscratch_mask = (config4 >> 16) & 0xff;
-
-	return config4 & MIPS_CONF_M;
-}
-
-static void __cpuinit decode_configs(struct cpuinfo_mips *c)
-{
-	int ok;
-
-	/* MIPS32 or MIPS64 compliant CPU.  */
-	c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER |
-		     MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK;
-
-	c->scache.flags = MIPS_CACHE_NOT_PRESENT;
-
-	ok = decode_config0(c);			/* Read Config registers.  */
-	BUG_ON(!ok);				/* Arch spec violation!  */
-	if (ok)
-		ok = decode_config1(c);
-	if (ok)
-		ok = decode_config2(c);
-	if (ok)
-		ok = decode_config3(c);
-	if (ok)
-		ok = decode_config4(c);
-
-	mips_probe_watch_registers(c);
-
-	if (cpu_has_mips_r2)
-		c->core = read_c0_ebase() & 0x3ff;
 }
 
 static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
@@ -810,6 +824,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
 		c->cputype = CPU_5KC;
 		__cpu_name[cpu] = "MIPS 5Kc";
 		break;
+	case PRID_IMP_5KE:
+		c->cputype = CPU_5KE;
+		__cpu_name[cpu] = "MIPS 5KE";
+		break;
 	case PRID_IMP_20KC:
 		c->cputype = CPU_20KC;
 		__cpu_name[cpu] = "MIPS 20Kc";
@@ -831,6 +849,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
 		c->cputype = CPU_74K;
 		__cpu_name[cpu] = "MIPS 74Kc";
 		break;
+	case PRID_IMP_M14KC:
+		c->cputype = CPU_M14KC;
+		__cpu_name[cpu] = "MIPS M14Kc";
+		break;
 	case PRID_IMP_1004K:
 		c->cputype = CPU_1004K;
 		__cpu_name[cpu] = "MIPS 1004Kc";
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index 37acfa0..a6c1332 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -77,7 +77,7 @@ FEXPORT(syscall_exit)
 	and	t0, a2, t0
 	bnez	t0, syscall_exit_work
 
-FEXPORT(restore_all)			# restore full frame
+restore_all:				# restore full frame
 #ifdef CONFIG_MIPS_MT_SMTC
 #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
 /* Re-arm any temporarily masked interrupts not explicitly "acked" */
@@ -117,7 +117,7 @@ FEXPORT(restore_all)			# restore full frame
 	RESTORE_TEMP
 	RESTORE_AT
 	RESTORE_STATIC
-FEXPORT(restore_partial)		# restore partial frame
+restore_partial:		# restore partial frame
 #ifdef CONFIG_TRACE_IRQFLAGS
 	SAVE_STATIC
 	SAVE_AT
@@ -164,9 +164,18 @@ work_notifysig:				# deal with pending signals and
 	jal	do_notify_resume	# a2 already loaded
 	j	resume_userspace
 
-FEXPORT(syscall_exit_work_partial)
+FEXPORT(syscall_exit_partial)
+	local_irq_disable		# make sure need_resched doesn't
+					# change between and return
+	LONG_L	a2, TI_FLAGS($28)	# current->work
+	li	t0, _TIF_ALLWORK_MASK
+	and	t0, a2
+	beqz	t0, restore_partial
 	SAVE_STATIC
 syscall_exit_work:
+	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
+	andi	t0, t0, KU_USER
+	beqz	t0, resume_kernel
 	li	t0, _TIF_WORK_SYSCALL_EXIT
 	and	t0, a2			# a2 is preloaded with TI_FLAGS
 	beqz	t0, work_pending	# trace bit set?
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index 57ba13e..3fc1691 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996, 97, 98, 99, 2000, 01, 03, 04, 05 by Ralf Baechle
+ * Copyright (C) 1996, 97, 98, 99, 2000, 01, 03, 04, 05, 12 by Ralf Baechle
  * Copyright (C) 1999, 2000, 01 Silicon Graphics, Inc.
  */
 #include <linux/interrupt.h>
@@ -35,6 +35,12 @@ EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(kernel_thread);
 
 /*
+ * Functions that operate on entire pages.  Mostly used by memory management.
+ */
+EXPORT_SYMBOL(clear_page);
+EXPORT_SYMBOL(copy_page);
+
+/*
  * Userspace access stuff.
  */
 EXPORT_SYMBOL(__copy_user);
diff --git a/arch/mips/kernel/octeon_switch.S b/arch/mips/kernel/octeon_switch.S
index ce89c80..0441f54 100644
--- a/arch/mips/kernel/octeon_switch.S
+++ b/arch/mips/kernel/octeon_switch.S
@@ -31,7 +31,7 @@
 
 /*
  * task_struct *resume(task_struct *prev, task_struct *next,
- *                     struct thread_info *next_ti)
+ *                     struct thread_info *next_ti, int usedfpu)
  */
 	.align	7
 	LEAF(resume)
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c
index f29099b..2f28d3b 100644
--- a/arch/mips/kernel/perf_event_mipsxx.c
+++ b/arch/mips/kernel/perf_event_mipsxx.c
@@ -162,11 +162,6 @@ static unsigned int counters_total_to_per_cpu(unsigned int counters)
 	return counters >> vpe_shift();
 }
 
-static unsigned int counters_per_cpu_to_total(unsigned int counters)
-{
-	return counters << vpe_shift();
-}
-
 #else /* !CONFIG_MIPS_MT_SMP */
 #define vpe_id()	0
 
@@ -1564,6 +1559,11 @@ init_hw_perf_events(void)
 		mipspmu.general_event_map = &mipsxxcore_event_map;
 		mipspmu.cache_event_map = &mipsxxcore_cache_map;
 		break;
+	case CPU_LOONGSON1:
+		mipspmu.name = "mips/loongson1";
+		mipspmu.general_event_map = &mipsxxcore_event_map;
+		mipspmu.cache_event_map = &mipsxxcore_cache_map;
+		break;
 	case CPU_CAVIUM_OCTEON:
 	case CPU_CAVIUM_OCTEON_PLUS:
 	case CPU_CAVIUM_OCTEON2:
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
index 2938983..9c51be5 100644
--- a/arch/mips/kernel/r2300_switch.S
+++ b/arch/mips/kernel/r2300_switch.S
@@ -43,7 +43,7 @@
 
 /*
  * task_struct *resume(task_struct *prev, task_struct *next,
- *                     struct thread_info *next_ti) )
+ *                     struct thread_info *next_ti, int usedfpu)
  */
 LEAF(resume)
 	mfc0	t1, CP0_STATUS
@@ -51,18 +51,9 @@ LEAF(resume)
 	cpu_save_nonscratch a0
 	sw	ra, THREAD_REG31(a0)
 
-	/*
-	 * check if we need to save FPU registers
-	 */
-	lw	t3, TASK_THREAD_INFO(a0)
-	lw	t0, TI_FLAGS(t3)
-	li	t1, _TIF_USEDFPU
-	and	t2, t0, t1
-	beqz	t2, 1f
-	nor	t1, zero, t1
+	beqz	a3, 1f
 
-	and	t0, t0, t1
-	sw	t0, TI_FLAGS(t3)
+	PTR_L	t3, TASK_THREAD_INFO(a0)
 
 	/*
 	 * clear saved user stack CU1 bit
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 9414f93..42d2a39 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -41,7 +41,7 @@
 
 /*
  * task_struct *resume(task_struct *prev, task_struct *next,
- *                     struct thread_info *next_ti)
+ *                     struct thread_info *next_ti, int usedfpu)
  */
 	.align	5
 	LEAF(resume)
@@ -53,16 +53,10 @@
 	/*
 	 * check if we need to save FPU registers
 	 */
-	PTR_L	t3, TASK_THREAD_INFO(a0)
-	LONG_L	t0, TI_FLAGS(t3)
-	li	t1, _TIF_USEDFPU
-	and	t2, t0, t1
-	beqz	t2, 1f
-	nor	t1, zero, t1
 
-	and	t0, t0, t1
-	LONG_S	t0, TI_FLAGS(t3)
+	beqz    a3, 1f
 
+	PTR_L	t3, TASK_THREAD_INFO(a0)
 	/*
 	 * clear saved user stack CU1 bit
 	 */
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index a632bc1..dfd47dc 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -69,18 +69,7 @@ stack_done:
 1:	sw	v0, PT_R2(sp)		# result
 
 o32_syscall_exit:
-	local_irq_disable		# make sure need_resched and
-					# signals dont change between
-					# sampling and return
-	lw	a2, TI_FLAGS($28)	# current->work
-	li	t0, _TIF_ALLWORK_MASK
-	and	t0, a2
-	bnez	t0, o32_syscall_exit_work
-
-	j	restore_partial
-
-o32_syscall_exit_work:
-	j	syscall_exit_work_partial
+	j	syscall_exit_partial
 
 /* ------------------------------------------------------------------------ */
 
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index 3b5a5e9..b83dc8b 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -72,18 +72,7 @@ NESTED(handle_sys64, PT_SIZE, sp)
 1:	sd	v0, PT_R2(sp)		# result
 
 n64_syscall_exit:
-	local_irq_disable		# make sure need_resched and
-					# signals dont change between
-					# sampling and return
-	LONG_L	a2, TI_FLAGS($28)	# current->work
-	li	t0, _TIF_ALLWORK_MASK
-	and	t0, a2, t0
-	bnez	t0, n64_syscall_exit_work
-
-	j	restore_partial
-
-n64_syscall_exit_work:
-	j	syscall_exit_work_partial
+	j	syscall_exit_partial
 
 /* ------------------------------------------------------------------------ */
 
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 6be6f70..0cff8a3 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -70,18 +70,7 @@ NESTED(handle_sysn32, PT_SIZE, sp)
 	sd	t1, PT_R0(sp)		# save it for syscall restarting
 1:	sd	v0, PT_R2(sp)		# result
 
-	local_irq_disable		# make sure need_resched and
-					# signals dont change between
-					# sampling and return
-	LONG_L  a2, TI_FLAGS($28)	# current->work
-	li	t0, _TIF_ALLWORK_MASK
-	and	t0, a2, t0
-	bnez	t0, n32_syscall_exit_work
-
-	j	restore_partial
-
-n32_syscall_exit_work:
-	j	syscall_exit_work_partial
+	j	syscall_exit_partial
 
 /* ------------------------------------------------------------------------ */
 
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 5422855..9b040e4 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -99,18 +99,7 @@ NESTED(handle_sys, PT_SIZE, sp)
 1:	sd	v0, PT_R2(sp)		# result
 
 o32_syscall_exit:
-	local_irq_disable		# make need_resched and
-					# signals dont change between
-					# sampling and return
-	LONG_L	a2, TI_FLAGS($28)
-	li	t0, _TIF_ALLWORK_MASK
-	and	t0, a2, t0
-	bnez	t0, o32_syscall_exit_work
-
-	j	restore_partial
-
-o32_syscall_exit_work:
-	j	syscall_exit_work_partial
+	j	syscall_exit_partial
 
 /* ------------------------------------------------------------------------ */
 
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index f2c09cf..0e1a5b8 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -560,14 +560,6 @@ static void do_signal(struct pt_regs *regs)
 	siginfo_t info;
 	int signr;
 
-	/*
-	 * We want the common case to go fast, which is why we may in certain
-	 * cases get here from kernel mode. Just return without doing anything
-	 * if so.
-	 */
-	if (!user_mode(regs))
-		return;
-
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index 3046e29..8e393b8 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -15,7 +15,6 @@
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
-#include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
 #include <linux/reboot.h>
@@ -197,13 +196,6 @@ static void bmips_init_secondary(void)
 
 	write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0));
 #endif
-
-	/* make sure there won't be a timer interrupt for a little while */
-	write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
-
-	irq_enable_hazard();
-	set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ1 | IE_IRQ5 | ST0_IE);
-	irq_enable_hazard();
 }
 
 /*
@@ -212,6 +204,13 @@ static void bmips_init_secondary(void)
 static void bmips_smp_finish(void)
 {
 	pr_info("SMP: CPU%d is running\n", smp_processor_id());
+
+	/* make sure there won't be a timer interrupt for a little while */
+	write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
+
+	irq_enable_hazard();
+	set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ1 | IE_IRQ5 | ST0_IE);
+	irq_enable_hazard();
 }
 
 /*
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 48650c8..31637d8 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -102,7 +102,9 @@ asmlinkage __cpuinit void start_secondary(void)
 
 #ifdef CONFIG_MIPS_MT_SMTC
 	/* Only do cpu_probe for first TC of CPU */
-	if ((read_c0_tcbind() & TCBIND_CURTC) == 0)
+	if ((read_c0_tcbind() & TCBIND_CURTC) != 0)
+		__cpu_name[smp_processor_id()] = __cpu_name[0];
+	else
 #endif /* CONFIG_MIPS_MT_SMTC */
 	cpu_probe();
 	cpu_report();
@@ -122,13 +124,21 @@ asmlinkage __cpuinit void start_secondary(void)
 
 	notify_cpu_starting(cpu);
 
-	mp_ops->smp_finish();
+	set_cpu_online(cpu, true);
+
 	set_cpu_sibling_map(cpu);
 
 	cpu_set(cpu, cpu_callin_map);
 
 	synchronise_count_slave();
 
+	/*
+	 * irq will be enabled in ->smp_finish(), enabling it too early
+	 * is dangerous.
+	 */
+	WARN_ON_ONCE(!irqs_disabled());
+	mp_ops->smp_finish();
+
 	cpu_idle();
 }
 
@@ -196,8 +206,6 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
 	while (!cpu_isset(cpu, cpu_callin_map))
 		udelay(100);
 
-	set_cpu_online(cpu, true);
-
 	return 0;
 }
 
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index f5dd38f..1d47843 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -86,6 +86,13 @@ struct smtc_ipi_q IPIQ[NR_CPUS];
 static struct smtc_ipi_q freeIPIq;
 
 
+/*
+ * Number of FPU contexts for each VPE
+ */
+
+static int smtc_nconf1[MAX_SMTC_VPES];
+
+
 /* Forward declarations */
 
 void ipi_decode(struct smtc_ipi *);
@@ -174,9 +181,9 @@ static int __init tintq(char *str)
 
 __setup("tintq=", tintq);
 
-static int imstuckcount[2][8];
+static int imstuckcount[MAX_SMTC_VPES][8];
 /* vpemask represents IM/IE bits of per-VPE Status registers, low-to-high */
-static int vpemask[2][8] = {
+static int vpemask[MAX_SMTC_VPES][8] = {
 	{0, 0, 1, 0, 0, 0, 0, 1},
 	{0, 0, 0, 0, 0, 0, 0, 1}
 };
@@ -322,7 +329,7 @@ int __init smtc_build_cpu_map(int start_cpu_slot)
 
 /*
  * Common setup before any secondaries are started
- * Make sure all CPU's are in a sensible state before we boot any of the
+ * Make sure all CPUs are in a sensible state before we boot any of the
  * secondaries.
  *
  * For MIPS MT "SMTC" operation, we set up all TCs, spread as evenly
@@ -331,6 +338,22 @@ int __init smtc_build_cpu_map(int start_cpu_slot)
 
 static void smtc_tc_setup(int vpe, int tc, int cpu)
 {
+	static int cp1contexts[MAX_SMTC_VPES];
+
+	/*
+	 * Make a local copy of the available FPU contexts in order
+	 * to keep track of TCs that can have one.
+	 */
+	if (tc == 1)
+	{
+		/*
+		 * FIXME: Multi-core SMTC hasn't been tested and the
+		 *        maximum number of VPEs may change.
+		 */
+		cp1contexts[0] = smtc_nconf1[0] - 1;
+		cp1contexts[1] = smtc_nconf1[1];
+	}
+
 	settc(tc);
 	write_tc_c0_tchalt(TCHALT_H);
 	mips_ihb();
@@ -340,26 +363,33 @@ static void smtc_tc_setup(int vpe, int tc, int cpu)
 	/*
 	 * TCContext gets an offset from the base of the IPIQ array
 	 * to be used in low-level code to detect the presence of
-	 * an active IPI queue
+	 * an active IPI queue.
 	 */
 	write_tc_c0_tccontext((sizeof(struct smtc_ipi_q) * cpu) << 16);
-	/* Bind tc to vpe */
+
+	/* Bind TC to VPE. */
 	write_tc_c0_tcbind(vpe);
-	/* In general, all TCs should have the same cpu_data indications */
+
+	/* In general, all TCs should have the same cpu_data indications. */
 	memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips));
-	/* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */
-	if (cpu_data[0].cputype == CPU_34K ||
-	    cpu_data[0].cputype == CPU_1004K)
+
+	/* Check to see if there is a FPU context available for this TC. */
+	if (!cp1contexts[vpe])
 		cpu_data[cpu].options &= ~MIPS_CPU_FPU;
+	else
+		cp1contexts[vpe]--;
+
+	/* Store the TC and VPE into the cpu_data structure. */
 	cpu_data[cpu].vpe_id = vpe;
 	cpu_data[cpu].tc_id = tc;
-	/* Multi-core SMTC hasn't been tested, but be prepared */
+
+	/* FIXME: Multi-core SMTC hasn't been tested, but be prepared. */
 	cpu_data[cpu].core = (read_vpe_c0_ebase() >> 1) & 0xff;
 }
 
 /*
- * Tweak to get Count registes in as close a sync as possible.
- * Value seems good for 34K-class cores.
+ * Tweak to get Count registers synced as closely as possible. The
+ * value seems good for 34K-class cores.
  */
 
 #define CP0_SKEW 8
@@ -466,6 +496,24 @@ void smtc_prepare_cpus(int cpus)
 	smtc_configure_tlb();
 
 	for (tc = 0, vpe = 0 ; (vpe < nvpe) && (tc < ntc) ; vpe++) {
+		/* Get number of CP1 contexts for each VPE. */
+		if (tc == 0)
+		{
+			/*
+			 * Do not call settc() for TC0 or the FPU context
+			 * value will be incorrect. Besides, we know that
+			 * we are TC0 anyway.
+			 */
+			smtc_nconf1[0] = ((read_vpe_c0_vpeconf1() &
+				VPECONF1_NCP1) >> VPECONF1_NCP1_SHIFT);
+			if (nvpe == 2)
+			{
+				settc(1);
+				smtc_nconf1[1] = ((read_vpe_c0_vpeconf1() &
+					VPECONF1_NCP1) >> VPECONF1_NCP1_SHIFT);
+				settc(0);
+			}
+		}
 		if (tcpervpe[vpe] == 0)
 			continue;
 		if (vpe != 0)
@@ -479,6 +527,18 @@ void smtc_prepare_cpus(int cpus)
 			 */
 			if (tc != 0) {
 				smtc_tc_setup(vpe, tc, cpu);
+				if (vpe != 0) {
+					/*
+					 * Set MVP bit (possibly again).  Do it
+					 * here to catch CPUs that have no TCs
+					 * bound to the VPE at reset.  In that
+					 * case, a TC must be bound to the VPE
+					 * before we can set VPEControl[MVP]
+					 */
+					write_vpe_c0_vpeconf0(
+						read_vpe_c0_vpeconf0() |
+						VPECONF0_MVP);
+				}
 				cpu++;
 			}
 			printk(" %d", tc);
@@ -615,7 +675,6 @@ void __cpuinit smtc_boot_secondary(int cpu, struct task_struct *idle)
 
 void smtc_init_secondary(void)
 {
-	local_irq_enable();
 }
 
 void smtc_smp_finish(void)
@@ -631,6 +690,8 @@ void smtc_smp_finish(void)
 	if (cpu > 0 && (cpu_data[cpu].vpe_id != cpu_data[cpu - 1].vpe_id))
 		write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
 
+	local_irq_enable();
+
 	printk("TC %d going on-line as CPU %d\n",
 		cpu_data[smp_processor_id()].tc_id, smp_processor_id());
 }
diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c
index 99f913c..842d55e 100644
--- a/arch/mips/kernel/sync-r4k.c
+++ b/arch/mips/kernel/sync-r4k.c
@@ -111,7 +111,6 @@ void __cpuinit synchronise_count_master(void)
 void __cpuinit synchronise_count_slave(void)
 {
 	int i;
-	unsigned long flags;
 	unsigned int initcount;
 	int ncpus;
 
@@ -123,8 +122,6 @@ void __cpuinit synchronise_count_slave(void)
 	return;
 #endif
 
-	local_irq_save(flags);
-
 	/*
 	 * Not every cpu is online at the time this gets called,
 	 * so we first wait for the master to say everyone is ready
@@ -154,7 +151,5 @@ void __cpuinit synchronise_count_slave(void)
 	}
 	/* Arrange for an interrupt in a short while */
 	write_c0_compare(read_c0_count() + COUNTON);
-
-	local_irq_restore(flags);
 }
 #undef NR_LOOPS
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 2d0c2a2..9be3df1 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -132,6 +132,9 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs)
 	unsigned long ra = regs->regs[31];
 	unsigned long pc = regs->cp0_epc;
 
+	if (!task)
+		task = current;
+
 	if (raw_show_trace || !__kernel_text_address(pc)) {
 		show_raw_backtrace(sp);
 		return;
@@ -1249,6 +1252,8 @@ static inline void parity_protection_init(void)
 		break;
 
 	case CPU_5KC:
+	case CPU_5KE:
+	case CPU_LOONGSON1:
 		write_c0_ecc(0x80000000);
 		back_to_back_c0_hazard();
 		/* Set the PE bit (bit 31) in the c0_errctl register. */
@@ -1498,6 +1503,7 @@ extern void flush_tlb_handlers(void);
  * Timer interrupt
  */
 int cp0_compare_irq;
+EXPORT_SYMBOL_GPL(cp0_compare_irq);
 int cp0_compare_irq_shift;
 
 /*
@@ -1597,7 +1603,7 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu)
 			cp0_perfcount_irq = -1;
 	} else {
 		cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ;
-		cp0_compare_irq_shift = cp0_compare_irq;
+		cp0_compare_irq_shift = CP0_LEGACY_PERFCNT_IRQ;
 		cp0_perfcount_irq = -1;
 	}
 
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 924da5e..df243a6 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -1,5 +1,6 @@
 #include <asm/asm-offsets.h>
 #include <asm/page.h>
+#include <asm/thread_info.h>
 #include <asm-generic/vmlinux.lds.h>
 
 #undef mips
@@ -72,7 +73,7 @@ SECTIONS
 	.data : {	/* Data */
 		. = . + DATAOFFSET;		/* for CONFIG_MAPPED_KERNEL */
 
-		INIT_TASK_DATA(PAGE_SIZE)
+		INIT_TASK_DATA(THREAD_SIZE)
 		NOSAVE_DATA
 		CACHELINE_ALIGNED_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
 		READ_MOSTLY_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 2a7c74f..399a50a 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -2,7 +2,7 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y	+= csum_partial.o delay.o memcpy.o memcpy-inatomic.o memset.o \
+lib-y	+= csum_partial.o delay.o memcpy.o memset.o \
 	   strlen_user.o strncpy_user.o strnlen_user.o uncached.o
 
 obj-y			+= iomap.o
diff --git a/arch/mips/lib/memcpy-inatomic.S b/arch/mips/lib/memcpy-inatomic.S
deleted file mode 100644
index 68853a0..0000000
--- a/arch/mips/lib/memcpy-inatomic.S
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Unified implementation of memcpy, memmove and the __copy_user backend.
- *
- * Copyright (C) 1998, 99, 2000, 01, 2002 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 1999, 2000, 01, 2002 Silicon Graphics, Inc.
- * Copyright (C) 2002 Broadcom, Inc.
- *   memcpy/copy_user author: Mark Vandevoorde
- * Copyright (C) 2007  Maciej W. Rozycki
- *
- * Mnemonic names for arguments to memcpy/__copy_user
- */
-
-/*
- * Hack to resolve longstanding prefetch issue
- *
- * Prefetching may be fatal on some systems if we're prefetching beyond the
- * end of memory on some systems.  It's also a seriously bad idea on non
- * dma-coherent systems.
- */
-#ifdef CONFIG_DMA_NONCOHERENT
-#undef CONFIG_CPU_HAS_PREFETCH
-#endif
-#ifdef CONFIG_MIPS_MALTA
-#undef CONFIG_CPU_HAS_PREFETCH
-#endif
-
-#include <asm/asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/regdef.h>
-
-#define dst a0
-#define src a1
-#define len a2
-
-/*
- * Spec
- *
- * memcpy copies len bytes from src to dst and sets v0 to dst.
- * It assumes that
- *   - src and dst don't overlap
- *   - src is readable
- *   - dst is writable
- * memcpy uses the standard calling convention
- *
- * __copy_user copies up to len bytes from src to dst and sets a2 (len) to
- * the number of uncopied bytes due to an exception caused by a read or write.
- * __copy_user assumes that src and dst don't overlap, and that the call is
- * implementing one of the following:
- *   copy_to_user
- *     - src is readable  (no exceptions when reading src)
- *   copy_from_user
- *     - dst is writable  (no exceptions when writing dst)
- * __copy_user uses a non-standard calling convention; see
- * include/asm-mips/uaccess.h
- *
- * When an exception happens on a load, the handler must
- # ensure that all of the destination buffer is overwritten to prevent
- * leaking information to user mode programs.
- */
-
-/*
- * Implementation
- */
-
-/*
- * The exception handler for loads requires that:
- *  1- AT contain the address of the byte just past the end of the source
- *     of the copy,
- *  2- src_entry <= src < AT, and
- *  3- (dst - src) == (dst_entry - src_entry),
- * The _entry suffix denotes values when __copy_user was called.
- *
- * (1) is set up up by uaccess.h and maintained by not writing AT in copy_user
- * (2) is met by incrementing src by the number of bytes copied
- * (3) is met by not doing loads between a pair of increments of dst and src
- *
- * The exception handlers for stores adjust len (if necessary) and return.
- * These handlers do not need to overwrite any data.
- *
- * For __rmemcpy and memmove an exception is always a kernel bug, therefore
- * they're not protected.
- */
-
-#define EXC(inst_reg,addr,handler)		\
-9:	inst_reg, addr;				\
-	.section __ex_table,"a";		\
-	PTR	9b, handler;			\
-	.previous
-
-/*
- * Only on the 64-bit kernel we can made use of 64-bit registers.
- */
-#ifdef CONFIG_64BIT
-#define USE_DOUBLE
-#endif
-
-#ifdef USE_DOUBLE
-
-#define LOAD   ld
-#define LOADL  ldl
-#define LOADR  ldr
-#define STOREL sdl
-#define STORER sdr
-#define STORE  sd
-#define ADD    daddu
-#define SUB    dsubu
-#define SRL    dsrl
-#define SRA    dsra
-#define SLL    dsll
-#define SLLV   dsllv
-#define SRLV   dsrlv
-#define NBYTES 8
-#define LOG_NBYTES 3
-
-/*
- * As we are sharing code base with the mips32 tree (which use the o32 ABI
- * register definitions). We need to redefine the register definitions from
- * the n64 ABI register naming to the o32 ABI register naming.
- */
-#undef t0
-#undef t1
-#undef t2
-#undef t3
-#define t0	$8
-#define t1	$9
-#define t2	$10
-#define t3	$11
-#define t4	$12
-#define t5	$13
-#define t6	$14
-#define t7	$15
-
-#else
-
-#define LOAD   lw
-#define LOADL  lwl
-#define LOADR  lwr
-#define STOREL swl
-#define STORER swr
-#define STORE  sw
-#define ADD    addu
-#define SUB    subu
-#define SRL    srl
-#define SLL    sll
-#define SRA    sra
-#define SLLV   sllv
-#define SRLV   srlv
-#define NBYTES 4
-#define LOG_NBYTES 2
-
-#endif /* USE_DOUBLE */
-
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
-#define LDFIRST LOADR
-#define LDREST  LOADL
-#define STFIRST STORER
-#define STREST  STOREL
-#define SHIFT_DISCARD SLLV
-#else
-#define LDFIRST LOADL
-#define LDREST  LOADR
-#define STFIRST STOREL
-#define STREST  STORER
-#define SHIFT_DISCARD SRLV
-#endif
-
-#define FIRST(unit) ((unit)*NBYTES)
-#define REST(unit)  (FIRST(unit)+NBYTES-1)
-#define UNIT(unit)  FIRST(unit)
-
-#define ADDRMASK (NBYTES-1)
-
-	.text
-	.set	noreorder
-#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
-	.set	noat
-#else
-	.set	at=v1
-#endif
-
-/*
- * A combined memcpy/__copy_user
- * __copy_user sets len to 0 for success; else to an upper bound of
- * the number of uncopied bytes.
- * memcpy sets v0 to dst.
- */
-	.align	5
-LEAF(__copy_user_inatomic)
-	/*
-	 * Note: dst & src may be unaligned, len may be 0
-	 * Temps
-	 */
-#define rem t8
-
-	/*
-	 * The "issue break"s below are very approximate.
-	 * Issue delays for dcache fills will perturb the schedule, as will
-	 * load queue full replay traps, etc.
-	 *
-	 * If len < NBYTES use byte operations.
-	 */
-	PREF(	0, 0(src) )
-	PREF(	1, 0(dst) )
-	sltu	t2, len, NBYTES
-	and	t1, dst, ADDRMASK
-	PREF(	0, 1*32(src) )
-	PREF(	1, 1*32(dst) )
-	bnez	t2, .Lcopy_bytes_checklen
-	 and	t0, src, ADDRMASK
-	PREF(	0, 2*32(src) )
-	PREF(	1, 2*32(dst) )
-	bnez	t1, .Ldst_unaligned
-	 nop
-	bnez	t0, .Lsrc_unaligned_dst_aligned
-	/*
-	 * use delay slot for fall-through
-	 * src and dst are aligned; need to compute rem
-	 */
-.Lboth_aligned:
-	 SRL	t0, len, LOG_NBYTES+3    	# +3 for 8 units/iter
-	beqz	t0, .Lcleanup_both_aligned	# len < 8*NBYTES
-	 and	rem, len, (8*NBYTES-1)	 	# rem = len % (8*NBYTES)
-	PREF(	0, 3*32(src) )
-	PREF(	1, 3*32(dst) )
-	.align	4
-1:
-EXC(	LOAD	t0, UNIT(0)(src),	.Ll_exc)
-EXC(	LOAD	t1, UNIT(1)(src),	.Ll_exc_copy)
-EXC(	LOAD	t2, UNIT(2)(src),	.Ll_exc_copy)
-EXC(	LOAD	t3, UNIT(3)(src),	.Ll_exc_copy)
-	SUB	len, len, 8*NBYTES
-EXC(	LOAD	t4, UNIT(4)(src),	.Ll_exc_copy)
-EXC(	LOAD	t7, UNIT(5)(src),	.Ll_exc_copy)
-	STORE	t0, UNIT(0)(dst)
-	STORE	t1, UNIT(1)(dst)
-EXC(	LOAD	t0, UNIT(6)(src),	.Ll_exc_copy)
-EXC(	LOAD	t1, UNIT(7)(src),	.Ll_exc_copy)
-	ADD	src, src, 8*NBYTES
-	ADD	dst, dst, 8*NBYTES
-	STORE	t2, UNIT(-6)(dst)
-	STORE	t3, UNIT(-5)(dst)
-	STORE	t4, UNIT(-4)(dst)
-	STORE	t7, UNIT(-3)(dst)
-	STORE	t0, UNIT(-2)(dst)
-	STORE	t1, UNIT(-1)(dst)
-	PREF(	0, 8*32(src) )
-	PREF(	1, 8*32(dst) )
-	bne	len, rem, 1b
-	 nop
-
-	/*
-	 * len == rem == the number of bytes left to copy < 8*NBYTES
-	 */
-.Lcleanup_both_aligned:
-	beqz	len, .Ldone
-	 sltu	t0, len, 4*NBYTES
-	bnez	t0, .Lless_than_4units
-	 and	rem, len, (NBYTES-1)	# rem = len % NBYTES
-	/*
-	 * len >= 4*NBYTES
-	 */
-EXC(	LOAD	t0, UNIT(0)(src),	.Ll_exc)
-EXC(	LOAD	t1, UNIT(1)(src),	.Ll_exc_copy)
-EXC(	LOAD	t2, UNIT(2)(src),	.Ll_exc_copy)
-EXC(	LOAD	t3, UNIT(3)(src),	.Ll_exc_copy)
-	SUB	len, len, 4*NBYTES
-	ADD	src, src, 4*NBYTES
-	STORE	t0, UNIT(0)(dst)
-	STORE	t1, UNIT(1)(dst)
-	STORE	t2, UNIT(2)(dst)
-	STORE	t3, UNIT(3)(dst)
-	.set	reorder				/* DADDI_WAR */
-	ADD	dst, dst, 4*NBYTES
-	beqz	len, .Ldone
-	.set	noreorder
-.Lless_than_4units:
-	/*
-	 * rem = len % NBYTES
-	 */
-	beq	rem, len, .Lcopy_bytes
-	 nop
-1:
-EXC(	LOAD	t0, 0(src),		.Ll_exc)
-	ADD	src, src, NBYTES
-	SUB	len, len, NBYTES
-	STORE	t0, 0(dst)
-	.set	reorder				/* DADDI_WAR */
-	ADD	dst, dst, NBYTES
-	bne	rem, len, 1b
-	.set	noreorder
-
-	/*
-	 * src and dst are aligned, need to copy rem bytes (rem < NBYTES)
-	 * A loop would do only a byte at a time with possible branch
-	 * mispredicts.  Can't do an explicit LOAD dst,mask,or,STORE
-	 * because can't assume read-access to dst.  Instead, use
-	 * STREST dst, which doesn't require read access to dst.
-	 *
-	 * This code should perform better than a simple loop on modern,
-	 * wide-issue mips processors because the code has fewer branches and
-	 * more instruction-level parallelism.
-	 */
-#define bits t2
-	beqz	len, .Ldone
-	 ADD	t1, dst, len	# t1 is just past last byte of dst
-	li	bits, 8*NBYTES
-	SLL	rem, len, 3	# rem = number of bits to keep
-EXC(	LOAD	t0, 0(src),		.Ll_exc)
-	SUB	bits, bits, rem	# bits = number of bits to discard
-	SHIFT_DISCARD t0, t0, bits
-	STREST	t0, -1(t1)
-	jr	ra
-	 move	len, zero
-.Ldst_unaligned:
-	/*
-	 * dst is unaligned
-	 * t0 = src & ADDRMASK
-	 * t1 = dst & ADDRMASK; T1 > 0
-	 * len >= NBYTES
-	 *
-	 * Copy enough bytes to align dst
-	 * Set match = (src and dst have same alignment)
-	 */
-#define match rem
-EXC(	LDFIRST	t3, FIRST(0)(src),	.Ll_exc)
-	ADD	t2, zero, NBYTES
-EXC(	LDREST	t3, REST(0)(src),	.Ll_exc_copy)
-	SUB	t2, t2, t1	# t2 = number of bytes copied
-	xor	match, t0, t1
-	STFIRST t3, FIRST(0)(dst)
-	beq	len, t2, .Ldone
-	 SUB	len, len, t2
-	ADD	dst, dst, t2
-	beqz	match, .Lboth_aligned
-	 ADD	src, src, t2
-
-.Lsrc_unaligned_dst_aligned:
-	SRL	t0, len, LOG_NBYTES+2    # +2 for 4 units/iter
-	PREF(	0, 3*32(src) )
-	beqz	t0, .Lcleanup_src_unaligned
-	 and	rem, len, (4*NBYTES-1)   # rem = len % 4*NBYTES
-	PREF(	1, 3*32(dst) )
-1:
-/*
- * Avoid consecutive LD*'s to the same register since some mips
- * implementations can't issue them in the same cycle.
- * It's OK to load FIRST(N+1) before REST(N) because the two addresses
- * are to the same unit (unless src is aligned, but it's not).
- */
-EXC(	LDFIRST	t0, FIRST(0)(src),	.Ll_exc)
-EXC(	LDFIRST	t1, FIRST(1)(src),	.Ll_exc_copy)
-	SUB     len, len, 4*NBYTES
-EXC(	LDREST	t0, REST(0)(src),	.Ll_exc_copy)
-EXC(	LDREST	t1, REST(1)(src),	.Ll_exc_copy)
-EXC(	LDFIRST	t2, FIRST(2)(src),	.Ll_exc_copy)
-EXC(	LDFIRST	t3, FIRST(3)(src),	.Ll_exc_copy)
-EXC(	LDREST	t2, REST(2)(src),	.Ll_exc_copy)
-EXC(	LDREST	t3, REST(3)(src),	.Ll_exc_copy)
-	PREF(	0, 9*32(src) )		# 0 is PREF_LOAD  (not streamed)
-	ADD	src, src, 4*NBYTES
-#ifdef CONFIG_CPU_SB1
-	nop				# improves slotting
-#endif
-	STORE	t0, UNIT(0)(dst)
-	STORE	t1, UNIT(1)(dst)
-	STORE	t2, UNIT(2)(dst)
-	STORE	t3, UNIT(3)(dst)
-	PREF(	1, 9*32(dst) )     	# 1 is PREF_STORE (not streamed)
-	.set	reorder				/* DADDI_WAR */
-	ADD	dst, dst, 4*NBYTES
-	bne	len, rem, 1b
-	.set	noreorder
-
-.Lcleanup_src_unaligned:
-	beqz	len, .Ldone
-	 and	rem, len, NBYTES-1  # rem = len % NBYTES
-	beq	rem, len, .Lcopy_bytes
-	 nop
-1:
-EXC(	LDFIRST t0, FIRST(0)(src),	.Ll_exc)
-EXC(	LDREST	t0, REST(0)(src),	.Ll_exc_copy)
-	ADD	src, src, NBYTES
-	SUB	len, len, NBYTES
-	STORE	t0, 0(dst)
-	.set	reorder				/* DADDI_WAR */
-	ADD	dst, dst, NBYTES
-	bne	len, rem, 1b
-	.set	noreorder
-
-.Lcopy_bytes_checklen:
-	beqz	len, .Ldone
-	 nop
-.Lcopy_bytes:
-	/* 0 < len < NBYTES  */
-#define COPY_BYTE(N)			\
-EXC(	lb	t0, N(src), .Ll_exc);	\
-	SUB	len, len, 1;		\
-	beqz	len, .Ldone;		\
-	 sb	t0, N(dst)
-
-	COPY_BYTE(0)
-	COPY_BYTE(1)
-#ifdef USE_DOUBLE
-	COPY_BYTE(2)
-	COPY_BYTE(3)
-	COPY_BYTE(4)
-	COPY_BYTE(5)
-#endif
-EXC(	lb	t0, NBYTES-2(src), .Ll_exc)
-	SUB	len, len, 1
-	jr	ra
-	 sb	t0, NBYTES-2(dst)
-.Ldone:
-	jr	ra
-	 nop
-	END(__copy_user_inatomic)
-
-.Ll_exc_copy:
-	/*
-	 * Copy bytes from src until faulting load address (or until a
-	 * lb faults)
-	 *
-	 * When reached by a faulting LDFIRST/LDREST, THREAD_BUADDR($28)
-	 * may be more than a byte beyond the last address.
-	 * Hence, the lb below may get an exception.
-	 *
-	 * Assumes src < THREAD_BUADDR($28)
-	 */
-	LOAD	t0, TI_TASK($28)
-	 nop
-	LOAD	t0, THREAD_BUADDR(t0)
-1:
-EXC(	lb	t1, 0(src),	.Ll_exc)
-	ADD	src, src, 1
-	sb	t1, 0(dst)	# can't fault -- we're copy_from_user
-	.set	reorder				/* DADDI_WAR */
-	ADD	dst, dst, 1
-	bne	src, t0, 1b
-	.set	noreorder
-.Ll_exc:
-	LOAD	t0, TI_TASK($28)
-	 nop
-	LOAD	t0, THREAD_BUADDR(t0)	# t0 is just past last good address
-	 nop
-	SUB	len, AT, t0		# len number of uncopied bytes
-	jr	ra
-	 nop
diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S
index 56a1f85..65192c0 100644
--- a/arch/mips/lib/memcpy.S
+++ b/arch/mips/lib/memcpy.S
@@ -183,6 +183,14 @@
 #endif
 
 /*
+ * t6 is used as a flag to note inatomic mode.
+ */
+LEAF(__copy_user_inatomic)
+	b	__copy_user_common
+	 li	t6, 1
+	END(__copy_user_inatomic)
+
+/*
  * A combined memcpy/__copy_user
  * __copy_user sets len to 0 for success; else to an upper bound of
  * the number of uncopied bytes.
@@ -193,6 +201,8 @@ LEAF(memcpy)					/* a0=dst a1=src a2=len */
 	move	v0, dst				/* return value */
 .L__memcpy:
 FEXPORT(__copy_user)
+	li	t6, 0	/* not inatomic */
+__copy_user_common:
 	/*
 	 * Note: dst & src may be unaligned, len may be 0
 	 * Temps
@@ -458,6 +468,7 @@ EXC(	lb	t1, 0(src),	.Ll_exc)
 	LOAD	t0, THREAD_BUADDR(t0)	# t0 is just past last good address
 	 nop
 	SUB	len, AT, t0		# len number of uncopied bytes
+	bnez	t6, .Ldone	/* Skip the zeroing part if inatomic */
 	/*
 	 * Here's where we rely on src and dst being incremented in tandem,
 	 *   See (3) above.
diff --git a/arch/mips/loongson1/Kconfig b/arch/mips/loongson1/Kconfig
new file mode 100644
index 0000000..237fa21
--- /dev/null
+++ b/arch/mips/loongson1/Kconfig
@@ -0,0 +1,21 @@
+if MACH_LOONGSON1
+
+choice
+	prompt "Machine Type"
+
+config LOONGSON1_LS1B
+	bool "Loongson LS1B board"
+	select CEVT_R4K
+	select CSRC_R4K
+	select SYS_HAS_CPU_LOONGSON1B
+	select DMA_NONCOHERENT
+	select BOOT_ELF32
+	select IRQ_CPU
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select SYS_SUPPORTS_LITTLE_ENDIAN
+	select SYS_SUPPORTS_HIGHMEM
+	select SYS_HAS_EARLY_PRINTK
+
+endchoice
+
+endif # MACH_LOONGSON1
diff --git a/arch/mips/loongson1/Makefile b/arch/mips/loongson1/Makefile
new file mode 100644
index 0000000..e9123c2
--- /dev/null
+++ b/arch/mips/loongson1/Makefile
@@ -0,0 +1,11 @@
+#
+# Common code for all Loongson1 based systems
+#
+
+obj-$(CONFIG_MACH_LOONGSON1) += common/
+
+#
+# Loongson LS1B board
+#
+
+obj-$(CONFIG_LOONGSON1_LS1B)  += ls1b/
diff --git a/arch/mips/loongson1/Platform b/arch/mips/loongson1/Platform
new file mode 100644
index 0000000..92804c6
--- /dev/null
+++ b/arch/mips/loongson1/Platform
@@ -0,0 +1,7 @@
+cflags-$(CONFIG_CPU_LOONGSON1)  += \
+	$(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
+	-Wa,-mips32r2 -Wa,--trap
+
+platform-$(CONFIG_MACH_LOONGSON1)	+= loongson1/
+cflags-$(CONFIG_MACH_LOONGSON1)		+= -I$(srctree)/arch/mips/include/asm/mach-loongson1
+load-$(CONFIG_LOONGSON1_LS1B)		+= 0xffffffff80010000
diff --git a/arch/mips/loongson1/common/Makefile b/arch/mips/loongson1/common/Makefile
new file mode 100644
index 0000000..b279770
--- /dev/null
+++ b/arch/mips/loongson1/common/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for common code of loongson1 based machines.
+#
+
+obj-y	+= clock.o irq.o platform.o prom.o reset.o setup.o
diff --git a/arch/mips/loongson1/common/clock.c b/arch/mips/loongson1/common/clock.c
new file mode 100644
index 0000000..2d98fb0
--- /dev/null
+++ b/arch/mips/loongson1/common/clock.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@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/module.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/clock.h>
+#include <asm/time.h>
+
+#include <loongson1.h>
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+
+struct clk *clk_get(struct device *dev, const char *name)
+{
+	struct clk *c;
+	struct clk *ret = NULL;
+
+	mutex_lock(&clocks_mutex);
+	list_for_each_entry(c, &clocks, node) {
+		if (!strcmp(c->name, name)) {
+			ret = c;
+			break;
+		}
+	}
+	mutex_unlock(&clocks_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_get);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+static void pll_clk_init(struct clk *clk)
+{
+	u32 pll;
+
+	pll = __raw_readl(LS1X_CLK_PLL_FREQ);
+	clk->rate = (12 + (pll & 0x3f)) * 33 / 2
+			+ ((pll >> 8) & 0x3ff) * 33 / 1024 / 2;
+	clk->rate *= 1000000;
+}
+
+static void cpu_clk_init(struct clk *clk)
+{
+	u32 pll, ctrl;
+
+	pll = clk_get_rate(clk->parent);
+	ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_CPU;
+	clk->rate = pll / (ctrl >> DIV_CPU_SHIFT);
+}
+
+static void ddr_clk_init(struct clk *clk)
+{
+	u32 pll, ctrl;
+
+	pll = clk_get_rate(clk->parent);
+	ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_DDR;
+	clk->rate = pll / (ctrl >> DIV_DDR_SHIFT);
+}
+
+static void dc_clk_init(struct clk *clk)
+{
+	u32 pll, ctrl;
+
+	pll = clk_get_rate(clk->parent);
+	ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_DC;
+	clk->rate = pll / (ctrl >> DIV_DC_SHIFT);
+}
+
+static struct clk_ops pll_clk_ops = {
+	.init	= pll_clk_init,
+};
+
+static struct clk_ops cpu_clk_ops = {
+	.init	= cpu_clk_init,
+};
+
+static struct clk_ops ddr_clk_ops = {
+	.init	= ddr_clk_init,
+};
+
+static struct clk_ops dc_clk_ops = {
+	.init	= dc_clk_init,
+};
+
+static struct clk pll_clk = {
+	.name	= "pll",
+	.ops	= &pll_clk_ops,
+};
+
+static struct clk cpu_clk = {
+	.name	= "cpu",
+	.parent = &pll_clk,
+	.ops	= &cpu_clk_ops,
+};
+
+static struct clk ddr_clk = {
+	.name	= "ddr",
+	.parent = &pll_clk,
+	.ops	= &ddr_clk_ops,
+};
+
+static struct clk dc_clk = {
+	.name	= "dc",
+	.parent = &pll_clk,
+	.ops	= &dc_clk_ops,
+};
+
+int clk_register(struct clk *clk)
+{
+	mutex_lock(&clocks_mutex);
+	list_add(&clk->node, &clocks);
+	if (clk->ops->init)
+		clk->ops->init(clk);
+	mutex_unlock(&clocks_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+static struct clk *ls1x_clks[] = {
+	&pll_clk,
+	&cpu_clk,
+	&ddr_clk,
+	&dc_clk,
+};
+
+int __init ls1x_clock_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ls1x_clks); i++)
+		clk_register(ls1x_clks[i]);
+
+	return 0;
+}
+
+void __init plat_time_init(void)
+{
+	struct clk *clk;
+
+	/* Initialize LS1X clocks */
+	ls1x_clock_init();
+
+	/* setup mips r4k timer */
+	clk = clk_get(NULL, "cpu");
+	if (IS_ERR(clk))
+		panic("unable to get dc clock, err=%ld", PTR_ERR(clk));
+
+	mips_hpt_frequency = clk_get_rate(clk) / 2;
+}
diff --git a/arch/mips/loongson1/common/irq.c b/arch/mips/loongson1/common/irq.c
new file mode 100644
index 0000000..41bc8ff
--- /dev/null
+++ b/arch/mips/loongson1/common/irq.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@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/interrupt.h>
+#include <linux/irq.h>
+#include <asm/irq_cpu.h>
+
+#include <loongson1.h>
+#include <irq.h>
+
+#define LS1X_INTC_REG(n, x) \
+		((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x)))
+
+#define LS1X_INTC_INTISR(n)		LS1X_INTC_REG(n, 0x0)
+#define LS1X_INTC_INTIEN(n)		LS1X_INTC_REG(n, 0x4)
+#define LS1X_INTC_INTSET(n)		LS1X_INTC_REG(n, 0x8)
+#define LS1X_INTC_INTCLR(n)		LS1X_INTC_REG(n, 0xc)
+#define LS1X_INTC_INTPOL(n)		LS1X_INTC_REG(n, 0x10)
+#define LS1X_INTC_INTEDGE(n)		LS1X_INTC_REG(n, 0x14)
+
+static void ls1x_irq_ack(struct irq_data *d)
+{
+	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
+	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
+
+	__raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
+			| (1 << bit), LS1X_INTC_INTCLR(n));
+}
+
+static void ls1x_irq_mask(struct irq_data *d)
+{
+	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
+	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
+
+	__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
+			& ~(1 << bit), LS1X_INTC_INTIEN(n));
+}
+
+static void ls1x_irq_mask_ack(struct irq_data *d)
+{
+	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
+	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
+
+	__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
+			& ~(1 << bit), LS1X_INTC_INTIEN(n));
+	__raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
+			| (1 << bit), LS1X_INTC_INTCLR(n));
+}
+
+static void ls1x_irq_unmask(struct irq_data *d)
+{
+	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
+	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
+
+	__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
+			| (1 << bit), LS1X_INTC_INTIEN(n));
+}
+
+static struct irq_chip ls1x_irq_chip = {
+	.name		= "LS1X-INTC",
+	.irq_ack	= ls1x_irq_ack,
+	.irq_mask	= ls1x_irq_mask,
+	.irq_mask_ack	= ls1x_irq_mask_ack,
+	.irq_unmask	= ls1x_irq_unmask,
+};
+
+static void ls1x_irq_dispatch(int n)
+{
+	u32 int_status, irq;
+
+	/* Get pending sources, masked by current enables */
+	int_status = __raw_readl(LS1X_INTC_INTISR(n)) &
+			__raw_readl(LS1X_INTC_INTIEN(n));
+
+	if (int_status) {
+		irq = LS1X_IRQ(n, __ffs(int_status));
+		do_IRQ(irq);
+	}
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+	unsigned int pending;
+
+	pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+	if (pending & CAUSEF_IP7)
+		do_IRQ(TIMER_IRQ);
+	else if (pending & CAUSEF_IP2)
+		ls1x_irq_dispatch(0); /* INT0 */
+	else if (pending & CAUSEF_IP3)
+		ls1x_irq_dispatch(1); /* INT1 */
+	else if (pending & CAUSEF_IP4)
+		ls1x_irq_dispatch(2); /* INT2 */
+	else if (pending & CAUSEF_IP5)
+		ls1x_irq_dispatch(3); /* INT3 */
+	else if (pending & CAUSEF_IP6)
+		ls1x_irq_dispatch(4); /* INT4 */
+	else
+		spurious_interrupt();
+
+}
+
+struct irqaction cascade_irqaction = {
+	.handler = no_action,
+	.name = "cascade",
+	.flags = IRQF_NO_THREAD,
+};
+
+static void __init ls1x_irq_init(int base)
+{
+	int n;
+
+	/* Disable interrupts and clear pending,
+	 * setup all IRQs as high level triggered
+	 */
+	for (n = 0; n < 4; n++) {
+		__raw_writel(0x0, LS1X_INTC_INTIEN(n));
+		__raw_writel(0xffffffff, LS1X_INTC_INTCLR(n));
+		__raw_writel(0xffffffff, LS1X_INTC_INTPOL(n));
+		/* set DMA0, DMA1 and DMA2 to edge trigger */
+		__raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n));
+	}
+
+
+	for (n = base; n < LS1X_IRQS; n++) {
+		irq_set_chip_and_handler(n, &ls1x_irq_chip,
+					 handle_level_irq);
+	}
+
+	setup_irq(INT0_IRQ, &cascade_irqaction);
+	setup_irq(INT1_IRQ, &cascade_irqaction);
+	setup_irq(INT2_IRQ, &cascade_irqaction);
+	setup_irq(INT3_IRQ, &cascade_irqaction);
+}
+
+void __init arch_init_irq(void)
+{
+	mips_cpu_irq_init();
+	ls1x_irq_init(LS1X_IRQ_BASE);
+}
diff --git a/arch/mips/loongson1/common/platform.c b/arch/mips/loongson1/common/platform.c
new file mode 100644
index 0000000..d928af5
--- /dev/null
+++ b/arch/mips/loongson1/common/platform.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@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/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/phy.h>
+#include <linux/serial_8250.h>
+#include <linux/stmmac.h>
+#include <asm-generic/sizes.h>
+
+#include <loongson1.h>
+
+#define LS1X_UART(_id)						\
+	{							\
+		.mapbase	= LS1X_UART ## _id ## _BASE,	\
+		.irq		= LS1X_UART ## _id ## _IRQ,	\
+		.iotype		= UPIO_MEM,			\
+		.flags		= UPF_IOREMAP | UPF_FIXED_TYPE,	\
+		.type		= PORT_16550A,			\
+	}
+
+static struct plat_serial8250_port ls1x_serial8250_port[] = {
+	LS1X_UART(0),
+	LS1X_UART(1),
+	LS1X_UART(2),
+	LS1X_UART(3),
+	{},
+};
+
+struct platform_device ls1x_uart_device = {
+	.name		= "serial8250",
+	.id		= PLAT8250_DEV_PLATFORM,
+	.dev		= {
+		.platform_data = ls1x_serial8250_port,
+	},
+};
+
+void __init ls1x_serial_setup(void)
+{
+	struct clk *clk;
+	struct plat_serial8250_port *p;
+
+	clk = clk_get(NULL, "dc");
+	if (IS_ERR(clk))
+		panic("unable to get dc clock, err=%ld", PTR_ERR(clk));
+
+	for (p = ls1x_serial8250_port; p->flags != 0; ++p)
+		p->uartclk = clk_get_rate(clk);
+}
+
+/* Synopsys Ethernet GMAC */
+#if IS_ENABLED(CONFIG_STMMAC_ETH)
+static struct resource ls1x_eth0_resources[] = {
+	[0] = {
+		.start	= LS1X_GMAC0_BASE,
+		.end	= LS1X_GMAC0_BASE + SZ_64K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "macirq",
+		.start	= LS1X_GMAC0_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = {
+	.bus_id		= 0,
+	.phy_mask	= 0,
+};
+
+static struct plat_stmmacenet_data ls1x_eth_data = {
+	.bus_id		= 0,
+	.phy_addr	= -1,
+	.mdio_bus_data	= &ls1x_mdio_bus_data,
+	.pbl		= 32,
+	.has_gmac	= 1,
+	.tx_coe		= 1,
+};
+
+struct platform_device ls1x_eth0_device = {
+	.name		= "stmmaceth",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(ls1x_eth0_resources),
+	.resource	= ls1x_eth0_resources,
+	.dev		= {
+		.platform_data = &ls1x_eth_data,
+	},
+};
+#endif
+
+/* EHCI */
+#if IS_ENABLED(CONFIG_USB_EHCI_HCD)
+static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ls1x_ehci_resources[] = {
+	[0] = {
+		.start	= LS1X_EHCI_BASE,
+		.end	= LS1X_EHCI_BASE + SZ_32K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= LS1X_EHCI_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device ls1x_ehci_device = {
+	.name		= "ls1x-ehci",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ls1x_ehci_resources),
+	.resource	= ls1x_ehci_resources,
+	.dev		= {
+		.dma_mask = &ls1x_ehci_dmamask,
+	},
+};
+#endif
+
+#if IS_ENABLED(CONFIG_RTC_DRV_LOONGSON1)
+struct platform_device ls1x_rtc_device = {
+	.name		= "ls1x-rtc",
+	.id		= -1,
+};
+#endif
diff --git a/arch/mips/loongson1/common/prom.c b/arch/mips/loongson1/common/prom.c
new file mode 100644
index 0000000..1f8e49f
--- /dev/null
+++ b/arch/mips/loongson1/common/prom.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * Modified from arch/mips/pnx833x/common/prom.c.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/serial_reg.h>
+#include <asm/bootinfo.h>
+
+#include <loongson1.h>
+#include <prom.h>
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+unsigned long memsize, highmemsize;
+
+char *prom_getenv(char *envname)
+{
+	char **env = prom_envp;
+	int i;
+
+	i = strlen(envname);
+
+	while (*env) {
+		if (strncmp(envname, *env, i) == 0 && *(*env+i) == '=')
+			return *env + i + 1;
+		env++;
+	}
+
+	return 0;
+}
+
+static inline unsigned long env_or_default(char *env, unsigned long dfl)
+{
+	char *str = prom_getenv(env);
+	return str ? simple_strtol(str, 0, 0) : dfl;
+}
+
+void __init prom_init_cmdline(void)
+{
+	char *c = &(arcs_cmdline[0]);
+	int i;
+
+	for (i = 1; i < prom_argc; i++) {
+		strcpy(c, prom_argv[i]);
+		c += strlen(prom_argv[i]);
+		if (i < prom_argc-1)
+			*c++ = ' ';
+	}
+	*c = 0;
+}
+
+void __init prom_init(void)
+{
+	prom_argc = fw_arg0;
+	prom_argv = (char **)fw_arg1;
+	prom_envp = (char **)fw_arg2;
+
+	prom_init_cmdline();
+
+	memsize = env_or_default("memsize", DEFAULT_MEMSIZE);
+	highmemsize = env_or_default("highmemsize", 0x0);
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+#define PORT(offset)	(u8 *)(KSEG1ADDR(LS1X_UART0_BASE + offset))
+
+void __init prom_putchar(char c)
+{
+	int timeout;
+
+	timeout = 1024;
+
+	while (((readb(PORT(UART_LSR)) & UART_LSR_THRE) == 0)
+			&& (timeout-- > 0))
+		;
+
+	writeb(c, PORT(UART_TX));
+}
diff --git a/arch/mips/loongson1/common/reset.c b/arch/mips/loongson1/common/reset.c
new file mode 100644
index 0000000..fb979a7
--- /dev/null
+++ b/arch/mips/loongson1/common/reset.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@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/io.h>
+#include <linux/pm.h>
+#include <asm/reboot.h>
+
+#include <loongson1.h>
+
+static void ls1x_restart(char *command)
+{
+	__raw_writel(0x1, LS1X_WDT_EN);
+	__raw_writel(0x5000000, LS1X_WDT_TIMER);
+	__raw_writel(0x1, LS1X_WDT_SET);
+}
+
+static void ls1x_halt(void)
+{
+	while (1) {
+		if (cpu_wait)
+			cpu_wait();
+	}
+}
+
+static void ls1x_power_off(void)
+{
+	ls1x_halt();
+}
+
+static int __init ls1x_reboot_setup(void)
+{
+	_machine_restart = ls1x_restart;
+	_machine_halt = ls1x_halt;
+	pm_power_off = ls1x_power_off;
+
+	return 0;
+}
+
+arch_initcall(ls1x_reboot_setup);
diff --git a/arch/mips/loongson1/common/setup.c b/arch/mips/loongson1/common/setup.c
new file mode 100644
index 0000000..62128cc
--- /dev/null
+++ b/arch/mips/loongson1/common/setup.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@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 <asm/bootinfo.h>
+
+#include <prom.h>
+
+void __init plat_mem_setup(void)
+{
+	add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM);
+}
+
+const char *get_system_type(void)
+{
+	unsigned int processor_id = (&current_cpu_data)->processor_id;
+
+	switch (processor_id & PRID_REV_MASK) {
+	case PRID_REV_LOONGSON1B:
+		return "LOONGSON LS1B";
+	default:
+		return "LOONGSON (unknown)";
+	}
+}
diff --git a/arch/mips/loongson1/ls1b/Makefile b/arch/mips/loongson1/ls1b/Makefile
new file mode 100644
index 0000000..891eac4
--- /dev/null
+++ b/arch/mips/loongson1/ls1b/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for loongson1B based machines.
+#
+
+obj-y += board.o
diff --git a/arch/mips/loongson1/ls1b/board.c b/arch/mips/loongson1/ls1b/board.c
new file mode 100644
index 0000000..1ec350d
--- /dev/null
+++ b/arch/mips/loongson1/ls1b/board.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@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 <platform.h>
+
+#include <linux/serial_8250.h>
+#include <loongson1.h>
+
+static struct platform_device *ls1b_platform_devices[] __initdata = {
+	&ls1x_uart_device,
+#if IS_ENABLED(CONFIG_STMMAC_ETH)
+	&ls1x_eth0_device,
+#endif
+#if IS_ENABLED(CONFIG_USB_EHCI_HCD)
+	&ls1x_ehci_device,
+#endif
+#if IS_ENABLED(CONFIG_RTC_DRV_LOONGSON1)
+	&ls1x_rtc_device,
+#endif
+};
+
+static int __init ls1b_platform_init(void)
+{
+	int err;
+
+	ls1x_serial_setup();
+
+	err = platform_add_devices(ls1b_platform_devices,
+				   ARRAY_SIZE(ls1b_platform_devices));
+	return err;
+}
+
+arch_initcall(ls1b_platform_init);
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index 4aa2028..fd6203f 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -3,8 +3,8 @@
 #
 
 obj-y				+= cache.o dma-default.o extable.o fault.o \
-				   gup.o init.o mmap.o page.o tlbex.o \
-				   tlbex-fault.o uasm.o
+				   gup.o init.o mmap.o page.o page-funcs.o \
+				   tlbex.o tlbex-fault.o uasm.o
 
 obj-$(CONFIG_32BIT)		+= ioremap.o pgtable-32.o
 obj-$(CONFIG_64BIT)		+= pgtable-64.o
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 5109be9..f092c26 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -977,7 +977,7 @@ static void __cpuinit probe_pcache(void)
 			c->icache.linesz = 2 << lsize;
 		else
 			c->icache.linesz = lsize;
-		c->icache.sets = 64 << ((config1 >> 22) & 7);
+		c->icache.sets = 32 << (((config1 >> 22) + 1) & 7);
 		c->icache.ways = 1 + ((config1 >> 16) & 7);
 
 		icache_size = c->icache.sets *
@@ -997,7 +997,7 @@ static void __cpuinit probe_pcache(void)
 			c->dcache.linesz = 2 << lsize;
 		else
 			c->dcache.linesz= lsize;
-		c->dcache.sets = 64 << ((config1 >> 13) & 7);
+		c->dcache.sets = 32 << (((config1 >> 13) + 1) & 7);
 		c->dcache.ways = 1 + ((config1 >> 7) & 7);
 
 		dcache_size = c->dcache.sets *
@@ -1051,6 +1051,7 @@ static void __cpuinit probe_pcache(void)
 	case CPU_R14000:
 		break;
 
+	case CPU_M14KC:
 	case CPU_24K:
 	case CPU_34K:
 	case CPU_74K:
diff --git a/arch/mips/mm/page-funcs.S b/arch/mips/mm/page-funcs.S
new file mode 100644
index 0000000..48a6b38
--- /dev/null
+++ b/arch/mips/mm/page-funcs.S
@@ -0,0 +1,50 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Micro-assembler generated clear_page/copy_page functions.
+ *
+ * Copyright (C) 2012  MIPS Technologies, Inc.
+ * Copyright (C) 2012  Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
+#define cpu_clear_page_function_name	clear_page_cpu
+#define cpu_copy_page_function_name	copy_page_cpu
+#else
+#define cpu_clear_page_function_name	clear_page
+#define cpu_copy_page_function_name	copy_page
+#endif
+
+/*
+ * Maximum sizes:
+ *
+ * R4000 128 bytes S-cache:		0x058 bytes
+ * R4600 v1.7:				0x05c bytes
+ * R4600 v2.0:				0x060 bytes
+ * With prefetching, 16 word strides	0x120 bytes
+ */
+EXPORT(__clear_page_start)
+LEAF(cpu_clear_page_function_name)
+1:	j	1b		/* Dummy, will be replaced. */
+	.space 288
+END(cpu_clear_page_function_name)
+EXPORT(__clear_page_end)
+
+/*
+ * Maximum sizes:
+ *
+ * R4000 128 bytes S-cache:		0x11c bytes
+ * R4600 v1.7:				0x080 bytes
+ * R4600 v2.0:				0x07c bytes
+ * With prefetching, 16 word strides	0x540 bytes
+ */
+EXPORT(__copy_page_start)
+LEAF(cpu_copy_page_function_name)
+1:	j	1b		/* Dummy, will be replaced. */
+	.space 1344
+END(cpu_copy_page_function_name)
+EXPORT(__copy_page_end)
diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
index cc0b626..98f530e 100644
--- a/arch/mips/mm/page.c
+++ b/arch/mips/mm/page.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 2007  Maciej W. Rozycki
  * Copyright (C) 2008  Thiemo Seufer
+ * Copyright (C) 2012  MIPS Technologies, Inc.
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -71,45 +72,6 @@ static struct uasm_reloc __cpuinitdata relocs[5];
 #define cpu_is_r4600_v1_x()	((read_c0_prid() & 0xfffffff0) == 0x00002010)
 #define cpu_is_r4600_v2_x()	((read_c0_prid() & 0xfffffff0) == 0x00002020)
 
-/*
- * Maximum sizes:
- *
- * R4000 128 bytes S-cache:		0x058 bytes
- * R4600 v1.7:				0x05c bytes
- * R4600 v2.0:				0x060 bytes
- * With prefetching, 16 word strides	0x120 bytes
- */
-
-static u32 clear_page_array[0x120 / 4];
-
-#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
-void clear_page_cpu(void *page) __attribute__((alias("clear_page_array")));
-#else
-void clear_page(void *page) __attribute__((alias("clear_page_array")));
-#endif
-
-EXPORT_SYMBOL(clear_page);
-
-/*
- * Maximum sizes:
- *
- * R4000 128 bytes S-cache:		0x11c bytes
- * R4600 v1.7:				0x080 bytes
- * R4600 v2.0:				0x07c bytes
- * With prefetching, 16 word strides	0x540 bytes
- */
-static u32 copy_page_array[0x540 / 4];
-
-#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
-void
-copy_page_cpu(void *to, void *from) __attribute__((alias("copy_page_array")));
-#else
-void copy_page(void *to, void *from) __attribute__((alias("copy_page_array")));
-#endif
-
-EXPORT_SYMBOL(copy_page);
-
-
 static int pref_bias_clear_store __cpuinitdata;
 static int pref_bias_copy_load __cpuinitdata;
 static int pref_bias_copy_store __cpuinitdata;
@@ -282,10 +244,15 @@ static inline void __cpuinit build_clear_pref(u32 **buf, int off)
 		}
 }
 
+extern u32 __clear_page_start;
+extern u32 __clear_page_end;
+extern u32 __copy_page_start;
+extern u32 __copy_page_end;
+
 void __cpuinit build_clear_page(void)
 {
 	int off;
-	u32 *buf = (u32 *)&clear_page_array;
+	u32 *buf = &__clear_page_start;
 	struct uasm_label *l = labels;
 	struct uasm_reloc *r = relocs;
 	int i;
@@ -356,17 +323,17 @@ void __cpuinit build_clear_page(void)
 	uasm_i_jr(&buf, RA);
 	uasm_i_nop(&buf);
 
-	BUG_ON(buf > clear_page_array + ARRAY_SIZE(clear_page_array));
+	BUG_ON(buf > &__clear_page_end);
 
 	uasm_resolve_relocs(relocs, labels);
 
 	pr_debug("Synthesized clear page handler (%u instructions).\n",
-		 (u32)(buf - clear_page_array));
+		 (u32)(buf - &__clear_page_start));
 
 	pr_debug("\t.set push\n");
 	pr_debug("\t.set noreorder\n");
-	for (i = 0; i < (buf - clear_page_array); i++)
-		pr_debug("\t.word 0x%08x\n", clear_page_array[i]);
+	for (i = 0; i < (buf - &__clear_page_start); i++)
+		pr_debug("\t.word 0x%08x\n", (&__clear_page_start)[i]);
 	pr_debug("\t.set pop\n");
 }
 
@@ -427,7 +394,7 @@ static inline void build_copy_store_pref(u32 **buf, int off)
 void __cpuinit build_copy_page(void)
 {
 	int off;
-	u32 *buf = (u32 *)&copy_page_array;
+	u32 *buf = &__copy_page_start;
 	struct uasm_label *l = labels;
 	struct uasm_reloc *r = relocs;
 	int i;
@@ -595,21 +562,23 @@ void __cpuinit build_copy_page(void)
 	uasm_i_jr(&buf, RA);
 	uasm_i_nop(&buf);
 
-	BUG_ON(buf > copy_page_array + ARRAY_SIZE(copy_page_array));
+	BUG_ON(buf > &__copy_page_end);
 
 	uasm_resolve_relocs(relocs, labels);
 
 	pr_debug("Synthesized copy page handler (%u instructions).\n",
-		 (u32)(buf - copy_page_array));
+		 (u32)(buf - &__copy_page_start));
 
 	pr_debug("\t.set push\n");
 	pr_debug("\t.set noreorder\n");
-	for (i = 0; i < (buf - copy_page_array); i++)
-		pr_debug("\t.word 0x%08x\n", copy_page_array[i]);
+	for (i = 0; i < (buf - &__copy_page_start); i++)
+		pr_debug("\t.word 0x%08x\n", (&__copy_page_start)[i]);
 	pr_debug("\t.set pop\n");
 }
 
 #ifdef CONFIG_SIBYTE_DMA_PAGEOPS
+extern void clear_page_cpu(void *page);
+extern void copy_page_cpu(void *to, void *from);
 
 /*
  * Pad descriptors to cacheline, since each is exclusively owned by a
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 0bc485b..03eb0ef 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -9,6 +9,7 @@
  * Copyright (C) 2005, 2007, 2008, 2009  Maciej W. Rozycki
  * Copyright (C) 2006  Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 2008, 2009 Cavium Networks, Inc.
+ * Copyright (C) 2011  MIPS Technologies, Inc.
  *
  * ... and the days got worse and worse and now you see
  * I've gone completly out of my mind.
@@ -494,6 +495,7 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
 	case CPU_R14000:
 	case CPU_4KC:
 	case CPU_4KEC:
+	case CPU_M14KC:
 	case CPU_SB1:
 	case CPU_SB1A:
 	case CPU_4KSC:
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c
index 5fa1851..64a28e8 100644
--- a/arch/mips/mm/uasm.c
+++ b/arch/mips/mm/uasm.c
@@ -58,18 +58,16 @@ enum fields {
 
 enum opcode {
 	insn_invalid,
-	insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
-	insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
-	insn_bne, insn_cache, insn_daddu, insn_daddiu, insn_dmfc0,
-	insn_dmtc0, insn_dsll, insn_dsll32, insn_dsra, insn_dsrl,
-	insn_dsrl32, insn_drotr, insn_drotr32, insn_dsubu, insn_eret,
-	insn_j, insn_jal, insn_jr, insn_ld, insn_ll, insn_lld,
-	insn_lui, insn_lw, insn_mfc0, insn_mtc0, insn_or, insn_ori,
-	insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
-	insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp,
+	insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1,
+	insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
+	insn_bne, insn_cache, insn_daddiu, insn_daddu, insn_dins, insn_dinsm,
+	insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll,
+	insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret,
+	insn_j, insn_jal, insn_jr, insn_ld, insn_ldx, insn_ll, insn_lld,
+	insn_lui, insn_lw, insn_lwx, insn_mfc0, insn_mtc0, insn_or, insn_ori,
+	insn_pref, insn_rfe, insn_rotr, insn_sc, insn_scd, insn_sd, insn_sll,
+	insn_sra, insn_srl, insn_subu, insn_sw, insn_syscall, insn_tlbp,
 	insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori,
-	insn_dins, insn_dinsm, insn_syscall, insn_bbit0, insn_bbit1,
-	insn_lwx, insn_ldx
 };
 
 struct insn {
@@ -90,65 +88,65 @@ struct insn {
 static struct insn insn_table[] __uasminitdata = {
 	{ insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
 	{ insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
-	{ insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
 	{ insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
-	{ insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+	{ insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
+	{ insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+	{ insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
 	{ insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-	{ insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
+	{ insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
 	{ insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
-	{ insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
+	{ insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
 	{ insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
+	{ insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
 	{ insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
 	{ insn_cache,  M(cache_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
 	{ insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
 	{ insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
+	{ insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
+	{ insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
 	{ insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
 	{ insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
-	{ insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
+	{ insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE },
+	{ insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE },
 	{ insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
+	{ insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
 	{ insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
-	{ insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
 	{ insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
-	{ insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE },
-	{ insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE },
+	{ insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
 	{ insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
 	{ insn_eret,  M(cop0_op, cop_op, 0, 0, 0, eret_op),  0 },
-	{ insn_j,  M(j_op, 0, 0, 0, 0, 0),  JIMM },
 	{ insn_jal,  M(jal_op, 0, 0, 0, 0, 0),  JIMM },
+	{ insn_j,  M(j_op, 0, 0, 0, 0, 0),  JIMM },
 	{ insn_jr,  M(spec_op, 0, 0, 0, 0, jr_op),  RS },
 	{ insn_ld,  M(ld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-	{ insn_ll,  M(ll_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+	{ insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
 	{ insn_lld,  M(lld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+	{ insn_ll,  M(ll_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
 	{ insn_lui,  M(lui_op, 0, 0, 0, 0, 0),  RT | SIMM },
 	{ insn_lw,  M(lw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+	{ insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
 	{ insn_mfc0,  M(cop0_op, mfc_op, 0, 0, 0, 0),  RT | RD | SET},
 	{ insn_mtc0,  M(cop0_op, mtc_op, 0, 0, 0, 0),  RT | RD | SET},
-	{ insn_or,  M(spec_op, 0, 0, 0, 0, or_op),  RS | RT | RD },
 	{ insn_ori,  M(ori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
+	{ insn_or,  M(spec_op, 0, 0, 0, 0, or_op),  RS | RT | RD },
 	{ insn_pref,  M(pref_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
 	{ insn_rfe,  M(cop0_op, cop_op, 0, 0, 0, rfe_op),  0 },
-	{ insn_sc,  M(sc_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+	{ insn_rotr,  M(spec_op, 1, 0, 0, 0, srl_op),  RT | RD | RE },
 	{ insn_scd,  M(scd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+	{ insn_sc,  M(sc_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
 	{ insn_sd,  M(sd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
 	{ insn_sll,  M(spec_op, 0, 0, 0, 0, sll_op),  RT | RD | RE },
 	{ insn_sra,  M(spec_op, 0, 0, 0, 0, sra_op),  RT | RD | RE },
 	{ insn_srl,  M(spec_op, 0, 0, 0, 0, srl_op),  RT | RD | RE },
-	{ insn_rotr,  M(spec_op, 1, 0, 0, 0, srl_op),  RT | RD | RE },
 	{ insn_subu,  M(spec_op, 0, 0, 0, 0, subu_op),  RS | RT | RD },
 	{ insn_sw,  M(sw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+	{ insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
 	{ insn_tlbp,  M(cop0_op, cop_op, 0, 0, 0, tlbp_op),  0 },
 	{ insn_tlbr,  M(cop0_op, cop_op, 0, 0, 0, tlbr_op),  0 },
 	{ insn_tlbwi,  M(cop0_op, cop_op, 0, 0, 0, tlbwi_op),  0 },
 	{ insn_tlbwr,  M(cop0_op, cop_op, 0, 0, 0, tlbwr_op),  0 },
-	{ insn_xor,  M(spec_op, 0, 0, 0, 0, xor_op),  RS | RT | RD },
 	{ insn_xori,  M(xori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
-	{ insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
-	{ insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
-	{ insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
-	{ insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-	{ insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-	{ insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
-	{ insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
+	{ insn_xor,  M(spec_op, 0, 0, 0, 0, xor_op),  RS | RT | RD },
 	{ insn_invalid, 0, 0 }
 };
 
diff --git a/arch/mips/mti-malta/malta-pci.c b/arch/mips/mti-malta/malta-pci.c
index bf80921..284dea5 100644
--- a/arch/mips/mti-malta/malta-pci.c
+++ b/arch/mips/mti-malta/malta-pci.c
@@ -241,8 +241,9 @@ void __init mips_pcibios_init(void)
 		return;
 	}
 
-	if (controller->io_resource->start < 0x00001000UL)	/* FIXME */
-		controller->io_resource->start = 0x00001000UL;
+	/* Change start address to avoid conflicts with ACPI and SMB devices */
+	if (controller->io_resource->start < 0x00002000UL)
+		controller->io_resource->start = 0x00002000UL;
 
 	iomem_resource.end &= 0xfffffffffULL;			/* 64 GB */
 	ioport_resource.end = controller->io_resource->end;
@@ -253,7 +254,7 @@ void __init mips_pcibios_init(void)
 }
 
 /* Enable PCI 2.1 compatibility in PIIX4 */
-static void __init quirk_dlcsetup(struct pci_dev *dev)
+static void __devinit quirk_dlcsetup(struct pci_dev *dev)
 {
 	u8 odlc, ndlc;
 	(void) pci_read_config_byte(dev, 0x82, &odlc);
diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c
index b7f37d4..2e28f65 100644
--- a/arch/mips/mti-malta/malta-setup.c
+++ b/arch/mips/mti-malta/malta-setup.c
@@ -111,7 +111,7 @@ static void __init pci_clock_check(void)
 	unsigned int __iomem *jmpr_p =
 		(unsigned int *) ioremap(MALTA_JMPRS_REG, sizeof(unsigned int));
 	int jmpr = (__raw_readl(jmpr_p) >> 2) & 0x07;
-	static const int pciclocks[] __initdata = {
+	static const int pciclocks[] __initconst = {
 		33, 20, 25, 30, 12, 16, 37, 10
 	};
 	int pciclock = pciclocks[jmpr];
diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S
index c138b1a..a58f498 100644
--- a/arch/mips/netlogic/common/smpboot.S
+++ b/arch/mips/netlogic/common/smpboot.S
@@ -54,28 +54,67 @@
 			XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + \
 			SYS_CPU_NONCOHERENT_MODE * 4
 
-.macro __config_lsu
-	li      t0, LSU_DEFEATURE
-	mfcr    t1, t0
+#define	XLP_AX_WORKAROUND	/* enable Ax silicon workarounds */
 
-	lui     t2, 0x4080  /* Enable Unaligned Access, L2HPE */
-	or      t1, t1, t2
-	li	t2, ~0xe    /* S1RCM */
+/* Enable XLP features and workarounds in the LSU */
+.macro xlp_config_lsu
+	li	t0, LSU_DEFEATURE
+	mfcr	t1, t0
+
+	lui	t2, 0x4080	/* Enable Unaligned Access, L2HPE */
+	or	t1, t1, t2
+#ifdef XLP_AX_WORKAROUND
+	li	t2, ~0xe	/* S1RCM */
 	and	t1, t1, t2
+#endif
 	mtcr    t1, t0
 
-	li      t0, SCHED_DEFEATURE
-	lui     t1, 0x0100  /* Experimental: Disable BRU accepting ALU ops */
-	mtcr    t1, t0
+#ifdef XLP_AX_WORKAROUND
+	li	t0, SCHED_DEFEATURE
+	lui	t1, 0x0100	/* Disable BRU accepting ALU ops */
+	mtcr	t1, t0
+#endif
+.endm
+
+/*
+ * Low level L1 d-cache flush for core, needs to be called before
+ * threads are enabled
+ */
+.macro	xlp_flush_l1_dcache
+	li	t0, LSU_DEBUG_DATA0
+	li      t1, LSU_DEBUG_ADDR
+	li	t2, 0		/* index */
+	li 	t3, 0x200	/* loop count, 512 sets */
+1:
+	sll	v0, t2, 5
+	mtcr	zero, t0
+	ori	v1, v0, 0x3	/* way0 | write_enable | write_active */
+	mtcr	v1, t1
+2:
+	mfcr	v1, t1
+	andi	v1, 0x1		/* wait for write_active == 0 */
+	bnez	v1, 2b
+	nop
+	mtcr    zero, t0
+	ori	v1, v0, 0x7	/* way1 | write_enable | write_active */
+	mtcr    v1, t1
+3:
+	mfcr    v1, t1
+	andi    v1, 0x1		/* wait for write_active == 0 */
+	bnez    v1, 3b
+	nop
+	addi	t2, 1
+	bne	t3, t2, 1b
+	nop
 .endm
 
 /*
  * The cores can come start when they are woken up. This is also the NMI
  * entry, so check that first.
  *
- * The data corresponding to reset is stored at RESET_DATA_PHYS location,
- * this will have the thread mask (used when core is woken up) and the
- * current NMI handler in case we reached here for an NMI.
+ * The data corresponding to reset/NMI is stored at RESET_DATA_PHYS
+ * location, this will have the thread mask (used when core is woken up)
+ * and the current NMI handler in case we reached here for an NMI.
  *
  * When a core or thread is newly woken up, it loops in a 'wait'. When
  * the CPU really needs waking up, we send an NMI to it, with the NMI
@@ -89,12 +128,12 @@
 FEXPORT(nlm_reset_entry)
 	dmtc0	k0, $22, 6
 	dmtc0	k1, $22, 7
-	mfc0    k0, CP0_STATUS
-	li      k1, 0x80000
-	and     k1, k0, k1
-	beqz    k1, 1f         /* go to real reset entry */
+	mfc0	k0, CP0_STATUS
+	li	k1, 0x80000
+	and	k1, k0, k1
+	beqz	k1, 1f		/* go to real reset entry */
 	nop
-	li	k1, CKSEG1ADDR(RESET_DATA_PHYS)   /* NMI */
+	li	k1, CKSEG1ADDR(RESET_DATA_PHYS)	/* NMI */
 	ld	k0, BOOT_NMI_HANDLER(k1)
 	jr	k0
 	nop
@@ -114,21 +153,24 @@ FEXPORT(nlm_reset_entry)
 	li	t2, SYS_CPU_COHERENT_BASE(0)
 	add	t2, t2, t3		/* t2 <- SYS offset for node */
 	lw	t1, 0(t2)
-	and     t1, t1, t0
-	sw      t1, 0(t2)
+	and	t1, t1, t0
+	sw	t1, 0(t2)
 
 	/* read back to ensure complete */
-	lw      t1, 0(t2)
+	lw	t1, 0(t2)
 	sync
 
 	/* Configure LSU on Non-0 Cores. */
-	__config_lsu
+	xlp_config_lsu
+	/* FALL THROUGH */
 
 /*
  * Wake up sibling threads from the initial thread in
  * a core.
  */
 EXPORT(nlm_boot_siblings)
+	/* core L1D flush before enable threads */
+	xlp_flush_l1_dcache
 	li	t0, CKSEG1ADDR(RESET_DATA_PHYS)
 	lw	t1, BOOT_THREAD_MODE(t0)	/* t1 <- thread mode */
 	li	t0, ((CPU_BLOCKID_MAP << 8) | MAP_THREADMODE)
@@ -139,13 +181,14 @@ EXPORT(nlm_boot_siblings)
 	/*
 	 * The new hardware thread starts at the next instruction
 	 * For all the cases other than core 0 thread 0, we will
-         * jump to the secondary wait function.
-         */
+	* jump to the secondary wait function.
+	*/
 	mfc0	v0, CP0_EBASE, 1
 	andi	v0, 0x7f		/* v0 <- node/core */
 
-#if 1
-	/* A0 errata - Write MMU_SETUP after changing thread mode register. */
+	/* Init MMU in the first thread after changing THREAD_MODE
+	 * register (Ax Errata?)
+	 */
 	andi	v1, v0, 0x3		/* v1 <- thread id */
 	bnez	v1, 2f
 	nop
@@ -153,17 +196,13 @@ EXPORT(nlm_boot_siblings)
         li	t0, MMU_SETUP
         li	t1, 0
         mtcr	t1, t0
-	ehb
-#endif
+	_ehb
 
-2:	beqz	v0, 4f
+2:	beqz	v0, 4f		/* boot cpu (cpuid == 0)? */
 	nop
 
 	/* setup status reg */
-	mfc0	t1, CP0_STATUS
-	li	t0, ST0_BEV
-	or	t1, t0
-	xor	t1, t0
+	move	t1, zero
 #ifdef CONFIG_64BIT
 	ori	t1, ST0_KX
 #endif
@@ -183,9 +222,9 @@ EXPORT(nlm_boot_siblings)
 	 * For the boot CPU, we have to restore registers and
 	 * return
 	 */
-4:	dmfc0	t0, $4, 2       /* restore SP from UserLocal */
+4:	dmfc0	t0, $4, 2	/* restore SP from UserLocal */
 	li	t1, 0xfadebeef
-	dmtc0	t1, $4, 2       /* restore SP from UserLocal */
+	dmtc0	t1, $4, 2	/* restore SP from UserLocal */
 	PTR_SUBU sp, t0, PT_SIZE
 	RESTORE_ALL
 	jr   ra
@@ -193,7 +232,7 @@ EXPORT(nlm_boot_siblings)
 EXPORT(nlm_reset_entry_end)
 
 FEXPORT(xlp_boot_core0_siblings)	/* "Master" cpu starts from here */
-	__config_lsu
+	xlp_config_lsu
 	dmtc0   sp, $4, 2		/* SP saved in UserLocal */
 	SAVE_ALL
 	sync
@@ -210,6 +249,12 @@ FEXPORT(xlp_boot_core0_siblings)	/* "Master" cpu starts from here */
 
 	__CPUINIT
 NESTED(nlm_boot_secondary_cpus, 16, sp)
+	/* Initialize CP0 Status */
+	move	t1, zero
+#ifdef CONFIG_64BIT
+	ori	t1, ST0_KX
+#endif
+	mtc0	t1, CP0_STATUS
 	PTR_LA	t1, nlm_next_sp
 	PTR_L	sp, 0(t1)
 	PTR_LA	t1, nlm_next_gp
@@ -234,36 +279,36 @@ END(nlm_boot_secondary_cpus)
  */
 	__CPUINIT
 NESTED(nlm_rmiboot_preboot, 16, sp)
-	mfc0	t0, $15, 1	# read ebase
-	andi	t0, 0x1f	# t0 has the processor_id()
-	andi	t2, t0, 0x3	# thread no
-	sll	t0, 2		# offset in cpu array
+	mfc0	t0, $15, 1	/* read ebase */
+	andi	t0, 0x1f	/* t0 has the processor_id() */
+	andi	t2, t0, 0x3	/* thread num */
+	sll	t0, 2		/* offset in cpu array */
 
-	PTR_LA	t1, nlm_cpu_ready # mark CPU ready
+	PTR_LA	t1, nlm_cpu_ready /* mark CPU ready */
 	PTR_ADDU t1, t0
 	li	t3, 1
 	sw	t3, 0(t1)
 
-	bnez	t2, 1f		# skip thread programming
-	nop			# for non zero hw threads
+	bnez	t2, 1f		/* skip thread programming */
+	nop			/* for thread id != 0 */
 
 	/*
-	 * MMU setup only for first thread in core
+	 * XLR MMU setup only for first thread in core
 	 */
 	li	t0, 0x400
 	mfcr	t1, t0
-	li	t2, 6 		# XLR thread mode mask
+	li	t2, 6 		/* XLR thread mode mask */
 	nor	t3, t2, zero
-	and	t2, t1, t2	# t2 - current thread mode
+	and	t2, t1, t2	/* t2 - current thread mode */
 	li	v0, CKSEG1ADDR(RESET_DATA_PHYS)
-	lw	v1, BOOT_THREAD_MODE(v0) # v1 - new thread mode
+	lw	v1, BOOT_THREAD_MODE(v0) /* v1 - new thread mode */
 	sll	v1, 1
-	beq	v1, t2, 1f 	# same as request value
-	nop			# nothing to do */
+	beq	v1, t2, 1f 	/* same as request value */
+	nop			/* nothing to do */
 
-	and	t2, t1, t3	# mask out old thread mode
-	or	t1, t2, v1	# put in new value
-	mtcr	t1, t0		# update core control
+	and	t2, t1, t3	/* mask out old thread mode */
+	or	t1, t2, v1	/* put in new value */
+	mtcr	t1, t0		/* update core control */
 
 1:	wait
 	j	1b
diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile
index b93ed83..5bd24b6 100644
--- a/arch/mips/netlogic/xlp/Makefile
+++ b/arch/mips/netlogic/xlp/Makefile
@@ -1,2 +1,3 @@
 obj-y				+= setup.o platform.o nlm_hal.o
 obj-$(CONFIG_SMP)		+= wakeup.o
+obj-$(CONFIG_USB)		+= usb-init.o
diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c
index 9428e71..6c65ac7 100644
--- a/arch/mips/netlogic/xlp/nlm_hal.c
+++ b/arch/mips/netlogic/xlp/nlm_hal.c
@@ -69,6 +69,32 @@ int nlm_irq_to_irt(int irq)
 		return PIC_IRT_UART_0_INDEX;
 	case PIC_UART_1_IRQ:
 		return PIC_IRT_UART_1_INDEX;
+	case PIC_PCIE_LINK_0_IRQ:
+	       return PIC_IRT_PCIE_LINK_0_INDEX;
+	case PIC_PCIE_LINK_1_IRQ:
+	       return PIC_IRT_PCIE_LINK_1_INDEX;
+	case PIC_PCIE_LINK_2_IRQ:
+	       return PIC_IRT_PCIE_LINK_2_INDEX;
+	case PIC_PCIE_LINK_3_IRQ:
+	       return PIC_IRT_PCIE_LINK_3_INDEX;
+	case PIC_EHCI_0_IRQ:
+	       return PIC_IRT_EHCI_0_INDEX;
+	case PIC_EHCI_1_IRQ:
+	       return PIC_IRT_EHCI_1_INDEX;
+	case PIC_OHCI_0_IRQ:
+	       return PIC_IRT_OHCI_0_INDEX;
+	case PIC_OHCI_1_IRQ:
+	       return PIC_IRT_OHCI_1_INDEX;
+	case PIC_OHCI_2_IRQ:
+	       return PIC_IRT_OHCI_2_INDEX;
+	case PIC_OHCI_3_IRQ:
+	       return PIC_IRT_OHCI_3_INDEX;
+	case PIC_MMC_IRQ:
+	       return PIC_IRT_MMC_INDEX;
+	case PIC_I2C_0_IRQ:
+		return PIC_IRT_I2C_0_INDEX;
+	case PIC_I2C_1_IRQ:
+		return PIC_IRT_I2C_1_INDEX;
 	default:
 		return -1;
 	}
@@ -81,6 +107,32 @@ int nlm_irt_to_irq(int irt)
 		return PIC_UART_0_IRQ;
 	case PIC_IRT_UART_1_INDEX:
 		return PIC_UART_1_IRQ;
+	case PIC_IRT_PCIE_LINK_0_INDEX:
+	       return PIC_PCIE_LINK_0_IRQ;
+	case PIC_IRT_PCIE_LINK_1_INDEX:
+	       return PIC_PCIE_LINK_1_IRQ;
+	case PIC_IRT_PCIE_LINK_2_INDEX:
+	       return PIC_PCIE_LINK_2_IRQ;
+	case PIC_IRT_PCIE_LINK_3_INDEX:
+	       return PIC_PCIE_LINK_3_IRQ;
+	case PIC_IRT_EHCI_0_INDEX:
+		return PIC_EHCI_0_IRQ;
+	case PIC_IRT_EHCI_1_INDEX:
+		return PIC_EHCI_1_IRQ;
+	case PIC_IRT_OHCI_0_INDEX:
+		return PIC_OHCI_0_IRQ;
+	case PIC_IRT_OHCI_1_INDEX:
+		return PIC_OHCI_1_IRQ;
+	case PIC_IRT_OHCI_2_INDEX:
+		return PIC_OHCI_2_IRQ;
+	case PIC_IRT_OHCI_3_INDEX:
+		return PIC_OHCI_3_IRQ;
+	case PIC_IRT_MMC_INDEX:
+	       return PIC_MMC_IRQ;
+	case PIC_IRT_I2C_0_INDEX:
+		return PIC_I2C_0_IRQ;
+	case PIC_IRT_I2C_1_INDEX:
+		return PIC_I2C_1_IRQ;
 	default:
 		return -1;
 	}
diff --git a/arch/mips/netlogic/xlp/platform.c b/arch/mips/netlogic/xlp/platform.c
index 1f5e4cb..2c510d5 100644
--- a/arch/mips/netlogic/xlp/platform.c
+++ b/arch/mips/netlogic/xlp/platform.c
@@ -53,7 +53,7 @@
 
 static unsigned int nlm_xlp_uart_in(struct uart_port *p, int offset)
 {
-	 return nlm_read_reg(p->iobase, offset);
+	return nlm_read_reg(p->iobase, offset);
 }
 
 static void nlm_xlp_uart_out(struct uart_port *p, int offset, int value)
diff --git a/arch/mips/netlogic/xlp/setup.c b/arch/mips/netlogic/xlp/setup.c
index acb677a..3dec9f2 100644
--- a/arch/mips/netlogic/xlp/setup.c
+++ b/arch/mips/netlogic/xlp/setup.c
@@ -41,6 +41,8 @@
 #include <asm/bootinfo.h>
 
 #include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
 
 #include <asm/netlogic/haldefs.h>
 #include <asm/netlogic/common.h>
@@ -82,8 +84,10 @@ void __init prom_free_prom_memory(void)
 
 void xlp_mmu_init(void)
 {
+	/* enable extended TLB and Large Fixed TLB */
 	write_c0_config6(read_c0_config6() | 0x24);
-	current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1;
+
+	/* set page mask of Fixed TLB in config7 */
 	write_c0_config7(PM_DEFAULT_MASK >>
 		(13 + (ffz(PM_DEFAULT_MASK >> 13) / 2)));
 }
@@ -100,6 +104,24 @@ void __init prom_init(void)
 	nlm_common_ebase = read_c0_ebase() & (~((1 << 12) - 1));
 #ifdef CONFIG_SMP
 	nlm_wakeup_secondary_cpus(0xffffffff);
+
+	/* update TLB size after waking up threads */
+	current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1;
+
 	register_smp_ops(&nlm_smp_ops);
 #endif
 }
+
+static struct of_device_id __initdata xlp_ids[] = {
+	{ .compatible = "simple-bus", },
+	{},
+};
+
+int __init xlp8xx_ds_publish_devices(void)
+{
+	if (!of_have_populated_dt())
+		return 0;
+	return of_platform_bus_probe(NULL, xlp_ids, NULL);
+}
+
+device_initcall(xlp8xx_ds_publish_devices);
diff --git a/arch/mips/netlogic/xlp/usb-init.c b/arch/mips/netlogic/xlp/usb-init.c
new file mode 100644
index 0000000..dbe083a
--- /dev/null
+++ b/arch/mips/netlogic/xlp/usb-init.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * 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 Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/usb.h>
+
+static void nlm_usb_intr_en(int node, int port)
+{
+	uint32_t val;
+	uint64_t port_addr;
+
+	port_addr = nlm_get_usb_regbase(node, port);
+	val = nlm_read_usb_reg(port_addr, USB_INT_EN);
+	val = USB_CTRL_INTERRUPT_EN  | USB_OHCI_INTERRUPT_EN |
+		USB_OHCI_INTERRUPT1_EN | USB_CTRL_INTERRUPT_EN  |
+		USB_OHCI_INTERRUPT_EN | USB_OHCI_INTERRUPT2_EN;
+	nlm_write_usb_reg(port_addr, USB_INT_EN, val);
+}
+
+static void nlm_usb_hw_reset(int node, int port)
+{
+	uint64_t port_addr;
+	uint32_t val;
+
+	/* reset USB phy */
+	port_addr = nlm_get_usb_regbase(node, port);
+	val = nlm_read_usb_reg(port_addr, USB_PHY_0);
+	val &= ~(USB_PHY_RESET | USB_PHY_PORT_RESET_0 | USB_PHY_PORT_RESET_1);
+	nlm_write_usb_reg(port_addr, USB_PHY_0, val);
+
+	mdelay(100);
+	val = nlm_read_usb_reg(port_addr, USB_CTL_0);
+	val &= ~(USB_CONTROLLER_RESET);
+	val |= 0x4;
+	nlm_write_usb_reg(port_addr, USB_CTL_0, val);
+}
+
+static int __init nlm_platform_usb_init(void)
+{
+	pr_info("Initializing USB Interface\n");
+	nlm_usb_hw_reset(0, 0);
+	nlm_usb_hw_reset(0, 3);
+
+	/* Enable PHY interrupts */
+	nlm_usb_intr_en(0, 0);
+	nlm_usb_intr_en(0, 3);
+
+	return 0;
+}
+
+arch_initcall(nlm_platform_usb_init);
+
+static u64 xlp_usb_dmamask = ~(u32)0;
+
+/* Fixup the IRQ for USB devices which is exist on XLP SOC PCIE bus */
+static void nlm_usb_fixup_final(struct pci_dev *dev)
+{
+	dev->dev.dma_mask		= &xlp_usb_dmamask;
+	dev->dev.coherent_dma_mask	= DMA_BIT_MASK(64);
+	switch (dev->devfn) {
+	case 0x10:
+	       dev->irq = PIC_EHCI_0_IRQ;
+	       break;
+	case 0x11:
+	       dev->irq = PIC_OHCI_0_IRQ;
+	       break;
+	case 0x12:
+	       dev->irq = PIC_OHCI_1_IRQ;
+	       break;
+	case 0x13:
+	       dev->irq = PIC_EHCI_1_IRQ;
+	       break;
+	case 0x14:
+	       dev->irq = PIC_OHCI_2_IRQ;
+	       break;
+	case 0x15:
+	       dev->irq = PIC_OHCI_3_IRQ;
+	       break;
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_EHCI,
+		nlm_usb_fixup_final);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_OHCI,
+		nlm_usb_fixup_final);
diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile
index f01e4d7..c287dea 100644
--- a/arch/mips/netlogic/xlr/Makefile
+++ b/arch/mips/netlogic/xlr/Makefile
@@ -1,2 +1,2 @@
-obj-y				+= setup.o platform.o
+obj-y				+= setup.o platform.o platform-flash.o
 obj-$(CONFIG_SMP)		+= wakeup.o
diff --git a/arch/mips/netlogic/xlr/platform-flash.c b/arch/mips/netlogic/xlr/platform-flash.c
new file mode 100644
index 0000000..340ab16
--- /dev/null
+++ b/arch/mips/netlogic/xlr/platform-flash.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2011, Netlogic Microsystems.
+ * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/resource.h>
+#include <linux/spi/flash.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/flash.h>
+#include <asm/netlogic/xlr/bridge.h>
+#include <asm/netlogic/xlr/gpio.h>
+#include <asm/netlogic/xlr/xlr.h>
+
+/*
+ * Default NOR partition layout
+ */
+static struct mtd_partition xlr_nor_parts[] = {
+	{
+		.name = "User FS",
+		.offset = 0x800000,
+		.size   = MTDPART_SIZ_FULL,
+	}
+};
+
+/*
+ * Default NAND partition layout
+ */
+static struct mtd_partition xlr_nand_parts[] = {
+	{
+		.name	= "Root Filesystem",
+		.offset	= 64 * 64 * 2048,
+		.size	= 432 * 64 * 2048,
+	},
+	{
+		.name	= "Home Filesystem",
+		.offset	= MTDPART_OFS_APPEND,
+		.size   = MTDPART_SIZ_FULL,
+	},
+};
+
+/* Use PHYSMAP flash for NOR */
+struct physmap_flash_data xlr_nor_data = {
+	.width		= 2,
+	.parts		= xlr_nor_parts,
+	.nr_parts	= ARRAY_SIZE(xlr_nor_parts),
+};
+
+static struct resource xlr_nor_res[] = {
+	{
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device xlr_nor_dev = {
+	.name	= "physmap-flash",
+	.dev	= {
+		.platform_data	= &xlr_nor_data,
+	},
+	.num_resources  = ARRAY_SIZE(xlr_nor_res),
+	.resource       = xlr_nor_res,
+};
+
+const char *xlr_part_probes[] = { "cmdlinepart", NULL };
+
+/*
+ * Use "gen_nand" driver for NAND flash
+ *
+ * There seems to be no way to store a private pointer containing
+ * platform specific info in gen_nand drivier. We will use a global
+ * struct for now, since we currently have only one NAND chip per board.
+ */
+struct xlr_nand_flash_priv {
+	int cs;
+	uint64_t flash_mmio;
+};
+
+static struct xlr_nand_flash_priv nand_priv;
+
+static void xlr_nand_ctrl(struct mtd_info *mtd, int cmd,
+		unsigned int ctrl)
+{
+	if (ctrl & NAND_CLE)
+		nlm_write_reg(nand_priv.flash_mmio,
+			FLASH_NAND_CLE(nand_priv.cs), cmd);
+	else if (ctrl & NAND_ALE)
+		nlm_write_reg(nand_priv.flash_mmio,
+			FLASH_NAND_ALE(nand_priv.cs), cmd);
+}
+
+struct platform_nand_data xlr_nand_data = {
+	.chip = {
+		.nr_chips	= 1,
+		.nr_partitions	= ARRAY_SIZE(xlr_nand_parts),
+		.chip_delay	= 50,
+		.partitions	= xlr_nand_parts,
+		.part_probe_types = xlr_part_probes,
+	},
+	.ctrl = {
+		.cmd_ctrl	= xlr_nand_ctrl,
+	},
+};
+
+static struct resource xlr_nand_res[] = {
+	{
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device xlr_nand_dev = {
+	.name		= "gen_nand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(xlr_nand_res),
+	.resource	= xlr_nand_res,
+	.dev		= {
+		.platform_data	= &xlr_nand_data,
+	}
+};
+
+/*
+ * XLR/XLS supports upto 8 devices on its FLASH interface. The value in
+ * FLASH_BAR (on the MEM/IO bridge) gives the base for mapping all the
+ * flash devices.
+ * Under this, each flash device has an offset and size given by the
+ * CSBASE_ADDR and CSBASE_MASK registers for the device.
+ *
+ * The CSBASE_ registers are expected to be setup by the bootloader.
+ */
+static void setup_flash_resource(uint64_t flash_mmio,
+	uint64_t flash_map_base, int cs, struct resource *res)
+{
+	u32 base, mask;
+
+	base = nlm_read_reg(flash_mmio, FLASH_CSBASE_ADDR(cs));
+	mask = nlm_read_reg(flash_mmio, FLASH_CSADDR_MASK(cs));
+
+	res->start = flash_map_base + ((unsigned long)base << 16);
+	res->end = res->start + (mask + 1) * 64 * 1024;
+}
+
+static int __init xlr_flash_init(void)
+{
+	uint64_t gpio_mmio, flash_mmio, flash_map_base;
+	u32 gpio_resetcfg, flash_bar;
+	int cs, boot_nand, boot_nor;
+
+	/* Flash address bits 39:24 is in bridge flash BAR */
+	flash_bar = nlm_read_reg(nlm_io_base, BRIDGE_FLASH_BAR);
+	flash_map_base = (flash_bar & 0xffff0000) << 8;
+
+	gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET);
+	flash_mmio = nlm_mmio_base(NETLOGIC_IO_FLASH_OFFSET);
+
+	/* Get the chip reset config */
+	gpio_resetcfg = nlm_read_reg(gpio_mmio, GPIO_PWRON_RESET_CFG_REG);
+
+	/* Check for boot flash type */
+	boot_nor = boot_nand = 0;
+	if (nlm_chip_is_xls()) {
+		/* On XLS, check boot from NAND bit (GPIO reset reg bit 16) */
+		if (gpio_resetcfg & (1 << 16))
+			boot_nand = 1;
+
+		/* check boot from PCMCIA, (GPIO reset reg bit 15 */
+		if ((gpio_resetcfg & (1 << 15)) == 0)
+			boot_nor = 1;	/* not set, booted from NOR */
+	} else { /* XLR */
+		/* check boot from PCMCIA (bit 16 in GPIO reset on XLR) */
+		if ((gpio_resetcfg & (1 << 16)) == 0)
+			boot_nor = 1;	/* not set, booted from NOR */
+	}
+
+	/* boot flash at chip select 0 */
+	cs = 0;
+
+	if (boot_nand) {
+		nand_priv.cs = cs;
+		nand_priv.flash_mmio = flash_mmio;
+		setup_flash_resource(flash_mmio, flash_map_base, cs,
+			 xlr_nand_res);
+
+		/* Initialize NAND flash at CS 0 */
+		nlm_write_reg(flash_mmio, FLASH_CSDEV_PARM(cs),
+				FLASH_NAND_CSDEV_PARAM);
+		nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMA(cs),
+				FLASH_NAND_CSTIME_PARAMA);
+		nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMB(cs),
+				FLASH_NAND_CSTIME_PARAMB);
+
+		pr_info("ChipSelect %d: NAND Flash %pR\n", cs, xlr_nand_res);
+		return platform_device_register(&xlr_nand_dev);
+	}
+
+	if (boot_nor) {
+		setup_flash_resource(flash_mmio, flash_map_base, cs,
+			xlr_nor_res);
+		pr_info("ChipSelect %d: NOR Flash %pR\n", cs, xlr_nor_res);
+		return platform_device_register(&xlr_nor_dev);
+	}
+	return 0;
+}
+
+arch_initcall(xlr_flash_init);
diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c
index eab64b4..71b44d8 100644
--- a/arch/mips/netlogic/xlr/platform.c
+++ b/arch/mips/netlogic/xlr/platform.c
@@ -14,6 +14,7 @@
 #include <linux/resource.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
+#include <linux/i2c.h>
 
 #include <asm/netlogic/haldefs.h>
 #include <asm/netlogic/xlr/iomap.h>
@@ -97,3 +98,142 @@ static int __init nlm_uart_init(void)
 }
 
 arch_initcall(nlm_uart_init);
+
+#ifdef CONFIG_USB
+/* Platform USB devices, only on XLS chips */
+static u64 xls_usb_dmamask = ~(u32)0;
+#define USB_PLATFORM_DEV(n, i, irq)					\
+	{								\
+		.name		= n,					\
+		.id		= i,					\
+		.num_resources	= 2,					\
+		.dev		= {					\
+			.dma_mask	= &xls_usb_dmamask,		\
+			.coherent_dma_mask = 0xffffffff,		\
+		},							\
+		.resource	= (struct resource[]) {			\
+			{						\
+				.flags = IORESOURCE_MEM,		\
+			},						\
+			{						\
+				.start	= irq,				\
+				.end	= irq,				\
+				.flags = IORESOURCE_IRQ,		\
+			},						\
+		},							\
+	}
+
+static struct platform_device xls_usb_ehci_device =
+			 USB_PLATFORM_DEV("ehci-xls", 0, PIC_USB_IRQ);
+static struct platform_device xls_usb_ohci_device_0 =
+			 USB_PLATFORM_DEV("ohci-xls-0", 1, PIC_USB_IRQ);
+static struct platform_device xls_usb_ohci_device_1 =
+			 USB_PLATFORM_DEV("ohci-xls-1", 2, PIC_USB_IRQ);
+
+static struct platform_device *xls_platform_devices[] = {
+	&xls_usb_ehci_device,
+	&xls_usb_ohci_device_0,
+	&xls_usb_ohci_device_1,
+};
+
+int xls_platform_usb_init(void)
+{
+	uint64_t usb_mmio, gpio_mmio;
+	unsigned long memres;
+	uint32_t val;
+
+	if (!nlm_chip_is_xls())
+		return 0;
+
+	gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET);
+	usb_mmio  = nlm_mmio_base(NETLOGIC_IO_USB_1_OFFSET);
+
+	/* Clear Rogue Phy INTs */
+	nlm_write_reg(usb_mmio, 49, 0x10000000);
+	/* Enable all interrupts */
+	nlm_write_reg(usb_mmio, 50, 0x1f000000);
+
+	/* Enable ports */
+	nlm_write_reg(usb_mmio,  1, 0x07000500);
+
+	val = nlm_read_reg(gpio_mmio, 21);
+	if (((val >> 22) & 0x01) == 0) {
+		pr_info("Detected USB Device mode - Not supported!\n");
+		nlm_write_reg(usb_mmio,  0, 0x01000000);
+		return 0;
+	}
+
+	pr_info("Detected USB Host mode - Adding XLS USB devices.\n");
+	/* Clear reset, host mode */
+	nlm_write_reg(usb_mmio,  0, 0x02000000);
+
+	/* Memory resource for various XLS usb ports */
+	usb_mmio = nlm_mmio_base(NETLOGIC_IO_USB_0_OFFSET);
+	memres = CPHYSADDR((unsigned long)usb_mmio);
+	xls_usb_ehci_device.resource[0].start = memres;
+	xls_usb_ehci_device.resource[0].end = memres + 0x400 - 1;
+
+	memres += 0x400;
+	xls_usb_ohci_device_0.resource[0].start = memres;
+	xls_usb_ohci_device_0.resource[0].end = memres + 0x400 - 1;
+
+	memres += 0x400;
+	xls_usb_ohci_device_1.resource[0].start = memres;
+	xls_usb_ohci_device_1.resource[0].end = memres + 0x400 - 1;
+
+	return platform_add_devices(xls_platform_devices,
+				ARRAY_SIZE(xls_platform_devices));
+}
+
+arch_initcall(xls_platform_usb_init);
+#endif
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info nlm_i2c_board_info1[] __initdata = {
+	/* All XLR boards have this RTC and Max6657 Temp Chip */
+	[0] = {
+		.type	= "ds1374",
+		.addr	= 0x68
+	},
+	[1] = {
+		.type	= "lm90",
+		.addr	= 0x4c
+	},
+};
+
+static struct resource i2c_resources[] = {
+	[0] = {
+		.start	= 0,	/* filled at init */
+		.end	= 0,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device nlm_xlr_i2c_1 = {
+	.name           = "xlr-i2cbus",
+	.id             = 1,
+	.num_resources	= 1,
+	.resource	= i2c_resources,
+};
+
+static int __init nlm_i2c_init(void)
+{
+	int err = 0;
+	unsigned int offset;
+
+	/* I2C bus 0 does not have any useful devices, configure only bus 1 */
+	offset = NETLOGIC_IO_I2C_1_OFFSET;
+	nlm_xlr_i2c_1.resource[0].start = CPHYSADDR(nlm_mmio_base(offset));
+	nlm_xlr_i2c_1.resource[0].end = nlm_xlr_i2c_1.resource[0].start + 0xfff;
+
+	platform_device_register(&nlm_xlr_i2c_1);
+
+	err = i2c_register_board_info(1, nlm_i2c_board_info1,
+				ARRAY_SIZE(nlm_i2c_board_info1));
+	if (err < 0)
+		pr_err("nlm-i2c: cannot register board I2C devices\n");
+	return err;
+}
+
+arch_initcall(nlm_i2c_init);
+#endif
diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c
index c9d066d..81b1d31 100644
--- a/arch/mips/netlogic/xlr/setup.c
+++ b/arch/mips/netlogic/xlr/setup.c
@@ -85,7 +85,7 @@ static void nlm_linux_exit(void)
 
 	gpiobase = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET);
 	/* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */
-	nlm_write_reg(gpiobase, NETLOGIC_GPIO_SWRESET_REG, 1);
+	nlm_write_reg(gpiobase, GPIO_SWRESET_REG, 1);
 	for ( ; ; )
 		cpu_wait();
 }
diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c
index d1f2d4c..f80480a 100644
--- a/arch/mips/oprofile/common.c
+++ b/arch/mips/oprofile/common.c
@@ -78,12 +78,14 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
 
 	switch (current_cpu_type()) {
 	case CPU_5KC:
+	case CPU_M14KC:
 	case CPU_20KC:
 	case CPU_24K:
 	case CPU_25KF:
 	case CPU_34K:
 	case CPU_1004K:
 	case CPU_74K:
+	case CPU_LOONGSON1:
 	case CPU_SB1:
 	case CPU_SB1A:
 	case CPU_R10000:
diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
index baba3bc..28ea1a4 100644
--- a/arch/mips/oprofile/op_model_mipsxx.c
+++ b/arch/mips/oprofile/op_model_mipsxx.c
@@ -322,6 +322,10 @@ static int __init mipsxx_init(void)
 
 	op_model_mipsxx_ops.num_counters = counters;
 	switch (current_cpu_type()) {
+	case CPU_M14KC:
+		op_model_mipsxx_ops.cpu_type = "mips/M14Kc";
+		break;
+
 	case CPU_20KC:
 		op_model_mipsxx_ops.cpu_type = "mips/20K";
 		break;
@@ -335,12 +339,6 @@ static int __init mipsxx_init(void)
 		break;
 
 	case CPU_1004K:
-#if 0
-		/* FIXME: report as 34K for now */
-		op_model_mipsxx_ops.cpu_type = "mips/1004K";
-		break;
-#endif
-
 	case CPU_34K:
 		op_model_mipsxx_ops.cpu_type = "mips/34K";
 		break;
@@ -370,6 +368,10 @@ static int __init mipsxx_init(void)
 		op_model_mipsxx_ops.cpu_type = "mips/sb1";
 		break;
 
+	case CPU_LOONGSON1:
+		op_model_mipsxx_ops.cpu_type = "mips/loongson1";
+		break;
+
 	default:
 		printk(KERN_ERR "Profiling unsupported for this CPU\n");
 
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index c703f43..e13a71c 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_WR_PPMC)		+= fixup-wrppmc.o
 obj-$(CONFIG_MIKROTIK_RB532)	+= pci-rc32434.o ops-rc32434.o fixup-rc32434.o
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)	+= pci-octeon.o pcie-octeon.o
 obj-$(CONFIG_CPU_XLR)		+= pci-xlr.o
+obj-$(CONFIG_CPU_XLP)		+= pci-xlp.o
 
 ifdef CONFIG_PCI_MSI
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)	+= msi-octeon.o
diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c
index 9553b14..3e7ce65 100644
--- a/arch/mips/pci/fixup-cobalt.c
+++ b/arch/mips/pci/fixup-cobalt.c
@@ -37,7 +37,7 @@
 #define VIA_COBALT_BRD_ID_REG  0x94
 #define VIA_COBALT_BRD_REG_to_ID(reg)	((unsigned char)(reg) >> 4)
 
-static void qube_raq_galileo_early_fixup(struct pci_dev *dev)
+static void __devinit qube_raq_galileo_early_fixup(struct pci_dev *dev)
 {
 	if (dev->devfn == PCI_DEVFN(0, 0) &&
 		(dev->class >> 8) == PCI_CLASS_MEMORY_OTHER) {
@@ -51,7 +51,7 @@ static void qube_raq_galileo_early_fixup(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
 	 qube_raq_galileo_early_fixup);
 
-static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
+static void __devinit qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
 {
 	unsigned short cfgword;
 	unsigned char lt;
@@ -74,7 +74,7 @@ static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,
 	 qube_raq_via_bmIDE_fixup);
 
-static void qube_raq_galileo_fixup(struct pci_dev *dev)
+static void __devinit qube_raq_galileo_fixup(struct pci_dev *dev)
 {
 	if (dev->devfn != PCI_DEVFN(0, 0))
 		return;
@@ -129,7 +129,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
 
 int cobalt_board_id;
 
-static void qube_raq_via_board_id_fixup(struct pci_dev *dev)
+static void __devinit qube_raq_via_board_id_fixup(struct pci_dev *dev)
 {
 	u8 id;
 	int retval;
diff --git a/arch/mips/pci/fixup-fuloong2e.c b/arch/mips/pci/fixup-fuloong2e.c
index d5d4c01..0857ab8 100644
--- a/arch/mips/pci/fixup-fuloong2e.c
+++ b/arch/mips/pci/fixup-fuloong2e.c
@@ -48,7 +48,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 	return 0;
 }
 
-static void __init loongson2e_nec_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_nec_fixup(struct pci_dev *pdev)
 {
 	unsigned int val;
 
@@ -60,7 +60,7 @@ static void __init loongson2e_nec_fixup(struct pci_dev *pdev)
 	pci_write_config_dword(pdev, 0xe4, 1 << 5);
 }
 
-static void __init loongson2e_686b_func0_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func0_fixup(struct pci_dev *pdev)
 {
 	unsigned char c;
 
@@ -135,7 +135,7 @@ static void __init loongson2e_686b_func0_fixup(struct pci_dev *pdev)
 	printk(KERN_INFO"via686b fix: ISA bridge done\n");
 }
 
-static void __init loongson2e_686b_func1_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func1_fixup(struct pci_dev *pdev)
 {
 	printk(KERN_INFO"via686b fix: IDE\n");
 
@@ -168,19 +168,19 @@ static void __init loongson2e_686b_func1_fixup(struct pci_dev *pdev)
 	printk(KERN_INFO"via686b fix: IDE done\n");
 }
 
-static void __init loongson2e_686b_func2_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func2_fixup(struct pci_dev *pdev)
 {
 	/* irq routing */
 	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, 10);
 }
 
-static void __init loongson2e_686b_func3_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func3_fixup(struct pci_dev *pdev)
 {
 	/* irq routing */
 	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, 11);
 }
 
-static void __init loongson2e_686b_func5_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func5_fixup(struct pci_dev *pdev)
 {
 	unsigned int val;
 	unsigned char c;
diff --git a/arch/mips/pci/fixup-lemote2f.c b/arch/mips/pci/fixup-lemote2f.c
index 4b9768d..a7b917dcf 100644
--- a/arch/mips/pci/fixup-lemote2f.c
+++ b/arch/mips/pci/fixup-lemote2f.c
@@ -96,21 +96,21 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 }
 
 /* CS5536 SPEC. fixup */
-static void __init loongson_cs5536_isa_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_isa_fixup(struct pci_dev *pdev)
 {
 	/* the uart1 and uart2 interrupt in PIC is enabled as default */
 	pci_write_config_dword(pdev, PCI_UART1_INT_REG, 1);
 	pci_write_config_dword(pdev, PCI_UART2_INT_REG, 1);
 }
 
-static void __init loongson_cs5536_ide_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_ide_fixup(struct pci_dev *pdev)
 {
 	/* setting the mutex pin as IDE function */
 	pci_write_config_dword(pdev, PCI_IDE_CFG_REG,
 			       CS5536_IDE_FLASH_SIGNATURE);
 }
 
-static void __init loongson_cs5536_acc_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_acc_fixup(struct pci_dev *pdev)
 {
 	/* enable the AUDIO interrupt in PIC  */
 	pci_write_config_dword(pdev, PCI_ACC_INT_REG, 1);
@@ -118,14 +118,14 @@ static void __init loongson_cs5536_acc_fixup(struct pci_dev *pdev)
 	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xc0);
 }
 
-static void __init loongson_cs5536_ohci_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_ohci_fixup(struct pci_dev *pdev)
 {
 	/* enable the OHCI interrupt in PIC */
 	/* THE OHCI, EHCI, UDC, OTG are shared with interrupt in PIC */
 	pci_write_config_dword(pdev, PCI_OHCI_INT_REG, 1);
 }
 
-static void __init loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
 {
 	u32 hi, lo;
 
@@ -137,7 +137,7 @@ static void __init loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
 	pci_write_config_dword(pdev, PCI_EHCI_FLADJ_REG, 0x2000);
 }
 
-static void __init loongson_nec_fixup(struct pci_dev *pdev)
+static void __devinit loongson_nec_fixup(struct pci_dev *pdev)
 {
 	unsigned int val;
 
diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c
index 0f48498..4d2c7ff 100644
--- a/arch/mips/pci/fixup-malta.c
+++ b/arch/mips/pci/fixup-malta.c
@@ -49,7 +49,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 	return 0;
 }
 
-static void __init malta_piix_func0_fixup(struct pci_dev *pdev)
+static void __devinit malta_piix_func0_fixup(struct pci_dev *pdev)
 {
 	unsigned char reg_val;
 	static int piixirqmap[16] __initdata = {  /* PIIX PIRQC[A:D] irq mappings */
@@ -83,7 +83,7 @@ static void __init malta_piix_func0_fixup(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
 	 malta_piix_func0_fixup);
 
-static void __init malta_piix_func1_fixup(struct pci_dev *pdev)
+static void __devinit malta_piix_func1_fixup(struct pci_dev *pdev)
 {
 	unsigned char reg_val;
 
@@ -101,3 +101,17 @@ static void __init malta_piix_func1_fixup(struct pci_dev *pdev)
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
 	 malta_piix_func1_fixup);
+
+/* Enable PCI 2.1 compatibility in PIIX4 */
+static void __devinit quirk_dlcsetup(struct pci_dev *dev)
+{
+	u8 odlc, ndlc;
+
+	(void) pci_read_config_byte(dev, 0x82, &odlc);
+	/* Enable passive releases and delayed transaction */
+	ndlc = odlc | 7;
+	(void) pci_write_config_byte(dev, 0x82, ndlc);
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
+	quirk_dlcsetup);
diff --git a/arch/mips/pci/fixup-mpc30x.c b/arch/mips/pci/fixup-mpc30x.c
index e08f49c..8e4f828 100644
--- a/arch/mips/pci/fixup-mpc30x.c
+++ b/arch/mips/pci/fixup-mpc30x.c
@@ -22,13 +22,13 @@
 
 #include <asm/vr41xx/mpc30x.h>
 
-static const int internal_func_irqs[] __initdata = {
+static const int internal_func_irqs[] __initconst = {
 	VRC4173_CASCADE_IRQ,
 	VRC4173_AC97_IRQ,
 	VRC4173_USB_IRQ,
 };
 
-static const int irq_tab_mpc30x[] __initdata = {
+static const int irq_tab_mpc30x[] __initconst = {
  [12] = VRC4173_PCMCIA1_IRQ,
  [13] = VRC4173_PCMCIA2_IRQ,
  [29] = MQ200_IRQ,
diff --git a/arch/mips/pci/fixup-rc32434.c b/arch/mips/pci/fixup-rc32434.c
index 3d86823..76bb1be 100644
--- a/arch/mips/pci/fixup-rc32434.c
+++ b/arch/mips/pci/fixup-rc32434.c
@@ -47,7 +47,7 @@ int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 	return irq + GROUP4_IRQ_BASE + 4;
 }
 
-static void rc32434_pci_early_fixup(struct pci_dev *dev)
+static void __devinit rc32434_pci_early_fixup(struct pci_dev *dev)
 {
 	if (PCI_SLOT(dev->devfn) == 6 && dev->bus->number == 0) {
 		/* disable prefetched memory range */
diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c
index f0bb914..d02900a 100644
--- a/arch/mips/pci/fixup-sb1250.c
+++ b/arch/mips/pci/fixup-sb1250.c
@@ -15,7 +15,7 @@
  * Set the BCM1250, etc. PCI host bridge's TRDY timeout
  * to the finite max.
  */
-static void __init quirk_sb1250_pci(struct pci_dev *dev)
+static void __devinit quirk_sb1250_pci(struct pci_dev *dev)
 {
 	pci_write_config_byte(dev, 0x40, 0xff);
 }
@@ -25,7 +25,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI,
 /*
  * The BCM1250, etc. PCI/HT bridge reports as a host bridge.
  */
-static void __init quirk_sb1250_ht(struct pci_dev *dev)
+static void __devinit quirk_sb1250_ht(struct pci_dev *dev)
 {
 	dev->class = PCI_CLASS_BRIDGE_PCI << 8;
 }
@@ -35,7 +35,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT,
 /*
  * Set the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
  */
-static void __init quirk_sp1011(struct pci_dev *dev)
+static void __devinit quirk_sp1011(struct pci_dev *dev)
 {
 	pci_write_config_byte(dev, 0x64, 0xff);
 }
diff --git a/arch/mips/pci/ops-bcm63xx.c b/arch/mips/pci/ops-bcm63xx.c
index 822ae17..65c7bd1 100644
--- a/arch/mips/pci/ops-bcm63xx.c
+++ b/arch/mips/pci/ops-bcm63xx.c
@@ -411,7 +411,7 @@ struct pci_ops bcm63xx_cb_ops = {
  * only one IO window, so it  cannot be shared by PCI and cardbus, use
  * fixup to choose and detect unhandled configuration
  */
-static void bcm63xx_fixup(struct pci_dev *dev)
+static void __devinit bcm63xx_fixup(struct pci_dev *dev)
 {
 	static int io_window = -1;
 	int i, found, new_io_window;
@@ -465,3 +465,64 @@ static void bcm63xx_fixup(struct pci_dev *dev)
 
 DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, bcm63xx_fixup);
 #endif
+
+static int bcm63xx_pcie_can_access(struct pci_bus *bus, int devfn)
+{
+	switch (bus->number) {
+	case PCIE_BUS_BRIDGE:
+		return (PCI_SLOT(devfn) == 0);
+	case PCIE_BUS_DEVICE:
+		if (PCI_SLOT(devfn) == 0)
+			return bcm_pcie_readl(PCIE_DLSTATUS_REG)
+					& DLSTATUS_PHYLINKUP;
+	default:
+		return false;
+	}
+}
+
+static int bcm63xx_pcie_read(struct pci_bus *bus, unsigned int devfn,
+			     int where, int size, u32 *val)
+{
+	u32 data;
+	u32 reg = where & ~3;
+
+	if (!bcm63xx_pcie_can_access(bus, devfn))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (bus->number == PCIE_BUS_DEVICE)
+		reg += PCIE_DEVICE_OFFSET;
+
+	data = bcm_pcie_readl(reg);
+
+	*val = postprocess_read(data, where, size);
+
+	return PCIBIOS_SUCCESSFUL;
+
+}
+
+static int bcm63xx_pcie_write(struct pci_bus *bus, unsigned int devfn,
+			      int where, int size, u32 val)
+{
+	u32 data;
+	u32 reg = where & ~3;
+
+	if (!bcm63xx_pcie_can_access(bus, devfn))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (bus->number == PCIE_BUS_DEVICE)
+		reg += PCIE_DEVICE_OFFSET;
+
+
+	data = bcm_pcie_readl(reg);
+
+	data = preprocess_write(data, val, where, size);
+	bcm_pcie_writel(data, reg);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+struct pci_ops bcm63xx_pcie_ops = {
+	.read   = bcm63xx_pcie_read,
+	.write  = bcm63xx_pcie_write
+};
diff --git a/arch/mips/pci/ops-tx4927.c b/arch/mips/pci/ops-tx4927.c
index a1e7e6d..bc13e29 100644
--- a/arch/mips/pci/ops-tx4927.c
+++ b/arch/mips/pci/ops-tx4927.c
@@ -495,7 +495,7 @@ irqreturn_t tx4927_pcierr_interrupt(int irq, void *dev_id)
 }
 
 #ifdef CONFIG_TOSHIBA_FPCIB0
-static void __init tx4927_quirk_slc90e66_bridge(struct pci_dev *dev)
+static void __devinit tx4927_quirk_slc90e66_bridge(struct pci_dev *dev)
 {
 	struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(dev->bus);
 
diff --git a/arch/mips/pci/pci-bcm63xx.c b/arch/mips/pci/pci-bcm63xx.c
index 39eb7c4..8a48139 100644
--- a/arch/mips/pci/pci-bcm63xx.c
+++ b/arch/mips/pci/pci-bcm63xx.c
@@ -10,6 +10,7 @@
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/bootinfo.h>
 
 #include "pci-bcm63xx.h"
@@ -71,6 +72,26 @@ struct pci_controller bcm63xx_cb_controller = {
 };
 #endif
 
+static struct resource bcm_pcie_mem_resource = {
+	.name   = "bcm63xx PCIe memory space",
+	.start  = BCM_PCIE_MEM_BASE_PA,
+	.end    = BCM_PCIE_MEM_END_PA,
+	.flags  = IORESOURCE_MEM,
+};
+
+static struct resource bcm_pcie_io_resource = {
+	.name   = "bcm63xx PCIe IO space",
+	.start  = 0,
+	.end    = 0,
+	.flags  = 0,
+};
+
+struct pci_controller bcm63xx_pcie_controller = {
+	.pci_ops	= &bcm63xx_pcie_ops,
+	.io_resource	= &bcm_pcie_io_resource,
+	.mem_resource	= &bcm_pcie_mem_resource,
+};
+
 static u32 bcm63xx_int_cfg_readl(u32 reg)
 {
 	u32 tmp;
@@ -94,17 +115,99 @@ static void bcm63xx_int_cfg_writel(u32 val, u32 reg)
 
 void __iomem *pci_iospace_start;
 
-static int __init bcm63xx_pci_init(void)
+static void __init bcm63xx_reset_pcie(void)
 {
-	unsigned int mem_size;
 	u32 val;
 
-	if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358() && !BCMCPU_IS_6368())
-		return -ENODEV;
+	/* enable clock */
+	val = bcm_perf_readl(PERF_CKCTL_REG);
+	val |= CKCTL_6328_PCIE_EN;
+	bcm_perf_writel(val, PERF_CKCTL_REG);
+
+	/* enable SERDES */
+	val = bcm_misc_readl(MISC_SERDES_CTRL_REG);
+	val |= SERDES_PCIE_EN | SERDES_PCIE_EXD_EN;
+	bcm_misc_writel(val, MISC_SERDES_CTRL_REG);
+
+	/* reset the PCIe core */
+	val = bcm_perf_readl(PERF_SOFTRESET_6328_REG);
+
+	val &= ~SOFTRESET_6328_PCIE_MASK;
+	val &= ~SOFTRESET_6328_PCIE_CORE_MASK;
+	val &= ~SOFTRESET_6328_PCIE_HARD_MASK;
+	val &= ~SOFTRESET_6328_PCIE_EXT_MASK;
+	bcm_perf_writel(val, PERF_SOFTRESET_6328_REG);
+	mdelay(10);
+
+	val |= SOFTRESET_6328_PCIE_MASK;
+	val |= SOFTRESET_6328_PCIE_CORE_MASK;
+	val |= SOFTRESET_6328_PCIE_HARD_MASK;
+	bcm_perf_writel(val, PERF_SOFTRESET_6328_REG);
+	mdelay(10);
+
+	val |= SOFTRESET_6328_PCIE_EXT_MASK;
+	bcm_perf_writel(val, PERF_SOFTRESET_6328_REG);
+	mdelay(200);
+}
 
-	if (!bcm63xx_pci_enabled)
-		return -ENODEV;
+static int __init bcm63xx_register_pcie(void)
+{
+	u32 val;
 
+	bcm63xx_reset_pcie();
+
+	/* configure the PCIe bridge */
+	val = bcm_pcie_readl(PCIE_BRIDGE_OPT1_REG);
+	val |= OPT1_RD_BE_OPT_EN;
+	val |= OPT1_RD_REPLY_BE_FIX_EN;
+	val |= OPT1_PCIE_BRIDGE_HOLE_DET_EN;
+	val |= OPT1_L1_INT_STATUS_MASK_POL;
+	bcm_pcie_writel(val, PCIE_BRIDGE_OPT1_REG);
+
+	/* setup the interrupts */
+	val = bcm_pcie_readl(PCIE_BRIDGE_RC_INT_MASK_REG);
+	val |= PCIE_RC_INT_A | PCIE_RC_INT_B | PCIE_RC_INT_C | PCIE_RC_INT_D;
+	bcm_pcie_writel(val, PCIE_BRIDGE_RC_INT_MASK_REG);
+
+	val = bcm_pcie_readl(PCIE_BRIDGE_OPT2_REG);
+	/* enable credit checking and error checking */
+	val |= OPT2_TX_CREDIT_CHK_EN;
+	val |= OPT2_UBUS_UR_DECODE_DIS;
+
+	/* set device bus/func for the pcie device */
+	val |= (PCIE_BUS_DEVICE << OPT2_CFG_TYPE1_BUS_NO_SHIFT);
+	val |= OPT2_CFG_TYPE1_BD_SEL;
+	bcm_pcie_writel(val, PCIE_BRIDGE_OPT2_REG);
+
+	/* setup class code as bridge */
+	val = bcm_pcie_readl(PCIE_IDVAL3_REG);
+	val &= ~IDVAL3_CLASS_CODE_MASK;
+	val |= (PCI_CLASS_BRIDGE_PCI << IDVAL3_SUBCLASS_SHIFT);
+	bcm_pcie_writel(val, PCIE_IDVAL3_REG);
+
+	/* disable bar1 size */
+	val = bcm_pcie_readl(PCIE_CONFIG2_REG);
+	val &= ~CONFIG2_BAR1_SIZE_MASK;
+	bcm_pcie_writel(val, PCIE_CONFIG2_REG);
+
+	/* set bar0 to little endian */
+	val = (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_BASE_SHIFT;
+	val |= (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_MASK_SHIFT;
+	val |= BASEMASK_REMAP_EN;
+	bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_BASEMASK_REG);
+
+	val = (BCM_PCIE_MEM_BASE_PA >> 20) << REBASE_ADDR_BASE_SHIFT;
+	bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_REBASE_ADDR_REG);
+
+	register_pci_controller(&bcm63xx_pcie_controller);
+
+	return 0;
+}
+
+static int __init bcm63xx_register_pci(void)
+{
+	unsigned int mem_size;
+	u32 val;
 	/*
 	 * configuration  access are  done through  IO space,  remap 4
 	 * first bytes to access it from CPU.
@@ -221,4 +324,22 @@ static int __init bcm63xx_pci_init(void)
 	return 0;
 }
 
+
+static int __init bcm63xx_pci_init(void)
+{
+	if (!bcm63xx_pci_enabled)
+		return -ENODEV;
+
+	switch (bcm63xx_get_cpu_id()) {
+	case BCM6328_CPU_ID:
+		return bcm63xx_register_pcie();
+	case BCM6348_CPU_ID:
+	case BCM6358_CPU_ID:
+	case BCM6368_CPU_ID:
+		return bcm63xx_register_pci();
+	default:
+		return -ENODEV;
+	}
+}
+
 arch_initcall(bcm63xx_pci_init);
diff --git a/arch/mips/pci/pci-bcm63xx.h b/arch/mips/pci/pci-bcm63xx.h
index a6e594e..e6736d5 100644
--- a/arch/mips/pci/pci-bcm63xx.h
+++ b/arch/mips/pci/pci-bcm63xx.h
@@ -13,11 +13,16 @@
  */
 #define CARDBUS_PCI_IDSEL	0x8
 
+
+#define PCIE_BUS_BRIDGE		0
+#define PCIE_BUS_DEVICE		1
+
 /*
  * defined in ops-bcm63xx.c
  */
 extern struct pci_ops bcm63xx_pci_ops;
 extern struct pci_ops bcm63xx_cb_ops;
+extern struct pci_ops bcm63xx_pcie_ops;
 
 /*
  * defined in pci-bcm63xx.c
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
index 0fbe4c0..fdc2444 100644
--- a/arch/mips/pci/pci-ip27.c
+++ b/arch/mips/pci/pci-ip27.c
@@ -212,7 +212,7 @@ static inline void pci_enable_swapping(struct pci_dev *dev)
 	bridge->b_widget.w_tflush;	/* Flush */
 }
 
-static void __init pci_fixup_ioc3(struct pci_dev *d)
+static void __devinit pci_fixup_ioc3(struct pci_dev *d)
 {
 	pci_disable_swapping(d);
 }
diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c
new file mode 100644
index 0000000..3e177e9
--- /dev/null
+++ b/arch/mips/pci/pci-xlp.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * 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 Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/msi.h>
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/haldefs.h>
+
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/pic.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/pcibus.h>
+#include <asm/netlogic/xlp-hal/bridge.h>
+
+static void *pci_config_base;
+
+#define	pci_cfg_addr(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))
+
+/* PCI ops */
+static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,
+	int where)
+{
+	u32 data;
+	u32 *cfgaddr;
+
+	cfgaddr = (u32 *)(pci_config_base +
+			pci_cfg_addr(bus->number, devfn, where & ~3));
+	data = *cfgaddr;
+	return data;
+}
+
+static inline void pci_cfg_write_32bit(struct pci_bus *bus, unsigned int devfn,
+	int where, u32 data)
+{
+	u32 *cfgaddr;
+
+	cfgaddr = (u32 *)(pci_config_base +
+			pci_cfg_addr(bus->number, devfn, where & ~3));
+	*cfgaddr = data;
+}
+
+static int nlm_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+	int where, int size, u32 *val)
+{
+	u32 data;
+
+	if ((size == 2) && (where & 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	else if ((size == 4) && (where & 3))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	data = pci_cfg_read_32bit(bus, devfn, where);
+
+	if (size == 1)
+		*val = (data >> ((where & 3) << 3)) & 0xff;
+	else if (size == 2)
+		*val = (data >> ((where & 3) << 3)) & 0xffff;
+	else
+		*val = data;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int nlm_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+		int where, int size, u32 val)
+{
+	u32 data;
+
+	if ((size == 2) && (where & 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	else if ((size == 4) && (where & 3))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	data = pci_cfg_read_32bit(bus, devfn, where);
+
+	if (size == 1)
+		data = (data & ~(0xff << ((where & 3) << 3))) |
+			(val << ((where & 3) << 3));
+	else if (size == 2)
+		data = (data & ~(0xffff << ((where & 3) << 3))) |
+			(val << ((where & 3) << 3));
+	else
+		data = val;
+
+	pci_cfg_write_32bit(bus, devfn, where, data);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops nlm_pci_ops = {
+	.read  = nlm_pcibios_read,
+	.write = nlm_pcibios_write
+};
+
+static struct resource nlm_pci_mem_resource = {
+	.name           = "XLP PCI MEM",
+	.start          = 0xd0000000UL,	/* 256MB PCI mem @ 0xd000_0000 */
+	.end            = 0xdfffffffUL,
+	.flags          = IORESOURCE_MEM,
+};
+
+static struct resource nlm_pci_io_resource = {
+	.name           = "XLP IO MEM",
+	.start          = 0x14000000UL,	/* 64MB PCI IO @ 0x1000_0000 */
+	.end            = 0x17ffffffUL,
+	.flags          = IORESOURCE_IO,
+};
+
+struct pci_controller nlm_pci_controller = {
+	.index          = 0,
+	.pci_ops        = &nlm_pci_ops,
+	.mem_resource   = &nlm_pci_mem_resource,
+	.mem_offset     = 0x00000000UL,
+	.io_resource    = &nlm_pci_io_resource,
+	.io_offset      = 0x00000000UL,
+};
+
+static int get_irq_vector(const struct pci_dev *dev)
+{
+	/*
+	 * For XLP PCIe, there is an IRQ per Link, find out which
+	 * link the device is on to assign interrupts
+	*/
+	if (dev->bus->self == NULL)
+		return 0;
+
+	switch	(dev->bus->self->devfn) {
+	case 0x8:
+		return PIC_PCIE_LINK_0_IRQ;
+	case 0x9:
+		return PIC_PCIE_LINK_1_IRQ;
+	case 0xa:
+		return PIC_PCIE_LINK_2_IRQ;
+	case 0xb:
+		return PIC_PCIE_LINK_3_IRQ;
+	}
+	WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn);
+	return 0;
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	return get_irq_vector(dev);
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+	return 0;
+}
+
+static int xlp_enable_pci_bswap(void)
+{
+	uint64_t pciebase, sysbase;
+	int node, i;
+	u32 reg;
+
+	/* Chip-0 so node set to 0 */
+	node = 0;
+	sysbase = nlm_get_bridge_regbase(node);
+	/*
+	 *  Enable byte swap in hardware. Program each link's PCIe SWAP regions
+	 * from the link's address ranges.
+	 */
+	for (i = 0; i < 4; i++) {
+		pciebase = nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, i));
+		if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff)
+			continue;
+
+		reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_BASE0 + i);
+		nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_BASE, reg);
+
+		reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_LIMIT0 + i);
+		nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_LIM, reg);
+
+		reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_BASE0 + i);
+		nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_BASE, reg);
+
+		reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_LIMIT0 + i);
+		nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_LIM, reg);
+	}
+	return 0;
+}
+
+static int __init pcibios_init(void)
+{
+	/* Firmware assigns PCI resources */
+	pci_set_flags(PCI_PROBE_ONLY);
+	pci_config_base = ioremap(XLP_DEFAULT_PCI_ECFG_BASE, 64 << 20);
+
+	/* Extend IO port for memory mapped io */
+	ioport_resource.start =  0;
+	ioport_resource.end   = ~0;
+
+	xlp_enable_pci_bswap();
+	set_io_port_base(CKSEG1);
+	nlm_pci_controller.io_map_base = CKSEG1;
+
+	register_pci_controller(&nlm_pci_controller);
+	pr_info("XLP PCIe Controller %pR%pR.\n", &nlm_pci_io_resource,
+		&nlm_pci_mem_resource);
+
+	return 0;
+}
+arch_initcall(pcibios_init);
diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c
index 1644805..18af021 100644
--- a/arch/mips/pci/pci-xlr.c
+++ b/arch/mips/pci/pci-xlr.c
@@ -41,6 +41,7 @@
 #include <linux/irq.h>
 #include <linux/irqdesc.h>
 #include <linux/console.h>
+#include <linux/pci_regs.h>
 
 #include <asm/io.h>
 
@@ -156,35 +157,55 @@ struct pci_controller nlm_pci_controller = {
 	.io_offset      = 0x00000000UL,
 };
 
+/*
+ * The top level PCIe links on the XLS PCIe controller appear as
+ * bridges. Given a device, this function finds which link it is
+ * on.
+ */
+static struct pci_dev *xls_get_pcie_link(const struct pci_dev *dev)
+{
+	struct pci_bus *bus, *p;
+
+	/* Find the bridge on bus 0 */
+	bus = dev->bus;
+	for (p = bus->parent; p && p->number != 0; p = p->parent)
+		bus = p;
+
+	return p ? bus->self : NULL;
+}
+
 static int get_irq_vector(const struct pci_dev *dev)
 {
+	struct pci_dev *lnk;
+
 	if (!nlm_chip_is_xls())
-		return	PIC_PCIX_IRQ;	/* for XLR just one IRQ*/
+		return	PIC_PCIX_IRQ;	/* for XLR just one IRQ */
 
 	/*
 	 * For XLS PCIe, there is an IRQ per Link, find out which
 	 * link the device is on to assign interrupts
-	*/
-	if (dev->bus->self == NULL)
+	 */
+	lnk = xls_get_pcie_link(dev);
+	if (lnk == NULL)
 		return 0;
 
-	switch	(dev->bus->self->devfn) {
-	case 0x0:
+	switch	(PCI_SLOT(lnk->devfn)) {
+	case 0:
 		return PIC_PCIE_LINK0_IRQ;
-	case 0x8:
+	case 1:
 		return PIC_PCIE_LINK1_IRQ;
-	case 0x10:
+	case 2:
 		if (nlm_chip_is_xls_b())
 			return PIC_PCIE_XLSB0_LINK2_IRQ;
 		else
 			return PIC_PCIE_LINK2_IRQ;
-	case 0x18:
+	case 3:
 		if (nlm_chip_is_xls_b())
 			return PIC_PCIE_XLSB0_LINK3_IRQ;
 		else
 			return PIC_PCIE_LINK3_IRQ;
 	}
-	WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn);
+	WARN(1, "Unexpected devfn %d\n", lnk->devfn);
 	return 0;
 }
 
@@ -202,7 +223,27 @@ void arch_teardown_msi_irq(unsigned int irq)
 int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 {
 	struct msi_msg msg;
+	struct pci_dev *lnk;
 	int irq, ret;
+	u16 val;
+
+	/* MSI not supported on XLR */
+	if (!nlm_chip_is_xls())
+		return 1;
+
+	/*
+	 * Enable MSI on the XLS PCIe controller bridge which was disabled
+	 * at enumeration, the bridge MSI capability is at 0x50
+	 */
+	lnk = xls_get_pcie_link(dev);
+	if (lnk == NULL)
+		return 1;
+
+	pci_read_config_word(lnk, 0x50 + PCI_MSI_FLAGS, &val);
+	if ((val & PCI_MSI_FLAGS_ENABLE) == 0) {
+		val |= PCI_MSI_FLAGS_ENABLE;
+		pci_write_config_word(lnk, 0x50 + PCI_MSI_FLAGS, val);
+	}
 
 	irq = get_irq_vector(dev);
 	if (irq <= 0)
@@ -327,14 +368,10 @@ static int __init pcibios_init(void)
 		}
 	} else {
 		/* XLR PCI controller ACK */
-		irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack);
+		irq_set_handler_data(PIC_PCIX_IRQ, xlr_pci_ack);
 	}
 
 	return 0;
 }
 
 arch_initcall(pcibios_init);
-
-struct pci_fixup pcibios_fixups[] = {
-	{0}
-};
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 271e8c4a..0a9bf77 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -102,7 +102,7 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose)
 	need_domain_info = need_domain_info || hose->index;
 	hose->need_domain_info = need_domain_info;
 	if (bus) {
-		next_busno = bus->subordinate + 1;
+		next_busno = bus->busn_res.end + 1;
 		/* Don't allow 8-bit bus number overflow inside the hose -
 		   reserve some space for bridges. */
 		if (next_busno > 224) {
diff --git a/arch/mips/pmc-sierra/yosemite/smp.c b/arch/mips/pmc-sierra/yosemite/smp.c
index b71fae2..5edab2b 100644
--- a/arch/mips/pmc-sierra/yosemite/smp.c
+++ b/arch/mips/pmc-sierra/yosemite/smp.c
@@ -115,11 +115,11 @@ static void yos_send_ipi_mask(const struct cpumask *mask, unsigned int action)
  */
 static void __cpuinit yos_init_secondary(void)
 {
-	set_c0_status(ST0_CO | ST0_IE | ST0_IM);
 }
 
 static void __cpuinit yos_smp_finish(void)
 {
+	set_c0_status(ST0_CO | ST0_IM | ST0_IE);
 }
 
 /* Hook for after all CPUs are online */
diff --git a/arch/mips/pnx833x/stb22x/board.c b/arch/mips/pnx833x/stb22x/board.c
index 644eb7c..4b328ac 100644
--- a/arch/mips/pnx833x/stb22x/board.c
+++ b/arch/mips/pnx833x/stb22x/board.c
@@ -91,7 +91,7 @@ void __init pnx833x_board_setup(void)
 	pnx833x_gpio_select_function_alt(32);
 	pnx833x_gpio_select_function_alt(33);
 
-#if defined(CONFIG_MTD_NAND_PLATFORM) || defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
+#if IS_ENABLED(CONFIG_MTD_NAND_PLATFORM)
 	/* Setup MIU for NAND access on CS0...
 	 *
 	 * (it seems that we must also configure CS1 for reliable operation,
@@ -117,7 +117,7 @@ void __init pnx833x_board_setup(void)
 	pnx833x_gpio_select_output(5);
 	pnx833x_gpio_write(1, 5);
 
-#elif defined(CONFIG_MTD_CFI) || defined(CONFIG_MTD_CFI_MODULE)
+#elif IS_ENABLED(CONFIG_MTD_CFI)
 
 	/* Set up MIU for 16-bit NOR access on CS0 and CS1... */
 
diff --git a/arch/mips/powertv/asic/asic-calliope.c b/arch/mips/powertv/asic/asic-calliope.c
index 0a170e0..7773f3d 100644
--- a/arch/mips/powertv/asic/asic-calliope.c
+++ b/arch/mips/powertv/asic/asic-calliope.c
@@ -28,7 +28,7 @@
 
 #define CALLIOPE_ADDR(x)	(CALLIOPE_IO_BASE + (x))
 
-const struct register_map calliope_register_map __initdata = {
+const struct register_map calliope_register_map __initconst = {
 	.eic_slow0_strt_add = {.phys = CALLIOPE_ADDR(0x800000)},
 	.eic_cfg_bits = {.phys = CALLIOPE_ADDR(0x800038)},
 	.eic_ready_status = {.phys = CALLIOPE_ADDR(0x80004c)},
diff --git a/arch/mips/powertv/asic/asic-cronus.c b/arch/mips/powertv/asic/asic-cronus.c
index bbc0c12..da076db 100644
--- a/arch/mips/powertv/asic/asic-cronus.c
+++ b/arch/mips/powertv/asic/asic-cronus.c
@@ -28,7 +28,7 @@
 
 #define CRONUS_ADDR(x)	(CRONUS_IO_BASE + (x))
 
-const struct register_map cronus_register_map __initdata = {
+const struct register_map cronus_register_map __initconst = {
 	.eic_slow0_strt_add = {.phys = CRONUS_ADDR(0x000000)},
 	.eic_cfg_bits = {.phys = CRONUS_ADDR(0x000038)},
 	.eic_ready_status = {.phys = CRONUS_ADDR(0x00004C)},
diff --git a/arch/mips/powertv/asic/asic-gaia.c b/arch/mips/powertv/asic/asic-gaia.c
index 91dda68..47683b3 100644
--- a/arch/mips/powertv/asic/asic-gaia.c
+++ b/arch/mips/powertv/asic/asic-gaia.c
@@ -23,7 +23,7 @@
 #include <linux/init.h>
 #include <asm/mach-powertv/asic.h>
 
-const struct register_map gaia_register_map __initdata = {
+const struct register_map gaia_register_map __initconst = {
 	.eic_slow0_strt_add = {.phys = GAIA_IO_BASE + 0x000000},
 	.eic_cfg_bits = {.phys = GAIA_IO_BASE + 0x000038},
 	.eic_ready_status = {.phys = GAIA_IO_BASE + 0x00004C},
diff --git a/arch/mips/powertv/asic/asic-zeus.c b/arch/mips/powertv/asic/asic-zeus.c
index 4a05bb0..6ff4b10 100644
--- a/arch/mips/powertv/asic/asic-zeus.c
+++ b/arch/mips/powertv/asic/asic-zeus.c
@@ -28,7 +28,7 @@
 
 #define ZEUS_ADDR(x)	(ZEUS_IO_BASE + (x))
 
-const struct register_map zeus_register_map __initdata = {
+const struct register_map zeus_register_map __initconst = {
 	.eic_slow0_strt_add = {.phys = ZEUS_ADDR(0x000000)},
 	.eic_cfg_bits = {.phys = ZEUS_ADDR(0x000038)},
 	.eic_ready_status = {.phys = ZEUS_ADDR(0x00004c)},
diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c
index 682efb0..bab4953 100644
--- a/arch/mips/txx9/generic/pci.c
+++ b/arch/mips/txx9/generic/pci.c
@@ -269,7 +269,7 @@ txx9_i8259_irq_setup(int irq)
 	return err;
 }
 
-static void __init quirk_slc90e66_bridge(struct pci_dev *dev)
+static void __devinit quirk_slc90e66_bridge(struct pci_dev *dev)
 {
 	int irq;	/* PCI/ISA Bridge interrupt */
 	u8 reg_64;
@@ -304,7 +304,7 @@ static void __init quirk_slc90e66_bridge(struct pci_dev *dev)
 	smsc_fdc37m81x_config_end();
 }
 
-static void quirk_slc90e66_ide(struct pci_dev *dev)
+static void __devinit quirk_slc90e66_ide(struct pci_dev *dev)
 {
 	unsigned char dat;
 	int regs[2] = {0x41, 0x43};
@@ -339,7 +339,7 @@ static void quirk_slc90e66_ide(struct pci_dev *dev)
 }
 #endif /* CONFIG_TOSHIBA_FPCIB0 */
 
-static void tc35815_fixup(struct pci_dev *dev)
+static void __devinit tc35815_fixup(struct pci_dev *dev)
 {
 	/* This device may have PM registers but not they are not suported. */
 	if (dev->pm_cap) {
@@ -348,7 +348,7 @@ static void tc35815_fixup(struct pci_dev *dev)
 	}
 }
 
-static void final_fixup(struct pci_dev *dev)
+static void __devinit final_fixup(struct pci_dev *dev)
 {
 	unsigned char bist;
 
diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c
index ae77a79..560fe89 100644
--- a/arch/mips/txx9/generic/setup.c
+++ b/arch/mips/txx9/generic/setup.c
@@ -632,7 +632,7 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr,
 				    unsigned long size,
 				    const struct physmap_flash_data *pdata)
 {
-#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+#if IS_ENABLED(CONFIG_MTD_PHYSMAP)
 	struct resource res = {
 		.start = addr,
 		.end = addr + size - 1,
@@ -670,8 +670,7 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr,
 void __init txx9_ndfmc_init(unsigned long baseaddr,
 			    const struct txx9ndfmc_platform_data *pdata)
 {
-#if defined(CONFIG_MTD_NAND_TXX9NDFMC) || \
-	defined(CONFIG_MTD_NAND_TXX9NDFMC_MODULE)
+#if IS_ENABLED(CONFIG_MTD_NAND_TXX9NDFMC)
 	struct resource res = {
 		.start = baseaddr,
 		.end = baseaddr + 0x1000 - 1,
@@ -687,7 +686,7 @@ void __init txx9_ndfmc_init(unsigned long baseaddr,
 #endif
 }
 
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#if IS_ENABLED(CONFIG_LEDS_GPIO)
 static DEFINE_SPINLOCK(txx9_iocled_lock);
 
 #define TXX9_IOCLED_MAXLEDS 8
@@ -810,7 +809,7 @@ void __init txx9_iocled_init(unsigned long baseaddr,
 void __init txx9_dmac_init(int id, unsigned long baseaddr, int irq,
 			   const struct txx9dmac_platform_data *pdata)
 {
-#if defined(CONFIG_TXX9_DMAC) || defined(CONFIG_TXX9_DMAC_MODULE)
+#if IS_ENABLED(CONFIG_TXX9_DMAC)
 	struct resource res[] = {
 		{
 			.start = baseaddr,
@@ -866,8 +865,7 @@ void __init txx9_aclc_init(unsigned long baseaddr, int irq,
 			   unsigned int dma_chan_out,
 			   unsigned int dma_chan_in)
 {
-#if defined(CONFIG_SND_SOC_TXX9ACLC) || \
-	defined(CONFIG_SND_SOC_TXX9ACLC_MODULE)
+#if IS_ENABLED(CONFIG_SND_SOC_TXX9ACLC)
 	unsigned int dma_base = dmac_id * TXX9_DMA_MAX_NR_CHANNELS;
 	struct resource res[] = {
 		{
diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c
index 6567895..5ff7a95 100644
--- a/arch/mips/txx9/generic/setup_tx4939.c
+++ b/arch/mips/txx9/generic/setup_tx4939.c
@@ -317,7 +317,7 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)
 	}
 }
 
-#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
+#if IS_ENABLED(CONFIG_TC35815)
 static u32 tx4939_get_eth_speed(struct net_device *dev)
 {
 	struct ethtool_cmd cmd;
diff --git a/arch/mips/txx9/rbtx4939/setup.c b/arch/mips/txx9/rbtx4939/setup.c
index 2ad8973..e15641d 100644
--- a/arch/mips/txx9/rbtx4939/setup.c
+++ b/arch/mips/txx9/rbtx4939/setup.c
@@ -40,8 +40,7 @@ static void __init rbtx4939_time_init(void)
 	tx4939_time_init(0);
 }
 
-#if defined(__BIG_ENDIAN) && \
-	(defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE))
+#if defined(__BIG_ENDIAN) && IS_ENABLED(CONFIG_SMC91X)
 #define HAVE_RBTX4939_IOSWAB
 #define IS_CE1_ADDR(addr) \
 	((((unsigned long)(addr) - IO_BASE) & 0xfff00000) == TXX9_CE(1))
@@ -187,7 +186,7 @@ static void __init rbtx4939_update_ioc_pen(void)
 
 #define RBTX4939_MAX_7SEGLEDS	8
 
-#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+#if IS_ENABLED(CONFIG_LEDS_CLASS)
 static u8 led_val[RBTX4939_MAX_7SEGLEDS];
 struct rbtx4939_led_data {
 	struct led_classdev cdev;
@@ -263,7 +262,7 @@ static inline void rbtx4939_led_setup(void)
 
 static void __rbtx4939_7segled_putc(unsigned int pos, unsigned char val)
 {
-#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+#if IS_ENABLED(CONFIG_LEDS_CLASS)
 	unsigned long flags;
 	local_irq_save(flags);
 	/* bit7: reserved for LED class */
@@ -287,7 +286,7 @@ static void rbtx4939_7segled_putc(unsigned int pos, unsigned char val)
 	__rbtx4939_7segled_putc(pos, val);
 }
 
-#if defined(CONFIG_MTD_RBTX4939) || defined(CONFIG_MTD_RBTX4939_MODULE)
+#if IS_ENABLED(CONFIG_MTD_RBTX4939)
 /* special mapping for boot rom */
 static unsigned long rbtx4939_flash_fixup_ofs(unsigned long ofs)
 {
@@ -463,7 +462,7 @@ static void __init rbtx4939_device_init(void)
 		.flags = SMC91X_USE_16BIT,
 	};
 	struct platform_device *pdev;
-#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
+#if IS_ENABLED(CONFIG_TC35815)
 	int i, j;
 	unsigned char ethaddr[2][6];
 	u8 bdipsw = readb(rbtx4939_bdipsw_addr) & 0x0f;
diff --git a/arch/mn10300/include/asm/ptrace.h b/arch/mn10300/include/asm/ptrace.h
index 55b79ef..44251b9 100644
--- a/arch/mn10300/include/asm/ptrace.h
+++ b/arch/mn10300/include/asm/ptrace.h
@@ -81,9 +81,6 @@ struct pt_regs {
 #define PTRACE_GETFPREGS          14
 #define PTRACE_SETFPREGS          15
 
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD     0x00000001
-
 #ifdef __KERNEL__
 
 #define user_mode(regs)			(((regs)->epsw & EPSW_nSL) == EPSW_nSL)
diff --git a/arch/mn10300/include/asm/thread_info.h b/arch/mn10300/include/asm/thread_info.h
index 08251d6..52b1efa 100644
--- a/arch/mn10300/include/asm/thread_info.h
+++ b/arch/mn10300/include/asm/thread_info.h
@@ -160,12 +160,13 @@ void arch_release_thread_info(struct thread_info *ti)
 #define _TIF_SIGPENDING		+(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	+(1 << TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		+(1 << TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK	+(1 << TIF_RESTORE_SIGMASK)
 #define _TIF_POLLING_NRFLAG	+(1 << TIF_POLLING_NRFLAG)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
 
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/mn10300/include/asm/timex.h b/arch/mn10300/include/asm/timex.h
index bd4e90d..f8e6642 100644
--- a/arch/mn10300/include/asm/timex.h
+++ b/arch/mn10300/include/asm/timex.h
@@ -11,7 +11,6 @@
 #ifndef _ASM_TIMEX_H
 #define _ASM_TIMEX_H
 
-#include <asm/hardirq.h>
 #include <unit/timex.h>
 
 #define TICK_SIZE (tick_nsec / 1000)
@@ -30,16 +29,6 @@ static inline cycles_t get_cycles(void)
 extern int init_clockevents(void);
 extern int init_clocksource(void);
 
-static inline void setup_jiffies_interrupt(int irq,
-					   struct irqaction *action)
-{
-	u16 tmp;
-	setup_irq(irq, action);
-	set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));
-	GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
-	tmp = GxICR(irq);
-}
-
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_TIMEX_H */
diff --git a/arch/mn10300/kernel/cevt-mn10300.c b/arch/mn10300/kernel/cevt-mn10300.c
index 69cae02..ccce35e 100644
--- a/arch/mn10300/kernel/cevt-mn10300.c
+++ b/arch/mn10300/kernel/cevt-mn10300.c
@@ -70,6 +70,16 @@ static void event_handler(struct clock_event_device *dev)
 {
 }
 
+static inline void setup_jiffies_interrupt(int irq,
+					   struct irqaction *action)
+{
+	u16 tmp;
+	setup_irq(irq, action);
+	set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));
+	GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
+	tmp = GxICR(irq);
+}
+
 int __init init_clockevents(void)
 {
 	struct clock_event_device *cd;
diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S
index 8e11f9f..976c540 100644
--- a/arch/mn10300/kernel/entry.S
+++ b/arch/mn10300/kernel/entry.S
@@ -94,6 +94,10 @@ restore_all:
 ###############################################################################
 	ALIGN
 syscall_exit_work:
+	mov	(REG_EPSW,fp),d0
+	and	EPSW_nSL,d0
+	beq	resume_kernel		# returning to supervisor mode
+
 	btst	_TIF_SYSCALL_TRACE,d2
 	beq	work_pending
 	LOCAL_IRQ_ENABLE		# could let syscall_trace_exit() call
diff --git a/arch/mn10300/kernel/internal.h b/arch/mn10300/kernel/internal.h
index a5ac755..2df4401 100644
--- a/arch/mn10300/kernel/internal.h
+++ b/arch/mn10300/kernel/internal.h
@@ -9,6 +9,8 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
+#include <linux/irqreturn.h>
+
 struct clocksource;
 struct clock_event_device;
 
diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c
index 2381df8..35932a8 100644
--- a/arch/mn10300/kernel/irq.c
+++ b/arch/mn10300/kernel/irq.c
@@ -170,9 +170,9 @@ mn10300_cpupic_setaffinity(struct irq_data *d, const struct cpumask *mask,
 	case SC1TXIRQ:
 #ifdef CONFIG_MN10300_TTYSM1_TIMER12
 	case TM12IRQ:
-#elif CONFIG_MN10300_TTYSM1_TIMER9
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER9)
 	case TM9IRQ:
-#elif CONFIG_MN10300_TTYSM1_TIMER3
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER3)
 	case TM3IRQ:
 #endif /* CONFIG_MN10300_TTYSM1_TIMER12 */
 #endif /* CONFIG_MN10300_TTYSM1 */
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c
index 6ab0bee..a348e79 100644
--- a/arch/mn10300/kernel/signal.c
+++ b/arch/mn10300/kernel/signal.c
@@ -398,10 +398,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	regs->d0 = sig;
 	regs->d1 = (long) &frame->info;
 
-	/* the tracer may want to single-step inside the handler */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 #if DEBUG_SIG
 	printk(KERN_DEBUG "SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
 	       sig, current->comm, current->pid, frame, regs->pc,
@@ -474,11 +470,6 @@ static void do_signal(struct pt_regs *regs)
 	siginfo_t info;
 	int signr;
 
-	/* we want the common case to go fast, which is why we may in certain
-	 * cases get here from kernel mode */
-	if (!user_mode(regs))
-		return;
-
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
 		if (handle_signal(signr, &info, &ka, regs) == 0) {
diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c
index 090d35d..e62c223 100644
--- a/arch/mn10300/kernel/smp.c
+++ b/arch/mn10300/kernel/smp.c
@@ -876,9 +876,7 @@ static void __init smp_online(void)
 
 	notify_cpu_starting(cpu);
 
-	ipi_call_lock();
 	set_cpu_online(cpu, true);
-	ipi_call_unlock();
 
 	local_irq_enable();
 }
diff --git a/arch/mn10300/kernel/traps.c b/arch/mn10300/kernel/traps.c
index 94a9c6d..b900e5a 100644
--- a/arch/mn10300/kernel/traps.c
+++ b/arch/mn10300/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/kdebug.h>
 #include <linux/bug.h>
 #include <linux/irq.h>
+#include <linux/export.h>
 #include <asm/processor.h>
 #include <linux/uaccess.h>
 #include <asm/io.h>
diff --git a/arch/mn10300/mm/dma-alloc.c b/arch/mn10300/mm/dma-alloc.c
index 159acb0..e244ebe 100644
--- a/arch/mn10300/mm/dma-alloc.c
+++ b/arch/mn10300/mm/dma-alloc.c
@@ -15,6 +15,7 @@
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/gfp.h>
+#include <linux/export.h>
 #include <asm/io.h>
 
 static unsigned long pci_sram_allocated = 0xbc000000;
diff --git a/arch/mn10300/unit-asb2303/include/unit/timex.h b/arch/mn10300/unit-asb2303/include/unit/timex.h
index cc18fe7..c37f983 100644
--- a/arch/mn10300/unit-asb2303/include/unit/timex.h
+++ b/arch/mn10300/unit-asb2303/include/unit/timex.h
@@ -11,10 +11,6 @@
 #ifndef _ASM_UNIT_TIMEX_H
 #define _ASM_UNIT_TIMEX_H
 
-#ifndef __ASSEMBLY__
-#include <linux/irq.h>
-#endif /* __ASSEMBLY__ */
-
 #include <asm/timer-regs.h>
 #include <unit/clock.h>
 #include <asm/param.h>
diff --git a/arch/mn10300/unit-asb2303/smc91111.c b/arch/mn10300/unit-asb2303/smc91111.c
index 43c2464..5367769 100644
--- a/arch/mn10300/unit-asb2303/smc91111.c
+++ b/arch/mn10300/unit-asb2303/smc91111.c
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/timex.h>
 #include <asm/processor.h>
 #include <asm/intctl-regs.h>
diff --git a/arch/mn10300/unit-asb2305/include/unit/timex.h b/arch/mn10300/unit-asb2305/include/unit/timex.h
index 758af30..4cefc22 100644
--- a/arch/mn10300/unit-asb2305/include/unit/timex.h
+++ b/arch/mn10300/unit-asb2305/include/unit/timex.h
@@ -11,10 +11,6 @@
 #ifndef _ASM_UNIT_TIMEX_H
 #define _ASM_UNIT_TIMEX_H
 
-#ifndef __ASSEMBLY__
-#include <linux/irq.h>
-#endif /* __ASSEMBLY__ */
-
 #include <asm/timer-regs.h>
 #include <unit/clock.h>
 #include <asm/param.h>
diff --git a/arch/mn10300/unit-asb2305/unit-init.c b/arch/mn10300/unit-asb2305/unit-init.c
index e1becd6..bc4adfa 100644
--- a/arch/mn10300/unit-asb2305/unit-init.c
+++ b/arch/mn10300/unit-asb2305/unit-init.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/processor.h>
 #include <asm/intctl-regs.h>
diff --git a/arch/mn10300/unit-asb2364/include/unit/timex.h b/arch/mn10300/unit-asb2364/include/unit/timex.h
index ddb7ed0..42f32db 100644
--- a/arch/mn10300/unit-asb2364/include/unit/timex.h
+++ b/arch/mn10300/unit-asb2364/include/unit/timex.h
@@ -11,10 +11,6 @@
 #ifndef _ASM_UNIT_TIMEX_H
 #define _ASM_UNIT_TIMEX_H
 
-#ifndef __ASSEMBLY__
-#include <linux/irq.h>
-#endif /* __ASSEMBLY__ */
-
 #include <asm/timer-regs.h>
 #include <unit/clock.h>
 #include <asm/param.h>
diff --git a/arch/openrisc/include/asm/thread_info.h b/arch/openrisc/include/asm/thread_info.h
index 07a8bc0..07f3212 100644
--- a/arch/openrisc/include/asm/thread_info.h
+++ b/arch/openrisc/include/asm/thread_info.h
@@ -121,7 +121,6 @@ register struct thread_info *current_thread_info_reg asm("r10");
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK     (1<<TIF_RESTORE_SIGMASK)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 
@@ -129,6 +128,8 @@ register struct thread_info *current_thread_info_reg asm("r10");
 /* For OpenRISC, this is anything in the LSW other than syscall trace */
 #define _TIF_WORK_MASK (0xff & ~(_TIF_SYSCALL_TRACE|_TIF_SINGLESTEP))
 
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/parisc/hpux/gate.S b/arch/parisc/hpux/gate.S
index 38a1c1b..0114688 100644
--- a/arch/parisc/hpux/gate.S
+++ b/arch/parisc/hpux/gate.S
@@ -71,7 +71,7 @@ ENTRY(hpux_gateway_page)
 	STREG	%r26, TASK_PT_GR26(%r1)	 	/* 1st argument */
 	STREG	%r27, TASK_PT_GR27(%r1)		/* user dp */
 	STREG   %r28, TASK_PT_GR28(%r1)         /* return value 0 */
-	STREG   %r28, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
+	STREG   %r0, TASK_PT_ORIG_R28(%r1)     /* don't prohibit restarts */
 	STREG   %r29, TASK_PT_GR29(%r1)         /* 8th argument */
 	STREG	%r31, TASK_PT_GR31(%r1)		/* preserve syscall return ptr */
 	
diff --git a/arch/parisc/include/asm/errno.h b/arch/parisc/include/asm/errno.h
index 135ad60..753cc5c 100644
--- a/arch/parisc/include/asm/errno.h
+++ b/arch/parisc/include/asm/errno.h
@@ -123,5 +123,8 @@
 #define	ERFKILL		256	/* Operation not possible due to RF-kill */
 
 #define EHWPOISON	257	/* Memory page has hardware error */
+#define	ENOAUTHSERVICE	258	/* Authentication service not available */
+#define	ENONAMESERVICE	259	/* Network name service unavailable */
+#define	ENAMEUNKNOWN	260	/* Network name unknown */
 
 #endif
diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h
index 22b4726..d1fb79a 100644
--- a/arch/parisc/include/asm/thread_info.h
+++ b/arch/parisc/include/asm/thread_info.h
@@ -68,13 +68,16 @@ struct thread_info {
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_32BIT		(1 << TIF_32BIT)
-#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_BLOCKSTEP		(1 << TIF_BLOCKSTEP)
 
 #define _TIF_USER_WORK_MASK     (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | \
                                  _TIF_NEED_RESCHED)
+#define _TIF_SYSCALL_TRACE_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP |	\
+				 _TIF_BLOCKSTEP)
+
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
 
 #endif /* __KERNEL__ */
 
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 594459b..5379969 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -113,6 +113,8 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
 		(usp - sigframe_size);
 	DBG(2,"sys_rt_sigreturn: frame is %p\n", frame);
 
+	regs->orig_r28 = 1; /* no restarts for sigreturn */
+
 #ifdef CONFIG_64BIT
 	compat_frame = (struct compat_rt_sigframe __user *)frame;
 	
@@ -437,7 +439,7 @@ give_sigsegv:
  * OK, we're invoking a handler.
  */	
 
-static long
+static void
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 		struct pt_regs *regs, int in_syscall)
 {
@@ -447,7 +449,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 	
 	/* Set up the stack frame */
 	if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
-		return 0;
+		return;
 
 	signal_delivered(sig, info, ka, regs, 
 		test_thread_flag(TIF_SINGLESTEP) ||
@@ -455,13 +457,14 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 
 	DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n",
 		regs->gr[28]);
-
-	return 1;
 }
 
 static inline void
 syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 {
+	if (regs->orig_r28)
+		return;
+	regs->orig_r28 = 1; /* no more restarts */
 	/* Check the return code */
 	switch (regs->gr[28]) {
 	case -ERESTART_RESTARTBLOCK:
@@ -482,8 +485,6 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 		 * we have to do is fiddle the return pointer.
 		 */
 		regs->gr[31] -= 8; /* delayed branching */
-		/* Preserve original r28. */
-		regs->gr[28] = regs->orig_r28;
 		break;
 	}
 }
@@ -491,6 +492,9 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 static inline void
 insert_restart_trampoline(struct pt_regs *regs)
 {
+	if (regs->orig_r28)
+		return;
+	regs->orig_r28 = 1; /* no more restarts */
 	switch(regs->gr[28]) {
 	case -ERESTART_RESTARTBLOCK: {
 		/* Restart the system call - no handlers present */
@@ -525,9 +529,6 @@ insert_restart_trampoline(struct pt_regs *regs)
 		flush_user_icache_range(regs->gr[30], regs->gr[30] + 4);
 
 		regs->gr[31] = regs->gr[30] + 8;
-		/* Preserve original r28. */
-		regs->gr[28] = regs->orig_r28;
-
 		return;
 	}
 	case -ERESTARTNOHAND:
@@ -539,9 +540,6 @@ insert_restart_trampoline(struct pt_regs *regs)
 		 * slot of the branch external instruction.
 		 */
 		regs->gr[31] -= 8;
-		/* Preserve original r28. */
-		regs->gr[28] = regs->orig_r28;
-
 		return;
 	}
 	default:
@@ -570,30 +568,17 @@ do_signal(struct pt_regs *regs, long in_syscall)
 	DBG(1,"\ndo_signal: regs=0x%p, sr7 %#lx, in_syscall=%d\n",
 	       regs, regs->sr[7], in_syscall);
 
-	/* Everyone else checks to see if they are in kernel mode at
-	   this point and exits if that's the case.  I'm not sure why
-	   we would be called in that case, but for some reason we
-	   are. */
-
-	/* May need to force signal if handle_signal failed to deliver */
-	while (1) {
-		signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-		DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); 
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); 
 	
-		if (signr <= 0)
-		  break;
-		
+	if (signr > 0) {
 		/* Restart a system call if necessary. */
 		if (in_syscall)
 			syscall_restart(regs, &ka);
 
-		/* Whee!  Actually deliver the signal.  If the
-		   delivery failed, we need to continue to iterate in
-		   this loop so we can deliver the SIGSEGV... */
-		if (handle_signal(signr, &info, &ka, regs, in_syscall))
-			return;
+		handle_signal(signr, &info, &ka, regs, in_syscall);
+		return;
 	}
-	/* end of while(1) looping forever if we can't force a signal */
 
 	/* Did we come from a system call? */
 	if (in_syscall)
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index a47828d..6266730 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -300,9 +300,7 @@ smp_cpu_init(int cpunum)
 
 	notify_cpu_starting(cpunum);
 
-	ipi_call_lock();
 	set_cpu_online(cpunum, true);
-	ipi_call_unlock();
 
 	/* Initialise the idle task for this CPU */
 	atomic_inc(&init_mm.mm_count);
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
index 82a52b2..86742df 100644
--- a/arch/parisc/kernel/syscall.S
+++ b/arch/parisc/kernel/syscall.S
@@ -156,7 +156,7 @@ linux_gateway_entry:
 	STREG	%r26, TASK_PT_GR26(%r1)	 	/* 1st argument */
 	STREG	%r27, TASK_PT_GR27(%r1)		/* user dp */
 	STREG   %r28, TASK_PT_GR28(%r1)         /* return value 0 */
-	STREG   %r28, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
+	STREG   %r0, TASK_PT_ORIG_R28(%r1)      /* don't prohibit restarts */
 	STREG	%r29, TASK_PT_GR29(%r1)		/* return value 1 */
 	STREG	%r31, TASK_PT_GR31(%r1)		/* preserve syscall return ptr */
 	
@@ -180,9 +180,10 @@ linux_gateway_entry:
 
 	/* Are we being ptraced? */
 	mfctl	%cr30, %r1
-	LDREG	TI_TASK(%r1),%r1
-	ldw	TASK_PTRACE(%r1), %r1
-	bb,<,n	%r1,31,.Ltracesys
+	LDREG	TI_FLAGS(%r1),%r1
+	ldi	_TIF_SYSCALL_TRACE_MASK, %r19
+	and,COND(=) %r1, %r19, %r0
+	b,n	.Ltracesys
 	
 	/* Note!  We cannot use the syscall table that is mapped
 	nearby since the gateway page is mapped execute-only. */
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index 62678e3..7816087 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -27,7 +27,10 @@ extern void *dma_direct_alloc_coherent(struct device *dev, size_t size,
 extern void dma_direct_free_coherent(struct device *dev, size_t size,
 				     void *vaddr, dma_addr_t dma_handle,
 				     struct dma_attrs *attrs);
-
+extern int dma_direct_mmap_coherent(struct device *dev,
+				    struct vm_area_struct *vma,
+				    void *cpu_addr, dma_addr_t handle,
+				    size_t size, struct dma_attrs *attrs);
 
 #ifdef CONFIG_NOT_COHERENT_CACHE
 /*
@@ -207,11 +210,8 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 
-extern int dma_mmap_coherent(struct device *, struct vm_area_struct *,
-			     void *, dma_addr_t, size_t);
 #define ARCH_HAS_DMA_MMAP_COHERENT
 
-
 static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
 		enum dma_data_direction direction)
 {
diff --git a/arch/powerpc/include/asm/epapr_hcalls.h b/arch/powerpc/include/asm/epapr_hcalls.h
index 976835d..bf2c06c 100644
--- a/arch/powerpc/include/asm/epapr_hcalls.h
+++ b/arch/powerpc/include/asm/epapr_hcalls.h
@@ -153,6 +153,8 @@
 #define EV_HCALL_CLOBBERS2 EV_HCALL_CLOBBERS3, "r5"
 #define EV_HCALL_CLOBBERS1 EV_HCALL_CLOBBERS2, "r4"
 
+extern bool epapr_paravirt_enabled;
+extern u32 epapr_hypercall_start[];
 
 /*
  * We use "uintptr_t" to define a register because it's guaranteed to be a
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h
index 32b394f..3b245f1 100644
--- a/arch/powerpc/include/asm/hw_irq.h
+++ b/arch/powerpc/include/asm/hw_irq.h
@@ -34,6 +34,8 @@ extern void __replay_interrupt(unsigned int vector);
 
 extern void timer_interrupt(struct pt_regs *);
 extern void performance_monitor_exception(struct pt_regs *regs);
+extern void WatchdogException(struct pt_regs *regs);
+extern void unknown_exception(struct pt_regs *regs);
 
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
diff --git a/arch/powerpc/include/asm/kmap_types.h b/arch/powerpc/include/asm/kmap_types.h
index bca8fdc..5acabbd 100644
--- a/arch/powerpc/include/asm/kmap_types.h
+++ b/arch/powerpc/include/asm/kmap_types.h
@@ -10,36 +10,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-enum km_type {
-	KM_BOUNCE_READ,
-	KM_SKB_SUNRPC_DATA,
-	KM_SKB_DATA_SOFTIRQ,
-	KM_USER0,
-	KM_USER1,
-	KM_BIO_SRC_IRQ,
-	KM_BIO_DST_IRQ,
-	KM_PTE0,
-	KM_PTE1,
-	KM_IRQ0,
-	KM_IRQ1,
-	KM_SOFTIRQ0,
-	KM_SOFTIRQ1,
-	KM_PPC_SYNC_PAGE,
-	KM_PPC_SYNC_ICACHE,
-	KM_KDB,
-	KM_TYPE_NR
-};
-
-/*
- * This is a temporary build fix that (so they say on lkml....) should no longer
- * be required after 2.6.33, because of changes planned to the kmap code.
- * Let's try to remove this cruft then.
- */
-#ifdef CONFIG_DEBUG_HIGHMEM
-#define KM_NMI		(-1)
-#define KM_NMI_PTE	(-1)
-#define KM_IRQ_PTE	(-1)
-#endif
+#define KM_TYPE_NR 16
 
 #endif	/* __KERNEL__ */
 #endif	/* _ASM_POWERPC_KMAP_TYPES_H */
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index b0c08b1..0dd1d86 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -36,11 +36,8 @@ static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)
 #define SPAPR_TCE_SHIFT		12
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
-/* For now use fixed-size 16MB page table */
-#define HPT_ORDER	24
-#define HPT_NPTEG	(1ul << (HPT_ORDER - 7))	/* 128B per pteg */
-#define HPT_NPTE	(HPT_NPTEG << 3)		/* 8 PTEs per PTEG */
-#define HPT_HASH_MASK	(HPT_NPTEG - 1)
+#define KVM_DEFAULT_HPT_ORDER	24	/* 16MB HPT by default */
+extern int kvm_hpt_order;		/* order of preallocated HPTs */
 #endif
 
 #define VRMA_VSID	0x1ffffffUL	/* 1TB VSID reserved for VRMA */
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index d848cdc..50ea12f 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -237,6 +237,10 @@ struct kvm_arch {
 	unsigned long vrma_slb_v;
 	int rma_setup_done;
 	int using_mmu_notifiers;
+	u32 hpt_order;
+	atomic_t vcpus_running;
+	unsigned long hpt_npte;
+	unsigned long hpt_mask;
 	spinlock_t slot_phys_lock;
 	unsigned long *slot_phys[KVM_MEM_SLOTS_NUM];
 	int slot_npages[KVM_MEM_SLOTS_NUM];
@@ -414,7 +418,9 @@ struct kvm_vcpu_arch {
 	ulong mcsrr1;
 	ulong mcsr;
 	u32 dec;
+#ifdef CONFIG_BOOKE
 	u32 decar;
+#endif
 	u32 tbl;
 	u32 tbu;
 	u32 tcr;
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index f68c22f..0124937 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -119,7 +119,8 @@ extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu);
 extern int kvmppc_kvm_pv(struct kvm_vcpu *vcpu);
 extern void kvmppc_map_magic(struct kvm_vcpu *vcpu);
 
-extern long kvmppc_alloc_hpt(struct kvm *kvm);
+extern long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp);
+extern long kvmppc_alloc_reset_hpt(struct kvm *kvm, u32 *htab_orderp);
 extern void kvmppc_free_hpt(struct kvm *kvm);
 extern long kvmppc_prepare_vrma(struct kvm *kvm,
 				struct kvm_userspace_memory_region *mem);
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index ac39e6a..8cccbee 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -30,6 +30,7 @@ struct pci_controller {
 	int first_busno;
 	int last_busno;
 	int self_busno;
+	struct resource busn;
 
 	void __iomem *io_base_virt;
 #ifdef CONFIG_PPC64
diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h
index 68831e9..642abd7 100644
--- a/arch/powerpc/include/asm/thread_info.h
+++ b/arch/powerpc/include/asm/thread_info.h
@@ -171,6 +171,8 @@ static inline bool test_thread_local_flags(unsigned int flags)
 #define is_32bit_task()	(1)
 #endif
 
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif	/* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 83afacd..bb282dd 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -128,6 +128,7 @@ ifneq ($(CONFIG_XMON)$(CONFIG_KEXEC),)
 obj-y				+= ppc_save_regs.o
 endif
 
+obj-$(CONFIG_EPAPR_PARAVIRT)	+= epapr_paravirt.o epapr_hcalls.o
 obj-$(CONFIG_KVM_GUEST)		+= kvm.o kvm_emul.o
 
 # Disable GCOV in odd or sensitive code
diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c
index bcfdcd2..2d7bb8c 100644
--- a/arch/powerpc/kernel/dma-iommu.c
+++ b/arch/powerpc/kernel/dma-iommu.c
@@ -109,6 +109,7 @@ static u64 dma_iommu_get_required_mask(struct device *dev)
 struct dma_map_ops dma_iommu_ops = {
 	.alloc			= dma_iommu_alloc_coherent,
 	.free			= dma_iommu_free_coherent,
+	.mmap			= dma_direct_mmap_coherent,
 	.map_sg			= dma_iommu_map_sg,
 	.unmap_sg		= dma_iommu_unmap_sg,
 	.dma_supported		= dma_iommu_dma_supported,
diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c
index 4ab88da..4694365 100644
--- a/arch/powerpc/kernel/dma-swiotlb.c
+++ b/arch/powerpc/kernel/dma-swiotlb.c
@@ -49,6 +49,7 @@ static u64 swiotlb_powerpc_get_required(struct device *dev)
 struct dma_map_ops swiotlb_dma_ops = {
 	.alloc = dma_direct_alloc_coherent,
 	.free = dma_direct_free_coherent,
+	.mmap = dma_direct_mmap_coherent,
 	.map_sg = swiotlb_map_sg_attrs,
 	.unmap_sg = swiotlb_unmap_sg_attrs,
 	.dma_supported = swiotlb_dma_supported,
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index b1ec983..062bf20 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -65,6 +65,24 @@ void dma_direct_free_coherent(struct device *dev, size_t size,
 #endif
 }
 
+int dma_direct_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+			     void *cpu_addr, dma_addr_t handle, size_t size,
+			     struct dma_attrs *attrs)
+{
+	unsigned long pfn;
+
+#ifdef CONFIG_NOT_COHERENT_CACHE
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	pfn = __dma_get_coherent_pfn((unsigned long)cpu_addr);
+#else
+	pfn = page_to_pfn(virt_to_page(cpu_addr));
+#endif
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
 static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
 			     int nents, enum dma_data_direction direction,
 			     struct dma_attrs *attrs)
@@ -154,6 +172,7 @@ static inline void dma_direct_sync_single(struct device *dev,
 struct dma_map_ops dma_direct_ops = {
 	.alloc				= dma_direct_alloc_coherent,
 	.free				= dma_direct_free_coherent,
+	.mmap				= dma_direct_mmap_coherent,
 	.map_sg				= dma_direct_map_sg,
 	.unmap_sg			= dma_direct_unmap_sg,
 	.dma_supported			= dma_direct_dma_supported,
@@ -211,20 +230,3 @@ static int __init dma_init(void)
 }
 fs_initcall(dma_init);
 
-int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
-		      void *cpu_addr, dma_addr_t handle, size_t size)
-{
-	unsigned long pfn;
-
-#ifdef CONFIG_NOT_COHERENT_CACHE
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	pfn = __dma_get_coherent_pfn((unsigned long)cpu_addr);
-#else
-	pfn = page_to_pfn(virt_to_page(cpu_addr));
-#endif
-	return remap_pfn_range(vma, vma->vm_start,
-			       pfn + vma->vm_pgoff,
-			       vma->vm_end - vma->vm_start,
-			       vma->vm_page_prot);
-}
-EXPORT_SYMBOL_GPL(dma_mmap_coherent);
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index ed1718f..e4fd9bb 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -563,9 +563,10 @@ _GLOBAL(ret_from_except_lite)
 	li	r0,_TIF_NEED_RESCHED	/* bits to check */
 	ld	r3,_MSR(r1)
 	ld	r4,TI_FLAGS(r9)
-	/* Move MSR_PR bit in r3 to _TIF_SIGPENDING position in r0 */
+	/* Add MSR_PR bit in r3 in _TIF_SIGPENDING and _TIF_NOTIFY_RESUME positions in r0 */
 	rlwimi	r0,r3,32+TIF_SIGPENDING-MSR_PR_LG,_TIF_SIGPENDING
-	and.	r0,r4,r0	/* check NEED_RESCHED and maybe SIGPENDING */
+	rlwimi	r0,r3,32+TIF_NOTIFY_RESUME-MSR_PR_LG,_TIF_NOTIFY_RESUME
+	and.	r0,r4,r0	/* check NEED_RESCHED and maybe SIGPENDING/NOTIFY_RESUME */
 	bne	do_work
 
 #else /* !CONFIG_PREEMPT */
diff --git a/arch/powerpc/kernel/epapr_hcalls.S b/arch/powerpc/kernel/epapr_hcalls.S
new file mode 100644
index 0000000..697b390
--- /dev/null
+++ b/arch/powerpc/kernel/epapr_hcalls.S
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/threads.h>
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+/* Hypercall entry point. Will be patched with device tree instructions. */
+.global epapr_hypercall_start
+epapr_hypercall_start:
+	li	r3, -1
+	nop
+	nop
+	nop
+	blr
diff --git a/arch/powerpc/kernel/epapr_paravirt.c b/arch/powerpc/kernel/epapr_paravirt.c
new file mode 100644
index 0000000..028aeae
--- /dev/null
+++ b/arch/powerpc/kernel/epapr_paravirt.c
@@ -0,0 +1,52 @@
+/*
+ * ePAPR para-virtualization support.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ */
+
+#include <linux/of.h>
+#include <asm/epapr_hcalls.h>
+#include <asm/cacheflush.h>
+#include <asm/code-patching.h>
+
+bool epapr_paravirt_enabled;
+
+static int __init epapr_paravirt_init(void)
+{
+	struct device_node *hyper_node;
+	const u32 *insts;
+	int len, i;
+
+	hyper_node = of_find_node_by_path("/hypervisor");
+	if (!hyper_node)
+		return -ENODEV;
+
+	insts = of_get_property(hyper_node, "hcall-instructions", &len);
+	if (!insts)
+		return -ENODEV;
+
+	if (len % 4 || len > (4 * 4))
+		return -ENODEV;
+
+	for (i = 0; i < (len / 4); i++)
+		patch_instruction(epapr_hypercall_start + i, insts[i]);
+
+	epapr_paravirt_enabled = true;
+
+	return 0;
+}
+
+early_initcall(epapr_paravirt_init);
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
index 62bdf23..1c13307 100644
--- a/arch/powerpc/kernel/kvm.c
+++ b/arch/powerpc/kernel/kvm.c
@@ -31,6 +31,7 @@
 #include <asm/cacheflush.h>
 #include <asm/disassemble.h>
 #include <asm/ppc-opcode.h>
+#include <asm/epapr_hcalls.h>
 
 #define KVM_MAGIC_PAGE		(-4096L)
 #define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x)
@@ -726,7 +727,7 @@ unsigned long kvm_hypercall(unsigned long *in,
 	unsigned long register r11 asm("r11") = nr;
 	unsigned long register r12 asm("r12");
 
-	asm volatile("bl	kvm_hypercall_start"
+	asm volatile("bl	epapr_hypercall_start"
 		     : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6),
 		       "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11),
 		       "=r"(r12)
@@ -747,29 +748,6 @@ unsigned long kvm_hypercall(unsigned long *in,
 }
 EXPORT_SYMBOL_GPL(kvm_hypercall);
 
-static int kvm_para_setup(void)
-{
-	extern u32 kvm_hypercall_start;
-	struct device_node *hyper_node;
-	u32 *insts;
-	int len, i;
-
-	hyper_node = of_find_node_by_path("/hypervisor");
-	if (!hyper_node)
-		return -1;
-
-	insts = (u32*)of_get_property(hyper_node, "hcall-instructions", &len);
-	if (len % 4)
-		return -1;
-	if (len > (4 * 4))
-		return -1;
-
-	for (i = 0; i < (len / 4); i++)
-		kvm_patch_ins(&(&kvm_hypercall_start)[i], insts[i]);
-
-	return 0;
-}
-
 static __init void kvm_free_tmp(void)
 {
 	unsigned long start, end;
@@ -791,7 +769,7 @@ static int __init kvm_guest_init(void)
 	if (!kvm_para_available())
 		goto free_tmp;
 
-	if (kvm_para_setup())
+	if (!epapr_paravirt_enabled)
 		goto free_tmp;
 
 	if (kvm_para_has_feature(KVM_FEATURE_MAGIC_PAGE))
diff --git a/arch/powerpc/kernel/kvm_emul.S b/arch/powerpc/kernel/kvm_emul.S
index e291cf3..e100ff3 100644
--- a/arch/powerpc/kernel/kvm_emul.S
+++ b/arch/powerpc/kernel/kvm_emul.S
@@ -24,16 +24,6 @@
 #include <asm/page.h>
 #include <asm/asm-offsets.h>
 
-/* Hypercall entry point. Will be patched with device tree instructions. */
-
-.global kvm_hypercall_start
-kvm_hypercall_start:
-	li	r3, -1
-	nop
-	nop
-	nop
-	blr
-
 #define KVM_MAGIC_PAGE		(-4096)
 
 #ifdef CONFIG_64BIT
@@ -132,7 +122,7 @@ kvm_emulate_mtmsrd_len:
 	.long (kvm_emulate_mtmsrd_end - kvm_emulate_mtmsrd) / 4
 
 
-#define MSR_SAFE_BITS (MSR_EE | MSR_CE | MSR_ME | MSR_RI)
+#define MSR_SAFE_BITS (MSR_EE | MSR_RI)
 #define MSR_CRITICAL_BITS ~MSR_SAFE_BITS
 
 .global kvm_emulate_mtmsr
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 8e78e93..2d5d41e 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -248,8 +248,7 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
 	} else {
 		pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
 			 oirq.size, oirq.specifier[0], oirq.specifier[1],
-			 oirq.controller ? oirq.controller->full_name :
-			 "<default>");
+			 of_node_full_name(oirq.controller));
 
 		virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
 					     oirq.size);
@@ -1628,8 +1627,7 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
 	struct device_node *node = hose->dn;
 	int mode;
 
-	pr_debug("PCI: Scanning PHB %s\n",
-		 node ? node->full_name : "<NO NAME>");
+	pr_debug("PCI: Scanning PHB %s\n", of_node_full_name(node));
 
 	/* Get some IO space for the new PHB */
 	pcibios_setup_phb_io_space(hose);
@@ -1637,6 +1635,11 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
 	/* Wire up PHB bus resources */
 	pcibios_setup_phb_resources(hose, &resources);
 
+	hose->busn.start = hose->first_busno;
+	hose->busn.end	 = hose->last_busno;
+	hose->busn.flags = IORESOURCE_BUS;
+	pci_add_resource(&resources, &hose->busn);
+
 	/* Create an empty bus for the toplevel */
 	bus = pci_create_root_bus(hose->parent, hose->first_busno,
 				  hose->ops, hose, &resources);
@@ -1646,7 +1649,6 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
 		pci_free_resource_list(&resources);
 		return;
 	}
-	bus->secondary = hose->first_busno;
 	hose->bus = bus;
 
 	/* Get probe mode and perform scan */
@@ -1654,13 +1656,14 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
 	if (node && ppc_md.pci_probe_mode)
 		mode = ppc_md.pci_probe_mode(bus);
 	pr_debug("    probe mode: %d\n", mode);
-	if (mode == PCI_PROBE_DEVTREE) {
-		bus->subordinate = hose->last_busno;
+	if (mode == PCI_PROBE_DEVTREE)
 		of_scan_bus(node, bus);
-	}
 
-	if (mode == PCI_PROBE_NORMAL)
-		hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+	if (mode == PCI_PROBE_NORMAL) {
+		pci_bus_update_busn_res_end(bus, 255);
+		hose->last_busno = pci_scan_child_bus(bus);
+		pci_bus_update_busn_res_end(bus, hose->last_busno);
+	}
 
 	/* Platform gets a chance to do some global fixups before
 	 * we proceed to resource allocation
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 94a54f6..4ff190f 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -236,7 +236,7 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
 
 	for (ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {
 		bus = pci_bus_b(ln);
-		if (in_bus >= bus->number && in_bus <= bus->subordinate)
+		if (in_bus >= bus->number && in_bus <= bus->busn_res.end)
 			break;
 		bus = NULL;
 	}
diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
index 89dde17..ae5ea5e 100644
--- a/arch/powerpc/kernel/pci_of_scan.c
+++ b/arch/powerpc/kernel/pci_of_scan.c
@@ -240,7 +240,7 @@ void __devinit of_scan_pci_bridge(struct pci_dev *dev)
 	}
 
 	bus->primary = dev->bus->number;
-	bus->subordinate = busrange[1];
+	pci_bus_insert_busn_res(bus, busrange[0], busrange[1]);
 	bus->bridge_ctl = 0;
 
 	/* parse ranges property */
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 8b4c049..804e323 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -35,7 +35,6 @@
 #include <linux/stddef.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
-#include <linux/freezer.h>
 #endif
 
 #include <asm/uaccess.h>
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index e4cb343..e1417c4 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -571,7 +571,6 @@ void __devinit start_secondary(void *unused)
 	if (system_state == SYSTEM_RUNNING)
 		vdso_data->processorCount++;
 #endif
-	ipi_call_lock();
 	notify_cpu_starting(cpu);
 	set_cpu_online(cpu, true);
 	/* Update sibling maps */
@@ -601,7 +600,6 @@ void __devinit start_secondary(void *unused)
 		of_node_put(np);
 	}
 	of_node_put(l2_cache);
-	ipi_call_unlock();
 
 	local_irq_enable();
 
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index cb87301..9f46e31 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -613,6 +613,7 @@ static u64 vio_dma_get_required_mask(struct device *dev)
 struct dma_map_ops vio_dma_mapping_ops = {
 	.alloc             = vio_dma_iommu_alloc_coherent,
 	.free              = vio_dma_iommu_free_coherent,
+	.mmap		   = dma_direct_mmap_coherent,
 	.map_sg            = vio_dma_iommu_map_sg,
 	.unmap_sg          = vio_dma_iommu_unmap_sg,
 	.map_page          = vio_dma_iommu_map_page,
@@ -1296,8 +1297,7 @@ static void __devinit vio_dev_release(struct device *dev)
 	struct iommu_table *tbl = get_iommu_table_base(dev);
 
 	if (tbl)
-		iommu_free_table(tbl, dev->of_node ?
-			dev->of_node->full_name : dev_name(dev));
+		iommu_free_table(tbl, of_node_full_name(dev->of_node));
 	of_node_put(dev->of_node);
 	kfree(to_vio_dev(dev));
 }
@@ -1509,7 +1509,7 @@ static ssize_t devspec_show(struct device *dev,
 {
 	struct device_node *of_node = dev->of_node;
 
-	return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none");
+	return sprintf(buf, "%s\n", of_node_full_name(of_node));
 }
 
 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 80a5775..d03eb6f 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -37,56 +37,121 @@
 /* POWER7 has 10-bit LPIDs, PPC970 has 6-bit LPIDs */
 #define MAX_LPID_970	63
 
-long kvmppc_alloc_hpt(struct kvm *kvm)
+/* Power architecture requires HPT is at least 256kB */
+#define PPC_MIN_HPT_ORDER	18
+
+long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp)
 {
 	unsigned long hpt;
-	long lpid;
 	struct revmap_entry *rev;
 	struct kvmppc_linear_info *li;
+	long order = kvm_hpt_order;
 
-	/* Allocate guest's hashed page table */
-	li = kvm_alloc_hpt();
-	if (li) {
-		/* using preallocated memory */
-		hpt = (ulong)li->base_virt;
-		kvm->arch.hpt_li = li;
-	} else {
-		/* using dynamic memory */
+	if (htab_orderp) {
+		order = *htab_orderp;
+		if (order < PPC_MIN_HPT_ORDER)
+			order = PPC_MIN_HPT_ORDER;
+	}
+
+	/*
+	 * If the user wants a different size from default,
+	 * try first to allocate it from the kernel page allocator.
+	 */
+	hpt = 0;
+	if (order != kvm_hpt_order) {
 		hpt = __get_free_pages(GFP_KERNEL|__GFP_ZERO|__GFP_REPEAT|
-				       __GFP_NOWARN, HPT_ORDER - PAGE_SHIFT);
+				       __GFP_NOWARN, order - PAGE_SHIFT);
+		if (!hpt)
+			--order;
 	}
 
+	/* Next try to allocate from the preallocated pool */
 	if (!hpt) {
-		pr_err("kvm_alloc_hpt: Couldn't alloc HPT\n");
-		return -ENOMEM;
+		li = kvm_alloc_hpt();
+		if (li) {
+			hpt = (ulong)li->base_virt;
+			kvm->arch.hpt_li = li;
+			order = kvm_hpt_order;
+		}
 	}
+
+	/* Lastly try successively smaller sizes from the page allocator */
+	while (!hpt && order > PPC_MIN_HPT_ORDER) {
+		hpt = __get_free_pages(GFP_KERNEL|__GFP_ZERO|__GFP_REPEAT|
+				       __GFP_NOWARN, order - PAGE_SHIFT);
+		if (!hpt)
+			--order;
+	}
+
+	if (!hpt)
+		return -ENOMEM;
+
 	kvm->arch.hpt_virt = hpt;
+	kvm->arch.hpt_order = order;
+	/* HPTEs are 2**4 bytes long */
+	kvm->arch.hpt_npte = 1ul << (order - 4);
+	/* 128 (2**7) bytes in each HPTEG */
+	kvm->arch.hpt_mask = (1ul << (order - 7)) - 1;
 
 	/* Allocate reverse map array */
-	rev = vmalloc(sizeof(struct revmap_entry) * HPT_NPTE);
+	rev = vmalloc(sizeof(struct revmap_entry) * kvm->arch.hpt_npte);
 	if (!rev) {
 		pr_err("kvmppc_alloc_hpt: Couldn't alloc reverse map array\n");
 		goto out_freehpt;
 	}
 	kvm->arch.revmap = rev;
+	kvm->arch.sdr1 = __pa(hpt) | (order - 18);
 
-	lpid = kvmppc_alloc_lpid();
-	if (lpid < 0)
-		goto out_freeboth;
+	pr_info("KVM guest htab at %lx (order %ld), LPID %x\n",
+		hpt, order, kvm->arch.lpid);
 
-	kvm->arch.sdr1 = __pa(hpt) | (HPT_ORDER - 18);
-	kvm->arch.lpid = lpid;
-
-	pr_info("KVM guest htab at %lx, LPID %lx\n", hpt, lpid);
+	if (htab_orderp)
+		*htab_orderp = order;
 	return 0;
 
- out_freeboth:
-	vfree(rev);
  out_freehpt:
-	free_pages(hpt, HPT_ORDER - PAGE_SHIFT);
+	if (kvm->arch.hpt_li)
+		kvm_release_hpt(kvm->arch.hpt_li);
+	else
+		free_pages(hpt, order - PAGE_SHIFT);
 	return -ENOMEM;
 }
 
+long kvmppc_alloc_reset_hpt(struct kvm *kvm, u32 *htab_orderp)
+{
+	long err = -EBUSY;
+	long order;
+
+	mutex_lock(&kvm->lock);
+	if (kvm->arch.rma_setup_done) {
+		kvm->arch.rma_setup_done = 0;
+		/* order rma_setup_done vs. vcpus_running */
+		smp_mb();
+		if (atomic_read(&kvm->arch.vcpus_running)) {
+			kvm->arch.rma_setup_done = 1;
+			goto out;
+		}
+	}
+	if (kvm->arch.hpt_virt) {
+		order = kvm->arch.hpt_order;
+		/* Set the entire HPT to 0, i.e. invalid HPTEs */
+		memset((void *)kvm->arch.hpt_virt, 0, 1ul << order);
+		/*
+		 * Set the whole last_vcpu array to an invalid vcpu number.
+		 * This ensures that each vcpu will flush its TLB on next entry.
+		 */
+		memset(kvm->arch.last_vcpu, 0xff, sizeof(kvm->arch.last_vcpu));
+		*htab_orderp = order;
+		err = 0;
+	} else {
+		err = kvmppc_alloc_hpt(kvm, htab_orderp);
+		order = *htab_orderp;
+	}
+ out:
+	mutex_unlock(&kvm->lock);
+	return err;
+}
+
 void kvmppc_free_hpt(struct kvm *kvm)
 {
 	kvmppc_free_lpid(kvm->arch.lpid);
@@ -94,7 +159,8 @@ void kvmppc_free_hpt(struct kvm *kvm)
 	if (kvm->arch.hpt_li)
 		kvm_release_hpt(kvm->arch.hpt_li);
 	else
-		free_pages(kvm->arch.hpt_virt, HPT_ORDER - PAGE_SHIFT);
+		free_pages(kvm->arch.hpt_virt,
+			   kvm->arch.hpt_order - PAGE_SHIFT);
 }
 
 /* Bits in first HPTE dword for pagesize 4k, 64k or 16M */
@@ -119,6 +185,7 @@ void kvmppc_map_vrma(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
 	unsigned long psize;
 	unsigned long hp0, hp1;
 	long ret;
+	struct kvm *kvm = vcpu->kvm;
 
 	psize = 1ul << porder;
 	npages = memslot->npages >> (porder - PAGE_SHIFT);
@@ -127,8 +194,8 @@ void kvmppc_map_vrma(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
 	if (npages > 1ul << (40 - porder))
 		npages = 1ul << (40 - porder);
 	/* Can't use more than 1 HPTE per HPTEG */
-	if (npages > HPT_NPTEG)
-		npages = HPT_NPTEG;
+	if (npages > kvm->arch.hpt_mask + 1)
+		npages = kvm->arch.hpt_mask + 1;
 
 	hp0 = HPTE_V_1TB_SEG | (VRMA_VSID << (40 - 16)) |
 		HPTE_V_BOLTED | hpte0_pgsize_encoding(psize);
@@ -138,7 +205,7 @@ void kvmppc_map_vrma(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
 	for (i = 0; i < npages; ++i) {
 		addr = i << porder;
 		/* can't use hpt_hash since va > 64 bits */
-		hash = (i ^ (VRMA_VSID ^ (VRMA_VSID << 25))) & HPT_HASH_MASK;
+		hash = (i ^ (VRMA_VSID ^ (VRMA_VSID << 25))) & kvm->arch.hpt_mask;
 		/*
 		 * We assume that the hash table is empty and no
 		 * vcpus are using it at this stage.  Since we create
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 3abe1b86..83e929e 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -56,7 +56,7 @@
 /* #define EXIT_DEBUG_INT */
 
 static void kvmppc_end_cede(struct kvm_vcpu *vcpu);
-static int kvmppc_hv_setup_rma(struct kvm_vcpu *vcpu);
+static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu);
 
 void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
@@ -1104,11 +1104,15 @@ int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		return -EINTR;
 	}
 
-	/* On the first time here, set up VRMA or RMA */
+	atomic_inc(&vcpu->kvm->arch.vcpus_running);
+	/* Order vcpus_running vs. rma_setup_done, see kvmppc_alloc_reset_hpt */
+	smp_mb();
+
+	/* On the first time here, set up HTAB and VRMA or RMA */
 	if (!vcpu->kvm->arch.rma_setup_done) {
-		r = kvmppc_hv_setup_rma(vcpu);
+		r = kvmppc_hv_setup_htab_rma(vcpu);
 		if (r)
-			return r;
+			goto out;
 	}
 
 	flush_fp_to_thread(current);
@@ -1126,6 +1130,9 @@ int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
 			kvmppc_core_prepare_to_enter(vcpu);
 		}
 	} while (r == RESUME_GUEST);
+
+ out:
+	atomic_dec(&vcpu->kvm->arch.vcpus_running);
 	return r;
 }
 
@@ -1341,7 +1348,7 @@ void kvmppc_core_commit_memory_region(struct kvm *kvm,
 {
 }
 
-static int kvmppc_hv_setup_rma(struct kvm_vcpu *vcpu)
+static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
 {
 	int err = 0;
 	struct kvm *kvm = vcpu->kvm;
@@ -1360,6 +1367,15 @@ static int kvmppc_hv_setup_rma(struct kvm_vcpu *vcpu)
 	if (kvm->arch.rma_setup_done)
 		goto out;	/* another vcpu beat us to it */
 
+	/* Allocate hashed page table (if not done already) and reset it */
+	if (!kvm->arch.hpt_virt) {
+		err = kvmppc_alloc_hpt(kvm, NULL);
+		if (err) {
+			pr_err("KVM: Couldn't alloc HPT\n");
+			goto out;
+		}
+	}
+
 	/* Look up the memslot for guest physical address 0 */
 	memslot = gfn_to_memslot(kvm, 0);
 
@@ -1471,13 +1487,14 @@ static int kvmppc_hv_setup_rma(struct kvm_vcpu *vcpu)
 
 int kvmppc_core_init_vm(struct kvm *kvm)
 {
-	long r;
-	unsigned long lpcr;
+	unsigned long lpcr, lpid;
 
-	/* Allocate hashed page table */
-	r = kvmppc_alloc_hpt(kvm);
-	if (r)
-		return r;
+	/* Allocate the guest's logical partition ID */
+
+	lpid = kvmppc_alloc_lpid();
+	if (lpid < 0)
+		return -ENOMEM;
+	kvm->arch.lpid = lpid;
 
 	INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
 
@@ -1487,7 +1504,6 @@ int kvmppc_core_init_vm(struct kvm *kvm)
 
 	if (cpu_has_feature(CPU_FTR_ARCH_201)) {
 		/* PPC970; HID4 is effectively the LPCR */
-		unsigned long lpid = kvm->arch.lpid;
 		kvm->arch.host_lpid = 0;
 		kvm->arch.host_lpcr = lpcr = mfspr(SPRN_HID4);
 		lpcr &= ~((3 << HID4_LPID1_SH) | (0xful << HID4_LPID5_SH));
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index e1b60f5..fb4eac2 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -25,6 +25,9 @@ static void __init kvm_linear_init_one(ulong size, int count, int type);
 static struct kvmppc_linear_info *kvm_alloc_linear(int type);
 static void kvm_release_linear(struct kvmppc_linear_info *ri);
 
+int kvm_hpt_order = KVM_DEFAULT_HPT_ORDER;
+EXPORT_SYMBOL_GPL(kvm_hpt_order);
+
 /*************** RMA *************/
 
 /*
@@ -209,7 +212,7 @@ static void kvm_release_linear(struct kvmppc_linear_info *ri)
 void __init kvm_linear_init(void)
 {
 	/* HPT */
-	kvm_linear_init_one(1 << HPT_ORDER, kvm_hpt_count, KVM_LINEAR_HPT);
+	kvm_linear_init_one(1 << kvm_hpt_order, kvm_hpt_count, KVM_LINEAR_HPT);
 
 	/* RMA */
 	/* Only do this on PPC970 in HV mode */
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index cec4dad..5c70d19 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -237,7 +237,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
 
 	/* Find and lock the HPTEG slot to use */
  do_insert:
-	if (pte_index >= HPT_NPTE)
+	if (pte_index >= kvm->arch.hpt_npte)
 		return H_PARAMETER;
 	if (likely((flags & H_EXACT) == 0)) {
 		pte_index &= ~7UL;
@@ -352,7 +352,7 @@ long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,
 	unsigned long v, r, rb;
 	struct revmap_entry *rev;
 
-	if (pte_index >= HPT_NPTE)
+	if (pte_index >= kvm->arch.hpt_npte)
 		return H_PARAMETER;
 	hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
 	while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
@@ -419,7 +419,8 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
 				i = 4;
 				break;
 			}
-			if (req != 1 || flags == 3 || pte_index >= HPT_NPTE) {
+			if (req != 1 || flags == 3 ||
+			    pte_index >= kvm->arch.hpt_npte) {
 				/* parameter error */
 				args[j] = ((0xa0 | flags) << 56) + pte_index;
 				ret = H_PARAMETER;
@@ -521,7 +522,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
 	struct revmap_entry *rev;
 	unsigned long v, r, rb, mask, bits;
 
-	if (pte_index >= HPT_NPTE)
+	if (pte_index >= kvm->arch.hpt_npte)
 		return H_PARAMETER;
 
 	hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
@@ -583,7 +584,7 @@ long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags,
 	int i, n = 1;
 	struct revmap_entry *rev = NULL;
 
-	if (pte_index >= HPT_NPTE)
+	if (pte_index >= kvm->arch.hpt_npte)
 		return H_PARAMETER;
 	if (flags & H_READ_4) {
 		pte_index &= ~3;
@@ -678,7 +679,7 @@ long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr, unsigned long slb_v,
 		somask = (1UL << 28) - 1;
 		vsid = (slb_v & ~SLB_VSID_B) >> SLB_VSID_SHIFT;
 	}
-	hash = (vsid ^ ((eaddr & somask) >> pshift)) & HPT_HASH_MASK;
+	hash = (vsid ^ ((eaddr & somask) >> pshift)) & kvm->arch.hpt_mask;
 	avpn = slb_v & ~(somask >> 16);	/* also includes B */
 	avpn |= (eaddr & somask) >> 16;
 
@@ -723,7 +724,7 @@ long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr, unsigned long slb_v,
 		if (val & HPTE_V_SECONDARY)
 			break;
 		val |= HPTE_V_SECONDARY;
-		hash = hash ^ HPT_HASH_MASK;
+		hash = hash ^ kvm->arch.hpt_mask;
 	}
 	return -1;
 }
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 72f13f4..d25a097 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -612,6 +612,12 @@ static void kvmppc_fill_pt_regs(struct pt_regs *regs)
 	regs->link = lr;
 }
 
+/*
+ * For interrupts needed to be handled by host interrupt handlers,
+ * corresponding host handler are called from here in similar way
+ * (but not exact) as they are called from low level handler
+ * (such as from arch/powerpc/kernel/head_fsl_booke.S).
+ */
 static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
 				     unsigned int exit_nr)
 {
@@ -639,6 +645,17 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
 		kvmppc_fill_pt_regs(&regs);
 		performance_monitor_exception(&regs);
 		break;
+	case BOOKE_INTERRUPT_WATCHDOG:
+		kvmppc_fill_pt_regs(&regs);
+#ifdef CONFIG_BOOKE_WDT
+		WatchdogException(&regs);
+#else
+		unknown_exception(&regs);
+#endif
+		break;
+	case BOOKE_INTERRUPT_CRITICAL:
+		unknown_exception(&regs);
+		break;
 	}
 }
 
@@ -683,6 +700,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		r = RESUME_GUEST;
 		break;
 
+	case BOOKE_INTERRUPT_WATCHDOG:
+		r = RESUME_GUEST;
+		break;
+
 	case BOOKE_INTERRUPT_DOORBELL:
 		kvmppc_account_exit(vcpu, DBELL_EXITS);
 		r = RESUME_GUEST;
@@ -1267,6 +1288,11 @@ void kvmppc_decrementer_func(unsigned long data)
 {
 	struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
 
+	if (vcpu->arch.tcr & TCR_ARE) {
+		vcpu->arch.dec = vcpu->arch.decar;
+		kvmppc_emulate_dec(vcpu);
+	}
+
 	kvmppc_set_tsr_bits(vcpu, TSR_DIS);
 }
 
diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
index 6c76397..9eb9809 100644
--- a/arch/powerpc/kvm/booke_emulate.c
+++ b/arch/powerpc/kvm/booke_emulate.c
@@ -129,6 +129,9 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
 		kvmppc_set_tcr(vcpu, spr_val);
 		break;
 
+	case SPRN_DECAR:
+		vcpu->arch.decar = spr_val;
+		break;
 	/*
 	 * Note: SPRG4-7 are user-readable.
 	 * These values are loaded into the real SPRGs when resuming the
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
index 8feec2f..09456c4 100644
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -53,16 +53,21 @@
                        (1<<BOOKE_INTERRUPT_PROGRAM) | \
                        (1<<BOOKE_INTERRUPT_DTLB_MISS))
 
-.macro KVM_HANDLER ivor_nr
+.macro KVM_HANDLER ivor_nr scratch srr0
 _GLOBAL(kvmppc_handler_\ivor_nr)
 	/* Get pointer to vcpu and record exit number. */
-	mtspr	SPRN_SPRG_WSCRATCH0, r4
+	mtspr	\scratch , r4
 	mfspr	r4, SPRN_SPRG_RVCPU
+	stw	r3, VCPU_GPR(r3)(r4)
 	stw	r5, VCPU_GPR(r5)(r4)
 	stw	r6, VCPU_GPR(r6)(r4)
+	mfspr	r3, \scratch
 	mfctr	r5
-	lis	r6, kvmppc_resume_host@h
+	stw	r3, VCPU_GPR(r4)(r4)
 	stw	r5, VCPU_CTR(r4)
+	mfspr	r3, \srr0
+	lis	r6, kvmppc_resume_host@h
+	stw	r3, VCPU_PC(r4)
 	li	r5, \ivor_nr
 	ori	r6, r6, kvmppc_resume_host@l
 	mtctr	r6
@@ -70,37 +75,35 @@ _GLOBAL(kvmppc_handler_\ivor_nr)
 .endm
 
 _GLOBAL(kvmppc_handlers_start)
-KVM_HANDLER BOOKE_INTERRUPT_CRITICAL
-KVM_HANDLER BOOKE_INTERRUPT_MACHINE_CHECK
-KVM_HANDLER BOOKE_INTERRUPT_DATA_STORAGE
-KVM_HANDLER BOOKE_INTERRUPT_INST_STORAGE
-KVM_HANDLER BOOKE_INTERRUPT_EXTERNAL
-KVM_HANDLER BOOKE_INTERRUPT_ALIGNMENT
-KVM_HANDLER BOOKE_INTERRUPT_PROGRAM
-KVM_HANDLER BOOKE_INTERRUPT_FP_UNAVAIL
-KVM_HANDLER BOOKE_INTERRUPT_SYSCALL
-KVM_HANDLER BOOKE_INTERRUPT_AP_UNAVAIL
-KVM_HANDLER BOOKE_INTERRUPT_DECREMENTER
-KVM_HANDLER BOOKE_INTERRUPT_FIT
-KVM_HANDLER BOOKE_INTERRUPT_WATCHDOG
-KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS
-KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS
-KVM_HANDLER BOOKE_INTERRUPT_DEBUG
-KVM_HANDLER BOOKE_INTERRUPT_SPE_UNAVAIL
-KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_DATA
-KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_ROUND
+KVM_HANDLER BOOKE_INTERRUPT_CRITICAL SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0
+KVM_HANDLER BOOKE_INTERRUPT_MACHINE_CHECK  SPRN_SPRG_RSCRATCH_MC SPRN_MCSRR0
+KVM_HANDLER BOOKE_INTERRUPT_DATA_STORAGE SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_INST_STORAGE SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_EXTERNAL SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_ALIGNMENT SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_PROGRAM SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_FP_UNAVAIL SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_SYSCALL SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_AP_UNAVAIL SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_DECREMENTER SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_FIT SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_WATCHDOG SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0
+KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_DEBUG SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0
+KVM_HANDLER BOOKE_INTERRUPT_SPE_UNAVAIL SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_DATA SPRN_SPRG_RSCRATCH0 SPRN_SRR0
+KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_ROUND SPRN_SPRG_RSCRATCH0 SPRN_SRR0
 
 _GLOBAL(kvmppc_handler_len)
 	.long kvmppc_handler_1 - kvmppc_handler_0
 
-
 /* Registers:
  *  SPRG_SCRATCH0: guest r4
  *  r4: vcpu pointer
  *  r5: KVM exit number
  */
 _GLOBAL(kvmppc_resume_host)
-	stw	r3, VCPU_GPR(r3)(r4)
 	mfcr	r3
 	stw	r3, VCPU_CR(r4)
 	stw	r7, VCPU_GPR(r7)(r4)
@@ -181,10 +184,6 @@ _GLOBAL(kvmppc_resume_host)
 	stw	r3, VCPU_LR(r4)
 	mfxer	r3
 	stw	r3, VCPU_XER(r4)
-	mfspr	r3, SPRN_SPRG_RSCRATCH0
-	stw	r3, VCPU_GPR(r4)(r4)
-	mfspr	r3, SPRN_SRR0
-	stw	r3, VCPU_PC(r4)
 
 	/* Restore host stack pointer and PID before IVPR, since the host
 	 * exception handlers use them. */
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c
index 8b99e07..e04b0ef 100644
--- a/arch/powerpc/kvm/e500_emulate.c
+++ b/arch/powerpc/kvm/e500_emulate.c
@@ -269,6 +269,9 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
 		*spr_val = vcpu->arch.shared->mas7_3 >> 32;
 		break;
 #endif
+	case SPRN_DECAR:
+		*spr_val = vcpu->arch.decar;
+		break;
 	case SPRN_TLB0CFG:
 		*spr_val = vcpu->arch.tlbcfg[0];
 		break;
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 1493c8d..87f4dc8 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -246,6 +246,7 @@ int kvm_dev_ioctl_check_extension(long ext)
 #endif
 #ifdef CONFIG_PPC_BOOK3S_64
 	case KVM_CAP_SPAPR_TCE:
+	case KVM_CAP_PPC_ALLOC_HTAB:
 		r = 1;
 		break;
 #endif /* CONFIG_PPC_BOOK3S_64 */
@@ -802,6 +803,23 @@ long kvm_arch_vm_ioctl(struct file *filp,
 			r = -EFAULT;
 		break;
 	}
+
+	case KVM_PPC_ALLOCATE_HTAB: {
+		struct kvm *kvm = filp->private_data;
+		u32 htab_order;
+
+		r = -EFAULT;
+		if (get_user(htab_order, (u32 __user *)argp))
+			break;
+		r = kvmppc_alloc_reset_hpt(kvm, &htab_order);
+		if (r)
+			break;
+		r = -EFAULT;
+		if (put_user(htab_order, (u32 __user *)argp))
+			break;
+		r = 0;
+		break;
+	}
 #endif /* CONFIG_KVM_BOOK3S_64_HV */
 
 #ifdef CONFIG_PPC_BOOK3S_64
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index c169998..b62508b 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -2,6 +2,7 @@ config PPC_MPC512x
 	bool "512x-based boards"
 	depends on 6xx
 	select FSL_SOC
+	select FB_FSL_DIU
 	select IPIC
 	select PPC_CLOCK
 	select PPC_PCI_CHOICE
diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c
index 1d8700f..9f771e0 100644
--- a/arch/powerpc/platforms/512x/clock.c
+++ b/arch/powerpc/platforms/512x/clock.c
@@ -54,14 +54,16 @@ static DEFINE_MUTEX(clocks_mutex);
 static struct clk *mpc5121_clk_get(struct device *dev, const char *id)
 {
 	struct clk *p, *clk = ERR_PTR(-ENOENT);
-	int dev_match = 0;
-	int id_match = 0;
+	int dev_match;
+	int id_match;
 
 	if (dev == NULL || id == NULL)
 		return clk;
 
 	mutex_lock(&clocks_mutex);
 	list_for_each_entry(p, &clocks, node) {
+		dev_match = id_match = 0;
+
 		if (dev == p->dev)
 			dev_match++;
 		if (strcmp(id, p->name) == 0)
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index cfe958e..1650e09 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -191,8 +191,6 @@ mpc512x_valid_monitor_port(enum fsl_diu_monitor_port port)
 
 static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
 
-#if defined(CONFIG_FB_FSL_DIU) || \
-    defined(CONFIG_FB_FSL_DIU_MODULE)
 static inline void mpc512x_free_bootmem(struct page *page)
 {
 	__ClearPageReserved(page);
@@ -220,7 +218,6 @@ void mpc512x_release_bootmem(void)
 	}
 	diu_ops.release_bootmem	= NULL;
 }
-#endif
 
 /*
  * Check if DIU was pre-initialized. If so, perform steps
@@ -323,15 +320,12 @@ void __init mpc512x_setup_diu(void)
 		}
 	}
 
-#if defined(CONFIG_FB_FSL_DIU) || \
-    defined(CONFIG_FB_FSL_DIU_MODULE)
 	diu_ops.get_pixel_format	= mpc512x_get_pixel_format;
 	diu_ops.set_gamma_table		= mpc512x_set_gamma_table;
 	diu_ops.set_monitor_port	= mpc512x_set_monitor_port;
 	diu_ops.set_pixel_clock		= mpc512x_set_pixel_clock;
 	diu_ops.valid_monitor_port	= mpc512x_valid_monitor_port;
 	diu_ops.release_bootmem		= mpc512x_release_bootmem;
-#endif
 }
 
 void __init mpc512x_init_IRQ(void)
diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c
index 4d786c2..3e70a20 100644
--- a/arch/powerpc/platforms/85xx/tqm85xx.c
+++ b/arch/powerpc/platforms/85xx/tqm85xx.c
@@ -102,7 +102,7 @@ static void tqm85xx_show_cpuinfo(struct seq_file *m)
 	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
 }
 
-static void __init tqm85xx_ti1520_fixup(struct pci_dev *pdev)
+static void __devinit tqm85xx_ti1520_fixup(struct pci_dev *pdev)
 {
 	unsigned int val;
 
diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c
index 1fca663..563aafa8 100644
--- a/arch/powerpc/platforms/86xx/gef_ppc9a.c
+++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c
@@ -164,7 +164,7 @@ static void gef_ppc9a_show_cpuinfo(struct seq_file *m)
 		gef_ppc9a_get_vme_is_syscon() ? "yes" : "no");
 }
 
-static void __init gef_ppc9a_nec_fixup(struct pci_dev *pdev)
+static void __devinit gef_ppc9a_nec_fixup(struct pci_dev *pdev)
 {
 	unsigned int val;
 
diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c
index 14e0e576..cc6a91a 100644
--- a/arch/powerpc/platforms/86xx/gef_sbc310.c
+++ b/arch/powerpc/platforms/86xx/gef_sbc310.c
@@ -152,7 +152,7 @@ static void gef_sbc310_show_cpuinfo(struct seq_file *m)
 
 }
 
-static void __init gef_sbc310_nec_fixup(struct pci_dev *pdev)
+static void __devinit gef_sbc310_nec_fixup(struct pci_dev *pdev)
 {
 	unsigned int val;
 
diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c
index 1638f43..aead6b3 100644
--- a/arch/powerpc/platforms/86xx/gef_sbc610.c
+++ b/arch/powerpc/platforms/86xx/gef_sbc610.c
@@ -141,7 +141,7 @@ static void gef_sbc610_show_cpuinfo(struct seq_file *m)
 	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 }
 
-static void __init gef_sbc610_nec_fixup(struct pci_dev *pdev)
+static void __devinit gef_sbc610_nec_fixup(struct pci_dev *pdev)
 {
 	unsigned int val;
 
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index a35ca44..e7a896a 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -25,6 +25,7 @@ source "arch/powerpc/platforms/wsp/Kconfig"
 config KVM_GUEST
 	bool "KVM Guest support"
 	default n
+	select EPAPR_PARAVIRT
 	---help---
 	  This option enables various optimizations for running under the KVM
 	  hypervisor. Overhead for the kernel when not running inside KVM should
@@ -32,6 +33,14 @@ config KVM_GUEST
 
 	  In case of doubt, say Y
 
+config EPAPR_PARAVIRT
+	bool "ePAPR para-virtualization support"
+	default n
+	help
+	  Enables ePAPR para-virtualization support for guests.
+
+	  In case of doubt, say Y
+
 config PPC_NATIVE
 	bool
 	depends on 6xx || PPC64
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index b9f509a..b673200 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -552,8 +552,7 @@ static struct iommu_table *cell_get_iommu_table(struct device *dev)
 	iommu = cell_iommu_for_node(dev_to_node(dev));
 	if (iommu == NULL || list_empty(&iommu->windows)) {
 		printk(KERN_ERR "iommu: missing iommu for %s (node %d)\n",
-		       dev->of_node ? dev->of_node->full_name : "?",
-		       dev_to_node(dev));
+		       of_node_full_name(dev->of_node), dev_to_node(dev));
 		return NULL;
 	}
 	window = list_entry(iommu->windows.next, struct iommu_window, list);
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index fbdd74d..9cda6a1 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -589,7 +589,7 @@ static int __devinit pnv_ioda_configure_pe(struct pnv_phb *phb,
 		dcomp = OPAL_IGNORE_RID_DEVICE_NUMBER;
 		fcomp = OPAL_IGNORE_RID_FUNCTION_NUMBER;
 		parent = pe->pbus->self;
-		count = pe->pbus->subordinate - pe->pbus->secondary + 1;
+		count = pe->pbus->busn_res.end - pe->pbus->busn_res.start + 1;
 		switch(count) {
 		case  1: bcomp = OpalPciBusAll;		break;
 		case  2: bcomp = OpalPciBus7Bits;	break;
@@ -816,11 +816,11 @@ static void __devinit pnv_ioda_setup_bus_PE(struct pci_dev *dev,
 	pe->pdev = NULL;
 	pe->tce32_seg = -1;
 	pe->mve_number = -1;
-	pe->rid = bus->secondary << 8;
+	pe->rid = bus->busn_res.start << 8;
 	pe->dma_weight = 0;
 
-	pe_info(pe, "Secondary busses %d..%d associated with PE\n",
-		bus->secondary, bus->subordinate);
+	pe_info(pe, "Secondary busses %pR associated with PE\n",
+		&bus->busn_res);
 
 	if (pnv_ioda_configure_pe(phb, pe)) {
 		/* XXX What do we do here ? */
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 0915b1a..aab5fbc 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -1051,7 +1051,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
 	if (!pdn || !PCI_DN(pdn)) {
 		printk(KERN_WARNING "pci_dma_dev_setup_pSeriesLP: "
 		       "no DMA window found for pci dev=%s dn=%s\n",
-				 pci_name(dev), dn? dn->full_name : "<null>");
+				 pci_name(dev), of_node_full_name(dn));
 		return;
 	}
 	pr_debug("  parent is %s\n", pdn->full_name);
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index 8b7bafa..3ccebc8 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -121,7 +121,7 @@ void pcibios_add_pci_devices(struct pci_bus * bus)
 		if (!num)
 			return;
 		pcibios_setup_bus_devices(bus);
-		max = bus->secondary;
+		max = bus->busn_res.start;
 		for (pass=0; pass < 2; pass++)
 			list_for_each_entry(dev, &bus->devices, bus_list) {
 			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 6073288..edbf794 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -36,7 +36,7 @@
 
 static int fsl_pcie_bus_fixup, is_mpc83xx_pci;
 
-static void __init quirk_fsl_pcie_header(struct pci_dev *dev)
+static void __devinit quirk_fsl_pcie_header(struct pci_dev *dev)
 {
 	u8 progif;
 
diff --git a/arch/powerpc/sysdev/mv64x60_pci.c b/arch/powerpc/sysdev/mv64x60_pci.c
index b0037ce..364b14d 100644
--- a/arch/powerpc/sysdev/mv64x60_pci.c
+++ b/arch/powerpc/sysdev/mv64x60_pci.c
@@ -104,7 +104,7 @@ subsys_initcall(mv64x60_sysfs_init);
 
 #endif /* CONFIG_SYSFS */
 
-static void __init mv64x60_pci_fixup_early(struct pci_dev *dev)
+static void __devinit mv64x60_pci_fixup_early(struct pci_dev *dev)
 {
 	/*
 	 * Set the host bridge hdr_type to an invalid value so that
diff --git a/arch/s390/crypto/crypto_des.h b/arch/s390/crypto/crypto_des.h
deleted file mode 100644
index 6210457..0000000
--- a/arch/s390/crypto/crypto_des.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Function for checking keys for the DES and Tripple DES Encryption
- * algorithms.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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 __CRYPTO_DES_H__
-#define __CRYPTO_DES_H__
-
-extern int crypto_des_check_key(const u8*, unsigned int, u32*);
-
-#endif /*__CRYPTO_DES_H__*/
diff --git a/arch/s390/include/asm/ccwgroup.h b/arch/s390/include/asm/ccwgroup.h
index f2ef34f..01a905e 100644
--- a/arch/s390/include/asm/ccwgroup.h
+++ b/arch/s390/include/asm/ccwgroup.h
@@ -6,14 +6,12 @@ struct ccw_driver;
 
 /**
  * struct ccwgroup_device - ccw group device
- * @creator_id: unique number of the driver
  * @state: online/offline state
  * @count: number of attached slave devices
  * @dev: embedded device structure
  * @cdev: variable number of slave devices, allocated as needed
  */
 struct ccwgroup_device {
-	unsigned long creator_id;
 	enum {
 		CCWGROUP_OFFLINE,
 		CCWGROUP_ONLINE,
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index 47853de..a47c6e2 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -302,12 +302,7 @@ struct _lowcore {
 	 */
 	__u64	ipib;				/* 0x0e00 */
 	__u32	ipib_checksum;			/* 0x0e08 */
-	/*
-	 * Because the vmcore_info pointer is not 8 byte aligned it never
-	 * should not be accessed directly. For accessing the pointer, first
-	 * copy it to a local pointer variable.
-	 */
-	__u8	vmcore_info[8];			/* 0x0e0c */
+	__u64	vmcore_info;			/* 0x0e0c */
 	__u8	pad_0x0e14[0x0e18-0x0e14];	/* 0x0e14 */
 	__u64	os_info;			/* 0x0e18 */
 	__u8	pad_0x0e20[0x0f00-0x0e20];	/* 0x0e20 */
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 20d0585..f1700c5 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -348,4 +348,14 @@ extern void (*s390_base_ext_handler_fn)(void);
 	".previous\n"
 #endif
 
+extern int memcpy_real(void *, void *, size_t);
+extern void memcpy_absolute(void *, void *, size_t);
+
+#define mem_assign_absolute(dest, val) {			\
+	__typeof__(dest) __tmp = (val);				\
+								\
+	BUILD_BUG_ON(sizeof(__tmp) != sizeof(val));		\
+	memcpy_absolute(&(dest), &__tmp, sizeof(__tmp));	\
+}
+
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index bf238c5..173f07a 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -55,5 +55,7 @@ int sclp_chp_configure(struct chp_id chpid);
 int sclp_chp_deconfigure(struct chp_id chpid);
 int sclp_chp_read_info(struct sclp_chp_info *info);
 void sclp_get_ipl_info(struct sclp_ipl_info *info);
+bool sclp_has_linemode(void);
+bool sclp_has_vt220(void);
 
 #endif /* _ASM_S390_SCLP_H */
diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h
new file mode 100644
index 0000000..7306270
--- /dev/null
+++ b/arch/s390/include/asm/sigp.h
@@ -0,0 +1,31 @@
+#ifndef __S390_ASM_SIGP_H
+#define __S390_ASM_SIGP_H
+
+/* SIGP order codes */
+#define SIGP_SENSE		      1
+#define SIGP_EXTERNAL_CALL	      2
+#define SIGP_EMERGENCY_SIGNAL	      3
+#define SIGP_STOP		      5
+#define SIGP_RESTART		      6
+#define SIGP_STOP_AND_STORE_STATUS    9
+#define SIGP_INITIAL_CPU_RESET	     11
+#define SIGP_SET_PREFIX		     13
+#define SIGP_STORE_STATUS_AT_ADDRESS 14
+#define SIGP_SET_ARCHITECTURE	     18
+#define SIGP_SENSE_RUNNING	     21
+
+/* SIGP condition codes */
+#define SIGP_CC_ORDER_CODE_ACCEPTED 0
+#define SIGP_CC_STATUS_STORED	    1
+#define SIGP_CC_BUSY		    2
+#define SIGP_CC_NOT_OPERATIONAL	    3
+
+/* SIGP cpu status bits */
+
+#define SIGP_STATUS_CHECK_STOP		0x00000010UL
+#define SIGP_STATUS_STOPPED		0x00000040UL
+#define SIGP_STATUS_INVALID_PARAMETER	0x00000100UL
+#define SIGP_STATUS_INCORRECT_STATE	0x00000200UL
+#define SIGP_STATUS_NOT_RUNNING		0x00000400UL
+
+#endif /* __S390_ASM_SIGP_H */
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index 4e40b25..5636ac4 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -93,8 +93,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_AUDIT	9	/* syscall auditing active */
 #define TIF_SECCOMP		10	/* secure computing */
 #define TIF_SYSCALL_TRACEPOINT	11	/* syscall tracepoint instrumentation */
-#define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling
-					   TIF_NEED_RESCHED */
 #define TIF_31BIT		17	/* 32bit process */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	19	/* restore signal mask in do_signal() */
@@ -102,7 +100,6 @@ static inline struct thread_info *current_thread_info(void)
 
 #define _TIF_SYSCALL		(1<<TIF_SYSCALL)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_PER_TRAP		(1<<TIF_PER_TRAP)
@@ -111,7 +108,6 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
 #define _TIF_SYSCALL_TRACEPOINT	(1<<TIF_SYSCALL_TRACEPOINT)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_31BIT		(1<<TIF_31BIT)
 #define _TIF_SINGLE_STEP	(1<<TIF_SINGLE_STEP)
 
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 1f3a79b..7e72851 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -381,8 +381,6 @@ clear_user(void __user *to, unsigned long n)
 	return n;
 }
 
-extern int memcpy_real(void *, void *, size_t);
-extern void memcpy_absolute(void *, void *, size_t);
 extern int copy_to_user_real(void __user *dest, void *src, size_t count);
 extern int copy_from_user_real(void *dest, void __user *src, size_t count);
 
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 83e6edf..0e974dd 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -131,6 +131,8 @@ int main(void)
 	DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack));
 	DEFINE(__LC_RESTART_STACK, offsetof(struct _lowcore, restart_stack));
 	DEFINE(__LC_RESTART_FN, offsetof(struct _lowcore, restart_fn));
+	DEFINE(__LC_RESTART_DATA, offsetof(struct _lowcore, restart_data));
+	DEFINE(__LC_RESTART_SOURCE, offsetof(struct _lowcore, restart_source));
 	DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce));
 	DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
 	DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S
index c880ff7..8c20d0e 100644
--- a/arch/s390/kernel/base.S
+++ b/arch/s390/kernel/base.S
@@ -9,6 +9,7 @@
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
 #include <asm/ptrace.h>
+#include <asm/sigp.h>
 
 #ifdef CONFIG_64BIT
 
@@ -100,7 +101,7 @@ ENTRY(diag308_reset)
 .Lrestart_part2:
 	lhi	%r0,0			# Load r0 with zero
 	lhi	%r1,2			# Use mode 2 = ESAME (dump)
-	sigp	%r1,%r0,0x12		# Switch to ESAME mode
+	sigp	%r1,%r0,SIGP_SET_ARCHITECTURE	# Switch to ESAME mode
 	sam64				# Switch to 64 bit addressing mode
 	larl	%r4,.Lctlregs		# Restore control registers
 	lctlg	%c0,%c15,0(%r4)
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 1ae93b5..4ea53cd 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -18,6 +18,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/unistd.h>
 #include <asm/page.h>
+#include <asm/sigp.h>
 
 __PT_R0      =	__PT_GPRS
 __PT_R1      =	__PT_GPRS + 4
@@ -723,15 +724,17 @@ ENTRY(restart_int_handler)
 	mvc	__PT_PSW(8,%r15),__LC_RST_OLD_PSW # store restart old psw
 	ahi	%r15,-STACK_FRAME_OVERHEAD	# create stack frame on stack
 	xc	0(STACK_FRAME_OVERHEAD,%r15),0(%r15)
-	lm	%r1,%r3,__LC_RESTART_FN		# load fn, parm & source cpu
+	l	%r1,__LC_RESTART_FN		# load fn, parm & source cpu
+	l	%r2,__LC_RESTART_DATA
+	l	%r3,__LC_RESTART_SOURCE
 	ltr	%r3,%r3				# test source cpu address
 	jm	1f				# negative -> skip source stop
-0:	sigp	%r4,%r3,1			# sigp sense to source cpu
+0:	sigp	%r4,%r3,SIGP_SENSE		# sigp sense to source cpu
 	brc	10,0b				# wait for status stored
 1:	basr	%r14,%r1			# call function
 	stap	__SF_EMPTY(%r15)		# store cpu address
 	lh	%r3,__SF_EMPTY(%r15)
-2:	sigp	%r4,%r3,5			# sigp stop to current cpu
+2:	sigp	%r4,%r3,SIGP_STOP		# sigp stop to current cpu
 	brc	2,2b
 3:	j	3b
 
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 229fe1d..2813e83 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -18,6 +18,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/unistd.h>
 #include <asm/page.h>
+#include <asm/sigp.h>
 
 __PT_R0      =	__PT_GPRS
 __PT_R1      =	__PT_GPRS + 8
@@ -750,15 +751,17 @@ ENTRY(restart_int_handler)
 	mvc	__PT_PSW(16,%r15),__LC_RST_OLD_PSW # store restart old psw
 	aghi	%r15,-STACK_FRAME_OVERHEAD	# create stack frame on stack
 	xc	0(STACK_FRAME_OVERHEAD,%r15),0(%r15)
-	lmg	%r1,%r3,__LC_RESTART_FN		# load fn, parm & source cpu
+	lg	%r1,__LC_RESTART_FN		# load fn, parm & source cpu
+	lg	%r2,__LC_RESTART_DATA
+	lg	%r3,__LC_RESTART_SOURCE
 	ltgr	%r3,%r3				# test source cpu address
 	jm	1f				# negative -> skip source stop
-0:	sigp	%r4,%r3,1			# sigp sense to source cpu
+0:	sigp	%r4,%r3,SIGP_SENSE		# sigp sense to source cpu
 	brc	10,0b				# wait for status stored
 1:	basr	%r14,%r1			# call function
 	stap	__SF_EMPTY(%r15)		# store cpu address
 	llgh	%r3,__SF_EMPTY(%r15)
-2:	sigp	%r4,%r3,5			# sigp stop to current cpu
+2:	sigp	%r4,%r3,SIGP_STOP		# sigp stop to current cpu
 	brc	2,2b
 3:	j	3b
 
@@ -974,7 +977,6 @@ ENTRY(sie64a)
 	stg	%r3,__SF_EMPTY+8(%r15)		# save guest register save area
 	xc	__SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # host id == 0
 	lmg	%r0,%r13,0(%r3)			# load guest gprs 0-13
-	lg	%r14,__LC_THREAD_INFO		# pointer thread_info struct
 sie_loop:
 	lg	%r14,__LC_THREAD_INFO		# pointer thread_info struct
 	tm	__TI_flags+7(%r14),_TIF_EXIT_SIE
diff --git a/arch/s390/kernel/head_kdump.S b/arch/s390/kernel/head_kdump.S
index 796c976..acaaaf4 100644
--- a/arch/s390/kernel/head_kdump.S
+++ b/arch/s390/kernel/head_kdump.S
@@ -5,6 +5,8 @@
  * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
  */
 
+#include <asm/sigp.h>
+
 #define DATAMOVER_ADDR	0x4000
 #define COPY_PAGE_ADDR	0x6000
 
@@ -19,7 +21,7 @@
 .align 2
 .Lep_startup_kdump:
 	lhi	%r1,2				# mode 2 = esame (dump)
-	sigp	%r1,%r0,0x12			# Switch to esame mode
+	sigp	%r1,%r0,SIGP_SET_ARCHITECTURE	# Switch to esame mode
 	sam64					# Switch to 64 bit addressing
 	basr	%r13,0
 .Lbase:
@@ -88,7 +90,7 @@ startup_kdump_relocated:
 	sam31					# Switch to 31 bit addr mode
 	sr	%r1,%r1				# Erase register r1
 	sr	%r2,%r2				# Erase register r2
-	sigp	%r1,%r2,0x12			# Switch to 31 bit arch mode
+	sigp	%r1,%r2,SIGP_SET_ARCHITECTURE	# Switch to 31 bit arch mode
 	lpsw	0				# Start new kernel...
 .align	8
 .Lrestart_psw:
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 2f6cfd4..25241cd 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -1528,15 +1528,12 @@ static struct shutdown_action __refdata dump_action = {
 
 static void dump_reipl_run(struct shutdown_trigger *trigger)
 {
-	struct {
-		void	*addr;
-		__u32	csum;
-	} __packed ipib;
-
-	ipib.csum = csum_partial(reipl_block_actual,
-				 reipl_block_actual->hdr.len, 0);
-	ipib.addr = reipl_block_actual;
-	memcpy_absolute(&S390_lowcore.ipib, &ipib, sizeof(ipib));
+	unsigned long ipib = (unsigned long) &reipl_block_actual;
+	unsigned int csum;
+
+	csum = csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0);
+	mem_assign_absolute(S390_lowcore.ipib, ipib);
+	mem_assign_absolute(S390_lowcore.ipib_checksum, csum);
 	dump_run(trigger);
 }
 
diff --git a/arch/s390/kernel/os_info.c b/arch/s390/kernel/os_info.c
index 95fa5ac..46480d8 100644
--- a/arch/s390/kernel/os_info.c
+++ b/arch/s390/kernel/os_info.c
@@ -60,7 +60,7 @@ void __init os_info_init(void)
 	os_info.version_minor = OS_INFO_VERSION_MINOR;
 	os_info.magic = OS_INFO_MAGIC;
 	os_info.csum = os_info_csum(&os_info);
-	memcpy_absolute(&S390_lowcore.os_info, &ptr, sizeof(ptr));
+	mem_assign_absolute(S390_lowcore.os_info, (unsigned long) ptr);
 }
 
 #ifdef CONFIG_CRASH_DUMP
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
index ad67c21..1c5e9e3 100644
--- a/arch/s390/kernel/reipl.S
+++ b/arch/s390/kernel/reipl.S
@@ -8,6 +8,7 @@
 
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
+#include <asm/sigp.h>
 
 #
 # store_status: Empty implementation until kdump is supported on 31 bit
@@ -60,7 +61,7 @@ ENTRY(do_reipl_asm)
 		bas	%r14,.Ldisab-.Lpg0(%r13)
 .L003:		st	%r1,__LC_SUBCHANNEL_ID
 		lpsw	0
-		sigp	0,0,0(6)
+		sigp	0,0,SIGP_RESTART
 .Ldisab:	st	%r14,.Ldispsw+4-.Lpg0(%r13)
 		lpsw	.Ldispsw-.Lpg0(%r13)
 		.align	8
diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S
index 36b3265..02f5a73 100644
--- a/arch/s390/kernel/reipl64.S
+++ b/arch/s390/kernel/reipl64.S
@@ -6,6 +6,7 @@
 
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
+#include <asm/sigp.h>
 
 #
 # store_status
@@ -106,7 +107,7 @@ ENTRY(do_reipl_asm)
 .L003:		st	%r1,__LC_SUBCHANNEL_ID
 		lhi	%r1,0		 # mode 0 = esa
 		slr	%r0,%r0 	 # set cpuid to zero
-		sigp	%r1,%r0,0x12	 # switch to esa mode
+		sigp	%r1,%r0,SIGP_SET_ARCHITECTURE # switch to esa mode
 		lpsw	0
 .Ldisab:	sll	%r14,1
 		srl	%r14,1		 # need to kill hi bit to avoid specification exceptions.
diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S
index c91d70a..bfad96a 100644
--- a/arch/s390/kernel/relocate_kernel.S
+++ b/arch/s390/kernel/relocate_kernel.S
@@ -9,6 +9,7 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/sigp.h>
 
 /*
  * moves the new kernel to its destination...
@@ -93,7 +94,7 @@ ENTRY(relocate_kernel)
 	.no_diag308:
 		sr	%r1,%r1		# clear %r1
 		sr	%r2,%r2		# clear %r2
-		sigp	%r1,%r2,0x12	# set cpuid to zero
+		sigp	%r1,%r2,SIGP_SET_ARCHITECTURE # set cpuid to zero
 		lpsw	0		# hopefully start new kernel...
 
 		.align	8
diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S
index 7c3ce58..35508f3 100644
--- a/arch/s390/kernel/relocate_kernel64.S
+++ b/arch/s390/kernel/relocate_kernel64.S
@@ -9,6 +9,7 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/sigp.h>
 
 /*
  * moves the new kernel to its destination...
@@ -45,7 +46,7 @@ ENTRY(relocate_kernel)
 		diag	%r0,%r0,0x308
 	.back:
 		lhi	%r1,1		# mode 1 = esame
-		sigp	%r1,%r0,0x12	# switch to esame mode
+		sigp	%r1,%r0,SIGP_SET_ARCHITECTURE # switch to esame mode
 		sam64			# switch to 64 bit addressing mode
 		basr	%r13,0
 	.back_base:
@@ -96,7 +97,7 @@ ENTRY(relocate_kernel)
 		sam31			# 31 bit mode
 		sr	%r1,%r1		# erase register r1
 		sr	%r2,%r2		# erase register r2
-		sigp	%r1,%r2,0x12	# set cpuid to zero
+		sigp	%r1,%r2,SIGP_SET_ARCHITECTURE # set cpuid to zero
 		lpsw	0		# hopefully start new kernel...
 
 		.align	8
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 489d1d8..0ecf484 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -63,6 +63,7 @@
 #include <asm/kvm_virtio.h>
 #include <asm/diag.h>
 #include <asm/os_info.h>
+#include <asm/sclp.h>
 #include "entry.h"
 
 long psw_kernel_bits	= PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_ASC_PRIMARY |
@@ -138,9 +139,14 @@ __setup("condev=", condev_setup);
 
 static void __init set_preferred_console(void)
 {
-	if (MACHINE_IS_KVM)
-		add_preferred_console("hvc", 0, NULL);
-	else if (CONSOLE_IS_3215 || CONSOLE_IS_SCLP)
+	if (MACHINE_IS_KVM) {
+		if (sclp_has_vt220())
+			add_preferred_console("ttyS", 1, NULL);
+		else if (sclp_has_linemode())
+			add_preferred_console("ttyS", 0, NULL);
+		else
+			add_preferred_console("hvc", 0, NULL);
+	} else if (CONSOLE_IS_3215 || CONSOLE_IS_SCLP)
 		add_preferred_console("ttyS", 0, NULL);
 	else if (CONSOLE_IS_3270)
 		add_preferred_console("tty3270", 0, NULL);
@@ -430,10 +436,11 @@ static void __init setup_lowcore(void)
 	lc->restart_source = -1UL;
 
 	/* Setup absolute zero lowcore */
-	memcpy_absolute(&S390_lowcore.restart_stack, &lc->restart_stack,
-			4 * sizeof(unsigned long));
-	memcpy_absolute(&S390_lowcore.restart_psw, &lc->restart_psw,
-			sizeof(lc->restart_psw));
+	mem_assign_absolute(S390_lowcore.restart_stack, lc->restart_stack);
+	mem_assign_absolute(S390_lowcore.restart_fn, lc->restart_fn);
+	mem_assign_absolute(S390_lowcore.restart_data, lc->restart_data);
+	mem_assign_absolute(S390_lowcore.restart_source, lc->restart_source);
+	mem_assign_absolute(S390_lowcore.restart_psw, lc->restart_psw);
 
 	set_prefix((u32)(unsigned long) lc);
 	lowcore_ptr[0] = lc;
@@ -598,9 +605,7 @@ static void __init setup_memory_end(void)
 static void __init setup_vmcoreinfo(void)
 {
 #ifdef CONFIG_KEXEC
-	unsigned long ptr = paddr_vmcoreinfo_note();
-
-	memcpy_absolute(&S390_lowcore.vmcore_info, &ptr, sizeof(ptr));
+	mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note());
 #endif
 }
 
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 15cca26..ac6134a 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -44,34 +44,10 @@
 #include <asm/vdso.h>
 #include <asm/debug.h>
 #include <asm/os_info.h>
+#include <asm/sigp.h>
 #include "entry.h"
 
 enum {
-	sigp_sense = 1,
-	sigp_external_call = 2,
-	sigp_emergency_signal = 3,
-	sigp_start = 4,
-	sigp_stop = 5,
-	sigp_restart = 6,
-	sigp_stop_and_store_status = 9,
-	sigp_initial_cpu_reset = 11,
-	sigp_cpu_reset = 12,
-	sigp_set_prefix = 13,
-	sigp_store_status_at_address = 14,
-	sigp_store_extended_status_at_address = 15,
-	sigp_set_architecture = 18,
-	sigp_conditional_emergency_signal = 19,
-	sigp_sense_running = 21,
-};
-
-enum {
-	sigp_order_code_accepted = 0,
-	sigp_status_stored = 1,
-	sigp_busy = 2,
-	sigp_not_operational = 3,
-};
-
-enum {
 	ec_schedule = 0,
 	ec_call_function,
 	ec_call_function_single,
@@ -124,7 +100,7 @@ static inline int __pcpu_sigp_relax(u16 addr, u8 order, u32 parm, u32 *status)
 
 	while (1) {
 		cc = __pcpu_sigp(addr, order, parm, status);
-		if (cc != sigp_busy)
+		if (cc != SIGP_CC_BUSY)
 			return cc;
 		cpu_relax();
 	}
@@ -136,7 +112,7 @@ static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm)
 
 	for (retry = 0; ; retry++) {
 		cc = __pcpu_sigp(pcpu->address, order, parm, &pcpu->status);
-		if (cc != sigp_busy)
+		if (cc != SIGP_CC_BUSY)
 			break;
 		if (retry >= 3)
 			udelay(10);
@@ -146,20 +122,19 @@ static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm)
 
 static inline int pcpu_stopped(struct pcpu *pcpu)
 {
-	if (__pcpu_sigp(pcpu->address, sigp_sense,
-			0, &pcpu->status) != sigp_status_stored)
+	if (__pcpu_sigp(pcpu->address, SIGP_SENSE,
+			0, &pcpu->status) != SIGP_CC_STATUS_STORED)
 		return 0;
-	/* Check for stopped and check stop state */
-	return !!(pcpu->status & 0x50);
+	return !!(pcpu->status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED));
 }
 
 static inline int pcpu_running(struct pcpu *pcpu)
 {
-	if (__pcpu_sigp(pcpu->address, sigp_sense_running,
-			0, &pcpu->status) != sigp_status_stored)
+	if (__pcpu_sigp(pcpu->address, SIGP_SENSE_RUNNING,
+			0, &pcpu->status) != SIGP_CC_STATUS_STORED)
 		return 1;
-	/* Check for running status */
-	return !(pcpu->status & 0x400);
+	/* Status stored condition code is equivalent to cpu not running. */
+	return 0;
 }
 
 /*
@@ -181,7 +156,7 @@ static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit)
 
 	set_bit(ec_bit, &pcpu->ec_mask);
 	order = pcpu_running(pcpu) ?
-		sigp_external_call : sigp_emergency_signal;
+		SIGP_EXTERNAL_CALL : SIGP_EMERGENCY_SIGNAL;
 	pcpu_sigp_retry(pcpu, order, 0);
 }
 
@@ -214,7 +189,7 @@ static int __cpuinit pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
 		goto out;
 #endif
 	lowcore_ptr[cpu] = lc;
-	pcpu_sigp_retry(pcpu, sigp_set_prefix, (u32)(unsigned long) lc);
+	pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, (u32)(unsigned long) lc);
 	return 0;
 out:
 	if (pcpu != &pcpu_devices[0]) {
@@ -229,7 +204,7 @@ out:
 
 static void pcpu_free_lowcore(struct pcpu *pcpu)
 {
-	pcpu_sigp_retry(pcpu, sigp_set_prefix, 0);
+	pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0);
 	lowcore_ptr[pcpu - pcpu_devices] = NULL;
 #ifndef CONFIG_64BIT
 	if (MACHINE_HAS_IEEE) {
@@ -288,7 +263,7 @@ static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data)
 	lc->restart_fn = (unsigned long) func;
 	lc->restart_data = (unsigned long) data;
 	lc->restart_source = -1UL;
-	pcpu_sigp_retry(pcpu, sigp_restart, 0);
+	pcpu_sigp_retry(pcpu, SIGP_RESTART, 0);
 }
 
 /*
@@ -298,26 +273,26 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
 			  void *data, unsigned long stack)
 {
 	struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices];
-	struct {
-		unsigned long	stack;
-		void		*func;
-		void		*data;
-		unsigned long	source;
-	} restart = { stack, func, data, stap() };
+	unsigned long source_cpu = stap();
 
 	__load_psw_mask(psw_kernel_bits);
-	if (pcpu->address == restart.source)
+	if (pcpu->address == source_cpu)
 		func(data);	/* should not return */
 	/* Stop target cpu (if func returns this stops the current cpu). */
-	pcpu_sigp_retry(pcpu, sigp_stop, 0);
+	pcpu_sigp_retry(pcpu, SIGP_STOP, 0);
 	/* Restart func on the target cpu and stop the current cpu. */
-	memcpy_absolute(&lc->restart_stack, &restart, sizeof(restart));
+	mem_assign_absolute(lc->restart_stack, stack);
+	mem_assign_absolute(lc->restart_fn, (unsigned long) func);
+	mem_assign_absolute(lc->restart_data, (unsigned long) data);
+	mem_assign_absolute(lc->restart_source, source_cpu);
 	asm volatile(
-		"0:	sigp	0,%0,6	# sigp restart to target cpu\n"
+		"0:	sigp	0,%0,%2	# sigp restart to target cpu\n"
 		"	brc	2,0b	# busy, try again\n"
-		"1:	sigp	0,%1,5	# sigp stop to current cpu\n"
+		"1:	sigp	0,%1,%3	# sigp stop to current cpu\n"
 		"	brc	2,1b	# busy, try again\n"
-		: : "d" (pcpu->address), "d" (restart.source) : "0", "1", "cc");
+		: : "d" (pcpu->address), "d" (source_cpu),
+		    "K" (SIGP_RESTART), "K" (SIGP_STOP)
+		: "0", "1", "cc");
 	for (;;) ;
 }
 
@@ -388,8 +363,8 @@ void smp_emergency_stop(cpumask_t *cpumask)
 	for_each_cpu(cpu, cpumask) {
 		struct pcpu *pcpu = pcpu_devices + cpu;
 		set_bit(ec_stop_cpu, &pcpu->ec_mask);
-		while (__pcpu_sigp(pcpu->address, sigp_emergency_signal,
-				   0, NULL) == sigp_busy &&
+		while (__pcpu_sigp(pcpu->address, SIGP_EMERGENCY_SIGNAL,
+				   0, NULL) == SIGP_CC_BUSY &&
 		       get_clock() < end)
 			cpu_relax();
 	}
@@ -425,7 +400,7 @@ void smp_send_stop(void)
 	/* stop all processors */
 	for_each_cpu(cpu, &cpumask) {
 		struct pcpu *pcpu = pcpu_devices + cpu;
-		pcpu_sigp_retry(pcpu, sigp_stop, 0);
+		pcpu_sigp_retry(pcpu, SIGP_STOP, 0);
 		while (!pcpu_stopped(pcpu))
 			cpu_relax();
 	}
@@ -436,7 +411,7 @@ void smp_send_stop(void)
  */
 void smp_stop_cpu(void)
 {
-	pcpu_sigp_retry(pcpu_devices + smp_processor_id(), sigp_stop, 0);
+	pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
 	for (;;) ;
 }
 
@@ -590,7 +565,7 @@ static void __init smp_get_save_area(int cpu, u16 address)
 	}
 #endif
 	/* Get the registers of a non-boot cpu. */
-	__pcpu_sigp_relax(address, sigp_stop_and_store_status, 0, NULL);
+	__pcpu_sigp_relax(address, SIGP_STOP_AND_STORE_STATUS, 0, NULL);
 	memcpy_real(save_area, lc + SAVE_AREA_BASE, sizeof(*save_area));
 }
 
@@ -599,8 +574,8 @@ int smp_store_status(int cpu)
 	struct pcpu *pcpu;
 
 	pcpu = pcpu_devices + cpu;
-	if (__pcpu_sigp_relax(pcpu->address, sigp_stop_and_store_status,
-			      0, NULL) != sigp_order_code_accepted)
+	if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS,
+			      0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED)
 		return -EIO;
 	return 0;
 }
@@ -621,8 +596,8 @@ static struct sclp_cpu_info *smp_get_cpu_info(void)
 	if (info && (use_sigp_detection || sclp_get_cpu_info(info))) {
 		use_sigp_detection = 1;
 		for (address = 0; address <= MAX_CPU_ADDRESS; address++) {
-			if (__pcpu_sigp_relax(address, sigp_sense, 0, NULL) ==
-			    sigp_not_operational)
+			if (__pcpu_sigp_relax(address, SIGP_SENSE, 0, NULL) ==
+			    SIGP_CC_NOT_OPERATIONAL)
 				continue;
 			info->cpu[info->configured].address = address;
 			info->configured++;
@@ -717,9 +692,7 @@ static void __cpuinit smp_start_secondary(void *cpuvoid)
 	init_cpu_vtimer();
 	pfault_init();
 	notify_cpu_starting(smp_processor_id());
-	ipi_call_lock();
 	set_cpu_online(smp_processor_id(), true);
-	ipi_call_unlock();
 	local_irq_enable();
 	/* cpu_idle will call schedule for us */
 	cpu_idle();
@@ -734,8 +707,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
 	pcpu = pcpu_devices + cpu;
 	if (pcpu->state != CPU_STATE_CONFIGURED)
 		return -EIO;
-	if (pcpu_sigp_retry(pcpu, sigp_initial_cpu_reset, 0) !=
-	    sigp_order_code_accepted)
+	if (pcpu_sigp_retry(pcpu, SIGP_INITIAL_CPU_RESET, 0) !=
+	    SIGP_CC_ORDER_CODE_ACCEPTED)
 		return -EIO;
 
 	rc = pcpu_alloc_lowcore(pcpu, cpu);
@@ -795,7 +768,7 @@ void __cpu_die(unsigned int cpu)
 void __noreturn cpu_die(void)
 {
 	idle_task_exit();
-	pcpu_sigp_retry(pcpu_devices + smp_processor_id(), sigp_stop, 0);
+	pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
 	for (;;) ;
 }
 
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S
index dd70ef0..d4ca4e0 100644
--- a/arch/s390/kernel/swsusp_asm64.S
+++ b/arch/s390/kernel/swsusp_asm64.S
@@ -12,6 +12,7 @@
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
 #include <asm/asm-offsets.h>
+#include <asm/sigp.h>
 
 /*
  * Save register context in absolute 0 lowcore and call swsusp_save() to
@@ -163,7 +164,7 @@ ENTRY(swsusp_arch_resume)
 	diag	%r0,%r0,0x308
 restart_entry:
 	lhi	%r1,1
-	sigp	%r1,%r0,0x12
+	sigp	%r1,%r0,SIGP_SET_ARCHITECTURE
 	sam64
 	larl	%r1,.Lnew_pgm_check_psw
 	lpswe	0(%r1)
@@ -179,7 +180,7 @@ pgm_check_entry:
 	larl	%r4,.Lrestart_suspend_psw	/* Set new restart PSW */
 	mvc	__LC_RST_NEW_PSW(16,%r0),0(%r4)
 3:
-	sigp	%r9,%r1,11			/* sigp initial cpu reset */
+	sigp	%r9,%r1,SIGP_INITIAL_CPU_RESET	/* sigp initial cpu reset */
 	brc	8,4f				/* accepted */
 	brc	2,3b				/* busy, try again */
 
@@ -190,16 +191,16 @@ pgm_check_entry:
 	larl	%r3,_sclp_print_early
 	lghi	%r1,0
 	sam31
-	sigp	%r1,%r0,0x12
+	sigp	%r1,%r0,SIGP_SET_ARCHITECTURE
 	basr	%r14,%r3
 	larl	%r3,.Ldisabled_wait_31
 	lpsw	0(%r3)
 4:
 	/* Switch to suspend CPU */
-	sigp	%r9,%r1,6		/* sigp restart to suspend CPU */
+	sigp	%r9,%r1,SIGP_RESTART	/* sigp restart to suspend CPU */
 	brc	2,4b			/* busy, try again */
 5:
-	sigp	%r9,%r2,5		/* sigp stop to current resume CPU */
+	sigp	%r9,%r2,SIGP_STOP	/* sigp stop to current resume CPU */
 	brc	2,5b			/* busy, try again */
 6:	j	6b
 
@@ -207,7 +208,7 @@ restart_suspend:
 	larl	%r1,.Lresume_cpu
 	llgh	%r2,0(%r1)
 7:
-	sigp	%r9,%r2,1		/* sigp sense, wait for resume CPU */
+	sigp	%r9,%r2,SIGP_SENSE	/* sigp sense, wait for resume CPU */
 	brc	8,7b			/* accepted, status 0, still running */
 	brc	2,7b			/* busy, try again */
 	tmll	%r9,0x40		/* Test if resume CPU is stopped */
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 664766d..ace9360 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -347,6 +347,7 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
 	vcpu->arch.guest_fpregs.fpc = 0;
 	asm volatile("lfpc %0" : : "Q" (vcpu->arch.guest_fpregs.fpc));
 	vcpu->arch.sie_block->gbea = 1;
+	atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
 }
 
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 0ad4cf2..fda1d64 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -15,38 +15,10 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/slab.h>
+#include <asm/sigp.h>
 #include "gaccess.h"
 #include "kvm-s390.h"
 
-/* sigp order codes */
-#define SIGP_SENSE             0x01
-#define SIGP_EXTERNAL_CALL     0x02
-#define SIGP_EMERGENCY         0x03
-#define SIGP_START             0x04
-#define SIGP_STOP              0x05
-#define SIGP_RESTART           0x06
-#define SIGP_STOP_STORE_STATUS 0x09
-#define SIGP_INITIAL_CPU_RESET 0x0b
-#define SIGP_CPU_RESET         0x0c
-#define SIGP_SET_PREFIX        0x0d
-#define SIGP_STORE_STATUS_ADDR 0x0e
-#define SIGP_SET_ARCH          0x12
-#define SIGP_SENSE_RUNNING     0x15
-
-/* cpu status bits */
-#define SIGP_STAT_EQUIPMENT_CHECK   0x80000000UL
-#define SIGP_STAT_NOT_RUNNING	    0x00000400UL
-#define SIGP_STAT_INCORRECT_STATE   0x00000200UL
-#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
-#define SIGP_STAT_EXT_CALL_PENDING  0x00000080UL
-#define SIGP_STAT_STOPPED           0x00000040UL
-#define SIGP_STAT_OPERATOR_INTERV   0x00000020UL
-#define SIGP_STAT_CHECK_STOP        0x00000010UL
-#define SIGP_STAT_INOPERATIVE       0x00000004UL
-#define SIGP_STAT_INVALID_ORDER     0x00000002UL
-#define SIGP_STAT_RECEIVER_CHECK    0x00000001UL
-
-
 static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
 			u64 *reg)
 {
@@ -65,7 +37,7 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
 		rc = 1; /* status stored */
 	} else {
 		*reg &= 0xffffffff00000000UL;
-		*reg |= SIGP_STAT_STOPPED;
+		*reg |= SIGP_STATUS_STOPPED;
 		rc = 1; /* status stored */
 	}
 	spin_unlock(&fi->lock);
@@ -235,7 +207,7 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
 	address = address & 0x7fffe000u;
 	if (copy_from_guest_absolute(vcpu, &tmp, address, 1) ||
 	   copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1)) {
-		*reg |= SIGP_STAT_INVALID_PARAMETER;
+		*reg |= SIGP_STATUS_INVALID_PARAMETER;
 		return 1; /* invalid parameter */
 	}
 
@@ -249,7 +221,7 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
 
 	if (li == NULL) {
 		rc = 1; /* incorrect state */
-		*reg &= SIGP_STAT_INCORRECT_STATE;
+		*reg &= SIGP_STATUS_INCORRECT_STATE;
 		kfree(inti);
 		goto out_fi;
 	}
@@ -258,7 +230,7 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
 	/* cpu must be in stopped state */
 	if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
 		rc = 1; /* incorrect state */
-		*reg &= SIGP_STAT_INCORRECT_STATE;
+		*reg &= SIGP_STATUS_INCORRECT_STATE;
 		kfree(inti);
 		goto out_li;
 	}
@@ -300,7 +272,7 @@ static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
 		} else {
 			/* not running */
 			*reg &= 0xffffffff00000000UL;
-			*reg |= SIGP_STAT_NOT_RUNNING;
+			*reg |= SIGP_STATUS_NOT_RUNNING;
 			rc = 0;
 		}
 	}
@@ -375,7 +347,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
 		vcpu->stat.instruction_sigp_external_call++;
 		rc = __sigp_external_call(vcpu, cpu_addr);
 		break;
-	case SIGP_EMERGENCY:
+	case SIGP_EMERGENCY_SIGNAL:
 		vcpu->stat.instruction_sigp_emergency++;
 		rc = __sigp_emergency(vcpu, cpu_addr);
 		break;
@@ -383,12 +355,12 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
 		vcpu->stat.instruction_sigp_stop++;
 		rc = __sigp_stop(vcpu, cpu_addr, ACTION_STOP_ON_STOP);
 		break;
-	case SIGP_STOP_STORE_STATUS:
+	case SIGP_STOP_AND_STORE_STATUS:
 		vcpu->stat.instruction_sigp_stop++;
 		rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP |
 						 ACTION_STOP_ON_STOP);
 		break;
-	case SIGP_SET_ARCH:
+	case SIGP_SET_ARCHITECTURE:
 		vcpu->stat.instruction_sigp_arch++;
 		rc = __sigp_set_arch(vcpu, parameter);
 		break;
diff --git a/arch/score/include/asm/thread_info.h b/arch/score/include/asm/thread_info.h
index a18006e9..1425cc0 100644
--- a/arch/score/include/asm/thread_info.h
+++ b/arch/score/include/asm/thread_info.h
@@ -86,16 +86,12 @@ register struct thread_info *__current_thread_info __asm__("r28");
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
 #define TIF_NOTIFY_RESUME	5	/* callback before returning to user */
 #define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal() */
-#define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling
-						 TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 #define _TIF_WORK_MASK		(0x0000ffff)
 
diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c
index e382c52..c268bbf 100644
--- a/arch/score/kernel/signal.c
+++ b/arch/score/kernel/signal.c
@@ -174,6 +174,7 @@ score_rt_sigreturn(struct pt_regs *regs)
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
 	do_sigaltstack((stack_t __user *)&st, NULL, regs->regs[0]);
+	regs->is_syscall = 0;
 
 	__asm__ __volatile__(
 		"mv\tr0, %0\n\t"
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 31d9db7..a24595d 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -60,6 +60,7 @@ config SUPERH32
 
 config SUPERH64
 	def_bool ARCH = "sh64"
+	select KALLSYMS
 
 config ARCH_DEFCONFIG
 	string
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 1f56b35..7048c03 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -44,6 +44,8 @@ config SH_7721_SOLUTION_ENGINE
 config SH_7722_SOLUTION_ENGINE
 	bool "SolutionEngine7722"
 	select SOLUTION_ENGINE
+	select GENERIC_IRQ_CHIP
+	select IRQ_DOMAIN
 	depends on CPU_SUBTYPE_SH7722
 	help
 	  Select 7722 SolutionEngine if configuring for a Hitachi SH772
@@ -80,6 +82,8 @@ config SH_7780_SOLUTION_ENGINE
 config SH_7343_SOLUTION_ENGINE
 	bool "SolutionEngine7343"
 	select SOLUTION_ENGINE
+	select GENERIC_IRQ_CHIP
+	select IRQ_DOMAIN
 	depends on CPU_SUBTYPE_SH7343
 	help
 	  Select 7343 SolutionEngine if configuring for a Hitachi
@@ -295,6 +299,7 @@ config SH_X3PROTO
 	bool "SH-X3 Prototype board"
 	depends on CPU_SUBTYPE_SHX3
 	select NO_IOPORT if !PCI
+	select IRQ_DOMAIN
 
 config SH_MAGIC_PANEL_R2
 	bool "Magic Panel R2"
diff --git a/arch/sh/boards/mach-dreamcast/irq.c b/arch/sh/boards/mach-dreamcast/irq.c
index f63d323..2789647 100644
--- a/arch/sh/boards/mach-dreamcast/irq.c
+++ b/arch/sh/boards/mach-dreamcast/irq.c
@@ -8,10 +8,11 @@
  * This file is part of the LinuxDC project (www.linuxdc.org)
  * Released under the terms of the GNU GPL v2.0
  */
-
 #include <linux/irq.h>
 #include <linux/io.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
+#include <linux/export.h>
+#include <linux/err.h>
 #include <mach/sysasic.h>
 
 /*
@@ -141,26 +142,15 @@ int systemasic_irq_demux(int irq)
 
 void systemasic_irq_init(void)
 {
-	int i, nid = cpu_to_node(boot_cpu_data);
-
-	/* Assign all virtual IRQs to the System ASIC int. handler */
-	for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++) {
-		unsigned int irq;
-
-		irq = create_irq_nr(i, nid);
-		if (unlikely(irq == 0)) {
-			pr_err("%s: failed hooking irq %d for systemasic\n",
-			       __func__, i);
-			return;
-		}
+	int irq_base, i;
 
-		if (unlikely(irq != i)) {
-			pr_err("%s: got irq %d but wanted %d, bailing.\n",
-			       __func__, irq, i);
-			destroy_irq(irq);
-			return;
-		}
+	irq_base = irq_alloc_descs(HW_EVENT_IRQ_BASE, HW_EVENT_IRQ_BASE,
+				   HW_EVENT_IRQ_MAX - HW_EVENT_IRQ_BASE, -1);
+	if (IS_ERR_VALUE(irq_base)) {
+		pr_err("%s: failed hooking irqs\n", __func__);
+		return;
+	}
 
+	for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
 		irq_set_chip_and_handler(i, &systemasic_int, handle_level_irq);
-	}
 }
diff --git a/arch/sh/boards/mach-se/7343/irq.c b/arch/sh/boards/mach-se/7343/irq.c
index fd45ffc..7646bf0 100644
--- a/arch/sh/boards/mach-se/7343/irq.c
+++ b/arch/sh/boards/mach-se/7343/irq.c
@@ -1,86 +1,129 @@
 /*
- * linux/arch/sh/boards/se/7343/irq.c
+ * Hitachi UL SolutionEngine 7343 FPGA IRQ Support.
  *
  * Copyright (C) 2008  Yoshihiro Shimoda
+ * Copyright (C) 2012  Paul Mundt
  *
- * Based on linux/arch/sh/boards/se/7722/irq.c
+ * Based on linux/arch/sh/boards/se/7343/irq.c
  * Copyright (C) 2007  Nobuhiro Iwamatsu
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#define DRV_NAME "SE7343-FPGA"
+#define pr_fmt(fmt) DRV_NAME ": " fmt
+
+#define irq_reg_readl	ioread16
+#define irq_reg_writel	iowrite16
+
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/io.h>
+#include <asm/sizes.h>
 #include <mach-se/mach/se7343.h>
 
-unsigned int se7343_fpga_irq[SE7343_FPGA_IRQ_NR] = { 0, };
+#define PA_CPLD_BASE_ADDR	0x11400000
+#define PA_CPLD_ST_REG		0x08	/* CPLD Interrupt status register */
+#define PA_CPLD_IMSK_REG	0x0a	/* CPLD Interrupt mask register */
 
-static void disable_se7343_irq(struct irq_data *data)
-{
-	unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
-	__raw_writew(__raw_readw(PA_CPLD_IMSK) | 1 << bit, PA_CPLD_IMSK);
-}
+static void __iomem *se7343_irq_regs;
+struct irq_domain *se7343_irq_domain;
 
-static void enable_se7343_irq(struct irq_data *data)
+static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
-	unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
-	__raw_writew(__raw_readw(PA_CPLD_IMSK) & ~(1 << bit), PA_CPLD_IMSK);
-}
+	struct irq_data *data = irq_get_irq_data(irq);
+	struct irq_chip *chip = irq_data_get_irq_chip(data);
+	unsigned long mask;
+	int bit;
 
-static struct irq_chip se7343_irq_chip __read_mostly = {
-	.name		= "SE7343-FPGA",
-	.irq_mask	= disable_se7343_irq,
-	.irq_unmask	= enable_se7343_irq,
-};
+	chip->irq_mask_ack(data);
 
-static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc)
+	mask = ioread16(se7343_irq_regs + PA_CPLD_ST_REG);
+
+	for_each_set_bit(bit, &mask, SE7343_FPGA_IRQ_NR)
+		generic_handle_irq(irq_linear_revmap(se7343_irq_domain, bit));
+
+	chip->irq_unmask(data);
+}
+
+static void __init se7343_domain_init(void)
 {
-	unsigned short intv = __raw_readw(PA_CPLD_ST);
-	unsigned int ext_irq = 0;
+	int i;
 
-	intv &= (1 << SE7343_FPGA_IRQ_NR) - 1;
+	se7343_irq_domain = irq_domain_add_linear(NULL, SE7343_FPGA_IRQ_NR,
+						  &irq_domain_simple_ops, NULL);
+	if (unlikely(!se7343_irq_domain)) {
+		printk("Failed to get IRQ domain\n");
+		return;
+	}
 
-	for (; intv; intv >>= 1, ext_irq++) {
-		if (!(intv & 1))
-			continue;
+	for (i = 0; i < SE7343_FPGA_IRQ_NR; i++) {
+		int irq = irq_create_mapping(se7343_irq_domain, i);
 
-		generic_handle_irq(se7343_fpga_irq[ext_irq]);
+		if (unlikely(irq == 0)) {
+			printk("Failed to allocate IRQ %d\n", i);
+			return;
+		}
 	}
 }
 
-/*
- * Initialize IRQ setting
- */
-void __init init_7343se_IRQ(void)
+static void __init se7343_gc_init(void)
 {
-	int i, irq;
+	struct irq_chip_generic *gc;
+	struct irq_chip_type *ct;
+	unsigned int irq_base;
 
-	__raw_writew(0, PA_CPLD_IMSK);	/* disable all irqs */
-	__raw_writew(0x2000, 0xb03fffec);	/* mrshpc irq enable */
+	irq_base = irq_linear_revmap(se7343_irq_domain, 0);
 
-	for (i = 0; i < SE7343_FPGA_IRQ_NR; i++) {
-		irq = create_irq();
-		if (irq < 0)
-			return;
-		se7343_fpga_irq[i] = irq;
+	gc = irq_alloc_generic_chip(DRV_NAME, 1, irq_base, se7343_irq_regs,
+				    handle_level_irq);
+	if (unlikely(!gc))
+		return;
 
-		irq_set_chip_and_handler_name(se7343_fpga_irq[i],
-					      &se7343_irq_chip,
-					      handle_level_irq,
-					      "level");
+	ct = gc->chip_types;
+	ct->chip.irq_mask = irq_gc_mask_set_bit;
+	ct->chip.irq_unmask = irq_gc_mask_clr_bit;
 
-		irq_set_chip_data(se7343_fpga_irq[i], (void *)i);
-	}
+	ct->regs.mask = PA_CPLD_IMSK_REG;
+
+	irq_setup_generic_chip(gc, IRQ_MSK(SE7343_FPGA_IRQ_NR),
+			       IRQ_GC_INIT_MASK_CACHE,
+			       IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 
 	irq_set_chained_handler(IRQ0_IRQ, se7343_irq_demux);
 	irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
+
 	irq_set_chained_handler(IRQ1_IRQ, se7343_irq_demux);
 	irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
+
 	irq_set_chained_handler(IRQ4_IRQ, se7343_irq_demux);
 	irq_set_irq_type(IRQ4_IRQ, IRQ_TYPE_LEVEL_LOW);
+
 	irq_set_chained_handler(IRQ5_IRQ, se7343_irq_demux);
 	irq_set_irq_type(IRQ5_IRQ, IRQ_TYPE_LEVEL_LOW);
 }
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_7343se_IRQ(void)
+{
+	se7343_irq_regs = ioremap(PA_CPLD_BASE_ADDR, SZ_16);
+	if (unlikely(!se7343_irq_regs)) {
+		pr_err("Failed to remap CPLD\n");
+		return;
+	}
+
+	/*
+	 * All FPGA IRQs disabled by default
+	 */
+	iowrite16(0, se7343_irq_regs + PA_CPLD_IMSK_REG);
+
+	__raw_writew(0x2000, 0xb03fffec);	/* mrshpc irq enable */
+
+	se7343_domain_init();
+	se7343_gc_init();
+}
diff --git a/arch/sh/boards/mach-se/7343/setup.c b/arch/sh/boards/mach-se/7343/setup.c
index d2370af..8ce4f2a 100644
--- a/arch/sh/boards/mach-se/7343/setup.c
+++ b/arch/sh/boards/mach-se/7343/setup.c
@@ -5,6 +5,7 @@
 #include <linux/serial_reg.h>
 #include <linux/usb/isp116x.h>
 #include <linux/delay.h>
+#include <linux/irqdomain.h>
 #include <asm/machvec.h>
 #include <mach-se/mach/se7343.h>
 #include <asm/heartbeat.h>
@@ -145,11 +146,12 @@ static struct platform_device *sh7343se_platform_devices[] __initdata = {
 static int __init sh7343se_devices_setup(void)
 {
 	/* Wire-up dynamic vectors */
-	serial_platform_data[0].irq = se7343_fpga_irq[SE7343_FPGA_IRQ_UARTA];
-	serial_platform_data[1].irq = se7343_fpga_irq[SE7343_FPGA_IRQ_UARTB];
-
+	serial_platform_data[0].irq = irq_find_mapping(se7343_irq_domain,
+						       SE7343_FPGA_IRQ_UARTA);
+	serial_platform_data[1].irq = irq_find_mapping(se7343_irq_domain,
+						       SE7343_FPGA_IRQ_UARTB);
 	usb_resources[2].start = usb_resources[2].end =
-		se7343_fpga_irq[SE7343_FPGA_IRQ_USB];
+		irq_find_mapping(se7343_irq_domain, SE7343_FPGA_IRQ_USB);
 
 	return platform_add_devices(sh7343se_platform_devices,
 				    ARRAY_SIZE(sh7343se_platform_devices));
diff --git a/arch/sh/boards/mach-se/7722/irq.c b/arch/sh/boards/mach-se/7722/irq.c
index aac92f2..f5e2af1 100644
--- a/arch/sh/boards/mach-se/7722/irq.c
+++ b/arch/sh/boards/mach-se/7722/irq.c
@@ -1,79 +1,96 @@
 /*
- * linux/arch/sh/boards/se/7722/irq.c
+ * Hitachi UL SolutionEngine 7722 FPGA IRQ Support.
  *
  * Copyright (C) 2007  Nobuhiro Iwamatsu
- *
- * Hitachi UL SolutionEngine 7722 Support.
+ * Copyright (C) 2012  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#define DRV_NAME "SE7722-FPGA"
+#define pr_fmt(fmt) DRV_NAME ": " fmt
+
+#define irq_reg_readl	ioread16
+#define irq_reg_writel	iowrite16
+
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
-#include <asm/io.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <asm/sizes.h>
 #include <mach-se/mach/se7722.h>
 
-unsigned int se7722_fpga_irq[SE7722_FPGA_IRQ_NR] = { 0, };
+#define IRQ01_BASE_ADDR	0x11800000
+#define IRQ01_MODE_REG	0
+#define IRQ01_STS_REG	4
+#define IRQ01_MASK_REG	8
 
-static void disable_se7722_irq(struct irq_data *data)
-{
-	unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
-	__raw_writew(__raw_readw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
-}
+static void __iomem *se7722_irq_regs;
+struct irq_domain *se7722_irq_domain;
 
-static void enable_se7722_irq(struct irq_data *data)
+static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
-	unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
-	__raw_writew(__raw_readw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK);
-}
+	struct irq_data *data = irq_get_irq_data(irq);
+	struct irq_chip *chip = irq_data_get_irq_chip(data);
+	unsigned long mask;
+	int bit;
 
-static struct irq_chip se7722_irq_chip __read_mostly = {
-	.name		= "SE7722-FPGA",
-	.irq_mask	= disable_se7722_irq,
-	.irq_unmask	= enable_se7722_irq,
-};
+	chip->irq_mask_ack(data);
 
-static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
+	mask = ioread16(se7722_irq_regs + IRQ01_STS_REG);
+
+	for_each_set_bit(bit, &mask, SE7722_FPGA_IRQ_NR)
+		generic_handle_irq(irq_linear_revmap(se7722_irq_domain, bit));
+
+	chip->irq_unmask(data);
+}
+
+static void __init se7722_domain_init(void)
 {
-	unsigned short intv = __raw_readw(IRQ01_STS);
-	unsigned int ext_irq = 0;
+	int i;
 
-	intv &= (1 << SE7722_FPGA_IRQ_NR) - 1;
+	se7722_irq_domain = irq_domain_add_linear(NULL, SE7722_FPGA_IRQ_NR,
+						  &irq_domain_simple_ops, NULL);
+	if (unlikely(!se7722_irq_domain)) {
+		printk("Failed to get IRQ domain\n");
+		return;
+	}
 
-	for (; intv; intv >>= 1, ext_irq++) {
-		if (!(intv & 1))
-			continue;
+	for (i = 0; i < SE7722_FPGA_IRQ_NR; i++) {
+		int irq = irq_create_mapping(se7722_irq_domain, i);
 
-		generic_handle_irq(se7722_fpga_irq[ext_irq]);
+		if (unlikely(irq == 0)) {
+			printk("Failed to allocate IRQ %d\n", i);
+			return;
+		}
 	}
 }
 
-/*
- * Initialize IRQ setting
- */
-void __init init_se7722_IRQ(void)
+static void __init se7722_gc_init(void)
 {
-	int i, irq;
+	struct irq_chip_generic *gc;
+	struct irq_chip_type *ct;
+	unsigned int irq_base;
 
-	__raw_writew(0, IRQ01_MASK);       /* disable all irqs */
-	__raw_writew(0x2000, 0xb03fffec);  /* mrshpc irq enable */
+	irq_base = irq_linear_revmap(se7722_irq_domain, 0);
 
-	for (i = 0; i < SE7722_FPGA_IRQ_NR; i++) {
-		irq = create_irq();
-		if (irq < 0)
-			return;
-		se7722_fpga_irq[i] = irq;
+	gc = irq_alloc_generic_chip(DRV_NAME, 1, irq_base, se7722_irq_regs,
+				    handle_level_irq);
+	if (unlikely(!gc))
+		return;
 
-		irq_set_chip_and_handler_name(se7722_fpga_irq[i],
-					      &se7722_irq_chip,
-					      handle_level_irq,
-					      "level");
+	ct = gc->chip_types;
+	ct->chip.irq_mask = irq_gc_mask_set_bit;
+	ct->chip.irq_unmask = irq_gc_mask_clr_bit;
 
-		irq_set_chip_data(se7722_fpga_irq[i], (void *)i);
-	}
+	ct->regs.mask = IRQ01_MASK_REG;
+
+	irq_setup_generic_chip(gc, IRQ_MSK(SE7722_FPGA_IRQ_NR),
+			       IRQ_GC_INIT_MASK_CACHE,
+			       IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 
 	irq_set_chained_handler(IRQ0_IRQ, se7722_irq_demux);
 	irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
@@ -81,3 +98,25 @@ void __init init_se7722_IRQ(void)
 	irq_set_chained_handler(IRQ1_IRQ, se7722_irq_demux);
 	irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
 }
+
+/*
+ * Initialize FPGA IRQs
+ */
+void __init init_se7722_IRQ(void)
+{
+	se7722_irq_regs = ioremap(IRQ01_BASE_ADDR, SZ_16);
+	if (unlikely(!se7722_irq_regs)) {
+		printk("Failed to remap IRQ01 regs\n");
+		return;
+	}
+
+	/*
+	 * All FPGA IRQs disabled by default
+	 */
+	iowrite16(0, se7722_irq_regs + IRQ01_MASK_REG);
+
+	__raw_writew(0x2000, 0xb03fffec);  /* mrshpc irq enable */
+
+	se7722_domain_init();
+	se7722_gc_init();
+}
diff --git a/arch/sh/boards/mach-se/7722/setup.c b/arch/sh/boards/mach-se/7722/setup.c
index 8f7f055..e04e2bc 100644
--- a/arch/sh/boards/mach-se/7722/setup.c
+++ b/arch/sh/boards/mach-se/7722/setup.c
@@ -2,6 +2,7 @@
  * linux/arch/sh/boards/se/7722/setup.c
  *
  * Copyright (C) 2007 Nobuhiro Iwamatsu
+ * Copyright (C) 2012 Paul Mundt
  *
  * Hitachi UL SolutionEngine 7722 Support.
  *
@@ -15,6 +16,7 @@
 #include <linux/ata_platform.h>
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
+#include <linux/irqdomain.h>
 #include <linux/smc91x.h>
 #include <linux/sh_intc.h>
 #include <mach-se/mach/se7722.h>
@@ -143,10 +145,10 @@ static int __init se7722_devices_setup(void)
 
 	/* Wire-up dynamic vectors */
 	cf_ide_resources[2].start = cf_ide_resources[2].end =
-		se7722_fpga_irq[SE7722_FPGA_IRQ_MRSHPC0];
+		irq_find_mapping(se7722_irq_domain, SE7722_FPGA_IRQ_MRSHPC0);
 
 	smc91x_eth_resources[1].start = smc91x_eth_resources[1].end =
-		se7722_fpga_irq[SE7722_FPGA_IRQ_SMC];
+		irq_find_mapping(se7722_irq_domain, SE7722_FPGA_IRQ_SMC);
 
 	return platform_add_devices(se7722_devices, ARRAY_SIZE(se7722_devices));
 }
diff --git a/arch/sh/boards/mach-se/7724/irq.c b/arch/sh/boards/mach-se/7724/irq.c
index c6342ce..5d1d3ec 100644
--- a/arch/sh/boards/mach-se/7724/irq.c
+++ b/arch/sh/boards/mach-se/7724/irq.c
@@ -17,8 +17,10 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
-#include <asm/io.h>
+#include <linux/export.h>
+#include <linux/topology.h>
+#include <linux/io.h>
+#include <linux/err.h>
 #include <mach-se/mach/se7724.h>
 
 struct fpga_irq {
@@ -111,7 +113,7 @@ static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc)
  */
 void __init init_se7724_IRQ(void)
 {
-	int i, nid = cpu_to_node(boot_cpu_data);
+	int irq_base, i;
 
 	__raw_writew(0xffff, IRQ0_MR);  /* mask all */
 	__raw_writew(0xffff, IRQ1_MR);  /* mask all */
@@ -121,28 +123,16 @@ void __init init_se7724_IRQ(void)
 	__raw_writew(0x0000, IRQ2_SR);  /* clear irq */
 	__raw_writew(0x002a, IRQ_MODE); /* set irq type */
 
-	for (i = 0; i < SE7724_FPGA_IRQ_NR; i++) {
-		int irq, wanted;
-
-		wanted = SE7724_FPGA_IRQ_BASE + i;
-
-		irq = create_irq_nr(wanted, nid);
-		if (unlikely(irq == 0)) {
-			pr_err("%s: failed hooking irq %d for FPGA\n",
-			       __func__, wanted);
-			return;
-		}
-
-		if (unlikely(irq != wanted)) {
-			pr_err("%s: got irq %d but wanted %d, bailing.\n",
-			       __func__, irq, wanted);
-			destroy_irq(irq);
-			return;
-		}
+	irq_base = irq_alloc_descs(SE7724_FPGA_IRQ_BASE, SE7724_FPGA_IRQ_BASE,
+				   SE7724_FPGA_IRQ_NR, numa_node_id());
+	if (IS_ERR_VALUE(irq_base)) {
+		pr_err("%s: failed hooking irqs for FPGA\n", __func__);
+		return;
+	}
 
-		irq_set_chip_and_handler_name(irq, &se7724_irq_chip,
+	for (i = 0; i < SE7724_FPGA_IRQ_NR; i++)
+		irq_set_chip_and_handler_name(irq_base + i, &se7724_irq_chip,
 					      handle_level_irq, "level");
-	}
 
 	irq_set_chained_handler(IRQ0_IRQ, se7724_irq_demux);
 	irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
diff --git a/arch/sh/boards/mach-x3proto/gpio.c b/arch/sh/boards/mach-x3proto/gpio.c
index f33b2b5..3ea65e9 100644
--- a/arch/sh/boards/mach-x3proto/gpio.c
+++ b/arch/sh/boards/mach-x3proto/gpio.c
@@ -3,7 +3,7 @@
  *
  * Renesas SH-X3 Prototype Baseboard GPIO Support.
  *
- * Copyright (C) 2010  Paul Mundt
+ * Copyright (C) 2010 - 2012  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -17,6 +17,7 @@
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
+#include <linux/irqdomain.h>
 #include <linux/io.h>
 #include <mach/ilsel.h>
 #include <mach/hardware.h>
@@ -26,7 +27,7 @@
 #define KEYDETR 0xb81c0004
 
 static DEFINE_SPINLOCK(x3proto_gpio_lock);
-static unsigned int x3proto_gpio_irq_map[NR_BASEBOARD_GPIOS] = { 0, };
+static struct irq_domain *x3proto_irq_domain;
 
 static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 {
@@ -49,7 +50,14 @@ static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio)
 
 static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
 {
-	return x3proto_gpio_irq_map[gpio];
+	int virq;
+
+	if (gpio < chip->ngpio)
+		virq = irq_create_mapping(x3proto_irq_domain, gpio);
+	else
+		virq = -ENXIO;
+
+	return virq;
 }
 
 static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
@@ -62,9 +70,8 @@ static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 	chip->irq_mask_ack(data);
 
 	mask = __raw_readw(KEYDETR);
-
 	for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)
-		generic_handle_irq(x3proto_gpio_to_irq(NULL, pin));
+		generic_handle_irq(irq_linear_revmap(x3proto_irq_domain, pin));
 
 	chip->irq_unmask(data);
 }
@@ -78,10 +85,23 @@ struct gpio_chip x3proto_gpio_chip = {
 	.ngpio			= NR_BASEBOARD_GPIOS,
 };
 
+static int x3proto_gpio_irq_map(struct irq_domain *domain, unsigned int virq,
+				irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler_name(virq, &dummy_irq_chip, handle_simple_irq,
+				      "gpio");
+
+	return 0;
+}
+
+static struct irq_domain_ops x3proto_gpio_irq_ops = {
+	.map	= x3proto_gpio_irq_map,
+	.xlate	= irq_domain_xlate_twocell,
+};
+
 int __init x3proto_gpio_setup(void)
 {
-	int ilsel;
-	int ret, i;
+	int ilsel, ret;
 
 	ilsel = ilsel_enable(ILSEL_KEY);
 	if (unlikely(ilsel < 0))
@@ -91,21 +111,10 @@ int __init x3proto_gpio_setup(void)
 	if (unlikely(ret))
 		goto err_gpio;
 
-	for (i = 0; i < NR_BASEBOARD_GPIOS; i++) {
-		unsigned long flags;
-		int irq = create_irq();
-
-		if (unlikely(irq < 0)) {
-			ret = -EINVAL;
-			goto err_irq;
-		}
-
-		spin_lock_irqsave(&x3proto_gpio_lock, flags);
-		x3proto_gpio_irq_map[i] = irq;
-		irq_set_chip_and_handler_name(irq, &dummy_irq_chip,
-					      handle_simple_irq, "gpio");
-		spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
-	}
+	x3proto_irq_domain = irq_domain_add_linear(NULL, NR_BASEBOARD_GPIOS,
+						   &x3proto_gpio_irq_ops, NULL);
+	if (unlikely(!x3proto_irq_domain))
+		goto err_irq;
 
 	pr_info("registering '%s' support, handling GPIOs %u -> %u, "
 		"bound to IRQ %u\n",
@@ -119,10 +128,6 @@ int __init x3proto_gpio_setup(void)
 	return 0;
 
 err_irq:
-	for (; i >= 0; --i)
-		if (x3proto_gpio_irq_map[i])
-			destroy_irq(x3proto_gpio_irq_map[i]);
-
 	ret = gpiochip_remove(&x3proto_gpio_chip);
 	if (unlikely(ret))
 		pr_err("Failed deregistering GPIO\n");
diff --git a/arch/sh/cchips/hd6446x/hd64461.c b/arch/sh/cchips/hd6446x/hd64461.c
index eb4ea4d..e973561 100644
--- a/arch/sh/cchips/hd6446x/hd64461.c
+++ b/arch/sh/cchips/hd6446x/hd64461.c
@@ -73,10 +73,7 @@ static void hd64461_irq_demux(unsigned int irq, struct irq_desc *desc)
 
 int __init setup_hd64461(void)
 {
-	int i, nid = cpu_to_node(boot_cpu_data);
-
-	if (!MACH_HD64461)
-		return 0;
+	int irq_base, i;
 
 	printk(KERN_INFO
 	       "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n",
@@ -89,28 +86,16 @@ int __init setup_hd64461(void)
 #endif
 	__raw_writew(0xffff, HD64461_NIMR);
 
-	/*  IRQ 80 -> 95 belongs to HD64461  */
-	for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) {
-		unsigned int irq;
-
-		irq = create_irq_nr(i, nid);
-		if (unlikely(irq == 0)) {
-			pr_err("%s: failed hooking irq %d for HD64461\n",
-			       __func__, i);
-			return -EBUSY;
-		}
-
-		if (unlikely(irq != i)) {
-			pr_err("%s: got irq %d but wanted %d, bailing.\n",
-			       __func__, irq, i);
-			destroy_irq(irq);
-			return -EINVAL;
-		}
-
-		irq_set_chip_and_handler(i, &hd64461_irq_chip,
-					 handle_level_irq);
+	irq_base = irq_alloc_descs(HD64461_IRQBASE, HD64461_IRQBASE, 16, -1);
+	if (IS_ERR_VALUE(irq_base)) {
+		pr_err("%s: failed hooking irqs for HD64461\n", __func__);
+		return irq_base;
 	}
 
+	for (i = 0; i < 16; i++)
+		irq_set_chip_and_handler(irq_base + i, &hd64461_irq_chip,
+					 handle_level_irq);
+
 	irq_set_chained_handler(CONFIG_HD64461_IRQ, hd64461_irq_demux);
 	irq_set_irq_type(CONFIG_HD64461_IRQ, IRQ_TYPE_LEVEL_LOW);
 
diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c
index edeea89..a5fe1b5 100644
--- a/arch/sh/drivers/pci/fixups-dreamcast.c
+++ b/arch/sh/drivers/pci/fixups-dreamcast.c
@@ -28,7 +28,7 @@
 #include <asm/irq.h>
 #include <mach/pci.h>
 
-static void __init gapspci_fixup_resources(struct pci_dev *dev)
+static void __devinit gapspci_fixup_resources(struct pci_dev *dev)
 {
 	struct pci_channel *p = dev->sysdata;
 
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 9d10a3c..43068dc 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -59,7 +59,7 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose)
 	need_domain_info = need_domain_info || hose->index;
 	hose->need_domain_info = need_domain_info;
 	if (bus) {
-		next_busno = bus->subordinate + 1;
+		next_busno = bus->busn_res.end + 1;
 		/* Don't allow 8-bit bus number overflow inside the hose -
 		   reserve some space for bridges. */
 		if (next_busno > 224) {
diff --git a/arch/sh/include/asm/bug.h b/arch/sh/include/asm/bug.h
index 2b87d86..dcf2780 100644
--- a/arch/sh/include/asm/bug.h
+++ b/arch/sh/include/asm/bug.h
@@ -110,6 +110,10 @@ do {							\
 #include <asm-generic/bug.h>
 
 struct pt_regs;
+
+/* arch/sh/kernel/traps.c */
 extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn));
+extern void die_if_kernel(const char *str, struct pt_regs *regs, long err);
+extern void die_if_no_fixup(const char *str, struct pt_regs *regs, long err);
 
 #endif /* __ASM_SH_BUG_H */
diff --git a/arch/sh/include/asm/kdebug.h b/arch/sh/include/asm/kdebug.h
index a6201f1..8d6a831 100644
--- a/arch/sh/include/asm/kdebug.h
+++ b/arch/sh/include/asm/kdebug.h
@@ -10,6 +10,8 @@ enum die_val {
 	DIE_SSTEP,
 };
 
+/* arch/sh/kernel/dumpstack.c */
 extern void printk_address(unsigned long address, int reliable);
+extern void dump_mem(const char *str, unsigned long bottom, unsigned long top);
 
 #endif /* __ASM_SH_KDEBUG_H */
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h
index bc13b57..7d5ac4e 100644
--- a/arch/sh/include/asm/thread_info.h
+++ b/arch/sh/include/asm/thread_info.h
@@ -206,6 +206,9 @@ static inline bool test_and_clear_restore_sigmask(void)
 	ti->status &= ~TS_RESTORE_SIGMASK;
 	return true;
 }
+
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif	/* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/sh/include/mach-se/mach/se7343.h b/arch/sh/include/mach-se/mach/se7343.h
index 50b5d57..542521c 100644
--- a/arch/sh/include/mach-se/mach/se7343.h
+++ b/arch/sh/include/mach-se/mach/se7343.h
@@ -50,9 +50,6 @@
 #define PA_LED		0xb0C00000	/* LED */
 #define LED_SHIFT       0
 #define PA_DIPSW	0xb0900000	/* Dip switch 31 */
-#define PA_CPLD_MODESET	0xb1400004	/* CPLD Mode set register */
-#define PA_CPLD_ST	0xb1400008	/* CPLD Interrupt status register */
-#define PA_CPLD_IMSK	0xb140000a	/* CPLD Interrupt mask register */
 /* Area 5 */
 #define PA_EXT5		0x14000000
 #define PA_EXT5_SIZE	0x04000000
@@ -135,8 +132,10 @@
 
 #define SE7343_FPGA_IRQ_NR	12
 
+struct irq_domain;
+
 /* arch/sh/boards/se/7343/irq.c */
-extern unsigned int se7343_fpga_irq[];
+extern struct irq_domain *se7343_irq_domain;
 
 void init_7343se_IRQ(void);
 
diff --git a/arch/sh/include/mach-se/mach/se7722.h b/arch/sh/include/mach-se/mach/se7722.h
index 201081e..637e7ac 100644
--- a/arch/sh/include/mach-se/mach/se7722.h
+++ b/arch/sh/include/mach-se/mach/se7722.h
@@ -81,12 +81,6 @@
 #define IRQ0_IRQ        evt2irq(0x600)
 #define IRQ1_IRQ        evt2irq(0x620)
 
-#define IRQ01_MODE      0xb1800000
-#define IRQ01_STS       0xb1800004
-#define IRQ01_MASK      0xb1800008
-
-/* Bits in IRQ01_* registers */
-
 #define SE7722_FPGA_IRQ_USB	0 /* IRQ0 */
 #define SE7722_FPGA_IRQ_SMC	1 /* IRQ0 */
 #define SE7722_FPGA_IRQ_MRSHPC0	2 /* IRQ1 */
@@ -95,8 +89,10 @@
 #define SE7722_FPGA_IRQ_MRSHPC3	5 /* IRQ1 */
 #define SE7722_FPGA_IRQ_NR	6
 
+struct irq_domain;
+
 /* arch/sh/boards/se/7722/irq.c */
-extern unsigned int se7722_fpga_irq[];
+extern struct irq_domain *se7722_irq_domain;
 
 void init_se7722_IRQ(void);
 
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index b7cf6a5..0170508 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -933,7 +933,7 @@ ret_with_reschedule:
 
 	pta	restore_all, tr1
 
-	movi	_TIF_SIGPENDING, r8
+	movi	_TIF_SIGPENDING|_TIF_NOTIFY_RESUME, r8
 	and	r8, r7, r8
 	pta	work_notifysig, tr0
 	bne	r8, ZERO, tr0
diff --git a/arch/sh/kernel/cpu/sh5/unwind.c b/arch/sh/kernel/cpu/sh5/unwind.c
index b205b25..10aed41 100644
--- a/arch/sh/kernel/cpu/sh5/unwind.c
+++ b/arch/sh/kernel/cpu/sh5/unwind.c
@@ -16,6 +16,8 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/io.h>
+#include <asm/unwinder.h>
+#include <asm/stacktrace.h>
 
 static u8 regcache[63];
 
@@ -199,8 +201,11 @@ static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc,
 	return 0;
 }
 
-/* Don't put this on the stack since we'll want to call sh64_unwind
- * when we're close to underflowing the stack anyway. */
+/*
+ * Don't put this on the stack since we'll want to call in to
+ * sh64_unwinder_dump() when we're close to underflowing the stack
+ * anyway.
+ */
 static struct pt_regs here_regs;
 
 extern const char syscall_ret;
@@ -208,17 +213,19 @@ extern const char ret_from_syscall;
 extern const char ret_from_exception;
 extern const char ret_from_irq;
 
-static void sh64_unwind_inner(struct pt_regs *regs);
+static void sh64_unwind_inner(const struct stacktrace_ops *ops,
+			      void *data, struct pt_regs *regs);
 
-static void unwind_nested (unsigned long pc, unsigned long fp)
+static inline void unwind_nested(const struct stacktrace_ops *ops, void *data,
+				 unsigned long pc, unsigned long fp)
 {
 	if ((fp >= __MEMORY_START) &&
-	    ((fp & 7) == 0)) {
-		sh64_unwind_inner((struct pt_regs *) fp);
-	}
+	    ((fp & 7) == 0))
+		sh64_unwind_inner(ops, data, (struct pt_regs *)fp);
 }
 
-static void sh64_unwind_inner(struct pt_regs *regs)
+static void sh64_unwind_inner(const struct stacktrace_ops *ops,
+			      void *data, struct pt_regs *regs)
 {
 	unsigned long pc, fp;
 	int ofs = 0;
@@ -232,29 +239,29 @@ static void sh64_unwind_inner(struct pt_regs *regs)
 		int cond;
 		unsigned long next_fp, next_pc;
 
-		if (pc == ((unsigned long) &syscall_ret & ~1)) {
+		if (pc == ((unsigned long)&syscall_ret & ~1)) {
 			printk("SYSCALL\n");
-			unwind_nested(pc,fp);
+			unwind_nested(ops, data, pc, fp);
 			return;
 		}
 
-		if (pc == ((unsigned long) &ret_from_syscall & ~1)) {
+		if (pc == ((unsigned long)&ret_from_syscall & ~1)) {
 			printk("SYSCALL (PREEMPTED)\n");
-			unwind_nested(pc,fp);
+			unwind_nested(ops, data, pc, fp);
 			return;
 		}
 
 		/* In this case, the PC is discovered by lookup_prev_stack_frame but
 		   it has 4 taken off it to look like the 'caller' */
-		if (pc == ((unsigned long) &ret_from_exception & ~1)) {
+		if (pc == ((unsigned long)&ret_from_exception & ~1)) {
 			printk("EXCEPTION\n");
-			unwind_nested(pc,fp);
+			unwind_nested(ops, data, pc, fp);
 			return;
 		}
 
-		if (pc == ((unsigned long) &ret_from_irq & ~1)) {
+		if (pc == ((unsigned long)&ret_from_irq & ~1)) {
 			printk("IRQ\n");
-			unwind_nested(pc,fp);
+			unwind_nested(ops, data, pc, fp);
 			return;
 		}
 
@@ -263,8 +270,7 @@ static void sh64_unwind_inner(struct pt_regs *regs)
 
 		pc -= ofs;
 
-		printk("[<%08lx>] ", pc);
-		print_symbol("%s\n", pc);
+		ops->address(data, pc, 1);
 
 		if (first_pass) {
 			/* If the innermost frame is a leaf function, it's
@@ -287,10 +293,13 @@ static void sh64_unwind_inner(struct pt_regs *regs)
 	}
 
 	printk("\n");
-
 }
 
-void sh64_unwind(struct pt_regs *regs)
+static void sh64_unwinder_dump(struct task_struct *task,
+			       struct pt_regs *regs,
+			       unsigned long *sp,
+			       const struct stacktrace_ops *ops,
+			       void *data)
 {
 	if (!regs) {
 		/*
@@ -320,7 +329,17 @@ void sh64_unwind(struct pt_regs *regs)
 		);
 	}
 
-	printk("\nCall Trace:\n");
-	sh64_unwind_inner(regs);
+	sh64_unwind_inner(ops, data, regs);
 }
 
+static struct unwinder sh64_unwinder = {
+	.name	= "sh64-unwinder",
+	.dump	= sh64_unwinder_dump,
+	.rating	= 150,
+};
+
+static int __init sh64_unwinder_init(void)
+{
+	return unwinder_register(&sh64_unwinder);
+}
+early_initcall(sh64_unwinder_init);
diff --git a/arch/sh/kernel/dumpstack.c b/arch/sh/kernel/dumpstack.c
index 694158b..7617dc4 100644
--- a/arch/sh/kernel/dumpstack.c
+++ b/arch/sh/kernel/dumpstack.c
@@ -2,13 +2,48 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
  *  Copyright (C) 2009  Matt Fleming
+ *  Copyright (C) 2002 - 2012  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
  */
 #include <linux/kallsyms.h>
 #include <linux/ftrace.h>
 #include <linux/debug_locks.h>
+#include <linux/kdebug.h>
+#include <linux/export.h>
+#include <linux/uaccess.h>
 #include <asm/unwinder.h>
 #include <asm/stacktrace.h>
 
+void dump_mem(const char *str, unsigned long bottom, unsigned long top)
+{
+	unsigned long p;
+	int i;
+
+	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
+
+	for (p = bottom & ~31; p < top; ) {
+		printk("%04lx: ", p & 0xffff);
+
+		for (i = 0; i < 8; i++, p += 4) {
+			unsigned int val;
+
+			if (p < bottom || p >= top)
+				printk("         ");
+			else {
+				if (__get_user(val, (unsigned int __user *)p)) {
+					printk("\n");
+					return;
+				}
+				printk("%08x ", val);
+			}
+		}
+		printk("\n");
+	}
+}
+
 void printk_address(unsigned long address, int reliable)
 {
 	printk(" [<%p>] %s%pS\n", (void *) address,
@@ -106,3 +141,26 @@ void show_trace(struct task_struct *tsk, unsigned long *sp,
 
 	debug_show_held_locks(tsk);
 }
+
+void show_stack(struct task_struct *tsk, unsigned long *sp)
+{
+	unsigned long stack;
+
+	if (!tsk)
+		tsk = current;
+	if (tsk == current)
+		sp = (unsigned long *)current_stack_pointer;
+	else
+		sp = (unsigned long *)tsk->thread.sp;
+
+	stack = (unsigned long)sp;
+	dump_mem("Stack: ", stack, THREAD_SIZE +
+		 (unsigned long)task_stack_page(tsk));
+	show_trace(tsk, sp, NULL);
+}
+
+void dump_stack(void)
+{
+	show_stack(NULL, NULL);
+}
+EXPORT_SYMBOL(dump_stack);
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index f67601c..f4a7a05 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -139,7 +139,7 @@ work_pending:
 	! r8: current_thread_info
 	! t:  result of "tst	#_TIF_NEED_RESCHED, r0"
 	bf/s	work_resched
-	 tst	#_TIF_SIGPENDING, r0
+	 tst	#_TIF_SIGPENDING|_TIF_NOTIFY_RESUME, r0
 work_notifysig:
 	bt/s	__restore_all
 	 mov	r15, r4
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index dadce73..063af10 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -231,16 +231,6 @@ void __init init_IRQ(void)
 	irq_ctx_init(smp_processor_id());
 }
 
-#ifdef CONFIG_SPARSE_IRQ
-int __init arch_probe_nr_irqs(void)
-{
-	/*
-	 * No pre-allocated IRQs.
-	 */
-	return 0;
-}
-#endif
-
 #ifdef CONFIG_HOTPLUG_CPU
 static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
 {
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index d6b7b61..2f1f653 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -22,7 +22,6 @@
 #include <linux/elf.h>
 #include <linux/personality.h>
 #include <linux/binfmts.h>
-#include <linux/freezer.h>
 #include <linux/io.h>
 #include <linux/tracehook.h>
 #include <asm/ucontext.h>
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index 6b5b3df..2385381 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -18,7 +18,6 @@
 #include <linux/errno.h>
 #include <linux/wait.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index a87e58a..72246bc 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -6,9 +6,80 @@
 #include <linux/sched.h>
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/module.h>
 #include <asm/unwinder.h>
 #include <asm/traps.h>
 
+static DEFINE_SPINLOCK(die_lock);
+
+void die(const char *str, struct pt_regs *regs, long err)
+{
+	static int die_counter;
+
+	oops_enter();
+
+	spin_lock_irq(&die_lock);
+	console_verbose();
+	bust_spinlocks(1);
+
+	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
+	print_modules();
+	show_regs(regs);
+
+	printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
+			task_pid_nr(current), task_stack_page(current) + 1);
+
+	if (!user_mode(regs) || in_interrupt())
+		dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
+			 (unsigned long)task_stack_page(current));
+
+	notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV);
+
+	bust_spinlocks(0);
+	add_taint(TAINT_DIE);
+	spin_unlock_irq(&die_lock);
+	oops_exit();
+
+	if (kexec_should_crash(current))
+		crash_kexec(regs);
+
+	if (in_interrupt())
+		panic("Fatal exception in interrupt");
+
+	if (panic_on_oops)
+		panic("Fatal exception");
+
+	do_exit(SIGSEGV);
+}
+
+void die_if_kernel(const char *str, struct pt_regs *regs, long err)
+{
+	if (!user_mode(regs))
+		die(str, regs, err);
+}
+
+/*
+ * try and fix up kernelspace address errors
+ * - userspace errors just cause EFAULT to be returned, resulting in SEGV
+ * - kernel/userspace interfaces cause a jump to an appropriate handler
+ * - other kernel errors are bad
+ */
+void die_if_no_fixup(const char *str, struct pt_regs *regs, long err)
+{
+	if (!user_mode(regs)) {
+		const struct exception_table_entry *fixup;
+		fixup = search_exception_tables(regs->pc);
+		if (fixup) {
+			regs->pc = fixup->fixup;
+			return;
+		}
+
+		die(str, regs, err);
+	}
+}
+
 #ifdef CONFIG_GENERIC_BUG
 static void handle_BUG(struct pt_regs *regs)
 {
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index a37175d..5f513a6 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -16,13 +16,11 @@
 #include <linux/hardirq.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
-#include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/io.h>
 #include <linux/bug.h>
 #include <linux/debug_locks.h>
 #include <linux/kdebug.h>
-#include <linux/kexec.h>
 #include <linux/limits.h>
 #include <linux/sysfs.h>
 #include <linux/uaccess.h>
@@ -48,102 +46,6 @@
 #define TRAP_ILLEGAL_SLOT_INST	13
 #endif
 
-static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
-{
-	unsigned long p;
-	int i;
-
-	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
-
-	for (p = bottom & ~31; p < top; ) {
-		printk("%04lx: ", p & 0xffff);
-
-		for (i = 0; i < 8; i++, p += 4) {
-			unsigned int val;
-
-			if (p < bottom || p >= top)
-				printk("         ");
-			else {
-				if (__get_user(val, (unsigned int __user *)p)) {
-					printk("\n");
-					return;
-				}
-				printk("%08x ", val);
-			}
-		}
-		printk("\n");
-	}
-}
-
-static DEFINE_SPINLOCK(die_lock);
-
-void die(const char * str, struct pt_regs * regs, long err)
-{
-	static int die_counter;
-
-	oops_enter();
-
-	spin_lock_irq(&die_lock);
-	console_verbose();
-	bust_spinlocks(1);
-
-	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
-	print_modules();
-	show_regs(regs);
-
-	printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
-			task_pid_nr(current), task_stack_page(current) + 1);
-
-	if (!user_mode(regs) || in_interrupt())
-		dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
-			 (unsigned long)task_stack_page(current));
-
-	notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV);
-
-	bust_spinlocks(0);
-	add_taint(TAINT_DIE);
-	spin_unlock_irq(&die_lock);
-	oops_exit();
-
-	if (kexec_should_crash(current))
-		crash_kexec(regs);
-
-	if (in_interrupt())
-		panic("Fatal exception in interrupt");
-
-	if (panic_on_oops)
-		panic("Fatal exception");
-
-	do_exit(SIGSEGV);
-}
-
-static inline void die_if_kernel(const char *str, struct pt_regs *regs,
-				 long err)
-{
-	if (!user_mode(regs))
-		die(str, regs, err);
-}
-
-/*
- * try and fix up kernelspace address errors
- * - userspace errors just cause EFAULT to be returned, resulting in SEGV
- * - kernel/userspace interfaces cause a jump to an appropriate handler
- * - other kernel errors are bad
- */
-static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
-{
-	if (!user_mode(regs)) {
-		const struct exception_table_entry *fixup;
-		fixup = search_exception_tables(regs->pc);
-		if (fixup) {
-			regs->pc = fixup->fixup;
-			return;
-		}
-
-		die(str, regs, err);
-	}
-}
-
 static inline void sign_extend(unsigned int count, unsigned char *dst)
 {
 #ifdef __LITTLE_ENDIAN__
@@ -900,26 +802,3 @@ void __init trap_init(void)
 	set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler);
 #endif
 }
-
-void show_stack(struct task_struct *tsk, unsigned long *sp)
-{
-	unsigned long stack;
-
-	if (!tsk)
-		tsk = current;
-	if (tsk == current)
-		sp = (unsigned long *)current_stack_pointer;
-	else
-		sp = (unsigned long *)tsk->thread.sp;
-
-	stack = (unsigned long)sp;
-	dump_mem("Stack: ", stack, THREAD_SIZE +
-		 (unsigned long)task_stack_page(tsk));
-	show_trace(tsk, sp, NULL);
-}
-
-void dump_stack(void)
-{
-	show_stack(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c
index 8dae93e..f87d20d 100644
--- a/arch/sh/kernel/traps_64.c
+++ b/arch/sh/kernel/traps_64.c
@@ -27,283 +27,25 @@
 #include <linux/perf_event.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <linux/atomic.h>
+#include <asm/alignment.h>
 #include <asm/processor.h>
 #include <asm/pgtable.h>
 #include <asm/fpu.h>
 
-#undef DEBUG_EXCEPTION
-#ifdef DEBUG_EXCEPTION
-/* implemented in ../lib/dbg.c */
-extern void show_excp_regs(char *fname, int trapnr, int signr,
-			   struct pt_regs *regs);
-#else
-#define show_excp_regs(a, b, c, d)
-#endif
-
-static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name,
-		unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk);
-
-#define DO_ERROR(trapnr, signr, str, name, tsk) \
-asmlinkage void do_##name(unsigned long error_code, struct pt_regs *regs) \
-{ \
-	do_unhandled_exception(trapnr, signr, str, __stringify(name), error_code, regs, current); \
-}
-
-static DEFINE_SPINLOCK(die_lock);
-
-void die(const char * str, struct pt_regs * regs, long err)
-{
-	console_verbose();
-	spin_lock_irq(&die_lock);
-	printk("%s: %lx\n", str, (err & 0xffffff));
-	show_regs(regs);
-	spin_unlock_irq(&die_lock);
-	do_exit(SIGSEGV);
-}
-
-static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
-{
-	if (!user_mode(regs))
-		die(str, regs, err);
-}
-
-static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
-{
-	if (!user_mode(regs)) {
-		const struct exception_table_entry *fixup;
-		fixup = search_exception_tables(regs->pc);
-		if (fixup) {
-			regs->pc = fixup->fixup;
-			return;
-		}
-		die(str, regs, err);
-	}
-}
-
-DO_ERROR(13, SIGILL,  "illegal slot instruction", illegal_slot_inst, current)
-DO_ERROR(87, SIGSEGV, "address error (exec)", address_error_exec, current)
-
-
-/* Implement misaligned load/store handling for kernel (and optionally for user
-   mode too).  Limitation : only SHmedia mode code is handled - there is no
-   handling at all for misaligned accesses occurring in SHcompact code yet. */
-
-static int misaligned_fixup(struct pt_regs *regs);
-
-asmlinkage void do_address_error_load(unsigned long error_code, struct pt_regs *regs)
-{
-	if (misaligned_fixup(regs) < 0) {
-		do_unhandled_exception(7, SIGSEGV, "address error(load)",
-				"do_address_error_load",
-				error_code, regs, current);
-	}
-	return;
-}
-
-asmlinkage void do_address_error_store(unsigned long error_code, struct pt_regs *regs)
-{
-	if (misaligned_fixup(regs) < 0) {
-		do_unhandled_exception(8, SIGSEGV, "address error(store)",
-				"do_address_error_store",
-				error_code, regs, current);
-	}
-	return;
-}
-
-#if defined(CONFIG_SH64_ID2815_WORKAROUND)
-
-#define OPCODE_INVALID      0
-#define OPCODE_USER_VALID   1
-#define OPCODE_PRIV_VALID   2
-
-/* getcon/putcon - requires checking which control register is referenced. */
-#define OPCODE_CTRL_REG     3
-
-/* Table of valid opcodes for SHmedia mode.
-   Form a 10-bit value by concatenating the major/minor opcodes i.e.
-   opcode[31:26,20:16].  The 6 MSBs of this value index into the following
-   array.  The 4 LSBs select the bit-pair in the entry (bits 1:0 correspond to
-   LSBs==4'b0000 etc). */
-static unsigned long shmedia_opcode_table[64] = {
-	0x55554044,0x54445055,0x15141514,0x14541414,0x00000000,0x10001000,0x01110055,0x04050015,
-	0x00000444,0xc0000000,0x44545515,0x40405555,0x55550015,0x10005555,0x55555505,0x04050000,
-	0x00000555,0x00000404,0x00040445,0x15151414,0x00000000,0x00000000,0x00000000,0x00000000,
-	0x00000055,0x40404444,0x00000404,0xc0009495,0x00000000,0x00000000,0x00000000,0x00000000,
-	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
-	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
-	0x80005050,0x04005055,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
-	0x81055554,0x00000404,0x55555555,0x55555555,0x00000000,0x00000000,0x00000000,0x00000000
-};
-
-void do_reserved_inst(unsigned long error_code, struct pt_regs *regs)
-{
-	/* Workaround SH5-101 cut2 silicon defect #2815 :
-	   in some situations, inter-mode branches from SHcompact -> SHmedia
-	   which should take ITLBMISS or EXECPROT exceptions at the target
-	   falsely take RESINST at the target instead. */
-
-	unsigned long opcode = 0x6ff4fff0; /* guaranteed reserved opcode */
-	unsigned long pc, aligned_pc;
-	int get_user_error;
-	int trapnr = 12;
-	int signr = SIGILL;
-	char *exception_name = "reserved_instruction";
-
-	pc = regs->pc;
-	if ((pc & 3) == 1) {
-		/* SHmedia : check for defect.  This requires executable vmas
-		   to be readable too. */
-		aligned_pc = pc & ~3;
-		if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) {
-			get_user_error = -EFAULT;
-		} else {
-			get_user_error = __get_user(opcode, (unsigned long *)aligned_pc);
-		}
-		if (get_user_error >= 0) {
-			unsigned long index, shift;
-			unsigned long major, minor, combined;
-			unsigned long reserved_field;
-			reserved_field = opcode & 0xf; /* These bits are currently reserved as zero in all valid opcodes */
-			major = (opcode >> 26) & 0x3f;
-			minor = (opcode >> 16) & 0xf;
-			combined = (major << 4) | minor;
-			index = major;
-			shift = minor << 1;
-			if (reserved_field == 0) {
-				int opcode_state = (shmedia_opcode_table[index] >> shift) & 0x3;
-				switch (opcode_state) {
-					case OPCODE_INVALID:
-						/* Trap. */
-						break;
-					case OPCODE_USER_VALID:
-						/* Restart the instruction : the branch to the instruction will now be from an RTE
-						   not from SHcompact so the silicon defect won't be triggered. */
-						return;
-					case OPCODE_PRIV_VALID:
-						if (!user_mode(regs)) {
-							/* Should only ever get here if a module has
-							   SHcompact code inside it.  If so, the same fix up is needed. */
-							return; /* same reason */
-						}
-						/* Otherwise, user mode trying to execute a privileged instruction -
-						   fall through to trap. */
-						break;
-					case OPCODE_CTRL_REG:
-						/* If in privileged mode, return as above. */
-						if (!user_mode(regs)) return;
-						/* In user mode ... */
-						if (combined == 0x9f) { /* GETCON */
-							unsigned long regno = (opcode >> 20) & 0x3f;
-							if (regno >= 62) {
-								return;
-							}
-							/* Otherwise, reserved or privileged control register, => trap */
-						} else if (combined == 0x1bf) { /* PUTCON */
-							unsigned long regno = (opcode >> 4) & 0x3f;
-							if (regno >= 62) {
-								return;
-							}
-							/* Otherwise, reserved or privileged control register, => trap */
-						} else {
-							/* Trap */
-						}
-						break;
-					default:
-						/* Fall through to trap. */
-						break;
-				}
-			}
-			/* fall through to normal resinst processing */
-		} else {
-			/* Error trying to read opcode.  This typically means a
-			   real fault, not a RESINST any more.  So change the
-			   codes. */
-			trapnr = 87;
-			exception_name = "address error (exec)";
-			signr = SIGSEGV;
-		}
-	}
-
-	do_unhandled_exception(trapnr, signr, exception_name, "do_reserved_inst", error_code, regs, current);
-}
-
-#else /* CONFIG_SH64_ID2815_WORKAROUND */
-
-/* If the workaround isn't needed, this is just a straightforward reserved
-   instruction */
-DO_ERROR(12, SIGILL,  "reserved instruction", reserved_inst, current)
-
-#endif /* CONFIG_SH64_ID2815_WORKAROUND */
-
-/* Called with interrupts disabled */
-asmlinkage void do_exception_error(unsigned long ex, struct pt_regs *regs)
-{
-	show_excp_regs(__func__, -1, -1, regs);
-	die_if_kernel("exception", regs, ex);
-}
-
-int do_unknown_trapa(unsigned long scId, struct pt_regs *regs)
-{
-	/* Syscall debug */
-        printk("System call ID error: [0x1#args:8 #syscall:16  0x%lx]\n", scId);
-
-	die_if_kernel("unknown trapa", regs, scId);
-
-	return -ENOSYS;
-}
-
-void show_stack(struct task_struct *tsk, unsigned long *sp)
-{
-#ifdef CONFIG_KALLSYMS
-	extern void sh64_unwind(struct pt_regs *regs);
-	struct pt_regs *regs;
-
-	regs = tsk ? tsk->thread.kregs : NULL;
-
-	sh64_unwind(regs);
-#else
-	printk(KERN_ERR "Can't backtrace on sh64 without CONFIG_KALLSYMS\n");
-#endif
-}
-
-void show_task(unsigned long *sp)
-{
-	show_stack(NULL, sp);
-}
-
-void dump_stack(void)
-{
-	show_task(NULL);
-}
-/* Needed by any user of WARN_ON in view of the defn in include/asm-sh/bug.h */
-EXPORT_SYMBOL(dump_stack);
-
-static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name,
-		unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk)
-{
-	show_excp_regs(fn_name, trapnr, signr, regs);
-
-	if (user_mode(regs))
-		force_sig(signr, tsk);
-
-	die_if_no_fixup(str, regs, error_code);
-}
-
-static int read_opcode(unsigned long long pc, unsigned long *result_opcode, int from_user_mode)
+static int read_opcode(reg_size_t pc, insn_size_t *result_opcode, int from_user_mode)
 {
 	int get_user_error;
 	unsigned long aligned_pc;
-	unsigned long opcode;
+	insn_size_t opcode;
 
 	if ((pc & 3) == 1) {
 		/* SHmedia */
 		aligned_pc = pc & ~3;
 		if (from_user_mode) {
-			if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) {
+			if (!access_ok(VERIFY_READ, aligned_pc, sizeof(insn_size_t))) {
 				get_user_error = -EFAULT;
 			} else {
-				get_user_error = __get_user(opcode, (unsigned long *)aligned_pc);
+				get_user_error = __get_user(opcode, (insn_size_t *)aligned_pc);
 				*result_opcode = opcode;
 			}
 			return get_user_error;
@@ -311,7 +53,7 @@ static int read_opcode(unsigned long long pc, unsigned long *result_opcode, int
 			/* If the fault was in the kernel, we can either read
 			 * this directly, or if not, we fault.
 			*/
-			*result_opcode = *(unsigned long *) aligned_pc;
+			*result_opcode = *(insn_size_t *)aligned_pc;
 			return 0;
 		}
 	} else if ((pc & 1) == 0) {
@@ -337,17 +79,23 @@ static int address_is_sign_extended(__u64 a)
 #endif
 }
 
+/* return -1 for fault, 0 for OK */
 static int generate_and_check_address(struct pt_regs *regs,
-				      __u32 opcode,
+				      insn_size_t opcode,
 				      int displacement_not_indexed,
 				      int width_shift,
 				      __u64 *address)
 {
-	/* return -1 for fault, 0 for OK */
-
 	__u64 base_address, addr;
 	int basereg;
 
+	switch (1 << width_shift) {
+	case 1: inc_unaligned_byte_access(); break;
+	case 2: inc_unaligned_word_access(); break;
+	case 4: inc_unaligned_dword_access(); break;
+	case 8: inc_unaligned_multi_access(); break;
+	}
+
 	basereg = (opcode >> 20) & 0x3f;
 	base_address = regs->regs[basereg];
 	if (displacement_not_indexed) {
@@ -364,28 +112,28 @@ static int generate_and_check_address(struct pt_regs *regs,
 	}
 
 	/* Check sign extended */
-	if (!address_is_sign_extended(addr)) {
+	if (!address_is_sign_extended(addr))
 		return -1;
-	}
 
 	/* Check accessible.  For misaligned access in the kernel, assume the
 	   address is always accessible (and if not, just fault when the
 	   load/store gets done.) */
 	if (user_mode(regs)) {
-		if (addr >= TASK_SIZE) {
+		inc_unaligned_user_access();
+
+		if (addr >= TASK_SIZE)
 			return -1;
-		}
-		/* Do access_ok check later - it depends on whether it's a load or a store. */
-	}
+	} else
+		inc_unaligned_kernel_access();
 
 	*address = addr;
+
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, addr);
+	unaligned_fixups_notify(current, opcode, regs);
+
 	return 0;
 }
 
-static int user_mode_unaligned_fixup_count = 10;
-static int user_mode_unaligned_fixup_enable = 1;
-static int kernel_mode_unaligned_fixup_count = 32;
-
 static void misaligned_kernel_word_load(__u64 address, int do_sign_extend, __u64 *result)
 {
 	unsigned short x;
@@ -415,7 +163,7 @@ static void misaligned_kernel_word_store(__u64 address, __u64 value)
 }
 
 static int misaligned_load(struct pt_regs *regs,
-			   __u32 opcode,
+			   insn_size_t opcode,
 			   int displacement_not_indexed,
 			   int width_shift,
 			   int do_sign_extend)
@@ -427,11 +175,8 @@ static int misaligned_load(struct pt_regs *regs,
 
 	error = generate_and_check_address(regs, opcode,
 			displacement_not_indexed, width_shift, &address);
-	if (error < 0) {
+	if (error < 0)
 		return error;
-	}
-
-	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, address);
 
 	destreg = (opcode >> 4) & 0x3f;
 	if (user_mode(regs)) {
@@ -490,11 +235,10 @@ static int misaligned_load(struct pt_regs *regs,
 	}
 
 	return 0;
-
 }
 
 static int misaligned_store(struct pt_regs *regs,
-			    __u32 opcode,
+			    insn_size_t opcode,
 			    int displacement_not_indexed,
 			    int width_shift)
 {
@@ -505,11 +249,8 @@ static int misaligned_store(struct pt_regs *regs,
 
 	error = generate_and_check_address(regs, opcode,
 			displacement_not_indexed, width_shift, &address);
-	if (error < 0) {
+	if (error < 0)
 		return error;
-	}
-
-	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, address);
 
 	srcreg = (opcode >> 4) & 0x3f;
 	if (user_mode(regs)) {
@@ -563,13 +304,12 @@ static int misaligned_store(struct pt_regs *regs,
 	}
 
 	return 0;
-
 }
 
 /* Never need to fix up misaligned FPU accesses within the kernel since that's a real
    error. */
 static int misaligned_fpu_load(struct pt_regs *regs,
-			   __u32 opcode,
+			   insn_size_t opcode,
 			   int displacement_not_indexed,
 			   int width_shift,
 			   int do_paired_load)
@@ -581,11 +321,8 @@ static int misaligned_fpu_load(struct pt_regs *regs,
 
 	error = generate_and_check_address(regs, opcode,
 			displacement_not_indexed, width_shift, &address);
-	if (error < 0) {
+	if (error < 0)
 		return error;
-	}
-
-	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, address);
 
 	destreg = (opcode >> 4) & 0x3f;
 	if (user_mode(regs)) {
@@ -641,12 +378,10 @@ static int misaligned_fpu_load(struct pt_regs *regs,
 		die ("Misaligned FPU load inside kernel", regs, 0);
 		return -1;
 	}
-
-
 }
 
 static int misaligned_fpu_store(struct pt_regs *regs,
-			   __u32 opcode,
+			   insn_size_t opcode,
 			   int displacement_not_indexed,
 			   int width_shift,
 			   int do_paired_load)
@@ -658,11 +393,8 @@ static int misaligned_fpu_store(struct pt_regs *regs,
 
 	error = generate_and_check_address(regs, opcode,
 			displacement_not_indexed, width_shift, &address);
-	if (error < 0) {
+	if (error < 0)
 		return error;
-	}
-
-	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, address);
 
 	srcreg = (opcode >> 4) & 0x3f;
 	if (user_mode(regs)) {
@@ -723,11 +455,13 @@ static int misaligned_fpu_store(struct pt_regs *regs,
 
 static int misaligned_fixup(struct pt_regs *regs)
 {
-	unsigned long opcode;
+	insn_size_t opcode;
 	int error;
 	int major, minor;
+	unsigned int user_action;
 
-	if (!user_mode_unaligned_fixup_enable)
+	user_action = unaligned_user_action();
+	if (!(user_action & UM_FIXUP))
 		return -1;
 
 	error = read_opcode(regs->pc, &opcode, user_mode(regs));
@@ -737,23 +471,6 @@ static int misaligned_fixup(struct pt_regs *regs)
 	major = (opcode >> 26) & 0x3f;
 	minor = (opcode >> 16) & 0xf;
 
-	if (user_mode(regs) && (user_mode_unaligned_fixup_count > 0)) {
-		--user_mode_unaligned_fixup_count;
-		/* Only do 'count' worth of these reports, to remove a potential DoS against syslog */
-		printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n",
-		       current->comm, task_pid_nr(current), (__u32)regs->pc, opcode);
-	} else if (!user_mode(regs) && (kernel_mode_unaligned_fixup_count > 0)) {
-		--kernel_mode_unaligned_fixup_count;
-		if (in_interrupt()) {
-			printk("Fixing up unaligned kernelspace access in interrupt pc=0x%08x ins=0x%08lx\n",
-			       (__u32)regs->pc, opcode);
-		} else {
-			printk("Fixing up unaligned kernelspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n",
-			       current->comm, task_pid_nr(current), (__u32)regs->pc, opcode);
-		}
-	}
-
-
 	switch (major) {
 		case (0x84>>2): /* LD.W */
 			error = misaligned_load(regs, opcode, 1, 1, 1);
@@ -878,59 +595,202 @@ static int misaligned_fixup(struct pt_regs *regs)
 		regs->pc += 4; /* Skip the instruction that's just been emulated */
 		return 0;
 	}
+}
+
+static void do_unhandled_exception(int signr, char *str, unsigned long error,
+				   struct pt_regs *regs)
+{
+	if (user_mode(regs))
+		force_sig(signr, current);
 
+	die_if_no_fixup(str, regs, error);
 }
 
-static ctl_table unaligned_table[] = {
-	{
-		.procname	= "kernel_reports",
-		.data		= &kernel_mode_unaligned_fixup_count,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec
-	},
-	{
-		.procname	= "user_reports",
-		.data		= &user_mode_unaligned_fixup_count,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec
-	},
-	{
-		.procname	= "user_enable",
-		.data		= &user_mode_unaligned_fixup_enable,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec},
-	{}
-};
+#define DO_ERROR(signr, str, name) \
+asmlinkage void do_##name(unsigned long error_code, struct pt_regs *regs) \
+{ \
+	do_unhandled_exception(signr, str, error_code, regs); \
+}
 
-static ctl_table unaligned_root[] = {
-	{
-		.procname	= "unaligned_fixup",
-		.mode		= 0555,
-		.child		= unaligned_table
-	},
-	{}
-};
+DO_ERROR(SIGILL,  "illegal slot instruction", illegal_slot_inst)
+DO_ERROR(SIGSEGV, "address error (exec)", address_error_exec)
+
+#if defined(CONFIG_SH64_ID2815_WORKAROUND)
+
+#define OPCODE_INVALID      0
+#define OPCODE_USER_VALID   1
+#define OPCODE_PRIV_VALID   2
 
-static ctl_table sh64_root[] = {
-	{
-		.procname	= "sh64",
-		.mode		= 0555,
-		.child		= unaligned_root
-	},
-	{}
+/* getcon/putcon - requires checking which control register is referenced. */
+#define OPCODE_CTRL_REG     3
+
+/* Table of valid opcodes for SHmedia mode.
+   Form a 10-bit value by concatenating the major/minor opcodes i.e.
+   opcode[31:26,20:16].  The 6 MSBs of this value index into the following
+   array.  The 4 LSBs select the bit-pair in the entry (bits 1:0 correspond to
+   LSBs==4'b0000 etc). */
+static unsigned long shmedia_opcode_table[64] = {
+	0x55554044,0x54445055,0x15141514,0x14541414,0x00000000,0x10001000,0x01110055,0x04050015,
+	0x00000444,0xc0000000,0x44545515,0x40405555,0x55550015,0x10005555,0x55555505,0x04050000,
+	0x00000555,0x00000404,0x00040445,0x15151414,0x00000000,0x00000000,0x00000000,0x00000000,
+	0x00000055,0x40404444,0x00000404,0xc0009495,0x00000000,0x00000000,0x00000000,0x00000000,
+	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
+	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
+	0x80005050,0x04005055,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
+	0x81055554,0x00000404,0x55555555,0x55555555,0x00000000,0x00000000,0x00000000,0x00000000
 };
-static struct ctl_table_header *sysctl_header;
-static int __init init_sysctl(void)
+
+/* Workaround SH5-101 cut2 silicon defect #2815 :
+   in some situations, inter-mode branches from SHcompact -> SHmedia
+   which should take ITLBMISS or EXECPROT exceptions at the target
+   falsely take RESINST at the target instead. */
+void do_reserved_inst(unsigned long error_code, struct pt_regs *regs)
 {
-	sysctl_header = register_sysctl_table(sh64_root);
-	return 0;
+	insn_size_t opcode = 0x6ff4fff0; /* guaranteed reserved opcode */
+	unsigned long pc, aligned_pc;
+	unsigned long index, shift;
+	unsigned long major, minor, combined;
+	unsigned long reserved_field;
+	int opcode_state;
+	int get_user_error;
+	int signr = SIGILL;
+	char *exception_name = "reserved_instruction";
+
+	pc = regs->pc;
+
+	/* SHcompact is not handled */
+	if (unlikely((pc & 3) == 0))
+		goto out;
+
+	/* SHmedia : check for defect.  This requires executable vmas
+	   to be readable too. */
+	aligned_pc = pc & ~3;
+	if (!access_ok(VERIFY_READ, aligned_pc, sizeof(insn_size_t)))
+		get_user_error = -EFAULT;
+	else
+		get_user_error = __get_user(opcode, (insn_size_t *)aligned_pc);
+
+	if (get_user_error < 0) {
+		/*
+		 * Error trying to read opcode.  This typically means a
+		 * real fault, not a RESINST any more.  So change the
+		 * codes.
+		 */
+		exception_name = "address error (exec)";
+		signr = SIGSEGV;
+		goto out;
+	}
+
+	/* These bits are currently reserved as zero in all valid opcodes */
+	reserved_field = opcode & 0xf;
+	if (unlikely(reserved_field))
+		goto out;	/* invalid opcode */
+
+	major = (opcode >> 26) & 0x3f;
+	minor = (opcode >> 16) & 0xf;
+	combined = (major << 4) | minor;
+	index = major;
+	shift = minor << 1;
+	opcode_state = (shmedia_opcode_table[index] >> shift) & 0x3;
+	switch (opcode_state) {
+	case OPCODE_INVALID:
+		/* Trap. */
+		break;
+	case OPCODE_USER_VALID:
+		/*
+		 * Restart the instruction: the branch to the instruction
+		 * will now be from an RTE not from SHcompact so the
+		 * silicon defect won't be triggered.
+		 */
+		return;
+	case OPCODE_PRIV_VALID:
+		if (!user_mode(regs)) {
+			/*
+			 * Should only ever get here if a module has
+			 * SHcompact code inside it. If so, the same fix
+			 * up is needed.
+			 */
+			return; /* same reason */
+		}
+
+		/*
+		 * Otherwise, user mode trying to execute a privileged
+		 * instruction - fall through to trap.
+		 */
+		break;
+	case OPCODE_CTRL_REG:
+		/* If in privileged mode, return as above. */
+		if (!user_mode(regs))
+			return;
+
+		/* In user mode ... */
+		if (combined == 0x9f) { /* GETCON */
+			unsigned long regno = (opcode >> 20) & 0x3f;
+
+			if (regno >= 62)
+				return;
+
+			/* reserved/privileged control register => trap */
+		} else if (combined == 0x1bf) { /* PUTCON */
+			unsigned long regno = (opcode >> 4) & 0x3f;
+
+			if (regno >= 62)
+				return;
+
+			/* reserved/privileged control register => trap */
+		}
+
+		break;
+	default:
+		/* Fall through to trap. */
+		break;
+	}
+
+out:
+	do_unhandled_exception(signr, exception_name, error_code, regs);
 }
 
-__initcall(init_sysctl);
+#else /* CONFIG_SH64_ID2815_WORKAROUND */
 
+/* If the workaround isn't needed, this is just a straightforward reserved
+   instruction */
+DO_ERROR(SIGILL, "reserved instruction", reserved_inst)
+
+#endif /* CONFIG_SH64_ID2815_WORKAROUND */
+
+/* Called with interrupts disabled */
+asmlinkage void do_exception_error(unsigned long ex, struct pt_regs *regs)
+{
+	die_if_kernel("exception", regs, ex);
+}
+
+asmlinkage int do_unknown_trapa(unsigned long scId, struct pt_regs *regs)
+{
+	/* Syscall debug */
+	printk("System call ID error: [0x1#args:8 #syscall:16  0x%lx]\n", scId);
+
+	die_if_kernel("unknown trapa", regs, scId);
+
+	return -ENOSYS;
+}
+
+/* Implement misaligned load/store handling for kernel (and optionally for user
+   mode too).  Limitation : only SHmedia mode code is handled - there is no
+   handling at all for misaligned accesses occurring in SHcompact code yet. */
+
+asmlinkage void do_address_error_load(unsigned long error_code, struct pt_regs *regs)
+{
+	if (misaligned_fixup(regs) < 0)
+		do_unhandled_exception(SIGSEGV, "address error(load)",
+				       error_code, regs);
+}
+
+asmlinkage void do_address_error_store(unsigned long error_code, struct pt_regs *regs)
+{
+	if (misaligned_fixup(regs) < 0)
+		do_unhandled_exception(SIGSEGV, "address error(store)",
+				error_code, regs);
+}
 
 asmlinkage void do_debug_interrupt(unsigned long code, struct pt_regs *regs)
 {
@@ -942,10 +802,9 @@ asmlinkage void do_debug_interrupt(unsigned long code, struct pt_regs *regs)
 	   of access we make to them - just go direct to their physical
 	   addresses. */
 	exp_cause = peek_real_address_q(DM_EXP_CAUSE_PHY);
-	if (exp_cause & ~4) {
+	if (exp_cause & ~4)
 		printk("DM.EXP_CAUSE had unexpected bits set (=%08lx)\n",
 			(unsigned long)(exp_cause & 0xffffffff));
-	}
 	show_state();
 	/* Clear all DEBUGINT causes */
 	poke_real_address_q(DM_EXP_CAUSE_PHY, 0x0);
diff --git a/arch/sh/lib64/Makefile b/arch/sh/lib64/Makefile
index 1fee75a..69779ff 100644
--- a/arch/sh/lib64/Makefile
+++ b/arch/sh/lib64/Makefile
@@ -10,7 +10,7 @@
 #
 
 # Panic should really be compiled as PIC
-lib-y  := udelay.o dbg.o panic.o memcpy.o memset.o \
+lib-y  := udelay.o panic.o memcpy.o memset.o \
 	  copy_user_memcpy.o copy_page.o strcpy.o strlen.o
 
 # Extracted from libgcc
diff --git a/arch/sh/lib64/dbg.c b/arch/sh/lib64/dbg.c
deleted file mode 100644
index 6152a6a..0000000
--- a/arch/sh/lib64/dbg.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*--------------------------------------------------------------------------
---
--- Identity : Linux50 Debug Funcions
---
--- File     : arch/sh/lib64/dbg.c
---
--- Copyright 2000, 2001 STMicroelectronics Limited.
--- Copyright 2004 Richard Curnow (evt_debug etc)
---
---------------------------------------------------------------------------*/
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <asm/mmu_context.h>
-
-typedef u64 regType_t;
-
-static regType_t getConfigReg(u64 id)
-{
-	register u64 reg __asm__("r2");
-	asm volatile ("getcfg   %1, 0, %0":"=r" (reg):"r"(id));
-	return (reg);
-}
-
-/* ======================================================================= */
-
-static char *szTab[] = { "4k", "64k", "1M", "512M" };
-static char *protTab[] = { "----",
-	"---R",
-	"--X-",
-	"--XR",
-	"-W--",
-	"-W-R",
-	"-WX-",
-	"-WXR",
-	"U---",
-	"U--R",
-	"U-X-",
-	"U-XR",
-	"UW--",
-	"UW-R",
-	"UWX-",
-	"UWXR"
-};
-#define  ITLB_BASE	0x00000000
-#define  DTLB_BASE	0x00800000
-#define  MAX_TLBs		64
-/* PTE High */
-#define  GET_VALID(pte)        ((pte) & 0x1)
-#define  GET_SHARED(pte)       ((pte) & 0x2)
-#define  GET_ASID(pte)         ((pte >> 2) & 0x0ff)
-#define  GET_EPN(pte)          ((pte) & 0xfffff000)
-
-/* PTE Low */
-#define  GET_CBEHAVIOR(pte)    ((pte) & 0x3)
-#define  GET_PAGE_SIZE(pte)    szTab[((pte >> 3) & 0x3)]
-#define  GET_PROTECTION(pte)   protTab[((pte >> 6) & 0xf)]
-#define  GET_PPN(pte)          ((pte) & 0xfffff000)
-
-#define PAGE_1K_MASK           0x00000000
-#define PAGE_4K_MASK           0x00000010
-#define PAGE_64K_MASK          0x00000080
-#define MMU_PAGESIZE_MASK      (PAGE_64K_MASK | PAGE_4K_MASK)
-#define PAGE_1MB_MASK          MMU_PAGESIZE_MASK
-#define PAGE_1K                (1024)
-#define PAGE_4K                (1024 * 4)
-#define PAGE_64K               (1024 * 64)
-#define PAGE_1MB               (1024 * 1024)
-
-#define HOW_TO_READ_TLB_CONTENT  \
-       "[ ID]  PPN         EPN        ASID  Share  CB  P.Size   PROT.\n"
-
-void print_single_tlb(unsigned long tlb, int single_print)
-{
-	regType_t pteH;
-	regType_t pteL;
-	unsigned int valid, shared, asid, epn, cb, ppn;
-	char *pSize;
-	char *pProt;
-
-	/*
-	   ** in case of single print <single_print> is true, this implies:
-	   **   1) print the TLB in any case also if NOT VALID
-	   **   2) print out the header
-	 */
-
-	pteH = getConfigReg(tlb);
-	valid = GET_VALID(pteH);
-	if (single_print)
-		printk(HOW_TO_READ_TLB_CONTENT);
-	else if (!valid)
-		return;
-
-	pteL = getConfigReg(tlb + 1);
-
-	shared = GET_SHARED(pteH);
-	asid = GET_ASID(pteH);
-	epn = GET_EPN(pteH);
-	cb = GET_CBEHAVIOR(pteL);
-	pSize = GET_PAGE_SIZE(pteL);
-	pProt = GET_PROTECTION(pteL);
-	ppn = GET_PPN(pteL);
-	printk("[%c%2ld]  0x%08x  0x%08x  %03d   %02x    %02x   %4s    %s\n",
-	       ((valid) ? ' ' : 'u'), ((tlb & 0x0ffff) / TLB_STEP),
-	       ppn, epn, asid, shared, cb, pSize, pProt);
-}
-
-void print_dtlb(void)
-{
-	int count;
-	unsigned long tlb;
-
-	printk(" ================= SH-5 D-TLBs Status ===================\n");
-	printk(HOW_TO_READ_TLB_CONTENT);
-	tlb = DTLB_BASE;
-	for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP)
-		print_single_tlb(tlb, 0);
-	printk
-	    (" =============================================================\n");
-}
-
-void print_itlb(void)
-{
-	int count;
-	unsigned long tlb;
-
-	printk(" ================= SH-5 I-TLBs Status ===================\n");
-	printk(HOW_TO_READ_TLB_CONTENT);
-	tlb = ITLB_BASE;
-	for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP)
-		print_single_tlb(tlb, 0);
-	printk
-	    (" =============================================================\n");
-}
-
-void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs)
-{
-
-	unsigned long long ah, al, bh, bl, ch, cl;
-
-	printk("\n");
-	printk("EXCEPTION - %s: task %d; Linux trap # %d; signal = %d\n",
-	       ((from) ? from : "???"), current->pid, trapnr, signr);
-
-	asm volatile ("getcon   " __EXPEVT ", %0":"=r"(ah));
-	asm volatile ("getcon   " __EXPEVT ", %0":"=r"(al));
-	ah = (ah) >> 32;
-	al = (al) & 0xffffffff;
-	asm volatile ("getcon   " __KCR1 ", %0":"=r"(bh));
-	asm volatile ("getcon   " __KCR1 ", %0":"=r"(bl));
-	bh = (bh) >> 32;
-	bl = (bl) & 0xffffffff;
-	asm volatile ("getcon   " __INTEVT ", %0":"=r"(ch));
-	asm volatile ("getcon   " __INTEVT ", %0":"=r"(cl));
-	ch = (ch) >> 32;
-	cl = (cl) & 0xffffffff;
-	printk("EXPE: %08Lx%08Lx KCR1: %08Lx%08Lx INTE: %08Lx%08Lx\n",
-	       ah, al, bh, bl, ch, cl);
-
-	asm volatile ("getcon   " __PEXPEVT ", %0":"=r"(ah));
-	asm volatile ("getcon   " __PEXPEVT ", %0":"=r"(al));
-	ah = (ah) >> 32;
-	al = (al) & 0xffffffff;
-	asm volatile ("getcon   " __PSPC ", %0":"=r"(bh));
-	asm volatile ("getcon   " __PSPC ", %0":"=r"(bl));
-	bh = (bh) >> 32;
-	bl = (bl) & 0xffffffff;
-	asm volatile ("getcon   " __PSSR ", %0":"=r"(ch));
-	asm volatile ("getcon   " __PSSR ", %0":"=r"(cl));
-	ch = (ch) >> 32;
-	cl = (cl) & 0xffffffff;
-	printk("PEXP: %08Lx%08Lx PSPC: %08Lx%08Lx PSSR: %08Lx%08Lx\n",
-	       ah, al, bh, bl, ch, cl);
-
-	ah = (regs->pc) >> 32;
-	al = (regs->pc) & 0xffffffff;
-	bh = (regs->regs[18]) >> 32;
-	bl = (regs->regs[18]) & 0xffffffff;
-	ch = (regs->regs[15]) >> 32;
-	cl = (regs->regs[15]) & 0xffffffff;
-	printk("PC  : %08Lx%08Lx LINK: %08Lx%08Lx SP  : %08Lx%08Lx\n",
-	       ah, al, bh, bl, ch, cl);
-
-	ah = (regs->sr) >> 32;
-	al = (regs->sr) & 0xffffffff;
-	asm volatile ("getcon   " __TEA ", %0":"=r"(bh));
-	asm volatile ("getcon   " __TEA ", %0":"=r"(bl));
-	bh = (bh) >> 32;
-	bl = (bl) & 0xffffffff;
-	asm volatile ("getcon   " __KCR0 ", %0":"=r"(ch));
-	asm volatile ("getcon   " __KCR0 ", %0":"=r"(cl));
-	ch = (ch) >> 32;
-	cl = (cl) & 0xffffffff;
-	printk("SR  : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n",
-	       ah, al, bh, bl, ch, cl);
-
-	ah = (regs->regs[0]) >> 32;
-	al = (regs->regs[0]) & 0xffffffff;
-	bh = (regs->regs[1]) >> 32;
-	bl = (regs->regs[1]) & 0xffffffff;
-	ch = (regs->regs[2]) >> 32;
-	cl = (regs->regs[2]) & 0xffffffff;
-	printk("R0  : %08Lx%08Lx R1  : %08Lx%08Lx R2  : %08Lx%08Lx\n",
-	       ah, al, bh, bl, ch, cl);
-
-	ah = (regs->regs[3]) >> 32;
-	al = (regs->regs[3]) & 0xffffffff;
-	bh = (regs->regs[4]) >> 32;
-	bl = (regs->regs[4]) & 0xffffffff;
-	ch = (regs->regs[5]) >> 32;
-	cl = (regs->regs[5]) & 0xffffffff;
-	printk("R3  : %08Lx%08Lx R4  : %08Lx%08Lx R5  : %08Lx%08Lx\n",
-	       ah, al, bh, bl, ch, cl);
-
-	ah = (regs->regs[6]) >> 32;
-	al = (regs->regs[6]) & 0xffffffff;
-	bh = (regs->regs[7]) >> 32;
-	bl = (regs->regs[7]) & 0xffffffff;
-	ch = (regs->regs[8]) >> 32;
-	cl = (regs->regs[8]) & 0xffffffff;
-	printk("R6  : %08Lx%08Lx R7  : %08Lx%08Lx R8  : %08Lx%08Lx\n",
-	       ah, al, bh, bl, ch, cl);
-
-	ah = (regs->regs[9]) >> 32;
-	al = (regs->regs[9]) & 0xffffffff;
-	bh = (regs->regs[10]) >> 32;
-	bl = (regs->regs[10]) & 0xffffffff;
-	ch = (regs->regs[11]) >> 32;
-	cl = (regs->regs[11]) & 0xffffffff;
-	printk("R9  : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n",
-	       ah, al, bh, bl, ch, cl);
-	printk("....\n");
-
-	ah = (regs->tregs[0]) >> 32;
-	al = (regs->tregs[0]) & 0xffffffff;
-	bh = (regs->tregs[1]) >> 32;
-	bl = (regs->tregs[1]) & 0xffffffff;
-	ch = (regs->tregs[2]) >> 32;
-	cl = (regs->tregs[2]) & 0xffffffff;
-	printk("T0  : %08Lx%08Lx T1  : %08Lx%08Lx T2  : %08Lx%08Lx\n",
-	       ah, al, bh, bl, ch, cl);
-	printk("....\n");
-
-	print_dtlb();
-	print_itlb();
-}
diff --git a/arch/sh/mm/tlb-sh5.c b/arch/sh/mm/tlb-sh5.c
index 3aea25d..ff1c40a 100644
--- a/arch/sh/mm/tlb-sh5.c
+++ b/arch/sh/mm/tlb-sh5.c
@@ -17,7 +17,7 @@
 /**
  * sh64_tlb_init - Perform initial setup for the DTLB and ITLB.
  */
-int __init sh64_tlb_init(void)
+int __cpuinit sh64_tlb_init(void)
 {
 	/* Assign some sane DTLB defaults */
 	cpu_data->dtlb.entries	= 64;
diff --git a/arch/sparc/include/asm/errno.h b/arch/sparc/include/asm/errno.h
index c351aba..01c9769 100644
--- a/arch/sparc/include/asm/errno.h
+++ b/arch/sparc/include/asm/errno.h
@@ -113,5 +113,8 @@
 #define	ERFKILL		134	/* Operation not possible due to RF-kill */
 
 #define EHWPOISON	135	/* Memory page has hardware error */
+#define	ENOAUTHSERVICE	136	/* Authentication service not available */
+#define	ENONAMESERVICE	137	/* Network name service unavailable */
+#define	ENAMEUNKNOWN	138	/* Network name unknown */
 
 #endif
diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h
index e6cd224..25849ae 100644
--- a/arch/sparc/include/asm/thread_info_32.h
+++ b/arch/sparc/include/asm/thread_info_32.h
@@ -126,13 +126,14 @@ register struct thread_info *current_thread_info_reg asm("g6");
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 #define _TIF_DO_NOTIFY_RESUME_MASK	(_TIF_NOTIFY_RESUME | \
 					 _TIF_SIGPENDING)
 
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h
index cfa8c38..4e22766 100644
--- a/arch/sparc/include/asm/thread_info_64.h
+++ b/arch/sparc/include/asm/thread_info_64.h
@@ -256,6 +256,9 @@ static inline bool test_and_clear_restore_sigmask(void)
 	ti->status &= ~TS_RESTORE_SIGMASK;
 	return true;
 }
+
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif	/* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/sparc/kernel/of_device_64.c b/arch/sparc/kernel/of_device_64.c
index 7a3be6f..7bbdc26 100644
--- a/arch/sparc/kernel/of_device_64.c
+++ b/arch/sparc/kernel/of_device_64.c
@@ -580,7 +580,7 @@ static unsigned int __init build_one_device_irq(struct platform_device *op,
 				printk("%s: Apply [%s:%x] imap --> [%s:%x]\n",
 				       op->dev.of_node->full_name,
 				       pp->full_name, this_orig_irq,
-				       (iret ? iret->full_name : "NULL"), irq);
+				       of_node_full_name(iret), irq);
 
 			if (!iret)
 				break;
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index fdaf218..4f92a9a 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -535,7 +535,7 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
 	}
 
 	bus->primary = dev->bus->number;
-	bus->subordinate = busrange[1];
+	pci_bus_insert_busn_res(bus, busrange[0], busrange[1]);
 	bus->bridge_ctl = 0;
 
 	/* parse ranges property, or cook one up by hand for Simba */
@@ -685,6 +685,10 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
 				pbm->io_space.start);
 	pci_add_resource_offset(&resources, &pbm->mem_space,
 				pbm->mem_space.start);
+	pbm->busn.start = pbm->pci_first_busno;
+	pbm->busn.end	= pbm->pci_last_busno;
+	pbm->busn.flags	= IORESOURCE_BUS;
+	pci_add_resource(&resources, &pbm->busn);
 	bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
 				  pbm, &resources);
 	if (!bus) {
@@ -693,8 +697,6 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
 		pci_free_resource_list(&resources);
 		return NULL;
 	}
-	bus->secondary = pbm->pci_first_busno;
-	bus->subordinate = pbm->pci_last_busno;
 
 	pci_of_scan_bus(pbm, node, bus);
 	pci_bus_add_devices(bus);
diff --git a/arch/sparc/kernel/pci_impl.h b/arch/sparc/kernel/pci_impl.h
index 6beb60d..918a203 100644
--- a/arch/sparc/kernel/pci_impl.h
+++ b/arch/sparc/kernel/pci_impl.h
@@ -97,6 +97,7 @@ struct pci_pbm_info {
 	/* PBM I/O and Memory space resources. */
 	struct resource			io_space;
 	struct resource			mem_space;
+	struct resource			busn;
 
 	/* Base of PCI Config space, can be per-PBM or shared. */
 	unsigned long			config_space;
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index ded3f60..46ba849 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -884,11 +884,6 @@ void __init sun4m_pci_init_IRQ(void)
 	sparc_config.load_profile_irq = pcic_load_profile_irq;
 }
 
-int pcibios_assign_resource(struct pci_dev *pdev, int resource)
-{
-	return -ENXIO;
-}
-
 /*
  * This probably belongs here rather than ioport.c because
  * we do not want this crud linked into SBus kernels.
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index f591598..781bcb1 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -103,8 +103,6 @@ void __cpuinit smp_callin(void)
 	if (cheetah_pcache_forced_on)
 		cheetah_enable_pcache();
 
-	local_irq_enable();
-
 	callin_flag = 1;
 	__asm__ __volatile__("membar #Sync\n\t"
 			     "flush  %%g6" : : : "memory");
@@ -124,9 +122,8 @@ void __cpuinit smp_callin(void)
 	while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
 		rmb();
 
-	ipi_call_lock_irq();
 	set_cpu_online(cpuid, true);
-	ipi_call_unlock_irq();
+	local_irq_enable();
 
 	/* idle thread is expected to have preempt disabled */
 	preempt_disable();
@@ -1308,9 +1305,7 @@ int __cpu_disable(void)
 	mdelay(1);
 	local_irq_disable();
 
-	ipi_call_lock();
 	set_cpu_online(cpu, false);
-	ipi_call_unlock();
 
 	cpu_map_rebuild();
 
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c
index 1a69244..e9073e9 100644
--- a/arch/sparc/net/bpf_jit_comp.c
+++ b/arch/sparc/net/bpf_jit_comp.c
@@ -96,6 +96,7 @@ static void bpf_flush_icache(void *start_, void *end_)
 #define AND		F3(2, 0x01)
 #define ANDCC		F3(2, 0x11)
 #define OR		F3(2, 0x02)
+#define XOR		F3(2, 0x03)
 #define SUB		F3(2, 0x04)
 #define SUBCC		F3(2, 0x14)
 #define MUL		F3(2, 0x0a)	/* umul */
@@ -462,6 +463,9 @@ void bpf_jit_compile(struct sk_filter *fp)
 			case BPF_S_ALU_OR_K:	/* A |= K */
 				emit_alu_K(OR, K);
 				break;
+			case BPF_S_ANC_ALU_XOR_X: /* A ^= X; */
+				emit_alu_X(XOR);
+				break;
 			case BPF_S_ALU_LSH_X:	/* A <<= X */
 				emit_alu_X(SLL);
 				break;
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index fe12881..932e443 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -3,6 +3,8 @@
 
 config TILE
 	def_bool y
+	select HAVE_DMA_ATTRS
+	select HAVE_DMA_API_DEBUG
 	select HAVE_KVM if !TILEGX
 	select GENERIC_FIND_FIRST_BIT
 	select USE_GENERIC_SMP_HELPERS
@@ -79,6 +81,9 @@ config ARCH_DMA_ADDR_T_64BIT
 config NEED_DMA_MAP_STATE
 	def_bool y
 
+config ARCH_HAS_DMA_SET_COHERENT_MASK
+	bool
+
 config LOCKDEP_SUPPORT
 	def_bool y
 
@@ -212,6 +217,22 @@ config HIGHMEM
 
 	  If unsure, say "true".
 
+config ZONE_DMA
+	def_bool y
+
+config IOMMU_HELPER
+	bool
+
+config NEED_SG_DMA_LENGTH
+	bool
+
+config SWIOTLB
+	bool
+	default TILEGX
+	select IOMMU_HELPER
+	select NEED_SG_DMA_LENGTH
+	select ARCH_HAS_DMA_SET_COHERENT_MASK
+
 # We do not currently support disabling NUMA.
 config NUMA
 	bool # "NUMA Memory Allocation and Scheduler Support"
@@ -345,6 +366,8 @@ config KERNEL_PL
 	  kernel will be built to run at.  Generally you should use
 	  the default value here.
 
+source "arch/tile/gxio/Kconfig"
+
 endmenu  # Tilera-specific configuration
 
 menu "Bus options"
@@ -354,6 +377,9 @@ config PCI
 	default y
 	select PCI_DOMAINS
 	select GENERIC_PCI_IOMAP
+	select TILE_GXIO_TRIO if TILEGX
+	select ARCH_SUPPORTS_MSI if TILEGX
+	select PCI_MSI if TILEGX
 	---help---
 	  Enable PCI root complex support, so PCIe endpoint devices can
 	  be attached to the Tile chip.  Many, but not all, PCI devices
@@ -370,6 +396,22 @@ config NO_IOPORT
 
 source "drivers/pci/Kconfig"
 
+config TILE_USB
+	tristate "Tilera USB host adapter support"
+	default y
+	depends on USB
+	depends on TILEGX
+	select TILE_GXIO_USB_HOST
+	---help---
+	  Provides USB host adapter support for the built-in EHCI and OHCI
+	  interfaces on TILE-Gx chips.
+
+# USB OHCI needs the bounce pool since tilegx will often have more
+# than 4GB of memory, but we don't currently use the IOTLB to present
+# a 32-bit address to OHCI.  So we need to use a bounce pool instead.
+config NEED_BOUNCE_POOL
+	def_bool USB_OHCI_HCD
+
 config HOTPLUG
 	bool "Support for hot-pluggable devices"
 	---help---
diff --git a/arch/tile/Makefile b/arch/tile/Makefile
index e20b0a0..55640cf 100644
--- a/arch/tile/Makefile
+++ b/arch/tile/Makefile
@@ -59,6 +59,8 @@ libs-y		+= $(LIBGCC_PATH)
 # See arch/tile/Kbuild for content of core part of the kernel
 core-y		+= arch/tile/
 
+core-$(CONFIG_TILE_GXIO) += arch/tile/gxio/
+
 ifdef TILERA_ROOT
 INSTALL_PATH ?= $(TILERA_ROOT)/tile/boot
 endif
diff --git a/arch/tile/gxio/Kconfig b/arch/tile/gxio/Kconfig
new file mode 100644
index 0000000..d221f8d
--- /dev/null
+++ b/arch/tile/gxio/Kconfig
@@ -0,0 +1,28 @@
+# Support direct access to TILE-Gx hardware from user space, via the
+# gxio library, or from kernel space, via kernel IORPC support.
+config TILE_GXIO
+	bool
+	depends on TILEGX
+
+# Support direct access to the common I/O DMA facility within the
+# TILE-Gx mPIPE and Trio hardware from kernel space.
+config TILE_GXIO_DMA
+	bool
+	select TILE_GXIO
+
+# Support direct access to the TILE-Gx mPIPE hardware from kernel space.
+config TILE_GXIO_MPIPE
+	bool
+	select TILE_GXIO
+	select TILE_GXIO_DMA
+
+# Support direct access to the TILE-Gx TRIO hardware from kernel space.
+config TILE_GXIO_TRIO
+	bool
+	select TILE_GXIO
+	select TILE_GXIO_DMA
+
+# Support direct access to the TILE-Gx USB hardware from kernel space.
+config TILE_GXIO_USB_HOST
+	bool
+	select TILE_GXIO
diff --git a/arch/tile/gxio/Makefile b/arch/tile/gxio/Makefile
new file mode 100644
index 0000000..8684bca
--- /dev/null
+++ b/arch/tile/gxio/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the Tile-Gx device access support.
+#
+
+obj-$(CONFIG_TILE_GXIO) += iorpc_globals.o kiorpc.o
+obj-$(CONFIG_TILE_GXIO_DMA) += dma_queue.o
+obj-$(CONFIG_TILE_GXIO_MPIPE) += mpipe.o iorpc_mpipe.o iorpc_mpipe_info.o
+obj-$(CONFIG_TILE_GXIO_TRIO) += trio.o iorpc_trio.o
+obj-$(CONFIG_TILE_GXIO_USB_HOST) += usb_host.o iorpc_usb_host.o
diff --git a/arch/tile/gxio/dma_queue.c b/arch/tile/gxio/dma_queue.c
new file mode 100644
index 0000000..baa6035
--- /dev/null
+++ b/arch/tile/gxio/dma_queue.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/io.h>
+#include <linux/atomic.h>
+#include <linux/module.h>
+#include <gxio/dma_queue.h>
+
+/* Wait for a memory read to complete. */
+#define wait_for_value(val)                             \
+  __asm__ __volatile__("move %0, %0" :: "r"(val))
+
+/* The index is in the low 16. */
+#define DMA_QUEUE_INDEX_MASK ((1 << 16) - 1)
+
+/*
+ * The hardware descriptor-ring type.
+ * This matches the types used by mpipe (MPIPE_EDMA_POST_REGION_VAL_t)
+ * and trio (TRIO_PUSH_DMA_REGION_VAL_t or TRIO_PULL_DMA_REGION_VAL_t).
+ * See those types for more documentation on the individual fields.
+ */
+typedef union {
+	struct {
+#ifndef __BIG_ENDIAN__
+		uint64_t ring_idx:16;
+		uint64_t count:16;
+		uint64_t gen:1;
+		uint64_t __reserved:31;
+#else
+		uint64_t __reserved:31;
+		uint64_t gen:1;
+		uint64_t count:16;
+		uint64_t ring_idx:16;
+#endif
+	};
+	uint64_t word;
+} __gxio_ring_t;
+
+void __gxio_dma_queue_init(__gxio_dma_queue_t *dma_queue,
+			   void *post_region_addr, unsigned int num_entries)
+{
+	/*
+	 * Limit 65536 entry rings to 65535 credits because we only have a
+	 * 16 bit completion counter.
+	 */
+	int64_t credits = (num_entries < 65536) ? num_entries : 65535;
+
+	memset(dma_queue, 0, sizeof(*dma_queue));
+
+	dma_queue->post_region_addr = post_region_addr;
+	dma_queue->hw_complete_count = 0;
+	dma_queue->credits_and_next_index = credits << DMA_QUEUE_CREDIT_SHIFT;
+}
+
+EXPORT_SYMBOL_GPL(__gxio_dma_queue_init);
+
+void __gxio_dma_queue_update_credits(__gxio_dma_queue_t *dma_queue)
+{
+	__gxio_ring_t val;
+	uint64_t count;
+	uint64_t delta;
+	uint64_t new_count;
+
+	/*
+	 * Read the 64-bit completion count without touching the cache, so
+	 * we later avoid having to evict any sharers of this cache line
+	 * when we update it below.
+	 */
+	uint64_t orig_hw_complete_count =
+		cmpxchg(&dma_queue->hw_complete_count,
+			-1, -1);
+
+	/* Make sure the load completes before we access the hardware. */
+	wait_for_value(orig_hw_complete_count);
+
+	/* Read the 16-bit count of how many packets it has completed. */
+	val.word = __gxio_mmio_read(dma_queue->post_region_addr);
+	count = val.count;
+
+	/*
+	 * Calculate the number of completions since we last updated the
+	 * 64-bit counter.  It's safe to ignore the high bits because the
+	 * maximum credit value is 65535.
+	 */
+	delta = (count - orig_hw_complete_count) & 0xffff;
+	if (delta == 0)
+		return;
+
+	/*
+	 * Try to write back the count, advanced by delta.  If we race with
+	 * another thread, this might fail, in which case we return
+	 * immediately on the assumption that some credits are (or at least
+	 * were) available.
+	 */
+	new_count = orig_hw_complete_count + delta;
+	if (cmpxchg(&dma_queue->hw_complete_count,
+		    orig_hw_complete_count,
+		    new_count) != orig_hw_complete_count)
+		return;
+
+	/*
+	 * We succeeded in advancing the completion count; add back the
+	 * corresponding number of egress credits.
+	 */
+	__insn_fetchadd(&dma_queue->credits_and_next_index,
+			(delta << DMA_QUEUE_CREDIT_SHIFT));
+}
+
+EXPORT_SYMBOL_GPL(__gxio_dma_queue_update_credits);
+
+/*
+ * A separate 'blocked' method for put() so that backtraces and
+ * profiles will clearly indicate that we're wasting time spinning on
+ * egress availability rather than actually posting commands.
+ */
+int64_t __gxio_dma_queue_wait_for_credits(__gxio_dma_queue_t *dma_queue,
+					  int64_t modifier)
+{
+	int backoff = 16;
+	int64_t old;
+
+	do {
+		int i;
+		/* Back off to avoid spamming memory networks. */
+		for (i = backoff; i > 0; i--)
+			__insn_mfspr(SPR_PASS);
+
+		/* Check credits again. */
+		__gxio_dma_queue_update_credits(dma_queue);
+		old = __insn_fetchaddgez(&dma_queue->credits_and_next_index,
+					 modifier);
+
+		/* Calculate bounded exponential backoff for next iteration. */
+		if (backoff < 256)
+			backoff *= 2;
+	} while (old + modifier < 0);
+
+	return old;
+}
+
+EXPORT_SYMBOL_GPL(__gxio_dma_queue_wait_for_credits);
+
+int64_t __gxio_dma_queue_reserve_aux(__gxio_dma_queue_t *dma_queue,
+				     unsigned int num, int wait)
+{
+	return __gxio_dma_queue_reserve(dma_queue, num, wait != 0, true);
+}
+
+EXPORT_SYMBOL_GPL(__gxio_dma_queue_reserve_aux);
+
+int __gxio_dma_queue_is_complete(__gxio_dma_queue_t *dma_queue,
+				 int64_t completion_slot, int update)
+{
+	if (update) {
+		if (ACCESS_ONCE(dma_queue->hw_complete_count) >
+		    completion_slot)
+			return 1;
+
+		__gxio_dma_queue_update_credits(dma_queue);
+	}
+
+	return ACCESS_ONCE(dma_queue->hw_complete_count) > completion_slot;
+}
+
+EXPORT_SYMBOL_GPL(__gxio_dma_queue_is_complete);
diff --git a/arch/tile/gxio/iorpc_globals.c b/arch/tile/gxio/iorpc_globals.c
new file mode 100644
index 0000000..e178e90
--- /dev/null
+++ b/arch/tile/gxio/iorpc_globals.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+#include "gxio/iorpc_globals.h"
+
+struct arm_pollfd_param {
+	union iorpc_pollfd pollfd;
+};
+
+int __iorpc_arm_pollfd(int fd, int pollfd_cookie)
+{
+	struct arm_pollfd_param temp;
+	struct arm_pollfd_param *params = &temp;
+
+	params->pollfd.kernel.cookie = pollfd_cookie;
+
+	return hv_dev_pwrite(fd, 0, (HV_VirtAddr) params, sizeof(*params),
+			     IORPC_OP_ARM_POLLFD);
+}
+
+EXPORT_SYMBOL(__iorpc_arm_pollfd);
+
+struct close_pollfd_param {
+	union iorpc_pollfd pollfd;
+};
+
+int __iorpc_close_pollfd(int fd, int pollfd_cookie)
+{
+	struct close_pollfd_param temp;
+	struct close_pollfd_param *params = &temp;
+
+	params->pollfd.kernel.cookie = pollfd_cookie;
+
+	return hv_dev_pwrite(fd, 0, (HV_VirtAddr) params, sizeof(*params),
+			     IORPC_OP_CLOSE_POLLFD);
+}
+
+EXPORT_SYMBOL(__iorpc_close_pollfd);
+
+struct get_mmio_base_param {
+	HV_PTE base;
+};
+
+int __iorpc_get_mmio_base(int fd, HV_PTE *base)
+{
+	int __result;
+	struct get_mmio_base_param temp;
+	struct get_mmio_base_param *params = &temp;
+
+	__result =
+	    hv_dev_pread(fd, 0, (HV_VirtAddr) params, sizeof(*params),
+			 IORPC_OP_GET_MMIO_BASE);
+	*base = params->base;
+
+	return __result;
+}
+
+EXPORT_SYMBOL(__iorpc_get_mmio_base);
+
+struct check_mmio_offset_param {
+	unsigned long offset;
+	unsigned long size;
+};
+
+int __iorpc_check_mmio_offset(int fd, unsigned long offset, unsigned long size)
+{
+	struct check_mmio_offset_param temp;
+	struct check_mmio_offset_param *params = &temp;
+
+	params->offset = offset;
+	params->size = size;
+
+	return hv_dev_pwrite(fd, 0, (HV_VirtAddr) params, sizeof(*params),
+			     IORPC_OP_CHECK_MMIO_OFFSET);
+}
+
+EXPORT_SYMBOL(__iorpc_check_mmio_offset);
diff --git a/arch/tile/gxio/iorpc_mpipe.c b/arch/tile/gxio/iorpc_mpipe.c
new file mode 100644
index 0000000..31b87bf
--- /dev/null
+++ b/arch/tile/gxio/iorpc_mpipe.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+#include "gxio/iorpc_mpipe.h"
+
+struct alloc_buffer_stacks_param {
+	unsigned int count;
+	unsigned int first;
+	unsigned int flags;
+};
+
+int gxio_mpipe_alloc_buffer_stacks(gxio_mpipe_context_t * context,
+				   unsigned int count, unsigned int first,
+				   unsigned int flags)
+{
+	struct alloc_buffer_stacks_param temp;
+	struct alloc_buffer_stacks_param *params = &temp;
+
+	params->count = count;
+	params->first = first;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_MPIPE_OP_ALLOC_BUFFER_STACKS);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_alloc_buffer_stacks);
+
+struct init_buffer_stack_aux_param {
+	union iorpc_mem_buffer buffer;
+	unsigned int stack;
+	unsigned int buffer_size_enum;
+};
+
+int gxio_mpipe_init_buffer_stack_aux(gxio_mpipe_context_t * context,
+				     void *mem_va, size_t mem_size,
+				     unsigned int mem_flags, unsigned int stack,
+				     unsigned int buffer_size_enum)
+{
+	int __result;
+	unsigned long long __cpa;
+	pte_t __pte;
+	struct init_buffer_stack_aux_param temp;
+	struct init_buffer_stack_aux_param *params = &temp;
+
+	__result = va_to_cpa_and_pte(mem_va, &__cpa, &__pte);
+	if (__result != 0)
+		return __result;
+	params->buffer.kernel.cpa = __cpa;
+	params->buffer.kernel.size = mem_size;
+	params->buffer.kernel.pte = __pte;
+	params->buffer.kernel.flags = mem_flags;
+	params->stack = stack;
+	params->buffer_size_enum = buffer_size_enum;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_MPIPE_OP_INIT_BUFFER_STACK_AUX);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_init_buffer_stack_aux);
+
+
+struct alloc_notif_rings_param {
+	unsigned int count;
+	unsigned int first;
+	unsigned int flags;
+};
+
+int gxio_mpipe_alloc_notif_rings(gxio_mpipe_context_t * context,
+				 unsigned int count, unsigned int first,
+				 unsigned int flags)
+{
+	struct alloc_notif_rings_param temp;
+	struct alloc_notif_rings_param *params = &temp;
+
+	params->count = count;
+	params->first = first;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_ALLOC_NOTIF_RINGS);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_alloc_notif_rings);
+
+struct init_notif_ring_aux_param {
+	union iorpc_mem_buffer buffer;
+	unsigned int ring;
+};
+
+int gxio_mpipe_init_notif_ring_aux(gxio_mpipe_context_t * context, void *mem_va,
+				   size_t mem_size, unsigned int mem_flags,
+				   unsigned int ring)
+{
+	int __result;
+	unsigned long long __cpa;
+	pte_t __pte;
+	struct init_notif_ring_aux_param temp;
+	struct init_notif_ring_aux_param *params = &temp;
+
+	__result = va_to_cpa_and_pte(mem_va, &__cpa, &__pte);
+	if (__result != 0)
+		return __result;
+	params->buffer.kernel.cpa = __cpa;
+	params->buffer.kernel.size = mem_size;
+	params->buffer.kernel.pte = __pte;
+	params->buffer.kernel.flags = mem_flags;
+	params->ring = ring;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_MPIPE_OP_INIT_NOTIF_RING_AUX);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_init_notif_ring_aux);
+
+struct request_notif_ring_interrupt_param {
+	union iorpc_interrupt interrupt;
+	unsigned int ring;
+};
+
+int gxio_mpipe_request_notif_ring_interrupt(gxio_mpipe_context_t * context,
+					    int inter_x, int inter_y,
+					    int inter_ipi, int inter_event,
+					    unsigned int ring)
+{
+	struct request_notif_ring_interrupt_param temp;
+	struct request_notif_ring_interrupt_param *params = &temp;
+
+	params->interrupt.kernel.x = inter_x;
+	params->interrupt.kernel.y = inter_y;
+	params->interrupt.kernel.ipi = inter_ipi;
+	params->interrupt.kernel.event = inter_event;
+	params->ring = ring;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_MPIPE_OP_REQUEST_NOTIF_RING_INTERRUPT);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_request_notif_ring_interrupt);
+
+struct enable_notif_ring_interrupt_param {
+	unsigned int ring;
+};
+
+int gxio_mpipe_enable_notif_ring_interrupt(gxio_mpipe_context_t * context,
+					   unsigned int ring)
+{
+	struct enable_notif_ring_interrupt_param temp;
+	struct enable_notif_ring_interrupt_param *params = &temp;
+
+	params->ring = ring;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_MPIPE_OP_ENABLE_NOTIF_RING_INTERRUPT);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_enable_notif_ring_interrupt);
+
+struct alloc_notif_groups_param {
+	unsigned int count;
+	unsigned int first;
+	unsigned int flags;
+};
+
+int gxio_mpipe_alloc_notif_groups(gxio_mpipe_context_t * context,
+				  unsigned int count, unsigned int first,
+				  unsigned int flags)
+{
+	struct alloc_notif_groups_param temp;
+	struct alloc_notif_groups_param *params = &temp;
+
+	params->count = count;
+	params->first = first;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_ALLOC_NOTIF_GROUPS);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_alloc_notif_groups);
+
+struct init_notif_group_param {
+	unsigned int group;
+	gxio_mpipe_notif_group_bits_t bits;
+};
+
+int gxio_mpipe_init_notif_group(gxio_mpipe_context_t * context,
+				unsigned int group,
+				gxio_mpipe_notif_group_bits_t bits)
+{
+	struct init_notif_group_param temp;
+	struct init_notif_group_param *params = &temp;
+
+	params->group = group;
+	params->bits = bits;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_INIT_NOTIF_GROUP);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_init_notif_group);
+
+struct alloc_buckets_param {
+	unsigned int count;
+	unsigned int first;
+	unsigned int flags;
+};
+
+int gxio_mpipe_alloc_buckets(gxio_mpipe_context_t * context, unsigned int count,
+			     unsigned int first, unsigned int flags)
+{
+	struct alloc_buckets_param temp;
+	struct alloc_buckets_param *params = &temp;
+
+	params->count = count;
+	params->first = first;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_ALLOC_BUCKETS);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_alloc_buckets);
+
+struct init_bucket_param {
+	unsigned int bucket;
+	MPIPE_LBL_INIT_DAT_BSTS_TBL_t bucket_info;
+};
+
+int gxio_mpipe_init_bucket(gxio_mpipe_context_t * context, unsigned int bucket,
+			   MPIPE_LBL_INIT_DAT_BSTS_TBL_t bucket_info)
+{
+	struct init_bucket_param temp;
+	struct init_bucket_param *params = &temp;
+
+	params->bucket = bucket;
+	params->bucket_info = bucket_info;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_INIT_BUCKET);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_init_bucket);
+
+struct alloc_edma_rings_param {
+	unsigned int count;
+	unsigned int first;
+	unsigned int flags;
+};
+
+int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t * context,
+				unsigned int count, unsigned int first,
+				unsigned int flags)
+{
+	struct alloc_edma_rings_param temp;
+	struct alloc_edma_rings_param *params = &temp;
+
+	params->count = count;
+	params->first = first;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_ALLOC_EDMA_RINGS);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_alloc_edma_rings);
+
+struct init_edma_ring_aux_param {
+	union iorpc_mem_buffer buffer;
+	unsigned int ring;
+	unsigned int channel;
+};
+
+int gxio_mpipe_init_edma_ring_aux(gxio_mpipe_context_t * context, void *mem_va,
+				  size_t mem_size, unsigned int mem_flags,
+				  unsigned int ring, unsigned int channel)
+{
+	int __result;
+	unsigned long long __cpa;
+	pte_t __pte;
+	struct init_edma_ring_aux_param temp;
+	struct init_edma_ring_aux_param *params = &temp;
+
+	__result = va_to_cpa_and_pte(mem_va, &__cpa, &__pte);
+	if (__result != 0)
+		return __result;
+	params->buffer.kernel.cpa = __cpa;
+	params->buffer.kernel.size = mem_size;
+	params->buffer.kernel.pte = __pte;
+	params->buffer.kernel.flags = mem_flags;
+	params->ring = ring;
+	params->channel = channel;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_INIT_EDMA_RING_AUX);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_init_edma_ring_aux);
+
+
+int gxio_mpipe_commit_rules(gxio_mpipe_context_t * context, const void *blob,
+			    size_t blob_size)
+{
+	const void *params = blob;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, blob_size,
+			     GXIO_MPIPE_OP_COMMIT_RULES);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_commit_rules);
+
+struct register_client_memory_param {
+	unsigned int iotlb;
+	HV_PTE pte;
+	unsigned int flags;
+};
+
+int gxio_mpipe_register_client_memory(gxio_mpipe_context_t * context,
+				      unsigned int iotlb, HV_PTE pte,
+				      unsigned int flags)
+{
+	struct register_client_memory_param temp;
+	struct register_client_memory_param *params = &temp;
+
+	params->iotlb = iotlb;
+	params->pte = pte;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_MPIPE_OP_REGISTER_CLIENT_MEMORY);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_register_client_memory);
+
+struct link_open_aux_param {
+	_gxio_mpipe_link_name_t name;
+	unsigned int flags;
+};
+
+int gxio_mpipe_link_open_aux(gxio_mpipe_context_t * context,
+			     _gxio_mpipe_link_name_t name, unsigned int flags)
+{
+	struct link_open_aux_param temp;
+	struct link_open_aux_param *params = &temp;
+
+	params->name = name;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_LINK_OPEN_AUX);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_link_open_aux);
+
+struct link_close_aux_param {
+	int mac;
+};
+
+int gxio_mpipe_link_close_aux(gxio_mpipe_context_t * context, int mac)
+{
+	struct link_close_aux_param temp;
+	struct link_close_aux_param *params = &temp;
+
+	params->mac = mac;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_LINK_CLOSE_AUX);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_link_close_aux);
+
+
+struct get_timestamp_aux_param {
+	uint64_t sec;
+	uint64_t nsec;
+	uint64_t cycles;
+};
+
+int gxio_mpipe_get_timestamp_aux(gxio_mpipe_context_t * context, uint64_t * sec,
+				 uint64_t * nsec, uint64_t * cycles)
+{
+	int __result;
+	struct get_timestamp_aux_param temp;
+	struct get_timestamp_aux_param *params = &temp;
+
+	__result =
+	    hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params),
+			 GXIO_MPIPE_OP_GET_TIMESTAMP_AUX);
+	*sec = params->sec;
+	*nsec = params->nsec;
+	*cycles = params->cycles;
+
+	return __result;
+}
+
+EXPORT_SYMBOL(gxio_mpipe_get_timestamp_aux);
+
+struct set_timestamp_aux_param {
+	uint64_t sec;
+	uint64_t nsec;
+	uint64_t cycles;
+};
+
+int gxio_mpipe_set_timestamp_aux(gxio_mpipe_context_t * context, uint64_t sec,
+				 uint64_t nsec, uint64_t cycles)
+{
+	struct set_timestamp_aux_param temp;
+	struct set_timestamp_aux_param *params = &temp;
+
+	params->sec = sec;
+	params->nsec = nsec;
+	params->cycles = cycles;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_SET_TIMESTAMP_AUX);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_set_timestamp_aux);
+
+struct adjust_timestamp_aux_param {
+	int64_t nsec;
+};
+
+int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t * context,
+				    int64_t nsec)
+{
+	struct adjust_timestamp_aux_param temp;
+	struct adjust_timestamp_aux_param *params = &temp;
+
+	params->nsec = nsec;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_MPIPE_OP_ADJUST_TIMESTAMP_AUX);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_aux);
+
+struct arm_pollfd_param {
+	union iorpc_pollfd pollfd;
+};
+
+int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie)
+{
+	struct arm_pollfd_param temp;
+	struct arm_pollfd_param *params = &temp;
+
+	params->pollfd.kernel.cookie = pollfd_cookie;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_ARM_POLLFD);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_arm_pollfd);
+
+struct close_pollfd_param {
+	union iorpc_pollfd pollfd;
+};
+
+int gxio_mpipe_close_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie)
+{
+	struct close_pollfd_param temp;
+	struct close_pollfd_param *params = &temp;
+
+	params->pollfd.kernel.cookie = pollfd_cookie;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_CLOSE_POLLFD);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_close_pollfd);
+
+struct get_mmio_base_param {
+	HV_PTE base;
+};
+
+int gxio_mpipe_get_mmio_base(gxio_mpipe_context_t * context, HV_PTE *base)
+{
+	int __result;
+	struct get_mmio_base_param temp;
+	struct get_mmio_base_param *params = &temp;
+
+	__result =
+	    hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params),
+			 GXIO_MPIPE_OP_GET_MMIO_BASE);
+	*base = params->base;
+
+	return __result;
+}
+
+EXPORT_SYMBOL(gxio_mpipe_get_mmio_base);
+
+struct check_mmio_offset_param {
+	unsigned long offset;
+	unsigned long size;
+};
+
+int gxio_mpipe_check_mmio_offset(gxio_mpipe_context_t * context,
+				 unsigned long offset, unsigned long size)
+{
+	struct check_mmio_offset_param temp;
+	struct check_mmio_offset_param *params = &temp;
+
+	params->offset = offset;
+	params->size = size;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_MPIPE_OP_CHECK_MMIO_OFFSET);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_check_mmio_offset);
diff --git a/arch/tile/gxio/iorpc_mpipe_info.c b/arch/tile/gxio/iorpc_mpipe_info.c
new file mode 100644
index 0000000..d0254aa
--- /dev/null
+++ b/arch/tile/gxio/iorpc_mpipe_info.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+#include "gxio/iorpc_mpipe_info.h"
+
+
+struct enumerate_aux_param {
+	_gxio_mpipe_link_name_t name;
+	_gxio_mpipe_link_mac_t mac;
+};
+
+int gxio_mpipe_info_enumerate_aux(gxio_mpipe_info_context_t * context,
+				  unsigned int idx,
+				  _gxio_mpipe_link_name_t * name,
+				  _gxio_mpipe_link_mac_t * mac)
+{
+	int __result;
+	struct enumerate_aux_param temp;
+	struct enumerate_aux_param *params = &temp;
+
+	__result =
+	    hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params),
+			 (((uint64_t) idx << 32) |
+			  GXIO_MPIPE_INFO_OP_ENUMERATE_AUX));
+	*name = params->name;
+	*mac = params->mac;
+
+	return __result;
+}
+
+EXPORT_SYMBOL(gxio_mpipe_info_enumerate_aux);
+
+struct get_mmio_base_param {
+	HV_PTE base;
+};
+
+int gxio_mpipe_info_get_mmio_base(gxio_mpipe_info_context_t * context,
+				  HV_PTE *base)
+{
+	int __result;
+	struct get_mmio_base_param temp;
+	struct get_mmio_base_param *params = &temp;
+
+	__result =
+	    hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params),
+			 GXIO_MPIPE_INFO_OP_GET_MMIO_BASE);
+	*base = params->base;
+
+	return __result;
+}
+
+EXPORT_SYMBOL(gxio_mpipe_info_get_mmio_base);
+
+struct check_mmio_offset_param {
+	unsigned long offset;
+	unsigned long size;
+};
+
+int gxio_mpipe_info_check_mmio_offset(gxio_mpipe_info_context_t * context,
+				      unsigned long offset, unsigned long size)
+{
+	struct check_mmio_offset_param temp;
+	struct check_mmio_offset_param *params = &temp;
+
+	params->offset = offset;
+	params->size = size;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_MPIPE_INFO_OP_CHECK_MMIO_OFFSET);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_info_check_mmio_offset);
diff --git a/arch/tile/gxio/iorpc_trio.c b/arch/tile/gxio/iorpc_trio.c
new file mode 100644
index 0000000..cef4b22
--- /dev/null
+++ b/arch/tile/gxio/iorpc_trio.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+#include "gxio/iorpc_trio.h"
+
+struct alloc_asids_param {
+	unsigned int count;
+	unsigned int first;
+	unsigned int flags;
+};
+
+int gxio_trio_alloc_asids(gxio_trio_context_t * context, unsigned int count,
+			  unsigned int first, unsigned int flags)
+{
+	struct alloc_asids_param temp;
+	struct alloc_asids_param *params = &temp;
+
+	params->count = count;
+	params->first = first;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_TRIO_OP_ALLOC_ASIDS);
+}
+
+EXPORT_SYMBOL(gxio_trio_alloc_asids);
+
+
+struct alloc_memory_maps_param {
+	unsigned int count;
+	unsigned int first;
+	unsigned int flags;
+};
+
+int gxio_trio_alloc_memory_maps(gxio_trio_context_t * context,
+				unsigned int count, unsigned int first,
+				unsigned int flags)
+{
+	struct alloc_memory_maps_param temp;
+	struct alloc_memory_maps_param *params = &temp;
+
+	params->count = count;
+	params->first = first;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_TRIO_OP_ALLOC_MEMORY_MAPS);
+}
+
+EXPORT_SYMBOL(gxio_trio_alloc_memory_maps);
+
+
+struct alloc_pio_regions_param {
+	unsigned int count;
+	unsigned int first;
+	unsigned int flags;
+};
+
+int gxio_trio_alloc_pio_regions(gxio_trio_context_t * context,
+				unsigned int count, unsigned int first,
+				unsigned int flags)
+{
+	struct alloc_pio_regions_param temp;
+	struct alloc_pio_regions_param *params = &temp;
+
+	params->count = count;
+	params->first = first;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_TRIO_OP_ALLOC_PIO_REGIONS);
+}
+
+EXPORT_SYMBOL(gxio_trio_alloc_pio_regions);
+
+struct init_pio_region_aux_param {
+	unsigned int pio_region;
+	unsigned int mac;
+	uint32_t bus_address_hi;
+	unsigned int flags;
+};
+
+int gxio_trio_init_pio_region_aux(gxio_trio_context_t * context,
+				  unsigned int pio_region, unsigned int mac,
+				  uint32_t bus_address_hi, unsigned int flags)
+{
+	struct init_pio_region_aux_param temp;
+	struct init_pio_region_aux_param *params = &temp;
+
+	params->pio_region = pio_region;
+	params->mac = mac;
+	params->bus_address_hi = bus_address_hi;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_TRIO_OP_INIT_PIO_REGION_AUX);
+}
+
+EXPORT_SYMBOL(gxio_trio_init_pio_region_aux);
+
+
+struct init_memory_map_mmu_aux_param {
+	unsigned int map;
+	unsigned long va;
+	uint64_t size;
+	unsigned int asid;
+	unsigned int mac;
+	uint64_t bus_address;
+	unsigned int node;
+	unsigned int order_mode;
+};
+
+int gxio_trio_init_memory_map_mmu_aux(gxio_trio_context_t * context,
+				      unsigned int map, unsigned long va,
+				      uint64_t size, unsigned int asid,
+				      unsigned int mac, uint64_t bus_address,
+				      unsigned int node,
+				      unsigned int order_mode)
+{
+	struct init_memory_map_mmu_aux_param temp;
+	struct init_memory_map_mmu_aux_param *params = &temp;
+
+	params->map = map;
+	params->va = va;
+	params->size = size;
+	params->asid = asid;
+	params->mac = mac;
+	params->bus_address = bus_address;
+	params->node = node;
+	params->order_mode = order_mode;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_TRIO_OP_INIT_MEMORY_MAP_MMU_AUX);
+}
+
+EXPORT_SYMBOL(gxio_trio_init_memory_map_mmu_aux);
+
+struct get_port_property_param {
+	struct pcie_trio_ports_property trio_ports;
+};
+
+int gxio_trio_get_port_property(gxio_trio_context_t * context,
+				struct pcie_trio_ports_property *trio_ports)
+{
+	int __result;
+	struct get_port_property_param temp;
+	struct get_port_property_param *params = &temp;
+
+	__result =
+	    hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params),
+			 GXIO_TRIO_OP_GET_PORT_PROPERTY);
+	*trio_ports = params->trio_ports;
+
+	return __result;
+}
+
+EXPORT_SYMBOL(gxio_trio_get_port_property);
+
+struct config_legacy_intr_param {
+	union iorpc_interrupt interrupt;
+	unsigned int mac;
+	unsigned int intx;
+};
+
+int gxio_trio_config_legacy_intr(gxio_trio_context_t * context, int inter_x,
+				 int inter_y, int inter_ipi, int inter_event,
+				 unsigned int mac, unsigned int intx)
+{
+	struct config_legacy_intr_param temp;
+	struct config_legacy_intr_param *params = &temp;
+
+	params->interrupt.kernel.x = inter_x;
+	params->interrupt.kernel.y = inter_y;
+	params->interrupt.kernel.ipi = inter_ipi;
+	params->interrupt.kernel.event = inter_event;
+	params->mac = mac;
+	params->intx = intx;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_TRIO_OP_CONFIG_LEGACY_INTR);
+}
+
+EXPORT_SYMBOL(gxio_trio_config_legacy_intr);
+
+struct config_msi_intr_param {
+	union iorpc_interrupt interrupt;
+	unsigned int mac;
+	unsigned int mem_map;
+	uint64_t mem_map_base;
+	uint64_t mem_map_limit;
+	unsigned int asid;
+};
+
+int gxio_trio_config_msi_intr(gxio_trio_context_t * context, int inter_x,
+			      int inter_y, int inter_ipi, int inter_event,
+			      unsigned int mac, unsigned int mem_map,
+			      uint64_t mem_map_base, uint64_t mem_map_limit,
+			      unsigned int asid)
+{
+	struct config_msi_intr_param temp;
+	struct config_msi_intr_param *params = &temp;
+
+	params->interrupt.kernel.x = inter_x;
+	params->interrupt.kernel.y = inter_y;
+	params->interrupt.kernel.ipi = inter_ipi;
+	params->interrupt.kernel.event = inter_event;
+	params->mac = mac;
+	params->mem_map = mem_map;
+	params->mem_map_base = mem_map_base;
+	params->mem_map_limit = mem_map_limit;
+	params->asid = asid;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_TRIO_OP_CONFIG_MSI_INTR);
+}
+
+EXPORT_SYMBOL(gxio_trio_config_msi_intr);
+
+
+struct set_mps_mrs_param {
+	uint16_t mps;
+	uint16_t mrs;
+	unsigned int mac;
+};
+
+int gxio_trio_set_mps_mrs(gxio_trio_context_t * context, uint16_t mps,
+			  uint16_t mrs, unsigned int mac)
+{
+	struct set_mps_mrs_param temp;
+	struct set_mps_mrs_param *params = &temp;
+
+	params->mps = mps;
+	params->mrs = mrs;
+	params->mac = mac;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_TRIO_OP_SET_MPS_MRS);
+}
+
+EXPORT_SYMBOL(gxio_trio_set_mps_mrs);
+
+struct force_rc_link_up_param {
+	unsigned int mac;
+};
+
+int gxio_trio_force_rc_link_up(gxio_trio_context_t * context, unsigned int mac)
+{
+	struct force_rc_link_up_param temp;
+	struct force_rc_link_up_param *params = &temp;
+
+	params->mac = mac;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_TRIO_OP_FORCE_RC_LINK_UP);
+}
+
+EXPORT_SYMBOL(gxio_trio_force_rc_link_up);
+
+struct force_ep_link_up_param {
+	unsigned int mac;
+};
+
+int gxio_trio_force_ep_link_up(gxio_trio_context_t * context, unsigned int mac)
+{
+	struct force_ep_link_up_param temp;
+	struct force_ep_link_up_param *params = &temp;
+
+	params->mac = mac;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_TRIO_OP_FORCE_EP_LINK_UP);
+}
+
+EXPORT_SYMBOL(gxio_trio_force_ep_link_up);
+
+struct get_mmio_base_param {
+	HV_PTE base;
+};
+
+int gxio_trio_get_mmio_base(gxio_trio_context_t * context, HV_PTE *base)
+{
+	int __result;
+	struct get_mmio_base_param temp;
+	struct get_mmio_base_param *params = &temp;
+
+	__result =
+	    hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params),
+			 GXIO_TRIO_OP_GET_MMIO_BASE);
+	*base = params->base;
+
+	return __result;
+}
+
+EXPORT_SYMBOL(gxio_trio_get_mmio_base);
+
+struct check_mmio_offset_param {
+	unsigned long offset;
+	unsigned long size;
+};
+
+int gxio_trio_check_mmio_offset(gxio_trio_context_t * context,
+				unsigned long offset, unsigned long size)
+{
+	struct check_mmio_offset_param temp;
+	struct check_mmio_offset_param *params = &temp;
+
+	params->offset = offset;
+	params->size = size;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_TRIO_OP_CHECK_MMIO_OFFSET);
+}
+
+EXPORT_SYMBOL(gxio_trio_check_mmio_offset);
diff --git a/arch/tile/gxio/iorpc_usb_host.c b/arch/tile/gxio/iorpc_usb_host.c
new file mode 100644
index 0000000..cf3c3cc
--- /dev/null
+++ b/arch/tile/gxio/iorpc_usb_host.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+#include "gxio/iorpc_usb_host.h"
+
+struct cfg_interrupt_param {
+	union iorpc_interrupt interrupt;
+};
+
+int gxio_usb_host_cfg_interrupt(gxio_usb_host_context_t * context, int inter_x,
+				int inter_y, int inter_ipi, int inter_event)
+{
+	struct cfg_interrupt_param temp;
+	struct cfg_interrupt_param *params = &temp;
+
+	params->interrupt.kernel.x = inter_x;
+	params->interrupt.kernel.y = inter_y;
+	params->interrupt.kernel.ipi = inter_ipi;
+	params->interrupt.kernel.event = inter_event;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params), GXIO_USB_HOST_OP_CFG_INTERRUPT);
+}
+
+EXPORT_SYMBOL(gxio_usb_host_cfg_interrupt);
+
+struct register_client_memory_param {
+	HV_PTE pte;
+	unsigned int flags;
+};
+
+int gxio_usb_host_register_client_memory(gxio_usb_host_context_t * context,
+					 HV_PTE pte, unsigned int flags)
+{
+	struct register_client_memory_param temp;
+	struct register_client_memory_param *params = &temp;
+
+	params->pte = pte;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_USB_HOST_OP_REGISTER_CLIENT_MEMORY);
+}
+
+EXPORT_SYMBOL(gxio_usb_host_register_client_memory);
+
+struct get_mmio_base_param {
+	HV_PTE base;
+};
+
+int gxio_usb_host_get_mmio_base(gxio_usb_host_context_t * context, HV_PTE *base)
+{
+	int __result;
+	struct get_mmio_base_param temp;
+	struct get_mmio_base_param *params = &temp;
+
+	__result =
+	    hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params),
+			 GXIO_USB_HOST_OP_GET_MMIO_BASE);
+	*base = params->base;
+
+	return __result;
+}
+
+EXPORT_SYMBOL(gxio_usb_host_get_mmio_base);
+
+struct check_mmio_offset_param {
+	unsigned long offset;
+	unsigned long size;
+};
+
+int gxio_usb_host_check_mmio_offset(gxio_usb_host_context_t * context,
+				    unsigned long offset, unsigned long size)
+{
+	struct check_mmio_offset_param temp;
+	struct check_mmio_offset_param *params = &temp;
+
+	params->offset = offset;
+	params->size = size;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_USB_HOST_OP_CHECK_MMIO_OFFSET);
+}
+
+EXPORT_SYMBOL(gxio_usb_host_check_mmio_offset);
diff --git a/arch/tile/gxio/kiorpc.c b/arch/tile/gxio/kiorpc.c
new file mode 100644
index 0000000..c8096aa
--- /dev/null
+++ b/arch/tile/gxio/kiorpc.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * TILE-Gx IORPC support for kernel I/O drivers.
+ */
+
+#include <linux/mmzone.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <gxio/iorpc_globals.h>
+#include <gxio/kiorpc.h>
+
+#ifdef DEBUG_IORPC
+#define TRACE(FMT, ...) pr_info(SIMPLE_MSG_LINE FMT, ## __VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+/* Create kernel-VA-space MMIO mapping for an on-chip IO device. */
+void __iomem *iorpc_ioremap(int hv_fd, resource_size_t offset,
+			    unsigned long size)
+{
+	pgprot_t mmio_base, prot = { 0 };
+	unsigned long pfn;
+	int err;
+
+	/* Look up the shim's lotar and base PA. */
+	err = __iorpc_get_mmio_base(hv_fd, &mmio_base);
+	if (err) {
+		TRACE("get_mmio_base() failure: %d\n", err);
+		return NULL;
+	}
+
+	/* Make sure the HV driver approves of our offset and size. */
+	err = __iorpc_check_mmio_offset(hv_fd, offset, size);
+	if (err) {
+		TRACE("check_mmio_offset() failure: %d\n", err);
+		return NULL;
+	}
+
+	/*
+	 * mmio_base contains a base pfn and homing coordinates.  Turn
+	 * it into an MMIO pgprot and offset pfn.
+	 */
+	prot = hv_pte_set_lotar(prot, hv_pte_get_lotar(mmio_base));
+	pfn = pte_pfn(mmio_base) + PFN_DOWN(offset);
+
+	return ioremap_prot(PFN_PHYS(pfn), size, prot);
+}
+
+EXPORT_SYMBOL(iorpc_ioremap);
diff --git a/arch/tile/gxio/mpipe.c b/arch/tile/gxio/mpipe.c
new file mode 100644
index 0000000..e71c633
--- /dev/null
+++ b/arch/tile/gxio/mpipe.c
@@ -0,0 +1,545 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/*
+ * Implementation of mpipe gxio calls.
+ */
+
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include <gxio/iorpc_globals.h>
+#include <gxio/iorpc_mpipe.h>
+#include <gxio/iorpc_mpipe_info.h>
+#include <gxio/kiorpc.h>
+#include <gxio/mpipe.h>
+
+/* HACK: Avoid pointless "shadow" warnings. */
+#define link link_shadow
+
+int gxio_mpipe_init(gxio_mpipe_context_t *context, unsigned int mpipe_index)
+{
+	char file[32];
+
+	int fd;
+	int i;
+
+	snprintf(file, sizeof(file), "mpipe/%d/iorpc", mpipe_index);
+	fd = hv_dev_open((HV_VirtAddr) file, 0);
+	if (fd < 0) {
+		if (fd >= GXIO_ERR_MIN && fd <= GXIO_ERR_MAX)
+			return fd;
+		else
+			return -ENODEV;
+	}
+
+	context->fd = fd;
+
+	/* Map in the MMIO space. */
+	context->mmio_cfg_base = (void __force *)
+		iorpc_ioremap(fd, HV_MPIPE_CONFIG_MMIO_OFFSET,
+			      HV_MPIPE_CONFIG_MMIO_SIZE);
+	if (context->mmio_cfg_base == NULL)
+		goto cfg_failed;
+
+	context->mmio_fast_base = (void __force *)
+		iorpc_ioremap(fd, HV_MPIPE_FAST_MMIO_OFFSET,
+			      HV_MPIPE_FAST_MMIO_SIZE);
+	if (context->mmio_fast_base == NULL)
+		goto fast_failed;
+
+	/* Initialize the stacks. */
+	for (i = 0; i < 8; i++)
+		context->__stacks.stacks[i] = 255;
+
+	return 0;
+
+      fast_failed:
+	iounmap((void __force __iomem *)(context->mmio_cfg_base));
+      cfg_failed:
+	hv_dev_close(context->fd);
+	return -ENODEV;
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_init);
+
+int gxio_mpipe_destroy(gxio_mpipe_context_t *context)
+{
+	iounmap((void __force __iomem *)(context->mmio_cfg_base));
+	iounmap((void __force __iomem *)(context->mmio_fast_base));
+	return hv_dev_close(context->fd);
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_destroy);
+
+static int16_t gxio_mpipe_buffer_sizes[8] =
+	{ 128, 256, 512, 1024, 1664, 4096, 10368, 16384 };
+
+gxio_mpipe_buffer_size_enum_t gxio_mpipe_buffer_size_to_buffer_size_enum(size_t
+									 size)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		if (size <= gxio_mpipe_buffer_sizes[i])
+			break;
+	return i;
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_buffer_size_to_buffer_size_enum);
+
+size_t gxio_mpipe_buffer_size_enum_to_buffer_size(gxio_mpipe_buffer_size_enum_t
+						  buffer_size_enum)
+{
+	if (buffer_size_enum > 7)
+		buffer_size_enum = 7;
+
+	return gxio_mpipe_buffer_sizes[buffer_size_enum];
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_buffer_size_enum_to_buffer_size);
+
+size_t gxio_mpipe_calc_buffer_stack_bytes(unsigned long buffers)
+{
+	const int BUFFERS_PER_LINE = 12;
+
+	/* Count the number of cachlines. */
+	unsigned long lines =
+		(buffers + BUFFERS_PER_LINE - 1) / BUFFERS_PER_LINE;
+
+	/* Convert to bytes. */
+	return lines * CHIP_L2_LINE_SIZE();
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_calc_buffer_stack_bytes);
+
+int gxio_mpipe_init_buffer_stack(gxio_mpipe_context_t *context,
+				 unsigned int stack,
+				 gxio_mpipe_buffer_size_enum_t
+				 buffer_size_enum, void *mem, size_t mem_size,
+				 unsigned int mem_flags)
+{
+	int result;
+
+	memset(mem, 0, mem_size);
+
+	result = gxio_mpipe_init_buffer_stack_aux(context, mem, mem_size,
+						  mem_flags, stack,
+						  buffer_size_enum);
+	if (result < 0)
+		return result;
+
+	/* Save the stack. */
+	context->__stacks.stacks[buffer_size_enum] = stack;
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_init_buffer_stack);
+
+int gxio_mpipe_init_notif_ring(gxio_mpipe_context_t *context,
+			       unsigned int ring,
+			       void *mem, size_t mem_size,
+			       unsigned int mem_flags)
+{
+	return gxio_mpipe_init_notif_ring_aux(context, mem, mem_size,
+					      mem_flags, ring);
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_init_notif_ring);
+
+int gxio_mpipe_init_notif_group_and_buckets(gxio_mpipe_context_t *context,
+					    unsigned int group,
+					    unsigned int ring,
+					    unsigned int num_rings,
+					    unsigned int bucket,
+					    unsigned int num_buckets,
+					    gxio_mpipe_bucket_mode_t mode)
+{
+	int i;
+	int result;
+
+	gxio_mpipe_bucket_info_t bucket_info = { {
+						  .group = group,
+						  .mode = mode,
+						  }
+	};
+
+	gxio_mpipe_notif_group_bits_t bits = { {0} };
+
+	for (i = 0; i < num_rings; i++)
+		gxio_mpipe_notif_group_add_ring(&bits, ring + i);
+
+	result = gxio_mpipe_init_notif_group(context, group, bits);
+	if (result != 0)
+		return result;
+
+	for (i = 0; i < num_buckets; i++) {
+		bucket_info.notifring = ring + (i % num_rings);
+
+		result = gxio_mpipe_init_bucket(context, bucket + i,
+						bucket_info);
+		if (result != 0)
+			return result;
+	}
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_init_notif_group_and_buckets);
+
+int gxio_mpipe_init_edma_ring(gxio_mpipe_context_t *context,
+			      unsigned int ring, unsigned int channel,
+			      void *mem, size_t mem_size,
+			      unsigned int mem_flags)
+{
+	memset(mem, 0, mem_size);
+
+	return gxio_mpipe_init_edma_ring_aux(context, mem, mem_size, mem_flags,
+					     ring, channel);
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_init_edma_ring);
+
+void gxio_mpipe_rules_init(gxio_mpipe_rules_t *rules,
+			   gxio_mpipe_context_t *context)
+{
+	rules->context = context;
+	memset(&rules->list, 0, sizeof(rules->list));
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_rules_init);
+
+int gxio_mpipe_rules_begin(gxio_mpipe_rules_t *rules,
+			   unsigned int bucket, unsigned int num_buckets,
+			   gxio_mpipe_rules_stacks_t *stacks)
+{
+	int i;
+	int stack = 255;
+
+	gxio_mpipe_rules_list_t *list = &rules->list;
+
+	/* Current rule. */
+	gxio_mpipe_rules_rule_t *rule =
+		(gxio_mpipe_rules_rule_t *) (list->rules + list->head);
+
+	unsigned int head = list->tail;
+
+	/*
+	 * Align next rule properly.
+	 *Note that "dmacs_and_vlans" will also be aligned.
+	 */
+	unsigned int pad = 0;
+	while (((head + pad) % __alignof__(gxio_mpipe_rules_rule_t)) != 0)
+		pad++;
+
+	/*
+	 * Verify room.
+	 * ISSUE: Mark rules as broken on error?
+	 */
+	if (head + pad + sizeof(*rule) >= sizeof(list->rules))
+		return GXIO_MPIPE_ERR_RULES_FULL;
+
+	/* Verify num_buckets is a power of 2. */
+	if (__builtin_popcount(num_buckets) != 1)
+		return GXIO_MPIPE_ERR_RULES_INVALID;
+
+	/* Add padding to previous rule. */
+	rule->size += pad;
+
+	/* Start a new rule. */
+	list->head = head + pad;
+
+	rule = (gxio_mpipe_rules_rule_t *) (list->rules + list->head);
+
+	/* Default some values. */
+	rule->headroom = 2;
+	rule->tailroom = 0;
+	rule->capacity = 16384;
+
+	/* Save the bucket info. */
+	rule->bucket_mask = num_buckets - 1;
+	rule->bucket_first = bucket;
+
+	for (i = 8 - 1; i >= 0; i--) {
+		int maybe =
+			stacks ? stacks->stacks[i] : rules->context->__stacks.
+			stacks[i];
+		if (maybe != 255)
+			stack = maybe;
+		rule->stacks.stacks[i] = stack;
+	}
+
+	if (stack == 255)
+		return GXIO_MPIPE_ERR_RULES_INVALID;
+
+	/* NOTE: Only entries at the end of the array can be 255. */
+	for (i = 8 - 1; i > 0; i--) {
+		if (rule->stacks.stacks[i] == 255) {
+			rule->stacks.stacks[i] = stack;
+			rule->capacity =
+				gxio_mpipe_buffer_size_enum_to_buffer_size(i -
+									   1);
+		}
+	}
+
+	rule->size = sizeof(*rule);
+	list->tail = list->head + rule->size;
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_rules_begin);
+
+int gxio_mpipe_rules_add_channel(gxio_mpipe_rules_t *rules,
+				 unsigned int channel)
+{
+	gxio_mpipe_rules_list_t *list = &rules->list;
+
+	gxio_mpipe_rules_rule_t *rule =
+		(gxio_mpipe_rules_rule_t *) (list->rules + list->head);
+
+	/* Verify channel. */
+	if (channel >= 32)
+		return GXIO_MPIPE_ERR_RULES_INVALID;
+
+	/* Verify begun. */
+	if (list->tail == 0)
+		return GXIO_MPIPE_ERR_RULES_EMPTY;
+
+	rule->channel_bits |= (1UL << channel);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_rules_add_channel);
+
+int gxio_mpipe_rules_set_headroom(gxio_mpipe_rules_t *rules, uint8_t headroom)
+{
+	gxio_mpipe_rules_list_t *list = &rules->list;
+
+	gxio_mpipe_rules_rule_t *rule =
+		(gxio_mpipe_rules_rule_t *) (list->rules + list->head);
+
+	/* Verify begun. */
+	if (list->tail == 0)
+		return GXIO_MPIPE_ERR_RULES_EMPTY;
+
+	rule->headroom = headroom;
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_rules_set_headroom);
+
+int gxio_mpipe_rules_commit(gxio_mpipe_rules_t *rules)
+{
+	gxio_mpipe_rules_list_t *list = &rules->list;
+	unsigned int size =
+		offsetof(gxio_mpipe_rules_list_t, rules) + list->tail;
+	return gxio_mpipe_commit_rules(rules->context, list, size);
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_rules_commit);
+
+int gxio_mpipe_iqueue_init(gxio_mpipe_iqueue_t *iqueue,
+			   gxio_mpipe_context_t *context,
+			   unsigned int ring,
+			   void *mem, size_t mem_size, unsigned int mem_flags)
+{
+	/* The init call below will verify that "mem_size" is legal. */
+	unsigned int num_entries = mem_size / sizeof(gxio_mpipe_idesc_t);
+
+	iqueue->context = context;
+	iqueue->idescs = (gxio_mpipe_idesc_t *)mem;
+	iqueue->ring = ring;
+	iqueue->num_entries = num_entries;
+	iqueue->mask_num_entries = num_entries - 1;
+	iqueue->log2_num_entries = __builtin_ctz(num_entries);
+	iqueue->head = 1;
+#ifdef __BIG_ENDIAN__
+	iqueue->swapped = 0;
+#endif
+
+	/* Initialize the "tail". */
+	__gxio_mmio_write(mem, iqueue->head);
+
+	return gxio_mpipe_init_notif_ring(context, ring, mem, mem_size,
+					  mem_flags);
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_iqueue_init);
+
+int gxio_mpipe_equeue_init(gxio_mpipe_equeue_t *equeue,
+			   gxio_mpipe_context_t *context,
+			   unsigned int edma_ring_id,
+			   unsigned int channel,
+			   void *mem, unsigned int mem_size,
+			   unsigned int mem_flags)
+{
+	/* The init call below will verify that "mem_size" is legal. */
+	unsigned int num_entries = mem_size / sizeof(gxio_mpipe_edesc_t);
+
+	/* Offset used to read number of completed commands. */
+	MPIPE_EDMA_POST_REGION_ADDR_t offset;
+
+	int result = gxio_mpipe_init_edma_ring(context, edma_ring_id, channel,
+					       mem, mem_size, mem_flags);
+	if (result < 0)
+		return result;
+
+	memset(equeue, 0, sizeof(*equeue));
+
+	offset.word = 0;
+	offset.region =
+		MPIPE_MMIO_ADDR__REGION_VAL_EDMA -
+		MPIPE_MMIO_ADDR__REGION_VAL_IDMA;
+	offset.ring = edma_ring_id;
+
+	__gxio_dma_queue_init(&equeue->dma_queue,
+			      context->mmio_fast_base + offset.word,
+			      num_entries);
+	equeue->edescs = mem;
+	equeue->mask_num_entries = num_entries - 1;
+	equeue->log2_num_entries = __builtin_ctz(num_entries);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_equeue_init);
+
+int gxio_mpipe_set_timestamp(gxio_mpipe_context_t *context,
+			     const struct timespec *ts)
+{
+	cycles_t cycles = get_cycles();
+	return gxio_mpipe_set_timestamp_aux(context, (uint64_t)ts->tv_sec,
+					    (uint64_t)ts->tv_nsec,
+					    (uint64_t)cycles);
+}
+
+int gxio_mpipe_get_timestamp(gxio_mpipe_context_t *context,
+			     struct timespec *ts)
+{
+	int ret;
+	cycles_t cycles_prev, cycles_now, clock_rate;
+	cycles_prev = get_cycles();
+	ret = gxio_mpipe_get_timestamp_aux(context, (uint64_t *)&ts->tv_sec,
+					   (uint64_t *)&ts->tv_nsec,
+					   (uint64_t *)&cycles_now);
+	if (ret < 0) {
+		return ret;
+	}
+
+	clock_rate = get_clock_rate();
+	ts->tv_nsec -= (cycles_now - cycles_prev) * 1000000000LL / clock_rate;
+	if (ts->tv_nsec < 0) {
+		ts->tv_nsec += 1000000000LL;
+		ts->tv_sec -= 1;
+	}
+	return ret;
+}
+
+int gxio_mpipe_adjust_timestamp(gxio_mpipe_context_t *context, int64_t delta)
+{
+	return gxio_mpipe_adjust_timestamp_aux(context, delta);
+}
+
+/* Get our internal context used for link name access.  This context is
+ *  special in that it is not associated with an mPIPE service domain.
+ */
+static gxio_mpipe_context_t *_gxio_get_link_context(void)
+{
+	static gxio_mpipe_context_t context;
+	static gxio_mpipe_context_t *contextp;
+	static int tried_open = 0;
+	static DEFINE_MUTEX(mutex);
+
+	mutex_lock(&mutex);
+
+	if (!tried_open) {
+		int i = 0;
+		tried_open = 1;
+
+		/*
+		 * "4" here is the maximum possible number of mPIPE shims; it's
+		 * an exaggeration but we shouldn't ever go beyond 2 anyway.
+		 */
+		for (i = 0; i < 4; i++) {
+			char file[80];
+
+			snprintf(file, sizeof(file), "mpipe/%d/iorpc_info", i);
+			context.fd = hv_dev_open((HV_VirtAddr) file, 0);
+			if (context.fd < 0)
+				continue;
+
+			contextp = &context;
+			break;
+		}
+	}
+
+	mutex_unlock(&mutex);
+
+	return contextp;
+}
+
+int gxio_mpipe_link_enumerate_mac(int idx, char *link_name, uint8_t *link_mac)
+{
+	int rv;
+	_gxio_mpipe_link_name_t name;
+	_gxio_mpipe_link_mac_t mac;
+
+	gxio_mpipe_context_t *context = _gxio_get_link_context();
+	if (!context)
+		return GXIO_ERR_NO_DEVICE;
+
+	rv = gxio_mpipe_info_enumerate_aux(context, idx, &name, &mac);
+	if (rv >= 0) {
+		strncpy(link_name, name.name, sizeof(name.name));
+		memcpy(link_mac, mac.mac, sizeof(mac.mac));
+	}
+
+	return rv;
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_link_enumerate_mac);
+
+int gxio_mpipe_link_open(gxio_mpipe_link_t *link,
+			 gxio_mpipe_context_t *context, const char *link_name,
+			 unsigned int flags)
+{
+	_gxio_mpipe_link_name_t name;
+	int rv;
+
+	strncpy(name.name, link_name, sizeof(name.name));
+	name.name[GXIO_MPIPE_LINK_NAME_LEN - 1] = '\0';
+
+	rv = gxio_mpipe_link_open_aux(context, name, flags);
+	if (rv < 0)
+		return rv;
+
+	link->context = context;
+	link->channel = rv >> 8;
+	link->mac = rv & 0xFF;
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_link_open);
+
+int gxio_mpipe_link_close(gxio_mpipe_link_t *link)
+{
+	return gxio_mpipe_link_close_aux(link->context, link->mac);
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_link_close);
diff --git a/arch/tile/gxio/trio.c b/arch/tile/gxio/trio.c
new file mode 100644
index 0000000..69f0b8d
--- /dev/null
+++ b/arch/tile/gxio/trio.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/*
+ * Implementation of trio gxio calls.
+ */
+
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include <gxio/trio.h>
+#include <gxio/iorpc_globals.h>
+#include <gxio/iorpc_trio.h>
+#include <gxio/kiorpc.h>
+
+int gxio_trio_init(gxio_trio_context_t *context, unsigned int trio_index)
+{
+	char file[32];
+	int fd;
+
+	snprintf(file, sizeof(file), "trio/%d/iorpc", trio_index);
+	fd = hv_dev_open((HV_VirtAddr) file, 0);
+	if (fd < 0) {
+		context->fd = -1;
+
+		if (fd >= GXIO_ERR_MIN && fd <= GXIO_ERR_MAX)
+			return fd;
+		else
+			return -ENODEV;
+	}
+
+	context->fd = fd;
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(gxio_trio_init);
diff --git a/arch/tile/gxio/usb_host.c b/arch/tile/gxio/usb_host.c
new file mode 100644
index 0000000..66b002f
--- /dev/null
+++ b/arch/tile/gxio/usb_host.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/*
+ *
+ * Implementation of USB gxio calls.
+ */
+
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+
+#include <gxio/iorpc_globals.h>
+#include <gxio/iorpc_usb_host.h>
+#include <gxio/kiorpc.h>
+#include <gxio/usb_host.h>
+
+int gxio_usb_host_init(gxio_usb_host_context_t * context, int usb_index,
+		       int is_ehci)
+{
+	char file[32];
+	int fd;
+
+	if (is_ehci)
+		snprintf(file, sizeof(file), "usb_host/%d/iorpc/ehci",
+			 usb_index);
+	else
+		snprintf(file, sizeof(file), "usb_host/%d/iorpc/ohci",
+			 usb_index);
+
+	fd = hv_dev_open((HV_VirtAddr) file, 0);
+	if (fd < 0) {
+		if (fd >= GXIO_ERR_MIN && fd <= GXIO_ERR_MAX)
+			return fd;
+		else
+			return -ENODEV;
+	}
+
+	context->fd = fd;
+
+	// Map in the MMIO space.
+	context->mmio_base =
+		(void __force *)iorpc_ioremap(fd, 0, HV_USB_HOST_MMIO_SIZE);
+
+	if (context->mmio_base == NULL) {
+		hv_dev_close(context->fd);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(gxio_usb_host_init);
+
+int gxio_usb_host_destroy(gxio_usb_host_context_t * context)
+{
+	iounmap((void __force __iomem *)(context->mmio_base));
+	hv_dev_close(context->fd);
+
+	context->mmio_base = NULL;
+	context->fd = -1;
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(gxio_usb_host_destroy);
+
+void *gxio_usb_host_get_reg_start(gxio_usb_host_context_t * context)
+{
+	return context->mmio_base;
+}
+
+EXPORT_SYMBOL_GPL(gxio_usb_host_get_reg_start);
+
+size_t gxio_usb_host_get_reg_len(gxio_usb_host_context_t * context)
+{
+	return HV_USB_HOST_MMIO_SIZE;
+}
+
+EXPORT_SYMBOL_GPL(gxio_usb_host_get_reg_len);
diff --git a/arch/tile/include/arch/mpipe.h b/arch/tile/include/arch/mpipe.h
new file mode 100644
index 0000000..8a33912
--- /dev/null
+++ b/arch/tile/include/arch/mpipe.h
@@ -0,0 +1,359 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_MPIPE_H__
+#define __ARCH_MPIPE_H__
+
+#include <arch/abi.h>
+#include <arch/mpipe_def.h>
+
+#ifndef __ASSEMBLER__
+
+/*
+ * MMIO Ingress DMA Release Region Address.
+ * This is a description of the physical addresses used to manipulate ingress
+ * credit counters.  Accesses to this address space should use an address of
+ * this form and a value like that specified in IDMA_RELEASE_REGION_VAL.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /* Reserved. */
+    uint_reg_t __reserved_0  : 3;
+    /* NotifRing to be released */
+    uint_reg_t ring          : 8;
+    /* Bucket to be released */
+    uint_reg_t bucket        : 13;
+    /* Enable NotifRing release */
+    uint_reg_t ring_enable   : 1;
+    /* Enable Bucket release */
+    uint_reg_t bucket_enable : 1;
+    /*
+     * This field of the address selects the region (address space) to be
+     * accessed.  For the iDMA release region, this field must be 4.
+     */
+    uint_reg_t region        : 3;
+    /* Reserved. */
+    uint_reg_t __reserved_1  : 6;
+    /* This field of the address indexes the 32 entry service domain table. */
+    uint_reg_t svc_dom       : 5;
+    /* Reserved. */
+    uint_reg_t __reserved_2  : 24;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved_2  : 24;
+    uint_reg_t svc_dom       : 5;
+    uint_reg_t __reserved_1  : 6;
+    uint_reg_t region        : 3;
+    uint_reg_t bucket_enable : 1;
+    uint_reg_t ring_enable   : 1;
+    uint_reg_t bucket        : 13;
+    uint_reg_t ring          : 8;
+    uint_reg_t __reserved_0  : 3;
+#endif
+  };
+
+  uint_reg_t word;
+} MPIPE_IDMA_RELEASE_REGION_ADDR_t;
+
+/*
+ * MMIO Ingress DMA Release Region Value - Release NotifRing and/or Bucket.
+ * Provides release of the associated NotifRing.  The address of the MMIO
+ * operation is described in IDMA_RELEASE_REGION_ADDR.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /*
+     * Number of packets being released.  The load balancer's count of
+     * inflight packets will be decremented by this amount for the associated
+     * Bucket and/or NotifRing
+     */
+    uint_reg_t count      : 16;
+    /* Reserved. */
+    uint_reg_t __reserved : 48;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved : 48;
+    uint_reg_t count      : 16;
+#endif
+  };
+
+  uint_reg_t word;
+} MPIPE_IDMA_RELEASE_REGION_VAL_t;
+
+/*
+ * MMIO Buffer Stack Manager Region Address.
+ * This MMIO region is used for posting or fetching buffers to/from the
+ * buffer stack manager.  On an MMIO load, this pops a buffer descriptor from
+ * the top of stack if one is available.  On an MMIO store, this pushes a
+ * buffer to the stack.  The value read or written is described in
+ * BSM_REGION_VAL.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /* Reserved. */
+    uint_reg_t __reserved_0 : 3;
+    /* BufferStack being accessed. */
+    uint_reg_t stack        : 5;
+    /* Reserved. */
+    uint_reg_t __reserved_1 : 18;
+    /*
+     * This field of the address selects the region (address space) to be
+     * accessed.  For the buffer stack manager region, this field must be 6.
+     */
+    uint_reg_t region       : 3;
+    /* Reserved. */
+    uint_reg_t __reserved_2 : 6;
+    /* This field of the address indexes the 32 entry service domain table. */
+    uint_reg_t svc_dom      : 5;
+    /* Reserved. */
+    uint_reg_t __reserved_3 : 24;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved_3 : 24;
+    uint_reg_t svc_dom      : 5;
+    uint_reg_t __reserved_2 : 6;
+    uint_reg_t region       : 3;
+    uint_reg_t __reserved_1 : 18;
+    uint_reg_t stack        : 5;
+    uint_reg_t __reserved_0 : 3;
+#endif
+  };
+
+  uint_reg_t word;
+} MPIPE_BSM_REGION_ADDR_t;
+
+/*
+ * MMIO Buffer Stack Manager Region Value.
+ * This MMIO region is used for posting or fetching buffers to/from the
+ * buffer stack manager.  On an MMIO load, this pops a buffer descriptor from
+ * the top of stack if one is available. On an MMIO store, this pushes a
+ * buffer to the stack.  The address of the MMIO operation is described in
+ * BSM_REGION_ADDR.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /* Reserved. */
+    uint_reg_t __reserved_0 : 7;
+    /*
+     * Base virtual address of the buffer.  Must be sign extended by consumer.
+     */
+    int_reg_t va           : 35;
+    /* Reserved. */
+    uint_reg_t __reserved_1 : 6;
+    /*
+     * Index of the buffer stack to which this buffer belongs.  Ignored on
+     * writes since the offset bits specify the stack being accessed.
+     */
+    uint_reg_t stack_idx    : 5;
+    /* Reserved. */
+    uint_reg_t __reserved_2 : 5;
+    /*
+     * Reads as one to indicate that this is a hardware managed buffer.
+     * Ignored on writes since all buffers on a given stack are the same size.
+     */
+    uint_reg_t hwb          : 1;
+    /*
+     * Encoded size of buffer (ignored on writes):
+     * 0 = 128 bytes
+     * 1 = 256 bytes
+     * 2 = 512 bytes
+     * 3 = 1024 bytes
+     * 4 = 1664 bytes
+     * 5 = 4096 bytes
+     * 6 = 10368 bytes
+     * 7 = 16384 bytes
+     */
+    uint_reg_t size         : 3;
+    /*
+     * Valid indication for the buffer.  Ignored on writes.
+     * 0 : Valid buffer descriptor popped from stack.
+     * 3 : Could not pop a buffer from the stack.  Either the stack is empty,
+     * or the hardware's prefetch buffer is empty for this stack.
+     */
+    uint_reg_t c            : 2;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t c            : 2;
+    uint_reg_t size         : 3;
+    uint_reg_t hwb          : 1;
+    uint_reg_t __reserved_2 : 5;
+    uint_reg_t stack_idx    : 5;
+    uint_reg_t __reserved_1 : 6;
+    int_reg_t va           : 35;
+    uint_reg_t __reserved_0 : 7;
+#endif
+  };
+
+  uint_reg_t word;
+} MPIPE_BSM_REGION_VAL_t;
+
+/*
+ * MMIO Egress DMA Post Region Address.
+ * Used to post descriptor locations to the eDMA descriptor engine.  The
+ * value to be written is described in EDMA_POST_REGION_VAL
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /* Reserved. */
+    uint_reg_t __reserved_0 : 3;
+    /* eDMA ring being accessed */
+    uint_reg_t ring         : 5;
+    /* Reserved. */
+    uint_reg_t __reserved_1 : 18;
+    /*
+     * This field of the address selects the region (address space) to be
+     * accessed.  For the egress DMA post region, this field must be 5.
+     */
+    uint_reg_t region       : 3;
+    /* Reserved. */
+    uint_reg_t __reserved_2 : 6;
+    /* This field of the address indexes the 32 entry service domain table. */
+    uint_reg_t svc_dom      : 5;
+    /* Reserved. */
+    uint_reg_t __reserved_3 : 24;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved_3 : 24;
+    uint_reg_t svc_dom      : 5;
+    uint_reg_t __reserved_2 : 6;
+    uint_reg_t region       : 3;
+    uint_reg_t __reserved_1 : 18;
+    uint_reg_t ring         : 5;
+    uint_reg_t __reserved_0 : 3;
+#endif
+  };
+
+  uint_reg_t word;
+} MPIPE_EDMA_POST_REGION_ADDR_t;
+
+/*
+ * MMIO Egress DMA Post Region Value.
+ * Used to post descriptor locations to the eDMA descriptor engine.  The
+ * address is described in EDMA_POST_REGION_ADDR.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /*
+     * For writes, this specifies the current ring tail pointer prior to any
+     * post.  For example, to post 1 or more descriptors starting at location
+     * 23, this would contain 23 (not 24).  On writes, this index must be
+     * masked based on the ring size.  The new tail pointer after this post
+     * is COUNT+RING_IDX (masked by the ring size).
+     *
+     * For reads, this provides the hardware descriptor fetcher's head
+     * pointer.  The descriptors prior to the head pointer, however, may not
+     * yet have been processed so this indicator is only used to determine
+     * how full the ring is and if software may post more descriptors.
+     */
+    uint_reg_t ring_idx   : 16;
+    /*
+     * For writes, this specifies number of contiguous descriptors that are
+     * being posted.  Software may post up to RingSize descriptors with a
+     * single MMIO store.  A zero in this field on a write will "wake up" an
+     * eDMA ring and cause it fetch descriptors regardless of the hardware's
+     * current view of the state of the tail pointer.
+     *
+     * For reads, this field provides a rolling count of the number of
+     * descriptors that have been completely processed.  This may be used by
+     * software to determine when buffers associated with a descriptor may be
+     * returned or reused.  When the ring's flush bit is cleared by software
+     * (after having been set by HW or SW), the COUNT will be cleared.
+     */
+    uint_reg_t count      : 16;
+    /*
+     * For writes, this specifies the generation number of the tail being
+     * posted. Note that if tail+cnt wraps to the beginning of the ring, the
+     * eDMA hardware assumes that the descriptors posted at the beginning of
+     * the ring are also valid so it is okay to post around the wrap point.
+     *
+     * For reads, this is the current generation number.  Valid descriptors
+     * will have the inverse of this generation number.
+     */
+    uint_reg_t gen        : 1;
+    /* Reserved. */
+    uint_reg_t __reserved : 31;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved : 31;
+    uint_reg_t gen        : 1;
+    uint_reg_t count      : 16;
+    uint_reg_t ring_idx   : 16;
+#endif
+  };
+
+  uint_reg_t word;
+} MPIPE_EDMA_POST_REGION_VAL_t;
+
+/*
+ * Load Balancer Bucket Status Data.
+ * Read/Write data for load balancer Bucket-Status Table. 4160 entries
+ * indexed by LBL_INIT_CTL.IDX when LBL_INIT_CTL.STRUCT_SEL is BSTS_TBL
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /* NotifRing currently assigned to this bucket. */
+    uint_reg_t notifring  : 8;
+    /* Current reference count. */
+    uint_reg_t count      : 16;
+    /* Group associated with this bucket. */
+    uint_reg_t group      : 5;
+    /* Mode select for this bucket. */
+    uint_reg_t mode       : 3;
+    /* Reserved. */
+    uint_reg_t __reserved : 32;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved : 32;
+    uint_reg_t mode       : 3;
+    uint_reg_t group      : 5;
+    uint_reg_t count      : 16;
+    uint_reg_t notifring  : 8;
+#endif
+  };
+
+  uint_reg_t word;
+} MPIPE_LBL_INIT_DAT_BSTS_TBL_t;
+#endif /* !defined(__ASSEMBLER__) */
+
+#endif /* !defined(__ARCH_MPIPE_H__) */
diff --git a/arch/tile/include/arch/mpipe_constants.h b/arch/tile/include/arch/mpipe_constants.h
new file mode 100644
index 0000000..410a040
--- /dev/null
+++ b/arch/tile/include/arch/mpipe_constants.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+
+#ifndef __ARCH_MPIPE_CONSTANTS_H__
+#define __ARCH_MPIPE_CONSTANTS_H__
+
+#define MPIPE_NUM_CLASSIFIERS 10
+#define MPIPE_CLS_MHZ 1200
+
+#define MPIPE_NUM_EDMA_RINGS 32
+
+#define MPIPE_NUM_SGMII_MACS 16
+#define MPIPE_NUM_XAUI_MACS 4
+#define MPIPE_NUM_LOOPBACK_CHANNELS 4
+#define MPIPE_NUM_NON_LB_CHANNELS 28
+
+#define MPIPE_NUM_IPKT_BLOCKS 1536
+
+#define MPIPE_NUM_BUCKETS 4160
+
+#define MPIPE_NUM_NOTIF_RINGS 256
+
+#define MPIPE_NUM_NOTIF_GROUPS 32
+
+#define MPIPE_NUM_TLBS_PER_ASID 16
+#define MPIPE_TLB_IDX_WIDTH 4
+
+#define MPIPE_MMIO_NUM_SVC_DOM 32
+
+#endif /* __ARCH_MPIPE_CONSTANTS_H__ */
diff --git a/arch/tile/include/arch/mpipe_def.h b/arch/tile/include/arch/mpipe_def.h
new file mode 100644
index 0000000..c3d3021
--- /dev/null
+++ b/arch/tile/include/arch/mpipe_def.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_MPIPE_DEF_H__
+#define __ARCH_MPIPE_DEF_H__
+#define MPIPE_MMIO_ADDR__REGION_SHIFT 26
+#define MPIPE_MMIO_ADDR__REGION_VAL_CFG 0x0
+#define MPIPE_MMIO_ADDR__REGION_VAL_IDMA 0x4
+#define MPIPE_MMIO_ADDR__REGION_VAL_EDMA 0x5
+#define MPIPE_MMIO_ADDR__REGION_VAL_BSM 0x6
+#define MPIPE_BSM_REGION_VAL__VA_SHIFT 7
+#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_128 0x0
+#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_256 0x1
+#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_512 0x2
+#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_1024 0x3
+#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_1664 0x4
+#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_4096 0x5
+#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_10368 0x6
+#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_16384 0x7
+#define MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_DFA 0x0
+#define MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_FIXED 0x1
+#define MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_ALWAYS_PICK 0x2
+#define MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_STICKY 0x3
+#define MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_STICKY_RAND 0x7
+#define MPIPE_LBL_NR_STATE__FIRST_WORD 0x2138
+#endif /* !defined(__ARCH_MPIPE_DEF_H__) */
diff --git a/arch/tile/include/arch/mpipe_shm.h b/arch/tile/include/arch/mpipe_shm.h
new file mode 100644
index 0000000..f2e9e12
--- /dev/null
+++ b/arch/tile/include/arch/mpipe_shm.h
@@ -0,0 +1,509 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+
+#ifndef __ARCH_MPIPE_SHM_H__
+#define __ARCH_MPIPE_SHM_H__
+
+#include <arch/abi.h>
+#include <arch/mpipe_shm_def.h>
+
+#ifndef __ASSEMBLER__
+/**
+ * MPIPE eDMA Descriptor.
+ * The eDMA descriptor is written by software and consumed by hardware.  It
+ * is used to specify the location of egress packet data to be sent out of
+ * the chip via one of the packet interfaces.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+    /* Word 0 */
+
+#ifndef __BIG_ENDIAN__
+    /**
+     * Generation number.  Used to indicate a valid descriptor in ring.  When
+     * a new descriptor is written into the ring, software must toggle this
+     * bit.  The net effect is that the GEN bit being written into new
+     * descriptors toggles each time the ring tail pointer wraps.
+     */
+    uint_reg_t gen        : 1;
+    /** Reserved.  Must be zero. */
+    uint_reg_t r0         : 7;
+    /** Checksum generation enabled for this transfer. */
+    uint_reg_t csum       : 1;
+    /**
+     * Nothing to be sent.  Used, for example, when software has dropped a
+     * packet but still wishes to return all of the associated buffers.
+     */
+    uint_reg_t ns         : 1;
+    /**
+     * Notification interrupt will be delivered when packet has been egressed.
+     */
+    uint_reg_t notif      : 1;
+    /**
+     * Boundary indicator.  When 1, this transfer includes the EOP for this
+     * command.  Must be clear on all but the last descriptor for an egress
+     * packet.
+     */
+    uint_reg_t bound      : 1;
+    /** Reserved.  Must be zero. */
+    uint_reg_t r1         : 4;
+    /**
+     * Number of bytes to be sent for this descriptor.  When zero, no data
+     * will be moved and the buffer descriptor will be ignored.  If the
+     * buffer descriptor indicates that it is chained, the low 7 bits of the
+     * VA indicate the offset within the first buffer (e.g. 127 bytes is the
+     * maximum offset into the first buffer).  If the size exceeds a single
+     * buffer, subsequent buffer descriptors will be fetched prior to
+     * processing the next eDMA descriptor in the ring.
+     */
+    uint_reg_t xfer_size  : 14;
+    /** Reserved.  Must be zero. */
+    uint_reg_t r2         : 2;
+    /**
+     * Destination of checksum relative to CSUM_START relative to the first
+     * byte moved by this descriptor.  Must be zero if CSUM=0 in this
+     * descriptor.  Must be less than XFER_SIZE (e.g. the first byte of the
+     * CSUM_DEST must be within the span of this descriptor).
+     */
+    uint_reg_t csum_dest  : 8;
+    /**
+     * Start byte of checksum relative to the first byte moved by this
+     * descriptor.  If this is not the first descriptor for the egress
+     * packet, CSUM_START is still relative to the first byte in this
+     * descriptor.  Must be zero if CSUM=0 in this descriptor.
+     */
+    uint_reg_t csum_start : 8;
+    /**
+     * Initial value for 16-bit 1's compliment checksum if enabled via CSUM.
+     * Specified in network order.  That is, bits[7:0] will be added to the
+     * byte pointed to by CSUM_START and bits[15:8] will be added to the byte
+     * pointed to by CSUM_START+1 (with appropriate 1's compliment carries).
+     * Must be zero if CSUM=0 in this descriptor.
+     */
+    uint_reg_t csum_seed  : 16;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t csum_seed  : 16;
+    uint_reg_t csum_start : 8;
+    uint_reg_t csum_dest  : 8;
+    uint_reg_t r2         : 2;
+    uint_reg_t xfer_size  : 14;
+    uint_reg_t r1         : 4;
+    uint_reg_t bound      : 1;
+    uint_reg_t notif      : 1;
+    uint_reg_t ns         : 1;
+    uint_reg_t csum       : 1;
+    uint_reg_t r0         : 7;
+    uint_reg_t gen        : 1;
+#endif
+
+    /* Word 1 */
+
+#ifndef __BIG_ENDIAN__
+    /** Virtual address.  Must be sign extended by consumer. */
+    int_reg_t va           : 42;
+    /** Reserved. */
+    uint_reg_t __reserved_0 : 6;
+    /** Index of the buffer stack to which this buffer belongs. */
+    uint_reg_t stack_idx    : 5;
+    /** Reserved. */
+    uint_reg_t __reserved_1 : 3;
+    /**
+     * Instance ID.  For devices that support more than one mPIPE instance,
+     * this field indicates the buffer owner.  If the INST field does not
+     * match the mPIPE's instance number when a packet is egressed, buffers
+     * with HWB set will be returned to the other mPIPE instance.
+     */
+    uint_reg_t inst         : 1;
+    /** Reserved. */
+    uint_reg_t __reserved_2 : 1;
+    /**
+     * Always set to one by hardware in iDMA packet descriptors.  For eDMA,
+     * indicates whether the buffer will be released to the buffer stack
+     * manager.  When 0, software is responsible for releasing the buffer.
+     */
+    uint_reg_t hwb          : 1;
+    /**
+     * Encoded size of buffer.  Set by the ingress hardware for iDMA packet
+     * descriptors.  For eDMA descriptors, indicates the buffer size if .c
+     * indicates a chained packet.  If an eDMA descriptor is not chained and
+     * the .hwb bit is not set, this field is ignored and the size is
+     * specified by the .xfer_size field.
+     * 0 = 128 bytes
+     * 1 = 256 bytes
+     * 2 = 512 bytes
+     * 3 = 1024 bytes
+     * 4 = 1664 bytes
+     * 5 = 4096 bytes
+     * 6 = 10368 bytes
+     * 7 = 16384 bytes
+     */
+    uint_reg_t size         : 3;
+    /**
+     * Chaining configuration for the buffer.  Indicates that an ingress
+     * packet or egress command is chained across multiple buffers, with each
+     * buffer's size indicated by the .size field.
+     */
+    uint_reg_t c            : 2;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t c            : 2;
+    uint_reg_t size         : 3;
+    uint_reg_t hwb          : 1;
+    uint_reg_t __reserved_2 : 1;
+    uint_reg_t inst         : 1;
+    uint_reg_t __reserved_1 : 3;
+    uint_reg_t stack_idx    : 5;
+    uint_reg_t __reserved_0 : 6;
+    int_reg_t va           : 42;
+#endif
+
+  };
+
+  /** Word access */
+  uint_reg_t words[2];
+} MPIPE_EDMA_DESC_t;
+
+/**
+ * MPIPE Packet Descriptor.
+ * The packet descriptor is filled by the mPIPE's classification,
+ * load-balancing, and buffer management services.  Some fields are consumed
+ * by mPIPE hardware, and others are consumed by Tile software.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+    /* Word 0 */
+
+#ifndef __BIG_ENDIAN__
+    /**
+     * Notification ring into which this packet descriptor is written.
+     * Typically written by load balancer, but can be overridden by
+     * classification program if NR is asserted.
+     */
+    uint_reg_t notif_ring   : 8;
+    /** Source channel for this packet.  Written by mPIPE DMA hardware. */
+    uint_reg_t channel      : 5;
+    /** Reserved. */
+    uint_reg_t __reserved_0 : 1;
+    /**
+     * MAC Error.
+     * Generated by the MAC interface.  Asserted if there was an overrun of
+     * the MAC's receive FIFO.  This condition generally only occurs if the
+     * mPIPE clock is running too slowly.
+     */
+    uint_reg_t me           : 1;
+    /**
+     * Truncation Error.
+     * Written by the iDMA hardware.  Asserted if packet was truncated due to
+     * insufficient space in iPkt buffer
+     */
+    uint_reg_t tr           : 1;
+    /**
+     * Written by the iDMA hardware.  Indicates the number of bytes written
+     * to Tile memory.  In general, this is the actual size of the packet as
+     * received from the MAC.  But if the packet is truncated due to running
+     * out of buffers or due to the iPkt buffer filling up, then the L2_SIZE
+     * will be reduced to reflect the actual number of valid bytes written to
+     * Tile memory.
+     */
+    uint_reg_t l2_size      : 14;
+    /**
+     * CRC Error.
+     * Generated by the MAC.  Asserted if MAC indicated an L2 CRC error or
+     * other L2 error (bad length etc.) on the packet.
+     */
+    uint_reg_t ce           : 1;
+    /**
+     * Cut Through.
+     * Written by the iDMA hardware.  Asserted if packet was not completely
+     * received before being sent to classifier.  L2_Size will indicate
+     * number of bytes received so far.
+     */
+    uint_reg_t ct           : 1;
+    /**
+     * Written by the classification program.  Used by the load balancer to
+     * select the ring into which this packet descriptor is written.
+     */
+    uint_reg_t bucket_id    : 13;
+    /** Reserved. */
+    uint_reg_t __reserved_1 : 3;
+    /**
+     * Checksum.
+     * Written by classification program.  When 1, the checksum engine will
+     * perform checksum based on the CSUM_SEED, CSUM_START, and CSUM_BYTES
+     * fields.  The result will be placed in CSUM_VAL.
+     */
+    uint_reg_t cs           : 1;
+    /**
+     * Notification Ring Select.
+     * Written by the classification program.  When 1, the NotifRingIDX is
+     * set by classification program rather than being set by load balancer.
+     */
+    uint_reg_t nr           : 1;
+    /**
+     * Written by classification program.  Indicates whether packet and
+     * descriptor should both be dropped, both be delivered, or only the
+     * descriptor should be delivered.
+     */
+    uint_reg_t dest         : 2;
+    /**
+     * General Purpose Sequence Number Enable.
+     * Written by the classification program.  When 1, the GP_SQN_SEL field
+     * contains the sequence number selector and the GP_SQN field will be
+     * replaced with the associated sequence number.  When clear, the GP_SQN
+     * field is left intact and be used as "Custom" bytes.
+     */
+    uint_reg_t sq           : 1;
+    /**
+     * TimeStamp Enable.
+     * Enable TimeStamp insertion.  When clear, timestamp field may be filled
+     * with custom data by classifier.  When set, hardware inserts the
+     * timestamp when the start of packet is received from the MAC.
+     */
+    uint_reg_t ts           : 1;
+    /**
+     * Packet Sequence Number Enable.
+     * Enable PacketSQN insertion.  When clear, PacketSQN field may be filled
+     * with custom data by classifier.  When set, hardware inserts the packet
+     * sequence number when the packet descriptor is written to a
+     * notification ring.
+     */
+    uint_reg_t ps           : 1;
+    /**
+     * Buffer Error.
+     * Written by the iDMA hardware.  Asserted if iDMA ran out of buffers
+     * while writing the packet. Software must still return any buffer
+     * descriptors whose C field indicates a valid descriptor was consumed.
+     */
+    uint_reg_t be           : 1;
+    /**
+     * Written by  the classification program.  The associated counter is
+     * incremented when the packet is sent.
+     */
+    uint_reg_t ctr0         : 5;
+    /** Reserved. */
+    uint_reg_t __reserved_2 : 3;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved_2 : 3;
+    uint_reg_t ctr0         : 5;
+    uint_reg_t be           : 1;
+    uint_reg_t ps           : 1;
+    uint_reg_t ts           : 1;
+    uint_reg_t sq           : 1;
+    uint_reg_t dest         : 2;
+    uint_reg_t nr           : 1;
+    uint_reg_t cs           : 1;
+    uint_reg_t __reserved_1 : 3;
+    uint_reg_t bucket_id    : 13;
+    uint_reg_t ct           : 1;
+    uint_reg_t ce           : 1;
+    uint_reg_t l2_size      : 14;
+    uint_reg_t tr           : 1;
+    uint_reg_t me           : 1;
+    uint_reg_t __reserved_0 : 1;
+    uint_reg_t channel      : 5;
+    uint_reg_t notif_ring   : 8;
+#endif
+
+    /* Word 1 */
+
+#ifndef __BIG_ENDIAN__
+    /**
+     * Written by  the classification program.  The associated counter is
+     * incremented when the packet is sent.
+     */
+    uint_reg_t ctr1          : 5;
+    /** Reserved. */
+    uint_reg_t __reserved_3  : 3;
+    /**
+     * Written by classification program.  Indicates the start byte for
+     * checksum.  Relative to 1st byte received from MAC.
+     */
+    uint_reg_t csum_start    : 8;
+    /**
+     * Checksum seed written by classification program.  Overwritten with
+     * resultant checksum if CS bit is asserted.  The endianness of the CSUM
+     * value bits when viewed by Tile software match the packet byte order.
+     * That is, bits[7:0] of the resulting checksum value correspond to
+     * earlier (more significant) bytes in the packet.  To avoid classifier
+     * software from having to byte swap the CSUM_SEED, the iDMA checksum
+     * engine byte swaps the classifier's result before seeding the checksum
+     * calculation.  Thus, the CSUM_START byte of packet data is added to
+     * bits[15:8] of the CSUM_SEED field generated by the classifier.  This
+     * byte swap will be visible to Tile software if the CS bit is clear.
+     */
+    uint_reg_t csum_seed_val : 16;
+    /**
+     * Written by  the classification program.  Not interpreted by mPIPE
+     * hardware.
+     */
+    uint_reg_t custom0       : 32;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t custom0       : 32;
+    uint_reg_t csum_seed_val : 16;
+    uint_reg_t csum_start    : 8;
+    uint_reg_t __reserved_3  : 3;
+    uint_reg_t ctr1          : 5;
+#endif
+
+    /* Word 2 */
+
+#ifndef __BIG_ENDIAN__
+    /**
+     * Written by  the classification program.  Not interpreted by mPIPE
+     * hardware.
+     */
+    uint_reg_t custom1 : 64;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t custom1 : 64;
+#endif
+
+    /* Word 3 */
+
+#ifndef __BIG_ENDIAN__
+    /**
+     * Written by  the classification program.  Not interpreted by mPIPE
+     * hardware.
+     */
+    uint_reg_t custom2 : 64;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t custom2 : 64;
+#endif
+
+    /* Word 4 */
+
+#ifndef __BIG_ENDIAN__
+    /**
+     * Written by  the classification program.  Not interpreted by mPIPE
+     * hardware.
+     */
+    uint_reg_t custom3 : 64;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t custom3 : 64;
+#endif
+
+    /* Word 5 */
+
+#ifndef __BIG_ENDIAN__
+    /**
+     * Sequence number applied when packet is distributed.   Classifier
+     * selects which sequence number is to be applied by writing the 13-bit
+     * SQN-selector into this field.
+     */
+    uint_reg_t gp_sqn     : 16;
+    /**
+     * Written by notification hardware.  The packet sequence number is
+     * incremented for each packet that wasn't dropped.
+     */
+    uint_reg_t packet_sqn : 48;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t packet_sqn : 48;
+    uint_reg_t gp_sqn     : 16;
+#endif
+
+    /* Word 6 */
+
+#ifndef __BIG_ENDIAN__
+    /**
+     * Written by hardware when the start-of-packet is received by the mPIPE
+     * from the MAC.  This is the nanoseconds part of the packet timestamp.
+     */
+    uint_reg_t time_stamp_ns  : 32;
+    /**
+     * Written by hardware when the start-of-packet is received by the mPIPE
+     * from the MAC.  This is the seconds part of the packet timestamp.
+     */
+    uint_reg_t time_stamp_sec : 32;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t time_stamp_sec : 32;
+    uint_reg_t time_stamp_ns  : 32;
+#endif
+
+    /* Word 7 */
+
+#ifndef __BIG_ENDIAN__
+    /** Virtual address.  Must be sign extended by consumer. */
+    int_reg_t va           : 42;
+    /** Reserved. */
+    uint_reg_t __reserved_4 : 6;
+    /** Index of the buffer stack to which this buffer belongs. */
+    uint_reg_t stack_idx    : 5;
+    /** Reserved. */
+    uint_reg_t __reserved_5 : 3;
+    /**
+     * Instance ID.  For devices that support more than one mPIPE instance,
+     * this field indicates the buffer owner.  If the INST field does not
+     * match the mPIPE's instance number when a packet is egressed, buffers
+     * with HWB set will be returned to the other mPIPE instance.
+     */
+    uint_reg_t inst         : 1;
+    /** Reserved. */
+    uint_reg_t __reserved_6 : 1;
+    /**
+     * Always set to one by hardware in iDMA packet descriptors.  For eDMA,
+     * indicates whether the buffer will be released to the buffer stack
+     * manager.  When 0, software is responsible for releasing the buffer.
+     */
+    uint_reg_t hwb          : 1;
+    /**
+     * Encoded size of buffer.  Set by the ingress hardware for iDMA packet
+     * descriptors.  For eDMA descriptors, indicates the buffer size if .c
+     * indicates a chained packet.  If an eDMA descriptor is not chained and
+     * the .hwb bit is not set, this field is ignored and the size is
+     * specified by the .xfer_size field.
+     * 0 = 128 bytes
+     * 1 = 256 bytes
+     * 2 = 512 bytes
+     * 3 = 1024 bytes
+     * 4 = 1664 bytes
+     * 5 = 4096 bytes
+     * 6 = 10368 bytes
+     * 7 = 16384 bytes
+     */
+    uint_reg_t size         : 3;
+    /**
+     * Chaining configuration for the buffer.  Indicates that an ingress
+     * packet or egress command is chained across multiple buffers, with each
+     * buffer's size indicated by the .size field.
+     */
+    uint_reg_t c            : 2;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t c            : 2;
+    uint_reg_t size         : 3;
+    uint_reg_t hwb          : 1;
+    uint_reg_t __reserved_6 : 1;
+    uint_reg_t inst         : 1;
+    uint_reg_t __reserved_5 : 3;
+    uint_reg_t stack_idx    : 5;
+    uint_reg_t __reserved_4 : 6;
+    int_reg_t va           : 42;
+#endif
+
+  };
+
+  /** Word access */
+  uint_reg_t words[8];
+} MPIPE_PDESC_t;
+#endif /* !defined(__ASSEMBLER__) */
+
+#endif /* !defined(__ARCH_MPIPE_SHM_H__) */
diff --git a/arch/tile/include/arch/mpipe_shm_def.h b/arch/tile/include/arch/mpipe_shm_def.h
new file mode 100644
index 0000000..6124d39
--- /dev/null
+++ b/arch/tile/include/arch/mpipe_shm_def.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_MPIPE_SHM_DEF_H__
+#define __ARCH_MPIPE_SHM_DEF_H__
+#define MPIPE_EDMA_DESC_WORD1__C_VAL_UNCHAINED 0x0
+#define MPIPE_EDMA_DESC_WORD1__C_VAL_CHAINED 0x1
+#define MPIPE_EDMA_DESC_WORD1__C_VAL_NOT_RDY 0x2
+#define MPIPE_EDMA_DESC_WORD1__C_VAL_INVALID 0x3
+#endif /* !defined(__ARCH_MPIPE_SHM_DEF_H__) */
diff --git a/arch/tile/include/arch/trio.h b/arch/tile/include/arch/trio.h
new file mode 100644
index 0000000..d3000a8
--- /dev/null
+++ b/arch/tile/include/arch/trio.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_TRIO_H__
+#define __ARCH_TRIO_H__
+
+#include <arch/abi.h>
+#include <arch/trio_def.h>
+
+#ifndef __ASSEMBLER__
+
+/*
+ * Tile PIO Region Configuration - CFG Address Format.
+ * This register describes the address format for PIO accesses when the
+ * associated region is setup with TYPE=CFG.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /* Register Address (full byte address). */
+    uint_reg_t reg_addr     : 12;
+    /* Function Number */
+    uint_reg_t fn           : 3;
+    /* Device Number */
+    uint_reg_t dev          : 5;
+    /* BUS Number */
+    uint_reg_t bus          : 8;
+    /* Config Type: 0 for access to directly-attached device.  1 otherwise. */
+    uint_reg_t type         : 1;
+    /* Reserved. */
+    uint_reg_t __reserved_0 : 1;
+    /*
+     * MAC select.  This must match the configuration in
+     * TILE_PIO_REGION_SETUP.MAC.
+     */
+    uint_reg_t mac          : 2;
+    /* Reserved. */
+    uint_reg_t __reserved_1 : 32;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved_1 : 32;
+    uint_reg_t mac          : 2;
+    uint_reg_t __reserved_0 : 1;
+    uint_reg_t type         : 1;
+    uint_reg_t bus          : 8;
+    uint_reg_t dev          : 5;
+    uint_reg_t fn           : 3;
+    uint_reg_t reg_addr     : 12;
+#endif
+  };
+
+  uint_reg_t word;
+} TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR_t;
+#endif /* !defined(__ASSEMBLER__) */
+
+#endif /* !defined(__ARCH_TRIO_H__) */
diff --git a/arch/tile/include/arch/trio_constants.h b/arch/tile/include/arch/trio_constants.h
new file mode 100644
index 0000000..628b045
--- /dev/null
+++ b/arch/tile/include/arch/trio_constants.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+
+#ifndef __ARCH_TRIO_CONSTANTS_H__
+#define __ARCH_TRIO_CONSTANTS_H__
+
+#define TRIO_NUM_ASIDS 16
+#define TRIO_NUM_TLBS_PER_ASID 16
+
+#define TRIO_NUM_TPIO_REGIONS 8
+#define TRIO_LOG2_NUM_TPIO_REGIONS 3
+
+#define TRIO_NUM_MAP_MEM_REGIONS 16
+#define TRIO_LOG2_NUM_MAP_MEM_REGIONS 4
+#define TRIO_NUM_MAP_SQ_REGIONS 8
+#define TRIO_LOG2_NUM_MAP_SQ_REGIONS 3
+
+#define TRIO_LOG2_NUM_SQ_FIFO_ENTRIES 6
+
+#define TRIO_NUM_PUSH_DMA_RINGS 32
+
+#define TRIO_NUM_PULL_DMA_RINGS 32
+
+#endif /* __ARCH_TRIO_CONSTANTS_H__ */
diff --git a/arch/tile/include/arch/trio_def.h b/arch/tile/include/arch/trio_def.h
new file mode 100644
index 0000000..e805003
--- /dev/null
+++ b/arch/tile/include/arch/trio_def.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_TRIO_DEF_H__
+#define __ARCH_TRIO_DEF_H__
+#define TRIO_CFG_REGION_ADDR__REG_SHIFT 0
+#define TRIO_CFG_REGION_ADDR__INTFC_SHIFT 16
+#define TRIO_CFG_REGION_ADDR__INTFC_VAL_TRIO 0x0
+#define TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE 0x1
+#define TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD 0x2
+#define TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_PROTECTED 0x3
+#define TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT 18
+#define TRIO_CFG_REGION_ADDR__PROT_SHIFT 20
+#define TRIO_PIO_REGIONS_ADDR__REGION_SHIFT 32
+#define TRIO_MAP_MEM_REG_INT0 0x1000000000
+#define TRIO_MAP_MEM_REG_INT1 0x1000000008
+#define TRIO_MAP_MEM_REG_INT2 0x1000000010
+#define TRIO_MAP_MEM_REG_INT3 0x1000000018
+#define TRIO_MAP_MEM_REG_INT4 0x1000000020
+#define TRIO_MAP_MEM_REG_INT5 0x1000000028
+#define TRIO_MAP_MEM_REG_INT6 0x1000000030
+#define TRIO_MAP_MEM_REG_INT7 0x1000000038
+#define TRIO_MAP_MEM_LIM__ADDR_SHIFT 12
+#define TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_UNORDERED 0x0
+#define TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_STRICT 0x1
+#define TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_REL_ORD 0x2
+#define TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT 30
+#endif /* !defined(__ARCH_TRIO_DEF_H__) */
diff --git a/arch/tile/include/arch/trio_pcie_intfc.h b/arch/tile/include/arch/trio_pcie_intfc.h
new file mode 100644
index 0000000..0487fdb
--- /dev/null
+++ b/arch/tile/include/arch/trio_pcie_intfc.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_TRIO_PCIE_INTFC_H__
+#define __ARCH_TRIO_PCIE_INTFC_H__
+
+#include <arch/abi.h>
+#include <arch/trio_pcie_intfc_def.h>
+
+#ifndef __ASSEMBLER__
+
+/*
+ * Port Configuration.
+ * Configuration of the PCIe Port
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /* Provides the state of the strapping pins for this port. */
+    uint_reg_t strap_state      : 3;
+    /* Reserved. */
+    uint_reg_t __reserved_0     : 1;
+    /*
+     * When 1, the device type will be overridden using OVD_DEV_TYPE_VAL.
+     * When 0, the device type is determined based on the STRAP_STATE.
+     */
+    uint_reg_t ovd_dev_type     : 1;
+    /* Provides the device type when OVD_DEV_TYPE is 1. */
+    uint_reg_t ovd_dev_type_val : 4;
+    /* Determines how link is trained. */
+    uint_reg_t train_mode       : 2;
+    /* Reserved. */
+    uint_reg_t __reserved_1     : 1;
+    /*
+     * For PCIe, used to flip physical RX lanes that were not properly wired.
+     *  This is not the same as lane reversal which is handled automatically
+     * during link training.  When 0, RX Lane0 must be wired to the link
+     * partner (either to its Lane0 or it's LaneN).  When RX_LANE_FLIP is 1,
+     * the highest numbered lane for this port becomes Lane0 and Lane0 does
+     * NOT have to be wired to the link partner.
+     */
+    uint_reg_t rx_lane_flip     : 1;
+    /*
+     * For PCIe, used to flip physical TX lanes that were not properly wired.
+     *  This is not the same as lane reversal which is handled automatically
+     * during link training.  When 0, TX Lane0 must be wired to the link
+     * partner (either to its Lane0 or it's LaneN).  When TX_LANE_FLIP is 1,
+     * the highest numbered lane for this port becomes Lane0 and Lane0 does
+     * NOT have to be wired to the link partner.
+     */
+    uint_reg_t tx_lane_flip     : 1;
+    /*
+     * For StreamIO port, configures the width of the port when TRAIN_MODE is
+     * not STRAP.
+     */
+    uint_reg_t stream_width     : 2;
+    /*
+     * For StreamIO port, configures the rate of the port when TRAIN_MODE is
+     * not STRAP.
+     */
+    uint_reg_t stream_rate      : 2;
+    /* Reserved. */
+    uint_reg_t __reserved_2     : 46;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved_2     : 46;
+    uint_reg_t stream_rate      : 2;
+    uint_reg_t stream_width     : 2;
+    uint_reg_t tx_lane_flip     : 1;
+    uint_reg_t rx_lane_flip     : 1;
+    uint_reg_t __reserved_1     : 1;
+    uint_reg_t train_mode       : 2;
+    uint_reg_t ovd_dev_type_val : 4;
+    uint_reg_t ovd_dev_type     : 1;
+    uint_reg_t __reserved_0     : 1;
+    uint_reg_t strap_state      : 3;
+#endif
+  };
+
+  uint_reg_t word;
+} TRIO_PCIE_INTFC_PORT_CONFIG_t;
+
+/*
+ * Port Status.
+ * Status of the PCIe Port.  This register applies to the StreamIO port when
+ * StreamIO is enabled.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /*
+     * Indicates the DL state of the port.  When 1, the port is up and ready
+     * to receive traffic.
+     */
+    uint_reg_t dl_up        : 1;
+    /*
+     * Indicates the number of times the link has gone down.  Clears on read.
+     */
+    uint_reg_t dl_down_cnt  : 7;
+    /* Indicates the SERDES PLL has spun up and is providing a valid clock. */
+    uint_reg_t clock_ready  : 1;
+    /* Reserved. */
+    uint_reg_t __reserved_0 : 7;
+    /* Device revision ID. */
+    uint_reg_t device_rev   : 8;
+    /* Link state (PCIe). */
+    uint_reg_t ltssm_state  : 6;
+    /* Link power management state (PCIe). */
+    uint_reg_t pm_state     : 3;
+    /* Reserved. */
+    uint_reg_t __reserved_1 : 31;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved_1 : 31;
+    uint_reg_t pm_state     : 3;
+    uint_reg_t ltssm_state  : 6;
+    uint_reg_t device_rev   : 8;
+    uint_reg_t __reserved_0 : 7;
+    uint_reg_t clock_ready  : 1;
+    uint_reg_t dl_down_cnt  : 7;
+    uint_reg_t dl_up        : 1;
+#endif
+  };
+
+  uint_reg_t word;
+} TRIO_PCIE_INTFC_PORT_STATUS_t;
+
+/*
+ * Transmit FIFO Control.
+ * Contains TX FIFO thresholds.  These registers are for diagnostics purposes
+ * only.  Changing these values causes undefined behavior.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /*
+     * Almost-Empty level for TX0 data.  Typically set to at least
+     * roundup(38.0*M/N) where N=tclk frequency and M=MAC symbol rate in MHz
+     * for a x4 port (250MHz).
+     */
+    uint_reg_t tx0_data_ae_lvl : 7;
+    /* Reserved. */
+    uint_reg_t __reserved_0    : 1;
+    /* Almost-Empty level for TX1 data. */
+    uint_reg_t tx1_data_ae_lvl : 7;
+    /* Reserved. */
+    uint_reg_t __reserved_1    : 1;
+    /* Almost-Full level for TX0 data. */
+    uint_reg_t tx0_data_af_lvl : 7;
+    /* Reserved. */
+    uint_reg_t __reserved_2    : 1;
+    /* Almost-Full level for TX1 data. */
+    uint_reg_t tx1_data_af_lvl : 7;
+    /* Reserved. */
+    uint_reg_t __reserved_3    : 1;
+    /* Almost-Full level for TX0 info. */
+    uint_reg_t tx0_info_af_lvl : 5;
+    /* Reserved. */
+    uint_reg_t __reserved_4    : 3;
+    /* Almost-Full level for TX1 info. */
+    uint_reg_t tx1_info_af_lvl : 5;
+    /* Reserved. */
+    uint_reg_t __reserved_5    : 3;
+    /*
+     * This register provides performance adjustment for high bandwidth
+     * flows.  The MAC will assert almost-full to TRIO if non-posted credits
+     * fall below this level.  Note that setting this larger than the initial
+     * PORT_CREDIT.NPH value will cause READS to never be sent.  If the
+     * initial credit value from the link partner is smaller than this value
+     * when the link comes up, the value will be reset to the initial credit
+     * value to prevent lockup.
+     */
+    uint_reg_t min_np_credits  : 8;
+    /*
+     * This register provides performance adjustment for high bandwidth
+     * flows.  The MAC will assert almost-full to TRIO if posted credits fall
+     * below this level.  Note that setting this larger than the initial
+     * PORT_CREDIT.PH value will cause WRITES to never be sent.  If the
+     * initial credit value from the link partner is smaller than this value
+     * when the link comes up, the value will be reset to the initial credit
+     * value to prevent lockup.
+     */
+    uint_reg_t min_p_credits   : 8;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t min_p_credits   : 8;
+    uint_reg_t min_np_credits  : 8;
+    uint_reg_t __reserved_5    : 3;
+    uint_reg_t tx1_info_af_lvl : 5;
+    uint_reg_t __reserved_4    : 3;
+    uint_reg_t tx0_info_af_lvl : 5;
+    uint_reg_t __reserved_3    : 1;
+    uint_reg_t tx1_data_af_lvl : 7;
+    uint_reg_t __reserved_2    : 1;
+    uint_reg_t tx0_data_af_lvl : 7;
+    uint_reg_t __reserved_1    : 1;
+    uint_reg_t tx1_data_ae_lvl : 7;
+    uint_reg_t __reserved_0    : 1;
+    uint_reg_t tx0_data_ae_lvl : 7;
+#endif
+  };
+
+  uint_reg_t word;
+} TRIO_PCIE_INTFC_TX_FIFO_CTL_t;
+#endif /* !defined(__ASSEMBLER__) */
+
+#endif /* !defined(__ARCH_TRIO_PCIE_INTFC_H__) */
diff --git a/arch/tile/include/arch/trio_pcie_intfc_def.h b/arch/tile/include/arch/trio_pcie_intfc_def.h
new file mode 100644
index 0000000..d3fd678
--- /dev/null
+++ b/arch/tile/include/arch/trio_pcie_intfc_def.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_TRIO_PCIE_INTFC_DEF_H__
+#define __ARCH_TRIO_PCIE_INTFC_DEF_H__
+#define TRIO_PCIE_INTFC_MAC_INT_STS 0x0000
+#define TRIO_PCIE_INTFC_MAC_INT_STS__INT_LEVEL_MASK  0xf000
+#define TRIO_PCIE_INTFC_PORT_CONFIG 0x0018
+#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_DISABLED 0x0
+#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT 0x1
+#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC 0x2
+#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT_G1 0x3
+#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC_G1 0x4
+#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_XLINK 0x5
+#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_STREAM_X1 0x6
+#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_STREAM_X4 0x7
+#define TRIO_PCIE_INTFC_PORT_STATUS 0x0020
+#define TRIO_PCIE_INTFC_TX_FIFO_CTL 0x0050
+#endif /* !defined(__ARCH_TRIO_PCIE_INTFC_DEF_H__) */
diff --git a/arch/tile/include/arch/trio_pcie_rc.h b/arch/tile/include/arch/trio_pcie_rc.h
new file mode 100644
index 0000000..6a25d0a
--- /dev/null
+++ b/arch/tile/include/arch/trio_pcie_rc.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_TRIO_PCIE_RC_H__
+#define __ARCH_TRIO_PCIE_RC_H__
+
+#include <arch/abi.h>
+#include <arch/trio_pcie_rc_def.h>
+
+#ifndef __ASSEMBLER__
+
+/* Device Capabilities Register. */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /*
+     * Max_Payload_Size Supported, writablethrough the MAC_STANDARD interface
+     */
+    uint_reg_t mps_sup                    : 3;
+    /*
+     * This field is writable through the MAC_STANDARD interface.  However,
+     * Phantom Function is not  supported. Therefore, the application must
+     * not write any value other than 0x0 to this  field.
+     */
+    uint_reg_t phantom_function_supported : 2;
+    /* This bit is writable through the MAC_STANDARD interface. */
+    uint_reg_t ext_tag_field_supported    : 1;
+    /* Reserved. */
+    uint_reg_t __reserved_0               : 3;
+    /* Endpoint L1 Acceptable Latency Must be 0x0 for non-Endpoint devices. */
+    uint_reg_t l1_lat                     : 3;
+    /*
+     * Undefined since PCI Express 1.1 (Was Attention Button Present for PCI
+     * Express 1.0a)
+     */
+    uint_reg_t r1                         : 1;
+    /*
+     * Undefined since PCI Express 1.1 (Was Attention Indicator Present for
+     * PCI  Express 1.0a)
+     */
+    uint_reg_t r2                         : 1;
+    /*
+     * Undefined since PCI Express 1.1 (Was Power Indicator Present for PCI
+     * Express 1.0a)
+     */
+    uint_reg_t r3                         : 1;
+    /*
+     * Role-Based Error Reporting, writable through the MAC_STANDARD
+     * interface.  Required to be set for device compliant to 1.1  spec and
+     * later.
+     */
+    uint_reg_t rer                        : 1;
+    /* Reserved. */
+    uint_reg_t __reserved_1               : 2;
+    /* Captured Slot Power Limit Value Upstream port only. */
+    uint_reg_t slot_pwr_lim               : 8;
+    /* Captured Slot Power Limit Scale Upstream port only. */
+    uint_reg_t slot_pwr_scale             : 2;
+    /* Reserved. */
+    uint_reg_t __reserved_2               : 4;
+    /* Endpoint L0s Acceptable LatencyMust be 0x0 for non-Endpoint devices. */
+    uint_reg_t l0s_lat                    : 1;
+    /* Reserved. */
+    uint_reg_t __reserved_3               : 31;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved_3               : 31;
+    uint_reg_t l0s_lat                    : 1;
+    uint_reg_t __reserved_2               : 4;
+    uint_reg_t slot_pwr_scale             : 2;
+    uint_reg_t slot_pwr_lim               : 8;
+    uint_reg_t __reserved_1               : 2;
+    uint_reg_t rer                        : 1;
+    uint_reg_t r3                         : 1;
+    uint_reg_t r2                         : 1;
+    uint_reg_t r1                         : 1;
+    uint_reg_t l1_lat                     : 3;
+    uint_reg_t __reserved_0               : 3;
+    uint_reg_t ext_tag_field_supported    : 1;
+    uint_reg_t phantom_function_supported : 2;
+    uint_reg_t mps_sup                    : 3;
+#endif
+  };
+
+  uint_reg_t word;
+} TRIO_PCIE_RC_DEVICE_CAP_t;
+
+/* Device Control Register. */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /* Correctable Error Reporting Enable */
+    uint_reg_t cor_err_ena      : 1;
+    /* Non-Fatal Error Reporting Enable */
+    uint_reg_t nf_err_ena       : 1;
+    /* Fatal Error Reporting Enable */
+    uint_reg_t fatal_err_ena    : 1;
+    /* Unsupported Request Reporting Enable */
+    uint_reg_t ur_ena           : 1;
+    /* Relaxed orderring enable */
+    uint_reg_t ro_ena           : 1;
+    /* Max Payload Size */
+    uint_reg_t max_payload_size : 3;
+    /* Extended Tag Field Enable */
+    uint_reg_t ext_tag          : 1;
+    /* Phantom Function Enable */
+    uint_reg_t ph_fn_ena        : 1;
+    /* AUX Power PM Enable */
+    uint_reg_t aux_pm_ena       : 1;
+    /* Enable NoSnoop */
+    uint_reg_t no_snoop         : 1;
+    /* Max read request size */
+    uint_reg_t max_read_req_sz  : 3;
+    /* Reserved. */
+    uint_reg_t __reserved       : 49;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved       : 49;
+    uint_reg_t max_read_req_sz  : 3;
+    uint_reg_t no_snoop         : 1;
+    uint_reg_t aux_pm_ena       : 1;
+    uint_reg_t ph_fn_ena        : 1;
+    uint_reg_t ext_tag          : 1;
+    uint_reg_t max_payload_size : 3;
+    uint_reg_t ro_ena           : 1;
+    uint_reg_t ur_ena           : 1;
+    uint_reg_t fatal_err_ena    : 1;
+    uint_reg_t nf_err_ena       : 1;
+    uint_reg_t cor_err_ena      : 1;
+#endif
+  };
+
+  uint_reg_t word;
+} TRIO_PCIE_RC_DEVICE_CONTROL_t;
+#endif /* !defined(__ASSEMBLER__) */
+
+#endif /* !defined(__ARCH_TRIO_PCIE_RC_H__) */
diff --git a/arch/tile/include/arch/trio_pcie_rc_def.h b/arch/tile/include/arch/trio_pcie_rc_def.h
new file mode 100644
index 0000000..74081a6
--- /dev/null
+++ b/arch/tile/include/arch/trio_pcie_rc_def.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_TRIO_PCIE_RC_DEF_H__
+#define __ARCH_TRIO_PCIE_RC_DEF_H__
+#define TRIO_PCIE_RC_DEVICE_CAP 0x0074
+#define TRIO_PCIE_RC_DEVICE_CONTROL 0x0078
+#define TRIO_PCIE_RC_DEVICE_ID_VEN_ID 0x0000
+#define TRIO_PCIE_RC_DEVICE_ID_VEN_ID__DEV_ID_SHIFT 16
+#define TRIO_PCIE_RC_REVISION_ID 0x0008
+#endif /* !defined(__ARCH_TRIO_PCIE_RC_DEF_H__) */
diff --git a/arch/tile/include/arch/trio_shm.h b/arch/tile/include/arch/trio_shm.h
new file mode 100644
index 0000000..3382e38
--- /dev/null
+++ b/arch/tile/include/arch/trio_shm.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+
+#ifndef __ARCH_TRIO_SHM_H__
+#define __ARCH_TRIO_SHM_H__
+
+#include <arch/abi.h>
+#include <arch/trio_shm_def.h>
+
+#ifndef __ASSEMBLER__
+/**
+ * TRIO DMA Descriptor.
+ * The TRIO DMA descriptor is written by software and consumed by hardware.
+ * It is used to specify the location of transaction data in the IO and Tile
+ * domains.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+    /* Word 0 */
+
+#ifndef __BIG_ENDIAN__
+    /** Tile side virtual address. */
+    int_reg_t va           : 42;
+    /**
+     * Encoded size of buffer used on push DMA when C=1:
+     * 0 = 128 bytes
+     * 1 = 256 bytes
+     * 2 = 512 bytes
+     * 3 = 1024 bytes
+     * 4 = 1664 bytes
+     * 5 = 4096 bytes
+     * 6 = 10368 bytes
+     * 7 = 16384 bytes
+     */
+    uint_reg_t bsz          : 3;
+    /**
+     * Chaining designation.  Always zero for pull DMA
+     * 0 : Unchained buffer pointer
+     * 1 : Chained buffer pointer.  Next buffer descriptor (e.g. VA) stored
+     * in 1st 8-bytes in buffer.  For chained buffers, first 8-bytes of each
+     * buffer contain the next buffer descriptor formatted exactly like a PDE
+     * buffer descriptor.  This allows a chained PDE buffer to be sent using
+     * push DMA.
+     */
+    uint_reg_t c            : 1;
+    /**
+     * Notification interrupt will be delivered when the transaction has
+     * completed (all data has been read from or written to the Tile-side
+     * buffer).
+     */
+    uint_reg_t notif        : 1;
+    /**
+     * When 0, the XSIZE field specifies the total byte count for the
+     * transaction.  When 1, the XSIZE field is encoded as 2^(N+14) for N in
+     * {0..6}:
+     * 0 = 16KB
+     * 1 = 32KB
+     * 2 = 64KB
+     * 3 = 128KB
+     * 4 = 256KB
+     * 5 = 512KB
+     * 6 = 1MB
+     * All other encodings of the XSIZE field are reserved when SMOD=1
+     */
+    uint_reg_t smod         : 1;
+    /**
+     * Total number of bytes to move for this transaction.   When SMOD=1,
+     * this field is encoded - see SMOD description.
+     */
+    uint_reg_t xsize        : 14;
+    /** Reserved. */
+    uint_reg_t __reserved_0 : 1;
+    /**
+     * Generation number.  Used to indicate a valid descriptor in ring.  When
+     * a new descriptor is written into the ring, software must toggle this
+     * bit.  The net effect is that the GEN bit being written into new
+     * descriptors toggles each time the ring tail pointer wraps.
+     */
+    uint_reg_t gen          : 1;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t gen          : 1;
+    uint_reg_t __reserved_0 : 1;
+    uint_reg_t xsize        : 14;
+    uint_reg_t smod         : 1;
+    uint_reg_t notif        : 1;
+    uint_reg_t c            : 1;
+    uint_reg_t bsz          : 3;
+    int_reg_t va           : 42;
+#endif
+
+    /* Word 1 */
+
+#ifndef __BIG_ENDIAN__
+    /** IO-side address */
+    uint_reg_t io_address : 64;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t io_address : 64;
+#endif
+
+  };
+
+  /** Word access */
+  uint_reg_t words[2];
+} TRIO_DMA_DESC_t;
+#endif /* !defined(__ASSEMBLER__) */
+
+#endif /* !defined(__ARCH_TRIO_SHM_H__) */
diff --git a/arch/tile/include/arch/trio_shm_def.h b/arch/tile/include/arch/trio_shm_def.h
new file mode 100644
index 0000000..72a59c8
--- /dev/null
+++ b/arch/tile/include/arch/trio_shm_def.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_TRIO_SHM_DEF_H__
+#define __ARCH_TRIO_SHM_DEF_H__
+#endif /* !defined(__ARCH_TRIO_SHM_DEF_H__) */
diff --git a/arch/tile/include/arch/usb_host.h b/arch/tile/include/arch/usb_host.h
new file mode 100644
index 0000000..d09f326
--- /dev/null
+++ b/arch/tile/include/arch/usb_host.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_USB_HOST_H__
+#define __ARCH_USB_HOST_H__
+
+#include <arch/abi.h>
+#include <arch/usb_host_def.h>
+
+#ifndef __ASSEMBLER__
+#endif /* !defined(__ASSEMBLER__) */
+
+#endif /* !defined(__ARCH_USB_HOST_H__) */
diff --git a/arch/tile/include/arch/usb_host_def.h b/arch/tile/include/arch/usb_host_def.h
new file mode 100644
index 0000000..aeed775
--- /dev/null
+++ b/arch/tile/include/arch/usb_host_def.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* Machine-generated file; do not edit. */
+
+#ifndef __ARCH_USB_HOST_DEF_H__
+#define __ARCH_USB_HOST_DEF_H__
+#endif /* !defined(__ARCH_USB_HOST_DEF_H__) */
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild
index 143473e..fb7c65a 100644
--- a/arch/tile/include/asm/Kbuild
+++ b/arch/tile/include/asm/Kbuild
@@ -9,7 +9,6 @@ header-y += hardwall.h
 generic-y += bug.h
 generic-y += bugs.h
 generic-y += cputime.h
-generic-y += device.h
 generic-y += div64.h
 generic-y += emergency-restart.h
 generic-y += errno.h
diff --git a/arch/tile/include/asm/cache.h b/arch/tile/include/asm/cache.h
index 392e533..a9a5299 100644
--- a/arch/tile/include/asm/cache.h
+++ b/arch/tile/include/asm/cache.h
@@ -27,11 +27,17 @@
 #define L2_CACHE_ALIGN(x)	(((x)+(L2_CACHE_BYTES-1)) & -L2_CACHE_BYTES)
 
 /*
- * TILE-Gx is fully coherent so we don't need to define ARCH_DMA_MINALIGN.
+ * TILEPro I/O is not always coherent (networking typically uses coherent
+ * I/O, but PCI traffic does not) and setting ARCH_DMA_MINALIGN to the
+ * L2 cacheline size helps ensure that kernel heap allocations are aligned.
+ * TILE-Gx I/O is always coherent when used on hash-for-home pages.
+ *
+ * However, it's possible at runtime to request not to use hash-for-home
+ * for the kernel heap, in which case the kernel will use flush-and-inval
+ * to manage coherence.  As a result, we use L2_CACHE_BYTES for the
+ * DMA minimum alignment to avoid false sharing in the kernel heap.
  */
-#ifndef __tilegx__
 #define ARCH_DMA_MINALIGN	L2_CACHE_BYTES
-#endif
 
 /* use the cache line size for the L2, which is where it counts */
 #define SMP_CACHE_BYTES_SHIFT	L2_CACHE_SHIFT
diff --git a/arch/tile/include/asm/checksum.h b/arch/tile/include/asm/checksum.h
index a120766..b21a2fd 100644
--- a/arch/tile/include/asm/checksum.h
+++ b/arch/tile/include/asm/checksum.h
@@ -21,4 +21,22 @@
 __wsum do_csum(const unsigned char *buff, int len);
 #define do_csum do_csum
 
+/*
+ * Return the sum of all the 16-bit subwords in a long.
+ * This sums two subwords on a 32-bit machine, and four on 64 bits.
+ * The implementation does two vector adds to capture any overflow.
+ */
+static inline unsigned int csum_long(unsigned long x)
+{
+	unsigned long ret;
+#ifdef __tilegx__
+	ret = __insn_v2sadu(x, 0);
+	ret = __insn_v2sadu(ret, 0);
+#else
+	ret = __insn_sadh_u(x, 0);
+	ret = __insn_sadh_u(ret, 0);
+#endif
+	return ret;
+}
+
 #endif /* _ASM_TILE_CHECKSUM_H */
diff --git a/arch/tile/include/asm/device.h b/arch/tile/include/asm/device.h
new file mode 100644
index 0000000..5182705
--- /dev/null
+++ b/arch/tile/include/asm/device.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ * Arch specific extensions to struct device
+ */
+
+#ifndef _ASM_TILE_DEVICE_H
+#define _ASM_TILE_DEVICE_H
+
+struct dev_archdata {
+	/* DMA operations on that device */
+        struct dma_map_ops	*dma_ops;
+
+	/* Offset of the DMA address from the PA. */
+	dma_addr_t		dma_offset;
+
+	/* Highest DMA address that can be generated by this device. */
+	dma_addr_t		max_direct_dma_addr;
+};
+
+struct pdev_archdata {
+};
+
+#endif /* _ASM_TILE_DEVICE_H */
diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h
index eaa06d1..4b6247d 100644
--- a/arch/tile/include/asm/dma-mapping.h
+++ b/arch/tile/include/asm/dma-mapping.h
@@ -20,69 +20,80 @@
 #include <linux/cache.h>
 #include <linux/io.h>
 
-/*
- * Note that on x86 and powerpc, there is a "struct dma_mapping_ops"
- * that is used for all the DMA operations.  For now, we don't have an
- * equivalent on tile, because we only have a single way of doing DMA.
- * (Tilera bug 7994 to use dma_mapping_ops.)
- */
+extern struct dma_map_ops *tile_dma_map_ops;
+extern struct dma_map_ops *gx_pci_dma_map_ops;
+extern struct dma_map_ops *gx_legacy_pci_dma_map_ops;
+
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+	if (dev && dev->archdata.dma_ops)
+		return dev->archdata.dma_ops;
+	else
+		return tile_dma_map_ops;
+}
+
+static inline dma_addr_t get_dma_offset(struct device *dev)
+{
+	return dev->archdata.dma_offset;
+}
+
+static inline void set_dma_offset(struct device *dev, dma_addr_t off)
+{
+	dev->archdata.dma_offset = off;
+}
 
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-
-extern dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-			  enum dma_data_direction);
-extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-			     size_t size, enum dma_data_direction);
-extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-	       enum dma_data_direction);
-extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-			 int nhwentries, enum dma_data_direction);
-extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
-			       unsigned long offset, size_t size,
-			       enum dma_data_direction);
-extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-			   size_t size, enum dma_data_direction);
-extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-				int nelems, enum dma_data_direction);
-extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
-				   int nelems, enum dma_data_direction);
-
-
-void *dma_alloc_coherent(struct device *dev, size_t size,
-			   dma_addr_t *dma_handle, gfp_t flag);
-
-void dma_free_coherent(struct device *dev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle);
-
-extern void dma_sync_single_for_cpu(struct device *, dma_addr_t, size_t,
-				    enum dma_data_direction);
-extern void dma_sync_single_for_device(struct device *, dma_addr_t,
-				       size_t, enum dma_data_direction);
-extern void dma_sync_single_range_for_cpu(struct device *, dma_addr_t,
-					  unsigned long offset, size_t,
-					  enum dma_data_direction);
-extern void dma_sync_single_range_for_device(struct device *, dma_addr_t,
-					     unsigned long offset, size_t,
-					     enum dma_data_direction);
-extern void dma_cache_sync(struct device *dev, void *vaddr, size_t,
-			   enum dma_data_direction);
+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	return paddr + get_dma_offset(dev);
+}
+
+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+	return daddr - get_dma_offset(dev);
+}
+
+static inline void dma_mark_clean(void *addr, size_t size) {}
+
+#include <asm-generic/dma-mapping-common.h>
+
+static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
+{
+	dev->archdata.dma_ops = ops;
+}
+
+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+	if (!dev->dma_mask)
+		return 0;
+
+	return addr + size - 1 <= *dev->dma_mask;
+}
 
 static inline int
 dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
-	return 0;
+	return get_dma_ops(dev)->mapping_error(dev, dma_addr);
 }
 
 static inline int
 dma_supported(struct device *dev, u64 mask)
 {
-	return 1;
+	return get_dma_ops(dev)->dma_supported(dev, mask);
 }
 
 static inline int
 dma_set_mask(struct device *dev, u64 mask)
 {
+	struct dma_map_ops *dma_ops = get_dma_ops(dev);
+
+	/* Handle legacy PCI devices with limited memory addressability. */
+	if ((dma_ops == gx_pci_dma_map_ops) && (mask <= DMA_BIT_MASK(32))) {
+		set_dma_ops(dev, gx_legacy_pci_dma_map_ops);
+		set_dma_offset(dev, 0);
+		if (mask > dev->archdata.max_direct_dma_addr)
+			mask = dev->archdata.max_direct_dma_addr;
+	}
+
 	if (!dev->dma_mask || !dma_supported(dev, mask))
 		return -EIO;
 
@@ -91,4 +102,43 @@ dma_set_mask(struct device *dev, u64 mask)
 	return 0;
 }
 
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+				    dma_addr_t *dma_handle, gfp_t flag,
+				    struct dma_attrs *attrs)
+{
+	struct dma_map_ops *dma_ops = get_dma_ops(dev);
+	void *cpu_addr;
+
+	cpu_addr = dma_ops->alloc(dev, size, dma_handle, flag, attrs);
+
+	debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
+
+	return cpu_addr;
+}
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				  void *cpu_addr, dma_addr_t dma_handle,
+				  struct dma_attrs *attrs)
+{
+	struct dma_map_ops *dma_ops = get_dma_ops(dev);
+
+	debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
+
+	dma_ops->free(dev, size, cpu_addr, dma_handle, attrs);
+}
+
+#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL)
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL)
+#define dma_free_coherent(d, s, v, h) dma_free_attrs(d, s, v, h, NULL)
+#define dma_free_noncoherent(d, s, v, h) dma_free_attrs(d, s, v, h, NULL)
+
+/*
+ * dma_alloc_noncoherent() is #defined to return coherent memory,
+ * so there's no need to do any flushing here.
+ */
+static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+				  enum dma_data_direction direction)
+{
+}
+
 #endif /* _ASM_TILE_DMA_MAPPING_H */
diff --git a/arch/tile/include/asm/fixmap.h b/arch/tile/include/asm/fixmap.h
index c66f793..e16dbf9 100644
--- a/arch/tile/include/asm/fixmap.h
+++ b/arch/tile/include/asm/fixmap.h
@@ -45,15 +45,23 @@
  *
  * TLB entries of such buffers will not be flushed across
  * task switches.
- *
- * We don't bother with a FIX_HOLE since above the fixmaps
- * is unmapped memory in any case.
  */
 enum fixed_addresses {
+#ifdef __tilegx__
+	/*
+	 * TILEPro has unmapped memory above so the hole isn't needed,
+	 * and in any case the hole pushes us over a single 16MB pmd.
+	 */
+	FIX_HOLE,
+#endif
 #ifdef CONFIG_HIGHMEM
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
 #endif
+#ifdef __tilegx__  /* see homecache.c */
+	FIX_HOMECACHE_BEGIN,
+	FIX_HOMECACHE_END = FIX_HOMECACHE_BEGIN+(NR_CPUS)-1,
+#endif
 	__end_of_permanent_fixed_addresses,
 
 	/*
diff --git a/arch/tile/include/asm/homecache.h b/arch/tile/include/asm/homecache.h
index a824386..7b77713 100644
--- a/arch/tile/include/asm/homecache.h
+++ b/arch/tile/include/asm/homecache.h
@@ -79,10 +79,17 @@ extern void homecache_change_page_home(struct page *, int order, int home);
 /*
  * Flush a page out of whatever cache(s) it is in.
  * This is more than just finv, since it properly handles waiting
- * for the data to reach memory on tilepro, but it can be quite
- * heavyweight, particularly on hash-for-home memory.
+ * for the data to reach memory, but it can be quite
+ * heavyweight, particularly on incoherent or immutable memory.
  */
-extern void homecache_flush_cache(struct page *, int order);
+extern void homecache_finv_page(struct page *);
+
+/*
+ * Flush a page out of the specified home cache.
+ * Note that the specified home need not be the actual home of the page,
+ * as for example might be the case when coordinating with I/O devices.
+ */
+extern void homecache_finv_map_page(struct page *, int home);
 
 /*
  * Allocate a page with the given GFP flags, home, and optionally
@@ -104,10 +111,10 @@ extern struct page *homecache_alloc_pages_node(int nid, gfp_t gfp_mask,
  * routines use homecache_change_page_home() to reset the home
  * back to the default before returning the page to the allocator.
  */
+void __homecache_free_pages(struct page *, unsigned int order);
 void homecache_free_pages(unsigned long addr, unsigned int order);
-#define homecache_free_page(page) \
-  homecache_free_pages((page), 0)
-
+#define __homecache_free_page(page) __homecache_free_pages((page), 0)
+#define homecache_free_page(page) homecache_free_pages((page), 0)
 
 
 /*
diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h
index d2152de..2a9b293 100644
--- a/arch/tile/include/asm/io.h
+++ b/arch/tile/include/asm/io.h
@@ -62,6 +62,92 @@ extern void iounmap(volatile void __iomem *addr);
 #define mm_ptov(addr)		((void *)phys_to_virt(addr))
 #define mm_vtop(addr)		((unsigned long)virt_to_phys(addr))
 
+#if CHIP_HAS_MMIO()
+
+/*
+ * We use inline assembly to guarantee that the compiler does not
+ * split an access into multiple byte-sized accesses as it might
+ * sometimes do if a register data structure is marked "packed".
+ * Obviously on tile we can't tolerate such an access being
+ * actually unaligned, but we want to avoid the case where the
+ * compiler conservatively would generate multiple accesses even
+ * for an aligned read or write.
+ */
+
+static inline u8 __raw_readb(const volatile void __iomem *addr)
+{
+	return *(const volatile u8 __force *)addr;
+}
+
+static inline u16 __raw_readw(const volatile void __iomem *addr)
+{
+	u16 ret;
+	asm volatile("ld2u %0, %1" : "=r" (ret) : "r" (addr));
+	barrier();
+	return le16_to_cpu(ret);
+}
+
+static inline u32 __raw_readl(const volatile void __iomem *addr)
+{
+	u32 ret;
+	/* Sign-extend to conform to u32 ABI sign-extension convention. */
+	asm volatile("ld4s %0, %1" : "=r" (ret) : "r" (addr));
+	barrier();
+	return le32_to_cpu(ret);
+}
+
+static inline u64 __raw_readq(const volatile void __iomem *addr)
+{
+	u64 ret;
+	asm volatile("ld %0, %1" : "=r" (ret) : "r" (addr));
+	barrier();
+	return le64_to_cpu(ret);
+}
+
+static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
+{
+	*(volatile u8 __force *)addr = val;
+}
+
+static inline void __raw_writew(u16 val, volatile void __iomem *addr)
+{
+	asm volatile("st2 %0, %1" :: "r" (addr), "r" (cpu_to_le16(val)));
+}
+
+static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+{
+	asm volatile("st4 %0, %1" :: "r" (addr), "r" (cpu_to_le32(val)));
+}
+
+static inline void __raw_writeq(u64 val, volatile void __iomem *addr)
+{
+	asm volatile("st %0, %1" :: "r" (addr), "r" (cpu_to_le64(val)));
+}
+
+/*
+ * The on-chip I/O hardware on tilegx is configured with VA=PA for the
+ * kernel's PA range.  The low-level APIs and field names use "va" and
+ * "void *" nomenclature, to be consistent with the general notion
+ * that the addresses in question are virtualizable, but in the kernel
+ * context we are actually manipulating PA values.  (In other contexts,
+ * e.g. access from user space, we do in fact use real virtual addresses
+ * in the va fields.)  To allow readers of the code to understand what's
+ * happening, we direct their attention to this comment by using the
+ * following two functions that just duplicate __va() and __pa().
+ */
+typedef unsigned long tile_io_addr_t;
+static inline tile_io_addr_t va_to_tile_io_addr(void *va)
+{
+	BUILD_BUG_ON(sizeof(phys_addr_t) != sizeof(tile_io_addr_t));
+	return __pa(va);
+}
+static inline void *tile_io_addr_to_va(tile_io_addr_t tile_io_addr)
+{
+	return __va(tile_io_addr);
+}
+
+#else /* CHIP_HAS_MMIO() */
+
 #ifdef CONFIG_PCI
 
 extern u8 _tile_readb(unsigned long addr);
@@ -73,10 +159,19 @@ extern void _tile_writew(u16 val, unsigned long addr);
 extern void _tile_writel(u32 val, unsigned long addr);
 extern void _tile_writeq(u64 val, unsigned long addr);
 
-#else
+#define __raw_readb(addr) _tile_readb((unsigned long)addr)
+#define __raw_readw(addr) _tile_readw((unsigned long)addr)
+#define __raw_readl(addr) _tile_readl((unsigned long)addr)
+#define __raw_readq(addr) _tile_readq((unsigned long)addr)
+#define __raw_writeb(val, addr) _tile_writeb(val, (unsigned long)addr)
+#define __raw_writew(val, addr) _tile_writew(val, (unsigned long)addr)
+#define __raw_writel(val, addr) _tile_writel(val, (unsigned long)addr)
+#define __raw_writeq(val, addr) _tile_writeq(val, (unsigned long)addr)
+
+#else /* CONFIG_PCI */
 
 /*
- * The Tile architecture does not support IOMEM unless PCI is enabled.
+ * The tilepro architecture does not support IOMEM unless PCI is enabled.
  * Unfortunately we can't yet simply not declare these methods,
  * since some generic code that compiles into the kernel, but
  * we never run, uses them unconditionally.
@@ -88,65 +183,58 @@ static inline int iomem_panic(void)
 	return 0;
 }
 
-static inline u8 _tile_readb(unsigned long addr)
+static inline u8 readb(unsigned long addr)
 {
 	return iomem_panic();
 }
 
-static inline u16 _tile_readw(unsigned long addr)
+static inline u16 _readw(unsigned long addr)
 {
 	return iomem_panic();
 }
 
-static inline u32 _tile_readl(unsigned long addr)
+static inline u32 readl(unsigned long addr)
 {
 	return iomem_panic();
 }
 
-static inline u64 _tile_readq(unsigned long addr)
+static inline u64 readq(unsigned long addr)
 {
 	return iomem_panic();
 }
 
-static inline void _tile_writeb(u8  val, unsigned long addr)
+static inline void writeb(u8  val, unsigned long addr)
 {
 	iomem_panic();
 }
 
-static inline void _tile_writew(u16 val, unsigned long addr)
+static inline void writew(u16 val, unsigned long addr)
 {
 	iomem_panic();
 }
 
-static inline void _tile_writel(u32 val, unsigned long addr)
+static inline void writel(u32 val, unsigned long addr)
 {
 	iomem_panic();
 }
 
-static inline void _tile_writeq(u64 val, unsigned long addr)
+static inline void writeq(u64 val, unsigned long addr)
 {
 	iomem_panic();
 }
 
-#endif
+#endif /* CONFIG_PCI */
+
+#endif /* CHIP_HAS_MMIO() */
 
-#define readb(addr) _tile_readb((unsigned long)addr)
-#define readw(addr) _tile_readw((unsigned long)addr)
-#define readl(addr) _tile_readl((unsigned long)addr)
-#define readq(addr) _tile_readq((unsigned long)addr)
-#define writeb(val, addr) _tile_writeb(val, (unsigned long)addr)
-#define writew(val, addr) _tile_writew(val, (unsigned long)addr)
-#define writel(val, addr) _tile_writel(val, (unsigned long)addr)
-#define writeq(val, addr) _tile_writeq(val, (unsigned long)addr)
-
-#define __raw_readb readb
-#define __raw_readw readw
-#define __raw_readl readl
-#define __raw_readq readq
-#define __raw_writeb writeb
-#define __raw_writew writew
-#define __raw_writel writel
-#define __raw_writeq writeq
+#define readb __raw_readb
+#define readw __raw_readw
+#define readl __raw_readl
+#define readq __raw_readq
+#define writeb __raw_writeb
+#define writew __raw_writew
+#define writel __raw_writel
+#define writeq __raw_writeq
 
 #define readb_relaxed readb
 #define readw_relaxed readw
diff --git a/arch/tile/include/asm/kmap_types.h b/arch/tile/include/asm/kmap_types.h
index 3d0f202..054374c 100644
--- a/arch/tile/include/asm/kmap_types.h
+++ b/arch/tile/include/asm/kmap_types.h
@@ -27,31 +27,5 @@ enum km_type {
 	KM_TYPE_NR = 8
 };
 
-/*
- * We provide dummy definitions of all the stray values that used to be
- * required for kmap_atomic() and no longer are.
- */
-enum {
-	KM_BOUNCE_READ,
-	KM_SKB_SUNRPC_DATA,
-	KM_SKB_DATA_SOFTIRQ,
-	KM_USER0,
-	KM_USER1,
-	KM_BIO_SRC_IRQ,
-	KM_BIO_DST_IRQ,
-	KM_PTE0,
-	KM_PTE1,
-	KM_IRQ0,
-	KM_IRQ1,
-	KM_SOFTIRQ0,
-	KM_SOFTIRQ1,
-	KM_SYNC_ICACHE,
-	KM_SYNC_DCACHE,
-	KM_UML_USERCOPY,
-	KM_IRQ_PTE,
-	KM_NMI,
-	KM_NMI_PTE,
-	KM_KDB
-};
 
 #endif /* _ASM_TILE_KMAP_TYPES_H */
diff --git a/arch/tile/include/asm/memprof.h b/arch/tile/include/asm/memprof.h
deleted file mode 100644
index 359949b..0000000
--- a/arch/tile/include/asm/memprof.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License
- *   as published by the Free Software Foundation, version 2.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- *   NON INFRINGEMENT.  See the GNU General Public License for
- *   more details.
- *
- * The hypervisor's memory controller profiling infrastructure allows
- * the programmer to find out what fraction of the available memory
- * bandwidth is being consumed at each memory controller.  The
- * profiler provides start, stop, and clear operations to allows
- * profiling over a specific time window, as well as an interface for
- * reading the most recent profile values.
- *
- * This header declares IOCTL codes necessary to control memprof.
- */
-#ifndef _ASM_TILE_MEMPROF_H
-#define _ASM_TILE_MEMPROF_H
-
-#include <linux/ioctl.h>
-
-#define MEMPROF_IOCTL_TYPE 0xB4
-#define MEMPROF_IOCTL_START _IO(MEMPROF_IOCTL_TYPE, 0)
-#define MEMPROF_IOCTL_STOP _IO(MEMPROF_IOCTL_TYPE, 1)
-#define MEMPROF_IOCTL_CLEAR _IO(MEMPROF_IOCTL_TYPE, 2)
-
-#endif /* _ASM_TILE_MEMPROF_H */
diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h
index 9d9131e..dd033a4 100644
--- a/arch/tile/include/asm/page.h
+++ b/arch/tile/include/asm/page.h
@@ -174,7 +174,9 @@ static inline __attribute_const__ int get_order(unsigned long size)
 #define MEM_LOW_END		(HALF_VA_SPACE - 1)         /* low half */
 #define MEM_HIGH_START		(-HALF_VA_SPACE)            /* high half */
 #define PAGE_OFFSET		MEM_HIGH_START
-#define _VMALLOC_START		_AC(0xfffffff500000000, UL) /* 4 GB */
+#define FIXADDR_BASE		_AC(0xfffffff400000000, UL) /* 4 GB */
+#define FIXADDR_TOP		_AC(0xfffffff500000000, UL) /* 4 GB */
+#define _VMALLOC_START		FIXADDR_TOP
 #define HUGE_VMAP_BASE		_AC(0xfffffff600000000, UL) /* 4 GB */
 #define MEM_SV_START		_AC(0xfffffff700000000, UL) /* 256 MB */
 #define MEM_SV_INTRPT		MEM_SV_START
@@ -185,9 +187,6 @@ static inline __attribute_const__ int get_order(unsigned long size)
 /* Highest DTLB address we will use */
 #define KERNEL_HIGH_VADDR	MEM_SV_START
 
-/* Since we don't currently provide any fixmaps, we use an impossible VA. */
-#define FIXADDR_TOP             MEM_HV_START
-
 #else /* !__tilegx__ */
 
 /*
diff --git a/arch/tile/include/asm/pci.h b/arch/tile/include/asm/pci.h
index 32e6cbe..553b7ff 100644
--- a/arch/tile/include/asm/pci.h
+++ b/arch/tile/include/asm/pci.h
@@ -15,9 +15,13 @@
 #ifndef _ASM_TILE_PCI_H
 #define _ASM_TILE_PCI_H
 
+#include <linux/dma-mapping.h>
 #include <linux/pci.h>
+#include <linux/numa.h>
 #include <asm-generic/pci_iomap.h>
 
+#ifndef __tilegx__
+
 /*
  * Structure of a PCI controller (host bridge)
  */
@@ -41,21 +45,162 @@ struct pci_controller {
 };
 
 /*
+ * This flag tells if the platform is TILEmpower that needs
+ * special configuration for the PLX switch chip.
+ */
+extern int tile_plx_gen1;
+
+static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {}
+
+#define	TILE_NUM_PCIE	2
+
+/*
  * The hypervisor maps the entirety of CPA-space as bus addresses, so
  * bus addresses are physical addresses.  The networking and block
  * device layers use this boolean for bounce buffer decisions.
  */
 #define PCI_DMA_BUS_IS_PHYS     1
 
+/* generic pci stuff */
+#include <asm-generic/pci.h>
+
+#else
+
+#include <asm/page.h>
+#include <gxio/trio.h>
+
+/**
+ * We reserve the hugepage-size address range at the top of the 64-bit address
+ * space to serve as the PCI window, emulating the BAR0 space of an endpoint
+ * device. This window is used by the chip-to-chip applications running on
+ * the RC node. The reason for carving out this window is that Mem-Maps that
+ * back up this window will not overlap with those that map the real physical
+ * memory.
+ */
+#define PCIE_HOST_BAR0_SIZE		HPAGE_SIZE
+#define PCIE_HOST_BAR0_START		HPAGE_MASK
+
+/**
+ * The first PAGE_SIZE of the above "BAR" window is mapped to the
+ * gxpci_host_regs structure.
+ */
+#define PCIE_HOST_REGS_SIZE		PAGE_SIZE
+
+/*
+ * This is the PCI address where the Mem-Map interrupt regions start.
+ * We use the 2nd to the last huge page of the 64-bit address space.
+ * The last huge page is used for the rootcomplex "bar", for C2C purpose.
+ */
+#define	MEM_MAP_INTR_REGIONS_BASE	(HPAGE_MASK - HPAGE_SIZE)
+
+/*
+ * Each Mem-Map interrupt region occupies 4KB.
+ */
+#define	MEM_MAP_INTR_REGION_SIZE	(1 << TRIO_MAP_MEM_LIM__ADDR_SHIFT)
+
+/*
+ * Allocate the PCI BAR window right below 4GB.
+ */
+#define	TILE_PCI_BAR_WINDOW_TOP		(1ULL << 32)
+
+/*
+ * Allocate 1GB for the PCI BAR window.
+ */
+#define	TILE_PCI_BAR_WINDOW_SIZE	(1 << 30)
+
+/*
+ * This is the highest bus address targeting the host memory that
+ * can be generated by legacy PCI devices with 32-bit or less
+ * DMA capability, dictated by the BAR window size and location.
+ */
+#define	TILE_PCI_MAX_DIRECT_DMA_ADDRESS \
+	(TILE_PCI_BAR_WINDOW_TOP - TILE_PCI_BAR_WINDOW_SIZE - 1)
+
+/*
+ * We shift the PCI bus range for all the physical memory up by the whole PA
+ * range. The corresponding CPA of an incoming PCI request will be the PCI
+ * address minus TILE_PCI_MEM_MAP_BASE_OFFSET. This also implies
+ * that the 64-bit capable devices will be given DMA addresses as
+ * the CPA plus TILE_PCI_MEM_MAP_BASE_OFFSET. To support 32-bit
+ * devices, we create a separate map region that handles the low
+ * 4GB.
+ */
+#define	TILE_PCI_MEM_MAP_BASE_OFFSET	(1ULL << CHIP_PA_WIDTH())
+
+/*
+ * End of the PCI memory resource.
+ */
+#define	TILE_PCI_MEM_END	\
+		((1ULL << CHIP_PA_WIDTH()) + TILE_PCI_BAR_WINDOW_TOP)
+
+/*
+ * Start of the PCI memory resource.
+ */
+#define	TILE_PCI_MEM_START	(TILE_PCI_MEM_END - TILE_PCI_BAR_WINDOW_SIZE)
+
+/*
+ * Structure of a PCI controller (host bridge) on Gx.
+ */
+struct pci_controller {
+
+	/* Pointer back to the TRIO that this PCIe port is connected to. */
+	gxio_trio_context_t *trio;
+	int mac;		/* PCIe mac index on the TRIO shim */
+	int trio_index;		/* Index of TRIO shim that contains the MAC. */
+
+	int pio_mem_index;	/* PIO region index for memory access */
+
+	/*
+	 * Mem-Map regions for all the memory controllers so that Linux can
+	 * map all of its physical memory space to the PCI bus.
+	 */
+	int mem_maps[MAX_NUMNODES];
+
+	int index;		/* PCI domain number */
+	struct pci_bus *root_bus;
+
+	uint64_t mem_offset;	/* cpu->bus memory mapping offset. */
+
+	int last_busno;
+
+	struct pci_ops *ops;
+
+	/* Table that maps the INTx numbers to Linux irq numbers. */
+	int irq_intx_table[4];
+
+	struct resource mem_space;
+
+	/* Address ranges that are routed to this controller/bridge. */
+	struct resource mem_resources[3];
+};
+
+extern struct pci_controller pci_controllers[TILEGX_NUM_TRIO * TILEGX_TRIO_PCIES];
+extern gxio_trio_context_t trio_contexts[TILEGX_NUM_TRIO];
+
+extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
+
+extern void
+pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+			struct resource *res);
+
+extern void
+pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+			struct pci_bus_region *region);
+
+/*
+ * The PCI address space does not equal the physical memory address
+ * space (we have an IOMMU). The IDE and SCSI device layers use this
+ * boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS     0
+
+#endif /* __tilegx__ */
+
 int __init tile_pci_init(void);
 int __init pcibios_init(void);
 
-static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {}
-
 void __devinit pcibios_fixup_bus(struct pci_bus *bus);
 
-#define	TILE_NUM_PCIE	2
-
 #define pci_domain_nr(bus) (((struct pci_controller *)(bus)->sysdata)->index)
 
 /*
@@ -79,19 +224,10 @@ static inline int pcibios_assign_all_busses(void)
 #define PCIBIOS_MIN_MEM		0
 #define PCIBIOS_MIN_IO		0
 
-/*
- * This flag tells if the platform is TILEmpower that needs
- * special configuration for the PLX switch chip.
- */
-extern int tile_plx_gen1;
-
 /* Use any cpu for PCI. */
 #define cpumask_of_pcibus(bus) cpu_online_mask
 
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
-/* generic pci stuff */
-#include <asm-generic/pci.h>
-
 #endif /* _ASM_TILE_PCI_H */
diff --git a/arch/tile/include/gxio/common.h b/arch/tile/include/gxio/common.h
new file mode 100644
index 0000000..724595a
--- /dev/null
+++ b/arch/tile/include/gxio/common.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef _GXIO_COMMON_H_
+#define _GXIO_COMMON_H_
+
+/*
+ * Routines shared between the various GXIO device components.
+ */
+
+#include <hv/iorpc.h>
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/io.h>
+
+/* Define the standard gxio MMIO functions using kernel functions. */
+#define __gxio_mmio_read8(addr)		readb(addr)
+#define __gxio_mmio_read16(addr)	readw(addr)
+#define __gxio_mmio_read32(addr)	readl(addr)
+#define __gxio_mmio_read64(addr)	readq(addr)
+#define __gxio_mmio_write8(addr, val)	writeb((val), (addr))
+#define __gxio_mmio_write16(addr, val)	writew((val), (addr))
+#define __gxio_mmio_write32(addr, val)	writel((val), (addr))
+#define __gxio_mmio_write64(addr, val)	writeq((val), (addr))
+#define __gxio_mmio_read(addr)		__gxio_mmio_read64(addr)
+#define __gxio_mmio_write(addr, val)	__gxio_mmio_write64((addr), (val))
+
+#endif /* !_GXIO_COMMON_H_ */
diff --git a/arch/tile/include/gxio/dma_queue.h b/arch/tile/include/gxio/dma_queue.h
new file mode 100644
index 0000000..00654fe
--- /dev/null
+++ b/arch/tile/include/gxio/dma_queue.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef _GXIO_DMA_QUEUE_H_
+#define _GXIO_DMA_QUEUE_H_
+
+/*
+ * DMA queue management APIs shared between TRIO and mPIPE.
+ */
+
+#include "common.h"
+
+/* The credit counter lives in the high 32 bits. */
+#define DMA_QUEUE_CREDIT_SHIFT 32
+
+/*
+ * State object that tracks a DMA queue's head and tail indices, as
+ * well as the number of commands posted and completed.  The
+ * structure is accessed via a thread-safe, lock-free algorithm.
+ */
+typedef struct {
+	/*
+	 * Address of a MPIPE_EDMA_POST_REGION_VAL_t,
+	 * TRIO_PUSH_DMA_REGION_VAL_t, or TRIO_PULL_DMA_REGION_VAL_t
+	 * register.  These register have identical encodings and provide
+	 * information about how many commands have been processed.
+	 */
+	void *post_region_addr;
+
+	/*
+	 * A lazily-updated count of how many edescs the hardware has
+	 * completed.
+	 */
+	uint64_t hw_complete_count __attribute__ ((aligned(64)));
+
+	/*
+	 * High 32 bits are a count of available egress command credits,
+	 * low 24 bits are the next egress "slot".
+	 */
+	int64_t credits_and_next_index;
+
+} __gxio_dma_queue_t;
+
+/* Initialize a dma queue. */
+extern void __gxio_dma_queue_init(__gxio_dma_queue_t *dma_queue,
+				  void *post_region_addr,
+				  unsigned int num_entries);
+
+/*
+ * Update the "credits_and_next_index" and "hw_complete_count" fields
+ * based on pending hardware completions.  Note that some other thread
+ * may have already done this and, importantly, may still be in the
+ * process of updating "credits_and_next_index".
+ */
+extern void __gxio_dma_queue_update_credits(__gxio_dma_queue_t *dma_queue);
+
+/* Wait for credits to become available. */
+extern int64_t __gxio_dma_queue_wait_for_credits(__gxio_dma_queue_t *dma_queue,
+						 int64_t modifier);
+
+/* Reserve slots in the queue, optionally waiting for slots to become
+ * available, and optionally returning a "completion_slot" suitable for
+ * direct comparison to "hw_complete_count".
+ */
+static inline int64_t __gxio_dma_queue_reserve(__gxio_dma_queue_t *dma_queue,
+					       unsigned int num, bool wait,
+					       bool completion)
+{
+	uint64_t slot;
+
+	/*
+	 * Try to reserve 'num' egress command slots.  We do this by
+	 * constructing a constant that subtracts N credits and adds N to
+	 * the index, and using fetchaddgez to only apply it if the credits
+	 * count doesn't go negative.
+	 */
+	int64_t modifier = (((int64_t)(-num)) << DMA_QUEUE_CREDIT_SHIFT) | num;
+	int64_t old =
+		__insn_fetchaddgez(&dma_queue->credits_and_next_index,
+				   modifier);
+
+	if (unlikely(old + modifier < 0)) {
+		/*
+		 * We're out of credits.  Try once to get more by checking for
+		 * completed egress commands.  If that fails, wait or fail.
+		 */
+		__gxio_dma_queue_update_credits(dma_queue);
+		old = __insn_fetchaddgez(&dma_queue->credits_and_next_index,
+					 modifier);
+		if (old + modifier < 0) {
+			if (wait)
+				old = __gxio_dma_queue_wait_for_credits
+					(dma_queue, modifier);
+			else
+				return GXIO_ERR_DMA_CREDITS;
+		}
+	}
+
+	/* The bottom 24 bits of old encode the "slot". */
+	slot = (old & 0xffffff);
+
+	if (completion) {
+		/*
+		 * A "completion_slot" is a "slot" which can be compared to
+		 * "hw_complete_count" at any time in the future.  To convert
+		 * "slot" into a "completion_slot", we access "hw_complete_count"
+		 * once (knowing that we have reserved a slot, and thus, it will
+		 * be "basically" accurate), and combine its high 40 bits with
+		 * the 24 bit "slot", and handle "wrapping" by adding "1 << 24"
+		 * if the result is LESS than "hw_complete_count".
+		 */
+		uint64_t complete;
+		complete = ACCESS_ONCE(dma_queue->hw_complete_count);
+		slot |= (complete & 0xffffffffff000000);
+		if (slot < complete)
+			slot += 0x1000000;
+	}
+
+	/*
+	 * If any of our slots mod 256 were equivalent to 0, go ahead and
+	 * collect some egress credits, and update "hw_complete_count", and
+	 * make sure the index doesn't overflow into the credits.
+	 */
+	if (unlikely(((old + num) & 0xff) < num)) {
+		__gxio_dma_queue_update_credits(dma_queue);
+
+		/* Make sure the index doesn't overflow into the credits. */
+#ifdef __BIG_ENDIAN__
+		*(((uint8_t *)&dma_queue->credits_and_next_index) + 4) = 0;
+#else
+		*(((uint8_t *)&dma_queue->credits_and_next_index) + 3) = 0;
+#endif
+	}
+
+	return slot;
+}
+
+/* Non-inlinable "__gxio_dma_queue_reserve(..., true)". */
+extern int64_t __gxio_dma_queue_reserve_aux(__gxio_dma_queue_t *dma_queue,
+					    unsigned int num, int wait);
+
+/* Check whether a particular "completion slot" has completed.
+ *
+ * Note that this function requires a "completion slot", and thus
+ * cannot be used with the result of any "reserve_fast" function.
+ */
+extern int __gxio_dma_queue_is_complete(__gxio_dma_queue_t *dma_queue,
+					int64_t completion_slot, int update);
+
+#endif /* !_GXIO_DMA_QUEUE_H_ */
diff --git a/arch/tile/include/gxio/iorpc_globals.h b/arch/tile/include/gxio/iorpc_globals.h
new file mode 100644
index 0000000..52c721f
--- /dev/null
+++ b/arch/tile/include/gxio/iorpc_globals.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+#ifndef __IORPC_LINUX_RPC_H__
+#define __IORPC_LINUX_RPC_H__
+
+#include <hv/iorpc.h>
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <asm/pgtable.h>
+
+#define IORPC_OP_ARM_POLLFD            IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9000)
+#define IORPC_OP_CLOSE_POLLFD          IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9001)
+#define IORPC_OP_GET_MMIO_BASE         IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
+#define IORPC_OP_CHECK_MMIO_OFFSET     IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
+
+int __iorpc_arm_pollfd(int fd, int pollfd_cookie);
+
+int __iorpc_close_pollfd(int fd, int pollfd_cookie);
+
+int __iorpc_get_mmio_base(int fd, HV_PTE *base);
+
+int __iorpc_check_mmio_offset(int fd, unsigned long offset, unsigned long size);
+
+#endif /* !__IORPC_LINUX_RPC_H__ */
diff --git a/arch/tile/include/gxio/iorpc_mpipe.h b/arch/tile/include/gxio/iorpc_mpipe.h
new file mode 100644
index 0000000..9d50fce
--- /dev/null
+++ b/arch/tile/include/gxio/iorpc_mpipe.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+#ifndef __GXIO_MPIPE_LINUX_RPC_H__
+#define __GXIO_MPIPE_LINUX_RPC_H__
+
+#include <hv/iorpc.h>
+
+#include <hv/drv_mpipe_intf.h>
+#include <asm/page.h>
+#include <gxio/kiorpc.h>
+#include <gxio/mpipe.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <asm/pgtable.h>
+
+#define GXIO_MPIPE_OP_ALLOC_BUFFER_STACKS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1200)
+#define GXIO_MPIPE_OP_INIT_BUFFER_STACK_AUX IORPC_OPCODE(IORPC_FORMAT_KERNEL_MEM, 0x1201)
+
+#define GXIO_MPIPE_OP_ALLOC_NOTIF_RINGS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1203)
+#define GXIO_MPIPE_OP_INIT_NOTIF_RING_AUX IORPC_OPCODE(IORPC_FORMAT_KERNEL_MEM, 0x1204)
+#define GXIO_MPIPE_OP_REQUEST_NOTIF_RING_INTERRUPT IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1205)
+#define GXIO_MPIPE_OP_ENABLE_NOTIF_RING_INTERRUPT IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1206)
+#define GXIO_MPIPE_OP_ALLOC_NOTIF_GROUPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1207)
+#define GXIO_MPIPE_OP_INIT_NOTIF_GROUP IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1208)
+#define GXIO_MPIPE_OP_ALLOC_BUCKETS    IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1209)
+#define GXIO_MPIPE_OP_INIT_BUCKET      IORPC_OPCODE(IORPC_FORMAT_NONE, 0x120a)
+#define GXIO_MPIPE_OP_ALLOC_EDMA_RINGS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x120b)
+#define GXIO_MPIPE_OP_INIT_EDMA_RING_AUX IORPC_OPCODE(IORPC_FORMAT_KERNEL_MEM, 0x120c)
+
+#define GXIO_MPIPE_OP_COMMIT_RULES     IORPC_OPCODE(IORPC_FORMAT_NONE, 0x120f)
+#define GXIO_MPIPE_OP_REGISTER_CLIENT_MEMORY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1210)
+#define GXIO_MPIPE_OP_LINK_OPEN_AUX    IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1211)
+#define GXIO_MPIPE_OP_LINK_CLOSE_AUX   IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1212)
+
+#define GXIO_MPIPE_OP_GET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x121e)
+#define GXIO_MPIPE_OP_SET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x121f)
+#define GXIO_MPIPE_OP_ADJUST_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1220)
+#define GXIO_MPIPE_OP_ARM_POLLFD       IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9000)
+#define GXIO_MPIPE_OP_CLOSE_POLLFD     IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9001)
+#define GXIO_MPIPE_OP_GET_MMIO_BASE    IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
+#define GXIO_MPIPE_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
+
+int gxio_mpipe_alloc_buffer_stacks(gxio_mpipe_context_t * context,
+				   unsigned int count, unsigned int first,
+				   unsigned int flags);
+
+int gxio_mpipe_init_buffer_stack_aux(gxio_mpipe_context_t * context,
+				     void *mem_va, size_t mem_size,
+				     unsigned int mem_flags, unsigned int stack,
+				     unsigned int buffer_size_enum);
+
+
+int gxio_mpipe_alloc_notif_rings(gxio_mpipe_context_t * context,
+				 unsigned int count, unsigned int first,
+				 unsigned int flags);
+
+int gxio_mpipe_init_notif_ring_aux(gxio_mpipe_context_t * context, void *mem_va,
+				   size_t mem_size, unsigned int mem_flags,
+				   unsigned int ring);
+
+int gxio_mpipe_request_notif_ring_interrupt(gxio_mpipe_context_t * context,
+					    int inter_x, int inter_y,
+					    int inter_ipi, int inter_event,
+					    unsigned int ring);
+
+int gxio_mpipe_enable_notif_ring_interrupt(gxio_mpipe_context_t * context,
+					   unsigned int ring);
+
+int gxio_mpipe_alloc_notif_groups(gxio_mpipe_context_t * context,
+				  unsigned int count, unsigned int first,
+				  unsigned int flags);
+
+int gxio_mpipe_init_notif_group(gxio_mpipe_context_t * context,
+				unsigned int group,
+				gxio_mpipe_notif_group_bits_t bits);
+
+int gxio_mpipe_alloc_buckets(gxio_mpipe_context_t * context, unsigned int count,
+			     unsigned int first, unsigned int flags);
+
+int gxio_mpipe_init_bucket(gxio_mpipe_context_t * context, unsigned int bucket,
+			   MPIPE_LBL_INIT_DAT_BSTS_TBL_t bucket_info);
+
+int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t * context,
+				unsigned int count, unsigned int first,
+				unsigned int flags);
+
+int gxio_mpipe_init_edma_ring_aux(gxio_mpipe_context_t * context, void *mem_va,
+				  size_t mem_size, unsigned int mem_flags,
+				  unsigned int ring, unsigned int channel);
+
+
+int gxio_mpipe_commit_rules(gxio_mpipe_context_t * context, const void *blob,
+			    size_t blob_size);
+
+int gxio_mpipe_register_client_memory(gxio_mpipe_context_t * context,
+				      unsigned int iotlb, HV_PTE pte,
+				      unsigned int flags);
+
+int gxio_mpipe_link_open_aux(gxio_mpipe_context_t * context,
+			     _gxio_mpipe_link_name_t name, unsigned int flags);
+
+int gxio_mpipe_link_close_aux(gxio_mpipe_context_t * context, int mac);
+
+
+int gxio_mpipe_get_timestamp_aux(gxio_mpipe_context_t * context, uint64_t * sec,
+				 uint64_t * nsec, uint64_t * cycles);
+
+int gxio_mpipe_set_timestamp_aux(gxio_mpipe_context_t * context, uint64_t sec,
+				 uint64_t nsec, uint64_t cycles);
+
+int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t * context,
+				    int64_t nsec);
+
+int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie);
+
+int gxio_mpipe_close_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie);
+
+int gxio_mpipe_get_mmio_base(gxio_mpipe_context_t * context, HV_PTE *base);
+
+int gxio_mpipe_check_mmio_offset(gxio_mpipe_context_t * context,
+				 unsigned long offset, unsigned long size);
+
+#endif /* !__GXIO_MPIPE_LINUX_RPC_H__ */
diff --git a/arch/tile/include/gxio/iorpc_mpipe_info.h b/arch/tile/include/gxio/iorpc_mpipe_info.h
new file mode 100644
index 0000000..0bcf3f7
--- /dev/null
+++ b/arch/tile/include/gxio/iorpc_mpipe_info.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+#ifndef __GXIO_MPIPE_INFO_LINUX_RPC_H__
+#define __GXIO_MPIPE_INFO_LINUX_RPC_H__
+
+#include <hv/iorpc.h>
+
+#include <hv/drv_mpipe_intf.h>
+#include <asm/page.h>
+#include <gxio/kiorpc.h>
+#include <gxio/mpipe.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <asm/pgtable.h>
+
+
+#define GXIO_MPIPE_INFO_OP_ENUMERATE_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1251)
+#define GXIO_MPIPE_INFO_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
+#define GXIO_MPIPE_INFO_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
+
+
+int gxio_mpipe_info_enumerate_aux(gxio_mpipe_info_context_t * context,
+				  unsigned int idx,
+				  _gxio_mpipe_link_name_t * name,
+				  _gxio_mpipe_link_mac_t * mac);
+
+int gxio_mpipe_info_get_mmio_base(gxio_mpipe_info_context_t * context,
+				  HV_PTE *base);
+
+int gxio_mpipe_info_check_mmio_offset(gxio_mpipe_info_context_t * context,
+				      unsigned long offset, unsigned long size);
+
+#endif /* !__GXIO_MPIPE_INFO_LINUX_RPC_H__ */
diff --git a/arch/tile/include/gxio/iorpc_trio.h b/arch/tile/include/gxio/iorpc_trio.h
new file mode 100644
index 0000000..15fb779
--- /dev/null
+++ b/arch/tile/include/gxio/iorpc_trio.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+#ifndef __GXIO_TRIO_LINUX_RPC_H__
+#define __GXIO_TRIO_LINUX_RPC_H__
+
+#include <hv/iorpc.h>
+
+#include <hv/drv_trio_intf.h>
+#include <gxio/trio.h>
+#include <gxio/kiorpc.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <asm/pgtable.h>
+
+#define GXIO_TRIO_OP_ALLOC_ASIDS       IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1400)
+
+#define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1402)
+
+#define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140e)
+#define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140f)
+
+#define GXIO_TRIO_OP_INIT_MEMORY_MAP_MMU_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1417)
+#define GXIO_TRIO_OP_GET_PORT_PROPERTY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1418)
+#define GXIO_TRIO_OP_CONFIG_LEGACY_INTR IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1419)
+#define GXIO_TRIO_OP_CONFIG_MSI_INTR   IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x141a)
+
+#define GXIO_TRIO_OP_SET_MPS_MRS       IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141c)
+#define GXIO_TRIO_OP_FORCE_RC_LINK_UP  IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141d)
+#define GXIO_TRIO_OP_FORCE_EP_LINK_UP  IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141e)
+#define GXIO_TRIO_OP_GET_MMIO_BASE     IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
+#define GXIO_TRIO_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
+
+int gxio_trio_alloc_asids(gxio_trio_context_t * context, unsigned int count,
+			  unsigned int first, unsigned int flags);
+
+
+int gxio_trio_alloc_memory_maps(gxio_trio_context_t * context,
+				unsigned int count, unsigned int first,
+				unsigned int flags);
+
+
+int gxio_trio_alloc_pio_regions(gxio_trio_context_t * context,
+				unsigned int count, unsigned int first,
+				unsigned int flags);
+
+int gxio_trio_init_pio_region_aux(gxio_trio_context_t * context,
+				  unsigned int pio_region, unsigned int mac,
+				  uint32_t bus_address_hi, unsigned int flags);
+
+
+int gxio_trio_init_memory_map_mmu_aux(gxio_trio_context_t * context,
+				      unsigned int map, unsigned long va,
+				      uint64_t size, unsigned int asid,
+				      unsigned int mac, uint64_t bus_address,
+				      unsigned int node,
+				      unsigned int order_mode);
+
+int gxio_trio_get_port_property(gxio_trio_context_t * context,
+				struct pcie_trio_ports_property *trio_ports);
+
+int gxio_trio_config_legacy_intr(gxio_trio_context_t * context, int inter_x,
+				 int inter_y, int inter_ipi, int inter_event,
+				 unsigned int mac, unsigned int intx);
+
+int gxio_trio_config_msi_intr(gxio_trio_context_t * context, int inter_x,
+			      int inter_y, int inter_ipi, int inter_event,
+			      unsigned int mac, unsigned int mem_map,
+			      uint64_t mem_map_base, uint64_t mem_map_limit,
+			      unsigned int asid);
+
+
+int gxio_trio_set_mps_mrs(gxio_trio_context_t * context, uint16_t mps,
+			  uint16_t mrs, unsigned int mac);
+
+int gxio_trio_force_rc_link_up(gxio_trio_context_t * context, unsigned int mac);
+
+int gxio_trio_force_ep_link_up(gxio_trio_context_t * context, unsigned int mac);
+
+int gxio_trio_get_mmio_base(gxio_trio_context_t * context, HV_PTE *base);
+
+int gxio_trio_check_mmio_offset(gxio_trio_context_t * context,
+				unsigned long offset, unsigned long size);
+
+#endif /* !__GXIO_TRIO_LINUX_RPC_H__ */
diff --git a/arch/tile/include/gxio/iorpc_usb_host.h b/arch/tile/include/gxio/iorpc_usb_host.h
new file mode 100644
index 0000000..8622e7d
--- /dev/null
+++ b/arch/tile/include/gxio/iorpc_usb_host.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+#ifndef __GXIO_USB_HOST_LINUX_RPC_H__
+#define __GXIO_USB_HOST_LINUX_RPC_H__
+
+#include <hv/iorpc.h>
+
+#include <hv/drv_usb_host_intf.h>
+#include <asm/page.h>
+#include <gxio/kiorpc.h>
+#include <gxio/usb_host.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <asm/pgtable.h>
+
+#define GXIO_USB_HOST_OP_CFG_INTERRUPT IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1800)
+#define GXIO_USB_HOST_OP_REGISTER_CLIENT_MEMORY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1801)
+#define GXIO_USB_HOST_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
+#define GXIO_USB_HOST_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
+
+int gxio_usb_host_cfg_interrupt(gxio_usb_host_context_t * context, int inter_x,
+				int inter_y, int inter_ipi, int inter_event);
+
+int gxio_usb_host_register_client_memory(gxio_usb_host_context_t * context,
+					 HV_PTE pte, unsigned int flags);
+
+int gxio_usb_host_get_mmio_base(gxio_usb_host_context_t * context,
+				HV_PTE *base);
+
+int gxio_usb_host_check_mmio_offset(gxio_usb_host_context_t * context,
+				    unsigned long offset, unsigned long size);
+
+#endif /* !__GXIO_USB_HOST_LINUX_RPC_H__ */
diff --git a/arch/tile/include/gxio/kiorpc.h b/arch/tile/include/gxio/kiorpc.h
new file mode 100644
index 0000000..ee58209
--- /dev/null
+++ b/arch/tile/include/gxio/kiorpc.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Support routines for kernel IORPC drivers.
+ */
+
+#ifndef _GXIO_KIORPC_H
+#define _GXIO_KIORPC_H
+
+#include <linux/types.h>
+#include <asm/page.h>
+#include <arch/chip.h>
+
+#if CHIP_HAS_MMIO()
+void __iomem *iorpc_ioremap(int hv_fd, resource_size_t offset,
+			    unsigned long size);
+#endif
+
+#endif /* _GXIO_KIORPC_H */
diff --git a/arch/tile/include/gxio/mpipe.h b/arch/tile/include/gxio/mpipe.h
new file mode 100644
index 0000000..78c5986
--- /dev/null
+++ b/arch/tile/include/gxio/mpipe.h
@@ -0,0 +1,1736 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef _GXIO_MPIPE_H_
+#define _GXIO_MPIPE_H_
+
+/*
+ *
+ * An API for allocating, configuring, and manipulating mPIPE hardware
+ * resources.
+ */
+
+#include "common.h"
+#include "dma_queue.h"
+
+#include <linux/time.h>
+
+#include <arch/mpipe_def.h>
+#include <arch/mpipe_shm.h>
+
+#include <hv/drv_mpipe_intf.h>
+#include <hv/iorpc.h>
+
+/*
+ *
+ * The TILE-Gx mPIPE&tm; shim provides Ethernet connectivity, packet
+ * classification, and packet load balancing services.  The
+ * gxio_mpipe_ API, declared in <gxio/mpipe.h>, allows applications to
+ * allocate mPIPE IO channels, configure packet distribution
+ * parameters, and send and receive Ethernet packets.  The API is
+ * designed to be a minimal wrapper around the mPIPE hardware, making
+ * system calls only where necessary to preserve inter-process
+ * protection guarantees.
+ *
+ * The APIs described below allow the programmer to allocate and
+ * configure mPIPE resources.  As described below, the mPIPE is a
+ * single shared hardware device that provides partitionable resources
+ * that are shared between all applications in the system.  The
+ * gxio_mpipe_ API allows userspace code to make resource request
+ * calls to the hypervisor, which in turns keeps track of the
+ * resources in use by all applications, maintains protection
+ * guarantees, and resets resources upon application shutdown.
+ *
+ * We strongly recommend reading the mPIPE section of the IO Device
+ * Guide (UG404) before working with this API.  Most functions in the
+ * gxio_mpipe_ API are directly analogous to hardware interfaces and
+ * the documentation assumes that the reader understands those
+ * hardware interfaces.
+ *
+ * @section mpipe__ingress mPIPE Ingress Hardware Resources
+ *
+ * The mPIPE ingress hardware provides extensive hardware offload for
+ * tasks like packet header parsing, load balancing, and memory
+ * management.  This section provides a brief introduction to the
+ * hardware components and the gxio_mpipe_ calls used to manage them;
+ * see the IO Device Guide for a much more detailed description of the
+ * mPIPE's capabilities.
+ *
+ * When a packet arrives at one of the mPIPE's Ethernet MACs, it is
+ * assigned a channel number indicating which MAC received it.  It
+ * then proceeds through the following hardware pipeline:
+ *
+ * @subsection mpipe__classification Classification
+ *
+ * A set of classification processors run header parsing code on each
+ * incoming packet, extracting information including the destination
+ * MAC address, VLAN, Ethernet type, and five-tuple hash.  Some of
+ * this information is then used to choose which buffer stack will be
+ * used to hold the packet, and which bucket will be used by the load
+ * balancer to determine which application will receive the packet.
+ *
+ * The rules by which the buffer stack and bucket are chosen can be
+ * configured via the @ref gxio_mpipe_classifier API.  A given app can
+ * specify multiple rules, each one specifying a bucket range, and a
+ * set of buffer stacks, to be used for packets matching the rule.
+ * Each rule can optionally specify a restricted set of channels,
+ * VLANs, and/or dMACs, in which it is interested.  By default, a
+ * given rule starts out matching all channels associated with the
+ * mPIPE context's set of open links; all VLANs; and all dMACs.
+ * Subsequent restrictions can then be added.
+ *
+ * @subsection mpipe__load_balancing Load Balancing
+ *
+ * The mPIPE load balancer is responsible for choosing the NotifRing
+ * to which the packet will be delivered.  This decision is based on
+ * the bucket number indicated by the classification program.  In
+ * general, the bucket number is based on some number of low bits of
+ * the packet's flow hash (applications that aren't interested in flow
+ * hashing use a single bucket).  Each load balancer bucket keeps a
+ * record of the NotifRing to which packets directed to that bucket
+ * are currently being delivered.  Based on the bucket's load
+ * balancing mode (@ref gxio_mpipe_bucket_mode_t), the load balancer
+ * either forwards the packet to the previously assigned NotifRing or
+ * decides to choose a new NotifRing.  If a new NotifRing is required,
+ * the load balancer chooses the least loaded ring in the NotifGroup
+ * associated with the bucket.
+ *
+ * The load balancer is a shared resource.  Each application needs to
+ * explicitly allocate NotifRings, NotifGroups, and buckets, using
+ * gxio_mpipe_alloc_notif_rings(), gxio_mpipe_alloc_notif_groups(),
+ * and gxio_mpipe_alloc_buckets().  Then the application needs to
+ * configure them using gxio_mpipe_init_notif_ring() and
+ * gxio_mpipe_init_notif_group_and_buckets().
+ *
+ * @subsection mpipe__buffers Buffer Selection and Packet Delivery
+ *
+ * Once the load balancer has chosen the destination NotifRing, the
+ * mPIPE DMA engine pops at least one buffer off of the 'buffer stack'
+ * chosen by the classification program and DMAs the packet data into
+ * that buffer.  Each buffer stack provides a hardware-accelerated
+ * stack of data buffers with the same size.  If the packet data is
+ * larger than the buffers provided by the chosen buffer stack, the
+ * mPIPE hardware pops off multiple buffers and chains the packet data
+ * through a multi-buffer linked list.  Once the packet data is
+ * delivered to the buffer(s), the mPIPE hardware writes the
+ * ::gxio_mpipe_idesc_t metadata object (calculated by the classifier)
+ * into the NotifRing and increments the number of packets delivered
+ * to that ring.
+ *
+ * Applications can push buffers onto a buffer stack by calling
+ * gxio_mpipe_push_buffer() or by egressing a packet with the
+ * ::gxio_mpipe_edesc_t::hwb bit set, indicating that the egressed
+ * buffers should be returned to the stack.
+ *
+ * Applications can allocate and initialize buffer stacks with the
+ * gxio_mpipe_alloc_buffer_stacks() and gxio_mpipe_init_buffer_stack()
+ * APIs.
+ *
+ * The application must also register the memory pages that will hold
+ * packets.  This requires calling gxio_mpipe_register_page() for each
+ * memory page that will hold packets allocated by the application for
+ * a given buffer stack.  Since each buffer stack is limited to 16
+ * registered pages, it may be necessary to use huge pages, or even
+ * extremely huge pages, to hold all the buffers.
+ *
+ * @subsection mpipe__iqueue NotifRings
+ *
+ * Each NotifRing is a region of shared memory, allocated by the
+ * application, to which the mPIPE delivers packet descriptors
+ * (::gxio_mpipe_idesc_t).  The application can allocate them via
+ * gxio_mpipe_alloc_notif_rings().  The application can then either
+ * explicitly initialize them with gxio_mpipe_init_notif_ring() and
+ * then read from them manually, or can make use of the convenience
+ * wrappers provided by @ref gxio_mpipe_wrappers.
+ *
+ * @section mpipe__egress mPIPE Egress Hardware
+ *
+ * Applications use eDMA rings to queue packets for egress.  The
+ * application can allocate them via gxio_mpipe_alloc_edma_rings().
+ * The application can then either explicitly initialize them with
+ * gxio_mpipe_init_edma_ring() and then write to them manually, or
+ * can make use of the convenience wrappers provided by
+ * @ref gxio_mpipe_wrappers.
+ *
+ * @section gxio__shortcomings Plans for Future API Revisions
+ *
+ * The API defined here is only an initial version of the mPIPE API.
+ * Future plans include:
+ *
+ * - Higher level wrapper functions to provide common initialization
+ * patterns.  This should help users start writing mPIPE programs
+ * without having to learn the details of the hardware.
+ *
+ * - Support for reset and deallocation of resources, including
+ * cleanup upon application shutdown.
+ *
+ * - Support for calling these APIs in the BME.
+ *
+ * - Support for IO interrupts.
+ *
+ * - Clearer definitions of thread safety guarantees.
+ *
+ * @section gxio__mpipe_examples Examples
+ *
+ * See the following mPIPE example programs for more information about
+ * allocating mPIPE resources and using them in real applications:
+ *
+ * - @ref mpipe/ingress/app.c : Receiving packets.
+ *
+ * - @ref mpipe/forward/app.c : Forwarding packets.
+ *
+ * Note that there are several more examples.
+ */
+
+/* Flags that can be passed to resource allocation functions. */
+enum gxio_mpipe_alloc_flags_e {
+	/* Require an allocation to start at a specified resource index. */
+	GXIO_MPIPE_ALLOC_FIXED = HV_MPIPE_ALLOC_FIXED,
+};
+
+/* Flags that can be passed to memory registration functions. */
+enum gxio_mpipe_mem_flags_e {
+	/* Do not fill L3 when writing, and invalidate lines upon egress. */
+	GXIO_MPIPE_MEM_FLAG_NT_HINT = IORPC_MEM_BUFFER_FLAG_NT_HINT,
+
+	/* L3 cache fills should only populate IO cache ways. */
+	GXIO_MPIPE_MEM_FLAG_IO_PIN = IORPC_MEM_BUFFER_FLAG_IO_PIN,
+};
+
+/* An ingress packet descriptor.  When a packet arrives, the mPIPE
+ * hardware generates this structure and writes it into a NotifRing.
+ */
+typedef MPIPE_PDESC_t gxio_mpipe_idesc_t;
+
+/* An egress command descriptor.  Applications write this structure
+ * into eDMA rings and the hardware performs the indicated operation
+ * (normally involving egressing some bytes).  Note that egressing a
+ * single packet may involve multiple egress command descriptors.
+ */
+typedef MPIPE_EDMA_DESC_t gxio_mpipe_edesc_t;
+
+/* Get the "va" field from an "idesc".
+ *
+ * This is the address at which the ingress hardware copied the first
+ * byte of the packet.
+ *
+ * If the classifier detected a custom header, then this will point to
+ * the custom header, and gxio_mpipe_idesc_get_l2_start() will point
+ * to the actual L2 header.
+ *
+ * Note that this value may be misleading if "idesc->be" is set.
+ *
+ * @param idesc An ingress packet descriptor.
+ */
+static inline unsigned char *gxio_mpipe_idesc_get_va(gxio_mpipe_idesc_t *idesc)
+{
+	return (unsigned char *)(long)idesc->va;
+}
+
+/* Get the "xfer_size" from an "idesc".
+ *
+ * This is the actual number of packet bytes transferred into memory
+ * by the hardware.
+ *
+ * Note that this value may be misleading if "idesc->be" is set.
+ *
+ * @param idesc An ingress packet descriptor.
+ *
+ * ISSUE: Is this the best name for this?
+ * FIXME: Add more docs about chaining, clipping, etc.
+ */
+static inline unsigned int gxio_mpipe_idesc_get_xfer_size(gxio_mpipe_idesc_t
+							  *idesc)
+{
+	return idesc->l2_size;
+}
+
+/* Get the "l2_offset" from an "idesc".
+ *
+ * Extremely customized classifiers might not support this function.
+ *
+ * This is the number of bytes between the "va" and the L2 header.
+ *
+ * The L2 header consists of a destination mac address, a source mac
+ * address, and an initial ethertype.  Various initial ethertypes
+ * allow encoding extra information in the L2 header, often including
+ * a vlan, and/or a new ethertype.
+ *
+ * Note that the "l2_offset" will be non-zero if (and only if) the
+ * classifier processed a custom header for the packet.
+ *
+ * @param idesc An ingress packet descriptor.
+ */
+static inline uint8_t gxio_mpipe_idesc_get_l2_offset(gxio_mpipe_idesc_t *idesc)
+{
+	return (idesc->custom1 >> 32) & 0xFF;
+}
+
+/* Get the "l2_start" from an "idesc".
+ *
+ * This is simply gxio_mpipe_idesc_get_va() plus
+ * gxio_mpipe_idesc_get_l2_offset().
+ *
+ * @param idesc An ingress packet descriptor.
+ */
+static inline unsigned char *gxio_mpipe_idesc_get_l2_start(gxio_mpipe_idesc_t
+							   *idesc)
+{
+	unsigned char *va = gxio_mpipe_idesc_get_va(idesc);
+	return va + gxio_mpipe_idesc_get_l2_offset(idesc);
+}
+
+/* Get the "l2_length" from an "idesc".
+ *
+ * This is simply gxio_mpipe_idesc_get_xfer_size() minus
+ * gxio_mpipe_idesc_get_l2_offset().
+ *
+ * @param idesc An ingress packet descriptor.
+ */
+static inline unsigned int gxio_mpipe_idesc_get_l2_length(gxio_mpipe_idesc_t
+							  *idesc)
+{
+	unsigned int xfer_size = idesc->l2_size;
+	return xfer_size - gxio_mpipe_idesc_get_l2_offset(idesc);
+}
+
+/* A context object used to manage mPIPE hardware resources. */
+typedef struct {
+
+	/* File descriptor for calling up to Linux (and thus the HV). */
+	int fd;
+
+	/* The VA at which configuration registers are mapped. */
+	char *mmio_cfg_base;
+
+	/* The VA at which IDMA, EDMA, and buffer manager are mapped. */
+	char *mmio_fast_base;
+
+	/* The "initialized" buffer stacks. */
+	gxio_mpipe_rules_stacks_t __stacks;
+
+} gxio_mpipe_context_t;
+
+/* This is only used internally, but it's most easily made visible here. */
+typedef gxio_mpipe_context_t gxio_mpipe_info_context_t;
+
+/* Initialize an mPIPE context.
+ *
+ * This function allocates an mPIPE "service domain" and maps the MMIO
+ * registers into the caller's VA space.
+ *
+ * @param context Context object to be initialized.
+ * @param mpipe_instance Instance number of mPIPE shim to be controlled via
+ *  context.
+ */
+extern int gxio_mpipe_init(gxio_mpipe_context_t *context,
+			   unsigned int mpipe_instance);
+
+/* Destroy an mPIPE context.
+ *
+ * This function frees the mPIPE "service domain" and unmaps the MMIO
+ * registers from the caller's VA space.
+ *
+ * If a user process exits without calling this routine, the kernel
+ * will destroy the mPIPE context as part of process teardown.
+ *
+ * @param context Context object to be destroyed.
+ */
+extern int gxio_mpipe_destroy(gxio_mpipe_context_t *context);
+
+/*****************************************************************
+ *                         Buffer Stacks                          *
+ ******************************************************************/
+
+/* Allocate a set of buffer stacks.
+ *
+ * The return value is NOT interesting if count is zero.
+ *
+ * @param context An initialized mPIPE context.
+ * @param count Number of stacks required.
+ * @param first Index of first stack if ::GXIO_MPIPE_ALLOC_FIXED flag is set,
+ *   otherwise ignored.
+ * @param flags Flag bits from ::gxio_mpipe_alloc_flags_e.
+ * @return Index of first allocated buffer stack, or
+ * ::GXIO_MPIPE_ERR_NO_BUFFER_STACK if allocation failed.
+ */
+extern int gxio_mpipe_alloc_buffer_stacks(gxio_mpipe_context_t *context,
+					  unsigned int count,
+					  unsigned int first,
+					  unsigned int flags);
+
+/* Enum codes for buffer sizes supported by mPIPE. */
+typedef enum {
+	/* 128 byte packet data buffer. */
+	GXIO_MPIPE_BUFFER_SIZE_128 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_128,
+	/* 256 byte packet data buffer. */
+	GXIO_MPIPE_BUFFER_SIZE_256 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_256,
+	/* 512 byte packet data buffer. */
+	GXIO_MPIPE_BUFFER_SIZE_512 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_512,
+	/* 1024 byte packet data buffer. */
+	GXIO_MPIPE_BUFFER_SIZE_1024 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_1024,
+	/* 1664 byte packet data buffer. */
+	GXIO_MPIPE_BUFFER_SIZE_1664 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_1664,
+	/* 4096 byte packet data buffer. */
+	GXIO_MPIPE_BUFFER_SIZE_4096 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_4096,
+	/* 10368 byte packet data buffer. */
+	GXIO_MPIPE_BUFFER_SIZE_10368 =
+		MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_10368,
+	/* 16384 byte packet data buffer. */
+	GXIO_MPIPE_BUFFER_SIZE_16384 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_16384
+} gxio_mpipe_buffer_size_enum_t;
+
+/* Convert a buffer size in bytes into a buffer size enum. */
+extern gxio_mpipe_buffer_size_enum_t
+gxio_mpipe_buffer_size_to_buffer_size_enum(size_t size);
+
+/* Convert a buffer size enum into a buffer size in bytes. */
+extern size_t
+gxio_mpipe_buffer_size_enum_to_buffer_size(gxio_mpipe_buffer_size_enum_t
+					   buffer_size_enum);
+
+/* Calculate the number of bytes required to store a given number of
+ * buffers in the memory registered with a buffer stack via
+ * gxio_mpipe_init_buffer_stack().
+ */
+extern size_t gxio_mpipe_calc_buffer_stack_bytes(unsigned long buffers);
+
+/* Initialize a buffer stack.  This function binds a region of memory
+ * to be used by the hardware for storing buffer addresses pushed via
+ * gxio_mpipe_push_buffer() or as the result of sending a buffer out
+ * the egress with the 'push to stack when done' bit set.  Once this
+ * function returns, the memory region's contents may be arbitrarily
+ * modified by the hardware at any time and software should not access
+ * the memory region again.
+ *
+ * @param context An initialized mPIPE context.
+ * @param stack The buffer stack index.
+ * @param buffer_size_enum The size of each buffer in the buffer stack,
+ * as an enum.
+ * @param mem The address of the buffer stack.  This memory must be
+ * physically contiguous and aligned to a 64kB boundary.
+ * @param mem_size The size of the buffer stack, in bytes.
+ * @param mem_flags ::gxio_mpipe_mem_flags_e memory flags.
+ * @return Zero on success, ::GXIO_MPIPE_ERR_INVAL_BUFFER_SIZE if
+ * buffer_size_enum is invalid, ::GXIO_MPIPE_ERR_BAD_BUFFER_STACK if
+ * stack has not been allocated.
+ */
+extern int gxio_mpipe_init_buffer_stack(gxio_mpipe_context_t *context,
+					unsigned int stack,
+					gxio_mpipe_buffer_size_enum_t
+					buffer_size_enum, void *mem,
+					size_t mem_size,
+					unsigned int mem_flags);
+
+/* Push a buffer onto a previously initialized buffer stack.
+ *
+ * The size of the buffer being pushed must match the size that was
+ * registered with gxio_mpipe_init_buffer_stack().  All packet buffer
+ * addresses are 128-byte aligned; the low 7 bits of the specified
+ * buffer address will be ignored.
+ *
+ * @param context An initialized mPIPE context.
+ * @param stack The buffer stack index.
+ * @param buffer The buffer (the low seven bits are ignored).
+ */
+static inline void gxio_mpipe_push_buffer(gxio_mpipe_context_t *context,
+					  unsigned int stack, void *buffer)
+{
+	MPIPE_BSM_REGION_ADDR_t offset = { {0} };
+	MPIPE_BSM_REGION_VAL_t val = { {0} };
+
+	/*
+	 * The mmio_fast_base region starts at the IDMA region, so subtract
+	 * off that initial offset.
+	 */
+	offset.region =
+		MPIPE_MMIO_ADDR__REGION_VAL_BSM -
+		MPIPE_MMIO_ADDR__REGION_VAL_IDMA;
+	offset.stack = stack;
+
+#if __SIZEOF_POINTER__ == 4
+	val.va = ((ulong) buffer) >> MPIPE_BSM_REGION_VAL__VA_SHIFT;
+#else
+	val.va = ((long)buffer) >> MPIPE_BSM_REGION_VAL__VA_SHIFT;
+#endif
+
+	__gxio_mmio_write(context->mmio_fast_base + offset.word, val.word);
+}
+
+/* Pop a buffer off of a previously initialized buffer stack.
+ *
+ * @param context An initialized mPIPE context.
+ * @param stack The buffer stack index.
+ * @return The buffer, or NULL if the stack is empty.
+ */
+static inline void *gxio_mpipe_pop_buffer(gxio_mpipe_context_t *context,
+					  unsigned int stack)
+{
+	MPIPE_BSM_REGION_ADDR_t offset = { {0} };
+
+	/*
+	 * The mmio_fast_base region starts at the IDMA region, so subtract
+	 * off that initial offset.
+	 */
+	offset.region =
+		MPIPE_MMIO_ADDR__REGION_VAL_BSM -
+		MPIPE_MMIO_ADDR__REGION_VAL_IDMA;
+	offset.stack = stack;
+
+	while (1) {
+		/*
+		 * Case 1: val.c == ..._UNCHAINED, va is non-zero.
+		 * Case 2: val.c == ..._INVALID, va is zero.
+		 * Case 3: val.c == ..._NOT_RDY, va is zero.
+		 */
+		MPIPE_BSM_REGION_VAL_t val;
+		val.word =
+			__gxio_mmio_read(context->mmio_fast_base +
+					 offset.word);
+
+		/*
+		 * Handle case 1 and 2 by returning the buffer (or NULL).
+		 * Handle case 3 by waiting for the prefetch buffer to refill.
+		 */
+		if (val.c != MPIPE_EDMA_DESC_WORD1__C_VAL_NOT_RDY)
+			return (void *)((unsigned long)val.
+					va << MPIPE_BSM_REGION_VAL__VA_SHIFT);
+	}
+}
+
+/*****************************************************************
+ *                          NotifRings                            *
+ ******************************************************************/
+
+/* Allocate a set of NotifRings.
+ *
+ * The return value is NOT interesting if count is zero.
+ *
+ * Note that NotifRings are allocated in chunks, so allocating one at
+ * a time is much less efficient than allocating several at once.
+ *
+ * @param context An initialized mPIPE context.
+ * @param count Number of NotifRings required.
+ * @param first Index of first NotifRing if ::GXIO_MPIPE_ALLOC_FIXED flag
+ *   is set, otherwise ignored.
+ * @param flags Flag bits from ::gxio_mpipe_alloc_flags_e.
+ * @return Index of first allocated buffer NotifRing, or
+ * ::GXIO_MPIPE_ERR_NO_NOTIF_RING if allocation failed.
+ */
+extern int gxio_mpipe_alloc_notif_rings(gxio_mpipe_context_t *context,
+					unsigned int count, unsigned int first,
+					unsigned int flags);
+
+/* Initialize a NotifRing, using the given memory and size.
+ *
+ * @param context An initialized mPIPE context.
+ * @param ring The NotifRing index.
+ * @param mem A physically contiguous region of memory to be filled
+ * with a ring of ::gxio_mpipe_idesc_t structures.
+ * @param mem_size Number of bytes in the ring.  Must be 128, 512,
+ * 2048, or 65536 * sizeof(gxio_mpipe_idesc_t).
+ * @param mem_flags ::gxio_mpipe_mem_flags_e memory flags.
+ *
+ * @return 0 on success, ::GXIO_MPIPE_ERR_BAD_NOTIF_RING or
+ * ::GXIO_ERR_INVAL_MEMORY_SIZE on failure.
+ */
+extern int gxio_mpipe_init_notif_ring(gxio_mpipe_context_t *context,
+				      unsigned int ring,
+				      void *mem, size_t mem_size,
+				      unsigned int mem_flags);
+
+/* Configure an interrupt to be sent to a tile on incoming NotifRing
+ *  traffic.  Once an interrupt is sent for a particular ring, no more
+ *  will be sent until gxio_mica_enable_notif_ring_interrupt() is called.
+ *
+ * @param context An initialized mPIPE context.
+ * @param x X coordinate of interrupt target tile.
+ * @param y Y coordinate of interrupt target tile.
+ * @param i Index of the IPI register which will receive the interrupt.
+ * @param e Specific event which will be set in the target IPI register when
+ * the interrupt occurs.
+ * @param ring The NotifRing index.
+ * @return Zero on success, GXIO_ERR_INVAL if params are out of range.
+ */
+extern int gxio_mpipe_request_notif_ring_interrupt(gxio_mpipe_context_t
+						   *context, int x, int y,
+						   int i, int e,
+						   unsigned int ring);
+
+/* Enable an interrupt on incoming NotifRing traffic.
+ *
+ * @param context An initialized mPIPE context.
+ * @param ring The NotifRing index.
+ * @return Zero on success, GXIO_ERR_INVAL if params are out of range.
+ */
+extern int gxio_mpipe_enable_notif_ring_interrupt(gxio_mpipe_context_t
+						  *context, unsigned int ring);
+
+/* Map all of a client's memory via the given IOTLB.
+ * @param context An initialized mPIPE context.
+ * @param iotlb IOTLB index.
+ * @param pte Page table entry.
+ * @param flags Flags.
+ * @return Zero on success, or a negative error code.
+ */
+extern int gxio_mpipe_register_client_memory(gxio_mpipe_context_t *context,
+					     unsigned int iotlb, HV_PTE pte,
+					     unsigned int flags);
+
+/*****************************************************************
+ *                        Notif Groups                            *
+ ******************************************************************/
+
+/* Allocate a set of NotifGroups.
+ *
+ * The return value is NOT interesting if count is zero.
+ *
+ * @param context An initialized mPIPE context.
+ * @param count Number of NotifGroups required.
+ * @param first Index of first NotifGroup if ::GXIO_MPIPE_ALLOC_FIXED flag
+ *   is set, otherwise ignored.
+ * @param flags Flag bits from ::gxio_mpipe_alloc_flags_e.
+ * @return Index of first allocated buffer NotifGroup, or
+ * ::GXIO_MPIPE_ERR_NO_NOTIF_GROUP if allocation failed.
+ */
+extern int gxio_mpipe_alloc_notif_groups(gxio_mpipe_context_t *context,
+					 unsigned int count,
+					 unsigned int first,
+					 unsigned int flags);
+
+/* Add a NotifRing to a NotifGroup.  This only sets a bit in the
+ * application's 'group' object; the hardware NotifGroup can be
+ * initialized by passing 'group' to gxio_mpipe_init_notif_group() or
+ * gxio_mpipe_init_notif_group_and_buckets().
+ */
+static inline void
+gxio_mpipe_notif_group_add_ring(gxio_mpipe_notif_group_bits_t *bits, int ring)
+{
+	bits->ring_mask[ring / 64] |= (1ull << (ring % 64));
+}
+
+/* Set a particular NotifGroup bitmask.  Since the load balancer
+ * makes decisions based on both bucket and NotifGroup state, most
+ * applications should use gxio_mpipe_init_notif_group_and_buckets()
+ * rather than using this function to configure just a NotifGroup.
+ */
+extern int gxio_mpipe_init_notif_group(gxio_mpipe_context_t *context,
+				       unsigned int group,
+				       gxio_mpipe_notif_group_bits_t bits);
+
+/*****************************************************************
+ *                         Load Balancer                          *
+ ******************************************************************/
+
+/* Allocate a set of load balancer buckets.
+ *
+ * The return value is NOT interesting if count is zero.
+ *
+ * Note that buckets are allocated in chunks, so allocating one at
+ * a time is much less efficient than allocating several at once.
+ *
+ * Note that the buckets are actually divided into two sub-ranges, of
+ * different sizes, and different chunk sizes, and the range you get
+ * by default is determined by the size of the request.  Allocations
+ * cannot span the two sub-ranges.
+ *
+ * @param context An initialized mPIPE context.
+ * @param count Number of buckets required.
+ * @param first Index of first bucket if ::GXIO_MPIPE_ALLOC_FIXED flag is set,
+ *   otherwise ignored.
+ * @param flags Flag bits from ::gxio_mpipe_alloc_flags_e.
+ * @return Index of first allocated buffer bucket, or
+ * ::GXIO_MPIPE_ERR_NO_BUCKET if allocation failed.
+ */
+extern int gxio_mpipe_alloc_buckets(gxio_mpipe_context_t *context,
+				    unsigned int count, unsigned int first,
+				    unsigned int flags);
+
+/* The legal modes for gxio_mpipe_bucket_info_t and
+ * gxio_mpipe_init_notif_group_and_buckets().
+ *
+ * All modes except ::GXIO_MPIPE_BUCKET_ROUND_ROBIN expect that the user
+ * will allocate a power-of-two number of buckets and initialize them
+ * to the same mode.  The classifier program then uses the appropriate
+ * number of low bits from the incoming packet's flow hash to choose a
+ * load balancer bucket.  Based on that bucket's load balancing mode,
+ * reference count, and currently active NotifRing, the load balancer
+ * chooses the NotifRing to which the packet will be delivered.
+ */
+typedef enum {
+	/* All packets for a bucket go to the same NotifRing unless the
+	 * NotifRing gets full, in which case packets will be dropped.  If
+	 * the bucket reference count ever reaches zero, a new NotifRing may
+	 * be chosen.
+	 */
+	GXIO_MPIPE_BUCKET_DYNAMIC_FLOW_AFFINITY =
+		MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_DFA,
+
+	/* All packets for a bucket always go to the same NotifRing.
+	 */
+	GXIO_MPIPE_BUCKET_STATIC_FLOW_AFFINITY =
+		MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_FIXED,
+
+	/* All packets for a bucket go to the least full NotifRing in the
+	 * group, providing load balancing round robin behavior.
+	 */
+	GXIO_MPIPE_BUCKET_ROUND_ROBIN =
+		MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_ALWAYS_PICK,
+
+	/* All packets for a bucket go to the same NotifRing unless the
+	 * NotifRing gets full, at which point the bucket starts using the
+	 * least full NotifRing in the group.  If all NotifRings in the
+	 * group are full, packets will be dropped.
+	 */
+	GXIO_MPIPE_BUCKET_STICKY_FLOW_LOCALITY =
+		MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_STICKY,
+
+	/* All packets for a bucket go to the same NotifRing unless the
+	 * NotifRing gets full, or a random timer fires, at which point the
+	 * bucket starts using the least full NotifRing in the group.  If
+	 * all NotifRings in the group are full, packets will be dropped.
+	 * WARNING: This mode is BROKEN on chips with fewer than 64 tiles.
+	 */
+	GXIO_MPIPE_BUCKET_PREFER_FLOW_LOCALITY =
+		MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_STICKY_RAND,
+
+} gxio_mpipe_bucket_mode_t;
+
+/* Copy a set of bucket initialization values into the mPIPE
+ * hardware.  Since the load balancer makes decisions based on both
+ * bucket and NotifGroup state, most applications should use
+ * gxio_mpipe_init_notif_group_and_buckets() rather than using this
+ * function to configure a single bucket.
+ *
+ * @param context An initialized mPIPE context.
+ * @param bucket Bucket index to be initialized.
+ * @param bucket_info Initial reference count, NotifRing index, and mode.
+ * @return 0 on success, ::GXIO_MPIPE_ERR_BAD_BUCKET on failure.
+ */
+extern int gxio_mpipe_init_bucket(gxio_mpipe_context_t *context,
+				  unsigned int bucket,
+				  gxio_mpipe_bucket_info_t bucket_info);
+
+/* Initializes a group and range of buckets and range of rings such
+ * that the load balancer runs a particular load balancing function.
+ *
+ * First, the group is initialized with the given rings.
+ *
+ * Second, each bucket is initialized with the mode and group, and a
+ * ring chosen round-robin from the given rings.
+ *
+ * Normally, the classifier picks a bucket, and then the load balancer
+ * picks a ring, based on the bucket's mode, group, and current ring,
+ * possibly updating the bucket's ring.
+ *
+ * @param context An initialized mPIPE context.
+ * @param group The group.
+ * @param ring The first ring.
+ * @param num_rings The number of rings.
+ * @param bucket The first bucket.
+ * @param num_buckets The number of buckets.
+ * @param mode The load balancing mode.
+ *
+ * @return 0 on success, ::GXIO_MPIPE_ERR_BAD_BUCKET,
+ * ::GXIO_MPIPE_ERR_BAD_NOTIF_GROUP, or
+ * ::GXIO_MPIPE_ERR_BAD_NOTIF_RING on failure.
+ */
+extern int gxio_mpipe_init_notif_group_and_buckets(gxio_mpipe_context_t
+						   *context,
+						   unsigned int group,
+						   unsigned int ring,
+						   unsigned int num_rings,
+						   unsigned int bucket,
+						   unsigned int num_buckets,
+						   gxio_mpipe_bucket_mode_t
+						   mode);
+
+/* Return credits to a NotifRing and/or bucket.
+ *
+ * @param context An initialized mPIPE context.
+ * @param ring The NotifRing index, or -1.
+ * @param bucket The bucket, or -1.
+ * @param count The number of credits to return.
+ */
+static inline void gxio_mpipe_credit(gxio_mpipe_context_t *context,
+				     int ring, int bucket, unsigned int count)
+{
+	/* NOTE: Fancy struct initialization would break "C89" header test. */
+
+	MPIPE_IDMA_RELEASE_REGION_ADDR_t offset = { {0} };
+	MPIPE_IDMA_RELEASE_REGION_VAL_t val = { {0} };
+
+	/*
+	 * The mmio_fast_base region starts at the IDMA region, so subtract
+	 * off that initial offset.
+	 */
+	offset.region =
+		MPIPE_MMIO_ADDR__REGION_VAL_IDMA -
+		MPIPE_MMIO_ADDR__REGION_VAL_IDMA;
+	offset.ring = ring;
+	offset.bucket = bucket;
+	offset.ring_enable = (ring >= 0);
+	offset.bucket_enable = (bucket >= 0);
+	val.count = count;
+
+	__gxio_mmio_write(context->mmio_fast_base + offset.word, val.word);
+}
+
+/*****************************************************************
+ *                         Egress Rings                           *
+ ******************************************************************/
+
+/* Allocate a set of eDMA rings.
+ *
+ * The return value is NOT interesting if count is zero.
+ *
+ * @param context An initialized mPIPE context.
+ * @param count Number of eDMA rings required.
+ * @param first Index of first eDMA ring if ::GXIO_MPIPE_ALLOC_FIXED flag
+ *   is set, otherwise ignored.
+ * @param flags Flag bits from ::gxio_mpipe_alloc_flags_e.
+ * @return Index of first allocated buffer eDMA ring, or
+ * ::GXIO_MPIPE_ERR_NO_EDMA_RING if allocation failed.
+ */
+extern int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t *context,
+				       unsigned int count, unsigned int first,
+				       unsigned int flags);
+
+/* Initialize an eDMA ring, using the given memory and size.
+ *
+ * @param context An initialized mPIPE context.
+ * @param ring The eDMA ring index.
+ * @param channel The channel to use.  This must be one of the channels
+ * associated with the context's set of open links.
+ * @param mem A physically contiguous region of memory to be filled
+ * with a ring of ::gxio_mpipe_edesc_t structures.
+ * @param mem_size Number of bytes in the ring.  Must be 512, 2048,
+ * 8192 or 65536, times 16 (i.e. sizeof(gxio_mpipe_edesc_t)).
+ * @param mem_flags ::gxio_mpipe_mem_flags_e memory flags.
+ *
+ * @return 0 on success, ::GXIO_MPIPE_ERR_BAD_EDMA_RING or
+ * ::GXIO_ERR_INVAL_MEMORY_SIZE on failure.
+ */
+extern int gxio_mpipe_init_edma_ring(gxio_mpipe_context_t *context,
+				     unsigned int ring, unsigned int channel,
+				     void *mem, size_t mem_size,
+				     unsigned int mem_flags);
+
+/*****************************************************************
+ *                      Classifier Program                        *
+ ******************************************************************/
+
+/*
+ *
+ * Functions for loading or configuring the mPIPE classifier program.
+ *
+ * The mPIPE classification processors all run a special "classifier"
+ * program which, for each incoming packet, parses the packet headers,
+ * encodes some packet metadata in the "idesc", and either drops the
+ * packet, or picks a notif ring to handle the packet, and a buffer
+ * stack to contain the packet, usually based on the channel, VLAN,
+ * dMAC, flow hash, and packet size, under the guidance of the "rules"
+ * API described below.
+ *
+ * @section gxio_mpipe_classifier_default Default Classifier
+ *
+ * The MDE provides a simple "default" classifier program.  It is
+ * shipped as source in "$TILERA_ROOT/src/sys/mpipe/classifier.c",
+ * which serves as its official documentation.  It is shipped as a
+ * binary program in "$TILERA_ROOT/tile/boot/classifier", which is
+ * automatically included in bootroms created by "tile-monitor", and
+ * is automatically loaded by the hypervisor at boot time.
+ *
+ * The L2 analysis handles LLC packets, SNAP packets, and "VLAN
+ * wrappers" (keeping the outer VLAN).
+ *
+ * The L3 analysis handles IPv4 and IPv6, dropping packets with bad
+ * IPv4 header checksums, requesting computation of a TCP/UDP checksum
+ * if appropriate, and hashing the dest and src IP addresses, plus the
+ * ports for TCP/UDP packets, into the flow hash.  No special analysis
+ * is done for "fragmented" packets or "tunneling" protocols.  Thus,
+ * the first fragment of a fragmented TCP/UDP packet is hashed using
+ * src/dest IP address and ports and all subsequent fragments are only
+ * hashed according to src/dest IP address.
+ *
+ * The L3 analysis handles other packets too, hashing the dMAC
+ * smac into a flow hash.
+ *
+ * The channel, VLAN, and dMAC used to pick a "rule" (see the
+ * "rules" APIs below), which in turn is used to pick a buffer stack
+ * (based on the packet size) and a bucket (based on the flow hash).
+ *
+ * To receive traffic matching a particular (channel/VLAN/dMAC
+ * pattern, an application should allocate its own buffer stacks and
+ * load balancer buckets, and map traffic to those stacks and buckets,
+ * as decribed by the "rules" API below.
+ *
+ * Various packet metadata is encoded in the idesc.  The flow hash is
+ * four bytes at 0x0C.  The VLAN is two bytes at 0x10.  The ethtype is
+ * two bytes at 0x12.  The l3 start is one byte at 0x14.  The l4 start
+ * is one byte at 0x15 for IPv4 and IPv6 packets, and otherwise zero.
+ * The protocol is one byte at 0x16 for IPv4 and IPv6 packets, and
+ * otherwise zero.
+ *
+ * @section gxio_mpipe_classifier_custom Custom Classifiers.
+ *
+ * A custom classifier may be created using "tile-mpipe-cc" with a
+ * customized version of the default classifier sources.
+ *
+ * The custom classifier may be included in bootroms using the
+ * "--classifier" option to "tile-monitor", or loaded dynamically
+ * using gxio_mpipe_classifier_load_from_file().
+ *
+ * Be aware that "extreme" customizations may break the assumptions of
+ * the "rules" APIs described below, but simple customizations, such
+ * as adding new packet metadata, should be fine.
+ */
+
+/* A set of classifier rules, plus a context. */
+typedef struct {
+
+	/* The context. */
+	gxio_mpipe_context_t *context;
+
+	/* The actual rules. */
+	gxio_mpipe_rules_list_t list;
+
+} gxio_mpipe_rules_t;
+
+/* Initialize a classifier program rules list.
+ *
+ * This function can be called on a previously initialized rules list
+ * to discard any previously added rules.
+ *
+ * @param rules Rules list to initialize.
+ * @param context An initialized mPIPE context.
+ */
+extern void gxio_mpipe_rules_init(gxio_mpipe_rules_t *rules,
+				  gxio_mpipe_context_t *context);
+
+/* Begin a new rule on the indicated rules list.
+ *
+ * Note that an empty rule matches all packets, but an empty rule list
+ * matches no packets.
+ *
+ * @param rules Rules list to which new rule is appended.
+ * @param bucket First load balancer bucket to which packets will be
+ * delivered.
+ * @param num_buckets Number of buckets (must be a power of two) across
+ * which packets will be distributed based on the "flow hash".
+ * @param stacks Either NULL, to assign each packet to the smallest
+ * initialized buffer stack which does not induce chaining (and to
+ * drop packets which exceed the largest initialized buffer stack
+ * buffer size), or an array, with each entry indicating which buffer
+ * stack should be used for packets up to that size (with 255
+ * indicating that those packets should be dropped).
+ * @return 0 on success, or a negative error code on failure.
+ */
+extern int gxio_mpipe_rules_begin(gxio_mpipe_rules_t *rules,
+				  unsigned int bucket,
+				  unsigned int num_buckets,
+				  gxio_mpipe_rules_stacks_t *stacks);
+
+/* Set the headroom of the current rule.
+ *
+ * @param rules Rules list whose current rule will be modified.
+ * @param headroom The headroom.
+ * @return 0 on success, or a negative error code on failure.
+ */
+extern int gxio_mpipe_rules_set_headroom(gxio_mpipe_rules_t *rules,
+					 uint8_t headroom);
+
+/* Indicate that packets from a particular channel can be delivered
+ * to the buckets and buffer stacks associated with the current rule.
+ *
+ * Channels added must be associated with links opened by the mPIPE context
+ * used in gxio_mpipe_rules_init().  A rule with no channels is equivalent
+ * to a rule naming all such associated channels.
+ *
+ * @param rules Rules list whose current rule will be modified.
+ * @param channel The channel to add.
+ * @return 0 on success, or a negative error code on failure.
+ */
+extern int gxio_mpipe_rules_add_channel(gxio_mpipe_rules_t *rules,
+					unsigned int channel);
+
+/* Commit rules.
+ *
+ * The rules are sent to the hypervisor, where they are combined with
+ * the rules from other apps, and used to program the hardware classifier.
+ *
+ * Note that if this function returns an error, then the rules will NOT
+ * have been committed, even if the error is due to interactions with
+ * rules from another app.
+ *
+ * @param rules Rules list to commit.
+ * @return 0 on success, or a negative error code on failure.
+ */
+extern int gxio_mpipe_rules_commit(gxio_mpipe_rules_t *rules);
+
+/*****************************************************************
+ *                     Ingress Queue Wrapper                      *
+ ******************************************************************/
+
+/*
+ *
+ * Convenience functions for receiving packets from a NotifRing and
+ * sending packets via an eDMA ring.
+ *
+ * The mpipe ingress and egress hardware uses shared memory packet
+ * descriptors to describe packets that have arrived on ingress or
+ * are destined for egress.  These descriptors are stored in shared
+ * memory ring buffers and written or read by hardware as necessary.
+ * The gxio library provides wrapper functions that manage the head and
+ * tail pointers for these rings, allowing the user to easily read or
+ * write packet descriptors.
+ *
+ * The initialization interface for ingress and egress rings is quite
+ * similar.  For example, to create an ingress queue, the user passes
+ * a ::gxio_mpipe_iqueue_t state object, a ring number from
+ * gxio_mpipe_alloc_notif_rings(), and the address of memory to hold a
+ * ring buffer to the gxio_mpipe_iqueue_init() function.  The function
+ * returns success when the state object has been initialized and the
+ * hardware configured to deliver packets to the specified ring
+ * buffer.  Similarly, gxio_mpipe_equeue_init() takes a
+ * ::gxio_mpipe_equeue_t state object, a ring number from
+ * gxio_mpipe_alloc_edma_rings(), and a shared memory buffer.
+ *
+ * @section gxio_mpipe_iqueue Working with Ingress Queues
+ *
+ * Once initialized, the gxio_mpipe_iqueue_t API provides two flows
+ * for getting the ::gxio_mpipe_idesc_t packet descriptor associated
+ * with incoming packets.  The simplest is to call
+ * gxio_mpipe_iqueue_get() or gxio_mpipe_iqueue_try_get().  These
+ * functions copy the oldest packet descriptor out of the NotifRing and
+ * into a descriptor provided by the caller.  They also immediately
+ * inform the hardware that a descriptor has been processed.
+ *
+ * For applications with stringent performance requirements, higher
+ * efficiency can be achieved by avoiding the packet descriptor copy
+ * and processing multiple descriptors at once.  The
+ * gxio_mpipe_iqueue_peek() and gxio_mpipe_iqueue_try_peek() functions
+ * allow such optimizations.  These functions provide a pointer to the
+ * next valid ingress descriptor in the NotifRing's shared memory ring
+ * buffer, and a count of how many contiguous descriptors are ready to
+ * be processed.  The application can then process any number of those
+ * descriptors in place, calling gxio_mpipe_iqueue_consume() to inform
+ * the hardware after each one has been processed.
+ *
+ * @section gxio_mpipe_equeue Working with Egress Queues
+ *
+ * Similarly, the egress queue API provides a high-performance
+ * interface plus a simple wrapper for use in posting
+ * ::gxio_mpipe_edesc_t egress packet descriptors.  The simple
+ * version, gxio_mpipe_equeue_put(), allows the programmer to wait for
+ * an eDMA ring slot to become available and write a single descriptor
+ * into the ring.
+ *
+ * Alternatively, you can reserve slots in the eDMA ring using
+ * gxio_mpipe_equeue_reserve() or gxio_mpipe_equeue_try_reserve(), and
+ * then fill in each slot using gxio_mpipe_equeue_put_at().  This
+ * capability can be used to amortize the cost of reserving slots
+ * across several packets.  It also allows gather operations to be
+ * performed on a shared equeue, by ensuring that the edescs for all
+ * the fragments are all contiguous in the eDMA ring.
+ *
+ * The gxio_mpipe_equeue_reserve() and gxio_mpipe_equeue_try_reserve()
+ * functions return a 63-bit "completion slot", which is actually a
+ * sequence number, the low bits of which indicate the ring buffer
+ * index and the high bits the number of times the application has
+ * gone around the egress ring buffer.  The extra bits allow an
+ * application to check for egress completion by calling
+ * gxio_mpipe_equeue_is_complete() to see whether a particular 'slot'
+ * number has finished.  Given the maximum packet rates of the Gx
+ * processor, the 63-bit slot number will never wrap.
+ *
+ * In practice, most applications use the ::gxio_mpipe_edesc_t::hwb
+ * bit to indicate that the buffers containing egress packet data
+ * should be pushed onto a buffer stack when egress is complete.  Such
+ * applications generally do not need to know when an egress operation
+ * completes (since there is no need to free a buffer post-egress),
+ * and thus can use the optimized gxio_mpipe_equeue_reserve_fast() or
+ * gxio_mpipe_equeue_try_reserve_fast() functions, which return a 24
+ * bit "slot", instead of a 63-bit "completion slot".
+ *
+ * Once a slot has been "reserved", it MUST be filled.  If the
+ * application reserves a slot and then decides that it does not
+ * actually need it, it can set the ::gxio_mpipe_edesc_t::ns (no send)
+ * bit on the descriptor passed to gxio_mpipe_equeue_put_at() to
+ * indicate that no data should be sent.  This technique can also be
+ * used to drop an incoming packet, instead of forwarding it, since
+ * any buffer will still be pushed onto the buffer stack when the
+ * egress descriptor is processed.
+ */
+
+/* A convenient interface to a NotifRing, for use by a single thread.
+ */
+typedef struct {
+
+	/* The context. */
+	gxio_mpipe_context_t *context;
+
+	/* The actual NotifRing. */
+	gxio_mpipe_idesc_t *idescs;
+
+	/* The number of entries. */
+	unsigned long num_entries;
+
+	/* The number of entries minus one. */
+	unsigned long mask_num_entries;
+
+	/* The log2() of the number of entries. */
+	unsigned long log2_num_entries;
+
+	/* The next entry. */
+	unsigned int head;
+
+	/* The NotifRing id. */
+	unsigned int ring;
+
+#ifdef __BIG_ENDIAN__
+	/* The number of byteswapped entries. */
+	unsigned int swapped;
+#endif
+
+} gxio_mpipe_iqueue_t;
+
+/* Initialize an "iqueue".
+ *
+ * Takes the iqueue plus the same args as gxio_mpipe_init_notif_ring().
+ */
+extern int gxio_mpipe_iqueue_init(gxio_mpipe_iqueue_t *iqueue,
+				  gxio_mpipe_context_t *context,
+				  unsigned int ring,
+				  void *mem, size_t mem_size,
+				  unsigned int mem_flags);
+
+/* Advance over some old entries in an iqueue.
+ *
+ * Please see the documentation for gxio_mpipe_iqueue_consume().
+ *
+ * @param iqueue An ingress queue initialized via gxio_mpipe_iqueue_init().
+ * @param count The number of entries to advance over.
+ */
+static inline void gxio_mpipe_iqueue_advance(gxio_mpipe_iqueue_t *iqueue,
+					     int count)
+{
+	/* Advance with proper wrap. */
+	int head = iqueue->head + count;
+	iqueue->head =
+		(head & iqueue->mask_num_entries) +
+		(head >> iqueue->log2_num_entries);
+
+#ifdef __BIG_ENDIAN__
+	/* HACK: Track swapped entries. */
+	iqueue->swapped -= count;
+#endif
+}
+
+/* Release the ring and bucket for an old entry in an iqueue.
+ *
+ * Releasing the ring allows more packets to be delivered to the ring.
+ *
+ * Releasing the bucket allows flows using the bucket to be moved to a
+ * new ring when using GXIO_MPIPE_BUCKET_DYNAMIC_FLOW_AFFINITY.
+ *
+ * This function is shorthand for "gxio_mpipe_credit(iqueue->context,
+ * iqueue->ring, idesc->bucket_id, 1)", and it may be more convenient
+ * to make that underlying call, using those values, instead of
+ * tracking the entire "idesc".
+ *
+ * If packet processing is deferred, optimal performance requires that
+ * the releasing be deferred as well.
+ *
+ * Please see the documentation for gxio_mpipe_iqueue_consume().
+ *
+ * @param iqueue An ingress queue initialized via gxio_mpipe_iqueue_init().
+ * @param idesc The descriptor which was processed.
+ */
+static inline void gxio_mpipe_iqueue_release(gxio_mpipe_iqueue_t *iqueue,
+					     gxio_mpipe_idesc_t *idesc)
+{
+	gxio_mpipe_credit(iqueue->context, iqueue->ring, idesc->bucket_id, 1);
+}
+
+/* Consume a packet from an "iqueue".
+ *
+ * After processing packets peeked at via gxio_mpipe_iqueue_peek()
+ * or gxio_mpipe_iqueue_try_peek(), you must call this function, or
+ * gxio_mpipe_iqueue_advance() plus gxio_mpipe_iqueue_release(), to
+ * advance over those entries, and release their rings and buckets.
+ *
+ * You may call this function as each packet is processed, or you can
+ * wait until several packets have been processed.
+ *
+ * Note that if you are using a single bucket, and you are handling
+ * batches of N packets, then you can replace several calls to this
+ * function with calls to "gxio_mpipe_iqueue_advance(iqueue, N)" and
+ * "gxio_mpipe_credit(iqueue->context, iqueue->ring, bucket, N)".
+ *
+ * Note that if your classifier sets "idesc->nr", then you should
+ * explicitly call "gxio_mpipe_iqueue_advance(iqueue, idesc)" plus
+ * "gxio_mpipe_credit(iqueue->context, iqueue->ring, -1, 1)", to
+ * avoid incorrectly crediting the (unused) bucket.
+ *
+ * @param iqueue An ingress queue initialized via gxio_mpipe_iqueue_init().
+ * @param idesc The descriptor which was processed.
+ */
+static inline void gxio_mpipe_iqueue_consume(gxio_mpipe_iqueue_t *iqueue,
+					     gxio_mpipe_idesc_t *idesc)
+{
+	gxio_mpipe_iqueue_advance(iqueue, 1);
+	gxio_mpipe_iqueue_release(iqueue, idesc);
+}
+
+/* Peek at the next packet(s) in an "iqueue", without waiting.
+ *
+ * If no packets are available, fills idesc_ref with NULL, and then
+ * returns ::GXIO_MPIPE_ERR_IQUEUE_EMPTY.  Otherwise, fills idesc_ref
+ * with the address of the next valid packet descriptor, and returns
+ * the maximum number of valid descriptors which can be processed.
+ * You may process fewer descriptors if desired.
+ *
+ * Call gxio_mpipe_iqueue_consume() on each packet once it has been
+ * processed (or dropped), to allow more packets to be delivered.
+ *
+ * @param iqueue An ingress queue initialized via gxio_mpipe_iqueue_init().
+ * @param idesc_ref A pointer to a packet descriptor pointer.
+ * @return The (positive) number of packets which can be processed,
+ * or ::GXIO_MPIPE_ERR_IQUEUE_EMPTY if no packets are available.
+ */
+static inline int gxio_mpipe_iqueue_try_peek(gxio_mpipe_iqueue_t *iqueue,
+					     gxio_mpipe_idesc_t **idesc_ref)
+{
+	gxio_mpipe_idesc_t *next;
+
+	uint64_t head = iqueue->head;
+	uint64_t tail = __gxio_mmio_read(iqueue->idescs);
+
+	/* Available entries. */
+	uint64_t avail =
+		(tail >= head) ? (tail - head) : (iqueue->num_entries - head);
+
+	if (avail == 0) {
+		*idesc_ref = NULL;
+		return GXIO_MPIPE_ERR_IQUEUE_EMPTY;
+	}
+
+	next = &iqueue->idescs[head];
+
+	/* ISSUE: Is this helpful? */
+	__insn_prefetch(next);
+
+#ifdef __BIG_ENDIAN__
+	/* HACK: Swap new entries directly in memory. */
+	{
+		int i, j;
+		for (i = iqueue->swapped; i < avail; i++) {
+			for (j = 0; j < 8; j++)
+				next[i].words[j] =
+					__builtin_bswap64(next[i].words[j]);
+		}
+		iqueue->swapped = avail;
+	}
+#endif
+
+	*idesc_ref = next;
+
+	return avail;
+}
+
+/* Drop a packet by pushing its buffer (if appropriate).
+ *
+ * NOTE: The caller must still call gxio_mpipe_iqueue_consume() if idesc
+ * came from gxio_mpipe_iqueue_try_peek() or gxio_mpipe_iqueue_peek().
+ *
+ * @param iqueue An ingress queue initialized via gxio_mpipe_iqueue_init().
+ * @param idesc A packet descriptor.
+ */
+static inline void gxio_mpipe_iqueue_drop(gxio_mpipe_iqueue_t *iqueue,
+					  gxio_mpipe_idesc_t *idesc)
+{
+	/* FIXME: Handle "chaining" properly. */
+
+	if (!idesc->be) {
+		unsigned char *va = gxio_mpipe_idesc_get_va(idesc);
+		gxio_mpipe_push_buffer(iqueue->context, idesc->stack_idx, va);
+	}
+}
+
+/*****************************************************************
+ *                      Egress Queue Wrapper                      *
+ ******************************************************************/
+
+/* A convenient, thread-safe interface to an eDMA ring. */
+typedef struct {
+
+	/* State object for tracking head and tail pointers. */
+	__gxio_dma_queue_t dma_queue;
+
+	/* The ring entries. */
+	gxio_mpipe_edesc_t *edescs;
+
+	/* The number of entries minus one. */
+	unsigned long mask_num_entries;
+
+	/* The log2() of the number of entries. */
+	unsigned long log2_num_entries;
+
+} gxio_mpipe_equeue_t;
+
+/* Initialize an "equeue".
+ *
+ * Takes the equeue plus the same args as gxio_mpipe_init_edma_ring().
+ */
+extern int gxio_mpipe_equeue_init(gxio_mpipe_equeue_t *equeue,
+				  gxio_mpipe_context_t *context,
+				  unsigned int edma_ring_id,
+				  unsigned int channel,
+				  void *mem, unsigned int mem_size,
+				  unsigned int mem_flags);
+
+/* Reserve completion slots for edescs.
+ *
+ * Use gxio_mpipe_equeue_put_at() to actually populate the slots.
+ *
+ * This function is slower than gxio_mpipe_equeue_reserve_fast(), but
+ * returns a full 64 bit completion slot, which can be used with
+ * gxio_mpipe_equeue_is_complete().
+ *
+ * @param equeue An egress queue initialized via gxio_mpipe_equeue_init().
+ * @param num Number of slots to reserve (must be non-zero).
+ * @return The first reserved completion slot, or a negative error code.
+ */
+static inline int64_t gxio_mpipe_equeue_reserve(gxio_mpipe_equeue_t *equeue,
+						unsigned int num)
+{
+	return __gxio_dma_queue_reserve_aux(&equeue->dma_queue, num, true);
+}
+
+/* Reserve completion slots for edescs, if possible.
+ *
+ * Use gxio_mpipe_equeue_put_at() to actually populate the slots.
+ *
+ * This function is slower than gxio_mpipe_equeue_try_reserve_fast(),
+ * but returns a full 64 bit completion slot, which can be used with
+ * gxio_mpipe_equeue_is_complete().
+ *
+ * @param equeue An egress queue initialized via gxio_mpipe_equeue_init().
+ * @param num Number of slots to reserve (must be non-zero).
+ * @return The first reserved completion slot, or a negative error code.
+ */
+static inline int64_t gxio_mpipe_equeue_try_reserve(gxio_mpipe_equeue_t
+						    *equeue, unsigned int num)
+{
+	return __gxio_dma_queue_reserve_aux(&equeue->dma_queue, num, false);
+}
+
+/* Reserve slots for edescs.
+ *
+ * Use gxio_mpipe_equeue_put_at() to actually populate the slots.
+ *
+ * This function is faster than gxio_mpipe_equeue_reserve(), but
+ * returns a 24 bit slot (instead of a 64 bit completion slot), which
+ * thus cannot be used with gxio_mpipe_equeue_is_complete().
+ *
+ * @param equeue An egress queue initialized via gxio_mpipe_equeue_init().
+ * @param num Number of slots to reserve (should be non-zero).
+ * @return The first reserved slot, or a negative error code.
+ */
+static inline int64_t gxio_mpipe_equeue_reserve_fast(gxio_mpipe_equeue_t
+						     *equeue, unsigned int num)
+{
+	return __gxio_dma_queue_reserve(&equeue->dma_queue, num, true, false);
+}
+
+/* Reserve slots for edescs, if possible.
+ *
+ * Use gxio_mpipe_equeue_put_at() to actually populate the slots.
+ *
+ * This function is faster than gxio_mpipe_equeue_try_reserve(), but
+ * returns a 24 bit slot (instead of a 64 bit completion slot), which
+ * thus cannot be used with gxio_mpipe_equeue_is_complete().
+ *
+ * @param equeue An egress queue initialized via gxio_mpipe_equeue_init().
+ * @param num Number of slots to reserve (should be non-zero).
+ * @return The first reserved slot, or a negative error code.
+ */
+static inline int64_t gxio_mpipe_equeue_try_reserve_fast(gxio_mpipe_equeue_t
+							 *equeue,
+							 unsigned int num)
+{
+	return __gxio_dma_queue_reserve(&equeue->dma_queue, num, false, false);
+}
+
+/*
+ * HACK: This helper function tricks gcc 4.6 into avoiding saving
+ * a copy of "edesc->words[0]" on the stack for no obvious reason.
+ */
+
+static inline void gxio_mpipe_equeue_put_at_aux(gxio_mpipe_equeue_t *equeue,
+						uint_reg_t ew[2],
+						unsigned long slot)
+{
+	unsigned long edma_slot = slot & equeue->mask_num_entries;
+	gxio_mpipe_edesc_t *edesc_p = &equeue->edescs[edma_slot];
+
+	/*
+	 * ISSUE: Could set eDMA ring to be on generation 1 at start, which
+	 * would avoid the negation here, perhaps allowing "__insn_bfins()".
+	 */
+	ew[0] |= !((slot >> equeue->log2_num_entries) & 1);
+
+	/*
+	 * NOTE: We use "__gxio_mpipe_write()", plus the fact that the eDMA
+	 * queue alignment restrictions ensure that these two words are on
+	 * the same cacheline, to force proper ordering between the stores.
+	 */
+	__gxio_mmio_write64(&edesc_p->words[1], ew[1]);
+	__gxio_mmio_write64(&edesc_p->words[0], ew[0]);
+}
+
+/* Post an edesc to a given slot in an equeue.
+ *
+ * This function copies the supplied edesc into entry "slot mod N" in
+ * the underlying ring, setting the "gen" bit to the appropriate value
+ * based on "(slot mod N*2)", where "N" is the size of the ring.  Note
+ * that the higher bits of slot are unused, and thus, this function
+ * can handle "slots" as well as "completion slots".
+ *
+ * Normally this function is used to fill in slots reserved by
+ * gxio_mpipe_equeue_try_reserve(), gxio_mpipe_equeue_reserve(),
+ * gxio_mpipe_equeue_try_reserve_fast(), or
+ * gxio_mpipe_equeue_reserve_fast(),
+ *
+ * This function can also be used without "reserving" slots, if the
+ * application KNOWS that the ring can never overflow, for example, by
+ * pushing fewer buffers into the buffer stacks than there are total
+ * slots in the equeue, but this is NOT recommended.
+ *
+ * @param equeue An egress queue initialized via gxio_mpipe_equeue_init().
+ * @param edesc The egress descriptor to be posted.
+ * @param slot An egress slot (only the low bits are actually used).
+ */
+static inline void gxio_mpipe_equeue_put_at(gxio_mpipe_equeue_t *equeue,
+					    gxio_mpipe_edesc_t edesc,
+					    unsigned long slot)
+{
+	gxio_mpipe_equeue_put_at_aux(equeue, edesc.words, slot);
+}
+
+/* Post an edesc to the next slot in an equeue.
+ *
+ * This is a convenience wrapper around
+ * gxio_mpipe_equeue_reserve_fast() and gxio_mpipe_equeue_put_at().
+ *
+ * @param equeue An egress queue initialized via gxio_mpipe_equeue_init().
+ * @param edesc The egress descriptor to be posted.
+ * @return 0 on success.
+ */
+static inline int gxio_mpipe_equeue_put(gxio_mpipe_equeue_t *equeue,
+					gxio_mpipe_edesc_t edesc)
+{
+	int64_t slot = gxio_mpipe_equeue_reserve_fast(equeue, 1);
+	if (slot < 0)
+		return (int)slot;
+
+	gxio_mpipe_equeue_put_at(equeue, edesc, slot);
+
+	return 0;
+}
+
+/* Ask the mPIPE hardware to egress outstanding packets immediately.
+ *
+ * This call is not necessary, but may slightly reduce overall latency.
+ *
+ * Technically, you should flush all gxio_mpipe_equeue_put_at() writes
+ * to memory before calling this function, to ensure the descriptors
+ * are visible in memory before the mPIPE hardware actually looks for
+ * them.  But this should be very rare, and the only side effect would
+ * be increased latency, so it is up to the caller to decide whether
+ * or not to flush memory.
+ *
+ * @param equeue An egress queue initialized via gxio_mpipe_equeue_init().
+ */
+static inline void gxio_mpipe_equeue_flush(gxio_mpipe_equeue_t *equeue)
+{
+	/* Use "ring_idx = 0" and "count = 0" to "wake up" the eDMA ring. */
+	MPIPE_EDMA_POST_REGION_VAL_t val = { {0} };
+	/* Flush the write buffers. */
+	__insn_flushwb();
+	__gxio_mmio_write(equeue->dma_queue.post_region_addr, val.word);
+}
+
+/* Determine if a given edesc has been completed.
+ *
+ * Note that this function requires a "completion slot", and thus may
+ * NOT be used with a "slot" from gxio_mpipe_equeue_reserve_fast() or
+ * gxio_mpipe_equeue_try_reserve_fast().
+ *
+ * @param equeue An egress queue initialized via gxio_mpipe_equeue_init().
+ * @param completion_slot The completion slot used by the edesc.
+ * @param update If true, and the desc does not appear to have completed
+ * yet, then update any software cache of the hardware completion counter,
+ * and check again.  This should normally be true.
+ * @return True iff the given edesc has been completed.
+ */
+static inline int gxio_mpipe_equeue_is_complete(gxio_mpipe_equeue_t *equeue,
+						int64_t completion_slot,
+						int update)
+{
+	return __gxio_dma_queue_is_complete(&equeue->dma_queue,
+					    completion_slot, update);
+}
+
+/*****************************************************************
+ *                        Link Management                         *
+ ******************************************************************/
+
+/*
+ *
+ * Functions for manipulating and sensing the state and configuration
+ * of physical network links.
+ *
+ * @section gxio_mpipe_link_perm Link Permissions
+ *
+ * Opening a link (with gxio_mpipe_link_open()) requests a set of link
+ * permissions, which control what may be done with the link, and potentially
+ * what permissions may be granted to other processes.
+ *
+ * Data permission allows the process to receive packets from the link by
+ * specifying the link's channel number in mPIPE packet distribution rules,
+ * and to send packets to the link by using the link's channel number as
+ * the target for an eDMA ring.
+ *
+ * Stats permission allows the process to retrieve link attributes (such as
+ * the speeds it is capable of running at, or whether it is currently up), and
+ * to read and write certain statistics-related registers in the link's MAC.
+ *
+ * Control permission allows the process to retrieve and modify link attributes
+ * (so that it may, for example, bring the link up and take it down), and
+ * read and write many registers in the link's MAC and PHY.
+ *
+ * Any permission may be requested as shared, which allows other processes
+ * to also request shared permission, or exclusive, which prevents other
+ * processes from requesting it.  In keeping with GXIO's typical usage in
+ * an embedded environment, the defaults for all permissions are shared.
+ *
+ * Permissions are granted on a first-come, first-served basis, so if two
+ * applications request an exclusive permission on the same link, the one
+ * to run first will win.  Note, however, that some system components, like
+ * the kernel Ethernet driver, may get an opportunity to open links before
+ * any applications run.
+ *
+ * @section gxio_mpipe_link_names Link Names
+ *
+ * Link names are of the form gbe<em>number</em> (for Gigabit Ethernet),
+ * xgbe<em>number</em> (for 10 Gigabit Ethernet), loop<em>number</em> (for
+ * internal mPIPE loopback), or ilk<em>number</em>/<em>channel</em>
+ * (for Interlaken links); for instance, gbe0, xgbe1, loop3, and
+ * ilk0/12 are all possible link names.  The correspondence between
+ * the link name and an mPIPE instance number or mPIPE channel number is
+ * system-dependent; all links will not exist on all systems, and the set
+ * of numbers used for a particular link type may not start at zero and may
+ * not be contiguous.  Use gxio_mpipe_link_enumerate() to retrieve the set of
+ * links which exist on a system, and always use gxio_mpipe_link_instance()
+ * to determine which mPIPE controls a particular link.
+ *
+ * Note that in some cases, links may share hardware, such as PHYs, or
+ * internal mPIPE buffers; in these cases, only one of the links may be
+ * opened at a time.  This is especially common with xgbe and gbe ports,
+ * since each xgbe port uses 4 SERDES lanes, each of which may also be
+ * configured as one gbe port.
+ *
+ * @section gxio_mpipe_link_states Link States
+ *
+ * The mPIPE link management model revolves around three different states,
+ * which are maintained for each link:
+ *
+ * 1. The <em>current</em> link state: is the link up now, and if so, at
+ *    what speed?
+ *
+ * 2. The <em>desired</em> link state: what do we want the link state to be?
+ *    The system is always working to make this state the current state;
+ *    thus, if the desired state is up, and the link is down, we'll be
+ *    constantly trying to bring it up, automatically.
+ *
+ * 3. The <em>possible</em> link state: what speeds are valid for this
+ *    particular link?  Or, in other words, what are the capabilities of
+ *    the link hardware?
+ *
+ * These link states are not, strictly speaking, related to application
+ * state; they may be manipulated at any time, whether or not the link
+ * is currently being used for data transfer.  However, for convenience,
+ * gxio_mpipe_link_open() and gxio_mpipe_link_close() (or application exit)
+ * can affect the link state.  These implicit link management operations
+ * may be modified or disabled by the use of link open flags.
+ *
+ * From an application, you can use gxio_mpipe_link_get_attr()
+ * and gxio_mpipe_link_set_attr() to manipulate the link states.
+ * gxio_mpipe_link_get_attr() with ::GXIO_MPIPE_LINK_POSSIBLE_STATE
+ * gets you the possible link state.  gxio_mpipe_link_get_attr() with
+ * ::GXIO_MPIPE_LINK_CURRENT_STATE gets you the current link state.
+ * Finally, gxio_mpipe_link_set_attr() and gxio_mpipe_link_get_attr()
+ * with ::GXIO_MPIPE_LINK_DESIRED_STATE allow you to modify or retrieve
+ * the desired link state.
+ *
+ * If you want to manage a link from a part of your application which isn't
+ * involved in packet processing, you can use the ::GXIO_MPIPE_LINK_NO_DATA
+ * flags on a gxio_mpipe_link_open() call.  This opens the link, but does
+ * not request data permission, so it does not conflict with any exclusive
+ * permissions which may be held by other processes.  You can then can use
+ * gxio_mpipe_link_get_attr() and gxio_mpipe_link_set_attr() on this link
+ * object to bring up or take down the link.
+ *
+ * Some links support link state bits which support various loopback
+ * modes. ::GXIO_MPIPE_LINK_LOOP_MAC tests datapaths within the Tile
+ * Processor itself; ::GXIO_MPIPE_LINK_LOOP_PHY tests the datapath between
+ * the Tile Processor and the external physical layer interface chip; and
+ * ::GXIO_MPIPE_LINK_LOOP_EXT tests the entire network datapath with the
+ * aid of an external loopback connector.  In addition to enabling hardware
+ * testing, such configuration can be useful for software testing, as well.
+ *
+ * When LOOP_MAC or LOOP_PHY is enabled, packets transmitted on a channel
+ * will be received by that channel, instead of being emitted on the
+ * physical link, and packets received on the physical link will be ignored.
+ * Other than that, all standard GXIO operations work as you might expect.
+ * Note that loopback operation requires that the link be brought up using
+ * one or more of the GXIO_MPIPE_LINK_SPEED_xxx link state bits.
+ *
+ * Those familiar with previous versions of the MDE on TILEPro hardware
+ * will notice significant similarities between the NetIO link management
+ * model and the mPIPE link management model.  However, the NetIO model
+ * was developed in stages, and some of its features -- for instance,
+ * the default setting of certain flags -- were shaped by the need to be
+ * compatible with previous versions of NetIO.  Since the features provided
+ * by the mPIPE hardware and the mPIPE GXIO library are significantly
+ * different than those provided by NetIO, in some cases, we have made
+ * different choices in the mPIPE link management API.  Thus, please read
+ * this documentation carefully before assuming that mPIPE link management
+ * operations are exactly equivalent to their NetIO counterparts.
+ */
+
+/* An object used to manage mPIPE link state and resources. */
+typedef struct {
+	/* The overall mPIPE context. */
+	gxio_mpipe_context_t *context;
+
+	/* The channel number used by this link. */
+	uint8_t channel;
+
+	/* The MAC index used by this link. */
+	uint8_t mac;
+} gxio_mpipe_link_t;
+
+/* Retrieve one of this system's legal link names, and its MAC address.
+ *
+ * @param index Link name index.  If a system supports N legal link names,
+ *  then indices between 0 and N - 1, inclusive, each correspond to one of
+ *  those names.  Thus, to retrieve all of a system's legal link names,
+ *  call this function in a loop, starting with an index of zero, and
+ *  incrementing it once per iteration until -1 is returned.
+ * @param link_name Pointer to the buffer which will receive the retrieved
+ *  link name.  The buffer should contain space for at least
+ *  ::GXIO_MPIPE_LINK_NAME_LEN bytes; the returned name, including the
+ *  terminating null byte, will be no longer than that.
+ * @param link_name Pointer to the buffer which will receive the retrieved
+ *  MAC address.  The buffer should contain space for at least 6 bytes.
+ * @return Zero if a link name was successfully retrieved; -1 if one was
+ *  not.
+ */
+extern int gxio_mpipe_link_enumerate_mac(int index, char *link_name,
+					 uint8_t *mac_addr);
+
+/* Open an mPIPE link.
+ *
+ *  A link must be opened before it may be used to send or receive packets,
+ *  and before its state may be examined or changed.  Depending up on the
+ *  link's intended use, one or more link permissions may be requested via
+ *  the flags parameter; see @ref gxio_mpipe_link_perm.  In addition, flags
+ *  may request that the link's state be modified at open time.  See @ref
+ *  gxio_mpipe_link_states and @ref gxio_mpipe_link_open_flags for more detail.
+ *
+ * @param link A link state object, which will be initialized if this
+ *  function completes successfully.
+ * @param context An initialized mPIPE context.
+ * @param link_name Name of the link.
+ * @param flags Zero or more @ref gxio_mpipe_link_open_flags, ORed together.
+ * @return 0 if the link was successfully opened, or a negative error code.
+ *
+ */
+extern int gxio_mpipe_link_open(gxio_mpipe_link_t *link,
+				gxio_mpipe_context_t *context,
+				const char *link_name, unsigned int flags);
+
+/* Close an mPIPE link.
+ *
+ *  Closing a link makes it available for use by other processes.  Once
+ *  a link has been closed, packets may no longer be sent on or received
+ *  from the link, and its state may not be examined or changed.
+ *
+ * @param link A link state object, which will no longer be initialized
+ *  if this function completes successfully.
+ * @return 0 if the link was successfully closed, or a negative error code.
+ *
+ */
+extern int gxio_mpipe_link_close(gxio_mpipe_link_t *link);
+
+/* Return a link's channel number.
+ *
+ * @param link A properly initialized link state object.
+ * @return The channel number for the link.
+ */
+static inline int gxio_mpipe_link_channel(gxio_mpipe_link_t *link)
+{
+	return link->channel;
+}
+
+///////////////////////////////////////////////////////////////////
+//                             Timestamp                         //
+///////////////////////////////////////////////////////////////////
+
+/* Get the timestamp of mPIPE when this routine is called.
+ *
+ * @param context An initialized mPIPE context.
+ * @param ts A timespec structure to store the current clock.
+ * @return If the call was successful, zero; otherwise, a negative error
+ *  code.
+ */
+extern int gxio_mpipe_get_timestamp(gxio_mpipe_context_t *context,
+				    struct timespec *ts);
+
+/* Set the timestamp of mPIPE.
+ *
+ * @param context An initialized mPIPE context.
+ * @param ts A timespec structure to store the requested clock.
+ * @return If the call was successful, zero; otherwise, a negative error
+ *  code.
+ */
+extern int gxio_mpipe_set_timestamp(gxio_mpipe_context_t *context,
+				    const struct timespec *ts);
+
+/* Adjust the timestamp of mPIPE.
+ *
+ * @param context An initialized mPIPE context.
+ * @param delta A signed time offset to adjust, in nanoseconds.
+ * The absolute value of this parameter must be less than or
+ * equal to 1000000000.
+ * @return If the call was successful, zero; otherwise, a negative error
+ *  code.
+ */
+extern int gxio_mpipe_adjust_timestamp(gxio_mpipe_context_t *context,
+				       int64_t delta);
+
+#endif /* !_GXIO_MPIPE_H_ */
diff --git a/arch/tile/include/gxio/trio.h b/arch/tile/include/gxio/trio.h
new file mode 100644
index 0000000..77b80cd
--- /dev/null
+++ b/arch/tile/include/gxio/trio.h
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/*
+ *
+ * An API for allocating, configuring, and manipulating TRIO hardware
+ * resources
+ */
+
+/*
+ *
+ * The TILE-Gx TRIO shim provides connections to external devices via
+ * PCIe or other transaction IO standards.  The gxio_trio_ API,
+ * declared in <gxio/trio.h>, allows applications to allocate and
+ * configure TRIO IO resources like DMA command rings, memory map
+ * windows, and device interrupts.  The following sections introduce
+ * the various components of the API.  We strongly recommend reading
+ * the TRIO section of the IO Device Guide (UG404) before working with
+ * this API.
+ *
+ * @section trio__ingress TRIO Ingress Hardware Resources
+ *
+ * The TRIO ingress hardware is responsible for examining incoming
+ * PCIe or StreamIO packets and choosing a processing mechanism based
+ * on the packets' bus address.  The gxio_trio_ API can be used to
+ * configure different handlers for different ranges of bus address
+ * space.  The user can configure "mapped memory" and "scatter queue"
+ * regions to match incoming packets within 4kB-aligned ranges of bus
+ * addresses.  Each range specifies a different set of mapping
+ * parameters to be applied when handling the ingress packet.  The
+ * following sections describe how to work with MapMem and scatter
+ * queue regions.
+ *
+ * @subsection trio__mapmem TRIO MapMem Regions
+ *
+ * TRIO mapped memory (or MapMem) regions allow the user to map
+ * incoming read and write requests directly to the application's
+ * memory space.  MapMem regions are allocated via
+ * gxio_trio_alloc_memory_maps().  Given an integer MapMem number,
+ * applications can use gxio_trio_init_memory_map() to specify the
+ * range of bus addresses that will match the region and the range of
+ * virtual addresses to which those packets will be applied.
+ *
+ * As with many other gxio APIs, the programmer must be sure to
+ * register memory pages that will be used with MapMem regions.  Pages
+ * can be registered with TRIO by allocating an ASID (address space
+ * identifier) and then using gxio_trio_register_page() to register up to
+ * 16 pages with the hardware.  The initialization functions for
+ * resources that require registered memory (MapMem, scatter queues,
+ * push DMA, and pull DMA) then take an 'asid' parameter in order to
+ * configure which set of registered pages is used by each resource.
+ *
+ * @subsection trio__scatter_queue TRIO Scatter Queues
+ *
+ * The TRIO shim's scatter queue regions allow users to dynamically
+ * map buffers from a large address space into a small range of bus
+ * addresses.  This is particularly helpful for PCIe endpoint devices,
+ * where the host generally limits the size of BARs to tens of
+ * megabytes.
+ *
+ * Each scatter queue consists of a memory map region, a queue of
+ * tile-side buffer VAs to be mapped to that region, and a bus-mapped
+ * "doorbell" register that the remote endpoint can write to trigger a
+ * dequeue of the current buffer VA, thus swapping in a new buffer.
+ * The VAs pushed onto a scatter queue must be 4kB aligned, so
+ * applications may need to use higher-level protocols to inform
+ * remote entities that they should apply some additional, sub-4kB
+ * offset when reading or writing the scatter queue region.  For more
+ * information, see the IO Device Guide (UG404).
+ *
+ * @section trio__egress TRIO Egress Hardware Resources
+ *
+ * The TRIO shim supports two mechanisms for egress packet generation:
+ * programmed IO (PIO) and push/pull DMA.  PIO allows applications to
+ * create MMIO mappings for PCIe or StreamIO address space, such that
+ * the application can generate word-sized read or write transactions
+ * by issuing load or store instructions.  Push and pull DMA are tuned
+ * for larger transactions; they use specialized hardware engines to
+ * transfer large blocks of data at line rate.
+ *
+ * @subsection trio__pio TRIO Programmed IO
+ *
+ * Programmed IO allows applications to create MMIO mappings for PCIe
+ * or StreamIO address space.  The hardware PIO regions support access
+ * to PCIe configuration, IO, and memory space, but the gxio_trio API
+ * only supports memory space accesses.  PIO regions are allocated
+ * with gxio_trio_alloc_pio_regions() and initialized via
+ * gxio_trio_init_pio_region().  Once a region is bound to a range of
+ * bus address via the initialization function, the application can
+ * use gxio_trio_map_pio_region() to create MMIO mappings from its VA
+ * space onto the range of bus addresses supported by the PIO region.
+ *
+ * @subsection trio_dma TRIO Push and Pull DMA
+ *
+ * The TRIO push and pull DMA engines allow users to copy blocks of
+ * data between application memory and the bus.  Push DMA generates
+ * write packets that copy from application memory to the bus and pull
+ * DMA generates read packets that copy from the bus into application
+ * memory.  The DMA engines are managed via an API that is very
+ * similar to the mPIPE eDMA interface.  For a detailed explanation of
+ * the eDMA queue API, see @ref gxio_mpipe_wrappers.
+ *
+ * Push and pull DMA queues are allocated via
+ * gxio_trio_alloc_push_dma_ring() / gxio_trio_alloc_pull_dma_ring().
+ * Once allocated, users generally use a ::gxio_trio_dma_queue_t
+ * object to manage the queue, providing easy wrappers for reserving
+ * command slots in the DMA command ring, filling those slots, and
+ * waiting for commands to complete.  DMA queues can be initialized
+ * via gxio_trio_init_push_dma_queue() or
+ * gxio_trio_init_pull_dma_queue().
+ *
+ * See @ref trio/push_dma/app.c for an example of how to use push DMA.
+ *
+ * @section trio_shortcomings Plans for Future API Revisions
+ *
+ * The simulation framework is incomplete.  Future features include:
+ *
+ * - Support for reset and deallocation of resources.
+ *
+ * - Support for pull DMA.
+ *
+ * - Support for interrupt regions and user-space interrupt delivery.
+ *
+ * - Support for getting BAR mappings and reserving regions of BAR
+ *   address space.
+ */
+#ifndef _GXIO_TRIO_H_
+#define _GXIO_TRIO_H_
+
+#include <linux/types.h>
+
+#include "common.h"
+#include "dma_queue.h"
+
+#include <arch/trio_constants.h>
+#include <arch/trio.h>
+#include <arch/trio_pcie_intfc.h>
+#include <arch/trio_pcie_rc.h>
+#include <arch/trio_shm.h>
+#include <hv/drv_trio_intf.h>
+#include <hv/iorpc.h>
+
+/* A context object used to manage TRIO hardware resources. */
+typedef struct {
+
+	/* File descriptor for calling up to Linux (and thus the HV). */
+	int fd;
+
+	/* The VA at which the MAC MMIO registers are mapped. */
+	char *mmio_base_mac;
+
+	/* The VA at which the PIO config space are mapped for each PCIe MAC.
+	   Gx36 has max 3 PCIe MACs per TRIO shim. */
+	char *mmio_base_pio_cfg[TILEGX_TRIO_PCIES];
+
+#ifdef USE_SHARED_PCIE_CONFIG_REGION
+	/* Index of the shared PIO region for PCI config access. */
+	int pio_cfg_index;
+#else
+	/* Index of the PIO region for PCI config access per MAC. */
+	int pio_cfg_index[TILEGX_TRIO_PCIES];
+#endif
+
+	/*  The VA at which the push DMA MMIO registers are mapped. */
+	char *mmio_push_dma[TRIO_NUM_PUSH_DMA_RINGS];
+
+	/*  The VA at which the pull DMA MMIO registers are mapped. */
+	char *mmio_pull_dma[TRIO_NUM_PUSH_DMA_RINGS];
+
+	/* Application space ID. */
+	unsigned int asid;
+
+} gxio_trio_context_t;
+
+/* Command descriptor for push or pull DMA. */
+typedef TRIO_DMA_DESC_t gxio_trio_dma_desc_t;
+
+/* A convenient, thread-safe interface to an eDMA ring. */
+typedef struct {
+
+	/* State object for tracking head and tail pointers. */
+	__gxio_dma_queue_t dma_queue;
+
+	/* The ring entries. */
+	gxio_trio_dma_desc_t *dma_descs;
+
+	/* The number of entries minus one. */
+	unsigned long mask_num_entries;
+
+	/* The log2() of the number of entries. */
+	unsigned int log2_num_entries;
+
+} gxio_trio_dma_queue_t;
+
+/* Initialize a TRIO context.
+ *
+ * This function allocates a TRIO "service domain" and maps the MMIO
+ * registers into the the caller's VA space.
+ *
+ * @param trio_index Which TRIO shim; Gx36 must pass 0.
+ * @param context Context object to be initialized.
+ */
+extern int gxio_trio_init(gxio_trio_context_t *context,
+			  unsigned int trio_index);
+
+/* This indicates that an ASID hasn't been allocated. */
+#define GXIO_ASID_NULL -1
+
+/* Ordering modes for map memory regions and scatter queue regions. */
+typedef enum gxio_trio_order_mode_e {
+	/* Writes are not ordered.  Reads always wait for previous writes. */
+	GXIO_TRIO_ORDER_MODE_UNORDERED =
+		TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_UNORDERED,
+	/* Both writes and reads wait for previous transactions to complete. */
+	GXIO_TRIO_ORDER_MODE_STRICT =
+		TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_STRICT,
+	/* Writes are ordered unless the incoming packet has the
+	   relaxed-ordering attributes set. */
+	GXIO_TRIO_ORDER_MODE_OBEY_PACKET =
+		TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_REL_ORD
+} gxio_trio_order_mode_t;
+
+/* Initialize a memory mapping region.
+ *
+ * @param context An initialized TRIO context.
+ * @param map A Memory map region allocated by gxio_trio_alloc_memory_map().
+ * @param target_mem VA of backing memory, should be registered via
+ *   gxio_trio_register_page() and aligned to 4kB.
+ * @param target_size Length of the memory mapping, must be a multiple
+ * of 4kB.
+ * @param asid ASID to be used for Tile-side address translation.
+ * @param mac MAC number.
+ * @param bus_address Bus address at which the mapping starts.
+ * @param order_mode Memory ordering mode for this mapping.
+ * @return Zero on success, else ::GXIO_TRIO_ERR_BAD_MEMORY_MAP,
+ * GXIO_TRIO_ERR_BAD_ASID, or ::GXIO_TRIO_ERR_BAD_BUS_RANGE.
+ */
+extern int gxio_trio_init_memory_map(gxio_trio_context_t *context,
+				     unsigned int map, void *target_mem,
+				     size_t target_size, unsigned int asid,
+				     unsigned int mac, uint64_t bus_address,
+				     gxio_trio_order_mode_t order_mode);
+
+/* Flags that can be passed to resource allocation functions. */
+enum gxio_trio_alloc_flags_e {
+	GXIO_TRIO_ALLOC_FIXED = HV_TRIO_ALLOC_FIXED,
+};
+
+/* Flags that can be passed to memory registration functions. */
+enum gxio_trio_mem_flags_e {
+	/* Do not fill L3 when writing, and invalidate lines upon egress. */
+	GXIO_TRIO_MEM_FLAG_NT_HINT = IORPC_MEM_BUFFER_FLAG_NT_HINT,
+
+	/* L3 cache fills should only populate IO cache ways. */
+	GXIO_TRIO_MEM_FLAG_IO_PIN = IORPC_MEM_BUFFER_FLAG_IO_PIN,
+};
+
+/* Flag indicating a request generator uses a special traffic
+    class. */
+#define GXIO_TRIO_FLAG_TRAFFIC_CLASS(N) HV_TRIO_FLAG_TC(N)
+
+/* Flag indicating a request generator uses a virtual function
+    number. */
+#define GXIO_TRIO_FLAG_VFUNC(N) HV_TRIO_FLAG_VFUNC(N)
+
+/*****************************************************************
+ *                       Memory Registration                      *
+ ******************************************************************/
+
+/* Allocate Application Space Identifiers (ASIDs).  Each ASID can
+ * register up to 16 page translations.  ASIDs are used by memory map
+ * regions, scatter queues, and DMA queues to translate application
+ * VAs into memory system PAs.
+ *
+ * @param context An initialized TRIO context.
+ * @param count Number of ASIDs required.
+ * @param first Index of first ASID if ::GXIO_TRIO_ALLOC_FIXED flag
+ *   is set, otherwise ignored.
+ * @param flags Flag bits, including bits from ::gxio_trio_alloc_flags_e.
+ * @return Index of first ASID, or ::GXIO_TRIO_ERR_NO_ASID if allocation
+ *   failed.
+ */
+extern int gxio_trio_alloc_asids(gxio_trio_context_t *context,
+				 unsigned int count, unsigned int first,
+				 unsigned int flags);
+
+#endif /* ! _GXIO_TRIO_H_ */
diff --git a/arch/tile/include/gxio/usb_host.h b/arch/tile/include/gxio/usb_host.h
new file mode 100644
index 0000000..a60a126
--- /dev/null
+++ b/arch/tile/include/gxio/usb_host.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+#ifndef _GXIO_USB_H_
+#define _GXIO_USB_H_
+
+#include "common.h"
+
+#include <hv/drv_usb_host_intf.h>
+#include <hv/iorpc.h>
+
+/*
+ *
+ * An API for manipulating general-purpose I/O pins.
+ */
+
+/*
+ *
+ * The USB shim allows access to the processor's Universal Serial Bus
+ * connections.
+ */
+
+/* A context object used to manage USB hardware resources. */
+typedef struct {
+
+	/* File descriptor for calling up to the hypervisor. */
+	int fd;
+
+	/* The VA at which our MMIO registers are mapped. */
+	char *mmio_base;
+} gxio_usb_host_context_t;
+
+/* Initialize a USB context.
+ *
+ *  A properly initialized context must be obtained before any of the other
+ *  gxio_usb_host routines may be used.
+ *
+ * @param context Pointer to a gxio_usb_host_context_t, which will be
+ *  initialized by this routine, if it succeeds.
+ * @param usb_index Index of the USB shim to use.
+ * @param is_ehci Nonzero to use the EHCI interface; zero to use the OHCI
+ *  intereface.
+ * @return Zero if the context was successfully initialized, else a
+ *  GXIO_ERR_xxx error code.
+ */
+extern int gxio_usb_host_init(gxio_usb_host_context_t * context, int usb_index,
+			      int is_ehci);
+
+/* Destroy a USB context.
+ *
+ *  Once destroyed, a context may not be used with any gxio_usb_host routines
+ *  other than gxio_usb_host_init().  After this routine returns, no further
+ *  interrupts or signals requested on this context will be delivered.  The
+ *  state and configuration of the pins which had been attached to this
+ *  context are unchanged by this operation.
+ *
+ * @param context Pointer to a gxio_usb_host_context_t.
+ * @return Zero if the context was successfully destroyed, else a
+ *  GXIO_ERR_xxx error code.
+ */
+extern int gxio_usb_host_destroy(gxio_usb_host_context_t * context);
+
+/* Retrieve the address of the shim's MMIO registers.
+ *
+ * @param context Pointer to a properly initialized gxio_usb_host_context_t.
+ * @return The address of the shim's MMIO registers.
+ */
+extern void *gxio_usb_host_get_reg_start(gxio_usb_host_context_t * context);
+
+/* Retrieve the length of the shim's MMIO registers.
+ *
+ * @param context Pointer to a properly initialized gxio_usb_host_context_t.
+ * @return The length of the shim's MMIO registers.
+ */
+extern size_t gxio_usb_host_get_reg_len(gxio_usb_host_context_t * context);
+
+#endif /* _GXIO_USB_H_ */
diff --git a/arch/tile/include/hv/drv_mpipe_intf.h b/arch/tile/include/hv/drv_mpipe_intf.h
new file mode 100644
index 0000000..6cdae3b
--- /dev/null
+++ b/arch/tile/include/hv/drv_mpipe_intf.h
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * Interface definitions for the mpipe driver.
+ */
+
+#ifndef _SYS_HV_DRV_MPIPE_INTF_H
+#define _SYS_HV_DRV_MPIPE_INTF_H
+
+#include <arch/mpipe.h>
+#include <arch/mpipe_constants.h>
+
+
+/** Number of buffer stacks (32). */
+#define HV_MPIPE_NUM_BUFFER_STACKS \
+  (MPIPE_MMIO_INIT_DAT_GX36_1__BUFFER_STACK_MASK_WIDTH)
+
+/** Number of NotifRings (256). */
+#define HV_MPIPE_NUM_NOTIF_RINGS (MPIPE_NUM_NOTIF_RINGS)
+
+/** Number of NotifGroups (32). */
+#define HV_MPIPE_NUM_NOTIF_GROUPS (MPIPE_NUM_NOTIF_GROUPS)
+
+/** Number of buckets (4160). */
+#define HV_MPIPE_NUM_BUCKETS (MPIPE_NUM_BUCKETS)
+
+/** Number of "lo" buckets (4096). */
+#define HV_MPIPE_NUM_LO_BUCKETS 4096
+
+/** Number of "hi" buckets (64). */
+#define HV_MPIPE_NUM_HI_BUCKETS \
+  (HV_MPIPE_NUM_BUCKETS - HV_MPIPE_NUM_LO_BUCKETS)
+
+/** Number of edma rings (24). */
+#define HV_MPIPE_NUM_EDMA_RINGS \
+  (MPIPE_MMIO_INIT_DAT_GX36_1__EDMA_POST_MASK_WIDTH)
+
+
+
+
+/** A flag bit indicating a fixed resource allocation. */
+#define HV_MPIPE_ALLOC_FIXED 0x01
+
+/** Offset for the config register MMIO region. */
+#define HV_MPIPE_CONFIG_MMIO_OFFSET \
+  (MPIPE_MMIO_ADDR__REGION_VAL_CFG << MPIPE_MMIO_ADDR__REGION_SHIFT)
+
+/** Size of the config register MMIO region. */
+#define HV_MPIPE_CONFIG_MMIO_SIZE (64 * 1024)
+
+/** Offset for the config register MMIO region. */
+#define HV_MPIPE_FAST_MMIO_OFFSET \
+  (MPIPE_MMIO_ADDR__REGION_VAL_IDMA << MPIPE_MMIO_ADDR__REGION_SHIFT)
+
+/** Size of the fast register MMIO region (IDMA, EDMA, buffer stack). */
+#define HV_MPIPE_FAST_MMIO_SIZE \
+  ((MPIPE_MMIO_ADDR__REGION_VAL_BSM + 1 - MPIPE_MMIO_ADDR__REGION_VAL_IDMA) \
+   << MPIPE_MMIO_ADDR__REGION_SHIFT)
+
+
+/*
+ * Each type of resource allocation comes in quantized chunks, where
+ * XXX_BITS is the number of chunks, and XXX_RES_PER_BIT is the number
+ * of resources in each chunk.
+ */
+
+/** Number of buffer stack chunks available (32). */
+#define HV_MPIPE_ALLOC_BUFFER_STACKS_BITS \
+  MPIPE_MMIO_INIT_DAT_GX36_1__BUFFER_STACK_MASK_WIDTH
+
+/** Granularity of buffer stack allocation (1). */
+#define HV_MPIPE_ALLOC_BUFFER_STACKS_RES_PER_BIT \
+  (HV_MPIPE_NUM_BUFFER_STACKS / HV_MPIPE_ALLOC_BUFFER_STACKS_BITS)
+
+/** Number of NotifRing chunks available (32). */
+#define HV_MPIPE_ALLOC_NOTIF_RINGS_BITS \
+  MPIPE_MMIO_INIT_DAT_GX36_0__NOTIF_RING_MASK_WIDTH
+
+/** Granularity of NotifRing allocation (8). */
+#define HV_MPIPE_ALLOC_NOTIF_RINGS_RES_PER_BIT \
+  (HV_MPIPE_NUM_NOTIF_RINGS / HV_MPIPE_ALLOC_NOTIF_RINGS_BITS)
+
+/** Number of NotifGroup chunks available (32). */
+#define HV_MPIPE_ALLOC_NOTIF_GROUPS_BITS \
+  HV_MPIPE_NUM_NOTIF_GROUPS
+
+/** Granularity of NotifGroup allocation (1). */
+#define HV_MPIPE_ALLOC_NOTIF_GROUPS_RES_PER_BIT \
+  (HV_MPIPE_NUM_NOTIF_GROUPS / HV_MPIPE_ALLOC_NOTIF_GROUPS_BITS)
+
+/** Number of lo bucket chunks available (16). */
+#define HV_MPIPE_ALLOC_LO_BUCKETS_BITS \
+  MPIPE_MMIO_INIT_DAT_GX36_0__BUCKET_RELEASE_MASK_LO_WIDTH
+
+/** Granularity of lo bucket allocation (256). */
+#define HV_MPIPE_ALLOC_LO_BUCKETS_RES_PER_BIT \
+  (HV_MPIPE_NUM_LO_BUCKETS / HV_MPIPE_ALLOC_LO_BUCKETS_BITS)
+
+/** Number of hi bucket chunks available (16). */
+#define HV_MPIPE_ALLOC_HI_BUCKETS_BITS \
+  MPIPE_MMIO_INIT_DAT_GX36_0__BUCKET_RELEASE_MASK_HI_WIDTH
+
+/** Granularity of hi bucket allocation (4). */
+#define HV_MPIPE_ALLOC_HI_BUCKETS_RES_PER_BIT \
+  (HV_MPIPE_NUM_HI_BUCKETS / HV_MPIPE_ALLOC_HI_BUCKETS_BITS)
+
+/** Number of eDMA ring chunks available (24). */
+#define HV_MPIPE_ALLOC_EDMA_RINGS_BITS \
+  MPIPE_MMIO_INIT_DAT_GX36_1__EDMA_POST_MASK_WIDTH
+
+/** Granularity of eDMA ring allocation (1). */
+#define HV_MPIPE_ALLOC_EDMA_RINGS_RES_PER_BIT \
+  (HV_MPIPE_NUM_EDMA_RINGS / HV_MPIPE_ALLOC_EDMA_RINGS_BITS)
+
+
+
+
+/** Bit vector encoding which NotifRings are in a NotifGroup. */
+typedef struct
+{
+  /** The actual bits. */
+  uint64_t ring_mask[4];
+
+} gxio_mpipe_notif_group_bits_t;
+
+
+/** Another name for MPIPE_LBL_INIT_DAT_BSTS_TBL_t. */
+typedef MPIPE_LBL_INIT_DAT_BSTS_TBL_t gxio_mpipe_bucket_info_t;
+
+
+
+/** Eight buffer stack ids. */
+typedef struct
+{
+  /** The stacks. */
+  uint8_t stacks[8];
+
+} gxio_mpipe_rules_stacks_t;
+
+
+/** A destination mac address. */
+typedef struct
+{
+  /** The octets. */
+  uint8_t octets[6];
+
+} gxio_mpipe_rules_dmac_t;
+
+
+/** A vlan. */
+typedef uint16_t gxio_mpipe_rules_vlan_t;
+
+
+
+/** Maximum number of characters in a link name. */
+#define GXIO_MPIPE_LINK_NAME_LEN  32
+
+
+/** Structure holding a link name.  Only needed, and only typedef'ed,
+ *  because the IORPC stub generator only handles types which are single
+ *  words coming before the parameter name. */
+typedef struct
+{
+  /** The name itself. */
+  char name[GXIO_MPIPE_LINK_NAME_LEN];
+}
+_gxio_mpipe_link_name_t;
+
+/** Maximum number of characters in a symbol name. */
+#define GXIO_MPIPE_SYMBOL_NAME_LEN  128
+
+
+/** Structure holding a symbol name.  Only needed, and only typedef'ed,
+ *  because the IORPC stub generator only handles types which are single
+ *  words coming before the parameter name. */
+typedef struct
+{
+  /** The name itself. */
+  char name[GXIO_MPIPE_SYMBOL_NAME_LEN];
+}
+_gxio_mpipe_symbol_name_t;
+
+
+/** Structure holding a MAC address. */
+typedef struct
+{
+  /** The address. */
+  uint8_t mac[6];
+}
+_gxio_mpipe_link_mac_t;
+
+
+
+/** Request shared data permission -- that is, the ability to send and
+ *  receive packets -- on the specified link.  Other processes may also
+ *  request shared data permission on the same link.
+ *
+ *  No more than one of ::GXIO_MPIPE_LINK_DATA, ::GXIO_MPIPE_LINK_NO_DATA,
+ *  or ::GXIO_MPIPE_LINK_EXCL_DATA may be specifed in a gxio_mpipe_link_open()
+ *  call.  If none are specified, ::GXIO_MPIPE_LINK_DATA is assumed.
+ */
+#define GXIO_MPIPE_LINK_DATA               0x00000001UL
+
+/** Do not request data permission on the specified link.
+ *
+ *  No more than one of ::GXIO_MPIPE_LINK_DATA, ::GXIO_MPIPE_LINK_NO_DATA,
+ *  or ::GXIO_MPIPE_LINK_EXCL_DATA may be specifed in a gxio_mpipe_link_open()
+ *  call.  If none are specified, ::GXIO_MPIPE_LINK_DATA is assumed.
+ */
+#define GXIO_MPIPE_LINK_NO_DATA            0x00000002UL
+
+/** Request exclusive data permission -- that is, the ability to send and
+ *  receive packets -- on the specified link.  No other processes may
+ *  request data permission on this link, and if any process already has
+ *  data permission on it, this open will fail.
+ *
+ *  No more than one of ::GXIO_MPIPE_LINK_DATA, ::GXIO_MPIPE_LINK_NO_DATA,
+ *  or ::GXIO_MPIPE_LINK_EXCL_DATA may be specifed in a gxio_mpipe_link_open()
+ *  call.  If none are specified, ::GXIO_MPIPE_LINK_DATA is assumed.
+ */
+#define GXIO_MPIPE_LINK_EXCL_DATA          0x00000004UL
+
+/** Request shared stats permission -- that is, the ability to read and write
+ *  registers which contain link statistics, and to get link attributes --
+ *  on the specified link.  Other processes may also request shared stats
+ *  permission on the same link.
+ *
+ *  No more than one of ::GXIO_MPIPE_LINK_STATS, ::GXIO_MPIPE_LINK_NO_STATS,
+ *  or ::GXIO_MPIPE_LINK_EXCL_STATS may be specifed in a gxio_mpipe_link_open()
+ *  call.  If none are specified, ::GXIO_MPIPE_LINK_STATS is assumed.
+ */
+#define GXIO_MPIPE_LINK_STATS              0x00000008UL
+
+/** Do not request stats permission on the specified link.
+ *
+ *  No more than one of ::GXIO_MPIPE_LINK_STATS, ::GXIO_MPIPE_LINK_NO_STATS,
+ *  or ::GXIO_MPIPE_LINK_EXCL_STATS may be specifed in a gxio_mpipe_link_open()
+ *  call.  If none are specified, ::GXIO_MPIPE_LINK_STATS is assumed.
+ */
+#define GXIO_MPIPE_LINK_NO_STATS           0x00000010UL
+
+/** Request exclusive stats permission -- that is, the ability to read and
+ *  write registers which contain link statistics, and to get link
+ *  attributes -- on the specified link.  No other processes may request
+ *  stats permission on this link, and if any process already
+ *  has stats permission on it, this open will fail.
+ *
+ *  Requesting exclusive stats permission is normally a very bad idea, since
+ *  it prevents programs like mpipe-stat from providing information on this
+ *  link.  Applications should only do this if they use MAC statistics
+ *  registers, and cannot tolerate any of the clear-on-read registers being
+ *  reset by other statistics programs.
+ *
+ *  No more than one of ::GXIO_MPIPE_LINK_STATS, ::GXIO_MPIPE_LINK_NO_STATS,
+ *  or ::GXIO_MPIPE_LINK_EXCL_STATS may be specifed in a gxio_mpipe_link_open()
+ *  call.  If none are specified, ::GXIO_MPIPE_LINK_STATS is assumed.
+ */
+#define GXIO_MPIPE_LINK_EXCL_STATS         0x00000020UL
+
+/** Request shared control permission -- that is, the ability to modify link
+ *  attributes, and read and write MAC and MDIO registers -- on the
+ *  specified link.  Other processes may also request shared control
+ *  permission on the same link.
+ *
+ *  No more than one of ::GXIO_MPIPE_LINK_CTL, ::GXIO_MPIPE_LINK_NO_CTL,
+ *  or ::GXIO_MPIPE_LINK_EXCL_CTL may be specifed in a gxio_mpipe_link_open()
+ *  call.  If none are specified, ::GXIO_MPIPE_LINK_CTL is assumed.
+ */
+#define GXIO_MPIPE_LINK_CTL                0x00000040UL
+
+/** Do not request control permission on the specified link.
+ *
+ *  No more than one of ::GXIO_MPIPE_LINK_CTL, ::GXIO_MPIPE_LINK_NO_CTL,
+ *  or ::GXIO_MPIPE_LINK_EXCL_CTL may be specifed in a gxio_mpipe_link_open()
+ *  call.  If none are specified, ::GXIO_MPIPE_LINK_CTL is assumed.
+ */
+#define GXIO_MPIPE_LINK_NO_CTL             0x00000080UL
+
+/** Request exclusive control permission -- that is, the ability to modify
+ *  link attributes, and read and write MAC and MDIO registers -- on the
+ *  specified link.  No other processes may request control permission on
+ *  this link, and if any process already has control permission on it,
+ *  this open will fail.
+ *
+ *  Requesting exclusive control permission is not always a good idea, since
+ *  it prevents programs like mpipe-link from configuring the link.
+ *
+ *  No more than one of ::GXIO_MPIPE_LINK_CTL, ::GXIO_MPIPE_LINK_NO_CTL,
+ *  or ::GXIO_MPIPE_LINK_EXCL_CTL may be specifed in a gxio_mpipe_link_open()
+ *  call.  If none are specified, ::GXIO_MPIPE_LINK_CTL is assumed.
+ */
+#define GXIO_MPIPE_LINK_EXCL_CTL           0x00000100UL
+
+/** Set the desired state of the link to up, allowing any speeds which are
+ *  supported by the link hardware, as part of this open operation; do not
+ *  change the desired state of the link when it is closed or the process
+ *  exits.  No more than one of ::GXIO_MPIPE_LINK_AUTO_UP,
+ *  ::GXIO_MPIPE_LINK_AUTO_UPDOWN, ::GXIO_MPIPE_LINK_AUTO_DOWN, or
+ *  ::GXIO_MPIPE_LINK_AUTO_NONE may be specifed in a gxio_mpipe_link_open()
+ *  call.  If none are specified, ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed.
+ */
+#define GXIO_MPIPE_LINK_AUTO_UP            0x00000200UL
+
+/** Set the desired state of the link to up, allowing any speeds which are
+ *  supported by the link hardware, as part of this open operation; when the
+ *  link is closed or this process exits, if no other process has the link
+ *  open, set the desired state of the link to down.  No more than one of
+ *  ::GXIO_MPIPE_LINK_AUTO_UP, ::GXIO_MPIPE_LINK_AUTO_UPDOWN,
+ *  ::GXIO_MPIPE_LINK_AUTO_DOWN, or ::GXIO_MPIPE_LINK_AUTO_NONE may be
+ *  specifed in a gxio_mpipe_link_open() call.  If none are specified,
+ *  ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed.
+ */
+#define GXIO_MPIPE_LINK_AUTO_UPDOWN        0x00000400UL
+
+/** Do not change the desired state of the link as part of the open
+ *  operation; when the link is closed or this process exits, if no other
+ *  process has the link open, set the desired state of the link to down.
+ *  No more than one of ::GXIO_MPIPE_LINK_AUTO_UP,
+ *  ::GXIO_MPIPE_LINK_AUTO_UPDOWN, ::GXIO_MPIPE_LINK_AUTO_DOWN, or
+ *  ::GXIO_MPIPE_LINK_AUTO_NONE may be specifed in a gxio_mpipe_link_open()
+ *  call.  If none are specified, ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed.
+ */
+#define GXIO_MPIPE_LINK_AUTO_DOWN          0x00000800UL
+
+/** Do not change the desired state of the link as part of the open
+ *  operation; do not change the desired state of the link when it is
+ *  closed or the process exits.  No more than one of
+ *  ::GXIO_MPIPE_LINK_AUTO_UP, ::GXIO_MPIPE_LINK_AUTO_UPDOWN,
+ *  ::GXIO_MPIPE_LINK_AUTO_DOWN, or ::GXIO_MPIPE_LINK_AUTO_NONE may be
+ *  specifed in a gxio_mpipe_link_open() call.  If none are specified,
+ *  ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed.
+ */
+#define GXIO_MPIPE_LINK_AUTO_NONE          0x00001000UL
+
+/** Request that this open call not complete until the network link is up.
+ *  The process will wait as long as necessary for this to happen;
+ *  applications which wish to abandon waiting for the link after a
+ *  specific time period should not specify this flag when opening a link,
+ *  but should instead call gxio_mpipe_link_wait() afterward.  The link
+ *  must be opened with stats permission.  Note that this flag by itself
+ *  does not change the desired link state; if other open flags or previous
+ *  link state changes have not requested a desired state of up, the open
+ *  call will never complete.  This flag is not available to kernel
+ *  clients.
+ */
+#define GXIO_MPIPE_LINK_WAIT               0x00002000UL
+
+
+/*
+ * Note: link attributes must fit in 24 bits, since we use the top 8 bits
+ * of the IORPC offset word for the channel number.
+ */
+
+/** Determine whether jumbo frames may be received.  If this attribute's
+ *  value value is nonzero, the MAC will accept frames of up to 10240 bytes.
+ *  If the value is zero, the MAC will only accept frames of up to 1544
+ *  bytes.  The default value is zero. */
+#define GXIO_MPIPE_LINK_RECEIVE_JUMBO      0x010000
+
+/** Determine whether to send pause frames on this link if the mPIPE packet
+ *  FIFO is nearly full.  If the value is zero, pause frames are not sent.
+ *  If the value is nonzero, it is the delay value which will be sent in any
+ *  pause frames which are output, in units of 512 bit times.
+ *
+ *  Bear in mind that in almost all circumstances, the mPIPE packet FIFO
+ *  will never fill up, since mPIPE will empty it as fast as or faster than
+ *  the incoming data rate, by either delivering or dropping packets.  The
+ *  only situation in which this is not true is if the memory and cache
+ *  subsystem is extremely heavily loaded, and mPIPE cannot perform DMA of
+ *  packet data to memory in a timely fashion.  In particular, pause frames
+ *  will <em>not</em> be sent if packets cannot be delivered because
+ *  NotifRings are full, buckets are full, or buffers are not available in
+ *  a buffer stack. */
+#define GXIO_MPIPE_LINK_SEND_PAUSE         0x020000
+
+/** Determine whether to suspend output on the receipt of pause frames.
+ *  If the value is nonzero, mPIPE shim will suspend output on the link's
+ *  channel when a pause frame is received.  If the value is zero, pause
+ *  frames will be ignored.  The default value is zero. */
+#define GXIO_MPIPE_LINK_RECEIVE_PAUSE      0x030000
+
+/** Interface MAC address.  The value is a 6-byte MAC address, in the least
+ *  significant 48 bits of the value; in other words, an address which would
+ *  be printed as '12:34:56:78:90:AB' in IEEE 802 canonical format would
+ *  be returned as 0x12345678ab.
+ *
+ *  Depending upon the overall system design, a MAC address may or may not
+ *  be available for each interface.  Note that the interface's MAC address
+ *  does not limit the packets received on its channel, although the
+ *  classifier's rules could be configured to do that.  Similarly, the MAC
+ *  address is not used when transmitting packets, although applications
+ *  could certainly decide to use the assigned address as a source MAC
+ *  address when doing so.  This attribute may only be retrieved with
+ *  gxio_mpipe_link_get_attr(); it may not be modified.
+ */
+#define GXIO_MPIPE_LINK_MAC                0x040000
+
+/** Determine whether to discard egress packets on link down. If this value
+ *  is nonzero, packets sent on this link while the link is down will be
+ *  discarded.  If this value is zero, no packets will be sent on this link
+ *  while it is down.  The default value is one. */
+#define GXIO_MPIPE_LINK_DISCARD_IF_DOWN    0x050000
+
+/** Possible link state.  The value is a combination of link state flags,
+ *  ORed together, that indicate link modes which are actually supported by
+ *  the hardware.  This attribute may only be retrieved with
+ *  gxio_mpipe_link_get_attr(); it may not be modified. */
+#define GXIO_MPIPE_LINK_POSSIBLE_STATE     0x060000
+
+/** Current link state.  The value is a combination of link state flags,
+ *  ORed together, that indicate the current state of the hardware.  If the
+ *  link is down, the value ANDed with ::GXIO_MPIPE_LINK_SPEED will be zero;
+ *  if the link is up, the value ANDed with ::GXIO_MPIPE_LINK_SPEED will
+ *  result in exactly one of the speed values, indicating the current speed.
+ *  This attribute may only be retrieved with gxio_mpipe_link_get_attr(); it
+ *  may not be modified. */
+#define GXIO_MPIPE_LINK_CURRENT_STATE      0x070000
+
+/** Desired link state. The value is a conbination of flags, which specify
+ *  the desired state for the link.  With gxio_mpipe_link_set_attr(), this
+ *  will, in the background, attempt to bring up the link using whichever of
+ *  the requested flags are reasonable, or take down the link if the flags
+ *  are zero.  The actual link up or down operation may happen after this
+ *  call completes.  If the link state changes in the future, the system
+ *  will continue to try to get back to the desired link state; for
+ *  instance, if the link is brought up successfully, and then the network
+ *  cable is disconnected, the link will go down.  However, the desired
+ *  state of the link is still up, so if the cable is reconnected, the link
+ *  will be brought up again.
+ *
+ *  With gxio_mpipe_link_set_attr(), this will indicate the desired state
+ *  for the link, as set with a previous gxio_mpipe_link_set_attr() call,
+ *  or implicitly by a gxio_mpipe_link_open() or link close operation.
+ *  This may not reflect the current state of the link; to get that, use
+ *  ::GXIO_MPIPE_LINK_CURRENT_STATE.
+ */
+#define GXIO_MPIPE_LINK_DESIRED_STATE      0x080000
+
+
+
+/** Link can run, should run, or is running at 10 Mbps. */
+#define GXIO_MPIPE_LINK_10M        0x0000000000000001UL
+
+/** Link can run, should run, or is running at 100 Mbps. */
+#define GXIO_MPIPE_LINK_100M       0x0000000000000002UL
+
+/** Link can run, should run, or is running at 1 Gbps. */
+#define GXIO_MPIPE_LINK_1G         0x0000000000000004UL
+
+/** Link can run, should run, or is running at 10 Gbps. */
+#define GXIO_MPIPE_LINK_10G        0x0000000000000008UL
+
+/** Link can run, should run, or is running at 20 Gbps. */
+#define GXIO_MPIPE_LINK_20G        0x0000000000000010UL
+
+/** Link can run, should run, or is running at 25 Gbps. */
+#define GXIO_MPIPE_LINK_25G        0x0000000000000020UL
+
+/** Link can run, should run, or is running at 50 Gbps. */
+#define GXIO_MPIPE_LINK_50G        0x0000000000000040UL
+
+/** Link should run at the highest speed supported by the link and by
+ *  the device connected to the link.  Only usable as a value for
+ *  the link's desired state; never returned as a value for the current
+ *  or possible states. */
+#define GXIO_MPIPE_LINK_ANYSPEED   0x0000000000000800UL
+
+/** All legal link speeds.  This value is provided for use in extracting
+ *  the speed-related subset of the link state flags; it is not intended
+ *  to be set directly as a value for one of the GXIO_MPIPE_LINK_xxx_STATE
+ *  attributes.  A link is up or is requested to be up if its current or
+ *  desired state, respectively, ANDED with this value, is nonzero. */
+#define GXIO_MPIPE_LINK_SPEED_MASK 0x0000000000000FFFUL
+
+/** Link can run, should run, or is running in MAC loopback mode.  This
+ *  loops transmitted packets back to the receiver, inside the Tile
+ *  Processor. */
+#define GXIO_MPIPE_LINK_LOOP_MAC   0x0000000000001000UL
+
+/** Link can run, should run, or is running in PHY loopback mode.  This
+ *  loops transmitted packets back to the receiver, inside the external
+ *  PHY chip. */
+#define GXIO_MPIPE_LINK_LOOP_PHY   0x0000000000002000UL
+
+/** Link can run, should run, or is running in external loopback mode.
+ *  This requires that an external loopback plug be installed on the
+ *  Ethernet port.  Note that only some links require that this be
+ *  configured via the gxio_mpipe_link routines; other links can do
+ *  external loopack with the plug and no special configuration. */
+#define GXIO_MPIPE_LINK_LOOP_EXT   0x0000000000004000UL
+
+/** All legal loopback types. */
+#define GXIO_MPIPE_LINK_LOOP_MASK  0x000000000000F000UL
+
+/** Link can run, should run, or is running in full-duplex mode.
+ *  If neither ::GXIO_MPIPE_LINK_FDX nor ::GXIO_MPIPE_LINK_HDX are
+ *  specified in a set of desired state flags, both are assumed. */
+#define GXIO_MPIPE_LINK_FDX        0x0000000000010000UL
+
+/** Link can run, should run, or is running in half-duplex mode.
+ *  If neither ::GXIO_MPIPE_LINK_FDX nor ::GXIO_MPIPE_LINK_HDX are
+ *  specified in a set of desired state flags, both are assumed. */
+#define GXIO_MPIPE_LINK_HDX        0x0000000000020000UL
+
+
+/** An individual rule. */
+typedef struct
+{
+  /** The total size. */
+  uint16_t size;
+
+  /** The priority. */
+  int16_t priority;
+
+  /** The "headroom" in each buffer. */
+  uint8_t headroom;
+
+  /** The "tailroom" in each buffer. */
+  uint8_t tailroom;
+
+  /** The "capacity" of the largest buffer. */
+  uint16_t capacity;
+
+  /** The mask for converting a flow hash into a bucket. */
+  uint16_t bucket_mask;
+
+  /** The offset for converting a flow hash into a bucket. */
+  uint16_t bucket_first;
+
+  /** The buffer stack ids. */
+  gxio_mpipe_rules_stacks_t stacks;
+
+  /** The actual channels. */
+  uint32_t channel_bits;
+
+  /** The number of dmacs. */
+  uint16_t num_dmacs;
+
+  /** The number of vlans. */
+  uint16_t num_vlans;
+
+  /** The actual dmacs and vlans. */
+  uint8_t dmacs_and_vlans[];
+
+} gxio_mpipe_rules_rule_t;
+
+
+/** A list of classifier rules. */
+typedef struct
+{
+  /** The offset to the end of the current rule. */
+  uint16_t tail;
+
+  /** The offset to the start of the current rule. */
+  uint16_t head;
+
+  /** The actual rules. */
+  uint8_t rules[4096 - 4];
+
+} gxio_mpipe_rules_list_t;
+
+
+
+
+/** mPIPE statistics structure. These counters include all relevant
+ *  events occurring on all links within the mPIPE shim. */
+typedef struct
+{
+  /** Number of ingress packets dropped for any reason. */
+  uint64_t ingress_drops;
+  /** Number of ingress packets dropped because a buffer stack was empty. */
+  uint64_t ingress_drops_no_buf;
+  /** Number of ingress packets dropped or truncated due to lack of space in
+   *  the iPkt buffer. */
+  uint64_t ingress_drops_ipkt;
+  /** Number of ingress packets dropped by the classifier or load balancer */
+  uint64_t ingress_drops_cls_lb;
+  /** Total number of ingress packets. */
+  uint64_t ingress_packets;
+  /** Total number of egress packets. */
+  uint64_t egress_packets;
+  /** Total number of ingress bytes. */
+  uint64_t ingress_bytes;
+  /** Total number of egress bytes. */
+  uint64_t egress_bytes;
+}
+gxio_mpipe_stats_t;
+
+
+#endif /* _SYS_HV_DRV_MPIPE_INTF_H */
diff --git a/arch/tile/include/hv/drv_trio_intf.h b/arch/tile/include/hv/drv_trio_intf.h
new file mode 100644
index 0000000..ef9f3f5
--- /dev/null
+++ b/arch/tile/include/hv/drv_trio_intf.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * Interface definitions for the trio driver.
+ */
+
+#ifndef _SYS_HV_DRV_TRIO_INTF_H
+#define _SYS_HV_DRV_TRIO_INTF_H
+
+#include <arch/trio.h>
+
+/** The vendor ID for all Tilera processors. */
+#define TILERA_VENDOR_ID 0x1a41
+
+/** The device ID for the Gx36 processor. */
+#define TILERA_GX36_DEV_ID 0x0200
+
+/** Device ID for our internal bridge when running as RC. */
+#define TILERA_GX36_RC_DEV_ID 0x2000
+
+/** Maximum number of TRIO interfaces. */
+#define TILEGX_NUM_TRIO         2
+
+/** Gx36 has max 3 PCIe MACs per TRIO interface. */
+#define TILEGX_TRIO_PCIES       3
+
+/** Specify port properties for a PCIe MAC. */
+struct pcie_port_property
+{
+  /** If true, the link can be configured in PCIe root complex mode. */
+  uint8_t allow_rc: 1;
+
+  /** If true, the link can be configured in PCIe endpoint mode. */
+  uint8_t allow_ep: 1;
+
+  /** If true, the link can be configured in StreamIO mode. */
+  uint8_t allow_sio: 1;
+
+  /** If true, the link is allowed to support 1-lane operation. Software
+   *  will not consider it an error if the link comes up as a x1 link. */
+  uint8_t allow_x1: 1;
+
+  /** If true, the link is allowed to support 2-lane operation. Software
+   *  will not consider it an error if the link comes up as a x2 link. */
+  uint8_t allow_x2: 1;
+
+  /** If true, the link is allowed to support 4-lane operation. Software
+   *  will not consider it an error if the link comes up as a x4 link. */
+  uint8_t allow_x4: 1;
+
+  /** If true, the link is allowed to support 8-lane operation. Software
+   *  will not consider it an error if the link comes up as a x8 link. */
+  uint8_t allow_x8: 1;
+
+  /** Reserved. */
+  uint8_t reserved: 1;
+
+};
+
+/** Configurations can be issued to configure a char stream interrupt. */
+typedef enum pcie_stream_intr_config_sel_e
+{
+  /** Interrupt configuration for memory map regions. */
+  MEM_MAP_SEL,
+
+  /** Interrupt configuration for push DMAs. */
+  PUSH_DMA_SEL,
+
+  /** Interrupt configuration for pull DMAs. */
+  PULL_DMA_SEL,
+}
+pcie_stream_intr_config_sel_t;
+
+
+/** The mmap file offset (PA) of the TRIO config region. */
+#define HV_TRIO_CONFIG_OFFSET                                        \
+  ((unsigned long long)TRIO_MMIO_ADDRESS_SPACE__REGION_VAL_CFG <<   \
+    TRIO_MMIO_ADDRESS_SPACE__REGION_SHIFT)
+
+/** The maximum size of the TRIO config region. */
+#define HV_TRIO_CONFIG_SIZE                                 \
+  (1ULL << TRIO_CFG_REGION_ADDR__REGION_SHIFT)
+
+/** Size of the config region mapped into client. We can't use
+ *  TRIO_MMIO_ADDRESS_SPACE__OFFSET_WIDTH because it
+ *  will require the kernel to allocate 4GB VA space
+ *  from the VMALLOC region which has a total range
+ *  of 4GB.
+ */
+#define HV_TRIO_CONFIG_IOREMAP_SIZE                            \
+  ((uint64_t) 1 << TRIO_CFG_REGION_ADDR__PROT_SHIFT)
+
+/** The mmap file offset (PA) of a scatter queue region. */
+#define HV_TRIO_SQ_OFFSET(queue)                                        \
+  (((unsigned long long)TRIO_MMIO_ADDRESS_SPACE__REGION_VAL_MAP_SQ <<   \
+    TRIO_MMIO_ADDRESS_SPACE__REGION_SHIFT) |                            \
+   ((queue) << TRIO_MAP_SQ_REGION_ADDR__SQ_SEL_SHIFT))
+
+/** The maximum size of a scatter queue region. */
+#define HV_TRIO_SQ_SIZE                                 \
+  (1ULL << TRIO_MAP_SQ_REGION_ADDR__SQ_SEL_SHIFT)
+
+
+/** The "hardware MMIO region" of the first PIO region. */
+#define HV_TRIO_FIRST_PIO_REGION 8
+
+/** The mmap file offset (PA) of a PIO region. */
+#define HV_TRIO_PIO_OFFSET(region)                           \
+  (((unsigned long long)(region) + HV_TRIO_FIRST_PIO_REGION) \
+   << TRIO_PIO_REGIONS_ADDR__REGION_SHIFT)
+
+/** The maximum size of a PIO region. */
+#define HV_TRIO_PIO_SIZE (1ULL << TRIO_PIO_REGIONS_ADDR__ADDR_WIDTH)
+
+
+/** The mmap file offset (PA) of a push DMA region. */
+#define HV_TRIO_PUSH_DMA_OFFSET(ring)                                   \
+  (((unsigned long long)TRIO_MMIO_ADDRESS_SPACE__REGION_VAL_PUSH_DMA << \
+    TRIO_MMIO_ADDRESS_SPACE__REGION_SHIFT) |                            \
+   ((ring) << TRIO_PUSH_DMA_REGION_ADDR__RING_SEL_SHIFT))
+
+/** The mmap file offset (PA) of a pull DMA region. */
+#define HV_TRIO_PULL_DMA_OFFSET(ring)                                   \
+  (((unsigned long long)TRIO_MMIO_ADDRESS_SPACE__REGION_VAL_PULL_DMA << \
+    TRIO_MMIO_ADDRESS_SPACE__REGION_SHIFT) |                            \
+   ((ring) << TRIO_PULL_DMA_REGION_ADDR__RING_SEL_SHIFT))
+
+/** The maximum size of a DMA region. */
+#define HV_TRIO_DMA_REGION_SIZE                         \
+  (1ULL << TRIO_PUSH_DMA_REGION_ADDR__RING_SEL_SHIFT)
+
+
+/** The mmap file offset (PA) of a Mem-Map interrupt region. */
+#define HV_TRIO_MEM_MAP_INTR_OFFSET(map)                                 \
+  (((unsigned long long)TRIO_MMIO_ADDRESS_SPACE__REGION_VAL_MAP_MEM <<   \
+    TRIO_MMIO_ADDRESS_SPACE__REGION_SHIFT) |                            \
+   ((map) << TRIO_MAP_MEM_REGION_ADDR__MAP_SEL_SHIFT))
+
+/** The maximum size of a Mem-Map interrupt region. */
+#define HV_TRIO_MEM_MAP_INTR_SIZE                                 \
+  (1ULL << TRIO_MAP_MEM_REGION_ADDR__MAP_SEL_SHIFT)
+
+
+/** A flag bit indicating a fixed resource allocation. */
+#define HV_TRIO_ALLOC_FIXED 0x01
+
+/** TRIO requires that all mappings have 4kB aligned start addresses. */
+#define HV_TRIO_PAGE_SHIFT 12
+
+/** TRIO requires that all mappings have 4kB aligned start addresses. */
+#define HV_TRIO_PAGE_SIZE (1ull << HV_TRIO_PAGE_SHIFT)
+
+
+/* Specify all PCIe port properties for a TRIO. */
+struct pcie_trio_ports_property
+{
+  struct pcie_port_property ports[TILEGX_TRIO_PCIES];
+};
+
+/* Flags indicating traffic class. */
+#define HV_TRIO_FLAG_TC_SHIFT 4
+#define HV_TRIO_FLAG_TC_RMASK 0xf
+#define HV_TRIO_FLAG_TC(N) \
+  ((((N) & HV_TRIO_FLAG_TC_RMASK) + 1) << HV_TRIO_FLAG_TC_SHIFT)
+
+/* Flags indicating virtual functions. */
+#define HV_TRIO_FLAG_VFUNC_SHIFT 8
+#define HV_TRIO_FLAG_VFUNC_RMASK 0xff
+#define HV_TRIO_FLAG_VFUNC(N) \
+  ((((N) & HV_TRIO_FLAG_VFUNC_RMASK) + 1) << HV_TRIO_FLAG_VFUNC_SHIFT)
+
+
+/* Flag indicating an ordered PIO region. */
+#define HV_TRIO_PIO_FLAG_ORDERED (1 << 16)
+
+/* Flags indicating special types of PIO regions. */
+#define HV_TRIO_PIO_FLAG_SPACE_SHIFT 17
+#define HV_TRIO_PIO_FLAG_SPACE_MASK (0x3 << HV_TRIO_PIO_FLAG_SPACE_SHIFT)
+#define HV_TRIO_PIO_FLAG_CONFIG_SPACE (0x1 << HV_TRIO_PIO_FLAG_SPACE_SHIFT)
+#define HV_TRIO_PIO_FLAG_IO_SPACE (0x2 << HV_TRIO_PIO_FLAG_SPACE_SHIFT)
+
+
+#endif /* _SYS_HV_DRV_TRIO_INTF_H */
diff --git a/arch/tile/include/hv/drv_usb_host_intf.h b/arch/tile/include/hv/drv_usb_host_intf.h
new file mode 100644
index 0000000..24ce774
--- /dev/null
+++ b/arch/tile/include/hv/drv_usb_host_intf.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * Interface definitions for the USB host driver.
+ */
+
+#ifndef _SYS_HV_DRV_USB_HOST_INTF_H
+#define _SYS_HV_DRV_USB_HOST_INTF_H
+
+#include <arch/usb_host.h>
+
+
+/** Offset for the EHCI register MMIO region. */
+#define HV_USB_HOST_MMIO_OFFSET_EHCI ((uint64_t) USB_HOST_HCCAPBASE_REG)
+
+/** Offset for the OHCI register MMIO region. */
+#define HV_USB_HOST_MMIO_OFFSET_OHCI ((uint64_t) USB_HOST_OHCD_HC_REVISION_REG)
+
+/** Size of the register MMIO region.  This turns out to be the same for
+ *  both EHCI and OHCI. */
+#define HV_USB_HOST_MMIO_SIZE ((uint64_t) 0x1000)
+
+/** The number of service domains supported by the USB host shim. */
+#define HV_USB_HOST_NUM_SVC_DOM 1
+
+
+#endif /* _SYS_HV_DRV_USB_HOST_INTF_H */
diff --git a/arch/tile/include/hv/iorpc.h b/arch/tile/include/hv/iorpc.h
new file mode 100644
index 0000000..89c72a5
--- /dev/null
+++ b/arch/tile/include/hv/iorpc.h
@@ -0,0 +1,714 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+#ifndef _HV_IORPC_H_
+#define _HV_IORPC_H_
+
+/**
+ *
+ * Error codes and struct definitions for the IO RPC library.
+ *
+ * The hypervisor's IO RPC component provides a convenient way for
+ * driver authors to proxy system calls between user space, linux, and
+ * the hypervisor driver.  The core of the system is a set of Python
+ * files that take ".idl" files as input and generates the following
+ * source code:
+ *
+ * - _rpc_call() routines for use in userspace IO libraries.  These
+ * routines take an argument list specified in the .idl file, pack the
+ * arguments in to a buffer, and read or write that buffer via the
+ * Linux iorpc driver.
+ *
+ * - dispatch_read() and dispatch_write() routines that hypervisor
+ * drivers can use to implement most of their dev_pread() and
+ * dev_pwrite() methods.  These routines decode the incoming parameter
+ * blob, permission check and translate parameters where appropriate,
+ * and then invoke a callback routine for whichever RPC call has
+ * arrived.  The driver simply implements the set of callback
+ * routines.
+ *
+ * The IO RPC system also includes the Linux 'iorpc' driver, which
+ * proxies calls between the userspace library and the hypervisor
+ * driver.  The Linux driver is almost entirely device agnostic; it
+ * watches for special flags indicating cases where a memory buffer
+ * address might need to be translated, etc.  As a result, driver
+ * writers can avoid many of the problem cases related to registering
+ * hardware resources like memory pages or interrupts.  However, the
+ * drivers must be careful to obey the conventions documented below in
+ * order to work properly with the generic Linux iorpc driver.
+ *
+ * @section iorpc_domains Service Domains
+ *
+ * All iorpc-based drivers must support a notion of service domains.
+ * A service domain is basically an application context - state
+ * indicating resources that are allocated to that particular app
+ * which it may access and (perhaps) other applications may not
+ * access.  Drivers can support any number of service domains they
+ * choose.  In some cases the design is limited by a number of service
+ * domains supported by the IO hardware; in other cases the service
+ * domains are a purely software concept and the driver chooses a
+ * maximum number of domains based on how much state memory it is
+ * willing to preallocate.
+ *
+ * For example, the mPIPE driver only supports as many service domains
+ * as are supported by the mPIPE hardware.  This limitation is
+ * required because the hardware implements its own MMIO protection
+ * scheme to allow large MMIO mappings while still protecting small
+ * register ranges within the page that should only be accessed by the
+ * hypervisor.
+ *
+ * In contrast, drivers with no hardware service domain limitations
+ * (for instance the TRIO shim) can implement an arbitrary number of
+ * service domains.  In these cases, each service domain is limited to
+ * a carefully restricted set of legal MMIO addresses if necessary to
+ * keep one application from corrupting another application's state.
+ *
+ * @section iorpc_conventions System Call Conventions
+ *
+ * The driver's open routine is responsible for allocating a new
+ * service domain for each hv_dev_open() call.  By convention, the
+ * return value from open() should be the service domain number on
+ * success, or GXIO_ERR_NO_SVC_DOM if no more service domains are
+ * available.
+ *
+ * The implementations of hv_dev_pread() and hv_dev_pwrite() are
+ * responsible for validating the devhdl value passed up by the
+ * client.  Since the device handle returned by hv_dev_open() should
+ * embed the positive service domain number, drivers should make sure
+ * that DRV_HDL2BITS(devhdl) is a legal service domain.  If the client
+ * passes an illegal service domain number, the routine should return
+ * GXIO_ERR_INVAL_SVC_DOM.  Once the service domain number has been
+ * validated, the driver can copy to/from the client buffer and call
+ * the dispatch_read() or dispatch_write() methods created by the RPC
+ * generator.
+ *
+ * The hv_dev_close() implementation should reset all service domain
+ * state and put the service domain back on a free list for
+ * reallocation by a future application.  In most cases, this will
+ * require executing a hardware reset or drain flow and denying any
+ * MMIO regions that were created for the service domain.
+ *
+ * @section iorpc_data Special Data Types
+ *
+ * The .idl file syntax allows the creation of syscalls with special
+ * parameters that require permission checks or translations as part
+ * of the system call path.  Because of limitations in the code
+ * generator, APIs are generally limited to just one of these special
+ * parameters per system call, and they are sometimes required to be
+ * the first or last parameter to the call.  Special parameters
+ * include:
+ *
+ * @subsection iorpc_mem_buffer MEM_BUFFER
+ *
+ * The MEM_BUFFER() datatype allows user space to "register" memory
+ * buffers with a device.  Registering memory accomplishes two tasks:
+ * Linux keeps track of all buffers that might be modified by a
+ * hardware device, and the hardware device drivers bind registered
+ * buffers to particular hardware resources like ingress NotifRings.
+ * The MEM_BUFFER() idl syntax can take extra flags like ALIGN_64KB,
+ * ALIGN_SELF_SIZE, and FLAGS indicating that memory buffers must have
+ * certain alignment or that the user should be able to pass a "memory
+ * flags" word specifying attributes like nt_hint or IO cache pinning.
+ * The parser will accept multiple MEM_BUFFER() flags.
+ *
+ * Implementations must obey the following conventions when
+ * registering memory buffers via the iorpc flow.  These rules are a
+ * result of the Linux driver implementation, which needs to keep
+ * track of how many times a particular page has been registered with
+ * the hardware so that it can release the page when all those
+ * registrations are cleared.
+ *
+ * - Memory registrations that refer to a resource which has already
+ * been bound must return GXIO_ERR_ALREADY_INIT.  Thus, it is an
+ * error to register memory twice without resetting (i.e. closing) the
+ * resource in between.  This convention keeps the Linux driver from
+ * having to track which particular devices a page is bound to.
+ *
+ * - At present, a memory registration is only cleared when the
+ * service domain is reset.  In this case, the Linux driver simply
+ * closes the HV device file handle and then decrements the reference
+ * counts of all pages that were previously registered with the
+ * device.
+ *
+ * - In the future, we may add a mechanism for unregistering memory.
+ * One possible implementation would require that the user specify
+ * which buffer is currently registered.  The HV would then verify
+ * that that page was actually the one currently mapped and return
+ * success or failure to Linux, which would then only decrement the
+ * page reference count if the addresses were mapped.  Another scheme
+ * might allow Linux to pass a token to the HV to be returned when the
+ * resource is unmapped.
+ *
+ * @subsection iorpc_interrupt INTERRUPT
+ *
+ * The INTERRUPT .idl datatype allows the client to bind hardware
+ * interrupts to a particular combination of IPI parameters - CPU, IPI
+ * PL, and event bit number.  This data is passed via a special
+ * datatype so that the Linux driver can validate the CPU and PL and
+ * the HV generic iorpc code can translate client CPUs to real CPUs.
+ *
+ * @subsection iorpc_pollfd_setup POLLFD_SETUP
+ *
+ * The POLLFD_SETUP .idl datatype allows the client to set up hardware
+ * interrupt bindings which are received by Linux but which are made
+ * visible to user processes as state transitions on a file descriptor;
+ * this allows user processes to use Linux primitives, such as poll(), to
+ * await particular hardware events.  This data is passed via a special
+ * datatype so that the Linux driver may recognize the pollable file
+ * descriptor and translate it to a set of interrupt target information,
+ * and so that the HV generic iorpc code can translate client CPUs to real
+ * CPUs.
+ *
+ * @subsection iorpc_pollfd POLLFD
+ *
+ * The POLLFD .idl datatype allows manipulation of hardware interrupt
+ * bindings set up via the POLLFD_SETUP datatype; common operations are
+ * resetting the state of the requested interrupt events, and unbinding any
+ * bound interrupts.  This data is passed via a special datatype so that
+ * the Linux driver may recognize the pollable file descriptor and
+ * translate it to an interrupt identifier previously supplied by the
+ * hypervisor as the result of an earlier pollfd_setup operation.
+ *
+ * @subsection iorpc_blob BLOB
+ *
+ * The BLOB .idl datatype allows the client to write an arbitrary
+ * length string of bytes up to the hypervisor driver.  This can be
+ * useful for passing up large, arbitrarily structured data like
+ * classifier programs.  The iorpc stack takes care of validating the
+ * buffer VA and CPA as the data passes up to the hypervisor.  Unlike
+ * MEM_BUFFER(), the buffer is not registered - Linux does not bump
+ * page refcounts and the HV driver should not reuse the buffer once
+ * the system call is complete.
+ *
+ * @section iorpc_translation Translating User Space Calls
+ *
+ * The ::iorpc_offset structure describes the formatting of the offset
+ * that is passed to pread() or pwrite() as part of the generated RPC code.
+ * When the user calls up to Linux, the rpc code fills in all the fields of
+ * the offset, including a 16-bit opcode, a 16 bit format indicator, and 32
+ * bits of user-specified "sub-offset".  The opcode indicates which syscall
+ * is being requested.  The format indicates whether there is a "prefix
+ * struct" at the start of the memory buffer passed to pwrite(), and if so
+ * what data is in that prefix struct.  These prefix structs are used to
+ * implement special datatypes like MEM_BUFFER() and INTERRUPT - we arrange
+ * to put data that needs translation and permission checks at the start of
+ * the buffer so that the Linux driver and generic portions of the HV iorpc
+ * code can easily access the data.  The 32 bits of user-specified
+ * "sub-offset" are most useful for pread() calls where the user needs to
+ * also pass in a few bits indicating which register to read, etc.
+ *
+ * The Linux iorpc driver watches for system calls that contain prefix
+ * structs so that it can translate parameters and bump reference
+ * counts as appropriate.  It does not (currently) have any knowledge
+ * of the per-device opcodes - it doesn't care what operation you're
+ * doing to mPIPE, so long as it can do all the generic book-keeping.
+ * The hv/iorpc.h header file defines all of the generic encoding bits
+ * needed to translate iorpc calls without knowing which particular
+ * opcode is being issued.
+ *
+ * @section iorpc_globals Global iorpc Calls
+ *
+ * Implementing mmap() required adding some special iorpc syscalls
+ * that are only called by the Linux driver, never by userspace.
+ * These include get_mmio_base() and check_mmio_offset().  These
+ * routines are described in globals.idl and must be included in every
+ * iorpc driver.  By providing these routines in every driver, Linux's
+ * mmap implementation can easily get the PTE bits it needs and
+ * validate the PA offset without needing to know the per-device
+ * opcodes to perform those tasks.
+ *
+ * @section iorpc_kernel Supporting gxio APIs in the Kernel
+ *
+ * The iorpc code generator also supports generation of kernel code
+ * implementing the gxio APIs.  This capability is currently used by
+ * the mPIPE network driver, and will likely be used by the TRIO root
+ * complex and endpoint drivers and perhaps an in-kernel crypto
+ * driver.  Each driver that wants to instantiate iorpc calls in the
+ * kernel needs to generate a kernel version of the generate rpc code
+ * and (probably) copy any related gxio source files into the kernel.
+ * The mPIPE driver provides a good example of this pattern.
+ */
+
+#ifdef __KERNEL__
+#include <linux/stddef.h>
+#else
+#include <stddef.h>
+#endif
+
+#if defined(__HV__)
+#include <hv/hypervisor.h>
+#elif defined(__KERNEL__)
+#include "hypervisor.h"
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
+
+/** Code indicating translation services required within the RPC path.
+ * These indicate whether there is a translatable struct at the start
+ * of the RPC buffer and what information that struct contains.
+ */
+enum iorpc_format_e
+{
+  /** No translation required, no prefix struct. */
+  IORPC_FORMAT_NONE,
+
+  /** No translation required, no prefix struct, no access to this
+   *  operation from user space. */
+  IORPC_FORMAT_NONE_NOUSER,
+
+  /** Prefix struct contains user VA and size. */
+  IORPC_FORMAT_USER_MEM,
+
+  /** Prefix struct contains CPA, size, and homing bits. */
+  IORPC_FORMAT_KERNEL_MEM,
+
+  /** Prefix struct contains interrupt. */
+  IORPC_FORMAT_KERNEL_INTERRUPT,
+
+  /** Prefix struct contains user-level interrupt. */
+  IORPC_FORMAT_USER_INTERRUPT,
+
+  /** Prefix struct contains pollfd_setup (interrupt information). */
+  IORPC_FORMAT_KERNEL_POLLFD_SETUP,
+
+  /** Prefix struct contains user-level pollfd_setup (file descriptor). */
+  IORPC_FORMAT_USER_POLLFD_SETUP,
+
+  /** Prefix struct contains pollfd (interrupt cookie). */
+  IORPC_FORMAT_KERNEL_POLLFD,
+
+  /** Prefix struct contains user-level pollfd (file descriptor). */
+  IORPC_FORMAT_USER_POLLFD,
+};
+
+
+/** Generate an opcode given format and code. */
+#define IORPC_OPCODE(FORMAT, CODE) (((FORMAT) << 16) | (CODE))
+
+/** The offset passed through the read() and write() system calls
+    combines an opcode with 32 bits of user-specified offset. */
+union iorpc_offset
+{
+#ifndef __BIG_ENDIAN__
+  uint64_t offset;              /**< All bits. */
+
+  struct
+  {
+    uint16_t code;              /**< RPC code. */
+    uint16_t format;            /**< iorpc_format_e */
+    uint32_t sub_offset;        /**< caller-specified offset. */
+  };
+
+  uint32_t opcode;              /**< Opcode combines code & format. */
+#else
+  uint64_t offset;              /**< All bits. */
+
+  struct
+  {
+    uint32_t sub_offset;        /**< caller-specified offset. */
+    uint16_t format;            /**< iorpc_format_e */
+    uint16_t code;              /**< RPC code. */
+  };
+
+  struct
+  {
+    uint32_t padding;
+    uint32_t opcode;              /**< Opcode combines code & format. */
+  };
+#endif
+};
+
+
+/** Homing and cache hinting bits that can be used by IO devices. */
+struct iorpc_mem_attr
+{
+  unsigned int lotar_x:4;       /**< lotar X bits (or Gx page_mask). */
+  unsigned int lotar_y:4;       /**< lotar Y bits (or Gx page_offset). */
+  unsigned int hfh:1;           /**< Uses hash-for-home. */
+  unsigned int nt_hint:1;       /**< Non-temporal hint. */
+  unsigned int io_pin:1;        /**< Only fill 'IO' cache ways. */
+};
+
+/** Set the nt_hint bit. */
+#define IORPC_MEM_BUFFER_FLAG_NT_HINT (1 << 0)
+
+/** Set the IO pin bit. */
+#define IORPC_MEM_BUFFER_FLAG_IO_PIN (1 << 1)
+
+
+/** A structure used to describe memory registration.  Different
+    protection levels describe memory differently, so this union
+    contains all the different possible descriptions.  As a request
+    moves up the call chain, each layer translates from one
+    description format to the next.  In particular, the Linux iorpc
+    driver translates user VAs into CPAs and homing parameters. */
+union iorpc_mem_buffer
+{
+  struct
+  {
+    uint64_t va;                /**< User virtual address. */
+    uint64_t size;              /**< Buffer size. */
+    unsigned int flags;         /**< nt_hint, IO pin. */
+  }
+  user;                         /**< Buffer as described by user apps. */
+
+  struct
+  {
+    unsigned long long cpa;     /**< Client physical address. */
+#if defined(__KERNEL__) || defined(__HV__)
+    size_t size;                /**< Buffer size. */
+    HV_PTE pte;                 /**< PTE describing memory homing. */
+#else
+    uint64_t size;
+    uint64_t pte;
+#endif
+    unsigned int flags;         /**< nt_hint, IO pin. */
+  }
+  kernel;                       /**< Buffer as described by kernel. */
+
+  struct
+  {
+    unsigned long long pa;      /**< Physical address. */
+    size_t size;                /**< Buffer size. */
+    struct iorpc_mem_attr attr;      /**< Homing and locality hint bits. */
+  }
+  hv;                           /**< Buffer parameters for HV driver. */
+};
+
+
+/** A structure used to describe interrupts.  The format differs slightly
+ *  for user and kernel interrupts.  As with the mem_buffer_t, translation
+ *  between the formats is done at each level. */
+union iorpc_interrupt
+{
+  struct
+  {
+    int cpu;   /**< CPU. */
+    int event; /**< evt_num */
+  }
+  user;        /**< Interrupt as described by user applications. */
+
+  struct
+  {
+    int x;     /**< X coord. */
+    int y;     /**< Y coord. */
+    int ipi;   /**< int_num */
+    int event; /**< evt_num */
+  }
+  kernel;      /**< Interrupt as described by the kernel. */
+
+};
+
+
+/** A structure used to describe interrupts used with poll().  The format
+ *  differs significantly for requests from user to kernel, and kernel to
+ *  hypervisor.  As with the mem_buffer_t, translation between the formats
+ *  is done at each level. */
+union iorpc_pollfd_setup
+{
+  struct
+  {
+    int fd;    /**< Pollable file descriptor. */
+  }
+  user;        /**< pollfd_setup as described by user applications. */
+
+  struct
+  {
+    int x;     /**< X coord. */
+    int y;     /**< Y coord. */
+    int ipi;   /**< int_num */
+    int event; /**< evt_num */
+  }
+  kernel;      /**< pollfd_setup as described by the kernel. */
+
+};
+
+
+/** A structure used to describe previously set up interrupts used with
+ *  poll().  The format differs significantly for requests from user to
+ *  kernel, and kernel to hypervisor.  As with the mem_buffer_t, translation
+ *  between the formats is done at each level. */
+union iorpc_pollfd
+{
+  struct
+  {
+    int fd;    /**< Pollable file descriptor. */
+  }
+  user;        /**< pollfd as described by user applications. */
+
+  struct
+  {
+    int cookie; /**< hv cookie returned by the pollfd_setup operation. */
+  }
+  kernel;      /**< pollfd as described by the kernel. */
+
+};
+
+
+/** The various iorpc devices use error codes from -1100 to -1299.
+ *
+ * This range is distinct from netio (-700 to -799), the hypervisor
+ * (-800 to -899), tilepci (-900 to -999), ilib (-1000 to -1099),
+ * gxcr (-1300 to -1399) and gxpci (-1400 to -1499).
+ */
+enum gxio_err_e {
+
+  /** Largest iorpc error number. */
+  GXIO_ERR_MAX = -1101,
+
+
+  /********************************************************/
+  /*                   Generic Error Codes                */
+  /********************************************************/
+
+  /** Bad RPC opcode - possible version incompatibility. */
+  GXIO_ERR_OPCODE = -1101,
+
+  /** Invalid parameter. */
+  GXIO_ERR_INVAL = -1102,
+
+  /** Memory buffer did not meet alignment requirements. */
+  GXIO_ERR_ALIGNMENT = -1103,
+
+  /** Memory buffers must be coherent and cacheable. */
+  GXIO_ERR_COHERENCE = -1104,
+
+  /** Resource already initialized. */
+  GXIO_ERR_ALREADY_INIT = -1105,
+
+  /** No service domains available. */
+  GXIO_ERR_NO_SVC_DOM = -1106,
+
+  /** Illegal service domain number. */
+  GXIO_ERR_INVAL_SVC_DOM = -1107,
+
+  /** Illegal MMIO address. */
+  GXIO_ERR_MMIO_ADDRESS = -1108,
+
+  /** Illegal interrupt binding. */
+  GXIO_ERR_INTERRUPT = -1109,
+
+  /** Unreasonable client memory. */
+  GXIO_ERR_CLIENT_MEMORY = -1110,
+
+  /** No more IOTLB entries. */
+  GXIO_ERR_IOTLB_ENTRY = -1111,
+
+  /** Invalid memory size. */
+  GXIO_ERR_INVAL_MEMORY_SIZE = -1112,
+
+  /** Unsupported operation. */
+  GXIO_ERR_UNSUPPORTED_OP = -1113,
+
+  /** Insufficient DMA credits. */
+  GXIO_ERR_DMA_CREDITS = -1114,
+
+  /** Operation timed out. */
+  GXIO_ERR_TIMEOUT = -1115,
+
+  /** No such device or object. */
+  GXIO_ERR_NO_DEVICE = -1116,
+
+  /** Device or resource busy. */
+  GXIO_ERR_BUSY = -1117,
+
+  /** I/O error. */
+  GXIO_ERR_IO = -1118,
+
+  /** Permissions error. */
+  GXIO_ERR_PERM = -1119,
+
+
+
+  /********************************************************/
+  /*                 Test Device Error Codes              */
+  /********************************************************/
+
+  /** Illegal register number. */
+  GXIO_TEST_ERR_REG_NUMBER = -1120,
+
+  /** Illegal buffer slot. */
+  GXIO_TEST_ERR_BUFFER_SLOT = -1121,
+
+
+  /********************************************************/
+  /*                    MPIPE Error Codes                 */
+  /********************************************************/
+
+
+  /** Invalid buffer size. */
+  GXIO_MPIPE_ERR_INVAL_BUFFER_SIZE = -1131,
+
+  /** Cannot allocate buffer stack. */
+  GXIO_MPIPE_ERR_NO_BUFFER_STACK = -1140,
+
+  /** Invalid buffer stack number. */
+  GXIO_MPIPE_ERR_BAD_BUFFER_STACK = -1141,
+
+  /** Cannot allocate NotifRing. */
+  GXIO_MPIPE_ERR_NO_NOTIF_RING = -1142,
+
+  /** Invalid NotifRing number. */
+  GXIO_MPIPE_ERR_BAD_NOTIF_RING = -1143,
+
+  /** Cannot allocate NotifGroup. */
+  GXIO_MPIPE_ERR_NO_NOTIF_GROUP = -1144,
+
+  /** Invalid NotifGroup number. */
+  GXIO_MPIPE_ERR_BAD_NOTIF_GROUP = -1145,
+
+  /** Cannot allocate bucket. */
+  GXIO_MPIPE_ERR_NO_BUCKET = -1146,
+
+  /** Invalid bucket number. */
+  GXIO_MPIPE_ERR_BAD_BUCKET = -1147,
+
+  /** Cannot allocate eDMA ring. */
+  GXIO_MPIPE_ERR_NO_EDMA_RING = -1148,
+
+  /** Invalid eDMA ring number. */
+  GXIO_MPIPE_ERR_BAD_EDMA_RING = -1149,
+
+  /** Invalid channel number. */
+  GXIO_MPIPE_ERR_BAD_CHANNEL = -1150,
+
+  /** Bad configuration. */
+  GXIO_MPIPE_ERR_BAD_CONFIG = -1151,
+
+  /** Empty iqueue. */
+  GXIO_MPIPE_ERR_IQUEUE_EMPTY = -1152,
+
+  /** Empty rules. */
+  GXIO_MPIPE_ERR_RULES_EMPTY = -1160,
+
+  /** Full rules. */
+  GXIO_MPIPE_ERR_RULES_FULL = -1161,
+
+  /** Corrupt rules. */
+  GXIO_MPIPE_ERR_RULES_CORRUPT = -1162,
+
+  /** Invalid rules. */
+  GXIO_MPIPE_ERR_RULES_INVALID = -1163,
+
+  /** Classifier is too big. */
+  GXIO_MPIPE_ERR_CLASSIFIER_TOO_BIG = -1170,
+
+  /** Classifier is too complex. */
+  GXIO_MPIPE_ERR_CLASSIFIER_TOO_COMPLEX = -1171,
+
+  /** Classifier has bad header. */
+  GXIO_MPIPE_ERR_CLASSIFIER_BAD_HEADER = -1172,
+
+  /** Classifier has bad contents. */
+  GXIO_MPIPE_ERR_CLASSIFIER_BAD_CONTENTS = -1173,
+
+  /** Classifier encountered invalid symbol. */
+  GXIO_MPIPE_ERR_CLASSIFIER_INVAL_SYMBOL = -1174,
+
+  /** Classifier encountered invalid bounds. */
+  GXIO_MPIPE_ERR_CLASSIFIER_INVAL_BOUNDS = -1175,
+
+  /** Classifier encountered invalid relocation. */
+  GXIO_MPIPE_ERR_CLASSIFIER_INVAL_RELOCATION = -1176,
+
+  /** Classifier encountered undefined symbol. */
+  GXIO_MPIPE_ERR_CLASSIFIER_UNDEF_SYMBOL = -1177,
+
+
+  /********************************************************/
+  /*                    TRIO  Error Codes                 */
+  /********************************************************/
+
+  /** Cannot allocate memory map region. */
+  GXIO_TRIO_ERR_NO_MEMORY_MAP = -1180,
+
+  /** Invalid memory map region number. */
+  GXIO_TRIO_ERR_BAD_MEMORY_MAP = -1181,
+
+  /** Cannot allocate scatter queue. */
+  GXIO_TRIO_ERR_NO_SCATTER_QUEUE = -1182,
+
+  /** Invalid scatter queue number. */
+  GXIO_TRIO_ERR_BAD_SCATTER_QUEUE = -1183,
+
+  /** Cannot allocate push DMA ring. */
+  GXIO_TRIO_ERR_NO_PUSH_DMA_RING = -1184,
+
+  /** Invalid push DMA ring index. */
+  GXIO_TRIO_ERR_BAD_PUSH_DMA_RING = -1185,
+
+  /** Cannot allocate pull DMA ring. */
+  GXIO_TRIO_ERR_NO_PULL_DMA_RING = -1186,
+
+  /** Invalid pull DMA ring index. */
+  GXIO_TRIO_ERR_BAD_PULL_DMA_RING = -1187,
+
+  /** Cannot allocate PIO region. */
+  GXIO_TRIO_ERR_NO_PIO = -1188,
+
+  /** Invalid PIO region index. */
+  GXIO_TRIO_ERR_BAD_PIO = -1189,
+
+  /** Cannot allocate ASID. */
+  GXIO_TRIO_ERR_NO_ASID = -1190,
+
+  /** Invalid ASID. */
+  GXIO_TRIO_ERR_BAD_ASID = -1191,
+
+
+  /********************************************************/
+  /*                    MICA Error Codes                  */
+  /********************************************************/
+
+  /** No such accelerator type. */
+  GXIO_MICA_ERR_BAD_ACCEL_TYPE = -1220,
+
+  /** Cannot allocate context. */
+  GXIO_MICA_ERR_NO_CONTEXT = -1221,
+
+  /** PKA command queue is full, can't add another command. */
+  GXIO_MICA_ERR_PKA_CMD_QUEUE_FULL = -1222,
+
+  /** PKA result queue is empty, can't get a result from the queue. */
+  GXIO_MICA_ERR_PKA_RESULT_QUEUE_EMPTY = -1223,
+
+  /********************************************************/
+  /*                    GPIO Error Codes                  */
+  /********************************************************/
+
+  /** Pin not available.  Either the physical pin does not exist, or
+   *  it is reserved by the hypervisor for system usage. */
+  GXIO_GPIO_ERR_PIN_UNAVAILABLE = -1240,
+
+  /** Pin busy.  The pin exists, and is available for use via GXIO, but
+   *  it has been attached by some other process or driver. */
+  GXIO_GPIO_ERR_PIN_BUSY = -1241,
+
+  /** Cannot access unattached pin.  One or more of the pins being
+   *  manipulated by this call are not attached to the requesting
+   *  context. */
+  GXIO_GPIO_ERR_PIN_UNATTACHED = -1242,
+
+  /** Invalid I/O mode for pin.  The wiring of the pin in the system
+   *  is such that the I/O mode or electrical control parameters
+   *  requested could cause damage. */
+  GXIO_GPIO_ERR_PIN_INVALID_MODE = -1243,
+
+  /** Smallest iorpc error number. */
+  GXIO_ERR_MIN = -1299
+};
+
+
+#endif /* !_HV_IORPC_H_ */
diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile
index 5de9924..5334be8 100644
--- a/arch/tile/kernel/Makefile
+++ b/arch/tile/kernel/Makefile
@@ -14,4 +14,9 @@ obj-$(CONFIG_SMP)		+= smpboot.o smp.o tlb.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel_$(BITS).o
+ifdef CONFIG_TILEGX
+obj-$(CONFIG_PCI)		+= pci_gx.o
+else
 obj-$(CONFIG_PCI)		+= pci.o
+endif
+obj-$(CONFIG_TILE_USB)		+= usb.o
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index 474571b..3690f01 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -411,15 +411,6 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	regs->regs[1] = ptr_to_compat_reg(&frame->info);
 	regs->regs[2] = ptr_to_compat_reg(&frame->uc);
 	regs->flags |= PT_FLAGS_CALLER_SAVES;
-
-	/*
-	 * Notify any tracer that was single-stepping it.
-	 * The tracer may want to single-step inside the
-	 * handler too.
-	 */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 	return 0;
 
 give_sigsegv:
diff --git a/arch/tile/kernel/pci-dma.c b/arch/tile/kernel/pci-dma.c
index b3ed19f..b9fe80e 100644
--- a/arch/tile/kernel/pci-dma.c
+++ b/arch/tile/kernel/pci-dma.c
@@ -14,6 +14,7 @@
 
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
+#include <linux/swiotlb.h>
 #include <linux/vmalloc.h>
 #include <linux/export.h>
 #include <asm/tlbflush.h>
@@ -22,13 +23,18 @@
 /* Generic DMA mapping functions: */
 
 /*
- * Allocate what Linux calls "coherent" memory, which for us just
- * means uncached.
+ * Allocate what Linux calls "coherent" memory.  On TILEPro this is
+ * uncached memory; on TILE-Gx it is hash-for-home memory.
  */
-void *dma_alloc_coherent(struct device *dev,
-			 size_t size,
-			 dma_addr_t *dma_handle,
-			 gfp_t gfp)
+#ifdef __tilepro__
+#define PAGE_HOME_DMA PAGE_HOME_UNCACHED
+#else
+#define PAGE_HOME_DMA PAGE_HOME_HASH
+#endif
+
+static void *tile_dma_alloc_coherent(struct device *dev, size_t size,
+				     dma_addr_t *dma_handle, gfp_t gfp,
+				     struct dma_attrs *attrs)
 {
 	u64 dma_mask = dev->coherent_dma_mask ?: DMA_BIT_MASK(32);
 	int node = dev_to_node(dev);
@@ -39,39 +45,42 @@ void *dma_alloc_coherent(struct device *dev,
 	gfp |= __GFP_ZERO;
 
 	/*
-	 * By forcing NUMA node 0 for 32-bit masks we ensure that the
-	 * high 32 bits of the resulting PA will be zero.  If the mask
-	 * size is, e.g., 24, we may still not be able to guarantee a
-	 * suitable memory address, in which case we will return NULL.
-	 * But such devices are uncommon.
+	 * If the mask specifies that the memory be in the first 4 GB, then
+	 * we force the allocation to come from the DMA zone.  We also
+	 * force the node to 0 since that's the only node where the DMA
+	 * zone isn't empty.  If the mask size is smaller than 32 bits, we
+	 * may still not be able to guarantee a suitable memory address, in
+	 * which case we will return NULL.  But such devices are uncommon.
 	 */
-	if (dma_mask <= DMA_BIT_MASK(32))
+	if (dma_mask <= DMA_BIT_MASK(32)) {
+		gfp |= GFP_DMA;
 		node = 0;
+	}
 
-	pg = homecache_alloc_pages_node(node, gfp, order, PAGE_HOME_UNCACHED);
+	pg = homecache_alloc_pages_node(node, gfp, order, PAGE_HOME_DMA);
 	if (pg == NULL)
 		return NULL;
 
 	addr = page_to_phys(pg);
 	if (addr + size > dma_mask) {
-		homecache_free_pages(addr, order);
+		__homecache_free_pages(pg, order);
 		return NULL;
 	}
 
 	*dma_handle = addr;
+
 	return page_address(pg);
 }
-EXPORT_SYMBOL(dma_alloc_coherent);
 
 /*
- * Free memory that was allocated with dma_alloc_coherent.
+ * Free memory that was allocated with tile_dma_alloc_coherent.
  */
-void dma_free_coherent(struct device *dev, size_t size,
-		  void *vaddr, dma_addr_t dma_handle)
+static void tile_dma_free_coherent(struct device *dev, size_t size,
+				   void *vaddr, dma_addr_t dma_handle,
+				   struct dma_attrs *attrs)
 {
 	homecache_free_pages((unsigned long)vaddr, get_order(size));
 }
-EXPORT_SYMBOL(dma_free_coherent);
 
 /*
  * The map routines "map" the specified address range for DMA
@@ -87,52 +96,285 @@ EXPORT_SYMBOL(dma_free_coherent);
  * can count on nothing having been touched.
  */
 
-/* Flush a PA range from cache page by page. */
-static void __dma_map_pa_range(dma_addr_t dma_addr, size_t size)
+/* Set up a single page for DMA access. */
+static void __dma_prep_page(struct page *page, unsigned long offset,
+			    size_t size, enum dma_data_direction direction)
+{
+	/*
+	 * Flush the page from cache if necessary.
+	 * On tilegx, data is delivered to hash-for-home L3; on tilepro,
+	 * data is delivered direct to memory.
+	 *
+	 * NOTE: If we were just doing DMA_TO_DEVICE we could optimize
+	 * this to be a "flush" not a "finv" and keep some of the
+	 * state in cache across the DMA operation, but it doesn't seem
+	 * worth creating the necessary flush_buffer_xxx() infrastructure.
+	 */
+	int home = page_home(page);
+	switch (home) {
+	case PAGE_HOME_HASH:
+#ifdef __tilegx__
+		return;
+#endif
+		break;
+	case PAGE_HOME_UNCACHED:
+#ifdef __tilepro__
+		return;
+#endif
+		break;
+	case PAGE_HOME_IMMUTABLE:
+		/* Should be going to the device only. */
+		BUG_ON(direction == DMA_FROM_DEVICE ||
+		       direction == DMA_BIDIRECTIONAL);
+		return;
+	case PAGE_HOME_INCOHERENT:
+		/* Incoherent anyway, so no need to work hard here. */
+		return;
+	default:
+		BUG_ON(home < 0 || home >= NR_CPUS);
+		break;
+	}
+	homecache_finv_page(page);
+
+#ifdef DEBUG_ALIGNMENT
+	/* Warn if the region isn't cacheline aligned. */
+	if (offset & (L2_CACHE_BYTES - 1) || (size & (L2_CACHE_BYTES - 1)))
+		pr_warn("Unaligned DMA to non-hfh memory: PA %#llx/%#lx\n",
+			PFN_PHYS(page_to_pfn(page)) + offset, size);
+#endif
+}
+
+/* Make the page ready to be read by the core. */
+static void __dma_complete_page(struct page *page, unsigned long offset,
+				size_t size, enum dma_data_direction direction)
+{
+#ifdef __tilegx__
+	switch (page_home(page)) {
+	case PAGE_HOME_HASH:
+		/* I/O device delivered data the way the cpu wanted it. */
+		break;
+	case PAGE_HOME_INCOHERENT:
+		/* Incoherent anyway, so no need to work hard here. */
+		break;
+	case PAGE_HOME_IMMUTABLE:
+		/* Extra read-only copies are not a problem. */
+		break;
+	default:
+		/* Flush the bogus hash-for-home I/O entries to memory. */
+		homecache_finv_map_page(page, PAGE_HOME_HASH);
+		break;
+	}
+#endif
+}
+
+static void __dma_prep_pa_range(dma_addr_t dma_addr, size_t size,
+				enum dma_data_direction direction)
 {
 	struct page *page = pfn_to_page(PFN_DOWN(dma_addr));
-	size_t bytesleft = PAGE_SIZE - (dma_addr & (PAGE_SIZE - 1));
+	unsigned long offset = dma_addr & (PAGE_SIZE - 1);
+	size_t bytes = min(size, (size_t)(PAGE_SIZE - offset));
+
+	while (size != 0) {
+		__dma_prep_page(page, offset, bytes, direction);
+		size -= bytes;
+		++page;
+		offset = 0;
+		bytes = min((size_t)PAGE_SIZE, size);
+	}
+}
 
-	while ((ssize_t)size > 0) {
-		/* Flush the page. */
-		homecache_flush_cache(page++, 0);
+static void __dma_complete_pa_range(dma_addr_t dma_addr, size_t size,
+				    enum dma_data_direction direction)
+{
+	struct page *page = pfn_to_page(PFN_DOWN(dma_addr));
+	unsigned long offset = dma_addr & (PAGE_SIZE - 1);
+	size_t bytes = min(size, (size_t)(PAGE_SIZE - offset));
+
+	while (size != 0) {
+		__dma_complete_page(page, offset, bytes, direction);
+		size -= bytes;
+		++page;
+		offset = 0;
+		bytes = min((size_t)PAGE_SIZE, size);
+	}
+}
+
+static int tile_dma_map_sg(struct device *dev, struct scatterlist *sglist,
+			   int nents, enum dma_data_direction direction,
+			   struct dma_attrs *attrs)
+{
+	struct scatterlist *sg;
+	int i;
+
+	BUG_ON(!valid_dma_direction(direction));
+
+	WARN_ON(nents == 0 || sglist->length == 0);
 
-		/* Figure out if we need to continue on the next page. */
-		size -= bytesleft;
-		bytesleft = PAGE_SIZE;
+	for_each_sg(sglist, sg, nents, i) {
+		sg->dma_address = sg_phys(sg);
+		__dma_prep_pa_range(sg->dma_address, sg->length, direction);
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+		sg->dma_length = sg->length;
+#endif
 	}
+
+	return nents;
 }
 
-/*
- * dma_map_single can be passed any memory address, and there appear
- * to be no alignment constraints.
- *
- * There is a chance that the start of the buffer will share a cache
- * line with some other data that has been touched in the meantime.
- */
-dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-	       enum dma_data_direction direction)
+static void tile_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
+			      int nents, enum dma_data_direction direction,
+			      struct dma_attrs *attrs)
+{
+	struct scatterlist *sg;
+	int i;
+
+	BUG_ON(!valid_dma_direction(direction));
+	for_each_sg(sglist, sg, nents, i) {
+		sg->dma_address = sg_phys(sg);
+		__dma_complete_pa_range(sg->dma_address, sg->length,
+					direction);
+	}
+}
+
+static dma_addr_t tile_dma_map_page(struct device *dev, struct page *page,
+				    unsigned long offset, size_t size,
+				    enum dma_data_direction direction,
+				    struct dma_attrs *attrs)
 {
-	dma_addr_t dma_addr = __pa(ptr);
+	BUG_ON(!valid_dma_direction(direction));
+
+	BUG_ON(offset + size > PAGE_SIZE);
+	__dma_prep_page(page, offset, size, direction);
 
+	return page_to_pa(page) + offset;
+}
+
+static void tile_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+				size_t size, enum dma_data_direction direction,
+				struct dma_attrs *attrs)
+{
 	BUG_ON(!valid_dma_direction(direction));
-	WARN_ON(size == 0);
 
-	__dma_map_pa_range(dma_addr, size);
+	__dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)),
+			    dma_address & PAGE_OFFSET, size, direction);
+}
 
-	return dma_addr;
+static void tile_dma_sync_single_for_cpu(struct device *dev,
+					 dma_addr_t dma_handle,
+					 size_t size,
+					 enum dma_data_direction direction)
+{
+	BUG_ON(!valid_dma_direction(direction));
+
+	__dma_complete_pa_range(dma_handle, size, direction);
+}
+
+static void tile_dma_sync_single_for_device(struct device *dev,
+					    dma_addr_t dma_handle, size_t size,
+					    enum dma_data_direction direction)
+{
+	__dma_prep_pa_range(dma_handle, size, direction);
 }
-EXPORT_SYMBOL(dma_map_single);
 
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-		 enum dma_data_direction direction)
+static void tile_dma_sync_sg_for_cpu(struct device *dev,
+				     struct scatterlist *sglist, int nelems,
+				     enum dma_data_direction direction)
 {
+	struct scatterlist *sg;
+	int i;
+
+	BUG_ON(!valid_dma_direction(direction));
+	WARN_ON(nelems == 0 || sglist->length == 0);
+
+	for_each_sg(sglist, sg, nelems, i) {
+		dma_sync_single_for_cpu(dev, sg->dma_address,
+					sg_dma_len(sg), direction);
+	}
+}
+
+static void tile_dma_sync_sg_for_device(struct device *dev,
+					struct scatterlist *sglist, int nelems,
+					enum dma_data_direction direction)
+{
+	struct scatterlist *sg;
+	int i;
+
 	BUG_ON(!valid_dma_direction(direction));
+	WARN_ON(nelems == 0 || sglist->length == 0);
+
+	for_each_sg(sglist, sg, nelems, i) {
+		dma_sync_single_for_device(dev, sg->dma_address,
+					   sg_dma_len(sg), direction);
+	}
+}
+
+static inline int
+tile_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+	return 0;
+}
+
+static inline int
+tile_dma_supported(struct device *dev, u64 mask)
+{
+	return 1;
+}
+
+static struct dma_map_ops tile_default_dma_map_ops = {
+	.alloc = tile_dma_alloc_coherent,
+	.free = tile_dma_free_coherent,
+	.map_page = tile_dma_map_page,
+	.unmap_page = tile_dma_unmap_page,
+	.map_sg = tile_dma_map_sg,
+	.unmap_sg = tile_dma_unmap_sg,
+	.sync_single_for_cpu = tile_dma_sync_single_for_cpu,
+	.sync_single_for_device = tile_dma_sync_single_for_device,
+	.sync_sg_for_cpu = tile_dma_sync_sg_for_cpu,
+	.sync_sg_for_device = tile_dma_sync_sg_for_device,
+	.mapping_error = tile_dma_mapping_error,
+	.dma_supported = tile_dma_supported
+};
+
+struct dma_map_ops *tile_dma_map_ops = &tile_default_dma_map_ops;
+EXPORT_SYMBOL(tile_dma_map_ops);
+
+/* Generic PCI DMA mapping functions */
+
+static void *tile_pci_dma_alloc_coherent(struct device *dev, size_t size,
+					 dma_addr_t *dma_handle, gfp_t gfp,
+					 struct dma_attrs *attrs)
+{
+	int node = dev_to_node(dev);
+	int order = get_order(size);
+	struct page *pg;
+	dma_addr_t addr;
+
+	gfp |= __GFP_ZERO;
+
+	pg = homecache_alloc_pages_node(node, gfp, order, PAGE_HOME_DMA);
+	if (pg == NULL)
+		return NULL;
+
+	addr = page_to_phys(pg);
+
+	*dma_handle = phys_to_dma(dev, addr);
+
+	return page_address(pg);
+}
+
+/*
+ * Free memory that was allocated with tile_pci_dma_alloc_coherent.
+ */
+static void tile_pci_dma_free_coherent(struct device *dev, size_t size,
+				       void *vaddr, dma_addr_t dma_handle,
+				       struct dma_attrs *attrs)
+{
+	homecache_free_pages((unsigned long)vaddr, get_order(size));
 }
-EXPORT_SYMBOL(dma_unmap_single);
 
-int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
-	   enum dma_data_direction direction)
+static int tile_pci_dma_map_sg(struct device *dev, struct scatterlist *sglist,
+			       int nents, enum dma_data_direction direction,
+			       struct dma_attrs *attrs)
 {
 	struct scatterlist *sg;
 	int i;
@@ -143,73 +385,103 @@ int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
 
 	for_each_sg(sglist, sg, nents, i) {
 		sg->dma_address = sg_phys(sg);
-		__dma_map_pa_range(sg->dma_address, sg->length);
+		__dma_prep_pa_range(sg->dma_address, sg->length, direction);
+
+		sg->dma_address = phys_to_dma(dev, sg->dma_address);
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+		sg->dma_length = sg->length;
+#endif
 	}
 
 	return nents;
 }
-EXPORT_SYMBOL(dma_map_sg);
 
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-	     enum dma_data_direction direction)
+static void tile_pci_dma_unmap_sg(struct device *dev,
+				  struct scatterlist *sglist, int nents,
+				  enum dma_data_direction direction,
+				  struct dma_attrs *attrs)
 {
+	struct scatterlist *sg;
+	int i;
+
 	BUG_ON(!valid_dma_direction(direction));
+	for_each_sg(sglist, sg, nents, i) {
+		sg->dma_address = sg_phys(sg);
+		__dma_complete_pa_range(sg->dma_address, sg->length,
+					direction);
+	}
 }
-EXPORT_SYMBOL(dma_unmap_sg);
 
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
-			unsigned long offset, size_t size,
-			enum dma_data_direction direction)
+static dma_addr_t tile_pci_dma_map_page(struct device *dev, struct page *page,
+					unsigned long offset, size_t size,
+					enum dma_data_direction direction,
+					struct dma_attrs *attrs)
 {
 	BUG_ON(!valid_dma_direction(direction));
 
 	BUG_ON(offset + size > PAGE_SIZE);
-	homecache_flush_cache(page, 0);
+	__dma_prep_page(page, offset, size, direction);
 
-	return page_to_pa(page) + offset;
+	return phys_to_dma(dev, page_to_pa(page) + offset);
 }
-EXPORT_SYMBOL(dma_map_page);
 
-void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-	       enum dma_data_direction direction)
+static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+				    size_t size,
+				    enum dma_data_direction direction,
+				    struct dma_attrs *attrs)
 {
 	BUG_ON(!valid_dma_direction(direction));
+
+	dma_address = dma_to_phys(dev, dma_address);
+
+	__dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)),
+			    dma_address & PAGE_OFFSET, size, direction);
 }
-EXPORT_SYMBOL(dma_unmap_page);
 
-void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-			     size_t size, enum dma_data_direction direction)
+static void tile_pci_dma_sync_single_for_cpu(struct device *dev,
+					     dma_addr_t dma_handle,
+					     size_t size,
+					     enum dma_data_direction direction)
 {
 	BUG_ON(!valid_dma_direction(direction));
+
+	dma_handle = dma_to_phys(dev, dma_handle);
+
+	__dma_complete_pa_range(dma_handle, size, direction);
 }
-EXPORT_SYMBOL(dma_sync_single_for_cpu);
 
-void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-				size_t size, enum dma_data_direction direction)
+static void tile_pci_dma_sync_single_for_device(struct device *dev,
+						dma_addr_t dma_handle,
+						size_t size,
+						enum dma_data_direction
+						direction)
 {
-	unsigned long start = PFN_DOWN(dma_handle);
-	unsigned long end = PFN_DOWN(dma_handle + size - 1);
-	unsigned long i;
+	dma_handle = dma_to_phys(dev, dma_handle);
 
-	BUG_ON(!valid_dma_direction(direction));
-	for (i = start; i <= end; ++i)
-		homecache_flush_cache(pfn_to_page(i), 0);
+	__dma_prep_pa_range(dma_handle, size, direction);
 }
-EXPORT_SYMBOL(dma_sync_single_for_device);
 
-void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-		    enum dma_data_direction direction)
+static void tile_pci_dma_sync_sg_for_cpu(struct device *dev,
+					 struct scatterlist *sglist,
+					 int nelems,
+					 enum dma_data_direction direction)
 {
+	struct scatterlist *sg;
+	int i;
+
 	BUG_ON(!valid_dma_direction(direction));
-	WARN_ON(nelems == 0 || sg[0].length == 0);
+	WARN_ON(nelems == 0 || sglist->length == 0);
+
+	for_each_sg(sglist, sg, nelems, i) {
+		dma_sync_single_for_cpu(dev, sg->dma_address,
+					sg_dma_len(sg), direction);
+	}
 }
-EXPORT_SYMBOL(dma_sync_sg_for_cpu);
 
-/*
- * Flush and invalidate cache for scatterlist.
- */
-void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
-			    int nelems, enum dma_data_direction direction)
+static void tile_pci_dma_sync_sg_for_device(struct device *dev,
+					    struct scatterlist *sglist,
+					    int nelems,
+					    enum dma_data_direction direction)
 {
 	struct scatterlist *sg;
 	int i;
@@ -222,31 +494,93 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
 					   sg_dma_len(sg), direction);
 	}
 }
-EXPORT_SYMBOL(dma_sync_sg_for_device);
 
-void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-				   unsigned long offset, size_t size,
-				   enum dma_data_direction direction)
+static inline int
+tile_pci_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
-	dma_sync_single_for_cpu(dev, dma_handle + offset, size, direction);
+	return 0;
 }
-EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
 
-void dma_sync_single_range_for_device(struct device *dev,
-				      dma_addr_t dma_handle,
-				      unsigned long offset, size_t size,
-				      enum dma_data_direction direction)
+static inline int
+tile_pci_dma_supported(struct device *dev, u64 mask)
 {
-	dma_sync_single_for_device(dev, dma_handle + offset, size, direction);
+	return 1;
 }
-EXPORT_SYMBOL(dma_sync_single_range_for_device);
 
-/*
- * dma_alloc_noncoherent() returns non-cacheable memory, so there's no
- * need to do any flushing here.
- */
-void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-		    enum dma_data_direction direction)
+static struct dma_map_ops tile_pci_default_dma_map_ops = {
+	.alloc = tile_pci_dma_alloc_coherent,
+	.free = tile_pci_dma_free_coherent,
+	.map_page = tile_pci_dma_map_page,
+	.unmap_page = tile_pci_dma_unmap_page,
+	.map_sg = tile_pci_dma_map_sg,
+	.unmap_sg = tile_pci_dma_unmap_sg,
+	.sync_single_for_cpu = tile_pci_dma_sync_single_for_cpu,
+	.sync_single_for_device = tile_pci_dma_sync_single_for_device,
+	.sync_sg_for_cpu = tile_pci_dma_sync_sg_for_cpu,
+	.sync_sg_for_device = tile_pci_dma_sync_sg_for_device,
+	.mapping_error = tile_pci_dma_mapping_error,
+	.dma_supported = tile_pci_dma_supported
+};
+
+struct dma_map_ops *gx_pci_dma_map_ops = &tile_pci_default_dma_map_ops;
+EXPORT_SYMBOL(gx_pci_dma_map_ops);
+
+/* PCI DMA mapping functions for legacy PCI devices */
+
+#ifdef CONFIG_SWIOTLB
+static void *tile_swiotlb_alloc_coherent(struct device *dev, size_t size,
+					 dma_addr_t *dma_handle, gfp_t gfp,
+					 struct dma_attrs *attrs)
 {
+	gfp |= GFP_DMA;
+	return swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
+}
+
+static void tile_swiotlb_free_coherent(struct device *dev, size_t size,
+				       void *vaddr, dma_addr_t dma_addr,
+				       struct dma_attrs *attrs)
+{
+	swiotlb_free_coherent(dev, size, vaddr, dma_addr);
+}
+
+static struct dma_map_ops pci_swiotlb_dma_ops = {
+	.alloc = tile_swiotlb_alloc_coherent,
+	.free = tile_swiotlb_free_coherent,
+	.map_page = swiotlb_map_page,
+	.unmap_page = swiotlb_unmap_page,
+	.map_sg = swiotlb_map_sg_attrs,
+	.unmap_sg = swiotlb_unmap_sg_attrs,
+	.sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+	.sync_single_for_device = swiotlb_sync_single_for_device,
+	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = swiotlb_sync_sg_for_device,
+	.dma_supported = swiotlb_dma_supported,
+	.mapping_error = swiotlb_dma_mapping_error,
+};
+
+struct dma_map_ops *gx_legacy_pci_dma_map_ops = &pci_swiotlb_dma_ops;
+#else
+struct dma_map_ops *gx_legacy_pci_dma_map_ops;
+#endif
+EXPORT_SYMBOL(gx_legacy_pci_dma_map_ops);
+
+#ifdef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK
+int dma_set_coherent_mask(struct device *dev, u64 mask)
+{
+	struct dma_map_ops *dma_ops = get_dma_ops(dev);
+
+	/* Handle legacy PCI devices with limited memory addressability. */
+	if (((dma_ops == gx_pci_dma_map_ops) ||
+	    (dma_ops == gx_legacy_pci_dma_map_ops)) &&
+	    (mask <= DMA_BIT_MASK(32))) {
+		if (mask > dev->archdata.max_direct_dma_addr)
+			mask = dev->archdata.max_direct_dma_addr;
+	}
+
+	if (!dma_supported(dev, mask))
+		return -EIO;
+	dev->coherent_dma_mask = mask;
+	return 0;
 }
-EXPORT_SYMBOL(dma_cache_sync);
+EXPORT_SYMBOL(dma_set_coherent_mask);
+#endif
diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c
index b56d12b..87422ed 100644
--- a/arch/tile/kernel/pci.c
+++ b/arch/tile/kernel/pci.c
@@ -310,6 +310,7 @@ int __init pcibios_init(void)
 		if (pci_scan_flags[i] == 0 && controllers[i].ops != NULL) {
 			struct pci_controller *controller = &controllers[i];
 			struct pci_bus *bus;
+			LIST_HEAD(resources);
 
 			if (tile_init_irqs(i, controller)) {
 				pr_err("PCI: Could not initialize IRQs\n");
@@ -327,9 +328,11 @@ int __init pcibios_init(void)
 			 * This is inlined in linux/pci.h and calls into
 			 * pci_scan_bus_parented() in probe.c.
 			 */
-			bus = pci_scan_bus(0, controller->ops, controller);
+			pci_add_resource(&resources, &ioport_resource);
+			pci_add_resource(&resources, &iomem_resource);
+			bus = pci_scan_root_bus(NULL, 0, controller->ops, controller, &resources);
 			controller->root_bus = bus;
-			controller->last_busno = bus->subordinate;
+			controller->last_busno = bus->busn_res.end;
 		}
 	}
 
@@ -366,7 +369,7 @@ int __init pcibios_init(void)
 				 */
 				if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
 					(PCI_SLOT(dev->devfn) == 0)) {
-					next_bus = dev->subordinate;
+					next_bus = dev->busn_res.end;
 					controllers[i].mem_resources[0] =
 						*next_bus->resource[0];
 					controllers[i].mem_resources[1] =
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
new file mode 100644
index 0000000..27f7ab0
--- /dev/null
+++ b/arch/tile/kernel/pci_gx.c
@@ -0,0 +1,1547 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mmzone.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/msi.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/ctype.h>
+
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/byteorder.h>
+
+#include <gxio/iorpc_globals.h>
+#include <gxio/kiorpc.h>
+#include <gxio/trio.h>
+#include <gxio/iorpc_trio.h>
+#include <hv/drv_trio_intf.h>
+
+#include <arch/sim.h>
+
+/*
+ * This file containes the routines to search for PCI buses,
+ * enumerate the buses, and configure any attached devices.
+ */
+
+#define DEBUG_PCI_CFG	0
+
+#if DEBUG_PCI_CFG
+#define TRACE_CFG_WR(size, val, bus, dev, func, offset) \
+	pr_info("CFG WR %d-byte VAL %#x to bus %d dev %d func %d addr %u\n", \
+		size, val, bus, dev, func, offset & 0xFFF);
+#define TRACE_CFG_RD(size, val, bus, dev, func, offset) \
+	pr_info("CFG RD %d-byte VAL %#x from bus %d dev %d func %d addr %u\n", \
+		size, val, bus, dev, func, offset & 0xFFF);
+#else
+#define TRACE_CFG_WR(...)
+#define TRACE_CFG_RD(...)
+#endif
+
+static int __devinitdata pci_probe = 1;
+
+/* Information on the PCIe RC ports configuration. */
+static int __devinitdata pcie_rc[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
+
+/*
+ * On some platforms with one or more Gx endpoint ports, we need to
+ * delay the PCIe RC port probe for a few seconds to work around
+ * a HW PCIe link-training bug. The exact delay is specified with
+ * a kernel boot argument in the form of "pcie_rc_delay=T,P,S",
+ * where T is the TRIO instance number, P is the port number and S is
+ * the delay in seconds. If the delay is not provided, the value
+ * will be DEFAULT_RC_DELAY.
+ */
+static int __devinitdata rc_delay[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
+
+/* Default number of seconds that the PCIe RC port probe can be delayed. */
+#define DEFAULT_RC_DELAY	10
+
+/* Max number of seconds that the PCIe RC port probe can be delayed. */
+#define MAX_RC_DELAY		20
+
+/* Array of the PCIe ports configuration info obtained from the BIB. */
+struct pcie_port_property pcie_ports[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
+
+/* All drivers share the TRIO contexts defined here. */
+gxio_trio_context_t trio_contexts[TILEGX_NUM_TRIO];
+
+/* Pointer to an array of PCIe RC controllers. */
+struct pci_controller pci_controllers[TILEGX_NUM_TRIO * TILEGX_TRIO_PCIES];
+int num_rc_controllers;
+static int num_ep_controllers;
+
+static struct pci_ops tile_cfg_ops;
+
+/* Mask of CPUs that should receive PCIe interrupts. */
+static struct cpumask intr_cpus_map;
+
+/* PCI I/O space support is not implemented. */
+static struct resource pci_ioport_resource = {
+	.name	= "PCI IO",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_IO,
+};
+
+static struct resource pci_iomem_resource = {
+	.name	= "PCI mem",
+	.start	= TILE_PCI_MEM_START,
+	.end	= TILE_PCI_MEM_END,
+	.flags	= IORESOURCE_MEM,
+};
+
+/*
+ * We don't need to worry about the alignment of resources.
+ */
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+				resource_size_t size, resource_size_t align)
+{
+	return res->start;
+}
+EXPORT_SYMBOL(pcibios_align_resource);
+
+
+/*
+ * Pick a CPU to receive and handle the PCIe interrupts, based on the IRQ #.
+ * For now, we simply send interrupts to non-dataplane CPUs.
+ * We may implement methods to allow user to specify the target CPUs,
+ * e.g. via boot arguments.
+ */
+static int tile_irq_cpu(int irq)
+{
+	unsigned int count;
+	int i = 0;
+	int cpu;
+
+	count = cpumask_weight(&intr_cpus_map);
+	if (unlikely(count == 0)) {
+		pr_warning("intr_cpus_map empty, interrupts will be"
+			   " delievered to dataplane tiles\n");
+		return irq % (smp_height * smp_width);
+	}
+
+	count = irq % count;
+	for_each_cpu(cpu, &intr_cpus_map) {
+		if (i++ == count)
+			break;
+	}
+	return cpu;
+}
+
+/*
+ * Open a file descriptor to the TRIO shim.
+ */
+static int __devinit tile_pcie_open(int trio_index)
+{
+	gxio_trio_context_t *context = &trio_contexts[trio_index];
+	int ret;
+
+	/*
+	 * This opens a file descriptor to the TRIO shim.
+	 */
+	ret = gxio_trio_init(context, trio_index);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Allocate an ASID for the kernel.
+	 */
+	ret = gxio_trio_alloc_asids(context, 1, 0, 0);
+	if (ret < 0) {
+		pr_err("PCI: ASID alloc failure on TRIO %d, give up\n",
+			trio_index);
+		goto asid_alloc_failure;
+	}
+
+	context->asid = ret;
+
+#ifdef USE_SHARED_PCIE_CONFIG_REGION
+	/*
+	 * Alloc a PIO region for config access, shared by all MACs per TRIO.
+	 * This shouldn't fail since the kernel is supposed to the first
+	 * client of the TRIO's PIO regions.
+	 */
+	ret = gxio_trio_alloc_pio_regions(context, 1, 0, 0);
+	if (ret < 0) {
+		pr_err("PCI: CFG PIO alloc failure on TRIO %d, give up\n",
+			trio_index);
+		goto pio_alloc_failure;
+	}
+
+	context->pio_cfg_index = ret;
+
+	/*
+	 * For PIO CFG, the bus_address_hi parameter is 0. The mac parameter
+	 * is also 0 because it is specified in PIO_REGION_SETUP_CFG_ADDR.
+	 */
+	ret = gxio_trio_init_pio_region_aux(context, context->pio_cfg_index,
+		0, 0, HV_TRIO_PIO_FLAG_CONFIG_SPACE);
+	if (ret < 0) {
+		pr_err("PCI: CFG PIO init failure on TRIO %d, give up\n",
+			trio_index);
+		goto pio_alloc_failure;
+	}
+#endif
+
+	return ret;
+
+asid_alloc_failure:
+#ifdef USE_SHARED_PCIE_CONFIG_REGION
+pio_alloc_failure:
+#endif
+	hv_dev_close(context->fd);
+
+	return ret;
+}
+
+static void
+tilegx_legacy_irq_ack(struct irq_data *d)
+{
+	__insn_mtspr(SPR_IPI_EVENT_RESET_K, 1UL << d->irq);
+}
+
+static void
+tilegx_legacy_irq_mask(struct irq_data *d)
+{
+	__insn_mtspr(SPR_IPI_MASK_SET_K, 1UL << d->irq);
+}
+
+static void
+tilegx_legacy_irq_unmask(struct irq_data *d)
+{
+	__insn_mtspr(SPR_IPI_MASK_RESET_K, 1UL << d->irq);
+}
+
+static struct irq_chip tilegx_legacy_irq_chip = {
+	.name			= "tilegx_legacy_irq",
+	.irq_ack		= tilegx_legacy_irq_ack,
+	.irq_mask		= tilegx_legacy_irq_mask,
+	.irq_unmask		= tilegx_legacy_irq_unmask,
+
+	/* TBD: support set_affinity. */
+};
+
+/*
+ * This is a wrapper function of the kernel level-trigger interrupt
+ * handler handle_level_irq() for PCI legacy interrupts. The TRIO
+ * is configured such that only INTx Assert interrupts are proxied
+ * to Linux which just calls handle_level_irq() after clearing the
+ * MAC INTx Assert status bit associated with this interrupt.
+ */
+static void
+trio_handle_level_irq(unsigned int irq, struct irq_desc *desc)
+{
+	struct pci_controller *controller = irq_desc_get_handler_data(desc);
+	gxio_trio_context_t *trio_context = controller->trio;
+	uint64_t intx = (uint64_t)irq_desc_get_chip_data(desc);
+	int mac = controller->mac;
+	unsigned int reg_offset;
+	uint64_t level_mask;
+
+	handle_level_irq(irq, desc);
+
+	/*
+	 * Clear the INTx Level status, otherwise future interrupts are
+	 * not sent.
+	 */
+	reg_offset = (TRIO_PCIE_INTFC_MAC_INT_STS <<
+		TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+		(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE <<
+		TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
+		(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+
+	level_mask = TRIO_PCIE_INTFC_MAC_INT_STS__INT_LEVEL_MASK << intx;
+
+	__gxio_mmio_write(trio_context->mmio_base_mac + reg_offset, level_mask);
+}
+
+/*
+ * Create kernel irqs and set up the handlers for the legacy interrupts.
+ * Also some minimum initialization for the MSI support.
+ */
+static int __devinit tile_init_irqs(struct pci_controller *controller)
+{
+	int i;
+	int j;
+	int irq;
+	int result;
+
+	cpumask_copy(&intr_cpus_map, cpu_online_mask);
+
+
+	for (i = 0; i < 4; i++) {
+		gxio_trio_context_t *context = controller->trio;
+		int cpu;
+
+		/* Ask the kernel to allocate an IRQ. */
+		irq = create_irq();
+		if (irq < 0) {
+			pr_err("PCI: no free irq vectors, failed for %d\n", i);
+
+			goto free_irqs;
+		}
+		controller->irq_intx_table[i] = irq;
+
+		/* Distribute the 4 IRQs to different tiles. */
+		cpu = tile_irq_cpu(irq);
+
+		/* Configure the TRIO intr binding for this IRQ. */
+		result = gxio_trio_config_legacy_intr(context, cpu_x(cpu),
+						      cpu_y(cpu), KERNEL_PL,
+						      irq, controller->mac, i);
+		if (result < 0) {
+			pr_err("PCI: MAC intx config failed for %d\n", i);
+
+			goto free_irqs;
+		}
+
+		/*
+		 * Register the IRQ handler with the kernel.
+		 */
+		irq_set_chip_and_handler(irq, &tilegx_legacy_irq_chip,
+					trio_handle_level_irq);
+		irq_set_chip_data(irq, (void *)(uint64_t)i);
+		irq_set_handler_data(irq, controller);
+	}
+
+	return 0;
+
+free_irqs:
+	for (j = 0; j < i; j++)
+		destroy_irq(controller->irq_intx_table[j]);
+
+	return -1;
+}
+
+/*
+ * Find valid controllers and fill in pci_controller structs for each
+ * of them.
+ *
+ * Returns the number of controllers discovered.
+ */
+int __init tile_pci_init(void)
+{
+	int num_trio_shims = 0;
+	int ctl_index = 0;
+	int i, j;
+
+	if (!pci_probe) {
+		pr_info("PCI: disabled by boot argument\n");
+		return 0;
+	}
+
+	pr_info("PCI: Searching for controllers...\n");
+
+	/*
+	 * We loop over all the TRIO shims.
+	 */
+	for (i = 0; i < TILEGX_NUM_TRIO; i++) {
+		int ret;
+
+		ret = tile_pcie_open(i);
+		if (ret < 0)
+			continue;
+
+		num_trio_shims++;
+	}
+
+	if (num_trio_shims == 0 || sim_is_simulator())
+		return 0;
+
+	/*
+	 * Now determine which PCIe ports are configured to operate in RC mode.
+	 * We look at the Board Information Block first and then see if there
+	 * are any overriding configuration by the HW strapping pin.
+	 */
+	for (i = 0; i < TILEGX_NUM_TRIO; i++) {
+		gxio_trio_context_t *context = &trio_contexts[i];
+		int ret;
+
+		if (context->fd < 0)
+			continue;
+
+		ret = hv_dev_pread(context->fd, 0,
+			(HV_VirtAddr)&pcie_ports[i][0],
+			sizeof(struct pcie_port_property) * TILEGX_TRIO_PCIES,
+			GXIO_TRIO_OP_GET_PORT_PROPERTY);
+		if (ret < 0) {
+			pr_err("PCI: PCIE_GET_PORT_PROPERTY failure, error %d,"
+				" on TRIO %d\n", ret, i);
+			continue;
+		}
+
+		for (j = 0; j < TILEGX_TRIO_PCIES; j++) {
+			if (pcie_ports[i][j].allow_rc) {
+				pcie_rc[i][j] = 1;
+				num_rc_controllers++;
+			}
+			else if (pcie_ports[i][j].allow_ep) {
+				num_ep_controllers++;
+			}
+		}
+	}
+
+	/*
+	 * Return if no PCIe ports are configured to operate in RC mode.
+	 */
+	if (num_rc_controllers == 0)
+		return 0;
+
+	/*
+	 * Set the TRIO pointer and MAC index for each PCIe RC port.
+	 */
+	for (i = 0; i < TILEGX_NUM_TRIO; i++) {
+		for (j = 0; j < TILEGX_TRIO_PCIES; j++) {
+			if (pcie_rc[i][j]) {
+				pci_controllers[ctl_index].trio =
+					&trio_contexts[i];
+				pci_controllers[ctl_index].mac = j;
+				pci_controllers[ctl_index].trio_index = i;
+				ctl_index++;
+				if (ctl_index == num_rc_controllers)
+					goto out;
+			}
+		}
+	}
+
+out:
+	/*
+	 * Configure each PCIe RC port.
+	 */
+	for (i = 0; i < num_rc_controllers; i++) {
+		/*
+		 * Configure the PCIe MAC to run in RC mode.
+		 */
+
+		struct pci_controller *controller = &pci_controllers[i];
+
+		controller->index = i;
+		controller->last_busno = 0xff;
+		controller->ops = &tile_cfg_ops;
+
+	}
+
+	return num_rc_controllers;
+}
+
+/*
+ * (pin - 1) converts from the PCI standard's [1:4] convention to
+ * a normal [0:3] range.
+ */
+static int tile_map_irq(const struct pci_dev *dev, u8 device, u8 pin)
+{
+	struct pci_controller *controller =
+		(struct pci_controller *)dev->sysdata;
+	return controller->irq_intx_table[pin - 1];
+}
+
+
+static void __devinit fixup_read_and_payload_sizes(struct pci_controller *
+						controller)
+{
+	gxio_trio_context_t *trio_context = controller->trio;
+	struct pci_bus *root_bus = controller->root_bus;
+	TRIO_PCIE_RC_DEVICE_CONTROL_t dev_control;
+	TRIO_PCIE_RC_DEVICE_CAP_t rc_dev_cap;
+	unsigned int reg_offset;
+	struct pci_bus *child;
+	int mac;
+	int err;
+
+	mac = controller->mac;
+
+	/*
+	 * Set our max read request size to be 4KB.
+	 */
+	reg_offset =
+		(TRIO_PCIE_RC_DEVICE_CONTROL <<
+			TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+		(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD <<
+			TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
+		(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+
+	dev_control.word = __gxio_mmio_read32(trio_context->mmio_base_mac +
+						reg_offset);
+	dev_control.max_read_req_sz = 5;
+	__gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset,
+						dev_control.word);
+
+	/*
+	 * Set the max payload size supported by this Gx PCIe MAC.
+	 * Though Gx PCIe supports Max Payload Size of up to 1024 bytes,
+	 * experiments have shown that setting MPS to 256 yields the
+	 * best performance.
+	 */
+	reg_offset =
+		(TRIO_PCIE_RC_DEVICE_CAP <<
+			TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+		(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD <<
+			TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
+		(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+
+	rc_dev_cap.word = __gxio_mmio_read32(trio_context->mmio_base_mac +
+						reg_offset);
+	rc_dev_cap.mps_sup = 1;
+	__gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset,
+						rc_dev_cap.word);
+
+	/* Configure PCI Express MPS setting. */
+	list_for_each_entry(child, &root_bus->children, node) {
+		struct pci_dev *self = child->self;
+		if (!self)
+			continue;
+
+		pcie_bus_configure_settings(child, self->pcie_mpss);
+	}
+
+	/*
+	 * Set the mac_config register in trio based on the MPS/MRS of the link.
+	 */
+	reg_offset =
+		(TRIO_PCIE_RC_DEVICE_CONTROL <<
+			TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+		(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD <<
+			TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
+		(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+
+	dev_control.word = __gxio_mmio_read32(trio_context->mmio_base_mac +
+						reg_offset);
+
+	err = gxio_trio_set_mps_mrs(trio_context,
+				    dev_control.max_payload_size,
+				    dev_control.max_read_req_sz,
+				    mac);
+        if (err < 0) {
+		pr_err("PCI: PCIE_CONFIGURE_MAC_MPS_MRS failure, "
+			"MAC %d on TRIO %d\n",
+			mac, controller->trio_index);
+	}
+}
+
+static int __devinit setup_pcie_rc_delay(char *str)
+{
+	unsigned long delay = 0;
+	unsigned long trio_index;
+	unsigned long mac;
+
+	if (str == NULL || !isdigit(*str))
+		return -EINVAL;
+	trio_index = simple_strtoul(str, (char **)&str, 10);
+	if (trio_index >= TILEGX_NUM_TRIO)
+		return -EINVAL;
+
+	if (*str != ',')
+		return -EINVAL;
+
+	str++;
+	if (!isdigit(*str))
+		return -EINVAL;
+	mac = simple_strtoul(str, (char **)&str, 10);
+	if (mac >= TILEGX_TRIO_PCIES)
+		return -EINVAL;
+
+	if (*str != '\0') {
+		if (*str != ',')
+			return -EINVAL;
+
+		str++;
+		if (!isdigit(*str))
+			return -EINVAL;
+		delay = simple_strtoul(str, (char **)&str, 10);
+		if (delay > MAX_RC_DELAY)
+			return -EINVAL;
+	}
+
+	rc_delay[trio_index][mac] = delay ? : DEFAULT_RC_DELAY;
+	pr_info("Delaying PCIe RC link training for %u sec"
+		" on MAC %lu on TRIO %lu\n", rc_delay[trio_index][mac],
+		mac, trio_index);
+	return 0;
+}
+early_param("pcie_rc_delay", setup_pcie_rc_delay);
+
+/*
+ * PCI initialization entry point, called by subsys_initcall.
+ */
+int __init pcibios_init(void)
+{
+	resource_size_t offset;
+	LIST_HEAD(resources);
+	int i;
+
+	tile_pci_init();
+
+	if (num_rc_controllers == 0 && num_ep_controllers == 0)
+		return 0;
+
+	/*
+	 * We loop over all the TRIO shims and set up the MMIO mappings.
+	 */
+	for (i = 0; i < TILEGX_NUM_TRIO; i++) {
+		gxio_trio_context_t *context = &trio_contexts[i];
+
+		if (context->fd < 0)
+			continue;
+
+		/*
+		 * Map in the MMIO space for the MAC.
+		 */
+		offset = 0;
+		context->mmio_base_mac =
+			iorpc_ioremap(context->fd, offset,
+				      HV_TRIO_CONFIG_IOREMAP_SIZE);
+		if (context->mmio_base_mac == NULL) {
+			pr_err("PCI: MAC map failure on TRIO %d\n", i);
+
+			hv_dev_close(context->fd);
+			context->fd = -1;
+			continue;
+		}
+	}
+
+	/*
+	 * Delay a bit in case devices aren't ready.  Some devices are
+	 * known to require at least 20ms here, but we use a more
+	 * conservative value.
+	 */
+	msleep(250);
+
+	/* Scan all of the recorded PCI controllers.  */
+	for (i = 0; i < num_rc_controllers; i++) {
+		struct pci_controller *controller = &pci_controllers[i];
+		gxio_trio_context_t *trio_context = controller->trio;
+		TRIO_PCIE_INTFC_PORT_CONFIG_t port_config;
+		TRIO_PCIE_INTFC_PORT_STATUS_t port_status;
+		TRIO_PCIE_INTFC_TX_FIFO_CTL_t tx_fifo_ctl;
+		struct pci_bus *bus;
+		unsigned int reg_offset;
+		unsigned int class_code_revision;
+		int trio_index;
+		int mac;
+		int ret;
+
+		if (trio_context->fd < 0)
+			continue;
+
+		trio_index = controller->trio_index;
+		mac = controller->mac;
+
+		/*
+		 * Check the port strap state which will override the BIB
+		 * setting.
+		 */
+
+		reg_offset =
+			(TRIO_PCIE_INTFC_PORT_CONFIG <<
+				TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+			(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE <<
+				TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
+			(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+
+		port_config.word =
+			__gxio_mmio_read(trio_context->mmio_base_mac +
+					 reg_offset);
+
+		if ((port_config.strap_state !=
+			TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC) &&
+			(port_config.strap_state !=
+			TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC_G1)) {
+			/*
+			 * If this is really intended to be an EP port,
+			 * record it so that the endpoint driver will know about it.
+			 */
+			if (port_config.strap_state ==
+			TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT ||
+			port_config.strap_state ==
+			TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT_G1)
+				pcie_ports[trio_index][mac].allow_ep = 1;
+
+			continue;
+		}
+
+		/*
+		 * Delay the RC link training if needed.
+		 */
+		if (rc_delay[trio_index][mac])
+			msleep(rc_delay[trio_index][mac] * 1000);
+
+		ret = gxio_trio_force_rc_link_up(trio_context, mac);
+		if (ret < 0)
+			pr_err("PCI: PCIE_FORCE_LINK_UP failure, "
+				"MAC %d on TRIO %d\n", mac, trio_index);
+
+		pr_info("PCI: Found PCI controller #%d on TRIO %d MAC %d\n", i,
+			trio_index, controller->mac);
+
+		/*
+		 * Wait a bit here because some EP devices take longer
+		 * to come up.
+		 */
+		msleep(1000);
+
+		/*
+		 * Check for PCIe link-up status.
+		 */
+
+		reg_offset =
+			(TRIO_PCIE_INTFC_PORT_STATUS <<
+				TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+			(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE <<
+				TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
+			(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+
+		port_status.word =
+			__gxio_mmio_read(trio_context->mmio_base_mac +
+					 reg_offset);
+		if (!port_status.dl_up) {
+			pr_err("PCI: link is down, MAC %d on TRIO %d\n",
+				mac, trio_index);
+			continue;
+		}
+
+		/*
+		 * Ensure that the link can come out of L1 power down state.
+		 * Strictly speaking, this is needed only in the case of
+		 * heavy RC-initiated DMAs.
+		 */
+		reg_offset =
+			(TRIO_PCIE_INTFC_TX_FIFO_CTL <<
+				TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+			(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE <<
+				TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
+			(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+		tx_fifo_ctl.word =
+			__gxio_mmio_read(trio_context->mmio_base_mac +
+					 reg_offset);
+		tx_fifo_ctl.min_p_credits = 0;
+		__gxio_mmio_write(trio_context->mmio_base_mac + reg_offset,
+				  tx_fifo_ctl.word);
+
+		/*
+		 * Change the device ID so that Linux bus crawl doesn't confuse
+		 * the internal bridge with any Tilera endpoints.
+		 */
+
+		reg_offset =
+			(TRIO_PCIE_RC_DEVICE_ID_VEN_ID <<
+				TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+			(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD <<
+				TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
+			(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+
+		__gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset,
+				    (TILERA_GX36_RC_DEV_ID <<
+				    TRIO_PCIE_RC_DEVICE_ID_VEN_ID__DEV_ID_SHIFT) |
+				    TILERA_VENDOR_ID);
+
+		/*
+		 * Set the internal P2P bridge class code.
+		 */
+
+		reg_offset =
+			(TRIO_PCIE_RC_REVISION_ID <<
+				TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+			(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD <<
+				TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
+			(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+
+		class_code_revision =
+			__gxio_mmio_read32(trio_context->mmio_base_mac +
+					   reg_offset);
+		class_code_revision = (class_code_revision & 0xff ) |
+					(PCI_CLASS_BRIDGE_PCI << 16);
+
+		__gxio_mmio_write32(trio_context->mmio_base_mac +
+				    reg_offset, class_code_revision);
+
+#ifdef USE_SHARED_PCIE_CONFIG_REGION
+
+		/*
+		 * Map in the MMIO space for the PIO region.
+		 */
+		offset = HV_TRIO_PIO_OFFSET(trio_context->pio_cfg_index) |
+			(((unsigned long long)mac) <<
+			TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT);
+
+#else
+
+		/*
+		 * Alloc a PIO region for PCI config access per MAC.
+		 */
+		ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0);
+		if (ret < 0) {
+			pr_err("PCI: PCI CFG PIO alloc failure for mac %d "
+				"on TRIO %d, give up\n", mac, trio_index);
+
+			continue;
+		}
+
+		trio_context->pio_cfg_index[mac] = ret;
+
+		/*
+		 * For PIO CFG, the bus_address_hi parameter is 0.
+		 */
+		ret = gxio_trio_init_pio_region_aux(trio_context,
+			trio_context->pio_cfg_index[mac],
+			mac, 0, HV_TRIO_PIO_FLAG_CONFIG_SPACE);
+		if (ret < 0) {
+			pr_err("PCI: PCI CFG PIO init failure for mac %d "
+				"on TRIO %d, give up\n", mac, trio_index);
+
+			continue;
+		}
+
+		offset = HV_TRIO_PIO_OFFSET(trio_context->pio_cfg_index[mac]) |
+			(((unsigned long long)mac) <<
+			TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT);
+
+#endif
+
+		trio_context->mmio_base_pio_cfg[mac] =
+			iorpc_ioremap(trio_context->fd, offset,
+			(1 << TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT));
+		if (trio_context->mmio_base_pio_cfg[mac] == NULL) {
+			pr_err("PCI: PIO map failure for mac %d on TRIO %d\n",
+				mac, trio_index);
+
+			continue;
+		}
+
+		/*
+		 * Initialize the PCIe interrupts.
+		 */
+		if (tile_init_irqs(controller)) {
+			pr_err("PCI: IRQs init failure for mac %d on TRIO %d\n",
+				mac, trio_index);
+
+			continue;
+		}
+
+		/*
+		 * The PCI memory resource is located above the PA space.
+		 * The memory range for the PCI root bus should not overlap
+		 * with the physical RAM
+		 */
+		pci_add_resource_offset(&resources, &iomem_resource,
+					1ULL << CHIP_PA_WIDTH());
+
+		bus = pci_scan_root_bus(NULL, 0, controller->ops,
+					controller, &resources);
+		controller->root_bus = bus;
+		controller->last_busno = bus->subordinate;
+
+	}
+
+	/* Do machine dependent PCI interrupt routing */
+	pci_fixup_irqs(pci_common_swizzle, tile_map_irq);
+
+	/*
+	 * This comes from the generic Linux PCI driver.
+	 *
+	 * It allocates all of the resources (I/O memory, etc)
+	 * associated with the devices read in above.
+	 */
+
+	pci_assign_unassigned_resources();
+
+	/* Record the I/O resources in the PCI controller structure. */
+	for (i = 0; i < num_rc_controllers; i++) {
+		struct pci_controller *controller = &pci_controllers[i];
+		gxio_trio_context_t *trio_context = controller->trio;
+		struct pci_bus *root_bus = pci_controllers[i].root_bus;
+		struct pci_bus *next_bus;
+		uint32_t bus_address_hi;
+		struct pci_dev *dev;
+		int ret;
+		int j;
+
+		/*
+		 * Skip controllers that are not properly initialized or
+		 * have down links.
+		 */
+		if (root_bus == NULL)
+			continue;
+
+		/* Configure the max_payload_size values for this domain. */
+		fixup_read_and_payload_sizes(controller);
+
+		list_for_each_entry(dev, &root_bus->devices, bus_list) {
+			/* Find the PCI host controller, ie. the 1st bridge. */
+			if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+				(PCI_SLOT(dev->devfn) == 0)) {
+				next_bus = dev->subordinate;
+				pci_controllers[i].mem_resources[0] =
+					*next_bus->resource[0];
+				pci_controllers[i].mem_resources[1] =
+					 *next_bus->resource[1];
+				pci_controllers[i].mem_resources[2] =
+					 *next_bus->resource[2];
+
+				break;
+			}
+		}
+
+		if (pci_controllers[i].mem_resources[1].flags & IORESOURCE_MEM)
+			bus_address_hi =
+				pci_controllers[i].mem_resources[1].start >> 32;
+		else if (pci_controllers[i].mem_resources[2].flags & IORESOURCE_PREFETCH)
+			bus_address_hi =
+				pci_controllers[i].mem_resources[2].start >> 32;
+		else {
+			/* This is unlikely. */
+			pr_err("PCI: no memory resources on TRIO %d mac %d\n",
+				controller->trio_index, controller->mac);
+			continue;
+		}
+
+		/*
+		 * Alloc a PIO region for PCI memory access for each RC port.
+		 */
+		ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0);
+		if (ret < 0) {
+			pr_err("PCI: MEM PIO alloc failure on TRIO %d mac %d, "
+				"give up\n", controller->trio_index,
+				controller->mac);
+
+			continue;
+		}
+
+		controller->pio_mem_index = ret;
+
+		/*
+		 * For PIO MEM, the bus_address_hi parameter is hard-coded 0
+		 * because we always assign 32-bit PCI bus BAR ranges.
+		 */
+		ret = gxio_trio_init_pio_region_aux(trio_context,
+						    controller->pio_mem_index,
+						    controller->mac,
+						    0,
+						    0);
+		if (ret < 0) {
+			pr_err("PCI: MEM PIO init failure on TRIO %d mac %d, "
+				"give up\n", controller->trio_index,
+				controller->mac);
+
+			continue;
+		}
+
+		/*
+		 * Configure a Mem-Map region for each memory controller so
+		 * that Linux can map all of its PA space to the PCI bus.
+		 * Use the IOMMU to handle hash-for-home memory.
+		 */
+		for_each_online_node(j) {
+			unsigned long start_pfn = node_start_pfn[j];
+			unsigned long end_pfn = node_end_pfn[j];
+			unsigned long nr_pages = end_pfn - start_pfn;
+
+			ret = gxio_trio_alloc_memory_maps(trio_context, 1, 0,
+							  0);
+			if (ret < 0) {
+				pr_err("PCI: Mem-Map alloc failure on TRIO %d "
+					"mac %d for MC %d, give up\n",
+					controller->trio_index,
+					controller->mac, j);
+
+				goto alloc_mem_map_failed;
+			}
+
+			controller->mem_maps[j] = ret;
+
+			/*
+			 * Initialize the Mem-Map and the I/O MMU so that all
+			 * the physical memory can be accessed by the endpoint
+			 * devices. The base bus address is set to the base CPA
+			 * of this memory controller plus an offset (see pci.h).
+			 * The region's base VA is set to the base CPA. The
+			 * I/O MMU table essentially translates the CPA to
+			 * the real PA. Implicitly, for node 0, we create
+			 * a separate Mem-Map region that serves as the inbound
+			 * window for legacy 32-bit devices. This is a direct
+			 * map of the low 4GB CPA space.
+			 */
+			ret = gxio_trio_init_memory_map_mmu_aux(trio_context,
+				controller->mem_maps[j],
+				start_pfn << PAGE_SHIFT,
+				nr_pages << PAGE_SHIFT,
+				trio_context->asid,
+				controller->mac,
+				(start_pfn << PAGE_SHIFT) +
+				TILE_PCI_MEM_MAP_BASE_OFFSET,
+				j,
+				GXIO_TRIO_ORDER_MODE_UNORDERED);
+			if (ret < 0) {
+				pr_err("PCI: Mem-Map init failure on TRIO %d "
+					"mac %d for MC %d, give up\n",
+					controller->trio_index,
+					controller->mac, j);
+
+				goto alloc_mem_map_failed;
+			}
+			continue;
+
+alloc_mem_map_failed:
+			break;
+		}
+
+	}
+
+	return 0;
+}
+subsys_initcall(pcibios_init);
+
+/*
+ * PCI scan code calls the arch specific pcibios_fixup_bus() each time it scans
+ * a new bridge. Called after each bus is probed, but before its children are
+ * examined.
+ */
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_dev *dev = bus->self;
+
+	if (!dev) {
+		/* This is the root bus. */
+		bus->resource[0] = &pci_ioport_resource;
+		bus->resource[1] = &pci_iomem_resource;
+	}
+}
+
+/*
+ * This can be called from the generic PCI layer, but doesn't need to
+ * do anything.
+ */
+char __devinit *pcibios_setup(char *str)
+{
+	if (!strcmp(str, "off")) {
+		pci_probe = 0;
+		return NULL;
+	}
+	return str;
+}
+
+/*
+ * This is called from the generic Linux layer.
+ */
+void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+/*
+ * Enable memory address decoding, as appropriate, for the
+ * device described by the 'dev' struct. The I/O decoding
+ * is disabled, though the TILE-Gx supports I/O addressing.
+ *
+ * This is called from the generic PCI layer, and can be called
+ * for bridges or endpoints.
+ */
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+	return pci_enable_resources(dev, mask);
+}
+
+/* Called for each device after PCI setup is done. */
+static void __init
+pcibios_fixup_final(struct pci_dev *pdev)
+{
+	set_dma_ops(&pdev->dev, gx_pci_dma_map_ops);
+	set_dma_offset(&pdev->dev, TILE_PCI_MEM_MAP_BASE_OFFSET);
+	pdev->dev.archdata.max_direct_dma_addr =
+		TILE_PCI_MAX_DIRECT_DMA_ADDRESS;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_final);
+
+/* Map a PCI MMIO bus address into VA space. */
+void __iomem *ioremap(resource_size_t phys_addr, unsigned long size)
+{
+	struct pci_controller *controller = NULL;
+	resource_size_t bar_start;
+	resource_size_t bar_end;
+	resource_size_t offset;
+	resource_size_t start;
+	resource_size_t end;
+	int trio_fd;
+	int i, j;
+
+	start = phys_addr;
+	end = phys_addr + size - 1;
+
+	/*
+	 * In the following, each PCI controller's mem_resources[1]
+	 * represents its (non-prefetchable) PCI memory resource and
+	 * mem_resources[2] refers to its prefetchable PCI memory resource.
+	 * By searching phys_addr in each controller's mem_resources[], we can
+	 * determine the controller that should accept the PCI memory access.
+	 */
+
+	for (i = 0; i < num_rc_controllers; i++) {
+		/*
+		 * Skip controllers that are not properly initialized or
+		 * have down links.
+		 */
+		if (pci_controllers[i].root_bus == NULL)
+			continue;
+
+		for (j = 1; j < 3; j++) {
+			bar_start =
+				pci_controllers[i].mem_resources[j].start;
+			bar_end =
+				pci_controllers[i].mem_resources[j].end;
+
+			if ((start >= bar_start) && (end <= bar_end)) {
+
+				controller = &pci_controllers[i];
+
+				goto got_it;
+			}
+		}
+	}
+
+	if (controller == NULL)
+		return NULL;
+
+got_it:
+	trio_fd = controller->trio->fd;
+
+	offset = HV_TRIO_PIO_OFFSET(controller->pio_mem_index) + phys_addr;
+
+	/*
+	 * We need to keep the PCI bus address's in-page offset in the VA.
+	 */
+	return iorpc_ioremap(trio_fd, offset, size) +
+		(phys_addr & (PAGE_SIZE - 1));
+}
+EXPORT_SYMBOL(ioremap);
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+	iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);
+
+/****************************************************************
+ *
+ * Tile PCI config space read/write routines
+ *
+ ****************************************************************/
+
+/*
+ * These are the normal read and write ops
+ * These are expanded with macros from  pci_bus_read_config_byte() etc.
+ *
+ * devfn is the combined PCI device & function.
+ *
+ * offset is in bytes, from the start of config space for the
+ * specified bus & device.
+ */
+
+static int __devinit tile_cfg_read(struct pci_bus *bus,
+				   unsigned int devfn,
+				   int offset,
+				   int size,
+				   u32 *val)
+{
+	struct pci_controller *controller = bus->sysdata;
+	gxio_trio_context_t *trio_context = controller->trio;
+	int busnum = bus->number & 0xff;
+	int device = PCI_SLOT(devfn);
+	int function = PCI_FUNC(devfn);
+	int config_type = 1;
+	TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR_t cfg_addr;
+	void *mmio_addr;
+
+	/*
+	 * Map all accesses to the local device (bus == 0) into the
+	 * MMIO space of the MAC. Accesses to the downstream devices
+	 * go to the PIO space.
+	 */
+	if (busnum == 0) {
+		if (device == 0) {
+			/*
+			 * This is the internal downstream P2P bridge,
+			 * access directly.
+			 */
+			unsigned int reg_offset;
+
+			reg_offset = ((offset & 0xFFF) <<
+				TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+				(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_PROTECTED
+				<< TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
+				(controller->mac <<
+					TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+
+			mmio_addr = trio_context->mmio_base_mac + reg_offset;
+
+			goto valid_device;
+
+		} else {
+			/*
+			 * We fake an empty device for (device > 0),
+			 * since there is only one device on bus 0.
+			 */
+			goto invalid_device;
+		}
+	}
+
+	/*
+	 * Accesses to the directly attached device (bus == 1) have to be
+	 * sent as type-0 configs.
+	 */
+
+	if (busnum == 1) {
+		/*
+		 * There is only one device off of our built-in P2P bridge.
+		 */
+		if (device != 0)
+			goto invalid_device;
+
+		config_type = 0;
+	}
+
+	cfg_addr.word = 0;
+	cfg_addr.reg_addr = (offset & 0xFFF);
+	cfg_addr.fn = function;
+	cfg_addr.dev = device;
+	cfg_addr.bus = busnum;
+	cfg_addr.type = config_type;
+
+	/*
+	 * Note that we don't set the mac field in cfg_addr because the
+	 * mapping is per port.
+	 */
+
+	mmio_addr = trio_context->mmio_base_pio_cfg[controller->mac] +
+			cfg_addr.word;
+
+valid_device:
+
+	switch (size) {
+	case 4:
+		*val = __gxio_mmio_read32(mmio_addr);
+		break;
+
+	case 2:
+		*val = __gxio_mmio_read16(mmio_addr);
+		break;
+
+	case 1:
+		*val = __gxio_mmio_read8(mmio_addr);
+		break;
+
+	default:
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+	}
+
+	TRACE_CFG_RD(size, *val, busnum, device, function, offset);
+
+	return 0;
+
+invalid_device:
+
+	switch (size) {
+	case 4:
+		*val = 0xFFFFFFFF;
+		break;
+
+	case 2:
+		*val = 0xFFFF;
+		break;
+
+	case 1:
+		*val = 0xFF;
+		break;
+
+	default:
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+	}
+
+	return 0;
+}
+
+
+/*
+ * See tile_cfg_read() for relevent comments.
+ * Note that "val" is the value to write, not a pointer to that value.
+ */
+static int __devinit tile_cfg_write(struct pci_bus *bus,
+				    unsigned int devfn,
+				    int offset,
+				    int size,
+				    u32 val)
+{
+	struct pci_controller *controller = bus->sysdata;
+	gxio_trio_context_t *trio_context = controller->trio;
+	int busnum = bus->number & 0xff;
+	int device = PCI_SLOT(devfn);
+	int function = PCI_FUNC(devfn);
+	int config_type = 1;
+	TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR_t cfg_addr;
+	void *mmio_addr;
+	u32 val_32 = (u32)val;
+	u16 val_16 = (u16)val;
+	u8 val_8 = (u8)val;
+
+	/*
+	 * Map all accesses to the local device (bus == 0) into the
+	 * MMIO space of the MAC. Accesses to the downstream devices
+	 * go to the PIO space.
+	 */
+	if (busnum == 0) {
+		if (device == 0) {
+			/*
+			 * This is the internal downstream P2P bridge,
+			 * access directly.
+			 */
+			unsigned int reg_offset;
+
+			reg_offset = ((offset & 0xFFF) <<
+				TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+				(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_PROTECTED
+				<< TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
+				(controller->mac <<
+					TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+
+			mmio_addr = trio_context->mmio_base_mac + reg_offset;
+
+			goto valid_device;
+
+		} else {
+			/*
+			 * We fake an empty device for (device > 0),
+			 * since there is only one device on bus 0.
+			 */
+			goto invalid_device;
+		}
+	}
+
+	/*
+	 * Accesses to the directly attached device (bus == 1) have to be
+	 * sent as type-0 configs.
+	 */
+
+	if (busnum == 1) {
+		/*
+		 * There is only one device off of our built-in P2P bridge.
+		 */
+		if (device != 0)
+			goto invalid_device;
+
+		config_type = 0;
+	}
+
+	cfg_addr.word = 0;
+	cfg_addr.reg_addr = (offset & 0xFFF);
+	cfg_addr.fn = function;
+	cfg_addr.dev = device;
+	cfg_addr.bus = busnum;
+	cfg_addr.type = config_type;
+
+	/*
+	 * Note that we don't set the mac field in cfg_addr because the
+	 * mapping is per port.
+	 */
+
+	mmio_addr = trio_context->mmio_base_pio_cfg[controller->mac] +
+			cfg_addr.word;
+
+valid_device:
+
+	switch (size) {
+	case 4:
+		__gxio_mmio_write32(mmio_addr, val_32);
+		TRACE_CFG_WR(size, val_32, busnum, device, function, offset);
+		break;
+
+	case 2:
+		__gxio_mmio_write16(mmio_addr, val_16);
+		TRACE_CFG_WR(size, val_16, busnum, device, function, offset);
+		break;
+
+	case 1:
+		__gxio_mmio_write8(mmio_addr, val_8);
+		TRACE_CFG_WR(size, val_8, busnum, device, function, offset);
+		break;
+
+	default:
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+	}
+
+invalid_device:
+
+	return 0;
+}
+
+
+static struct pci_ops tile_cfg_ops = {
+	.read =         tile_cfg_read,
+	.write =        tile_cfg_write,
+};
+
+
+/*
+ * MSI support starts here.
+ */
+static unsigned int
+tilegx_msi_startup(struct irq_data *d)
+{
+	if (d->msi_desc)
+		unmask_msi_irq(d);
+
+	return 0;
+}
+
+static void
+tilegx_msi_ack(struct irq_data *d)
+{
+	__insn_mtspr(SPR_IPI_EVENT_RESET_K, 1UL << d->irq);
+}
+
+static void
+tilegx_msi_mask(struct irq_data *d)
+{
+	mask_msi_irq(d);
+	__insn_mtspr(SPR_IPI_MASK_SET_K, 1UL << d->irq);
+}
+
+static void
+tilegx_msi_unmask(struct irq_data *d)
+{
+	__insn_mtspr(SPR_IPI_MASK_RESET_K, 1UL << d->irq);
+	unmask_msi_irq(d);
+}
+
+static struct irq_chip tilegx_msi_chip = {
+	.name			= "tilegx_msi",
+	.irq_startup		= tilegx_msi_startup,
+	.irq_ack		= tilegx_msi_ack,
+	.irq_mask		= tilegx_msi_mask,
+	.irq_unmask		= tilegx_msi_unmask,
+
+	/* TBD: support set_affinity. */
+};
+
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
+{
+	struct pci_controller *controller;
+	gxio_trio_context_t *trio_context;
+	struct msi_msg msg;
+	int default_irq;
+	uint64_t mem_map_base;
+	uint64_t mem_map_limit;
+	u64 msi_addr;
+	int mem_map;
+	int cpu;
+	int irq;
+	int ret;
+
+	irq = create_irq();
+	if (irq < 0)
+		return irq;
+
+	/*
+	 * Since we use a 64-bit Mem-Map to accept the MSI write, we fail
+	 * devices that are not capable of generating a 64-bit message address.
+	 * These devices will fall back to using the legacy interrupts.
+	 * Most PCIe endpoint devices do support 64-bit message addressing.
+	 */
+	if (desc->msi_attrib.is_64 == 0) {
+		dev_printk(KERN_INFO, &pdev->dev,
+			"64-bit MSI message address not supported, "
+			"falling back to legacy interrupts.\n");
+
+		ret = -ENOMEM;
+		goto is_64_failure;
+	}
+
+	default_irq = desc->msi_attrib.default_irq;
+	controller = irq_get_handler_data(default_irq);
+
+	BUG_ON(!controller);
+
+	trio_context = controller->trio;
+
+	/*
+	 * Allocate the Mem-Map that will accept the MSI write and
+	 * trigger the TILE-side interrupts.
+	 */
+	mem_map = gxio_trio_alloc_memory_maps(trio_context, 1, 0, 0);
+	if (mem_map < 0) {
+		dev_printk(KERN_INFO, &pdev->dev,
+			"%s Mem-Map alloc failure. "
+			"Failed to initialize MSI interrupts. "
+			"Falling back to legacy interrupts.\n",
+			desc->msi_attrib.is_msix ? "MSI-X" : "MSI");
+
+		ret = -ENOMEM;
+		goto msi_mem_map_alloc_failure;
+	}
+
+	/* We try to distribute different IRQs to different tiles. */
+	cpu = tile_irq_cpu(irq);
+
+	/*
+	 * Now call up to the HV to configure the Mem-Map interrupt and
+	 * set up the IPI binding.
+	 */
+	mem_map_base = MEM_MAP_INTR_REGIONS_BASE +
+		mem_map * MEM_MAP_INTR_REGION_SIZE;
+	mem_map_limit = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 1;
+
+	ret = gxio_trio_config_msi_intr(trio_context, cpu_x(cpu), cpu_y(cpu),
+					KERNEL_PL, irq, controller->mac,
+					mem_map, mem_map_base, mem_map_limit,
+					trio_context->asid);
+	if (ret < 0) {
+		dev_printk(KERN_INFO, &pdev->dev, "HV MSI config failed.\n");
+
+		goto hv_msi_config_failure;
+	}
+
+	irq_set_msi_desc(irq, desc);
+
+	msi_addr = mem_map_base + TRIO_MAP_MEM_REG_INT3 - TRIO_MAP_MEM_REG_INT0;
+
+	msg.address_hi = msi_addr >> 32;
+	msg.address_lo = msi_addr & 0xffffffff;
+
+	msg.data = mem_map;
+
+	write_msi_msg(irq, &msg);
+	irq_set_chip_and_handler(irq, &tilegx_msi_chip, handle_level_irq);
+	irq_set_handler_data(irq, controller);
+
+	return 0;
+
+hv_msi_config_failure:
+	/* Free mem-map */
+msi_mem_map_alloc_failure:
+is_64_failure:
+	destroy_irq(irq);
+	return ret;
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+	destroy_irq(irq);
+}
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index dd87f34..f47d25f 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -23,8 +23,10 @@
 #include <linux/irq.h>
 #include <linux/kexec.h>
 #include <linux/pci.h>
+#include <linux/swiotlb.h>
 #include <linux/initrd.h>
 #include <linux/io.h>
+#include <linux/start_kernel.h>
 #include <linux/highmem.h>
 #include <linux/smp.h>
 #include <linux/timex.h>
@@ -109,7 +111,7 @@ static unsigned int __initdata maxnodemem_pfn[MAX_NUMNODES] = {
 };
 static nodemask_t __initdata isolnodes;
 
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && !defined(__tilegx__)
 enum { DEFAULT_PCI_RESERVE_MB = 64 };
 static unsigned int __initdata pci_reserve_mb = DEFAULT_PCI_RESERVE_MB;
 unsigned long __initdata pci_reserve_start_pfn = -1U;
@@ -160,7 +162,7 @@ static int __init setup_isolnodes(char *str)
 }
 early_param("isolnodes", setup_isolnodes);
 
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && !defined(__tilegx__)
 static int __init setup_pci_reserve(char* str)
 {
 	unsigned long mb;
@@ -171,7 +173,7 @@ static int __init setup_pci_reserve(char* str)
 
 	pci_reserve_mb = mb;
 	pr_info("Reserving %dMB for PCIE root complex mappings\n",
-	       pci_reserve_mb);
+		pci_reserve_mb);
 	return 0;
 }
 early_param("pci_reserve", setup_pci_reserve);
@@ -411,7 +413,7 @@ static void __init setup_memory(void)
 			continue;
 		}
 #endif
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && !defined(__tilegx__)
 		/*
 		 * Blocks that overlap the pci reserved region must
 		 * have enough space to hold the maximum percpu data
@@ -604,11 +606,9 @@ static void __init setup_bootmem_allocator_node(int i)
 	/* Free all the space back into the allocator. */
 	free_bootmem(PFN_PHYS(start), PFN_PHYS(end - start));
 
-#if defined(CONFIG_PCI)
+#if defined(CONFIG_PCI) && !defined(__tilegx__)
 	/*
-	 * Throw away any memory aliased by the PCI region.  FIXME: this
-	 * is a temporary hack to work around bug 10502, and needs to be
-	 * fixed properly.
+	 * Throw away any memory aliased by the PCI region.
 	 */
 	if (pci_reserve_start_pfn < end && pci_reserve_end_pfn > start)
 		reserve_bootmem(PFN_PHYS(pci_reserve_start_pfn),
@@ -658,6 +658,8 @@ static void __init zone_sizes_init(void)
 	unsigned long zones_size[MAX_NR_ZONES] = { 0 };
 	int size = percpu_size();
 	int num_cpus = smp_height * smp_width;
+	const unsigned long dma_end = (1UL << (32 - PAGE_SHIFT));
+
 	int i;
 
 	for (i = 0; i < num_cpus; ++i)
@@ -729,6 +731,14 @@ static void __init zone_sizes_init(void)
 		zones_size[ZONE_NORMAL] = end - start;
 #endif
 
+		if (start < dma_end) {
+			zones_size[ZONE_DMA] = min(zones_size[ZONE_NORMAL],
+						   dma_end - start);
+			zones_size[ZONE_NORMAL] -= zones_size[ZONE_DMA];
+		} else {
+			zones_size[ZONE_DMA] = 0;
+		}
+
 		/* Take zone metadata from controller 0 if we're isolnode. */
 		if (node_isset(i, isolnodes))
 			NODE_DATA(i)->bdata = &bootmem_node_data[0];
@@ -738,7 +748,7 @@ static void __init zone_sizes_init(void)
 		       PFN_UP(node_percpu[i]));
 
 		/* Track the type of memory on each node */
-		if (zones_size[ZONE_NORMAL])
+		if (zones_size[ZONE_NORMAL] || zones_size[ZONE_DMA])
 			node_set_state(i, N_NORMAL_MEMORY);
 #ifdef CONFIG_HIGHMEM
 		if (end != start)
@@ -1343,7 +1353,7 @@ void __init setup_arch(char **cmdline_p)
 	setup_cpu_maps();
 
 
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && !defined(__tilegx__)
 	/*
 	 * Initialize the PCI structures.  This is done before memory
 	 * setup so that we know whether or not a pci_reserve region
@@ -1372,6 +1382,10 @@ void __init setup_arch(char **cmdline_p)
 	 * any memory using the bootmem allocator.
 	 */
 
+#ifdef CONFIG_SWIOTLB
+	swiotlb_init(0);
+#endif
+
 	paging_init();
 	setup_numa_mapping();
 	zone_sizes_init();
@@ -1522,11 +1536,11 @@ static struct resource code_resource = {
 };
 
 /*
- * We reserve all resources above 4GB so that PCI won't try to put
+ * On Pro, we reserve all resources above 4GB so that PCI won't try to put
  * mappings above 4GB; the standard allows that for some devices but
  * the probing code trunates values to 32 bits.
  */
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && !defined(__tilegx__)
 static struct resource* __init
 insert_non_bus_resource(void)
 {
@@ -1572,7 +1586,7 @@ static int __init request_standard_resources(void)
 	enum { CODE_DELTA = MEM_SV_INTRPT - PAGE_OFFSET };
 
 	iomem_resource.end = -1LL;
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && !defined(__tilegx__)
 	insert_non_bus_resource();
 #endif
 
@@ -1580,7 +1594,7 @@ static int __init request_standard_resources(void)
 		u64 start_pfn = node_start_pfn[i];
 		u64 end_pfn = node_end_pfn[i];
 
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && !defined(__tilegx__)
 		if (start_pfn <= pci_reserve_start_pfn &&
 		    end_pfn > pci_reserve_start_pfn) {
 			if (end_pfn > pci_reserve_end_pfn)
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index e29b055..67efb65 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -219,15 +219,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	regs->regs[1] = (unsigned long) &frame->info;
 	regs->regs[2] = (unsigned long) &frame->uc;
 	regs->flags |= PT_FLAGS_CALLER_SAVES;
-
-	/*
-	 * Notify any tracer that was single-stepping it.
-	 * The tracer may want to single-step inside the
-	 * handler too.
-	 */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 	return 0;
 
 give_sigsegv:
@@ -278,7 +269,8 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
 		ret = setup_rt_frame(sig, ka, info, oldset, regs);
 	if (ret)
 		return;
-	signal_delivered(sig, info, ka, regs, 0);
+	signal_delivered(sig, info, ka, regs,
+			test_thread_flag(TIF_SINGLESTEP));
 }
 
 /*
diff --git a/arch/tile/kernel/smpboot.c b/arch/tile/kernel/smpboot.c
index 84873fb..e686c5a 100644
--- a/arch/tile/kernel/smpboot.c
+++ b/arch/tile/kernel/smpboot.c
@@ -198,17 +198,7 @@ void __cpuinit online_secondary(void)
 
 	notify_cpu_starting(smp_processor_id());
 
-	/*
-	 * We need to hold call_lock, so there is no inconsistency
-	 * between the time smp_call_function() determines number of
-	 * IPI recipients, and the time when the determination is made
-	 * for which cpus receive the IPI. Holding this
-	 * lock helps us to not include this cpu in a currently in progress
-	 * smp_call_function().
-	 */
-	ipi_call_lock();
 	set_cpu_online(smp_processor_id(), 1);
-	ipi_call_unlock();
 	__get_cpu_var(cpu_state) = CPU_ONLINE;
 
 	/* Set up tile-specific state for this cpu. */
diff --git a/arch/tile/kernel/usb.c b/arch/tile/kernel/usb.c
new file mode 100644
index 0000000..5af8deb
--- /dev/null
+++ b/arch/tile/kernel/usb.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Register the Tile-Gx USB interfaces as platform devices.
+ *
+ * The actual USB driver is just some glue (in
+ * drivers/usb/host/[eo]hci-tilegx.c) which makes the registers available
+ * to the standard kernel EHCI and OHCI drivers.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/usb/tilegx.h>
+#include <linux/types.h>
+
+static u64 ehci_dmamask = DMA_BIT_MASK(32);
+
+#define USB_HOST_DEF(unit, type, dmamask) \
+	static struct \
+	    tilegx_usb_platform_data tilegx_usb_platform_data_ ## type ## \
+		hci ## unit = { \
+		.dev_index = unit, \
+	}; \
+	\
+	static struct platform_device tilegx_usb_ ## type ## hci ## unit = { \
+		.name		= "tilegx-" #type "hci", \
+		.id		= unit, \
+		.dev = { \
+			.dma_mask		= dmamask, \
+			.coherent_dma_mask	= DMA_BIT_MASK(32), \
+			.platform_data = \
+				&tilegx_usb_platform_data_ ## type ## hci ## \
+				unit, \
+		}, \
+	};
+
+USB_HOST_DEF(0, e, &ehci_dmamask)
+USB_HOST_DEF(0, o, NULL)
+USB_HOST_DEF(1, e, &ehci_dmamask)
+USB_HOST_DEF(1, o, NULL)
+
+#undef USB_HOST_DEF
+
+static struct platform_device *tilegx_usb_devices[] __initdata = {
+	&tilegx_usb_ehci0,
+	&tilegx_usb_ehci1,
+	&tilegx_usb_ohci0,
+	&tilegx_usb_ohci1,
+};
+
+/** Add our set of possible USB devices. */
+static int __init tilegx_usb_init(void)
+{
+	platform_add_devices(tilegx_usb_devices,
+			     ARRAY_SIZE(tilegx_usb_devices));
+
+	return 0;
+}
+arch_initcall(tilegx_usb_init);
diff --git a/arch/tile/lib/checksum.c b/arch/tile/lib/checksum.c
index e4bab5b..c3ca3e6 100644
--- a/arch/tile/lib/checksum.c
+++ b/arch/tile/lib/checksum.c
@@ -16,19 +16,6 @@
 #include <net/checksum.h>
 #include <linux/module.h>
 
-static inline unsigned int longto16(unsigned long x)
-{
-	unsigned long ret;
-#ifdef __tilegx__
-	ret = __insn_v2sadu(x, 0);
-	ret = __insn_v2sadu(ret, 0);
-#else
-	ret = __insn_sadh_u(x, 0);
-	ret = __insn_sadh_u(ret, 0);
-#endif
-	return ret;
-}
-
 __wsum do_csum(const unsigned char *buff, int len)
 {
 	int odd, count;
@@ -94,7 +81,7 @@ __wsum do_csum(const unsigned char *buff, int len)
 	}
 	if (len & 1)
 		result += *buff;
-	result = longto16(result);
+	result = csum_long(result);
 	if (odd)
 		result = swab16(result);
 out:
diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c
index dbcbdf7..5f7868d 100644
--- a/arch/tile/mm/homecache.c
+++ b/arch/tile/mm/homecache.c
@@ -64,10 +64,6 @@ early_param("noallocl2", set_noallocl2);
 
 #endif
 
-/* Provide no-op versions of these routines to keep flush_remote() cleaner. */
-#define mark_caches_evicted_start() 0
-#define mark_caches_evicted_finish(mask, timestamp) do {} while (0)
-
 
 /*
  * Update the irq_stat for cpus that we are going to interrupt
@@ -107,7 +103,6 @@ static void hv_flush_update(const struct cpumask *cache_cpumask,
  *    there's never any good reason for hv_flush_remote() to fail.
  *  - Accepts a 32-bit PFN rather than a 64-bit PA, which generally
  *    is the type that Linux wants to pass around anyway.
- *  - Centralizes the mark_caches_evicted() handling.
  *  - Canonicalizes that lengths of zero make cpumasks NULL.
  *  - Handles deferring TLB flushes for dataplane tiles.
  *  - Tracks remote interrupts in the per-cpu irq_cpustat_t.
@@ -126,7 +121,6 @@ void flush_remote(unsigned long cache_pfn, unsigned long cache_control,
 		  HV_Remote_ASID *asids, int asidcount)
 {
 	int rc;
-	int timestamp = 0;  /* happy compiler */
 	struct cpumask cache_cpumask_copy, tlb_cpumask_copy;
 	struct cpumask *cache_cpumask, *tlb_cpumask;
 	HV_PhysAddr cache_pa;
@@ -157,15 +151,11 @@ void flush_remote(unsigned long cache_pfn, unsigned long cache_control,
 	hv_flush_update(cache_cpumask, tlb_cpumask, tlb_va, tlb_length,
 			asids, asidcount);
 	cache_pa = (HV_PhysAddr)cache_pfn << PAGE_SHIFT;
-	if (cache_control & HV_FLUSH_EVICT_L2)
-		timestamp = mark_caches_evicted_start();
 	rc = hv_flush_remote(cache_pa, cache_control,
 			     cpumask_bits(cache_cpumask),
 			     tlb_va, tlb_length, tlb_pgsize,
 			     cpumask_bits(tlb_cpumask),
 			     asids, asidcount);
-	if (cache_control & HV_FLUSH_EVICT_L2)
-		mark_caches_evicted_finish(cache_cpumask, timestamp);
 	if (rc == 0)
 		return;
 	cpumask_scnprintf(cache_buf, sizeof(cache_buf), &cache_cpumask_copy);
@@ -180,85 +170,86 @@ void flush_remote(unsigned long cache_pfn, unsigned long cache_control,
 	panic("Unsafe to continue.");
 }
 
-void flush_remote_page(struct page *page, int order)
+static void homecache_finv_page_va(void* va, int home)
 {
-	int i, pages = (1 << order);
-	for (i = 0; i < pages; ++i, ++page) {
-		void *p = kmap_atomic(page);
-		int hfh = 0;
-		int home = page_home(page);
-#if CHIP_HAS_CBOX_HOME_MAP()
-		if (home == PAGE_HOME_HASH)
-			hfh = 1;
-		else
-#endif
-			BUG_ON(home < 0 || home >= NR_CPUS);
-		finv_buffer_remote(p, PAGE_SIZE, hfh);
-		kunmap_atomic(p);
+	if (home == smp_processor_id()) {
+		finv_buffer_local(va, PAGE_SIZE);
+	} else if (home == PAGE_HOME_HASH) {
+		finv_buffer_remote(va, PAGE_SIZE, 1);
+	} else {
+		BUG_ON(home < 0 || home >= NR_CPUS);
+		finv_buffer_remote(va, PAGE_SIZE, 0);
 	}
 }
 
-void homecache_evict(const struct cpumask *mask)
+void homecache_finv_map_page(struct page *page, int home)
 {
-	flush_remote(0, HV_FLUSH_EVICT_L2, mask, 0, 0, 0, NULL, NULL, 0);
+	unsigned long flags;
+	unsigned long va;
+	pte_t *ptep;
+	pte_t pte;
+
+	if (home == PAGE_HOME_UNCACHED)
+		return;
+	local_irq_save(flags);
+#ifdef CONFIG_HIGHMEM
+	va = __fix_to_virt(FIX_KMAP_BEGIN + kmap_atomic_idx_push() +
+			   (KM_TYPE_NR * smp_processor_id()));
+#else
+	va = __fix_to_virt(FIX_HOMECACHE_BEGIN + smp_processor_id());
+#endif
+	ptep = virt_to_pte(NULL, (unsigned long)va);
+	pte = pfn_pte(page_to_pfn(page), PAGE_KERNEL);
+	__set_pte(ptep, pte_set_home(pte, home));
+	homecache_finv_page_va((void *)va, home);
+	__pte_clear(ptep);
+	hv_flush_page(va, PAGE_SIZE);
+#ifdef CONFIG_HIGHMEM
+	kmap_atomic_idx_pop();
+#endif
+	local_irq_restore(flags);
 }
 
-/*
- * Return a mask of the cpus whose caches currently own these pages.
- * The return value is whether the pages are all coherently cached
- * (i.e. none are immutable, incoherent, or uncached).
- */
-static int homecache_mask(struct page *page, int pages,
-			  struct cpumask *home_mask)
+static void homecache_finv_page_home(struct page *page, int home)
 {
-	int i;
-	int cached_coherently = 1;
-	cpumask_clear(home_mask);
-	for (i = 0; i < pages; ++i) {
-		int home = page_home(&page[i]);
-		if (home == PAGE_HOME_IMMUTABLE ||
-		    home == PAGE_HOME_INCOHERENT) {
-			cpumask_copy(home_mask, cpu_possible_mask);
-			return 0;
-		}
-#if CHIP_HAS_CBOX_HOME_MAP()
-		if (home == PAGE_HOME_HASH) {
-			cpumask_or(home_mask, home_mask, &hash_for_home_map);
-			continue;
-		}
-#endif
-		if (home == PAGE_HOME_UNCACHED) {
-			cached_coherently = 0;
-			continue;
-		}
-		BUG_ON(home < 0 || home >= NR_CPUS);
-		cpumask_set_cpu(home, home_mask);
-	}
-	return cached_coherently;
+	if (!PageHighMem(page) && home == page_home(page))
+		homecache_finv_page_va(page_address(page), home);
+	else
+		homecache_finv_map_page(page, home);
 }
 
-/*
- * Return the passed length, or zero if it's long enough that we
- * believe we should evict the whole L2 cache.
- */
-static unsigned long cache_flush_length(unsigned long length)
+static inline bool incoherent_home(int home)
 {
-	return (length >= CHIP_L2_CACHE_SIZE()) ? HV_FLUSH_EVICT_L2 : length;
+	return home == PAGE_HOME_IMMUTABLE || home == PAGE_HOME_INCOHERENT;
 }
 
-/* Flush a page out of whatever cache(s) it is in. */
-void homecache_flush_cache(struct page *page, int order)
+static void homecache_finv_page_internal(struct page *page, int force_map)
 {
-	int pages = 1 << order;
-	int length = cache_flush_length(pages * PAGE_SIZE);
-	unsigned long pfn = page_to_pfn(page);
-	struct cpumask home_mask;
-
-	homecache_mask(page, pages, &home_mask);
-	flush_remote(pfn, length, &home_mask, 0, 0, 0, NULL, NULL, 0);
-	sim_validate_lines_evicted(PFN_PHYS(pfn), pages * PAGE_SIZE);
+	int home = page_home(page);
+	if (home == PAGE_HOME_UNCACHED)
+		return;
+	if (incoherent_home(home)) {
+		int cpu;
+		for_each_cpu(cpu, &cpu_cacheable_map)
+			homecache_finv_map_page(page, cpu);
+	} else if (force_map) {
+		/* Force if, e.g., the normal mapping is migrating. */
+		homecache_finv_map_page(page, home);
+	} else {
+		homecache_finv_page_home(page, home);
+	}
+	sim_validate_lines_evicted(PFN_PHYS(page_to_pfn(page)), PAGE_SIZE);
 }
 
+void homecache_finv_page(struct page *page)
+{
+	homecache_finv_page_internal(page, 0);
+}
+
+void homecache_evict(const struct cpumask *mask)
+{
+	flush_remote(0, HV_FLUSH_EVICT_L2, mask, 0, 0, 0, NULL, NULL, 0);
+}
 
 /* Report the home corresponding to a given PTE. */
 static int pte_to_home(pte_t pte)
@@ -441,15 +432,8 @@ struct page *homecache_alloc_pages_node(int nid, gfp_t gfp_mask,
 	return page;
 }
 
-void homecache_free_pages(unsigned long addr, unsigned int order)
+void __homecache_free_pages(struct page *page, unsigned int order)
 {
-	struct page *page;
-
-	if (addr == 0)
-		return;
-
-	VM_BUG_ON(!virt_addr_valid((void *)addr));
-	page = virt_to_page((void *)addr);
 	if (put_page_testzero(page)) {
 		homecache_change_page_home(page, order, initial_page_home());
 		if (order == 0) {
@@ -460,3 +444,13 @@ void homecache_free_pages(unsigned long addr, unsigned int order)
 		}
 	}
 }
+EXPORT_SYMBOL(__homecache_free_pages);
+
+void homecache_free_pages(unsigned long addr, unsigned int order)
+{
+	if (addr != 0) {
+		VM_BUG_ON(!virt_addr_valid((void *)addr));
+		__homecache_free_pages(virt_to_page((void *)addr), order);
+	}
+}
+EXPORT_SYMBOL(homecache_free_pages);
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index 630dd2c..ef29d6c 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
@@ -150,7 +150,21 @@ void __init shatter_pmd(pmd_t *pmd)
 	assign_pte(pmd, pte);
 }
 
-#ifdef CONFIG_HIGHMEM
+#ifdef __tilegx__
+static pmd_t *__init get_pmd(pgd_t pgtables[], unsigned long va)
+{
+	pud_t *pud = pud_offset(&pgtables[pgd_index(va)], va);
+	if (pud_none(*pud))
+		assign_pmd(pud, alloc_pmd());
+	return pmd_offset(pud, va);
+}
+#else
+static pmd_t *__init get_pmd(pgd_t pgtables[], unsigned long va)
+{
+	return pmd_offset(pud_offset(&pgtables[pgd_index(va)], va), va);
+}
+#endif
+
 /*
  * This function initializes a certain range of kernel virtual memory
  * with new bootmem page tables, everywhere page tables are missing in
@@ -163,24 +177,17 @@ void __init shatter_pmd(pmd_t *pmd)
  * checking the pgd every time.
  */
 static void __init page_table_range_init(unsigned long start,
-					 unsigned long end, pgd_t *pgd_base)
+					 unsigned long end, pgd_t *pgd)
 {
-	pgd_t *pgd;
-	int pgd_idx;
 	unsigned long vaddr;
-
-	vaddr = start;
-	pgd_idx = pgd_index(vaddr);
-	pgd = pgd_base + pgd_idx;
-
-	for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) {
-		pmd_t *pmd = pmd_offset(pud_offset(pgd, vaddr), vaddr);
+	start = round_down(start, PMD_SIZE);
+	end = round_up(end, PMD_SIZE);
+	for (vaddr = start; vaddr < end; vaddr += PMD_SIZE) {
+		pmd_t *pmd = get_pmd(pgd, vaddr);
 		if (pmd_none(*pmd))
 			assign_pte(pmd, alloc_pte());
-		vaddr += PMD_SIZE;
 	}
 }
-#endif /* CONFIG_HIGHMEM */
 
 
 #if CHIP_HAS_CBOX_HOME_MAP()
@@ -404,21 +411,6 @@ static inline pgprot_t ktext_set_nocache(pgprot_t prot)
 	return prot;
 }
 
-#ifndef __tilegx__
-static pmd_t *__init get_pmd(pgd_t pgtables[], unsigned long va)
-{
-	return pmd_offset(pud_offset(&pgtables[pgd_index(va)], va), va);
-}
-#else
-static pmd_t *__init get_pmd(pgd_t pgtables[], unsigned long va)
-{
-	pud_t *pud = pud_offset(&pgtables[pgd_index(va)], va);
-	if (pud_none(*pud))
-		assign_pmd(pud, alloc_pmd());
-	return pmd_offset(pud, va);
-}
-#endif
-
 /* Temporary page table we use for staging. */
 static pgd_t pgtables[PTRS_PER_PGD]
  __attribute__((aligned(HV_PAGE_TABLE_ALIGN)));
@@ -741,16 +733,15 @@ static void __init set_non_bootmem_pages_init(void)
 	for_each_zone(z) {
 		unsigned long start, end;
 		int nid = z->zone_pgdat->node_id;
+#ifdef CONFIG_HIGHMEM
 		int idx = zone_idx(z);
+#endif
 
 		start = z->zone_start_pfn;
-		if (start == 0)
-			continue;  /* bootmem */
 		end = start + z->spanned_pages;
-		if (idx == ZONE_NORMAL) {
-			BUG_ON(start != node_start_pfn[nid]);
-			start = node_free_pfn[nid];
-		}
+		start = max(start, node_free_pfn[nid]);
+		start = max(start, max_low_pfn);
+
 #ifdef CONFIG_HIGHMEM
 		if (idx == ZONE_HIGHMEM)
 			totalhigh_pages += z->spanned_pages;
@@ -779,9 +770,6 @@ static void __init set_non_bootmem_pages_init(void)
  */
 void __init paging_init(void)
 {
-#ifdef CONFIG_HIGHMEM
-	unsigned long vaddr, end;
-#endif
 #ifdef __tilegx__
 	pud_t *pud;
 #endif
@@ -789,14 +777,14 @@ void __init paging_init(void)
 
 	kernel_physical_mapping_init(pgd_base);
 
-#ifdef CONFIG_HIGHMEM
 	/*
 	 * Fixed mappings, only the page table structure has to be
 	 * created - mappings will be set by set_fixmap():
 	 */
-	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
-	end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK;
-	page_table_range_init(vaddr, end, pgd_base);
+	page_table_range_init(fix_to_virt(__end_of_fixed_addresses - 1),
+			      FIXADDR_TOP, pgd_base);
+
+#ifdef CONFIG_HIGHMEM
 	permanent_kmaps_init(pgd_base);
 #endif
 
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c
index 345edfe..de0de0c 100644
--- a/arch/tile/mm/pgtable.c
+++ b/arch/tile/mm/pgtable.c
@@ -575,13 +575,6 @@ void __iomem *ioremap_prot(resource_size_t phys_addr, unsigned long size,
 }
 EXPORT_SYMBOL(ioremap_prot);
 
-/* Map a PCI MMIO bus address into VA space. */
-void __iomem *ioremap(resource_size_t phys_addr, unsigned long size)
-{
-	panic("ioremap for PCI MMIO is not supported");
-}
-EXPORT_SYMBOL(ioremap);
-
 /* Unmap an MMIO VA mapping. */
 void iounmap(volatile void __iomem *addr_in)
 {
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 45e248c..87eebfe 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -150,9 +150,11 @@ void chan_enable_winch(struct chan *chan, struct tty_struct *tty)
 static void line_timer_cb(struct work_struct *work)
 {
 	struct line *line = container_of(work, struct line, task.work);
+	struct tty_struct *tty = tty_port_tty_get(&line->port);
 
 	if (!line->throttled)
-		chan_interrupt(line, line->tty, line->driver->read_irq);
+		chan_interrupt(line, tty, line->driver->read_irq);
+	tty_kref_put(tty);
 }
 
 int enable_chan(struct line *line)
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index acfd0e0..fb6e4ea 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -19,9 +19,11 @@ static irqreturn_t line_interrupt(int irq, void *data)
 {
 	struct chan *chan = data;
 	struct line *line = chan->line;
+	struct tty_struct *tty = tty_port_tty_get(&line->port);
 
 	if (line)
-		chan_interrupt(line, line->tty, irq);
+		chan_interrupt(line, tty, irq);
+	tty_kref_put(tty);
 	return IRQ_HANDLED;
 }
 
@@ -333,7 +335,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
 {
 	struct chan *chan = data;
 	struct line *line = chan->line;
-	struct tty_struct *tty = line->tty;
+	struct tty_struct *tty;
 	int err;
 
 	/*
@@ -352,10 +354,13 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
 	}
 	spin_unlock(&line->lock);
 
+	tty = tty_port_tty_get(&line->port);
 	if (tty == NULL)
 		return IRQ_NONE;
 
 	tty_wakeup(tty);
+	tty_kref_put(tty);
+
 	return IRQ_HANDLED;
 }
 
@@ -404,12 +409,12 @@ int line_open(struct line *lines, struct tty_struct *tty)
 		goto out_unlock;
 
 	err = 0;
-	if (line->count++)
+	if (line->port.count++)
 		goto out_unlock;
 
 	BUG_ON(tty->driver_data);
 	tty->driver_data = line;
-	line->tty = tty;
+	tty_port_tty_set(&line->port, tty);
 
 	err = enable_chan(line);
 	if (err) /* line_close() will be called by our caller */
@@ -446,10 +451,10 @@ void line_close(struct tty_struct *tty, struct file * filp)
 	mutex_lock(&line->count_lock);
 	BUG_ON(!line->valid);
 
-	if (--line->count)
+	if (--line->port.count)
 		goto out_unlock;
 
-	line->tty = NULL;
+	tty_port_tty_set(&line->port, NULL);
 	tty->driver_data = NULL;
 
 	if (line->sigio) {
@@ -478,7 +483,7 @@ int setup_one_line(struct line *lines, int n, char *init,
 
 	mutex_lock(&line->count_lock);
 
-	if (line->count) {
+	if (line->port.count) {
 		*error_out = "Device is already open";
 		goto out;
 	}
@@ -610,9 +615,15 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
 	mutex_lock(&line->count_lock);
 	if (!line->valid)
 		CONFIG_CHUNK(str, size, n, "none", 1);
-	else if (line->tty == NULL)
-		CONFIG_CHUNK(str, size, n, line->init_str, 1);
-	else n = chan_config_string(line, str, size, error_out);
+	else {
+		struct tty_struct *tty = tty_port_tty_get(&line->port);
+		if (tty == NULL) {
+			CONFIG_CHUNK(str, size, n, line->init_str, 1);
+		} else {
+			n = chan_config_string(line, str, size, error_out);
+			tty_kref_put(tty);
+		}
+	}
 	mutex_unlock(&line->count_lock);
 
 	return n;
@@ -663,6 +674,7 @@ int register_lines(struct line_driver *line_driver,
 	driver->init_termios = tty_std_termios;
 	
 	for (i = 0; i < nlines; i++) {
+		tty_port_init(&lines[i].port);
 		spin_lock_init(&lines[i].lock);
 		mutex_init(&lines[i].count_lock);
 		lines[i].driver = line_driver;
diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h
index 0a18347..5b3d4fb 100644
--- a/arch/um/drivers/line.h
+++ b/arch/um/drivers/line.h
@@ -32,9 +32,8 @@ struct line_driver {
 };
 
 struct line {
-	struct tty_struct *tty;
+	struct tty_port port;
 	struct mutex count_lock;
-	unsigned long count;
 	int valid;
 
 	char *init_str;
diff --git a/arch/um/include/asm/kmap_types.h b/arch/um/include/asm/kmap_types.h
index 6c03acd..2e0a6b1 100644
--- a/arch/um/include/asm/kmap_types.h
+++ b/arch/um/include/asm/kmap_types.h
@@ -8,22 +8,6 @@
 
 /* No more #include "asm/arch/kmap_types.h" ! */
 
-enum km_type {
-	KM_BOUNCE_READ,
-	KM_SKB_SUNRPC_DATA,
-	KM_SKB_DATA_SOFTIRQ,
-	KM_USER0,
-	KM_USER1,
-	KM_UML_USERCOPY,	/* UML specific, for copy_*_user - used in do_op_one_page */
-	KM_BIO_SRC_IRQ,
-	KM_BIO_DST_IRQ,
-	KM_PTE0,
-	KM_PTE1,
-	KM_IRQ0,
-	KM_IRQ1,
-	KM_SOFTIRQ0,
-	KM_SOFTIRQ1,
-	KM_TYPE_NR
-};
+#define KM_TYPE_NR 14
 
 #endif
diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h
index c04e5ab..2c8eeb2 100644
--- a/arch/um/include/asm/thread_info.h
+++ b/arch/um/include/asm/thread_info.h
@@ -65,8 +65,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 #define TIF_SIGPENDING		1	/* signal pending */
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
-#define TIF_POLLING_NRFLAG      3       /* true if poll_idle() is polling
-					 * TIF_NEED_RESCHED */
 #define TIF_RESTART_BLOCK	4
 #define TIF_MEMDIE		5	/* is terminating due to OOM killer */
 #define TIF_SYSCALL_AUDIT	6
@@ -76,7 +74,6 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG     (1 << TIF_POLLING_NRFLAG)
 #define _TIF_MEMDIE		(1 << TIF_MEMDIE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 
diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
index 03c9ff8..dfc72cc 100644
--- a/arch/unicore32/Kconfig
+++ b/arch/unicore32/Kconfig
@@ -65,6 +65,9 @@ config GENERIC_CALIBRATE_DELAY
 config ARCH_MAY_HAVE_PC_FDC
 	bool
 
+config ZONE_DMA
+	def_bool y
+
 config NEED_DMA_MAP_STATE
        def_bool y
 
diff --git a/arch/unicore32/include/asm/bug.h b/arch/unicore32/include/asm/bug.h
index b1ff8ca..93a56f3 100644
--- a/arch/unicore32/include/asm/bug.h
+++ b/arch/unicore32/include/asm/bug.h
@@ -19,9 +19,4 @@ extern void die(const char *msg, struct pt_regs *regs, int err);
 extern void uc32_notify_die(const char *str, struct pt_regs *regs,
 		struct siginfo *info, unsigned long err, unsigned long trap);
 
-extern asmlinkage void __backtrace(void);
-extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
-
-extern void __show_regs(struct pt_regs *);
-
 #endif /* __UNICORE_BUG_H__ */
diff --git a/arch/unicore32/include/asm/cmpxchg.h b/arch/unicore32/include/asm/cmpxchg.h
index df4d5ac..8e797ad 100644
--- a/arch/unicore32/include/asm/cmpxchg.h
+++ b/arch/unicore32/include/asm/cmpxchg.h
@@ -35,7 +35,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
 			: "memory", "cc");
 		break;
 	default:
-		ret = __xchg_bad_pointer();
+		__xchg_bad_pointer();
 	}
 
 	return ret;
diff --git a/arch/unicore32/include/asm/thread_info.h b/arch/unicore32/include/asm/thread_info.h
index 89f7557..818b4a1 100644
--- a/arch/unicore32/include/asm/thread_info.h
+++ b/arch/unicore32/include/asm/thread_info.h
@@ -141,12 +141,12 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
-#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 
 /*
  * Change these and you break ASM code in entry-common.S
  */
-#define _TIF_WORK_MASK		0x000000ff
+#define _TIF_WORK_MASK \
+	(_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME)
 
 #endif /* __KERNEL__ */
 #endif /* __UNICORE_THREAD_INFO_H__ */
diff --git a/arch/unicore32/kernel/entry.S b/arch/unicore32/kernel/entry.S
index 00a259f..dcb87ab 100644
--- a/arch/unicore32/kernel/entry.S
+++ b/arch/unicore32/kernel/entry.S
@@ -544,8 +544,6 @@ fast_work_pending:
 work_pending:
 	cand.a	r1, #_TIF_NEED_RESCHED
 	bne	work_resched
-	cand.a	r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME
-	beq	no_work_pending
 	mov	r0, sp				@ 'regs'
 	mov	r2, why				@ 'syscall'
 	cand.a	r1, #_TIF_SIGPENDING		@ delivering a signal?
diff --git a/arch/unicore32/kernel/setup.h b/arch/unicore32/kernel/setup.h
index f239550..30f749d 100644
--- a/arch/unicore32/kernel/setup.h
+++ b/arch/unicore32/kernel/setup.h
@@ -30,4 +30,10 @@ extern char __vectors_start[], __vectors_end[];
 extern void kernel_thread_helper(void);
 
 extern void __init early_signal_init(void);
+
+extern asmlinkage void __backtrace(void);
+extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
+
+extern void __show_regs(struct pt_regs *);
+
 #endif
diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c
index 8adedb3..b8b2ffd 100644
--- a/arch/unicore32/kernel/signal.c
+++ b/arch/unicore32/kernel/signal.c
@@ -12,7 +12,6 @@
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/tracehook.h>
 #include <linux/elf.h>
diff --git a/arch/unicore32/mm/fault.c b/arch/unicore32/mm/fault.c
index 2eeb9c0..f9b5c10 100644
--- a/arch/unicore32/mm/fault.c
+++ b/arch/unicore32/mm/fault.c
@@ -168,7 +168,7 @@ static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma)
 }
 
 static int __do_pf(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
-		struct task_struct *tsk)
+		unsigned int flags, struct task_struct *tsk)
 {
 	struct vm_area_struct *vma;
 	int fault;
@@ -194,14 +194,7 @@ good_area:
 	 * If for any reason at all we couldn't handle the fault, make
 	 * sure we exit gracefully rather than endlessly redo the fault.
 	 */
-	fault = handle_mm_fault(mm, vma, addr & PAGE_MASK,
-			    (!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0);
-	if (unlikely(fault & VM_FAULT_ERROR))
-		return fault;
-	if (fault & VM_FAULT_MAJOR)
-		tsk->maj_flt++;
-	else
-		tsk->min_flt++;
+	fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, flags);
 	return fault;
 
 check_stack:
@@ -216,6 +209,8 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	struct task_struct *tsk;
 	struct mm_struct *mm;
 	int fault, sig, code;
+	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+				 ((!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0);
 
 	tsk = current;
 	mm = tsk->mm;
@@ -236,6 +231,7 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 		if (!user_mode(regs)
 		    && !search_exception_tables(regs->UCreg_pc))
 			goto no_context;
+retry:
 		down_read(&mm->mmap_sem);
 	} else {
 		/*
@@ -251,7 +247,28 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 #endif
 	}
 
-	fault = __do_pf(mm, addr, fsr, tsk);
+	fault = __do_pf(mm, addr, fsr, flags, tsk);
+
+	/* If we need to retry but a fatal signal is pending, handle the
+	 * signal first. We do not need to release the mmap_sem because
+	 * it would already be released in __lock_page_or_retry in
+	 * mm/filemap.c. */
+	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+		return 0;
+
+	if (!(fault & VM_FAULT_ERROR) && (flags & FAULT_FLAG_ALLOW_RETRY)) {
+		if (fault & VM_FAULT_MAJOR)
+			tsk->maj_flt++;
+		else
+			tsk->min_flt++;
+		if (fault & VM_FAULT_RETRY) {
+			/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+			* of starvation. */
+			flags &= ~FAULT_FLAG_ALLOW_RETRY;
+			goto retry;
+		}
+	}
+
 	up_read(&mm->mmap_sem);
 
 	/*
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c70684f..d35438e 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -547,6 +547,37 @@ config SCHED_OMIT_FRAME_POINTER
 
 	  If in doubt, say "Y".
 
+config KVMTOOL_TEST_ENABLE
+	bool "Enable options to create a bootable tools/kvm/ kernel"
+	select NET
+	select NETDEVICES
+	select PCI
+	select BLOCK
+	select BLK_DEV
+	select NETWORK_FILESYSTEMS
+	select INET
+	select EXPERIMENTAL
+	select SERIAL_8250
+	select SERIAL_8250_CONSOLE
+	select IP_PNP
+	select IP_PNP_DHCP
+	select BINFMT_ELF
+	select PCI_MSI
+	select HAVE_ARCH_KGDB
+	select DEBUG_KERNEL
+	select KGDB
+	select KGDB_SERIAL_CONSOLE
+	select VIRTUALIZATION
+	select VIRTIO
+	select VIRTIO_RING
+	select VIRTIO_PCI
+	select VIRTIO_BLK
+	select VIRTIO_CONSOLE
+	select VIRTIO_NET
+	select 9P_FS
+	select NET_9P
+	select NET_9P_VIRTIO
+
 menuconfig PARAVIRT_GUEST
 	bool "Paravirtualized guest support"
 	---help---
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 1f25214..b0c5276 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -49,6 +49,9 @@ else
         KBUILD_AFLAGS += -m64
         KBUILD_CFLAGS += -m64
 
+	# Use -mpreferred-stack-boundary=3 if supported.
+	KBUILD_CFLAGS += $(call cc-option,-mno-sse -mpreferred-stack-boundary=3)
+
         # FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu)
         cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8)
         cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona)
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index efe5acf..9b9c647 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -406,13 +406,6 @@ init_size:		.long INIT_SIZE		# kernel initialization size
 
 	.section ".entrytext", "ax"
 start_of_setup:
-#ifdef SAFE_RESET_DISK_CONTROLLER
-# Reset the disk controller.
-	movw	$0x0000, %ax		# Reset disk controller
-	movb	$0x80, %dl		# All disks
-	int	$0x13
-#endif
-
 # Force %es = %ds
 	movw	%ds, %ax
 	movw	%ax, %es
diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
index e191ac0..83caa4b 100644
--- a/arch/x86/crypto/Makefile
+++ b/arch/x86/crypto/Makefile
@@ -12,8 +12,10 @@ obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o
 obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o
+obj-$(CONFIG_CRYPTO_TWOFISH_AVX_X86_64) += twofish-avx-x86_64.o
 obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o
 obj-$(CONFIG_CRYPTO_SERPENT_SSE2_X86_64) += serpent-sse2-x86_64.o
+obj-$(CONFIG_CRYPTO_SERPENT_AVX_X86_64) += serpent-avx-x86_64.o
 obj-$(CONFIG_CRYPTO_AES_NI_INTEL) += aesni-intel.o
 obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o
 
@@ -30,16 +32,11 @@ camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o
 blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o
 twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
 twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o
+twofish-avx-x86_64-y := twofish-avx-x86_64-asm_64.o twofish_avx_glue.o
 salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o
 serpent-sse2-x86_64-y := serpent-sse2-x86_64-asm_64.o serpent_sse2_glue.o
+serpent-avx-x86_64-y := serpent-avx-x86_64-asm_64.o serpent_avx_glue.o
 
 aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o fpu.o
-
 ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o
-
-# enable AVX support only when $(AS) can actually assemble the instructions
-ifeq ($(call as-instr,vpxor %xmm0$(comma)%xmm1$(comma)%xmm2,yes,no),yes)
-AFLAGS_sha1_ssse3_asm.o += -DSHA1_ENABLE_AVX_SUPPORT
-CFLAGS_sha1_ssse3_glue.o += -DSHA1_ENABLE_AVX_SUPPORT
-endif
 sha1-ssse3-y := sha1_ssse3_asm.o sha1_ssse3_glue.o
diff --git a/arch/x86/crypto/serpent-avx-x86_64-asm_64.S b/arch/x86/crypto/serpent-avx-x86_64-asm_64.S
new file mode 100644
index 0000000..504106b
--- /dev/null
+++ b/arch/x86/crypto/serpent-avx-x86_64-asm_64.S
@@ -0,0 +1,704 @@
+/*
+ * Serpent Cipher 8-way parallel algorithm (x86_64/AVX)
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * Based on arch/x86/crypto/serpent-sse2-x86_64-asm_64.S by
+ *  Copyright (C) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+.file "serpent-avx-x86_64-asm_64.S"
+.text
+
+#define CTX %rdi
+
+/**********************************************************************
+  8-way AVX serpent
+ **********************************************************************/
+#define RA1 %xmm0
+#define RB1 %xmm1
+#define RC1 %xmm2
+#define RD1 %xmm3
+#define RE1 %xmm4
+
+#define tp  %xmm5
+
+#define RA2 %xmm6
+#define RB2 %xmm7
+#define RC2 %xmm8
+#define RD2 %xmm9
+#define RE2 %xmm10
+
+#define RNOT %xmm11
+
+#define RK0 %xmm12
+#define RK1 %xmm13
+#define RK2 %xmm14
+#define RK3 %xmm15
+
+
+#define S0_1(x0, x1, x2, x3, x4)      \
+	vpor		x0,   x3, tp; \
+	vpxor		x3,   x0, x0; \
+	vpxor		x2,   x3, x4; \
+	vpxor		RNOT, x4, x4; \
+	vpxor		x1,   tp, x3; \
+	vpand		x0,   x1, x1; \
+	vpxor		x4,   x1, x1; \
+	vpxor		x0,   x2, x2;
+#define S0_2(x0, x1, x2, x3, x4)      \
+	vpxor		x3,   x0, x0; \
+	vpor		x0,   x4, x4; \
+	vpxor		x2,   x0, x0; \
+	vpand		x1,   x2, x2; \
+	vpxor		x2,   x3, x3; \
+	vpxor		RNOT, x1, x1; \
+	vpxor		x4,   x2, x2; \
+	vpxor		x2,   x1, x1;
+
+#define S1_1(x0, x1, x2, x3, x4)      \
+	vpxor		x0,   x1, tp; \
+	vpxor		x3,   x0, x0; \
+	vpxor		RNOT, x3, x3; \
+	vpand		tp,   x1, x4; \
+	vpor		tp,   x0, x0; \
+	vpxor		x2,   x3, x3; \
+	vpxor		x3,   x0, x0; \
+	vpxor		x3,   tp, x1;
+#define S1_2(x0, x1, x2, x3, x4)      \
+	vpxor		x4,   x3, x3; \
+	vpor		x4,   x1, x1; \
+	vpxor		x2,   x4, x4; \
+	vpand		x0,   x2, x2; \
+	vpxor		x1,   x2, x2; \
+	vpor		x0,   x1, x1; \
+	vpxor		RNOT, x0, x0; \
+	vpxor		x2,   x0, x0; \
+	vpxor		x1,   x4, x4;
+
+#define S2_1(x0, x1, x2, x3, x4)      \
+	vpxor		RNOT, x3, x3; \
+	vpxor		x0,   x1, x1; \
+	vpand		x2,   x0, tp; \
+	vpxor		x3,   tp, tp; \
+	vpor		x0,   x3, x3; \
+	vpxor		x1,   x2, x2; \
+	vpxor		x1,   x3, x3; \
+	vpand		tp,   x1, x1;
+#define S2_2(x0, x1, x2, x3, x4)      \
+	vpxor		x2,   tp, tp; \
+	vpand		x3,   x2, x2; \
+	vpor		x1,   x3, x3; \
+	vpxor		RNOT, tp, tp; \
+	vpxor		tp,   x3, x3; \
+	vpxor		tp,   x0, x4; \
+	vpxor		x2,   tp, x0; \
+	vpor		x2,   x1, x1;
+
+#define S3_1(x0, x1, x2, x3, x4)      \
+	vpxor		x3,   x1, tp; \
+	vpor		x0,   x3, x3; \
+	vpand		x0,   x1, x4; \
+	vpxor		x2,   x0, x0; \
+	vpxor		tp,   x2, x2; \
+	vpand		x3,   tp, x1; \
+	vpxor		x3,   x2, x2; \
+	vpor		x4,   x0, x0; \
+	vpxor		x3,   x4, x4;
+#define S3_2(x0, x1, x2, x3, x4)      \
+	vpxor		x0,   x1, x1; \
+	vpand		x3,   x0, x0; \
+	vpand		x4,   x3, x3; \
+	vpxor		x2,   x3, x3; \
+	vpor		x1,   x4, x4; \
+	vpand		x1,   x2, x2; \
+	vpxor		x3,   x4, x4; \
+	vpxor		x3,   x0, x0; \
+	vpxor		x2,   x3, x3;
+
+#define S4_1(x0, x1, x2, x3, x4)      \
+	vpand		x0,   x3, tp; \
+	vpxor		x3,   x0, x0; \
+	vpxor		x2,   tp, tp; \
+	vpor		x3,   x2, x2; \
+	vpxor		x1,   x0, x0; \
+	vpxor		tp,   x3, x4; \
+	vpor		x0,   x2, x2; \
+	vpxor		x1,   x2, x2;
+#define S4_2(x0, x1, x2, x3, x4)      \
+	vpand		x0,   x1, x1; \
+	vpxor		x4,   x1, x1; \
+	vpand		x2,   x4, x4; \
+	vpxor		tp,   x2, x2; \
+	vpxor		x0,   x4, x4; \
+	vpor		x1,   tp, x3; \
+	vpxor		RNOT, x1, x1; \
+	vpxor		x0,   x3, x3;
+
+#define S5_1(x0, x1, x2, x3, x4)      \
+	vpor		x0,   x1, tp; \
+	vpxor		tp,   x2, x2; \
+	vpxor		RNOT, x3, x3; \
+	vpxor		x0,   x1, x4; \
+	vpxor		x2,   x0, x0; \
+	vpand		x4,   tp, x1; \
+	vpor		x3,   x4, x4; \
+	vpxor		x0,   x4, x4;
+#define S5_2(x0, x1, x2, x3, x4)      \
+	vpand		x3,   x0, x0; \
+	vpxor		x3,   x1, x1; \
+	vpxor		x2,   x3, x3; \
+	vpxor		x1,   x0, x0; \
+	vpand		x4,   x2, x2; \
+	vpxor		x2,   x1, x1; \
+	vpand		x0,   x2, x2; \
+	vpxor		x2,   x3, x3;
+
+#define S6_1(x0, x1, x2, x3, x4)      \
+	vpxor		x0,   x3, x3; \
+	vpxor		x2,   x1, tp; \
+	vpxor		x0,   x2, x2; \
+	vpand		x3,   x0, x0; \
+	vpor		x3,   tp, tp; \
+	vpxor		RNOT, x1, x4; \
+	vpxor		tp,   x0, x0; \
+	vpxor		x2,   tp, x1;
+#define S6_2(x0, x1, x2, x3, x4)      \
+	vpxor		x4,   x3, x3; \
+	vpxor		x0,   x4, x4; \
+	vpand		x0,   x2, x2; \
+	vpxor		x1,   x4, x4; \
+	vpxor		x3,   x2, x2; \
+	vpand		x1,   x3, x3; \
+	vpxor		x0,   x3, x3; \
+	vpxor		x2,   x1, x1;
+
+#define S7_1(x0, x1, x2, x3, x4)      \
+	vpxor		RNOT, x1, tp; \
+	vpxor		RNOT, x0, x0; \
+	vpand		x2,   tp, x1; \
+	vpxor		x3,   x1, x1; \
+	vpor		tp,   x3, x3; \
+	vpxor		x2,   tp, x4; \
+	vpxor		x3,   x2, x2; \
+	vpxor		x0,   x3, x3; \
+	vpor		x1,   x0, x0;
+#define S7_2(x0, x1, x2, x3, x4)      \
+	vpand		x0,   x2, x2; \
+	vpxor		x4,   x0, x0; \
+	vpxor		x3,   x4, x4; \
+	vpand		x0,   x3, x3; \
+	vpxor		x1,   x4, x4; \
+	vpxor		x4,   x2, x2; \
+	vpxor		x1,   x3, x3; \
+	vpor		x0,   x4, x4; \
+	vpxor		x1,   x4, x4;
+
+#define SI0_1(x0, x1, x2, x3, x4)     \
+	vpxor		x0,   x1, x1; \
+	vpor		x1,   x3, tp; \
+	vpxor		x1,   x3, x4; \
+	vpxor		RNOT, x0, x0; \
+	vpxor		tp,   x2, x2; \
+	vpxor		x0,   tp, x3; \
+	vpand		x1,   x0, x0; \
+	vpxor		x2,   x0, x0;
+#define SI0_2(x0, x1, x2, x3, x4)     \
+	vpand		x3,   x2, x2; \
+	vpxor		x4,   x3, x3; \
+	vpxor		x3,   x2, x2; \
+	vpxor		x3,   x1, x1; \
+	vpand		x0,   x3, x3; \
+	vpxor		x0,   x1, x1; \
+	vpxor		x2,   x0, x0; \
+	vpxor		x3,   x4, x4;
+
+#define SI1_1(x0, x1, x2, x3, x4)     \
+	vpxor		x3,   x1, x1; \
+	vpxor		x2,   x0, tp; \
+	vpxor		RNOT, x2, x2; \
+	vpor		x1,   x0, x4; \
+	vpxor		x3,   x4, x4; \
+	vpand		x1,   x3, x3; \
+	vpxor		x2,   x1, x1; \
+	vpand		x4,   x2, x2;
+#define SI1_2(x0, x1, x2, x3, x4)     \
+	vpxor		x1,   x4, x4; \
+	vpor		x3,   x1, x1; \
+	vpxor		tp,   x3, x3; \
+	vpxor		tp,   x2, x2; \
+	vpor		x4,   tp, x0; \
+	vpxor		x4,   x2, x2; \
+	vpxor		x0,   x1, x1; \
+	vpxor		x1,   x4, x4;
+
+#define SI2_1(x0, x1, x2, x3, x4)     \
+	vpxor		x1,   x2, x2; \
+	vpxor		RNOT, x3, tp; \
+	vpor		x2,   tp, tp; \
+	vpxor		x3,   x2, x2; \
+	vpxor		x0,   x3, x4; \
+	vpxor		x1,   tp, x3; \
+	vpor		x2,   x1, x1; \
+	vpxor		x0,   x2, x2;
+#define SI2_2(x0, x1, x2, x3, x4)     \
+	vpxor		x4,   x1, x1; \
+	vpor		x3,   x4, x4; \
+	vpxor		x3,   x2, x2; \
+	vpxor		x2,   x4, x4; \
+	vpand		x1,   x2, x2; \
+	vpxor		x3,   x2, x2; \
+	vpxor		x4,   x3, x3; \
+	vpxor		x0,   x4, x4;
+
+#define SI3_1(x0, x1, x2, x3, x4)     \
+	vpxor		x1,   x2, x2; \
+	vpand		x2,   x1, tp; \
+	vpxor		x0,   tp, tp; \
+	vpor		x1,   x0, x0; \
+	vpxor		x3,   x1, x4; \
+	vpxor		x3,   x0, x0; \
+	vpor		tp,   x3, x3; \
+	vpxor		x2,   tp, x1;
+#define SI3_2(x0, x1, x2, x3, x4)     \
+	vpxor		x3,   x1, x1; \
+	vpxor		x2,   x0, x0; \
+	vpxor		x3,   x2, x2; \
+	vpand		x1,   x3, x3; \
+	vpxor		x0,   x1, x1; \
+	vpand		x2,   x0, x0; \
+	vpxor		x3,   x4, x4; \
+	vpxor		x0,   x3, x3; \
+	vpxor		x1,   x0, x0;
+
+#define SI4_1(x0, x1, x2, x3, x4)     \
+	vpxor		x3,   x2, x2; \
+	vpand		x1,   x0, tp; \
+	vpxor		x2,   tp, tp; \
+	vpor		x3,   x2, x2; \
+	vpxor		RNOT, x0, x4; \
+	vpxor		tp,   x1, x1; \
+	vpxor		x2,   tp, x0; \
+	vpand		x4,   x2, x2;
+#define SI4_2(x0, x1, x2, x3, x4)     \
+	vpxor		x0,   x2, x2; \
+	vpor		x4,   x0, x0; \
+	vpxor		x3,   x0, x0; \
+	vpand		x2,   x3, x3; \
+	vpxor		x3,   x4, x4; \
+	vpxor		x1,   x3, x3; \
+	vpand		x0,   x1, x1; \
+	vpxor		x1,   x4, x4; \
+	vpxor		x3,   x0, x0;
+
+#define SI5_1(x0, x1, x2, x3, x4)     \
+	vpor		x2,   x1, tp; \
+	vpxor		x1,   x2, x2; \
+	vpxor		x3,   tp, tp; \
+	vpand		x1,   x3, x3; \
+	vpxor		x3,   x2, x2; \
+	vpor		x0,   x3, x3; \
+	vpxor		RNOT, x0, x0; \
+	vpxor		x2,   x3, x3; \
+	vpor		x0,   x2, x2;
+#define SI5_2(x0, x1, x2, x3, x4)     \
+	vpxor		tp,   x1, x4; \
+	vpxor		x4,   x2, x2; \
+	vpand		x0,   x4, x4; \
+	vpxor		tp,   x0, x0; \
+	vpxor		x3,   tp, x1; \
+	vpand		x2,   x0, x0; \
+	vpxor		x3,   x2, x2; \
+	vpxor		x2,   x0, x0; \
+	vpxor		x4,   x2, x2; \
+	vpxor		x3,   x4, x4;
+
+#define SI6_1(x0, x1, x2, x3, x4)     \
+	vpxor		x2,   x0, x0; \
+	vpand		x3,   x0, tp; \
+	vpxor		x3,   x2, x2; \
+	vpxor		x2,   tp, tp; \
+	vpxor		x1,   x3, x3; \
+	vpor		x0,   x2, x2; \
+	vpxor		x3,   x2, x2; \
+	vpand		tp,   x3, x3;
+#define SI6_2(x0, x1, x2, x3, x4)     \
+	vpxor		RNOT, tp, tp; \
+	vpxor		x1,   x3, x3; \
+	vpand		x2,   x1, x1; \
+	vpxor		tp,   x0, x4; \
+	vpxor		x4,   x3, x3; \
+	vpxor		x2,   x4, x4; \
+	vpxor		x1,   tp, x0; \
+	vpxor		x0,   x2, x2;
+
+#define SI7_1(x0, x1, x2, x3, x4)     \
+	vpand		x0,   x3, tp; \
+	vpxor		x2,   x0, x0; \
+	vpor		x3,   x2, x2; \
+	vpxor		x1,   x3, x4; \
+	vpxor		RNOT, x0, x0; \
+	vpor		tp,   x1, x1; \
+	vpxor		x0,   x4, x4; \
+	vpand		x2,   x0, x0; \
+	vpxor		x1,   x0, x0;
+#define SI7_2(x0, x1, x2, x3, x4)     \
+	vpand		x2,   x1, x1; \
+	vpxor		x2,   tp, x3; \
+	vpxor		x3,   x4, x4; \
+	vpand		x3,   x2, x2; \
+	vpor		x0,   x3, x3; \
+	vpxor		x4,   x1, x1; \
+	vpxor		x4,   x3, x3; \
+	vpand		x0,   x4, x4; \
+	vpxor		x2,   x4, x4;
+
+#define get_key(i, j, t) \
+	vbroadcastss (4*(i)+(j))*4(CTX), t;
+
+#define K2(x0, x1, x2, x3, x4, i) \
+	get_key(i, 0, RK0); \
+	get_key(i, 1, RK1); \
+	get_key(i, 2, RK2); \
+	get_key(i, 3, RK3); \
+	vpxor RK0,	x0 ## 1, x0 ## 1; \
+	vpxor RK1,	x1 ## 1, x1 ## 1; \
+	vpxor RK2,	x2 ## 1, x2 ## 1; \
+	vpxor RK3,	x3 ## 1, x3 ## 1; \
+		vpxor RK0,	x0 ## 2, x0 ## 2; \
+		vpxor RK1,	x1 ## 2, x1 ## 2; \
+		vpxor RK2,	x2 ## 2, x2 ## 2; \
+		vpxor RK3,	x3 ## 2, x3 ## 2;
+
+#define LK2(x0, x1, x2, x3, x4, i) \
+	vpslld $13,		x0 ## 1, x4 ## 1;          \
+	vpsrld $(32 - 13),	x0 ## 1, x0 ## 1;          \
+	vpor			x4 ## 1, x0 ## 1, x0 ## 1; \
+	vpxor			x0 ## 1, x1 ## 1, x1 ## 1; \
+	vpslld $3,		x2 ## 1, x4 ## 1;          \
+	vpsrld $(32 - 3),	x2 ## 1, x2 ## 1;          \
+	vpor			x4 ## 1, x2 ## 1, x2 ## 1; \
+	vpxor			x2 ## 1, x1 ## 1, x1 ## 1; \
+		vpslld $13,		x0 ## 2, x4 ## 2;          \
+		vpsrld $(32 - 13),	x0 ## 2, x0 ## 2;          \
+		vpor			x4 ## 2, x0 ## 2, x0 ## 2; \
+		vpxor			x0 ## 2, x1 ## 2, x1 ## 2; \
+		vpslld $3,		x2 ## 2, x4 ## 2;          \
+		vpsrld $(32 - 3),	x2 ## 2, x2 ## 2;          \
+		vpor			x4 ## 2, x2 ## 2, x2 ## 2; \
+		vpxor			x2 ## 2, x1 ## 2, x1 ## 2; \
+	vpslld $1,		x1 ## 1, x4 ## 1;          \
+	vpsrld $(32 - 1),	x1 ## 1, x1 ## 1;          \
+	vpor			x4 ## 1, x1 ## 1, x1 ## 1; \
+	vpslld $3,		x0 ## 1, x4 ## 1;          \
+	vpxor			x2 ## 1, x3 ## 1, x3 ## 1; \
+	vpxor			x4 ## 1, x3 ## 1, x3 ## 1; \
+	get_key(i, 1, RK1); \
+		vpslld $1,		x1 ## 2, x4 ## 2;          \
+		vpsrld $(32 - 1),	x1 ## 2, x1 ## 2;          \
+		vpor			x4 ## 2, x1 ## 2, x1 ## 2; \
+		vpslld $3,		x0 ## 2, x4 ## 2;          \
+		vpxor			x2 ## 2, x3 ## 2, x3 ## 2; \
+		vpxor			x4 ## 2, x3 ## 2, x3 ## 2; \
+		get_key(i, 3, RK3); \
+	vpslld $7,		x3 ## 1, x4 ## 1;          \
+	vpsrld $(32 - 7),	x3 ## 1, x3 ## 1;          \
+	vpor			x4 ## 1, x3 ## 1, x3 ## 1; \
+	vpslld $7,		x1 ## 1, x4 ## 1;          \
+	vpxor			x1 ## 1, x0 ## 1, x0 ## 1; \
+	vpxor			x3 ## 1, x0 ## 1, x0 ## 1; \
+	vpxor			x3 ## 1, x2 ## 1, x2 ## 1; \
+	vpxor			x4 ## 1, x2 ## 1, x2 ## 1; \
+	get_key(i, 0, RK0); \
+		vpslld $7,		x3 ## 2, x4 ## 2;          \
+		vpsrld $(32 - 7),	x3 ## 2, x3 ## 2;          \
+		vpor			x4 ## 2, x3 ## 2, x3 ## 2; \
+		vpslld $7,		x1 ## 2, x4 ## 2;          \
+		vpxor			x1 ## 2, x0 ## 2, x0 ## 2; \
+		vpxor			x3 ## 2, x0 ## 2, x0 ## 2; \
+		vpxor			x3 ## 2, x2 ## 2, x2 ## 2; \
+		vpxor			x4 ## 2, x2 ## 2, x2 ## 2; \
+		get_key(i, 2, RK2); \
+	vpxor			RK1, x1 ## 1, x1 ## 1;     \
+	vpxor			RK3, x3 ## 1, x3 ## 1;     \
+	vpslld $5,		x0 ## 1, x4 ## 1;          \
+	vpsrld $(32 - 5),	x0 ## 1, x0 ## 1;          \
+	vpor			x4 ## 1, x0 ## 1, x0 ## 1; \
+	vpslld $22,		x2 ## 1, x4 ## 1;          \
+	vpsrld $(32 - 22),	x2 ## 1, x2 ## 1;          \
+	vpor			x4 ## 1, x2 ## 1, x2 ## 1; \
+	vpxor			RK0, x0 ## 1, x0 ## 1;     \
+	vpxor			RK2, x2 ## 1, x2 ## 1;     \
+		vpxor			RK1, x1 ## 2, x1 ## 2;     \
+		vpxor			RK3, x3 ## 2, x3 ## 2;     \
+		vpslld $5,		x0 ## 2, x4 ## 2;          \
+		vpsrld $(32 - 5),	x0 ## 2, x0 ## 2;          \
+		vpor			x4 ## 2, x0 ## 2, x0 ## 2; \
+		vpslld $22,		x2 ## 2, x4 ## 2;          \
+		vpsrld $(32 - 22),	x2 ## 2, x2 ## 2;          \
+		vpor			x4 ## 2, x2 ## 2, x2 ## 2; \
+		vpxor			RK0, x0 ## 2, x0 ## 2;     \
+		vpxor			RK2, x2 ## 2, x2 ## 2;
+
+#define KL2(x0, x1, x2, x3, x4, i) \
+	vpxor			RK0, x0 ## 1, x0 ## 1;     \
+	vpxor			RK2, x2 ## 1, x2 ## 1;     \
+	vpsrld $5,		x0 ## 1, x4 ## 1;          \
+	vpslld $(32 - 5),	x0 ## 1, x0 ## 1;          \
+	vpor			x4 ## 1, x0 ## 1, x0 ## 1; \
+	vpxor			RK3, x3 ## 1, x3 ## 1;     \
+	vpxor			RK1, x1 ## 1, x1 ## 1;     \
+	vpsrld $22,		x2 ## 1, x4 ## 1;          \
+	vpslld $(32 - 22),	x2 ## 1, x2 ## 1;          \
+	vpor			x4 ## 1, x2 ## 1, x2 ## 1; \
+	vpxor			x3 ## 1, x2 ## 1, x2 ## 1; \
+		vpxor			RK0, x0 ## 2, x0 ## 2;     \
+		vpxor			RK2, x2 ## 2, x2 ## 2;     \
+		vpsrld $5,		x0 ## 2, x4 ## 2;          \
+		vpslld $(32 - 5),	x0 ## 2, x0 ## 2;          \
+		vpor			x4 ## 2, x0 ## 2, x0 ## 2; \
+		vpxor			RK3, x3 ## 2, x3 ## 2;     \
+		vpxor			RK1, x1 ## 2, x1 ## 2;     \
+		vpsrld $22,		x2 ## 2, x4 ## 2;          \
+		vpslld $(32 - 22),	x2 ## 2, x2 ## 2;          \
+		vpor			x4 ## 2, x2 ## 2, x2 ## 2; \
+		vpxor			x3 ## 2, x2 ## 2, x2 ## 2; \
+	vpxor			x3 ## 1, x0 ## 1, x0 ## 1; \
+	vpslld $7,		x1 ## 1, x4 ## 1;          \
+	vpxor			x1 ## 1, x0 ## 1, x0 ## 1; \
+	vpxor			x4 ## 1, x2 ## 1, x2 ## 1; \
+	vpsrld $1,		x1 ## 1, x4 ## 1;          \
+	vpslld $(32 - 1),	x1 ## 1, x1 ## 1;          \
+	vpor			x4 ## 1, x1 ## 1, x1 ## 1; \
+		vpxor			x3 ## 2, x0 ## 2, x0 ## 2; \
+		vpslld $7,		x1 ## 2, x4 ## 2;          \
+		vpxor			x1 ## 2, x0 ## 2, x0 ## 2; \
+		vpxor			x4 ## 2, x2 ## 2, x2 ## 2; \
+		vpsrld $1,		x1 ## 2, x4 ## 2;          \
+		vpslld $(32 - 1),	x1 ## 2, x1 ## 2;          \
+		vpor			x4 ## 2, x1 ## 2, x1 ## 2; \
+	vpsrld $7,		x3 ## 1, x4 ## 1;          \
+	vpslld $(32 - 7),	x3 ## 1, x3 ## 1;          \
+	vpor			x4 ## 1, x3 ## 1, x3 ## 1; \
+	vpxor			x0 ## 1, x1 ## 1, x1 ## 1; \
+	vpslld $3,		x0 ## 1, x4 ## 1;          \
+	vpxor			x4 ## 1, x3 ## 1, x3 ## 1; \
+		vpsrld $7,		x3 ## 2, x4 ## 2;          \
+		vpslld $(32 - 7),	x3 ## 2, x3 ## 2;          \
+		vpor			x4 ## 2, x3 ## 2, x3 ## 2; \
+		vpxor			x0 ## 2, x1 ## 2, x1 ## 2; \
+		vpslld $3,		x0 ## 2, x4 ## 2;          \
+		vpxor			x4 ## 2, x3 ## 2, x3 ## 2; \
+	vpsrld $13,		x0 ## 1, x4 ## 1;          \
+	vpslld $(32 - 13),	x0 ## 1, x0 ## 1;          \
+	vpor			x4 ## 1, x0 ## 1, x0 ## 1; \
+	vpxor			x2 ## 1, x1 ## 1, x1 ## 1; \
+	vpxor			x2 ## 1, x3 ## 1, x3 ## 1; \
+	vpsrld $3,		x2 ## 1, x4 ## 1;          \
+	vpslld $(32 - 3),	x2 ## 1, x2 ## 1;          \
+	vpor			x4 ## 1, x2 ## 1, x2 ## 1; \
+		vpsrld $13,		x0 ## 2, x4 ## 2;          \
+		vpslld $(32 - 13),	x0 ## 2, x0 ## 2;          \
+		vpor			x4 ## 2, x0 ## 2, x0 ## 2; \
+		vpxor			x2 ## 2, x1 ## 2, x1 ## 2; \
+		vpxor			x2 ## 2, x3 ## 2, x3 ## 2; \
+		vpsrld $3,		x2 ## 2, x4 ## 2;          \
+		vpslld $(32 - 3),	x2 ## 2, x2 ## 2;          \
+		vpor			x4 ## 2, x2 ## 2, x2 ## 2;
+
+#define S(SBOX, x0, x1, x2, x3, x4) \
+	SBOX ## _1(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+	SBOX ## _2(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+	SBOX ## _1(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \
+	SBOX ## _2(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2);
+
+#define SP(SBOX, x0, x1, x2, x3, x4, i) \
+	get_key(i, 0, RK0); \
+	SBOX ## _1(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+	get_key(i, 2, RK2); \
+	SBOX ## _2(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+	get_key(i, 3, RK3); \
+	SBOX ## _1(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \
+	get_key(i, 1, RK1); \
+	SBOX ## _2(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \
+
+#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+	vpunpckldq		x1, x0, t0; \
+	vpunpckhdq		x1, x0, t2; \
+	vpunpckldq		x3, x2, t1; \
+	vpunpckhdq		x3, x2, x3; \
+	\
+	vpunpcklqdq		t1, t0, x0; \
+	vpunpckhqdq		t1, t0, x1; \
+	vpunpcklqdq		x3, t2, x2; \
+	vpunpckhqdq		x3, t2, x3;
+
+#define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \
+	vmovdqu (0*4*4)(in),	x0; \
+	vmovdqu (1*4*4)(in),	x1; \
+	vmovdqu (2*4*4)(in),	x2; \
+	vmovdqu (3*4*4)(in),	x3; \
+	\
+	transpose_4x4(x0, x1, x2, x3, t0, t1, t2)
+
+#define write_blocks(out, x0, x1, x2, x3, t0, t1, t2) \
+	transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+	\
+	vmovdqu x0,		(0*4*4)(out); \
+	vmovdqu x1,		(1*4*4)(out); \
+	vmovdqu x2,		(2*4*4)(out); \
+	vmovdqu x3,		(3*4*4)(out);
+
+#define xor_blocks(out, x0, x1, x2, x3, t0, t1, t2) \
+	transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+	\
+	vpxor (0*4*4)(out),	x0, x0;       \
+	vmovdqu x0,		(0*4*4)(out); \
+	vpxor (1*4*4)(out),	x1, x1;       \
+	vmovdqu x1,		(1*4*4)(out); \
+	vpxor (2*4*4)(out),	x2, x2;       \
+	vmovdqu x2,		(2*4*4)(out); \
+	vpxor (3*4*4)(out),	x3, x3;       \
+	vmovdqu x3,		(3*4*4)(out);
+
+.align 8
+.global __serpent_enc_blk_8way_avx
+.type   __serpent_enc_blk_8way_avx,@function;
+
+__serpent_enc_blk_8way_avx:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst
+	 *	%rdx: src
+	 *	%rcx: bool, if true: xor output
+	 */
+
+	vpcmpeqd RNOT, RNOT, RNOT;
+
+	leaq (4*4*4)(%rdx), %rax;
+	read_blocks(%rdx, RA1, RB1, RC1, RD1, RK0, RK1, RK2);
+	read_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2);
+
+						 K2(RA, RB, RC, RD, RE, 0);
+	S(S0, RA, RB, RC, RD, RE);		LK2(RC, RB, RD, RA, RE, 1);
+	S(S1, RC, RB, RD, RA, RE);		LK2(RE, RD, RA, RC, RB, 2);
+	S(S2, RE, RD, RA, RC, RB);		LK2(RB, RD, RE, RC, RA, 3);
+	S(S3, RB, RD, RE, RC, RA);		LK2(RC, RA, RD, RB, RE, 4);
+	S(S4, RC, RA, RD, RB, RE);		LK2(RA, RD, RB, RE, RC, 5);
+	S(S5, RA, RD, RB, RE, RC);		LK2(RC, RA, RD, RE, RB, 6);
+	S(S6, RC, RA, RD, RE, RB);		LK2(RD, RB, RA, RE, RC, 7);
+	S(S7, RD, RB, RA, RE, RC);		LK2(RC, RA, RE, RD, RB, 8);
+	S(S0, RC, RA, RE, RD, RB);		LK2(RE, RA, RD, RC, RB, 9);
+	S(S1, RE, RA, RD, RC, RB);		LK2(RB, RD, RC, RE, RA, 10);
+	S(S2, RB, RD, RC, RE, RA);		LK2(RA, RD, RB, RE, RC, 11);
+	S(S3, RA, RD, RB, RE, RC);		LK2(RE, RC, RD, RA, RB, 12);
+	S(S4, RE, RC, RD, RA, RB);		LK2(RC, RD, RA, RB, RE, 13);
+	S(S5, RC, RD, RA, RB, RE);		LK2(RE, RC, RD, RB, RA, 14);
+	S(S6, RE, RC, RD, RB, RA);		LK2(RD, RA, RC, RB, RE, 15);
+	S(S7, RD, RA, RC, RB, RE);		LK2(RE, RC, RB, RD, RA, 16);
+	S(S0, RE, RC, RB, RD, RA);		LK2(RB, RC, RD, RE, RA, 17);
+	S(S1, RB, RC, RD, RE, RA);		LK2(RA, RD, RE, RB, RC, 18);
+	S(S2, RA, RD, RE, RB, RC);		LK2(RC, RD, RA, RB, RE, 19);
+	S(S3, RC, RD, RA, RB, RE);		LK2(RB, RE, RD, RC, RA, 20);
+	S(S4, RB, RE, RD, RC, RA);		LK2(RE, RD, RC, RA, RB, 21);
+	S(S5, RE, RD, RC, RA, RB);		LK2(RB, RE, RD, RA, RC, 22);
+	S(S6, RB, RE, RD, RA, RC);		LK2(RD, RC, RE, RA, RB, 23);
+	S(S7, RD, RC, RE, RA, RB);		LK2(RB, RE, RA, RD, RC, 24);
+	S(S0, RB, RE, RA, RD, RC);		LK2(RA, RE, RD, RB, RC, 25);
+	S(S1, RA, RE, RD, RB, RC);		LK2(RC, RD, RB, RA, RE, 26);
+	S(S2, RC, RD, RB, RA, RE);		LK2(RE, RD, RC, RA, RB, 27);
+	S(S3, RE, RD, RC, RA, RB);		LK2(RA, RB, RD, RE, RC, 28);
+	S(S4, RA, RB, RD, RE, RC);		LK2(RB, RD, RE, RC, RA, 29);
+	S(S5, RB, RD, RE, RC, RA);		LK2(RA, RB, RD, RC, RE, 30);
+	S(S6, RA, RB, RD, RC, RE);		LK2(RD, RE, RB, RC, RA, 31);
+	S(S7, RD, RE, RB, RC, RA);		 K2(RA, RB, RC, RD, RE, 32);
+
+	leaq (4*4*4)(%rsi), %rax;
+
+	testb %cl, %cl;
+	jnz __enc_xor8;
+
+	write_blocks(%rsi, RA1, RB1, RC1, RD1, RK0, RK1, RK2);
+	write_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2);
+
+	ret;
+
+__enc_xor8:
+	xor_blocks(%rsi, RA1, RB1, RC1, RD1, RK0, RK1, RK2);
+	xor_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2);
+
+	ret;
+
+.align 8
+.global serpent_dec_blk_8way_avx
+.type   serpent_dec_blk_8way_avx,@function;
+
+serpent_dec_blk_8way_avx:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst
+	 *	%rdx: src
+	 */
+
+	vpcmpeqd RNOT, RNOT, RNOT;
+
+	leaq (4*4*4)(%rdx), %rax;
+	read_blocks(%rdx, RA1, RB1, RC1, RD1, RK0, RK1, RK2);
+	read_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2);
+
+						 K2(RA, RB, RC, RD, RE, 32);
+	SP(SI7, RA, RB, RC, RD, RE, 31);	KL2(RB, RD, RA, RE, RC, 31);
+	SP(SI6, RB, RD, RA, RE, RC, 30);	KL2(RA, RC, RE, RB, RD, 30);
+	SP(SI5, RA, RC, RE, RB, RD, 29);	KL2(RC, RD, RA, RE, RB, 29);
+	SP(SI4, RC, RD, RA, RE, RB, 28);	KL2(RC, RA, RB, RE, RD, 28);
+	SP(SI3, RC, RA, RB, RE, RD, 27);	KL2(RB, RC, RD, RE, RA, 27);
+	SP(SI2, RB, RC, RD, RE, RA, 26);	KL2(RC, RA, RE, RD, RB, 26);
+	SP(SI1, RC, RA, RE, RD, RB, 25);	KL2(RB, RA, RE, RD, RC, 25);
+	SP(SI0, RB, RA, RE, RD, RC, 24);	KL2(RE, RC, RA, RB, RD, 24);
+	SP(SI7, RE, RC, RA, RB, RD, 23);	KL2(RC, RB, RE, RD, RA, 23);
+	SP(SI6, RC, RB, RE, RD, RA, 22);	KL2(RE, RA, RD, RC, RB, 22);
+	SP(SI5, RE, RA, RD, RC, RB, 21);	KL2(RA, RB, RE, RD, RC, 21);
+	SP(SI4, RA, RB, RE, RD, RC, 20);	KL2(RA, RE, RC, RD, RB, 20);
+	SP(SI3, RA, RE, RC, RD, RB, 19);	KL2(RC, RA, RB, RD, RE, 19);
+	SP(SI2, RC, RA, RB, RD, RE, 18);	KL2(RA, RE, RD, RB, RC, 18);
+	SP(SI1, RA, RE, RD, RB, RC, 17);	KL2(RC, RE, RD, RB, RA, 17);
+	SP(SI0, RC, RE, RD, RB, RA, 16);	KL2(RD, RA, RE, RC, RB, 16);
+	SP(SI7, RD, RA, RE, RC, RB, 15);	KL2(RA, RC, RD, RB, RE, 15);
+	SP(SI6, RA, RC, RD, RB, RE, 14);	KL2(RD, RE, RB, RA, RC, 14);
+	SP(SI5, RD, RE, RB, RA, RC, 13);	KL2(RE, RC, RD, RB, RA, 13);
+	SP(SI4, RE, RC, RD, RB, RA, 12);	KL2(RE, RD, RA, RB, RC, 12);
+	SP(SI3, RE, RD, RA, RB, RC, 11);	KL2(RA, RE, RC, RB, RD, 11);
+	SP(SI2, RA, RE, RC, RB, RD, 10);	KL2(RE, RD, RB, RC, RA, 10);
+	SP(SI1, RE, RD, RB, RC, RA, 9);		KL2(RA, RD, RB, RC, RE, 9);
+	SP(SI0, RA, RD, RB, RC, RE, 8);		KL2(RB, RE, RD, RA, RC, 8);
+	SP(SI7, RB, RE, RD, RA, RC, 7);		KL2(RE, RA, RB, RC, RD, 7);
+	SP(SI6, RE, RA, RB, RC, RD, 6);		KL2(RB, RD, RC, RE, RA, 6);
+	SP(SI5, RB, RD, RC, RE, RA, 5);		KL2(RD, RA, RB, RC, RE, 5);
+	SP(SI4, RD, RA, RB, RC, RE, 4);		KL2(RD, RB, RE, RC, RA, 4);
+	SP(SI3, RD, RB, RE, RC, RA, 3);		KL2(RE, RD, RA, RC, RB, 3);
+	SP(SI2, RE, RD, RA, RC, RB, 2);		KL2(RD, RB, RC, RA, RE, 2);
+	SP(SI1, RD, RB, RC, RA, RE, 1);		KL2(RE, RB, RC, RA, RD, 1);
+	S(SI0, RE, RB, RC, RA, RD);		 K2(RC, RD, RB, RE, RA, 0);
+
+	leaq (4*4*4)(%rsi), %rax;
+	write_blocks(%rsi, RC1, RD1, RB1, RE1, RK0, RK1, RK2);
+	write_blocks(%rax, RC2, RD2, RB2, RE2, RK0, RK1, RK2);
+
+	ret;
diff --git a/arch/x86/crypto/serpent_avx_glue.c b/arch/x86/crypto/serpent_avx_glue.c
new file mode 100644
index 0000000..dd81bab
--- /dev/null
+++ b/arch/x86/crypto/serpent_avx_glue.c
@@ -0,0 +1,949 @@
+/*
+ * Glue Code for AVX assembler versions of Serpent Cipher
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * Glue code based on serpent_sse2_glue.c by:
+ *  Copyright (C) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/algapi.h>
+#include <crypto/serpent.h>
+#include <crypto/cryptd.h>
+#include <crypto/b128ops.h>
+#include <crypto/ctr.h>
+#include <crypto/lrw.h>
+#include <crypto/xts.h>
+#include <asm/i387.h>
+#include <asm/xcr.h>
+#include <asm/xsave.h>
+#include <asm/serpent-avx.h>
+#include <crypto/scatterwalk.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+
+struct async_serpent_ctx {
+	struct cryptd_ablkcipher *cryptd_tfm;
+};
+
+static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+{
+	if (fpu_enabled)
+		return true;
+
+	/* AVX is only used when chunk to be processed is large enough, so
+	 * do not enable FPU until it is necessary.
+	 */
+	if (nbytes < SERPENT_BLOCK_SIZE * SERPENT_PARALLEL_BLOCKS)
+		return false;
+
+	kernel_fpu_begin();
+	return true;
+}
+
+static inline void serpent_fpu_end(bool fpu_enabled)
+{
+	if (fpu_enabled)
+		kernel_fpu_end();
+}
+
+static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
+		     bool enc)
+{
+	bool fpu_enabled = false;
+	struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = SERPENT_BLOCK_SIZE;
+	unsigned int nbytes;
+	int err;
+
+	err = blkcipher_walk_virt(desc, walk);
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	while ((nbytes = walk->nbytes)) {
+		u8 *wsrc = walk->src.virt.addr;
+		u8 *wdst = walk->dst.virt.addr;
+
+		fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
+
+		/* Process multi-block batch */
+		if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
+			do {
+				if (enc)
+					serpent_enc_blk_xway(ctx, wdst, wsrc);
+				else
+					serpent_dec_blk_xway(ctx, wdst, wsrc);
+
+				wsrc += bsize * SERPENT_PARALLEL_BLOCKS;
+				wdst += bsize * SERPENT_PARALLEL_BLOCKS;
+				nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
+			} while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
+
+			if (nbytes < bsize)
+				goto done;
+		}
+
+		/* Handle leftovers */
+		do {
+			if (enc)
+				__serpent_encrypt(ctx, wdst, wsrc);
+			else
+				__serpent_decrypt(ctx, wdst, wsrc);
+
+			wsrc += bsize;
+			wdst += bsize;
+			nbytes -= bsize;
+		} while (nbytes >= bsize);
+
+done:
+		err = blkcipher_walk_done(desc, walk, nbytes);
+	}
+
+	serpent_fpu_end(fpu_enabled);
+	return err;
+}
+
+static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	return ecb_crypt(desc, &walk, true);
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	return ecb_crypt(desc, &walk, false);
+}
+
+static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
+				  struct blkcipher_walk *walk)
+{
+	struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = SERPENT_BLOCK_SIZE;
+	unsigned int nbytes = walk->nbytes;
+	u128 *src = (u128 *)walk->src.virt.addr;
+	u128 *dst = (u128 *)walk->dst.virt.addr;
+	u128 *iv = (u128 *)walk->iv;
+
+	do {
+		u128_xor(dst, src, iv);
+		__serpent_encrypt(ctx, (u8 *)dst, (u8 *)dst);
+		iv = dst;
+
+		src += 1;
+		dst += 1;
+		nbytes -= bsize;
+	} while (nbytes >= bsize);
+
+	u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv);
+	return nbytes;
+}
+
+static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt(desc, &walk);
+
+	while ((nbytes = walk.nbytes)) {
+		nbytes = __cbc_encrypt(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	return err;
+}
+
+static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
+				  struct blkcipher_walk *walk)
+{
+	struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = SERPENT_BLOCK_SIZE;
+	unsigned int nbytes = walk->nbytes;
+	u128 *src = (u128 *)walk->src.virt.addr;
+	u128 *dst = (u128 *)walk->dst.virt.addr;
+	u128 ivs[SERPENT_PARALLEL_BLOCKS - 1];
+	u128 last_iv;
+	int i;
+
+	/* Start of the last block. */
+	src += nbytes / bsize - 1;
+	dst += nbytes / bsize - 1;
+
+	last_iv = *src;
+
+	/* Process multi-block batch */
+	if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
+		do {
+			nbytes -= bsize * (SERPENT_PARALLEL_BLOCKS - 1);
+			src -= SERPENT_PARALLEL_BLOCKS - 1;
+			dst -= SERPENT_PARALLEL_BLOCKS - 1;
+
+			for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++)
+				ivs[i] = src[i];
+
+			serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src);
+
+			for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++)
+				u128_xor(dst + (i + 1), dst + (i + 1), ivs + i);
+
+			nbytes -= bsize;
+			if (nbytes < bsize)
+				goto done;
+
+			u128_xor(dst, dst, src - 1);
+			src -= 1;
+			dst -= 1;
+		} while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
+
+		if (nbytes < bsize)
+			goto done;
+	}
+
+	/* Handle leftovers */
+	for (;;) {
+		__serpent_decrypt(ctx, (u8 *)dst, (u8 *)src);
+
+		nbytes -= bsize;
+		if (nbytes < bsize)
+			break;
+
+		u128_xor(dst, dst, src - 1);
+		src -= 1;
+		dst -= 1;
+	}
+
+done:
+	u128_xor(dst, dst, (u128 *)walk->iv);
+	*(u128 *)walk->iv = last_iv;
+
+	return nbytes;
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	bool fpu_enabled = false;
+	struct blkcipher_walk walk;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt(desc, &walk);
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	while ((nbytes = walk.nbytes)) {
+		fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
+		nbytes = __cbc_decrypt(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	serpent_fpu_end(fpu_enabled);
+	return err;
+}
+
+static inline void u128_to_be128(be128 *dst, const u128 *src)
+{
+	dst->a = cpu_to_be64(src->a);
+	dst->b = cpu_to_be64(src->b);
+}
+
+static inline void be128_to_u128(u128 *dst, const be128 *src)
+{
+	dst->a = be64_to_cpu(src->a);
+	dst->b = be64_to_cpu(src->b);
+}
+
+static inline void u128_inc(u128 *i)
+{
+	i->b++;
+	if (!i->b)
+		i->a++;
+}
+
+static void ctr_crypt_final(struct blkcipher_desc *desc,
+			    struct blkcipher_walk *walk)
+{
+	struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	u8 *ctrblk = walk->iv;
+	u8 keystream[SERPENT_BLOCK_SIZE];
+	u8 *src = walk->src.virt.addr;
+	u8 *dst = walk->dst.virt.addr;
+	unsigned int nbytes = walk->nbytes;
+
+	__serpent_encrypt(ctx, keystream, ctrblk);
+	crypto_xor(keystream, src, nbytes);
+	memcpy(dst, keystream, nbytes);
+
+	crypto_inc(ctrblk, SERPENT_BLOCK_SIZE);
+}
+
+static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
+				struct blkcipher_walk *walk)
+{
+	struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = SERPENT_BLOCK_SIZE;
+	unsigned int nbytes = walk->nbytes;
+	u128 *src = (u128 *)walk->src.virt.addr;
+	u128 *dst = (u128 *)walk->dst.virt.addr;
+	u128 ctrblk;
+	be128 ctrblocks[SERPENT_PARALLEL_BLOCKS];
+	int i;
+
+	be128_to_u128(&ctrblk, (be128 *)walk->iv);
+
+	/* Process multi-block batch */
+	if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
+		do {
+			/* create ctrblks for parallel encrypt */
+			for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) {
+				if (dst != src)
+					dst[i] = src[i];
+
+				u128_to_be128(&ctrblocks[i], &ctrblk);
+				u128_inc(&ctrblk);
+			}
+
+			serpent_enc_blk_xway_xor(ctx, (u8 *)dst,
+						 (u8 *)ctrblocks);
+
+			src += SERPENT_PARALLEL_BLOCKS;
+			dst += SERPENT_PARALLEL_BLOCKS;
+			nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
+		} while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
+
+		if (nbytes < bsize)
+			goto done;
+	}
+
+	/* Handle leftovers */
+	do {
+		if (dst != src)
+			*dst = *src;
+
+		u128_to_be128(&ctrblocks[0], &ctrblk);
+		u128_inc(&ctrblk);
+
+		__serpent_encrypt(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks);
+		u128_xor(dst, dst, (u128 *)ctrblocks);
+
+		src += 1;
+		dst += 1;
+		nbytes -= bsize;
+	} while (nbytes >= bsize);
+
+done:
+	u128_to_be128((be128 *)walk->iv, &ctrblk);
+	return nbytes;
+}
+
+static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		     struct scatterlist *src, unsigned int nbytes)
+{
+	bool fpu_enabled = false;
+	struct blkcipher_walk walk;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt_block(desc, &walk, SERPENT_BLOCK_SIZE);
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	while ((nbytes = walk.nbytes) >= SERPENT_BLOCK_SIZE) {
+		fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
+		nbytes = __ctr_crypt(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	serpent_fpu_end(fpu_enabled);
+
+	if (walk.nbytes) {
+		ctr_crypt_final(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, 0);
+	}
+
+	return err;
+}
+
+struct crypt_priv {
+	struct serpent_ctx *ctx;
+	bool fpu_enabled;
+};
+
+static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+	const unsigned int bsize = SERPENT_BLOCK_SIZE;
+	struct crypt_priv *ctx = priv;
+	int i;
+
+	ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
+
+	if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
+		serpent_enc_blk_xway(ctx->ctx, srcdst, srcdst);
+		return;
+	}
+
+	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+		__serpent_encrypt(ctx->ctx, srcdst, srcdst);
+}
+
+static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+	const unsigned int bsize = SERPENT_BLOCK_SIZE;
+	struct crypt_priv *ctx = priv;
+	int i;
+
+	ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
+
+	if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
+		serpent_dec_blk_xway(ctx->ctx, srcdst, srcdst);
+		return;
+	}
+
+	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+		__serpent_decrypt(ctx->ctx, srcdst, srcdst);
+}
+
+struct serpent_lrw_ctx {
+	struct lrw_table_ctx lrw_table;
+	struct serpent_ctx serpent_ctx;
+};
+
+static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
+			      unsigned int keylen)
+{
+	struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+	int err;
+
+	err = __serpent_setkey(&ctx->serpent_ctx, key, keylen -
+							SERPENT_BLOCK_SIZE);
+	if (err)
+		return err;
+
+	return lrw_init_table(&ctx->lrw_table, key + keylen -
+						SERPENT_BLOCK_SIZE);
+}
+
+static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[SERPENT_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->serpent_ctx,
+		.fpu_enabled = false,
+	};
+	struct lrw_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.table_ctx = &ctx->lrw_table,
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = encrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = lrw_crypt(desc, dst, src, nbytes, &req);
+	serpent_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[SERPENT_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->serpent_ctx,
+		.fpu_enabled = false,
+	};
+	struct lrw_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.table_ctx = &ctx->lrw_table,
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = decrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = lrw_crypt(desc, dst, src, nbytes, &req);
+	serpent_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static void lrw_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	lrw_free_table(&ctx->lrw_table);
+}
+
+struct serpent_xts_ctx {
+	struct serpent_ctx tweak_ctx;
+	struct serpent_ctx crypt_ctx;
+};
+
+static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
+			      unsigned int keylen)
+{
+	struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+	u32 *flags = &tfm->crt_flags;
+	int err;
+
+	/* key consists of keys of equal size concatenated, therefore
+	 * the length must be even
+	 */
+	if (keylen % 2) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	/* first half of xts-key is for crypt */
+	err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2);
+	if (err)
+		return err;
+
+	/* second half of xts-key is for tweak */
+	return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2);
+}
+
+static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[SERPENT_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->crypt_ctx,
+		.fpu_enabled = false,
+	};
+	struct xts_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.tweak_ctx = &ctx->tweak_ctx,
+		.tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = encrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = xts_crypt(desc, dst, src, nbytes, &req);
+	serpent_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[SERPENT_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->crypt_ctx,
+		.fpu_enabled = false,
+	};
+	struct xts_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.tweak_ctx = &ctx->tweak_ctx,
+		.tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = decrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = xts_crypt(desc, dst, src, nbytes, &req);
+	serpent_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
+			unsigned int key_len)
+{
+	struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+	struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base;
+	int err;
+
+	crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm)
+				    & CRYPTO_TFM_REQ_MASK);
+	err = crypto_ablkcipher_setkey(child, key, key_len);
+	crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child)
+				    & CRYPTO_TFM_RES_MASK);
+	return err;
+}
+
+static int __ablk_encrypt(struct ablkcipher_request *req)
+{
+	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+	struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+	struct blkcipher_desc desc;
+
+	desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
+	desc.info = req->info;
+	desc.flags = 0;
+
+	return crypto_blkcipher_crt(desc.tfm)->encrypt(
+		&desc, req->dst, req->src, req->nbytes);
+}
+
+static int ablk_encrypt(struct ablkcipher_request *req)
+{
+	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+	struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+	if (!irq_fpu_usable()) {
+		struct ablkcipher_request *cryptd_req =
+			ablkcipher_request_ctx(req);
+
+		memcpy(cryptd_req, req, sizeof(*req));
+		ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
+
+		return crypto_ablkcipher_encrypt(cryptd_req);
+	} else {
+		return __ablk_encrypt(req);
+	}
+}
+
+static int ablk_decrypt(struct ablkcipher_request *req)
+{
+	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+	struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+	if (!irq_fpu_usable()) {
+		struct ablkcipher_request *cryptd_req =
+			ablkcipher_request_ctx(req);
+
+		memcpy(cryptd_req, req, sizeof(*req));
+		ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
+
+		return crypto_ablkcipher_decrypt(cryptd_req);
+	} else {
+		struct blkcipher_desc desc;
+
+		desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
+		desc.info = req->info;
+		desc.flags = 0;
+
+		return crypto_blkcipher_crt(desc.tfm)->decrypt(
+			&desc, req->dst, req->src, req->nbytes);
+	}
+}
+
+static void ablk_exit(struct crypto_tfm *tfm)
+{
+	struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	cryptd_free_ablkcipher(ctx->cryptd_tfm);
+}
+
+static int ablk_init(struct crypto_tfm *tfm)
+{
+	struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct cryptd_ablkcipher *cryptd_tfm;
+	char drv_name[CRYPTO_MAX_ALG_NAME];
+
+	snprintf(drv_name, sizeof(drv_name), "__driver-%s",
+					crypto_tfm_alg_driver_name(tfm));
+
+	cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0);
+	if (IS_ERR(cryptd_tfm))
+		return PTR_ERR(cryptd_tfm);
+
+	ctx->cryptd_tfm = cryptd_tfm;
+	tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
+		crypto_ablkcipher_reqsize(&cryptd_tfm->base);
+
+	return 0;
+}
+
+static struct crypto_alg serpent_algs[10] = { {
+	.cra_name		= "__ecb-serpent-avx",
+	.cra_driver_name	= "__driver-ecb-serpent-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= SERPENT_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct serpent_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(serpent_algs[0].cra_list),
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= SERPENT_MIN_KEY_SIZE,
+			.max_keysize	= SERPENT_MAX_KEY_SIZE,
+			.setkey		= serpent_setkey,
+			.encrypt	= ecb_encrypt,
+			.decrypt	= ecb_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__cbc-serpent-avx",
+	.cra_driver_name	= "__driver-cbc-serpent-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= SERPENT_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct serpent_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(serpent_algs[1].cra_list),
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= SERPENT_MIN_KEY_SIZE,
+			.max_keysize	= SERPENT_MAX_KEY_SIZE,
+			.setkey		= serpent_setkey,
+			.encrypt	= cbc_encrypt,
+			.decrypt	= cbc_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__ctr-serpent-avx",
+	.cra_driver_name	= "__driver-ctr-serpent-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct serpent_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(serpent_algs[2].cra_list),
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= SERPENT_MIN_KEY_SIZE,
+			.max_keysize	= SERPENT_MAX_KEY_SIZE,
+			.ivsize		= SERPENT_BLOCK_SIZE,
+			.setkey		= serpent_setkey,
+			.encrypt	= ctr_crypt,
+			.decrypt	= ctr_crypt,
+		},
+	},
+}, {
+	.cra_name		= "__lrw-serpent-avx",
+	.cra_driver_name	= "__driver-lrw-serpent-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= SERPENT_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct serpent_lrw_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(serpent_algs[3].cra_list),
+	.cra_exit		= lrw_exit_tfm,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= SERPENT_MIN_KEY_SIZE +
+					  SERPENT_BLOCK_SIZE,
+			.max_keysize	= SERPENT_MAX_KEY_SIZE +
+					  SERPENT_BLOCK_SIZE,
+			.ivsize		= SERPENT_BLOCK_SIZE,
+			.setkey		= lrw_serpent_setkey,
+			.encrypt	= lrw_encrypt,
+			.decrypt	= lrw_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__xts-serpent-avx",
+	.cra_driver_name	= "__driver-xts-serpent-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= SERPENT_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct serpent_xts_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(serpent_algs[4].cra_list),
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= SERPENT_MIN_KEY_SIZE * 2,
+			.max_keysize	= SERPENT_MAX_KEY_SIZE * 2,
+			.ivsize		= SERPENT_BLOCK_SIZE,
+			.setkey		= xts_serpent_setkey,
+			.encrypt	= xts_encrypt,
+			.decrypt	= xts_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "ecb(serpent)",
+	.cra_driver_name	= "ecb-serpent-avx",
+	.cra_priority		= 500,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= SERPENT_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_serpent_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(serpent_algs[5].cra_list),
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= SERPENT_MIN_KEY_SIZE,
+			.max_keysize	= SERPENT_MAX_KEY_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "cbc(serpent)",
+	.cra_driver_name	= "cbc-serpent-avx",
+	.cra_priority		= 500,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= SERPENT_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_serpent_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(serpent_algs[6].cra_list),
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= SERPENT_MIN_KEY_SIZE,
+			.max_keysize	= SERPENT_MAX_KEY_SIZE,
+			.ivsize		= SERPENT_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= __ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "ctr(serpent)",
+	.cra_driver_name	= "ctr-serpent-avx",
+	.cra_priority		= 500,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct async_serpent_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(serpent_algs[7].cra_list),
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= SERPENT_MIN_KEY_SIZE,
+			.max_keysize	= SERPENT_MAX_KEY_SIZE,
+			.ivsize		= SERPENT_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_encrypt,
+			.geniv		= "chainiv",
+		},
+	},
+}, {
+	.cra_name		= "lrw(serpent)",
+	.cra_driver_name	= "lrw-serpent-avx",
+	.cra_priority		= 500,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= SERPENT_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_serpent_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(serpent_algs[8].cra_list),
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= SERPENT_MIN_KEY_SIZE +
+					  SERPENT_BLOCK_SIZE,
+			.max_keysize	= SERPENT_MAX_KEY_SIZE +
+					  SERPENT_BLOCK_SIZE,
+			.ivsize		= SERPENT_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "xts(serpent)",
+	.cra_driver_name	= "xts-serpent-avx",
+	.cra_priority		= 500,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= SERPENT_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_serpent_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(serpent_algs[9].cra_list),
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= SERPENT_MIN_KEY_SIZE * 2,
+			.max_keysize	= SERPENT_MAX_KEY_SIZE * 2,
+			.ivsize		= SERPENT_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+} };
+
+static int __init serpent_init(void)
+{
+	u64 xcr0;
+
+	if (!cpu_has_avx || !cpu_has_osxsave) {
+		printk(KERN_INFO "AVX instructions are not detected.\n");
+		return -ENODEV;
+	}
+
+	xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
+	if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
+		printk(KERN_INFO "AVX detected but unusable.\n");
+		return -ENODEV;
+	}
+
+	return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
+}
+
+static void __exit serpent_exit(void)
+{
+	crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
+}
+
+module_init(serpent_init);
+module_exit(serpent_exit);
+
+MODULE_DESCRIPTION("Serpent Cipher Algorithm, AVX optimized");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("serpent");
diff --git a/arch/x86/crypto/serpent_sse2_glue.c b/arch/x86/crypto/serpent_sse2_glue.c
index 4b21be8..deecd25 100644
--- a/arch/x86/crypto/serpent_sse2_glue.c
+++ b/arch/x86/crypto/serpent_sse2_glue.c
@@ -42,7 +42,7 @@
 #include <crypto/lrw.h>
 #include <crypto/xts.h>
 #include <asm/i387.h>
-#include <asm/serpent.h>
+#include <asm/serpent-sse2.h>
 #include <crypto/scatterwalk.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
diff --git a/arch/x86/crypto/sha1_ssse3_asm.S b/arch/x86/crypto/sha1_ssse3_asm.S
index b2c2f57..49d6987 100644
--- a/arch/x86/crypto/sha1_ssse3_asm.S
+++ b/arch/x86/crypto/sha1_ssse3_asm.S
@@ -468,7 +468,7 @@ W_PRECALC_SSSE3
  */
 SHA1_VECTOR_ASM     sha1_transform_ssse3
 
-#ifdef SHA1_ENABLE_AVX_SUPPORT
+#ifdef CONFIG_AS_AVX
 
 .macro W_PRECALC_AVX
 
diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c
index f916499..4a11a9d 100644
--- a/arch/x86/crypto/sha1_ssse3_glue.c
+++ b/arch/x86/crypto/sha1_ssse3_glue.c
@@ -35,7 +35,7 @@
 
 asmlinkage void sha1_transform_ssse3(u32 *digest, const char *data,
 				     unsigned int rounds);
-#ifdef SHA1_ENABLE_AVX_SUPPORT
+#ifdef CONFIG_AS_AVX
 asmlinkage void sha1_transform_avx(u32 *digest, const char *data,
 				   unsigned int rounds);
 #endif
@@ -184,7 +184,7 @@ static struct shash_alg alg = {
 	}
 };
 
-#ifdef SHA1_ENABLE_AVX_SUPPORT
+#ifdef CONFIG_AS_AVX
 static bool __init avx_usable(void)
 {
 	u64 xcr0;
@@ -209,7 +209,7 @@ static int __init sha1_ssse3_mod_init(void)
 	if (cpu_has_ssse3)
 		sha1_transform_asm = sha1_transform_ssse3;
 
-#ifdef SHA1_ENABLE_AVX_SUPPORT
+#ifdef CONFIG_AS_AVX
 	/* allow AVX to override SSSE3, it's a little faster */
 	if (avx_usable())
 		sha1_transform_asm = sha1_transform_avx;
diff --git a/arch/x86/crypto/twofish-avx-x86_64-asm_64.S b/arch/x86/crypto/twofish-avx-x86_64-asm_64.S
new file mode 100644
index 0000000..fc31b89
--- /dev/null
+++ b/arch/x86/crypto/twofish-avx-x86_64-asm_64.S
@@ -0,0 +1,301 @@
+/*
+ * Twofish Cipher 8-way parallel algorithm (AVX/x86_64)
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.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
+ *
+ */
+
+.file "twofish-avx-x86_64-asm_64.S"
+.text
+
+/* structure of crypto context */
+#define s0	0
+#define s1	1024
+#define s2	2048
+#define s3	3072
+#define w	4096
+#define k	4128
+
+/**********************************************************************
+  8-way AVX twofish
+ **********************************************************************/
+#define CTX %rdi
+
+#define RA1 %xmm0
+#define RB1 %xmm1
+#define RC1 %xmm2
+#define RD1 %xmm3
+
+#define RA2 %xmm4
+#define RB2 %xmm5
+#define RC2 %xmm6
+#define RD2 %xmm7
+
+#define RX %xmm8
+#define RY %xmm9
+
+#define RK1 %xmm10
+#define RK2 %xmm11
+
+#define RID1  %rax
+#define RID1b %al
+#define RID2  %rbx
+#define RID2b %bl
+
+#define RGI1   %rdx
+#define RGI1bl %dl
+#define RGI1bh %dh
+#define RGI2   %rcx
+#define RGI2bl %cl
+#define RGI2bh %ch
+
+#define RGS1  %r8
+#define RGS1d %r8d
+#define RGS2  %r9
+#define RGS2d %r9d
+#define RGS3  %r10
+#define RGS3d %r10d
+
+
+#define lookup_32bit(t0, t1, t2, t3, src, dst) \
+	movb		src ## bl,        RID1b;     \
+	movb		src ## bh,        RID2b;     \
+	movl		t0(CTX, RID1, 4), dst ## d;  \
+	xorl		t1(CTX, RID2, 4), dst ## d;  \
+	shrq $16,	src;                         \
+	movb		src ## bl,        RID1b;     \
+	movb		src ## bh,        RID2b;     \
+	xorl		t2(CTX, RID1, 4), dst ## d;  \
+	xorl		t3(CTX, RID2, 4), dst ## d;
+
+#define G(a, x, t0, t1, t2, t3) \
+	vmovq		a,    RGI1;               \
+	vpsrldq $8,	a,    x;                  \
+	vmovq		x,    RGI2;               \
+	\
+	lookup_32bit(t0, t1, t2, t3, RGI1, RGS1); \
+	shrq $16,	RGI1;                     \
+	lookup_32bit(t0, t1, t2, t3, RGI1, RGS2); \
+	shlq $32,	RGS2;                     \
+	orq		RGS1, RGS2;               \
+	\
+	lookup_32bit(t0, t1, t2, t3, RGI2, RGS1); \
+	shrq $16,	RGI2;                     \
+	lookup_32bit(t0, t1, t2, t3, RGI2, RGS3); \
+	shlq $32,	RGS3;                     \
+	orq		RGS1, RGS3;               \
+	\
+	vmovq		RGS2, x;                  \
+	vpinsrq $1,	RGS3, x, x;
+
+#define encround(a, b, c, d, x, y) \
+	G(a, x, s0, s1, s2, s3);           \
+	G(b, y, s1, s2, s3, s0);           \
+	vpaddd			x, y,   x; \
+	vpaddd			y, x,   y; \
+	vpaddd			x, RK1, x; \
+	vpaddd			y, RK2, y; \
+	vpxor			x, c,   c; \
+	vpsrld $1,		c, x;      \
+	vpslld $(32 - 1),	c, c;      \
+	vpor			c, x,   c; \
+	vpslld $1,		d, x;      \
+	vpsrld $(32 - 1),	d, d;      \
+	vpor			d, x,   d; \
+	vpxor			d, y,   d;
+
+#define decround(a, b, c, d, x, y) \
+	G(a, x, s0, s1, s2, s3);           \
+	G(b, y, s1, s2, s3, s0);           \
+	vpaddd			x, y,   x; \
+	vpaddd			y, x,   y; \
+	vpaddd			y, RK2, y; \
+	vpxor			d, y,   d; \
+	vpsrld $1,		d, y;      \
+	vpslld $(32 - 1),	d, d;      \
+	vpor			d, y,   d; \
+	vpslld $1,		c, y;      \
+	vpsrld $(32 - 1),	c, c;      \
+	vpor			c, y,   c; \
+	vpaddd			x, RK1, x; \
+	vpxor			x, c,   c;
+
+#define encrypt_round(n, a, b, c, d) \
+	vbroadcastss (k+4*(2*(n)))(CTX),   RK1;           \
+	vbroadcastss (k+4*(2*(n)+1))(CTX), RK2;           \
+	encround(a ## 1, b ## 1, c ## 1, d ## 1, RX, RY); \
+	encround(a ## 2, b ## 2, c ## 2, d ## 2, RX, RY);
+
+#define decrypt_round(n, a, b, c, d) \
+	vbroadcastss (k+4*(2*(n)))(CTX),   RK1;           \
+	vbroadcastss (k+4*(2*(n)+1))(CTX), RK2;           \
+	decround(a ## 1, b ## 1, c ## 1, d ## 1, RX, RY); \
+	decround(a ## 2, b ## 2, c ## 2, d ## 2, RX, RY);
+
+#define encrypt_cycle(n) \
+	encrypt_round((2*n), RA, RB, RC, RD);       \
+	encrypt_round(((2*n) + 1), RC, RD, RA, RB);
+
+#define decrypt_cycle(n) \
+	decrypt_round(((2*n) + 1), RC, RD, RA, RB); \
+	decrypt_round((2*n), RA, RB, RC, RD);
+
+
+#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+	vpunpckldq		x1, x0, t0; \
+	vpunpckhdq		x1, x0, t2; \
+	vpunpckldq		x3, x2, t1; \
+	vpunpckhdq		x3, x2, x3; \
+	\
+	vpunpcklqdq		t1, t0, x0; \
+	vpunpckhqdq		t1, t0, x1; \
+	vpunpcklqdq		x3, t2, x2; \
+	vpunpckhqdq		x3, t2, x3;
+
+#define inpack_blocks(in, x0, x1, x2, x3, wkey, t0, t1, t2) \
+	vpxor (0*4*4)(in),	wkey, x0; \
+	vpxor (1*4*4)(in),	wkey, x1; \
+	vpxor (2*4*4)(in),	wkey, x2; \
+	vpxor (3*4*4)(in),	wkey, x3; \
+	\
+	transpose_4x4(x0, x1, x2, x3, t0, t1, t2)
+
+#define outunpack_blocks(out, x0, x1, x2, x3, wkey, t0, t1, t2) \
+	transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+	\
+	vpxor		x0, wkey, x0;     \
+	vmovdqu 	x0, (0*4*4)(out); \
+	vpxor		x1, wkey, x1;     \
+	vmovdqu		x1, (1*4*4)(out); \
+	vpxor		x2, wkey, x2;     \
+	vmovdqu		x2, (2*4*4)(out); \
+	vpxor		x3, wkey, x3;     \
+	vmovdqu		x3, (3*4*4)(out);
+
+#define outunpack_xor_blocks(out, x0, x1, x2, x3, wkey, t0, t1, t2) \
+	transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+	\
+	vpxor		x0, wkey, x0;         \
+	vpxor		(0*4*4)(out), x0, x0; \
+	vmovdqu 	x0, (0*4*4)(out);     \
+	vpxor		x1, wkey, x1;         \
+	vpxor		(1*4*4)(out), x1, x1; \
+	vmovdqu	        x1, (1*4*4)(out);     \
+	vpxor		x2, wkey, x2;         \
+	vpxor           (2*4*4)(out), x2, x2; \
+	vmovdqu		x2, (2*4*4)(out);     \
+	vpxor		x3, wkey, x3;         \
+	vpxor           (3*4*4)(out), x3, x3; \
+	vmovdqu		x3, (3*4*4)(out);
+
+.align 8
+.global __twofish_enc_blk_8way
+.type   __twofish_enc_blk_8way,@function;
+
+__twofish_enc_blk_8way:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst
+	 *	%rdx: src
+	 *	%rcx: bool, if true: xor output
+	 */
+
+	pushq %rbx;
+	pushq %rcx;
+
+	vmovdqu w(CTX), RK1;
+
+	leaq (4*4*4)(%rdx), %rax;
+	inpack_blocks(%rdx, RA1, RB1, RC1, RD1, RK1, RX, RY, RK2);
+	inpack_blocks(%rax, RA2, RB2, RC2, RD2, RK1, RX, RY, RK2);
+
+	xorq RID1, RID1;
+	xorq RID2, RID2;
+
+	encrypt_cycle(0);
+	encrypt_cycle(1);
+	encrypt_cycle(2);
+	encrypt_cycle(3);
+	encrypt_cycle(4);
+	encrypt_cycle(5);
+	encrypt_cycle(6);
+	encrypt_cycle(7);
+
+	vmovdqu (w+4*4)(CTX), RK1;
+
+	popq %rcx;
+	popq %rbx;
+
+	leaq (4*4*4)(%rsi), %rax;
+	leaq (4*4*4)(%rax), %rdx;
+
+	testb %cl, %cl;
+	jnz __enc_xor8;
+
+	outunpack_blocks(%rsi, RC1, RD1, RA1, RB1, RK1, RX, RY, RK2);
+	outunpack_blocks(%rax, RC2, RD2, RA2, RB2, RK1, RX, RY, RK2);
+
+	ret;
+
+__enc_xor8:
+	outunpack_xor_blocks(%rsi, RC1, RD1, RA1, RB1, RK1, RX, RY, RK2);
+	outunpack_xor_blocks(%rax, RC2, RD2, RA2, RB2, RK1, RX, RY, RK2);
+
+	ret;
+
+.align 8
+.global twofish_dec_blk_8way
+.type   twofish_dec_blk_8way,@function;
+
+twofish_dec_blk_8way:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst
+	 *	%rdx: src
+	 */
+
+	pushq %rbx;
+
+	vmovdqu (w+4*4)(CTX), RK1;
+
+	leaq (4*4*4)(%rdx), %rax;
+	inpack_blocks(%rdx, RC1, RD1, RA1, RB1, RK1, RX, RY, RK2);
+	inpack_blocks(%rax, RC2, RD2, RA2, RB2, RK1, RX, RY, RK2);
+
+	xorq RID1, RID1;
+	xorq RID2, RID2;
+
+	decrypt_cycle(7);
+	decrypt_cycle(6);
+	decrypt_cycle(5);
+	decrypt_cycle(4);
+	decrypt_cycle(3);
+	decrypt_cycle(2);
+	decrypt_cycle(1);
+	decrypt_cycle(0);
+
+	vmovdqu (w)(CTX), RK1;
+
+	popq %rbx;
+
+	leaq (4*4*4)(%rsi), %rax;
+	outunpack_blocks(%rsi, RA1, RB1, RC1, RD1, RK1, RX, RY, RK2);
+	outunpack_blocks(%rax, RA2, RB2, RC2, RD2, RK1, RX, RY, RK2);
+
+	ret;
diff --git a/arch/x86/crypto/twofish_avx_glue.c b/arch/x86/crypto/twofish_avx_glue.c
new file mode 100644
index 0000000..599f19e
--- /dev/null
+++ b/arch/x86/crypto/twofish_avx_glue.c
@@ -0,0 +1,1086 @@
+/*
+ * Glue Code for AVX assembler version of Twofish Cipher
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * Glue code based on serpent_sse2_glue.c by:
+ *  Copyright (C) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/algapi.h>
+#include <crypto/twofish.h>
+#include <crypto/cryptd.h>
+#include <crypto/b128ops.h>
+#include <crypto/ctr.h>
+#include <crypto/lrw.h>
+#include <crypto/xts.h>
+#include <asm/i387.h>
+#include <asm/xcr.h>
+#include <asm/xsave.h>
+#include <crypto/scatterwalk.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+
+
+#define TWOFISH_PARALLEL_BLOCKS 8
+
+/* regular block cipher functions from twofish_x86_64 module */
+asmlinkage void twofish_enc_blk(struct twofish_ctx *ctx, u8 *dst,
+				const u8 *src);
+asmlinkage void twofish_dec_blk(struct twofish_ctx *ctx, u8 *dst,
+				const u8 *src);
+
+/* 3-way parallel cipher functions from twofish_x86_64-3way module */
+asmlinkage void __twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
+				       const u8 *src, bool xor);
+asmlinkage void twofish_dec_blk_3way(struct twofish_ctx *ctx, u8 *dst,
+				     const u8 *src);
+
+static inline void twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
+					const u8 *src)
+{
+	__twofish_enc_blk_3way(ctx, dst, src, false);
+}
+
+static inline void twofish_enc_blk_3way_xor(struct twofish_ctx *ctx, u8 *dst,
+					    const u8 *src)
+{
+	__twofish_enc_blk_3way(ctx, dst, src, true);
+}
+
+/* 8-way parallel cipher functions */
+asmlinkage void __twofish_enc_blk_8way(struct twofish_ctx *ctx, u8 *dst,
+				       const u8 *src, bool xor);
+asmlinkage void twofish_dec_blk_8way(struct twofish_ctx *ctx, u8 *dst,
+				     const u8 *src);
+
+static inline void twofish_enc_blk_xway(struct twofish_ctx *ctx, u8 *dst,
+					const u8 *src)
+{
+	__twofish_enc_blk_8way(ctx, dst, src, false);
+}
+
+static inline void twofish_enc_blk_xway_xor(struct twofish_ctx *ctx, u8 *dst,
+					    const u8 *src)
+{
+	__twofish_enc_blk_8way(ctx, dst, src, true);
+}
+
+static inline void twofish_dec_blk_xway(struct twofish_ctx *ctx, u8 *dst,
+					const u8 *src)
+{
+	twofish_dec_blk_8way(ctx, dst, src);
+}
+
+
+
+struct async_twofish_ctx {
+	struct cryptd_ablkcipher *cryptd_tfm;
+};
+
+static inline bool twofish_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+{
+	if (fpu_enabled)
+		return true;
+
+	/* AVX is only used when chunk to be processed is large enough, so
+	 * do not enable FPU until it is necessary.
+	 */
+	if (nbytes < TF_BLOCK_SIZE * TWOFISH_PARALLEL_BLOCKS)
+		return false;
+
+	kernel_fpu_begin();
+	return true;
+}
+
+static inline void twofish_fpu_end(bool fpu_enabled)
+{
+	if (fpu_enabled)
+		kernel_fpu_end();
+}
+
+static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
+		     bool enc)
+{
+	bool fpu_enabled = false;
+	struct twofish_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = TF_BLOCK_SIZE;
+	unsigned int nbytes;
+	int err;
+
+	err = blkcipher_walk_virt(desc, walk);
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	while ((nbytes = walk->nbytes)) {
+		u8 *wsrc = walk->src.virt.addr;
+		u8 *wdst = walk->dst.virt.addr;
+
+		fpu_enabled = twofish_fpu_begin(fpu_enabled, nbytes);
+
+		/* Process multi-block batch */
+		if (nbytes >= bsize * TWOFISH_PARALLEL_BLOCKS) {
+			do {
+				if (enc)
+					twofish_enc_blk_xway(ctx, wdst, wsrc);
+				else
+					twofish_dec_blk_xway(ctx, wdst, wsrc);
+
+				wsrc += bsize * TWOFISH_PARALLEL_BLOCKS;
+				wdst += bsize * TWOFISH_PARALLEL_BLOCKS;
+				nbytes -= bsize * TWOFISH_PARALLEL_BLOCKS;
+			} while (nbytes >= bsize * TWOFISH_PARALLEL_BLOCKS);
+
+			if (nbytes < bsize)
+				goto done;
+		}
+
+		/* Process three block batch */
+		if (nbytes >= bsize * 3) {
+			do {
+				if (enc)
+					twofish_enc_blk_3way(ctx, wdst, wsrc);
+				else
+					twofish_dec_blk_3way(ctx, wdst, wsrc);
+
+				wsrc += bsize * 3;
+				wdst += bsize * 3;
+				nbytes -= bsize * 3;
+			} while (nbytes >= bsize * 3);
+
+			if (nbytes < bsize)
+				goto done;
+		}
+
+		/* Handle leftovers */
+		do {
+			if (enc)
+				twofish_enc_blk(ctx, wdst, wsrc);
+			else
+				twofish_dec_blk(ctx, wdst, wsrc);
+
+			wsrc += bsize;
+			wdst += bsize;
+			nbytes -= bsize;
+		} while (nbytes >= bsize);
+
+done:
+		err = blkcipher_walk_done(desc, walk, nbytes);
+	}
+
+	twofish_fpu_end(fpu_enabled);
+	return err;
+}
+
+static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	return ecb_crypt(desc, &walk, true);
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	return ecb_crypt(desc, &walk, false);
+}
+
+static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
+				  struct blkcipher_walk *walk)
+{
+	struct twofish_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = TF_BLOCK_SIZE;
+	unsigned int nbytes = walk->nbytes;
+	u128 *src = (u128 *)walk->src.virt.addr;
+	u128 *dst = (u128 *)walk->dst.virt.addr;
+	u128 *iv = (u128 *)walk->iv;
+
+	do {
+		u128_xor(dst, src, iv);
+		twofish_enc_blk(ctx, (u8 *)dst, (u8 *)dst);
+		iv = dst;
+
+		src += 1;
+		dst += 1;
+		nbytes -= bsize;
+	} while (nbytes >= bsize);
+
+	u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv);
+	return nbytes;
+}
+
+static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt(desc, &walk);
+
+	while ((nbytes = walk.nbytes)) {
+		nbytes = __cbc_encrypt(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	return err;
+}
+
+static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
+				  struct blkcipher_walk *walk)
+{
+	struct twofish_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = TF_BLOCK_SIZE;
+	unsigned int nbytes = walk->nbytes;
+	u128 *src = (u128 *)walk->src.virt.addr;
+	u128 *dst = (u128 *)walk->dst.virt.addr;
+	u128 ivs[TWOFISH_PARALLEL_BLOCKS - 1];
+	u128 last_iv;
+	int i;
+
+	/* Start of the last block. */
+	src += nbytes / bsize - 1;
+	dst += nbytes / bsize - 1;
+
+	last_iv = *src;
+
+	/* Process multi-block batch */
+	if (nbytes >= bsize * TWOFISH_PARALLEL_BLOCKS) {
+		do {
+			nbytes -= bsize * (TWOFISH_PARALLEL_BLOCKS - 1);
+			src -= TWOFISH_PARALLEL_BLOCKS - 1;
+			dst -= TWOFISH_PARALLEL_BLOCKS - 1;
+
+			for (i = 0; i < TWOFISH_PARALLEL_BLOCKS - 1; i++)
+				ivs[i] = src[i];
+
+			twofish_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src);
+
+			for (i = 0; i < TWOFISH_PARALLEL_BLOCKS - 1; i++)
+				u128_xor(dst + (i + 1), dst + (i + 1), ivs + i);
+
+			nbytes -= bsize;
+			if (nbytes < bsize)
+				goto done;
+
+			u128_xor(dst, dst, src - 1);
+			src -= 1;
+			dst -= 1;
+		} while (nbytes >= bsize * TWOFISH_PARALLEL_BLOCKS);
+
+		if (nbytes < bsize)
+			goto done;
+	}
+
+	/* Process three block batch */
+	if (nbytes >= bsize * 3) {
+		do {
+			nbytes -= bsize * (3 - 1);
+			src -= 3 - 1;
+			dst -= 3 - 1;
+
+			ivs[0] = src[0];
+			ivs[1] = src[1];
+
+			twofish_dec_blk_3way(ctx, (u8 *)dst, (u8 *)src);
+
+			u128_xor(dst + 1, dst + 1, ivs + 0);
+			u128_xor(dst + 2, dst + 2, ivs + 1);
+
+			nbytes -= bsize;
+			if (nbytes < bsize)
+				goto done;
+
+			u128_xor(dst, dst, src - 1);
+			src -= 1;
+			dst -= 1;
+		} while (nbytes >= bsize * 3);
+
+		if (nbytes < bsize)
+			goto done;
+	}
+
+	/* Handle leftovers */
+	for (;;) {
+		twofish_dec_blk(ctx, (u8 *)dst, (u8 *)src);
+
+		nbytes -= bsize;
+		if (nbytes < bsize)
+			break;
+
+		u128_xor(dst, dst, src - 1);
+		src -= 1;
+		dst -= 1;
+	}
+
+done:
+	u128_xor(dst, dst, (u128 *)walk->iv);
+	*(u128 *)walk->iv = last_iv;
+
+	return nbytes;
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	bool fpu_enabled = false;
+	struct blkcipher_walk walk;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt(desc, &walk);
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	while ((nbytes = walk.nbytes)) {
+		fpu_enabled = twofish_fpu_begin(fpu_enabled, nbytes);
+		nbytes = __cbc_decrypt(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	twofish_fpu_end(fpu_enabled);
+	return err;
+}
+
+static inline void u128_to_be128(be128 *dst, const u128 *src)
+{
+	dst->a = cpu_to_be64(src->a);
+	dst->b = cpu_to_be64(src->b);
+}
+
+static inline void be128_to_u128(u128 *dst, const be128 *src)
+{
+	dst->a = be64_to_cpu(src->a);
+	dst->b = be64_to_cpu(src->b);
+}
+
+static inline void u128_inc(u128 *i)
+{
+	i->b++;
+	if (!i->b)
+		i->a++;
+}
+
+static void ctr_crypt_final(struct blkcipher_desc *desc,
+			    struct blkcipher_walk *walk)
+{
+	struct twofish_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	u8 *ctrblk = walk->iv;
+	u8 keystream[TF_BLOCK_SIZE];
+	u8 *src = walk->src.virt.addr;
+	u8 *dst = walk->dst.virt.addr;
+	unsigned int nbytes = walk->nbytes;
+
+	twofish_enc_blk(ctx, keystream, ctrblk);
+	crypto_xor(keystream, src, nbytes);
+	memcpy(dst, keystream, nbytes);
+
+	crypto_inc(ctrblk, TF_BLOCK_SIZE);
+}
+
+static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
+				struct blkcipher_walk *walk)
+{
+	struct twofish_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = TF_BLOCK_SIZE;
+	unsigned int nbytes = walk->nbytes;
+	u128 *src = (u128 *)walk->src.virt.addr;
+	u128 *dst = (u128 *)walk->dst.virt.addr;
+	u128 ctrblk;
+	be128 ctrblocks[TWOFISH_PARALLEL_BLOCKS];
+	int i;
+
+	be128_to_u128(&ctrblk, (be128 *)walk->iv);
+
+	/* Process multi-block batch */
+	if (nbytes >= bsize * TWOFISH_PARALLEL_BLOCKS) {
+		do {
+			/* create ctrblks for parallel encrypt */
+			for (i = 0; i < TWOFISH_PARALLEL_BLOCKS; i++) {
+				if (dst != src)
+					dst[i] = src[i];
+
+				u128_to_be128(&ctrblocks[i], &ctrblk);
+				u128_inc(&ctrblk);
+			}
+
+			twofish_enc_blk_xway_xor(ctx, (u8 *)dst,
+						 (u8 *)ctrblocks);
+
+			src += TWOFISH_PARALLEL_BLOCKS;
+			dst += TWOFISH_PARALLEL_BLOCKS;
+			nbytes -= bsize * TWOFISH_PARALLEL_BLOCKS;
+		} while (nbytes >= bsize * TWOFISH_PARALLEL_BLOCKS);
+
+		if (nbytes < bsize)
+			goto done;
+	}
+
+	/* Process three block batch */
+	if (nbytes >= bsize * 3) {
+		do {
+			if (dst != src) {
+				dst[0] = src[0];
+				dst[1] = src[1];
+				dst[2] = src[2];
+			}
+
+			/* create ctrblks for parallel encrypt */
+			u128_to_be128(&ctrblocks[0], &ctrblk);
+			u128_inc(&ctrblk);
+			u128_to_be128(&ctrblocks[1], &ctrblk);
+			u128_inc(&ctrblk);
+			u128_to_be128(&ctrblocks[2], &ctrblk);
+			u128_inc(&ctrblk);
+
+			twofish_enc_blk_3way_xor(ctx, (u8 *)dst,
+						 (u8 *)ctrblocks);
+
+			src += 3;
+			dst += 3;
+			nbytes -= bsize * 3;
+		} while (nbytes >= bsize * 3);
+
+		if (nbytes < bsize)
+			goto done;
+	}
+
+	/* Handle leftovers */
+	do {
+		if (dst != src)
+			*dst = *src;
+
+		u128_to_be128(&ctrblocks[0], &ctrblk);
+		u128_inc(&ctrblk);
+
+		twofish_enc_blk(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks);
+		u128_xor(dst, dst, (u128 *)ctrblocks);
+
+		src += 1;
+		dst += 1;
+		nbytes -= bsize;
+	} while (nbytes >= bsize);
+
+done:
+	u128_to_be128((be128 *)walk->iv, &ctrblk);
+	return nbytes;
+}
+
+static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		     struct scatterlist *src, unsigned int nbytes)
+{
+	bool fpu_enabled = false;
+	struct blkcipher_walk walk;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt_block(desc, &walk, TF_BLOCK_SIZE);
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	while ((nbytes = walk.nbytes) >= TF_BLOCK_SIZE) {
+		fpu_enabled = twofish_fpu_begin(fpu_enabled, nbytes);
+		nbytes = __ctr_crypt(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	twofish_fpu_end(fpu_enabled);
+
+	if (walk.nbytes) {
+		ctr_crypt_final(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, 0);
+	}
+
+	return err;
+}
+
+struct crypt_priv {
+	struct twofish_ctx *ctx;
+	bool fpu_enabled;
+};
+
+static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+	const unsigned int bsize = TF_BLOCK_SIZE;
+	struct crypt_priv *ctx = priv;
+	int i;
+
+	ctx->fpu_enabled = twofish_fpu_begin(ctx->fpu_enabled, nbytes);
+
+	if (nbytes == bsize * TWOFISH_PARALLEL_BLOCKS) {
+		twofish_enc_blk_xway(ctx->ctx, srcdst, srcdst);
+		return;
+	}
+
+	for (i = 0; i < nbytes / (bsize * 3); i++, srcdst += bsize * 3)
+		twofish_enc_blk_3way(ctx->ctx, srcdst, srcdst);
+
+	nbytes %= bsize * 3;
+
+	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+		twofish_enc_blk(ctx->ctx, srcdst, srcdst);
+}
+
+static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+	const unsigned int bsize = TF_BLOCK_SIZE;
+	struct crypt_priv *ctx = priv;
+	int i;
+
+	ctx->fpu_enabled = twofish_fpu_begin(ctx->fpu_enabled, nbytes);
+
+	if (nbytes == bsize * TWOFISH_PARALLEL_BLOCKS) {
+		twofish_dec_blk_xway(ctx->ctx, srcdst, srcdst);
+		return;
+	}
+
+	for (i = 0; i < nbytes / (bsize * 3); i++, srcdst += bsize * 3)
+		twofish_dec_blk_3way(ctx->ctx, srcdst, srcdst);
+
+	nbytes %= bsize * 3;
+
+	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+		twofish_dec_blk(ctx->ctx, srcdst, srcdst);
+}
+
+struct twofish_lrw_ctx {
+	struct lrw_table_ctx lrw_table;
+	struct twofish_ctx twofish_ctx;
+};
+
+static int lrw_twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
+			      unsigned int keylen)
+{
+	struct twofish_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+	int err;
+
+	err = __twofish_setkey(&ctx->twofish_ctx, key,
+				keylen - TF_BLOCK_SIZE, &tfm->crt_flags);
+	if (err)
+		return err;
+
+	return lrw_init_table(&ctx->lrw_table, key + keylen -
+						TF_BLOCK_SIZE);
+}
+
+static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[TWOFISH_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->twofish_ctx,
+		.fpu_enabled = false,
+	};
+	struct lrw_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.table_ctx = &ctx->lrw_table,
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = encrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = lrw_crypt(desc, dst, src, nbytes, &req);
+	twofish_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[TWOFISH_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->twofish_ctx,
+		.fpu_enabled = false,
+	};
+	struct lrw_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.table_ctx = &ctx->lrw_table,
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = decrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = lrw_crypt(desc, dst, src, nbytes, &req);
+	twofish_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static void lrw_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct twofish_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	lrw_free_table(&ctx->lrw_table);
+}
+
+struct twofish_xts_ctx {
+	struct twofish_ctx tweak_ctx;
+	struct twofish_ctx crypt_ctx;
+};
+
+static int xts_twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
+			      unsigned int keylen)
+{
+	struct twofish_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+	u32 *flags = &tfm->crt_flags;
+	int err;
+
+	/* key consists of keys of equal size concatenated, therefore
+	 * the length must be even
+	 */
+	if (keylen % 2) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	/* first half of xts-key is for crypt */
+	err = __twofish_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
+	if (err)
+		return err;
+
+	/* second half of xts-key is for tweak */
+	return __twofish_setkey(&ctx->tweak_ctx,
+				key + keylen / 2, keylen / 2, flags);
+}
+
+static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[TWOFISH_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->crypt_ctx,
+		.fpu_enabled = false,
+	};
+	struct xts_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.tweak_ctx = &ctx->tweak_ctx,
+		.tweak_fn = XTS_TWEAK_CAST(twofish_enc_blk),
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = encrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = xts_crypt(desc, dst, src, nbytes, &req);
+	twofish_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[TWOFISH_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->crypt_ctx,
+		.fpu_enabled = false,
+	};
+	struct xts_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.tweak_ctx = &ctx->tweak_ctx,
+		.tweak_fn = XTS_TWEAK_CAST(twofish_enc_blk),
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = decrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = xts_crypt(desc, dst, src, nbytes, &req);
+	twofish_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
+			unsigned int key_len)
+{
+	struct async_twofish_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+	struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base;
+	int err;
+
+	crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm)
+				    & CRYPTO_TFM_REQ_MASK);
+	err = crypto_ablkcipher_setkey(child, key, key_len);
+	crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child)
+				    & CRYPTO_TFM_RES_MASK);
+	return err;
+}
+
+static int __ablk_encrypt(struct ablkcipher_request *req)
+{
+	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+	struct async_twofish_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+	struct blkcipher_desc desc;
+
+	desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
+	desc.info = req->info;
+	desc.flags = 0;
+
+	return crypto_blkcipher_crt(desc.tfm)->encrypt(
+		&desc, req->dst, req->src, req->nbytes);
+}
+
+static int ablk_encrypt(struct ablkcipher_request *req)
+{
+	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+	struct async_twofish_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+	if (!irq_fpu_usable()) {
+		struct ablkcipher_request *cryptd_req =
+			ablkcipher_request_ctx(req);
+
+		memcpy(cryptd_req, req, sizeof(*req));
+		ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
+
+		return crypto_ablkcipher_encrypt(cryptd_req);
+	} else {
+		return __ablk_encrypt(req);
+	}
+}
+
+static int ablk_decrypt(struct ablkcipher_request *req)
+{
+	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+	struct async_twofish_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+	if (!irq_fpu_usable()) {
+		struct ablkcipher_request *cryptd_req =
+			ablkcipher_request_ctx(req);
+
+		memcpy(cryptd_req, req, sizeof(*req));
+		ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
+
+		return crypto_ablkcipher_decrypt(cryptd_req);
+	} else {
+		struct blkcipher_desc desc;
+
+		desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
+		desc.info = req->info;
+		desc.flags = 0;
+
+		return crypto_blkcipher_crt(desc.tfm)->decrypt(
+			&desc, req->dst, req->src, req->nbytes);
+	}
+}
+
+static void ablk_exit(struct crypto_tfm *tfm)
+{
+	struct async_twofish_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	cryptd_free_ablkcipher(ctx->cryptd_tfm);
+}
+
+static int ablk_init(struct crypto_tfm *tfm)
+{
+	struct async_twofish_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct cryptd_ablkcipher *cryptd_tfm;
+	char drv_name[CRYPTO_MAX_ALG_NAME];
+
+	snprintf(drv_name, sizeof(drv_name), "__driver-%s",
+					crypto_tfm_alg_driver_name(tfm));
+
+	cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0);
+	if (IS_ERR(cryptd_tfm))
+		return PTR_ERR(cryptd_tfm);
+
+	ctx->cryptd_tfm = cryptd_tfm;
+	tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
+		crypto_ablkcipher_reqsize(&cryptd_tfm->base);
+
+	return 0;
+}
+
+static struct crypto_alg twofish_algs[10] = { {
+	.cra_name		= "__ecb-twofish-avx",
+	.cra_driver_name	= "__driver-ecb-twofish-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= TF_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct twofish_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(twofish_algs[0].cra_list),
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= TF_MIN_KEY_SIZE,
+			.max_keysize	= TF_MAX_KEY_SIZE,
+			.setkey		= twofish_setkey,
+			.encrypt	= ecb_encrypt,
+			.decrypt	= ecb_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__cbc-twofish-avx",
+	.cra_driver_name	= "__driver-cbc-twofish-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= TF_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct twofish_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(twofish_algs[1].cra_list),
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= TF_MIN_KEY_SIZE,
+			.max_keysize	= TF_MAX_KEY_SIZE,
+			.setkey		= twofish_setkey,
+			.encrypt	= cbc_encrypt,
+			.decrypt	= cbc_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__ctr-twofish-avx",
+	.cra_driver_name	= "__driver-ctr-twofish-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct twofish_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(twofish_algs[2].cra_list),
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= TF_MIN_KEY_SIZE,
+			.max_keysize	= TF_MAX_KEY_SIZE,
+			.ivsize		= TF_BLOCK_SIZE,
+			.setkey		= twofish_setkey,
+			.encrypt	= ctr_crypt,
+			.decrypt	= ctr_crypt,
+		},
+	},
+}, {
+	.cra_name		= "__lrw-twofish-avx",
+	.cra_driver_name	= "__driver-lrw-twofish-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= TF_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct twofish_lrw_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(twofish_algs[3].cra_list),
+	.cra_exit		= lrw_exit_tfm,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= TF_MIN_KEY_SIZE +
+					  TF_BLOCK_SIZE,
+			.max_keysize	= TF_MAX_KEY_SIZE +
+					  TF_BLOCK_SIZE,
+			.ivsize		= TF_BLOCK_SIZE,
+			.setkey		= lrw_twofish_setkey,
+			.encrypt	= lrw_encrypt,
+			.decrypt	= lrw_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__xts-twofish-avx",
+	.cra_driver_name	= "__driver-xts-twofish-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= TF_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct twofish_xts_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(twofish_algs[4].cra_list),
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= TF_MIN_KEY_SIZE * 2,
+			.max_keysize	= TF_MAX_KEY_SIZE * 2,
+			.ivsize		= TF_BLOCK_SIZE,
+			.setkey		= xts_twofish_setkey,
+			.encrypt	= xts_encrypt,
+			.decrypt	= xts_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "ecb(twofish)",
+	.cra_driver_name	= "ecb-twofish-avx",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= TF_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_twofish_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(twofish_algs[5].cra_list),
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= TF_MIN_KEY_SIZE,
+			.max_keysize	= TF_MAX_KEY_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "cbc(twofish)",
+	.cra_driver_name	= "cbc-twofish-avx",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= TF_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_twofish_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(twofish_algs[6].cra_list),
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= TF_MIN_KEY_SIZE,
+			.max_keysize	= TF_MAX_KEY_SIZE,
+			.ivsize		= TF_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= __ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "ctr(twofish)",
+	.cra_driver_name	= "ctr-twofish-avx",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct async_twofish_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(twofish_algs[7].cra_list),
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= TF_MIN_KEY_SIZE,
+			.max_keysize	= TF_MAX_KEY_SIZE,
+			.ivsize		= TF_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_encrypt,
+			.geniv		= "chainiv",
+		},
+	},
+}, {
+	.cra_name		= "lrw(twofish)",
+	.cra_driver_name	= "lrw-twofish-avx",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= TF_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_twofish_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(twofish_algs[8].cra_list),
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= TF_MIN_KEY_SIZE +
+					  TF_BLOCK_SIZE,
+			.max_keysize	= TF_MAX_KEY_SIZE +
+					  TF_BLOCK_SIZE,
+			.ivsize		= TF_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "xts(twofish)",
+	.cra_driver_name	= "xts-twofish-avx",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= TF_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_twofish_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(twofish_algs[9].cra_list),
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= TF_MIN_KEY_SIZE * 2,
+			.max_keysize	= TF_MAX_KEY_SIZE * 2,
+			.ivsize		= TF_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+} };
+
+static int __init twofish_init(void)
+{
+	u64 xcr0;
+
+	if (!cpu_has_avx || !cpu_has_osxsave) {
+		printk(KERN_INFO "AVX instructions are not detected.\n");
+		return -ENODEV;
+	}
+
+	xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
+	if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
+		printk(KERN_INFO "AVX detected but unusable.\n");
+		return -ENODEV;
+	}
+
+	return crypto_register_algs(twofish_algs, ARRAY_SIZE(twofish_algs));
+}
+
+static void __exit twofish_exit(void)
+{
+	crypto_unregister_algs(twofish_algs, ARRAY_SIZE(twofish_algs));
+}
+
+module_init(twofish_init);
+module_exit(twofish_exit);
+
+MODULE_DESCRIPTION("Twofish Cipher Algorithm, AVX optimized");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("twofish");
diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c
index 922ab24..77e4e55 100644
--- a/arch/x86/crypto/twofish_glue_3way.c
+++ b/arch/x86/crypto/twofish_glue_3way.c
@@ -45,8 +45,10 @@ asmlinkage void twofish_dec_blk(struct twofish_ctx *ctx, u8 *dst,
 /* 3-way parallel cipher functions */
 asmlinkage void __twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
 				       const u8 *src, bool xor);
+EXPORT_SYMBOL_GPL(__twofish_enc_blk_3way);
 asmlinkage void twofish_dec_blk_3way(struct twofish_ctx *ctx, u8 *dst,
 				     const u8 *src);
+EXPORT_SYMBOL_GPL(twofish_dec_blk_3way);
 
 static inline void twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
 					const u8 *src)
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index daeca56..673ac9b 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -38,7 +38,7 @@
 int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
 {
 	int err = 0;
-	bool ia32 = is_ia32_task();
+	bool ia32 = test_thread_flag(TIF_IA32);
 
 	if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
 		return -EFAULT;
diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h
index 49ad773..b3341e9 100644
--- a/arch/x86/include/asm/amd_nb.h
+++ b/arch/x86/include/asm/amd_nb.h
@@ -26,10 +26,31 @@ struct amd_l3_cache {
 	u8	 subcaches[4];
 };
 
+struct threshold_block {
+	unsigned int		block;
+	unsigned int		bank;
+	unsigned int		cpu;
+	u32			address;
+	u16			interrupt_enable;
+	bool			interrupt_capable;
+	u16			threshold_limit;
+	struct kobject		kobj;
+	struct list_head	miscj;
+};
+
+struct threshold_bank {
+	struct kobject		*kobj;
+	struct threshold_block	*blocks;
+
+	/* initialized to the number of CPUs on the node sharing this bank */
+	atomic_t		cpus;
+};
+
 struct amd_northbridge {
 	struct pci_dev *misc;
 	struct pci_dev *link;
 	struct amd_l3_cache l3_cache;
+	struct threshold_bank *bank4;
 };
 
 struct amd_northbridge_info {
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index eaff479..8619a87 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -306,7 +306,7 @@ struct apic {
 	unsigned long (*check_apicid_used)(physid_mask_t *map, int apicid);
 	unsigned long (*check_apicid_present)(int apicid);
 
-	void (*vector_allocation_domain)(int cpu, struct cpumask *retmask);
+	bool (*vector_allocation_domain)(int cpu, struct cpumask *retmask);
 	void (*init_apic_ldr)(void);
 
 	void (*ioapic_phys_id_map)(physid_mask_t *phys_map, physid_mask_t *retmap);
@@ -331,9 +331,9 @@ struct apic {
 	unsigned long (*set_apic_id)(unsigned int id);
 	unsigned long apic_id_mask;
 
-	unsigned int (*cpu_mask_to_apicid)(const struct cpumask *cpumask);
-	unsigned int (*cpu_mask_to_apicid_and)(const struct cpumask *cpumask,
-					       const struct cpumask *andmask);
+	int (*cpu_mask_to_apicid_and)(const struct cpumask *cpumask,
+				      const struct cpumask *andmask,
+				      unsigned int *apicid);
 
 	/* ipi */
 	void (*send_IPI_mask)(const struct cpumask *mask, int vector);
@@ -537,7 +537,12 @@ static inline const struct cpumask *default_target_cpus(void)
 #endif
 }
 
-DECLARE_EARLY_PER_CPU(u16, x86_bios_cpu_apicid);
+static inline const struct cpumask *online_target_cpus(void)
+{
+	return cpu_online_mask;
+}
+
+DECLARE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_bios_cpu_apicid);
 
 
 static inline unsigned int read_apic_id(void)
@@ -586,21 +591,50 @@ static inline int default_phys_pkg_id(int cpuid_apic, int index_msb)
 
 #endif
 
-static inline unsigned int
-default_cpu_mask_to_apicid(const struct cpumask *cpumask)
+static inline int
+flat_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
+			    const struct cpumask *andmask,
+			    unsigned int *apicid)
 {
-	return cpumask_bits(cpumask)[0] & APIC_ALL_CPUS;
+	unsigned long cpu_mask = cpumask_bits(cpumask)[0] &
+				 cpumask_bits(andmask)[0] &
+				 cpumask_bits(cpu_online_mask)[0] &
+				 APIC_ALL_CPUS;
+
+	if (likely(cpu_mask)) {
+		*apicid = (unsigned int)cpu_mask;
+		return 0;
+	} else {
+		return -EINVAL;
+	}
 }
 
-static inline unsigned int
+extern int
 default_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-			       const struct cpumask *andmask)
+			       const struct cpumask *andmask,
+			       unsigned int *apicid);
+
+static inline bool
+flat_vector_allocation_domain(int cpu, struct cpumask *retmask)
 {
-	unsigned long mask1 = cpumask_bits(cpumask)[0];
-	unsigned long mask2 = cpumask_bits(andmask)[0];
-	unsigned long mask3 = cpumask_bits(cpu_online_mask)[0];
+	/* Careful. Some cpus do not strictly honor the set of cpus
+	 * specified in the interrupt destination when using lowest
+	 * priority interrupt delivery mode.
+	 *
+	 * In particular there was a hyperthreading cpu observed to
+	 * deliver interrupts to the wrong hyperthread when only one
+	 * hyperthread was specified in the interrupt desitination.
+	 */
+	cpumask_clear(retmask);
+	cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
+	return false;
+}
 
-	return (unsigned int)(mask1 & mask2 & mask3);
+static inline bool
+default_vector_allocation_domain(int cpu, struct cpumask *retmask)
+{
+	cpumask_copy(retmask, cpumask_of(cpu));
+	return true;
 }
 
 static inline unsigned long default_check_apicid_used(physid_mask_t *map, int apicid)
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 340ee49..f91e80f 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -176,7 +176,7 @@
 #define X86_FEATURE_XSAVEOPT	(7*32+ 4) /* Optimized Xsave */
 #define X86_FEATURE_PLN		(7*32+ 5) /* Intel Power Limit Notification */
 #define X86_FEATURE_PTS		(7*32+ 6) /* Intel Package Thermal Status */
-#define X86_FEATURE_DTS		(7*32+ 7) /* Digital Thermal Sensor */
+#define X86_FEATURE_DTHERM	(7*32+ 7) /* Digital Thermal Sensor */
 #define X86_FEATURE_HW_PSTATE	(7*32+ 8) /* AMD HW-PState */
 
 /* Virtualization flags: Linux defined, word 8 */
diff --git a/arch/x86/include/asm/emergency-restart.h b/arch/x86/include/asm/emergency-restart.h
index cc70c1c..75ce3f4 100644
--- a/arch/x86/include/asm/emergency-restart.h
+++ b/arch/x86/include/asm/emergency-restart.h
@@ -4,9 +4,7 @@
 enum reboot_type {
 	BOOT_TRIPLE = 't',
 	BOOT_KBD = 'k',
-#ifdef CONFIG_X86_32
 	BOOT_BIOS = 'b',
-#endif
 	BOOT_ACPI = 'a',
 	BOOT_EFI = 'e',
 	BOOT_CF9 = 'p',
diff --git a/arch/x86/include/asm/floppy.h b/arch/x86/include/asm/floppy.h
index dbe82a5..d3d7469 100644
--- a/arch/x86/include/asm/floppy.h
+++ b/arch/x86/include/asm/floppy.h
@@ -99,7 +99,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id)
 		virtual_dma_residue += virtual_dma_count;
 		virtual_dma_count = 0;
 #ifdef TRACE_FLPY_INT
-		printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n",
+		printk(KERN_DEBUG "count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n",
 		       virtual_dma_count, virtual_dma_residue, calls, bytes,
 		       dma_wait);
 		calls = 0;
diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h
index dffc38e..345c99c 100644
--- a/arch/x86/include/asm/iommu.h
+++ b/arch/x86/include/asm/iommu.h
@@ -5,7 +5,6 @@ extern struct dma_map_ops nommu_dma_ops;
 extern int force_iommu, no_iommu;
 extern int iommu_detected;
 extern int iommu_pass_through;
-extern int iommu_group_mf;
 
 /* 10 seconds */
 #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 084ef95..813ed10 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -115,8 +115,8 @@ notrace static inline int native_write_msr_safe(unsigned int msr,
 
 extern unsigned long long native_read_tsc(void);
 
-extern int native_rdmsr_safe_regs(u32 regs[8]);
-extern int native_wrmsr_safe_regs(u32 regs[8]);
+extern int rdmsr_safe_regs(u32 regs[8]);
+extern int wrmsr_safe_regs(u32 regs[8]);
 
 static __always_inline unsigned long long __native_read_tsc(void)
 {
@@ -187,43 +187,6 @@ static inline int rdmsrl_safe(unsigned msr, unsigned long long *p)
 	return err;
 }
 
-static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
-{
-	u32 gprs[8] = { 0 };
-	int err;
-
-	gprs[1] = msr;
-	gprs[7] = 0x9c5a203a;
-
-	err = native_rdmsr_safe_regs(gprs);
-
-	*p = gprs[0] | ((u64)gprs[2] << 32);
-
-	return err;
-}
-
-static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val)
-{
-	u32 gprs[8] = { 0 };
-
-	gprs[0] = (u32)val;
-	gprs[1] = msr;
-	gprs[2] = val >> 32;
-	gprs[7] = 0x9c5a203a;
-
-	return native_wrmsr_safe_regs(gprs);
-}
-
-static inline int rdmsr_safe_regs(u32 regs[8])
-{
-	return native_rdmsr_safe_regs(regs);
-}
-
-static inline int wrmsr_safe_regs(u32 regs[8])
-{
-	return native_wrmsr_safe_regs(regs);
-}
-
 #define rdtscl(low)						\
 	((low) = (u32)__native_read_tsc())
 
@@ -237,6 +200,8 @@ do {							\
 	(high) = (u32)(_l >> 32);			\
 } while (0)
 
+#define rdpmcl(counter, val) ((val) = native_read_pmc(counter))
+
 #define rdtscp(low, high, aux)					\
 do {                                                            \
 	unsigned long long _val = native_read_tscp(&(aux));     \
@@ -248,8 +213,7 @@ do {                                                            \
 
 #endif	/* !CONFIG_PARAVIRT */
 
-
-#define checking_wrmsrl(msr, val) wrmsr_safe((msr), (u32)(val),		\
+#define wrmsrl_safe(msr, val) wrmsr_safe((msr), (u32)(val),		\
 					     (u32)((val) >> 32))
 
 #define write_tsc(val1, val2) wrmsr(MSR_IA32_TSC, (val1), (val2))
diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h
index dc580c4..c0fa356 100644
--- a/arch/x86/include/asm/nmi.h
+++ b/arch/x86/include/asm/nmi.h
@@ -44,28 +44,14 @@ struct nmiaction {
 	const char		*name;
 };
 
-#define register_nmi_handler(t, fn, fg, n)		\
+#define register_nmi_handler(t, fn, fg, n, init...)	\
 ({							\
-	static struct nmiaction fn##_na = {		\
+	static struct nmiaction init fn##_na = {	\
 		.handler = (fn),			\
 		.name = (n),				\
 		.flags = (fg),				\
 	};						\
-	__register_nmi_handler((t), &fn##_na);	\
-})
-
-/*
- * For special handlers that register/unregister in the
- * init section only.  This should be considered rare.
- */
-#define register_nmi_handler_initonly(t, fn, fg, n)		\
-({							\
-	static struct nmiaction fn##_na __initdata = {		\
-		.handler = (fn),			\
-		.name = (n),				\
-		.flags = (fg),				\
-	};						\
-	__register_nmi_handler((t), &fn##_na);	\
+	__register_nmi_handler((t), &fn##_na);		\
 })
 
 int __register_nmi_handler(unsigned int, struct nmiaction *);
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 6cbbabf..0b47ddb 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -128,21 +128,11 @@ static inline u64 paravirt_read_msr(unsigned msr, int *err)
 	return PVOP_CALL2(u64, pv_cpu_ops.read_msr, msr, err);
 }
 
-static inline int paravirt_rdmsr_regs(u32 *regs)
-{
-	return PVOP_CALL1(int, pv_cpu_ops.rdmsr_regs, regs);
-}
-
 static inline int paravirt_write_msr(unsigned msr, unsigned low, unsigned high)
 {
 	return PVOP_CALL3(int, pv_cpu_ops.write_msr, msr, low, high);
 }
 
-static inline int paravirt_wrmsr_regs(u32 *regs)
-{
-	return PVOP_CALL1(int, pv_cpu_ops.wrmsr_regs, regs);
-}
-
 /* These should all do BUG_ON(_err), but our headers are too tangled. */
 #define rdmsr(msr, val1, val2)			\
 do {						\
@@ -176,9 +166,6 @@ do {						\
 	_err;					\
 })
 
-#define rdmsr_safe_regs(regs)	paravirt_rdmsr_regs(regs)
-#define wrmsr_safe_regs(regs)	paravirt_wrmsr_regs(regs)
-
 static inline int rdmsrl_safe(unsigned msr, unsigned long long *p)
 {
 	int err;
@@ -186,32 +173,6 @@ static inline int rdmsrl_safe(unsigned msr, unsigned long long *p)
 	*p = paravirt_read_msr(msr, &err);
 	return err;
 }
-static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
-{
-	u32 gprs[8] = { 0 };
-	int err;
-
-	gprs[1] = msr;
-	gprs[7] = 0x9c5a203a;
-
-	err = paravirt_rdmsr_regs(gprs);
-
-	*p = gprs[0] | ((u64)gprs[2] << 32);
-
-	return err;
-}
-
-static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val)
-{
-	u32 gprs[8] = { 0 };
-
-	gprs[0] = (u32)val;
-	gprs[1] = msr;
-	gprs[2] = val >> 32;
-	gprs[7] = 0x9c5a203a;
-
-	return paravirt_wrmsr_regs(gprs);
-}
 
 static inline u64 paravirt_read_tsc(void)
 {
@@ -252,6 +213,8 @@ do {						\
 	high = _l >> 32;			\
 } while (0)
 
+#define rdpmcl(counter, val) ((val) = paravirt_read_pmc(counter))
+
 static inline unsigned long long paravirt_rdtscp(unsigned int *aux)
 {
 	return PVOP_CALL1(u64, pv_cpu_ops.read_tscp, aux);
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index 8e8b9a4..8613cbb 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -153,9 +153,7 @@ struct pv_cpu_ops {
 	/* MSR, PMC and TSR operations.
 	   err = 0/-EFAULT.  wrmsr returns 0/-EFAULT. */
 	u64 (*read_msr)(unsigned int msr, int *err);
-	int (*rdmsr_regs)(u32 *regs);
 	int (*write_msr)(unsigned int msr, unsigned low, unsigned high);
-	int (*wrmsr_regs)(u32 *regs);
 
 	u64 (*read_tsc)(void);
 	u64 (*read_pmc)(int counter);
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index b3a5317..73e8eef 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -7,9 +7,13 @@
 #undef DEBUG
 
 #ifdef DEBUG
-#define DBG(x...) printk(x)
+#define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
 #else
-#define DBG(x...)
+#define DBG(fmt, ...)				\
+do {						\
+	if (0)					\
+		printk(fmt, ##__VA_ARGS__);	\
+} while (0)
 #endif
 
 #define PCI_PROBE_BIOS		0x0001
@@ -100,6 +104,7 @@ struct pci_raw_ops {
 extern const struct pci_raw_ops *raw_pci_ops;
 extern const struct pci_raw_ops *raw_pci_ext_ops;
 
+extern const struct pci_raw_ops pci_mmcfg;
 extern const struct pci_raw_ops pci_direct_conf1;
 extern bool port_cf9_safe;
 
@@ -135,6 +140,12 @@ struct pci_mmcfg_region {
 
 extern int __init pci_mmcfg_arch_init(void);
 extern void __init pci_mmcfg_arch_free(void);
+extern int __devinit pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
+extern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);
+extern int __devinit pci_mmconfig_insert(struct device *dev,
+					 u16 seg, u8 start,
+					 u8 end, phys_addr_t addr);
+extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
 extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
 
 extern struct list_head pci_mmcfg_list;
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index d9b8e3f..1104afa 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -551,6 +551,12 @@ DECLARE_PER_CPU(unsigned long, this_cpu_off);
 				{ [0 ... NR_CPUS-1] = _initvalue };	\
 	__typeof__(_type) *_name##_early_ptr __refdata = _name##_early_map
 
+#define DEFINE_EARLY_PER_CPU_READ_MOSTLY(_type, _name, _initvalue)	\
+	DEFINE_PER_CPU_READ_MOSTLY(_type, _name) = _initvalue;		\
+	__typeof__(_type) _name##_early_map[NR_CPUS] __initdata =	\
+				{ [0 ... NR_CPUS-1] = _initvalue };	\
+	__typeof__(_type) *_name##_early_ptr __refdata = _name##_early_map
+
 #define EXPORT_EARLY_PER_CPU_SYMBOL(_name)			\
 	EXPORT_PER_CPU_SYMBOL(_name)
 
@@ -559,6 +565,11 @@ DECLARE_PER_CPU(unsigned long, this_cpu_off);
 	extern __typeof__(_type) *_name##_early_ptr;		\
 	extern __typeof__(_type)  _name##_early_map[]
 
+#define DECLARE_EARLY_PER_CPU_READ_MOSTLY(_type, _name)		\
+	DECLARE_PER_CPU_READ_MOSTLY(_type, _name);		\
+	extern __typeof__(_type) *_name##_early_ptr;		\
+	extern __typeof__(_type)  _name##_early_map[]
+
 #define	early_per_cpu_ptr(_name) (_name##_early_ptr)
 #define	early_per_cpu_map(_name, _idx) (_name##_early_map[_idx])
 #define	early_per_cpu(_name, _cpu) 				\
@@ -570,12 +581,18 @@ DECLARE_PER_CPU(unsigned long, this_cpu_off);
 #define	DEFINE_EARLY_PER_CPU(_type, _name, _initvalue)		\
 	DEFINE_PER_CPU(_type, _name) = _initvalue
 
+#define DEFINE_EARLY_PER_CPU_READ_MOSTLY(_type, _name, _initvalue)	\
+	DEFINE_PER_CPU_READ_MOSTLY(_type, _name) = _initvalue
+
 #define EXPORT_EARLY_PER_CPU_SYMBOL(_name)			\
 	EXPORT_PER_CPU_SYMBOL(_name)
 
 #define DECLARE_EARLY_PER_CPU(_type, _name)			\
 	DECLARE_PER_CPU(_type, _name)
 
+#define DECLARE_EARLY_PER_CPU_READ_MOSTLY(_type, _name)		\
+	DECLARE_PER_CPU_READ_MOSTLY(_type, _name)
+
 #define	early_per_cpu(_name, _cpu) per_cpu(_name, _cpu)
 #define	early_per_cpu_ptr(_name) NULL
 /* no early_per_cpu_map() */
diff --git a/arch/x86/include/asm/pgtable-2level.h b/arch/x86/include/asm/pgtable-2level.h
index 98391db..f2b489c 100644
--- a/arch/x86/include/asm/pgtable-2level.h
+++ b/arch/x86/include/asm/pgtable-2level.h
@@ -2,9 +2,9 @@
 #define _ASM_X86_PGTABLE_2LEVEL_H
 
 #define pte_ERROR(e) \
-	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, (e).pte_low)
+	pr_err("%s:%d: bad pte %08lx\n", __FILE__, __LINE__, (e).pte_low)
 #define pgd_ERROR(e) \
-	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+	pr_err("%s:%d: bad pgd %08lx\n", __FILE__, __LINE__, pgd_val(e))
 
 /*
  * Certain architectures need to do special things when PTEs
diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h
index cb00ccc..4cc9f2b 100644
--- a/arch/x86/include/asm/pgtable-3level.h
+++ b/arch/x86/include/asm/pgtable-3level.h
@@ -9,13 +9,13 @@
  */
 
 #define pte_ERROR(e)							\
-	printk("%s:%d: bad pte %p(%08lx%08lx).\n",			\
+	pr_err("%s:%d: bad pte %p(%08lx%08lx)\n",			\
 	       __FILE__, __LINE__, &(e), (e).pte_high, (e).pte_low)
 #define pmd_ERROR(e)							\
-	printk("%s:%d: bad pmd %p(%016Lx).\n",				\
+	pr_err("%s:%d: bad pmd %p(%016Lx)\n",				\
 	       __FILE__, __LINE__, &(e), pmd_val(e))
 #define pgd_ERROR(e)							\
-	printk("%s:%d: bad pgd %p(%016Lx).\n",				\
+	pr_err("%s:%d: bad pgd %p(%016Lx)\n",				\
 	       __FILE__, __LINE__, &(e), pgd_val(e))
 
 /* Rules for using set_pte: the pte being assigned *must* be
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h
index 975f709..8251be0 100644
--- a/arch/x86/include/asm/pgtable_64.h
+++ b/arch/x86/include/asm/pgtable_64.h
@@ -26,16 +26,16 @@ extern pgd_t init_level4_pgt[];
 extern void paging_init(void);
 
 #define pte_ERROR(e)					\
-	printk("%s:%d: bad pte %p(%016lx).\n",		\
+	pr_err("%s:%d: bad pte %p(%016lx)\n",		\
 	       __FILE__, __LINE__, &(e), pte_val(e))
 #define pmd_ERROR(e)					\
-	printk("%s:%d: bad pmd %p(%016lx).\n",		\
+	pr_err("%s:%d: bad pmd %p(%016lx)\n",		\
 	       __FILE__, __LINE__, &(e), pmd_val(e))
 #define pud_ERROR(e)					\
-	printk("%s:%d: bad pud %p(%016lx).\n",		\
+	pr_err("%s:%d: bad pud %p(%016lx)\n",		\
 	       __FILE__, __LINE__, &(e), pud_val(e))
 #define pgd_ERROR(e)					\
-	printk("%s:%d: bad pgd %p(%016lx).\n",		\
+	pr_err("%s:%d: bad pgd %p(%016lx)\n",		\
 	       __FILE__, __LINE__, &(e), pgd_val(e))
 
 struct mm_struct;
diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index fce3f4a..fe1ec5b 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -21,8 +21,9 @@ struct real_mode_header {
 	u32	wakeup_header;
 #endif
 	/* APM/BIOS reboot */
-#ifdef CONFIG_X86_32
 	u32	machine_real_restart_asm;
+#ifdef CONFIG_X86_64
+	u32	machine_real_restart_seg;
 #endif
 };
 
diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h
index 92f29706..a82c4f1 100644
--- a/arch/x86/include/asm/reboot.h
+++ b/arch/x86/include/asm/reboot.h
@@ -18,8 +18,8 @@ extern struct machine_ops machine_ops;
 
 void native_machine_crash_shutdown(struct pt_regs *regs);
 void native_machine_shutdown(void);
-void machine_real_restart(unsigned int type);
-/* These must match dispatch_table in reboot_32.S */
+void __noreturn machine_real_restart(unsigned int type);
+/* These must match dispatch in arch/x86/realmore/rm/reboot.S */
 #define MRR_BIOS	0
 #define MRR_APM		1
 
diff --git a/arch/x86/include/asm/serpent-avx.h b/arch/x86/include/asm/serpent-avx.h
new file mode 100644
index 0000000..432deed
--- /dev/null
+++ b/arch/x86/include/asm/serpent-avx.h
@@ -0,0 +1,32 @@
+#ifndef ASM_X86_SERPENT_AVX_H
+#define ASM_X86_SERPENT_AVX_H
+
+#include <linux/crypto.h>
+#include <crypto/serpent.h>
+
+#define SERPENT_PARALLEL_BLOCKS 8
+
+asmlinkage void __serpent_enc_blk_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+					   const u8 *src, bool xor);
+asmlinkage void serpent_dec_blk_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+					 const u8 *src);
+
+static inline void serpent_enc_blk_xway(struct serpent_ctx *ctx, u8 *dst,
+				   const u8 *src)
+{
+	__serpent_enc_blk_8way_avx(ctx, dst, src, false);
+}
+
+static inline void serpent_enc_blk_xway_xor(struct serpent_ctx *ctx, u8 *dst,
+				       const u8 *src)
+{
+	__serpent_enc_blk_8way_avx(ctx, dst, src, true);
+}
+
+static inline void serpent_dec_blk_xway(struct serpent_ctx *ctx, u8 *dst,
+				   const u8 *src)
+{
+	serpent_dec_blk_8way_avx(ctx, dst, src);
+}
+
+#endif
diff --git a/arch/x86/include/asm/serpent-sse2.h b/arch/x86/include/asm/serpent-sse2.h
new file mode 100644
index 0000000..e6e77df
--- /dev/null
+++ b/arch/x86/include/asm/serpent-sse2.h
@@ -0,0 +1,63 @@
+#ifndef ASM_X86_SERPENT_SSE2_H
+#define ASM_X86_SERPENT_SSE2_H
+
+#include <linux/crypto.h>
+#include <crypto/serpent.h>
+
+#ifdef CONFIG_X86_32
+
+#define SERPENT_PARALLEL_BLOCKS 4
+
+asmlinkage void __serpent_enc_blk_4way(struct serpent_ctx *ctx, u8 *dst,
+				       const u8 *src, bool xor);
+asmlinkage void serpent_dec_blk_4way(struct serpent_ctx *ctx, u8 *dst,
+				     const u8 *src);
+
+static inline void serpent_enc_blk_xway(struct serpent_ctx *ctx, u8 *dst,
+					const u8 *src)
+{
+	__serpent_enc_blk_4way(ctx, dst, src, false);
+}
+
+static inline void serpent_enc_blk_xway_xor(struct serpent_ctx *ctx, u8 *dst,
+					    const u8 *src)
+{
+	__serpent_enc_blk_4way(ctx, dst, src, true);
+}
+
+static inline void serpent_dec_blk_xway(struct serpent_ctx *ctx, u8 *dst,
+					const u8 *src)
+{
+	serpent_dec_blk_4way(ctx, dst, src);
+}
+
+#else
+
+#define SERPENT_PARALLEL_BLOCKS 8
+
+asmlinkage void __serpent_enc_blk_8way(struct serpent_ctx *ctx, u8 *dst,
+				       const u8 *src, bool xor);
+asmlinkage void serpent_dec_blk_8way(struct serpent_ctx *ctx, u8 *dst,
+				     const u8 *src);
+
+static inline void serpent_enc_blk_xway(struct serpent_ctx *ctx, u8 *dst,
+				   const u8 *src)
+{
+	__serpent_enc_blk_8way(ctx, dst, src, false);
+}
+
+static inline void serpent_enc_blk_xway_xor(struct serpent_ctx *ctx, u8 *dst,
+				       const u8 *src)
+{
+	__serpent_enc_blk_8way(ctx, dst, src, true);
+}
+
+static inline void serpent_dec_blk_xway(struct serpent_ctx *ctx, u8 *dst,
+				   const u8 *src)
+{
+	serpent_dec_blk_8way(ctx, dst, src);
+}
+
+#endif
+
+#endif
diff --git a/arch/x86/include/asm/serpent.h b/arch/x86/include/asm/serpent.h
deleted file mode 100644
index d3ef63f..0000000
--- a/arch/x86/include/asm/serpent.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef ASM_X86_SERPENT_H
-#define ASM_X86_SERPENT_H
-
-#include <linux/crypto.h>
-#include <crypto/serpent.h>
-
-#ifdef CONFIG_X86_32
-
-#define SERPENT_PARALLEL_BLOCKS 4
-
-asmlinkage void __serpent_enc_blk_4way(struct serpent_ctx *ctx, u8 *dst,
-				       const u8 *src, bool xor);
-asmlinkage void serpent_dec_blk_4way(struct serpent_ctx *ctx, u8 *dst,
-				     const u8 *src);
-
-static inline void serpent_enc_blk_xway(struct serpent_ctx *ctx, u8 *dst,
-					const u8 *src)
-{
-	__serpent_enc_blk_4way(ctx, dst, src, false);
-}
-
-static inline void serpent_enc_blk_xway_xor(struct serpent_ctx *ctx, u8 *dst,
-					    const u8 *src)
-{
-	__serpent_enc_blk_4way(ctx, dst, src, true);
-}
-
-static inline void serpent_dec_blk_xway(struct serpent_ctx *ctx, u8 *dst,
-					const u8 *src)
-{
-	serpent_dec_blk_4way(ctx, dst, src);
-}
-
-#else
-
-#define SERPENT_PARALLEL_BLOCKS 8
-
-asmlinkage void __serpent_enc_blk_8way(struct serpent_ctx *ctx, u8 *dst,
-				       const u8 *src, bool xor);
-asmlinkage void serpent_dec_blk_8way(struct serpent_ctx *ctx, u8 *dst,
-				     const u8 *src);
-
-static inline void serpent_enc_blk_xway(struct serpent_ctx *ctx, u8 *dst,
-				   const u8 *src)
-{
-	__serpent_enc_blk_8way(ctx, dst, src, false);
-}
-
-static inline void serpent_enc_blk_xway_xor(struct serpent_ctx *ctx, u8 *dst,
-				       const u8 *src)
-{
-	__serpent_enc_blk_8way(ctx, dst, src, true);
-}
-
-static inline void serpent_dec_blk_xway(struct serpent_ctx *ctx, u8 *dst,
-				   const u8 *src)
-{
-	serpent_dec_blk_8way(ctx, dst, src);
-}
-
-#endif
-
-#endif
diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
index f483945..4f19a15 100644
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -31,12 +31,12 @@ static inline bool cpu_has_ht_siblings(void)
 	return has_siblings;
 }
 
-DECLARE_PER_CPU(cpumask_var_t, cpu_sibling_map);
-DECLARE_PER_CPU(cpumask_var_t, cpu_core_map);
+DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
+DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_core_map);
 /* cpus sharing the last level cache: */
-DECLARE_PER_CPU(cpumask_var_t, cpu_llc_shared_map);
-DECLARE_PER_CPU(u16, cpu_llc_id);
-DECLARE_PER_CPU(int, cpu_number);
+DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map);
+DECLARE_PER_CPU_READ_MOSTLY(u16, cpu_llc_id);
+DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
 
 static inline struct cpumask *cpu_sibling_mask(int cpu)
 {
@@ -53,10 +53,10 @@ static inline struct cpumask *cpu_llc_shared_mask(int cpu)
 	return per_cpu(cpu_llc_shared_map, cpu);
 }
 
-DECLARE_EARLY_PER_CPU(u16, x86_cpu_to_apicid);
-DECLARE_EARLY_PER_CPU(u16, x86_bios_cpu_apicid);
+DECLARE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_cpu_to_apicid);
+DECLARE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_bios_cpu_apicid);
 #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_32)
-DECLARE_EARLY_PER_CPU(int, x86_cpu_to_logical_apicid);
+DECLARE_EARLY_PER_CPU_READ_MOSTLY(int, x86_cpu_to_logical_apicid);
 #endif
 
 /* Static state in head.S used to set up a CPU */
@@ -169,11 +169,6 @@ void x86_idle_thread_init(unsigned int cpu, struct task_struct *idle);
 void smp_store_cpu_info(int id);
 #define cpu_physical_id(cpu)	per_cpu(x86_cpu_to_apicid, cpu)
 
-/* We don't mark CPUs online until __cpu_up(), so we need another measure */
-static inline int num_booting_cpus(void)
-{
-	return cpumask_weight(cpu_callout_mask);
-}
 #else /* !CONFIG_SMP */
 #define wbinvd_on_cpu(cpu)     wbinvd()
 static inline int wbinvd_on_all_cpus(void)
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index b315a33..33692ea 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -12,8 +12,7 @@
  * Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
  *
- * These are fair FIFO ticket locks, which are currently limited to 256
- * CPUs.
+ * These are fair FIFO ticket locks, which support up to 2^16 CPUs.
  *
  * (the type definitions are in asm/spinlock_types.h)
  */
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index 89f794f..c509d07 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -79,7 +79,6 @@ struct thread_info {
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_SINGLESTEP		4	/* reenable singlestep on user return*/
-#define TIF_IRET		5	/* force IRET */
 #define TIF_SYSCALL_EMU		6	/* syscall emulation active */
 #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
 #define TIF_SECCOMP		8	/* secure computing */
@@ -104,7 +103,6 @@ struct thread_info {
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
-#define _TIF_IRET		(1 << TIF_IRET)
 #define _TIF_SYSCALL_EMU	(1 << TIF_SYSCALL_EMU)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h
index 1e9bed1..f3971bb 100644
--- a/arch/x86/include/asm/uprobes.h
+++ b/arch/x86/include/asm/uprobes.h
@@ -48,7 +48,7 @@ struct arch_uprobe_task {
 #endif
 };
 
-extern int  arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm);
+extern int  arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr);
 extern int  arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs);
 extern int  arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
 extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h
index 6149b47..a06983c 100644
--- a/arch/x86/include/asm/uv/uv_bau.h
+++ b/arch/x86/include/asm/uv/uv_bau.h
@@ -140,6 +140,9 @@
 #define IPI_RESET_LIMIT			1
 /* after this # consecutive successes, bump up the throttle if it was lowered */
 #define COMPLETE_THRESHOLD		5
+/* after this # of giveups (fall back to kernel IPI's) disable the use of
+   the BAU for a period of time */
+#define GIVEUP_LIMIT			100
 
 #define UV_LB_SUBNODEID			0x10
 
@@ -166,7 +169,6 @@
 #define FLUSH_RETRY_TIMEOUT		2
 #define FLUSH_GIVEUP			3
 #define FLUSH_COMPLETE			4
-#define FLUSH_RETRY_BUSYBUG		5
 
 /*
  * tuning the action when the numalink network is extremely delayed
@@ -175,7 +177,7 @@
 						   microseconds */
 #define CONGESTED_REPS			10	/* long delays averaged over
 						   this many broadcasts */
-#define CONGESTED_PERIOD		30	/* time for the bau to be
+#define DISABLED_PERIOD			10	/* time for the bau to be
 						   disabled, in seconds */
 /* see msg_type: */
 #define MSG_NOOP			0
@@ -520,6 +522,12 @@ struct ptc_stats {
 	unsigned long	s_uv2_wars;		/* uv2 workaround, perm. busy */
 	unsigned long	s_uv2_wars_hw;		/* uv2 workaround, hiwater */
 	unsigned long	s_uv2_war_waits;	/* uv2 workaround, long waits */
+	unsigned long	s_overipilimit;		/* over the ipi reset limit */
+	unsigned long	s_giveuplimit;		/* disables, over giveup limit*/
+	unsigned long	s_enters;		/* entries to the driver */
+	unsigned long	s_ipifordisabled;	/* fall back to IPI; disabled */
+	unsigned long	s_plugged;		/* plugged by h/w bug*/
+	unsigned long	s_congested;		/* giveup on long wait */
 	/* destination statistics */
 	unsigned long	d_alltlb;		/* times all tlb's on this
 						   cpu were flushed */
@@ -586,8 +594,8 @@ struct bau_control {
 	int			timeout_tries;
 	int			ipi_attempts;
 	int			conseccompletes;
-	int			baudisabled;
-	int			set_bau_off;
+	short			nobau;
+	short			baudisabled;
 	short			cpu;
 	short			osnode;
 	short			uvhub_cpu;
@@ -596,14 +604,16 @@ struct bau_control {
 	short			cpus_in_socket;
 	short			cpus_in_uvhub;
 	short			partition_base_pnode;
-	short			using_desc; /* an index, like uvhub_cpu */
-	unsigned int		inuse_map;
+	short			busy;       /* all were busy (war) */
 	unsigned short		message_number;
 	unsigned short		uvhub_quiesce;
 	short			socket_acknowledge_count[DEST_Q_SIZE];
 	cycles_t		send_message;
+	cycles_t		period_end;
+	cycles_t		period_time;
 	spinlock_t		uvhub_lock;
 	spinlock_t		queue_lock;
+	spinlock_t		disable_lock;
 	/* tunables */
 	int			max_concurr;
 	int			max_concurr_const;
@@ -614,9 +624,9 @@ struct bau_control {
 	int			complete_threshold;
 	int			cong_response_us;
 	int			cong_reps;
-	int			cong_period;
-	unsigned long		clocks_per_100_usec;
-	cycles_t		period_time;
+	cycles_t		disabled_period;
+	int			period_giveups;
+	int			giveup_limit;
 	long			period_requests;
 	struct hub_and_pnode	*thp;
 };
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 31f180c..de007c2 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -404,6 +404,7 @@ enum vmcs_field {
 #define VMX_EPTP_WB_BIT				(1ull << 14)
 #define VMX_EPT_2MB_PAGE_BIT			(1ull << 16)
 #define VMX_EPT_1GB_PAGE_BIT			(1ull << 17)
+#define VMX_EPT_AD_BIT					(1ull << 21)
 #define VMX_EPT_EXTENT_INDIVIDUAL_BIT		(1ull << 24)
 #define VMX_EPT_EXTENT_CONTEXT_BIT		(1ull << 25)
 #define VMX_EPT_EXTENT_GLOBAL_BIT		(1ull << 26)
@@ -415,11 +416,14 @@ enum vmcs_field {
 #define VMX_EPT_MAX_GAW				0x4
 #define VMX_EPT_MT_EPTE_SHIFT			3
 #define VMX_EPT_GAW_EPTP_SHIFT			3
+#define VMX_EPT_AD_ENABLE_BIT			(1ull << 6)
 #define VMX_EPT_DEFAULT_MT			0x6ull
 #define VMX_EPT_READABLE_MASK			0x1ull
 #define VMX_EPT_WRITABLE_MASK			0x2ull
 #define VMX_EPT_EXECUTABLE_MASK			0x4ull
 #define VMX_EPT_IPAT_BIT    			(1ull << 6)
+#define VMX_EPT_ACCESS_BIT				(1ull << 8)
+#define VMX_EPT_DIRTY_BIT				(1ull << 9)
 
 #define VMX_EPT_IDENTITY_PAGETABLE_ADDR		0xfffbc000ul
 
diff --git a/arch/x86/include/asm/x2apic.h b/arch/x86/include/asm/x2apic.h
index 92e54ab..f90f0a5 100644
--- a/arch/x86/include/asm/x2apic.h
+++ b/arch/x86/include/asm/x2apic.h
@@ -9,15 +9,6 @@
 #include <asm/ipi.h>
 #include <linux/cpumask.h>
 
-/*
- * Need to use more than cpu 0, because we need more vectors
- * when MSI-X are used.
- */
-static const struct cpumask *x2apic_target_cpus(void)
-{
-	return cpu_online_mask;
-}
-
 static int x2apic_apic_id_valid(int apicid)
 {
 	return 1;
@@ -28,15 +19,6 @@ static int x2apic_apic_id_registered(void)
 	return 1;
 }
 
-/*
- * For now each logical cpu is in its own vector allocation domain.
- */
-static void x2apic_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-	cpumask_clear(retmask);
-	cpumask_set_cpu(cpu, retmask);
-}
-
 static void
 __x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest)
 {
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index c090af1..38155f6 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -156,7 +156,6 @@ struct x86_cpuinit_ops {
 /**
  * struct x86_platform_ops - platform specific runtime functions
  * @calibrate_tsc:		calibrate TSC
- * @wallclock_init:		init the wallclock device
  * @get_wallclock:		get time from HW clock like RTC etc.
  * @set_wallclock:		set time back to HW clock
  * @is_untracked_pat_range	exclude from PAT logic
@@ -164,10 +163,10 @@ struct x86_cpuinit_ops {
  * @i8042_detect		pre-detect if i8042 controller exists
  * @save_sched_clock_state:	save state for sched_clock() on suspend
  * @restore_sched_clock_state:	restore state for sched_clock() on resume
+ * @apic_post_init:		adjust apic if neeeded
  */
 struct x86_platform_ops {
 	unsigned long (*calibrate_tsc)(void);
-	void (*wallclock_init)(void);
 	unsigned long (*get_wallclock)(void);
 	int (*set_wallclock)(unsigned long nowtime);
 	void (*iommu_shutdown)(void);
@@ -177,6 +176,7 @@ struct x86_platform_ops {
 	int (*i8042_detect)(void);
 	void (*save_sched_clock_state)(void);
 	void (*restore_sched_clock_state)(void);
+	void (*apic_post_init)(void);
 };
 
 struct pci_dev;
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h
index 5728852..59c226d 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -48,6 +48,7 @@
 #include <xen/interface/sched.h>
 #include <xen/interface/physdev.h>
 #include <xen/interface/platform.h>
+#include <xen/interface/xen-mca.h>
 
 /*
  * The hypercall asms have to meet several constraints:
@@ -302,6 +303,13 @@ HYPERVISOR_set_timer_op(u64 timeout)
 }
 
 static inline int
+HYPERVISOR_mca(struct xen_mc *mc_op)
+{
+	mc_op->interface_version = XEN_MCA_INTERFACE_VERSION;
+	return _hypercall1(int, mca, mc_op);
+}
+
+static inline int
 HYPERVISOR_dom0_op(struct xen_platform_op *platform_op)
 {
 	platform_op->interface_version = XENPF_INTERFACE_VERSION;
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 8afb693..b2297e5 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -422,12 +422,14 @@ acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
 		return 0;
 	}
 
-	if (intsrc->source_irq == 0 && intsrc->global_irq == 2) {
+	if (intsrc->source_irq == 0) {
 		if (acpi_skip_timer_override) {
-			printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
+			printk(PREFIX "BIOS IRQ0 override ignored.\n");
 			return 0;
 		}
-		if (acpi_fix_pin2_polarity && (intsrc->inti_flags & ACPI_MADT_POLARITY_MASK)) {
+
+		if ((intsrc->global_irq == 2) && acpi_fix_pin2_polarity
+			&& (intsrc->inti_flags & ACPI_MADT_POLARITY_MASK)) {
 			intsrc->inti_flags &= ~ACPI_MADT_POLARITY_MASK;
 			printk(PREFIX "BIOS IRQ0 pin2 override: forcing polarity to high active.\n");
 		}
@@ -1334,17 +1336,12 @@ static int __init dmi_disable_acpi(const struct dmi_system_id *d)
 }
 
 /*
- * Force ignoring BIOS IRQ0 pin2 override
+ * Force ignoring BIOS IRQ0 override
  */
 static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
 {
-	/*
-	 * The ati_ixp4x0_rev() early PCI quirk should have set
-	 * the acpi_skip_timer_override flag already:
-	 */
 	if (!acpi_skip_timer_override) {
-		WARN(1, KERN_ERR "ati_ixp4x0 quirk not complete.\n");
-		pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n",
+		pr_notice("%s detected: Ignoring BIOS IRQ0 override\n",
 			d->ident);
 		acpi_skip_timer_override = 1;
 	}
@@ -1438,7 +1435,7 @@ static struct dmi_system_id __initdata acpi_dmi_table_late[] = {
 	 * is enabled.  This input is incorrectly designated the
 	 * ISA IRQ 0 via an interrupt source override even though
 	 * it is wired to the output of the master 8259A and INTIN0
-	 * is not connected at all.  Force ignoring BIOS IRQ0 pin2
+	 * is not connected at all.  Force ignoring BIOS IRQ0
 	 * override in that cases.
 	 */
 	{
@@ -1473,6 +1470,14 @@ static struct dmi_system_id __initdata acpi_dmi_table_late[] = {
 		     DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6715b"),
 		     },
 	 },
+	{
+	 .callback = dmi_ignore_irq0_timer_override,
+	 .ident = "FUJITSU SIEMENS",
+	 .matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"),
+		     },
+	 },
 	{}
 };
 
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 1f84794..931280f 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) "SMP alternatives: " fmt
+
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/mutex.h>
@@ -63,8 +65,11 @@ static int __init setup_noreplace_paravirt(char *str)
 __setup("noreplace-paravirt", setup_noreplace_paravirt);
 #endif
 
-#define DPRINTK(fmt, args...) if (debug_alternative) \
-	printk(KERN_DEBUG fmt, args)
+#define DPRINTK(fmt, ...)				\
+do {							\
+	if (debug_alternative)				\
+		printk(KERN_DEBUG fmt, ##__VA_ARGS__);	\
+} while (0)
 
 /*
  * Each GENERIC_NOPX is of X bytes, and defined as an array of bytes
@@ -428,7 +433,7 @@ void alternatives_smp_switch(int smp)
 	 * If this still occurs then you should see a hang
 	 * or crash shortly after this line:
 	 */
-	printk("lockdep: fixing up alternatives.\n");
+	pr_info("lockdep: fixing up alternatives\n");
 #endif
 
 	if (noreplace_smp || smp_alt_once || skip_smp_alternatives)
@@ -444,14 +449,14 @@ void alternatives_smp_switch(int smp)
 	if (smp == smp_mode) {
 		/* nothing */
 	} else if (smp) {
-		printk(KERN_INFO "SMP alternatives: switching to SMP code\n");
+		pr_info("switching to SMP code\n");
 		clear_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
 		clear_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
 		list_for_each_entry(mod, &smp_alt_modules, next)
 			alternatives_smp_lock(mod->locks, mod->locks_end,
 					      mod->text, mod->text_end);
 	} else {
-		printk(KERN_INFO "SMP alternatives: switching to UP code\n");
+		pr_info("switching to UP code\n");
 		set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
 		set_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
 		list_for_each_entry(mod, &smp_alt_modules, next)
@@ -546,7 +551,7 @@ void __init alternative_instructions(void)
 #ifdef CONFIG_SMP
 	if (smp_alt_once) {
 		if (1 == num_possible_cpus()) {
-			printk(KERN_INFO "SMP alternatives: switching to UP code\n");
+			pr_info("switching to UP code\n");
 			set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
 			set_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
 
@@ -664,7 +669,7 @@ static int __kprobes stop_machine_text_poke(void *data)
 	struct text_poke_param *p;
 	int i;
 
-	if (atomic_dec_and_test(&stop_machine_first)) {
+	if (atomic_xchg(&stop_machine_first, 0)) {
 		for (i = 0; i < tpp->nparams; i++) {
 			p = &tpp->params[i];
 			text_poke(p->addr, p->opcode, p->len);
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index be16854..aadf335 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -2,6 +2,9 @@
  * Shared support code for AMD K8 northbridges and derivates.
  * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -16,6 +19,7 @@ const struct pci_device_id amd_nb_misc_ids[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
 	{}
 };
 EXPORT_SYMBOL(amd_nb_misc_ids);
@@ -258,7 +262,7 @@ void amd_flush_garts(void)
 	}
 	spin_unlock_irqrestore(&gart_lock, flags);
 	if (!flushed)
-		printk("nothing to flush?\n");
+		pr_notice("nothing to flush?\n");
 }
 EXPORT_SYMBOL_GPL(amd_flush_garts);
 
@@ -269,11 +273,10 @@ static __init int init_amd_nbs(void)
 	err = amd_cache_northbridges();
 
 	if (err < 0)
-		printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
+		pr_notice("Cannot enumerate AMD northbridges\n");
 
 	if (amd_cache_gart() < 0)
-		printk(KERN_NOTICE "AMD NB: Cannot initialize GART flush words, "
-		       "GART support disabled.\n");
+		pr_notice("Cannot initialize GART flush words, GART support disabled\n");
 
 	return err;
 }
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 39a222e..563f68d 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -75,8 +75,8 @@ physid_mask_t phys_cpu_present_map;
 /*
  * Map cpu index to physical APIC ID
  */
-DEFINE_EARLY_PER_CPU(u16, x86_cpu_to_apicid, BAD_APICID);
-DEFINE_EARLY_PER_CPU(u16, x86_bios_cpu_apicid, BAD_APICID);
+DEFINE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_cpu_to_apicid, BAD_APICID);
+DEFINE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_bios_cpu_apicid, BAD_APICID);
 EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_apicid);
 EXPORT_EARLY_PER_CPU_SYMBOL(x86_bios_cpu_apicid);
 
@@ -88,7 +88,7 @@ EXPORT_EARLY_PER_CPU_SYMBOL(x86_bios_cpu_apicid);
  * used for the mapping.  This is where the behaviors of x86_64 and 32
  * actually diverge.  Let's keep it ugly for now.
  */
-DEFINE_EARLY_PER_CPU(int, x86_cpu_to_logical_apicid, BAD_APICID);
+DEFINE_EARLY_PER_CPU_READ_MOSTLY(int, x86_cpu_to_logical_apicid, BAD_APICID);
 
 /*
  * Knob to control our willingness to enable the local APIC.
@@ -2123,6 +2123,25 @@ void default_init_apic_ldr(void)
 	apic_write(APIC_LDR, val);
 }
 
+int default_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
+				   const struct cpumask *andmask,
+				   unsigned int *apicid)
+{
+	unsigned int cpu;
+
+	for_each_cpu_and(cpu, cpumask, andmask) {
+		if (cpumask_test_cpu(cpu, cpu_online_mask))
+			break;
+	}
+
+	if (likely(cpu < nr_cpu_ids)) {
+		*apicid = per_cpu(x86_cpu_to_apicid, cpu);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 /*
  * Power management
  */
diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c
index 0e881c4..00c77cf 100644
--- a/arch/x86/kernel/apic/apic_flat_64.c
+++ b/arch/x86/kernel/apic/apic_flat_64.c
@@ -36,25 +36,6 @@ static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 	return 1;
 }
 
-static const struct cpumask *flat_target_cpus(void)
-{
-	return cpu_online_mask;
-}
-
-static void flat_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-	/* Careful. Some cpus do not strictly honor the set of cpus
-	 * specified in the interrupt destination when using lowest
-	 * priority interrupt delivery mode.
-	 *
-	 * In particular there was a hyperthreading cpu observed to
-	 * deliver interrupts to the wrong hyperthread when only one
-	 * hyperthread was specified in the interrupt desitination.
-	 */
-	cpumask_clear(retmask);
-	cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
-}
-
 /*
  * Set up the logical destination ID.
  *
@@ -92,7 +73,7 @@ static void flat_send_IPI_mask(const struct cpumask *cpumask, int vector)
 }
 
 static void
- flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector)
+flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector)
 {
 	unsigned long mask = cpumask_bits(cpumask)[0];
 	int cpu = smp_processor_id();
@@ -186,7 +167,7 @@ static struct apic apic_flat =  {
 	.irq_delivery_mode		= dest_LowestPrio,
 	.irq_dest_mode			= 1, /* logical */
 
-	.target_cpus			= flat_target_cpus,
+	.target_cpus			= online_target_cpus,
 	.disable_esr			= 0,
 	.dest_logical			= APIC_DEST_LOGICAL,
 	.check_apicid_used		= NULL,
@@ -210,8 +191,7 @@ static struct apic apic_flat =  {
 	.set_apic_id			= set_apic_id,
 	.apic_id_mask			= 0xFFu << 24,
 
-	.cpu_mask_to_apicid		= default_cpu_mask_to_apicid,
-	.cpu_mask_to_apicid_and		= default_cpu_mask_to_apicid_and,
+	.cpu_mask_to_apicid_and		= flat_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= flat_send_IPI_mask,
 	.send_IPI_mask_allbutself	= flat_send_IPI_mask_allbutself,
@@ -262,17 +242,6 @@ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 	return 0;
 }
 
-static const struct cpumask *physflat_target_cpus(void)
-{
-	return cpu_online_mask;
-}
-
-static void physflat_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-	cpumask_clear(retmask);
-	cpumask_set_cpu(cpu, retmask);
-}
-
 static void physflat_send_IPI_mask(const struct cpumask *cpumask, int vector)
 {
 	default_send_IPI_mask_sequence_phys(cpumask, vector);
@@ -294,38 +263,6 @@ static void physflat_send_IPI_all(int vector)
 	physflat_send_IPI_mask(cpu_online_mask, vector);
 }
 
-static unsigned int physflat_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-	int cpu;
-
-	/*
-	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
-	 * May as well be the first.
-	 */
-	cpu = cpumask_first(cpumask);
-	if ((unsigned)cpu < nr_cpu_ids)
-		return per_cpu(x86_cpu_to_apicid, cpu);
-	else
-		return BAD_APICID;
-}
-
-static unsigned int
-physflat_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-				const struct cpumask *andmask)
-{
-	int cpu;
-
-	/*
-	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
-	 * May as well be the first.
-	 */
-	for_each_cpu_and(cpu, cpumask, andmask) {
-		if (cpumask_test_cpu(cpu, cpu_online_mask))
-			break;
-	}
-	return per_cpu(x86_cpu_to_apicid, cpu);
-}
-
 static int physflat_probe(void)
 {
 	if (apic == &apic_physflat || num_possible_cpus() > 8)
@@ -345,13 +282,13 @@ static struct apic apic_physflat =  {
 	.irq_delivery_mode		= dest_Fixed,
 	.irq_dest_mode			= 0, /* physical */
 
-	.target_cpus			= physflat_target_cpus,
+	.target_cpus			= online_target_cpus,
 	.disable_esr			= 0,
 	.dest_logical			= 0,
 	.check_apicid_used		= NULL,
 	.check_apicid_present		= NULL,
 
-	.vector_allocation_domain	= physflat_vector_allocation_domain,
+	.vector_allocation_domain	= default_vector_allocation_domain,
 	/* not needed, but shouldn't hurt: */
 	.init_apic_ldr			= flat_init_apic_ldr,
 
@@ -370,8 +307,7 @@ static struct apic apic_physflat =  {
 	.set_apic_id			= set_apic_id,
 	.apic_id_mask			= 0xFFu << 24,
 
-	.cpu_mask_to_apicid		= physflat_cpu_mask_to_apicid,
-	.cpu_mask_to_apicid_and		= physflat_cpu_mask_to_apicid_and,
+	.cpu_mask_to_apicid_and		= default_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= physflat_send_IPI_mask,
 	.send_IPI_mask_allbutself	= physflat_send_IPI_mask_allbutself,
diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c
index a6e4c6e..65c07fc 100644
--- a/arch/x86/kernel/apic/apic_noop.c
+++ b/arch/x86/kernel/apic/apic_noop.c
@@ -100,12 +100,12 @@ static unsigned long noop_check_apicid_present(int bit)
 	return physid_isset(bit, phys_cpu_present_map);
 }
 
-static void noop_vector_allocation_domain(int cpu, struct cpumask *retmask)
+static bool noop_vector_allocation_domain(int cpu, struct cpumask *retmask)
 {
 	if (cpu != 0)
 		pr_warning("APIC: Vector allocated for non-BSP cpu\n");
-	cpumask_clear(retmask);
-	cpumask_set_cpu(cpu, retmask);
+	cpumask_copy(retmask, cpumask_of(cpu));
+	return true;
 }
 
 static u32 noop_apic_read(u32 reg)
@@ -159,8 +159,7 @@ struct apic apic_noop = {
 	.set_apic_id			= NULL,
 	.apic_id_mask			= 0x0F << 24,
 
-	.cpu_mask_to_apicid		= default_cpu_mask_to_apicid,
-	.cpu_mask_to_apicid_and		= default_cpu_mask_to_apicid_and,
+	.cpu_mask_to_apicid_and		= flat_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= noop_send_IPI_mask,
 	.send_IPI_mask_allbutself	= noop_send_IPI_mask_allbutself,
diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c
index 6ec6d5d..bc552cf 100644
--- a/arch/x86/kernel/apic/apic_numachip.c
+++ b/arch/x86/kernel/apic/apic_numachip.c
@@ -72,17 +72,6 @@ static int numachip_phys_pkg_id(int initial_apic_id, int index_msb)
 	return initial_apic_id >> index_msb;
 }
 
-static const struct cpumask *numachip_target_cpus(void)
-{
-	return cpu_online_mask;
-}
-
-static void numachip_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-	cpumask_clear(retmask);
-	cpumask_set_cpu(cpu, retmask);
-}
-
 static int __cpuinit numachip_wakeup_secondary(int phys_apicid, unsigned long start_rip)
 {
 	union numachip_csr_g3_ext_irq_gen int_gen;
@@ -157,38 +146,6 @@ static void numachip_send_IPI_self(int vector)
 	__default_send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
 }
 
-static unsigned int numachip_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-	int cpu;
-
-	/*
-	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
-	 * May as well be the first.
-	 */
-	cpu = cpumask_first(cpumask);
-	if (likely((unsigned)cpu < nr_cpu_ids))
-		return per_cpu(x86_cpu_to_apicid, cpu);
-
-	return BAD_APICID;
-}
-
-static unsigned int
-numachip_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-				const struct cpumask *andmask)
-{
-	int cpu;
-
-	/*
-	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
-	 * May as well be the first.
-	 */
-	for_each_cpu_and(cpu, cpumask, andmask) {
-		if (cpumask_test_cpu(cpu, cpu_online_mask))
-			break;
-	}
-	return per_cpu(x86_cpu_to_apicid, cpu);
-}
-
 static int __init numachip_probe(void)
 {
 	return apic == &apic_numachip;
@@ -253,13 +210,13 @@ static struct apic apic_numachip __refconst = {
 	.irq_delivery_mode		= dest_Fixed,
 	.irq_dest_mode			= 0, /* physical */
 
-	.target_cpus			= numachip_target_cpus,
+	.target_cpus			= online_target_cpus,
 	.disable_esr			= 0,
 	.dest_logical			= 0,
 	.check_apicid_used		= NULL,
 	.check_apicid_present		= NULL,
 
-	.vector_allocation_domain	= numachip_vector_allocation_domain,
+	.vector_allocation_domain	= default_vector_allocation_domain,
 	.init_apic_ldr			= flat_init_apic_ldr,
 
 	.ioapic_phys_id_map		= NULL,
@@ -277,8 +234,7 @@ static struct apic apic_numachip __refconst = {
 	.set_apic_id			= set_apic_id,
 	.apic_id_mask			= 0xffU << 24,
 
-	.cpu_mask_to_apicid		= numachip_cpu_mask_to_apicid,
-	.cpu_mask_to_apicid_and		= numachip_cpu_mask_to_apicid_and,
+	.cpu_mask_to_apicid_and		= default_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= numachip_send_IPI_mask,
 	.send_IPI_mask_allbutself	= numachip_send_IPI_mask_allbutself,
diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c
index 31fbdbf..d50e364 100644
--- a/arch/x86/kernel/apic/bigsmp_32.c
+++ b/arch/x86/kernel/apic/bigsmp_32.c
@@ -26,15 +26,6 @@ static int bigsmp_apic_id_registered(void)
 	return 1;
 }
 
-static const struct cpumask *bigsmp_target_cpus(void)
-{
-#ifdef CONFIG_SMP
-	return cpu_online_mask;
-#else
-	return cpumask_of(0);
-#endif
-}
-
 static unsigned long bigsmp_check_apicid_used(physid_mask_t *map, int apicid)
 {
 	return 0;
@@ -105,32 +96,6 @@ static int bigsmp_check_phys_apicid_present(int phys_apicid)
 	return 1;
 }
 
-/* As we are using single CPU as destination, pick only one CPU here */
-static unsigned int bigsmp_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-	int cpu = cpumask_first(cpumask);
-
-	if (cpu < nr_cpu_ids)
-		return cpu_physical_id(cpu);
-	return BAD_APICID;
-}
-
-static unsigned int bigsmp_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-			      const struct cpumask *andmask)
-{
-	int cpu;
-
-	/*
-	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
-	 * May as well be the first.
-	 */
-	for_each_cpu_and(cpu, cpumask, andmask) {
-		if (cpumask_test_cpu(cpu, cpu_online_mask))
-			return cpu_physical_id(cpu);
-	}
-	return BAD_APICID;
-}
-
 static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)
 {
 	return cpuid_apic >> index_msb;
@@ -177,12 +142,6 @@ static const struct dmi_system_id bigsmp_dmi_table[] = {
 	{ } /* NULL entry stops DMI scanning */
 };
 
-static void bigsmp_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-	cpumask_clear(retmask);
-	cpumask_set_cpu(cpu, retmask);
-}
-
 static int probe_bigsmp(void)
 {
 	if (def_to_bigsmp)
@@ -205,13 +164,13 @@ static struct apic apic_bigsmp = {
 	/* phys delivery to target CPU: */
 	.irq_dest_mode			= 0,
 
-	.target_cpus			= bigsmp_target_cpus,
+	.target_cpus			= default_target_cpus,
 	.disable_esr			= 1,
 	.dest_logical			= 0,
 	.check_apicid_used		= bigsmp_check_apicid_used,
 	.check_apicid_present		= bigsmp_check_apicid_present,
 
-	.vector_allocation_domain	= bigsmp_vector_allocation_domain,
+	.vector_allocation_domain	= default_vector_allocation_domain,
 	.init_apic_ldr			= bigsmp_init_apic_ldr,
 
 	.ioapic_phys_id_map		= bigsmp_ioapic_phys_id_map,
@@ -229,8 +188,7 @@ static struct apic apic_bigsmp = {
 	.set_apic_id			= NULL,
 	.apic_id_mask			= 0xFF << 24,
 
-	.cpu_mask_to_apicid		= bigsmp_cpu_mask_to_apicid,
-	.cpu_mask_to_apicid_and		= bigsmp_cpu_mask_to_apicid_and,
+	.cpu_mask_to_apicid_and		= default_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= bigsmp_send_IPI_mask,
 	.send_IPI_mask_allbutself	= NULL,
diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c
index db4ab1b..0874799 100644
--- a/arch/x86/kernel/apic/es7000_32.c
+++ b/arch/x86/kernel/apic/es7000_32.c
@@ -394,21 +394,6 @@ static void es7000_enable_apic_mode(void)
 		WARN(1, "Command failed, status = %x\n", mip_status);
 }
 
-static void es7000_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-	/* Careful. Some cpus do not strictly honor the set of cpus
-	 * specified in the interrupt destination when using lowest
-	 * priority interrupt delivery mode.
-	 *
-	 * In particular there was a hyperthreading cpu observed to
-	 * deliver interrupts to the wrong hyperthread when only one
-	 * hyperthread was specified in the interrupt desitination.
-	 */
-	cpumask_clear(retmask);
-	cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
-}
-
-
 static void es7000_wait_for_init_deassert(atomic_t *deassert)
 {
 	while (!atomic_read(deassert))
@@ -540,45 +525,49 @@ static int es7000_check_phys_apicid_present(int cpu_physical_apicid)
 	return 1;
 }
 
-static unsigned int es7000_cpu_mask_to_apicid(const struct cpumask *cpumask)
+static inline int
+es7000_cpu_mask_to_apicid(const struct cpumask *cpumask, unsigned int *dest_id)
 {
 	unsigned int round = 0;
-	int cpu, uninitialized_var(apicid);
+	unsigned int cpu, uninitialized_var(apicid);
 
 	/*
 	 * The cpus in the mask must all be on the apic cluster.
 	 */
-	for_each_cpu(cpu, cpumask) {
+	for_each_cpu_and(cpu, cpumask, cpu_online_mask) {
 		int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
 
 		if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) {
 			WARN(1, "Not a valid mask!");
 
-			return BAD_APICID;
+			return -EINVAL;
 		}
-		apicid = new_apicid;
+		apicid |= new_apicid;
 		round++;
 	}
-	return apicid;
+	if (!round)
+		return -EINVAL;
+	*dest_id = apicid;
+	return 0;
 }
 
-static unsigned int
+static int
 es7000_cpu_mask_to_apicid_and(const struct cpumask *inmask,
-			      const struct cpumask *andmask)
+			      const struct cpumask *andmask,
+			      unsigned int *apicid)
 {
-	int apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
 	cpumask_var_t cpumask;
+	*apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
 
 	if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
-		return apicid;
+		return 0;
 
 	cpumask_and(cpumask, inmask, andmask);
-	cpumask_and(cpumask, cpumask, cpu_online_mask);
-	apicid = es7000_cpu_mask_to_apicid(cpumask);
+	es7000_cpu_mask_to_apicid(cpumask, apicid);
 
 	free_cpumask_var(cpumask);
 
-	return apicid;
+	return 0;
 }
 
 static int es7000_phys_pkg_id(int cpuid_apic, int index_msb)
@@ -638,7 +627,7 @@ static struct apic __refdata apic_es7000_cluster = {
 	.check_apicid_used		= es7000_check_apicid_used,
 	.check_apicid_present		= es7000_check_apicid_present,
 
-	.vector_allocation_domain	= es7000_vector_allocation_domain,
+	.vector_allocation_domain	= flat_vector_allocation_domain,
 	.init_apic_ldr			= es7000_init_apic_ldr_cluster,
 
 	.ioapic_phys_id_map		= es7000_ioapic_phys_id_map,
@@ -656,7 +645,6 @@ static struct apic __refdata apic_es7000_cluster = {
 	.set_apic_id			= NULL,
 	.apic_id_mask			= 0xFF << 24,
 
-	.cpu_mask_to_apicid		= es7000_cpu_mask_to_apicid,
 	.cpu_mask_to_apicid_and		= es7000_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= es7000_send_IPI_mask,
@@ -705,7 +693,7 @@ static struct apic __refdata apic_es7000 = {
 	.check_apicid_used		= es7000_check_apicid_used,
 	.check_apicid_present		= es7000_check_apicid_present,
 
-	.vector_allocation_domain	= es7000_vector_allocation_domain,
+	.vector_allocation_domain	= flat_vector_allocation_domain,
 	.init_apic_ldr			= es7000_init_apic_ldr,
 
 	.ioapic_phys_id_map		= es7000_ioapic_phys_id_map,
@@ -723,7 +711,6 @@ static struct apic __refdata apic_es7000 = {
 	.set_apic_id			= NULL,
 	.apic_id_mask			= 0xFF << 24,
 
-	.cpu_mask_to_apicid		= es7000_cpu_mask_to_apicid,
 	.cpu_mask_to_apicid_and		= es7000_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= es7000_send_IPI_mask,
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 5f0ff59..99a794d 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -448,8 +448,8 @@ static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pi
 
 	entry = alloc_irq_pin_list(node);
 	if (!entry) {
-		printk(KERN_ERR "can not alloc irq_pin_list (%d,%d,%d)\n",
-				node, apic, pin);
+		pr_err("can not alloc irq_pin_list (%d,%d,%d)\n",
+		       node, apic, pin);
 		return -ENOMEM;
 	}
 	entry->apic = apic;
@@ -661,7 +661,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 	ioapic_mask_entry(apic, pin);
 	entry = ioapic_read_entry(apic, pin);
 	if (entry.irr)
-		printk(KERN_ERR "Unable to reset IRR for apic: %d, pin :%d\n",
+		pr_err("Unable to reset IRR for apic: %d, pin :%d\n",
 		       mpc_ioapic_id(apic), pin);
 }
 
@@ -895,7 +895,7 @@ static int irq_polarity(int idx)
 		}
 		case 2: /* reserved */
 		{
-			printk(KERN_WARNING "broken BIOS!!\n");
+			pr_warn("broken BIOS!!\n");
 			polarity = 1;
 			break;
 		}
@@ -906,7 +906,7 @@ static int irq_polarity(int idx)
 		}
 		default: /* invalid */
 		{
-			printk(KERN_WARNING "broken BIOS!!\n");
+			pr_warn("broken BIOS!!\n");
 			polarity = 1;
 			break;
 		}
@@ -948,7 +948,7 @@ static int irq_trigger(int idx)
 				}
 				default:
 				{
-					printk(KERN_WARNING "broken BIOS!!\n");
+					pr_warn("broken BIOS!!\n");
 					trigger = 1;
 					break;
 				}
@@ -962,7 +962,7 @@ static int irq_trigger(int idx)
 		}
 		case 2: /* reserved */
 		{
-			printk(KERN_WARNING "broken BIOS!!\n");
+			pr_warn("broken BIOS!!\n");
 			trigger = 1;
 			break;
 		}
@@ -973,7 +973,7 @@ static int irq_trigger(int idx)
 		}
 		default: /* invalid */
 		{
-			printk(KERN_WARNING "broken BIOS!!\n");
+			pr_warn("broken BIOS!!\n");
 			trigger = 0;
 			break;
 		}
@@ -991,7 +991,7 @@ static int pin_2_irq(int idx, int apic, int pin)
 	 * Debugging check, we are in big trouble if this message pops up!
 	 */
 	if (mp_irqs[idx].dstirq != pin)
-		printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
+		pr_err("broken BIOS or MPTABLE parser, ayiee!!\n");
 
 	if (test_bit(bus, mp_bus_not_pci)) {
 		irq = mp_irqs[idx].srcbusirq;
@@ -1112,7 +1112,7 @@ __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
 	 * 0x80, because int 0x80 is hm, kind of importantish. ;)
 	 */
 	static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
-	static int current_offset = VECTOR_OFFSET_START % 8;
+	static int current_offset = VECTOR_OFFSET_START % 16;
 	unsigned int old_vector;
 	int cpu, err;
 	cpumask_var_t tmp_mask;
@@ -1126,8 +1126,7 @@ __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
 	old_vector = cfg->vector;
 	if (old_vector) {
 		cpumask_and(tmp_mask, mask, cpu_online_mask);
-		cpumask_and(tmp_mask, cfg->domain, tmp_mask);
-		if (!cpumask_empty(tmp_mask)) {
+		if (cpumask_subset(tmp_mask, cfg->domain)) {
 			free_cpumask_var(tmp_mask);
 			return 0;
 		}
@@ -1138,20 +1137,30 @@ __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
 	for_each_cpu_and(cpu, mask, cpu_online_mask) {
 		int new_cpu;
 		int vector, offset;
+		bool more_domains;
 
-		apic->vector_allocation_domain(cpu, tmp_mask);
+		more_domains = apic->vector_allocation_domain(cpu, tmp_mask);
+
+		if (cpumask_subset(tmp_mask, cfg->domain)) {
+			free_cpumask_var(tmp_mask);
+			return 0;
+		}
 
 		vector = current_vector;
 		offset = current_offset;
 next:
-		vector += 8;
+		vector += 16;
 		if (vector >= first_system_vector) {
-			/* If out of vectors on large boxen, must share them. */
-			offset = (offset + 1) % 8;
+			offset = (offset + 1) % 16;
 			vector = FIRST_EXTERNAL_VECTOR + offset;
 		}
-		if (unlikely(current_vector == vector))
-			continue;
+
+		if (unlikely(current_vector == vector)) {
+			if (more_domains)
+				continue;
+			else
+				break;
+		}
 
 		if (test_bit(vector, used_vectors))
 			goto next;
@@ -1346,18 +1355,18 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
 
 	if (!IO_APIC_IRQ(irq))
 		return;
-	/*
-	 * For legacy irqs, cfg->domain starts with cpu 0 for legacy
-	 * controllers like 8259. Now that IO-APIC can handle this irq, update
-	 * the cfg->domain.
-	 */
-	if (irq < legacy_pic->nr_legacy_irqs && cpumask_test_cpu(0, cfg->domain))
-		apic->vector_allocation_domain(0, cfg->domain);
 
 	if (assign_irq_vector(irq, cfg, apic->target_cpus()))
 		return;
 
-	dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus());
+	if (apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus(),
+					 &dest)) {
+		pr_warn("Failed to obtain apicid for ioapic %d, pin %d\n",
+			mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
+		__clear_irq_vector(irq, cfg);
+
+		return;
+	}
 
 	apic_printk(APIC_VERBOSE,KERN_DEBUG
 		    "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> "
@@ -1366,7 +1375,7 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
 		    cfg->vector, irq, attr->trigger, attr->polarity, dest);
 
 	if (setup_ioapic_entry(irq, &entry, dest, cfg->vector, attr)) {
-		pr_warn("Failed to setup ioapic entry for ioapic  %d, pin %d\n",
+		pr_warn("Failed to setup ioapic entry for ioapic %d, pin %d\n",
 			mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
 		__clear_irq_vector(irq, cfg);
 
@@ -1469,9 +1478,10 @@ void setup_IO_APIC_irq_extra(u32 gsi)
  * Set up the timer pin, possibly with the 8259A-master behind.
  */
 static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
-					 unsigned int pin, int vector)
+					unsigned int pin, int vector)
 {
 	struct IO_APIC_route_entry entry;
+	unsigned int dest;
 
 	if (irq_remapping_enabled)
 		return;
@@ -1482,9 +1492,13 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
 	 * We use logical delivery to get the timer IRQ
 	 * to the first CPU.
 	 */
+	if (unlikely(apic->cpu_mask_to_apicid_and(apic->target_cpus(),
+						  apic->target_cpus(), &dest)))
+		dest = BAD_APICID;
+
 	entry.dest_mode = apic->irq_dest_mode;
 	entry.mask = 0;			/* don't mask IRQ for edge */
-	entry.dest = apic->cpu_mask_to_apicid(apic->target_cpus());
+	entry.dest = dest;
 	entry.delivery_mode = apic->irq_delivery_mode;
 	entry.polarity = 0;
 	entry.trigger = 0;
@@ -1521,7 +1535,6 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
 		reg_03.raw = io_apic_read(ioapic_idx, 3);
 	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 
-	printk("\n");
 	printk(KERN_DEBUG "IO APIC #%d......\n", mpc_ioapic_id(ioapic_idx));
 	printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
 	printk(KERN_DEBUG ".......    : physical APIC id: %02X\n", reg_00.bits.ID);
@@ -1578,7 +1591,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
 				i,
 				ir_entry->index
 			);
-			printk("%1d   %1d    %1d    %1d   %1d   "
+			pr_cont("%1d   %1d    %1d    %1d   %1d   "
 				"%1d    %1d     %X    %02X\n",
 				ir_entry->format,
 				ir_entry->mask,
@@ -1598,7 +1611,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
 				i,
 				entry.dest
 			);
-			printk("%1d    %1d    %1d   %1d   %1d    "
+			pr_cont("%1d    %1d    %1d   %1d   %1d    "
 				"%1d    %1d    %02X\n",
 				entry.mask,
 				entry.trigger,
@@ -1651,8 +1664,8 @@ __apicdebuginit(void) print_IO_APICs(void)
 			continue;
 		printk(KERN_DEBUG "IRQ%d ", irq);
 		for_each_irq_pin(entry, cfg->irq_2_pin)
-			printk("-> %d:%d", entry->apic, entry->pin);
-		printk("\n");
+			pr_cont("-> %d:%d", entry->apic, entry->pin);
+		pr_cont("\n");
 	}
 
 	printk(KERN_INFO ".................................... done.\n");
@@ -1665,9 +1678,9 @@ __apicdebuginit(void) print_APIC_field(int base)
 	printk(KERN_DEBUG);
 
 	for (i = 0; i < 8; i++)
-		printk(KERN_CONT "%08x", apic_read(base + i*0x10));
+		pr_cont("%08x", apic_read(base + i*0x10));
 
-	printk(KERN_CONT "\n");
+	pr_cont("\n");
 }
 
 __apicdebuginit(void) print_local_APIC(void *dummy)
@@ -1769,7 +1782,7 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
 			printk(KERN_DEBUG "... APIC EILVT%d: %08x\n", i, v);
 		}
 	}
-	printk("\n");
+	pr_cont("\n");
 }
 
 __apicdebuginit(void) print_local_APICs(int maxcpu)
@@ -2065,7 +2078,7 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
 		reg_00.raw = io_apic_read(ioapic_idx, 0);
 		raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 		if (reg_00.bits.ID != mpc_ioapic_id(ioapic_idx))
-			printk("could not set ID!\n");
+			pr_cont("could not set ID!\n");
 		else
 			apic_printk(APIC_VERBOSE, " ok.\n");
 	}
@@ -2210,71 +2223,6 @@ void send_cleanup_vector(struct irq_cfg *cfg)
 	cfg->move_in_progress = 0;
 }
 
-static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
-{
-	int apic, pin;
-	struct irq_pin_list *entry;
-	u8 vector = cfg->vector;
-
-	for_each_irq_pin(entry, cfg->irq_2_pin) {
-		unsigned int reg;
-
-		apic = entry->apic;
-		pin = entry->pin;
-		/*
-		 * With interrupt-remapping, destination information comes
-		 * from interrupt-remapping table entry.
-		 */
-		if (!irq_remapped(cfg))
-			io_apic_write(apic, 0x11 + pin*2, dest);
-		reg = io_apic_read(apic, 0x10 + pin*2);
-		reg &= ~IO_APIC_REDIR_VECTOR_MASK;
-		reg |= vector;
-		io_apic_modify(apic, 0x10 + pin*2, reg);
-	}
-}
-
-/*
- * Either sets data->affinity to a valid value, and returns
- * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and
- * leaves data->affinity untouched.
- */
-int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
-			  unsigned int *dest_id)
-{
-	struct irq_cfg *cfg = data->chip_data;
-
-	if (!cpumask_intersects(mask, cpu_online_mask))
-		return -1;
-
-	if (assign_irq_vector(data->irq, data->chip_data, mask))
-		return -1;
-
-	cpumask_copy(data->affinity, mask);
-
-	*dest_id = apic->cpu_mask_to_apicid_and(mask, cfg->domain);
-	return 0;
-}
-
-static int
-ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
-		    bool force)
-{
-	unsigned int dest, irq = data->irq;
-	unsigned long flags;
-	int ret;
-
-	raw_spin_lock_irqsave(&ioapic_lock, flags);
-	ret = __ioapic_set_affinity(data, mask, &dest);
-	if (!ret) {
-		/* Only the high 8 bits are valid. */
-		dest = SET_APIC_LOGICAL_ID(dest);
-		__target_IO_APIC_irq(irq, dest, data->chip_data);
-	}
-	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
-	return ret;
-}
-
 asmlinkage void smp_irq_move_cleanup_interrupt(void)
 {
 	unsigned vector, me;
@@ -2362,6 +2310,87 @@ void irq_force_complete_move(int irq)
 static inline void irq_complete_move(struct irq_cfg *cfg) { }
 #endif
 
+static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
+{
+	int apic, pin;
+	struct irq_pin_list *entry;
+	u8 vector = cfg->vector;
+
+	for_each_irq_pin(entry, cfg->irq_2_pin) {
+		unsigned int reg;
+
+		apic = entry->apic;
+		pin = entry->pin;
+		/*
+		 * With interrupt-remapping, destination information comes
+		 * from interrupt-remapping table entry.
+		 */
+		if (!irq_remapped(cfg))
+			io_apic_write(apic, 0x11 + pin*2, dest);
+		reg = io_apic_read(apic, 0x10 + pin*2);
+		reg &= ~IO_APIC_REDIR_VECTOR_MASK;
+		reg |= vector;
+		io_apic_modify(apic, 0x10 + pin*2, reg);
+	}
+}
+
+/*
+ * Either sets data->affinity to a valid value, and returns
+ * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and
+ * leaves data->affinity untouched.
+ */
+int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+			  unsigned int *dest_id)
+{
+	struct irq_cfg *cfg = data->chip_data;
+	unsigned int irq = data->irq;
+	int err;
+
+	if (!config_enabled(CONFIG_SMP))
+		return -1;
+
+	if (!cpumask_intersects(mask, cpu_online_mask))
+		return -EINVAL;
+
+	err = assign_irq_vector(irq, cfg, mask);
+	if (err)
+		return err;
+
+	err = apic->cpu_mask_to_apicid_and(mask, cfg->domain, dest_id);
+	if (err) {
+		if (assign_irq_vector(irq, cfg, data->affinity))
+			pr_err("Failed to recover vector for irq %d\n", irq);
+		return err;
+	}
+
+	cpumask_copy(data->affinity, mask);
+
+	return 0;
+}
+
+static int
+ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+		    bool force)
+{
+	unsigned int dest, irq = data->irq;
+	unsigned long flags;
+	int ret;
+
+	if (!config_enabled(CONFIG_SMP))
+		return -1;
+
+	raw_spin_lock_irqsave(&ioapic_lock, flags);
+	ret = __ioapic_set_affinity(data, mask, &dest);
+	if (!ret) {
+		/* Only the high 8 bits are valid. */
+		dest = SET_APIC_LOGICAL_ID(dest);
+		__target_IO_APIC_irq(irq, dest, data->chip_data);
+		ret = IRQ_SET_MASK_OK_NOCOPY;
+	}
+	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+	return ret;
+}
+
 static void ack_apic_edge(struct irq_data *data)
 {
 	irq_complete_move(data->chip_data);
@@ -2541,9 +2570,7 @@ static void irq_remap_modify_chip_defaults(struct irq_chip *chip)
 	chip->irq_ack = ir_ack_apic_edge;
 	chip->irq_eoi = ir_ack_apic_level;
 
-#ifdef CONFIG_SMP
 	chip->irq_set_affinity = set_remapped_irq_affinity;
-#endif
 }
 #endif /* CONFIG_IRQ_REMAP */
 
@@ -2554,9 +2581,7 @@ static struct irq_chip ioapic_chip __read_mostly = {
 	.irq_unmask		= unmask_ioapic_irq,
 	.irq_ack		= ack_apic_edge,
 	.irq_eoi		= ack_apic_level,
-#ifdef CONFIG_SMP
 	.irq_set_affinity	= ioapic_set_affinity,
-#endif
 	.irq_retrigger		= ioapic_retrigger_irq,
 };
 
@@ -3038,7 +3063,10 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
 	if (err)
 		return err;
 
-	dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus());
+	err = apic->cpu_mask_to_apicid_and(cfg->domain,
+					   apic->target_cpus(), &dest);
+	if (err)
+		return err;
 
 	if (irq_remapped(cfg)) {
 		compose_remapped_msi_msg(pdev, irq, dest, msg, hpet_id);
@@ -3072,7 +3100,6 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
 	return err;
 }
 
-#ifdef CONFIG_SMP
 static int
 msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
 {
@@ -3092,9 +3119,8 @@ msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
 
 	__write_msi_msg(data->msi_desc, &msg);
 
-	return 0;
+	return IRQ_SET_MASK_OK_NOCOPY;
 }
-#endif /* CONFIG_SMP */
 
 /*
  * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
@@ -3105,9 +3131,7 @@ static struct irq_chip msi_chip = {
 	.irq_unmask		= unmask_msi_irq,
 	.irq_mask		= mask_msi_irq,
 	.irq_ack		= ack_apic_edge,
-#ifdef CONFIG_SMP
 	.irq_set_affinity	= msi_set_affinity,
-#endif
 	.irq_retrigger		= ioapic_retrigger_irq,
 };
 
@@ -3192,7 +3216,6 @@ void native_teardown_msi_irq(unsigned int irq)
 }
 
 #ifdef CONFIG_DMAR_TABLE
-#ifdef CONFIG_SMP
 static int
 dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
 		      bool force)
@@ -3214,19 +3237,15 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
 
 	dmar_msi_write(irq, &msg);
 
-	return 0;
+	return IRQ_SET_MASK_OK_NOCOPY;
 }
 
-#endif /* CONFIG_SMP */
-
 static struct irq_chip dmar_msi_type = {
 	.name			= "DMAR_MSI",
 	.irq_unmask		= dmar_msi_unmask,
 	.irq_mask		= dmar_msi_mask,
 	.irq_ack		= ack_apic_edge,
-#ifdef CONFIG_SMP
 	.irq_set_affinity	= dmar_msi_set_affinity,
-#endif
 	.irq_retrigger		= ioapic_retrigger_irq,
 };
 
@@ -3247,7 +3266,6 @@ int arch_setup_dmar_msi(unsigned int irq)
 
 #ifdef CONFIG_HPET_TIMER
 
-#ifdef CONFIG_SMP
 static int hpet_msi_set_affinity(struct irq_data *data,
 				 const struct cpumask *mask, bool force)
 {
@@ -3267,19 +3285,15 @@ static int hpet_msi_set_affinity(struct irq_data *data,
 
 	hpet_msi_write(data->handler_data, &msg);
 
-	return 0;
+	return IRQ_SET_MASK_OK_NOCOPY;
 }
 
-#endif /* CONFIG_SMP */
-
 static struct irq_chip hpet_msi_type = {
 	.name = "HPET_MSI",
 	.irq_unmask = hpet_msi_unmask,
 	.irq_mask = hpet_msi_mask,
 	.irq_ack = ack_apic_edge,
-#ifdef CONFIG_SMP
 	.irq_set_affinity = hpet_msi_set_affinity,
-#endif
 	.irq_retrigger = ioapic_retrigger_irq,
 };
 
@@ -3314,8 +3328,6 @@ int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
  */
 #ifdef CONFIG_HT_IRQ
 
-#ifdef CONFIG_SMP
-
 static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
 {
 	struct ht_irq_msg msg;
@@ -3340,25 +3352,23 @@ ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
 		return -1;
 
 	target_ht_irq(data->irq, dest, cfg->vector);
-	return 0;
+	return IRQ_SET_MASK_OK_NOCOPY;
 }
 
-#endif
-
 static struct irq_chip ht_irq_chip = {
 	.name			= "PCI-HT",
 	.irq_mask		= mask_ht_irq,
 	.irq_unmask		= unmask_ht_irq,
 	.irq_ack		= ack_apic_edge,
-#ifdef CONFIG_SMP
 	.irq_set_affinity	= ht_set_affinity,
-#endif
 	.irq_retrigger		= ioapic_retrigger_irq,
 };
 
 int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 {
 	struct irq_cfg *cfg;
+	struct ht_irq_msg msg;
+	unsigned dest;
 	int err;
 
 	if (disable_apic)
@@ -3366,36 +3376,37 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 
 	cfg = irq_cfg(irq);
 	err = assign_irq_vector(irq, cfg, apic->target_cpus());
-	if (!err) {
-		struct ht_irq_msg msg;
-		unsigned dest;
+	if (err)
+		return err;
+
+	err = apic->cpu_mask_to_apicid_and(cfg->domain,
+					   apic->target_cpus(), &dest);
+	if (err)
+		return err;
 
-		dest = apic->cpu_mask_to_apicid_and(cfg->domain,
-						    apic->target_cpus());
+	msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
 
-		msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
+	msg.address_lo =
+		HT_IRQ_LOW_BASE |
+		HT_IRQ_LOW_DEST_ID(dest) |
+		HT_IRQ_LOW_VECTOR(cfg->vector) |
+		((apic->irq_dest_mode == 0) ?
+			HT_IRQ_LOW_DM_PHYSICAL :
+			HT_IRQ_LOW_DM_LOGICAL) |
+		HT_IRQ_LOW_RQEOI_EDGE |
+		((apic->irq_delivery_mode != dest_LowestPrio) ?
+			HT_IRQ_LOW_MT_FIXED :
+			HT_IRQ_LOW_MT_ARBITRATED) |
+		HT_IRQ_LOW_IRQ_MASKED;
 
-		msg.address_lo =
-			HT_IRQ_LOW_BASE |
-			HT_IRQ_LOW_DEST_ID(dest) |
-			HT_IRQ_LOW_VECTOR(cfg->vector) |
-			((apic->irq_dest_mode == 0) ?
-				HT_IRQ_LOW_DM_PHYSICAL :
-				HT_IRQ_LOW_DM_LOGICAL) |
-			HT_IRQ_LOW_RQEOI_EDGE |
-			((apic->irq_delivery_mode != dest_LowestPrio) ?
-				HT_IRQ_LOW_MT_FIXED :
-				HT_IRQ_LOW_MT_ARBITRATED) |
-			HT_IRQ_LOW_IRQ_MASKED;
+	write_ht_irq_msg(irq, &msg);
 
-		write_ht_irq_msg(irq, &msg);
+	irq_set_chip_and_handler_name(irq, &ht_irq_chip,
+				      handle_edge_irq, "edge");
 
-		irq_set_chip_and_handler_name(irq, &ht_irq_chip,
-					      handle_edge_irq, "edge");
+	dev_printk(KERN_DEBUG, &dev->dev, "irq %d for HT\n", irq);
 
-		dev_printk(KERN_DEBUG, &dev->dev, "irq %d for HT\n", irq);
-	}
-	return err;
+	return 0;
 }
 #endif /* CONFIG_HT_IRQ */
 
@@ -3563,7 +3574,8 @@ static int __init io_apic_get_unique_id(int ioapic, int apic_id)
 
 		/* Sanity check */
 		if (reg_00.bits.ID != apic_id) {
-			printk("IOAPIC[%d]: Unable to change apic_id!\n", ioapic);
+			pr_err("IOAPIC[%d]: Unable to change apic_id!\n",
+			       ioapic);
 			return -1;
 		}
 	}
diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c
index f00a68c..d661ee9 100644
--- a/arch/x86/kernel/apic/numaq_32.c
+++ b/arch/x86/kernel/apic/numaq_32.c
@@ -406,16 +406,13 @@ static inline int numaq_check_phys_apicid_present(int phys_apicid)
  * We use physical apicids here, not logical, so just return the default
  * physical broadcast to stop people from breaking us
  */
-static unsigned int numaq_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-	return 0x0F;
-}
-
-static inline unsigned int
+static int
 numaq_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-			     const struct cpumask *andmask)
+			     const struct cpumask *andmask,
+			     unsigned int *apicid)
 {
-	return 0x0F;
+	*apicid = 0x0F;
+	return 0;
 }
 
 /* No NUMA-Q box has a HT CPU, but it can't hurt to use the default code. */
@@ -441,20 +438,6 @@ static int probe_numaq(void)
 	return found_numaq;
 }
 
-static void numaq_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-	/* Careful. Some cpus do not strictly honor the set of cpus
-	 * specified in the interrupt destination when using lowest
-	 * priority interrupt delivery mode.
-	 *
-	 * In particular there was a hyperthreading cpu observed to
-	 * deliver interrupts to the wrong hyperthread when only one
-	 * hyperthread was specified in the interrupt desitination.
-	 */
-	cpumask_clear(retmask);
-	cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
-}
-
 static void numaq_setup_portio_remap(void)
 {
 	int num_quads = num_online_nodes();
@@ -491,7 +474,7 @@ static struct apic __refdata apic_numaq = {
 	.check_apicid_used		= numaq_check_apicid_used,
 	.check_apicid_present		= numaq_check_apicid_present,
 
-	.vector_allocation_domain	= numaq_vector_allocation_domain,
+	.vector_allocation_domain	= flat_vector_allocation_domain,
 	.init_apic_ldr			= numaq_init_apic_ldr,
 
 	.ioapic_phys_id_map		= numaq_ioapic_phys_id_map,
@@ -509,7 +492,6 @@ static struct apic __refdata apic_numaq = {
 	.set_apic_id			= NULL,
 	.apic_id_mask			= 0x0F << 24,
 
-	.cpu_mask_to_apicid		= numaq_cpu_mask_to_apicid,
 	.cpu_mask_to_apicid_and		= numaq_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= numaq_send_IPI_mask,
diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c
index 1b291da..eb35ef9 100644
--- a/arch/x86/kernel/apic/probe_32.c
+++ b/arch/x86/kernel/apic/probe_32.c
@@ -66,21 +66,6 @@ static void setup_apic_flat_routing(void)
 #endif
 }
 
-static void default_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-	/*
-	 * Careful. Some cpus do not strictly honor the set of cpus
-	 * specified in the interrupt destination when using lowest
-	 * priority interrupt delivery mode.
-	 *
-	 * In particular there was a hyperthreading cpu observed to
-	 * deliver interrupts to the wrong hyperthread when only one
-	 * hyperthread was specified in the interrupt desitination.
-	 */
-	cpumask_clear(retmask);
-	cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
-}
-
 /* should be called last. */
 static int probe_default(void)
 {
@@ -105,7 +90,7 @@ static struct apic apic_default = {
 	.check_apicid_used		= default_check_apicid_used,
 	.check_apicid_present		= default_check_apicid_present,
 
-	.vector_allocation_domain	= default_vector_allocation_domain,
+	.vector_allocation_domain	= flat_vector_allocation_domain,
 	.init_apic_ldr			= default_init_apic_ldr,
 
 	.ioapic_phys_id_map		= default_ioapic_phys_id_map,
@@ -123,8 +108,7 @@ static struct apic apic_default = {
 	.set_apic_id			= NULL,
 	.apic_id_mask			= 0x0F << 24,
 
-	.cpu_mask_to_apicid		= default_cpu_mask_to_apicid,
-	.cpu_mask_to_apicid_and		= default_cpu_mask_to_apicid_and,
+	.cpu_mask_to_apicid_and		= flat_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= default_send_IPI_mask_logical,
 	.send_IPI_mask_allbutself	= default_send_IPI_mask_allbutself_logical,
@@ -208,6 +192,9 @@ void __init default_setup_apic_routing(void)
 
 	if (apic->setup_apic_routing)
 		apic->setup_apic_routing();
+
+	if (x86_platform.apic_post_init)
+		x86_platform.apic_post_init();
 }
 
 void __init generic_apic_probe(void)
diff --git a/arch/x86/kernel/apic/probe_64.c b/arch/x86/kernel/apic/probe_64.c
index 3fe9866..1793dba 100644
--- a/arch/x86/kernel/apic/probe_64.c
+++ b/arch/x86/kernel/apic/probe_64.c
@@ -23,11 +23,6 @@
 #include <asm/ipi.h>
 #include <asm/setup.h>
 
-static int apicid_phys_pkg_id(int initial_apic_id, int index_msb)
-{
-	return hard_smp_processor_id() >> index_msb;
-}
-
 /*
  * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
  */
@@ -48,10 +43,8 @@ void __init default_setup_apic_routing(void)
 		}
 	}
 
-	if (is_vsmp_box()) {
-		/* need to update phys_pkg_id */
-		apic->phys_pkg_id = apicid_phys_pkg_id;
-	}
+	if (x86_platform.apic_post_init)
+		x86_platform.apic_post_init();
 }
 
 /* Same for both flat and physical. */
diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c
index 659897c..77c95c0 100644
--- a/arch/x86/kernel/apic/summit_32.c
+++ b/arch/x86/kernel/apic/summit_32.c
@@ -26,6 +26,8 @@
  *
  */
 
+#define pr_fmt(fmt) "summit: %s: " fmt, __func__
+
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <asm/io.h>
@@ -235,8 +237,8 @@ static int summit_apic_id_registered(void)
 
 static void summit_setup_apic_routing(void)
 {
-	printk("Enabling APIC mode:  Summit.  Using %d I/O APICs\n",
-						nr_ioapics);
+	pr_info("Enabling APIC mode:  Summit.  Using %d I/O APICs\n",
+		nr_ioapics);
 }
 
 static int summit_cpu_present_to_apicid(int mps_cpu)
@@ -263,43 +265,48 @@ static int summit_check_phys_apicid_present(int physical_apicid)
 	return 1;
 }
 
-static unsigned int summit_cpu_mask_to_apicid(const struct cpumask *cpumask)
+static inline int
+summit_cpu_mask_to_apicid(const struct cpumask *cpumask, unsigned int *dest_id)
 {
 	unsigned int round = 0;
-	int cpu, apicid = 0;
+	unsigned int cpu, apicid = 0;
 
 	/*
 	 * The cpus in the mask must all be on the apic cluster.
 	 */
-	for_each_cpu(cpu, cpumask) {
+	for_each_cpu_and(cpu, cpumask, cpu_online_mask) {
 		int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
 
 		if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) {
-			printk("%s: Not a valid mask!\n", __func__);
-			return BAD_APICID;
+			pr_err("Not a valid mask!\n");
+			return -EINVAL;
 		}
 		apicid |= new_apicid;
 		round++;
 	}
-	return apicid;
+	if (!round)
+		return -EINVAL;
+	*dest_id = apicid;
+	return 0;
 }
 
-static unsigned int summit_cpu_mask_to_apicid_and(const struct cpumask *inmask,
-			      const struct cpumask *andmask)
+static int
+summit_cpu_mask_to_apicid_and(const struct cpumask *inmask,
+			      const struct cpumask *andmask,
+			      unsigned int *apicid)
 {
-	int apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
 	cpumask_var_t cpumask;
+	*apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
 
 	if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
-		return apicid;
+		return 0;
 
 	cpumask_and(cpumask, inmask, andmask);
-	cpumask_and(cpumask, cpumask, cpu_online_mask);
-	apicid = summit_cpu_mask_to_apicid(cpumask);
+	summit_cpu_mask_to_apicid(cpumask, apicid);
 
 	free_cpumask_var(cpumask);
 
-	return apicid;
+	return 0;
 }
 
 /*
@@ -320,20 +327,6 @@ static int probe_summit(void)
 	return 0;
 }
 
-static void summit_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-	/* Careful. Some cpus do not strictly honor the set of cpus
-	 * specified in the interrupt destination when using lowest
-	 * priority interrupt delivery mode.
-	 *
-	 * In particular there was a hyperthreading cpu observed to
-	 * deliver interrupts to the wrong hyperthread when only one
-	 * hyperthread was specified in the interrupt desitination.
-	 */
-	cpumask_clear(retmask);
-	cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
-}
-
 #ifdef CONFIG_X86_SUMMIT_NUMA
 static struct rio_table_hdr *rio_table_hdr;
 static struct scal_detail   *scal_devs[MAX_NUMNODES];
@@ -355,7 +348,7 @@ static int setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus)
 		}
 	}
 	if (i == rio_table_hdr->num_rio_dev) {
-		printk(KERN_ERR "%s: Couldn't find owner Cyclone for Winnipeg!\n", __func__);
+		pr_err("Couldn't find owner Cyclone for Winnipeg!\n");
 		return last_bus;
 	}
 
@@ -366,7 +359,7 @@ static int setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus)
 		}
 	}
 	if (i == rio_table_hdr->num_scal_dev) {
-		printk(KERN_ERR "%s: Couldn't find owner Twister for Cyclone!\n", __func__);
+		pr_err("Couldn't find owner Twister for Cyclone!\n");
 		return last_bus;
 	}
 
@@ -396,7 +389,7 @@ static int setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus)
 		num_buses = 9;
 		break;
 	default:
-		printk(KERN_INFO "%s: Unsupported Winnipeg type!\n", __func__);
+		pr_info("Unsupported Winnipeg type!\n");
 		return last_bus;
 	}
 
@@ -411,13 +404,15 @@ static int build_detail_arrays(void)
 	int i, scal_detail_size, rio_detail_size;
 
 	if (rio_table_hdr->num_scal_dev > MAX_NUMNODES) {
-		printk(KERN_WARNING "%s: MAX_NUMNODES too low!  Defined as %d, but system has %d nodes.\n", __func__, MAX_NUMNODES, rio_table_hdr->num_scal_dev);
+		pr_warn("MAX_NUMNODES too low!  Defined as %d, but system has %d nodes\n",
+			MAX_NUMNODES, rio_table_hdr->num_scal_dev);
 		return 0;
 	}
 
 	switch (rio_table_hdr->version) {
 	default:
-		printk(KERN_WARNING "%s: Invalid Rio Grande Table Version: %d\n", __func__, rio_table_hdr->version);
+		pr_warn("Invalid Rio Grande Table Version: %d\n",
+			rio_table_hdr->version);
 		return 0;
 	case 2:
 		scal_detail_size = 11;
@@ -462,7 +457,7 @@ void setup_summit(void)
 		offset = *((unsigned short *)(ptr + offset));
 	}
 	if (!rio_table_hdr) {
-		printk(KERN_ERR "%s: Unable to locate Rio Grande Table in EBDA - bailing!\n", __func__);
+		pr_err("Unable to locate Rio Grande Table in EBDA - bailing!\n");
 		return;
 	}
 
@@ -509,7 +504,7 @@ static struct apic apic_summit = {
 	.check_apicid_used		= summit_check_apicid_used,
 	.check_apicid_present		= summit_check_apicid_present,
 
-	.vector_allocation_domain	= summit_vector_allocation_domain,
+	.vector_allocation_domain	= flat_vector_allocation_domain,
 	.init_apic_ldr			= summit_init_apic_ldr,
 
 	.ioapic_phys_id_map		= summit_ioapic_phys_id_map,
@@ -527,7 +522,6 @@ static struct apic apic_summit = {
 	.set_apic_id			= NULL,
 	.apic_id_mask			= 0xFF << 24,
 
-	.cpu_mask_to_apicid		= summit_cpu_mask_to_apicid,
 	.cpu_mask_to_apicid_and		= summit_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= summit_send_IPI_mask,
diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c
index ff35cff..943d03f 100644
--- a/arch/x86/kernel/apic/x2apic_cluster.c
+++ b/arch/x86/kernel/apic/x2apic_cluster.c
@@ -81,7 +81,7 @@ static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
 }
 
 static void
- x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector)
+x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector)
 {
 	__x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLBUT);
 }
@@ -96,36 +96,37 @@ static void x2apic_send_IPI_all(int vector)
 	__x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC);
 }
 
-static unsigned int x2apic_cpu_mask_to_apicid(const struct cpumask *cpumask)
+static int
+x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
+			      const struct cpumask *andmask,
+			      unsigned int *apicid)
 {
-	/*
-	 * We're using fixed IRQ delivery, can only return one logical APIC ID.
-	 * May as well be the first.
-	 */
-	int cpu = cpumask_first(cpumask);
+	u32 dest = 0;
+	u16 cluster;
+	int i;
 
-	if ((unsigned)cpu < nr_cpu_ids)
-		return per_cpu(x86_cpu_to_logical_apicid, cpu);
-	else
-		return BAD_APICID;
-}
+	for_each_cpu_and(i, cpumask, andmask) {
+		if (!cpumask_test_cpu(i, cpu_online_mask))
+			continue;
+		dest = per_cpu(x86_cpu_to_logical_apicid, i);
+		cluster = x2apic_cluster(i);
+		break;
+	}
 
-static unsigned int
-x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-			      const struct cpumask *andmask)
-{
-	int cpu;
+	if (!dest)
+		return -EINVAL;
 
-	/*
-	 * We're using fixed IRQ delivery, can only return one logical APIC ID.
-	 * May as well be the first.
-	 */
-	for_each_cpu_and(cpu, cpumask, andmask) {
-		if (cpumask_test_cpu(cpu, cpu_online_mask))
-			break;
+	for_each_cpu_and(i, cpumask, andmask) {
+		if (!cpumask_test_cpu(i, cpu_online_mask))
+			continue;
+		if (cluster != x2apic_cluster(i))
+			continue;
+		dest |= per_cpu(x86_cpu_to_logical_apicid, i);
 	}
 
-	return per_cpu(x86_cpu_to_logical_apicid, cpu);
+	*apicid = dest;
+
+	return 0;
 }
 
 static void init_x2apic_ldr(void)
@@ -208,6 +209,16 @@ static int x2apic_cluster_probe(void)
 		return 0;
 }
 
+/*
+ * Each x2apic cluster is an allocation domain.
+ */
+static bool cluster_vector_allocation_domain(int cpu, struct cpumask *retmask)
+{
+	cpumask_clear(retmask);
+	cpumask_copy(retmask, per_cpu(cpus_in_cluster, cpu));
+	return true;
+}
+
 static struct apic apic_x2apic_cluster = {
 
 	.name				= "cluster x2apic",
@@ -219,13 +230,13 @@ static struct apic apic_x2apic_cluster = {
 	.irq_delivery_mode		= dest_LowestPrio,
 	.irq_dest_mode			= 1, /* logical */
 
-	.target_cpus			= x2apic_target_cpus,
+	.target_cpus			= online_target_cpus,
 	.disable_esr			= 0,
 	.dest_logical			= APIC_DEST_LOGICAL,
 	.check_apicid_used		= NULL,
 	.check_apicid_present		= NULL,
 
-	.vector_allocation_domain	= x2apic_vector_allocation_domain,
+	.vector_allocation_domain	= cluster_vector_allocation_domain,
 	.init_apic_ldr			= init_x2apic_ldr,
 
 	.ioapic_phys_id_map		= NULL,
@@ -243,7 +254,6 @@ static struct apic apic_x2apic_cluster = {
 	.set_apic_id			= x2apic_set_apic_id,
 	.apic_id_mask			= 0xFFFFFFFFu,
 
-	.cpu_mask_to_apicid		= x2apic_cpu_mask_to_apicid,
 	.cpu_mask_to_apicid_and		= x2apic_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= x2apic_send_IPI_mask,
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index c17e982..e03a1e1 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -76,38 +76,6 @@ static void x2apic_send_IPI_all(int vector)
 	__x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC);
 }
 
-static unsigned int x2apic_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-	/*
-	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
-	 * May as well be the first.
-	 */
-	int cpu = cpumask_first(cpumask);
-
-	if ((unsigned)cpu < nr_cpu_ids)
-		return per_cpu(x86_cpu_to_apicid, cpu);
-	else
-		return BAD_APICID;
-}
-
-static unsigned int
-x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-			      const struct cpumask *andmask)
-{
-	int cpu;
-
-	/*
-	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
-	 * May as well be the first.
-	 */
-	for_each_cpu_and(cpu, cpumask, andmask) {
-		if (cpumask_test_cpu(cpu, cpu_online_mask))
-			break;
-	}
-
-	return per_cpu(x86_cpu_to_apicid, cpu);
-}
-
 static void init_x2apic_ldr(void)
 {
 }
@@ -131,13 +99,13 @@ static struct apic apic_x2apic_phys = {
 	.irq_delivery_mode		= dest_Fixed,
 	.irq_dest_mode			= 0, /* physical */
 
-	.target_cpus			= x2apic_target_cpus,
+	.target_cpus			= online_target_cpus,
 	.disable_esr			= 0,
 	.dest_logical			= 0,
 	.check_apicid_used		= NULL,
 	.check_apicid_present		= NULL,
 
-	.vector_allocation_domain	= x2apic_vector_allocation_domain,
+	.vector_allocation_domain	= default_vector_allocation_domain,
 	.init_apic_ldr			= init_x2apic_ldr,
 
 	.ioapic_phys_id_map		= NULL,
@@ -155,8 +123,7 @@ static struct apic apic_x2apic_phys = {
 	.set_apic_id			= x2apic_set_apic_id,
 	.apic_id_mask			= 0xFFFFFFFFu,
 
-	.cpu_mask_to_apicid		= x2apic_cpu_mask_to_apicid,
-	.cpu_mask_to_apicid_and		= x2apic_cpu_mask_to_apicid_and,
+	.cpu_mask_to_apicid_and		= default_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= x2apic_send_IPI_mask,
 	.send_IPI_mask_allbutself	= x2apic_send_IPI_mask_allbutself,
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index c6d03f7..8cfade9 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -185,17 +185,6 @@ EXPORT_SYMBOL_GPL(uv_possible_blades);
 unsigned long sn_rtc_cycles_per_second;
 EXPORT_SYMBOL(sn_rtc_cycles_per_second);
 
-static const struct cpumask *uv_target_cpus(void)
-{
-	return cpu_online_mask;
-}
-
-static void uv_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-	cpumask_clear(retmask);
-	cpumask_set_cpu(cpu, retmask);
-}
-
 static int __cpuinit uv_wakeup_secondary(int phys_apicid, unsigned long start_rip)
 {
 #ifdef CONFIG_SMP
@@ -280,25 +269,12 @@ static void uv_init_apic_ldr(void)
 {
 }
 
-static unsigned int uv_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-	/*
-	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
-	 * May as well be the first.
-	 */
-	int cpu = cpumask_first(cpumask);
-
-	if ((unsigned)cpu < nr_cpu_ids)
-		return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits;
-	else
-		return BAD_APICID;
-}
-
-static unsigned int
+static int
 uv_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-			  const struct cpumask *andmask)
+			  const struct cpumask *andmask,
+			  unsigned int *apicid)
 {
-	int cpu;
+	int unsigned cpu;
 
 	/*
 	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
@@ -308,7 +284,13 @@ uv_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
 		if (cpumask_test_cpu(cpu, cpu_online_mask))
 			break;
 	}
-	return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits;
+
+	if (likely(cpu < nr_cpu_ids)) {
+		*apicid = per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits;
+		return 0;
+	}
+
+	return -EINVAL;
 }
 
 static unsigned int x2apic_get_apic_id(unsigned long x)
@@ -362,13 +344,13 @@ static struct apic __refdata apic_x2apic_uv_x = {
 	.irq_delivery_mode		= dest_Fixed,
 	.irq_dest_mode			= 0, /* physical */
 
-	.target_cpus			= uv_target_cpus,
+	.target_cpus			= online_target_cpus,
 	.disable_esr			= 0,
 	.dest_logical			= APIC_DEST_LOGICAL,
 	.check_apicid_used		= NULL,
 	.check_apicid_present		= NULL,
 
-	.vector_allocation_domain	= uv_vector_allocation_domain,
+	.vector_allocation_domain	= default_vector_allocation_domain,
 	.init_apic_ldr			= uv_init_apic_ldr,
 
 	.ioapic_phys_id_map		= NULL,
@@ -386,7 +368,6 @@ static struct apic __refdata apic_x2apic_uv_x = {
 	.set_apic_id			= set_apic_id,
 	.apic_id_mask			= 0xFFFFFFFFu,
 
-	.cpu_mask_to_apicid		= uv_cpu_mask_to_apicid,
 	.cpu_mask_to_apicid_and		= uv_cpu_mask_to_apicid_and,
 
 	.send_IPI_mask			= uv_send_IPI_mask,
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 07b0c0d..d65464e 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -201,6 +201,8 @@
  *    http://www.microsoft.com/whdc/archive/amp_12.mspx]
  */
 
+#define pr_fmt(fmt) "apm: " fmt
+
 #include <linux/module.h>
 
 #include <linux/poll.h>
@@ -485,11 +487,11 @@ static void apm_error(char *str, int err)
 		if (error_table[i].key == err)
 			break;
 	if (i < ERROR_COUNT)
-		printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);
+		pr_notice("%s: %s\n", str, error_table[i].msg);
 	else if (err < 0)
-		printk(KERN_NOTICE "apm: %s: linux error code %i\n", str, err);
+		pr_notice("%s: linux error code %i\n", str, err);
 	else
-		printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",
+		pr_notice("%s: unknown error code %#2.2x\n",
 		       str, err);
 }
 
@@ -1184,7 +1186,7 @@ static void queue_event(apm_event_t event, struct apm_user *sender)
 			static int notified;
 
 			if (notified++ == 0)
-			    printk(KERN_ERR "apm: an event queue overflowed\n");
+				pr_err("an event queue overflowed\n");
 			if (++as->event_tail >= APM_MAX_EVENTS)
 				as->event_tail = 0;
 		}
@@ -1447,7 +1449,7 @@ static void apm_mainloop(void)
 static int check_apm_user(struct apm_user *as, const char *func)
 {
 	if (as == NULL || as->magic != APM_BIOS_MAGIC) {
-		printk(KERN_ERR "apm: %s passed bad filp\n", func);
+		pr_err("%s passed bad filp\n", func);
 		return 1;
 	}
 	return 0;
@@ -1586,7 +1588,7 @@ static int do_release(struct inode *inode, struct file *filp)
 		     as1 = as1->next)
 			;
 		if (as1 == NULL)
-			printk(KERN_ERR "apm: filp not in user list\n");
+			pr_err("filp not in user list\n");
 		else
 			as1->next = as->next;
 	}
@@ -1600,11 +1602,9 @@ static int do_open(struct inode *inode, struct file *filp)
 	struct apm_user *as;
 
 	as = kmalloc(sizeof(*as), GFP_KERNEL);
-	if (as == NULL) {
-		printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
-		       sizeof(*as));
+	if (as == NULL)
 		return -ENOMEM;
-	}
+
 	as->magic = APM_BIOS_MAGIC;
 	as->event_tail = as->event_head = 0;
 	as->suspends_pending = as->standbys_pending = 0;
@@ -2313,16 +2313,16 @@ static int __init apm_init(void)
 	}
 
 	if (apm_info.disabled) {
-		printk(KERN_NOTICE "apm: disabled on user request.\n");
+		pr_notice("disabled on user request.\n");
 		return -ENODEV;
 	}
 	if ((num_online_cpus() > 1) && !power_off && !smp) {
-		printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
+		pr_notice("disabled - APM is not SMP safe.\n");
 		apm_info.disabled = 1;
 		return -ENODEV;
 	}
 	if (!acpi_disabled) {
-		printk(KERN_NOTICE "apm: overridden by ACPI.\n");
+		pr_notice("overridden by ACPI.\n");
 		apm_info.disabled = 1;
 		return -ENODEV;
 	}
@@ -2356,8 +2356,7 @@ static int __init apm_init(void)
 
 	kapmd_task = kthread_create(apm, NULL, "kapmd");
 	if (IS_ERR(kapmd_task)) {
-		printk(KERN_ERR "apm: disabled - Unable to start kernel "
-				"thread.\n");
+		pr_err("disabled - Unable to start kernel thread\n");
 		err = PTR_ERR(kapmd_task);
 		kapmd_task = NULL;
 		remove_proc_entry("apm", NULL);
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 6ab6aa2..d30a6a9 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -14,7 +14,7 @@ CFLAGS_common.o		:= $(nostackp)
 
 obj-y			:= intel_cacheinfo.o scattered.o topology.o
 obj-y			+= proc.o capflags.o powerflags.o common.o
-obj-y			+= vmware.o hypervisor.o sched.o mshyperv.o
+obj-y			+= vmware.o hypervisor.o mshyperv.o
 obj-y			+= rdrand.o
 obj-y			+= match.o
 
@@ -32,7 +32,9 @@ obj-$(CONFIG_PERF_EVENTS)		+= perf_event.o
 
 ifdef CONFIG_PERF_EVENTS
 obj-$(CONFIG_CPU_SUP_AMD)		+= perf_event_amd.o
-obj-$(CONFIG_CPU_SUP_INTEL)		+= perf_event_p6.o perf_event_p4.o perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o
+obj-$(CONFIG_CPU_SUP_INTEL)		+= perf_event_p6.o perf_event_p4.o
+obj-$(CONFIG_CPU_SUP_INTEL)		+= perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o
+obj-$(CONFIG_CPU_SUP_INTEL)		+= perf_event_intel_uncore.o
 endif
 
 obj-$(CONFIG_X86_MCE)			+= mcheck/
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 146bb62..9d92e19 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -19,6 +19,39 @@
 
 #include "cpu.h"
 
+static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
+{
+	struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
+	u32 gprs[8] = { 0 };
+	int err;
+
+	WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__);
+
+	gprs[1] = msr;
+	gprs[7] = 0x9c5a203a;
+
+	err = rdmsr_safe_regs(gprs);
+
+	*p = gprs[0] | ((u64)gprs[2] << 32);
+
+	return err;
+}
+
+static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val)
+{
+	struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
+	u32 gprs[8] = { 0 };
+
+	WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__);
+
+	gprs[0] = (u32)val;
+	gprs[1] = msr;
+	gprs[2] = val >> 32;
+	gprs[7] = 0x9c5a203a;
+
+	return wrmsr_safe_regs(gprs);
+}
+
 #ifdef CONFIG_X86_32
 /*
  *	B step AMD K6 before B 9730xxxx have hardware bugs that can cause
@@ -586,9 +619,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 	    !cpu_has(c, X86_FEATURE_TOPOEXT)) {
 		u64 val;
 
-		if (!rdmsrl_amd_safe(0xc0011005, &val)) {
+		if (!rdmsrl_safe(0xc0011005, &val)) {
 			val |= 1ULL << 54;
-			wrmsrl_amd_safe(0xc0011005, val);
+			wrmsrl_safe(0xc0011005, val);
 			rdmsrl(0xc0011005, val);
 			if (val & (1ULL << 54)) {
 				set_cpu_cap(c, X86_FEATURE_TOPOEXT);
@@ -679,7 +712,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 		err = rdmsrl_safe(MSR_AMD64_MCx_MASK(4), &mask);
 		if (err == 0) {
 			mask |= (1 << 10);
-			checking_wrmsrl(MSR_AMD64_MCx_MASK(4), mask);
+			wrmsrl_safe(MSR_AMD64_MCx_MASK(4), mask);
 		}
 	}
 
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 46674fb..c97bb7b 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -55,8 +55,8 @@ static void __init check_fpu(void)
 
 	if (!boot_cpu_data.hard_math) {
 #ifndef CONFIG_MATH_EMULATION
-		printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
-		printk(KERN_EMERG "Giving up.\n");
+		pr_emerg("No coprocessor found and no math emulation present\n");
+		pr_emerg("Giving up\n");
 		for (;;) ;
 #endif
 		return;
@@ -86,7 +86,7 @@ static void __init check_fpu(void)
 
 	boot_cpu_data.fdiv_bug = fdiv_bug;
 	if (boot_cpu_data.fdiv_bug)
-		printk(KERN_WARNING "Hmm, FPU with FDIV bug.\n");
+		pr_warn("Hmm, FPU with FDIV bug\n");
 }
 
 static void __init check_hlt(void)
@@ -94,16 +94,16 @@ static void __init check_hlt(void)
 	if (boot_cpu_data.x86 >= 5 || paravirt_enabled())
 		return;
 
-	printk(KERN_INFO "Checking 'hlt' instruction... ");
+	pr_info("Checking 'hlt' instruction... ");
 	if (!boot_cpu_data.hlt_works_ok) {
-		printk("disabled\n");
+		pr_cont("disabled\n");
 		return;
 	}
 	halt();
 	halt();
 	halt();
 	halt();
-	printk(KERN_CONT "OK.\n");
+	pr_cont("OK\n");
 }
 
 /*
@@ -116,7 +116,7 @@ static void __init check_popad(void)
 #ifndef CONFIG_X86_POPAD_OK
 	int res, inp = (int) &res;
 
-	printk(KERN_INFO "Checking for popad bug... ");
+	pr_info("Checking for popad bug... ");
 	__asm__ __volatile__(
 	  "movl $12345678,%%eax; movl $0,%%edi; pusha; popa; movl (%%edx,%%edi),%%ecx "
 	  : "=&a" (res)
@@ -127,9 +127,9 @@ static void __init check_popad(void)
 	 * CPU hard. Too bad.
 	 */
 	if (res != 12345678)
-		printk(KERN_CONT "Buggy.\n");
+		pr_cont("Buggy\n");
 	else
-		printk(KERN_CONT "OK.\n");
+		pr_cont("OK\n");
 #endif
 }
 
@@ -161,7 +161,7 @@ void __init check_bugs(void)
 {
 	identify_boot_cpu();
 #ifndef CONFIG_SMP
-	printk(KERN_INFO "CPU: ");
+	pr_info("CPU: ");
 	print_cpu_info(&boot_cpu_data);
 #endif
 	check_config();
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 6b9333b..5bbc082 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -947,7 +947,7 @@ static void __cpuinit __print_cpu_msr(void)
 		index_max = msr_range_array[i].max;
 
 		for (index = index_min; index < index_max; index++) {
-			if (rdmsrl_amd_safe(index, &val))
+			if (rdmsrl_safe(index, &val))
 				continue;
 			printk(KERN_INFO " MSR%08x: %016llx\n", index, val);
 		}
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index da27c5d..4b4408b 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -7,6 +7,9 @@
  * Copyright 2008 Intel Corporation
  * Author: Andi Kleen
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/thread_info.h>
 #include <linux/capability.h>
 #include <linux/miscdevice.h>
@@ -57,8 +60,6 @@ static DEFINE_MUTEX(mce_chrdev_read_mutex);
 
 int mce_disabled __read_mostly;
 
-#define MISC_MCELOG_MINOR	227
-
 #define SPINUNIT 100	/* 100ns */
 
 atomic_t mce_entry;
@@ -210,7 +211,7 @@ static void drain_mcelog_buffer(void)
 				cpu_relax();
 
 				if (!m->finished && retries >= 4) {
-					pr_err("MCE: skipping error being logged currently!\n");
+					pr_err("skipping error being logged currently!\n");
 					break;
 				}
 			}
@@ -1167,8 +1168,9 @@ int memory_failure(unsigned long pfn, int vector, int flags)
 {
 	/* mce_severity() should not hand us an ACTION_REQUIRED error */
 	BUG_ON(flags & MF_ACTION_REQUIRED);
-	printk(KERN_ERR "Uncorrected memory error in page 0x%lx ignored\n"
-		"Rebuild kernel with CONFIG_MEMORY_FAILURE=y for smarter handling\n", pfn);
+	pr_err("Uncorrected memory error in page 0x%lx ignored\n"
+	       "Rebuild kernel with CONFIG_MEMORY_FAILURE=y for smarter handling\n",
+	       pfn);
 
 	return 0;
 }
@@ -1358,11 +1360,10 @@ static int __cpuinit __mcheck_cpu_cap_init(void)
 
 	b = cap & MCG_BANKCNT_MASK;
 	if (!banks)
-		printk(KERN_INFO "mce: CPU supports %d MCE banks\n", b);
+		pr_info("CPU supports %d MCE banks\n", b);
 
 	if (b > MAX_NR_BANKS) {
-		printk(KERN_WARNING
-		       "MCE: Using only %u machine check banks out of %u\n",
+		pr_warn("Using only %u machine check banks out of %u\n",
 			MAX_NR_BANKS, b);
 		b = MAX_NR_BANKS;
 	}
@@ -1419,7 +1420,7 @@ static void __mcheck_cpu_init_generic(void)
 static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
 {
 	if (c->x86_vendor == X86_VENDOR_UNKNOWN) {
-		pr_info("MCE: unknown CPU type - not enabling MCE support.\n");
+		pr_info("unknown CPU type - not enabling MCE support\n");
 		return -EOPNOTSUPP;
 	}
 
@@ -1574,7 +1575,7 @@ static void __mcheck_cpu_init_timer(void)
 /* Handle unconfigured int18 (should never happen) */
 static void unexpected_machine_check(struct pt_regs *regs, long error_code)
 {
-	printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n",
+	pr_err("CPU#%d: Unexpected int18 (Machine Check)\n",
 	       smp_processor_id());
 }
 
@@ -1893,8 +1894,7 @@ static int __init mcheck_enable(char *str)
 			get_option(&str, &monarch_timeout);
 		}
 	} else {
-		printk(KERN_INFO "mce argument %s ignored. Please use /sys\n",
-		       str);
+		pr_info("mce argument %s ignored. Please use /sys\n", str);
 		return 0;
 	}
 	return 1;
@@ -2342,7 +2342,7 @@ static __init int mcheck_init_device(void)
 
 	return err;
 }
-device_initcall(mcheck_init_device);
+device_initcall_sync(mcheck_init_device);
 
 /*
  * Old style boot options parsing. Only for compatibility.
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index f4873a6..c4e916d 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -1,15 +1,17 @@
 /*
- *  (c) 2005, 2006 Advanced Micro Devices, Inc.
+ *  (c) 2005-2012 Advanced Micro Devices, Inc.
  *  Your use of this code is subject to the terms and conditions of the
  *  GNU general public license version 2. See "COPYING" or
  *  http://www.gnu.org/licenses/gpl.html
  *
  *  Written by Jacob Shin - AMD, Inc.
  *
- *  Support : jacob.shin@amd.com
+ *  Support: borislav.petkov@amd.com
  *
  *  April 2006
  *     - added support for AMD Family 0x10 processors
+ *  May 2012
+ *     - major scrubbing
  *
  *  All MC4_MISCi registers are shared between multi-cores
  */
@@ -25,6 +27,7 @@
 #include <linux/cpu.h>
 #include <linux/smp.h>
 
+#include <asm/amd_nb.h>
 #include <asm/apic.h>
 #include <asm/idle.h>
 #include <asm/mce.h>
@@ -45,23 +48,15 @@
 #define MASK_BLKPTR_LO    0xFF000000
 #define MCG_XBLK_ADDR     0xC0000400
 
-struct threshold_block {
-	unsigned int		block;
-	unsigned int		bank;
-	unsigned int		cpu;
-	u32			address;
-	u16			interrupt_enable;
-	bool			interrupt_capable;
-	u16			threshold_limit;
-	struct kobject		kobj;
-	struct list_head	miscj;
+static const char * const th_names[] = {
+	"load_store",
+	"insn_fetch",
+	"combined_unit",
+	"",
+	"northbridge",
+	"execution_unit",
 };
 
-struct threshold_bank {
-	struct kobject		*kobj;
-	struct threshold_block	*blocks;
-	cpumask_var_t		cpus;
-};
 static DEFINE_PER_CPU(struct threshold_bank * [NR_BANKS], threshold_banks);
 
 static unsigned char shared_bank[NR_BANKS] = {
@@ -84,6 +79,26 @@ struct thresh_restart {
 	u16			old_limit;
 };
 
+static const char * const bank4_names(struct threshold_block *b)
+{
+	switch (b->address) {
+	/* MSR4_MISC0 */
+	case 0x00000413:
+		return "dram";
+
+	case 0xc0000408:
+		return "ht_links";
+
+	case 0xc0000409:
+		return "l3_cache";
+
+	default:
+		WARN(1, "Funny MSR: 0x%08x\n", b->address);
+		return "";
+	}
+};
+
+
 static bool lvt_interrupt_supported(unsigned int bank, u32 msr_high_bits)
 {
 	/*
@@ -224,8 +239,6 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
 
 			if (!block)
 				per_cpu(bank_map, cpu) |= (1 << bank);
-			if (shared_bank[bank] && c->cpu_core_id)
-				break;
 
 			memset(&b, 0, sizeof(b));
 			b.cpu			= cpu;
@@ -326,7 +339,7 @@ struct threshold_attr {
 #define SHOW_FIELDS(name)						\
 static ssize_t show_ ## name(struct threshold_block *b, char *buf)	\
 {									\
-	return sprintf(buf, "%lx\n", (unsigned long) b->name);		\
+	return sprintf(buf, "%lu\n", (unsigned long) b->name);		\
 }
 SHOW_FIELDS(interrupt_enable)
 SHOW_FIELDS(threshold_limit)
@@ -377,38 +390,21 @@ store_threshold_limit(struct threshold_block *b, const char *buf, size_t size)
 	return size;
 }
 
-struct threshold_block_cross_cpu {
-	struct threshold_block	*tb;
-	long			retval;
-};
-
-static void local_error_count_handler(void *_tbcc)
-{
-	struct threshold_block_cross_cpu *tbcc = _tbcc;
-	struct threshold_block *b = tbcc->tb;
-	u32 low, high;
-
-	rdmsr(b->address, low, high);
-	tbcc->retval = (high & 0xFFF) - (THRESHOLD_MAX - b->threshold_limit);
-}
-
 static ssize_t show_error_count(struct threshold_block *b, char *buf)
 {
-	struct threshold_block_cross_cpu tbcc = { .tb = b, };
+	u32 lo, hi;
 
-	smp_call_function_single(b->cpu, local_error_count_handler, &tbcc, 1);
-	return sprintf(buf, "%lx\n", tbcc.retval);
-}
-
-static ssize_t store_error_count(struct threshold_block *b,
-				 const char *buf, size_t count)
-{
-	struct thresh_restart tr = { .b = b, .reset = 1, .old_limit = 0 };
+	rdmsr_on_cpu(b->cpu, b->address, &lo, &hi);
 
-	smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
-	return 1;
+	return sprintf(buf, "%u\n", ((hi & THRESHOLD_MAX) -
+				     (THRESHOLD_MAX - b->threshold_limit)));
 }
 
+static struct threshold_attr error_count = {
+	.attr = {.name = __stringify(error_count), .mode = 0444 },
+	.show = show_error_count,
+};
+
 #define RW_ATTR(val)							\
 static struct threshold_attr val = {					\
 	.attr	= {.name = __stringify(val), .mode = 0644 },		\
@@ -418,7 +414,6 @@ static struct threshold_attr val = {					\
 
 RW_ATTR(interrupt_enable);
 RW_ATTR(threshold_limit);
-RW_ATTR(error_count);
 
 static struct attribute *default_attrs[] = {
 	&threshold_limit.attr,
@@ -517,7 +512,7 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
 
 	err = kobject_init_and_add(&b->kobj, &threshold_ktype,
 				   per_cpu(threshold_banks, cpu)[bank]->kobj,
-				   "misc%i", block);
+				   (bank == 4 ? bank4_names(b) : th_names[bank]));
 	if (err)
 		goto out_free;
 recurse:
@@ -548,98 +543,91 @@ out_free:
 	return err;
 }
 
-static __cpuinit long
-local_allocate_threshold_blocks(int cpu, unsigned int bank)
+static __cpuinit int __threshold_add_blocks(struct threshold_bank *b)
 {
-	return allocate_threshold_blocks(cpu, bank, 0,
-					 MSR_IA32_MC0_MISC + bank * 4);
+	struct list_head *head = &b->blocks->miscj;
+	struct threshold_block *pos = NULL;
+	struct threshold_block *tmp = NULL;
+	int err = 0;
+
+	err = kobject_add(&b->blocks->kobj, b->kobj, b->blocks->kobj.name);
+	if (err)
+		return err;
+
+	list_for_each_entry_safe(pos, tmp, head, miscj) {
+
+		err = kobject_add(&pos->kobj, b->kobj, pos->kobj.name);
+		if (err) {
+			list_for_each_entry_safe_reverse(pos, tmp, head, miscj)
+				kobject_del(&pos->kobj);
+
+			return err;
+		}
+	}
+	return err;
 }
 
-/* symlinks sibling shared banks to first core.  first core owns dir/files. */
 static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
 {
-	int i, err = 0;
-	struct threshold_bank *b = NULL;
 	struct device *dev = per_cpu(mce_device, cpu);
-	char name[32];
+	struct amd_northbridge *nb = NULL;
+	struct threshold_bank *b = NULL;
+	const char *name = th_names[bank];
+	int err = 0;
 
-	sprintf(name, "threshold_bank%i", bank);
+	if (shared_bank[bank]) {
 
-#ifdef CONFIG_SMP
-	if (cpu_data(cpu).cpu_core_id && shared_bank[bank]) {	/* symlink */
-		i = cpumask_first(cpu_llc_shared_mask(cpu));
+		nb = node_to_amd_nb(amd_get_nb_id(cpu));
+		WARN_ON(!nb);
 
-		/* first core not up yet */
-		if (cpu_data(i).cpu_core_id)
-			goto out;
+		/* threshold descriptor already initialized on this node? */
+		if (nb->bank4) {
+			/* yes, use it */
+			b = nb->bank4;
+			err = kobject_add(b->kobj, &dev->kobj, name);
+			if (err)
+				goto out;
 
-		/* already linked */
-		if (per_cpu(threshold_banks, cpu)[bank])
-			goto out;
+			per_cpu(threshold_banks, cpu)[bank] = b;
+			atomic_inc(&b->cpus);
 
-		b = per_cpu(threshold_banks, i)[bank];
+			err = __threshold_add_blocks(b);
 
-		if (!b)
 			goto out;
-
-		err = sysfs_create_link(&dev->kobj, b->kobj, name);
-		if (err)
-			goto out;
-
-		cpumask_copy(b->cpus, cpu_llc_shared_mask(cpu));
-		per_cpu(threshold_banks, cpu)[bank] = b;
-
-		goto out;
+		}
 	}
-#endif
 
 	b = kzalloc(sizeof(struct threshold_bank), GFP_KERNEL);
 	if (!b) {
 		err = -ENOMEM;
 		goto out;
 	}
-	if (!zalloc_cpumask_var(&b->cpus, GFP_KERNEL)) {
-		kfree(b);
-		err = -ENOMEM;
-		goto out;
-	}
 
 	b->kobj = kobject_create_and_add(name, &dev->kobj);
-	if (!b->kobj)
+	if (!b->kobj) {
+		err = -EINVAL;
 		goto out_free;
-
-#ifndef CONFIG_SMP
-	cpumask_setall(b->cpus);
-#else
-	cpumask_set_cpu(cpu, b->cpus);
-#endif
+	}
 
 	per_cpu(threshold_banks, cpu)[bank] = b;
 
-	err = local_allocate_threshold_blocks(cpu, bank);
-	if (err)
-		goto out_free;
-
-	for_each_cpu(i, b->cpus) {
-		if (i == cpu)
-			continue;
-
-		dev = per_cpu(mce_device, i);
-		if (dev)
-			err = sysfs_create_link(&dev->kobj,b->kobj, name);
-		if (err)
-			goto out;
+	if (shared_bank[bank]) {
+		atomic_set(&b->cpus, 1);
 
-		per_cpu(threshold_banks, i)[bank] = b;
+		/* nb is already initialized, see above */
+		WARN_ON(nb->bank4);
+		nb->bank4 = b;
 	}
 
-	goto out;
+	err = allocate_threshold_blocks(cpu, bank, 0,
+					MSR_IA32_MC0_MISC + bank * 4);
+	if (!err)
+		goto out;
 
-out_free:
-	per_cpu(threshold_banks, cpu)[bank] = NULL;
-	free_cpumask_var(b->cpus);
+ out_free:
 	kfree(b);
-out:
+
+ out:
 	return err;
 }
 
@@ -660,12 +648,6 @@ static __cpuinit int threshold_create_device(unsigned int cpu)
 	return err;
 }
 
-/*
- * let's be hotplug friendly.
- * in case of multiple core processors, the first core always takes ownership
- *   of shared sysfs dir/files, and rest of the cores will be symlinked to it.
- */
-
 static void deallocate_threshold_block(unsigned int cpu,
 						 unsigned int bank)
 {
@@ -686,41 +668,42 @@ static void deallocate_threshold_block(unsigned int cpu,
 	per_cpu(threshold_banks, cpu)[bank]->blocks = NULL;
 }
 
+static void __threshold_remove_blocks(struct threshold_bank *b)
+{
+	struct threshold_block *pos = NULL;
+	struct threshold_block *tmp = NULL;
+
+	kobject_del(b->kobj);
+
+	list_for_each_entry_safe(pos, tmp, &b->blocks->miscj, miscj)
+		kobject_del(&pos->kobj);
+}
+
 static void threshold_remove_bank(unsigned int cpu, int bank)
 {
+	struct amd_northbridge *nb;
 	struct threshold_bank *b;
-	struct device *dev;
-	char name[32];
-	int i = 0;
 
 	b = per_cpu(threshold_banks, cpu)[bank];
 	if (!b)
 		return;
+
 	if (!b->blocks)
 		goto free_out;
 
-	sprintf(name, "threshold_bank%i", bank);
-
-#ifdef CONFIG_SMP
-	/* sibling symlink */
-	if (shared_bank[bank] && b->blocks->cpu != cpu) {
-		dev = per_cpu(mce_device, cpu);
-		sysfs_remove_link(&dev->kobj, name);
-		per_cpu(threshold_banks, cpu)[bank] = NULL;
-
-		return;
-	}
-#endif
-
-	/* remove all sibling symlinks before unregistering */
-	for_each_cpu(i, b->cpus) {
-		if (i == cpu)
-			continue;
-
-		dev = per_cpu(mce_device, i);
-		if (dev)
-			sysfs_remove_link(&dev->kobj, name);
-		per_cpu(threshold_banks, i)[bank] = NULL;
+	if (shared_bank[bank]) {
+		if (!atomic_dec_and_test(&b->cpus)) {
+			__threshold_remove_blocks(b);
+			per_cpu(threshold_banks, cpu)[bank] = NULL;
+			return;
+		} else {
+			/*
+			 * the last CPU on this node using the shared bank is
+			 * going away, remove that bank now.
+			 */
+			nb = node_to_amd_nb(amd_get_nb_id(cpu));
+			nb->bank4 = NULL;
+		}
 	}
 
 	deallocate_threshold_block(cpu, bank);
@@ -728,7 +711,6 @@ static void threshold_remove_bank(unsigned int cpu, int bank)
 free_out:
 	kobject_del(b->kobj);
 	kobject_put(b->kobj);
-	free_cpumask_var(b->cpus);
 	kfree(b);
 	per_cpu(threshold_banks, cpu)[bank] = NULL;
 }
@@ -777,4 +759,24 @@ static __init int threshold_init_device(void)
 
 	return 0;
 }
-device_initcall(threshold_init_device);
+/*
+ * there are 3 funcs which need to be _initcalled in a logic sequence:
+ * 1. xen_late_init_mcelog
+ * 2. mcheck_init_device
+ * 3. threshold_init_device
+ *
+ * xen_late_init_mcelog must register xen_mce_chrdev_device before
+ * native mce_chrdev_device registration if running under xen platform;
+ *
+ * mcheck_init_device should be inited before threshold_init_device to
+ * initialize mce_device, otherwise a NULL ptr dereference will cause panic.
+ *
+ * so we use following _initcalls
+ * 1. device_initcall(xen_late_init_mcelog);
+ * 2. device_initcall_sync(mcheck_init_device);
+ * 3. late_initcall(threshold_init_device);
+ *
+ * when running under xen, the initcall order is 1,2,3;
+ * on baremetal, we skip 1 and we do only 2 and 3.
+ */
+late_initcall(threshold_init_device);
diff --git a/arch/x86/kernel/cpu/mkcapflags.pl b/arch/x86/kernel/cpu/mkcapflags.pl
index dfea390..c7b3fe2 100644
--- a/arch/x86/kernel/cpu/mkcapflags.pl
+++ b/arch/x86/kernel/cpu/mkcapflags.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/perl -w
 #
 # Generate the x86_cap_flags[] array from include/asm-x86/cpufeature.h
 #
@@ -11,22 +11,35 @@ open(OUT, "> $out\0") or die "$0: cannot create: $out: $!\n";
 print OUT "#include <asm/cpufeature.h>\n\n";
 print OUT "const char * const x86_cap_flags[NCAPINTS*32] = {\n";
 
+%features = ();
+$err = 0;
+
 while (defined($line = <IN>)) {
 	if ($line =~ /^\s*\#\s*define\s+(X86_FEATURE_(\S+))\s+(.*)$/) {
 		$macro = $1;
-		$feature = $2;
+		$feature = "\L$2";
 		$tail = $3;
 		if ($tail =~ /\/\*\s*\"([^"]*)\".*\*\//) {
-			$feature = $1;
+			$feature = "\L$1";
 		}
 
-		if ($feature ne '') {
-			printf OUT "\t%-32s = \"%s\",\n",
-				"[$macro]", "\L$feature";
+		next if ($feature eq '');
+
+		if ($features{$feature}++) {
+			print STDERR "$in: duplicate feature name: $feature\n";
+			$err++;
 		}
+		printf OUT "\t%-32s = \"%s\",\n", "[$macro]", $feature;
 	}
 }
 print OUT "};\n";
 
 close(IN);
 close(OUT);
+
+if ($err) {
+	unlink($out);
+	exit(1);
+}
+
+exit(0);
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index c4706cf..41db515 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -35,17 +35,6 @@
 
 #include "perf_event.h"
 
-#if 0
-#undef wrmsrl
-#define wrmsrl(msr, val) 					\
-do {								\
-	trace_printk("wrmsrl(%lx, %lx)\n", (unsigned long)(msr),\
-			(unsigned long)(val));			\
-	native_write_msr((msr), (u32)((u64)(val)), 		\
-			(u32)((u64)(val) >> 32));		\
-} while (0)
-#endif
-
 struct x86_pmu x86_pmu __read_mostly;
 
 DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
@@ -86,7 +75,7 @@ u64 x86_perf_event_update(struct perf_event *event)
 	 */
 again:
 	prev_raw_count = local64_read(&hwc->prev_count);
-	rdmsrl(hwc->event_base, new_raw_count);
+	rdpmcl(hwc->event_base_rdpmc, new_raw_count);
 
 	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
 					new_raw_count) != prev_raw_count)
@@ -222,7 +211,7 @@ static bool check_hw_exists(void)
 	 * that don't trap on the MSR access and always return 0s.
 	 */
 	val = 0xabcdUL;
-	ret = checking_wrmsrl(x86_pmu_event_addr(0), val);
+	ret = wrmsrl_safe(x86_pmu_event_addr(0), val);
 	ret |= rdmsrl_safe(x86_pmu_event_addr(0), &val_new);
 	if (ret || val != val_new)
 		goto msr_fail;
@@ -637,7 +626,7 @@ static bool __perf_sched_find_counter(struct perf_sched *sched)
 	c = sched->constraints[sched->state.event];
 
 	/* Prefer fixed purpose counters */
-	if (x86_pmu.num_counters_fixed) {
+	if (c->idxmsk64 & (~0ULL << X86_PMC_IDX_FIXED)) {
 		idx = X86_PMC_IDX_FIXED;
 		for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_MAX) {
 			if (!__test_and_set_bit(idx, sched->state.used))
@@ -704,8 +693,8 @@ static bool perf_sched_next_event(struct perf_sched *sched)
 /*
  * Assign a counter for each event.
  */
-static int perf_assign_events(struct event_constraint **constraints, int n,
-			      int wmin, int wmax, int *assign)
+int perf_assign_events(struct event_constraint **constraints, int n,
+			int wmin, int wmax, int *assign)
 {
 	struct perf_sched sched;
 
@@ -830,9 +819,11 @@ static inline void x86_assign_hw_event(struct perf_event *event,
 	} else if (hwc->idx >= X86_PMC_IDX_FIXED) {
 		hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL;
 		hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0 + (hwc->idx - X86_PMC_IDX_FIXED);
+		hwc->event_base_rdpmc = (hwc->idx - X86_PMC_IDX_FIXED) | 1<<30;
 	} else {
 		hwc->config_base = x86_pmu_config_addr(hwc->idx);
 		hwc->event_base  = x86_pmu_event_addr(hwc->idx);
+		hwc->event_base_rdpmc = hwc->idx;
 	}
 }
 
@@ -1649,7 +1640,12 @@ static ssize_t set_attr_rdpmc(struct device *cdev,
 			      struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
-	unsigned long val = simple_strtoul(buf, NULL, 0);
+	unsigned long val;
+	ssize_t ret;
+
+	ret = kstrtoul(buf, 0, &val);
+	if (ret)
+		return ret;
 
 	if (!!val != !!x86_pmu.attr_rdpmc) {
 		x86_pmu.attr_rdpmc = !!val;
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 7241e2f..83238f2 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -14,6 +14,18 @@
 
 #include <linux/perf_event.h>
 
+#if 0
+#undef wrmsrl
+#define wrmsrl(msr, val) 						\
+do {									\
+	unsigned int _msr = (msr);					\
+	u64 _val = (val);						\
+	trace_printk("wrmsrl(%x, %Lx)\n", (unsigned int)(_msr),		\
+			(unsigned long long)(_val));			\
+	native_write_msr((_msr), (u32)(_val), (u32)(_val >> 32));	\
+} while (0)
+#endif
+
 /*
  *          |   NHM/WSM    |      SNB     |
  * register -------------------------------
@@ -57,7 +69,7 @@ struct amd_nb {
 };
 
 /* The maximal number of PEBS events: */
-#define MAX_PEBS_EVENTS		4
+#define MAX_PEBS_EVENTS		8
 
 /*
  * A debug store configuration.
@@ -366,6 +378,7 @@ struct x86_pmu {
 	void		(*drain_pebs)(struct pt_regs *regs);
 	struct event_constraint *pebs_constraints;
 	void		(*pebs_aliases)(struct perf_event *event);
+	int 		max_pebs_events;
 
 	/*
 	 * Intel LBR
@@ -468,6 +481,8 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
 
 void x86_pmu_enable_all(int added);
 
+int perf_assign_events(struct event_constraint **constraints, int n,
+			int wmin, int wmax, int *assign);
 int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign);
 
 void x86_pmu_stop(struct perf_event *event, int flags);
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 187c294..364a093 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -5,6 +5,8 @@
  * among events on a single PMU.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/stddef.h>
 #include <linux/types.h>
 #include <linux/init.h>
@@ -1000,14 +1002,14 @@ static void intel_pmu_reset(void)
 
 	local_irq_save(flags);
 
-	printk("clearing PMU state on CPU#%d\n", smp_processor_id());
+	pr_info("clearing PMU state on CPU#%d\n", smp_processor_id());
 
 	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
-		checking_wrmsrl(x86_pmu_config_addr(idx), 0ull);
-		checking_wrmsrl(x86_pmu_event_addr(idx),  0ull);
+		wrmsrl_safe(x86_pmu_config_addr(idx), 0ull);
+		wrmsrl_safe(x86_pmu_event_addr(idx),  0ull);
 	}
 	for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++)
-		checking_wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull);
+		wrmsrl_safe(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull);
 
 	if (ds)
 		ds->bts_index = ds->bts_buffer_base;
@@ -1707,14 +1709,14 @@ static __init void intel_clovertown_quirk(void)
 	 * But taken together it might just make sense to not enable PEBS on
 	 * these chips.
 	 */
-	printk(KERN_WARNING "PEBS disabled due to CPU errata.\n");
+	pr_warn("PEBS disabled due to CPU errata\n");
 	x86_pmu.pebs = 0;
 	x86_pmu.pebs_constraints = NULL;
 }
 
 static __init void intel_sandybridge_quirk(void)
 {
-	printk(KERN_WARNING "PEBS disabled due to CPU errata.\n");
+	pr_warn("PEBS disabled due to CPU errata\n");
 	x86_pmu.pebs = 0;
 	x86_pmu.pebs_constraints = NULL;
 }
@@ -1736,8 +1738,8 @@ static __init void intel_arch_events_quirk(void)
 	/* disable event that reported as not presend by cpuid */
 	for_each_set_bit(bit, x86_pmu.events_mask, ARRAY_SIZE(intel_arch_events_map)) {
 		intel_perfmon_event_map[intel_arch_events_map[bit].id] = 0;
-		printk(KERN_WARNING "CPUID marked event: \'%s\' unavailable\n",
-				intel_arch_events_map[bit].name);
+		pr_warn("CPUID marked event: \'%s\' unavailable\n",
+			intel_arch_events_map[bit].name);
 	}
 }
 
@@ -1756,7 +1758,7 @@ static __init void intel_nehalem_quirk(void)
 		intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89;
 		ebx.split.no_branch_misses_retired = 0;
 		x86_pmu.events_maskl = ebx.full;
-		printk(KERN_INFO "CPU erratum AAJ80 worked around\n");
+		pr_info("CPU erratum AAJ80 worked around\n");
 	}
 }
 
@@ -1800,6 +1802,8 @@ __init int intel_pmu_init(void)
 	x86_pmu.events_maskl		= ebx.full;
 	x86_pmu.events_mask_len		= eax.split.mask_length;
 
+	x86_pmu.max_pebs_events		= min_t(unsigned, MAX_PEBS_EVENTS, x86_pmu.num_counters);
+
 	/*
 	 * Quirk: v2 perfmon does not report fixed-purpose events, so
 	 * assume at least 3 events:
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 35e2192..026373e 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -620,7 +620,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
 	 * Should not happen, we program the threshold at 1 and do not
 	 * set a reset value.
 	 */
-	WARN_ON_ONCE(n > 1);
+	WARN_ONCE(n > 1, "bad leftover pebs %d\n", n);
 	at += n - 1;
 
 	__intel_pmu_pebs_event(event, iregs, at);
@@ -651,10 +651,10 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
 	 * Should not happen, we program the threshold at 1 and do not
 	 * set a reset value.
 	 */
-	WARN_ON_ONCE(n > MAX_PEBS_EVENTS);
+	WARN_ONCE(n > x86_pmu.max_pebs_events, "Unexpected number of pebs records %d\n", n);
 
 	for ( ; at < top; at++) {
-		for_each_set_bit(bit, (unsigned long *)&at->status, MAX_PEBS_EVENTS) {
+		for_each_set_bit(bit, (unsigned long *)&at->status, x86_pmu.max_pebs_events) {
 			event = cpuc->events[bit];
 			if (!test_bit(bit, cpuc->active_mask))
 				continue;
@@ -670,7 +670,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
 			break;
 		}
 
-		if (!event || bit >= MAX_PEBS_EVENTS)
+		if (!event || bit >= x86_pmu.max_pebs_events)
 			continue;
 
 		__intel_pmu_pebs_event(event, iregs, at);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
new file mode 100644
index 0000000..6f43f95
--- /dev/null
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -0,0 +1,1703 @@
+#include "perf_event_intel_uncore.h"
+
+static struct intel_uncore_type *empty_uncore[] = { NULL, };
+static struct intel_uncore_type **msr_uncores = empty_uncore;
+static struct intel_uncore_type **pci_uncores = empty_uncore;
+/* pci bus to socket mapping */
+static int pcibus_to_physid[256] = { [0 ... 255] = -1, };
+
+static DEFINE_RAW_SPINLOCK(uncore_box_lock);
+
+/* mask of cpus that collect uncore events */
+static cpumask_t uncore_cpu_mask;
+
+/* constraint for the fixed counter */
+static struct event_constraint constraint_fixed =
+	EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL);
+
+DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
+DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
+DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28");
+DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28");
+DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15");
+DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30");
+DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
+
+/* Sandy Bridge-EP uncore support */
+static void snbep_uncore_pci_disable_box(struct intel_uncore_box *box)
+{
+	struct pci_dev *pdev = box->pci_dev;
+	int box_ctl = uncore_pci_box_ctl(box);
+	u32 config;
+
+	pci_read_config_dword(pdev, box_ctl, &config);
+	config |= SNBEP_PMON_BOX_CTL_FRZ;
+	pci_write_config_dword(pdev, box_ctl, config);
+}
+
+static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box)
+{
+	struct pci_dev *pdev = box->pci_dev;
+	int box_ctl = uncore_pci_box_ctl(box);
+	u32 config;
+
+	pci_read_config_dword(pdev, box_ctl, &config);
+	config &= ~SNBEP_PMON_BOX_CTL_FRZ;
+	pci_write_config_dword(pdev, box_ctl, config);
+}
+
+static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box,
+					struct perf_event *event)
+{
+	struct pci_dev *pdev = box->pci_dev;
+	struct hw_perf_event *hwc = &event->hw;
+
+	pci_write_config_dword(pdev, hwc->config_base, hwc->config |
+				SNBEP_PMON_CTL_EN);
+}
+
+static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box,
+					struct perf_event *event)
+{
+	struct pci_dev *pdev = box->pci_dev;
+	struct hw_perf_event *hwc = &event->hw;
+
+	pci_write_config_dword(pdev, hwc->config_base, hwc->config);
+}
+
+static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box,
+					struct perf_event *event)
+{
+	struct pci_dev *pdev = box->pci_dev;
+	struct hw_perf_event *hwc = &event->hw;
+	u64 count;
+
+	pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count);
+	pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1);
+	return count;
+}
+
+static void snbep_uncore_pci_init_box(struct intel_uncore_box *box)
+{
+	struct pci_dev *pdev = box->pci_dev;
+	pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL,
+				SNBEP_PMON_BOX_CTL_INT);
+}
+
+static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+	u64 config;
+	unsigned msr;
+
+	msr = uncore_msr_box_ctl(box);
+	if (msr) {
+		rdmsrl(msr, config);
+		config |= SNBEP_PMON_BOX_CTL_FRZ;
+		wrmsrl(msr, config);
+		return;
+	}
+}
+
+static void snbep_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+	u64 config;
+	unsigned msr;
+
+	msr = uncore_msr_box_ctl(box);
+	if (msr) {
+		rdmsrl(msr, config);
+		config &= ~SNBEP_PMON_BOX_CTL_FRZ;
+		wrmsrl(msr, config);
+		return;
+	}
+}
+
+static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box,
+					struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static void snbep_uncore_msr_disable_event(struct intel_uncore_box *box,
+					struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	wrmsrl(hwc->config_base, hwc->config);
+}
+
+static u64 snbep_uncore_msr_read_counter(struct intel_uncore_box *box,
+					struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	u64 count;
+
+	rdmsrl(hwc->event_base, count);
+	return count;
+}
+
+static void snbep_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+	unsigned msr = uncore_msr_box_ctl(box);
+	if (msr)
+		wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT);
+}
+
+static struct attribute *snbep_uncore_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh8.attr,
+	NULL,
+};
+
+static struct attribute *snbep_uncore_ubox_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh5.attr,
+	NULL,
+};
+
+static struct attribute *snbep_uncore_pcu_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_occ_sel.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_thresh5.attr,
+	&format_attr_occ_invert.attr,
+	&format_attr_occ_edge.attr,
+	NULL,
+};
+
+static struct uncore_event_desc snbep_uncore_imc_events[] = {
+	INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0xff,umask=0xff"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"),
+	INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
+	{ /* end: all zeroes */ },
+};
+
+static struct uncore_event_desc snbep_uncore_qpi_events[] = {
+	INTEL_UNCORE_EVENT_DESC(clockticks,       "event=0x14"),
+	INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x00,umask=0x06"),
+	INTEL_UNCORE_EVENT_DESC(drs_data,         "event=0x02,umask=0x08"),
+	INTEL_UNCORE_EVENT_DESC(ncb_data,         "event=0x03,umask=0x04"),
+	{ /* end: all zeroes */ },
+};
+
+static struct attribute_group snbep_uncore_format_group = {
+	.name = "format",
+	.attrs = snbep_uncore_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_ubox_format_group = {
+	.name = "format",
+	.attrs = snbep_uncore_ubox_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_pcu_format_group = {
+	.name = "format",
+	.attrs = snbep_uncore_pcu_formats_attr,
+};
+
+static struct intel_uncore_ops snbep_uncore_msr_ops = {
+	.init_box	= snbep_uncore_msr_init_box,
+	.disable_box	= snbep_uncore_msr_disable_box,
+	.enable_box	= snbep_uncore_msr_enable_box,
+	.disable_event	= snbep_uncore_msr_disable_event,
+	.enable_event	= snbep_uncore_msr_enable_event,
+	.read_counter	= snbep_uncore_msr_read_counter,
+};
+
+static struct intel_uncore_ops snbep_uncore_pci_ops = {
+	.init_box	= snbep_uncore_pci_init_box,
+	.disable_box	= snbep_uncore_pci_disable_box,
+	.enable_box	= snbep_uncore_pci_enable_box,
+	.disable_event	= snbep_uncore_pci_disable_event,
+	.enable_event	= snbep_uncore_pci_enable_event,
+	.read_counter	= snbep_uncore_pci_read_counter,
+};
+
+static struct event_constraint snbep_uncore_cbox_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x01, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x02, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x04, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x05, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x07, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x13, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x1b, 0xc),
+	UNCORE_EVENT_CONSTRAINT(0x1c, 0xc),
+	UNCORE_EVENT_CONSTRAINT(0x1d, 0xc),
+	UNCORE_EVENT_CONSTRAINT(0x1e, 0xc),
+	UNCORE_EVENT_CONSTRAINT(0x1f, 0xe),
+	UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x35, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x3b, 0x1),
+	EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint snbep_uncore_r2pcie_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x12, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+	EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint snbep_uncore_r3qpi_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x30, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
+	UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+	EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type snbep_uncore_ubox = {
+	.name		= "ubox",
+	.num_counters   = 2,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 44,
+	.fixed_ctr_bits	= 48,
+	.perf_ctr	= SNBEP_U_MSR_PMON_CTR0,
+	.event_ctl	= SNBEP_U_MSR_PMON_CTL0,
+	.event_mask	= SNBEP_U_MSR_PMON_RAW_EVENT_MASK,
+	.fixed_ctr	= SNBEP_U_MSR_PMON_UCLK_FIXED_CTR,
+	.fixed_ctl	= SNBEP_U_MSR_PMON_UCLK_FIXED_CTL,
+	.ops		= &snbep_uncore_msr_ops,
+	.format_group	= &snbep_uncore_ubox_format_group,
+};
+
+static struct intel_uncore_type snbep_uncore_cbox = {
+	.name		= "cbox",
+	.num_counters   = 4,
+	.num_boxes	= 8,
+	.perf_ctr_bits	= 44,
+	.event_ctl	= SNBEP_C0_MSR_PMON_CTL0,
+	.perf_ctr	= SNBEP_C0_MSR_PMON_CTR0,
+	.event_mask	= SNBEP_PMON_RAW_EVENT_MASK,
+	.box_ctl	= SNBEP_C0_MSR_PMON_BOX_CTL,
+	.msr_offset	= SNBEP_CBO_MSR_OFFSET,
+	.constraints	= snbep_uncore_cbox_constraints,
+	.ops		= &snbep_uncore_msr_ops,
+	.format_group	= &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type snbep_uncore_pcu = {
+	.name		= "pcu",
+	.num_counters   = 4,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 48,
+	.perf_ctr	= SNBEP_PCU_MSR_PMON_CTR0,
+	.event_ctl	= SNBEP_PCU_MSR_PMON_CTL0,
+	.event_mask	= SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
+	.box_ctl	= SNBEP_PCU_MSR_PMON_BOX_CTL,
+	.ops		= &snbep_uncore_msr_ops,
+	.format_group	= &snbep_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *snbep_msr_uncores[] = {
+	&snbep_uncore_ubox,
+	&snbep_uncore_cbox,
+	&snbep_uncore_pcu,
+	NULL,
+};
+
+#define SNBEP_UNCORE_PCI_COMMON_INIT()				\
+	.perf_ctr	= SNBEP_PCI_PMON_CTR0,			\
+	.event_ctl	= SNBEP_PCI_PMON_CTL0,			\
+	.event_mask	= SNBEP_PMON_RAW_EVENT_MASK,		\
+	.box_ctl	= SNBEP_PCI_PMON_BOX_CTL,		\
+	.ops		= &snbep_uncore_pci_ops,		\
+	.format_group	= &snbep_uncore_format_group
+
+static struct intel_uncore_type snbep_uncore_ha = {
+	.name		= "ha",
+	.num_counters   = 4,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 48,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_imc = {
+	.name		= "imc",
+	.num_counters   = 4,
+	.num_boxes	= 4,
+	.perf_ctr_bits	= 48,
+	.fixed_ctr_bits	= 48,
+	.fixed_ctr	= SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
+	.fixed_ctl	= SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
+	.event_descs	= snbep_uncore_imc_events,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_qpi = {
+	.name		= "qpi",
+	.num_counters   = 4,
+	.num_boxes	= 2,
+	.perf_ctr_bits	= 48,
+	.event_descs	= snbep_uncore_qpi_events,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+
+static struct intel_uncore_type snbep_uncore_r2pcie = {
+	.name		= "r2pcie",
+	.num_counters   = 4,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 44,
+	.constraints	= snbep_uncore_r2pcie_constraints,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_r3qpi = {
+	.name		= "r3qpi",
+	.num_counters   = 3,
+	.num_boxes	= 2,
+	.perf_ctr_bits	= 44,
+	.constraints	= snbep_uncore_r3qpi_constraints,
+	SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type *snbep_pci_uncores[] = {
+	&snbep_uncore_ha,
+	&snbep_uncore_imc,
+	&snbep_uncore_qpi,
+	&snbep_uncore_r2pcie,
+	&snbep_uncore_r3qpi,
+	NULL,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(snbep_uncore_pci_ids) = {
+	{ /* Home Agent */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA),
+		.driver_data = (unsigned long)&snbep_uncore_ha,
+	},
+	{ /* MC Channel 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0),
+		.driver_data = (unsigned long)&snbep_uncore_imc,
+	},
+	{ /* MC Channel 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1),
+		.driver_data = (unsigned long)&snbep_uncore_imc,
+	},
+	{ /* MC Channel 2 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2),
+		.driver_data = (unsigned long)&snbep_uncore_imc,
+	},
+	{ /* MC Channel 3 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3),
+		.driver_data = (unsigned long)&snbep_uncore_imc,
+	},
+	{ /* QPI Port 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0),
+		.driver_data = (unsigned long)&snbep_uncore_qpi,
+	},
+	{ /* QPI Port 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1),
+		.driver_data = (unsigned long)&snbep_uncore_qpi,
+	},
+	{ /* P2PCIe */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE),
+		.driver_data = (unsigned long)&snbep_uncore_r2pcie,
+	},
+	{ /* R3QPI Link 0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0),
+		.driver_data = (unsigned long)&snbep_uncore_r3qpi,
+	},
+	{ /* R3QPI Link 1 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1),
+		.driver_data = (unsigned long)&snbep_uncore_r3qpi,
+	},
+	{ /* end: all zeroes */ }
+};
+
+static struct pci_driver snbep_uncore_pci_driver = {
+	.name		= "snbep_uncore",
+	.id_table	= snbep_uncore_pci_ids,
+};
+
+/*
+ * build pci bus to socket mapping
+ */
+static void snbep_pci2phy_map_init(void)
+{
+	struct pci_dev *ubox_dev = NULL;
+	int i, bus, nodeid;
+	u32 config;
+
+	while (1) {
+		/* find the UBOX device */
+		ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX,
+					ubox_dev);
+		if (!ubox_dev)
+			break;
+		bus = ubox_dev->bus->number;
+		/* get the Node ID of the local register */
+		pci_read_config_dword(ubox_dev, 0x40, &config);
+		nodeid = config;
+		/* get the Node ID mapping */
+		pci_read_config_dword(ubox_dev, 0x54, &config);
+		/*
+		 * every three bits in the Node ID mapping register maps
+		 * to a particular node.
+		 */
+		for (i = 0; i < 8; i++) {
+			if (nodeid == ((config >> (3 * i)) & 0x7)) {
+				pcibus_to_physid[bus] = i;
+				break;
+			}
+		}
+	};
+	return;
+}
+/* end of Sandy Bridge-EP uncore support */
+
+
+/* Sandy Bridge uncore support */
+static void snb_uncore_msr_enable_event(struct intel_uncore_box *box,
+					struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (hwc->idx < UNCORE_PMC_IDX_FIXED)
+		wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
+	else
+		wrmsrl(hwc->config_base, SNB_UNC_CTL_EN);
+}
+
+static void snb_uncore_msr_disable_event(struct intel_uncore_box *box,
+					struct perf_event *event)
+{
+	wrmsrl(event->hw.config_base, 0);
+}
+
+static u64 snb_uncore_msr_read_counter(struct intel_uncore_box *box,
+					struct perf_event *event)
+{
+	u64 count;
+	rdmsrl(event->hw.event_base, count);
+	return count;
+}
+
+static void snb_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+	if (box->pmu->pmu_idx == 0) {
+		wrmsrl(SNB_UNC_PERF_GLOBAL_CTL,
+			SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL);
+	}
+}
+
+static struct attribute *snb_uncore_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask5.attr,
+	NULL,
+};
+
+static struct attribute_group snb_uncore_format_group = {
+	.name = "format",
+	.attrs = snb_uncore_formats_attr,
+};
+
+static struct intel_uncore_ops snb_uncore_msr_ops = {
+	.init_box	= snb_uncore_msr_init_box,
+	.disable_event	= snb_uncore_msr_disable_event,
+	.enable_event	= snb_uncore_msr_enable_event,
+	.read_counter	= snb_uncore_msr_read_counter,
+};
+
+static struct event_constraint snb_uncore_cbox_constraints[] = {
+	UNCORE_EVENT_CONSTRAINT(0x80, 0x1),
+	UNCORE_EVENT_CONSTRAINT(0x83, 0x1),
+	EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type snb_uncore_cbox = {
+	.name		= "cbox",
+	.num_counters   = 2,
+	.num_boxes	= 4,
+	.perf_ctr_bits	= 44,
+	.fixed_ctr_bits	= 48,
+	.perf_ctr	= SNB_UNC_CBO_0_PER_CTR0,
+	.event_ctl	= SNB_UNC_CBO_0_PERFEVTSEL0,
+	.fixed_ctr	= SNB_UNC_FIXED_CTR,
+	.fixed_ctl	= SNB_UNC_FIXED_CTR_CTRL,
+	.single_fixed	= 1,
+	.event_mask	= SNB_UNC_RAW_EVENT_MASK,
+	.msr_offset	= SNB_UNC_CBO_MSR_OFFSET,
+	.constraints	= snb_uncore_cbox_constraints,
+	.ops		= &snb_uncore_msr_ops,
+	.format_group	= &snb_uncore_format_group,
+};
+
+static struct intel_uncore_type *snb_msr_uncores[] = {
+	&snb_uncore_cbox,
+	NULL,
+};
+/* end of Sandy Bridge uncore support */
+
+/* Nehalem uncore support */
+static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+	wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0);
+}
+
+static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+	wrmsrl(NHM_UNC_PERF_GLOBAL_CTL,
+		NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC);
+}
+
+static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box,
+					struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (hwc->idx < UNCORE_PMC_IDX_FIXED)
+		wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
+	else
+		wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN);
+}
+
+static struct attribute *nhm_uncore_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask8.attr,
+	NULL,
+};
+
+static struct attribute_group nhm_uncore_format_group = {
+	.name = "format",
+	.attrs = nhm_uncore_formats_attr,
+};
+
+static struct uncore_event_desc nhm_uncore_events[] = {
+	INTEL_UNCORE_EVENT_DESC(clockticks,                "event=0xff,umask=0xff"),
+	INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any,       "event=0x2f,umask=0x0f"),
+	INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any,      "event=0x2c,umask=0x0f"),
+	INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads,     "event=0x20,umask=0x01"),
+	INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes,    "event=0x20,umask=0x02"),
+	INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads,  "event=0x20,umask=0x04"),
+	INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"),
+	INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads,   "event=0x20,umask=0x10"),
+	INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes,  "event=0x20,umask=0x20"),
+	{ /* end: all zeroes */ },
+};
+
+static struct intel_uncore_ops nhm_uncore_msr_ops = {
+	.disable_box	= nhm_uncore_msr_disable_box,
+	.enable_box	= nhm_uncore_msr_enable_box,
+	.disable_event	= snb_uncore_msr_disable_event,
+	.enable_event	= nhm_uncore_msr_enable_event,
+	.read_counter	= snb_uncore_msr_read_counter,
+};
+
+static struct intel_uncore_type nhm_uncore = {
+	.name		= "",
+	.num_counters   = 8,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 48,
+	.fixed_ctr_bits	= 48,
+	.event_ctl	= NHM_UNC_PERFEVTSEL0,
+	.perf_ctr	= NHM_UNC_UNCORE_PMC0,
+	.fixed_ctr	= NHM_UNC_FIXED_CTR,
+	.fixed_ctl	= NHM_UNC_FIXED_CTR_CTRL,
+	.event_mask	= NHM_UNC_RAW_EVENT_MASK,
+	.event_descs	= nhm_uncore_events,
+	.ops		= &nhm_uncore_msr_ops,
+	.format_group	= &nhm_uncore_format_group,
+};
+
+static struct intel_uncore_type *nhm_msr_uncores[] = {
+	&nhm_uncore,
+	NULL,
+};
+/* end of Nehalem uncore support */
+
+static void uncore_assign_hw_event(struct intel_uncore_box *box,
+				struct perf_event *event, int idx)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	hwc->idx = idx;
+	hwc->last_tag = ++box->tags[idx];
+
+	if (hwc->idx == UNCORE_PMC_IDX_FIXED) {
+		hwc->event_base = uncore_fixed_ctr(box);
+		hwc->config_base = uncore_fixed_ctl(box);
+		return;
+	}
+
+	hwc->config_base = uncore_event_ctl(box, hwc->idx);
+	hwc->event_base  = uncore_perf_ctr(box, hwc->idx);
+}
+
+static void uncore_perf_event_update(struct intel_uncore_box *box,
+					struct perf_event *event)
+{
+	u64 prev_count, new_count, delta;
+	int shift;
+
+	if (event->hw.idx >= UNCORE_PMC_IDX_FIXED)
+		shift = 64 - uncore_fixed_ctr_bits(box);
+	else
+		shift = 64 - uncore_perf_ctr_bits(box);
+
+	/* the hrtimer might modify the previous event value */
+again:
+	prev_count = local64_read(&event->hw.prev_count);
+	new_count = uncore_read_counter(box, event);
+	if (local64_xchg(&event->hw.prev_count, new_count) != prev_count)
+		goto again;
+
+	delta = (new_count << shift) - (prev_count << shift);
+	delta >>= shift;
+
+	local64_add(delta, &event->count);
+}
+
+/*
+ * The overflow interrupt is unavailable for SandyBridge-EP, is broken
+ * for SandyBridge. So we use hrtimer to periodically poll the counter
+ * to avoid overflow.
+ */
+static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
+{
+	struct intel_uncore_box *box;
+	unsigned long flags;
+	int bit;
+
+	box = container_of(hrtimer, struct intel_uncore_box, hrtimer);
+	if (!box->n_active || box->cpu != smp_processor_id())
+		return HRTIMER_NORESTART;
+	/*
+	 * disable local interrupt to prevent uncore_pmu_event_start/stop
+	 * to interrupt the update process
+	 */
+	local_irq_save(flags);
+
+	for_each_set_bit(bit, box->active_mask, UNCORE_PMC_IDX_MAX)
+		uncore_perf_event_update(box, box->events[bit]);
+
+	local_irq_restore(flags);
+
+	hrtimer_forward_now(hrtimer, ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL));
+	return HRTIMER_RESTART;
+}
+
+static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box)
+{
+	__hrtimer_start_range_ns(&box->hrtimer,
+			ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL), 0,
+			HRTIMER_MODE_REL_PINNED, 0);
+}
+
+static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box)
+{
+	hrtimer_cancel(&box->hrtimer);
+}
+
+static void uncore_pmu_init_hrtimer(struct intel_uncore_box *box)
+{
+	hrtimer_init(&box->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	box->hrtimer.function = uncore_pmu_hrtimer;
+}
+
+struct intel_uncore_box *uncore_alloc_box(int cpu)
+{
+	struct intel_uncore_box *box;
+
+	box = kmalloc_node(sizeof(*box), GFP_KERNEL | __GFP_ZERO,
+			   cpu_to_node(cpu));
+	if (!box)
+		return NULL;
+
+	uncore_pmu_init_hrtimer(box);
+	atomic_set(&box->refcnt, 1);
+	box->cpu = -1;
+	box->phys_id = -1;
+
+	return box;
+}
+
+static struct intel_uncore_box *
+uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
+{
+	static struct intel_uncore_box *box;
+
+	box = *per_cpu_ptr(pmu->box, cpu);
+	if (box)
+		return box;
+
+	raw_spin_lock(&uncore_box_lock);
+	list_for_each_entry(box, &pmu->box_list, list) {
+		if (box->phys_id == topology_physical_package_id(cpu)) {
+			atomic_inc(&box->refcnt);
+			*per_cpu_ptr(pmu->box, cpu) = box;
+			break;
+		}
+	}
+	raw_spin_unlock(&uncore_box_lock);
+
+	return *per_cpu_ptr(pmu->box, cpu);
+}
+
+static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
+{
+	return container_of(event->pmu, struct intel_uncore_pmu, pmu);
+}
+
+static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
+{
+	/*
+	 * perf core schedules event on the basis of cpu, uncore events are
+	 * collected by one of the cpus inside a physical package.
+	 */
+	return uncore_pmu_to_box(uncore_event_to_pmu(event),
+				 smp_processor_id());
+}
+
+static int uncore_collect_events(struct intel_uncore_box *box,
+				struct perf_event *leader, bool dogrp)
+{
+	struct perf_event *event;
+	int n, max_count;
+
+	max_count = box->pmu->type->num_counters;
+	if (box->pmu->type->fixed_ctl)
+		max_count++;
+
+	if (box->n_events >= max_count)
+		return -EINVAL;
+
+	n = box->n_events;
+	box->event_list[n] = leader;
+	n++;
+	if (!dogrp)
+		return n;
+
+	list_for_each_entry(event, &leader->sibling_list, group_entry) {
+		if (event->state <= PERF_EVENT_STATE_OFF)
+			continue;
+
+		if (n >= max_count)
+			return -EINVAL;
+
+		box->event_list[n] = event;
+		n++;
+	}
+	return n;
+}
+
+static struct event_constraint *
+uncore_event_constraint(struct intel_uncore_type *type,
+			struct perf_event *event)
+{
+	struct event_constraint *c;
+
+	if (event->hw.config == ~0ULL)
+		return &constraint_fixed;
+
+	if (type->constraints) {
+		for_each_event_constraint(c, type->constraints) {
+			if ((event->hw.config & c->cmask) == c->code)
+				return c;
+		}
+	}
+
+	return &type->unconstrainted;
+}
+
+static int uncore_assign_events(struct intel_uncore_box *box,
+				int assign[], int n)
+{
+	unsigned long used_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)];
+	struct event_constraint *c, *constraints[UNCORE_PMC_IDX_MAX];
+	int i, ret, wmin, wmax;
+	struct hw_perf_event *hwc;
+
+	bitmap_zero(used_mask, UNCORE_PMC_IDX_MAX);
+
+	for (i = 0, wmin = UNCORE_PMC_IDX_MAX, wmax = 0; i < n; i++) {
+		c = uncore_event_constraint(box->pmu->type,
+				box->event_list[i]);
+		constraints[i] = c;
+		wmin = min(wmin, c->weight);
+		wmax = max(wmax, c->weight);
+	}
+
+	/* fastpath, try to reuse previous register */
+	for (i = 0; i < n; i++) {
+		hwc = &box->event_list[i]->hw;
+		c = constraints[i];
+
+		/* never assigned */
+		if (hwc->idx == -1)
+			break;
+
+		/* constraint still honored */
+		if (!test_bit(hwc->idx, c->idxmsk))
+			break;
+
+		/* not already used */
+		if (test_bit(hwc->idx, used_mask))
+			break;
+
+		__set_bit(hwc->idx, used_mask);
+		assign[i] = hwc->idx;
+	}
+	if (i == n)
+		return 0;
+
+	/* slow path */
+	ret = perf_assign_events(constraints, n, wmin, wmax, assign);
+	return ret ? -EINVAL : 0;
+}
+
+static void uncore_pmu_event_start(struct perf_event *event, int flags)
+{
+	struct intel_uncore_box *box = uncore_event_to_box(event);
+	int idx = event->hw.idx;
+
+	if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+		return;
+
+	if (WARN_ON_ONCE(idx == -1 || idx >= UNCORE_PMC_IDX_MAX))
+		return;
+
+	event->hw.state = 0;
+	box->events[idx] = event;
+	box->n_active++;
+	__set_bit(idx, box->active_mask);
+
+	local64_set(&event->hw.prev_count, uncore_read_counter(box, event));
+	uncore_enable_event(box, event);
+
+	if (box->n_active == 1) {
+		uncore_enable_box(box);
+		uncore_pmu_start_hrtimer(box);
+	}
+}
+
+static void uncore_pmu_event_stop(struct perf_event *event, int flags)
+{
+	struct intel_uncore_box *box = uncore_event_to_box(event);
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (__test_and_clear_bit(hwc->idx, box->active_mask)) {
+		uncore_disable_event(box, event);
+		box->n_active--;
+		box->events[hwc->idx] = NULL;
+		WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+		hwc->state |= PERF_HES_STOPPED;
+
+		if (box->n_active == 0) {
+			uncore_disable_box(box);
+			uncore_pmu_cancel_hrtimer(box);
+		}
+	}
+
+	if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+		/*
+		 * Drain the remaining delta count out of a event
+		 * that we are disabling:
+		 */
+		uncore_perf_event_update(box, event);
+		hwc->state |= PERF_HES_UPTODATE;
+	}
+}
+
+static int uncore_pmu_event_add(struct perf_event *event, int flags)
+{
+	struct intel_uncore_box *box = uncore_event_to_box(event);
+	struct hw_perf_event *hwc = &event->hw;
+	int assign[UNCORE_PMC_IDX_MAX];
+	int i, n, ret;
+
+	if (!box)
+		return -ENODEV;
+
+	ret = n = uncore_collect_events(box, event, false);
+	if (ret < 0)
+		return ret;
+
+	hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+	if (!(flags & PERF_EF_START))
+		hwc->state |= PERF_HES_ARCH;
+
+	ret = uncore_assign_events(box, assign, n);
+	if (ret)
+		return ret;
+
+	/* save events moving to new counters */
+	for (i = 0; i < box->n_events; i++) {
+		event = box->event_list[i];
+		hwc = &event->hw;
+
+		if (hwc->idx == assign[i] &&
+			hwc->last_tag == box->tags[assign[i]])
+			continue;
+		/*
+		 * Ensure we don't accidentally enable a stopped
+		 * counter simply because we rescheduled.
+		 */
+		if (hwc->state & PERF_HES_STOPPED)
+			hwc->state |= PERF_HES_ARCH;
+
+		uncore_pmu_event_stop(event, PERF_EF_UPDATE);
+	}
+
+	/* reprogram moved events into new counters */
+	for (i = 0; i < n; i++) {
+		event = box->event_list[i];
+		hwc = &event->hw;
+
+		if (hwc->idx != assign[i] ||
+			hwc->last_tag != box->tags[assign[i]])
+			uncore_assign_hw_event(box, event, assign[i]);
+		else if (i < box->n_events)
+			continue;
+
+		if (hwc->state & PERF_HES_ARCH)
+			continue;
+
+		uncore_pmu_event_start(event, 0);
+	}
+	box->n_events = n;
+
+	return 0;
+}
+
+static void uncore_pmu_event_del(struct perf_event *event, int flags)
+{
+	struct intel_uncore_box *box = uncore_event_to_box(event);
+	int i;
+
+	uncore_pmu_event_stop(event, PERF_EF_UPDATE);
+
+	for (i = 0; i < box->n_events; i++) {
+		if (event == box->event_list[i]) {
+			while (++i < box->n_events)
+				box->event_list[i - 1] = box->event_list[i];
+
+			--box->n_events;
+			break;
+		}
+	}
+
+	event->hw.idx = -1;
+	event->hw.last_tag = ~0ULL;
+}
+
+static void uncore_pmu_event_read(struct perf_event *event)
+{
+	struct intel_uncore_box *box = uncore_event_to_box(event);
+	uncore_perf_event_update(box, event);
+}
+
+/*
+ * validation ensures the group can be loaded onto the
+ * PMU if it was the only group available.
+ */
+static int uncore_validate_group(struct intel_uncore_pmu *pmu,
+				struct perf_event *event)
+{
+	struct perf_event *leader = event->group_leader;
+	struct intel_uncore_box *fake_box;
+	int assign[UNCORE_PMC_IDX_MAX];
+	int ret = -EINVAL, n;
+
+	fake_box = uncore_alloc_box(smp_processor_id());
+	if (!fake_box)
+		return -ENOMEM;
+
+	fake_box->pmu = pmu;
+	/*
+	 * the event is not yet connected with its
+	 * siblings therefore we must first collect
+	 * existing siblings, then add the new event
+	 * before we can simulate the scheduling
+	 */
+	n = uncore_collect_events(fake_box, leader, true);
+	if (n < 0)
+		goto out;
+
+	fake_box->n_events = n;
+	n = uncore_collect_events(fake_box, event, false);
+	if (n < 0)
+		goto out;
+
+	fake_box->n_events = n;
+
+	ret = uncore_assign_events(fake_box, assign, n);
+out:
+	kfree(fake_box);
+	return ret;
+}
+
+int uncore_pmu_event_init(struct perf_event *event)
+{
+	struct intel_uncore_pmu *pmu;
+	struct intel_uncore_box *box;
+	struct hw_perf_event *hwc = &event->hw;
+	int ret;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	pmu = uncore_event_to_pmu(event);
+	/* no device found for this pmu */
+	if (pmu->func_id < 0)
+		return -ENOENT;
+
+	/*
+	 * Uncore PMU does measure at all privilege level all the time.
+	 * So it doesn't make sense to specify any exclude bits.
+	 */
+	if (event->attr.exclude_user || event->attr.exclude_kernel ||
+			event->attr.exclude_hv || event->attr.exclude_idle)
+		return -EINVAL;
+
+	/* Sampling not supported yet */
+	if (hwc->sample_period)
+		return -EINVAL;
+
+	/*
+	 * Place all uncore events for a particular physical package
+	 * onto a single cpu
+	 */
+	if (event->cpu < 0)
+		return -EINVAL;
+	box = uncore_pmu_to_box(pmu, event->cpu);
+	if (!box || box->cpu < 0)
+		return -EINVAL;
+	event->cpu = box->cpu;
+
+	if (event->attr.config == UNCORE_FIXED_EVENT) {
+		/* no fixed counter */
+		if (!pmu->type->fixed_ctl)
+			return -EINVAL;
+		/*
+		 * if there is only one fixed counter, only the first pmu
+		 * can access the fixed counter
+		 */
+		if (pmu->type->single_fixed && pmu->pmu_idx > 0)
+			return -EINVAL;
+		hwc->config = ~0ULL;
+	} else {
+		hwc->config = event->attr.config & pmu->type->event_mask;
+	}
+
+	event->hw.idx = -1;
+	event->hw.last_tag = ~0ULL;
+
+	if (event->group_leader != event)
+		ret = uncore_validate_group(pmu, event);
+	else
+		ret = 0;
+
+	return ret;
+}
+
+static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
+{
+	int ret;
+
+	pmu->pmu = (struct pmu) {
+		.attr_groups	= pmu->type->attr_groups,
+		.task_ctx_nr	= perf_invalid_context,
+		.event_init	= uncore_pmu_event_init,
+		.add		= uncore_pmu_event_add,
+		.del		= uncore_pmu_event_del,
+		.start		= uncore_pmu_event_start,
+		.stop		= uncore_pmu_event_stop,
+		.read		= uncore_pmu_event_read,
+	};
+
+	if (pmu->type->num_boxes == 1) {
+		if (strlen(pmu->type->name) > 0)
+			sprintf(pmu->name, "uncore_%s", pmu->type->name);
+		else
+			sprintf(pmu->name, "uncore");
+	} else {
+		sprintf(pmu->name, "uncore_%s_%d", pmu->type->name,
+			pmu->pmu_idx);
+	}
+
+	ret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
+	return ret;
+}
+
+static void __init uncore_type_exit(struct intel_uncore_type *type)
+{
+	int i;
+
+	for (i = 0; i < type->num_boxes; i++)
+		free_percpu(type->pmus[i].box);
+	kfree(type->pmus);
+	type->pmus = NULL;
+	kfree(type->attr_groups[1]);
+	type->attr_groups[1] = NULL;
+}
+
+static void uncore_types_exit(struct intel_uncore_type **types)
+{
+	int i;
+	for (i = 0; types[i]; i++)
+		uncore_type_exit(types[i]);
+}
+
+static int __init uncore_type_init(struct intel_uncore_type *type)
+{
+	struct intel_uncore_pmu *pmus;
+	struct attribute_group *events_group;
+	struct attribute **attrs;
+	int i, j;
+
+	pmus = kzalloc(sizeof(*pmus) * type->num_boxes, GFP_KERNEL);
+	if (!pmus)
+		return -ENOMEM;
+
+	type->unconstrainted = (struct event_constraint)
+		__EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1,
+				0, type->num_counters, 0);
+
+	for (i = 0; i < type->num_boxes; i++) {
+		pmus[i].func_id = -1;
+		pmus[i].pmu_idx = i;
+		pmus[i].type = type;
+		INIT_LIST_HEAD(&pmus[i].box_list);
+		pmus[i].box = alloc_percpu(struct intel_uncore_box *);
+		if (!pmus[i].box)
+			goto fail;
+	}
+
+	if (type->event_descs) {
+		i = 0;
+		while (type->event_descs[i].attr.attr.name)
+			i++;
+
+		events_group = kzalloc(sizeof(struct attribute *) * (i + 1) +
+					sizeof(*events_group), GFP_KERNEL);
+		if (!events_group)
+			goto fail;
+
+		attrs = (struct attribute **)(events_group + 1);
+		events_group->name = "events";
+		events_group->attrs = attrs;
+
+		for (j = 0; j < i; j++)
+			attrs[j] = &type->event_descs[j].attr.attr;
+
+		type->attr_groups[1] = events_group;
+	}
+
+	type->pmus = pmus;
+	return 0;
+fail:
+	uncore_type_exit(type);
+	return -ENOMEM;
+}
+
+static int __init uncore_types_init(struct intel_uncore_type **types)
+{
+	int i, ret;
+
+	for (i = 0; types[i]; i++) {
+		ret = uncore_type_init(types[i]);
+		if (ret)
+			goto fail;
+	}
+	return 0;
+fail:
+	while (--i >= 0)
+		uncore_type_exit(types[i]);
+	return ret;
+}
+
+static struct pci_driver *uncore_pci_driver;
+static bool pcidrv_registered;
+
+/*
+ * add a pci uncore device
+ */
+static int __devinit uncore_pci_add(struct intel_uncore_type *type,
+				    struct pci_dev *pdev)
+{
+	struct intel_uncore_pmu *pmu;
+	struct intel_uncore_box *box;
+	int i, phys_id;
+
+	phys_id = pcibus_to_physid[pdev->bus->number];
+	if (phys_id < 0)
+		return -ENODEV;
+
+	box = uncore_alloc_box(0);
+	if (!box)
+		return -ENOMEM;
+
+	/*
+	 * for performance monitoring unit with multiple boxes,
+	 * each box has a different function id.
+	 */
+	for (i = 0; i < type->num_boxes; i++) {
+		pmu = &type->pmus[i];
+		if (pmu->func_id == pdev->devfn)
+			break;
+		if (pmu->func_id < 0) {
+			pmu->func_id = pdev->devfn;
+			break;
+		}
+		pmu = NULL;
+	}
+
+	if (!pmu) {
+		kfree(box);
+		return -EINVAL;
+	}
+
+	box->phys_id = phys_id;
+	box->pci_dev = pdev;
+	box->pmu = pmu;
+	uncore_box_init(box);
+	pci_set_drvdata(pdev, box);
+
+	raw_spin_lock(&uncore_box_lock);
+	list_add_tail(&box->list, &pmu->box_list);
+	raw_spin_unlock(&uncore_box_lock);
+
+	return 0;
+}
+
+static void uncore_pci_remove(struct pci_dev *pdev)
+{
+	struct intel_uncore_box *box = pci_get_drvdata(pdev);
+	struct intel_uncore_pmu *pmu = box->pmu;
+	int cpu, phys_id = pcibus_to_physid[pdev->bus->number];
+
+	if (WARN_ON_ONCE(phys_id != box->phys_id))
+		return;
+
+	raw_spin_lock(&uncore_box_lock);
+	list_del(&box->list);
+	raw_spin_unlock(&uncore_box_lock);
+
+	for_each_possible_cpu(cpu) {
+		if (*per_cpu_ptr(pmu->box, cpu) == box) {
+			*per_cpu_ptr(pmu->box, cpu) = NULL;
+			atomic_dec(&box->refcnt);
+		}
+	}
+
+	WARN_ON_ONCE(atomic_read(&box->refcnt) != 1);
+	kfree(box);
+}
+
+static int __devinit uncore_pci_probe(struct pci_dev *pdev,
+				const struct pci_device_id *id)
+{
+	struct intel_uncore_type *type;
+
+	type = (struct intel_uncore_type *)id->driver_data;
+	return uncore_pci_add(type, pdev);
+}
+
+static int __init uncore_pci_init(void)
+{
+	int ret;
+
+	switch (boot_cpu_data.x86_model) {
+	case 45: /* Sandy Bridge-EP */
+		pci_uncores = snbep_pci_uncores;
+		uncore_pci_driver = &snbep_uncore_pci_driver;
+		snbep_pci2phy_map_init();
+		break;
+	default:
+		return 0;
+	}
+
+	ret = uncore_types_init(pci_uncores);
+	if (ret)
+		return ret;
+
+	uncore_pci_driver->probe = uncore_pci_probe;
+	uncore_pci_driver->remove = uncore_pci_remove;
+
+	ret = pci_register_driver(uncore_pci_driver);
+	if (ret == 0)
+		pcidrv_registered = true;
+	else
+		uncore_types_exit(pci_uncores);
+
+	return ret;
+}
+
+static void __init uncore_pci_exit(void)
+{
+	if (pcidrv_registered) {
+		pcidrv_registered = false;
+		pci_unregister_driver(uncore_pci_driver);
+		uncore_types_exit(pci_uncores);
+	}
+}
+
+static void __cpuinit uncore_cpu_dying(int cpu)
+{
+	struct intel_uncore_type *type;
+	struct intel_uncore_pmu *pmu;
+	struct intel_uncore_box *box;
+	int i, j;
+
+	for (i = 0; msr_uncores[i]; i++) {
+		type = msr_uncores[i];
+		for (j = 0; j < type->num_boxes; j++) {
+			pmu = &type->pmus[j];
+			box = *per_cpu_ptr(pmu->box, cpu);
+			*per_cpu_ptr(pmu->box, cpu) = NULL;
+			if (box && atomic_dec_and_test(&box->refcnt))
+				kfree(box);
+		}
+	}
+}
+
+static int __cpuinit uncore_cpu_starting(int cpu)
+{
+	struct intel_uncore_type *type;
+	struct intel_uncore_pmu *pmu;
+	struct intel_uncore_box *box, *exist;
+	int i, j, k, phys_id;
+
+	phys_id = topology_physical_package_id(cpu);
+
+	for (i = 0; msr_uncores[i]; i++) {
+		type = msr_uncores[i];
+		for (j = 0; j < type->num_boxes; j++) {
+			pmu = &type->pmus[j];
+			box = *per_cpu_ptr(pmu->box, cpu);
+			/* called by uncore_cpu_init? */
+			if (box && box->phys_id >= 0) {
+				uncore_box_init(box);
+				continue;
+			}
+
+			for_each_online_cpu(k) {
+				exist = *per_cpu_ptr(pmu->box, k);
+				if (exist && exist->phys_id == phys_id) {
+					atomic_inc(&exist->refcnt);
+					*per_cpu_ptr(pmu->box, cpu) = exist;
+					kfree(box);
+					box = NULL;
+					break;
+				}
+			}
+
+			if (box) {
+				box->phys_id = phys_id;
+				uncore_box_init(box);
+			}
+		}
+	}
+	return 0;
+}
+
+static int __cpuinit uncore_cpu_prepare(int cpu, int phys_id)
+{
+	struct intel_uncore_type *type;
+	struct intel_uncore_pmu *pmu;
+	struct intel_uncore_box *box;
+	int i, j;
+
+	for (i = 0; msr_uncores[i]; i++) {
+		type = msr_uncores[i];
+		for (j = 0; j < type->num_boxes; j++) {
+			pmu = &type->pmus[j];
+			if (pmu->func_id < 0)
+				pmu->func_id = j;
+
+			box = uncore_alloc_box(cpu);
+			if (!box)
+				return -ENOMEM;
+
+			box->pmu = pmu;
+			box->phys_id = phys_id;
+			*per_cpu_ptr(pmu->box, cpu) = box;
+		}
+	}
+	return 0;
+}
+
+static void __cpuinit uncore_change_context(struct intel_uncore_type **uncores,
+					    int old_cpu, int new_cpu)
+{
+	struct intel_uncore_type *type;
+	struct intel_uncore_pmu *pmu;
+	struct intel_uncore_box *box;
+	int i, j;
+
+	for (i = 0; uncores[i]; i++) {
+		type = uncores[i];
+		for (j = 0; j < type->num_boxes; j++) {
+			pmu = &type->pmus[j];
+			if (old_cpu < 0)
+				box = uncore_pmu_to_box(pmu, new_cpu);
+			else
+				box = uncore_pmu_to_box(pmu, old_cpu);
+			if (!box)
+				continue;
+
+			if (old_cpu < 0) {
+				WARN_ON_ONCE(box->cpu != -1);
+				box->cpu = new_cpu;
+				continue;
+			}
+
+			WARN_ON_ONCE(box->cpu != old_cpu);
+			if (new_cpu >= 0) {
+				uncore_pmu_cancel_hrtimer(box);
+				perf_pmu_migrate_context(&pmu->pmu,
+						old_cpu, new_cpu);
+				box->cpu = new_cpu;
+			} else {
+				box->cpu = -1;
+			}
+		}
+	}
+}
+
+static void __cpuinit uncore_event_exit_cpu(int cpu)
+{
+	int i, phys_id, target;
+
+	/* if exiting cpu is used for collecting uncore events */
+	if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask))
+		return;
+
+	/* find a new cpu to collect uncore events */
+	phys_id = topology_physical_package_id(cpu);
+	target = -1;
+	for_each_online_cpu(i) {
+		if (i == cpu)
+			continue;
+		if (phys_id == topology_physical_package_id(i)) {
+			target = i;
+			break;
+		}
+	}
+
+	/* migrate uncore events to the new cpu */
+	if (target >= 0)
+		cpumask_set_cpu(target, &uncore_cpu_mask);
+
+	uncore_change_context(msr_uncores, cpu, target);
+	uncore_change_context(pci_uncores, cpu, target);
+}
+
+static void __cpuinit uncore_event_init_cpu(int cpu)
+{
+	int i, phys_id;
+
+	phys_id = topology_physical_package_id(cpu);
+	for_each_cpu(i, &uncore_cpu_mask) {
+		if (phys_id == topology_physical_package_id(i))
+			return;
+	}
+
+	cpumask_set_cpu(cpu, &uncore_cpu_mask);
+
+	uncore_change_context(msr_uncores, -1, cpu);
+	uncore_change_context(pci_uncores, -1, cpu);
+}
+
+static int __cpuinit uncore_cpu_notifier(struct notifier_block *self,
+					 unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (long)hcpu;
+
+	/* allocate/free data structure for uncore box */
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_UP_PREPARE:
+		uncore_cpu_prepare(cpu, -1);
+		break;
+	case CPU_STARTING:
+		uncore_cpu_starting(cpu);
+		break;
+	case CPU_UP_CANCELED:
+	case CPU_DYING:
+		uncore_cpu_dying(cpu);
+		break;
+	default:
+		break;
+	}
+
+	/* select the cpu that collects uncore events */
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_DOWN_FAILED:
+	case CPU_STARTING:
+		uncore_event_init_cpu(cpu);
+		break;
+	case CPU_DOWN_PREPARE:
+		uncore_event_exit_cpu(cpu);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block uncore_cpu_nb __cpuinitdata = {
+	.notifier_call = uncore_cpu_notifier,
+	/*
+	 * to migrate uncore events, our notifier should be executed
+	 * before perf core's notifier.
+	 */
+	.priority = CPU_PRI_PERF + 1,
+};
+
+static void __init uncore_cpu_setup(void *dummy)
+{
+	uncore_cpu_starting(smp_processor_id());
+}
+
+static int __init uncore_cpu_init(void)
+{
+	int ret, cpu;
+
+	switch (boot_cpu_data.x86_model) {
+	case 26: /* Nehalem */
+	case 30:
+	case 37: /* Westmere */
+	case 44:
+		msr_uncores = nhm_msr_uncores;
+		break;
+	case 42: /* Sandy Bridge */
+		msr_uncores = snb_msr_uncores;
+		break;
+	case 45: /* Sandy Birdge-EP */
+		msr_uncores = snbep_msr_uncores;
+		break;
+	default:
+		return 0;
+	}
+
+	ret = uncore_types_init(msr_uncores);
+	if (ret)
+		return ret;
+
+	get_online_cpus();
+
+	for_each_online_cpu(cpu) {
+		int i, phys_id = topology_physical_package_id(cpu);
+
+		for_each_cpu(i, &uncore_cpu_mask) {
+			if (phys_id == topology_physical_package_id(i)) {
+				phys_id = -1;
+				break;
+			}
+		}
+		if (phys_id < 0)
+			continue;
+
+		uncore_cpu_prepare(cpu, phys_id);
+		uncore_event_init_cpu(cpu);
+	}
+	on_each_cpu(uncore_cpu_setup, NULL, 1);
+
+	register_cpu_notifier(&uncore_cpu_nb);
+
+	put_online_cpus();
+
+	return 0;
+}
+
+static int __init uncore_pmus_register(void)
+{
+	struct intel_uncore_pmu *pmu;
+	struct intel_uncore_type *type;
+	int i, j;
+
+	for (i = 0; msr_uncores[i]; i++) {
+		type = msr_uncores[i];
+		for (j = 0; j < type->num_boxes; j++) {
+			pmu = &type->pmus[j];
+			uncore_pmu_register(pmu);
+		}
+	}
+
+	for (i = 0; pci_uncores[i]; i++) {
+		type = pci_uncores[i];
+		for (j = 0; j < type->num_boxes; j++) {
+			pmu = &type->pmus[j];
+			uncore_pmu_register(pmu);
+		}
+	}
+
+	return 0;
+}
+
+static int __init intel_uncore_init(void)
+{
+	int ret;
+
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+		return -ENODEV;
+
+	ret = uncore_pci_init();
+	if (ret)
+		goto fail;
+	ret = uncore_cpu_init();
+	if (ret) {
+		uncore_pci_exit();
+		goto fail;
+	}
+
+	uncore_pmus_register();
+	return 0;
+fail:
+	return ret;
+}
+device_initcall(intel_uncore_init);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
new file mode 100644
index 0000000..689e5e5
--- /dev/null
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -0,0 +1,406 @@
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/perf_event.h>
+#include "perf_event.h"
+
+#define UNCORE_PMU_NAME_LEN		32
+#define UNCORE_BOX_HASH_SIZE		8
+
+#define UNCORE_PMU_HRTIMER_INTERVAL	(60LL * NSEC_PER_SEC)
+
+#define UNCORE_FIXED_EVENT		0xffff
+#define UNCORE_PMC_IDX_MAX_GENERIC	8
+#define UNCORE_PMC_IDX_FIXED		UNCORE_PMC_IDX_MAX_GENERIC
+#define UNCORE_PMC_IDX_MAX		(UNCORE_PMC_IDX_FIXED + 1)
+
+#define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff)
+
+/* SNB event control */
+#define SNB_UNC_CTL_EV_SEL_MASK			0x000000ff
+#define SNB_UNC_CTL_UMASK_MASK			0x0000ff00
+#define SNB_UNC_CTL_EDGE_DET			(1 << 18)
+#define SNB_UNC_CTL_EN				(1 << 22)
+#define SNB_UNC_CTL_INVERT			(1 << 23)
+#define SNB_UNC_CTL_CMASK_MASK			0x1f000000
+#define NHM_UNC_CTL_CMASK_MASK			0xff000000
+#define NHM_UNC_FIXED_CTR_CTL_EN		(1 << 0)
+
+#define SNB_UNC_RAW_EVENT_MASK			(SNB_UNC_CTL_EV_SEL_MASK | \
+						 SNB_UNC_CTL_UMASK_MASK | \
+						 SNB_UNC_CTL_EDGE_DET | \
+						 SNB_UNC_CTL_INVERT | \
+						 SNB_UNC_CTL_CMASK_MASK)
+
+#define NHM_UNC_RAW_EVENT_MASK			(SNB_UNC_CTL_EV_SEL_MASK | \
+						 SNB_UNC_CTL_UMASK_MASK | \
+						 SNB_UNC_CTL_EDGE_DET | \
+						 SNB_UNC_CTL_INVERT | \
+						 NHM_UNC_CTL_CMASK_MASK)
+
+/* SNB global control register */
+#define SNB_UNC_PERF_GLOBAL_CTL                 0x391
+#define SNB_UNC_FIXED_CTR_CTRL                  0x394
+#define SNB_UNC_FIXED_CTR                       0x395
+
+/* SNB uncore global control */
+#define SNB_UNC_GLOBAL_CTL_CORE_ALL             ((1 << 4) - 1)
+#define SNB_UNC_GLOBAL_CTL_EN                   (1 << 29)
+
+/* SNB Cbo register */
+#define SNB_UNC_CBO_0_PERFEVTSEL0               0x700
+#define SNB_UNC_CBO_0_PER_CTR0                  0x706
+#define SNB_UNC_CBO_MSR_OFFSET                  0x10
+
+/* NHM global control register */
+#define NHM_UNC_PERF_GLOBAL_CTL                 0x391
+#define NHM_UNC_FIXED_CTR                       0x394
+#define NHM_UNC_FIXED_CTR_CTRL                  0x395
+
+/* NHM uncore global control */
+#define NHM_UNC_GLOBAL_CTL_EN_PC_ALL            ((1ULL << 8) - 1)
+#define NHM_UNC_GLOBAL_CTL_EN_FC                (1ULL << 32)
+
+/* NHM uncore register */
+#define NHM_UNC_PERFEVTSEL0                     0x3c0
+#define NHM_UNC_UNCORE_PMC0                     0x3b0
+
+/* SNB-EP Box level control */
+#define SNBEP_PMON_BOX_CTL_RST_CTRL	(1 << 0)
+#define SNBEP_PMON_BOX_CTL_RST_CTRS	(1 << 1)
+#define SNBEP_PMON_BOX_CTL_FRZ		(1 << 8)
+#define SNBEP_PMON_BOX_CTL_FRZ_EN	(1 << 16)
+#define SNBEP_PMON_BOX_CTL_INT		(SNBEP_PMON_BOX_CTL_RST_CTRL | \
+					 SNBEP_PMON_BOX_CTL_RST_CTRS | \
+					 SNBEP_PMON_BOX_CTL_FRZ_EN)
+/* SNB-EP event control */
+#define SNBEP_PMON_CTL_EV_SEL_MASK	0x000000ff
+#define SNBEP_PMON_CTL_UMASK_MASK	0x0000ff00
+#define SNBEP_PMON_CTL_RST		(1 << 17)
+#define SNBEP_PMON_CTL_EDGE_DET		(1 << 18)
+#define SNBEP_PMON_CTL_EV_SEL_EXT	(1 << 21)	/* only for QPI */
+#define SNBEP_PMON_CTL_EN		(1 << 22)
+#define SNBEP_PMON_CTL_INVERT		(1 << 23)
+#define SNBEP_PMON_CTL_TRESH_MASK	0xff000000
+#define SNBEP_PMON_RAW_EVENT_MASK	(SNBEP_PMON_CTL_EV_SEL_MASK | \
+					 SNBEP_PMON_CTL_UMASK_MASK | \
+					 SNBEP_PMON_CTL_EDGE_DET | \
+					 SNBEP_PMON_CTL_INVERT | \
+					 SNBEP_PMON_CTL_TRESH_MASK)
+
+/* SNB-EP Ubox event control */
+#define SNBEP_U_MSR_PMON_CTL_TRESH_MASK		0x1f000000
+#define SNBEP_U_MSR_PMON_RAW_EVENT_MASK		\
+				(SNBEP_PMON_CTL_EV_SEL_MASK | \
+				 SNBEP_PMON_CTL_UMASK_MASK | \
+				 SNBEP_PMON_CTL_EDGE_DET | \
+				 SNBEP_PMON_CTL_INVERT | \
+				 SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
+
+/* SNB-EP PCU event control */
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK	0x0000c000
+#define SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK	0x1f000000
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT	(1 << 30)
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET	(1 << 31)
+#define SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK	\
+				(SNBEP_PMON_CTL_EV_SEL_MASK | \
+				 SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
+				 SNBEP_PMON_CTL_EDGE_DET | \
+				 SNBEP_PMON_CTL_INVERT | \
+				 SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
+				 SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
+				 SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
+
+/* SNB-EP pci control register */
+#define SNBEP_PCI_PMON_BOX_CTL			0xf4
+#define SNBEP_PCI_PMON_CTL0			0xd8
+/* SNB-EP pci counter register */
+#define SNBEP_PCI_PMON_CTR0			0xa0
+
+/* SNB-EP home agent register */
+#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH0	0x40
+#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH1	0x44
+#define SNBEP_HA_PCI_PMON_BOX_OPCODEMATCH	0x48
+/* SNB-EP memory controller register */
+#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTL		0xf0
+#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTR		0xd0
+/* SNB-EP QPI register */
+#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH0		0x228
+#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH1		0x22c
+#define SNBEP_Q_Py_PCI_PMON_PKT_MASK0		0x238
+#define SNBEP_Q_Py_PCI_PMON_PKT_MASK1		0x23c
+
+/* SNB-EP Ubox register */
+#define SNBEP_U_MSR_PMON_CTR0			0xc16
+#define SNBEP_U_MSR_PMON_CTL0			0xc10
+
+#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTL		0xc08
+#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTR		0xc09
+
+/* SNB-EP Cbo register */
+#define SNBEP_C0_MSR_PMON_CTR0			0xd16
+#define SNBEP_C0_MSR_PMON_CTL0			0xd10
+#define SNBEP_C0_MSR_PMON_BOX_FILTER		0xd14
+#define SNBEP_C0_MSR_PMON_BOX_CTL		0xd04
+#define SNBEP_CBO_MSR_OFFSET			0x20
+
+/* SNB-EP PCU register */
+#define SNBEP_PCU_MSR_PMON_CTR0			0xc36
+#define SNBEP_PCU_MSR_PMON_CTL0			0xc30
+#define SNBEP_PCU_MSR_PMON_BOX_FILTER		0xc34
+#define SNBEP_PCU_MSR_PMON_BOX_CTL		0xc24
+#define SNBEP_PCU_MSR_CORE_C3_CTR		0x3fc
+#define SNBEP_PCU_MSR_CORE_C6_CTR		0x3fd
+
+struct intel_uncore_ops;
+struct intel_uncore_pmu;
+struct intel_uncore_box;
+struct uncore_event_desc;
+
+struct intel_uncore_type {
+	const char *name;
+	int num_counters;
+	int num_boxes;
+	int perf_ctr_bits;
+	int fixed_ctr_bits;
+	int single_fixed;
+	unsigned perf_ctr;
+	unsigned event_ctl;
+	unsigned event_mask;
+	unsigned fixed_ctr;
+	unsigned fixed_ctl;
+	unsigned box_ctl;
+	unsigned msr_offset;
+	struct event_constraint unconstrainted;
+	struct event_constraint *constraints;
+	struct intel_uncore_pmu *pmus;
+	struct intel_uncore_ops *ops;
+	struct uncore_event_desc *event_descs;
+	const struct attribute_group *attr_groups[3];
+};
+
+#define format_group attr_groups[0]
+
+struct intel_uncore_ops {
+	void (*init_box)(struct intel_uncore_box *);
+	void (*disable_box)(struct intel_uncore_box *);
+	void (*enable_box)(struct intel_uncore_box *);
+	void (*disable_event)(struct intel_uncore_box *, struct perf_event *);
+	void (*enable_event)(struct intel_uncore_box *, struct perf_event *);
+	u64 (*read_counter)(struct intel_uncore_box *, struct perf_event *);
+};
+
+struct intel_uncore_pmu {
+	struct pmu pmu;
+	char name[UNCORE_PMU_NAME_LEN];
+	int pmu_idx;
+	int func_id;
+	struct intel_uncore_type *type;
+	struct intel_uncore_box ** __percpu box;
+	struct list_head box_list;
+};
+
+struct intel_uncore_box {
+	int phys_id;
+	int n_active;	/* number of active events */
+	int n_events;
+	int cpu;	/* cpu to collect events */
+	unsigned long flags;
+	atomic_t refcnt;
+	struct perf_event *events[UNCORE_PMC_IDX_MAX];
+	struct perf_event *event_list[UNCORE_PMC_IDX_MAX];
+	unsigned long active_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)];
+	u64 tags[UNCORE_PMC_IDX_MAX];
+	struct pci_dev *pci_dev;
+	struct intel_uncore_pmu *pmu;
+	struct hrtimer hrtimer;
+	struct list_head list;
+};
+
+#define UNCORE_BOX_FLAG_INITIATED	0
+
+struct uncore_event_desc {
+	struct kobj_attribute attr;
+	const char *config;
+};
+
+#define INTEL_UNCORE_EVENT_DESC(_name, _config)			\
+{								\
+	.attr	= __ATTR(_name, 0444, uncore_event_show, NULL),	\
+	.config	= _config,					\
+}
+
+#define DEFINE_UNCORE_FORMAT_ATTR(_var, _name, _format)			\
+static ssize_t __uncore_##_var##_show(struct kobject *kobj,		\
+				struct kobj_attribute *attr,		\
+				char *page)				\
+{									\
+	BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);			\
+	return sprintf(page, _format "\n");				\
+}									\
+static struct kobj_attribute format_attr_##_var =			\
+	__ATTR(_name, 0444, __uncore_##_var##_show, NULL)
+
+
+static ssize_t uncore_event_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *buf)
+{
+	struct uncore_event_desc *event =
+		container_of(attr, struct uncore_event_desc, attr);
+	return sprintf(buf, "%s", event->config);
+}
+
+static inline unsigned uncore_pci_box_ctl(struct intel_uncore_box *box)
+{
+	return box->pmu->type->box_ctl;
+}
+
+static inline unsigned uncore_pci_fixed_ctl(struct intel_uncore_box *box)
+{
+	return box->pmu->type->fixed_ctl;
+}
+
+static inline unsigned uncore_pci_fixed_ctr(struct intel_uncore_box *box)
+{
+	return box->pmu->type->fixed_ctr;
+}
+
+static inline
+unsigned uncore_pci_event_ctl(struct intel_uncore_box *box, int idx)
+{
+	return idx * 4 + box->pmu->type->event_ctl;
+}
+
+static inline
+unsigned uncore_pci_perf_ctr(struct intel_uncore_box *box, int idx)
+{
+	return idx * 8 + box->pmu->type->perf_ctr;
+}
+
+static inline
+unsigned uncore_msr_box_ctl(struct intel_uncore_box *box)
+{
+	if (!box->pmu->type->box_ctl)
+		return 0;
+	return box->pmu->type->box_ctl +
+		box->pmu->type->msr_offset * box->pmu->pmu_idx;
+}
+
+static inline
+unsigned uncore_msr_fixed_ctl(struct intel_uncore_box *box)
+{
+	if (!box->pmu->type->fixed_ctl)
+		return 0;
+	return box->pmu->type->fixed_ctl +
+		box->pmu->type->msr_offset * box->pmu->pmu_idx;
+}
+
+static inline
+unsigned uncore_msr_fixed_ctr(struct intel_uncore_box *box)
+{
+	return box->pmu->type->fixed_ctr +
+		box->pmu->type->msr_offset * box->pmu->pmu_idx;
+}
+
+static inline
+unsigned uncore_msr_event_ctl(struct intel_uncore_box *box, int idx)
+{
+	return idx + box->pmu->type->event_ctl +
+		box->pmu->type->msr_offset * box->pmu->pmu_idx;
+}
+
+static inline
+unsigned uncore_msr_perf_ctr(struct intel_uncore_box *box, int idx)
+{
+	return idx + box->pmu->type->perf_ctr +
+		box->pmu->type->msr_offset * box->pmu->pmu_idx;
+}
+
+static inline
+unsigned uncore_fixed_ctl(struct intel_uncore_box *box)
+{
+	if (box->pci_dev)
+		return uncore_pci_fixed_ctl(box);
+	else
+		return uncore_msr_fixed_ctl(box);
+}
+
+static inline
+unsigned uncore_fixed_ctr(struct intel_uncore_box *box)
+{
+	if (box->pci_dev)
+		return uncore_pci_fixed_ctr(box);
+	else
+		return uncore_msr_fixed_ctr(box);
+}
+
+static inline
+unsigned uncore_event_ctl(struct intel_uncore_box *box, int idx)
+{
+	if (box->pci_dev)
+		return uncore_pci_event_ctl(box, idx);
+	else
+		return uncore_msr_event_ctl(box, idx);
+}
+
+static inline
+unsigned uncore_perf_ctr(struct intel_uncore_box *box, int idx)
+{
+	if (box->pci_dev)
+		return uncore_pci_perf_ctr(box, idx);
+	else
+		return uncore_msr_perf_ctr(box, idx);
+}
+
+static inline int uncore_perf_ctr_bits(struct intel_uncore_box *box)
+{
+	return box->pmu->type->perf_ctr_bits;
+}
+
+static inline int uncore_fixed_ctr_bits(struct intel_uncore_box *box)
+{
+	return box->pmu->type->fixed_ctr_bits;
+}
+
+static inline int uncore_num_counters(struct intel_uncore_box *box)
+{
+	return box->pmu->type->num_counters;
+}
+
+static inline void uncore_disable_box(struct intel_uncore_box *box)
+{
+	if (box->pmu->type->ops->disable_box)
+		box->pmu->type->ops->disable_box(box);
+}
+
+static inline void uncore_enable_box(struct intel_uncore_box *box)
+{
+	if (box->pmu->type->ops->enable_box)
+		box->pmu->type->ops->enable_box(box);
+}
+
+static inline void uncore_disable_event(struct intel_uncore_box *box,
+				struct perf_event *event)
+{
+	box->pmu->type->ops->disable_event(box, event);
+}
+
+static inline void uncore_enable_event(struct intel_uncore_box *box,
+				struct perf_event *event)
+{
+	box->pmu->type->ops->enable_event(box, event);
+}
+
+static inline u64 uncore_read_counter(struct intel_uncore_box *box,
+				struct perf_event *event)
+{
+	return box->pmu->type->ops->read_counter(box, event);
+}
+
+static inline void uncore_box_init(struct intel_uncore_box *box)
+{
+	if (!test_and_set_bit(UNCORE_BOX_FLAG_INITIATED, &box->flags)) {
+		if (box->pmu->type->ops->init_box)
+			box->pmu->type->ops->init_box(box);
+	}
+}
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index 47124a7..6c82e40 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -895,8 +895,8 @@ static void p4_pmu_disable_pebs(void)
 	 * So at moment let leave metrics turned on forever -- it's
 	 * ok for now but need to be revisited!
 	 *
-	 * (void)checking_wrmsrl(MSR_IA32_PEBS_ENABLE, (u64)0);
-	 * (void)checking_wrmsrl(MSR_P4_PEBS_MATRIX_VERT, (u64)0);
+	 * (void)wrmsrl_safe(MSR_IA32_PEBS_ENABLE, (u64)0);
+	 * (void)wrmsrl_safe(MSR_P4_PEBS_MATRIX_VERT, (u64)0);
 	 */
 }
 
@@ -909,7 +909,7 @@ static inline void p4_pmu_disable_event(struct perf_event *event)
 	 * state we need to clear P4_CCCR_OVF, otherwise interrupt get
 	 * asserted again and again
 	 */
-	(void)checking_wrmsrl(hwc->config_base,
+	(void)wrmsrl_safe(hwc->config_base,
 		(u64)(p4_config_unpack_cccr(hwc->config)) &
 			~P4_CCCR_ENABLE & ~P4_CCCR_OVF & ~P4_CCCR_RESERVED);
 }
@@ -943,8 +943,8 @@ static void p4_pmu_enable_pebs(u64 config)
 
 	bind = &p4_pebs_bind_map[idx];
 
-	(void)checking_wrmsrl(MSR_IA32_PEBS_ENABLE,	(u64)bind->metric_pebs);
-	(void)checking_wrmsrl(MSR_P4_PEBS_MATRIX_VERT,	(u64)bind->metric_vert);
+	(void)wrmsrl_safe(MSR_IA32_PEBS_ENABLE,	(u64)bind->metric_pebs);
+	(void)wrmsrl_safe(MSR_P4_PEBS_MATRIX_VERT,	(u64)bind->metric_vert);
 }
 
 static void p4_pmu_enable_event(struct perf_event *event)
@@ -978,8 +978,8 @@ static void p4_pmu_enable_event(struct perf_event *event)
 	 */
 	p4_pmu_enable_pebs(hwc->config);
 
-	(void)checking_wrmsrl(escr_addr, escr_conf);
-	(void)checking_wrmsrl(hwc->config_base,
+	(void)wrmsrl_safe(escr_addr, escr_conf);
+	(void)wrmsrl_safe(hwc->config_base,
 				(cccr & ~P4_CCCR_RESERVED) | P4_CCCR_ENABLE);
 }
 
diff --git a/arch/x86/kernel/cpu/perf_event_p6.c b/arch/x86/kernel/cpu/perf_event_p6.c
index 32bcfc7..e4dd0f7 100644
--- a/arch/x86/kernel/cpu/perf_event_p6.c
+++ b/arch/x86/kernel/cpu/perf_event_p6.c
@@ -71,7 +71,7 @@ p6_pmu_disable_event(struct perf_event *event)
 	if (cpuc->enabled)
 		val |= ARCH_PERFMON_EVENTSEL_ENABLE;
 
-	(void)checking_wrmsrl(hwc->config_base, val);
+	(void)wrmsrl_safe(hwc->config_base, val);
 }
 
 static void p6_pmu_enable_event(struct perf_event *event)
@@ -84,7 +84,7 @@ static void p6_pmu_enable_event(struct perf_event *event)
 	if (cpuc->enabled)
 		val |= ARCH_PERFMON_EVENTSEL_ENABLE;
 
-	(void)checking_wrmsrl(hwc->config_base, val);
+	(void)wrmsrl_safe(hwc->config_base, val);
 }
 
 PMU_FORMAT_ATTR(event,	"config:0-7"	);
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index addf9e8..ee8e9ab 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -31,7 +31,7 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
 	const struct cpuid_bit *cb;
 
 	static const struct cpuid_bit __cpuinitconst cpuid_bits[] = {
-		{ X86_FEATURE_DTS,		CR_EAX, 0, 0x00000006, 0 },
+		{ X86_FEATURE_DTHERM,		CR_EAX, 0, 0x00000006, 0 },
 		{ X86_FEATURE_IDA,		CR_EAX, 1, 0x00000006, 0 },
 		{ X86_FEATURE_ARAT,		CR_EAX, 2, 0x00000006, 0 },
 		{ X86_FEATURE_PLN,		CR_EAX, 4, 0x00000006, 0 },
diff --git a/arch/x86/kernel/cpu/sched.c b/arch/x86/kernel/cpu/sched.c
deleted file mode 100644
index a640ae5..0000000
--- a/arch/x86/kernel/cpu/sched.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <linux/sched.h>
-#include <linux/math64.h>
-#include <linux/percpu.h>
-#include <linux/irqflags.h>
-
-#include <asm/cpufeature.h>
-#include <asm/processor.h>
-
-#ifdef CONFIG_SMP
-
-static DEFINE_PER_CPU(struct aperfmperf, old_perf_sched);
-
-static unsigned long scale_aperfmperf(void)
-{
-	struct aperfmperf val, *old = &__get_cpu_var(old_perf_sched);
-	unsigned long ratio, flags;
-
-	local_irq_save(flags);
-	get_aperfmperf(&val);
-	local_irq_restore(flags);
-
-	ratio = calc_aperfmperf_ratio(old, &val);
-	*old = val;
-
-	return ratio;
-}
-
-unsigned long arch_scale_freq_power(struct sched_domain *sd, int cpu)
-{
-	/*
-	 * do aperf/mperf on the cpu level because it includes things
-	 * like turbo mode, which are relevant to full cores.
-	 */
-	if (boot_cpu_has(X86_FEATURE_APERFMPERF))
-		return scale_aperfmperf();
-
-	/*
-	 * maybe have something cpufreq here
-	 */
-
-	return default_scale_freq_power(sd, cpu);
-}
-
-unsigned long arch_scale_smt_power(struct sched_domain *sd, int cpu)
-{
-	/*
-	 * aperf/mperf already includes the smt gain
-	 */
-	if (boot_cpu_has(X86_FEATURE_APERFMPERF))
-		return SCHED_LOAD_SCALE;
-
-	return default_scale_smt_power(sd, cpu);
-}
-
-#endif
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 571246d..ae42418b 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -27,8 +27,8 @@ static int die_counter;
 
 void printk_address(unsigned long address, int reliable)
 {
-	printk(" [<%p>] %s%pB\n", (void *) address,
-			reliable ? "" : "? ", (void *) address);
+	pr_cont(" [<%p>] %s%pB\n",
+		(void *)address, reliable ? "" : "? ", (void *)address);
 }
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -271,6 +271,7 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err)
 			current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP)
 		return 1;
 
+	print_modules();
 	show_regs(regs);
 #ifdef CONFIG_X86_32
 	if (user_mode_vm(regs)) {
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index e0b1d78..1038a41 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -73,11 +73,11 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
 		if (kstack_end(stack))
 			break;
 		if (i && ((i % STACKSLOTS_PER_LINE) == 0))
-			printk(KERN_CONT "\n");
-		printk(KERN_CONT " %08lx", *stack++);
+			pr_cont("\n");
+		pr_cont(" %08lx", *stack++);
 		touch_nmi_watchdog();
 	}
-	printk(KERN_CONT "\n");
+	pr_cont("\n");
 	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
 
@@ -86,12 +86,11 @@ void show_regs(struct pt_regs *regs)
 {
 	int i;
 
-	print_modules();
 	__show_regs(regs, !user_mode_vm(regs));
 
-	printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n",
-		TASK_COMM_LEN, current->comm, task_pid_nr(current),
-		current_thread_info(), current, task_thread_info(current));
+	pr_emerg("Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n",
+		 TASK_COMM_LEN, current->comm, task_pid_nr(current),
+		 current_thread_info(), current, task_thread_info(current));
 	/*
 	 * When in-kernel, we also print out the stack and code at the
 	 * time of the fault..
@@ -102,10 +101,10 @@ void show_regs(struct pt_regs *regs)
 		unsigned char c;
 		u8 *ip;
 
-		printk(KERN_EMERG "Stack:\n");
+		pr_emerg("Stack:\n");
 		show_stack_log_lvl(NULL, regs, &regs->sp, 0, KERN_EMERG);
 
-		printk(KERN_EMERG "Code: ");
+		pr_emerg("Code:");
 
 		ip = (u8 *)regs->ip - code_prologue;
 		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
@@ -116,16 +115,16 @@ void show_regs(struct pt_regs *regs)
 		for (i = 0; i < code_len; i++, ip++) {
 			if (ip < (u8 *)PAGE_OFFSET ||
 					probe_kernel_address(ip, c)) {
-				printk(KERN_CONT " Bad EIP value.");
+				pr_cont("  Bad EIP value.");
 				break;
 			}
 			if (ip == (u8 *)regs->ip)
-				printk(KERN_CONT "<%02x> ", c);
+				pr_cont(" <%02x>", c);
 			else
-				printk(KERN_CONT "%02x ", c);
+				pr_cont(" %02x", c);
 		}
 	}
-	printk(KERN_CONT "\n");
+	pr_cont("\n");
 }
 
 int is_valid_bugaddr(unsigned long ip)
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 791b761..b653675 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -228,20 +228,20 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
 		if (stack >= irq_stack && stack <= irq_stack_end) {
 			if (stack == irq_stack_end) {
 				stack = (unsigned long *) (irq_stack_end[-1]);
-				printk(KERN_CONT " <EOI> ");
+				pr_cont(" <EOI> ");
 			}
 		} else {
 		if (((long) stack & (THREAD_SIZE-1)) == 0)
 			break;
 		}
 		if (i && ((i % STACKSLOTS_PER_LINE) == 0))
-			printk(KERN_CONT "\n");
-		printk(KERN_CONT " %016lx", *stack++);
+			pr_cont("\n");
+		pr_cont(" %016lx", *stack++);
 		touch_nmi_watchdog();
 	}
 	preempt_enable();
 
-	printk(KERN_CONT "\n");
+	pr_cont("\n");
 	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
 
@@ -254,10 +254,9 @@ void show_regs(struct pt_regs *regs)
 
 	sp = regs->sp;
 	printk("CPU %d ", cpu);
-	print_modules();
 	__show_regs(regs, 1);
-	printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
-		cur->comm, cur->pid, task_thread_info(cur), cur);
+	printk(KERN_DEFAULT "Process %s (pid: %d, threadinfo %p, task %p)\n",
+	       cur->comm, cur->pid, task_thread_info(cur), cur);
 
 	/*
 	 * When in-kernel, we also print out the stack and code at the
@@ -284,16 +283,16 @@ void show_regs(struct pt_regs *regs)
 		for (i = 0; i < code_len; i++, ip++) {
 			if (ip < (u8 *)PAGE_OFFSET ||
 					probe_kernel_address(ip, c)) {
-				printk(KERN_CONT " Bad RIP value.");
+				pr_cont(" Bad RIP value.");
 				break;
 			}
 			if (ip == (u8 *)regs->ip)
-				printk(KERN_CONT "<%02x> ", c);
+				pr_cont("<%02x> ", c);
 			else
-				printk(KERN_CONT "%02x ", c);
+				pr_cont("%02x ", c);
 		}
 	}
-	printk(KERN_CONT "\n");
+	pr_cont("\n");
 }
 
 int is_valid_bugaddr(unsigned long ip)
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 623f288..e8310c8 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -612,6 +612,10 @@ work_notifysig:				# deal with pending signals and
 	movl %esp, %eax
 	jne work_notifysig_v86		# returning to kernel-space or
 					# vm86-space
+1:
+#else
+	movl %esp, %eax
+#endif
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
 	movb PT_CS(%esp), %bl
@@ -622,24 +626,15 @@ work_notifysig:				# deal with pending signals and
 	call do_notify_resume
 	jmp resume_userspace
 
+#ifdef CONFIG_VM86
 	ALIGN
 work_notifysig_v86:
 	pushl_cfi %ecx			# save ti_flags for do_notify_resume
 	call save_v86_state		# %eax contains pt_regs pointer
 	popl_cfi %ecx
 	movl %eax, %esp
-#else
-	movl %esp, %eax
+	jmp 1b
 #endif
-	TRACE_IRQS_ON
-	ENABLE_INTERRUPTS(CLBR_NONE)
-	movb PT_CS(%esp), %bl
-	andb $SEGMENT_RPL_MASK, %bl
-	cmpb $USER_RPL, %bl
-	jb resume_kernel
-	xorl %edx, %edx
-	call do_notify_resume
-	jmp resume_userspace
 END(work_pending)
 
 	# perform syscall exit tracing
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 7d65133..111f6bb 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1758,10 +1758,30 @@ end_repeat_nmi:
 	 */
 	call save_paranoid
 	DEFAULT_FRAME 0
+
+	/*
+	 * Save off the CR2 register. If we take a page fault in the NMI then
+	 * it could corrupt the CR2 value. If the NMI preempts a page fault
+	 * handler before it was able to read the CR2 register, and then the
+	 * NMI itself takes a page fault, the page fault that was preempted
+	 * will read the information from the NMI page fault and not the
+	 * origin fault. Save it off and restore it if it changes.
+	 * Use the r12 callee-saved register.
+	 */
+	movq %cr2, %r12
+
 	/* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
 	movq %rsp,%rdi
 	movq $-1,%rsi
 	call do_nmi
+
+	/* Did the NMI take a page fault? Restore cr2 if it did */
+	movq %cr2, %rcx
+	cmpq %rcx, %r12
+	je 1f
+	movq %r12, %cr2
+1:
+	
 	testl %ebx,%ebx				/* swapgs needed? */
 	jnz nmi_restore
 nmi_swapgs:
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 3dafc60..1f5f1d5 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -294,9 +294,9 @@ void fixup_irqs(void)
 		raw_spin_unlock(&desc->lock);
 
 		if (break_affinity && set_affinity)
-			printk("Broke affinity for irq %i\n", irq);
+			pr_notice("Broke affinity for irq %i\n", irq);
 		else if (!set_affinity)
-			printk("Cannot set affinity for irq %i\n", irq);
+			pr_notice("Cannot set affinity for irq %i\n", irq);
 	}
 
 	/*
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index 8bfb614..3f61904 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -444,12 +444,12 @@ void kgdb_roundup_cpus(unsigned long flags)
 
 /**
  *	kgdb_arch_handle_exception - Handle architecture specific GDB packets.
- *	@vector: The error vector of the exception that happened.
+ *	@e_vector: The error vector of the exception that happened.
  *	@signo: The signal number of the exception that happened.
  *	@err_code: The error code of the exception that happened.
- *	@remcom_in_buffer: The buffer of the packet we have read.
- *	@remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into.
- *	@regs: The &struct pt_regs of the current process.
+ *	@remcomInBuffer: The buffer of the packet we have read.
+ *	@remcomOutBuffer: The buffer of %BUFMAX bytes to write a packet into.
+ *	@linux_regs: The &struct pt_regs of the current process.
  *
  *	This function MUST handle the 'c' and 's' command packets,
  *	as well packets to set / remove a hardware breakpoint, if used.
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
index fbdfc69..c383b3f 100644
--- a/arch/x86/kernel/microcode_core.c
+++ b/arch/x86/kernel/microcode_core.c
@@ -504,7 +504,7 @@ static struct notifier_block __refdata mc_cpu_notifier = {
 
 #ifdef MODULE
 /* Autoload on Intel and AMD systems */
-static const struct x86_cpu_id microcode_id[] = {
+static const struct x86_cpu_id __initconst microcode_id[] = {
 #ifdef CONFIG_MICROCODE_INTEL
 	{ X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, },
 #endif
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index f21fd94..202494d 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -15,6 +15,9 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/moduleloader.h>
 #include <linux/elf.h>
 #include <linux/vmalloc.h>
@@ -30,9 +33,14 @@
 #include <asm/pgtable.h>
 
 #if 0
-#define DEBUGP printk
+#define DEBUGP(fmt, ...)				\
+	printk(KERN_DEBUG fmt, ##__VA_ARGS__)
 #else
-#define DEBUGP(fmt...)
+#define DEBUGP(fmt, ...)				\
+do {							\
+	if (0)						\
+		printk(KERN_DEBUG fmt, ##__VA_ARGS__);	\
+} while (0)
 #endif
 
 void *module_alloc(unsigned long size)
@@ -56,8 +64,8 @@ int apply_relocate(Elf32_Shdr *sechdrs,
 	Elf32_Sym *sym;
 	uint32_t *location;
 
-	DEBUGP("Applying relocate section %u to %u\n", relsec,
-	       sechdrs[relsec].sh_info);
+	DEBUGP("Applying relocate section %u to %u\n",
+	       relsec, sechdrs[relsec].sh_info);
 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
 		/* This is where to make the change */
 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
@@ -77,7 +85,7 @@ int apply_relocate(Elf32_Shdr *sechdrs,
 			*location += sym->st_value - (uint32_t)location;
 			break;
 		default:
-			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+			pr_err("%s: Unknown relocation: %u\n",
 			       me->name, ELF32_R_TYPE(rel[i].r_info));
 			return -ENOEXEC;
 		}
@@ -97,8 +105,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
 	void *loc;
 	u64 val;
 
-	DEBUGP("Applying relocate section %u to %u\n", relsec,
-	       sechdrs[relsec].sh_info);
+	DEBUGP("Applying relocate section %u to %u\n",
+	       relsec, sechdrs[relsec].sh_info);
 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
 		/* This is where to make the change */
 		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
@@ -110,8 +118,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
 			+ ELF64_R_SYM(rel[i].r_info);
 
 		DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
-			(int)ELF64_R_TYPE(rel[i].r_info),
-			sym->st_value, rel[i].r_addend, (u64)loc);
+		       (int)ELF64_R_TYPE(rel[i].r_info),
+		       sym->st_value, rel[i].r_addend, (u64)loc);
 
 		val = sym->st_value + rel[i].r_addend;
 
@@ -140,7 +148,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
 #endif
 			break;
 		default:
-			printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n",
+			pr_err("%s: Unknown rela relocation: %llu\n",
 			       me->name, ELF64_R_TYPE(rel[i].r_info));
 			return -ENOEXEC;
 		}
@@ -148,9 +156,9 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
 	return 0;
 
 overflow:
-	printk(KERN_ERR "overflow in relocation type %d val %Lx\n",
+	pr_err("overflow in relocation type %d val %Lx\n",
 	       (int)ELF64_R_TYPE(rel[i].r_info), val);
-	printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n",
+	pr_err("`%s' likely not compiled with -mcmodel=kernel\n",
 	       me->name);
 	return -ENOEXEC;
 }
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index a0b2f84..f84f5c5 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -365,8 +365,9 @@ static __kprobes void default_do_nmi(struct pt_regs *regs)
 #ifdef CONFIG_X86_32
 /*
  * For i386, NMIs use the same stack as the kernel, and we can
- * add a workaround to the iret problem in C. Simply have 3 states
- * the NMI can be in.
+ * add a workaround to the iret problem in C (preventing nested
+ * NMIs if an NMI takes a trap). Simply have 3 states the NMI
+ * can be in:
  *
  *  1) not running
  *  2) executing
@@ -383,32 +384,50 @@ static __kprobes void default_do_nmi(struct pt_regs *regs)
  * If an NMI hits a breakpoint that executes an iret, another
  * NMI can preempt it. We do not want to allow this new NMI
  * to run, but we want to execute it when the first one finishes.
- * We set the state to "latched", and the first NMI will perform
- * an cmpxchg on the state, and if it doesn't successfully
- * reset the state to "not running" it will restart the next
- * NMI.
+ * We set the state to "latched", and the exit of the first NMI will
+ * perform a dec_return, if the result is zero (NOT_RUNNING), then
+ * it will simply exit the NMI handler. If not, the dec_return
+ * would have set the state to NMI_EXECUTING (what we want it to
+ * be when we are running). In this case, we simply jump back
+ * to rerun the NMI handler again, and restart the 'latched' NMI.
+ *
+ * No trap (breakpoint or page fault) should be hit before nmi_restart,
+ * thus there is no race between the first check of state for NOT_RUNNING
+ * and setting it to NMI_EXECUTING. The HW will prevent nested NMIs
+ * at this point.
+ *
+ * In case the NMI takes a page fault, we need to save off the CR2
+ * because the NMI could have preempted another page fault and corrupt
+ * the CR2 that is about to be read. As nested NMIs must be restarted
+ * and they can not take breakpoints or page faults, the update of the
+ * CR2 must be done before converting the nmi state back to NOT_RUNNING.
+ * Otherwise, there would be a race of another nested NMI coming in
+ * after setting state to NOT_RUNNING but before updating the nmi_cr2.
  */
 enum nmi_states {
-	NMI_NOT_RUNNING,
+	NMI_NOT_RUNNING = 0,
 	NMI_EXECUTING,
 	NMI_LATCHED,
 };
 static DEFINE_PER_CPU(enum nmi_states, nmi_state);
+static DEFINE_PER_CPU(unsigned long, nmi_cr2);
 
 #define nmi_nesting_preprocess(regs)					\
 	do {								\
-		if (__get_cpu_var(nmi_state) != NMI_NOT_RUNNING) {	\
-			__get_cpu_var(nmi_state) = NMI_LATCHED;		\
+		if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) {	\
+			this_cpu_write(nmi_state, NMI_LATCHED);		\
 			return;						\
 		}							\
-	nmi_restart:							\
-		__get_cpu_var(nmi_state) = NMI_EXECUTING;		\
-	} while (0)
+		this_cpu_write(nmi_state, NMI_EXECUTING);		\
+		this_cpu_write(nmi_cr2, read_cr2());			\
+	} while (0);							\
+	nmi_restart:
 
 #define nmi_nesting_postprocess()					\
 	do {								\
-		if (cmpxchg(&__get_cpu_var(nmi_state),			\
-		    NMI_EXECUTING, NMI_NOT_RUNNING) != NMI_EXECUTING)	\
+		if (unlikely(this_cpu_read(nmi_cr2) != read_cr2()))	\
+			write_cr2(this_cpu_read(nmi_cr2));		\
+		if (this_cpu_dec_return(nmi_state))			\
 			goto nmi_restart;				\
 	} while (0)
 #else /* x86_64 */
diff --git a/arch/x86/kernel/nmi_selftest.c b/arch/x86/kernel/nmi_selftest.c
index 149b8d9..6d9582e 100644
--- a/arch/x86/kernel/nmi_selftest.c
+++ b/arch/x86/kernel/nmi_selftest.c
@@ -42,7 +42,8 @@ static int __init nmi_unk_cb(unsigned int val, struct pt_regs *regs)
 static void __init init_nmi_testsuite(void)
 {
 	/* trap all the unknown NMIs we may generate */
-	register_nmi_handler_initonly(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk");
+	register_nmi_handler(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk",
+			__initdata);
 }
 
 static void __init cleanup_nmi_testsuite(void)
@@ -64,8 +65,8 @@ static void __init test_nmi_ipi(struct cpumask *mask)
 {
 	unsigned long timeout;
 
-	if (register_nmi_handler_initonly(NMI_LOCAL, test_nmi_ipi_callback,
-				 NMI_FLAG_FIRST, "nmi_selftest")) {
+	if (register_nmi_handler(NMI_LOCAL, test_nmi_ipi_callback,
+				 NMI_FLAG_FIRST, "nmi_selftest", __initdata)) {
 		nmi_fail = FAILURE;
 		return;
 	}
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 9ce8859..17fff18 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -352,9 +352,7 @@ struct pv_cpu_ops pv_cpu_ops = {
 #endif
 	.wbinvd = native_wbinvd,
 	.read_msr = native_read_msr_safe,
-	.rdmsr_regs = native_rdmsr_safe_regs,
 	.write_msr = native_write_msr_safe,
-	.wrmsr_regs = native_wrmsr_safe_regs,
 	.read_tsc = native_read_tsc,
 	.read_pmc = native_read_pmc,
 	.read_tscp = native_read_tscp,
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index b72838b..299d493 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -22,6 +22,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#define pr_fmt(fmt) "Calgary: " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -245,7 +247,7 @@ static unsigned long iommu_range_alloc(struct device *dev,
 		offset = iommu_area_alloc(tbl->it_map, tbl->it_size, 0,
 					  npages, 0, boundary_size, 0);
 		if (offset == ~0UL) {
-			printk(KERN_WARNING "Calgary: IOMMU full.\n");
+			pr_warn("IOMMU full\n");
 			spin_unlock_irqrestore(&tbl->it_lock, flags);
 			if (panic_on_overflow)
 				panic("Calgary: fix the allocator.\n");
@@ -271,8 +273,8 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
 	entry = iommu_range_alloc(dev, tbl, npages);
 
 	if (unlikely(entry == DMA_ERROR_CODE)) {
-		printk(KERN_WARNING "Calgary: failed to allocate %u pages in "
-		       "iommu %p\n", npages, tbl);
+		pr_warn("failed to allocate %u pages in iommu %p\n",
+			npages, tbl);
 		return DMA_ERROR_CODE;
 	}
 
@@ -561,8 +563,7 @@ static void calgary_tce_cache_blast(struct iommu_table *tbl)
 		i++;
 	} while ((val & 0xff) != 0xff && i < 100);
 	if (i == 100)
-		printk(KERN_WARNING "Calgary: PCI bus not quiesced, "
-		       "continuing anyway\n");
+		pr_warn("PCI bus not quiesced, continuing anyway\n");
 
 	/* invalidate TCE cache */
 	target = calgary_reg(bbar, tar_offset(tbl->it_busno));
@@ -604,8 +605,7 @@ begin:
 		i++;
 	} while ((val64 & 0xff) != 0xff && i < 100);
 	if (i == 100)
-		printk(KERN_WARNING "CalIOC2: PCI bus not quiesced, "
-		       "continuing anyway\n");
+		pr_warn("CalIOC2: PCI bus not quiesced, continuing anyway\n");
 
 	/* 3. poll Page Migration DEBUG for SoftStopFault */
 	target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_DEBUG);
@@ -617,8 +617,7 @@ begin:
 		if (++count < 100)
 			goto begin;
 		else {
-			printk(KERN_WARNING "CalIOC2: too many SoftStopFaults, "
-			       "aborting TCE cache flush sequence!\n");
+			pr_warn("CalIOC2: too many SoftStopFaults, aborting TCE cache flush sequence!\n");
 			return; /* pray for the best */
 		}
 	}
@@ -840,8 +839,8 @@ static void calgary_dump_error_regs(struct iommu_table *tbl)
 	plssr = be32_to_cpu(readl(target));
 
 	/* If no error, the agent ID in the CSR is not valid */
-	printk(KERN_EMERG "Calgary: DMA error on Calgary PHB 0x%x, "
-	       "0x%08x@CSR 0x%08x@PLSSR\n", tbl->it_busno, csr, plssr);
+	pr_emerg("DMA error on Calgary PHB 0x%x, 0x%08x@CSR 0x%08x@PLSSR\n",
+		 tbl->it_busno, csr, plssr);
 }
 
 static void calioc2_dump_error_regs(struct iommu_table *tbl)
@@ -867,22 +866,21 @@ static void calioc2_dump_error_regs(struct iommu_table *tbl)
 	target = calgary_reg(bbar, phboff | 0x800);
 	mck = be32_to_cpu(readl(target));
 
-	printk(KERN_EMERG "Calgary: DMA error on CalIOC2 PHB 0x%x\n",
-	       tbl->it_busno);
+	pr_emerg("DMA error on CalIOC2 PHB 0x%x\n", tbl->it_busno);
 
-	printk(KERN_EMERG "Calgary: 0x%08x@CSR 0x%08x@PLSSR 0x%08x@CSMR 0x%08x@MCK\n",
-	       csr, plssr, csmr, mck);
+	pr_emerg("0x%08x@CSR 0x%08x@PLSSR 0x%08x@CSMR 0x%08x@MCK\n",
+		 csr, plssr, csmr, mck);
 
 	/* dump rest of error regs */
-	printk(KERN_EMERG "Calgary: ");
+	pr_emerg("");
 	for (i = 0; i < ARRAY_SIZE(errregs); i++) {
 		/* err regs are at 0x810 - 0x870 */
 		erroff = (0x810 + (i * 0x10));
 		target = calgary_reg(bbar, phboff | erroff);
 		errregs[i] = be32_to_cpu(readl(target));
-		printk("0x%08x@0x%lx ", errregs[i], erroff);
+		pr_cont("0x%08x@0x%lx ", errregs[i], erroff);
 	}
-	printk("\n");
+	pr_cont("\n");
 
 	/* root complex status */
 	target = calgary_reg(bbar, phboff | PHB_ROOT_COMPLEX_STATUS);
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index c0f420f..de2b7ad 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -45,15 +45,6 @@ int iommu_detected __read_mostly = 0;
  */
 int iommu_pass_through __read_mostly;
 
-/*
- * Group multi-function PCI devices into a single device-group for the
- * iommu_device_group interface.  This tells the iommu driver to pretend
- * it cannot distinguish between functions of a device, exposing only one
- * group for the device.  Useful for disallowing use of individual PCI
- * functions from userspace drivers.
- */
-int iommu_group_mf __read_mostly;
-
 extern struct iommu_table_entry __iommu_table[], __iommu_table_end[];
 
 /* Dummy device used for NULL arguments (normally ISA). */
@@ -194,8 +185,6 @@ static __init int iommu_setup(char *p)
 #endif
 		if (!strncmp(p, "pt", 2))
 			iommu_pass_through = 1;
-		if (!strncmp(p, "group_mf", 8))
-			iommu_group_mf = 1;
 
 		gart_parse_options(p);
 
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 735279e..b89c39e 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -145,16 +147,14 @@ void show_regs_common(void)
 	/* Board Name is optional */
 	board = dmi_get_system_info(DMI_BOARD_NAME);
 
-	printk(KERN_CONT "\n");
-	printk(KERN_DEFAULT "Pid: %d, comm: %.20s %s %s %.*s",
-		current->pid, current->comm, print_tainted(),
-		init_utsname()->release,
-		(int)strcspn(init_utsname()->version, " "),
-		init_utsname()->version);
-	printk(KERN_CONT " %s %s", vendor, product);
-	if (board)
-		printk(KERN_CONT "/%s", board);
-	printk(KERN_CONT "\n");
+	printk(KERN_DEFAULT "Pid: %d, comm: %.20s %s %s %.*s %s %s%s%s\n",
+	       current->pid, current->comm, print_tainted(),
+	       init_utsname()->release,
+	       (int)strcspn(init_utsname()->version, " "),
+	       init_utsname()->version,
+	       vendor, product,
+	       board ? "/" : "",
+	       board ? board : "");
 }
 
 void flush_thread(void)
@@ -355,7 +355,7 @@ long sys_execve(const char __user *name,
 #ifdef CONFIG_X86_32
 	if (error == 0) {
 		/* Make sure we don't return using sysenter.. */
-                set_thread_flag(TIF_IRET);
+                set_thread_flag(TIF_NOTIFY_RESUME);
         }
 #endif
 
@@ -645,7 +645,7 @@ static void amd_e400_idle(void)
 			amd_e400_c1e_detected = true;
 			if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
 				mark_tsc_unstable("TSC halt in AMD C1E");
-			printk(KERN_INFO "System has AMD C1E enabled\n");
+			pr_info("System has AMD C1E enabled\n");
 		}
 	}
 
@@ -659,8 +659,7 @@ static void amd_e400_idle(void)
 			 */
 			clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
 					   &cpu);
-			printk(KERN_INFO "Switch to broadcast mode on CPU%d\n",
-			       cpu);
+			pr_info("Switch to broadcast mode on CPU%d\n", cpu);
 		}
 		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
 
@@ -681,8 +680,7 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
 	if (pm_idle == poll_idle && smp_num_siblings > 1) {
-		printk_once(KERN_WARNING "WARNING: polling idle and HT enabled,"
-			" performance may degrade.\n");
+		pr_warn_once("WARNING: polling idle and HT enabled, performance may degrade\n");
 	}
 #endif
 	if (pm_idle)
@@ -692,11 +690,11 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
 		/*
 		 * One CPU supports mwait => All CPUs supports mwait
 		 */
-		printk(KERN_INFO "using mwait in idle threads.\n");
+		pr_info("using mwait in idle threads\n");
 		pm_idle = mwait_idle;
 	} else if (cpu_has_amd_erratum(amd_erratum_400)) {
 		/* E400: APIC timer interrupt does not wake up CPU from C1e */
-		printk(KERN_INFO "using AMD E400 aware idle routine\n");
+		pr_info("using AMD E400 aware idle routine\n");
 		pm_idle = amd_e400_idle;
 	} else
 		pm_idle = default_idle;
@@ -715,7 +713,7 @@ static int __init idle_setup(char *str)
 		return -EINVAL;
 
 	if (!strcmp(str, "poll")) {
-		printk("using polling idle threads.\n");
+		pr_info("using polling idle threads\n");
 		pm_idle = poll_idle;
 		boot_option_idle_override = IDLE_POLL;
 	} else if (!strcmp(str, "mwait")) {
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 61cdf7f..0a980c9 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -117,10 +117,10 @@ void release_thread(struct task_struct *dead_task)
 {
 	if (dead_task->mm) {
 		if (dead_task->mm->context.size) {
-			printk("WARNING: dead process %8s still has LDT? <%p/%d>\n",
-					dead_task->comm,
-					dead_task->mm->context.ldt,
-					dead_task->mm->context.size);
+			pr_warn("WARNING: dead process %8s still has LDT? <%p/%d>\n",
+				dead_task->comm,
+				dead_task->mm->context.ldt,
+				dead_task->mm->context.size);
 			BUG();
 		}
 	}
@@ -466,7 +466,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
 			task->thread.gs = addr;
 			if (doit) {
 				load_gs_index(0);
-				ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr);
+				ret = wrmsrl_safe(MSR_KERNEL_GS_BASE, addr);
 			}
 		}
 		put_cpu();
@@ -494,7 +494,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
 				/* set the selector to 0 to not confuse
 				   __switch_to */
 				loadsegment(fs, 0);
-				ret = checking_wrmsrl(MSR_FS_BASE, addr);
+				ret = wrmsrl_safe(MSR_FS_BASE, addr);
 			}
 		}
 		put_cpu();
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index 03920a1..1b27de5 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -512,7 +512,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
 
 #if defined(CONFIG_PCI) && defined(CONFIG_NUMA)
 /* Set correct numa_node information for AMD NB functions */
-static void __init quirk_amd_nb_node(struct pci_dev *dev)
+static void __devinit quirk_amd_nb_node(struct pci_dev *dev)
 {
 	struct pci_dev *nb_ht;
 	unsigned int devfn;
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 25b48ed..52190a9 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
@@ -20,14 +22,12 @@
 #include <asm/virtext.h>
 #include <asm/cpu.h>
 #include <asm/nmi.h>
+#include <asm/smp.h>
 
-#ifdef CONFIG_X86_32
-# include <linux/ctype.h>
-# include <linux/mc146818rtc.h>
-# include <asm/realmode.h>
-#else
-# include <asm/x86_init.h>
-#endif
+#include <linux/ctype.h>
+#include <linux/mc146818rtc.h>
+#include <asm/realmode.h>
+#include <asm/x86_init.h>
 
 /*
  * Power off function, if any
@@ -49,7 +49,7 @@ int reboot_force;
  */
 static int reboot_default = 1;
 
-#if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
+#ifdef CONFIG_SMP
 static int reboot_cpu = -1;
 #endif
 
@@ -67,8 +67,8 @@ bool port_cf9_safe = false;
  * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
  * warm   Don't set the cold reboot flag
  * cold   Set the cold reboot flag
- * bios   Reboot by jumping through the BIOS (only for X86_32)
- * smp    Reboot by executing reset on BSP or other CPU (only for X86_32)
+ * bios   Reboot by jumping through the BIOS
+ * smp    Reboot by executing reset on BSP or other CPU
  * triple Force a triple fault (init)
  * kbd    Use the keyboard controller. cold reset (default)
  * acpi   Use the RESET_REG in the FADT
@@ -95,7 +95,6 @@ static int __init reboot_setup(char *str)
 			reboot_mode = 0;
 			break;
 
-#ifdef CONFIG_X86_32
 #ifdef CONFIG_SMP
 		case 's':
 			if (isdigit(*(str+1))) {
@@ -112,7 +111,6 @@ static int __init reboot_setup(char *str)
 #endif /* CONFIG_SMP */
 
 		case 'b':
-#endif
 		case 'a':
 		case 'k':
 		case 't':
@@ -138,7 +136,6 @@ static int __init reboot_setup(char *str)
 __setup("reboot=", reboot_setup);
 
 
-#ifdef CONFIG_X86_32
 /*
  * Reboot options and system auto-detection code provided by
  * Dell Inc. so their systems "just work". :-)
@@ -152,16 +149,14 @@ static int __init set_bios_reboot(const struct dmi_system_id *d)
 {
 	if (reboot_type != BOOT_BIOS) {
 		reboot_type = BOOT_BIOS;
-		printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
+		pr_info("%s series board detected. Selecting %s-method for reboots.\n",
+			"BIOS", d->ident);
 	}
 	return 0;
 }
 
-void machine_real_restart(unsigned int type)
+void __noreturn machine_real_restart(unsigned int type)
 {
-	void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int))
-		real_mode_header->machine_real_restart_asm;
-
 	local_irq_disable();
 
 	/*
@@ -181,25 +176,28 @@ void machine_real_restart(unsigned int type)
 	/*
 	 * Switch back to the initial page table.
 	 */
+#ifdef CONFIG_X86_32
 	load_cr3(initial_page_table);
-
-	/*
-	 * Write 0x1234 to absolute memory location 0x472.  The BIOS reads
-	 * this on booting to tell it to "Bypass memory test (also warm
-	 * boot)".  This seems like a fairly standard thing that gets set by
-	 * REBOOT.COM programs, and the previous reset routine did this
-	 * too. */
-	*((unsigned short *)0x472) = reboot_mode;
+#else
+	write_cr3(real_mode_header->trampoline_pgd);
+#endif
 
 	/* Jump to the identity-mapped low memory code */
-	restart_lowmem(type);
+#ifdef CONFIG_X86_32
+	asm volatile("jmpl *%0" : :
+		     "rm" (real_mode_header->machine_real_restart_asm),
+		     "a" (type));
+#else
+	asm volatile("ljmpl *%0" : :
+		     "m" (real_mode_header->machine_real_restart_asm),
+		     "D" (type));
+#endif
+	unreachable();
 }
 #ifdef CONFIG_APM_MODULE
 EXPORT_SYMBOL(machine_real_restart);
 #endif
 
-#endif /* CONFIG_X86_32 */
-
 /*
  * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
  */
@@ -207,8 +205,8 @@ static int __init set_pci_reboot(const struct dmi_system_id *d)
 {
 	if (reboot_type != BOOT_CF9) {
 		reboot_type = BOOT_CF9;
-		printk(KERN_INFO "%s series board detected. "
-		       "Selecting PCI-method for reboots.\n", d->ident);
+		pr_info("%s series board detected. Selecting %s-method for reboots.\n",
+			"PCI", d->ident);
 	}
 	return 0;
 }
@@ -217,17 +215,16 @@ static int __init set_kbd_reboot(const struct dmi_system_id *d)
 {
 	if (reboot_type != BOOT_KBD) {
 		reboot_type = BOOT_KBD;
-		printk(KERN_INFO "%s series board detected. Selecting KBD-method for reboot.\n", d->ident);
+		pr_info("%s series board detected. Selecting %s-method for reboot.\n",
+			"KBD", d->ident);
 	}
 	return 0;
 }
 
 /*
- * This is a single dmi_table handling all reboot quirks.  Note that
- * REBOOT_BIOS is only available for 32bit
+ * This is a single dmi_table handling all reboot quirks.
  */
 static struct dmi_system_id __initdata reboot_dmi_table[] = {
-#ifdef CONFIG_X86_32
 	{	/* Handle problems with rebooting on Dell E520's */
 		.callback = set_bios_reboot,
 		.ident = "Dell E520",
@@ -377,7 +374,6 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
 			DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
 		},
 	},
-#endif /* CONFIG_X86_32 */
 
 	{	/* Handle reboot issue on Acer Aspire one */
 		.callback = set_kbd_reboot,
@@ -451,6 +447,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"),
 		},
 	},
+	{	/* Handle problems with rebooting on the Precision M6600. */
+		.callback = set_pci_reboot,
+		.ident = "Dell OptiPlex 990",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"),
+		},
+	},
 	{ }
 };
 
@@ -576,13 +580,11 @@ static void native_machine_emergency_restart(void)
 			reboot_type = BOOT_KBD;
 			break;
 
-#ifdef CONFIG_X86_32
 		case BOOT_BIOS:
 			machine_real_restart(MRR_BIOS);
 
 			reboot_type = BOOT_KBD;
 			break;
-#endif
 
 		case BOOT_ACPI:
 			acpi_reboot();
@@ -624,12 +626,10 @@ void native_machine_shutdown(void)
 	/* The boot cpu is always logical cpu 0 */
 	int reboot_cpu_id = 0;
 
-#ifdef CONFIG_X86_32
 	/* See if there has been given a command line override */
 	if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &&
 		cpu_online(reboot_cpu))
 		reboot_cpu_id = reboot_cpu;
-#endif
 
 	/* Make certain the cpu I'm about to reboot on is online */
 	if (!cpu_online(reboot_cpu_id))
@@ -670,7 +670,7 @@ static void __machine_emergency_restart(int emergency)
 
 static void native_machine_restart(char *__unused)
 {
-	printk("machine restart\n");
+	pr_notice("machine restart\n");
 
 	if (!reboot_force)
 		machine_shutdown();
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 16be6dc..f4b9b80 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1031,8 +1031,6 @@ void __init setup_arch(char **cmdline_p)
 
 	x86_init.timers.wallclock_init();
 
-	x86_platform.wallclock_init();
-
 	mcheck_init();
 
 	arch_init_ideal_nops();
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
index 5a98aa2..5cdff03 100644
--- a/arch/x86/kernel/setup_percpu.c
+++ b/arch/x86/kernel/setup_percpu.c
@@ -21,7 +21,7 @@
 #include <asm/cpu.h>
 #include <asm/stackprotector.h>
 
-DEFINE_PER_CPU(int, cpu_number);
+DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number);
 EXPORT_PER_CPU_SYMBOL(cpu_number);
 
 #ifdef CONFIG_X86_64
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 21af737..c648fc5 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -6,6 +6,9 @@
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
  *  2000-2002   x86-64 support by Andi Kleen
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
@@ -797,10 +800,6 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 	}
 	if (thread_info_flags & _TIF_USER_RETURN_NOTIFY)
 		fire_user_return_notifiers();
-
-#ifdef CONFIG_X86_32
-	clear_thread_flag(TIF_IRET);
-#endif /* CONFIG_X86_32 */
 }
 
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
@@ -814,7 +813,7 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
 		       me->comm, me->pid, where, frame,
 		       regs->ip, regs->sp, regs->orig_ax);
 		print_vma_addr(" in ", regs->ip);
-		printk(KERN_CONT "\n");
+		pr_cont("\n");
 	}
 
 	force_sig(SIGSEGV, me);
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 7bd8a08..7c5a8c3 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1,4 +1,4 @@
-/*
+ /*
  *	x86 SMP booting functions
  *
  *	(c) 1995 Alan Cox, Building #3 <alan@lxorguk.ukuu.org.uk>
@@ -39,6 +39,8 @@
  *	Glauber Costa		:	i386 and x86_64 integration
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/module.h>
@@ -104,17 +106,17 @@ int smp_num_siblings = 1;
 EXPORT_SYMBOL(smp_num_siblings);
 
 /* Last level cache ID of each logical CPU */
-DEFINE_PER_CPU(u16, cpu_llc_id) = BAD_APICID;
+DEFINE_PER_CPU_READ_MOSTLY(u16, cpu_llc_id) = BAD_APICID;
 
 /* representing HT siblings of each logical CPU */
-DEFINE_PER_CPU(cpumask_var_t, cpu_sibling_map);
+DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
 EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
 
 /* representing HT and core siblings of each logical CPU */
-DEFINE_PER_CPU(cpumask_var_t, cpu_core_map);
+DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_core_map);
 EXPORT_PER_CPU_SYMBOL(cpu_core_map);
 
-DEFINE_PER_CPU(cpumask_var_t, cpu_llc_shared_map);
+DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map);
 
 /* Per CPU bogomips and other parameters */
 DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
@@ -184,7 +186,7 @@ static void __cpuinit smp_callin(void)
 	 * boards)
 	 */
 
-	pr_debug("CALLIN, before setup_local_APIC().\n");
+	pr_debug("CALLIN, before setup_local_APIC()\n");
 	if (apic->smp_callin_clear_local_apic)
 		apic->smp_callin_clear_local_apic();
 	setup_local_APIC();
@@ -255,22 +257,13 @@ notrace static void __cpuinit start_secondary(void *unused)
 	check_tsc_sync_target();
 
 	/*
-	 * We need to hold call_lock, so there is no inconsistency
-	 * between the time smp_call_function() determines number of
-	 * IPI recipients, and the time when the determination is made
-	 * for which cpus receive the IPI. Holding this
-	 * lock helps us to not include this cpu in a currently in progress
-	 * smp_call_function().
-	 *
 	 * We need to hold vector_lock so there the set of online cpus
 	 * does not change while we are assigning vectors to cpus.  Holding
 	 * this lock ensures we don't half assign or remove an irq from a cpu.
 	 */
-	ipi_call_lock();
 	lock_vector_lock();
 	set_cpu_online(smp_processor_id(), true);
 	unlock_vector_lock();
-	ipi_call_unlock();
 	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 	x86_platform.nmi_init();
 
@@ -432,17 +425,16 @@ static void impress_friends(void)
 	/*
 	 * Allow the user to impress friends.
 	 */
-	pr_debug("Before bogomips.\n");
+	pr_debug("Before bogomips\n");
 	for_each_possible_cpu(cpu)
 		if (cpumask_test_cpu(cpu, cpu_callout_mask))
 			bogosum += cpu_data(cpu).loops_per_jiffy;
-	printk(KERN_INFO
-		"Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+	pr_info("Total of %d processors activated (%lu.%02lu BogoMIPS)\n",
 		num_online_cpus(),
 		bogosum/(500000/HZ),
 		(bogosum/(5000/HZ))%100);
 
-	pr_debug("Before bogocount - setting activated=1.\n");
+	pr_debug("Before bogocount - setting activated=1\n");
 }
 
 void __inquire_remote_apic(int apicid)
@@ -452,18 +444,17 @@ void __inquire_remote_apic(int apicid)
 	int timeout;
 	u32 status;
 
-	printk(KERN_INFO "Inquiring remote APIC 0x%x...\n", apicid);
+	pr_info("Inquiring remote APIC 0x%x...\n", apicid);
 
 	for (i = 0; i < ARRAY_SIZE(regs); i++) {
-		printk(KERN_INFO "... APIC 0x%x %s: ", apicid, names[i]);
+		pr_info("... APIC 0x%x %s: ", apicid, names[i]);
 
 		/*
 		 * Wait for idle.
 		 */
 		status = safe_apic_wait_icr_idle();
 		if (status)
-			printk(KERN_CONT
-			       "a previous APIC delivery may have failed\n");
+			pr_cont("a previous APIC delivery may have failed\n");
 
 		apic_icr_write(APIC_DM_REMRD | regs[i], apicid);
 
@@ -476,10 +467,10 @@ void __inquire_remote_apic(int apicid)
 		switch (status) {
 		case APIC_ICR_RR_VALID:
 			status = apic_read(APIC_RRR);
-			printk(KERN_CONT "%08x\n", status);
+			pr_cont("%08x\n", status);
 			break;
 		default:
-			printk(KERN_CONT "failed\n");
+			pr_cont("failed\n");
 		}
 	}
 }
@@ -513,12 +504,12 @@ wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip)
 			apic_write(APIC_ESR, 0);
 		accept_status = (apic_read(APIC_ESR) & 0xEF);
 	}
-	pr_debug("NMI sent.\n");
+	pr_debug("NMI sent\n");
 
 	if (send_status)
-		printk(KERN_ERR "APIC never delivered???\n");
+		pr_err("APIC never delivered???\n");
 	if (accept_status)
-		printk(KERN_ERR "APIC delivery error (%lx).\n", accept_status);
+		pr_err("APIC delivery error (%lx)\n", accept_status);
 
 	return (send_status | accept_status);
 }
@@ -540,7 +531,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
 		apic_read(APIC_ESR);
 	}
 
-	pr_debug("Asserting INIT.\n");
+	pr_debug("Asserting INIT\n");
 
 	/*
 	 * Turn INIT on target chip
@@ -556,7 +547,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
 
 	mdelay(10);
 
-	pr_debug("Deasserting INIT.\n");
+	pr_debug("Deasserting INIT\n");
 
 	/* Target chip */
 	/* Send IPI */
@@ -589,14 +580,14 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
 	/*
 	 * Run STARTUP IPI loop.
 	 */
-	pr_debug("#startup loops: %d.\n", num_starts);
+	pr_debug("#startup loops: %d\n", num_starts);
 
 	for (j = 1; j <= num_starts; j++) {
-		pr_debug("Sending STARTUP #%d.\n", j);
+		pr_debug("Sending STARTUP #%d\n", j);
 		if (maxlvt > 3)		/* Due to the Pentium erratum 3AP.  */
 			apic_write(APIC_ESR, 0);
 		apic_read(APIC_ESR);
-		pr_debug("After apic_write.\n");
+		pr_debug("After apic_write\n");
 
 		/*
 		 * STARTUP IPI
@@ -613,7 +604,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
 		 */
 		udelay(300);
 
-		pr_debug("Startup point 1.\n");
+		pr_debug("Startup point 1\n");
 
 		pr_debug("Waiting for send to finish...\n");
 		send_status = safe_apic_wait_icr_idle();
@@ -628,12 +619,12 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
 		if (send_status || accept_status)
 			break;
 	}
-	pr_debug("After Startup.\n");
+	pr_debug("After Startup\n");
 
 	if (send_status)
-		printk(KERN_ERR "APIC never delivered???\n");
+		pr_err("APIC never delivered???\n");
 	if (accept_status)
-		printk(KERN_ERR "APIC delivery error (%lx).\n", accept_status);
+		pr_err("APIC delivery error (%lx)\n", accept_status);
 
 	return (send_status | accept_status);
 }
@@ -647,11 +638,11 @@ static void __cpuinit announce_cpu(int cpu, int apicid)
 	if (system_state == SYSTEM_BOOTING) {
 		if (node != current_node) {
 			if (current_node > (-1))
-				pr_cont(" Ok.\n");
+				pr_cont(" OK\n");
 			current_node = node;
 			pr_info("Booting Node %3d, Processors ", node);
 		}
-		pr_cont(" #%d%s", cpu, cpu == (nr_cpu_ids - 1) ? " Ok.\n" : "");
+		pr_cont(" #%d%s", cpu, cpu == (nr_cpu_ids - 1) ? " OK\n" : "");
 		return;
 	} else
 		pr_info("Booting Node %d Processor %d APIC 0x%x\n",
@@ -731,9 +722,9 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
 		/*
 		 * allow APs to start initializing.
 		 */
-		pr_debug("Before Callout %d.\n", cpu);
+		pr_debug("Before Callout %d\n", cpu);
 		cpumask_set_cpu(cpu, cpu_callout_mask);
-		pr_debug("After Callout %d.\n", cpu);
+		pr_debug("After Callout %d\n", cpu);
 
 		/*
 		 * Wait 5s total for a response
@@ -761,7 +752,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
 				pr_err("CPU%d: Stuck ??\n", cpu);
 			else
 				/* trampoline code not run */
-				pr_err("CPU%d: Not responding.\n", cpu);
+				pr_err("CPU%d: Not responding\n", cpu);
 			if (apic->inquire_remote_apic)
 				apic->inquire_remote_apic(apicid);
 		}
@@ -806,7 +797,7 @@ int __cpuinit native_cpu_up(unsigned int cpu, struct task_struct *tidle)
 	if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid ||
 	    !physid_isset(apicid, phys_cpu_present_map) ||
 	    !apic->apic_id_valid(apicid)) {
-		printk(KERN_ERR "%s: bad cpu %d\n", __func__, cpu);
+		pr_err("%s: bad cpu %d\n", __func__, cpu);
 		return -EINVAL;
 	}
 
@@ -887,9 +878,8 @@ static int __init smp_sanity_check(unsigned max_cpus)
 		unsigned int cpu;
 		unsigned nr;
 
-		printk(KERN_WARNING
-		       "More than 8 CPUs detected - skipping them.\n"
-		       "Use CONFIG_X86_BIGSMP.\n");
+		pr_warn("More than 8 CPUs detected - skipping them\n"
+			"Use CONFIG_X86_BIGSMP\n");
 
 		nr = 0;
 		for_each_present_cpu(cpu) {
@@ -910,8 +900,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
 #endif
 
 	if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) {
-		printk(KERN_WARNING
-			"weird, boot CPU (#%d) not listed by the BIOS.\n",
+		pr_warn("weird, boot CPU (#%d) not listed by the BIOS\n",
 			hard_smp_processor_id());
 
 		physid_set(hard_smp_processor_id(), phys_cpu_present_map);
@@ -923,11 +912,10 @@ static int __init smp_sanity_check(unsigned max_cpus)
 	 */
 	if (!smp_found_config && !acpi_lapic) {
 		preempt_enable();
-		printk(KERN_NOTICE "SMP motherboard not detected.\n");
+		pr_notice("SMP motherboard not detected\n");
 		disable_smp();
 		if (APIC_init_uniprocessor())
-			printk(KERN_NOTICE "Local APIC not detected."
-					   " Using dummy APIC emulation.\n");
+			pr_notice("Local APIC not detected. Using dummy APIC emulation.\n");
 		return -1;
 	}
 
@@ -936,9 +924,8 @@ static int __init smp_sanity_check(unsigned max_cpus)
 	 * CPU too, but we do it for the sake of robustness anyway.
 	 */
 	if (!apic->check_phys_apicid_present(boot_cpu_physical_apicid)) {
-		printk(KERN_NOTICE
-			"weird, boot CPU (#%d) not listed by the BIOS.\n",
-			boot_cpu_physical_apicid);
+		pr_notice("weird, boot CPU (#%d) not listed by the BIOS\n",
+			  boot_cpu_physical_apicid);
 		physid_set(hard_smp_processor_id(), phys_cpu_present_map);
 	}
 	preempt_enable();
@@ -951,8 +938,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
 		if (!disable_apic) {
 			pr_err("BIOS bug, local APIC #%d not detected!...\n",
 				boot_cpu_physical_apicid);
-			pr_err("... forcing use of dummy APIC emulation."
-				"(tell your hw vendor)\n");
+			pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n");
 		}
 		smpboot_clear_io_apic();
 		disable_ioapic_support();
@@ -965,7 +951,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
 	 * If SMP should be disabled, then really disable it!
 	 */
 	if (!max_cpus) {
-		printk(KERN_INFO "SMP mode deactivated.\n");
+		pr_info("SMP mode deactivated\n");
 		smpboot_clear_io_apic();
 
 		connect_bsp_APIC();
@@ -1017,7 +1003,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 
 
 	if (smp_sanity_check(max_cpus) < 0) {
-		printk(KERN_INFO "SMP disabled\n");
+		pr_info("SMP disabled\n");
 		disable_smp();
 		goto out;
 	}
@@ -1055,7 +1041,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 	 * Set up local APIC timer on boot CPU.
 	 */
 
-	printk(KERN_INFO "CPU%d: ", 0);
+	pr_info("CPU%d: ", 0);
 	print_cpu_info(&cpu_data(0));
 	x86_init.timers.setup_percpu_clockev();
 
@@ -1105,7 +1091,7 @@ void __init native_smp_prepare_boot_cpu(void)
 
 void __init native_smp_cpus_done(unsigned int max_cpus)
 {
-	pr_debug("Boot done.\n");
+	pr_debug("Boot done\n");
 
 	nmi_selftest();
 	impress_friends();
@@ -1166,8 +1152,7 @@ __init void prefill_possible_map(void)
 
 	/* nr_cpu_ids could be reduced via nr_cpus= */
 	if (possible > nr_cpu_ids) {
-		printk(KERN_WARNING
-			"%d Processors exceeds NR_CPUS limit of %d\n",
+		pr_warn("%d Processors exceeds NR_CPUS limit of %d\n",
 			possible, nr_cpu_ids);
 		possible = nr_cpu_ids;
 	}
@@ -1176,13 +1161,12 @@ __init void prefill_possible_map(void)
 	if (!setup_max_cpus)
 #endif
 	if (possible > i) {
-		printk(KERN_WARNING
-			"%d Processors exceeds max_cpus limit of %u\n",
+		pr_warn("%d Processors exceeds max_cpus limit of %u\n",
 			possible, setup_max_cpus);
 		possible = i;
 	}
 
-	printk(KERN_INFO "SMP: Allowing %d CPUs, %d hotplug CPUs\n",
+	pr_info("Allowing %d CPUs, %d hotplug CPUs\n",
 		possible, max_t(int, possible - num_processors, 0));
 
 	for (i = 0; i < possible; i++)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 05b31d9..b481341 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -9,6 +9,9 @@
 /*
  * Handle hardware traps and faults.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/interrupt.h>
 #include <linux/kallsyms.h>
 #include <linux/spinlock.h>
@@ -143,12 +146,11 @@ trap_signal:
 #ifdef CONFIG_X86_64
 	if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
 	    printk_ratelimit()) {
-		printk(KERN_INFO
-		       "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
-		       tsk->comm, tsk->pid, str,
-		       regs->ip, regs->sp, error_code);
+		pr_info("%s[%d] trap %s ip:%lx sp:%lx error:%lx",
+			tsk->comm, tsk->pid, str,
+			regs->ip, regs->sp, error_code);
 		print_vma_addr(" in ", regs->ip);
-		printk("\n");
+		pr_cont("\n");
 	}
 #endif
 
@@ -269,12 +271,11 @@ do_general_protection(struct pt_regs *regs, long error_code)
 
 	if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
 			printk_ratelimit()) {
-		printk(KERN_INFO
-			"%s[%d] general protection ip:%lx sp:%lx error:%lx",
+		pr_info("%s[%d] general protection ip:%lx sp:%lx error:%lx",
 			tsk->comm, task_pid_nr(tsk),
 			regs->ip, regs->sp, error_code);
 		print_vma_addr(" in ", regs->ip);
-		printk("\n");
+		pr_cont("\n");
 	}
 
 	force_sig(SIGSEGV, tsk);
@@ -570,7 +571,7 @@ do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
 	conditional_sti(regs);
 #if 0
 	/* No need to warn about this any longer. */
-	printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
+	pr_info("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
 #endif
 }
 
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index fc0a147..cfa5d4f 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/init.h>
@@ -84,8 +86,7 @@ EXPORT_SYMBOL_GPL(check_tsc_unstable);
 #ifdef CONFIG_X86_TSC
 int __init notsc_setup(char *str)
 {
-	printk(KERN_WARNING "notsc: Kernel compiled with CONFIG_X86_TSC, "
-			"cannot disable TSC completely.\n");
+	pr_warn("Kernel compiled with CONFIG_X86_TSC, cannot disable TSC completely\n");
 	tsc_disabled = 1;
 	return 1;
 }
@@ -373,7 +374,7 @@ static unsigned long quick_pit_calibrate(void)
 			goto success;
 		}
 	}
-	printk("Fast TSC calibration failed\n");
+	pr_err("Fast TSC calibration failed\n");
 	return 0;
 
 success:
@@ -392,7 +393,7 @@ success:
 	 */
 	delta *= PIT_TICK_RATE;
 	do_div(delta, i*256*1000);
-	printk("Fast TSC calibration using PIT\n");
+	pr_info("Fast TSC calibration using PIT\n");
 	return delta;
 }
 
@@ -487,9 +488,8 @@ unsigned long native_calibrate_tsc(void)
 		 * use the reference value, as it is more precise.
 		 */
 		if (delta >= 90 && delta <= 110) {
-			printk(KERN_INFO
-			       "TSC: PIT calibration matches %s. %d loops\n",
-			       hpet ? "HPET" : "PMTIMER", i + 1);
+			pr_info("PIT calibration matches %s. %d loops\n",
+				hpet ? "HPET" : "PMTIMER", i + 1);
 			return tsc_ref_min;
 		}
 
@@ -511,38 +511,36 @@ unsigned long native_calibrate_tsc(void)
 	 */
 	if (tsc_pit_min == ULONG_MAX) {
 		/* PIT gave no useful value */
-		printk(KERN_WARNING "TSC: Unable to calibrate against PIT\n");
+		pr_warn("Unable to calibrate against PIT\n");
 
 		/* We don't have an alternative source, disable TSC */
 		if (!hpet && !ref1 && !ref2) {
-			printk("TSC: No reference (HPET/PMTIMER) available\n");
+			pr_notice("No reference (HPET/PMTIMER) available\n");
 			return 0;
 		}
 
 		/* The alternative source failed as well, disable TSC */
 		if (tsc_ref_min == ULONG_MAX) {
-			printk(KERN_WARNING "TSC: HPET/PMTIMER calibration "
-			       "failed.\n");
+			pr_warn("HPET/PMTIMER calibration failed\n");
 			return 0;
 		}
 
 		/* Use the alternative source */
-		printk(KERN_INFO "TSC: using %s reference calibration\n",
-		       hpet ? "HPET" : "PMTIMER");
+		pr_info("using %s reference calibration\n",
+			hpet ? "HPET" : "PMTIMER");
 
 		return tsc_ref_min;
 	}
 
 	/* We don't have an alternative source, use the PIT calibration value */
 	if (!hpet && !ref1 && !ref2) {
-		printk(KERN_INFO "TSC: Using PIT calibration value\n");
+		pr_info("Using PIT calibration value\n");
 		return tsc_pit_min;
 	}
 
 	/* The alternative source failed, use the PIT calibration value */
 	if (tsc_ref_min == ULONG_MAX) {
-		printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed. "
-		       "Using PIT calibration\n");
+		pr_warn("HPET/PMTIMER calibration failed. Using PIT calibration.\n");
 		return tsc_pit_min;
 	}
 
@@ -551,9 +549,9 @@ unsigned long native_calibrate_tsc(void)
 	 * the PIT value as we know that there are PMTIMERs around
 	 * running at double speed. At least we let the user know:
 	 */
-	printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n",
-	       hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min);
-	printk(KERN_INFO "TSC: Using PIT calibration value\n");
+	pr_warn("PIT calibration deviates from %s: %lu %lu\n",
+		hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min);
+	pr_info("Using PIT calibration value\n");
 	return tsc_pit_min;
 }
 
@@ -785,7 +783,7 @@ void mark_tsc_unstable(char *reason)
 		tsc_unstable = 1;
 		sched_clock_stable = 0;
 		disable_sched_clock_irqtime();
-		printk(KERN_INFO "Marking TSC unstable due to %s\n", reason);
+		pr_info("Marking TSC unstable due to %s\n", reason);
 		/* Change only the rating, when not registered */
 		if (clocksource_tsc.mult)
 			clocksource_mark_unstable(&clocksource_tsc);
@@ -912,9 +910,9 @@ static void tsc_refine_calibration_work(struct work_struct *work)
 		goto out;
 
 	tsc_khz = freq;
-	printk(KERN_INFO "Refined TSC clocksource calibration: "
-		"%lu.%03lu MHz.\n", (unsigned long)tsc_khz / 1000,
-					(unsigned long)tsc_khz % 1000);
+	pr_info("Refined TSC clocksource calibration: %lu.%03lu MHz\n",
+		(unsigned long)tsc_khz / 1000,
+		(unsigned long)tsc_khz % 1000);
 
 out:
 	clocksource_register_khz(&clocksource_tsc, tsc_khz);
@@ -970,9 +968,9 @@ void __init tsc_init(void)
 		return;
 	}
 
-	printk("Detected %lu.%03lu MHz processor.\n",
-			(unsigned long)cpu_khz / 1000,
-			(unsigned long)cpu_khz % 1000);
+	pr_info("Detected %lu.%03lu MHz processor\n",
+		(unsigned long)cpu_khz / 1000,
+		(unsigned long)cpu_khz % 1000);
 
 	/*
 	 * Secondary CPUs do not run through tsc_init(), so set up
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index dc4e910..36fd420 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -409,9 +409,10 @@ static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm,
  * arch_uprobe_analyze_insn - instruction analysis including validity and fixups.
  * @mm: the probed address space.
  * @arch_uprobe: the probepoint information.
+ * @addr: virtual address at which to install the probepoint
  * Return 0 on success or a -ve number on error.
  */
-int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm)
+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr)
 {
 	int ret;
 	struct insn insn;
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 255f58a..20245a2 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -28,6 +28,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
@@ -137,14 +139,14 @@ struct pt_regs *save_v86_state(struct kernel_vm86_regs *regs)
 	local_irq_enable();
 
 	if (!current->thread.vm86_info) {
-		printk("no vm86_info: BAD\n");
+		pr_alert("no vm86_info: BAD\n");
 		do_exit(SIGSEGV);
 	}
 	set_flags(regs->pt.flags, VEFLAGS, X86_EFLAGS_VIF | current->thread.v86mask);
 	tmp = copy_vm86_regs_to_user(&current->thread.vm86_info->regs, regs);
 	tmp += put_user(current->thread.screen_bitmap, &current->thread.vm86_info->screen_bitmap);
 	if (tmp) {
-		printk("vm86: could not access userspace vm86_info\n");
+		pr_alert("could not access userspace vm86_info\n");
 		do_exit(SIGSEGV);
 	}
 
@@ -561,7 +563,7 @@ int handle_vm86_trap(struct kernel_vm86_regs *regs, long error_code, int trapno)
 			/* setting this flag forces the code in entry_32.S to
 			   call save_v86_state() and change the stack pointer
 			   to KVM86->regs32 */
-			set_thread_flag(TIF_IRET);
+			set_thread_flag(TIF_NOTIFY_RESUME);
 			return 0;
 		}
 		do_int(regs, trapno, (unsigned char __user *) (regs->pt.ss << 4), SP(regs));
diff --git a/arch/x86/kernel/vsmp_64.c b/arch/x86/kernel/vsmp_64.c
index 8eeb55a..fa5adb7 100644
--- a/arch/x86/kernel/vsmp_64.c
+++ b/arch/x86/kernel/vsmp_64.c
@@ -16,6 +16,7 @@
 #include <linux/pci_ids.h>
 #include <linux/pci_regs.h>
 #include <linux/smp.h>
+#include <linux/irq.h>
 
 #include <asm/apic.h>
 #include <asm/pci-direct.h>
@@ -95,6 +96,18 @@ static void __init set_vsmp_pv_ops(void)
 	ctl = readl(address + 4);
 	printk(KERN_INFO "vSMP CTL: capabilities:0x%08x  control:0x%08x\n",
 	       cap, ctl);
+
+	/* If possible, let the vSMP foundation route the interrupt optimally */
+#ifdef CONFIG_SMP
+	if (cap & ctl & BIT(8)) {
+		ctl &= ~BIT(8);
+#ifdef CONFIG_PROC_FS
+		/* Don't let users change irq affinity via procfs */
+		no_irq_affinity = 1;
+#endif
+	}
+#endif
+
 	if (cap & ctl & (1 << 4)) {
 		/* Setup irq ops and turn on vSMP  IRQ fastpath handling */
 		pv_irq_ops.irq_disable = PV_CALLEE_SAVE(vsmp_irq_disable);
@@ -102,12 +115,11 @@ static void __init set_vsmp_pv_ops(void)
 		pv_irq_ops.save_fl  = PV_CALLEE_SAVE(vsmp_save_fl);
 		pv_irq_ops.restore_fl  = PV_CALLEE_SAVE(vsmp_restore_fl);
 		pv_init_ops.patch = vsmp_patch;
-
 		ctl &= ~(1 << 4);
-		writel(ctl, address + 4);
-		ctl = readl(address + 4);
-		printk(KERN_INFO "vSMP CTL: control set to:0x%08x\n", ctl);
 	}
+	writel(ctl, address + 4);
+	ctl = readl(address + 4);
+	pr_info("vSMP CTL: control set to:0x%08x\n", ctl);
 
 	early_iounmap(address, 8);
 }
@@ -187,12 +199,36 @@ static void __init vsmp_cap_cpus(void)
 #endif
 }
 
+static int apicid_phys_pkg_id(int initial_apic_id, int index_msb)
+{
+	return hard_smp_processor_id() >> index_msb;
+}
+
+/*
+ * In vSMP, all cpus should be capable of handling interrupts, regardless of
+ * the APIC used.
+ */
+static bool fill_vector_allocation_domain(int cpu, struct cpumask *retmask)
+{
+	cpumask_setall(retmask);
+	return false;
+}
+
+static void vsmp_apic_post_init(void)
+{
+	/* need to update phys_pkg_id */
+	apic->phys_pkg_id = apicid_phys_pkg_id;
+	apic->vector_allocation_domain = fill_vector_allocation_domain;
+}
+
 void __init vsmp_init(void)
 {
 	detect_vsmp_box();
 	if (!is_vsmp_box())
 		return;
 
+	x86_platform.apic_post_init = vsmp_apic_post_init;
+
 	vsmp_cap_cpus();
 
 	set_vsmp_pv_ops();
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index 7515cf0..acdc125 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -18,6 +18,8 @@
  *  use the vDSO.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -111,18 +113,13 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
 static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
 			      const char *message)
 {
-	static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
-	struct task_struct *tsk;
-
-	if (!show_unhandled_signals || !__ratelimit(&rs))
+	if (!show_unhandled_signals)
 		return;
 
-	tsk = current;
-
-	printk("%s%s[%d] %s ip:%lx cs:%lx sp:%lx ax:%lx si:%lx di:%lx\n",
-	       level, tsk->comm, task_pid_nr(tsk),
-	       message, regs->ip, regs->cs,
-	       regs->sp, regs->ax, regs->si, regs->di);
+	pr_notice_ratelimited("%s%s[%d] %s ip:%lx cs:%lx sp:%lx ax:%lx si:%lx di:%lx\n",
+			      level, current->comm, task_pid_nr(current),
+			      message, regs->ip, regs->cs,
+			      regs->sp, regs->ax, regs->si, regs->di);
 }
 
 static int addr_to_vsyscall_nr(unsigned long addr)
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 35c5e54..9f3167e 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -29,7 +29,6 @@ void __init x86_init_uint_noop(unsigned int unused) { }
 void __init x86_init_pgd_noop(pgd_t *unused) { }
 int __init iommu_init_noop(void) { return 0; }
 void iommu_shutdown_noop(void) { }
-void wallclock_init_noop(void) { }
 
 /*
  * The platform setup functions are preset with the default functions
@@ -101,7 +100,6 @@ static int default_i8042_detect(void) { return 1; };
 
 struct x86_platform_ops x86_platform = {
 	.calibrate_tsc			= native_calibrate_tsc,
-	.wallclock_init			= wallclock_init_noop,
 	.get_wallclock			= mach_get_cmos_time,
 	.set_wallclock			= mach_set_rtc_mmss,
 	.iommu_shutdown			= iommu_shutdown_noop,
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index bd18149..3d3e207 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -3,6 +3,9 @@
  *
  * Author: Suresh Siddha <suresh.b.siddha@intel.com>
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bootmem.h>
 #include <linux/compat.h>
 #include <asm/i387.h>
@@ -162,7 +165,7 @@ int save_i387_xstate(void __user *buf)
 	BUG_ON(sig_xstate_size < xstate_size);
 
 	if ((unsigned long)buf % 64)
-		printk("save_i387_xstate: bad fpstate %p\n", buf);
+		pr_err("%s: bad fpstate %p\n", __func__, buf);
 
 	if (!used_math())
 		return 0;
@@ -422,7 +425,7 @@ static void __init xstate_enable_boot_cpu(void)
 	pcntxt_mask = eax + ((u64)edx << 32);
 
 	if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
-		printk(KERN_ERR "FP/SSE not shown under xsave features 0x%llx\n",
+		pr_err("FP/SSE not shown under xsave features 0x%llx\n",
 		       pcntxt_mask);
 		BUG();
 	}
@@ -445,9 +448,8 @@ static void __init xstate_enable_boot_cpu(void)
 
 	setup_xstate_init();
 
-	printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%llx, "
-	       "cntxt size 0x%x\n",
-	       pcntxt_mask, xstate_size);
+	pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n",
+		pcntxt_mask, xstate_size);
 }
 
 /*
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index be3cea4..3b53d9e 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -90,7 +90,7 @@ module_param(dbg, bool, 0644);
 
 #define PTE_PREFETCH_NUM		8
 
-#define PT_FIRST_AVAIL_BITS_SHIFT 9
+#define PT_FIRST_AVAIL_BITS_SHIFT 10
 #define PT64_SECOND_AVAIL_BITS_SHIFT 52
 
 #define PT64_LEVEL_BITS 9
@@ -652,8 +652,7 @@ static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
 				mmu_page_header_cache);
 }
 
-static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
-				    size_t size)
+static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc)
 {
 	void *p;
 
@@ -664,8 +663,7 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
 
 static struct pte_list_desc *mmu_alloc_pte_list_desc(struct kvm_vcpu *vcpu)
 {
-	return mmu_memory_cache_alloc(&vcpu->arch.mmu_pte_list_desc_cache,
-				      sizeof(struct pte_list_desc));
+	return mmu_memory_cache_alloc(&vcpu->arch.mmu_pte_list_desc_cache);
 }
 
 static void mmu_free_pte_list_desc(struct pte_list_desc *pte_list_desc)
@@ -1238,11 +1236,12 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
 			 unsigned long data)
 {
 	u64 *sptep;
-	struct rmap_iterator iter;
+	struct rmap_iterator uninitialized_var(iter);
 	int young = 0;
 
 	/*
-	 * Emulate the accessed bit for EPT, by checking if this page has
+	 * In case of absence of EPT Access and Dirty Bits supports,
+	 * emulate the accessed bit for EPT, by checking if this page has
 	 * an EPT mapping, and clearing it if it does. On the next access,
 	 * a new EPT mapping will be established.
 	 * This has some overhead, but not as much as the cost of swapping
@@ -1253,11 +1252,12 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
 
 	for (sptep = rmap_get_first(*rmapp, &iter); sptep;
 	     sptep = rmap_get_next(&iter)) {
-		BUG_ON(!(*sptep & PT_PRESENT_MASK));
+		BUG_ON(!is_shadow_present_pte(*sptep));
 
-		if (*sptep & PT_ACCESSED_MASK) {
+		if (*sptep & shadow_accessed_mask) {
 			young = 1;
-			clear_bit(PT_ACCESSED_SHIFT, (unsigned long *)sptep);
+			clear_bit((ffs(shadow_accessed_mask) - 1),
+				 (unsigned long *)sptep);
 		}
 	}
 
@@ -1281,9 +1281,9 @@ static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
 
 	for (sptep = rmap_get_first(*rmapp, &iter); sptep;
 	     sptep = rmap_get_next(&iter)) {
-		BUG_ON(!(*sptep & PT_PRESENT_MASK));
+		BUG_ON(!is_shadow_present_pte(*sptep));
 
-		if (*sptep & PT_ACCESSED_MASK) {
+		if (*sptep & shadow_accessed_mask) {
 			young = 1;
 			break;
 		}
@@ -1401,12 +1401,10 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
 					       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 = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache);
+	sp->spt = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache);
 	if (!direct)
-		sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache,
-						  PAGE_SIZE);
+		sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache);
 	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_MEM_SLOTS_NUM);
@@ -3942,7 +3940,6 @@ static void kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm,
 static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc)
 {
 	struct kvm *kvm;
-	struct kvm *kvm_freed = NULL;
 	int nr_to_scan = sc->nr_to_scan;
 
 	if (nr_to_scan == 0)
@@ -3954,22 +3951,30 @@ static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc)
 		int idx;
 		LIST_HEAD(invalid_list);
 
+		/*
+		 * n_used_mmu_pages is accessed without holding kvm->mmu_lock
+		 * here. We may skip a VM instance errorneosly, but we do not
+		 * want to shrink a VM that only started to populate its MMU
+		 * anyway.
+		 */
+		if (kvm->arch.n_used_mmu_pages > 0) {
+			if (!nr_to_scan--)
+				break;
+			continue;
+		}
+
 		idx = srcu_read_lock(&kvm->srcu);
 		spin_lock(&kvm->mmu_lock);
-		if (!kvm_freed && nr_to_scan > 0 &&
-		    kvm->arch.n_used_mmu_pages > 0) {
-			kvm_mmu_remove_some_alloc_mmu_pages(kvm,
-							    &invalid_list);
-			kvm_freed = kvm;
-		}
-		nr_to_scan--;
 
+		kvm_mmu_remove_some_alloc_mmu_pages(kvm, &invalid_list);
 		kvm_mmu_commit_zap_page(kvm, &invalid_list);
+
 		spin_unlock(&kvm->mmu_lock);
 		srcu_read_unlock(&kvm->srcu, idx);
+
+		list_move_tail(&kvm->vm_list, &vm_list);
+		break;
 	}
-	if (kvm_freed)
-		list_move_tail(&kvm_freed->vm_list, &vm_list);
 
 	raw_spin_unlock(&kvm_lock);
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index f75af40..7a41878 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3185,8 +3185,8 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
 		break;
 	case MSR_IA32_DEBUGCTLMSR:
 		if (!boot_cpu_has(X86_FEATURE_LBRV)) {
-			pr_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTL 0x%llx, nop\n",
-					__func__, data);
+			vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTL 0x%llx, nop\n",
+				    __func__, data);
 			break;
 		}
 		if (data & DEBUGCTL_RESERVED_BITS)
@@ -3205,7 +3205,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
 	case MSR_VM_CR:
 		return svm_set_vm_cr(vcpu, data);
 	case MSR_VM_IGNNE:
-		pr_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
+		vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
 		break;
 	default:
 		return kvm_set_msr_common(vcpu, ecx, data);
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 32eb588..eeeb4a2 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -71,6 +71,9 @@ static bool __read_mostly enable_unrestricted_guest = 1;
 module_param_named(unrestricted_guest,
 			enable_unrestricted_guest, bool, S_IRUGO);
 
+static bool __read_mostly enable_ept_ad_bits = 1;
+module_param_named(eptad, enable_ept_ad_bits, bool, S_IRUGO);
+
 static bool __read_mostly emulate_invalid_guest_state = 0;
 module_param(emulate_invalid_guest_state, bool, S_IRUGO);
 
@@ -615,6 +618,10 @@ static void kvm_cpu_vmxon(u64 addr);
 static void kvm_cpu_vmxoff(void);
 static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
 static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr);
+static void vmx_set_segment(struct kvm_vcpu *vcpu,
+			    struct kvm_segment *var, int seg);
+static void vmx_get_segment(struct kvm_vcpu *vcpu,
+			    struct kvm_segment *var, int seg);
 
 static DEFINE_PER_CPU(struct vmcs *, vmxarea);
 static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
@@ -789,6 +796,11 @@ 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_ept_ad_bits(void)
+{
+	return vmx_capability.ept & VMX_EPT_AD_BIT;
+}
+
 static inline bool cpu_has_vmx_invept_individual_addr(void)
 {
 	return vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT;
@@ -2645,8 +2657,12 @@ static __init int hardware_setup(void)
 	    !cpu_has_vmx_ept_4levels()) {
 		enable_ept = 0;
 		enable_unrestricted_guest = 0;
+		enable_ept_ad_bits = 0;
 	}
 
+	if (!cpu_has_vmx_ept_ad_bits())
+		enable_ept_ad_bits = 0;
+
 	if (!cpu_has_vmx_unrestricted_guest())
 		enable_unrestricted_guest = 0;
 
@@ -2770,6 +2786,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
 {
 	unsigned long flags;
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	struct kvm_segment var;
 
 	if (enable_unrestricted_guest)
 		return;
@@ -2813,20 +2830,23 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
 	if (emulate_invalid_guest_state)
 		goto continue_rmode;
 
-	vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4);
-	vmcs_write32(GUEST_SS_LIMIT, 0xffff);
-	vmcs_write32(GUEST_SS_AR_BYTES, 0xf3);
+	vmx_get_segment(vcpu, &var, VCPU_SREG_SS);
+	vmx_set_segment(vcpu, &var, VCPU_SREG_SS);
+
+	vmx_get_segment(vcpu, &var, VCPU_SREG_CS);
+	vmx_set_segment(vcpu, &var, VCPU_SREG_CS);
 
-	vmcs_write32(GUEST_CS_AR_BYTES, 0xf3);
-	vmcs_write32(GUEST_CS_LIMIT, 0xffff);
-	if (vmcs_readl(GUEST_CS_BASE) == 0xffff0000)
-		vmcs_writel(GUEST_CS_BASE, 0xf0000);
-	vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4);
+	vmx_get_segment(vcpu, &var, VCPU_SREG_ES);
+	vmx_set_segment(vcpu, &var, VCPU_SREG_ES);
 
-	fix_rmode_seg(VCPU_SREG_ES, &vmx->rmode.es);
-	fix_rmode_seg(VCPU_SREG_DS, &vmx->rmode.ds);
-	fix_rmode_seg(VCPU_SREG_GS, &vmx->rmode.gs);
-	fix_rmode_seg(VCPU_SREG_FS, &vmx->rmode.fs);
+	vmx_get_segment(vcpu, &var, VCPU_SREG_DS);
+	vmx_set_segment(vcpu, &var, VCPU_SREG_DS);
+
+	vmx_get_segment(vcpu, &var, VCPU_SREG_GS);
+	vmx_set_segment(vcpu, &var, VCPU_SREG_GS);
+
+	vmx_get_segment(vcpu, &var, VCPU_SREG_FS);
+	vmx_set_segment(vcpu, &var, VCPU_SREG_FS);
 
 continue_rmode:
 	kvm_mmu_reset_context(vcpu);
@@ -3027,6 +3047,8 @@ static u64 construct_eptp(unsigned long root_hpa)
 	/* TODO write the value reading from MSR */
 	eptp = VMX_EPT_DEFAULT_MT |
 		VMX_EPT_DEFAULT_GAW << VMX_EPT_GAW_EPTP_SHIFT;
+	if (enable_ept_ad_bits)
+		eptp |= VMX_EPT_AD_ENABLE_BIT;
 	eptp |= (root_hpa & PAGE_MASK);
 
 	return eptp;
@@ -3229,6 +3251,44 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
 
 	vmcs_write32(sf->ar_bytes, ar);
 	__clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
+
+	/*
+	 * Fix segments for real mode guest in hosts that don't have
+	 * "unrestricted_mode" or it was disabled.
+	 * This is done to allow migration of the guests from hosts with
+	 * unrestricted guest like Westmere to older host that don't have
+	 * unrestricted guest like Nehelem.
+	 */
+	if (!enable_unrestricted_guest && vmx->rmode.vm86_active) {
+		switch (seg) {
+		case VCPU_SREG_CS:
+			vmcs_write32(GUEST_CS_AR_BYTES, 0xf3);
+			vmcs_write32(GUEST_CS_LIMIT, 0xffff);
+			if (vmcs_readl(GUEST_CS_BASE) == 0xffff0000)
+				vmcs_writel(GUEST_CS_BASE, 0xf0000);
+			vmcs_write16(GUEST_CS_SELECTOR,
+				     vmcs_readl(GUEST_CS_BASE) >> 4);
+			break;
+		case VCPU_SREG_ES:
+			fix_rmode_seg(VCPU_SREG_ES, &vmx->rmode.es);
+			break;
+		case VCPU_SREG_DS:
+			fix_rmode_seg(VCPU_SREG_DS, &vmx->rmode.ds);
+			break;
+		case VCPU_SREG_GS:
+			fix_rmode_seg(VCPU_SREG_GS, &vmx->rmode.gs);
+			break;
+		case VCPU_SREG_FS:
+			fix_rmode_seg(VCPU_SREG_FS, &vmx->rmode.fs);
+			break;
+		case VCPU_SREG_SS:
+			vmcs_write16(GUEST_SS_SELECTOR,
+				     vmcs_readl(GUEST_SS_BASE) >> 4);
+			vmcs_write32(GUEST_SS_LIMIT, 0xffff);
+			vmcs_write32(GUEST_SS_AR_BYTES, 0xf3);
+			break;
+		}
+	}
 }
 
 static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
@@ -4489,7 +4549,7 @@ static int handle_cr(struct kvm_vcpu *vcpu)
 		break;
 	}
 	vcpu->run->exit_reason = 0;
-	pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n",
+	vcpu_unimpl(vcpu, "unhandled control register: op %d cr %d\n",
 	       (int)(exit_qualification >> 4) & 3, cr);
 	return 0;
 }
@@ -7275,8 +7335,10 @@ static int __init vmx_init(void)
 	vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
 
 	if (enable_ept) {
-		kvm_mmu_set_mask_ptes(0ull, 0ull, 0ull, 0ull,
-				VMX_EPT_EXECUTABLE_MASK);
+		kvm_mmu_set_mask_ptes(0ull,
+			(enable_ept_ad_bits) ? VMX_EPT_ACCESS_BIT : 0ull,
+			(enable_ept_ad_bits) ? VMX_EPT_DIRTY_BIT : 0ull,
+			0ull, VMX_EPT_EXECUTABLE_MASK);
 		ept_set_mmio_spte_mask();
 		kvm_enable_tdp();
 	} else
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index be6d549..a01a424 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1437,8 +1437,8 @@ static int set_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 		break;
 	}
 	default:
-		pr_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x "
-			  "data 0x%llx\n", msr, data);
+		vcpu_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x "
+			    "data 0x%llx\n", msr, data);
 		return 1;
 	}
 	return 0;
@@ -1470,8 +1470,8 @@ static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 	case HV_X64_MSR_TPR:
 		return kvm_hv_vapic_msr_write(vcpu, APIC_TASKPRI, data);
 	default:
-		pr_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x "
-			  "data 0x%llx\n", msr, data);
+		vcpu_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x "
+			    "data 0x%llx\n", msr, data);
 		return 1;
 	}
 
@@ -1551,15 +1551,15 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 		data &= ~(u64)0x100;	/* ignore ignne emulation enable */
 		data &= ~(u64)0x8;	/* ignore TLB cache disable */
 		if (data != 0) {
-			pr_unimpl(vcpu, "unimplemented HWCR wrmsr: 0x%llx\n",
-				data);
+			vcpu_unimpl(vcpu, "unimplemented HWCR wrmsr: 0x%llx\n",
+				    data);
 			return 1;
 		}
 		break;
 	case MSR_FAM10H_MMIO_CONF_BASE:
 		if (data != 0) {
-			pr_unimpl(vcpu, "unimplemented MMIO_CONF_BASE wrmsr: "
-				"0x%llx\n", data);
+			vcpu_unimpl(vcpu, "unimplemented MMIO_CONF_BASE wrmsr: "
+				    "0x%llx\n", data);
 			return 1;
 		}
 		break;
@@ -1574,8 +1574,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 			   thus reserved and should throw a #GP */
 			return 1;
 		}
-		pr_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTLMSR 0x%llx, nop\n",
-			__func__, data);
+		vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTLMSR 0x%llx, nop\n",
+			    __func__, data);
 		break;
 	case MSR_IA32_UCODE_REV:
 	case MSR_IA32_UCODE_WRITE:
@@ -1671,8 +1671,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 	case MSR_K7_EVNTSEL2:
 	case MSR_K7_EVNTSEL3:
 		if (data != 0)
-			pr_unimpl(vcpu, "unimplemented perfctr wrmsr: "
-				"0x%x data 0x%llx\n", msr, data);
+			vcpu_unimpl(vcpu, "unimplemented perfctr wrmsr: "
+				    "0x%x data 0x%llx\n", msr, data);
 		break;
 	/* at least RHEL 4 unconditionally writes to the perfctr registers,
 	 * so we ignore writes to make it happy.
@@ -1681,8 +1681,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 	case MSR_K7_PERFCTR1:
 	case MSR_K7_PERFCTR2:
 	case MSR_K7_PERFCTR3:
-		pr_unimpl(vcpu, "unimplemented perfctr wrmsr: "
-			"0x%x data 0x%llx\n", msr, data);
+		vcpu_unimpl(vcpu, "unimplemented perfctr wrmsr: "
+			    "0x%x data 0x%llx\n", msr, data);
 		break;
 	case MSR_P6_PERFCTR0:
 	case MSR_P6_PERFCTR1:
@@ -1693,8 +1693,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 			return kvm_pmu_set_msr(vcpu, msr, data);
 
 		if (pr || data != 0)
-			pr_unimpl(vcpu, "disabled perfctr wrmsr: "
-				"0x%x data 0x%llx\n", msr, data);
+			vcpu_unimpl(vcpu, "disabled perfctr wrmsr: "
+				    "0x%x data 0x%llx\n", msr, data);
 		break;
 	case MSR_K7_CLK_CTL:
 		/*
@@ -1720,7 +1720,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 		/* Drop writes to this legacy MSR -- see rdmsr
 		 * counterpart for further detail.
 		 */
-		pr_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n", msr, data);
+		vcpu_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n", msr, data);
 		break;
 	case MSR_AMD64_OSVW_ID_LENGTH:
 		if (!guest_cpuid_has_osvw(vcpu))
@@ -1738,12 +1738,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 		if (kvm_pmu_msr(vcpu, msr))
 			return kvm_pmu_set_msr(vcpu, msr, data);
 		if (!ignore_msrs) {
-			pr_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n",
-				msr, data);
+			vcpu_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n",
+				    msr, data);
 			return 1;
 		} else {
-			pr_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n",
-				msr, data);
+			vcpu_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n",
+				    msr, data);
 			break;
 		}
 	}
@@ -1846,7 +1846,7 @@ static int get_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
 		data = kvm->arch.hv_hypercall;
 		break;
 	default:
-		pr_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
+		vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
 		return 1;
 	}
 
@@ -1877,7 +1877,7 @@ static int get_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
 		data = vcpu->arch.hv_vapic;
 		break;
 	default:
-		pr_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
+		vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
 		return 1;
 	}
 	*pdata = data;
@@ -2030,10 +2030,10 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
 		if (kvm_pmu_msr(vcpu, msr))
 			return kvm_pmu_get_msr(vcpu, msr, pdata);
 		if (!ignore_msrs) {
-			pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
+			vcpu_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
 			return 1;
 		} else {
-			pr_unimpl(vcpu, "ignored rdmsr: 0x%x\n", msr);
+			vcpu_unimpl(vcpu, "ignored rdmsr: 0x%x\n", msr);
 			data = 0;
 		}
 		break;
@@ -4116,7 +4116,7 @@ static unsigned long emulator_get_cr(struct x86_emulate_ctxt *ctxt, int cr)
 		value = kvm_get_cr8(vcpu);
 		break;
 	default:
-		vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
+		kvm_err("%s: unexpected cr %u\n", __func__, cr);
 		return 0;
 	}
 
@@ -4145,7 +4145,7 @@ static int emulator_set_cr(struct x86_emulate_ctxt *ctxt, int cr, ulong val)
 		res = kvm_set_cr8(vcpu, val);
 		break;
 	default:
-		vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
+		kvm_err("%s: unexpected cr %u\n", __func__, cr);
 		res = -1;
 	}
 
@@ -6304,7 +6304,7 @@ void kvm_arch_free_memslot(struct kvm_memory_slot *free,
 
 	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
 		if (!dont || free->arch.lpage_info[i] != dont->arch.lpage_info[i]) {
-			vfree(free->arch.lpage_info[i]);
+			kvm_kvfree(free->arch.lpage_info[i]);
 			free->arch.lpage_info[i] = NULL;
 		}
 	}
@@ -6323,7 +6323,7 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
 				      slot->base_gfn, level) + 1;
 
 		slot->arch.lpage_info[i] =
-			vzalloc(lpages * sizeof(*slot->arch.lpage_info[i]));
+			kvm_kvzalloc(lpages * sizeof(*slot->arch.lpage_info[i]));
 		if (!slot->arch.lpage_info[i])
 			goto out_free;
 
diff --git a/arch/x86/lib/csum-wrappers_64.c b/arch/x86/lib/csum-wrappers_64.c
index 459b58a..25b7ae8 100644
--- a/arch/x86/lib/csum-wrappers_64.c
+++ b/arch/x86/lib/csum-wrappers_64.c
@@ -115,7 +115,7 @@ EXPORT_SYMBOL(csum_partial_copy_to_user);
  * @src: source address
  * @dst: destination address
  * @len: number of bytes to be copied.
- * @isum: initial sum that is added into the result (32bit unfolded)
+ * @sum: initial sum that is added into the result (32bit unfolded)
  *
  * Returns an 32bit unfolded checksum of the buffer.
  */
diff --git a/arch/x86/lib/msr-reg-export.c b/arch/x86/lib/msr-reg-export.c
index a311cc5..8d6ef78 100644
--- a/arch/x86/lib/msr-reg-export.c
+++ b/arch/x86/lib/msr-reg-export.c
@@ -1,5 +1,5 @@
 #include <linux/module.h>
 #include <asm/msr.h>
 
-EXPORT_SYMBOL(native_rdmsr_safe_regs);
-EXPORT_SYMBOL(native_wrmsr_safe_regs);
+EXPORT_SYMBOL(rdmsr_safe_regs);
+EXPORT_SYMBOL(wrmsr_safe_regs);
diff --git a/arch/x86/lib/msr-reg.S b/arch/x86/lib/msr-reg.S
index 69fa106..f6d13ee 100644
--- a/arch/x86/lib/msr-reg.S
+++ b/arch/x86/lib/msr-reg.S
@@ -6,13 +6,13 @@
 
 #ifdef CONFIG_X86_64
 /*
- * int native_{rdmsr,wrmsr}_safe_regs(u32 gprs[8]);
+ * int {rdmsr,wrmsr}_safe_regs(u32 gprs[8]);
  *
  * reg layout: u32 gprs[eax, ecx, edx, ebx, esp, ebp, esi, edi]
  *
  */
 .macro op_safe_regs op
-ENTRY(native_\op\()_safe_regs)
+ENTRY(\op\()_safe_regs)
 	CFI_STARTPROC
 	pushq_cfi %rbx
 	pushq_cfi %rbp
@@ -45,13 +45,13 @@ ENTRY(native_\op\()_safe_regs)
 
 	_ASM_EXTABLE(1b, 3b)
 	CFI_ENDPROC
-ENDPROC(native_\op\()_safe_regs)
+ENDPROC(\op\()_safe_regs)
 .endm
 
 #else /* X86_32 */
 
 .macro op_safe_regs op
-ENTRY(native_\op\()_safe_regs)
+ENTRY(\op\()_safe_regs)
 	CFI_STARTPROC
 	pushl_cfi %ebx
 	pushl_cfi %ebp
@@ -92,7 +92,7 @@ ENTRY(native_\op\()_safe_regs)
 
 	_ASM_EXTABLE(1b, 3b)
 	CFI_ENDPROC
-ENDPROC(native_\op\()_safe_regs)
+ENDPROC(\op\()_safe_regs)
 .endm
 
 #endif
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index bc4e9d8..e0e6990 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -385,7 +385,7 @@ void free_initmem(void)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
+void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
 	/*
 	 * end could be not aligned, and We can not align that,
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index a718e0d..931930a 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -919,11 +919,13 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
 
 	/*
 	 * On success we use clflush, when the CPU supports it to
-	 * avoid the wbindv. If the CPU does not support it and in the
-	 * error case we fall back to cpa_flush_all (which uses
-	 * wbindv):
+	 * avoid the wbindv. If the CPU does not support it, in the
+	 * error case, and during early boot (for EFI) we fall back
+	 * to cpa_flush_all (which uses wbinvd):
 	 */
-	if (!ret && cpu_has_clflush) {
+	if (early_boot_irqs_disabled)
+		__cpa_flush_all((void *)(long)cache);
+	else if (!ret && cpu_has_clflush) {
 		if (cpa.flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) {
 			cpa_flush_array(addr, numpages, cache,
 					cpa.flags, pages);
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 0597f95..33643a8 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -309,6 +309,10 @@ void bpf_jit_compile(struct sk_filter *fp)
 				else
 					EMIT1_off32(0x0d, K);	/* or imm32,%eax */
 				break;
+			case BPF_S_ANC_ALU_XOR_X: /* A ^= X; */
+				seen |= SEEN_XREG;
+				EMIT2(0x31, 0xd8);		/* xor %ebx,%eax */
+				break;
 			case BPF_S_ALU_LSH_X: /* A <<= X; */
 				seen |= SEEN_XREG;
 				EMIT4(0x89, 0xd9, 0xd3, 0xe0);	/* mov %ebx,%ecx; shl %cl,%eax */
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index fc09c27..505acdd 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -12,8 +12,13 @@ struct pci_root_info {
 	char name[16];
 	unsigned int res_num;
 	struct resource *res;
-	int busnum;
 	struct pci_sysdata sd;
+#ifdef	CONFIG_PCI_MMCONFIG
+	bool mcfg_added;
+	u16 segment;
+	u8 start_bus;
+	u8 end_bus;
+#endif
 };
 
 static bool pci_use_crs = true;
@@ -120,6 +125,81 @@ void __init pci_acpi_crs_quirks(void)
 	       pci_use_crs ? "nocrs" : "use_crs");
 }
 
+#ifdef	CONFIG_PCI_MMCONFIG
+static int __devinit check_segment(u16 seg, struct device *dev, char *estr)
+{
+	if (seg) {
+		dev_err(dev,
+			"%s can't access PCI configuration "
+			"space under this host bridge.\n",
+			estr);
+		return -EIO;
+	}
+
+	/*
+	 * Failure in adding MMCFG information is not fatal,
+	 * just can't access extended configuration space of
+	 * devices under this host bridge.
+	 */
+	dev_warn(dev,
+		 "%s can't access extended PCI configuration "
+		 "space under this bridge.\n",
+		 estr);
+
+	return 0;
+}
+
+static int __devinit setup_mcfg_map(struct pci_root_info *info,
+				    u16 seg, u8 start, u8 end,
+				    phys_addr_t addr)
+{
+	int result;
+	struct device *dev = &info->bridge->dev;
+
+	info->start_bus = start;
+	info->end_bus = end;
+	info->mcfg_added = false;
+
+	/* return success if MMCFG is not in use */
+	if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg)
+		return 0;
+
+	if (!(pci_probe & PCI_PROBE_MMCONF))
+		return check_segment(seg, dev, "MMCONFIG is disabled,");
+
+	result = pci_mmconfig_insert(dev, seg, start, end, addr);
+	if (result == 0) {
+		/* enable MMCFG if it hasn't been enabled yet */
+		if (raw_pci_ext_ops == NULL)
+			raw_pci_ext_ops = &pci_mmcfg;
+		info->mcfg_added = true;
+	} else if (result != -EEXIST)
+		return check_segment(seg, dev,
+			 "fail to add MMCONFIG information,");
+
+	return 0;
+}
+
+static void teardown_mcfg_map(struct pci_root_info *info)
+{
+	if (info->mcfg_added) {
+		pci_mmconfig_delete(info->segment, info->start_bus,
+				    info->end_bus);
+		info->mcfg_added = false;
+	}
+}
+#else
+static int __devinit setup_mcfg_map(struct pci_root_info *info,
+				    u16 seg, u8 start, u8 end,
+				    phys_addr_t addr)
+{
+	return 0;
+}
+static void teardown_mcfg_map(struct pci_root_info *info)
+{
+}
+#endif
+
 static acpi_status
 resource_to_addr(struct acpi_resource *resource,
 			struct acpi_resource_address64 *addr)
@@ -234,13 +314,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
 	}
 
 	info->res_num++;
-	if (addr.translation_offset)
-		dev_info(&info->bridge->dev, "host bridge window %pR "
-			 "(PCI address [%#llx-%#llx])\n",
-			 res, res->start - addr.translation_offset,
-			 res->end - addr.translation_offset);
-	else
-		dev_info(&info->bridge->dev, "host bridge window %pR\n", res);
 
 	return AE_OK;
 }
@@ -332,8 +405,11 @@ static void __release_pci_root_info(struct pci_root_info *info)
 
 	free_pci_root_info_res(info);
 
+	teardown_mcfg_map(info);
+
 	kfree(info);
 }
+
 static void release_pci_root_info(struct pci_host_bridge *bridge)
 {
 	struct pci_root_info *info = bridge->release_data;
@@ -347,7 +423,9 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
 {
 	size_t size;
 
+	sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
 	info->bridge = device;
+
 	info->res_num = 0;
 	acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
 				info);
@@ -360,8 +438,6 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
 	if (!info->res)
 		return;
 
-	sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
-
 	acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
 				info);
 }
@@ -373,7 +449,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
 	int domain = root->segment;
 	int busnum = root->secondary.start;
 	LIST_HEAD(resources);
-	struct pci_bus *bus;
+	struct pci_bus *bus = NULL;
 	struct pci_sysdata *sd;
 	int node;
 #ifdef CONFIG_ACPI_NUMA
@@ -426,6 +502,8 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
 	} else {
 		probe_pci_root_info(info, device, busnum, domain);
 
+		/* insert busn res at first */
+		pci_add_resource(&resources,  &root->secondary);
 		/*
 		 * _CRS with no apertures is normal, so only fall back to
 		 * defaults or native bridge info if we're ignoring _CRS.
@@ -437,10 +515,13 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
 			x86_pci_root_bus_resources(busnum, &resources);
 		}
 
-		bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd,
-					  &resources);
+		if (!setup_mcfg_map(info, domain, (u8)root->secondary.start,
+				    (u8)root->secondary.end, root->mcfg_addr))
+			bus = pci_create_root_bus(NULL, busnum, &pci_root_ops,
+						  sd, &resources);
+
 		if (bus) {
-			bus->subordinate = pci_scan_child_bus(bus);
+			pci_scan_child_bus(bus);
 			pci_set_host_bridge_release(
 				to_pci_host_bridge(bus->bridge),
 				release_pci_root_info, info);
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index 5aed49b..e9e6ed5 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -121,7 +121,6 @@ static int __init early_fill_mp_bus_info(void)
 		link = (reg >> 8) & 0x03;
 
 		info = alloc_pci_root_info(min_bus, max_bus, node, link);
-		sprintf(info->name, "PCI Bus #%02x", min_bus);
 	}
 
 	/* get the default node and link for left over res */
@@ -300,9 +299,9 @@ static int __init early_fill_mp_bus_info(void)
 		int busnum;
 		struct pci_root_res *root_res;
 
-		busnum = info->bus_min;
-		printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n",
-		       info->bus_min, info->bus_max, info->node, info->link);
+		busnum = info->busn.start;
+		printk(KERN_DEBUG "bus: %pR on node %x link %x\n",
+		       &info->busn, info->node, info->link);
 		list_for_each_entry(root_res, &info->resources, list)
 			printk(KERN_DEBUG "bus: %02x %pR\n",
 				       busnum, &root_res->res);
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
index 306579f..d37e2fe 100644
--- a/arch/x86/pci/bus_numa.c
+++ b/arch/x86/pci/bus_numa.c
@@ -14,7 +14,7 @@ static struct pci_root_info *x86_find_pci_root_info(int bus)
 		return NULL;
 
 	list_for_each_entry(info, &pci_root_infos, list)
-		if (info->bus_min == bus)
+		if (info->busn.start == bus)
 			return info;
 
 	return NULL;
@@ -24,6 +24,8 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources)
 {
 	struct pci_root_info *info = x86_find_pci_root_info(bus);
 	struct pci_root_res *root_res;
+	struct pci_host_bridge_window *window;
+	bool found = false;
 
 	if (!info)
 		goto default_resources;
@@ -31,6 +33,16 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources)
 	printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n",
 	       bus);
 
+	/* already added by acpi ? */
+	list_for_each_entry(window, resources, list)
+		if (window->res->flags & IORESOURCE_BUS) {
+			found = true;
+			break;
+		}
+
+	if (!found)
+		pci_add_resource(resources, &info->busn);
+
 	list_for_each_entry(root_res, &info->resources, list) {
 		struct resource *res;
 		struct resource *root;
@@ -66,9 +78,13 @@ struct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max,
 	if (!info)
 		return info;
 
+	sprintf(info->name, "PCI Bus #%02x", bus_min);
+
 	INIT_LIST_HEAD(&info->resources);
-	info->bus_min = bus_min;
-	info->bus_max = bus_max;
+	info->busn.name  = info->name;
+	info->busn.start = bus_min;
+	info->busn.end   = bus_max;
+	info->busn.flags = IORESOURCE_BUS;
 	info->node = node;
 	info->link = link;
 
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h
index 226a466..ff8f65b 100644
--- a/arch/x86/pci/bus_numa.h
+++ b/arch/x86/pci/bus_numa.h
@@ -13,8 +13,7 @@ struct pci_root_info {
 	struct list_head list;
 	char name[12];
 	struct list_head resources;
-	int bus_min;
-	int bus_max;
+	struct resource busn;
 	int node;
 	int link;
 };
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index 301e325..937bcec 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -17,6 +17,8 @@
 #include <linux/bitmap.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/rculist.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 #include <asm/acpi.h>
@@ -24,7 +26,9 @@
 #define PREFIX "PCI: "
 
 /* Indicate if the mmcfg resources have been placed into the resource table. */
-static int __initdata pci_mmcfg_resources_inserted;
+static bool pci_mmcfg_running_state;
+static bool pci_mmcfg_arch_init_failed;
+static DEFINE_MUTEX(pci_mmcfg_lock);
 
 LIST_HEAD(pci_mmcfg_list);
 
@@ -45,24 +49,25 @@ static __init void free_all_mmcfg(void)
 		pci_mmconfig_remove(cfg);
 }
 
-static __init void list_add_sorted(struct pci_mmcfg_region *new)
+static __devinit void list_add_sorted(struct pci_mmcfg_region *new)
 {
 	struct pci_mmcfg_region *cfg;
 
 	/* keep list sorted by segment and starting bus number */
-	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
 		if (cfg->segment > new->segment ||
 		    (cfg->segment == new->segment &&
 		     cfg->start_bus >= new->start_bus)) {
-			list_add_tail(&new->list, &cfg->list);
+			list_add_tail_rcu(&new->list, &cfg->list);
 			return;
 		}
 	}
-	list_add_tail(&new->list, &pci_mmcfg_list);
+	list_add_tail_rcu(&new->list, &pci_mmcfg_list);
 }
 
-static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
-							int end, u64 addr)
+static __devinit struct pci_mmcfg_region *pci_mmconfig_alloc(int segment,
+							     int start,
+							     int end, u64 addr)
 {
 	struct pci_mmcfg_region *new;
 	struct resource *res;
@@ -79,8 +84,6 @@ static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
 	new->start_bus = start;
 	new->end_bus = end;
 
-	list_add_sorted(new);
-
 	res = &new->res;
 	res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
 	res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
@@ -89,9 +92,25 @@ static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
 		 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
 	res->name = new->name;
 
-	printk(KERN_INFO PREFIX "MMCONFIG for domain %04x [bus %02x-%02x] at "
-	       "%pR (base %#lx)\n", segment, start, end, &new->res,
-	       (unsigned long) addr);
+	return new;
+}
+
+static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
+							int end, u64 addr)
+{
+	struct pci_mmcfg_region *new;
+
+	new = pci_mmconfig_alloc(segment, start, end, addr);
+	if (new) {
+		mutex_lock(&pci_mmcfg_lock);
+		list_add_sorted(new);
+		mutex_unlock(&pci_mmcfg_lock);
+
+		pr_info(PREFIX
+		       "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
+		       "(base %#lx)\n",
+		       segment, start, end, &new->res, (unsigned long)addr);
+	}
 
 	return new;
 }
@@ -100,7 +119,7 @@ struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
 {
 	struct pci_mmcfg_region *cfg;
 
-	list_for_each_entry(cfg, &pci_mmcfg_list, list)
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
 		if (cfg->segment == segment &&
 		    cfg->start_bus <= bus && bus <= cfg->end_bus)
 			return cfg;
@@ -343,8 +362,7 @@ static int __init pci_mmcfg_check_hostbridge(void)
 			name = pci_mmcfg_probes[i].probe();
 
 		if (name)
-			printk(KERN_INFO PREFIX "%s with MMCONFIG support\n",
-			       name);
+			pr_info(PREFIX "%s with MMCONFIG support\n", name);
 	}
 
 	/* some end_bus_number is crazy, fix it */
@@ -353,19 +371,8 @@ static int __init pci_mmcfg_check_hostbridge(void)
 	return !list_empty(&pci_mmcfg_list);
 }
 
-static void __init pci_mmcfg_insert_resources(void)
-{
-	struct pci_mmcfg_region *cfg;
-
-	list_for_each_entry(cfg, &pci_mmcfg_list, list)
-		insert_resource(&iomem_resource, &cfg->res);
-
-	/* Mark that the resources have been inserted. */
-	pci_mmcfg_resources_inserted = 1;
-}
-
-static acpi_status __init check_mcfg_resource(struct acpi_resource *res,
-					      void *data)
+static acpi_status __devinit check_mcfg_resource(struct acpi_resource *res,
+						 void *data)
 {
 	struct resource *mcfg_res = data;
 	struct acpi_resource_address64 address;
@@ -401,8 +408,8 @@ static acpi_status __init check_mcfg_resource(struct acpi_resource *res,
 	return AE_OK;
 }
 
-static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl,
-		void *context, void **rv)
+static acpi_status __devinit find_mboard_resource(acpi_handle handle, u32 lvl,
+						  void *context, void **rv)
 {
 	struct resource *mcfg_res = context;
 
@@ -415,7 +422,7 @@ static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl,
 	return AE_OK;
 }
 
-static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used)
+static int __devinit is_acpi_reserved(u64 start, u64 end, unsigned not_used)
 {
 	struct resource mcfg_res;
 
@@ -434,13 +441,15 @@ static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used)
 
 typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);
 
-static int __init is_mmconf_reserved(check_reserved_t is_reserved,
-				    struct pci_mmcfg_region *cfg, int with_e820)
+static int __ref is_mmconf_reserved(check_reserved_t is_reserved,
+				    struct pci_mmcfg_region *cfg,
+				    struct device *dev, int with_e820)
 {
 	u64 addr = cfg->res.start;
 	u64 size = resource_size(&cfg->res);
 	u64 old_size = size;
-	int valid = 0, num_buses;
+	int num_buses;
+	char *method = with_e820 ? "E820" : "ACPI motherboard resources";
 
 	while (!is_reserved(addr, addr + size, E820_RESERVED)) {
 		size >>= 1;
@@ -448,30 +457,76 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved,
 			break;
 	}
 
-	if (size >= (16UL<<20) || size == old_size) {
-		printk(KERN_INFO PREFIX "MMCONFIG at %pR reserved in %s\n",
-		       &cfg->res,
-		       with_e820 ? "E820" : "ACPI motherboard resources");
-		valid = 1;
-
-		if (old_size != size) {
-			/* update end_bus */
-			cfg->end_bus = cfg->start_bus + ((size>>20) - 1);
-			num_buses = cfg->end_bus - cfg->start_bus + 1;
-			cfg->res.end = cfg->res.start +
-			    PCI_MMCFG_BUS_OFFSET(num_buses) - 1;
-			snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN,
-				 "PCI MMCONFIG %04x [bus %02x-%02x]",
-				 cfg->segment, cfg->start_bus, cfg->end_bus);
-			printk(KERN_INFO PREFIX
-			       "MMCONFIG for %04x [bus%02x-%02x] "
-			       "at %pR (base %#lx) (size reduced!)\n",
-			       cfg->segment, cfg->start_bus, cfg->end_bus,
-			       &cfg->res, (unsigned long) cfg->address);
-		}
+	if (size < (16UL<<20) && size != old_size)
+		return 0;
+
+	if (dev)
+		dev_info(dev, "MMCONFIG at %pR reserved in %s\n",
+			 &cfg->res, method);
+	else
+		pr_info(PREFIX "MMCONFIG at %pR reserved in %s\n",
+		       &cfg->res, method);
+
+	if (old_size != size) {
+		/* update end_bus */
+		cfg->end_bus = cfg->start_bus + ((size>>20) - 1);
+		num_buses = cfg->end_bus - cfg->start_bus + 1;
+		cfg->res.end = cfg->res.start +
+		    PCI_MMCFG_BUS_OFFSET(num_buses) - 1;
+		snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN,
+			 "PCI MMCONFIG %04x [bus %02x-%02x]",
+			 cfg->segment, cfg->start_bus, cfg->end_bus);
+
+		if (dev)
+			dev_info(dev,
+				"MMCONFIG "
+				"at %pR (base %#lx) (size reduced!)\n",
+				&cfg->res, (unsigned long) cfg->address);
+		else
+			pr_info(PREFIX
+				"MMCONFIG for %04x [bus%02x-%02x] "
+				"at %pR (base %#lx) (size reduced!)\n",
+				cfg->segment, cfg->start_bus, cfg->end_bus,
+				&cfg->res, (unsigned long) cfg->address);
 	}
 
-	return valid;
+	return 1;
+}
+
+static int __ref pci_mmcfg_check_reserved(struct device *dev,
+		  struct pci_mmcfg_region *cfg, int early)
+{
+	if (!early && !acpi_disabled) {
+		if (is_mmconf_reserved(is_acpi_reserved, cfg, dev, 0))
+			return 1;
+
+		if (dev)
+			dev_info(dev, FW_INFO
+				 "MMCONFIG at %pR not reserved in "
+				 "ACPI motherboard resources\n",
+				 &cfg->res);
+		else
+			pr_info(FW_INFO PREFIX
+			       "MMCONFIG at %pR not reserved in "
+			       "ACPI motherboard resources\n",
+			       &cfg->res);
+	}
+
+	/*
+	 * e820_all_mapped() is marked as __init.
+	 * All entries from ACPI MCFG table have been checked at boot time.
+	 * For MCFG information constructed from hotpluggable host bridge's
+	 * _CBA method, just assume it's reserved.
+	 */
+	if (pci_mmcfg_running_state)
+		return 1;
+
+	/* Don't try to do this check unless configuration
+	   type 1 is available. how about type 2 ?*/
+	if (raw_pci_ops)
+		return is_mmconf_reserved(e820_all_mapped, cfg, dev, 1);
+
+	return 0;
 }
 
 static void __init pci_mmcfg_reject_broken(int early)
@@ -479,38 +534,14 @@ static void __init pci_mmcfg_reject_broken(int early)
 	struct pci_mmcfg_region *cfg;
 
 	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
-		int valid = 0;
-
-		if (!early && !acpi_disabled) {
-			valid = is_mmconf_reserved(is_acpi_reserved, cfg, 0);
-
-			if (valid)
-				continue;
-			else
-				printk(KERN_ERR FW_BUG PREFIX
-				       "MMCONFIG at %pR not reserved in "
-				       "ACPI motherboard resources\n",
-				       &cfg->res);
+		if (pci_mmcfg_check_reserved(NULL, cfg, early) == 0) {
+			pr_info(PREFIX "not using MMCONFIG\n");
+			free_all_mmcfg();
+			return;
 		}
-
-		/* Don't try to do this check unless configuration
-		   type 1 is available. how about type 2 ?*/
-		if (raw_pci_ops)
-			valid = is_mmconf_reserved(e820_all_mapped, cfg, 1);
-
-		if (!valid)
-			goto reject;
 	}
-
-	return;
-
-reject:
-	printk(KERN_INFO PREFIX "not using MMCONFIG\n");
-	free_all_mmcfg();
 }
 
-static int __initdata known_bridge;
-
 static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
 					struct acpi_mcfg_allocation *cfg)
 {
@@ -529,7 +560,7 @@ static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
 			return 0;
 	}
 
-	printk(KERN_ERR PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
+	pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
 	       "is above 4GB, ignored\n", cfg->pci_segment,
 	       cfg->start_bus_number, cfg->end_bus_number, cfg->address);
 	return -EINVAL;
@@ -556,7 +587,7 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header)
 		i -= sizeof(struct acpi_mcfg_allocation);
 	};
 	if (entries == 0) {
-		printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
+		pr_err(PREFIX "MMCONFIG has no entries\n");
 		return -ENODEV;
 	}
 
@@ -570,8 +601,7 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header)
 
 		if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
 				   cfg->end_bus_number, cfg->address) == NULL) {
-			printk(KERN_WARNING PREFIX
-			       "no memory for MCFG entries\n");
+			pr_warn(PREFIX "no memory for MCFG entries\n");
 			free_all_mmcfg();
 			return -ENOMEM;
 		}
@@ -582,28 +612,7 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header)
 
 static void __init __pci_mmcfg_init(int early)
 {
-	/* MMCONFIG disabled */
-	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
-		return;
-
-	/* MMCONFIG already enabled */
-	if (!early && !(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF))
-		return;
-
-	/* for late to exit */
-	if (known_bridge)
-		return;
-
-	if (early) {
-		if (pci_mmcfg_check_hostbridge())
-			known_bridge = 1;
-	}
-
-	if (!known_bridge)
-		acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
-
 	pci_mmcfg_reject_broken(early);
-
 	if (list_empty(&pci_mmcfg_list))
 		return;
 
@@ -620,33 +629,48 @@ static void __init __pci_mmcfg_init(int early)
 	if (pci_mmcfg_arch_init())
 		pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
 	else {
-		/*
-		 * Signal not to attempt to insert mmcfg resources because
-		 * the architecture mmcfg setup could not initialize.
-		 */
-		pci_mmcfg_resources_inserted = 1;
+		free_all_mmcfg();
+		pci_mmcfg_arch_init_failed = true;
 	}
 }
 
+static int __initdata known_bridge;
+
 void __init pci_mmcfg_early_init(void)
 {
-	__pci_mmcfg_init(1);
+	if (pci_probe & PCI_PROBE_MMCONF) {
+		if (pci_mmcfg_check_hostbridge())
+			known_bridge = 1;
+		else
+			acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+		__pci_mmcfg_init(1);
+	}
 }
 
 void __init pci_mmcfg_late_init(void)
 {
-	__pci_mmcfg_init(0);
+	/* MMCONFIG disabled */
+	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
+		return;
+
+	if (known_bridge)
+		return;
+
+	/* MMCONFIG hasn't been enabled yet, try again */
+	if (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) {
+		acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+		__pci_mmcfg_init(0);
+	}
 }
 
 static int __init pci_mmcfg_late_insert_resources(void)
 {
-	/*
-	 * If resources are already inserted or we are not using MMCONFIG,
-	 * don't insert the resources.
-	 */
-	if ((pci_mmcfg_resources_inserted == 1) ||
-	    (pci_probe & PCI_PROBE_MMCONF) == 0 ||
-	    list_empty(&pci_mmcfg_list))
+	struct pci_mmcfg_region *cfg;
+
+	pci_mmcfg_running_state = true;
+
+	/* If we are not using MMCONFIG, don't insert the resources. */
+	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
 		return 1;
 
 	/*
@@ -654,7 +678,9 @@ static int __init pci_mmcfg_late_insert_resources(void)
 	 * marked so it won't cause request errors when __request_region is
 	 * called.
 	 */
-	pci_mmcfg_insert_resources();
+	list_for_each_entry(cfg, &pci_mmcfg_list, list)
+		if (!cfg->res.parent)
+			insert_resource(&iomem_resource, &cfg->res);
 
 	return 0;
 }
@@ -665,3 +691,101 @@ static int __init pci_mmcfg_late_insert_resources(void)
  * with other system resources.
  */
 late_initcall(pci_mmcfg_late_insert_resources);
+
+/* Add MMCFG information for host bridges */
+int __devinit pci_mmconfig_insert(struct device *dev,
+				  u16 seg, u8 start, u8 end,
+				  phys_addr_t addr)
+{
+	int rc;
+	struct resource *tmp = NULL;
+	struct pci_mmcfg_region *cfg;
+
+	if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
+		return -ENODEV;
+
+	if (start > end)
+		return -EINVAL;
+
+	mutex_lock(&pci_mmcfg_lock);
+	cfg = pci_mmconfig_lookup(seg, start);
+	if (cfg) {
+		if (cfg->end_bus < end)
+			dev_info(dev, FW_INFO
+				 "MMCONFIG for "
+				 "domain %04x [bus %02x-%02x] "
+				 "only partially covers this bridge\n",
+				  cfg->segment, cfg->start_bus, cfg->end_bus);
+		mutex_unlock(&pci_mmcfg_lock);
+		return -EEXIST;
+	}
+
+	if (!addr) {
+		mutex_unlock(&pci_mmcfg_lock);
+		return -EINVAL;
+	}
+
+	rc = -EBUSY;
+	cfg = pci_mmconfig_alloc(seg, start, end, addr);
+	if (cfg == NULL) {
+		dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
+		rc = -ENOMEM;
+	} else if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
+		dev_warn(dev, FW_BUG "MMCONFIG %pR isn't reserved\n",
+			 &cfg->res);
+	} else {
+		/* Insert resource if it's not in boot stage */
+		if (pci_mmcfg_running_state)
+			tmp = insert_resource_conflict(&iomem_resource,
+						       &cfg->res);
+
+		if (tmp) {
+			dev_warn(dev,
+				 "MMCONFIG %pR conflicts with "
+				 "%s %pR\n",
+				 &cfg->res, tmp->name, tmp);
+		} else if (pci_mmcfg_arch_map(cfg)) {
+			dev_warn(dev, "fail to map MMCONFIG %pR.\n",
+				 &cfg->res);
+		} else {
+			list_add_sorted(cfg);
+			dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
+				 &cfg->res, (unsigned long)addr);
+			cfg = NULL;
+			rc = 0;
+		}
+	}
+
+	if (cfg) {
+		if (cfg->res.parent)
+			release_resource(&cfg->res);
+		kfree(cfg);
+	}
+
+	mutex_unlock(&pci_mmcfg_lock);
+
+	return rc;
+}
+
+/* Delete MMCFG information for host bridges */
+int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
+{
+	struct pci_mmcfg_region *cfg;
+
+	mutex_lock(&pci_mmcfg_lock);
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
+		if (cfg->segment == seg && cfg->start_bus == start &&
+		    cfg->end_bus == end) {
+			list_del_rcu(&cfg->list);
+			synchronize_rcu();
+			pci_mmcfg_arch_unmap(cfg);
+			if (cfg->res.parent)
+				release_resource(&cfg->res);
+			mutex_unlock(&pci_mmcfg_lock);
+			kfree(cfg);
+			return 0;
+		}
+	mutex_unlock(&pci_mmcfg_lock);
+
+	return -ENOENT;
+}
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index 5372e86..db63ac2 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -11,6 +11,7 @@
 
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/rcupdate.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 #include <acpi/acpi.h>
@@ -60,9 +61,12 @@ err:		*value = -1;
 		return -EINVAL;
 	}
 
+	rcu_read_lock();
 	base = get_base_addr(seg, bus, devfn);
-	if (!base)
+	if (!base) {
+		rcu_read_unlock();
 		goto err;
+	}
 
 	raw_spin_lock_irqsave(&pci_config_lock, flags);
 
@@ -80,6 +84,7 @@ err:		*value = -1;
 		break;
 	}
 	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
+	rcu_read_unlock();
 
 	return 0;
 }
@@ -93,9 +98,12 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
 	if ((bus > 255) || (devfn > 255) || (reg > 4095))
 		return -EINVAL;
 
+	rcu_read_lock();
 	base = get_base_addr(seg, bus, devfn);
-	if (!base)
+	if (!base) {
+		rcu_read_unlock();
 		return -EINVAL;
+	}
 
 	raw_spin_lock_irqsave(&pci_config_lock, flags);
 
@@ -113,11 +121,12 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
 		break;
 	}
 	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
+	rcu_read_unlock();
 
 	return 0;
 }
 
-static const struct pci_raw_ops pci_mmcfg = {
+const struct pci_raw_ops pci_mmcfg = {
 	.read =		pci_mmcfg_read,
 	.write =	pci_mmcfg_write,
 };
@@ -132,3 +141,18 @@ int __init pci_mmcfg_arch_init(void)
 void __init pci_mmcfg_arch_free(void)
 {
 }
+
+int __devinit pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
+{
+	return 0;
+}
+
+void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
+{
+	unsigned long flags;
+
+	/* Invalidate the cached mmcfg map entry. */
+	raw_spin_lock_irqsave(&pci_config_lock, flags);
+	mmcfg_last_accessed_device = 0;
+	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
+}
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index 915a493..d4ebd07 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/bitmap.h>
+#include <linux/rcupdate.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
@@ -34,9 +35,12 @@ err:		*value = -1;
 		return -EINVAL;
 	}
 
+	rcu_read_lock();
 	addr = pci_dev_base(seg, bus, devfn);
-	if (!addr)
+	if (!addr) {
+		rcu_read_unlock();
 		goto err;
+	}
 
 	switch (len) {
 	case 1:
@@ -49,6 +53,7 @@ err:		*value = -1;
 		*value = mmio_config_readl(addr + reg);
 		break;
 	}
+	rcu_read_unlock();
 
 	return 0;
 }
@@ -62,9 +67,12 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
 	if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
 		return -EINVAL;
 
+	rcu_read_lock();
 	addr = pci_dev_base(seg, bus, devfn);
-	if (!addr)
+	if (!addr) {
+		rcu_read_unlock();
 		return -EINVAL;
+	}
 
 	switch (len) {
 	case 1:
@@ -77,16 +85,17 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
 		mmio_config_writel(addr + reg, value);
 		break;
 	}
+	rcu_read_unlock();
 
 	return 0;
 }
 
-static const struct pci_raw_ops pci_mmcfg = {
+const struct pci_raw_ops pci_mmcfg = {
 	.read =		pci_mmcfg_read,
 	.write =	pci_mmcfg_write,
 };
 
-static void __iomem * __init mcfg_ioremap(struct pci_mmcfg_region *cfg)
+static void __iomem * __devinit mcfg_ioremap(struct pci_mmcfg_region *cfg)
 {
 	void __iomem *addr;
 	u64 start, size;
@@ -105,16 +114,14 @@ int __init pci_mmcfg_arch_init(void)
 {
 	struct pci_mmcfg_region *cfg;
 
-	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
-		cfg->virt = mcfg_ioremap(cfg);
-		if (!cfg->virt) {
-			printk(KERN_ERR PREFIX "can't map MMCONFIG at %pR\n",
-			       &cfg->res);
+	list_for_each_entry(cfg, &pci_mmcfg_list, list)
+		if (pci_mmcfg_arch_map(cfg)) {
 			pci_mmcfg_arch_free();
 			return 0;
 		}
-	}
+
 	raw_pci_ext_ops = &pci_mmcfg;
+
 	return 1;
 }
 
@@ -122,10 +129,25 @@ void __init pci_mmcfg_arch_free(void)
 {
 	struct pci_mmcfg_region *cfg;
 
-	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
-		if (cfg->virt) {
-			iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
-			cfg->virt = NULL;
-		}
+	list_for_each_entry(cfg, &pci_mmcfg_list, list)
+		pci_mmcfg_arch_unmap(cfg);
+}
+
+int __devinit pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
+{
+	cfg->virt = mcfg_ioremap(cfg);
+	if (!cfg->virt) {
+		pr_err(PREFIX "can't map MMCONFIG at %pR\n", &cfg->res);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
+{
+	if (cfg && cfg->virt) {
+		iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
+		cfg->virt = NULL;
 	}
 }
diff --git a/arch/x86/pci/mrst.c b/arch/x86/pci/mrst.c
index 140942f..e14a2ff 100644
--- a/arch/x86/pci/mrst.c
+++ b/arch/x86/pci/mrst.c
@@ -264,7 +264,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup);
 
 static void __devinit mrst_power_off_unused_dev(struct pci_dev *dev)
 {
-	pci_set_power_state(dev, PCI_D3cold);
+	pci_set_power_state(dev, PCI_D3hot);
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0801, mrst_power_off_unused_dev);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0809, mrst_power_off_unused_dev);
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 92660eda..2dc29f5 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -234,22 +234,7 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
 	return status;
 }
 
-static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
-					     efi_time_cap_t *tc)
-{
-	unsigned long flags;
-	efi_status_t status;
-
-	spin_lock_irqsave(&rtc_lock, flags);
-	efi_call_phys_prelog();
-	status = efi_call_phys2(efi_phys.get_time, virt_to_phys(tm),
-				virt_to_phys(tc));
-	efi_call_phys_epilog();
-	spin_unlock_irqrestore(&rtc_lock, flags);
-	return status;
-}
-
-int efi_set_rtc_mmss(unsigned long nowtime)
+static int efi_set_rtc_mmss(unsigned long nowtime)
 {
 	int real_seconds, real_minutes;
 	efi_status_t 	status;
@@ -278,7 +263,7 @@ int efi_set_rtc_mmss(unsigned long nowtime)
 	return 0;
 }
 
-unsigned long efi_get_time(void)
+static unsigned long efi_get_time(void)
 {
 	efi_status_t status;
 	efi_time_t eft;
@@ -621,18 +606,13 @@ static int __init efi_runtime_init(void)
 	}
 	/*
 	 * We will only need *early* access to the following
-	 * two EFI runtime services before set_virtual_address_map
+	 * EFI runtime service before set_virtual_address_map
 	 * is invoked.
 	 */
-	efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
 	efi_phys.set_virtual_address_map =
 		(efi_set_virtual_address_map_t *)
 		runtime->set_virtual_address_map;
-	/*
-	 * Make efi_get_time can be called before entering
-	 * virtual mode.
-	 */
-	efi.get_time = phys_efi_get_time;
+
 	early_iounmap(runtime, sizeof(efi_runtime_services_t));
 
 	return 0;
@@ -720,12 +700,10 @@ void __init efi_init(void)
 		efi_enabled = 0;
 		return;
 	}
-#ifdef CONFIG_X86_32
 	if (efi_native) {
 		x86_platform.get_wallclock = efi_get_time;
 		x86_platform.set_wallclock = efi_set_rtc_mmss;
 	}
-#endif
 
 #if EFI_DEBUG
 	print_efi_memmap();
diff --git a/arch/x86/platform/iris/iris.c b/arch/x86/platform/iris/iris.c
index 5917eb5..e6cb80f 100644
--- a/arch/x86/platform/iris/iris.c
+++ b/arch/x86/platform/iris/iris.c
@@ -23,6 +23,7 @@
 
 #include <linux/moduleparam.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
@@ -62,29 +63,75 @@ static void iris_power_off(void)
  * by reading its input port and seeing whether the read value is
  * meaningful.
  */
-static int iris_init(void)
+static int iris_probe(struct platform_device *pdev)
 {
-	unsigned char status;
-	if (force != 1) {
-		printk(KERN_ERR "The force parameter has not been set to 1 so the Iris poweroff handler will not be installed.\n");
-		return -ENODEV;
-	}
-	status = inb(IRIS_GIO_INPUT);
+	unsigned char status = inb(IRIS_GIO_INPUT);
 	if (status == IRIS_GIO_NODEV) {
-		printk(KERN_ERR "This machine does not seem to be an Iris. Power_off handler not installed.\n");
+		printk(KERN_ERR "This machine does not seem to be an Iris. "
+			"Power off handler not installed.\n");
 		return -ENODEV;
 	}
 	old_pm_power_off = pm_power_off;
 	pm_power_off = &iris_power_off;
 	printk(KERN_INFO "Iris power_off handler installed.\n");
-
 	return 0;
 }
 
-static void iris_exit(void)
+static int iris_remove(struct platform_device *pdev)
 {
 	pm_power_off = old_pm_power_off;
 	printk(KERN_INFO "Iris power_off handler uninstalled.\n");
+	return 0;
+}
+
+static struct platform_driver iris_driver = {
+	.driver		= {
+		.name   = "iris",
+		.owner  = THIS_MODULE,
+	},
+	.probe          = iris_probe,
+	.remove         = iris_remove,
+};
+
+static struct resource iris_resources[] = {
+	{
+		.start  = IRIS_GIO_BASE,
+		.end    = IRIS_GIO_OUTPUT,
+		.flags  = IORESOURCE_IO,
+		.name   = "address"
+	}
+};
+
+static struct platform_device *iris_device;
+
+static int iris_init(void)
+{
+	int ret;
+	if (force != 1) {
+		printk(KERN_ERR "The force parameter has not been set to 1."
+			" The Iris poweroff handler will not be installed.\n");
+		return -ENODEV;
+	}
+	ret = platform_driver_register(&iris_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Failed to register iris platform driver: %d\n",
+			ret);
+		return ret;
+	}
+	iris_device = platform_device_register_simple("iris", (-1),
+				iris_resources, ARRAY_SIZE(iris_resources));
+	if (IS_ERR(iris_device)) {
+		printk(KERN_ERR "Failed to register iris platform device\n");
+		platform_driver_unregister(&iris_driver);
+		return PTR_ERR(iris_device);
+	}
+	return 0;
+}
+
+static void iris_exit(void)
+{
+	platform_device_unregister(iris_device);
+	platform_driver_unregister(&iris_driver);
 }
 
 module_init(iris_init);
diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c
index 59880af..71b5d5a 100644
--- a/arch/x86/platform/uv/tlb_uv.c
+++ b/arch/x86/platform/uv/tlb_uv.c
@@ -1,7 +1,7 @@
 /*
  *	SGI UltraViolet TLB flush routines.
  *
- *	(c) 2008-2011 Cliff Wickman <cpw@sgi.com>, SGI.
+ *	(c) 2008-2012 Cliff Wickman <cpw@sgi.com>, SGI.
  *
  *	This code is released under the GNU General Public License version 2 or
  *	later.
@@ -38,8 +38,7 @@ static int timeout_base_ns[] = {
 
 static int timeout_us;
 static int nobau;
-static int baudisabled;
-static spinlock_t disable_lock;
+static int nobau_perm;
 static cycles_t congested_cycles;
 
 /* tunables: */
@@ -47,12 +46,13 @@ static int max_concurr		= MAX_BAU_CONCURRENT;
 static int max_concurr_const	= MAX_BAU_CONCURRENT;
 static int plugged_delay	= PLUGGED_DELAY;
 static int plugsb4reset		= PLUGSB4RESET;
+static int giveup_limit		= GIVEUP_LIMIT;
 static int timeoutsb4reset	= TIMEOUTSB4RESET;
 static int ipi_reset_limit	= IPI_RESET_LIMIT;
 static int complete_threshold	= COMPLETE_THRESHOLD;
 static int congested_respns_us	= CONGESTED_RESPONSE_US;
 static int congested_reps	= CONGESTED_REPS;
-static int congested_period	= CONGESTED_PERIOD;
+static int disabled_period	= DISABLED_PERIOD;
 
 static struct tunables tunables[] = {
 	{&max_concurr, MAX_BAU_CONCURRENT}, /* must be [0] */
@@ -63,7 +63,8 @@ static struct tunables tunables[] = {
 	{&complete_threshold, COMPLETE_THRESHOLD},
 	{&congested_respns_us, CONGESTED_RESPONSE_US},
 	{&congested_reps, CONGESTED_REPS},
-	{&congested_period, CONGESTED_PERIOD}
+	{&disabled_period, DISABLED_PERIOD},
+	{&giveup_limit, GIVEUP_LIMIT}
 };
 
 static struct dentry *tunables_dir;
@@ -120,6 +121,40 @@ static DEFINE_PER_CPU(struct ptc_stats, ptcstats);
 static DEFINE_PER_CPU(struct bau_control, bau_control);
 static DEFINE_PER_CPU(cpumask_var_t, uv_flush_tlb_mask);
 
+static void
+set_bau_on(void)
+{
+	int cpu;
+	struct bau_control *bcp;
+
+	if (nobau_perm) {
+		pr_info("BAU not initialized; cannot be turned on\n");
+		return;
+	}
+	nobau = 0;
+	for_each_present_cpu(cpu) {
+		bcp = &per_cpu(bau_control, cpu);
+		bcp->nobau = 0;
+	}
+	pr_info("BAU turned on\n");
+	return;
+}
+
+static void
+set_bau_off(void)
+{
+	int cpu;
+	struct bau_control *bcp;
+
+	nobau = 1;
+	for_each_present_cpu(cpu) {
+		bcp = &per_cpu(bau_control, cpu);
+		bcp->nobau = 1;
+	}
+	pr_info("BAU turned off\n");
+	return;
+}
+
 /*
  * Determine the first node on a uvhub. 'Nodes' are used for kernel
  * memory allocation.
@@ -278,7 +313,7 @@ static void bau_process_message(struct msg_desc *mdp, struct bau_control *bcp,
 		 * Both sockets dump their completed count total into
 		 * the message's count.
 		 */
-		smaster->socket_acknowledge_count[mdp->msg_slot] = 0;
+		*sp = 0;
 		asp = (struct atomic_short *)&msg->acknowledge_count;
 		msg_ack_count = atom_asr(socket_ack_count, asp);
 
@@ -491,16 +526,15 @@ static int uv1_wait_completion(struct bau_desc *bau_desc,
 }
 
 /*
- * UV2 has an extra bit of status in the ACTIVATION_STATUS_2 register.
+ * UV2 could have an extra bit of status in the ACTIVATION_STATUS_2 register.
+ * But not currently used.
  */
 static unsigned long uv2_read_status(unsigned long offset, int rshft, int desc)
 {
 	unsigned long descriptor_status;
-	unsigned long descriptor_status2;
 
-	descriptor_status = ((read_lmmr(offset) >> rshft) & UV_ACT_STATUS_MASK);
-	descriptor_status2 = (read_mmr_uv2_status() >> desc) & 0x1UL;
-	descriptor_status = (descriptor_status << 1) | descriptor_status2;
+	descriptor_status =
+		((read_lmmr(offset) >> rshft) & UV_ACT_STATUS_MASK) << 1;
 	return descriptor_status;
 }
 
@@ -531,87 +565,11 @@ int normal_busy(struct bau_control *bcp)
  */
 int handle_uv2_busy(struct bau_control *bcp)
 {
-	int busy_one = bcp->using_desc;
-	int normal = bcp->uvhub_cpu;
-	int selected = -1;
-	int i;
-	unsigned long descriptor_status;
-	unsigned long status;
-	int mmr_offset;
-	struct bau_desc *bau_desc_old;
-	struct bau_desc *bau_desc_new;
-	struct bau_control *hmaster = bcp->uvhub_master;
 	struct ptc_stats *stat = bcp->statp;
-	cycles_t ttm;
 
 	stat->s_uv2_wars++;
-	spin_lock(&hmaster->uvhub_lock);
-	/* try for the original first */
-	if (busy_one != normal) {
-		if (!normal_busy(bcp))
-			selected = normal;
-	}
-	if (selected < 0) {
-		/* can't use the normal, select an alternate */
-		mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
-		descriptor_status = read_lmmr(mmr_offset);
-
-		/* scan available descriptors 32-63 */
-		for (i = 0; i < UV_CPUS_PER_AS; i++) {
-			if ((hmaster->inuse_map & (1 << i)) == 0) {
-				status = ((descriptor_status >>
-						(i * UV_ACT_STATUS_SIZE)) &
-						UV_ACT_STATUS_MASK) << 1;
-				if (status != UV2H_DESC_BUSY) {
-					selected = i + UV_CPUS_PER_AS;
-					break;
-				}
-			}
-		}
-	}
-
-	if (busy_one != normal)
-		/* mark the busy alternate as not in-use */
-		hmaster->inuse_map &= ~(1 << (busy_one - UV_CPUS_PER_AS));
-
-	if (selected >= 0) {
-		/* switch to the selected descriptor */
-		if (selected != normal) {
-			/* set the selected alternate as in-use */
-			hmaster->inuse_map |=
-					(1 << (selected - UV_CPUS_PER_AS));
-			if (selected > stat->s_uv2_wars_hw)
-				stat->s_uv2_wars_hw = selected;
-		}
-		bau_desc_old = bcp->descriptor_base;
-		bau_desc_old += (ITEMS_PER_DESC * busy_one);
-		bcp->using_desc = selected;
-		bau_desc_new = bcp->descriptor_base;
-		bau_desc_new += (ITEMS_PER_DESC * selected);
-		*bau_desc_new = *bau_desc_old;
-	} else {
-		/*
-		 * All are busy. Wait for the normal one for this cpu to
-		 * free up.
-		 */
-		stat->s_uv2_war_waits++;
-		spin_unlock(&hmaster->uvhub_lock);
-		ttm = get_cycles();
-		do {
-			cpu_relax();
-		} while (normal_busy(bcp));
-		spin_lock(&hmaster->uvhub_lock);
-		/* switch to the original descriptor */
-		bcp->using_desc = normal;
-		bau_desc_old = bcp->descriptor_base;
-		bau_desc_old += (ITEMS_PER_DESC * bcp->using_desc);
-		bcp->using_desc = (ITEMS_PER_DESC * normal);
-		bau_desc_new = bcp->descriptor_base;
-		bau_desc_new += (ITEMS_PER_DESC * normal);
-		*bau_desc_new = *bau_desc_old; /* copy the entire descriptor */
-	}
-	spin_unlock(&hmaster->uvhub_lock);
-	return FLUSH_RETRY_BUSYBUG;
+	bcp->busy = 1;
+	return FLUSH_GIVEUP;
 }
 
 static int uv2_wait_completion(struct bau_desc *bau_desc,
@@ -620,7 +578,7 @@ static int uv2_wait_completion(struct bau_desc *bau_desc,
 {
 	unsigned long descriptor_stat;
 	cycles_t ttm;
-	int desc = bcp->using_desc;
+	int desc = bcp->uvhub_cpu;
 	long busy_reps = 0;
 	struct ptc_stats *stat = bcp->statp;
 
@@ -628,24 +586,38 @@ static int uv2_wait_completion(struct bau_desc *bau_desc,
 
 	/* spin on the status MMR, waiting for it to go idle */
 	while (descriptor_stat != UV2H_DESC_IDLE) {
-		/*
-		 * Our software ack messages may be blocked because
-		 * there are no swack resources available.  As long
-		 * as none of them has timed out hardware will NACK
-		 * our message and its state will stay IDLE.
-		 */
-		if ((descriptor_stat == UV2H_DESC_SOURCE_TIMEOUT) ||
-		    (descriptor_stat == UV2H_DESC_DEST_PUT_ERR)) {
+		if ((descriptor_stat == UV2H_DESC_SOURCE_TIMEOUT)) {
+			/*
+			 * A h/w bug on the destination side may
+			 * have prevented the message being marked
+			 * pending, thus it doesn't get replied to
+			 * and gets continually nacked until it times
+			 * out with a SOURCE_TIMEOUT.
+			 */
 			stat->s_stimeout++;
 			return FLUSH_GIVEUP;
-		} else if (descriptor_stat == UV2H_DESC_DEST_STRONG_NACK) {
-			stat->s_strongnacks++;
-			bcp->conseccompletes = 0;
-			return FLUSH_GIVEUP;
 		} else if (descriptor_stat == UV2H_DESC_DEST_TIMEOUT) {
+			ttm = get_cycles();
+
+			/*
+			 * Our retries may be blocked by all destination
+			 * swack resources being consumed, and a timeout
+			 * pending.  In that case hardware returns the
+			 * ERROR that looks like a destination timeout.
+			 * Without using the extended status we have to
+			 * deduce from the short time that this was a
+			 * strong nack.
+			 */
+			if (cycles_2_us(ttm - bcp->send_message) < timeout_us) {
+				bcp->conseccompletes = 0;
+				stat->s_plugged++;
+				/* FLUSH_RETRY_PLUGGED causes hang on boot */
+				return FLUSH_GIVEUP;
+			}
 			stat->s_dtimeout++;
 			bcp->conseccompletes = 0;
-			return FLUSH_RETRY_TIMEOUT;
+			/* FLUSH_RETRY_TIMEOUT causes hang on boot */
+			return FLUSH_GIVEUP;
 		} else {
 			busy_reps++;
 			if (busy_reps > 1000000) {
@@ -653,9 +625,8 @@ static int uv2_wait_completion(struct bau_desc *bau_desc,
 				busy_reps = 0;
 				ttm = get_cycles();
 				if ((ttm - bcp->send_message) >
-					(bcp->clocks_per_100_usec)) {
+						bcp->timeout_interval)
 					return handle_uv2_busy(bcp);
-				}
 			}
 			/*
 			 * descriptor_stat is still BUSY
@@ -679,7 +650,7 @@ static int wait_completion(struct bau_desc *bau_desc,
 {
 	int right_shift;
 	unsigned long mmr_offset;
-	int desc = bcp->using_desc;
+	int desc = bcp->uvhub_cpu;
 
 	if (desc < UV_CPUS_PER_AS) {
 		mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
@@ -758,33 +729,31 @@ static void destination_timeout(struct bau_desc *bau_desc,
 }
 
 /*
- * Completions are taking a very long time due to a congested numalink
- * network.
+ * Stop all cpus on a uvhub from using the BAU for a period of time.
+ * This is reversed by check_enable.
  */
-static void disable_for_congestion(struct bau_control *bcp,
-					struct ptc_stats *stat)
+static void disable_for_period(struct bau_control *bcp, struct ptc_stats *stat)
 {
-	/* let only one cpu do this disabling */
-	spin_lock(&disable_lock);
-
-	if (!baudisabled && bcp->period_requests &&
-	    ((bcp->period_time / bcp->period_requests) > congested_cycles)) {
-		int tcpu;
-		struct bau_control *tbcp;
-		/* it becomes this cpu's job to turn on the use of the
-		   BAU again */
-		baudisabled = 1;
-		bcp->set_bau_off = 1;
-		bcp->set_bau_on_time = get_cycles();
-		bcp->set_bau_on_time += sec_2_cycles(bcp->cong_period);
+	int tcpu;
+	struct bau_control *tbcp;
+	struct bau_control *hmaster;
+	cycles_t tm1;
+
+	hmaster = bcp->uvhub_master;
+	spin_lock(&hmaster->disable_lock);
+	if (!bcp->baudisabled) {
 		stat->s_bau_disabled++;
+		tm1 = get_cycles();
 		for_each_present_cpu(tcpu) {
 			tbcp = &per_cpu(bau_control, tcpu);
-			tbcp->baudisabled = 1;
+			if (tbcp->uvhub_master == hmaster) {
+				tbcp->baudisabled = 1;
+				tbcp->set_bau_on_time =
+					tm1 + bcp->disabled_period;
+			}
 		}
 	}
-
-	spin_unlock(&disable_lock);
+	spin_unlock(&hmaster->disable_lock);
 }
 
 static void count_max_concurr(int stat, struct bau_control *bcp,
@@ -815,16 +784,30 @@ static void record_send_stats(cycles_t time1, cycles_t time2,
 			bcp->period_requests++;
 			bcp->period_time += elapsed;
 			if ((elapsed > congested_cycles) &&
-			    (bcp->period_requests > bcp->cong_reps))
-				disable_for_congestion(bcp, stat);
+			    (bcp->period_requests > bcp->cong_reps) &&
+			    ((bcp->period_time / bcp->period_requests) >
+							congested_cycles)) {
+				stat->s_congested++;
+				disable_for_period(bcp, stat);
+			}
 		}
 	} else
 		stat->s_requestor--;
 
 	if (completion_status == FLUSH_COMPLETE && try > 1)
 		stat->s_retriesok++;
-	else if (completion_status == FLUSH_GIVEUP)
+	else if (completion_status == FLUSH_GIVEUP) {
 		stat->s_giveup++;
+		if (get_cycles() > bcp->period_end)
+			bcp->period_giveups = 0;
+		bcp->period_giveups++;
+		if (bcp->period_giveups == 1)
+			bcp->period_end = get_cycles() + bcp->disabled_period;
+		if (bcp->period_giveups > bcp->giveup_limit) {
+			disable_for_period(bcp, stat);
+			stat->s_giveuplimit++;
+		}
+	}
 }
 
 /*
@@ -868,7 +851,8 @@ static void handle_cmplt(int completion_status, struct bau_desc *bau_desc,
  * Returns 1 if it gives up entirely and the original cpu mask is to be
  * returned to the kernel.
  */
-int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp)
+int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp,
+	struct bau_desc *bau_desc)
 {
 	int seq_number = 0;
 	int completion_stat = 0;
@@ -881,24 +865,23 @@ int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp)
 	struct bau_control *hmaster = bcp->uvhub_master;
 	struct uv1_bau_msg_header *uv1_hdr = NULL;
 	struct uv2_bau_msg_header *uv2_hdr = NULL;
-	struct bau_desc *bau_desc;
 
-	if (bcp->uvhub_version == 1)
+	if (bcp->uvhub_version == 1) {
+		uv1 = 1;
 		uv1_throttle(hmaster, stat);
+	}
 
 	while (hmaster->uvhub_quiesce)
 		cpu_relax();
 
 	time1 = get_cycles();
+	if (uv1)
+		uv1_hdr = &bau_desc->header.uv1_hdr;
+	else
+		uv2_hdr = &bau_desc->header.uv2_hdr;
+
 	do {
-		bau_desc = bcp->descriptor_base;
-		bau_desc += (ITEMS_PER_DESC * bcp->using_desc);
-		if (bcp->uvhub_version == 1) {
-			uv1 = 1;
-			uv1_hdr = &bau_desc->header.uv1_hdr;
-		} else
-			uv2_hdr = &bau_desc->header.uv2_hdr;
-		if ((try == 0) || (completion_stat == FLUSH_RETRY_BUSYBUG)) {
+		if (try == 0) {
 			if (uv1)
 				uv1_hdr->msg_type = MSG_REGULAR;
 			else
@@ -916,25 +899,24 @@ int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp)
 			uv1_hdr->sequence = seq_number;
 		else
 			uv2_hdr->sequence = seq_number;
-		index = (1UL << AS_PUSH_SHIFT) | bcp->using_desc;
+		index = (1UL << AS_PUSH_SHIFT) | bcp->uvhub_cpu;
 		bcp->send_message = get_cycles();
 
 		write_mmr_activation(index);
 
 		try++;
 		completion_stat = wait_completion(bau_desc, bcp, try);
-		/* UV2: wait_completion() may change the bcp->using_desc */
 
 		handle_cmplt(completion_stat, bau_desc, bcp, hmaster, stat);
 
 		if (bcp->ipi_attempts >= bcp->ipi_reset_limit) {
 			bcp->ipi_attempts = 0;
+			stat->s_overipilimit++;
 			completion_stat = FLUSH_GIVEUP;
 			break;
 		}
 		cpu_relax();
 	} while ((completion_stat == FLUSH_RETRY_PLUGGED) ||
-		 (completion_stat == FLUSH_RETRY_BUSYBUG) ||
 		 (completion_stat == FLUSH_RETRY_TIMEOUT));
 
 	time2 = get_cycles();
@@ -955,28 +937,33 @@ int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp)
 }
 
 /*
- * The BAU is disabled. When the disabled time period has expired, the cpu
- * that disabled it must re-enable it.
- * Return 0 if it is re-enabled for all cpus.
+ * The BAU is disabled for this uvhub. When the disabled time period has
+ * expired re-enable it.
+ * Return 0 if it is re-enabled for all cpus on this uvhub.
  */
 static int check_enable(struct bau_control *bcp, struct ptc_stats *stat)
 {
 	int tcpu;
 	struct bau_control *tbcp;
+	struct bau_control *hmaster;
 
-	if (bcp->set_bau_off) {
-		if (get_cycles() >= bcp->set_bau_on_time) {
-			stat->s_bau_reenabled++;
-			baudisabled = 0;
-			for_each_present_cpu(tcpu) {
-				tbcp = &per_cpu(bau_control, tcpu);
+	hmaster = bcp->uvhub_master;
+	spin_lock(&hmaster->disable_lock);
+	if (bcp->baudisabled && (get_cycles() >= bcp->set_bau_on_time)) {
+		stat->s_bau_reenabled++;
+		for_each_present_cpu(tcpu) {
+			tbcp = &per_cpu(bau_control, tcpu);
+			if (tbcp->uvhub_master == hmaster) {
 				tbcp->baudisabled = 0;
 				tbcp->period_requests = 0;
 				tbcp->period_time = 0;
+				tbcp->period_giveups = 0;
 			}
-			return 0;
 		}
+		spin_unlock(&hmaster->disable_lock);
+		return 0;
 	}
+	spin_unlock(&hmaster->disable_lock);
 	return -1;
 }
 
@@ -1078,18 +1065,32 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
 	struct cpumask *flush_mask;
 	struct ptc_stats *stat;
 	struct bau_control *bcp;
-
-	/* kernel was booted 'nobau' */
-	if (nobau)
-		return cpumask;
+	unsigned long descriptor_status;
+	unsigned long status;
 
 	bcp = &per_cpu(bau_control, cpu);
 	stat = bcp->statp;
+	stat->s_enters++;
+
+	if (bcp->nobau)
+		return cpumask;
+
+	if (bcp->busy) {
+		descriptor_status =
+			read_lmmr(UVH_LB_BAU_SB_ACTIVATION_STATUS_0);
+		status = ((descriptor_status >> (bcp->uvhub_cpu *
+			UV_ACT_STATUS_SIZE)) & UV_ACT_STATUS_MASK) << 1;
+		if (status == UV2H_DESC_BUSY)
+			return cpumask;
+		bcp->busy = 0;
+	}
 
 	/* bau was disabled due to slow response */
 	if (bcp->baudisabled) {
-		if (check_enable(bcp, stat))
+		if (check_enable(bcp, stat)) {
+			stat->s_ipifordisabled++;
 			return cpumask;
+		}
 	}
 
 	/*
@@ -1105,7 +1106,7 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
 		stat->s_ntargself++;
 
 	bau_desc = bcp->descriptor_base;
-	bau_desc += (ITEMS_PER_DESC * bcp->using_desc);
+	bau_desc += (ITEMS_PER_DESC * bcp->uvhub_cpu);
 	bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
 	if (set_distrib_bits(flush_mask, bcp, bau_desc, &locals, &remotes))
 		return NULL;
@@ -1118,25 +1119,27 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
 	 * uv_flush_send_and_wait returns 0 if all cpu's were messaged,
 	 * or 1 if it gave up and the original cpumask should be returned.
 	 */
-	if (!uv_flush_send_and_wait(flush_mask, bcp))
+	if (!uv_flush_send_and_wait(flush_mask, bcp, bau_desc))
 		return NULL;
 	else
 		return cpumask;
 }
 
 /*
- * Search the message queue for any 'other' message with the same software
- * acknowledge resource bit vector.
+ * Search the message queue for any 'other' unprocessed message with the
+ * same software acknowledge resource bit vector as the 'msg' message.
  */
 struct bau_pq_entry *find_another_by_swack(struct bau_pq_entry *msg,
-			struct bau_control *bcp, unsigned char swack_vec)
+					   struct bau_control *bcp)
 {
 	struct bau_pq_entry *msg_next = msg + 1;
+	unsigned char swack_vec = msg->swack_vec;
 
 	if (msg_next > bcp->queue_last)
 		msg_next = bcp->queue_first;
-	while ((msg_next->swack_vec != 0) && (msg_next != msg)) {
-		if (msg_next->swack_vec == swack_vec)
+	while (msg_next != msg) {
+		if ((msg_next->canceled == 0) && (msg_next->replied_to == 0) &&
+				(msg_next->swack_vec == swack_vec))
 			return msg_next;
 		msg_next++;
 		if (msg_next > bcp->queue_last)
@@ -1165,32 +1168,30 @@ void process_uv2_message(struct msg_desc *mdp, struct bau_control *bcp)
 		 * This message was assigned a swack resource, but no
 		 * reserved acknowlegment is pending.
 		 * The bug has prevented this message from setting the MMR.
-		 * And no other message has used the same sw_ack resource.
-		 * Do the requested shootdown but do not reply to the msg.
-		 * (the 0 means make no acknowledge)
 		 */
-		bau_process_message(mdp, bcp, 0);
-		return;
-	}
-
-	/*
-	 * Some message has set the MMR 'pending' bit; it might have been
-	 * another message.  Look for that message.
-	 */
-	other_msg = find_another_by_swack(msg, bcp, msg->swack_vec);
-	if (other_msg) {
-		/* There is another.  Do not ack the current one. */
-		bau_process_message(mdp, bcp, 0);
 		/*
-		 * Let the natural processing of that message acknowledge
-		 * it. Don't get the processing of sw_ack's out of order.
+		 * Some message has set the MMR 'pending' bit; it might have
+		 * been another message.  Look for that message.
 		 */
-		return;
+		other_msg = find_another_by_swack(msg, bcp);
+		if (other_msg) {
+			/*
+			 * There is another. Process this one but do not
+			 * ack it.
+			 */
+			bau_process_message(mdp, bcp, 0);
+			/*
+			 * Let the natural processing of that other message
+			 * acknowledge it. Don't get the processing of sw_ack's
+			 * out of order.
+			 */
+			return;
+		}
 	}
 
 	/*
-	 * There is no other message using this sw_ack, so it is safe to
-	 * acknowledge it.
+	 * Either the MMR shows this one pending a reply or there is no
+	 * other message using this sw_ack, so it is safe to acknowledge it.
 	 */
 	bau_process_message(mdp, bcp, 1);
 
@@ -1295,7 +1296,8 @@ static void __init enable_timeouts(void)
 		 */
 		mmr_image |= (1L << SOFTACK_MSHIFT);
 		if (is_uv2_hub()) {
-			mmr_image |= (1L << UV2_EXT_SHFT);
+			/* hw bug workaround; do not use extended status */
+			mmr_image &= ~(1L << UV2_EXT_SHFT);
 		}
 		write_mmr_misc_control(pnode, mmr_image);
 	}
@@ -1338,29 +1340,34 @@ static inline unsigned long long usec_2_cycles(unsigned long microsec)
 static int ptc_seq_show(struct seq_file *file, void *data)
 {
 	struct ptc_stats *stat;
+	struct bau_control *bcp;
 	int cpu;
 
 	cpu = *(loff_t *)data;
 	if (!cpu) {
 		seq_printf(file,
-			"# cpu sent stime self locals remotes ncpus localhub ");
+		 "# cpu bauoff sent stime self locals remotes ncpus localhub ");
 		seq_printf(file,
 			"remotehub numuvhubs numuvhubs16 numuvhubs8 ");
 		seq_printf(file,
-		    "numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries rok ");
+			"numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries ");
+		seq_printf(file,
+			"rok resetp resett giveup sto bz throt disable ");
 		seq_printf(file,
-			"resetp resett giveup sto bz throt swack recv rtime ");
+			"enable wars warshw warwaits enters ipidis plugged ");
 		seq_printf(file,
-			"all one mult none retry canc nocan reset rcan ");
+			"ipiover glim cong swack recv rtime all one mult ");
 		seq_printf(file,
-			"disable enable wars warshw warwaits\n");
+			"none retry canc nocan reset rcan\n");
 	}
 	if (cpu < num_possible_cpus() && cpu_online(cpu)) {
-		stat = &per_cpu(ptcstats, cpu);
+		bcp = &per_cpu(bau_control, cpu);
+		stat = bcp->statp;
 		/* source side statistics */
 		seq_printf(file,
-			"cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
-			   cpu, stat->s_requestor, cycles_2_us(stat->s_time),
+			"cpu %d %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
+			   cpu, bcp->nobau, stat->s_requestor,
+			   cycles_2_us(stat->s_time),
 			   stat->s_ntargself, stat->s_ntarglocals,
 			   stat->s_ntargremotes, stat->s_ntargcpu,
 			   stat->s_ntarglocaluvhub, stat->s_ntargremoteuvhub,
@@ -1374,20 +1381,23 @@ static int ptc_seq_show(struct seq_file *file, void *data)
 			   stat->s_resets_plug, stat->s_resets_timeout,
 			   stat->s_giveup, stat->s_stimeout,
 			   stat->s_busy, stat->s_throttles);
+		seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
+			   stat->s_bau_disabled, stat->s_bau_reenabled,
+			   stat->s_uv2_wars, stat->s_uv2_wars_hw,
+			   stat->s_uv2_war_waits, stat->s_enters,
+			   stat->s_ipifordisabled, stat->s_plugged,
+			   stat->s_overipilimit, stat->s_giveuplimit,
+			   stat->s_congested);
 
 		/* destination side statistics */
 		seq_printf(file,
-			   "%lx %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
+			"%lx %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n",
 			   read_gmmr_sw_ack(uv_cpu_to_pnode(cpu)),
 			   stat->d_requestee, cycles_2_us(stat->d_time),
 			   stat->d_alltlb, stat->d_onetlb, stat->d_multmsg,
 			   stat->d_nomsg, stat->d_retries, stat->d_canceled,
 			   stat->d_nocanceled, stat->d_resets,
 			   stat->d_rcanceled);
-		seq_printf(file, "%ld %ld %ld %ld %ld\n",
-			stat->s_bau_disabled, stat->s_bau_reenabled,
-			stat->s_uv2_wars, stat->s_uv2_wars_hw,
-			stat->s_uv2_war_waits);
 	}
 	return 0;
 }
@@ -1401,13 +1411,14 @@ static ssize_t tunables_read(struct file *file, char __user *userbuf,
 	char *buf;
 	int ret;
 
-	buf = kasprintf(GFP_KERNEL, "%s %s %s\n%d %d %d %d %d %d %d %d %d\n",
-		"max_concur plugged_delay plugsb4reset",
-		"timeoutsb4reset ipi_reset_limit complete_threshold",
-		"congested_response_us congested_reps congested_period",
+	buf = kasprintf(GFP_KERNEL, "%s %s %s\n%d %d %d %d %d %d %d %d %d %d\n",
+		"max_concur plugged_delay plugsb4reset timeoutsb4reset",
+		"ipi_reset_limit complete_threshold congested_response_us",
+		"congested_reps disabled_period giveup_limit",
 		max_concurr, plugged_delay, plugsb4reset,
 		timeoutsb4reset, ipi_reset_limit, complete_threshold,
-		congested_respns_us, congested_reps, congested_period);
+		congested_respns_us, congested_reps, disabled_period,
+		giveup_limit);
 
 	if (!buf)
 		return -ENOMEM;
@@ -1438,6 +1449,14 @@ static ssize_t ptc_proc_write(struct file *file, const char __user *user,
 		return -EFAULT;
 	optstr[count - 1] = '\0';
 
+	if (!strcmp(optstr, "on")) {
+		set_bau_on();
+		return count;
+	} else if (!strcmp(optstr, "off")) {
+		set_bau_off();
+		return count;
+	}
+
 	if (strict_strtol(optstr, 10, &input_arg) < 0) {
 		printk(KERN_DEBUG "%s is invalid\n", optstr);
 		return -EINVAL;
@@ -1570,7 +1589,8 @@ static ssize_t tunables_write(struct file *file, const char __user *user,
 		bcp->complete_threshold =	complete_threshold;
 		bcp->cong_response_us =		congested_respns_us;
 		bcp->cong_reps =		congested_reps;
-		bcp->cong_period =		congested_period;
+		bcp->disabled_period =		sec_2_cycles(disabled_period);
+		bcp->giveup_limit =		giveup_limit;
 	}
 	return count;
 }
@@ -1699,6 +1719,10 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode)
 			 *   fairness chaining multilevel count replied_to
 			 */
 		} else {
+			/*
+			 * BIOS uses legacy mode, but UV2 hardware always
+			 * uses native mode for selective broadcasts.
+			 */
 			uv2_hdr = &bd2->header.uv2_hdr;
 			uv2_hdr->swack_flag =	1;
 			uv2_hdr->base_dest_nasid =
@@ -1811,8 +1835,8 @@ static int calculate_destination_timeout(void)
 		index = (mmr_image >> BAU_URGENCY_7_SHIFT) & BAU_URGENCY_7_MASK;
 		mmr_image = uv_read_local_mmr(UVH_TRANSACTION_TIMEOUT);
 		mult2 = (mmr_image >> BAU_TRANS_SHIFT) & BAU_TRANS_MASK;
-		base = timeout_base_ns[index];
-		ts_ns = base * mult1 * mult2;
+		ts_ns = timeout_base_ns[index];
+		ts_ns *= (mult1 * mult2);
 		ret = ts_ns / 1000;
 	} else {
 		/* 4 bits  0/1 for 10/80us base, 3 bits of multiplier */
@@ -1836,6 +1860,8 @@ static void __init init_per_cpu_tunables(void)
 	for_each_present_cpu(cpu) {
 		bcp = &per_cpu(bau_control, cpu);
 		bcp->baudisabled		= 0;
+		if (nobau)
+			bcp->nobau		= 1;
 		bcp->statp			= &per_cpu(ptcstats, cpu);
 		/* time interval to catch a hardware stay-busy bug */
 		bcp->timeout_interval		= usec_2_cycles(2*timeout_us);
@@ -1848,10 +1874,11 @@ static void __init init_per_cpu_tunables(void)
 		bcp->complete_threshold		= complete_threshold;
 		bcp->cong_response_us		= congested_respns_us;
 		bcp->cong_reps			= congested_reps;
-		bcp->cong_period		= congested_period;
-		bcp->clocks_per_100_usec =	usec_2_cycles(100);
+		bcp->disabled_period =		sec_2_cycles(disabled_period);
+		bcp->giveup_limit =		giveup_limit;
 		spin_lock_init(&bcp->queue_lock);
 		spin_lock_init(&bcp->uvhub_lock);
+		spin_lock_init(&bcp->disable_lock);
 	}
 }
 
@@ -1972,7 +1999,6 @@ static int scan_sock(struct socket_desc *sdp, struct uvhub_desc *bdp,
 		}
 		bcp->uvhub_master = *hmasterp;
 		bcp->uvhub_cpu = uv_cpu_hub_info(cpu)->blade_processor_id;
-		bcp->using_desc = bcp->uvhub_cpu;
 		if (bcp->uvhub_cpu >= MAX_CPUS_PER_UVHUB) {
 			printk(KERN_EMERG "%d cpus per uvhub invalid\n",
 				bcp->uvhub_cpu);
@@ -2069,16 +2095,12 @@ static int __init uv_bau_init(void)
 	if (!is_uv_system())
 		return 0;
 
-	if (nobau)
-		return 0;
-
 	for_each_possible_cpu(cur_cpu) {
 		mask = &per_cpu(uv_flush_tlb_mask, cur_cpu);
 		zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu));
 	}
 
 	nuvhubs = uv_num_possible_blades();
-	spin_lock_init(&disable_lock);
 	congested_cycles = usec_2_cycles(congested_respns_us);
 
 	uv_base_pnode = 0x7fffffff;
@@ -2091,7 +2113,8 @@ static int __init uv_bau_init(void)
 	enable_timeouts();
 
 	if (init_per_cpu(nuvhubs, uv_base_pnode)) {
-		nobau = 1;
+		set_bau_off();
+		nobau_perm = 1;
 		return 0;
 	}
 
diff --git a/arch/x86/platform/uv/uv_irq.c b/arch/x86/platform/uv/uv_irq.c
index f25c276..acf7752 100644
--- a/arch/x86/platform/uv/uv_irq.c
+++ b/arch/x86/platform/uv/uv_irq.c
@@ -135,6 +135,7 @@ arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
 	unsigned long mmr_value;
 	struct uv_IO_APIC_route_entry *entry;
 	int mmr_pnode, err;
+	unsigned int dest;
 
 	BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
 			sizeof(unsigned long));
@@ -143,6 +144,10 @@ arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
 	if (err != 0)
 		return err;
 
+	err = apic->cpu_mask_to_apicid_and(eligible_cpu, eligible_cpu, &dest);
+	if (err != 0)
+		return err;
+
 	if (limit == UV_AFFINITY_CPU)
 		irq_set_status_flags(irq, IRQ_NO_BALANCING);
 	else
@@ -159,7 +164,7 @@ arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
 	entry->polarity		= 0;
 	entry->trigger		= 0;
 	entry->mask		= 0;
-	entry->dest		= apic->cpu_mask_to_apicid(eligible_cpu);
+	entry->dest		= dest;
 
 	mmr_pnode = uv_blade_to_pnode(mmr_blade);
 	uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
@@ -222,7 +227,7 @@ uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask,
 	if (cfg->move_in_progress)
 		send_cleanup_vector(cfg);
 
-	return 0;
+	return IRQ_SET_MASK_OK_NOCOPY;
 }
 
 /*
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 5b84a2d..b2d534c 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -22,7 +22,7 @@ wakeup-objs	+= video-bios.o
 realmode-y			+= header.o
 realmode-y			+= trampoline_$(BITS).o
 realmode-y			+= stack.o
-realmode-$(CONFIG_X86_32)	+= reboot_32.o
+realmode-y			+= reboot.o
 realmode-$(CONFIG_ACPI_SLEEP)	+= $(wakeup-objs)
 
 targets	+= $(realmode-y)
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index fadf483..a28221d 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -6,6 +6,7 @@
 
 #include <linux/linkage.h>
 #include <asm/page_types.h>
+#include <asm/segment.h>
 
 #include "realmode.h"
 	
@@ -28,8 +29,9 @@ GLOBAL(real_mode_header)
 	.long	pa_wakeup_header
 #endif
 	/* APM/BIOS reboot */
-#ifdef CONFIG_X86_32
 	.long	pa_machine_real_restart_asm
+#ifdef CONFIG_X86_64
+	.long	__KERNEL32_CS
 #endif
 END(real_mode_header)
 
diff --git a/arch/x86/realmode/rm/reboot.S b/arch/x86/realmode/rm/reboot.S
new file mode 100644
index 0000000..f932ea6
--- /dev/null
+++ b/arch/x86/realmode/rm/reboot.S
@@ -0,0 +1,156 @@
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/segment.h>
+#include <asm/page_types.h>
+#include <asm/processor-flags.h>
+#include <asm/msr-index.h>
+#include "realmode.h"
+
+/*
+ * The following code and data reboots the machine by switching to real
+ * mode and jumping to the BIOS reset entry point, as if the CPU has
+ * really been reset.  The previous version asked the keyboard
+ * controller to pulse the CPU reset line, which is more thorough, but
+ * doesn't work with at least one type of 486 motherboard.  It is easy
+ * to stop this code working; hence the copious comments.
+ *
+ * This code is called with the restart type (0 = BIOS, 1 = APM) in
+ * the primary argument register (%eax for 32 bit, %edi for 64 bit).
+ */
+	.section ".text32", "ax"
+	.code32
+ENTRY(machine_real_restart_asm)
+
+#ifdef CONFIG_X86_64
+	/* Switch to trampoline GDT as it is guaranteed < 4 GiB */
+	movl	$__KERNEL_DS, %eax
+	movl	%eax, %ds
+	lgdtl	pa_tr_gdt
+
+	/* Disable paging to drop us out of long mode */
+	movl	%cr0, %eax
+	andl	$~X86_CR0_PG, %eax
+	movl	%eax, %cr0
+	ljmpl	$__KERNEL32_CS, $pa_machine_real_restart_paging_off
+
+GLOBAL(machine_real_restart_paging_off)
+	xorl	%eax, %eax
+	xorl	%edx, %edx
+	movl	$MSR_EFER, %ecx
+	wrmsr
+
+	movl	%edi, %eax
+	
+#endif /* CONFIG_X86_64 */
+	
+	/* Set up the IDT for real mode. */
+	lidtl	pa_machine_real_restart_idt
+
+	/*
+	 * Set up a GDT from which we can load segment descriptors for real
+	 * mode.  The GDT is not used in real mode; it is just needed here to
+	 * prepare the descriptors.
+	 */
+	lgdtl	pa_machine_real_restart_gdt
+
+	/*
+	 * Load the data segment registers with 16-bit compatible values
+	 */
+	movl	$16, %ecx
+	movl	%ecx, %ds
+	movl	%ecx, %es
+	movl	%ecx, %fs
+	movl	%ecx, %gs
+	movl	%ecx, %ss
+	ljmpw	$8, $1f
+
+/*
+ * This is 16-bit protected mode code to disable paging and the cache,
+ * switch to real mode and jump to the BIOS reset code.
+ *
+ * The instruction that switches to real mode by writing to CR0 must be
+ * followed immediately by a far jump instruction, which set CS to a
+ * valid value for real mode, and flushes the prefetch queue to avoid
+ * running instructions that have already been decoded in protected
+ * mode.
+ *
+ * Clears all the flags except ET, especially PG (paging), PE
+ * (protected-mode enable) and TS (task switch for coprocessor state
+ * save).  Flushes the TLB after paging has been disabled.  Sets CD and
+ * NW, to disable the cache on a 486, and invalidates the cache.  This
+ * is more like the state of a 486 after reset.  I don't know if
+ * something else should be done for other chips.
+ *
+ * More could be done here to set up the registers as if a CPU reset had
+ * occurred; hopefully real BIOSs don't assume much.  This is not the
+ * actual BIOS entry point, anyway (that is at 0xfffffff0).
+ *
+ * Most of this work is probably excessive, but it is what is tested.
+ */
+	.text
+	.code16
+
+	.balign	16
+machine_real_restart_asm16:
+1:
+	xorl	%ecx, %ecx
+	movl	%cr0, %edx
+	andl	$0x00000011, %edx
+	orl	$0x60000000, %edx
+	movl	%edx, %cr0
+	movl	%ecx, %cr3
+	movl	%cr0, %edx
+	testl	$0x60000000, %edx	/* If no cache bits -> no wbinvd */
+	jz	2f
+	wbinvd
+2:
+	andb	$0x10, %dl
+	movl	%edx, %cr0
+	LJMPW_RM(3f)
+3:
+	andw	%ax, %ax
+	jz	bios
+
+apm:
+	movw	$0x1000, %ax
+	movw	%ax, %ss
+	movw	$0xf000, %sp
+	movw	$0x5307, %ax
+	movw	$0x0001, %bx
+	movw	$0x0003, %cx
+	int	$0x15
+	/* This should never return... */
+
+bios:
+	ljmpw	$0xf000, $0xfff0
+
+	.section ".rodata", "a"
+
+	.balign	16
+GLOBAL(machine_real_restart_idt)
+	.word	0xffff		/* Length - real mode default value */
+	.long	0		/* Base - real mode default value */
+END(machine_real_restart_idt)
+
+	.balign	16
+GLOBAL(machine_real_restart_gdt)
+	/* Self-pointer */
+	.word	0xffff		/* Length - real mode default value */
+	.long	pa_machine_real_restart_gdt
+	.word	0
+
+	/*
+	 * 16-bit code segment pointing to real_mode_seg
+	 * Selector value 8
+	 */
+	.word	0xffff		/* Limit */
+	.long	0x9b000000 + pa_real_mode_base
+	.word	0
+
+	/*
+	 * 16-bit data segment with the selector value 16 = 0x10 and
+	 * base value 0x100; since this is consistent with real mode
+	 * semantics we don't have to reload the segments once CR0.PE = 0.
+	 */
+	.quad	GDT_ENTRY(0x0093, 0x100, 0xffff)
+END(machine_real_restart_gdt)
diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
deleted file mode 100644
index 1140448..0000000
--- a/arch/x86/realmode/rm/reboot_32.S
+++ /dev/null
@@ -1,132 +0,0 @@
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/segment.h>
-#include <asm/page_types.h>
-#include "realmode.h"
-
-/*
- * The following code and data reboots the machine by switching to real
- * mode and jumping to the BIOS reset entry point, as if the CPU has
- * really been reset.  The previous version asked the keyboard
- * controller to pulse the CPU reset line, which is more thorough, but
- * doesn't work with at least one type of 486 motherboard.  It is easy
- * to stop this code working; hence the copious comments.
- *
- * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax.
- */
-	.section ".text32", "ax"
-	.code32
-
-	.balign	16
-ENTRY(machine_real_restart_asm)
-	/* Set up the IDT for real mode. */
-	lidtl	pa_machine_real_restart_idt
-
-	/*
-	 * Set up a GDT from which we can load segment descriptors for real
-	 * mode.  The GDT is not used in real mode; it is just needed here to
-	 * prepare the descriptors.
-	 */
-	lgdtl	pa_machine_real_restart_gdt
-
-	/*
-	 * Load the data segment registers with 16-bit compatible values
-	 */
-	movl	$16, %ecx
-	movl	%ecx, %ds
-	movl	%ecx, %es
-	movl	%ecx, %fs
-	movl	%ecx, %gs
-	movl	%ecx, %ss
-	ljmpw	$8, $1f
-
-/*
- * This is 16-bit protected mode code to disable paging and the cache,
- * switch to real mode and jump to the BIOS reset code.
- *
- * The instruction that switches to real mode by writing to CR0 must be
- * followed immediately by a far jump instruction, which set CS to a
- * valid value for real mode, and flushes the prefetch queue to avoid
- * running instructions that have already been decoded in protected
- * mode.
- *
- * Clears all the flags except ET, especially PG (paging), PE
- * (protected-mode enable) and TS (task switch for coprocessor state
- * save).  Flushes the TLB after paging has been disabled.  Sets CD and
- * NW, to disable the cache on a 486, and invalidates the cache.  This
- * is more like the state of a 486 after reset.  I don't know if
- * something else should be done for other chips.
- *
- * More could be done here to set up the registers as if a CPU reset had
- * occurred; hopefully real BIOSs don't assume much.  This is not the
- * actual BIOS entry point, anyway (that is at 0xfffffff0).
- *
- * Most of this work is probably excessive, but it is what is tested.
- */
-	.text
-	.code16
-
-	.balign	16
-machine_real_restart_asm16:
-1:
-	xorl	%ecx, %ecx
-	movl	%cr0, %edx
-	andl	$0x00000011, %edx
-	orl	$0x60000000, %edx
-	movl	%edx, %cr0
-	movl	%ecx, %cr3
-	movl	%cr0, %edx
-	testl	$0x60000000, %edx	/* If no cache bits -> no wbinvd */
-	jz	2f
-	wbinvd
-2:
-	andb	$0x10, %dl
-	movl	%edx, %cr0
-	LJMPW_RM(3f)
-3:
-	andw	%ax, %ax
-	jz	bios
-
-apm:
-	movw	$0x1000, %ax
-	movw	%ax, %ss
-	movw	$0xf000, %sp
-	movw	$0x5307, %ax
-	movw	$0x0001, %bx
-	movw	$0x0003, %cx
-	int	$0x15
-	/* This should never return... */
-
-bios:
-	ljmpw	$0xf000, $0xfff0
-
-	.section ".rodata", "a"
-
-	.balign	16
-GLOBAL(machine_real_restart_idt)
-	.word	0xffff		/* Length - real mode default value */
-	.long	0		/* Base - real mode default value */
-END(machine_real_restart_idt)
-
-	.balign	16
-GLOBAL(machine_real_restart_gdt)
-	/* Self-pointer */
-	.word	0xffff		/* Length - real mode default value */
-	.long	pa_machine_real_restart_gdt
-	.word	0
-
-	/*
-	 * 16-bit code segment pointing to real_mode_seg
-	 * Selector value 8
-	 */
-	.word	0xffff		/* Limit */
-	.long	0x9b000000 + pa_real_mode_base
-	.word	0
-
-	/*
-	 * 16-bit data segment with the selector value 16 = 0x10 and
-	 * base value 0x100; since this is consistent with real mode
-	 * semantics we don't have to reload the segments once CR0.PE = 0.
-	 */
-	.quad	GDT_ENTRY(0x0093, 0x100, 0xffff)
-END(machine_real_restart_gdt)
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index 66e6d93..0faad64 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -205,9 +205,9 @@ void syscall32_cpu_init(void)
 {
 	/* Load these always in case some future AMD CPU supports
 	   SYSENTER from compat mode too. */
-	checking_wrmsrl(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
-	checking_wrmsrl(MSR_IA32_SYSENTER_ESP, 0ULL);
-	checking_wrmsrl(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target);
+	wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
+	wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL);
+	wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target);
 
 	wrmsrl(MSR_CSTAR, ia32_cstar_target);
 }
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index ff962d4..84838ce 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -38,6 +38,7 @@
 #include <xen/interface/physdev.h>
 #include <xen/interface/vcpu.h>
 #include <xen/interface/memory.h>
+#include <xen/interface/xen-mca.h>
 #include <xen/features.h>
 #include <xen/page.h>
 #include <xen/hvm.h>
@@ -209,9 +210,6 @@ static void __init xen_banner(void)
 	       xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
 }
 
-#define CPUID_THERM_POWER_LEAF 6
-#define APERFMPERF_PRESENT 0
-
 static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0;
 static __read_mostly unsigned int cpuid_leaf1_ecx_mask = ~0;
 
@@ -245,11 +243,6 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
 		*dx = cpuid_leaf5_edx_val;
 		return;
 
-	case CPUID_THERM_POWER_LEAF:
-		/* Disabling APERFMPERF for kernel usage */
-		maskecx = ~(1 << APERFMPERF_PRESENT);
-		break;
-
 	case 0xb:
 		/* Suppress extended topology stuff */
 		maskebx = 0;
@@ -341,9 +334,7 @@ static void __init xen_init_cpuid_mask(void)
 	unsigned int xsave_mask;
 
 	cpuid_leaf1_edx_mask =
-		~((1 << X86_FEATURE_MCE)  |  /* disable MCE */
-		  (1 << X86_FEATURE_MCA)  |  /* disable MCA */
-		  (1 << X86_FEATURE_MTRR) |  /* disable MTRR */
+		~((1 << X86_FEATURE_MTRR) |  /* disable MTRR */
 		  (1 << X86_FEATURE_ACC));   /* thermal monitoring */
 
 	if (!xen_initial_domain())
@@ -627,8 +618,8 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,
 	/*
 	 * Look for known traps using IST, and substitute them
 	 * appropriately.  The debugger ones are the only ones we care
-	 * about.  Xen will handle faults like double_fault and
-	 * machine_check, so we should never see them.  Warn if
+	 * about.  Xen will handle faults like double_fault,
+	 * so we should never see them.  Warn if
 	 * there's an unexpected IST-using fault handler.
 	 */
 	if (addr == (unsigned long)debug)
@@ -643,7 +634,11 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,
 		return 0;
 #ifdef CONFIG_X86_MCE
 	} else if (addr == (unsigned long)machine_check) {
-		return 0;
+		/*
+		 * when xen hypervisor inject vMCE to guest,
+		 * use native mce handler to handle it
+		 */
+		;
 #endif
 	} else {
 		/* Some other trap using IST? */
@@ -1124,9 +1119,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
 	.wbinvd = native_wbinvd,
 
 	.read_msr = native_read_msr_safe,
-	.rdmsr_regs = native_rdmsr_safe_regs,
 	.write_msr = xen_write_msr_safe,
-	.wrmsr_regs = native_wrmsr_safe_regs,
 
 	.read_tsc = native_read_tsc,
 	.read_pmc = native_read_pmc,
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index afb250d..f58dca7 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -80,9 +80,7 @@ static void __cpuinit cpu_bringup(void)
 
 	notify_cpu_starting(cpu);
 
-	ipi_call_lock();
 	set_cpu_online(cpu, true);
-	ipi_call_unlock();
 
 	this_cpu_write(cpu_state, CPU_ONLINE);
 
diff --git a/arch/xtensa/include/asm/thread_info.h b/arch/xtensa/include/asm/thread_info.h
index 81abfd5..9481004 100644
--- a/arch/xtensa/include/asm/thread_info.h
+++ b/arch/xtensa/include/asm/thread_info.h
@@ -128,19 +128,14 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SIGPENDING		1	/* signal pending */
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
 #define TIF_SINGLESTEP		3	/* restore singlestep on return to user mode */
-#define TIF_IRET		4	/* return with iret */
 #define TIF_MEMDIE		5	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	6	/* restore signal mask in do_signal() */
 #define TIF_NOTIFY_RESUME	7	/* callback before returning to user */
-#define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
-#define _TIF_IRET		(1<<TIF_IRET)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index eb30e35..9c57c1e 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -187,7 +187,7 @@ static int __init pcibios_init(void)
 		bus = pci_scan_root_bus(NULL, pci_ctrl->first_busno,
 					pci_ctrl->ops, pci_ctrl, &resources);
 		pci_ctrl->bus = bus;
-		pci_ctrl->last_busno = bus->subordinate;
+		pci_ctrl->last_busno = bus->busn_res.end;
 		if (next_busno <= pci_ctrl->last_busno)
 			next_busno = pci_ctrl->last_busno+1;
 	}
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index efe4e85..63c566f 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -19,7 +19,6 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 
 #include <asm/ucontext.h>
@@ -527,9 +526,6 @@ static void do_signal(struct pt_regs *regs)
 
 void do_notify_resume(struct pt_regs *regs)
 {
-	if (!user_mode(regs))
-		return;
-
 	if (test_thread_flag(TIF_SIGPENDING))
 		do_signal(regs);
 
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 02cf633..e7dee61 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -125,12 +125,8 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q)
 
 		blkg->pd[i] = pd;
 		pd->blkg = blkg;
-	}
-
-	/* invoke per-policy init */
-	for (i = 0; i < BLKCG_MAX_POLS; i++) {
-		struct blkcg_policy *pol = blkcg_policy[i];
 
+		/* invoke per-policy init */
 		if (blkcg_policy_enabled(blkg->q, pol))
 			pol->pd_init_fn(blkg);
 	}
@@ -245,10 +241,9 @@ EXPORT_SYMBOL_GPL(blkg_lookup_create);
 
 static void blkg_destroy(struct blkcg_gq *blkg)
 {
-	struct request_queue *q = blkg->q;
 	struct blkcg *blkcg = blkg->blkcg;
 
-	lockdep_assert_held(q->queue_lock);
+	lockdep_assert_held(blkg->q->queue_lock);
 	lockdep_assert_held(&blkcg->lock);
 
 	/* Something wrong if we are trying to remove same group twice */
diff --git a/block/blk-core.c b/block/blk-core.c
index 3c923a7..93eb3e4 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -361,9 +361,10 @@ EXPORT_SYMBOL(blk_put_queue);
  */
 void blk_drain_queue(struct request_queue *q, bool drain_all)
 {
+	int i;
+
 	while (true) {
 		bool drain = false;
-		int i;
 
 		spin_lock_irq(q->queue_lock);
 
@@ -408,6 +409,18 @@ void blk_drain_queue(struct request_queue *q, bool drain_all)
 			break;
 		msleep(10);
 	}
+
+	/*
+	 * With queue marked dead, any woken up waiter will fail the
+	 * allocation path, so the wakeup chaining is lost and we're
+	 * left with hung waiters. We need to wake up those waiters.
+	 */
+	if (q->request_fn) {
+		spin_lock_irq(q->queue_lock);
+		for (i = 0; i < ARRAY_SIZE(q->rq.wait); i++)
+			wake_up_all(&q->rq.wait[i]);
+		spin_unlock_irq(q->queue_lock);
+	}
 }
 
 /**
@@ -467,7 +480,6 @@ void blk_cleanup_queue(struct request_queue *q)
 	/* mark @q DEAD, no new request or merges will be allowed afterwards */
 	mutex_lock(&q->sysfs_lock);
 	queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);
-
 	spin_lock_irq(lock);
 
 	/*
@@ -485,10 +497,6 @@ void blk_cleanup_queue(struct request_queue *q)
 	queue_flag_set(QUEUE_FLAG_NOMERGES, q);
 	queue_flag_set(QUEUE_FLAG_NOXMERGES, q);
 	queue_flag_set(QUEUE_FLAG_DEAD, q);
-
-	if (q->queue_lock != &q->__queue_lock)
-		q->queue_lock = &q->__queue_lock;
-
 	spin_unlock_irq(lock);
 	mutex_unlock(&q->sysfs_lock);
 
@@ -499,6 +507,11 @@ void blk_cleanup_queue(struct request_queue *q)
 	del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);
 	blk_sync_queue(q);
 
+	spin_lock_irq(lock);
+	if (q->queue_lock != &q->__queue_lock)
+		q->queue_lock = &q->__queue_lock;
+	spin_unlock_irq(lock);
+
 	/* @q is and will stay empty, shutdown and put */
 	blk_put_queue(q);
 }
diff --git a/block/blk-timeout.c b/block/blk-timeout.c
index 7803548..6e4744c 100644
--- a/block/blk-timeout.c
+++ b/block/blk-timeout.c
@@ -197,44 +197,3 @@ void blk_add_timer(struct request *req)
 		mod_timer(&q->timeout, expiry);
 }
 
-/**
- * blk_abort_queue -- Abort all request on given queue
- * @queue:	pointer to queue
- *
- */
-void blk_abort_queue(struct request_queue *q)
-{
-	unsigned long flags;
-	struct request *rq, *tmp;
-	LIST_HEAD(list);
-
-	/*
-	 * Not a request based block device, nothing to abort
-	 */
-	if (!q->request_fn)
-		return;
-
-	spin_lock_irqsave(q->queue_lock, flags);
-
-	elv_abort_queue(q);
-
-	/*
-	 * Splice entries to local list, to avoid deadlocking if entries
-	 * get readded to the timeout list by error handling
-	 */
-	list_splice_init(&q->timeout_list, &list);
-
-	list_for_each_entry_safe(rq, tmp, &list, timeout_list)
-		blk_abort_request(rq);
-
-	/*
-	 * Occasionally, blk_abort_request() will return without
-	 * deleting the element from the list. Make sure we add those back
-	 * instead of leaving them on the local stack list.
-	 */
-	list_splice(&list, &q->timeout_list);
-
-	spin_unlock_irqrestore(q->queue_lock, flags);
-
-}
-EXPORT_SYMBOL_GPL(blk_abort_queue);
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 673c977..fb52df9 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -17,8 +17,6 @@
 #include "blk.h"
 #include "blk-cgroup.h"
 
-static struct blkcg_policy blkcg_policy_cfq __maybe_unused;
-
 /*
  * tunables
  */
@@ -418,11 +416,6 @@ static inline struct cfq_group *pd_to_cfqg(struct blkg_policy_data *pd)
 	return pd ? container_of(pd, struct cfq_group, pd) : NULL;
 }
 
-static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg)
-{
-	return pd_to_cfqg(blkg_to_pd(blkg, &blkcg_policy_cfq));
-}
-
 static inline struct blkcg_gq *cfqg_to_blkg(struct cfq_group *cfqg)
 {
 	return pd_to_blkg(&cfqg->pd);
@@ -572,6 +565,13 @@ static inline void cfqg_stats_update_avg_queue_size(struct cfq_group *cfqg) { }
 
 #ifdef CONFIG_CFQ_GROUP_IOSCHED
 
+static struct blkcg_policy blkcg_policy_cfq;
+
+static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg)
+{
+	return pd_to_cfqg(blkg_to_pd(blkg, &blkcg_policy_cfq));
+}
+
 static inline void cfqg_get(struct cfq_group *cfqg)
 {
 	return blkg_get(cfqg_to_blkg(cfqg));
@@ -3951,10 +3951,11 @@ static void cfq_exit_queue(struct elevator_queue *e)
 
 	cfq_shutdown_timer_wq(cfqd);
 
-#ifndef CONFIG_CFQ_GROUP_IOSCHED
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+	blkcg_deactivate_policy(q, &blkcg_policy_cfq);
+#else
 	kfree(cfqd->root_group);
 #endif
-	blkcg_deactivate_policy(q, &blkcg_policy_cfq);
 	kfree(cfqd);
 }
 
@@ -4194,14 +4195,15 @@ static int __init cfq_init(void)
 #ifdef CONFIG_CFQ_GROUP_IOSCHED
 	if (!cfq_group_idle)
 		cfq_group_idle = 1;
-#else
-		cfq_group_idle = 0;
-#endif
 
 	ret = blkcg_policy_register(&blkcg_policy_cfq);
 	if (ret)
 		return ret;
+#else
+	cfq_group_idle = 0;
+#endif
 
+	ret = -ENOMEM;
 	cfq_pool = KMEM_CACHE(cfq_queue, 0);
 	if (!cfq_pool)
 		goto err_pol_unreg;
@@ -4215,13 +4217,17 @@ static int __init cfq_init(void)
 err_free_pool:
 	kmem_cache_destroy(cfq_pool);
 err_pol_unreg:
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
 	blkcg_policy_unregister(&blkcg_policy_cfq);
+#endif
 	return ret;
 }
 
 static void __exit cfq_exit(void)
 {
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
 	blkcg_policy_unregister(&blkcg_policy_cfq);
+#endif
 	elv_unregister(&iosched_cfq);
 	kmem_cache_destroy(cfq_pool);
 }
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 260fa80..9a87daa 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -721,11 +721,14 @@ int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd)
 		break;
 	}
 
+	if (capable(CAP_SYS_RAWIO))
+		return 0;
+
 	/* In particular, rule out all resets and host-specific ioctls.  */
 	printk_ratelimited(KERN_WARNING
 			   "%s: sending ioctl %x to a partition!\n", current->comm, cmd);
 
-	return capable(CAP_SYS_RAWIO) ? 0 : -ENOIOCTLCMD;
+	return -ENOIOCTLCMD;
 }
 EXPORT_SYMBOL(scsi_verify_blk_ioctl);
 
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 8e84225..2c1c2df 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -821,6 +821,26 @@ config CRYPTO_SERPENT_SSE2_586
 	  See also:
 	  <http://www.cl.cam.ac.uk/~rja14/serpent.html>
 
+config CRYPTO_SERPENT_AVX_X86_64
+	tristate "Serpent cipher algorithm (x86_64/AVX)"
+	depends on X86 && 64BIT
+	select CRYPTO_ALGAPI
+	select CRYPTO_CRYPTD
+	select CRYPTO_SERPENT
+	select CRYPTO_LRW
+	select CRYPTO_XTS
+	help
+	  Serpent cipher algorithm, by Anderson, Biham & Knudsen.
+
+	  Keys are allowed to be from 0 to 256 bits in length, in steps
+	  of 8 bits.
+
+	  This module provides the Serpent cipher algorithm that processes
+	  eight blocks parallel using the AVX instruction set.
+
+	  See also:
+	  <http://www.cl.cam.ac.uk/~rja14/serpent.html>
+
 config CRYPTO_TEA
 	tristate "TEA, XTEA and XETA cipher algorithms"
 	select CRYPTO_ALGAPI
@@ -913,6 +933,30 @@ config CRYPTO_TWOFISH_X86_64_3WAY
 	  See also:
 	  <http://www.schneier.com/twofish.html>
 
+config CRYPTO_TWOFISH_AVX_X86_64
+	tristate "Twofish cipher algorithm (x86_64/AVX)"
+	depends on X86 && 64BIT
+	select CRYPTO_ALGAPI
+	select CRYPTO_CRYPTD
+	select CRYPTO_TWOFISH_COMMON
+	select CRYPTO_TWOFISH_X86_64
+	select CRYPTO_TWOFISH_X86_64_3WAY
+	select CRYPTO_LRW
+	select CRYPTO_XTS
+	help
+	  Twofish cipher algorithm (x86_64/AVX).
+
+	  Twofish was submitted as an AES (Advanced Encryption Standard)
+	  candidate cipher by researchers at CounterPane Systems.  It is a
+	  16 round block cipher supporting key sizes of 128, 192, and 256
+	  bits.
+
+	  This module provides the Twofish cipher algorithm that processes
+	  eight blocks parallel using the AVX Instruction Set.
+
+	  See also:
+	  <http://www.schneier.com/twofish.html>
+
 comment "Compression"
 
 config CRYPTO_DEFLATE
diff --git a/crypto/algapi.c b/crypto/algapi.c
index 056571b..c3b9bfe 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -24,22 +24,6 @@
 
 static LIST_HEAD(crypto_template_list);
 
-void crypto_larval_error(const char *name, u32 type, u32 mask)
-{
-	struct crypto_alg *alg;
-
-	alg = crypto_alg_lookup(name, type, mask);
-
-	if (alg) {
-		if (crypto_is_larval(alg)) {
-			struct crypto_larval *larval = (void *)alg;
-			complete_all(&larval->completion);
-		}
-		crypto_mod_put(alg);
-	}
-}
-EXPORT_SYMBOL_GPL(crypto_larval_error);
-
 static inline int crypto_set_driver_name(struct crypto_alg *alg)
 {
 	static const char suffix[] = "-generic";
@@ -295,7 +279,6 @@ found:
 				continue;
 
 			larval->adult = alg;
-			complete_all(&larval->completion);
 			continue;
 		}
 
diff --git a/crypto/algboss.c b/crypto/algboss.c
index 791d194..f97027e 100644
--- a/crypto/algboss.c
+++ b/crypto/algboss.c
@@ -11,6 +11,7 @@
  */
 
 #include <crypto/internal/aead.h>
+#include <linux/completion.h>
 #include <linux/ctype.h>
 #include <linux/err.h>
 #include <linux/init.h>
@@ -47,6 +48,8 @@ struct cryptomgr_param {
 	char larval[CRYPTO_MAX_ALG_NAME];
 	char template[CRYPTO_MAX_ALG_NAME];
 
+	struct completion *completion;
+
 	u32 otype;
 	u32 omask;
 };
@@ -66,7 +69,7 @@ static int cryptomgr_probe(void *data)
 
 	tmpl = crypto_lookup_template(param->template);
 	if (!tmpl)
-		goto err;
+		goto out;
 
 	do {
 		if (tmpl->create) {
@@ -83,16 +86,10 @@ static int cryptomgr_probe(void *data)
 
 	crypto_tmpl_put(tmpl);
 
-	if (err)
-		goto err;
-
 out:
+	complete(param->completion);
 	kfree(param);
 	module_put_and_exit(0);
-
-err:
-	crypto_larval_error(param->larval, param->otype, param->omask);
-	goto out;
 }
 
 static int cryptomgr_schedule_probe(struct crypto_larval *larval)
@@ -192,10 +189,14 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval)
 
 	memcpy(param->larval, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME);
 
+	param->completion = &larval->completion;
+
 	thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe");
 	if (IS_ERR(thread))
 		goto err_free_param;
 
+	wait_for_completion_interruptible(&larval->completion);
+
 	return NOTIFY_STOP;
 
 err_free_param:
diff --git a/crypto/arc4.c b/crypto/arc4.c
index 0d12a96..5a772c3 100644
--- a/crypto/arc4.c
+++ b/crypto/arc4.c
@@ -11,17 +11,19 @@
  * (at your option) any later version.
  *
  */
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/crypto.h>
+#include <crypto/algapi.h>
 
 #define ARC4_MIN_KEY_SIZE	1
 #define ARC4_MAX_KEY_SIZE	256
 #define ARC4_BLOCK_SIZE		1
 
 struct arc4_ctx {
-	u8 S[256];
-	u8 x, y;
+	u32 S[256];
+	u32 x, y;
 };
 
 static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key,
@@ -37,7 +39,7 @@ static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 		ctx->S[i] = i;
 
 	for (i = 0; i < 256; i++) {
-		u8 a = ctx->S[i];
+		u32 a = ctx->S[i];
 		j = (j + in_key[k] + a) & 0xff;
 		ctx->S[i] = ctx->S[j];
 		ctx->S[j] = a;
@@ -48,51 +50,114 @@ static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 	return 0;
 }
 
-static void arc4_crypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+static void arc4_crypt(struct arc4_ctx *ctx, u8 *out, const u8 *in,
+		       unsigned int len)
 {
-	struct arc4_ctx *ctx = crypto_tfm_ctx(tfm);
+	u32 *const S = ctx->S;
+	u32 x, y, a, b;
+	u32 ty, ta, tb;
+
+	if (len == 0)
+		return;
 
-	u8 *const S = ctx->S;
-	u8 x = ctx->x;
-	u8 y = ctx->y;
-	u8 a, b;
+	x = ctx->x;
+	y = ctx->y;
 
 	a = S[x];
 	y = (y + a) & 0xff;
 	b = S[y];
-	S[x] = b;
-	S[y] = a;
-	x = (x + 1) & 0xff;
-	*out++ = *in ^ S[(a + b) & 0xff];
+
+	do {
+		S[y] = a;
+		a = (a + b) & 0xff;
+		S[x] = b;
+		x = (x + 1) & 0xff;
+		ta = S[x];
+		ty = (y + ta) & 0xff;
+		tb = S[ty];
+		*out++ = *in++ ^ S[a];
+		if (--len == 0)
+			break;
+		y = ty;
+		a = ta;
+		b = tb;
+	} while (true);
 
 	ctx->x = x;
 	ctx->y = y;
 }
 
-static struct crypto_alg arc4_alg = {
+static void arc4_crypt_one(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+	arc4_crypt(crypto_tfm_ctx(tfm), out, in, 1);
+}
+
+static int ecb_arc4_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+			  struct scatterlist *src, unsigned int nbytes)
+{
+	struct arc4_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	struct blkcipher_walk walk;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+
+	err = blkcipher_walk_virt(desc, &walk);
+
+	while (walk.nbytes > 0) {
+		u8 *wsrc = walk.src.virt.addr;
+		u8 *wdst = walk.dst.virt.addr;
+
+		arc4_crypt(ctx, wdst, wsrc, walk.nbytes);
+
+		err = blkcipher_walk_done(desc, &walk, 0);
+	}
+
+	return err;
+}
+
+static struct crypto_alg arc4_algs[2] = { {
 	.cra_name		=	"arc4",
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	ARC4_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct arc4_ctx),
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(arc4_alg.cra_list),
-	.cra_u			=	{ .cipher = {
-	.cia_min_keysize	=	ARC4_MIN_KEY_SIZE,
-	.cia_max_keysize	=	ARC4_MAX_KEY_SIZE,
-	.cia_setkey		=	arc4_set_key,
-	.cia_encrypt		=	arc4_crypt,
-	.cia_decrypt		=	arc4_crypt } }
-};
+	.cra_u			=	{
+		.cipher = {
+			.cia_min_keysize	=	ARC4_MIN_KEY_SIZE,
+			.cia_max_keysize	=	ARC4_MAX_KEY_SIZE,
+			.cia_setkey		=	arc4_set_key,
+			.cia_encrypt		=	arc4_crypt_one,
+			.cia_decrypt		=	arc4_crypt_one,
+		},
+	},
+}, {
+	.cra_name		=	"ecb(arc4)",
+	.cra_priority		=	100,
+	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		=	ARC4_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct arc4_ctx),
+	.cra_alignmask		=	0,
+	.cra_type		=	&crypto_blkcipher_type,
+	.cra_module		=	THIS_MODULE,
+	.cra_u			=	{
+		.blkcipher = {
+			.min_keysize	=	ARC4_MIN_KEY_SIZE,
+			.max_keysize	=	ARC4_MAX_KEY_SIZE,
+			.setkey		=	arc4_set_key,
+			.encrypt	=	ecb_arc4_crypt,
+			.decrypt	=	ecb_arc4_crypt,
+		},
+	},
+} };
 
 static int __init arc4_init(void)
 {
-	return crypto_register_alg(&arc4_alg);
+	return crypto_register_algs(arc4_algs, ARRAY_SIZE(arc4_algs));
 }
 
-
 static void __exit arc4_exit(void)
 {
-	crypto_unregister_alg(&arc4_alg);
+	crypto_unregister_algs(arc4_algs, ARRAY_SIZE(arc4_algs));
 }
 
 module_init(arc4_init);
diff --git a/crypto/internal.h b/crypto/internal.h
index b865ca1..9ebedae 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -83,7 +83,6 @@ void crypto_exit_compress_ops(struct crypto_tfm *tfm);
 struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask);
 void crypto_larval_kill(struct crypto_alg *alg);
 struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask);
-void crypto_larval_error(const char *name, u32 type, u32 mask);
 void crypto_alg_tested(const char *name, int err);
 
 void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 8f147bf..58ad4fe 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -1192,6 +1192,9 @@ static int do_test(int m)
 	case 109:
 		ret += tcrypt_test("vmac(aes)");
 		break;
+	case 110:
+		ret += tcrypt_test("hmac(crc32)");
+		break;
 
 	case 150:
 		ret += tcrypt_test("ansi_cprng");
@@ -1339,6 +1342,11 @@ static int do_test(int m)
 				  speed_template_32_64);
 		break;
 
+	case 208:
+		test_cipher_speed("ecb(arc4)", ENCRYPT, sec, NULL, 0,
+				  speed_template_8);
+		break;
+
 	case 300:
 		/* fall through */
 
@@ -1563,6 +1571,34 @@ static int do_test(int m)
 				   speed_template_32_64);
 		break;
 
+	case 504:
+		test_acipher_speed("ecb(twofish)", ENCRYPT, sec, NULL, 0,
+				   speed_template_16_24_32);
+		test_acipher_speed("ecb(twofish)", DECRYPT, sec, NULL, 0,
+				   speed_template_16_24_32);
+		test_acipher_speed("cbc(twofish)", ENCRYPT, sec, NULL, 0,
+				   speed_template_16_24_32);
+		test_acipher_speed("cbc(twofish)", DECRYPT, sec, NULL, 0,
+				   speed_template_16_24_32);
+		test_acipher_speed("ctr(twofish)", ENCRYPT, sec, NULL, 0,
+				   speed_template_16_24_32);
+		test_acipher_speed("ctr(twofish)", DECRYPT, sec, NULL, 0,
+				   speed_template_16_24_32);
+		test_acipher_speed("lrw(twofish)", ENCRYPT, sec, NULL, 0,
+				   speed_template_32_40_48);
+		test_acipher_speed("lrw(twofish)", DECRYPT, sec, NULL, 0,
+				   speed_template_32_40_48);
+		test_acipher_speed("xts(twofish)", ENCRYPT, sec, NULL, 0,
+				   speed_template_32_48_64);
+		test_acipher_speed("xts(twofish)", DECRYPT, sec, NULL, 0,
+				   speed_template_32_48_64);
+		break;
+
+	case 505:
+		test_acipher_speed("ecb(arc4)", ENCRYPT, sec, NULL, 0,
+				   speed_template_8);
+		break;
+
 	case 1000:
 		test_available();
 		break;
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 5674878..36748a5 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -1534,6 +1534,21 @@ static int alg_test_null(const struct alg_test_desc *desc,
 /* Please keep this list sorted by algorithm name. */
 static const struct alg_test_desc alg_test_descs[] = {
 	{
+		.alg = "__cbc-serpent-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "__cbc-serpent-sse2",
 		.test = alg_test_null,
 		.suite = {
@@ -1549,6 +1564,21 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "__cbc-twofish-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "__driver-cbc-aes-aesni",
 		.test = alg_test_null,
 		.suite = {
@@ -1564,6 +1594,21 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "__driver-cbc-serpent-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "__driver-cbc-serpent-sse2",
 		.test = alg_test_null,
 		.suite = {
@@ -1579,6 +1624,21 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "__driver-cbc-twofish-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "__driver-ecb-aes-aesni",
 		.test = alg_test_null,
 		.suite = {
@@ -1594,6 +1654,21 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "__driver-ecb-serpent-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "__driver-ecb-serpent-sse2",
 		.test = alg_test_null,
 		.suite = {
@@ -1609,6 +1684,21 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "__driver-ecb-twofish-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "__ghash-pclmulqdqni",
 		.test = alg_test_null,
 		.suite = {
@@ -1791,6 +1881,21 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "cryptd(__driver-ecb-serpent-avx)",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "cryptd(__driver-ecb-serpent-sse2)",
 		.test = alg_test_null,
 		.suite = {
@@ -1806,6 +1911,21 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "cryptd(__driver-ecb-twofish-avx)",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "cryptd(__ghash-pclmulqdqni)",
 		.test = alg_test_null,
 		.suite = {
@@ -2220,6 +2340,15 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "hmac(crc32)",
+		.test = alg_test_hash,
+		.suite = {
+			.hash = {
+				.vecs = bfin_crc_tv_template,
+				.count = BFIN_CRC_TEST_VECTORS
+			}
+		}
+	}, {
 		.alg = "hmac(md5)",
 		.test = alg_test_hash,
 		.suite = {
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 36e5a8e..4d84fe4 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -2765,8 +2765,62 @@ static struct cipher_testvec tf_enc_tv_template[] = {
 			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
 			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
 			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
-			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C",
-		.ilen	= 64,
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.ilen	= 496,
 		.result	= "\x88\xCB\x1E\xC2\xAF\x8A\x97\xFF"
 			  "\xF6\x90\x46\x9C\x4A\x0F\x08\xDC"
 			  "\xDE\xAB\xAD\xFA\xFC\xA8\xC2\x3D"
@@ -2774,8 +2828,62 @@ static struct cipher_testvec tf_enc_tv_template[] = {
 			  "\x34\x9E\xB6\x08\xB2\xDD\xA8\xF5"
 			  "\xDF\xFA\xC7\xE8\x09\x50\x76\x08"
 			  "\xA2\xB6\x6A\x59\xC0\x2B\x6D\x05"
-			  "\x89\xF6\x82\xF0\xD3\xDB\x06\x02",
-		.rlen	= 64,
+			  "\x89\xF6\x82\xF0\xD3\xDB\x06\x02"
+			  "\xB5\x11\x5C\x5E\x79\x1A\xAC\x43"
+			  "\x5C\xC0\x30\x4B\x6B\x16\xA1\x40"
+			  "\x80\x27\x88\xBA\x2C\x74\x42\xE0"
+			  "\x1B\xA5\x85\x08\xB9\xE6\x22\x7A"
+			  "\x36\x3B\x0D\x9F\xA0\x22\x6C\x2A"
+			  "\x91\x75\x47\xBC\x67\x21\x4E\xF9"
+			  "\xEA\xFF\xD9\xD5\xC0\xFC\x9E\x2C"
+			  "\x3E\xAD\xC6\x61\x0E\x93\x7A\x22"
+			  "\x09\xC8\x8D\xC1\x8E\xB4\x8B\x5C"
+			  "\xC6\x24\x42\xB8\x23\x66\x80\xA9"
+			  "\x32\x0B\x7A\x29\xBF\xB3\x0B\x63"
+			  "\x43\x27\x13\xA9\xBE\xEB\xBD\xF3"
+			  "\x33\x62\x70\xE2\x1B\x86\x7A\xA1"
+			  "\x51\x4A\x16\xFE\x29\x63\x7E\xD0"
+			  "\x7A\xA4\x6E\x2C\xF8\xC1\xDB\xE8"
+			  "\xCB\x4D\xD2\x8C\x04\x14\xB4\x66"
+			  "\x41\xB7\x3A\x96\x16\x7C\x1D\x5B"
+			  "\xB6\x41\x42\x64\x43\xEE\x6E\x7C"
+			  "\x8B\xAF\x01\x9C\xA4\x6E\x75\x8F"
+			  "\xDE\x10\x9F\xA6\xE7\xD6\x44\x97"
+			  "\x66\xA3\x96\x0F\x1C\x25\x60\xF5"
+			  "\x3C\x2E\x32\x69\x0E\x82\xFF\x27"
+			  "\x0F\xB5\x06\xDA\xD8\x31\x15\x6C"
+			  "\xDF\x18\x6C\x87\xF5\x3B\x11\x9A"
+			  "\x1B\x42\x1F\x5B\x29\x19\x96\x13"
+			  "\x68\x2E\x5E\x08\x1C\x8F\x32\x4B"
+			  "\x81\x77\x6D\xF4\xA0\x01\x42\xEC"
+			  "\xDD\x5B\xFD\x3A\x8E\x6A\x14\xFB"
+			  "\x83\x54\xDF\x0F\x86\xB7\xEA\x40"
+			  "\x46\x39\xF7\x2A\x89\x8D\x4E\x96"
+			  "\x5F\x5F\x6D\x76\xC6\x13\x9D\x3D"
+			  "\x1D\x5F\x0C\x7D\xE2\xBC\xC2\x16"
+			  "\x16\xBE\x89\x3E\xB0\x61\xA2\x5D"
+			  "\xAF\xD1\x40\x5F\x1A\xB8\x26\x41"
+			  "\xC6\xBD\x36\xEF\xED\x29\x50\x6D"
+			  "\x10\xEF\x26\xE8\xA8\x93\x11\x3F"
+			  "\x2D\x1F\x88\x20\x77\x45\xF5\x66"
+			  "\x08\xB9\xF1\xEF\xB1\x93\xA8\x81"
+			  "\x65\xC5\xCD\x3E\x8C\x06\x60\x2C"
+			  "\xB2\x10\x7A\xCA\x05\x25\x59\xDB"
+			  "\xC7\x28\xF5\x20\x35\x52\x9E\x62"
+			  "\xF8\x88\x24\x1C\x4D\x84\x12\x39"
+			  "\x39\xE4\x2E\xF4\xD4\x9D\x2B\xBC"
+			  "\x87\x66\xE6\xC0\x6B\x31\x9A\x66"
+			  "\x03\xDC\x95\xD8\x6B\xD0\x30\x8F"
+			  "\xDF\x8F\x8D\xFA\xEC\x1F\x08\xBD"
+			  "\xA3\x63\xE2\x71\x4F\x03\x94\x87"
+			  "\x50\xDF\x15\x1F\xED\x3A\xA3\x7F"
+			  "\x1F\x2A\xB5\xA1\x69\xAC\x4B\x0D"
+			  "\x84\x9B\x2A\xE9\x55\xDD\x46\x91"
+			  "\x15\x33\xF3\x2B\x9B\x46\x97\x00"
+			  "\xF0\x29\xD8\x59\x5D\x33\x37\xF9"
+			  "\x58\x33\x9B\x78\xC7\x58\x48\x6B"
+			  "\x2C\x75\x64\xC4\xCA\xC1\x7E\xD5",
+		.rlen	= 496,
 	},
 };
 
@@ -2822,8 +2930,62 @@ static struct cipher_testvec tf_dec_tv_template[] = {
 			  "\x34\x9E\xB6\x08\xB2\xDD\xA8\xF5"
 			  "\xDF\xFA\xC7\xE8\x09\x50\x76\x08"
 			  "\xA2\xB6\x6A\x59\xC0\x2B\x6D\x05"
-			  "\x89\xF6\x82\xF0\xD3\xDB\x06\x02",
-		.ilen	= 64,
+			  "\x89\xF6\x82\xF0\xD3\xDB\x06\x02"
+			  "\xB5\x11\x5C\x5E\x79\x1A\xAC\x43"
+			  "\x5C\xC0\x30\x4B\x6B\x16\xA1\x40"
+			  "\x80\x27\x88\xBA\x2C\x74\x42\xE0"
+			  "\x1B\xA5\x85\x08\xB9\xE6\x22\x7A"
+			  "\x36\x3B\x0D\x9F\xA0\x22\x6C\x2A"
+			  "\x91\x75\x47\xBC\x67\x21\x4E\xF9"
+			  "\xEA\xFF\xD9\xD5\xC0\xFC\x9E\x2C"
+			  "\x3E\xAD\xC6\x61\x0E\x93\x7A\x22"
+			  "\x09\xC8\x8D\xC1\x8E\xB4\x8B\x5C"
+			  "\xC6\x24\x42\xB8\x23\x66\x80\xA9"
+			  "\x32\x0B\x7A\x29\xBF\xB3\x0B\x63"
+			  "\x43\x27\x13\xA9\xBE\xEB\xBD\xF3"
+			  "\x33\x62\x70\xE2\x1B\x86\x7A\xA1"
+			  "\x51\x4A\x16\xFE\x29\x63\x7E\xD0"
+			  "\x7A\xA4\x6E\x2C\xF8\xC1\xDB\xE8"
+			  "\xCB\x4D\xD2\x8C\x04\x14\xB4\x66"
+			  "\x41\xB7\x3A\x96\x16\x7C\x1D\x5B"
+			  "\xB6\x41\x42\x64\x43\xEE\x6E\x7C"
+			  "\x8B\xAF\x01\x9C\xA4\x6E\x75\x8F"
+			  "\xDE\x10\x9F\xA6\xE7\xD6\x44\x97"
+			  "\x66\xA3\x96\x0F\x1C\x25\x60\xF5"
+			  "\x3C\x2E\x32\x69\x0E\x82\xFF\x27"
+			  "\x0F\xB5\x06\xDA\xD8\x31\x15\x6C"
+			  "\xDF\x18\x6C\x87\xF5\x3B\x11\x9A"
+			  "\x1B\x42\x1F\x5B\x29\x19\x96\x13"
+			  "\x68\x2E\x5E\x08\x1C\x8F\x32\x4B"
+			  "\x81\x77\x6D\xF4\xA0\x01\x42\xEC"
+			  "\xDD\x5B\xFD\x3A\x8E\x6A\x14\xFB"
+			  "\x83\x54\xDF\x0F\x86\xB7\xEA\x40"
+			  "\x46\x39\xF7\x2A\x89\x8D\x4E\x96"
+			  "\x5F\x5F\x6D\x76\xC6\x13\x9D\x3D"
+			  "\x1D\x5F\x0C\x7D\xE2\xBC\xC2\x16"
+			  "\x16\xBE\x89\x3E\xB0\x61\xA2\x5D"
+			  "\xAF\xD1\x40\x5F\x1A\xB8\x26\x41"
+			  "\xC6\xBD\x36\xEF\xED\x29\x50\x6D"
+			  "\x10\xEF\x26\xE8\xA8\x93\x11\x3F"
+			  "\x2D\x1F\x88\x20\x77\x45\xF5\x66"
+			  "\x08\xB9\xF1\xEF\xB1\x93\xA8\x81"
+			  "\x65\xC5\xCD\x3E\x8C\x06\x60\x2C"
+			  "\xB2\x10\x7A\xCA\x05\x25\x59\xDB"
+			  "\xC7\x28\xF5\x20\x35\x52\x9E\x62"
+			  "\xF8\x88\x24\x1C\x4D\x84\x12\x39"
+			  "\x39\xE4\x2E\xF4\xD4\x9D\x2B\xBC"
+			  "\x87\x66\xE6\xC0\x6B\x31\x9A\x66"
+			  "\x03\xDC\x95\xD8\x6B\xD0\x30\x8F"
+			  "\xDF\x8F\x8D\xFA\xEC\x1F\x08\xBD"
+			  "\xA3\x63\xE2\x71\x4F\x03\x94\x87"
+			  "\x50\xDF\x15\x1F\xED\x3A\xA3\x7F"
+			  "\x1F\x2A\xB5\xA1\x69\xAC\x4B\x0D"
+			  "\x84\x9B\x2A\xE9\x55\xDD\x46\x91"
+			  "\x15\x33\xF3\x2B\x9B\x46\x97\x00"
+			  "\xF0\x29\xD8\x59\x5D\x33\x37\xF9"
+			  "\x58\x33\x9B\x78\xC7\x58\x48\x6B"
+			  "\x2C\x75\x64\xC4\xCA\xC1\x7E\xD5",
+		.ilen	= 496,
 		.result	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
 			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
 			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
@@ -2831,8 +2993,62 @@ static struct cipher_testvec tf_dec_tv_template[] = {
 			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
 			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
 			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
-			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C",
-		.rlen	= 64,
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.rlen	= 496,
 	},
 };
 
@@ -2894,8 +3110,62 @@ static struct cipher_testvec tf_cbc_enc_tv_template[] = {
 			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
 			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
 			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
-			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C",
-		.ilen	= 64,
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.ilen	= 496,
 		.result	= "\xC8\xFF\xF2\x53\xA6\x27\x09\xD1"
 			  "\x33\x38\xC2\xC0\x0C\x14\x7E\xB5"
 			  "\x26\x1B\x05\x0C\x05\x12\x3F\xC0"
@@ -2903,8 +3173,62 @@ static struct cipher_testvec tf_cbc_enc_tv_template[] = {
 			  "\x3D\x32\xDF\xDA\x56\x00\x6E\xEE"
 			  "\x5B\x2A\x72\x9D\xC2\x4D\x19\xBC"
 			  "\x8C\x53\xFA\x87\x6F\xDD\x81\xA3"
-			  "\xB1\xD3\x44\x65\xDF\xE7\x63\x38",
-		.rlen	= 64,
+			  "\xB1\xD3\x44\x65\xDF\xE7\x63\x38"
+			  "\x4A\xFC\xDC\xEC\x3F\x26\x8E\xB8"
+			  "\x43\xFC\xFE\x18\xB5\x11\x6D\x31"
+			  "\x81\x8B\x0D\x75\xF6\x80\xEC\x84"
+			  "\x04\xB9\xE6\x09\x63\xED\x39\xDB"
+			  "\xC3\xF6\x14\xD6\x6E\x5E\x8B\xBD"
+			  "\x3E\xFA\xD7\x98\x50\x6F\xD9\x63"
+			  "\x02\xCD\x0D\x39\x4B\x0D\xEC\x80"
+			  "\xE3\x6A\x17\xF4\xCC\xAD\xFF\x68"
+			  "\x45\xDD\xC8\x83\x1D\x41\x96\x0D"
+			  "\x91\x2E\x05\xD3\x59\x82\xE0\x43"
+			  "\x90\x4F\xB9\xF7\xAD\x6B\x2E\xAF"
+			  "\xA7\x84\x00\x53\xCD\x6F\xD1\x0C"
+			  "\x4E\xF9\x5A\x23\xFB\xCA\xC7\xD3"
+			  "\xA9\xAA\x9D\xB2\x3F\x66\xF1\xAC"
+			  "\x25\x21\x8F\xF7\xEF\xF2\x6A\xDF"
+			  "\xE8\xDA\x75\x1A\x8A\xF1\xDD\x38"
+			  "\x1F\xF9\x3D\x68\x4A\xBB\x9E\x34"
+			  "\x1F\x66\x1F\x9C\x2B\x54\xFF\x60"
+			  "\x7F\x29\x4B\x55\x80\x8F\x4E\xA7"
+			  "\xA6\x9A\x0A\xD9\x0D\x19\x00\xF8"
+			  "\x1F\xBC\x0C\x40\x6B\xEC\x99\x25"
+			  "\x94\x70\x74\x0E\x1D\xC5\xBC\x12"
+			  "\xF3\x42\xBE\x95\xBF\xFB\x4E\x55"
+			  "\x9A\xB9\xCE\x14\x16\x5B\xDC\xD3"
+			  "\x75\x42\x62\x04\x31\x1F\x95\x7C"
+			  "\x66\x1A\x97\xDC\x2F\x40\x5C\x39"
+			  "\x78\xE6\x02\xDB\x49\xE1\xC6\x47"
+			  "\xC2\x78\x9A\xBB\xF3\xBE\xCB\x93"
+			  "\xD8\xB8\xE8\xBB\x8C\xB3\x9B\xA7"
+			  "\xC2\x89\xF3\x91\x88\x83\x3D\xF0"
+			  "\x29\xA2\xCD\xB5\x79\x16\xC2\x40"
+			  "\x11\x03\x8E\x9C\xFD\xC9\x43\xC4"
+			  "\xC2\x19\xF0\x4A\x32\xEF\x0C\x2B"
+			  "\xD3\x2B\xE9\xD4\x4C\xDE\x95\xCF"
+			  "\x04\x03\xD3\x2C\x7F\x82\xC8\xFA"
+			  "\x0F\xD8\x7A\x39\x7B\x01\x41\x9C"
+			  "\x78\xB6\xC9\xBF\xF9\x78\x57\x88"
+			  "\xB1\xA5\xE1\xE0\xD9\x16\xD4\xC8"
+			  "\xEE\xC4\xBE\x7B\x55\x59\x00\x48"
+			  "\x1B\xBC\x14\xFA\x2A\x9D\xC9\x1C"
+			  "\xFB\x28\x3F\x95\xDD\xB7\xD6\xCE"
+			  "\x3A\x7F\x09\x0C\x0E\x69\x30\x7D"
+			  "\xBC\x68\x9C\x91\x2A\x59\x57\x04"
+			  "\xED\x1A\x1E\x00\xB1\x85\x92\x04"
+			  "\x28\x8C\x0C\x3C\xC1\xD5\x12\xF7"
+			  "\x4C\x3E\xB0\xE7\x86\x62\x68\x91"
+			  "\xFC\xC4\xE2\xCE\xA6\xDC\x5E\x93"
+			  "\x5D\x8D\x8C\x68\xB3\xB2\xB9\x64"
+			  "\x16\xB8\xC8\x6F\xD8\xEE\x21\xBD"
+			  "\xAC\x18\x0C\x7D\x0D\x05\xAB\xF1"
+			  "\xFA\xDD\xE2\x48\xDF\x4C\x02\x39"
+			  "\x69\xA1\x62\xBD\x49\x3A\x9D\x91"
+			  "\x30\x70\x56\xA4\x37\xDD\x7C\xC0"
+			  "\x0A\xA3\x30\x10\x26\x25\x41\x2C",
+		.rlen	= 496,
 	},
 };
 
@@ -2966,8 +3290,62 @@ static struct cipher_testvec tf_cbc_dec_tv_template[] = {
 			  "\x3D\x32\xDF\xDA\x56\x00\x6E\xEE"
 			  "\x5B\x2A\x72\x9D\xC2\x4D\x19\xBC"
 			  "\x8C\x53\xFA\x87\x6F\xDD\x81\xA3"
-			  "\xB1\xD3\x44\x65\xDF\xE7\x63\x38",
-		.ilen	= 64,
+			  "\xB1\xD3\x44\x65\xDF\xE7\x63\x38"
+			  "\x4A\xFC\xDC\xEC\x3F\x26\x8E\xB8"
+			  "\x43\xFC\xFE\x18\xB5\x11\x6D\x31"
+			  "\x81\x8B\x0D\x75\xF6\x80\xEC\x84"
+			  "\x04\xB9\xE6\x09\x63\xED\x39\xDB"
+			  "\xC3\xF6\x14\xD6\x6E\x5E\x8B\xBD"
+			  "\x3E\xFA\xD7\x98\x50\x6F\xD9\x63"
+			  "\x02\xCD\x0D\x39\x4B\x0D\xEC\x80"
+			  "\xE3\x6A\x17\xF4\xCC\xAD\xFF\x68"
+			  "\x45\xDD\xC8\x83\x1D\x41\x96\x0D"
+			  "\x91\x2E\x05\xD3\x59\x82\xE0\x43"
+			  "\x90\x4F\xB9\xF7\xAD\x6B\x2E\xAF"
+			  "\xA7\x84\x00\x53\xCD\x6F\xD1\x0C"
+			  "\x4E\xF9\x5A\x23\xFB\xCA\xC7\xD3"
+			  "\xA9\xAA\x9D\xB2\x3F\x66\xF1\xAC"
+			  "\x25\x21\x8F\xF7\xEF\xF2\x6A\xDF"
+			  "\xE8\xDA\x75\x1A\x8A\xF1\xDD\x38"
+			  "\x1F\xF9\x3D\x68\x4A\xBB\x9E\x34"
+			  "\x1F\x66\x1F\x9C\x2B\x54\xFF\x60"
+			  "\x7F\x29\x4B\x55\x80\x8F\x4E\xA7"
+			  "\xA6\x9A\x0A\xD9\x0D\x19\x00\xF8"
+			  "\x1F\xBC\x0C\x40\x6B\xEC\x99\x25"
+			  "\x94\x70\x74\x0E\x1D\xC5\xBC\x12"
+			  "\xF3\x42\xBE\x95\xBF\xFB\x4E\x55"
+			  "\x9A\xB9\xCE\x14\x16\x5B\xDC\xD3"
+			  "\x75\x42\x62\x04\x31\x1F\x95\x7C"
+			  "\x66\x1A\x97\xDC\x2F\x40\x5C\x39"
+			  "\x78\xE6\x02\xDB\x49\xE1\xC6\x47"
+			  "\xC2\x78\x9A\xBB\xF3\xBE\xCB\x93"
+			  "\xD8\xB8\xE8\xBB\x8C\xB3\x9B\xA7"
+			  "\xC2\x89\xF3\x91\x88\x83\x3D\xF0"
+			  "\x29\xA2\xCD\xB5\x79\x16\xC2\x40"
+			  "\x11\x03\x8E\x9C\xFD\xC9\x43\xC4"
+			  "\xC2\x19\xF0\x4A\x32\xEF\x0C\x2B"
+			  "\xD3\x2B\xE9\xD4\x4C\xDE\x95\xCF"
+			  "\x04\x03\xD3\x2C\x7F\x82\xC8\xFA"
+			  "\x0F\xD8\x7A\x39\x7B\x01\x41\x9C"
+			  "\x78\xB6\xC9\xBF\xF9\x78\x57\x88"
+			  "\xB1\xA5\xE1\xE0\xD9\x16\xD4\xC8"
+			  "\xEE\xC4\xBE\x7B\x55\x59\x00\x48"
+			  "\x1B\xBC\x14\xFA\x2A\x9D\xC9\x1C"
+			  "\xFB\x28\x3F\x95\xDD\xB7\xD6\xCE"
+			  "\x3A\x7F\x09\x0C\x0E\x69\x30\x7D"
+			  "\xBC\x68\x9C\x91\x2A\x59\x57\x04"
+			  "\xED\x1A\x1E\x00\xB1\x85\x92\x04"
+			  "\x28\x8C\x0C\x3C\xC1\xD5\x12\xF7"
+			  "\x4C\x3E\xB0\xE7\x86\x62\x68\x91"
+			  "\xFC\xC4\xE2\xCE\xA6\xDC\x5E\x93"
+			  "\x5D\x8D\x8C\x68\xB3\xB2\xB9\x64"
+			  "\x16\xB8\xC8\x6F\xD8\xEE\x21\xBD"
+			  "\xAC\x18\x0C\x7D\x0D\x05\xAB\xF1"
+			  "\xFA\xDD\xE2\x48\xDF\x4C\x02\x39"
+			  "\x69\xA1\x62\xBD\x49\x3A\x9D\x91"
+			  "\x30\x70\x56\xA4\x37\xDD\x7C\xC0"
+			  "\x0A\xA3\x30\x10\x26\x25\x41\x2C",
+		.ilen	= 496,
 		.result	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
 			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
 			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
@@ -2975,8 +3353,62 @@ static struct cipher_testvec tf_cbc_dec_tv_template[] = {
 			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
 			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
 			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
-			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C",
-		.rlen	= 64,
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.rlen	= 496,
 	},
 };
 
@@ -2996,8 +3428,62 @@ static struct cipher_testvec tf_ctr_enc_tv_template[] = {
 			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
 			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
 			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
-			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C",
-		.ilen	= 64,
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.ilen	= 496,
 		.result	= "\xDF\xDD\x69\xFA\xB0\x2E\xFD\xFE"
 			  "\x70\x9E\xC5\x4B\xC9\xD4\xA1\x30"
 			  "\x26\x9B\x89\xA1\xEE\x43\xE0\x52"
@@ -3005,8 +3491,62 @@ static struct cipher_testvec tf_ctr_enc_tv_template[] = {
 			  "\x9F\x8D\x40\x9F\x24\xFD\x92\xA0"
 			  "\xBC\x8F\x35\xDD\x67\x38\xD8\xAA"
 			  "\xCF\xF8\x48\xCA\xFB\xE4\x5C\x60"
-			  "\x01\x41\x21\x12\x38\xAB\x52\x4F",
-		.rlen	= 64,
+			  "\x01\x41\x21\x12\x38\xAB\x52\x4F"
+			  "\xA8\x57\x20\xE0\x21\x6A\x17\x0D"
+			  "\x0E\xF9\x8E\x49\x42\x00\x3C\x94"
+			  "\x14\xC0\xD0\x8D\x8A\x98\xEB\x29"
+			  "\xEC\xAE\x96\x44\xC0\x3C\x48\xDC"
+			  "\x29\x35\x25\x2F\xE7\x11\x6C\x68"
+			  "\xC8\x67\x0A\x2F\xF4\x07\xBE\xF9"
+			  "\x2C\x31\x87\x40\xAB\xB2\xB6\xFA"
+			  "\xD2\xC9\x6D\x5C\x50\xE9\xE6\x7E"
+			  "\xE3\x0A\xD2\xD5\x6D\x8D\x64\x9E"
+			  "\x70\xCE\x03\x76\xDD\xE0\xF0\x8C"
+			  "\x84\x86\x8B\x6A\xFE\xC7\xF9\x69"
+			  "\x2E\xFE\xFC\xC2\xC4\x1A\x55\x58"
+			  "\xB3\xBE\xE2\x7E\xED\x39\x42\x6C"
+			  "\xB4\x42\x97\x9A\xEC\xE1\x0A\x06"
+			  "\x02\xC5\x03\x9D\xC4\x48\x15\x66"
+			  "\x35\x6A\xC2\xC9\xA2\x26\x30\xBB"
+			  "\xDB\x2D\xC8\x08\x2B\xA0\x29\x1A"
+			  "\x23\x61\x48\xEA\x80\x04\x27\xAA"
+			  "\x69\x49\xE8\xE8\x4A\x83\x6B\x5A"
+			  "\xCA\x7C\xD3\xB1\xB5\x0B\xCC\x23"
+			  "\x74\x1F\xA9\x87\xCD\xED\xC0\x2D"
+			  "\xBF\xEB\xCF\x16\x2D\x2A\x2E\x1D"
+			  "\x96\xBA\x36\x11\x45\x41\xDA\xCE"
+			  "\xA4\x48\x80\x8B\x06\xF4\x98\x89"
+			  "\x8B\x23\x08\x53\xF4\xD4\x5A\x24"
+			  "\x8B\xF8\x43\x73\xD1\xEE\xC4\xB0"
+			  "\xF8\xFE\x09\x0C\x75\x05\x38\x0B"
+			  "\x7C\x81\xDE\x9D\xE4\x61\x37\x63"
+			  "\x63\xAD\x12\xD2\x04\xB9\xCE\x45"
+			  "\x5A\x1A\x6E\xB3\x78\x2A\xA4\x74"
+			  "\x86\xD0\xE3\xFF\xDA\x38\x9C\xB5"
+			  "\xB8\xB1\xDB\x38\x2F\xC5\x6A\xB4"
+			  "\xEB\x6E\x96\xE8\x43\x80\xB5\x51"
+			  "\x61\x2D\x48\xAA\x07\x65\x11\x8C"
+			  "\x48\xE3\x90\x7E\x78\x3A\xEC\x97"
+			  "\x05\x3D\x84\xE7\x90\x2B\xAA\xBD"
+			  "\x83\x29\x0E\x1A\x81\x73\x7B\xE0"
+			  "\x7A\x01\x4A\x37\x3B\x77\x7F\x8D"
+			  "\x49\xA4\x2F\x6E\xBE\x68\x99\x08"
+			  "\x99\xAA\x4C\x12\x04\xAE\x1F\x77"
+			  "\x35\x88\xF1\x65\x06\x0A\x0B\x4D"
+			  "\x47\xF9\x50\x38\x5D\x71\xF9\x6E"
+			  "\xDE\xEC\x61\x35\x2C\x4C\x96\x50"
+			  "\xE8\x28\x93\x9C\x7E\x01\xC6\x04"
+			  "\xB2\xD6\xBC\x6C\x17\xEB\xC1\x7D"
+			  "\x11\xE9\x43\x83\x76\xAA\x53\x37"
+			  "\x0C\x1D\x39\x89\x53\x72\x09\x7E"
+			  "\xD9\x85\x16\x04\xA5\x2C\x05\x6F"
+			  "\x17\x0C\x6E\x66\xAA\x84\xA7\xD9"
+			  "\xE2\xD9\xC4\xEB\x43\x3E\xB1\x8D"
+			  "\x7C\x36\xC7\x71\x70\x9C\x10\xD8"
+			  "\xE8\x47\x2A\x4D\xFD\xA1\xBC\xE3"
+			  "\xB9\x32\xE2\xC1\x82\xAC\xFE\xCC"
+			  "\xC5\xC9\x7F\x9E\xCF\x33\x7A\xDF",
+		.rlen	= 496,
 	}, { /* Generated with Crypto++ */
 		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
 			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
@@ -3023,8 +3563,62 @@ static struct cipher_testvec tf_ctr_enc_tv_template[] = {
 			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
 			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
 			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
-			  "\xC3\x37\xCE",
-		.ilen	= 67,
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7"
+			  "\x2B\xC2\x59",
+		.ilen	= 499,
 		.result	= "\xDF\xDD\x69\xFA\xB0\x2E\xFD\xFE"
 			  "\x70\x9E\xC5\x4B\xC9\xD4\xA1\x30"
 			  "\x26\x9B\x89\xA1\xEE\x43\xE0\x52"
@@ -3033,8 +3627,62 @@ static struct cipher_testvec tf_ctr_enc_tv_template[] = {
 			  "\xBC\x8F\x35\xDD\x67\x38\xD8\xAA"
 			  "\xCF\xF8\x48\xCA\xFB\xE4\x5C\x60"
 			  "\x01\x41\x21\x12\x38\xAB\x52\x4F"
-			  "\xA8\x57\x20",
-		.rlen	= 67,
+			  "\xA8\x57\x20\xE0\x21\x6A\x17\x0D"
+			  "\x0E\xF9\x8E\x49\x42\x00\x3C\x94"
+			  "\x14\xC0\xD0\x8D\x8A\x98\xEB\x29"
+			  "\xEC\xAE\x96\x44\xC0\x3C\x48\xDC"
+			  "\x29\x35\x25\x2F\xE7\x11\x6C\x68"
+			  "\xC8\x67\x0A\x2F\xF4\x07\xBE\xF9"
+			  "\x2C\x31\x87\x40\xAB\xB2\xB6\xFA"
+			  "\xD2\xC9\x6D\x5C\x50\xE9\xE6\x7E"
+			  "\xE3\x0A\xD2\xD5\x6D\x8D\x64\x9E"
+			  "\x70\xCE\x03\x76\xDD\xE0\xF0\x8C"
+			  "\x84\x86\x8B\x6A\xFE\xC7\xF9\x69"
+			  "\x2E\xFE\xFC\xC2\xC4\x1A\x55\x58"
+			  "\xB3\xBE\xE2\x7E\xED\x39\x42\x6C"
+			  "\xB4\x42\x97\x9A\xEC\xE1\x0A\x06"
+			  "\x02\xC5\x03\x9D\xC4\x48\x15\x66"
+			  "\x35\x6A\xC2\xC9\xA2\x26\x30\xBB"
+			  "\xDB\x2D\xC8\x08\x2B\xA0\x29\x1A"
+			  "\x23\x61\x48\xEA\x80\x04\x27\xAA"
+			  "\x69\x49\xE8\xE8\x4A\x83\x6B\x5A"
+			  "\xCA\x7C\xD3\xB1\xB5\x0B\xCC\x23"
+			  "\x74\x1F\xA9\x87\xCD\xED\xC0\x2D"
+			  "\xBF\xEB\xCF\x16\x2D\x2A\x2E\x1D"
+			  "\x96\xBA\x36\x11\x45\x41\xDA\xCE"
+			  "\xA4\x48\x80\x8B\x06\xF4\x98\x89"
+			  "\x8B\x23\x08\x53\xF4\xD4\x5A\x24"
+			  "\x8B\xF8\x43\x73\xD1\xEE\xC4\xB0"
+			  "\xF8\xFE\x09\x0C\x75\x05\x38\x0B"
+			  "\x7C\x81\xDE\x9D\xE4\x61\x37\x63"
+			  "\x63\xAD\x12\xD2\x04\xB9\xCE\x45"
+			  "\x5A\x1A\x6E\xB3\x78\x2A\xA4\x74"
+			  "\x86\xD0\xE3\xFF\xDA\x38\x9C\xB5"
+			  "\xB8\xB1\xDB\x38\x2F\xC5\x6A\xB4"
+			  "\xEB\x6E\x96\xE8\x43\x80\xB5\x51"
+			  "\x61\x2D\x48\xAA\x07\x65\x11\x8C"
+			  "\x48\xE3\x90\x7E\x78\x3A\xEC\x97"
+			  "\x05\x3D\x84\xE7\x90\x2B\xAA\xBD"
+			  "\x83\x29\x0E\x1A\x81\x73\x7B\xE0"
+			  "\x7A\x01\x4A\x37\x3B\x77\x7F\x8D"
+			  "\x49\xA4\x2F\x6E\xBE\x68\x99\x08"
+			  "\x99\xAA\x4C\x12\x04\xAE\x1F\x77"
+			  "\x35\x88\xF1\x65\x06\x0A\x0B\x4D"
+			  "\x47\xF9\x50\x38\x5D\x71\xF9\x6E"
+			  "\xDE\xEC\x61\x35\x2C\x4C\x96\x50"
+			  "\xE8\x28\x93\x9C\x7E\x01\xC6\x04"
+			  "\xB2\xD6\xBC\x6C\x17\xEB\xC1\x7D"
+			  "\x11\xE9\x43\x83\x76\xAA\x53\x37"
+			  "\x0C\x1D\x39\x89\x53\x72\x09\x7E"
+			  "\xD9\x85\x16\x04\xA5\x2C\x05\x6F"
+			  "\x17\x0C\x6E\x66\xAA\x84\xA7\xD9"
+			  "\xE2\xD9\xC4\xEB\x43\x3E\xB1\x8D"
+			  "\x7C\x36\xC7\x71\x70\x9C\x10\xD8"
+			  "\xE8\x47\x2A\x4D\xFD\xA1\xBC\xE3"
+			  "\xB9\x32\xE2\xC1\x82\xAC\xFE\xCC"
+			  "\xC5\xC9\x7F\x9E\xCF\x33\x7A\xDF"
+			  "\x6C\x82\x9D",
+		.rlen	= 499,
 	},
 };
 
@@ -3054,8 +3702,62 @@ static struct cipher_testvec tf_ctr_dec_tv_template[] = {
 			  "\x9F\x8D\x40\x9F\x24\xFD\x92\xA0"
 			  "\xBC\x8F\x35\xDD\x67\x38\xD8\xAA"
 			  "\xCF\xF8\x48\xCA\xFB\xE4\x5C\x60"
-			  "\x01\x41\x21\x12\x38\xAB\x52\x4F",
-		.ilen	= 64,
+			  "\x01\x41\x21\x12\x38\xAB\x52\x4F"
+			  "\xA8\x57\x20\xE0\x21\x6A\x17\x0D"
+			  "\x0E\xF9\x8E\x49\x42\x00\x3C\x94"
+			  "\x14\xC0\xD0\x8D\x8A\x98\xEB\x29"
+			  "\xEC\xAE\x96\x44\xC0\x3C\x48\xDC"
+			  "\x29\x35\x25\x2F\xE7\x11\x6C\x68"
+			  "\xC8\x67\x0A\x2F\xF4\x07\xBE\xF9"
+			  "\x2C\x31\x87\x40\xAB\xB2\xB6\xFA"
+			  "\xD2\xC9\x6D\x5C\x50\xE9\xE6\x7E"
+			  "\xE3\x0A\xD2\xD5\x6D\x8D\x64\x9E"
+			  "\x70\xCE\x03\x76\xDD\xE0\xF0\x8C"
+			  "\x84\x86\x8B\x6A\xFE\xC7\xF9\x69"
+			  "\x2E\xFE\xFC\xC2\xC4\x1A\x55\x58"
+			  "\xB3\xBE\xE2\x7E\xED\x39\x42\x6C"
+			  "\xB4\x42\x97\x9A\xEC\xE1\x0A\x06"
+			  "\x02\xC5\x03\x9D\xC4\x48\x15\x66"
+			  "\x35\x6A\xC2\xC9\xA2\x26\x30\xBB"
+			  "\xDB\x2D\xC8\x08\x2B\xA0\x29\x1A"
+			  "\x23\x61\x48\xEA\x80\x04\x27\xAA"
+			  "\x69\x49\xE8\xE8\x4A\x83\x6B\x5A"
+			  "\xCA\x7C\xD3\xB1\xB5\x0B\xCC\x23"
+			  "\x74\x1F\xA9\x87\xCD\xED\xC0\x2D"
+			  "\xBF\xEB\xCF\x16\x2D\x2A\x2E\x1D"
+			  "\x96\xBA\x36\x11\x45\x41\xDA\xCE"
+			  "\xA4\x48\x80\x8B\x06\xF4\x98\x89"
+			  "\x8B\x23\x08\x53\xF4\xD4\x5A\x24"
+			  "\x8B\xF8\x43\x73\xD1\xEE\xC4\xB0"
+			  "\xF8\xFE\x09\x0C\x75\x05\x38\x0B"
+			  "\x7C\x81\xDE\x9D\xE4\x61\x37\x63"
+			  "\x63\xAD\x12\xD2\x04\xB9\xCE\x45"
+			  "\x5A\x1A\x6E\xB3\x78\x2A\xA4\x74"
+			  "\x86\xD0\xE3\xFF\xDA\x38\x9C\xB5"
+			  "\xB8\xB1\xDB\x38\x2F\xC5\x6A\xB4"
+			  "\xEB\x6E\x96\xE8\x43\x80\xB5\x51"
+			  "\x61\x2D\x48\xAA\x07\x65\x11\x8C"
+			  "\x48\xE3\x90\x7E\x78\x3A\xEC\x97"
+			  "\x05\x3D\x84\xE7\x90\x2B\xAA\xBD"
+			  "\x83\x29\x0E\x1A\x81\x73\x7B\xE0"
+			  "\x7A\x01\x4A\x37\x3B\x77\x7F\x8D"
+			  "\x49\xA4\x2F\x6E\xBE\x68\x99\x08"
+			  "\x99\xAA\x4C\x12\x04\xAE\x1F\x77"
+			  "\x35\x88\xF1\x65\x06\x0A\x0B\x4D"
+			  "\x47\xF9\x50\x38\x5D\x71\xF9\x6E"
+			  "\xDE\xEC\x61\x35\x2C\x4C\x96\x50"
+			  "\xE8\x28\x93\x9C\x7E\x01\xC6\x04"
+			  "\xB2\xD6\xBC\x6C\x17\xEB\xC1\x7D"
+			  "\x11\xE9\x43\x83\x76\xAA\x53\x37"
+			  "\x0C\x1D\x39\x89\x53\x72\x09\x7E"
+			  "\xD9\x85\x16\x04\xA5\x2C\x05\x6F"
+			  "\x17\x0C\x6E\x66\xAA\x84\xA7\xD9"
+			  "\xE2\xD9\xC4\xEB\x43\x3E\xB1\x8D"
+			  "\x7C\x36\xC7\x71\x70\x9C\x10\xD8"
+			  "\xE8\x47\x2A\x4D\xFD\xA1\xBC\xE3"
+			  "\xB9\x32\xE2\xC1\x82\xAC\xFE\xCC"
+			  "\xC5\xC9\x7F\x9E\xCF\x33\x7A\xDF",
+		.ilen	= 496,
 		.result	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
 			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
 			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
@@ -3063,8 +3765,62 @@ static struct cipher_testvec tf_ctr_dec_tv_template[] = {
 			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
 			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
 			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
-			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C",
-		.rlen	= 64,
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.rlen	= 496,
 	}, { /* Generated with Crypto++ */
 		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
 			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
@@ -3081,8 +3837,62 @@ static struct cipher_testvec tf_ctr_dec_tv_template[] = {
 			  "\xBC\x8F\x35\xDD\x67\x38\xD8\xAA"
 			  "\xCF\xF8\x48\xCA\xFB\xE4\x5C\x60"
 			  "\x01\x41\x21\x12\x38\xAB\x52\x4F"
-			  "\xA8\x57\x20",
-		.ilen	= 67,
+			  "\xA8\x57\x20\xE0\x21\x6A\x17\x0D"
+			  "\x0E\xF9\x8E\x49\x42\x00\x3C\x94"
+			  "\x14\xC0\xD0\x8D\x8A\x98\xEB\x29"
+			  "\xEC\xAE\x96\x44\xC0\x3C\x48\xDC"
+			  "\x29\x35\x25\x2F\xE7\x11\x6C\x68"
+			  "\xC8\x67\x0A\x2F\xF4\x07\xBE\xF9"
+			  "\x2C\x31\x87\x40\xAB\xB2\xB6\xFA"
+			  "\xD2\xC9\x6D\x5C\x50\xE9\xE6\x7E"
+			  "\xE3\x0A\xD2\xD5\x6D\x8D\x64\x9E"
+			  "\x70\xCE\x03\x76\xDD\xE0\xF0\x8C"
+			  "\x84\x86\x8B\x6A\xFE\xC7\xF9\x69"
+			  "\x2E\xFE\xFC\xC2\xC4\x1A\x55\x58"
+			  "\xB3\xBE\xE2\x7E\xED\x39\x42\x6C"
+			  "\xB4\x42\x97\x9A\xEC\xE1\x0A\x06"
+			  "\x02\xC5\x03\x9D\xC4\x48\x15\x66"
+			  "\x35\x6A\xC2\xC9\xA2\x26\x30\xBB"
+			  "\xDB\x2D\xC8\x08\x2B\xA0\x29\x1A"
+			  "\x23\x61\x48\xEA\x80\x04\x27\xAA"
+			  "\x69\x49\xE8\xE8\x4A\x83\x6B\x5A"
+			  "\xCA\x7C\xD3\xB1\xB5\x0B\xCC\x23"
+			  "\x74\x1F\xA9\x87\xCD\xED\xC0\x2D"
+			  "\xBF\xEB\xCF\x16\x2D\x2A\x2E\x1D"
+			  "\x96\xBA\x36\x11\x45\x41\xDA\xCE"
+			  "\xA4\x48\x80\x8B\x06\xF4\x98\x89"
+			  "\x8B\x23\x08\x53\xF4\xD4\x5A\x24"
+			  "\x8B\xF8\x43\x73\xD1\xEE\xC4\xB0"
+			  "\xF8\xFE\x09\x0C\x75\x05\x38\x0B"
+			  "\x7C\x81\xDE\x9D\xE4\x61\x37\x63"
+			  "\x63\xAD\x12\xD2\x04\xB9\xCE\x45"
+			  "\x5A\x1A\x6E\xB3\x78\x2A\xA4\x74"
+			  "\x86\xD0\xE3\xFF\xDA\x38\x9C\xB5"
+			  "\xB8\xB1\xDB\x38\x2F\xC5\x6A\xB4"
+			  "\xEB\x6E\x96\xE8\x43\x80\xB5\x51"
+			  "\x61\x2D\x48\xAA\x07\x65\x11\x8C"
+			  "\x48\xE3\x90\x7E\x78\x3A\xEC\x97"
+			  "\x05\x3D\x84\xE7\x90\x2B\xAA\xBD"
+			  "\x83\x29\x0E\x1A\x81\x73\x7B\xE0"
+			  "\x7A\x01\x4A\x37\x3B\x77\x7F\x8D"
+			  "\x49\xA4\x2F\x6E\xBE\x68\x99\x08"
+			  "\x99\xAA\x4C\x12\x04\xAE\x1F\x77"
+			  "\x35\x88\xF1\x65\x06\x0A\x0B\x4D"
+			  "\x47\xF9\x50\x38\x5D\x71\xF9\x6E"
+			  "\xDE\xEC\x61\x35\x2C\x4C\x96\x50"
+			  "\xE8\x28\x93\x9C\x7E\x01\xC6\x04"
+			  "\xB2\xD6\xBC\x6C\x17\xEB\xC1\x7D"
+			  "\x11\xE9\x43\x83\x76\xAA\x53\x37"
+			  "\x0C\x1D\x39\x89\x53\x72\x09\x7E"
+			  "\xD9\x85\x16\x04\xA5\x2C\x05\x6F"
+			  "\x17\x0C\x6E\x66\xAA\x84\xA7\xD9"
+			  "\xE2\xD9\xC4\xEB\x43\x3E\xB1\x8D"
+			  "\x7C\x36\xC7\x71\x70\x9C\x10\xD8"
+			  "\xE8\x47\x2A\x4D\xFD\xA1\xBC\xE3"
+			  "\xB9\x32\xE2\xC1\x82\xAC\xFE\xCC"
+			  "\xC5\xC9\x7F\x9E\xCF\x33\x7A\xDF"
+			  "\x6C\x82\x9D",
+		.ilen	= 499,
 		.result	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
 			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
 			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
@@ -3091,8 +3901,62 @@ static struct cipher_testvec tf_ctr_dec_tv_template[] = {
 			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
 			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
 			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
-			  "\xC3\x37\xCE",
-		.rlen	= 67,
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7"
+			  "\x2B\xC2\x59",
+		.rlen	= 499,
 	},
 };
 
@@ -14858,4 +15722,94 @@ static struct hash_testvec crc32c_tv_template[] = {
 	},
 };
 
+/*
+ * Blakcifn CRC test vectors
+ */
+#define BFIN_CRC_TEST_VECTORS 6
+
+static struct hash_testvec bfin_crc_tv_template[] = {
+	{
+		.psize = 0,
+		.digest = "\x00\x00\x00\x00",
+	},
+	{
+		.key = "\x87\xa9\xcb\xed",
+		.ksize = 4,
+		.psize = 0,
+		.digest = "\x87\xa9\xcb\xed",
+	},
+	{
+		.key = "\xff\xff\xff\xff",
+		.ksize = 4,
+		.plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08"
+			     "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			     "\x11\x12\x13\x14\x15\x16\x17\x18"
+			     "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
+			     "\x21\x22\x23\x24\x25\x26\x27\x28",
+		.psize = 40,
+		.digest = "\x84\x0c\x8d\xa2",
+	},
+	{
+		.key = "\xff\xff\xff\xff",
+		.ksize = 4,
+		.plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08"
+			     "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			     "\x11\x12\x13\x14\x15\x16\x17\x18"
+			     "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
+			     "\x21\x22\x23\x24\x25\x26",
+		.psize = 38,
+		.digest = "\x8c\x58\xec\xb7",
+	},
+	{
+		.key = "\xff\xff\xff\xff",
+		.ksize = 4,
+		.plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08"
+			     "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			     "\x11\x12\x13\x14\x15\x16\x17\x18"
+			     "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
+			     "\x21\x22\x23\x24\x25\x26\x27",
+		.psize = 39,
+		.digest = "\xdc\x50\x28\x7b",
+	},
+	{
+		.key = "\xff\xff\xff\xff",
+		.ksize = 4,
+		.plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08"
+			     "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+			     "\x11\x12\x13\x14\x15\x16\x17\x18"
+			     "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
+			     "\x21\x22\x23\x24\x25\x26\x27\x28"
+			     "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
+			     "\x31\x32\x33\x34\x35\x36\x37\x38"
+			     "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
+			     "\x41\x42\x43\x44\x45\x46\x47\x48"
+			     "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
+			     "\x51\x52\x53\x54\x55\x56\x57\x58"
+			     "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
+			     "\x61\x62\x63\x64\x65\x66\x67\x68"
+			     "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+			     "\x71\x72\x73\x74\x75\x76\x77\x78"
+			     "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
+			     "\x81\x82\x83\x84\x85\x86\x87\x88"
+			     "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
+			     "\x91\x92\x93\x94\x95\x96\x97\x98"
+			     "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
+			     "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
+			     "\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
+			     "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8"
+			     "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
+			     "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8"
+			     "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
+			     "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8"
+			     "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
+			     "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
+			     "\xe9\xea\xeb\xec\xed\xee\xef\xf0",
+		.psize = 240,
+		.digest = "\x10\x19\x4a\x5c",
+		.np = 2,
+		.tap = { 31, 209 }
+	},
+
+};
+
 #endif	/* _CRYPTO_TESTMGR_H */
diff --git a/drivers/Kconfig b/drivers/Kconfig
index bfc9186..1459f67 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -112,6 +112,8 @@ source "drivers/auxdisplay/Kconfig"
 
 source "drivers/uio/Kconfig"
 
+source "drivers/vfio/Kconfig"
+
 source "drivers/vlynq/Kconfig"
 
 source "drivers/virtio/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 2ba29ff..e6efe27 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_ATM)		+= atm/
 obj-$(CONFIG_FUSION)		+= message/
 obj-y				+= firewire/
 obj-$(CONFIG_UIO)		+= uio/
+obj-$(CONFIG_VFIO)		+= vfio/
 obj-y				+= cdrom/
 obj-y				+= auxdisplay/
 obj-$(CONFIG_PCCARD)		+= pcmcia/
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index d985713..24c807f 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -341,7 +341,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
 {
 	struct acpi_memory_device *mem_device;
 	struct acpi_device *device;
-
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
 
 	switch (event) {
 	case ACPI_NOTIFY_BUS_CHECK:
@@ -354,15 +354,20 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
 					  "\nReceived DEVICE CHECK notification for device\n"));
 		if (acpi_memory_get_device(handle, &mem_device)) {
 			printk(KERN_ERR PREFIX "Cannot find driver data\n");
-			return;
+			break;
 		}
 
-		if (!acpi_memory_check_device(mem_device)) {
-			if (acpi_memory_enable_device(mem_device))
-				printk(KERN_ERR PREFIX
-					    "Cannot enable memory device\n");
+		if (acpi_memory_check_device(mem_device))
+			break;
+
+		if (acpi_memory_enable_device(mem_device)) {
+			printk(KERN_ERR PREFIX "Cannot enable memory device\n");
+			break;
 		}
+
+		ost_code = ACPI_OST_SC_SUCCESS;
 		break;
+
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "\nReceived EJECT REQUEST notification for device\n"));
@@ -383,19 +388,35 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
 		 * TBD: Can also be disabled by Callback registration
 		 *      with generic sysfs driver
 		 */
-		if (acpi_memory_disable_device(mem_device))
-			printk(KERN_ERR PREFIX
-				    "Disable memory device\n");
+		if (acpi_memory_disable_device(mem_device)) {
+			printk(KERN_ERR PREFIX "Disable memory device\n");
+			/*
+			 * If _EJ0 was called but failed, _OST is not
+			 * necessary.
+			 */
+			if (mem_device->state == MEMORY_INVALID_STATE)
+				return;
+
+			break;
+		}
+
 		/*
 		 * TBD: Invoke acpi_bus_remove to cleanup data structures
 		 */
-		break;
+
+		/* _EJ0 succeeded; _OST is not necessary */
+		return;
+
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Unsupported event [0x%x]\n", event));
-		break;
+
+		/* non-hotplug event; possibly handled by other handler */
+		return;
 	}
 
+	/* Inform firmware that the hotplug operation has completed */
+	(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
 	return;
 }
 
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index a43fa1a..af4aad6 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -36,6 +36,7 @@
 #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
 #define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
 static DEFINE_MUTEX(isolated_cpus_lock);
+static DEFINE_MUTEX(round_robin_lock);
 
 static unsigned long power_saving_mwait_eax;
 
@@ -107,7 +108,7 @@ static void round_robin_cpu(unsigned int tsk_index)
 	if (!alloc_cpumask_var(&tmp, GFP_KERNEL))
 		return;
 
-	mutex_lock(&isolated_cpus_lock);
+	mutex_lock(&round_robin_lock);
 	cpumask_clear(tmp);
 	for_each_cpu(cpu, pad_busy_cpus)
 		cpumask_or(tmp, tmp, topology_thread_cpumask(cpu));
@@ -116,7 +117,7 @@ static void round_robin_cpu(unsigned int tsk_index)
 	if (cpumask_empty(tmp))
 		cpumask_andnot(tmp, cpu_online_mask, pad_busy_cpus);
 	if (cpumask_empty(tmp)) {
-		mutex_unlock(&isolated_cpus_lock);
+		mutex_unlock(&round_robin_lock);
 		return;
 	}
 	for_each_cpu(cpu, tmp) {
@@ -131,7 +132,7 @@ static void round_robin_cpu(unsigned int tsk_index)
 	tsk_in_cpu[tsk_index] = preferred_cpu;
 	cpumask_set_cpu(preferred_cpu, pad_busy_cpus);
 	cpu_weight[preferred_cpu]++;
-	mutex_unlock(&isolated_cpus_lock);
+	mutex_unlock(&round_robin_lock);
 
 	set_cpus_allowed_ptr(current, cpumask_of(preferred_cpu));
 }
@@ -144,7 +145,7 @@ static void exit_round_robin(unsigned int tsk_index)
 }
 
 static unsigned int idle_pct = 5; /* percentage */
-static unsigned int round_robin_time = 10; /* second */
+static unsigned int round_robin_time = 1; /* second */
 static int power_saving_thread(void *data)
 {
 	struct sched_param param = {.sched_priority = 1};
@@ -234,7 +235,7 @@ static int create_power_saving_task(void)
 
 	ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread,
 		(void *)(unsigned long)ps_tsk_num,
-		"power_saving/%d", ps_tsk_num);
+		"acpi_pad/%d", ps_tsk_num);
 	rc = IS_ERR(ps_tsks[ps_tsk_num]) ? PTR_ERR(ps_tsks[ps_tsk_num]) : 0;
 	if (!rc)
 		ps_tsk_num++;
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 4f7d3f5..dec7994 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -278,8 +278,7 @@ ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache;
 
 /* Global handlers */
 
-ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_device_notify;
-ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify;
+ACPI_EXTERN struct acpi_global_notify_handler acpi_gbl_global_notify[2];
 ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
 ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
 ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index e3922ca..28f6778 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -600,13 +600,22 @@ acpi_status(*acpi_parse_downwards) (struct acpi_walk_state * walk_state,
 
 typedef acpi_status(*acpi_parse_upwards) (struct acpi_walk_state * walk_state);
 
+/* Global handlers for AML Notifies */
+
+struct acpi_global_notify_handler {
+	acpi_notify_handler handler;
+	void *context;
+};
+
 /*
  * Notify info - used to pass info to the deferred notify
  * handler/dispatcher.
  */
 struct acpi_notify_info {
-	ACPI_STATE_COMMON struct acpi_namespace_node *node;
-	union acpi_operand_object *handler_obj;
+	ACPI_STATE_COMMON u8 handler_list_id;
+	struct acpi_namespace_node *node;
+	union acpi_operand_object *handler_list_head;
+	struct acpi_global_notify_handler *global;
 };
 
 /* Generic state is union of structs above */
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index c065078..39a2b84 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -206,8 +206,7 @@ struct acpi_object_method {
  * Common fields for objects that support ASL notifications
  */
 #define ACPI_COMMON_NOTIFY_INFO \
-	union acpi_operand_object       *system_notify;     /* Handler for system notifies */\
-	union acpi_operand_object       *device_notify;     /* Handler for driver notifies */\
+	union acpi_operand_object       *notify_list[2];    /* Handlers for system/device notifies */\
 	union acpi_operand_object       *handler;	/* Handler for Address space */
 
 struct acpi_object_notify_common {	/* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */
@@ -296,10 +295,10 @@ struct acpi_object_buffer_field {
 
 struct acpi_object_notify_handler {
 	ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node;	/* Parent device */
-	u32 handler_type;
-	acpi_notify_handler handler;
+	u32 handler_type;	/* Type: Device/System/Both */
+	acpi_notify_handler handler;	/* Handler address */
 	void *context;
-	struct acpi_object_notify_handler *next;
+	union acpi_operand_object *next[2];	/* Device and System handler lists */
 };
 
 struct acpi_object_addr_handler {
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 925ccf2..5035327 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -460,6 +460,8 @@ acpi_ut_short_divide(u64 in_dividend,
 /*
  * utmisc
  */
+void ut_convert_backslashes(char *pathname);
+
 const char *acpi_ut_validate_exception(acpi_status status);
 
 u8 acpi_ut_is_pci_root_bridge(char *id);
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index cd243cf..8098439 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -53,11 +53,79 @@
 ACPI_MODULE_NAME("dsfield")
 
 /* Local prototypes */
+#ifdef ACPI_ASL_COMPILER
+#include "acdisasm.h"
+static acpi_status
+acpi_ds_create_external_region(acpi_status lookup_status,
+			       union acpi_parse_object *op,
+			       char *path,
+			       struct acpi_walk_state *walk_state,
+			       struct acpi_namespace_node **node);
+#endif
+
 static acpi_status
 acpi_ds_get_field_names(struct acpi_create_field_info *info,
 			struct acpi_walk_state *walk_state,
 			union acpi_parse_object *arg);
 
+#ifdef ACPI_ASL_COMPILER
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_create_external_region (i_aSL Disassembler only)
+ *
+ * PARAMETERS:  lookup_status   - Status from ns_lookup operation
+ *              Op              - Op containing the Field definition and args
+ *              Path            - Pathname of the region
+ *  `           walk_state      - Current method state
+ *              Node            - Where the new region node is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Add region to the external list if NOT_FOUND. Create a new
+ *              region node/object.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_create_external_region(acpi_status lookup_status,
+			       union acpi_parse_object *op,
+			       char *path,
+			       struct acpi_walk_state *walk_state,
+			       struct acpi_namespace_node **node)
+{
+	acpi_status status;
+	union acpi_operand_object *obj_desc;
+
+	if (lookup_status != AE_NOT_FOUND) {
+		return (lookup_status);
+	}
+
+	/*
+	 * Table disassembly:
+	 * operation_region not found. Generate an External for it, and
+	 * insert the name into the namespace.
+	 */
+	acpi_dm_add_to_external_list(op, path, ACPI_TYPE_REGION, 0);
+	status = acpi_ns_lookup(walk_state->scope_info, path, ACPI_TYPE_REGION,
+				ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT,
+				walk_state, node);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	/* Must create and install a region object for the new node */
+
+	obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION);
+	if (!obj_desc) {
+		return (AE_NO_MEMORY);
+	}
+
+	obj_desc->region.node = *node;
+	status = acpi_ns_attach_object(*node, obj_desc, ACPI_TYPE_REGION);
+	return (status);
+}
+#endif
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ds_create_buffer_field
@@ -413,12 +481,19 @@ acpi_ds_create_field(union acpi_parse_object *op,
 	/* First arg is the name of the parent op_region (must already exist) */
 
 	arg = op->common.value.arg;
+
 	if (!region_node) {
 		status =
 		    acpi_ns_lookup(walk_state->scope_info,
 				   arg->common.value.name, ACPI_TYPE_REGION,
 				   ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,
 				   walk_state, &region_node);
+#ifdef ACPI_ASL_COMPILER
+		status = acpi_ds_create_external_region(status, arg,
+							arg->common.value.name,
+							walk_state,
+							&region_node);
+#endif
 		if (ACPI_FAILURE(status)) {
 			ACPI_ERROR_NAMESPACE(arg->common.value.name, status);
 			return_ACPI_STATUS(status);
@@ -591,6 +666,12 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
 				   arg->common.value.name, ACPI_TYPE_REGION,
 				   ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,
 				   walk_state, &region_node);
+#ifdef ACPI_ASL_COMPILER
+		status = acpi_ds_create_external_region(status, arg,
+							arg->common.value.name,
+							walk_state,
+							&region_node);
+#endif
 		if (ACPI_FAILURE(status)) {
 			ACPI_ERROR_NAMESPACE(arg->common.value.name, status);
 			return_ACPI_STATUS(status);
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index 51ef9f5..381fce9 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -101,102 +101,77 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
 			     u32 notify_value)
 {
 	union acpi_operand_object *obj_desc;
-	union acpi_operand_object *handler_obj = NULL;
-	union acpi_generic_state *notify_info;
+	union acpi_operand_object *handler_list_head = NULL;
+	union acpi_generic_state *info;
+	u8 handler_list_id = 0;
 	acpi_status status = AE_OK;
 
 	ACPI_FUNCTION_NAME(ev_queue_notify_request);
 
-	/*
-	 * For value 0x03 (Ejection Request), may need to run a device method.
-	 * For value 0x02 (Device Wake), if _PRW exists, may need to run
-	 *   the _PS0 method.
-	 * For value 0x80 (Status Change) on the power button or sleep button,
-	 *   initiate soft-off or sleep operation.
-	 *
-	 * For all cases, simply dispatch the notify to the handler.
-	 */
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			  "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
-			  acpi_ut_get_node_name(node),
-			  acpi_ut_get_type_name(node->type), notify_value,
-			  acpi_ut_get_notify_name(notify_value), node));
+	/* Are Notifies allowed on this object? */
 
-	/* Get the notify object attached to the NS Node */
-
-	obj_desc = acpi_ns_get_attached_object(node);
-	if (obj_desc) {
-
-		/* We have the notify object, Get the correct handler */
-
-		switch (node->type) {
+	if (!acpi_ev_is_notify_object(node)) {
+		return (AE_TYPE);
+	}
 
-			/* Notify is allowed only on these types */
+	/* Get the correct notify list type (System or Device) */
 
-		case ACPI_TYPE_DEVICE:
-		case ACPI_TYPE_THERMAL:
-		case ACPI_TYPE_PROCESSOR:
+	if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
+		handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
+	} else {
+		handler_list_id = ACPI_DEVICE_HANDLER_LIST;
+	}
 
-			if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
-				handler_obj =
-				    obj_desc->common_notify.system_notify;
-			} else {
-				handler_obj =
-				    obj_desc->common_notify.device_notify;
-			}
-			break;
+	/* Get the notify object attached to the namespace Node */
 
-		default:
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (obj_desc) {
 
-			/* All other types are not supported */
+		/* We have an attached object, Get the correct handler list */
 
-			return (AE_TYPE);
-		}
+		handler_list_head =
+		    obj_desc->common_notify.notify_list[handler_list_id];
 	}
 
 	/*
-	 * If there is a handler to run, schedule the dispatcher.
-	 * Check for:
-	 * 1) Global system notify handler
-	 * 2) Global device notify handler
-	 * 3) Per-device notify handler
+	 * If there is no notify handler (Global or Local)
+	 * for this object, just ignore the notify
 	 */
-	if ((acpi_gbl_system_notify.handler &&
-	     (notify_value <= ACPI_MAX_SYS_NOTIFY)) ||
-	    (acpi_gbl_device_notify.handler &&
-	     (notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) {
-		notify_info = acpi_ut_create_generic_state();
-		if (!notify_info) {
-			return (AE_NO_MEMORY);
-		}
+	if (!acpi_gbl_global_notify[handler_list_id].handler
+	    && !handler_list_head) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
+				  acpi_ut_get_node_name(node), notify_value,
+				  node));
 
-		if (!handler_obj) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "Executing system notify handler for Notify (%4.4s, %X) "
-					  "node %p\n",
-					  acpi_ut_get_node_name(node),
-					  notify_value, node));
-		}
+		return (AE_OK);
+	}
 
-		notify_info->common.descriptor_type =
-		    ACPI_DESC_TYPE_STATE_NOTIFY;
-		notify_info->notify.node = node;
-		notify_info->notify.value = (u16) notify_value;
-		notify_info->notify.handler_obj = handler_obj;
+	/* Setup notify info and schedule the notify dispatcher */
 
-		status =
-		    acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
-				    notify_info);
-		if (ACPI_FAILURE(status)) {
-			acpi_ut_delete_generic_state(notify_info);
-		}
-	} else {
-		/* There is no notify handler (per-device or system) for this device */
+	info = acpi_ut_create_generic_state();
+	if (!info) {
+		return (AE_NO_MEMORY);
+	}
 
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "No notify handler for Notify (%4.4s, %X) node %p\n",
-				  acpi_ut_get_node_name(node), notify_value,
-				  node));
+	info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY;
+
+	info->notify.node = node;
+	info->notify.value = (u16)notify_value;
+	info->notify.handler_list_id = handler_list_id;
+	info->notify.handler_list_head = handler_list_head;
+	info->notify.global = &acpi_gbl_global_notify[handler_list_id];
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+			  "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
+			  acpi_ut_get_node_name(node),
+			  acpi_ut_get_type_name(node->type), notify_value,
+			  acpi_ut_get_notify_name(notify_value), node));
+
+	status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
+				 info);
+	if (ACPI_FAILURE(status)) {
+		acpi_ut_delete_generic_state(info);
 	}
 
 	return (status);
@@ -217,60 +192,34 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
 
 static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
 {
-	union acpi_generic_state *notify_info =
-	    (union acpi_generic_state *)context;
-	acpi_notify_handler global_handler = NULL;
-	void *global_context = NULL;
+	union acpi_generic_state *info = (union acpi_generic_state *)context;
 	union acpi_operand_object *handler_obj;
 
 	ACPI_FUNCTION_ENTRY();
 
-	/*
-	 * We will invoke a global notify handler if installed. This is done
-	 * _before_ we invoke the per-device handler attached to the device.
-	 */
-	if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
-
-		/* Global system notification handler */
-
-		if (acpi_gbl_system_notify.handler) {
-			global_handler = acpi_gbl_system_notify.handler;
-			global_context = acpi_gbl_system_notify.context;
-		}
-	} else {
-		/* Global driver notification handler */
-
-		if (acpi_gbl_device_notify.handler) {
-			global_handler = acpi_gbl_device_notify.handler;
-			global_context = acpi_gbl_device_notify.context;
-		}
-	}
-
-	/* Invoke the system handler first, if present */
+	/* Invoke a global notify handler if installed */
 
-	if (global_handler) {
-		global_handler(notify_info->notify.node,
-			       notify_info->notify.value, global_context);
+	if (info->notify.global->handler) {
+		info->notify.global->handler(info->notify.node,
+					     info->notify.value,
+					     info->notify.global->context);
 	}
 
-	/* Now invoke the per-device handler, if present */
+	/* Now invoke the local notify handler(s) if any are installed */
 
-	handler_obj = notify_info->notify.handler_obj;
-	if (handler_obj) {
-		struct acpi_object_notify_handler *notifier;
+	handler_obj = info->notify.handler_list_head;
+	while (handler_obj) {
+		handler_obj->notify.handler(info->notify.node,
+					    info->notify.value,
+					    handler_obj->notify.context);
 
-		notifier = &handler_obj->notify;
-		while (notifier) {
-			notifier->handler(notify_info->notify.node,
-					  notify_info->notify.value,
-					  notifier->context);
-			notifier = notifier->next;
-		}
+		handler_obj =
+		    handler_obj->notify.next[info->notify.handler_list_id];
 	}
 
 	/* All done with the info object */
 
-	acpi_ut_delete_generic_state(notify_info);
+	acpi_ut_delete_generic_state(info);
 }
 
 #if (!ACPI_REDUCED_HARDWARE)
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 44bef57..6a8b537 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -54,86 +54,25 @@ ACPI_MODULE_NAME("evxface")
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_populate_handler_object
- *
- * PARAMETERS:  handler_obj        - Handler object to populate
- *              handler_type       - The type of handler:
- *                                  ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
- *                                  ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
- *                                  ACPI_ALL_NOTIFY:  both system and device
- *              handler            - Address of the handler
- *              context            - Value passed to the handler on each GPE
- *              next               - Address of a handler object to link to
- *
- * RETURN:      None
- *
- * DESCRIPTION: Populate a handler object.
- *
- ******************************************************************************/
-static void
-acpi_populate_handler_object(struct acpi_object_notify_handler *handler_obj,
-			     u32 handler_type,
-			     acpi_notify_handler handler, void *context,
-			     struct acpi_object_notify_handler *next)
-{
-	handler_obj->handler_type = handler_type;
-	handler_obj->handler = handler;
-	handler_obj->context = context;
-	handler_obj->next = next;
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_add_handler_object
- *
- * PARAMETERS:  parent_obj         - Parent of the new object
- *              handler            - Address of the handler
- *              context            - Value passed to the handler on each GPE
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Create a new handler object and populate it.
- *
- ******************************************************************************/
-static acpi_status
-acpi_add_handler_object(struct acpi_object_notify_handler *parent_obj,
-			acpi_notify_handler handler, void *context)
-{
-	struct acpi_object_notify_handler *handler_obj;
-
-	/* The parent must not be a defice notify handler object. */
-	if (parent_obj->handler_type & ACPI_DEVICE_NOTIFY)
-		return AE_BAD_PARAMETER;
-
-	handler_obj = ACPI_ALLOCATE_ZEROED(sizeof(*handler_obj));
-	if (!handler_obj)
-		return AE_NO_MEMORY;
-
-	acpi_populate_handler_object(handler_obj,
-					ACPI_SYSTEM_NOTIFY,
-					handler, context,
-					parent_obj->next);
-	parent_obj->next = handler_obj;
-
-	return AE_OK;
-}
-
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_install_notify_handler
  *
  * PARAMETERS:  Device          - The device for which notifies will be handled
  *              handler_type    - The type of handler:
- *                                  ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
- *                                  ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
- *                                  ACPI_ALL_NOTIFY:  both system and device
+ *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
+ *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
+ *                                  ACPI_ALL_NOTIFY:    Both System and Device
  *              Handler         - Address of the handler
  *              Context         - Value passed to the handler on each GPE
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Install a handler for notifies on an ACPI device
+ * DESCRIPTION: Install a handler for notifications on an ACPI Device,
+ *              thermal_zone, or Processor object.
+ *
+ * NOTES:       The Root namespace object may have only one handler for each
+ *              type of notify (System/Device). Device/Thermal/Processor objects
+ *              may have one device notify handler, and multiple system notify
+ *              handlers.
  *
  ******************************************************************************/
 acpi_status
@@ -141,17 +80,19 @@ acpi_install_notify_handler(acpi_handle device,
 			    u32 handler_type,
 			    acpi_notify_handler handler, void *context)
 {
+	struct acpi_namespace_node *node =
+	    ACPI_CAST_PTR(struct acpi_namespace_node, device);
 	union acpi_operand_object *obj_desc;
-	union acpi_operand_object *notify_obj;
-	struct acpi_namespace_node *node;
+	union acpi_operand_object *handler_obj;
 	acpi_status status;
+	u32 i;
 
 	ACPI_FUNCTION_TRACE(acpi_install_notify_handler);
 
 	/* Parameter validation */
 
-	if ((!device) ||
-	    (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
+	if ((!device) || (!handler) || (!handler_type) ||
+	    (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
@@ -160,144 +101,112 @@ acpi_install_notify_handler(acpi_handle device,
 		return_ACPI_STATUS(status);
 	}
 
-	/* Convert and validate the device handle */
-
-	node = acpi_ns_validate_handle(device);
-	if (!node) {
-		status = AE_BAD_PARAMETER;
-		goto unlock_and_exit;
-	}
-
 	/*
 	 * Root Object:
 	 * Registering a notify handler on the root object indicates that the
 	 * caller wishes to receive notifications for all objects. Note that
-	 * only one <external> global handler can be regsitered (per notify type).
+	 * only one global handler can be registered per notify type.
+	 * Ensure that a handler is not already installed.
 	 */
 	if (device == ACPI_ROOT_OBJECT) {
+		for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
+			if (handler_type & (i + 1)) {
+				if (acpi_gbl_global_notify[i].handler) {
+					status = AE_ALREADY_EXISTS;
+					goto unlock_and_exit;
+				}
 
-		/* Make sure the handler is not already installed */
-
-		if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
-		     acpi_gbl_system_notify.handler) ||
-		    ((handler_type & ACPI_DEVICE_NOTIFY) &&
-		     acpi_gbl_device_notify.handler)) {
-			status = AE_ALREADY_EXISTS;
-			goto unlock_and_exit;
-		}
-
-		if (handler_type & ACPI_SYSTEM_NOTIFY) {
-			acpi_gbl_system_notify.node = node;
-			acpi_gbl_system_notify.handler = handler;
-			acpi_gbl_system_notify.context = context;
-		}
-
-		if (handler_type & ACPI_DEVICE_NOTIFY) {
-			acpi_gbl_device_notify.node = node;
-			acpi_gbl_device_notify.handler = handler;
-			acpi_gbl_device_notify.context = context;
+				acpi_gbl_global_notify[i].handler = handler;
+				acpi_gbl_global_notify[i].context = context;
+			}
 		}
 
-		/* Global notify handler installed */
+		goto unlock_and_exit;	/* Global notify handler installed, all done */
 	}
 
 	/*
 	 * All Other Objects:
-	 * Caller will only receive notifications specific to the target object.
-	 * Note that only certain object types can receive notifications.
+	 * Caller will only receive notifications specific to the target
+	 * object. Note that only certain object types are allowed to
+	 * receive notifications.
 	 */
-	else {
-		/* Notifies allowed on this object? */
 
-		if (!acpi_ev_is_notify_object(node)) {
-			status = AE_TYPE;
-			goto unlock_and_exit;
-		}
+	/* Are Notifies allowed on this object? */
 
-		/* Check for an existing internal object */
+	if (!acpi_ev_is_notify_object(node)) {
+		status = AE_TYPE;
+		goto unlock_and_exit;
+	}
 
-		obj_desc = acpi_ns_get_attached_object(node);
-		if (obj_desc) {
+	/* Check for an existing internal object, might not exist */
 
-			/* Object exists. */
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (!obj_desc) {
 
-			/* For a device notify, make sure there's no handler. */
-			if ((handler_type & ACPI_DEVICE_NOTIFY) &&
-			     obj_desc->common_notify.device_notify) {
-				status = AE_ALREADY_EXISTS;
-				goto unlock_and_exit;
-			}
+		/* Create a new object */
 
-			/* System notifies may have more handlers installed. */
-			notify_obj = obj_desc->common_notify.system_notify;
+		obj_desc = acpi_ut_create_internal_object(node->type);
+		if (!obj_desc) {
+			status = AE_NO_MEMORY;
+			goto unlock_and_exit;
+		}
 
-			if ((handler_type & ACPI_SYSTEM_NOTIFY) && notify_obj) {
-				struct acpi_object_notify_handler *parent_obj;
+		/* Attach new object to the Node, remove local reference */
 
-				if (handler_type & ACPI_DEVICE_NOTIFY) {
+		status = acpi_ns_attach_object(device, obj_desc, node->type);
+		acpi_ut_remove_reference(obj_desc);
+		if (ACPI_FAILURE(status)) {
+			goto unlock_and_exit;
+		}
+	}
+
+	/* Ensure that the handler is not already installed in the lists */
+
+	for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
+		if (handler_type & (i + 1)) {
+			handler_obj = obj_desc->common_notify.notify_list[i];
+			while (handler_obj) {
+				if (handler_obj->notify.handler == handler) {
 					status = AE_ALREADY_EXISTS;
 					goto unlock_and_exit;
 				}
 
-				parent_obj = &notify_obj->notify;
-				status = acpi_add_handler_object(parent_obj,
-								 handler,
-								 context);
-				goto unlock_and_exit;
-			}
-		} else {
-			/* Create a new object */
-
-			obj_desc = acpi_ut_create_internal_object(node->type);
-			if (!obj_desc) {
-				status = AE_NO_MEMORY;
-				goto unlock_and_exit;
-			}
-
-			/* Attach new object to the Node */
-
-			status =
-			    acpi_ns_attach_object(device, obj_desc, node->type);
-
-			/* Remove local reference to the object */
-
-			acpi_ut_remove_reference(obj_desc);
-			if (ACPI_FAILURE(status)) {
-				goto unlock_and_exit;
+				handler_obj = handler_obj->notify.next[i];
 			}
 		}
+	}
 
-		/* Install the handler */
+	/* Create and populate a new notify handler object */
 
-		notify_obj =
-		    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
-		if (!notify_obj) {
-			status = AE_NO_MEMORY;
-			goto unlock_and_exit;
-		}
+	handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
+	if (!handler_obj) {
+		status = AE_NO_MEMORY;
+		goto unlock_and_exit;
+	}
 
-		acpi_populate_handler_object(&notify_obj->notify,
-						handler_type,
-						handler, context,
-						NULL);
+	handler_obj->notify.node = node;
+	handler_obj->notify.handler_type = handler_type;
+	handler_obj->notify.handler = handler;
+	handler_obj->notify.context = context;
 
-		if (handler_type & ACPI_SYSTEM_NOTIFY) {
-			obj_desc->common_notify.system_notify = notify_obj;
-		}
+	/* Install the handler at the list head(s) */
 
-		if (handler_type & ACPI_DEVICE_NOTIFY) {
-			obj_desc->common_notify.device_notify = notify_obj;
-		}
+	for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
+		if (handler_type & (i + 1)) {
+			handler_obj->notify.next[i] =
+			    obj_desc->common_notify.notify_list[i];
 
-		if (handler_type == ACPI_ALL_NOTIFY) {
+			obj_desc->common_notify.notify_list[i] = handler_obj;
+		}
+	}
 
-			/* Extra ref if installed in both */
+	/* Add an extra reference if handler was installed in both lists */
 
-			acpi_ut_add_reference(notify_obj);
-		}
+	if (handler_type == ACPI_ALL_NOTIFY) {
+		acpi_ut_add_reference(handler_obj);
 	}
 
-      unlock_and_exit:
+unlock_and_exit:
 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 	return_ACPI_STATUS(status);
 }
@@ -308,11 +217,11 @@ ACPI_EXPORT_SYMBOL(acpi_install_notify_handler)
  *
  * FUNCTION:    acpi_remove_notify_handler
  *
- * PARAMETERS:  Device          - The device for which notifies will be handled
+ * PARAMETERS:  Device          - The device for which the handler is installed
  *              handler_type    - The type of handler:
- *                                  ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
- *                                  ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
- *                                  ACPI_ALL_NOTIFY:  both system and device
+ *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
+ *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
+ *                                  ACPI_ALL_NOTIFY:    Both System and Device
  *              Handler         - Address of the handler
  *
  * RETURN:      Status
@@ -324,165 +233,106 @@ acpi_status
 acpi_remove_notify_handler(acpi_handle device,
 			   u32 handler_type, acpi_notify_handler handler)
 {
-	union acpi_operand_object *notify_obj;
+	struct acpi_namespace_node *node =
+	    ACPI_CAST_PTR(struct acpi_namespace_node, device);
 	union acpi_operand_object *obj_desc;
-	struct acpi_namespace_node *node;
+	union acpi_operand_object *handler_obj;
+	union acpi_operand_object *previous_handler_obj;
 	acpi_status status;
+	u32 i;
 
 	ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
 
 	/* Parameter validation */
 
-	if ((!device) ||
-	    (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
-		status = AE_BAD_PARAMETER;
-		goto exit;
+	if ((!device) || (!handler) || (!handler_type) ||
+	    (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
-
-
 	/* Make sure all deferred tasks are completed */
-	acpi_os_wait_events_complete(NULL);
+
+	acpi_os_wait_events_complete();
 
 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 	if (ACPI_FAILURE(status)) {
-		goto exit;
-	}
-
-	/* Convert and validate the device handle */
-
-	node = acpi_ns_validate_handle(device);
-	if (!node) {
-		status = AE_BAD_PARAMETER;
-		goto unlock_and_exit;
+		return_ACPI_STATUS(status);
 	}
 
-	/* Root Object */
+	/* Root Object. Global handlers are removed here */
 
 	if (device == ACPI_ROOT_OBJECT) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Removing notify handler for namespace root object\n"));
+		for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
+			if (handler_type & (i + 1)) {
+				if (!acpi_gbl_global_notify[i].handler ||
+				    (acpi_gbl_global_notify[i].handler !=
+				     handler)) {
+					status = AE_NOT_EXIST;
+					goto unlock_and_exit;
+				}
 
-		if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
-		     !acpi_gbl_system_notify.handler) ||
-		    ((handler_type & ACPI_DEVICE_NOTIFY) &&
-		     !acpi_gbl_device_notify.handler)) {
-			status = AE_NOT_EXIST;
-			goto unlock_and_exit;
-		}
+				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+						  "Removing global notify handler\n"));
 
-		if (handler_type & ACPI_SYSTEM_NOTIFY) {
-			acpi_gbl_system_notify.node = NULL;
-			acpi_gbl_system_notify.handler = NULL;
-			acpi_gbl_system_notify.context = NULL;
+				acpi_gbl_global_notify[i].handler = NULL;
+				acpi_gbl_global_notify[i].context = NULL;
+			}
 		}
 
-		if (handler_type & ACPI_DEVICE_NOTIFY) {
-			acpi_gbl_device_notify.node = NULL;
-			acpi_gbl_device_notify.handler = NULL;
-			acpi_gbl_device_notify.context = NULL;
-		}
+		goto unlock_and_exit;
 	}
 
-	/* All Other Objects */
-
-	else {
-		/* Notifies allowed on this object? */
+	/* All other objects: Are Notifies allowed on this object? */
 
-		if (!acpi_ev_is_notify_object(node)) {
-			status = AE_TYPE;
-			goto unlock_and_exit;
-		}
+	if (!acpi_ev_is_notify_object(node)) {
+		status = AE_TYPE;
+		goto unlock_and_exit;
+	}
 
-		/* Check for an existing internal object */
+	/* Must have an existing internal object */
 
-		obj_desc = acpi_ns_get_attached_object(node);
-		if (!obj_desc) {
-			status = AE_NOT_EXIST;
-			goto unlock_and_exit;
-		}
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (!obj_desc) {
+		status = AE_NOT_EXIST;
+		goto unlock_and_exit;
+	}
 
-		/* Object exists - make sure there's an existing handler */
+	/* Internal object exists. Find the handler and remove it */
 
-		if (handler_type & ACPI_SYSTEM_NOTIFY) {
-			struct acpi_object_notify_handler *handler_obj;
-			struct acpi_object_notify_handler *parent_obj;
+	for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
+		if (handler_type & (i + 1)) {
+			handler_obj = obj_desc->common_notify.notify_list[i];
+			previous_handler_obj = NULL;
 
-			notify_obj = obj_desc->common_notify.system_notify;
-			if (!notify_obj) {
-				status = AE_NOT_EXIST;
-				goto unlock_and_exit;
-			}
+			/* Attempt to find the handler in the handler list */
 
-			handler_obj = &notify_obj->notify;
-			parent_obj = NULL;
-			while (handler_obj->handler != handler) {
-				if (handler_obj->next) {
-					parent_obj = handler_obj;
-					handler_obj = handler_obj->next;
-				} else {
-					break;
-				}
+			while (handler_obj &&
+			       (handler_obj->notify.handler != handler)) {
+				previous_handler_obj = handler_obj;
+				handler_obj = handler_obj->notify.next[i];
 			}
 
-			if (handler_obj->handler != handler) {
-				status = AE_BAD_PARAMETER;
+			if (!handler_obj) {
+				status = AE_NOT_EXIST;
 				goto unlock_and_exit;
 			}
 
-			/*
-			 * Remove the handler.  There are three possible cases.
-			 * First, we may need to remove a non-embedded object.
-			 * Second, we may need to remove the embedded object's
-			 * handler data, while non-embedded objects exist.
-			 * Finally, we may need to remove the embedded object
-			 * entirely along with its container.
-			 */
-			if (parent_obj) {
-				/* Non-embedded object is being removed. */
-				parent_obj->next = handler_obj->next;
-				ACPI_FREE(handler_obj);
-			} else if (notify_obj->notify.next) {
-				/*
-				 * The handler matches the embedded object, but
-				 * there are more handler objects in the list.
-				 * Replace the embedded object's data with the
-				 * first next object's data and remove that
-				 * object.
-				 */
-				parent_obj = &notify_obj->notify;
-				handler_obj = notify_obj->notify.next;
-				*parent_obj = *handler_obj;
-				ACPI_FREE(handler_obj);
-			} else {
-				/* No more handler objects in the list. */
-				obj_desc->common_notify.system_notify = NULL;
-				acpi_ut_remove_reference(notify_obj);
-			}
-		}
+			/* Remove the handler object from the list */
 
-		if (handler_type & ACPI_DEVICE_NOTIFY) {
-			notify_obj = obj_desc->common_notify.device_notify;
-			if (!notify_obj) {
-				status = AE_NOT_EXIST;
-				goto unlock_and_exit;
-			}
+			if (previous_handler_obj) {	/* Handler is not at the list head */
+				previous_handler_obj->notify.next[i] =
+				    handler_obj->notify.next[i];
+			} else {	/* Handler is at the list head */
 
-			if (notify_obj->notify.handler != handler) {
-				status = AE_BAD_PARAMETER;
-				goto unlock_and_exit;
+				obj_desc->common_notify.notify_list[i] =
+				    handler_obj->notify.next[i];
 			}
 
-			/* Remove the handler */
-			obj_desc->common_notify.device_notify = NULL;
-			acpi_ut_remove_reference(notify_obj);
+			acpi_ut_remove_reference(handler_obj);
 		}
 	}
 
-      unlock_and_exit:
+unlock_and_exit:
 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
-      exit:
-	if (ACPI_FAILURE(status))
-		ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler"));
 	return_ACPI_STATUS(status);
 }
 
@@ -849,7 +699,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 
 	/* Make sure all deferred tasks are completed */
 
-	acpi_os_wait_events_complete(NULL);
+	acpi_os_wait_events_complete();
 
 	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
 	if (ACPI_FAILURE(status)) {
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index 2a6ac0a..26c5654 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -109,9 +109,9 @@ static struct acpi_exdump_info acpi_ex_dump_package[5] = {
 static struct acpi_exdump_info acpi_ex_dump_device[4] = {
 	{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_device), NULL},
 	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.handler), "Handler"},
-	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.system_notify),
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[0]),
 	 "System Notify"},
-	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.device_notify),
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[1]),
 	 "Device Notify"}
 };
 
@@ -158,9 +158,9 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = {
 	 "System Level"},
 	{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(power_resource.resource_order),
 	 "Resource Order"},
-	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.system_notify),
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[0]),
 	 "System Notify"},
-	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.device_notify),
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[1]),
 	 "Device Notify"}
 };
 
@@ -169,18 +169,18 @@ static struct acpi_exdump_info acpi_ex_dump_processor[7] = {
 	{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
 	{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"},
 	{ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"},
-	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.system_notify),
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.notify_list[0]),
 	 "System Notify"},
-	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.device_notify),
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.notify_list[1]),
 	 "Device Notify"},
 	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.handler), "Handler"}
 };
 
 static struct acpi_exdump_info acpi_ex_dump_thermal[4] = {
 	{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_thermal), NULL},
-	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.system_notify),
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.notify_list[0]),
 	 "System Notify"},
-	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.device_notify),
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.notify_list[1]),
 	 "Device Notify"},
 	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.handler), "Handler"}
 };
@@ -241,10 +241,15 @@ static struct acpi_exdump_info acpi_ex_dump_address_handler[6] = {
 	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.context), "Context"}
 };
 
-static struct acpi_exdump_info acpi_ex_dump_notify[3] = {
+static struct acpi_exdump_info acpi_ex_dump_notify[7] = {
 	{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_notify), NULL},
 	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.node), "Node"},
-	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.context), "Context"}
+	{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(notify.handler_type), "Handler Type"},
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.handler), "Handler"},
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.context), "Context"},
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.next[0]),
+	 "Next System Notify"},
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.next[1]), "Next Device Notify"}
 };
 
 /* Miscellaneous tables */
@@ -926,9 +931,7 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc,
 	case ACPI_TYPE_STRING:
 
 		acpi_os_printf("[String] Value: ");
-		for (i = 0; i < obj_desc->string.length; i++) {
-			acpi_os_printf("%c", obj_desc->string.pointer[i]);
-		}
+		acpi_ut_print_string(obj_desc->string.pointer, ACPI_UINT8_MAX);
 		acpi_os_printf("\n");
 		break;
 
diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c
index 29e8592..3680c45 100644
--- a/drivers/acpi/acpica/hwesleep.c
+++ b/drivers/acpi/acpica/hwesleep.c
@@ -117,7 +117,8 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags)
 
 	/* Clear wake status (WAK_STS) */
 
-	status = acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
+	status =
+	    acpi_write((u64)ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
@@ -147,7 +148,7 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags)
 	    ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
 	     ACPI_X_SLEEP_TYPE_MASK);
 
-	status = acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE),
+	status = acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE),
 			    &acpi_gbl_FADT.sleep_control);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
@@ -195,7 +196,7 @@ acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags)
 		    ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
 		     ACPI_X_SLEEP_TYPE_MASK);
 
-		(void)acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE),
+		(void)acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE),
 				 &acpi_gbl_FADT.sleep_control);
 	}
 
@@ -239,7 +240,7 @@ acpi_status acpi_hw_extended_wake(u8 sleep_state, u8 flags)
 	 * and use it to determine whether the system is rebooting or
 	 * resuming. Clear WAK_STS for compatibility.
 	 */
-	(void)acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
+	(void)acpi_write((u64)ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
 	acpi_gbl_system_awake_and_running = TRUE;
 
 	acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING);
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 5ac36ab..a683d66 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -618,6 +618,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
 
 				arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP);
 				if (!arg) {
+					acpi_ps_free_op(field);
 					return_PTR(NULL);
 				}
 
@@ -662,6 +663,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
 		} else {
 			arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP);
 			if (!arg) {
+				acpi_ps_free_op(field);
 				return_PTR(NULL);
 			}
 
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 4c9c760..d919f40 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -49,9 +49,10 @@
 ACPI_MODULE_NAME("tbfadt")
 
 /* Local prototypes */
-static ACPI_INLINE void
+static void
 acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
-			     u8 space_id, u8 byte_width, u64 address);
+			     u8 space_id,
+			     u8 byte_width, u64 address, char *register_name);
 
 static void acpi_tb_convert_fadt(void);
 
@@ -182,10 +183,25 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = {
  *
  ******************************************************************************/
 
-static ACPI_INLINE void
+static void
 acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
-			     u8 space_id, u8 byte_width, u64 address)
+			     u8 space_id,
+			     u8 byte_width, u64 address, char *register_name)
 {
+	u8 bit_width;
+
+	/* Bit width field in the GAS is only one byte long, 255 max */
+
+	bit_width = (u8)(byte_width * 8);
+
+	if (byte_width > 31) {	/* (31*8)=248 */
+		ACPI_ERROR((AE_INFO,
+			    "%s - 32-bit FADT register is too long (%u bytes, %u bits) "
+			    "to convert to GAS struct - 255 bits max, truncating",
+			    register_name, byte_width, (byte_width * 8)));
+
+		bit_width = 255;
+	}
 
 	/*
 	 * The 64-bit Address field is non-aligned in the byte packed
@@ -196,7 +212,7 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
 	/* All other fields are byte-wide */
 
 	generic_address->space_id = space_id;
-	generic_address->bit_width = (u8)ACPI_MUL_8(byte_width);
+	generic_address->bit_width = bit_width;
 	generic_address->bit_offset = 0;
 	generic_address->access_width = 0;	/* Access width ANY */
 }
@@ -456,7 +472,8 @@ static void acpi_tb_convert_fadt(void)
 								   &acpi_gbl_FADT,
 								   fadt_info_table
 								   [i].length),
-						     (u64) address32);
+						     (u64) address32,
+						     fadt_info_table[i].name);
 		}
 	}
 }
@@ -670,7 +687,8 @@ static void acpi_tb_setup_fadt_registers(void)
 						     source64->address +
 						     (fadt_pm_info_table[i].
 						      register_num *
-						      pm1_register_byte_width));
+						      pm1_register_byte_width),
+						     "PmRegisters");
 		}
 	}
 }
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index 2a6c3e1..0d50f2c 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -152,7 +152,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
 	case ACPI_TYPE_PROCESSOR:
 	case ACPI_TYPE_THERMAL:
 
-		/* Walk the notify handler list for this object */
+		/* Walk the address handler list for this object */
 
 		handler_desc = object->common_notify.handler;
 		while (handler_desc) {
@@ -480,6 +480,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
 	acpi_status status = AE_OK;
 	union acpi_generic_state *state_list = NULL;
 	union acpi_operand_object *next_object = NULL;
+	union acpi_operand_object *prev_object;
 	union acpi_generic_state *state;
 	u32 i;
 
@@ -505,12 +506,21 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
 		case ACPI_TYPE_POWER:
 		case ACPI_TYPE_THERMAL:
 
-			/* Update the notify objects for these types (if present) */
-
-			acpi_ut_update_ref_count(object->common_notify.
-						 system_notify, action);
-			acpi_ut_update_ref_count(object->common_notify.
-						 device_notify, action);
+			/*
+			 * Update the notify objects for these types (if present)
+			 * Two lists, system and device notify handlers.
+			 */
+			for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
+				prev_object =
+				    object->common_notify.notify_list[i];
+				while (prev_object) {
+					next_object =
+					    prev_object->notify.next[i];
+					acpi_ut_update_ref_count(prev_object,
+								 action);
+					prev_object = next_object;
+				}
+			}
 			break;
 
 		case ACPI_TYPE_PACKAGE:
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 90f53b4..78cf1fe 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -304,8 +304,8 @@ acpi_status acpi_ut_init_globals(void)
 
 	/* Global handlers */
 
-	acpi_gbl_system_notify.handler = NULL;
-	acpi_gbl_device_notify.handler = NULL;
+	acpi_gbl_global_notify[0].handler = NULL;
+	acpi_gbl_global_notify[1].handler = NULL;
 	acpi_gbl_exception_handler = NULL;
 	acpi_gbl_init_handler = NULL;
 	acpi_gbl_table_handler = NULL;
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index 86f19db..e86f897 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -52,6 +52,34 @@ ACPI_MODULE_NAME("utmisc")
 
 /*******************************************************************************
  *
+ * FUNCTION:    ut_convert_backslashes
+ *
+ * PARAMETERS:  Pathname        - File pathname string to be converted
+ *
+ * RETURN:      Modifies the input Pathname
+ *
+ * DESCRIPTION: Convert all backslashes (0x5C) to forward slashes (0x2F) within
+ *              the entire input file pathname string.
+ *
+ ******************************************************************************/
+void ut_convert_backslashes(char *pathname)
+{
+
+	if (!pathname) {
+		return;
+	}
+
+	while (*pathname) {
+		if (*pathname == '\\') {
+			*pathname = '/';
+		}
+
+		pathname++;
+	}
+}
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_ut_validate_exception
  *
  * PARAMETERS:  Status       - The acpi_status code to be formatted
@@ -63,6 +91,7 @@ ACPI_MODULE_NAME("utmisc")
  *              an ASCII string.
  *
  ******************************************************************************/
+
 const char *acpi_ut_validate_exception(acpi_status status)
 {
 	u32 sub_status;
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 5577762..6686b1e 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx,
 	u8 ins = entry->instruction;
 
 	if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
-		return acpi_os_map_generic_address(&entry->register_region);
+		return apei_map_generic_address(&entry->register_region);
 
 	return 0;
 }
@@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx,
 	u8 ins = entry->instruction;
 
 	if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
-		acpi_os_unmap_generic_address(&entry->register_region);
+		apei_unmap_generic_address(&entry->register_region);
 
 	return 0;
 }
@@ -606,6 +606,19 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr,
 	return 0;
 }
 
+int apei_map_generic_address(struct acpi_generic_address *reg)
+{
+	int rc;
+	u32 access_bit_width;
+	u64 address;
+
+	rc = apei_check_gar(reg, &address, &access_bit_width);
+	if (rc)
+		return rc;
+	return acpi_os_map_generic_address(reg);
+}
+EXPORT_SYMBOL_GPL(apei_map_generic_address);
+
 /* read GAR in interrupt (including NMI) or process context */
 int apei_read(u64 *val, struct acpi_generic_address *reg)
 {
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h
index cca240a..f220d64 100644
--- a/drivers/acpi/apei/apei-internal.h
+++ b/drivers/acpi/apei/apei-internal.h
@@ -7,6 +7,8 @@
 #define APEI_INTERNAL_H
 
 #include <linux/cper.h>
+#include <linux/acpi.h>
+#include <linux/acpi_io.h>
 
 struct apei_exec_context;
 
@@ -68,6 +70,13 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio
 /* IP has been set in instruction function */
 #define APEI_EXEC_SET_IP	1
 
+int apei_map_generic_address(struct acpi_generic_address *reg);
+
+static inline void apei_unmap_generic_address(struct acpi_generic_address *reg)
+{
+	acpi_os_unmap_generic_address(reg);
+}
+
 int apei_read(u64 *val, struct acpi_generic_address *reg);
 int apei_write(u64 val, struct acpi_generic_address *reg);
 
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 9b3cac0..1599566 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -301,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
 	if (!ghes)
 		return ERR_PTR(-ENOMEM);
 	ghes->generic = generic;
-	rc = acpi_os_map_generic_address(&generic->error_status_address);
+	rc = apei_map_generic_address(&generic->error_status_address);
 	if (rc)
 		goto err_free;
 	error_block_length = generic->error_block_length;
@@ -321,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
 	return ghes;
 
 err_unmap:
-	acpi_os_unmap_generic_address(&generic->error_status_address);
+	apei_unmap_generic_address(&generic->error_status_address);
 err_free:
 	kfree(ghes);
 	return ERR_PTR(rc);
@@ -330,7 +330,7 @@ err_free:
 static void ghes_fini(struct ghes *ghes)
 {
 	kfree(ghes->estatus);
-	acpi_os_unmap_generic_address(&ghes->generic->error_status_address);
+	apei_unmap_generic_address(&ghes->generic->error_status_address);
 }
 
 enum {
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index adceafd..9628652 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -574,6 +574,10 @@ static void acpi_bus_osc_support(void)
 	capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PPC_OST_SUPPORT;
 #endif
 
+#ifdef ACPI_HOTPLUG_OST
+	capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_HOTPLUG_OST_SUPPORT;
+#endif
+
 	if (!ghes_disable)
 		capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_APEI_SUPPORT;
 	if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 45cd03b..1f9f7d7 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -158,9 +158,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
 	int result;
 	int present;
 	acpi_status status;
-
-
-	present = is_device_present(handle);
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
 
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
@@ -169,32 +167,47 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
 		printk(KERN_WARNING "Container driver received %s event\n",
 		       (type == ACPI_NOTIFY_BUS_CHECK) ?
 		       "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
+
+		present = is_device_present(handle);
 		status = acpi_bus_get_device(handle, &device);
-		if (present) {
-			if (ACPI_FAILURE(status) || !device) {
-				result = container_device_add(&device, handle);
-				if (!result)
-					kobject_uevent(&device->dev.kobj,
-						       KOBJ_ONLINE);
-				else
-					printk(KERN_WARNING
-					       "Failed to add container\n");
-			}
-		} else {
+		if (!present) {
 			if (ACPI_SUCCESS(status)) {
 				/* device exist and this is a remove request */
+				device->flags.eject_pending = 1;
 				kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
+				return;
 			}
+			break;
+		}
+
+		if (!ACPI_FAILURE(status) || device)
+			break;
+
+		result = container_device_add(&device, handle);
+		if (result) {
+			printk(KERN_WARNING "Failed to add container\n");
+			break;
 		}
+
+		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
+		ost_code = ACPI_OST_SC_SUCCESS;
 		break;
+
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		if (!acpi_bus_get_device(handle, &device) && device) {
+			device->flags.eject_pending = 1;
 			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
+			return;
 		}
 		break;
+
 	default:
-		break;
+		/* non-hotplug event; possibly handled by other handler */
+		return;
 	}
+
+	/* Inform firmware that the hotplug operation has completed */
+	(void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
 	return;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index c3881b2..9eaf708 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -891,7 +891,7 @@ static void acpi_os_execute_deferred(struct work_struct *work)
 	struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
 
 	if (dpc->wait)
-		acpi_os_wait_events_complete(NULL);
+		acpi_os_wait_events_complete();
 
 	dpc->function(dpc->context);
 	kfree(dpc);
@@ -987,7 +987,7 @@ acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
 	return __acpi_os_execute(0, function, context, 1);
 }
 
-void acpi_os_wait_events_complete(void *context)
+void acpi_os_wait_events_complete(void)
 {
 	flush_workqueue(kacpid_wq);
 	flush_workqueue(kacpi_notify_wq);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 7aff631..ec54014 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -505,6 +505,8 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
 	strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
 	device->driver_data = root;
 
+	root->mcfg_addr = acpi_pci_root_get_mcfg_addr(device->handle);
+
 	/*
 	 * All supported architectures that use ACPI have support for
 	 * PCI domains, so we indicate this in _OSC support capabilities.
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 0734086..971c454 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -701,9 +701,9 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
 {
 	struct acpi_processor *pr;
 	struct acpi_device *device = NULL;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
 	int result;
 
-
 	switch (event) {
 	case ACPI_NOTIFY_BUS_CHECK:
 	case ACPI_NOTIFY_DEVICE_CHECK:
@@ -715,14 +715,18 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
 		if (!is_processor_present(handle))
 			break;
 
-		if (acpi_bus_get_device(handle, &device)) {
-			result = acpi_processor_device_add(handle, &device);
-			if (result)
-				printk(KERN_ERR PREFIX
-					    "Unable to add the device\n");
+		if (!acpi_bus_get_device(handle, &device))
+			break;
+
+		result = acpi_processor_device_add(handle, &device);
+		if (result) {
+			printk(KERN_ERR PREFIX "Unable to add the device\n");
 			break;
 		}
+
+		ost_code = ACPI_OST_SC_SUCCESS;
 		break;
+
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "received ACPI_NOTIFY_EJECT_REQUEST\n"));
@@ -736,15 +740,23 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
 		if (!pr) {
 			printk(KERN_ERR PREFIX
 				    "Driver data is NULL, dropping EJECT\n");
-			return;
+			break;
 		}
+
+		/* REVISIT: update when eject is supported */
+		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
 		break;
+
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Unsupported event [0x%x]\n", event));
-		break;
+
+		/* non-hotplug event; possibly handled by other handler */
+		return;
 	}
 
+	/* Inform firmware that the hotplug operation has completed */
+	(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
 	return;
 }
 
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index f3decb3..47a8caa 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -224,6 +224,7 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
 /*
  * Suspend / resume control
  */
+static int acpi_idle_suspend;
 static u32 saved_bm_rld;
 
 static void acpi_idle_bm_rld_save(void)
@@ -242,13 +243,21 @@ static void acpi_idle_bm_rld_restore(void)
 
 int acpi_processor_suspend(struct acpi_device * device, pm_message_t state)
 {
+	if (acpi_idle_suspend == 1)
+		return 0;
+
 	acpi_idle_bm_rld_save();
+	acpi_idle_suspend = 1;
 	return 0;
 }
 
 int acpi_processor_resume(struct acpi_device * device)
 {
+	if (acpi_idle_suspend == 0)
+		return 0;
+
 	acpi_idle_bm_rld_restore();
+	acpi_idle_suspend = 0;
 	return 0;
 }
 
@@ -754,6 +763,12 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
 
 	local_irq_disable();
 
+	if (acpi_idle_suspend) {
+		local_irq_enable();
+		cpu_relax();
+		return -EBUSY;
+	}
+
 	lapic_timer_state_broadcast(pr, cx, 1);
 	kt1 = ktime_get_real();
 	acpi_idle_do_entry(cx);
@@ -823,6 +838,12 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 
 	local_irq_disable();
 
+	if (acpi_idle_suspend) {
+		local_irq_enable();
+		cpu_relax();
+		return -EBUSY;
+	}
+
 	if (cx->entry_method != ACPI_CSTATE_FFH) {
 		current_thread_info()->status &= ~TS_POLLING;
 		/*
@@ -907,14 +928,21 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
 						drv, drv->safe_state_index);
 		} else {
 			local_irq_disable();
-			acpi_safe_halt();
+			if (!acpi_idle_suspend)
+				acpi_safe_halt();
 			local_irq_enable();
-			return -EINVAL;
+			return -EBUSY;
 		}
 	}
 
 	local_irq_disable();
 
+	if (acpi_idle_suspend) {
+		local_irq_enable();
+		cpu_relax();
+		return -EBUSY;
+	}
+
 	if (cx->entry_method != ACPI_CSTATE_FFH) {
 		current_thread_info()->status &= ~TS_POLLING;
 		/*
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index c8a1f3b..148556a 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -83,19 +83,29 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
-static void acpi_bus_hot_remove_device(void *context)
+/**
+ * acpi_bus_hot_remove_device: hot-remove a device and its children
+ * @context: struct acpi_eject_event pointer (freed in this func)
+ *
+ * Hot-remove a device and its children. This function frees up the
+ * memory space passed by arg context, so that the caller may call
+ * this function asynchronously through acpi_os_hotplug_execute().
+ */
+void acpi_bus_hot_remove_device(void *context)
 {
+	struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context;
 	struct acpi_device *device;
-	acpi_handle handle = context;
+	acpi_handle handle = ej_event->handle;
 	struct acpi_object_list arg_list;
 	union acpi_object arg;
 	acpi_status status = AE_OK;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
 
 	if (acpi_bus_get_device(handle, &device))
-		return;
+		goto err_out;
 
 	if (!device)
-		return;
+		goto err_out;
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 		"Hot-removing device %s...\n", dev_name(&device->dev)));
@@ -103,7 +113,7 @@ static void acpi_bus_hot_remove_device(void *context)
 	if (acpi_bus_trim(device, 1)) {
 		printk(KERN_ERR PREFIX
 				"Removing device failed\n");
-		return;
+		goto err_out;
 	}
 
 	/* power off device */
@@ -129,10 +139,21 @@ static void acpi_bus_hot_remove_device(void *context)
 	 * TBD: _EJD support.
 	 */
 	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
-	if (ACPI_FAILURE(status))
-		printk(KERN_WARNING PREFIX
-				"Eject device failed\n");
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND)
+			printk(KERN_WARNING PREFIX
+					"Eject device failed\n");
+		goto err_out;
+	}
+
+	kfree(context);
+	return;
 
+err_out:
+	/* Inform firmware the hot-remove operation has completed w/ error */
+	(void) acpi_evaluate_hotplug_ost(handle,
+				ej_event->event, ost_code, NULL);
+	kfree(context);
 	return;
 }
 
@@ -144,6 +165,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
 	acpi_status status;
 	acpi_object_type type = 0;
 	struct acpi_device *acpi_device = to_acpi_device(d);
+	struct acpi_eject_event *ej_event;
 
 	if ((!count) || (buf[0] != '1')) {
 		return -EINVAL;
@@ -160,7 +182,25 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
 		goto err;
 	}
 
-	acpi_os_hotplug_execute(acpi_bus_hot_remove_device, acpi_device->handle);
+	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
+	if (!ej_event) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ej_event->handle = acpi_device->handle;
+	if (acpi_device->flags.eject_pending) {
+		/* event originated from ACPI eject notification */
+		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
+		acpi_device->flags.eject_pending = 0;
+	} else {
+		/* event originated from user */
+		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
+		(void) acpi_evaluate_hotplug_ost(ej_event->handle,
+			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	}
+
+	acpi_os_hotplug_execute(acpi_bus_hot_remove_device, (void *)ej_event);
 err:
 	return ret;
 }
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 8856102..fb9d793 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -143,7 +143,7 @@ void __init acpi_old_suspend_ordering(void)
 static int acpi_pm_freeze(void)
 {
 	acpi_disable_all_gpes();
-	acpi_os_wait_events_complete(NULL);
+	acpi_os_wait_events_complete();
 	acpi_ec_block_transactions();
 	return 0;
 }
@@ -716,8 +716,9 @@ int acpi_suspend(u32 acpi_state)
  *	@dev: device to examine; its driver model wakeup flags control
  *		whether it should be able to wake up the system
  *	@d_min_p: used to store the upper limit of allowed states range
- *	Return value: preferred power state of the device on success, -ENODEV on
- *		failure (ie. if there's no 'struct acpi_device' for @dev)
+ *	@d_max_in: specify the lowest allowed states
+ *	Return value: preferred power state of the device on success, -ENODEV
+ *	(ie. if there's no 'struct acpi_device' for @dev) or -EINVAL on failure
  *
  *	Find the lowest power (highest number) ACPI device power state that
  *	device @dev can be in while the system is in the sleep state represented
@@ -732,13 +733,15 @@ int acpi_suspend(u32 acpi_state)
  *	via @wake.
  */
 
-int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
+int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in)
 {
 	acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
 	struct acpi_device *adev;
 	char acpi_method[] = "_SxD";
 	unsigned long long d_min, d_max;
 
+	if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3)
+		return -EINVAL;
 	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
 		printk(KERN_DEBUG "ACPI handle has no context!\n");
 		return -ENODEV;
@@ -746,8 +749,10 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
 
 	acpi_method[2] = '0' + acpi_target_sleep_state;
 	/*
-	 * If the sleep state is S0, we will return D3, but if the device has
-	 * _S0W, we will use the value from _S0W
+	 * If the sleep state is S0, the lowest limit from ACPI is D3,
+	 * but if the device has _S0W, we will use the value from _S0W
+	 * as the lowest limit from ACPI.  Finally, we will constrain
+	 * the lowest limit with the specified one.
 	 */
 	d_min = ACPI_STATE_D0;
 	d_max = ACPI_STATE_D3;
@@ -791,8 +796,17 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
 		}
 	}
 
+	if (d_max_in < d_min)
+		return -EINVAL;
 	if (d_min_p)
 		*d_min_p = d_min;
+	/* constrain d_max with specified lowest limit (max number) */
+	if (d_max > d_max_in) {
+		for (d_max = d_max_in; d_max > d_min; d_max--) {
+			if (adev->power.states[d_max].flags.valid)
+				break;
+		}
+	}
 	return d_max;
 }
 #endif /* CONFIG_PM */
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 9f66181..240a244 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -173,7 +173,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp)
 {
 	int result = 0;
 
-	if (!strncmp(val, "enable", strlen("enable") - 1)) {
+	if (!strncmp(val, "enable", strlen("enable"))) {
 		result = acpi_debug_trace(trace_method_name, trace_debug_level,
 					  trace_debug_layer, 0);
 		if (result)
@@ -181,7 +181,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp)
 		goto exit;
 	}
 
-	if (!strncmp(val, "disable", strlen("disable") - 1)) {
+	if (!strncmp(val, "disable", strlen("disable"))) {
 		int name = 0;
 		result = acpi_debug_trace((char *)&name, trace_debug_level,
 					  trace_debug_layer, 0);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 7dbebea..2107d1b 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -845,7 +845,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 
 	if (tz->trips.passive.flags.valid)
 		tz->thermal_zone =
-			thermal_zone_device_register("acpitz", trips, tz,
+			thermal_zone_device_register("acpitz", trips, 0, tz,
 						     &acpi_thermal_zone_ops,
 						     tz->trips.passive.tc1,
 						     tz->trips.passive.tc2,
@@ -853,7 +853,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 						     tz->polling_frequency*100);
 	else
 		tz->thermal_zone =
-			thermal_zone_device_register("acpitz", trips, tz,
+			thermal_zone_device_register("acpitz", trips, 0, tz,
 						     &acpi_thermal_zone_ops,
 						     0, 0, 0,
 						     tz->polling_frequency*100);
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index adbbc1c..3e87c9c 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -412,3 +412,45 @@ out:
 	return status;
 }
 EXPORT_SYMBOL(acpi_get_physical_device_location);
+
+/**
+ * acpi_evaluate_hotplug_ost: Evaluate _OST for hotplug operations
+ * @handle: ACPI device handle
+ * @source_event: source event code
+ * @status_code: status code
+ * @status_buf: optional detailed information (NULL if none)
+ *
+ * Evaluate _OST for hotplug operations. All ACPI hotplug handlers
+ * must call this function when evaluating _OST for hotplug operations.
+ * When the platform does not support _OST, this function has no effect.
+ */
+acpi_status
+acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
+		u32 status_code, struct acpi_buffer *status_buf)
+{
+#ifdef ACPI_HOTPLUG_OST
+	union acpi_object params[3] = {
+		{.type = ACPI_TYPE_INTEGER,},
+		{.type = ACPI_TYPE_INTEGER,},
+		{.type = ACPI_TYPE_BUFFER,}
+	};
+	struct acpi_object_list arg_list = {3, params};
+	acpi_status status;
+
+	params[0].integer.value = source_event;
+	params[1].integer.value = status_code;
+	if (status_buf != NULL) {
+		params[2].buffer.pointer = status_buf->pointer;
+		params[2].buffer.length = status_buf->length;
+	} else {
+		params[2].buffer.pointer = NULL;
+		params[2].buffer.length = 0;
+	}
+
+	status = acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
+	return status;
+#else
+	return AE_OK;
+#endif
+}
+EXPORT_SYMBOL(acpi_evaluate_hotplug_ost);
diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c
index aa0b1f1..0b6f0b2 100644
--- a/drivers/amba/tegra-ahb.c
+++ b/drivers/amba/tegra-ahb.c
@@ -264,11 +264,6 @@ static int __devinit tegra_ahb_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int __devexit tegra_ahb_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-
 static const struct of_device_id tegra_ahb_of_match[] __devinitconst = {
 	{ .compatible = "nvidia,tegra30-ahb", },
 	{ .compatible = "nvidia,tegra20-ahb", },
@@ -277,7 +272,6 @@ static const struct of_device_id tegra_ahb_of_match[] __devinitconst = {
 
 static struct platform_driver tegra_ahb_driver = {
 	.probe = tegra_ahb_probe,
-	.remove = __devexit_p(tegra_ahb_remove),
 	.driver = {
 		.name = DRV_NAME,
 		.owner = THIS_MODULE,
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index cece3a4..da31691 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -80,6 +80,8 @@ const struct ata_port_operations ata_base_port_ops = {
 	.prereset		= ata_std_prereset,
 	.postreset		= ata_std_postreset,
 	.error_handler		= ata_std_error_handler,
+	.sched_eh		= ata_std_sched_eh,
+	.end_eh			= ata_std_end_eh,
 };
 
 const struct ata_port_operations sata_port_ops = {
@@ -5246,16 +5248,20 @@ bool ata_link_offline(struct ata_link *link)
 #ifdef CONFIG_PM
 static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 			       unsigned int action, unsigned int ehi_flags,
-			       int wait)
+			       int *async)
 {
 	struct ata_link *link;
 	unsigned long flags;
-	int rc;
+	int rc = 0;
 
 	/* Previous resume operation might still be in
 	 * progress.  Wait for PM_PENDING to clear.
 	 */
 	if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+		if (async) {
+			*async = -EAGAIN;
+			return 0;
+		}
 		ata_port_wait_eh(ap);
 		WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
 	}
@@ -5264,10 +5270,10 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 	spin_lock_irqsave(ap->lock, flags);
 
 	ap->pm_mesg = mesg;
-	if (wait) {
-		rc = 0;
+	if (async)
+		ap->pm_result = async;
+	else
 		ap->pm_result = &rc;
-	}
 
 	ap->pflags |= ATA_PFLAG_PM_PENDING;
 	ata_for_each_link(link, ap, HOST_FIRST) {
@@ -5280,7 +5286,7 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 	spin_unlock_irqrestore(ap->lock, flags);
 
 	/* wait and check result */
-	if (wait) {
+	if (!async) {
 		ata_port_wait_eh(ap);
 		WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
 	}
@@ -5290,9 +5296,8 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 
 #define to_ata_port(d) container_of(d, struct ata_port, tdev)
 
-static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
 {
-	struct ata_port *ap = to_ata_port(dev);
 	unsigned int ehi_flags = ATA_EHI_QUIET;
 	int rc;
 
@@ -5307,10 +5312,17 @@ static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
 	if (mesg.event == PM_EVENT_SUSPEND)
 		ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
 
-	rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, 1);
+	rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
 	return rc;
 }
 
+static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+{
+	struct ata_port *ap = to_ata_port(dev);
+
+	return __ata_port_suspend_common(ap, mesg, NULL);
+}
+
 static int ata_port_suspend(struct device *dev)
 {
 	if (pm_runtime_suspended(dev))
@@ -5335,16 +5347,22 @@ static int ata_port_poweroff(struct device *dev)
 	return ata_port_suspend_common(dev, PMSG_HIBERNATE);
 }
 
-static int ata_port_resume_common(struct device *dev)
+static int __ata_port_resume_common(struct ata_port *ap, int *async)
 {
-	struct ata_port *ap = to_ata_port(dev);
 	int rc;
 
 	rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
-		ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 1);
+		ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
 	return rc;
 }
 
+static int ata_port_resume_common(struct device *dev)
+{
+	struct ata_port *ap = to_ata_port(dev);
+
+	return __ata_port_resume_common(ap, NULL);
+}
+
 static int ata_port_resume(struct device *dev)
 {
 	int rc;
@@ -5377,6 +5395,24 @@ static const struct dev_pm_ops ata_port_pm_ops = {
 	.runtime_idle = ata_port_runtime_idle,
 };
 
+/* sas ports don't participate in pm runtime management of ata_ports,
+ * and need to resume ata devices at the domain level, not the per-port
+ * level. sas suspend/resume is async to allow parallel port recovery
+ * since sas has multiple ata_port instances per Scsi_Host.
+ */
+int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+{
+	return __ata_port_suspend_common(ap, PMSG_SUSPEND, async);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
+
+int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+{
+	return __ata_port_resume_common(ap, async);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
+
+
 /**
  *	ata_host_suspend - suspend host
  *	@host: host to suspend
@@ -6386,6 +6422,7 @@ static int __init ata_parse_force_one(char **cur,
 		{ "nohrst",	.lflags		= ATA_LFLAG_NO_HRST },
 		{ "nosrst",	.lflags		= ATA_LFLAG_NO_SRST },
 		{ "norst",	.lflags		= ATA_LFLAG_NO_HRST | ATA_LFLAG_NO_SRST },
+		{ "rstonce",	.lflags		= ATA_LFLAG_RST_ONCE },
 	};
 	char *start = *cur, *p = *cur;
 	char *id, *val, *endp;
@@ -6642,6 +6679,8 @@ struct ata_port_operations ata_dummy_port_ops = {
 	.qc_prep		= ata_noop_qc_prep,
 	.qc_issue		= ata_dummy_qc_issue,
 	.error_handler		= ata_dummy_error_handler,
+	.sched_eh		= ata_std_sched_eh,
+	.end_eh			= ata_std_end_eh,
 };
 
 const struct ata_port_info ata_dummy_port_info = {
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 6d53cf9..a5d2aba 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -793,12 +793,12 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)
 		ata_for_each_link(link, ap, HOST_FIRST)
 			memset(&link->eh_info, 0, sizeof(link->eh_info));
 
-		/* Clear host_eh_scheduled while holding ap->lock such
-		 * that if exception occurs after this point but
-		 * before EH completion, SCSI midlayer will
+		/* end eh (clear host_eh_scheduled) while holding
+		 * ap->lock such that if exception occurs after this
+		 * point but before EH completion, SCSI midlayer will
 		 * re-initiate EH.
 		 */
-		host->host_eh_scheduled = 0;
+		ap->ops->end_eh(ap);
 
 		spin_unlock_irqrestore(ap->lock, flags);
 		ata_eh_release(ap);
@@ -986,16 +986,13 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
 }
 
 /**
- *	ata_port_schedule_eh - schedule error handling without a qc
- *	@ap: ATA port to schedule EH for
- *
- *	Schedule error handling for @ap.  EH will kick in as soon as
- *	all commands are drained.
+ * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine
+ * @ap: ATA port to schedule EH for
  *
- *	LOCKING:
+ *	LOCKING: inherited from ata_port_schedule_eh
  *	spin_lock_irqsave(host lock)
  */
-void ata_port_schedule_eh(struct ata_port *ap)
+void ata_std_sched_eh(struct ata_port *ap)
 {
 	WARN_ON(!ap->ops->error_handler);
 
@@ -1007,6 +1004,44 @@ void ata_port_schedule_eh(struct ata_port *ap)
 
 	DPRINTK("port EH scheduled\n");
 }
+EXPORT_SYMBOL_GPL(ata_std_sched_eh);
+
+/**
+ * ata_std_end_eh - non-libsas ata_ports complete eh with this common routine
+ * @ap: ATA port to end EH for
+ *
+ * In the libata object model there is a 1:1 mapping of ata_port to
+ * shost, so host fields can be directly manipulated under ap->lock, in
+ * the libsas case we need to hold a lock at the ha->level to coordinate
+ * these events.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+void ata_std_end_eh(struct ata_port *ap)
+{
+	struct Scsi_Host *host = ap->scsi_host;
+
+	host->host_eh_scheduled = 0;
+}
+EXPORT_SYMBOL(ata_std_end_eh);
+
+
+/**
+ *	ata_port_schedule_eh - schedule error handling without a qc
+ *	@ap: ATA port to schedule EH for
+ *
+ *	Schedule error handling for @ap.  EH will kick in as soon as
+ *	all commands are drained.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+void ata_port_schedule_eh(struct ata_port *ap)
+{
+	/* see: ata_std_sched_eh, unless you know better */
+	ap->ops->sched_eh(ap);
+}
 
 static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
 {
@@ -2588,6 +2623,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
 	 */
 	while (ata_eh_reset_timeouts[max_tries] != ULONG_MAX)
 		max_tries++;
+	if (link->flags & ATA_LFLAG_RST_ONCE)
+		max_tries = 1;
 	if (link->flags & ATA_LFLAG_NO_HRST)
 		hardreset = NULL;
 	if (link->flags & ATA_LFLAG_NO_SRST)
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index ac6a5be..bfaa5cb 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -184,10 +184,8 @@
 struct arasan_cf_dev {
 	/* pointer to ata_host structure */
 	struct ata_host *host;
-	/* clk structure, only if HAVE_CLK is defined */
-#ifdef CONFIG_HAVE_CLK
+	/* clk structure */
 	struct clk *clk;
-#endif
 
 	/* physical base address of controller */
 	dma_addr_t pbase;
@@ -312,13 +310,11 @@ static int cf_init(struct arasan_cf_dev *acdev)
 	unsigned long flags;
 	int ret = 0;
 
-#ifdef CONFIG_HAVE_CLK
 	ret = clk_enable(acdev->clk);
 	if (ret) {
 		dev_dbg(acdev->host->dev, "clock enable failed");
 		return ret;
 	}
-#endif
 
 	spin_lock_irqsave(&acdev->host->lock, flags);
 	/* configure CF interface clock */
@@ -344,9 +340,7 @@ static void cf_exit(struct arasan_cf_dev *acdev)
 	writel(readl(acdev->vbase + OP_MODE) & ~CFHOST_ENB,
 			acdev->vbase + OP_MODE);
 	spin_unlock_irqrestore(&acdev->host->lock, flags);
-#ifdef CONFIG_HAVE_CLK
 	clk_disable(acdev->clk);
-#endif
 }
 
 static void dma_callback(void *dev)
@@ -828,13 +822,11 @@ static int __devinit arasan_cf_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-#ifdef CONFIG_HAVE_CLK
 	acdev->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(acdev->clk)) {
 		dev_warn(&pdev->dev, "Clock not found\n");
 		return PTR_ERR(acdev->clk);
 	}
-#endif
 
 	/* allocate host */
 	host = ata_host_alloc(&pdev->dev, 1);
@@ -899,9 +891,7 @@ static int __devinit arasan_cf_probe(struct platform_device *pdev)
 			&arasan_cf_sht);
 
 free_clk:
-#ifdef CONFIG_HAVE_CLK
 	clk_put(acdev->clk);
-#endif
 	return ret;
 }
 
@@ -912,9 +902,7 @@ static int __devexit arasan_cf_remove(struct platform_device *pdev)
 
 	ata_host_detach(host);
 	cf_exit(acdev);
-#ifdef CONFIG_HAVE_CLK
 	clk_put(acdev->clk);
-#endif
 
 	return 0;
 }
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 346be8b..846d12b 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1754,25 +1754,25 @@ int device_move(struct device *dev, struct device *new_parent,
 		set_dev_node(dev, dev_to_node(new_parent));
 	}
 
-	if (!dev->class)
-		goto out_put;
-	error = device_move_class_links(dev, old_parent, new_parent);
-	if (error) {
-		/* We ignore errors on cleanup since we're hosed anyway... */
-		device_move_class_links(dev, new_parent, old_parent);
-		if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
-			if (new_parent)
-				klist_remove(&dev->p->knode_parent);
-			dev->parent = old_parent;
-			if (old_parent) {
-				klist_add_tail(&dev->p->knode_parent,
-					       &old_parent->p->klist_children);
-				set_dev_node(dev, dev_to_node(old_parent));
+	if (dev->class) {
+		error = device_move_class_links(dev, old_parent, new_parent);
+		if (error) {
+			/* We ignore errors on cleanup since we're hosed anyway... */
+			device_move_class_links(dev, new_parent, old_parent);
+			if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
+				if (new_parent)
+					klist_remove(&dev->p->knode_parent);
+				dev->parent = old_parent;
+				if (old_parent) {
+					klist_add_tail(&dev->p->knode_parent,
+						       &old_parent->p->klist_children);
+					set_dev_node(dev, dev_to_node(old_parent));
+				}
 			}
+			cleanup_glue_dir(dev, new_parent_kobj);
+			put_device(new_parent);
+			goto out;
 		}
-		cleanup_glue_dir(dev, new_parent_kobj);
-		put_device(new_parent);
-		goto out;
 	}
 	switch (dpm_order) {
 	case DPM_ORDER_NONE:
@@ -1787,7 +1787,7 @@ int device_move(struct device *dev, struct device *new_parent,
 		device_pm_move_last(dev);
 		break;
 	}
-out_put:
+
 	put_device(old_parent);
 out:
 	device_pm_unlock();
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index dcb8a6e..6cd2c6c 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -283,6 +283,7 @@ probe_failed:
 	devres_release_all(dev);
 	driver_sysfs_remove(dev);
 	dev->driver = NULL;
+	dev_set_drvdata(dev, NULL);
 
 	if (ret == -EPROBE_DEFER) {
 		/* Driver requested deferred probing */
@@ -487,6 +488,7 @@ static void __device_release_driver(struct device *dev)
 			drv->remove(dev);
 		devres_release_all(dev);
 		dev->driver = NULL;
+		dev_set_drvdata(dev, NULL);
 		klist_remove(&dev->p->knode_driver);
 		if (dev->bus)
 			blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 765c3a2..d91a3a0 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -227,33 +227,24 @@ static int handle_create(const char *nodename, umode_t mode, struct device *dev)
 
 static int dev_rmdir(const char *name)
 {
-	struct nameidata nd;
+	struct path parent;
 	struct dentry *dentry;
 	int err;
 
-	err = kern_path_parent(name, &nd);
-	if (err)
-		return err;
-
-	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
-	dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
-	if (!IS_ERR(dentry)) {
-		if (dentry->d_inode) {
-			if (dentry->d_inode->i_private == &thread)
-				err = vfs_rmdir(nd.path.dentry->d_inode,
-						dentry);
-			else
-				err = -EPERM;
-		} else {
-			err = -ENOENT;
-		}
-		dput(dentry);
+	dentry = kern_path_locked(name, &parent);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+	if (dentry->d_inode) {
+		if (dentry->d_inode->i_private == &thread)
+			err = vfs_rmdir(parent.dentry->d_inode, dentry);
+		else
+			err = -EPERM;
 	} else {
-		err = PTR_ERR(dentry);
+		err = -ENOENT;
 	}
-
-	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-	path_put(&nd.path);
+	dput(dentry);
+	mutex_unlock(&parent.dentry->d_inode->i_mutex);
+	path_put(&parent);
 	return err;
 }
 
@@ -305,50 +296,43 @@ static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *sta
 
 static int handle_remove(const char *nodename, struct device *dev)
 {
-	struct nameidata nd;
+	struct path parent;
 	struct dentry *dentry;
-	struct kstat stat;
 	int deleted = 1;
 	int err;
 
-	err = kern_path_parent(nodename, &nd);
-	if (err)
-		return err;
+	dentry = kern_path_locked(nodename, &parent);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
 
-	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
-	dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
-	if (!IS_ERR(dentry)) {
-		if (dentry->d_inode) {
-			err = vfs_getattr(nd.path.mnt, dentry, &stat);
-			if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
-				struct iattr newattrs;
-				/*
-				 * before unlinking this node, reset permissions
-				 * of possible references like hardlinks
-				 */
-				newattrs.ia_uid = 0;
-				newattrs.ia_gid = 0;
-				newattrs.ia_mode = stat.mode & ~0777;
-				newattrs.ia_valid =
-					ATTR_UID|ATTR_GID|ATTR_MODE;
-				mutex_lock(&dentry->d_inode->i_mutex);
-				notify_change(dentry, &newattrs);
-				mutex_unlock(&dentry->d_inode->i_mutex);
-				err = vfs_unlink(nd.path.dentry->d_inode,
-						 dentry);
-				if (!err || err == -ENOENT)
-					deleted = 1;
-			}
-		} else {
-			err = -ENOENT;
+	if (dentry->d_inode) {
+		struct kstat stat;
+		err = vfs_getattr(parent.mnt, dentry, &stat);
+		if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
+			struct iattr newattrs;
+			/*
+			 * before unlinking this node, reset permissions
+			 * of possible references like hardlinks
+			 */
+			newattrs.ia_uid = 0;
+			newattrs.ia_gid = 0;
+			newattrs.ia_mode = stat.mode & ~0777;
+			newattrs.ia_valid =
+				ATTR_UID|ATTR_GID|ATTR_MODE;
+			mutex_lock(&dentry->d_inode->i_mutex);
+			notify_change(dentry, &newattrs);
+			mutex_unlock(&dentry->d_inode->i_mutex);
+			err = vfs_unlink(parent.dentry->d_inode, dentry);
+			if (!err || err == -ENOENT)
+				deleted = 1;
 		}
-		dput(dentry);
 	} else {
-		err = PTR_ERR(dentry);
+		err = -ENOENT;
 	}
-	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+	dput(dentry);
+	mutex_unlock(&parent.dentry->d_inode->i_mutex);
 
-	path_put(&nd.path);
+	path_put(&parent);
 	if (deleted && strchr(nodename, '/'))
 		delete_path(nodename);
 	return err;
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 24e88fe..c30f3e1 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -493,6 +493,7 @@ EXPORT_SYMBOL_GPL(dma_buf_vmap);
 /**
  * dma_buf_vunmap - Unmap a vmap obtained by dma_buf_vmap.
  * @dmabuf:	[in]	buffer to vunmap
+ * @vaddr:	[in]	vmap to vunmap
  */
 void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
 {
diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c
index 1b85949..560a717 100644
--- a/drivers/base/dma-coherent.c
+++ b/drivers/base/dma-coherent.c
@@ -186,6 +186,7 @@ EXPORT_SYMBOL(dma_release_from_coherent);
  * @vma:	vm_area for the userspace memory
  * @vaddr:	cpu address returned by dma_alloc_from_coherent
  * @size:	size of the memory buffer allocated by dma_alloc_from_coherent
+ * @ret:	result from remap_pfn_range()
  *
  * This checks whether the memory was allocated from the per-device
  * coherent memory pool and if so, maps that memory to the provided vma.
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
index 6f3676f..3fbedc7 100644
--- a/drivers/base/dma-mapping.c
+++ b/drivers/base/dma-mapping.c
@@ -10,6 +10,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
 #include <linux/gfp.h>
+#include <asm-generic/dma-coherent.h>
 
 /*
  * Managed DMA API
@@ -217,4 +218,52 @@ void dmam_release_declared_memory(struct device *dev)
 }
 EXPORT_SYMBOL(dmam_release_declared_memory);
 
+/*
+ * Create scatter-list for the already allocated DMA buffer.
+ */
+int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
+		 void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	struct page *page = virt_to_page(cpu_addr);
+	int ret;
+
+	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
+	if (unlikely(ret))
+		return ret;
+
+	sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
+	return 0;
+}
+EXPORT_SYMBOL(dma_common_get_sgtable);
+
 #endif
+
+/*
+ * Create userspace mapping for the DMA-coherent memory.
+ */
+int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+		    void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+	int ret = -ENXIO;
+#ifdef CONFIG_MMU
+	unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+	unsigned long off = vma->vm_pgoff;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+		return ret;
+
+	if (off < count && user_count <= (count - off)) {
+		ret = remap_pfn_range(vma, vma->vm_start,
+				      pfn + off,
+				      user_count << PAGE_SHIFT,
+				      vma->vm_page_prot);
+	}
+#endif	/* CONFIG_MMU */
+
+	return ret;
+}
+EXPORT_SYMBOL(dma_common_mmap);
diff --git a/drivers/base/node.c b/drivers/base/node.c
index af1a177..ef51157 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -169,7 +169,7 @@ static ssize_t node_read_numastat(struct device *dev,
 		       node_page_state(dev->id, NUMA_HIT),
 		       node_page_state(dev->id, NUMA_MISS),
 		       node_page_state(dev->id, NUMA_FOREIGN),
-		       node_page_state(dev->id, NUMA_INTERLEAVE_HIT),
+		       0UL,
 		       node_page_state(dev->id, NUMA_LOCAL),
 		       node_page_state(dev->id, NUMA_OTHER));
 }
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 83aa694..25cafe1 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -139,6 +139,19 @@ static void genpd_set_active(struct generic_pm_domain *genpd)
 		genpd->status = GPD_STATE_ACTIVE;
 }
 
+static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd)
+{
+	s64 usecs64;
+
+	if (!genpd->cpu_data)
+		return;
+
+	usecs64 = genpd->power_on_latency_ns;
+	do_div(usecs64, NSEC_PER_USEC);
+	usecs64 += genpd->cpu_data->saved_exit_latency;
+	genpd->cpu_data->idle_state->exit_latency = usecs64;
+}
+
 /**
  * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
@@ -176,6 +189,13 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd)
 		return 0;
 	}
 
+	if (genpd->cpu_data) {
+		cpuidle_pause_and_lock();
+		genpd->cpu_data->idle_state->disable = true;
+		cpuidle_resume_and_unlock();
+		goto out;
+	}
+
 	/*
 	 * The list is guaranteed not to change while the loop below is being
 	 * executed, unless one of the masters' .power_on() callbacks fiddles
@@ -215,6 +235,7 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd)
 		if (elapsed_ns > genpd->power_on_latency_ns) {
 			genpd->power_on_latency_ns = elapsed_ns;
 			genpd->max_off_time_changed = true;
+			genpd_recalc_cpu_exit_latency(genpd);
 			if (genpd->name)
 				pr_warning("%s: Power-on latency exceeded, "
 					"new value %lld ns\n", genpd->name,
@@ -222,6 +243,7 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd)
 		}
 	}
 
+ out:
 	genpd_set_active(genpd);
 
 	return 0;
@@ -339,19 +361,16 @@ static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
 {
 	struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
 	struct device *dev = pdd->dev;
+	bool need_restore = gpd_data->need_restore;
 
-	if (!gpd_data->need_restore)
-		return;
-
+	gpd_data->need_restore = false;
 	mutex_unlock(&genpd->lock);
 
 	genpd_start_dev(genpd, dev);
-	genpd_restore_dev(genpd, dev);
-	genpd_stop_dev(genpd, dev);
+	if (need_restore)
+		genpd_restore_dev(genpd, dev);
 
 	mutex_lock(&genpd->lock);
-
-	gpd_data->need_restore = false;
 }
 
 /**
@@ -458,6 +477,21 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
 		}
 	}
 
+	if (genpd->cpu_data) {
+		/*
+		 * If cpu_data is set, cpuidle should turn the domain off when
+		 * the CPU in it is idle.  In that case we don't decrement the
+		 * subdomain counts of the master domains, so that power is not
+		 * removed from the current domain prematurely as a result of
+		 * cutting off the masters' power.
+		 */
+		genpd->status = GPD_STATE_POWER_OFF;
+		cpuidle_pause_and_lock();
+		genpd->cpu_data->idle_state->disable = false;
+		cpuidle_resume_and_unlock();
+		goto out;
+	}
+
 	if (genpd->power_off) {
 		ktime_t time_start;
 		s64 elapsed_ns;
@@ -595,7 +629,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
 
 	/* If power.irq_safe, the PM domain is never powered off. */
 	if (dev->power.irq_safe)
-		goto out;
+		return genpd_start_dev(genpd, dev);
 
 	mutex_lock(&genpd->lock);
 	ret = __pm_genpd_poweron(genpd);
@@ -628,9 +662,6 @@ static int pm_genpd_runtime_resume(struct device *dev)
 	wake_up_all(&genpd->status_wait_queue);
 	mutex_unlock(&genpd->lock);
 
- out:
-	genpd_start_dev(genpd, dev);
-
 	return 0;
 }
 
@@ -1606,6 +1637,86 @@ int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
 }
 EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks);
 
+int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
+{
+	struct cpuidle_driver *cpuidle_drv;
+	struct gpd_cpu_data *cpu_data;
+	struct cpuidle_state *idle_state;
+	int ret = 0;
+
+	if (IS_ERR_OR_NULL(genpd) || state < 0)
+		return -EINVAL;
+
+	genpd_acquire_lock(genpd);
+
+	if (genpd->cpu_data) {
+		ret = -EEXIST;
+		goto out;
+	}
+	cpu_data = kzalloc(sizeof(*cpu_data), GFP_KERNEL);
+	if (!cpu_data) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	cpuidle_drv = cpuidle_driver_ref();
+	if (!cpuidle_drv) {
+		ret = -ENODEV;
+		goto out;
+	}
+	if (cpuidle_drv->state_count <= state) {
+		ret = -EINVAL;
+		goto err;
+	}
+	idle_state = &cpuidle_drv->states[state];
+	if (!idle_state->disable) {
+		ret = -EAGAIN;
+		goto err;
+	}
+	cpu_data->idle_state = idle_state;
+	cpu_data->saved_exit_latency = idle_state->exit_latency;
+	genpd->cpu_data = cpu_data;
+	genpd_recalc_cpu_exit_latency(genpd);
+
+ out:
+	genpd_release_lock(genpd);
+	return ret;
+
+ err:
+	cpuidle_driver_unref();
+	goto out;
+}
+
+int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
+{
+	struct gpd_cpu_data *cpu_data;
+	struct cpuidle_state *idle_state;
+	int ret = 0;
+
+	if (IS_ERR_OR_NULL(genpd))
+		return -EINVAL;
+
+	genpd_acquire_lock(genpd);
+
+	cpu_data = genpd->cpu_data;
+	if (!cpu_data) {
+		ret = -ENODEV;
+		goto out;
+	}
+	idle_state = cpu_data->idle_state;
+	if (!idle_state->disable) {
+		ret = -EAGAIN;
+		goto out;
+	}
+	idle_state->exit_latency = cpu_data->saved_exit_latency;
+	cpuidle_driver_unref();
+	genpd->cpu_data = NULL;
+	kfree(cpu_data);
+
+ out:
+	genpd_release_lock(genpd);
+	return ret;
+}
+
 /* Default device callbacks for generic PM domains. */
 
 /**
@@ -1615,16 +1726,24 @@ EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks);
 static int pm_genpd_default_save_state(struct device *dev)
 {
 	int (*cb)(struct device *__dev);
-	struct device_driver *drv = dev->driver;
 
 	cb = dev_gpd_data(dev)->ops.save_state;
 	if (cb)
 		return cb(dev);
 
-	if (drv && drv->pm && drv->pm->runtime_suspend)
-		return drv->pm->runtime_suspend(dev);
+	if (dev->type && dev->type->pm)
+		cb = dev->type->pm->runtime_suspend;
+	else if (dev->class && dev->class->pm)
+		cb = dev->class->pm->runtime_suspend;
+	else if (dev->bus && dev->bus->pm)
+		cb = dev->bus->pm->runtime_suspend;
+	else
+		cb = NULL;
 
-	return 0;
+	if (!cb && dev->driver && dev->driver->pm)
+		cb = dev->driver->pm->runtime_suspend;
+
+	return cb ? cb(dev) : 0;
 }
 
 /**
@@ -1634,16 +1753,24 @@ static int pm_genpd_default_save_state(struct device *dev)
 static int pm_genpd_default_restore_state(struct device *dev)
 {
 	int (*cb)(struct device *__dev);
-	struct device_driver *drv = dev->driver;
 
 	cb = dev_gpd_data(dev)->ops.restore_state;
 	if (cb)
 		return cb(dev);
 
-	if (drv && drv->pm && drv->pm->runtime_resume)
-		return drv->pm->runtime_resume(dev);
+	if (dev->type && dev->type->pm)
+		cb = dev->type->pm->runtime_resume;
+	else if (dev->class && dev->class->pm)
+		cb = dev->class->pm->runtime_resume;
+	else if (dev->bus && dev->bus->pm)
+		cb = dev->bus->pm->runtime_resume;
+	else
+		cb = NULL;
 
-	return 0;
+	if (!cb && dev->driver && dev->driver->pm)
+		cb = dev->driver->pm->runtime_resume;
+
+	return cb ? cb(dev) : 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index e0fb5b0..df5f41d 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -166,7 +166,7 @@ static ktime_t initcall_debug_start(struct device *dev)
 {
 	ktime_t calltime = ktime_set(0, 0);
 
-	if (initcall_debug) {
+	if (pm_print_times_enabled) {
 		pr_info("calling  %s+ @ %i, parent: %s\n",
 			dev_name(dev), task_pid_nr(current),
 			dev->parent ? dev_name(dev->parent) : "none");
@@ -181,7 +181,7 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime,
 {
 	ktime_t delta, rettime;
 
-	if (initcall_debug) {
+	if (pm_print_times_enabled) {
 		rettime = ktime_get();
 		delta = ktime_sub(rettime, calltime);
 		pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
@@ -1031,7 +1031,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
 	dpm_wait_for_children(dev, async);
 
 	if (async_error)
-		return 0;
+		goto Complete;
 
 	pm_runtime_get_noresume(dev);
 	if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
@@ -1040,7 +1040,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
 	if (pm_wakeup_pending()) {
 		pm_runtime_put_sync(dev);
 		async_error = -EBUSY;
-		return 0;
+		goto Complete;
 	}
 
 	device_lock(dev);
@@ -1097,6 +1097,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
 	}
 
 	device_unlock(dev);
+
+ Complete:
 	complete_all(&dev->power.completion);
 
 	if (error) {
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index b986b86..80f9ab9 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -95,6 +95,9 @@ struct regmap {
 
 	/* if set, converts bulk rw to single rw */
 	bool use_single_rw;
+
+	struct rb_root range_tree;
+	void *selector_work_buf;	/* Scratch buffer used for selector */
 };
 
 struct regcache_ops {
@@ -115,6 +118,20 @@ bool regmap_precious(struct regmap *map, unsigned int reg);
 int _regmap_write(struct regmap *map, unsigned int reg,
 		  unsigned int val);
 
+struct regmap_range_node {
+	struct rb_node node;
+
+	unsigned int range_min;
+	unsigned int range_max;
+
+	unsigned int selector_reg;
+	unsigned int selector_mask;
+	int selector_shift;
+
+	unsigned int window_start;
+	unsigned int window_len;
+};
+
 #ifdef CONFIG_DEBUG_FS
 extern void regmap_debugfs_initcall(void);
 extern void regmap_debugfs_init(struct regmap *map, const char *name);
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 4fac4b9..a897346 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -24,14 +24,18 @@ struct regmap_irq_chip_data {
 	struct mutex lock;
 
 	struct regmap *map;
-	struct regmap_irq_chip *chip;
+	const struct regmap_irq_chip *chip;
 
 	int irq_base;
 	struct irq_domain *domain;
 
+	int irq;
+	int wake_count;
+
 	unsigned int *status_buf;
 	unsigned int *mask_buf;
 	unsigned int *mask_buf_def;
+	unsigned int *wake_buf;
 
 	unsigned int irq_reg_stride;
 };
@@ -71,6 +75,16 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
 				d->chip->mask_base + (i * map->reg_stride));
 	}
 
+	/* If we've changed our wakeup count propagate it to the parent */
+	if (d->wake_count < 0)
+		for (i = d->wake_count; i < 0; i++)
+			irq_set_irq_wake(d->irq, 0);
+	else if (d->wake_count > 0)
+		for (i = 0; i < d->wake_count; i++)
+			irq_set_irq_wake(d->irq, 1);
+
+	d->wake_count = 0;
+
 	mutex_unlock(&d->lock);
 }
 
@@ -92,18 +106,41 @@ static void regmap_irq_disable(struct irq_data *data)
 	d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
 }
 
+static int regmap_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+	struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+	struct regmap *map = d->map;
+	const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
+
+	if (!d->chip->wake_base)
+		return -EINVAL;
+
+	if (on) {
+		d->wake_buf[irq_data->reg_offset / map->reg_stride]
+			&= ~irq_data->mask;
+		d->wake_count++;
+	} else {
+		d->wake_buf[irq_data->reg_offset / map->reg_stride]
+			|= irq_data->mask;
+		d->wake_count--;
+	}
+
+	return 0;
+}
+
 static struct irq_chip regmap_irq_chip = {
 	.name			= "regmap",
 	.irq_bus_lock		= regmap_irq_lock,
 	.irq_bus_sync_unlock	= regmap_irq_sync_unlock,
 	.irq_disable		= regmap_irq_disable,
 	.irq_enable		= regmap_irq_enable,
+	.irq_set_wake		= regmap_irq_set_wake,
 };
 
 static irqreturn_t regmap_irq_thread(int irq, void *d)
 {
 	struct regmap_irq_chip_data *data = d;
-	struct regmap_irq_chip *chip = data->chip;
+	const struct regmap_irq_chip *chip = data->chip;
 	struct regmap *map = data->map;
 	int ret, i;
 	bool handled = false;
@@ -195,7 +232,7 @@ static struct irq_domain_ops regmap_domain_ops = {
  * register values used by the IRQ controller over suspend and resume.
  */
 int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
-			int irq_base, struct regmap_irq_chip *chip,
+			int irq_base, const struct regmap_irq_chip *chip,
 			struct regmap_irq_chip_data **data)
 {
 	struct regmap_irq_chip_data *d;
@@ -240,6 +277,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 	if (!d->mask_buf_def)
 		goto err_alloc;
 
+	if (chip->wake_base) {
+		d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
+				      GFP_KERNEL);
+		if (!d->wake_buf)
+			goto err_alloc;
+	}
+
+	d->irq = irq;
 	d->map = map;
 	d->chip = chip;
 	d->irq_base = irq_base;
@@ -294,6 +339,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 err_domain:
 	/* Should really dispose of the domain but... */
 err_alloc:
+	kfree(d->wake_buf);
 	kfree(d->mask_buf_def);
 	kfree(d->mask_buf);
 	kfree(d->status_buf);
@@ -315,6 +361,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
 
 	free_irq(irq, d);
 	/* We should unmap the domain but... */
+	kfree(d->wake_buf);
 	kfree(d->mask_buf_def);
 	kfree(d->mask_buf);
 	kfree(d->status_buf);
@@ -346,6 +393,10 @@ EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base);
  */
 int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq)
 {
+	/* Handle holes in the IRQ list */
+	if (!data->chip->irqs[irq].mask)
+		return -EINVAL;
+
 	return irq_create_mapping(data->domain, irq);
 }
 EXPORT_SYMBOL_GPL(regmap_irq_get_virq);
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index febd6de..d64a7fc 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -37,7 +37,7 @@ static int regmap_mmio_gather_write(void *context,
 
 	BUG_ON(reg_size != 4);
 
-	offset = be32_to_cpup(reg);
+	offset = *(u32 *)reg;
 
 	while (val_size) {
 		switch (ctx->val_bytes) {
@@ -45,14 +45,14 @@ static int regmap_mmio_gather_write(void *context,
 			writeb(*(u8 *)val, ctx->regs + offset);
 			break;
 		case 2:
-			writew(be16_to_cpup(val), ctx->regs + offset);
+			writew(*(u16 *)val, ctx->regs + offset);
 			break;
 		case 4:
-			writel(be32_to_cpup(val), ctx->regs + offset);
+			writel(*(u32 *)val, ctx->regs + offset);
 			break;
 #ifdef CONFIG_64BIT
 		case 8:
-			writeq(be64_to_cpup(val), ctx->regs + offset);
+			writeq(*(u64 *)val, ctx->regs + offset);
 			break;
 #endif
 		default:
@@ -83,7 +83,7 @@ static int regmap_mmio_read(void *context,
 
 	BUG_ON(reg_size != 4);
 
-	offset = be32_to_cpup(reg);
+	offset = *(u32 *)reg;
 
 	while (val_size) {
 		switch (ctx->val_bytes) {
@@ -91,14 +91,14 @@ static int regmap_mmio_read(void *context,
 			*(u8 *)val = readb(ctx->regs + offset);
 			break;
 		case 2:
-			*(u16 *)val = cpu_to_be16(readw(ctx->regs + offset));
+			*(u16 *)val = readw(ctx->regs + offset);
 			break;
 		case 4:
-			*(u32 *)val = cpu_to_be32(readl(ctx->regs + offset));
+			*(u32 *)val = readl(ctx->regs + offset);
 			break;
 #ifdef CONFIG_64BIT
 		case 8:
-			*(u64 *)val = cpu_to_be32(readq(ctx->regs + offset));
+			*(u64 *)val = readq(ctx->regs + offset);
 			break;
 #endif
 		default:
@@ -124,9 +124,11 @@ static struct regmap_bus regmap_mmio = {
 	.gather_write = regmap_mmio_gather_write,
 	.read = regmap_mmio_read,
 	.free_context = regmap_mmio_free_context,
+	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
 };
 
-struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
+static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
 					const struct regmap_config *config)
 {
 	struct regmap_mmio_context *ctx;
@@ -162,6 +164,14 @@ struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
 	if (config->reg_stride < min_stride)
 		return ERR_PTR(-EINVAL);
 
+	switch (config->reg_format_endian) {
+	case REGMAP_ENDIAN_DEFAULT:
+	case REGMAP_ENDIAN_NATIVE:
+		break;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
 	ctx = kzalloc(GFP_KERNEL, sizeof(*ctx));
 	if (!ctx)
 		return ERR_PTR(-ENOMEM);
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index c89aa01..13fc70b 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -15,12 +15,17 @@
 #include <linux/export.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
+#include <linux/rbtree.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/regmap.h>
 
 #include "internal.h"
 
+static int _regmap_update_bits(struct regmap *map, unsigned int reg,
+			       unsigned int mask, unsigned int val,
+			       bool *change);
+
 bool regmap_writeable(struct regmap *map, unsigned int reg)
 {
 	if (map->max_register && reg > map->max_register)
@@ -119,13 +124,19 @@ static void regmap_format_8(void *buf, unsigned int val, unsigned int shift)
 	b[0] = val << shift;
 }
 
-static void regmap_format_16(void *buf, unsigned int val, unsigned int shift)
+static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift)
 {
 	__be16 *b = buf;
 
 	b[0] = cpu_to_be16(val << shift);
 }
 
+static void regmap_format_16_native(void *buf, unsigned int val,
+				    unsigned int shift)
+{
+	*(u16 *)buf = val << shift;
+}
+
 static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
 {
 	u8 *b = buf;
@@ -137,13 +148,19 @@ static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
 	b[2] = val;
 }
 
-static void regmap_format_32(void *buf, unsigned int val, unsigned int shift)
+static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift)
 {
 	__be32 *b = buf;
 
 	b[0] = cpu_to_be32(val << shift);
 }
 
+static void regmap_format_32_native(void *buf, unsigned int val,
+				    unsigned int shift)
+{
+	*(u32 *)buf = val << shift;
+}
+
 static unsigned int regmap_parse_8(void *buf)
 {
 	u8 *b = buf;
@@ -151,7 +168,7 @@ static unsigned int regmap_parse_8(void *buf)
 	return b[0];
 }
 
-static unsigned int regmap_parse_16(void *buf)
+static unsigned int regmap_parse_16_be(void *buf)
 {
 	__be16 *b = buf;
 
@@ -160,6 +177,11 @@ static unsigned int regmap_parse_16(void *buf)
 	return b[0];
 }
 
+static unsigned int regmap_parse_16_native(void *buf)
+{
+	return *(u16 *)buf;
+}
+
 static unsigned int regmap_parse_24(void *buf)
 {
 	u8 *b = buf;
@@ -170,7 +192,7 @@ static unsigned int regmap_parse_24(void *buf)
 	return ret;
 }
 
-static unsigned int regmap_parse_32(void *buf)
+static unsigned int regmap_parse_32_be(void *buf)
 {
 	__be32 *b = buf;
 
@@ -179,6 +201,11 @@ static unsigned int regmap_parse_32(void *buf)
 	return b[0];
 }
 
+static unsigned int regmap_parse_32_native(void *buf)
+{
+	return *(u32 *)buf;
+}
+
 static void regmap_lock_mutex(struct regmap *map)
 {
 	mutex_lock(&map->mutex);
@@ -208,6 +235,67 @@ static void dev_get_regmap_release(struct device *dev, void *res)
 	 */
 }
 
+static bool _regmap_range_add(struct regmap *map,
+			      struct regmap_range_node *data)
+{
+	struct rb_root *root = &map->range_tree;
+	struct rb_node **new = &(root->rb_node), *parent = NULL;
+
+	while (*new) {
+		struct regmap_range_node *this =
+			container_of(*new, struct regmap_range_node, node);
+
+		parent = *new;
+		if (data->range_max < this->range_min)
+			new = &((*new)->rb_left);
+		else if (data->range_min > this->range_max)
+			new = &((*new)->rb_right);
+		else
+			return false;
+	}
+
+	rb_link_node(&data->node, parent, new);
+	rb_insert_color(&data->node, root);
+
+	return true;
+}
+
+static struct regmap_range_node *_regmap_range_lookup(struct regmap *map,
+						      unsigned int reg)
+{
+	struct rb_node *node = map->range_tree.rb_node;
+
+	while (node) {
+		struct regmap_range_node *this =
+			container_of(node, struct regmap_range_node, node);
+
+		if (reg < this->range_min)
+			node = node->rb_left;
+		else if (reg > this->range_max)
+			node = node->rb_right;
+		else
+			return this;
+	}
+
+	return NULL;
+}
+
+static void regmap_range_exit(struct regmap *map)
+{
+	struct rb_node *next;
+	struct regmap_range_node *range_node;
+
+	next = rb_first(&map->range_tree);
+	while (next) {
+		range_node = rb_entry(next, struct regmap_range_node, node);
+		next = rb_next(&range_node->node);
+		rb_erase(&range_node->node, &map->range_tree);
+		kfree(range_node);
+	}
+
+	kfree(map->selector_work_buf);
+}
+
 /**
  * regmap_init(): Initialise register map
  *
@@ -227,6 +315,8 @@ struct regmap *regmap_init(struct device *dev,
 {
 	struct regmap *map, **m;
 	int ret = -EINVAL;
+	enum regmap_endian reg_endian, val_endian;
+	int i, j;
 
 	if (!bus || !config)
 		goto err;
@@ -275,6 +365,18 @@ struct regmap *regmap_init(struct device *dev,
 		map->read_flag_mask = bus->read_flag_mask;
 	}
 
+	reg_endian = config->reg_format_endian;
+	if (reg_endian == REGMAP_ENDIAN_DEFAULT)
+		reg_endian = bus->reg_format_endian_default;
+	if (reg_endian == REGMAP_ENDIAN_DEFAULT)
+		reg_endian = REGMAP_ENDIAN_BIG;
+
+	val_endian = config->val_format_endian;
+	if (val_endian == REGMAP_ENDIAN_DEFAULT)
+		val_endian = bus->val_format_endian_default;
+	if (val_endian == REGMAP_ENDIAN_DEFAULT)
+		val_endian = REGMAP_ENDIAN_BIG;
+
 	switch (config->reg_bits + map->reg_shift) {
 	case 2:
 		switch (config->val_bits) {
@@ -321,11 +423,29 @@ struct regmap *regmap_init(struct device *dev,
 		break;
 
 	case 16:
-		map->format.format_reg = regmap_format_16;
+		switch (reg_endian) {
+		case REGMAP_ENDIAN_BIG:
+			map->format.format_reg = regmap_format_16_be;
+			break;
+		case REGMAP_ENDIAN_NATIVE:
+			map->format.format_reg = regmap_format_16_native;
+			break;
+		default:
+			goto err_map;
+		}
 		break;
 
 	case 32:
-		map->format.format_reg = regmap_format_32;
+		switch (reg_endian) {
+		case REGMAP_ENDIAN_BIG:
+			map->format.format_reg = regmap_format_32_be;
+			break;
+		case REGMAP_ENDIAN_NATIVE:
+			map->format.format_reg = regmap_format_32_native;
+			break;
+		default:
+			goto err_map;
+		}
 		break;
 
 	default:
@@ -338,21 +458,47 @@ struct regmap *regmap_init(struct device *dev,
 		map->format.parse_val = regmap_parse_8;
 		break;
 	case 16:
-		map->format.format_val = regmap_format_16;
-		map->format.parse_val = regmap_parse_16;
+		switch (val_endian) {
+		case REGMAP_ENDIAN_BIG:
+			map->format.format_val = regmap_format_16_be;
+			map->format.parse_val = regmap_parse_16_be;
+			break;
+		case REGMAP_ENDIAN_NATIVE:
+			map->format.format_val = regmap_format_16_native;
+			map->format.parse_val = regmap_parse_16_native;
+			break;
+		default:
+			goto err_map;
+		}
 		break;
 	case 24:
+		if (val_endian != REGMAP_ENDIAN_BIG)
+			goto err_map;
 		map->format.format_val = regmap_format_24;
 		map->format.parse_val = regmap_parse_24;
 		break;
 	case 32:
-		map->format.format_val = regmap_format_32;
-		map->format.parse_val = regmap_parse_32;
+		switch (val_endian) {
+		case REGMAP_ENDIAN_BIG:
+			map->format.format_val = regmap_format_32_be;
+			map->format.parse_val = regmap_parse_32_be;
+			break;
+		case REGMAP_ENDIAN_NATIVE:
+			map->format.format_val = regmap_format_32_native;
+			map->format.parse_val = regmap_parse_32_native;
+			break;
+		default:
+			goto err_map;
+		}
 		break;
 	}
 
-	if (map->format.format_write)
+	if (map->format.format_write) {
+		if ((reg_endian != REGMAP_ENDIAN_BIG) ||
+		    (val_endian != REGMAP_ENDIAN_BIG))
+			goto err_map;
 		map->use_single_rw = true;
+	}
 
 	if (!map->format.format_write &&
 	    !(map->format.format_reg && map->format.format_val))
@@ -364,27 +510,88 @@ struct regmap *regmap_init(struct device *dev,
 		goto err_map;
 	}
 
-	regmap_debugfs_init(map, config->name);
+	map->range_tree = RB_ROOT;
+	for (i = 0; i < config->n_ranges; i++) {
+		const struct regmap_range_cfg *range_cfg = &config->ranges[i];
+		struct regmap_range_node *new;
+
+		/* Sanity check */
+		if (range_cfg->range_max < range_cfg->range_min ||
+		    range_cfg->range_max > map->max_register ||
+		    range_cfg->selector_reg > map->max_register ||
+		    range_cfg->window_len == 0)
+			goto err_range;
+
+		/* Make sure, that this register range has no selector
+		   or data window within its boundary */
+		for (j = 0; j < config->n_ranges; j++) {
+			unsigned sel_reg = config->ranges[j].selector_reg;
+			unsigned win_min = config->ranges[j].window_start;
+			unsigned win_max = win_min +
+					   config->ranges[j].window_len - 1;
+
+			if (range_cfg->range_min <= sel_reg &&
+			    sel_reg <= range_cfg->range_max) {
+				goto err_range;
+			}
+
+			if (!(win_max < range_cfg->range_min ||
+			      win_min > range_cfg->range_max)) {
+				goto err_range;
+			}
+		}
+
+		new = kzalloc(sizeof(*new), GFP_KERNEL);
+		if (new == NULL) {
+			ret = -ENOMEM;
+			goto err_range;
+		}
+
+		new->range_min = range_cfg->range_min;
+		new->range_max = range_cfg->range_max;
+		new->selector_reg = range_cfg->selector_reg;
+		new->selector_mask = range_cfg->selector_mask;
+		new->selector_shift = range_cfg->selector_shift;
+		new->window_start = range_cfg->window_start;
+		new->window_len = range_cfg->window_len;
+
+		if (_regmap_range_add(map, new) == false) {
+			kfree(new);
+			goto err_range;
+		}
+
+		if (map->selector_work_buf == NULL) {
+			map->selector_work_buf =
+				kzalloc(map->format.buf_size, GFP_KERNEL);
+			if (map->selector_work_buf == NULL) {
+				ret = -ENOMEM;
+				goto err_range;
+			}
+		}
+	}
 
 	ret = regcache_init(map, config);
 	if (ret < 0)
-		goto err_debugfs;
+		goto err_range;
+
+	regmap_debugfs_init(map, config->name);
 
 	/* Add a devres resource for dev_get_regmap() */
 	m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
 	if (!m) {
 		ret = -ENOMEM;
-		goto err_cache;
+		goto err_debugfs;
 	}
 	*m = map;
 	devres_add(dev, m);
 
 	return map;
 
-err_cache:
-	regcache_exit(map);
 err_debugfs:
 	regmap_debugfs_exit(map);
+	regcache_exit(map);
+err_range:
+	regmap_range_exit(map);
 	kfree(map->work_buf);
 err_map:
 	kfree(map);
@@ -481,6 +688,7 @@ void regmap_exit(struct regmap *map)
 {
 	regcache_exit(map);
 	regmap_debugfs_exit(map);
+	regmap_range_exit(map);
 	if (map->bus->free_context)
 		map->bus->free_context(map->bus_context);
 	kfree(map->work_buf);
@@ -526,6 +734,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name)
 }
 EXPORT_SYMBOL_GPL(dev_get_regmap);
 
+static int _regmap_select_page(struct regmap *map, unsigned int *reg,
+			       unsigned int val_num)
+{
+	struct regmap_range_node *range;
+	void *orig_work_buf;
+	unsigned int win_offset;
+	unsigned int win_page;
+	bool page_chg;
+	int ret;
+
+	range = _regmap_range_lookup(map, *reg);
+	if (range) {
+		win_offset = (*reg - range->range_min) % range->window_len;
+		win_page = (*reg - range->range_min) / range->window_len;
+
+		if (val_num > 1) {
+			/* Bulk write shouldn't cross range boundary */
+			if (*reg + val_num - 1 > range->range_max)
+				return -EINVAL;
+
+			/* ... or single page boundary */
+			if (val_num > range->window_len - win_offset)
+				return -EINVAL;
+		}
+
+		/* It is possible to have selector register inside data window.
+		   In that case, selector register is located on every page and
+		   it needs no page switching, when accessed alone. */
+		if (val_num > 1 ||
+		    range->window_start + win_offset != range->selector_reg) {
+			/* Use separate work_buf during page switching */
+			orig_work_buf = map->work_buf;
+			map->work_buf = map->selector_work_buf;
+
+			ret = _regmap_update_bits(map, range->selector_reg,
+					range->selector_mask,
+					win_page << range->selector_shift,
+					&page_chg);
+
+			map->work_buf = orig_work_buf;
+
+			if (ret < 0)
+				return ret;
+		}
+
+		*reg = range->window_start + win_offset;
+	}
+
+	return 0;
+}
+
 static int _regmap_raw_write(struct regmap *map, unsigned int reg,
 			     const void *val, size_t val_len)
 {
@@ -563,6 +822,10 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
 		}
 	}
 
+	ret = _regmap_select_page(map, &reg, val_len / map->format.val_bytes);
+	if (ret < 0)
+		return ret;
+
 	map->format.format_reg(map->work_buf, reg, map->reg_shift);
 
 	u8[0] |= map->write_flag_mask;
@@ -626,6 +889,10 @@ int _regmap_write(struct regmap *map, unsigned int reg,
 	trace_regmap_reg_write(map->dev, reg, val);
 
 	if (map->format.format_write) {
+		ret = _regmap_select_page(map, &reg, 1);
+		if (ret < 0)
+			return ret;
+
 		map->format.format_write(map, reg, val);
 
 		trace_regmap_hw_write_start(map->dev, reg, 1);
@@ -783,6 +1050,10 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 	u8 *u8 = map->work_buf;
 	int ret;
 
+	ret = _regmap_select_page(map, &reg, val_len / map->format.val_bytes);
+	if (ret < 0)
+		return ret;
+
 	map->format.format_reg(map->work_buf, reg, map->reg_shift);
 
 	/*
@@ -982,11 +1253,9 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
 	int ret;
 	unsigned int tmp, orig;
 
-	map->lock(map);
-
 	ret = _regmap_read(map, reg, &orig);
 	if (ret != 0)
-		goto out;
+		return ret;
 
 	tmp = orig & ~mask;
 	tmp |= val & mask;
@@ -998,9 +1267,6 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
 		*change = false;
 	}
 
-out:
-	map->unlock(map);
-
 	return ret;
 }
 
@@ -1018,7 +1284,13 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
 		       unsigned int mask, unsigned int val)
 {
 	bool change;
-	return _regmap_update_bits(map, reg, mask, val, &change);
+	int ret;
+
+	map->lock(map);
+	ret = _regmap_update_bits(map, reg, mask, val, &change);
+	map->unlock(map);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(regmap_update_bits);
 
@@ -1038,7 +1310,12 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
 			     unsigned int mask, unsigned int val,
 			     bool *change)
 {
-	return _regmap_update_bits(map, reg, mask, val, change);
+	int ret;
+
+	map->lock(map);
+	ret = _regmap_update_bits(map, reg, mask, val, change);
+	map->unlock(map);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(regmap_update_bits_check);
 
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index acda773..38aa6dd 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -763,16 +763,7 @@ static void complete_scsi_command(CommandList_struct *c, int timeout,
 		{
 			case CMD_TARGET_STATUS:
 				/* Pass it up to the upper layers... */
-				if( ei->ScsiStatus)
-                		{
-#if 0
-                    			printk(KERN_WARNING "cciss: cmd %p "
-						"has SCSI Status = %x\n",
-						c, ei->ScsiStatus);
-#endif
-					cmd->result |= (ei->ScsiStatus << 1);
-                		}
-				else {  /* scsi status is zero??? How??? */
+				if (!ei->ScsiStatus) {
 					
 	/* Ordinarily, this case should never happen, but there is a bug
 	   in some released firmware revisions that allows it to happen
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
index b5c5ff5..fcb956b 100644
--- a/drivers/block/drbd/drbd_bitmap.c
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -1475,10 +1475,17 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
 		first_word = 0;
 		spin_lock_irq(&b->bm_lock);
 	}
-
 	/* last page (respectively only page, for first page == last page) */
 	last_word = MLPP(el >> LN2_BPL);
-	bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);
+
+	/* consider bitmap->bm_bits = 32768, bitmap->bm_number_of_pages = 1. (or multiples).
+	 * ==> e = 32767, el = 32768, last_page = 2,
+	 * and now last_word = 0.
+	 * We do not want to touch last_page in this case,
+	 * as we did not allocate it, it is not present in bitmap->bm_pages.
+	 */
+	if (last_word)
+		bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);
 
 	/* possibly trailing bits.
 	 * example: (e & 63) == 63, el will be e+1.
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 9c5c849..8e93a6a 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -472,12 +472,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
 		req->rq_state |= RQ_LOCAL_COMPLETED;
 		req->rq_state &= ~RQ_LOCAL_PENDING;
 
-		D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+		if (req->rq_state & RQ_LOCAL_ABORTED) {
+			_req_may_be_done(req, m);
+			break;
+		}
 
 		__drbd_chk_io_error(mdev, false);
 
 	goto_queue_for_net_read:
 
+		D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+
 		/* no point in retrying if there is no good remote data,
 		 * or we have no connection. */
 		if (mdev->state.pdsk != D_UP_TO_DATE) {
@@ -765,6 +770,40 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s
 	return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr);
 }
 
+static void maybe_pull_ahead(struct drbd_conf *mdev)
+{
+	int congested = 0;
+
+	/* If I don't even have good local storage, we can not reasonably try
+	 * to pull ahead of the peer. We also need the local reference to make
+	 * sure mdev->act_log is there.
+	 * Note: caller has to make sure that net_conf is there.
+	 */
+	if (!get_ldev_if_state(mdev, D_UP_TO_DATE))
+		return;
+
+	if (mdev->net_conf->cong_fill &&
+	    atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) {
+		dev_info(DEV, "Congestion-fill threshold reached\n");
+		congested = 1;
+	}
+
+	if (mdev->act_log->used >= mdev->net_conf->cong_extents) {
+		dev_info(DEV, "Congestion-extents threshold reached\n");
+		congested = 1;
+	}
+
+	if (congested) {
+		queue_barrier(mdev); /* last barrier, after mirrored writes */
+
+		if (mdev->net_conf->on_congestion == OC_PULL_AHEAD)
+			_drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
+		else  /*mdev->net_conf->on_congestion == OC_DISCONNECT */
+			_drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
+	}
+	put_ldev(mdev);
+}
+
 static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time)
 {
 	const int rw = bio_rw(bio);
@@ -972,29 +1011,8 @@ allocate_barrier:
 		_req_mod(req, queue_for_send_oos);
 
 	if (remote &&
-	    mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) {
-		int congested = 0;
-
-		if (mdev->net_conf->cong_fill &&
-		    atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) {
-			dev_info(DEV, "Congestion-fill threshold reached\n");
-			congested = 1;
-		}
-
-		if (mdev->act_log->used >= mdev->net_conf->cong_extents) {
-			dev_info(DEV, "Congestion-extents threshold reached\n");
-			congested = 1;
-		}
-
-		if (congested) {
-			queue_barrier(mdev); /* last barrier, after mirrored writes */
-
-			if (mdev->net_conf->on_congestion == OC_PULL_AHEAD)
-				_drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
-			else  /*mdev->net_conf->on_congestion == OC_DISCONNECT */
-				_drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
-		}
-	}
+	    mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96)
+		maybe_pull_ahead(mdev);
 
 	spin_unlock_irq(&mdev->req_lock);
 	kfree(b); /* if someone else has beaten us to it... */
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 264bc77..a8fddeb 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -37,6 +37,7 @@
 #include <linux/kthread.h>
 #include <../drivers/ata/ahci.h>
 #include <linux/export.h>
+#include <linux/debugfs.h>
 #include "mtip32xx.h"
 
 #define HW_CMD_SLOT_SZ		(MTIP_MAX_COMMAND_SLOTS * 32)
@@ -85,6 +86,7 @@ static int instance;
  * allocated in mtip_init().
  */
 static int mtip_major;
+static struct dentry *dfs_parent;
 
 static DEFINE_SPINLOCK(rssd_index_lock);
 static DEFINE_IDA(rssd_index_ida);
@@ -2546,7 +2548,7 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
 }
 
 /*
- * Sysfs register/status dump.
+ * Sysfs status dump.
  *
  * @dev  Pointer to the device structure, passed by the kernrel.
  * @attr Pointer to the device_attribute structure passed by the kernel.
@@ -2555,45 +2557,68 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
  * return value
  *	The size, in bytes, of the data copied into buf.
  */
-static ssize_t mtip_hw_show_registers(struct device *dev,
+static ssize_t mtip_hw_show_status(struct device *dev,
 				struct device_attribute *attr,
 				char *buf)
 {
-	u32 group_allocated;
 	struct driver_data *dd = dev_to_disk(dev)->private_data;
 	int size = 0;
+
+	if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))
+		size += sprintf(buf, "%s", "thermal_shutdown\n");
+	else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag))
+		size += sprintf(buf, "%s", "write_protect\n");
+	else
+		size += sprintf(buf, "%s", "online\n");
+
+	return size;
+}
+
+static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);
+
+static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
+				  size_t len, loff_t *offset)
+{
+	struct driver_data *dd =  (struct driver_data *)f->private_data;
+	char buf[MTIP_DFS_MAX_BUF_SIZE];
+	u32 group_allocated;
+	int size = *offset;
 	int n;
 
-	size += sprintf(&buf[size], "Hardware\n--------\n");
-	size += sprintf(&buf[size], "S ACTive      : [ 0x");
+	if (!len || size)
+		return 0;
+
+	if (size < 0)
+		return -EINVAL;
+
+	size += sprintf(&buf[size], "H/ S ACTive      : [ 0x");
 
 	for (n = dd->slot_groups-1; n >= 0; n--)
 		size += sprintf(&buf[size], "%08X ",
 					 readl(dd->port->s_active[n]));
 
 	size += sprintf(&buf[size], "]\n");
-	size += sprintf(&buf[size], "Command Issue : [ 0x");
+	size += sprintf(&buf[size], "H/ Command Issue : [ 0x");
 
 	for (n = dd->slot_groups-1; n >= 0; n--)
 		size += sprintf(&buf[size], "%08X ",
 					readl(dd->port->cmd_issue[n]));
 
 	size += sprintf(&buf[size], "]\n");
-	size += sprintf(&buf[size], "Completed     : [ 0x");
+	size += sprintf(&buf[size], "H/ Completed     : [ 0x");
 
 	for (n = dd->slot_groups-1; n >= 0; n--)
 		size += sprintf(&buf[size], "%08X ",
 				readl(dd->port->completed[n]));
 
 	size += sprintf(&buf[size], "]\n");
-	size += sprintf(&buf[size], "PORT IRQ STAT : [ 0x%08X ]\n",
+	size += sprintf(&buf[size], "H/ PORT IRQ STAT : [ 0x%08X ]\n",
 				readl(dd->port->mmio + PORT_IRQ_STAT));
-	size += sprintf(&buf[size], "HOST IRQ STAT : [ 0x%08X ]\n",
+	size += sprintf(&buf[size], "H/ HOST IRQ STAT : [ 0x%08X ]\n",
 				readl(dd->mmio + HOST_IRQ_STAT));
 	size += sprintf(&buf[size], "\n");
 
-	size += sprintf(&buf[size], "Local\n-----\n");
-	size += sprintf(&buf[size], "Allocated    : [ 0x");
+	size += sprintf(&buf[size], "L/ Allocated     : [ 0x");
 
 	for (n = dd->slot_groups-1; n >= 0; n--) {
 		if (sizeof(long) > sizeof(u32))
@@ -2605,7 +2630,7 @@ static ssize_t mtip_hw_show_registers(struct device *dev,
 	}
 	size += sprintf(&buf[size], "]\n");
 
-	size += sprintf(&buf[size], "Commands in Q: [ 0x");
+	size += sprintf(&buf[size], "L/ Commands in Q : [ 0x");
 
 	for (n = dd->slot_groups-1; n >= 0; n--) {
 		if (sizeof(long) > sizeof(u32))
@@ -2617,44 +2642,53 @@ static ssize_t mtip_hw_show_registers(struct device *dev,
 	}
 	size += sprintf(&buf[size], "]\n");
 
-	return size;
+	*offset = size <= len ? size : len;
+	size = copy_to_user(ubuf, buf, *offset);
+	if (size)
+		return -EFAULT;
+
+	return *offset;
 }
 
-static ssize_t mtip_hw_show_status(struct device *dev,
-				struct device_attribute *attr,
-				char *buf)
+static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf,
+				  size_t len, loff_t *offset)
 {
-	struct driver_data *dd = dev_to_disk(dev)->private_data;
-	int size = 0;
+	struct driver_data *dd =  (struct driver_data *)f->private_data;
+	char buf[MTIP_DFS_MAX_BUF_SIZE];
+	int size = *offset;
 
-	if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))
-		size += sprintf(buf, "%s", "thermal_shutdown\n");
-	else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag))
-		size += sprintf(buf, "%s", "write_protect\n");
-	else
-		size += sprintf(buf, "%s", "online\n");
-
-	return size;
-}
+	if (!len || size)
+		return 0;
 
-static ssize_t mtip_hw_show_flags(struct device *dev,
-				struct device_attribute *attr,
-				char *buf)
-{
-	struct driver_data *dd = dev_to_disk(dev)->private_data;
-	int size = 0;
+	if (size < 0)
+		return -EINVAL;
 
-	size += sprintf(&buf[size], "Flag in port struct : [ %08lX ]\n",
+	size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n",
 							dd->port->flags);
-	size += sprintf(&buf[size], "Flag in dd struct   : [ %08lX ]\n",
+	size += sprintf(&buf[size], "Flag-dd   : [ %08lX ]\n",
 							dd->dd_flag);
 
-	return size;
+	*offset = size <= len ? size : len;
+	size = copy_to_user(ubuf, buf, *offset);
+	if (size)
+		return -EFAULT;
+
+	return *offset;
 }
 
-static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL);
-static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);
-static DEVICE_ATTR(flags, S_IRUGO, mtip_hw_show_flags, NULL);
+static const struct file_operations mtip_regs_fops = {
+	.owner  = THIS_MODULE,
+	.open   = simple_open,
+	.read   = mtip_hw_read_registers,
+	.llseek = no_llseek,
+};
+
+static const struct file_operations mtip_flags_fops = {
+	.owner  = THIS_MODULE,
+	.open   = simple_open,
+	.read   = mtip_hw_read_flags,
+	.llseek = no_llseek,
+};
 
 /*
  * Create the sysfs related attributes.
@@ -2671,15 +2705,9 @@ static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj)
 	if (!kobj || !dd)
 		return -EINVAL;
 
-	if (sysfs_create_file(kobj, &dev_attr_registers.attr))
-		dev_warn(&dd->pdev->dev,
-			"Error creating 'registers' sysfs entry\n");
 	if (sysfs_create_file(kobj, &dev_attr_status.attr))
 		dev_warn(&dd->pdev->dev,
 			"Error creating 'status' sysfs entry\n");
-	if (sysfs_create_file(kobj, &dev_attr_flags.attr))
-		dev_warn(&dd->pdev->dev,
-			"Error creating 'flags' sysfs entry\n");
 	return 0;
 }
 
@@ -2698,13 +2726,39 @@ static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj)
 	if (!kobj || !dd)
 		return -EINVAL;
 
-	sysfs_remove_file(kobj, &dev_attr_registers.attr);
 	sysfs_remove_file(kobj, &dev_attr_status.attr);
-	sysfs_remove_file(kobj, &dev_attr_flags.attr);
 
 	return 0;
 }
 
+static int mtip_hw_debugfs_init(struct driver_data *dd)
+{
+	if (!dfs_parent)
+		return -1;
+
+	dd->dfs_node = debugfs_create_dir(dd->disk->disk_name, dfs_parent);
+	if (IS_ERR_OR_NULL(dd->dfs_node)) {
+		dev_warn(&dd->pdev->dev,
+			"Error creating node %s under debugfs\n",
+						dd->disk->disk_name);
+		dd->dfs_node = NULL;
+		return -1;
+	}
+
+	debugfs_create_file("flags", S_IRUGO, dd->dfs_node, dd,
+							&mtip_flags_fops);
+	debugfs_create_file("registers", S_IRUGO, dd->dfs_node, dd,
+							&mtip_regs_fops);
+
+	return 0;
+}
+
+static void mtip_hw_debugfs_exit(struct driver_data *dd)
+{
+	debugfs_remove_recursive(dd->dfs_node);
+}
+
+
 /*
  * Perform any init/resume time hardware setup
  *
@@ -3730,6 +3784,7 @@ skip_create_disk:
 		mtip_hw_sysfs_init(dd, kobj);
 		kobject_put(kobj);
 	}
+	mtip_hw_debugfs_init(dd);
 
 	if (dd->mtip_svc_handler) {
 		set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag);
@@ -3755,6 +3810,8 @@ start_service_thread:
 	return rv;
 
 kthread_run_error:
+	mtip_hw_debugfs_exit(dd);
+
 	/* Delete our gendisk. This also removes the device from /dev */
 	del_gendisk(dd->disk);
 
@@ -3805,6 +3862,7 @@ static int mtip_block_remove(struct driver_data *dd)
 			kobject_put(kobj);
 		}
 	}
+	mtip_hw_debugfs_exit(dd);
 
 	/*
 	 * Delete our gendisk structure. This also removes the device
@@ -4152,10 +4210,20 @@ static int __init mtip_init(void)
 	}
 	mtip_major = error;
 
+	if (!dfs_parent) {
+		dfs_parent = debugfs_create_dir("rssd", NULL);
+		if (IS_ERR_OR_NULL(dfs_parent)) {
+			printk(KERN_WARNING "Error creating debugfs parent\n");
+			dfs_parent = NULL;
+		}
+	}
+
 	/* Register our PCI operations. */
 	error = pci_register_driver(&mtip_pci_driver);
-	if (error)
+	if (error) {
+		debugfs_remove(dfs_parent);
 		unregister_blkdev(mtip_major, MTIP_DRV_NAME);
+	}
 
 	return error;
 }
@@ -4172,6 +4240,8 @@ static int __init mtip_init(void)
  */
 static void __exit mtip_exit(void)
 {
+	debugfs_remove_recursive(dfs_parent);
+
 	/* Release the allocated major block device number. */
 	unregister_blkdev(mtip_major, MTIP_DRV_NAME);
 
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
index b2c88da..f51fc23 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -26,7 +26,6 @@
 #include <linux/ata.h>
 #include <linux/interrupt.h>
 #include <linux/genhd.h>
-#include <linux/version.h>
 
 /* Offset of Subsystem Device ID in pci confoguration space */
 #define PCI_SUBSYSTEM_DEVICEID	0x2E
@@ -111,6 +110,8 @@
  #define dbg_printk(format, arg...)
 #endif
 
+#define MTIP_DFS_MAX_BUF_SIZE 1024
+
 #define __force_bit2int (unsigned int __force)
 
 enum {
@@ -447,6 +448,8 @@ struct driver_data {
 	unsigned long dd_flag; /* NOTE: use atomic bit operations on this */
 
 	struct task_struct *mtip_svc_handler; /* task_struct of svc thd */
+
+	struct dentry *dfs_node;
 };
 
 #endif
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 65665c9..8f428a8 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -499,7 +499,7 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
 			 / sizeof (*ondisk))
 		return -EINVAL;
 	header->snapc = kmalloc(sizeof(struct ceph_snap_context) +
-				snap_count * sizeof (*ondisk),
+				snap_count * sizeof(u64),
 				gfp_flags);
 	if (!header->snapc)
 		return -ENOMEM;
@@ -977,7 +977,7 @@ static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg)
 	op = (void *)(replyhead + 1);
 	rc = le32_to_cpu(replyhead->result);
 	bytes = le64_to_cpu(op->extent.length);
-	read_op = (le32_to_cpu(op->op) == CEPH_OSD_OP_READ);
+	read_op = (le16_to_cpu(op->op) == CEPH_OSD_OP_READ);
 
 	dout("rbd_req_cb bytes=%lld readop=%d rc=%d\n", bytes, read_op, rc);
 
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index aa27120..9a72277 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -513,6 +513,44 @@ static void process_page(unsigned long data)
 	}
 }
 
+struct mm_plug_cb {
+	struct blk_plug_cb cb;
+	struct cardinfo *card;
+};
+
+static void mm_unplug(struct blk_plug_cb *cb)
+{
+	struct mm_plug_cb *mmcb = container_of(cb, struct mm_plug_cb, cb);
+
+	spin_lock_irq(&mmcb->card->lock);
+	activate(mmcb->card);
+	spin_unlock_irq(&mmcb->card->lock);
+	kfree(mmcb);
+}
+
+static int mm_check_plugged(struct cardinfo *card)
+{
+	struct blk_plug *plug = current->plug;
+	struct mm_plug_cb *mmcb;
+
+	if (!plug)
+		return 0;
+
+	list_for_each_entry(mmcb, &plug->cb_list, cb.list) {
+		if (mmcb->cb.callback == mm_unplug && mmcb->card == card)
+			return 1;
+	}
+	/* Not currently on the callback list */
+	mmcb = kmalloc(sizeof(*mmcb), GFP_ATOMIC);
+	if (!mmcb)
+		return 0;
+
+	mmcb->card = card;
+	mmcb->cb.callback = mm_unplug;
+	list_add(&mmcb->cb.list, &plug->cb_list);
+	return 1;
+}
+
 static void mm_make_request(struct request_queue *q, struct bio *bio)
 {
 	struct cardinfo *card = q->queuedata;
@@ -523,6 +561,8 @@ static void mm_make_request(struct request_queue *q, struct bio *bio)
 	*card->biotail = bio;
 	bio->bi_next = NULL;
 	card->biotail = &bio->bi_next;
+	if (bio->bi_rw & REQ_SYNC || !mm_check_plugged(card))
+		activate(card);
 	spin_unlock_irq(&card->lock);
 
 	return;
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 693187d..774c31d 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -21,8 +21,6 @@ struct workqueue_struct *virtblk_wq;
 
 struct virtio_blk
 {
-	spinlock_t lock;
-
 	struct virtio_device *vdev;
 	struct virtqueue *vq;
 
@@ -65,7 +63,7 @@ static void blk_done(struct virtqueue *vq)
 	unsigned int len;
 	unsigned long flags;
 
-	spin_lock_irqsave(&vblk->lock, flags);
+	spin_lock_irqsave(vblk->disk->queue->queue_lock, flags);
 	while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) {
 		int error;
 
@@ -99,7 +97,7 @@ static void blk_done(struct virtqueue *vq)
 	}
 	/* In case queue is stopped waiting for more buffers. */
 	blk_start_queue(vblk->disk->queue);
-	spin_unlock_irqrestore(&vblk->lock, flags);
+	spin_unlock_irqrestore(vblk->disk->queue->queue_lock, flags);
 }
 
 static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
@@ -431,7 +429,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
 		goto out_free_index;
 	}
 
-	spin_lock_init(&vblk->lock);
 	vblk->vdev = vdev;
 	vblk->sg_elems = sg_elems;
 	sg_init_table(vblk->sg, vblk->sg_elems);
@@ -456,7 +453,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
 		goto out_mempool;
 	}
 
-	q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
+	q = vblk->disk->queue = blk_init_queue(do_virtblk_request, NULL);
 	if (!q) {
 		err = -ENOMEM;
 		goto out_put_disk;
@@ -576,30 +573,20 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
 {
 	struct virtio_blk *vblk = vdev->priv;
 	int index = vblk->index;
-	struct virtblk_req *vbr;
-	unsigned long flags;
 
 	/* Prevent config work handler from accessing the device. */
 	mutex_lock(&vblk->config_lock);
 	vblk->config_enable = false;
 	mutex_unlock(&vblk->config_lock);
 
+	del_gendisk(vblk->disk);
+	blk_cleanup_queue(vblk->disk->queue);
+
 	/* Stop all the virtqueues. */
 	vdev->config->reset(vdev);
 
 	flush_work(&vblk->config_work);
 
-	del_gendisk(vblk->disk);
-
-	/* Abort requests dispatched to driver. */
-	spin_lock_irqsave(&vblk->lock, flags);
-	while ((vbr = virtqueue_detach_unused_buf(vblk->vq))) {
-		__blk_end_request_all(vbr->req, -EIO);
-		mempool_free(vbr, vblk->pool);
-	}
-	spin_unlock_irqrestore(&vblk->lock, flags);
-
-	blk_cleanup_queue(vblk->disk->queue);
 	put_disk(vblk->disk);
 	mempool_destroy(vblk->pool);
 	vdev->config->del_vqs(vdev);
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
index 773cf27..9ad3b5e 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -257,6 +257,7 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
 		break;
 	case BLKIF_OP_DISCARD:
 		dst->u.discard.flag = src->u.discard.flag;
+		dst->u.discard.id = src->u.discard.id;
 		dst->u.discard.sector_number = src->u.discard.sector_number;
 		dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
 		break;
@@ -287,6 +288,7 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst,
 		break;
 	case BLKIF_OP_DISCARD:
 		dst->u.discard.flag = src->u.discard.flag;
+		dst->u.discard.id = src->u.discard.id;
 		dst->u.discard.sector_number = src->u.discard.sector_number;
 		dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
 		break;
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 60eed4b..e4fb337 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -141,14 +141,36 @@ static int get_id_from_freelist(struct blkfront_info *info)
 	return free;
 }
 
-static void add_id_to_freelist(struct blkfront_info *info,
+static int add_id_to_freelist(struct blkfront_info *info,
 			       unsigned long id)
 {
+	if (info->shadow[id].req.u.rw.id != id)
+		return -EINVAL;
+	if (info->shadow[id].request == NULL)
+		return -EINVAL;
 	info->shadow[id].req.u.rw.id  = info->shadow_free;
 	info->shadow[id].request = NULL;
 	info->shadow_free = id;
+	return 0;
 }
 
+static const char *op_name(int op)
+{
+	static const char *const names[] = {
+		[BLKIF_OP_READ] = "read",
+		[BLKIF_OP_WRITE] = "write",
+		[BLKIF_OP_WRITE_BARRIER] = "barrier",
+		[BLKIF_OP_FLUSH_DISKCACHE] = "flush",
+		[BLKIF_OP_DISCARD] = "discard" };
+
+	if (op < 0 || op >= ARRAY_SIZE(names))
+		return "unknown";
+
+	if (!names[op])
+		return "reserved";
+
+	return names[op];
+}
 static int xlbd_reserve_minors(unsigned int minor, unsigned int nr)
 {
 	unsigned int end = minor + nr;
@@ -746,20 +768,36 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 
 		bret = RING_GET_RESPONSE(&info->ring, i);
 		id   = bret->id;
+		/*
+		 * The backend has messed up and given us an id that we would
+		 * never have given to it (we stamp it up to BLK_RING_SIZE -
+		 * look in get_id_from_freelist.
+		 */
+		if (id >= BLK_RING_SIZE) {
+			WARN(1, "%s: response to %s has incorrect id (%ld)\n",
+			     info->gd->disk_name, op_name(bret->operation), id);
+			/* We can't safely get the 'struct request' as
+			 * the id is busted. */
+			continue;
+		}
 		req  = info->shadow[id].request;
 
 		if (bret->operation != BLKIF_OP_DISCARD)
 			blkif_completion(&info->shadow[id]);
 
-		add_id_to_freelist(info, id);
+		if (add_id_to_freelist(info, id)) {
+			WARN(1, "%s: response to %s (id %ld) couldn't be recycled!\n",
+			     info->gd->disk_name, op_name(bret->operation), id);
+			continue;
+		}
 
 		error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
 		switch (bret->operation) {
 		case BLKIF_OP_DISCARD:
 			if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
 				struct request_queue *rq = info->rq;
-				printk(KERN_WARNING "blkfront: %s: discard op failed\n",
-					   info->gd->disk_name);
+				printk(KERN_WARNING "blkfront: %s: %s op failed\n",
+					   info->gd->disk_name, op_name(bret->operation));
 				error = -EOPNOTSUPP;
 				info->feature_discard = 0;
 				info->feature_secdiscard = 0;
@@ -771,18 +809,14 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 		case BLKIF_OP_FLUSH_DISKCACHE:
 		case BLKIF_OP_WRITE_BARRIER:
 			if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
-				printk(KERN_WARNING "blkfront: %s: write %s op failed\n",
-				       info->flush_op == BLKIF_OP_WRITE_BARRIER ?
-				       "barrier" :  "flush disk cache",
-				       info->gd->disk_name);
+				printk(KERN_WARNING "blkfront: %s: %s op failed\n",
+				       info->gd->disk_name, op_name(bret->operation));
 				error = -EOPNOTSUPP;
 			}
 			if (unlikely(bret->status == BLKIF_RSP_ERROR &&
 				     info->shadow[id].req.u.rw.nr_segments == 0)) {
-				printk(KERN_WARNING "blkfront: %s: empty write %s op failed\n",
-				       info->flush_op == BLKIF_OP_WRITE_BARRIER ?
-				       "barrier" :  "flush disk cache",
-				       info->gd->disk_name);
+				printk(KERN_WARNING "blkfront: %s: empty %s op failed\n",
+				       info->gd->disk_name, op_name(bret->operation));
 				error = -EOPNOTSUPP;
 			}
 			if (unlikely(error)) {
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index ad591bd..10308cd 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -63,6 +63,7 @@ static struct usb_device_id ath3k_table[] = {
 
 	/* Atheros AR3011 with sflash firmware*/
 	{ USB_DEVICE(0x0CF3, 0x3002) },
+	{ USB_DEVICE(0x0CF3, 0xE019) },
 	{ USB_DEVICE(0x13d3, 0x3304) },
 	{ USB_DEVICE(0x0930, 0x0215) },
 	{ USB_DEVICE(0x0489, 0xE03D) },
@@ -77,6 +78,7 @@ static struct usb_device_id ath3k_table[] = {
 	{ USB_DEVICE(0x04CA, 0x3005) },
 	{ USB_DEVICE(0x13d3, 0x3362) },
 	{ USB_DEVICE(0x0CF3, 0xE004) },
+	{ USB_DEVICE(0x0930, 0x0219) },
 
 	/* Atheros AR5BBU12 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xE02C) },
@@ -101,6 +103,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
 	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
 
 	/* Atheros AR5BBU22 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 1fcd923..585c88e 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -231,12 +231,12 @@ static void bluecard_write_wakeup(bluecard_info_t *info)
 	}
 
 	do {
-		register unsigned int iobase = info->p_dev->resource[0]->start;
-		register unsigned int offset;
-		register unsigned char command;
-		register unsigned long ready_bit;
+		unsigned int iobase = info->p_dev->resource[0]->start;
+		unsigned int offset;
+		unsigned char command;
+		unsigned long ready_bit;
 		register struct sk_buff *skb;
-		register int len;
+		int len;
 
 		clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index 609861a..29caaed 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -470,7 +470,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
 	hdev->flush    = bpa10x_flush;
 	hdev->send     = bpa10x_send_frame;
 
-	set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+	set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 
 	err = hci_register_dev(hdev);
 	if (err < 0) {
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 308c859..b2b0fbb 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -186,9 +186,9 @@ static void bt3c_write_wakeup(bt3c_info_t *info)
 		return;
 
 	do {
-		register unsigned int iobase = info->p_dev->resource[0]->start;
+		unsigned int iobase = info->p_dev->resource[0]->start;
 		register struct sk_buff *skb;
-		register int len;
+		int len;
 
 		if (!pcmcia_dev_present(info->p_dev))
 			break;
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index 94f2d65..27068d1 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -136,7 +136,7 @@ int btmrvl_remove_card(struct btmrvl_private *priv);
 
 void btmrvl_interrupt(struct btmrvl_private *priv);
 
-void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
+bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
 int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
 
 int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index 681ca9d..dc304de 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -44,23 +44,33 @@ void btmrvl_interrupt(struct btmrvl_private *priv)
 }
 EXPORT_SYMBOL_GPL(btmrvl_interrupt);
 
-void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
+bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
 {
 	struct hci_event_hdr *hdr = (void *) skb->data;
 	struct hci_ev_cmd_complete *ec;
-	u16 opcode, ocf;
+	u16 opcode, ocf, ogf;
 
 	if (hdr->evt == HCI_EV_CMD_COMPLETE) {
 		ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE);
 		opcode = __le16_to_cpu(ec->opcode);
 		ocf = hci_opcode_ocf(opcode);
+		ogf = hci_opcode_ogf(opcode);
+
 		if (ocf == BT_CMD_MODULE_CFG_REQ &&
 					priv->btmrvl_dev.sendcmdflag) {
 			priv->btmrvl_dev.sendcmdflag = false;
 			priv->adapter->cmd_complete = true;
 			wake_up_interruptible(&priv->adapter->cmd_wait_q);
 		}
+
+		if (ogf == OGF) {
+			BT_DBG("vendor event skipped: ogf 0x%4.4x", ogf);
+			kfree_skb(skb);
+			return false;
+		}
 	}
+
+	return true;
 }
 EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt);
 
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index a853244..cf7588ed 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -110,6 +110,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
 	/* Marvell SD8787 Bluetooth device */
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
 			.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
+	/* Marvell SD8787 Bluetooth AMP device */
+	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B),
+			.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
 	/* Marvell SD8797 Bluetooth device */
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
 			.driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
@@ -562,10 +565,12 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
 		skb_put(skb, buf_len);
 		skb_pull(skb, SDIO_HEADER_LEN);
 
-		if (type == HCI_EVENT_PKT)
-			btmrvl_check_evtpkt(priv, skb);
+		if (type == HCI_EVENT_PKT) {
+			if (btmrvl_check_evtpkt(priv, skb))
+				hci_recv_frame(skb);
+		} else
+			hci_recv_frame(skb);
 
-		hci_recv_frame(skb);
 		hdev->stat.byte_rx += buf_len;
 		break;
 
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index c4fc2f3..65b8d99 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -140,9 +140,9 @@ static void btuart_write_wakeup(btuart_info_t *info)
 	}
 
 	do {
-		register unsigned int iobase = info->p_dev->resource[0]->start;
+		unsigned int iobase = info->p_dev->resource[0]->start;
 		register struct sk_buff *skb;
-		register int len;
+		int len;
 
 		clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index c9463af..e272214 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -21,15 +21,7 @@
  *
  */
 
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/skbuff.h>
-
 #include <linux/usb.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -125,6 +117,7 @@ static struct usb_device_id blacklist_table[] = {
 
 	/* Atheros 3011 with sflash firmware */
 	{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
+	{ USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE },
 	{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
 	{ USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
 	{ USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
@@ -139,6 +132,7 @@ static struct usb_device_id blacklist_table[] = {
 	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
 
 	/* Atheros AR5BBU12 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -1026,7 +1020,7 @@ static int btusb_probe(struct usb_interface *intf,
 	data->isoc = usb_ifnum_to_if(data->udev, 1);
 
 	if (!reset)
-		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+		set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 
 	if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) {
 		if (!disable_scofix)
@@ -1038,7 +1032,7 @@ static int btusb_probe(struct usb_interface *intf,
 
 	if (id->driver_info & BTUSB_DIGIANSWER) {
 		data->cmdreq_type = USB_TYPE_VENDOR;
-		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+		set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 	}
 
 	if (id->driver_info & BTUSB_CSR) {
@@ -1046,7 +1040,7 @@ static int btusb_probe(struct usb_interface *intf,
 
 		/* Old firmware would otherwise execute USB reset */
 		if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117)
-			set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+			set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 	}
 
 	if (id->driver_info & BTUSB_SNIFFER) {
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 6e8d961..b1b37cc 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -144,9 +144,9 @@ static void dtl1_write_wakeup(dtl1_info_t *info)
 	}
 
 	do {
-		register unsigned int iobase = info->p_dev->resource[0]->start;
+		unsigned int iobase = info->p_dev->resource[0]->start;
 		register struct sk_buff *skb;
-		register int len;
+		int len;
 
 		clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 661a8dc..57e502e 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -552,7 +552,7 @@ static u16 bscp_get_crc(struct bcsp_struct *bcsp)
 static int bcsp_recv(struct hci_uart *hu, void *data, int count)
 {
 	struct bcsp_struct *bcsp = hu->priv;
-	register unsigned char *ptr;
+	unsigned char *ptr;
 
 	BT_DBG("hu %p count %d rx_state %d rx_count %ld", 
 		hu, count, bcsp->rx_state, bcsp->rx_count);
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 7483294..c60623f 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -126,7 +126,7 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 
 static inline int h4_check_data_len(struct h4_struct *h4, int len)
 {
-	register int room = skb_tailroom(h4->rx_skb);
+	int room = skb_tailroom(h4->rx_skb);
 
 	BT_DBG("len %d room %d", len, room);
 
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index e564579..2f9b796 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -394,7 +394,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
 		set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
 
 	if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
-		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+		set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 
 	if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
 		hdev->dev_type = HCI_AMP;
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index b874c0e..ff6d589 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -348,7 +348,7 @@ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 
 static inline int ll_check_data_len(struct ll_struct *ll, int len)
 {
-	register int room = skb_tailroom(ll->rx_skb);
+	int room = skb_tailroom(ll->rx_skb);
 
 	BT_DBG("len %d room %d", len, room);
 
@@ -374,11 +374,11 @@ static inline int ll_check_data_len(struct ll_struct *ll, int len)
 static int ll_recv(struct hci_uart *hu, void *data, int count)
 {
 	struct ll_struct *ll = hu->priv;
-	register char *ptr;
+	char *ptr;
 	struct hci_event_hdr *eh;
 	struct hci_acl_hdr   *ah;
 	struct hci_sco_hdr   *sh;
-	register int len, type, dlen;
+	int len, type, dlen;
 
 	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count);
 
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index f45dad3..6640311 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -73,6 +73,20 @@ config HW_RANDOM_ATMEL
 
 	  If unsure, say Y.
 
+config HW_RANDOM_BCM63XX
+	tristate "Broadcom BCM63xx Random Number Generator support"
+	depends on HW_RANDOM && BCM63XX
+	default HW_RANDOM
+	---help---
+	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on the Broadcom BCM63xx SoCs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bcm63xx-rng
+
+	  If unusure, say Y.
+
+
 config HW_RANDOM_GEODE
 	tristate "AMD Geode HW Random Number Generator support"
 	depends on HW_RANDOM && X86_32 && PCI
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index d901dfa..67f57bf 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o
 obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o
 obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o
 obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
+obj-$(CONFIG_HW_RANDOM_BCM63XX)	+= bcm63xx-rng.o
 obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
 obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o
 n2-rng-y := n2-drv.o n2-asm.o
diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c
new file mode 100644
index 0000000..b789dbf
--- /dev/null
+++ b/drivers/char/hw_random/bcm63xx-rng.c
@@ -0,0 +1,175 @@
+/*
+ * Broadcom BCM63xx Random Number Generator support
+ *
+ * Copyright (C) 2011, Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2009, Broadcom Corporation
+ *
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+
+#include <bcm63xx_io.h>
+#include <bcm63xx_regs.h>
+
+struct bcm63xx_rng_priv {
+	struct clk *clk;
+	void __iomem *regs;
+};
+
+#define to_rng_priv(rng)	((struct bcm63xx_rng_priv *)rng->priv)
+
+static int bcm63xx_rng_init(struct hwrng *rng)
+{
+	struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
+	u32 val;
+
+	val = bcm_readl(priv->regs + RNG_CTRL);
+	val |= RNG_EN;
+	bcm_writel(val, priv->regs + RNG_CTRL);
+
+	return 0;
+}
+
+static void bcm63xx_rng_cleanup(struct hwrng *rng)
+{
+	struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
+	u32 val;
+
+	val = bcm_readl(priv->regs + RNG_CTRL);
+	val &= ~RNG_EN;
+	bcm_writel(val, priv->regs + RNG_CTRL);
+}
+
+static int bcm63xx_rng_data_present(struct hwrng *rng, int wait)
+{
+	struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
+
+	return bcm_readl(priv->regs + RNG_STAT) & RNG_AVAIL_MASK;
+}
+
+static int bcm63xx_rng_data_read(struct hwrng *rng, u32 *data)
+{
+	struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
+
+	*data = bcm_readl(priv->regs + RNG_DATA);
+
+	return 4;
+}
+
+static int __init bcm63xx_rng_probe(struct platform_device *pdev)
+{
+	struct resource *r;
+	struct clk *clk;
+	int ret;
+	struct bcm63xx_rng_priv *priv;
+	struct hwrng *rng;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		dev_err(&pdev->dev, "no iomem resource\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&pdev->dev, "no memory for private structure\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	rng = kzalloc(sizeof(*rng), GFP_KERNEL);
+	if (!rng) {
+		dev_err(&pdev->dev, "no memory for rng structure\n");
+		ret = -ENOMEM;
+		goto out_free_priv;
+	}
+
+	platform_set_drvdata(pdev, rng);
+	rng->priv = (unsigned long)priv;
+	rng->name = pdev->name;
+	rng->init = bcm63xx_rng_init;
+	rng->cleanup = bcm63xx_rng_cleanup;
+	rng->data_present = bcm63xx_rng_data_present;
+	rng->data_read = bcm63xx_rng_data_read;
+
+	clk = clk_get(&pdev->dev, "ipsec");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "no clock for device\n");
+		ret = PTR_ERR(clk);
+		goto out_free_rng;
+	}
+
+	priv->clk = clk;
+
+	if (!devm_request_mem_region(&pdev->dev, r->start,
+					resource_size(r), pdev->name)) {
+		dev_err(&pdev->dev, "request mem failed");
+		ret = -ENOMEM;
+		goto out_free_rng;
+	}
+
+	priv->regs = devm_ioremap_nocache(&pdev->dev, r->start,
+					resource_size(r));
+	if (!priv->regs) {
+		dev_err(&pdev->dev, "ioremap failed");
+		ret = -ENOMEM;
+		goto out_free_rng;
+	}
+
+	clk_enable(clk);
+
+	ret = hwrng_register(rng);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register rng device\n");
+		goto out_clk_disable;
+	}
+
+	dev_info(&pdev->dev, "registered RNG driver\n");
+
+	return 0;
+
+out_clk_disable:
+	clk_disable(clk);
+out_free_rng:
+	platform_set_drvdata(pdev, NULL);
+	kfree(rng);
+out_free_priv:
+	kfree(priv);
+out:
+	return ret;
+}
+
+static int __devexit bcm63xx_rng_remove(struct platform_device *pdev)
+{
+	struct hwrng *rng = platform_get_drvdata(pdev);
+	struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
+
+	hwrng_unregister(rng);
+	clk_disable(priv->clk);
+	kfree(priv);
+	kfree(rng);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver bcm63xx_rng_driver = {
+	.probe		= bcm63xx_rng_probe,
+	.remove		= __devexit_p(bcm63xx_rng_remove),
+	.driver		= {
+		.name	= "bcm63xx-rng",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(bcm63xx_rng_driver);
+
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
+MODULE_DESCRIPTION("Broadcom BCM63xx RNG driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 723725b..5708299 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -55,6 +55,7 @@ static void register_buffer(u8 *buf, size_t size)
 
 static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
 {
+	int ret;
 
 	if (!busy) {
 		busy = true;
@@ -65,7 +66,9 @@ static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
 	if (!wait)
 		return 0;
 
-	wait_for_completion(&have_data);
+	ret = wait_for_completion_killable(&have_data);
+	if (ret < 0)
+		return ret;
 
 	busy = false;
 
@@ -85,7 +88,7 @@ static struct hwrng virtio_hwrng = {
 	.read		= virtio_read,
 };
 
-static int virtrng_probe(struct virtio_device *vdev)
+static int probe_common(struct virtio_device *vdev)
 {
 	int err;
 
@@ -103,13 +106,37 @@ static int virtrng_probe(struct virtio_device *vdev)
 	return 0;
 }
 
-static void __devexit virtrng_remove(struct virtio_device *vdev)
+static void remove_common(struct virtio_device *vdev)
 {
 	vdev->config->reset(vdev);
+	busy = false;
 	hwrng_unregister(&virtio_hwrng);
 	vdev->config->del_vqs(vdev);
 }
 
+static int virtrng_probe(struct virtio_device *vdev)
+{
+	return probe_common(vdev);
+}
+
+static void __devexit virtrng_remove(struct virtio_device *vdev)
+{
+	remove_common(vdev);
+}
+
+#ifdef CONFIG_PM
+static int virtrng_freeze(struct virtio_device *vdev)
+{
+	remove_common(vdev);
+	return 0;
+}
+
+static int virtrng_restore(struct virtio_device *vdev)
+{
+	return probe_common(vdev);
+}
+#endif
+
 static struct virtio_device_id id_table[] = {
 	{ VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID },
 	{ 0 },
@@ -121,6 +148,10 @@ static struct virtio_driver virtio_rng_driver = {
 	.id_table =	id_table,
 	.probe =	virtrng_probe,
 	.remove =	__devexit_p(virtrng_remove),
+#ifdef CONFIG_PM
+	.freeze =	virtrng_freeze,
+	.restore =	virtrng_restore,
+#endif
 };
 
 static int __init init(void)
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 7ed356e..37b8be7 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -141,17 +141,6 @@
 
 #define IPMI_WDOG_TIMER_NOT_INIT_RESP	0x80
 
-/* These are here until the real ones get into the watchdog.h interface. */
-#ifndef WDIOC_GETTIMEOUT
-#define	WDIOC_GETTIMEOUT        _IOW(WATCHDOG_IOCTL_BASE, 20, int)
-#endif
-#ifndef WDIOC_SET_PRETIMEOUT
-#define	WDIOC_SET_PRETIMEOUT     _IOW(WATCHDOG_IOCTL_BASE, 21, int)
-#endif
-#ifndef WDIOC_GET_PRETIMEOUT
-#define	WDIOC_GET_PRETIMEOUT     _IOW(WATCHDOG_IOCTL_BASE, 22, int)
-#endif
-
 static DEFINE_MUTEX(ipmi_watchdog_mutex);
 static bool nowayout = WATCHDOG_NOWAYOUT;
 
@@ -732,7 +721,6 @@ static int ipmi_ioctl(struct file *file,
 			return -EFAULT;
 		return 0;
 
-	case WDIOC_SET_PRETIMEOUT:
 	case WDIOC_SETPRETIMEOUT:
 		i = copy_from_user(&val, argp, sizeof(int));
 		if (i)
@@ -740,7 +728,6 @@ static int ipmi_ioctl(struct file *file,
 		pretimeout = val;
 		return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
 
-	case WDIOC_GET_PRETIMEOUT:
 	case WDIOC_GETPRETIMEOUT:
 		i = copy_to_user(argp, &pretimeout, sizeof(pretimeout));
 		if (i)
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index d45c334..a0e2f7d 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -30,7 +30,6 @@
 
 #include <asm/hardware/dec21285.h>
 #include <asm/io.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
 
@@ -179,9 +178,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf,
 
 	written = 0;
 
-	leds_event(led_claim);
-	leds_event(led_green_on);
-
 	nBlock = (int) p >> 16;	//block # of 64K bytes
 
 	/*
@@ -258,11 +254,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf,
 			printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written);
 	}
 
-	/*
-	 * restore reg on exit
-	 */
-	leds_event(led_release);
-
 	mutex_unlock(&nwflash_mutex);
 
 	return written;
@@ -334,11 +325,6 @@ static int erase_block(int nBlock)
 	int temp, temp1;
 
 	/*
-	 * orange LED == erase
-	 */
-	leds_event(led_amber_on);
-
-	/*
 	 * reset footbridge to the correct offset 0 (...0..3)
 	 */
 	*CSR_ROMWRITEREG = 0;
@@ -446,12 +432,6 @@ static int write_block(unsigned long p, const char __user *buf, int count)
 	unsigned long timeout;
 	unsigned long timeout1;
 
-	/*
-	 * red LED == write
-	 */
-	leds_event(led_amber_off);
-	leds_event(led_red_on);
-
 	pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p));
 
 	/*
@@ -558,17 +538,9 @@ static int write_block(unsigned long p, const char __user *buf, int count)
 					       pWritePtr - FLASH_BASE);
 
 				/*
-				 * no LED == waiting
-				 */
-				leds_event(led_amber_off);
-				/*
 				 * wait couple ms
 				 */
 				msleep(10);
-				/*
-				 * red LED == write
-				 */
-				leds_event(led_red_on);
 
 				goto WriteRetry;
 			} else {
@@ -583,12 +555,6 @@ static int write_block(unsigned long p, const char __user *buf, int count)
 		}
 	}
 
-	/*
-	 * green LED == read/verify
-	 */
-	leds_event(led_amber_off);
-	leds_event(led_green_on);
-
 	msleep(10);
 
 	pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p));
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index ad7c732..d39b1f6 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -827,10 +827,10 @@ EXPORT_SYMBOL_GPL(tpm_pcr_extend);
 int tpm_do_selftest(struct tpm_chip *chip)
 {
 	int rc;
-	u8 digest[TPM_DIGEST_SIZE];
 	unsigned int loops;
 	unsigned int delay_msec = 1000;
 	unsigned long duration;
+	struct tpm_cmd_t cmd;
 
 	duration = tpm_calc_ordinal_duration(chip,
 	                                     TPM_ORD_CONTINUE_SELFTEST);
@@ -845,7 +845,15 @@ int tpm_do_selftest(struct tpm_chip *chip)
 		return rc;
 
 	do {
-		rc = __tpm_pcr_read(chip, 0, digest);
+		/* Attempt to read a PCR value */
+		cmd.header.in = pcrread_header;
+		cmd.params.pcrread_in.pcr_idx = cpu_to_be32(0);
+		rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE);
+
+		if (rc < TPM_HEADER_SIZE)
+			return -EFAULT;
+
+		rc = be32_to_cpu(cmd.header.out.return_code);
 		if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
 			dev_info(chip->dev,
 				 "TPM is disabled/deactivated (0x%X)\n", rc);
@@ -1322,6 +1330,9 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume);
 
 void tpm_dev_vendor_release(struct tpm_chip *chip)
 {
+	if (!chip)
+		return;
+
 	if (chip->vendor.release)
 		chip->vendor.release(chip->dev);
 
@@ -1339,6 +1350,9 @@ void tpm_dev_release(struct device *dev)
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 
+	if (!chip)
+		return;
+
 	tpm_dev_vendor_release(chip);
 
 	chip->release(dev);
@@ -1405,15 +1419,12 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
 			"unable to misc_register %s, minor %d\n",
 			chip->vendor.miscdev.name,
 			chip->vendor.miscdev.minor);
-		put_device(chip->dev);
-		return NULL;
+		goto put_device;
 	}
 
 	if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
 		misc_deregister(&chip->vendor.miscdev);
-		put_device(chip->dev);
-
-		return NULL;
+		goto put_device;
 	}
 
 	chip->bios_dir = tpm_bios_log_setup(devname);
@@ -1425,6 +1436,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
 
 	return chip;
 
+put_device:
+	put_device(chip->dev);
 out_free:
 	kfree(chip);
 	kfree(devname);
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index 76da32e..3251a44 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -4,8 +4,8 @@
  * SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module
  * Specifications at www.trustedcomputinggroup.org
  *
- * Copyright (C) 2005, Marcel Selhorst <m.selhorst@sirrix.com>
- * Sirrix AG - security technologies, http://www.sirrix.com and
+ * Copyright (C) 2005, Marcel Selhorst <tpmdd@selhorst.net>
+ * Sirrix AG - security technologies <tpmdd@sirrix.com> and
  * Applied Data Security Group, Ruhr-University Bochum, Germany
  * Project-Homepage: http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ 
  *
@@ -671,7 +671,7 @@ static void __exit cleanup_inf(void)
 module_init(init_inf);
 module_exit(cleanup_inf);
 
-MODULE_AUTHOR("Marcel Selhorst <m.selhorst@sirrix.com>");
+MODULE_AUTHOR("Marcel Selhorst <tpmdd@sirrix.com>");
 MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
 MODULE_VERSION("1.9.2");
 MODULE_LICENSE("GPL");
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4864407..6835e6a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -25,7 +25,6 @@ menu "Common Clock Framework"
 
 config COMMON_CLK_DEBUG
 	bool "DebugFS representation of clock tree"
-	depends on COMMON_CLK
 	select DEBUG_FS
 	---help---
 	  Creates a directory hierchy in debugfs for visualizing the clk
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index b9a5158..26b6b92 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -3,5 +3,6 @@ obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
 obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-fixed-rate.o clk-gate.o \
 				   clk-mux.o clk-divider.o clk-fixed-factor.o
 # SoCs specific
+obj-$(CONFIG_ARCH_NOMADIK)	+= clk-nomadik.o
 obj-$(CONFIG_ARCH_MXS)		+= mxs/
 obj-$(CONFIG_PLAT_SPEAR)	+= spear/
diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c
new file mode 100644
index 0000000..517a8ff
--- /dev/null
+++ b/drivers/clk/clk-nomadik.c
@@ -0,0 +1,47 @@
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+
+/*
+ * The Nomadik clock tree is described in the STN8815A12 DB V4.2
+ * reference manual for the chip, page 94 ff.
+ */
+
+void __init nomadik_clk_init(void)
+{
+	struct clk *clk;
+
+	clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
+	clk_register_clkdev(clk, "apb_pclk", NULL);
+	clk_register_clkdev(clk, NULL, "gpio.0");
+	clk_register_clkdev(clk, NULL, "gpio.1");
+	clk_register_clkdev(clk, NULL, "gpio.2");
+	clk_register_clkdev(clk, NULL, "gpio.3");
+	clk_register_clkdev(clk, NULL, "rng");
+
+	/*
+	 * The 2.4 MHz TIMCLK reference clock is active at boot time, this is
+	 * actually the MXTALCLK @19.2 MHz divided by 8. This clock is used
+	 * by the timers and watchdog. See page 105 ff.
+	 */
+	clk = clk_register_fixed_rate(NULL, "TIMCLK", NULL, CLK_IS_ROOT,
+				      2400000);
+	clk_register_clkdev(clk, NULL, "mtu0");
+	clk_register_clkdev(clk, NULL, "mtu1");
+
+	/*
+	 * At boot time, PLL2 is set to generate a set of fixed clocks,
+	 * one of them is CLK48, the 48 MHz clock, routed to the UART, MMC/SD
+	 * I2C, IrDA, USB and SSP blocks.
+	 */
+	clk = clk_register_fixed_rate(NULL, "CLK48", NULL, CLK_IS_ROOT,
+				      48000000);
+	clk_register_clkdev(clk, NULL, "uart0");
+	clk_register_clkdev(clk, NULL, "uart1");
+	clk_register_clkdev(clk, NULL, "mmci");
+	clk_register_clkdev(clk, NULL, "ssp");
+	clk_register_clkdev(clk, NULL, "nmk-i2c.0");
+	clk_register_clkdev(clk, NULL, "nmk-i2c.1");
+}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 687b00d..7bd795bf9 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -464,6 +464,9 @@ static void __clk_disable(struct clk *clk)
 	if (!clk)
 		return;
 
+	if (WARN_ON(IS_ERR(clk)))
+		return;
+
 	if (WARN_ON(clk->enable_count == 0))
 		return;
 
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 78a666d..a76b689 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -18,3 +18,6 @@ config CPU_IDLE_GOV_MENU
 	bool
 	depends on CPU_IDLE && NO_HZ
 	default y
+
+config ARCH_NEEDS_CPU_IDLE_COUPLED
+	def_bool n
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 5634f88..38c8f69 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
+obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c
new file mode 100644
index 0000000..2c9bf26
--- /dev/null
+++ b/drivers/cpuidle/coupled.c
@@ -0,0 +1,715 @@
+/*
+ * coupled.c - helper functions to enter the same idle state on multiple cpus
+ *
+ * Copyright (c) 2011 Google, Inc.
+ *
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpu.h>
+#include <linux/cpuidle.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "cpuidle.h"
+
+/**
+ * DOC: Coupled cpuidle states
+ *
+ * On some ARM SMP SoCs (OMAP4460, Tegra 2, and probably more), the
+ * cpus cannot be independently powered down, either due to
+ * sequencing restrictions (on Tegra 2, cpu 0 must be the last to
+ * power down), or due to HW bugs (on OMAP4460, a cpu powering up
+ * will corrupt the gic state unless the other cpu runs a work
+ * around).  Each cpu has a power state that it can enter without
+ * coordinating with the other cpu (usually Wait For Interrupt, or
+ * WFI), and one or more "coupled" power states that affect blocks
+ * shared between the cpus (L2 cache, interrupt controller, and
+ * sometimes the whole SoC).  Entering a coupled power state must
+ * be tightly controlled on both cpus.
+ *
+ * This file implements a solution, where each cpu will wait in the
+ * WFI state until all cpus are ready to enter a coupled state, at
+ * which point the coupled state function will be called on all
+ * cpus at approximately the same time.
+ *
+ * Once all cpus are ready to enter idle, they are woken by an smp
+ * cross call.  At this point, there is a chance that one of the
+ * cpus will find work to do, and choose not to enter idle.  A
+ * final pass is needed to guarantee that all cpus will call the
+ * power state enter function at the same time.  During this pass,
+ * each cpu will increment the ready counter, and continue once the
+ * ready counter matches the number of online coupled cpus.  If any
+ * cpu exits idle, the other cpus will decrement their counter and
+ * retry.
+ *
+ * requested_state stores the deepest coupled idle state each cpu
+ * is ready for.  It is assumed that the states are indexed from
+ * shallowest (highest power, lowest exit latency) to deepest
+ * (lowest power, highest exit latency).  The requested_state
+ * variable is not locked.  It is only written from the cpu that
+ * it stores (or by the on/offlining cpu if that cpu is offline),
+ * and only read after all the cpus are ready for the coupled idle
+ * state are are no longer updating it.
+ *
+ * Three atomic counters are used.  alive_count tracks the number
+ * of cpus in the coupled set that are currently or soon will be
+ * online.  waiting_count tracks the number of cpus that are in
+ * the waiting loop, in the ready loop, or in the coupled idle state.
+ * ready_count tracks the number of cpus that are in the ready loop
+ * or in the coupled idle state.
+ *
+ * To use coupled cpuidle states, a cpuidle driver must:
+ *
+ *    Set struct cpuidle_device.coupled_cpus to the mask of all
+ *    coupled cpus, usually the same as cpu_possible_mask if all cpus
+ *    are part of the same cluster.  The coupled_cpus mask must be
+ *    set in the struct cpuidle_device for each cpu.
+ *
+ *    Set struct cpuidle_device.safe_state to a state that is not a
+ *    coupled state.  This is usually WFI.
+ *
+ *    Set CPUIDLE_FLAG_COUPLED in struct cpuidle_state.flags for each
+ *    state that affects multiple cpus.
+ *
+ *    Provide a struct cpuidle_state.enter function for each state
+ *    that affects multiple cpus.  This function is guaranteed to be
+ *    called on all cpus at approximately the same time.  The driver
+ *    should ensure that the cpus all abort together if any cpu tries
+ *    to abort once the function is called.  The function should return
+ *    with interrupts still disabled.
+ */
+
+/**
+ * struct cpuidle_coupled - data for set of cpus that share a coupled idle state
+ * @coupled_cpus: mask of cpus that are part of the coupled set
+ * @requested_state: array of requested states for cpus in the coupled set
+ * @ready_waiting_counts: combined count of cpus  in ready or waiting loops
+ * @online_count: count of cpus that are online
+ * @refcnt: reference count of cpuidle devices that are using this struct
+ * @prevent: flag to prevent coupled idle while a cpu is hotplugging
+ */
+struct cpuidle_coupled {
+	cpumask_t coupled_cpus;
+	int requested_state[NR_CPUS];
+	atomic_t ready_waiting_counts;
+	int online_count;
+	int refcnt;
+	int prevent;
+};
+
+#define WAITING_BITS 16
+#define MAX_WAITING_CPUS (1 << WAITING_BITS)
+#define WAITING_MASK (MAX_WAITING_CPUS - 1)
+#define READY_MASK (~WAITING_MASK)
+
+#define CPUIDLE_COUPLED_NOT_IDLE	(-1)
+
+static DEFINE_MUTEX(cpuidle_coupled_lock);
+static DEFINE_PER_CPU(struct call_single_data, cpuidle_coupled_poke_cb);
+
+/*
+ * The cpuidle_coupled_poked_mask mask is used to avoid calling
+ * __smp_call_function_single with the per cpu call_single_data struct already
+ * in use.  This prevents a deadlock where two cpus are waiting for each others
+ * call_single_data struct to be available
+ */
+static cpumask_t cpuidle_coupled_poked_mask;
+
+/**
+ * cpuidle_coupled_parallel_barrier - synchronize all online coupled cpus
+ * @dev: cpuidle_device of the calling cpu
+ * @a:   atomic variable to hold the barrier
+ *
+ * No caller to this function will return from this function until all online
+ * cpus in the same coupled group have called this function.  Once any caller
+ * has returned from this function, the barrier is immediately available for
+ * reuse.
+ *
+ * The atomic variable a must be initialized to 0 before any cpu calls
+ * this function, will be reset to 0 before any cpu returns from this function.
+ *
+ * Must only be called from within a coupled idle state handler
+ * (state.enter when state.flags has CPUIDLE_FLAG_COUPLED set).
+ *
+ * Provides full smp barrier semantics before and after calling.
+ */
+void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a)
+{
+	int n = dev->coupled->online_count;
+
+	smp_mb__before_atomic_inc();
+	atomic_inc(a);
+
+	while (atomic_read(a) < n)
+		cpu_relax();
+
+	if (atomic_inc_return(a) == n * 2) {
+		atomic_set(a, 0);
+		return;
+	}
+
+	while (atomic_read(a) > n)
+		cpu_relax();
+}
+
+/**
+ * cpuidle_state_is_coupled - check if a state is part of a coupled set
+ * @dev: struct cpuidle_device for the current cpu
+ * @drv: struct cpuidle_driver for the platform
+ * @state: index of the target state in drv->states
+ *
+ * Returns true if the target state is coupled with cpus besides this one
+ */
+bool cpuidle_state_is_coupled(struct cpuidle_device *dev,
+	struct cpuidle_driver *drv, int state)
+{
+	return drv->states[state].flags & CPUIDLE_FLAG_COUPLED;
+}
+
+/**
+ * cpuidle_coupled_set_ready - mark a cpu as ready
+ * @coupled: the struct coupled that contains the current cpu
+ */
+static inline void cpuidle_coupled_set_ready(struct cpuidle_coupled *coupled)
+{
+	atomic_add(MAX_WAITING_CPUS, &coupled->ready_waiting_counts);
+}
+
+/**
+ * cpuidle_coupled_set_not_ready - mark a cpu as not ready
+ * @coupled: the struct coupled that contains the current cpu
+ *
+ * Decrements the ready counter, unless the ready (and thus the waiting) counter
+ * is equal to the number of online cpus.  Prevents a race where one cpu
+ * decrements the waiting counter and then re-increments it just before another
+ * cpu has decremented its ready counter, leading to the ready counter going
+ * down from the number of online cpus without going through the coupled idle
+ * state.
+ *
+ * Returns 0 if the counter was decremented successfully, -EINVAL if the ready
+ * counter was equal to the number of online cpus.
+ */
+static
+inline int cpuidle_coupled_set_not_ready(struct cpuidle_coupled *coupled)
+{
+	int all;
+	int ret;
+
+	all = coupled->online_count || (coupled->online_count << WAITING_BITS);
+	ret = atomic_add_unless(&coupled->ready_waiting_counts,
+		-MAX_WAITING_CPUS, all);
+
+	return ret ? 0 : -EINVAL;
+}
+
+/**
+ * cpuidle_coupled_no_cpus_ready - check if no cpus in a coupled set are ready
+ * @coupled: the struct coupled that contains the current cpu
+ *
+ * Returns true if all of the cpus in a coupled set are out of the ready loop.
+ */
+static inline int cpuidle_coupled_no_cpus_ready(struct cpuidle_coupled *coupled)
+{
+	int r = atomic_read(&coupled->ready_waiting_counts) >> WAITING_BITS;
+	return r == 0;
+}
+
+/**
+ * cpuidle_coupled_cpus_ready - check if all cpus in a coupled set are ready
+ * @coupled: the struct coupled that contains the current cpu
+ *
+ * Returns true if all cpus coupled to this target state are in the ready loop
+ */
+static inline bool cpuidle_coupled_cpus_ready(struct cpuidle_coupled *coupled)
+{
+	int r = atomic_read(&coupled->ready_waiting_counts) >> WAITING_BITS;
+	return r == coupled->online_count;
+}
+
+/**
+ * cpuidle_coupled_cpus_waiting - check if all cpus in a coupled set are waiting
+ * @coupled: the struct coupled that contains the current cpu
+ *
+ * Returns true if all cpus coupled to this target state are in the wait loop
+ */
+static inline bool cpuidle_coupled_cpus_waiting(struct cpuidle_coupled *coupled)
+{
+	int w = atomic_read(&coupled->ready_waiting_counts) & WAITING_MASK;
+	return w == coupled->online_count;
+}
+
+/**
+ * cpuidle_coupled_no_cpus_waiting - check if no cpus in coupled set are waiting
+ * @coupled: the struct coupled that contains the current cpu
+ *
+ * Returns true if all of the cpus in a coupled set are out of the waiting loop.
+ */
+static inline int cpuidle_coupled_no_cpus_waiting(struct cpuidle_coupled *coupled)
+{
+	int w = atomic_read(&coupled->ready_waiting_counts) & WAITING_MASK;
+	return w == 0;
+}
+
+/**
+ * cpuidle_coupled_get_state - determine the deepest idle state
+ * @dev: struct cpuidle_device for this cpu
+ * @coupled: the struct coupled that contains the current cpu
+ *
+ * Returns the deepest idle state that all coupled cpus can enter
+ */
+static inline int cpuidle_coupled_get_state(struct cpuidle_device *dev,
+		struct cpuidle_coupled *coupled)
+{
+	int i;
+	int state = INT_MAX;
+
+	/*
+	 * Read barrier ensures that read of requested_state is ordered after
+	 * reads of ready_count.  Matches the write barriers
+	 * cpuidle_set_state_waiting.
+	 */
+	smp_rmb();
+
+	for_each_cpu_mask(i, coupled->coupled_cpus)
+		if (cpu_online(i) && coupled->requested_state[i] < state)
+			state = coupled->requested_state[i];
+
+	return state;
+}
+
+static void cpuidle_coupled_poked(void *info)
+{
+	int cpu = (unsigned long)info;
+	cpumask_clear_cpu(cpu, &cpuidle_coupled_poked_mask);
+}
+
+/**
+ * cpuidle_coupled_poke - wake up a cpu that may be waiting
+ * @cpu: target cpu
+ *
+ * Ensures that the target cpu exits it's waiting idle state (if it is in it)
+ * and will see updates to waiting_count before it re-enters it's waiting idle
+ * state.
+ *
+ * If cpuidle_coupled_poked_mask is already set for the target cpu, that cpu
+ * either has or will soon have a pending IPI that will wake it out of idle,
+ * or it is currently processing the IPI and is not in idle.
+ */
+static void cpuidle_coupled_poke(int cpu)
+{
+	struct call_single_data *csd = &per_cpu(cpuidle_coupled_poke_cb, cpu);
+
+	if (!cpumask_test_and_set_cpu(cpu, &cpuidle_coupled_poked_mask))
+		__smp_call_function_single(cpu, csd, 0);
+}
+
+/**
+ * cpuidle_coupled_poke_others - wake up all other cpus that may be waiting
+ * @dev: struct cpuidle_device for this cpu
+ * @coupled: the struct coupled that contains the current cpu
+ *
+ * Calls cpuidle_coupled_poke on all other online cpus.
+ */
+static void cpuidle_coupled_poke_others(int this_cpu,
+		struct cpuidle_coupled *coupled)
+{
+	int cpu;
+
+	for_each_cpu_mask(cpu, coupled->coupled_cpus)
+		if (cpu != this_cpu && cpu_online(cpu))
+			cpuidle_coupled_poke(cpu);
+}
+
+/**
+ * cpuidle_coupled_set_waiting - mark this cpu as in the wait loop
+ * @dev: struct cpuidle_device for this cpu
+ * @coupled: the struct coupled that contains the current cpu
+ * @next_state: the index in drv->states of the requested state for this cpu
+ *
+ * Updates the requested idle state for the specified cpuidle device,
+ * poking all coupled cpus out of idle if necessary to let them see the new
+ * state.
+ */
+static void cpuidle_coupled_set_waiting(int cpu,
+		struct cpuidle_coupled *coupled, int next_state)
+{
+	int w;
+
+	coupled->requested_state[cpu] = next_state;
+
+	/*
+	 * If this is the last cpu to enter the waiting state, poke
+	 * all the other cpus out of their waiting state so they can
+	 * enter a deeper state.  This can race with one of the cpus
+	 * exiting the waiting state due to an interrupt and
+	 * decrementing waiting_count, see comment below.
+	 *
+	 * The atomic_inc_return provides a write barrier to order the write
+	 * to requested_state with the later write that increments ready_count.
+	 */
+	w = atomic_inc_return(&coupled->ready_waiting_counts) & WAITING_MASK;
+	if (w == coupled->online_count)
+		cpuidle_coupled_poke_others(cpu, coupled);
+}
+
+/**
+ * cpuidle_coupled_set_not_waiting - mark this cpu as leaving the wait loop
+ * @dev: struct cpuidle_device for this cpu
+ * @coupled: the struct coupled that contains the current cpu
+ *
+ * Removes the requested idle state for the specified cpuidle device.
+ */
+static void cpuidle_coupled_set_not_waiting(int cpu,
+		struct cpuidle_coupled *coupled)
+{
+	/*
+	 * Decrementing waiting count can race with incrementing it in
+	 * cpuidle_coupled_set_waiting, but that's OK.  Worst case, some
+	 * cpus will increment ready_count and then spin until they
+	 * notice that this cpu has cleared it's requested_state.
+	 */
+	atomic_dec(&coupled->ready_waiting_counts);
+
+	coupled->requested_state[cpu] = CPUIDLE_COUPLED_NOT_IDLE;
+}
+
+/**
+ * cpuidle_coupled_set_done - mark this cpu as leaving the ready loop
+ * @cpu: the current cpu
+ * @coupled: the struct coupled that contains the current cpu
+ *
+ * Marks this cpu as no longer in the ready and waiting loops.  Decrements
+ * the waiting count first to prevent another cpu looping back in and seeing
+ * this cpu as waiting just before it exits idle.
+ */
+static void cpuidle_coupled_set_done(int cpu, struct cpuidle_coupled *coupled)
+{
+	cpuidle_coupled_set_not_waiting(cpu, coupled);
+	atomic_sub(MAX_WAITING_CPUS, &coupled->ready_waiting_counts);
+}
+
+/**
+ * cpuidle_coupled_clear_pokes - spin until the poke interrupt is processed
+ * @cpu - this cpu
+ *
+ * Turns on interrupts and spins until any outstanding poke interrupts have
+ * been processed and the poke bit has been cleared.
+ *
+ * Other interrupts may also be processed while interrupts are enabled, so
+ * need_resched() must be tested after turning interrupts off again to make sure
+ * the interrupt didn't schedule work that should take the cpu out of idle.
+ *
+ * Returns 0 if need_resched was false, -EINTR if need_resched was true.
+ */
+static int cpuidle_coupled_clear_pokes(int cpu)
+{
+	local_irq_enable();
+	while (cpumask_test_cpu(cpu, &cpuidle_coupled_poked_mask))
+		cpu_relax();
+	local_irq_disable();
+
+	return need_resched() ? -EINTR : 0;
+}
+
+/**
+ * cpuidle_enter_state_coupled - attempt to enter a state with coupled cpus
+ * @dev: struct cpuidle_device for the current cpu
+ * @drv: struct cpuidle_driver for the platform
+ * @next_state: index of the requested state in drv->states
+ *
+ * Coordinate with coupled cpus to enter the target state.  This is a two
+ * stage process.  In the first stage, the cpus are operating independently,
+ * and may call into cpuidle_enter_state_coupled at completely different times.
+ * To save as much power as possible, the first cpus to call this function will
+ * go to an intermediate state (the cpuidle_device's safe state), and wait for
+ * all the other cpus to call this function.  Once all coupled cpus are idle,
+ * the second stage will start.  Each coupled cpu will spin until all cpus have
+ * guaranteed that they will call the target_state.
+ *
+ * This function must be called with interrupts disabled.  It may enable
+ * interrupts while preparing for idle, and it will always return with
+ * interrupts enabled.
+ */
+int cpuidle_enter_state_coupled(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int next_state)
+{
+	int entered_state = -1;
+	struct cpuidle_coupled *coupled = dev->coupled;
+
+	if (!coupled)
+		return -EINVAL;
+
+	while (coupled->prevent) {
+		if (cpuidle_coupled_clear_pokes(dev->cpu)) {
+			local_irq_enable();
+			return entered_state;
+		}
+		entered_state = cpuidle_enter_state(dev, drv,
+			dev->safe_state_index);
+	}
+
+	/* Read barrier ensures online_count is read after prevent is cleared */
+	smp_rmb();
+
+	cpuidle_coupled_set_waiting(dev->cpu, coupled, next_state);
+
+retry:
+	/*
+	 * Wait for all coupled cpus to be idle, using the deepest state
+	 * allowed for a single cpu.
+	 */
+	while (!cpuidle_coupled_cpus_waiting(coupled)) {
+		if (cpuidle_coupled_clear_pokes(dev->cpu)) {
+			cpuidle_coupled_set_not_waiting(dev->cpu, coupled);
+			goto out;
+		}
+
+		if (coupled->prevent) {
+			cpuidle_coupled_set_not_waiting(dev->cpu, coupled);
+			goto out;
+		}
+
+		entered_state = cpuidle_enter_state(dev, drv,
+			dev->safe_state_index);
+	}
+
+	if (cpuidle_coupled_clear_pokes(dev->cpu)) {
+		cpuidle_coupled_set_not_waiting(dev->cpu, coupled);
+		goto out;
+	}
+
+	/*
+	 * All coupled cpus are probably idle.  There is a small chance that
+	 * one of the other cpus just became active.  Increment the ready count,
+	 * and spin until all coupled cpus have incremented the counter. Once a
+	 * cpu has incremented the ready counter, it cannot abort idle and must
+	 * spin until either all cpus have incremented the ready counter, or
+	 * another cpu leaves idle and decrements the waiting counter.
+	 */
+
+	cpuidle_coupled_set_ready(coupled);
+	while (!cpuidle_coupled_cpus_ready(coupled)) {
+		/* Check if any other cpus bailed out of idle. */
+		if (!cpuidle_coupled_cpus_waiting(coupled))
+			if (!cpuidle_coupled_set_not_ready(coupled))
+				goto retry;
+
+		cpu_relax();
+	}
+
+	/* all cpus have acked the coupled state */
+	next_state = cpuidle_coupled_get_state(dev, coupled);
+
+	entered_state = cpuidle_enter_state(dev, drv, next_state);
+
+	cpuidle_coupled_set_done(dev->cpu, coupled);
+
+out:
+	/*
+	 * Normal cpuidle states are expected to return with irqs enabled.
+	 * That leads to an inefficiency where a cpu receiving an interrupt
+	 * that brings it out of idle will process that interrupt before
+	 * exiting the idle enter function and decrementing ready_count.  All
+	 * other cpus will need to spin waiting for the cpu that is processing
+	 * the interrupt.  If the driver returns with interrupts disabled,
+	 * all other cpus will loop back into the safe idle state instead of
+	 * spinning, saving power.
+	 *
+	 * Calling local_irq_enable here allows coupled states to return with
+	 * interrupts disabled, but won't cause problems for drivers that
+	 * exit with interrupts enabled.
+	 */
+	local_irq_enable();
+
+	/*
+	 * Wait until all coupled cpus have exited idle.  There is no risk that
+	 * a cpu exits and re-enters the ready state because this cpu has
+	 * already decremented its waiting_count.
+	 */
+	while (!cpuidle_coupled_no_cpus_ready(coupled))
+		cpu_relax();
+
+	return entered_state;
+}
+
+static void cpuidle_coupled_update_online_cpus(struct cpuidle_coupled *coupled)
+{
+	cpumask_t cpus;
+	cpumask_and(&cpus, cpu_online_mask, &coupled->coupled_cpus);
+	coupled->online_count = cpumask_weight(&cpus);
+}
+
+/**
+ * cpuidle_coupled_register_device - register a coupled cpuidle device
+ * @dev: struct cpuidle_device for the current cpu
+ *
+ * Called from cpuidle_register_device to handle coupled idle init.  Finds the
+ * cpuidle_coupled struct for this set of coupled cpus, or creates one if none
+ * exists yet.
+ */
+int cpuidle_coupled_register_device(struct cpuidle_device *dev)
+{
+	int cpu;
+	struct cpuidle_device *other_dev;
+	struct call_single_data *csd;
+	struct cpuidle_coupled *coupled;
+
+	if (cpumask_empty(&dev->coupled_cpus))
+		return 0;
+
+	for_each_cpu_mask(cpu, dev->coupled_cpus) {
+		other_dev = per_cpu(cpuidle_devices, cpu);
+		if (other_dev && other_dev->coupled) {
+			coupled = other_dev->coupled;
+			goto have_coupled;
+		}
+	}
+
+	/* No existing coupled info found, create a new one */
+	coupled = kzalloc(sizeof(struct cpuidle_coupled), GFP_KERNEL);
+	if (!coupled)
+		return -ENOMEM;
+
+	coupled->coupled_cpus = dev->coupled_cpus;
+
+have_coupled:
+	dev->coupled = coupled;
+	if (WARN_ON(!cpumask_equal(&dev->coupled_cpus, &coupled->coupled_cpus)))
+		coupled->prevent++;
+
+	cpuidle_coupled_update_online_cpus(coupled);
+
+	coupled->refcnt++;
+
+	csd = &per_cpu(cpuidle_coupled_poke_cb, dev->cpu);
+	csd->func = cpuidle_coupled_poked;
+	csd->info = (void *)(unsigned long)dev->cpu;
+
+	return 0;
+}
+
+/**
+ * cpuidle_coupled_unregister_device - unregister a coupled cpuidle device
+ * @dev: struct cpuidle_device for the current cpu
+ *
+ * Called from cpuidle_unregister_device to tear down coupled idle.  Removes the
+ * cpu from the coupled idle set, and frees the cpuidle_coupled_info struct if
+ * this was the last cpu in the set.
+ */
+void cpuidle_coupled_unregister_device(struct cpuidle_device *dev)
+{
+	struct cpuidle_coupled *coupled = dev->coupled;
+
+	if (cpumask_empty(&dev->coupled_cpus))
+		return;
+
+	if (--coupled->refcnt)
+		kfree(coupled);
+	dev->coupled = NULL;
+}
+
+/**
+ * cpuidle_coupled_prevent_idle - prevent cpus from entering a coupled state
+ * @coupled: the struct coupled that contains the cpu that is changing state
+ *
+ * Disables coupled cpuidle on a coupled set of cpus.  Used to ensure that
+ * cpu_online_mask doesn't change while cpus are coordinating coupled idle.
+ */
+static void cpuidle_coupled_prevent_idle(struct cpuidle_coupled *coupled)
+{
+	int cpu = get_cpu();
+
+	/* Force all cpus out of the waiting loop. */
+	coupled->prevent++;
+	cpuidle_coupled_poke_others(cpu, coupled);
+	put_cpu();
+	while (!cpuidle_coupled_no_cpus_waiting(coupled))
+		cpu_relax();
+}
+
+/**
+ * cpuidle_coupled_allow_idle - allows cpus to enter a coupled state
+ * @coupled: the struct coupled that contains the cpu that is changing state
+ *
+ * Enables coupled cpuidle on a coupled set of cpus.  Used to ensure that
+ * cpu_online_mask doesn't change while cpus are coordinating coupled idle.
+ */
+static void cpuidle_coupled_allow_idle(struct cpuidle_coupled *coupled)
+{
+	int cpu = get_cpu();
+
+	/*
+	 * Write barrier ensures readers see the new online_count when they
+	 * see prevent == 0.
+	 */
+	smp_wmb();
+	coupled->prevent--;
+	/* Force cpus out of the prevent loop. */
+	cpuidle_coupled_poke_others(cpu, coupled);
+	put_cpu();
+}
+
+/**
+ * cpuidle_coupled_cpu_notify - notifier called during hotplug transitions
+ * @nb: notifier block
+ * @action: hotplug transition
+ * @hcpu: target cpu number
+ *
+ * Called when a cpu is brought on or offline using hotplug.  Updates the
+ * coupled cpu set appropriately
+ */
+static int cpuidle_coupled_cpu_notify(struct notifier_block *nb,
+		unsigned long action, void *hcpu)
+{
+	int cpu = (unsigned long)hcpu;
+	struct cpuidle_device *dev;
+
+	mutex_lock(&cpuidle_lock);
+
+	dev = per_cpu(cpuidle_devices, cpu);
+	if (!dev->coupled)
+		goto out;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_UP_PREPARE:
+	case CPU_DOWN_PREPARE:
+		cpuidle_coupled_prevent_idle(dev->coupled);
+		break;
+	case CPU_ONLINE:
+	case CPU_DEAD:
+		cpuidle_coupled_update_online_cpus(dev->coupled);
+		/* Fall through */
+	case CPU_UP_CANCELED:
+	case CPU_DOWN_FAILED:
+		cpuidle_coupled_allow_idle(dev->coupled);
+		break;
+	}
+
+out:
+	mutex_unlock(&cpuidle_lock);
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cpuidle_coupled_cpu_notifier = {
+	.notifier_call = cpuidle_coupled_cpu_notify,
+};
+
+static int __init cpuidle_coupled_init(void)
+{
+	return register_cpu_notifier(&cpuidle_coupled_cpu_notifier);
+}
+core_initcall(cpuidle_coupled_init);
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index d90519c..bb4e827 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -92,6 +92,34 @@ int cpuidle_play_dead(void)
 }
 
 /**
+ * cpuidle_enter_state - enter the state and update stats
+ * @dev: cpuidle device for this cpu
+ * @drv: cpuidle driver for this cpu
+ * @next_state: index into drv->states of the state to enter
+ */
+int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
+		int next_state)
+{
+	int entered_state;
+
+	entered_state = cpuidle_enter_ops(dev, drv, next_state);
+
+	if (entered_state >= 0) {
+		/* Update cpuidle counters */
+		/* This can be moved to within driver enter routine
+		 * but that results in multiple copies of same code.
+		 */
+		dev->states_usage[entered_state].time +=
+				(unsigned long long)dev->last_residency;
+		dev->states_usage[entered_state].usage++;
+	} else {
+		dev->last_residency = 0;
+	}
+
+	return entered_state;
+}
+
+/**
  * cpuidle_idle_call - the main idle loop
  *
  * NOTE: no locks or semaphores should be used here
@@ -113,15 +141,6 @@ int cpuidle_idle_call(void)
 	if (!dev || !dev->enabled)
 		return -EBUSY;
 
-#if 0
-	/* shows regressions, re-enable for 2.6.29 */
-	/*
-	 * run any timers that can be run now, at this point
-	 * before calculating the idle duration etc.
-	 */
-	hrtimer_peek_ahead_timers();
-#endif
-
 	/* ask the governor for the next state */
 	next_state = cpuidle_curr_governor->select(drv, dev);
 	if (need_resched()) {
@@ -132,23 +151,15 @@ int cpuidle_idle_call(void)
 	trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu);
 	trace_cpu_idle_rcuidle(next_state, dev->cpu);
 
-	entered_state = cpuidle_enter_ops(dev, drv, next_state);
+	if (cpuidle_state_is_coupled(dev, drv, next_state))
+		entered_state = cpuidle_enter_state_coupled(dev, drv,
+							    next_state);
+	else
+		entered_state = cpuidle_enter_state(dev, drv, next_state);
 
 	trace_power_end_rcuidle(dev->cpu);
 	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
 
-	if (entered_state >= 0) {
-		/* Update cpuidle counters */
-		/* This can be moved to within driver enter routine
-		 * but that results in multiple copies of same code.
-		 */
-		dev->states_usage[entered_state].time +=
-				(unsigned long long)dev->last_residency;
-		dev->states_usage[entered_state].usage++;
-	} else {
-		dev->last_residency = 0;
-	}
-
 	/* give the governor an opportunity to reflect on the outcome */
 	if (cpuidle_curr_governor->reflect)
 		cpuidle_curr_governor->reflect(dev, entered_state);
@@ -283,6 +294,9 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
 	int ret, i;
 	struct cpuidle_driver *drv = cpuidle_get_driver();
 
+	if (!dev)
+		return -EINVAL;
+
 	if (dev->enabled)
 		return 0;
 	if (!drv || !cpuidle_curr_governor)
@@ -367,8 +381,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
 	struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu);
 	struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
 
-	if (!dev)
-		return -EINVAL;
 	if (!try_module_get(cpuidle_driver->owner))
 		return -EINVAL;
 
@@ -376,13 +388,25 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
 
 	per_cpu(cpuidle_devices, dev->cpu) = dev;
 	list_add(&dev->device_list, &cpuidle_detected_devices);
-	if ((ret = cpuidle_add_sysfs(cpu_dev))) {
-		module_put(cpuidle_driver->owner);
-		return ret;
-	}
+	ret = cpuidle_add_sysfs(cpu_dev);
+	if (ret)
+		goto err_sysfs;
+
+	ret = cpuidle_coupled_register_device(dev);
+	if (ret)
+		goto err_coupled;
 
 	dev->registered = 1;
 	return 0;
+
+err_coupled:
+	cpuidle_remove_sysfs(cpu_dev);
+	wait_for_completion(&dev->kobj_unregister);
+err_sysfs:
+	list_del(&dev->device_list);
+	per_cpu(cpuidle_devices, dev->cpu) = NULL;
+	module_put(cpuidle_driver->owner);
+	return ret;
 }
 
 /**
@@ -393,6 +417,9 @@ int cpuidle_register_device(struct cpuidle_device *dev)
 {
 	int ret;
 
+	if (!dev)
+		return -EINVAL;
+
 	mutex_lock(&cpuidle_lock);
 
 	if ((ret = __cpuidle_register_device(dev))) {
@@ -432,6 +459,8 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
 	wait_for_completion(&dev->kobj_unregister);
 	per_cpu(cpuidle_devices, dev->cpu) = NULL;
 
+	cpuidle_coupled_unregister_device(dev);
+
 	cpuidle_resume_and_unlock();
 
 	module_put(cpuidle_driver->owner);
diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h
index 7db1866..76e7f69 100644
--- a/drivers/cpuidle/cpuidle.h
+++ b/drivers/cpuidle/cpuidle.h
@@ -14,6 +14,8 @@ extern struct list_head cpuidle_detected_devices;
 extern struct mutex cpuidle_lock;
 extern spinlock_t cpuidle_driver_lock;
 extern int cpuidle_disabled(void);
+extern int cpuidle_enter_state(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int next_state);
 
 /* idle loop */
 extern void cpuidle_install_idle_handler(void);
@@ -30,4 +32,34 @@ extern void cpuidle_remove_state_sysfs(struct cpuidle_device *device);
 extern int cpuidle_add_sysfs(struct device *dev);
 extern void cpuidle_remove_sysfs(struct device *dev);
 
+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
+bool cpuidle_state_is_coupled(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int state);
+int cpuidle_enter_state_coupled(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int next_state);
+int cpuidle_coupled_register_device(struct cpuidle_device *dev);
+void cpuidle_coupled_unregister_device(struct cpuidle_device *dev);
+#else
+static inline bool cpuidle_state_is_coupled(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int state)
+{
+	return false;
+}
+
+static inline int cpuidle_enter_state_coupled(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int next_state)
+{
+	return -1;
+}
+
+static inline int cpuidle_coupled_register_device(struct cpuidle_device *dev)
+{
+	return 0;
+}
+
+static inline void cpuidle_coupled_unregister_device(struct cpuidle_device *dev)
+{
+}
+#endif
+
 #endif /* __DRIVER_CPUIDLE_H */
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 40cd3f3..58bf3b1 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -16,6 +16,7 @@
 
 static struct cpuidle_driver *cpuidle_curr_driver;
 DEFINE_SPINLOCK(cpuidle_driver_lock);
+int cpuidle_driver_refcount;
 
 static void __cpuidle_register_driver(struct cpuidle_driver *drv)
 {
@@ -89,8 +90,34 @@ void cpuidle_unregister_driver(struct cpuidle_driver *drv)
 	}
 
 	spin_lock(&cpuidle_driver_lock);
-	cpuidle_curr_driver = NULL;
+
+	if (!WARN_ON(cpuidle_driver_refcount > 0))
+		cpuidle_curr_driver = NULL;
+
 	spin_unlock(&cpuidle_driver_lock);
 }
 
 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
+
+struct cpuidle_driver *cpuidle_driver_ref(void)
+{
+	struct cpuidle_driver *drv;
+
+	spin_lock(&cpuidle_driver_lock);
+
+	drv = cpuidle_curr_driver;
+	cpuidle_driver_refcount++;
+
+	spin_unlock(&cpuidle_driver_lock);
+	return drv;
+}
+
+void cpuidle_driver_unref(void)
+{
+	spin_lock(&cpuidle_driver_lock);
+
+	if (!WARN_ON(cpuidle_driver_refcount <= 0))
+		cpuidle_driver_refcount--;
+
+	spin_unlock(&cpuidle_driver_lock);
+}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 1092a77..dd4d5af 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -325,4 +325,11 @@ if CRYPTO_DEV_UX500
 	source "drivers/crypto/ux500/Kconfig"
 endif # if CRYPTO_DEV_UX500
 
+config CRYPTO_DEV_BFIN_CRC
+	tristate "Support for Blackfin CRC hardware"
+	depends on BF60x
+	help
+	  Newer Blackfin processors have CRC hardware. Select this if you
+	  want to use the Blackfin CRC module.
+
 endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 0139032..d5062bb 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -14,4 +14,5 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
 obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
 obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
 obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
-obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
\ No newline at end of file
+obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
+obj-$(CONFIG_CRYPTO_DEV_BFIN_CRC) += bfin_crc.o
diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c
new file mode 100644
index 0000000..5398580
--- /dev/null
+++ b/drivers/crypto/bfin_crc.c
@@ -0,0 +1,780 @@
+/*
+ * Cryptographic API.
+ *
+ * Support Blackfin CRC HW acceleration.
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/unaligned/access_ok.h>
+#include <linux/crypto.h>
+#include <linux/cryptohash.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include <crypto/internal/hash.h>
+
+#include <asm/blackfin.h>
+#include <asm/bfin_crc.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#define CRC_CCRYPTO_QUEUE_LENGTH	5
+
+#define DRIVER_NAME "bfin-hmac-crc"
+#define CHKSUM_DIGEST_SIZE      4
+#define CHKSUM_BLOCK_SIZE       1
+
+#define CRC_MAX_DMA_DESC	100
+
+#define CRC_CRYPTO_STATE_UPDATE		1
+#define CRC_CRYPTO_STATE_FINALUPDATE	2
+#define CRC_CRYPTO_STATE_FINISH		3
+
+struct bfin_crypto_crc {
+	struct list_head	list;
+	struct device		*dev;
+	spinlock_t		lock;
+
+	int			irq;
+	int			dma_ch;
+	u32			poly;
+	volatile struct crc_register *regs;
+
+	struct ahash_request	*req; /* current request in operation */
+	struct dma_desc_array	*sg_cpu; /* virt addr of sg dma descriptors */
+	dma_addr_t		sg_dma; /* phy addr of sg dma descriptors */
+	u8			*sg_mid_buf;
+
+	struct tasklet_struct	done_task;
+	struct crypto_queue	queue; /* waiting requests */
+
+	u8			busy:1; /* crc device in operation flag */
+};
+
+static struct bfin_crypto_crc_list {
+	struct list_head	dev_list;
+	spinlock_t		lock;
+} crc_list;
+
+struct bfin_crypto_crc_reqctx {
+	struct bfin_crypto_crc	*crc;
+
+	unsigned int		total;	/* total request bytes */
+	size_t			sg_buflen; /* bytes for this update */
+	unsigned int		sg_nents;
+	struct scatterlist	*sg; /* sg list head for this update*/
+	struct scatterlist	bufsl[2]; /* chained sg list */
+
+	size_t			bufnext_len;
+	size_t			buflast_len;
+	u8			bufnext[CHKSUM_DIGEST_SIZE]; /* extra bytes for next udpate */
+	u8			buflast[CHKSUM_DIGEST_SIZE]; /* extra bytes from last udpate */
+
+	u8			flag;
+};
+
+struct bfin_crypto_crc_ctx {
+	struct bfin_crypto_crc	*crc;
+	u32			key;
+};
+
+
+/*
+ * derive number of elements in scatterlist
+ */
+static int sg_count(struct scatterlist *sg_list)
+{
+	struct scatterlist *sg = sg_list;
+	int sg_nents = 1;
+
+	if (sg_list == NULL)
+		return 0;
+
+	while (!sg_is_last(sg)) {
+		sg_nents++;
+		sg = scatterwalk_sg_next(sg);
+	}
+
+	return sg_nents;
+}
+
+/*
+ * get element in scatter list by given index
+ */
+static struct scatterlist *sg_get(struct scatterlist *sg_list, unsigned int nents,
+				unsigned int index)
+{
+	struct scatterlist *sg = NULL;
+	int i;
+
+	for_each_sg(sg_list, sg, nents, i)
+		if (i == index)
+			break;
+
+	return sg;
+}
+
+static int bfin_crypto_crc_init_hw(struct bfin_crypto_crc *crc, u32 key)
+{
+	crc->regs->datacntrld = 0;
+	crc->regs->control = MODE_CALC_CRC << OPMODE_OFFSET;
+	crc->regs->curresult = key;
+
+	/* setup CRC interrupts */
+	crc->regs->status = CMPERRI | DCNTEXPI;
+	crc->regs->intrenset = CMPERRI | DCNTEXPI;
+	SSYNC();
+
+	return 0;
+}
+
+static int bfin_crypto_crc_init(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
+	struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
+	struct bfin_crypto_crc *crc;
+
+	dev_dbg(crc->dev, "crc_init\n");
+	spin_lock_bh(&crc_list.lock);
+	list_for_each_entry(crc, &crc_list.dev_list, list) {
+		crc_ctx->crc = crc;
+		break;
+	}
+	spin_unlock_bh(&crc_list.lock);
+
+	if (sg_count(req->src) > CRC_MAX_DMA_DESC) {
+		dev_dbg(crc->dev, "init: requested sg list is too big > %d\n",
+			CRC_MAX_DMA_DESC);
+		return -EINVAL;
+	}
+
+	ctx->crc = crc;
+	ctx->bufnext_len = 0;
+	ctx->buflast_len = 0;
+	ctx->sg_buflen = 0;
+	ctx->total = 0;
+	ctx->flag = 0;
+
+	/* init crc results */
+	put_unaligned_le32(crc_ctx->key, req->result);
+
+	dev_dbg(crc->dev, "init: digest size: %d\n",
+		crypto_ahash_digestsize(tfm));
+
+	return bfin_crypto_crc_init_hw(crc, crc_ctx->key);
+}
+
+static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc)
+{
+	struct scatterlist *sg;
+	struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(crc->req);
+	int i = 0, j = 0;
+	unsigned long dma_config;
+	unsigned int dma_count;
+	unsigned int dma_addr;
+	unsigned int mid_dma_count = 0;
+	int dma_mod;
+
+	dma_map_sg(crc->dev, ctx->sg, ctx->sg_nents, DMA_TO_DEVICE);
+
+	for_each_sg(ctx->sg, sg, ctx->sg_nents, j) {
+		dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32;
+		dma_addr = sg_dma_address(sg);
+		/* deduce extra bytes in last sg */
+		if (sg_is_last(sg))
+			dma_count = sg_dma_len(sg) - ctx->bufnext_len;
+		else
+			dma_count = sg_dma_len(sg);
+
+		if (mid_dma_count) {
+			/* Append last middle dma buffer to 4 bytes with first
+			   bytes in current sg buffer. Move addr of current
+			   sg and deduce the length of current sg.
+			 */
+			memcpy(crc->sg_mid_buf +((i-1) << 2) + mid_dma_count,
+				(void *)dma_addr,
+				CHKSUM_DIGEST_SIZE - mid_dma_count);
+			dma_addr += CHKSUM_DIGEST_SIZE - mid_dma_count;
+			dma_count -= CHKSUM_DIGEST_SIZE - mid_dma_count;
+		}
+		/* chop current sg dma len to multiple of 32 bits */
+		mid_dma_count = dma_count % 4;
+		dma_count &= ~0x3;
+
+		if (dma_addr % 4 == 0) {
+			dma_config |= WDSIZE_32;
+			dma_count >>= 2;
+			dma_mod = 4;
+		} else if (dma_addr % 2 == 0) {
+			dma_config |= WDSIZE_16;
+			dma_count >>= 1;
+			dma_mod = 2;
+		} else {
+			dma_config |= WDSIZE_8;
+			dma_mod = 1;
+		}
+
+		crc->sg_cpu[i].start_addr = dma_addr;
+		crc->sg_cpu[i].cfg = dma_config;
+		crc->sg_cpu[i].x_count = dma_count;
+		crc->sg_cpu[i].x_modify = dma_mod;
+		dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
+			"cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
+			i, crc->sg_cpu[i].start_addr,
+			crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
+			crc->sg_cpu[i].x_modify);
+		i++;
+
+		if (mid_dma_count) {
+			/* copy extra bytes to next middle dma buffer */
+			dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 |
+				DMAEN | PSIZE_32 | WDSIZE_32;
+			memcpy(crc->sg_mid_buf + (i << 2),
+				(void *)(dma_addr + (dma_count << 2)),
+				mid_dma_count);
+			/* setup new dma descriptor for next middle dma */
+			crc->sg_cpu[i].start_addr = dma_map_single(crc->dev,
+					crc->sg_mid_buf + (i << 2),
+					CHKSUM_DIGEST_SIZE, DMA_TO_DEVICE);
+			crc->sg_cpu[i].cfg = dma_config;
+			crc->sg_cpu[i].x_count = 1;
+			crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE;
+			dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
+				"cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
+				i, crc->sg_cpu[i].start_addr,
+				crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
+				crc->sg_cpu[i].x_modify);
+			i++;
+		}
+	}
+
+	dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32 | WDSIZE_32;
+	/* For final update req, append the buffer for next update as well*/
+	if (ctx->bufnext_len && (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE ||
+		ctx->flag == CRC_CRYPTO_STATE_FINISH)) {
+		crc->sg_cpu[i].start_addr = dma_map_single(crc->dev, ctx->bufnext,
+						CHKSUM_DIGEST_SIZE, DMA_TO_DEVICE);
+		crc->sg_cpu[i].cfg = dma_config;
+		crc->sg_cpu[i].x_count = 1;
+		crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE;
+		dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
+			"cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
+			i, crc->sg_cpu[i].start_addr,
+			crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
+			crc->sg_cpu[i].x_modify);
+		i++;
+	}
+
+	if (i == 0)
+		return;
+
+	flush_dcache_range((unsigned int)crc->sg_cpu,
+			(unsigned int)crc->sg_cpu +
+			i * sizeof(struct dma_desc_array));
+
+	/* Set the last descriptor to stop mode */
+	crc->sg_cpu[i - 1].cfg &= ~(DMAFLOW | NDSIZE);
+	crc->sg_cpu[i - 1].cfg |= DI_EN;
+	set_dma_curr_desc_addr(crc->dma_ch, (unsigned long *)crc->sg_dma);
+	set_dma_x_count(crc->dma_ch, 0);
+	set_dma_x_modify(crc->dma_ch, 0);
+	SSYNC();
+	set_dma_config(crc->dma_ch, dma_config);
+}
+
+static int bfin_crypto_crc_handle_queue(struct bfin_crypto_crc *crc,
+				  struct ahash_request *req)
+{
+	struct crypto_async_request *async_req, *backlog;
+	struct bfin_crypto_crc_reqctx *ctx;
+	struct scatterlist *sg;
+	int ret = 0;
+	int nsg, i, j;
+	unsigned int nextlen;
+	unsigned long flags;
+
+	spin_lock_irqsave(&crc->lock, flags);
+	if (req)
+		ret = ahash_enqueue_request(&crc->queue, req);
+	if (crc->busy) {
+		spin_unlock_irqrestore(&crc->lock, flags);
+		return ret;
+	}
+	backlog = crypto_get_backlog(&crc->queue);
+	async_req = crypto_dequeue_request(&crc->queue);
+	if (async_req)
+		crc->busy = 1;
+	spin_unlock_irqrestore(&crc->lock, flags);
+
+	if (!async_req)
+		return ret;
+
+	if (backlog)
+		backlog->complete(backlog, -EINPROGRESS);
+
+	req = ahash_request_cast(async_req);
+	crc->req = req;
+	ctx = ahash_request_ctx(req);
+	ctx->sg = NULL;
+	ctx->sg_buflen = 0;
+	ctx->sg_nents = 0;
+
+	dev_dbg(crc->dev, "handling new req, flag=%u, nbytes: %d\n",
+						ctx->flag, req->nbytes);
+
+	if (ctx->flag == CRC_CRYPTO_STATE_FINISH) {
+		if (ctx->bufnext_len == 0) {
+			crc->busy = 0;
+			return 0;
+		}
+
+		/* Pack last crc update buffer to 32bit */
+		memset(ctx->bufnext + ctx->bufnext_len, 0,
+				CHKSUM_DIGEST_SIZE - ctx->bufnext_len);
+	} else {
+		/* Pack small data which is less than 32bit to buffer for next update. */
+		if (ctx->bufnext_len + req->nbytes < CHKSUM_DIGEST_SIZE) {
+			memcpy(ctx->bufnext + ctx->bufnext_len,
+				sg_virt(req->src), req->nbytes);
+			ctx->bufnext_len += req->nbytes;
+			if (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE &&
+				ctx->bufnext_len) {
+				goto finish_update;
+			} else {
+				crc->busy = 0;
+				return 0;
+			}
+		}
+
+		if (ctx->bufnext_len) {
+			/* Chain in extra bytes of last update */
+			ctx->buflast_len = ctx->bufnext_len;
+			memcpy(ctx->buflast, ctx->bufnext, ctx->buflast_len);
+
+			nsg = ctx->sg_buflen ? 2 : 1;
+			sg_init_table(ctx->bufsl, nsg);
+			sg_set_buf(ctx->bufsl, ctx->buflast, ctx->buflast_len);
+			if (nsg > 1)
+				scatterwalk_sg_chain(ctx->bufsl, nsg,
+						req->src);
+			ctx->sg = ctx->bufsl;
+		} else
+			ctx->sg = req->src;
+
+		/* Chop crc buffer size to multiple of 32 bit */
+		nsg = ctx->sg_nents = sg_count(ctx->sg);
+		ctx->sg_buflen = ctx->buflast_len + req->nbytes;
+		ctx->bufnext_len = ctx->sg_buflen % 4;
+		ctx->sg_buflen &= ~0x3;
+
+		if (ctx->bufnext_len) {
+			/* copy extra bytes to buffer for next update */
+			memset(ctx->bufnext, 0, CHKSUM_DIGEST_SIZE);
+			nextlen = ctx->bufnext_len;
+			for (i = nsg - 1; i >= 0; i--) {
+				sg = sg_get(ctx->sg, nsg, i);
+				j = min(nextlen, sg_dma_len(sg));
+				memcpy(ctx->bufnext + nextlen - j,
+					sg_virt(sg) + sg_dma_len(sg) - j, j);
+				if (j == sg_dma_len(sg))
+					ctx->sg_nents--;
+				nextlen -= j;
+				if (nextlen == 0)
+					break;
+			}
+		}
+	}
+
+finish_update:
+	if (ctx->bufnext_len && (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE ||
+		ctx->flag == CRC_CRYPTO_STATE_FINISH))
+		ctx->sg_buflen += CHKSUM_DIGEST_SIZE;
+
+	/* set CRC data count before start DMA */
+	crc->regs->datacnt = ctx->sg_buflen >> 2;
+
+	/* setup and enable CRC DMA */
+	bfin_crypto_crc_config_dma(crc);
+
+	/* finally kick off CRC operation */
+	crc->regs->control |= BLKEN;
+	SSYNC();
+
+	return -EINPROGRESS;
+}
+
+static int bfin_crypto_crc_update(struct ahash_request *req)
+{
+	struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
+
+	if (!req->nbytes)
+		return 0;
+
+	dev_dbg(ctx->crc->dev, "crc_update\n");
+	ctx->total += req->nbytes;
+	ctx->flag = CRC_CRYPTO_STATE_UPDATE;
+
+	return bfin_crypto_crc_handle_queue(ctx->crc, req);
+}
+
+static int bfin_crypto_crc_final(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
+	struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
+
+	dev_dbg(ctx->crc->dev, "crc_final\n");
+	ctx->flag = CRC_CRYPTO_STATE_FINISH;
+	crc_ctx->key = 0;
+
+	return bfin_crypto_crc_handle_queue(ctx->crc, req);
+}
+
+static int bfin_crypto_crc_finup(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
+	struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
+
+	dev_dbg(ctx->crc->dev, "crc_finishupdate\n");
+	ctx->total += req->nbytes;
+	ctx->flag = CRC_CRYPTO_STATE_FINALUPDATE;
+	crc_ctx->key = 0;
+
+	return bfin_crypto_crc_handle_queue(ctx->crc, req);
+}
+
+static int bfin_crypto_crc_digest(struct ahash_request *req)
+{
+	int ret;
+
+	ret = bfin_crypto_crc_init(req);
+	if (ret)
+		return ret;
+
+	return bfin_crypto_crc_finup(req);
+}
+
+static int bfin_crypto_crc_setkey(struct crypto_ahash *tfm, const u8 *key,
+			unsigned int keylen)
+{
+	struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
+
+	dev_dbg(crc_ctx->crc->dev, "crc_setkey\n");
+	if (keylen != CHKSUM_DIGEST_SIZE) {
+		crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+
+	crc_ctx->key = get_unaligned_le32(key);
+
+	return 0;
+}
+
+static int bfin_crypto_crc_cra_init(struct crypto_tfm *tfm)
+{
+	struct bfin_crypto_crc_ctx *crc_ctx = crypto_tfm_ctx(tfm);
+
+	crc_ctx->key = 0;
+	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+				 sizeof(struct bfin_crypto_crc_reqctx));
+
+	return 0;
+}
+
+static void bfin_crypto_crc_cra_exit(struct crypto_tfm *tfm)
+{
+}
+
+static struct ahash_alg algs = {
+	.init		= bfin_crypto_crc_init,
+	.update		= bfin_crypto_crc_update,
+	.final		= bfin_crypto_crc_final,
+	.finup		= bfin_crypto_crc_finup,
+	.digest		= bfin_crypto_crc_digest,
+	.setkey		= bfin_crypto_crc_setkey,
+	.halg.digestsize	= CHKSUM_DIGEST_SIZE,
+	.halg.base	= {
+		.cra_name		= "hmac(crc32)",
+		.cra_driver_name	= DRIVER_NAME,
+		.cra_priority		= 100,
+		.cra_flags		= CRYPTO_ALG_TYPE_AHASH |
+						CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= CHKSUM_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct bfin_crypto_crc_ctx),
+		.cra_alignmask		= 3,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= bfin_crypto_crc_cra_init,
+		.cra_exit		= bfin_crypto_crc_cra_exit,
+	}
+};
+
+static void bfin_crypto_crc_done_task(unsigned long data)
+{
+	struct bfin_crypto_crc *crc = (struct bfin_crypto_crc *)data;
+
+	bfin_crypto_crc_handle_queue(crc, NULL);
+}
+
+static irqreturn_t bfin_crypto_crc_handler(int irq, void *dev_id)
+{
+	struct bfin_crypto_crc *crc = dev_id;
+
+	if (crc->regs->status & DCNTEXP) {
+		crc->regs->status = DCNTEXP;
+		SSYNC();
+
+		/* prepare results */
+		put_unaligned_le32(crc->regs->result, crc->req->result);
+
+		crc->regs->control &= ~BLKEN;
+		crc->busy = 0;
+
+		if (crc->req->base.complete)
+			crc->req->base.complete(&crc->req->base, 0);
+
+		tasklet_schedule(&crc->done_task);
+
+		return IRQ_HANDLED;
+	} else
+		return IRQ_NONE;
+}
+
+#ifdef CONFIG_PM
+/**
+ *	bfin_crypto_crc_suspend - suspend crc device
+ *	@pdev: device being suspended
+ *	@state: requested suspend state
+ */
+static int bfin_crypto_crc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct bfin_crypto_crc *crc = platform_get_drvdata(pdev);
+	int i = 100000;
+
+	while ((crc->regs->control & BLKEN) && --i)
+		cpu_relax();
+
+	if (i == 0)
+		return -EBUSY;
+
+	return 0;
+}
+#else
+# define bfin_crypto_crc_suspend NULL
+#endif
+
+#define bfin_crypto_crc_resume NULL
+
+/**
+ *	bfin_crypto_crc_probe - Initialize module
+ *
+ */
+static int __devinit bfin_crypto_crc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct bfin_crypto_crc *crc;
+	unsigned int timeout = 100000;
+	int ret;
+
+	crc = kzalloc(sizeof(*crc), GFP_KERNEL);
+	if (!crc) {
+		dev_err(&pdev->dev, "fail to malloc bfin_crypto_crc\n");
+		return -ENOMEM;
+	}
+
+	crc->dev = dev;
+
+	INIT_LIST_HEAD(&crc->list);
+	spin_lock_init(&crc->lock);
+	tasklet_init(&crc->done_task, bfin_crypto_crc_done_task, (unsigned long)crc);
+	crypto_init_queue(&crc->queue, CRC_CCRYPTO_QUEUE_LENGTH);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+		ret = -ENOENT;
+		goto out_error_free_mem;
+	}
+
+	crc->regs = ioremap(res->start, resource_size(res));
+	if (!crc->regs) {
+		dev_err(&pdev->dev, "Cannot map CRC IO\n");
+		ret = -ENXIO;
+		goto out_error_free_mem;
+	}
+
+	crc->irq = platform_get_irq(pdev, 0);
+	if (crc->irq < 0) {
+		dev_err(&pdev->dev, "No CRC DCNTEXP IRQ specified\n");
+		ret = -ENOENT;
+		goto out_error_unmap;
+	}
+
+	ret = request_irq(crc->irq, bfin_crypto_crc_handler, IRQF_SHARED, dev_name(dev), crc);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to request blackfin crc irq\n");
+		goto out_error_unmap;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "No CRC DMA channel specified\n");
+		ret = -ENOENT;
+		goto out_error_irq;
+	}
+	crc->dma_ch = res->start;
+
+	ret = request_dma(crc->dma_ch, dev_name(dev));
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to attach Blackfin CRC DMA channel\n");
+		goto out_error_irq;
+	}
+
+	crc->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &crc->sg_dma, GFP_KERNEL);
+	if (crc->sg_cpu == NULL) {
+		ret = -ENOMEM;
+		goto out_error_dma;
+	}
+	/*
+	 * need at most CRC_MAX_DMA_DESC sg + CRC_MAX_DMA_DESC middle  +
+	 * 1 last + 1 next dma descriptors
+	 */
+	crc->sg_mid_buf = (u8 *)(crc->sg_cpu + ((CRC_MAX_DMA_DESC + 1) << 1));
+
+	crc->regs->control = 0;
+	SSYNC();
+	crc->regs->poly = crc->poly = (u32)pdev->dev.platform_data;
+	SSYNC();
+
+	while (!(crc->regs->status & LUTDONE) && (--timeout) > 0)
+		cpu_relax();
+
+	if (timeout == 0)
+		dev_info(&pdev->dev, "init crc poly timeout\n");
+
+	spin_lock(&crc_list.lock);
+	list_add(&crc->list, &crc_list.dev_list);
+	spin_unlock(&crc_list.lock);
+
+	platform_set_drvdata(pdev, crc);
+
+	ret = crypto_register_ahash(&algs);
+	if (ret) {
+		spin_lock(&crc_list.lock);
+		list_del(&crc->list);
+		spin_unlock(&crc_list.lock);
+		dev_err(&pdev->dev, "Cann't register crypto ahash device\n");
+		goto out_error_dma;
+	}
+
+	dev_info(&pdev->dev, "initialized\n");
+
+	return 0;
+
+out_error_dma:
+	if (crc->sg_cpu)
+		dma_free_coherent(&pdev->dev, PAGE_SIZE, crc->sg_cpu, crc->sg_dma);
+	free_dma(crc->dma_ch);
+out_error_irq:
+	free_irq(crc->irq, crc->dev);
+out_error_unmap:
+	iounmap((void *)crc->regs);
+out_error_free_mem:
+	kfree(crc);
+
+	return ret;
+}
+
+/**
+ *	bfin_crypto_crc_remove - Initialize module
+ *
+ */
+static int __devexit bfin_crypto_crc_remove(struct platform_device *pdev)
+{
+	struct bfin_crypto_crc *crc = platform_get_drvdata(pdev);
+
+	if (!crc)
+		return -ENODEV;
+
+	spin_lock(&crc_list.lock);
+	list_del(&crc->list);
+	spin_unlock(&crc_list.lock);
+
+	crypto_unregister_ahash(&algs);
+	tasklet_kill(&crc->done_task);
+	iounmap((void *)crc->regs);
+	free_dma(crc->dma_ch);
+	if (crc->irq > 0)
+		free_irq(crc->irq, crc->dev);
+	kfree(crc);
+
+	return 0;
+}
+
+static struct platform_driver bfin_crypto_crc_driver = {
+	.probe     = bfin_crypto_crc_probe,
+	.remove    = __devexit_p(bfin_crypto_crc_remove),
+	.suspend   = bfin_crypto_crc_suspend,
+	.resume    = bfin_crypto_crc_resume,
+	.driver    = {
+		.name  = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+/**
+ *	bfin_crypto_crc_mod_init - Initialize module
+ *
+ *	Checks the module params and registers the platform driver.
+ *	Real work is in the platform probe function.
+ */
+static int __init bfin_crypto_crc_mod_init(void)
+{
+	int ret;
+
+	pr_info("Blackfin hardware CRC crypto driver\n");
+
+	INIT_LIST_HEAD(&crc_list.dev_list);
+	spin_lock_init(&crc_list.lock);
+
+	ret = platform_driver_register(&bfin_crypto_crc_driver);
+	if (ret) {
+		pr_info(KERN_ERR "unable to register driver\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ *	bfin_crypto_crc_mod_exit - Deinitialize module
+ */
+static void __exit bfin_crypto_crc_mod_exit(void)
+{
+	platform_driver_unregister(&bfin_crypto_crc_driver);
+}
+
+module_init(bfin_crypto_crc_mod_init);
+module_exit(bfin_crypto_crc_mod_exit);
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Blackfin CRC hardware crypto driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index 1cc6b3f..0d40717 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -24,6 +24,7 @@
 
 #define MV_CESA	"MV-CESA:"
 #define MAX_HW_HASH_SIZE	0xFFFF
+#define MV_CESA_EXPIRE		500 /* msec */
 
 /*
  * STM:
@@ -87,6 +88,7 @@ struct crypto_priv {
 	spinlock_t lock;
 	struct crypto_queue queue;
 	enum engine_status eng_st;
+	struct timer_list completion_timer;
 	struct crypto_async_request *cur_req;
 	struct req_progress p;
 	int max_req_size;
@@ -138,6 +140,29 @@ struct mv_req_hash_ctx {
 	int count_add;
 };
 
+static void mv_completion_timer_callback(unsigned long unused)
+{
+	int active = readl(cpg->reg + SEC_ACCEL_CMD) & SEC_CMD_EN_SEC_ACCL0;
+
+	printk(KERN_ERR MV_CESA
+	       "completion timer expired (CESA %sactive), cleaning up.\n",
+	       active ? "" : "in");
+
+	del_timer(&cpg->completion_timer);
+	writel(SEC_CMD_DISABLE_SEC, cpg->reg + SEC_ACCEL_CMD);
+	while(readl(cpg->reg + SEC_ACCEL_CMD) & SEC_CMD_DISABLE_SEC)
+		printk(KERN_INFO MV_CESA "%s: waiting for engine finishing\n", __func__);
+	cpg->eng_st = ENGINE_W_DEQUEUE;
+	wake_up_process(cpg->queue_th);
+}
+
+static void mv_setup_timer(void)
+{
+	setup_timer(&cpg->completion_timer, &mv_completion_timer_callback, 0);
+	mod_timer(&cpg->completion_timer,
+			jiffies + msecs_to_jiffies(MV_CESA_EXPIRE));
+}
+
 static void compute_aes_dec_key(struct mv_ctx *ctx)
 {
 	struct crypto_aes_ctx gen_aes_key;
@@ -273,12 +298,8 @@ static void mv_process_current_q(int first_block)
 			sizeof(struct sec_accel_config));
 
 	/* GO */
+	mv_setup_timer();
 	writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD);
-
-	/*
-	 * XXX: add timer if the interrupt does not occur for some mystery
-	 * reason
-	 */
 }
 
 static void mv_crypto_algo_completion(void)
@@ -357,12 +378,8 @@ static void mv_process_hash_current(int first_block)
 	memcpy(cpg->sram + SRAM_CONFIG, &op, sizeof(struct sec_accel_config));
 
 	/* GO */
+	mv_setup_timer();
 	writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD);
-
-	/*
-	* XXX: add timer if the interrupt does not occur for some mystery
-	* reason
-	*/
 }
 
 static inline int mv_hash_import_sha1_ctx(const struct mv_req_hash_ctx *ctx,
@@ -406,6 +423,15 @@ out:
 	return rc;
 }
 
+static void mv_save_digest_state(struct mv_req_hash_ctx *ctx)
+{
+	ctx->state[0] = readl(cpg->reg + DIGEST_INITIAL_VAL_A);
+	ctx->state[1] = readl(cpg->reg + DIGEST_INITIAL_VAL_B);
+	ctx->state[2] = readl(cpg->reg + DIGEST_INITIAL_VAL_C);
+	ctx->state[3] = readl(cpg->reg + DIGEST_INITIAL_VAL_D);
+	ctx->state[4] = readl(cpg->reg + DIGEST_INITIAL_VAL_E);
+}
+
 static void mv_hash_algo_completion(void)
 {
 	struct ahash_request *req = ahash_request_cast(cpg->cur_req);
@@ -420,14 +446,12 @@ static void mv_hash_algo_completion(void)
 			memcpy(req->result, cpg->sram + SRAM_DIGEST_BUF,
 			       crypto_ahash_digestsize(crypto_ahash_reqtfm
 						       (req)));
-		} else
+		} else {
+			mv_save_digest_state(ctx);
 			mv_hash_final_fallback(req);
+		}
 	} else {
-		ctx->state[0] = readl(cpg->reg + DIGEST_INITIAL_VAL_A);
-		ctx->state[1] = readl(cpg->reg + DIGEST_INITIAL_VAL_B);
-		ctx->state[2] = readl(cpg->reg + DIGEST_INITIAL_VAL_C);
-		ctx->state[3] = readl(cpg->reg + DIGEST_INITIAL_VAL_D);
-		ctx->state[4] = readl(cpg->reg + DIGEST_INITIAL_VAL_E);
+		mv_save_digest_state(ctx);
 	}
 }
 
@@ -888,6 +912,10 @@ irqreturn_t crypto_int(int irq, void *priv)
 	if (!(val & SEC_INT_ACCEL0_DONE))
 		return IRQ_NONE;
 
+	if (!del_timer(&cpg->completion_timer)) {
+		printk(KERN_WARNING MV_CESA
+		       "got an interrupt but no pending timer?\n");
+	}
 	val &= ~SEC_INT_ACCEL0_DONE;
 	writel(val, cpg->reg + FPGA_INT_STATUS);
 	writel(val, cpg->reg + SEC_ACCEL_INT_STATUS);
@@ -1061,6 +1089,7 @@ static int mv_probe(struct platform_device *pdev)
 	if (!IS_ERR(cp->clk))
 		clk_prepare_enable(cp->clk);
 
+	writel(0, cpg->reg + SEC_ACCEL_INT_STATUS);
 	writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK);
 	writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG);
 	writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0);
diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c
index 422a976..ac236f6 100644
--- a/drivers/crypto/tegra-aes.c
+++ b/drivers/crypto/tegra-aes.c
@@ -572,7 +572,7 @@ static void aes_workqueue_handler(struct work_struct *work)
 	struct tegra_aes_dev *dd = aes_dev;
 	int ret;
 
-	ret = clk_enable(dd->aes_clk);
+	ret = clk_prepare_enable(dd->aes_clk);
 	if (ret)
 		BUG_ON("clock enable failed");
 
@@ -581,7 +581,7 @@ static void aes_workqueue_handler(struct work_struct *work)
 		ret = tegra_aes_handle_req(dd);
 	} while (!ret);
 
-	clk_disable(dd->aes_clk);
+	clk_disable_unprepare(dd->aes_clk);
 }
 
 static irqreturn_t aes_irq(int irq, void *dev_id)
@@ -673,7 +673,7 @@ static int tegra_aes_get_random(struct crypto_rng *tfm, u8 *rdata,
 	/* take mutex to access the aes hw */
 	mutex_lock(&aes_lock);
 
-	ret = clk_enable(dd->aes_clk);
+	ret = clk_prepare_enable(dd->aes_clk);
 	if (ret)
 		return ret;
 
@@ -700,7 +700,7 @@ static int tegra_aes_get_random(struct crypto_rng *tfm, u8 *rdata,
 	}
 
 out:
-	clk_disable(dd->aes_clk);
+	clk_disable_unprepare(dd->aes_clk);
 	mutex_unlock(&aes_lock);
 
 	dev_dbg(dd->dev, "%s: done\n", __func__);
@@ -758,7 +758,7 @@ static int tegra_aes_rng_reset(struct crypto_rng *tfm, u8 *seed,
 
 	dd->flags = FLAGS_ENCRYPT | FLAGS_RNG;
 
-	ret = clk_enable(dd->aes_clk);
+	ret = clk_prepare_enable(dd->aes_clk);
 	if (ret)
 		return ret;
 
@@ -788,7 +788,7 @@ static int tegra_aes_rng_reset(struct crypto_rng *tfm, u8 *seed,
 	memcpy(dd->dt, dt, DEFAULT_RNG_BLK_SZ);
 
 out:
-	clk_disable(dd->aes_clk);
+	clk_disable_unprepare(dd->aes_clk);
 	mutex_unlock(&aes_lock);
 
 	dev_dbg(dd->dev, "%s: done\n", __func__);
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index aadeb5b..d45cf1b 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -148,6 +148,20 @@ config TXX9_DMAC
 	  Support the TXx9 SoC internal DMA controller.  This can be
 	  integrated in chips such as the Toshiba TX4927/38/39.
 
+config TEGRA20_APB_DMA
+	bool "NVIDIA Tegra20 APB DMA support"
+	depends on ARCH_TEGRA
+	select DMA_ENGINE
+	help
+	  Support for the NVIDIA Tegra20 APB DMA controller driver. The
+	  DMA controller is having multiple DMA channel which can be
+	  configured for different peripherals like audio, UART, SPI,
+	  I2C etc which is in APB bus.
+	  This DMA controller transfers data from memory to peripheral fifo
+	  or vice versa. It does not support memory to memory data transfer.
+
+
+
 config SH_DMAE
 	tristate "Renesas SuperH DMAC support"
 	depends on (SUPERH && SH_DMA) || (ARM && ARCH_SHMOBILE)
@@ -237,7 +251,7 @@ config IMX_DMA
 
 config MXS_DMA
 	bool "MXS DMA support"
-	depends on SOC_IMX23 || SOC_IMX28
+	depends on SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q
 	select STMP_DEVICE
 	select DMA_ENGINE
 	help
@@ -260,6 +274,16 @@ config DMA_SA11X0
 	  SA-1110 SoCs.  This DMA engine can only be used with on-chip
 	  devices.
 
+config MMP_TDMA
+	bool "MMP Two-Channel DMA support"
+	depends on ARCH_MMP
+	select DMA_ENGINE
+	help
+	  Support the MMP Two-Channel DMA engine.
+	  This engine used for MMP Audio DMA and pxa910 SQU.
+
+	  Say Y here if you enabled MMP ADMA, otherwise say N.
+
 config DMA_ENGINE
 	bool
 
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 86b795b..370a655 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -23,8 +23,10 @@ obj-$(CONFIG_MXS_DMA) += mxs-dma.o
 obj-$(CONFIG_TIMB_DMA) += timb_dma.o
 obj-$(CONFIG_SIRF_DMA) += sirf-dma.o
 obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
+obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o
 obj-$(CONFIG_PL330_DMA) += pl330.o
 obj-$(CONFIG_PCH_DMA) += pch_dma.o
 obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
 obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
 obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
+obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 7292aa8..bb16013 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -9,10 +9,9 @@
  * (at your option) any later version.
  *
  *
- * This supports the Atmel AHB DMA Controller,
- *
- * The driver has currently been tested with the Atmel AT91SAM9RL
- * and AT91SAM9G45 series.
+ * This supports the Atmel AHB DMA Controller found in several Atmel SoCs.
+ * The only Atmel DMA Controller that is not covered by this driver is the one
+ * found on AT91SAM9263.
  */
 
 #include <linux/clk.h>
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index e67b4e0..aa384e5 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -1438,34 +1438,32 @@ static int __init coh901318_probe(struct platform_device *pdev)
 
 	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!io)
-		goto err_get_resource;
+		return -ENODEV;
 
 	/* Map DMA controller registers to virtual memory */
-	if (request_mem_region(io->start,
-			       resource_size(io),
-			       pdev->dev.driver->name) == NULL) {
-		err = -EBUSY;
-		goto err_request_mem;
-	}
+	if (devm_request_mem_region(&pdev->dev,
+				    io->start,
+				    resource_size(io),
+				    pdev->dev.driver->name) == NULL)
+		return -ENOMEM;
 
 	pdata = pdev->dev.platform_data;
 	if (!pdata)
-		goto err_no_platformdata;
+		return -ENODEV;
 
-	base = kmalloc(ALIGN(sizeof(struct coh901318_base), 4) +
-		       pdata->max_channels *
-		       sizeof(struct coh901318_chan),
-		       GFP_KERNEL);
+	base = devm_kzalloc(&pdev->dev,
+			    ALIGN(sizeof(struct coh901318_base), 4) +
+			    pdata->max_channels *
+			    sizeof(struct coh901318_chan),
+			    GFP_KERNEL);
 	if (!base)
-		goto err_alloc_coh_dma_channels;
+		return -ENOMEM;
 
 	base->chans = ((void *)base) + ALIGN(sizeof(struct coh901318_base), 4);
 
-	base->virtbase = ioremap(io->start, resource_size(io));
-	if (!base->virtbase) {
-		err = -ENOMEM;
-		goto err_no_ioremap;
-	}
+	base->virtbase = devm_ioremap(&pdev->dev, io->start, resource_size(io));
+	if (!base->virtbase)
+		return -ENOMEM;
 
 	base->dev = &pdev->dev;
 	base->platform = pdata;
@@ -1474,25 +1472,20 @@ static int __init coh901318_probe(struct platform_device *pdev)
 
 	COH901318_DEBUGFS_ASSIGN(debugfs_dma_base, base);
 
-	platform_set_drvdata(pdev, base);
-
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
-		goto err_no_irq;
-
-	err = request_irq(irq, dma_irq_handler, IRQF_DISABLED,
-			  "coh901318", base);
-	if (err) {
-		dev_crit(&pdev->dev,
-			 "Cannot allocate IRQ for DMA controller!\n");
-		goto err_request_irq;
-	}
+		return irq;
+
+	err = devm_request_irq(&pdev->dev, irq, dma_irq_handler, IRQF_DISABLED,
+			       "coh901318", base);
+	if (err)
+		return err;
 
 	err = coh901318_pool_create(&base->pool, &pdev->dev,
 				    sizeof(struct coh901318_lli),
 				    32);
 	if (err)
-		goto err_pool_create;
+		return err;
 
 	/* init channels for device transfers */
 	coh901318_base_init(&base->dma_slave,  base->platform->chans_slave,
@@ -1538,6 +1531,7 @@ static int __init coh901318_probe(struct platform_device *pdev)
 	if (err)
 		goto err_register_memcpy;
 
+	platform_set_drvdata(pdev, base);
 	dev_info(&pdev->dev, "Initialized COH901318 DMA on virtual base 0x%08x\n",
 		(u32) base->virtbase);
 
@@ -1547,19 +1541,6 @@ static int __init coh901318_probe(struct platform_device *pdev)
 	dma_async_device_unregister(&base->dma_slave);
  err_register_slave:
 	coh901318_pool_destroy(&base->pool);
- err_pool_create:
-	free_irq(platform_get_irq(pdev, 0), base);
- err_request_irq:
- err_no_irq:
-	iounmap(base->virtbase);
- err_no_ioremap:
-	kfree(base);
- err_alloc_coh_dma_channels:
- err_no_platformdata:
-	release_mem_region(pdev->resource->start,
-			   resource_size(pdev->resource));
- err_request_mem:
- err_get_resource:
 	return err;
 }
 
@@ -1570,11 +1551,6 @@ static int __exit coh901318_remove(struct platform_device *pdev)
 	dma_async_device_unregister(&base->dma_memcpy);
 	dma_async_device_unregister(&base->dma_slave);
 	coh901318_pool_destroy(&base->pool);
-	free_irq(platform_get_irq(pdev, 0), base);
-	iounmap(base->virtbase);
-	kfree(base);
-	release_mem_region(pdev->resource->start,
-			   resource_size(pdev->resource));
 	return 0;
 }
 
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 7212961..234c067 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -105,13 +105,13 @@ static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)
 
 	spin_lock_irqsave(&dwc->lock, flags);
 	list_for_each_entry_safe(desc, _desc, &dwc->free_list, desc_node) {
+		i++;
 		if (async_tx_test_ack(&desc->txd)) {
 			list_del(&desc->desc_node);
 			ret = desc;
 			break;
 		}
 		dev_dbg(chan2dev(&dwc->chan), "desc %p not ACKed\n", desc);
-		i++;
 	}
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
@@ -191,6 +191,42 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
 
 /*----------------------------------------------------------------------*/
 
+static inline unsigned int dwc_fast_fls(unsigned long long v)
+{
+	/*
+	 * We can be a lot more clever here, but this should take care
+	 * of the most common optimization.
+	 */
+	if (!(v & 7))
+		return 3;
+	else if (!(v & 3))
+		return 2;
+	else if (!(v & 1))
+		return 1;
+	return 0;
+}
+
+static void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
+{
+	dev_err(chan2dev(&dwc->chan),
+		"  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
+		channel_readl(dwc, SAR),
+		channel_readl(dwc, DAR),
+		channel_readl(dwc, LLP),
+		channel_readl(dwc, CTL_HI),
+		channel_readl(dwc, CTL_LO));
+}
+
+
+static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
+{
+	channel_clear_bit(dw, CH_EN, dwc->mask);
+	while (dma_readl(dw, CH_EN) & dwc->mask)
+		cpu_relax();
+}
+
+/*----------------------------------------------------------------------*/
+
 /* Called with dwc->lock held and bh disabled */
 static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
 {
@@ -200,13 +236,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
 	if (dma_readl(dw, CH_EN) & dwc->mask) {
 		dev_err(chan2dev(&dwc->chan),
 			"BUG: Attempted to start non-idle channel\n");
-		dev_err(chan2dev(&dwc->chan),
-			"  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
-			channel_readl(dwc, SAR),
-			channel_readl(dwc, DAR),
-			channel_readl(dwc, LLP),
-			channel_readl(dwc, CTL_HI),
-			channel_readl(dwc, CTL_LO));
+		dwc_dump_chan_regs(dwc);
 
 		/* The tasklet will hopefully advance the queue... */
 		return;
@@ -290,9 +320,7 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
 			"BUG: XFER bit set, but channel not idle!\n");
 
 		/* Try to continue after resetting the channel... */
-		channel_clear_bit(dw, CH_EN, dwc->mask);
-		while (dma_readl(dw, CH_EN) & dwc->mask)
-			cpu_relax();
+		dwc_chan_disable(dw, dwc);
 	}
 
 	/*
@@ -337,7 +365,8 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
 		return;
 	}
 
-	dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%x\n", llp);
+	dev_vdbg(chan2dev(&dwc->chan), "%s: llp=0x%llx\n", __func__,
+			(unsigned long long)llp);
 
 	list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
 		/* check first descriptors addr */
@@ -373,9 +402,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
 		"BUG: All descriptors done, but channel not idle!\n");
 
 	/* Try to continue after resetting the channel... */
-	channel_clear_bit(dw, CH_EN, dwc->mask);
-	while (dma_readl(dw, CH_EN) & dwc->mask)
-		cpu_relax();
+	dwc_chan_disable(dw, dwc);
 
 	if (!list_empty(&dwc->queue)) {
 		list_move(dwc->queue.next, &dwc->active_list);
@@ -387,8 +414,10 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
 static void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli)
 {
 	dev_printk(KERN_CRIT, chan2dev(&dwc->chan),
-			"  desc: s0x%x d0x%x l0x%x c0x%x:%x\n",
-			lli->sar, lli->dar, lli->llp,
+			"  desc: s0x%llx d0x%llx l0x%llx c0x%x:%x\n",
+			(unsigned long long)lli->sar,
+			(unsigned long long)lli->dar,
+			(unsigned long long)lli->llp,
 			lli->ctlhi, lli->ctllo);
 }
 
@@ -487,17 +516,9 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
 
 		spin_lock_irqsave(&dwc->lock, flags);
 
-		dev_err(chan2dev(&dwc->chan),
-			"  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
-			channel_readl(dwc, SAR),
-			channel_readl(dwc, DAR),
-			channel_readl(dwc, LLP),
-			channel_readl(dwc, CTL_HI),
-			channel_readl(dwc, CTL_LO));
+		dwc_dump_chan_regs(dwc);
 
-		channel_clear_bit(dw, CH_EN, dwc->mask);
-		while (dma_readl(dw, CH_EN) & dwc->mask)
-			cpu_relax();
+		dwc_chan_disable(dw, dwc);
 
 		/* make sure DMA does not restart by loading a new list */
 		channel_writel(dwc, LLP, 0);
@@ -527,7 +548,7 @@ static void dw_dma_tasklet(unsigned long data)
 	status_xfer = dma_readl(dw, RAW.XFER);
 	status_err = dma_readl(dw, RAW.ERROR);
 
-	dev_vdbg(dw->dma.dev, "tasklet: status_err=%x\n", status_err);
+	dev_vdbg(dw->dma.dev, "%s: status_err=%x\n", __func__, status_err);
 
 	for (i = 0; i < dw->dma.chancnt; i++) {
 		dwc = &dw->chan[i];
@@ -551,7 +572,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
 	struct dw_dma *dw = dev_id;
 	u32 status;
 
-	dev_vdbg(dw->dma.dev, "interrupt: status=0x%x\n",
+	dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__,
 			dma_readl(dw, STATUS_INT));
 
 	/*
@@ -597,12 +618,12 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
 	 * for DMA. But this is hard to do in a race-free manner.
 	 */
 	if (list_empty(&dwc->active_list)) {
-		dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
+		dev_vdbg(chan2dev(tx->chan), "%s: started %u\n", __func__,
 				desc->txd.cookie);
 		list_add_tail(&desc->desc_node, &dwc->active_list);
 		dwc_dostart(dwc, dwc_first_active(dwc));
 	} else {
-		dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
+		dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n", __func__,
 				desc->txd.cookie);
 
 		list_add_tail(&desc->desc_node, &dwc->queue);
@@ -627,26 +648,17 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 	unsigned int		dst_width;
 	u32			ctllo;
 
-	dev_vdbg(chan2dev(chan), "prep_dma_memcpy d0x%x s0x%x l0x%zx f0x%lx\n",
-			dest, src, len, flags);
+	dev_vdbg(chan2dev(chan),
+			"%s: d0x%llx s0x%llx l0x%zx f0x%lx\n", __func__,
+			(unsigned long long)dest, (unsigned long long)src,
+			len, flags);
 
 	if (unlikely(!len)) {
-		dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
+		dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__);
 		return NULL;
 	}
 
-	/*
-	 * We can be a lot more clever here, but this should take care
-	 * of the most common optimization.
-	 */
-	if (!((src | dest  | len) & 7))
-		src_width = dst_width = 3;
-	else if (!((src | dest  | len) & 3))
-		src_width = dst_width = 2;
-	else if (!((src | dest | len) & 1))
-		src_width = dst_width = 1;
-	else
-		src_width = dst_width = 0;
+	src_width = dst_width = dwc_fast_fls(src | dest | len);
 
 	ctllo = DWC_DEFAULT_CTLLO(chan)
 			| DWC_CTLL_DST_WIDTH(dst_width)
@@ -720,7 +732,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	struct scatterlist	*sg;
 	size_t			total_len = 0;
 
-	dev_vdbg(chan2dev(chan), "prep_dma_slave\n");
+	dev_vdbg(chan2dev(chan), "%s\n", __func__);
 
 	if (unlikely(!dws || !sg_len))
 		return NULL;
@@ -746,14 +758,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
 
-			if (!((mem | len) & 7))
-				mem_width = 3;
-			else if (!((mem | len) & 3))
-				mem_width = 2;
-			else if (!((mem | len) & 1))
-				mem_width = 1;
-			else
-				mem_width = 0;
+			mem_width = dwc_fast_fls(mem | len);
 
 slave_sg_todev_fill_desc:
 			desc = dwc_desc_get(dwc);
@@ -813,14 +818,7 @@ slave_sg_todev_fill_desc:
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
 
-			if (!((mem | len) & 7))
-				mem_width = 3;
-			else if (!((mem | len) & 3))
-				mem_width = 2;
-			else if (!((mem | len) & 1))
-				mem_width = 1;
-			else
-				mem_width = 0;
+			mem_width = dwc_fast_fls(mem | len);
 
 slave_sg_fromdev_fill_desc:
 			desc = dwc_desc_get(dwc);
@@ -950,9 +948,7 @@ static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 	} else if (cmd == DMA_TERMINATE_ALL) {
 		spin_lock_irqsave(&dwc->lock, flags);
 
-		channel_clear_bit(dw, CH_EN, dwc->mask);
-		while (dma_readl(dw, CH_EN) & dwc->mask)
-			cpu_relax();
+		dwc_chan_disable(dw, dwc);
 
 		dwc->paused = false;
 
@@ -1014,7 +1010,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
 	int			i;
 	unsigned long		flags;
 
-	dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
+	dev_vdbg(chan2dev(chan), "%s\n", __func__);
 
 	/* ASSERT:  channel is idle */
 	if (dma_readl(dw, CH_EN) & dwc->mask) {
@@ -1057,8 +1053,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
 
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
-	dev_dbg(chan2dev(chan),
-		"alloc_chan_resources allocated %d descriptors\n", i);
+	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n", __func__, i);
 
 	return i;
 }
@@ -1071,7 +1066,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
 	unsigned long		flags;
 	LIST_HEAD(list);
 
-	dev_dbg(chan2dev(chan), "free_chan_resources (descs allocated=%u)\n",
+	dev_dbg(chan2dev(chan), "%s: descs allocated=%u\n", __func__,
 			dwc->descs_allocated);
 
 	/* ASSERT:  channel is idle */
@@ -1097,7 +1092,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
 		kfree(desc);
 	}
 
-	dev_vdbg(chan2dev(chan), "free_chan_resources done\n");
+	dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
 }
 
 /* --------------------- Cyclic DMA API extensions -------------------- */
@@ -1126,13 +1121,7 @@ int dw_dma_cyclic_start(struct dma_chan *chan)
 	if (dma_readl(dw, CH_EN) & dwc->mask) {
 		dev_err(chan2dev(&dwc->chan),
 			"BUG: Attempted to start non-idle channel\n");
-		dev_err(chan2dev(&dwc->chan),
-			"  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
-			channel_readl(dwc, SAR),
-			channel_readl(dwc, DAR),
-			channel_readl(dwc, LLP),
-			channel_readl(dwc, CTL_HI),
-			channel_readl(dwc, CTL_LO));
+		dwc_dump_chan_regs(dwc);
 		spin_unlock_irqrestore(&dwc->lock, flags);
 		return -EBUSY;
 	}
@@ -1167,9 +1156,7 @@ void dw_dma_cyclic_stop(struct dma_chan *chan)
 
 	spin_lock_irqsave(&dwc->lock, flags);
 
-	channel_clear_bit(dw, CH_EN, dwc->mask);
-	while (dma_readl(dw, CH_EN) & dwc->mask)
-		cpu_relax();
+	dwc_chan_disable(dw, dwc);
 
 	spin_unlock_irqrestore(&dwc->lock, flags);
 }
@@ -1308,9 +1295,9 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
 	dma_sync_single_for_device(chan2parent(chan), last->txd.phys,
 			sizeof(last->lli), DMA_TO_DEVICE);
 
-	dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%08x len %zu "
-			"period %zu periods %d\n", buf_addr, buf_len,
-			period_len, periods);
+	dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%llx len %zu "
+			"period %zu periods %d\n", (unsigned long long)buf_addr,
+			buf_len, period_len, periods);
 
 	cdesc->periods = periods;
 	dwc->cdesc = cdesc;
@@ -1340,16 +1327,14 @@ void dw_dma_cyclic_free(struct dma_chan *chan)
 	int			i;
 	unsigned long		flags;
 
-	dev_dbg(chan2dev(&dwc->chan), "cyclic free\n");
+	dev_dbg(chan2dev(&dwc->chan), "%s\n", __func__);
 
 	if (!cdesc)
 		return;
 
 	spin_lock_irqsave(&dwc->lock, flags);
 
-	channel_clear_bit(dw, CH_EN, dwc->mask);
-	while (dma_readl(dw, CH_EN) & dwc->mask)
-		cpu_relax();
+	dwc_chan_disable(dw, dwc);
 
 	dma_writel(dw, CLEAR.ERROR, dwc->mask);
 	dma_writel(dw, CLEAR.XFER, dwc->mask);
@@ -1386,7 +1371,7 @@ static void dw_dma_off(struct dw_dma *dw)
 		dw->chan[i].initialized = false;
 }
 
-static int __init dw_probe(struct platform_device *pdev)
+static int __devinit dw_probe(struct platform_device *pdev)
 {
 	struct dw_dma_platform_data *pdata;
 	struct resource		*io;
@@ -1432,9 +1417,15 @@ static int __init dw_probe(struct platform_device *pdev)
 	}
 	clk_prepare_enable(dw->clk);
 
+	/* Calculate all channel mask before DMA setup */
+	dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
+
 	/* force dma off, just in case */
 	dw_dma_off(dw);
 
+	/* disable BLOCK interrupts as well */
+	channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
+
 	err = request_irq(irq, dw_dma_interrupt, 0, "dw_dmac", dw);
 	if (err)
 		goto err_irq;
@@ -1443,8 +1434,6 @@ static int __init dw_probe(struct platform_device *pdev)
 
 	tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw);
 
-	dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
-
 	INIT_LIST_HEAD(&dw->dma.channels);
 	for (i = 0; i < pdata->nr_channels; i++) {
 		struct dw_dma_chan	*dwc = &dw->chan[i];
@@ -1474,17 +1463,13 @@ static int __init dw_probe(struct platform_device *pdev)
 		channel_clear_bit(dw, CH_EN, dwc->mask);
 	}
 
-	/* Clear/disable all interrupts on all channels. */
+	/* Clear all interrupts on all channels. */
 	dma_writel(dw, CLEAR.XFER, dw->all_chan_mask);
+	dma_writel(dw, CLEAR.BLOCK, dw->all_chan_mask);
 	dma_writel(dw, CLEAR.SRC_TRAN, dw->all_chan_mask);
 	dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask);
 	dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask);
 
-	channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
-	channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
-	channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
-	channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
-
 	dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask);
 	dma_cap_set(DMA_SLAVE, dw->dma.cap_mask);
 	if (pdata->is_private)
@@ -1523,7 +1508,7 @@ err_kfree:
 	return err;
 }
 
-static int __exit dw_remove(struct platform_device *pdev)
+static int __devexit dw_remove(struct platform_device *pdev)
 {
 	struct dw_dma		*dw = platform_get_drvdata(pdev);
 	struct dw_dma_chan	*dwc, *_dwc;
@@ -1602,7 +1587,7 @@ MODULE_DEVICE_TABLE(of, dw_dma_id_table);
 #endif
 
 static struct platform_driver dw_driver = {
-	.remove		= __exit_p(dw_remove),
+	.remove		= __devexit_p(dw_remove),
 	.shutdown	= dw_shutdown,
 	.driver = {
 		.name	= "dw_dmac",
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index f298f69..e248481 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -82,7 +82,7 @@ struct dw_dma_regs {
 	DW_REG(ID);
 	DW_REG(TEST);
 
-	/* optional encoded params, 0x3c8..0x3 */
+	/* optional encoded params, 0x3c8..0x3f7 */
 };
 
 /* Bitfields in CTL_LO */
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
new file mode 100644
index 0000000..8a15cf2
--- /dev/null
+++ b/drivers/dma/mmp_tdma.c
@@ -0,0 +1,610 @@
+/*
+ * Driver For Marvell Two-channel DMA Engine
+ *
+ * Copyright: Marvell International Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <mach/regs-icu.h>
+#include <mach/sram.h>
+
+#include "dmaengine.h"
+
+/*
+ * Two-Channel DMA registers
+ */
+#define TDBCR		0x00	/* Byte Count */
+#define TDSAR		0x10	/* Src Addr */
+#define TDDAR		0x20	/* Dst Addr */
+#define TDNDPR		0x30	/* Next Desc */
+#define TDCR		0x40	/* Control */
+#define TDCP		0x60	/* Priority*/
+#define TDCDPR		0x70	/* Current Desc */
+#define TDIMR		0x80	/* Int Mask */
+#define TDISR		0xa0	/* Int Status */
+
+/* Two-Channel DMA Control Register */
+#define TDCR_SSZ_8_BITS		(0x0 << 22)	/* Sample Size */
+#define TDCR_SSZ_12_BITS	(0x1 << 22)
+#define TDCR_SSZ_16_BITS	(0x2 << 22)
+#define TDCR_SSZ_20_BITS	(0x3 << 22)
+#define TDCR_SSZ_24_BITS	(0x4 << 22)
+#define TDCR_SSZ_32_BITS	(0x5 << 22)
+#define TDCR_SSZ_SHIFT		(0x1 << 22)
+#define TDCR_SSZ_MASK		(0x7 << 22)
+#define TDCR_SSPMOD		(0x1 << 21)	/* SSP MOD */
+#define TDCR_ABR		(0x1 << 20)	/* Channel Abort */
+#define TDCR_CDE		(0x1 << 17)	/* Close Desc Enable */
+#define TDCR_PACKMOD		(0x1 << 16)	/* Pack Mode (ADMA Only) */
+#define TDCR_CHANACT		(0x1 << 14)	/* Channel Active */
+#define TDCR_FETCHND		(0x1 << 13)	/* Fetch Next Desc */
+#define TDCR_CHANEN		(0x1 << 12)	/* Channel Enable */
+#define TDCR_INTMODE		(0x1 << 10)	/* Interrupt Mode */
+#define TDCR_CHAINMOD		(0x1 << 9)	/* Chain Mode */
+#define TDCR_BURSTSZ_MSK	(0x7 << 6)	/* Burst Size */
+#define TDCR_BURSTSZ_4B		(0x0 << 6)
+#define TDCR_BURSTSZ_8B		(0x1 << 6)
+#define TDCR_BURSTSZ_16B	(0x3 << 6)
+#define TDCR_BURSTSZ_32B	(0x6 << 6)
+#define TDCR_BURSTSZ_64B	(0x7 << 6)
+#define TDCR_BURSTSZ_SQU_32B	(0x7 << 6)
+#define TDCR_BURSTSZ_128B	(0x5 << 6)
+#define TDCR_DSTDIR_MSK		(0x3 << 4)	/* Dst Direction */
+#define TDCR_DSTDIR_ADDR_HOLD	(0x2 << 4)	/* Dst Addr Hold */
+#define TDCR_DSTDIR_ADDR_INC	(0x0 << 4)	/* Dst Addr Increment */
+#define TDCR_SRCDIR_MSK		(0x3 << 2)	/* Src Direction */
+#define TDCR_SRCDIR_ADDR_HOLD	(0x2 << 2)	/* Src Addr Hold */
+#define TDCR_SRCDIR_ADDR_INC	(0x0 << 2)	/* Src Addr Increment */
+#define TDCR_DSTDESCCONT	(0x1 << 1)
+#define TDCR_SRCDESTCONT	(0x1 << 0)
+
+/* Two-Channel DMA Int Mask Register */
+#define TDIMR_COMP		(0x1 << 0)
+
+/* Two-Channel DMA Int Status Register */
+#define TDISR_COMP		(0x1 << 0)
+
+/*
+ * Two-Channel DMA Descriptor Struct
+ * NOTE: desc's buf must be aligned to 16 bytes.
+ */
+struct mmp_tdma_desc {
+	u32 byte_cnt;
+	u32 src_addr;
+	u32 dst_addr;
+	u32 nxt_desc;
+};
+
+enum mmp_tdma_type {
+	MMP_AUD_TDMA = 0,
+	PXA910_SQU,
+};
+
+#define TDMA_ALIGNMENT		3
+#define TDMA_MAX_XFER_BYTES    SZ_64K
+
+struct mmp_tdma_chan {
+	struct device			*dev;
+	struct dma_chan			chan;
+	struct dma_async_tx_descriptor	desc;
+	struct tasklet_struct		tasklet;
+
+	struct mmp_tdma_desc		*desc_arr;
+	phys_addr_t			desc_arr_phys;
+	int				desc_num;
+	enum dma_transfer_direction	dir;
+	dma_addr_t			dev_addr;
+	u32				burst_sz;
+	enum dma_slave_buswidth		buswidth;
+	enum dma_status			status;
+
+	int				idx;
+	enum mmp_tdma_type		type;
+	int				irq;
+	unsigned long			reg_base;
+
+	size_t				buf_len;
+	size_t				period_len;
+	size_t				pos;
+};
+
+#define TDMA_CHANNEL_NUM 2
+struct mmp_tdma_device {
+	struct device			*dev;
+	void __iomem			*base;
+	struct dma_device		device;
+	struct mmp_tdma_chan		*tdmac[TDMA_CHANNEL_NUM];
+	int				irq;
+};
+
+#define to_mmp_tdma_chan(dchan) container_of(dchan, struct mmp_tdma_chan, chan)
+
+static void mmp_tdma_chan_set_desc(struct mmp_tdma_chan *tdmac, dma_addr_t phys)
+{
+	writel(phys, tdmac->reg_base + TDNDPR);
+	writel(readl(tdmac->reg_base + TDCR) | TDCR_FETCHND,
+					tdmac->reg_base + TDCR);
+}
+
+static void mmp_tdma_enable_chan(struct mmp_tdma_chan *tdmac)
+{
+	/* enable irq */
+	writel(TDIMR_COMP, tdmac->reg_base + TDIMR);
+	/* enable dma chan */
+	writel(readl(tdmac->reg_base + TDCR) | TDCR_CHANEN,
+					tdmac->reg_base + TDCR);
+	tdmac->status = DMA_IN_PROGRESS;
+}
+
+static void mmp_tdma_disable_chan(struct mmp_tdma_chan *tdmac)
+{
+	writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN,
+					tdmac->reg_base + TDCR);
+	tdmac->status = DMA_SUCCESS;
+}
+
+static void mmp_tdma_resume_chan(struct mmp_tdma_chan *tdmac)
+{
+	writel(readl(tdmac->reg_base + TDCR) | TDCR_CHANEN,
+					tdmac->reg_base + TDCR);
+	tdmac->status = DMA_IN_PROGRESS;
+}
+
+static void mmp_tdma_pause_chan(struct mmp_tdma_chan *tdmac)
+{
+	writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN,
+					tdmac->reg_base + TDCR);
+	tdmac->status = DMA_PAUSED;
+}
+
+static int mmp_tdma_config_chan(struct mmp_tdma_chan *tdmac)
+{
+	unsigned int tdcr;
+
+	mmp_tdma_disable_chan(tdmac);
+
+	if (tdmac->dir == DMA_MEM_TO_DEV)
+		tdcr = TDCR_DSTDIR_ADDR_HOLD | TDCR_SRCDIR_ADDR_INC;
+	else if (tdmac->dir == DMA_DEV_TO_MEM)
+		tdcr = TDCR_SRCDIR_ADDR_HOLD | TDCR_DSTDIR_ADDR_INC;
+
+	if (tdmac->type == MMP_AUD_TDMA) {
+		tdcr |= TDCR_PACKMOD;
+
+		switch (tdmac->burst_sz) {
+		case 4:
+			tdcr |= TDCR_BURSTSZ_4B;
+			break;
+		case 8:
+			tdcr |= TDCR_BURSTSZ_8B;
+			break;
+		case 16:
+			tdcr |= TDCR_BURSTSZ_16B;
+			break;
+		case 32:
+			tdcr |= TDCR_BURSTSZ_32B;
+			break;
+		case 64:
+			tdcr |= TDCR_BURSTSZ_64B;
+			break;
+		case 128:
+			tdcr |= TDCR_BURSTSZ_128B;
+			break;
+		default:
+			dev_err(tdmac->dev, "mmp_tdma: unknown burst size.\n");
+			return -EINVAL;
+		}
+
+		switch (tdmac->buswidth) {
+		case DMA_SLAVE_BUSWIDTH_1_BYTE:
+			tdcr |= TDCR_SSZ_8_BITS;
+			break;
+		case DMA_SLAVE_BUSWIDTH_2_BYTES:
+			tdcr |= TDCR_SSZ_16_BITS;
+			break;
+		case DMA_SLAVE_BUSWIDTH_4_BYTES:
+			tdcr |= TDCR_SSZ_32_BITS;
+			break;
+		default:
+			dev_err(tdmac->dev, "mmp_tdma: unknown bus size.\n");
+			return -EINVAL;
+		}
+	} else if (tdmac->type == PXA910_SQU) {
+		tdcr |= TDCR_BURSTSZ_SQU_32B;
+		tdcr |= TDCR_SSPMOD;
+	}
+
+	writel(tdcr, tdmac->reg_base + TDCR);
+	return 0;
+}
+
+static int mmp_tdma_clear_chan_irq(struct mmp_tdma_chan *tdmac)
+{
+	u32 reg = readl(tdmac->reg_base + TDISR);
+
+	if (reg & TDISR_COMP) {
+		/* clear irq */
+		reg &= ~TDISR_COMP;
+		writel(reg, tdmac->reg_base + TDISR);
+
+		return 0;
+	}
+	return -EAGAIN;
+}
+
+static irqreturn_t mmp_tdma_chan_handler(int irq, void *dev_id)
+{
+	struct mmp_tdma_chan *tdmac = dev_id;
+
+	if (mmp_tdma_clear_chan_irq(tdmac) == 0) {
+		tdmac->pos = (tdmac->pos + tdmac->period_len) % tdmac->buf_len;
+		tasklet_schedule(&tdmac->tasklet);
+		return IRQ_HANDLED;
+	} else
+		return IRQ_NONE;
+}
+
+static irqreturn_t mmp_tdma_int_handler(int irq, void *dev_id)
+{
+	struct mmp_tdma_device *tdev = dev_id;
+	int i, ret;
+	int irq_num = 0;
+
+	for (i = 0; i < TDMA_CHANNEL_NUM; i++) {
+		struct mmp_tdma_chan *tdmac = tdev->tdmac[i];
+
+		ret = mmp_tdma_chan_handler(irq, tdmac);
+		if (ret == IRQ_HANDLED)
+			irq_num++;
+	}
+
+	if (irq_num)
+		return IRQ_HANDLED;
+	else
+		return IRQ_NONE;
+}
+
+static void dma_do_tasklet(unsigned long data)
+{
+	struct mmp_tdma_chan *tdmac = (struct mmp_tdma_chan *)data;
+
+	if (tdmac->desc.callback)
+		tdmac->desc.callback(tdmac->desc.callback_param);
+
+}
+
+static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
+{
+	struct gen_pool *gpool;
+	int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
+
+	gpool = sram_get_gpool("asram");
+	if (tdmac->desc_arr)
+		gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
+				size);
+	tdmac->desc_arr = NULL;
+
+	return;
+}
+
+static dma_cookie_t mmp_tdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(tx->chan);
+
+	mmp_tdma_chan_set_desc(tdmac, tdmac->desc_arr_phys);
+
+	return 0;
+}
+
+static int mmp_tdma_alloc_chan_resources(struct dma_chan *chan)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+	int ret;
+
+	dma_async_tx_descriptor_init(&tdmac->desc, chan);
+	tdmac->desc.tx_submit = mmp_tdma_tx_submit;
+
+	if (tdmac->irq) {
+		ret = devm_request_irq(tdmac->dev, tdmac->irq,
+			mmp_tdma_chan_handler, IRQF_DISABLED, "tdma", tdmac);
+		if (ret)
+			return ret;
+	}
+	return 1;
+}
+
+static void mmp_tdma_free_chan_resources(struct dma_chan *chan)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+	if (tdmac->irq)
+		devm_free_irq(tdmac->dev, tdmac->irq, tdmac);
+	mmp_tdma_free_descriptor(tdmac);
+	return;
+}
+
+struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
+{
+	struct gen_pool *gpool;
+	int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
+
+	gpool = sram_get_gpool("asram");
+	if (!gpool)
+		return NULL;
+
+	tdmac->desc_arr = (void *)gen_pool_alloc(gpool, size);
+	if (!tdmac->desc_arr)
+		return NULL;
+
+	tdmac->desc_arr_phys = gen_pool_virt_to_phys(gpool,
+			(unsigned long)tdmac->desc_arr);
+
+	return tdmac->desc_arr;
+}
+
+static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+		size_t period_len, enum dma_transfer_direction direction,
+		void *context)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+	struct mmp_tdma_desc *desc;
+	int num_periods = buf_len / period_len;
+	int i = 0, buf = 0;
+
+	if (tdmac->status != DMA_SUCCESS)
+		return NULL;
+
+	if (period_len > TDMA_MAX_XFER_BYTES) {
+		dev_err(tdmac->dev,
+				"maximum period size exceeded: %d > %d\n",
+				period_len, TDMA_MAX_XFER_BYTES);
+		goto err_out;
+	}
+
+	tdmac->status = DMA_IN_PROGRESS;
+	tdmac->desc_num = num_periods;
+	desc = mmp_tdma_alloc_descriptor(tdmac);
+	if (!desc)
+		goto err_out;
+
+	while (buf < buf_len) {
+		desc = &tdmac->desc_arr[i];
+
+		if (i + 1 == num_periods)
+			desc->nxt_desc = tdmac->desc_arr_phys;
+		else
+			desc->nxt_desc = tdmac->desc_arr_phys +
+				sizeof(*desc) * (i + 1);
+
+		if (direction == DMA_MEM_TO_DEV) {
+			desc->src_addr = dma_addr;
+			desc->dst_addr = tdmac->dev_addr;
+		} else {
+			desc->src_addr = tdmac->dev_addr;
+			desc->dst_addr = dma_addr;
+		}
+		desc->byte_cnt = period_len;
+		dma_addr += period_len;
+		buf += period_len;
+		i++;
+	}
+
+	tdmac->buf_len = buf_len;
+	tdmac->period_len = period_len;
+	tdmac->pos = 0;
+
+	return &tdmac->desc;
+
+err_out:
+	tdmac->status = DMA_ERROR;
+	return NULL;
+}
+
+static int mmp_tdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+		unsigned long arg)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+	struct dma_slave_config *dmaengine_cfg = (void *)arg;
+	int ret = 0;
+
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		mmp_tdma_disable_chan(tdmac);
+		break;
+	case DMA_PAUSE:
+		mmp_tdma_pause_chan(tdmac);
+		break;
+	case DMA_RESUME:
+		mmp_tdma_resume_chan(tdmac);
+		break;
+	case DMA_SLAVE_CONFIG:
+		if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
+			tdmac->dev_addr = dmaengine_cfg->src_addr;
+			tdmac->burst_sz = dmaengine_cfg->src_maxburst;
+			tdmac->buswidth = dmaengine_cfg->src_addr_width;
+		} else {
+			tdmac->dev_addr = dmaengine_cfg->dst_addr;
+			tdmac->burst_sz = dmaengine_cfg->dst_maxburst;
+			tdmac->buswidth = dmaengine_cfg->dst_addr_width;
+		}
+		tdmac->dir = dmaengine_cfg->direction;
+		return mmp_tdma_config_chan(tdmac);
+	default:
+		ret = -ENOSYS;
+	}
+
+	return ret;
+}
+
+static enum dma_status mmp_tdma_tx_status(struct dma_chan *chan,
+			dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+	dma_set_residue(txstate, tdmac->buf_len - tdmac->pos);
+
+	return tdmac->status;
+}
+
+static void mmp_tdma_issue_pending(struct dma_chan *chan)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+	mmp_tdma_enable_chan(tdmac);
+}
+
+static int __devexit mmp_tdma_remove(struct platform_device *pdev)
+{
+	struct mmp_tdma_device *tdev = platform_get_drvdata(pdev);
+
+	dma_async_device_unregister(&tdev->device);
+	return 0;
+}
+
+static int __devinit mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
+						int idx, int irq, int type)
+{
+	struct mmp_tdma_chan *tdmac;
+
+	if (idx >= TDMA_CHANNEL_NUM) {
+		dev_err(tdev->dev, "too many channels for device!\n");
+		return -EINVAL;
+	}
+
+	/* alloc channel */
+	tdmac = devm_kzalloc(tdev->dev, sizeof(*tdmac), GFP_KERNEL);
+	if (!tdmac) {
+		dev_err(tdev->dev, "no free memory for DMA channels!\n");
+		return -ENOMEM;
+	}
+	if (irq)
+		tdmac->irq = irq + idx;
+	tdmac->dev	   = tdev->dev;
+	tdmac->chan.device = &tdev->device;
+	tdmac->idx	   = idx;
+	tdmac->type	   = type;
+	tdmac->reg_base	   = (unsigned long)tdev->base + idx * 4;
+	tdmac->status = DMA_SUCCESS;
+	tdev->tdmac[tdmac->idx] = tdmac;
+	tasklet_init(&tdmac->tasklet, dma_do_tasklet, (unsigned long)tdmac);
+
+	/* add the channel to tdma_chan list */
+	list_add_tail(&tdmac->chan.device_node,
+			&tdev->device.channels);
+
+	return 0;
+}
+
+static int __devinit mmp_tdma_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	enum mmp_tdma_type type = id->driver_data;
+	struct mmp_tdma_device *tdev;
+	struct resource *iores;
+	int i, ret;
+	int irq = 0;
+	int chan_num = TDMA_CHANNEL_NUM;
+
+	/* always have couple channels */
+	tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
+	if (!tdev)
+		return -ENOMEM;
+
+	tdev->dev = &pdev->dev;
+	iores = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!iores)
+		return -EINVAL;
+
+	if (resource_size(iores) != chan_num)
+		tdev->irq = iores->start;
+	else
+		irq = iores->start;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iores)
+		return -EINVAL;
+
+	tdev->base = devm_request_and_ioremap(&pdev->dev, iores);
+	if (!tdev->base)
+		return -EADDRNOTAVAIL;
+
+	if (tdev->irq) {
+		ret = devm_request_irq(&pdev->dev, tdev->irq,
+			mmp_tdma_int_handler, IRQF_DISABLED, "tdma", tdev);
+		if (ret)
+			return ret;
+	}
+
+	dma_cap_set(DMA_SLAVE, tdev->device.cap_mask);
+	dma_cap_set(DMA_CYCLIC, tdev->device.cap_mask);
+
+	INIT_LIST_HEAD(&tdev->device.channels);
+
+	/* initialize channel parameters */
+	for (i = 0; i < chan_num; i++) {
+		ret = mmp_tdma_chan_init(tdev, i, irq, type);
+		if (ret)
+			return ret;
+	}
+
+	tdev->device.dev = &pdev->dev;
+	tdev->device.device_alloc_chan_resources =
+					mmp_tdma_alloc_chan_resources;
+	tdev->device.device_free_chan_resources =
+					mmp_tdma_free_chan_resources;
+	tdev->device.device_prep_dma_cyclic = mmp_tdma_prep_dma_cyclic;
+	tdev->device.device_tx_status = mmp_tdma_tx_status;
+	tdev->device.device_issue_pending = mmp_tdma_issue_pending;
+	tdev->device.device_control = mmp_tdma_control;
+	tdev->device.copy_align = TDMA_ALIGNMENT;
+
+	dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+	platform_set_drvdata(pdev, tdev);
+
+	ret = dma_async_device_register(&tdev->device);
+	if (ret) {
+		dev_err(tdev->device.dev, "unable to register\n");
+		return ret;
+	}
+
+	dev_info(tdev->device.dev, "initialized\n");
+	return 0;
+}
+
+static const struct platform_device_id mmp_tdma_id_table[] = {
+	{ "mmp-adma",	MMP_AUD_TDMA },
+	{ "pxa910-squ",	PXA910_SQU },
+	{ },
+};
+
+static struct platform_driver mmp_tdma_driver = {
+	.driver		= {
+		.name	= "mmp-tdma",
+		.owner  = THIS_MODULE,
+	},
+	.id_table	= mmp_tdma_id_table,
+	.probe		= mmp_tdma_probe,
+	.remove		= __devexit_p(mmp_tdma_remove),
+};
+
+module_platform_driver(mmp_tdma_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MMP Two-Channel DMA Driver");
+MODULE_ALIAS("platform:mmp-tdma");
+MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
+MODULE_AUTHOR("Zhangfei Gao <zhangfei.gao@marvell.com>");
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index c96ab15..90b980d 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -29,7 +29,6 @@
 #include <linux/of_device.h>
 
 #include <asm/irq.h>
-#include <mach/mxs.h>
 
 #include "dmaengine.h"
 
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
new file mode 100644
index 0000000..134ea7c
--- /dev/null
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -0,0 +1,1410 @@
+/*
+ * DMA driver for Nvidia's Tegra20 APB DMA controller.
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include <mach/clk.h>
+#include "dmaengine.h"
+
+#define TEGRA_APBDMA_GENERAL			0x0
+#define TEGRA_APBDMA_GENERAL_ENABLE		BIT(31)
+
+#define TEGRA_APBDMA_CONTROL			0x010
+#define TEGRA_APBDMA_IRQ_MASK			0x01c
+#define TEGRA_APBDMA_IRQ_MASK_SET		0x020
+
+/* CSR register */
+#define TEGRA_APBDMA_CHAN_CSR			0x00
+#define TEGRA_APBDMA_CSR_ENB			BIT(31)
+#define TEGRA_APBDMA_CSR_IE_EOC			BIT(30)
+#define TEGRA_APBDMA_CSR_HOLD			BIT(29)
+#define TEGRA_APBDMA_CSR_DIR			BIT(28)
+#define TEGRA_APBDMA_CSR_ONCE			BIT(27)
+#define TEGRA_APBDMA_CSR_FLOW			BIT(21)
+#define TEGRA_APBDMA_CSR_REQ_SEL_SHIFT		16
+#define TEGRA_APBDMA_CSR_WCOUNT_MASK		0xFFFC
+
+/* STATUS register */
+#define TEGRA_APBDMA_CHAN_STATUS		0x004
+#define TEGRA_APBDMA_STATUS_BUSY		BIT(31)
+#define TEGRA_APBDMA_STATUS_ISE_EOC		BIT(30)
+#define TEGRA_APBDMA_STATUS_HALT		BIT(29)
+#define TEGRA_APBDMA_STATUS_PING_PONG		BIT(28)
+#define TEGRA_APBDMA_STATUS_COUNT_SHIFT		2
+#define TEGRA_APBDMA_STATUS_COUNT_MASK		0xFFFC
+
+/* AHB memory address */
+#define TEGRA_APBDMA_CHAN_AHBPTR		0x010
+
+/* AHB sequence register */
+#define TEGRA_APBDMA_CHAN_AHBSEQ		0x14
+#define TEGRA_APBDMA_AHBSEQ_INTR_ENB		BIT(31)
+#define TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_8		(0 << 28)
+#define TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_16	(1 << 28)
+#define TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32	(2 << 28)
+#define TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_64	(3 << 28)
+#define TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_128	(4 << 28)
+#define TEGRA_APBDMA_AHBSEQ_DATA_SWAP		BIT(27)
+#define TEGRA_APBDMA_AHBSEQ_BURST_1		(4 << 24)
+#define TEGRA_APBDMA_AHBSEQ_BURST_4		(5 << 24)
+#define TEGRA_APBDMA_AHBSEQ_BURST_8		(6 << 24)
+#define TEGRA_APBDMA_AHBSEQ_DBL_BUF		BIT(19)
+#define TEGRA_APBDMA_AHBSEQ_WRAP_SHIFT		16
+#define TEGRA_APBDMA_AHBSEQ_WRAP_NONE		0
+
+/* APB address */
+#define TEGRA_APBDMA_CHAN_APBPTR		0x018
+
+/* APB sequence register */
+#define TEGRA_APBDMA_CHAN_APBSEQ		0x01c
+#define TEGRA_APBDMA_APBSEQ_BUS_WIDTH_8		(0 << 28)
+#define TEGRA_APBDMA_APBSEQ_BUS_WIDTH_16	(1 << 28)
+#define TEGRA_APBDMA_APBSEQ_BUS_WIDTH_32	(2 << 28)
+#define TEGRA_APBDMA_APBSEQ_BUS_WIDTH_64	(3 << 28)
+#define TEGRA_APBDMA_APBSEQ_BUS_WIDTH_128	(4 << 28)
+#define TEGRA_APBDMA_APBSEQ_DATA_SWAP		BIT(27)
+#define TEGRA_APBDMA_APBSEQ_WRAP_WORD_1		(1 << 16)
+
+/*
+ * If any burst is in flight and DMA paused then this is the time to complete
+ * on-flight burst and update DMA status register.
+ */
+#define TEGRA_APBDMA_BURST_COMPLETE_TIME	20
+
+/* Channel base address offset from APBDMA base address */
+#define TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET	0x1000
+
+/* DMA channel register space size */
+#define TEGRA_APBDMA_CHANNEL_REGISTER_SIZE	0x20
+
+struct tegra_dma;
+
+/*
+ * tegra_dma_chip_data Tegra chip specific DMA data
+ * @nr_channels: Number of channels available in the controller.
+ * @max_dma_count: Maximum DMA transfer count supported by DMA controller.
+ */
+struct tegra_dma_chip_data {
+	int nr_channels;
+	int max_dma_count;
+};
+
+/* DMA channel registers */
+struct tegra_dma_channel_regs {
+	unsigned long	csr;
+	unsigned long	ahb_ptr;
+	unsigned long	apb_ptr;
+	unsigned long	ahb_seq;
+	unsigned long	apb_seq;
+};
+
+/*
+ * tegra_dma_sg_req: Dma request details to configure hardware. This
+ * contains the details for one transfer to configure DMA hw.
+ * The client's request for data transfer can be broken into multiple
+ * sub-transfer as per requester details and hw support.
+ * This sub transfer get added in the list of transfer and point to Tegra
+ * DMA descriptor which manages the transfer details.
+ */
+struct tegra_dma_sg_req {
+	struct tegra_dma_channel_regs	ch_regs;
+	int				req_len;
+	bool				configured;
+	bool				last_sg;
+	bool				half_done;
+	struct list_head		node;
+	struct tegra_dma_desc		*dma_desc;
+};
+
+/*
+ * tegra_dma_desc: Tegra DMA descriptors which manages the client requests.
+ * This descriptor keep track of transfer status, callbacks and request
+ * counts etc.
+ */
+struct tegra_dma_desc {
+	struct dma_async_tx_descriptor	txd;
+	int				bytes_requested;
+	int				bytes_transferred;
+	enum dma_status			dma_status;
+	struct list_head		node;
+	struct list_head		tx_list;
+	struct list_head		cb_node;
+	int				cb_count;
+};
+
+struct tegra_dma_channel;
+
+typedef void (*dma_isr_handler)(struct tegra_dma_channel *tdc,
+				bool to_terminate);
+
+/* tegra_dma_channel: Channel specific information */
+struct tegra_dma_channel {
+	struct dma_chan		dma_chan;
+	bool			config_init;
+	int			id;
+	int			irq;
+	unsigned long		chan_base_offset;
+	spinlock_t		lock;
+	bool			busy;
+	struct tegra_dma	*tdma;
+	bool			cyclic;
+
+	/* Different lists for managing the requests */
+	struct list_head	free_sg_req;
+	struct list_head	pending_sg_req;
+	struct list_head	free_dma_desc;
+	struct list_head	cb_desc;
+
+	/* ISR handler and tasklet for bottom half of isr handling */
+	dma_isr_handler		isr_handler;
+	struct tasklet_struct	tasklet;
+	dma_async_tx_callback	callback;
+	void			*callback_param;
+
+	/* Channel-slave specific configuration */
+	struct dma_slave_config dma_sconfig;
+};
+
+/* tegra_dma: Tegra DMA specific information */
+struct tegra_dma {
+	struct dma_device		dma_dev;
+	struct device			*dev;
+	struct clk			*dma_clk;
+	spinlock_t			global_lock;
+	void __iomem			*base_addr;
+	struct tegra_dma_chip_data	*chip_data;
+
+	/* Some register need to be cache before suspend */
+	u32				reg_gen;
+
+	/* Last member of the structure */
+	struct tegra_dma_channel channels[0];
+};
+
+static inline void tdma_write(struct tegra_dma *tdma, u32 reg, u32 val)
+{
+	writel(val, tdma->base_addr + reg);
+}
+
+static inline u32 tdma_read(struct tegra_dma *tdma, u32 reg)
+{
+	return readl(tdma->base_addr + reg);
+}
+
+static inline void tdc_write(struct tegra_dma_channel *tdc,
+		u32 reg, u32 val)
+{
+	writel(val, tdc->tdma->base_addr + tdc->chan_base_offset + reg);
+}
+
+static inline u32 tdc_read(struct tegra_dma_channel *tdc, u32 reg)
+{
+	return readl(tdc->tdma->base_addr + tdc->chan_base_offset + reg);
+}
+
+static inline struct tegra_dma_channel *to_tegra_dma_chan(struct dma_chan *dc)
+{
+	return container_of(dc, struct tegra_dma_channel, dma_chan);
+}
+
+static inline struct tegra_dma_desc *txd_to_tegra_dma_desc(
+		struct dma_async_tx_descriptor *td)
+{
+	return container_of(td, struct tegra_dma_desc, txd);
+}
+
+static inline struct device *tdc2dev(struct tegra_dma_channel *tdc)
+{
+	return &tdc->dma_chan.dev->device;
+}
+
+static dma_cookie_t tegra_dma_tx_submit(struct dma_async_tx_descriptor *tx);
+static int tegra_dma_runtime_suspend(struct device *dev);
+static int tegra_dma_runtime_resume(struct device *dev);
+
+/* Get DMA desc from free list, if not there then allocate it.  */
+static struct tegra_dma_desc *tegra_dma_desc_get(
+		struct tegra_dma_channel *tdc)
+{
+	struct tegra_dma_desc *dma_desc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tdc->lock, flags);
+
+	/* Do not allocate if desc are waiting for ack */
+	list_for_each_entry(dma_desc, &tdc->free_dma_desc, node) {
+		if (async_tx_test_ack(&dma_desc->txd)) {
+			list_del(&dma_desc->node);
+			spin_unlock_irqrestore(&tdc->lock, flags);
+			return dma_desc;
+		}
+	}
+
+	spin_unlock_irqrestore(&tdc->lock, flags);
+
+	/* Allocate DMA desc */
+	dma_desc = kzalloc(sizeof(*dma_desc), GFP_ATOMIC);
+	if (!dma_desc) {
+		dev_err(tdc2dev(tdc), "dma_desc alloc failed\n");
+		return NULL;
+	}
+
+	dma_async_tx_descriptor_init(&dma_desc->txd, &tdc->dma_chan);
+	dma_desc->txd.tx_submit = tegra_dma_tx_submit;
+	dma_desc->txd.flags = 0;
+	return dma_desc;
+}
+
+static void tegra_dma_desc_put(struct tegra_dma_channel *tdc,
+		struct tegra_dma_desc *dma_desc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&tdc->lock, flags);
+	if (!list_empty(&dma_desc->tx_list))
+		list_splice_init(&dma_desc->tx_list, &tdc->free_sg_req);
+	list_add_tail(&dma_desc->node, &tdc->free_dma_desc);
+	spin_unlock_irqrestore(&tdc->lock, flags);
+}
+
+static struct tegra_dma_sg_req *tegra_dma_sg_req_get(
+		struct tegra_dma_channel *tdc)
+{
+	struct tegra_dma_sg_req *sg_req = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tdc->lock, flags);
+	if (!list_empty(&tdc->free_sg_req)) {
+		sg_req = list_first_entry(&tdc->free_sg_req,
+					typeof(*sg_req), node);
+		list_del(&sg_req->node);
+		spin_unlock_irqrestore(&tdc->lock, flags);
+		return sg_req;
+	}
+	spin_unlock_irqrestore(&tdc->lock, flags);
+
+	sg_req = kzalloc(sizeof(struct tegra_dma_sg_req), GFP_ATOMIC);
+	if (!sg_req)
+		dev_err(tdc2dev(tdc), "sg_req alloc failed\n");
+	return sg_req;
+}
+
+static int tegra_dma_slave_config(struct dma_chan *dc,
+		struct dma_slave_config *sconfig)
+{
+	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+
+	if (!list_empty(&tdc->pending_sg_req)) {
+		dev_err(tdc2dev(tdc), "Configuration not allowed\n");
+		return -EBUSY;
+	}
+
+	memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig));
+	tdc->config_init = true;
+	return 0;
+}
+
+static void tegra_dma_global_pause(struct tegra_dma_channel *tdc,
+	bool wait_for_burst_complete)
+{
+	struct tegra_dma *tdma = tdc->tdma;
+
+	spin_lock(&tdma->global_lock);
+	tdma_write(tdma, TEGRA_APBDMA_GENERAL, 0);
+	if (wait_for_burst_complete)
+		udelay(TEGRA_APBDMA_BURST_COMPLETE_TIME);
+}
+
+static void tegra_dma_global_resume(struct tegra_dma_channel *tdc)
+{
+	struct tegra_dma *tdma = tdc->tdma;
+
+	tdma_write(tdma, TEGRA_APBDMA_GENERAL, TEGRA_APBDMA_GENERAL_ENABLE);
+	spin_unlock(&tdma->global_lock);
+}
+
+static void tegra_dma_stop(struct tegra_dma_channel *tdc)
+{
+	u32 csr;
+	u32 status;
+
+	/* Disable interrupts */
+	csr = tdc_read(tdc, TEGRA_APBDMA_CHAN_CSR);
+	csr &= ~TEGRA_APBDMA_CSR_IE_EOC;
+	tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, csr);
+
+	/* Disable DMA */
+	csr &= ~TEGRA_APBDMA_CSR_ENB;
+	tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, csr);
+
+	/* Clear interrupt status if it is there */
+	status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
+	if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
+		dev_dbg(tdc2dev(tdc), "%s():clearing interrupt\n", __func__);
+		tdc_write(tdc, TEGRA_APBDMA_CHAN_STATUS, status);
+	}
+	tdc->busy = false;
+}
+
+static void tegra_dma_start(struct tegra_dma_channel *tdc,
+		struct tegra_dma_sg_req *sg_req)
+{
+	struct tegra_dma_channel_regs *ch_regs = &sg_req->ch_regs;
+
+	tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, ch_regs->csr);
+	tdc_write(tdc, TEGRA_APBDMA_CHAN_APBSEQ, ch_regs->apb_seq);
+	tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, ch_regs->apb_ptr);
+	tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBSEQ, ch_regs->ahb_seq);
+	tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, ch_regs->ahb_ptr);
+
+	/* Start DMA */
+	tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR,
+				ch_regs->csr | TEGRA_APBDMA_CSR_ENB);
+}
+
+static void tegra_dma_configure_for_next(struct tegra_dma_channel *tdc,
+		struct tegra_dma_sg_req *nsg_req)
+{
+	unsigned long status;
+
+	/*
+	 * The DMA controller reloads the new configuration for next transfer
+	 * after last burst of current transfer completes.
+	 * If there is no IEC status then this makes sure that last burst
+	 * has not be completed. There may be case that last burst is on
+	 * flight and so it can complete but because DMA is paused, it
+	 * will not generates interrupt as well as not reload the new
+	 * configuration.
+	 * If there is already IEC status then interrupt handler need to
+	 * load new configuration.
+	 */
+	tegra_dma_global_pause(tdc, false);
+	status  = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
+
+	/*
+	 * If interrupt is pending then do nothing as the ISR will handle
+	 * the programing for new request.
+	 */
+	if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
+		dev_err(tdc2dev(tdc),
+			"Skipping new configuration as interrupt is pending\n");
+		tegra_dma_global_resume(tdc);
+		return;
+	}
+
+	/* Safe to program new configuration */
+	tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, nsg_req->ch_regs.apb_ptr);
+	tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, nsg_req->ch_regs.ahb_ptr);
+	tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR,
+				nsg_req->ch_regs.csr | TEGRA_APBDMA_CSR_ENB);
+	nsg_req->configured = true;
+
+	tegra_dma_global_resume(tdc);
+}
+
+static void tdc_start_head_req(struct tegra_dma_channel *tdc)
+{
+	struct tegra_dma_sg_req *sg_req;
+
+	if (list_empty(&tdc->pending_sg_req))
+		return;
+
+	sg_req = list_first_entry(&tdc->pending_sg_req,
+					typeof(*sg_req), node);
+	tegra_dma_start(tdc, sg_req);
+	sg_req->configured = true;
+	tdc->busy = true;
+}
+
+static void tdc_configure_next_head_desc(struct tegra_dma_channel *tdc)
+{
+	struct tegra_dma_sg_req *hsgreq;
+	struct tegra_dma_sg_req *hnsgreq;
+
+	if (list_empty(&tdc->pending_sg_req))
+		return;
+
+	hsgreq = list_first_entry(&tdc->pending_sg_req, typeof(*hsgreq), node);
+	if (!list_is_last(&hsgreq->node, &tdc->pending_sg_req)) {
+		hnsgreq = list_first_entry(&hsgreq->node,
+					typeof(*hnsgreq), node);
+		tegra_dma_configure_for_next(tdc, hnsgreq);
+	}
+}
+
+static inline int get_current_xferred_count(struct tegra_dma_channel *tdc,
+	struct tegra_dma_sg_req *sg_req, unsigned long status)
+{
+	return sg_req->req_len - (status & TEGRA_APBDMA_STATUS_COUNT_MASK) - 4;
+}
+
+static void tegra_dma_abort_all(struct tegra_dma_channel *tdc)
+{
+	struct tegra_dma_sg_req *sgreq;
+	struct tegra_dma_desc *dma_desc;
+
+	while (!list_empty(&tdc->pending_sg_req)) {
+		sgreq = list_first_entry(&tdc->pending_sg_req,
+						typeof(*sgreq), node);
+		list_del(&sgreq->node);
+		list_add_tail(&sgreq->node, &tdc->free_sg_req);
+		if (sgreq->last_sg) {
+			dma_desc = sgreq->dma_desc;
+			dma_desc->dma_status = DMA_ERROR;
+			list_add_tail(&dma_desc->node, &tdc->free_dma_desc);
+
+			/* Add in cb list if it is not there. */
+			if (!dma_desc->cb_count)
+				list_add_tail(&dma_desc->cb_node,
+							&tdc->cb_desc);
+			dma_desc->cb_count++;
+		}
+	}
+	tdc->isr_handler = NULL;
+}
+
+static bool handle_continuous_head_request(struct tegra_dma_channel *tdc,
+		struct tegra_dma_sg_req *last_sg_req, bool to_terminate)
+{
+	struct tegra_dma_sg_req *hsgreq = NULL;
+
+	if (list_empty(&tdc->pending_sg_req)) {
+		dev_err(tdc2dev(tdc), "Dma is running without req\n");
+		tegra_dma_stop(tdc);
+		return false;
+	}
+
+	/*
+	 * Check that head req on list should be in flight.
+	 * If it is not in flight then abort transfer as
+	 * looping of transfer can not continue.
+	 */
+	hsgreq = list_first_entry(&tdc->pending_sg_req, typeof(*hsgreq), node);
+	if (!hsgreq->configured) {
+		tegra_dma_stop(tdc);
+		dev_err(tdc2dev(tdc), "Error in dma transfer, aborting dma\n");
+		tegra_dma_abort_all(tdc);
+		return false;
+	}
+
+	/* Configure next request */
+	if (!to_terminate)
+		tdc_configure_next_head_desc(tdc);
+	return true;
+}
+
+static void handle_once_dma_done(struct tegra_dma_channel *tdc,
+	bool to_terminate)
+{
+	struct tegra_dma_sg_req *sgreq;
+	struct tegra_dma_desc *dma_desc;
+
+	tdc->busy = false;
+	sgreq = list_first_entry(&tdc->pending_sg_req, typeof(*sgreq), node);
+	dma_desc = sgreq->dma_desc;
+	dma_desc->bytes_transferred += sgreq->req_len;
+
+	list_del(&sgreq->node);
+	if (sgreq->last_sg) {
+		dma_desc->dma_status = DMA_SUCCESS;
+		dma_cookie_complete(&dma_desc->txd);
+		if (!dma_desc->cb_count)
+			list_add_tail(&dma_desc->cb_node, &tdc->cb_desc);
+		dma_desc->cb_count++;
+		list_add_tail(&dma_desc->node, &tdc->free_dma_desc);
+	}
+	list_add_tail(&sgreq->node, &tdc->free_sg_req);
+
+	/* Do not start DMA if it is going to be terminate */
+	if (to_terminate || list_empty(&tdc->pending_sg_req))
+		return;
+
+	tdc_start_head_req(tdc);
+	return;
+}
+
+static void handle_cont_sngl_cycle_dma_done(struct tegra_dma_channel *tdc,
+		bool to_terminate)
+{
+	struct tegra_dma_sg_req *sgreq;
+	struct tegra_dma_desc *dma_desc;
+	bool st;
+
+	sgreq = list_first_entry(&tdc->pending_sg_req, typeof(*sgreq), node);
+	dma_desc = sgreq->dma_desc;
+	dma_desc->bytes_transferred += sgreq->req_len;
+
+	/* Callback need to be call */
+	if (!dma_desc->cb_count)
+		list_add_tail(&dma_desc->cb_node, &tdc->cb_desc);
+	dma_desc->cb_count++;
+
+	/* If not last req then put at end of pending list */
+	if (!list_is_last(&sgreq->node, &tdc->pending_sg_req)) {
+		list_del(&sgreq->node);
+		list_add_tail(&sgreq->node, &tdc->pending_sg_req);
+		sgreq->configured = false;
+		st = handle_continuous_head_request(tdc, sgreq, to_terminate);
+		if (!st)
+			dma_desc->dma_status = DMA_ERROR;
+	}
+	return;
+}
+
+static void tegra_dma_tasklet(unsigned long data)
+{
+	struct tegra_dma_channel *tdc = (struct tegra_dma_channel *)data;
+	dma_async_tx_callback callback = NULL;
+	void *callback_param = NULL;
+	struct tegra_dma_desc *dma_desc;
+	unsigned long flags;
+	int cb_count;
+
+	spin_lock_irqsave(&tdc->lock, flags);
+	while (!list_empty(&tdc->cb_desc)) {
+		dma_desc  = list_first_entry(&tdc->cb_desc,
+					typeof(*dma_desc), cb_node);
+		list_del(&dma_desc->cb_node);
+		callback = dma_desc->txd.callback;
+		callback_param = dma_desc->txd.callback_param;
+		cb_count = dma_desc->cb_count;
+		dma_desc->cb_count = 0;
+		spin_unlock_irqrestore(&tdc->lock, flags);
+		while (cb_count-- && callback)
+			callback(callback_param);
+		spin_lock_irqsave(&tdc->lock, flags);
+	}
+	spin_unlock_irqrestore(&tdc->lock, flags);
+}
+
+static irqreturn_t tegra_dma_isr(int irq, void *dev_id)
+{
+	struct tegra_dma_channel *tdc = dev_id;
+	unsigned long status;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tdc->lock, flags);
+
+	status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
+	if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
+		tdc_write(tdc, TEGRA_APBDMA_CHAN_STATUS, status);
+		tdc->isr_handler(tdc, false);
+		tasklet_schedule(&tdc->tasklet);
+		spin_unlock_irqrestore(&tdc->lock, flags);
+		return IRQ_HANDLED;
+	}
+
+	spin_unlock_irqrestore(&tdc->lock, flags);
+	dev_info(tdc2dev(tdc),
+		"Interrupt already served status 0x%08lx\n", status);
+	return IRQ_NONE;
+}
+
+static dma_cookie_t tegra_dma_tx_submit(struct dma_async_tx_descriptor *txd)
+{
+	struct tegra_dma_desc *dma_desc = txd_to_tegra_dma_desc(txd);
+	struct tegra_dma_channel *tdc = to_tegra_dma_chan(txd->chan);
+	unsigned long flags;
+	dma_cookie_t cookie;
+
+	spin_lock_irqsave(&tdc->lock, flags);
+	dma_desc->dma_status = DMA_IN_PROGRESS;
+	cookie = dma_cookie_assign(&dma_desc->txd);
+	list_splice_tail_init(&dma_desc->tx_list, &tdc->pending_sg_req);
+	spin_unlock_irqrestore(&tdc->lock, flags);
+	return cookie;
+}
+
+static void tegra_dma_issue_pending(struct dma_chan *dc)
+{
+	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&tdc->lock, flags);
+	if (list_empty(&tdc->pending_sg_req)) {
+		dev_err(tdc2dev(tdc), "No DMA request\n");
+		goto end;
+	}
+	if (!tdc->busy) {
+		tdc_start_head_req(tdc);
+
+		/* Continuous single mode: Configure next req */
+		if (tdc->cyclic) {
+			/*
+			 * Wait for 1 burst time for configure DMA for
+			 * next transfer.
+			 */
+			udelay(TEGRA_APBDMA_BURST_COMPLETE_TIME);
+			tdc_configure_next_head_desc(tdc);
+		}
+	}
+end:
+	spin_unlock_irqrestore(&tdc->lock, flags);
+	return;
+}
+
+static void tegra_dma_terminate_all(struct dma_chan *dc)
+{
+	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+	struct tegra_dma_sg_req *sgreq;
+	struct tegra_dma_desc *dma_desc;
+	unsigned long flags;
+	unsigned long status;
+	bool was_busy;
+
+	spin_lock_irqsave(&tdc->lock, flags);
+	if (list_empty(&tdc->pending_sg_req)) {
+		spin_unlock_irqrestore(&tdc->lock, flags);
+		return;
+	}
+
+	if (!tdc->busy)
+		goto skip_dma_stop;
+
+	/* Pause DMA before checking the queue status */
+	tegra_dma_global_pause(tdc, true);
+
+	status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
+	if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
+		dev_dbg(tdc2dev(tdc), "%s():handling isr\n", __func__);
+		tdc->isr_handler(tdc, true);
+		status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
+	}
+
+	was_busy = tdc->busy;
+	tegra_dma_stop(tdc);
+
+	if (!list_empty(&tdc->pending_sg_req) && was_busy) {
+		sgreq = list_first_entry(&tdc->pending_sg_req,
+					typeof(*sgreq), node);
+		sgreq->dma_desc->bytes_transferred +=
+				get_current_xferred_count(tdc, sgreq, status);
+	}
+	tegra_dma_global_resume(tdc);
+
+skip_dma_stop:
+	tegra_dma_abort_all(tdc);
+
+	while (!list_empty(&tdc->cb_desc)) {
+		dma_desc  = list_first_entry(&tdc->cb_desc,
+					typeof(*dma_desc), cb_node);
+		list_del(&dma_desc->cb_node);
+		dma_desc->cb_count = 0;
+	}
+	spin_unlock_irqrestore(&tdc->lock, flags);
+}
+
+static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
+	dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+	struct tegra_dma_desc *dma_desc;
+	struct tegra_dma_sg_req *sg_req;
+	enum dma_status ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tdc->lock, flags);
+
+	ret = dma_cookie_status(dc, cookie, txstate);
+	if (ret == DMA_SUCCESS) {
+		dma_set_residue(txstate, 0);
+		spin_unlock_irqrestore(&tdc->lock, flags);
+		return ret;
+	}
+
+	/* Check on wait_ack desc status */
+	list_for_each_entry(dma_desc, &tdc->free_dma_desc, node) {
+		if (dma_desc->txd.cookie == cookie) {
+			dma_set_residue(txstate,
+				dma_desc->bytes_requested -
+				dma_desc->bytes_transferred);
+			ret = dma_desc->dma_status;
+			spin_unlock_irqrestore(&tdc->lock, flags);
+			return ret;
+		}
+	}
+
+	/* Check in pending list */
+	list_for_each_entry(sg_req, &tdc->pending_sg_req, node) {
+		dma_desc = sg_req->dma_desc;
+		if (dma_desc->txd.cookie == cookie) {
+			dma_set_residue(txstate,
+				dma_desc->bytes_requested -
+				dma_desc->bytes_transferred);
+			ret = dma_desc->dma_status;
+			spin_unlock_irqrestore(&tdc->lock, flags);
+			return ret;
+		}
+	}
+
+	dev_dbg(tdc2dev(tdc), "cookie %d does not found\n", cookie);
+	spin_unlock_irqrestore(&tdc->lock, flags);
+	return ret;
+}
+
+static int tegra_dma_device_control(struct dma_chan *dc, enum dma_ctrl_cmd cmd,
+			unsigned long arg)
+{
+	switch (cmd) {
+	case DMA_SLAVE_CONFIG:
+		return tegra_dma_slave_config(dc,
+				(struct dma_slave_config *)arg);
+
+	case DMA_TERMINATE_ALL:
+		tegra_dma_terminate_all(dc);
+		return 0;
+
+	default:
+		break;
+	}
+
+	return -ENXIO;
+}
+
+static inline int get_bus_width(struct tegra_dma_channel *tdc,
+		enum dma_slave_buswidth slave_bw)
+{
+	switch (slave_bw) {
+	case DMA_SLAVE_BUSWIDTH_1_BYTE:
+		return TEGRA_APBDMA_APBSEQ_BUS_WIDTH_8;
+	case DMA_SLAVE_BUSWIDTH_2_BYTES:
+		return TEGRA_APBDMA_APBSEQ_BUS_WIDTH_16;
+	case DMA_SLAVE_BUSWIDTH_4_BYTES:
+		return TEGRA_APBDMA_APBSEQ_BUS_WIDTH_32;
+	case DMA_SLAVE_BUSWIDTH_8_BYTES:
+		return TEGRA_APBDMA_APBSEQ_BUS_WIDTH_64;
+	default:
+		dev_warn(tdc2dev(tdc),
+			"slave bw is not supported, using 32bits\n");
+		return TEGRA_APBDMA_APBSEQ_BUS_WIDTH_32;
+	}
+}
+
+static inline int get_burst_size(struct tegra_dma_channel *tdc,
+	u32 burst_size, enum dma_slave_buswidth slave_bw, int len)
+{
+	int burst_byte;
+	int burst_ahb_width;
+
+	/*
+	 * burst_size from client is in terms of the bus_width.
+	 * convert them into AHB memory width which is 4 byte.
+	 */
+	burst_byte = burst_size * slave_bw;
+	burst_ahb_width = burst_byte / 4;
+
+	/* If burst size is 0 then calculate the burst size based on length */
+	if (!burst_ahb_width) {
+		if (len & 0xF)
+			return TEGRA_APBDMA_AHBSEQ_BURST_1;
+		else if ((len >> 4) & 0x1)
+			return TEGRA_APBDMA_AHBSEQ_BURST_4;
+		else
+			return TEGRA_APBDMA_AHBSEQ_BURST_8;
+	}
+	if (burst_ahb_width < 4)
+		return TEGRA_APBDMA_AHBSEQ_BURST_1;
+	else if (burst_ahb_width < 8)
+		return TEGRA_APBDMA_AHBSEQ_BURST_4;
+	else
+		return TEGRA_APBDMA_AHBSEQ_BURST_8;
+}
+
+static int get_transfer_param(struct tegra_dma_channel *tdc,
+	enum dma_transfer_direction direction, unsigned long *apb_addr,
+	unsigned long *apb_seq,	unsigned long *csr, unsigned int *burst_size,
+	enum dma_slave_buswidth *slave_bw)
+{
+
+	switch (direction) {
+	case DMA_MEM_TO_DEV:
+		*apb_addr = tdc->dma_sconfig.dst_addr;
+		*apb_seq = get_bus_width(tdc, tdc->dma_sconfig.dst_addr_width);
+		*burst_size = tdc->dma_sconfig.dst_maxburst;
+		*slave_bw = tdc->dma_sconfig.dst_addr_width;
+		*csr = TEGRA_APBDMA_CSR_DIR;
+		return 0;
+
+	case DMA_DEV_TO_MEM:
+		*apb_addr = tdc->dma_sconfig.src_addr;
+		*apb_seq = get_bus_width(tdc, tdc->dma_sconfig.src_addr_width);
+		*burst_size = tdc->dma_sconfig.src_maxburst;
+		*slave_bw = tdc->dma_sconfig.src_addr_width;
+		*csr = 0;
+		return 0;
+
+	default:
+		dev_err(tdc2dev(tdc), "Dma direction is not supported\n");
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
+static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
+	struct dma_chan *dc, struct scatterlist *sgl, unsigned int sg_len,
+	enum dma_transfer_direction direction, unsigned long flags,
+	void *context)
+{
+	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+	struct tegra_dma_desc *dma_desc;
+	unsigned int	    i;
+	struct scatterlist      *sg;
+	unsigned long csr, ahb_seq, apb_ptr, apb_seq;
+	struct list_head req_list;
+	struct tegra_dma_sg_req  *sg_req = NULL;
+	u32 burst_size;
+	enum dma_slave_buswidth slave_bw;
+	int ret;
+
+	if (!tdc->config_init) {
+		dev_err(tdc2dev(tdc), "dma channel is not configured\n");
+		return NULL;
+	}
+	if (sg_len < 1) {
+		dev_err(tdc2dev(tdc), "Invalid segment length %d\n", sg_len);
+		return NULL;
+	}
+
+	ret = get_transfer_param(tdc, direction, &apb_ptr, &apb_seq, &csr,
+				&burst_size, &slave_bw);
+	if (ret < 0)
+		return NULL;
+
+	INIT_LIST_HEAD(&req_list);
+
+	ahb_seq = TEGRA_APBDMA_AHBSEQ_INTR_ENB;
+	ahb_seq |= TEGRA_APBDMA_AHBSEQ_WRAP_NONE <<
+					TEGRA_APBDMA_AHBSEQ_WRAP_SHIFT;
+	ahb_seq |= TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32;
+
+	csr |= TEGRA_APBDMA_CSR_ONCE | TEGRA_APBDMA_CSR_FLOW;
+	csr |= tdc->dma_sconfig.slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
+	if (flags & DMA_PREP_INTERRUPT)
+		csr |= TEGRA_APBDMA_CSR_IE_EOC;
+
+	apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1;
+
+	dma_desc = tegra_dma_desc_get(tdc);
+	if (!dma_desc) {
+		dev_err(tdc2dev(tdc), "Dma descriptors not available\n");
+		return NULL;
+	}
+	INIT_LIST_HEAD(&dma_desc->tx_list);
+	INIT_LIST_HEAD(&dma_desc->cb_node);
+	dma_desc->cb_count = 0;
+	dma_desc->bytes_requested = 0;
+	dma_desc->bytes_transferred = 0;
+	dma_desc->dma_status = DMA_IN_PROGRESS;
+
+	/* Make transfer requests */
+	for_each_sg(sgl, sg, sg_len, i) {
+		u32 len, mem;
+
+		mem = sg_phys(sg);
+		len = sg_dma_len(sg);
+
+		if ((len & 3) || (mem & 3) ||
+				(len > tdc->tdma->chip_data->max_dma_count)) {
+			dev_err(tdc2dev(tdc),
+				"Dma length/memory address is not supported\n");
+			tegra_dma_desc_put(tdc, dma_desc);
+			return NULL;
+		}
+
+		sg_req = tegra_dma_sg_req_get(tdc);
+		if (!sg_req) {
+			dev_err(tdc2dev(tdc), "Dma sg-req not available\n");
+			tegra_dma_desc_put(tdc, dma_desc);
+			return NULL;
+		}
+
+		ahb_seq |= get_burst_size(tdc, burst_size, slave_bw, len);
+		dma_desc->bytes_requested += len;
+
+		sg_req->ch_regs.apb_ptr = apb_ptr;
+		sg_req->ch_regs.ahb_ptr = mem;
+		sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC);
+		sg_req->ch_regs.apb_seq = apb_seq;
+		sg_req->ch_regs.ahb_seq = ahb_seq;
+		sg_req->configured = false;
+		sg_req->last_sg = false;
+		sg_req->dma_desc = dma_desc;
+		sg_req->req_len = len;
+
+		list_add_tail(&sg_req->node, &dma_desc->tx_list);
+	}
+	sg_req->last_sg = true;
+	if (flags & DMA_CTRL_ACK)
+		dma_desc->txd.flags = DMA_CTRL_ACK;
+
+	/*
+	 * Make sure that mode should not be conflicting with currently
+	 * configured mode.
+	 */
+	if (!tdc->isr_handler) {
+		tdc->isr_handler = handle_once_dma_done;
+		tdc->cyclic = false;
+	} else {
+		if (tdc->cyclic) {
+			dev_err(tdc2dev(tdc), "DMA configured in cyclic mode\n");
+			tegra_dma_desc_put(tdc, dma_desc);
+			return NULL;
+		}
+	}
+
+	return &dma_desc->txd;
+}
+
+struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
+	struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_len,
+	size_t period_len, enum dma_transfer_direction direction,
+	void *context)
+{
+	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+	struct tegra_dma_desc *dma_desc = NULL;
+	struct tegra_dma_sg_req  *sg_req = NULL;
+	unsigned long csr, ahb_seq, apb_ptr, apb_seq;
+	int len;
+	size_t remain_len;
+	dma_addr_t mem = buf_addr;
+	u32 burst_size;
+	enum dma_slave_buswidth slave_bw;
+	int ret;
+
+	if (!buf_len || !period_len) {
+		dev_err(tdc2dev(tdc), "Invalid buffer/period len\n");
+		return NULL;
+	}
+
+	if (!tdc->config_init) {
+		dev_err(tdc2dev(tdc), "DMA slave is not configured\n");
+		return NULL;
+	}
+
+	/*
+	 * We allow to take more number of requests till DMA is
+	 * not started. The driver will loop over all requests.
+	 * Once DMA is started then new requests can be queued only after
+	 * terminating the DMA.
+	 */
+	if (tdc->busy) {
+		dev_err(tdc2dev(tdc), "Request not allowed when dma running\n");
+		return NULL;
+	}
+
+	/*
+	 * We only support cycle transfer when buf_len is multiple of
+	 * period_len.
+	 */
+	if (buf_len % period_len) {
+		dev_err(tdc2dev(tdc), "buf_len is not multiple of period_len\n");
+		return NULL;
+	}
+
+	len = period_len;
+	if ((len & 3) || (buf_addr & 3) ||
+			(len > tdc->tdma->chip_data->max_dma_count)) {
+		dev_err(tdc2dev(tdc), "Req len/mem address is not correct\n");
+		return NULL;
+	}
+
+	ret = get_transfer_param(tdc, direction, &apb_ptr, &apb_seq, &csr,
+				&burst_size, &slave_bw);
+	if (ret < 0)
+		return NULL;
+
+
+	ahb_seq = TEGRA_APBDMA_AHBSEQ_INTR_ENB;
+	ahb_seq |= TEGRA_APBDMA_AHBSEQ_WRAP_NONE <<
+					TEGRA_APBDMA_AHBSEQ_WRAP_SHIFT;
+	ahb_seq |= TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32;
+
+	csr |= TEGRA_APBDMA_CSR_FLOW | TEGRA_APBDMA_CSR_IE_EOC;
+	csr |= tdc->dma_sconfig.slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
+
+	apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1;
+
+	dma_desc = tegra_dma_desc_get(tdc);
+	if (!dma_desc) {
+		dev_err(tdc2dev(tdc), "not enough descriptors available\n");
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&dma_desc->tx_list);
+	INIT_LIST_HEAD(&dma_desc->cb_node);
+	dma_desc->cb_count = 0;
+
+	dma_desc->bytes_transferred = 0;
+	dma_desc->bytes_requested = buf_len;
+	remain_len = buf_len;
+
+	/* Split transfer equal to period size */
+	while (remain_len) {
+		sg_req = tegra_dma_sg_req_get(tdc);
+		if (!sg_req) {
+			dev_err(tdc2dev(tdc), "Dma sg-req not available\n");
+			tegra_dma_desc_put(tdc, dma_desc);
+			return NULL;
+		}
+
+		ahb_seq |= get_burst_size(tdc, burst_size, slave_bw, len);
+		sg_req->ch_regs.apb_ptr = apb_ptr;
+		sg_req->ch_regs.ahb_ptr = mem;
+		sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC);
+		sg_req->ch_regs.apb_seq = apb_seq;
+		sg_req->ch_regs.ahb_seq = ahb_seq;
+		sg_req->configured = false;
+		sg_req->half_done = false;
+		sg_req->last_sg = false;
+		sg_req->dma_desc = dma_desc;
+		sg_req->req_len = len;
+
+		list_add_tail(&sg_req->node, &dma_desc->tx_list);
+		remain_len -= len;
+		mem += len;
+	}
+	sg_req->last_sg = true;
+	dma_desc->txd.flags = DMA_CTRL_ACK;
+
+	/*
+	 * Make sure that mode should not be conflicting with currently
+	 * configured mode.
+	 */
+	if (!tdc->isr_handler) {
+		tdc->isr_handler = handle_cont_sngl_cycle_dma_done;
+		tdc->cyclic = true;
+	} else {
+		if (!tdc->cyclic) {
+			dev_err(tdc2dev(tdc), "DMA configuration conflict\n");
+			tegra_dma_desc_put(tdc, dma_desc);
+			return NULL;
+		}
+	}
+
+	return &dma_desc->txd;
+}
+
+static int tegra_dma_alloc_chan_resources(struct dma_chan *dc)
+{
+	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+
+	dma_cookie_init(&tdc->dma_chan);
+	tdc->config_init = false;
+	return 0;
+}
+
+static void tegra_dma_free_chan_resources(struct dma_chan *dc)
+{
+	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+
+	struct tegra_dma_desc *dma_desc;
+	struct tegra_dma_sg_req *sg_req;
+	struct list_head dma_desc_list;
+	struct list_head sg_req_list;
+	unsigned long flags;
+
+	INIT_LIST_HEAD(&dma_desc_list);
+	INIT_LIST_HEAD(&sg_req_list);
+
+	dev_dbg(tdc2dev(tdc), "Freeing channel %d\n", tdc->id);
+
+	if (tdc->busy)
+		tegra_dma_terminate_all(dc);
+
+	spin_lock_irqsave(&tdc->lock, flags);
+	list_splice_init(&tdc->pending_sg_req, &sg_req_list);
+	list_splice_init(&tdc->free_sg_req, &sg_req_list);
+	list_splice_init(&tdc->free_dma_desc, &dma_desc_list);
+	INIT_LIST_HEAD(&tdc->cb_desc);
+	tdc->config_init = false;
+	spin_unlock_irqrestore(&tdc->lock, flags);
+
+	while (!list_empty(&dma_desc_list)) {
+		dma_desc = list_first_entry(&dma_desc_list,
+					typeof(*dma_desc), node);
+		list_del(&dma_desc->node);
+		kfree(dma_desc);
+	}
+
+	while (!list_empty(&sg_req_list)) {
+		sg_req = list_first_entry(&sg_req_list, typeof(*sg_req), node);
+		list_del(&sg_req->node);
+		kfree(sg_req);
+	}
+}
+
+/* Tegra20 specific DMA controller information */
+static struct tegra_dma_chip_data tegra20_dma_chip_data = {
+	.nr_channels		= 16,
+	.max_dma_count		= 1024UL * 64,
+};
+
+#if defined(CONFIG_OF)
+/* Tegra30 specific DMA controller information */
+static struct tegra_dma_chip_data tegra30_dma_chip_data = {
+	.nr_channels		= 32,
+	.max_dma_count		= 1024UL * 64,
+};
+
+static const struct of_device_id tegra_dma_of_match[] __devinitconst = {
+	{
+		.compatible = "nvidia,tegra30-apbdma-new",
+		.data = &tegra30_dma_chip_data,
+	}, {
+		.compatible = "nvidia,tegra20-apbdma-new",
+		.data = &tegra20_dma_chip_data,
+	}, {
+	},
+};
+MODULE_DEVICE_TABLE(of, tegra_dma_of_match);
+#endif
+
+static int __devinit tegra_dma_probe(struct platform_device *pdev)
+{
+	struct resource	*res;
+	struct tegra_dma *tdma;
+	int ret;
+	int i;
+	struct tegra_dma_chip_data *cdata = NULL;
+
+	if (pdev->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_device(of_match_ptr(tegra_dma_of_match),
+					&pdev->dev);
+		if (!match) {
+			dev_err(&pdev->dev, "Error: No device match found\n");
+			return -ENODEV;
+		}
+		cdata = match->data;
+	} else {
+		/* If no device tree then fallback to tegra20 */
+		cdata = &tegra20_dma_chip_data;
+	}
+
+	tdma = devm_kzalloc(&pdev->dev, sizeof(*tdma) + cdata->nr_channels *
+			sizeof(struct tegra_dma_channel), GFP_KERNEL);
+	if (!tdma) {
+		dev_err(&pdev->dev, "Error: memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	tdma->dev = &pdev->dev;
+	tdma->chip_data = cdata;
+	platform_set_drvdata(pdev, tdma);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "No mem resource for DMA\n");
+		return -EINVAL;
+	}
+
+	tdma->base_addr = devm_request_and_ioremap(&pdev->dev, res);
+	if (!tdma->base_addr) {
+		dev_err(&pdev->dev,
+			"Cannot request memregion/iomap dma address\n");
+		return -EADDRNOTAVAIL;
+	}
+
+	tdma->dma_clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(tdma->dma_clk)) {
+		dev_err(&pdev->dev, "Error: Missing controller clock\n");
+		return PTR_ERR(tdma->dma_clk);
+	}
+
+	spin_lock_init(&tdma->global_lock);
+
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev)) {
+		ret = tegra_dma_runtime_resume(&pdev->dev);
+		if (ret) {
+			dev_err(&pdev->dev, "dma_runtime_resume failed %d\n",
+				ret);
+			goto err_pm_disable;
+		}
+	}
+
+	/* Reset DMA controller */
+	tegra_periph_reset_assert(tdma->dma_clk);
+	udelay(2);
+	tegra_periph_reset_deassert(tdma->dma_clk);
+
+	/* Enable global DMA registers */
+	tdma_write(tdma, TEGRA_APBDMA_GENERAL, TEGRA_APBDMA_GENERAL_ENABLE);
+	tdma_write(tdma, TEGRA_APBDMA_CONTROL, 0);
+	tdma_write(tdma, TEGRA_APBDMA_IRQ_MASK_SET, 0xFFFFFFFFul);
+
+	INIT_LIST_HEAD(&tdma->dma_dev.channels);
+	for (i = 0; i < cdata->nr_channels; i++) {
+		struct tegra_dma_channel *tdc = &tdma->channels[i];
+		char irq_name[30];
+
+		tdc->chan_base_offset = TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET +
+					i * TEGRA_APBDMA_CHANNEL_REGISTER_SIZE;
+
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+		if (!res) {
+			ret = -EINVAL;
+			dev_err(&pdev->dev, "No irq resource for chan %d\n", i);
+			goto err_irq;
+		}
+		tdc->irq = res->start;
+		snprintf(irq_name, sizeof(irq_name), "apbdma.%d", i);
+		ret = devm_request_irq(&pdev->dev, tdc->irq,
+				tegra_dma_isr, 0, irq_name, tdc);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"request_irq failed with err %d channel %d\n",
+				i, ret);
+			goto err_irq;
+		}
+
+		tdc->dma_chan.device = &tdma->dma_dev;
+		dma_cookie_init(&tdc->dma_chan);
+		list_add_tail(&tdc->dma_chan.device_node,
+				&tdma->dma_dev.channels);
+		tdc->tdma = tdma;
+		tdc->id = i;
+
+		tasklet_init(&tdc->tasklet, tegra_dma_tasklet,
+				(unsigned long)tdc);
+		spin_lock_init(&tdc->lock);
+
+		INIT_LIST_HEAD(&tdc->pending_sg_req);
+		INIT_LIST_HEAD(&tdc->free_sg_req);
+		INIT_LIST_HEAD(&tdc->free_dma_desc);
+		INIT_LIST_HEAD(&tdc->cb_desc);
+	}
+
+	dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask);
+	dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask);
+	tdma->dma_dev.dev = &pdev->dev;
+	tdma->dma_dev.device_alloc_chan_resources =
+					tegra_dma_alloc_chan_resources;
+	tdma->dma_dev.device_free_chan_resources =
+					tegra_dma_free_chan_resources;
+	tdma->dma_dev.device_prep_slave_sg = tegra_dma_prep_slave_sg;
+	tdma->dma_dev.device_prep_dma_cyclic = tegra_dma_prep_dma_cyclic;
+	tdma->dma_dev.device_control = tegra_dma_device_control;
+	tdma->dma_dev.device_tx_status = tegra_dma_tx_status;
+	tdma->dma_dev.device_issue_pending = tegra_dma_issue_pending;
+
+	ret = dma_async_device_register(&tdma->dma_dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"Tegra20 APB DMA driver registration failed %d\n", ret);
+		goto err_irq;
+	}
+
+	dev_info(&pdev->dev, "Tegra20 APB DMA driver register %d channels\n",
+			cdata->nr_channels);
+	return 0;
+
+err_irq:
+	while (--i >= 0) {
+		struct tegra_dma_channel *tdc = &tdma->channels[i];
+		tasklet_kill(&tdc->tasklet);
+	}
+
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		tegra_dma_runtime_suspend(&pdev->dev);
+	return ret;
+}
+
+static int __devexit tegra_dma_remove(struct platform_device *pdev)
+{
+	struct tegra_dma *tdma = platform_get_drvdata(pdev);
+	int i;
+	struct tegra_dma_channel *tdc;
+
+	dma_async_device_unregister(&tdma->dma_dev);
+
+	for (i = 0; i < tdma->chip_data->nr_channels; ++i) {
+		tdc = &tdma->channels[i];
+		tasklet_kill(&tdc->tasklet);
+	}
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		tegra_dma_runtime_suspend(&pdev->dev);
+
+	return 0;
+}
+
+static int tegra_dma_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tegra_dma *tdma = platform_get_drvdata(pdev);
+
+	clk_disable(tdma->dma_clk);
+	return 0;
+}
+
+static int tegra_dma_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tegra_dma *tdma = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = clk_enable(tdma->dma_clk);
+	if (ret < 0) {
+		dev_err(dev, "clk_enable failed: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static const struct dev_pm_ops tegra_dma_dev_pm_ops __devinitconst = {
+#ifdef CONFIG_PM_RUNTIME
+	.runtime_suspend = tegra_dma_runtime_suspend,
+	.runtime_resume = tegra_dma_runtime_resume,
+#endif
+};
+
+static struct platform_driver tegra_dmac_driver = {
+	.driver = {
+		.name	= "tegra20-apbdma",
+		.owner = THIS_MODULE,
+		.pm	= &tegra_dma_dev_pm_ops,
+		.of_match_table = of_match_ptr(tegra_dma_of_match),
+	},
+	.probe		= tegra_dma_probe,
+	.remove		= __devexit_p(tegra_dma_remove),
+};
+
+module_platform_driver(tegra_dmac_driver);
+
+MODULE_ALIAS("platform:tegra20-apbdma");
+MODULE_DESCRIPTION("NVIDIA Tegra APB DMA Controller driver");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index fdffa1b..409b92b 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -7,7 +7,7 @@
 menuconfig EDAC
 	bool "EDAC (Error Detection And Correction) reporting"
 	depends on HAS_IOMEM
-	depends on X86 || PPC || TILE
+	depends on X86 || PPC || TILE || ARM
 	help
 	  EDAC is designed to report errors in the core system.
 	  These are low-level errors that are reported in the CPU or
@@ -31,6 +31,14 @@ if EDAC
 
 comment "Reporting subsystems"
 
+config EDAC_LEGACY_SYSFS
+	bool "EDAC legacy sysfs"
+	default y
+	help
+	  Enable the compatibility sysfs nodes.
+	  Use 'Y' if your edac utilities aren't ported to work with the newer
+	  structures.
+
 config EDAC_DEBUG
 	bool "Debugging"
 	help
@@ -294,4 +302,18 @@ config EDAC_TILE
 	  Support for error detection and correction on the
 	  Tilera memory controller.
 
+config EDAC_HIGHBANK_MC
+	tristate "Highbank Memory Controller"
+	depends on EDAC_MM_EDAC && ARCH_HIGHBANK
+	help
+	  Support for error detection and correction on the
+	  Calxeda Highbank memory controller.
+
+config EDAC_HIGHBANK_L2
+	tristate "Highbank L2 Cache"
+	depends on EDAC_MM_EDAC && ARCH_HIGHBANK
+	help
+	  Support for error detection and correction on the
+	  Calxeda Highbank memory controller.
+
 endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 196a63d..7e5129a 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -55,3 +55,6 @@ obj-$(CONFIG_EDAC_AMD8111)		+= amd8111_edac.o
 obj-$(CONFIG_EDAC_AMD8131)		+= amd8131_edac.o
 
 obj-$(CONFIG_EDAC_TILE)			+= tile_edac.o
+
+obj-$(CONFIG_EDAC_HIGHBANK_MC)	+= highbank_mc_edac.o
+obj-$(CONFIG_EDAC_HIGHBANK_L2)	+= highbank_l2_edac.o
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 7be9b72..5a297a2 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -321,8 +321,8 @@ found:
 	return edac_mc_find((int)node_id);
 
 err_no_match:
-	debugf2("sys_addr 0x%lx doesn't match any node\n",
-		(unsigned long)sys_addr);
+	edac_dbg(2, "sys_addr 0x%lx doesn't match any node\n",
+		 (unsigned long)sys_addr);
 
 	return NULL;
 }
@@ -393,15 +393,15 @@ static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
 		mask = ~mask;
 
 		if ((input_addr & mask) == (base & mask)) {
-			debugf2("InputAddr 0x%lx matches csrow %d (node %d)\n",
-				(unsigned long)input_addr, csrow,
-				pvt->mc_node_id);
+			edac_dbg(2, "InputAddr 0x%lx matches csrow %d (node %d)\n",
+				 (unsigned long)input_addr, csrow,
+				 pvt->mc_node_id);
 
 			return csrow;
 		}
 	}
-	debugf2("no matching csrow for InputAddr 0x%lx (MC node %d)\n",
-		(unsigned long)input_addr, pvt->mc_node_id);
+	edac_dbg(2, "no matching csrow for InputAddr 0x%lx (MC node %d)\n",
+		 (unsigned long)input_addr, pvt->mc_node_id);
 
 	return -1;
 }
@@ -430,20 +430,20 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
 
 	/* only revE and later have the DRAM Hole Address Register */
 	if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_E) {
-		debugf1("  revision %d for node %d does not support DHAR\n",
-			pvt->ext_model, pvt->mc_node_id);
+		edac_dbg(1, "  revision %d for node %d does not support DHAR\n",
+			 pvt->ext_model, pvt->mc_node_id);
 		return 1;
 	}
 
 	/* valid for Fam10h and above */
 	if (boot_cpu_data.x86 >= 0x10 && !dhar_mem_hoist_valid(pvt)) {
-		debugf1("  Dram Memory Hoisting is DISABLED on this system\n");
+		edac_dbg(1, "  Dram Memory Hoisting is DISABLED on this system\n");
 		return 1;
 	}
 
 	if (!dhar_valid(pvt)) {
-		debugf1("  Dram Memory Hoisting is DISABLED on this node %d\n",
-			pvt->mc_node_id);
+		edac_dbg(1, "  Dram Memory Hoisting is DISABLED on this node %d\n",
+			 pvt->mc_node_id);
 		return 1;
 	}
 
@@ -475,9 +475,9 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
 	else
 		*hole_offset = k8_dhar_offset(pvt);
 
-	debugf1("  DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
-		pvt->mc_node_id, (unsigned long)*hole_base,
-		(unsigned long)*hole_offset, (unsigned long)*hole_size);
+	edac_dbg(1, "  DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
+		 pvt->mc_node_id, (unsigned long)*hole_base,
+		 (unsigned long)*hole_offset, (unsigned long)*hole_size);
 
 	return 0;
 }
@@ -528,10 +528,9 @@ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
 			/* use DHAR to translate SysAddr to DramAddr */
 			dram_addr = sys_addr - hole_offset;
 
-			debugf2("using DHAR to translate SysAddr 0x%lx to "
-				"DramAddr 0x%lx\n",
-				(unsigned long)sys_addr,
-				(unsigned long)dram_addr);
+			edac_dbg(2, "using DHAR to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
+				 (unsigned long)sys_addr,
+				 (unsigned long)dram_addr);
 
 			return dram_addr;
 		}
@@ -548,9 +547,8 @@ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
 	 */
 	dram_addr = (sys_addr & GENMASK(0, 39)) - dram_base;
 
-	debugf2("using DRAM Base register to translate SysAddr 0x%lx to "
-		"DramAddr 0x%lx\n", (unsigned long)sys_addr,
-		(unsigned long)dram_addr);
+	edac_dbg(2, "using DRAM Base register to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
+		 (unsigned long)sys_addr, (unsigned long)dram_addr);
 	return dram_addr;
 }
 
@@ -586,9 +584,9 @@ static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)
 	input_addr = ((dram_addr >> intlv_shift) & GENMASK(12, 35)) +
 		      (dram_addr & 0xfff);
 
-	debugf2("  Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n",
-		intlv_shift, (unsigned long)dram_addr,
-		(unsigned long)input_addr);
+	edac_dbg(2, "  Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n",
+		 intlv_shift, (unsigned long)dram_addr,
+		 (unsigned long)input_addr);
 
 	return input_addr;
 }
@@ -604,8 +602,8 @@ static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
 	input_addr =
 	    dram_addr_to_input_addr(mci, sys_addr_to_dram_addr(mci, sys_addr));
 
-	debugf2("SysAdddr 0x%lx translates to InputAddr 0x%lx\n",
-		(unsigned long)sys_addr, (unsigned long)input_addr);
+	edac_dbg(2, "SysAdddr 0x%lx translates to InputAddr 0x%lx\n",
+		 (unsigned long)sys_addr, (unsigned long)input_addr);
 
 	return input_addr;
 }
@@ -637,8 +635,8 @@ static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
 
 	intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
 	if (intlv_shift == 0) {
-		debugf1("    InputAddr 0x%lx translates to DramAddr of "
-			"same value\n",	(unsigned long)input_addr);
+		edac_dbg(1, "    InputAddr 0x%lx translates to DramAddr of same value\n",
+			 (unsigned long)input_addr);
 
 		return input_addr;
 	}
@@ -649,9 +647,9 @@ static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
 	intlv_sel = dram_intlv_sel(pvt, node_id) & ((1 << intlv_shift) - 1);
 	dram_addr = bits + (intlv_sel << 12);
 
-	debugf1("InputAddr 0x%lx translates to DramAddr 0x%lx "
-		"(%d node interleave bits)\n", (unsigned long)input_addr,
-		(unsigned long)dram_addr, intlv_shift);
+	edac_dbg(1, "InputAddr 0x%lx translates to DramAddr 0x%lx (%d node interleave bits)\n",
+		 (unsigned long)input_addr,
+		 (unsigned long)dram_addr, intlv_shift);
 
 	return dram_addr;
 }
@@ -673,9 +671,9 @@ static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
 		    (dram_addr < (hole_base + hole_size))) {
 			sys_addr = dram_addr + hole_offset;
 
-			debugf1("using DHAR to translate DramAddr 0x%lx to "
-				"SysAddr 0x%lx\n", (unsigned long)dram_addr,
-				(unsigned long)sys_addr);
+			edac_dbg(1, "using DHAR to translate DramAddr 0x%lx to SysAddr 0x%lx\n",
+				 (unsigned long)dram_addr,
+				 (unsigned long)sys_addr);
 
 			return sys_addr;
 		}
@@ -697,9 +695,9 @@ static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
 	 */
 	sys_addr |= ~((sys_addr & (1ull << 39)) - 1);
 
-	debugf1("    Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n",
-		pvt->mc_node_id, (unsigned long)dram_addr,
-		(unsigned long)sys_addr);
+	edac_dbg(1, "    Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n",
+		 pvt->mc_node_id, (unsigned long)dram_addr,
+		 (unsigned long)sys_addr);
 
 	return sys_addr;
 }
@@ -768,49 +766,48 @@ static void amd64_debug_display_dimm_sizes(struct amd64_pvt *, u8);
 
 static void amd64_dump_dramcfg_low(u32 dclr, int chan)
 {
-	debugf1("F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
+	edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
 
-	debugf1("  DIMM type: %sbuffered; all DIMMs support ECC: %s\n",
-		(dclr & BIT(16)) ?  "un" : "",
-		(dclr & BIT(19)) ? "yes" : "no");
+	edac_dbg(1, "  DIMM type: %sbuffered; all DIMMs support ECC: %s\n",
+		 (dclr & BIT(16)) ?  "un" : "",
+		 (dclr & BIT(19)) ? "yes" : "no");
 
-	debugf1("  PAR/ERR parity: %s\n",
-		(dclr & BIT(8)) ?  "enabled" : "disabled");
+	edac_dbg(1, "  PAR/ERR parity: %s\n",
+		 (dclr & BIT(8)) ?  "enabled" : "disabled");
 
 	if (boot_cpu_data.x86 == 0x10)
-		debugf1("  DCT 128bit mode width: %s\n",
-			(dclr & BIT(11)) ?  "128b" : "64b");
+		edac_dbg(1, "  DCT 128bit mode width: %s\n",
+			 (dclr & BIT(11)) ?  "128b" : "64b");
 
-	debugf1("  x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n",
-		(dclr & BIT(12)) ?  "yes" : "no",
-		(dclr & BIT(13)) ?  "yes" : "no",
-		(dclr & BIT(14)) ?  "yes" : "no",
-		(dclr & BIT(15)) ?  "yes" : "no");
+	edac_dbg(1, "  x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n",
+		 (dclr & BIT(12)) ?  "yes" : "no",
+		 (dclr & BIT(13)) ?  "yes" : "no",
+		 (dclr & BIT(14)) ?  "yes" : "no",
+		 (dclr & BIT(15)) ?  "yes" : "no");
 }
 
 /* Display and decode various NB registers for debug purposes. */
 static void dump_misc_regs(struct amd64_pvt *pvt)
 {
-	debugf1("F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
+	edac_dbg(1, "F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
 
-	debugf1("  NB two channel DRAM capable: %s\n",
-		(pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
+	edac_dbg(1, "  NB two channel DRAM capable: %s\n",
+		 (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
 
-	debugf1("  ECC capable: %s, ChipKill ECC capable: %s\n",
-		(pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
-		(pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
+	edac_dbg(1, "  ECC capable: %s, ChipKill ECC capable: %s\n",
+		 (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
+		 (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
 
 	amd64_dump_dramcfg_low(pvt->dclr0, 0);
 
-	debugf1("F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
+	edac_dbg(1, "F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
 
-	debugf1("F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, "
-			"offset: 0x%08x\n",
-			pvt->dhar, dhar_base(pvt),
-			(boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt)
-						   : f10_dhar_offset(pvt));
+	edac_dbg(1, "F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, offset: 0x%08x\n",
+		 pvt->dhar, dhar_base(pvt),
+		 (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt)
+		 : f10_dhar_offset(pvt));
 
-	debugf1("  DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
+	edac_dbg(1, "  DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
 
 	amd64_debug_display_dimm_sizes(pvt, 0);
 
@@ -857,15 +854,15 @@ static void read_dct_base_mask(struct amd64_pvt *pvt)
 		u32 *base1 = &pvt->csels[1].csbases[cs];
 
 		if (!amd64_read_dct_pci_cfg(pvt, reg0, base0))
-			debugf0("  DCSB0[%d]=0x%08x reg: F2x%x\n",
-				cs, *base0, reg0);
+			edac_dbg(0, "  DCSB0[%d]=0x%08x reg: F2x%x\n",
+				 cs, *base0, reg0);
 
 		if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
 			continue;
 
 		if (!amd64_read_dct_pci_cfg(pvt, reg1, base1))
-			debugf0("  DCSB1[%d]=0x%08x reg: F2x%x\n",
-				cs, *base1, reg1);
+			edac_dbg(0, "  DCSB1[%d]=0x%08x reg: F2x%x\n",
+				 cs, *base1, reg1);
 	}
 
 	for_each_chip_select_mask(cs, 0, pvt) {
@@ -875,15 +872,15 @@ static void read_dct_base_mask(struct amd64_pvt *pvt)
 		u32 *mask1 = &pvt->csels[1].csmasks[cs];
 
 		if (!amd64_read_dct_pci_cfg(pvt, reg0, mask0))
-			debugf0("    DCSM0[%d]=0x%08x reg: F2x%x\n",
-				cs, *mask0, reg0);
+			edac_dbg(0, "    DCSM0[%d]=0x%08x reg: F2x%x\n",
+				 cs, *mask0, reg0);
 
 		if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
 			continue;
 
 		if (!amd64_read_dct_pci_cfg(pvt, reg1, mask1))
-			debugf0("    DCSM1[%d]=0x%08x reg: F2x%x\n",
-				cs, *mask1, reg1);
+			edac_dbg(0, "    DCSM1[%d]=0x%08x reg: F2x%x\n",
+				 cs, *mask1, reg1);
 	}
 }
 
@@ -1049,24 +1046,22 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
 	if (!src_mci) {
 		amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
 			     (unsigned long)sys_addr);
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     page, offset, syndrome,
 				     -1, -1, -1,
-				     EDAC_MOD_STR,
 				     "failed to map error addr to a node",
-				     NULL);
+				     "");
 		return;
 	}
 
 	/* Now map the sys_addr to a CSROW */
 	csrow = sys_addr_to_csrow(src_mci, sys_addr);
 	if (csrow < 0) {
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     page, offset, syndrome,
 				     -1, -1, -1,
-				     EDAC_MOD_STR,
 				     "failed to map error addr to a csrow",
-				     NULL);
+				     "");
 		return;
 	}
 
@@ -1082,12 +1077,11 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
 			amd64_mc_warn(src_mci, "unknown syndrome 0x%04x - "
 				      "possible error reporting race\n",
 				      syndrome);
-			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 					     page, offset, syndrome,
 					     csrow, -1, -1,
-					     EDAC_MOD_STR,
 					     "unknown syndrome - possible error reporting race",
-					     NULL);
+					     "");
 			return;
 		}
 	} else {
@@ -1102,10 +1096,10 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
 		channel = ((sys_addr & BIT(3)) != 0);
 	}
 
-	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, src_mci,
+	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, src_mci, 1,
 			     page, offset, syndrome,
 			     csrow, channel, -1,
-			     EDAC_MOD_STR, "", NULL);
+			     "", "");
 }
 
 static int ddr2_cs_size(unsigned i, bool dct_width)
@@ -1193,7 +1187,7 @@ static int f1x_early_channel_count(struct amd64_pvt *pvt)
 	 * Need to check DCT0[0] and DCT1[0] to see if only one of them has
 	 * their CSEnable bit on. If so, then SINGLE DIMM case.
 	 */
-	debugf0("Data width is not 128 bits - need more decoding\n");
+	edac_dbg(0, "Data width is not 128 bits - need more decoding\n");
 
 	/*
 	 * Check DRAM Bank Address Mapping values for each DIMM to see if there
@@ -1272,25 +1266,24 @@ static void read_dram_ctl_register(struct amd64_pvt *pvt)
 		return;
 
 	if (!amd64_read_dct_pci_cfg(pvt, DCT_SEL_LO, &pvt->dct_sel_lo)) {
-		debugf0("F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
-			pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
+		edac_dbg(0, "F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
+			 pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
 
-		debugf0("  DCTs operate in %s mode.\n",
-			(dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
+		edac_dbg(0, "  DCTs operate in %s mode\n",
+			 (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
 
 		if (!dct_ganging_enabled(pvt))
-			debugf0("  Address range split per DCT: %s\n",
-				(dct_high_range_enabled(pvt) ? "yes" : "no"));
+			edac_dbg(0, "  Address range split per DCT: %s\n",
+				 (dct_high_range_enabled(pvt) ? "yes" : "no"));
 
-		debugf0("  data interleave for ECC: %s, "
-			"DRAM cleared since last warm reset: %s\n",
-			(dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
-			(dct_memory_cleared(pvt) ? "yes" : "no"));
+		edac_dbg(0, "  data interleave for ECC: %s, DRAM cleared since last warm reset: %s\n",
+			 (dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
+			 (dct_memory_cleared(pvt) ? "yes" : "no"));
 
-		debugf0("  channel interleave: %s, "
-			"interleave bits selector: 0x%x\n",
-			(dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
-			dct_sel_interleave_addr(pvt));
+		edac_dbg(0, "  channel interleave: %s, "
+			 "interleave bits selector: 0x%x\n",
+			 (dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
+			 dct_sel_interleave_addr(pvt));
 	}
 
 	amd64_read_dct_pci_cfg(pvt, DCT_SEL_HI, &pvt->dct_sel_hi);
@@ -1428,7 +1421,7 @@ static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
 
 	pvt = mci->pvt_info;
 
-	debugf1("input addr: 0x%llx, DCT: %d\n", in_addr, dct);
+	edac_dbg(1, "input addr: 0x%llx, DCT: %d\n", in_addr, dct);
 
 	for_each_chip_select(csrow, dct, pvt) {
 		if (!csrow_enabled(csrow, dct, pvt))
@@ -1436,19 +1429,18 @@ static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
 
 		get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask);
 
-		debugf1("    CSROW=%d CSBase=0x%llx CSMask=0x%llx\n",
-			csrow, cs_base, cs_mask);
+		edac_dbg(1, "    CSROW=%d CSBase=0x%llx CSMask=0x%llx\n",
+			 csrow, cs_base, cs_mask);
 
 		cs_mask = ~cs_mask;
 
-		debugf1("    (InputAddr & ~CSMask)=0x%llx "
-			"(CSBase & ~CSMask)=0x%llx\n",
-			(in_addr & cs_mask), (cs_base & cs_mask));
+		edac_dbg(1, "    (InputAddr & ~CSMask)=0x%llx (CSBase & ~CSMask)=0x%llx\n",
+			 (in_addr & cs_mask), (cs_base & cs_mask));
 
 		if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
 			cs_found = f10_process_possible_spare(pvt, dct, csrow);
 
-			debugf1(" MATCH csrow=%d\n", cs_found);
+			edac_dbg(1, " MATCH csrow=%d\n", cs_found);
 			break;
 		}
 	}
@@ -1505,8 +1497,8 @@ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
 	u8 intlv_en   = dram_intlv_en(pvt, range);
 	u32 intlv_sel = dram_intlv_sel(pvt, range);
 
-	debugf1("(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
-		range, sys_addr, get_dram_limit(pvt, range));
+	edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
+		 range, sys_addr, get_dram_limit(pvt, range));
 
 	if (dhar_valid(pvt) &&
 	    dhar_base(pvt) <= sys_addr &&
@@ -1562,7 +1554,7 @@ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
 				     (chan_addr & 0xfff);
 	}
 
-	debugf1("   Normalized DCT addr: 0x%llx\n", chan_addr);
+	edac_dbg(1, "   Normalized DCT addr: 0x%llx\n", chan_addr);
 
 	cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
 
@@ -1616,12 +1608,11 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
 	csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
 
 	if (csrow < 0) {
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     page, offset, syndrome,
 				     -1, -1, -1,
-				     EDAC_MOD_STR,
 				     "failed to map error addr to a csrow",
-				     NULL);
+				     "");
 		return;
 	}
 
@@ -1633,10 +1624,10 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
 	if (dct_ganging_enabled(pvt))
 		chan = get_channel_from_ecc_syndrome(mci, syndrome);
 
-	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 			     page, offset, syndrome,
 			     csrow, chan, -1,
-			     EDAC_MOD_STR, "", NULL);
+			     "", "");
 }
 
 /*
@@ -1664,7 +1655,8 @@ static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
 	dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->csels[1].csbases
 						   : pvt->csels[0].csbases;
 
-	debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam);
+	edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n",
+		 ctrl, dbam);
 
 	edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl);
 
@@ -1840,7 +1832,7 @@ static int decode_syndrome(u16 syndrome, u16 *vectors, unsigned num_vecs,
 		}
 	}
 
-	debugf0("syndrome(%x) not found\n", syndrome);
+	edac_dbg(0, "syndrome(%x) not found\n", syndrome);
 	return -1;
 }
 
@@ -1917,12 +1909,11 @@ static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m)
 	/* Ensure that the Error Address is VALID */
 	if (!(m->status & MCI_STATUS_ADDRV)) {
 		amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     0, 0, 0,
 				     -1, -1, -1,
-				     EDAC_MOD_STR,
 				     "HW has no ERROR_ADDRESS available",
-				     NULL);
+				     "");
 		return;
 	}
 
@@ -1946,12 +1937,11 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
 
 	if (!(m->status & MCI_STATUS_ADDRV)) {
 		amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 				     0, 0, 0,
 				     -1, -1, -1,
-				     EDAC_MOD_STR,
 				     "HW has no ERROR_ADDRESS available",
-				     NULL);
+				     "");
 		return;
 	}
 
@@ -1966,11 +1956,11 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
 	if (!src_mci) {
 		amd64_mc_err(mci, "ERROR ADDRESS (0x%lx) NOT mapped to a MC\n",
 				  (unsigned long)sys_addr);
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 				     page, offset, 0,
 				     -1, -1, -1,
-				     EDAC_MOD_STR,
-				     "ERROR ADDRESS NOT mapped to a MC", NULL);
+				     "ERROR ADDRESS NOT mapped to a MC",
+				     "");
 		return;
 	}
 
@@ -1980,17 +1970,16 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
 	if (csrow < 0) {
 		amd64_mc_err(mci, "ERROR_ADDRESS (0x%lx) NOT mapped to CS\n",
 				  (unsigned long)sys_addr);
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 				     page, offset, 0,
 				     -1, -1, -1,
-				     EDAC_MOD_STR,
 				     "ERROR ADDRESS NOT mapped to CS",
-				     NULL);
+				     "");
 	} else {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 				     page, offset, 0,
 				     csrow, -1, -1,
-				     EDAC_MOD_STR, "", NULL);
+				     "", "");
 	}
 }
 
@@ -2047,9 +2036,9 @@ static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 f1_id, u16 f3_id)
 
 		return -ENODEV;
 	}
-	debugf1("F1: %s\n", pci_name(pvt->F1));
-	debugf1("F2: %s\n", pci_name(pvt->F2));
-	debugf1("F3: %s\n", pci_name(pvt->F3));
+	edac_dbg(1, "F1: %s\n", pci_name(pvt->F1));
+	edac_dbg(1, "F2: %s\n", pci_name(pvt->F2));
+	edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
 
 	return 0;
 }
@@ -2076,15 +2065,15 @@ static void read_mc_regs(struct amd64_pvt *pvt)
 	 * those are Read-As-Zero
 	 */
 	rdmsrl(MSR_K8_TOP_MEM1, pvt->top_mem);
-	debugf0("  TOP_MEM:  0x%016llx\n", pvt->top_mem);
+	edac_dbg(0, "  TOP_MEM:  0x%016llx\n", pvt->top_mem);
 
 	/* check first whether TOP_MEM2 is enabled */
 	rdmsrl(MSR_K8_SYSCFG, msr_val);
 	if (msr_val & (1U << 21)) {
 		rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2);
-		debugf0("  TOP_MEM2: 0x%016llx\n", pvt->top_mem2);
+		edac_dbg(0, "  TOP_MEM2: 0x%016llx\n", pvt->top_mem2);
 	} else
-		debugf0("  TOP_MEM2 disabled.\n");
+		edac_dbg(0, "  TOP_MEM2 disabled\n");
 
 	amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap);
 
@@ -2100,17 +2089,17 @@ static void read_mc_regs(struct amd64_pvt *pvt)
 		if (!rw)
 			continue;
 
-		debugf1("  DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n",
-			range,
-			get_dram_base(pvt, range),
-			get_dram_limit(pvt, range));
+		edac_dbg(1, "  DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n",
+			 range,
+			 get_dram_base(pvt, range),
+			 get_dram_limit(pvt, range));
 
-		debugf1("   IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n",
-			dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
-			(rw & 0x1) ? "R" : "-",
-			(rw & 0x2) ? "W" : "-",
-			dram_intlv_sel(pvt, range),
-			dram_dst_node(pvt, range));
+		edac_dbg(1, "   IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n",
+			 dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
+			 (rw & 0x1) ? "R" : "-",
+			 (rw & 0x2) ? "W" : "-",
+			 dram_intlv_sel(pvt, range),
+			 dram_dst_node(pvt, range));
 	}
 
 	read_dct_base_mask(pvt);
@@ -2191,9 +2180,9 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
 
 	nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
 
-	debugf0("  (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode);
-	debugf0("    nr_pages/channel= %u  channel-count = %d\n",
-		nr_pages, pvt->channel_count);
+	edac_dbg(0, "  (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode);
+	edac_dbg(0, "    nr_pages/channel= %u  channel-count = %d\n",
+		 nr_pages, pvt->channel_count);
 
 	return nr_pages;
 }
@@ -2205,6 +2194,7 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
 static int init_csrows(struct mem_ctl_info *mci)
 {
 	struct csrow_info *csrow;
+	struct dimm_info *dimm;
 	struct amd64_pvt *pvt = mci->pvt_info;
 	u64 base, mask;
 	u32 val;
@@ -2217,22 +2207,19 @@ static int init_csrows(struct mem_ctl_info *mci)
 
 	pvt->nbcfg = val;
 
-	debugf0("node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
-		pvt->mc_node_id, val,
-		!!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
+	edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
+		 pvt->mc_node_id, val,
+		 !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
 
 	for_each_chip_select(i, 0, pvt) {
-		csrow = &mci->csrows[i];
+		csrow = mci->csrows[i];
 
 		if (!csrow_enabled(i, 0, pvt) && !csrow_enabled(i, 1, pvt)) {
-			debugf1("----CSROW %d EMPTY for node %d\n", i,
-				pvt->mc_node_id);
+			edac_dbg(1, "----CSROW %d VALID for MC node %d\n",
+				 i, pvt->mc_node_id);
 			continue;
 		}
 
-		debugf1("----CSROW %d VALID for MC node %d\n",
-			i, pvt->mc_node_id);
-
 		empty = 0;
 		if (csrow_enabled(i, 0, pvt))
 			nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
@@ -2244,8 +2231,9 @@ static int init_csrows(struct mem_ctl_info *mci)
 
 		mtype = amd64_determine_memory_type(pvt, i);
 
-		debugf1("  for MC node %d csrow %d:\n", pvt->mc_node_id, i);
-		debugf1("    nr_pages: %u\n", nr_pages * pvt->channel_count);
+		edac_dbg(1, "  for MC node %d csrow %d:\n", pvt->mc_node_id, i);
+		edac_dbg(1, "    nr_pages: %u\n",
+			 nr_pages * pvt->channel_count);
 
 		/*
 		 * determine whether CHIPKILL or JUST ECC or NO ECC is operating
@@ -2257,9 +2245,10 @@ static int init_csrows(struct mem_ctl_info *mci)
 			edac_mode = EDAC_NONE;
 
 		for (j = 0; j < pvt->channel_count; j++) {
-			csrow->channels[j].dimm->mtype = mtype;
-			csrow->channels[j].dimm->edac_mode = edac_mode;
-			csrow->channels[j].dimm->nr_pages = nr_pages;
+			dimm = csrow->channels[j]->dimm;
+			dimm->mtype = mtype;
+			dimm->edac_mode = edac_mode;
+			dimm->nr_pages = nr_pages;
 		}
 	}
 
@@ -2296,9 +2285,9 @@ static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
 		struct msr *reg = per_cpu_ptr(msrs, cpu);
 		nbe = reg->l & MSR_MCGCTL_NBE;
 
-		debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
-			cpu, reg->q,
-			(nbe ? "enabled" : "disabled"));
+		edac_dbg(0, "core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
+			 cpu, reg->q,
+			 (nbe ? "enabled" : "disabled"));
 
 		if (!nbe)
 			goto out;
@@ -2369,8 +2358,8 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
 
 	amd64_read_pci_cfg(F3, NBCFG, &value);
 
-	debugf0("1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
-		nid, value, !!(value & NBCFG_ECC_ENABLE));
+	edac_dbg(0, "1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
+		 nid, value, !!(value & NBCFG_ECC_ENABLE));
 
 	if (!(value & NBCFG_ECC_ENABLE)) {
 		amd64_warn("DRAM ECC disabled on this node, enabling...\n");
@@ -2394,8 +2383,8 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
 		s->flags.nb_ecc_prev = 1;
 	}
 
-	debugf0("2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
-		nid, value, !!(value & NBCFG_ECC_ENABLE));
+	edac_dbg(0, "2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
+		 nid, value, !!(value & NBCFG_ECC_ENABLE));
 
 	return ret;
 }
@@ -2463,26 +2452,29 @@ static bool ecc_enabled(struct pci_dev *F3, u8 nid)
 	return true;
 }
 
-struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) +
-					  ARRAY_SIZE(amd64_inj_attrs) +
-					  1];
-
-struct mcidev_sysfs_attribute terminator = { .attr = { .name = NULL } };
-
-static void set_mc_sysfs_attrs(struct mem_ctl_info *mci)
+static int set_mc_sysfs_attrs(struct mem_ctl_info *mci)
 {
-	unsigned int i = 0, j = 0;
+	int rc;
 
-	for (; i < ARRAY_SIZE(amd64_dbg_attrs); i++)
-		sysfs_attrs[i] = amd64_dbg_attrs[i];
+	rc = amd64_create_sysfs_dbg_files(mci);
+	if (rc < 0)
+		return rc;
 
-	if (boot_cpu_data.x86 >= 0x10)
-		for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++)
-			sysfs_attrs[i] = amd64_inj_attrs[j];
+	if (boot_cpu_data.x86 >= 0x10) {
+		rc = amd64_create_sysfs_inject_files(mci);
+		if (rc < 0)
+			return rc;
+	}
+
+	return 0;
+}
 
-	sysfs_attrs[i] = terminator;
+static void del_mc_sysfs_attrs(struct mem_ctl_info *mci)
+{
+	amd64_remove_sysfs_dbg_files(mci);
 
-	mci->mc_driver_sysfs_attributes = sysfs_attrs;
+	if (boot_cpu_data.x86 >= 0x10)
+		amd64_remove_sysfs_inject_files(mci);
 }
 
 static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
@@ -2601,20 +2593,22 @@ static int amd64_init_one_instance(struct pci_dev *F2)
 		goto err_siblings;
 
 	mci->pvt_info = pvt;
-	mci->dev = &pvt->F2->dev;
+	mci->pdev = &pvt->F2->dev;
 
 	setup_mci_misc_attrs(mci, fam_type);
 
 	if (init_csrows(mci))
 		mci->edac_cap = EDAC_FLAG_NONE;
 
-	set_mc_sysfs_attrs(mci);
-
 	ret = -ENODEV;
 	if (edac_mc_add_mc(mci)) {
-		debugf1("failed edac_mc_add_mc()\n");
+		edac_dbg(1, "failed edac_mc_add_mc()\n");
 		goto err_add_mc;
 	}
+	if (set_mc_sysfs_attrs(mci)) {
+		edac_dbg(1, "failed edac_mc_add_mc()\n");
+		goto err_add_sysfs;
+	}
 
 	/* register stuff with EDAC MCE */
 	if (report_gart_errors)
@@ -2628,6 +2622,8 @@ static int amd64_init_one_instance(struct pci_dev *F2)
 
 	return 0;
 
+err_add_sysfs:
+	edac_mc_del_mc(mci->pdev);
 err_add_mc:
 	edac_mc_free(mci);
 
@@ -2651,7 +2647,7 @@ static int __devinit amd64_probe_one_instance(struct pci_dev *pdev,
 
 	ret = pci_enable_device(pdev);
 	if (ret < 0) {
-		debugf0("ret=%d\n", ret);
+		edac_dbg(0, "ret=%d\n", ret);
 		return -EIO;
 	}
 
@@ -2698,6 +2694,8 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
 	struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
 	struct ecc_settings *s = ecc_stngs[nid];
 
+	mci = find_mci_by_dev(&pdev->dev);
+	del_mc_sysfs_attrs(mci);
 	/* Remove from EDAC CORE tracking list */
 	mci = edac_mc_del_mc(&pdev->dev);
 	if (!mci)
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 9a666cb..8d48047 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -413,20 +413,33 @@ struct ecc_settings {
 };
 
 #ifdef CONFIG_EDAC_DEBUG
-#define NUM_DBG_ATTRS 5
+int amd64_create_sysfs_dbg_files(struct mem_ctl_info *mci);
+void amd64_remove_sysfs_dbg_files(struct mem_ctl_info *mci);
+
 #else
-#define NUM_DBG_ATTRS 0
+static inline int amd64_create_sysfs_dbg_files(struct mem_ctl_info *mci)
+{
+	return 0;
+}
+static void inline amd64_remove_sysfs_dbg_files(struct mem_ctl_info *mci)
+{
+}
 #endif
 
 #ifdef CONFIG_EDAC_AMD64_ERROR_INJECTION
-#define NUM_INJ_ATTRS 5
+int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci);
+void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci);
+
 #else
-#define NUM_INJ_ATTRS 0
+static inline int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci)
+{
+	return 0;
+}
+static inline void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci)
+{
+}
 #endif
 
-extern struct mcidev_sysfs_attribute amd64_dbg_attrs[NUM_DBG_ATTRS],
-				     amd64_inj_attrs[NUM_INJ_ATTRS];
-
 /*
  * Each of the PCI Device IDs types have their own set of hardware accessor
  * functions and per device encoding/decoding logic.
@@ -460,3 +473,5 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
 
 int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
 			     u64 *hole_offset, u64 *hole_size);
+
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
diff --git a/drivers/edac/amd64_edac_dbg.c b/drivers/edac/amd64_edac_dbg.c
index e356228..2c1bbf7 100644
--- a/drivers/edac/amd64_edac_dbg.c
+++ b/drivers/edac/amd64_edac_dbg.c
@@ -1,8 +1,11 @@
 #include "amd64_edac.h"
 
 #define EDAC_DCT_ATTR_SHOW(reg)						\
-static ssize_t amd64_##reg##_show(struct mem_ctl_info *mci, char *data)	\
+static ssize_t amd64_##reg##_show(struct device *dev,			\
+			       struct device_attribute *mattr,		\
+			       char *data)				\
 {									\
+	struct mem_ctl_info *mci = to_mci(dev);				\
 	struct amd64_pvt *pvt = mci->pvt_info;				\
 		return sprintf(data, "0x%016llx\n", (u64)pvt->reg);	\
 }
@@ -12,8 +15,12 @@ EDAC_DCT_ATTR_SHOW(dbam0);
 EDAC_DCT_ATTR_SHOW(top_mem);
 EDAC_DCT_ATTR_SHOW(top_mem2);
 
-static ssize_t amd64_hole_show(struct mem_ctl_info *mci, char *data)
+static ssize_t amd64_hole_show(struct device *dev,
+			       struct device_attribute *mattr,
+			       char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
+
 	u64 hole_base = 0;
 	u64 hole_offset = 0;
 	u64 hole_size = 0;
@@ -27,46 +34,40 @@ static ssize_t amd64_hole_show(struct mem_ctl_info *mci, char *data)
 /*
  * update NUM_DBG_ATTRS in case you add new members
  */
-struct mcidev_sysfs_attribute amd64_dbg_attrs[] = {
+static DEVICE_ATTR(dhar, S_IRUGO, amd64_dhar_show, NULL);
+static DEVICE_ATTR(dbam, S_IRUGO, amd64_dbam0_show, NULL);
+static DEVICE_ATTR(topmem, S_IRUGO, amd64_top_mem_show, NULL);
+static DEVICE_ATTR(topmem2, S_IRUGO, amd64_top_mem2_show, NULL);
+static DEVICE_ATTR(dram_hole, S_IRUGO, amd64_hole_show, NULL);
+
+int amd64_create_sysfs_dbg_files(struct mem_ctl_info *mci)
+{
+	int rc;
+
+	rc = device_create_file(&mci->dev, &dev_attr_dhar);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_dbam);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_topmem);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_topmem2);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_dram_hole);
+	if (rc < 0)
+		return rc;
 
-	{
-		.attr = {
-			.name = "dhar",
-			.mode = (S_IRUGO)
-		},
-		.show = amd64_dhar_show,
-		.store = NULL,
-	},
-	{
-		.attr = {
-			.name = "dbam",
-			.mode = (S_IRUGO)
-		},
-		.show = amd64_dbam0_show,
-		.store = NULL,
-	},
-	{
-		.attr = {
-			.name = "topmem",
-			.mode = (S_IRUGO)
-		},
-		.show = amd64_top_mem_show,
-		.store = NULL,
-	},
-	{
-		.attr = {
-			.name = "topmem2",
-			.mode = (S_IRUGO)
-		},
-		.show = amd64_top_mem2_show,
-		.store = NULL,
-	},
-	{
-		.attr = {
-			.name = "dram_hole",
-			.mode = (S_IRUGO)
-		},
-		.show = amd64_hole_show,
-		.store = NULL,
-	},
-};
+	return 0;
+}
+
+void amd64_remove_sysfs_dbg_files(struct mem_ctl_info *mci)
+{
+	device_remove_file(&mci->dev, &dev_attr_dhar);
+	device_remove_file(&mci->dev, &dev_attr_dbam);
+	device_remove_file(&mci->dev, &dev_attr_topmem);
+	device_remove_file(&mci->dev, &dev_attr_topmem2);
+	device_remove_file(&mci->dev, &dev_attr_dram_hole);
+}
diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c
index 303f10e..53d972e 100644
--- a/drivers/edac/amd64_edac_inj.c
+++ b/drivers/edac/amd64_edac_inj.c
@@ -1,7 +1,10 @@
 #include "amd64_edac.h"
 
-static ssize_t amd64_inject_section_show(struct mem_ctl_info *mci, char *buf)
+static ssize_t amd64_inject_section_show(struct device *dev,
+					 struct device_attribute *mattr,
+					 char *buf)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct amd64_pvt *pvt = mci->pvt_info;
 	return sprintf(buf, "0x%x\n", pvt->injection.section);
 }
@@ -12,9 +15,11 @@ static ssize_t amd64_inject_section_show(struct mem_ctl_info *mci, char *buf)
  *
  * range: 0..3
  */
-static ssize_t amd64_inject_section_store(struct mem_ctl_info *mci,
+static ssize_t amd64_inject_section_store(struct device *dev,
+					  struct device_attribute *mattr,
 					  const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct amd64_pvt *pvt = mci->pvt_info;
 	unsigned long value;
 	int ret = 0;
@@ -33,8 +38,11 @@ static ssize_t amd64_inject_section_store(struct mem_ctl_info *mci,
 	return ret;
 }
 
-static ssize_t amd64_inject_word_show(struct mem_ctl_info *mci, char *buf)
+static ssize_t amd64_inject_word_show(struct device *dev,
+					struct device_attribute *mattr,
+					char *buf)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct amd64_pvt *pvt = mci->pvt_info;
 	return sprintf(buf, "0x%x\n", pvt->injection.word);
 }
@@ -45,9 +53,11 @@ static ssize_t amd64_inject_word_show(struct mem_ctl_info *mci, char *buf)
  *
  * range: 0..8
  */
-static ssize_t amd64_inject_word_store(struct mem_ctl_info *mci,
-					const char *data, size_t count)
+static ssize_t amd64_inject_word_store(struct device *dev,
+				       struct device_attribute *mattr,
+				       const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct amd64_pvt *pvt = mci->pvt_info;
 	unsigned long value;
 	int ret = 0;
@@ -66,8 +76,11 @@ static ssize_t amd64_inject_word_store(struct mem_ctl_info *mci,
 	return ret;
 }
 
-static ssize_t amd64_inject_ecc_vector_show(struct mem_ctl_info *mci, char *buf)
+static ssize_t amd64_inject_ecc_vector_show(struct device *dev,
+					    struct device_attribute *mattr,
+					    char *buf)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct amd64_pvt *pvt = mci->pvt_info;
 	return sprintf(buf, "0x%x\n", pvt->injection.bit_map);
 }
@@ -77,9 +90,11 @@ static ssize_t amd64_inject_ecc_vector_show(struct mem_ctl_info *mci, char *buf)
  * corresponding bit within the error injection word above. When used during a
  * DRAM ECC read, it holds the contents of the of the DRAM ECC bits.
  */
-static ssize_t amd64_inject_ecc_vector_store(struct mem_ctl_info *mci,
-					     const char *data, size_t count)
+static ssize_t amd64_inject_ecc_vector_store(struct device *dev,
+				       struct device_attribute *mattr,
+				       const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct amd64_pvt *pvt = mci->pvt_info;
 	unsigned long value;
 	int ret = 0;
@@ -103,9 +118,11 @@ static ssize_t amd64_inject_ecc_vector_store(struct mem_ctl_info *mci,
  * Do a DRAM ECC read. Assemble staged values in the pvt area, format into
  * fields needed by the injection registers and read the NB Array Data Port.
  */
-static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci,
-					const char *data, size_t count)
+static ssize_t amd64_inject_read_store(struct device *dev,
+				       struct device_attribute *mattr,
+				       const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct amd64_pvt *pvt = mci->pvt_info;
 	unsigned long value;
 	u32 section, word_bits;
@@ -125,7 +142,8 @@ static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci,
 		/* Issue 'word' and 'bit' along with the READ request */
 		amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
 
-		debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);
+		edac_dbg(0, "section=0x%x word_bits=0x%x\n",
+			 section, word_bits);
 
 		return count;
 	}
@@ -136,9 +154,11 @@ static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci,
  * Do a DRAM ECC write. Assemble staged values in the pvt area and format into
  * fields needed by the injection registers.
  */
-static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci,
+static ssize_t amd64_inject_write_store(struct device *dev,
+					struct device_attribute *mattr,
 					const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct amd64_pvt *pvt = mci->pvt_info;
 	unsigned long value;
 	u32 section, word_bits;
@@ -158,7 +178,8 @@ static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci,
 		/* Issue 'word' and 'bit' along with the READ request */
 		amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
 
-		debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);
+		edac_dbg(0, "section=0x%x word_bits=0x%x\n",
+			 section, word_bits);
 
 		return count;
 	}
@@ -168,46 +189,47 @@ static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci,
 /*
  * update NUM_INJ_ATTRS in case you add new members
  */
-struct mcidev_sysfs_attribute amd64_inj_attrs[] = {
-
-	{
-		.attr = {
-			.name = "inject_section",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show = amd64_inject_section_show,
-		.store = amd64_inject_section_store,
-	},
-	{
-		.attr = {
-			.name = "inject_word",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show = amd64_inject_word_show,
-		.store = amd64_inject_word_store,
-	},
-	{
-		.attr = {
-			.name = "inject_ecc_vector",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show = amd64_inject_ecc_vector_show,
-		.store = amd64_inject_ecc_vector_store,
-	},
-	{
-		.attr = {
-			.name = "inject_write",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show = NULL,
-		.store = amd64_inject_write_store,
-	},
-	{
-		.attr = {
-			.name = "inject_read",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show = NULL,
-		.store = amd64_inject_read_store,
-	},
-};
+
+static DEVICE_ATTR(inject_section, S_IRUGO | S_IWUSR,
+		   amd64_inject_section_show, amd64_inject_section_store);
+static DEVICE_ATTR(inject_word, S_IRUGO | S_IWUSR,
+		   amd64_inject_word_show, amd64_inject_word_store);
+static DEVICE_ATTR(inject_ecc_vector, S_IRUGO | S_IWUSR,
+		   amd64_inject_ecc_vector_show, amd64_inject_ecc_vector_store);
+static DEVICE_ATTR(inject_write, S_IRUGO | S_IWUSR,
+		   NULL, amd64_inject_write_store);
+static DEVICE_ATTR(inject_read, S_IRUGO | S_IWUSR,
+		   NULL, amd64_inject_read_store);
+
+
+int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci)
+{
+	int rc;
+
+	rc = device_create_file(&mci->dev, &dev_attr_inject_section);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_word);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_ecc_vector);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_write);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_read);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci)
+{
+	device_remove_file(&mci->dev, &dev_attr_inject_section);
+	device_remove_file(&mci->dev, &dev_attr_inject_word);
+	device_remove_file(&mci->dev, &dev_attr_inject_ecc_vector);
+	device_remove_file(&mci->dev, &dev_attr_inject_write);
+	device_remove_file(&mci->dev, &dev_attr_inject_read);
+}
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index 9774d44..29eeb68 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -105,7 +105,7 @@ static void amd76x_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 	pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS,
 			&info->ecc_mode_status);
 
@@ -145,10 +145,10 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
 
 		if (handle_errors) {
 			row = (info->ecc_mode_status >> 4) & 0xf;
-			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
-					     mci->csrows[row].first_page, 0, 0,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
+					     mci->csrows[row]->first_page, 0, 0,
 					     row, 0, -1,
-					     mci->ctl_name, "", NULL);
+					     mci->ctl_name, "");
 		}
 	}
 
@@ -160,10 +160,10 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
 
 		if (handle_errors) {
 			row = info->ecc_mode_status & 0xf;
-			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
-					     mci->csrows[row].first_page, 0, 0,
+			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
+					     mci->csrows[row]->first_page, 0, 0,
 					     row, 0, -1,
-					     mci->ctl_name, "", NULL);
+					     mci->ctl_name, "");
 		}
 	}
 
@@ -180,7 +180,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
 static void amd76x_check(struct mem_ctl_info *mci)
 {
 	struct amd76x_error_info info;
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 	amd76x_get_error_info(mci, &info);
 	amd76x_process_error_info(mci, &info, 1);
 }
@@ -194,8 +194,8 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	int index;
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		/* find the DRAM Chip Select Base address and mask */
 		pci_read_config_dword(pdev,
@@ -241,7 +241,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
 	u32 ems_mode;
 	struct amd76x_error_info discard;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 	pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
 	ems_mode = (ems >> 10) & 0x3;
 
@@ -256,8 +256,8 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
 	if (mci == NULL)
 		return -ENOMEM;
 
-	debugf0("%s(): mci = %p\n", __func__, mci);
-	mci->dev = &pdev->dev;
+	edac_dbg(0, "mci = %p\n", mci);
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_RDDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	mci->edac_cap = ems_mode ?
@@ -276,7 +276,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
 	if (edac_mc_add_mc(mci)) {
-		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "failed edac_mc_add_mc()\n");
 		goto fail;
 	}
 
@@ -292,7 +292,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
 	}
 
 	/* get this far and it's successful */
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 	return 0;
 
 fail:
@@ -304,7 +304,7 @@ fail:
 static int __devinit amd76x_init_one(struct pci_dev *pdev,
 				const struct pci_device_id *ent)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* don't need to call pci_enable_device() */
 	return amd76x_probe1(pdev, ent->driver_data);
@@ -322,7 +322,7 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	if (amd76x_pci)
 		edac_pci_release_generic_ctl(amd76x_pci);
diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c
index 69ee6aa..a1bbd8e 100644
--- a/drivers/edac/cell_edac.c
+++ b/drivers/edac/cell_edac.c
@@ -33,10 +33,10 @@ struct cell_edac_priv
 static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
 {
 	struct cell_edac_priv		*priv = mci->pvt_info;
-	struct csrow_info		*csrow = &mci->csrows[0];
+	struct csrow_info		*csrow = mci->csrows[0];
 	unsigned long			address, pfn, offset, syndrome;
 
-	dev_dbg(mci->dev, "ECC CE err on node %d, channel %d, ar = 0x%016llx\n",
+	dev_dbg(mci->pdev, "ECC CE err on node %d, channel %d, ar = 0x%016llx\n",
 		priv->node, chan, ar);
 
 	/* Address decoding is likely a bit bogus, to dbl check */
@@ -48,18 +48,18 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
 	syndrome = (ar & 0x000000001fe00000ul) >> 21;
 
 	/* TODO: Decoding of the error address */
-	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 			     csrow->first_page + pfn, offset, syndrome,
-			     0, chan, -1, "", "", NULL);
+			     0, chan, -1, "", "");
 }
 
 static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
 {
 	struct cell_edac_priv		*priv = mci->pvt_info;
-	struct csrow_info		*csrow = &mci->csrows[0];
+	struct csrow_info		*csrow = mci->csrows[0];
 	unsigned long			address, pfn, offset;
 
-	dev_dbg(mci->dev, "ECC UE err on node %d, channel %d, ar = 0x%016llx\n",
+	dev_dbg(mci->pdev, "ECC UE err on node %d, channel %d, ar = 0x%016llx\n",
 		priv->node, chan, ar);
 
 	/* Address decoding is likely a bit bogus, to dbl check */
@@ -70,9 +70,9 @@ static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
 	offset = address & ~PAGE_MASK;
 
 	/* TODO: Decoding of the error address */
-	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 			     csrow->first_page + pfn, offset, 0,
-			     0, chan, -1, "", "", NULL);
+			     0, chan, -1, "", "");
 }
 
 static void cell_edac_check(struct mem_ctl_info *mci)
@@ -83,7 +83,7 @@ static void cell_edac_check(struct mem_ctl_info *mci)
 	fir = in_be64(&priv->regs->mic_fir);
 #ifdef DEBUG
 	if (fir != priv->prev_fir) {
-		dev_dbg(mci->dev, "fir change : 0x%016lx\n", fir);
+		dev_dbg(mci->pdev, "fir change : 0x%016lx\n", fir);
 		priv->prev_fir = fir;
 	}
 #endif
@@ -119,14 +119,14 @@ static void cell_edac_check(struct mem_ctl_info *mci)
 		mb();	/* sync up */
 #ifdef DEBUG
 		fir = in_be64(&priv->regs->mic_fir);
-		dev_dbg(mci->dev, "fir clear  : 0x%016lx\n", fir);
+		dev_dbg(mci->pdev, "fir clear  : 0x%016lx\n", fir);
 #endif
 	}
 }
 
 static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
 {
-	struct csrow_info		*csrow = &mci->csrows[0];
+	struct csrow_info		*csrow = mci->csrows[0];
 	struct dimm_info		*dimm;
 	struct cell_edac_priv		*priv = mci->pvt_info;
 	struct device_node		*np;
@@ -150,12 +150,12 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
 		csrow->last_page = csrow->first_page + nr_pages - 1;
 
 		for (j = 0; j < csrow->nr_channels; j++) {
-			dimm = csrow->channels[j].dimm;
+			dimm = csrow->channels[j]->dimm;
 			dimm->mtype = MEM_XDR;
 			dimm->edac_mode = EDAC_SECDED;
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
 		}
-		dev_dbg(mci->dev,
+		dev_dbg(mci->pdev,
 			"Initialized on node %d, chanmask=0x%x,"
 			" first_page=0x%lx, nr_pages=0x%x\n",
 			priv->node, priv->chanmask,
@@ -212,7 +212,7 @@ static int __devinit cell_edac_probe(struct platform_device *pdev)
 	priv->regs = regs;
 	priv->node = pdev->id;
 	priv->chanmask = chanmask;
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_XDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	mci->edac_cap = EDAC_FLAG_EC | EDAC_FLAG_SECDED;
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c
index e22030a..c2ef134 100644
--- a/drivers/edac/cpc925_edac.c
+++ b/drivers/edac/cpc925_edac.c
@@ -316,13 +316,12 @@ static void get_total_mem(struct cpc925_mc_pdata *pdata)
 		reg += aw;
 		size = of_read_number(reg, sw);
 		reg += sw;
-		debugf1("%s: start 0x%lx, size 0x%lx\n", __func__,
-			start, size);
+		edac_dbg(1, "start 0x%lx, size 0x%lx\n", start, size);
 		pdata->total_mem += size;
 	} while (reg < reg_end);
 
 	of_node_put(np);
-	debugf0("%s: total_mem 0x%lx\n", __func__, pdata->total_mem);
+	edac_dbg(0, "total_mem 0x%lx\n", pdata->total_mem);
 }
 
 static void cpc925_init_csrows(struct mem_ctl_info *mci)
@@ -330,8 +329,9 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
 	struct cpc925_mc_pdata *pdata = mci->pvt_info;
 	struct csrow_info *csrow;
 	struct dimm_info *dimm;
+	enum dev_type dtype;
 	int index, j;
-	u32 mbmr, mbbar, bba;
+	u32 mbmr, mbbar, bba, grain;
 	unsigned long row_size, nr_pages, last_nr_pages = 0;
 
 	get_total_mem(pdata);
@@ -347,7 +347,7 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
 		if (bba == 0)
 			continue; /* not populated */
 
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		row_size = bba * (1UL << 28);	/* 256M */
 		csrow->first_page = last_nr_pages;
@@ -355,37 +355,36 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
 		csrow->last_page = csrow->first_page + nr_pages - 1;
 		last_nr_pages = csrow->last_page + 1;
 
+		switch (csrow->nr_channels) {
+		case 1: /* Single channel */
+			grain = 32; /* four-beat burst of 32 bytes */
+			break;
+		case 2: /* Dual channel */
+		default:
+			grain = 64; /* four-beat burst of 64 bytes */
+			break;
+		}
+		switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) {
+		case 6: /* 0110, no way to differentiate X8 VS X16 */
+		case 5:	/* 0101 */
+		case 8: /* 1000 */
+			dtype = DEV_X16;
+			break;
+		case 7: /* 0111 */
+		case 9: /* 1001 */
+			dtype = DEV_X8;
+			break;
+		default:
+			dtype = DEV_UNKNOWN;
+		break;
+		}
 		for (j = 0; j < csrow->nr_channels; j++) {
-			dimm = csrow->channels[j].dimm;
-
+			dimm = csrow->channels[j]->dimm;
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
 			dimm->mtype = MEM_RDDR;
 			dimm->edac_mode = EDAC_SECDED;
-
-			switch (csrow->nr_channels) {
-			case 1: /* Single channel */
-				dimm->grain = 32; /* four-beat burst of 32 bytes */
-				break;
-			case 2: /* Dual channel */
-			default:
-				dimm->grain = 64; /* four-beat burst of 64 bytes */
-				break;
-			}
-
-			switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) {
-			case 6: /* 0110, no way to differentiate X8 VS X16 */
-			case 5:	/* 0101 */
-			case 8: /* 1000 */
-				dimm->dtype = DEV_X16;
-				break;
-			case 7: /* 0111 */
-			case 9: /* 1001 */
-				dimm->dtype = DEV_X8;
-				break;
-			default:
-				dimm->dtype = DEV_UNKNOWN;
-				break;
-			}
+			dimm->grain = grain;
+			dimm->dtype = dtype;
 		}
 	}
 }
@@ -463,7 +462,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear,
 	*csrow = rank;
 
 #ifdef CONFIG_EDAC_DEBUG
-	if (mci->csrows[rank].first_page == 0) {
+	if (mci->csrows[rank]->first_page == 0) {
 		cpc925_mc_printk(mci, KERN_ERR, "ECC occurs in a "
 			"non-populated csrow, broken hardware?\n");
 		return;
@@ -471,7 +470,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear,
 #endif
 
 	/* Revert csrow number */
-	pa = mci->csrows[rank].first_page << PAGE_SHIFT;
+	pa = mci->csrows[rank]->first_page << PAGE_SHIFT;
 
 	/* Revert column address */
 	col += bcnt;
@@ -512,7 +511,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear,
 	*offset = pa & (PAGE_SIZE - 1);
 	*pfn = pa >> PAGE_SHIFT;
 
-	debugf0("%s: ECC physical address 0x%lx\n", __func__, pa);
+	edac_dbg(0, "ECC physical address 0x%lx\n", pa);
 }
 
 static int cpc925_mc_find_channel(struct mem_ctl_info *mci, u16 syndrome)
@@ -555,18 +554,18 @@ static void cpc925_mc_check(struct mem_ctl_info *mci)
 	if (apiexcp & CECC_EXCP_DETECTED) {
 		cpc925_mc_printk(mci, KERN_INFO, "DRAM CECC Fault\n");
 		channel = cpc925_mc_find_channel(mci, syndrome);
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     pfn, offset, syndrome,
 				     csrow, channel, -1,
-				     mci->ctl_name, "", NULL);
+				     mci->ctl_name, "");
 	}
 
 	if (apiexcp & UECC_EXCP_DETECTED) {
 		cpc925_mc_printk(mci, KERN_INFO, "DRAM UECC Fault\n");
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     pfn, offset, 0,
 				     csrow, -1, -1,
-				     mci->ctl_name, "", NULL);
+				     mci->ctl_name, "");
 	}
 
 	cpc925_mc_printk(mci, KERN_INFO, "Dump registers:\n");
@@ -852,8 +851,8 @@ static void cpc925_add_edac_devices(void __iomem *vbase)
 			goto err2;
 		}
 
-		debugf0("%s: Successfully added edac device for %s\n",
-			__func__, dev_info->ctl_name);
+		edac_dbg(0, "Successfully added edac device for %s\n",
+			 dev_info->ctl_name);
 
 		continue;
 
@@ -884,8 +883,8 @@ static void cpc925_del_edac_devices(void)
 		if (dev_info->exit)
 			dev_info->exit(dev_info);
 
-		debugf0("%s: Successfully deleted edac device for %s\n",
-			__func__, dev_info->ctl_name);
+		edac_dbg(0, "Successfully deleted edac device for %s\n",
+			 dev_info->ctl_name);
 	}
 }
 
@@ -900,7 +899,7 @@ static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci)
 	mscr = __raw_readl(pdata->vbase + REG_MSCR_OFFSET);
 	si = (mscr & MSCR_SI_MASK) >> MSCR_SI_SHIFT;
 
-	debugf0("%s, Mem Scrub Ctrl Register 0x%x\n", __func__, mscr);
+	edac_dbg(0, "Mem Scrub Ctrl Register 0x%x\n", mscr);
 
 	if (((mscr & MSCR_SCRUB_MOD_MASK) != MSCR_BACKGR_SCRUB) ||
 	    (si == 0)) {
@@ -928,8 +927,7 @@ static int cpc925_mc_get_channels(void __iomem *vbase)
 	    ((mbcr & MBCR_64BITBUS_MASK) == 0))
 		dual = 1;
 
-	debugf0("%s: %s channel\n", __func__,
-		(dual > 0) ? "Dual" : "Single");
+	edac_dbg(0, "%s channel\n", (dual > 0) ? "Dual" : "Single");
 
 	return dual;
 }
@@ -944,7 +942,7 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
 	struct resource *r;
 	int res = 0, nr_channels;
 
-	debugf0("%s: %s platform device found!\n", __func__, pdev->name);
+	edac_dbg(0, "%s platform device found!\n", pdev->name);
 
 	if (!devres_open_group(&pdev->dev, cpc925_probe, GFP_KERNEL)) {
 		res = -ENOMEM;
@@ -995,7 +993,7 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
 	pdata->edac_idx = edac_mc_idx++;
 	pdata->name = pdev->name;
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	platform_set_drvdata(pdev, mci);
 	mci->dev_name = dev_name(&pdev->dev);
 	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
@@ -1026,7 +1024,7 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
 	cpc925_add_edac_devices(vbase);
 
 	/* get this far and it's successful */
-	debugf0("%s: success\n", __func__);
+	edac_dbg(0, "success\n");
 
 	res = 0;
 	goto out;
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 3186512..a5ed6b7 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -309,7 +309,7 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
 	u32 remap;
 	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
 	if (page < pvt->tolm)
 		return page;
@@ -335,7 +335,7 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
 	int i;
 	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
 	/* convert the addr to 4k page */
 	page = sec1_add >> (PAGE_SHIFT - 4);
@@ -371,10 +371,10 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
 	channel = !(error_one & 1);
 
 	/* e752x mc reads 34:6 of the DRAM linear address */
-	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 			     page, offset_in_page(sec1_add << 4), sec1_syndrome,
 			     row, channel, -1,
-			     "e752x CE", "", NULL);
+			     "e752x CE", "");
 }
 
 static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
@@ -394,7 +394,7 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
 	int row;
 	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
 	if (error_one & 0x0202) {
 		error_2b = ded_add;
@@ -408,11 +408,11 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
 			edac_mc_find_csrow_by_page(mci, block_page);
 
 		/* e752x mc reads 34:6 of the DRAM linear address */
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 					block_page,
 					offset_in_page(error_2b << 4), 0,
 					 row, -1, -1,
-					"e752x UE from Read", "", NULL);
+					"e752x UE from Read", "");
 
 	}
 	if (error_one & 0x0404) {
@@ -427,11 +427,11 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
 			edac_mc_find_csrow_by_page(mci, block_page);
 
 		/* e752x mc reads 34:6 of the DRAM linear address */
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 					block_page,
 					offset_in_page(error_2b << 4), 0,
 					row, -1, -1,
-					"e752x UE from Scruber", "", NULL);
+					"e752x UE from Scruber", "");
 	}
 }
 
@@ -453,10 +453,10 @@ static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
 	if (!handle_error)
 		return;
 
-	debugf3("%s()\n", __func__);
-	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
+	edac_dbg(3, "\n");
+	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
 			     -1, -1, -1,
-			     "e752x UE log memory write", "", NULL);
+			     "e752x UE log memory write", "");
 }
 
 static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error,
@@ -982,7 +982,7 @@ static void e752x_check(struct mem_ctl_info *mci)
 {
 	struct e752x_error_info info;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 	e752x_get_error_info(mci, &info);
 	e752x_process_error_info(mci, &info, 1);
 }
@@ -1069,6 +1069,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 			u16 ddrcsr)
 {
 	struct csrow_info *csrow;
+	enum edac_type edac_mode;
 	unsigned long last_cumul_size;
 	int index, mem_dev, drc_chan;
 	int drc_drbg;		/* DRB granularity 0=64mb, 1=128mb */
@@ -1095,14 +1096,13 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
 		/* mem_dev 0=x8, 1=x4 */
 		mem_dev = (dra >> (index * 4 + 2)) & 0x3;
-		csrow = &mci->csrows[remap_csrow_index(mci, index)];
+		csrow = mci->csrows[remap_csrow_index(mci, index)];
 
 		mem_dev = (mem_dev == 2);
 		pci_read_config_byte(pdev, E752X_DRB + index, &value);
 		/* convert a 128 or 64 MiB DRB to a page size. */
 		cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
-		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
-			cumul_size);
+		edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size);
 		if (cumul_size == last_cumul_size)
 			continue;	/* not populated */
 
@@ -1111,29 +1111,29 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 		nr_pages = cumul_size - last_cumul_size;
 		last_cumul_size = cumul_size;
 
+		/*
+		* if single channel or x8 devices then SECDED
+		* if dual channel and x4 then S4ECD4ED
+		*/
+		if (drc_ddim) {
+			if (drc_chan && mem_dev) {
+				edac_mode = EDAC_S4ECD4ED;
+				mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
+			} else {
+				edac_mode = EDAC_SECDED;
+				mci->edac_cap |= EDAC_FLAG_SECDED;
+			}
+		} else
+			edac_mode = EDAC_NONE;
 		for (i = 0; i < csrow->nr_channels; i++) {
-			struct dimm_info *dimm = csrow->channels[i].dimm;
+			struct dimm_info *dimm = csrow->channels[i]->dimm;
 
-			debugf3("Initializing rank at (%i,%i)\n", index, i);
+			edac_dbg(3, "Initializing rank at (%i,%i)\n", index, i);
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
 			dimm->grain = 1 << 12;	/* 4KiB - resolution of CELOG */
 			dimm->mtype = MEM_RDDR;	/* only one type supported */
 			dimm->dtype = mem_dev ? DEV_X4 : DEV_X8;
-
-			/*
-			* if single channel or x8 devices then SECDED
-			* if dual channel and x4 then S4ECD4ED
-			*/
-			if (drc_ddim) {
-				if (drc_chan && mem_dev) {
-					dimm->edac_mode = EDAC_S4ECD4ED;
-					mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
-				} else {
-					dimm->edac_mode = EDAC_SECDED;
-					mci->edac_cap |= EDAC_FLAG_SECDED;
-				}
-			} else
-				dimm->edac_mode = EDAC_NONE;
+			dimm->edac_mode = edac_mode;
 		}
 	}
 }
@@ -1269,8 +1269,8 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
 	int drc_chan;		/* Number of channels 0=1chan,1=2chan */
 	struct e752x_error_info discard;
 
-	debugf0("%s(): mci\n", __func__);
-	debugf0("Starting Probe1\n");
+	edac_dbg(0, "mci\n");
+	edac_dbg(0, "Starting Probe1\n");
 
 	/* check to see if device 0 function 1 is enabled; if it isn't, we
 	 * assume the BIOS has reserved it for a reason and is expecting
@@ -1300,7 +1300,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
 	if (mci == NULL)
 		return -ENOMEM;
 
-	debugf3("%s(): init mci\n", __func__);
+	edac_dbg(3, "init mci\n");
 	mci->mtype_cap = MEM_FLAG_RDDR;
 	/* 3100 IMCH supports SECDEC only */
 	mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED :
@@ -1308,9 +1308,9 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
 	/* FIXME - what if different memory types are in different csrows? */
 	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = E752X_REVISION;
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 
-	debugf3("%s(): init pvt\n", __func__);
+	edac_dbg(3, "init pvt\n");
 	pvt = (struct e752x_pvt *)mci->pvt_info;
 	pvt->dev_info = &e752x_devs[dev_idx];
 	pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
@@ -1320,7 +1320,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
 		return -ENODEV;
 	}
 
-	debugf3("%s(): more mci init\n", __func__);
+	edac_dbg(3, "more mci init\n");
 	mci->ctl_name = pvt->dev_info->ctl_name;
 	mci->dev_name = pci_name(pdev);
 	mci->edac_check = e752x_check;
@@ -1342,7 +1342,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
 		mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */
 	else
 		mci->edac_cap |= EDAC_FLAG_NONE;
-	debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
+	edac_dbg(3, "tolm, remapbase, remaplimit\n");
 
 	/* load the top of low memory, remap base, and remap limit vars */
 	pci_read_config_word(pdev, E752X_TOLM, &pci_data);
@@ -1359,7 +1359,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
 	if (edac_mc_add_mc(mci)) {
-		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "failed edac_mc_add_mc()\n");
 		goto fail;
 	}
 
@@ -1377,7 +1377,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
 	}
 
 	/* get this far and it's successful */
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 	return 0;
 
 fail:
@@ -1393,7 +1393,7 @@ fail:
 static int __devinit e752x_init_one(struct pci_dev *pdev,
 				const struct pci_device_id *ent)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* wake up and enable device */
 	if (pci_enable_device(pdev) < 0)
@@ -1407,7 +1407,7 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
 	struct mem_ctl_info *mci;
 	struct e752x_pvt *pvt;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	if (e752x_pci)
 		edac_pci_release_generic_ctl(e752x_pci);
@@ -1453,7 +1453,7 @@ static int __init e752x_init(void)
 {
 	int pci_rc;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -1464,7 +1464,7 @@ static int __init e752x_init(void)
 
 static void __exit e752x_exit(void)
 {
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 	pci_unregister_driver(&e752x_driver);
 }
 
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 9a9c1a5..9ff57f3 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -166,7 +166,7 @@ static const struct e7xxx_dev_info e7xxx_devs[] = {
 /* FIXME - is this valid for both SECDED and S4ECD4ED? */
 static inline int e7xxx_find_channel(u16 syndrome)
 {
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
 	if ((syndrome & 0xff00) == 0)
 		return 0;
@@ -186,7 +186,7 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
 	u32 remap;
 	struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
 	if ((page < pvt->tolm) ||
 		((page >= 0x100000) && (page < pvt->remapbase)))
@@ -208,7 +208,7 @@ static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
 	int row;
 	int channel;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 	/* read the error address */
 	error_1b = info->dram_celog_add;
 	/* FIXME - should use PAGE_SHIFT */
@@ -219,15 +219,15 @@ static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
 	row = edac_mc_find_csrow_by_page(mci, page);
 	/* convert syndrome to channel */
 	channel = e7xxx_find_channel(syndrome);
-	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, page, 0, syndrome,
-			     row, channel, -1, "e7xxx CE", "", NULL);
+	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, page, 0, syndrome,
+			     row, channel, -1, "e7xxx CE", "");
 }
 
 static void process_ce_no_info(struct mem_ctl_info *mci)
 {
-	debugf3("%s()\n", __func__);
-	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, -1, -1, -1,
-			     "e7xxx CE log register overflow", "", NULL);
+	edac_dbg(3, "\n");
+	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1,
+			     "e7xxx CE log register overflow", "");
 }
 
 static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
@@ -235,23 +235,23 @@ static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
 	u32 error_2b, block_page;
 	int row;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 	/* read the error address */
 	error_2b = info->dram_uelog_add;
 	/* FIXME - should use PAGE_SHIFT */
 	block_page = error_2b >> 6;	/* convert to 4k address */
 	row = edac_mc_find_csrow_by_page(mci, block_page);
 
-	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, block_page, 0, 0,
-			     row, -1, -1, "e7xxx UE", "", NULL);
+	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, block_page, 0, 0,
+			     row, -1, -1, "e7xxx UE", "");
 }
 
 static void process_ue_no_info(struct mem_ctl_info *mci)
 {
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
-	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, -1, -1, -1,
-			     "e7xxx UE log register overflow", "", NULL);
+	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1,
+			     "e7xxx UE log register overflow", "");
 }
 
 static void e7xxx_get_error_info(struct mem_ctl_info *mci,
@@ -334,7 +334,7 @@ static void e7xxx_check(struct mem_ctl_info *mci)
 {
 	struct e7xxx_error_info info;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 	e7xxx_get_error_info(mci, &info);
 	e7xxx_process_error_info(mci, &info, 1);
 }
@@ -362,6 +362,7 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	int drc_chan, drc_drbg, drc_ddim, mem_dev;
 	struct csrow_info *csrow;
 	struct dimm_info *dimm;
+	enum edac_type edac_mode;
 
 	pci_read_config_dword(pdev, E7XXX_DRA, &dra);
 	drc_chan = dual_channel_active(drc, dev_idx);
@@ -377,13 +378,12 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	for (index = 0; index < mci->nr_csrows; index++) {
 		/* mem_dev 0=x8, 1=x4 */
 		mem_dev = (dra >> (index * 4 + 3)) & 0x1;
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		pci_read_config_byte(pdev, E7XXX_DRB + index, &value);
 		/* convert a 64 or 32 MiB DRB to a page size. */
 		cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
-		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
-			cumul_size);
+		edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size);
 		if (cumul_size == last_cumul_size)
 			continue;	/* not populated */
 
@@ -392,28 +392,29 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 		nr_pages = cumul_size - last_cumul_size;
 		last_cumul_size = cumul_size;
 
+		/*
+		* if single channel or x8 devices then SECDED
+		* if dual channel and x4 then S4ECD4ED
+		*/
+		if (drc_ddim) {
+			if (drc_chan && mem_dev) {
+				edac_mode = EDAC_S4ECD4ED;
+				mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
+			} else {
+				edac_mode = EDAC_SECDED;
+				mci->edac_cap |= EDAC_FLAG_SECDED;
+			}
+		} else
+			edac_mode = EDAC_NONE;
+
 		for (j = 0; j < drc_chan + 1; j++) {
-			dimm = csrow->channels[j].dimm;
+			dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / (drc_chan + 1);
 			dimm->grain = 1 << 12;	/* 4KiB - resolution of CELOG */
 			dimm->mtype = MEM_RDDR;	/* only one type supported */
 			dimm->dtype = mem_dev ? DEV_X4 : DEV_X8;
-
-			/*
-			* if single channel or x8 devices then SECDED
-			* if dual channel and x4 then S4ECD4ED
-			*/
-			if (drc_ddim) {
-				if (drc_chan && mem_dev) {
-					dimm->edac_mode = EDAC_S4ECD4ED;
-					mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
-				} else {
-					dimm->edac_mode = EDAC_SECDED;
-					mci->edac_cap |= EDAC_FLAG_SECDED;
-				}
-			} else
-				dimm->edac_mode = EDAC_NONE;
+			dimm->edac_mode = edac_mode;
 		}
 	}
 }
@@ -428,7 +429,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
 	int drc_chan;
 	struct e7xxx_error_info discard;
 
-	debugf0("%s(): mci\n", __func__);
+	edac_dbg(0, "mci\n");
 
 	pci_read_config_dword(pdev, E7XXX_DRC, &drc);
 
@@ -451,15 +452,15 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
 	if (mci == NULL)
 		return -ENOMEM;
 
-	debugf3("%s(): init mci\n", __func__);
+	edac_dbg(3, "init mci\n");
 	mci->mtype_cap = MEM_FLAG_RDDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
 		EDAC_FLAG_S4ECD4ED;
 	/* FIXME - what if different memory types are in different csrows? */
 	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = E7XXX_REVISION;
-	mci->dev = &pdev->dev;
-	debugf3("%s(): init pvt\n", __func__);
+	mci->pdev = &pdev->dev;
+	edac_dbg(3, "init pvt\n");
 	pvt = (struct e7xxx_pvt *)mci->pvt_info;
 	pvt->dev_info = &e7xxx_devs[dev_idx];
 	pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
@@ -472,14 +473,14 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
 		goto fail0;
 	}
 
-	debugf3("%s(): more mci init\n", __func__);
+	edac_dbg(3, "more mci init\n");
 	mci->ctl_name = pvt->dev_info->ctl_name;
 	mci->dev_name = pci_name(pdev);
 	mci->edac_check = e7xxx_check;
 	mci->ctl_page_to_phys = ctl_page_to_phys;
 	e7xxx_init_csrows(mci, pdev, dev_idx, drc);
 	mci->edac_cap |= EDAC_FLAG_NONE;
-	debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
+	edac_dbg(3, "tolm, remapbase, remaplimit\n");
 	/* load the top of low memory, remap base, and remap limit vars */
 	pci_read_config_word(pdev, E7XXX_TOLM, &pci_data);
 	pvt->tolm = ((u32) pci_data) << 4;
@@ -498,7 +499,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
 	if (edac_mc_add_mc(mci)) {
-		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "failed edac_mc_add_mc()\n");
 		goto fail1;
 	}
 
@@ -514,7 +515,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
 	}
 
 	/* get this far and it's successful */
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 	return 0;
 
 fail1:
@@ -530,7 +531,7 @@ fail0:
 static int __devinit e7xxx_init_one(struct pci_dev *pdev,
 				const struct pci_device_id *ent)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* wake up and enable device */
 	return pci_enable_device(pdev) ?
@@ -542,7 +543,7 @@ static void __devexit e7xxx_remove_one(struct pci_dev *pdev)
 	struct mem_ctl_info *mci;
 	struct e7xxx_pvt *pvt;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	if (e7xxx_pci)
 		edac_pci_release_generic_ctl(e7xxx_pci);
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index 117490d..23bb99f 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -71,26 +71,21 @@ extern const char *edac_mem_types[];
 #ifdef CONFIG_EDAC_DEBUG
 extern int edac_debug_level;
 
-#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)
-
-#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
-#define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ )
-#define debugf2( ... ) edac_debug_printk(2, __VA_ARGS__ )
-#define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ )
-#define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ )
+#define edac_dbg(level, fmt, ...)					\
+do {									\
+	if (level <= edac_debug_level)					\
+		edac_printk(KERN_DEBUG, EDAC_DEBUG,			\
+			    "%s: " fmt, __func__, ##__VA_ARGS__);	\
+} while (0)
 
 #else				/* !CONFIG_EDAC_DEBUG */
 
-#define debugf0( ... )
-#define debugf1( ... )
-#define debugf2( ... )
-#define debugf3( ... )
-#define debugf4( ... )
+#define edac_dbg(level, fmt, ...)					\
+do {									\
+	if (0)								\
+		edac_printk(KERN_DEBUG, EDAC_DEBUG,			\
+			    "%s: " fmt, __func__, ##__VA_ARGS__);	\
+} while (0)
 
 #endif				/* !CONFIG_EDAC_DEBUG */
 
@@ -460,15 +455,15 @@ extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
 				      unsigned long page);
 void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  struct mem_ctl_info *mci,
+			  const u16 error_count,
 			  const unsigned long page_frame_number,
 			  const unsigned long offset_in_page,
 			  const unsigned long syndrome,
-			  const int layer0,
-			  const int layer1,
-			  const int layer2,
+			  const int top_layer,
+			  const int mid_layer,
+			  const int low_layer,
 			  const char *msg,
-			  const char *other_detail,
-			  const void *mcelog);
+			  const char *other_detail);
 
 /*
  * edac_device APIs
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index ee3f1f8..211021d 100644
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -40,12 +40,13 @@ static LIST_HEAD(edac_device_list);
 #ifdef CONFIG_EDAC_DEBUG
 static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
 {
-	debugf3("\tedac_dev = %p dev_idx=%d \n", edac_dev, edac_dev->dev_idx);
-	debugf4("\tedac_dev->edac_check = %p\n", edac_dev->edac_check);
-	debugf3("\tdev = %p\n", edac_dev->dev);
-	debugf3("\tmod_name:ctl_name = %s:%s\n",
-		edac_dev->mod_name, edac_dev->ctl_name);
-	debugf3("\tpvt_info = %p\n\n", edac_dev->pvt_info);
+	edac_dbg(3, "\tedac_dev = %p dev_idx=%d\n",
+		 edac_dev, edac_dev->dev_idx);
+	edac_dbg(4, "\tedac_dev->edac_check = %p\n", edac_dev->edac_check);
+	edac_dbg(3, "\tdev = %p\n", edac_dev->dev);
+	edac_dbg(3, "\tmod_name:ctl_name = %s:%s\n",
+		 edac_dev->mod_name, edac_dev->ctl_name);
+	edac_dbg(3, "\tpvt_info = %p\n\n", edac_dev->pvt_info);
 }
 #endif				/* CONFIG_EDAC_DEBUG */
 
@@ -82,8 +83,7 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
 	void *pvt, *p;
 	int err;
 
-	debugf4("%s() instances=%d blocks=%d\n",
-		__func__, nr_instances, nr_blocks);
+	edac_dbg(4, "instances=%d blocks=%d\n", nr_instances, nr_blocks);
 
 	/* Calculate the size of memory we need to allocate AND
 	 * determine the offsets of the various item arrays
@@ -156,8 +156,8 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
 	/* Name of this edac device */
 	snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s",edac_device_name);
 
-	debugf4("%s() edac_dev=%p next after end=%p\n",
-		__func__, dev_ctl, pvt + sz_private );
+	edac_dbg(4, "edac_dev=%p next after end=%p\n",
+		 dev_ctl, pvt + sz_private);
 
 	/* Initialize every Instance */
 	for (instance = 0; instance < nr_instances; instance++) {
@@ -178,10 +178,8 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
 			snprintf(blk->name, sizeof(blk->name),
 				 "%s%d", edac_block_name, block+offset_value);
 
-			debugf4("%s() instance=%d inst_p=%p block=#%d "
-				"block_p=%p name='%s'\n",
-				__func__, instance, inst, block,
-				blk, blk->name);
+			edac_dbg(4, "instance=%d inst_p=%p block=#%d block_p=%p name='%s'\n",
+				 instance, inst, block, blk, blk->name);
 
 			/* if there are NO attributes OR no attribute pointer
 			 * then continue on to next block iteration
@@ -194,8 +192,8 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
 			attrib_p = &dev_attrib[block*nr_instances*nr_attrib];
 			blk->block_attributes = attrib_p;
 
-			debugf4("%s() THIS BLOCK_ATTRIB=%p\n",
-				__func__, blk->block_attributes);
+			edac_dbg(4, "THIS BLOCK_ATTRIB=%p\n",
+				 blk->block_attributes);
 
 			/* Initialize every user specified attribute in this
 			 * block with the data the caller passed in
@@ -214,11 +212,10 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
 
 				attrib->block = blk;	/* up link */
 
-				debugf4("%s() alloc-attrib=%p attrib_name='%s' "
-					"attrib-spec=%p spec-name=%s\n",
-					__func__, attrib, attrib->attr.name,
-					&attrib_spec[attr],
-					attrib_spec[attr].attr.name
+				edac_dbg(4, "alloc-attrib=%p attrib_name='%s' attrib-spec=%p spec-name=%s\n",
+					 attrib, attrib->attr.name,
+					 &attrib_spec[attr],
+					 attrib_spec[attr].attr.name
 					);
 			}
 		}
@@ -273,7 +270,7 @@ static struct edac_device_ctl_info *find_edac_device_by_dev(struct device *dev)
 	struct edac_device_ctl_info *edac_dev;
 	struct list_head *item;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	list_for_each(item, &edac_device_list) {
 		edac_dev = list_entry(item, struct edac_device_ctl_info, link);
@@ -408,7 +405,7 @@ static void edac_device_workq_function(struct work_struct *work_req)
 void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
 				unsigned msec)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* take the arg 'msec' and set it into the control structure
 	 * to used in the time period calculation
@@ -496,7 +493,7 @@ EXPORT_SYMBOL_GPL(edac_device_alloc_index);
  */
 int edac_device_add_device(struct edac_device_ctl_info *edac_dev)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 #ifdef CONFIG_EDAC_DEBUG
 	if (edac_debug_level >= 3)
@@ -570,7 +567,7 @@ struct edac_device_ctl_info *edac_device_del_device(struct device *dev)
 {
 	struct edac_device_ctl_info *edac_dev;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	mutex_lock(&device_ctls_mutex);
 
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
index b4ea185..fb68a06 100644
--- a/drivers/edac/edac_device_sysfs.c
+++ b/drivers/edac/edac_device_sysfs.c
@@ -202,7 +202,7 @@ static void edac_device_ctrl_master_release(struct kobject *kobj)
 {
 	struct edac_device_ctl_info *edac_dev = to_edacdev(kobj);
 
-	debugf4("%s() control index=%d\n", __func__, edac_dev->dev_idx);
+	edac_dbg(4, "control index=%d\n", edac_dev->dev_idx);
 
 	/* decrement the EDAC CORE module ref count */
 	module_put(edac_dev->owner);
@@ -233,12 +233,12 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
 	struct bus_type *edac_subsys;
 	int err;
 
-	debugf1("%s()\n", __func__);
+	edac_dbg(1, "\n");
 
 	/* get the /sys/devices/system/edac reference */
 	edac_subsys = edac_get_sysfs_subsys();
 	if (edac_subsys == NULL) {
-		debugf1("%s() no edac_subsys error\n", __func__);
+		edac_dbg(1, "no edac_subsys error\n");
 		err = -ENODEV;
 		goto err_out;
 	}
@@ -264,8 +264,8 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
 				   &edac_subsys->dev_root->kobj,
 				   "%s", edac_dev->name);
 	if (err) {
-		debugf1("%s()Failed to register '.../edac/%s'\n",
-			__func__, edac_dev->name);
+		edac_dbg(1, "Failed to register '.../edac/%s'\n",
+			 edac_dev->name);
 		goto err_kobj_reg;
 	}
 	kobject_uevent(&edac_dev->kobj, KOBJ_ADD);
@@ -274,8 +274,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
 	 * edac_device_unregister_sysfs_main_kobj() must be used
 	 */
 
-	debugf4("%s() Registered '.../edac/%s' kobject\n",
-		__func__, edac_dev->name);
+	edac_dbg(4, "Registered '.../edac/%s' kobject\n", edac_dev->name);
 
 	return 0;
 
@@ -296,9 +295,8 @@ err_out:
  */
 void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
 {
-	debugf0("%s()\n", __func__);
-	debugf4("%s() name of kobject is: %s\n",
-		__func__, kobject_name(&dev->kobj));
+	edac_dbg(0, "\n");
+	edac_dbg(4, "name of kobject is: %s\n", kobject_name(&dev->kobj));
 
 	/*
 	 * Unregister the edac device's kobject and
@@ -336,7 +334,7 @@ static void edac_device_ctrl_instance_release(struct kobject *kobj)
 {
 	struct edac_device_instance *instance;
 
-	debugf1("%s()\n", __func__);
+	edac_dbg(1, "\n");
 
 	/* map from this kobj to the main control struct
 	 * and then dec the main kobj count
@@ -442,7 +440,7 @@ static void edac_device_ctrl_block_release(struct kobject *kobj)
 {
 	struct edac_device_block *block;
 
-	debugf1("%s()\n", __func__);
+	edac_dbg(1, "\n");
 
 	/* get the container of the kobj */
 	block = to_block(kobj);
@@ -524,10 +522,10 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
 	struct edac_dev_sysfs_block_attribute *sysfs_attrib;
 	struct kobject *main_kobj;
 
-	debugf4("%s() Instance '%s' inst_p=%p  block '%s'  block_p=%p\n",
-		__func__, instance->name, instance, block->name, block);
-	debugf4("%s() block kobj=%p  block kobj->parent=%p\n",
-		__func__, &block->kobj, &block->kobj.parent);
+	edac_dbg(4, "Instance '%s' inst_p=%p  block '%s'  block_p=%p\n",
+		 instance->name, instance, block->name, block);
+	edac_dbg(4, "block kobj=%p  block kobj->parent=%p\n",
+		 &block->kobj, &block->kobj.parent);
 
 	/* init this block's kobject */
 	memset(&block->kobj, 0, sizeof(struct kobject));
@@ -546,8 +544,7 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
 				   &instance->kobj,
 				   "%s", block->name);
 	if (err) {
-		debugf1("%s() Failed to register instance '%s'\n",
-			__func__, block->name);
+		edac_dbg(1, "Failed to register instance '%s'\n", block->name);
 		kobject_put(main_kobj);
 		err = -ENODEV;
 		goto err_out;
@@ -560,11 +557,9 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
 	if (sysfs_attrib && block->nr_attribs) {
 		for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
 
-			debugf4("%s() creating block attrib='%s' "
-				"attrib->%p to kobj=%p\n",
-				__func__,
-				sysfs_attrib->attr.name,
-				sysfs_attrib, &block->kobj);
+			edac_dbg(4, "creating block attrib='%s' attrib->%p to kobj=%p\n",
+				 sysfs_attrib->attr.name,
+				 sysfs_attrib, &block->kobj);
 
 			/* Create each block_attribute file */
 			err = sysfs_create_file(&block->kobj,
@@ -647,14 +642,14 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
 	err = kobject_init_and_add(&instance->kobj, &ktype_instance_ctrl,
 				   &edac_dev->kobj, "%s", instance->name);
 	if (err != 0) {
-		debugf2("%s() Failed to register instance '%s'\n",
-			__func__, instance->name);
+		edac_dbg(2, "Failed to register instance '%s'\n",
+			 instance->name);
 		kobject_put(main_kobj);
 		goto err_out;
 	}
 
-	debugf4("%s() now register '%d' blocks for instance %d\n",
-		__func__, instance->nr_blocks, idx);
+	edac_dbg(4, "now register '%d' blocks for instance %d\n",
+		 instance->nr_blocks, idx);
 
 	/* register all blocks of this instance */
 	for (i = 0; i < instance->nr_blocks; i++) {
@@ -670,8 +665,8 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
 	}
 	kobject_uevent(&instance->kobj, KOBJ_ADD);
 
-	debugf4("%s() Registered instance %d '%s' kobject\n",
-		__func__, idx, instance->name);
+	edac_dbg(4, "Registered instance %d '%s' kobject\n",
+		 idx, instance->name);
 
 	return 0;
 
@@ -715,7 +710,7 @@ static int edac_device_create_instances(struct edac_device_ctl_info *edac_dev)
 	int i, j;
 	int err;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* iterate over creation of the instances */
 	for (i = 0; i < edac_dev->nr_instances; i++) {
@@ -817,12 +812,12 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
 	int err;
 	struct kobject *edac_kobj = &edac_dev->kobj;
 
-	debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx);
+	edac_dbg(0, "idx=%d\n", edac_dev->dev_idx);
 
 	/*  go create any main attributes callers wants */
 	err = edac_device_add_main_sysfs_attributes(edac_dev);
 	if (err) {
-		debugf0("%s() failed to add sysfs attribs\n", __func__);
+		edac_dbg(0, "failed to add sysfs attribs\n");
 		goto err_out;
 	}
 
@@ -832,8 +827,7 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
 	err = sysfs_create_link(edac_kobj,
 				&edac_dev->dev->kobj, EDAC_DEVICE_SYMLINK);
 	if (err) {
-		debugf0("%s() sysfs_create_link() returned err= %d\n",
-			__func__, err);
+		edac_dbg(0, "sysfs_create_link() returned err= %d\n", err);
 		goto err_remove_main_attribs;
 	}
 
@@ -843,14 +837,13 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
 	 */
 	err = edac_device_create_instances(edac_dev);
 	if (err) {
-		debugf0("%s() edac_device_create_instances() "
-			"returned err= %d\n", __func__, err);
+		edac_dbg(0, "edac_device_create_instances() returned err= %d\n",
+			 err);
 		goto err_remove_link;
 	}
 
 
-	debugf4("%s() create-instances done, idx=%d\n",
-		__func__, edac_dev->dev_idx);
+	edac_dbg(4, "create-instances done, idx=%d\n", edac_dev->dev_idx);
 
 	return 0;
 
@@ -873,7 +866,7 @@ err_out:
  */
 void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* remove any main attributes for this device */
 	edac_device_remove_main_sysfs_attributes(edac_dev);
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index de5ba86e..616d90b 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -27,70 +27,95 @@
 #include <linux/list.h>
 #include <linux/ctype.h>
 #include <linux/edac.h>
+#include <linux/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/edac.h>
 #include "edac_core.h"
 #include "edac_module.h"
 
+#define CREATE_TRACE_POINTS
+#define TRACE_INCLUDE_PATH ../../include/ras
+#include <ras/ras_event.h>
+
 /* lock to memory controller's control array */
 static DEFINE_MUTEX(mem_ctls_mutex);
 static LIST_HEAD(mc_devices);
 
+unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
+			         unsigned len)
+{
+	struct mem_ctl_info *mci = dimm->mci;
+	int i, n, count = 0;
+	char *p = buf;
+
+	for (i = 0; i < mci->n_layers; i++) {
+		n = snprintf(p, len, "%s %d ",
+			      edac_layer_name[mci->layers[i].type],
+			      dimm->location[i]);
+		p += n;
+		len -= n;
+		count += n;
+		if (!len)
+			break;
+	}
+
+	return count;
+}
+
 #ifdef CONFIG_EDAC_DEBUG
 
 static void edac_mc_dump_channel(struct rank_info *chan)
 {
-	debugf4("\tchannel = %p\n", chan);
-	debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx);
-	debugf4("\tchannel->csrow = %p\n\n", chan->csrow);
-	debugf4("\tchannel->dimm = %p\n", chan->dimm);
+	edac_dbg(4, "  channel->chan_idx = %d\n", chan->chan_idx);
+	edac_dbg(4, "    channel = %p\n", chan);
+	edac_dbg(4, "    channel->csrow = %p\n", chan->csrow);
+	edac_dbg(4, "    channel->dimm = %p\n", chan->dimm);
 }
 
-static void edac_mc_dump_dimm(struct dimm_info *dimm)
+static void edac_mc_dump_dimm(struct dimm_info *dimm, int number)
 {
-	int i;
-
-	debugf4("\tdimm = %p\n", dimm);
-	debugf4("\tdimm->label = '%s'\n", dimm->label);
-	debugf4("\tdimm->nr_pages = 0x%x\n", dimm->nr_pages);
-	debugf4("\tdimm location ");
-	for (i = 0; i < dimm->mci->n_layers; i++) {
-		printk(KERN_CONT "%d", dimm->location[i]);
-		if (i < dimm->mci->n_layers - 1)
-			printk(KERN_CONT ".");
-	}
-	printk(KERN_CONT "\n");
-	debugf4("\tdimm->grain = %d\n", dimm->grain);
-	debugf4("\tdimm->nr_pages = 0x%x\n", dimm->nr_pages);
+	char location[80];
+
+	edac_dimm_info_location(dimm, location, sizeof(location));
+
+	edac_dbg(4, "%s%i: %smapped as virtual row %d, chan %d\n",
+		 dimm->mci->mem_is_per_rank ? "rank" : "dimm",
+		 number, location, dimm->csrow, dimm->cschannel);
+	edac_dbg(4, "  dimm = %p\n", dimm);
+	edac_dbg(4, "  dimm->label = '%s'\n", dimm->label);
+	edac_dbg(4, "  dimm->nr_pages = 0x%x\n", dimm->nr_pages);
+	edac_dbg(4, "  dimm->grain = %d\n", dimm->grain);
+	edac_dbg(4, "  dimm->nr_pages = 0x%x\n", dimm->nr_pages);
 }
 
 static void edac_mc_dump_csrow(struct csrow_info *csrow)
 {
-	debugf4("\tcsrow = %p\n", csrow);
-	debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx);
-	debugf4("\tcsrow->first_page = 0x%lx\n", csrow->first_page);
-	debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page);
-	debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask);
-	debugf4("\tcsrow->nr_channels = %d\n", csrow->nr_channels);
-	debugf4("\tcsrow->channels = %p\n", csrow->channels);
-	debugf4("\tcsrow->mci = %p\n\n", csrow->mci);
+	edac_dbg(4, "csrow->csrow_idx = %d\n", csrow->csrow_idx);
+	edac_dbg(4, "  csrow = %p\n", csrow);
+	edac_dbg(4, "  csrow->first_page = 0x%lx\n", csrow->first_page);
+	edac_dbg(4, "  csrow->last_page = 0x%lx\n", csrow->last_page);
+	edac_dbg(4, "  csrow->page_mask = 0x%lx\n", csrow->page_mask);
+	edac_dbg(4, "  csrow->nr_channels = %d\n", csrow->nr_channels);
+	edac_dbg(4, "  csrow->channels = %p\n", csrow->channels);
+	edac_dbg(4, "  csrow->mci = %p\n", csrow->mci);
 }
 
 static void edac_mc_dump_mci(struct mem_ctl_info *mci)
 {
-	debugf3("\tmci = %p\n", mci);
-	debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap);
-	debugf3("\tmci->edac_ctl_cap = %lx\n", mci->edac_ctl_cap);
-	debugf3("\tmci->edac_cap = %lx\n", mci->edac_cap);
-	debugf4("\tmci->edac_check = %p\n", mci->edac_check);
-	debugf3("\tmci->nr_csrows = %d, csrows = %p\n",
-		mci->nr_csrows, mci->csrows);
-	debugf3("\tmci->nr_dimms = %d, dimms = %p\n",
-		mci->tot_dimms, mci->dimms);
-	debugf3("\tdev = %p\n", mci->dev);
-	debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name);
-	debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
+	edac_dbg(3, "\tmci = %p\n", mci);
+	edac_dbg(3, "\tmci->mtype_cap = %lx\n", mci->mtype_cap);
+	edac_dbg(3, "\tmci->edac_ctl_cap = %lx\n", mci->edac_ctl_cap);
+	edac_dbg(3, "\tmci->edac_cap = %lx\n", mci->edac_cap);
+	edac_dbg(4, "\tmci->edac_check = %p\n", mci->edac_check);
+	edac_dbg(3, "\tmci->nr_csrows = %d, csrows = %p\n",
+		 mci->nr_csrows, mci->csrows);
+	edac_dbg(3, "\tmci->nr_dimms = %d, dimms = %p\n",
+		 mci->tot_dimms, mci->dimms);
+	edac_dbg(3, "\tdev = %p\n", mci->pdev);
+	edac_dbg(3, "\tmod_name:ctl_name = %s:%s\n",
+		 mci->mod_name, mci->ctl_name);
+	edac_dbg(3, "\tpvt_info = %p\n\n", mci->pvt_info);
 }
 
 #endif				/* CONFIG_EDAC_DEBUG */
@@ -205,15 +230,15 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 {
 	struct mem_ctl_info *mci;
 	struct edac_mc_layer *layer;
-	struct csrow_info *csi, *csr;
-	struct rank_info *chi, *chp, *chan;
+	struct csrow_info *csr;
+	struct rank_info *chan;
 	struct dimm_info *dimm;
 	u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
 	unsigned pos[EDAC_MAX_LAYERS];
 	unsigned size, tot_dimms = 1, count = 1;
 	unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
 	void *pvt, *p, *ptr = NULL;
-	int i, j, err, row, chn, n, len;
+	int i, j, row, chn, n, len, off;
 	bool per_rank = false;
 
 	BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0);
@@ -239,26 +264,24 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	 */
 	mci = edac_align_ptr(&ptr, sizeof(*mci), 1);
 	layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers);
-	csi = edac_align_ptr(&ptr, sizeof(*csi), tot_csrows);
-	chi = edac_align_ptr(&ptr, sizeof(*chi), tot_csrows * tot_channels);
-	dimm = edac_align_ptr(&ptr, sizeof(*dimm), tot_dimms);
 	for (i = 0; i < n_layers; i++) {
 		count *= layers[i].size;
-		debugf4("%s: errcount layer %d size %d\n", __func__, i, count);
+		edac_dbg(4, "errcount layer %d size %d\n", i, count);
 		ce_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count);
 		ue_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count);
 		tot_errcount += 2 * count;
 	}
 
-	debugf4("%s: allocating %d error counters\n", __func__, tot_errcount);
+	edac_dbg(4, "allocating %d error counters\n", tot_errcount);
 	pvt = edac_align_ptr(&ptr, sz_pvt, 1);
 	size = ((unsigned long)pvt) + sz_pvt;
 
-	debugf1("%s(): allocating %u bytes for mci data (%d %s, %d csrows/channels)\n",
-		__func__, size,
-		tot_dimms,
-		per_rank ? "ranks" : "dimms",
-		tot_csrows * tot_channels);
+	edac_dbg(1, "allocating %u bytes for mci data (%d %s, %d csrows/channels)\n",
+		 size,
+		 tot_dimms,
+		 per_rank ? "ranks" : "dimms",
+		 tot_csrows * tot_channels);
+
 	mci = kzalloc(size, GFP_KERNEL);
 	if (mci == NULL)
 		return NULL;
@@ -267,9 +290,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	 * rather than an imaginary chunk of memory located at address 0.
 	 */
 	layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer));
-	csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
-	chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi));
-	dimm = (struct dimm_info *)(((char *)mci) + ((unsigned long)dimm));
 	for (i = 0; i < n_layers; i++) {
 		mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i]));
 		mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i]));
@@ -278,8 +298,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 
 	/* setup index and various internal pointers */
 	mci->mc_idx = mc_num;
-	mci->csrows = csi;
-	mci->dimms  = dimm;
 	mci->tot_dimms = tot_dimms;
 	mci->pvt_info = pvt;
 	mci->n_layers = n_layers;
@@ -290,40 +308,57 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	mci->mem_is_per_rank = per_rank;
 
 	/*
-	 * Fill the csrow struct
+	 * Alocate and fill the csrow/channels structs
 	 */
+	mci->csrows = kcalloc(sizeof(*mci->csrows), tot_csrows, GFP_KERNEL);
+	if (!mci->csrows)
+		goto error;
 	for (row = 0; row < tot_csrows; row++) {
-		csr = &csi[row];
+		csr = kzalloc(sizeof(**mci->csrows), GFP_KERNEL);
+		if (!csr)
+			goto error;
+		mci->csrows[row] = csr;
 		csr->csrow_idx = row;
 		csr->mci = mci;
 		csr->nr_channels = tot_channels;
-		chp = &chi[row * tot_channels];
-		csr->channels = chp;
+		csr->channels = kcalloc(sizeof(*csr->channels), tot_channels,
+					GFP_KERNEL);
+		if (!csr->channels)
+			goto error;
 
 		for (chn = 0; chn < tot_channels; chn++) {
-			chan = &chp[chn];
+			chan = kzalloc(sizeof(**csr->channels), GFP_KERNEL);
+			if (!chan)
+				goto error;
+			csr->channels[chn] = chan;
 			chan->chan_idx = chn;
 			chan->csrow = csr;
 		}
 	}
 
 	/*
-	 * Fill the dimm struct
+	 * Allocate and fill the dimm structs
 	 */
+	mci->dimms  = kcalloc(sizeof(*mci->dimms), tot_dimms, GFP_KERNEL);
+	if (!mci->dimms)
+		goto error;
+
 	memset(&pos, 0, sizeof(pos));
 	row = 0;
 	chn = 0;
-	debugf4("%s: initializing %d %s\n", __func__, tot_dimms,
-		per_rank ? "ranks" : "dimms");
 	for (i = 0; i < tot_dimms; i++) {
-		chan = &csi[row].channels[chn];
-		dimm = EDAC_DIMM_PTR(layer, mci->dimms, n_layers,
-			       pos[0], pos[1], pos[2]);
-		dimm->mci = mci;
+		chan = mci->csrows[row]->channels[chn];
+		off = EDAC_DIMM_OFF(layer, n_layers, pos[0], pos[1], pos[2]);
+		if (off < 0 || off >= tot_dimms) {
+			edac_mc_printk(mci, KERN_ERR, "EDAC core bug: EDAC_DIMM_OFF is trying to do an illegal data access\n");
+			goto error;
+		}
 
-		debugf2("%s: %d: %s%zd (%d:%d:%d): row %d, chan %d\n", __func__,
-			i, per_rank ? "rank" : "dimm", (dimm - mci->dimms),
-			pos[0], pos[1], pos[2], row, chn);
+		dimm = kzalloc(sizeof(**mci->dimms), GFP_KERNEL);
+		if (!dimm)
+			goto error;
+		mci->dimms[off] = dimm;
+		dimm->mci = mci;
 
 		/*
 		 * Copy DIMM location and initialize it.
@@ -367,16 +402,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	}
 
 	mci->op_state = OP_ALLOC;
-	INIT_LIST_HEAD(&mci->grp_kobj_list);
-
-	/*
-	 * Initialize the 'root' kobj for the edac_mc controller
-	 */
-	err = edac_mc_register_sysfs_main_kobj(mci);
-	if (err) {
-		kfree(mci);
-		return NULL;
-	}
 
 	/* at this point, the root kobj is valid, and in order to
 	 * 'free' the object, then the function:
@@ -384,7 +409,30 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	 * which will perform kobj unregistration and the actual free
 	 * will occur during the kobject callback operation
 	 */
+
 	return mci;
+
+error:
+	if (mci->dimms) {
+		for (i = 0; i < tot_dimms; i++)
+			kfree(mci->dimms[i]);
+		kfree(mci->dimms);
+	}
+	if (mci->csrows) {
+		for (chn = 0; chn < tot_channels; chn++) {
+			csr = mci->csrows[chn];
+			if (csr) {
+				for (chn = 0; chn < tot_channels; chn++)
+					kfree(csr->channels[chn]);
+				kfree(csr);
+			}
+			kfree(mci->csrows[i]);
+		}
+		kfree(mci->csrows);
+	}
+	kfree(mci);
+
+	return NULL;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
 
@@ -395,12 +443,10 @@ EXPORT_SYMBOL_GPL(edac_mc_alloc);
  */
 void edac_mc_free(struct mem_ctl_info *mci)
 {
-	debugf1("%s()\n", __func__);
+	edac_dbg(1, "\n");
 
-	edac_mc_unregister_sysfs_main_kobj(mci);
-
-	/* free the mci instance memory here */
-	kfree(mci);
+	/* the mci instance is freed here, when the sysfs object is dropped */
+	edac_unregister_sysfs(mci);
 }
 EXPORT_SYMBOL_GPL(edac_mc_free);
 
@@ -417,12 +463,12 @@ struct mem_ctl_info *find_mci_by_dev(struct device *dev)
 	struct mem_ctl_info *mci;
 	struct list_head *item;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
 	list_for_each(item, &mc_devices) {
 		mci = list_entry(item, struct mem_ctl_info, link);
 
-		if (mci->dev == dev)
+		if (mci->pdev == dev)
 			return mci;
 	}
 
@@ -485,7 +531,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
  */
 static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* if this instance is not in the POLL state, then simply return */
 	if (mci->op_state != OP_RUNNING_POLL)
@@ -512,8 +558,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
 
 	status = cancel_delayed_work(&mci->work);
 	if (status == 0) {
-		debugf0("%s() not canceled, flush the queue\n",
-			__func__);
+		edac_dbg(0, "not canceled, flush the queue\n");
 
 		/* workq instance might be running, wait for it */
 		flush_workqueue(edac_workqueue);
@@ -574,7 +619,7 @@ static int add_mc_to_global_list(struct mem_ctl_info *mci)
 
 	insert_before = &mc_devices;
 
-	p = find_mci_by_dev(mci->dev);
+	p = find_mci_by_dev(mci->pdev);
 	if (unlikely(p != NULL))
 		goto fail0;
 
@@ -596,7 +641,7 @@ static int add_mc_to_global_list(struct mem_ctl_info *mci)
 
 fail0:
 	edac_printk(KERN_WARNING, EDAC_MC,
-		"%s (%s) %s %s already assigned %d\n", dev_name(p->dev),
+		"%s (%s) %s %s already assigned %d\n", dev_name(p->pdev),
 		edac_dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
 	return 1;
 
@@ -660,7 +705,7 @@ EXPORT_SYMBOL(edac_mc_find);
 /* FIXME - should a warning be printed if no error detection? correction? */
 int edac_mc_add_mc(struct mem_ctl_info *mci)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 #ifdef CONFIG_EDAC_DEBUG
 	if (edac_debug_level >= 3)
@@ -670,15 +715,22 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
 		int i;
 
 		for (i = 0; i < mci->nr_csrows; i++) {
+			struct csrow_info *csrow = mci->csrows[i];
+			u32 nr_pages = 0;
 			int j;
 
-			edac_mc_dump_csrow(&mci->csrows[i]);
-			for (j = 0; j < mci->csrows[i].nr_channels; j++)
-				edac_mc_dump_channel(&mci->csrows[i].
-						channels[j]);
+			for (j = 0; j < csrow->nr_channels; j++)
+				nr_pages += csrow->channels[j]->dimm->nr_pages;
+			if (!nr_pages)
+				continue;
+			edac_mc_dump_csrow(csrow);
+			for (j = 0; j < csrow->nr_channels; j++)
+				if (csrow->channels[j]->dimm->nr_pages)
+					edac_mc_dump_channel(csrow->channels[j]);
 		}
 		for (i = 0; i < mci->tot_dimms; i++)
-			edac_mc_dump_dimm(&mci->dimms[i]);
+			if (mci->dimms[i]->nr_pages)
+				edac_mc_dump_dimm(mci->dimms[i], i);
 	}
 #endif
 	mutex_lock(&mem_ctls_mutex);
@@ -732,7 +784,7 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	mutex_lock(&mem_ctls_mutex);
 
@@ -770,7 +822,7 @@ static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
 	void *virt_addr;
 	unsigned long flags = 0;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
 	/* ECC error page was not in our memory. Ignore it. */
 	if (!pfn_valid(page))
@@ -797,26 +849,26 @@ static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
 /* FIXME - should return -1 */
 int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
 {
-	struct csrow_info *csrows = mci->csrows;
+	struct csrow_info **csrows = mci->csrows;
 	int row, i, j, n;
 
-	debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page);
+	edac_dbg(1, "MC%d: 0x%lx\n", mci->mc_idx, page);
 	row = -1;
 
 	for (i = 0; i < mci->nr_csrows; i++) {
-		struct csrow_info *csrow = &csrows[i];
+		struct csrow_info *csrow = csrows[i];
 		n = 0;
 		for (j = 0; j < csrow->nr_channels; j++) {
-			struct dimm_info *dimm = csrow->channels[j].dimm;
+			struct dimm_info *dimm = csrow->channels[j]->dimm;
 			n += dimm->nr_pages;
 		}
 		if (n == 0)
 			continue;
 
-		debugf3("MC%d: %s(): first(0x%lx) page(0x%lx) last(0x%lx) "
-			"mask(0x%lx)\n", mci->mc_idx, __func__,
-			csrow->first_page, page, csrow->last_page,
-			csrow->page_mask);
+		edac_dbg(3, "MC%d: first(0x%lx) page(0x%lx) last(0x%lx) mask(0x%lx)\n",
+			 mci->mc_idx,
+			 csrow->first_page, page, csrow->last_page,
+			 csrow->page_mask);
 
 		if ((page >= csrow->first_page) &&
 		    (page <= csrow->last_page) &&
@@ -845,15 +897,16 @@ const char *edac_layer_name[] = {
 EXPORT_SYMBOL_GPL(edac_layer_name);
 
 static void edac_inc_ce_error(struct mem_ctl_info *mci,
-				    bool enable_per_layer_report,
-				    const int pos[EDAC_MAX_LAYERS])
+			      bool enable_per_layer_report,
+			      const int pos[EDAC_MAX_LAYERS],
+			      const u16 count)
 {
 	int i, index = 0;
 
-	mci->ce_mc++;
+	mci->ce_mc += count;
 
 	if (!enable_per_layer_report) {
-		mci->ce_noinfo_count++;
+		mci->ce_noinfo_count += count;
 		return;
 	}
 
@@ -861,7 +914,7 @@ static void edac_inc_ce_error(struct mem_ctl_info *mci,
 		if (pos[i] < 0)
 			break;
 		index += pos[i];
-		mci->ce_per_layer[i][index]++;
+		mci->ce_per_layer[i][index] += count;
 
 		if (i < mci->n_layers - 1)
 			index *= mci->layers[i + 1].size;
@@ -870,14 +923,15 @@ static void edac_inc_ce_error(struct mem_ctl_info *mci,
 
 static void edac_inc_ue_error(struct mem_ctl_info *mci,
 				    bool enable_per_layer_report,
-				    const int pos[EDAC_MAX_LAYERS])
+				    const int pos[EDAC_MAX_LAYERS],
+				    const u16 count)
 {
 	int i, index = 0;
 
-	mci->ue_mc++;
+	mci->ue_mc += count;
 
 	if (!enable_per_layer_report) {
-		mci->ce_noinfo_count++;
+		mci->ce_noinfo_count += count;
 		return;
 	}
 
@@ -885,7 +939,7 @@ static void edac_inc_ue_error(struct mem_ctl_info *mci,
 		if (pos[i] < 0)
 			break;
 		index += pos[i];
-		mci->ue_per_layer[i][index]++;
+		mci->ue_per_layer[i][index] += count;
 
 		if (i < mci->n_layers - 1)
 			index *= mci->layers[i + 1].size;
@@ -893,6 +947,7 @@ static void edac_inc_ue_error(struct mem_ctl_info *mci,
 }
 
 static void edac_ce_error(struct mem_ctl_info *mci,
+			  const u16 error_count,
 			  const int pos[EDAC_MAX_LAYERS],
 			  const char *msg,
 			  const char *location,
@@ -902,23 +957,25 @@ static void edac_ce_error(struct mem_ctl_info *mci,
 			  const bool enable_per_layer_report,
 			  const unsigned long page_frame_number,
 			  const unsigned long offset_in_page,
-			  u32 grain)
+			  long grain)
 {
 	unsigned long remapped_page;
 
 	if (edac_mc_get_log_ce()) {
 		if (other_detail && *other_detail)
 			edac_mc_printk(mci, KERN_WARNING,
-				       "CE %s on %s (%s%s - %s)\n",
+				       "%d CE %s on %s (%s %s - %s)\n",
+				       error_count,
 				       msg, label, location,
 				       detail, other_detail);
 		else
 			edac_mc_printk(mci, KERN_WARNING,
-				       "CE %s on %s (%s%s)\n",
+				       "%d CE %s on %s (%s %s)\n",
+				       error_count,
 				       msg, label, location,
 				       detail);
 	}
-	edac_inc_ce_error(mci, enable_per_layer_report, pos);
+	edac_inc_ce_error(mci, enable_per_layer_report, pos, error_count);
 
 	if (mci->scrub_mode & SCRUB_SW_SRC) {
 		/*
@@ -942,6 +999,7 @@ static void edac_ce_error(struct mem_ctl_info *mci,
 }
 
 static void edac_ue_error(struct mem_ctl_info *mci,
+			  const u16 error_count,
 			  const int pos[EDAC_MAX_LAYERS],
 			  const char *msg,
 			  const char *location,
@@ -953,12 +1011,14 @@ static void edac_ue_error(struct mem_ctl_info *mci,
 	if (edac_mc_get_log_ue()) {
 		if (other_detail && *other_detail)
 			edac_mc_printk(mci, KERN_WARNING,
-				       "UE %s on %s (%s%s - %s)\n",
+				       "%d UE %s on %s (%s %s - %s)\n",
+				       error_count,
 			               msg, label, location, detail,
 				       other_detail);
 		else
 			edac_mc_printk(mci, KERN_WARNING,
-				       "UE %s on %s (%s%s)\n",
+				       "%d UE %s on %s (%s %s)\n",
+				       error_count,
 			               msg, label, location, detail);
 	}
 
@@ -971,33 +1031,53 @@ static void edac_ue_error(struct mem_ctl_info *mci,
 			      msg, label, location, detail);
 	}
 
-	edac_inc_ue_error(mci, enable_per_layer_report, pos);
+	edac_inc_ue_error(mci, enable_per_layer_report, pos, error_count);
 }
 
 #define OTHER_LABEL " or "
+
+/**
+ * edac_mc_handle_error - reports a memory event to userspace
+ *
+ * @type:		severity of the error (CE/UE/Fatal)
+ * @mci:		a struct mem_ctl_info pointer
+ * @error_count:	Number of errors of the same type
+ * @page_frame_number:	mem page where the error occurred
+ * @offset_in_page:	offset of the error inside the page
+ * @syndrome:		ECC syndrome
+ * @top_layer:		Memory layer[0] position
+ * @mid_layer:		Memory layer[1] position
+ * @low_layer:		Memory layer[2] position
+ * @msg:		Message meaningful to the end users that
+ *			explains the event
+ * @other_detail:	Technical details about the event that
+ *			may help hardware manufacturers and
+ *			EDAC developers to analyse the event
+ */
 void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  struct mem_ctl_info *mci,
+			  const u16 error_count,
 			  const unsigned long page_frame_number,
 			  const unsigned long offset_in_page,
 			  const unsigned long syndrome,
-			  const int layer0,
-			  const int layer1,
-			  const int layer2,
+			  const int top_layer,
+			  const int mid_layer,
+			  const int low_layer,
 			  const char *msg,
-			  const char *other_detail,
-			  const void *mcelog)
+			  const char *other_detail)
 {
 	/* FIXME: too much for stack: move it to some pre-alocated area */
 	char detail[80], location[80];
 	char label[(EDAC_MC_LABEL_LEN + 1 + sizeof(OTHER_LABEL)) * mci->tot_dimms];
 	char *p;
 	int row = -1, chan = -1;
-	int pos[EDAC_MAX_LAYERS] = { layer0, layer1, layer2 };
+	int pos[EDAC_MAX_LAYERS] = { top_layer, mid_layer, low_layer };
 	int i;
-	u32 grain;
+	long grain;
 	bool enable_per_layer_report = false;
+	u8 grain_bits;
 
-	debugf3("MC%d: %s()\n", mci->mc_idx, __func__);
+	edac_dbg(3, "MC%d\n", mci->mc_idx);
 
 	/*
 	 * Check if the event report is consistent and if the memory
@@ -1043,13 +1123,13 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 	p = label;
 	*p = '\0';
 	for (i = 0; i < mci->tot_dimms; i++) {
-		struct dimm_info *dimm = &mci->dimms[i];
+		struct dimm_info *dimm = mci->dimms[i];
 
-		if (layer0 >= 0 && layer0 != dimm->location[0])
+		if (top_layer >= 0 && top_layer != dimm->location[0])
 			continue;
-		if (layer1 >= 0 && layer1 != dimm->location[1])
+		if (mid_layer >= 0 && mid_layer != dimm->location[1])
 			continue;
-		if (layer2 >= 0 && layer2 != dimm->location[2])
+		if (low_layer >= 0 && low_layer != dimm->location[2])
 			continue;
 
 		/* get the max grain, over the error match range */
@@ -1075,11 +1155,9 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			 * get csrow/channel of the DIMM, in order to allow
 			 * incrementing the compat API counters
 			 */
-			debugf4("%s: %s csrows map: (%d,%d)\n",
-				__func__,
-				mci->mem_is_per_rank ? "rank" : "dimm",
-				dimm->csrow, dimm->cschannel);
-
+			edac_dbg(4, "%s csrows map: (%d,%d)\n",
+				 mci->mem_is_per_rank ? "rank" : "dimm",
+				 dimm->csrow, dimm->cschannel);
 			if (row == -1)
 				row = dimm->csrow;
 			else if (row >= 0 && row != dimm->csrow)
@@ -1095,19 +1173,18 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 	if (!enable_per_layer_report) {
 		strcpy(label, "any memory");
 	} else {
-		debugf4("%s: csrow/channel to increment: (%d,%d)\n",
-			__func__, row, chan);
+		edac_dbg(4, "csrow/channel to increment: (%d,%d)\n", row, chan);
 		if (p == label)
 			strcpy(label, "unknown memory");
 		if (type == HW_EVENT_ERR_CORRECTED) {
 			if (row >= 0) {
-				mci->csrows[row].ce_count++;
+				mci->csrows[row]->ce_count += error_count;
 				if (chan >= 0)
-					mci->csrows[row].channels[chan].ce_count++;
+					mci->csrows[row]->channels[chan]->ce_count += error_count;
 			}
 		} else
 			if (row >= 0)
-				mci->csrows[row].ue_count++;
+				mci->csrows[row]->ue_count += error_count;
 	}
 
 	/* Fill the RAM location data */
@@ -1120,23 +1197,33 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			     edac_layer_name[mci->layers[i].type],
 			     pos[i]);
 	}
+	if (p > location)
+		*(p - 1) = '\0';
+
+	/* Report the error via the trace interface */
+
+	grain_bits = fls_long(grain) + 1;
+	trace_mc_event(type, msg, label, error_count,
+		       mci->mc_idx, top_layer, mid_layer, low_layer,
+		       PAGES_TO_MiB(page_frame_number) | offset_in_page,
+		       grain_bits, syndrome, other_detail);
 
 	/* Memory type dependent details about the error */
 	if (type == HW_EVENT_ERR_CORRECTED) {
 		snprintf(detail, sizeof(detail),
-			"page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx",
+			"page:0x%lx offset:0x%lx grain:%ld syndrome:0x%lx",
 			page_frame_number, offset_in_page,
 			grain, syndrome);
-		edac_ce_error(mci, pos, msg, location, label, detail,
-			      other_detail, enable_per_layer_report,
+		edac_ce_error(mci, error_count, pos, msg, location, label,
+			      detail, other_detail, enable_per_layer_report,
 			      page_frame_number, offset_in_page, grain);
 	} else {
 		snprintf(detail, sizeof(detail),
-			"page:0x%lx offset:0x%lx grain:%d",
+			"page:0x%lx offset:0x%lx grain:%ld",
 			page_frame_number, offset_in_page, grain);
 
-		edac_ue_error(mci, pos, msg, location, label, detail,
-			      other_detail, enable_per_layer_report);
+		edac_ue_error(mci, error_count, pos, msg, location, label,
+			      detail, other_detail, enable_per_layer_report);
 	}
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index f6a29b0..ed0bc07 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -7,17 +7,21 @@
  *
  * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
  *
+ * (c) 2012 - Mauro Carvalho Chehab <mchehab@redhat.com>
+ *	The entire API were re-written, and ported to use struct device
+ *
  */
 
 #include <linux/ctype.h>
 #include <linux/slab.h>
 #include <linux/edac.h>
 #include <linux/bug.h>
+#include <linux/pm_runtime.h>
+#include <linux/uaccess.h>
 
 #include "edac_core.h"
 #include "edac_module.h"
 
-
 /* MC EDAC Controls, setable by module parameter, and sysfs */
 static int edac_mc_log_ue = 1;
 static int edac_mc_log_ce = 1;
@@ -78,6 +82,8 @@ module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int,
 		  &edac_mc_poll_msec, 0644);
 MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
 
+static struct device *mci_pdev;
+
 /*
  * various constants for Memory Controllers
  */
@@ -125,317 +131,526 @@ static const char *edac_caps[] = {
 	[EDAC_S16ECD16ED] = "S16ECD16ED"
 };
 
-/* EDAC sysfs CSROW data structures and methods
+#ifdef CONFIG_EDAC_LEGACY_SYSFS
+/*
+ * EDAC sysfs CSROW data structures and methods
+ */
+
+#define to_csrow(k) container_of(k, struct csrow_info, dev)
+
+/*
+ * We need it to avoid namespace conflicts between the legacy API
+ * and the per-dimm/per-rank one
  */
+#define DEVICE_ATTR_LEGACY(_name, _mode, _show, _store) \
+	struct device_attribute dev_attr_legacy_##_name = __ATTR(_name, _mode, _show, _store)
+
+struct dev_ch_attribute {
+	struct device_attribute attr;
+	int channel;
+};
+
+#define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \
+	struct dev_ch_attribute dev_attr_legacy_##_name = \
+		{ __ATTR(_name, _mode, _show, _store), (_var) }
+
+#define to_channel(k) (container_of(k, struct dev_ch_attribute, attr)->channel)
 
 /* Set of more default csrow<id> attribute show/store functions */
-static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data,
-				int private)
+static ssize_t csrow_ue_count_show(struct device *dev,
+				   struct device_attribute *mattr, char *data)
 {
+	struct csrow_info *csrow = to_csrow(dev);
+
 	return sprintf(data, "%u\n", csrow->ue_count);
 }
 
-static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data,
-				int private)
+static ssize_t csrow_ce_count_show(struct device *dev,
+				   struct device_attribute *mattr, char *data)
 {
+	struct csrow_info *csrow = to_csrow(dev);
+
 	return sprintf(data, "%u\n", csrow->ce_count);
 }
 
-static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
-				int private)
+static ssize_t csrow_size_show(struct device *dev,
+			       struct device_attribute *mattr, char *data)
 {
+	struct csrow_info *csrow = to_csrow(dev);
 	int i;
 	u32 nr_pages = 0;
 
 	for (i = 0; i < csrow->nr_channels; i++)
-		nr_pages += csrow->channels[i].dimm->nr_pages;
-
+		nr_pages += csrow->channels[i]->dimm->nr_pages;
 	return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages));
 }
 
-static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data,
-				int private)
+static ssize_t csrow_mem_type_show(struct device *dev,
+				   struct device_attribute *mattr, char *data)
 {
-	return sprintf(data, "%s\n", mem_types[csrow->channels[0].dimm->mtype]);
+	struct csrow_info *csrow = to_csrow(dev);
+
+	return sprintf(data, "%s\n", mem_types[csrow->channels[0]->dimm->mtype]);
 }
 
-static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data,
-				int private)
+static ssize_t csrow_dev_type_show(struct device *dev,
+				   struct device_attribute *mattr, char *data)
 {
-	return sprintf(data, "%s\n", dev_types[csrow->channels[0].dimm->dtype]);
+	struct csrow_info *csrow = to_csrow(dev);
+
+	return sprintf(data, "%s\n", dev_types[csrow->channels[0]->dimm->dtype]);
 }
 
-static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data,
-				int private)
+static ssize_t csrow_edac_mode_show(struct device *dev,
+				    struct device_attribute *mattr,
+				    char *data)
 {
-	return sprintf(data, "%s\n", edac_caps[csrow->channels[0].dimm->edac_mode]);
+	struct csrow_info *csrow = to_csrow(dev);
+
+	return sprintf(data, "%s\n", edac_caps[csrow->channels[0]->dimm->edac_mode]);
 }
 
 /* show/store functions for DIMM Label attributes */
-static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
-				char *data, int channel)
+static ssize_t channel_dimm_label_show(struct device *dev,
+				       struct device_attribute *mattr,
+				       char *data)
 {
+	struct csrow_info *csrow = to_csrow(dev);
+	unsigned chan = to_channel(mattr);
+	struct rank_info *rank = csrow->channels[chan];
+
 	/* if field has not been initialized, there is nothing to send */
-	if (!csrow->channels[channel].dimm->label[0])
+	if (!rank->dimm->label[0])
 		return 0;
 
 	return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n",
-			csrow->channels[channel].dimm->label);
+			rank->dimm->label);
 }
 
-static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
-					const char *data,
-					size_t count, int channel)
+static ssize_t channel_dimm_label_store(struct device *dev,
+					struct device_attribute *mattr,
+					const char *data, size_t count)
 {
+	struct csrow_info *csrow = to_csrow(dev);
+	unsigned chan = to_channel(mattr);
+	struct rank_info *rank = csrow->channels[chan];
+
 	ssize_t max_size = 0;
 
 	max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
-	strncpy(csrow->channels[channel].dimm->label, data, max_size);
-	csrow->channels[channel].dimm->label[max_size] = '\0';
+	strncpy(rank->dimm->label, data, max_size);
+	rank->dimm->label[max_size] = '\0';
 
 	return max_size;
 }
 
 /* show function for dynamic chX_ce_count attribute */
-static ssize_t channel_ce_count_show(struct csrow_info *csrow,
-				char *data, int channel)
+static ssize_t channel_ce_count_show(struct device *dev,
+				     struct device_attribute *mattr, char *data)
 {
-	return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
+	struct csrow_info *csrow = to_csrow(dev);
+	unsigned chan = to_channel(mattr);
+	struct rank_info *rank = csrow->channels[chan];
+
+	return sprintf(data, "%u\n", rank->ce_count);
 }
 
-/* csrow specific attribute structure */
-struct csrowdev_attribute {
-	struct attribute attr;
-	 ssize_t(*show) (struct csrow_info *, char *, int);
-	 ssize_t(*store) (struct csrow_info *, const char *, size_t, int);
-	int private;
-};
+/* cwrow<id>/attribute files */
+DEVICE_ATTR_LEGACY(size_mb, S_IRUGO, csrow_size_show, NULL);
+DEVICE_ATTR_LEGACY(dev_type, S_IRUGO, csrow_dev_type_show, NULL);
+DEVICE_ATTR_LEGACY(mem_type, S_IRUGO, csrow_mem_type_show, NULL);
+DEVICE_ATTR_LEGACY(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL);
+DEVICE_ATTR_LEGACY(ue_count, S_IRUGO, csrow_ue_count_show, NULL);
+DEVICE_ATTR_LEGACY(ce_count, S_IRUGO, csrow_ce_count_show, NULL);
 
-#define to_csrow(k) container_of(k, struct csrow_info, kobj)
-#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
+/* default attributes of the CSROW<id> object */
+static struct attribute *csrow_attrs[] = {
+	&dev_attr_legacy_dev_type.attr,
+	&dev_attr_legacy_mem_type.attr,
+	&dev_attr_legacy_edac_mode.attr,
+	&dev_attr_legacy_size_mb.attr,
+	&dev_attr_legacy_ue_count.attr,
+	&dev_attr_legacy_ce_count.attr,
+	NULL,
+};
 
-/* Set of show/store higher level functions for default csrow attributes */
-static ssize_t csrowdev_show(struct kobject *kobj,
-			struct attribute *attr, char *buffer)
-{
-	struct csrow_info *csrow = to_csrow(kobj);
-	struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
+static struct attribute_group csrow_attr_grp = {
+	.attrs	= csrow_attrs,
+};
 
-	if (csrowdev_attr->show)
-		return csrowdev_attr->show(csrow,
-					buffer, csrowdev_attr->private);
-	return -EIO;
-}
+static const struct attribute_group *csrow_attr_groups[] = {
+	&csrow_attr_grp,
+	NULL
+};
 
-static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
-			const char *buffer, size_t count)
+static void csrow_attr_release(struct device *dev)
 {
-	struct csrow_info *csrow = to_csrow(kobj);
-	struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
-
-	if (csrowdev_attr->store)
-		return csrowdev_attr->store(csrow,
-					buffer,
-					count, csrowdev_attr->private);
-	return -EIO;
-}
+	struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
 
-static const struct sysfs_ops csrowfs_ops = {
-	.show = csrowdev_show,
-	.store = csrowdev_store
-};
+	edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev));
+	kfree(csrow);
+}
 
-#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private)	\
-static struct csrowdev_attribute attr_##_name = {			\
-	.attr = {.name = __stringify(_name), .mode = _mode },	\
-	.show   = _show,					\
-	.store  = _store,					\
-	.private = _private,					\
+static struct device_type csrow_attr_type = {
+	.groups		= csrow_attr_groups,
+	.release	= csrow_attr_release,
 };
 
-/* default cwrow<id>/attribute files */
-CSROWDEV_ATTR(size_mb, S_IRUGO, csrow_size_show, NULL, 0);
-CSROWDEV_ATTR(dev_type, S_IRUGO, csrow_dev_type_show, NULL, 0);
-CSROWDEV_ATTR(mem_type, S_IRUGO, csrow_mem_type_show, NULL, 0);
-CSROWDEV_ATTR(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL, 0);
-CSROWDEV_ATTR(ue_count, S_IRUGO, csrow_ue_count_show, NULL, 0);
-CSROWDEV_ATTR(ce_count, S_IRUGO, csrow_ce_count_show, NULL, 0);
+/*
+ * possible dynamic channel DIMM Label attribute files
+ *
+ */
 
-/* default attributes of the CSROW<id> object */
-static struct csrowdev_attribute *default_csrow_attr[] = {
-	&attr_dev_type,
-	&attr_mem_type,
-	&attr_edac_mode,
-	&attr_size_mb,
-	&attr_ue_count,
-	&attr_ce_count,
-	NULL,
-};
+#define EDAC_NR_CHANNELS	6
 
-/* possible dynamic channel DIMM Label attribute files */
-CSROWDEV_ATTR(ch0_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
 	channel_dimm_label_show, channel_dimm_label_store, 0);
-CSROWDEV_ATTR(ch1_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
 	channel_dimm_label_show, channel_dimm_label_store, 1);
-CSROWDEV_ATTR(ch2_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch2_dimm_label, S_IRUGO | S_IWUSR,
 	channel_dimm_label_show, channel_dimm_label_store, 2);
-CSROWDEV_ATTR(ch3_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch3_dimm_label, S_IRUGO | S_IWUSR,
 	channel_dimm_label_show, channel_dimm_label_store, 3);
-CSROWDEV_ATTR(ch4_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch4_dimm_label, S_IRUGO | S_IWUSR,
 	channel_dimm_label_show, channel_dimm_label_store, 4);
-CSROWDEV_ATTR(ch5_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
 	channel_dimm_label_show, channel_dimm_label_store, 5);
 
 /* Total possible dynamic DIMM Label attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
-	&attr_ch0_dimm_label,
-	&attr_ch1_dimm_label,
-	&attr_ch2_dimm_label,
-	&attr_ch3_dimm_label,
-	&attr_ch4_dimm_label,
-	&attr_ch5_dimm_label
+static struct device_attribute *dynamic_csrow_dimm_attr[] = {
+	&dev_attr_legacy_ch0_dimm_label.attr,
+	&dev_attr_legacy_ch1_dimm_label.attr,
+	&dev_attr_legacy_ch2_dimm_label.attr,
+	&dev_attr_legacy_ch3_dimm_label.attr,
+	&dev_attr_legacy_ch4_dimm_label.attr,
+	&dev_attr_legacy_ch5_dimm_label.attr
 };
 
 /* possible dynamic channel ce_count attribute files */
-CSROWDEV_ATTR(ch0_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 0);
-CSROWDEV_ATTR(ch1_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 1);
-CSROWDEV_ATTR(ch2_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 2);
-CSROWDEV_ATTR(ch3_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 3);
-CSROWDEV_ATTR(ch4_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 4);
-CSROWDEV_ATTR(ch5_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 5);
+DEVICE_CHANNEL(ch0_ce_count, S_IRUGO | S_IWUSR,
+		   channel_ce_count_show, NULL, 0);
+DEVICE_CHANNEL(ch1_ce_count, S_IRUGO | S_IWUSR,
+		   channel_ce_count_show, NULL, 1);
+DEVICE_CHANNEL(ch2_ce_count, S_IRUGO | S_IWUSR,
+		   channel_ce_count_show, NULL, 2);
+DEVICE_CHANNEL(ch3_ce_count, S_IRUGO | S_IWUSR,
+		   channel_ce_count_show, NULL, 3);
+DEVICE_CHANNEL(ch4_ce_count, S_IRUGO | S_IWUSR,
+		   channel_ce_count_show, NULL, 4);
+DEVICE_CHANNEL(ch5_ce_count, S_IRUGO | S_IWUSR,
+		   channel_ce_count_show, NULL, 5);
 
 /* Total possible dynamic ce_count attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
-	&attr_ch0_ce_count,
-	&attr_ch1_ce_count,
-	&attr_ch2_ce_count,
-	&attr_ch3_ce_count,
-	&attr_ch4_ce_count,
-	&attr_ch5_ce_count
+static struct device_attribute *dynamic_csrow_ce_count_attr[] = {
+	&dev_attr_legacy_ch0_ce_count.attr,
+	&dev_attr_legacy_ch1_ce_count.attr,
+	&dev_attr_legacy_ch2_ce_count.attr,
+	&dev_attr_legacy_ch3_ce_count.attr,
+	&dev_attr_legacy_ch4_ce_count.attr,
+	&dev_attr_legacy_ch5_ce_count.attr
 };
 
-#define EDAC_NR_CHANNELS	6
+static inline int nr_pages_per_csrow(struct csrow_info *csrow)
+{
+	int chan, nr_pages = 0;
+
+	for (chan = 0; chan < csrow->nr_channels; chan++)
+		nr_pages += csrow->channels[chan]->dimm->nr_pages;
+
+	return nr_pages;
+}
 
-/* Create dynamic CHANNEL files, indexed by 'chan',  under specifed CSROW */
-static int edac_create_channel_files(struct kobject *kobj, int chan)
+/* Create a CSROW object under specifed edac_mc_device */
+static int edac_create_csrow_object(struct mem_ctl_info *mci,
+				    struct csrow_info *csrow, int index)
 {
-	int err = -ENODEV;
+	int err, chan;
+
+	if (csrow->nr_channels >= EDAC_NR_CHANNELS)
+		return -ENODEV;
+
+	csrow->dev.type = &csrow_attr_type;
+	csrow->dev.bus = &mci->bus;
+	device_initialize(&csrow->dev);
+	csrow->dev.parent = &mci->dev;
+	dev_set_name(&csrow->dev, "csrow%d", index);
+	dev_set_drvdata(&csrow->dev, csrow);
 
-	if (chan >= EDAC_NR_CHANNELS)
+	edac_dbg(0, "creating (virtual) csrow node %s\n",
+		 dev_name(&csrow->dev));
+
+	err = device_add(&csrow->dev);
+	if (err < 0)
 		return err;
 
-	/* create the DIMM label attribute file */
-	err = sysfs_create_file(kobj,
-				(struct attribute *)
-				dynamic_csrow_dimm_attr[chan]);
-
-	if (!err) {
-		/* create the CE Count attribute file */
-		err = sysfs_create_file(kobj,
-					(struct attribute *)
-					dynamic_csrow_ce_count_attr[chan]);
-	} else {
-		debugf1("%s()  dimm labels and ce_count files created",
-			__func__);
+	for (chan = 0; chan < csrow->nr_channels; chan++) {
+		/* Only expose populated DIMMs */
+		if (!csrow->channels[chan]->dimm->nr_pages)
+			continue;
+		err = device_create_file(&csrow->dev,
+					 dynamic_csrow_dimm_attr[chan]);
+		if (err < 0)
+			goto error;
+		err = device_create_file(&csrow->dev,
+					 dynamic_csrow_ce_count_attr[chan]);
+		if (err < 0) {
+			device_remove_file(&csrow->dev,
+					   dynamic_csrow_dimm_attr[chan]);
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	for (--chan; chan >= 0; chan--) {
+		device_remove_file(&csrow->dev,
+					dynamic_csrow_dimm_attr[chan]);
+		device_remove_file(&csrow->dev,
+					   dynamic_csrow_ce_count_attr[chan]);
 	}
+	put_device(&csrow->dev);
 
 	return err;
 }
 
-/* No memory to release for this kobj */
-static void edac_csrow_instance_release(struct kobject *kobj)
+/* Create a CSROW object under specifed edac_mc_device */
+static int edac_create_csrow_objects(struct mem_ctl_info *mci)
 {
-	struct mem_ctl_info *mci;
-	struct csrow_info *cs;
+	int err, i, chan;
+	struct csrow_info *csrow;
+
+	for (i = 0; i < mci->nr_csrows; i++) {
+		csrow = mci->csrows[i];
+		if (!nr_pages_per_csrow(csrow))
+			continue;
+		err = edac_create_csrow_object(mci, mci->csrows[i], i);
+		if (err < 0)
+			goto error;
+	}
+	return 0;
 
-	debugf1("%s()\n", __func__);
+error:
+	for (--i; i >= 0; i--) {
+		csrow = mci->csrows[i];
+		if (!nr_pages_per_csrow(csrow))
+			continue;
+		for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
+			if (!csrow->channels[chan]->dimm->nr_pages)
+				continue;
+			device_remove_file(&csrow->dev,
+						dynamic_csrow_dimm_attr[chan]);
+			device_remove_file(&csrow->dev,
+						dynamic_csrow_ce_count_attr[chan]);
+		}
+		put_device(&mci->csrows[i]->dev);
+	}
 
-	cs = container_of(kobj, struct csrow_info, kobj);
-	mci = cs->mci;
+	return err;
+}
 
-	kobject_put(&mci->edac_mci_kobj);
+static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
+{
+	int i, chan;
+	struct csrow_info *csrow;
+
+	for (i = mci->nr_csrows - 1; i >= 0; i--) {
+		csrow = mci->csrows[i];
+		if (!nr_pages_per_csrow(csrow))
+			continue;
+		for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
+			if (!csrow->channels[chan]->dimm->nr_pages)
+				continue;
+			edac_dbg(1, "Removing csrow %d channel %d sysfs nodes\n",
+				 i, chan);
+			device_remove_file(&csrow->dev,
+						dynamic_csrow_dimm_attr[chan]);
+			device_remove_file(&csrow->dev,
+						dynamic_csrow_ce_count_attr[chan]);
+		}
+		put_device(&mci->csrows[i]->dev);
+		device_del(&mci->csrows[i]->dev);
+	}
 }
+#endif
 
-/* the kobj_type instance for a CSROW */
-static struct kobj_type ktype_csrow = {
-	.release = edac_csrow_instance_release,
-	.sysfs_ops = &csrowfs_ops,
-	.default_attrs = (struct attribute **)default_csrow_attr,
+/*
+ * Per-dimm (or per-rank) devices
+ */
+
+#define to_dimm(k) container_of(k, struct dimm_info, dev)
+
+/* show/store functions for DIMM Label attributes */
+static ssize_t dimmdev_location_show(struct device *dev,
+				     struct device_attribute *mattr, char *data)
+{
+	struct dimm_info *dimm = to_dimm(dev);
+
+	return edac_dimm_info_location(dimm, data, PAGE_SIZE);
+}
+
+static ssize_t dimmdev_label_show(struct device *dev,
+				  struct device_attribute *mattr, char *data)
+{
+	struct dimm_info *dimm = to_dimm(dev);
+
+	/* if field has not been initialized, there is nothing to send */
+	if (!dimm->label[0])
+		return 0;
+
+	return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", dimm->label);
+}
+
+static ssize_t dimmdev_label_store(struct device *dev,
+				   struct device_attribute *mattr,
+				   const char *data,
+				   size_t count)
+{
+	struct dimm_info *dimm = to_dimm(dev);
+
+	ssize_t max_size = 0;
+
+	max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
+	strncpy(dimm->label, data, max_size);
+	dimm->label[max_size] = '\0';
+
+	return max_size;
+}
+
+static ssize_t dimmdev_size_show(struct device *dev,
+				 struct device_attribute *mattr, char *data)
+{
+	struct dimm_info *dimm = to_dimm(dev);
+
+	return sprintf(data, "%u\n", PAGES_TO_MiB(dimm->nr_pages));
+}
+
+static ssize_t dimmdev_mem_type_show(struct device *dev,
+				     struct device_attribute *mattr, char *data)
+{
+	struct dimm_info *dimm = to_dimm(dev);
+
+	return sprintf(data, "%s\n", mem_types[dimm->mtype]);
+}
+
+static ssize_t dimmdev_dev_type_show(struct device *dev,
+				     struct device_attribute *mattr, char *data)
+{
+	struct dimm_info *dimm = to_dimm(dev);
+
+	return sprintf(data, "%s\n", dev_types[dimm->dtype]);
+}
+
+static ssize_t dimmdev_edac_mode_show(struct device *dev,
+				      struct device_attribute *mattr,
+				      char *data)
+{
+	struct dimm_info *dimm = to_dimm(dev);
+
+	return sprintf(data, "%s\n", edac_caps[dimm->edac_mode]);
+}
+
+/* dimm/rank attribute files */
+static DEVICE_ATTR(dimm_label, S_IRUGO | S_IWUSR,
+		   dimmdev_label_show, dimmdev_label_store);
+static DEVICE_ATTR(dimm_location, S_IRUGO, dimmdev_location_show, NULL);
+static DEVICE_ATTR(size, S_IRUGO, dimmdev_size_show, NULL);
+static DEVICE_ATTR(dimm_mem_type, S_IRUGO, dimmdev_mem_type_show, NULL);
+static DEVICE_ATTR(dimm_dev_type, S_IRUGO, dimmdev_dev_type_show, NULL);
+static DEVICE_ATTR(dimm_edac_mode, S_IRUGO, dimmdev_edac_mode_show, NULL);
+
+/* attributes of the dimm<id>/rank<id> object */
+static struct attribute *dimm_attrs[] = {
+	&dev_attr_dimm_label.attr,
+	&dev_attr_dimm_location.attr,
+	&dev_attr_size.attr,
+	&dev_attr_dimm_mem_type.attr,
+	&dev_attr_dimm_dev_type.attr,
+	&dev_attr_dimm_edac_mode.attr,
+	NULL,
 };
 
-/* Create a CSROW object under specifed edac_mc_device */
-static int edac_create_csrow_object(struct mem_ctl_info *mci,
-					struct csrow_info *csrow, int index)
+static struct attribute_group dimm_attr_grp = {
+	.attrs	= dimm_attrs,
+};
+
+static const struct attribute_group *dimm_attr_groups[] = {
+	&dimm_attr_grp,
+	NULL
+};
+
+static void dimm_attr_release(struct device *dev)
 {
-	struct kobject *kobj_mci = &mci->edac_mci_kobj;
-	struct kobject *kobj;
-	int chan;
-	int err;
+	struct dimm_info *dimm = container_of(dev, struct dimm_info, dev);
 
-	/* generate ..../edac/mc/mc<id>/csrow<index>   */
-	memset(&csrow->kobj, 0, sizeof(csrow->kobj));
-	csrow->mci = mci;	/* include container up link */
+	edac_dbg(1, "Releasing dimm device %s\n", dev_name(dev));
+	kfree(dimm);
+}
 
-	/* bump the mci instance's kobject's ref count */
-	kobj = kobject_get(&mci->edac_mci_kobj);
-	if (!kobj) {
-		err = -ENODEV;
-		goto err_out;
-	}
+static struct device_type dimm_attr_type = {
+	.groups		= dimm_attr_groups,
+	.release	= dimm_attr_release,
+};
+
+/* Create a DIMM object under specifed memory controller device */
+static int edac_create_dimm_object(struct mem_ctl_info *mci,
+				   struct dimm_info *dimm,
+				   int index)
+{
+	int err;
+	dimm->mci = mci;
 
-	/* Instanstiate the csrow object */
-	err = kobject_init_and_add(&csrow->kobj, &ktype_csrow, kobj_mci,
-				   "csrow%d", index);
-	if (err)
-		goto err_release_top_kobj;
+	dimm->dev.type = &dimm_attr_type;
+	dimm->dev.bus = &mci->bus;
+	device_initialize(&dimm->dev);
 
-	/* At this point, to release a csrow kobj, one must
-	 * call the kobject_put and allow that tear down
-	 * to work the releasing
-	 */
+	dimm->dev.parent = &mci->dev;
+	if (mci->mem_is_per_rank)
+		dev_set_name(&dimm->dev, "rank%d", index);
+	else
+		dev_set_name(&dimm->dev, "dimm%d", index);
+	dev_set_drvdata(&dimm->dev, dimm);
+	pm_runtime_forbid(&mci->dev);
 
-	/* Create the dyanmic attribute files on this csrow,
-	 * namely, the DIMM labels and the channel ce_count
-	 */
-	for (chan = 0; chan < csrow->nr_channels; chan++) {
-		err = edac_create_channel_files(&csrow->kobj, chan);
-		if (err) {
-			/* special case the unregister here */
-			kobject_put(&csrow->kobj);
-			goto err_out;
-		}
-	}
-	kobject_uevent(&csrow->kobj, KOBJ_ADD);
-	return 0;
+	err =  device_add(&dimm->dev);
 
-	/* error unwind stack */
-err_release_top_kobj:
-	kobject_put(&mci->edac_mci_kobj);
+	edac_dbg(0, "creating rank/dimm device %s\n", dev_name(&dimm->dev));
 
-err_out:
 	return err;
 }
 
-/* default sysfs methods and data structures for the main MCI kobject */
+/*
+ * Memory controller device
+ */
+
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
 
-static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
+static ssize_t mci_reset_counters_store(struct device *dev,
+					struct device_attribute *mattr,
 					const char *data, size_t count)
 {
-	int row, chan;
-
-	mci->ue_noinfo_count = 0;
-	mci->ce_noinfo_count = 0;
+	struct mem_ctl_info *mci = to_mci(dev);
+	int cnt, row, chan, i;
 	mci->ue_mc = 0;
 	mci->ce_mc = 0;
+	mci->ue_noinfo_count = 0;
+	mci->ce_noinfo_count = 0;
 
 	for (row = 0; row < mci->nr_csrows; row++) {
-		struct csrow_info *ri = &mci->csrows[row];
+		struct csrow_info *ri = mci->csrows[row];
 
 		ri->ue_count = 0;
 		ri->ce_count = 0;
 
 		for (chan = 0; chan < ri->nr_channels; chan++)
-			ri->channels[chan].ce_count = 0;
+			ri->channels[chan]->ce_count = 0;
+	}
+
+	cnt = 1;
+	for (i = 0; i < mci->n_layers; i++) {
+		cnt *= mci->layers[i].size;
+		memset(mci->ce_per_layer[i], 0, cnt * sizeof(u32));
+		memset(mci->ue_per_layer[i], 0, cnt * sizeof(u32));
 	}
 
 	mci->start_time = jiffies;
@@ -451,9 +666,11 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
  * Negative value still means that an error has occurred while setting
  * the scrub rate.
  */
-static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
+static ssize_t mci_sdram_scrub_rate_store(struct device *dev,
+					  struct device_attribute *mattr,
 					  const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	unsigned long bandwidth = 0;
 	int new_bw = 0;
 
@@ -476,8 +693,11 @@ static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
 /*
  * ->get_sdram_scrub_rate() return value semantics same as above.
  */
-static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_sdram_scrub_rate_show(struct device *dev,
+					 struct device_attribute *mattr,
+					 char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	int bandwidth = 0;
 
 	if (!mci->get_sdram_scrub_rate)
@@ -493,45 +713,72 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
 }
 
 /* default attribute files for the MCI object */
-static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_ue_count_show(struct device *dev,
+				 struct device_attribute *mattr,
+				 char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
+
 	return sprintf(data, "%d\n", mci->ue_mc);
 }
 
-static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_ce_count_show(struct device *dev,
+				 struct device_attribute *mattr,
+				 char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
+
 	return sprintf(data, "%d\n", mci->ce_mc);
 }
 
-static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_ce_noinfo_show(struct device *dev,
+				  struct device_attribute *mattr,
+				  char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
+
 	return sprintf(data, "%d\n", mci->ce_noinfo_count);
 }
 
-static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_ue_noinfo_show(struct device *dev,
+				  struct device_attribute *mattr,
+				  char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
+
 	return sprintf(data, "%d\n", mci->ue_noinfo_count);
 }
 
-static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_seconds_show(struct device *dev,
+				struct device_attribute *mattr,
+				char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
+
 	return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);
 }
 
-static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_ctl_name_show(struct device *dev,
+				 struct device_attribute *mattr,
+				 char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
+
 	return sprintf(data, "%s\n", mci->ctl_name);
 }
 
-static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_size_mb_show(struct device *dev,
+				struct device_attribute *mattr,
+				char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	int total_pages = 0, csrow_idx, j;
 
 	for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) {
-		struct csrow_info *csrow = &mci->csrows[csrow_idx];
+		struct csrow_info *csrow = mci->csrows[csrow_idx];
 
 		for (j = 0; j < csrow->nr_channels; j++) {
-			struct dimm_info *dimm = csrow->channels[j].dimm;
+			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
 			total_pages += dimm->nr_pages;
 		}
@@ -540,361 +787,187 @@ static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
 	return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
 }
 
-#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
-#define to_mcidev_attr(a) container_of(a,struct mcidev_sysfs_attribute,attr)
-
-/* MCI show/store functions for top most object */
-static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
-			char *buffer)
+static ssize_t mci_max_location_show(struct device *dev,
+				     struct device_attribute *mattr,
+				     char *data)
 {
-	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
-	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
-
-	debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+	struct mem_ctl_info *mci = to_mci(dev);
+	int i;
+	char *p = data;
 
-	if (mcidev_attr->show)
-		return mcidev_attr->show(mem_ctl_info, buffer);
+	for (i = 0; i < mci->n_layers; i++) {
+		p += sprintf(p, "%s %d ",
+			     edac_layer_name[mci->layers[i].type],
+			     mci->layers[i].size - 1);
+	}
 
-	return -EIO;
+	return p - data;
 }
 
-static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
-			const char *buffer, size_t count)
+#ifdef CONFIG_EDAC_DEBUG
+static ssize_t edac_fake_inject_write(struct file *file,
+				      const char __user *data,
+				      size_t count, loff_t *ppos)
 {
-	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
-	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
-
-	debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
-
-	if (mcidev_attr->store)
-		return mcidev_attr->store(mem_ctl_info, buffer, count);
+	struct device *dev = file->private_data;
+	struct mem_ctl_info *mci = to_mci(dev);
+	static enum hw_event_mc_err_type type;
+	u16 errcount = mci->fake_inject_count;
+
+	if (!errcount)
+		errcount = 1;
+
+	type = mci->fake_inject_ue ? HW_EVENT_ERR_UNCORRECTED
+				   : HW_EVENT_ERR_CORRECTED;
+
+	printk(KERN_DEBUG
+	       "Generating %d %s fake error%s to %d.%d.%d to test core handling. NOTE: this won't test the driver-specific decoding logic.\n",
+		errcount,
+		(type == HW_EVENT_ERR_UNCORRECTED) ? "UE" : "CE",
+		errcount > 1 ? "s" : "",
+		mci->fake_inject_layer[0],
+		mci->fake_inject_layer[1],
+		mci->fake_inject_layer[2]
+	       );
+	edac_mc_handle_error(type, mci, errcount, 0, 0, 0,
+			     mci->fake_inject_layer[0],
+			     mci->fake_inject_layer[1],
+			     mci->fake_inject_layer[2],
+			     "FAKE ERROR", "for EDAC testing only");
 
-	return -EIO;
+	return count;
 }
 
-/* Intermediate show/store table */
-static const struct sysfs_ops mci_ops = {
-	.show = mcidev_show,
-	.store = mcidev_store
-};
+static int debugfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
 
-#define MCIDEV_ATTR(_name,_mode,_show,_store)			\
-static struct mcidev_sysfs_attribute mci_attr_##_name = {			\
-	.attr = {.name = __stringify(_name), .mode = _mode },	\
-	.show   = _show,					\
-	.store  = _store,					\
+static const struct file_operations debug_fake_inject_fops = {
+	.open = debugfs_open,
+	.write = edac_fake_inject_write,
+	.llseek = generic_file_llseek,
 };
+#endif
 
 /* default Control file */
-MCIDEV_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
+DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
 
 /* default Attribute files */
-MCIDEV_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
-MCIDEV_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
-MCIDEV_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
-MCIDEV_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
-MCIDEV_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
-MCIDEV_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
-MCIDEV_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
+DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
+DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
+DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
+DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
+DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
+DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
+DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
+DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL);
 
 /* memory scrubber attribute file */
-MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
+DEVICE_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
 	mci_sdram_scrub_rate_store);
 
-static struct mcidev_sysfs_attribute *mci_attr[] = {
-	&mci_attr_reset_counters,
-	&mci_attr_mc_name,
-	&mci_attr_size_mb,
-	&mci_attr_seconds_since_reset,
-	&mci_attr_ue_noinfo_count,
-	&mci_attr_ce_noinfo_count,
-	&mci_attr_ue_count,
-	&mci_attr_ce_count,
-	&mci_attr_sdram_scrub_rate,
+static struct attribute *mci_attrs[] = {
+	&dev_attr_reset_counters.attr,
+	&dev_attr_mc_name.attr,
+	&dev_attr_size_mb.attr,
+	&dev_attr_seconds_since_reset.attr,
+	&dev_attr_ue_noinfo_count.attr,
+	&dev_attr_ce_noinfo_count.attr,
+	&dev_attr_ue_count.attr,
+	&dev_attr_ce_count.attr,
+	&dev_attr_sdram_scrub_rate.attr,
+	&dev_attr_max_location.attr,
 	NULL
 };
 
+static struct attribute_group mci_attr_grp = {
+	.attrs	= mci_attrs,
+};
 
-/*
- * Release of a MC controlling instance
- *
- *	each MC control instance has the following resources upon entry:
- *		a) a ref count on the top memctl kobj
- *		b) a ref count on this module
- *
- *	this function must decrement those ref counts and then
- *	issue a free on the instance's memory
- */
-static void edac_mci_control_release(struct kobject *kobj)
-{
-	struct mem_ctl_info *mci;
-
-	mci = to_mci(kobj);
+static const struct attribute_group *mci_attr_groups[] = {
+	&mci_attr_grp,
+	NULL
+};
 
-	debugf0("%s() mci instance idx=%d releasing\n", __func__, mci->mc_idx);
+static void mci_attr_release(struct device *dev)
+{
+	struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev);
 
-	/* decrement the module ref count */
-	module_put(mci->owner);
+	edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev));
+	kfree(mci);
 }
 
-static struct kobj_type ktype_mci = {
-	.release = edac_mci_control_release,
-	.sysfs_ops = &mci_ops,
-	.default_attrs = (struct attribute **)mci_attr,
+static struct device_type mci_attr_type = {
+	.groups		= mci_attr_groups,
+	.release	= mci_attr_release,
 };
 
-/* EDAC memory controller sysfs kset:
- *	/sys/devices/system/edac/mc
- */
-static struct kset *mc_kset;
+#ifdef CONFIG_EDAC_DEBUG
+static struct dentry *edac_debugfs;
 
-/*
- * edac_mc_register_sysfs_main_kobj
- *
- *	setups and registers the main kobject for each mci
- */
-int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
+int __init edac_debugfs_init(void)
 {
-	struct kobject *kobj_mci;
-	int err;
-
-	debugf1("%s()\n", __func__);
-
-	kobj_mci = &mci->edac_mci_kobj;
-
-	/* Init the mci's kobject */
-	memset(kobj_mci, 0, sizeof(*kobj_mci));
-
-	/* Record which module 'owns' this control structure
-	 * and bump the ref count of the module
-	 */
-	mci->owner = THIS_MODULE;
-
-	/* bump ref count on this module */
-	if (!try_module_get(mci->owner)) {
-		err = -ENODEV;
-		goto fail_out;
-	}
-
-	/* this instance become part of the mc_kset */
-	kobj_mci->kset = mc_kset;
-
-	/* register the mc<id> kobject to the mc_kset */
-	err = kobject_init_and_add(kobj_mci, &ktype_mci, NULL,
-				   "mc%d", mci->mc_idx);
-	if (err) {
-		debugf1("%s()Failed to register '.../edac/mc%d'\n",
-			__func__, mci->mc_idx);
-		goto kobj_reg_fail;
+	edac_debugfs = debugfs_create_dir("edac", NULL);
+	if (IS_ERR(edac_debugfs)) {
+		edac_debugfs = NULL;
+		return -ENOMEM;
 	}
-	kobject_uevent(kobj_mci, KOBJ_ADD);
-
-	/* At this point, to 'free' the control struct,
-	 * edac_mc_unregister_sysfs_main_kobj() must be used
-	 */
-
-	debugf1("%s() Registered '.../edac/mc%d' kobject\n",
-		__func__, mci->mc_idx);
-
 	return 0;
-
-	/* Error exit stack */
-
-kobj_reg_fail:
-	module_put(mci->owner);
-
-fail_out:
-	return err;
-}
-
-/*
- * edac_mc_register_sysfs_main_kobj
- *
- *	tears down and the main mci kobject from the mc_kset
- */
-void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
-{
-	debugf1("%s()\n", __func__);
-
-	/* delete the kobj from the mc_kset */
-	kobject_put(&mci->edac_mci_kobj);
-}
-
-#define EDAC_DEVICE_SYMLINK	"device"
-
-#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group_kobj, kobj)->mci)
-
-/* MCI show/store functions for top most object */
-static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr,
-			char *buffer)
-{
-	struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
-	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
-
-	debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
-
-	if (mcidev_attr->show)
-		return mcidev_attr->show(mem_ctl_info, buffer);
-
-	return -EIO;
 }
 
-static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr,
-			const char *buffer, size_t count)
+void __exit edac_debugfs_exit(void)
 {
-	struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
-	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
-
-	debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
-
-	if (mcidev_attr->store)
-		return mcidev_attr->store(mem_ctl_info, buffer, count);
-
-	return -EIO;
+	debugfs_remove(edac_debugfs);
 }
 
-/* No memory to release for this kobj */
-static void edac_inst_grp_release(struct kobject *kobj)
+int edac_create_debug_nodes(struct mem_ctl_info *mci)
 {
-	struct mcidev_sysfs_group_kobj *grp;
-	struct mem_ctl_info *mci;
-
-	debugf1("%s()\n", __func__);
-
-	grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
-	mci = grp->mci;
-}
-
-/* Intermediate show/store table */
-static struct sysfs_ops inst_grp_ops = {
-	.show = inst_grp_show,
-	.store = inst_grp_store
-};
-
-/* the kobj_type instance for a instance group */
-static struct kobj_type ktype_inst_grp = {
-	.release = edac_inst_grp_release,
-	.sysfs_ops = &inst_grp_ops,
-};
-
+	struct dentry *d, *parent;
+	char name[80];
+	int i;
 
-/*
- * edac_create_mci_instance_attributes
- *	create MC driver specific attributes bellow an specified kobj
- * This routine calls itself recursively, in order to create an entire
- * object tree.
- */
-static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
-				const struct mcidev_sysfs_attribute *sysfs_attrib,
-				struct kobject *kobj)
-{
-	int err;
+	if (!edac_debugfs)
+		return -ENODEV;
 
-	debugf4("%s()\n", __func__);
-
-	while (sysfs_attrib) {
-		debugf4("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
-		if (sysfs_attrib->grp) {
-			struct mcidev_sysfs_group_kobj *grp_kobj;
-
-			grp_kobj = kzalloc(sizeof(*grp_kobj), GFP_KERNEL);
-			if (!grp_kobj)
-				return -ENOMEM;
-
-			grp_kobj->grp = sysfs_attrib->grp;
-			grp_kobj->mci = mci;
-			list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
-
-			debugf0("%s() grp %s, mci %p\n", __func__,
-				sysfs_attrib->grp->name, mci);
-
-			err = kobject_init_and_add(&grp_kobj->kobj,
-						&ktype_inst_grp,
-						&mci->edac_mci_kobj,
-						sysfs_attrib->grp->name);
-			if (err < 0) {
-				printk(KERN_ERR "kobject_init_and_add failed: %d\n", err);
-				return err;
-			}
-			err = edac_create_mci_instance_attributes(mci,
-					grp_kobj->grp->mcidev_attr,
-					&grp_kobj->kobj);
-
-			if (err < 0)
-				return err;
-		} else if (sysfs_attrib->attr.name) {
-			debugf4("%s() file %s\n", __func__,
-				sysfs_attrib->attr.name);
-
-			err = sysfs_create_file(kobj, &sysfs_attrib->attr);
-			if (err < 0) {
-				printk(KERN_ERR "sysfs_create_file failed: %d\n", err);
-				return err;
-			}
-		} else
-			break;
-
-		sysfs_attrib++;
+	d = debugfs_create_dir(mci->dev.kobj.name, edac_debugfs);
+	if (!d)
+		return -ENOMEM;
+	parent = d;
+
+	for (i = 0; i < mci->n_layers; i++) {
+		sprintf(name, "fake_inject_%s",
+			     edac_layer_name[mci->layers[i].type]);
+		d = debugfs_create_u8(name, S_IRUGO | S_IWUSR, parent,
+				      &mci->fake_inject_layer[i]);
+		if (!d)
+			goto nomem;
 	}
 
-	return 0;
-}
+	d = debugfs_create_bool("fake_inject_ue", S_IRUGO | S_IWUSR, parent,
+				&mci->fake_inject_ue);
+	if (!d)
+		goto nomem;
 
-/*
- * edac_remove_mci_instance_attributes
- *	remove MC driver specific attributes at the topmost level
- *	directory of this mci instance.
- */
-static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
-				const struct mcidev_sysfs_attribute *sysfs_attrib,
-				struct kobject *kobj, int count)
-{
-	struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
+	d = debugfs_create_u16("fake_inject_count", S_IRUGO | S_IWUSR, parent,
+				&mci->fake_inject_count);
+	if (!d)
+		goto nomem;
 
-	debugf1("%s()\n", __func__);
-
-	/*
-	 * loop if there are attributes and until we hit a NULL entry
-	 * Remove first all the attributes
-	 */
-	while (sysfs_attrib) {
-		debugf4("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
-		if (sysfs_attrib->grp) {
-			debugf4("%s() seeking for group %s\n",
-				__func__, sysfs_attrib->grp->name);
-			list_for_each_entry(grp_kobj,
-					    &mci->grp_kobj_list, list) {
-				debugf4("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp);
-				if (grp_kobj->grp == sysfs_attrib->grp) {
-					edac_remove_mci_instance_attributes(mci,
-						    grp_kobj->grp->mcidev_attr,
-						    &grp_kobj->kobj, count + 1);
-					debugf4("%s() group %s\n", __func__,
-						sysfs_attrib->grp->name);
-					kobject_put(&grp_kobj->kobj);
-				}
-			}
-			debugf4("%s() end of seeking for group %s\n",
-				__func__, sysfs_attrib->grp->name);
-		} else if (sysfs_attrib->attr.name) {
-			debugf4("%s() file %s\n", __func__,
-				sysfs_attrib->attr.name);
-			sysfs_remove_file(kobj, &sysfs_attrib->attr);
-		} else
-			break;
-		sysfs_attrib++;
-	}
+	d = debugfs_create_file("fake_inject", S_IWUSR, parent,
+				&mci->dev,
+				&debug_fake_inject_fops);
+	if (!d)
+		goto nomem;
 
-	/* Remove the group objects */
-	if (count)
-		return;
-	list_for_each_entry_safe(grp_kobj, tmp,
-				 &mci->grp_kobj_list, list) {
-		list_del(&grp_kobj->list);
-		kfree(grp_kobj);
-	}
+	mci->debugfs = parent;
+	return 0;
+nomem:
+	debugfs_remove(mci->debugfs);
+	return -ENOMEM;
 }
-
+#endif
 
 /*
  * Create a new Memory Controller kobject instance,
@@ -906,77 +979,87 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
  */
 int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
 {
-	int i, j;
-	int err;
-	struct csrow_info *csrow;
-	struct kobject *kobj_mci = &mci->edac_mci_kobj;
+	int i, err;
 
-	debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
-
-	INIT_LIST_HEAD(&mci->grp_kobj_list);
+	/*
+	 * The memory controller needs its own bus, in order to avoid
+	 * namespace conflicts at /sys/bus/edac.
+	 */
+	mci->bus.name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
+	if (!mci->bus.name)
+		return -ENOMEM;
+	edac_dbg(0, "creating bus %s\n", mci->bus.name);
+	err = bus_register(&mci->bus);
+	if (err < 0)
+		return err;
 
-	/* create a symlink for the device */
-	err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
-				EDAC_DEVICE_SYMLINK);
-	if (err) {
-		debugf1("%s() failure to create symlink\n", __func__);
-		goto fail0;
+	/* get the /sys/devices/system/edac subsys reference */
+	mci->dev.type = &mci_attr_type;
+	device_initialize(&mci->dev);
+
+	mci->dev.parent = mci_pdev;
+	mci->dev.bus = &mci->bus;
+	dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
+	dev_set_drvdata(&mci->dev, mci);
+	pm_runtime_forbid(&mci->dev);
+
+	edac_dbg(0, "creating device %s\n", dev_name(&mci->dev));
+	err = device_add(&mci->dev);
+	if (err < 0) {
+		bus_unregister(&mci->bus);
+		kfree(mci->bus.name);
+		return err;
 	}
 
-	/* If the low level driver desires some attributes,
-	 * then create them now for the driver.
+	/*
+	 * Create the dimm/rank devices
 	 */
-	if (mci->mc_driver_sysfs_attributes) {
-		err = edac_create_mci_instance_attributes(mci,
-					mci->mc_driver_sysfs_attributes,
-					&mci->edac_mci_kobj);
+	for (i = 0; i < mci->tot_dimms; i++) {
+		struct dimm_info *dimm = mci->dimms[i];
+		/* Only expose populated DIMMs */
+		if (dimm->nr_pages == 0)
+			continue;
+#ifdef CONFIG_EDAC_DEBUG
+		edac_dbg(1, "creating dimm%d, located at ", i);
+		if (edac_debug_level >= 1) {
+			int lay;
+			for (lay = 0; lay < mci->n_layers; lay++)
+				printk(KERN_CONT "%s %d ",
+					edac_layer_name[mci->layers[lay].type],
+					dimm->location[lay]);
+			printk(KERN_CONT "\n");
+		}
+#endif
+		err = edac_create_dimm_object(mci, dimm, i);
 		if (err) {
-			debugf1("%s() failure to create mci attributes\n",
-				__func__);
-			goto fail0;
+			edac_dbg(1, "failure: create dimm %d obj\n", i);
+			goto fail;
 		}
 	}
 
-	/* Make directories for each CSROW object under the mc<id> kobject
-	 */
-	for (i = 0; i < mci->nr_csrows; i++) {
-		int nr_pages = 0;
-
-		csrow = &mci->csrows[i];
-		for (j = 0; j < csrow->nr_channels; j++)
-			nr_pages += csrow->channels[j].dimm->nr_pages;
-
-		if (nr_pages > 0) {
-			err = edac_create_csrow_object(mci, csrow, i);
-			if (err) {
-				debugf1("%s() failure: create csrow %d obj\n",
-					__func__, i);
-				goto fail1;
-			}
-		}
-	}
+#ifdef CONFIG_EDAC_LEGACY_SYSFS
+	err = edac_create_csrow_objects(mci);
+	if (err < 0)
+		goto fail;
+#endif
 
+#ifdef CONFIG_EDAC_DEBUG
+	edac_create_debug_nodes(mci);
+#endif
 	return 0;
 
-fail1:
+fail:
 	for (i--; i >= 0; i--) {
-		int nr_pages = 0;
-
-		csrow = &mci->csrows[i];
-		for (j = 0; j < csrow->nr_channels; j++)
-			nr_pages += csrow->channels[j].dimm->nr_pages;
-		if (nr_pages > 0)
-			kobject_put(&mci->csrows[i].kobj);
+		struct dimm_info *dimm = mci->dimms[i];
+		if (dimm->nr_pages == 0)
+			continue;
+		put_device(&dimm->dev);
+		device_del(&dimm->dev);
 	}
-
-	/* remove the mci instance's attributes, if any */
-	edac_remove_mci_instance_attributes(mci,
-		mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0);
-
-	/* remove the symlink */
-	sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
-
-fail0:
+	put_device(&mci->dev);
+	device_del(&mci->dev);
+	bus_unregister(&mci->bus);
+	kfree(mci->bus.name);
 	return err;
 }
 
@@ -985,98 +1068,84 @@ fail0:
  */
 void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
 {
-	struct csrow_info *csrow;
-	int i, j;
-
-	debugf0("%s()\n", __func__);
-
-	/* remove all csrow kobjects */
-	debugf4("%s()  unregister this mci kobj\n", __func__);
-	for (i = 0; i < mci->nr_csrows; i++) {
-		int nr_pages = 0;
-
-		csrow = &mci->csrows[i];
-		for (j = 0; j < csrow->nr_channels; j++)
-			nr_pages += csrow->channels[j].dimm->nr_pages;
-		if (nr_pages > 0) {
-			debugf0("%s()  unreg csrow-%d\n", __func__, i);
-			kobject_put(&mci->csrows[i].kobj);
-		}
-	}
+	int i;
 
-	/* remove this mci instance's attribtes */
-	if (mci->mc_driver_sysfs_attributes) {
-		debugf4("%s()  unregister mci private attributes\n", __func__);
-		edac_remove_mci_instance_attributes(mci,
-						mci->mc_driver_sysfs_attributes,
-						&mci->edac_mci_kobj, 0);
+	edac_dbg(0, "\n");
+
+#ifdef CONFIG_EDAC_DEBUG
+	debugfs_remove(mci->debugfs);
+#endif
+#ifdef CONFIG_EDAC_LEGACY_SYSFS
+	edac_delete_csrow_objects(mci);
+#endif
+
+	for (i = 0; i < mci->tot_dimms; i++) {
+		struct dimm_info *dimm = mci->dimms[i];
+		if (dimm->nr_pages == 0)
+			continue;
+		edac_dbg(0, "removing device %s\n", dev_name(&dimm->dev));
+		put_device(&dimm->dev);
+		device_del(&dimm->dev);
 	}
-
-	/* remove the symlink */
-	debugf4("%s()  remove_link\n", __func__);
-	sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
-
-	/* unregister this instance's kobject */
-	debugf4("%s()  remove_mci_instance\n", __func__);
-	kobject_put(&mci->edac_mci_kobj);
 }
 
+void edac_unregister_sysfs(struct mem_ctl_info *mci)
+{
+	edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
+	put_device(&mci->dev);
+	device_del(&mci->dev);
+	bus_unregister(&mci->bus);
+	kfree(mci->bus.name);
+}
 
+static void mc_attr_release(struct device *dev)
+{
+	/*
+	 * There's no container structure here, as this is just the mci
+	 * parent device, used to create the /sys/devices/mc sysfs node.
+	 * So, there are no attributes on it.
+	 */
+	edac_dbg(1, "Releasing device %s\n", dev_name(dev));
+	kfree(dev);
+}
 
-
+static struct device_type mc_attr_type = {
+	.release	= mc_attr_release,
+};
 /*
- * edac_setup_sysfs_mc_kset(void)
- *
- * Initialize the mc_kset for the 'mc' entry
- *	This requires creating the top 'mc' directory with a kset
- *	and its controls/attributes.
- *
- *	To this 'mc' kset, instance 'mci' will be grouped as children.
- *
- * Return:  0 SUCCESS
- *         !0 FAILURE error code
+ * Init/exit code for the module. Basically, creates/removes /sys/class/rc
  */
-int edac_sysfs_setup_mc_kset(void)
+int __init edac_mc_sysfs_init(void)
 {
-	int err = -EINVAL;
 	struct bus_type *edac_subsys;
-
-	debugf1("%s()\n", __func__);
+	int err;
 
 	/* get the /sys/devices/system/edac subsys reference */
 	edac_subsys = edac_get_sysfs_subsys();
 	if (edac_subsys == NULL) {
-		debugf1("%s() no edac_subsys error=%d\n", __func__, err);
-		goto fail_out;
+		edac_dbg(1, "no edac_subsys\n");
+		return -EINVAL;
 	}
 
-	/* Init the MC's kobject */
-	mc_kset = kset_create_and_add("mc", NULL, &edac_subsys->dev_root->kobj);
-	if (!mc_kset) {
-		err = -ENOMEM;
-		debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
-		goto fail_kset;
-	}
+	mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
 
-	debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);
+	mci_pdev->bus = edac_subsys;
+	mci_pdev->type = &mc_attr_type;
+	device_initialize(mci_pdev);
+	dev_set_name(mci_pdev, "mc");
 
-	return 0;
+	err = device_add(mci_pdev);
+	if (err < 0)
+		return err;
 
-fail_kset:
-	edac_put_sysfs_subsys();
+	edac_dbg(0, "device %s created\n", dev_name(mci_pdev));
 
-fail_out:
-	return err;
+	return 0;
 }
 
-/*
- * edac_sysfs_teardown_mc_kset
- *
- *	deconstruct the mc_ket for memory controllers
- */
-void edac_sysfs_teardown_mc_kset(void)
+void __exit edac_mc_sysfs_exit(void)
 {
-	kset_unregister(mc_kset);
+	put_device(mci_pdev);
+	device_del(mci_pdev);
 	edac_put_sysfs_subsys();
 }
-
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
index 5ddaa86..58a28d8 100644
--- a/drivers/edac/edac_module.c
+++ b/drivers/edac/edac_module.c
@@ -15,7 +15,7 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
-#define EDAC_VERSION "Ver: 2.1.0"
+#define EDAC_VERSION "Ver: 3.0.0"
 
 #ifdef CONFIG_EDAC_DEBUG
 /* Values of 0 to 4 will generate output */
@@ -90,26 +90,21 @@ static int __init edac_init(void)
 	 */
 	edac_pci_clear_parity_errors();
 
-	/*
-	 * now set up the mc_kset under the edac class object
-	 */
-	err = edac_sysfs_setup_mc_kset();
+	err = edac_mc_sysfs_init();
 	if (err)
 		goto error;
 
+	edac_debugfs_init();
+
 	/* Setup/Initialize the workq for this core */
 	err = edac_workqueue_setup();
 	if (err) {
 		edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
-		goto workq_fail;
+		goto error;
 	}
 
 	return 0;
 
-	/* Error teardown stack */
-workq_fail:
-	edac_sysfs_teardown_mc_kset();
-
 error:
 	return err;
 }
@@ -120,11 +115,12 @@ error:
  */
 static void __exit edac_exit(void)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* tear down the various subsystems */
 	edac_workqueue_teardown();
-	edac_sysfs_teardown_mc_kset();
+	edac_mc_sysfs_exit();
+	edac_debugfs_exit();
 }
 
 /*
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index 0ea7d14..3d139c6 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -19,12 +19,12 @@
  *
  * edac_mc objects
  */
-extern int edac_sysfs_setup_mc_kset(void);
-extern void edac_sysfs_teardown_mc_kset(void);
-extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci);
-extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
+	/* on edac_mc_sysfs.c */
+int edac_mc_sysfs_init(void);
+void edac_mc_sysfs_exit(void);
 extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
 extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
+void edac_unregister_sysfs(struct mem_ctl_info *mci);
 extern int edac_get_log_ue(void);
 extern int edac_get_log_ce(void);
 extern int edac_get_panic_on_ue(void);
@@ -34,6 +34,10 @@ extern int edac_mc_get_panic_on_ue(void);
 extern int edac_get_poll_msec(void);
 extern int edac_mc_get_poll_msec(void);
 
+unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
+				 unsigned len);
+
+	/* on edac_device.c */
 extern int edac_device_register_sysfs_main_kobj(
 				struct edac_device_ctl_info *edac_dev);
 extern void edac_device_unregister_sysfs_main_kobj(
@@ -53,6 +57,20 @@ extern void edac_mc_reset_delay_period(int value);
 extern void *edac_align_ptr(void **p, unsigned size, int n_elems);
 
 /*
+ * EDAC debugfs functions
+ */
+#ifdef CONFIG_EDAC_DEBUG
+int edac_debugfs_init(void);
+void edac_debugfs_exit(void);
+#else
+static inline int edac_debugfs_init(void)
+{
+	return -ENODEV;
+}
+static inline void edac_debugfs_exit(void) {}
+#endif
+
+/*
  * EDAC PCI functions
  */
 #ifdef	CONFIG_PCI
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
index f1ac866..ee87ef9 100644
--- a/drivers/edac/edac_pci.c
+++ b/drivers/edac/edac_pci.c
@@ -45,7 +45,7 @@ struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
 	void *p = NULL, *pvt;
 	unsigned int size;
 
-	debugf1("%s()\n", __func__);
+	edac_dbg(1, "\n");
 
 	pci = edac_align_ptr(&p, sizeof(*pci), 1);
 	pvt = edac_align_ptr(&p, 1, sz_pvt);
@@ -80,7 +80,7 @@ EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
  */
 void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)
 {
-	debugf1("%s()\n", __func__);
+	edac_dbg(1, "\n");
 
 	edac_pci_remove_sysfs(pci);
 }
@@ -97,7 +97,7 @@ static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev)
 	struct edac_pci_ctl_info *pci;
 	struct list_head *item;
 
-	debugf1("%s()\n", __func__);
+	edac_dbg(1, "\n");
 
 	list_for_each(item, &edac_pci_list) {
 		pci = list_entry(item, struct edac_pci_ctl_info, link);
@@ -122,7 +122,7 @@ static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
 	struct list_head *item, *insert_before;
 	struct edac_pci_ctl_info *rover;
 
-	debugf1("%s()\n", __func__);
+	edac_dbg(1, "\n");
 
 	insert_before = &edac_pci_list;
 
@@ -226,7 +226,7 @@ static void edac_pci_workq_function(struct work_struct *work_req)
 	int msec;
 	unsigned long delay;
 
-	debugf3("%s() checking\n", __func__);
+	edac_dbg(3, "checking\n");
 
 	mutex_lock(&edac_pci_ctls_mutex);
 
@@ -261,7 +261,7 @@ static void edac_pci_workq_function(struct work_struct *work_req)
 static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
 				 unsigned int msec)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
 	queue_delayed_work(edac_workqueue, &pci->work,
@@ -276,7 +276,7 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
 {
 	int status;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	status = cancel_delayed_work(&pci->work);
 	if (status == 0)
@@ -293,7 +293,7 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
 void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
 				 unsigned long value)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	edac_pci_workq_teardown(pci);
 
@@ -333,7 +333,7 @@ EXPORT_SYMBOL_GPL(edac_pci_alloc_index);
  */
 int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	pci->pci_idx = edac_idx;
 	pci->start_time = jiffies;
@@ -393,7 +393,7 @@ struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
 {
 	struct edac_pci_ctl_info *pci;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	mutex_lock(&edac_pci_ctls_mutex);
 
@@ -430,7 +430,7 @@ EXPORT_SYMBOL_GPL(edac_pci_del_device);
  */
 static void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
 {
-	debugf4("%s()\n", __func__);
+	edac_dbg(4, "\n");
 	edac_pci_do_parity_check();
 }
 
@@ -475,7 +475,7 @@ struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev,
 	pdata->edac_idx = edac_pci_idx++;
 
 	if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
-		debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+		edac_dbg(3, "failed edac_pci_add_device()\n");
 		edac_pci_free_ctl_info(pci);
 		return NULL;
 	}
@@ -491,7 +491,7 @@ EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl);
  */
 void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)
 {
-	debugf0("%s() pci mod=%s\n", __func__, pci->mod_name);
+	edac_dbg(0, "pci mod=%s\n", pci->mod_name);
 
 	edac_pci_del_device(pci->dev);
 	edac_pci_free_ctl_info(pci);
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
index 97f5064..e164c55 100644
--- a/drivers/edac/edac_pci_sysfs.c
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -78,7 +78,7 @@ static void edac_pci_instance_release(struct kobject *kobj)
 {
 	struct edac_pci_ctl_info *pci;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* Form pointer to containing struct, the pci control struct */
 	pci = to_instance(kobj);
@@ -161,7 +161,7 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
 	struct kobject *main_kobj;
 	int err;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* First bump the ref count on the top main kobj, which will
 	 * track the number of PCI instances we have, and thus nest
@@ -177,14 +177,13 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
 	err = kobject_init_and_add(&pci->kobj, &ktype_pci_instance,
 				   edac_pci_top_main_kobj, "pci%d", idx);
 	if (err != 0) {
-		debugf2("%s() failed to register instance pci%d\n",
-			__func__, idx);
+		edac_dbg(2, "failed to register instance pci%d\n", idx);
 		kobject_put(edac_pci_top_main_kobj);
 		goto error_out;
 	}
 
 	kobject_uevent(&pci->kobj, KOBJ_ADD);
-	debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);
+	edac_dbg(1, "Register instance 'pci%d' kobject\n", idx);
 
 	return 0;
 
@@ -201,7 +200,7 @@ error_out:
 static void edac_pci_unregister_sysfs_instance_kobj(
 			struct edac_pci_ctl_info *pci)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* Unregister the instance kobject and allow its release
 	 * function release the main reference count and then
@@ -317,7 +316,7 @@ static struct edac_pci_dev_attribute *edac_pci_attr[] = {
  */
 static void edac_pci_release_main_kobj(struct kobject *kobj)
 {
-	debugf0("%s() here to module_put(THIS_MODULE)\n", __func__);
+	edac_dbg(0, "here to module_put(THIS_MODULE)\n");
 
 	kfree(kobj);
 
@@ -345,7 +344,7 @@ static int edac_pci_main_kobj_setup(void)
 	int err;
 	struct bus_type *edac_subsys;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* check and count if we have already created the main kobject */
 	if (atomic_inc_return(&edac_pci_sysfs_refcount) != 1)
@@ -356,7 +355,7 @@ static int edac_pci_main_kobj_setup(void)
 	 */
 	edac_subsys = edac_get_sysfs_subsys();
 	if (edac_subsys == NULL) {
-		debugf1("%s() no edac_subsys\n", __func__);
+		edac_dbg(1, "no edac_subsys\n");
 		err = -ENODEV;
 		goto decrement_count_fail;
 	}
@@ -366,14 +365,14 @@ static int edac_pci_main_kobj_setup(void)
 	 * level main kobj for EDAC PCI
 	 */
 	if (!try_module_get(THIS_MODULE)) {
-		debugf1("%s() try_module_get() failed\n", __func__);
+		edac_dbg(1, "try_module_get() failed\n");
 		err = -ENODEV;
 		goto mod_get_fail;
 	}
 
 	edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
 	if (!edac_pci_top_main_kobj) {
-		debugf1("Failed to allocate\n");
+		edac_dbg(1, "Failed to allocate\n");
 		err = -ENOMEM;
 		goto kzalloc_fail;
 	}
@@ -383,7 +382,7 @@ static int edac_pci_main_kobj_setup(void)
 				   &ktype_edac_pci_main_kobj,
 				   &edac_subsys->dev_root->kobj, "pci");
 	if (err) {
-		debugf1("Failed to register '.../edac/pci'\n");
+		edac_dbg(1, "Failed to register '.../edac/pci'\n");
 		goto kobject_init_and_add_fail;
 	}
 
@@ -392,7 +391,7 @@ static int edac_pci_main_kobj_setup(void)
 	 * must be used, for resources to be cleaned up properly
 	 */
 	kobject_uevent(edac_pci_top_main_kobj, KOBJ_ADD);
-	debugf1("Registered '.../edac/pci' kobject\n");
+	edac_dbg(1, "Registered '.../edac/pci' kobject\n");
 
 	return 0;
 
@@ -421,15 +420,14 @@ decrement_count_fail:
  */
 static void edac_pci_main_kobj_teardown(void)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* Decrement the count and only if no more controller instances
 	 * are connected perform the unregisteration of the top level
 	 * main kobj
 	 */
 	if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
-		debugf0("%s() called kobject_put on main kobj\n",
-			__func__);
+		edac_dbg(0, "called kobject_put on main kobj\n");
 		kobject_put(edac_pci_top_main_kobj);
 	}
 	edac_put_sysfs_subsys();
@@ -446,7 +444,7 @@ int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)
 	int err;
 	struct kobject *edac_kobj = &pci->kobj;
 
-	debugf0("%s() idx=%d\n", __func__, pci->pci_idx);
+	edac_dbg(0, "idx=%d\n", pci->pci_idx);
 
 	/* create the top main EDAC PCI kobject, IF needed */
 	err = edac_pci_main_kobj_setup();
@@ -460,8 +458,7 @@ int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)
 
 	err = sysfs_create_link(edac_kobj, &pci->dev->kobj, EDAC_PCI_SYMLINK);
 	if (err) {
-		debugf0("%s() sysfs_create_link() returned err= %d\n",
-			__func__, err);
+		edac_dbg(0, "sysfs_create_link() returned err= %d\n", err);
 		goto symlink_fail;
 	}
 
@@ -484,7 +481,7 @@ unregister_cleanup:
  */
 void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)
 {
-	debugf0("%s() index=%d\n", __func__, pci->pci_idx);
+	edac_dbg(0, "index=%d\n", pci->pci_idx);
 
 	/* Remove the symlink */
 	sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK);
@@ -496,7 +493,7 @@ void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)
 	 * if this 'pci' is the last instance.
 	 * If it is, the main kobject will be unregistered as a result
 	 */
-	debugf0("%s() calling edac_pci_main_kobj_teardown()\n", __func__);
+	edac_dbg(0, "calling edac_pci_main_kobj_teardown()\n");
 	edac_pci_main_kobj_teardown();
 }
 
@@ -572,7 +569,7 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev)
 
 	local_irq_restore(flags);
 
-	debugf4("PCI STATUS= 0x%04x %s\n", status, dev_name(&dev->dev));
+	edac_dbg(4, "PCI STATUS= 0x%04x %s\n", status, dev_name(&dev->dev));
 
 	/* check the status reg for errors on boards NOT marked as broken
 	 * if broken, we cannot trust any of the status bits
@@ -603,13 +600,15 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev)
 	}
 
 
-	debugf4("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev_name(&dev->dev));
+	edac_dbg(4, "PCI HEADER TYPE= 0x%02x %s\n",
+		 header_type, dev_name(&dev->dev));
 
 	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
 		/* On bridges, need to examine secondary status register  */
 		status = get_pci_parity_status(dev, 1);
 
-		debugf4("PCI SEC_STATUS= 0x%04x %s\n", status, dev_name(&dev->dev));
+		edac_dbg(4, "PCI SEC_STATUS= 0x%04x %s\n",
+			 status, dev_name(&dev->dev));
 
 		/* check the secondary status reg for errors,
 		 * on NOT broken boards
@@ -671,7 +670,7 @@ void edac_pci_do_parity_check(void)
 {
 	int before_count;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
 	/* if policy has PCI check off, leave now */
 	if (!check_pci_errors)
diff --git a/drivers/edac/highbank_l2_edac.c b/drivers/edac/highbank_l2_edac.c
new file mode 100644
index 0000000..e599b00
--- /dev/null
+++ b/drivers/edac/highbank_l2_edac.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2011-2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define SR_CLR_SB_ECC_INTR	0x0
+#define SR_CLR_DB_ECC_INTR	0x4
+
+struct hb_l2_drvdata {
+	void __iomem *base;
+	int sb_irq;
+	int db_irq;
+};
+
+static irqreturn_t highbank_l2_err_handler(int irq, void *dev_id)
+{
+	struct edac_device_ctl_info *dci = dev_id;
+	struct hb_l2_drvdata *drvdata = dci->pvt_info;
+
+	if (irq == drvdata->sb_irq) {
+		writel(1, drvdata->base + SR_CLR_SB_ECC_INTR);
+		edac_device_handle_ce(dci, 0, 0, dci->ctl_name);
+	}
+	if (irq == drvdata->db_irq) {
+		writel(1, drvdata->base + SR_CLR_DB_ECC_INTR);
+		edac_device_handle_ue(dci, 0, 0, dci->ctl_name);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit highbank_l2_err_probe(struct platform_device *pdev)
+{
+	struct edac_device_ctl_info *dci;
+	struct hb_l2_drvdata *drvdata;
+	struct resource *r;
+	int res = 0;
+
+	dci = edac_device_alloc_ctl_info(sizeof(*drvdata), "cpu",
+		1, "L", 1, 2, NULL, 0, 0);
+	if (!dci)
+		return -ENOMEM;
+
+	drvdata = dci->pvt_info;
+	dci->dev = &pdev->dev;
+	platform_set_drvdata(pdev, dci);
+
+	if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
+		return -ENOMEM;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		dev_err(&pdev->dev, "Unable to get mem resource\n");
+		res = -ENODEV;
+		goto err;
+	}
+
+	if (!devm_request_mem_region(&pdev->dev, r->start,
+				     resource_size(r), dev_name(&pdev->dev))) {
+		dev_err(&pdev->dev, "Error while requesting mem region\n");
+		res = -EBUSY;
+		goto err;
+	}
+
+	drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+	if (!drvdata->base) {
+		dev_err(&pdev->dev, "Unable to map regs\n");
+		res = -ENOMEM;
+		goto err;
+	}
+
+	drvdata->db_irq = platform_get_irq(pdev, 0);
+	res = devm_request_irq(&pdev->dev, drvdata->db_irq,
+			       highbank_l2_err_handler,
+			       0, dev_name(&pdev->dev), dci);
+	if (res < 0)
+		goto err;
+
+	drvdata->sb_irq = platform_get_irq(pdev, 1);
+	res = devm_request_irq(&pdev->dev, drvdata->sb_irq,
+			       highbank_l2_err_handler,
+			       0, dev_name(&pdev->dev), dci);
+	if (res < 0)
+		goto err;
+
+	dci->mod_name = dev_name(&pdev->dev);
+	dci->dev_name = dev_name(&pdev->dev);
+
+	if (edac_device_add_device(dci))
+		goto err;
+
+	devres_close_group(&pdev->dev, NULL);
+	return 0;
+err:
+	devres_release_group(&pdev->dev, NULL);
+	edac_device_free_ctl_info(dci);
+	return res;
+}
+
+static int highbank_l2_err_remove(struct platform_device *pdev)
+{
+	struct edac_device_ctl_info *dci = platform_get_drvdata(pdev);
+
+	edac_device_del_device(&pdev->dev);
+	edac_device_free_ctl_info(dci);
+	return 0;
+}
+
+static const struct of_device_id hb_l2_err_of_match[] = {
+	{ .compatible = "calxeda,hb-sregs-l2-ecc", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, hb_l2_err_of_match);
+
+static struct platform_driver highbank_l2_edac_driver = {
+	.probe = highbank_l2_err_probe,
+	.remove = highbank_l2_err_remove,
+	.driver = {
+		.name = "hb_l2_edac",
+		.of_match_table = hb_l2_err_of_match,
+	},
+};
+
+module_platform_driver(highbank_l2_edac_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Calxeda, Inc.");
+MODULE_DESCRIPTION("EDAC Driver for Calxeda Highbank L2 Cache");
diff --git a/drivers/edac/highbank_mc_edac.c b/drivers/edac/highbank_mc_edac.c
new file mode 100644
index 0000000..d00dc0b
--- /dev/null
+++ b/drivers/edac/highbank_mc_edac.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2011-2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/uaccess.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+/* DDR Ctrlr Error Registers */
+#define HB_DDR_ECC_OPT			0x128
+#define HB_DDR_ECC_U_ERR_ADDR		0x130
+#define HB_DDR_ECC_U_ERR_STAT		0x134
+#define HB_DDR_ECC_U_ERR_DATAL		0x138
+#define HB_DDR_ECC_U_ERR_DATAH		0x13c
+#define HB_DDR_ECC_C_ERR_ADDR		0x140
+#define HB_DDR_ECC_C_ERR_STAT		0x144
+#define HB_DDR_ECC_C_ERR_DATAL		0x148
+#define HB_DDR_ECC_C_ERR_DATAH		0x14c
+#define HB_DDR_ECC_INT_STATUS		0x180
+#define HB_DDR_ECC_INT_ACK		0x184
+#define HB_DDR_ECC_U_ERR_ID		0x424
+#define HB_DDR_ECC_C_ERR_ID		0x428
+
+#define HB_DDR_ECC_INT_STAT_CE		0x8
+#define HB_DDR_ECC_INT_STAT_DOUBLE_CE	0x10
+#define HB_DDR_ECC_INT_STAT_UE		0x20
+#define HB_DDR_ECC_INT_STAT_DOUBLE_UE	0x40
+
+#define HB_DDR_ECC_OPT_MODE_MASK	0x3
+#define HB_DDR_ECC_OPT_FWC		0x100
+#define HB_DDR_ECC_OPT_XOR_SHIFT	16
+
+struct hb_mc_drvdata {
+	void __iomem *mc_vbase;
+};
+
+static irqreturn_t highbank_mc_err_handler(int irq, void *dev_id)
+{
+	struct mem_ctl_info *mci = dev_id;
+	struct hb_mc_drvdata *drvdata = mci->pvt_info;
+	u32 status, err_addr;
+
+	/* Read the interrupt status register */
+	status = readl(drvdata->mc_vbase + HB_DDR_ECC_INT_STATUS);
+
+	if (status & HB_DDR_ECC_INT_STAT_UE) {
+		err_addr = readl(drvdata->mc_vbase + HB_DDR_ECC_U_ERR_ADDR);
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
+				     err_addr >> PAGE_SHIFT,
+				     err_addr & ~PAGE_MASK, 0,
+				     0, 0, -1,
+				     mci->ctl_name, "");
+	}
+	if (status & HB_DDR_ECC_INT_STAT_CE) {
+		u32 syndrome = readl(drvdata->mc_vbase + HB_DDR_ECC_C_ERR_STAT);
+		syndrome = (syndrome >> 8) & 0xff;
+		err_addr = readl(drvdata->mc_vbase + HB_DDR_ECC_C_ERR_ADDR);
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
+				     err_addr >> PAGE_SHIFT,
+				     err_addr & ~PAGE_MASK, syndrome,
+				     0, 0, -1,
+				     mci->ctl_name, "");
+	}
+
+	/* clear the error, clears the interrupt */
+	writel(status, drvdata->mc_vbase + HB_DDR_ECC_INT_ACK);
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_EDAC_DEBUG
+static ssize_t highbank_mc_err_inject_write(struct file *file,
+				      const char __user *data,
+				      size_t count, loff_t *ppos)
+{
+	struct mem_ctl_info *mci = file->private_data;
+	struct hb_mc_drvdata *pdata = mci->pvt_info;
+	char buf[32];
+	size_t buf_size;
+	u32 reg;
+	u8 synd;
+
+	buf_size = min(count, (sizeof(buf)-1));
+	if (copy_from_user(buf, data, buf_size))
+		return -EFAULT;
+	buf[buf_size] = 0;
+
+	if (!kstrtou8(buf, 16, &synd)) {
+		reg = readl(pdata->mc_vbase + HB_DDR_ECC_OPT);
+		reg &= HB_DDR_ECC_OPT_MODE_MASK;
+		reg |= (synd << HB_DDR_ECC_OPT_XOR_SHIFT) | HB_DDR_ECC_OPT_FWC;
+		writel(reg, pdata->mc_vbase + HB_DDR_ECC_OPT);
+	}
+
+	return count;
+}
+
+static int debugfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations highbank_mc_debug_inject_fops = {
+	.open = debugfs_open,
+	.write = highbank_mc_err_inject_write,
+	.llseek = generic_file_llseek,
+};
+#endif
+
+static int __devinit highbank_mc_probe(struct platform_device *pdev)
+{
+	struct edac_mc_layer layers[2];
+	struct mem_ctl_info *mci;
+	struct hb_mc_drvdata *drvdata;
+	struct dimm_info *dimm;
+	struct resource *r;
+	u32 control;
+	int irq;
+	int res = 0;
+
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = 1;
+	layers[0].is_virt_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = 1;
+	layers[1].is_virt_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
+			    sizeof(struct hb_mc_drvdata));
+	if (!mci)
+		return -ENOMEM;
+
+	mci->pdev = &pdev->dev;
+	drvdata = mci->pvt_info;
+	platform_set_drvdata(pdev, mci);
+
+	if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
+		return -ENOMEM;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		dev_err(&pdev->dev, "Unable to get mem resource\n");
+		res = -ENODEV;
+		goto err;
+	}
+
+	if (!devm_request_mem_region(&pdev->dev, r->start,
+				     resource_size(r), dev_name(&pdev->dev))) {
+		dev_err(&pdev->dev, "Error while requesting mem region\n");
+		res = -EBUSY;
+		goto err;
+	}
+
+	drvdata->mc_vbase = devm_ioremap(&pdev->dev,
+					  r->start, resource_size(r));
+	if (!drvdata->mc_vbase) {
+		dev_err(&pdev->dev, "Unable to map regs\n");
+		res = -ENOMEM;
+		goto err;
+	}
+
+	control = readl(drvdata->mc_vbase + HB_DDR_ECC_OPT) & 0x3;
+	if (!control || (control == 0x2)) {
+		dev_err(&pdev->dev, "No ECC present, or ECC disabled\n");
+		res = -ENODEV;
+		goto err;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	res = devm_request_irq(&pdev->dev, irq, highbank_mc_err_handler,
+			       0, dev_name(&pdev->dev), mci);
+	if (res < 0) {
+		dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
+		goto err;
+	}
+
+	mci->mtype_cap = MEM_FLAG_DDR3;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+	mci->edac_cap = EDAC_FLAG_SECDED;
+	mci->mod_name = dev_name(&pdev->dev);
+	mci->mod_ver = "1";
+	mci->ctl_name = dev_name(&pdev->dev);
+	mci->scrub_mode = SCRUB_SW_SRC;
+
+	/* Only a single 4GB DIMM is supported */
+	dimm = *mci->dimms;
+	dimm->nr_pages = (~0UL >> PAGE_SHIFT) + 1;
+	dimm->grain = 8;
+	dimm->dtype = DEV_X8;
+	dimm->mtype = MEM_DDR3;
+	dimm->edac_mode = EDAC_SECDED;
+
+	res = edac_mc_add_mc(mci);
+	if (res < 0)
+		goto err;
+
+	if (mci->debugfs)
+		debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs,
+				    mci,
+				    &highbank_mc_debug_inject_fops);
+
+	devres_close_group(&pdev->dev, NULL);
+	return 0;
+err:
+	devres_release_group(&pdev->dev, NULL);
+	edac_mc_free(mci);
+	return res;
+}
+
+static int highbank_mc_remove(struct platform_device *pdev)
+{
+	struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+	edac_mc_del_mc(&pdev->dev);
+	edac_mc_free(mci);
+	return 0;
+}
+
+static const struct of_device_id hb_ddr_ctrl_of_match[] = {
+	{ .compatible = "calxeda,hb-ddr-ctrl", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, hb_ddr_ctrl_of_match);
+
+static struct platform_driver highbank_mc_edac_driver = {
+	.probe = highbank_mc_probe,
+	.remove = highbank_mc_remove,
+	.driver = {
+		.name = "hb_mc_edac",
+		.of_match_table = hb_ddr_ctrl_of_match,
+	},
+};
+
+module_platform_driver(highbank_mc_edac_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Calxeda, Inc.");
+MODULE_DESCRIPTION("EDAC Driver for Calxeda Highbank");
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
index 8ad1744..d3d19cc 100644
--- a/drivers/edac/i3000_edac.c
+++ b/drivers/edac/i3000_edac.c
@@ -194,7 +194,7 @@ static void i3000_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -236,7 +236,7 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
 	int row, multi_chan, channel;
 	unsigned long pfn, offset;
 
-	multi_chan = mci->csrows[0].nr_channels - 1;
+	multi_chan = mci->csrows[0]->nr_channels - 1;
 
 	if (!(info->errsts & I3000_ERRSTS_BITS))
 		return 0;
@@ -245,9 +245,9 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
 		return 1;
 
 	if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
 				     -1, -1, -1,
-				     "UE overwrote CE", "", NULL);
+				     "UE overwrote CE", "");
 		info->errsts = info->errsts2;
 	}
 
@@ -258,15 +258,15 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
 	row = edac_mc_find_csrow_by_page(mci, pfn);
 
 	if (info->errsts & I3000_ERRSTS_UE)
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 				     pfn, offset, 0,
 				     row, -1, -1,
-				     "i3000 UE", "", NULL);
+				     "i3000 UE", "");
 	else
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     pfn, offset, info->derrsyn,
 				     row, multi_chan ? channel : 0, -1,
-				     "i3000 CE", "", NULL);
+				     "i3000 CE", "");
 
 	return 1;
 }
@@ -275,7 +275,7 @@ static void i3000_check(struct mem_ctl_info *mci)
 {
 	struct i3000_error_info info;
 
-	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+	edac_dbg(1, "MC%d\n", mci->mc_idx);
 	i3000_get_error_info(mci, &info);
 	i3000_process_error_info(mci, &info, 1);
 }
@@ -322,7 +322,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 	unsigned long mchbar;
 	void __iomem *window;
 
-	debugf0("MC: %s()\n", __func__);
+	edac_dbg(0, "MC:\n");
 
 	pci_read_config_dword(pdev, I3000_MCHBAR, (u32 *) & mchbar);
 	mchbar &= I3000_MCHBAR_MASK;
@@ -366,9 +366,9 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 	if (!mci)
 		return -ENOMEM;
 
-	debugf3("MC: %s(): init mci\n", __func__);
+	edac_dbg(3, "MC: init mci\n");
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR2;
 
 	mci->edac_ctl_cap = EDAC_FLAG_SECDED;
@@ -393,14 +393,13 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 	for (last_cumul_size = i = 0; i < mci->nr_csrows; i++) {
 		u8 value;
 		u32 cumul_size;
-		struct csrow_info *csrow = &mci->csrows[i];
+		struct csrow_info *csrow = mci->csrows[i];
 
 		value = drb[i];
 		cumul_size = value << (I3000_DRB_SHIFT - PAGE_SHIFT);
 		if (interleaved)
 			cumul_size <<= 1;
-		debugf3("MC: %s(): (%d) cumul_size 0x%x\n",
-			__func__, i, cumul_size);
+		edac_dbg(3, "MC: (%d) cumul_size 0x%x\n", i, cumul_size);
 		if (cumul_size == last_cumul_size)
 			continue;
 
@@ -410,7 +409,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 		last_cumul_size = cumul_size;
 
 		for (j = 0; j < nr_channels; j++) {
-			struct dimm_info *dimm = csrow->channels[j].dimm;
+			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / nr_channels;
 			dimm->grain = I3000_DEAP_GRAIN;
@@ -429,7 +428,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 
 	rc = -ENODEV;
 	if (edac_mc_add_mc(mci)) {
-		debugf3("MC: %s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "MC: failed edac_mc_add_mc()\n");
 		goto fail;
 	}
 
@@ -445,7 +444,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 	}
 
 	/* get this far and it's successful */
-	debugf3("MC: %s(): success\n", __func__);
+	edac_dbg(3, "MC: success\n");
 	return 0;
 
 fail:
@@ -461,7 +460,7 @@ static int __devinit i3000_init_one(struct pci_dev *pdev,
 {
 	int rc;
 
-	debugf0("MC: %s()\n", __func__);
+	edac_dbg(0, "MC:\n");
 
 	if (pci_enable_device(pdev) < 0)
 		return -EIO;
@@ -477,7 +476,7 @@ static void __devexit i3000_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	if (i3000_pci)
 		edac_pci_release_generic_ctl(i3000_pci);
@@ -511,7 +510,7 @@ static int __init i3000_init(void)
 {
 	int pci_rc;
 
-	debugf3("MC: %s()\n", __func__);
+	edac_dbg(3, "MC:\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -525,14 +524,14 @@ static int __init i3000_init(void)
 		mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
 					PCI_DEVICE_ID_INTEL_3000_HB, NULL);
 		if (!mci_pdev) {
-			debugf0("i3000 pci_get_device fail\n");
+			edac_dbg(0, "i3000 pci_get_device fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
 
 		pci_rc = i3000_init_one(mci_pdev, i3000_pci_tbl);
 		if (pci_rc < 0) {
-			debugf0("i3000 init fail\n");
+			edac_dbg(0, "i3000 init fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
@@ -552,7 +551,7 @@ fail0:
 
 static void __exit i3000_exit(void)
 {
-	debugf3("MC: %s()\n", __func__);
+	edac_dbg(3, "MC:\n");
 
 	pci_unregister_driver(&i3000_driver);
 	if (!i3000_registered) {
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index bbe43ef..47180a0 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -110,10 +110,10 @@ static int how_many_channels(struct pci_dev *pdev)
 
 	pci_read_config_byte(pdev, I3200_CAPID0 + 8, &capid0_8b);
 	if (capid0_8b & 0x20) { /* check DCD: Dual Channel Disable */
-		debugf0("In single channel mode.\n");
+		edac_dbg(0, "In single channel mode\n");
 		return 1;
 	} else {
-		debugf0("In dual channel mode.\n");
+		edac_dbg(0, "In dual channel mode\n");
 		return 2;
 	}
 }
@@ -159,7 +159,7 @@ static void i3200_clear_error_info(struct mem_ctl_info *mci)
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * Clear any error bits.
@@ -176,7 +176,7 @@ static void i3200_get_and_clear_error_info(struct mem_ctl_info *mci,
 	struct i3200_priv *priv = mci->pvt_info;
 	void __iomem *window = priv->window;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -218,25 +218,25 @@ static void i3200_process_error_info(struct mem_ctl_info *mci,
 		return;
 
 	if ((info->errsts ^ info->errsts2) & I3200_ERRSTS_BITS) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-				     -1, -1, -1, "UE overwrote CE", "", NULL);
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
+				     -1, -1, -1, "UE overwrote CE", "");
 		info->errsts = info->errsts2;
 	}
 
 	for (channel = 0; channel < nr_channels; channel++) {
 		log = info->eccerrlog[channel];
 		if (log & I3200_ECCERRLOG_UE) {
-			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 					     0, 0, 0,
 					     eccerrlog_row(channel, log),
 					     -1, -1,
-					     "i3000 UE", "", NULL);
+					     "i3000 UE", "");
 		} else if (log & I3200_ECCERRLOG_CE) {
-			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 					     0, 0, eccerrlog_syndrome(log),
 					     eccerrlog_row(channel, log),
 					     -1, -1,
-					     "i3000 UE", "", NULL);
+					     "i3000 UE", "");
 		}
 	}
 }
@@ -245,7 +245,7 @@ static void i3200_check(struct mem_ctl_info *mci)
 {
 	struct i3200_error_info info;
 
-	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+	edac_dbg(1, "MC%d\n", mci->mc_idx);
 	i3200_get_and_clear_error_info(mci, &info);
 	i3200_process_error_info(mci, &info);
 }
@@ -332,7 +332,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 	void __iomem *window;
 	struct i3200_priv *priv;
 
-	debugf0("MC: %s()\n", __func__);
+	edac_dbg(0, "MC:\n");
 
 	window = i3200_map_mchbar(pdev);
 	if (!window)
@@ -352,9 +352,9 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 	if (!mci)
 		return -ENOMEM;
 
-	debugf3("MC: %s(): init mci\n", __func__);
+	edac_dbg(3, "MC: init mci\n");
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR2;
 
 	mci->edac_ctl_cap = EDAC_FLAG_SECDED;
@@ -379,7 +379,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 	 */
 	for (i = 0; i < mci->nr_csrows; i++) {
 		unsigned long nr_pages;
-		struct csrow_info *csrow = &mci->csrows[i];
+		struct csrow_info *csrow = mci->csrows[i];
 
 		nr_pages = drb_to_nr_pages(drbs, stacked,
 			i / I3200_RANKS_PER_CHANNEL,
@@ -389,7 +389,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 			continue;
 
 		for (j = 0; j < nr_channels; j++) {
-			struct dimm_info *dimm = csrow->channels[j].dimm;
+			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / nr_channels;
 			dimm->grain = nr_pages << PAGE_SHIFT;
@@ -403,12 +403,12 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 
 	rc = -ENODEV;
 	if (edac_mc_add_mc(mci)) {
-		debugf3("MC: %s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "MC: failed edac_mc_add_mc()\n");
 		goto fail;
 	}
 
 	/* get this far and it's successful */
-	debugf3("MC: %s(): success\n", __func__);
+	edac_dbg(3, "MC: success\n");
 	return 0;
 
 fail:
@@ -424,7 +424,7 @@ static int __devinit i3200_init_one(struct pci_dev *pdev,
 {
 	int rc;
 
-	debugf0("MC: %s()\n", __func__);
+	edac_dbg(0, "MC:\n");
 
 	if (pci_enable_device(pdev) < 0)
 		return -EIO;
@@ -441,7 +441,7 @@ static void __devexit i3200_remove_one(struct pci_dev *pdev)
 	struct mem_ctl_info *mci;
 	struct i3200_priv *priv;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	mci = edac_mc_del_mc(&pdev->dev);
 	if (!mci)
@@ -475,7 +475,7 @@ static int __init i3200_init(void)
 {
 	int pci_rc;
 
-	debugf3("MC: %s()\n", __func__);
+	edac_dbg(3, "MC:\n");
 
 	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
 	opstate_init();
@@ -489,14 +489,14 @@ static int __init i3200_init(void)
 		mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
 				PCI_DEVICE_ID_INTEL_3200_HB, NULL);
 		if (!mci_pdev) {
-			debugf0("i3200 pci_get_device fail\n");
+			edac_dbg(0, "i3200 pci_get_device fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
 
 		pci_rc = i3200_init_one(mci_pdev, i3200_pci_tbl);
 		if (pci_rc < 0) {
-			debugf0("i3200 init fail\n");
+			edac_dbg(0, "i3200 init fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
@@ -516,7 +516,7 @@ fail0:
 
 static void __exit i3200_exit(void)
 {
-	debugf3("MC: %s()\n", __func__);
+	edac_dbg(3, "MC:\n");
 
 	pci_unregister_driver(&i3200_driver);
 	if (!i3200_registered) {
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 11ea835..a5c33df 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -273,7 +273,7 @@
 #define CHANNELS_PER_BRANCH	2
 #define MAX_BRANCHES		2
 
-/* Defines to extract the vaious fields from the
+/* Defines to extract the various fields from the
  *	MTRx - Memory Technology Registers
  */
 #define MTR_DIMMS_PRESENT(mtr)		((mtr) & (0x1 << 8))
@@ -287,22 +287,6 @@
 #define MTR_DIMM_COLS(mtr)		((mtr) & 0x3)
 #define MTR_DIMM_COLS_ADDR_BITS(mtr)	(MTR_DIMM_COLS(mtr) + 10)
 
-#ifdef CONFIG_EDAC_DEBUG
-static char *numrow_toString[] = {
-	"8,192 - 13 rows",
-	"16,384 - 14 rows",
-	"32,768 - 15 rows",
-	"reserved"
-};
-
-static char *numcol_toString[] = {
-	"1,024 - 10 columns",
-	"2,048 - 11 columns",
-	"4,096 - 12 columns",
-	"reserved"
-};
-#endif
-
 /* enables the report of miscellaneous messages as CE errors - default off */
 static int misc_messages;
 
@@ -494,10 +478,9 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
 	ras = NREC_RAS(info->nrecmemb);
 	cas = NREC_CAS(info->nrecmemb);
 
-	debugf0("\t\tCSROW= %d  Channel= %d "
-		"(DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
-		rank, channel, bank,
-		rdwr ? "Write" : "Read", ras, cas);
+	edac_dbg(0, "\t\tCSROW= %d  Channel= %d (DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+		 rank, channel, bank,
+		 rdwr ? "Write" : "Read", ras, cas);
 
 	/* Only 1 bit will be on */
 	switch (allErrors) {
@@ -536,10 +519,10 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
 		 bank, ras, cas, allErrors, specific);
 
 	/* Call the helper to output message */
-	edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 0, 0, 0,
+	edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 1, 0, 0, 0,
 			     channel >> 1, channel & 1, rank,
 			     rdwr ? "Write error" : "Read error",
-			     msg, NULL);
+			     msg);
 }
 
 /*
@@ -574,7 +557,7 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
 	/* ONLY ONE of the possible error bits will be set, as per the docs */
 	ue_errors = allErrors & FERR_NF_UNCORRECTABLE;
 	if (ue_errors) {
-		debugf0("\tUncorrected bits= 0x%x\n", ue_errors);
+		edac_dbg(0, "\tUncorrected bits= 0x%x\n", ue_errors);
 
 		branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
 
@@ -590,11 +573,9 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
 		ras = NREC_RAS(info->nrecmemb);
 		cas = NREC_CAS(info->nrecmemb);
 
-		debugf0
-			("\t\tCSROW= %d  Channels= %d,%d  (Branch= %d "
-			"DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
-			rank, channel, channel + 1, branch >> 1, bank,
-			rdwr ? "Write" : "Read", ras, cas);
+		edac_dbg(0, "\t\tCSROW= %d  Channels= %d,%d  (Branch= %d DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+			 rank, channel, channel + 1, branch >> 1, bank,
+			 rdwr ? "Write" : "Read", ras, cas);
 
 		switch (ue_errors) {
 		case FERR_NF_M12ERR:
@@ -637,16 +618,16 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
 			 rank, bank, ras, cas, ue_errors, specific);
 
 		/* Call the helper to output message */
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
 				channel >> 1, -1, rank,
 				rdwr ? "Write error" : "Read error",
-				msg, NULL);
+				msg);
 	}
 
 	/* Check correctable errors */
 	ce_errors = allErrors & FERR_NF_CORRECTABLE;
 	if (ce_errors) {
-		debugf0("\tCorrected bits= 0x%x\n", ce_errors);
+		edac_dbg(0, "\tCorrected bits= 0x%x\n", ce_errors);
 
 		branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
 
@@ -664,10 +645,9 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
 		ras = REC_RAS(info->recmemb);
 		cas = REC_CAS(info->recmemb);
 
-		debugf0("\t\tCSROW= %d Channel= %d  (Branch %d "
-			"DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
-			rank, channel, branch >> 1, bank,
-			rdwr ? "Write" : "Read", ras, cas);
+		edac_dbg(0, "\t\tCSROW= %d Channel= %d  (Branch %d DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+			 rank, channel, branch >> 1, bank,
+			 rdwr ? "Write" : "Read", ras, cas);
 
 		switch (ce_errors) {
 		case FERR_NF_M17ERR:
@@ -692,10 +672,10 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
 			 specific);
 
 		/* Call the helper to output message */
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0,
 				channel >> 1, channel % 2, rank,
 				rdwr ? "Write error" : "Read error",
-				msg, NULL);
+				msg);
 	}
 
 	if (!misc_messages)
@@ -738,9 +718,9 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
 			 "Err=%#x (%s)", misc_errors, specific);
 
 		/* Call the helper to output message */
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0,
 				branch >> 1, -1, -1,
-				"Misc error", msg, NULL);
+				"Misc error", msg);
 	}
 }
 
@@ -779,7 +759,7 @@ static void i5000_clear_error(struct mem_ctl_info *mci)
 static void i5000_check_error(struct mem_ctl_info *mci)
 {
 	struct i5000_error_info info;
-	debugf4("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
+	edac_dbg(4, "MC%d\n", mci->mc_idx);
 	i5000_get_error_info(mci, &info);
 	i5000_process_error_info(mci, &info, 1);
 }
@@ -850,15 +830,16 @@ static int i5000_get_devices(struct mem_ctl_info *mci, int dev_idx)
 
 	pvt->fsb_error_regs = pdev;
 
-	debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
-		pci_name(pvt->system_address),
-		pvt->system_address->vendor, pvt->system_address->device);
-	debugf1("Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
-		pci_name(pvt->branchmap_werrors),
-		pvt->branchmap_werrors->vendor, pvt->branchmap_werrors->device);
-	debugf1("FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
-		pci_name(pvt->fsb_error_regs),
-		pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
+	edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
+		 pci_name(pvt->system_address),
+		 pvt->system_address->vendor, pvt->system_address->device);
+	edac_dbg(1, "Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
+		 pci_name(pvt->branchmap_werrors),
+		 pvt->branchmap_werrors->vendor,
+		 pvt->branchmap_werrors->device);
+	edac_dbg(1, "FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
+		 pci_name(pvt->fsb_error_regs),
+		 pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
 
 	pdev = NULL;
 	pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
@@ -981,16 +962,25 @@ static void decode_mtr(int slot_row, u16 mtr)
 
 	ans = MTR_DIMMS_PRESENT(mtr);
 
-	debugf2("\tMTR%d=0x%x:  DIMMs are %s\n", slot_row, mtr,
-		ans ? "Present" : "NOT Present");
+	edac_dbg(2, "\tMTR%d=0x%x:  DIMMs are %sPresent\n",
+		 slot_row, mtr, ans ? "" : "NOT ");
 	if (!ans)
 		return;
 
-	debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
-	debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
-	debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANK(mtr) ? "double" : "single");
-	debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
-	debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
+	edac_dbg(2, "\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+	edac_dbg(2, "\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+	edac_dbg(2, "\t\tNUMRANK: %s\n",
+		 MTR_DIMM_RANK(mtr) ? "double" : "single");
+	edac_dbg(2, "\t\tNUMROW: %s\n",
+		 MTR_DIMM_ROWS(mtr) == 0 ? "8,192 - 13 rows" :
+		 MTR_DIMM_ROWS(mtr) == 1 ? "16,384 - 14 rows" :
+		 MTR_DIMM_ROWS(mtr) == 2 ? "32,768 - 15 rows" :
+		 "reserved");
+	edac_dbg(2, "\t\tNUMCOL: %s\n",
+		 MTR_DIMM_COLS(mtr) == 0 ? "1,024 - 10 columns" :
+		 MTR_DIMM_COLS(mtr) == 1 ? "2,048 - 11 columns" :
+		 MTR_DIMM_COLS(mtr) == 2 ? "4,096 - 12 columns" :
+		 "reserved");
 }
 
 static void handle_channel(struct i5000_pvt *pvt, int slot, int channel,
@@ -1061,7 +1051,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
 				"--------------------------------");
 			p += n;
 			space -= n;
-			debugf2("%s\n", mem_buffer);
+			edac_dbg(2, "%s\n", mem_buffer);
 			p = mem_buffer;
 			space = PAGE_SIZE;
 		}
@@ -1082,7 +1072,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
 		}
 		p += n;
 		space -= n;
-		debugf2("%s\n", mem_buffer);
+		edac_dbg(2, "%s\n", mem_buffer);
 		p = mem_buffer;
 		space = PAGE_SIZE;
 	}
@@ -1092,7 +1082,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
 		"--------------------------------");
 	p += n;
 	space -= n;
-	debugf2("%s\n", mem_buffer);
+	edac_dbg(2, "%s\n", mem_buffer);
 	p = mem_buffer;
 	space = PAGE_SIZE;
 
@@ -1105,7 +1095,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
 		p += n;
 		space -= n;
 	}
-	debugf2("%s\n", mem_buffer);
+	edac_dbg(2, "%s\n", mem_buffer);
 	p = mem_buffer;
 	space = PAGE_SIZE;
 
@@ -1118,7 +1108,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
 	}
 
 	/* output the last message and free buffer */
-	debugf2("%s\n", mem_buffer);
+	edac_dbg(2, "%s\n", mem_buffer);
 	kfree(mem_buffer);
 }
 
@@ -1148,17 +1138,18 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
 	maxdimmperch = pvt->maxdimmperch;
 	maxch = pvt->maxch;
 
-	debugf2("AMBASE= 0x%lx  MAXCH= %d  MAX-DIMM-Per-CH= %d\n",
-		(long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
+	edac_dbg(2, "AMBASE= 0x%lx  MAXCH= %d  MAX-DIMM-Per-CH= %d\n",
+		 (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
 
 	/* Get the Branch Map regs */
 	pci_read_config_word(pvt->branchmap_werrors, TOLM, &pvt->tolm);
 	pvt->tolm >>= 12;
-	debugf2("\nTOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
-		pvt->tolm);
+	edac_dbg(2, "TOLM (number of 256M regions) =%u (0x%x)\n",
+		 pvt->tolm, pvt->tolm);
 
 	actual_tolm = pvt->tolm << 28;
-	debugf2("Actual TOLM byte addr=%u (0x%x)\n", actual_tolm, actual_tolm);
+	edac_dbg(2, "Actual TOLM byte addr=%u (0x%x)\n",
+		 actual_tolm, actual_tolm);
 
 	pci_read_config_word(pvt->branchmap_werrors, MIR0, &pvt->mir0);
 	pci_read_config_word(pvt->branchmap_werrors, MIR1, &pvt->mir1);
@@ -1168,15 +1159,18 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
 	limit = (pvt->mir0 >> 4) & 0x0FFF;
 	way0 = pvt->mir0 & 0x1;
 	way1 = pvt->mir0 & 0x2;
-	debugf2("MIR0: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+	edac_dbg(2, "MIR0: limit= 0x%x  WAY1= %u  WAY0= %x\n",
+		 limit, way1, way0);
 	limit = (pvt->mir1 >> 4) & 0x0FFF;
 	way0 = pvt->mir1 & 0x1;
 	way1 = pvt->mir1 & 0x2;
-	debugf2("MIR1: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+	edac_dbg(2, "MIR1: limit= 0x%x  WAY1= %u  WAY0= %x\n",
+		 limit, way1, way0);
 	limit = (pvt->mir2 >> 4) & 0x0FFF;
 	way0 = pvt->mir2 & 0x1;
 	way1 = pvt->mir2 & 0x2;
-	debugf2("MIR2: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+	edac_dbg(2, "MIR2: limit= 0x%x  WAY1= %u  WAY0= %x\n",
+		 limit, way1, way0);
 
 	/* Get the MTR[0-3] regs */
 	for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
@@ -1185,31 +1179,31 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
 		pci_read_config_word(pvt->branch_0, where,
 				&pvt->b0_mtr[slot_row]);
 
-		debugf2("MTR%d where=0x%x B0 value=0x%x\n", slot_row, where,
-			pvt->b0_mtr[slot_row]);
+		edac_dbg(2, "MTR%d where=0x%x B0 value=0x%x\n",
+			 slot_row, where, pvt->b0_mtr[slot_row]);
 
 		if (pvt->maxch >= CHANNELS_PER_BRANCH) {
 			pci_read_config_word(pvt->branch_1, where,
 					&pvt->b1_mtr[slot_row]);
-			debugf2("MTR%d where=0x%x B1 value=0x%x\n", slot_row,
-				where, pvt->b1_mtr[slot_row]);
+			edac_dbg(2, "MTR%d where=0x%x B1 value=0x%x\n",
+				 slot_row, where, pvt->b1_mtr[slot_row]);
 		} else {
 			pvt->b1_mtr[slot_row] = 0;
 		}
 	}
 
 	/* Read and dump branch 0's MTRs */
-	debugf2("\nMemory Technology Registers:\n");
-	debugf2("   Branch 0:\n");
+	edac_dbg(2, "Memory Technology Registers:\n");
+	edac_dbg(2, "   Branch 0:\n");
 	for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
 		decode_mtr(slot_row, pvt->b0_mtr[slot_row]);
 	}
 	pci_read_config_word(pvt->branch_0, AMB_PRESENT_0,
 			&pvt->b0_ambpresent0);
-	debugf2("\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
+	edac_dbg(2, "\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
 	pci_read_config_word(pvt->branch_0, AMB_PRESENT_1,
 			&pvt->b0_ambpresent1);
-	debugf2("\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
+	edac_dbg(2, "\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
 
 	/* Only if we have 2 branchs (4 channels) */
 	if (pvt->maxch < CHANNELS_PER_BRANCH) {
@@ -1217,18 +1211,18 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
 		pvt->b1_ambpresent1 = 0;
 	} else {
 		/* Read and dump  branch 1's MTRs */
-		debugf2("   Branch 1:\n");
+		edac_dbg(2, "   Branch 1:\n");
 		for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
 			decode_mtr(slot_row, pvt->b1_mtr[slot_row]);
 		}
 		pci_read_config_word(pvt->branch_1, AMB_PRESENT_0,
 				&pvt->b1_ambpresent0);
-		debugf2("\t\tAMB-Branch 1-present0 0x%x:\n",
-			pvt->b1_ambpresent0);
+		edac_dbg(2, "\t\tAMB-Branch 1-present0 0x%x:\n",
+			 pvt->b1_ambpresent0);
 		pci_read_config_word(pvt->branch_1, AMB_PRESENT_1,
 				&pvt->b1_ambpresent1);
-		debugf2("\t\tAMB-Branch 1-present1 0x%x:\n",
-			pvt->b1_ambpresent1);
+		edac_dbg(2, "\t\tAMB-Branch 1-present1 0x%x:\n",
+			 pvt->b1_ambpresent1);
 	}
 
 	/* Go and determine the size of each DIMM and place in an
@@ -1363,10 +1357,9 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
 	int num_channels;
 	int num_dimms_per_channel;
 
-	debugf0("MC: %s: %s(), pdev bus %u dev=0x%x fn=0x%x\n",
-		__FILE__, __func__,
-		pdev->bus->number,
-		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+	edac_dbg(0, "MC: pdev bus %u dev=0x%x fn=0x%x\n",
+		 pdev->bus->number,
+		 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
 	/* We only are looking for func 0 of the set */
 	if (PCI_FUNC(pdev->devfn) != 0)
@@ -1388,8 +1381,8 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
 	i5000_get_dimm_and_channel_counts(pdev, &num_dimms_per_channel,
 					&num_channels);
 
-	debugf0("MC: %s(): Number of Branches=2 Channels= %d  DIMMS= %d\n",
-		__func__, num_channels, num_dimms_per_channel);
+	edac_dbg(0, "MC: Number of Branches=2 Channels= %d  DIMMS= %d\n",
+		 num_channels, num_dimms_per_channel);
 
 	/* allocate a new MC control structure */
 
@@ -1406,10 +1399,9 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
 	if (mci == NULL)
 		return -ENOMEM;
 
-	kobject_get(&mci->edac_mci_kobj);
-	debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
+	edac_dbg(0, "MC: mci = %p\n", mci);
 
-	mci->dev = &pdev->dev;	/* record ptr  to the generic device */
+	mci->pdev = &pdev->dev;	/* record ptr  to the generic device */
 
 	pvt = mci->pvt_info;
 	pvt->system_address = pdev;	/* Record this device in our private */
@@ -1439,19 +1431,16 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
 	/* initialize the MC control structure 'csrows' table
 	 * with the mapping and control information */
 	if (i5000_init_csrows(mci)) {
-		debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
-			"    because i5000_init_csrows() returned nonzero "
-			"value\n");
+		edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i5000_init_csrows() returned nonzero value\n");
 		mci->edac_cap = EDAC_FLAG_NONE;	/* no csrows found */
 	} else {
-		debugf1("MC: Enable error reporting now\n");
+		edac_dbg(1, "MC: Enable error reporting now\n");
 		i5000_enable_error_reporting(mci);
 	}
 
 	/* add this new MC control structure to EDAC's list of MCs */
 	if (edac_mc_add_mc(mci)) {
-		debugf0("MC: %s: %s(): failed edac_mc_add_mc()\n",
-			__FILE__, __func__);
+		edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
 		/* FIXME: perhaps some code should go here that disables error
 		 * reporting if we just enabled it
 		 */
@@ -1479,7 +1468,6 @@ fail1:
 	i5000_put_devices(mci);
 
 fail0:
-	kobject_put(&mci->edac_mci_kobj);
 	edac_mc_free(mci);
 	return -ENODEV;
 }
@@ -1496,7 +1484,7 @@ static int __devinit i5000_init_one(struct pci_dev *pdev,
 {
 	int rc;
 
-	debugf0("MC: %s: %s()\n", __FILE__, __func__);
+	edac_dbg(0, "MC:\n");
 
 	/* wake up device */
 	rc = pci_enable_device(pdev);
@@ -1515,7 +1503,7 @@ static void __devexit i5000_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0("%s: %s()\n", __FILE__, __func__);
+	edac_dbg(0, "\n");
 
 	if (i5000_pci)
 		edac_pci_release_generic_ctl(i5000_pci);
@@ -1525,7 +1513,6 @@ static void __devexit i5000_remove_one(struct pci_dev *pdev)
 
 	/* retrieve references to resources, and free those resources */
 	i5000_put_devices(mci);
-	kobject_put(&mci->edac_mci_kobj);
 	edac_mc_free(mci);
 }
 
@@ -1562,7 +1549,7 @@ static int __init i5000_init(void)
 {
 	int pci_rc;
 
-	debugf2("MC: %s: %s()\n", __FILE__, __func__);
+	edac_dbg(2, "MC:\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -1578,7 +1565,7 @@ static int __init i5000_init(void)
  */
 static void __exit i5000_exit(void)
 {
-	debugf2("MC: %s: %s()\n", __FILE__, __func__);
+	edac_dbg(2, "MC:\n");
 	pci_unregister_driver(&i5000_driver);
 }
 
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index e9e7c2a..c4b5e5f 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -431,10 +431,10 @@ static void i5100_handle_ce(struct mem_ctl_info *mci,
 		 "bank %u, cas %u, ras %u\n",
 		 bank, cas, ras);
 
-	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 			     0, 0, syndrome,
 			     chan, rank, -1,
-			     msg, detail, NULL);
+			     msg, detail);
 }
 
 static void i5100_handle_ue(struct mem_ctl_info *mci,
@@ -453,10 +453,10 @@ static void i5100_handle_ue(struct mem_ctl_info *mci,
 		 "bank %u, cas %u, ras %u\n",
 		 bank, cas, ras);
 
-	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 			     0, 0, syndrome,
 			     chan, rank, -1,
-			     msg, detail, NULL);
+			     msg, detail);
 }
 
 static void i5100_read_log(struct mem_ctl_info *mci, int chan,
@@ -859,8 +859,8 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
 				i5100_rank_to_slot(mci, chan, rank));
 		}
 
-		debugf2("dimm channel %d, rank %d, size %ld\n",
-			chan, rank, (long)PAGES_TO_MiB(npages));
+		edac_dbg(2, "dimm channel %d, rank %d, size %ld\n",
+			 chan, rank, (long)PAGES_TO_MiB(npages));
 	}
 }
 
@@ -943,7 +943,7 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
 		goto bail_disable_ch1;
 	}
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 
 	priv = mci->pvt_info;
 	priv->ranksperchan = ranksperch;
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index 6640c29..50069c6 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
@@ -300,24 +300,6 @@ static inline int extract_fbdchan_indx(u32 x)
 	return (x>>28) & 0x3;
 }
 
-#ifdef CONFIG_EDAC_DEBUG
-/* MTR NUMROW */
-static const char *numrow_toString[] = {
-	"8,192 - 13 rows",
-	"16,384 - 14 rows",
-	"32,768 - 15 rows",
-	"65,536 - 16 rows"
-};
-
-/* MTR NUMCOL */
-static const char *numcol_toString[] = {
-	"1,024 - 10 columns",
-	"2,048 - 11 columns",
-	"4,096 - 12 columns",
-	"reserved"
-};
-#endif
-
 /* Device name and register DID (Device ID) */
 struct i5400_dev_info {
 	const char *ctl_name;	/* name for this device */
@@ -560,10 +542,9 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
 	ras = nrec_ras(info);
 	cas = nrec_cas(info);
 
-	debugf0("\t\tDIMM= %d  Channels= %d,%d  (Branch= %d "
-		"DRAM Bank= %d Buffer ID = %d rdwr= %s ras= %d cas= %d)\n",
-		rank, channel, channel + 1, branch >> 1, bank,
-		buf_id, rdwr_str(rdwr), ras, cas);
+	edac_dbg(0, "\t\tDIMM= %d  Channels= %d,%d  (Branch= %d DRAM Bank= %d Buffer ID = %d rdwr= %s ras= %d cas= %d)\n",
+		 rank, channel, channel + 1, branch >> 1, bank,
+		 buf_id, rdwr_str(rdwr), ras, cas);
 
 	/* Only 1 bit will be on */
 	errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name));
@@ -573,10 +554,10 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
 		 "Bank=%d Buffer ID = %d RAS=%d CAS=%d Err=0x%lx (%s)",
 		 bank, buf_id, ras, cas, allErrors, error_name[errnum]);
 
-	edac_mc_handle_error(tp_event, mci, 0, 0, 0,
+	edac_mc_handle_error(tp_event, mci, 1, 0, 0, 0,
 			     branch >> 1, -1, rank,
 			     rdwr ? "Write error" : "Read error",
-			     msg, NULL);
+			     msg);
 }
 
 /*
@@ -613,7 +594,7 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci,
 
 	/* Correctable errors */
 	if (allErrors & ERROR_NF_CORRECTABLE) {
-		debugf0("\tCorrected bits= 0x%lx\n", allErrors);
+		edac_dbg(0, "\tCorrected bits= 0x%lx\n", allErrors);
 
 		branch = extract_fbdchan_indx(info->ferr_nf_fbd);
 
@@ -634,10 +615,9 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci,
 		/* Only 1 bit will be on */
 		errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name));
 
-		debugf0("\t\tDIMM= %d Channel= %d  (Branch %d "
-			"DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
-			rank, channel, branch >> 1, bank,
-			rdwr_str(rdwr), ras, cas);
+		edac_dbg(0, "\t\tDIMM= %d Channel= %d  (Branch %d DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+			 rank, channel, branch >> 1, bank,
+			 rdwr_str(rdwr), ras, cas);
 
 		/* Form out message */
 		snprintf(msg, sizeof(msg),
@@ -646,10 +626,10 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci,
 			 branch >> 1, bank, rdwr_str(rdwr), ras, cas,
 			 allErrors, error_name[errnum]);
 
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0,
 				     branch >> 1, channel % 2, rank,
 				     rdwr ? "Write error" : "Read error",
-				     msg, NULL);
+				     msg);
 
 		return;
 	}
@@ -700,7 +680,7 @@ static void i5400_clear_error(struct mem_ctl_info *mci)
 static void i5400_check_error(struct mem_ctl_info *mci)
 {
 	struct i5400_error_info info;
-	debugf4("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
+	edac_dbg(4, "MC%d\n", mci->mc_idx);
 	i5400_get_error_info(mci, &info);
 	i5400_process_error_info(mci, &info);
 }
@@ -786,15 +766,16 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
 	}
 	pvt->fsb_error_regs = pdev;
 
-	debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
-		pci_name(pvt->system_address),
-		pvt->system_address->vendor, pvt->system_address->device);
-	debugf1("Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
-		pci_name(pvt->branchmap_werrors),
-		pvt->branchmap_werrors->vendor, pvt->branchmap_werrors->device);
-	debugf1("FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
-		pci_name(pvt->fsb_error_regs),
-		pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
+	edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
+		 pci_name(pvt->system_address),
+		 pvt->system_address->vendor, pvt->system_address->device);
+	edac_dbg(1, "Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
+		 pci_name(pvt->branchmap_werrors),
+		 pvt->branchmap_werrors->vendor,
+		 pvt->branchmap_werrors->device);
+	edac_dbg(1, "FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
+		 pci_name(pvt->fsb_error_regs),
+		 pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
 
 	pvt->branch_0 = pci_get_device(PCI_VENDOR_ID_INTEL,
 				       PCI_DEVICE_ID_INTEL_5400_FBD0, NULL);
@@ -882,8 +863,8 @@ static int determine_mtr(struct i5400_pvt *pvt, int dimm, int channel)
 	n = dimm;
 
 	if (n >= DIMMS_PER_CHANNEL) {
-		debugf0("ERROR: trying to access an invalid dimm: %d\n",
-			dimm);
+		edac_dbg(0, "ERROR: trying to access an invalid dimm: %d\n",
+			 dimm);
 		return 0;
 	}
 
@@ -903,20 +884,29 @@ static void decode_mtr(int slot_row, u16 mtr)
 
 	ans = MTR_DIMMS_PRESENT(mtr);
 
-	debugf2("\tMTR%d=0x%x:  DIMMs are %s\n", slot_row, mtr,
-		ans ? "Present" : "NOT Present");
+	edac_dbg(2, "\tMTR%d=0x%x:  DIMMs are %sPresent\n",
+		 slot_row, mtr, ans ? "" : "NOT ");
 	if (!ans)
 		return;
 
-	debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
-
-	debugf2("\t\tELECTRICAL THROTTLING is %s\n",
-		MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
-
-	debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
-	debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANK(mtr) ? "double" : "single");
-	debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
-	debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
+	edac_dbg(2, "\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+
+	edac_dbg(2, "\t\tELECTRICAL THROTTLING is %s\n",
+		 MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
+
+	edac_dbg(2, "\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+	edac_dbg(2, "\t\tNUMRANK: %s\n",
+		 MTR_DIMM_RANK(mtr) ? "double" : "single");
+	edac_dbg(2, "\t\tNUMROW: %s\n",
+		 MTR_DIMM_ROWS(mtr) == 0 ? "8,192 - 13 rows" :
+		 MTR_DIMM_ROWS(mtr) == 1 ? "16,384 - 14 rows" :
+		 MTR_DIMM_ROWS(mtr) == 2 ? "32,768 - 15 rows" :
+		 "65,536 - 16 rows");
+	edac_dbg(2, "\t\tNUMCOL: %s\n",
+		 MTR_DIMM_COLS(mtr) == 0 ? "1,024 - 10 columns" :
+		 MTR_DIMM_COLS(mtr) == 1 ? "2,048 - 11 columns" :
+		 MTR_DIMM_COLS(mtr) == 2 ? "4,096 - 12 columns" :
+		 "reserved");
 }
 
 static void handle_channel(struct i5400_pvt *pvt, int dimm, int channel,
@@ -989,7 +979,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
 					"-------------------------------");
 			p += n;
 			space -= n;
-			debugf2("%s\n", mem_buffer);
+			edac_dbg(2, "%s\n", mem_buffer);
 			p = mem_buffer;
 			space = PAGE_SIZE;
 		}
@@ -1004,7 +994,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
 			p += n;
 			space -= n;
 		}
-		debugf2("%s\n", mem_buffer);
+		edac_dbg(2, "%s\n", mem_buffer);
 		p = mem_buffer;
 		space = PAGE_SIZE;
 	}
@@ -1014,7 +1004,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
 			"-------------------------------");
 	p += n;
 	space -= n;
-	debugf2("%s\n", mem_buffer);
+	edac_dbg(2, "%s\n", mem_buffer);
 	p = mem_buffer;
 	space = PAGE_SIZE;
 
@@ -1029,7 +1019,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
 	}
 
 	space -= n;
-	debugf2("%s\n", mem_buffer);
+	edac_dbg(2, "%s\n", mem_buffer);
 	p = mem_buffer;
 	space = PAGE_SIZE;
 
@@ -1042,7 +1032,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
 	}
 
 	/* output the last message and free buffer */
-	debugf2("%s\n", mem_buffer);
+	edac_dbg(2, "%s\n", mem_buffer);
 	kfree(mem_buffer);
 }
 
@@ -1072,18 +1062,18 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
 	maxdimmperch = pvt->maxdimmperch;
 	maxch = pvt->maxch;
 
-	debugf2("AMBASE= 0x%lx  MAXCH= %d  MAX-DIMM-Per-CH= %d\n",
-		(long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
+	edac_dbg(2, "AMBASE= 0x%lx  MAXCH= %d  MAX-DIMM-Per-CH= %d\n",
+		 (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
 
 	/* Get the Branch Map regs */
 	pci_read_config_word(pvt->branchmap_werrors, TOLM, &pvt->tolm);
 	pvt->tolm >>= 12;
-	debugf2("\nTOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
-		pvt->tolm);
+	edac_dbg(2, "\nTOLM (number of 256M regions) =%u (0x%x)\n",
+		 pvt->tolm, pvt->tolm);
 
 	actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28));
-	debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
-		actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
+	edac_dbg(2, "Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
+		 actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
 
 	pci_read_config_word(pvt->branchmap_werrors, MIR0, &pvt->mir0);
 	pci_read_config_word(pvt->branchmap_werrors, MIR1, &pvt->mir1);
@@ -1092,11 +1082,13 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
 	limit = (pvt->mir0 >> 4) & 0x0fff;
 	way0 = pvt->mir0 & 0x1;
 	way1 = pvt->mir0 & 0x2;
-	debugf2("MIR0: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+	edac_dbg(2, "MIR0: limit= 0x%x  WAY1= %u  WAY0= %x\n",
+		 limit, way1, way0);
 	limit = (pvt->mir1 >> 4) & 0xfff;
 	way0 = pvt->mir1 & 0x1;
 	way1 = pvt->mir1 & 0x2;
-	debugf2("MIR1: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+	edac_dbg(2, "MIR1: limit= 0x%x  WAY1= %u  WAY0= %x\n",
+		 limit, way1, way0);
 
 	/* Get the set of MTR[0-3] regs by each branch */
 	for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++) {
@@ -1106,8 +1098,8 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
 		pci_read_config_word(pvt->branch_0, where,
 				&pvt->b0_mtr[slot_row]);
 
-		debugf2("MTR%d where=0x%x B0 value=0x%x\n", slot_row, where,
-			pvt->b0_mtr[slot_row]);
+		edac_dbg(2, "MTR%d where=0x%x B0 value=0x%x\n",
+			 slot_row, where, pvt->b0_mtr[slot_row]);
 
 		if (pvt->maxch < CHANNELS_PER_BRANCH) {
 			pvt->b1_mtr[slot_row] = 0;
@@ -1117,22 +1109,22 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
 		/* Branch 1 set of MTR registers */
 		pci_read_config_word(pvt->branch_1, where,
 				&pvt->b1_mtr[slot_row]);
-		debugf2("MTR%d where=0x%x B1 value=0x%x\n", slot_row, where,
-			pvt->b1_mtr[slot_row]);
+		edac_dbg(2, "MTR%d where=0x%x B1 value=0x%x\n",
+			 slot_row, where, pvt->b1_mtr[slot_row]);
 	}
 
 	/* Read and dump branch 0's MTRs */
-	debugf2("\nMemory Technology Registers:\n");
-	debugf2("   Branch 0:\n");
+	edac_dbg(2, "Memory Technology Registers:\n");
+	edac_dbg(2, "   Branch 0:\n");
 	for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++)
 		decode_mtr(slot_row, pvt->b0_mtr[slot_row]);
 
 	pci_read_config_word(pvt->branch_0, AMBPRESENT_0,
 			&pvt->b0_ambpresent0);
-	debugf2("\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
+	edac_dbg(2, "\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
 	pci_read_config_word(pvt->branch_0, AMBPRESENT_1,
 			&pvt->b0_ambpresent1);
-	debugf2("\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
+	edac_dbg(2, "\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
 
 	/* Only if we have 2 branchs (4 channels) */
 	if (pvt->maxch < CHANNELS_PER_BRANCH) {
@@ -1140,18 +1132,18 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
 		pvt->b1_ambpresent1 = 0;
 	} else {
 		/* Read and dump  branch 1's MTRs */
-		debugf2("   Branch 1:\n");
+		edac_dbg(2, "   Branch 1:\n");
 		for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++)
 			decode_mtr(slot_row, pvt->b1_mtr[slot_row]);
 
 		pci_read_config_word(pvt->branch_1, AMBPRESENT_0,
 				&pvt->b1_ambpresent0);
-		debugf2("\t\tAMB-Branch 1-present0 0x%x:\n",
-			pvt->b1_ambpresent0);
+		edac_dbg(2, "\t\tAMB-Branch 1-present0 0x%x:\n",
+			 pvt->b1_ambpresent0);
 		pci_read_config_word(pvt->branch_1, AMBPRESENT_1,
 				&pvt->b1_ambpresent1);
-		debugf2("\t\tAMB-Branch 1-present1 0x%x:\n",
-			pvt->b1_ambpresent1);
+		edac_dbg(2, "\t\tAMB-Branch 1-present1 0x%x:\n",
+			 pvt->b1_ambpresent1);
 	}
 
 	/* Go and determine the size of each DIMM and place in an
@@ -1203,10 +1195,9 @@ static int i5400_init_dimms(struct mem_ctl_info *mci)
 
 			size_mb =  pvt->dimm_info[slot][channel].megabytes;
 
-			debugf2("%s: dimm%zd (branch %d channel %d slot %d): %d.%03d GB\n",
-				__func__, dimm - mci->dimms,
-				channel / 2, channel % 2, slot,
-				size_mb / 1000, size_mb % 1000);
+			edac_dbg(2, "dimm (branch %d channel %d slot %d): %d.%03d GB\n",
+				 channel / 2, channel % 2, slot,
+				 size_mb / 1000, size_mb % 1000);
 
 			dimm->nr_pages = size_mb << 8;
 			dimm->grain = 8;
@@ -1227,7 +1218,7 @@ static int i5400_init_dimms(struct mem_ctl_info *mci)
 	 * With such single-DIMM mode, the SDCC algorithm degrades to SECDEC+.
 	 */
 	if (ndimms == 1)
-		mci->dimms[0].edac_mode = EDAC_SECDED;
+		mci->dimms[0]->edac_mode = EDAC_SECDED;
 
 	return (ndimms == 0);
 }
@@ -1270,10 +1261,9 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
 	if (dev_idx >= ARRAY_SIZE(i5400_devs))
 		return -EINVAL;
 
-	debugf0("MC: %s: %s(), pdev bus %u dev=0x%x fn=0x%x\n",
-		__FILE__, __func__,
-		pdev->bus->number,
-		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+	edac_dbg(0, "MC: pdev bus %u dev=0x%x fn=0x%x\n",
+		 pdev->bus->number,
+		 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
 	/* We only are looking for func 0 of the set */
 	if (PCI_FUNC(pdev->devfn) != 0)
@@ -1297,9 +1287,9 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
 	if (mci == NULL)
 		return -ENOMEM;
 
-	debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
+	edac_dbg(0, "MC: mci = %p\n", mci);
 
-	mci->dev = &pdev->dev;	/* record ptr  to the generic device */
+	mci->pdev = &pdev->dev;	/* record ptr  to the generic device */
 
 	pvt = mci->pvt_info;
 	pvt->system_address = pdev;	/* Record this device in our private */
@@ -1329,19 +1319,16 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
 	/* initialize the MC control structure 'dimms' table
 	 * with the mapping and control information */
 	if (i5400_init_dimms(mci)) {
-		debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
-			"    because i5400_init_dimms() returned nonzero "
-			"value\n");
+		edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i5400_init_dimms() returned nonzero value\n");
 		mci->edac_cap = EDAC_FLAG_NONE;	/* no dimms found */
 	} else {
-		debugf1("MC: Enable error reporting now\n");
+		edac_dbg(1, "MC: Enable error reporting now\n");
 		i5400_enable_error_reporting(mci);
 	}
 
 	/* add this new MC control structure to EDAC's list of MCs */
 	if (edac_mc_add_mc(mci)) {
-		debugf0("MC: %s: %s(): failed edac_mc_add_mc()\n",
-			__FILE__, __func__);
+		edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
 		/* FIXME: perhaps some code should go here that disables error
 		 * reporting if we just enabled it
 		 */
@@ -1385,7 +1372,7 @@ static int __devinit i5400_init_one(struct pci_dev *pdev,
 {
 	int rc;
 
-	debugf0("MC: %s: %s()\n", __FILE__, __func__);
+	edac_dbg(0, "MC:\n");
 
 	/* wake up device */
 	rc = pci_enable_device(pdev);
@@ -1404,7 +1391,7 @@ static void __devexit i5400_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0("%s: %s()\n", __FILE__, __func__);
+	edac_dbg(0, "\n");
 
 	if (i5400_pci)
 		edac_pci_release_generic_ctl(i5400_pci);
@@ -1450,7 +1437,7 @@ static int __init i5400_init(void)
 {
 	int pci_rc;
 
-	debugf2("MC: %s: %s()\n", __FILE__, __func__);
+	edac_dbg(2, "MC:\n");
 
 	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
 	opstate_init();
@@ -1466,7 +1453,7 @@ static int __init i5400_init(void)
  */
 static void __exit i5400_exit(void)
 {
-	debugf2("MC: %s: %s()\n", __FILE__, __func__);
+	edac_dbg(2, "MC:\n");
 	pci_unregister_driver(&i5400_driver);
 }
 
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index 97c22fd..a09d066 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -182,24 +182,6 @@ static const u16 mtr_regs[MAX_SLOTS] = {
 #define MTR_DIMM_COLS(mtr)		((mtr) & 0x3)
 #define MTR_DIMM_COLS_ADDR_BITS(mtr)	(MTR_DIMM_COLS(mtr) + 10)
 
-#ifdef CONFIG_EDAC_DEBUG
-/* MTR NUMROW */
-static const char *numrow_toString[] = {
-	"8,192 - 13 rows",
-	"16,384 - 14 rows",
-	"32,768 - 15 rows",
-	"65,536 - 16 rows"
-};
-
-/* MTR NUMCOL */
-static const char *numcol_toString[] = {
-	"1,024 - 10 columns",
-	"2,048 - 11 columns",
-	"4,096 - 12 columns",
-	"reserved"
-};
-#endif
-
 /************************************************
  * i7300 Register definitions for error detection
  ************************************************/
@@ -467,10 +449,10 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
 			 "Bank=%d RAS=%d CAS=%d Err=0x%lx (%s))",
 			 bank, ras, cas, errors, specific);
 
-		edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 0, 0, 0,
+		edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 1, 0, 0, 0,
 				     branch, -1, rank,
 				     is_wr ? "Write error" : "Read error",
-				     pvt->tmp_prt_buffer, NULL);
+				     pvt->tmp_prt_buffer);
 
 	}
 
@@ -513,11 +495,11 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
 			 "DRAM-Bank=%d RAS=%d CAS=%d, Err=0x%lx (%s))",
 			 bank, ras, cas, errors, specific);
 
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0,
 				     syndrome,
 				     branch >> 1, channel % 2, rank,
 				     is_wr ? "Write error" : "Read error",
-				     pvt->tmp_prt_buffer, NULL);
+				     pvt->tmp_prt_buffer);
 	}
 	return;
 }
@@ -614,9 +596,8 @@ static int decode_mtr(struct i7300_pvt *pvt,
 	mtr = pvt->mtr[slot][branch];
 	ans = MTR_DIMMS_PRESENT(mtr) ? 1 : 0;
 
-	debugf2("\tMTR%d CH%d: DIMMs are %s (mtr)\n",
-		slot, channel,
-		ans ? "Present" : "NOT Present");
+	edac_dbg(2, "\tMTR%d CH%d: DIMMs are %sPresent (mtr)\n",
+		 slot, channel, ans ? "" : "NOT ");
 
 	/* Determine if there is a DIMM present in this DIMM slot */
 	if (!ans)
@@ -638,16 +619,25 @@ static int decode_mtr(struct i7300_pvt *pvt,
 
 	dinfo->megabytes = 1 << addrBits;
 
-	debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
-
-	debugf2("\t\tELECTRICAL THROTTLING is %s\n",
-		MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
-
-	debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
-	debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANKS(mtr) ? "double" : "single");
-	debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
-	debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
-	debugf2("\t\tSIZE: %d MB\n", dinfo->megabytes);
+	edac_dbg(2, "\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+
+	edac_dbg(2, "\t\tELECTRICAL THROTTLING is %s\n",
+		 MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
+
+	edac_dbg(2, "\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+	edac_dbg(2, "\t\tNUMRANK: %s\n",
+		 MTR_DIMM_RANKS(mtr) ? "double" : "single");
+	edac_dbg(2, "\t\tNUMROW: %s\n",
+		 MTR_DIMM_ROWS(mtr) == 0 ? "8,192 - 13 rows" :
+		 MTR_DIMM_ROWS(mtr) == 1 ? "16,384 - 14 rows" :
+		 MTR_DIMM_ROWS(mtr) == 2 ? "32,768 - 15 rows" :
+		 "65,536 - 16 rows");
+	edac_dbg(2, "\t\tNUMCOL: %s\n",
+		 MTR_DIMM_COLS(mtr) == 0 ? "1,024 - 10 columns" :
+		 MTR_DIMM_COLS(mtr) == 1 ? "2,048 - 11 columns" :
+		 MTR_DIMM_COLS(mtr) == 2 ? "4,096 - 12 columns" :
+		 "reserved");
+	edac_dbg(2, "\t\tSIZE: %d MB\n", dinfo->megabytes);
 
 	/*
 	 * The type of error detection actually depends of the
@@ -663,9 +653,9 @@ static int decode_mtr(struct i7300_pvt *pvt,
 	dimm->mtype = MEM_FB_DDR2;
 	if (IS_SINGLE_MODE(pvt->mc_settings_a)) {
 		dimm->edac_mode = EDAC_SECDED;
-		debugf2("\t\tECC code is 8-byte-over-32-byte SECDED+ code\n");
+		edac_dbg(2, "\t\tECC code is 8-byte-over-32-byte SECDED+ code\n");
 	} else {
-		debugf2("\t\tECC code is on Lockstep mode\n");
+		edac_dbg(2, "\t\tECC code is on Lockstep mode\n");
 		if (MTR_DRAM_WIDTH(mtr) == 8)
 			dimm->edac_mode = EDAC_S8ECD8ED;
 		else
@@ -674,9 +664,9 @@ static int decode_mtr(struct i7300_pvt *pvt,
 
 	/* ask what device type on this row */
 	if (MTR_DRAM_WIDTH(mtr) == 8) {
-		debugf2("\t\tScrub algorithm for x8 is on %s mode\n",
-			IS_SCRBALGO_ENHANCED(pvt->mc_settings) ?
-					    "enhanced" : "normal");
+		edac_dbg(2, "\t\tScrub algorithm for x8 is on %s mode\n",
+			 IS_SCRBALGO_ENHANCED(pvt->mc_settings) ?
+			 "enhanced" : "normal");
 
 		dimm->dtype = DEV_X8;
 	} else
@@ -710,14 +700,14 @@ static void print_dimm_size(struct i7300_pvt *pvt)
 		p += n;
 		space -= n;
 	}
-	debugf2("%s\n", pvt->tmp_prt_buffer);
+	edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
 	p = pvt->tmp_prt_buffer;
 	space = PAGE_SIZE;
 	n = snprintf(p, space, "-------------------------------"
 			       "------------------------------");
 	p += n;
 	space -= n;
-	debugf2("%s\n", pvt->tmp_prt_buffer);
+	edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
 	p = pvt->tmp_prt_buffer;
 	space = PAGE_SIZE;
 
@@ -733,7 +723,7 @@ static void print_dimm_size(struct i7300_pvt *pvt)
 			space -= n;
 		}
 
-		debugf2("%s\n", pvt->tmp_prt_buffer);
+		edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
 		p = pvt->tmp_prt_buffer;
 		space = PAGE_SIZE;
 	}
@@ -742,7 +732,7 @@ static void print_dimm_size(struct i7300_pvt *pvt)
 			       "------------------------------");
 	p += n;
 	space -= n;
-	debugf2("%s\n", pvt->tmp_prt_buffer);
+	edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
 	p = pvt->tmp_prt_buffer;
 	space = PAGE_SIZE;
 #endif
@@ -765,7 +755,7 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
 
 	pvt = mci->pvt_info;
 
-	debugf2("Memory Technology Registers:\n");
+	edac_dbg(2, "Memory Technology Registers:\n");
 
 	/* Get the AMB present registers for the four channels */
 	for (branch = 0; branch < MAX_BRANCHES; branch++) {
@@ -774,15 +764,15 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
 		pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
 				     AMBPRESENT_0,
 				&pvt->ambpresent[channel]);
-		debugf2("\t\tAMB-present CH%d = 0x%x:\n",
-			channel, pvt->ambpresent[channel]);
+		edac_dbg(2, "\t\tAMB-present CH%d = 0x%x:\n",
+			 channel, pvt->ambpresent[channel]);
 
 		channel = to_channel(1, branch);
 		pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
 				     AMBPRESENT_1,
 				&pvt->ambpresent[channel]);
-		debugf2("\t\tAMB-present CH%d = 0x%x:\n",
-			channel, pvt->ambpresent[channel]);
+		edac_dbg(2, "\t\tAMB-present CH%d = 0x%x:\n",
+			 channel, pvt->ambpresent[channel]);
 	}
 
 	/* Get the set of MTR[0-7] regs by each branch */
@@ -824,12 +814,11 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
 static void decode_mir(int mir_no, u16 mir[MAX_MIR])
 {
 	if (mir[mir_no] & 3)
-		debugf2("MIR%d: limit= 0x%x Branch(es) that participate:"
-			" %s %s\n",
-			mir_no,
-			(mir[mir_no] >> 4) & 0xfff,
-			(mir[mir_no] & 1) ? "B0" : "",
-			(mir[mir_no] & 2) ? "B1" : "");
+		edac_dbg(2, "MIR%d: limit= 0x%x Branch(es) that participate: %s %s\n",
+			 mir_no,
+			 (mir[mir_no] >> 4) & 0xfff,
+			 (mir[mir_no] & 1) ? "B0" : "",
+			 (mir[mir_no] & 2) ? "B1" : "");
 }
 
 /**
@@ -849,17 +838,17 @@ static int i7300_get_mc_regs(struct mem_ctl_info *mci)
 	pci_read_config_dword(pvt->pci_dev_16_0_fsb_ctlr, AMBASE,
 			(u32 *) &pvt->ambase);
 
-	debugf2("AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase);
+	edac_dbg(2, "AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase);
 
 	/* Get the Branch Map regs */
 	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, TOLM, &pvt->tolm);
 	pvt->tolm >>= 12;
-	debugf2("TOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
-		pvt->tolm);
+	edac_dbg(2, "TOLM (number of 256M regions) =%u (0x%x)\n",
+		 pvt->tolm, pvt->tolm);
 
 	actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28));
-	debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
-		actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
+	edac_dbg(2, "Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
+		 actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
 
 	/* Get memory controller settings */
 	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS,
@@ -868,15 +857,15 @@ static int i7300_get_mc_regs(struct mem_ctl_info *mci)
 			     &pvt->mc_settings_a);
 
 	if (IS_SINGLE_MODE(pvt->mc_settings_a))
-		debugf0("Memory controller operating on single mode\n");
+		edac_dbg(0, "Memory controller operating on single mode\n");
 	else
-		debugf0("Memory controller operating on %s mode\n",
-		IS_MIRRORED(pvt->mc_settings) ? "mirrored" : "non-mirrored");
+		edac_dbg(0, "Memory controller operating on %smirrored mode\n",
+			 IS_MIRRORED(pvt->mc_settings) ? "" : "non-");
 
-	debugf0("Error detection is %s\n",
-		IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
-	debugf0("Retry is %s\n",
-		IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
+	edac_dbg(0, "Error detection is %s\n",
+		 IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
+	edac_dbg(0, "Retry is %s\n",
+		 IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
 
 	/* Get Memory Interleave Range registers */
 	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR0,
@@ -970,18 +959,18 @@ static int __devinit i7300_get_devices(struct mem_ctl_info *mci)
 		}
 	}
 
-	debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
-		pci_name(pvt->pci_dev_16_0_fsb_ctlr),
-		pvt->pci_dev_16_0_fsb_ctlr->vendor,
-		pvt->pci_dev_16_0_fsb_ctlr->device);
-	debugf1("Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
-		pci_name(pvt->pci_dev_16_1_fsb_addr_map),
-		pvt->pci_dev_16_1_fsb_addr_map->vendor,
-		pvt->pci_dev_16_1_fsb_addr_map->device);
-	debugf1("FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
-		pci_name(pvt->pci_dev_16_2_fsb_err_regs),
-		pvt->pci_dev_16_2_fsb_err_regs->vendor,
-		pvt->pci_dev_16_2_fsb_err_regs->device);
+	edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
+		 pci_name(pvt->pci_dev_16_0_fsb_ctlr),
+		 pvt->pci_dev_16_0_fsb_ctlr->vendor,
+		 pvt->pci_dev_16_0_fsb_ctlr->device);
+	edac_dbg(1, "Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
+		 pci_name(pvt->pci_dev_16_1_fsb_addr_map),
+		 pvt->pci_dev_16_1_fsb_addr_map->vendor,
+		 pvt->pci_dev_16_1_fsb_addr_map->device);
+	edac_dbg(1, "FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
+		 pci_name(pvt->pci_dev_16_2_fsb_err_regs),
+		 pvt->pci_dev_16_2_fsb_err_regs->vendor,
+		 pvt->pci_dev_16_2_fsb_err_regs->device);
 
 	pvt->pci_dev_2x_0_fbd_branch[0] = pci_get_device(PCI_VENDOR_ID_INTEL,
 					    PCI_DEVICE_ID_INTEL_I7300_MCH_FB0,
@@ -1032,10 +1021,9 @@ static int __devinit i7300_init_one(struct pci_dev *pdev,
 	if (rc == -EIO)
 		return rc;
 
-	debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
-		__func__,
-		pdev->bus->number,
-		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+	edac_dbg(0, "MC: pdev bus %u dev=0x%x fn=0x%x\n",
+		 pdev->bus->number,
+		 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
 	/* We only are looking for func 0 of the set */
 	if (PCI_FUNC(pdev->devfn) != 0)
@@ -1055,9 +1043,9 @@ static int __devinit i7300_init_one(struct pci_dev *pdev,
 	if (mci == NULL)
 		return -ENOMEM;
 
-	debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+	edac_dbg(0, "MC: mci = %p\n", mci);
 
-	mci->dev = &pdev->dev;	/* record ptr  to the generic device */
+	mci->pdev = &pdev->dev;	/* record ptr  to the generic device */
 
 	pvt = mci->pvt_info;
 	pvt->pci_dev_16_0_fsb_ctlr = pdev;	/* Record this device in our private */
@@ -1088,19 +1076,16 @@ static int __devinit i7300_init_one(struct pci_dev *pdev,
 	/* initialize the MC control structure 'csrows' table
 	 * with the mapping and control information */
 	if (i7300_get_mc_regs(mci)) {
-		debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
-			"    because i7300_init_csrows() returned nonzero "
-			"value\n");
+		edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i7300_init_csrows() returned nonzero value\n");
 		mci->edac_cap = EDAC_FLAG_NONE;	/* no csrows found */
 	} else {
-		debugf1("MC: Enable error reporting now\n");
+		edac_dbg(1, "MC: Enable error reporting now\n");
 		i7300_enable_error_reporting(mci);
 	}
 
 	/* add this new MC control structure to EDAC's list of MCs */
 	if (edac_mc_add_mc(mci)) {
-		debugf0("MC: " __FILE__
-			": %s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
 		/* FIXME: perhaps some code should go here that disables error
 		 * reporting if we just enabled it
 		 */
@@ -1142,7 +1127,7 @@ static void __devexit i7300_remove_one(struct pci_dev *pdev)
 	struct mem_ctl_info *mci;
 	char *tmp;
 
-	debugf0(__FILE__ ": %s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	if (i7300_pci)
 		edac_pci_release_generic_ctl(i7300_pci);
@@ -1189,7 +1174,7 @@ static int __init i7300_init(void)
 {
 	int pci_rc;
 
-	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+	edac_dbg(2, "\n");
 
 	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
 	opstate_init();
@@ -1204,7 +1189,7 @@ static int __init i7300_init(void)
  */
 static void __exit i7300_exit(void)
 {
-	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+	edac_dbg(2, "\n");
 	pci_unregister_driver(&i7300_driver);
 }
 
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index a499c7e..3672101 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -248,6 +248,8 @@ struct i7core_dev {
 };
 
 struct i7core_pvt {
+	struct device *addrmatch_dev, *chancounts_dev;
+
 	struct pci_dev	*pci_noncore;
 	struct pci_dev	*pci_mcr[MAX_MCR_FUNC + 1];
 	struct pci_dev	*pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1];
@@ -514,29 +516,28 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 	pci_read_config_dword(pdev, MC_MAX_DOD, &pvt->info.max_dod);
 	pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map);
 
-	debugf0("QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n",
-		pvt->i7core_dev->socket, pvt->info.mc_control, pvt->info.mc_status,
-		pvt->info.max_dod, pvt->info.ch_map);
+	edac_dbg(0, "QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n",
+		 pvt->i7core_dev->socket, pvt->info.mc_control,
+		 pvt->info.mc_status, pvt->info.max_dod, pvt->info.ch_map);
 
 	if (ECC_ENABLED(pvt)) {
-		debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt) ? 8 : 4);
+		edac_dbg(0, "ECC enabled with x%d SDCC\n", ECCx8(pvt) ? 8 : 4);
 		if (ECCx8(pvt))
 			mode = EDAC_S8ECD8ED;
 		else
 			mode = EDAC_S4ECD4ED;
 	} else {
-		debugf0("ECC disabled\n");
+		edac_dbg(0, "ECC disabled\n");
 		mode = EDAC_NONE;
 	}
 
 	/* FIXME: need to handle the error codes */
-	debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked "
-		"x%x x 0x%x\n",
-		numdimms(pvt->info.max_dod),
-		numrank(pvt->info.max_dod >> 2),
-		numbank(pvt->info.max_dod >> 4),
-		numrow(pvt->info.max_dod >> 6),
-		numcol(pvt->info.max_dod >> 9));
+	edac_dbg(0, "DOD Max limits: DIMMS: %d, %d-ranked, %d-banked x%x x 0x%x\n",
+		 numdimms(pvt->info.max_dod),
+		 numrank(pvt->info.max_dod >> 2),
+		 numbank(pvt->info.max_dod >> 4),
+		 numrow(pvt->info.max_dod >> 6),
+		 numcol(pvt->info.max_dod >> 9));
 
 	for (i = 0; i < NUM_CHANS; i++) {
 		u32 data, dimm_dod[3], value[8];
@@ -545,11 +546,11 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 			continue;
 
 		if (!CH_ACTIVE(pvt, i)) {
-			debugf0("Channel %i is not active\n", i);
+			edac_dbg(0, "Channel %i is not active\n", i);
 			continue;
 		}
 		if (CH_DISABLED(pvt, i)) {
-			debugf0("Channel %i is disabled\n", i);
+			edac_dbg(0, "Channel %i is disabled\n", i);
 			continue;
 		}
 
@@ -580,15 +581,14 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 		pci_read_config_dword(pvt->pci_ch[i][1],
 				MC_DOD_CH_DIMM2, &dimm_dod[2]);
 
-		debugf0("Ch%d phy rd%d, wr%d (0x%08x): "
-			"%s%s%s%cDIMMs\n",
-			i,
-			RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i),
-			data,
-			pvt->channel[i].is_3dimms_present ? "3DIMMS " : "",
-			pvt->channel[i].is_3dimms_present ? "SINGLE_4R " : "",
-			pvt->channel[i].has_4rank ? "HAS_4R " : "",
-			(data & REGISTERED_DIMM) ? 'R' : 'U');
+		edac_dbg(0, "Ch%d phy rd%d, wr%d (0x%08x): %s%s%s%cDIMMs\n",
+			 i,
+			 RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i),
+			 data,
+			 pvt->channel[i].is_3dimms_present ? "3DIMMS " : "",
+			 pvt->channel[i].is_3dimms_present ? "SINGLE_4R " : "",
+			 pvt->channel[i].has_4rank ? "HAS_4R " : "",
+			 (data & REGISTERED_DIMM) ? 'R' : 'U');
 
 		for (j = 0; j < 3; j++) {
 			u32 banks, ranks, rows, cols;
@@ -607,11 +607,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 			/* DDR3 has 8 I/O banks */
 			size = (rows * cols * banks * ranks) >> (20 - 3);
 
-			debugf0("\tdimm %d %d Mb offset: %x, "
-				"bank: %d, rank: %d, row: %#x, col: %#x\n",
-				j, size,
-				RANKOFFSET(dimm_dod[j]),
-				banks, ranks, rows, cols);
+			edac_dbg(0, "\tdimm %d %d Mb offset: %x, bank: %d, rank: %d, row: %#x, col: %#x\n",
+				 j, size,
+				 RANKOFFSET(dimm_dod[j]),
+				 banks, ranks, rows, cols);
 
 			npages = MiB_TO_PAGES(size);
 
@@ -647,12 +646,12 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 		pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]);
 		pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]);
 		pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]);
-		debugf1("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i);
+		edac_dbg(1, "\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i);
 		for (j = 0; j < 8; j++)
-			debugf1("\t\t%#x\t%#x\t%#x\n",
-				(value[j] >> 27) & 0x1,
-				(value[j] >> 24) & 0x7,
-				(value[j] & ((1 << 24) - 1)));
+			edac_dbg(1, "\t\t%#x\t%#x\t%#x\n",
+				 (value[j] >> 27) & 0x1,
+				 (value[j] >> 24) & 0x7,
+				 (value[j] & ((1 << 24) - 1)));
 	}
 
 	return 0;
@@ -662,6 +661,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 			Error insertion routines
  ****************************************************************************/
 
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
+
 /* The i7core has independent error injection features per channel.
    However, to have a simpler code, we don't allow enabling error injection
    on more than one channel.
@@ -691,9 +692,11 @@ static int disable_inject(const struct mem_ctl_info *mci)
  *	bit 0 - refers to the lower 32-byte half cacheline
  *	bit 1 - refers to the upper 32-byte half cacheline
  */
-static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
+static ssize_t i7core_inject_section_store(struct device *dev,
+					   struct device_attribute *mattr,
 					   const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
 	unsigned long value;
 	int rc;
@@ -709,9 +712,11 @@ static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
 	return count;
 }
 
-static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
-					      char *data)
+static ssize_t i7core_inject_section_show(struct device *dev,
+					  struct device_attribute *mattr,
+					  char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
 	return sprintf(data, "0x%08x\n", pvt->inject.section);
 }
@@ -724,10 +729,12 @@ static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
  *	bit 1 - inject ECC error
  *	bit 2 - inject parity error
  */
-static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
+static ssize_t i7core_inject_type_store(struct device *dev,
+					struct device_attribute *mattr,
 					const char *data, size_t count)
 {
-	struct i7core_pvt *pvt = mci->pvt_info;
+	struct mem_ctl_info *mci = to_mci(dev);
+struct i7core_pvt *pvt = mci->pvt_info;
 	unsigned long value;
 	int rc;
 
@@ -742,10 +749,13 @@ static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
 	return count;
 }
 
-static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
-					      char *data)
+static ssize_t i7core_inject_type_show(struct device *dev,
+				       struct device_attribute *mattr,
+				       char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
+
 	return sprintf(data, "0x%08x\n", pvt->inject.type);
 }
 
@@ -759,9 +769,11 @@ static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
  *   23:16 and 31:24). Flipping bits in two symbol pairs will cause an
  *   uncorrectable error to be injected.
  */
-static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
-					const char *data, size_t count)
+static ssize_t i7core_inject_eccmask_store(struct device *dev,
+					   struct device_attribute *mattr,
+					   const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
 	unsigned long value;
 	int rc;
@@ -777,10 +789,13 @@ static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
 	return count;
 }
 
-static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
-					      char *data)
+static ssize_t i7core_inject_eccmask_show(struct device *dev,
+					  struct device_attribute *mattr,
+					  char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
+
 	return sprintf(data, "0x%08x\n", pvt->inject.eccmask);
 }
 
@@ -797,14 +812,16 @@ static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
 
 #define DECLARE_ADDR_MATCH(param, limit)			\
 static ssize_t i7core_inject_store_##param(			\
-		struct mem_ctl_info *mci,			\
-		const char *data, size_t count)			\
+	struct device *dev,					\
+	struct device_attribute *mattr,				\
+	const char *data, size_t count)				\
 {								\
+	struct mem_ctl_info *mci = to_mci(dev);			\
 	struct i7core_pvt *pvt;					\
 	long value;						\
 	int rc;							\
 								\
-	debugf1("%s()\n", __func__);				\
+	edac_dbg(1, "\n");					\
 	pvt = mci->pvt_info;					\
 								\
 	if (pvt->inject.enable)					\
@@ -824,13 +841,15 @@ static ssize_t i7core_inject_store_##param(			\
 }								\
 								\
 static ssize_t i7core_inject_show_##param(			\
-		struct mem_ctl_info *mci,			\
-		char *data)					\
+	struct device *dev,					\
+	struct device_attribute *mattr,				\
+	char *data)						\
 {								\
+	struct mem_ctl_info *mci = to_mci(dev);			\
 	struct i7core_pvt *pvt;					\
 								\
 	pvt = mci->pvt_info;					\
-	debugf1("%s() pvt=%p\n", __func__, pvt);		\
+	edac_dbg(1, "pvt=%p\n", pvt);				\
 	if (pvt->inject.param < 0)				\
 		return sprintf(data, "any\n");			\
 	else							\
@@ -838,14 +857,9 @@ static ssize_t i7core_inject_show_##param(			\
 }
 
 #define ATTR_ADDR_MATCH(param)					\
-	{							\
-		.attr = {					\
-			.name = #param,				\
-			.mode = (S_IRUGO | S_IWUSR)		\
-		},						\
-		.show  = i7core_inject_show_##param,		\
-		.store = i7core_inject_store_##param,		\
-	}
+	static DEVICE_ATTR(param, S_IRUGO | S_IWUSR,		\
+		    i7core_inject_show_##param,			\
+		    i7core_inject_store_##param)
 
 DECLARE_ADDR_MATCH(channel, 3);
 DECLARE_ADDR_MATCH(dimm, 3);
@@ -854,14 +868,21 @@ DECLARE_ADDR_MATCH(bank, 32);
 DECLARE_ADDR_MATCH(page, 0x10000);
 DECLARE_ADDR_MATCH(col, 0x4000);
 
+ATTR_ADDR_MATCH(channel);
+ATTR_ADDR_MATCH(dimm);
+ATTR_ADDR_MATCH(rank);
+ATTR_ADDR_MATCH(bank);
+ATTR_ADDR_MATCH(page);
+ATTR_ADDR_MATCH(col);
+
 static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
 {
 	u32 read;
 	int count;
 
-	debugf0("setting pci %02x:%02x.%x reg=%02x value=%08x\n",
-		dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
-		where, val);
+	edac_dbg(0, "setting pci %02x:%02x.%x reg=%02x value=%08x\n",
+		 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+		 where, val);
 
 	for (count = 0; count < 10; count++) {
 		if (count)
@@ -899,9 +920,11 @@ static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
  *    is reliable enough to check if the MC is using the
  *    three channels. However, this is not clear at the datasheet.
  */
-static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
-				       const char *data, size_t count)
+static ssize_t i7core_inject_enable_store(struct device *dev,
+					  struct device_attribute *mattr,
+					  const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
 	u32 injectmask;
 	u64 mask = 0;
@@ -994,17 +1017,18 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
 	pci_write_config_dword(pvt->pci_noncore,
 			       MC_CFG_CONTROL, 8);
 
-	debugf0("Error inject addr match 0x%016llx, ecc 0x%08x,"
-		" inject 0x%08x\n",
-		mask, pvt->inject.eccmask, injectmask);
+	edac_dbg(0, "Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x\n",
+		 mask, pvt->inject.eccmask, injectmask);
 
 
 	return count;
 }
 
-static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
-					char *data)
+static ssize_t i7core_inject_enable_show(struct device *dev,
+					 struct device_attribute *mattr,
+					 char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
 	u32 injectmask;
 
@@ -1014,7 +1038,7 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
 	pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0],
 			       MC_CHANNEL_ERROR_INJECT, &injectmask);
 
-	debugf0("Inject error read: 0x%018x\n", injectmask);
+	edac_dbg(0, "Inject error read: 0x%018x\n", injectmask);
 
 	if (injectmask & 0x0c)
 		pvt->inject.enable = 1;
@@ -1024,12 +1048,14 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
 
 #define DECLARE_COUNTER(param)					\
 static ssize_t i7core_show_counter_##param(			\
-		struct mem_ctl_info *mci,			\
-		char *data)					\
+	struct device *dev,					\
+	struct device_attribute *mattr,				\
+	char *data)						\
 {								\
+	struct mem_ctl_info *mci = to_mci(dev);			\
 	struct i7core_pvt *pvt = mci->pvt_info;			\
 								\
-	debugf1("%s() \n", __func__);				\
+	edac_dbg(1, "\n");					\
 	if (!pvt->ce_count_available || (pvt->is_registered))	\
 		return sprintf(data, "data unavailable\n");	\
 	return sprintf(data, "%lu\n",				\
@@ -1037,121 +1063,179 @@ static ssize_t i7core_show_counter_##param(			\
 }
 
 #define ATTR_COUNTER(param)					\
-	{							\
-		.attr = {					\
-			.name = __stringify(udimm##param),	\
-			.mode = (S_IRUGO | S_IWUSR)		\
-		},						\
-		.show  = i7core_show_counter_##param		\
-	}
+	static DEVICE_ATTR(udimm##param, S_IRUGO | S_IWUSR,	\
+		    i7core_show_counter_##param,		\
+		    NULL)
 
 DECLARE_COUNTER(0);
 DECLARE_COUNTER(1);
 DECLARE_COUNTER(2);
 
+ATTR_COUNTER(0);
+ATTR_COUNTER(1);
+ATTR_COUNTER(2);
+
 /*
- * Sysfs struct
+ * inject_addrmatch device sysfs struct
  */
 
-static const struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
-	ATTR_ADDR_MATCH(channel),
-	ATTR_ADDR_MATCH(dimm),
-	ATTR_ADDR_MATCH(rank),
-	ATTR_ADDR_MATCH(bank),
-	ATTR_ADDR_MATCH(page),
-	ATTR_ADDR_MATCH(col),
-	{ } /* End of list */
+static struct attribute *i7core_addrmatch_attrs[] = {
+	&dev_attr_channel.attr,
+	&dev_attr_dimm.attr,
+	&dev_attr_rank.attr,
+	&dev_attr_bank.attr,
+	&dev_attr_page.attr,
+	&dev_attr_col.attr,
+	NULL
 };
 
-static const struct mcidev_sysfs_group i7core_inject_addrmatch = {
-	.name  = "inject_addrmatch",
-	.mcidev_attr = i7core_addrmatch_attrs,
+static struct attribute_group addrmatch_grp = {
+	.attrs	= i7core_addrmatch_attrs,
 };
 
-static const struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
-	ATTR_COUNTER(0),
-	ATTR_COUNTER(1),
-	ATTR_COUNTER(2),
-	{ .attr = { .name = NULL } }
+static const struct attribute_group *addrmatch_groups[] = {
+	&addrmatch_grp,
+	NULL
 };
 
-static const struct mcidev_sysfs_group i7core_udimm_counters = {
-	.name  = "all_channel_counts",
-	.mcidev_attr = i7core_udimm_counters_attrs,
+static void addrmatch_release(struct device *device)
+{
+	edac_dbg(1, "Releasing device %s\n", dev_name(device));
+	kfree(device);
+}
+
+static struct device_type addrmatch_type = {
+	.groups		= addrmatch_groups,
+	.release	= addrmatch_release,
 };
 
-static const struct mcidev_sysfs_attribute i7core_sysfs_rdimm_attrs[] = {
-	{
-		.attr = {
-			.name = "inject_section",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_section_show,
-		.store = i7core_inject_section_store,
-	}, {
-		.attr = {
-			.name = "inject_type",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_type_show,
-		.store = i7core_inject_type_store,
-	}, {
-		.attr = {
-			.name = "inject_eccmask",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_eccmask_show,
-		.store = i7core_inject_eccmask_store,
-	}, {
-		.grp = &i7core_inject_addrmatch,
-	}, {
-		.attr = {
-			.name = "inject_enable",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_enable_show,
-		.store = i7core_inject_enable_store,
-	},
-	{ }	/* End of list */
+/*
+ * all_channel_counts sysfs struct
+ */
+
+static struct attribute *i7core_udimm_counters_attrs[] = {
+	&dev_attr_udimm0.attr,
+	&dev_attr_udimm1.attr,
+	&dev_attr_udimm2.attr,
+	NULL
 };
 
-static const struct mcidev_sysfs_attribute i7core_sysfs_udimm_attrs[] = {
-	{
-		.attr = {
-			.name = "inject_section",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_section_show,
-		.store = i7core_inject_section_store,
-	}, {
-		.attr = {
-			.name = "inject_type",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_type_show,
-		.store = i7core_inject_type_store,
-	}, {
-		.attr = {
-			.name = "inject_eccmask",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_eccmask_show,
-		.store = i7core_inject_eccmask_store,
-	}, {
-		.grp = &i7core_inject_addrmatch,
-	}, {
-		.attr = {
-			.name = "inject_enable",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_enable_show,
-		.store = i7core_inject_enable_store,
-	}, {
-		.grp = &i7core_udimm_counters,
-	},
-	{ }	/* End of list */
+static struct attribute_group all_channel_counts_grp = {
+	.attrs	= i7core_udimm_counters_attrs,
 };
 
+static const struct attribute_group *all_channel_counts_groups[] = {
+	&all_channel_counts_grp,
+	NULL
+};
+
+static void all_channel_counts_release(struct device *device)
+{
+	edac_dbg(1, "Releasing device %s\n", dev_name(device));
+	kfree(device);
+}
+
+static struct device_type all_channel_counts_type = {
+	.groups		= all_channel_counts_groups,
+	.release	= all_channel_counts_release,
+};
+
+/*
+ * inject sysfs attributes
+ */
+
+static DEVICE_ATTR(inject_section, S_IRUGO | S_IWUSR,
+		   i7core_inject_section_show, i7core_inject_section_store);
+
+static DEVICE_ATTR(inject_type, S_IRUGO | S_IWUSR,
+		   i7core_inject_type_show, i7core_inject_type_store);
+
+
+static DEVICE_ATTR(inject_eccmask, S_IRUGO | S_IWUSR,
+		   i7core_inject_eccmask_show, i7core_inject_eccmask_store);
+
+static DEVICE_ATTR(inject_enable, S_IRUGO | S_IWUSR,
+		   i7core_inject_enable_show, i7core_inject_enable_store);
+
+static int i7core_create_sysfs_devices(struct mem_ctl_info *mci)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	int rc;
+
+	rc = device_create_file(&mci->dev, &dev_attr_inject_section);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_type);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_eccmask);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_enable);
+	if (rc < 0)
+		return rc;
+
+	pvt->addrmatch_dev = kzalloc(sizeof(*pvt->addrmatch_dev), GFP_KERNEL);
+	if (!pvt->addrmatch_dev)
+		return rc;
+
+	pvt->addrmatch_dev->type = &addrmatch_type;
+	pvt->addrmatch_dev->bus = mci->dev.bus;
+	device_initialize(pvt->addrmatch_dev);
+	pvt->addrmatch_dev->parent = &mci->dev;
+	dev_set_name(pvt->addrmatch_dev, "inject_addrmatch");
+	dev_set_drvdata(pvt->addrmatch_dev, mci);
+
+	edac_dbg(1, "creating %s\n", dev_name(pvt->addrmatch_dev));
+
+	rc = device_add(pvt->addrmatch_dev);
+	if (rc < 0)
+		return rc;
+
+	if (!pvt->is_registered) {
+		pvt->chancounts_dev = kzalloc(sizeof(*pvt->chancounts_dev),
+					      GFP_KERNEL);
+		if (!pvt->chancounts_dev) {
+			put_device(pvt->addrmatch_dev);
+			device_del(pvt->addrmatch_dev);
+			return rc;
+		}
+
+		pvt->chancounts_dev->type = &all_channel_counts_type;
+		pvt->chancounts_dev->bus = mci->dev.bus;
+		device_initialize(pvt->chancounts_dev);
+		pvt->chancounts_dev->parent = &mci->dev;
+		dev_set_name(pvt->chancounts_dev, "all_channel_counts");
+		dev_set_drvdata(pvt->chancounts_dev, mci);
+
+		edac_dbg(1, "creating %s\n", dev_name(pvt->chancounts_dev));
+
+		rc = device_add(pvt->chancounts_dev);
+		if (rc < 0)
+			return rc;
+	}
+	return 0;
+}
+
+static void i7core_delete_sysfs_devices(struct mem_ctl_info *mci)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+
+	edac_dbg(1, "\n");
+
+	device_remove_file(&mci->dev, &dev_attr_inject_section);
+	device_remove_file(&mci->dev, &dev_attr_inject_type);
+	device_remove_file(&mci->dev, &dev_attr_inject_eccmask);
+	device_remove_file(&mci->dev, &dev_attr_inject_enable);
+
+	if (!pvt->is_registered) {
+		put_device(pvt->chancounts_dev);
+		device_del(pvt->chancounts_dev);
+	}
+	put_device(pvt->addrmatch_dev);
+	device_del(pvt->addrmatch_dev);
+}
+
 /****************************************************************************
 	Device initialization routines: put/get, init/exit
  ****************************************************************************/
@@ -1164,14 +1248,14 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev)
 {
 	int i;
 
-	debugf0(__FILE__ ": %s()\n", __func__);
+	edac_dbg(0, "\n");
 	for (i = 0; i < i7core_dev->n_devs; i++) {
 		struct pci_dev *pdev = i7core_dev->pdev[i];
 		if (!pdev)
 			continue;
-		debugf0("Removing dev %02x:%02x.%d\n",
-			pdev->bus->number,
-			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+		edac_dbg(0, "Removing dev %02x:%02x.%d\n",
+			 pdev->bus->number,
+			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 		pci_dev_put(pdev);
 	}
 }
@@ -1214,12 +1298,12 @@ static unsigned i7core_pci_lastbus(void)
 
 	while ((b = pci_find_next_bus(b)) != NULL) {
 		bus = b->number;
-		debugf0("Found bus %d\n", bus);
+		edac_dbg(0, "Found bus %d\n", bus);
 		if (bus > last_bus)
 			last_bus = bus;
 	}
 
-	debugf0("Last bus %d\n", last_bus);
+	edac_dbg(0, "Last bus %d\n", last_bus);
 
 	return last_bus;
 }
@@ -1326,10 +1410,10 @@ static int i7core_get_onedevice(struct pci_dev **prev,
 		return -ENODEV;
 	}
 
-	debugf0("Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n",
-		socket, bus, dev_descr->dev,
-		dev_descr->func,
-		PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+	edac_dbg(0, "Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n",
+		 socket, bus, dev_descr->dev,
+		 dev_descr->func,
+		 PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
 	/*
 	 * As stated on drivers/pci/search.c, the reference count for
@@ -1427,13 +1511,13 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
 				family = "unknown";
 				pvt->enable_scrub = false;
 			}
-			debugf0("Detected a processor type %s\n", family);
+			edac_dbg(0, "Detected a processor type %s\n", family);
 		} else
 			goto error;
 
-		debugf0("Associated fn %d.%d, dev = %p, socket %d\n",
-			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-			pdev, i7core_dev->socket);
+		edac_dbg(0, "Associated fn %d.%d, dev = %p, socket %d\n",
+			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+			 pdev, i7core_dev->socket);
 
 		if (PCI_SLOT(pdev->devfn) == 3 &&
 			PCI_FUNC(pdev->devfn) == 2)
@@ -1452,18 +1536,6 @@ error:
 /****************************************************************************
 			Error check routines
  ****************************************************************************/
-static void i7core_rdimm_update_errcount(struct mem_ctl_info *mci,
-				      const int chan,
-				      const int dimm,
-				      const int add)
-{
-	int i;
-
-	for (i = 0; i < add; i++) {
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
-				     chan, dimm, -1, "error", "", NULL);
-	}
-}
 
 static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
 					 const int chan,
@@ -1502,12 +1574,17 @@ static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
 
 	/*updated the edac core */
 	if (add0 != 0)
-		i7core_rdimm_update_errcount(mci, chan, 0, add0);
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, add0,
+				     0, 0, 0,
+				     chan, 0, -1, "error", "");
 	if (add1 != 0)
-		i7core_rdimm_update_errcount(mci, chan, 1, add1);
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, add1,
+				     0, 0, 0,
+				     chan, 1, -1, "error", "");
 	if (add2 != 0)
-		i7core_rdimm_update_errcount(mci, chan, 2, add2);
-
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, add2,
+				     0, 0, 0,
+				     chan, 2, -1, "error", "");
 }
 
 static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci)
@@ -1530,8 +1607,8 @@ static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci)
 	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_5,
 								&rcv[2][1]);
 	for (i = 0 ; i < 3; i++) {
-		debugf3("MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n",
-			(i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]);
+		edac_dbg(3, "MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n",
+			 (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]);
 		/*if the channel has 3 dimms*/
 		if (pvt->channel[i].dimms > 2) {
 			new0 = DIMM_BOT_COR_ERR(rcv[i][0]);
@@ -1562,7 +1639,7 @@ static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci)
 	int new0, new1, new2;
 
 	if (!pvt->pci_mcr[4]) {
-		debugf0("%s MCR registers not found\n", __func__);
+		edac_dbg(0, "MCR registers not found\n");
 		return;
 	}
 
@@ -1626,7 +1703,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
 				    const struct mce *m)
 {
 	struct i7core_pvt *pvt = mci->pvt_info;
-	char *type, *optype, *err, msg[80];
+	char *type, *optype, *err;
 	enum hw_event_mc_err_type tp_event;
 	unsigned long error = m->status & 0x1ff0000l;
 	bool uncorrected_error = m->mcgstatus & 1ll << 61;
@@ -1704,20 +1781,18 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
 		err = "unknown";
 	}
 
-	snprintf(msg, sizeof(msg), "count=%d %s", core_err_cnt, optype);
-
 	/*
 	 * Call the helper to output message
 	 * FIXME: what to do if core_err_cnt > 1? Currently, it generates
 	 * only one event
 	 */
 	if (uncorrected_error || !pvt->is_registered)
-		edac_mc_handle_error(tp_event, mci,
+		edac_mc_handle_error(tp_event, mci, core_err_cnt,
 				     m->addr >> PAGE_SHIFT,
 				     m->addr & ~PAGE_MASK,
 				     syndrome,
 				     channel, dimm, -1,
-				     err, msg, m);
+				     err, optype);
 }
 
 /*
@@ -2094,8 +2169,7 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
 	struct i7core_pvt *pvt;
 
 	if (unlikely(!mci || !mci->pvt_info)) {
-		debugf0("MC: " __FILE__ ": %s(): dev = %p\n",
-			__func__, &i7core_dev->pdev[0]->dev);
+		edac_dbg(0, "MC: dev = %p\n", &i7core_dev->pdev[0]->dev);
 
 		i7core_printk(KERN_ERR, "Couldn't find mci handler\n");
 		return;
@@ -2103,8 +2177,7 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
 
 	pvt = mci->pvt_info;
 
-	debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
-		__func__, mci, &i7core_dev->pdev[0]->dev);
+	edac_dbg(0, "MC: mci = %p, dev = %p\n", mci, &i7core_dev->pdev[0]->dev);
 
 	/* Disable scrubrate setting */
 	if (pvt->enable_scrub)
@@ -2114,9 +2187,10 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
 	i7core_pci_ctl_release(pvt);
 
 	/* Remove MC sysfs nodes */
-	edac_mc_del_mc(mci->dev);
+	i7core_delete_sysfs_devices(mci);
+	edac_mc_del_mc(mci->pdev);
 
-	debugf1("%s: free mci struct\n", mci->ctl_name);
+	edac_dbg(1, "%s: free mci struct\n", mci->ctl_name);
 	kfree(mci->ctl_name);
 	edac_mc_free(mci);
 	i7core_dev->mci = NULL;
@@ -2142,8 +2216,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
 	if (unlikely(!mci))
 		return -ENOMEM;
 
-	debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
-		__func__, mci, &i7core_dev->pdev[0]->dev);
+	edac_dbg(0, "MC: mci = %p, dev = %p\n", mci, &i7core_dev->pdev[0]->dev);
 
 	pvt = mci->pvt_info;
 	memset(pvt, 0, sizeof(*pvt));
@@ -2172,15 +2245,11 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
 	if (unlikely(rc < 0))
 		goto fail0;
 
-	if (pvt->is_registered)
-		mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs;
-	else
-		mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs;
 
 	/* Get dimm basic config */
 	get_dimm_config(mci);
 	/* record ptr to the generic device */
-	mci->dev = &i7core_dev->pdev[0]->dev;
+	mci->pdev = &i7core_dev->pdev[0]->dev;
 	/* Set the function pointer to an actual operation function */
 	mci->edac_check = i7core_check_error;
 
@@ -2190,8 +2259,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
 
 	/* add this new MC control structure to EDAC's list of MCs */
 	if (unlikely(edac_mc_add_mc(mci))) {
-		debugf0("MC: " __FILE__
-			": %s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
 		/* FIXME: perhaps some code should go here that disables error
 		 * reporting if we just enabled it
 		 */
@@ -2199,6 +2267,12 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
 		rc = -EINVAL;
 		goto fail0;
 	}
+	if (i7core_create_sysfs_devices(mci)) {
+		edac_dbg(0, "MC: failed to create sysfs nodes\n");
+		edac_mc_del_mc(mci->pdev);
+		rc = -EINVAL;
+		goto fail0;
+	}
 
 	/* Default error mask is any memory */
 	pvt->inject.channel = 0;
@@ -2298,7 +2372,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev)
 {
 	struct i7core_dev *i7core_dev;
 
-	debugf0(__FILE__ ": %s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/*
 	 * we have a trouble here: pdev value for removal will be wrong, since
@@ -2347,7 +2421,7 @@ static int __init i7core_init(void)
 {
 	int pci_rc;
 
-	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+	edac_dbg(2, "\n");
 
 	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
 	opstate_init();
@@ -2374,7 +2448,7 @@ static int __init i7core_init(void)
  */
 static void __exit i7core_exit(void)
 {
-	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+	edac_dbg(2, "\n");
 	pci_unregister_driver(&i7core_driver);
 	mce_unregister_decode_chain(&i7_mce_dec);
 }
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
index 52072c2..90f303d 100644
--- a/drivers/edac/i82443bxgx_edac.c
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -124,7 +124,7 @@ static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
 				*info)
 {
 	struct pci_dev *pdev;
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 	pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap);
 	if (info->eap & I82443BXGX_EAP_OFFSET_SBE)
 		/* Clear error to allow next error to be reported [p.61] */
@@ -156,19 +156,19 @@ static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
 	if (info->eap & I82443BXGX_EAP_OFFSET_SBE) {
 		error_found = 1;
 		if (handle_errors)
-			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 					     page, pageoffset, 0,
 					     edac_mc_find_csrow_by_page(mci, page),
-					     0, -1, mci->ctl_name, "", NULL);
+					     0, -1, mci->ctl_name, "");
 	}
 
 	if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
 		error_found = 1;
 		if (handle_errors)
-			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 					     page, pageoffset, 0,
 					     edac_mc_find_csrow_by_page(mci, page),
-					     0, -1, mci->ctl_name, "", NULL);
+					     0, -1, mci->ctl_name, "");
 	}
 
 	return error_found;
@@ -178,7 +178,7 @@ static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
 {
 	struct i82443bxgx_edacmc_error_info info;
 
-	debugf1("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
+	edac_dbg(1, "MC%d\n", mci->mc_idx);
 	i82443bxgx_edacmc_get_error_info(mci, &info);
 	i82443bxgx_edacmc_process_error_info(mci, &info, 1);
 }
@@ -197,18 +197,17 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
 	pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
 	row_high_limit_last = 0;
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
-		debugf1("MC%d: %s: %s() Row=%d DRB = %#0x\n",
-			mci->mc_idx, __FILE__, __func__, index, drbar);
+		edac_dbg(1, "MC%d: Row=%d DRB = %#0x\n",
+			 mci->mc_idx, index, drbar);
 		row_high_limit = ((u32) drbar << 23);
 		/* find the DRAM Chip Select Base address and mask */
-		debugf1("MC%d: %s: %s() Row=%d, "
-			"Boundary Address=%#0x, Last = %#0x\n",
-			mci->mc_idx, __FILE__, __func__, index, row_high_limit,
-			row_high_limit_last);
+		edac_dbg(1, "MC%d: Row=%d, Boundary Address=%#0x, Last = %#0x\n",
+			 mci->mc_idx, index, row_high_limit,
+			 row_high_limit_last);
 
 		/* 440GX goes to 2GB, represented with a DRB of 0. */
 		if (row_high_limit_last && !row_high_limit)
@@ -241,7 +240,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
 	enum mem_type mtype;
 	enum edac_type edac_mode;
 
-	debugf0("MC: %s: %s()\n", __FILE__, __func__);
+	edac_dbg(0, "MC:\n");
 
 	/* Something is really hosed if PCI config space reads from
 	 * the MC aren't working.
@@ -259,8 +258,8 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
 	if (mci == NULL)
 		return -ENOMEM;
 
-	debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
-	mci->dev = &pdev->dev;
+	edac_dbg(0, "MC: mci = %p\n", mci);
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
@@ -275,8 +274,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
 		mtype = MEM_RDR;
 		break;
 	default:
-		debugf0("Unknown/reserved DRAM type value "
-			"in DRAMC register!\n");
+		edac_dbg(0, "Unknown/reserved DRAM type value in DRAMC register!\n");
 		mtype = -MEM_UNKNOWN;
 	}
 
@@ -305,8 +303,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
 		edac_mode = EDAC_SECDED;
 		break;
 	default:
-		debugf0("%s(): Unknown/reserved ECC state "
-			"in NBXCFG register!\n", __func__);
+		edac_dbg(0, "Unknown/reserved ECC state in NBXCFG register!\n");
 		edac_mode = EDAC_UNKNOWN;
 		break;
 	}
@@ -330,7 +327,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
 	mci->ctl_page_to_phys = NULL;
 
 	if (edac_mc_add_mc(mci)) {
-		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "failed edac_mc_add_mc()\n");
 		goto fail;
 	}
 
@@ -345,7 +342,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
 			__func__);
 	}
 
-	debugf3("MC: %s: %s(): success\n", __FILE__, __func__);
+	edac_dbg(3, "MC: success\n");
 	return 0;
 
 fail:
@@ -361,7 +358,7 @@ static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
 {
 	int rc;
 
-	debugf0("MC: %s: %s()\n", __FILE__, __func__);
+	edac_dbg(0, "MC:\n");
 
 	/* don't need to call pci_enable_device() */
 	rc = i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
@@ -376,7 +373,7 @@ static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0("%s: %s()\n", __FILE__, __func__);
+	edac_dbg(0, "\n");
 
 	if (i82443bxgx_pci)
 		edac_pci_release_generic_ctl(i82443bxgx_pci);
@@ -428,7 +425,7 @@ static int __init i82443bxgx_edacmc_init(void)
 			id = &i82443bxgx_pci_tbl[i];
 		}
 		if (!mci_pdev) {
-			debugf0("i82443bxgx pci_get_device fail\n");
+			edac_dbg(0, "i82443bxgx pci_get_device fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
@@ -436,7 +433,7 @@ static int __init i82443bxgx_edacmc_init(void)
 		pci_rc = i82443bxgx_edacmc_init_one(mci_pdev, i82443bxgx_pci_tbl);
 
 		if (pci_rc < 0) {
-			debugf0("i82443bxgx init fail\n");
+			edac_dbg(0, "i82443bxgx init fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index 0804505..1faa749 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -67,7 +67,7 @@ static void i82860_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -109,25 +109,25 @@ static int i82860_process_error_info(struct mem_ctl_info *mci,
 		return 1;
 
 	if ((info->errsts ^ info->errsts2) & 0x0003) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-				     -1, -1, -1, "UE overwrote CE", "", NULL);
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
+				     -1, -1, -1, "UE overwrote CE", "");
 		info->errsts = info->errsts2;
 	}
 
 	info->eap >>= PAGE_SHIFT;
 	row = edac_mc_find_csrow_by_page(mci, info->eap);
-	dimm = mci->csrows[row].channels[0].dimm;
+	dimm = mci->csrows[row]->channels[0]->dimm;
 
 	if (info->errsts & 0x0002)
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 				     info->eap, 0, 0,
 				     dimm->location[0], dimm->location[1], -1,
-				     "i82860 UE", "", NULL);
+				     "i82860 UE", "");
 	else
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 				     info->eap, 0, info->derrsyn,
 				     dimm->location[0], dimm->location[1], -1,
-				     "i82860 CE", "", NULL);
+				     "i82860 CE", "");
 
 	return 1;
 }
@@ -136,7 +136,7 @@ static void i82860_check(struct mem_ctl_info *mci)
 {
 	struct i82860_error_info info;
 
-	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+	edac_dbg(1, "MC%d\n", mci->mc_idx);
 	i82860_get_error_info(mci, &info);
 	i82860_process_error_info(mci, &info, 1);
 }
@@ -161,14 +161,13 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
 	 * in all eight rows.
 	 */
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
 		cumul_size = (value & I82860_GBA_MASK) <<
 			(I82860_GBA_SHIFT - PAGE_SHIFT);
-		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
-			cumul_size);
+		edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size);
 
 		if (cumul_size == last_cumul_size)
 			continue;	/* not populated */
@@ -210,8 +209,8 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
 	if (!mci)
 		return -ENOMEM;
 
-	debugf3("%s(): init mci\n", __func__);
-	mci->dev = &pdev->dev;
+	edac_dbg(3, "init mci\n");
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 	/* I"m not sure about this but I think that all RDRAM is SECDED */
@@ -229,7 +228,7 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
 	if (edac_mc_add_mc(mci)) {
-		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "failed edac_mc_add_mc()\n");
 		goto fail;
 	}
 
@@ -245,7 +244,7 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
 	}
 
 	/* get this far and it's successful */
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 
 	return 0;
 
@@ -260,7 +259,7 @@ static int __devinit i82860_init_one(struct pci_dev *pdev,
 {
 	int rc;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 	i82860_printk(KERN_INFO, "i82860 init one\n");
 
 	if (pci_enable_device(pdev) < 0)
@@ -278,7 +277,7 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	if (i82860_pci)
 		edac_pci_release_generic_ctl(i82860_pci);
@@ -311,7 +310,7 @@ static int __init i82860_init(void)
 {
 	int pci_rc;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -324,7 +323,7 @@ static int __init i82860_init(void)
 					PCI_DEVICE_ID_INTEL_82860_0, NULL);
 
 		if (mci_pdev == NULL) {
-			debugf0("860 pci_get_device fail\n");
+			edac_dbg(0, "860 pci_get_device fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
@@ -332,7 +331,7 @@ static int __init i82860_init(void)
 		pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl);
 
 		if (pci_rc < 0) {
-			debugf0("860 init fail\n");
+			edac_dbg(0, "860 init fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
@@ -352,7 +351,7 @@ fail0:
 
 static void __exit i82860_exit(void)
 {
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
 	pci_unregister_driver(&i82860_driver);
 
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index b613e31..3e416b1 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -189,7 +189,7 @@ static void i82875p_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -227,7 +227,7 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,
 {
 	int row, multi_chan;
 
-	multi_chan = mci->csrows[0].nr_channels - 1;
+	multi_chan = mci->csrows[0]->nr_channels - 1;
 
 	if (!(info->errsts & 0x0081))
 		return 0;
@@ -236,9 +236,9 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,
 		return 1;
 
 	if ((info->errsts ^ info->errsts2) & 0x0081) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
 				     -1, -1, -1,
-				     "UE overwrote CE", "", NULL);
+				     "UE overwrote CE", "");
 		info->errsts = info->errsts2;
 	}
 
@@ -246,15 +246,15 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,
 	row = edac_mc_find_csrow_by_page(mci, info->eap);
 
 	if (info->errsts & 0x0080)
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 				     info->eap, 0, 0,
 				     row, -1, -1,
-				     "i82875p UE", "", NULL);
+				     "i82875p UE", "");
 	else
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     info->eap, 0, info->derrsyn,
 				     row, multi_chan ? (info->des & 0x1) : 0,
-				     -1, "i82875p CE", "", NULL);
+				     -1, "i82875p CE", "");
 
 	return 1;
 }
@@ -263,7 +263,7 @@ static void i82875p_check(struct mem_ctl_info *mci)
 {
 	struct i82875p_error_info info;
 
-	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+	edac_dbg(1, "MC%d\n", mci->mc_idx);
 	i82875p_get_error_info(mci, &info);
 	i82875p_process_error_info(mci, &info, 1);
 }
@@ -367,12 +367,11 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci,
 	 */
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		value = readb(ovrfl_window + I82875P_DRB + index);
 		cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT);
-		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
-			cumul_size);
+		edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size);
 		if (cumul_size == last_cumul_size)
 			continue;	/* not populated */
 
@@ -382,7 +381,7 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci,
 		last_cumul_size = cumul_size;
 
 		for (j = 0; j < nr_chans; j++) {
-			dimm = csrow->channels[j].dimm;
+			dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / nr_chans;
 			dimm->grain = 1 << 12;	/* I82875P_EAP has 4KiB reolution */
@@ -405,7 +404,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
 	u32 nr_chans;
 	struct i82875p_error_info discard;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
 
@@ -426,11 +425,8 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
 		goto fail0;
 	}
 
-	/* Keeps mci available after edac_mc_del_mc() till edac_mc_free() */
-	kobject_get(&mci->edac_mci_kobj);
-
-	debugf3("%s(): init mci\n", __func__);
-	mci->dev = &pdev->dev;
+	edac_dbg(3, "init mci\n");
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 	mci->edac_cap = EDAC_FLAG_UNKNOWN;
@@ -440,7 +436,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
 	mci->dev_name = pci_name(pdev);
 	mci->edac_check = i82875p_check;
 	mci->ctl_page_to_phys = NULL;
-	debugf3("%s(): init pvt\n", __func__);
+	edac_dbg(3, "init pvt\n");
 	pvt = (struct i82875p_pvt *)mci->pvt_info;
 	pvt->ovrfl_pdev = ovrfl_pdev;
 	pvt->ovrfl_window = ovrfl_window;
@@ -451,7 +447,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
 	if (edac_mc_add_mc(mci)) {
-		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "failed edac_mc_add_mc()\n");
 		goto fail1;
 	}
 
@@ -467,11 +463,10 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
 	}
 
 	/* get this far and it's successful */
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 	return 0;
 
 fail1:
-	kobject_put(&mci->edac_mci_kobj);
 	edac_mc_free(mci);
 
 fail0:
@@ -489,7 +484,7 @@ static int __devinit i82875p_init_one(struct pci_dev *pdev,
 {
 	int rc;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 	i82875p_printk(KERN_INFO, "i82875p init one\n");
 
 	if (pci_enable_device(pdev) < 0)
@@ -508,7 +503,7 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
 	struct mem_ctl_info *mci;
 	struct i82875p_pvt *pvt = NULL;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	if (i82875p_pci)
 		edac_pci_release_generic_ctl(i82875p_pci);
@@ -554,7 +549,7 @@ static int __init i82875p_init(void)
 {
 	int pci_rc;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -569,7 +564,7 @@ static int __init i82875p_init(void)
 					PCI_DEVICE_ID_INTEL_82875_0, NULL);
 
 		if (!mci_pdev) {
-			debugf0("875p pci_get_device fail\n");
+			edac_dbg(0, "875p pci_get_device fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
@@ -577,7 +572,7 @@ static int __init i82875p_init(void)
 		pci_rc = i82875p_init_one(mci_pdev, i82875p_pci_tbl);
 
 		if (pci_rc < 0) {
-			debugf0("875p init fail\n");
+			edac_dbg(0, "875p init fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
@@ -597,7 +592,7 @@ fail0:
 
 static void __exit i82875p_exit(void)
 {
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
 	i82875p_remove_one(mci_pdev);
 	pci_dev_put(mci_pdev);
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index 433332c..069e26c 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -241,7 +241,7 @@ static void i82975x_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -288,8 +288,8 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
 		return 1;
 
 	if ((info->errsts ^ info->errsts2) & 0x0003) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-				     -1, -1, -1, "UE overwrote CE", "", NULL);
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
+				     -1, -1, -1, "UE overwrote CE", "");
 		info->errsts = info->errsts2;
 	}
 
@@ -308,21 +308,21 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
 			(info->xeap & 1) ? 1 : 0, info->eap, (unsigned int) page);
 		return 0;
 	}
-	chan = (mci->csrows[row].nr_channels == 1) ? 0 : info->eap & 1;
+	chan = (mci->csrows[row]->nr_channels == 1) ? 0 : info->eap & 1;
 	offst = info->eap
 			& ((1 << PAGE_SHIFT) -
-			   (1 << mci->csrows[row].channels[chan].dimm->grain));
+			   (1 << mci->csrows[row]->channels[chan]->dimm->grain));
 
 	if (info->errsts & 0x0002)
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 				     page, offst, 0,
 				     row, -1, -1,
-				     "i82975x UE", "", NULL);
+				     "i82975x UE", "");
 	else
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     page, offst, info->derrsyn,
 				     row, chan ? chan : 0, -1,
-				     "i82975x CE", "", NULL);
+				     "i82975x CE", "");
 
 	return 1;
 }
@@ -331,7 +331,7 @@ static void i82975x_check(struct mem_ctl_info *mci)
 {
 	struct i82975x_error_info info;
 
-	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+	edac_dbg(1, "MC%d\n", mci->mc_idx);
 	i82975x_get_error_info(mci, &info);
 	i82975x_process_error_info(mci, &info, 1);
 }
@@ -394,7 +394,7 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
 	 */
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		value = readb(mch_window + I82975X_DRB + index +
 					((index >= 4) ? 0x80 : 0));
@@ -406,8 +406,7 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
 		 */
 		if (csrow->nr_channels > 1)
 			cumul_size <<= 1;
-		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
-			cumul_size);
+		edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size);
 
 		nr_pages = cumul_size - last_cumul_size;
 		if (!nr_pages)
@@ -421,10 +420,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
 		 */
 		dtype = i82975x_dram_type(mch_window, index);
 		for (chan = 0; chan < csrow->nr_channels; chan++) {
-			dimm = mci->csrows[index].channels[chan].dimm;
+			dimm = mci->csrows[index]->channels[chan]->dimm;
 
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
-			strncpy(csrow->channels[chan].dimm->label,
+			strncpy(csrow->channels[chan]->dimm->label,
 					labels[(index >> 1) + (chan * 2)],
 					EDAC_MC_LABEL_LEN);
 			dimm->grain = 1 << 7;	/* 128Byte cache-line resolution */
@@ -489,11 +488,11 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
 	u8 c1drb[4];
 #endif
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	pci_read_config_dword(pdev, I82975X_MCHBAR, &mchbar);
 	if (!(mchbar & 1)) {
-		debugf3("%s(): failed, MCHBAR disabled!\n", __func__);
+		edac_dbg(3, "failed, MCHBAR disabled!\n");
 		goto fail0;
 	}
 	mchbar &= 0xffffc000;	/* bits 31:14 used for 16K window */
@@ -558,8 +557,8 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
 		goto fail1;
 	}
 
-	debugf3("%s(): init mci\n", __func__);
-	mci->dev = &pdev->dev;
+	edac_dbg(3, "init mci\n");
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR2;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 	mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
@@ -569,7 +568,7 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
 	mci->dev_name = pci_name(pdev);
 	mci->edac_check = i82975x_check;
 	mci->ctl_page_to_phys = NULL;
-	debugf3("%s(): init pvt\n", __func__);
+	edac_dbg(3, "init pvt\n");
 	pvt = (struct i82975x_pvt *) mci->pvt_info;
 	pvt->mch_window = mch_window;
 	i82975x_init_csrows(mci, pdev, mch_window);
@@ -578,12 +577,12 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
 
 	/* finalize this instance of memory controller with edac core */
 	if (edac_mc_add_mc(mci)) {
-		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "failed edac_mc_add_mc()\n");
 		goto fail2;
 	}
 
 	/* get this far and it's successful */
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 	return 0;
 
 fail2:
@@ -601,7 +600,7 @@ static int __devinit i82975x_init_one(struct pci_dev *pdev,
 {
 	int rc;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	if (pci_enable_device(pdev) < 0)
 		return -EIO;
@@ -619,7 +618,7 @@ static void __devexit i82975x_remove_one(struct pci_dev *pdev)
 	struct mem_ctl_info *mci;
 	struct i82975x_pvt *pvt;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	mci = edac_mc_del_mc(&pdev->dev);
 	if (mci  == NULL)
@@ -655,7 +654,7 @@ static int __init i82975x_init(void)
 {
 	int pci_rc;
 
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -669,7 +668,7 @@ static int __init i82975x_init(void)
 				PCI_DEVICE_ID_INTEL_82975_0, NULL);
 
 		if (!mci_pdev) {
-			debugf0("i82975x pci_get_device fail\n");
+			edac_dbg(0, "i82975x pci_get_device fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
@@ -677,7 +676,7 @@ static int __init i82975x_init(void)
 		pci_rc = i82975x_init_one(mci_pdev, i82975x_pci_tbl);
 
 		if (pci_rc < 0) {
-			debugf0("i82975x init fail\n");
+			edac_dbg(0, "i82975x init fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
@@ -697,7 +696,7 @@ fail0:
 
 static void __exit i82975x_exit(void)
 {
-	debugf3("%s()\n", __func__);
+	edac_dbg(3, "\n");
 
 	pci_unregister_driver(&i82975x_driver);
 
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 0e37462..a1e791e 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -49,34 +49,45 @@ static u32 orig_hid1[2];
 
 /************************ MC SYSFS parts ***********************************/
 
-static ssize_t mpc85xx_mc_inject_data_hi_show(struct mem_ctl_info *mci,
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
+
+static ssize_t mpc85xx_mc_inject_data_hi_show(struct device *dev,
+					      struct device_attribute *mattr,
 					      char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	return sprintf(data, "0x%08x",
 		       in_be32(pdata->mc_vbase +
 			       MPC85XX_MC_DATA_ERR_INJECT_HI));
 }
 
-static ssize_t mpc85xx_mc_inject_data_lo_show(struct mem_ctl_info *mci,
+static ssize_t mpc85xx_mc_inject_data_lo_show(struct device *dev,
+					      struct device_attribute *mattr,
 					      char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	return sprintf(data, "0x%08x",
 		       in_be32(pdata->mc_vbase +
 			       MPC85XX_MC_DATA_ERR_INJECT_LO));
 }
 
-static ssize_t mpc85xx_mc_inject_ctrl_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mpc85xx_mc_inject_ctrl_show(struct device *dev,
+					   struct device_attribute *mattr,
+					   char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	return sprintf(data, "0x%08x",
 		       in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT));
 }
 
-static ssize_t mpc85xx_mc_inject_data_hi_store(struct mem_ctl_info *mci,
+static ssize_t mpc85xx_mc_inject_data_hi_store(struct device *dev,
+					       struct device_attribute *mattr,
 					       const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	if (isdigit(*data)) {
 		out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI,
@@ -86,9 +97,11 @@ static ssize_t mpc85xx_mc_inject_data_hi_store(struct mem_ctl_info *mci,
 	return 0;
 }
 
-static ssize_t mpc85xx_mc_inject_data_lo_store(struct mem_ctl_info *mci,
+static ssize_t mpc85xx_mc_inject_data_lo_store(struct device *dev,
+					       struct device_attribute *mattr,
 					       const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	if (isdigit(*data)) {
 		out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO,
@@ -98,9 +111,11 @@ static ssize_t mpc85xx_mc_inject_data_lo_store(struct mem_ctl_info *mci,
 	return 0;
 }
 
-static ssize_t mpc85xx_mc_inject_ctrl_store(struct mem_ctl_info *mci,
-					    const char *data, size_t count)
+static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev,
+					       struct device_attribute *mattr,
+					       const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	if (isdigit(*data)) {
 		out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT,
@@ -110,38 +125,35 @@ static ssize_t mpc85xx_mc_inject_ctrl_store(struct mem_ctl_info *mci,
 	return 0;
 }
 
-static struct mcidev_sysfs_attribute mpc85xx_mc_sysfs_attributes[] = {
-	{
-	 .attr = {
-		  .name = "inject_data_hi",
-		  .mode = (S_IRUGO | S_IWUSR)
-		  },
-	 .show = mpc85xx_mc_inject_data_hi_show,
-	 .store = mpc85xx_mc_inject_data_hi_store},
-	{
-	 .attr = {
-		  .name = "inject_data_lo",
-		  .mode = (S_IRUGO | S_IWUSR)
-		  },
-	 .show = mpc85xx_mc_inject_data_lo_show,
-	 .store = mpc85xx_mc_inject_data_lo_store},
-	{
-	 .attr = {
-		  .name = "inject_ctrl",
-		  .mode = (S_IRUGO | S_IWUSR)
-		  },
-	 .show = mpc85xx_mc_inject_ctrl_show,
-	 .store = mpc85xx_mc_inject_ctrl_store},
+DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR,
+	    mpc85xx_mc_inject_data_hi_show, mpc85xx_mc_inject_data_hi_store);
+DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR,
+	    mpc85xx_mc_inject_data_lo_show, mpc85xx_mc_inject_data_lo_store);
+DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR,
+	    mpc85xx_mc_inject_ctrl_show, mpc85xx_mc_inject_ctrl_store);
 
-	/* End of list */
-	{
-	 .attr = {.name = NULL}
-	 }
-};
+static int mpc85xx_create_sysfs_attributes(struct mem_ctl_info *mci)
+{
+	int rc;
+
+	rc = device_create_file(&mci->dev, &dev_attr_inject_data_hi);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_data_lo);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_ctrl);
+	if (rc < 0)
+		return rc;
 
-static void mpc85xx_set_mc_sysfs_attributes(struct mem_ctl_info *mci)
+	return 0;
+}
+
+static void mpc85xx_remove_sysfs_attributes(struct mem_ctl_info *mci)
 {
-	mci->mc_driver_sysfs_attributes = mpc85xx_mc_sysfs_attributes;
+	device_remove_file(&mci->dev, &dev_attr_inject_data_hi);
+	device_remove_file(&mci->dev, &dev_attr_inject_data_lo);
+	device_remove_file(&mci->dev, &dev_attr_inject_ctrl);
 }
 
 /**************************** PCI Err device ***************************/
@@ -268,7 +280,7 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op)
 	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);
 
 	if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
-		debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+		edac_dbg(3, "failed edac_pci_add_device()\n");
 		goto err;
 	}
 
@@ -291,7 +303,7 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op)
 	}
 
 	devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 	printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n");
 
 	return 0;
@@ -309,7 +321,7 @@ static int mpc85xx_pci_err_remove(struct platform_device *op)
 	struct edac_pci_ctl_info *pci = dev_get_drvdata(&op->dev);
 	struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR,
 		 orig_pci_err_cap_dr);
@@ -570,7 +582,7 @@ static int __devinit mpc85xx_l2_err_probe(struct platform_device *op)
 	pdata->edac_idx = edac_dev_idx++;
 
 	if (edac_device_add_device(edac_dev) > 0) {
-		debugf3("%s(): failed edac_device_add_device()\n", __func__);
+		edac_dbg(3, "failed edac_device_add_device()\n");
 		goto err;
 	}
 
@@ -598,7 +610,7 @@ static int __devinit mpc85xx_l2_err_probe(struct platform_device *op)
 
 	devres_remove_group(&op->dev, mpc85xx_l2_err_probe);
 
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 	printk(KERN_INFO EDAC_MOD_STR " L2 err registered\n");
 
 	return 0;
@@ -616,7 +628,7 @@ static int mpc85xx_l2_err_remove(struct platform_device *op)
 	struct edac_device_ctl_info *edac_dev = dev_get_drvdata(&op->dev);
 	struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	if (edac_op_state == EDAC_OPSTATE_INT) {
 		out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINTEN, 0);
@@ -813,7 +825,7 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
 	pfn = err_addr >> PAGE_SHIFT;
 
 	for (row_index = 0; row_index < mci->nr_csrows; row_index++) {
-		csrow = &mci->csrows[row_index];
+		csrow = mci->csrows[row_index];
 		if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page))
 			break;
 	}
@@ -854,16 +866,16 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
 		mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n");
 
 	if (err_detect & DDR_EDE_SBE)
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     pfn, err_addr & ~PAGE_MASK, syndrome,
 				     row_index, 0, -1,
-				     mci->ctl_name, "", NULL);
+				     mci->ctl_name, "");
 
 	if (err_detect & DDR_EDE_MBE)
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 				     pfn, err_addr & ~PAGE_MASK, syndrome,
 				     row_index, 0, -1,
-				     mci->ctl_name, "", NULL);
+				     mci->ctl_name, "");
 
 	out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect);
 }
@@ -933,8 +945,8 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
 		u32 start;
 		u32 end;
 
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 +
 				  (index * MPC85XX_MC_CS_BNDS_OFS));
@@ -990,9 +1002,9 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
 	pdata = mci->pvt_info;
 	pdata->name = "mpc85xx_mc_err";
 	pdata->irq = NO_IRQ;
-	mci->dev = &op->dev;
+	mci->pdev = &op->dev;
 	pdata->edac_idx = edac_mc_idx++;
-	dev_set_drvdata(mci->dev, mci);
+	dev_set_drvdata(mci->pdev, mci);
 	mci->ctl_name = pdata->name;
 	mci->dev_name = pdata->name;
 
@@ -1026,7 +1038,7 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
 		goto err;
 	}
 
-	debugf3("%s(): init mci\n", __func__);
+	edac_dbg(3, "init mci\n");
 	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 |
 	    MEM_FLAG_DDR | MEM_FLAG_DDR2;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
@@ -1041,8 +1053,6 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
 
 	mci->scrub_mode = SCRUB_SW_SRC;
 
-	mpc85xx_set_mc_sysfs_attributes(mci);
-
 	mpc85xx_init_csrows(mci);
 
 	/* store the original error disable bits */
@@ -1054,7 +1064,13 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
 	out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, ~0);
 
 	if (edac_mc_add_mc(mci)) {
-		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "failed edac_mc_add_mc()\n");
+		goto err;
+	}
+
+	if (mpc85xx_create_sysfs_attributes(mci)) {
+		edac_mc_del_mc(mci->pdev);
+		edac_dbg(3, "failed edac_mc_add_mc()\n");
 		goto err;
 	}
 
@@ -1088,7 +1104,7 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
 	}
 
 	devres_remove_group(&op->dev, mpc85xx_mc_err_probe);
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 	printk(KERN_INFO EDAC_MOD_STR " MC err registered\n");
 
 	return 0;
@@ -1106,7 +1122,7 @@ static int mpc85xx_mc_err_remove(struct platform_device *op)
 	struct mem_ctl_info *mci = dev_get_drvdata(&op->dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	if (edac_op_state == EDAC_OPSTATE_INT) {
 		out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, 0);
@@ -1117,6 +1133,7 @@ static int mpc85xx_mc_err_remove(struct platform_device *op)
 		 orig_ddr_err_disable);
 	out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe);
 
+	mpc85xx_remove_sysfs_attributes(mci);
 	edac_mc_del_mc(&op->dev);
 	edac_mc_free(mci);
 	return 0;
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c
index b0bb5a3..2b315c2 100644
--- a/drivers/edac/mv64x60_edac.c
+++ b/drivers/edac/mv64x60_edac.c
@@ -169,7 +169,7 @@ static int __devinit mv64x60_pci_err_probe(struct platform_device *pdev)
 		 MV64X60_PCIx_ERR_MASK_VAL);
 
 	if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
-		debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+		edac_dbg(3, "failed edac_pci_add_device()\n");
 		goto err;
 	}
 
@@ -194,7 +194,7 @@ static int __devinit mv64x60_pci_err_probe(struct platform_device *pdev)
 	devres_remove_group(&pdev->dev, mv64x60_pci_err_probe);
 
 	/* get this far and it's successful */
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 
 	return 0;
 
@@ -210,7 +210,7 @@ static int mv64x60_pci_err_remove(struct platform_device *pdev)
 {
 	struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev);
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	edac_pci_del_device(&pdev->dev);
 
@@ -336,7 +336,7 @@ static int __devinit mv64x60_sram_err_probe(struct platform_device *pdev)
 	pdata->edac_idx = edac_dev_idx++;
 
 	if (edac_device_add_device(edac_dev) > 0) {
-		debugf3("%s(): failed edac_device_add_device()\n", __func__);
+		edac_dbg(3, "failed edac_device_add_device()\n");
 		goto err;
 	}
 
@@ -363,7 +363,7 @@ static int __devinit mv64x60_sram_err_probe(struct platform_device *pdev)
 	devres_remove_group(&pdev->dev, mv64x60_sram_err_probe);
 
 	/* get this far and it's successful */
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 
 	return 0;
 
@@ -379,7 +379,7 @@ static int mv64x60_sram_err_remove(struct platform_device *pdev)
 {
 	struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	edac_device_del_device(&pdev->dev);
 	edac_device_free_ctl_info(edac_dev);
@@ -531,7 +531,7 @@ static int __devinit mv64x60_cpu_err_probe(struct platform_device *pdev)
 	pdata->edac_idx = edac_dev_idx++;
 
 	if (edac_device_add_device(edac_dev) > 0) {
-		debugf3("%s(): failed edac_device_add_device()\n", __func__);
+		edac_dbg(3, "failed edac_device_add_device()\n");
 		goto err;
 	}
 
@@ -558,7 +558,7 @@ static int __devinit mv64x60_cpu_err_probe(struct platform_device *pdev)
 	devres_remove_group(&pdev->dev, mv64x60_cpu_err_probe);
 
 	/* get this far and it's successful */
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 
 	return 0;
 
@@ -574,7 +574,7 @@ static int mv64x60_cpu_err_remove(struct platform_device *pdev)
 {
 	struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	edac_device_del_device(&pdev->dev);
 	edac_device_free_ctl_info(edac_dev);
@@ -611,17 +611,17 @@ static void mv64x60_mc_check(struct mem_ctl_info *mci)
 
 	/* first bit clear in ECC Err Reg, 1 bit error, correctable by HW */
 	if (!(reg & 0x1))
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     err_addr >> PAGE_SHIFT,
 				     err_addr & PAGE_MASK, syndrome,
 				     0, 0, -1,
-				     mci->ctl_name, "", NULL);
+				     mci->ctl_name, "");
 	else	/* 2 bit error, UE */
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 				     err_addr >> PAGE_SHIFT,
 				     err_addr & PAGE_MASK, 0,
 				     0, 0, -1,
-				     mci->ctl_name, "", NULL);
+				     mci->ctl_name, "");
 
 	/* clear the error */
 	out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0);
@@ -670,8 +670,8 @@ static void mv64x60_init_csrows(struct mem_ctl_info *mci,
 
 	ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
 
-	csrow = &mci->csrows[0];
-	dimm = csrow->channels[0].dimm;
+	csrow = mci->csrows[0];
+	dimm = csrow->channels[0]->dimm;
 
 	dimm->nr_pages = pdata->total_mem >> PAGE_SHIFT;
 	dimm->grain = 8;
@@ -724,7 +724,7 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
 	}
 
 	pdata = mci->pvt_info;
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	platform_set_drvdata(pdev, mci);
 	pdata->name = "mv64x60_mc_err";
 	pdata->irq = NO_IRQ;
@@ -766,7 +766,7 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
 		goto err2;
 	}
 
-	debugf3("%s(): init mci\n", __func__);
+	edac_dbg(3, "init mci\n");
 	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 	mci->edac_cap = EDAC_FLAG_SECDED;
@@ -790,7 +790,7 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
 	out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL, ctl);
 
 	if (edac_mc_add_mc(mci)) {
-		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "failed edac_mc_add_mc()\n");
 		goto err;
 	}
 
@@ -815,7 +815,7 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
 	}
 
 	/* get this far and it's successful */
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 
 	return 0;
 
@@ -831,7 +831,7 @@ static int mv64x60_mc_err_remove(struct platform_device *pdev)
 {
 	struct mem_ctl_info *mci = platform_get_drvdata(pdev);
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	edac_mc_del_mc(&pdev->dev);
 	edac_mc_free(mci);
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
index b095a90..2d35b78 100644
--- a/drivers/edac/pasemi_edac.c
+++ b/drivers/edac/pasemi_edac.c
@@ -74,7 +74,7 @@ static int system_mmc_id;
 
 static u32 pasemi_edac_get_error_info(struct mem_ctl_info *mci)
 {
-	struct pci_dev *pdev = to_pci_dev(mci->dev);
+	struct pci_dev *pdev = to_pci_dev(mci->pdev);
 	u32 tmp;
 
 	pci_read_config_dword(pdev, MCDEBUG_ERRSTA,
@@ -95,7 +95,7 @@ static u32 pasemi_edac_get_error_info(struct mem_ctl_info *mci)
 
 static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
 {
-	struct pci_dev *pdev = to_pci_dev(mci->dev);
+	struct pci_dev *pdev = to_pci_dev(mci->pdev);
 	u32 errlog1a;
 	u32 cs;
 
@@ -110,16 +110,16 @@ static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
 	/* uncorrectable/multi-bit errors */
 	if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS |
 		      MCDEBUG_ERRSTA_RFL_STATUS)) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
-				     mci->csrows[cs].first_page, 0, 0,
-				     cs, 0, -1, mci->ctl_name, "", NULL);
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
+				     mci->csrows[cs]->first_page, 0, 0,
+				     cs, 0, -1, mci->ctl_name, "");
 	}
 
 	/* correctable/single-bit errors */
 	if (errsta & MCDEBUG_ERRSTA_SBE_STATUS)
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
-				     mci->csrows[cs].first_page, 0, 0,
-				     cs, 0, -1, mci->ctl_name, "", NULL);
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
+				     mci->csrows[cs]->first_page, 0, 0,
+				     cs, 0, -1, mci->ctl_name, "");
 }
 
 static void pasemi_edac_check(struct mem_ctl_info *mci)
@@ -141,8 +141,8 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
 	int index;
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		pci_read_config_dword(pdev,
 				      MCDRAM_RANKCFG + (index * 12),
@@ -225,7 +225,7 @@ static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
 		MCCFG_ERRCOR_ECC_GEN_EN |
 		MCCFG_ERRCOR_ECC_CRR_EN;
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	mci->edac_cap = (errcor & MCCFG_ERRCOR_ECC_GEN_EN) ?
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index f3f9fed..bf09576 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
@@ -727,10 +727,10 @@ ppc4xx_edac_handle_ce(struct mem_ctl_info *mci,
 
 	for (row = 0; row < mci->nr_csrows; row++)
 		if (ppc4xx_edac_check_bank_error(status, row))
-			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 					     0, 0, 0,
 					     row, 0, -1,
-					     message, "", NULL);
+					     message, "");
 }
 
 /**
@@ -758,10 +758,10 @@ ppc4xx_edac_handle_ue(struct mem_ctl_info *mci,
 
 	for (row = 0; row < mci->nr_csrows; row++)
 		if (ppc4xx_edac_check_bank_error(status, row))
-			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 					     page, offset, 0,
 					     row, 0, -1,
-					     message, "", NULL);
+					     message, "");
 }
 
 /**
@@ -1027,9 +1027,9 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
 
 	/* Initial driver pointers and private data */
 
-	mci->dev		= &op->dev;
+	mci->pdev		= &op->dev;
 
-	dev_set_drvdata(mci->dev, mci);
+	dev_set_drvdata(mci->pdev, mci);
 
 	pdata			= mci->pvt_info;
 
@@ -1334,7 +1334,7 @@ static int __devinit ppc4xx_edac_probe(struct platform_device *op)
 	return 0;
 
  fail1:
-	edac_mc_del_mc(mci->dev);
+	edac_mc_del_mc(mci->pdev);
 
  fail:
 	edac_mc_free(mci);
@@ -1368,7 +1368,7 @@ ppc4xx_edac_remove(struct platform_device *op)
 
 	dcr_unmap(pdata->dcr_host, SDRAM_DCR_RESOURCE_LEN);
 
-	edac_mc_del_mc(mci->dev);
+	edac_mc_del_mc(mci->pdev);
 	edac_mc_free(mci);
 
 	return 0;
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index e1cacd1..f854deb 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
@@ -140,7 +140,7 @@ static void r82600_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 	pci_read_config_dword(pdev, R82600_EAP, &info->eapr);
 
 	if (info->eapr & BIT(0))
@@ -179,11 +179,11 @@ static int r82600_process_error_info(struct mem_ctl_info *mci,
 		error_found = 1;
 
 		if (handle_errors)
-			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 					     page, 0, syndrome,
 					     edac_mc_find_csrow_by_page(mci, page),
 					     0, -1,
-					     mci->ctl_name, "", NULL);
+					     mci->ctl_name, "");
 	}
 
 	if (info->eapr & BIT(1)) {	/* UE? */
@@ -191,11 +191,11 @@ static int r82600_process_error_info(struct mem_ctl_info *mci,
 
 		if (handle_errors)
 			/* 82600 doesn't give enough info */
-			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 					     page, 0, 0,
 					     edac_mc_find_csrow_by_page(mci, page),
 					     0, -1,
-					     mci->ctl_name, "", NULL);
+					     mci->ctl_name, "");
 	}
 
 	return error_found;
@@ -205,7 +205,7 @@ static void r82600_check(struct mem_ctl_info *mci)
 {
 	struct r82600_error_info info;
 
-	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+	edac_dbg(1, "MC%d\n", mci->mc_idx);
 	r82600_get_error_info(mci, &info);
 	r82600_process_error_info(mci, &info, 1);
 }
@@ -230,19 +230,19 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	row_high_limit_last = 0;
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		/* find the DRAM Chip Select Base address and mask */
 		pci_read_config_byte(pdev, R82600_DRBA + index, &drbar);
 
-		debugf1("%s() Row=%d DRBA = %#0x\n", __func__, index, drbar);
+		edac_dbg(1, "Row=%d DRBA = %#0x\n", index, drbar);
 
 		row_high_limit = ((u32) drbar << 24);
 /*		row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */
 
-		debugf1("%s() Row=%d, Boundary Address=%#0x, Last = %#0x\n",
-			__func__, index, row_high_limit, row_high_limit_last);
+		edac_dbg(1, "Row=%d, Boundary Address=%#0x, Last = %#0x\n",
+			 index, row_high_limit, row_high_limit_last);
 
 		/* Empty row [p.57] */
 		if (row_high_limit == row_high_limit_last)
@@ -277,14 +277,13 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
 	u32 sdram_refresh_rate;
 	struct r82600_error_info discard;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 	pci_read_config_byte(pdev, R82600_DRAMC, &dramcr);
 	pci_read_config_dword(pdev, R82600_EAP, &eapr);
 	scrub_disabled = eapr & BIT(31);
 	sdram_refresh_rate = dramcr & (BIT(0) | BIT(1));
-	debugf2("%s(): sdram refresh rate = %#0x\n", __func__,
-		sdram_refresh_rate);
-	debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr);
+	edac_dbg(2, "sdram refresh rate = %#0x\n", sdram_refresh_rate);
+	edac_dbg(2, "DRAMC register = %#0x\n", dramcr);
 	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
 	layers[0].size = R82600_NR_CSROWS;
 	layers[0].is_virt_csrow = true;
@@ -295,8 +294,8 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
 	if (mci == NULL)
 		return -ENOMEM;
 
-	debugf0("%s(): mci = %p\n", __func__, mci);
-	mci->dev = &pdev->dev;
+	edac_dbg(0, "mci = %p\n", mci);
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	/* FIXME try to work out if the chip leads have been used for COM2
@@ -311,8 +310,8 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
 
 	if (ecc_enabled(dramcr)) {
 		if (scrub_disabled)
-			debugf3("%s(): mci = %p - Scrubbing disabled! EAP: "
-				"%#0x\n", __func__, mci, eapr);
+			edac_dbg(3, "mci = %p - Scrubbing disabled! EAP: %#0x\n",
+				 mci, eapr);
 	} else
 		mci->edac_cap = EDAC_FLAG_NONE;
 
@@ -329,15 +328,14 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
 	if (edac_mc_add_mc(mci)) {
-		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "failed edac_mc_add_mc()\n");
 		goto fail;
 	}
 
 	/* get this far and it's successful */
 
 	if (disable_hardware_scrub) {
-		debugf3("%s(): Disabling Hardware Scrub (scrub on error)\n",
-			__func__);
+		edac_dbg(3, "Disabling Hardware Scrub (scrub on error)\n");
 		pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31));
 	}
 
@@ -352,7 +350,7 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
 			__func__);
 	}
 
-	debugf3("%s(): success\n", __func__);
+	edac_dbg(3, "success\n");
 	return 0;
 
 fail:
@@ -364,7 +362,7 @@ fail:
 static int __devinit r82600_init_one(struct pci_dev *pdev,
 				const struct pci_device_id *ent)
 {
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/* don't need to call pci_enable_device() */
 	return r82600_probe1(pdev, ent->driver_data);
@@ -374,7 +372,7 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	if (r82600_pci)
 		edac_pci_release_generic_ctl(r82600_pci);
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 36ad17e..f3b1f9f 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -381,8 +381,8 @@ static inline int numrank(u32 mtr)
 	int ranks = (1 << RANK_CNT_BITS(mtr));
 
 	if (ranks > 4) {
-		debugf0("Invalid number of ranks: %d (max = 4) raw value = %x (%04x)",
-			ranks, (unsigned int)RANK_CNT_BITS(mtr), mtr);
+		edac_dbg(0, "Invalid number of ranks: %d (max = 4) raw value = %x (%04x)\n",
+			 ranks, (unsigned int)RANK_CNT_BITS(mtr), mtr);
 		return -EINVAL;
 	}
 
@@ -394,8 +394,8 @@ static inline int numrow(u32 mtr)
 	int rows = (RANK_WIDTH_BITS(mtr) + 12);
 
 	if (rows < 13 || rows > 18) {
-		debugf0("Invalid number of rows: %d (should be between 14 and 17) raw value = %x (%04x)",
-			rows, (unsigned int)RANK_WIDTH_BITS(mtr), mtr);
+		edac_dbg(0, "Invalid number of rows: %d (should be between 14 and 17) raw value = %x (%04x)\n",
+			 rows, (unsigned int)RANK_WIDTH_BITS(mtr), mtr);
 		return -EINVAL;
 	}
 
@@ -407,8 +407,8 @@ static inline int numcol(u32 mtr)
 	int cols = (COL_WIDTH_BITS(mtr) + 10);
 
 	if (cols > 12) {
-		debugf0("Invalid number of cols: %d (max = 4) raw value = %x (%04x)",
-			cols, (unsigned int)COL_WIDTH_BITS(mtr), mtr);
+		edac_dbg(0, "Invalid number of cols: %d (max = 4) raw value = %x (%04x)\n",
+			 cols, (unsigned int)COL_WIDTH_BITS(mtr), mtr);
 		return -EINVAL;
 	}
 
@@ -475,8 +475,8 @@ static struct pci_dev *get_pdev_slot_func(u8 bus, unsigned slot,
 
 		if (PCI_SLOT(sbridge_dev->pdev[i]->devfn) == slot &&
 		    PCI_FUNC(sbridge_dev->pdev[i]->devfn) == func) {
-			debugf1("Associated %02x.%02x.%d with %p\n",
-				bus, slot, func, sbridge_dev->pdev[i]);
+			edac_dbg(1, "Associated %02x.%02x.%d with %p\n",
+				 bus, slot, func, sbridge_dev->pdev[i]);
 			return sbridge_dev->pdev[i];
 		}
 	}
@@ -523,45 +523,45 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 
 	pci_read_config_dword(pvt->pci_br, SAD_CONTROL, &reg);
 	pvt->sbridge_dev->node_id = NODE_ID(reg);
-	debugf0("mc#%d: Node ID: %d, source ID: %d\n",
-		pvt->sbridge_dev->mc,
-		pvt->sbridge_dev->node_id,
-		pvt->sbridge_dev->source_id);
+	edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",
+		 pvt->sbridge_dev->mc,
+		 pvt->sbridge_dev->node_id,
+		 pvt->sbridge_dev->source_id);
 
 	pci_read_config_dword(pvt->pci_ras, RASENABLES, &reg);
 	if (IS_MIRROR_ENABLED(reg)) {
-		debugf0("Memory mirror is enabled\n");
+		edac_dbg(0, "Memory mirror is enabled\n");
 		pvt->is_mirrored = true;
 	} else {
-		debugf0("Memory mirror is disabled\n");
+		edac_dbg(0, "Memory mirror is disabled\n");
 		pvt->is_mirrored = false;
 	}
 
 	pci_read_config_dword(pvt->pci_ta, MCMTR, &pvt->info.mcmtr);
 	if (IS_LOCKSTEP_ENABLED(pvt->info.mcmtr)) {
-		debugf0("Lockstep is enabled\n");
+		edac_dbg(0, "Lockstep is enabled\n");
 		mode = EDAC_S8ECD8ED;
 		pvt->is_lockstep = true;
 	} else {
-		debugf0("Lockstep is disabled\n");
+		edac_dbg(0, "Lockstep is disabled\n");
 		mode = EDAC_S4ECD4ED;
 		pvt->is_lockstep = false;
 	}
 	if (IS_CLOSE_PG(pvt->info.mcmtr)) {
-		debugf0("address map is on closed page mode\n");
+		edac_dbg(0, "address map is on closed page mode\n");
 		pvt->is_close_pg = true;
 	} else {
-		debugf0("address map is on open page mode\n");
+		edac_dbg(0, "address map is on open page mode\n");
 		pvt->is_close_pg = false;
 	}
 
 	pci_read_config_dword(pvt->pci_ddrio, RANK_CFG_A, &reg);
 	if (IS_RDIMM_ENABLED(reg)) {
 		/* FIXME: Can also be LRDIMM */
-		debugf0("Memory is registered\n");
+		edac_dbg(0, "Memory is registered\n");
 		mtype = MEM_RDDR3;
 	} else {
-		debugf0("Memory is unregistered\n");
+		edac_dbg(0, "Memory is unregistered\n");
 		mtype = MEM_DDR3;
 	}
 
@@ -576,7 +576,7 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 				       i, j, 0);
 			pci_read_config_dword(pvt->pci_tad[i],
 					      mtr_regs[j], &mtr);
-			debugf4("Channel #%d  MTR%d = %x\n", i, j, mtr);
+			edac_dbg(4, "Channel #%d  MTR%d = %x\n", i, j, mtr);
 			if (IS_DIMM_PRESENT(mtr)) {
 				pvt->channel[i].dimms++;
 
@@ -588,10 +588,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 				size = (rows * cols * banks * ranks) >> (20 - 3);
 				npages = MiB_TO_PAGES(size);
 
-				debugf0("mc#%d: channel %d, dimm %d, %d Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
-					pvt->sbridge_dev->mc, i, j,
-					size, npages,
-					banks, ranks, rows, cols);
+				edac_dbg(0, "mc#%d: channel %d, dimm %d, %d Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
+					 pvt->sbridge_dev->mc, i, j,
+					 size, npages,
+					 banks, ranks, rows, cols);
 
 				dimm->nr_pages = npages;
 				dimm->grain = 32;
@@ -629,8 +629,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 	tmp_mb = (1 + pvt->tolm) >> 20;
 
 	mb = div_u64_rem(tmp_mb, 1000, &kb);
-	debugf0("TOLM: %u.%03u GB (0x%016Lx)\n",
-		mb, kb, (u64)pvt->tolm);
+	edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tolm);
 
 	/* Address range is already 45:25 */
 	pci_read_config_dword(pvt->pci_sad1, TOHM,
@@ -639,8 +638,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 	tmp_mb = (1 + pvt->tohm) >> 20;
 
 	mb = div_u64_rem(tmp_mb, 1000, &kb);
-	debugf0("TOHM: %u.%03u GB (0x%016Lx)",
-		mb, kb, (u64)pvt->tohm);
+	edac_dbg(0, "TOHM: %u.%03u GB (0x%016Lx)", mb, kb, (u64)pvt->tohm);
 
 	/*
 	 * Step 2) Get SAD range and SAD Interleave list
@@ -663,13 +661,13 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 
 		tmp_mb = (limit + 1) >> 20;
 		mb = div_u64_rem(tmp_mb, 1000, &kb);
-		debugf0("SAD#%d %s up to %u.%03u GB (0x%016Lx) %s reg=0x%08x\n",
-			n_sads,
-			get_dram_attr(reg),
-			mb, kb,
-			((u64)tmp_mb) << 20L,
-			INTERLEAVE_MODE(reg) ? "Interleave: 8:6" : "Interleave: [8:6]XOR[18:16]",
-			reg);
+		edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n",
+			 n_sads,
+			 get_dram_attr(reg),
+			 mb, kb,
+			 ((u64)tmp_mb) << 20L,
+			 INTERLEAVE_MODE(reg) ? "8:6" : "[8:6]XOR[18:16]",
+			 reg);
 		prv = limit;
 
 		pci_read_config_dword(pvt->pci_sad0, interleave_list[n_sads],
@@ -679,8 +677,8 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 			if (j > 0 && sad_interl == sad_pkg(reg, j))
 				break;
 
-			debugf0("SAD#%d, interleave #%d: %d\n",
-			n_sads, j, sad_pkg(reg, j));
+			edac_dbg(0, "SAD#%d, interleave #%d: %d\n",
+				 n_sads, j, sad_pkg(reg, j));
 		}
 	}
 
@@ -697,16 +695,16 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 		tmp_mb = (limit + 1) >> 20;
 
 		mb = div_u64_rem(tmp_mb, 1000, &kb);
-		debugf0("TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
-			n_tads, mb, kb,
-			((u64)tmp_mb) << 20L,
-			(u32)TAD_SOCK(reg),
-			(u32)TAD_CH(reg),
-			(u32)TAD_TGT0(reg),
-			(u32)TAD_TGT1(reg),
-			(u32)TAD_TGT2(reg),
-			(u32)TAD_TGT3(reg),
-			reg);
+		edac_dbg(0, "TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
+			 n_tads, mb, kb,
+			 ((u64)tmp_mb) << 20L,
+			 (u32)TAD_SOCK(reg),
+			 (u32)TAD_CH(reg),
+			 (u32)TAD_TGT0(reg),
+			 (u32)TAD_TGT1(reg),
+			 (u32)TAD_TGT2(reg),
+			 (u32)TAD_TGT3(reg),
+			 reg);
 		prv = limit;
 	}
 
@@ -722,11 +720,11 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 					      &reg);
 			tmp_mb = TAD_OFFSET(reg) >> 20;
 			mb = div_u64_rem(tmp_mb, 1000, &kb);
-			debugf0("TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n",
-				i, j,
-				mb, kb,
-				((u64)tmp_mb) << 20L,
-				reg);
+			edac_dbg(0, "TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n",
+				 i, j,
+				 mb, kb,
+				 ((u64)tmp_mb) << 20L,
+				 reg);
 		}
 	}
 
@@ -747,12 +745,12 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 			tmp_mb = RIR_LIMIT(reg) >> 20;
 			rir_way = 1 << RIR_WAY(reg);
 			mb = div_u64_rem(tmp_mb, 1000, &kb);
-			debugf0("CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
-				i, j,
-				mb, kb,
-				((u64)tmp_mb) << 20L,
-				rir_way,
-				reg);
+			edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
+				 i, j,
+				 mb, kb,
+				 ((u64)tmp_mb) << 20L,
+				 rir_way,
+				 reg);
 
 			for (k = 0; k < rir_way; k++) {
 				pci_read_config_dword(pvt->pci_tad[i],
@@ -761,12 +759,12 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 				tmp_mb = RIR_OFFSET(reg) << 6;
 
 				mb = div_u64_rem(tmp_mb, 1000, &kb);
-				debugf0("CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
-					i, j, k,
-					mb, kb,
-					((u64)tmp_mb) << 20L,
-					(u32)RIR_RNK_TGT(reg),
-					reg);
+				edac_dbg(0, "CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
+					 i, j, k,
+					 mb, kb,
+					 ((u64)tmp_mb) << 20L,
+					 (u32)RIR_RNK_TGT(reg),
+					 reg);
 			}
 		}
 	}
@@ -853,16 +851,16 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 		if (sad_way > 0 && sad_interl == sad_pkg(reg, sad_way))
 			break;
 		sad_interleave[sad_way] = sad_pkg(reg, sad_way);
-		debugf0("SAD interleave #%d: %d\n",
-			sad_way, sad_interleave[sad_way]);
+		edac_dbg(0, "SAD interleave #%d: %d\n",
+			 sad_way, sad_interleave[sad_way]);
 	}
-	debugf0("mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n",
-		pvt->sbridge_dev->mc,
-		n_sads,
-		addr,
-		limit,
-		sad_way + 7,
-		interleave_mode ? "" : "XOR[18:16]");
+	edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n",
+		 pvt->sbridge_dev->mc,
+		 n_sads,
+		 addr,
+		 limit,
+		 sad_way + 7,
+		 interleave_mode ? "" : "XOR[18:16]");
 	if (interleave_mode)
 		idx = ((addr >> 6) ^ (addr >> 16)) & 7;
 	else
@@ -884,8 +882,8 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 		return -EINVAL;
 	}
 	*socket = sad_interleave[idx];
-	debugf0("SAD interleave index: %d (wayness %d) = CPU socket %d\n",
-		idx, sad_way, *socket);
+	edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",
+		 idx, sad_way, *socket);
 
 	/*
 	 * Move to the proper node structure, in order to access the
@@ -972,16 +970,16 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 
 	offset = TAD_OFFSET(tad_offset);
 
-	debugf0("TAD#%d: address 0x%016Lx < 0x%016Lx, socket interleave %d, channel interleave %d (offset 0x%08Lx), index %d, base ch: %d, ch mask: 0x%02lx\n",
-		n_tads,
-		addr,
-		limit,
-		(u32)TAD_SOCK(reg),
-		ch_way,
-		offset,
-		idx,
-		base_ch,
-		*channel_mask);
+	edac_dbg(0, "TAD#%d: address 0x%016Lx < 0x%016Lx, socket interleave %d, channel interleave %d (offset 0x%08Lx), index %d, base ch: %d, ch mask: 0x%02lx\n",
+		 n_tads,
+		 addr,
+		 limit,
+		 (u32)TAD_SOCK(reg),
+		 ch_way,
+		 offset,
+		 idx,
+		 base_ch,
+		 *channel_mask);
 
 	/* Calculate channel address */
 	/* Remove the TAD offset */
@@ -1017,11 +1015,11 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 
 		limit = RIR_LIMIT(reg);
 		mb = div_u64_rem(limit >> 20, 1000, &kb);
-		debugf0("RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
-			n_rir,
-			mb, kb,
-			limit,
-			1 << RIR_WAY(reg));
+		edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
+			 n_rir,
+			 mb, kb,
+			 limit,
+			 1 << RIR_WAY(reg));
 		if  (ch_addr <= limit)
 			break;
 	}
@@ -1042,12 +1040,12 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 			      &reg);
 	*rank = RIR_RNK_TGT(reg);
 
-	debugf0("RIR#%d: channel address 0x%08Lx < 0x%08Lx, RIR interleave %d, index %d\n",
-		n_rir,
-		ch_addr,
-		limit,
-		rir_way,
-		idx);
+	edac_dbg(0, "RIR#%d: channel address 0x%08Lx < 0x%08Lx, RIR interleave %d, index %d\n",
+		 n_rir,
+		 ch_addr,
+		 limit,
+		 rir_way,
+		 idx);
 
 	return 0;
 }
@@ -1064,14 +1062,14 @@ static void sbridge_put_devices(struct sbridge_dev *sbridge_dev)
 {
 	int i;
 
-	debugf0(__FILE__ ": %s()\n", __func__);
+	edac_dbg(0, "\n");
 	for (i = 0; i < sbridge_dev->n_devs; i++) {
 		struct pci_dev *pdev = sbridge_dev->pdev[i];
 		if (!pdev)
 			continue;
-		debugf0("Removing dev %02x:%02x.%d\n",
-			pdev->bus->number,
-			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+		edac_dbg(0, "Removing dev %02x:%02x.%d\n",
+			 pdev->bus->number,
+			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 		pci_dev_put(pdev);
 	}
 }
@@ -1177,10 +1175,9 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
 		return -ENODEV;
 	}
 
-	debugf0("Detected dev %02x:%d.%d PCI ID %04x:%04x\n",
-		bus, dev_descr->dev,
-		dev_descr->func,
-		PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+	edac_dbg(0, "Detected dev %02x:%d.%d PCI ID %04x:%04x\n",
+		 bus, dev_descr->dev, dev_descr->func,
+		 PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
 	/*
 	 * As stated on drivers/pci/search.c, the reference count for
@@ -1297,10 +1294,10 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
 			goto error;
 		}
 
-		debugf0("Associated PCI %02x.%02d.%d with dev = %p\n",
-			sbridge_dev->bus,
-			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-			pdev);
+		edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
+			 sbridge_dev->bus,
+			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+			 pdev);
 	}
 
 	/* Check if everything were registered */
@@ -1435,8 +1432,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 	 * to the group of dimm's where the error may be happening.
 	 */
 	snprintf(msg, sizeof(msg),
-		 "count:%d%s%s area:%s err_code:%04x:%04x socket:%d channel_mask:%ld rank:%d",
-		 core_err_cnt,
+		 "%s%s area:%s err_code:%04x:%04x socket:%d channel_mask:%ld rank:%d",
 		 overflow ? " OVERFLOW" : "",
 		 (uncorrected_error && recoverable) ? " recoverable" : "",
 		 area_type,
@@ -1445,20 +1441,20 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 		 channel_mask,
 		 rank);
 
-	debugf0("%s", msg);
+	edac_dbg(0, "%s\n", msg);
 
 	/* FIXME: need support for channel mask */
 
 	/* Call the helper to output message */
-	edac_mc_handle_error(tp_event, mci,
+	edac_mc_handle_error(tp_event, mci, core_err_cnt,
 			     m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
 			     channel, dimm, -1,
-			     optype, msg, m);
+			     optype, msg);
 	return;
 err_parsing:
-	edac_mc_handle_error(tp_event, mci, 0, 0, 0,
+	edac_mc_handle_error(tp_event, mci, core_err_cnt, 0, 0, 0,
 			     -1, -1, -1,
-			     msg, "", m);
+			     msg, "");
 
 }
 
@@ -1592,8 +1588,7 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
 	struct sbridge_pvt *pvt;
 
 	if (unlikely(!mci || !mci->pvt_info)) {
-		debugf0("MC: " __FILE__ ": %s(): dev = %p\n",
-			__func__, &sbridge_dev->pdev[0]->dev);
+		edac_dbg(0, "MC: dev = %p\n", &sbridge_dev->pdev[0]->dev);
 
 		sbridge_printk(KERN_ERR, "Couldn't find mci handler\n");
 		return;
@@ -1601,13 +1596,13 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
 
 	pvt = mci->pvt_info;
 
-	debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
-		__func__, mci, &sbridge_dev->pdev[0]->dev);
+	edac_dbg(0, "MC: mci = %p, dev = %p\n",
+		 mci, &sbridge_dev->pdev[0]->dev);
 
 	/* Remove MC sysfs nodes */
-	edac_mc_del_mc(mci->dev);
+	edac_mc_del_mc(mci->pdev);
 
-	debugf1("%s: free mci struct\n", mci->ctl_name);
+	edac_dbg(1, "%s: free mci struct\n", mci->ctl_name);
 	kfree(mci->ctl_name);
 	edac_mc_free(mci);
 	sbridge_dev->mci = NULL;
@@ -1638,8 +1633,8 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 	if (unlikely(!mci))
 		return -ENOMEM;
 
-	debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
-		__func__, mci, &sbridge_dev->pdev[0]->dev);
+	edac_dbg(0, "MC: mci = %p, dev = %p\n",
+		 mci, &sbridge_dev->pdev[0]->dev);
 
 	pvt = mci->pvt_info;
 	memset(pvt, 0, sizeof(*pvt));
@@ -1670,12 +1665,11 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 	get_memory_layout(mci);
 
 	/* record ptr to the generic device */
-	mci->dev = &sbridge_dev->pdev[0]->dev;
+	mci->pdev = &sbridge_dev->pdev[0]->dev;
 
 	/* add this new MC control structure to EDAC's list of MCs */
 	if (unlikely(edac_mc_add_mc(mci))) {
-		debugf0("MC: " __FILE__
-			": %s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
 		rc = -EINVAL;
 		goto fail0;
 	}
@@ -1722,7 +1716,8 @@ static int __devinit sbridge_probe(struct pci_dev *pdev,
 	mc = 0;
 
 	list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
-		debugf0("Registering MC#%d (%d of %d)\n", mc, mc + 1, num_mc);
+		edac_dbg(0, "Registering MC#%d (%d of %d)\n",
+			 mc, mc + 1, num_mc);
 		sbridge_dev->mc = mc++;
 		rc = sbridge_register_mci(sbridge_dev);
 		if (unlikely(rc < 0))
@@ -1752,7 +1747,7 @@ static void __devexit sbridge_remove(struct pci_dev *pdev)
 {
 	struct sbridge_dev *sbridge_dev;
 
-	debugf0(__FILE__ ": %s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	/*
 	 * we have a trouble here: pdev value for removal will be wrong, since
@@ -1801,7 +1796,7 @@ static int __init sbridge_init(void)
 {
 	int pci_rc;
 
-	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+	edac_dbg(2, "\n");
 
 	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
 	opstate_init();
@@ -1825,7 +1820,7 @@ static int __init sbridge_init(void)
  */
 static void __exit sbridge_exit(void)
 {
-	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+	edac_dbg(2, "\n");
 	pci_unregister_driver(&sbridge_driver);
 	mce_unregister_decode_chain(&sbridge_mce_dec);
 }
diff --git a/drivers/edac/tile_edac.c b/drivers/edac/tile_edac.c
index 7bb4614..1e904b7 100644
--- a/drivers/edac/tile_edac.c
+++ b/drivers/edac/tile_edac.c
@@ -69,12 +69,12 @@ static void tile_edac_check(struct mem_ctl_info *mci)
 
 	/* Check if the current error count is different from the saved one. */
 	if (mem_error.sbe_count != priv->ce_count) {
-		dev_dbg(mci->dev, "ECC CE err on node %d\n", priv->node);
+		dev_dbg(mci->pdev, "ECC CE err on node %d\n", priv->node);
 		priv->ce_count = mem_error.sbe_count;
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 				     0, 0, 0,
 				     0, 0, -1,
-				     mci->ctl_name, "", NULL);
+				     mci->ctl_name, "");
 	}
 }
 
@@ -84,10 +84,10 @@ static void tile_edac_check(struct mem_ctl_info *mci)
  */
 static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
 {
-	struct csrow_info	*csrow = &mci->csrows[0];
+	struct csrow_info	*csrow = mci->csrows[0];
 	struct tile_edac_priv	*priv = mci->pvt_info;
 	struct mshim_mem_info	mem_info;
-	struct dimm_info *dimm = csrow->channels[0].dimm;
+	struct dimm_info *dimm = csrow->channels[0]->dimm;
 
 	if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_info,
 		sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) !=
@@ -149,7 +149,7 @@ static int __devinit tile_edac_mc_probe(struct platform_device *pdev)
 	priv->node = pdev->id;
 	priv->hv_devhdl = hv_devhdl;
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR2;
 	mci->edac_ctl_cap = EDAC_FLAG_SECDED;
 
diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c
index 1ac7962..08a9926 100644
--- a/drivers/edac/x38_edac.c
+++ b/drivers/edac/x38_edac.c
@@ -103,10 +103,10 @@ static int how_many_channel(struct pci_dev *pdev)
 
 	pci_read_config_byte(pdev, X38_CAPID0 + 8, &capid0_8b);
 	if (capid0_8b & 0x20) {	/* check DCD: Dual Channel Disable */
-		debugf0("In single channel mode.\n");
+		edac_dbg(0, "In single channel mode\n");
 		x38_channel_num = 1;
 	} else {
-		debugf0("In dual channel mode.\n");
+		edac_dbg(0, "In dual channel mode\n");
 		x38_channel_num = 2;
 	}
 
@@ -151,7 +151,7 @@ static void x38_clear_error_info(struct mem_ctl_info *mci)
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * Clear any error bits.
@@ -172,7 +172,7 @@ static void x38_get_and_clear_error_info(struct mem_ctl_info *mci,
 	struct pci_dev *pdev;
 	void __iomem *window = mci->pvt_info;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -215,26 +215,26 @@ static void x38_process_error_info(struct mem_ctl_info *mci,
 		return;
 
 	if ((info->errsts ^ info->errsts2) & X38_ERRSTS_BITS) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
 				     -1, -1, -1,
-				     "UE overwrote CE", "", NULL);
+				     "UE overwrote CE", "");
 		info->errsts = info->errsts2;
 	}
 
 	for (channel = 0; channel < x38_channel_num; channel++) {
 		log = info->eccerrlog[channel];
 		if (log & X38_ECCERRLOG_UE) {
-			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 					     0, 0, 0,
 					     eccerrlog_row(channel, log),
 					     -1, -1,
-					     "x38 UE", "", NULL);
+					     "x38 UE", "");
 		} else if (log & X38_ECCERRLOG_CE) {
-			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 					     0, 0, eccerrlog_syndrome(log),
 					     eccerrlog_row(channel, log),
 					     -1, -1,
-					     "x38 CE", "", NULL);
+					     "x38 CE", "");
 		}
 	}
 }
@@ -243,7 +243,7 @@ static void x38_check(struct mem_ctl_info *mci)
 {
 	struct x38_error_info info;
 
-	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+	edac_dbg(1, "MC%d\n", mci->mc_idx);
 	x38_get_and_clear_error_info(mci, &info);
 	x38_process_error_info(mci, &info);
 }
@@ -331,7 +331,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 	bool stacked;
 	void __iomem *window;
 
-	debugf0("MC: %s()\n", __func__);
+	edac_dbg(0, "MC:\n");
 
 	window = x38_map_mchbar(pdev);
 	if (!window)
@@ -352,9 +352,9 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 	if (!mci)
 		return -ENOMEM;
 
-	debugf3("MC: %s(): init mci\n", __func__);
+	edac_dbg(3, "MC: init mci\n");
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR2;
 
 	mci->edac_ctl_cap = EDAC_FLAG_SECDED;
@@ -378,7 +378,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 	 */
 	for (i = 0; i < mci->nr_csrows; i++) {
 		unsigned long nr_pages;
-		struct csrow_info *csrow = &mci->csrows[i];
+		struct csrow_info *csrow = mci->csrows[i];
 
 		nr_pages = drb_to_nr_pages(drbs, stacked,
 			i / X38_RANKS_PER_CHANNEL,
@@ -388,7 +388,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 			continue;
 
 		for (j = 0; j < x38_channel_num; j++) {
-			struct dimm_info *dimm = csrow->channels[j].dimm;
+			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / x38_channel_num;
 			dimm->grain = nr_pages << PAGE_SHIFT;
@@ -402,12 +402,12 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 
 	rc = -ENODEV;
 	if (edac_mc_add_mc(mci)) {
-		debugf3("MC: %s(): failed edac_mc_add_mc()\n", __func__);
+		edac_dbg(3, "MC: failed edac_mc_add_mc()\n");
 		goto fail;
 	}
 
 	/* get this far and it's successful */
-	debugf3("MC: %s(): success\n", __func__);
+	edac_dbg(3, "MC: success\n");
 	return 0;
 
 fail:
@@ -423,7 +423,7 @@ static int __devinit x38_init_one(struct pci_dev *pdev,
 {
 	int rc;
 
-	debugf0("MC: %s()\n", __func__);
+	edac_dbg(0, "MC:\n");
 
 	if (pci_enable_device(pdev) < 0)
 		return -EIO;
@@ -439,7 +439,7 @@ static void __devexit x38_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0("%s()\n", __func__);
+	edac_dbg(0, "\n");
 
 	mci = edac_mc_del_mc(&pdev->dev);
 	if (!mci)
@@ -472,7 +472,7 @@ static int __init x38_init(void)
 {
 	int pci_rc;
 
-	debugf3("MC: %s()\n", __func__);
+	edac_dbg(3, "MC:\n");
 
 	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
 	opstate_init();
@@ -486,14 +486,14 @@ static int __init x38_init(void)
 		mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
 					PCI_DEVICE_ID_INTEL_X38_HB, NULL);
 		if (!mci_pdev) {
-			debugf0("x38 pci_get_device fail\n");
+			edac_dbg(0, "x38 pci_get_device fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
 
 		pci_rc = x38_init_one(mci_pdev, x38_pci_tbl);
 		if (pci_rc < 0) {
-			debugf0("x38 init fail\n");
+			edac_dbg(0, "x38 init fail\n");
 			pci_rc = -ENODEV;
 			goto fail1;
 		}
@@ -513,7 +513,7 @@ fail0:
 
 static void __exit x38_exit(void)
 {
-	debugf3("MC: %s()\n", __func__);
+	edac_dbg(3, "MC:\n");
 
 	pci_unregister_driver(&x38_driver);
 	if (!x38_registered) {
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 29c5cf8..bb385ac 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -29,4 +29,12 @@ config EXTCON_MAX8997
 	  Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory
 	  detector and switch.
 
+config EXTCON_ARIZONA
+	tristate "Wolfson Arizona EXTCON support"
+	depends on MFD_ARIZONA
+	help
+	  Say Y here to enable support for external accessory detection
+	  with Wolfson Arizona devices. These are audio CODECs with
+	  advanced audio accessory detection support.
+
 endif # MULTISTATE_SWITCH
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 86020bd..e932caa 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -5,3 +5,4 @@
 obj-$(CONFIG_EXTCON)		+= extcon_class.o
 obj-$(CONFIG_EXTCON_GPIO)	+= extcon_gpio.o
 obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
+obj-$(CONFIG_EXTCON_ARIZONA)	+= extcon-arizona.o
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
new file mode 100644
index 0000000..b068bc9
--- /dev/null
+++ b/drivers/extcon/extcon-arizona.c
@@ -0,0 +1,491 @@
+/*
+ * extcon-arizona.c - Extcon driver Wolfson Arizona devices
+ *
+ *  Copyright (C) 2012 Wolfson Microelectronics plc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/extcon.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/pdata.h>
+#include <linux/mfd/arizona/registers.h>
+
+struct arizona_extcon_info {
+	struct device *dev;
+	struct arizona *arizona;
+	struct mutex lock;
+	struct regulator *micvdd;
+
+	int micd_mode;
+	const struct arizona_micd_config *micd_modes;
+	int micd_num_modes;
+
+	bool micd_reva;
+
+	bool mic;
+	bool detecting;
+	int jack_flips;
+
+	struct extcon_dev edev;
+};
+
+static const struct arizona_micd_config micd_default_modes[] = {
+	{ ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
+	{ 0,                  2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
+};
+
+#define ARIZONA_CABLE_MECHANICAL "Mechanical"
+#define ARIZONA_CABLE_HEADPHONE  "Headphone"
+#define ARIZONA_CABLE_HEADSET    "Headset"
+
+static const char *arizona_cable[] = {
+	ARIZONA_CABLE_MECHANICAL,
+	ARIZONA_CABLE_HEADSET,
+	ARIZONA_CABLE_HEADPHONE,
+	NULL,
+};
+
+static const u32 arizona_exclusions[] = {
+	0x6,   /* Headphone and headset */
+	0,
+};
+
+static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
+{
+	struct arizona *arizona = info->arizona;
+
+	gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
+				info->micd_modes[mode].gpio);
+	regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+			   ARIZONA_MICD_BIAS_SRC_MASK,
+			   info->micd_modes[mode].bias);
+	regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
+			   ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
+
+	info->micd_mode = mode;
+
+	dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
+}
+
+static void arizona_start_mic(struct arizona_extcon_info *info)
+{
+	struct arizona *arizona = info->arizona;
+	bool change;
+	int ret;
+
+	info->detecting = true;
+	info->mic = false;
+	info->jack_flips = 0;
+
+	/* Microphone detection can't use idle mode */
+	pm_runtime_get(info->dev);
+
+	ret = regulator_enable(info->micvdd);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
+			ret);
+	}
+
+	if (info->micd_reva) {
+		regmap_write(arizona->regmap, 0x80, 0x3);
+		regmap_write(arizona->regmap, 0x294, 0);
+		regmap_write(arizona->regmap, 0x80, 0x0);
+	}
+
+	regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+				 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
+				 &change);
+	if (!change) {
+		regulator_disable(info->micvdd);
+		pm_runtime_put_autosuspend(info->dev);
+	}
+}
+
+static void arizona_stop_mic(struct arizona_extcon_info *info)
+{
+	struct arizona *arizona = info->arizona;
+	bool change;
+
+	regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+				 ARIZONA_MICD_ENA, 0,
+				 &change);
+
+	if (info->micd_reva) {
+		regmap_write(arizona->regmap, 0x80, 0x3);
+		regmap_write(arizona->regmap, 0x294, 2);
+		regmap_write(arizona->regmap, 0x80, 0x0);
+	}
+
+	if (change) {
+		regulator_disable(info->micvdd);
+		pm_runtime_put_autosuspend(info->dev);
+	}
+}
+
+static irqreturn_t arizona_micdet(int irq, void *data)
+{
+	struct arizona_extcon_info *info = data;
+	struct arizona *arizona = info->arizona;
+	unsigned int val;
+	int ret;
+
+	mutex_lock(&info->lock);
+
+	ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	dev_dbg(arizona->dev, "MICDET: %x\n", val);
+
+	if (!(val & ARIZONA_MICD_VALID)) {
+		dev_warn(arizona->dev, "Microphone detection state invalid\n");
+		mutex_unlock(&info->lock);
+		return IRQ_NONE;
+	}
+
+	/* Due to jack detect this should never happen */
+	if (!(val & ARIZONA_MICD_STS)) {
+		dev_warn(arizona->dev, "Detected open circuit\n");
+		info->detecting = false;
+		goto handled;
+	}
+
+	/* If we got a high impedence we should have a headset, report it. */
+	if (info->detecting && (val & 0x400)) {
+		ret = extcon_set_cable_state(&info->edev,
+					     ARIZONA_CABLE_HEADSET, true);
+
+		if (ret != 0)
+			dev_err(arizona->dev, "Headset report failed: %d\n",
+				ret);
+
+		info->mic = true;
+		info->detecting = false;
+		goto handled;
+	}
+
+	/* If we detected a lower impedence during initial startup
+	 * then we probably have the wrong polarity, flip it.  Don't
+	 * do this for the lowest impedences to speed up detection of
+	 * plain headphones.  If both polarities report a low
+	 * impedence then give up and report headphones.
+	 */
+	if (info->detecting && (val & 0x3f8)) {
+		info->jack_flips++;
+
+		if (info->jack_flips >= info->micd_num_modes) {
+			dev_dbg(arizona->dev, "Detected headphone\n");
+			info->detecting = false;
+			ret = extcon_set_cable_state(&info->edev,
+						     ARIZONA_CABLE_HEADPHONE,
+						     true);
+			if (ret != 0)
+				dev_err(arizona->dev,
+					"Headphone report failed: %d\n",
+				ret);
+		} else {
+			info->micd_mode++;
+			if (info->micd_mode == info->micd_num_modes)
+				info->micd_mode = 0;
+			arizona_extcon_set_mode(info, info->micd_mode);
+
+			info->jack_flips++;
+		}
+
+		goto handled;
+	}
+
+	/*
+	 * If we're still detecting and we detect a short then we've
+	 * got a headphone.  Otherwise it's a button press, the
+	 * button reporting is stubbed out for now.
+	 */
+	if (val & 0x3fc) {
+		if (info->mic) {
+			dev_dbg(arizona->dev, "Mic button detected\n");
+
+		} else if (info->detecting) {
+			dev_dbg(arizona->dev, "Headphone detected\n");
+			info->detecting = false;
+			arizona_stop_mic(info);
+
+			ret = extcon_set_cable_state(&info->edev,
+						     ARIZONA_CABLE_HEADPHONE,
+						     true);
+			if (ret != 0)
+				dev_err(arizona->dev,
+					"Headphone report failed: %d\n",
+				ret);
+		} else {
+			dev_warn(arizona->dev, "Button with no mic: %x\n",
+				 val);
+		}
+	} else {
+		dev_dbg(arizona->dev, "Mic button released\n");
+	}
+
+handled:
+	pm_runtime_mark_last_busy(info->dev);
+	mutex_unlock(&info->lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t arizona_jackdet(int irq, void *data)
+{
+	struct arizona_extcon_info *info = data;
+	struct arizona *arizona = info->arizona;
+	unsigned int val;
+	int ret;
+
+	pm_runtime_get_sync(info->dev);
+
+	mutex_lock(&info->lock);
+
+	ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
+			ret);
+		mutex_unlock(&info->lock);
+		pm_runtime_put_autosuspend(info->dev);
+		return IRQ_NONE;
+	}
+
+	if (val & ARIZONA_JD1_STS) {
+		dev_dbg(arizona->dev, "Detected jack\n");
+		ret = extcon_set_cable_state(&info->edev,
+					     ARIZONA_CABLE_MECHANICAL, true);
+
+		if (ret != 0)
+			dev_err(arizona->dev, "Mechanical report failed: %d\n",
+				ret);
+
+		arizona_start_mic(info);
+	} else {
+		dev_dbg(arizona->dev, "Detected jack removal\n");
+
+		arizona_stop_mic(info);
+
+		ret = extcon_update_state(&info->edev, 0xffffffff, 0);
+		if (ret != 0)
+			dev_err(arizona->dev, "Removal report failed: %d\n",
+				ret);
+	}
+
+	mutex_unlock(&info->lock);
+
+	pm_runtime_mark_last_busy(info->dev);
+	pm_runtime_put_autosuspend(info->dev);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit arizona_extcon_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct arizona_pdata *pdata;
+	struct arizona_extcon_info *info;
+	int ret, mode;
+
+	pdata = dev_get_platdata(arizona->dev);
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
+	if (IS_ERR(info->micvdd)) {
+		ret = PTR_ERR(info->micvdd);
+		dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
+		goto err;
+	}
+
+	mutex_init(&info->lock);
+	info->arizona = arizona;
+	info->dev = &pdev->dev;
+	info->detecting = true;
+	platform_set_drvdata(pdev, info);
+
+	switch (arizona->type) {
+	case WM5102:
+		switch (arizona->rev) {
+		case 0:
+			info->micd_reva = true;
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	info->edev.name = "Headset Jack";
+	info->edev.supported_cable = arizona_cable;
+	info->edev.mutually_exclusive = arizona_exclusions;
+
+	ret = extcon_dev_register(&info->edev, arizona->dev);
+	if (ret < 0) {
+		dev_err(arizona->dev, "extcon_dev_regster() failed: %d\n",
+			ret);
+		goto err;
+	}
+
+	if (pdata->num_micd_configs) {
+		info->micd_modes = pdata->micd_configs;
+		info->micd_num_modes = pdata->num_micd_configs;
+	} else {
+		info->micd_modes = micd_default_modes;
+		info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
+	}
+
+	if (arizona->pdata.micd_pol_gpio > 0) {
+		if (info->micd_modes[0].gpio)
+			mode = GPIOF_OUT_INIT_HIGH;
+		else
+			mode = GPIOF_OUT_INIT_LOW;
+
+		ret = devm_gpio_request_one(&pdev->dev,
+					    arizona->pdata.micd_pol_gpio,
+					    mode,
+					    "MICD polarity");
+		if (ret != 0) {
+			dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
+				arizona->pdata.micd_pol_gpio, ret);
+			goto err_register;
+		}
+	}
+
+	arizona_extcon_set_mode(info, 0);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_idle(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+
+	ret = arizona_request_irq(arizona, ARIZONA_IRQ_JD_RISE,
+				  "JACKDET rise", arizona_jackdet, info);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
+			ret);
+		goto err_register;
+	}
+
+	ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 1);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
+			ret);
+		goto err_rise;
+	}
+
+	ret = arizona_request_irq(arizona, ARIZONA_IRQ_JD_FALL,
+				  "JACKDET fall", arizona_jackdet, info);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
+		goto err_rise_wake;
+	}
+
+	ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 1);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
+			ret);
+		goto err_fall;
+	}
+
+	ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
+				  "MICDET", arizona_micdet, info);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
+		goto err_fall_wake;
+	}
+
+	regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+			   ARIZONA_MICD_BIAS_STARTTIME_MASK |
+			   ARIZONA_MICD_RATE_MASK,
+			   7 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT |
+			   8 << ARIZONA_MICD_RATE_SHIFT);
+
+	arizona_clk32k_enable(arizona);
+	regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
+			   ARIZONA_JD1_DB, ARIZONA_JD1_DB);
+	regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
+			   ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
+
+	pm_runtime_put(&pdev->dev);
+
+	return 0;
+
+err_fall_wake:
+	arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 0);
+err_fall:
+	arizona_free_irq(arizona, ARIZONA_IRQ_JD_FALL, info);
+err_rise_wake:
+	arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0);
+err_rise:
+	arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info);
+err_register:
+	pm_runtime_disable(&pdev->dev);
+	extcon_dev_unregister(&info->edev);
+err:
+	return ret;
+}
+
+static int __devexit arizona_extcon_remove(struct platform_device *pdev)
+{
+	struct arizona_extcon_info *info = platform_get_drvdata(pdev);
+	struct arizona *arizona = info->arizona;
+
+	pm_runtime_disable(&pdev->dev);
+
+	arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0);
+	arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 0);
+	arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
+	arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info);
+	arizona_free_irq(arizona, ARIZONA_IRQ_JD_FALL, info);
+	regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
+			   ARIZONA_JD1_ENA, 0);
+	arizona_clk32k_disable(arizona);
+	extcon_dev_unregister(&info->edev);
+
+	return 0;
+}
+
+static struct platform_driver arizona_extcon_driver = {
+	.driver		= {
+		.name	= "arizona-extcon",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= arizona_extcon_probe,
+	.remove		= __devexit_p(arizona_extcon_remove),
+};
+
+module_platform_driver(arizona_extcon_driver);
+
+MODULE_DESCRIPTION("Arizona Extcon driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:extcon-arizona");
diff --git a/drivers/extcon/extcon_class.c b/drivers/extcon/extcon_class.c
index 159aeb0..f6419f9 100644
--- a/drivers/extcon/extcon_class.c
+++ b/drivers/extcon/extcon_class.c
@@ -65,7 +65,7 @@ const char *extcon_cable_name[] = {
 	NULL,
 };
 
-struct class *extcon_class;
+static struct class *extcon_class;
 #if defined(CONFIG_ANDROID)
 static struct class_compat *switch_class;
 #endif /* CONFIG_ANDROID */
diff --git a/drivers/extcon/extcon_gpio.c b/drivers/extcon/extcon_gpio.c
index 8a0dcc1..fe3db45 100644
--- a/drivers/extcon/extcon_gpio.c
+++ b/drivers/extcon/extcon_gpio.c
@@ -105,25 +105,25 @@ static int __devinit gpio_extcon_probe(struct platform_device *pdev)
 
 	ret = extcon_dev_register(&extcon_data->edev, &pdev->dev);
 	if (ret < 0)
-		goto err_extcon_dev_register;
+		return ret;
 
 	ret = gpio_request_one(extcon_data->gpio, GPIOF_DIR_IN, pdev->name);
 	if (ret < 0)
-		goto err_request_gpio;
+		goto err;
 
 	INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);
 
 	extcon_data->irq = gpio_to_irq(extcon_data->gpio);
 	if (extcon_data->irq < 0) {
 		ret = extcon_data->irq;
-		goto err_detect_irq_num_failed;
+		goto err;
 	}
 
 	ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler,
 				      pdata->irq_flags, pdev->name,
 				      extcon_data);
 	if (ret < 0)
-		goto err_request_irq;
+		goto err;
 
 	platform_set_drvdata(pdev, extcon_data);
 	/* Perform initial detection */
@@ -131,13 +131,8 @@ static int __devinit gpio_extcon_probe(struct platform_device *pdev)
 
 	return 0;
 
-err_request_irq:
-err_detect_irq_num_failed:
-	gpio_free(extcon_data->gpio);
-err_request_gpio:
+err:
 	extcon_dev_unregister(&extcon_data->edev);
-err_extcon_dev_register:
-	devm_kfree(&pdev->dev, extcon_data);
 
 	return ret;
 }
@@ -148,9 +143,7 @@ static int __devexit gpio_extcon_remove(struct platform_device *pdev)
 
 	cancel_delayed_work_sync(&extcon_data->work);
 	free_irq(extcon_data->irq, extcon_data);
-	gpio_free(extcon_data->gpio);
 	extcon_dev_unregister(&extcon_data->edev);
-	devm_kfree(&pdev->dev, extcon_data);
 
 	return 0;
 }
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c
index 8382e27..38c0aa6 100644
--- a/drivers/firewire/core-iso.c
+++ b/drivers/firewire/core-iso.c
@@ -146,7 +146,7 @@ EXPORT_SYMBOL(fw_iso_buffer_destroy);
 /* Convert DMA address to offset into virtually contiguous buffer. */
 size_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed)
 {
-	int i;
+	size_t i;
 	dma_addr_t address;
 	ssize_t offset;
 
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 780708d..87d6f2d 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -525,9 +525,10 @@ const struct fw_address_region fw_high_memory_region =
 	{ .start = 0x000100000000ULL, .end = 0xffffe0000000ULL,  };
 EXPORT_SYMBOL(fw_high_memory_region);
 
-#if 0
-const struct fw_address_region fw_low_memory_region =
+static const struct fw_address_region low_memory_region =
 	{ .start = 0x000000000000ULL, .end = 0x000100000000ULL,  };
+
+#if 0
 const struct fw_address_region fw_private_region =
 	{ .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL,  };
 const struct fw_address_region fw_csr_region =
@@ -1198,6 +1199,23 @@ static struct fw_address_handler registers = {
 	.address_callback	= handle_registers,
 };
 
+static void handle_low_memory(struct fw_card *card, struct fw_request *request,
+		int tcode, int destination, int source, int generation,
+		unsigned long long offset, void *payload, size_t length,
+		void *callback_data)
+{
+	/*
+	 * This catches requests not handled by the physical DMA unit,
+	 * i.e., wrong transaction types or unauthorized source nodes.
+	 */
+	fw_send_response(card, request, RCODE_TYPE_ERROR);
+}
+
+static struct fw_address_handler low_memory = {
+	.length			= 0x000100000000ULL,
+	.address_callback	= handle_low_memory,
+};
+
 MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
 MODULE_DESCRIPTION("Core IEEE1394 transaction logic");
 MODULE_LICENSE("GPL");
@@ -1259,6 +1277,7 @@ static int __init fw_core_init(void)
 
 	fw_core_add_address_handler(&topology_map, &topology_map_region);
 	fw_core_add_address_handler(&registers, &registers_region);
+	fw_core_add_address_handler(&low_memory, &low_memory_region);
 	fw_core_add_descriptor(&vendor_id_descriptor);
 	fw_core_add_descriptor(&model_id_descriptor);
 
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index c1af05e..c788dbd 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -191,6 +191,7 @@ struct fw_ohci {
 	unsigned quirks;
 	unsigned int pri_req_max;
 	u32 bus_time;
+	bool bus_time_running;
 	bool is_root;
 	bool csr_state_setclear_abdicate;
 	int n_ir;
@@ -1726,6 +1727,13 @@ static u32 update_bus_time(struct fw_ohci *ohci)
 {
 	u32 cycle_time_seconds = get_cycle_time(ohci) >> 25;
 
+	if (unlikely(!ohci->bus_time_running)) {
+		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_cycle64Seconds);
+		ohci->bus_time = (lower_32_bits(get_seconds()) & ~0x7f) |
+		                 (cycle_time_seconds & 0x40);
+		ohci->bus_time_running = true;
+	}
+
 	if ((ohci->bus_time & 0x40) != (cycle_time_seconds & 0x40))
 		ohci->bus_time += 0x40;
 
@@ -2213,7 +2221,7 @@ static int ohci_enable(struct fw_card *card,
 {
 	struct fw_ohci *ohci = fw_ohci(card);
 	struct pci_dev *dev = to_pci_dev(card->device);
-	u32 lps, seconds, version, irqs;
+	u32 lps, version, irqs;
 	int i, ret;
 
 	if (software_reset(ohci)) {
@@ -2269,9 +2277,12 @@ static int ohci_enable(struct fw_card *card,
 		  (OHCI1394_MAX_PHYS_RESP_RETRIES << 8) |
 		  (200 << 16));
 
-	seconds = lower_32_bits(get_seconds());
-	reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25);
-	ohci->bus_time = seconds & ~0x3f;
+	ohci->bus_time_running = false;
+
+	for (i = 0; i < 32; i++)
+		if (ohci->ir_context_support & (1 << i))
+			reg_write(ohci, OHCI1394_IsoRcvContextControlClear(i),
+				  IR_CONTEXT_MULTI_CHANNEL_MODE);
 
 	version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
 	if (version >= OHCI_VERSION_1_1) {
@@ -2369,7 +2380,6 @@ static int ohci_enable(struct fw_card *card,
 		OHCI1394_postedWriteErr |
 		OHCI1394_selfIDComplete |
 		OHCI1394_regAccessFail |
-		OHCI1394_cycle64Seconds |
 		OHCI1394_cycleInconsistent |
 		OHCI1394_unrecoverableError |
 		OHCI1394_cycleTooLong |
@@ -2658,7 +2668,8 @@ static void ohci_write_csr(struct fw_card *card, int csr_offset, u32 value)
 
 	case CSR_BUS_TIME:
 		spin_lock_irqsave(&ohci->lock, flags);
-		ohci->bus_time = (ohci->bus_time & 0x7f) | (value & ~0x7f);
+		ohci->bus_time = (update_bus_time(ohci) & 0x40) |
+		                 (value & ~0x7f);
 		spin_unlock_irqrestore(&ohci->lock, flags);
 		break;
 
@@ -3539,6 +3550,13 @@ static int __devinit pci_probe(struct pci_dev *dev,
 
 	INIT_WORK(&ohci->bus_reset_work, bus_reset_work);
 
+	if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM) ||
+	    pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE) {
+		dev_err(&dev->dev, "invalid MMIO resource\n");
+		err = -ENXIO;
+		goto fail_disable;
+	}
+
 	err = pci_request_region(dev, 0, ohci_driver_name);
 	if (err) {
 		dev_err(&dev->dev, "MMIO resource unavailable\n");
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 9e9947c..1077754 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -98,6 +98,7 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
 
 	return 0;
 }
+EXPORT_SYMBOL(devm_gpio_request_one);
 
 /**
  *      devm_gpio_free - free an interrupt
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 1c313c7..de24af2 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -98,12 +98,11 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
 	if (chip->gpio_chip.ngpio <= 8)
 		ret = i2c_smbus_write_byte_data(chip->client, reg, val);
 	else if (chip->gpio_chip.ngpio == 24) {
-		ret = i2c_smbus_write_word_data(chip->client,
+		cpu_to_le32s(&val);
+		ret = i2c_smbus_write_i2c_block_data(chip->client,
 						(reg << 2) | REG_ADDR_AI,
-						val & 0xffff);
-		ret = i2c_smbus_write_byte_data(chip->client,
-						(reg << 2) + 2,
-						(val & 0xff0000) >> 16);
+						3,
+						(u8 *) &val);
 	}
 	else {
 		switch (chip->chip_type) {
@@ -135,22 +134,27 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
 {
 	int ret;
 
-	if (chip->gpio_chip.ngpio <= 8)
+	if (chip->gpio_chip.ngpio <= 8) {
 		ret = i2c_smbus_read_byte_data(chip->client, reg);
-	else if (chip->gpio_chip.ngpio == 24) {
-		ret =  i2c_smbus_read_word_data(chip->client, reg << 2);
-		ret |= (i2c_smbus_read_byte_data(chip->client,
-						 (reg << 2) + 2)<<16);
+		*val = ret;
 	}
-	else
+	else if (chip->gpio_chip.ngpio == 24) {
+		*val = 0;
+		ret = i2c_smbus_read_i2c_block_data(chip->client,
+						(reg << 2) | REG_ADDR_AI,
+						3,
+						(u8 *) val);
+		le32_to_cpus(val);
+	} else {
 		ret = i2c_smbus_read_word_data(chip->client, reg << 1);
+		*val = ret;
+	}
 
 	if (ret < 0) {
 		dev_err(&chip->client->dev, "failed reading register\n");
 		return ret;
 	}
 
-	*val = (u32)ret;
 	return 0;
 }
 
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index d18068a..8389d4a 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -21,7 +21,7 @@
 #include <linux/of_gpio.h>
 #include <linux/slab.h>
 
-/* Private data structure for of_gpiochip_is_match */
+/* Private data structure for of_gpiochip_find_and_xlate */
 struct gg_data {
 	enum of_gpio_flags *flags;
 	struct of_phandle_args gpiospec;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 5363e9c..4fa00fc 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1765,6 +1765,64 @@ static const struct file_operations i915_max_freq_fops = {
 };
 
 static ssize_t
+i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max,
+		   loff_t *ppos)
+{
+	struct drm_device *dev = filp->private_data;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	char buf[80];
+	int len;
+
+	len = snprintf(buf, sizeof(buf),
+		       "min freq: %d\n", dev_priv->min_delay * 50);
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
+	return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+}
+
+static ssize_t
+i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt,
+		    loff_t *ppos)
+{
+	struct drm_device *dev = filp->private_data;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	char buf[20];
+	int val = 1;
+
+	if (cnt > 0) {
+		if (cnt > sizeof(buf) - 1)
+			return -EINVAL;
+
+		if (copy_from_user(buf, ubuf, cnt))
+			return -EFAULT;
+		buf[cnt] = 0;
+
+		val = simple_strtoul(buf, NULL, 0);
+	}
+
+	DRM_DEBUG_DRIVER("Manually setting min freq to %d\n", val);
+
+	/*
+	 * Turbo will still be enabled, but won't go below the set value.
+	 */
+	dev_priv->min_delay = val / 50;
+
+	gen6_set_rps(dev, val / 50);
+
+	return cnt;
+}
+
+static const struct file_operations i915_min_freq_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = i915_min_freq_read,
+	.write = i915_min_freq_write,
+	.llseek = default_llseek,
+};
+
+static ssize_t
 i915_cache_sharing_read(struct file *filp,
 		   char __user *ubuf,
 		   size_t max,
@@ -1997,6 +2055,12 @@ int i915_debugfs_init(struct drm_minor *minor)
 		return ret;
 
 	ret = i915_debugfs_create(minor->debugfs_root, minor,
+				  "i915_min_freq",
+				  &i915_min_freq_fops);
+	if (ret)
+		return ret;
+
+	ret = i915_debugfs_create(minor->debugfs_root, minor,
 				  "i915_cache_sharing",
 				  &i915_cache_sharing_fops);
 	if (ret)
@@ -2028,6 +2092,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
 				 1, minor);
 	drm_debugfs_remove_files((struct drm_info_list *) &i915_max_freq_fops,
 				 1, minor);
+	drm_debugfs_remove_files((struct drm_info_list *) &i915_min_freq_fops,
+				 1, minor);
 	drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops,
 				 1, minor);
 	drm_debugfs_remove_files((struct drm_info_list *) &i915_ring_stop_fops,
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index f947926..262a74d 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1803,6 +1803,7 @@ struct drm_ioctl_desc i915_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, intel_sprite_get_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED),
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index b0b676a..7cc36db 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -657,6 +657,8 @@ typedef struct drm_i915_private {
 		/** PPGTT used for aliasing the PPGTT with the GTT */
 		struct i915_hw_ppgtt *aliasing_ppgtt;
 
+		u32 *l3_remap_info;
+
 		struct shrinker inactive_shrinker;
 
 		/**
@@ -817,6 +819,8 @@ typedef struct drm_i915_private {
 
 	struct drm_property *broadcast_rgb_property;
 	struct drm_property *force_audio_property;
+
+	struct work_struct parity_error_work;
 } drm_i915_private_t;
 
 /* Iterate over initialised rings */
@@ -1237,6 +1241,8 @@ int i915_gem_get_tiling(struct drm_device *dev, void *data,
 			struct drm_file *file_priv);
 int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 				struct drm_file *file_priv);
+int i915_gem_wait_ioctl(struct drm_device *dev, void *data,
+			struct drm_file *file_priv);
 void i915_gem_load(struct drm_device *dev);
 int i915_gem_init_object(struct drm_gem_object *obj);
 int __must_check i915_gem_flush_ring(struct intel_ring_buffer *ring,
@@ -1315,6 +1321,7 @@ int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj,
 int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
 int __must_check i915_gem_init(struct drm_device *dev);
 int __must_check i915_gem_init_hw(struct drm_device *dev);
+void i915_gem_l3_remap(struct drm_device *dev);
 void i915_gem_init_swizzling(struct drm_device *dev);
 void i915_gem_init_ppgtt(struct drm_device *dev);
 void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
@@ -1323,8 +1330,8 @@ int __must_check i915_gem_idle(struct drm_device *dev);
 int __must_check i915_add_request(struct intel_ring_buffer *ring,
 				  struct drm_file *file,
 				  struct drm_i915_gem_request *request);
-int __must_check i915_wait_request(struct intel_ring_buffer *ring,
-				   uint32_t seqno);
+int __must_check i915_wait_seqno(struct intel_ring_buffer *ring,
+				 uint32_t seqno);
 int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 int __must_check
 i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 288d7b8..af67803 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1899,34 +1899,82 @@ i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno)
 	return ret;
 }
 
+/**
+ * __wait_seqno - wait until execution of seqno has finished
+ * @ring: the ring expected to report seqno
+ * @seqno: duh!
+ * @interruptible: do an interruptible wait (normally yes)
+ * @timeout: in - how long to wait (NULL forever); out - how much time remaining
+ *
+ * Returns 0 if the seqno was found within the alloted time. Else returns the
+ * errno with remaining time filled in timeout argument.
+ */
 static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
-			bool interruptible)
+			bool interruptible, struct timespec *timeout)
 {
 	drm_i915_private_t *dev_priv = ring->dev->dev_private;
-	int ret = 0;
+	struct timespec before, now, wait_time={1,0};
+	unsigned long timeout_jiffies;
+	long end;
+	bool wait_forever = true;
 
 	if (i915_seqno_passed(ring->get_seqno(ring), seqno))
 		return 0;
 
 	trace_i915_gem_request_wait_begin(ring, seqno);
+
+	if (timeout != NULL) {
+		wait_time = *timeout;
+		wait_forever = false;
+	}
+
+	timeout_jiffies = timespec_to_jiffies(&wait_time);
+
 	if (WARN_ON(!ring->irq_get(ring)))
 		return -ENODEV;
 
+	/* Record current time in case interrupted by signal, or wedged * */
+	getrawmonotonic(&before);
+
 #define EXIT_COND \
 	(i915_seqno_passed(ring->get_seqno(ring), seqno) || \
 	atomic_read(&dev_priv->mm.wedged))
+	do {
+		if (interruptible)
+			end = wait_event_interruptible_timeout(ring->irq_queue,
+							       EXIT_COND,
+							       timeout_jiffies);
+		else
+			end = wait_event_timeout(ring->irq_queue, EXIT_COND,
+						 timeout_jiffies);
 
-	if (interruptible)
-		ret = wait_event_interruptible(ring->irq_queue,
-					       EXIT_COND);
-	else
-		wait_event(ring->irq_queue, EXIT_COND);
+		if (atomic_read(&dev_priv->mm.wedged))
+			end = -EAGAIN;
+	} while (end == 0 && wait_forever);
+
+	getrawmonotonic(&now);
 
 	ring->irq_put(ring);
 	trace_i915_gem_request_wait_end(ring, seqno);
 #undef EXIT_COND
 
-	return ret;
+	if (timeout) {
+		struct timespec sleep_time = timespec_sub(now, before);
+		*timeout = timespec_sub(*timeout, sleep_time);
+	}
+
+	switch (end) {
+	case -EAGAIN: /* Wedged */
+	case -ERESTARTSYS: /* Signal */
+		return (int)end;
+	case 0: /* Timeout */
+		if (timeout)
+			set_normalized_timespec(timeout, 0, 0);
+		return -ETIME;
+	default: /* Completed */
+		WARN_ON(end < 0); /* We're not aware of other errors */
+		return 0;
+	}
 }
 
 /**
@@ -1934,8 +1982,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
  * request and object lists appropriately for that event.
  */
 int
-i915_wait_request(struct intel_ring_buffer *ring,
-		  uint32_t seqno)
+i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno)
 {
 	drm_i915_private_t *dev_priv = ring->dev->dev_private;
 	int ret = 0;
@@ -1950,9 +1997,7 @@ i915_wait_request(struct intel_ring_buffer *ring,
 	if (ret)
 		return ret;
 
-	ret = __wait_seqno(ring, seqno, dev_priv->mm.interruptible);
-	if (atomic_read(&dev_priv->mm.wedged))
-		ret = -EAGAIN;
+	ret = __wait_seqno(ring, seqno, dev_priv->mm.interruptible, NULL);
 
 	return ret;
 }
@@ -1975,7 +2020,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
 	 * it.
 	 */
 	if (obj->active) {
-		ret = i915_wait_request(obj->ring, obj->last_rendering_seqno);
+		ret = i915_wait_seqno(obj->ring, obj->last_rendering_seqno);
 		if (ret)
 			return ret;
 		i915_gem_retire_requests_ring(obj->ring);
@@ -1985,6 +2030,110 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
 }
 
 /**
+ * Ensures that an object will eventually get non-busy by flushing any required
+ * write domains, emitting any outstanding lazy request and retiring and
+ * completed requests.
+ */
+static int
+i915_gem_object_flush_active(struct drm_i915_gem_object *obj)
+{
+	int ret;
+
+	if (obj->active) {
+		ret = i915_gem_object_flush_gpu_write_domain(obj);
+		if (ret)
+			return ret;
+
+		ret = i915_gem_check_olr(obj->ring,
+					 obj->last_rendering_seqno);
+		if (ret)
+			return ret;
+		i915_gem_retire_requests_ring(obj->ring);
+	}
+
+	return 0;
+}
+
+/**
+ * i915_gem_wait_ioctl - implements DRM_IOCTL_I915_GEM_WAIT
+ * @DRM_IOCTL_ARGS: standard ioctl arguments
+ *
+ * Returns 0 if successful, else an error is returned with the remaining time in
+ * the timeout parameter.
+ *  -ETIME: object is still busy after timeout
+ *  -ERESTARTSYS: signal interrupted the wait
+ *  -ENONENT: object doesn't exist
+ * Also possible, but rare:
+ *  -EAGAIN: GPU wedged
+ *  -ENOMEM: damn
+ *  -ENODEV: Internal IRQ fail
+ *  -E?: The add request failed
+ *
+ * The wait ioctl with a timeout of 0 reimplements the busy ioctl. With any
+ * non-zero timeout parameter the wait ioctl will wait for the given number of
+ * nanoseconds on an object becoming unbusy. Since the wait itself does so
+ * without holding struct_mutex the object may become re-busied before this
+ * function completes. A similar but shorter * race condition exists in the busy
+ * ioctl
+ */
+int
+i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
+{
+	struct drm_i915_gem_wait *args = data;
+	struct drm_i915_gem_object *obj;
+	struct intel_ring_buffer *ring = NULL;
+	struct timespec timeout;
+	u32 seqno = 0;
+	int ret = 0;
+
+	timeout = ns_to_timespec(args->timeout_ns);
+
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
+
+	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->bo_handle));
+	if (&obj->base == NULL) {
+		mutex_unlock(&dev->struct_mutex);
+		return -ENOENT;
+	}
+
+	/* Need to make sure the object gets inactive eventually. */
+	ret = i915_gem_object_flush_active(obj);
+	if (ret)
+		goto out;
+
+	if (obj->active) {
+		seqno = obj->last_rendering_seqno;
+		ring = obj->ring;
+	}
+
+	if (seqno == 0)
+		 goto out;
+
+	/* Do this after OLR check to make sure we make forward progress polling
+	 * on this IOCTL with a 0 timeout (like busy ioctl)
+	 */
+	if (!args->timeout_ns) {
+		ret = -ETIME;
+		goto out;
+	}
+
+	drm_gem_object_unreference(&obj->base);
+	mutex_unlock(&dev->struct_mutex);
+
+	ret = __wait_seqno(ring, seqno, true, &timeout);
+	WARN_ON(!timespec_valid(&timeout));
+	args->timeout_ns = timespec_to_ns(&timeout);
+	return ret;
+
+out:
+	drm_gem_object_unreference(&obj->base);
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
+}
+
+/**
  * i915_gem_object_sync - sync an object to a ring.
  *
  * @obj: object which may be in use on another ring.
@@ -2160,7 +2309,7 @@ static int i915_ring_idle(struct intel_ring_buffer *ring)
 			return ret;
 	}
 
-	return i915_wait_request(ring, i915_gem_next_request_seqno(ring));
+	return i915_wait_seqno(ring, i915_gem_next_request_seqno(ring));
 }
 
 int i915_gpu_idle(struct drm_device *dev)
@@ -2364,7 +2513,7 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj)
 	}
 
 	if (obj->last_fenced_seqno) {
-		ret = i915_wait_request(obj->ring, obj->last_fenced_seqno);
+		ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno);
 		if (ret)
 			return ret;
 
@@ -3030,7 +3179,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
 	if (seqno == 0)
 		return 0;
 
-	ret = __wait_seqno(ring, seqno, true);
+	ret = __wait_seqno(ring, seqno, true, NULL);
 	if (ret == 0)
 		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
 
@@ -3199,30 +3348,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 	 * become non-busy without any further actions, therefore emit any
 	 * necessary flushes here.
 	 */
-	args->busy = obj->active;
-	if (args->busy) {
-		/* Unconditionally flush objects, even when the gpu still uses this
-		 * object. Userspace calling this function indicates that it wants to
-		 * use this buffer rather sooner than later, so issuing the required
-		 * flush earlier is beneficial.
-		 */
-		if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
-			ret = i915_gem_flush_ring(obj->ring,
-						  0, obj->base.write_domain);
-		} else {
-			ret = i915_gem_check_olr(obj->ring,
-						 obj->last_rendering_seqno);
-		}
+	ret = i915_gem_object_flush_active(obj);
 
-		/* Update the active list for the hardware's current position.
-		 * Otherwise this only updates on a delayed timer or when irqs
-		 * are actually unmasked, and our working set ends up being
-		 * larger than required.
-		 */
-		i915_gem_retire_requests_ring(obj->ring);
-
-		args->busy = obj->active;
-	}
+	args->busy = obj->active;
 
 	drm_gem_object_unreference(&obj->base);
 unlock:
@@ -3435,6 +3563,38 @@ i915_gem_idle(struct drm_device *dev)
 	return 0;
 }
 
+void i915_gem_l3_remap(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	u32 misccpctl;
+	int i;
+
+	if (!IS_IVYBRIDGE(dev))
+		return;
+
+	if (!dev_priv->mm.l3_remap_info)
+		return;
+
+	misccpctl = I915_READ(GEN7_MISCCPCTL);
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+	POSTING_READ(GEN7_MISCCPCTL);
+
+	for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) {
+		u32 remap = I915_READ(GEN7_L3LOG_BASE + i);
+		if (remap && remap != dev_priv->mm.l3_remap_info[i/4])
+			DRM_DEBUG("0x%x was already programmed to %x\n",
+				  GEN7_L3LOG_BASE + i, remap);
+		if (remap && !dev_priv->mm.l3_remap_info[i/4])
+			DRM_DEBUG_DRIVER("Clearing remapped register\n");
+		I915_WRITE(GEN7_L3LOG_BASE + i, dev_priv->mm.l3_remap_info[i/4]);
+	}
+
+	/* Make sure all the writes land before disabling dop clock gating */
+	POSTING_READ(GEN7_L3LOG_BASE);
+
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl);
+}
+
 void i915_gem_init_swizzling(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -3524,6 +3684,8 @@ i915_gem_init_hw(struct drm_device *dev)
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int ret;
 
+	i915_gem_l3_remap(dev);
+
 	i915_gem_init_swizzling(dev);
 
 	ret = intel_init_render_ring_buffer(dev);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b1fe0ed..75e0b02 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -375,6 +375,86 @@ static void gen6_pm_rps_work(struct work_struct *work)
 	mutex_unlock(&dev_priv->dev->struct_mutex);
 }
 
+
+/**
+ * ivybridge_parity_work - Workqueue called when a parity error interrupt
+ * occurred.
+ * @work: workqueue struct
+ *
+ * Doesn't actually do anything except notify userspace. As a consequence of
+ * this event, userspace should try to remap the bad rows since statistically
+ * it is likely the same row is more likely to go bad again.
+ */
+static void ivybridge_parity_work(struct work_struct *work)
+{
+	drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+						    parity_error_work);
+	u32 error_status, row, bank, subbank;
+	char *parity_event[5];
+	uint32_t misccpctl;
+	unsigned long flags;
+
+	/* We must turn off DOP level clock gating to access the L3 registers.
+	 * In order to prevent a get/put style interface, acquire struct mutex
+	 * any time we access those registers.
+	 */
+	mutex_lock(&dev_priv->dev->struct_mutex);
+
+	misccpctl = I915_READ(GEN7_MISCCPCTL);
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+	POSTING_READ(GEN7_MISCCPCTL);
+
+	error_status = I915_READ(GEN7_L3CDERRST1);
+	row = GEN7_PARITY_ERROR_ROW(error_status);
+	bank = GEN7_PARITY_ERROR_BANK(error_status);
+	subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
+
+	I915_WRITE(GEN7_L3CDERRST1, GEN7_PARITY_ERROR_VALID |
+				    GEN7_L3CDERRST1_ENABLE);
+	POSTING_READ(GEN7_L3CDERRST1);
+
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl);
+
+	spin_lock_irqsave(&dev_priv->irq_lock, flags);
+	dev_priv->gt_irq_mask &= ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+	mutex_unlock(&dev_priv->dev->struct_mutex);
+
+	parity_event[0] = "L3_PARITY_ERROR=1";
+	parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
+	parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
+	parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
+	parity_event[4] = NULL;
+
+	kobject_uevent_env(&dev_priv->dev->primary->kdev.kobj,
+			   KOBJ_CHANGE, parity_event);
+
+	DRM_DEBUG("Parity error: Row = %d, Bank = %d, Sub bank = %d.\n",
+		  row, bank, subbank);
+
+	kfree(parity_event[3]);
+	kfree(parity_event[2]);
+	kfree(parity_event[1]);
+}
+
+static void ivybridge_handle_parity_error(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	unsigned long flags;
+
+	if (!IS_IVYBRIDGE(dev))
+		return;
+
+	spin_lock_irqsave(&dev_priv->irq_lock, flags);
+	dev_priv->gt_irq_mask |= GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+	queue_work(dev_priv->wq, &dev_priv->parity_error_work);
+}
+
 static void snb_gt_irq_handler(struct drm_device *dev,
 			       struct drm_i915_private *dev_priv,
 			       u32 gt_iir)
@@ -394,6 +474,9 @@ static void snb_gt_irq_handler(struct drm_device *dev,
 		DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir);
 		i915_handle_error(dev, false);
 	}
+
+	if (gt_iir & GT_GEN7_L3_PARITY_ERROR_INTERRUPT)
+		ivybridge_handle_parity_error(dev);
 }
 
 static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
@@ -1649,7 +1732,6 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
 
 	atomic_set(&dev_priv->irq_received, 0);
 
-
 	I915_WRITE(HWSTAM, 0xeffe);
 
 	/* XXX hotplug from PCH */
@@ -1812,13 +1894,13 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
 		   DE_PIPEA_VBLANK_IVB);
 	POSTING_READ(DEIER);
 
-	dev_priv->gt_irq_mask = ~0;
+	dev_priv->gt_irq_mask = ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
 
 	I915_WRITE(GTIIR, I915_READ(GTIIR));
 	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 
 	render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
-		GEN6_BLITTER_USER_INTERRUPT;
+		GEN6_BLITTER_USER_INTERRUPT | GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
 	I915_WRITE(GTIER, render_irqs);
 	POSTING_READ(GTIER);
 
@@ -2167,9 +2249,9 @@ static int i915_irq_postinstall(struct drm_device *dev)
 			hotplug_en |= HDMIC_HOTPLUG_INT_EN;
 		if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
 			hotplug_en |= HDMID_HOTPLUG_INT_EN;
-		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
+		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
 			hotplug_en |= SDVOC_HOTPLUG_INT_EN;
-		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
+		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
 			hotplug_en |= SDVOB_HOTPLUG_INT_EN;
 		if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
 			hotplug_en |= CRT_HOTPLUG_INT_EN;
@@ -2329,10 +2411,8 @@ static void i965_irq_preinstall(struct drm_device * dev)
 
 	atomic_set(&dev_priv->irq_received, 0);
 
-	if (I915_HAS_HOTPLUG(dev)) {
-		I915_WRITE(PORT_HOTPLUG_EN, 0);
-		I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
-	}
+	I915_WRITE(PORT_HOTPLUG_EN, 0);
+	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
 	I915_WRITE(HWSTAM, 0xeffe);
 	for_each_pipe(pipe)
@@ -2345,11 +2425,13 @@ static void i965_irq_preinstall(struct drm_device * dev)
 static int i965_irq_postinstall(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	u32 hotplug_en;
 	u32 enable_mask;
 	u32 error_mask;
 
 	/* Unmask the interrupts that we always want on. */
 	dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
+			       I915_DISPLAY_PORT_INTERRUPT |
 			       I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
 			       I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
 			       I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
@@ -2365,13 +2447,6 @@ static int i965_irq_postinstall(struct drm_device *dev)
 	dev_priv->pipestat[0] = 0;
 	dev_priv->pipestat[1] = 0;
 
-	if (I915_HAS_HOTPLUG(dev)) {
-		/* Enable in IER... */
-		enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
-		/* and unmask in IMR */
-		dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT;
-	}
-
 	/*
 	 * Enable some error detection, note the instruction error mask
 	 * bit is reserved, so we leave it masked.
@@ -2391,36 +2466,40 @@ static int i965_irq_postinstall(struct drm_device *dev)
 	I915_WRITE(IER, enable_mask);
 	POSTING_READ(IER);
 
-	if (I915_HAS_HOTPLUG(dev)) {
-		u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
-
-		/* Note HDMI and DP share bits */
-		if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
-			hotplug_en |= HDMIB_HOTPLUG_INT_EN;
-		if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
-			hotplug_en |= HDMIC_HOTPLUG_INT_EN;
-		if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
-			hotplug_en |= HDMID_HOTPLUG_INT_EN;
-		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
+	/* Note HDMI and DP share hotplug bits */
+	hotplug_en = 0;
+	if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
+		hotplug_en |= HDMIB_HOTPLUG_INT_EN;
+	if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
+		hotplug_en |= HDMIC_HOTPLUG_INT_EN;
+	if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
+		hotplug_en |= HDMID_HOTPLUG_INT_EN;
+	if (IS_G4X(dev)) {
+		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X)
 			hotplug_en |= SDVOC_HOTPLUG_INT_EN;
-		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
+		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_G4X)
 			hotplug_en |= SDVOB_HOTPLUG_INT_EN;
-		if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
-			hotplug_en |= CRT_HOTPLUG_INT_EN;
+	} else {
+		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I965)
+			hotplug_en |= SDVOC_HOTPLUG_INT_EN;
+		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I965)
+			hotplug_en |= SDVOB_HOTPLUG_INT_EN;
+	}
+	if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
+		hotplug_en |= CRT_HOTPLUG_INT_EN;
 
-			/* Programming the CRT detection parameters tends
-			   to generate a spurious hotplug event about three
-			   seconds later.  So just do it once.
-			*/
-			if (IS_G4X(dev))
-				hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
-			hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
-		}
+		/* Programming the CRT detection parameters tends
+		   to generate a spurious hotplug event about three
+		   seconds later.  So just do it once.
+		   */
+		if (IS_G4X(dev))
+			hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
+		hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
+	}
 
-		/* Ignore TV since it's buggy */
+	/* Ignore TV since it's buggy */
 
-		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
-	}
+	I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
 
 	intel_opregion_enable_asle(dev);
 
@@ -2478,8 +2557,7 @@ static irqreturn_t i965_irq_handler(DRM_IRQ_ARGS)
 		ret = IRQ_HANDLED;
 
 		/* Consume port.  Then clear IIR or we'll miss events */
-		if ((I915_HAS_HOTPLUG(dev)) &&
-		    (iir & I915_DISPLAY_PORT_INTERRUPT)) {
+		if (iir & I915_DISPLAY_PORT_INTERRUPT) {
 			u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
 
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
@@ -2552,10 +2630,8 @@ static void i965_irq_uninstall(struct drm_device * dev)
 	if (!dev_priv)
 		return;
 
-	if (I915_HAS_HOTPLUG(dev)) {
-		I915_WRITE(PORT_HOTPLUG_EN, 0);
-		I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
-	}
+	I915_WRITE(PORT_HOTPLUG_EN, 0);
+	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
 	I915_WRITE(HWSTAM, 0xffffffff);
 	for_each_pipe(pipe)
@@ -2576,6 +2652,7 @@ void intel_irq_init(struct drm_device *dev)
 	INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
 	INIT_WORK(&dev_priv->error_work, i915_error_work_func);
 	INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
+	INIT_WORK(&dev_priv->parity_error_work, ivybridge_parity_work);
 
 	dev->driver->get_vblank_counter = i915_get_vblank_counter;
 	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 48d5e8e..35113d8 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1566,20 +1566,34 @@
 #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV	(1 << 2)
 
 #define PORT_HOTPLUG_STAT	0x61114
-#define   HDMIB_HOTPLUG_INT_STATUS		(1 << 29)
-#define   DPB_HOTPLUG_INT_STATUS		(1 << 29)
-#define   HDMIC_HOTPLUG_INT_STATUS		(1 << 28)
-#define   DPC_HOTPLUG_INT_STATUS		(1 << 28)
-#define   HDMID_HOTPLUG_INT_STATUS		(1 << 27)
-#define   DPD_HOTPLUG_INT_STATUS		(1 << 27)
+/* HDMI/DP bits are gen4+ */
+#define   DPB_HOTPLUG_LIVE_STATUS               (1 << 29)
+#define   DPC_HOTPLUG_LIVE_STATUS               (1 << 28)
+#define   DPD_HOTPLUG_LIVE_STATUS               (1 << 27)
+#define   DPD_HOTPLUG_INT_STATUS		(3 << 21)
+#define   DPC_HOTPLUG_INT_STATUS		(3 << 19)
+#define   DPB_HOTPLUG_INT_STATUS		(3 << 17)
+/* HDMI bits are shared with the DP bits */
+#define   HDMIB_HOTPLUG_LIVE_STATUS             (1 << 29)
+#define   HDMIC_HOTPLUG_LIVE_STATUS             (1 << 28)
+#define   HDMID_HOTPLUG_LIVE_STATUS             (1 << 27)
+#define   HDMID_HOTPLUG_INT_STATUS		(3 << 21)
+#define   HDMIC_HOTPLUG_INT_STATUS		(3 << 19)
+#define   HDMIB_HOTPLUG_INT_STATUS		(3 << 17)
+/* CRT/TV common between gen3+ */
 #define   CRT_HOTPLUG_INT_STATUS		(1 << 11)
 #define   TV_HOTPLUG_INT_STATUS			(1 << 10)
 #define   CRT_HOTPLUG_MONITOR_MASK		(3 << 8)
 #define   CRT_HOTPLUG_MONITOR_COLOR		(3 << 8)
 #define   CRT_HOTPLUG_MONITOR_MONO		(2 << 8)
 #define   CRT_HOTPLUG_MONITOR_NONE		(0 << 8)
-#define   SDVOC_HOTPLUG_INT_STATUS		(1 << 7)
-#define   SDVOB_HOTPLUG_INT_STATUS		(1 << 6)
+/* SDVO is different across gen3/4 */
+#define   SDVOC_HOTPLUG_INT_STATUS_G4X		(1 << 3)
+#define   SDVOB_HOTPLUG_INT_STATUS_G4X		(1 << 2)
+#define   SDVOC_HOTPLUG_INT_STATUS_I965		(3 << 4)
+#define   SDVOB_HOTPLUG_INT_STATUS_I965		(3 << 2)
+#define   SDVOC_HOTPLUG_INT_STATUS_I915		(1 << 7)
+#define   SDVOB_HOTPLUG_INT_STATUS_I915		(1 << 6)
 
 /* SDVO port control */
 #define SDVOB			0x61140
@@ -1711,8 +1725,10 @@
 #define   VIDEO_DIP_PORT_C		(2 << 29)
 #define   VIDEO_DIP_PORT_D		(3 << 29)
 #define   VIDEO_DIP_PORT_MASK		(3 << 29)
+#define   VIDEO_DIP_ENABLE_GCP		(1 << 25)
 #define   VIDEO_DIP_ENABLE_AVI		(1 << 21)
 #define   VIDEO_DIP_ENABLE_VENDOR	(2 << 21)
+#define   VIDEO_DIP_ENABLE_GAMUT	(4 << 21)
 #define   VIDEO_DIP_ENABLE_SPD		(8 << 21)
 #define   VIDEO_DIP_SELECT_AVI		(0 << 19)
 #define   VIDEO_DIP_SELECT_VENDOR	(1 << 19)
@@ -1723,7 +1739,11 @@
 #define   VIDEO_DIP_FREQ_2VSYNC		(2 << 16)
 #define   VIDEO_DIP_FREQ_MASK		(3 << 16)
 /* HSW and later: */
+#define   VIDEO_DIP_ENABLE_VSC_HSW	(1 << 20)
+#define   VIDEO_DIP_ENABLE_GCP_HSW	(1 << 16)
 #define   VIDEO_DIP_ENABLE_AVI_HSW	(1 << 12)
+#define   VIDEO_DIP_ENABLE_VS_HSW	(1 << 8)
+#define   VIDEO_DIP_ENABLE_GMP_HSW	(1 << 4)
 #define   VIDEO_DIP_ENABLE_SPD_HSW	(1 << 0)
 
 /* Panel power sequencing */
@@ -4111,6 +4131,26 @@
 #define   GEN6_RC6			3
 #define   GEN6_RC7			4
 
+#define GEN7_MISCCPCTL			(0x9424)
+#define   GEN7_DOP_CLOCK_GATE_ENABLE	(1<<0)
+
+/* IVYBRIDGE DPF */
+#define GEN7_L3CDERRST1			0xB008 /* L3CD Error Status 1 */
+#define   GEN7_L3CDERRST1_ROW_MASK	(0x7ff<<14)
+#define   GEN7_PARITY_ERROR_VALID	(1<<13)
+#define   GEN7_L3CDERRST1_BANK_MASK	(3<<11)
+#define   GEN7_L3CDERRST1_SUBBANK_MASK	(7<<8)
+#define GEN7_PARITY_ERROR_ROW(reg) \
+		((reg & GEN7_L3CDERRST1_ROW_MASK) >> 14)
+#define GEN7_PARITY_ERROR_BANK(reg) \
+		((reg & GEN7_L3CDERRST1_BANK_MASK) >> 11)
+#define GEN7_PARITY_ERROR_SUBBANK(reg) \
+		((reg & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8)
+#define   GEN7_L3CDERRST1_ENABLE	(1<<7)
+
+#define GEN7_L3LOG_BASE			0xB070
+#define GEN7_L3LOG_SIZE			0x80
+
 #define G4X_AUD_VID_DID			0x62020
 #define INTEL_AUDIO_DEVCL		0x808629FB
 #define INTEL_AUDIO_DEVBLC		0x80862801
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 79f8344..2f5388a 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/stat.h>
 #include <linux/sysfs.h>
+#include "intel_drv.h"
 #include "i915_drv.h"
 
 static u32 calc_residency(struct drm_device *dev, const u32 reg)
@@ -92,20 +93,134 @@ static struct attribute_group rc6_attr_group = {
 	.attrs =  rc6_attrs
 };
 
-void i915_setup_sysfs(struct drm_device *dev)
+static int l3_access_valid(struct drm_device *dev, loff_t offset)
+{
+	if (!IS_IVYBRIDGE(dev))
+		return -EPERM;
+
+	if (offset % 4 != 0)
+		return -EINVAL;
+
+	if (offset >= GEN7_L3LOG_SIZE)
+		return -ENXIO;
+
+	return 0;
+}
+
+static ssize_t
+i915_l3_read(struct file *filp, struct kobject *kobj,
+	     struct bin_attribute *attr, char *buf,
+	     loff_t offset, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
+	struct drm_device *drm_dev = dminor->dev;
+	struct drm_i915_private *dev_priv = drm_dev->dev_private;
+	uint32_t misccpctl;
+	int i, ret;
+
+	ret = l3_access_valid(drm_dev, offset);
+	if (ret)
+		return ret;
+
+	ret = i915_mutex_lock_interruptible(drm_dev);
+	if (ret)
+		return ret;
+
+	misccpctl = I915_READ(GEN7_MISCCPCTL);
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+
+	for (i = offset; count >= 4 && i < GEN7_L3LOG_SIZE; i += 4, count -= 4)
+		*((uint32_t *)(&buf[i])) = I915_READ(GEN7_L3LOG_BASE + i);
+
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl);
+
+	mutex_unlock(&drm_dev->struct_mutex);
+
+	return i - offset;
+}
+
+static ssize_t
+i915_l3_write(struct file *filp, struct kobject *kobj,
+	      struct bin_attribute *attr, char *buf,
+	      loff_t offset, size_t count)
 {
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
+	struct drm_device *drm_dev = dminor->dev;
+	struct drm_i915_private *dev_priv = drm_dev->dev_private;
+	u32 *temp = NULL; /* Just here to make handling failures easy */
 	int ret;
 
-	/* ILK doesn't have any residency information */
-	if (INTEL_INFO(dev)->gen < 6)
-		return;
+	ret = l3_access_valid(drm_dev, offset);
+	if (ret)
+		return ret;
 
-	ret = sysfs_merge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
+	ret = i915_mutex_lock_interruptible(drm_dev);
 	if (ret)
-		DRM_ERROR("sysfs setup failed\n");
+		return ret;
+
+	if (!dev_priv->mm.l3_remap_info) {
+		temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
+		if (!temp) {
+			mutex_unlock(&drm_dev->struct_mutex);
+			return -ENOMEM;
+		}
+	}
+
+	ret = i915_gpu_idle(drm_dev);
+	if (ret) {
+		kfree(temp);
+		mutex_unlock(&drm_dev->struct_mutex);
+		return ret;
+	}
+
+	/* TODO: Ideally we really want a GPU reset here to make sure errors
+	 * aren't propagated. Since I cannot find a stable way to reset the GPU
+	 * at this point it is left as a TODO.
+	*/
+	if (temp)
+		dev_priv->mm.l3_remap_info = temp;
+
+	memcpy(dev_priv->mm.l3_remap_info + (offset/4),
+	       buf + (offset/4),
+	       count);
+
+	i915_gem_l3_remap(drm_dev);
+
+	mutex_unlock(&drm_dev->struct_mutex);
+
+	return count;
+}
+
+static struct bin_attribute dpf_attrs = {
+	.attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)},
+	.size = GEN7_L3LOG_SIZE,
+	.read = i915_l3_read,
+	.write = i915_l3_write,
+	.mmap = NULL
+};
+
+void i915_setup_sysfs(struct drm_device *dev)
+{
+	int ret;
+
+	if (INTEL_INFO(dev)->gen >= 6) {
+		ret = sysfs_merge_group(&dev->primary->kdev.kobj,
+					&rc6_attr_group);
+		if (ret)
+			DRM_ERROR("RC6 residency sysfs setup failed\n");
+	}
+
+	if (IS_IVYBRIDGE(dev)) {
+		ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs);
+		if (ret)
+			DRM_ERROR("l3 parity sysfs setup failed\n");
+	}
 }
 
 void i915_teardown_sysfs(struct drm_device *dev)
 {
+	device_remove_bin_file(&dev->primary->kdev,  &dpf_attrs);
 	sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
 }
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index dac7bba..fe90b3a 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -311,9 +311,33 @@ DEFINE_EVENT(i915_gem_request, i915_gem_request_retire,
 	    TP_ARGS(ring, seqno)
 );
 
-DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_begin,
+TRACE_EVENT(i915_gem_request_wait_begin,
 	    TP_PROTO(struct intel_ring_buffer *ring, u32 seqno),
-	    TP_ARGS(ring, seqno)
+	    TP_ARGS(ring, seqno),
+
+	    TP_STRUCT__entry(
+			     __field(u32, dev)
+			     __field(u32, ring)
+			     __field(u32, seqno)
+			     __field(bool, blocking)
+			     ),
+
+	    /* NB: the blocking information is racy since mutex_is_locked
+	     * doesn't check that the current thread holds the lock. The only
+	     * other option would be to pass the boolean information of whether
+	     * or not the class was blocking down through the stack which is
+	     * less desirable.
+	     */
+	    TP_fast_assign(
+			   __entry->dev = ring->dev->primary->index;
+			   __entry->ring = ring->id;
+			   __entry->seqno = seqno;
+			   __entry->blocking = mutex_is_locked(&ring->dev->struct_mutex);
+			   ),
+
+	    TP_printk("dev=%u, ring=%u, seqno=%u, blocking=%s",
+		      __entry->dev, __entry->ring, __entry->seqno,
+		      __entry->blocking ?  "yes (NB)" : "no")
 );
 
 DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end,
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 46d1e88..f33fe1a 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -726,8 +726,7 @@ void intel_ddi_mode_set(struct drm_encoder *encoder,
 
 	I915_WRITE(DDI_FUNC_CTL(pipe), temp);
 
-	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
-	intel_hdmi_set_spd_infoframe(encoder);
+	intel_hdmi->set_infoframes(encoder, adjusted_mode);
 }
 
 void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a7c727d..add1a15 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4405,25 +4405,10 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 						    &clock,
 						    &reduced_clock);
 	}
-	/* SDVO TV has fixed PLL values depend on its clock range,
-	   this mirrors vbios setting. */
-	if (is_sdvo && is_tv) {
-		if (adjusted_mode->clock >= 100000
-		    && adjusted_mode->clock < 140500) {
-			clock.p1 = 2;
-			clock.p2 = 10;
-			clock.n = 3;
-			clock.m1 = 16;
-			clock.m2 = 8;
-		} else if (adjusted_mode->clock >= 140500
-			   && adjusted_mode->clock <= 200000) {
-			clock.p1 = 1;
-			clock.p2 = 10;
-			clock.n = 6;
-			clock.m1 = 12;
-			clock.m2 = 8;
-		}
-	}
+
+	if (is_sdvo && is_tv)
+		i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
+
 
 	/* FDI link */
 	pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
@@ -4431,16 +4416,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 	/* CPU eDP doesn't require FDI link, so just set DP M/N
 	   according to current link config */
 	if (is_cpu_edp) {
-		target_clock = mode->clock;
 		intel_edp_link_config(edp_encoder, &lane, &link_bw);
 	} else {
-		/* [e]DP over FDI requires target mode clock
-		   instead of link clock */
-		if (is_dp)
-			target_clock = mode->clock;
-		else
-			target_clock = adjusted_mode->clock;
-
 		/* FDI is a binary signal running at ~2.7GHz, encoding
 		 * each output octet as 10 bits. The actual frequency
 		 * is stored as a divider into a 100MHz clock, and the
@@ -4451,6 +4428,14 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 		link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
 	}
 
+	/* [e]DP over FDI requires target mode clock instead of link clock. */
+	if (edp_encoder)
+		target_clock = intel_edp_target_clock(edp_encoder, mode);
+	else if (is_dp)
+		target_clock = mode->clock;
+	else
+		target_clock = adjusted_mode->clock;
+
 	/* determine panel color depth */
 	temp = I915_READ(PIPECONF(pipe));
 	temp &= ~PIPE_BPC_MASK;
@@ -4662,16 +4647,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 		if (is_lvds && has_reduced_clock && i915_powersave) {
 			I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2);
 			intel_crtc->lowfreq_avail = true;
-			if (HAS_PIPE_CXSR(dev)) {
-				DRM_DEBUG_KMS("enabling CxSR downclocking\n");
-				pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
-			}
 		} else {
 			I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp);
-			if (HAS_PIPE_CXSR(dev)) {
-				DRM_DEBUG_KMS("disabling CxSR downclocking\n");
-				pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
-			}
 		}
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index c044932..76a7080 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -155,6 +155,18 @@ intel_edp_link_config(struct intel_encoder *intel_encoder,
 		*link_bw = 270000;
 }
 
+int
+intel_edp_target_clock(struct intel_encoder *intel_encoder,
+		       struct drm_display_mode *mode)
+{
+	struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base);
+
+	if (intel_dp->panel_fixed_mode)
+		return intel_dp->panel_fixed_mode->clock;
+	else
+		return mode->clock;
+}
+
 static int
 intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
@@ -225,7 +237,7 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
 static bool
 intel_dp_adjust_dithering(struct intel_dp *intel_dp,
 			  struct drm_display_mode *mode,
-			  struct drm_display_mode *adjusted_mode)
+			  bool adjust_mode)
 {
 	int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
 	int max_lanes = intel_dp_max_lane_count(intel_dp);
@@ -239,8 +251,8 @@ intel_dp_adjust_dithering(struct intel_dp *intel_dp,
 		if (mode_rate > max_rate)
 			return false;
 
-		if (adjusted_mode)
-			adjusted_mode->private_flags
+		if (adjust_mode)
+			mode->private_flags
 				|= INTEL_MODE_DP_FORCE_6BPC;
 
 		return true;
@@ -263,7 +275,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
 			return MODE_PANEL;
 	}
 
-	if (!intel_dp_adjust_dithering(intel_dp, mode, NULL))
+	if (!intel_dp_adjust_dithering(intel_dp, mode, false))
 		return MODE_CLOCK_HIGH;
 
 	if (mode->clock < 10000)
@@ -706,25 +718,20 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
 		intel_fixed_panel_mode(intel_dp->panel_fixed_mode, adjusted_mode);
 		intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN,
 					mode, adjusted_mode);
-		/*
-		 * the mode->clock is used to calculate the Data&Link M/N
-		 * of the pipe. For the eDP the fixed clock should be used.
-		 */
-		mode->clock = intel_dp->panel_fixed_mode->clock;
 	}
 
-	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
 		return false;
 
 	DRM_DEBUG_KMS("DP link computation with max lane count %i "
 		      "max bw %02x pixel clock %iKHz\n",
-		      max_lane_count, bws[max_clock], mode->clock);
+		      max_lane_count, bws[max_clock], adjusted_mode->clock);
 
-	if (!intel_dp_adjust_dithering(intel_dp, mode, adjusted_mode))
+	if (!intel_dp_adjust_dithering(intel_dp, adjusted_mode, true))
 		return false;
 
 	bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24;
-	mode_rate = intel_dp_link_required(mode->clock, bpp);
+	mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp);
 
 	for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
 		for (clock = 0; clock <= max_clock; clock++) {
@@ -1922,7 +1929,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
 			DP |= DP_LINK_TRAIN_OFF;
 	}
 
-	if (!HAS_PCH_CPT(dev) &&
+	if (HAS_PCH_IBX(dev) &&
 	    I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
 		struct drm_crtc *crtc = intel_dp->base.base.crtc;
 
@@ -2099,25 +2106,23 @@ g4x_dp_detect(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint32_t temp, bit;
+	uint32_t bit;
 
 	switch (intel_dp->output_reg) {
 	case DP_B:
-		bit = DPB_HOTPLUG_INT_STATUS;
+		bit = DPB_HOTPLUG_LIVE_STATUS;
 		break;
 	case DP_C:
-		bit = DPC_HOTPLUG_INT_STATUS;
+		bit = DPC_HOTPLUG_LIVE_STATUS;
 		break;
 	case DP_D:
-		bit = DPD_HOTPLUG_INT_STATUS;
+		bit = DPD_HOTPLUG_LIVE_STATUS;
 		break;
 	default:
 		return connector_status_unknown;
 	}
 
-	temp = I915_READ(PORT_HOTPLUG_STAT);
-
-	if ((temp & bit) == 0)
+	if ((I915_READ(PORT_HOTPLUG_STAT) & bit) == 0)
 		return connector_status_disconnected;
 
 	return intel_dp_detect_dpcd(intel_dp);
@@ -2520,19 +2525,19 @@ intel_dp_init(struct drm_device *dev, int output_reg)
 		case DP_B:
 		case PCH_DP_B:
 			dev_priv->hotplug_supported_mask |=
-				HDMIB_HOTPLUG_INT_STATUS;
+				DPB_HOTPLUG_INT_STATUS;
 			name = "DPDDC-B";
 			break;
 		case DP_C:
 		case PCH_DP_C:
 			dev_priv->hotplug_supported_mask |=
-				HDMIC_HOTPLUG_INT_STATUS;
+				DPC_HOTPLUG_INT_STATUS;
 			name = "DPDDC-C";
 			break;
 		case DP_D:
 		case PCH_DP_D:
 			dev_priv->hotplug_supported_mask |=
-				HDMID_HOTPLUG_INT_STATUS;
+				DPD_HOTPLUG_INT_STATUS;
 			name = "DPDDC-D";
 			break;
 	}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 3e09188..c35edd7 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -301,6 +301,8 @@ struct intel_hdmi {
 	enum hdmi_force_audio force_audio;
 	void (*write_infoframe)(struct drm_encoder *encoder,
 				struct dip_infoframe *frame);
+	void (*set_infoframes)(struct drm_encoder *encoder,
+			       struct drm_display_mode *adjusted_mode);
 };
 
 static inline struct drm_crtc *
@@ -343,9 +345,6 @@ extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector)
 extern void intel_crt_init(struct drm_device *dev);
 extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
 extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
-extern void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
-			    struct drm_display_mode *adjusted_mode);
-extern void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder);
 extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
 extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg,
 			    bool is_sdvob);
@@ -360,6 +359,8 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
 		 struct drm_display_mode *adjusted_mode);
 extern bool intel_dpd_is_edp(struct drm_device *dev);
 extern void intel_edp_link_config(struct intel_encoder *, int *, int *);
+extern int intel_edp_target_clock(struct intel_encoder *,
+				  struct drm_display_mode *mode);
 extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
 extern int intel_plane_init(struct drm_device *dev, enum pipe pipe);
 extern void intel_flush_display_plane(struct drm_i915_private *dev_priv,
@@ -372,7 +373,7 @@ extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
 				   struct drm_display_mode *adjusted_mode);
 extern void intel_pch_panel_fitting(struct drm_device *dev,
 				    int fitting_mode,
-				    struct drm_display_mode *mode,
+				    const struct drm_display_mode *mode,
 				    struct drm_display_mode *adjusted_mode);
 extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
 extern u32 intel_panel_get_backlight(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 2ead3bf..b507d38 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -121,36 +121,31 @@ static void g4x_write_infoframe(struct drm_encoder *encoder,
 	uint32_t *data = (uint32_t *)frame;
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 	u32 val = I915_READ(VIDEO_DIP_CTL);
 	unsigned i, len = DIP_HEADER_SIZE + frame->len;
 
-	val &= ~VIDEO_DIP_PORT_MASK;
-	if (intel_hdmi->sdvox_reg == SDVOB)
-		val |= VIDEO_DIP_PORT_B;
-	else if (intel_hdmi->sdvox_reg == SDVOC)
-		val |= VIDEO_DIP_PORT_C;
-	else
-		return;
+	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
 
 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
 	val |= g4x_infoframe_index(frame);
 
 	val &= ~g4x_infoframe_enable(frame);
-	val |= VIDEO_DIP_ENABLE;
 
 	I915_WRITE(VIDEO_DIP_CTL, val);
 
+	mmiowb();
 	for (i = 0; i < len; i += 4) {
 		I915_WRITE(VIDEO_DIP_DATA, *data);
 		data++;
 	}
+	mmiowb();
 
 	val |= g4x_infoframe_enable(frame);
 	val &= ~VIDEO_DIP_FREQ_MASK;
 	val |= VIDEO_DIP_FREQ_VSYNC;
 
 	I915_WRITE(VIDEO_DIP_CTL, val);
+	POSTING_READ(VIDEO_DIP_CTL);
 }
 
 static void ibx_write_infoframe(struct drm_encoder *encoder,
@@ -160,46 +155,32 @@ static void ibx_write_infoframe(struct drm_encoder *encoder,
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 	int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
 	unsigned i, len = DIP_HEADER_SIZE + frame->len;
 	u32 val = I915_READ(reg);
 
-	val &= ~VIDEO_DIP_PORT_MASK;
-	switch (intel_hdmi->sdvox_reg) {
-	case HDMIB:
-		val |= VIDEO_DIP_PORT_B;
-		break;
-	case HDMIC:
-		val |= VIDEO_DIP_PORT_C;
-		break;
-	case HDMID:
-		val |= VIDEO_DIP_PORT_D;
-		break;
-	default:
-		return;
-	}
-
-	intel_wait_for_vblank(dev, intel_crtc->pipe);
+	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
 
 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
 	val |= g4x_infoframe_index(frame);
 
 	val &= ~g4x_infoframe_enable(frame);
-	val |= VIDEO_DIP_ENABLE;
 
 	I915_WRITE(reg, val);
 
+	mmiowb();
 	for (i = 0; i < len; i += 4) {
 		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
 		data++;
 	}
+	mmiowb();
 
 	val |= g4x_infoframe_enable(frame);
 	val &= ~VIDEO_DIP_FREQ_MASK;
 	val |= VIDEO_DIP_FREQ_VSYNC;
 
 	I915_WRITE(reg, val);
+	POSTING_READ(reg);
 }
 
 static void cpt_write_infoframe(struct drm_encoder *encoder,
@@ -213,32 +194,31 @@ static void cpt_write_infoframe(struct drm_encoder *encoder,
 	unsigned i, len = DIP_HEADER_SIZE + frame->len;
 	u32 val = I915_READ(reg);
 
-	intel_wait_for_vblank(dev, intel_crtc->pipe);
+	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
 
 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
 	val |= g4x_infoframe_index(frame);
 
 	/* The DIP control register spec says that we need to update the AVI
 	 * infoframe without clearing its enable bit */
-	if (frame->type == DIP_TYPE_AVI)
-		val |= VIDEO_DIP_ENABLE_AVI;
-	else
+	if (frame->type != DIP_TYPE_AVI)
 		val &= ~g4x_infoframe_enable(frame);
 
-	val |= VIDEO_DIP_ENABLE;
-
 	I915_WRITE(reg, val);
 
+	mmiowb();
 	for (i = 0; i < len; i += 4) {
 		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
 		data++;
 	}
+	mmiowb();
 
 	val |= g4x_infoframe_enable(frame);
 	val &= ~VIDEO_DIP_FREQ_MASK;
 	val |= VIDEO_DIP_FREQ_VSYNC;
 
 	I915_WRITE(reg, val);
+	POSTING_READ(reg);
 }
 
 static void vlv_write_infoframe(struct drm_encoder *encoder,
@@ -252,26 +232,28 @@ static void vlv_write_infoframe(struct drm_encoder *encoder,
 	unsigned i, len = DIP_HEADER_SIZE + frame->len;
 	u32 val = I915_READ(reg);
 
-	intel_wait_for_vblank(dev, intel_crtc->pipe);
+	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
 
 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
 	val |= g4x_infoframe_index(frame);
 
 	val &= ~g4x_infoframe_enable(frame);
-	val |= VIDEO_DIP_ENABLE;
 
 	I915_WRITE(reg, val);
 
+	mmiowb();
 	for (i = 0; i < len; i += 4) {
 		I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
 		data++;
 	}
+	mmiowb();
 
 	val |= g4x_infoframe_enable(frame);
 	val &= ~VIDEO_DIP_FREQ_MASK;
 	val |= VIDEO_DIP_FREQ_VSYNC;
 
 	I915_WRITE(reg, val);
+	POSTING_READ(reg);
 }
 
 static void hsw_write_infoframe(struct drm_encoder *encoder,
@@ -289,18 +271,19 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
 	if (data_reg == 0)
 		return;
 
-	intel_wait_for_vblank(dev, intel_crtc->pipe);
-
 	val &= ~hsw_infoframe_enable(frame);
 	I915_WRITE(ctl_reg, val);
 
+	mmiowb();
 	for (i = 0; i < len; i += 4) {
 		I915_WRITE(data_reg + i, *data);
 		data++;
 	}
+	mmiowb();
 
 	val |= hsw_infoframe_enable(frame);
 	I915_WRITE(ctl_reg, val);
+	POSTING_READ(ctl_reg);
 }
 
 static void intel_set_infoframe(struct drm_encoder *encoder,
@@ -308,14 +291,11 @@ static void intel_set_infoframe(struct drm_encoder *encoder,
 {
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 
-	if (!intel_hdmi->has_hdmi_sink)
-		return;
-
 	intel_dip_infoframe_csum(frame);
 	intel_hdmi->write_infoframe(encoder, frame);
 }
 
-void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
+static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
 					 struct drm_display_mode *adjusted_mode)
 {
 	struct dip_infoframe avi_if = {
@@ -330,7 +310,7 @@ void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
 	intel_set_infoframe(encoder, &avi_if);
 }
 
-void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
+static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
 {
 	struct dip_infoframe spd_if;
 
@@ -345,6 +325,213 @@ void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
 	intel_set_infoframe(encoder, &spd_if);
 }
 
+static void g4x_set_infoframes(struct drm_encoder *encoder,
+			       struct drm_display_mode *adjusted_mode)
+{
+	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	u32 reg = VIDEO_DIP_CTL;
+	u32 val = I915_READ(reg);
+	u32 port;
+
+	/* If the registers were not initialized yet, they might be zeroes,
+	 * which means we're selecting the AVI DIP and we're setting its
+	 * frequency to once. This seems to really confuse the HW and make
+	 * things stop working (the register spec says the AVI always needs to
+	 * be sent every VSync). So here we avoid writing to the register more
+	 * than we need and also explicitly select the AVI DIP and explicitly
+	 * set its frequency to every VSync. Avoiding to write it twice seems to
+	 * be enough to solve the problem, but being defensive shouldn't hurt us
+	 * either. */
+	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+	if (!intel_hdmi->has_hdmi_sink) {
+		if (!(val & VIDEO_DIP_ENABLE))
+			return;
+		val &= ~VIDEO_DIP_ENABLE;
+		I915_WRITE(reg, val);
+		POSTING_READ(reg);
+		return;
+	}
+
+	switch (intel_hdmi->sdvox_reg) {
+	case SDVOB:
+		port = VIDEO_DIP_PORT_B;
+		break;
+	case SDVOC:
+		port = VIDEO_DIP_PORT_C;
+		break;
+	default:
+		return;
+	}
+
+	if (port != (val & VIDEO_DIP_PORT_MASK)) {
+		if (val & VIDEO_DIP_ENABLE) {
+			val &= ~VIDEO_DIP_ENABLE;
+			I915_WRITE(reg, val);
+			POSTING_READ(reg);
+		}
+		val &= ~VIDEO_DIP_PORT_MASK;
+		val |= port;
+	}
+
+	val |= VIDEO_DIP_ENABLE;
+	val &= ~VIDEO_DIP_ENABLE_VENDOR;
+
+	I915_WRITE(reg, val);
+	POSTING_READ(reg);
+
+	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+	intel_hdmi_set_spd_infoframe(encoder);
+}
+
+static void ibx_set_infoframes(struct drm_encoder *encoder,
+			       struct drm_display_mode *adjusted_mode)
+{
+	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+	u32 val = I915_READ(reg);
+	u32 port;
+
+	/* See the big comment in g4x_set_infoframes() */
+	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+	if (!intel_hdmi->has_hdmi_sink) {
+		if (!(val & VIDEO_DIP_ENABLE))
+			return;
+		val &= ~VIDEO_DIP_ENABLE;
+		I915_WRITE(reg, val);
+		POSTING_READ(reg);
+		return;
+	}
+
+	switch (intel_hdmi->sdvox_reg) {
+	case HDMIB:
+		port = VIDEO_DIP_PORT_B;
+		break;
+	case HDMIC:
+		port = VIDEO_DIP_PORT_C;
+		break;
+	case HDMID:
+		port = VIDEO_DIP_PORT_D;
+		break;
+	default:
+		return;
+	}
+
+	if (port != (val & VIDEO_DIP_PORT_MASK)) {
+		if (val & VIDEO_DIP_ENABLE) {
+			val &= ~VIDEO_DIP_ENABLE;
+			I915_WRITE(reg, val);
+			POSTING_READ(reg);
+		}
+		val &= ~VIDEO_DIP_PORT_MASK;
+		val |= port;
+	}
+
+	val |= VIDEO_DIP_ENABLE;
+	val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+		 VIDEO_DIP_ENABLE_GCP);
+
+	I915_WRITE(reg, val);
+	POSTING_READ(reg);
+
+	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+	intel_hdmi_set_spd_infoframe(encoder);
+}
+
+static void cpt_set_infoframes(struct drm_encoder *encoder,
+			       struct drm_display_mode *adjusted_mode)
+{
+	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+	u32 val = I915_READ(reg);
+
+	/* See the big comment in g4x_set_infoframes() */
+	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+	if (!intel_hdmi->has_hdmi_sink) {
+		if (!(val & VIDEO_DIP_ENABLE))
+			return;
+		val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI);
+		I915_WRITE(reg, val);
+		POSTING_READ(reg);
+		return;
+	}
+
+	/* Set both together, unset both together: see the spec. */
+	val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI;
+	val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+		 VIDEO_DIP_ENABLE_GCP);
+
+	I915_WRITE(reg, val);
+	POSTING_READ(reg);
+
+	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+	intel_hdmi_set_spd_infoframe(encoder);
+}
+
+static void vlv_set_infoframes(struct drm_encoder *encoder,
+			       struct drm_display_mode *adjusted_mode)
+{
+	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
+	u32 val = I915_READ(reg);
+
+	/* See the big comment in g4x_set_infoframes() */
+	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+	if (!intel_hdmi->has_hdmi_sink) {
+		if (!(val & VIDEO_DIP_ENABLE))
+			return;
+		val &= ~VIDEO_DIP_ENABLE;
+		I915_WRITE(reg, val);
+		POSTING_READ(reg);
+		return;
+	}
+
+	val |= VIDEO_DIP_ENABLE;
+	val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+		 VIDEO_DIP_ENABLE_GCP);
+
+	I915_WRITE(reg, val);
+	POSTING_READ(reg);
+
+	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+	intel_hdmi_set_spd_infoframe(encoder);
+}
+
+static void hsw_set_infoframes(struct drm_encoder *encoder,
+			       struct drm_display_mode *adjusted_mode)
+{
+	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
+	u32 val = I915_READ(reg);
+
+	if (!intel_hdmi->has_hdmi_sink) {
+		I915_WRITE(reg, 0);
+		POSTING_READ(reg);
+		return;
+	}
+
+	val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW |
+		 VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW);
+
+	I915_WRITE(reg, val);
+	POSTING_READ(reg);
+
+	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+	intel_hdmi_set_spd_infoframe(encoder);
+}
+
 static void intel_hdmi_mode_set(struct drm_encoder *encoder,
 				struct drm_display_mode *mode,
 				struct drm_display_mode *adjusted_mode)
@@ -355,7 +542,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 	u32 sdvox;
 
-	sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
+	sdvox = SDVO_ENCODING_HDMI;
 	if (!HAS_PCH_SPLIT(dev))
 		sdvox |= intel_hdmi->color_range;
 	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
@@ -388,8 +575,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
 	I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
 	POSTING_READ(intel_hdmi->sdvox_reg);
 
-	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
-	intel_hdmi_set_spd_infoframe(encoder);
+	intel_hdmi->set_infoframes(encoder, adjusted_mode);
 }
 
 static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
@@ -452,6 +638,27 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
 	return true;
 }
 
+static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi)
+{
+	struct drm_device *dev = intel_hdmi->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t bit;
+
+	switch (intel_hdmi->sdvox_reg) {
+	case SDVOB:
+		bit = HDMIB_HOTPLUG_LIVE_STATUS;
+		break;
+	case SDVOC:
+		bit = HDMIC_HOTPLUG_LIVE_STATUS;
+		break;
+	default:
+		bit = 0;
+		break;
+	}
+
+	return I915_READ(PORT_HOTPLUG_STAT) & bit;
+}
+
 static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
@@ -460,6 +667,9 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
 	struct edid *edid;
 	enum drm_connector_status status = connector_status_disconnected;
 
+	if (IS_G4X(connector->dev) && !g4x_hdmi_connected(intel_hdmi))
+		return status;
+
 	intel_hdmi->has_hdmi_sink = false;
 	intel_hdmi->has_audio = false;
 	edid = drm_get_edid(connector,
@@ -633,7 +843,6 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
 	struct intel_encoder *intel_encoder;
 	struct intel_connector *intel_connector;
 	struct intel_hdmi *intel_hdmi;
-	int i;
 
 	intel_hdmi = kzalloc(sizeof(struct intel_hdmi), GFP_KERNEL);
 	if (!intel_hdmi)
@@ -710,26 +919,19 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
 
 	if (!HAS_PCH_SPLIT(dev)) {
 		intel_hdmi->write_infoframe = g4x_write_infoframe;
-		I915_WRITE(VIDEO_DIP_CTL, 0);
+		intel_hdmi->set_infoframes = g4x_set_infoframes;
 	} else if (IS_VALLEYVIEW(dev)) {
 		intel_hdmi->write_infoframe = vlv_write_infoframe;
-		for_each_pipe(i)
-			I915_WRITE(VLV_TVIDEO_DIP_CTL(i), 0);
+		intel_hdmi->set_infoframes = vlv_set_infoframes;
 	} else if (IS_HASWELL(dev)) {
-		/* FIXME: Haswell has a new set of DIP frame registers, but we are
-		 * just doing the minimal required for HDMI to work at this stage.
-		 */
 		intel_hdmi->write_infoframe = hsw_write_infoframe;
-		for_each_pipe(i)
-			I915_WRITE(HSW_TVIDEO_DIP_CTL(i), 0);
+		intel_hdmi->set_infoframes = hsw_set_infoframes;
 	} else if (HAS_PCH_IBX(dev)) {
 		intel_hdmi->write_infoframe = ibx_write_infoframe;
-		for_each_pipe(i)
-			I915_WRITE(TVIDEO_DIP_CTL(i), 0);
+		intel_hdmi->set_infoframes = ibx_set_infoframes;
 	} else {
 		intel_hdmi->write_infoframe = cpt_write_infoframe;
-		for_each_pipe(i)
-			I915_WRITE(TVIDEO_DIP_CTL(i), 0);
+		intel_hdmi->set_infoframes = cpt_set_infoframes;
 	}
 
 	if (IS_HASWELL(dev))
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 458743d..830d0dd 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -226,7 +226,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
 	}
 	overlay->last_flip_req = request->seqno;
 	overlay->flip_tail = tail;
-	ret = i915_wait_request(ring, overlay->last_flip_req);
+	ret = i915_wait_seqno(ring, overlay->last_flip_req);
 	if (ret)
 		return ret;
 	i915_gem_retire_requests(dev);
@@ -452,7 +452,7 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
 	if (overlay->last_flip_req == 0)
 		return 0;
 
-	ret = i915_wait_request(ring, overlay->last_flip_req);
+	ret = i915_wait_seqno(ring, overlay->last_flip_req);
 	if (ret)
 		return ret;
 	i915_gem_retire_requests(dev);
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 2a1625d..7180cc8 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -56,7 +56,7 @@ intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
 void
 intel_pch_panel_fitting(struct drm_device *dev,
 			int fitting_mode,
-			struct drm_display_mode *mode,
+			const struct drm_display_mode *mode,
 			struct drm_display_mode *adjusted_mode)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index e5b84ff..f30850b 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -438,6 +438,9 @@ static int init_render_ring(struct intel_ring_buffer *ring)
 	if (INTEL_INFO(dev)->gen >= 6)
 		I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
 
+	if (IS_IVYBRIDGE(dev))
+		I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+
 	return ret;
 }
 
@@ -825,7 +828,11 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
 	if (ring->irq_refcount++ == 0) {
-		I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
+		if (IS_IVYBRIDGE(dev) && ring->id == RCS)
+			I915_WRITE_IMR(ring, ~(ring->irq_enable_mask |
+						GEN6_RENDER_L3_PARITY_ERROR));
+		else
+			I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
 		dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
 		I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 		POSTING_READ(GTIMR);
@@ -844,7 +851,10 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
 	if (--ring->irq_refcount == 0) {
-		I915_WRITE_IMR(ring, ~0);
+		if (IS_IVYBRIDGE(dev) && ring->id == RCS)
+			I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+		else
+			I915_WRITE_IMR(ring, ~0);
 		dev_priv->gt_irq_mask |= ring->irq_enable_mask;
 		I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 		POSTING_READ(GTIMR);
@@ -1100,7 +1110,7 @@ static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno)
 	was_interruptible = dev_priv->mm.interruptible;
 	dev_priv->mm.interruptible = false;
 
-	ret = i915_wait_request(ring, seqno);
+	ret = i915_wait_seqno(ring, seqno);
 
 	dev_priv->mm.interruptible = was_interruptible;
 	if (!ret)
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index b6a9d45..2f5106a 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -140,9 +140,6 @@ struct intel_sdvo {
 
 	/* DDC bus used by this SDVO encoder */
 	uint8_t ddc_bus;
-
-	/* Input timings for adjusted_mode */
-	struct intel_sdvo_dtd input_dtd;
 };
 
 struct intel_sdvo_connector {
@@ -953,11 +950,15 @@ intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo,
 	return true;
 }
 
+/* Asks the sdvo controller for the preferred input mode given the output mode.
+ * Unfortunately we have to set up the full output mode to do that. */
 static bool
-intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
-					struct drm_display_mode *mode,
-					struct drm_display_mode *adjusted_mode)
+intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
+				    struct drm_display_mode *mode,
+				    struct drm_display_mode *adjusted_mode)
 {
+	struct intel_sdvo_dtd input_dtd;
+
 	/* Reset the input timing to the screen. Assume always input 0. */
 	if (!intel_sdvo_set_target_input(intel_sdvo))
 		return false;
@@ -969,10 +970,10 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
 		return false;
 
 	if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
-						   &intel_sdvo->input_dtd))
+						   &input_dtd))
 		return false;
 
-	intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);
+	intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
 
 	return true;
 }
@@ -993,17 +994,17 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
 		if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode))
 			return false;
 
-		(void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,
-							     mode,
-							     adjusted_mode);
+		(void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
+							   mode,
+							   adjusted_mode);
 	} else if (intel_sdvo->is_lvds) {
 		if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
 							     intel_sdvo->sdvo_lvds_fixed_mode))
 			return false;
 
-		(void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,
-							     mode,
-							     adjusted_mode);
+		(void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
+							   mode,
+							   adjusted_mode);
 	}
 
 	/* Make the CRTC code factor in the SDVO pixel multiplier.  The
@@ -1057,7 +1058,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
 					     intel_sdvo->sdvo_lvds_fixed_mode);
 	else
 		intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
-	(void) intel_sdvo_set_output_timing(intel_sdvo, &output_dtd);
+	if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))
+		DRM_INFO("Setting output timings on %s failed\n",
+			 SDVO_NAME(intel_sdvo));
 
 	/* Set the input timing to the screen. Assume always input 0. */
 	if (!intel_sdvo_set_target_input(intel_sdvo))
@@ -1079,7 +1082,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
 	 * adjusted_mode.
 	 */
 	intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
-	(void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd);
+	if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd))
+		DRM_INFO("Setting input timings on %s failed\n",
+			 SDVO_NAME(intel_sdvo));
 
 	switch (pixel_multiplier) {
 	default:
@@ -1376,7 +1381,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
 
 	/* add 30ms delay when the output type might be TV */
 	if (intel_sdvo->caps.output_flags & SDVO_TV_MASK)
-		mdelay(30);
+		msleep(30);
 
 	if (!intel_sdvo_read_response(intel_sdvo, &response, 2))
 		return connector_status_unknown;
@@ -2521,6 +2526,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *intel_encoder;
 	struct intel_sdvo *intel_sdvo;
+	u32 hotplug_mask;
 	int i;
 
 	intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);
@@ -2552,10 +2558,18 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
 		}
 	}
 
-	if (intel_sdvo->is_sdvob)
-		dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
-	else
-		dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
+	hotplug_mask = 0;
+	if (IS_G4X(dev)) {
+		hotplug_mask = intel_sdvo->is_sdvob ?
+			SDVOB_HOTPLUG_INT_STATUS_G4X : SDVOC_HOTPLUG_INT_STATUS_G4X;
+	} else if (IS_GEN4(dev)) {
+		hotplug_mask = intel_sdvo->is_sdvob ?
+			SDVOB_HOTPLUG_INT_STATUS_I965 : SDVOC_HOTPLUG_INT_STATUS_I965;
+	} else {
+		hotplug_mask = intel_sdvo->is_sdvob ?
+			SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915;
+	}
+	dev_priv->hotplug_supported_mask |= hotplug_mask;
 
 	drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 153b9a1..1074bc5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -467,7 +467,7 @@ int nouveau_fbcon_init(struct drm_device *dev)
 	nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
 
 	ret = drm_fb_helper_init(dev, &nfbdev->helper,
-				 nv_two_heads(dev) ? 2 : 1, 4);
+				 dev->mode_config.num_crtc, 4);
 	if (ret) {
 		kfree(nfbdev);
 		return ret;
diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index a8d5f09..4c2d836 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -61,7 +61,7 @@ static int udl_parse_vendor_descriptor(struct drm_device *dev,
 			u8 length;
 			u16 key;
 
-			key = *((u16 *) desc);
+			key = le16_to_cpu(*((u16 *) desc));
 			desc += sizeof(u16);
 			length = *desc;
 			desc++;
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 034c80a..ad267a9 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -1,20 +1,11 @@
 #
 # HID driver configuration
 #
-menuconfig HID_SUPPORT
-	bool "HID Devices"
-	depends on INPUT
-	default y
-	---help---
-	  Say Y here to get to see options for various computer-human interface
-	  device drivers. This option alone does not add any kernel code.
-
-	  If you say N, all options in this submenu will be skipped and disabled.
-
-if HID_SUPPORT
+menu "HID support"
+     depends on INPUT
 
 config HID
-	tristate "Generic HID support"
+	tristate "HID bus support"
 	depends on INPUT
 	default y
 	---help---
@@ -23,14 +14,17 @@ config HID
 	  most commonly used to refer to the USB-HID specification, but other
 	  devices (such as, but not strictly limited to, Bluetooth) are
 	  designed using HID specification (this involves certain keyboards,
-	  mice, tablets, etc). This option compiles into kernel the generic
-	  HID layer code (parser, usages, etc.), which can then be used by
-	  transport-specific HID implementation (like USB or Bluetooth).
+	  mice, tablets, etc). This option adds the HID bus to the kernel,
+	  together with generic HID layer code. The HID devices are added and
+	  removed from the HID bus by the transport-layer drivers, such as
+	  usbhid (USB_HID) and hidp (BT_HIDP).
 
 	  For docs and specs, see http://www.usb.org/developers/hidpage/
 
 	  If unsure, say Y.
 
+if HID
+
 config HID_BATTERY_STRENGTH
 	bool "Battery level reporting for HID devices"
 	depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY
@@ -59,23 +53,43 @@ config HIDRAW
 
 	If unsure, say Y.
 
-source "drivers/hid/usbhid/Kconfig"
-
-menu "Special HID drivers"
+config UHID
+	tristate "User-space I/O driver support for HID subsystem"
 	depends on HID
+	default n
+	---help---
+	Say Y here if you want to provide HID I/O Drivers from user-space.
+	This allows to write I/O drivers in user-space and feed the data from
+	the device into the kernel. The kernel parses the HID reports, loads the
+	corresponding HID Device Driver or provides input devices on top of your
+	user-space device.
+
+	This driver cannot be used to parse HID-reports in user-space and write
+	special HID-drivers. You should use hidraw for that.
+	Instead, this driver allows to write the transport-layer driver in
+	user-space like USB-HID and Bluetooth-HID do in kernel-space.
+
+	If unsure, say N.
+
+	To compile this driver as a module, choose M here: the
+	module will be called uhid.
 
 config HID_GENERIC
 	tristate "Generic HID driver"
 	depends on HID
-	default y
+	default HID
 	---help---
-	Support for generic HID devices.
+	Support for generic devices on the HID bus. This includes most
+	keyboards and mice, joysticks, tablets and digitizers.
 
 	To compile this driver as a module, choose M here: the module
 	will be called hid-generic.
 
 	If unsure, say Y.
 
+menu "Special HID drivers"
+	depends on HID
+
 config HID_A4TECH
 	tristate "A4 tech mice" if EXPERT
 	depends on USB_HID
@@ -268,6 +282,19 @@ config HID_LCPOWER
 	---help---
 	Support for LC-Power RC1000MCE RF remote control.
 
+config HID_LENOVO_TPKBD
+	tristate "Lenovo ThinkPad USB Keyboard with TrackPoint"
+	depends on USB_HID
+	select NEW_LEDS
+	select LEDS_CLASS
+	---help---
+	Support for the Lenovo ThinkPad USB Keyboard with TrackPoint.
+
+	Say Y here if you have a Lenovo ThinkPad USB Keyboard with TrackPoint
+	and would like to use device-specific features like changing the
+	sensitivity of the trackpoint, using the microphone mute button or
+	controlling the mute and microphone mute LEDs.
+
 config HID_LOGITECH
 	tristate "Logitech devices" if EXPERT
 	depends on USB_HID
@@ -662,4 +689,8 @@ config HID_ZYDACRON
 
 endmenu
 
-endif # HID_SUPPORT
+endif # HID
+
+source "drivers/hid/usbhid/Kconfig"
+
+endmenu
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index ca6cc9f..dedc932 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -8,6 +8,7 @@ ifdef CONFIG_DEBUG_FS
 endif
 
 obj-$(CONFIG_HID)		+= hid.o
+obj-$(CONFIG_UHID)		+= uhid.o
 
 obj-$(CONFIG_HID_GENERIC)	+= hid-generic.o
 
@@ -54,6 +55,7 @@ obj-$(CONFIG_HID_KENSINGTON)	+= hid-kensington.o
 obj-$(CONFIG_HID_KEYTOUCH)	+= hid-keytouch.o
 obj-$(CONFIG_HID_KYE)		+= hid-kye.o
 obj-$(CONFIG_HID_LCPOWER)       += hid-lcpower.o
+obj-$(CONFIG_HID_LENOVO_TPKBD)	+= hid-lenovo-tpkbd.o
 obj-$(CONFIG_HID_LOGITECH)	+= hid-logitech.o
 obj-$(CONFIG_HID_LOGITECH_DJ)	+= hid-logitech-dj.o
 obj-$(CONFIG_HID_MAGICMOUSE)    += hid-magicmouse.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 8e3a6b2..8b637e4 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1544,6 +1544,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
@@ -1880,6 +1881,7 @@ static const struct hid_device_id hid_ignore_list[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AXENTIA, USB_DEVICE_ID_AXENTIA_FM_RADIO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 9373f53..f236847 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -160,6 +160,9 @@
 #define USB_VENDOR_ID_AVERMEDIA		0x07ca
 #define USB_DEVICE_ID_AVER_FM_MR800	0xb800
 
+#define USB_VENDOR_ID_AXENTIA		0x12cf
+#define USB_DEVICE_ID_AXENTIA_FM_RADIO	0x7111
+
 #define USB_VENDOR_ID_BAANTO		0x2453
 #define USB_DEVICE_ID_BAANTO_MT_190W2	0x0100
 
@@ -473,6 +476,9 @@
 #define USB_DEVICE_ID_LD_HYBRID		0x2090
 #define USB_DEVICE_ID_LD_HEATCONTROL	0x20A0
 
+#define USB_VENDOR_ID_LENOVO		0x17ef
+#define USB_DEVICE_ID_LENOVO_TPKBD	0x6009
+
 #define USB_VENDOR_ID_LG		0x1fd2
 #define USB_DEVICE_ID_LG_MULTITOUCH	0x0064
 
@@ -564,6 +570,9 @@
 #define USB_VENDOR_ID_NINTENDO		0x057e
 #define USB_DEVICE_ID_NINTENDO_WIIMOTE	0x0306
 
+#define USB_VENDOR_ID_NOVATEK		0x0603
+#define USB_DEVICE_ID_NOVATEK_PCT	0x0600
+
 #define USB_VENDOR_ID_NTRIG		0x1b96
 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN   0x0001
 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1   0x0003
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c
new file mode 100644
index 0000000..77d2df0
--- /dev/null
+++ b/drivers/hid/hid-lenovo-tpkbd.c
@@ -0,0 +1,564 @@
+/*
+ *  HID driver for Lenovo ThinkPad USB Keyboard with TrackPoint
+ *
+ *  Copyright (c) 2012 Bernhard Seibold
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/sysfs.h>
+#include <linux/device.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include "usbhid/usbhid.h"
+
+#include "hid-ids.h"
+
+/* This is only used for the trackpoint part of the driver, hence _tp */
+struct tpkbd_data_pointer {
+	int led_state;
+	struct led_classdev led_mute;
+	struct led_classdev led_micmute;
+	int press_to_select;
+	int dragging;
+	int release_to_select;
+	int select_right;
+	int sensitivity;
+	int press_speed;
+};
+
+#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
+
+static int tpkbd_input_mapping(struct hid_device *hdev,
+		struct hid_input *hi, struct hid_field *field,
+		struct hid_usage *usage, unsigned long **bit, int *max)
+{
+	struct usbhid_device *uhdev;
+
+	uhdev = (struct usbhid_device *) hdev->driver_data;
+	if (uhdev->ifnum == 1 && usage->hid == (HID_UP_BUTTON | 0x0010)) {
+		map_key_clear(KEY_MICMUTE);
+		return 1;
+	}
+	return 0;
+}
+
+#undef map_key_clear
+
+static int tpkbd_features_set(struct hid_device *hdev)
+{
+	struct hid_report *report;
+	struct tpkbd_data_pointer *data_pointer;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+	report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];
+
+	report->field[0]->value[0]  = data_pointer->press_to_select   ? 0x01 : 0x02;
+	report->field[0]->value[0] |= data_pointer->dragging          ? 0x04 : 0x08;
+	report->field[0]->value[0] |= data_pointer->release_to_select ? 0x10 : 0x20;
+	report->field[0]->value[0] |= data_pointer->select_right      ? 0x80 : 0x40;
+	report->field[1]->value[0] = 0x03; // unknown setting, imitate windows driver
+	report->field[2]->value[0] = data_pointer->sensitivity;
+	report->field[3]->value[0] = data_pointer->press_speed;
+
+	usbhid_submit_report(hdev, report, USB_DIR_OUT);
+	return 0;
+}
+
+static ssize_t pointer_press_to_select_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select);
+}
+
+static ssize_t pointer_press_to_select_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+	int value;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	if (kstrtoint(buf, 10, &value))
+		return -EINVAL;
+	if (value < 0 || value > 1)
+		return -EINVAL;
+
+	data_pointer->press_to_select = value;
+	tpkbd_features_set(hdev);
+
+	return count;
+}
+
+static ssize_t pointer_dragging_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging);
+}
+
+static ssize_t pointer_dragging_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+	int value;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	if (kstrtoint(buf, 10, &value))
+		return -EINVAL;
+	if (value < 0 || value > 1)
+		return -EINVAL;
+
+	data_pointer->dragging = value;
+	tpkbd_features_set(hdev);
+
+	return count;
+}
+
+static ssize_t pointer_release_to_select_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select);
+}
+
+static ssize_t pointer_release_to_select_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+	int value;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	if (kstrtoint(buf, 10, &value))
+		return -EINVAL;
+	if (value < 0 || value > 1)
+		return -EINVAL;
+
+	data_pointer->release_to_select = value;
+	tpkbd_features_set(hdev);
+
+	return count;
+}
+
+static ssize_t pointer_select_right_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right);
+}
+
+static ssize_t pointer_select_right_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+	int value;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	if (kstrtoint(buf, 10, &value))
+		return -EINVAL;
+	if (value < 0 || value > 1)
+		return -EINVAL;
+
+	data_pointer->select_right = value;
+	tpkbd_features_set(hdev);
+
+	return count;
+}
+
+static ssize_t pointer_sensitivity_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		data_pointer->sensitivity);
+}
+
+static ssize_t pointer_sensitivity_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+	int value;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
+		return -EINVAL;
+
+	data_pointer->sensitivity = value;
+	tpkbd_features_set(hdev);
+
+	return count;
+}
+
+static ssize_t pointer_press_speed_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		data_pointer->press_speed);
+}
+
+static ssize_t pointer_press_speed_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+	int value;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
+		return -EINVAL;
+
+	data_pointer->press_speed = value;
+	tpkbd_features_set(hdev);
+
+	return count;
+}
+
+static struct device_attribute dev_attr_pointer_press_to_select =
+	__ATTR(press_to_select, S_IWUSR | S_IRUGO,
+			pointer_press_to_select_show,
+			pointer_press_to_select_store);
+
+static struct device_attribute dev_attr_pointer_dragging =
+	__ATTR(dragging, S_IWUSR | S_IRUGO,
+			pointer_dragging_show,
+			pointer_dragging_store);
+
+static struct device_attribute dev_attr_pointer_release_to_select =
+	__ATTR(release_to_select, S_IWUSR | S_IRUGO,
+			pointer_release_to_select_show,
+			pointer_release_to_select_store);
+
+static struct device_attribute dev_attr_pointer_select_right =
+	__ATTR(select_right, S_IWUSR | S_IRUGO,
+			pointer_select_right_show,
+			pointer_select_right_store);
+
+static struct device_attribute dev_attr_pointer_sensitivity =
+	__ATTR(sensitivity, S_IWUSR | S_IRUGO,
+			pointer_sensitivity_show,
+			pointer_sensitivity_store);
+
+static struct device_attribute dev_attr_pointer_press_speed =
+	__ATTR(press_speed, S_IWUSR | S_IRUGO,
+			pointer_press_speed_show,
+			pointer_press_speed_store);
+
+static struct attribute *tpkbd_attributes_pointer[] = {
+	&dev_attr_pointer_press_to_select.attr,
+	&dev_attr_pointer_dragging.attr,
+	&dev_attr_pointer_release_to_select.attr,
+	&dev_attr_pointer_select_right.attr,
+	&dev_attr_pointer_sensitivity.attr,
+	&dev_attr_pointer_press_speed.attr,
+	NULL
+};
+
+static const struct attribute_group tpkbd_attr_group_pointer = {
+	.attrs = tpkbd_attributes_pointer,
+};
+
+static enum led_brightness tpkbd_led_brightness_get(
+			struct led_classdev *led_cdev)
+{
+	struct device *dev;
+	struct hid_device *hdev;
+	struct tpkbd_data_pointer *data_pointer;
+	int led_nr = 0;
+
+	dev = led_cdev->dev->parent;
+	hdev = container_of(dev, struct hid_device, dev);
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	if (led_cdev == &data_pointer->led_micmute)
+		led_nr = 1;
+
+	return data_pointer->led_state & (1 << led_nr)
+				? LED_FULL
+				: LED_OFF;
+}
+
+static void tpkbd_led_brightness_set(struct led_classdev *led_cdev,
+			enum led_brightness value)
+{
+	struct device *dev;
+	struct hid_device *hdev;
+	struct hid_report *report;
+	struct tpkbd_data_pointer *data_pointer;
+	int led_nr = 0;
+
+	dev = led_cdev->dev->parent;
+	hdev = container_of(dev, struct hid_device, dev);
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	if (led_cdev == &data_pointer->led_micmute)
+		led_nr = 1;
+
+	if (value == LED_OFF)
+		data_pointer->led_state &= ~(1 << led_nr);
+	else
+		data_pointer->led_state |= 1 << led_nr;
+
+	report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3];
+	report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1;
+	report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1;
+	usbhid_submit_report(hdev, report, USB_DIR_OUT);
+}
+
+static int tpkbd_probe_tp(struct hid_device *hdev)
+{
+	struct device *dev = &hdev->dev;
+	struct tpkbd_data_pointer *data_pointer;
+	size_t name_sz = strlen(dev_name(dev)) + 16;
+	char *name_mute, *name_micmute;
+	int ret;
+
+	if (sysfs_create_group(&hdev->dev.kobj,
+				&tpkbd_attr_group_pointer)) {
+		hid_warn(hdev, "Could not create sysfs group\n");
+	}
+
+	data_pointer = kzalloc(sizeof(struct tpkbd_data_pointer), GFP_KERNEL);
+	if (data_pointer == NULL) {
+		hid_err(hdev, "Could not allocate memory for driver data\n");
+		return -ENOMEM;
+	}
+
+	// set same default values as windows driver
+	data_pointer->sensitivity = 0xa0;
+	data_pointer->press_speed = 0x38;
+
+	name_mute = kzalloc(name_sz, GFP_KERNEL);
+	if (name_mute == NULL) {
+		hid_err(hdev, "Could not allocate memory for led data\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev));
+
+	name_micmute = kzalloc(name_sz, GFP_KERNEL);
+	if (name_micmute == NULL) {
+		hid_err(hdev, "Could not allocate memory for led data\n");
+		ret = -ENOMEM;
+		goto err2;
+	}
+	snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev));
+
+	hid_set_drvdata(hdev, data_pointer);
+
+	data_pointer->led_mute.name = name_mute;
+	data_pointer->led_mute.brightness_get = tpkbd_led_brightness_get;
+	data_pointer->led_mute.brightness_set = tpkbd_led_brightness_set;
+	data_pointer->led_mute.dev = dev;
+	led_classdev_register(dev, &data_pointer->led_mute);
+
+	data_pointer->led_micmute.name = name_micmute;
+	data_pointer->led_micmute.brightness_get = tpkbd_led_brightness_get;
+	data_pointer->led_micmute.brightness_set = tpkbd_led_brightness_set;
+	data_pointer->led_micmute.dev = dev;
+	led_classdev_register(dev, &data_pointer->led_micmute);
+
+	tpkbd_features_set(hdev);
+
+	return 0;
+
+err2:
+	kfree(name_mute);
+err:
+	kfree(data_pointer);
+	return ret;
+}
+
+static int tpkbd_probe(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	int ret;
+	struct usbhid_device *uhdev;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "hid_parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		hid_err(hdev, "hid_hw_start failed\n");
+		goto err_free;
+	}
+
+	uhdev = (struct usbhid_device *) hdev->driver_data;
+
+	if (uhdev->ifnum == 1)
+		return tpkbd_probe_tp(hdev);
+
+	return 0;
+err_free:
+	return ret;
+}
+
+static void tpkbd_remove_tp(struct hid_device *hdev)
+{
+	struct tpkbd_data_pointer *data_pointer;
+
+	sysfs_remove_group(&hdev->dev.kobj,
+			&tpkbd_attr_group_pointer);
+
+	data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev);
+
+	led_classdev_unregister(&data_pointer->led_micmute);
+	led_classdev_unregister(&data_pointer->led_mute);
+
+	hid_set_drvdata(hdev, NULL);
+	kfree(data_pointer);
+}
+
+static void tpkbd_remove(struct hid_device *hdev)
+{
+	struct usbhid_device *uhdev;
+
+	uhdev = (struct usbhid_device *) hdev->driver_data;
+	if (uhdev->ifnum == 1)
+		tpkbd_remove_tp(hdev);
+
+	hid_hw_stop(hdev);
+}
+
+static const struct hid_device_id tpkbd_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(hid, tpkbd_devices);
+
+static struct hid_driver tpkbd_driver = {
+	.name = "lenovo_tpkbd",
+	.id_table = tpkbd_devices,
+	.input_mapping = tpkbd_input_mapping,
+	.probe = tpkbd_probe,
+	.remove = tpkbd_remove,
+};
+
+static int __init tpkbd_init(void)
+{
+	return hid_register_driver(&tpkbd_driver);
+}
+
+static void __exit tpkbd_exit(void)
+{
+	hid_unregister_driver(&tpkbd_driver);
+}
+
+module_init(tpkbd_init);
+module_exit(tpkbd_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 5e8a7ed..0f9c146 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -436,27 +436,37 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
 
 static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
 {
-	struct dj_report dj_report;
+	struct dj_report *dj_report;
+	int retval;
 
-	memset(&dj_report, 0, sizeof(dj_report));
-	dj_report.report_id = REPORT_ID_DJ_SHORT;
-	dj_report.device_index = 0xFF;
-	dj_report.report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES;
-	return logi_dj_recv_send_report(djrcv_dev, &dj_report);
+	dj_report = kzalloc(sizeof(dj_report), GFP_KERNEL);
+	if (!dj_report)
+		return -ENOMEM;
+	dj_report->report_id = REPORT_ID_DJ_SHORT;
+	dj_report->device_index = 0xFF;
+	dj_report->report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES;
+	retval = logi_dj_recv_send_report(djrcv_dev, dj_report);
+	kfree(dj_report);
+	return retval;
 }
 
 static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
 					  unsigned timeout)
 {
-	struct dj_report dj_report;
+	struct dj_report *dj_report;
+	int retval;
 
-	memset(&dj_report, 0, sizeof(dj_report));
-	dj_report.report_id = REPORT_ID_DJ_SHORT;
-	dj_report.device_index = 0xFF;
-	dj_report.report_type = REPORT_TYPE_CMD_SWITCH;
-	dj_report.report_params[CMD_SWITCH_PARAM_DEVBITFIELD] = 0x3F;
-	dj_report.report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] = (u8)timeout;
-	return logi_dj_recv_send_report(djrcv_dev, &dj_report);
+	dj_report = kzalloc(sizeof(dj_report), GFP_KERNEL);
+	if (!dj_report)
+		return -ENOMEM;
+	dj_report->report_id = REPORT_ID_DJ_SHORT;
+	dj_report->device_index = 0xFF;
+	dj_report->report_type = REPORT_TYPE_CMD_SWITCH;
+	dj_report->report_params[CMD_SWITCH_PARAM_DEVBITFIELD] = 0x3F;
+	dj_report->report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] = (u8)timeout;
+	retval = logi_dj_recv_send_report(djrcv_dev, dj_report);
+	kfree(dj_report);
+	return retval;
 }
 
 
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 7cf3ffe..40ac665 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -426,8 +426,10 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
 		__set_bit(EV_ABS, input->evbit);
 
 		input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
-		input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0);
-		input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0);
+		input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2,
+				     4, 0);
+		input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255 << 2,
+				     4, 0);
 		input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
 
 		/* Note: Touch Y position from the device is inverted relative
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 6e3332a..61cc4cb 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -951,6 +951,11 @@ static const struct hid_device_id mt_devices[] = {
 		MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
 			USB_DEVICE_ID_PANABOARD_UBT880) },
 
+	/* Novatek Panel */
+	{ .driver_data = MT_CLS_DEFAULT,
+		MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK,
+			USB_DEVICE_ID_NOVATEK_PCT) },
+
 	/* PenMount panels */
 	{ .driver_data = MT_CLS_CONFIDENCE,
 		MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c
index aa95870..0a1805c 100644
--- a/drivers/hid/hid-wiimote-ext.c
+++ b/drivers/hid/hid-wiimote-ext.c
@@ -77,7 +77,7 @@ static __u16 wiiext_keymap[] = {
 	BTN_TR,		/* WIIEXT_KEY_RT */
 };
 
-/* diable all extensions */
+/* disable all extensions */
 static void ext_disable(struct wiimote_ext *ext)
 {
 	unsigned long flags;
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
new file mode 100644
index 0000000..119b7e6
--- /dev/null
+++ b/drivers/hid/uhid.c
@@ -0,0 +1,572 @@
+/*
+ * User-space I/O driver support for HID subsystem
+ * Copyright (c) 2012 David Herrmann
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/atomic.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/uhid.h>
+#include <linux/wait.h>
+
+#define UHID_NAME	"uhid"
+#define UHID_BUFSIZE	32
+
+struct uhid_device {
+	struct mutex devlock;
+	bool running;
+
+	__u8 *rd_data;
+	uint rd_size;
+
+	struct hid_device *hid;
+	struct uhid_event input_buf;
+
+	wait_queue_head_t waitq;
+	spinlock_t qlock;
+	__u8 head;
+	__u8 tail;
+	struct uhid_event *outq[UHID_BUFSIZE];
+
+	struct mutex report_lock;
+	wait_queue_head_t report_wait;
+	atomic_t report_done;
+	atomic_t report_id;
+	struct uhid_event report_buf;
+};
+
+static struct miscdevice uhid_misc;
+
+static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev)
+{
+	__u8 newhead;
+
+	newhead = (uhid->head + 1) % UHID_BUFSIZE;
+
+	if (newhead != uhid->tail) {
+		uhid->outq[uhid->head] = ev;
+		uhid->head = newhead;
+		wake_up_interruptible(&uhid->waitq);
+	} else {
+		hid_warn(uhid->hid, "Output queue is full\n");
+		kfree(ev);
+	}
+}
+
+static int uhid_queue_event(struct uhid_device *uhid, __u32 event)
+{
+	unsigned long flags;
+	struct uhid_event *ev;
+
+	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+	if (!ev)
+		return -ENOMEM;
+
+	ev->type = event;
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+	uhid_queue(uhid, ev);
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+
+	return 0;
+}
+
+static int uhid_hid_start(struct hid_device *hid)
+{
+	struct uhid_device *uhid = hid->driver_data;
+
+	return uhid_queue_event(uhid, UHID_START);
+}
+
+static void uhid_hid_stop(struct hid_device *hid)
+{
+	struct uhid_device *uhid = hid->driver_data;
+
+	hid->claimed = 0;
+	uhid_queue_event(uhid, UHID_STOP);
+}
+
+static int uhid_hid_open(struct hid_device *hid)
+{
+	struct uhid_device *uhid = hid->driver_data;
+
+	return uhid_queue_event(uhid, UHID_OPEN);
+}
+
+static void uhid_hid_close(struct hid_device *hid)
+{
+	struct uhid_device *uhid = hid->driver_data;
+
+	uhid_queue_event(uhid, UHID_CLOSE);
+}
+
+static int uhid_hid_input(struct input_dev *input, unsigned int type,
+			  unsigned int code, int value)
+{
+	struct hid_device *hid = input_get_drvdata(input);
+	struct uhid_device *uhid = hid->driver_data;
+	unsigned long flags;
+	struct uhid_event *ev;
+
+	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+	if (!ev)
+		return -ENOMEM;
+
+	ev->type = UHID_OUTPUT_EV;
+	ev->u.output_ev.type = type;
+	ev->u.output_ev.code = code;
+	ev->u.output_ev.value = value;
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+	uhid_queue(uhid, ev);
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+
+	return 0;
+}
+
+static int uhid_hid_parse(struct hid_device *hid)
+{
+	struct uhid_device *uhid = hid->driver_data;
+
+	return hid_parse_report(hid, uhid->rd_data, uhid->rd_size);
+}
+
+static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
+			    __u8 *buf, size_t count, unsigned char rtype)
+{
+	struct uhid_device *uhid = hid->driver_data;
+	__u8 report_type;
+	struct uhid_event *ev;
+	unsigned long flags;
+	int ret;
+	size_t uninitialized_var(len);
+	struct uhid_feature_answer_req *req;
+
+	if (!uhid->running)
+		return -EIO;
+
+	switch (rtype) {
+	case HID_FEATURE_REPORT:
+		report_type = UHID_FEATURE_REPORT;
+		break;
+	case HID_OUTPUT_REPORT:
+		report_type = UHID_OUTPUT_REPORT;
+		break;
+	case HID_INPUT_REPORT:
+		report_type = UHID_INPUT_REPORT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = mutex_lock_interruptible(&uhid->report_lock);
+	if (ret)
+		return ret;
+
+	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+	if (!ev) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+	ev->type = UHID_FEATURE;
+	ev->u.feature.id = atomic_inc_return(&uhid->report_id);
+	ev->u.feature.rnum = rnum;
+	ev->u.feature.rtype = report_type;
+
+	atomic_set(&uhid->report_done, 0);
+	uhid_queue(uhid, ev);
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+
+	ret = wait_event_interruptible_timeout(uhid->report_wait,
+				atomic_read(&uhid->report_done), 5 * HZ);
+
+	/*
+	 * Make sure "uhid->running" is cleared on shutdown before
+	 * "uhid->report_done" is set.
+	 */
+	smp_rmb();
+	if (!ret || !uhid->running) {
+		ret = -EIO;
+	} else if (ret < 0) {
+		ret = -ERESTARTSYS;
+	} else {
+		spin_lock_irqsave(&uhid->qlock, flags);
+		req = &uhid->report_buf.u.feature_answer;
+
+		if (req->err) {
+			ret = -EIO;
+		} else {
+			ret = 0;
+			len = min(count,
+				min_t(size_t, req->size, UHID_DATA_MAX));
+			memcpy(buf, req->data, len);
+		}
+
+		spin_unlock_irqrestore(&uhid->qlock, flags);
+	}
+
+	atomic_set(&uhid->report_done, 1);
+
+unlock:
+	mutex_unlock(&uhid->report_lock);
+	return ret ? ret : len;
+}
+
+static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
+			       unsigned char report_type)
+{
+	struct uhid_device *uhid = hid->driver_data;
+	__u8 rtype;
+	unsigned long flags;
+	struct uhid_event *ev;
+
+	switch (report_type) {
+	case HID_FEATURE_REPORT:
+		rtype = UHID_FEATURE_REPORT;
+		break;
+	case HID_OUTPUT_REPORT:
+		rtype = UHID_OUTPUT_REPORT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (count < 1 || count > UHID_DATA_MAX)
+		return -EINVAL;
+
+	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+	if (!ev)
+		return -ENOMEM;
+
+	ev->type = UHID_OUTPUT;
+	ev->u.output.size = count;
+	ev->u.output.rtype = rtype;
+	memcpy(ev->u.output.data, buf, count);
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+	uhid_queue(uhid, ev);
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+
+	return count;
+}
+
+static struct hid_ll_driver uhid_hid_driver = {
+	.start = uhid_hid_start,
+	.stop = uhid_hid_stop,
+	.open = uhid_hid_open,
+	.close = uhid_hid_close,
+	.hidinput_input_event = uhid_hid_input,
+	.parse = uhid_hid_parse,
+};
+
+static int uhid_dev_create(struct uhid_device *uhid,
+			   const struct uhid_event *ev)
+{
+	struct hid_device *hid;
+	int ret;
+
+	if (uhid->running)
+		return -EALREADY;
+
+	uhid->rd_size = ev->u.create.rd_size;
+	if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
+		return -EINVAL;
+
+	uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
+	if (!uhid->rd_data)
+		return -ENOMEM;
+
+	if (copy_from_user(uhid->rd_data, ev->u.create.rd_data,
+			   uhid->rd_size)) {
+		ret = -EFAULT;
+		goto err_free;
+	}
+
+	hid = hid_allocate_device();
+	if (IS_ERR(hid)) {
+		ret = PTR_ERR(hid);
+		goto err_free;
+	}
+
+	strncpy(hid->name, ev->u.create.name, 127);
+	hid->name[127] = 0;
+	strncpy(hid->phys, ev->u.create.phys, 63);
+	hid->phys[63] = 0;
+	strncpy(hid->uniq, ev->u.create.uniq, 63);
+	hid->uniq[63] = 0;
+
+	hid->ll_driver = &uhid_hid_driver;
+	hid->hid_get_raw_report = uhid_hid_get_raw;
+	hid->hid_output_raw_report = uhid_hid_output_raw;
+	hid->bus = ev->u.create.bus;
+	hid->vendor = ev->u.create.vendor;
+	hid->product = ev->u.create.product;
+	hid->version = ev->u.create.version;
+	hid->country = ev->u.create.country;
+	hid->driver_data = uhid;
+	hid->dev.parent = uhid_misc.this_device;
+
+	uhid->hid = hid;
+	uhid->running = true;
+
+	ret = hid_add_device(hid);
+	if (ret) {
+		hid_err(hid, "Cannot register HID device\n");
+		goto err_hid;
+	}
+
+	return 0;
+
+err_hid:
+	hid_destroy_device(hid);
+	uhid->hid = NULL;
+	uhid->running = false;
+err_free:
+	kfree(uhid->rd_data);
+	return ret;
+}
+
+static int uhid_dev_destroy(struct uhid_device *uhid)
+{
+	if (!uhid->running)
+		return -EINVAL;
+
+	/* clear "running" before setting "report_done" */
+	uhid->running = false;
+	smp_wmb();
+	atomic_set(&uhid->report_done, 1);
+	wake_up_interruptible(&uhid->report_wait);
+
+	hid_destroy_device(uhid->hid);
+	kfree(uhid->rd_data);
+
+	return 0;
+}
+
+static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
+{
+	if (!uhid->running)
+		return -EINVAL;
+
+	hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
+			 min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
+
+	return 0;
+}
+
+static int uhid_dev_feature_answer(struct uhid_device *uhid,
+				   struct uhid_event *ev)
+{
+	unsigned long flags;
+
+	if (!uhid->running)
+		return -EINVAL;
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+
+	/* id for old report; drop it silently */
+	if (atomic_read(&uhid->report_id) != ev->u.feature_answer.id)
+		goto unlock;
+	if (atomic_read(&uhid->report_done))
+		goto unlock;
+
+	memcpy(&uhid->report_buf, ev, sizeof(*ev));
+	atomic_set(&uhid->report_done, 1);
+	wake_up_interruptible(&uhid->report_wait);
+
+unlock:
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+	return 0;
+}
+
+static int uhid_char_open(struct inode *inode, struct file *file)
+{
+	struct uhid_device *uhid;
+
+	uhid = kzalloc(sizeof(*uhid), GFP_KERNEL);
+	if (!uhid)
+		return -ENOMEM;
+
+	mutex_init(&uhid->devlock);
+	mutex_init(&uhid->report_lock);
+	spin_lock_init(&uhid->qlock);
+	init_waitqueue_head(&uhid->waitq);
+	init_waitqueue_head(&uhid->report_wait);
+	uhid->running = false;
+	atomic_set(&uhid->report_done, 1);
+
+	file->private_data = uhid;
+	nonseekable_open(inode, file);
+
+	return 0;
+}
+
+static int uhid_char_release(struct inode *inode, struct file *file)
+{
+	struct uhid_device *uhid = file->private_data;
+	unsigned int i;
+
+	uhid_dev_destroy(uhid);
+
+	for (i = 0; i < UHID_BUFSIZE; ++i)
+		kfree(uhid->outq[i]);
+
+	kfree(uhid);
+
+	return 0;
+}
+
+static ssize_t uhid_char_read(struct file *file, char __user *buffer,
+				size_t count, loff_t *ppos)
+{
+	struct uhid_device *uhid = file->private_data;
+	int ret;
+	unsigned long flags;
+	size_t len;
+
+	/* they need at least the "type" member of uhid_event */
+	if (count < sizeof(__u32))
+		return -EINVAL;
+
+try_again:
+	if (file->f_flags & O_NONBLOCK) {
+		if (uhid->head == uhid->tail)
+			return -EAGAIN;
+	} else {
+		ret = wait_event_interruptible(uhid->waitq,
+						uhid->head != uhid->tail);
+		if (ret)
+			return ret;
+	}
+
+	ret = mutex_lock_interruptible(&uhid->devlock);
+	if (ret)
+		return ret;
+
+	if (uhid->head == uhid->tail) {
+		mutex_unlock(&uhid->devlock);
+		goto try_again;
+	} else {
+		len = min(count, sizeof(**uhid->outq));
+		if (copy_to_user(buffer, &uhid->outq[uhid->tail], len)) {
+			ret = -EFAULT;
+		} else {
+			kfree(uhid->outq[uhid->tail]);
+			uhid->outq[uhid->tail] = NULL;
+
+			spin_lock_irqsave(&uhid->qlock, flags);
+			uhid->tail = (uhid->tail + 1) % UHID_BUFSIZE;
+			spin_unlock_irqrestore(&uhid->qlock, flags);
+		}
+	}
+
+	mutex_unlock(&uhid->devlock);
+	return ret ? ret : len;
+}
+
+static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
+				size_t count, loff_t *ppos)
+{
+	struct uhid_device *uhid = file->private_data;
+	int ret;
+	size_t len;
+
+	/* we need at least the "type" member of uhid_event */
+	if (count < sizeof(__u32))
+		return -EINVAL;
+
+	ret = mutex_lock_interruptible(&uhid->devlock);
+	if (ret)
+		return ret;
+
+	memset(&uhid->input_buf, 0, sizeof(uhid->input_buf));
+	len = min(count, sizeof(uhid->input_buf));
+	if (copy_from_user(&uhid->input_buf, buffer, len)) {
+		ret = -EFAULT;
+		goto unlock;
+	}
+
+	switch (uhid->input_buf.type) {
+	case UHID_CREATE:
+		ret = uhid_dev_create(uhid, &uhid->input_buf);
+		break;
+	case UHID_DESTROY:
+		ret = uhid_dev_destroy(uhid);
+		break;
+	case UHID_INPUT:
+		ret = uhid_dev_input(uhid, &uhid->input_buf);
+		break;
+	case UHID_FEATURE_ANSWER:
+		ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+unlock:
+	mutex_unlock(&uhid->devlock);
+
+	/* return "count" not "len" to not confuse the caller */
+	return ret ? ret : count;
+}
+
+static unsigned int uhid_char_poll(struct file *file, poll_table *wait)
+{
+	struct uhid_device *uhid = file->private_data;
+
+	poll_wait(file, &uhid->waitq, wait);
+
+	if (uhid->head != uhid->tail)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+static const struct file_operations uhid_fops = {
+	.owner		= THIS_MODULE,
+	.open		= uhid_char_open,
+	.release	= uhid_char_release,
+	.read		= uhid_char_read,
+	.write		= uhid_char_write,
+	.poll		= uhid_char_poll,
+	.llseek		= no_llseek,
+};
+
+static struct miscdevice uhid_misc = {
+	.fops		= &uhid_fops,
+	.minor		= MISC_DYNAMIC_MINOR,
+	.name		= UHID_NAME,
+};
+
+static int __init uhid_init(void)
+{
+	return misc_register(&uhid_misc);
+}
+
+static void __exit uhid_exit(void)
+{
+	misc_deregister(&uhid_misc);
+}
+
+module_init(uhid_init);
+module_exit(uhid_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
+MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 0f20fd1..0108c59 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -1,13 +1,13 @@
-comment "USB Input Devices"
+menu "USB HID support"
 	depends on USB
 
 config USB_HID
-	tristate "USB Human Interface Device (full HID) support"
+	tristate "USB HID transport layer"
 	default y
 	depends on USB && INPUT
 	select HID
 	---help---
-	  Say Y here if you want full HID support to connect USB keyboards,
+	  Say Y here if you want to connect USB keyboards,
 	  mice, joysticks, graphic tablets, or any other HID based devices
 	  to your computer via USB, as well as Uninterruptible Power Supply
 	  (UPS) and monitor control devices.
@@ -81,4 +81,4 @@ config USB_MOUSE
 
 endmenu
 
-
+endmenu
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 6f1d167..4039353 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -314,6 +314,16 @@ config SENSORS_DS1621
 	  This driver can also be built as a module.  If so, the module
 	  will be called ds1621.
 
+config SENSORS_DA9052_ADC
+	tristate "Dialog DA9052/DA9053 ADC"
+	depends on PMIC_DA9052
+	help
+	  Say y here to support the ADC found on Dialog Semiconductor
+	  DA9052-BC and DA9053-AA/Bx PMICs.
+
+	  This driver can also be built as module. If so, the module
+	  will be called da9052-hwmon.
+
 config SENSORS_EXYNOS4_TMU
 	tristate "Temperature sensor on Samsung EXYNOS4"
 	depends on ARCH_EXYNOS4
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index e1eeac1..2f4c001 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_SENSORS_APPLESMC)	+= applesmc.o
 obj-$(CONFIG_SENSORS_ASC7621)	+= asc7621.o
 obj-$(CONFIG_SENSORS_ATXP1)	+= atxp1.o
 obj-$(CONFIG_SENSORS_CORETEMP)	+= coretemp.o
+obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
 obj-$(CONFIG_SENSORS_DME1737)	+= dme1737.o
 obj-$(CONFIG_SENSORS_DS620)	+= ds620.o
 obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index 4394e7e..fd1d1b1 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -366,11 +366,11 @@ static int adm1021_probe(struct i2c_client *client,
 	struct adm1021_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct adm1021_data),
+			    GFP_KERNEL);
 	if (!data) {
-		pr_debug("adm1021: detect failed, kzalloc failed!\n");
-		err = -ENOMEM;
-		goto error0;
+		pr_debug("adm1021: detect failed, devm_kzalloc failed!\n");
+		return -ENOMEM;
 	}
 
 	i2c_set_clientdata(client, data);
@@ -384,21 +384,18 @@ static int adm1021_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &adm1021_group);
 	if (err)
-		goto error1;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		err = PTR_ERR(data->hwmon_dev);
-		goto error3;
+		goto error;
 	}
 
 	return 0;
 
-error3:
+error:
 	sysfs_remove_group(&client->dev.kobj, &adm1021_group);
-error1:
-	kfree(data);
-error0:
 	return err;
 }
 
@@ -418,7 +415,6 @@ static int adm1021_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &adm1021_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index b8557f9..7e16e5d 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -477,11 +477,10 @@ static int adm1025_probe(struct i2c_client *client,
 	int err;
 	u8 config;
 
-	data = kzalloc(sizeof(struct adm1025_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct adm1025_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -492,7 +491,7 @@ static int adm1025_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &adm1025_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	/* Pin 11 is either in4 (+12V) or VID4 */
 	config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
@@ -513,9 +512,6 @@ static int adm1025_probe(struct i2c_client *client,
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &adm1025_group);
 	sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -569,7 +565,6 @@ static int adm1025_remove(struct i2c_client *client)
 	sysfs_remove_group(&client->dev.kobj, &adm1025_group);
 	sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index 1003219..0f068e7 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -1834,11 +1834,10 @@ static int adm1026_probe(struct i2c_client *client,
 	struct adm1026_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct adm1026_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct adm1026_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -1852,7 +1851,7 @@ static int adm1026_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &adm1026_group);
 	if (err)
-		goto exitfree;
+		return err;
 	if (data->config1 & CFG1_AIN8_9)
 		err = sysfs_create_group(&client->dev.kobj,
 					 &adm1026_group_in8_9);
@@ -1877,9 +1876,6 @@ exitremove:
 		sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
 	else
 		sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
-exitfree:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -1892,7 +1888,6 @@ static int adm1026_remove(struct i2c_client *client)
 		sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
 	else
 		sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 44e1fd7..c6a4631 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -954,11 +954,10 @@ static int adm1031_probe(struct i2c_client *client,
 	struct adm1031_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct adm1031_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct adm1031_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	data->chip_type = id->driver_data;
@@ -975,7 +974,7 @@ static int adm1031_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &adm1031_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	if (data->chip_type == adm1031) {
 		err = sysfs_create_group(&client->dev.kobj, &adm1031_group_opt);
@@ -994,9 +993,6 @@ static int adm1031_probe(struct i2c_client *client,
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &adm1031_group);
 	sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -1007,7 +1003,6 @@ static int adm1031_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &adm1031_group);
 	sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index c3c2865..5a78d10 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -650,11 +650,9 @@ static int adm9240_probe(struct i2c_client *new_client,
 	struct adm9240_data *data;
 	int err;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&new_client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(new_client, data);
 	mutex_init(&data->update_lock);
@@ -664,7 +662,7 @@ static int adm9240_probe(struct i2c_client *new_client,
 	/* populate sysfs filesystem */
 	err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&new_client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -676,9 +674,6 @@ static int adm9240_probe(struct i2c_client *new_client,
 
 exit_remove:
 	sysfs_remove_group(&new_client->dev.kobj, &adm9240_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -689,7 +684,6 @@ static int adm9240_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &adm9240_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index df29d13..861c756 100644
--- a/drivers/hwmon/adt7475.c
+++ b/drivers/hwmon/adt7475.c
@@ -1260,7 +1260,7 @@ static int adt7475_probe(struct i2c_client *client,
 	int i, ret = 0, revision;
 	u8 config2, config3;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
 
@@ -1344,7 +1344,7 @@ static int adt7475_probe(struct i2c_client *client,
 
 	ret = sysfs_create_group(&client->dev.kobj, &adt7475_attr_group);
 	if (ret)
-		goto efree;
+		return ret;
 
 	/* Features that can be disabled individually */
 	if (data->has_fan4) {
@@ -1410,8 +1410,6 @@ static int adt7475_probe(struct i2c_client *client,
 
 eremove:
 	adt7475_remove_files(client, data);
-efree:
-	kfree(data);
 	return ret;
 }
 
@@ -1421,7 +1419,6 @@ static int adt7475_remove(struct i2c_client *client)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	adt7475_remove_files(client, data);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 70d62f5..0162f55 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -8,7 +8,7 @@
  *
  * Based on hdaps.c driver:
  * Copyright (C) 2005 Robert Love <rml@novell.com>
- * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
+ * Copyright (C) 2005 Jesper Juhl <jj@chaosbits.net>
  *
  * Fan control based on smcFanControl:
  * Copyright (C) 2006 Hendrik Holtmann <holtmann@mac.com>
@@ -96,10 +96,6 @@ static const char *const fan_speed_fmt[] = {
 #define APPLESMC_INPUT_FUZZ	4	/* input event threshold */
 #define APPLESMC_INPUT_FLAT	4
 
-#define SENSOR_X 0
-#define SENSOR_Y 1
-#define SENSOR_Z 2
-
 #define to_index(attr) (to_sensor_dev_attr(attr)->index & 0xffff)
 #define to_option(attr) (to_sensor_dev_attr(attr)->index >> 16)
 
@@ -432,30 +428,19 @@ static int applesmc_has_key(const char *key, bool *value)
 }
 
 /*
- * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z).
+ * applesmc_read_s16 - Read 16-bit signed big endian register
  */
-static int applesmc_read_motion_sensor(int index, s16 *value)
+static int applesmc_read_s16(const char *key, s16 *value)
 {
 	u8 buffer[2];
 	int ret;
 
-	switch (index) {
-	case SENSOR_X:
-		ret = applesmc_read_key(MOTION_SENSOR_X_KEY, buffer, 2);
-		break;
-	case SENSOR_Y:
-		ret = applesmc_read_key(MOTION_SENSOR_Y_KEY, buffer, 2);
-		break;
-	case SENSOR_Z:
-		ret = applesmc_read_key(MOTION_SENSOR_Z_KEY, buffer, 2);
-		break;
-	default:
-		ret = -EINVAL;
-	}
+	ret = applesmc_read_key(key, buffer, 2);
+	if (ret)
+		return ret;
 
 	*value = ((s16)buffer[0] << 8) | buffer[1];
-
-	return ret;
+	return 0;
 }
 
 /*
@@ -624,8 +609,8 @@ static struct platform_driver applesmc_driver = {
  */
 static void applesmc_calibrate(void)
 {
-	applesmc_read_motion_sensor(SENSOR_X, &rest_x);
-	applesmc_read_motion_sensor(SENSOR_Y, &rest_y);
+	applesmc_read_s16(MOTION_SENSOR_X_KEY, &rest_x);
+	applesmc_read_s16(MOTION_SENSOR_Y_KEY, &rest_y);
 	rest_x = -rest_x;
 }
 
@@ -634,9 +619,9 @@ static void applesmc_idev_poll(struct input_polled_dev *dev)
 	struct input_dev *idev = dev->input;
 	s16 x, y;
 
-	if (applesmc_read_motion_sensor(SENSOR_X, &x))
+	if (applesmc_read_s16(MOTION_SENSOR_X_KEY, &x))
 		return;
-	if (applesmc_read_motion_sensor(SENSOR_Y, &y))
+	if (applesmc_read_s16(MOTION_SENSOR_Y_KEY, &y))
 		return;
 
 	x = -x;
@@ -659,13 +644,13 @@ static ssize_t applesmc_position_show(struct device *dev,
 	int ret;
 	s16 x, y, z;
 
-	ret = applesmc_read_motion_sensor(SENSOR_X, &x);
+	ret = applesmc_read_s16(MOTION_SENSOR_X_KEY, &x);
 	if (ret)
 		goto out;
-	ret = applesmc_read_motion_sensor(SENSOR_Y, &y);
+	ret = applesmc_read_s16(MOTION_SENSOR_Y_KEY, &y);
 	if (ret)
 		goto out;
-	ret = applesmc_read_motion_sensor(SENSOR_Z, &z);
+	ret = applesmc_read_s16(MOTION_SENSOR_Z_KEY, &z);
 	if (ret)
 		goto out;
 
diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c
index 7caa242..b867aab7 100644
--- a/drivers/hwmon/asc7621.c
+++ b/drivers/hwmon/asc7621.c
@@ -1109,7 +1109,8 @@ asc7621_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -EIO;
 
-	data = kzalloc(sizeof(struct asc7621_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct asc7621_data),
+			    GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
 
@@ -1143,7 +1144,6 @@ exit_remove:
 				   &(asc7621_params[i].sda.dev_attr));
 	}
 
-	kfree(data);
 	return err;
 }
 
@@ -1192,7 +1192,6 @@ static int asc7621_remove(struct i2c_client *client)
 				   &(asc7621_params[i].sda.dev_attr));
 	}
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index 58af6aa..aecb9ea 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -345,11 +345,10 @@ static int atxp1_probe(struct i2c_client *new_client,
 	struct atxp1_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct atxp1_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&new_client->dev, sizeof(struct atxp1_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	/* Get VRM */
 	data->vrm = vid_which_vrm();
@@ -362,7 +361,7 @@ static int atxp1_probe(struct i2c_client *new_client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&new_client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -377,9 +376,6 @@ static int atxp1_probe(struct i2c_client *new_client,
 
 exit_remove_files:
 	sysfs_remove_group(&new_client->dev.kobj, &atxp1_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 };
 
@@ -390,8 +386,6 @@ static int atxp1_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &atxp1_group);
 
-	kfree(data);
-
 	return 0;
 };
 
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 7f1feb2..faa16f8 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -693,7 +693,7 @@ static void __cpuinit get_core_online(unsigned int cpu)
 	 * sensors. We check this bit only, all the early CPUs
 	 * without thermal sensors will be filtered out.
 	 */
-	if (!cpu_has(c, X86_FEATURE_DTS))
+	if (!cpu_has(c, X86_FEATURE_DTHERM))
 		return;
 
 	if (!pdev) {
@@ -793,8 +793,8 @@ static struct notifier_block coretemp_cpu_notifier __refdata = {
 	.notifier_call = coretemp_cpu_callback,
 };
 
-static const struct x86_cpu_id coretemp_ids[] = {
-	{ X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTS },
+static const struct x86_cpu_id __initconst coretemp_ids[] = {
+	{ X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM },
 	{}
 };
 MODULE_DEVICE_TABLE(x86cpu, coretemp_ids);
diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c
new file mode 100644
index 0000000..fc65f2d
--- /dev/null
+++ b/drivers/hwmon/da9052-hwmon.c
@@ -0,0 +1,344 @@
+/*
+ * HWMON Driver for Dialog DA9052
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+struct da9052_hwmon {
+	struct da9052	*da9052;
+	struct device	*class_device;
+	struct mutex	hwmon_lock;
+};
+
+static const char * const input_names[] = {
+	[DA9052_ADC_VDDOUT]	=	"VDDOUT",
+	[DA9052_ADC_ICH]	=	"CHARGING CURRENT",
+	[DA9052_ADC_TBAT]	=	"BATTERY TEMP",
+	[DA9052_ADC_VBAT]	=	"BATTERY VOLTAGE",
+	[DA9052_ADC_IN4]	=	"ADC IN4",
+	[DA9052_ADC_IN5]	=	"ADC IN5",
+	[DA9052_ADC_IN6]	=	"ADC IN6",
+	[DA9052_ADC_TJUNC]	=	"BATTERY JUNCTION TEMP",
+	[DA9052_ADC_VBBAT]	=	"BACK-UP BATTERY VOLTAGE",
+};
+
+/* Conversion function for VDDOUT and VBAT */
+static inline int volt_reg_to_mV(int value)
+{
+	return DIV_ROUND_CLOSEST(value * 1000, 512) + 2500;
+}
+
+/* Conversion function for ADC channels 4, 5 and 6 */
+static inline int input_reg_to_mV(int value)
+{
+	return DIV_ROUND_CLOSEST(value * 2500, 1023);
+}
+
+/* Conversion function for VBBAT */
+static inline int vbbat_reg_to_mV(int value)
+{
+	return DIV_ROUND_CLOSEST(value * 2500, 512);
+}
+
+static int da9052_enable_vddout_channel(struct da9052 *da9052)
+{
+	int ret;
+
+	ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG);
+	if (ret < 0)
+		return ret;
+
+	ret |= DA9052_ADCCONT_AUTOVDDEN;
+
+	return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret);
+}
+
+static int da9052_disable_vddout_channel(struct da9052 *da9052)
+{
+	int ret;
+
+	ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG);
+	if (ret < 0)
+		return ret;
+
+	ret &= ~DA9052_ADCCONT_AUTOVDDEN;
+
+	return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret);
+}
+
+static ssize_t da9052_read_vddout(struct device *dev,
+				  struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int ret, vdd;
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	ret = da9052_enable_vddout_channel(hwmon->da9052);
+	if (ret < 0)
+		goto hwmon_err;
+
+	vdd = da9052_reg_read(hwmon->da9052, DA9052_VDD_RES_REG);
+	if (vdd < 0) {
+		ret = vdd;
+		goto hwmon_err_release;
+	}
+
+	ret = da9052_disable_vddout_channel(hwmon->da9052);
+	if (ret < 0)
+		goto hwmon_err;
+
+	mutex_unlock(&hwmon->hwmon_lock);
+	return sprintf(buf, "%d\n", volt_reg_to_mV(vdd));
+
+hwmon_err_release:
+	da9052_disable_vddout_channel(hwmon->da9052);
+hwmon_err:
+	mutex_unlock(&hwmon->hwmon_lock);
+	return ret;
+}
+
+static ssize_t da9052_read_ich(struct device *dev,
+			       struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int ret;
+
+	ret = da9052_reg_read(hwmon->da9052, DA9052_ICHG_AV_REG);
+	if (ret < 0)
+		return ret;
+
+	/* Equivalent to 3.9mA/bit in register ICHG_AV */
+	return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(ret * 39, 10));
+}
+
+static ssize_t da9052_read_tbat(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", da9052_adc_read_temp(hwmon->da9052));
+}
+
+static ssize_t da9052_read_vbat(struct device *dev,
+				struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int ret;
+
+	ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBAT);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", volt_reg_to_mV(ret));
+}
+
+static ssize_t da9052_read_misc_channel(struct device *dev,
+					struct device_attribute *devattr,
+					char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int channel = to_sensor_dev_attr(devattr)->index;
+	int ret;
+
+	ret = da9052_adc_manual_read(hwmon->da9052, channel);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", input_reg_to_mV(ret));
+}
+
+static ssize_t da9052_read_tjunc(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int tjunc;
+	int toffset;
+
+	tjunc = da9052_reg_read(hwmon->da9052, DA9052_TJUNC_RES_REG);
+	if (tjunc < 0)
+		return tjunc;
+
+	toffset = da9052_reg_read(hwmon->da9052, DA9052_T_OFFSET_REG);
+	if (toffset < 0)
+		return toffset;
+
+	/*
+	 * Degrees celsius = 1.708 * (TJUNC_RES - T_OFFSET) - 108.8
+	 * T_OFFSET is a trim value used to improve accuracy of the result
+	 */
+	return sprintf(buf, "%d\n", 1708 * (tjunc - toffset) - 108800);
+}
+
+static ssize_t da9052_read_vbbat(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
+	int ret;
+
+	ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBBAT);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", vbbat_reg_to_mV(ret));
+}
+
+static ssize_t da9052_hwmon_show_name(struct device *dev,
+				      struct device_attribute *devattr,
+				      char *buf)
+{
+	return sprintf(buf, "da9052-hwmon\n");
+}
+
+static ssize_t show_label(struct device *dev,
+			  struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n",
+		       input_names[to_sensor_dev_attr(devattr)->index]);
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9052_read_vddout, NULL,
+			  DA9052_ADC_VDDOUT);
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_VDDOUT);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, da9052_read_vbat, NULL,
+			  DA9052_ADC_VBAT);
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_VBAT);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, da9052_read_misc_channel, NULL,
+			  DA9052_ADC_IN4);
+static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_IN4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, da9052_read_misc_channel, NULL,
+			  DA9052_ADC_IN5);
+static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_IN5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, da9052_read_misc_channel, NULL,
+			  DA9052_ADC_IN6);
+static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_IN6);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, da9052_read_vbbat, NULL,
+			  DA9052_ADC_VBBAT);
+static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_VBBAT);
+
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, da9052_read_ich, NULL,
+			  DA9052_ADC_ICH);
+static SENSOR_DEVICE_ATTR(curr1_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_ICH);
+
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, da9052_read_tbat, NULL,
+			  DA9052_ADC_TBAT);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_TBAT);
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, da9052_read_tjunc, NULL,
+			  DA9052_ADC_TJUNC);
+static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO, show_label, NULL,
+			  DA9052_ADC_TJUNC);
+
+static DEVICE_ATTR(name, S_IRUGO, da9052_hwmon_show_name, NULL);
+
+static struct attribute *da9052_attr[] = {
+	&dev_attr_name.attr,
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_label.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_label.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_label.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in5_label.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_label.dev_attr.attr,
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_in9_label.dev_attr.attr,
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_label.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_label.dev_attr.attr,
+	&sensor_dev_attr_temp8_input.dev_attr.attr,
+	&sensor_dev_attr_temp8_label.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group da9052_attr_group = {.attrs = da9052_attr};
+
+static int __devinit da9052_hwmon_probe(struct platform_device *pdev)
+{
+	struct da9052_hwmon *hwmon;
+	int ret;
+
+	hwmon = devm_kzalloc(&pdev->dev, sizeof(struct da9052_hwmon),
+			     GFP_KERNEL);
+	if (!hwmon)
+		return -ENOMEM;
+
+	mutex_init(&hwmon->hwmon_lock);
+	hwmon->da9052 = dev_get_drvdata(pdev->dev.parent);
+
+	platform_set_drvdata(pdev, hwmon);
+
+	ret = sysfs_create_group(&pdev->dev.kobj, &da9052_attr_group);
+	if (ret)
+		goto err_mem;
+
+	hwmon->class_device = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(hwmon->class_device)) {
+		ret = PTR_ERR(hwmon->class_device);
+		goto err_sysfs;
+	}
+
+	return 0;
+
+err_sysfs:
+	sysfs_remove_group(&pdev->dev.kobj, &da9052_attr_group);
+err_mem:
+	return ret;
+}
+
+static int __devexit da9052_hwmon_remove(struct platform_device *pdev)
+{
+	struct da9052_hwmon *hwmon = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(hwmon->class_device);
+	sysfs_remove_group(&pdev->dev.kobj, &da9052_attr_group);
+
+	return 0;
+}
+
+static struct platform_driver da9052_hwmon_driver = {
+	.probe = da9052_hwmon_probe,
+	.remove = __devexit_p(da9052_hwmon_remove),
+	.driver = {
+		.name = "da9052-hwmon",
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(da9052_hwmon_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9052 HWMON driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-hwmon");
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index f647a33..1c56873 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -249,11 +249,10 @@ static int ds1621_probe(struct i2c_client *client,
 	struct ds1621_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct ds1621_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct ds1621_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -264,7 +263,7 @@ static int ds1621_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &ds1621_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -276,9 +275,6 @@ static int ds1621_probe(struct i2c_client *client,
 
  exit_remove_files:
 	sysfs_remove_group(&client->dev.kobj, &ds1621_group);
- exit_free:
-	kfree(data);
- exit:
 	return err;
 }
 
@@ -289,8 +285,6 @@ static int ds1621_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &ds1621_group);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c
index 840f511..ada12a9 100644
--- a/drivers/hwmon/emc6w201.c
+++ b/drivers/hwmon/emc6w201.c
@@ -492,11 +492,10 @@ static int emc6w201_probe(struct i2c_client *client,
 	struct emc6w201_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct emc6w201_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct emc6w201_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -504,7 +503,7 @@ static int emc6w201_probe(struct i2c_client *client,
 	/* Create sysfs attribute */
 	err = sysfs_create_group(&client->dev.kobj, &emc6w201_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	/* Expose as a hwmon device */
 	data->hwmon_dev = hwmon_device_register(&client->dev);
@@ -517,9 +516,6 @@ static int emc6w201_probe(struct i2c_client *client,
 
  exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &emc6w201_group);
- exit_free:
-	kfree(data);
- exit:
 	return err;
 }
 
@@ -529,7 +525,6 @@ static int emc6w201_remove(struct i2c_client *client)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &emc6w201_group);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 3e4da62..4dd7723 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -1386,20 +1386,20 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
 		"f71872f",
 	};
 
-	data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct f71805f_data),
+			    GFP_KERNEL);
 	if (!data) {
-		err = -ENOMEM;
 		pr_err("Out of memory\n");
-		goto exit;
+		return -ENOMEM;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start + ADDR_REG_OFFSET, 2, DRVNAME)) {
-		err = -EBUSY;
+	if (!devm_request_region(&pdev->dev, res->start + ADDR_REG_OFFSET, 2,
+				 DRVNAME)) {
 		dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n",
 			(unsigned long)(res->start + ADDR_REG_OFFSET),
 			(unsigned long)(res->start + ADDR_REG_OFFSET + 1));
-		goto exit_free;
+		return -EBUSY;
 	}
 	data->addr = res->start;
 	data->name = names[sio_data->kind];
@@ -1427,7 +1427,7 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
 	/* Register sysfs interface files */
 	err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group);
 	if (err)
-		goto exit_release_region;
+		return err;
 	if (data->has_in & (1 << 4)) { /* in4 */
 		err = sysfs_create_group(&pdev->dev.kobj,
 					 &f71805f_group_optin[0]);
@@ -1487,19 +1487,12 @@ exit_remove_files:
 	for (i = 0; i < 4; i++)
 		sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
 	sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
-exit_release_region:
-	release_region(res->start + ADDR_REG_OFFSET, 2);
-exit_free:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-exit:
 	return err;
 }
 
 static int __devexit f71805f_remove(struct platform_device *pdev)
 {
 	struct f71805f_data *data = platform_get_drvdata(pdev);
-	struct resource *res;
 	int i;
 
 	hwmon_device_unregister(data->hwmon_dev);
@@ -1507,11 +1500,6 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
 	for (i = 0; i < 4; i++)
 		sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
 	sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	release_region(res->start + ADDR_REG_OFFSET, 2);
 
 	return 0;
 }
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index 764a083..2c74673 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -544,11 +544,10 @@ static int gl518_probe(struct i2c_client *client,
 	struct gl518_data *data;
 	int err, revision;
 
-	data = kzalloc(sizeof(struct gl518_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct gl518_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	revision = gl518_read_value(client, GL518_REG_REVISION);
@@ -562,7 +561,7 @@ static int gl518_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &gl518_group);
 	if (err)
-		goto exit_free;
+		return err;
 	if (data->type == gl518sm_r80) {
 		err = sysfs_create_group(&client->dev.kobj, &gl518_group_r80);
 		if (err)
@@ -581,9 +580,6 @@ exit_remove_files:
 	sysfs_remove_group(&client->dev.kobj, &gl518_group);
 	if (data->type == gl518sm_r80)
 		sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -617,7 +613,6 @@ static int gl518_remove(struct i2c_client *client)
 	if (data->type == gl518sm_r80)
 		sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index 5ff452b..a21ff25 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -779,11 +779,10 @@ static int gl520_probe(struct i2c_client *client,
 	struct gl520_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct gl520_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct gl520_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -794,7 +793,7 @@ static int gl520_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &gl520_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	if (data->two_temps)
 		err = sysfs_create_group(&client->dev.kobj, &gl520_group_temp2);
@@ -816,9 +815,6 @@ exit_remove_files:
 	sysfs_remove_group(&client->dev.kobj, &gl520_group);
 	sysfs_remove_group(&client->dev.kobj, &gl520_group_in4);
 	sysfs_remove_group(&client->dev.kobj, &gl520_group_temp2);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -870,7 +866,6 @@ static int gl520_remove(struct i2c_client *client)
 	sysfs_remove_group(&client->dev.kobj, &gl520_group_in4);
 	sysfs_remove_group(&client->dev.kobj, &gl520_group_temp2);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 2ce8c44..b90b3e9 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -95,17 +95,17 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data,
 
 	fan_data->alarm = alarm;
 
-	err = gpio_request(alarm->gpio, "GPIO fan alarm");
+	err = devm_gpio_request(&pdev->dev, alarm->gpio, "GPIO fan alarm");
 	if (err)
 		return err;
 
 	err = gpio_direction_input(alarm->gpio);
 	if (err)
-		goto err_free_gpio;
+		return err;
 
 	err = device_create_file(&pdev->dev, &dev_attr_fan1_alarm);
 	if (err)
-		goto err_free_gpio;
+		return err;
 
 	/*
 	 * If the alarm GPIO don't support interrupts, just leave
@@ -117,8 +117,8 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data,
 
 	INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
 	irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
-	err = request_irq(alarm_irq, fan_alarm_irq_handler, IRQF_SHARED,
-			  "GPIO fan alarm", fan_data);
+	err = devm_request_irq(&pdev->dev, alarm_irq, fan_alarm_irq_handler,
+			       IRQF_SHARED, "GPIO fan alarm", fan_data);
 	if (err)
 		goto err_free_sysfs;
 
@@ -126,21 +126,14 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data,
 
 err_free_sysfs:
 	device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
-err_free_gpio:
-	gpio_free(alarm->gpio);
-
 	return err;
 }
 
 static void fan_alarm_free(struct gpio_fan_data *fan_data)
 {
 	struct platform_device *pdev = fan_data->pdev;
-	int alarm_irq = gpio_to_irq(fan_data->alarm->gpio);
 
-	if (alarm_irq >= 0)
-		free_irq(alarm_irq, fan_data);
 	device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
-	gpio_free(fan_data->alarm->gpio);
 }
 
 /*
@@ -365,15 +358,14 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
 	int i, err;
 
 	for (i = 0; i < num_ctrl; i++) {
-		err = gpio_request(ctrl[i], "GPIO fan control");
+		err = devm_gpio_request(&pdev->dev, ctrl[i],
+					"GPIO fan control");
 		if (err)
-			goto err_free_gpio;
+			return err;
 
 		err = gpio_direction_output(ctrl[i], gpio_get_value(ctrl[i]));
-		if (err) {
-			gpio_free(ctrl[i]);
-			goto err_free_gpio;
-		}
+		if (err)
+			return err;
 	}
 
 	fan_data->num_ctrl = num_ctrl;
@@ -382,32 +374,18 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
 	fan_data->speed = pdata->speed;
 	fan_data->pwm_enable = true; /* Enable manual fan speed control. */
 	fan_data->speed_index = get_fan_speed_index(fan_data);
-	if (fan_data->speed_index < 0) {
-		err = -ENODEV;
-		goto err_free_gpio;
-	}
+	if (fan_data->speed_index < 0)
+		return -ENODEV;
 
 	err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
-	if (err)
-		goto err_free_gpio;
-
-	return 0;
-
-err_free_gpio:
-	for (i = i - 1; i >= 0; i--)
-		gpio_free(ctrl[i]);
-
 	return err;
 }
 
 static void fan_ctrl_free(struct gpio_fan_data *fan_data)
 {
 	struct platform_device *pdev = fan_data->pdev;
-	int i;
 
 	sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
-	for (i = 0; i < fan_data->num_ctrl; i++)
-		gpio_free(fan_data->ctrl[i]);
 }
 
 /*
@@ -431,7 +409,8 @@ static int __devinit gpio_fan_probe(struct platform_device *pdev)
 	if (!pdata)
 		return -EINVAL;
 
-	fan_data = kzalloc(sizeof(struct gpio_fan_data), GFP_KERNEL);
+	fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data),
+				GFP_KERNEL);
 	if (!fan_data)
 		return -ENOMEM;
 
@@ -443,7 +422,7 @@ static int __devinit gpio_fan_probe(struct platform_device *pdev)
 	if (pdata->alarm) {
 		err = fan_alarm_init(fan_data, pdata->alarm);
 		if (err)
-			goto err_free_data;
+			return err;
 	}
 
 	/* Configure control GPIOs if available. */
@@ -480,10 +459,6 @@ err_free_ctrl:
 err_free_alarm:
 	if (fan_data->alarm)
 		fan_alarm_free(fan_data);
-err_free_data:
-	platform_set_drvdata(pdev, NULL);
-	kfree(fan_data);
-
 	return err;
 }
 
@@ -497,7 +472,6 @@ static int __devexit gpio_fan_remove(struct platform_device *pdev)
 		fan_alarm_free(fan_data);
 	if (fan_data->ctrl)
 		fan_ctrl_free(fan_data);
-	kfree(fan_data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c
index a9bfd67..e72ba5d 100644
--- a/drivers/hwmon/jc42.c
+++ b/drivers/hwmon/jc42.c
@@ -590,6 +590,6 @@ abort:
 
 module_i2c_driver(jc42_driver);
 
-MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
 MODULE_DESCRIPTION("JC42 driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index 7356b5e..f2fe807 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -33,9 +33,6 @@ static bool force;
 module_param(force, bool, 0444);
 MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
 
-/* PCI-IDs for Northbridge devices not used anywhere else */
-#define PCI_DEVICE_ID_AMD_15H_M10H_NB_F3	0x1403
-
 /* CPUID function 0x80000001, ebx */
 #define CPUID_PKGTYPE_MASK	0xf0000000
 #define CPUID_PKGTYPE_F		0x00000000
@@ -213,7 +210,7 @@ static DEFINE_PCI_DEVICE_TABLE(k10temp_id_table) = {
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
-	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_NB_F3) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
 	{}
 };
 MODULE_DEVICE_TABLE(pci, k10temp_id_table);
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index 35aac82..49a69c5 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -183,21 +183,17 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
 	u8 model, stepping;
 	struct k8temp_data *data;
 
-	data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&pdev->dev, sizeof(struct k8temp_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	model = boot_cpu_data.x86_model;
 	stepping = boot_cpu_data.x86_mask;
 
 	/* feature available since SH-C0, exclude older revisions */
-	if (((model == 4) && (stepping == 0)) ||
-	    ((model == 5) && (stepping <= 1))) {
-		err = -ENODEV;
-		goto exit_free;
-	}
+	if ((model == 4 && stepping == 0) ||
+	    (model == 5 && stepping <= 1))
+		return -ENODEV;
 
 	/*
 	 * AMD NPT family 0fh, i.e. RevF and RevG:
@@ -224,8 +220,7 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
 
 	if (scfg & (SEL_PLACE | SEL_CORE)) {
 		dev_err(&pdev->dev, "Configuration bit(s) stuck at 1!\n");
-		err = -ENODEV;
-		goto exit_free;
+		return -ENODEV;
 	}
 
 	scfg |= (SEL_PLACE | SEL_CORE);
@@ -307,10 +302,6 @@ exit_remove:
 	device_remove_file(&pdev->dev,
 			   &sensor_dev_attr_temp4_input.dev_attr);
 	device_remove_file(&pdev->dev, &dev_attr_name);
-exit_free:
-	pci_set_drvdata(pdev, NULL);
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -328,8 +319,6 @@ static void __devexit k8temp_remove(struct pci_dev *pdev)
 	device_remove_file(&pdev->dev,
 			   &sensor_dev_attr_temp4_input.dev_attr);
 	device_remove_file(&pdev->dev, &dev_attr_name);
-	pci_set_drvdata(pdev, NULL);
-	kfree(data);
 }
 
 static struct pci_driver k8temp_driver = {
diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c
index d264937..bd75d24 100644
--- a/drivers/hwmon/lineage-pem.c
+++ b/drivers/hwmon/lineage-pem.c
@@ -567,6 +567,6 @@ static struct i2c_driver pem_driver = {
 
 module_i2c_driver(pem_driver);
 
-MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
 MODULE_DESCRIPTION("Lineage CPL PEM hardware monitoring driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 602a0f0..eed4d94 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -1108,11 +1108,9 @@ static int lm63_probe(struct i2c_client *client,
 	struct lm63_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct lm63_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	data->valid = 0;
@@ -1129,7 +1127,7 @@ static int lm63_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &lm63_group);
 	if (err)
-		goto exit_free;
+		return err;
 	if (data->config & 0x04) { /* tachometer enabled */
 		err = sysfs_create_group(&client->dev.kobj, &lm63_group_fan1);
 		if (err)
@@ -1161,9 +1159,6 @@ exit_remove_files:
 		device_remove_file(&client->dev, &dev_attr_temp2_type);
 		sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut);
 	}
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -1179,7 +1174,6 @@ static int lm63_remove(struct i2c_client *client)
 		sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut);
 	}
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index a83f206..291edff 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -156,7 +156,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
 			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
 		return -EIO;
 
-	data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct lm75_data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -174,7 +174,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	status = lm75_read_value(client, LM75_REG_CONF);
 	if (status < 0) {
 		dev_dbg(&client->dev, "Can't read config? %d\n", status);
-		goto exit_free;
+		return status;
 	}
 	data->orig_conf = status;
 	new = status & ~clr_mask;
@@ -186,7 +186,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	/* Register sysfs hooks */
 	status = sysfs_create_group(&client->dev.kobj, &lm75_group);
 	if (status)
-		goto exit_free;
+		return status;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -201,8 +201,6 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &lm75_group);
-exit_free:
-	kfree(data);
 	return status;
 }
 
@@ -213,7 +211,6 @@ static int lm75_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm75_group);
 	lm75_write_value(client, LM75_REG_CONF, data->orig_conf);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index 0fca861..f82acf6 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -267,10 +267,9 @@ static const struct attribute_group lm77_group = {
 };
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
-static int lm77_detect(struct i2c_client *new_client,
-		       struct i2c_board_info *info)
+static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info)
 {
-	struct i2c_adapter *adapter = new_client->adapter;
+	struct i2c_adapter *adapter = client->adapter;
 	int i, cur, conf, hyst, crit, min, max;
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
@@ -292,18 +291,18 @@ static int lm77_detect(struct i2c_client *new_client,
 	 */
 
 	/* addresses cycling */
-	cur = i2c_smbus_read_word_data(new_client, 0);
-	conf = i2c_smbus_read_byte_data(new_client, 1);
-	hyst = i2c_smbus_read_word_data(new_client, 2);
-	crit = i2c_smbus_read_word_data(new_client, 3);
-	min = i2c_smbus_read_word_data(new_client, 4);
-	max = i2c_smbus_read_word_data(new_client, 5);
+	cur = i2c_smbus_read_word_data(client, 0);
+	conf = i2c_smbus_read_byte_data(client, 1);
+	hyst = i2c_smbus_read_word_data(client, 2);
+	crit = i2c_smbus_read_word_data(client, 3);
+	min = i2c_smbus_read_word_data(client, 4);
+	max = i2c_smbus_read_word_data(client, 5);
 	for (i = 8; i <= 0xff; i += 8) {
-		if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
-		 || i2c_smbus_read_word_data(new_client, i + 2) != hyst
-		 || i2c_smbus_read_word_data(new_client, i + 3) != crit
-		 || i2c_smbus_read_word_data(new_client, i + 4) != min
-		 || i2c_smbus_read_word_data(new_client, i + 5) != max)
+		if (i2c_smbus_read_byte_data(client, i + 1) != conf
+		 || i2c_smbus_read_word_data(client, i + 2) != hyst
+		 || i2c_smbus_read_word_data(client, i + 3) != crit
+		 || i2c_smbus_read_word_data(client, i + 4) != min
+		 || i2c_smbus_read_word_data(client, i + 5) != max)
 			return -ENODEV;
 	}
 
@@ -320,17 +319,17 @@ static int lm77_detect(struct i2c_client *new_client,
 		return -ENODEV;
 
 	/* 0x06 and 0x07 return the last read value */
-	cur = i2c_smbus_read_word_data(new_client, 0);
-	if (i2c_smbus_read_word_data(new_client, 6) != cur
-	 || i2c_smbus_read_word_data(new_client, 7) != cur)
+	cur = i2c_smbus_read_word_data(client, 0);
+	if (i2c_smbus_read_word_data(client, 6) != cur
+	 || i2c_smbus_read_word_data(client, 7) != cur)
 		return -ENODEV;
-	hyst = i2c_smbus_read_word_data(new_client, 2);
-	if (i2c_smbus_read_word_data(new_client, 6) != hyst
-	 || i2c_smbus_read_word_data(new_client, 7) != hyst)
+	hyst = i2c_smbus_read_word_data(client, 2);
+	if (i2c_smbus_read_word_data(client, 6) != hyst
+	 || i2c_smbus_read_word_data(client, 7) != hyst)
 		return -ENODEV;
-	min = i2c_smbus_read_word_data(new_client, 4);
-	if (i2c_smbus_read_word_data(new_client, 6) != min
-	 || i2c_smbus_read_word_data(new_client, 7) != min)
+	min = i2c_smbus_read_word_data(client, 4);
+	if (i2c_smbus_read_word_data(client, 6) != min
+	 || i2c_smbus_read_word_data(client, 7) != min)
 		return -ENODEV;
 
 	strlcpy(info->type, "lm77", I2C_NAME_SIZE);
@@ -338,31 +337,29 @@ static int lm77_detect(struct i2c_client *new_client,
 	return 0;
 }
 
-static int lm77_probe(struct i2c_client *new_client,
-		      const struct i2c_device_id *id)
+static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
+	struct device *dev = &client->dev;
 	struct lm77_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm77_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(dev, sizeof(struct lm77_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
-	i2c_set_clientdata(new_client, data);
+	i2c_set_clientdata(client, data);
 	data->valid = 0;
 	mutex_init(&data->update_lock);
 
 	/* Initialize the LM77 chip */
-	lm77_init_client(new_client);
+	lm77_init_client(client);
 
 	/* Register sysfs hooks */
-	err = sysfs_create_group(&new_client->dev.kobj, &lm77_group);
+	err = sysfs_create_group(&dev->kobj, &lm77_group);
 	if (err)
-		goto exit_free;
+		return err;
 
-	data->hwmon_dev = hwmon_device_register(&new_client->dev);
+	data->hwmon_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		err = PTR_ERR(data->hwmon_dev);
 		goto exit_remove;
@@ -371,10 +368,7 @@ static int lm77_probe(struct i2c_client *new_client,
 	return 0;
 
 exit_remove:
-	sysfs_remove_group(&new_client->dev.kobj, &lm77_group);
-exit_free:
-	kfree(data);
-exit:
+	sysfs_remove_group(&dev->kobj, &lm77_group);
 	return err;
 }
 
@@ -383,7 +377,6 @@ static int lm77_remove(struct i2c_client *client)
 	struct lm77_data *data = i2c_get_clientdata(client);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm77_group);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index f6bc414..c6ffafe 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -660,7 +660,7 @@ static int lm78_i2c_probe(struct i2c_client *client,
 	struct lm78_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct lm78_data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -674,20 +674,18 @@ static int lm78_i2c_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &lm78_group);
 	if (err)
-		goto ERROR3;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		err = PTR_ERR(data->hwmon_dev);
-		goto ERROR4;
+		goto error;
 	}
 
 	return 0;
 
-ERROR4:
+error:
 	sysfs_remove_group(&client->dev.kobj, &lm78_group);
-ERROR3:
-	kfree(data);
 	return err;
 }
 
@@ -697,7 +695,6 @@ static int lm78_i2c_remove(struct i2c_client *client)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm78_group);
-	kfree(data);
 
 	return 0;
 }
@@ -844,16 +841,14 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev)
 
 	/* Reserve the ISA region */
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start + LM78_ADDR_REG_OFFSET, 2, "lm78")) {
-		err = -EBUSY;
-		goto exit;
-	}
+	if (!devm_request_region(&pdev->dev, res->start + LM78_ADDR_REG_OFFSET,
+				 2, "lm78"))
+		return -EBUSY;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct lm78_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
-	data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit_release_region;
-	}
 	mutex_init(&data->lock);
 	data->isa_addr = res->start;
 	platform_set_drvdata(pdev, data);
@@ -888,25 +883,16 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev)
  exit_remove_files:
 	sysfs_remove_group(&pdev->dev.kobj, &lm78_group);
 	device_remove_file(&pdev->dev, &dev_attr_name);
-	kfree(data);
- exit_release_region:
-	release_region(res->start + LM78_ADDR_REG_OFFSET, 2);
- exit:
 	return err;
 }
 
 static int __devexit lm78_isa_remove(struct platform_device *pdev)
 {
 	struct lm78_data *data = platform_get_drvdata(pdev);
-	struct resource *res;
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&pdev->dev.kobj, &lm78_group);
 	device_remove_file(&pdev->dev, &dev_attr_name);
-	kfree(data);
-
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	release_region(res->start + LM78_ADDR_REG_OFFSET, 2);
 
 	return 0;
 }
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index e2c43e1..28a8b71 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -543,11 +543,9 @@ static int lm80_probe(struct i2c_client *client,
 	struct lm80_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm80_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct lm80_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -562,7 +560,7 @@ static int lm80_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &lm80_group);
 	if (err)
-		goto error_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -574,9 +572,6 @@ static int lm80_probe(struct i2c_client *client,
 
 error_remove:
 	sysfs_remove_group(&client->dev.kobj, &lm80_group);
-error_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -587,7 +582,6 @@ static int lm80_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm80_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index cd45b9d..e998034 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -343,11 +343,10 @@ static int lm83_probe(struct i2c_client *new_client,
 	struct lm83_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm83_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&new_client->dev, sizeof(struct lm83_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(new_client, data);
 	data->valid = 0;
@@ -362,7 +361,7 @@ static int lm83_probe(struct i2c_client *new_client,
 
 	err = sysfs_create_group(&new_client->dev.kobj, &lm83_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	if (id->driver_data == lm83) {
 		err = sysfs_create_group(&new_client->dev.kobj,
@@ -382,9 +381,6 @@ static int lm83_probe(struct i2c_client *new_client,
 exit_remove_files:
 	sysfs_remove_group(&new_client->dev.kobj, &lm83_group);
 	sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -396,7 +392,6 @@ static int lm83_remove(struct i2c_client *client)
 	sysfs_remove_group(&client->dev.kobj, &lm83_group);
 	sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 864c7d9..9f2dd77 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -1387,7 +1387,7 @@ static int lm85_probe(struct i2c_client *client,
 	struct lm85_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm85_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct lm85_data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -1419,7 +1419,7 @@ static int lm85_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &lm85_group);
 	if (err)
-		goto err_kfree;
+		return err;
 
 	/* minctl and temp_off exist on all chips except emc6d103s */
 	if (data->type != emc6d103s) {
@@ -1466,8 +1466,6 @@ static int lm85_probe(struct i2c_client *client,
 	/* Error out and cleanup code */
  err_remove_files:
 	lm85_remove_files(client, data);
- err_kfree:
-	kfree(data);
 	return err;
 }
 
@@ -1476,7 +1474,6 @@ static int lm85_remove(struct i2c_client *client)
 	struct lm85_data *data = i2c_get_clientdata(client);
 	hwmon_device_unregister(data->hwmon_dev);
 	lm85_remove_files(client, data);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 314d147..16e45d7 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -898,11 +898,9 @@ static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	struct lm87_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm87_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct lm87_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	data->valid = 0;
@@ -923,7 +921,7 @@ static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &lm87_group);
 	if (err)
-		goto exit_free;
+		goto exit_stop;
 
 	if (data->channel & CHAN_NO_FAN(0)) {
 		err = sysfs_create_group(&client->dev.kobj, &lm87_group_in6);
@@ -972,10 +970,8 @@ static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 exit_remove:
 	lm87_remove_files(client);
-exit_free:
+exit_stop:
 	lm87_write_value(client, LM87_REG_CONFIG, data->config);
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -987,7 +983,6 @@ static int lm87_remove(struct i2c_client *client)
 	lm87_remove_files(client);
 
 	lm87_write_value(client, LM87_REG_CONFIG, data->config);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 22b14a68..863412a 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -1399,11 +1399,10 @@ static int lm90_probe(struct i2c_client *client,
 	struct lm90_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm90_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct lm90_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
 
@@ -1474,8 +1473,6 @@ exit_remove_files:
 	lm90_remove_files(client, data);
 exit_restore:
 	lm90_restore_conf(client, data);
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -1487,7 +1484,6 @@ static int lm90_remove(struct i2c_client *client)
 	lm90_remove_files(client, data);
 	lm90_restore_conf(client, data);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index fdc691a..2282d77 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -373,11 +373,10 @@ static int lm92_probe(struct i2c_client *new_client,
 	struct lm92_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm92_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&new_client->dev, sizeof(struct lm92_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(new_client, data);
 	data->valid = 0;
@@ -389,7 +388,7 @@ static int lm92_probe(struct i2c_client *new_client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&new_client->dev.kobj, &lm92_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&new_client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -401,9 +400,6 @@ static int lm92_probe(struct i2c_client *new_client,
 
 exit_remove:
 	sysfs_remove_group(&new_client->dev.kobj, &lm92_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -414,7 +410,6 @@ static int lm92_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm92_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index 67e8fe2..bf94618 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -2738,15 +2738,13 @@ static int lm93_probe(struct i2c_client *client,
 	} else {
 		dev_dbg(&client->dev, "detect failed, "
 			"smbus byte and/or word data not supported!\n");
-		err = -ENODEV;
-		goto err_out;
+		return -ENODEV;
 	}
 
-	data = kzalloc(sizeof(struct lm93_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct lm93_data), GFP_KERNEL);
 	if (!data) {
 		dev_dbg(&client->dev, "out of memory!\n");
-		err = -ENOMEM;
-		goto err_out;
+		return -ENOMEM;
 	}
 	i2c_set_clientdata(client, data);
 
@@ -2760,7 +2758,7 @@ static int lm93_probe(struct i2c_client *client,
 
 	err = sysfs_create_group(&client->dev.kobj, &lm93_attr_grp);
 	if (err)
-		goto err_free;
+		return err;
 
 	/* Register hwmon driver class */
 	data->hwmon_dev = hwmon_device_register(&client->dev);
@@ -2770,9 +2768,6 @@ static int lm93_probe(struct i2c_client *client,
 	err = PTR_ERR(data->hwmon_dev);
 	dev_err(&client->dev, "error registering hwmon device.\n");
 	sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
-err_free:
-	kfree(data);
-err_out:
 	return err;
 }
 
@@ -2783,7 +2778,6 @@ static int lm93_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c
index 069b7d3..77476a5 100644
--- a/drivers/hwmon/ltc4261.c
+++ b/drivers/hwmon/ltc4261.c
@@ -292,6 +292,6 @@ static struct i2c_driver ltc4261_driver = {
 
 module_i2c_driver(ltc4261_driver);
 
-MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
 MODULE_DESCRIPTION("LTC4261 driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c
index 362a40e..f3978a4 100644
--- a/drivers/hwmon/max1111.c
+++ b/drivers/hwmon/max1111.c
@@ -168,7 +168,7 @@ static int __devinit max1111_probe(struct spi_device *spi)
 	if (err < 0)
 		return err;
 
-	data = kzalloc(sizeof(struct max1111_data), GFP_KERNEL);
+	data = devm_kzalloc(&spi->dev, sizeof(struct max1111_data), GFP_KERNEL);
 	if (data == NULL) {
 		dev_err(&spi->dev, "failed to allocate memory\n");
 		return -ENOMEM;
@@ -176,7 +176,7 @@ static int __devinit max1111_probe(struct spi_device *spi)
 
 	err = setup_transfer(data);
 	if (err)
-		goto err_free_data;
+		return err;
 
 	mutex_init(&data->drvdata_lock);
 
@@ -186,7 +186,7 @@ static int __devinit max1111_probe(struct spi_device *spi)
 	err = sysfs_create_group(&spi->dev.kobj, &max1111_attr_group);
 	if (err) {
 		dev_err(&spi->dev, "failed to create attribute group\n");
-		goto err_free_data;
+		return err;
 	}
 
 	data->hwmon_dev = hwmon_device_register(&spi->dev);
@@ -203,8 +203,6 @@ static int __devinit max1111_probe(struct spi_device *spi)
 
 err_remove:
 	sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
-err_free_data:
-	kfree(data);
 	return err;
 }
 
@@ -215,7 +213,6 @@ static int __devexit max1111_remove(struct spi_device *spi)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
 	mutex_destroy(&data->drvdata_lock);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
index 822261b..019427d 100644
--- a/drivers/hwmon/max16065.c
+++ b/drivers/hwmon/max16065.c
@@ -692,6 +692,6 @@ static struct i2c_driver max16065_driver = {
 
 module_i2c_driver(max16065_driver);
 
-MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
 MODULE_DESCRIPTION("MAX16065 driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index ecac04a..6c11ec2 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -267,11 +267,10 @@ static int max1619_probe(struct i2c_client *new_client,
 	struct max1619_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct max1619_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&new_client->dev, sizeof(struct max1619_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(new_client, data);
 	data->valid = 0;
@@ -283,7 +282,7 @@ static int max1619_probe(struct i2c_client *new_client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&new_client->dev.kobj, &max1619_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&new_client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -295,9 +294,6 @@ static int max1619_probe(struct i2c_client *new_client,
 
 exit_remove_files:
 	sysfs_remove_group(&new_client->dev.kobj, &max1619_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -323,7 +319,6 @@ static int max1619_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &max1619_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index de8f7ad..6e60036 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -548,11 +548,10 @@ static int max6639_probe(struct i2c_client *client,
 	struct max6639_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct max6639_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct max6639_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -560,12 +559,12 @@ static int max6639_probe(struct i2c_client *client,
 	/* Initialize the max6639 chip */
 	err = max6639_init_client(client);
 	if (err < 0)
-		goto error_free;
+		return err;
 
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &max6639_group);
 	if (err)
-		goto error_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -579,9 +578,6 @@ static int max6639_probe(struct i2c_client *client,
 
 error_remove:
 	sysfs_remove_group(&client->dev.kobj, &max6639_group);
-error_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -592,7 +588,6 @@ static int max6639_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &max6639_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c
index 4298909..bf236c0 100644
--- a/drivers/hwmon/max6642.c
+++ b/drivers/hwmon/max6642.c
@@ -286,11 +286,10 @@ static int max6642_probe(struct i2c_client *new_client,
 	struct max6642_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct max6642_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&new_client->dev, sizeof(struct max6642_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(new_client, data);
 	mutex_init(&data->update_lock);
@@ -301,7 +300,7 @@ static int max6642_probe(struct i2c_client *new_client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&new_client->dev.kobj, &max6642_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&new_client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -313,9 +312,6 @@ static int max6642_probe(struct i2c_client *new_client,
 
 exit_remove_files:
 	sysfs_remove_group(&new_client->dev.kobj, &max6642_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -326,7 +322,6 @@ static int max6642_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &max6642_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index 33a8a7f..f739f83 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -545,7 +545,8 @@ static int max6650_probe(struct i2c_client *client,
 	struct max6650_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct max6650_data),
+			    GFP_KERNEL);
 	if (!data) {
 		dev_err(&client->dev, "out of memory.\n");
 		return -ENOMEM;
@@ -560,11 +561,11 @@ static int max6650_probe(struct i2c_client *client,
 	 */
 	err = max6650_init_client(client);
 	if (err)
-		goto err_free;
+		return err;
 
 	err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
 	if (err)
-		goto err_free;
+		return err;
 	/* 3 additional fan inputs for the MAX6651 */
 	if (data->nr_fans == 4) {
 		err = sysfs_create_group(&client->dev.kobj, &max6651_attr_grp);
@@ -582,8 +583,6 @@ static int max6650_probe(struct i2c_client *client,
 		sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
 err_remove:
 	sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
-err_free:
-	kfree(data);
 	return err;
 }
 
@@ -595,7 +594,6 @@ static int max6650_remove(struct i2c_client *client)
 	if (data->nr_fans == 4)
 		sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
 	sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c
index ce86c5e..cf47a59 100644
--- a/drivers/hwmon/mc13783-adc.c
+++ b/drivers/hwmon/mc13783-adc.c
@@ -179,7 +179,7 @@ static int __init mc13783_adc_probe(struct platform_device *pdev)
 	const struct platform_device_id *id = platform_get_device_id(pdev);
 	char *dash;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
@@ -194,7 +194,7 @@ static int __init mc13783_adc_probe(struct platform_device *pdev)
 	/* Register sysfs hooks */
 	ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base);
 	if (ret)
-		goto out_err_create_base;
+		return ret;
 
 	if (id->driver_data & MC13783_ADC_16CHANS) {
 		ret = sysfs_create_group(&pdev->dev.kobj,
@@ -230,11 +230,6 @@ out_err_create_ts:
 out_err_create_16chans:
 
 	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
-out_err_create_base:
-
-	platform_set_drvdata(pdev, NULL);
-	kfree(priv);
-
 	return ret;
 }
 
@@ -253,9 +248,6 @@ static int __devexit mc13783_adc_remove(struct platform_device *pdev)
 
 	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
 
-	platform_set_drvdata(pdev, NULL);
-	kfree(priv);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index 6da9696..74a6c58 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -351,7 +351,7 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
 
 	data->dev = &pdev->dev;
 	data->pdata = pdata;
-	strncpy(data->name, pdev->id_entry->name, PLATFORM_NAME_SIZE);
+	strlcpy(data->name, pdev->id_entry->name, sizeof(data->name));
 
 	switch (pdev->id_entry->driver_data) {
 	case TYPE_NCPXXWB473:
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index 79ba48c..91d5b2a 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -1230,7 +1230,7 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
 	int use_thermistors = 0;
 	struct device *dev = &pdev->dev;
 
-	data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL);
+	data = devm_kzalloc(dev, sizeof(struct pc87360_data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -1269,15 +1269,12 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
 	for (i = 0; i < LDNI_MAX; i++) {
 		data->address[i] = extra_isa[i];
 		if (data->address[i]
-		 && !request_region(extra_isa[i], PC87360_EXTENT,
-				    pc87360_driver.driver.name)) {
+		 && !devm_request_region(dev, extra_isa[i], PC87360_EXTENT,
+					 pc87360_driver.driver.name)) {
 			dev_err(dev, "Region 0x%x-0x%x already "
 				"in use!\n", extra_isa[i],
 				extra_isa[i]+PC87360_EXTENT-1);
-			for (i--; i >= 0; i--)
-				release_region(extra_isa[i], PC87360_EXTENT);
-			err = -EBUSY;
-			goto ERROR1;
+			return -EBUSY;
 		}
 	}
 
@@ -1325,13 +1322,13 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
 	if (data->innr) {
 		err = sysfs_create_group(&dev->kobj, &pc8736x_vin_group);
 		if (err)
-			goto ERROR3;
+			goto error;
 	}
 
 	if (data->innr == 14) {
 		err = sysfs_create_group(&dev->kobj, &pc8736x_therm_group);
 		if (err)
-			goto ERROR3;
+			goto error;
 	}
 
 	/* create device attr-files for varying sysfs groups */
@@ -1341,11 +1338,11 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
 			err = sysfs_create_group(&dev->kobj,
 						 &pc8736x_temp_attr_group[i]);
 			if (err)
-				goto ERROR3;
+				goto error;
 		}
 		err = device_create_file(dev, &dev_attr_alarms_temp);
 		if (err)
-			goto ERROR3;
+			goto error;
 	}
 
 	for (i = 0; i < data->fannr; i++) {
@@ -1353,49 +1350,37 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
 			err = sysfs_create_group(&dev->kobj,
 						 &pc8736x_fan_attr_group[i]);
 			if (err)
-				goto ERROR3;
+				goto error;
 		}
 		if (FAN_CONFIG_CONTROL(data->fan_conf, i)) {
 			err = device_create_file(dev, &pwm[i].dev_attr);
 			if (err)
-				goto ERROR3;
+				goto error;
 		}
 	}
 
 	err = device_create_file(dev, &dev_attr_name);
 	if (err)
-		goto ERROR3;
+		goto error;
 
 	data->hwmon_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		err = PTR_ERR(data->hwmon_dev);
-		goto ERROR3;
+		goto error;
 	}
 	return 0;
 
-ERROR3:
+error:
 	pc87360_remove_files(dev);
-	for (i = 0; i < 3; i++) {
-		if (data->address[i])
-			release_region(data->address[i], PC87360_EXTENT);
-	}
-ERROR1:
-	kfree(data);
 	return err;
 }
 
 static int __devexit pc87360_remove(struct platform_device *pdev)
 {
 	struct pc87360_data *data = platform_get_drvdata(pdev);
-	int i;
 
 	hwmon_device_unregister(data->hwmon_dev);
 	pc87360_remove_files(&pdev->dev);
-	for (i = 0; i < 3; i++) {
-		if (data->address[i])
-			release_region(data->address[i], PC87360_EXTENT);
-	}
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 37059a3..f185b1f 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -956,44 +956,28 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
  * Device detection, attach and detach
  */
 
-static void pc87427_release_regions(struct platform_device *pdev, int count)
-{
-	struct resource *res;
-	int i;
-
-	for (i = 0; i < count; i++) {
-		res = platform_get_resource(pdev, IORESOURCE_IO, i);
-		release_region(res->start, resource_size(res));
-	}
-}
-
 static int __devinit pc87427_request_regions(struct platform_device *pdev,
 					     int count)
 {
 	struct resource *res;
-	int i, err = 0;
+	int i;
 
 	for (i = 0; i < count; i++) {
 		res = platform_get_resource(pdev, IORESOURCE_IO, i);
 		if (!res) {
-			err = -ENOENT;
 			dev_err(&pdev->dev, "Missing resource #%d\n", i);
-			break;
+			return -ENOENT;
 		}
-		if (!request_region(res->start, resource_size(res), DRVNAME)) {
-			err = -EBUSY;
+		if (!devm_request_region(&pdev->dev, res->start,
+					 resource_size(res), DRVNAME)) {
 			dev_err(&pdev->dev,
 				"Failed to request region 0x%lx-0x%lx\n",
 				(unsigned long)res->start,
 				(unsigned long)res->end);
-			break;
+			return -EBUSY;
 		}
 	}
-
-	if (err && i)
-		pc87427_release_regions(pdev, i);
-
-	return err;
+	return 0;
 }
 
 static void __devinit pc87427_init_device(struct device *dev)
@@ -1094,11 +1078,11 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
 	struct pc87427_data *data;
 	int i, err, res_count;
 
-	data = kzalloc(sizeof(struct pc87427_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct pc87427_data),
+			    GFP_KERNEL);
 	if (!data) {
-		err = -ENOMEM;
 		pr_err("Out of memory\n");
-		goto exit;
+		return -ENOMEM;
 	}
 
 	data->address[0] = sio_data->address[0];
@@ -1107,7 +1091,7 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
 
 	err = pc87427_request_regions(pdev, res_count);
 	if (err)
-		goto exit_kfree;
+		return err;
 
 	mutex_init(&data->lock);
 	data->name = "pc87427";
@@ -1117,7 +1101,7 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
 	/* Register sysfs hooks */
 	err = device_create_file(&pdev->dev, &dev_attr_name);
 	if (err)
-		goto exit_release_region;
+		return err;
 	for (i = 0; i < 8; i++) {
 		if (!(data->fan_enabled & (1 << i)))
 			continue;
@@ -1154,28 +1138,15 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
 
 exit_remove_files:
 	pc87427_remove_files(&pdev->dev);
-exit_release_region:
-	pc87427_release_regions(pdev, res_count);
-exit_kfree:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-exit:
 	return err;
 }
 
 static int __devexit pc87427_remove(struct platform_device *pdev)
 {
 	struct pc87427_data *data = platform_get_drvdata(pdev);
-	int res_count;
-
-	res_count = (data->address[0] != 0) + (data->address[1] != 0);
 
 	hwmon_device_unregister(data->hwmon_dev);
 	pc87427_remove_files(&pdev->dev);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
-	pc87427_release_regions(pdev, res_count);
 
 	return 0;
 }
diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c
index 4174c74..825883d 100644
--- a/drivers/hwmon/pcf8591.c
+++ b/drivers/hwmon/pcf8591.c
@@ -200,11 +200,10 @@ static int pcf8591_probe(struct i2c_client *client,
 	struct pcf8591_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct pcf8591_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -215,7 +214,7 @@ static int pcf8591_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group);
 	if (err)
-		goto exit_kfree;
+		return err;
 
 	/* Register input2 if not in "two differential inputs" mode */
 	if (input_mode != 3) {
@@ -242,9 +241,6 @@ static int pcf8591_probe(struct i2c_client *client,
 exit_sysfs_remove:
 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
-exit_kfree:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -255,7 +251,6 @@ static int pcf8591_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
-	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 6c4d8eb..8275f0e 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -593,17 +593,14 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
 
 	/* Reserve the ISA region */
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, SIS5595_EXTENT,
-			    sis5595_driver.driver.name)) {
-		err = -EBUSY;
-		goto exit;
-	}
+	if (!devm_request_region(&pdev->dev, res->start, SIS5595_EXTENT,
+				 sis5595_driver.driver.name))
+		return -EBUSY;
 
-	data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit_release;
-	}
+	data = devm_kzalloc(&pdev->dev, sizeof(struct sis5595_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	mutex_init(&data->lock);
 	mutex_init(&data->update_lock);
@@ -636,7 +633,7 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group);
 	if (err)
-		goto exit_free;
+		return err;
 	if (data->maxins == 4) {
 		err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_in4);
 		if (err)
@@ -659,11 +656,6 @@ exit_remove_files:
 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
-exit_free:
-	kfree(data);
-exit_release:
-	release_region(res->start, SIS5595_EXTENT);
-exit:
 	return err;
 }
 
@@ -676,10 +668,6 @@ static int __devexit sis5595_remove(struct platform_device *pdev)
 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
 
-	release_region(data->addr, SIS5595_EXTENT);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index c5f6be4..65b07de 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -231,13 +231,9 @@ static const struct attribute_group smsc47b397_group = {
 static int __devexit smsc47b397_remove(struct platform_device *pdev)
 {
 	struct smsc47b397_data *data = platform_get_drvdata(pdev);
-	struct resource *res;
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group);
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	release_region(res->start, SMSC_EXTENT);
-	kfree(data);
 
 	return 0;
 }
@@ -261,19 +257,17 @@ static int __devinit smsc47b397_probe(struct platform_device *pdev)
 	int err = 0;
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, SMSC_EXTENT,
-			    smsc47b397_driver.driver.name)) {
+	if (!devm_request_region(dev, res->start, SMSC_EXTENT,
+				 smsc47b397_driver.driver.name)) {
 		dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
 			(unsigned long)res->start,
 			(unsigned long)res->start + SMSC_EXTENT - 1);
 		return -EBUSY;
 	}
 
-	data = kzalloc(sizeof(struct smsc47b397_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto error_release;
-	}
+	data = devm_kzalloc(dev, sizeof(struct smsc47b397_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	data->addr = res->start;
 	data->name = "smsc47b397";
@@ -283,7 +277,7 @@ static int __devinit smsc47b397_probe(struct platform_device *pdev)
 
 	err = sysfs_create_group(&dev->kobj, &smsc47b397_group);
 	if (err)
-		goto error_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -295,10 +289,6 @@ static int __devinit smsc47b397_probe(struct platform_device *pdev)
 
 error_remove:
 	sysfs_remove_group(&dev->kobj, &smsc47b397_group);
-error_free:
-	kfree(data);
-error_release:
-	release_region(res->start, SMSC_EXTENT);
 	return err;
 }
 
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index b5aa38d..dba0c56 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -584,18 +584,17 @@ static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data)
 
 #define CHECK		1
 #define REQUEST		2
-#define RELEASE		3
 
 /*
  * This function can be used to:
  *  - test for resource conflicts with ACPI
  *  - request the resources
- *  - release the resources
  * We only allocate the I/O ports we really need, to minimize the risk of
  * conflicts with ACPI or with other drivers.
  */
-static int smsc47m1_handle_resources(unsigned short address, enum chips type,
-				     int action, struct device *dev)
+static int __init smsc47m1_handle_resources(unsigned short address,
+					    enum chips type, int action,
+					    struct device *dev)
 {
 	static const u8 ports_m1[] = {
 		/* register, region length */
@@ -642,21 +641,13 @@ static int smsc47m1_handle_resources(unsigned short address, enum chips type,
 			break;
 		case REQUEST:
 			/* Request the resources */
-			if (!request_region(start, len, DRVNAME)) {
-				dev_err(dev, "Region 0x%hx-0x%hx already in "
-					"use!\n", start, start + len);
-
-				/* Undo all requests */
-				for (i -= 2; i >= 0; i -= 2)
-					release_region(address + ports[i],
-						       ports[i + 1]);
+			if (!devm_request_region(dev, start, len, DRVNAME)) {
+				dev_err(dev,
+					"Region 0x%hx-0x%hx already in use!\n",
+					start, start + len);
 				return -EBUSY;
 			}
 			break;
-		case RELEASE:
-			/* Release the resources */
-			release_region(start, len);
-			break;
 		}
 	}
 
@@ -694,11 +685,9 @@ static int __init smsc47m1_probe(struct platform_device *pdev)
 	if (err < 0)
 		return err;
 
-	data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto error_release;
-	}
+	data = devm_kzalloc(dev, sizeof(struct smsc47m1_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	data->addr = res->start;
 	data->type = sio_data->type;
@@ -733,8 +722,7 @@ static int __init smsc47m1_probe(struct platform_device *pdev)
 	}
 	if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) {
 		dev_warn(dev, "Device not configured, will not use\n");
-		err = -ENODEV;
-		goto error_free;
+		return -ENODEV;
 	}
 
 	/*
@@ -810,27 +798,16 @@ static int __init smsc47m1_probe(struct platform_device *pdev)
 
 error_remove_files:
 	smsc47m1_remove_files(dev);
-error_free:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-error_release:
-	smsc47m1_handle_resources(res->start, sio_data->type, RELEASE, dev);
 	return err;
 }
 
 static int __exit smsc47m1_remove(struct platform_device *pdev)
 {
 	struct smsc47m1_data *data = platform_get_drvdata(pdev);
-	struct resource *res;
 
 	hwmon_device_unregister(data->hwmon_dev);
 	smsc47m1_remove_files(&pdev->dev);
 
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	smsc47m1_handle_resources(res->start, data->type, RELEASE, &pdev->dev);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index 4705a8b..36a3478 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -554,11 +554,10 @@ static int smsc47m192_probe(struct i2c_client *client,
 	int config;
 	int err;
 
-	data = kzalloc(sizeof(struct smsc47m192_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct smsc47m192_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	data->vrm = vid_which_vrm();
@@ -570,7 +569,7 @@ static int smsc47m192_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	/* Pin 110 is either in4 (+12V) or VID4 */
 	config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
@@ -592,9 +591,6 @@ static int smsc47m192_probe(struct i2c_client *client,
 exit_remove_files:
 	sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
 	sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -606,8 +602,6 @@ static int smsc47m192_remove(struct i2c_client *client)
 	sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
 	sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
index add9f01..080c263 100644
--- a/drivers/hwmon/thmc50.c
+++ b/drivers/hwmon/thmc50.c
@@ -361,12 +361,10 @@ static int thmc50_probe(struct i2c_client *client,
 	struct thmc50_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct thmc50_data), GFP_KERNEL);
-	if (!data) {
-		pr_debug("thmc50: detect failed, kzalloc failed!\n");
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct thmc50_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	data->type = id->driver_data;
@@ -377,7 +375,7 @@ static int thmc50_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &thmc50_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	/* Register ADM1022 sysfs hooks */
 	if (data->has_temp3) {
@@ -400,9 +398,6 @@ exit_remove_sysfs:
 		sysfs_remove_group(&client->dev.kobj, &temp3_group);
 exit_remove_sysfs_thmc50:
 	sysfs_remove_group(&client->dev.kobj, &thmc50_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -415,8 +410,6 @@ static int thmc50_remove(struct i2c_client *client)
 	if (data->has_temp3)
 		sysfs_remove_group(&client->dev.kobj, &temp3_group);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
index 0d466b9..4e1ff82 100644
--- a/drivers/hwmon/tmp102.c
+++ b/drivers/hwmon/tmp102.c
@@ -159,17 +159,16 @@ static int __devinit tmp102_probe(struct i2c_client *client,
 		return -ENODEV;
 	}
 
-	tmp102 = kzalloc(sizeof(*tmp102), GFP_KERNEL);
-	if (!tmp102) {
-		dev_dbg(&client->dev, "kzalloc failed\n");
+	tmp102 = devm_kzalloc(&client->dev, sizeof(*tmp102), GFP_KERNEL);
+	if (!tmp102)
 		return -ENOMEM;
-	}
+
 	i2c_set_clientdata(client, tmp102);
 
 	status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
 	if (status < 0) {
 		dev_err(&client->dev, "error reading config register\n");
-		goto fail_free;
+		return status;
 	}
 	tmp102->config_orig = status;
 	status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
@@ -213,9 +212,6 @@ fail_remove_sysfs:
 fail_restore_config:
 	i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
 				     tmp102->config_orig);
-fail_free:
-	kfree(tmp102);
-
 	return status;
 }
 
@@ -236,8 +232,6 @@ static int __devexit tmp102_remove(struct i2c_client *client)
 						     config | TMP102_CONF_SD);
 	}
 
-	kfree(tmp102);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
index ea54c33..e620548 100644
--- a/drivers/hwmon/tmp401.c
+++ b/drivers/hwmon/tmp401.c
@@ -594,7 +594,6 @@ static int tmp401_remove(struct i2c_client *client)
 					   &tmp411_attr[i].dev_attr);
 	}
 
-	kfree(data);
 	return 0;
 }
 
@@ -605,7 +604,8 @@ static int tmp401_probe(struct i2c_client *client,
 	struct tmp401_data *data;
 	const char *names[] = { "TMP401", "TMP411" };
 
-	data = kzalloc(sizeof(struct tmp401_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct tmp401_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -646,7 +646,7 @@ static int tmp401_probe(struct i2c_client *client,
 	return 0;
 
 exit_remove:
-	tmp401_remove(client); /* will also free data for us */
+	tmp401_remove(client);
 	return err;
 }
 
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
index 8fac87a..6a8ded2 100644
--- a/drivers/hwmon/tmp421.c
+++ b/drivers/hwmon/tmp421.c
@@ -267,7 +267,8 @@ static int tmp421_probe(struct i2c_client *client,
 	struct tmp421_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct tmp421_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct tmp421_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -277,11 +278,11 @@ static int tmp421_probe(struct i2c_client *client,
 
 	err = tmp421_init_client(client);
 	if (err)
-		goto exit_free;
+		return err;
 
 	err = sysfs_create_group(&client->dev.kobj, &tmp421_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -293,10 +294,6 @@ static int tmp421_probe(struct i2c_client *client,
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &tmp421_group);
-
-exit_free:
-	kfree(data);
-
 	return err;
 }
 
@@ -307,8 +304,6 @@ static int tmp421_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &tmp421_group);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c
index 8689664..ee4ebc1 100644
--- a/drivers/hwmon/via-cputemp.c
+++ b/drivers/hwmon/via-cputemp.c
@@ -309,7 +309,7 @@ static struct notifier_block via_cputemp_cpu_notifier __refdata = {
 	.notifier_call = via_cputemp_cpu_callback,
 };
 
-static const struct x86_cpu_id cputemp_ids[] = {
+static const struct x86_cpu_id __initconst cputemp_ids[] = {
 	{ X86_VENDOR_CENTAUR, 6, 0xa, }, /* C7 A */
 	{ X86_VENDOR_CENTAUR, 6, 0xd, }, /* C7 D */
 	{ X86_VENDOR_CENTAUR, 6, 0xf, }, /* Nano */
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 288135d..299399a 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -690,18 +690,17 @@ static int __devinit via686a_probe(struct platform_device *pdev)
 
 	/* Reserve the ISA region */
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, VIA686A_EXTENT,
-			    via686a_driver.driver.name)) {
+	if (!devm_request_region(&pdev->dev, res->start, VIA686A_EXTENT,
+				 via686a_driver.driver.name)) {
 		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
 			(unsigned long)res->start, (unsigned long)res->end);
 		return -ENODEV;
 	}
 
-	data = kzalloc(sizeof(struct via686a_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit_release;
-	}
+	data = devm_kzalloc(&pdev->dev, sizeof(struct via686a_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	platform_set_drvdata(pdev, data);
 	data->addr = res->start;
@@ -714,7 +713,7 @@ static int __devinit via686a_probe(struct platform_device *pdev)
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&pdev->dev.kobj, &via686a_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -726,10 +725,6 @@ static int __devinit via686a_probe(struct platform_device *pdev)
 
 exit_remove_files:
 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
-exit_free:
-	kfree(data);
-exit_release:
-	release_region(res->start, VIA686A_EXTENT);
 	return err;
 }
 
@@ -740,10 +735,6 @@ static int __devexit via686a_remove(struct platform_device *pdev)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
 
-	release_region(data->addr, VIA686A_EXTENT);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index c2c5c72..f2c6115 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -1148,19 +1148,18 @@ static int __devinit vt1211_probe(struct platform_device *pdev)
 	struct resource *res;
 	int i, err;
 
-	data = kzalloc(sizeof(struct vt1211_data), GFP_KERNEL);
+	data = devm_kzalloc(dev, sizeof(struct vt1211_data), GFP_KERNEL);
 	if (!data) {
-		err = -ENOMEM;
 		dev_err(dev, "Out of memory\n");
-		goto EXIT;
+		return -ENOMEM;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, resource_size(res), DRVNAME)) {
-		err = -EBUSY;
+	if (!devm_request_region(dev, res->start, resource_size(res),
+				 DRVNAME)) {
 		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
 			(unsigned long)res->start, (unsigned long)res->end);
-		goto EXIT_KFREE;
+		return -EBUSY;
 	}
 	data->addr = res->start;
 	data->name = DRVNAME;
@@ -1215,26 +1214,15 @@ EXIT_DEV_REMOVE:
 	dev_err(dev, "Sysfs interface creation failed (%d)\n", err);
 EXIT_DEV_REMOVE_SILENT:
 	vt1211_remove_sysfs(pdev);
-	release_region(res->start, resource_size(res));
-EXIT_KFREE:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-EXIT:
 	return err;
 }
 
 static int __devexit vt1211_remove(struct platform_device *pdev)
 {
 	struct vt1211_data *data = platform_get_drvdata(pdev);
-	struct resource *res;
 
 	hwmon_device_unregister(data->hwmon_dev);
 	vt1211_remove_sysfs(pdev);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	release_region(res->start, resource_size(res));
 
 	return 0;
 }
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 5ce54a2..ab48252 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -1359,19 +1359,17 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 	};
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
+	if (!devm_request_region(dev, res->start, WINB_REGION_SIZE, DRVNAME)) {
 		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
 			(unsigned long)res->start,
 			(unsigned long)(res->start + WINB_REGION_SIZE - 1));
-		err = -EBUSY;
-		goto ERROR0;
+		return -EBUSY;
 	}
 
-	data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto ERROR1;
-	}
+	data = devm_kzalloc(dev, sizeof(struct w83627hf_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
 	data->addr = res->start;
 	data->type = sio_data->type;
 	data->name = names[sio_data->type];
@@ -1391,7 +1389,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 	/* Register common device attributes */
 	err = sysfs_create_group(&dev->kobj, &w83627hf_group);
 	if (err)
-		goto ERROR3;
+		return err;
 
 	/* Register chip-specific device attributes */
 	if (data->type == w83627hf || data->type == w83697hf)
@@ -1419,7 +1417,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 				&sensor_dev_attr_pwm1_freq.dev_attr))
 		 || (err = device_create_file(dev,
 				&sensor_dev_attr_pwm2_freq.dev_attr)))
-			goto ERROR4;
+			goto error;
 
 	if (data->type != w83697hf)
 		if ((err = device_create_file(dev,
@@ -1454,7 +1452,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 				&sensor_dev_attr_temp3_beep.dev_attr))
 		 || (err = device_create_file(dev,
 				&sensor_dev_attr_temp3_type.dev_attr)))
-			goto ERROR4;
+			goto error;
 
 	if (data->type != w83697hf && data->vid != 0xff) {
 		/* Convert VID to voltage based on VRM */
@@ -1462,14 +1460,14 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 
 		if ((err = device_create_file(dev, &dev_attr_cpu0_vid))
 		 || (err = device_create_file(dev, &dev_attr_vrm)))
-			goto ERROR4;
+			goto error;
 	}
 
 	if (data->type == w83627thf || data->type == w83637hf
 	    || data->type == w83687thf) {
 		err = device_create_file(dev, &sensor_dev_attr_pwm3.dev_attr);
 		if (err)
-			goto ERROR4;
+			goto error;
 	}
 
 	if (data->type == w83637hf || data->type == w83687thf)
@@ -1479,57 +1477,45 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 				&sensor_dev_attr_pwm2_freq.dev_attr))
 		 || (err = device_create_file(dev,
 				&sensor_dev_attr_pwm3_freq.dev_attr)))
-			goto ERROR4;
+			goto error;
 
 	if (data->type != w83627hf)
 		if ((err = device_create_file(dev,
 				&sensor_dev_attr_pwm1_enable.dev_attr))
 		 || (err = device_create_file(dev,
 				&sensor_dev_attr_pwm2_enable.dev_attr)))
-			goto ERROR4;
+			goto error;
 
 	if (data->type == w83627thf || data->type == w83637hf
 	    || data->type == w83687thf) {
 		err = device_create_file(dev,
 					 &sensor_dev_attr_pwm3_enable.dev_attr);
 		if (err)
-			goto ERROR4;
+			goto error;
 	}
 
 	data->hwmon_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		err = PTR_ERR(data->hwmon_dev);
-		goto ERROR4;
+		goto error;
 	}
 
 	return 0;
 
-      ERROR4:
+ error:
 	sysfs_remove_group(&dev->kobj, &w83627hf_group);
 	sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
-      ERROR3:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-      ERROR1:
-	release_region(res->start, WINB_REGION_SIZE);
-      ERROR0:
 	return err;
 }
 
 static int __devexit w83627hf_remove(struct platform_device *pdev)
 {
 	struct w83627hf_data *data = platform_get_drvdata(pdev);
-	struct resource *res;
 
 	hwmon_device_unregister(data->hwmon_dev);
 
 	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
 	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	release_region(res->start, WINB_REGION_SIZE);
 
 	return 0;
 }
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index b03d54a..c11452e 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -1213,11 +1213,9 @@ w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	struct w83781d_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto ERROR1;
-	}
+	data = devm_kzalloc(dev, sizeof(struct w83781d_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->lock);
@@ -1229,7 +1227,7 @@ w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	/* attach secondary i2c lm75-like clients */
 	err = w83781d_detect_subclients(client);
 	if (err)
-		goto ERROR3;
+		return err;
 
 	/* Initialize the chip */
 	w83781d_init_device(dev);
@@ -1237,25 +1235,22 @@ w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	/* Register sysfs hooks */
 	err = w83781d_create_files(dev, data->type, 0);
 	if (err)
-		goto ERROR4;
+		goto exit_remove_files;
 
 	data->hwmon_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		err = PTR_ERR(data->hwmon_dev);
-		goto ERROR4;
+		goto exit_remove_files;
 	}
 
 	return 0;
 
-ERROR4:
+ exit_remove_files:
 	w83781d_remove_files(dev);
 	if (data->lm75[0])
 		i2c_unregister_device(data->lm75[0]);
 	if (data->lm75[1])
 		i2c_unregister_device(data->lm75[1]);
-ERROR3:
-	kfree(data);
-ERROR1:
 	return err;
 }
 
@@ -1273,8 +1268,6 @@ w83781d_remove(struct i2c_client *client)
 	if (data->lm75[1])
 		i2c_unregister_device(data->lm75[1]);
 
-	kfree(data);
-
 	return 0;
 }
 
@@ -1780,17 +1773,16 @@ w83781d_isa_probe(struct platform_device *pdev)
 
 	/* Reserve the ISA region */
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
-			    "w83781d")) {
-		err = -EBUSY;
-		goto exit;
-	}
+	if (!devm_request_region(&pdev->dev,
+				 res->start + W83781D_ADDR_REG_OFFSET, 2,
+				 "w83781d"))
+		return -EBUSY;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct w83781d_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
-	data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit_release_region;
-	}
 	mutex_init(&data->lock);
 	data->isa_addr = res->start;
 	platform_set_drvdata(pdev, data);
@@ -1829,10 +1821,6 @@ w83781d_isa_probe(struct platform_device *pdev)
  exit_remove_files:
 	w83781d_remove_files(&pdev->dev);
 	device_remove_file(&pdev->dev, &dev_attr_name);
-	kfree(data);
- exit_release_region:
-	release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
- exit:
 	return err;
 }
 
@@ -1844,8 +1832,6 @@ w83781d_isa_remove(struct platform_device *pdev)
 	hwmon_device_unregister(data->hwmon_dev);
 	w83781d_remove_files(&pdev->dev);
 	device_remove_file(&pdev->dev, &dev_attr_name);
-	release_region(data->isa_addr + W83781D_ADDR_REG_OFFSET, 2);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 2f446f9..9ade4d4 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -1384,18 +1384,17 @@ static int w83791d_probe(struct i2c_client *client,
 			(val1 >> 5) & 0x07, (val1 >> 1) & 0x0f, val1);
 #endif
 
-	data = kzalloc(sizeof(struct w83791d_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto error0;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct w83791d_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
 
 	err = w83791d_detect_subclients(client);
 	if (err)
-		goto error1;
+		return err;
 
 	/* Initialize the chip */
 	w83791d_init_client(client);
@@ -1440,9 +1439,6 @@ error3:
 		i2c_unregister_device(data->lm75[0]);
 	if (data->lm75[1] != NULL)
 		i2c_unregister_device(data->lm75[1]);
-error1:
-	kfree(data);
-error0:
 	return err;
 }
 
@@ -1458,7 +1454,6 @@ static int w83791d_remove(struct i2c_client *client)
 	if (data->lm75[1] != NULL)
 		i2c_unregister_device(data->lm75[1]);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index ffb5fdf..0ba5a2b 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -1422,11 +1422,9 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	struct device *dev = &client->dev;
 	int i, val1, err;
 
-	data = kzalloc(sizeof(struct w83792d_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto ERROR0;
-	}
+	data = devm_kzalloc(dev, sizeof(struct w83792d_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	data->valid = 0;
@@ -1434,7 +1432,7 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 	err = w83792d_detect_subclients(client);
 	if (err)
-		goto ERROR1;
+		return err;
 
 	/* Initialize the chip */
 	w83792d_init_client(client);
@@ -1448,7 +1446,7 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&dev->kobj, &w83792d_group);
 	if (err)
-		goto ERROR3;
+		goto exit_i2c_unregister;
 
 	/*
 	 * Read GPIO enable register to check if pins for fan 4,5 are used as
@@ -1493,14 +1491,11 @@ exit_remove_files:
 	sysfs_remove_group(&dev->kobj, &w83792d_group);
 	for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
 		sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
-ERROR3:
+exit_i2c_unregister:
 	if (data->lm75[0] != NULL)
 		i2c_unregister_device(data->lm75[0]);
 	if (data->lm75[1] != NULL)
 		i2c_unregister_device(data->lm75[1]);
-ERROR1:
-	kfree(data);
-ERROR0:
 	return err;
 }
 
@@ -1521,7 +1516,6 @@ w83792d_remove(struct i2c_client *client)
 	if (data->lm75[1] != NULL)
 		i2c_unregister_device(data->lm75[1]);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c
index d887cb3..b813c64 100644
--- a/drivers/hwmon/w83795.c
+++ b/drivers/hwmon/w83795.c
@@ -2157,11 +2157,9 @@ static int w83795_probe(struct i2c_client *client,
 	struct w83795_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct w83795_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(dev, sizeof(struct w83795_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	data->chip_type = id->driver_data;
@@ -2247,8 +2245,6 @@ static int w83795_probe(struct i2c_client *client,
 
 exit_remove:
 	w83795_handle_files(dev, device_remove_file_wrapper);
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -2258,7 +2254,6 @@ static int w83795_remove(struct i2c_client *client)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	w83795_handle_files(&client->dev, device_remove_file_wrapper);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index 5f14e38..39dbe99 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -176,19 +176,18 @@ static int w83l785ts_detect(struct i2c_client *client,
 	return 0;
 }
 
-static int w83l785ts_probe(struct i2c_client *new_client,
+static int w83l785ts_probe(struct i2c_client *client,
 			   const struct i2c_device_id *id)
 {
 	struct w83l785ts_data *data;
-	int err = 0;
+	struct device *dev = &client->dev;
+	int err;
 
-	data = kzalloc(sizeof(struct w83l785ts_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(dev, sizeof(struct w83l785ts_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
-	i2c_set_clientdata(new_client, data);
+	i2c_set_clientdata(client, data);
 	data->valid = 0;
 	mutex_init(&data->update_lock);
 
@@ -200,18 +199,16 @@ static int w83l785ts_probe(struct i2c_client *new_client,
 	 * Nothing yet, assume it is already started.
 	 */
 
-	err = device_create_file(&new_client->dev,
-				 &sensor_dev_attr_temp1_input.dev_attr);
+	err = device_create_file(dev, &sensor_dev_attr_temp1_input.dev_attr);
 	if (err)
-		goto exit_remove;
+		return err;
 
-	err = device_create_file(&new_client->dev,
-				 &sensor_dev_attr_temp1_max.dev_attr);
+	err = device_create_file(dev, &sensor_dev_attr_temp1_max.dev_attr);
 	if (err)
 		goto exit_remove;
 
 	/* Register sysfs hooks */
-	data->hwmon_dev = hwmon_device_register(&new_client->dev);
+	data->hwmon_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		err = PTR_ERR(data->hwmon_dev);
 		goto exit_remove;
@@ -220,12 +217,8 @@ static int w83l785ts_probe(struct i2c_client *new_client,
 	return 0;
 
 exit_remove:
-	device_remove_file(&new_client->dev,
-			   &sensor_dev_attr_temp1_input.dev_attr);
-	device_remove_file(&new_client->dev,
-			   &sensor_dev_attr_temp1_max.dev_attr);
-	kfree(data);
-exit:
+	device_remove_file(dev, &sensor_dev_attr_temp1_input.dev_attr);
+	device_remove_file(dev, &sensor_dev_attr_temp1_max.dev_attr);
 	return err;
 }
 
@@ -239,7 +232,6 @@ static int w83l785ts_remove(struct i2c_client *client)
 	device_remove_file(&client->dev,
 			   &sensor_dev_attr_temp1_max.dev_attr);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/wm831x-hwmon.c b/drivers/hwmon/wm831x-hwmon.c
index 07cb25a..d0db1f2 100644
--- a/drivers/hwmon/wm831x-hwmon.c
+++ b/drivers/hwmon/wm831x-hwmon.c
@@ -163,7 +163,8 @@ static int __devinit wm831x_hwmon_probe(struct platform_device *pdev)
 	struct wm831x_hwmon *hwmon;
 	int ret;
 
-	hwmon = kzalloc(sizeof(struct wm831x_hwmon), GFP_KERNEL);
+	hwmon = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_hwmon),
+			     GFP_KERNEL);
 	if (!hwmon)
 		return -ENOMEM;
 
@@ -171,7 +172,7 @@ static int __devinit wm831x_hwmon_probe(struct platform_device *pdev)
 
 	ret = sysfs_create_group(&pdev->dev.kobj, &wm831x_attr_group);
 	if (ret)
-		goto err;
+		return ret;
 
 	hwmon->classdev = hwmon_device_register(&pdev->dev);
 	if (IS_ERR(hwmon->classdev)) {
@@ -185,8 +186,6 @@ static int __devinit wm831x_hwmon_probe(struct platform_device *pdev)
 
 err_sysfs:
 	sysfs_remove_group(&pdev->dev.kobj, &wm831x_attr_group);
-err:
-	kfree(hwmon);
 	return ret;
 }
 
@@ -196,8 +195,6 @@ static int __devexit wm831x_hwmon_remove(struct platform_device *pdev)
 
 	hwmon_device_unregister(hwmon->classdev);
 	sysfs_remove_group(&pdev->dev.kobj, &wm831x_attr_group);
-	platform_set_drvdata(pdev, NULL);
-	kfree(hwmon);
 
 	return 0;
 }
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 7244c8b..2e7530a 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -133,7 +133,7 @@ config I2C_PIIX4
 	    ATI IXP300
 	    ATI IXP400
 	    ATI SB600
-	    ATI SB700
+	    ATI SB700/SP5100
 	    ATI SB800
 	    AMD Hudson-2
 	    Serverworks OSB4
@@ -143,6 +143,10 @@ config I2C_PIIX4
 	    Serverworks HT-1100
 	    SMSC Victory66
 
+	  Some AMD chipsets contain two PIIX4-compatible SMBus
+	  controllers. This driver will attempt to use both controllers
+	  on the SB700/SP5100, if they have been initialized by the BIOS.
+
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-piix4.
 
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index e66d248..125cd8e 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -531,15 +531,7 @@ static struct pci_driver ali1535_driver = {
 	.remove		= __devexit_p(ali1535_remove),
 };
 
-static int __init i2c_ali1535_init(void)
-{
-	return pci_register_driver(&ali1535_driver);
-}
-
-static void __exit i2c_ali1535_exit(void)
-{
-	pci_unregister_driver(&ali1535_driver);
-}
+module_pci_driver(ali1535_driver);
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
 	      "Philip Edelbrock <phil@netroedge.com>, "
@@ -547,6 +539,3 @@ MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
 	      "and Dan Eaton <dan.eaton@rocketlogix.com>");
 MODULE_DESCRIPTION("ALI1535 SMBus driver");
 MODULE_LICENSE("GPL");
-
-module_init(i2c_ali1535_init);
-module_exit(i2c_ali1535_exit);
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index 47ae009..e02d9f8 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -431,18 +431,6 @@ static struct pci_driver ali1563_pci_driver = {
 	.remove		= __devexit_p(ali1563_remove),
 };
 
-static int __init ali1563_init(void)
-{
-	return pci_register_driver(&ali1563_pci_driver);
-}
-
-module_init(ali1563_init);
-
-static void __exit ali1563_exit(void)
-{
-	pci_unregister_driver(&ali1563_pci_driver);
-}
-
-module_exit(ali1563_exit);
+module_pci_driver(ali1563_pci_driver);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index 087ea9c..ce8d26d 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -513,21 +513,10 @@ static struct pci_driver ali15x3_driver = {
 	.remove		= __devexit_p(ali15x3_remove),
 };
 
-static int __init i2c_ali15x3_init(void)
-{
-	return pci_register_driver(&ali15x3_driver);
-}
-
-static void __exit i2c_ali15x3_exit(void)
-{
-	pci_unregister_driver(&ali15x3_driver);
-}
+module_pci_driver(ali15x3_driver);
 
 MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
 		"Philip Edelbrock <phil@netroedge.com>, "
 		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
 MODULE_DESCRIPTION("ALI15X3 SMBus driver");
 MODULE_LICENSE("GPL");
-
-module_init(i2c_ali15x3_init);
-module_exit(i2c_ali15x3_exit);
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index eb778bf1..304aa03 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -410,21 +410,10 @@ static struct pci_driver amd756_driver = {
 	.remove		= __devexit_p(amd756_remove),
 };
 
-static int __init amd756_init(void)
-{
-	return pci_register_driver(&amd756_driver);
-}
-
-static void __exit amd756_exit(void)
-{
-	pci_unregister_driver(&amd756_driver);
-}
+module_pci_driver(amd756_driver);
 
 MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
 MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(amd756_smbus);
-
-module_init(amd756_init)
-module_exit(amd756_exit)
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index e5ac53b..0919ac1 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -491,15 +491,4 @@ static struct pci_driver amd8111_driver = {
 	.remove		= __devexit_p(amd8111_remove),
 };
 
-static int __init i2c_amd8111_init(void)
-{
-	return pci_register_driver(&amd8111_driver);
-}
-
-static void __exit i2c_amd8111_exit(void)
-{
-	pci_unregister_driver(&amd8111_driver);
-}
-
-module_init(i2c_amd8111_init);
-module_exit(i2c_amd8111_exit);
+module_pci_driver(amd8111_driver);
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
index 00e8f21..92a1e2c 100644
--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -374,17 +374,7 @@ static struct pci_driver dw_i2c_driver = {
 	},
 };
 
-static int __init dw_i2c_init_driver(void)
-{
-	return  pci_register_driver(&dw_i2c_driver);
-}
-module_init(dw_i2c_init_driver);
-
-static void __exit dw_i2c_exit_driver(void)
-{
-	pci_unregister_driver(&dw_i2c_driver);
-}
-module_exit(dw_i2c_exit_driver);
+module_pci_driver(dw_i2c_driver);
 
 MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
 MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c
index 7eb19a5..aedb94f 100644
--- a/drivers/i2c/busses/i2c-diolan-u2c.c
+++ b/drivers/i2c/busses/i2c-diolan-u2c.c
@@ -517,6 +517,6 @@ static struct usb_driver diolan_u2c_driver = {
 
 module_usb_driver(diolan_u2c_driver);
 
-MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
 MODULE_DESCRIPTION(DRIVER_NAME " driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index 2f74ae8..259f769 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -953,17 +953,7 @@ static struct pci_driver pch_pcidriver = {
 	.resume = pch_i2c_resume
 };
 
-static int __init pch_pci_init(void)
-{
-	return pci_register_driver(&pch_pcidriver);
-}
-module_init(pch_pci_init);
-
-static void __exit pch_pci_exit(void)
-{
-	pci_unregister_driver(&pch_pcidriver);
-}
-module_exit(pch_pci_exit);
+module_pci_driver(pch_pcidriver);
 
 MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C");
 MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
index c527de1..c9f95e1 100644
--- a/drivers/i2c/busses/i2c-hydra.c
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -156,23 +156,8 @@ static struct pci_driver hydra_driver = {
 	.remove		= __devexit_p(hydra_remove),
 };
 
-static int __init i2c_hydra_init(void)
-{
-	return pci_register_driver(&hydra_driver);
-}
-
-
-static void __exit i2c_hydra_exit(void)
-{
-	pci_unregister_driver(&hydra_driver);
-}
-
-
+module_pci_driver(hydra_driver);
 
 MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
 MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O");
 MODULE_LICENSE("GPL");
-
-module_init(i2c_hydra_init);
-module_exit(i2c_hydra_exit);
-
diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c
index 365bad5..7c28f10 100644
--- a/drivers/i2c/busses/i2c-intel-mid.c
+++ b/drivers/i2c/busses/i2c-intel-mid.c
@@ -1116,18 +1116,7 @@ static struct pci_driver intel_mid_i2c_driver = {
 	.remove		= __devexit_p(intel_mid_i2c_remove),
 };
 
-static int __init intel_mid_i2c_init(void)
-{
-	return pci_register_driver(&intel_mid_i2c_driver);
-}
-
-static void __exit intel_mid_i2c_exit(void)
-{
-	pci_unregister_driver(&intel_mid_i2c_driver);
-}
-
-module_init(intel_mid_i2c_init);
-module_exit(intel_mid_i2c_exit);
+module_pci_driver(intel_mid_i2c_driver);
 
 MODULE_AUTHOR("Ba Zheng <zheng.ba@intel.com>");
 MODULE_DESCRIPTION("I2C driver for Moorestown Platform");
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 43a96a1..392303b 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -453,16 +453,4 @@ static struct pci_driver nforce2_driver = {
 	.remove		= __devexit_p(nforce2_remove),
 };
 
-static int __init nforce2_init(void)
-{
-	return pci_register_driver(&nforce2_driver);
-}
-
-static void __exit nforce2_exit(void)
-{
-	pci_unregister_driver(&nforce2_driver);
-}
-
-module_init(nforce2_init);
-module_exit(nforce2_exit);
-
+module_pci_driver(nforce2_driver);
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 801df60..9895fa7 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -173,7 +173,7 @@ enum {
 
 /* Errata definitions */
 #define I2C_OMAP_ERRATA_I207		(1 << 0)
-#define I2C_OMAP3_1P153			(1 << 1)
+#define I2C_OMAP_ERRATA_I462		(1 << 1)
 
 struct omap_i2c_dev {
 	struct device		*dev;
@@ -269,47 +269,6 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
 				(i2c_dev->regs[reg] << i2c_dev->reg_shift));
 }
 
-static void omap_i2c_unidle(struct omap_i2c_dev *dev)
-{
-	if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
-		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
-		omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
-		omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
-		omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
-		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate);
-		omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate);
-		omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
-		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
-	}
-
-	/*
-	 * Don't write to this register if the IE state is 0 as it can
-	 * cause deadlock.
-	 */
-	if (dev->iestate)
-		omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
-}
-
-static void omap_i2c_idle(struct omap_i2c_dev *dev)
-{
-	u16 iv;
-
-	dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
-	if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
-		omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1);
-	else
-		omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
-
-	if (dev->rev < OMAP_I2C_OMAP1_REV_2) {
-		iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
-	} else {
-		omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
-
-		/* Flush posted write */
-		omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
-	}
-}
-
 static int omap_i2c_init(struct omap_i2c_dev *dev)
 {
 	u16 psc = 0, scll = 0, sclh = 0, buf = 0;
@@ -468,11 +427,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 	/* Take the I2C module out of reset: */
 	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
 
-	dev->errata = 0;
-
-	if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
-		dev->errata |= I2C_OMAP_ERRATA_I207;
-
 	/* Enable interrupts */
 	dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
 			OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
@@ -514,7 +468,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
 			     struct i2c_msg *msg, int stop)
 {
 	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
-	int r;
+	unsigned long timeout;
 	u16 w;
 
 	dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
@@ -582,12 +536,10 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
 	 * REVISIT: We should abort the transfer on signals, but the bus goes
 	 * into arbitration and we're currently unable to recover from it.
 	 */
-	r = wait_for_completion_timeout(&dev->cmd_complete,
-					OMAP_I2C_TIMEOUT);
+	timeout = wait_for_completion_timeout(&dev->cmd_complete,
+						OMAP_I2C_TIMEOUT);
 	dev->buf_len = 0;
-	if (r < 0)
-		return r;
-	if (r == 0) {
+	if (timeout == 0) {
 		dev_err(dev->dev, "controller timed out\n");
 		omap_i2c_init(dev);
 		return -ETIMEDOUT;
@@ -628,7 +580,9 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	int i;
 	int r;
 
-	pm_runtime_get_sync(dev->dev);
+	r = pm_runtime_get_sync(dev->dev);
+	if (IS_ERR_VALUE(r))
+		return r;
 
 	r = omap_i2c_wait_for_bb(dev);
 	if (r < 0)
@@ -764,11 +718,11 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id)
 #endif
 
 /*
- * OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing
+ * OMAP3430 Errata i462: When an XRDY/XDR is hit, wait for XUDF before writing
  * data to DATA_REG. Otherwise some data bytes can be lost while transferring
  * them from the memory to the I2C interface.
  */
-static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
+static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err)
 {
 	unsigned long timeout = 10000;
 
@@ -776,7 +730,6 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
 		if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
 			omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
 							OMAP_I2C_STAT_XDR));
-			*err |= OMAP_I2C_STAT_XUDF;
 			return -ETIMEDOUT;
 		}
 
@@ -789,6 +742,7 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
 		return 0;
 	}
 
+	*err |= OMAP_I2C_STAT_XUDF;
 	return 0;
 }
 
@@ -927,8 +881,8 @@ complete:
 					break;
 				}
 
-				if ((dev->errata & I2C_OMAP3_1P153) &&
-				    errata_omap3_1p153(dev, &stat, &err))
+				if ((dev->errata & I2C_OMAP_ERRATA_I462) &&
+				    errata_omap3_i462(dev, &stat, &err))
 					goto complete;
 
 				omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
@@ -1054,12 +1008,19 @@ omap_i2c_probe(struct platform_device *pdev)
 		dev->regs = (u8 *)reg_map_ip_v1;
 
 	pm_runtime_enable(dev->dev);
-	pm_runtime_get_sync(dev->dev);
+	r = pm_runtime_get_sync(dev->dev);
+	if (IS_ERR_VALUE(r))
+		goto err_free_mem;
 
 	dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
 
+	dev->errata = 0;
+
+	if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
+		dev->errata |= I2C_OMAP_ERRATA_I207;
+
 	if (dev->rev <= OMAP_I2C_REV_ON_3430)
-		dev->errata |= I2C_OMAP3_1P153;
+		dev->errata |= I2C_OMAP_ERRATA_I462;
 
 	if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) {
 		u16 s;
@@ -1092,7 +1053,7 @@ omap_i2c_probe(struct platform_device *pdev)
 
 	isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
 								   omap_i2c_isr;
-	r = request_irq(dev->irq, isr, 0, pdev->name, dev);
+	r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
 
 	if (r) {
 		dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
@@ -1102,8 +1063,6 @@ omap_i2c_probe(struct platform_device *pdev)
 	dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
 		 dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
 
-	pm_runtime_put(dev->dev);
-
 	adap = &dev->adapter;
 	i2c_set_adapdata(adap, dev);
 	adap->owner = THIS_MODULE;
@@ -1123,6 +1082,8 @@ omap_i2c_probe(struct platform_device *pdev)
 
 	of_i2c_register_devices(adap);
 
+	pm_runtime_put(dev->dev);
+
 	return 0;
 
 err_free_irq:
@@ -1131,6 +1092,7 @@ err_unuse_clocks:
 	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
 	pm_runtime_put(dev->dev);
 	iounmap(dev->base);
+	pm_runtime_disable(&pdev->dev);
 err_free_mem:
 	platform_set_drvdata(pdev, NULL);
 	kfree(dev);
@@ -1145,12 +1107,19 @@ omap_i2c_remove(struct platform_device *pdev)
 {
 	struct omap_i2c_dev	*dev = platform_get_drvdata(pdev);
 	struct resource		*mem;
+	int ret;
 
 	platform_set_drvdata(pdev, NULL);
 
 	free_irq(dev->irq, dev);
 	i2c_del_adapter(&dev->adapter);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
 	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
 	iounmap(dev->base);
 	kfree(dev);
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1163,8 +1132,20 @@ static int omap_i2c_runtime_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
+	u16 iv;
+
+	_dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
+
+	omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
 
-	omap_i2c_idle(_dev);
+	if (_dev->rev < OMAP_I2C_OMAP1_REV_2) {
+		iv = omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */
+	} else {
+		omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate);
+
+		/* Flush posted write */
+		omap_i2c_read_reg(_dev, OMAP_I2C_STAT_REG);
+	}
 
 	return 0;
 }
@@ -1174,7 +1155,23 @@ static int omap_i2c_runtime_resume(struct device *dev)
 	struct platform_device *pdev = to_platform_device(dev);
 	struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
 
-	omap_i2c_unidle(_dev);
+	if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
+		omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0);
+		omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate);
+		omap_i2c_write_reg(_dev, OMAP_I2C_SCLL_REG, _dev->scllstate);
+		omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate);
+		omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate);
+		omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate);
+		omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate);
+		omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+	}
+
+	/*
+	 * Don't write to this register if the IE state is 0 as it can
+	 * cause deadlock.
+	 */
+	if (_dev->iestate)
+		omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, _dev->iestate);
 
 	return 0;
 }
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
index eaaea73..12edefd 100644
--- a/drivers/i2c/busses/i2c-pasemi.c
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -415,19 +415,8 @@ static struct pci_driver pasemi_smb_driver = {
 	.remove		= __devexit_p(pasemi_smb_remove),
 };
 
-static int __init pasemi_smb_init(void)
-{
-	return pci_register_driver(&pasemi_smb_driver);
-}
-
-static void __exit pasemi_smb_exit(void)
-{
-	pci_unregister_driver(&pasemi_smb_driver);
-}
+module_pci_driver(pasemi_smb_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
 MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver");
-
-module_init(pasemi_smb_init);
-module_exit(pasemi_smb_exit);
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index c14d48d..ef511df 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -21,11 +21,12 @@
    Supports:
 	Intel PIIX4, 440MX
 	Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
-	ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
+	ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800
 	AMD Hudson-2
 	SMSC Victory66
 
-   Note: we assume there can only be one device, with one SMBus interface.
+   Note: we assume there can only be one device, with one or more
+   SMBus interfaces.
 */
 
 #include <linux/module.h>
@@ -94,10 +95,8 @@ MODULE_PARM_DESC(force_addr,
 		 "Forcibly enable the PIIX4 at the given address. "
 		 "EXTREMELY DANGEROUS!");
 
-static unsigned short piix4_smba;
 static int srvrworks_csb5_delay;
 static struct pci_driver piix4_driver;
-static struct i2c_adapter piix4_adapter;
 
 static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = {
 	{
@@ -127,10 +126,15 @@ static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = {
 	{ },
 };
 
+struct i2c_piix4_adapdata {
+	unsigned short smba;
+};
+
 static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 				const struct pci_device_id *id)
 {
 	unsigned char temp;
+	unsigned short piix4_smba;
 
 	if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
 	    (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5))
@@ -206,7 +210,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 			dev_err(&PIIX4_dev->dev,
 				"Host SMBus controller not enabled!\n");
 			release_region(piix4_smba, SMBIOSIZE);
-			piix4_smba = 0;
 			return -ENODEV;
 		}
 	}
@@ -224,12 +227,13 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 		 "SMBus Host Controller at 0x%x, revision %d\n",
 		 piix4_smba, temp);
 
-	return 0;
+	return piix4_smba;
 }
 
 static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
 				const struct pci_device_id *id)
 {
+	unsigned short piix4_smba;
 	unsigned short smba_idx = 0xcd6;
 	u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
 
@@ -273,7 +277,6 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
 		dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region "
 			"0x%x already in use!\n", piix4_smba + i2ccfg_offset);
 		release_region(piix4_smba, SMBIOSIZE);
-		piix4_smba = 0;
 		return -EBUSY;
 	}
 	i2ccfg = inb_p(piix4_smba + i2ccfg_offset);
@@ -288,30 +291,72 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
 		 "SMBus Host Controller at 0x%x, revision %d\n",
 		 piix4_smba, i2ccfg >> 4);
 
-	return 0;
+	return piix4_smba;
+}
+
+static int __devinit piix4_setup_aux(struct pci_dev *PIIX4_dev,
+				const struct pci_device_id *id,
+				unsigned short base_reg_addr)
+{
+	/* Set up auxiliary SMBus controllers found on some
+	 * AMD chipsets e.g. SP5100 (SB700 derivative) */
+
+	unsigned short piix4_smba;
+
+	/* Read address of auxiliary SMBus controller */
+	pci_read_config_word(PIIX4_dev, base_reg_addr, &piix4_smba);
+	if ((piix4_smba & 1) == 0) {
+		dev_dbg(&PIIX4_dev->dev,
+			"Auxiliary SMBus controller not enabled\n");
+		return -ENODEV;
+	}
+
+	piix4_smba &= 0xfff0;
+	if (piix4_smba == 0) {
+		dev_dbg(&PIIX4_dev->dev,
+			"Auxiliary SMBus base address uninitialized\n");
+		return -ENODEV;
+	}
+
+	if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+		return -ENODEV;
+
+	if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
+		dev_err(&PIIX4_dev->dev, "Auxiliary SMBus region 0x%x "
+			"already in use!\n", piix4_smba);
+		return -EBUSY;
+	}
+
+	dev_info(&PIIX4_dev->dev,
+		 "Auxiliary SMBus Host Controller at 0x%x\n",
+		 piix4_smba);
+
+	return piix4_smba;
 }
 
-static int piix4_transaction(void)
+static int piix4_transaction(struct i2c_adapter *piix4_adapter)
 {
+	struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter);
+	unsigned short piix4_smba = adapdata->smba;
 	int temp;
 	int result = 0;
 	int timeout = 0;
 
-	dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+	dev_dbg(&piix4_adapter->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
 		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
 		inb_p(SMBHSTDAT1));
 
 	/* Make sure the SMBus host is ready to start transmitting */
 	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-		dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). "
+		dev_dbg(&piix4_adapter->dev, "SMBus busy (%02x). "
 			"Resetting...\n", temp);
 		outb_p(temp, SMBHSTSTS);
 		if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-			dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
+			dev_err(&piix4_adapter->dev, "Failed! (%02x)\n", temp);
 			return -EBUSY;
 		} else {
-			dev_dbg(&piix4_adapter.dev, "Successful!\n");
+			dev_dbg(&piix4_adapter->dev, "Successful!\n");
 		}
 	}
 
@@ -330,35 +375,35 @@ static int piix4_transaction(void)
 
 	/* If the SMBus is still busy, we give up */
 	if (timeout == MAX_TIMEOUT) {
-		dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
+		dev_err(&piix4_adapter->dev, "SMBus Timeout!\n");
 		result = -ETIMEDOUT;
 	}
 
 	if (temp & 0x10) {
 		result = -EIO;
-		dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n");
+		dev_err(&piix4_adapter->dev, "Error: Failed bus transaction\n");
 	}
 
 	if (temp & 0x08) {
 		result = -EIO;
-		dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be "
+		dev_dbg(&piix4_adapter->dev, "Bus collision! SMBus may be "
 			"locked until next hard reset. (sorry!)\n");
 		/* Clock stops and slave is stuck in mid-transmission */
 	}
 
 	if (temp & 0x04) {
 		result = -ENXIO;
-		dev_dbg(&piix4_adapter.dev, "Error: no response!\n");
+		dev_dbg(&piix4_adapter->dev, "Error: no response!\n");
 	}
 
 	if (inb_p(SMBHSTSTS) != 0x00)
 		outb_p(inb(SMBHSTSTS), SMBHSTSTS);
 
 	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-		dev_err(&piix4_adapter.dev, "Failed reset at end of "
+		dev_err(&piix4_adapter->dev, "Failed reset at end of "
 			"transaction (%02x)\n", temp);
 	}
-	dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+	dev_dbg(&piix4_adapter->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
 		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
 		inb_p(SMBHSTDAT1));
@@ -370,6 +415,8 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
 		 unsigned short flags, char read_write,
 		 u8 command, int size, union i2c_smbus_data * data)
 {
+	struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
+	unsigned short piix4_smba = adapdata->smba;
 	int i, len;
 	int status;
 
@@ -426,7 +473,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
 
 	outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
 
-	status = piix4_transaction();
+	status = piix4_transaction(adap);
 	if (status)
 		return status;
 
@@ -466,12 +513,6 @@ static const struct i2c_algorithm smbus_algorithm = {
 	.functionality	= piix4_func,
 };
 
-static struct i2c_adapter piix4_adapter = {
-	.owner		= THIS_MODULE,
-	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
-	.algo		= &smbus_algorithm,
-};
-
 static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
@@ -496,6 +537,57 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
 
 MODULE_DEVICE_TABLE (pci, piix4_ids);
 
+static struct i2c_adapter *piix4_main_adapter;
+static struct i2c_adapter *piix4_aux_adapter;
+
+static int __devinit piix4_add_adapter(struct pci_dev *dev,
+					unsigned short smba,
+					struct i2c_adapter **padap)
+{
+	struct i2c_adapter *adap;
+	struct i2c_piix4_adapdata *adapdata;
+	int retval;
+
+	adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+	if (adap == NULL) {
+		release_region(smba, SMBIOSIZE);
+		return -ENOMEM;
+	}
+
+	adap->owner = THIS_MODULE;
+	adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	adap->algo = &smbus_algorithm;
+
+	adapdata = kzalloc(sizeof(*adapdata), GFP_KERNEL);
+	if (adapdata == NULL) {
+		kfree(adap);
+		release_region(smba, SMBIOSIZE);
+		return -ENOMEM;
+	}
+
+	adapdata->smba = smba;
+
+	/* set up the sysfs linkage to our parent device */
+	adap->dev.parent = &dev->dev;
+
+	snprintf(adap->name, sizeof(adap->name),
+		"SMBus PIIX4 adapter at %04x", smba);
+
+	i2c_set_adapdata(adap, adapdata);
+
+	retval = i2c_add_adapter(adap);
+	if (retval) {
+		dev_err(&dev->dev, "Couldn't register adapter!\n");
+		kfree(adapdata);
+		kfree(adap);
+		release_region(smba, SMBIOSIZE);
+		return retval;
+	}
+
+	*padap = adap;
+	return 0;
+}
+
 static int __devinit piix4_probe(struct pci_dev *dev,
 				const struct pci_device_id *id)
 {
@@ -510,30 +602,52 @@ static int __devinit piix4_probe(struct pci_dev *dev,
 	else
 		retval = piix4_setup(dev, id);
 
-	if (retval)
+	/* If no main SMBus found, give up */
+	if (retval < 0)
 		return retval;
 
-	/* set up the sysfs linkage to our parent device */
-	piix4_adapter.dev.parent = &dev->dev;
-
-	snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
-		"SMBus PIIX4 adapter at %04x", piix4_smba);
+	/* Try to register main SMBus adapter, give up if we can't */
+	retval = piix4_add_adapter(dev, retval, &piix4_main_adapter);
+	if (retval < 0)
+		return retval;
 
-	if ((retval = i2c_add_adapter(&piix4_adapter))) {
-		dev_err(&dev->dev, "Couldn't register adapter!\n");
-		release_region(piix4_smba, SMBIOSIZE);
-		piix4_smba = 0;
+	/* Check for auxiliary SMBus on some AMD chipsets */
+	if (dev->vendor == PCI_VENDOR_ID_ATI &&
+	    dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+	    dev->revision < 0x40) {
+		retval = piix4_setup_aux(dev, id, 0x58);
+		if (retval > 0) {
+			/* Try to add the aux adapter if it exists,
+			 * piix4_add_adapter will clean up if this fails */
+			piix4_add_adapter(dev, retval, &piix4_aux_adapter);
+		}
 	}
 
-	return retval;
+	return 0;
+}
+
+static void __devexit piix4_adap_remove(struct i2c_adapter *adap)
+{
+	struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
+
+	if (adapdata->smba) {
+		i2c_del_adapter(adap);
+		release_region(adapdata->smba, SMBIOSIZE);
+		kfree(adapdata);
+		kfree(adap);
+	}
 }
 
 static void __devexit piix4_remove(struct pci_dev *dev)
 {
-	if (piix4_smba) {
-		i2c_del_adapter(&piix4_adapter);
-		release_region(piix4_smba, SMBIOSIZE);
-		piix4_smba = 0;
+	if (piix4_main_adapter) {
+		piix4_adap_remove(piix4_main_adapter);
+		piix4_main_adapter = NULL;
+	}
+
+	if (piix4_aux_adapter) {
+		piix4_adap_remove(piix4_aux_adapter);
+		piix4_aux_adapter = NULL;
 	}
 }
 
@@ -544,20 +658,9 @@ static struct pci_driver piix4_driver = {
 	.remove		= __devexit_p(piix4_remove),
 };
 
-static int __init i2c_piix4_init(void)
-{
-	return pci_register_driver(&piix4_driver);
-}
-
-static void __exit i2c_piix4_exit(void)
-{
-	pci_unregister_driver(&piix4_driver);
-}
+module_pci_driver(piix4_driver);
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
 		"Philip Edelbrock <phil@netroedge.com>");
 MODULE_DESCRIPTION("PIIX4 SMBus driver");
 MODULE_LICENSE("GPL");
-
-module_init(i2c_piix4_init);
-module_exit(i2c_piix4_exit);
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c
index a058179..4dc9bef 100644
--- a/drivers/i2c/busses/i2c-pxa-pci.c
+++ b/drivers/i2c/busses/i2c-pxa-pci.c
@@ -163,17 +163,7 @@ static struct pci_driver ce4100_i2c_driver = {
 	.remove         = __devexit_p(ce4100_i2c_remove),
 };
 
-static int __init ce4100_i2c_init(void)
-{
-	return pci_register_driver(&ce4100_i2c_driver);
-}
-module_init(ce4100_i2c_init);
-
-static void __exit ce4100_i2c_exit(void)
-{
-	pci_unregister_driver(&ce4100_i2c_driver);
-}
-module_exit(ce4100_i2c_exit);
+module_pci_driver(ce4100_i2c_driver);
 
 MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index a997c7d..1034d93 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -41,13 +41,6 @@
 
 #include <asm/irq.h>
 
-#ifndef CONFIG_HAVE_CLK
-#define clk_get(dev, id)	NULL
-#define clk_put(clk)		do { } while (0)
-#define clk_disable(clk)	do { } while (0)
-#define clk_enable(clk)		do { } while (0)
-#endif
-
 struct pxa_reg_layout {
 	u32 ibmr;
 	u32 idbr;
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index 15cf78f..5d6723b 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -513,21 +513,8 @@ static struct pci_driver sis630_driver = {
 	.remove		= __devexit_p(sis630_remove),
 };
 
-static int __init i2c_sis630_init(void)
-{
-	return pci_register_driver(&sis630_driver);
-}
-
-
-static void __exit i2c_sis630_exit(void)
-{
-	pci_unregister_driver(&sis630_driver);
-}
-
+module_pci_driver(sis630_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexander Malysh <amalysh@web.de>");
 MODULE_DESCRIPTION("SIS630 SMBus driver");
-
-module_init(i2c_sis630_init);
-module_exit(i2c_sis630_exit);
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index cc5d149..7b72614 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -324,21 +324,8 @@ static struct pci_driver sis96x_driver = {
 	.remove		= __devexit_p(sis96x_remove),
 };
 
-static int __init i2c_sis96x_init(void)
-{
-	return pci_register_driver(&sis96x_driver);
-}
-
-static void __exit i2c_sis96x_exit(void)
-{
-	pci_unregister_driver(&sis96x_driver);
-}
+module_pci_driver(sis96x_driver);
 
 MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
 MODULE_DESCRIPTION("SiS96x SMBus driver");
 MODULE_LICENSE("GPL");
-
-/* Register initialization functions using helper macros */
-module_init(i2c_sis96x_init);
-module_exit(i2c_sis96x_exit);
-
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 8b2e555..f15cd49 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -97,8 +97,21 @@
 #define I2C_HEADER_10BIT_ADDR			(1<<18)
 #define I2C_HEADER_IE_ENABLE			(1<<17)
 #define I2C_HEADER_REPEAT_START			(1<<16)
+#define I2C_HEADER_CONTINUE_XFER		(1<<15)
 #define I2C_HEADER_MASTER_ADDR_SHIFT		12
 #define I2C_HEADER_SLAVE_ADDR_SHIFT		1
+/*
+ * msg_end_type: The bus control which need to be send at end of transfer.
+ * @MSG_END_STOP: Send stop pulse at end of transfer.
+ * @MSG_END_REPEAT_START: Send repeat start at end of transfer.
+ * @MSG_END_CONTINUE: The following on message is coming and so do not send
+ *		stop or repeat start.
+ */
+enum msg_end_type {
+	MSG_END_STOP,
+	MSG_END_REPEAT_START,
+	MSG_END_CONTINUE,
+};
 
 /**
  * struct tegra_i2c_dev	- per device i2c context
@@ -165,6 +178,10 @@ static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
 	unsigned long reg)
 {
 	writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+
+	/* Read back register to make sure that register writes completed */
+	if (reg != I2C_TX_FIFO)
+		readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
 }
 
 static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
@@ -341,7 +358,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 	u32 val;
 	int err = 0;
 
-	clk_enable(i2c_dev->clk);
+	clk_prepare_enable(i2c_dev->clk);
 
 	tegra_periph_reset_assert(i2c_dev->clk);
 	udelay(2);
@@ -372,7 +389,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 	if (tegra_i2c_flush_fifos(i2c_dev))
 		err = -ETIMEDOUT;
 
-	clk_disable(i2c_dev->clk);
+	clk_disable_unprepare(i2c_dev->clk);
 
 	if (i2c_dev->irq_disabled) {
 		i2c_dev->irq_disabled = 0;
@@ -449,7 +466,7 @@ err:
 }
 
 static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
-	struct i2c_msg *msg, int stop)
+	struct i2c_msg *msg, enum msg_end_type end_state)
 {
 	u32 packet_header;
 	u32 int_mask;
@@ -476,7 +493,9 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 	i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
 
 	packet_header = I2C_HEADER_IE_ENABLE;
-	if (!stop)
+	if (end_state == MSG_END_CONTINUE)
+		packet_header |= I2C_HEADER_CONTINUE_XFER;
+	else if (end_state == MSG_END_REPEAT_START)
 		packet_header |= I2C_HEADER_REPEAT_START;
 	if (msg->flags & I2C_M_TEN) {
 		packet_header |= msg->addr;
@@ -546,20 +565,27 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
 	if (i2c_dev->is_suspended)
 		return -EBUSY;
 
-	clk_enable(i2c_dev->clk);
+	clk_prepare_enable(i2c_dev->clk);
 	for (i = 0; i < num; i++) {
-		int stop = (i == (num - 1)) ? 1  : 0;
-		ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop);
+		enum msg_end_type end_type = MSG_END_STOP;
+		if (i < (num - 1)) {
+			if (msgs[i + 1].flags & I2C_M_NOSTART)
+				end_type = MSG_END_CONTINUE;
+			else
+				end_type = MSG_END_REPEAT_START;
+		}
+		ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], end_type);
 		if (ret)
 			break;
 	}
-	clk_disable(i2c_dev->clk);
+	clk_disable_unprepare(i2c_dev->clk);
 	return ret ?: i;
 }
 
 static u32 tegra_i2c_func(struct i2c_adapter *adap)
 {
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
+		I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART;
 }
 
 static const struct i2c_algorithm tegra_i2c_algo = {
@@ -572,7 +598,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
 	struct tegra_i2c_dev *i2c_dev;
 	struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data;
 	struct resource *res;
-	struct resource *iomem;
 	struct clk *clk;
 	struct clk *i2c_clk;
 	const unsigned int *prop;
@@ -585,50 +610,41 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "no mem resource\n");
 		return -EINVAL;
 	}
-	iomem = request_mem_region(res->start, resource_size(res), pdev->name);
-	if (!iomem) {
-		dev_err(&pdev->dev, "I2C region already claimed\n");
-		return -EBUSY;
-	}
 
-	base = ioremap(iomem->start, resource_size(iomem));
+	base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!base) {
-		dev_err(&pdev->dev, "Cannot ioremap I2C region\n");
-		return -ENOMEM;
+		dev_err(&pdev->dev, "Cannot request/ioremap I2C registers\n");
+		return -EADDRNOTAVAIL;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "no irq resource\n");
-		ret = -EINVAL;
-		goto err_iounmap;
+		return -EINVAL;
 	}
 	irq = res->start;
 
-	clk = clk_get(&pdev->dev, NULL);
+	clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "missing controller clock");
-		ret = PTR_ERR(clk);
-		goto err_release_region;
+		return PTR_ERR(clk);
 	}
 
-	i2c_clk = clk_get(&pdev->dev, "i2c");
+	i2c_clk = devm_clk_get(&pdev->dev, "i2c");
 	if (IS_ERR(i2c_clk)) {
 		dev_err(&pdev->dev, "missing bus clock");
-		ret = PTR_ERR(i2c_clk);
-		goto err_clk_put;
+		return PTR_ERR(i2c_clk);
 	}
 
-	i2c_dev = kzalloc(sizeof(struct tegra_i2c_dev), GFP_KERNEL);
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
 	if (!i2c_dev) {
-		ret = -ENOMEM;
-		goto err_i2c_clk_put;
+		dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev");
+		return -ENOMEM;
 	}
 
 	i2c_dev->base = base;
 	i2c_dev->clk = clk;
 	i2c_dev->i2c_clk = i2c_clk;
-	i2c_dev->iomem = iomem;
 	i2c_dev->adapter.algo = &tegra_i2c_algo;
 	i2c_dev->irq = irq;
 	i2c_dev->cont_id = pdev->id;
@@ -657,16 +673,17 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
 	ret = tegra_i2c_init(i2c_dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to initialize i2c controller");
-		goto err_free;
+		return ret;
 	}
 
-	ret = request_irq(i2c_dev->irq, tegra_i2c_isr, 0, pdev->name, i2c_dev);
+	ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
+			tegra_i2c_isr, 0, pdev->name, i2c_dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
-		goto err_free;
+		return ret;
 	}
 
-	clk_enable(i2c_dev->i2c_clk);
+	clk_prepare_enable(i2c_dev->i2c_clk);
 
 	i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
 	i2c_dev->adapter.owner = THIS_MODULE;
@@ -681,38 +698,19 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
 	ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to add I2C adapter\n");
-		goto err_free_irq;
+		clk_disable(i2c_dev->i2c_clk);
+		return ret;
 	}
 
 	of_i2c_register_devices(&i2c_dev->adapter);
 
 	return 0;
-err_free_irq:
-	free_irq(i2c_dev->irq, i2c_dev);
-err_free:
-	kfree(i2c_dev);
-err_i2c_clk_put:
-	clk_put(i2c_clk);
-err_clk_put:
-	clk_put(clk);
-err_release_region:
-	release_mem_region(iomem->start, resource_size(iomem));
-err_iounmap:
-	iounmap(base);
-	return ret;
 }
 
 static int __devexit tegra_i2c_remove(struct platform_device *pdev)
 {
 	struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
 	i2c_del_adapter(&i2c_dev->adapter);
-	free_irq(i2c_dev->irq, i2c_dev);
-	clk_put(i2c_dev->i2c_clk);
-	clk_put(i2c_dev->clk);
-	release_mem_region(i2c_dev->iomem->start,
-		resource_size(i2c_dev->iomem));
-	iounmap(i2c_dev->base);
-	kfree(i2c_dev);
 	return 0;
 }
 
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
index 713d31a..7ffee71 100644
--- a/drivers/i2c/busses/i2c-via.c
+++ b/drivers/i2c/busses/i2c-via.c
@@ -161,20 +161,8 @@ static struct pci_driver vt586b_driver = {
 	.remove		= __devexit_p(vt586b_remove),
 };
 
-static int __init i2c_vt586b_init(void)
-{
-	return pci_register_driver(&vt586b_driver);
-}
-
-static void __exit i2c_vt586b_exit(void)
-{
-	pci_unregister_driver(&vt586b_driver);
-}
-
+module_pci_driver(vt586b_driver);
 
 MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
 MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge");
 MODULE_LICENSE("GPL");
-
-module_init(i2c_vt586b_init);
-module_exit(i2c_vt586b_exit);
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index 8aacde1..f8f72f3 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -396,6 +396,6 @@ static struct i2c_driver pca9541_driver = {
 
 module_i2c_driver(pca9541_driver);
 
-MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
 MODULE_DESCRIPTION("PCA9541 I2C master selector driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index d0f59c3..a759a4c 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -169,6 +169,38 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
 		.enter = &intel_idle },
 };
 
+static struct cpuidle_state ivb_cstates[MWAIT_MAX_NUM_CSTATES] = {
+	{ /* MWAIT C0 */ },
+	{ /* MWAIT C1 */
+		.name = "C1-IVB",
+		.desc = "MWAIT 0x00",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 1,
+		.target_residency = 1,
+		.enter = &intel_idle },
+	{ /* MWAIT C2 */
+		.name = "C3-IVB",
+		.desc = "MWAIT 0x10",
+		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 59,
+		.target_residency = 156,
+		.enter = &intel_idle },
+	{ /* MWAIT C3 */
+		.name = "C6-IVB",
+		.desc = "MWAIT 0x20",
+		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 80,
+		.target_residency = 300,
+		.enter = &intel_idle },
+	{ /* MWAIT C4 */
+		.name = "C7-IVB",
+		.desc = "MWAIT 0x30",
+		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 87,
+		.target_residency = 300,
+		.enter = &intel_idle },
+};
+
 static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C0 */ },
 	{ /* MWAIT C1 */
@@ -347,6 +379,10 @@ static const struct idle_cpu idle_cpu_snb = {
 	.state_table = snb_cstates,
 };
 
+static const struct idle_cpu idle_cpu_ivb = {
+	.state_table = ivb_cstates,
+};
+
 #define ICPU(model, cpu) \
 	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
 
@@ -362,6 +398,7 @@ static const struct x86_cpu_id intel_idle_ids[] = {
 	ICPU(0x2f, idle_cpu_nehalem),
 	ICPU(0x2a, idle_cpu_snb),
 	ICPU(0x2d, idle_cpu_snb),
+	ICPU(0x3a, idle_cpu_ivb),
 	{}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 2ec93da..d4984c8 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -29,6 +29,13 @@ config IIO_KFIFO_BUF
 	  no buffer events so it is up to userspace to work out how
 	  often to read from the buffer.
 
+config IIO_TRIGGERED_BUFFER
+	tristate
+	select IIO_TRIGGER
+	select IIO_KFIFO_BUF
+	help
+	  Provides helper functions for setting up triggered buffers.
+
 endif # IIO_BUFFER
 
 config IIO_TRIGGER
@@ -49,5 +56,8 @@ config IIO_CONSUMERS_PER_TRIGGER
 
 source "drivers/iio/adc/Kconfig"
 source "drivers/iio/amplifiers/Kconfig"
+source "drivers/iio/light/Kconfig"
+source "drivers/iio/frequency/Kconfig"
+source "drivers/iio/dac/Kconfig"
 
 endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index e425afd..34309ab 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -7,7 +7,11 @@ industrialio-y := industrialio-core.o industrialio-event.o inkern.o
 industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
 industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
 
+obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
 obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
 
 obj-y += adc/
 obj-y += amplifiers/
+obj-y += light/
+obj-y += frequency/
+obj-y += dac/
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 9a0df81..4f7f584 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -7,8 +7,7 @@ config AT91_ADC
 	tristate "Atmel AT91 ADC"
 	depends on ARCH_AT91
 	select IIO_BUFFER
-	select IIO_KFIFO_BUF
-	select IIO_TRIGGER
+	select IIO_TRIGGERED_BUFFER
 	select SYSFS
 	help
 	  Say yes here to build support for Atmel AT91 ADC.
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index f18a95d..f61780a 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -26,9 +26,9 @@
 
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
-#include <linux/iio/kfifo_buf.h>
 #include <linux/iio/trigger.h>
 #include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #include <mach/at91_adc.h>
 
@@ -318,58 +318,15 @@ static void at91_adc_trigger_remove(struct iio_dev *idev)
 	}
 }
 
-static const struct iio_buffer_setup_ops at91_adc_buffer_ops = {
-	.preenable = &iio_sw_buffer_preenable,
-	.postenable = &iio_triggered_buffer_postenable,
-	.predisable = &iio_triggered_buffer_predisable,
-};
-
 static int at91_adc_buffer_init(struct iio_dev *idev)
 {
-	int ret;
-
-	idev->buffer = iio_kfifo_allocate(idev);
-	if (!idev->buffer) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-
-	idev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
-					    &at91_adc_trigger_handler,
-					    IRQF_ONESHOT,
-					    idev,
-					    "%s-consumer%d",
-					    idev->name,
-					    idev->id);
-	if (idev->pollfunc == NULL) {
-		ret = -ENOMEM;
-		goto error_pollfunc;
-	}
-
-	idev->setup_ops = &at91_adc_buffer_ops;
-	idev->modes |= INDIO_BUFFER_TRIGGERED;
-
-	ret = iio_buffer_register(idev,
-				  idev->channels,
-				  idev->num_channels);
-	if (ret)
-		goto error_register;
-
-	return 0;
-
-error_register:
-	iio_dealloc_pollfunc(idev->pollfunc);
-error_pollfunc:
-	iio_kfifo_free(idev->buffer);
-error_ret:
-	return ret;
+	return iio_triggered_buffer_setup(idev, &iio_pollfunc_store_time,
+		&at91_adc_trigger_handler, NULL);
 }
 
 static void at91_adc_buffer_remove(struct iio_dev *idev)
 {
-	iio_buffer_unregister(idev);
-	iio_dealloc_pollfunc(idev->pollfunc);
-	iio_kfifo_free(idev->buffer);
+	iio_triggered_buffer_cleanup(idev);
 }
 
 static int at91_adc_read_raw(struct iio_dev *idev,
@@ -392,9 +349,11 @@ static int at91_adc_read_raw(struct iio_dev *idev,
 						       st->done,
 						       msecs_to_jiffies(1000));
 		if (ret == 0)
-			return -ETIMEDOUT;
-		else if (ret < 0)
+			ret = -ETIMEDOUT;
+		if (ret < 0) {
+			mutex_unlock(&st->lock);
 			return ret;
+		}
 
 		*val = st->last_value;
 
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
new file mode 100644
index 0000000..afd207e
--- /dev/null
+++ b/drivers/iio/dac/Kconfig
@@ -0,0 +1,132 @@
+#
+# DAC drivers
+#
+menu "Digital to analog converters"
+
+config AD5064
+	tristate "Analog Devices AD5064/64-1/65/44/45/24/25, AD5628/48/66/68 DAC driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5024, AD5025, AD5044,
+	  AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648, AD5666, AD5668 Digital
+	  to Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5064.
+
+config AD5360
+	tristate "Analog Devices Analog Devices AD5360/61/62/63/70/71/73 DAC driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5360, AD5361,
+	  AD5362, AD5363, AD5370, AD5371, AD5373 multi-channel
+	  Digital to Analog Converters (DAC).
+
+	  To compile this driver as module choose M here: the module will be called
+	  ad5360.
+
+config AD5380
+	tristate "Analog Devices AD5380/81/82/83/84/90/91/92 DAC driver"
+	depends on (SPI_MASTER || I2C)
+	select REGMAP_I2C if I2C
+	select REGMAP_SPI if SPI_MASTER
+	help
+	  Say yes here to build support for Analog Devices AD5380, AD5381,
+	  AD5382, AD5383, AD5384, AD5390, AD5391, AD5392 multi-channel
+	  Digital to Analog Converters (DAC).
+
+	  To compile this driver as module choose M here: the module will be called
+	  ad5380.
+
+config AD5421
+	tristate "Analog Devices AD5421 DAC driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5421 loop-powered
+	  digital-to-analog convertors (DAC).
+
+	  To compile this driver as module choose M here: the module will be called
+	  ad5421.
+
+config AD5624R_SPI
+	tristate "Analog Devices AD5624/44/64R DAC spi driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5624R, AD5644R and
+	  AD5664R converters (DAC). This driver uses the common SPI interface.
+
+config AD5446
+	tristate "Analog Devices AD5446 and similar single channel DACs driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5444, AD5446, AD5450,
+	  AD5451, AD5452, AD5453, AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601,
+	  AD5611, AD5620, AD5621, AD5640, AD5660, AD5662 DACs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5446.
+
+config AD5504
+	tristate "Analog Devices AD5504/AD5501 DAC SPI driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5504, AD5501,
+	  High Voltage Digital to Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5504.
+
+config AD5764
+	tristate "Analog Devices AD5764/64R/44/44R DAC driver"
+	depends on SPI_MASTER
+	help
+	  Say yes here to build support for Analog Devices AD5764, AD5764R, AD5744,
+	  AD5744R Digital to Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5764.
+
+config AD5791
+	tristate "Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC SPI driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5760, AD5780,
+	  AD5781, AD5790, AD5791 High Resolution Voltage Output Digital to
+	  Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5791.
+
+config AD5686
+	tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5686R, AD5685R,
+	  AD5684R, AD5791 Voltage Output Digital to
+	  Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5686.
+
+config MAX517
+	tristate "Maxim MAX517/518/519 DAC driver"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the Maxim chips MAX517,
+	  MAX518 and MAX519 (I2C 8-Bit DACs with rail-to-rail outputs).
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max517.
+
+config MCP4725
+	tristate "MCP4725 DAC driver"
+	depends on I2C
+	---help---
+	  Say Y here if you want to build a driver for the Microchip
+	  MCP 4725 12-bit digital-to-analog converter (DAC) with I2C
+	  interface.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mcp4725.
+
+endmenu
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
new file mode 100644
index 0000000..9ea3cee
--- /dev/null
+++ b/drivers/iio/dac/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for industrial I/O DAC drivers
+#
+
+obj-$(CONFIG_AD5360) += ad5360.o
+obj-$(CONFIG_AD5380) += ad5380.o
+obj-$(CONFIG_AD5421) += ad5421.o
+obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
+obj-$(CONFIG_AD5064) += ad5064.o
+obj-$(CONFIG_AD5504) += ad5504.o
+obj-$(CONFIG_AD5446) += ad5446.o
+obj-$(CONFIG_AD5764) += ad5764.o
+obj-$(CONFIG_AD5791) += ad5791.o
+obj-$(CONFIG_AD5686) += ad5686.o
+obj-$(CONFIG_MAX517) += max517.o
+obj-$(CONFIG_MCP4725) += mcp4725.o
diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c
new file mode 100644
index 0000000..276af02
--- /dev/null
+++ b/drivers/iio/dac/ad5064.c
@@ -0,0 +1,538 @@
+/*
+ * AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648,
+ * AD5666, AD5668 Digital to analog converters driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AD5064_MAX_DAC_CHANNELS			8
+#define AD5064_MAX_VREFS			4
+
+#define AD5064_ADDR(x)				((x) << 20)
+#define AD5064_CMD(x)				((x) << 24)
+
+#define AD5064_ADDR_DAC(chan)			(chan)
+#define AD5064_ADDR_ALL_DAC			0xF
+
+#define AD5064_CMD_WRITE_INPUT_N		0x0
+#define AD5064_CMD_UPDATE_DAC_N			0x1
+#define AD5064_CMD_WRITE_INPUT_N_UPDATE_ALL	0x2
+#define AD5064_CMD_WRITE_INPUT_N_UPDATE_N	0x3
+#define AD5064_CMD_POWERDOWN_DAC		0x4
+#define AD5064_CMD_CLEAR			0x5
+#define AD5064_CMD_LDAC_MASK			0x6
+#define AD5064_CMD_RESET			0x7
+#define AD5064_CMD_CONFIG			0x8
+
+#define AD5064_CONFIG_DAISY_CHAIN_ENABLE	BIT(1)
+#define AD5064_CONFIG_INT_VREF_ENABLE		BIT(0)
+
+#define AD5064_LDAC_PWRDN_NONE			0x0
+#define AD5064_LDAC_PWRDN_1K			0x1
+#define AD5064_LDAC_PWRDN_100K			0x2
+#define AD5064_LDAC_PWRDN_3STATE		0x3
+
+/**
+ * struct ad5064_chip_info - chip specific information
+ * @shared_vref:	whether the vref supply is shared between channels
+ * @internal_vref:	internal reference voltage. 0 if the chip has no internal
+ *			vref.
+ * @channel:		channel specification
+ * @num_channels:	number of channels
+ */
+
+struct ad5064_chip_info {
+	bool shared_vref;
+	unsigned long internal_vref;
+	const struct iio_chan_spec *channels;
+	unsigned int num_channels;
+};
+
+/**
+ * struct ad5064_state - driver instance specific data
+ * @spi:		spi_device
+ * @chip_info:		chip model specific constants, available modes etc
+ * @vref_reg:		vref supply regulators
+ * @pwr_down:		whether channel is powered down
+ * @pwr_down_mode:	channel's current power down mode
+ * @dac_cache:		current DAC raw value (chip does not support readback)
+ * @use_internal_vref:	set to true if the internal reference voltage should be
+ *			used.
+ * @data:		spi transfer buffers
+ */
+
+struct ad5064_state {
+	struct spi_device		*spi;
+	const struct ad5064_chip_info	*chip_info;
+	struct regulator_bulk_data	vref_reg[AD5064_MAX_VREFS];
+	bool				pwr_down[AD5064_MAX_DAC_CHANNELS];
+	u8				pwr_down_mode[AD5064_MAX_DAC_CHANNELS];
+	unsigned int			dac_cache[AD5064_MAX_DAC_CHANNELS];
+	bool				use_internal_vref;
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	__be32 data ____cacheline_aligned;
+};
+
+enum ad5064_type {
+	ID_AD5024,
+	ID_AD5025,
+	ID_AD5044,
+	ID_AD5045,
+	ID_AD5064,
+	ID_AD5064_1,
+	ID_AD5065,
+	ID_AD5628_1,
+	ID_AD5628_2,
+	ID_AD5648_1,
+	ID_AD5648_2,
+	ID_AD5666_1,
+	ID_AD5666_2,
+	ID_AD5668_1,
+	ID_AD5668_2,
+};
+
+static int ad5064_spi_write(struct ad5064_state *st, unsigned int cmd,
+	unsigned int addr, unsigned int val, unsigned int shift)
+{
+	val <<= shift;
+
+	st->data = cpu_to_be32(AD5064_CMD(cmd) | AD5064_ADDR(addr) | val);
+
+	return spi_write(st->spi, &st->data, sizeof(st->data));
+}
+
+static int ad5064_sync_powerdown_mode(struct ad5064_state *st,
+	unsigned int channel)
+{
+	unsigned int val;
+	int ret;
+
+	val = (0x1 << channel);
+
+	if (st->pwr_down[channel])
+		val |= st->pwr_down_mode[channel] << 8;
+
+	ret = ad5064_spi_write(st, AD5064_CMD_POWERDOWN_DAC, 0, val, 0);
+
+	return ret;
+}
+
+static const char * const ad5064_powerdown_modes[] = {
+	"1kohm_to_gnd",
+	"100kohm_to_gnd",
+	"three_state",
+};
+
+static int ad5064_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+
+	return st->pwr_down_mode[chan->channel] - 1;
+}
+
+static int ad5064_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	st->pwr_down_mode[chan->channel] = mode + 1;
+
+	ret = ad5064_sync_powerdown_mode(st, chan->channel);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static const struct iio_enum ad5064_powerdown_mode_enum = {
+	.items = ad5064_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5064_powerdown_modes),
+	.get = ad5064_get_powerdown_mode,
+	.set = ad5064_set_powerdown_mode,
+};
+
+static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", st->pwr_down[chan->channel]);
+}
+
+static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev,
+	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	 size_t len)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+	bool pwr_down;
+	int ret;
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	mutex_lock(&indio_dev->mlock);
+	st->pwr_down[chan->channel] = pwr_down;
+
+	ret = ad5064_sync_powerdown_mode(st, chan->channel);
+	mutex_unlock(&indio_dev->mlock);
+	return ret ? ret : len;
+}
+
+static int ad5064_get_vref(struct ad5064_state *st,
+	struct iio_chan_spec const *chan)
+{
+	unsigned int i;
+
+	if (st->use_internal_vref)
+		return st->chip_info->internal_vref;
+
+	i = st->chip_info->shared_vref ? 0 : chan->channel;
+	return regulator_get_voltage(st->vref_reg[i].consumer);
+}
+
+static int ad5064_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+	int scale_uv;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		*val = st->dac_cache[chan->channel];
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = ad5064_get_vref(st, chan);
+		if (scale_uv < 0)
+			return scale_uv;
+
+		scale_uv = (scale_uv * 100) >> chan->scan_type.realbits;
+		*val =  scale_uv / 100000;
+		*val2 = (scale_uv % 100000) * 10;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int ad5064_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val > (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		mutex_lock(&indio_dev->mlock);
+		ret = ad5064_spi_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N,
+				chan->address, val, chan->scan_type.shift);
+		if (ret == 0)
+			st->dac_cache[chan->channel] = val;
+		mutex_unlock(&indio_dev->mlock);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct iio_info ad5064_info = {
+	.read_raw = ad5064_read_raw,
+	.write_raw = ad5064_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_chan_spec_ext_info ad5064_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5064_read_dac_powerdown,
+		.write = ad5064_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", false, &ad5064_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5064_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5064_CHANNEL(chan, bits) {				\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.channel = (chan),					\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+	IIO_CHAN_INFO_SCALE_SEPARATE_BIT,			\
+	.address = AD5064_ADDR_DAC(chan),			\
+	.scan_type = IIO_ST('u', (bits), 16, 20 - (bits)),	\
+	.ext_info = ad5064_ext_info,				\
+}
+
+#define DECLARE_AD5064_CHANNELS(name, bits) \
+const struct iio_chan_spec name[] = { \
+	AD5064_CHANNEL(0, bits), \
+	AD5064_CHANNEL(1, bits), \
+	AD5064_CHANNEL(2, bits), \
+	AD5064_CHANNEL(3, bits), \
+	AD5064_CHANNEL(4, bits), \
+	AD5064_CHANNEL(5, bits), \
+	AD5064_CHANNEL(6, bits), \
+	AD5064_CHANNEL(7, bits), \
+}
+
+static DECLARE_AD5064_CHANNELS(ad5024_channels, 12);
+static DECLARE_AD5064_CHANNELS(ad5044_channels, 14);
+static DECLARE_AD5064_CHANNELS(ad5064_channels, 16);
+
+static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
+	[ID_AD5024] = {
+		.shared_vref = false,
+		.channels = ad5024_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5025] = {
+		.shared_vref = false,
+		.channels = ad5024_channels,
+		.num_channels = 2,
+	},
+	[ID_AD5044] = {
+		.shared_vref = false,
+		.channels = ad5044_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5045] = {
+		.shared_vref = false,
+		.channels = ad5044_channels,
+		.num_channels = 2,
+	},
+	[ID_AD5064] = {
+		.shared_vref = false,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5064_1] = {
+		.shared_vref = true,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5065] = {
+		.shared_vref = false,
+		.channels = ad5064_channels,
+		.num_channels = 2,
+	},
+	[ID_AD5628_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5024_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5628_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5024_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5648_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5044_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5648_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5044_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5666_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5666_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5668_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5064_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5668_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5064_channels,
+		.num_channels = 8,
+	},
+};
+
+static inline unsigned int ad5064_num_vref(struct ad5064_state *st)
+{
+	return st->chip_info->shared_vref ? 1 : st->chip_info->num_channels;
+}
+
+static const char * const ad5064_vref_names[] = {
+	"vrefA",
+	"vrefB",
+	"vrefC",
+	"vrefD",
+};
+
+static const char * const ad5064_vref_name(struct ad5064_state *st,
+	unsigned int vref)
+{
+	return st->chip_info->shared_vref ? "vref" : ad5064_vref_names[vref];
+}
+
+static int __devinit ad5064_probe(struct spi_device *spi)
+{
+	enum ad5064_type type = spi_get_device_id(spi)->driver_data;
+	struct iio_dev *indio_dev;
+	struct ad5064_state *st;
+	unsigned int i;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL)
+		return  -ENOMEM;
+
+	st = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+
+	st->chip_info = &ad5064_chip_info_tbl[type];
+	st->spi = spi;
+
+	for (i = 0; i < ad5064_num_vref(st); ++i)
+		st->vref_reg[i].supply = ad5064_vref_name(st, i);
+
+	ret = regulator_bulk_get(&st->spi->dev, ad5064_num_vref(st),
+		st->vref_reg);
+	if (ret) {
+		if (!st->chip_info->internal_vref)
+			goto error_free;
+		st->use_internal_vref = true;
+		ret = ad5064_spi_write(st, AD5064_CMD_CONFIG, 0,
+			AD5064_CONFIG_INT_VREF_ENABLE, 0);
+		if (ret) {
+			dev_err(&spi->dev, "Failed to enable internal vref: %d\n",
+				ret);
+			goto error_free;
+		}
+	} else {
+		ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg);
+		if (ret)
+			goto error_free_reg;
+	}
+
+	for (i = 0; i < st->chip_info->num_channels; ++i) {
+		st->pwr_down_mode[i] = AD5064_LDAC_PWRDN_1K;
+		st->dac_cache[i] = 0x8000;
+	}
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5064_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = st->chip_info->channels;
+	indio_dev->num_channels = st->chip_info->num_channels;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_disable_reg;
+
+	return 0;
+
+error_disable_reg:
+	if (!st->use_internal_vref)
+		regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
+error_free_reg:
+	if (!st->use_internal_vref)
+		regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
+error_free:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+
+static int __devexit ad5064_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5064_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	if (!st->use_internal_vref) {
+		regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
+		regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
+	}
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5064_id[] = {
+	{"ad5024", ID_AD5024},
+	{"ad5025", ID_AD5025},
+	{"ad5044", ID_AD5044},
+	{"ad5045", ID_AD5045},
+	{"ad5064", ID_AD5064},
+	{"ad5064-1", ID_AD5064_1},
+	{"ad5065", ID_AD5065},
+	{"ad5628-1", ID_AD5628_1},
+	{"ad5628-2", ID_AD5628_2},
+	{"ad5648-1", ID_AD5648_1},
+	{"ad5648-2", ID_AD5648_2},
+	{"ad5666-1", ID_AD5666_1},
+	{"ad5666-2", ID_AD5666_2},
+	{"ad5668-1", ID_AD5668_1},
+	{"ad5668-2", ID_AD5668_2},
+	{"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5064_id);
+
+static struct spi_driver ad5064_driver = {
+	.driver = {
+		   .name = "ad5064",
+		   .owner = THIS_MODULE,
+	},
+	.probe = ad5064_probe,
+	.remove = __devexit_p(ad5064_remove),
+	.id_table = ad5064_id,
+};
+module_spi_driver(ad5064_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5024/25/44/45/64/64-1/65, AD5628/48/66/68 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c
new file mode 100644
index 0000000..8fce84f
--- /dev/null
+++ b/drivers/iio/dac/ad5360.c
@@ -0,0 +1,570 @@
+/*
+ * Analog devices AD5360, AD5361, AD5362, AD5363, AD5370, AD5371, AD5373
+ * multi-channel Digital to Analog Converters driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AD5360_CMD(x)				((x) << 22)
+#define AD5360_ADDR(x)				((x) << 16)
+
+#define AD5360_READBACK_TYPE(x)			((x) << 13)
+#define AD5360_READBACK_ADDR(x)			((x) << 7)
+
+#define AD5360_CHAN_ADDR(chan)			((chan) + 0x8)
+
+#define AD5360_CMD_WRITE_DATA			0x3
+#define AD5360_CMD_WRITE_OFFSET			0x2
+#define AD5360_CMD_WRITE_GAIN			0x1
+#define AD5360_CMD_SPECIAL_FUNCTION		0x0
+
+/* Special function register addresses */
+#define AD5360_REG_SF_NOP			0x0
+#define AD5360_REG_SF_CTRL			0x1
+#define AD5360_REG_SF_OFS(x)			(0x2 + (x))
+#define AD5360_REG_SF_READBACK			0x5
+
+#define AD5360_SF_CTRL_PWR_DOWN			BIT(0)
+
+#define AD5360_READBACK_X1A			0x0
+#define AD5360_READBACK_X1B			0x1
+#define AD5360_READBACK_OFFSET			0x2
+#define AD5360_READBACK_GAIN			0x3
+#define AD5360_READBACK_SF			0x4
+
+
+/**
+ * struct ad5360_chip_info - chip specific information
+ * @channel_template:	channel specification template
+ * @num_channels:	number of channels
+ * @channels_per_group:	number of channels per group
+ * @num_vrefs:		number of vref supplies for the chip
+*/
+
+struct ad5360_chip_info {
+	struct iio_chan_spec	channel_template;
+	unsigned int		num_channels;
+	unsigned int		channels_per_group;
+	unsigned int		num_vrefs;
+};
+
+/**
+ * struct ad5360_state - driver instance specific data
+ * @spi:		spi_device
+ * @chip_info:		chip model specific constants, available modes etc
+ * @vref_reg:		vref supply regulators
+ * @ctrl:		control register cache
+ * @data:		spi transfer buffers
+ */
+
+struct ad5360_state {
+	struct spi_device		*spi;
+	const struct ad5360_chip_info	*chip_info;
+	struct regulator_bulk_data	vref_reg[3];
+	unsigned int			ctrl;
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	union {
+		__be32 d32;
+		u8 d8[4];
+	} data[2] ____cacheline_aligned;
+};
+
+enum ad5360_type {
+	ID_AD5360,
+	ID_AD5361,
+	ID_AD5362,
+	ID_AD5363,
+	ID_AD5370,
+	ID_AD5371,
+	ID_AD5372,
+	ID_AD5373,
+};
+
+#define AD5360_CHANNEL(bits) {					\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |	\
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,	\
+	.scan_type = IIO_ST('u', (bits), 16, 16 - (bits))	\
+}
+
+static const struct ad5360_chip_info ad5360_chip_info_tbl[] = {
+	[ID_AD5360] = {
+		.channel_template = AD5360_CHANNEL(16),
+		.num_channels = 16,
+		.channels_per_group = 8,
+		.num_vrefs = 2,
+	},
+	[ID_AD5361] = {
+		.channel_template = AD5360_CHANNEL(14),
+		.num_channels = 16,
+		.channels_per_group = 8,
+		.num_vrefs = 2,
+	},
+	[ID_AD5362] = {
+		.channel_template = AD5360_CHANNEL(16),
+		.num_channels = 8,
+		.channels_per_group = 4,
+		.num_vrefs = 2,
+	},
+	[ID_AD5363] = {
+		.channel_template = AD5360_CHANNEL(14),
+		.num_channels = 8,
+		.channels_per_group = 4,
+		.num_vrefs = 2,
+	},
+	[ID_AD5370] = {
+		.channel_template = AD5360_CHANNEL(16),
+		.num_channels = 40,
+		.channels_per_group = 8,
+		.num_vrefs = 2,
+	},
+	[ID_AD5371] = {
+		.channel_template = AD5360_CHANNEL(14),
+		.num_channels = 40,
+		.channels_per_group = 8,
+		.num_vrefs = 3,
+	},
+	[ID_AD5372] = {
+		.channel_template = AD5360_CHANNEL(16),
+		.num_channels = 32,
+		.channels_per_group = 8,
+		.num_vrefs = 2,
+	},
+	[ID_AD5373] = {
+		.channel_template = AD5360_CHANNEL(14),
+		.num_channels = 32,
+		.channels_per_group = 8,
+		.num_vrefs = 2,
+	},
+};
+
+static unsigned int ad5360_get_channel_vref_index(struct ad5360_state *st,
+	unsigned int channel)
+{
+	unsigned int i;
+
+	/* The first groups have their own vref, while the remaining groups
+	 * share the last vref */
+	i = channel / st->chip_info->channels_per_group;
+	if (i >= st->chip_info->num_vrefs)
+		i = st->chip_info->num_vrefs - 1;
+
+	return i;
+}
+
+static int ad5360_get_channel_vref(struct ad5360_state *st,
+	unsigned int channel)
+{
+	unsigned int i = ad5360_get_channel_vref_index(st, channel);
+
+	return regulator_get_voltage(st->vref_reg[i].consumer);
+}
+
+
+static int ad5360_write_unlocked(struct iio_dev *indio_dev,
+	unsigned int cmd, unsigned int addr, unsigned int val,
+	unsigned int shift)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+
+	val <<= shift;
+	val |= AD5360_CMD(cmd) | AD5360_ADDR(addr);
+	st->data[0].d32 = cpu_to_be32(val);
+
+	return spi_write(st->spi, &st->data[0].d8[1], 3);
+}
+
+static int ad5360_write(struct iio_dev *indio_dev, unsigned int cmd,
+	unsigned int addr, unsigned int val, unsigned int shift)
+{
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	ret = ad5360_write_unlocked(indio_dev, cmd, addr, val, shift);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
+	unsigned int addr)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+	struct spi_message m;
+	int ret;
+	struct spi_transfer t[] = {
+		{
+			.tx_buf = &st->data[0].d8[1],
+			.len = 3,
+			.cs_change = 1,
+		}, {
+			.rx_buf = &st->data[1].d8[1],
+			.len = 3,
+		},
+	};
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	mutex_lock(&indio_dev->mlock);
+
+	st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) |
+		AD5360_ADDR(AD5360_REG_SF_READBACK) |
+		AD5360_READBACK_TYPE(type) |
+		AD5360_READBACK_ADDR(addr));
+
+	ret = spi_sync(st->spi, &m);
+	if (ret >= 0)
+		ret = be32_to_cpu(st->data[1].d32) & 0xffff;
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static ssize_t ad5360_read_dac_powerdown(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ad5360_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN));
+}
+
+static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
+	unsigned int clr)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+	unsigned int ret;
+
+	mutex_lock(&indio_dev->mlock);
+
+	st->ctrl |= set;
+	st->ctrl &= ~clr;
+
+	ret = ad5360_write_unlocked(indio_dev, AD5360_CMD_SPECIAL_FUNCTION,
+			AD5360_REG_SF_CTRL, st->ctrl, 0);
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static ssize_t ad5360_write_dac_powerdown(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	bool pwr_down;
+	int ret;
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	if (pwr_down)
+		ret = ad5360_update_ctrl(indio_dev, AD5360_SF_CTRL_PWR_DOWN, 0);
+	else
+		ret = ad5360_update_ctrl(indio_dev, 0, AD5360_SF_CTRL_PWR_DOWN);
+
+	return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(out_voltage_powerdown,
+			S_IRUGO | S_IWUSR,
+			ad5360_read_dac_powerdown,
+			ad5360_write_dac_powerdown, 0);
+
+static struct attribute *ad5360_attributes[] = {
+	&iio_dev_attr_out_voltage_powerdown.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ad5360_attribute_group = {
+	.attrs = ad5360_attributes,
+};
+
+static int ad5360_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+	int max_val = (1 << chan->scan_type.realbits);
+	unsigned int ofs_index;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5360_write(indio_dev, AD5360_CMD_WRITE_DATA,
+				 chan->address, val, chan->scan_type.shift);
+
+	case IIO_CHAN_INFO_CALIBBIAS:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5360_write(indio_dev, AD5360_CMD_WRITE_OFFSET,
+				 chan->address, val, chan->scan_type.shift);
+
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5360_write(indio_dev, AD5360_CMD_WRITE_GAIN,
+				 chan->address, val, chan->scan_type.shift);
+
+	case IIO_CHAN_INFO_OFFSET:
+		if (val <= -max_val || val > 0)
+			return -EINVAL;
+
+		val = -val;
+
+		/* offset is supposed to have the same scale as raw, but it
+		 * is always 14bits wide, so on a chip where the raw value has
+		 * more bits, we need to shift offset. */
+		val >>= (chan->scan_type.realbits - 14);
+
+		/* There is one DAC offset register per vref. Changing one
+		 * channels offset will also change the offset for all other
+		 * channels which share the same vref supply. */
+		ofs_index = ad5360_get_channel_vref_index(st, chan->channel);
+		return ad5360_write(indio_dev, AD5360_CMD_SPECIAL_FUNCTION,
+				 AD5360_REG_SF_OFS(ofs_index), val, 0);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int ad5360_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+	unsigned int ofs_index;
+	int scale_uv;
+	int ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		ret = ad5360_read(indio_dev, AD5360_READBACK_X1A,
+			chan->address);
+		if (ret < 0)
+			return ret;
+		*val = ret >> chan->scan_type.shift;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		/* vout = 4 * vref * dac_code */
+		scale_uv = ad5360_get_channel_vref(st, chan->channel) * 4 * 100;
+		if (scale_uv < 0)
+			return scale_uv;
+
+		scale_uv >>= (chan->scan_type.realbits);
+		*val =  scale_uv / 100000;
+		*val2 = (scale_uv % 100000) * 10;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		ret = ad5360_read(indio_dev, AD5360_READBACK_OFFSET,
+			chan->address);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		ret = ad5360_read(indio_dev, AD5360_READBACK_GAIN,
+			chan->address);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_OFFSET:
+		ofs_index = ad5360_get_channel_vref_index(st, chan->channel);
+		ret = ad5360_read(indio_dev, AD5360_READBACK_SF,
+			AD5360_REG_SF_OFS(ofs_index));
+		if (ret < 0)
+			return ret;
+
+		ret <<= (chan->scan_type.realbits - 14);
+		*val = -ret;
+		return IIO_VAL_INT;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info ad5360_info = {
+	.read_raw = ad5360_read_raw,
+	.write_raw = ad5360_write_raw,
+	.attrs = &ad5360_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static const char * const ad5360_vref_name[] = {
+	 "vref0", "vref1", "vref2"
+};
+
+static int __devinit ad5360_alloc_channels(struct iio_dev *indio_dev)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+	struct iio_chan_spec *channels;
+	unsigned int i;
+
+	channels = kcalloc(st->chip_info->num_channels,
+			   sizeof(struct iio_chan_spec), GFP_KERNEL);
+
+	if (!channels)
+		return -ENOMEM;
+
+	for (i = 0; i < st->chip_info->num_channels; ++i) {
+		channels[i] = st->chip_info->channel_template;
+		channels[i].channel = i;
+		channels[i].address = AD5360_CHAN_ADDR(i);
+	}
+
+	indio_dev->channels = channels;
+
+	return 0;
+}
+
+static int __devinit ad5360_probe(struct spi_device *spi)
+{
+	enum ad5360_type type = spi_get_device_id(spi)->driver_data;
+	struct iio_dev *indio_dev;
+	struct ad5360_state *st;
+	unsigned int i;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		dev_err(&spi->dev, "Failed to allocate iio device\n");
+		return  -ENOMEM;
+	}
+
+	st = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+
+	st->chip_info = &ad5360_chip_info_tbl[type];
+	st->spi = spi;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5360_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->num_channels = st->chip_info->num_channels;
+
+	ret = ad5360_alloc_channels(indio_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to allocate channel spec: %d\n", ret);
+		goto error_free;
+	}
+
+	for (i = 0; i < st->chip_info->num_vrefs; ++i)
+		st->vref_reg[i].supply = ad5360_vref_name[i];
+
+	ret = regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs,
+		st->vref_reg);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to request vref regulators: %d\n", ret);
+		goto error_free_channels;
+	}
+
+	ret = regulator_bulk_enable(st->chip_info->num_vrefs, st->vref_reg);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to enable vref regulators: %d\n", ret);
+		goto error_free_reg;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
+		goto error_disable_reg;
+	}
+
+	return 0;
+
+error_disable_reg:
+	regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
+error_free_reg:
+	regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
+error_free_channels:
+	kfree(indio_dev->channels);
+error_free:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad5360_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5360_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	kfree(indio_dev->channels);
+
+	regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
+	regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5360_ids[] = {
+	{ "ad5360", ID_AD5360 },
+	{ "ad5361", ID_AD5361 },
+	{ "ad5362", ID_AD5362 },
+	{ "ad5363", ID_AD5363 },
+	{ "ad5370", ID_AD5370 },
+	{ "ad5371", ID_AD5371 },
+	{ "ad5372", ID_AD5372 },
+	{ "ad5373", ID_AD5373 },
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5360_ids);
+
+static struct spi_driver ad5360_driver = {
+	.driver = {
+		   .name = "ad5360",
+		   .owner = THIS_MODULE,
+	},
+	.probe = ad5360_probe,
+	.remove = __devexit_p(ad5360_remove),
+	.id_table = ad5360_ids,
+};
+module_spi_driver(ad5360_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5360/61/62/63/70/71/72/73 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c
new file mode 100644
index 0000000..14991ac
--- /dev/null
+++ b/drivers/iio/dac/ad5380.c
@@ -0,0 +1,655 @@
+/*
+ * Analog devices AD5380, AD5381, AD5382, AD5383, AD5390, AD5391, AD5392
+ * multi-channel Digital to Analog Converters driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AD5380_REG_DATA(x)	(((x) << 2) | 3)
+#define AD5380_REG_OFFSET(x)	(((x) << 2) | 2)
+#define AD5380_REG_GAIN(x)	(((x) << 2) | 1)
+#define AD5380_REG_SF_PWR_DOWN	(8 << 2)
+#define AD5380_REG_SF_PWR_UP	(9 << 2)
+#define AD5380_REG_SF_CTRL	(12 << 2)
+
+#define AD5380_CTRL_PWR_DOWN_MODE_OFFSET	13
+#define AD5380_CTRL_INT_VREF_2V5		BIT(12)
+#define AD5380_CTRL_INT_VREF_EN			BIT(10)
+
+/**
+ * struct ad5380_chip_info - chip specific information
+ * @channel_template:	channel specification template
+ * @num_channels:	number of channels
+ * @int_vref:		internal vref in uV
+*/
+
+struct ad5380_chip_info {
+	struct iio_chan_spec	channel_template;
+	unsigned int		num_channels;
+	unsigned int		int_vref;
+};
+
+/**
+ * struct ad5380_state - driver instance specific data
+ * @regmap:		regmap instance used by the device
+ * @chip_info:		chip model specific constants, available modes etc
+ * @vref_reg:		vref supply regulator
+ * @vref:		actual reference voltage used in uA
+ * @pwr_down:		whether the chip is currently in power down mode
+ */
+
+struct ad5380_state {
+	struct regmap			*regmap;
+	const struct ad5380_chip_info	*chip_info;
+	struct regulator		*vref_reg;
+	int				vref;
+	bool				pwr_down;
+};
+
+enum ad5380_type {
+	ID_AD5380_3,
+	ID_AD5380_5,
+	ID_AD5381_3,
+	ID_AD5381_5,
+	ID_AD5382_3,
+	ID_AD5382_5,
+	ID_AD5383_3,
+	ID_AD5383_5,
+	ID_AD5390_3,
+	ID_AD5390_5,
+	ID_AD5391_3,
+	ID_AD5391_5,
+	ID_AD5392_3,
+	ID_AD5392_5,
+};
+
+static ssize_t ad5380_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", st->pwr_down);
+}
+
+static ssize_t ad5380_write_dac_powerdown(struct iio_dev *indio_dev,
+	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	 size_t len)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+	bool pwr_down;
+	int ret;
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	mutex_lock(&indio_dev->mlock);
+
+	if (pwr_down)
+		ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_DOWN, 0);
+	else
+		ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_UP, 0);
+
+	st->pwr_down = pwr_down;
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret ? ret : len;
+}
+
+static const char * const ad5380_powerdown_modes[] = {
+	"100kohm_to_gnd",
+	"three_state",
+};
+
+static int ad5380_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+	unsigned int mode;
+	int ret;
+
+	ret = regmap_read(st->regmap, AD5380_REG_SF_CTRL, &mode);
+	if (ret)
+		return ret;
+
+	mode = (mode >> AD5380_CTRL_PWR_DOWN_MODE_OFFSET) & 1;
+
+	return mode;
+}
+
+static int ad5380_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+	int ret;
+
+	ret = regmap_update_bits(st->regmap, AD5380_REG_SF_CTRL,
+		1 << AD5380_CTRL_PWR_DOWN_MODE_OFFSET,
+		mode << AD5380_CTRL_PWR_DOWN_MODE_OFFSET);
+
+	return ret;
+}
+
+static const struct iio_enum ad5380_powerdown_mode_enum = {
+	.items = ad5380_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5380_powerdown_modes),
+	.get = ad5380_get_powerdown_mode,
+	.set = ad5380_set_powerdown_mode,
+};
+
+static unsigned int ad5380_info_to_reg(struct iio_chan_spec const *chan,
+	long info)
+{
+	switch (info) {
+	case 0:
+		return AD5380_REG_DATA(chan->address);
+	case IIO_CHAN_INFO_CALIBBIAS:
+		return AD5380_REG_OFFSET(chan->address);
+	case IIO_CHAN_INFO_CALIBSCALE:
+		return AD5380_REG_GAIN(chan->address);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int ad5380_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long info)
+{
+	const unsigned int max_val = (1 << chan->scan_type.realbits);
+	struct ad5380_state *st = iio_priv(indio_dev);
+
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return regmap_write(st->regmap,
+			ad5380_info_to_reg(chan, info),
+			val << chan->scan_type.shift);
+	case IIO_CHAN_INFO_CALIBBIAS:
+		val += (1 << chan->scan_type.realbits) / 2;
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return regmap_write(st->regmap,
+			AD5380_REG_OFFSET(chan->address),
+			val << chan->scan_type.shift);
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int ad5380_read_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int *val, int *val2, long info)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+	int ret;
+
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_CALIBSCALE:
+		ret = regmap_read(st->regmap, ad5380_info_to_reg(chan, info),
+					val);
+		if (ret)
+			return ret;
+		*val >>= chan->scan_type.shift;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		ret = regmap_read(st->regmap, AD5380_REG_OFFSET(chan->address),
+					val);
+		if (ret)
+			return ret;
+		*val >>= chan->scan_type.shift;
+		val -= (1 << chan->scan_type.realbits) / 2;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = ((2 * st->vref) >> chan->scan_type.realbits) * 100;
+		*val =  scale_uv / 100000;
+		*val2 = (scale_uv % 100000) * 10;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info ad5380_info = {
+	.read_raw = ad5380_read_raw,
+	.write_raw = ad5380_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static struct iio_chan_spec_ext_info ad5380_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5380_read_dac_powerdown,
+		.write = ad5380_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", true, &ad5380_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5380_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5380_CHANNEL(_bits) {					\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |		\
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,		\
+	.scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits)),	\
+	.ext_info = ad5380_ext_info,				\
+}
+
+static const struct ad5380_chip_info ad5380_chip_info_tbl[] = {
+	[ID_AD5380_3] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 40,
+		.int_vref = 1250000,
+	},
+	[ID_AD5380_5] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 40,
+		.int_vref = 2500000,
+	},
+	[ID_AD5381_3] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 16,
+		.int_vref = 1250000,
+	},
+	[ID_AD5381_5] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 16,
+		.int_vref = 2500000,
+	},
+	[ID_AD5382_3] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 32,
+		.int_vref = 1250000,
+	},
+	[ID_AD5382_5] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 32,
+		.int_vref = 2500000,
+	},
+	[ID_AD5383_3] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 32,
+		.int_vref = 1250000,
+	},
+	[ID_AD5383_5] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 32,
+		.int_vref = 2500000,
+	},
+	[ID_AD5390_3] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 16,
+		.int_vref = 1250000,
+	},
+	[ID_AD5390_5] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 16,
+		.int_vref = 2500000,
+	},
+	[ID_AD5391_3] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 16,
+		.int_vref = 1250000,
+	},
+	[ID_AD5391_5] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 16,
+		.int_vref = 2500000,
+	},
+	[ID_AD5392_3] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 8,
+		.int_vref = 1250000,
+	},
+	[ID_AD5392_5] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 8,
+		.int_vref = 2500000,
+	},
+};
+
+static int __devinit ad5380_alloc_channels(struct iio_dev *indio_dev)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+	struct iio_chan_spec *channels;
+	unsigned int i;
+
+	channels = kcalloc(st->chip_info->num_channels,
+			   sizeof(struct iio_chan_spec), GFP_KERNEL);
+
+	if (!channels)
+		return -ENOMEM;
+
+	for (i = 0; i < st->chip_info->num_channels; ++i) {
+		channels[i] = st->chip_info->channel_template;
+		channels[i].channel = i;
+		channels[i].address = i;
+	}
+
+	indio_dev->channels = channels;
+
+	return 0;
+}
+
+static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap,
+	enum ad5380_type type, const char *name)
+{
+	struct iio_dev *indio_dev;
+	struct ad5380_state *st;
+	unsigned int ctrl = 0;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		dev_err(dev, "Failed to allocate iio device\n");
+		ret = -ENOMEM;
+		goto error_out;
+	}
+
+	st = iio_priv(indio_dev);
+	dev_set_drvdata(dev, indio_dev);
+
+	st->chip_info = &ad5380_chip_info_tbl[type];
+	st->regmap = regmap;
+
+	indio_dev->dev.parent = dev;
+	indio_dev->name = name;
+	indio_dev->info = &ad5380_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->num_channels = st->chip_info->num_channels;
+
+	ret = ad5380_alloc_channels(indio_dev);
+	if (ret) {
+		dev_err(dev, "Failed to allocate channel spec: %d\n", ret);
+		goto error_free;
+	}
+
+	if (st->chip_info->int_vref == 2500000)
+		ctrl |= AD5380_CTRL_INT_VREF_2V5;
+
+	st->vref_reg = regulator_get(dev, "vref");
+	if (!IS_ERR(st->vref_reg)) {
+		ret = regulator_enable(st->vref_reg);
+		if (ret) {
+			dev_err(dev, "Failed to enable vref regulators: %d\n",
+				ret);
+			goto error_free_reg;
+		}
+
+		st->vref = regulator_get_voltage(st->vref_reg);
+	} else {
+		st->vref = st->chip_info->int_vref;
+		ctrl |= AD5380_CTRL_INT_VREF_EN;
+	}
+
+	ret = regmap_write(st->regmap, AD5380_REG_SF_CTRL, ctrl);
+	if (ret) {
+		dev_err(dev, "Failed to write to device: %d\n", ret);
+		goto error_disable_reg;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(dev, "Failed to register iio device: %d\n", ret);
+		goto error_disable_reg;
+	}
+
+	return 0;
+
+error_disable_reg:
+	if (!IS_ERR(st->vref_reg))
+		regulator_disable(st->vref_reg);
+error_free_reg:
+	if (!IS_ERR(st->vref_reg))
+		regulator_put(st->vref_reg);
+
+	kfree(indio_dev->channels);
+error_free:
+	iio_device_free(indio_dev);
+error_out:
+
+	return ret;
+}
+
+static int __devexit ad5380_remove(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct ad5380_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	kfree(indio_dev->channels);
+
+	if (!IS_ERR(st->vref_reg)) {
+		regulator_disable(st->vref_reg);
+		regulator_put(st->vref_reg);
+	}
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static bool ad5380_reg_false(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static const struct regmap_config ad5380_regmap_config = {
+	.reg_bits = 10,
+	.val_bits = 14,
+
+	.max_register = AD5380_REG_DATA(40),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = ad5380_reg_false,
+	.readable_reg = ad5380_reg_false,
+};
+
+#if IS_ENABLED(CONFIG_SPI_MASTER)
+
+static int __devinit ad5380_spi_probe(struct spi_device *spi)
+{
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_spi(spi, &ad5380_regmap_config);
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name);
+}
+
+static int __devexit ad5380_spi_remove(struct spi_device *spi)
+{
+	return ad5380_remove(&spi->dev);
+}
+
+static const struct spi_device_id ad5380_spi_ids[] = {
+	{ "ad5380-3", ID_AD5380_3 },
+	{ "ad5380-5", ID_AD5380_5 },
+	{ "ad5381-3", ID_AD5381_3 },
+	{ "ad5381-5", ID_AD5381_5 },
+	{ "ad5382-3", ID_AD5382_3 },
+	{ "ad5382-5", ID_AD5382_5 },
+	{ "ad5383-3", ID_AD5383_3 },
+	{ "ad5383-5", ID_AD5383_5 },
+	{ "ad5384-3", ID_AD5380_3 },
+	{ "ad5384-5", ID_AD5380_5 },
+	{ "ad5390-3", ID_AD5390_3 },
+	{ "ad5390-5", ID_AD5390_5 },
+	{ "ad5391-3", ID_AD5391_3 },
+	{ "ad5391-5", ID_AD5391_5 },
+	{ "ad5392-3", ID_AD5392_3 },
+	{ "ad5392-5", ID_AD5392_5 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, ad5380_spi_ids);
+
+static struct spi_driver ad5380_spi_driver = {
+	.driver = {
+		   .name = "ad5380",
+		   .owner = THIS_MODULE,
+	},
+	.probe = ad5380_spi_probe,
+	.remove = __devexit_p(ad5380_spi_remove),
+	.id_table = ad5380_spi_ids,
+};
+
+static inline int ad5380_spi_register_driver(void)
+{
+	return spi_register_driver(&ad5380_spi_driver);
+}
+
+static inline void ad5380_spi_unregister_driver(void)
+{
+	spi_unregister_driver(&ad5380_spi_driver);
+}
+
+#else
+
+static inline int ad5380_spi_register_driver(void)
+{
+	return 0;
+}
+
+static inline void ad5380_spi_unregister_driver(void)
+{
+}
+
+#endif
+
+#if IS_ENABLED(CONFIG_I2C)
+
+static int __devinit ad5380_i2c_probe(struct i2c_client *i2c,
+	const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(i2c, &ad5380_regmap_config);
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name);
+}
+
+static int __devexit ad5380_i2c_remove(struct i2c_client *i2c)
+{
+	return ad5380_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id ad5380_i2c_ids[] = {
+	{ "ad5380-3", ID_AD5380_3 },
+	{ "ad5380-5", ID_AD5380_5 },
+	{ "ad5381-3", ID_AD5381_3 },
+	{ "ad5381-5", ID_AD5381_5 },
+	{ "ad5382-3", ID_AD5382_3 },
+	{ "ad5382-5", ID_AD5382_5 },
+	{ "ad5383-3", ID_AD5383_3 },
+	{ "ad5383-5", ID_AD5383_5 },
+	{ "ad5384-3", ID_AD5380_3 },
+	{ "ad5384-5", ID_AD5380_5 },
+	{ "ad5390-3", ID_AD5390_3 },
+	{ "ad5390-5", ID_AD5390_5 },
+	{ "ad5391-3", ID_AD5391_3 },
+	{ "ad5391-5", ID_AD5391_5 },
+	{ "ad5392-3", ID_AD5392_3 },
+	{ "ad5392-5", ID_AD5392_5 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids);
+
+static struct i2c_driver ad5380_i2c_driver = {
+	.driver = {
+		   .name = "ad5380",
+		   .owner = THIS_MODULE,
+	},
+	.probe = ad5380_i2c_probe,
+	.remove = __devexit_p(ad5380_i2c_remove),
+	.id_table = ad5380_i2c_ids,
+};
+
+static inline int ad5380_i2c_register_driver(void)
+{
+	return i2c_add_driver(&ad5380_i2c_driver);
+}
+
+static inline void ad5380_i2c_unregister_driver(void)
+{
+	i2c_del_driver(&ad5380_i2c_driver);
+}
+
+#else
+
+static inline int ad5380_i2c_register_driver(void)
+{
+	return 0;
+}
+
+static inline void ad5380_i2c_unregister_driver(void)
+{
+}
+
+#endif
+
+static int __init ad5380_spi_init(void)
+{
+	int ret;
+
+	ret = ad5380_spi_register_driver();
+	if (ret)
+		return ret;
+
+	ret = ad5380_i2c_register_driver();
+	if (ret) {
+		ad5380_spi_unregister_driver();
+		return ret;
+	}
+
+	return 0;
+}
+module_init(ad5380_spi_init);
+
+static void __exit ad5380_spi_exit(void)
+{
+	ad5380_i2c_unregister_driver();
+	ad5380_spi_unregister_driver();
+
+}
+module_exit(ad5380_spi_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5380/81/82/83/84/90/91/92 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c
new file mode 100644
index 0000000..cdbc5bf
--- /dev/null
+++ b/drivers/iio/dac/ad5421.c
@@ -0,0 +1,544 @@
+/*
+ * AD5421 Digital to analog converters  driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/dac/ad5421.h>
+
+
+#define AD5421_REG_DAC_DATA		0x1
+#define AD5421_REG_CTRL			0x2
+#define AD5421_REG_OFFSET		0x3
+#define AD5421_REG_GAIN			0x4
+/* load dac and fault shared the same register number. Writing to it will cause
+ * a dac load command, reading from it will return the fault status register */
+#define AD5421_REG_LOAD_DAC		0x5
+#define AD5421_REG_FAULT		0x5
+#define AD5421_REG_FORCE_ALARM_CURRENT	0x6
+#define AD5421_REG_RESET		0x7
+#define AD5421_REG_START_CONVERSION	0x8
+#define AD5421_REG_NOOP			0x9
+
+#define AD5421_CTRL_WATCHDOG_DISABLE	BIT(12)
+#define AD5421_CTRL_AUTO_FAULT_READBACK	BIT(11)
+#define AD5421_CTRL_MIN_CURRENT		BIT(9)
+#define AD5421_CTRL_ADC_SOURCE_TEMP	BIT(8)
+#define AD5421_CTRL_ADC_ENABLE		BIT(7)
+#define AD5421_CTRL_PWR_DOWN_INT_VREF	BIT(6)
+
+#define AD5421_FAULT_SPI			BIT(15)
+#define AD5421_FAULT_PEC			BIT(14)
+#define AD5421_FAULT_OVER_CURRENT		BIT(13)
+#define AD5421_FAULT_UNDER_CURRENT		BIT(12)
+#define AD5421_FAULT_TEMP_OVER_140		BIT(11)
+#define AD5421_FAULT_TEMP_OVER_100		BIT(10)
+#define AD5421_FAULT_UNDER_VOLTAGE_6V		BIT(9)
+#define AD5421_FAULT_UNDER_VOLTAGE_12V		BIT(8)
+
+/* These bits will cause the fault pin to go high */
+#define AD5421_FAULT_TRIGGER_IRQ \
+	(AD5421_FAULT_SPI | AD5421_FAULT_PEC | AD5421_FAULT_OVER_CURRENT | \
+	AD5421_FAULT_UNDER_CURRENT | AD5421_FAULT_TEMP_OVER_140)
+
+/**
+ * struct ad5421_state - driver instance specific data
+ * @spi:		spi_device
+ * @ctrl:		control register cache
+ * @current_range:	current range which the device is configured for
+ * @data:		spi transfer buffers
+ * @fault_mask:		software masking of events
+ */
+struct ad5421_state {
+	struct spi_device		*spi;
+	unsigned int			ctrl;
+	enum ad5421_current_range	current_range;
+	unsigned int			fault_mask;
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	union {
+		u32 d32;
+		u8 d8[4];
+	} data[2] ____cacheline_aligned;
+};
+
+static const struct iio_chan_spec ad5421_channels[] = {
+	{
+		.type = IIO_CURRENT,
+		.indexed = 1,
+		.output = 1,
+		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT |
+			IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+			IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+			IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+		.scan_type = IIO_ST('u', 16, 16, 0),
+		.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
+			IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING),
+	},
+	{
+		.type = IIO_TEMP,
+		.channel = -1,
+		.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
+	},
+};
+
+static int ad5421_write_unlocked(struct iio_dev *indio_dev,
+	unsigned int reg, unsigned int val)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+
+	st->data[0].d32 = cpu_to_be32((reg << 16) | val);
+
+	return spi_write(st->spi, &st->data[0].d8[1], 3);
+}
+
+static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg,
+	unsigned int val)
+{
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	ret = ad5421_write_unlocked(indio_dev, reg, val);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+	struct spi_message m;
+	int ret;
+	struct spi_transfer t[] = {
+		{
+			.tx_buf = &st->data[0].d8[1],
+			.len = 3,
+			.cs_change = 1,
+		}, {
+			.rx_buf = &st->data[1].d8[1],
+			.len = 3,
+		},
+	};
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	mutex_lock(&indio_dev->mlock);
+
+	st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
+
+	ret = spi_sync(st->spi, &m);
+	if (ret >= 0)
+		ret = be32_to_cpu(st->data[1].d32) & 0xffff;
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5421_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
+	unsigned int clr)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+	unsigned int ret;
+
+	mutex_lock(&indio_dev->mlock);
+
+	st->ctrl &= ~clr;
+	st->ctrl |= set;
+
+	ret = ad5421_write_unlocked(indio_dev, AD5421_REG_CTRL, st->ctrl);
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static irqreturn_t ad5421_fault_handler(int irq, void *data)
+{
+	struct iio_dev *indio_dev = data;
+	struct ad5421_state *st = iio_priv(indio_dev);
+	unsigned int fault;
+	unsigned int old_fault = 0;
+	unsigned int events;
+
+	fault = ad5421_read(indio_dev, AD5421_REG_FAULT);
+	if (!fault)
+		return IRQ_NONE;
+
+	/* If we had a fault, this might mean that the DAC has lost its state
+	 * and has been reset. Make sure that the control register actually
+	 * contains what we expect it to contain. Otherwise the watchdog might
+	 * be enabled and we get watchdog timeout faults, which will render the
+	 * DAC unusable. */
+	ad5421_update_ctrl(indio_dev, 0, 0);
+
+
+	/* The fault pin stays high as long as a fault condition is present and
+	 * it is not possible to mask fault conditions. For certain fault
+	 * conditions for example like over-temperature it takes some time
+	 * until the fault condition disappears. If we would exit the interrupt
+	 * handler immediately after handling the event it would be entered
+	 * again instantly. Thus we fall back to polling in case we detect that
+	 * a interrupt condition is still present.
+	 */
+	do {
+		/* 0xffff is a invalid value for the register and will only be
+		 * read if there has been a communication error */
+		if (fault == 0xffff)
+			fault = 0;
+
+		/* we are only interested in new events */
+		events = (old_fault ^ fault) & fault;
+		events &= st->fault_mask;
+
+		if (events & AD5421_FAULT_OVER_CURRENT) {
+			iio_push_event(indio_dev,
+				IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
+					0,
+					IIO_EV_TYPE_THRESH,
+					IIO_EV_DIR_RISING),
+			iio_get_time_ns());
+		}
+
+		if (events & AD5421_FAULT_UNDER_CURRENT) {
+			iio_push_event(indio_dev,
+				IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
+					0,
+					IIO_EV_TYPE_THRESH,
+					IIO_EV_DIR_FALLING),
+				iio_get_time_ns());
+		}
+
+		if (events & AD5421_FAULT_TEMP_OVER_140) {
+			iio_push_event(indio_dev,
+				IIO_UNMOD_EVENT_CODE(IIO_TEMP,
+					0,
+					IIO_EV_TYPE_MAG,
+					IIO_EV_DIR_RISING),
+				iio_get_time_ns());
+		}
+
+		old_fault = fault;
+		fault = ad5421_read(indio_dev, AD5421_REG_FAULT);
+
+		/* still active? go to sleep for some time */
+		if (fault & AD5421_FAULT_TRIGGER_IRQ)
+			msleep(1000);
+
+	} while (fault & AD5421_FAULT_TRIGGER_IRQ);
+
+
+	return IRQ_HANDLED;
+}
+
+static void ad5421_get_current_min_max(struct ad5421_state *st,
+	unsigned int *min, unsigned int *max)
+{
+	/* The current range is configured using external pins, which are
+	 * usually hard-wired and not run-time switchable. */
+	switch (st->current_range) {
+	case AD5421_CURRENT_RANGE_4mA_20mA:
+		*min = 4000;
+		*max = 20000;
+		break;
+	case AD5421_CURRENT_RANGE_3mA8_21mA:
+		*min = 3800;
+		*max = 21000;
+		break;
+	case AD5421_CURRENT_RANGE_3mA2_24mA:
+		*min = 3200;
+		*max = 24000;
+		break;
+	default:
+		*min = 0;
+		*max = 1;
+		break;
+	}
+}
+
+static inline unsigned int ad5421_get_offset(struct ad5421_state *st)
+{
+	unsigned int min, max;
+
+	ad5421_get_current_min_max(st, &min, &max);
+	return (min * (1 << 16)) / (max - min);
+}
+
+static inline unsigned int ad5421_get_scale(struct ad5421_state *st)
+{
+	unsigned int min, max;
+
+	ad5421_get_current_min_max(st, &min, &max);
+	return ((max - min) * 1000) / (1 << 16);
+}
+
+static int ad5421_read_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int *val, int *val2, long m)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+	int ret;
+
+	if (chan->type != IIO_CURRENT)
+		return -EINVAL;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		*val2 = ad5421_get_scale(st);
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = ad5421_get_offset(st);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		ret = ad5421_read(indio_dev, AD5421_REG_OFFSET);
+		if (ret < 0)
+			return ret;
+		*val = ret - 32768;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		ret = ad5421_read(indio_dev, AD5421_REG_GAIN);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+	}
+
+	return -EINVAL;
+}
+
+static int ad5421_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	const unsigned int max_val = 1 << 16;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5421_write(indio_dev, AD5421_REG_DAC_DATA, val);
+	case IIO_CHAN_INFO_CALIBBIAS:
+		val += 32768;
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5421_write(indio_dev, AD5421_REG_OFFSET, val);
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5421_write(indio_dev, AD5421_REG_GAIN, val);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int ad5421_write_event_config(struct iio_dev *indio_dev,
+	u64 event_code, int state)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+	unsigned int mask;
+
+	switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
+	case IIO_CURRENT:
+		if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
+			IIO_EV_DIR_RISING)
+			mask = AD5421_FAULT_OVER_CURRENT;
+		else
+			mask = AD5421_FAULT_UNDER_CURRENT;
+		break;
+	case IIO_TEMP:
+		mask = AD5421_FAULT_TEMP_OVER_140;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&indio_dev->mlock);
+	if (state)
+		st->fault_mask |= mask;
+	else
+		st->fault_mask &= ~mask;
+	mutex_unlock(&indio_dev->mlock);
+
+	return 0;
+}
+
+static int ad5421_read_event_config(struct iio_dev *indio_dev,
+	u64 event_code)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+	unsigned int mask;
+
+	switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
+	case IIO_CURRENT:
+		if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
+			IIO_EV_DIR_RISING)
+			mask = AD5421_FAULT_OVER_CURRENT;
+		else
+			mask = AD5421_FAULT_UNDER_CURRENT;
+		break;
+	case IIO_TEMP:
+		mask = AD5421_FAULT_TEMP_OVER_140;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return (bool)(st->fault_mask & mask);
+}
+
+static int ad5421_read_event_value(struct iio_dev *indio_dev, u64 event_code,
+	int *val)
+{
+	int ret;
+
+	switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
+	case IIO_CURRENT:
+		ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		break;
+	case IIO_TEMP:
+		*val = 140000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct iio_info ad5421_info = {
+	.read_raw =		ad5421_read_raw,
+	.write_raw =		ad5421_write_raw,
+	.read_event_config =	ad5421_read_event_config,
+	.write_event_config =	ad5421_write_event_config,
+	.read_event_value =	ad5421_read_event_value,
+	.driver_module =	THIS_MODULE,
+};
+
+static int __devinit ad5421_probe(struct spi_device *spi)
+{
+	struct ad5421_platform_data *pdata = dev_get_platdata(&spi->dev);
+	struct iio_dev *indio_dev;
+	struct ad5421_state *st;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		dev_err(&spi->dev, "Failed to allocate iio device\n");
+		return  -ENOMEM;
+	}
+
+	st = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+
+	st->spi = spi;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = "ad5421";
+	indio_dev->info = &ad5421_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = ad5421_channels;
+	indio_dev->num_channels = ARRAY_SIZE(ad5421_channels);
+
+	st->ctrl = AD5421_CTRL_WATCHDOG_DISABLE |
+			AD5421_CTRL_AUTO_FAULT_READBACK;
+
+	if (pdata) {
+		st->current_range = pdata->current_range;
+		if (pdata->external_vref)
+			st->ctrl |= AD5421_CTRL_PWR_DOWN_INT_VREF;
+	} else {
+		st->current_range = AD5421_CURRENT_RANGE_4mA_20mA;
+	}
+
+	/* write initial ctrl register value */
+	ad5421_update_ctrl(indio_dev, 0, 0);
+
+	if (spi->irq) {
+		ret = request_threaded_irq(spi->irq,
+					   NULL,
+					   ad5421_fault_handler,
+					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					   "ad5421 fault",
+					   indio_dev);
+		if (ret)
+			goto error_free;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
+		goto error_free_irq;
+	}
+
+	return 0;
+
+error_free_irq:
+	if (spi->irq)
+		free_irq(spi->irq, indio_dev);
+error_free:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad5421_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+	iio_device_unregister(indio_dev);
+	if (spi->irq)
+		free_irq(spi->irq, indio_dev);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static struct spi_driver ad5421_driver = {
+	.driver = {
+		   .name = "ad5421",
+		   .owner = THIS_MODULE,
+	},
+	.probe = ad5421_probe,
+	.remove = __devexit_p(ad5421_remove),
+};
+module_spi_driver(ad5421_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5421 DAC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:ad5421");
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
new file mode 100644
index 0000000..2ca5059
--- /dev/null
+++ b/drivers/iio/dac/ad5446.c
@@ -0,0 +1,393 @@
+/*
+ * AD5446 SPI DAC driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "ad5446.h"
+
+static int ad5446_write(struct ad5446_state *st, unsigned val)
+{
+	__be16 data = cpu_to_be16(val);
+	return spi_write(st->spi, &data, sizeof(data));
+}
+
+static int ad5660_write(struct ad5446_state *st, unsigned val)
+{
+	uint8_t data[3];
+
+	data[0] = (val >> 16) & 0xFF;
+	data[1] = (val >> 8) & 0xFF;
+	data[2] = val & 0xFF;
+
+	return spi_write(st->spi, data, sizeof(data));
+}
+
+static const char * const ad5446_powerdown_modes[] = {
+	"1kohm_to_gnd", "100kohm_to_gnd", "three_state"
+};
+
+static int ad5446_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+
+	st->pwr_down_mode = mode + 1;
+
+	return 0;
+}
+
+static int ad5446_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+
+	return st->pwr_down_mode - 1;
+}
+
+static const struct iio_enum ad5446_powerdown_mode_enum = {
+	.items = ad5446_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5446_powerdown_modes),
+	.get = ad5446_get_powerdown_mode,
+	.set = ad5446_set_powerdown_mode,
+};
+
+static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev,
+					   uintptr_t private,
+					   const struct iio_chan_spec *chan,
+					   char *buf)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", st->pwr_down);
+}
+
+static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev,
+					    uintptr_t private,
+					    const struct iio_chan_spec *chan,
+					    const char *buf, size_t len)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+	unsigned int shift;
+	unsigned int val;
+	bool powerdown;
+	int ret;
+
+	ret = strtobool(buf, &powerdown);
+	if (ret)
+		return ret;
+
+	mutex_lock(&indio_dev->mlock);
+	st->pwr_down = powerdown;
+
+	if (st->pwr_down) {
+		shift = chan->scan_type.realbits + chan->scan_type.shift;
+		val = st->pwr_down_mode << shift;
+	} else {
+		val = st->cached_val;
+	}
+
+	ret = st->chip_info->write(st, val);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret ? ret : len;
+}
+
+static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = {
+	{
+		.name = "powerdown",
+		.read = ad5446_read_dac_powerdown,
+		.write = ad5446_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", false, &ad5446_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5446_powerdown_mode_enum),
+	{ },
+};
+
+#define _AD5446_CHANNEL(bits, storage, shift, ext) { \
+	.type = IIO_VOLTAGE, \
+	.indexed = 1, \
+	.output = 1, \
+	.channel = 0, \
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+	IIO_CHAN_INFO_SCALE_SHARED_BIT,	\
+	.scan_type = IIO_ST('u', (bits), (storage), (shift)), \
+	.ext_info = (ext), \
+}
+
+#define AD5446_CHANNEL(bits, storage, shift) \
+	_AD5446_CHANNEL(bits, storage, shift, NULL)
+
+#define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \
+	_AD5446_CHANNEL(bits, storage, shift, ad5064_ext_info_powerdown)
+
+static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
+	[ID_AD5444] = {
+		.channel = AD5446_CHANNEL(12, 16, 2),
+		.write = ad5446_write,
+	},
+	[ID_AD5446] = {
+		.channel = AD5446_CHANNEL(14, 16, 0),
+		.write = ad5446_write,
+	},
+	[ID_AD5450] = {
+		.channel = AD5446_CHANNEL(8, 16, 6),
+		.write = ad5446_write,
+	},
+	[ID_AD5451] = {
+		.channel = AD5446_CHANNEL(10, 16, 4),
+		.write = ad5446_write,
+	},
+	[ID_AD5541A] = {
+		.channel = AD5446_CHANNEL(16, 16, 0),
+		.write = ad5446_write,
+	},
+	[ID_AD5512A] = {
+		.channel = AD5446_CHANNEL(12, 16, 4),
+		.write = ad5446_write,
+	},
+	[ID_AD5553] = {
+		.channel = AD5446_CHANNEL(14, 16, 0),
+		.write = ad5446_write,
+	},
+	[ID_AD5601] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
+		.write = ad5446_write,
+	},
+	[ID_AD5611] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4),
+		.write = ad5446_write,
+	},
+	[ID_AD5621] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+		.write = ad5446_write,
+	},
+	[ID_AD5620_2500] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+		.int_vref_mv = 2500,
+		.write = ad5446_write,
+	},
+	[ID_AD5620_1250] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+		.int_vref_mv = 1250,
+		.write = ad5446_write,
+	},
+	[ID_AD5640_2500] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
+		.int_vref_mv = 2500,
+		.write = ad5446_write,
+	},
+	[ID_AD5640_1250] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
+		.int_vref_mv = 1250,
+		.write = ad5446_write,
+	},
+	[ID_AD5660_2500] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+		.int_vref_mv = 2500,
+		.write = ad5660_write,
+	},
+	[ID_AD5660_1250] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+		.int_vref_mv = 1250,
+		.write = ad5660_write,
+	},
+	[ID_AD5662] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+		.write = ad5660_write,
+	},
+};
+
+static int ad5446_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		*val = st->cached_val;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+		*val =  scale_uv / 1000;
+		*val2 = (scale_uv % 1000) * 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	}
+	return -EINVAL;
+}
+
+static int ad5446_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+	int ret = 0;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		val <<= chan->scan_type.shift;
+		mutex_lock(&indio_dev->mlock);
+		st->cached_val = val;
+		if (!st->pwr_down)
+			ret = st->chip_info->write(st, val);
+		mutex_unlock(&indio_dev->mlock);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct iio_info ad5446_info = {
+	.read_raw = ad5446_read_raw,
+	.write_raw = ad5446_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad5446_probe(struct spi_device *spi)
+{
+	struct ad5446_state *st;
+	struct iio_dev *indio_dev;
+	struct regulator *reg;
+	int ret, voltage_uv = 0;
+
+	reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(reg)) {
+		ret = regulator_enable(reg);
+		if (ret)
+			goto error_put_reg;
+
+		voltage_uv = regulator_get_voltage(reg);
+	}
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_disable_reg;
+	}
+	st = iio_priv(indio_dev);
+	st->chip_info =
+		&ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+	spi_set_drvdata(spi, indio_dev);
+	st->reg = reg;
+	st->spi = spi;
+
+	/* Establish that the iio_dev is a child of the spi device */
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5446_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = &st->chip_info->channel;
+	indio_dev->num_channels = 1;
+
+	st->pwr_down_mode = MODE_PWRDWN_1k;
+
+	if (st->chip_info->int_vref_mv)
+		st->vref_mv = st->chip_info->int_vref_mv;
+	else if (voltage_uv)
+		st->vref_mv = voltage_uv / 1000;
+	else
+		dev_warn(&spi->dev, "reference voltage unspecified\n");
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_free_device;
+
+	return 0;
+
+error_free_device:
+	iio_device_free(indio_dev);
+error_disable_reg:
+	if (!IS_ERR(reg))
+		regulator_disable(reg);
+error_put_reg:
+	if (!IS_ERR(reg))
+		regulator_put(reg);
+
+	return ret;
+}
+
+static int ad5446_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5446_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5446_id[] = {
+	{"ad5444", ID_AD5444},
+	{"ad5446", ID_AD5446},
+	{"ad5450", ID_AD5450},
+	{"ad5451", ID_AD5451},
+	{"ad5452", ID_AD5444}, /* ad5452 is compatible to the ad5444 */
+	{"ad5453", ID_AD5446}, /* ad5453 is compatible to the ad5446 */
+	{"ad5512a", ID_AD5512A},
+	{"ad5541a", ID_AD5541A},
+	{"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
+	{"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
+	{"ad5553", ID_AD5553},
+	{"ad5601", ID_AD5601},
+	{"ad5611", ID_AD5611},
+	{"ad5621", ID_AD5621},
+	{"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */
+	{"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */
+	{"ad5640-2500", ID_AD5640_2500},
+	{"ad5640-1250", ID_AD5640_1250},
+	{"ad5660-2500", ID_AD5660_2500},
+	{"ad5660-1250", ID_AD5660_1250},
+	{"ad5662", ID_AD5662},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5446_id);
+
+static struct spi_driver ad5446_driver = {
+	.driver = {
+		.name	= "ad5446",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad5446_probe,
+	.remove		= __devexit_p(ad5446_remove),
+	.id_table	= ad5446_id,
+};
+module_spi_driver(ad5446_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5446.h b/drivers/iio/dac/ad5446.h
new file mode 100644
index 0000000..2934269
--- /dev/null
+++ b/drivers/iio/dac/ad5446.h
@@ -0,0 +1,91 @@
+/*
+ * AD5446 SPI DAC driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef IIO_DAC_AD5446_H_
+#define IIO_DAC_AD5446_H_
+
+/* DAC Control Bits */
+
+#define AD5446_LOAD		(0x0 << 14) /* Load and update */
+#define AD5446_SDO_DIS		(0x1 << 14) /* Disable SDO */
+#define AD5446_NOP		(0x2 << 14) /* No operation */
+#define AD5446_CLK_RISING	(0x3 << 14) /* Clock data on rising edge */
+
+#define AD5620_LOAD		(0x0 << 14) /* Load and update Norm Operation*/
+#define AD5620_PWRDWN_1k	(0x1 << 14) /* Power-down: 1kOhm to GND */
+#define AD5620_PWRDWN_100k	(0x2 << 14) /* Power-down: 100kOhm to GND */
+#define AD5620_PWRDWN_TRISTATE	(0x3 << 14) /* Power-down: Three-state */
+
+#define AD5660_LOAD		(0x0 << 16) /* Load and update Norm Operation*/
+#define AD5660_PWRDWN_1k	(0x1 << 16) /* Power-down: 1kOhm to GND */
+#define AD5660_PWRDWN_100k	(0x2 << 16) /* Power-down: 100kOhm to GND */
+#define AD5660_PWRDWN_TRISTATE	(0x3 << 16) /* Power-down: Three-state */
+
+#define MODE_PWRDWN_1k		0x1
+#define MODE_PWRDWN_100k	0x2
+#define MODE_PWRDWN_TRISTATE	0x3
+
+/**
+ * struct ad5446_state - driver instance specific data
+ * @spi:		spi_device
+ * @chip_info:		chip model specific constants, available modes etc
+ * @reg:		supply regulator
+ * @vref_mv:		actual reference voltage used
+ */
+
+struct ad5446_state {
+	struct spi_device		*spi;
+	const struct ad5446_chip_info	*chip_info;
+	struct regulator		*reg;
+	unsigned short			vref_mv;
+	unsigned			cached_val;
+	unsigned			pwr_down_mode;
+	unsigned			pwr_down;
+};
+
+/**
+ * struct ad5446_chip_info - chip specific information
+ * @channel:		channel spec for the DAC
+ * @int_vref_mv:	AD5620/40/60: the internal reference voltage
+ * @write:		chip specific helper function to write to the register
+ */
+
+struct ad5446_chip_info {
+	struct iio_chan_spec	channel;
+	u16			int_vref_mv;
+	int			(*write)(struct ad5446_state *st, unsigned val);
+};
+
+/**
+ * ad5446_supported_device_ids:
+ * The AD5620/40/60 parts are available in different fixed internal reference
+ * voltage options. The actual part numbers may look differently
+ * (and a bit cryptic), however this style is used to make clear which
+ * parts are supported here.
+ */
+
+enum ad5446_supported_device_ids {
+	ID_AD5444,
+	ID_AD5446,
+	ID_AD5450,
+	ID_AD5451,
+	ID_AD5541A,
+	ID_AD5512A,
+	ID_AD5553,
+	ID_AD5601,
+	ID_AD5611,
+	ID_AD5621,
+	ID_AD5620_2500,
+	ID_AD5620_1250,
+	ID_AD5640_2500,
+	ID_AD5640_1250,
+	ID_AD5660_2500,
+	ID_AD5660_1250,
+	ID_AD5662,
+};
+
+#endif /* IIO_DAC_AD5446_H_ */
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
new file mode 100644
index 0000000..242bdc7
--- /dev/null
+++ b/drivers/iio/dac/ad5504.c
@@ -0,0 +1,393 @@
+/*
+ * AD5504, AD5501 High Voltage Digital to Analog Converter
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/dac/ad5504.h>
+
+#define AD5505_BITS			12
+#define AD5504_RES_MASK			((1 << (AD5505_BITS)) - 1)
+
+#define AD5504_CMD_READ			(1 << 15)
+#define AD5504_CMD_WRITE		(0 << 15)
+#define AD5504_ADDR(addr)		((addr) << 12)
+
+/* Registers */
+#define AD5504_ADDR_NOOP		0
+#define AD5504_ADDR_DAC(x)		((x) + 1)
+#define AD5504_ADDR_ALL_DAC		5
+#define AD5504_ADDR_CTRL		7
+
+/* Control Register */
+#define AD5504_DAC_PWR(ch)		((ch) << 2)
+#define AD5504_DAC_PWRDWN_MODE(mode)	((mode) << 6)
+#define AD5504_DAC_PWRDN_20K		0
+#define AD5504_DAC_PWRDN_3STATE		1
+
+/**
+ * struct ad5446_state - driver instance specific data
+ * @us:			spi_device
+ * @reg:		supply regulator
+ * @vref_mv:		actual reference voltage used
+ * @pwr_down_mask	power down mask
+ * @pwr_down_mode	current power down mode
+ */
+
+struct ad5504_state {
+	struct spi_device		*spi;
+	struct regulator		*reg;
+	unsigned short			vref_mv;
+	unsigned			pwr_down_mask;
+	unsigned			pwr_down_mode;
+};
+
+/**
+ * ad5504_supported_device_ids:
+ */
+
+enum ad5504_supported_device_ids {
+	ID_AD5504,
+	ID_AD5501,
+};
+
+static int ad5504_spi_write(struct spi_device *spi, u8 addr, u16 val)
+{
+	u16 tmp = cpu_to_be16(AD5504_CMD_WRITE |
+			      AD5504_ADDR(addr) |
+			      (val & AD5504_RES_MASK));
+
+	return spi_write(spi, (u8 *)&tmp, 2);
+}
+
+static int ad5504_spi_read(struct spi_device *spi, u8 addr)
+{
+	u16 tmp = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr));
+	u16 val;
+	int ret;
+	struct spi_transfer	t = {
+			.tx_buf		= &tmp,
+			.rx_buf		= &val,
+			.len		= 2,
+		};
+	struct spi_message	m;
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+	ret = spi_sync(spi, &m);
+
+	if (ret < 0)
+		return ret;
+
+	return be16_to_cpu(val) & AD5504_RES_MASK;
+}
+
+static int ad5504_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5504_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+	int ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		ret = ad5504_spi_read(st->spi, chan->address);
+		if (ret < 0)
+			return ret;
+
+		*val = ret;
+
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+		*val =  scale_uv / 1000;
+		*val2 = (scale_uv % 1000) * 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	}
+	return -EINVAL;
+}
+
+static int ad5504_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct ad5504_state *st = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		return ad5504_spi_write(st->spi, chan->address, val);
+	default:
+		ret = -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+static const char * const ad5504_powerdown_modes[] = {
+	"20kohm_to_gnd",
+	"three_state",
+};
+
+static int ad5504_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5504_state *st = iio_priv(indio_dev);
+
+	return st->pwr_down_mode;
+}
+
+static int ad5504_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5504_state *st = iio_priv(indio_dev);
+
+	st->pwr_down_mode = mode;
+
+	return 0;
+}
+
+static const struct iio_enum ad5504_powerdown_mode_enum = {
+	.items = ad5504_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5504_powerdown_modes),
+	.get = ad5504_get_powerdown_mode,
+	.set = ad5504_set_powerdown_mode,
+};
+
+static ssize_t ad5504_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5504_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n",
+			!(st->pwr_down_mask & (1 << chan->channel)));
+}
+
+static ssize_t ad5504_write_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	size_t len)
+{
+	bool pwr_down;
+	int ret;
+	struct ad5504_state *st = iio_priv(indio_dev);
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	if (pwr_down)
+		st->pwr_down_mask |= (1 << chan->channel);
+	else
+		st->pwr_down_mask &= ~(1 << chan->channel);
+
+	ret = ad5504_spi_write(st->spi, AD5504_ADDR_CTRL,
+				AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) |
+				AD5504_DAC_PWR(st->pwr_down_mask));
+
+	/* writes to the CTRL register must be followed by a NOOP */
+	ad5504_spi_write(st->spi, AD5504_ADDR_NOOP, 0);
+
+	return ret ? ret : len;
+}
+
+static IIO_CONST_ATTR(temp0_thresh_rising_value, "110000");
+static IIO_CONST_ATTR(temp0_thresh_rising_en, "1");
+
+static struct attribute *ad5504_ev_attributes[] = {
+	&iio_const_attr_temp0_thresh_rising_value.dev_attr.attr,
+	&iio_const_attr_temp0_thresh_rising_en.dev_attr.attr,
+	NULL,
+};
+
+static struct attribute_group ad5504_ev_attribute_group = {
+	.attrs = ad5504_ev_attributes,
+	.name = "events",
+};
+
+static irqreturn_t ad5504_event_handler(int irq, void *private)
+{
+	iio_push_event(private,
+		       IIO_UNMOD_EVENT_CODE(IIO_TEMP,
+					    0,
+					    IIO_EV_TYPE_THRESH,
+					    IIO_EV_DIR_RISING),
+		       iio_get_time_ns());
+
+	return IRQ_HANDLED;
+}
+
+static const struct iio_info ad5504_info = {
+	.write_raw = ad5504_write_raw,
+	.read_raw = ad5504_read_raw,
+	.event_attrs = &ad5504_ev_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_chan_spec_ext_info ad5504_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5504_read_dac_powerdown,
+		.write = ad5504_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", true, &ad5504_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5504_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5504_CHANNEL(_chan) { \
+	.type = IIO_VOLTAGE, \
+	.indexed = 1, \
+	.output = 1, \
+	.channel = (_chan), \
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+		     IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+	.address = AD5504_ADDR_DAC(_chan), \
+	.scan_type = IIO_ST('u', 12, 16, 0), \
+	.ext_info = ad5504_ext_info, \
+}
+
+static const struct iio_chan_spec ad5504_channels[] = {
+	AD5504_CHANNEL(0),
+	AD5504_CHANNEL(1),
+	AD5504_CHANNEL(2),
+	AD5504_CHANNEL(3),
+};
+
+static int __devinit ad5504_probe(struct spi_device *spi)
+{
+	struct ad5504_platform_data *pdata = spi->dev.platform_data;
+	struct iio_dev *indio_dev;
+	struct ad5504_state *st;
+	struct regulator *reg;
+	int ret, voltage_uv = 0;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(reg)) {
+		ret = regulator_enable(reg);
+		if (ret)
+			goto error_put_reg;
+
+		voltage_uv = regulator_get_voltage(reg);
+	}
+
+	spi_set_drvdata(spi, indio_dev);
+	st = iio_priv(indio_dev);
+	if (voltage_uv)
+		st->vref_mv = voltage_uv / 1000;
+	else if (pdata)
+		st->vref_mv = pdata->vref_mv;
+	else
+		dev_warn(&spi->dev, "reference voltage unspecified\n");
+
+	st->reg = reg;
+	st->spi = spi;
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(st->spi)->name;
+	indio_dev->info = &ad5504_info;
+	if (spi_get_device_id(st->spi)->driver_data == ID_AD5501)
+		indio_dev->num_channels = 1;
+	else
+		indio_dev->num_channels = 4;
+	indio_dev->channels = ad5504_channels;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	if (spi->irq) {
+		ret = request_threaded_irq(spi->irq,
+					   NULL,
+					   &ad5504_event_handler,
+					   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+					   spi_get_device_id(st->spi)->name,
+					   indio_dev);
+		if (ret)
+			goto error_disable_reg;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_free_irq;
+
+	return 0;
+
+error_free_irq:
+	if (spi->irq)
+		free_irq(spi->irq, indio_dev);
+error_disable_reg:
+	if (!IS_ERR(reg))
+		regulator_disable(reg);
+error_put_reg:
+	if (!IS_ERR(reg))
+		regulator_put(reg);
+
+	iio_device_free(indio_dev);
+error_ret:
+	return ret;
+}
+
+static int __devexit ad5504_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5504_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (spi->irq)
+		free_irq(spi->irq, indio_dev);
+
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5504_id[] = {
+	{"ad5504", ID_AD5504},
+	{"ad5501", ID_AD5501},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5504_id);
+
+static struct spi_driver ad5504_driver = {
+	.driver = {
+		   .name = "ad5504",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = ad5504_probe,
+	.remove = __devexit_p(ad5504_remove),
+	.id_table = ad5504_id,
+};
+module_spi_driver(ad5504_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5624r.h b/drivers/iio/dac/ad5624r.h
new file mode 100644
index 0000000..5dca302
--- /dev/null
+++ b/drivers/iio/dac/ad5624r.h
@@ -0,0 +1,79 @@
+/*
+ * AD5624R SPI DAC driver
+ *
+ * Copyright 2010-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+#ifndef SPI_AD5624R_H_
+#define SPI_AD5624R_H_
+
+#define AD5624R_DAC_CHANNELS			4
+
+#define AD5624R_ADDR_DAC0			0x0
+#define AD5624R_ADDR_DAC1			0x1
+#define AD5624R_ADDR_DAC2			0x2
+#define AD5624R_ADDR_DAC3			0x3
+#define AD5624R_ADDR_ALL_DAC			0x7
+
+#define AD5624R_CMD_WRITE_INPUT_N		0x0
+#define AD5624R_CMD_UPDATE_DAC_N		0x1
+#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_ALL	0x2
+#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_N	0x3
+#define AD5624R_CMD_POWERDOWN_DAC		0x4
+#define AD5624R_CMD_RESET			0x5
+#define AD5624R_CMD_LDAC_SETUP			0x6
+#define AD5624R_CMD_INTERNAL_REFER_SETUP	0x7
+
+#define AD5624R_LDAC_PWRDN_NONE			0x0
+#define AD5624R_LDAC_PWRDN_1K			0x1
+#define AD5624R_LDAC_PWRDN_100K			0x2
+#define AD5624R_LDAC_PWRDN_3STATE		0x3
+
+/**
+ * struct ad5624r_chip_info - chip specific information
+ * @channels:		channel spec for the DAC
+ * @int_vref_mv:	AD5620/40/60: the internal reference voltage
+ */
+
+struct ad5624r_chip_info {
+	const struct iio_chan_spec	*channels;
+	u16				int_vref_mv;
+};
+
+/**
+ * struct ad5446_state - driver instance specific data
+ * @indio_dev:		the industrial I/O device
+ * @us:			spi_device
+ * @chip_info:		chip model specific constants, available modes etc
+ * @reg:		supply regulator
+ * @vref_mv:		actual reference voltage used
+ * @pwr_down_mask	power down mask
+ * @pwr_down_mode	current power down mode
+ */
+
+struct ad5624r_state {
+	struct spi_device		*us;
+	const struct ad5624r_chip_info	*chip_info;
+	struct regulator		*reg;
+	unsigned short			vref_mv;
+	unsigned			pwr_down_mask;
+	unsigned			pwr_down_mode;
+};
+
+/**
+ * ad5624r_supported_device_ids:
+ * The AD5624/44/64 parts are available in different
+ * fixed internal reference voltage options.
+ */
+
+enum ad5624r_supported_device_ids {
+	ID_AD5624R3,
+	ID_AD5644R3,
+	ID_AD5664R3,
+	ID_AD5624R5,
+	ID_AD5644R5,
+	ID_AD5664R5,
+};
+
+#endif /* SPI_AD5624R_H_ */
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c
new file mode 100644
index 0000000..6a7d6a4
--- /dev/null
+++ b/drivers/iio/dac/ad5624r_spi.c
@@ -0,0 +1,324 @@
+/*
+ * AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver
+ *
+ * Copyright 2010-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "ad5624r.h"
+
+static int ad5624r_spi_write(struct spi_device *spi,
+			     u8 cmd, u8 addr, u16 val, u8 len)
+{
+	u32 data;
+	u8 msg[3];
+
+	/*
+	 * The input shift register is 24 bits wide. The first two bits are
+	 * don't care bits. The next three are the command bits, C2 to C0,
+	 * followed by the 3-bit DAC address, A2 to A0, and then the
+	 * 16-, 14-, 12-bit data-word. The data-word comprises the 16-,
+	 * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits,
+	 * for the AD5664R, AD5644R, and AD5624R, respectively.
+	 */
+	data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len));
+	msg[0] = data >> 16;
+	msg[1] = data >> 8;
+	msg[2] = data;
+
+	return spi_write(spi, msg, 3);
+}
+
+static int ad5624r_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5624r_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+
+	switch (m) {
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+		*val =  scale_uv / 1000;
+		*val2 = (scale_uv % 1000) * 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	}
+	return -EINVAL;
+}
+
+static int ad5624r_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct ad5624r_state *st = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		return ad5624r_spi_write(st->us,
+				AD5624R_CMD_WRITE_INPUT_N_UPDATE_N,
+				chan->address, val,
+				chan->scan_type.shift);
+	default:
+		ret = -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+static const char * const ad5624r_powerdown_modes[] = {
+	"1kohm_to_gnd",
+	"100kohm_to_gnd",
+	"three_state"
+};
+
+static int ad5624r_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5624r_state *st = iio_priv(indio_dev);
+
+	return st->pwr_down_mode;
+}
+
+static int ad5624r_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5624r_state *st = iio_priv(indio_dev);
+
+	st->pwr_down_mode = mode;
+
+	return 0;
+}
+
+static const struct iio_enum ad5624r_powerdown_mode_enum = {
+	.items = ad5624r_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5624r_powerdown_modes),
+	.get = ad5624r_get_powerdown_mode,
+	.set = ad5624r_set_powerdown_mode,
+};
+
+static ssize_t ad5624r_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5624r_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n",
+			!!(st->pwr_down_mask & (1 << chan->channel)));
+}
+
+static ssize_t ad5624r_write_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	size_t len)
+{
+	bool pwr_down;
+	int ret;
+	struct ad5624r_state *st = iio_priv(indio_dev);
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	if (pwr_down)
+		st->pwr_down_mask |= (1 << chan->channel);
+	else
+		st->pwr_down_mask &= ~(1 << chan->channel);
+
+	ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0,
+				(st->pwr_down_mode << 4) |
+				st->pwr_down_mask, 16);
+
+	return ret ? ret : len;
+}
+
+static const struct iio_info ad5624r_info = {
+	.write_raw = ad5624r_write_raw,
+	.read_raw = ad5624r_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5624r_read_dac_powerdown,
+		.write = ad5624r_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", true, &ad5624r_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5624r_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5624R_CHANNEL(_chan, _bits) { \
+	.type = IIO_VOLTAGE, \
+	.indexed = 1, \
+	.output = 1, \
+	.channel = (_chan), \
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+		     IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+	.address = (_chan), \
+	.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \
+	.ext_info = ad5624r_ext_info, \
+}
+
+#define DECLARE_AD5624R_CHANNELS(_name, _bits) \
+	const struct iio_chan_spec _name##_channels[] = { \
+		AD5624R_CHANNEL(0, _bits), \
+		AD5624R_CHANNEL(1, _bits), \
+		AD5624R_CHANNEL(2, _bits), \
+		AD5624R_CHANNEL(3, _bits), \
+}
+
+static DECLARE_AD5624R_CHANNELS(ad5624r, 12);
+static DECLARE_AD5624R_CHANNELS(ad5644r, 14);
+static DECLARE_AD5624R_CHANNELS(ad5664r, 16);
+
+static const struct ad5624r_chip_info ad5624r_chip_info_tbl[] = {
+	[ID_AD5624R3] = {
+		.channels = ad5624r_channels,
+		.int_vref_mv = 1250,
+	},
+	[ID_AD5624R5] = {
+		.channels = ad5624r_channels,
+		.int_vref_mv = 2500,
+	},
+	[ID_AD5644R3] = {
+		.channels = ad5644r_channels,
+		.int_vref_mv = 1250,
+	},
+	[ID_AD5644R5] = {
+		.channels = ad5644r_channels,
+		.int_vref_mv = 2500,
+	},
+	[ID_AD5664R3] = {
+		.channels = ad5664r_channels,
+		.int_vref_mv = 1250,
+	},
+	[ID_AD5664R5] = {
+		.channels = ad5664r_channels,
+		.int_vref_mv = 2500,
+	},
+};
+
+static int __devinit ad5624r_probe(struct spi_device *spi)
+{
+	struct ad5624r_state *st;
+	struct iio_dev *indio_dev;
+	int ret, voltage_uv = 0;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	st = iio_priv(indio_dev);
+	st->reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(st->reg)) {
+		ret = regulator_enable(st->reg);
+		if (ret)
+			goto error_put_reg;
+
+		voltage_uv = regulator_get_voltage(st->reg);
+	}
+
+	spi_set_drvdata(spi, indio_dev);
+	st->chip_info =
+		&ad5624r_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+	if (voltage_uv)
+		st->vref_mv = voltage_uv / 1000;
+	else
+		st->vref_mv = st->chip_info->int_vref_mv;
+
+	st->us = spi;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5624r_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = st->chip_info->channels;
+	indio_dev->num_channels = AD5624R_DAC_CHANNELS;
+
+	ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0,
+				!!voltage_uv, 16);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_disable_reg;
+
+	return 0;
+
+error_disable_reg:
+	if (!IS_ERR(st->reg))
+		regulator_disable(st->reg);
+error_put_reg:
+	if (!IS_ERR(st->reg))
+		regulator_put(st->reg);
+	iio_device_free(indio_dev);
+error_ret:
+
+	return ret;
+}
+
+static int __devexit ad5624r_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5624r_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5624r_id[] = {
+	{"ad5624r3", ID_AD5624R3},
+	{"ad5644r3", ID_AD5644R3},
+	{"ad5664r3", ID_AD5664R3},
+	{"ad5624r5", ID_AD5624R5},
+	{"ad5644r5", ID_AD5644R5},
+	{"ad5664r5", ID_AD5664R5},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5624r_id);
+
+static struct spi_driver ad5624r_driver = {
+	.driver = {
+		   .name = "ad5624r",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = ad5624r_probe,
+	.remove = __devexit_p(ad5624r_remove),
+	.id_table = ad5624r_id,
+};
+module_spi_driver(ad5624r_driver);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD5624/44/64R DAC spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
new file mode 100644
index 0000000..6948d75
--- /dev/null
+++ b/drivers/iio/dac/ad5686.c
@@ -0,0 +1,418 @@
+/*
+ * AD5686R, AD5685R, AD5684R Digital to analog converters  driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AD5686_DAC_CHANNELS			4
+
+#define AD5686_ADDR(x)				((x) << 16)
+#define AD5686_CMD(x)				((x) << 20)
+
+#define AD5686_ADDR_DAC(chan)		(0x1 << (chan))
+#define AD5686_ADDR_ALL_DAC			0xF
+
+#define AD5686_CMD_NOOP				0x0
+#define AD5686_CMD_WRITE_INPUT_N		0x1
+#define AD5686_CMD_UPDATE_DAC_N			0x2
+#define AD5686_CMD_WRITE_INPUT_N_UPDATE_N	0x3
+#define AD5686_CMD_POWERDOWN_DAC		0x4
+#define AD5686_CMD_LDAC_MASK			0x5
+#define AD5686_CMD_RESET			0x6
+#define AD5686_CMD_INTERNAL_REFER_SETUP		0x7
+#define AD5686_CMD_DAISY_CHAIN_ENABLE		0x8
+#define AD5686_CMD_READBACK_ENABLE		0x9
+
+#define AD5686_LDAC_PWRDN_NONE			0x0
+#define AD5686_LDAC_PWRDN_1K			0x1
+#define AD5686_LDAC_PWRDN_100K			0x2
+#define AD5686_LDAC_PWRDN_3STATE		0x3
+
+/**
+ * struct ad5686_chip_info - chip specific information
+ * @int_vref_mv:	AD5620/40/60: the internal reference voltage
+ * @channel:		channel specification
+*/
+
+struct ad5686_chip_info {
+	u16				int_vref_mv;
+	struct iio_chan_spec		channel[AD5686_DAC_CHANNELS];
+};
+
+/**
+ * struct ad5446_state - driver instance specific data
+ * @spi:		spi_device
+ * @chip_info:		chip model specific constants, available modes etc
+ * @reg:		supply regulator
+ * @vref_mv:		actual reference voltage used
+ * @pwr_down_mask:	power down mask
+ * @pwr_down_mode:	current power down mode
+ * @data:		spi transfer buffers
+ */
+
+struct ad5686_state {
+	struct spi_device		*spi;
+	const struct ad5686_chip_info	*chip_info;
+	struct regulator		*reg;
+	unsigned short			vref_mv;
+	unsigned			pwr_down_mask;
+	unsigned			pwr_down_mode;
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+
+	union {
+		u32 d32;
+		u8 d8[4];
+	} data[3] ____cacheline_aligned;
+};
+
+/**
+ * ad5686_supported_device_ids:
+ */
+
+enum ad5686_supported_device_ids {
+	ID_AD5684,
+	ID_AD5685,
+	ID_AD5686,
+};
+static int ad5686_spi_write(struct ad5686_state *st,
+			     u8 cmd, u8 addr, u16 val, u8 shift)
+{
+	val <<= shift;
+
+	st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
+			      AD5686_ADDR(addr) |
+			      val);
+
+	return spi_write(st->spi, &st->data[0].d8[1], 3);
+}
+
+static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
+{
+	struct spi_transfer t[] = {
+		{
+			.tx_buf = &st->data[0].d8[1],
+			.len = 3,
+			.cs_change = 1,
+		}, {
+			.tx_buf = &st->data[1].d8[1],
+			.rx_buf = &st->data[2].d8[1],
+			.len = 3,
+		},
+	};
+	struct spi_message m;
+	int ret;
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) |
+			      AD5686_ADDR(addr));
+	st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
+
+	ret = spi_sync(st->spi, &m);
+	if (ret < 0)
+		return ret;
+
+	return be32_to_cpu(st->data[2].d32);
+}
+
+static const char * const ad5686_powerdown_modes[] = {
+	"1kohm_to_gnd",
+	"100kohm_to_gnd",
+	"three_state"
+};
+
+static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5686_state *st = iio_priv(indio_dev);
+
+	return ((st->pwr_down_mode >> (chan->channel * 2)) & 0x3) - 1;
+}
+
+static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5686_state *st = iio_priv(indio_dev);
+
+	st->pwr_down_mode &= ~(0x3 << (chan->channel * 2));
+	st->pwr_down_mode |= ((mode + 1) << (chan->channel * 2));
+
+	return 0;
+}
+
+static const struct iio_enum ad5686_powerdown_mode_enum = {
+	.items = ad5686_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5686_powerdown_modes),
+	.get = ad5686_get_powerdown_mode,
+	.set = ad5686_set_powerdown_mode,
+};
+
+static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5686_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", !!(st->pwr_down_mask &
+			(0x3 << (chan->channel * 2))));
+}
+
+static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
+	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	 size_t len)
+{
+	bool readin;
+	int ret;
+	struct ad5686_state *st = iio_priv(indio_dev);
+
+	ret = strtobool(buf, &readin);
+	if (ret)
+		return ret;
+
+	if (readin == true)
+		st->pwr_down_mask |= (0x3 << (chan->channel * 2));
+	else
+		st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
+
+	ret = ad5686_spi_write(st, AD5686_CMD_POWERDOWN_DAC, 0,
+			       st->pwr_down_mask & st->pwr_down_mode, 0);
+
+	return ret ? ret : len;
+}
+
+static int ad5686_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5686_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+	int ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&indio_dev->mlock);
+		ret = ad5686_spi_read(st, chan->address);
+		mutex_unlock(&indio_dev->mlock);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = (st->vref_mv * 100000)
+			>> (chan->scan_type.realbits);
+		*val =  scale_uv / 100000;
+		*val2 = (scale_uv % 100000) * 10;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	}
+	return -EINVAL;
+}
+
+static int ad5686_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct ad5686_state *st = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val > (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		mutex_lock(&indio_dev->mlock);
+		ret = ad5686_spi_write(st,
+				 AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
+				 chan->address,
+				 val,
+				 chan->scan_type.shift);
+		mutex_unlock(&indio_dev->mlock);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct iio_info ad5686_info = {
+	.read_raw = ad5686_read_raw,
+	.write_raw = ad5686_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5686_read_dac_powerdown,
+		.write = ad5686_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", false, &ad5686_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5686_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5868_CHANNEL(chan, bits, shift) {			\
+		.type = IIO_VOLTAGE,				\
+		.indexed = 1,					\
+		.output = 1,					\
+		.channel = chan,				\
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,			\
+		.address = AD5686_ADDR_DAC(chan),			\
+		.scan_type = IIO_ST('u', bits, 16, shift),	\
+		.ext_info = ad5686_ext_info,			\
+}
+
+static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
+	[ID_AD5684] = {
+		.channel[0] = AD5868_CHANNEL(0, 12, 4),
+		.channel[1] = AD5868_CHANNEL(1, 12, 4),
+		.channel[2] = AD5868_CHANNEL(2, 12, 4),
+		.channel[3] = AD5868_CHANNEL(3, 12, 4),
+		.int_vref_mv = 2500,
+	},
+	[ID_AD5685] = {
+		.channel[0] = AD5868_CHANNEL(0, 14, 2),
+		.channel[1] = AD5868_CHANNEL(1, 14, 2),
+		.channel[2] = AD5868_CHANNEL(2, 14, 2),
+		.channel[3] = AD5868_CHANNEL(3, 14, 2),
+		.int_vref_mv = 2500,
+	},
+	[ID_AD5686] = {
+		.channel[0] = AD5868_CHANNEL(0, 16, 0),
+		.channel[1] = AD5868_CHANNEL(1, 16, 0),
+		.channel[2] = AD5868_CHANNEL(2, 16, 0),
+		.channel[3] = AD5868_CHANNEL(3, 16, 0),
+		.int_vref_mv = 2500,
+	},
+};
+
+
+static int __devinit ad5686_probe(struct spi_device *spi)
+{
+	struct ad5686_state *st;
+	struct iio_dev *indio_dev;
+	int ret, regdone = 0, voltage_uv = 0;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL)
+		return  -ENOMEM;
+
+	st = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+
+	st->reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(st->reg)) {
+		ret = regulator_enable(st->reg);
+		if (ret)
+			goto error_put_reg;
+
+		voltage_uv = regulator_get_voltage(st->reg);
+	}
+
+	st->chip_info =
+		&ad5686_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+	if (voltage_uv)
+		st->vref_mv = voltage_uv / 1000;
+	else
+		st->vref_mv = st->chip_info->int_vref_mv;
+
+	st->spi = spi;
+
+	/* Set all the power down mode for all channels to 1K pulldown */
+	st->pwr_down_mode = 0x55;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5686_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = st->chip_info->channel;
+	indio_dev->num_channels = AD5686_DAC_CHANNELS;
+
+	regdone = 1;
+	ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0,
+				!!voltage_uv, 0);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_disable_reg;
+
+	return 0;
+
+error_disable_reg:
+	if (!IS_ERR(st->reg))
+		regulator_disable(st->reg);
+error_put_reg:
+	if (!IS_ERR(st->reg))
+		regulator_put(st->reg);
+
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad5686_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5686_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5686_id[] = {
+	{"ad5684", ID_AD5684},
+	{"ad5685", ID_AD5685},
+	{"ad5686", ID_AD5686},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5686_id);
+
+static struct spi_driver ad5686_driver = {
+	.driver = {
+		   .name = "ad5686",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = ad5686_probe,
+	.remove = __devexit_p(ad5686_remove),
+	.id_table = ad5686_id,
+};
+module_spi_driver(ad5686_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c
new file mode 100644
index 0000000..ffce304
--- /dev/null
+++ b/drivers/iio/dac/ad5764.c
@@ -0,0 +1,382 @@
+/*
+ * Analog devices AD5764, AD5764R, AD5744, AD5744R quad-channel
+ * Digital to Analog Converters driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AD5764_REG_SF_NOP			0x0
+#define AD5764_REG_SF_CONFIG			0x1
+#define AD5764_REG_SF_CLEAR			0x4
+#define AD5764_REG_SF_LOAD			0x5
+#define AD5764_REG_DATA(x)			((2 << 3) | (x))
+#define AD5764_REG_COARSE_GAIN(x)		((3 << 3) | (x))
+#define AD5764_REG_FINE_GAIN(x)			((4 << 3) | (x))
+#define AD5764_REG_OFFSET(x)			((5 << 3) | (x))
+
+#define AD5764_NUM_CHANNELS 4
+
+/**
+ * struct ad5764_chip_info - chip specific information
+ * @int_vref:	Value of the internal reference voltage in uV - 0 if external
+ *		reference voltage is used
+ * @channel	channel specification
+*/
+
+struct ad5764_chip_info {
+	unsigned long int_vref;
+	const struct iio_chan_spec *channels;
+};
+
+/**
+ * struct ad5764_state - driver instance specific data
+ * @spi:		spi_device
+ * @chip_info:		chip info
+ * @vref_reg:		vref supply regulators
+ * @data:		spi transfer buffers
+ */
+
+struct ad5764_state {
+	struct spi_device		*spi;
+	const struct ad5764_chip_info	*chip_info;
+	struct regulator_bulk_data	vref_reg[2];
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	union {
+		__be32 d32;
+		u8 d8[4];
+	} data[2] ____cacheline_aligned;
+};
+
+enum ad5764_type {
+	ID_AD5744,
+	ID_AD5744R,
+	ID_AD5764,
+	ID_AD5764R,
+};
+
+#define AD5764_CHANNEL(_chan, _bits) {				\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.channel = (_chan),					\
+	.address = (_chan),					\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_OFFSET_SHARED_BIT |		\
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,		\
+	.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits))	\
+}
+
+#define DECLARE_AD5764_CHANNELS(_name, _bits) \
+const struct iio_chan_spec _name##_channels[] = { \
+	AD5764_CHANNEL(0, (_bits)), \
+	AD5764_CHANNEL(1, (_bits)), \
+	AD5764_CHANNEL(2, (_bits)), \
+	AD5764_CHANNEL(3, (_bits)), \
+};
+
+static DECLARE_AD5764_CHANNELS(ad5764, 16);
+static DECLARE_AD5764_CHANNELS(ad5744, 14);
+
+static const struct ad5764_chip_info ad5764_chip_infos[] = {
+	[ID_AD5744] = {
+		.int_vref = 0,
+		.channels = ad5744_channels,
+	},
+	[ID_AD5744R] = {
+		.int_vref = 5000000,
+		.channels = ad5744_channels,
+	},
+	[ID_AD5764] = {
+		.int_vref = 0,
+		.channels = ad5764_channels,
+	},
+	[ID_AD5764R] = {
+		.int_vref = 5000000,
+		.channels = ad5764_channels,
+	},
+};
+
+static int ad5764_write(struct iio_dev *indio_dev, unsigned int reg,
+	unsigned int val)
+{
+	struct ad5764_state *st = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	st->data[0].d32 = cpu_to_be32((reg << 16) | val);
+
+	ret = spi_write(st->spi, &st->data[0].d8[1], 3);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg,
+	unsigned int *val)
+{
+	struct ad5764_state *st = iio_priv(indio_dev);
+	struct spi_message m;
+	int ret;
+	struct spi_transfer t[] = {
+		{
+			.tx_buf = &st->data[0].d8[1],
+			.len = 3,
+			.cs_change = 1,
+		}, {
+			.rx_buf = &st->data[1].d8[1],
+			.len = 3,
+		},
+	};
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	mutex_lock(&indio_dev->mlock);
+
+	st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
+
+	ret = spi_sync(st->spi, &m);
+	if (ret >= 0)
+		*val = be32_to_cpu(st->data[1].d32) & 0xffff;
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5764_chan_info_to_reg(struct iio_chan_spec const *chan, long info)
+{
+	switch (info) {
+	case 0:
+		return AD5764_REG_DATA(chan->address);
+	case IIO_CHAN_INFO_CALIBBIAS:
+		return AD5764_REG_OFFSET(chan->address);
+	case IIO_CHAN_INFO_CALIBSCALE:
+		return AD5764_REG_FINE_GAIN(chan->address);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int ad5764_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long info)
+{
+	const int max_val = (1 << chan->scan_type.realbits);
+	unsigned int reg;
+
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+		val <<= chan->scan_type.shift;
+		break;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		if (val >= 128 || val < -128)
+			return -EINVAL;
+		break;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (val >= 32 || val < -32)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	reg = ad5764_chan_info_to_reg(chan, info);
+	return ad5764_write(indio_dev, reg, (u16)val);
+}
+
+static int ad5764_get_channel_vref(struct ad5764_state *st,
+	unsigned int channel)
+{
+	if (st->chip_info->int_vref)
+		return st->chip_info->int_vref;
+	else
+		return regulator_get_voltage(st->vref_reg[channel / 2].consumer);
+}
+
+static int ad5764_read_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int *val, int *val2, long info)
+{
+	struct ad5764_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+	unsigned int reg;
+	int vref;
+	int ret;
+
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+		reg = AD5764_REG_DATA(chan->address);
+		ret = ad5764_read(indio_dev, reg, val);
+		if (ret < 0)
+			return ret;
+		*val >>= chan->scan_type.shift;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		reg = AD5764_REG_OFFSET(chan->address);
+		ret = ad5764_read(indio_dev, reg, val);
+		if (ret < 0)
+			return ret;
+		*val = sign_extend32(*val, 7);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		reg = AD5764_REG_FINE_GAIN(chan->address);
+		ret = ad5764_read(indio_dev, reg, val);
+		if (ret < 0)
+			return ret;
+		*val = sign_extend32(*val, 5);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		/* vout = 4 * vref + ((dac_code / 65535) - 0.5) */
+		vref = ad5764_get_channel_vref(st, chan->channel);
+		if (vref < 0)
+			return vref;
+
+		scale_uv = (vref * 4 * 100) >> chan->scan_type.realbits;
+		*val = scale_uv / 100000;
+		*val2 = (scale_uv % 100000) * 10;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = -(1 << chan->scan_type.realbits) / 2;
+		return IIO_VAL_INT;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info ad5764_info = {
+	.read_raw = ad5764_read_raw,
+	.write_raw = ad5764_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad5764_probe(struct spi_device *spi)
+{
+	enum ad5764_type type = spi_get_device_id(spi)->driver_data;
+	struct iio_dev *indio_dev;
+	struct ad5764_state *st;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		dev_err(&spi->dev, "Failed to allocate iio device\n");
+		return -ENOMEM;
+	}
+
+	st = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+
+	st->spi = spi;
+	st->chip_info = &ad5764_chip_infos[type];
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5764_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->num_channels = AD5764_NUM_CHANNELS;
+	indio_dev->channels = st->chip_info->channels;
+
+	if (st->chip_info->int_vref == 0) {
+		st->vref_reg[0].supply = "vrefAB";
+		st->vref_reg[1].supply = "vrefCD";
+
+		ret = regulator_bulk_get(&st->spi->dev,
+			ARRAY_SIZE(st->vref_reg), st->vref_reg);
+		if (ret) {
+			dev_err(&spi->dev, "Failed to request vref regulators: %d\n",
+				ret);
+			goto error_free;
+		}
+
+		ret = regulator_bulk_enable(ARRAY_SIZE(st->vref_reg),
+			st->vref_reg);
+		if (ret) {
+			dev_err(&spi->dev, "Failed to enable vref regulators: %d\n",
+				ret);
+			goto error_free_reg;
+		}
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
+		goto error_disable_reg;
+	}
+
+	return 0;
+
+error_disable_reg:
+	if (st->chip_info->int_vref == 0)
+		regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
+error_free_reg:
+	if (st->chip_info->int_vref == 0)
+		regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
+error_free:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad5764_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5764_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	if (st->chip_info->int_vref == 0) {
+		regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
+		regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
+	}
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5764_ids[] = {
+	{ "ad5744", ID_AD5744 },
+	{ "ad5744r", ID_AD5744R },
+	{ "ad5764", ID_AD5764 },
+	{ "ad5764r", ID_AD5764R },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, ad5764_ids);
+
+static struct spi_driver ad5764_driver = {
+	.driver = {
+		.name = "ad5764",
+		.owner = THIS_MODULE,
+	},
+	.probe = ad5764_probe,
+	.remove = __devexit_p(ad5764_remove),
+	.id_table = ad5764_ids,
+};
+module_spi_driver(ad5764_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5744/AD5744R/AD5764/AD5764R DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
new file mode 100644
index 0000000..2bd2e37
--- /dev/null
+++ b/drivers/iio/dac/ad5791.c
@@ -0,0 +1,485 @@
+/*
+ * AD5760, AD5780, AD5781, AD5790, AD5791 Voltage Output Digital to Analog
+ * Converter
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/dac/ad5791.h>
+
+#define AD5791_RES_MASK(x)		((1 << (x)) - 1)
+#define AD5791_DAC_MASK			AD5791_RES_MASK(20)
+#define AD5791_DAC_MSB			(1 << 19)
+
+#define AD5791_CMD_READ			(1 << 23)
+#define AD5791_CMD_WRITE		(0 << 23)
+#define AD5791_ADDR(addr)		((addr) << 20)
+
+/* Registers */
+#define AD5791_ADDR_NOOP		0
+#define AD5791_ADDR_DAC0		1
+#define AD5791_ADDR_CTRL		2
+#define AD5791_ADDR_CLRCODE		3
+#define AD5791_ADDR_SW_CTRL		4
+
+/* Control Register */
+#define AD5791_CTRL_RBUF		(1 << 1)
+#define AD5791_CTRL_OPGND		(1 << 2)
+#define AD5791_CTRL_DACTRI		(1 << 3)
+#define AD5791_CTRL_BIN2SC		(1 << 4)
+#define AD5791_CTRL_SDODIS		(1 << 5)
+#define AD5761_CTRL_LINCOMP(x)		((x) << 6)
+
+#define AD5791_LINCOMP_0_10		0
+#define AD5791_LINCOMP_10_12		1
+#define AD5791_LINCOMP_12_16		2
+#define AD5791_LINCOMP_16_19		3
+#define AD5791_LINCOMP_19_20		12
+
+#define AD5780_LINCOMP_0_10		0
+#define AD5780_LINCOMP_10_20		12
+
+/* Software Control Register */
+#define AD5791_SWCTRL_LDAC		(1 << 0)
+#define AD5791_SWCTRL_CLR		(1 << 1)
+#define AD5791_SWCTRL_RESET		(1 << 2)
+
+#define AD5791_DAC_PWRDN_6K		0
+#define AD5791_DAC_PWRDN_3STATE		1
+
+/**
+ * struct ad5791_chip_info - chip specific information
+ * @get_lin_comp:	function pointer to the device specific function
+ */
+
+struct ad5791_chip_info {
+	int (*get_lin_comp)	(unsigned int span);
+};
+
+/**
+ * struct ad5791_state - driver instance specific data
+ * @us:			spi_device
+ * @reg_vdd:		positive supply regulator
+ * @reg_vss:		negative supply regulator
+ * @chip_info:		chip model specific constants
+ * @vref_mv:		actual reference voltage used
+ * @vref_neg_mv:	voltage of the negative supply
+ * @pwr_down_mode	current power down mode
+ */
+
+struct ad5791_state {
+	struct spi_device		*spi;
+	struct regulator		*reg_vdd;
+	struct regulator		*reg_vss;
+	const struct ad5791_chip_info	*chip_info;
+	unsigned short			vref_mv;
+	unsigned int			vref_neg_mv;
+	unsigned			ctrl;
+	unsigned			pwr_down_mode;
+	bool				pwr_down;
+};
+
+/**
+ * ad5791_supported_device_ids:
+ */
+
+enum ad5791_supported_device_ids {
+	ID_AD5760,
+	ID_AD5780,
+	ID_AD5781,
+	ID_AD5791,
+};
+
+static int ad5791_spi_write(struct spi_device *spi, u8 addr, u32 val)
+{
+	union {
+		u32 d32;
+		u8 d8[4];
+	} data;
+
+	data.d32 = cpu_to_be32(AD5791_CMD_WRITE |
+			      AD5791_ADDR(addr) |
+			      (val & AD5791_DAC_MASK));
+
+	return spi_write(spi, &data.d8[1], 3);
+}
+
+static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val)
+{
+	union {
+		u32 d32;
+		u8 d8[4];
+	} data[3];
+	int ret;
+	struct spi_message msg;
+	struct spi_transfer xfers[] = {
+		{
+			.tx_buf = &data[0].d8[1],
+			.bits_per_word = 8,
+			.len = 3,
+			.cs_change = 1,
+		}, {
+			.tx_buf = &data[1].d8[1],
+			.rx_buf = &data[2].d8[1],
+			.bits_per_word = 8,
+			.len = 3,
+		},
+	};
+
+	data[0].d32 = cpu_to_be32(AD5791_CMD_READ |
+			      AD5791_ADDR(addr));
+	data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP));
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfers[0], &msg);
+	spi_message_add_tail(&xfers[1], &msg);
+	ret = spi_sync(spi, &msg);
+
+	*val = be32_to_cpu(data[2].d32);
+
+	return ret;
+}
+
+static const char * const ad5791_powerdown_modes[] = {
+	"6kohm_to_gnd",
+	"three_state",
+};
+
+static int ad5791_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	return st->pwr_down_mode;
+}
+
+static int ad5791_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	st->pwr_down_mode = mode;
+
+	return 0;
+}
+
+static const struct iio_enum ad5791_powerdown_mode_enum = {
+	.items = ad5791_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5791_powerdown_modes),
+	.get = ad5791_get_powerdown_mode,
+	.set = ad5791_set_powerdown_mode,
+};
+
+static ssize_t ad5791_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", st->pwr_down);
+}
+
+static ssize_t ad5791_write_dac_powerdown(struct iio_dev *indio_dev,
+	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	 size_t len)
+{
+	bool pwr_down;
+	int ret;
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	if (!pwr_down) {
+		st->ctrl &= ~(AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
+	} else {
+		if (st->pwr_down_mode == AD5791_DAC_PWRDN_6K)
+			st->ctrl |= AD5791_CTRL_OPGND;
+		else if (st->pwr_down_mode == AD5791_DAC_PWRDN_3STATE)
+			st->ctrl |= AD5791_CTRL_DACTRI;
+	}
+	st->pwr_down = pwr_down;
+
+	ret = ad5791_spi_write(st->spi, AD5791_ADDR_CTRL, st->ctrl);
+
+	return ret ? ret : len;
+}
+
+static int ad5791_get_lin_comp(unsigned int span)
+{
+	if (span <= 10000)
+		return AD5791_LINCOMP_0_10;
+	else if (span <= 12000)
+		return AD5791_LINCOMP_10_12;
+	else if (span <= 16000)
+		return AD5791_LINCOMP_12_16;
+	else if (span <= 19000)
+		return AD5791_LINCOMP_16_19;
+	else
+		return AD5791_LINCOMP_19_20;
+}
+
+static int ad5780_get_lin_comp(unsigned int span)
+{
+	if (span <= 10000)
+		return AD5780_LINCOMP_0_10;
+	else
+		return AD5780_LINCOMP_10_20;
+}
+static const struct ad5791_chip_info ad5791_chip_info_tbl[] = {
+	[ID_AD5760] = {
+		.get_lin_comp = ad5780_get_lin_comp,
+	},
+	[ID_AD5780] = {
+		.get_lin_comp = ad5780_get_lin_comp,
+	},
+	[ID_AD5781] = {
+		.get_lin_comp = ad5791_get_lin_comp,
+	},
+	[ID_AD5791] = {
+		.get_lin_comp = ad5791_get_lin_comp,
+	},
+};
+
+static int ad5791_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5791_state *st = iio_priv(indio_dev);
+	u64 val64;
+	int ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		ret = ad5791_spi_read(st->spi, chan->address, val);
+		if (ret)
+			return ret;
+		*val &= AD5791_DAC_MASK;
+		*val >>= chan->scan_type.shift;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		*val2 = (((u64)st->vref_mv) * 1000000ULL) >> chan->scan_type.realbits;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_OFFSET:
+		val64 = (((u64)st->vref_neg_mv) << chan->scan_type.realbits);
+		do_div(val64, st->vref_mv);
+		*val = -val64;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+
+};
+
+static const struct iio_chan_spec_ext_info ad5791_ext_info[] = {
+	{
+		.name = "powerdown",
+		.shared = true,
+		.read = ad5791_read_dac_powerdown,
+		.write = ad5791_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", true, &ad5791_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5791_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5791_CHAN(bits, shift) {			\
+	.type = IIO_VOLTAGE,				\
+	.output = 1,					\
+	.indexed = 1,					\
+	.address = AD5791_ADDR_DAC0,			\
+	.channel = 0,					\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |	\
+		IIO_CHAN_INFO_OFFSET_SHARED_BIT,	\
+	.scan_type = IIO_ST('u', bits, 24, shift),	\
+	.ext_info = ad5791_ext_info,			\
+}
+
+static const struct iio_chan_spec ad5791_channels[] = {
+	[ID_AD5760] = AD5791_CHAN(16, 4),
+	[ID_AD5780] = AD5791_CHAN(18, 2),
+	[ID_AD5781] = AD5791_CHAN(18, 2),
+	[ID_AD5791] = AD5791_CHAN(20, 0)
+};
+
+static int ad5791_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val,
+			    int val2,
+			    long mask)
+{
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		val &= AD5791_RES_MASK(chan->scan_type.realbits);
+		val <<= chan->scan_type.shift;
+
+		return ad5791_spi_write(st->spi, chan->address, val);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info ad5791_info = {
+	.read_raw = &ad5791_read_raw,
+	.write_raw = &ad5791_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad5791_probe(struct spi_device *spi)
+{
+	struct ad5791_platform_data *pdata = spi->dev.platform_data;
+	struct iio_dev *indio_dev;
+	struct ad5791_state *st;
+	int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	st = iio_priv(indio_dev);
+	st->reg_vdd = regulator_get(&spi->dev, "vdd");
+	if (!IS_ERR(st->reg_vdd)) {
+		ret = regulator_enable(st->reg_vdd);
+		if (ret)
+			goto error_put_reg_pos;
+
+		pos_voltage_uv = regulator_get_voltage(st->reg_vdd);
+	}
+
+	st->reg_vss = regulator_get(&spi->dev, "vss");
+	if (!IS_ERR(st->reg_vss)) {
+		ret = regulator_enable(st->reg_vss);
+		if (ret)
+			goto error_put_reg_neg;
+
+		neg_voltage_uv = regulator_get_voltage(st->reg_vss);
+	}
+
+	st->pwr_down = true;
+	st->spi = spi;
+
+	if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) {
+		st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000;
+		st->vref_neg_mv = neg_voltage_uv / 1000;
+	} else if (pdata) {
+		st->vref_mv = pdata->vref_pos_mv + pdata->vref_neg_mv;
+		st->vref_neg_mv = pdata->vref_neg_mv;
+	} else {
+		dev_warn(&spi->dev, "reference voltage unspecified\n");
+	}
+
+	ret = ad5791_spi_write(spi, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET);
+	if (ret)
+		goto error_disable_reg_neg;
+
+	st->chip_info =	&ad5791_chip_info_tbl[spi_get_device_id(spi)
+					      ->driver_data];
+
+
+	st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv))
+		  | ((pdata && pdata->use_rbuf_gain2) ? 0 : AD5791_CTRL_RBUF) |
+		  AD5791_CTRL_BIN2SC;
+
+	ret = ad5791_spi_write(spi, AD5791_ADDR_CTRL, st->ctrl |
+		AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
+	if (ret)
+		goto error_disable_reg_neg;
+
+	spi_set_drvdata(spi, indio_dev);
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->info = &ad5791_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels
+		= &ad5791_channels[spi_get_device_id(spi)->driver_data];
+	indio_dev->num_channels = 1;
+	indio_dev->name = spi_get_device_id(st->spi)->name;
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_disable_reg_neg;
+
+	return 0;
+
+error_disable_reg_neg:
+	if (!IS_ERR(st->reg_vss))
+		regulator_disable(st->reg_vss);
+error_put_reg_neg:
+	if (!IS_ERR(st->reg_vss))
+		regulator_put(st->reg_vss);
+
+	if (!IS_ERR(st->reg_vdd))
+		regulator_disable(st->reg_vdd);
+error_put_reg_pos:
+	if (!IS_ERR(st->reg_vdd))
+		regulator_put(st->reg_vdd);
+	iio_device_free(indio_dev);
+error_ret:
+
+	return ret;
+}
+
+static int __devexit ad5791_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (!IS_ERR(st->reg_vdd)) {
+		regulator_disable(st->reg_vdd);
+		regulator_put(st->reg_vdd);
+	}
+
+	if (!IS_ERR(st->reg_vss)) {
+		regulator_disable(st->reg_vss);
+		regulator_put(st->reg_vss);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5791_id[] = {
+	{"ad5760", ID_AD5760},
+	{"ad5780", ID_AD5780},
+	{"ad5781", ID_AD5781},
+	{"ad5790", ID_AD5791},
+	{"ad5791", ID_AD5791},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5791_id);
+
+static struct spi_driver ad5791_driver = {
+	.driver = {
+		   .name = "ad5791",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = ad5791_probe,
+	.remove = __devexit_p(ad5791_remove),
+	.id_table = ad5791_id,
+};
+module_spi_driver(ad5791_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
new file mode 100644
index 0000000..c3d748c
--- /dev/null
+++ b/drivers/iio/dac/max517.c
@@ -0,0 +1,242 @@
+/*
+ *  max517.c - Support for Maxim MAX517, MAX518 and MAX519
+ *
+ *  Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/dac/max517.h>
+
+#define MAX517_DRV_NAME	"max517"
+
+/* Commands */
+#define COMMAND_CHANNEL0	0x00
+#define COMMAND_CHANNEL1	0x01 /* for MAX518 and MAX519 */
+#define COMMAND_PD		0x08 /* Power Down */
+
+enum max517_device_ids {
+	ID_MAX517,
+	ID_MAX518,
+	ID_MAX519,
+};
+
+struct max517_data {
+	struct i2c_client	*client;
+	unsigned short		vref_mv[2];
+};
+
+/*
+ * channel: bit 0: channel 1
+ *          bit 1: channel 2
+ * (this way, it's possible to set both channels at once)
+ */
+static int max517_set_value(struct iio_dev *indio_dev,
+	long val, int channel)
+{
+	struct max517_data *data = iio_priv(indio_dev);
+	struct i2c_client *client = data->client;
+	u8 outbuf[2];
+	int res;
+
+	if (val < 0 || val > 255)
+		return -EINVAL;
+
+	outbuf[0] = channel;
+	outbuf[1] = val;
+
+	res = i2c_master_send(client, outbuf, 2);
+	if (res < 0)
+		return res;
+	else if (res != 2)
+		return -EIO;
+	else
+		return 0;
+}
+
+static int max517_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct max517_data *data = iio_priv(indio_dev);
+	unsigned int scale_uv;
+
+	switch (m) {
+	case IIO_CHAN_INFO_SCALE:
+		/* Corresponds to Vref / 2^(bits) */
+		scale_uv = (data->vref_mv[chan->channel] * 1000) >> 8;
+		*val =  scale_uv / 1000000;
+		*val2 = scale_uv % 1000000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int max517_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = max517_set_value(indio_dev, val, chan->channel);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max517_suspend(struct device *dev)
+{
+	u8 outbuf = COMMAND_PD;
+
+	return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
+}
+
+static int max517_resume(struct device *dev)
+{
+	u8 outbuf = 0;
+
+	return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
+}
+
+static SIMPLE_DEV_PM_OPS(max517_pm_ops, max517_suspend, max517_resume);
+#define MAX517_PM_OPS (&max517_pm_ops)
+#else
+#define MAX517_PM_OPS NULL
+#endif
+
+static const struct iio_info max517_info = {
+	.read_raw = max517_read_raw,
+	.write_raw = max517_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+#define MAX517_CHANNEL(chan) {				\
+	.type = IIO_VOLTAGE,				\
+	.indexed = 1,					\
+	.output = 1,					\
+	.channel = (chan),				\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+	IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
+	.scan_type = IIO_ST('u', 8, 8, 0),		\
+}
+
+static const struct iio_chan_spec max517_channels[] = {
+	MAX517_CHANNEL(0),
+	MAX517_CHANNEL(1)
+};
+
+static int __devinit max517_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct max517_data *data;
+	struct iio_dev *indio_dev;
+	struct max517_platform_data *platform_data = client->dev.platform_data;
+	int err;
+
+	indio_dev = iio_device_alloc(sizeof(*data));
+	if (indio_dev == NULL) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+
+	/* establish that the iio_dev is a child of the i2c device */
+	indio_dev->dev.parent = &client->dev;
+
+	/* reduced channel set for MAX517 */
+	if (id->driver_data == ID_MAX517)
+		indio_dev->num_channels = 1;
+	else
+		indio_dev->num_channels = 2;
+	indio_dev->channels = max517_channels;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &max517_info;
+
+	/*
+	 * Reference voltage on MAX518 and default is 5V, else take vref_mv
+	 * from platform_data
+	 */
+	if (id->driver_data == ID_MAX518 || !platform_data) {
+		data->vref_mv[0] = data->vref_mv[1] = 5000; /* mV */
+	} else {
+		data->vref_mv[0] = platform_data->vref_mv[0];
+		data->vref_mv[1] = platform_data->vref_mv[1];
+	}
+
+	err = iio_device_register(indio_dev);
+	if (err)
+		goto exit_free_device;
+
+	dev_info(&client->dev, "DAC registered\n");
+
+	return 0;
+
+exit_free_device:
+	iio_device_free(indio_dev);
+exit:
+	return err;
+}
+
+static int __devexit max517_remove(struct i2c_client *client)
+{
+	iio_device_unregister(i2c_get_clientdata(client));
+	iio_device_free(i2c_get_clientdata(client));
+
+	return 0;
+}
+
+static const struct i2c_device_id max517_id[] = {
+	{ "max517", ID_MAX517 },
+	{ "max518", ID_MAX518 },
+	{ "max519", ID_MAX519 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max517_id);
+
+static struct i2c_driver max517_driver = {
+	.driver = {
+		.name	= MAX517_DRV_NAME,
+		.pm		= MAX517_PM_OPS,
+	},
+	.probe		= max517_probe,
+	.remove		=  __devexit_p(max517_remove),
+	.id_table	= max517_id,
+};
+module_i2c_driver(max517_driver);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("MAX517/MAX518/MAX519 8-bit DAC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c
new file mode 100644
index 0000000..e0e168b
--- /dev/null
+++ b/drivers/iio/dac/mcp4725.c
@@ -0,0 +1,227 @@
+/*
+ * mcp4725.c - Support for Microchip MCP4725
+ *
+ * Copyright (C) 2012 Peter Meerwald <pmeerw@pmeerw.net>
+ *
+ * Based on max517 by Roland Stigge <stigge@antcom.de>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * driver for the Microchip I2C 12-bit digital-to-analog converter (DAC)
+ * (7-bit I2C slave address 0x60, the three LSBs can be configured in
+ * hardware)
+ *
+ * writing the DAC value to EEPROM is not supported
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include <linux/iio/dac/mcp4725.h>
+
+#define MCP4725_DRV_NAME "mcp4725"
+
+struct mcp4725_data {
+	struct i2c_client *client;
+	u16 vref_mv;
+	u16 dac_value;
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int mcp4725_suspend(struct device *dev)
+{
+	u8 outbuf[2];
+
+	outbuf[0] = 0x3 << 4; /* power-down bits, 500 kOhm resistor */
+	outbuf[1] = 0;
+
+	return i2c_master_send(to_i2c_client(dev), outbuf, 2);
+}
+
+static int mcp4725_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct mcp4725_data *data = iio_priv(indio_dev);
+	u8 outbuf[2];
+
+	/* restore previous DAC value */
+	outbuf[0] = (data->dac_value >> 8) & 0xf;
+	outbuf[1] = data->dac_value & 0xff;
+
+	return i2c_master_send(to_i2c_client(dev), outbuf, 2);
+}
+
+static SIMPLE_DEV_PM_OPS(mcp4725_pm_ops, mcp4725_suspend, mcp4725_resume);
+#define MCP4725_PM_OPS (&mcp4725_pm_ops)
+#else
+#define MCP4725_PM_OPS NULL
+#endif
+
+static const struct iio_chan_spec mcp4725_channel = {
+	.type		= IIO_VOLTAGE,
+	.indexed	= 1,
+	.output		= 1,
+	.channel	= 0,
+	.info_mask	= IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			  IIO_CHAN_INFO_SCALE_SHARED_BIT,
+	.scan_type	= IIO_ST('u', 12, 16, 0),
+};
+
+static int mcp4725_set_value(struct iio_dev *indio_dev, int val)
+{
+	struct mcp4725_data *data = iio_priv(indio_dev);
+	u8 outbuf[2];
+	int ret;
+
+	if (val >= (1 << 12) || val < 0)
+		return -EINVAL;
+
+	outbuf[0] = (val >> 8) & 0xf;
+	outbuf[1] = val & 0xff;
+
+	ret = i2c_master_send(data->client, outbuf, 2);
+	if (ret < 0)
+		return ret;
+	else if (ret != 2)
+		return -EIO;
+	else
+		return 0;
+}
+
+static int mcp4725_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long mask)
+{
+	struct mcp4725_data *data = iio_priv(indio_dev);
+	unsigned long scale_uv;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		*val = data->dac_value;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = (data->vref_mv * 1000) >> 12;
+		*val =  scale_uv / 1000000;
+		*val2 = scale_uv % 1000000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+	return -EINVAL;
+}
+
+static int mcp4725_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val, int val2, long mask)
+{
+	struct mcp4725_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = mcp4725_set_value(indio_dev, val);
+		data->dac_value = val;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static const struct iio_info mcp4725_info = {
+	.read_raw = mcp4725_read_raw,
+	.write_raw = mcp4725_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit mcp4725_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct mcp4725_data *data;
+	struct iio_dev *indio_dev;
+	struct mcp4725_platform_data *platform_data = client->dev.platform_data;
+	u8 inbuf[3];
+	int err;
+
+	if (!platform_data || !platform_data->vref_mv) {
+		dev_err(&client->dev, "invalid platform data");
+		err = -EINVAL;
+		goto exit;
+	}
+
+	indio_dev = iio_device_alloc(sizeof(*data));
+	if (indio_dev == NULL) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &mcp4725_info;
+	indio_dev->channels = &mcp4725_channel;
+	indio_dev->num_channels = 1;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	data->vref_mv = platform_data->vref_mv;
+
+	/* read current DAC value */
+	err = i2c_master_recv(client, inbuf, 3);
+	if (err < 0) {
+		dev_err(&client->dev, "failed to read DAC value");
+		goto exit_free_device;
+	}
+	data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4);
+
+	err = iio_device_register(indio_dev);
+	if (err)
+		goto exit_free_device;
+
+	dev_info(&client->dev, "MCP4725 DAC registered\n");
+
+	return 0;
+
+exit_free_device:
+	iio_device_free(indio_dev);
+exit:
+	return err;
+}
+
+static int __devexit mcp4725_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id mcp4725_id[] = {
+	{ "mcp4725", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mcp4725_id);
+
+static struct i2c_driver mcp4725_driver = {
+	.driver = {
+		.name	= MCP4725_DRV_NAME,
+		.pm	= MCP4725_PM_OPS,
+	},
+	.probe		= mcp4725_probe,
+	.remove		= __devexit_p(mcp4725_remove),
+	.id_table	= mcp4725_id,
+};
+module_i2c_driver(mcp4725_driver);
+
+MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
+MODULE_DESCRIPTION("MCP4725 12-bit DAC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig
new file mode 100644
index 0000000..6aaa33e
--- /dev/null
+++ b/drivers/iio/frequency/Kconfig
@@ -0,0 +1,41 @@
+#
+# Frequency
+#	Direct Digital Synthesis drivers (DDS)
+#	Clock Distribution device drivers
+#	Phase-Locked Loop (PLL) frequency synthesizers
+#
+
+menu "Frequency Synthesizers DDS/PLL"
+
+menu "Clock Generator/Distribution"
+
+config AD9523
+	tristate "Analog Devices AD9523 Low Jitter Clock Generator"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD9523 Low Jitter
+	  Clock Generator. The driver provides direct access via sysfs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad9523.
+
+endmenu
+
+#
+# Phase-Locked Loop (PLL) frequency synthesizers
+#
+
+menu "Phase-Locked Loop (PLL) frequency synthesizers"
+
+config ADF4350
+	tristate "Analog Devices ADF4350/ADF4351 Wideband Synthesizers"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices  ADF4350/ADF4351
+	  Wideband Synthesizers. The driver provides direct access via sysfs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adf4350.
+
+endmenu
+endmenu
diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile
new file mode 100644
index 0000000..00d26e5
--- /dev/null
+++ b/drivers/iio/frequency/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile iio/frequency
+#
+
+obj-$(CONFIG_AD9523) += ad9523.o
+obj-$(CONFIG_ADF4350) += adf4350.o
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
new file mode 100644
index 0000000..b737c64
--- /dev/null
+++ b/drivers/iio/frequency/ad9523.c
@@ -0,0 +1,1059 @@
+/*
+ * AD9523 SPI Low Jitter Clock Generator
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/frequency/ad9523.h>
+
+#define AD9523_READ	(1 << 15)
+#define AD9523_WRITE	(0 << 15)
+#define AD9523_CNT(x)	(((x) - 1) << 13)
+#define AD9523_ADDR(x)	((x) & 0xFFF)
+
+#define AD9523_R1B	(1 << 16)
+#define AD9523_R2B	(2 << 16)
+#define AD9523_R3B	(3 << 16)
+#define AD9523_TRANSF_LEN(x)			((x) >> 16)
+
+#define AD9523_SERIAL_PORT_CONFIG		(AD9523_R1B | 0x0)
+#define AD9523_VERSION_REGISTER			(AD9523_R1B | 0x2)
+#define AD9523_PART_REGISTER			(AD9523_R1B | 0x3)
+#define AD9523_READBACK_CTRL			(AD9523_R1B | 0x4)
+
+#define AD9523_EEPROM_CUSTOMER_VERSION_ID	(AD9523_R2B | 0x6)
+
+#define AD9523_PLL1_REF_A_DIVIDER		(AD9523_R2B | 0x11)
+#define AD9523_PLL1_REF_B_DIVIDER		(AD9523_R2B | 0x13)
+#define AD9523_PLL1_REF_TEST_DIVIDER		(AD9523_R1B | 0x14)
+#define AD9523_PLL1_FEEDBACK_DIVIDER		(AD9523_R2B | 0x17)
+#define AD9523_PLL1_CHARGE_PUMP_CTRL		(AD9523_R2B | 0x19)
+#define AD9523_PLL1_INPUT_RECEIVERS_CTRL	(AD9523_R1B | 0x1A)
+#define AD9523_PLL1_REF_CTRL			(AD9523_R1B | 0x1B)
+#define AD9523_PLL1_MISC_CTRL			(AD9523_R1B | 0x1C)
+#define AD9523_PLL1_LOOP_FILTER_CTRL		(AD9523_R1B | 0x1D)
+
+#define AD9523_PLL2_CHARGE_PUMP			(AD9523_R1B | 0xF0)
+#define AD9523_PLL2_FEEDBACK_DIVIDER_AB		(AD9523_R1B | 0xF1)
+#define AD9523_PLL2_CTRL			(AD9523_R1B | 0xF2)
+#define AD9523_PLL2_VCO_CTRL			(AD9523_R1B | 0xF3)
+#define AD9523_PLL2_VCO_DIVIDER			(AD9523_R1B | 0xF4)
+#define AD9523_PLL2_LOOP_FILTER_CTRL		(AD9523_R2B | 0xF6)
+#define AD9523_PLL2_R2_DIVIDER			(AD9523_R1B | 0xF7)
+
+#define AD9523_CHANNEL_CLOCK_DIST(ch)		(AD9523_R3B | (0x192 + 3 * ch))
+
+#define AD9523_PLL1_OUTPUT_CTRL			(AD9523_R1B | 0x1BA)
+#define AD9523_PLL1_OUTPUT_CHANNEL_CTRL		(AD9523_R1B | 0x1BB)
+
+#define AD9523_READBACK_0			(AD9523_R1B | 0x22C)
+#define AD9523_READBACK_1			(AD9523_R1B | 0x22D)
+
+#define AD9523_STATUS_SIGNALS			(AD9523_R3B | 0x232)
+#define AD9523_POWER_DOWN_CTRL			(AD9523_R1B | 0x233)
+#define AD9523_IO_UPDATE			(AD9523_R1B | 0x234)
+
+#define AD9523_EEPROM_DATA_XFER_STATUS		(AD9523_R1B | 0xB00)
+#define AD9523_EEPROM_ERROR_READBACK		(AD9523_R1B | 0xB01)
+#define AD9523_EEPROM_CTRL1			(AD9523_R1B | 0xB02)
+#define AD9523_EEPROM_CTRL2			(AD9523_R1B | 0xB03)
+
+/* AD9523_SERIAL_PORT_CONFIG */
+
+#define AD9523_SER_CONF_SDO_ACTIVE		(1 << 7)
+#define AD9523_SER_CONF_SOFT_RESET		(1 << 5)
+
+/* AD9523_READBACK_CTRL */
+#define AD9523_READBACK_CTRL_READ_BUFFERED	(1 << 0)
+
+/* AD9523_PLL1_CHARGE_PUMP_CTRL */
+#define AD9523_PLL1_CHARGE_PUMP_CURRENT_nA(x)	(((x) / 500) & 0x7F)
+#define AD9523_PLL1_CHARGE_PUMP_TRISTATE	(1 << 7)
+#define AD9523_PLL1_CHARGE_PUMP_MODE_NORMAL	(3 << 8)
+#define AD9523_PLL1_CHARGE_PUMP_MODE_PUMP_DOWN	(2 << 8)
+#define AD9523_PLL1_CHARGE_PUMP_MODE_PUMP_UP	(1 << 8)
+#define AD9523_PLL1_CHARGE_PUMP_MODE_TRISTATE	(0 << 8)
+#define AD9523_PLL1_BACKLASH_PW_MIN		(0 << 10)
+#define AD9523_PLL1_BACKLASH_PW_LOW		(1 << 10)
+#define AD9523_PLL1_BACKLASH_PW_HIGH		(2 << 10)
+#define AD9523_PLL1_BACKLASH_PW_MAX		(3 << 10)
+
+/* AD9523_PLL1_INPUT_RECEIVERS_CTRL */
+#define AD9523_PLL1_REF_TEST_RCV_EN		(1 << 7)
+#define AD9523_PLL1_REFB_DIFF_RCV_EN		(1 << 6)
+#define AD9523_PLL1_REFA_DIFF_RCV_EN		(1 << 5)
+#define AD9523_PLL1_REFB_RCV_EN			(1 << 4)
+#define AD9523_PLL1_REFA_RCV_EN			(1 << 3)
+#define AD9523_PLL1_REFA_REFB_PWR_CTRL_EN	(1 << 2)
+#define AD9523_PLL1_OSC_IN_CMOS_NEG_INP_EN	(1 << 1)
+#define AD9523_PLL1_OSC_IN_DIFF_EN		(1 << 0)
+
+/* AD9523_PLL1_REF_CTRL */
+#define AD9523_PLL1_BYPASS_REF_TEST_DIV_EN	(1 << 7)
+#define AD9523_PLL1_BYPASS_FEEDBACK_DIV_EN	(1 << 6)
+#define AD9523_PLL1_ZERO_DELAY_MODE_INT		(1 << 5)
+#define AD9523_PLL1_ZERO_DELAY_MODE_EXT		(0 << 5)
+#define AD9523_PLL1_OSC_IN_PLL_FEEDBACK_EN	(1 << 4)
+#define AD9523_PLL1_ZD_IN_CMOS_NEG_INP_EN	(1 << 3)
+#define AD9523_PLL1_ZD_IN_DIFF_EN		(1 << 2)
+#define AD9523_PLL1_REFB_CMOS_NEG_INP_EN	(1 << 1)
+#define AD9523_PLL1_REFA_CMOS_NEG_INP_EN	(1 << 0)
+
+/* AD9523_PLL1_MISC_CTRL */
+#define AD9523_PLL1_REFB_INDEP_DIV_CTRL_EN	(1 << 7)
+#define AD9523_PLL1_OSC_CTRL_FAIL_VCC_BY2_EN	(1 << 6)
+#define AD9523_PLL1_REF_MODE(x)			((x) << 2)
+#define AD9523_PLL1_BYPASS_REFB_DIV		(1 << 1)
+#define AD9523_PLL1_BYPASS_REFA_DIV		(1 << 0)
+
+/* AD9523_PLL1_LOOP_FILTER_CTRL */
+#define AD9523_PLL1_LOOP_FILTER_RZERO(x)	((x) & 0xF)
+
+/* AD9523_PLL2_CHARGE_PUMP */
+#define AD9523_PLL2_CHARGE_PUMP_CURRENT_nA(x)	((x) / 3500)
+
+/* AD9523_PLL2_FEEDBACK_DIVIDER_AB */
+#define AD9523_PLL2_FB_NDIV_A_CNT(x)		(((x) & 0x3) << 6)
+#define AD9523_PLL2_FB_NDIV_B_CNT(x)		(((x) & 0x3F) << 0)
+#define AD9523_PLL2_FB_NDIV(a, b)		(4 * (b) + (a))
+
+/* AD9523_PLL2_CTRL */
+#define AD9523_PLL2_CHARGE_PUMP_MODE_NORMAL	(3 << 0)
+#define AD9523_PLL2_CHARGE_PUMP_MODE_PUMP_DOWN	(2 << 0)
+#define AD9523_PLL2_CHARGE_PUMP_MODE_PUMP_UP	(1 << 0)
+#define AD9523_PLL2_CHARGE_PUMP_MODE_TRISTATE	(0 << 0)
+#define AD9523_PLL2_BACKLASH_PW_MIN		(0 << 2)
+#define AD9523_PLL2_BACKLASH_PW_LOW		(1 << 2)
+#define AD9523_PLL2_BACKLASH_PW_HIGH		(2 << 2)
+#define AD9523_PLL2_BACKLASH_PW_MAX		(3 << 1)
+#define AD9523_PLL2_BACKLASH_CTRL_EN		(1 << 4)
+#define AD9523_PLL2_FREQ_DOUBLER_EN		(1 << 5)
+#define AD9523_PLL2_LOCK_DETECT_PWR_DOWN_EN	(1 << 7)
+
+/* AD9523_PLL2_VCO_CTRL */
+#define AD9523_PLL2_VCO_CALIBRATE		(1 << 1)
+#define AD9523_PLL2_FORCE_VCO_MIDSCALE		(1 << 2)
+#define AD9523_PLL2_FORCE_REFERENCE_VALID	(1 << 3)
+#define AD9523_PLL2_FORCE_RELEASE_SYNC		(1 << 4)
+
+/* AD9523_PLL2_VCO_DIVIDER */
+#define AD9523_PLL2_VCO_DIV_M1(x)		((((x) - 3) & 0x3) << 0)
+#define AD9523_PLL2_VCO_DIV_M2(x)		((((x) - 3) & 0x3) << 4)
+#define AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN	(1 << 2)
+#define AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN	(1 << 6)
+
+/* AD9523_PLL2_LOOP_FILTER_CTRL */
+#define AD9523_PLL2_LOOP_FILTER_CPOLE1(x)	(((x) & 0x7) << 0)
+#define AD9523_PLL2_LOOP_FILTER_RZERO(x)	(((x) & 0x7) << 3)
+#define AD9523_PLL2_LOOP_FILTER_RPOLE2(x)	(((x) & 0x7) << 6)
+#define AD9523_PLL2_LOOP_FILTER_RZERO_BYPASS_EN	(1 << 8)
+
+/* AD9523_PLL2_R2_DIVIDER */
+#define AD9523_PLL2_R2_DIVIDER_VAL(x)		(((x) & 0x1F) << 0)
+
+/* AD9523_CHANNEL_CLOCK_DIST */
+#define AD9523_CLK_DIST_DIV_PHASE(x)		(((x) & 0x3F) << 18)
+#define AD9523_CLK_DIST_DIV_PHASE_REV(x)	((ret >> 18) & 0x3F)
+#define AD9523_CLK_DIST_DIV(x)			((((x) - 1) & 0x3FF) << 8)
+#define AD9523_CLK_DIST_DIV_REV(x)		(((ret >> 8) & 0x3FF) + 1)
+#define AD9523_CLK_DIST_INV_DIV_OUTPUT_EN	(1 << 7)
+#define AD9523_CLK_DIST_IGNORE_SYNC_EN		(1 << 6)
+#define AD9523_CLK_DIST_PWR_DOWN_EN		(1 << 5)
+#define AD9523_CLK_DIST_LOW_PWR_MODE_EN		(1 << 4)
+#define AD9523_CLK_DIST_DRIVER_MODE(x)		(((x) & 0xF) << 0)
+
+/* AD9523_PLL1_OUTPUT_CTRL */
+#define AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH6_M2	(1 << 7)
+#define AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH5_M2	(1 << 6)
+#define AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH4_M2	(1 << 5)
+#define AD9523_PLL1_OUTP_CTRL_CMOS_DRV_WEAK		(1 << 4)
+#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_1		(0 << 0)
+#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_2		(1 << 0)
+#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_4		(2 << 0)
+#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_8		(4 << 0)
+#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_16		(8 << 0)
+
+/* AD9523_PLL1_OUTPUT_CHANNEL_CTRL */
+#define AD9523_PLL1_OUTP_CH_CTRL_OUTPUT_PWR_DOWN_EN	(1 << 7)
+#define AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH9_M2	(1 << 6)
+#define AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH8_M2	(1 << 5)
+#define AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH7_M2	(1 << 4)
+#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH3	(1 << 3)
+#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH2	(1 << 2)
+#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH1	(1 << 1)
+#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH0	(1 << 0)
+
+/* AD9523_READBACK_0 */
+#define AD9523_READBACK_0_STAT_PLL2_REF_CLK		(1 << 7)
+#define AD9523_READBACK_0_STAT_PLL2_FB_CLK		(1 << 6)
+#define AD9523_READBACK_0_STAT_VCXO			(1 << 5)
+#define AD9523_READBACK_0_STAT_REF_TEST			(1 << 4)
+#define AD9523_READBACK_0_STAT_REFB			(1 << 3)
+#define AD9523_READBACK_0_STAT_REFA			(1 << 2)
+#define AD9523_READBACK_0_STAT_PLL2_LD			(1 << 1)
+#define AD9523_READBACK_0_STAT_PLL1_LD			(1 << 0)
+
+/* AD9523_READBACK_1 */
+#define AD9523_READBACK_1_HOLDOVER_ACTIVE		(1 << 3)
+#define AD9523_READBACK_1_AUTOMODE_SEL_REFB		(1 << 2)
+#define AD9523_READBACK_1_VCO_CALIB_IN_PROGRESS		(1 << 0)
+
+/* AD9523_STATUS_SIGNALS */
+#define AD9523_STATUS_SIGNALS_SYNC_MAN_CTRL		(1 << 16)
+#define AD9523_STATUS_MONITOR_01_PLL12_LOCKED		(0x302)
+/* AD9523_POWER_DOWN_CTRL */
+#define AD9523_POWER_DOWN_CTRL_PLL1_PWR_DOWN		(1 << 2)
+#define AD9523_POWER_DOWN_CTRL_PLL2_PWR_DOWN		(1 << 1)
+#define AD9523_POWER_DOWN_CTRL_DIST_PWR_DOWN		(1 << 0)
+
+/* AD9523_IO_UPDATE */
+#define AD9523_IO_UPDATE_EN				(1 << 0)
+
+/* AD9523_EEPROM_DATA_XFER_STATUS */
+#define AD9523_EEPROM_DATA_XFER_IN_PROGRESS		(1 << 0)
+
+/* AD9523_EEPROM_ERROR_READBACK */
+#define AD9523_EEPROM_ERROR_READBACK_FAIL		(1 << 0)
+
+/* AD9523_EEPROM_CTRL1 */
+#define AD9523_EEPROM_CTRL1_SOFT_EEPROM			(1 << 1)
+#define AD9523_EEPROM_CTRL1_EEPROM_WRITE_PROT_DIS	(1 << 0)
+
+/* AD9523_EEPROM_CTRL2 */
+#define AD9523_EEPROM_CTRL2_REG2EEPROM			(1 << 0)
+
+#define AD9523_NUM_CHAN					14
+#define AD9523_NUM_CHAN_ALT_CLK_SRC			10
+
+/* Helpers to avoid excess line breaks */
+#define AD_IFE(_pde, _a, _b) ((pdata->_pde) ? _a : _b)
+#define AD_IF(_pde, _a) AD_IFE(_pde, _a, 0)
+
+enum {
+	AD9523_STAT_PLL1_LD,
+	AD9523_STAT_PLL2_LD,
+	AD9523_STAT_REFA,
+	AD9523_STAT_REFB,
+	AD9523_STAT_REF_TEST,
+	AD9523_STAT_VCXO,
+	AD9523_STAT_PLL2_FB_CLK,
+	AD9523_STAT_PLL2_REF_CLK,
+	AD9523_SYNC,
+	AD9523_EEPROM,
+};
+
+enum {
+	AD9523_VCO1,
+	AD9523_VCO2,
+	AD9523_VCXO,
+	AD9523_NUM_CLK_SRC,
+};
+
+struct ad9523_state {
+	struct spi_device		*spi;
+	struct regulator		*reg;
+	struct ad9523_platform_data	*pdata;
+	struct iio_chan_spec		ad9523_channels[AD9523_NUM_CHAN];
+
+	unsigned long		vcxo_freq;
+	unsigned long		vco_freq;
+	unsigned long		vco_out_freq[AD9523_NUM_CLK_SRC];
+	unsigned char		vco_out_map[AD9523_NUM_CHAN_ALT_CLK_SRC];
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	union {
+		__be32 d32;
+		u8 d8[4];
+	} data[2] ____cacheline_aligned;
+};
+
+static int ad9523_read(struct iio_dev *indio_dev, unsigned addr)
+{
+	struct ad9523_state *st = iio_priv(indio_dev);
+	struct spi_message m;
+	int ret;
+
+	/* We encode the register size 1..3 bytes into the register address.
+	 * On transfer we get the size from the register datum, and make sure
+	 * the result is properly aligned.
+	 */
+
+	struct spi_transfer t[] = {
+		{
+			.tx_buf = &st->data[0].d8[2],
+			.len = 2,
+		}, {
+			.rx_buf = &st->data[1].d8[4 - AD9523_TRANSF_LEN(addr)],
+			.len = AD9523_TRANSF_LEN(addr),
+		},
+	};
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	st->data[0].d32 = cpu_to_be32(AD9523_READ |
+				      AD9523_CNT(AD9523_TRANSF_LEN(addr)) |
+				      AD9523_ADDR(addr));
+
+	ret = spi_sync(st->spi, &m);
+	if (ret < 0)
+		dev_err(&indio_dev->dev, "read failed (%d)", ret);
+	else
+		ret = be32_to_cpu(st->data[1].d32) & (0xFFFFFF >>
+				  (8 * (3 - AD9523_TRANSF_LEN(addr))));
+
+	return ret;
+};
+
+static int ad9523_write(struct iio_dev *indio_dev, unsigned addr, unsigned val)
+{
+	struct ad9523_state *st = iio_priv(indio_dev);
+	struct spi_message m;
+	int ret;
+	struct spi_transfer t[] = {
+		{
+			.tx_buf = &st->data[0].d8[2],
+			.len = 2,
+		}, {
+			.tx_buf = &st->data[1].d8[4 - AD9523_TRANSF_LEN(addr)],
+			.len = AD9523_TRANSF_LEN(addr),
+		},
+	};
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	st->data[0].d32 = cpu_to_be32(AD9523_WRITE |
+				      AD9523_CNT(AD9523_TRANSF_LEN(addr)) |
+				      AD9523_ADDR(addr));
+	st->data[1].d32 = cpu_to_be32(val);
+
+	ret = spi_sync(st->spi, &m);
+
+	if (ret < 0)
+		dev_err(&indio_dev->dev, "write failed (%d)", ret);
+
+	return ret;
+}
+
+static int ad9523_io_update(struct iio_dev *indio_dev)
+{
+	return ad9523_write(indio_dev, AD9523_IO_UPDATE, AD9523_IO_UPDATE_EN);
+}
+
+static int ad9523_vco_out_map(struct iio_dev *indio_dev,
+			      unsigned ch, unsigned out)
+{
+	struct ad9523_state *st = iio_priv(indio_dev);
+	int ret;
+	unsigned mask;
+
+	switch (ch) {
+	case 0 ... 3:
+		ret = ad9523_read(indio_dev, AD9523_PLL1_OUTPUT_CHANNEL_CTRL);
+		if (ret < 0)
+			break;
+		mask = AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH0 << ch;
+		if (out) {
+			ret |= mask;
+			out = 2;
+		} else {
+			ret &= ~mask;
+		}
+		ret = ad9523_write(indio_dev,
+				   AD9523_PLL1_OUTPUT_CHANNEL_CTRL, ret);
+		break;
+	case 4 ... 6:
+		ret = ad9523_read(indio_dev, AD9523_PLL1_OUTPUT_CTRL);
+		if (ret < 0)
+			break;
+		mask = AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH4_M2 << (ch - 4);
+		if (out)
+			ret |= mask;
+		else
+			ret &= ~mask;
+		ret = ad9523_write(indio_dev, AD9523_PLL1_OUTPUT_CTRL, ret);
+		break;
+	case 7 ... 9:
+		ret = ad9523_read(indio_dev, AD9523_PLL1_OUTPUT_CHANNEL_CTRL);
+		if (ret < 0)
+			break;
+		mask = AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH7_M2 << (ch - 7);
+		if (out)
+			ret |= mask;
+		else
+			ret &= ~mask;
+		ret = ad9523_write(indio_dev,
+				   AD9523_PLL1_OUTPUT_CHANNEL_CTRL, ret);
+		break;
+	default:
+		return 0;
+	}
+
+	st->vco_out_map[ch] = out;
+
+	return ret;
+}
+
+static int ad9523_set_clock_provider(struct iio_dev *indio_dev,
+			      unsigned ch, unsigned long freq)
+{
+	struct ad9523_state *st = iio_priv(indio_dev);
+	long tmp1, tmp2;
+	bool use_alt_clk_src;
+
+	switch (ch) {
+	case 0 ... 3:
+		use_alt_clk_src = (freq == st->vco_out_freq[AD9523_VCXO]);
+		break;
+	case 4 ... 9:
+		tmp1 = st->vco_out_freq[AD9523_VCO1] / freq;
+		tmp2 = st->vco_out_freq[AD9523_VCO2] / freq;
+		tmp1 *= freq;
+		tmp2 *= freq;
+		use_alt_clk_src = (abs(tmp1 - freq) > abs(tmp2 - freq));
+		break;
+	default:
+		/* Ch 10..14: No action required, return success */
+		return 0;
+	}
+
+	return ad9523_vco_out_map(indio_dev, ch, use_alt_clk_src);
+}
+
+static int ad9523_store_eeprom(struct iio_dev *indio_dev)
+{
+	int ret, tmp;
+
+	ret = ad9523_write(indio_dev, AD9523_EEPROM_CTRL1,
+			   AD9523_EEPROM_CTRL1_EEPROM_WRITE_PROT_DIS);
+	if (ret < 0)
+		return ret;
+	ret = ad9523_write(indio_dev, AD9523_EEPROM_CTRL2,
+			   AD9523_EEPROM_CTRL2_REG2EEPROM);
+	if (ret < 0)
+		return ret;
+
+	tmp = 4;
+	do {
+		msleep(16);
+		ret = ad9523_read(indio_dev,
+				  AD9523_EEPROM_DATA_XFER_STATUS);
+		if (ret < 0)
+			return ret;
+	} while ((ret & AD9523_EEPROM_DATA_XFER_IN_PROGRESS) && tmp--);
+
+	ret = ad9523_write(indio_dev, AD9523_EEPROM_CTRL1, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_read(indio_dev, AD9523_EEPROM_ERROR_READBACK);
+	if (ret < 0)
+		return ret;
+
+	if (ret & AD9523_EEPROM_ERROR_READBACK_FAIL) {
+		dev_err(&indio_dev->dev, "Verify EEPROM failed");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int ad9523_sync(struct iio_dev *indio_dev)
+{
+	int ret, tmp;
+
+	ret = ad9523_read(indio_dev, AD9523_STATUS_SIGNALS);
+	if (ret < 0)
+		return ret;
+
+	tmp = ret;
+	tmp |= AD9523_STATUS_SIGNALS_SYNC_MAN_CTRL;
+
+	ret = ad9523_write(indio_dev, AD9523_STATUS_SIGNALS, tmp);
+	if (ret < 0)
+		return ret;
+
+	ad9523_io_update(indio_dev);
+	tmp &= ~AD9523_STATUS_SIGNALS_SYNC_MAN_CTRL;
+
+	ret = ad9523_write(indio_dev, AD9523_STATUS_SIGNALS, tmp);
+	if (ret < 0)
+		return ret;
+
+	return ad9523_io_update(indio_dev);
+}
+
+static ssize_t ad9523_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	bool state;
+	int ret;
+
+	ret = strtobool(buf, &state);
+	if (ret < 0)
+		return ret;
+
+	if (!state)
+		return 0;
+
+	mutex_lock(&indio_dev->mlock);
+	switch ((u32)this_attr->address) {
+	case AD9523_SYNC:
+		ret = ad9523_sync(indio_dev);
+		break;
+	case AD9523_EEPROM:
+		ret = ad9523_store_eeprom(indio_dev);
+		break;
+	default:
+		ret = -ENODEV;
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret ? ret : len;
+}
+
+static ssize_t ad9523_show(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	ret = ad9523_read(indio_dev, AD9523_READBACK_0);
+	if (ret >= 0) {
+		ret = sprintf(buf, "%d\n", !!(ret & (1 <<
+			(u32)this_attr->address)));
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static IIO_DEVICE_ATTR(pll1_locked, S_IRUGO,
+			ad9523_show,
+			NULL,
+			AD9523_STAT_PLL1_LD);
+
+static IIO_DEVICE_ATTR(pll2_locked, S_IRUGO,
+			ad9523_show,
+			NULL,
+			AD9523_STAT_PLL2_LD);
+
+static IIO_DEVICE_ATTR(pll1_reference_clk_a_present, S_IRUGO,
+			ad9523_show,
+			NULL,
+			AD9523_STAT_REFA);
+
+static IIO_DEVICE_ATTR(pll1_reference_clk_b_present, S_IRUGO,
+			ad9523_show,
+			NULL,
+			AD9523_STAT_REFB);
+
+static IIO_DEVICE_ATTR(pll1_reference_clk_test_present, S_IRUGO,
+			ad9523_show,
+			NULL,
+			AD9523_STAT_REF_TEST);
+
+static IIO_DEVICE_ATTR(vcxo_clk_present, S_IRUGO,
+			ad9523_show,
+			NULL,
+			AD9523_STAT_VCXO);
+
+static IIO_DEVICE_ATTR(pll2_feedback_clk_present, S_IRUGO,
+			ad9523_show,
+			NULL,
+			AD9523_STAT_PLL2_FB_CLK);
+
+static IIO_DEVICE_ATTR(pll2_reference_clk_present, S_IRUGO,
+			ad9523_show,
+			NULL,
+			AD9523_STAT_PLL2_REF_CLK);
+
+static IIO_DEVICE_ATTR(sync_dividers, S_IWUSR,
+			NULL,
+			ad9523_store,
+			AD9523_SYNC);
+
+static IIO_DEVICE_ATTR(store_eeprom, S_IWUSR,
+			NULL,
+			ad9523_store,
+			AD9523_EEPROM);
+
+static struct attribute *ad9523_attributes[] = {
+	&iio_dev_attr_sync_dividers.dev_attr.attr,
+	&iio_dev_attr_store_eeprom.dev_attr.attr,
+	&iio_dev_attr_pll2_feedback_clk_present.dev_attr.attr,
+	&iio_dev_attr_pll2_reference_clk_present.dev_attr.attr,
+	&iio_dev_attr_pll1_reference_clk_a_present.dev_attr.attr,
+	&iio_dev_attr_pll1_reference_clk_b_present.dev_attr.attr,
+	&iio_dev_attr_pll1_reference_clk_test_present.dev_attr.attr,
+	&iio_dev_attr_vcxo_clk_present.dev_attr.attr,
+	&iio_dev_attr_pll1_locked.dev_attr.attr,
+	&iio_dev_attr_pll2_locked.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ad9523_attribute_group = {
+	.attrs = ad9523_attributes,
+};
+
+static int ad9523_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad9523_state *st = iio_priv(indio_dev);
+	unsigned code;
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel));
+	mutex_unlock(&indio_dev->mlock);
+
+	if (ret < 0)
+		return ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		*val = !(ret & AD9523_CLK_DIST_PWR_DOWN_EN);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_FREQUENCY:
+		*val = st->vco_out_freq[st->vco_out_map[chan->channel]] /
+			AD9523_CLK_DIST_DIV_REV(ret);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_PHASE:
+		code = (AD9523_CLK_DIST_DIV_PHASE_REV(ret) * 3141592) /
+			AD9523_CLK_DIST_DIV_REV(ret);
+		*val = code / 1000000;
+		*val2 = (code % 1000000) * 10;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+};
+
+static int ad9523_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val,
+			    int val2,
+			    long mask)
+{
+	struct ad9523_state *st = iio_priv(indio_dev);
+	unsigned reg;
+	int ret, tmp, code;
+
+	mutex_lock(&indio_dev->mlock);
+	ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel));
+	if (ret < 0)
+		goto out;
+
+	reg = ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val)
+			reg &= ~AD9523_CLK_DIST_PWR_DOWN_EN;
+		else
+			reg |= AD9523_CLK_DIST_PWR_DOWN_EN;
+		break;
+	case IIO_CHAN_INFO_FREQUENCY:
+		if (val <= 0) {
+			ret = -EINVAL;
+			goto out;
+		}
+		ret = ad9523_set_clock_provider(indio_dev, chan->channel, val);
+		if (ret < 0)
+			goto out;
+		tmp = st->vco_out_freq[st->vco_out_map[chan->channel]] / val;
+		tmp = clamp(tmp, 1, 1024);
+		reg &= ~(0x3FF << 8);
+		reg |= AD9523_CLK_DIST_DIV(tmp);
+		break;
+	case IIO_CHAN_INFO_PHASE:
+		code = val * 1000000 + val2 % 1000000;
+		tmp = (code * AD9523_CLK_DIST_DIV_REV(ret)) / 3141592;
+		tmp = clamp(tmp, 0, 63);
+		reg &= ~AD9523_CLK_DIST_DIV_PHASE(~0);
+		reg |= AD9523_CLK_DIST_DIV_PHASE(tmp);
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = ad9523_write(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel),
+			   reg);
+	if (ret < 0)
+		goto out;
+
+	ad9523_io_update(indio_dev);
+out:
+	mutex_unlock(&indio_dev->mlock);
+	return ret;
+}
+
+static int ad9523_reg_access(struct iio_dev *indio_dev,
+			      unsigned reg, unsigned writeval,
+			      unsigned *readval)
+{
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	if (readval == NULL) {
+		ret = ad9523_write(indio_dev, reg | AD9523_R1B, writeval);
+		ad9523_io_update(indio_dev);
+	} else {
+		ret = ad9523_read(indio_dev, reg | AD9523_R1B);
+		if (ret < 0)
+			goto out_unlock;
+		*readval = ret;
+		ret = 0;
+	}
+
+out_unlock:
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static const struct iio_info ad9523_info = {
+	.read_raw = &ad9523_read_raw,
+	.write_raw = &ad9523_write_raw,
+	.debugfs_reg_access = &ad9523_reg_access,
+	.attrs = &ad9523_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static int ad9523_setup(struct iio_dev *indio_dev)
+{
+	struct ad9523_state *st = iio_priv(indio_dev);
+	struct ad9523_platform_data *pdata = st->pdata;
+	struct ad9523_channel_spec *chan;
+	unsigned long active_mask = 0;
+	int ret, i;
+
+	ret = ad9523_write(indio_dev, AD9523_SERIAL_PORT_CONFIG,
+			   AD9523_SER_CONF_SOFT_RESET |
+			  (st->spi->mode & SPI_3WIRE ? 0 :
+			  AD9523_SER_CONF_SDO_ACTIVE));
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_READBACK_CTRL,
+			  AD9523_READBACK_CTRL_READ_BUFFERED);
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_io_update(indio_dev);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * PLL1 Setup
+	 */
+	ret = ad9523_write(indio_dev, AD9523_PLL1_REF_A_DIVIDER,
+		pdata->refa_r_div);
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL1_REF_B_DIVIDER,
+		pdata->refb_r_div);
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL1_FEEDBACK_DIVIDER,
+		pdata->pll1_feedback_div);
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL1_CHARGE_PUMP_CTRL,
+		AD9523_PLL1_CHARGE_PUMP_CURRENT_nA(pdata->
+			pll1_charge_pump_current_nA) |
+		AD9523_PLL1_CHARGE_PUMP_MODE_NORMAL |
+		AD9523_PLL1_BACKLASH_PW_MIN);
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL1_INPUT_RECEIVERS_CTRL,
+		AD_IF(refa_diff_rcv_en, AD9523_PLL1_REFA_RCV_EN) |
+		AD_IF(refb_diff_rcv_en, AD9523_PLL1_REFB_RCV_EN) |
+		AD_IF(osc_in_diff_en, AD9523_PLL1_OSC_IN_DIFF_EN) |
+		AD_IF(osc_in_cmos_neg_inp_en,
+		      AD9523_PLL1_OSC_IN_CMOS_NEG_INP_EN) |
+		AD_IF(refa_diff_rcv_en, AD9523_PLL1_REFA_DIFF_RCV_EN) |
+		AD_IF(refb_diff_rcv_en, AD9523_PLL1_REFB_DIFF_RCV_EN));
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL1_REF_CTRL,
+		AD_IF(zd_in_diff_en, AD9523_PLL1_ZD_IN_DIFF_EN) |
+		AD_IF(zd_in_cmos_neg_inp_en,
+		      AD9523_PLL1_ZD_IN_CMOS_NEG_INP_EN) |
+		AD_IF(zero_delay_mode_internal_en,
+		      AD9523_PLL1_ZERO_DELAY_MODE_INT) |
+		AD_IF(osc_in_feedback_en, AD9523_PLL1_OSC_IN_PLL_FEEDBACK_EN) |
+		AD_IF(refa_cmos_neg_inp_en, AD9523_PLL1_REFA_CMOS_NEG_INP_EN) |
+		AD_IF(refb_cmos_neg_inp_en, AD9523_PLL1_REFB_CMOS_NEG_INP_EN));
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL1_MISC_CTRL,
+		AD9523_PLL1_REFB_INDEP_DIV_CTRL_EN |
+		AD9523_PLL1_REF_MODE(pdata->ref_mode));
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL1_LOOP_FILTER_CTRL,
+		AD9523_PLL1_LOOP_FILTER_RZERO(pdata->pll1_loop_filter_rzero));
+	if (ret < 0)
+		return ret;
+	/*
+	 * PLL2 Setup
+	 */
+
+	ret = ad9523_write(indio_dev, AD9523_PLL2_CHARGE_PUMP,
+		AD9523_PLL2_CHARGE_PUMP_CURRENT_nA(pdata->
+			pll2_charge_pump_current_nA));
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL2_FEEDBACK_DIVIDER_AB,
+		AD9523_PLL2_FB_NDIV_A_CNT(pdata->pll2_ndiv_a_cnt) |
+		AD9523_PLL2_FB_NDIV_B_CNT(pdata->pll2_ndiv_b_cnt));
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL2_CTRL,
+		AD9523_PLL2_CHARGE_PUMP_MODE_NORMAL |
+		AD9523_PLL2_BACKLASH_CTRL_EN |
+		AD_IF(pll2_freq_doubler_en, AD9523_PLL2_FREQ_DOUBLER_EN));
+	if (ret < 0)
+		return ret;
+
+	st->vco_freq = (pdata->vcxo_freq * (pdata->pll2_freq_doubler_en ? 2 : 1)
+			/ pdata->pll2_r2_div) * AD9523_PLL2_FB_NDIV(pdata->
+			pll2_ndiv_a_cnt, pdata->pll2_ndiv_b_cnt);
+
+	ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_CTRL,
+		AD9523_PLL2_VCO_CALIBRATE);
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_DIVIDER,
+		AD9523_PLL2_VCO_DIV_M1(pdata->pll2_vco_diff_m1) |
+		AD9523_PLL2_VCO_DIV_M2(pdata->pll2_vco_diff_m2) |
+		AD_IFE(pll2_vco_diff_m1, 0,
+		       AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN) |
+		AD_IFE(pll2_vco_diff_m2, 0,
+		       AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN));
+	if (ret < 0)
+		return ret;
+
+	if (pdata->pll2_vco_diff_m1)
+		st->vco_out_freq[AD9523_VCO1] =
+			st->vco_freq / pdata->pll2_vco_diff_m1;
+
+	if (pdata->pll2_vco_diff_m2)
+		st->vco_out_freq[AD9523_VCO2] =
+			st->vco_freq / pdata->pll2_vco_diff_m2;
+
+	st->vco_out_freq[AD9523_VCXO] = pdata->vcxo_freq;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL2_R2_DIVIDER,
+		AD9523_PLL2_R2_DIVIDER_VAL(pdata->pll2_r2_div));
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_PLL2_LOOP_FILTER_CTRL,
+		AD9523_PLL2_LOOP_FILTER_CPOLE1(pdata->cpole1) |
+		AD9523_PLL2_LOOP_FILTER_RZERO(pdata->rzero) |
+		AD9523_PLL2_LOOP_FILTER_RPOLE2(pdata->rpole2) |
+		AD_IF(rzero_bypass_en,
+		      AD9523_PLL2_LOOP_FILTER_RZERO_BYPASS_EN));
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < pdata->num_channels; i++) {
+		chan = &pdata->channels[i];
+		if (chan->channel_num < AD9523_NUM_CHAN) {
+			__set_bit(chan->channel_num, &active_mask);
+			ret = ad9523_write(indio_dev,
+				AD9523_CHANNEL_CLOCK_DIST(chan->channel_num),
+				AD9523_CLK_DIST_DRIVER_MODE(chan->driver_mode) |
+				AD9523_CLK_DIST_DIV(chan->channel_divider) |
+				AD9523_CLK_DIST_DIV_PHASE(chan->divider_phase) |
+				(chan->sync_ignore_en ?
+					AD9523_CLK_DIST_IGNORE_SYNC_EN : 0) |
+				(chan->divider_output_invert_en ?
+					AD9523_CLK_DIST_INV_DIV_OUTPUT_EN : 0) |
+				(chan->low_power_mode_en ?
+					AD9523_CLK_DIST_LOW_PWR_MODE_EN : 0) |
+				(chan->output_dis ?
+					AD9523_CLK_DIST_PWR_DOWN_EN : 0));
+			if (ret < 0)
+				return ret;
+
+			ret = ad9523_vco_out_map(indio_dev, chan->channel_num,
+					   chan->use_alt_clock_src);
+			if (ret < 0)
+				return ret;
+
+			st->ad9523_channels[i].type = IIO_ALTVOLTAGE;
+			st->ad9523_channels[i].output = 1;
+			st->ad9523_channels[i].indexed = 1;
+			st->ad9523_channels[i].channel = chan->channel_num;
+			st->ad9523_channels[i].extend_name =
+				chan->extended_name;
+			st->ad9523_channels[i].info_mask =
+				IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+				IIO_CHAN_INFO_PHASE_SEPARATE_BIT |
+				IIO_CHAN_INFO_FREQUENCY_SEPARATE_BIT;
+		}
+	}
+
+	for_each_clear_bit(i, &active_mask, AD9523_NUM_CHAN)
+		ad9523_write(indio_dev,
+			     AD9523_CHANNEL_CLOCK_DIST(i),
+			     AD9523_CLK_DIST_DRIVER_MODE(TRISTATE) |
+			     AD9523_CLK_DIST_PWR_DOWN_EN);
+
+	ret = ad9523_write(indio_dev, AD9523_POWER_DOWN_CTRL, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_write(indio_dev, AD9523_STATUS_SIGNALS,
+			   AD9523_STATUS_MONITOR_01_PLL12_LOCKED);
+	if (ret < 0)
+		return ret;
+
+	ret = ad9523_io_update(indio_dev);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int __devinit ad9523_probe(struct spi_device *spi)
+{
+	struct ad9523_platform_data *pdata = spi->dev.platform_data;
+	struct iio_dev *indio_dev;
+	struct ad9523_state *st;
+	int ret;
+
+	if (!pdata) {
+		dev_err(&spi->dev, "no platform data?\n");
+		return -EINVAL;
+	}
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL)
+		return -ENOMEM;
+
+	st = iio_priv(indio_dev);
+
+	st->reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(st->reg)) {
+		ret = regulator_enable(st->reg);
+		if (ret)
+			goto error_put_reg;
+	}
+
+	spi_set_drvdata(spi, indio_dev);
+	st->spi = spi;
+	st->pdata = pdata;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = (pdata->name[0] != 0) ? pdata->name :
+			  spi_get_device_id(spi)->name;
+	indio_dev->info = &ad9523_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = st->ad9523_channels;
+	indio_dev->num_channels = pdata->num_channels;
+
+	ret = ad9523_setup(indio_dev);
+	if (ret < 0)
+		goto error_disable_reg;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_disable_reg;
+
+	dev_info(&spi->dev, "probed %s\n", indio_dev->name);
+
+	return 0;
+
+error_disable_reg:
+	if (!IS_ERR(st->reg))
+		regulator_disable(st->reg);
+error_put_reg:
+	if (!IS_ERR(st->reg))
+		regulator_put(st->reg);
+
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad9523_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad9523_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad9523_id[] = {
+	{"ad9523-1", 9523},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad9523_id);
+
+static struct spi_driver ad9523_driver = {
+	.driver = {
+		.name	= "ad9523",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad9523_probe,
+	.remove		= __devexit_p(ad9523_remove),
+	.id_table	= ad9523_id,
+};
+module_spi_driver(ad9523_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD9523 CLOCKDIST/PLL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
new file mode 100644
index 0000000..59fbb3ae
--- /dev/null
+++ b/drivers/iio/frequency/adf4350.c
@@ -0,0 +1,480 @@
+/*
+ * ADF4350/ADF4351 SPI Wideband Synthesizer driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <asm/div64.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/frequency/adf4350.h>
+
+enum {
+	ADF4350_FREQ,
+	ADF4350_FREQ_REFIN,
+	ADF4350_FREQ_RESOLUTION,
+	ADF4350_PWRDOWN,
+};
+
+struct adf4350_state {
+	struct spi_device		*spi;
+	struct regulator		*reg;
+	struct adf4350_platform_data	*pdata;
+	unsigned long			clkin;
+	unsigned long			chspc; /* Channel Spacing */
+	unsigned long			fpfd; /* Phase Frequency Detector */
+	unsigned long			min_out_freq;
+	unsigned			r0_fract;
+	unsigned			r0_int;
+	unsigned			r1_mod;
+	unsigned			r4_rf_div_sel;
+	unsigned long			regs[6];
+	unsigned long			regs_hw[6];
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	__be32				val ____cacheline_aligned;
+};
+
+static struct adf4350_platform_data default_pdata = {
+	.clkin = 122880000,
+	.channel_spacing = 10000,
+	.r2_user_settings = ADF4350_REG2_PD_POLARITY_POS |
+			    ADF4350_REG2_CHARGE_PUMP_CURR_uA(2500),
+	.r3_user_settings = ADF4350_REG3_12BIT_CLKDIV_MODE(0),
+	.r4_user_settings = ADF4350_REG4_OUTPUT_PWR(3) |
+			    ADF4350_REG4_MUTE_TILL_LOCK_EN,
+	.gpio_lock_detect = -1,
+};
+
+static int adf4350_sync_config(struct adf4350_state *st)
+{
+	int ret, i, doublebuf = 0;
+
+	for (i = ADF4350_REG5; i >= ADF4350_REG0; i--) {
+		if ((st->regs_hw[i] != st->regs[i]) ||
+			((i == ADF4350_REG0) && doublebuf)) {
+
+			switch (i) {
+			case ADF4350_REG1:
+			case ADF4350_REG4:
+				doublebuf = 1;
+				break;
+			}
+
+			st->val  = cpu_to_be32(st->regs[i] | i);
+			ret = spi_write(st->spi, &st->val, 4);
+			if (ret < 0)
+				return ret;
+			st->regs_hw[i] = st->regs[i];
+			dev_dbg(&st->spi->dev, "[%d] 0x%X\n",
+				i, (u32)st->regs[i] | i);
+		}
+	}
+	return 0;
+}
+
+static int adf4350_reg_access(struct iio_dev *indio_dev,
+			      unsigned reg, unsigned writeval,
+			      unsigned *readval)
+{
+	struct adf4350_state *st = iio_priv(indio_dev);
+	int ret;
+
+	if (reg > ADF4350_REG5)
+		return -EINVAL;
+
+	mutex_lock(&indio_dev->mlock);
+	if (readval == NULL) {
+		st->regs[reg] = writeval & ~(BIT(0) | BIT(1) | BIT(2));
+		ret = adf4350_sync_config(st);
+	} else {
+		*readval =  st->regs_hw[reg];
+		ret = 0;
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int adf4350_tune_r_cnt(struct adf4350_state *st, unsigned short r_cnt)
+{
+	struct adf4350_platform_data *pdata = st->pdata;
+
+	do {
+		r_cnt++;
+		st->fpfd = (st->clkin * (pdata->ref_doubler_en ? 2 : 1)) /
+			   (r_cnt * (pdata->ref_div2_en ? 2 : 1));
+	} while (st->fpfd > ADF4350_MAX_FREQ_PFD);
+
+	return r_cnt;
+}
+
+static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
+{
+	struct adf4350_platform_data *pdata = st->pdata;
+	u64 tmp;
+	u32 div_gcd, prescaler;
+	u16 mdiv, r_cnt = 0;
+	u8 band_sel_div;
+
+	if (freq > ADF4350_MAX_OUT_FREQ || freq < st->min_out_freq)
+		return -EINVAL;
+
+	if (freq > ADF4350_MAX_FREQ_45_PRESC) {
+		prescaler = ADF4350_REG1_PRESCALER;
+		mdiv = 75;
+	} else {
+		prescaler = 0;
+		mdiv = 23;
+	}
+
+	st->r4_rf_div_sel = 0;
+
+	while (freq < ADF4350_MIN_VCO_FREQ) {
+		freq <<= 1;
+		st->r4_rf_div_sel++;
+	}
+
+	/*
+	 * Allow a predefined reference division factor
+	 * if not set, compute our own
+	 */
+	if (pdata->ref_div_factor)
+		r_cnt = pdata->ref_div_factor - 1;
+
+	do  {
+		r_cnt = adf4350_tune_r_cnt(st, r_cnt);
+
+		st->r1_mod = st->fpfd / st->chspc;
+		while (st->r1_mod > ADF4350_MAX_MODULUS) {
+			r_cnt = adf4350_tune_r_cnt(st, r_cnt);
+			st->r1_mod = st->fpfd / st->chspc;
+		}
+
+		tmp = freq * (u64)st->r1_mod + (st->fpfd > 1);
+		do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */
+		st->r0_fract = do_div(tmp, st->r1_mod);
+		st->r0_int = tmp;
+	} while (mdiv > st->r0_int);
+
+	band_sel_div = DIV_ROUND_UP(st->fpfd, ADF4350_MAX_BANDSEL_CLK);
+
+	if (st->r0_fract && st->r1_mod) {
+		div_gcd = gcd(st->r1_mod, st->r0_fract);
+		st->r1_mod /= div_gcd;
+		st->r0_fract /= div_gcd;
+	} else {
+		st->r0_fract = 0;
+		st->r1_mod = 1;
+	}
+
+	dev_dbg(&st->spi->dev, "VCO: %llu Hz, PFD %lu Hz\n"
+		"REF_DIV %d, R0_INT %d, R0_FRACT %d\n"
+		"R1_MOD %d, RF_DIV %d\nPRESCALER %s, BAND_SEL_DIV %d\n",
+		freq, st->fpfd, r_cnt, st->r0_int, st->r0_fract, st->r1_mod,
+		1 << st->r4_rf_div_sel, prescaler ? "8/9" : "4/5",
+		band_sel_div);
+
+	st->regs[ADF4350_REG0] = ADF4350_REG0_INT(st->r0_int) |
+				 ADF4350_REG0_FRACT(st->r0_fract);
+
+	st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(0) |
+				 ADF4350_REG1_MOD(st->r1_mod) |
+				 prescaler;
+
+	st->regs[ADF4350_REG2] =
+		ADF4350_REG2_10BIT_R_CNT(r_cnt) |
+		ADF4350_REG2_DOUBLE_BUFF_EN |
+		(pdata->ref_doubler_en ? ADF4350_REG2_RMULT2_EN : 0) |
+		(pdata->ref_div2_en ? ADF4350_REG2_RDIV2_EN : 0) |
+		(pdata->r2_user_settings & (ADF4350_REG2_PD_POLARITY_POS |
+		ADF4350_REG2_LDP_6ns | ADF4350_REG2_LDF_INT_N |
+		ADF4350_REG2_CHARGE_PUMP_CURR_uA(5000) |
+		ADF4350_REG2_MUXOUT(0x7) | ADF4350_REG2_NOISE_MODE(0x9)));
+
+	st->regs[ADF4350_REG3] = pdata->r3_user_settings &
+				 (ADF4350_REG3_12BIT_CLKDIV(0xFFF) |
+				 ADF4350_REG3_12BIT_CLKDIV_MODE(0x3) |
+				 ADF4350_REG3_12BIT_CSR_EN |
+				 ADF4351_REG3_CHARGE_CANCELLATION_EN |
+				 ADF4351_REG3_ANTI_BACKLASH_3ns_EN |
+				 ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH);
+
+	st->regs[ADF4350_REG4] =
+		ADF4350_REG4_FEEDBACK_FUND |
+		ADF4350_REG4_RF_DIV_SEL(st->r4_rf_div_sel) |
+		ADF4350_REG4_8BIT_BAND_SEL_CLKDIV(band_sel_div) |
+		ADF4350_REG4_RF_OUT_EN |
+		(pdata->r4_user_settings &
+		(ADF4350_REG4_OUTPUT_PWR(0x3) |
+		ADF4350_REG4_AUX_OUTPUT_PWR(0x3) |
+		ADF4350_REG4_AUX_OUTPUT_EN |
+		ADF4350_REG4_AUX_OUTPUT_FUND |
+		ADF4350_REG4_MUTE_TILL_LOCK_EN));
+
+	st->regs[ADF4350_REG5] = ADF4350_REG5_LD_PIN_MODE_DIGITAL;
+
+	return adf4350_sync_config(st);
+}
+
+static ssize_t adf4350_write(struct iio_dev *indio_dev,
+				    uintptr_t private,
+				    const struct iio_chan_spec *chan,
+				    const char *buf, size_t len)
+{
+	struct adf4350_state *st = iio_priv(indio_dev);
+	unsigned long long readin;
+	int ret;
+
+	ret = kstrtoull(buf, 10, &readin);
+	if (ret)
+		return ret;
+
+	mutex_lock(&indio_dev->mlock);
+	switch ((u32)private) {
+	case ADF4350_FREQ:
+		ret = adf4350_set_freq(st, readin);
+		break;
+	case ADF4350_FREQ_REFIN:
+		if (readin > ADF4350_MAX_FREQ_REFIN)
+			ret = -EINVAL;
+		else
+			st->clkin = readin;
+		break;
+	case ADF4350_FREQ_RESOLUTION:
+		if (readin == 0)
+			ret = -EINVAL;
+		else
+			st->chspc = readin;
+		break;
+	case ADF4350_PWRDOWN:
+		if (readin)
+			st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN;
+		else
+			st->regs[ADF4350_REG2] &= ~ADF4350_REG2_POWER_DOWN_EN;
+
+		adf4350_sync_config(st);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret ? ret : len;
+}
+
+static ssize_t adf4350_read(struct iio_dev *indio_dev,
+				   uintptr_t private,
+				   const struct iio_chan_spec *chan,
+				   char *buf)
+{
+	struct adf4350_state *st = iio_priv(indio_dev);
+	unsigned long long val;
+	int ret = 0;
+
+	mutex_lock(&indio_dev->mlock);
+	switch ((u32)private) {
+	case ADF4350_FREQ:
+		val = (u64)((st->r0_int * st->r1_mod) + st->r0_fract) *
+			(u64)st->fpfd;
+		do_div(val, st->r1_mod * (1 << st->r4_rf_div_sel));
+		/* PLL unlocked? return error */
+		if (gpio_is_valid(st->pdata->gpio_lock_detect))
+			if (!gpio_get_value(st->pdata->gpio_lock_detect)) {
+				dev_dbg(&st->spi->dev, "PLL un-locked\n");
+				ret = -EBUSY;
+			}
+		break;
+	case ADF4350_FREQ_REFIN:
+		val = st->clkin;
+		break;
+	case ADF4350_FREQ_RESOLUTION:
+		val = st->chspc;
+		break;
+	case ADF4350_PWRDOWN:
+		val = !!(st->regs[ADF4350_REG2] & ADF4350_REG2_POWER_DOWN_EN);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret < 0 ? ret : sprintf(buf, "%llu\n", val);
+}
+
+#define _ADF4350_EXT_INFO(_name, _ident) { \
+	.name = _name, \
+	.read = adf4350_read, \
+	.write = adf4350_write, \
+	.private = _ident, \
+}
+
+static const struct iio_chan_spec_ext_info adf4350_ext_info[] = {
+	/* Ideally we use IIO_CHAN_INFO_FREQUENCY, but there are
+	 * values > 2^32 in order to support the entire frequency range
+	 * in Hz. Using scale is a bit ugly.
+	 */
+	_ADF4350_EXT_INFO("frequency", ADF4350_FREQ),
+	_ADF4350_EXT_INFO("frequency_resolution", ADF4350_FREQ_RESOLUTION),
+	_ADF4350_EXT_INFO("refin_frequency", ADF4350_FREQ_REFIN),
+	_ADF4350_EXT_INFO("powerdown", ADF4350_PWRDOWN),
+	{ },
+};
+
+static const struct iio_chan_spec adf4350_chan = {
+	.type = IIO_ALTVOLTAGE,
+	.indexed = 1,
+	.output = 1,
+	.ext_info = adf4350_ext_info,
+};
+
+static const struct iio_info adf4350_info = {
+	.debugfs_reg_access = &adf4350_reg_access,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit adf4350_probe(struct spi_device *spi)
+{
+	struct adf4350_platform_data *pdata = spi->dev.platform_data;
+	struct iio_dev *indio_dev;
+	struct adf4350_state *st;
+	int ret;
+
+	if (!pdata) {
+		dev_warn(&spi->dev, "no platform data? using default\n");
+
+		pdata = &default_pdata;
+	}
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL)
+		return -ENOMEM;
+
+	st = iio_priv(indio_dev);
+
+	st->reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(st->reg)) {
+		ret = regulator_enable(st->reg);
+		if (ret)
+			goto error_put_reg;
+	}
+
+	spi_set_drvdata(spi, indio_dev);
+	st->spi = spi;
+	st->pdata = pdata;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = (pdata->name[0] != 0) ? pdata->name :
+		spi_get_device_id(spi)->name;
+
+	indio_dev->info = &adf4350_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = &adf4350_chan;
+	indio_dev->num_channels = 1;
+
+	st->chspc = pdata->channel_spacing;
+	st->clkin = pdata->clkin;
+
+	st->min_out_freq = spi_get_device_id(spi)->driver_data == 4351 ?
+		ADF4351_MIN_OUT_FREQ : ADF4350_MIN_OUT_FREQ;
+
+	memset(st->regs_hw, 0xFF, sizeof(st->regs_hw));
+
+	if (gpio_is_valid(pdata->gpio_lock_detect)) {
+		ret = gpio_request(pdata->gpio_lock_detect, indio_dev->name);
+		if (ret) {
+			dev_err(&spi->dev, "fail to request lock detect GPIO-%d",
+				pdata->gpio_lock_detect);
+			goto error_disable_reg;
+		}
+		gpio_direction_input(pdata->gpio_lock_detect);
+	}
+
+	if (pdata->power_up_frequency) {
+		ret = adf4350_set_freq(st, pdata->power_up_frequency);
+		if (ret)
+			goto error_free_gpio;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_free_gpio;
+
+	return 0;
+
+error_free_gpio:
+	if (gpio_is_valid(pdata->gpio_lock_detect))
+		gpio_free(pdata->gpio_lock_detect);
+
+error_disable_reg:
+	if (!IS_ERR(st->reg))
+		regulator_disable(st->reg);
+error_put_reg:
+	if (!IS_ERR(st->reg))
+		regulator_put(st->reg);
+
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit adf4350_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct adf4350_state *st = iio_priv(indio_dev);
+	struct regulator *reg = st->reg;
+
+	st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN;
+	adf4350_sync_config(st);
+
+	iio_device_unregister(indio_dev);
+
+	if (!IS_ERR(reg)) {
+		regulator_disable(reg);
+		regulator_put(reg);
+	}
+
+	if (gpio_is_valid(st->pdata->gpio_lock_detect))
+		gpio_free(st->pdata->gpio_lock_detect);
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id adf4350_id[] = {
+	{"adf4350", 4350},
+	{"adf4351", 4351},
+	{}
+};
+
+static struct spi_driver adf4350_driver = {
+	.driver = {
+		.name	= "adf4350",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= adf4350_probe,
+	.remove		= __devexit_p(adf4350_remove),
+	.id_table	= adf4350_id,
+};
+module_spi_driver(adf4350_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices ADF4350/ADF4351 PLL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index ac185b8..3d8d187 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -285,6 +285,9 @@ int iio_buffer_register(struct iio_dev *indio_dev,
 	if (channels) {
 		/* new magic */
 		for (i = 0; i < num_channels; i++) {
+			if (channels[i].scan_index < 0)
+				continue;
+
 			/* Establish necessary mask length */
 			if (channels[i].scan_index >
 			    (int)indio_dev->masklength - 1)
@@ -553,6 +556,10 @@ int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
 					    buffer->scan_mask);
 	else
 		indio_dev->active_scan_mask = buffer->scan_mask;
+
+	if (indio_dev->active_scan_mask == NULL)
+		return -EINVAL;
+
 	iio_update_demux(indio_dev);
 
 	if (indio_dev->info->update_scan_mode)
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 4f947e4..a5a446b 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -289,6 +289,69 @@ static ssize_t iio_write_channel_ext_info(struct device *dev,
 			       this_attr->c, buf, len);
 }
 
+ssize_t iio_enum_available_read(struct iio_dev *indio_dev,
+	uintptr_t priv, const struct iio_chan_spec *chan, char *buf)
+{
+	const struct iio_enum *e = (const struct iio_enum *)priv;
+	unsigned int i;
+	size_t len = 0;
+
+	if (!e->num_items)
+		return 0;
+
+	for (i = 0; i < e->num_items; ++i)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%s ", e->items[i]);
+
+	/* replace last space with a newline */
+	buf[len - 1] = '\n';
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(iio_enum_available_read);
+
+ssize_t iio_enum_read(struct iio_dev *indio_dev,
+	uintptr_t priv, const struct iio_chan_spec *chan, char *buf)
+{
+	const struct iio_enum *e = (const struct iio_enum *)priv;
+	int i;
+
+	if (!e->get)
+		return -EINVAL;
+
+	i = e->get(indio_dev, chan);
+	if (i < 0)
+		return i;
+	else if (i >= e->num_items)
+		return -EINVAL;
+
+	return sprintf(buf, "%s\n", e->items[i]);
+}
+EXPORT_SYMBOL_GPL(iio_enum_read);
+
+ssize_t iio_enum_write(struct iio_dev *indio_dev,
+	uintptr_t priv, const struct iio_chan_spec *chan, const char *buf,
+	size_t len)
+{
+	const struct iio_enum *e = (const struct iio_enum *)priv;
+	unsigned int i;
+	int ret;
+
+	if (!e->set)
+		return -EINVAL;
+
+	for (i = 0; i < e->num_items; i++) {
+		if (sysfs_streq(buf, e->items[i]))
+			break;
+	}
+
+	if (i == e->num_items)
+		return -EINVAL;
+
+	ret = e->set(indio_dev, chan, i);
+	return ret ? ret : len;
+}
+EXPORT_SYMBOL_GPL(iio_enum_write);
+
 static ssize_t iio_read_channel_info(struct device *dev,
 				     struct device_attribute *attr,
 				     char *buf)
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 0f582df..ec653fb 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -45,7 +45,7 @@ static ssize_t iio_trigger_read_name(struct device *dev,
 				     struct device_attribute *attr,
 				     char *buf)
 {
-	struct iio_trigger *trig = dev_get_drvdata(dev);
+	struct iio_trigger *trig = to_iio_trigger(dev);
 	return sprintf(buf, "%s\n", trig->name);
 }
 
@@ -436,7 +436,6 @@ struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
 		trig->dev.type = &iio_trig_type;
 		trig->dev.bus = &iio_bus_type;
 		device_initialize(&trig->dev);
-		dev_set_drvdata(&trig->dev, (void *)trig);
 
 		mutex_init(&trig->pool_lock);
 		trig->subirq_base
diff --git a/drivers/iio/industrialio-triggered-buffer.c b/drivers/iio/industrialio-triggered-buffer.c
new file mode 100644
index 0000000..46c619b
--- /dev/null
+++ b/drivers/iio/industrialio-triggered-buffer.c
@@ -0,0 +1,110 @@
+ /*
+ * Copyright (c) 2012 Analog Devices, Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
+	.preenable = &iio_sw_buffer_preenable,
+	.postenable = &iio_triggered_buffer_postenable,
+	.predisable = &iio_triggered_buffer_predisable,
+};
+
+/**
+ * iio_triggered_buffer_setup() - Setup triggered buffer and pollfunc
+ * @indio_dev:		IIO device structure
+ * @pollfunc_bh:	Function which will be used as pollfunc bottom half
+ * @pollfunc_th:	Function which will be used as pollfunc top half
+ * @setup_ops:		Buffer setup functions to use for this device.
+ *			If NULL the default setup functions for triggered
+ *			buffers will be used.
+ *
+ * This function combines some common tasks which will normally be performed
+ * when setting up a triggered buffer. It will allocate the buffer and the
+ * pollfunc, as well as register the buffer with the IIO core.
+ *
+ * Before calling this function the indio_dev structure should already be
+ * completely initialized, but not yet registered. In practice this means that
+ * this function should be called right before iio_device_register().
+ *
+ * To free the resources allocated by this function call
+ * iio_triggered_buffer_cleanup().
+ */
+int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
+	irqreturn_t (*pollfunc_bh)(int irq, void *p),
+	irqreturn_t (*pollfunc_th)(int irq, void *p),
+	const struct iio_buffer_setup_ops *setup_ops)
+{
+	int ret;
+
+	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
+	if (!indio_dev->buffer) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	indio_dev->pollfunc = iio_alloc_pollfunc(pollfunc_bh,
+						 pollfunc_th,
+						 IRQF_ONESHOT,
+						 indio_dev,
+						 "%s_consumer%d",
+						 indio_dev->name,
+						 indio_dev->id);
+	if (indio_dev->pollfunc == NULL) {
+		ret = -ENOMEM;
+		goto error_kfifo_free;
+	}
+
+	/* Ring buffer functions - here trigger setup related */
+	if (setup_ops)
+		indio_dev->setup_ops = setup_ops;
+	else
+		indio_dev->setup_ops = &iio_triggered_buffer_setup_ops;
+
+	/* Flag that polled ring buffering is possible */
+	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
+
+	ret = iio_buffer_register(indio_dev,
+				  indio_dev->channels,
+				  indio_dev->num_channels);
+	if (ret)
+		goto error_dealloc_pollfunc;
+
+	return 0;
+
+error_dealloc_pollfunc:
+	iio_dealloc_pollfunc(indio_dev->pollfunc);
+error_kfifo_free:
+	iio_kfifo_free(indio_dev->buffer);
+error_ret:
+	return ret;
+}
+EXPORT_SYMBOL(iio_triggered_buffer_setup);
+
+/**
+ * iio_triggered_buffer_cleanup() - Free resources allocated by iio_triggered_buffer_setup()
+ * @indio_dev: IIO device structure
+ */
+void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev)
+{
+	iio_buffer_unregister(indio_dev);
+	iio_dealloc_pollfunc(indio_dev->pollfunc);
+	iio_kfifo_free(indio_dev->buffer);
+}
+EXPORT_SYMBOL(iio_triggered_buffer_cleanup);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("IIO helper functions for setting up triggered buffers");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 9226458..d4760bd 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -125,7 +125,7 @@ struct iio_channel *iio_st_channel_get(const char *name,
 		     strcmp(channel_name, c_i->map->consumer_channel) != 0))
 			continue;
 		c = c_i;
-		get_device(&c->indio_dev->dev);
+		iio_device_get(c->indio_dev);
 		break;
 	}
 	mutex_unlock(&iio_map_list_lock);
@@ -149,7 +149,7 @@ EXPORT_SYMBOL_GPL(iio_st_channel_get);
 
 void iio_st_channel_release(struct iio_channel *channel)
 {
-	put_device(&channel->indio_dev->dev);
+	iio_device_put(channel->indio_dev);
 	kfree(channel);
 }
 EXPORT_SYMBOL_GPL(iio_st_channel_release);
@@ -195,10 +195,10 @@ struct iio_channel *iio_st_channel_get_all(const char *name)
 						c->map->adc_channel_label);
 		if (chans[mapind].channel == NULL) {
 			ret = -EINVAL;
-			put_device(&chans[mapind].indio_dev->dev);
+			iio_device_put(chans[mapind].indio_dev);
 			goto error_free_chans;
 		}
-		get_device(&chans[mapind].indio_dev->dev);
+		iio_device_get(chans[mapind].indio_dev);
 		mapind++;
 	}
 	mutex_unlock(&iio_map_list_lock);
@@ -210,8 +210,7 @@ struct iio_channel *iio_st_channel_get_all(const char *name)
 
 error_free_chans:
 	for (i = 0; i < nummaps; i++)
-		if (chans[i].indio_dev)
-			put_device(&chans[i].indio_dev->dev);
+		iio_device_put(chans[i].indio_dev);
 	kfree(chans);
 error_ret:
 	mutex_unlock(&iio_map_list_lock);
@@ -225,7 +224,7 @@ void iio_st_channel_release_all(struct iio_channel *channels)
 	struct iio_channel *chan = &channels[0];
 
 	while (chan->indio_dev) {
-		put_device(&chan->indio_dev->dev);
+		iio_device_put(chan->indio_dev);
 		chan++;
 	}
 	kfree(channels);
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
new file mode 100644
index 0000000..f3ea90d
--- /dev/null
+++ b/drivers/iio/light/Kconfig
@@ -0,0 +1,33 @@
+#
+# Light sensors
+#
+menu "Light sensors"
+
+config SENSORS_LM3533
+	tristate "LM3533 ambient light sensor"
+	depends on MFD_LM3533
+	help
+	  If you say yes here you get support for the ambient light sensor
+	  interface on National Semiconductor / TI LM3533 Lighting Power
+	  chips.
+
+	  The sensor interface can be used to control the LEDs and backlights
+	  of the chip through defining five light zones and three sets of
+	  corresponding output-current values.
+
+	  The driver provides raw and mean adc readings along with the current
+	  light zone through sysfs. A threshold event can be generated on zone
+	  changes. The ALS-control output values can be set per zone for the
+	  three current output channels.
+
+config VCNL4000
+	tristate "VCNL4000 combined ALS and proximity sensor"
+	depends on I2C
+	help
+	 Say Y here if you want to build a driver for the Vishay VCNL4000
+	 combined ambient light and proximity sensor.
+
+	 To compile this driver as a module, choose M here: the
+	 module will be called vcnl4000.
+
+endmenu
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
new file mode 100644
index 0000000..06fa4d3
--- /dev/null
+++ b/drivers/iio/light/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for IIO Light sensors
+#
+
+obj-$(CONFIG_SENSORS_LM3533)	+= lm3533-als.o
+obj-$(CONFIG_VCNL4000)		+= vcnl4000.o
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
new file mode 100644
index 0000000..c3e7bac
--- /dev/null
+++ b/drivers/iio/light/lm3533-als.c
@@ -0,0 +1,932 @@
+/*
+ * lm3533-als.c -- LM3533 Ambient Light Sensor driver
+ *
+ * Copyright (C) 2011-2012 Texas Instruments
+ *
+ * Author: Johan Hovold <jhovold@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/atomic.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <linux/mfd/lm3533.h>
+
+
+#define LM3533_ALS_RESISTOR_MIN			1
+#define LM3533_ALS_RESISTOR_MAX			127
+#define LM3533_ALS_CHANNEL_CURRENT_MAX		2
+#define LM3533_ALS_THRESH_MAX			3
+#define LM3533_ALS_ZONE_MAX			4
+
+#define LM3533_REG_ALS_RESISTOR_SELECT		0x30
+#define LM3533_REG_ALS_CONF			0x31
+#define LM3533_REG_ALS_ZONE_INFO		0x34
+#define LM3533_REG_ALS_READ_ADC_RAW		0x37
+#define LM3533_REG_ALS_READ_ADC_AVERAGE		0x38
+#define LM3533_REG_ALS_BOUNDARY_BASE		0x50
+#define LM3533_REG_ALS_TARGET_BASE		0x60
+
+#define LM3533_ALS_ENABLE_MASK			0x01
+#define LM3533_ALS_INPUT_MODE_MASK		0x02
+#define LM3533_ALS_INT_ENABLE_MASK		0x01
+
+#define LM3533_ALS_ZONE_SHIFT			2
+#define LM3533_ALS_ZONE_MASK			0x1c
+
+#define LM3533_ALS_FLAG_INT_ENABLED		1
+
+
+struct lm3533_als {
+	struct lm3533 *lm3533;
+	struct platform_device *pdev;
+
+	unsigned long flags;
+	int irq;
+
+	atomic_t zone;
+	struct mutex thresh_mutex;
+};
+
+
+static int lm3533_als_get_adc(struct iio_dev *indio_dev, bool average,
+								int *adc)
+{
+	struct lm3533_als *als = iio_priv(indio_dev);
+	u8 reg;
+	u8 val;
+	int ret;
+
+	if (average)
+		reg = LM3533_REG_ALS_READ_ADC_AVERAGE;
+	else
+		reg = LM3533_REG_ALS_READ_ADC_RAW;
+
+	ret = lm3533_read(als->lm3533, reg, &val);
+	if (ret) {
+		dev_err(&indio_dev->dev, "failed to read adc\n");
+		return ret;
+	}
+
+	*adc = val;
+
+	return 0;
+}
+
+static int _lm3533_als_get_zone(struct iio_dev *indio_dev, u8 *zone)
+{
+	struct lm3533_als *als = iio_priv(indio_dev);
+	u8 val;
+	int ret;
+
+	ret = lm3533_read(als->lm3533, LM3533_REG_ALS_ZONE_INFO, &val);
+	if (ret) {
+		dev_err(&indio_dev->dev, "failed to read zone\n");
+		return ret;
+	}
+
+	val = (val & LM3533_ALS_ZONE_MASK) >> LM3533_ALS_ZONE_SHIFT;
+	*zone = min_t(u8, val, LM3533_ALS_ZONE_MAX);
+
+	return 0;
+}
+
+static int lm3533_als_get_zone(struct iio_dev *indio_dev, u8 *zone)
+{
+	struct lm3533_als *als = iio_priv(indio_dev);
+	int ret;
+
+	if (test_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags)) {
+		*zone = atomic_read(&als->zone);
+	} else {
+		ret = _lm3533_als_get_zone(indio_dev, zone);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * channel	output channel 0..2
+ * zone		zone 0..4
+ */
+static inline u8 lm3533_als_get_target_reg(unsigned channel, unsigned zone)
+{
+	return LM3533_REG_ALS_TARGET_BASE + 5 * channel + zone;
+}
+
+static int lm3533_als_get_target(struct iio_dev *indio_dev, unsigned channel,
+							unsigned zone, u8 *val)
+{
+	struct lm3533_als *als = iio_priv(indio_dev);
+	u8 reg;
+	int ret;
+
+	if (channel > LM3533_ALS_CHANNEL_CURRENT_MAX)
+		return -EINVAL;
+
+	if (zone > LM3533_ALS_ZONE_MAX)
+		return -EINVAL;
+
+	reg = lm3533_als_get_target_reg(channel, zone);
+	ret = lm3533_read(als->lm3533, reg, val);
+	if (ret)
+		dev_err(&indio_dev->dev, "failed to get target current\n");
+
+	return ret;
+}
+
+static int lm3533_als_set_target(struct iio_dev *indio_dev, unsigned channel,
+							unsigned zone, u8 val)
+{
+	struct lm3533_als *als = iio_priv(indio_dev);
+	u8 reg;
+	int ret;
+
+	if (channel > LM3533_ALS_CHANNEL_CURRENT_MAX)
+		return -EINVAL;
+
+	if (zone > LM3533_ALS_ZONE_MAX)
+		return -EINVAL;
+
+	reg = lm3533_als_get_target_reg(channel, zone);
+	ret = lm3533_write(als->lm3533, reg, val);
+	if (ret)
+		dev_err(&indio_dev->dev, "failed to set target current\n");
+
+	return ret;
+}
+
+static int lm3533_als_get_current(struct iio_dev *indio_dev, unsigned channel,
+								int *val)
+{
+	u8 zone;
+	u8 target;
+	int ret;
+
+	ret = lm3533_als_get_zone(indio_dev, &zone);
+	if (ret)
+		return ret;
+
+	ret = lm3533_als_get_target(indio_dev, channel, zone, &target);
+	if (ret)
+		return ret;
+
+	*val = target;
+
+	return 0;
+}
+
+static int lm3533_als_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	int ret;
+
+	switch (mask) {
+	case 0:
+		switch (chan->type) {
+		case IIO_LIGHT:
+			ret = lm3533_als_get_adc(indio_dev, false, val);
+			break;
+		case IIO_CURRENT:
+			ret = lm3533_als_get_current(indio_dev, chan->channel,
+									val);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case IIO_CHAN_INFO_AVERAGE_RAW:
+		ret = lm3533_als_get_adc(indio_dev, true, val);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ret)
+		return ret;
+
+	return IIO_VAL_INT;
+}
+
+#define CHANNEL_CURRENT(_channel)					\
+	{								\
+		.type		= IIO_CURRENT,				\
+		.channel	= _channel,				\
+		.indexed	= true,					\
+		.output		= true,					\
+		.info_mask	= IIO_CHAN_INFO_RAW_SEPARATE_BIT,	\
+	}
+
+static const struct iio_chan_spec lm3533_als_channels[] = {
+	{
+		.type		= IIO_LIGHT,
+		.channel	= 0,
+		.indexed	= true,
+		.info_mask	= (IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT |
+				   IIO_CHAN_INFO_RAW_SEPARATE_BIT),
+	},
+	CHANNEL_CURRENT(0),
+	CHANNEL_CURRENT(1),
+	CHANNEL_CURRENT(2),
+};
+
+static irqreturn_t lm3533_als_isr(int irq, void *dev_id)
+{
+
+	struct iio_dev *indio_dev = dev_id;
+	struct lm3533_als *als = iio_priv(indio_dev);
+	u8 zone;
+	int ret;
+
+	/* Clear interrupt by reading the ALS zone register. */
+	ret = _lm3533_als_get_zone(indio_dev, &zone);
+	if (ret)
+		goto out;
+
+	atomic_set(&als->zone, zone);
+
+	iio_push_event(indio_dev,
+		       IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+					    0,
+					    IIO_EV_TYPE_THRESH,
+					    IIO_EV_DIR_EITHER),
+		       iio_get_time_ns());
+out:
+	return IRQ_HANDLED;
+}
+
+static int lm3533_als_set_int_mode(struct iio_dev *indio_dev, int enable)
+{
+	struct lm3533_als *als = iio_priv(indio_dev);
+	u8 mask = LM3533_ALS_INT_ENABLE_MASK;
+	u8 val;
+	int ret;
+
+	if (enable)
+		val = mask;
+	else
+		val = 0;
+
+	ret = lm3533_update(als->lm3533, LM3533_REG_ALS_ZONE_INFO, val, mask);
+	if (ret) {
+		dev_err(&indio_dev->dev, "failed to set int mode %d\n",
+								enable);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int lm3533_als_get_int_mode(struct iio_dev *indio_dev, int *enable)
+{
+	struct lm3533_als *als = iio_priv(indio_dev);
+	u8 mask = LM3533_ALS_INT_ENABLE_MASK;
+	u8 val;
+	int ret;
+
+	ret = lm3533_read(als->lm3533, LM3533_REG_ALS_ZONE_INFO, &val);
+	if (ret) {
+		dev_err(&indio_dev->dev, "failed to get int mode\n");
+		return ret;
+	}
+
+	*enable = !!(val & mask);
+
+	return 0;
+}
+
+static inline u8 lm3533_als_get_threshold_reg(unsigned nr, bool raising)
+{
+	u8 offset = !raising;
+
+	return LM3533_REG_ALS_BOUNDARY_BASE + 2 * nr + offset;
+}
+
+static int lm3533_als_get_threshold(struct iio_dev *indio_dev, unsigned nr,
+							bool raising, u8 *val)
+{
+	struct lm3533_als *als = iio_priv(indio_dev);
+	u8 reg;
+	int ret;
+
+	if (nr > LM3533_ALS_THRESH_MAX)
+		return -EINVAL;
+
+	reg = lm3533_als_get_threshold_reg(nr, raising);
+	ret = lm3533_read(als->lm3533, reg, val);
+	if (ret)
+		dev_err(&indio_dev->dev, "failed to get threshold\n");
+
+	return ret;
+}
+
+static int lm3533_als_set_threshold(struct iio_dev *indio_dev, unsigned nr,
+							bool raising, u8 val)
+{
+	struct lm3533_als *als = iio_priv(indio_dev);
+	u8 val2;
+	u8 reg, reg2;
+	int ret;
+
+	if (nr > LM3533_ALS_THRESH_MAX)
+		return -EINVAL;
+
+	reg = lm3533_als_get_threshold_reg(nr, raising);
+	reg2 = lm3533_als_get_threshold_reg(nr, !raising);
+
+	mutex_lock(&als->thresh_mutex);
+	ret = lm3533_read(als->lm3533, reg2, &val2);
+	if (ret) {
+		dev_err(&indio_dev->dev, "failed to get threshold\n");
+		goto out;
+	}
+	/*
+	 * This device does not allow negative hysteresis (in fact, it uses
+	 * whichever value is smaller as the lower bound) so we need to make
+	 * sure that thresh_falling <= thresh_raising.
+	 */
+	if ((raising && (val < val2)) || (!raising && (val > val2))) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = lm3533_write(als->lm3533, reg, val);
+	if (ret) {
+		dev_err(&indio_dev->dev, "failed to set threshold\n");
+		goto out;
+	}
+out:
+	mutex_unlock(&als->thresh_mutex);
+
+	return ret;
+}
+
+static int lm3533_als_get_hysteresis(struct iio_dev *indio_dev, unsigned nr,
+								u8 *val)
+{
+	struct lm3533_als *als = iio_priv(indio_dev);
+	u8 falling;
+	u8 raising;
+	int ret;
+
+	if (nr > LM3533_ALS_THRESH_MAX)
+		return -EINVAL;
+
+	mutex_lock(&als->thresh_mutex);
+	ret = lm3533_als_get_threshold(indio_dev, nr, false, &falling);
+	if (ret)
+		goto out;
+	ret = lm3533_als_get_threshold(indio_dev, nr, true, &raising);
+	if (ret)
+		goto out;
+
+	*val = raising - falling;
+out:
+	mutex_unlock(&als->thresh_mutex);
+
+	return ret;
+}
+
+static int show_thresh_either_en(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct lm3533_als *als = iio_priv(indio_dev);
+	int enable;
+	int ret;
+
+	if (als->irq) {
+		ret = lm3533_als_get_int_mode(indio_dev, &enable);
+		if (ret)
+			return ret;
+	} else {
+		enable = 0;
+	}
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", enable);
+}
+
+static int store_thresh_either_en(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct lm3533_als *als = iio_priv(indio_dev);
+	unsigned long enable;
+	bool int_enabled;
+	u8 zone;
+	int ret;
+
+	if (!als->irq)
+		return -EBUSY;
+
+	if (kstrtoul(buf, 0, &enable))
+		return -EINVAL;
+
+	int_enabled = test_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
+
+	if (enable && !int_enabled) {
+		ret = lm3533_als_get_zone(indio_dev, &zone);
+		if (ret)
+			return ret;
+
+		atomic_set(&als->zone, zone);
+
+		set_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
+	}
+
+	ret = lm3533_als_set_int_mode(indio_dev, enable);
+	if (ret) {
+		if (!int_enabled)
+			clear_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
+
+		return ret;
+	}
+
+	if (!enable)
+		clear_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
+
+	return len;
+}
+
+static ssize_t show_zone(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	u8 zone;
+	int ret;
+
+	ret = lm3533_als_get_zone(indio_dev, &zone);
+	if (ret)
+		return ret;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", zone);
+}
+
+enum lm3533_als_attribute_type {
+	LM3533_ATTR_TYPE_HYSTERESIS,
+	LM3533_ATTR_TYPE_TARGET,
+	LM3533_ATTR_TYPE_THRESH_FALLING,
+	LM3533_ATTR_TYPE_THRESH_RAISING,
+};
+
+struct lm3533_als_attribute {
+	struct device_attribute dev_attr;
+	enum lm3533_als_attribute_type type;
+	u8 val1;
+	u8 val2;
+};
+
+static inline struct lm3533_als_attribute *
+to_lm3533_als_attr(struct device_attribute *attr)
+{
+	return container_of(attr, struct lm3533_als_attribute, dev_attr);
+}
+
+static ssize_t show_als_attr(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct lm3533_als_attribute *als_attr = to_lm3533_als_attr(attr);
+	u8 val;
+	int ret;
+
+	switch (als_attr->type) {
+	case LM3533_ATTR_TYPE_HYSTERESIS:
+		ret = lm3533_als_get_hysteresis(indio_dev, als_attr->val1,
+									&val);
+		break;
+	case LM3533_ATTR_TYPE_TARGET:
+		ret = lm3533_als_get_target(indio_dev, als_attr->val1,
+							als_attr->val2, &val);
+		break;
+	case LM3533_ATTR_TYPE_THRESH_FALLING:
+		ret = lm3533_als_get_threshold(indio_dev, als_attr->val1,
+								false, &val);
+		break;
+	case LM3533_ATTR_TYPE_THRESH_RAISING:
+		ret = lm3533_als_get_threshold(indio_dev, als_attr->val1,
+								true, &val);
+		break;
+	default:
+		ret = -ENXIO;
+	}
+
+	if (ret)
+		return ret;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+}
+
+static ssize_t store_als_attr(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct lm3533_als_attribute *als_attr = to_lm3533_als_attr(attr);
+	u8 val;
+	int ret;
+
+	if (kstrtou8(buf, 0, &val))
+		return -EINVAL;
+
+	switch (als_attr->type) {
+	case LM3533_ATTR_TYPE_TARGET:
+		ret = lm3533_als_set_target(indio_dev, als_attr->val1,
+							als_attr->val2, val);
+		break;
+	case LM3533_ATTR_TYPE_THRESH_FALLING:
+		ret = lm3533_als_set_threshold(indio_dev, als_attr->val1,
+								false, val);
+		break;
+	case LM3533_ATTR_TYPE_THRESH_RAISING:
+		ret = lm3533_als_set_threshold(indio_dev, als_attr->val1,
+								true, val);
+		break;
+	default:
+		ret = -ENXIO;
+	}
+
+	if (ret)
+		return ret;
+
+	return len;
+}
+
+#define ALS_ATTR(_name, _mode, _show, _store, _type, _val1, _val2)	\
+	{ .dev_attr	= __ATTR(_name, _mode, _show, _store),		\
+	  .type		= _type,					\
+	  .val1		= _val1,					\
+	  .val2		= _val2 }
+
+#define LM3533_ALS_ATTR(_name, _mode, _show, _store, _type, _val1, _val2) \
+	struct lm3533_als_attribute lm3533_als_attr_##_name =		  \
+		ALS_ATTR(_name, _mode, _show, _store, _type, _val1, _val2)
+
+#define ALS_TARGET_ATTR_RW(_channel, _zone)				\
+	LM3533_ALS_ATTR(out_current##_channel##_current##_zone##_raw,	\
+				S_IRUGO | S_IWUSR,			\
+				show_als_attr, store_als_attr,		\
+				LM3533_ATTR_TYPE_TARGET, _channel, _zone)
+/*
+ * ALS output current values (ALS mapper targets)
+ *
+ * out_current[0-2]_current[0-4]_raw		0-255
+ */
+static ALS_TARGET_ATTR_RW(0, 0);
+static ALS_TARGET_ATTR_RW(0, 1);
+static ALS_TARGET_ATTR_RW(0, 2);
+static ALS_TARGET_ATTR_RW(0, 3);
+static ALS_TARGET_ATTR_RW(0, 4);
+
+static ALS_TARGET_ATTR_RW(1, 0);
+static ALS_TARGET_ATTR_RW(1, 1);
+static ALS_TARGET_ATTR_RW(1, 2);
+static ALS_TARGET_ATTR_RW(1, 3);
+static ALS_TARGET_ATTR_RW(1, 4);
+
+static ALS_TARGET_ATTR_RW(2, 0);
+static ALS_TARGET_ATTR_RW(2, 1);
+static ALS_TARGET_ATTR_RW(2, 2);
+static ALS_TARGET_ATTR_RW(2, 3);
+static ALS_TARGET_ATTR_RW(2, 4);
+
+#define ALS_THRESH_FALLING_ATTR_RW(_nr)					\
+	LM3533_ALS_ATTR(in_illuminance0_thresh##_nr##_falling_value,	\
+			S_IRUGO | S_IWUSR,				\
+			show_als_attr, store_als_attr,		\
+			LM3533_ATTR_TYPE_THRESH_FALLING, _nr, 0)
+
+#define ALS_THRESH_RAISING_ATTR_RW(_nr)					\
+	LM3533_ALS_ATTR(in_illuminance0_thresh##_nr##_raising_value,	\
+			S_IRUGO | S_IWUSR,				\
+			show_als_attr, store_als_attr,			\
+			LM3533_ATTR_TYPE_THRESH_RAISING, _nr, 0)
+/*
+ * ALS Zone thresholds (boundaries)
+ *
+ * in_illuminance0_thresh[0-3]_falling_value	0-255
+ * in_illuminance0_thresh[0-3]_raising_value	0-255
+ */
+static ALS_THRESH_FALLING_ATTR_RW(0);
+static ALS_THRESH_FALLING_ATTR_RW(1);
+static ALS_THRESH_FALLING_ATTR_RW(2);
+static ALS_THRESH_FALLING_ATTR_RW(3);
+
+static ALS_THRESH_RAISING_ATTR_RW(0);
+static ALS_THRESH_RAISING_ATTR_RW(1);
+static ALS_THRESH_RAISING_ATTR_RW(2);
+static ALS_THRESH_RAISING_ATTR_RW(3);
+
+#define ALS_HYSTERESIS_ATTR_RO(_nr)					\
+	LM3533_ALS_ATTR(in_illuminance0_thresh##_nr##_hysteresis,	\
+			S_IRUGO, show_als_attr, NULL,			\
+			LM3533_ATTR_TYPE_HYSTERESIS, _nr, 0)
+/*
+ * ALS Zone threshold hysteresis
+ *
+ * threshY_hysteresis = threshY_raising - threshY_falling
+ *
+ * in_illuminance0_thresh[0-3]_hysteresis	0-255
+ * in_illuminance0_thresh[0-3]_hysteresis	0-255
+ */
+static ALS_HYSTERESIS_ATTR_RO(0);
+static ALS_HYSTERESIS_ATTR_RO(1);
+static ALS_HYSTERESIS_ATTR_RO(2);
+static ALS_HYSTERESIS_ATTR_RO(3);
+
+#define ILLUMINANCE_ATTR_RO(_name) \
+	DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO, show_##_name, NULL)
+#define ILLUMINANCE_ATTR_RW(_name) \
+	DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO | S_IWUSR , \
+						show_##_name, store_##_name)
+/*
+ * ALS Zone threshold-event enable
+ *
+ * in_illuminance0_thresh_either_en		0,1
+ */
+static ILLUMINANCE_ATTR_RW(thresh_either_en);
+
+/*
+ * ALS Current Zone
+ *
+ * in_illuminance0_zone		0-4
+ */
+static ILLUMINANCE_ATTR_RO(zone);
+
+static struct attribute *lm3533_als_event_attributes[] = {
+	&dev_attr_in_illuminance0_thresh_either_en.attr,
+	&lm3533_als_attr_in_illuminance0_thresh0_falling_value.dev_attr.attr,
+	&lm3533_als_attr_in_illuminance0_thresh0_hysteresis.dev_attr.attr,
+	&lm3533_als_attr_in_illuminance0_thresh0_raising_value.dev_attr.attr,
+	&lm3533_als_attr_in_illuminance0_thresh1_falling_value.dev_attr.attr,
+	&lm3533_als_attr_in_illuminance0_thresh1_hysteresis.dev_attr.attr,
+	&lm3533_als_attr_in_illuminance0_thresh1_raising_value.dev_attr.attr,
+	&lm3533_als_attr_in_illuminance0_thresh2_falling_value.dev_attr.attr,
+	&lm3533_als_attr_in_illuminance0_thresh2_hysteresis.dev_attr.attr,
+	&lm3533_als_attr_in_illuminance0_thresh2_raising_value.dev_attr.attr,
+	&lm3533_als_attr_in_illuminance0_thresh3_falling_value.dev_attr.attr,
+	&lm3533_als_attr_in_illuminance0_thresh3_hysteresis.dev_attr.attr,
+	&lm3533_als_attr_in_illuminance0_thresh3_raising_value.dev_attr.attr,
+	NULL
+};
+
+static struct attribute_group lm3533_als_event_attribute_group = {
+	.attrs = lm3533_als_event_attributes
+};
+
+static struct attribute *lm3533_als_attributes[] = {
+	&dev_attr_in_illuminance0_zone.attr,
+	&lm3533_als_attr_out_current0_current0_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current0_current1_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current0_current2_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current0_current3_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current0_current4_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current1_current0_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current1_current1_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current1_current2_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current1_current3_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current1_current4_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current2_current0_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current2_current1_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current2_current2_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current2_current3_raw.dev_attr.attr,
+	&lm3533_als_attr_out_current2_current4_raw.dev_attr.attr,
+	NULL
+};
+
+static struct attribute_group lm3533_als_attribute_group = {
+	.attrs = lm3533_als_attributes
+};
+
+static int __devinit lm3533_als_set_input_mode(struct lm3533_als *als,
+								bool pwm_mode)
+{
+	u8 mask = LM3533_ALS_INPUT_MODE_MASK;
+	u8 val;
+	int ret;
+
+	if (pwm_mode)
+		val = mask;	/* pwm input */
+	else
+		val = 0;	/* analog input */
+
+	ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, val, mask);
+	if (ret) {
+		dev_err(&als->pdev->dev, "failed to set input mode %d\n",
+								pwm_mode);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devinit lm3533_als_set_resistor(struct lm3533_als *als, u8 val)
+{
+	int ret;
+
+	if (val < LM3533_ALS_RESISTOR_MIN || val > LM3533_ALS_RESISTOR_MAX)
+		return -EINVAL;
+
+	ret = lm3533_write(als->lm3533, LM3533_REG_ALS_RESISTOR_SELECT, val);
+	if (ret) {
+		dev_err(&als->pdev->dev, "failed to set resistor\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devinit lm3533_als_setup(struct lm3533_als *als,
+					struct lm3533_als_platform_data *pdata)
+{
+	int ret;
+
+	ret = lm3533_als_set_input_mode(als, pdata->pwm_mode);
+	if (ret)
+		return ret;
+
+	/* ALS input is always high impedance in PWM-mode. */
+	if (!pdata->pwm_mode) {
+		ret = lm3533_als_set_resistor(als, pdata->r_select);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int __devinit lm3533_als_setup_irq(struct lm3533_als *als, void *dev)
+{
+	u8 mask = LM3533_ALS_INT_ENABLE_MASK;
+	int ret;
+
+	/* Make sure interrupts are disabled. */
+	ret = lm3533_update(als->lm3533, LM3533_REG_ALS_ZONE_INFO, 0, mask);
+	if (ret) {
+		dev_err(&als->pdev->dev, "failed to disable interrupts\n");
+		return ret;
+	}
+
+	ret = request_threaded_irq(als->irq, NULL, lm3533_als_isr,
+					IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+					dev_name(&als->pdev->dev), dev);
+	if (ret) {
+		dev_err(&als->pdev->dev, "failed to request irq %d\n",
+								als->irq);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devinit lm3533_als_enable(struct lm3533_als *als)
+{
+	u8 mask = LM3533_ALS_ENABLE_MASK;
+	int ret;
+
+	ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, mask, mask);
+	if (ret)
+		dev_err(&als->pdev->dev, "failed to enable ALS\n");
+
+	return ret;
+}
+
+static int lm3533_als_disable(struct lm3533_als *als)
+{
+	u8 mask = LM3533_ALS_ENABLE_MASK;
+	int ret;
+
+	ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, 0, mask);
+	if (ret)
+		dev_err(&als->pdev->dev, "failed to disable ALS\n");
+
+	return ret;
+}
+
+static const struct iio_info lm3533_als_info = {
+	.attrs		= &lm3533_als_attribute_group,
+	.event_attrs	= &lm3533_als_event_attribute_group,
+	.driver_module	= THIS_MODULE,
+	.read_raw	= &lm3533_als_read_raw,
+};
+
+static int __devinit lm3533_als_probe(struct platform_device *pdev)
+{
+	struct lm3533 *lm3533;
+	struct lm3533_als_platform_data *pdata;
+	struct lm3533_als *als;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	lm3533 = dev_get_drvdata(pdev->dev.parent);
+	if (!lm3533)
+		return -EINVAL;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data\n");
+		return -EINVAL;
+	}
+
+	indio_dev = iio_device_alloc(sizeof(*als));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	indio_dev->info = &lm3533_als_info;
+	indio_dev->channels = lm3533_als_channels;
+	indio_dev->num_channels = ARRAY_SIZE(lm3533_als_channels);
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->dev.parent = pdev->dev.parent;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	als = iio_priv(indio_dev);
+	als->lm3533 = lm3533;
+	als->pdev = pdev;
+	als->irq = lm3533->irq;
+	atomic_set(&als->zone, 0);
+	mutex_init(&als->thresh_mutex);
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	if (als->irq) {
+		ret = lm3533_als_setup_irq(als, indio_dev);
+		if (ret)
+			goto err_free_dev;
+	}
+
+	ret = lm3533_als_setup(als, pdata);
+	if (ret)
+		goto err_free_irq;
+
+	ret = lm3533_als_enable(als);
+	if (ret)
+		goto err_free_irq;
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register ALS\n");
+		goto err_disable;
+	}
+
+	return 0;
+
+err_disable:
+	lm3533_als_disable(als);
+err_free_irq:
+	if (als->irq)
+		free_irq(als->irq, indio_dev);
+err_free_dev:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit lm3533_als_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct lm3533_als *als = iio_priv(indio_dev);
+
+	lm3533_als_set_int_mode(indio_dev, false);
+	iio_device_unregister(indio_dev);
+	lm3533_als_disable(als);
+	if (als->irq)
+		free_irq(als->irq, indio_dev);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static struct platform_driver lm3533_als_driver = {
+	.driver	= {
+		.name	= "lm3533-als",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= lm3533_als_probe,
+	.remove		= __devexit_p(lm3533_als_remove),
+};
+module_platform_driver(lm3533_als_driver);
+
+MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
+MODULE_DESCRIPTION("LM3533 Ambient Light Sensor driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lm3533-als");
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
new file mode 100644
index 0000000..e49cb97
--- /dev/null
+++ b/drivers/iio/light/vcnl4000.c
@@ -0,0 +1,217 @@
+/*
+ * vcnl4000.c - Support for Vishay VCNL4000 combined ambient light and
+ * proximity sensor
+ *
+ * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * IIO driver for VCNL4000 (7-bit I2C slave address 0x13)
+ *
+ * TODO:
+ *   allow to adjust IR current
+ *   proximity threshold and event handling
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define VCNL4000_DRV_NAME "vcnl4000"
+
+#define VCNL4000_COMMAND	0x80 /* Command register */
+#define VCNL4000_PROD_REV	0x81 /* Product ID and Revision ID */
+#define VCNL4000_LED_CURRENT	0x83 /* IR LED current for proximity mode */
+#define VCNL4000_AL_PARAM	0x84 /* Ambient light parameter register */
+#define VCNL4000_AL_RESULT_HI	0x85 /* Ambient light result register, MSB */
+#define VCNL4000_AL_RESULT_LO	0x86 /* Ambient light result register, LSB */
+#define VCNL4000_PS_RESULT_HI	0x87 /* Proximity result register, MSB */
+#define VCNL4000_PS_RESULT_LO	0x88 /* Proximity result register, LSB */
+#define VCNL4000_PS_MEAS_FREQ	0x89 /* Proximity test signal frequency */
+#define VCNL4000_PS_MOD_ADJ	0x8a /* Proximity modulator timing adjustment */
+
+/* Bit masks for COMMAND register */
+#define VCNL4000_AL_RDY		0x40 /* ALS data ready? */
+#define VCNL4000_PS_RDY		0x20 /* proximity data ready? */
+#define VCNL4000_AL_OD		0x10 /* start on-demand ALS measurement */
+#define VCNL4000_PS_OD		0x08 /* start on-demand proximity measurement */
+
+struct vcnl4000_data {
+	struct i2c_client *client;
+};
+
+static const struct i2c_device_id vcnl4000_id[] = {
+	{ "vcnl4000", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
+
+static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
+				u8 rdy_mask, u8 data_reg, int *val)
+{
+	int tries = 20;
+	u16 buf;
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
+					req_mask);
+	if (ret < 0)
+		return ret;
+
+	/* wait for data to become ready */
+	while (tries--) {
+		ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
+		if (ret < 0)
+			return ret;
+		if (ret & rdy_mask)
+			break;
+		msleep(20); /* measurement takes up to 100 ms */
+	}
+
+	if (tries < 0) {
+		dev_err(&data->client->dev,
+			"vcnl4000_measure() failed, data not ready\n");
+		return -EIO;
+	}
+
+	ret = i2c_smbus_read_i2c_block_data(data->client,
+		data_reg, sizeof(buf), (u8 *) &buf);
+	if (ret < 0)
+		return ret;
+
+	*val = be16_to_cpu(buf);
+
+	return 0;
+}
+
+static const struct iio_chan_spec vcnl4000_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+	}, {
+		.type = IIO_PROXIMITY,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+	}
+};
+
+static int vcnl4000_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	int ret = -EINVAL;
+	struct vcnl4000_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_LIGHT:
+			ret = vcnl4000_measure(data,
+				VCNL4000_AL_OD, VCNL4000_AL_RDY,
+				VCNL4000_AL_RESULT_HI, val);
+			if (ret < 0)
+				return ret;
+			ret = IIO_VAL_INT;
+			break;
+		case IIO_PROXIMITY:
+			ret = vcnl4000_measure(data,
+				VCNL4000_PS_OD, VCNL4000_PS_RDY,
+				VCNL4000_PS_RESULT_HI, val);
+			if (ret < 0)
+				return ret;
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			break;
+		}
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type == IIO_LIGHT) {
+			*val = 0;
+			*val2 = 250000;
+			ret = IIO_VAL_INT_PLUS_MICRO;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static const struct iio_info vcnl4000_info = {
+	.read_raw = vcnl4000_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit vcnl4000_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct vcnl4000_data *data;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+
+	ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
+	if (ret < 0)
+		goto error_free_dev;
+
+	dev_info(&client->dev, "VCNL4000 Ambient light/proximity sensor, Prod %02x, Rev: %02x\n",
+		ret >> 4, ret & 0xf);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &vcnl4000_info;
+	indio_dev->channels = vcnl4000_channels;
+	indio_dev->num_channels = ARRAY_SIZE(vcnl4000_channels);
+	indio_dev->name = VCNL4000_DRV_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		goto error_free_dev;
+
+	return 0;
+
+error_free_dev:
+	iio_device_free(indio_dev);
+	return ret;
+}
+
+static int __devexit vcnl4000_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static struct i2c_driver vcnl4000_driver = {
+	.driver = {
+		.name   = VCNL4000_DRV_NAME,
+		.owner  = THIS_MODULE,
+	},
+	.probe  = vcnl4000_probe,
+	.remove = __devexit_p(vcnl4000_remove),
+	.id_table = vcnl4000_id,
+};
+
+module_i2c_driver(vcnl4000_driver);
+
+MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
+MODULE_DESCRIPTION("Vishay VCNL4000 proximity/ambient light sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index f658086..70a16c7 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -135,7 +135,7 @@ EXPORT_SYMBOL(input_mt_report_finger_count);
  */
 void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
 {
-	struct input_mt_slot *oldest = 0;
+	struct input_mt_slot *oldest = NULL;
 	int oldid = dev->trkid;
 	int count = 0;
 	int i;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 62bfce4..cbb1add 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -559,7 +559,6 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
 	pdata->rep = !!of_get_property(node, "autorepeat", NULL);
 
 	/* First count the subnodes */
-	pdata->nbuttons = 0;
 	pp = NULL;
 	while ((pp = of_get_next_child(node, pp)))
 		pdata->nbuttons++;
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
index 4ea4341..a880e74 100644
--- a/drivers/input/keyboard/nomadik-ske-keypad.c
+++ b/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -49,6 +49,7 @@
 #define SKE_ASR3	0x2C
 
 #define SKE_NUM_ASRX_REGISTERS	(4)
+#define	KEY_PRESSED_DELAY	10
 
 /**
  * struct ske_keypad  - data structure used by keypad driver
@@ -92,7 +93,7 @@ static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr,
 static int __init ske_keypad_chip_init(struct ske_keypad *keypad)
 {
 	u32 value;
-	int timeout = 50;
+	int timeout = keypad->board->debounce_ms;
 
 	/* check SKE_RIS to be 0 */
 	while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--)
@@ -135,12 +136,37 @@ static int __init ske_keypad_chip_init(struct ske_keypad *keypad)
 	return 0;
 }
 
-static void ske_keypad_read_data(struct ske_keypad *keypad)
+static void ske_keypad_report(struct ske_keypad *keypad, u8 status, int col)
 {
+	int row = 0, code, pos;
 	struct input_dev *input = keypad->input;
-	u16 status;
-	int col = 0, row = 0, code;
-	int ske_asr, ske_ris, key_pressed, i;
+	u32 ske_ris;
+	int key_pressed;
+	int num_of_rows;
+
+	/* find out the row */
+	num_of_rows = hweight8(status);
+	do {
+		pos = __ffs(status);
+		row = pos;
+		status &= ~(1 << pos);
+
+		code = MATRIX_SCAN_CODE(row, col, SKE_KEYPAD_ROW_SHIFT);
+		ske_ris = readl(keypad->reg_base + SKE_RIS);
+		key_pressed = ske_ris & SKE_KPRISA;
+
+		input_event(input, EV_MSC, MSC_SCAN, code);
+		input_report_key(input, keypad->keymap[code], key_pressed);
+		input_sync(input);
+		num_of_rows--;
+	} while (num_of_rows);
+}
+
+static void ske_keypad_read_data(struct ske_keypad *keypad)
+{
+	u8 status;
+	int col = 0;
+	int ske_asr, i;
 
 	/*
 	 * Read the auto scan registers
@@ -154,44 +180,38 @@ static void ske_keypad_read_data(struct ske_keypad *keypad)
 		if (!ske_asr)
 			continue;
 
-		/* now that ASRx is zero, find out the column x and row y*/
-		if (ske_asr & 0xff) {
+		/* now that ASRx is zero, find out the coloumn x and row y */
+		status = ske_asr & 0xff;
+		if (status) {
 			col = i * 2;
-			status = ske_asr & 0xff;
-		} else {
+			ske_keypad_report(keypad, status, col);
+		}
+		status = (ske_asr & 0xff00) >> 8;
+		if (status) {
 			col = (i * 2) + 1;
-			status = (ske_asr & 0xff00) >> 8;
+			ske_keypad_report(keypad, status, col);
 		}
-
-		/* find out the row */
-		row = __ffs(status);
-
-		code = MATRIX_SCAN_CODE(row, col, SKE_KEYPAD_ROW_SHIFT);
-		ske_ris = readl(keypad->reg_base + SKE_RIS);
-		key_pressed = ske_ris & SKE_KPRISA;
-
-		input_event(input, EV_MSC, MSC_SCAN, code);
-		input_report_key(input, keypad->keymap[code], key_pressed);
-		input_sync(input);
 	}
 }
 
 static irqreturn_t ske_keypad_irq(int irq, void *dev_id)
 {
 	struct ske_keypad *keypad = dev_id;
-	int retries = 20;
+	int timeout = keypad->board->debounce_ms;
 
 	/* disable auto scan interrupt; mask the interrupt generated */
 	ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
 	ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA);
 
-	while ((readl(keypad->reg_base + SKE_CR) & SKE_KPASON) && --retries)
-		msleep(5);
+	while ((readl(keypad->reg_base + SKE_CR) & SKE_KPASON) && --timeout)
+		cpu_relax();
 
-	if (retries) {
-		/* SKEx registers are stable and can be read */
-		ske_keypad_read_data(keypad);
-	}
+	/* SKEx registers are stable and can be read */
+	ske_keypad_read_data(keypad);
+
+	/* wait until raw interrupt is clear */
+	while ((readl(keypad->reg_base + SKE_RIS)) && --timeout)
+		msleep(KEY_PRESSED_DELAY);
 
 	/* enable auto scan interrupts */
 	ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index 4ffe64d..2c1c9ed 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -492,7 +492,7 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
 	unsigned int debounce_cnt;
 	u32 val = 0;
 
-	clk_enable(kbc->clk);
+	clk_prepare_enable(kbc->clk);
 
 	/* Reset the KBC controller to clear all previous status.*/
 	tegra_periph_reset_assert(kbc->clk);
@@ -556,7 +556,7 @@ static void tegra_kbc_stop(struct tegra_kbc *kbc)
 	disable_irq(kbc->irq);
 	del_timer_sync(&kbc->timer);
 
-	clk_disable(kbc->clk);
+	clk_disable_unprepare(kbc->clk);
 }
 
 static int tegra_kbc_open(struct input_dev *dev)
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c
index 350fd0c..84ec691 100644
--- a/drivers/input/misc/ab8500-ponkey.c
+++ b/drivers/input/misc/ab8500-ponkey.c
@@ -13,6 +13,7 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/abx500/ab8500.h>
+#include <linux/of.h>
 #include <linux/slab.h>
 
 /**
@@ -131,10 +132,18 @@ static int __devexit ab8500_ponkey_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id ab8500_ponkey_match[] = {
+	{ .compatible = "stericsson,ab8500-ponkey", },
+	{}
+};
+#endif
+
 static struct platform_driver ab8500_ponkey_driver = {
 	.driver		= {
 		.name	= "ab8500-poweron-key",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(ab8500_ponkey_match),
 	},
 	.probe		= ab8500_ponkey_probe,
 	.remove		= __devexit_p(ab8500_ponkey_remove),
diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c
index a3735a0..df9b756 100644
--- a/drivers/input/misc/cma3000_d0x.c
+++ b/drivers/input/misc/cma3000_d0x.c
@@ -58,7 +58,7 @@
 
 /*
  * Bit weights in mg for bit 0, other bits need
- * multipy factor 2^n. Eight bit is the sign bit.
+ * multiply factor 2^n. Eight bit is the sign bit.
  */
 #define BIT_TO_2G  18
 #define BIT_TO_8G  71
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index c34f6c0..c8a288a 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -251,7 +251,6 @@ static int twl6040_vibra_suspend(struct device *dev)
 
 	return 0;
 }
-
 #endif
 
 static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
@@ -259,13 +258,19 @@ static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
 static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
 {
 	struct twl6040_vibra_data *pdata = pdev->dev.platform_data;
-	struct device_node *node = pdev->dev.of_node;
+	struct device *twl6040_core_dev = pdev->dev.parent;
+	struct device_node *twl6040_core_node = NULL;
 	struct vibra_info *info;
 	int vddvibl_uV = 0;
 	int vddvibr_uV = 0;
 	int ret;
 
-	if (!pdata && !node) {
+#ifdef CONFIG_OF
+	twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node,
+						 "vibra");
+#endif
+
+	if (!pdata && !twl6040_core_node) {
 		dev_err(&pdev->dev, "platform_data not available\n");
 		return -EINVAL;
 	}
@@ -287,14 +292,18 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
 		vddvibl_uV = pdata->vddvibl_uV;
 		vddvibr_uV = pdata->vddvibr_uV;
 	} else {
-		of_property_read_u32(node, "vibldrv_res", &info->vibldrv_res);
-		of_property_read_u32(node, "vibrdrv_res", &info->vibrdrv_res);
-		of_property_read_u32(node, "viblmotor_res",
+		of_property_read_u32(twl6040_core_node, "ti,vibldrv-res",
+				     &info->vibldrv_res);
+		of_property_read_u32(twl6040_core_node, "ti,vibrdrv-res",
+				     &info->vibrdrv_res);
+		of_property_read_u32(twl6040_core_node, "ti,viblmotor-res",
 				     &info->viblmotor_res);
-		of_property_read_u32(node, "vibrmotor_res",
+		of_property_read_u32(twl6040_core_node, "ti,vibrmotor-res",
 				     &info->vibrmotor_res);
-		of_property_read_u32(node, "vddvibl_uV", &vddvibl_uV);
-		of_property_read_u32(node, "vddvibr_uV", &vddvibr_uV);
+		of_property_read_u32(twl6040_core_node, "ti,vddvibl-uV",
+				     &vddvibl_uV);
+		of_property_read_u32(twl6040_core_node, "ti,vddvibr-uV",
+				     &vddvibr_uV);
 	}
 
 	if ((!info->vibldrv_res && !info->viblmotor_res) ||
@@ -351,8 +360,12 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
 
 	info->supplies[0].supply = "vddvibl";
 	info->supplies[1].supply = "vddvibr";
-	ret = regulator_bulk_get(info->dev, ARRAY_SIZE(info->supplies),
-				 info->supplies);
+	/*
+	 * When booted with Device tree the regulators are attached to the
+	 * parent device (twl6040 MFD core)
+	 */
+	ret = regulator_bulk_get(pdata ? info->dev : twl6040_core_dev,
+				 ARRAY_SIZE(info->supplies), info->supplies);
 	if (ret) {
 		dev_err(info->dev, "couldn't get regulators %d\n", ret);
 		goto err_regulator;
@@ -418,12 +431,6 @@ static int __devexit twl6040_vibra_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id twl6040_vibra_of_match[] = {
-	{.compatible = "ti,twl6040-vibra", },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, twl6040_vibra_of_match);
-
 static struct platform_driver twl6040_vibra_driver = {
 	.probe		= twl6040_vibra_probe,
 	.remove		= __devexit_p(twl6040_vibra_remove),
@@ -431,7 +438,6 @@ static struct platform_driver twl6040_vibra_driver = {
 		.name	= "twl6040-vibra",
 		.owner	= THIS_MODULE,
 		.pm	= &twl6040_vibra_pm_ops,
-		.of_match_table = twl6040_vibra_of_match,
 	},
 };
 module_platform_driver(twl6040_vibra_driver);
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index cad5602..e7b99a4 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -443,8 +443,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
 	/* ask to report Wacom data */
 	if (features->device_type == BTN_TOOL_FINGER) {
 		/* if it is an MT Tablet PC touch */
-		if (features->type == TABLETPC2FG ||
-		    features->type == MTSCREEN) {
+		if (features->type > TABLETPC) {
 			do {
 				rep_data[0] = 3;
 				rep_data[1] = 4;
@@ -463,7 +462,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
 			} while ((error < 0 || rep_data[1] != 4) &&
 				 limit++ < WAC_MSG_RETRIES);
 		}
-	} else if (features->type != TABLETPC &&
+	} else if (features->type <= BAMBOO_PT &&
 		   features->type != WIRELESS &&
 		   features->device_type == BTN_TOOL_PEN) {
 		do {
@@ -513,10 +512,7 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
 	}
 
 	/* only devices that support touch need to retrieve the info */
-	if (features->type != TABLETPC &&
-	    features->type != TABLETPC2FG &&
-	    features->type != BAMBOO_PT &&
-	    features->type != MTSCREEN) {
+	if (features->type < BAMBOO_PT) {
 		goto out;
 	}
 
@@ -858,6 +854,7 @@ static int wacom_initialize_leds(struct wacom *wacom)
 
 	/* Initialize default values */
 	switch (wacom->wacom_wac.features.type) {
+	case INTUOS4S:
 	case INTUOS4:
 	case INTUOS4L:
 		wacom->led.select[0] = 0;
@@ -911,6 +908,7 @@ static int wacom_initialize_leds(struct wacom *wacom)
 static void wacom_destroy_leds(struct wacom *wacom)
 {
 	switch (wacom->wacom_wac.features.type) {
+	case INTUOS4S:
 	case INTUOS4:
 	case INTUOS4L:
 		sysfs_remove_group(&wacom->intf->dev.kobj,
@@ -970,6 +968,10 @@ static int wacom_initialize_battery(struct wacom *wacom)
 
 		error = power_supply_register(&wacom->usbdev->dev,
 					      &wacom->battery);
+
+		if (!error)
+			power_supply_powers(&wacom->battery,
+					    &wacom->usbdev->dev);
 	}
 
 	return error;
@@ -977,8 +979,11 @@ static int wacom_initialize_battery(struct wacom *wacom)
 
 static void wacom_destroy_battery(struct wacom *wacom)
 {
-	if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR)
+	if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR &&
+	    wacom->battery.dev) {
 		power_supply_unregister(&wacom->battery);
+		wacom->battery.dev = NULL;
+	}
 }
 
 static int wacom_register_input(struct wacom *wacom)
@@ -1025,23 +1030,30 @@ static void wacom_wireless_work(struct work_struct *work)
 	struct wacom *wacom = container_of(work, struct wacom, work);
 	struct usb_device *usbdev = wacom->usbdev;
 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+	struct wacom *wacom1, *wacom2;
+	struct wacom_wac *wacom_wac1, *wacom_wac2;
+	int error;
 
 	/*
 	 * Regardless if this is a disconnect or a new tablet,
-	 * remove any existing input devices.
+	 * remove any existing input and battery devices.
 	 */
 
+	wacom_destroy_battery(wacom);
+
 	/* Stylus interface */
-	wacom = usb_get_intfdata(usbdev->config->interface[1]);
-	if (wacom->wacom_wac.input)
-		input_unregister_device(wacom->wacom_wac.input);
-	wacom->wacom_wac.input = NULL;
+	wacom1 = usb_get_intfdata(usbdev->config->interface[1]);
+	wacom_wac1 = &(wacom1->wacom_wac);
+	if (wacom_wac1->input)
+		input_unregister_device(wacom_wac1->input);
+	wacom_wac1->input = NULL;
 
 	/* Touch interface */
-	wacom = usb_get_intfdata(usbdev->config->interface[2]);
-	if (wacom->wacom_wac.input)
-		input_unregister_device(wacom->wacom_wac.input);
-	wacom->wacom_wac.input = NULL;
+	wacom2 = usb_get_intfdata(usbdev->config->interface[2]);
+	wacom_wac2 = &(wacom2->wacom_wac);
+	if (wacom_wac2->input)
+		input_unregister_device(wacom_wac2->input);
+	wacom_wac2->input = NULL;
 
 	if (wacom_wac->pid == 0) {
 		dev_info(&wacom->intf->dev, "wireless tablet disconnected\n");
@@ -1066,24 +1078,39 @@ static void wacom_wireless_work(struct work_struct *work)
 		}
 
 		/* Stylus interface */
-		wacom = usb_get_intfdata(usbdev->config->interface[1]);
-		wacom_wac = &wacom->wacom_wac;
-		wacom_wac->features =
+		wacom_wac1->features =
 			*((struct wacom_features *)id->driver_info);
-		wacom_wac->features.device_type = BTN_TOOL_PEN;
-		wacom_register_input(wacom);
+		wacom_wac1->features.device_type = BTN_TOOL_PEN;
+		error = wacom_register_input(wacom1);
+		if (error)
+			goto fail1;
 
 		/* Touch interface */
-		wacom = usb_get_intfdata(usbdev->config->interface[2]);
-		wacom_wac = &wacom->wacom_wac;
-		wacom_wac->features =
+		wacom_wac2->features =
 			*((struct wacom_features *)id->driver_info);
-		wacom_wac->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
-		wacom_wac->features.device_type = BTN_TOOL_FINGER;
-		wacom_set_phy_from_res(&wacom_wac->features);
-		wacom_wac->features.x_max = wacom_wac->features.y_max = 4096;
-		wacom_register_input(wacom);
+		wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
+		wacom_wac2->features.device_type = BTN_TOOL_FINGER;
+		wacom_set_phy_from_res(&wacom_wac2->features);
+		wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
+		error = wacom_register_input(wacom2);
+		if (error)
+			goto fail2;
+
+		error = wacom_initialize_battery(wacom);
+		if (error)
+			goto fail3;
 	}
+
+	return;
+
+fail3:
+	input_unregister_device(wacom_wac2->input);
+	wacom_wac2->input = NULL;
+fail2:
+	input_unregister_device(wacom_wac1->input);
+	wacom_wac1->input = NULL;
+fail1:
+	return;
 }
 
 static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -1147,10 +1174,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 			features->device_type = BTN_TOOL_FINGER;
 			features->pktlen = WACOM_PKGLEN_BBTOUCH3;
 
-			features->x_phy =
-				(features->x_max * 100) / features->x_resolution;
-			features->y_phy =
-				(features->y_max * 100) / features->y_resolution;
+			wacom_set_phy_from_res(features);
 
 			features->x_max = 4096;
 			features->y_max = 4096;
@@ -1186,14 +1210,10 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 	if (error)
 		goto fail4;
 
-	error = wacom_initialize_battery(wacom);
-	if (error)
-		goto fail5;
-
 	if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
 		error = wacom_register_input(wacom);
 		if (error)
-			goto fail6;
+			goto fail5;
 	}
 
 	/* Note that if query fails it is not a hard failure */
@@ -1208,7 +1228,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 
 	return 0;
 
- fail6: wacom_destroy_battery(wacom);
  fail5: wacom_destroy_leds(wacom);
  fail4:	wacom_remove_shared_data(wacom_wac);
  fail3:	usb_free_urb(wacom->irq);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 004bc1b..4453864 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -248,7 +248,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
 		input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
 		input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
 		if (wacom->tool[0] != BTN_TOOL_MOUSE) {
-			input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8));
+			input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x03) << 8));
 			input_report_key(input, BTN_TOUCH, data[1] & 0x01);
 			input_report_key(input, BTN_STYLUS, data[1] & 0x02);
 			input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
@@ -888,7 +888,7 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
 			prox = data[0] & 0x01;
 			x = get_unaligned_le16(&data[1]);
 			y = get_unaligned_le16(&data[3]);
-		} else { /* with capacity */
+		} else {
 			prox = data[1] & 0x01;
 			x = le16_to_cpup((__le16 *)&data[2]);
 			y = le16_to_cpup((__le16 *)&data[4]);
@@ -961,6 +961,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
 		case WACOM_REPORT_TPC1FG:
 		case WACOM_REPORT_TPCHID:
 		case WACOM_REPORT_TPCST:
+		case WACOM_REPORT_TPC1FGE:
 			return wacom_tpc_single_touch(wacom, len);
 
 		case WACOM_REPORT_TPCMT:
@@ -1244,6 +1245,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 		break;
 
 	case TABLETPC:
+	case TABLETPCE:
 	case TABLETPC2FG:
 	case MTSCREEN:
 		sync = wacom_tpc_irq(wacom_wac, len);
@@ -1317,10 +1319,8 @@ void wacom_setup_device_quirks(struct wacom_features *features)
 	}
 
 	/* these device have multiple inputs */
-	if (features->type == TABLETPC || features->type == TABLETPC2FG ||
-	    features->type == BAMBOO_PT || features->type == WIRELESS ||
-	    (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
-	    features->type == MTSCREEN)
+	if (features->type >= WIRELESS ||
+	    (features->type >= INTUOS5S && features->type <= INTUOS5L))
 		features->quirks |= WACOM_QUIRK_MULTI_INPUT;
 
 	/* quirk for bamboo touch with 2 low res touches */
@@ -1571,6 +1571,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 		/* fall through */
 
 	case TABLETPC:
+	case TABLETPCE:
 		__clear_bit(ABS_MISC, input_dev->absbit);
 
 		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
@@ -1888,6 +1889,12 @@ static const struct wacom_features wacom_features_0xE6 =
 static const struct wacom_features wacom_features_0xEC =
 	{ "Wacom ISDv4 EC",       WACOM_PKGLEN_GRAPHIRE,  25710, 14500,  255,
 	  0, TABLETPC,    WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xED =
+	{ "Wacom ISDv4 ED",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
+	  0, TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xEF =
+	{ "Wacom ISDv4 EF",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
+	  0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x47 =
 	{ "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023,
 	  31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2062,6 +2069,8 @@ const struct usb_device_id wacom_ids[] = {
 	{ USB_DEVICE_WACOM(0xE5) },
 	{ USB_DEVICE_WACOM(0xE6) },
 	{ USB_DEVICE_WACOM(0xEC) },
+	{ USB_DEVICE_WACOM(0xED) },
+	{ USB_DEVICE_WACOM(0xEF) },
 	{ USB_DEVICE_WACOM(0x47) },
 	{ USB_DEVICE_WACOM(0xF4) },
 	{ USB_DEVICE_LENOVO(0x6004) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 78fbd3f..bd5d37b 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -48,6 +48,7 @@
 #define WACOM_REPORT_TPCMT		13
 #define WACOM_REPORT_TPCHID		15
 #define WACOM_REPORT_TPCST		16
+#define WACOM_REPORT_TPC1FGE		18
 
 /* device quirks */
 #define WACOM_QUIRK_MULTI_INPUT		0x0001
@@ -62,8 +63,6 @@ enum {
 	PTU,
 	PL,
 	DTU,
-	BAMBOO_PT,
-	WIRELESS,
 	INTUOS,
 	INTUOS3S,
 	INTUOS3,
@@ -79,7 +78,10 @@ enum {
 	CINTIQ,
 	WACOM_BEE,
 	WACOM_MO,
-	TABLETPC,
+	WIRELESS,
+	BAMBOO_PT,
+	TABLETPC,   /* add new TPC below */
+	TABLETPCE,
 	TABLETPC2FG,
 	MTSCREEN,
 	MAX_TYPE
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 3408937..9f69b56 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -13,6 +13,10 @@ menuconfig IOMMU_SUPPORT
 
 if IOMMU_SUPPORT
 
+config OF_IOMMU
+       def_bool y
+       depends on OF
+
 # MSM IOMMU support
 config MSM_IOMMU
 	bool "MSM IOMMU Support"
@@ -154,7 +158,7 @@ config TEGRA_IOMMU_GART
 
 config TEGRA_IOMMU_SMMU
 	bool "Tegra SMMU IOMMU Support"
-	depends on ARCH_TEGRA_3x_SOC
+	depends on ARCH_TEGRA_3x_SOC && TEGRA_AHB
 	select IOMMU_API
 	help
 	  Enables support for remapping discontiguous physical memory
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 76e54ef..14a4d5f 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_IOMMU_API) += iommu.o
+obj-$(CONFIG_OF_IOMMU)	+= of_iommu.o
 obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
 obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
 obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index a2e418c..4127b56 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -83,6 +83,8 @@ static struct iommu_ops amd_iommu_ops;
 static ATOMIC_NOTIFIER_HEAD(ppr_notifier);
 int amd_iommu_max_glx_val = -1;
 
+static struct dma_map_ops amd_iommu_dma_ops;
+
 /*
  * general struct to manage commands send to an IOMMU
  */
@@ -254,11 +256,21 @@ static bool check_device(struct device *dev)
 	return true;
 }
 
+static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to)
+{
+	pci_dev_put(*from);
+	*from = to;
+}
+
+#define REQ_ACS_FLAGS	(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
+
 static int iommu_init_device(struct device *dev)
 {
-	struct pci_dev *pdev = to_pci_dev(dev);
+	struct pci_dev *dma_pdev, *pdev = to_pci_dev(dev);
 	struct iommu_dev_data *dev_data;
+	struct iommu_group *group;
 	u16 alias;
+	int ret;
 
 	if (dev->archdata.iommu)
 		return 0;
@@ -279,8 +291,43 @@ static int iommu_init_device(struct device *dev)
 			return -ENOTSUPP;
 		}
 		dev_data->alias_data = alias_data;
+
+		dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff);
+	} else
+		dma_pdev = pci_dev_get(pdev);
+
+	swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
+
+	if (dma_pdev->multifunction &&
+	    !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
+		swap_pci_ref(&dma_pdev,
+			     pci_get_slot(dma_pdev->bus,
+					  PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
+					  0)));
+
+	while (!pci_is_root_bus(dma_pdev->bus)) {
+		if (pci_acs_path_enabled(dma_pdev->bus->self,
+					 NULL, REQ_ACS_FLAGS))
+			break;
+
+		swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self));
+	}
+
+	group = iommu_group_get(&dma_pdev->dev);
+	pci_dev_put(dma_pdev);
+	if (!group) {
+		group = iommu_group_alloc();
+		if (IS_ERR(group))
+			return PTR_ERR(group);
 	}
 
+	ret = iommu_group_add_device(group, dev);
+
+	iommu_group_put(group);
+
+	if (ret)
+		return ret;
+
 	if (pci_iommuv2_capable(pdev)) {
 		struct amd_iommu *iommu;
 
@@ -309,6 +356,8 @@ static void iommu_ignore_device(struct device *dev)
 
 static void iommu_uninit_device(struct device *dev)
 {
+	iommu_group_remove_device(dev);
+
 	/*
 	 * Nothing to do here - we keep dev_data around for unplugged devices
 	 * and reuse it when the device is re-plugged - not doing so would
@@ -2267,6 +2316,13 @@ static int device_change_notifier(struct notifier_block *nb,
 		list_add_tail(&dma_domain->list, &iommu_pd_list);
 		spin_unlock_irqrestore(&iommu_pd_list_lock, flags);
 
+		dev_data = get_dev_data(dev);
+
+		if (!dev_data->passthrough)
+			dev->archdata.dma_ops = &amd_iommu_dma_ops;
+		else
+			dev->archdata.dma_ops = &nommu_dma_ops;
+
 		break;
 	case BUS_NOTIFY_DEL_DEVICE:
 
@@ -3227,26 +3283,6 @@ static int amd_iommu_domain_has_cap(struct iommu_domain *domain,
 	return 0;
 }
 
-static int amd_iommu_device_group(struct device *dev, unsigned int *groupid)
-{
-	struct iommu_dev_data *dev_data = dev->archdata.iommu;
-	struct pci_dev *pdev = to_pci_dev(dev);
-	u16 devid;
-
-	if (!dev_data)
-		return -ENODEV;
-
-	if (pdev->is_virtfn || !iommu_group_mf)
-		devid = dev_data->devid;
-	else
-		devid = calc_devid(pdev->bus->number,
-				   PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
-
-	*groupid = amd_iommu_alias_table[devid];
-
-	return 0;
-}
-
 static struct iommu_ops amd_iommu_ops = {
 	.domain_init = amd_iommu_domain_init,
 	.domain_destroy = amd_iommu_domain_destroy,
@@ -3256,7 +3292,6 @@ static struct iommu_ops amd_iommu_ops = {
 	.unmap = amd_iommu_unmap,
 	.iova_to_phys = amd_iommu_iova_to_phys,
 	.domain_has_cap = amd_iommu_domain_has_cap,
-	.device_group = amd_iommu_device_group,
 	.pgsize_bitmap	= AMD_IOMMU_PGSIZES,
 };
 
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 542024b..c04ddca 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1641,6 +1641,8 @@ static int __init amd_iommu_init(void)
 
 	amd_iommu_init_api();
 
+	x86_platform.iommu_shutdown = disable_iommus;
+
 	if (iommu_pass_through)
 		goto out;
 
@@ -1649,8 +1651,6 @@ static int __init amd_iommu_init(void)
 	else
 		printk(KERN_INFO "AMD-Vi: Lazy IO/TLB flushing enabled\n");
 
-	x86_platform.iommu_shutdown = disable_iommus;
-
 out:
 	return ret;
 
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 3a74e44..86e2f4a 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -26,6 +26,8 @@
  * These routines are used by both DMA-remapping and Interrupt-remapping
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* has to precede printk.h */
+
 #include <linux/pci.h>
 #include <linux/dmar.h>
 #include <linux/iova.h>
@@ -39,8 +41,6 @@
 #include <asm/irq_remapping.h>
 #include <asm/iommu_table.h>
 
-#define PREFIX "DMAR: "
-
 /* No locks are needed as DMA remapping hardware unit
  * list is constructed at boot time and hotplug of
  * these units are not supported by the architecture.
@@ -83,16 +83,12 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
 		 * ignore it
 		 */
 		if (!bus) {
-			printk(KERN_WARNING
-			PREFIX "Device scope bus [%d] not found\n",
-			scope->bus);
+			pr_warn("Device scope bus [%d] not found\n", scope->bus);
 			break;
 		}
 		pdev = pci_get_slot(bus, PCI_DEVFN(path->dev, path->fn));
 		if (!pdev) {
-			printk(KERN_WARNING PREFIX
-			"Device scope device [%04x:%02x:%02x.%02x] not found\n",
-				segment, bus->number, path->dev, path->fn);
+			/* warning will be printed below */
 			break;
 		}
 		path ++;
@@ -100,9 +96,8 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
 		bus = pdev->subordinate;
 	}
 	if (!pdev) {
-		printk(KERN_WARNING PREFIX
-		"Device scope device [%04x:%02x:%02x.%02x] not found\n",
-		segment, scope->bus, path->dev, path->fn);
+		pr_warn("Device scope device [%04x:%02x:%02x.%02x] not found\n",
+			segment, scope->bus, path->dev, path->fn);
 		*dev = NULL;
 		return 0;
 	}
@@ -110,9 +105,8 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
 			pdev->subordinate) || (scope->entry_type == \
 			ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) {
 		pci_dev_put(pdev);
-		printk(KERN_WARNING PREFIX
-			"Device scope type does not match for %s\n",
-			 pci_name(pdev));
+		pr_warn("Device scope type does not match for %s\n",
+			pci_name(pdev));
 		return -EINVAL;
 	}
 	*dev = pdev;
@@ -134,8 +128,7 @@ int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
 		    scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
 			(*cnt)++;
 		else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC) {
-			printk(KERN_WARNING PREFIX
-			       "Unsupported device scope\n");
+			pr_warn("Unsupported device scope\n");
 		}
 		start += scope->length;
 	}
@@ -261,25 +254,23 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
 	case ACPI_DMAR_TYPE_HARDWARE_UNIT:
 		drhd = container_of(header, struct acpi_dmar_hardware_unit,
 				    header);
-		printk (KERN_INFO PREFIX
-			"DRHD base: %#016Lx flags: %#x\n",
+		pr_info("DRHD base: %#016Lx flags: %#x\n",
 			(unsigned long long)drhd->address, drhd->flags);
 		break;
 	case ACPI_DMAR_TYPE_RESERVED_MEMORY:
 		rmrr = container_of(header, struct acpi_dmar_reserved_memory,
 				    header);
-		printk (KERN_INFO PREFIX
-			"RMRR base: %#016Lx end: %#016Lx\n",
+		pr_info("RMRR base: %#016Lx end: %#016Lx\n",
 			(unsigned long long)rmrr->base_address,
 			(unsigned long long)rmrr->end_address);
 		break;
 	case ACPI_DMAR_TYPE_ATSR:
 		atsr = container_of(header, struct acpi_dmar_atsr, header);
-		printk(KERN_INFO PREFIX "ATSR flags: %#x\n", atsr->flags);
+		pr_info("ATSR flags: %#x\n", atsr->flags);
 		break;
 	case ACPI_DMAR_HARDWARE_AFFINITY:
 		rhsa = container_of(header, struct acpi_dmar_rhsa, header);
-		printk(KERN_INFO PREFIX "RHSA base: %#016Lx proximity domain: %#x\n",
+		pr_info("RHSA base: %#016Lx proximity domain: %#x\n",
 		       (unsigned long long)rhsa->base_address,
 		       rhsa->proximity_domain);
 		break;
@@ -299,7 +290,7 @@ static int __init dmar_table_detect(void)
 				&dmar_tbl_size);
 
 	if (ACPI_SUCCESS(status) && !dmar_tbl) {
-		printk (KERN_WARNING PREFIX "Unable to map DMAR\n");
+		pr_warn("Unable to map DMAR\n");
 		status = AE_NOT_FOUND;
 	}
 
@@ -333,20 +324,18 @@ parse_dmar_table(void)
 		return -ENODEV;
 
 	if (dmar->width < PAGE_SHIFT - 1) {
-		printk(KERN_WARNING PREFIX "Invalid DMAR haw\n");
+		pr_warn("Invalid DMAR haw\n");
 		return -EINVAL;
 	}
 
-	printk (KERN_INFO PREFIX "Host address width %d\n",
-		dmar->width + 1);
+	pr_info("Host address width %d\n", dmar->width + 1);
 
 	entry_header = (struct acpi_dmar_header *)(dmar + 1);
 	while (((unsigned long)entry_header) <
 			(((unsigned long)dmar) + dmar_tbl->length)) {
 		/* Avoid looping forever on bad ACPI tables */
 		if (entry_header->length == 0) {
-			printk(KERN_WARNING PREFIX
-				"Invalid 0-length structure\n");
+			pr_warn("Invalid 0-length structure\n");
 			ret = -EINVAL;
 			break;
 		}
@@ -369,8 +358,7 @@ parse_dmar_table(void)
 #endif
 			break;
 		default:
-			printk(KERN_WARNING PREFIX
-				"Unknown DMAR structure type %d\n",
+			pr_warn("Unknown DMAR structure type %d\n",
 				entry_header->type);
 			ret = 0; /* for forward compatibility */
 			break;
@@ -469,12 +457,12 @@ int __init dmar_table_init(void)
 	ret = parse_dmar_table();
 	if (ret) {
 		if (ret != -ENODEV)
-			printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
+			pr_info("parse DMAR table failure.\n");
 		return ret;
 	}
 
 	if (list_empty(&dmar_drhd_units)) {
-		printk(KERN_INFO PREFIX "No DMAR devices found\n");
+		pr_info("No DMAR devices found\n");
 		return -ENODEV;
 	}
 
@@ -506,8 +494,7 @@ int __init check_zero_address(void)
 			(((unsigned long)dmar) + dmar_tbl->length)) {
 		/* Avoid looping forever on bad ACPI tables */
 		if (entry_header->length == 0) {
-			printk(KERN_WARNING PREFIX
-				"Invalid 0-length structure\n");
+			pr_warn("Invalid 0-length structure\n");
 			return 0;
 		}
 
@@ -558,8 +545,7 @@ int __init detect_intel_iommu(void)
 
 		if (ret && irq_remapping_enabled && cpu_has_x2apic &&
 		    dmar->flags & 0x1)
-			printk(KERN_INFO
-			       "Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
+			pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
 
 		if (ret && !no_iommu && !iommu_detected && !dmar_disabled) {
 			iommu_detected = 1;
@@ -579,14 +565,89 @@ int __init detect_intel_iommu(void)
 }
 
 
+static void unmap_iommu(struct intel_iommu *iommu)
+{
+	iounmap(iommu->reg);
+	release_mem_region(iommu->reg_phys, iommu->reg_size);
+}
+
+/**
+ * map_iommu: map the iommu's registers
+ * @iommu: the iommu to map
+ * @phys_addr: the physical address of the base resgister
+ *
+ * Memory map the iommu's registers.  Start w/ a single page, and
+ * possibly expand if that turns out to be insufficent.
+ */
+static int map_iommu(struct intel_iommu *iommu, u64 phys_addr)
+{
+	int map_size, err=0;
+
+	iommu->reg_phys = phys_addr;
+	iommu->reg_size = VTD_PAGE_SIZE;
+
+	if (!request_mem_region(iommu->reg_phys, iommu->reg_size, iommu->name)) {
+		pr_err("IOMMU: can't reserve memory\n");
+		err = -EBUSY;
+		goto out;
+	}
+
+	iommu->reg = ioremap(iommu->reg_phys, iommu->reg_size);
+	if (!iommu->reg) {
+		pr_err("IOMMU: can't map the region\n");
+		err = -ENOMEM;
+		goto release;
+	}
+
+	iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
+	iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
+
+	if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) {
+		err = -EINVAL;
+		warn_invalid_dmar(phys_addr, " returns all ones");
+		goto unmap;
+	}
+
+	/* the registers might be more than one page */
+	map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
+			 cap_max_fault_reg_offset(iommu->cap));
+	map_size = VTD_PAGE_ALIGN(map_size);
+	if (map_size > iommu->reg_size) {
+		iounmap(iommu->reg);
+		release_mem_region(iommu->reg_phys, iommu->reg_size);
+		iommu->reg_size = map_size;
+		if (!request_mem_region(iommu->reg_phys, iommu->reg_size,
+					iommu->name)) {
+			pr_err("IOMMU: can't reserve memory\n");
+			err = -EBUSY;
+			goto out;
+		}
+		iommu->reg = ioremap(iommu->reg_phys, iommu->reg_size);
+		if (!iommu->reg) {
+			pr_err("IOMMU: can't map the region\n");
+			err = -ENOMEM;
+			goto release;
+		}
+	}
+	err = 0;
+	goto out;
+
+unmap:
+	iounmap(iommu->reg);
+release:
+	release_mem_region(iommu->reg_phys, iommu->reg_size);
+out:
+	return err;
+}
+
 int alloc_iommu(struct dmar_drhd_unit *drhd)
 {
 	struct intel_iommu *iommu;
-	int map_size;
 	u32 ver;
 	static int iommu_allocated = 0;
 	int agaw = 0;
 	int msagaw = 0;
+	int err;
 
 	if (!drhd->reg_base_addr) {
 		warn_invalid_dmar(0, "");
@@ -600,30 +661,22 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
 	iommu->seq_id = iommu_allocated++;
 	sprintf (iommu->name, "dmar%d", iommu->seq_id);
 
-	iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE);
-	if (!iommu->reg) {
-		printk(KERN_ERR "IOMMU: can't map the region\n");
+	err = map_iommu(iommu, drhd->reg_base_addr);
+	if (err) {
+		pr_err("IOMMU: failed to map %s\n", iommu->name);
 		goto error;
 	}
-	iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
-	iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
-
-	if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) {
-		warn_invalid_dmar(drhd->reg_base_addr, " returns all ones");
-		goto err_unmap;
-	}
 
+	err = -EINVAL;
 	agaw = iommu_calculate_agaw(iommu);
 	if (agaw < 0) {
-		printk(KERN_ERR
-		       "Cannot get a valid agaw for iommu (seq_id = %d)\n",
-		       iommu->seq_id);
+		pr_err("Cannot get a valid agaw for iommu (seq_id = %d)\n",
+			iommu->seq_id);
 		goto err_unmap;
 	}
 	msagaw = iommu_calculate_max_sagaw(iommu);
 	if (msagaw < 0) {
-		printk(KERN_ERR
-			"Cannot get a valid max agaw for iommu (seq_id = %d)\n",
+		pr_err("Cannot get a valid max agaw for iommu (seq_id = %d)\n",
 			iommu->seq_id);
 		goto err_unmap;
 	}
@@ -632,19 +685,6 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
 
 	iommu->node = -1;
 
-	/* the registers might be more than one page */
-	map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
-		cap_max_fault_reg_offset(iommu->cap));
-	map_size = VTD_PAGE_ALIGN(map_size);
-	if (map_size > VTD_PAGE_SIZE) {
-		iounmap(iommu->reg);
-		iommu->reg = ioremap(drhd->reg_base_addr, map_size);
-		if (!iommu->reg) {
-			printk(KERN_ERR "IOMMU: can't map the region\n");
-			goto error;
-		}
-	}
-
 	ver = readl(iommu->reg + DMAR_VER_REG);
 	pr_info("IOMMU %d: reg_base_addr %llx ver %d:%d cap %llx ecap %llx\n",
 		iommu->seq_id,
@@ -659,10 +699,10 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
 	return 0;
 
  err_unmap:
-	iounmap(iommu->reg);
+	unmap_iommu(iommu);
  error:
 	kfree(iommu);
-	return -1;
+	return err;
 }
 
 void free_iommu(struct intel_iommu *iommu)
@@ -673,7 +713,8 @@ void free_iommu(struct intel_iommu *iommu)
 	free_dmar_iommu(iommu);
 
 	if (iommu->reg)
-		iounmap(iommu->reg);
+		unmap_iommu(iommu);
+
 	kfree(iommu);
 }
 
@@ -710,7 +751,7 @@ static int qi_check_fault(struct intel_iommu *iommu, int index)
 	if (fault & DMA_FSTS_IQE) {
 		head = readl(iommu->reg + DMAR_IQH_REG);
 		if ((head >> DMAR_IQ_SHIFT) == index) {
-			printk(KERN_ERR "VT-d detected invalid descriptor: "
+			pr_err("VT-d detected invalid descriptor: "
 				"low=%llx, high=%llx\n",
 				(unsigned long long)qi->desc[index].low,
 				(unsigned long long)qi->desc[index].high);
@@ -1129,15 +1170,14 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
 	reason = dmar_get_fault_reason(fault_reason, &fault_type);
 
 	if (fault_type == INTR_REMAP)
-		printk(KERN_ERR "INTR-REMAP: Request device [[%02x:%02x.%d] "
+		pr_err("INTR-REMAP: Request device [[%02x:%02x.%d] "
 		       "fault index %llx\n"
 			"INTR-REMAP:[fault reason %02d] %s\n",
 			(source_id >> 8), PCI_SLOT(source_id & 0xFF),
 			PCI_FUNC(source_id & 0xFF), addr >> 48,
 			fault_reason, reason);
 	else
-		printk(KERN_ERR
-		       "DMAR:[%s] Request device [%02x:%02x.%d] "
+		pr_err("DMAR:[%s] Request device [%02x:%02x.%d] "
 		       "fault addr %llx \n"
 		       "DMAR:[fault reason %02d] %s\n",
 		       (type ? "DMA Read" : "DMA Write"),
@@ -1157,8 +1197,7 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
 	raw_spin_lock_irqsave(&iommu->register_lock, flag);
 	fault_status = readl(iommu->reg + DMAR_FSTS_REG);
 	if (fault_status)
-		printk(KERN_ERR "DRHD: handling fault status reg %x\n",
-		       fault_status);
+		pr_err("DRHD: handling fault status reg %x\n", fault_status);
 
 	/* TBD: ignore advanced fault log currently */
 	if (!(fault_status & DMA_FSTS_PPF))
@@ -1224,7 +1263,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
 
 	irq = create_irq();
 	if (!irq) {
-		printk(KERN_ERR "IOMMU: no free vectors\n");
+		pr_err("IOMMU: no free vectors\n");
 		return -EINVAL;
 	}
 
@@ -1241,7 +1280,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
 
 	ret = request_irq(irq, dmar_fault, IRQF_NO_THREAD, iommu->name, iommu);
 	if (ret)
-		printk(KERN_ERR "IOMMU: can't request irq\n");
+		pr_err("IOMMU: can't request irq\n");
 	return ret;
 }
 
@@ -1258,8 +1297,7 @@ int __init enable_drhd_fault_handling(void)
 		ret = dmar_set_interrupt(iommu);
 
 		if (ret) {
-			printk(KERN_ERR "DRHD %Lx: failed to enable fault, "
-			       " interrupt, ret %d\n",
+			pr_err("DRHD %Lx: failed to enable fault, interrupt, ret %d\n",
 			       (unsigned long long)drhd->reg_base_addr, ret);
 			return -1;
 		}
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index b12af2f..6505437 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -661,7 +661,7 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
 			if (drhd->devices[i] &&
 			    drhd->devices[i]->subordinate &&
 			    drhd->devices[i]->subordinate->number <= bus &&
-			    drhd->devices[i]->subordinate->subordinate >= bus)
+			    drhd->devices[i]->subordinate->busn_res.end >= bus)
 				return drhd->iommu;
 		}
 
@@ -4090,52 +4090,70 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
 	return 0;
 }
 
-/*
- * Group numbers are arbitrary.  Device with the same group number
- * indicate the iommu cannot differentiate between them.  To avoid
- * tracking used groups we just use the seg|bus|devfn of the lowest
- * level we're able to differentiate devices
- */
-static int intel_iommu_device_group(struct device *dev, unsigned int *groupid)
+static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to)
 {
-	struct pci_dev *pdev = to_pci_dev(dev);
-	struct pci_dev *bridge;
-	union {
-		struct {
-			u8 devfn;
-			u8 bus;
-			u16 segment;
-		} pci;
-		u32 group;
-	} id;
+	pci_dev_put(*from);
+	*from = to;
+}
 
-	if (iommu_no_mapping(dev))
-		return -ENODEV;
+#define REQ_ACS_FLAGS	(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
 
-	id.pci.segment = pci_domain_nr(pdev->bus);
-	id.pci.bus = pdev->bus->number;
-	id.pci.devfn = pdev->devfn;
+static int intel_iommu_add_device(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct pci_dev *bridge, *dma_pdev;
+	struct iommu_group *group;
+	int ret;
 
-	if (!device_to_iommu(id.pci.segment, id.pci.bus, id.pci.devfn))
+	if (!device_to_iommu(pci_domain_nr(pdev->bus),
+			     pdev->bus->number, pdev->devfn))
 		return -ENODEV;
 
 	bridge = pci_find_upstream_pcie_bridge(pdev);
 	if (bridge) {
-		if (pci_is_pcie(bridge)) {
-			id.pci.bus = bridge->subordinate->number;
-			id.pci.devfn = 0;
-		} else {
-			id.pci.bus = bridge->bus->number;
-			id.pci.devfn = bridge->devfn;
-		}
+		if (pci_is_pcie(bridge))
+			dma_pdev = pci_get_domain_bus_and_slot(
+						pci_domain_nr(pdev->bus),
+						bridge->subordinate->number, 0);
+		else
+			dma_pdev = pci_dev_get(bridge);
+	} else
+		dma_pdev = pci_dev_get(pdev);
+
+	swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
+
+	if (dma_pdev->multifunction &&
+	    !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
+		swap_pci_ref(&dma_pdev,
+			     pci_get_slot(dma_pdev->bus,
+					  PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
+					  0)));
+
+	while (!pci_is_root_bus(dma_pdev->bus)) {
+		if (pci_acs_path_enabled(dma_pdev->bus->self,
+					 NULL, REQ_ACS_FLAGS))
+			break;
+
+		swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self));
+	}
+
+	group = iommu_group_get(&dma_pdev->dev);
+	pci_dev_put(dma_pdev);
+	if (!group) {
+		group = iommu_group_alloc();
+		if (IS_ERR(group))
+			return PTR_ERR(group);
 	}
 
-	if (!pdev->is_virtfn && iommu_group_mf)
-		id.pci.devfn = PCI_DEVFN(PCI_SLOT(id.pci.devfn), 0);
+	ret = iommu_group_add_device(group, dev);
 
-	*groupid = id.group;
+	iommu_group_put(group);
+	return ret;
+}
 
-	return 0;
+static void intel_iommu_remove_device(struct device *dev)
+{
+	iommu_group_remove_device(dev);
 }
 
 static struct iommu_ops intel_iommu_ops = {
@@ -4147,7 +4165,8 @@ static struct iommu_ops intel_iommu_ops = {
 	.unmap		= intel_iommu_unmap,
 	.iova_to_phys	= intel_iommu_iova_to_phys,
 	.domain_has_cap = intel_iommu_domain_has_cap,
-	.device_group	= intel_iommu_device_group,
+	.add_device	= intel_iommu_add_device,
+	.remove_device	= intel_iommu_remove_device,
 	.pgsize_bitmap	= INTEL_IOMMU_PGSIZES,
 };
 
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 6d34706..e0b18f3 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -902,7 +902,6 @@ static int intel_setup_ioapic_entry(int irq,
 	return 0;
 }
 
-#ifdef CONFIG_SMP
 /*
  * Migrate the IO-APIC irq in the presence of intr-remapping.
  *
@@ -924,6 +923,10 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
 	struct irq_cfg *cfg = data->chip_data;
 	unsigned int dest, irq = data->irq;
 	struct irte irte;
+	int err;
+
+	if (!config_enabled(CONFIG_SMP))
+		return -EINVAL;
 
 	if (!cpumask_intersects(mask, cpu_online_mask))
 		return -EINVAL;
@@ -931,10 +934,16 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
 	if (get_irte(irq, &irte))
 		return -EBUSY;
 
-	if (assign_irq_vector(irq, cfg, mask))
-		return -EBUSY;
+	err = assign_irq_vector(irq, cfg, mask);
+	if (err)
+		return err;
 
-	dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask);
+	err = apic->cpu_mask_to_apicid_and(cfg->domain, mask, &dest);
+	if (err) {
+		if (assign_irq_vector(irq, cfg, data->affinity))
+			pr_err("Failed to recover vector for irq %d\n", irq);
+		return err;
+	}
 
 	irte.vector = cfg->vector;
 	irte.dest_id = IRTE_DEST(dest);
@@ -956,7 +965,6 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
 	cpumask_copy(data->affinity, mask);
 	return 0;
 }
-#endif
 
 static void intel_compose_msi_msg(struct pci_dev *pdev,
 				  unsigned int irq, unsigned int dest,
@@ -1058,9 +1066,7 @@ struct irq_remap_ops intel_irq_remap_ops = {
 	.reenable		= reenable_irq_remapping,
 	.enable_faulting	= enable_drhd_fault_handling,
 	.setup_ioapic_entry	= intel_setup_ioapic_entry,
-#ifdef CONFIG_SMP
 	.set_affinity		= intel_ioapic_set_affinity,
-#endif
 	.free_irq		= free_irte,
 	.compose_msi_msg	= intel_compose_msi_msg,
 	.msi_alloc_irq		= intel_msi_alloc_irq,
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 8b9ded8..0e928ac 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -26,60 +26,535 @@
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/iommu.h>
+#include <linux/idr.h>
+#include <linux/notifier.h>
+#include <linux/err.h>
+
+static struct kset *iommu_group_kset;
+static struct ida iommu_group_ida;
+static struct mutex iommu_group_mutex;
+
+struct iommu_group {
+	struct kobject kobj;
+	struct kobject *devices_kobj;
+	struct list_head devices;
+	struct mutex mutex;
+	struct blocking_notifier_head notifier;
+	void *iommu_data;
+	void (*iommu_data_release)(void *iommu_data);
+	char *name;
+	int id;
+};
+
+struct iommu_device {
+	struct list_head list;
+	struct device *dev;
+	char *name;
+};
+
+struct iommu_group_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct iommu_group *group, char *buf);
+	ssize_t (*store)(struct iommu_group *group,
+			 const char *buf, size_t count);
+};
+
+#define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)		\
+struct iommu_group_attribute iommu_group_attr_##_name =		\
+	__ATTR(_name, _mode, _show, _store)
 
-static ssize_t show_iommu_group(struct device *dev,
-				struct device_attribute *attr, char *buf)
+#define to_iommu_group_attr(_attr)	\
+	container_of(_attr, struct iommu_group_attribute, attr)
+#define to_iommu_group(_kobj)		\
+	container_of(_kobj, struct iommu_group, kobj)
+
+static ssize_t iommu_group_attr_show(struct kobject *kobj,
+				     struct attribute *__attr, char *buf)
 {
-	unsigned int groupid;
+	struct iommu_group_attribute *attr = to_iommu_group_attr(__attr);
+	struct iommu_group *group = to_iommu_group(kobj);
+	ssize_t ret = -EIO;
 
-	if (iommu_device_group(dev, &groupid))
-		return 0;
+	if (attr->show)
+		ret = attr->show(group, buf);
+	return ret;
+}
+
+static ssize_t iommu_group_attr_store(struct kobject *kobj,
+				      struct attribute *__attr,
+				      const char *buf, size_t count)
+{
+	struct iommu_group_attribute *attr = to_iommu_group_attr(__attr);
+	struct iommu_group *group = to_iommu_group(kobj);
+	ssize_t ret = -EIO;
 
-	return sprintf(buf, "%u", groupid);
+	if (attr->store)
+		ret = attr->store(group, buf, count);
+	return ret;
 }
-static DEVICE_ATTR(iommu_group, S_IRUGO, show_iommu_group, NULL);
 
-static int add_iommu_group(struct device *dev, void *data)
+static const struct sysfs_ops iommu_group_sysfs_ops = {
+	.show = iommu_group_attr_show,
+	.store = iommu_group_attr_store,
+};
+
+static int iommu_group_create_file(struct iommu_group *group,
+				   struct iommu_group_attribute *attr)
+{
+	return sysfs_create_file(&group->kobj, &attr->attr);
+}
+
+static void iommu_group_remove_file(struct iommu_group *group,
+				    struct iommu_group_attribute *attr)
+{
+	sysfs_remove_file(&group->kobj, &attr->attr);
+}
+
+static ssize_t iommu_group_show_name(struct iommu_group *group, char *buf)
+{
+	return sprintf(buf, "%s\n", group->name);
+}
+
+static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL);
+
+static void iommu_group_release(struct kobject *kobj)
+{
+	struct iommu_group *group = to_iommu_group(kobj);
+
+	if (group->iommu_data_release)
+		group->iommu_data_release(group->iommu_data);
+
+	mutex_lock(&iommu_group_mutex);
+	ida_remove(&iommu_group_ida, group->id);
+	mutex_unlock(&iommu_group_mutex);
+
+	kfree(group->name);
+	kfree(group);
+}
+
+static struct kobj_type iommu_group_ktype = {
+	.sysfs_ops = &iommu_group_sysfs_ops,
+	.release = iommu_group_release,
+};
+
+/**
+ * iommu_group_alloc - Allocate a new group
+ * @name: Optional name to associate with group, visible in sysfs
+ *
+ * This function is called by an iommu driver to allocate a new iommu
+ * group.  The iommu group represents the minimum granularity of the iommu.
+ * Upon successful return, the caller holds a reference to the supplied
+ * group in order to hold the group until devices are added.  Use
+ * iommu_group_put() to release this extra reference count, allowing the
+ * group to be automatically reclaimed once it has no devices or external
+ * references.
+ */
+struct iommu_group *iommu_group_alloc(void)
 {
-	unsigned int groupid;
+	struct iommu_group *group;
+	int ret;
+
+	group = kzalloc(sizeof(*group), GFP_KERNEL);
+	if (!group)
+		return ERR_PTR(-ENOMEM);
+
+	group->kobj.kset = iommu_group_kset;
+	mutex_init(&group->mutex);
+	INIT_LIST_HEAD(&group->devices);
+	BLOCKING_INIT_NOTIFIER_HEAD(&group->notifier);
+
+	mutex_lock(&iommu_group_mutex);
+
+again:
+	if (unlikely(0 == ida_pre_get(&iommu_group_ida, GFP_KERNEL))) {
+		kfree(group);
+		mutex_unlock(&iommu_group_mutex);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	if (-EAGAIN == ida_get_new(&iommu_group_ida, &group->id))
+		goto again;
+
+	mutex_unlock(&iommu_group_mutex);
 
-	if (iommu_device_group(dev, &groupid) == 0)
-		return device_create_file(dev, &dev_attr_iommu_group);
+	ret = kobject_init_and_add(&group->kobj, &iommu_group_ktype,
+				   NULL, "%d", group->id);
+	if (ret) {
+		mutex_lock(&iommu_group_mutex);
+		ida_remove(&iommu_group_ida, group->id);
+		mutex_unlock(&iommu_group_mutex);
+		kfree(group);
+		return ERR_PTR(ret);
+	}
+
+	group->devices_kobj = kobject_create_and_add("devices", &group->kobj);
+	if (!group->devices_kobj) {
+		kobject_put(&group->kobj); /* triggers .release & free */
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/*
+	 * The devices_kobj holds a reference on the group kobject, so
+	 * as long as that exists so will the group.  We can therefore
+	 * use the devices_kobj for reference counting.
+	 */
+	kobject_put(&group->kobj);
+
+	return group;
+}
+EXPORT_SYMBOL_GPL(iommu_group_alloc);
+
+/**
+ * iommu_group_get_iommudata - retrieve iommu_data registered for a group
+ * @group: the group
+ *
+ * iommu drivers can store data in the group for use when doing iommu
+ * operations.  This function provides a way to retrieve it.  Caller
+ * should hold a group reference.
+ */
+void *iommu_group_get_iommudata(struct iommu_group *group)
+{
+	return group->iommu_data;
+}
+EXPORT_SYMBOL_GPL(iommu_group_get_iommudata);
+
+/**
+ * iommu_group_set_iommudata - set iommu_data for a group
+ * @group: the group
+ * @iommu_data: new data
+ * @release: release function for iommu_data
+ *
+ * iommu drivers can store data in the group for use when doing iommu
+ * operations.  This function provides a way to set the data after
+ * the group has been allocated.  Caller should hold a group reference.
+ */
+void iommu_group_set_iommudata(struct iommu_group *group, void *iommu_data,
+			       void (*release)(void *iommu_data))
+{
+	group->iommu_data = iommu_data;
+	group->iommu_data_release = release;
+}
+EXPORT_SYMBOL_GPL(iommu_group_set_iommudata);
+
+/**
+ * iommu_group_set_name - set name for a group
+ * @group: the group
+ * @name: name
+ *
+ * Allow iommu driver to set a name for a group.  When set it will
+ * appear in a name attribute file under the group in sysfs.
+ */
+int iommu_group_set_name(struct iommu_group *group, const char *name)
+{
+	int ret;
+
+	if (group->name) {
+		iommu_group_remove_file(group, &iommu_group_attr_name);
+		kfree(group->name);
+		group->name = NULL;
+		if (!name)
+			return 0;
+	}
+
+	group->name = kstrdup(name, GFP_KERNEL);
+	if (!group->name)
+		return -ENOMEM;
+
+	ret = iommu_group_create_file(group, &iommu_group_attr_name);
+	if (ret) {
+		kfree(group->name);
+		group->name = NULL;
+		return ret;
+	}
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(iommu_group_set_name);
 
-static int remove_iommu_group(struct device *dev)
+/**
+ * iommu_group_add_device - add a device to an iommu group
+ * @group: the group into which to add the device (reference should be held)
+ * @dev: the device
+ *
+ * This function is called by an iommu driver to add a device into a
+ * group.  Adding a device increments the group reference count.
+ */
+int iommu_group_add_device(struct iommu_group *group, struct device *dev)
 {
-	unsigned int groupid;
+	int ret, i = 0;
+	struct iommu_device *device;
+
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (!device)
+		return -ENOMEM;
+
+	device->dev = dev;
 
-	if (iommu_device_group(dev, &groupid) == 0)
-		device_remove_file(dev, &dev_attr_iommu_group);
+	ret = sysfs_create_link(&dev->kobj, &group->kobj, "iommu_group");
+	if (ret) {
+		kfree(device);
+		return ret;
+	}
+
+	device->name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj));
+rename:
+	if (!device->name) {
+		sysfs_remove_link(&dev->kobj, "iommu_group");
+		kfree(device);
+		return -ENOMEM;
+	}
 
+	ret = sysfs_create_link_nowarn(group->devices_kobj,
+				       &dev->kobj, device->name);
+	if (ret) {
+		kfree(device->name);
+		if (ret == -EEXIST && i >= 0) {
+			/*
+			 * Account for the slim chance of collision
+			 * and append an instance to the name.
+			 */
+			device->name = kasprintf(GFP_KERNEL, "%s.%d",
+						 kobject_name(&dev->kobj), i++);
+			goto rename;
+		}
+
+		sysfs_remove_link(&dev->kobj, "iommu_group");
+		kfree(device);
+		return ret;
+	}
+
+	kobject_get(group->devices_kobj);
+
+	dev->iommu_group = group;
+
+	mutex_lock(&group->mutex);
+	list_add_tail(&device->list, &group->devices);
+	mutex_unlock(&group->mutex);
+
+	/* Notify any listeners about change to group. */
+	blocking_notifier_call_chain(&group->notifier,
+				     IOMMU_GROUP_NOTIFY_ADD_DEVICE, dev);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(iommu_group_add_device);
 
-static int iommu_device_notifier(struct notifier_block *nb,
-				 unsigned long action, void *data)
+/**
+ * iommu_group_remove_device - remove a device from it's current group
+ * @dev: device to be removed
+ *
+ * This function is called by an iommu driver to remove the device from
+ * it's current group.  This decrements the iommu group reference count.
+ */
+void iommu_group_remove_device(struct device *dev)
+{
+	struct iommu_group *group = dev->iommu_group;
+	struct iommu_device *tmp_device, *device = NULL;
+
+	/* Pre-notify listeners that a device is being removed. */
+	blocking_notifier_call_chain(&group->notifier,
+				     IOMMU_GROUP_NOTIFY_DEL_DEVICE, dev);
+
+	mutex_lock(&group->mutex);
+	list_for_each_entry(tmp_device, &group->devices, list) {
+		if (tmp_device->dev == dev) {
+			device = tmp_device;
+			list_del(&device->list);
+			break;
+		}
+	}
+	mutex_unlock(&group->mutex);
+
+	if (!device)
+		return;
+
+	sysfs_remove_link(group->devices_kobj, device->name);
+	sysfs_remove_link(&dev->kobj, "iommu_group");
+
+	kfree(device->name);
+	kfree(device);
+	dev->iommu_group = NULL;
+	kobject_put(group->devices_kobj);
+}
+EXPORT_SYMBOL_GPL(iommu_group_remove_device);
+
+/**
+ * iommu_group_for_each_dev - iterate over each device in the group
+ * @group: the group
+ * @data: caller opaque data to be passed to callback function
+ * @fn: caller supplied callback function
+ *
+ * This function is called by group users to iterate over group devices.
+ * Callers should hold a reference count to the group during callback.
+ * The group->mutex is held across callbacks, which will block calls to
+ * iommu_group_add/remove_device.
+ */
+int iommu_group_for_each_dev(struct iommu_group *group, void *data,
+			     int (*fn)(struct device *, void *))
+{
+	struct iommu_device *device;
+	int ret = 0;
+
+	mutex_lock(&group->mutex);
+	list_for_each_entry(device, &group->devices, list) {
+		ret = fn(device->dev, data);
+		if (ret)
+			break;
+	}
+	mutex_unlock(&group->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_group_for_each_dev);
+
+/**
+ * iommu_group_get - Return the group for a device and increment reference
+ * @dev: get the group that this device belongs to
+ *
+ * This function is called by iommu drivers and users to get the group
+ * for the specified device.  If found, the group is returned and the group
+ * reference in incremented, else NULL.
+ */
+struct iommu_group *iommu_group_get(struct device *dev)
+{
+	struct iommu_group *group = dev->iommu_group;
+
+	if (group)
+		kobject_get(group->devices_kobj);
+
+	return group;
+}
+EXPORT_SYMBOL_GPL(iommu_group_get);
+
+/**
+ * iommu_group_put - Decrement group reference
+ * @group: the group to use
+ *
+ * This function is called by iommu drivers and users to release the
+ * iommu group.  Once the reference count is zero, the group is released.
+ */
+void iommu_group_put(struct iommu_group *group)
+{
+	if (group)
+		kobject_put(group->devices_kobj);
+}
+EXPORT_SYMBOL_GPL(iommu_group_put);
+
+/**
+ * iommu_group_register_notifier - Register a notifier for group changes
+ * @group: the group to watch
+ * @nb: notifier block to signal
+ *
+ * This function allows iommu group users to track changes in a group.
+ * See include/linux/iommu.h for actions sent via this notifier.  Caller
+ * should hold a reference to the group throughout notifier registration.
+ */
+int iommu_group_register_notifier(struct iommu_group *group,
+				  struct notifier_block *nb)
+{
+	return blocking_notifier_chain_register(&group->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(iommu_group_register_notifier);
+
+/**
+ * iommu_group_unregister_notifier - Unregister a notifier
+ * @group: the group to watch
+ * @nb: notifier block to signal
+ *
+ * Unregister a previously registered group notifier block.
+ */
+int iommu_group_unregister_notifier(struct iommu_group *group,
+				    struct notifier_block *nb)
+{
+	return blocking_notifier_chain_unregister(&group->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(iommu_group_unregister_notifier);
+
+/**
+ * iommu_group_id - Return ID for a group
+ * @group: the group to ID
+ *
+ * Return the unique ID for the group matching the sysfs group number.
+ */
+int iommu_group_id(struct iommu_group *group)
+{
+	return group->id;
+}
+EXPORT_SYMBOL_GPL(iommu_group_id);
+
+static int add_iommu_group(struct device *dev, void *data)
+{
+	struct iommu_ops *ops = data;
+
+	if (!ops->add_device)
+		return -ENODEV;
+
+	WARN_ON(dev->iommu_group);
+
+	ops->add_device(dev);
+
+	return 0;
+}
+
+static int iommu_bus_notifier(struct notifier_block *nb,
+			      unsigned long action, void *data)
 {
 	struct device *dev = data;
+	struct iommu_ops *ops = dev->bus->iommu_ops;
+	struct iommu_group *group;
+	unsigned long group_action = 0;
+
+	/*
+	 * ADD/DEL call into iommu driver ops if provided, which may
+	 * result in ADD/DEL notifiers to group->notifier
+	 */
+	if (action == BUS_NOTIFY_ADD_DEVICE) {
+		if (ops->add_device)
+			return ops->add_device(dev);
+	} else if (action == BUS_NOTIFY_DEL_DEVICE) {
+		if (ops->remove_device && dev->iommu_group) {
+			ops->remove_device(dev);
+			return 0;
+		}
+	}
 
-	if (action == BUS_NOTIFY_ADD_DEVICE)
-		return add_iommu_group(dev, NULL);
-	else if (action == BUS_NOTIFY_DEL_DEVICE)
-		return remove_iommu_group(dev);
+	/*
+	 * Remaining BUS_NOTIFYs get filtered and republished to the
+	 * group, if anyone is listening
+	 */
+	group = iommu_group_get(dev);
+	if (!group)
+		return 0;
 
+	switch (action) {
+	case BUS_NOTIFY_BIND_DRIVER:
+		group_action = IOMMU_GROUP_NOTIFY_BIND_DRIVER;
+		break;
+	case BUS_NOTIFY_BOUND_DRIVER:
+		group_action = IOMMU_GROUP_NOTIFY_BOUND_DRIVER;
+		break;
+	case BUS_NOTIFY_UNBIND_DRIVER:
+		group_action = IOMMU_GROUP_NOTIFY_UNBIND_DRIVER;
+		break;
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		group_action = IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER;
+		break;
+	}
+
+	if (group_action)
+		blocking_notifier_call_chain(&group->notifier,
+					     group_action, dev);
+
+	iommu_group_put(group);
 	return 0;
 }
 
-static struct notifier_block iommu_device_nb = {
-	.notifier_call = iommu_device_notifier,
+static struct notifier_block iommu_bus_nb = {
+	.notifier_call = iommu_bus_notifier,
 };
 
 static void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops)
 {
-	bus_register_notifier(bus, &iommu_device_nb);
-	bus_for_each_dev(bus, NULL, NULL, add_iommu_group);
+	bus_register_notifier(bus, &iommu_bus_nb);
+	bus_for_each_dev(bus, NULL, ops, add_iommu_group);
 }
 
 /**
@@ -192,6 +667,45 @@ void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
 }
 EXPORT_SYMBOL_GPL(iommu_detach_device);
 
+/*
+ * IOMMU groups are really the natrual working unit of the IOMMU, but
+ * the IOMMU API works on domains and devices.  Bridge that gap by
+ * iterating over the devices in a group.  Ideally we'd have a single
+ * device which represents the requestor ID of the group, but we also
+ * allow IOMMU drivers to create policy defined minimum sets, where
+ * the physical hardware may be able to distiguish members, but we
+ * wish to group them at a higher level (ex. untrusted multi-function
+ * PCI devices).  Thus we attach each device.
+ */
+static int iommu_group_do_attach_device(struct device *dev, void *data)
+{
+	struct iommu_domain *domain = data;
+
+	return iommu_attach_device(domain, dev);
+}
+
+int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group)
+{
+	return iommu_group_for_each_dev(group, domain,
+					iommu_group_do_attach_device);
+}
+EXPORT_SYMBOL_GPL(iommu_attach_group);
+
+static int iommu_group_do_detach_device(struct device *dev, void *data)
+{
+	struct iommu_domain *domain = data;
+
+	iommu_detach_device(domain, dev);
+
+	return 0;
+}
+
+void iommu_detach_group(struct iommu_domain *domain, struct iommu_group *group)
+{
+	iommu_group_for_each_dev(group, domain, iommu_group_do_detach_device);
+}
+EXPORT_SYMBOL_GPL(iommu_detach_group);
+
 phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
 			       unsigned long iova)
 {
@@ -336,11 +850,15 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 }
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
-int iommu_device_group(struct device *dev, unsigned int *groupid)
+static int __init iommu_init(void)
 {
-	if (iommu_present(dev->bus) && dev->bus->iommu_ops->device_group)
-		return dev->bus->iommu_ops->device_group(dev, groupid);
+	iommu_group_kset = kset_create_and_add("iommu_groups",
+					       NULL, kernel_kobj);
+	ida_init(&iommu_group_ida);
+	mutex_init(&iommu_group_mutex);
 
-	return -ENODEV;
+	BUG_ON(!iommu_group_kset);
+
+	return 0;
 }
-EXPORT_SYMBOL_GPL(iommu_device_group);
+subsys_initcall(iommu_init);
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index 40cda8e..1d29b1c 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -111,16 +111,15 @@ int setup_ioapic_remapped_entry(int irq,
 					     vector, attr);
 }
 
-#ifdef CONFIG_SMP
 int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask,
 			      bool force)
 {
-	if (!remap_ops || !remap_ops->set_affinity)
+	if (!config_enabled(CONFIG_SMP) || !remap_ops ||
+	    !remap_ops->set_affinity)
 		return 0;
 
 	return remap_ops->set_affinity(data, mask, force);
 }
-#endif
 
 void free_remapped_irq(int irq)
 {
diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h
index be9d729..b12974c 100644
--- a/drivers/iommu/irq_remapping.h
+++ b/drivers/iommu/irq_remapping.h
@@ -59,11 +59,9 @@ struct irq_remap_ops {
 				  unsigned int, int,
 				  struct io_apic_irq_attr *);
 
-#ifdef CONFIG_SMP
 	/* Set the CPU affinity of a remapped interrupt */
 	int (*set_affinity)(struct irq_data *data, const struct cpumask *mask,
 			    bool force);
-#endif
 
 	/* Free an IRQ */
 	int (*free_irq)(int);
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
new file mode 100644
index 0000000..ee249bc
--- /dev/null
+++ b/drivers/iommu/of_iommu.c
@@ -0,0 +1,90 @@
+/*
+ * OF helpers for IOMMU
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/export.h>
+#include <linux/limits.h>
+#include <linux/of.h>
+
+/**
+ * of_get_dma_window - Parse *dma-window property and returns 0 if found.
+ *
+ * @dn: device node
+ * @prefix: prefix for property name if any
+ * @index: index to start to parse
+ * @busno: Returns busno if supported. Otherwise pass NULL
+ * @addr: Returns address that DMA starts
+ * @size: Returns the range that DMA can handle
+ *
+ * This supports different formats flexibly. "prefix" can be
+ * configured if any. "busno" and "index" are optionally
+ * specified. Set 0(or NULL) if not used.
+ */
+int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
+		      unsigned long *busno, dma_addr_t *addr, size_t *size)
+{
+	const __be32 *dma_window, *end;
+	int bytes, cur_index = 0;
+	char propname[NAME_MAX], addrname[NAME_MAX], sizename[NAME_MAX];
+
+	if (!dn || !addr || !size)
+		return -EINVAL;
+
+	if (!prefix)
+		prefix = "";
+
+	snprintf(propname, sizeof(propname), "%sdma-window", prefix);
+	snprintf(addrname, sizeof(addrname), "%s#dma-address-cells", prefix);
+	snprintf(sizename, sizeof(sizename), "%s#dma-size-cells", prefix);
+
+	dma_window = of_get_property(dn, propname, &bytes);
+	if (!dma_window)
+		return -ENODEV;
+	end = dma_window + bytes / sizeof(*dma_window);
+
+	while (dma_window < end) {
+		u32 cells;
+		const void *prop;
+
+		/* busno is one cell if supported */
+		if (busno)
+			*busno = be32_to_cpup(dma_window++);
+
+		prop = of_get_property(dn, addrname, NULL);
+		if (!prop)
+			prop = of_get_property(dn, "#address-cells", NULL);
+
+		cells = prop ? be32_to_cpup(prop) : of_n_addr_cells(dn);
+		if (!cells)
+			return -EINVAL;
+		*addr = of_read_number(dma_window, cells);
+		dma_window += cells;
+
+		prop = of_get_property(dn, sizename, NULL);
+		cells = prop ? be32_to_cpup(prop) : of_n_size_cells(dn);
+		if (!cells)
+			return -EINVAL;
+		*size = of_read_number(dma_window, cells);
+		dma_window += cells;
+
+		if (cur_index++ == index)
+			break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_get_dma_window);
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index ecd6790..becfc61 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -30,12 +30,15 @@
 #include <linux/sched.h>
 #include <linux/iommu.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_iommu.h>
 
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 
 #include <mach/iomap.h>
 #include <mach/smmu.h>
+#include <mach/tegra-ahb.h>
 
 /* bitmap of the page sizes currently supported */
 #define SMMU_IOMMU_PGSIZES	(SZ_4K)
@@ -111,12 +114,6 @@
 
 #define SMMU_PDE_NEXT_SHIFT		28
 
-/* AHB Arbiter Registers */
-#define AHB_XBAR_CTRL				0xe0
-#define AHB_XBAR_CTRL_SMMU_INIT_DONE_DONE	1
-#define AHB_XBAR_CTRL_SMMU_INIT_DONE_SHIFT	17
-
-#define SMMU_NUM_ASIDS				4
 #define SMMU_TLB_FLUSH_VA_SECTION__MASK		0xffc00000
 #define SMMU_TLB_FLUSH_VA_SECTION__SHIFT	12 /* right shift */
 #define SMMU_TLB_FLUSH_VA_GROUP__MASK		0xffffc000
@@ -136,6 +133,7 @@
 
 #define SMMU_PAGE_SHIFT 12
 #define SMMU_PAGE_SIZE	(1 << SMMU_PAGE_SHIFT)
+#define SMMU_PAGE_MASK	((1 << SMMU_PAGE_SHIFT) - 1)
 
 #define SMMU_PDIR_COUNT	1024
 #define SMMU_PDIR_SIZE	(sizeof(unsigned long) * SMMU_PDIR_COUNT)
@@ -177,6 +175,8 @@
 #define SMMU_ASID_DISABLE	0
 #define SMMU_ASID_ASID(n)	((n) & ~SMMU_ASID_ENABLE(0))
 
+#define NUM_SMMU_REG_BANKS	3
+
 #define smmu_client_enable_hwgrp(c, m)	smmu_client_set_hwgrp(c, m, 1)
 #define smmu_client_disable_hwgrp(c)	smmu_client_set_hwgrp(c, 0, 0)
 #define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1)
@@ -235,14 +235,12 @@ struct smmu_as {
  * Per SMMU device - IOMMU device
  */
 struct smmu_device {
-	void __iomem	*regs, *regs_ahbarb;
+	void __iomem	*regs[NUM_SMMU_REG_BANKS];
 	unsigned long	iovmm_base;	/* remappable base address */
 	unsigned long	page_count;	/* total remappable size */
 	spinlock_t	lock;
 	char		*name;
 	struct device	*dev;
-	int		num_as;
-	struct smmu_as	*as;		/* Run-time allocated array */
 	struct page *avp_vector_page;	/* dummy page shared by all AS's */
 
 	/*
@@ -252,29 +250,50 @@ struct smmu_device {
 	unsigned long translation_enable_1;
 	unsigned long translation_enable_2;
 	unsigned long asid_security;
+
+	struct device_node *ahb;
+
+	int		num_as;
+	struct smmu_as	as[0];		/* Run-time allocated array */
 };
 
 static struct smmu_device *smmu_handle; /* unique for a system */
 
 /*
- *	SMMU/AHB register accessors
+ *	SMMU register accessors
  */
 static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
 {
-	return readl(smmu->regs + offs);
-}
-static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
-{
-	writel(val, smmu->regs + offs);
+	BUG_ON(offs < 0x10);
+	if (offs < 0x3c)
+		return readl(smmu->regs[0] + offs - 0x10);
+	BUG_ON(offs < 0x1f0);
+	if (offs < 0x200)
+		return readl(smmu->regs[1] + offs - 0x1f0);
+	BUG_ON(offs < 0x228);
+	if (offs < 0x284)
+		return readl(smmu->regs[2] + offs - 0x228);
+	BUG();
 }
 
-static inline u32 ahb_read(struct smmu_device *smmu, size_t offs)
-{
-	return readl(smmu->regs_ahbarb + offs);
-}
-static inline void ahb_write(struct smmu_device *smmu, u32 val, size_t offs)
+static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
 {
-	writel(val, smmu->regs_ahbarb + offs);
+	BUG_ON(offs < 0x10);
+	if (offs < 0x3c) {
+		writel(val, smmu->regs[0] + offs - 0x10);
+		return;
+	}
+	BUG_ON(offs < 0x1f0);
+	if (offs < 0x200) {
+		writel(val, smmu->regs[1] + offs - 0x1f0);
+		return;
+	}
+	BUG_ON(offs < 0x228);
+	if (offs < 0x284) {
+		writel(val, smmu->regs[2] + offs - 0x228);
+		return;
+	}
+	BUG();
 }
 
 #define VA_PAGE_TO_PA(va, page)	\
@@ -370,7 +389,7 @@ static void smmu_flush_regs(struct smmu_device *smmu, int enable)
 	FLUSH_SMMU_REGS(smmu);
 }
 
-static void smmu_setup_regs(struct smmu_device *smmu)
+static int smmu_setup_regs(struct smmu_device *smmu)
 {
 	int i;
 	u32 val;
@@ -398,10 +417,7 @@ static void smmu_setup_regs(struct smmu_device *smmu)
 
 	smmu_flush_regs(smmu, 1);
 
-	val = ahb_read(smmu, AHB_XBAR_CTRL);
-	val |= AHB_XBAR_CTRL_SMMU_INIT_DONE_DONE <<
-		AHB_XBAR_CTRL_SMMU_INIT_DONE_SHIFT;
-	ahb_write(smmu, val, AHB_XBAR_CTRL);
+	return tegra_ahb_enable_smmu(smmu->ahb);
 }
 
 static void flush_ptc_and_tlb(struct smmu_device *smmu,
@@ -873,65 +889,73 @@ static int tegra_smmu_resume(struct device *dev)
 {
 	struct smmu_device *smmu = dev_get_drvdata(dev);
 	unsigned long flags;
+	int err;
 
 	spin_lock_irqsave(&smmu->lock, flags);
-	smmu_setup_regs(smmu);
+	err = smmu_setup_regs(smmu);
 	spin_unlock_irqrestore(&smmu->lock, flags);
-	return 0;
+	return err;
 }
 
 static int tegra_smmu_probe(struct platform_device *pdev)
 {
 	struct smmu_device *smmu;
-	struct resource *regs, *regs2, *window;
 	struct device *dev = &pdev->dev;
-	int i, err = 0;
+	int i, asids, err = 0;
+	dma_addr_t uninitialized_var(base);
+	size_t bytes, uninitialized_var(size);
 
 	if (smmu_handle)
 		return -EIO;
 
 	BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT);
 
-	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	regs2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	window = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-	if (!regs || !regs2 || !window) {
-		dev_err(dev, "No SMMU resources\n");
+	if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
 		return -ENODEV;
-	}
 
-	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
+	bytes = sizeof(*smmu) + asids * sizeof(*smmu->as);
+	smmu = devm_kzalloc(dev, bytes, GFP_KERNEL);
 	if (!smmu) {
 		dev_err(dev, "failed to allocate smmu_device\n");
 		return -ENOMEM;
 	}
 
-	smmu->dev = dev;
-	smmu->num_as = SMMU_NUM_ASIDS;
-	smmu->iovmm_base = (unsigned long)window->start;
-	smmu->page_count = resource_size(window) >> SMMU_PAGE_SHIFT;
-	smmu->regs = devm_ioremap(dev, regs->start, resource_size(regs));
-	smmu->regs_ahbarb = devm_ioremap(dev, regs2->start,
-					 resource_size(regs2));
-	if (!smmu->regs || !smmu->regs_ahbarb) {
-		dev_err(dev, "failed to remap SMMU registers\n");
-		err = -ENXIO;
-		goto fail;
+	for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
+		struct resource *res;
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res)
+			return -ENODEV;
+		smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
+		if (!smmu->regs[i])
+			return -EBUSY;
 	}
 
+	err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
+	if (err)
+		return -ENODEV;
+
+	if (size & SMMU_PAGE_MASK)
+		return -EINVAL;
+
+	size >>= SMMU_PAGE_SHIFT;
+	if (!size)
+		return -EINVAL;
+
+	smmu->ahb = of_parse_phandle(dev->of_node, "nvidia,ahb", 0);
+	if (!smmu->ahb)
+		return -ENODEV;
+
+	smmu->dev = dev;
+	smmu->num_as = asids;
+	smmu->iovmm_base = base;
+	smmu->page_count = size;
+
 	smmu->translation_enable_0 = ~0;
 	smmu->translation_enable_1 = ~0;
 	smmu->translation_enable_2 = ~0;
 	smmu->asid_security = 0;
 
-	smmu->as = devm_kzalloc(dev,
-			sizeof(smmu->as[0]) * smmu->num_as, GFP_KERNEL);
-	if (!smmu->as) {
-		dev_err(dev, "failed to allocate smmu_as\n");
-		err = -ENOMEM;
-		goto fail;
-	}
-
 	for (i = 0; i < smmu->num_as; i++) {
 		struct smmu_as *as = &smmu->as[i];
 
@@ -945,57 +969,28 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		INIT_LIST_HEAD(&as->client);
 	}
 	spin_lock_init(&smmu->lock);
-	smmu_setup_regs(smmu);
+	err = smmu_setup_regs(smmu);
+	if (err)
+		return err;
 	platform_set_drvdata(pdev, smmu);
 
 	smmu->avp_vector_page = alloc_page(GFP_KERNEL);
 	if (!smmu->avp_vector_page)
-		goto fail;
+		return -ENOMEM;
 
 	smmu_handle = smmu;
 	return 0;
-
-fail:
-	if (smmu->avp_vector_page)
-		__free_page(smmu->avp_vector_page);
-	if (smmu->regs)
-		devm_iounmap(dev, smmu->regs);
-	if (smmu->regs_ahbarb)
-		devm_iounmap(dev, smmu->regs_ahbarb);
-	if (smmu && smmu->as) {
-		for (i = 0; i < smmu->num_as; i++) {
-			if (smmu->as[i].pdir_page) {
-				ClearPageReserved(smmu->as[i].pdir_page);
-				__free_page(smmu->as[i].pdir_page);
-			}
-		}
-		devm_kfree(dev, smmu->as);
-	}
-	devm_kfree(dev, smmu);
-	return err;
 }
 
 static int tegra_smmu_remove(struct platform_device *pdev)
 {
 	struct smmu_device *smmu = platform_get_drvdata(pdev);
-	struct device *dev = smmu->dev;
+	int i;
 
 	smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG);
-	platform_set_drvdata(pdev, NULL);
-	if (smmu->as) {
-		int i;
-
-		for (i = 0; i < smmu->num_as; i++)
-			free_pdir(&smmu->as[i]);
-		devm_kfree(dev, smmu->as);
-	}
-	if (smmu->avp_vector_page)
-		__free_page(smmu->avp_vector_page);
-	if (smmu->regs)
-		devm_iounmap(dev, smmu->regs);
-	if (smmu->regs_ahbarb)
-		devm_iounmap(dev, smmu->regs_ahbarb);
-	devm_kfree(dev, smmu);
+	for (i = 0; i < smmu->num_as; i++)
+		free_pdir(&smmu->as[i]);
+	__free_page(smmu->avp_vector_page);
 	smmu_handle = NULL;
 	return 0;
 }
@@ -1005,6 +1000,14 @@ const struct dev_pm_ops tegra_smmu_pm_ops = {
 	.resume		= tegra_smmu_resume,
 };
 
+#ifdef CONFIG_OF
+static struct of_device_id tegra_smmu_of_match[] __devinitdata = {
+	{ .compatible = "nvidia,tegra30-smmu", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tegra_smmu_of_match);
+#endif
+
 static struct platform_driver tegra_smmu_driver = {
 	.probe		= tegra_smmu_probe,
 	.remove		= tegra_smmu_remove,
@@ -1012,6 +1015,7 @@ static struct platform_driver tegra_smmu_driver = {
 		.owner	= THIS_MODULE,
 		.name	= "tegra-smmu",
 		.pm	= &tegra_smmu_pm_ops,
+		.of_match_table = of_match_ptr(tegra_smmu_of_match),
 	},
 };
 
@@ -1031,4 +1035,5 @@ module_exit(tegra_smmu_exit);
 
 MODULE_DESCRIPTION("IOMMU API for SMMU in Tegra30");
 MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_ALIAS("platform:tegra-smmu");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 12b2b55..4c4be90 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -415,6 +415,14 @@ config LEDS_MAX8997
 	  This option enables support for on-chip LED drivers on
 	  MAXIM MAX8997 PMIC.
 
+config LEDS_LM3556
+	tristate "LED support for LM3556 Chip"
+	depends on LEDS_CLASS && I2C
+	select REGMAP_I2C
+	help
+	  This option enables support for LEDs connected to LM3556.
+	  LM3556 includes Torch, Flash and Indicator functions.
+
 config LEDS_OT200
 	tristate "LED support for the Bachmann OT200"
 	depends on LEDS_CLASS && HAS_IOMEM
@@ -443,6 +451,20 @@ config LEDS_TRIGGER_TIMER
 
 	  If unsure, say Y.
 
+config LEDS_TRIGGER_ONESHOT
+	tristate "LED One-shot Trigger"
+	depends on LEDS_TRIGGERS
+	help
+	  This allows LEDs to blink in one-shot pulses with parameters
+	  controlled via sysfs.  It's useful to notify the user on
+	  sporadic events, when there are no clear begin and end trap points,
+	  or on dense events, where this blinks the LED at constant rate if
+	  rearmed continuously.
+
+	  It also shows how to use the led_blink_set_oneshot() function.
+
+	  If unsure, say Y.
+
 config LEDS_TRIGGER_IDE_DISK
 	bool "LED IDE Disk Trigger"
 	depends on IDE_GD_ATA
@@ -469,6 +491,16 @@ config LEDS_TRIGGER_BACKLIGHT
 
 	  If unsure, say N.
 
+config LEDS_TRIGGER_CPU
+	tristate "LED CPU Trigger"
+	depends on LEDS_TRIGGERS
+	help
+	  This allows LEDs to be controlled by active CPUs. This shows
+	  the active CPUs across an array of LEDs so you can see which
+	  CPUs are active on the system at any given moment.
+
+	  If unsure, say N.
+
 config LEDS_TRIGGER_GPIO
 	tristate "LED GPIO Trigger"
 	depends on LEDS_TRIGGERS
@@ -497,7 +529,7 @@ config LEDS_TRIGGER_TRANSIENT
 	depends on LEDS_TRIGGERS
 	help
 	  This allows one time activation of a transient state on
-	  GPIO/PWM based hadrware.
+	  GPIO/PWM based hardware.
 	  If unsure, say Y.
 
 endif # NEW_LEDS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index f8958cd..c93ad73 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -47,15 +47,18 @@ obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
 obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o
 obj-$(CONFIG_LEDS_RENESAS_TPU)		+= leds-renesas-tpu.o
 obj-$(CONFIG_LEDS_MAX8997)		+= leds-max8997.o
+obj-$(CONFIG_LEDS_LM3556)		+= leds-lm3556.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)	+= ledtrig-timer.o
+obj-$(CONFIG_LEDS_TRIGGER_ONESHOT)	+= ledtrig-oneshot.o
 obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK)	+= ledtrig-ide-disk.o
 obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT)	+= ledtrig-heartbeat.o
 obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT)	+= ledtrig-backlight.o
 obj-$(CONFIG_LEDS_TRIGGER_GPIO)		+= ledtrig-gpio.o
+obj-$(CONFIG_LEDS_TRIGGER_CPU)		+= ledtrig-cpu.o
 obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON)	+= ledtrig-default-on.o
 obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT)	+= ledtrig-transient.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index e663e6f..c599095 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -53,7 +53,7 @@ static ssize_t led_brightness_store(struct device *dev,
 
 	if (state == LED_OFF)
 		led_trigger_remove(led_cdev);
-	led_set_brightness(led_cdev, state);
+	__led_set_brightness(led_cdev, state);
 
 	return size;
 }
@@ -82,7 +82,12 @@ static void led_timer_function(unsigned long data)
 	unsigned long delay;
 
 	if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
-		led_set_brightness(led_cdev, LED_OFF);
+		__led_set_brightness(led_cdev, LED_OFF);
+		return;
+	}
+
+	if (led_cdev->flags & LED_BLINK_ONESHOT_STOP) {
+		led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
 		return;
 	}
 
@@ -100,7 +105,21 @@ static void led_timer_function(unsigned long data)
 		delay = led_cdev->blink_delay_off;
 	}
 
-	led_set_brightness(led_cdev, brightness);
+	__led_set_brightness(led_cdev, brightness);
+
+	/* Return in next iteration if led is in one-shot mode and we are in
+	 * the final blink state so that the led is toggled each delay_on +
+	 * delay_off milliseconds in worst case.
+	 */
+	if (led_cdev->flags & LED_BLINK_ONESHOT) {
+		if (led_cdev->flags & LED_BLINK_INVERT) {
+			if (brightness)
+				led_cdev->flags |= LED_BLINK_ONESHOT_STOP;
+		} else {
+			if (!brightness)
+				led_cdev->flags |= LED_BLINK_ONESHOT_STOP;
+		}
+	}
 
 	mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
 }
@@ -203,7 +222,7 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
 #endif
 
 	/* Stop blinking */
-	led_brightness_set(led_cdev, LED_OFF);
+	led_set_brightness(led_cdev, LED_OFF);
 
 	device_unregister(led_cdev->dev);
 
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index d65353d..2ab05af 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -24,14 +24,6 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
 LIST_HEAD(leds_list);
 EXPORT_SYMBOL_GPL(leds_list);
 
-static void led_stop_software_blink(struct led_classdev *led_cdev)
-{
-	/* deactivate previous settings */
-	del_timer_sync(&led_cdev->blink_timer);
-	led_cdev->blink_delay_on = 0;
-	led_cdev->blink_delay_off = 0;
-}
-
 static void led_set_software_blink(struct led_classdev *led_cdev,
 				   unsigned long delay_on,
 				   unsigned long delay_off)
@@ -53,7 +45,7 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
 
 	/* never off - just set to brightness */
 	if (!delay_off) {
-		led_set_brightness(led_cdev, led_cdev->blink_brightness);
+		__led_set_brightness(led_cdev, led_cdev->blink_brightness);
 		return;
 	}
 
@@ -61,13 +53,12 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
 }
 
 
-void led_blink_set(struct led_classdev *led_cdev,
-		   unsigned long *delay_on,
-		   unsigned long *delay_off)
+static void led_blink_setup(struct led_classdev *led_cdev,
+		     unsigned long *delay_on,
+		     unsigned long *delay_off)
 {
-	del_timer_sync(&led_cdev->blink_timer);
-
-	if (led_cdev->blink_set &&
+	if (!(led_cdev->flags & LED_BLINK_ONESHOT) &&
+	    led_cdev->blink_set &&
 	    !led_cdev->blink_set(led_cdev, delay_on, delay_off))
 		return;
 
@@ -77,12 +68,49 @@ void led_blink_set(struct led_classdev *led_cdev,
 
 	led_set_software_blink(led_cdev, *delay_on, *delay_off);
 }
+
+void led_blink_set(struct led_classdev *led_cdev,
+		   unsigned long *delay_on,
+		   unsigned long *delay_off)
+{
+	del_timer_sync(&led_cdev->blink_timer);
+
+	led_cdev->flags &= ~LED_BLINK_ONESHOT;
+	led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
+
+	led_blink_setup(led_cdev, delay_on, delay_off);
+}
 EXPORT_SYMBOL(led_blink_set);
 
-void led_brightness_set(struct led_classdev *led_cdev,
+void led_blink_set_oneshot(struct led_classdev *led_cdev,
+			   unsigned long *delay_on,
+			   unsigned long *delay_off,
+			   int invert)
+{
+	if ((led_cdev->flags & LED_BLINK_ONESHOT) &&
+	     timer_pending(&led_cdev->blink_timer))
+		return;
+
+	led_cdev->flags |= LED_BLINK_ONESHOT;
+	led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
+
+	if (invert)
+		led_cdev->flags |= LED_BLINK_INVERT;
+	else
+		led_cdev->flags &= ~LED_BLINK_INVERT;
+
+	led_blink_setup(led_cdev, delay_on, delay_off);
+}
+EXPORT_SYMBOL(led_blink_set_oneshot);
+
+void led_set_brightness(struct led_classdev *led_cdev,
 			enum led_brightness brightness)
 {
-	led_stop_software_blink(led_cdev);
-	led_cdev->brightness_set(led_cdev, brightness);
+	/* stop and clear soft-blink timer */
+	del_timer_sync(&led_cdev->blink_timer);
+	led_cdev->blink_delay_on = 0;
+	led_cdev->blink_delay_off = 0;
+
+	__led_set_brightness(led_cdev, brightness);
 }
-EXPORT_SYMBOL(led_brightness_set);
+EXPORT_SYMBOL(led_set_brightness);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 46b4c76..6157cbb 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -99,7 +99,7 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
 EXPORT_SYMBOL_GPL(led_trigger_show);
 
 /* Caller must ensure led_cdev->trigger_lock held */
-void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
+void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
 {
 	unsigned long flags;
 
@@ -112,15 +112,15 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
 		if (led_cdev->trigger->deactivate)
 			led_cdev->trigger->deactivate(led_cdev);
 		led_cdev->trigger = NULL;
-		led_brightness_set(led_cdev, LED_OFF);
+		led_set_brightness(led_cdev, LED_OFF);
 	}
-	if (trigger) {
-		write_lock_irqsave(&trigger->leddev_list_lock, flags);
-		list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs);
-		write_unlock_irqrestore(&trigger->leddev_list_lock, flags);
-		led_cdev->trigger = trigger;
-		if (trigger->activate)
-			trigger->activate(led_cdev);
+	if (trig) {
+		write_lock_irqsave(&trig->leddev_list_lock, flags);
+		list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
+		write_unlock_irqrestore(&trig->leddev_list_lock, flags);
+		led_cdev->trigger = trig;
+		if (trig->activate)
+			trig->activate(led_cdev);
 	}
 }
 EXPORT_SYMBOL_GPL(led_trigger_set);
@@ -153,24 +153,24 @@ EXPORT_SYMBOL_GPL(led_trigger_set_default);
 
 /* LED Trigger Interface */
 
-int led_trigger_register(struct led_trigger *trigger)
+int led_trigger_register(struct led_trigger *trig)
 {
 	struct led_classdev *led_cdev;
-	struct led_trigger *trig;
+	struct led_trigger *_trig;
 
-	rwlock_init(&trigger->leddev_list_lock);
-	INIT_LIST_HEAD(&trigger->led_cdevs);
+	rwlock_init(&trig->leddev_list_lock);
+	INIT_LIST_HEAD(&trig->led_cdevs);
 
 	down_write(&triggers_list_lock);
 	/* Make sure the trigger's name isn't already in use */
-	list_for_each_entry(trig, &trigger_list, next_trig) {
-		if (!strcmp(trig->name, trigger->name)) {
+	list_for_each_entry(_trig, &trigger_list, next_trig) {
+		if (!strcmp(_trig->name, trig->name)) {
 			up_write(&triggers_list_lock);
 			return -EEXIST;
 		}
 	}
 	/* Add to the list of led triggers */
-	list_add_tail(&trigger->next_trig, &trigger_list);
+	list_add_tail(&trig->next_trig, &trigger_list);
 	up_write(&triggers_list_lock);
 
 	/* Register with any LEDs that have this as a default trigger */
@@ -178,8 +178,8 @@ int led_trigger_register(struct led_trigger *trigger)
 	list_for_each_entry(led_cdev, &leds_list, node) {
 		down_write(&led_cdev->trigger_lock);
 		if (!led_cdev->trigger && led_cdev->default_trigger &&
-			    !strcmp(led_cdev->default_trigger, trigger->name))
-			led_trigger_set(led_cdev, trigger);
+			    !strcmp(led_cdev->default_trigger, trig->name))
+			led_trigger_set(led_cdev, trig);
 		up_write(&led_cdev->trigger_lock);
 	}
 	up_read(&leds_list_lock);
@@ -188,20 +188,20 @@ int led_trigger_register(struct led_trigger *trigger)
 }
 EXPORT_SYMBOL_GPL(led_trigger_register);
 
-void led_trigger_unregister(struct led_trigger *trigger)
+void led_trigger_unregister(struct led_trigger *trig)
 {
 	struct led_classdev *led_cdev;
 
 	/* Remove from the list of led triggers */
 	down_write(&triggers_list_lock);
-	list_del(&trigger->next_trig);
+	list_del(&trig->next_trig);
 	up_write(&triggers_list_lock);
 
 	/* Remove anyone actively using this trigger */
 	down_read(&leds_list_lock);
 	list_for_each_entry(led_cdev, &leds_list, node) {
 		down_write(&led_cdev->trigger_lock);
-		if (led_cdev->trigger == trigger)
+		if (led_cdev->trigger == trig)
 			led_trigger_set(led_cdev, NULL);
 		up_write(&led_cdev->trigger_lock);
 	}
@@ -211,58 +211,80 @@ EXPORT_SYMBOL_GPL(led_trigger_unregister);
 
 /* Simple LED Tigger Interface */
 
-void led_trigger_event(struct led_trigger *trigger,
+void led_trigger_event(struct led_trigger *trig,
 			enum led_brightness brightness)
 {
 	struct list_head *entry;
 
-	if (!trigger)
+	if (!trig)
 		return;
 
-	read_lock(&trigger->leddev_list_lock);
-	list_for_each(entry, &trigger->led_cdevs) {
+	read_lock(&trig->leddev_list_lock);
+	list_for_each(entry, &trig->led_cdevs) {
 		struct led_classdev *led_cdev;
 
 		led_cdev = list_entry(entry, struct led_classdev, trig_list);
 		led_set_brightness(led_cdev, brightness);
 	}
-	read_unlock(&trigger->leddev_list_lock);
+	read_unlock(&trig->leddev_list_lock);
 }
 EXPORT_SYMBOL_GPL(led_trigger_event);
 
-void led_trigger_blink(struct led_trigger *trigger,
-		       unsigned long *delay_on,
-		       unsigned long *delay_off)
+static void led_trigger_blink_setup(struct led_trigger *trig,
+			     unsigned long *delay_on,
+			     unsigned long *delay_off,
+			     int oneshot,
+			     int invert)
 {
 	struct list_head *entry;
 
-	if (!trigger)
+	if (!trig)
 		return;
 
-	read_lock(&trigger->leddev_list_lock);
-	list_for_each(entry, &trigger->led_cdevs) {
+	read_lock(&trig->leddev_list_lock);
+	list_for_each(entry, &trig->led_cdevs) {
 		struct led_classdev *led_cdev;
 
 		led_cdev = list_entry(entry, struct led_classdev, trig_list);
-		led_blink_set(led_cdev, delay_on, delay_off);
+		if (oneshot)
+			led_blink_set_oneshot(led_cdev, delay_on, delay_off,
+					      invert);
+		else
+			led_blink_set(led_cdev, delay_on, delay_off);
 	}
-	read_unlock(&trigger->leddev_list_lock);
+	read_unlock(&trig->leddev_list_lock);
+}
+
+void led_trigger_blink(struct led_trigger *trig,
+		       unsigned long *delay_on,
+		       unsigned long *delay_off)
+{
+	led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0);
 }
 EXPORT_SYMBOL_GPL(led_trigger_blink);
 
+void led_trigger_blink_oneshot(struct led_trigger *trig,
+			       unsigned long *delay_on,
+			       unsigned long *delay_off,
+			       int invert)
+{
+	led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
+}
+EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot);
+
 void led_trigger_register_simple(const char *name, struct led_trigger **tp)
 {
-	struct led_trigger *trigger;
+	struct led_trigger *trig;
 	int err;
 
-	trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+	trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
 
-	if (trigger) {
-		trigger->name = name;
-		err = led_trigger_register(trigger);
+	if (trig) {
+		trig->name = name;
+		err = led_trigger_register(trig);
 		if (err < 0) {
-			kfree(trigger);
-			trigger = NULL;
+			kfree(trig);
+			trig = NULL;
 			printk(KERN_WARNING "LED trigger %s failed to register"
 				" (%d)\n", name, err);
 		}
@@ -270,15 +292,15 @@ void led_trigger_register_simple(const char *name, struct led_trigger **tp)
 		printk(KERN_WARNING "LED trigger %s failed to register"
 			" (no memory)\n", name);
 
-	*tp = trigger;
+	*tp = trig;
 }
 EXPORT_SYMBOL_GPL(led_trigger_register_simple);
 
-void led_trigger_unregister_simple(struct led_trigger *trigger)
+void led_trigger_unregister_simple(struct led_trigger *trig)
 {
-	if (trigger)
-		led_trigger_unregister(trigger);
-	kfree(trigger);
+	if (trig)
+		led_trigger_unregister(trig);
+	kfree(trig);
 }
 EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
 
diff --git a/drivers/leds/leds-lm3556.c b/drivers/leds/leds-lm3556.c
new file mode 100644
index 0000000..3062abd
--- /dev/null
+++ b/drivers/leds/leds-lm3556.c
@@ -0,0 +1,512 @@
+/*
+ * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Please refer Documentation/leds/leds-lm3556.txt file.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/regmap.h>
+#include <linux/platform_data/leds-lm3556.h>
+
+#define REG_FILT_TIME			(0x0)
+#define REG_IVFM_MODE			(0x1)
+#define REG_NTC				(0x2)
+#define REG_INDIC_TIME			(0x3)
+#define REG_INDIC_BLINK			(0x4)
+#define REG_INDIC_PERIOD		(0x5)
+#define REG_TORCH_TIME			(0x6)
+#define REG_CONF			(0x7)
+#define REG_FLASH			(0x8)
+#define REG_I_CTRL			(0x9)
+#define REG_ENABLE			(0xA)
+#define REG_FLAG			(0xB)
+#define REG_MAX				(0xB)
+
+#define IVFM_FILTER_TIME_SHIFT		(3)
+#define UVLO_EN_SHIFT			(7)
+#define HYSTERSIS_SHIFT			(5)
+#define IVM_D_TH_SHIFT			(2)
+#define IVFM_ADJ_MODE_SHIFT		(0)
+#define NTC_EVENT_LVL_SHIFT		(5)
+#define NTC_TRIP_TH_SHIFT		(2)
+#define NTC_BIAS_I_LVL_SHIFT		(0)
+#define INDIC_RAMP_UP_TIME_SHIFT	(3)
+#define INDIC_RAMP_DN_TIME_SHIFT	(0)
+#define INDIC_N_BLANK_SHIFT		(4)
+#define INDIC_PULSE_TIME_SHIFT		(0)
+#define INDIC_N_PERIOD_SHIFT		(0)
+#define TORCH_RAMP_UP_TIME_SHIFT	(3)
+#define TORCH_RAMP_DN_TIME_SHIFT	(0)
+#define STROBE_USUAGE_SHIFT		(7)
+#define STROBE_PIN_POLARITY_SHIFT	(6)
+#define TORCH_PIN_POLARITY_SHIFT	(5)
+#define TX_PIN_POLARITY_SHIFT		(4)
+#define TX_EVENT_LVL_SHIFT		(3)
+#define IVFM_EN_SHIFT			(2)
+#define NTC_MODE_SHIFT			(1)
+#define INDIC_MODE_SHIFT		(0)
+#define INDUCTOR_I_LIMIT_SHIFT		(6)
+#define FLASH_RAMP_TIME_SHIFT		(3)
+#define FLASH_TOUT_TIME_SHIFT		(0)
+#define TORCH_I_SHIFT			(4)
+#define FLASH_I_SHIFT			(0)
+#define NTC_EN_SHIFT			(7)
+#define TX_PIN_EN_SHIFT			(6)
+#define STROBE_PIN_EN_SHIFT		(5)
+#define TORCH_PIN_EN_SHIFT		(4)
+#define PRECHG_MODE_EN_SHIFT		(3)
+#define PASS_MODE_ONLY_EN_SHIFT		(2)
+#define MODE_BITS_SHIFT			(0)
+
+#define IVFM_FILTER_TIME_MASK		(0x3)
+#define UVLO_EN_MASK			(0x1)
+#define HYSTERSIS_MASK			(0x3)
+#define IVM_D_TH_MASK			(0x7)
+#define IVFM_ADJ_MODE_MASK		(0x3)
+#define NTC_EVENT_LVL_MASK		(0x1)
+#define NTC_TRIP_TH_MASK		(0x7)
+#define NTC_BIAS_I_LVL_MASK		(0x3)
+#define INDIC_RAMP_UP_TIME_MASK		(0x7)
+#define INDIC_RAMP_DN_TIME_MASK		(0x7)
+#define INDIC_N_BLANK_MASK		(0x7)
+#define INDIC_PULSE_TIME_MASK		(0x7)
+#define INDIC_N_PERIOD_MASK		(0x7)
+#define TORCH_RAMP_UP_TIME_MASK		(0x7)
+#define TORCH_RAMP_DN_TIME_MASK		(0x7)
+#define STROBE_USUAGE_MASK		(0x1)
+#define STROBE_PIN_POLARITY_MASK	(0x1)
+#define TORCH_PIN_POLARITY_MASK		(0x1)
+#define TX_PIN_POLARITY_MASK		(0x1)
+#define TX_EVENT_LVL_MASK		(0x1)
+#define IVFM_EN_MASK			(0x1)
+#define NTC_MODE_MASK			(0x1)
+#define INDIC_MODE_MASK			(0x1)
+#define INDUCTOR_I_LIMIT_MASK		(0x3)
+#define FLASH_RAMP_TIME_MASK		(0x7)
+#define FLASH_TOUT_TIME_MASK		(0x7)
+#define TORCH_I_MASK			(0x7)
+#define FLASH_I_MASK			(0xF)
+#define NTC_EN_MASK			(0x1)
+#define TX_PIN_EN_MASK			(0x1)
+#define STROBE_PIN_EN_MASK		(0x1)
+#define TORCH_PIN_EN_MASK		(0x1)
+#define PRECHG_MODE_EN_MASK		(0x1)
+#define PASS_MODE_ONLY_EN_MASK		(0x1)
+#define MODE_BITS_MASK			(0x13)
+#define EX_PIN_CONTROL_MASK		(0xF1)
+#define EX_PIN_ENABLE_MASK		(0x70)
+
+enum lm3556_indic_pulse_time {
+	PULSE_TIME_0_MS = 0,
+	PULSE_TIME_32_MS,
+	PULSE_TIME_64_MS,
+	PULSE_TIME_92_MS,
+	PULSE_TIME_128_MS,
+	PULSE_TIME_160_MS,
+	PULSE_TIME_196_MS,
+	PULSE_TIME_224_MS,
+	PULSE_TIME_256_MS,
+	PULSE_TIME_288_MS,
+	PULSE_TIME_320_MS,
+	PULSE_TIME_352_MS,
+	PULSE_TIME_384_MS,
+	PULSE_TIME_416_MS,
+	PULSE_TIME_448_MS,
+	PULSE_TIME_480_MS,
+};
+
+enum lm3556_indic_n_blank {
+	INDIC_N_BLANK_0 = 0,
+	INDIC_N_BLANK_1,
+	INDIC_N_BLANK_2,
+	INDIC_N_BLANK_3,
+	INDIC_N_BLANK_4,
+	INDIC_N_BLANK_5,
+	INDIC_N_BLANK_6,
+	INDIC_N_BLANK_7,
+	INDIC_N_BLANK_8,
+	INDIC_N_BLANK_9,
+	INDIC_N_BLANK_10,
+	INDIC_N_BLANK_11,
+	INDIC_N_BLANK_12,
+	INDIC_N_BLANK_13,
+	INDIC_N_BLANK_14,
+	INDIC_N_BLANK_15,
+};
+
+enum lm3556_indic_period {
+	INDIC_PERIOD_0 = 0,
+	INDIC_PERIOD_1,
+	INDIC_PERIOD_2,
+	INDIC_PERIOD_3,
+	INDIC_PERIOD_4,
+	INDIC_PERIOD_5,
+	INDIC_PERIOD_6,
+	INDIC_PERIOD_7,
+};
+
+enum lm3556_mode {
+	MODES_STASNDBY = 0,
+	MODES_INDIC,
+	MODES_TORCH,
+	MODES_FLASH
+};
+
+#define INDIC_PATTERN_SIZE 4
+
+struct indicator {
+	u8 blinking;
+	u8 period_cnt;
+};
+
+struct lm3556_chip_data {
+	struct device *dev;
+
+	struct led_classdev cdev_flash;
+	struct led_classdev cdev_torch;
+	struct led_classdev cdev_indicator;
+
+	struct lm3556_platform_data *pdata;
+	struct regmap *regmap;
+	struct mutex lock;
+
+	unsigned int last_flag;
+};
+
+/* indicator pattern */
+static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = {
+	[0] = {(INDIC_N_BLANK_1 << INDIC_N_BLANK_SHIFT)
+	       | PULSE_TIME_32_MS, INDIC_PERIOD_1},
+	[1] = {(INDIC_N_BLANK_15 << INDIC_N_BLANK_SHIFT)
+	       | PULSE_TIME_32_MS, INDIC_PERIOD_2},
+	[2] = {(INDIC_N_BLANK_10 << INDIC_N_BLANK_SHIFT)
+	       | PULSE_TIME_32_MS, INDIC_PERIOD_4},
+	[3] = {(INDIC_N_BLANK_5 << INDIC_N_BLANK_SHIFT)
+	       | PULSE_TIME_32_MS, INDIC_PERIOD_7},
+};
+
+/* chip initialize */
+static int __devinit lm3556_chip_init(struct lm3556_chip_data *chip)
+{
+	unsigned int reg_val;
+	int ret;
+	struct lm3556_platform_data *pdata = chip->pdata;
+
+	/* set config register */
+	ret = regmap_read(chip->regmap, REG_CONF, &reg_val);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to read REG_CONF Register\n");
+		goto out;
+	}
+
+	reg_val &= (~EX_PIN_CONTROL_MASK);
+	reg_val |= ((pdata->torch_pin_polarity & 0x01)
+		    << TORCH_PIN_POLARITY_SHIFT);
+	reg_val |= ((pdata->strobe_usuage & 0x01) << STROBE_USUAGE_SHIFT);
+	reg_val |= ((pdata->strobe_pin_polarity & 0x01)
+		    << STROBE_PIN_POLARITY_SHIFT);
+	reg_val |= ((pdata->tx_pin_polarity & 0x01) << TX_PIN_POLARITY_SHIFT);
+	reg_val |= ((pdata->indicator_mode & 0x01) << INDIC_MODE_SHIFT);
+
+	ret = regmap_write(chip->regmap, REG_CONF, reg_val);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to write REG_CONF Regisgter\n");
+		goto out;
+	}
+
+	/* set enable register */
+	ret = regmap_read(chip->regmap, REG_ENABLE, &reg_val);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to read REG_ENABLE Register\n");
+		goto out;
+	}
+
+	reg_val &= (~EX_PIN_ENABLE_MASK);
+	reg_val |= ((pdata->torch_pin_en & 0x01) << TORCH_PIN_EN_SHIFT);
+	reg_val |= ((pdata->strobe_pin_en & 0x01) << STROBE_PIN_EN_SHIFT);
+	reg_val |= ((pdata->tx_pin_en & 0x01) << TX_PIN_EN_SHIFT);
+
+	ret = regmap_write(chip->regmap, REG_ENABLE, reg_val);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+/* chip control */
+static int lm3556_control(struct lm3556_chip_data *chip,
+			  u8 brightness, enum lm3556_mode opmode)
+{
+	int ret;
+	struct lm3556_platform_data *pdata = chip->pdata;
+
+	ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to read REG_FLAG Register\n");
+		goto out;
+	}
+
+	if (chip->last_flag)
+		dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag);
+
+	/* brightness 0 means off-state */
+	if (!brightness)
+		opmode = MODES_STASNDBY;
+
+	switch (opmode) {
+	case MODES_TORCH:
+		ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+					 TORCH_I_MASK << TORCH_I_SHIFT,
+					 (brightness - 1) << TORCH_I_SHIFT);
+
+		if (pdata->torch_pin_en)
+			opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
+		break;
+
+	case MODES_FLASH:
+		ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+					 FLASH_I_MASK << FLASH_I_SHIFT,
+					 (brightness - 1) << FLASH_I_SHIFT);
+		break;
+
+	case MODES_INDIC:
+		ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+					 TORCH_I_MASK << TORCH_I_SHIFT,
+					 (brightness - 1) << TORCH_I_SHIFT);
+		break;
+
+	case MODES_STASNDBY:
+		if (pdata->torch_pin_en)
+			opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
+		break;
+
+	default:
+		return ret;
+	}
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n");
+		goto out;
+	}
+	ret = regmap_update_bits(chip->regmap, REG_ENABLE,
+				 MODE_BITS_MASK << MODE_BITS_SHIFT,
+				 opmode << MODE_BITS_SHIFT);
+
+out:
+	return ret;
+}
+
+/* torch */
+static void lm3556_torch_brightness_set(struct led_classdev *cdev,
+					enum led_brightness brightness)
+{
+	struct lm3556_chip_data *chip =
+	    container_of(cdev, struct lm3556_chip_data, cdev_torch);
+
+	mutex_lock(&chip->lock);
+	lm3556_control(chip, brightness, MODES_TORCH);
+	mutex_unlock(&chip->lock);
+}
+
+/* flash */
+static void lm3556_strobe_brightness_set(struct led_classdev *cdev,
+					 enum led_brightness brightness)
+{
+	struct lm3556_chip_data *chip =
+	    container_of(cdev, struct lm3556_chip_data, cdev_flash);
+
+	mutex_lock(&chip->lock);
+	lm3556_control(chip, brightness, MODES_FLASH);
+	mutex_unlock(&chip->lock);
+}
+
+/* indicator */
+static void lm3556_indicator_brightness_set(struct led_classdev *cdev,
+					    enum led_brightness brightness)
+{
+	struct lm3556_chip_data *chip =
+	    container_of(cdev, struct lm3556_chip_data, cdev_indicator);
+
+	mutex_lock(&chip->lock);
+	lm3556_control(chip, brightness, MODES_INDIC);
+	mutex_unlock(&chip->lock);
+}
+
+/* indicator pattern */
+static ssize_t lm3556_indicator_pattern_store(struct device *dev,
+					      struct device_attribute *devAttr,
+					      const char *buf, size_t size)
+{
+	ssize_t ret;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct lm3556_chip_data *chip =
+	    container_of(led_cdev, struct lm3556_chip_data, cdev_indicator);
+	unsigned int state;
+
+	ret = kstrtouint(buf, 10, &state);
+	if (ret)
+		goto out;
+	if (state > INDIC_PATTERN_SIZE - 1)
+		state = INDIC_PATTERN_SIZE - 1;
+
+	ret = regmap_write(chip->regmap, REG_INDIC_BLINK,
+			   indicator_pattern[state].blinking);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
+		goto out;
+	}
+
+	ret = regmap_write(chip->regmap, REG_INDIC_PERIOD,
+			   indicator_pattern[state].period_cnt);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
+		goto out;
+	}
+
+	return size;
+out:
+	dev_err(chip->dev, "Indicator pattern doesn't saved\n");
+	return size;
+}
+
+static DEVICE_ATTR(pattern, 0666, NULL, lm3556_indicator_pattern_store);
+
+static const struct regmap_config lm3556_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = REG_MAX,
+};
+
+/* module initialize */
+static int __devinit lm3556_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
+{
+	struct lm3556_platform_data *pdata = client->dev.platform_data;
+	struct lm3556_chip_data *chip;
+
+	int err;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "i2c functionality check fail.\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (pdata == NULL) {
+		dev_err(&client->dev, "Needs Platform Data.\n");
+		return -ENODATA;
+	}
+
+	chip =
+	    devm_kzalloc(&client->dev, sizeof(struct lm3556_chip_data),
+			 GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->dev = &client->dev;
+	chip->pdata = pdata;
+
+	chip->regmap = devm_regmap_init_i2c(client, &lm3556_regmap);
+	if (IS_ERR(chip->regmap)) {
+		err = PTR_ERR(chip->regmap);
+		dev_err(&client->dev, "Failed to allocate register map: %d\n",
+			err);
+		return err;
+	}
+
+	mutex_init(&chip->lock);
+	i2c_set_clientdata(client, chip);
+
+	err = lm3556_chip_init(chip);
+	if (err < 0)
+		goto err_out;
+
+	/* flash */
+	chip->cdev_flash.name = "flash";
+	chip->cdev_flash.max_brightness = 16;
+	chip->cdev_flash.brightness_set = lm3556_strobe_brightness_set;
+	err = led_classdev_register((struct device *)
+				    &client->dev, &chip->cdev_flash);
+	if (err < 0)
+		goto err_out;
+	/* torch */
+	chip->cdev_torch.name = "torch";
+	chip->cdev_torch.max_brightness = 8;
+	chip->cdev_torch.brightness_set = lm3556_torch_brightness_set;
+	err = led_classdev_register((struct device *)
+				    &client->dev, &chip->cdev_torch);
+	if (err < 0)
+		goto err_create_torch_file;
+	/* indicator */
+	chip->cdev_indicator.name = "indicator";
+	chip->cdev_indicator.max_brightness = 8;
+	chip->cdev_indicator.brightness_set = lm3556_indicator_brightness_set;
+	err = led_classdev_register((struct device *)
+				    &client->dev, &chip->cdev_indicator);
+	if (err < 0)
+		goto err_create_indicator_file;
+
+	err = device_create_file(chip->cdev_indicator.dev, &dev_attr_pattern);
+	if (err < 0)
+		goto err_create_pattern_file;
+
+	dev_info(&client->dev, "LM3556 is initialized\n");
+	return 0;
+
+err_create_pattern_file:
+	led_classdev_unregister(&chip->cdev_indicator);
+err_create_indicator_file:
+	led_classdev_unregister(&chip->cdev_torch);
+err_create_torch_file:
+	led_classdev_unregister(&chip->cdev_flash);
+err_out:
+	return err;
+}
+
+static int __devexit lm3556_remove(struct i2c_client *client)
+{
+	struct lm3556_chip_data *chip = i2c_get_clientdata(client);
+
+	device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern);
+	led_classdev_unregister(&chip->cdev_indicator);
+	led_classdev_unregister(&chip->cdev_torch);
+	led_classdev_unregister(&chip->cdev_flash);
+	regmap_write(chip->regmap, REG_ENABLE, 0);
+	return 0;
+}
+
+static const struct i2c_device_id lm3556_id[] = {
+	{LM3556_NAME, 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm3556_id);
+
+static struct i2c_driver lm3556_i2c_driver = {
+	.driver = {
+		   .name = LM3556_NAME,
+		   .owner = THIS_MODULE,
+		   .pm = NULL,
+		   },
+	.probe = lm3556_probe,
+	.remove = __devexit_p(lm3556_remove),
+	.id_table = lm3556_id,
+};
+
+module_i2c_driver(lm3556_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3556");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index bd0a5ed..e6ee105 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -106,10 +106,9 @@ static int s3c24xx_led_probe(struct platform_device *dev)
 	if (ret < 0) {
 		dev_err(&dev->dev, "led_classdev_register failed\n");
 		kfree(led);
-		return ret;
 	}
 
-	return 0;
+	return ret;
 }
 
 static struct platform_driver s3c24xx_led_driver = {
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index e77c7f8..d02acd4 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -17,7 +17,7 @@
 #include <linux/rwsem.h>
 #include <linux/leds.h>
 
-static inline void led_set_brightness(struct led_classdev *led_cdev,
+static inline void __led_set_brightness(struct led_classdev *led_cdev,
 					enum led_brightness value)
 {
 	if (value > led_cdev->max_brightness)
diff --git a/drivers/leds/ledtrig-backlight.c b/drivers/leds/ledtrig-backlight.c
index e272686..b941685 100644
--- a/drivers/leds/ledtrig-backlight.c
+++ b/drivers/leds/ledtrig-backlight.c
@@ -46,9 +46,9 @@ static int fb_notifier_callback(struct notifier_block *p,
 
 		if ((n->old_status == UNBLANK) ^ n->invert) {
 			n->brightness = led->brightness;
-			led_set_brightness(led, LED_OFF);
+			__led_set_brightness(led, LED_OFF);
 		} else {
-			led_set_brightness(led, n->brightness);
+			__led_set_brightness(led, n->brightness);
 		}
 
 		n->old_status = new_status;
@@ -87,9 +87,9 @@ static ssize_t bl_trig_invert_store(struct device *dev,
 
 	/* After inverting, we need to update the LED. */
 	if ((n->old_status == BLANK) ^ n->invert)
-		led_set_brightness(led, LED_OFF);
+		__led_set_brightness(led, LED_OFF);
 	else
-		led_set_brightness(led, n->brightness);
+		__led_set_brightness(led, n->brightness);
 
 	return num;
 }
diff --git a/drivers/leds/ledtrig-cpu.c b/drivers/leds/ledtrig-cpu.c
new file mode 100644
index 0000000..b312056
--- /dev/null
+++ b/drivers/leds/ledtrig-cpu.c
@@ -0,0 +1,163 @@
+/*
+ * ledtrig-cpu.c - LED trigger based on CPU activity
+ *
+ * This LED trigger will be registered for each possible CPU and named as
+ * cpu0, cpu1, cpu2, cpu3, etc.
+ *
+ * It can be bound to any LED just like other triggers using either a
+ * board file or via sysfs interface.
+ *
+ * An API named ledtrig_cpu is exported for any user, who want to add CPU
+ * activity indication in their code
+ *
+ * Copyright 2011 Linus Walleij <linus.walleij@linaro.org>
+ * Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/percpu.h>
+#include <linux/syscore_ops.h>
+#include <linux/rwsem.h>
+#include "leds.h"
+
+#define MAX_NAME_LEN	8
+
+struct led_trigger_cpu {
+	char name[MAX_NAME_LEN];
+	struct led_trigger *_trig;
+	struct mutex lock;
+	int lock_is_inited;
+};
+
+static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig);
+
+/**
+ * ledtrig_cpu - emit a CPU event as a trigger
+ * @evt: CPU event to be emitted
+ *
+ * Emit a CPU event on a CPU core, which will trigger a
+ * binded LED to turn on or turn off.
+ */
+void ledtrig_cpu(enum cpu_led_event ledevt)
+{
+	struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig);
+
+	/* mutex lock should be initialized before calling mutex_call() */
+	if (!trig->lock_is_inited)
+		return;
+
+	mutex_lock(&trig->lock);
+
+	/* Locate the correct CPU LED */
+	switch (ledevt) {
+	case CPU_LED_IDLE_END:
+	case CPU_LED_START:
+		/* Will turn the LED on, max brightness */
+		led_trigger_event(trig->_trig, LED_FULL);
+		break;
+
+	case CPU_LED_IDLE_START:
+	case CPU_LED_STOP:
+	case CPU_LED_HALTED:
+		/* Will turn the LED off */
+		led_trigger_event(trig->_trig, LED_OFF);
+		break;
+
+	default:
+		/* Will leave the LED as it is */
+		break;
+	}
+
+	mutex_unlock(&trig->lock);
+}
+EXPORT_SYMBOL(ledtrig_cpu);
+
+static int ledtrig_cpu_syscore_suspend(void)
+{
+	ledtrig_cpu(CPU_LED_STOP);
+	return 0;
+}
+
+static void ledtrig_cpu_syscore_resume(void)
+{
+	ledtrig_cpu(CPU_LED_START);
+}
+
+static void ledtrig_cpu_syscore_shutdown(void)
+{
+	ledtrig_cpu(CPU_LED_HALTED);
+}
+
+static struct syscore_ops ledtrig_cpu_syscore_ops = {
+	.shutdown	= ledtrig_cpu_syscore_shutdown,
+	.suspend	= ledtrig_cpu_syscore_suspend,
+	.resume		= ledtrig_cpu_syscore_resume,
+};
+
+static int __init ledtrig_cpu_init(void)
+{
+	int cpu;
+
+	/* Supports up to 9999 cpu cores */
+	BUILD_BUG_ON(CONFIG_NR_CPUS > 9999);
+
+	/*
+	 * Registering CPU led trigger for each CPU core here
+	 * ignores CPU hotplug, but after this CPU hotplug works
+	 * fine with this trigger.
+	 */
+	for_each_possible_cpu(cpu) {
+		struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
+
+		mutex_init(&trig->lock);
+
+		snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu);
+
+		mutex_lock(&trig->lock);
+		led_trigger_register_simple(trig->name, &trig->_trig);
+		trig->lock_is_inited = 1;
+		mutex_unlock(&trig->lock);
+	}
+
+	register_syscore_ops(&ledtrig_cpu_syscore_ops);
+
+	pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n");
+
+	return 0;
+}
+module_init(ledtrig_cpu_init);
+
+static void __exit ledtrig_cpu_exit(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
+
+		mutex_lock(&trig->lock);
+
+		led_trigger_unregister_simple(trig->_trig);
+		trig->_trig = NULL;
+		memset(trig->name, 0, MAX_NAME_LEN);
+		trig->lock_is_inited = 0;
+
+		mutex_unlock(&trig->lock);
+		mutex_destroy(&trig->lock);
+	}
+
+	unregister_syscore_ops(&ledtrig_cpu_syscore_ops);
+}
+module_exit(ledtrig_cpu_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_AUTHOR("Bryan Wu <bryan.wu@canonical.com>");
+MODULE_DESCRIPTION("CPU LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/ledtrig-default-on.c b/drivers/leds/ledtrig-default-on.c
index a4ef54b..eac1f1b 100644
--- a/drivers/leds/ledtrig-default-on.c
+++ b/drivers/leds/ledtrig-default-on.c
@@ -19,7 +19,7 @@
 
 static void defon_trig_activate(struct led_classdev *led_cdev)
 {
-	led_set_brightness(led_cdev, led_cdev->max_brightness);
+	__led_set_brightness(led_cdev, led_cdev->max_brightness);
 }
 
 static struct led_trigger defon_led_trigger = {
diff --git a/drivers/leds/ledtrig-gpio.c b/drivers/leds/ledtrig-gpio.c
index f057c10..ba215dc 100644
--- a/drivers/leds/ledtrig-gpio.c
+++ b/drivers/leds/ledtrig-gpio.c
@@ -54,12 +54,12 @@ static void gpio_trig_work(struct work_struct *work)
 
 	if (tmp) {
 		if (gpio_data->desired_brightness)
-			led_set_brightness(gpio_data->led,
+			__led_set_brightness(gpio_data->led,
 					   gpio_data->desired_brightness);
 		else
-			led_set_brightness(gpio_data->led, LED_FULL);
+			__led_set_brightness(gpio_data->led, LED_FULL);
 	} else {
-		led_set_brightness(gpio_data->led, LED_OFF);
+		__led_set_brightness(gpio_data->led, LED_OFF);
 	}
 }
 
diff --git a/drivers/leds/ledtrig-heartbeat.c b/drivers/leds/ledtrig-heartbeat.c
index 41dc76d..d3039f2 100644
--- a/drivers/leds/ledtrig-heartbeat.c
+++ b/drivers/leds/ledtrig-heartbeat.c
@@ -67,7 +67,7 @@ static void led_heartbeat_function(unsigned long data)
 		break;
 	}
 
-	led_set_brightness(led_cdev, brightness);
+	__led_set_brightness(led_cdev, brightness);
 	mod_timer(&heartbeat_data->timer, jiffies + delay);
 }
 
diff --git a/drivers/leds/ledtrig-ide-disk.c b/drivers/leds/ledtrig-ide-disk.c
index ec099fc..2cd7c0c 100644
--- a/drivers/leds/ledtrig-ide-disk.c
+++ b/drivers/leds/ledtrig-ide-disk.c
@@ -12,39 +12,22 @@
  */
 
 #include <linux/module.h>
-#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/timer.h>
 #include <linux/leds.h>
 
-static void ledtrig_ide_timerfunc(unsigned long data);
+#define BLINK_DELAY 30
 
 DEFINE_LED_TRIGGER(ledtrig_ide);
-static DEFINE_TIMER(ledtrig_ide_timer, ledtrig_ide_timerfunc, 0, 0);
-static int ide_activity;
-static int ide_lastactivity;
+static unsigned long ide_blink_delay = BLINK_DELAY;
 
 void ledtrig_ide_activity(void)
 {
-	ide_activity++;
-	if (!timer_pending(&ledtrig_ide_timer))
-		mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));
+	led_trigger_blink_oneshot(ledtrig_ide,
+				  &ide_blink_delay, &ide_blink_delay, 0);
 }
 EXPORT_SYMBOL(ledtrig_ide_activity);
 
-static void ledtrig_ide_timerfunc(unsigned long data)
-{
-	if (ide_lastactivity != ide_activity) {
-		ide_lastactivity = ide_activity;
-		/* INT_MAX will set each LED to its maximum brightness */
-		led_trigger_event(ledtrig_ide, INT_MAX);
-		mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));
-	} else {
-		led_trigger_event(ledtrig_ide, LED_OFF);
-	}
-}
-
 static int __init ledtrig_ide_init(void)
 {
 	led_trigger_register_simple("ide-disk", &ledtrig_ide);
diff --git a/drivers/leds/ledtrig-oneshot.c b/drivers/leds/ledtrig-oneshot.c
new file mode 100644
index 0000000..2c029aa
--- /dev/null
+++ b/drivers/leds/ledtrig-oneshot.c
@@ -0,0 +1,204 @@
+/*
+ * One-shot LED Trigger
+ *
+ * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
+ *
+ * Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+#define DEFAULT_DELAY 100
+
+struct oneshot_trig_data {
+	unsigned int invert;
+};
+
+static ssize_t led_shot(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
+
+	led_blink_set_oneshot(led_cdev,
+			&led_cdev->blink_delay_on, &led_cdev->blink_delay_off,
+			oneshot_data->invert);
+
+	/* content is ignored */
+	return size;
+}
+static ssize_t led_invert_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
+
+	return sprintf(buf, "%u\n", oneshot_data->invert);
+}
+
+static ssize_t led_invert_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
+	unsigned long state;
+	int ret;
+
+	ret = kstrtoul(buf, 0, &state);
+	if (ret)
+		return ret;
+
+	oneshot_data->invert = !!state;
+
+	if (oneshot_data->invert)
+		__led_set_brightness(led_cdev, LED_FULL);
+	else
+		__led_set_brightness(led_cdev, LED_OFF);
+
+	return size;
+}
+
+static ssize_t led_delay_on_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
+}
+
+static ssize_t led_delay_on_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	unsigned long state;
+	int ret;
+
+	ret = kstrtoul(buf, 0, &state);
+	if (ret)
+		return ret;
+
+	led_cdev->blink_delay_on = state;
+
+	return size;
+}
+static ssize_t led_delay_off_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
+}
+
+static ssize_t led_delay_off_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	unsigned long state;
+	int ret;
+
+	ret = kstrtoul(buf, 0, &state);
+	if (ret)
+		return ret;
+
+	led_cdev->blink_delay_off = state;
+
+	return size;
+}
+
+static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
+static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
+static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
+static DEVICE_ATTR(shot, 0200, NULL, led_shot);
+
+static void oneshot_trig_activate(struct led_classdev *led_cdev)
+{
+	struct oneshot_trig_data *oneshot_data;
+	int rc;
+
+	oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL);
+	if (!oneshot_data)
+		return;
+
+	led_cdev->trigger_data = oneshot_data;
+
+	rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
+	if (rc)
+		goto err_out_trig_data;
+	rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
+	if (rc)
+		goto err_out_delayon;
+	rc = device_create_file(led_cdev->dev, &dev_attr_invert);
+	if (rc)
+		goto err_out_delayoff;
+	rc = device_create_file(led_cdev->dev, &dev_attr_shot);
+	if (rc)
+		goto err_out_invert;
+
+	led_cdev->blink_delay_on = DEFAULT_DELAY;
+	led_cdev->blink_delay_off = DEFAULT_DELAY;
+
+	led_cdev->activated = true;
+
+	return;
+
+err_out_invert:
+	device_remove_file(led_cdev->dev, &dev_attr_invert);
+err_out_delayoff:
+	device_remove_file(led_cdev->dev, &dev_attr_delay_off);
+err_out_delayon:
+	device_remove_file(led_cdev->dev, &dev_attr_delay_on);
+err_out_trig_data:
+	kfree(led_cdev->trigger_data);
+}
+
+static void oneshot_trig_deactivate(struct led_classdev *led_cdev)
+{
+	struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
+
+	if (led_cdev->activated) {
+		device_remove_file(led_cdev->dev, &dev_attr_delay_on);
+		device_remove_file(led_cdev->dev, &dev_attr_delay_off);
+		device_remove_file(led_cdev->dev, &dev_attr_invert);
+		device_remove_file(led_cdev->dev, &dev_attr_shot);
+		kfree(oneshot_data);
+		led_cdev->activated = false;
+	}
+
+	/* Stop blinking */
+	led_set_brightness(led_cdev, LED_OFF);
+}
+
+static struct led_trigger oneshot_led_trigger = {
+	.name     = "oneshot",
+	.activate = oneshot_trig_activate,
+	.deactivate = oneshot_trig_deactivate,
+};
+
+static int __init oneshot_trig_init(void)
+{
+	return led_trigger_register(&oneshot_led_trigger);
+}
+
+static void __exit oneshot_trig_exit(void)
+{
+	led_trigger_unregister(&oneshot_led_trigger);
+}
+
+module_init(oneshot_trig_init);
+module_exit(oneshot_trig_exit);
+
+MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
+MODULE_DESCRIPTION("One-shot LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index 9010f7a..f774d05 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -104,7 +104,7 @@ static void timer_trig_deactivate(struct led_classdev *led_cdev)
 	}
 
 	/* Stop blinking */
-	led_brightness_set(led_cdev, LED_OFF);
+	led_set_brightness(led_cdev, LED_OFF);
 }
 
 static struct led_trigger timer_led_trigger = {
diff --git a/drivers/leds/ledtrig-transient.c b/drivers/leds/ledtrig-transient.c
index 83179f4..398f104 100644
--- a/drivers/leds/ledtrig-transient.c
+++ b/drivers/leds/ledtrig-transient.c
@@ -41,7 +41,7 @@ static void transient_timer_function(unsigned long data)
 	struct transient_trig_data *transient_data = led_cdev->trigger_data;
 
 	transient_data->activate = 0;
-	led_set_brightness(led_cdev, transient_data->restore_state);
+	__led_set_brightness(led_cdev, transient_data->restore_state);
 }
 
 static ssize_t transient_activate_show(struct device *dev,
@@ -72,7 +72,7 @@ static ssize_t transient_activate_store(struct device *dev,
 	if (state == 0 && transient_data->activate == 1) {
 		del_timer(&transient_data->timer);
 		transient_data->activate = state;
-		led_set_brightness(led_cdev, transient_data->restore_state);
+		__led_set_brightness(led_cdev, transient_data->restore_state);
 		return size;
 	}
 
@@ -80,7 +80,7 @@ static ssize_t transient_activate_store(struct device *dev,
 	if (state == 1 && transient_data->activate == 0 &&
 	    transient_data->duration != 0) {
 		transient_data->activate = state;
-		led_set_brightness(led_cdev, transient_data->state);
+		__led_set_brightness(led_cdev, transient_data->state);
 		transient_data->restore_state =
 		    (transient_data->state == LED_FULL) ? LED_OFF : LED_FULL;
 		mod_timer(&transient_data->timer,
@@ -203,7 +203,7 @@ static void transient_trig_deactivate(struct led_classdev *led_cdev)
 
 	if (led_cdev->activated) {
 		del_timer_sync(&transient_data->timer);
-		led_set_brightness(led_cdev, transient_data->restore_state);
+		__led_set_brightness(led_cdev, transient_data->restore_state);
 		device_remove_file(led_cdev->dev, &dev_attr_activate);
 		device_remove_file(led_cdev->dev, &dev_attr_duration);
 		device_remove_file(led_cdev->dev, &dev_attr_state);
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 65ebaeb..627d191 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -571,16 +571,6 @@ static void disk_dtr(struct dm_dirty_log *log)
 	destroy_log_context(lc);
 }
 
-static int count_bits32(uint32_t *addr, unsigned size)
-{
-	int count = 0, i;
-
-	for (i = 0; i < size; i++) {
-		count += hweight32(*(addr+i));
-	}
-	return count;
-}
-
 static void fail_log_device(struct log_c *lc)
 {
 	if (lc->log_dev_failed)
@@ -629,7 +619,8 @@ static int disk_resume(struct dm_dirty_log *log)
 
 	/* copy clean across to sync */
 	memcpy(lc->sync_bits, lc->clean_bits, size);
-	lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count);
+	lc->sync_count = memweight(lc->clean_bits,
+				lc->bitset_uint32_count * sizeof(uint32_t));
 	lc->sync_search = 0;
 
 	/* set the correct number of regions in the header */
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 017c34d..858a8b7 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -353,6 +353,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
 {
 	unsigned i, rebuild_cnt = 0;
 	unsigned long value, region_size = 0;
+	sector_t max_io_len;
 	char *key;
 
 	/*
@@ -522,14 +523,12 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
 		return -EINVAL;
 
 	if (rs->md.chunk_sectors)
-		rs->ti->split_io = rs->md.chunk_sectors;
+		max_io_len = rs->md.chunk_sectors;
 	else
-		rs->ti->split_io = region_size;
+		max_io_len = region_size;
 
-	if (rs->md.chunk_sectors)
-		rs->ti->split_io = rs->md.chunk_sectors;
-	else
-		rs->ti->split_io = region_size;
+	if (dm_set_target_max_io_len(rs->ti, max_io_len))
+		return -EINVAL;
 
 	/* Assume there are no metadata devices until the drives are parsed */
 	rs->md.persistent = 0;
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index d039de8..aa21a16 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1081,7 +1081,11 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 	}
 
 	ti->private = ms;
-	ti->split_io = dm_rh_get_region_size(ms->rh);
+
+	r = dm_set_target_max_io_len(ti, dm_rh_get_region_size(ms->rh));
+	if (r)
+		goto err_free_context;
+
 	ti->num_flush_requests = 1;
 	ti->num_discard_requests = 1;
 
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 6f75887..fc19b50 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -691,7 +691,7 @@ static int dm_add_exception(void *context, chunk_t old, chunk_t new)
  * Return a minimum chunk size of all snapshots that have the specified origin.
  * Return zero if the origin has no snapshots.
  */
-static sector_t __minimum_chunk_size(struct origin *o)
+static uint32_t __minimum_chunk_size(struct origin *o)
 {
 	struct dm_snapshot *snap;
 	unsigned chunk_size = 0;
@@ -701,7 +701,7 @@ static sector_t __minimum_chunk_size(struct origin *o)
 			chunk_size = min_not_zero(chunk_size,
 						  snap->store->chunk_size);
 
-	return chunk_size;
+	return (uint32_t) chunk_size;
 }
 
 /*
@@ -1172,7 +1172,10 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 		ti->error = "Chunk size not set";
 		goto bad_read_metadata;
 	}
-	ti->split_io = s->store->chunk_size;
+
+	r = dm_set_target_max_io_len(ti, s->store->chunk_size);
+	if (r)
+		goto bad_read_metadata;
 
 	return 0;
 
@@ -1239,7 +1242,7 @@ static void __handover_exceptions(struct dm_snapshot *snap_src,
 	snap_dest->store->snap = snap_dest;
 	snap_src->store->snap = snap_src;
 
-	snap_dest->ti->split_io = snap_dest->store->chunk_size;
+	snap_dest->ti->max_io_len = snap_dest->store->chunk_size;
 	snap_dest->valid = snap_src->valid;
 
 	/*
@@ -1817,9 +1820,9 @@ static void snapshot_resume(struct dm_target *ti)
 	up_write(&s->lock);
 }
 
-static sector_t get_origin_minimum_chunksize(struct block_device *bdev)
+static uint32_t get_origin_minimum_chunksize(struct block_device *bdev)
 {
-	sector_t min_chunksize;
+	uint32_t min_chunksize;
 
 	down_read(&_origins_lock);
 	min_chunksize = __minimum_chunk_size(__lookup_origin(bdev));
@@ -1838,9 +1841,9 @@ static void snapshot_merge_resume(struct dm_target *ti)
 	snapshot_resume(ti);
 
 	/*
-	 * snapshot-merge acts as an origin, so set ti->split_io
+	 * snapshot-merge acts as an origin, so set ti->max_io_len
 	 */
-	ti->split_io = get_origin_minimum_chunksize(s->origin->bdev);
+	ti->max_io_len = get_origin_minimum_chunksize(s->origin->bdev);
 
 	start_merge(s);
 }
@@ -2073,12 +2076,12 @@ static int origin_write_extent(struct dm_snapshot *merging_snap,
 	struct origin *o;
 
 	/*
-	 * The origin's __minimum_chunk_size() got stored in split_io
+	 * The origin's __minimum_chunk_size() got stored in max_io_len
 	 * by snapshot_merge_resume().
 	 */
 	down_read(&_origins_lock);
 	o = __lookup_origin(merging_snap->origin->bdev);
-	for (n = 0; n < size; n += merging_snap->ti->split_io)
+	for (n = 0; n < size; n += merging_snap->ti->max_io_len)
 		if (__origin_write(&o->snapshots, sector + n, NULL) ==
 		    DM_MAPIO_SUBMITTED)
 			must_wait = 1;
@@ -2138,14 +2141,14 @@ static int origin_map(struct dm_target *ti, struct bio *bio,
 }
 
 /*
- * Set the target "split_io" field to the minimum of all the snapshots'
+ * Set the target "max_io_len" field to the minimum of all the snapshots'
  * chunk sizes.
  */
 static void origin_resume(struct dm_target *ti)
 {
 	struct dm_dev *dev = ti->private;
 
-	ti->split_io = get_origin_minimum_chunksize(dev->bdev);
+	ti->max_io_len = get_origin_minimum_chunksize(dev->bdev);
 }
 
 static int origin_status(struct dm_target *ti, status_type_t type, char *result,
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 35c94ff..b065c69 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -26,14 +26,12 @@ struct stripe {
 struct stripe_c {
 	uint32_t stripes;
 	int stripes_shift;
-	sector_t stripes_mask;
 
 	/* The size of this target / num. stripes */
 	sector_t stripe_width;
 
-	/* stripe chunk size */
-	uint32_t chunk_shift;
-	sector_t chunk_mask;
+	uint32_t chunk_size;
+	int chunk_size_shift;
 
 	/* Needed for handling events */
 	struct dm_target *ti;
@@ -91,14 +89,14 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
 
 /*
  * Construct a striped mapping.
- * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
+ * <number of stripes> <chunk size> [<dev_path> <offset>]+
  */
 static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
 	struct stripe_c *sc;
 	sector_t width;
 	uint32_t stripes;
-	uint32_t chunk_size;
+	unsigned long chunk_size;
 	char *end;
 	int r;
 	unsigned int i;
@@ -115,27 +113,18 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 	}
 
 	chunk_size = simple_strtoul(argv[1], &end, 10);
-	if (*end) {
+	if (*end || !chunk_size || chunk_size != (uint32_t)chunk_size) {
 		ti->error = "Invalid chunk_size";
 		return -EINVAL;
 	}
 
-	/*
-	 * chunk_size is a power of two
-	 */
-	if (!is_power_of_2(chunk_size) ||
-	    (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) {
-		ti->error = "Invalid chunk size";
-		return -EINVAL;
-	}
-
-	if (ti->len & (chunk_size - 1)) {
+	width = ti->len;
+	if (sector_div(width, chunk_size)) {
 		ti->error = "Target length not divisible by "
 		    "chunk size";
 		return -EINVAL;
 	}
 
-	width = ti->len;
 	if (sector_div(width, stripes)) {
 		ti->error = "Target length not divisible by "
 		    "number of stripes";
@@ -167,17 +156,21 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
 	if (stripes & (stripes - 1))
 		sc->stripes_shift = -1;
-	else {
-		sc->stripes_shift = ffs(stripes) - 1;
-		sc->stripes_mask = ((sector_t) stripes) - 1;
-	}
+	else
+		sc->stripes_shift = __ffs(stripes);
+
+	r = dm_set_target_max_io_len(ti, chunk_size);
+	if (r)
+		return r;
 
-	ti->split_io = chunk_size;
 	ti->num_flush_requests = stripes;
 	ti->num_discard_requests = stripes;
 
-	sc->chunk_shift = ffs(chunk_size) - 1;
-	sc->chunk_mask = ((sector_t) chunk_size) - 1;
+	sc->chunk_size = chunk_size;
+	if (chunk_size & (chunk_size - 1))
+		sc->chunk_size_shift = -1;
+	else
+		sc->chunk_size_shift = __ffs(chunk_size);
 
 	/*
 	 * Get the stripe destinations.
@@ -216,17 +209,29 @@ static void stripe_dtr(struct dm_target *ti)
 static void stripe_map_sector(struct stripe_c *sc, sector_t sector,
 			      uint32_t *stripe, sector_t *result)
 {
-	sector_t offset = dm_target_offset(sc->ti, sector);
-	sector_t chunk = offset >> sc->chunk_shift;
+	sector_t chunk = dm_target_offset(sc->ti, sector);
+	sector_t chunk_offset;
+
+	if (sc->chunk_size_shift < 0)
+		chunk_offset = sector_div(chunk, sc->chunk_size);
+	else {
+		chunk_offset = chunk & (sc->chunk_size - 1);
+		chunk >>= sc->chunk_size_shift;
+	}
 
 	if (sc->stripes_shift < 0)
 		*stripe = sector_div(chunk, sc->stripes);
 	else {
-		*stripe = chunk & sc->stripes_mask;
+		*stripe = chunk & (sc->stripes - 1);
 		chunk >>= sc->stripes_shift;
 	}
 
-	*result = (chunk << sc->chunk_shift) | (offset & sc->chunk_mask);
+	if (sc->chunk_size_shift < 0)
+		chunk *= sc->chunk_size;
+	else
+		chunk <<= sc->chunk_size_shift;
+
+	*result = chunk + chunk_offset;
 }
 
 static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
@@ -237,9 +242,16 @@ static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
 	stripe_map_sector(sc, sector, &stripe, result);
 	if (stripe == target_stripe)
 		return;
-	*result &= ~sc->chunk_mask;			/* round down */
+
+	/* round down */
+	sector = *result;
+	if (sc->chunk_size_shift < 0)
+		*result -= sector_div(sector, sc->chunk_size);
+	else
+		*result = sector & ~(sector_t)(sc->chunk_size - 1);
+
 	if (target_stripe < stripe)
-		*result += sc->chunk_mask + 1;		/* next chunk */
+		*result += sc->chunk_size;		/* next chunk */
 }
 
 static int stripe_map_discard(struct stripe_c *sc, struct bio *bio,
@@ -324,7 +336,7 @@ static int stripe_status(struct dm_target *ti,
 
 	case STATUSTYPE_TABLE:
 		DMEMIT("%d %llu", sc->stripes,
-			(unsigned long long)sc->chunk_mask + 1);
+			(unsigned long long)sc->chunk_size);
 		for (i = 0; i < sc->stripes; i++)
 			DMEMIT(" %s %llu", sc->stripe[i].dev->name,
 			    (unsigned long long)sc->stripe[i].physical_start);
@@ -391,7 +403,7 @@ static void stripe_io_hints(struct dm_target *ti,
 			    struct queue_limits *limits)
 {
 	struct stripe_c *sc = ti->private;
-	unsigned chunk_size = (sc->chunk_mask + 1) << 9;
+	unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT;
 
 	blk_limits_io_min(limits, chunk_size);
 	blk_limits_io_opt(limits, chunk_size * sc->stripes);
@@ -419,7 +431,7 @@ static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
 
 static struct target_type stripe_target = {
 	.name   = "striped",
-	.version = {1, 4, 0},
+	.version = {1, 5, 0},
 	.module = THIS_MODULE,
 	.ctr    = stripe_ctr,
 	.dtr    = stripe_dtr,
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 3e2907f..c858931 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -1262,7 +1262,7 @@ dm_thin_id dm_thin_dev_id(struct dm_thin_device *td)
 	return td->id;
 }
 
-static int __snapshotted_since(struct dm_thin_device *td, uint32_t time)
+static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time)
 {
 	return td->snapshotted_time > time;
 }
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h
index b88918c..7b47c0a 100644
--- a/drivers/md/dm-thin-metadata.h
+++ b/drivers/md/dm-thin-metadata.h
@@ -119,7 +119,7 @@ dm_thin_id dm_thin_dev_id(struct dm_thin_device *td);
 
 struct dm_thin_lookup_result {
 	dm_block_t block;
-	int shared;
+	unsigned shared:1;
 };
 
 /*
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 37fdaf8..efc6b4e 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -510,10 +510,9 @@ struct pool {
 	struct block_device *md_dev;
 	struct dm_pool_metadata *pmd;
 
-	uint32_t sectors_per_block;
-	unsigned block_shift;
-	dm_block_t offset_mask;
 	dm_block_t low_water_blocks;
+	uint32_t sectors_per_block;
+	int sectors_per_block_shift;
 
 	struct pool_features pf;
 	unsigned low_water_triggered:1;	/* A dm event has been sent */
@@ -526,8 +525,8 @@ struct pool {
 	struct work_struct worker;
 	struct delayed_work waker;
 
-	unsigned ref_count;
 	unsigned long last_commit_jiffies;
+	unsigned ref_count;
 
 	spinlock_t lock;
 	struct bio_list deferred_bios;
@@ -679,16 +678,28 @@ static void requeue_io(struct thin_c *tc)
 
 static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio)
 {
-	return bio->bi_sector >> tc->pool->block_shift;
+	sector_t block_nr = bio->bi_sector;
+
+	if (tc->pool->sectors_per_block_shift < 0)
+		(void) sector_div(block_nr, tc->pool->sectors_per_block);
+	else
+		block_nr >>= tc->pool->sectors_per_block_shift;
+
+	return block_nr;
 }
 
 static void remap(struct thin_c *tc, struct bio *bio, dm_block_t block)
 {
 	struct pool *pool = tc->pool;
+	sector_t bi_sector = bio->bi_sector;
 
 	bio->bi_bdev = tc->pool_dev->bdev;
-	bio->bi_sector = (block << pool->block_shift) +
-		(bio->bi_sector & pool->offset_mask);
+	if (tc->pool->sectors_per_block_shift < 0)
+		bio->bi_sector = (block * pool->sectors_per_block) +
+				 sector_div(bi_sector, pool->sectors_per_block);
+	else
+		bio->bi_sector = (block << pool->sectors_per_block_shift) |
+				(bi_sector & (pool->sectors_per_block - 1));
 }
 
 static void remap_to_origin(struct thin_c *tc, struct bio *bio)
@@ -933,9 +944,7 @@ static void process_prepared(struct pool *pool, struct list_head *head,
  */
 static int io_overlaps_block(struct pool *pool, struct bio *bio)
 {
-	return !(bio->bi_sector & pool->offset_mask) &&
-		(bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT));
-
+	return bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT);
 }
 
 static int io_overwrites_block(struct pool *pool, struct bio *bio)
@@ -1218,7 +1227,7 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
 			 */
 			m = get_next_mapping(pool);
 			m->tc = tc;
-			m->pass_discard = (!lookup_result.shared) & pool->pf.discard_passdown;
+			m->pass_discard = (!lookup_result.shared) && pool->pf.discard_passdown;
 			m->virt_block = block;
 			m->data_block = lookup_result.block;
 			m->cell = cell;
@@ -1239,8 +1248,10 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
 			 * part of the discard that is in a subsequent
 			 * block.
 			 */
-			sector_t offset = bio->bi_sector - (block << pool->block_shift);
-			unsigned remaining = (pool->sectors_per_block - offset) << 9;
+			sector_t offset = pool->sectors_per_block_shift >= 0 ?
+			      bio->bi_sector & (pool->sectors_per_block - 1) :
+			      bio->bi_sector - block * pool->sectors_per_block;
+			unsigned remaining = (pool->sectors_per_block - offset) << SECTOR_SHIFT;
 			bio->bi_size = min(bio->bi_size, remaining);
 
 			cell_release_singleton(cell, bio);
@@ -1719,8 +1730,10 @@ static struct pool *pool_create(struct mapped_device *pool_md,
 
 	pool->pmd = pmd;
 	pool->sectors_per_block = block_size;
-	pool->block_shift = ffs(block_size) - 1;
-	pool->offset_mask = block_size - 1;
+	if (block_size & (block_size - 1))
+		pool->sectors_per_block_shift = -1;
+	else
+		pool->sectors_per_block_shift = __ffs(block_size);
 	pool->low_water_blocks = 0;
 	pool_features_init(&pool->pf);
 	pool->prison = prison_create(PRISON_CELLS);
@@ -1825,15 +1838,19 @@ static struct pool *__pool_find(struct mapped_device *pool_md,
 	struct pool *pool = __pool_table_lookup_metadata_dev(metadata_dev);
 
 	if (pool) {
-		if (pool->pool_md != pool_md)
+		if (pool->pool_md != pool_md) {
+			*error = "metadata device already in use by a pool";
 			return ERR_PTR(-EBUSY);
+		}
 		__pool_inc(pool);
 
 	} else {
 		pool = __pool_table_lookup(pool_md);
 		if (pool) {
-			if (pool->md_dev != metadata_dev)
+			if (pool->md_dev != metadata_dev) {
+				*error = "different pool cannot replace a pool";
 				return ERR_PTR(-EINVAL);
+			}
 			__pool_inc(pool);
 
 		} else {
@@ -1964,7 +1981,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
 	if (kstrtoul(argv[2], 10, &block_size) || !block_size ||
 	    block_size < DATA_DEV_BLOCK_SIZE_MIN_SECTORS ||
 	    block_size > DATA_DEV_BLOCK_SIZE_MAX_SECTORS ||
-	    !is_power_of_2(block_size)) {
+	    block_size & (DATA_DEV_BLOCK_SIZE_MIN_SECTORS - 1)) {
 		ti->error = "Invalid block size";
 		r = -EINVAL;
 		goto out;
@@ -2090,7 +2107,8 @@ static int pool_preresume(struct dm_target *ti)
 	int r;
 	struct pool_c *pt = ti->private;
 	struct pool *pool = pt->pool;
-	dm_block_t data_size, sb_data_size;
+	sector_t data_size = ti->len;
+	dm_block_t sb_data_size;
 
 	/*
 	 * Take control of the pool object.
@@ -2099,7 +2117,8 @@ static int pool_preresume(struct dm_target *ti)
 	if (r)
 		return r;
 
-	data_size = ti->len >> pool->block_shift;
+	(void) sector_div(data_size, pool->sectors_per_block);
+
 	r = dm_pool_get_data_dev_size(pool->pmd, &sb_data_size);
 	if (r) {
 		DMERR("failed to retrieve data device size");
@@ -2292,6 +2311,13 @@ static int process_reserve_metadata_snap_mesg(unsigned argc, char **argv, struct
 	if (r)
 		return r;
 
+	r = dm_pool_commit_metadata(pool->pmd);
+	if (r) {
+		DMERR("%s: dm_pool_commit_metadata() failed, error = %d",
+		      __func__, r);
+		return r;
+	}
+
 	r = dm_pool_reserve_metadata_snap(pool->pmd);
 	if (r)
 		DMWARN("reserve_metadata_snap message failed.");
@@ -2614,7 +2640,10 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 		goto bad_thin_open;
 	}
 
-	ti->split_io = tc->pool->sectors_per_block;
+	r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block);
+	if (r)
+		goto bad_thin_open;
+
 	ti->num_flush_requests = 1;
 
 	/* In case the pool supports discards, pass them on. */
@@ -2746,19 +2775,21 @@ static int thin_status(struct dm_target *ti, status_type_t type,
 static int thin_iterate_devices(struct dm_target *ti,
 				iterate_devices_callout_fn fn, void *data)
 {
-	dm_block_t blocks;
+	sector_t blocks;
 	struct thin_c *tc = ti->private;
+	struct pool *pool = tc->pool;
 
 	/*
 	 * We can't call dm_pool_get_data_dev_size() since that blocks.  So
 	 * we follow a more convoluted path through to the pool's target.
 	 */
-	if (!tc->pool->ti)
+	if (!pool->ti)
 		return 0;	/* nothing is bound */
 
-	blocks = tc->pool->ti->len >> tc->pool->block_shift;
+	blocks = pool->ti->len;
+	(void) sector_div(blocks, pool->sectors_per_block);
 	if (blocks)
-		return fn(ti, tc->pool_dev, 0, tc->pool->sectors_per_block * blocks, data);
+		return fn(ti, tc->pool_dev, 0, pool->sectors_per_block * blocks, data);
 
 	return 0;
 }
@@ -2775,7 +2806,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
 static struct target_type thin_target = {
 	.name = "thin",
-	.version = {1, 1, 0},
+	.version = {1, 2, 0},
 	.module	= THIS_MODULE,
 	.ctr = thin_ctr,
 	.dtr = thin_dtr,
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index e24143c..415c280 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -968,22 +968,41 @@ static sector_t max_io_len_target_boundary(sector_t sector, struct dm_target *ti
 static sector_t max_io_len(sector_t sector, struct dm_target *ti)
 {
 	sector_t len = max_io_len_target_boundary(sector, ti);
+	sector_t offset, max_len;
 
 	/*
-	 * Does the target need to split even further ?
+	 * Does the target need to split even further?
 	 */
-	if (ti->split_io) {
-		sector_t boundary;
-		sector_t offset = dm_target_offset(ti, sector);
-		boundary = ((offset + ti->split_io) & ~(ti->split_io - 1))
-			   - offset;
-		if (len > boundary)
-			len = boundary;
+	if (ti->max_io_len) {
+		offset = dm_target_offset(ti, sector);
+		if (unlikely(ti->max_io_len & (ti->max_io_len - 1)))
+			max_len = sector_div(offset, ti->max_io_len);
+		else
+			max_len = offset & (ti->max_io_len - 1);
+		max_len = ti->max_io_len - max_len;
+
+		if (len > max_len)
+			len = max_len;
 	}
 
 	return len;
 }
 
+int dm_set_target_max_io_len(struct dm_target *ti, sector_t len)
+{
+	if (len > UINT_MAX) {
+		DMERR("Specified maximum size of target IO (%llu) exceeds limit (%u)",
+		      (unsigned long long)len, UINT_MAX);
+		ti->error = "Maximum size of target IO is too large";
+		return -EINVAL;
+	}
+
+	ti->max_io_len = (uint32_t) len;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dm_set_target_max_io_len);
+
 static void __map_bio(struct dm_target *ti, struct bio *clone,
 		      struct dm_target_io *tio)
 {
diff --git a/drivers/md/persistent-data/dm-space-map-checker.c b/drivers/md/persistent-data/dm-space-map-checker.c
index 50ed53b..6d7c832 100644
--- a/drivers/md/persistent-data/dm-space-map-checker.c
+++ b/drivers/md/persistent-data/dm-space-map-checker.c
@@ -343,25 +343,25 @@ struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm)
 	int r;
 	struct sm_checker *smc;
 
-	if (!sm)
-		return NULL;
+	if (IS_ERR_OR_NULL(sm))
+		return ERR_PTR(-EINVAL);
 
 	smc = kmalloc(sizeof(*smc), GFP_KERNEL);
 	if (!smc)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	memcpy(&smc->sm, &ops_, sizeof(smc->sm));
 	r = ca_create(&smc->old_counts, sm);
 	if (r) {
 		kfree(smc);
-		return NULL;
+		return ERR_PTR(r);
 	}
 
 	r = ca_create(&smc->counts, sm);
 	if (r) {
 		ca_destroy(&smc->old_counts);
 		kfree(smc);
-		return NULL;
+		return ERR_PTR(r);
 	}
 
 	smc->real_sm = sm;
@@ -371,7 +371,7 @@ struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm)
 		ca_destroy(&smc->counts);
 		ca_destroy(&smc->old_counts);
 		kfree(smc);
-		return NULL;
+		return ERR_PTR(r);
 	}
 
 	r = ca_commit(&smc->old_counts, &smc->counts);
@@ -379,7 +379,7 @@ struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm)
 		ca_destroy(&smc->counts);
 		ca_destroy(&smc->old_counts);
 		kfree(smc);
-		return NULL;
+		return ERR_PTR(r);
 	}
 
 	return &smc->sm;
@@ -391,25 +391,25 @@ struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm)
 	int r;
 	struct sm_checker *smc;
 
-	if (!sm)
-		return NULL;
+	if (IS_ERR_OR_NULL(sm))
+		return ERR_PTR(-EINVAL);
 
 	smc = kmalloc(sizeof(*smc), GFP_KERNEL);
 	if (!smc)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	memcpy(&smc->sm, &ops_, sizeof(smc->sm));
 	r = ca_create(&smc->old_counts, sm);
 	if (r) {
 		kfree(smc);
-		return NULL;
+		return ERR_PTR(r);
 	}
 
 	r = ca_create(&smc->counts, sm);
 	if (r) {
 		ca_destroy(&smc->old_counts);
 		kfree(smc);
-		return NULL;
+		return ERR_PTR(r);
 	}
 
 	smc->real_sm = sm;
diff --git a/drivers/md/persistent-data/dm-space-map-disk.c b/drivers/md/persistent-data/dm-space-map-disk.c
index fc469ba..3d0ed53 100644
--- a/drivers/md/persistent-data/dm-space-map-disk.c
+++ b/drivers/md/persistent-data/dm-space-map-disk.c
@@ -290,7 +290,16 @@ struct dm_space_map *dm_sm_disk_create(struct dm_transaction_manager *tm,
 				       dm_block_t nr_blocks)
 {
 	struct dm_space_map *sm = dm_sm_disk_create_real(tm, nr_blocks);
-	return dm_sm_checker_create_fresh(sm);
+	struct dm_space_map *smc;
+
+	if (IS_ERR_OR_NULL(sm))
+		return sm;
+
+	smc = dm_sm_checker_create_fresh(sm);
+	if (IS_ERR(smc))
+		dm_sm_destroy(sm);
+
+	return smc;
 }
 EXPORT_SYMBOL_GPL(dm_sm_disk_create);
 
diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c
index 400fe14..e5604b3 100644
--- a/drivers/md/persistent-data/dm-transaction-manager.c
+++ b/drivers/md/persistent-data/dm-transaction-manager.c
@@ -138,6 +138,9 @@ EXPORT_SYMBOL_GPL(dm_tm_create_non_blocking_clone);
 
 void dm_tm_destroy(struct dm_transaction_manager *tm)
 {
+	if (!tm->is_clone)
+		wipe_shadow_table(tm);
+
 	kfree(tm);
 }
 EXPORT_SYMBOL_GPL(dm_tm_destroy);
@@ -344,8 +347,10 @@ static int dm_tm_create_internal(struct dm_block_manager *bm,
 		}
 
 		*sm = dm_sm_checker_create(inner);
-		if (!*sm)
+		if (IS_ERR(*sm)) {
+			r = PTR_ERR(*sm);
 			goto bad2;
+		}
 
 	} else {
 		r = dm_bm_write_lock(dm_tm_get_bm(*tm), sb_location,
@@ -364,8 +369,10 @@ static int dm_tm_create_internal(struct dm_block_manager *bm,
 		}
 
 		*sm = dm_sm_checker_create(inner);
-		if (!*sm)
+		if (IS_ERR(*sm)) {
+			r = PTR_ERR(*sm);
 			goto bad2;
+		}
 	}
 
 	return 0;
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 7d42c11..0cdbd74 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -198,7 +198,6 @@ static int fops_open(struct file *file)
 	struct saa7146_dev *dev = video_drvdata(file);
 	struct saa7146_fh *fh = NULL;
 	int result = 0;
-	enum v4l2_buf_type type;
 
 	DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
 
@@ -207,10 +206,6 @@ static int fops_open(struct file *file)
 
 	DEB_D("using: %p\n", dev);
 
-	type = vdev->vfl_type == VFL_TYPE_GRABBER
-	     ? V4L2_BUF_TYPE_VIDEO_CAPTURE
-	     : V4L2_BUF_TYPE_VBI_CAPTURE;
-
 	/* check if an extension is registered */
 	if( NULL == dev->ext ) {
 		DEB_S("no extension registered for this device\n");
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index 98ecaf0..3180f5b 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -516,9 +516,9 @@ static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 	if(cx24110_readreg(state,0x10)&0x40) {
 		/* the RS error counter has finished one counting window */
 		cx24110_writereg(state,0x10,0x60); /* select the byer reg */
-		cx24110_readreg(state, 0x12) |
+		(void)(cx24110_readreg(state, 0x12) |
 			(cx24110_readreg(state, 0x13) << 8) |
-			(cx24110_readreg(state, 0x14) << 16);
+			(cx24110_readreg(state, 0x14) << 16));
 		cx24110_writereg(state,0x10,0x70); /* select the bler reg */
 		state->lastbler=cx24110_readreg(state,0x12)|
 			(cx24110_readreg(state,0x13)<<8)|
diff --git a/drivers/media/dvb/frontends/cxd2820r_c.c b/drivers/media/dvb/frontends/cxd2820r_c.c
index 9454049..ed3b0ba6 100644
--- a/drivers/media/dvb/frontends/cxd2820r_c.c
+++ b/drivers/media/dvb/frontends/cxd2820r_c.c
@@ -121,7 +121,7 @@ int cxd2820r_get_frontend_c(struct dvb_frontend *fe)
 	if (ret)
 		goto error;
 
-	switch ((buf[0] >> 0) & 0x03) {
+	switch ((buf[0] >> 0) & 0x07) {
 	case 0:
 		c->modulation = QAM_16;
 		break;
diff --git a/drivers/media/dvb/frontends/lg2160.c b/drivers/media/dvb/frontends/lg2160.c
index a3ab1a5..cc11260 100644
--- a/drivers/media/dvb/frontends/lg2160.c
+++ b/drivers/media/dvb/frontends/lg2160.c
@@ -126,7 +126,7 @@ static int lg216x_write_regs(struct lg216x_state *state,
 
 	lg_reg("writing %d registers...\n", len);
 
-	for (i = 0; i < len - 1; i++) {
+	for (i = 0; i < len; i++) {
 		ret = lg216x_write_reg(state, regs[i].reg, regs[i].val);
 		if (lg_fail(ret))
 			return ret;
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 2322257..e2fec9e 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -634,7 +634,6 @@ static int s5h1420_set_frontend(struct dvb_frontend *fe)
 	struct s5h1420_state* state = fe->demodulator_priv;
 	int frequency_delta;
 	struct dvb_frontend_tune_settings fesettings;
-	uint8_t clock_setting;
 
 	dprintk("enter %s\n", __func__);
 
@@ -679,25 +678,6 @@ static int s5h1420_set_frontend(struct dvb_frontend *fe)
 	else
 		state->fclk = 44000000;
 
-	/* Clock */
-	switch (state->fclk) {
-	default:
-	case 88000000:
-		clock_setting = 80;
-		break;
-	case 86000000:
-		clock_setting = 78;
-		break;
-	case 80000000:
-		clock_setting = 72;
-		break;
-	case 59000000:
-		clock_setting = 51;
-		break;
-	case 44000000:
-		clock_setting = 36;
-		break;
-	}
 	dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
 	s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8);
 	s5h1420_writereg(state, PLL02, 0x40);
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c
index 8b0dc74..5d7f8a9 100644
--- a/drivers/media/dvb/frontends/stb0899_drv.c
+++ b/drivers/media/dvb/frontends/stb0899_drv.c
@@ -1129,7 +1129,6 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
 	struct stb0899_internal *internal	= &state->internal;
 
 	u8  lsb, msb;
-	u32 i;
 
 	*ber = 0;
 
@@ -1137,14 +1136,9 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
 	case SYS_DVBS:
 	case SYS_DSS:
 		if (internal->lock) {
-			/* average 5 BER values	*/
-			for (i = 0; i < 5; i++) {
-				msleep(100);
-				lsb = stb0899_read_reg(state, STB0899_ECNT1L);
-				msb = stb0899_read_reg(state, STB0899_ECNT1M);
-				*ber += MAKEWORD16(msb, lsb);
-			}
-			*ber /= 5;
+			lsb = stb0899_read_reg(state, STB0899_ECNT1L);
+			msb = stb0899_read_reg(state, STB0899_ECNT1M);
+			*ber = MAKEWORD16(msb, lsb);
 			/* Viterbi Check	*/
 			if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) {
 				/* Error Rate		*/
@@ -1157,13 +1151,9 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
 		break;
 	case SYS_DVBS2:
 		if (internal->lock) {
-			/* Average 5 PER values	*/
-			for (i = 0; i < 5; i++) {
-				msleep(100);
-				lsb = stb0899_read_reg(state, STB0899_ECNT1L);
-				msb = stb0899_read_reg(state, STB0899_ECNT1M);
-				*ber += MAKEWORD16(msb, lsb);
-			}
+			lsb = stb0899_read_reg(state, STB0899_ECNT1L);
+			msb = stb0899_read_reg(state, STB0899_ECNT1M);
+			*ber = MAKEWORD16(msb, lsb);
 			/* ber = ber * 10 ^ 7	*/
 			*ber *= 10000000;
 			*ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl))));
diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c
index fdd20c7..2a8aaeb 100644
--- a/drivers/media/dvb/frontends/stv0367.c
+++ b/drivers/media/dvb/frontends/stv0367.c
@@ -1584,7 +1584,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe)
 	struct stv0367ter_state *ter_state = state->ter_state;
 	int offset = 0, tempo = 0;
 	u8 u_var;
-	u8 /*constell,*/ counter, tps_rcvd[2];
+	u8 /*constell,*/ counter;
 	s8 step;
 	s32 timing_offset = 0;
 	u32 trl_nomrate = 0, InternalFreq = 0, temp = 0;
@@ -1709,9 +1709,6 @@ static int stv0367ter_algo(struct dvb_frontend *fe)
 		return 0;
 
 	ter_state->state = FE_TER_LOCKOK;
-	/* update results */
-	tps_rcvd[0] = stv0367_readreg(state, R367TER_TPS_RCVD2);
-	tps_rcvd[1] = stv0367_readreg(state, R367TER_TPS_RCVD3);
 
 	ter_state->mode = stv0367_readbits(state, F367TER_SYR_MODE);
 	ter_state->guard = stv0367_readbits(state, F367TER_SYR_GUARD);
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index d79e69f..d229dba 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -3172,7 +3172,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 	enum stv090x_signal_state signal_state = STV090x_NOCARRIER;
 	u32 reg;
 	s32 agc1_power, power_iq = 0, i;
-	int lock = 0, low_sr = 0, no_signal = 0;
+	int lock = 0, low_sr = 0;
 
 	reg = STV090x_READ_DEMOD(state, TSCFGH);
 	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */
@@ -3411,10 +3411,9 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 			/* Reset the packet Error counter2 */
 			if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
 				goto err;
-		} else {
+		} else
 			signal_state = STV090x_NODATA;
-			no_signal = stv090x_chk_signal(state);
-		}
+
 	}
 	return signal_state;
 
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
index 63c004a..664e460 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -544,6 +544,8 @@ static const struct usb_device_id smsusb_id_table[] __devinitconst = {
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 	{ USB_DEVICE(0x2040, 0xc0a0),
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0xf5a0),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 	{ } /* Terminating entry */
 	};
 
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index c257da1..f4c3924 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -191,10 +191,16 @@ config RADIO_CADET
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-cadet.
 
+config RADIO_LM7000
+	tristate
+	depends on RADIO_RTRACK || RADIO_SF16FMI
+	default RADIO_RTRACK || RADIO_SF16FMI
+
 config RADIO_RTRACK
 	tristate "AIMSlab RadioTrack (aka RadioReveal) support"
 	depends on ISA && VIDEO_V4L2
 	select RADIO_ISA
+	select RADIO_LM7000
 	---help---
 	  Choose Y here if you have one of these FM radio cards, and then fill
 	  in the port address below.
@@ -322,6 +328,7 @@ config RADIO_MIROPCM20
 config RADIO_SF16FMI
 	tristate "SF16-FMI/SF16-FMP/SF16-FMD Radio"
 	depends on ISA && VIDEO_V4L2
+	select RADIO_LM7000
 	---help---
 	  Choose Y here if you have one of these FM radio cards.
 
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index ca8c7d1..7f6aa63 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -28,5 +28,6 @@ obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
 obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
 obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o
 obj-$(CONFIG_RADIO_WL128X) += wl128x/
+obj-$(CONFIG_RADIO_LM7000) += lm7000.o
 
 ccflags-y += -Isound
diff --git a/drivers/media/radio/lm7000.c b/drivers/media/radio/lm7000.c
new file mode 100644
index 0000000..681f3af
--- /dev/null
+++ b/drivers/media/radio/lm7000.c
@@ -0,0 +1,52 @@
+/* Sanyo LM7000 tuner chip driver
+ *
+ * Copyright 2012 Ondrej Zary <linux@rainbow-software.org>
+ * based on radio-aimslab.c by M. Kirkwood
+ * and radio-sf16fmi.c by M. Kirkwood and Petr Vandrovec
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include "lm7000.h"
+
+MODULE_AUTHOR("Ondrej Zary <linux@rainbow-software.org>");
+MODULE_DESCRIPTION("Routines for Sanyo LM7000 AM/FM radio tuner chip");
+MODULE_LICENSE("GPL");
+
+/* write the 24-bit register, starting with LSB */
+static void lm7000_write(struct lm7000 *lm, u32 val)
+{
+	int i;
+	u8 data;
+
+	for (i = 0; i < 24; i++) {
+		data = val & (1 << i) ? LM7000_DATA : 0;
+		lm->set_pins(lm, data | LM7000_CE);
+		udelay(2);
+		lm->set_pins(lm, data | LM7000_CE | LM7000_CLK);
+		udelay(2);
+		lm->set_pins(lm, data | LM7000_CE);
+		udelay(2);
+	}
+	lm->set_pins(lm, 0);
+}
+
+void lm7000_set_freq(struct lm7000 *lm, u32 freq)
+{
+	freq += 171200;		/* Add 10.7 MHz IF */
+	freq /= 400;		/* Convert to 25 kHz units */
+	lm7000_write(lm, freq | LM7000_FM_25 | LM7000_BIT_FM);
+}
+EXPORT_SYMBOL(lm7000_set_freq);
+
+static int __init lm7000_module_init(void)
+{
+	return 0;
+}
+
+static void __exit lm7000_module_exit(void)
+{
+}
+
+module_init(lm7000_module_init)
+module_exit(lm7000_module_exit)
diff --git a/drivers/media/radio/lm7000.h b/drivers/media/radio/lm7000.h
new file mode 100644
index 0000000..a5bc7d6
--- /dev/null
+++ b/drivers/media/radio/lm7000.h
@@ -0,0 +1,32 @@
+#ifndef __LM7000_H
+#define __LM7000_H
+
+#define LM7000_DATA	(1 << 0)
+#define LM7000_CLK	(1 << 1)
+#define LM7000_CE	(1 << 2)
+
+#define LM7000_FREQ_MASK 0x3fff
+#define LM7000_BIT_T0	(1 << 14)
+#define LM7000_BIT_T1	(1 << 15)
+#define LM7000_BIT_B0	(1 << 16)
+#define LM7000_BIT_B1	(1 << 17)
+#define LM7000_BIT_B2	(1 << 18)
+#define LM7000_BIT_TB	(1 << 19)
+#define LM7000_FM_100	(0 << 20)
+#define LM7000_FM_50	(1 << 20)
+#define LM7000_FM_25	(2 << 20)
+#define LM7000_AM_5	(3 << 20)
+#define LM7000_AM_10	(4 << 20)
+#define LM7000_AM_9	(5 << 20)
+#define LM7000_AM_1	(6 << 20)
+#define LM7000_AM_5_	(7 << 20)
+#define LM7000_BIT_FM	(1 << 23)
+
+
+struct lm7000 {
+	void (*set_pins)(struct lm7000 *lm, u8 pins);
+};
+
+void lm7000_set_freq(struct lm7000 *lm, u32 freq);
+
+#endif /* __LM7000_H */
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 98e0c8c..48b72d8 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -37,6 +37,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
 #include "radio-isa.h"
+#include "lm7000.h"
 
 MODULE_AUTHOR("M. Kirkwood");
 MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
@@ -61,66 +62,53 @@ MODULE_PARM_DESC(radio_nr, "Radio device numbers");
 struct rtrack {
 	struct radio_isa_card isa;
 	int curvol;
+	struct lm7000 lm;
 };
 
-static struct radio_isa_card *rtrack_alloc(void)
+#define AIMS_BIT_TUN_CE		(1 << 0)
+#define AIMS_BIT_TUN_CLK	(1 << 1)
+#define AIMS_BIT_TUN_DATA	(1 << 2)
+#define AIMS_BIT_VOL_CE		(1 << 3)
+#define AIMS_BIT_TUN_STRQ	(1 << 4)
+/* bit 5 is not connected */
+#define AIMS_BIT_VOL_UP		(1 << 6)	/* active low */
+#define AIMS_BIT_VOL_DN		(1 << 7)	/* active low */
+
+void rtrack_set_pins(struct lm7000 *lm, u8 pins)
 {
-	struct rtrack *rt = kzalloc(sizeof(struct rtrack), GFP_KERNEL);
+	struct rtrack *rt = container_of(lm, struct rtrack, lm);
+	u8 bits = AIMS_BIT_VOL_DN | AIMS_BIT_VOL_UP | AIMS_BIT_TUN_STRQ;
 
-	if (rt)
-		rt->curvol = 0xff;
-	return rt ? &rt->isa : NULL;
-}
+	if (!v4l2_ctrl_g_ctrl(rt->isa.mute))
+		bits |= AIMS_BIT_VOL_CE;
 
-/* The 128+64 on these outb's is to keep the volume stable while tuning.
- * Without them, the volume _will_ creep up with each frequency change
- * and bit 4 (+16) is to keep the signal strength meter enabled.
- */
+	if (pins & LM7000_DATA)
+		bits |= AIMS_BIT_TUN_DATA;
+	if (pins & LM7000_CLK)
+		bits |= AIMS_BIT_TUN_CLK;
+	if (pins & LM7000_CE)
+		bits |= AIMS_BIT_TUN_CE;
 
-static void send_0_byte(struct radio_isa_card *isa, int on)
-{
-	outb_p(128+64+16+on+1, isa->io);	/* wr-enable + data low */
-	outb_p(128+64+16+on+2+1, isa->io);	/* clock */
-	msleep(1);
+	outb_p(bits, rt->isa.io);
 }
 
-static void send_1_byte(struct radio_isa_card *isa, int on)
+static struct radio_isa_card *rtrack_alloc(void)
 {
-	outb_p(128+64+16+on+4+1, isa->io);	/* wr-enable+data high */
-	outb_p(128+64+16+on+4+2+1, isa->io);	/* clock */
-	msleep(1);
+	struct rtrack *rt = kzalloc(sizeof(struct rtrack), GFP_KERNEL);
+
+	if (rt) {
+		rt->curvol = 0xff;
+		rt->lm.set_pins = rtrack_set_pins;
+	}
+	return rt ? &rt->isa : NULL;
 }
 
 static int rtrack_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
-	int on = v4l2_ctrl_g_ctrl(isa->mute) ? 0 : 8;
-	int i;
-
-	freq += 171200;			/* Add 10.7 MHz IF 		*/
-	freq /= 800;			/* Convert to 50 kHz units	*/
-
-	send_0_byte(isa, on);		/*  0: LSB of frequency		*/
-
-	for (i = 0; i < 13; i++)	/*   : frequency bits (1-13)	*/
-		if (freq & (1 << i))
-			send_1_byte(isa, on);
-		else
-			send_0_byte(isa, on);
-
-	send_0_byte(isa, on);		/* 14: test bit - always 0    */
-	send_0_byte(isa, on);		/* 15: test bit - always 0    */
-
-	send_0_byte(isa, on);		/* 16: band data 0 - always 0 */
-	send_0_byte(isa, on);		/* 17: band data 1 - always 0 */
-	send_0_byte(isa, on);		/* 18: band data 2 - always 0 */
-	send_0_byte(isa, on);		/* 19: time base - always 0   */
+	struct rtrack *rt = container_of(isa, struct rtrack, isa);
 
-	send_0_byte(isa, on);		/* 20: spacing (0 = 25 kHz)   */
-	send_1_byte(isa, on);		/* 21: spacing (1 = 25 kHz)   */
-	send_0_byte(isa, on);		/* 22: spacing (0 = 25 kHz)   */
-	send_1_byte(isa, on);		/* 23: AM/FM (FM = 1, always) */
+	lm7000_set_freq(&rt->lm, freq);
 
-	outb(0xd0 + on, isa->io);	/* volume steady + sigstr */
 	return 0;
 }
 
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 740a3d5..b415211 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -157,7 +157,7 @@ static int __devinit maxiradio_probe(struct pci_dev *pdev, const struct pci_devi
 		goto err_out_free_region;
 
 	dev->io = pci_resource_start(pdev, 0);
-	if (snd_tea575x_init(&dev->tea)) {
+	if (snd_tea575x_init(&dev->tea, THIS_MODULE)) {
 		printk(KERN_ERR "radio-maxiradio: Unable to detect TEA575x tuner\n");
 		goto err_out_free_region;
 	}
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index 94cb6bc..3182b26 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -295,7 +295,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 	v->type = V4L2_TUNER_RADIO;
 	v->rangelow = FREQ_MIN * FREQ_MUL;
 	v->rangehigh = FREQ_MAX * FREQ_MUL;
-	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+		V4L2_TUNER_CAP_HWSEEK_WRAP;
 	v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
 	v->audmode = radio->stereo ?
 		V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
@@ -372,7 +373,7 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *priv,
 	timeout = jiffies + msecs_to_jiffies(30000);
 	for (;;) {
 		if (time_after(jiffies, timeout)) {
-			retval = -EAGAIN;
+			retval = -ENODATA;
 			break;
 		}
 		if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index a81d723..ddd922d 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -27,6 +27,8 @@
 #include <linux/io.h>		/* outb, outb_p			*/
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include "lm7000.h"
 
 MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
 MODULE_DESCRIPTION("A driver for the SF16-FMI, SF16-FMP and SF16-FMD radio.");
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 52b8011..4efcbec 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -238,7 +238,7 @@ static int __devinit fmr2_probe(struct fmr2 *fmr2, struct device *pdev, int io)
 	snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "%s:%s",
 			fmr2->is_fmd2 ? "PnP" : "ISA", dev_name(pdev));
 
-	if (snd_tea575x_init(&fmr2->tea)) {
+	if (snd_tea575x_init(&fmr2->tea, THIS_MODULE)) {
 		printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n");
 		release_region(fmr2->io, 2);
 		return -ENODEV;
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index f1b6070..e8428f5 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -1514,7 +1514,8 @@ static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv,
 	tuner->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH);
 
 	tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS |
-		V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO;
+		V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+		V4L2_TUNER_CAP_HWSEEK_BOUNDED | V4L2_TUNER_CAP_HWSEEK_WRAP;
 
 	if (radio->stereo)
 		tuner->audmode = V4L2_TUNER_MODE_STEREO;
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 969cf49..d485b79 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -363,7 +363,7 @@ stop:
 
 	/* try again, if timed out */
 	if (retval == 0 && timed_out)
-		return -EAGAIN;
+		return -ENODATA;
 	return retval;
 }
 
@@ -596,7 +596,9 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
 	strcpy(tuner->name, "FM");
 	tuner->type = V4L2_TUNER_RADIO;
 	tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
-			    V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
+			    V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+			    V4L2_TUNER_CAP_HWSEEK_BOUNDED |
+			    V4L2_TUNER_CAP_HWSEEK_WRAP;
 
 	/* range limits */
 	switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index e9f6387..f412f7a 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -51,6 +51,8 @@ static struct usb_device_id si470x_usb_driver_id_table[] = {
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) },
 	/* Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) */
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x10c5, 0x819a, USB_CLASS_HID, 0, 0) },
+	/* Axentia ALERT FM USB Receiver */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x12cf, 0x7111, USB_CLASS_HID, 0, 0) },
 	/* Terminating entry */
 	{ }
 };
diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c
index 43fb722..3dd9fc0 100644
--- a/drivers/media/radio/wl128x/fmdrv_rx.c
+++ b/drivers/media/radio/wl128x/fmdrv_rx.c
@@ -251,7 +251,7 @@ again:
 	if (!timeleft) {
 		fmerr("Timeout(%d sec),didn't get tune ended int\n",
 			   jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000);
-		return -ETIMEDOUT;
+		return -ENODATA;
 	}
 
 	int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT);
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index 080b96a..49a11ec 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -285,7 +285,9 @@ static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv,
 	tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO |
 	((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0);
 	tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
-			    V4L2_TUNER_CAP_LOW;
+			    V4L2_TUNER_CAP_LOW |
+			    V4L2_TUNER_CAP_HWSEEK_BOUNDED |
+			    V4L2_TUNER_CAP_HWSEEK_WRAP;
 	tuner->audmode = (stereo_mono_mode ?
 			  V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO);
 
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index a820251..42e6b3e 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -90,7 +90,9 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
 	IR_dprintk(2, "sample: (%05dus %s)\n",
 		   TO_US(ev->duration), TO_STR(ev->pulse));
 
-	if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
+	if (kfifo_avail(&dev->raw->kfifo) >= sizeof(*ev))
+		kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev));
+	else
 		return -ENOMEM;
 
 	return 0;
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index ff2933a..856ab96 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -371,7 +371,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 2, 0, 0, 0 },
 		.gpiomute 	= 10,
-		.needs_tvaudio	= 1,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -384,7 +383,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0, 1, 2, 3 },
 		.gpiomute 	= 4,
-		.needs_tvaudio	= 1,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -398,7 +396,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomux 	= { 4, 0, 2, 3 },
 		.gpiomute 	= 1,
 		.no_msp34xx	= 1,
-		.needs_tvaudio	= 1,
 		.tuner_type     = TUNER_PHILIPS_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.pll            = PLL_28,
@@ -414,7 +411,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask	= 0,
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0 },
-		.needs_tvaudio	= 0,
 		.tuner_type	= TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -427,7 +423,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 0),
 		.gpiomux 	= { 0, 1, 0, 1 },
 		.gpiomute 	= 3,
-		.needs_tvaudio	= 1,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -440,7 +435,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask	= 0x0f,
 		.gpiomux 	= { 0x0c, 0x04, 0x08, 0x04 },
 		/*                0x04 for some cards ?? */
-		.needs_tvaudio	= 1,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.audio_mode_gpio= avermedia_tvphone_audio,
@@ -454,7 +448,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask	= 0,
 		.muxsel		= MUXSEL(2, 3, 1, 0, 0),
 		.gpiomux 	= { 0 },
-		.needs_tvaudio	= 1,
 		.tuner_type	= TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -469,7 +462,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0, 0xc00, 0x800, 0x400 },
 		.gpiomute 	= 0xc00,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -482,7 +474,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask	= 3,
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 1, 1, 2, 3 },
-		.needs_tvaudio	= 0,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_TEMIC_PAL,
 		.tuner_addr	= ADDR_UNSET,
@@ -496,7 +487,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 0, 1, 1),
 		.gpiomux 	= { 0, 1, 2, 3 },
 		.gpiomute 	= 4,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -510,7 +500,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0x20001,0x10001, 0, 0 },
 		.gpiomute 	= 10,
-		.needs_tvaudio	= 1,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -524,7 +513,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask	= 15,
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 13, 14, 11, 7 },
-		.needs_tvaudio	= 1,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -536,7 +524,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask	= 15,
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 13, 14, 11, 7 },
-		.needs_tvaudio	= 1,
 		.msp34xx_alt    = 1,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_PHILIPS_PAL,
@@ -553,7 +540,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0, 2, 1, 3 }, /* old: {0, 1, 2, 3, 4} */
 		.gpiomute 	= 4,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -567,7 +553,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0, 0, 1, 0 },
 		.gpiomute 	= 10,
-		.needs_tvaudio	= 1,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -583,7 +568,6 @@ struct tvcard bttv_tvcards[] = {
 		/* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
 		.gpiomux        = { 0x001e00, 0, 0x018000, 0x014000 },
 		.gpiomute 	= 0x002000,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= UNSET,
 		.tuner_addr     = ADDR_UNSET,
@@ -597,7 +581,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1, 0),
 		.gpiomux 	= { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 },
 		.gpiomute 	= 0xcfa007,
-		.needs_tvaudio	= 1,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.volume_gpio	= winview_volume,
@@ -611,7 +594,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask	= 0,
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 1, 0, 0, 0 },
-		.needs_tvaudio	= 1,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -660,7 +642,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0, 1, 0x800, 0x400 },
 		.gpiomute 	= 0xc00,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -691,7 +672,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= {0x400, 0x400, 0x400, 0x400 },
 		.gpiomute 	= 0xc00,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -706,7 +686,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 0x20000, 0x30000, 0x10000, 0 },
 		.gpiomute 	= 0x40000,
-		.needs_tvaudio	= 0,
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.audio_mode_gpio= terratv_audio,
@@ -720,7 +699,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 0, 1, 1),
 		.gpiomux 	= { 0, 1, 2, 3 },
 		.gpiomute 	= 4,
-		.needs_tvaudio	= 1,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -748,7 +726,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0x20000, 0x30000, 0x10000, 0x00000 },
 		.gpiomute 	= 0x40000,
-		.needs_tvaudio	= 0,
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.audio_mode_gpio= terratv_audio,
@@ -793,7 +770,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask	= 0,
 		.muxsel		= MUXSEL(2, 3, 1, 0, 0),
 		.gpiomux 	= { 0 },
-		.needs_tvaudio	= 1,
 		.tuner_type	= TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
 		.muxsel_hook    = PXC200_muxsel,
@@ -834,7 +810,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask	= 0,
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0 },
-		.needs_tvaudio	= 0,
 		.tuner_type	= TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -847,7 +822,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0x500, 0, 0x300, 0x900 },
 		.gpiomute 	= 0x900,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
@@ -874,7 +848,6 @@ struct tvcard bttv_tvcards[] = {
 		Note: There exists another variant "Winfast 2000" with tv stereo !?
 		Note: eeprom only contains FF and pci subsystem id 107d:6606
 		*/
-		.needs_tvaudio	= 0,
 		.pll		= PLL_28,
 		.has_radio	= 1,
 		.tuner_type	= TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
@@ -934,7 +907,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 0),
 		.gpiomux 	= { 0x551400, 0x551200, 0, 0 },
 		.gpiomute 	= 0x551c00,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_PHILIPS_PAL_I,
 		.tuner_addr	= ADDR_UNSET,
@@ -949,7 +921,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 2, 0xd0001, 0, 0 },
 		.gpiomute 	= 1,
-		.needs_tvaudio	= 0,
 		.pll		= PLL_28,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -966,7 +937,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomux 	= { 4, 0, 2, 3 },
 		.gpiomute 	= 1,
 		.no_msp34xx	= 1,
-		.needs_tvaudio	= 1,
 		.tuner_type     = TUNER_PHILIPS_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.pll            = PLL_28,
@@ -980,7 +950,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask	= 15,
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 13, 4, 11, 7 },
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -995,7 +964,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask	= 0,
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0, 0, 0, 0},
-		.needs_tvaudio	= 1,
 		.no_msp34xx	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_PHILIPS_PAL_I,
@@ -1066,7 +1034,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0x20000, 0x30000, 0x10000, 0 },
 		.gpiomute 	= 0x40000,
-		.needs_tvaudio	= 1,
 		.no_msp34xx	= 1,
 		.pll		= PLL_35,
 		.tuner_type	= TUNER_PHILIPS_PAL_I,
@@ -1084,7 +1051,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= {2,0,0,0 },
 		.gpiomute 	= 1,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -1163,7 +1129,6 @@ struct tvcard bttv_tvcards[] = {
 				MUX2 (mask 0x30000):
 					0,2,3= from MSP34xx
 					1= FM stereo Radio from Tuner */
-		.needs_tvaudio  = 0,
 		.pll            = PLL_28,
 		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -1179,7 +1144,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0, 0, 0x10, 8 },
 		.gpiomute 	= 4,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
@@ -1218,7 +1182,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 3, 1, 0),
 		.gpiomux        = { 2, 0, 0, 0 },
 		.gpiomute 	= 10,
-		.needs_tvaudio  = 0,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_TEMIC_PAL,
 		.tuner_addr	= ADDR_UNSET,
@@ -1250,7 +1213,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 0,
 		.muxsel         = MUXSEL(3, 1),
 		.gpiomux        = { 0 },
-		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_35,
 		.tuner_type     = TUNER_ABSENT,
@@ -1266,7 +1228,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 0x400, 0x400, 0x400, 0x400 },
 		.gpiomute 	= 0x800,
-		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_TEMIC_4036FY5_NTSC,
 		.tuner_addr	= ADDR_UNSET,
@@ -1312,7 +1273,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 2),
 		.gpiomux        = { },
 		.no_msp34xx     = 1,
-		.needs_tvaudio  = 0,
 		.pll		= PLL_28,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
@@ -1329,7 +1289,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 3, 1, 0),
 		.gpiomux        = { 1, 0, 4, 4 },
 		.gpiomute 	= 9,
-		.needs_tvaudio  = 0,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
@@ -1379,7 +1338,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomute 	= 0x1800,
 		.audio_mode_gpio= fv2000s_audio,
 		.no_msp34xx	= 1,
-		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
@@ -1393,7 +1351,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0x500, 0x500, 0x300, 0x900 },
 		.gpiomute 	= 0x900,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
@@ -1477,7 +1434,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 0, 0, 11, 7 }, /* TV and Radio with same GPIO ! */
 		.gpiomute 	= 13,
-		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_LG_PAL_I_FM,
 		.tuner_addr	= ADDR_UNSET,
@@ -1514,7 +1470,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 0x01, 0x00, 0x03, 0x03 },
 		.gpiomute 	= 0x09,
-		.needs_tvaudio  = 1,
 		.no_msp34xx	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_PHILIPS_PAL,
@@ -1540,7 +1495,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 0,
 		.muxsel         = MUXSEL(2, 3, 1, 0, 0),
 		.gpiomux        = { 0 },
-		.needs_tvaudio  = 0,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -1567,7 +1521,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 1, 1),
 		.gpiomux        = { 0, 1, 2, 2 },
 		.gpiomute 	= 4,
-		.needs_tvaudio  = 0,
 		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.pll		= PLL_28,
@@ -1597,7 +1550,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 0,
 		.muxsel         = MUXSEL(2, 3, 1, 0),
 		.gpiomux        = { 0 },
-		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
@@ -1619,7 +1571,6 @@ struct tvcard bttv_tvcards[] = {
 						* btwincap uses 0x80000/0x80003
 						*/
 		.gpiomute 	= 4,
-		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_PHILIPS_PAL,
@@ -1655,7 +1606,6 @@ struct tvcard bttv_tvcards[] = {
 		/* .audio_inputs= 1, */
 		.svhs           = 2,
 		.muxsel         = MUXSEL(2, 0, 1, 1),
-		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
 		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -1875,7 +1825,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 0, 1, 2, 3},
 		.gpiomute 	= 4,
-		.needs_tvaudio  = 1,
 		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.pll            = PLL_28,
@@ -1902,7 +1851,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 0,
 		.muxsel         = MUXSEL(2, 3),
 		.gpiomux        = { 0 },
-		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
@@ -1920,7 +1868,6 @@ struct tvcard bttv_tvcards[] = {
 		/*                  Tuner, Radio, external, internal, off,  on */
 		.gpiomux        = { 0x08,  0x0f,  0x0a,     0x08 },
 		.gpiomute 	= 0x0f,
-		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_PHILIPS_NTSC,
@@ -1936,7 +1883,6 @@ struct tvcard bttv_tvcards[] = {
 		.svhs           = 2,
 		.gpiomask       = 0x00,
 		.muxsel         = MUXSEL(2, 3, 1, 1),
-		.needs_tvaudio  = 1,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_PHILIPS_PAL,
@@ -2034,7 +1980,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 0,
 		.muxsel         = MUXSEL(2, 3, 1, 0),
 		.gpiomux        = { 0 },
-		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
@@ -2049,7 +1994,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 0x00,
 		.muxsel         = MUXSEL(2, 3, 1, 0),
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
-		.needs_tvaudio  = 0,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
@@ -2062,7 +2006,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 0x00,
 		.muxsel         = MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
-		.needs_tvaudio  = 0,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
@@ -2079,7 +2022,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 0),
 		.muxsel_hook	= phytec_muxsel,
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
-		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
@@ -2094,7 +2036,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 1),
 		.muxsel_hook	= phytec_muxsel,
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
-		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
@@ -2118,7 +2059,6 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
 		.svhs           = NO_SVHS,   /* card has no svhs */
-		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.no_tda7432     = 1,
 		.gpiomask       = 0x00,
@@ -2168,7 +2108,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 3,
 		.muxsel         = MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 1, 1, 1, 1 },
-		.needs_tvaudio  = 1,
 		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.pll            = PLL_35,
@@ -2210,7 +2149,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 3, 1, 0),
 		.no_msp34xx     = 1,
 		.no_tda7432     = 1,
-		.needs_tvaudio  = 0,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
 	},
@@ -2222,7 +2160,6 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.svhs           = 2,
-		.needs_tvaudio  = 0,
 		.gpiomask       = 0x68,
 		.muxsel         = MUXSEL(2, 3, 1),
 		.gpiomux        = { 0x68, 0x68, 0x61, 0x61 },
@@ -2241,7 +2178,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 0, 1, 2, 2 },
 		.gpiomute 	= 3,
-		.needs_tvaudio  = 0,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
@@ -2265,7 +2201,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 2, 2, 2),
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
 		.pll            = PLL_28,
-		.needs_tvaudio  = 0,
 		.muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
@@ -2358,7 +2293,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 2, 0, 0, 0 },
 		.gpiomute 	= 10,
-		.needs_tvaudio  = 0,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
@@ -2405,7 +2339,6 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_addr	= ADDR_UNSET,
 		.gpiomask       = 0x008007,
 		.gpiomux        = { 0, 0x000001,0,0 },
-		.needs_tvaudio  = 1,
 		.has_radio      = 1,
 	},
 	[BTTV_BOARD_TIBET_CS16] = {
@@ -2518,7 +2451,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 0x001e00, 0, 0x018000, 0x014000 },
 		.gpiomute 	= 0x002000,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_YMEC_TVF66T5_B_DFF,
 		.tuner_addr	= 0xc1 >>1,
@@ -2534,7 +2466,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 0, 1, 2, 2 },
 		.gpiomute 	= 3,
-		.needs_tvaudio  = 0,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_TENA_9533_DI,
 		.tuner_addr	= ADDR_UNSET,
@@ -2615,7 +2546,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel		= MUXSEL(2, 3, 1, 1),
 		.gpiomux 	= { 2, 0, 0, 0 },
 		.gpiomute 	= 1,
-		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= TUNER_PHILIPS_NTSC,
 		.tuner_addr	= ADDR_UNSET,
@@ -2714,7 +2644,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 0x20001,0x10001, 0, 0 },
 		.gpiomute       = 10,
-		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_PHILIPS_PAL_I,
 		.tuner_addr     = ADDR_UNSET,
@@ -2746,7 +2675,6 @@ struct tvcard bttv_tvcards[] = {
 		.muxsel         = MUXSEL(2, 3, 1, 1),
 		.gpiomux        = { 0, 1, 2, 2 }, /* CONTVFMi */
 		.gpiomute 	= 3, /* CONTVFMi */
-		.needs_tvaudio  = 0,
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MK3 */
 		.tuner_addr     = ADDR_UNSET,
 		.pll            = PLL_28,
@@ -2785,7 +2713,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 0x00,
 		.muxsel         = MUXSEL(0, 2, 3, 1),
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
-		.needs_tvaudio  = 0,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
@@ -2799,7 +2726,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 0x00,
 		.muxsel         = MUXSEL(2, 3, 1),
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
-		.needs_tvaudio  = 0,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
@@ -2813,7 +2739,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 0x00,
 		.muxsel         = MUXSEL(3, 2, 1),
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
-		.needs_tvaudio  = 0,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
@@ -2877,7 +2802,6 @@ struct tvcard bttv_tvcards[] = {
 		.gpiomask       = 0,
 		.muxsel         = MUXSEL(2, 3),
 		.gpiomux        = { 0 },
-		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
@@ -3649,7 +3573,7 @@ void __devinit bttv_init_tuner(struct bttv *btv)
 		struct tuner_setup tun_setup;
 
 		/* Load tuner module before issuing tuner config call! */
-		if (bttv_tvcards[btv->c.type].has_radio)
+		if (btv->has_radio)
 			v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
 				&btv->c.i2c_adap, "tuner",
 				0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
@@ -3664,7 +3588,7 @@ void __devinit bttv_init_tuner(struct bttv *btv)
 		tun_setup.type = btv->tuner_type;
 		tun_setup.addr = addr;
 
-		if (bttv_tvcards[btv->c.type].has_radio)
+		if (btv->has_radio)
 			tun_setup.mode_mask |= T_RADIO;
 
 		bttv_call_all(btv, tuner, s_type_addr, &tun_setup);
@@ -3724,6 +3648,10 @@ static void __devinit hauppauge_eeprom(struct bttv *btv)
 			bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name);
 		btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB;
 	}
+
+	/* The 61334 needs the msp3410 to do the radio demod to get sound */
+	if (tv.model == 61334)
+		btv->radio_uses_msp_demodulator = 1;
 }
 
 static int terratec_active_radio_upgrade(struct bttv *btv)
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index a9cfb0f..b58ff87 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -558,12 +558,6 @@ static const struct bttv_format formats[] = {
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
-		.name     = "4:2:2, packed, YUYV",
-		.fourcc   = V4L2_PIX_FMT_YUYV,
-		.btformat = BT848_COLOR_FMT_YUY2,
-		.depth    = 16,
-		.flags    = FORMAT_FLAGS_PACKED,
-	},{
 		.name     = "4:2:2, packed, UYVY",
 		.fourcc   = V4L2_PIX_FMT_UYVY,
 		.btformat = BT848_COLOR_FMT_YUY2,
@@ -1218,6 +1212,11 @@ audio_mux(struct bttv *btv, int input, int mute)
 		   For now this is sufficient. */
 		switch (input) {
 		case TVAUDIO_INPUT_RADIO:
+			/* Some boards need the msp do to the radio demod */
+			if (btv->radio_uses_msp_demodulator) {
+				in = MSP_INPUT_DEFAULT;
+				break;
+			}
 			in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
 				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
 			break;
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index c517161..acfe2f3 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -236,7 +236,6 @@ struct tvcard {
 	/* i2c audio flags */
 	unsigned int no_msp34xx:1;
 	unsigned int no_tda7432:1;
-	unsigned int needs_tvaudio:1;
 	unsigned int msp34xx_alt:1;
 	/* Note: currently no card definition needs to mark the presence
 	   of a RDS saa6588 chip. If this is ever needed, then add a new
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index db943a8d..70fd4f2 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -440,6 +440,7 @@ struct bttv {
 	/* radio data/state */
 	int has_radio;
 	int radio_user;
+	int radio_uses_msp_demodulator;
 
 	/* miro/pinnacle + Aimslab VHX
 	   philips matchbox (tea5757 radio tuner) support */
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 2520219..5b75a64 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -607,8 +607,9 @@ static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
 				}
 				o = i * pixels_per_line + pixels_read + k;
 				if (o < len) {
+					u8 ch = invert - buffer[k];
 					got++;
-					put_user((invert - buffer[k]) << shift, buf + o);
+					put_user(ch << shift, buf + o);
 				}
 			}
 			pixels_read += bytes;
@@ -648,8 +649,8 @@ static int qcam_querycap(struct file *file, void  *priv,
 	struct qcam *qcam = video_drvdata(file);
 
 	strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
-	strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card));
-	strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
+	strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card));
+	strlcpy(vcap->bus_info, qcam->pport->name, sizeof(vcap->bus_info));
 	vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
 	vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
@@ -688,8 +689,8 @@ static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
 	pix->height = qcam->height / qcam->transfer_scale;
 	pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6;
 	pix->field = V4L2_FIELD_NONE;
-	pix->bytesperline = qcam->width;
-	pix->sizeimage = qcam->width * qcam->height;
+	pix->bytesperline = pix->width;
+	pix->sizeimage = pix->width * pix->height;
 	/* Just a guess */
 	pix->colorspace = V4L2_COLORSPACE_SRGB;
 	return 0;
@@ -757,7 +758,7 @@ static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdes
 		  "4-Bit Monochrome", V4L2_PIX_FMT_Y4,
 		  { 0, 0, 0, 0 }
 		},
-		{ 0, 0, 0,
+		{ 1, 0, 0,
 		  "6-Bit Monochrome", V4L2_PIX_FMT_Y6,
 		  { 0, 0, 0, 0 }
 		},
@@ -772,6 +773,25 @@ static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdes
 	return 0;
 }
 
+static int qcam_enum_framesizes(struct file *file, void *fh,
+					 struct v4l2_frmsizeenum *fsize)
+{
+	static const struct v4l2_frmsize_discrete sizes[] = {
+		{  80,  60 },
+		{ 160, 120 },
+		{ 320, 240 },
+	};
+
+	if (fsize->index > 2)
+		return -EINVAL;
+	if (fsize->pixel_format != V4L2_PIX_FMT_Y4 &&
+	    fsize->pixel_format != V4L2_PIX_FMT_Y6)
+		return -EINVAL;
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	fsize->discrete = sizes[fsize->index];
+	return 0;
+}
+
 static ssize_t qcam_read(struct file *file, char __user *buf,
 		size_t count, loff_t *ppos)
 {
@@ -795,6 +815,11 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
 	return len;
 }
 
+static unsigned int qcam_poll(struct file *filp, poll_table *wait)
+{
+	return v4l2_ctrl_poll(filp, wait) | POLLIN | POLLRDNORM;
+}
+
 static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct qcam *qcam =
@@ -828,7 +853,7 @@ static const struct v4l2_file_operations qcam_fops = {
 	.owner		= THIS_MODULE,
 	.open		= v4l2_fh_open,
 	.release	= v4l2_fh_release,
-	.poll		= v4l2_ctrl_poll,
+	.poll		= qcam_poll,
 	.unlocked_ioctl = video_ioctl2,
 	.read		= qcam_read,
 };
@@ -839,6 +864,7 @@ static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
 	.vidioc_s_input      		    = qcam_s_input,
 	.vidioc_enum_input   		    = qcam_enum_input,
 	.vidioc_enum_fmt_vid_cap 	    = qcam_enum_fmt_vid_cap,
+	.vidioc_enum_framesizes		    = qcam_enum_framesizes,
 	.vidioc_g_fmt_vid_cap 		    = qcam_g_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap  		    = qcam_s_fmt_vid_cap,
 	.vidioc_try_fmt_vid_cap  	    = qcam_try_fmt_vid_cap,
@@ -864,9 +890,9 @@ static struct qcam *qcam_init(struct parport *port)
 		return NULL;
 
 	v4l2_dev = &qcam->v4l2_dev;
-	strlcpy(v4l2_dev->name, "bw-qcam", sizeof(v4l2_dev->name));
+	snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "bw-qcam%d", num_cams);
 
-	if (v4l2_device_register(NULL, v4l2_dev) < 0) {
+	if (v4l2_device_register(port->dev, v4l2_dev) < 0) {
 		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
 		kfree(qcam);
 		return NULL;
@@ -886,7 +912,7 @@ static struct qcam *qcam_init(struct parport *port)
 		return NULL;
 	}
 	qcam->pport = port;
-	qcam->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
+	qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL,
 			NULL, 0, NULL);
 	if (qcam->pdev == NULL) {
 		v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
@@ -975,6 +1001,7 @@ static int init_bwqcam(struct parport *port)
 		return -ENODEV;
 	}
 	qc_calibrate(qcam);
+	v4l2_ctrl_handler_setup(&qcam->hdl);
 
 	parport_release(qcam->pdev);
 
diff --git a/drivers/media/video/cs8420.h b/drivers/media/video/cs8420.h
deleted file mode 100644
index 621c0c6..0000000
--- a/drivers/media/video/cs8420.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* cs8420.h - cs8420 initializations
-   Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You 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 __CS8420_H__
-#define __CS8420_H__
-
-/* Initialization Sequence */
-
-static __u8 init8420[] = {
-	1, 0x01,	2, 0x02,	3, 0x00,	4, 0x46,
-	5, 0x24,	6, 0x84,	18, 0x18,	19, 0x13,
-};
-
-#define INIT8420LEN	(sizeof(init8420)/2)
-
-static __u8 mode8420pro[] = {	/* professional output mode */
-	32, 0xa1,	33, 0x00,	34, 0x00,	35, 0x00,
-	36, 0x00,	37, 0x00,	38, 0x00,	39, 0x00,
-	40, 0x00,	41, 0x00,	42, 0x00,	43, 0x00,
-	44, 0x00,	45, 0x00,	46, 0x00,	47, 0x00,
-	48, 0x00,	49, 0x00,	50, 0x00,	51, 0x00,
-	52, 0x00,	53, 0x00,	54, 0x00,	55, 0x00,
-};
-#define MODE8420LEN	(sizeof(mode8420pro)/2)
-
-static __u8 mode8420con[] = {	/* consumer output mode */
-	32, 0x20,	33, 0x00,	34, 0x00,	35, 0x48,
-	36, 0x00,	37, 0x00,	38, 0x00,	39, 0x00,
-	40, 0x00,	41, 0x00,	42, 0x00,	43, 0x00,
-	44, 0x00,	45, 0x00,	46, 0x00,	47, 0x00,
-	48, 0x00,	49, 0x00,	50, 0x00,	51, 0x00,
-	52, 0x00,	53, 0x00,	54, 0x00,	55, 0x00,
-};
-
-#endif
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index b55d57c..7e5ffd6 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -838,10 +838,10 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
 	}
 
 	CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
-		   "irq: %d, latency: %d, memory: 0x%lx\n",
+		   "irq: %d, latency: %d, memory: 0x%llx\n",
 		   cx->pci_dev->device, cx->card_rev, pci_dev->bus->number,
 		   PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn),
-		   cx->pci_dev->irq, pci_latency, (unsigned long)cx->base_addr);
+		   cx->pci_dev->irq, pci_latency, (u64)cx->base_addr);
 
 	return 0;
 }
@@ -938,7 +938,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
 	if (retval)
 		goto err;
 
-	CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
+	CX18_DEBUG_INFO("base addr: 0x%llx\n", (u64)cx->base_addr);
 
 	/* PCI Device Setup */
 	retval = cx18_setup_pci(cx, pci_dev, pci_id);
@@ -946,8 +946,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
 		goto free_workqueues;
 
 	/* map io memory */
-	CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
-		   cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
+	CX18_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
+		   (u64)cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
 	cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET,
 				       CX18_MEM_SIZE);
 	if (!cx->enc_mem) {
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index 7a37e0e..2767c64 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -622,7 +622,7 @@ struct cx18 {
 				   unique ID. Starts at 1, so 0 can be used as
 				   uninitialized value in the stream->id. */
 
-	u32 base_addr;
+	resource_size_t base_addr;
 
 	u8 card_rev;
 	void __iomem *enc_mem, *reg_mem;
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
index 1b3fb50..b85c292 100644
--- a/drivers/media/video/cx18/cx18-firmware.c
+++ b/drivers/media/video/cx18/cx18-firmware.c
@@ -164,8 +164,13 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
 
 	apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
 	while (offset + sizeof(seghdr) < fw->size) {
-		/* TODO: byteswapping */
-		memcpy(&seghdr, src + offset / 4, sizeof(seghdr));
+		const u32 *shptr = src + offset / 4;
+
+		seghdr.sync1 = le32_to_cpu(shptr[0]);
+		seghdr.sync2 = le32_to_cpu(shptr[1]);
+		seghdr.addr = le32_to_cpu(shptr[2]);
+		seghdr.size = le32_to_cpu(shptr[3]);
+
 		offset += sizeof(seghdr);
 		if (seghdr.sync1 != APU_ROM_SYNC1 ||
 		    seghdr.sync2 != APU_ROM_SYNC2) {
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index ed81183..eabf00c 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -434,6 +434,7 @@ static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
 	u32 handle, mdl_ack_offset, mdl_ack_count;
 	struct cx18_mailbox *mb;
+	int i;
 
 	mb = &order->mb;
 	handle = mb->args[0];
@@ -447,8 +448,9 @@ static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 		return -1;
 	}
 
-	cx18_memcpy_fromio(cx, order->mdl_ack, cx->enc_mem + mdl_ack_offset,
-			   sizeof(struct cx18_mdl_ack) * mdl_ack_count);
+	for (i = 0; i < sizeof(struct cx18_mdl_ack) * mdl_ack_count; i += sizeof(u32))
+		((u32 *)order->mdl_ack)[i / sizeof(u32)] =
+			cx18_readl(cx, cx->enc_mem + mdl_ack_offset + i);
 
 	if ((order->flags & CX18_F_EWO_MB_STALE) == 0)
 		mb_ack_irq(cx, order);
@@ -538,6 +540,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
 	struct cx18_mailbox *order_mb;
 	struct cx18_in_work_order *order;
 	int submit;
+	int i;
 
 	switch (rpu) {
 	case CPU:
@@ -562,10 +565,12 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
 	order_mb = &order->mb;
 
 	/* mb->cmd and mb->args[0] through mb->args[2] */
-	cx18_memcpy_fromio(cx, &order_mb->cmd, &mb->cmd, 4 * sizeof(u32));
+	for (i = 0; i < 4; i++)
+		(&order_mb->cmd)[i] = cx18_readl(cx, &mb->cmd + i);
+
 	/* mb->request and mb->ack.  N.B. we want to read mb->ack last */
-	cx18_memcpy_fromio(cx, &order_mb->request, &mb->request,
-			   2 * sizeof(u32));
+	for (i = 0; i < 2; i++)
+		(&order_mb->request)[i] = cx18_readl(cx, &mb->request + i);
 
 	if (order_mb->request == order_mb->ack) {
 		CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our "
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c
index 8ed460d..02d4d36 100644
--- a/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -1023,7 +1023,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
 	int nr = 0, ifnum;
 	int i, isoc_pipe = 0;
 	char *speed;
-	char descr[255] = "";
 	struct usb_interface_assoc_descriptor *assoc_desc;
 
 	udev = usb_get_dev(interface_to_usbdev(interface));
@@ -1098,20 +1097,10 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
 		speed = "unknown";
 	}
 
-	if (udev->manufacturer)
-		strlcpy(descr, udev->manufacturer, sizeof(descr));
-
-	if (udev->product) {
-		if (*descr)
-			strlcat(descr, " ", sizeof(descr));
-		strlcat(descr, udev->product, sizeof(descr));
-	}
-	if (*descr)
-		strlcat(descr, " ", sizeof(descr));
-
-	cx231xx_info("New device %s@ %s Mbps "
+	cx231xx_info("New device %s %s @ %s Mbps "
 	     "(%04x:%04x) with %d interfaces\n",
-	     descr,
+	     udev->manufacturer ? udev->manufacturer : "",
+	     udev->product ? udev->product : "",
 	     speed,
 	     le16_to_cpu(udev->descriptor.idVendor),
 	     le16_to_cpu(udev->descriptor.idProduct),
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index e46446a..ed7b2aa 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -471,7 +471,7 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
 	dprintk(1,"Loading firmware ...\n");
 	dataptr = (u32*)firmware->data;
 	for (i = 0; i < (firmware->size >> 2); i++) {
-		value = *dataptr;
+		value = le32_to_cpu(*dataptr);
 		checksum += ~value;
 		memory_write(dev->core, i, value);
 		dataptr++;
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index d7e2a3d..07dc594 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -42,6 +42,7 @@
 #include <sound/initval.h>
 #include <sound/control.h>
 #include <sound/tlv.h>
+#include <sound/ac97_codec.h>
 #include <media/v4l2-common.h>
 #include "em28xx.h"
 
@@ -679,19 +680,19 @@ static int em28xx_audio_init(struct em28xx *dev)
 	INIT_WORK(&dev->wq_trigger, audio_trigger);
 
 	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
-		em28xx_cvol_new(card, dev, "Video", AC97_VIDEO_VOL);
-		em28xx_cvol_new(card, dev, "Line In", AC97_LINEIN_VOL);
-		em28xx_cvol_new(card, dev, "Phone", AC97_PHONE_VOL);
-		em28xx_cvol_new(card, dev, "Microphone", AC97_PHONE_VOL);
-		em28xx_cvol_new(card, dev, "CD", AC97_CD_VOL);
-		em28xx_cvol_new(card, dev, "AUX", AC97_AUX_VOL);
-		em28xx_cvol_new(card, dev, "PCM", AC97_PCM_OUT_VOL);
-
-		em28xx_cvol_new(card, dev, "Master", AC97_MASTER_VOL);
-		em28xx_cvol_new(card, dev, "Line", AC97_LINE_LEVEL_VOL);
-		em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO_VOL);
-		em28xx_cvol_new(card, dev, "LFE", AC97_LFE_MASTER_VOL);
-		em28xx_cvol_new(card, dev, "Surround", AC97_SURR_MASTER_VOL);
+		em28xx_cvol_new(card, dev, "Video", AC97_VIDEO);
+		em28xx_cvol_new(card, dev, "Line In", AC97_LINE);
+		em28xx_cvol_new(card, dev, "Phone", AC97_PHONE);
+		em28xx_cvol_new(card, dev, "Microphone", AC97_MIC);
+		em28xx_cvol_new(card, dev, "CD", AC97_CD);
+		em28xx_cvol_new(card, dev, "AUX", AC97_AUX);
+		em28xx_cvol_new(card, dev, "PCM", AC97_PCM);
+
+		em28xx_cvol_new(card, dev, "Master", AC97_MASTER);
+		em28xx_cvol_new(card, dev, "Line", AC97_HEADPHONE);
+		em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO);
+		em28xx_cvol_new(card, dev, "LFE", AC97_CENTER_LFE_MASTER);
+		em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
 	}
 
 	err = snd_card_register(card);
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 20a7e24..054ac24 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -974,12 +974,14 @@ struct em28xx_board em28xx_boards[] = {
 	[EM2884_BOARD_CINERGY_HTC_STICK] = {
 		.name         = "Terratec Cinergy HTC Stick",
 		.has_dvb      = 1,
+		.ir_codes     = RC_MAP_NEC_TERRATEC_CINERGY_XS,
 #if 0
 		.tuner_type   = TUNER_PHILIPS_TDA8290,
 		.tuner_addr   = 0x41,
 		.dvb_gpio     = terratec_h5_digital, /* FIXME: probably wrong */
 		.tuner_gpio   = terratec_h5_gpio,
 #endif
+		.tuner_type   = TUNER_ABSENT,
 		.i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
 				EM28XX_I2C_CLK_WAIT_ENABLE |
 				EM28XX_I2C_FREQ_400_KHZ,
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 5717bde..de2cb20 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
+#include <sound/ac97_codec.h>
 #include <media/v4l2-common.h>
 
 #include "em28xx.h"
@@ -326,13 +327,13 @@ struct em28xx_vol_itable {
 };
 
 static struct em28xx_vol_itable inputs[] = {
-	{ EM28XX_AMUX_VIDEO, 	AC97_VIDEO_VOL   },
-	{ EM28XX_AMUX_LINE_IN,	AC97_LINEIN_VOL  },
-	{ EM28XX_AMUX_PHONE,	AC97_PHONE_VOL   },
-	{ EM28XX_AMUX_MIC,	AC97_MIC_VOL     },
-	{ EM28XX_AMUX_CD,	AC97_CD_VOL      },
-	{ EM28XX_AMUX_AUX,	AC97_AUX_VOL     },
-	{ EM28XX_AMUX_PCM_OUT,	AC97_PCM_OUT_VOL },
+	{ EM28XX_AMUX_VIDEO,	AC97_VIDEO	},
+	{ EM28XX_AMUX_LINE_IN,	AC97_LINE	},
+	{ EM28XX_AMUX_PHONE,	AC97_PHONE	},
+	{ EM28XX_AMUX_MIC,	AC97_MIC	},
+	{ EM28XX_AMUX_CD,	AC97_CD		},
+	{ EM28XX_AMUX_AUX,	AC97_AUX	},
+	{ EM28XX_AMUX_PCM_OUT,	AC97_PCM	},
 };
 
 static int set_ac97_input(struct em28xx *dev)
@@ -415,11 +416,11 @@ struct em28xx_vol_otable {
 };
 
 static const struct em28xx_vol_otable outputs[] = {
-	{ EM28XX_AOUT_MASTER, AC97_MASTER_VOL      },
-	{ EM28XX_AOUT_LINE,   AC97_LINE_LEVEL_VOL  },
-	{ EM28XX_AOUT_MONO,   AC97_MASTER_MONO_VOL },
-	{ EM28XX_AOUT_LFE,    AC97_LFE_MASTER_VOL  },
-	{ EM28XX_AOUT_SURR,   AC97_SURR_MASTER_VOL },
+	{ EM28XX_AOUT_MASTER, AC97_MASTER		},
+	{ EM28XX_AOUT_LINE,   AC97_HEADPHONE		},
+	{ EM28XX_AOUT_MONO,   AC97_MASTER_MONO		},
+	{ EM28XX_AOUT_LFE,    AC97_CENTER_LFE_MASTER	},
+	{ EM28XX_AOUT_SURR,   AC97_SURROUND_MASTER	},
 };
 
 int em28xx_audio_analog_set(struct em28xx *dev)
@@ -459,9 +460,9 @@ int em28xx_audio_analog_set(struct em28xx *dev)
 	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
 		int vol;
 
-		em28xx_write_ac97(dev, AC97_POWER_DOWN_CTRL, 0x4200);
-		em28xx_write_ac97(dev, AC97_EXT_AUD_CTRL, 0x0031);
-		em28xx_write_ac97(dev, AC97_PCM_IN_SRATE, 0xbb80);
+		em28xx_write_ac97(dev, AC97_POWERDOWN, 0x4200);
+		em28xx_write_ac97(dev, AC97_EXTENDED_STATUS, 0x0031);
+		em28xx_write_ac97(dev, AC97_PCM_LR_ADC_RATE, 0xbb80);
 
 		/* LSB: left channel - both channels with the same level */
 		vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8);
@@ -487,7 +488,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
 			   channels */
 			sel |= (sel << 8);
 
-			em28xx_write_ac97(dev, AC97_RECORD_SELECT, sel);
+			em28xx_write_ac97(dev, AC97_REC_SEL, sel);
 		}
 	}
 
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 16410ac..f8ffe10 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -310,14 +310,14 @@ static struct drxd_config em28xx_drxd = {
 	.disable_i2c_gate_ctrl = 1,
 };
 
-struct drxk_config terratec_h5_drxk = {
+static struct drxk_config terratec_h5_drxk = {
 	.adr = 0x29,
 	.single_master = 1,
 	.no_i2c_bridge = 1,
 	.microcode_name = "dvb-usb-terratec-h5-drxk.fw",
 };
 
-struct drxk_config hauppauge_930c_drxk = {
+static struct drxk_config hauppauge_930c_drxk = {
 	.adr = 0x29,
 	.single_master = 1,
 	.no_i2c_bridge = 1,
@@ -325,13 +325,25 @@ struct drxk_config hauppauge_930c_drxk = {
 	.chunk_size = 56,
 };
 
-struct drxk_config maxmedia_ub425_tc_drxk = {
+struct drxk_config terratec_htc_stick_drxk = {
 	.adr = 0x29,
 	.single_master = 1,
 	.no_i2c_bridge = 1,
+	.microcode_name = "dvb-usb-terratec-htc-stick-drxk.fw",
+	.chunk_size = 54,
+	/* Required for the antenna_gpio to disable LNA. */
+	.antenna_dvbt = true,
+	/* The windows driver uses the same. This will disable LNA. */
+	.antenna_gpio = 0x6,
 };
 
-struct drxk_config pctv_520e_drxk = {
+static struct drxk_config maxmedia_ub425_tc_drxk = {
+	.adr = 0x29,
+	.single_master = 1,
+	.no_i2c_bridge = 1,
+};
+
+static struct drxk_config pctv_520e_drxk = {
 	.adr = 0x29,
 	.single_master = 1,
 	.microcode_name = "dvb-demod-drxk-pctv.fw",
@@ -473,6 +485,57 @@ static void terratec_h5_init(struct em28xx *dev)
 	em28xx_gpio_set(dev, terratec_h5_end);
 };
 
+static void terratec_htc_stick_init(struct em28xx *dev)
+{
+	int i;
+
+	/*
+	 * GPIO configuration:
+	 * 0xff: unknown (does not affect DVB-T).
+	 * 0xf6: DRX-K (demodulator).
+	 * 0xe6: unknown (does not affect DVB-T).
+	 * 0xb6: unknown (does not affect DVB-T).
+	 */
+	struct em28xx_reg_seq terratec_htc_stick_init[] = {
+		{EM28XX_R08_GPIO,	0xff,	0xff,	10},
+		{EM2874_R80_GPIO,	0xf6,	0xff,	100},
+		{EM2874_R80_GPIO,	0xe6,	0xff,	50},
+		{EM2874_R80_GPIO,	0xf6,	0xff,	100},
+		{ -1,                   -1,     -1,     -1},
+	};
+	struct em28xx_reg_seq terratec_htc_stick_end[] = {
+		{EM2874_R80_GPIO,	0xb6,	0xff,	100},
+		{EM2874_R80_GPIO,	0xf6,	0xff,	50},
+		{ -1,                   -1,     -1,     -1},
+	};
+
+	/* Init the analog decoder? */
+	struct {
+		unsigned char r[4];
+		int len;
+	} regs[] = {
+		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
+		{{ 0x01, 0x02 }, 2},
+		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+		{{ 0x01, 0x00 }, 2},
+		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
+	};
+
+	em28xx_gpio_set(dev, terratec_htc_stick_init);
+
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+	msleep(10);
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
+	msleep(10);
+
+	dev->i2c_client.addr = 0x82 >> 1;
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++)
+		i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+
+	em28xx_gpio_set(dev, terratec_htc_stick_end);
+};
+
 static void pctv_520e_init(struct em28xx *dev)
 {
 	/*
@@ -944,7 +1007,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
 		break;
 	}
 	case EM2884_BOARD_TERRATEC_H5:
-	case EM2884_BOARD_CINERGY_HTC_STICK:
 		terratec_h5_init(dev);
 
 		dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap);
@@ -1021,6 +1083,25 @@ static int em28xx_dvb_init(struct em28xx *dev)
 			}
 		}
 		break;
+	case EM2884_BOARD_CINERGY_HTC_STICK:
+		terratec_htc_stick_init(dev);
+
+		/* attach demodulator */
+		dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
+					&dev->i2c_adap);
+		if (!dvb->fe[0]) {
+			result = -EINVAL;
+			goto out_free;
+		}
+
+		/* Attach the demodulator. */
+		if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+				&dev->i2c_adap,
+				&em28xx_cxd2820r_tda18271_config)) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
 	default:
 		em28xx_errdev("/2: The frontend of your DVB/ATSC card"
 				" isn't supported yet\n");
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 185db65..1683bd9 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -475,6 +475,7 @@ static struct i2c_client em28xx_client_template = {
  */
 static char *i2c_devs[128] = {
 	[0x4a >> 1] = "saa7113h",
+	[0x52 >> 1] = "drxk",
 	[0x60 >> 1] = "remote IR sensor",
 	[0x8e >> 1] = "remote IR sensor",
 	[0x86 >> 1] = "tda9887",
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index fce5f76..97d36b4 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -345,7 +345,7 @@ static void em28xx_ir_stop(struct rc_dev *rc)
 	cancel_delayed_work_sync(&ir->work);
 }
 
-int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
+static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
 {
 	int rc = 0;
 	struct em28xx_IR *ir = rc_dev->priv;
@@ -527,6 +527,8 @@ static int em28xx_ir_init(struct em28xx *dev)
 
 	if (dev->board.ir_codes == NULL) {
 		/* No remote control support */
+		em28xx_warn("Remote control support is not available for "
+				"this card.\n");
 		return 0;
 	}
 
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
index 2f62685..6ff3682 100644
--- a/drivers/media/video/em28xx/em28xx-reg.h
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -211,58 +211,9 @@ enum em28xx_chip_id {
 };
 
 /*
- * Registers used by em202 and other AC97 chips
+ * Registers used by em202
  */
 
-/* Standard AC97 registers */
-#define AC97_RESET               0x00
-
-	/* Output volumes */
-#define AC97_MASTER_VOL          0x02
-#define AC97_LINE_LEVEL_VOL      0x04	/* Some devices use for headphones */
-#define AC97_MASTER_MONO_VOL     0x06
-
-	/* Input volumes */
-#define AC97_PC_BEEP_VOL         0x0a
-#define AC97_PHONE_VOL           0x0c
-#define AC97_MIC_VOL             0x0e
-#define AC97_LINEIN_VOL          0x10
-#define AC97_CD_VOL              0x12
-#define AC97_VIDEO_VOL           0x14
-#define AC97_AUX_VOL             0x16
-#define AC97_PCM_OUT_VOL         0x18
-
-	/* capture registers */
-#define AC97_RECORD_SELECT       0x1a
-#define AC97_RECORD_GAIN         0x1c
-
-	/* control registers */
-#define AC97_GENERAL_PURPOSE     0x20
-#define AC97_3D_CTRL             0x22
-#define AC97_AUD_INT_AND_PAG     0x24
-#define AC97_POWER_DOWN_CTRL     0x26
-#define AC97_EXT_AUD_ID          0x28
-#define AC97_EXT_AUD_CTRL        0x2a
-
-/* Supported rate varies for each AC97 device
-   if write an unsupported value, it will return the closest one
- */
-#define AC97_PCM_OUT_FRONT_SRATE 0x2c
-#define AC97_PCM_OUT_SURR_SRATE  0x2e
-#define AC97_PCM_OUT_LFE_SRATE   0x30
-#define AC97_PCM_IN_SRATE        0x32
-
-	/* For devices with more than 2 channels, extra output volumes */
-#define AC97_LFE_MASTER_VOL      0x36
-#define AC97_SURR_MASTER_VOL     0x38
-
-	/* Digital SPDIF output control */
-#define AC97_SPDIF_OUT_CTRL      0x3a
-
-	/* Vendor ID identifier */
-#define AC97_VENDOR_ID1          0x7c
-#define AC97_VENDOR_ID2          0x7e
-
 /* EMP202 vendor registers */
 #define EM202_EXT_MODEM_CTRL     0x3e
 #define EM202_GPIO_CONF          0x4c
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 137166d..31721ea 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -1653,7 +1653,7 @@ static int vidioc_streamoff(struct file *file, void *priv,
 				enum v4l2_buf_type buf_type)
 {
 	struct gspca_dev *gspca_dev = video_drvdata(file);
-	int ret;
+	int i, ret;
 
 	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
@@ -1678,6 +1678,8 @@ static int vidioc_streamoff(struct file *file, void *priv,
 	wake_up_interruptible(&gspca_dev->wq);
 
 	/* empty the transfer queues */
+	for (i = 0; i < gspca_dev->nframes; i++)
+		gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS;
 	atomic_set(&gspca_dev->fr_q, 0);
 	atomic_set(&gspca_dev->fr_i, 0);
 	gspca_dev->fr_o = 0;
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index b5acb1e..80c81dd 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -96,7 +96,7 @@ static void setbrightness(struct gspca_dev *gspca_dev);
 static void setcontrast(struct gspca_dev *gspca_dev);
 static void setgain(struct gspca_dev *gspca_dev);
 static void setexposure(struct gspca_dev *gspca_dev);
-static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val);
+static void setagc(struct gspca_dev *gspca_dev);
 static void setawb(struct gspca_dev *gspca_dev);
 static void setaec(struct gspca_dev *gspca_dev);
 static void setsharpness(struct gspca_dev *gspca_dev);
@@ -189,7 +189,7 @@ static const struct ctrl sd_ctrls[] = {
 			.step    = 1,
 			.default_value = 1,
 		},
-		.set = sd_setagc
+		.set_control = setagc
 	},
 [AWB] = {
 		{
@@ -851,6 +851,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev)
 	int i;
 
 	for (i = 0; i < 5; i++) {
+		msleep(10);
 		data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);
 
 		switch (data) {
@@ -1242,10 +1243,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
 	cam->ctrls = sd->ctrls;
 
-	/* the auto white balance control works only when auto gain is set */
-	if (sd_ctrls[AGC].qctrl.default_value == 0)
-		gspca_dev->ctrl_inac |= (1 << AWB);
-
 	cam->cam_mode = ov772x_mode;
 	cam->nmodes = ARRAY_SIZE(ov772x_mode);
 
@@ -1486,29 +1483,6 @@ scan_next:
 	} while (remaining_len > 0);
 }
 
-static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->ctrls[AGC].val = val;
-
-	/* the auto white balance control works only
-	 * when auto gain is set */
-	if (val) {
-		gspca_dev->ctrl_inac &= ~(1 << AWB);
-	} else {
-		gspca_dev->ctrl_inac |= (1 << AWB);
-		if (sd->ctrls[AWB].val) {
-			sd->ctrls[AWB].val = 0;
-			if (gspca_dev->streaming)
-				setawb(gspca_dev);
-		}
-	}
-	if (gspca_dev->streaming)
-		setagc(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
 static int sd_querymenu(struct gspca_dev *gspca_dev,
 		struct v4l2_querymenu *menu)
 {
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c
index b579730..1fd41f0 100644
--- a/drivers/media/video/gspca/ov534_9.c
+++ b/drivers/media/video/gspca/ov534_9.c
@@ -1008,6 +1008,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev)
 	int i;
 
 	for (i = 0; i < 5; i++) {
+		msleep(10);
 		data = reg_r(gspca_dev, OV534_REG_STATUS);
 
 		switch (data) {
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 2cb7d95..115da16 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -418,7 +418,7 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
 
 	gspca_dev->vdev.ctrl_handler = hdl;
-	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_handler_init(hdl, 5);
 
 	sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 					V4L2_CID_CONTRAST, 0, 15, 1, 7);
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index ad09820..6c31e46 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -1761,7 +1761,6 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
 			V4L2_CID_SATURATION, 0, 255, 1, 127);
 	sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 			V4L2_CID_HUE, -180, 180, 1, 0);
-	v4l2_ctrl_cluster(4, &sd->brightness);
 
 	sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 			V4L2_CID_GAMMA, 0, 255, 1, 0x10);
@@ -1770,7 +1769,6 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
 			V4L2_CID_BLUE_BALANCE, 0, 127, 1, 0x28);
 	sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 			V4L2_CID_RED_BALANCE, 0, 127, 1, 0x28);
-	v4l2_ctrl_cluster(2, &sd->blue);
 
 	if (sd->sensor != SENSOR_OV9655 && sd->sensor != SENSOR_SOI968 &&
 	    sd->sensor != SENSOR_OV7670 && sd->sensor != SENSOR_MT9M001 &&
@@ -1779,7 +1777,6 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
 			V4L2_CID_HFLIP, 0, 1, 1, 0);
 		sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 			V4L2_CID_VFLIP, 0, 1, 1, 0);
-		v4l2_ctrl_cluster(2, &sd->hflip);
 	}
 
 	if (sd->sensor != SENSOR_SOI968 && sd->sensor != SENSOR_MT9VPRB &&
@@ -1794,6 +1791,20 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
 			V4L2_CID_GAIN, 0, 28, 1, 0);
 		sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	}
+
+	sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_JPEG_COMPRESSION_QUALITY, 50, 90, 1, 80);
+	if (hdl->error) {
+		pr_err("Could not initialize controls\n");
+		return hdl->error;
+	}
+
+	v4l2_ctrl_cluster(4, &sd->brightness);
+	v4l2_ctrl_cluster(2, &sd->blue);
+	if (sd->hflip)
+		v4l2_ctrl_cluster(2, &sd->hflip);
+	if (sd->autogain) {
 		if (sd->sensor == SENSOR_SOI968)
 			/* this sensor doesn't have the exposure control and
 			   autogain is clustered with gain instead. This works
@@ -1803,13 +1814,6 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
 			/* Otherwise autogain is clustered with exposure. */
 			v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
 	}
-
-	sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
-			V4L2_CID_JPEG_COMPRESSION_QUALITY, 50, 90, 1, 80);
-	if (hdl->error) {
-		pr_err("Could not initialize controls\n");
-		return hdl->error;
-	}
 	return 0;
 }
 
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 4d1696d..f38faa9 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -3120,7 +3120,7 @@ static const struct sd_desc sd_desc = {
 			| (SENSOR_ ## sensor << 8) \
 			| (flags)
 static const struct usb_device_id device_table[] = {
-	{USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)},
+	{USB_DEVICE(0x0458, 0x7025), BSF(SN9C120, MI0360B, F_PDN_INV)},
 	{USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)},
 	{USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, F_PDN_INV)},
 	{USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, F_PDN_INV)},
diff --git a/drivers/media/video/ibmmpeg2.h b/drivers/media/video/ibmmpeg2.h
deleted file mode 100644
index 68e1038..0000000
--- a/drivers/media/video/ibmmpeg2.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* ibmmpeg2.h - IBM MPEGCD21 definitions */
-
-#ifndef __IBM_MPEG2__
-#define __IBM_MPEG2__
-
-/* Define all MPEG Decoder registers */
-/* Chip Control and Status */
-#define IBM_MP2_CHIP_CONTROL	0x200*2
-#define IBM_MP2_CHIP_MODE	0x201*2
-/* Timer Control and Status */
-#define IBM_MP2_SYNC_STC2	0x202*2
-#define IBM_MP2_SYNC_STC1	0x203*2
-#define IBM_MP2_SYNC_STC0	0x204*2
-#define IBM_MP2_SYNC_PTS2	0x205*2
-#define IBM_MP2_SYNC_PTS1	0x206*2
-#define IBM_MP2_SYNC_PTS0	0x207*2
-/* Video FIFO Control */
-#define IBM_MP2_FIFO		0x208*2
-#define IBM_MP2_FIFOW		0x100*2
-#define IBM_MP2_FIFO_STAT	0x209*2
-#define IBM_MP2_RB_THRESHOLD	0x22b*2
-/* Command buffer */
-#define IBM_MP2_COMMAND		0x20a*2
-#define IBM_MP2_CMD_DATA	0x20b*2
-#define IBM_MP2_CMD_STAT	0x20c*2
-#define IBM_MP2_CMD_ADDR	0x20d*2
-/* Internal Processor Control and Status */
-#define IBM_MP2_PROC_IADDR	0x20e*2
-#define IBM_MP2_PROC_IDATA	0x20f*2
-#define IBM_MP2_WR_PROT		0x235*2
-/* DRAM Access */
-#define IBM_MP2_DRAM_ADDR	0x210*2
-#define IBM_MP2_DRAM_DATA	0x212*2
-#define IBM_MP2_DRAM_CMD_STAT	0x213*2
-#define IBM_MP2_BLOCK_SIZE	0x23b*2
-#define IBM_MP2_SRC_ADDR	0x23c*2
-/* Onscreen Display */
-#define IBM_MP2_OSD_ADDR	0x214*2
-#define IBM_MP2_OSD_DATA	0x215*2
-#define IBM_MP2_OSD_MODE	0x217*2
-#define IBM_MP2_OSD_LINK_ADDR	0x229*2
-#define IBM_MP2_OSD_SIZE	0x22a*2
-/* Interrupt Control */
-#define IBM_MP2_HOST_INT	0x218*2
-#define IBM_MP2_MASK0		0x219*2
-#define IBM_MP2_HOST_INT1	0x23e*2
-#define IBM_MP2_MASK1		0x23f*2
-/* Audio Control */
-#define IBM_MP2_AUD_IADDR	0x21a*2
-#define IBM_MP2_AUD_IDATA	0x21b*2
-#define IBM_MP2_AUD_FIFO	0x21c*2
-#define IBM_MP2_AUD_FIFOW	0x101*2
-#define IBM_MP2_AUD_CTL		0x21d*2
-#define IBM_MP2_BEEP_CTL	0x21e*2
-#define IBM_MP2_FRNT_ATTEN	0x22d*2
-/* Display Control */
-#define IBM_MP2_DISP_MODE	0x220*2
-#define IBM_MP2_DISP_DLY	0x221*2
-#define IBM_MP2_VBI_CTL		0x222*2
-#define IBM_MP2_DISP_LBOR	0x223*2
-#define IBM_MP2_DISP_TBOR	0x224*2
-/* Polarity Control */
-#define IBM_MP2_INFC_CTL	0x22c*2
-
-/* control commands */
-#define IBM_MP2_PLAY		0
-#define IBM_MP2_PAUSE		1
-#define IBM_MP2_SINGLE_FRAME	2
-#define IBM_MP2_FAST_FORWARD	3
-#define IBM_MP2_SLOW_MOTION	4
-#define IBM_MP2_IMED_NORM_PLAY	5
-#define IBM_MP2_RESET_WINDOW	6
-#define IBM_MP2_FREEZE_FRAME	7
-#define IBM_MP2_RESET_VID_RATE	8
-#define IBM_MP2_CONFIG_DECODER	9
-#define IBM_MP2_CHANNEL_SWITCH	10
-#define IBM_MP2_RESET_AUD_RATE	11
-#define IBM_MP2_PRE_OP_CHN_SW	12
-#define IBM_MP2_SET_STILL_MODE	14
-
-/* Define Xilinx FPGA Internal Registers */
-
-/* general control register 0 */
-#define XILINX_CTL0		0x600
-/* genlock delay resister 1 */
-#define XILINX_GLDELAY		0x602
-/* send 16 bits to CS3310 port */
-#define XILINX_CS3310		0x604
-/* send 16 bits to CS3310 and complete */
-#define XILINX_CS3310_CMPLT	0x60c
-/* pulse width modulator control */
-#define XILINX_PWM		0x606
-
-#endif
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 057929e..5462ce2 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -866,10 +866,10 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
 	pci_write_config_dword(pdev, 0x40, 0xffff);
 
 	IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
-		   "irq: %d, latency: %d, memory: 0x%lx\n",
+		   "irq: %d, latency: %d, memory: 0x%llx\n",
 		   pdev->device, pdev->revision, pdev->bus->number,
 		   PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-		   pdev->irq, pci_latency, (unsigned long)itv->base_addr);
+		   pdev->irq, pci_latency, (u64)itv->base_addr);
 
 	return 0;
 }
@@ -1007,7 +1007,7 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
 	itv->cxhdl.priv = itv;
 	itv->cxhdl.func = ivtv_api_func;
 
-	IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);
+	IVTV_DEBUG_INFO("base addr: 0x%llx\n", (u64)itv->base_addr);
 
 	/* PCI Device Setup */
 	retval = ivtv_setup_pci(itv, pdev, pci_id);
@@ -1017,8 +1017,8 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
 		goto free_mem;
 
 	/* map io memory */
-	IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
-		   itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE);
+	IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
+		   (u64)itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE);
 	itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET,
 				       IVTV_ENCODER_SIZE);
 	if (!itv->enc_mem) {
@@ -1034,8 +1034,8 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
 	}
 
 	if (itv->has_cx23415) {
-		IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
-				itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
+		IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
+				(u64)itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
 		itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET,
 				IVTV_DECODER_SIZE);
 		if (!itv->dec_mem) {
@@ -1056,8 +1056,8 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
 	}
 
 	/* map registers memory */
-	IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
-		   itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+	IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
+		   (u64)itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
 	itv->reg_mem =
 	    ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
 	if (!itv->reg_mem) {
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 2e22002..a7e00f8 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -622,7 +622,7 @@ struct ivtv {
 	struct v4l2_subdev *sd_video;	/* controlling video decoder subdev */
 	struct v4l2_subdev *sd_audio;	/* controlling audio subdev */
 	struct v4l2_subdev *sd_muxer;	/* controlling audio muxer subdev */
-	u32 base_addr;                  /* PCI resource base address */
+	resource_size_t base_addr;      /* PCI resource base address */
 	volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */
 	volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */
 	volatile void __iomem *reg_mem; /* pointer to mapped registers */
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c
index d2dec58..3945556 100644
--- a/drivers/media/video/mem2mem_testdev.c
+++ b/drivers/media/video/mem2mem_testdev.c
@@ -110,22 +110,6 @@ enum {
 	V4L2_M2M_DST = 1,
 };
 
-/* Source and destination queue data */
-static struct m2mtest_q_data q_data[2];
-
-static struct m2mtest_q_data *get_q_data(enum v4l2_buf_type type)
-{
-	switch (type) {
-	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-		return &q_data[V4L2_M2M_SRC];
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		return &q_data[V4L2_M2M_DST];
-	default:
-		BUG();
-	}
-	return NULL;
-}
-
 #define V4L2_CID_TRANS_TIME_MSEC	V4L2_CID_PRIVATE_BASE
 #define V4L2_CID_TRANS_NUM_BUFS		(V4L2_CID_PRIVATE_BASE + 1)
 
@@ -198,8 +182,26 @@ struct m2mtest_ctx {
 	int			aborting;
 
 	struct v4l2_m2m_ctx	*m2m_ctx;
+
+	/* Source and destination queue data */
+	struct m2mtest_q_data   q_data[2];
 };
 
+static struct m2mtest_q_data *get_q_data(struct m2mtest_ctx *ctx,
+					 enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &ctx->q_data[V4L2_M2M_SRC];
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &ctx->q_data[V4L2_M2M_DST];
+	default:
+		BUG();
+	}
+	return NULL;
+}
+
+
 static struct v4l2_queryctrl *get_ctrl(int id)
 {
 	int i;
@@ -223,7 +225,7 @@ static int device_process(struct m2mtest_ctx *ctx,
 	int tile_w, bytes_left;
 	int width, height, bytesperline;
 
-	q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
 
 	width	= q_data->width;
 	height	= q_data->height;
@@ -436,7 +438,7 @@ static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
 	if (!vq)
 		return -EINVAL;
 
-	q_data = get_q_data(f->type);
+	q_data = get_q_data(ctx, f->type);
 
 	f->fmt.pix.width	= q_data->width;
 	f->fmt.pix.height	= q_data->height;
@@ -535,7 +537,7 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
 	if (!vq)
 		return -EINVAL;
 
-	q_data = get_q_data(f->type);
+	q_data = get_q_data(ctx, f->type);
 	if (!q_data)
 		return -EINVAL;
 
@@ -747,7 +749,7 @@ static int m2mtest_queue_setup(struct vb2_queue *vq,
 	struct m2mtest_q_data *q_data;
 	unsigned int size, count = *nbuffers;
 
-	q_data = get_q_data(vq->type);
+	q_data = get_q_data(ctx, vq->type);
 
 	size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
 
@@ -775,7 +777,7 @@ static int m2mtest_buf_prepare(struct vb2_buffer *vb)
 
 	dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
 
-	q_data = get_q_data(vb->vb2_queue->type);
+	q_data = get_q_data(ctx, vb->vb2_queue->type);
 
 	if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
 		dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n",
@@ -860,6 +862,9 @@ static int m2mtest_open(struct file *file)
 	ctx->transtime = MEM2MEM_DEF_TRANSTIME;
 	ctx->num_processed = 0;
 
+	ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
+	ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
+
 	ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
 
 	if (IS_ERR(ctx->m2m_ctx)) {
@@ -986,9 +991,6 @@ static int m2mtest_probe(struct platform_device *pdev)
 		goto err_m2m;
 	}
 
-	q_data[V4L2_M2M_SRC].fmt = &formats[0];
-	q_data[V4L2_M2M_DST].fmt = &formats[0];
-
 	return 0;
 
 	v4l2_m2m_release(dev->m2m_dev);
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 7e64818..00583f5 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -22,7 +22,7 @@
 
 /*
  * mt9m001 i2c address 0x5d
- * The platform has to define ctruct i2c_board_info objects and link to them
+ * The platform has to define struct i2c_board_info objects and link to them
  * from struct soc_camera_link
  */
 
diff --git a/drivers/media/video/mt9m032.c b/drivers/media/video/mt9m032.c
index 3c1e626..445359c 100644
--- a/drivers/media/video/mt9m032.c
+++ b/drivers/media/video/mt9m032.c
@@ -688,11 +688,17 @@ static const struct v4l2_subdev_ops mt9m032_ops = {
 static int mt9m032_probe(struct i2c_client *client,
 			 const struct i2c_device_id *devid)
 {
+	struct mt9m032_platform_data *pdata = client->dev.platform_data;
 	struct i2c_adapter *adapter = client->adapter;
 	struct mt9m032 *sensor;
 	int chip_version;
 	int ret;
 
+	if (pdata == NULL) {
+		dev_err(&client->dev, "No platform data\n");
+		return -EINVAL;
+	}
+
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
 		dev_warn(&client->dev,
 			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
@@ -708,7 +714,7 @@ static int mt9m032_probe(struct i2c_client *client,
 
 	mutex_init(&sensor->lock);
 
-	sensor->pdata = client->dev.platform_data;
+	sensor->pdata = pdata;
 
 	v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops);
 	sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -738,7 +744,7 @@ static int mt9m032_probe(struct i2c_client *client,
 	sensor->format.field = V4L2_FIELD_NONE;
 	sensor->format.colorspace = V4L2_COLORSPACE_SRGB;
 
-	v4l2_ctrl_handler_init(&sensor->ctrls, 4);
+	v4l2_ctrl_handler_init(&sensor->ctrls, 5);
 
 	v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
 			  V4L2_CID_GAIN, 0, 127, 1, 64);
@@ -754,6 +760,9 @@ static int mt9m032_probe(struct i2c_client *client,
 			  V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN,
 			  MT9M032_SHUTTER_WIDTH_MAX, 1,
 			  MT9M032_SHUTTER_WIDTH_DEF);
+	v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
+			  V4L2_CID_PIXEL_RATE, pdata->pix_clock,
+			  pdata->pix_clock, 1, pdata->pix_clock);
 
 	if (sensor->ctrls.error) {
 		ret = sensor->ctrls.error;
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c
index 8f061d9..3be537e 100644
--- a/drivers/media/video/mt9p031.c
+++ b/drivers/media/video/mt9p031.c
@@ -950,7 +950,7 @@ static int mt9p031_probe(struct i2c_client *client,
 	mt9p031->model = did->driver_data;
 	mt9p031->reset = -1;
 
-	v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 4);
+	v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 5);
 
 	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
 			  V4L2_CID_EXPOSURE, MT9P031_SHUTTER_WIDTH_MIN,
@@ -963,6 +963,9 @@ static int mt9p031_probe(struct i2c_client *client,
 			  V4L2_CID_HFLIP, 0, 1, 1, 0);
 	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
 			  V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+			  V4L2_CID_PIXEL_RATE, pdata->target_freq,
+			  pdata->target_freq, 1, pdata->target_freq);
 
 	for (i = 0; i < ARRAY_SIZE(mt9p031_ctrls); ++i)
 		v4l2_ctrl_new_custom(&mt9p031->ctrls, &mt9p031_ctrls[i], NULL);
diff --git a/drivers/media/video/mt9t001.c b/drivers/media/video/mt9t001.c
index 49ca3cb..6d343ad 100644
--- a/drivers/media/video/mt9t001.c
+++ b/drivers/media/video/mt9t001.c
@@ -691,7 +691,7 @@ static int mt9t001_video_probe(struct i2c_client *client)
 		return ret;
 
 	/* Configure the pixel clock polarity */
-	if (pdata && pdata->clk_pol) {
+	if (pdata->clk_pol) {
 		ret  = mt9t001_write(client, MT9T001_PIXEL_CLOCK,
 				     MT9T001_PIXEL_CLOCK_INVERT);
 		if (ret < 0)
@@ -715,10 +715,16 @@ static int mt9t001_video_probe(struct i2c_client *client)
 static int mt9t001_probe(struct i2c_client *client,
 			 const struct i2c_device_id *did)
 {
+	struct mt9t001_platform_data *pdata = client->dev.platform_data;
 	struct mt9t001 *mt9t001;
 	unsigned int i;
 	int ret;
 
+	if (pdata == NULL) {
+		dev_err(&client->dev, "No platform data\n");
+		return -EINVAL;
+	}
+
 	if (!i2c_check_functionality(client->adapter,
 				     I2C_FUNC_SMBUS_WORD_DATA)) {
 		dev_warn(&client->adapter->dev,
@@ -735,7 +741,7 @@ static int mt9t001_probe(struct i2c_client *client,
 		return -ENOMEM;
 
 	v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) +
-						ARRAY_SIZE(mt9t001_gains) + 2);
+						ARRAY_SIZE(mt9t001_gains) + 3);
 
 	v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
 			  V4L2_CID_EXPOSURE, MT9T001_SHUTTER_WIDTH_MIN,
@@ -743,6 +749,9 @@ static int mt9t001_probe(struct i2c_client *client,
 			  MT9T001_SHUTTER_WIDTH_DEF);
 	v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
 			  V4L2_CID_BLACK_LEVEL, 1, 1, 1, 1);
+	v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
+			  V4L2_CID_PIXEL_RATE, pdata->ext_clk, pdata->ext_clk,
+			  1, pdata->ext_clk);
 
 	for (i = 0; i < ARRAY_SIZE(mt9t001_ctrls); ++i)
 		v4l2_ctrl_new_custom(&mt9t001->ctrls, &mt9t001_ctrls[i], NULL);
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index bf63417..7247924 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -23,7 +23,7 @@
 
 /*
  * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
- * The platform has to define ctruct i2c_board_info objects and link to them
+ * The platform has to define struct i2c_board_info objects and link to them
  * from struct soc_camera_link
  */
 
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
index ded26b7..41f9a25 100644
--- a/drivers/media/video/mx2_camera.c
+++ b/drivers/media/video/mx2_camera.c
@@ -345,19 +345,6 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
 					PRP_INTR_CH2OVF,
 		}
 	},
-	{
-		.in_fmt		= V4L2_MBUS_FMT_UYVY8_2X8,
-		.out_fmt	= V4L2_PIX_FMT_YUV420,
-		.cfg		= {
-			.channel	= 2,
-			.in_fmt		= PRP_CNTL_DATA_IN_YUV422,
-			.out_fmt	= PRP_CNTL_CH2_OUT_YUV420,
-			.src_pixel	= 0x22000888, /* YUV422 (YUYV) */
-			.irq_flags	= PRP_INTR_RDERR | PRP_INTR_CH2WERR |
-					PRP_INTR_CH2FC | PRP_INTR_LBOVF |
-					PRP_INTR_CH2OVF,
-		}
-	},
 };
 
 static struct mx2_fmt_cfg *mx27_emma_prp_get_format(
@@ -984,7 +971,6 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct mx2_camera_dev *pcdev = ici->priv;
 	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
-	const struct soc_camera_format_xlate *xlate;
 	unsigned long common_flags;
 	int ret;
 	int bytesperline;
@@ -1029,31 +1015,14 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
 		return ret;
 	}
 
-	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
-	if (!xlate) {
-		dev_warn(icd->parent, "Format %x not found\n", pixfmt);
-		return -EINVAL;
-	}
-
-	if (xlate->code == V4L2_MBUS_FMT_YUYV8_2X8) {
-		csicr1 |= CSICR1_PACK_DIR;
-		csicr1 &= ~CSICR1_SWAP16_EN;
-		dev_dbg(icd->parent, "already yuyv format, don't convert\n");
-	} else if (xlate->code == V4L2_MBUS_FMT_UYVY8_2X8) {
-		csicr1 &= ~CSICR1_PACK_DIR;
-		csicr1 |= CSICR1_SWAP16_EN;
-		dev_dbg(icd->parent, "convert uyvy mbus format into yuyv\n");
-	} else {
-		dev_warn(icd->parent, "mbus format not supported\n");
-		return -EINVAL;
-	}
-
 	if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
 		csicr1 |= CSICR1_REDGE;
 	if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
 		csicr1 |= CSICR1_SOF_POL;
 	if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
 		csicr1 |= CSICR1_HSYNC_POL;
+	if (pcdev->platform_flags & MX2_CAMERA_SWAP16)
+		csicr1 |= CSICR1_SWAP16_EN;
 	if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC)
 		csicr1 |= CSICR1_EXT_VSYNC;
 	if (pcdev->platform_flags & MX2_CAMERA_CCIR)
@@ -1064,6 +1033,8 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
 		csicr1 |= CSICR1_GCLK_MODE;
 	if (pcdev->platform_flags & MX2_CAMERA_INV_DATA)
 		csicr1 |= CSICR1_INV_DATA;
+	if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB)
+		csicr1 |= CSICR1_PACK_DIR;
 
 	pcdev->csicr1 = csicr1;
 
@@ -1138,8 +1109,7 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd,
 		return 0;
 	}
 
-	if (code == V4L2_MBUS_FMT_YUYV8_2X8 ||
-	    code == V4L2_MBUS_FMT_UYVY8_2X8) {
+	if (code == V4L2_MBUS_FMT_YUYV8_2X8) {
 		formats++;
 		if (xlate) {
 			/*
@@ -1155,18 +1125,6 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd,
 		}
 	}
 
-	if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
-		formats++;
-		if (xlate) {
-			xlate->host_fmt =
-				soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_2X8);
-			xlate->code	= code;
-			dev_dbg(dev, "Providing host format %s for sensor code %d\n",
-				xlate->host_fmt->name, code);
-			xlate++;
-		}
-	}
-
 	/* Generic pass-trough */
 	formats++;
 	if (xlate) {
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index c370c2d..b4c679b 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -26,6 +26,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 7bddfae..cbe4080 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -226,13 +226,11 @@ static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi)
 	struct v4l2_input tmp;
 	unsigned int cnt;
 	int val;
-	int ret;
 
 	cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
 
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.index = vi->index;
-	ret = 0;
 	if (vi->index >= fh->input_cnt)
 		return -EINVAL;
 	val = fh->input_map[vi->index];
@@ -556,9 +554,7 @@ static int pvr2_queryctrl(struct file *file, void *priv,
 	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
 	struct pvr2_ctrl *cptr;
 	int val;
-	int ret;
 
-	ret = 0;
 	if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
 		cptr = pvr2_hdw_get_ctrl_nextv4l(
 				hdw, (vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
@@ -705,11 +701,9 @@ static int pvr2_try_ext_ctrls(struct file *file, void *priv,
 	struct v4l2_ext_control *ctrl;
 	struct pvr2_ctrl *pctl;
 	unsigned int idx;
-	int ret;
 
 	/* For the moment just validate that the requested control
 	   actually exists. */
-	ret = 0;
 	for (idx = 0; idx < ctls->count; idx++) {
 		ctrl = ctls->controls + idx;
 		pctl = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id);
@@ -770,12 +764,10 @@ static int pvr2_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
 {
 	struct pvr2_v4l2_fh *fh = file->private_data;
 	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
-	struct v4l2_cropcap cap;
 	int ret;
 
 	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
-	cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	ret = pvr2_ctrl_set_value(
 			pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
 			crop->c.left);
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index 3545745..62ce539 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -1161,7 +1161,7 @@ static int fimc_cap_g_selection(struct file *file, void *fh,
 }
 
 /* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
-int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
 {
 	if (a->left < b->left || a->top < b->top)
 		return 0;
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index fedcd56..d083ec2 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -463,7 +463,7 @@ void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
 	    f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v);
 }
 
-int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx)
+static int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx)
 {
 	struct fimc_effect *effect = &ctx->effect;
 
@@ -615,7 +615,7 @@ int fimc_ctrls_create(struct fimc_ctx *ctx)
 	ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
 
 	if (!handler->error) {
-		v4l2_ctrl_cluster(3, &ctrls->colorfx);
+		v4l2_ctrl_cluster(2, &ctrls->colorfx);
 		ctrls->ready = true;
 	}
 
diff --git a/drivers/media/video/s5p-fimc/fimc-lite-reg.c b/drivers/media/video/s5p-fimc/fimc-lite-reg.c
index 419adfb..f996e94 100644
--- a/drivers/media/video/s5p-fimc/fimc-lite-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-lite-reg.c
@@ -215,7 +215,7 @@ void flite_hw_set_camera_bus(struct fimc_lite *dev,
 	flite_hw_set_camera_port(dev, s_info->mux_id);
 }
 
-void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
+static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
 {
 	static const u32 pixcode[4][2] = {
 		{ V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR },
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c
index 6753c45..7c5c739 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c
@@ -180,7 +180,7 @@ EXPORT_SYMBOL_GPL(fimc_pipeline_initialize);
  * sensor clock.
  * Called with the graph mutex held.
  */
-int __fimc_pipeline_shutdown(struct fimc_pipeline *p)
+static int __fimc_pipeline_shutdown(struct fimc_pipeline *p)
 {
 	int ret = 0;
 
@@ -1010,7 +1010,7 @@ static struct platform_driver fimc_md_driver = {
 	}
 };
 
-int __init fimc_md_init(void)
+static int __init fimc_md_init(void)
 {
 	int ret;
 
@@ -1021,7 +1021,8 @@ int __init fimc_md_init(void)
 
 	return platform_driver_register(&fimc_md_driver);
 }
-void __exit fimc_md_exit(void)
+
+static void __exit fimc_md_exit(void)
 {
 	platform_driver_unregister(&fimc_md_driver);
 	fimc_unregister_driver();
diff --git a/drivers/media/video/s5p-mfc/regs-mfc.h b/drivers/media/video/s5p-mfc/regs-mfc.h
index 053a8a8..a19bece 100644
--- a/drivers/media/video/s5p-mfc/regs-mfc.h
+++ b/drivers/media/video/s5p-mfc/regs-mfc.h
@@ -164,10 +164,15 @@
 								decoded pic */
 #define S5P_FIMV_SI_DISPLAY_Y_ADR	0x2010 /* luma addr of displayed pic */
 #define S5P_FIMV_SI_DISPLAY_C_ADR	0x2014 /* chroma addrof displayed pic */
+
 #define S5P_FIMV_SI_CONSUMED_BYTES	0x2018 /* Consumed number of bytes to
 							decode a frame */
 #define S5P_FIMV_SI_DISPLAY_STATUS	0x201c /* status of decoded picture */
 
+#define S5P_FIMV_SI_DECODE_Y_ADR	0x2024 /* luma addr of decoded pic */
+#define S5P_FIMV_SI_DECODE_C_ADR	0x2028 /* chroma addrof decoded pic */
+#define S5P_FIMV_SI_DECODE_STATUS	0x202c /* status of decoded picture */
+
 #define S5P_FIMV_SI_CH0_SB_ST_ADR	0x2044 /* start addr of stream buf */
 #define S5P_FIMV_SI_CH0_SB_FRM_SIZE	0x2048 /* size of stream buf */
 #define S5P_FIMV_SI_CH0_DESC_ADR	0x204c /* addr of descriptor buf */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
index c25ec02..4dd32fc 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
@@ -627,13 +627,13 @@ static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl)
 
 	switch (ctrl->id) {
 	case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
-		ctx->loop_filter_mpeg4 = ctrl->val;
+		ctx->display_delay = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE:
 		ctx->display_delay_enable = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
-		ctx->display_delay = ctrl->val;
+		ctx->loop_filter_mpeg4 = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
 		ctx->slice_interface = ctrl->val;
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
index acedb20..03d8334 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
@@ -243,12 +243,6 @@ static struct mfc_control controls[] = {
 		.minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
 		.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
 		.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
-		.menu_skip_mask = ~(
-				(1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
-				(1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
-				(1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
-				(1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_1)
-				),
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
@@ -494,7 +488,7 @@ static struct mfc_control controls[] = {
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
 		.maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
-		.default_value = 0,
+		.default_value = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
 		.menu_skip_mask = 0,
 	},
 	{
@@ -534,7 +528,7 @@ static struct mfc_control controls[] = {
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
 		.maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE,
-		.default_value = 0,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
 		.menu_skip_mask = 0,
 	},
 	{
@@ -907,6 +901,8 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 			mfc_err("failed to try output format\n");
 			return -EINVAL;
 		}
+		v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1,
+			&pix_fmt_mp->height, 4, 1080, 1, 0);
 	} else {
 		mfc_err("invalid buf type\n");
 		return -EINVAL;
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.h b/drivers/media/video/s5p-mfc/s5p_mfc_opr.h
index db83836..5932d1c 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_opr.h
@@ -57,10 +57,12 @@ void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
 					S5P_FIMV_SI_DISPLAY_Y_ADR) << \
 					MFC_OFFSET_SHIFT)
 #define s5p_mfc_get_dec_y_adr()		(readl(dev->regs_base + \
-					S5P_FIMV_SI_DISPLAY_Y_ADR) << \
+					S5P_FIMV_SI_DECODE_Y_ADR) << \
 					MFC_OFFSET_SHIFT)
 #define s5p_mfc_get_dspl_status()	readl(dev->regs_base + \
 						S5P_FIMV_SI_DISPLAY_STATUS)
+#define s5p_mfc_get_dec_status()	readl(dev->regs_base + \
+						S5P_FIMV_SI_DECODE_STATUS)
 #define s5p_mfc_get_frame_type()	(readl(dev->regs_base + \
 						S5P_FIMV_DECODE_FRAME_TYPE) \
 					& S5P_FIMV_DECODE_FRAME_MASK)
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_shm.h b/drivers/media/video/s5p-mfc/s5p_mfc_shm.h
index 764eac6..cf962a4 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_shm.h
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_shm.h
@@ -13,8 +13,7 @@
 #ifndef S5P_MFC_SHM_H_
 #define S5P_MFC_SHM_H_
 
-enum MFC_SHM_OFS
-{
+enum MFC_SHM_OFS {
 	EXTENEDED_DECODE_STATUS	= 0x00,	/* D */
 	SET_FRAME_TAG		= 0x04, /* D */
 	GET_FRAME_TAG_TOP	= 0x08, /* D */
diff --git a/drivers/media/video/saa7121.h b/drivers/media/video/saa7121.h
deleted file mode 100644
index 66967ae..0000000
--- a/drivers/media/video/saa7121.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/* saa7121.h - saa7121 initializations
-   Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You 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 __SAA7121_H__
-#define __SAA7121_H__
-
-#define NTSC_BURST_START	0x19	/* 28 */
-#define NTSC_BURST_END		0x1d	/* 29 */
-#define NTSC_CHROMA_PHASE	0x67	/* 5a */
-#define NTSC_GAINU		0x76	/* 5b */
-#define NTSC_GAINV		0xa5	/* 5c */
-#define NTSC_BLACK_LEVEL	0x2a	/* 5d */
-#define NTSC_BLANKING_LEVEL	0x2e	/* 5e */
-#define NTSC_VBI_BLANKING	0x2e	/* 5f */
-#define NTSC_DAC_CONTROL	0x11	/* 61 */
-#define NTSC_BURST_AMP		0x3f	/* 62 */
-#define NTSC_SUBC3		0x1f	/* 63 */
-#define NTSC_SUBC2		0x7c	/* 64 */
-#define NTSC_SUBC1		0xf0	/* 65 */
-#define NTSC_SUBC0		0x21	/* 66 */
-#define NTSC_HTRIG		0x72	/* 6c */
-#define NTSC_VTRIG		0x00	/* 6c */
-#define NTSC_MULTI		0x30	/* 6e */
-#define NTSC_CCTTX		0x11	/* 6f */
-#define NTSC_FIRST_ACTIVE	0x12	/* 7a */
-#define NTSC_LAST_ACTIVE	0x02	/* 7b */
-#define NTSC_MSB_VERTICAL	0x40	/* 7c */
-
-#define PAL_BURST_START		0x21	/* 28 */
-#define PAL_BURST_END		0x1d	/* 29 */
-#define PAL_CHROMA_PHASE	0x3f	/* 5a */
-#define PAL_GAINU		0x7d	/* 5b */
-#define PAL_GAINV		0xaf	/* 5c */
-#define PAL_BLACK_LEVEL		0x23	/* 5d */
-#define PAL_BLANKING_LEVEL	0x35	/* 5e */
-#define PAL_VBI_BLANKING	0x35	/* 5f */
-#define PAL_DAC_CONTROL		0x02	/* 61 */
-#define PAL_BURST_AMP		0x2f	/* 62 */
-#define PAL_SUBC3		0xcb	/* 63 */
-#define PAL_SUBC2		0x8a	/* 64 */
-#define PAL_SUBC1		0x09	/* 65 */
-#define PAL_SUBC0		0x2a	/* 66 */
-#define PAL_HTRIG		0x86	/* 6c */
-#define PAL_VTRIG		0x04	/* 6d */
-#define PAL_MULTI		0x20	/* 6e */
-#define PAL_CCTTX		0x15	/* 6f */
-#define PAL_FIRST_ACTIVE	0x16	/* 7a */
-#define PAL_LAST_ACTIVE		0x36	/* 7b */
-#define PAL_MSB_VERTICAL	0x40	/* 7c */
-
-/* Initialization Sequence */
-
-static __u8 init7121ntsc[] = {
-	0x26, 0x0,	0x27, 0x0,
-	0x28, NTSC_BURST_START,		0x29, NTSC_BURST_END,
-	0x2a, 0x0,	0x2b, 0x0,	0x2c, 0x0,	0x2d, 0x0,
-	0x2e, 0x0,	0x2f, 0x0,	0x30, 0x0,	0x31, 0x0,
-	0x32, 0x0,	0x33, 0x0,	0x34, 0x0,	0x35, 0x0,
-	0x36, 0x0,	0x37, 0x0,	0x38, 0x0,	0x39, 0x0,
-	0x3a, 0x03,	0x3b, 0x0,	0x3c, 0x0,	0x3d, 0x0,
-	0x3e, 0x0,	0x3f, 0x0,	0x40, 0x0,	0x41, 0x0,
-	0x42, 0x0,	0x43, 0x0,	0x44, 0x0,	0x45, 0x0,
-	0x46, 0x0,	0x47, 0x0,	0x48, 0x0,	0x49, 0x0,
-	0x4a, 0x0,	0x4b, 0x0,	0x4c, 0x0,	0x4d, 0x0,
-	0x4e, 0x0,	0x4f, 0x0,	0x50, 0x0,	0x51, 0x0,
-	0x52, 0x0,	0x53, 0x0,	0x54, 0x0,	0x55, 0x0,
-	0x56, 0x0,	0x57, 0x0,	0x58, 0x0,	0x59, 0x0,
-	0x5a, NTSC_CHROMA_PHASE,	0x5b, NTSC_GAINU,
-	0x5c, NTSC_GAINV,		0x5d, NTSC_BLACK_LEVEL,
-	0x5e, NTSC_BLANKING_LEVEL,	0x5f, NTSC_VBI_BLANKING,
-	0x60, 0x0,			0x61, NTSC_DAC_CONTROL,
-	0x62, NTSC_BURST_AMP,		0x63, NTSC_SUBC3,
-	0x64, NTSC_SUBC2,		0x65, NTSC_SUBC1,
-	0x66, NTSC_SUBC0,		0x67, 0x80,	0x68, 0x80,
-	0x69, 0x80,	0x6a, 0x80,	0x6b, 0x29,
-	0x6c, NTSC_HTRIG,		0x6d, NTSC_VTRIG,
-	0x6e, NTSC_MULTI,		0x6f, NTSC_CCTTX,
-	0x70, 0xc9,	0x71, 0x68,	0x72, 0x60,	0x73, 0x0,
-	0x74, 0x0,	0x75, 0x0,	0x76, 0x0,	0x77, 0x0,
-	0x78, 0x0,	0x79, 0x0,	0x7a, NTSC_FIRST_ACTIVE,
-	0x7b, NTSC_LAST_ACTIVE,		0x7c, NTSC_MSB_VERTICAL,
-	0x7d, 0x0,	0x7e, 0x0,	0x7f, 0x0
-};
-#define INIT7121LEN	(sizeof(init7121ntsc)/2)
-
-static __u8 init7121pal[] = {
-	0x26, 0x0,	0x27, 0x0,
-	0x28, PAL_BURST_START,		0x29, PAL_BURST_END,
-	0x2a, 0x0,	0x2b, 0x0,	0x2c, 0x0,	0x2d, 0x0,
-	0x2e, 0x0,	0x2f, 0x0,	0x30, 0x0,	0x31, 0x0,
-	0x32, 0x0,	0x33, 0x0,	0x34, 0x0,	0x35, 0x0,
-	0x36, 0x0,	0x37, 0x0,	0x38, 0x0,	0x39, 0x0,
-	0x3a, 0x03,	0x3b, 0x0,	0x3c, 0x0,	0x3d, 0x0,
-	0x3e, 0x0,	0x3f, 0x0,	0x40, 0x0,	0x41, 0x0,
-	0x42, 0x0,	0x43, 0x0,	0x44, 0x0,	0x45, 0x0,
-	0x46, 0x0,	0x47, 0x0,	0x48, 0x0,	0x49, 0x0,
-	0x4a, 0x0,	0x4b, 0x0,	0x4c, 0x0,	0x4d, 0x0,
-	0x4e, 0x0,	0x4f, 0x0,	0x50, 0x0,	0x51, 0x0,
-	0x52, 0x0,	0x53, 0x0,	0x54, 0x0,	0x55, 0x0,
-	0x56, 0x0,	0x57, 0x0,	0x58, 0x0,	0x59, 0x0,
-	0x5a, PAL_CHROMA_PHASE,		0x5b, PAL_GAINU,
-	0x5c, PAL_GAINV,		0x5d, PAL_BLACK_LEVEL,
-	0x5e, PAL_BLANKING_LEVEL,	0x5f, PAL_VBI_BLANKING,
-	0x60, 0x0,			0x61, PAL_DAC_CONTROL,
-	0x62, PAL_BURST_AMP,		0x63, PAL_SUBC3,
-	0x64, PAL_SUBC2,		0x65, PAL_SUBC1,
-	0x66, PAL_SUBC0,		0x67, 0x80,	0x68, 0x80,
-	0x69, 0x80,	0x6a, 0x80,	0x6b, 0x29,
-	0x6c, PAL_HTRIG,		0x6d, PAL_VTRIG,
-	0x6e, PAL_MULTI,		0x6f, PAL_CCTTX,
-	0x70, 0xc9,	0x71, 0x68,	0x72, 0x60,	0x73, 0x0,
-	0x74, 0x0,	0x75, 0x0,	0x76, 0x0,	0x77, 0x0,
-	0x78, 0x0,	0x79, 0x0,	0x7a, PAL_FIRST_ACTIVE,
-	0x7b, PAL_LAST_ACTIVE,		0x7c, PAL_MSB_VERTICAL,
-	0x7d, 0x0,	0x7e, 0x0,	0x7f, 0x0
-};
-#endif
diff --git a/drivers/media/video/saa7146.h b/drivers/media/video/saa7146.h
deleted file mode 100644
index 9fadb33..0000000
--- a/drivers/media/video/saa7146.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
-    saa7146.h - definitions philips saa7146 based cards
-    Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You 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 __SAA7146__
-#define __SAA7146__
-
-#define SAA7146_VERSION_CODE 0x000101
-
-#include <linux/types.h>
-#include <linux/wait.h>
-
-#ifndef O_NONCAP
-#define O_NONCAP	O_TRUNC
-#endif
-
-#define MAX_GBUFFERS	2
-#define FBUF_SIZE	0x190000
-
-#ifdef __KERNEL__
-
-struct saa7146_window
-{
-	int x, y;
-	ushort width, height;
-	ushort bpp, bpl;
-	ushort swidth, sheight;
-	short cropx, cropy;
-	ushort cropwidth, cropheight;
-	unsigned long vidadr;
-	int color_fmt;
-	ushort depth;
-};
-
-/*  Per-open data for handling multiple opens on one device */
-struct device_open
-{
-	int	     isopen;
-	int	     noncapturing;
-	struct saa7146  *dev;
-};
-#define MAX_OPENS 3
-
-struct saa7146
-{
-	struct video_device video_dev;
-	struct video_picture picture;
-	struct video_audio audio_dev;
-	struct video_info vidinfo;
-	int user;
-	int cap;
-	int capuser;
-	int irqstate;		/* irq routine is state driven */
-	int writemode;
-	int playmode;
-	unsigned int nr;
-	unsigned long irq;          /* IRQ used by SAA7146 card */
-	unsigned short id;
-	unsigned char revision;
-	unsigned char boardcfg[64];	/* 64 bytes of config from eeprom */
-	unsigned long saa7146_adr;   /* bus address of IO mem from PCI BIOS */
-	struct saa7146_window win;
-	unsigned char __iomem *saa7146_mem; /* pointer to mapped IO memory */
-	struct device_open open_data[MAX_OPENS];
-#define MAX_MARKS 16
-	/* for a/v sync */
-	int endmark[MAX_MARKS], endmarkhead, endmarktail;
-	u32 *dmaRPS1, *pageRPS1, *dmaRPS2, *pageRPS2, *dmavid1, *dmavid2,
-		*dmavid3, *dmaa1in, *dmaa1out, *dmaa2in, *dmaa2out,
-		*pagedebi, *pagevid1, *pagevid2, *pagevid3, *pagea1in,
-		*pagea1out, *pagea2in, *pagea2out;
-	wait_queue_head_t i2cq, debiq, audq, vidq;
-	u8  *vidbuf, *audbuf, *osdbuf, *dmadebi;
-	int audhead, vidhead, osdhead, audtail, vidtail, osdtail;
-	spinlock_t lock;	/* the device lock */
-};
-#endif
-
-#ifdef _ALPHA_SAA7146
-#define saawrite(dat,adr)    writel((dat), saa->saa7146_adr+(adr))
-#define saaread(adr)         readl(saa->saa7146_adr+(adr))
-#else
-#define saawrite(dat,adr)    writel((dat), saa->saa7146_mem+(adr))
-#define saaread(adr)         readl(saa->saa7146_mem+(adr))
-#endif
-
-#define saaand(dat,adr)      saawrite((dat) & saaread(adr), adr)
-#define saaor(dat,adr)       saawrite((dat) | saaread(adr), adr)
-#define saaaor(dat,mask,adr) saawrite((dat) | ((mask) & saaread(adr)), adr)
-
-/* bitmask of attached hardware found */
-#define SAA7146_UNKNOWN		0x00000000
-#define SAA7146_SAA7111		0x00000001
-#define SAA7146_SAA7121		0x00000002
-#define SAA7146_IBMMPEG		0x00000004
-
-#endif
diff --git a/drivers/media/video/saa7146reg.h b/drivers/media/video/saa7146reg.h
deleted file mode 100644
index 80ec2c1..0000000
--- a/drivers/media/video/saa7146reg.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
-    saa7146.h - definitions philips saa7146 based cards
-    Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You 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 __SAA7146_REG__
-#define __SAA7146_REG__
-#define SAA7146_BASE_ODD1	0x00
-#define SAA7146_BASE_EVEN1	0x04
-#define SAA7146_PROT_ADDR1	0x08
-#define SAA7146_PITCH1		0x0c
-#define SAA7146_PAGE1		0x10
-#define SAA7146_NUM_LINE_BYTE1	0x14
-#define SAA7146_BASE_ODD2	0x18
-#define SAA7146_BASE_EVEN2	0x1c
-#define SAA7146_PROT_ADDR2	0x20
-#define SAA7146_PITCH2		0x24
-#define SAA7146_PAGE2		0x28
-#define SAA7146_NUM_LINE_BYTE2	0x2c
-#define SAA7146_BASE_ODD3	0x30
-#define SAA7146_BASE_EVEN3	0x34
-#define SAA7146_PROT_ADDR3	0x38
-#define SAA7146_PITCH3		0x3c
-#define SAA7146_PAGE3		0x40
-#define SAA7146_NUM_LINE_BYTE3	0x44
-#define SAA7146_PCI_BT_V1	0x48
-#define SAA7146_PCI_BT_V2	0x49
-#define SAA7146_PCI_BT_V3	0x4a
-#define SAA7146_PCI_BT_DEBI	0x4b
-#define SAA7146_PCI_BT_A	0x4c
-#define SAA7146_DD1_INIT	0x50
-#define SAA7146_DD1_STREAM_B	0x54
-#define SAA7146_DD1_STREAM_A	0x56
-#define SAA7146_BRS_CTRL	0x58
-#define SAA7146_HPS_CTRL	0x5c
-#define SAA7146_HPS_V_SCALE	0x60
-#define SAA7146_HPS_V_GAIN	0x64
-#define SAA7146_HPS_H_PRESCALE	0x68
-#define SAA7146_HPS_H_SCALE	0x6c
-#define SAA7146_BCS_CTRL	0x70
-#define SAA7146_CHROMA_KEY_RANGE	0x74
-#define SAA7146_CLIP_FORMAT_CTRL	0x78
-#define SAA7146_DEBI_CONFIG	0x7c
-#define SAA7146_DEBI_COMMAND	0x80
-#define SAA7146_DEBI_PAGE	0x84
-#define SAA7146_DEBI_AD		0x88
-#define SAA7146_I2C_TRANSFER	0x8c
-#define SAA7146_I2C_STATUS	0x90
-#define SAA7146_BASE_A1_IN	0x94
-#define SAA7146_PROT_A1_IN	0x98
-#define SAA7146_PAGE_A1_IN	0x9C
-#define SAA7146_BASE_A1_OUT	0xa0
-#define SAA7146_PROT_A1_OUT	0xa4
-#define SAA7146_PAGE_A1_OUT	0xa8
-#define SAA7146_BASE_A2_IN	0xac
-#define SAA7146_PROT_A2_IN	0xb0
-#define SAA7146_PAGE_A2_IN	0xb4
-#define SAA7146_BASE_A2_OUT	0xb8
-#define SAA7146_PROT_A2_OUT	0xbc
-#define SAA7146_PAGE_A2_OUT	0xc0
-#define SAA7146_RPS_PAGE0	0xc4
-#define SAA7146_RPS_PAGE1	0xc8
-#define SAA7146_RPS_THRESH0	0xcc
-#define SAA7146_RPS_THRESH1	0xd0
-#define SAA7146_RPS_TOV0	0xd4
-#define SAA7146_RPS_TOV1	0xd8
-#define SAA7146_IER		0xdc
-#define SAA7146_GPIO_CTRL	0xe0
-#define SAA7146_EC1SSR		0xe4
-#define SAA7146_EC2SSR		0xe8
-#define SAA7146_ECT1R		0xec
-#define SAA7146_ECT2R		0xf0
-#define SAA7146_ACON1		0xf4
-#define SAA7146_ACON2		0xf8
-#define SAA7146_MC1		0xfc
-#define SAA7146_MC2		0x100
-#define SAA7146_RPS_ADDR0	0x104
-#define SAA7146_RPS_ADDR1	0x108
-#define SAA7146_ISR		0x10c
-#define SAA7146_PSR		0x110
-#define SAA7146_SSR		0x114
-#define SAA7146_EC1R		0x118
-#define SAA7146_EC2R		0x11c
-#define SAA7146_VDP1		0x120
-#define SAA7146_VDP2		0x124
-#define SAA7146_VDP3		0x128
-#define SAA7146_ADP1		0x12c
-#define SAA7146_ADP2		0x130
-#define SAA7146_ADP3		0x134
-#define SAA7146_ADP4		0x138
-#define SAA7146_DDP		0x13c
-#define SAA7146_LEVEL_REP	0x140
-#define SAA7146_FB_BUFFER1	0x144
-#define SAA7146_FB_BUFFER2	0x148
-#define SAA7146_A_TIME_SLOT1	0x180
-#define SAA7146_A_TIME_SLOT2	0x1C0
-
-/* bitfield defines */
-#define MASK_31			0x80000000
-#define MASK_30			0x40000000
-#define MASK_29			0x20000000
-#define MASK_28			0x10000000
-#define MASK_27			0x08000000
-#define MASK_26			0x04000000
-#define MASK_25			0x02000000
-#define MASK_24			0x01000000
-#define MASK_23			0x00800000
-#define MASK_22			0x00400000
-#define MASK_21			0x00200000
-#define MASK_20			0x00100000
-#define MASK_19			0x00080000
-#define MASK_18			0x00040000
-#define MASK_17			0x00020000
-#define MASK_16			0x00010000
-#define MASK_15			0x00008000
-#define MASK_14			0x00004000
-#define MASK_13			0x00002000
-#define MASK_12			0x00001000
-#define MASK_11			0x00000800
-#define MASK_10			0x00000400
-#define MASK_09			0x00000200
-#define MASK_08			0x00000100
-#define MASK_07			0x00000080
-#define MASK_06			0x00000040
-#define MASK_05			0x00000020
-#define MASK_04			0x00000010
-#define MASK_03			0x00000008
-#define MASK_02			0x00000004
-#define MASK_01			0x00000002
-#define MASK_00			0x00000001
-#define MASK_B0			0x000000ff
-#define MASK_B1			0x0000ff00
-#define MASK_B2			0x00ff0000
-#define MASK_B3			0xff000000
-#define MASK_W0			0x0000ffff
-#define MASK_W1			0xffff0000
-#define MASK_PA			0xfffffffc
-#define MASK_PR			0xfffffffe
-#define MASK_ER			0xffffffff
-#define MASK_NONE		0x00000000
-
-#define SAA7146_PAGE_MAP_EN	MASK_11
-/* main control register 1 */
-#define SAA7146_MC1_MRST_N	MASK_15
-#define SAA7146_MC1_ERPS1	MASK_13
-#define SAA7146_MC1_ERPS0	MASK_12
-#define SAA7146_MC1_EDP		MASK_11
-#define SAA7146_MC1_EVP		MASK_10
-#define SAA7146_MC1_EAP		MASK_09
-#define SAA7146_MC1_EI2C	MASK_08
-#define SAA7146_MC1_TR_E_DEBI	MASK_07
-#define SAA7146_MC1_TR_E_1	MASK_06
-#define SAA7146_MC1_TR_E_2	MASK_05
-#define SAA7146_MC1_TR_E_3	MASK_04
-#define SAA7146_MC1_TR_E_A2_OUT	MASK_03
-#define SAA7146_MC1_TR_E_A2_IN	MASK_02
-#define SAA7146_MC1_TR_E_A1_OUT	MASK_01
-#define SAA7146_MC1_TR_E_A1_IN	MASK_00
-/* main control register 2 */
-#define SAA7146_MC2_RPS_SIG4	MASK_15
-#define SAA7146_MC2_RPS_SIG3	MASK_14
-#define SAA7146_MC2_RPS_SIG2	MASK_13
-#define SAA7146_MC2_RPS_SIG1	MASK_12
-#define SAA7146_MC2_RPS_SIG0	MASK_11
-#define SAA7146_MC2_UPLD_D1_B	MASK_10
-#define SAA7146_MC2_UPLD_D1_A	MASK_09
-#define SAA7146_MC2_UPLD_BRS	MASK_08
-#define SAA7146_MC2_UPLD_HPS_H	MASK_06
-#define SAA7146_MC2_UPLD_HPS_V	MASK_05
-#define SAA7146_MC2_UPLD_DMA3	MASK_04
-#define SAA7146_MC2_UPLD_DMA2	MASK_03
-#define SAA7146_MC2_UPLD_DMA1	MASK_02
-#define SAA7146_MC2_UPLD_DEBI	MASK_01
-#define SAA7146_MC2_UPLD_I2C	MASK_00
-/* Primary Status Register and Interrupt Enable/Status Registers */
-#define SAA7146_PSR_PPEF	MASK_31
-#define SAA7146_PSR_PABO	MASK_30
-#define SAA7146_PSR_PPED	MASK_29
-#define SAA7146_PSR_RPS_I1	MASK_28
-#define SAA7146_PSR_RPS_I0	MASK_27
-#define SAA7146_PSR_RPS_LATE1	MASK_26
-#define SAA7146_PSR_RPS_LATE0	MASK_25
-#define SAA7146_PSR_RPS_E1	MASK_24
-#define SAA7146_PSR_RPS_E0	MASK_23
-#define SAA7146_PSR_RPS_TO1	MASK_22
-#define SAA7146_PSR_RPS_TO0	MASK_21
-#define SAA7146_PSR_UPLD	MASK_20
-#define SAA7146_PSR_DEBI_S	MASK_19
-#define SAA7146_PSR_DEBI_E	MASK_18
-#define SAA7146_PSR_I2C_S	MASK_17
-#define SAA7146_PSR_I2C_E	MASK_16
-#define SAA7146_PSR_A2_IN	MASK_15
-#define SAA7146_PSR_A2_OUT	MASK_14
-#define SAA7146_PSR_A1_IN	MASK_13
-#define SAA7146_PSR_A1_OUT	MASK_12
-#define SAA7146_PSR_AFOU	MASK_11
-#define SAA7146_PSR_V_PE	MASK_10
-#define SAA7146_PSR_VFOU	MASK_09
-#define SAA7146_PSR_FIDA	MASK_08
-#define SAA7146_PSR_FIDB	MASK_07
-#define SAA7146_PSR_PIN3	MASK_06
-#define SAA7146_PSR_PIN2	MASK_05
-#define SAA7146_PSR_PIN1	MASK_04
-#define SAA7146_PSR_PIN0	MASK_03
-#define SAA7146_PSR_ECS		MASK_02
-#define SAA7146_PSR_EC3S	MASK_01
-#define SAA7146_PSR_EC0S	MASK_00
-/* Secondary Status Register */
-#define SAA7146_SSR_PRQ		MASK_31
-#define SAA7146_SSR_PMA		MASK_30
-#define SAA7146_SSR_RPS_RE1	MASK_29
-#define SAA7146_SSR_RPS_PE1	MASK_28
-#define SAA7146_SSR_RPS_A1	MASK_27
-#define SAA7146_SSR_RPS_RE0	MASK_26
-#define SAA7146_SSR_RPS_PE0	MASK_25
-#define SAA7146_SSR_RPS_A0	MASK_24
-#define SAA7146_SSR_DEBI_TO	MASK_23
-#define SAA7146_SSR_DEBI_EF	MASK_22
-#define SAA7146_SSR_I2C_EA	MASK_21
-#define SAA7146_SSR_I2C_EW	MASK_20
-#define SAA7146_SSR_I2C_ER	MASK_19
-#define SAA7146_SSR_I2C_EL	MASK_18
-#define SAA7146_SSR_I2C_EF	MASK_17
-#define SAA7146_SSR_V3P		MASK_16
-#define SAA7146_SSR_V2P		MASK_15
-#define SAA7146_SSR_V1P		MASK_14
-#define SAA7146_SSR_VF3		MASK_13
-#define SAA7146_SSR_VF2		MASK_12
-#define SAA7146_SSR_VF1		MASK_11
-#define SAA7146_SSR_AF2_IN	MASK_10
-#define SAA7146_SSR_AF2_OUT	MASK_09
-#define SAA7146_SSR_AF1_IN	MASK_08
-#define SAA7146_SSR_AF1_OUT	MASK_07
-#define SAA7146_SSR_VGT		MASK_05
-#define SAA7146_SSR_LNQG	MASK_04
-#define SAA7146_SSR_EC5S	MASK_03
-#define SAA7146_SSR_EC4S	MASK_02
-#define SAA7146_SSR_EC2S	MASK_01
-#define SAA7146_SSR_EC1S	MASK_00
-/* I2C status register */
-#define SAA7146_I2C_ABORT	MASK_07
-#define SAA7146_I2C_SPERR	MASK_06
-#define SAA7146_I2C_APERR	MASK_05
-#define SAA7146_I2C_DTERR	MASK_04
-#define SAA7146_I2C_DRERR	MASK_03
-#define SAA7146_I2C_AL		MASK_02
-#define SAA7146_I2C_ERR		MASK_01
-#define SAA7146_I2C_BUSY	MASK_00
-/* output formats */
-#define SAA7146_YUV422	0
-#define SAA7146_RGB16	0
-#define SAA7146_YUV444	1
-#define SAA7146_RGB24	1
-#define SAA7146_ARGB32	2
-#define SAA7146_YUV411	3
-#define SAA7146_ARGB15  3
-#define SAA7146_YUV2	4
-#define SAA7146_RGAB15	4
-#define SAA7146_Y8	6
-#define SAA7146_YUV8	7
-#define SAA7146_RGB8	7
-#define SAA7146_YUV444p	8
-#define SAA7146_YUV422p	9
-#define SAA7146_YUV420p	10
-#define SAA7146_YUV1620	11
-#define SAA7146_Y1	13
-#define SAA7146_Y2	14
-#define SAA7146_YUV1	15
-#endif
diff --git a/drivers/media/video/saa7164/saa7164-api.c b/drivers/media/video/saa7164/saa7164-api.c
index 8a98ab6..c8799fd 100644
--- a/drivers/media/video/saa7164/saa7164-api.c
+++ b/drivers/media/video/saa7164/saa7164-api.c
@@ -1367,7 +1367,6 @@ int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
 	struct saa7164_dev *dev = bus->dev;
 	u16 len = 0;
 	int unitid;
-	u32 regval;
 	u8 buf[256];
 	int ret;
 
@@ -1376,19 +1375,6 @@ int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
 	if (reglen > 4)
 		return -EIO;
 
-	if (reglen == 1)
-		regval = *(reg);
-	else
-	if (reglen == 2)
-		regval = ((*(reg) << 8) || *(reg+1));
-	else
-	if (reglen == 3)
-		regval = ((*(reg) << 16) | (*(reg+1) << 8) | *(reg+2));
-	else
-	if (reglen == 4)
-		regval = ((*(reg) << 24) | (*(reg+1) << 16) |
-			(*(reg+2) << 8) | *(reg+3));
-
 	/* Prepare the send buffer */
 	/* Bytes 00-03 source register length
 	 *       04-07 source bytes to read
diff --git a/drivers/media/video/smiapp/Kconfig b/drivers/media/video/smiapp/Kconfig
index f7b35ff..fb99ff1 100644
--- a/drivers/media/video/smiapp/Kconfig
+++ b/drivers/media/video/smiapp/Kconfig
@@ -1,6 +1,6 @@
 config VIDEO_SMIAPP
 	tristate "SMIA++/SMIA sensor support"
-	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAVE_CLK
 	select VIDEO_SMIAPP_PLL
 	---help---
 	  This is a generic driver for SMIA++/SMIA camera modules.
diff --git a/drivers/media/video/smiapp/smiapp-core.c b/drivers/media/video/smiapp/smiapp-core.c
index f518026..9cf5bda 100644
--- a/drivers/media/video/smiapp/smiapp-core.c
+++ b/drivers/media/video/smiapp/smiapp-core.c
@@ -31,7 +31,9 @@
 #include <linux/device.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
 #include <linux/v4l2-mediabus.h>
 #include <media/v4l2-device.h>
 
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 3e050e1..1ad5ab6 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -1178,7 +1178,7 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 		return 0;
 	if (vt->type == t->mode && analog_ops->get_afc)
 		vt->afc = analog_ops->get_afc(&t->fe);
-	if (t->mode != V4L2_TUNER_RADIO) {
+	if (vt->type != V4L2_TUNER_RADIO) {
 		vt->capability |= V4L2_TUNER_CAP_NORM;
 		vt->rangelow = tv_range[0] * 16;
 		vt->rangehigh = tv_range[1] * 16;
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index c5b1a73..1e61cbf 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -118,7 +118,7 @@ struct CHIPSTATE {
 	audiocmd   shadow;
 
 	/* current settings */
-	__u16 left,right,treble,bass,muted,mode;
+	__u16 left, right, treble, bass, muted;
 	int prevmode;
 	int radio;
 	int input;
@@ -126,7 +126,6 @@ struct CHIPSTATE {
 	/* thread */
 	struct task_struct   *thread;
 	struct timer_list    wt;
-	int                  watch_stereo;
 	int 		     audmode;
 };
 
@@ -288,7 +287,7 @@ static int chip_thread(void *data)
 	struct CHIPSTATE *chip = data;
 	struct CHIPDESC  *desc = chip->desc;
 	struct v4l2_subdev *sd = &chip->sd;
-	int mode;
+	int mode, selected;
 
 	v4l2_dbg(1, debug, sd, "thread started\n");
 	set_freezable();
@@ -302,8 +301,8 @@ static int chip_thread(void *data)
 			break;
 		v4l2_dbg(1, debug, sd, "thread wakeup\n");
 
-		/* don't do anything for radio or if mode != auto */
-		if (chip->radio || chip->mode != 0)
+		/* don't do anything for radio */
+		if (chip->radio)
 			continue;
 
 		/* have a look what's going on */
@@ -316,16 +315,32 @@ static int chip_thread(void *data)
 
 		chip->prevmode = mode;
 
-		if (mode & V4L2_TUNER_MODE_STEREO)
-			desc->setmode(chip, V4L2_TUNER_MODE_STEREO);
-		if (mode & V4L2_TUNER_MODE_LANG1_LANG2)
-			desc->setmode(chip, V4L2_TUNER_MODE_STEREO);
-		else if (mode & V4L2_TUNER_MODE_LANG1)
-			desc->setmode(chip, V4L2_TUNER_MODE_LANG1);
-		else if (mode & V4L2_TUNER_MODE_LANG2)
-			desc->setmode(chip, V4L2_TUNER_MODE_LANG2);
-		else
-			desc->setmode(chip, V4L2_TUNER_MODE_MONO);
+		selected = V4L2_TUNER_MODE_MONO;
+		switch (chip->audmode) {
+		case V4L2_TUNER_MODE_MONO:
+			if (mode & V4L2_TUNER_SUB_LANG1)
+				selected = V4L2_TUNER_MODE_LANG1;
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+		case V4L2_TUNER_MODE_LANG1:
+			if (mode & V4L2_TUNER_SUB_LANG1)
+				selected = V4L2_TUNER_MODE_LANG1;
+			else if (mode & V4L2_TUNER_SUB_STEREO)
+				selected = V4L2_TUNER_MODE_STEREO;
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			if (mode & V4L2_TUNER_SUB_LANG2)
+				selected = V4L2_TUNER_MODE_LANG2;
+			else if (mode & V4L2_TUNER_SUB_STEREO)
+				selected = V4L2_TUNER_MODE_STEREO;
+			break;
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			if (mode & V4L2_TUNER_SUB_LANG2)
+				selected = V4L2_TUNER_MODE_LANG1_LANG2;
+			else if (mode & V4L2_TUNER_SUB_STEREO)
+				selected = V4L2_TUNER_MODE_STEREO;
+		}
+		desc->setmode(chip, selected);
 
 		/* schedule next check */
 		mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
@@ -364,11 +379,11 @@ static int tda9840_getmode(struct CHIPSTATE *chip)
 	int val, mode;
 
 	val = chip_read(chip);
-	mode = V4L2_TUNER_MODE_MONO;
+	mode = V4L2_TUNER_SUB_MONO;
 	if (val & TDA9840_DS_DUAL)
-		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+		mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 	if (val & TDA9840_ST_STEREO)
-		mode |= V4L2_TUNER_MODE_STEREO;
+		mode = V4L2_TUNER_SUB_STEREO;
 
 	v4l2_dbg(1, debug, sd, "tda9840_getmode(): raw chip read: %d, return: %d\n",
 		val, mode);
@@ -393,6 +408,9 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode)
 	case V4L2_TUNER_MODE_LANG2:
 		t |= TDA9840_DUALB;
 		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		t |= TDA9840_DUALAB;
+		break;
 	default:
 		update = 0;
 	}
@@ -477,6 +495,7 @@ static int tda9840_checkit(struct CHIPSTATE *chip)
 /* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */
 /* Common to TDA9855 and TDA9850: */
 #define TDA985x_SAP	3<<6 /* Selects SAP output, mute if not received */
+#define TDA985x_MONOSAP	2<<6 /* Selects Mono on left, SAP on right */
 #define TDA985x_STEREO	1<<6 /* Selects Stereo ouput, mono if not received */
 #define TDA985x_MONO	0    /* Forces Mono output */
 #define TDA985x_LMU	1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */
@@ -515,13 +534,17 @@ static int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; }
 
 static int  tda985x_getmode(struct CHIPSTATE *chip)
 {
-	int mode;
+	int mode, val;
 
-	mode = ((TDA985x_STP | TDA985x_SAPP) &
-		chip_read(chip)) >> 4;
 	/* Add mono mode regardless of SAP and stereo */
 	/* Allows forced mono */
-	return mode | V4L2_TUNER_MODE_MONO;
+	mode = V4L2_TUNER_SUB_MONO;
+	val = chip_read(chip);
+	if (val & TDA985x_STP)
+		mode = V4L2_TUNER_SUB_STEREO;
+	if (val & TDA985x_SAPP)
+		mode |= V4L2_TUNER_SUB_SAP;
+	return mode;
 }
 
 static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
@@ -534,11 +557,15 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
 		c6 |= TDA985x_MONO;
 		break;
 	case V4L2_TUNER_MODE_STEREO:
+	case V4L2_TUNER_MODE_LANG1:
 		c6 |= TDA985x_STEREO;
 		break;
-	case V4L2_TUNER_MODE_LANG1:
+	case V4L2_TUNER_MODE_SAP:
 		c6 |= TDA985x_SAP;
 		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		c6 |= TDA985x_MONOSAP;
+		break;
 	default:
 		update = 0;
 	}
@@ -583,9 +610,10 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
 #define TDA9873_TR_MASK     (7 << 2)
 #define TDA9873_TR_MONO     4
 #define TDA9873_TR_STEREO   1 << 4
-#define TDA9873_TR_REVERSE  (1 << 3) & (1 << 2)
+#define TDA9873_TR_REVERSE  ((1 << 3) | (1 << 2))
 #define TDA9873_TR_DUALA    1 << 2
 #define TDA9873_TR_DUALB    1 << 3
+#define TDA9873_TR_DUALAB   0
 
 /* output level controls
  * B5:  output level switch (0 = reduced gain, 1 = normal gain)
@@ -653,11 +681,11 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
 #define TDA9873_MOUT_DUALA  0
 #define TDA9873_MOUT_DUALB  1 << 3
 #define TDA9873_MOUT_ST     1 << 4
-#define TDA9873_MOUT_EXTM   (1 << 4 ) & (1 << 3)
+#define TDA9873_MOUT_EXTM   ((1 << 4) | (1 << 3))
 #define TDA9873_MOUT_EXTL   1 << 5
-#define TDA9873_MOUT_EXTR   (1 << 5 ) & (1 << 3)
-#define TDA9873_MOUT_EXTLR  (1 << 5 ) & (1 << 4)
-#define TDA9873_MOUT_MUTE   (1 << 5 ) & (1 << 4) & (1 << 3)
+#define TDA9873_MOUT_EXTR   ((1 << 5) | (1 << 3))
+#define TDA9873_MOUT_EXTLR  ((1 << 5) | (1 << 4))
+#define TDA9873_MOUT_MUTE   ((1 << 5) | (1 << 4) | (1 << 3))
 
 /* Status bits: (chip read) */
 #define TDA9873_PONR        0 /* Power-on reset detected if = 1 */
@@ -670,11 +698,11 @@ static int tda9873_getmode(struct CHIPSTATE *chip)
 	int val,mode;
 
 	val = chip_read(chip);
-	mode = V4L2_TUNER_MODE_MONO;
+	mode = V4L2_TUNER_SUB_MONO;
 	if (val & TDA9873_STEREO)
-		mode |= V4L2_TUNER_MODE_STEREO;
+		mode = V4L2_TUNER_SUB_STEREO;
 	if (val & TDA9873_DUAL)
-		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+		mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 	v4l2_dbg(1, debug, sd, "tda9873_getmode(): raw chip read: %d, return: %d\n",
 		val, mode);
 	return mode;
@@ -707,8 +735,10 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
 	case V4L2_TUNER_MODE_LANG2:
 		sw_data |= TDA9873_TR_DUALB;
 		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		sw_data |= TDA9873_TR_DUALAB;
+		break;
 	default:
-		chip->mode = 0;
 		return;
 	}
 
@@ -865,7 +895,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
 	int dsr,nsr,mode;
 	int necr; /* just for debugging */
 
-	mode = V4L2_TUNER_MODE_MONO;
+	mode = V4L2_TUNER_SUB_MONO;
 
 	if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR)))
 		return mode;
@@ -888,14 +918,14 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
 		 * external 4052 multiplexer in audio_hook().
 		 */
 		if(nsr & 0x02) /* NSR.S/MB=1 */
-			mode |= V4L2_TUNER_MODE_STEREO;
+			mode = V4L2_TUNER_SUB_STEREO;
 		if(nsr & 0x01) /* NSR.D/SB=1 */
-			mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+			mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 	} else {
 		if(dsr & 0x02) /* DSR.IDSTE=1 */
-			mode |= V4L2_TUNER_MODE_STEREO;
+			mode = V4L2_TUNER_SUB_STEREO;
 		if(dsr & 0x04) /* DSR.IDDUA=1 */
-			mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+			mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 	}
 
 	v4l2_dbg(1, debug, sd, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
@@ -939,8 +969,11 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
 			aosr = 0xa0; /* auto-select, dual B/B */
 			mdacosr = (tda9874a_mode) ? 0x83:0x81;
 			break;
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			aosr = 0x00; /* always route L to L and R to R */
+			mdacosr = (tda9874a_mode) ? 0x82:0x80;
+			break;
 		default:
-			chip->mode = 0;
 			return;
 		}
 		chip_write(chip, TDA9874A_AOSR, aosr);
@@ -974,8 +1007,11 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
 			fmmr = 0x02; /* dual */
 			aosr = 0x20; /* dual B/B */
 			break;
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			fmmr = 0x02; /* dual */
+			aosr = 0x00; /* dual A/B */
+			break;
 		default:
-			chip->mode = 0;
 			return;
 		}
 		chip_write(chip, TDA9874A_FMMR, fmmr);
@@ -1230,21 +1266,29 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
 {
 	int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
 
-	if (mode & V4L2_TUNER_MODE_LANG1) {
+	switch (mode) {
+	case V4L2_TUNER_MODE_LANG1:
 		s1 |= TDA8425_S1_ML_SOUND_A;
 		s1 |= TDA8425_S1_STEREO_PSEUDO;
-
-	} else if (mode & V4L2_TUNER_MODE_LANG2) {
+		break;
+	case V4L2_TUNER_MODE_LANG2:
 		s1 |= TDA8425_S1_ML_SOUND_B;
 		s1 |= TDA8425_S1_STEREO_PSEUDO;
-
-	} else {
+		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
 		s1 |= TDA8425_S1_ML_STEREO;
-
-		if (mode & V4L2_TUNER_MODE_MONO)
-			s1 |= TDA8425_S1_STEREO_MONO;
-		if (mode & V4L2_TUNER_MODE_STEREO)
-			s1 |= TDA8425_S1_STEREO_SPATIAL;
+		s1 |= TDA8425_S1_STEREO_LINEAR;
+		break;
+	case V4L2_TUNER_MODE_MONO:
+		s1 |= TDA8425_S1_ML_STEREO;
+		s1 |= TDA8425_S1_STEREO_MONO;
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+		s1 |= TDA8425_S1_ML_STEREO;
+		s1 |= TDA8425_S1_STEREO_SPATIAL;
+		break;
+	default:
+		return;
 	}
 	chip_write(chip,TDA8425_S1,s1);
 }
@@ -1302,11 +1346,11 @@ static int ta8874z_getmode(struct CHIPSTATE *chip)
 	int val, mode;
 
 	val = chip_read(chip);
-	mode = V4L2_TUNER_MODE_MONO;
+	mode = V4L2_TUNER_SUB_MONO;
 	if (val & TA8874Z_B1){
-		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+		mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 	}else if (!(val & TA8874Z_B0)){
-		mode |= V4L2_TUNER_MODE_STEREO;
+		mode = V4L2_TUNER_SUB_STEREO;
 	}
 	/* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
 	return mode;
@@ -1316,6 +1360,7 @@ static audiocmd ta8874z_stereo = { 2, {0, TA8874Z_SEPARATION_DEFAULT}};
 static audiocmd ta8874z_mono = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}};
 static audiocmd ta8874z_main = {2, { 0, TA8874Z_SEPARATION_DEFAULT}};
 static audiocmd ta8874z_sub = {2, { TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}};
+static audiocmd ta8874z_both = {2, { TA8874Z_MODE_MAIN | TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}};
 
 static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
 {
@@ -1338,6 +1383,9 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
 	case V4L2_TUNER_MODE_LANG2:
 		t = &ta8874z_sub;
 		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		t = &ta8874z_both;
+		break;
 	default:
 		update = 0;
 	}
@@ -1593,7 +1641,6 @@ static struct CHIPDESC chiplist[] = {
 		.addr_lo    = I2C_ADDR_TDA9840 >> 1,
 		.addr_hi    = I2C_ADDR_TDA9840 >> 1,
 		.registers  = 2,
-		.flags      = CHIP_NEED_CHECKMODE,
 
 		/* callbacks */
 		.getmode    = ta8874z_getmode,
@@ -1736,7 +1783,6 @@ static int tvaudio_s_radio(struct v4l2_subdev *sd)
 	struct CHIPSTATE *chip = to_state(sd);
 
 	chip->radio = 1;
-	chip->watch_stereo = 0;
 	/* del_timer(&chip->wt); */
 	return 0;
 }
@@ -1793,7 +1839,6 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 {
 	struct CHIPSTATE *chip = to_state(sd);
 	struct CHIPDESC *desc = chip->desc;
-	int mode = 0;
 
 	if (!desc->setmode)
 		return 0;
@@ -1805,22 +1850,18 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 	case V4L2_TUNER_MODE_STEREO:
 	case V4L2_TUNER_MODE_LANG1:
 	case V4L2_TUNER_MODE_LANG2:
-		mode = vt->audmode;
-		break;
 	case V4L2_TUNER_MODE_LANG1_LANG2:
-		mode = V4L2_TUNER_MODE_STEREO;
 		break;
 	default:
 		return -EINVAL;
 	}
 	chip->audmode = vt->audmode;
 
-	if (mode) {
-		chip->watch_stereo = 0;
-		/* del_timer(&chip->wt); */
-		chip->mode = mode;
-		desc->setmode(chip, mode);
-	}
+	if (chip->thread)
+		wake_up_process(chip->thread);
+	else
+		desc->setmode(chip, vt->audmode);
+
 	return 0;
 }
 
@@ -1828,7 +1869,6 @@ static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 {
 	struct CHIPSTATE *chip = to_state(sd);
 	struct CHIPDESC *desc = chip->desc;
-	int mode = V4L2_TUNER_MODE_MONO;
 
 	if (!desc->getmode)
 		return 0;
@@ -1836,22 +1876,10 @@ static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 		return 0;
 
 	vt->audmode = chip->audmode;
-	vt->rxsubchans = 0;
+	vt->rxsubchans = desc->getmode(chip);
 	vt->capability = V4L2_TUNER_CAP_STEREO |
 		V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
 
-	mode = desc->getmode(chip);
-
-	if (mode & V4L2_TUNER_MODE_MONO)
-		vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
-	if (mode & V4L2_TUNER_MODE_STEREO)
-		vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
-	/* Note: for SAP it should be mono/lang2 or stereo/lang2.
-	   When this module is converted fully to v4l2, then this
-	   should change for those chips that can detect SAP. */
-	if (mode & V4L2_TUNER_MODE_LANG1)
-		vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
-			V4L2_TUNER_SUB_LANG2;
 	return 0;
 }
 
@@ -1868,8 +1896,6 @@ static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fr
 	struct CHIPSTATE *chip = to_state(sd);
 	struct CHIPDESC *desc = chip->desc;
 
-	chip->mode = 0; /* automatic */
-
 	/* For chips that provide getmode and setmode, and doesn't
 	   automatically follows the stereo carrier, a kthread is
 	   created to set the audio standard. In this case, when then
@@ -1880,8 +1906,7 @@ static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fr
 	 */
 	if (chip->thread) {
 		desc->setmode(chip, V4L2_TUNER_MODE_MONO);
-		if (chip->prevmode != V4L2_TUNER_MODE_MONO)
-			chip->prevmode = -1; /* reset previous mode */
+		chip->prevmode = -1; /* reset previous mode */
 		mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
 	}
 	return 0;
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index af26bbe..f7061a5 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -2083,7 +2083,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 	/* Walk the entities list and instantiate controls */
 	list_for_each_entry(entity, &dev->entities, list) {
 		struct uvc_control *ctrl;
-		unsigned int bControlSize = 0, ncontrols = 0;
+		unsigned int bControlSize = 0, ncontrols;
 		__u8 *bmControls = NULL;
 
 		if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
@@ -2101,8 +2101,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 		uvc_ctrl_prune_entity(dev, entity);
 
 		/* Count supported controls and allocate the controls array */
-		for (i = 0; i < bControlSize; ++i)
-			ncontrols += hweight8(bmControls[i]);
+		ncontrols = memweight(bmControls, bControlSize);
 		if (ncontrols == 0)
 			continue;
 
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 5ccbd46..83dbb2d 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -656,7 +656,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
 	SET_VALID_IOCTL(ops, VIDIOC_TRY_ENCODER_CMD, vidioc_try_encoder_cmd);
 	SET_VALID_IOCTL(ops, VIDIOC_DECODER_CMD, vidioc_decoder_cmd);
 	SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd);
-	if (ops->vidioc_g_parm || vdev->current_norm)
+	if (ops->vidioc_g_parm || vdev->vfl_type == VFL_TYPE_GRABBER)
 		set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls);
 	SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm);
 	SET_VALID_IOCTL(ops, VIDIOC_G_TUNER, vidioc_g_tuner);
@@ -679,6 +679,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
 	SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset);
 	SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings);
 	SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings);
+	SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings);
+	SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings);
 	/* yes, really vidioc_subscribe_event */
 	SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
 	SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 91be4e8..d7fa896 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -1680,6 +1680,7 @@ static long __video_do_ioctl(struct file *file,
 				break;
 
 			ret = 0;
+			p->parm.capture.readbuffers = 2;
 			if (ops->vidioc_g_std)
 				ret = ops->vidioc_g_std(file, fh, &std);
 			if (ret == 0)
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index b6b5cc1..9b9a06f 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -40,7 +40,7 @@ struct videobuf_dma_contig_memory {
 
 static int __videobuf_dc_alloc(struct device *dev,
 			       struct videobuf_dma_contig_memory *mem,
-			       unsigned long size, unsigned long flags)
+			       unsigned long size, gfp_t flags)
 {
 	mem->size = size;
 	if (mem->cached) {
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 4d7391e..aae1720 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -2561,7 +2561,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
 	} else if (vino_drvdata->decoder
 		   && (vino_drvdata->decoder_owner == VINO_NO_CHANNEL)) {
 		int input;
-		int data_norm;
+		int data_norm = 0;
 		v4l2_std_id norm;
 
 		input = VINO_INPUT_COMPOSITE;
@@ -2651,7 +2651,7 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
 		}
 
 		if (vino_drvdata->decoder_owner == vcs->channel) {
-			int data_norm;
+			int data_norm = 0;
 			v4l2_std_id norm;
 
 			ret = decoder_call(video, s_routing,
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 0960d7f..08c1024 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -1149,10 +1149,14 @@ static ssize_t
 vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
 	struct vivi_dev *dev = video_drvdata(file);
+	int err;
 
 	dprintk(dev, 1, "read called\n");
-	return vb2_read(&dev->vb_vidq, data, count, ppos,
+	mutex_lock(&dev->mutex);
+	err = vb2_read(&dev->vb_vidq, data, count, ppos,
 		       file->f_flags & O_NONBLOCK);
+	mutex_unlock(&dev->mutex);
+	return err;
 }
 
 static unsigned int
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index e44cb33..9afab35 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -37,6 +37,10 @@
 #include <linux/highmem.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
 #include <media/videobuf-vmalloc.h>
 
 
@@ -120,11 +124,6 @@ static struct usb_device_id device_table[] = {
 
 MODULE_DEVICE_TABLE(usb, device_table);
 
-struct zr364xx_mode {
-	u32 color;	/* output video color format */
-	u32 brightness;	/* brightness */
-};
-
 /* frame structure */
 struct zr364xx_framei {
 	unsigned long ulState;	/* ulState:ZR364XX_READ_IDLE,
@@ -173,7 +172,10 @@ static const struct zr364xx_fmt formats[] = {
 struct zr364xx_camera {
 	struct usb_device *udev;	/* save off the usb device pointer */
 	struct usb_interface *interface;/* the interface for this device */
-	struct video_device *vdev;	/* v4l video device */
+	struct v4l2_device v4l2_dev;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct video_device vdev;	/* v4l video device */
+	struct v4l2_fh *owner;		/* owns the streaming */
 	int nb;
 	struct zr364xx_bufferi		buffer;
 	int skip;
@@ -181,12 +183,9 @@ struct zr364xx_camera {
 	int height;
 	int method;
 	struct mutex lock;
-	struct mutex open_lock;
-	int users;
 
 	spinlock_t		slock;
 	struct zr364xx_dmaqueue	vidq;
-	int			resources;
 	int			last_frame;
 	int			cur_frame;
 	unsigned long		frame_count;
@@ -197,8 +196,7 @@ struct zr364xx_camera {
 
 	const struct zr364xx_fmt *fmt;
 	struct videobuf_queue	vb_vidq;
-	enum v4l2_buf_type	type;
-	struct zr364xx_mode	mode;
+	bool was_streaming;
 };
 
 /* buffer for one video frame */
@@ -230,11 +228,6 @@ static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
 				 transfer_buffer, size, CTRL_TIMEOUT);
 
 	kfree(transfer_buffer);
-
-	if (status < 0)
-		dev_err(&udev->dev,
-			"Failed sending control message, error %d.\n", status);
-
 	return status;
 }
 
@@ -468,6 +461,7 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count,
 			    loff_t * ppos)
 {
 	struct zr364xx_camera *cam = video_drvdata(file);
+	int err = 0;
 
 	_DBG("%s\n", __func__);
 
@@ -477,17 +471,21 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count,
 	if (!count)
 		return -EINVAL;
 
-	if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-	    zr364xx_vidioc_streamon(file, cam, cam->type) == 0) {
-		DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count,
-		    (int) *ppos);
+	if (mutex_lock_interruptible(&cam->lock))
+		return -ERESTARTSYS;
+
+	err = zr364xx_vidioc_streamon(file, file->private_data,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	if (err == 0) {
+		DBG("%s: reading %d bytes at pos %d.\n", __func__,
+				(int) count, (int) *ppos);
 
 		/* NoMan Sux ! */
-		return videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
+		err = videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
 					file->f_flags & O_NONBLOCK);
 	}
-
-	return 0;
+	mutex_unlock(&cam->lock);
+	return err;
 }
 
 /* video buffer vmalloc implementation based partly on VIVI driver which is
@@ -702,35 +700,6 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
 	return 0;
 }
 
-static int res_get(struct zr364xx_camera *cam)
-{
-	/* is it free? */
-	mutex_lock(&cam->lock);
-	if (cam->resources) {
-		/* no, someone else uses it */
-		mutex_unlock(&cam->lock);
-		return 0;
-	}
-	/* it's free, grab it */
-	cam->resources = 1;
-	_DBG("res: get\n");
-	mutex_unlock(&cam->lock);
-	return 1;
-}
-
-static inline int res_check(struct zr364xx_camera *cam)
-{
-	return cam->resources;
-}
-
-static void res_free(struct zr364xx_camera *cam)
-{
-	mutex_lock(&cam->lock);
-	cam->resources = 0;
-	mutex_unlock(&cam->lock);
-	_DBG("res: put\n");
-}
-
 static int zr364xx_vidioc_querycap(struct file *file, void *priv,
 				   struct v4l2_capability *cap)
 {
@@ -740,9 +709,10 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv,
 	strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
 	strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
 		sizeof(cap->bus_info));
-	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
 			    V4L2_CAP_READWRITE |
 			    V4L2_CAP_STREAMING;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 
 	return 0;
 }
@@ -772,50 +742,18 @@ static int zr364xx_vidioc_s_input(struct file *file, void *priv,
 	return 0;
 }
 
-static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
-				    struct v4l2_queryctrl *c)
+static int zr364xx_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct zr364xx_camera *cam;
-
-	if (file == NULL)
-		return -ENODEV;
-	cam = video_drvdata(file);
-
-	switch (c->id) {
-	case V4L2_CID_BRIGHTNESS:
-		c->type = V4L2_CTRL_TYPE_INTEGER;
-		strcpy(c->name, "Brightness");
-		c->minimum = 0;
-		c->maximum = 127;
-		c->step = 1;
-		c->default_value = cam->mode.brightness;
-		c->flags = 0;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
-				 struct v4l2_control *c)
-{
-	struct zr364xx_camera *cam;
+	struct zr364xx_camera *cam =
+		container_of(ctrl->handler, struct zr364xx_camera, ctrl_handler);
 	int temp;
 
-	if (file == NULL)
-		return -ENODEV;
-	cam = video_drvdata(file);
-
-	switch (c->id) {
+	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		cam->mode.brightness = c->value;
 		/* hardware brightness */
-		mutex_lock(&cam->lock);
 		send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
-		temp = (0x60 << 8) + 127 - cam->mode.brightness;
+		temp = (0x60 << 8) + 127 - ctrl->val;
 		send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
-		mutex_unlock(&cam->lock);
 		break;
 	default:
 		return -EINVAL;
@@ -824,25 +762,6 @@ static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
 	return 0;
 }
 
-static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
-				 struct v4l2_control *c)
-{
-	struct zr364xx_camera *cam;
-
-	if (file == NULL)
-		return -ENODEV;
-	cam = video_drvdata(file);
-
-	switch (c->id) {
-	case V4L2_CID_BRIGHTNESS:
-		c->value = cam->mode.brightness;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
 static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
 				       void *priv, struct v4l2_fmtdesc *f)
 {
@@ -888,7 +807,7 @@ static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 	f->fmt.pix.field = V4L2_FIELD_NONE;
 	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
-	f->fmt.pix.colorspace = 0;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
 	f->fmt.pix.priv = 0;
 	DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
 	    decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
@@ -911,7 +830,7 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 	f->fmt.pix.height = cam->height;
 	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
-	f->fmt.pix.colorspace = 0;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
 	f->fmt.pix.priv = 0;
 	return 0;
 }
@@ -936,7 +855,7 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 		goto out;
 	}
 
-	if (res_check(cam)) {
+	if (cam->owner) {
 		DBG("%s can't change format after started\n", __func__);
 		ret = -EBUSY;
 		goto out;
@@ -944,14 +863,13 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 
 	cam->width = f->fmt.pix.width;
 	cam->height = f->fmt.pix.height;
-	dev_info(&cam->udev->dev, "%s: %dx%d mode selected\n", __func__,
+	DBG("%s: %dx%d mode selected\n", __func__,
 		 cam->width, cam->height);
 	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
-	f->fmt.pix.colorspace = 0;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
 	f->fmt.pix.priv = 0;
 	cam->vb_vidq.field = f->fmt.pix.field;
-	cam->mode.color = V4L2_PIX_FMT_JPEG;
 
 	if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120)
 		mode = 1;
@@ -1015,10 +933,11 @@ out:
 static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
 			  struct v4l2_requestbuffers *p)
 {
-	int rc;
 	struct zr364xx_camera *cam = video_drvdata(file);
-	rc = videobuf_reqbufs(&cam->vb_vidq, p);
-	return rc;
+
+	if (cam->owner && cam->owner != priv)
+		return -EBUSY;
+	return videobuf_reqbufs(&cam->vb_vidq, p);
 }
 
 static int zr364xx_vidioc_querybuf(struct file *file,
@@ -1038,6 +957,8 @@ static int zr364xx_vidioc_qbuf(struct file *file,
 	int rc;
 	struct zr364xx_camera *cam = video_drvdata(file);
 	_DBG("%s\n", __func__);
+	if (cam->owner && cam->owner != priv)
+		return -EBUSY;
 	rc = videobuf_qbuf(&cam->vb_vidq, p);
 	return rc;
 }
@@ -1049,6 +970,8 @@ static int zr364xx_vidioc_dqbuf(struct file *file,
 	int rc;
 	struct zr364xx_camera *cam = video_drvdata(file);
 	_DBG("%s\n", __func__);
+	if (cam->owner && cam->owner != priv)
+		return -EBUSY;
 	rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
 	return rc;
 }
@@ -1197,29 +1120,23 @@ static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
 	return 0;
 }
 
-static int zr364xx_vidioc_streamon(struct file *file, void *priv,
-				   enum v4l2_buf_type type)
+static int zr364xx_prepare(struct zr364xx_camera *cam)
 {
-	struct zr364xx_camera *cam = video_drvdata(file);
-	int j;
 	int res;
+	int i, j;
 
-	DBG("%s\n", __func__);
-
-	if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		dev_err(&cam->udev->dev, "invalid fh type0\n");
-		return -EINVAL;
-	}
-	if (cam->type != type) {
-		dev_err(&cam->udev->dev, "invalid fh type1\n");
-		return -EINVAL;
-	}
-
-	if (!res_get(cam)) {
-		dev_err(&cam->udev->dev, "stream busy\n");
-		return -EBUSY;
+	for (i = 0; init[cam->method][i].size != -1; i++) {
+		res = send_control_msg(cam->udev, 1, init[cam->method][i].value,
+				     0, init[cam->method][i].bytes,
+				     init[cam->method][i].size);
+		if (res < 0) {
+			dev_err(&cam->udev->dev,
+				"error during open sequence: %d\n", i);
+			return res;
+		}
 	}
 
+	cam->skip = 2;
 	cam->last_frame = -1;
 	cam->cur_frame = 0;
 	cam->frame_count = 0;
@@ -1227,11 +1144,31 @@ static int zr364xx_vidioc_streamon(struct file *file, void *priv,
 		cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
 		cam->buffer.frame[j].cur_size = 0;
 	}
+	v4l2_ctrl_handler_setup(&cam->ctrl_handler);
+	return 0;
+}
+
+static int zr364xx_vidioc_streamon(struct file *file, void *priv,
+				   enum v4l2_buf_type type)
+{
+	struct zr364xx_camera *cam = video_drvdata(file);
+	int res;
+
+	DBG("%s\n", __func__);
+
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (cam->owner && cam->owner != priv)
+		return -EBUSY;
+
+	res = zr364xx_prepare(cam);
+	if (res)
+		return res;
 	res = videobuf_streamon(&cam->vb_vidq);
 	if (res == 0) {
 		zr364xx_start_acquire(cam);
-	} else {
-		res_free(cam);
+		cam->owner = file->private_data;
 	}
 	return res;
 }
@@ -1239,67 +1176,32 @@ static int zr364xx_vidioc_streamon(struct file *file, void *priv,
 static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
 				    enum v4l2_buf_type type)
 {
-	int res;
 	struct zr364xx_camera *cam = video_drvdata(file);
 
 	DBG("%s\n", __func__);
-	if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		dev_err(&cam->udev->dev, "invalid fh type0\n");
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
-	}
-	if (cam->type != type) {
-		dev_err(&cam->udev->dev, "invalid fh type1\n");
-		return -EINVAL;
-	}
+	if (cam->owner && cam->owner != priv)
+		return -EBUSY;
 	zr364xx_stop_acquire(cam);
-	res = videobuf_streamoff(&cam->vb_vidq);
-	if (res < 0)
-		return res;
-	res_free(cam);
-	return 0;
+	return videobuf_streamoff(&cam->vb_vidq);
 }
 
 
 /* open the camera */
 static int zr364xx_open(struct file *file)
 {
-	struct video_device *vdev = video_devdata(file);
 	struct zr364xx_camera *cam = video_drvdata(file);
-	struct usb_device *udev = cam->udev;
-	int i, err;
+	int err;
 
 	DBG("%s\n", __func__);
 
-	mutex_lock(&cam->open_lock);
+	if (mutex_lock_interruptible(&cam->lock))
+		return -ERESTARTSYS;
 
-	if (cam->users) {
-		err = -EBUSY;
+	err = v4l2_fh_open(file);
+	if (err)
 		goto out;
-	}
-
-	for (i = 0; init[cam->method][i].size != -1; i++) {
-		err =
-		    send_control_msg(udev, 1, init[cam->method][i].value,
-				     0, init[cam->method][i].bytes,
-				     init[cam->method][i].size);
-		if (err < 0) {
-			dev_err(&cam->udev->dev,
-				"error during open sequence: %d\n", i);
-			goto out;
-		}
-	}
-
-	cam->skip = 2;
-	cam->users++;
-	file->private_data = vdev;
-	cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	cam->fmt = formats;
-
-	videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
-				    NULL, &cam->slock,
-				    cam->type,
-				    V4L2_FIELD_NONE,
-				    sizeof(struct zr364xx_buffer), cam, NULL);
 
 	/* Added some delay here, since opening/closing the camera quickly,
 	 * like Ekiga does during its startup, can crash the webcam
@@ -1308,29 +1210,20 @@ static int zr364xx_open(struct file *file)
 	err = 0;
 
 out:
-	mutex_unlock(&cam->open_lock);
+	mutex_unlock(&cam->lock);
 	DBG("%s: %d\n", __func__, err);
 	return err;
 }
 
-static void zr364xx_destroy(struct zr364xx_camera *cam)
+static void zr364xx_release(struct v4l2_device *v4l2_dev)
 {
+	struct zr364xx_camera *cam =
+		container_of(v4l2_dev, struct zr364xx_camera, v4l2_dev);
 	unsigned long i;
 
-	if (!cam) {
-		printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__);
-		return;
-	}
-	mutex_lock(&cam->open_lock);
-	if (cam->vdev)
-		video_unregister_device(cam->vdev);
-	cam->vdev = NULL;
-
-	/* stops the read pipe if it is running */
-	if (cam->b_acquire)
-		zr364xx_stop_acquire(cam);
+	v4l2_device_unregister(&cam->v4l2_dev);
 
-	zr364xx_stop_readpipe(cam);
+	videobuf_mmap_free(&cam->vb_vidq);
 
 	/* release sys buffers */
 	for (i = 0; i < FRAMES; i++) {
@@ -1341,62 +1234,45 @@ static void zr364xx_destroy(struct zr364xx_camera *cam)
 		cam->buffer.frame[i].lpvbits = NULL;
 	}
 
+	v4l2_ctrl_handler_free(&cam->ctrl_handler);
 	/* release transfer buffer */
 	kfree(cam->pipe->transfer_buffer);
-	cam->pipe->transfer_buffer = NULL;
-	mutex_unlock(&cam->open_lock);
 	kfree(cam);
-	cam = NULL;
 }
 
 /* release the camera */
-static int zr364xx_release(struct file *file)
+static int zr364xx_close(struct file *file)
 {
 	struct zr364xx_camera *cam;
 	struct usb_device *udev;
-	int i, err;
+	int i;
 
 	DBG("%s\n", __func__);
 	cam = video_drvdata(file);
 
-	if (!cam)
-		return -ENODEV;
-
-	mutex_lock(&cam->open_lock);
+	mutex_lock(&cam->lock);
 	udev = cam->udev;
 
-	/* turn off stream */
-	if (res_check(cam)) {
+	if (file->private_data == cam->owner) {
+		/* turn off stream */
 		if (cam->b_acquire)
 			zr364xx_stop_acquire(cam);
 		videobuf_streamoff(&cam->vb_vidq);
-		res_free(cam);
-	}
-
-	cam->users--;
-	file->private_data = NULL;
 
-	for (i = 0; i < 2; i++) {
-		err =
-		    send_control_msg(udev, 1, init[cam->method][i].value,
-				     0, init[cam->method][i].bytes,
-				     init[cam->method][i].size);
-		if (err < 0) {
-			dev_err(&udev->dev, "error during release sequence\n");
-			goto out;
+		for (i = 0; i < 2; i++) {
+			send_control_msg(udev, 1, init[cam->method][i].value,
+					0, init[cam->method][i].bytes,
+					init[cam->method][i].size);
 		}
+		cam->owner = NULL;
 	}
 
 	/* Added some delay here, since opening/closing the camera quickly,
 	 * like Ekiga does during its startup, can crash the webcam
 	 */
 	mdelay(100);
-	err = 0;
-
-out:
-	mutex_unlock(&cam->open_lock);
-
-	return err;
+	mutex_unlock(&cam->lock);
+	return v4l2_fh_release(file);
 }
 
 
@@ -1424,21 +1300,24 @@ static unsigned int zr364xx_poll(struct file *file,
 {
 	struct zr364xx_camera *cam = video_drvdata(file);
 	struct videobuf_queue *q = &cam->vb_vidq;
-	_DBG("%s\n", __func__);
+	unsigned res = v4l2_ctrl_poll(file, wait);
 
-	if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return POLLERR;
+	_DBG("%s\n", __func__);
 
-	return videobuf_poll_stream(file, q, wait);
+	return res | videobuf_poll_stream(file, q, wait);
 }
 
+static const struct v4l2_ctrl_ops zr364xx_ctrl_ops = {
+	.s_ctrl = zr364xx_s_ctrl,
+};
+
 static const struct v4l2_file_operations zr364xx_fops = {
 	.owner = THIS_MODULE,
 	.open = zr364xx_open,
-	.release = zr364xx_release,
+	.release = zr364xx_close,
 	.read = zr364xx_read,
 	.mmap = zr364xx_mmap,
-	.ioctl = video_ioctl2,
+	.unlocked_ioctl = video_ioctl2,
 	.poll = zr364xx_poll,
 };
 
@@ -1453,20 +1332,20 @@ static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
 	.vidioc_s_input		= zr364xx_vidioc_s_input,
 	.vidioc_streamon	= zr364xx_vidioc_streamon,
 	.vidioc_streamoff	= zr364xx_vidioc_streamoff,
-	.vidioc_queryctrl	= zr364xx_vidioc_queryctrl,
-	.vidioc_g_ctrl		= zr364xx_vidioc_g_ctrl,
-	.vidioc_s_ctrl		= zr364xx_vidioc_s_ctrl,
 	.vidioc_reqbufs         = zr364xx_vidioc_reqbufs,
 	.vidioc_querybuf        = zr364xx_vidioc_querybuf,
 	.vidioc_qbuf            = zr364xx_vidioc_qbuf,
 	.vidioc_dqbuf           = zr364xx_vidioc_dqbuf,
+	.vidioc_log_status      = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 static struct video_device zr364xx_template = {
 	.name = DRIVER_DESC,
 	.fops = &zr364xx_fops,
 	.ioctl_ops = &zr364xx_ioctl_ops,
-	.release = video_device_release,
+	.release = video_device_release_empty,
 };
 
 
@@ -1540,6 +1419,7 @@ static int zr364xx_probe(struct usb_interface *intf,
 	struct zr364xx_camera *cam = NULL;
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
+	struct v4l2_ctrl_handler *hdl;
 	int err;
 	int i;
 
@@ -1555,21 +1435,34 @@ static int zr364xx_probe(struct usb_interface *intf,
 		dev_err(&udev->dev, "cam: out of memory !\n");
 		return -ENOMEM;
 	}
-	/* save the init method used by this camera */
-	cam->method = id->driver_info;
 
-	cam->vdev = video_device_alloc();
-	if (cam->vdev == NULL) {
-		dev_err(&udev->dev, "cam->vdev: out of memory !\n");
+	cam->v4l2_dev.release = zr364xx_release;
+	err = v4l2_device_register(&intf->dev, &cam->v4l2_dev);
+	if (err < 0) {
+		dev_err(&udev->dev, "couldn't register v4l2_device\n");
 		kfree(cam);
-		cam = NULL;
-		return -ENOMEM;
+		return err;
 	}
-	memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
-	cam->vdev->parent = &intf->dev;
-	video_set_drvdata(cam->vdev, cam);
+	hdl = &cam->ctrl_handler;
+	v4l2_ctrl_handler_init(hdl, 1);
+	v4l2_ctrl_new_std(hdl, &zr364xx_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, 0, 127, 1, 64);
+	if (hdl->error) {
+		err = hdl->error;
+		dev_err(&udev->dev, "couldn't register control\n");
+		goto fail;
+	}
+	/* save the init method used by this camera */
+	cam->method = id->driver_info;
+	mutex_init(&cam->lock);
+	cam->vdev = zr364xx_template;
+	cam->vdev.lock = &cam->lock;
+	cam->vdev.v4l2_dev = &cam->v4l2_dev;
+	cam->vdev.ctrl_handler = &cam->ctrl_handler;
+	set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
+	video_set_drvdata(&cam->vdev, cam);
 	if (debug)
-		cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+		cam->vdev.debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
 
 	cam->udev = udev;
 
@@ -1615,11 +1508,7 @@ static int zr364xx_probe(struct usb_interface *intf,
 	header2[439] = cam->width / 256;
 	header2[440] = cam->width % 256;
 
-	cam->users = 0;
 	cam->nb = 0;
-	cam->mode.brightness = 64;
-	mutex_init(&cam->lock);
-	mutex_init(&cam->open_lock);
 
 	DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
 
@@ -1635,52 +1524,100 @@ static int zr364xx_probe(struct usb_interface *intf,
 	}
 
 	if (!cam->read_endpoint) {
+		err = -ENOMEM;
 		dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
-		video_device_release(cam->vdev);
-		kfree(cam);
-		cam = NULL;
-		return -ENOMEM;
+		goto fail;
 	}
 
 	/* v4l */
 	INIT_LIST_HEAD(&cam->vidq.active);
 	cam->vidq.cam = cam;
-	err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
-	if (err) {
-		dev_err(&udev->dev, "video_register_device failed\n");
-		video_device_release(cam->vdev);
-		kfree(cam);
-		cam = NULL;
-		return err;
-	}
 
 	usb_set_intfdata(intf, cam);
 
 	/* load zr364xx board specific */
 	err = zr364xx_board_init(cam);
-	if (err) {
-		spin_lock_init(&cam->slock);
-		return err;
-	}
+	if (!err)
+		err = v4l2_ctrl_handler_setup(hdl);
+	if (err)
+		goto fail;
 
 	spin_lock_init(&cam->slock);
 
+	cam->fmt = formats;
+
+	videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
+				    NULL, &cam->slock,
+				    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+				    V4L2_FIELD_NONE,
+				    sizeof(struct zr364xx_buffer), cam, &cam->lock);
+
+	err = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+	if (err) {
+		dev_err(&udev->dev, "video_register_device failed\n");
+		goto fail;
+	}
+
 	dev_info(&udev->dev, DRIVER_DESC " controlling device %s\n",
-		 video_device_node_name(cam->vdev));
+		 video_device_node_name(&cam->vdev));
 	return 0;
+
+fail:
+	v4l2_ctrl_handler_free(hdl);
+	v4l2_device_unregister(&cam->v4l2_dev);
+	kfree(cam);
+	return err;
 }
 
 
 static void zr364xx_disconnect(struct usb_interface *intf)
 {
 	struct zr364xx_camera *cam = usb_get_intfdata(intf);
-	videobuf_mmap_free(&cam->vb_vidq);
+
+	mutex_lock(&cam->lock);
 	usb_set_intfdata(intf, NULL);
 	dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
-	zr364xx_destroy(cam);
+	video_unregister_device(&cam->vdev);
+	v4l2_device_disconnect(&cam->v4l2_dev);
+
+	/* stops the read pipe if it is running */
+	if (cam->b_acquire)
+		zr364xx_stop_acquire(cam);
+
+	zr364xx_stop_readpipe(cam);
+	mutex_unlock(&cam->lock);
+	v4l2_device_put(&cam->v4l2_dev);
 }
 
 
+#ifdef CONFIG_PM
+static int zr364xx_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct zr364xx_camera *cam = usb_get_intfdata(intf);
+
+	cam->was_streaming = cam->b_acquire;
+	if (!cam->was_streaming)
+		return 0;
+	zr364xx_stop_acquire(cam);
+	zr364xx_stop_readpipe(cam);
+	return 0;
+}
+
+static int zr364xx_resume(struct usb_interface *intf)
+{
+	struct zr364xx_camera *cam = usb_get_intfdata(intf);
+	int res;
+
+	if (!cam->was_streaming)
+		return 0;
+
+	zr364xx_start_readpipe(cam);
+	res = zr364xx_prepare(cam);
+	if (!res)
+		zr364xx_start_acquire(cam);
+	return res;
+}
+#endif
 
 /**********************/
 /* Module integration */
@@ -1690,6 +1627,11 @@ static struct usb_driver zr364xx_driver = {
 	.name = "zr364xx",
 	.probe = zr364xx_probe,
 	.disconnect = zr364xx_disconnect,
+#ifdef CONFIG_PM
+	.suspend = zr364xx_suspend,
+	.resume = zr364xx_resume,
+	.reset_resume = zr364xx_resume,
+#endif
 	.id_table = device_table
 };
 
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index e129c82..a7d0c85 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -422,6 +422,19 @@ config PMIC_ADP5520
 	  individual components like LCD backlight, LEDs, GPIOs and Kepad
 	  under the corresponding menus.
 
+config MFD_MAX77686
+	bool "Maxim Semiconductor MAX77686 PMIC Support"
+	depends on I2C=y && GENERIC_HARDIRQS
+	select MFD_CORE
+	select REGMAP_I2C
+	select IRQ_DOMAIN
+	help
+	  Say yes here to support for Maxim Semiconductor MAX77686.
+	  This is a Power Management IC with RTC on chip.
+	  This driver provides common support for accessing the device;
+	  additional drivers must be enabled in order to use the functionality
+	  of the device.
+
 config MFD_MAX77693
 	bool "Maxim Semiconductor MAX77693 PMIC Support"
 	depends on I2C=y && GENERIC_HARDIRQS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 75f6ed6..8ee7a3b 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_PMIC_DA9052)	+= da9052-core.o
 obj-$(CONFIG_MFD_DA9052_SPI)	+= da9052-spi.o
 obj-$(CONFIG_MFD_DA9052_I2C)	+= da9052-i2c.o
 
+obj-$(CONFIG_MFD_MAX77686)	+= max77686.o max77686-irq.o
 obj-$(CONFIG_MFD_MAX77693)	+= max77693.o max77693-irq.o
 max8925-objs			:= max8925-core.o max8925-i2c.o
 obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
diff --git a/drivers/mfd/max77686-irq.c b/drivers/mfd/max77686-irq.c
new file mode 100644
index 0000000..fc10122
--- /dev/null
+++ b/drivers/mfd/max77686-irq.c
@@ -0,0 +1,309 @@
+/*
+ * max77686-irq.c - Interrupt controller support for MAX77686
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * Chiwoong Byun <woong.byun@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8997-irq.c
+ */
+
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/mfd/max77686.h>
+#include <linux/mfd/max77686-private.h>
+#include <linux/irqdomain.h>
+#include <linux/regmap.h>
+
+enum {
+	MAX77686_DEBUG_IRQ_INFO = 1 << 0,
+	MAX77686_DEBUG_IRQ_MASK = 1 << 1,
+	MAX77686_DEBUG_IRQ_INT = 1 << 2,
+};
+
+static int debug_mask = 0;
+module_param(debug_mask, int, 0);
+MODULE_PARM_DESC(debug_mask, "Set debug_mask : 0x0=off 0x1=IRQ_INFO  0x2=IRQ_MASK 0x4=IRQ_INI)");
+
+static const u8 max77686_mask_reg[] = {
+	[PMIC_INT1] = MAX77686_REG_INT1MSK,
+	[PMIC_INT2] = MAX77686_REG_INT2MSK,
+	[RTC_INT] = MAX77686_RTC_INTM,
+};
+
+static struct regmap *max77686_get_regmap(struct max77686_dev *max77686,
+				enum max77686_irq_source src)
+{
+	switch (src) {
+	case PMIC_INT1 ... PMIC_INT2:
+		return max77686->regmap;
+	case RTC_INT:
+		return max77686->rtc_regmap;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
+struct max77686_irq_data {
+	int mask;
+	enum max77686_irq_source group;
+};
+
+#define DECLARE_IRQ(idx, _group, _mask)		\
+	[(idx)] = { .group = (_group), .mask = (_mask) }
+static const struct max77686_irq_data max77686_irqs[] = {
+	DECLARE_IRQ(MAX77686_PMICIRQ_PWRONF,	PMIC_INT1, 1 << 0),
+	DECLARE_IRQ(MAX77686_PMICIRQ_PWRONR,	PMIC_INT1, 1 << 1),
+	DECLARE_IRQ(MAX77686_PMICIRQ_JIGONBF,	PMIC_INT1, 1 << 2),
+	DECLARE_IRQ(MAX77686_PMICIRQ_JIGONBR,	PMIC_INT1, 1 << 3),
+	DECLARE_IRQ(MAX77686_PMICIRQ_ACOKBF,	PMIC_INT1, 1 << 4),
+	DECLARE_IRQ(MAX77686_PMICIRQ_ACOKBR,	PMIC_INT1, 1 << 5),
+	DECLARE_IRQ(MAX77686_PMICIRQ_ONKEY1S,	PMIC_INT1, 1 << 6),
+	DECLARE_IRQ(MAX77686_PMICIRQ_MRSTB,		PMIC_INT1, 1 << 7),
+	DECLARE_IRQ(MAX77686_PMICIRQ_140C,		PMIC_INT2, 1 << 0),
+	DECLARE_IRQ(MAX77686_PMICIRQ_120C,		PMIC_INT2, 1 << 1),
+	DECLARE_IRQ(MAX77686_RTCIRQ_RTC60S,		RTC_INT, 1 << 0),
+	DECLARE_IRQ(MAX77686_RTCIRQ_RTCA1,		RTC_INT, 1 << 1),
+	DECLARE_IRQ(MAX77686_RTCIRQ_RTCA2,		RTC_INT, 1 << 2),
+	DECLARE_IRQ(MAX77686_RTCIRQ_SMPL,		RTC_INT, 1 << 3),
+	DECLARE_IRQ(MAX77686_RTCIRQ_RTC1S,		RTC_INT, 1 << 4),
+	DECLARE_IRQ(MAX77686_RTCIRQ_WTSR,		RTC_INT, 1 << 5),
+};
+
+static void max77686_irq_lock(struct irq_data *data)
+{
+	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
+
+	if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
+		pr_info("%s\n", __func__);
+
+	mutex_lock(&max77686->irqlock);
+}
+
+static void max77686_irq_sync_unlock(struct irq_data *data)
+{
+	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
+	int i;
+
+	for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++) {
+		u8 mask_reg = max77686_mask_reg[i];
+		struct regmap *map = max77686_get_regmap(max77686, i);
+
+		if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
+			pr_debug("%s: mask_reg[%d]=0x%x, cur=0x%x\n",
+			__func__, i, mask_reg, max77686->irq_masks_cur[i]);
+
+		if (mask_reg == MAX77686_REG_INVALID ||
+				IS_ERR_OR_NULL(map))
+			continue;
+
+		max77686->irq_masks_cache[i] = max77686->irq_masks_cur[i];
+
+		regmap_write(map, max77686_mask_reg[i],
+				max77686->irq_masks_cur[i]);
+	}
+
+	mutex_unlock(&max77686->irqlock);
+}
+
+static const inline struct max77686_irq_data *to_max77686_irq(int irq)
+{
+	struct irq_data *data = irq_get_irq_data(irq);
+	return &max77686_irqs[data->hwirq];
+}
+
+static void max77686_irq_mask(struct irq_data *data)
+{
+	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
+	const struct max77686_irq_data *irq_data = to_max77686_irq(data->irq);
+
+	max77686->irq_masks_cur[irq_data->group] |= irq_data->mask;
+
+	if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
+		pr_info("%s: group=%d, cur=0x%x\n",
+			__func__, irq_data->group,
+			max77686->irq_masks_cur[irq_data->group]);
+}
+
+static void max77686_irq_unmask(struct irq_data *data)
+{
+	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
+	const struct max77686_irq_data *irq_data = to_max77686_irq(data->irq);
+
+	max77686->irq_masks_cur[irq_data->group] &= ~irq_data->mask;
+
+	if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
+		pr_info("%s: group=%d, cur=0x%x\n",
+			__func__, irq_data->group,
+			max77686->irq_masks_cur[irq_data->group]);
+}
+
+static struct irq_chip max77686_irq_chip = {
+	.name			= "max77686",
+	.irq_bus_lock		= max77686_irq_lock,
+	.irq_bus_sync_unlock	= max77686_irq_sync_unlock,
+	.irq_mask		= max77686_irq_mask,
+	.irq_unmask		= max77686_irq_unmask,
+};
+
+static irqreturn_t max77686_irq_thread(int irq, void *data)
+{
+	struct max77686_dev *max77686 = data;
+	unsigned int irq_reg[MAX77686_IRQ_GROUP_NR] = {};
+	unsigned int irq_src;
+	int ret;
+	int i, cur_irq;
+
+	ret = regmap_read(max77686->regmap,  MAX77686_REG_INTSRC, &irq_src);
+	if (ret < 0) {
+		dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
+				ret);
+		return IRQ_NONE;
+	}
+
+	if (debug_mask & MAX77686_DEBUG_IRQ_INT)
+		pr_info("%s: irq_src=0x%x\n", __func__, irq_src);
+
+	if (irq_src == MAX77686_IRQSRC_PMIC) {
+		ret = regmap_bulk_read(max77686->rtc_regmap,
+					 MAX77686_REG_INT1, irq_reg, 2);
+		if (ret < 0) {
+			dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
+					ret);
+			return IRQ_NONE;
+		}
+
+		if (debug_mask & MAX77686_DEBUG_IRQ_INT)
+			pr_info("%s: int1=0x%x, int2=0x%x\n", __func__,
+				 irq_reg[PMIC_INT1], irq_reg[PMIC_INT2]);
+	}
+
+	if (irq_src & MAX77686_IRQSRC_RTC) {
+		ret = regmap_read(max77686->rtc_regmap,
+					MAX77686_RTC_INT, &irq_reg[RTC_INT]);
+		if (ret < 0) {
+			dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
+					ret);
+			return IRQ_NONE;
+		}
+
+		if (debug_mask & MAX77686_DEBUG_IRQ_INT)
+			pr_info("%s: rtc int=0x%x\n", __func__,
+							 irq_reg[RTC_INT]);
+
+	}
+
+	for (i = 0; i < MAX77686_IRQ_NR; i++) {
+		if (irq_reg[max77686_irqs[i].group] & max77686_irqs[i].mask) {
+			cur_irq = irq_find_mapping(max77686->irq_domain, i);
+			if (cur_irq)
+				handle_nested_irq(cur_irq);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int max77686_irq_domain_map(struct irq_domain *d, unsigned int irq,
+					irq_hw_number_t hw)
+{
+	struct max77686_dev *max77686 = d->host_data;
+
+	irq_set_chip_data(irq, max77686);
+	irq_set_chip_and_handler(irq, &max77686_irq_chip, handle_edge_irq);
+	irq_set_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+	set_irq_flags(irq, IRQF_VALID);
+#else
+	irq_set_noprobe(irq);
+#endif
+	return 0;
+}
+
+static struct irq_domain_ops max77686_irq_domain_ops = {
+	.map = max77686_irq_domain_map,
+};
+
+int max77686_irq_init(struct max77686_dev *max77686)
+{
+	struct irq_domain *domain;
+	int i;
+	int ret;
+	int val;
+	struct regmap *map;
+
+	mutex_init(&max77686->irqlock);
+
+	max77686->irq = gpio_to_irq(max77686->irq_gpio);
+
+	if (debug_mask & MAX77686_DEBUG_IRQ_INT) {
+		ret = gpio_request(max77686->irq_gpio, "pmic_irq");
+		if (ret < 0) {
+			dev_err(max77686->dev,
+				"Failed to request gpio %d with ret: %d\n",
+				max77686->irq_gpio, ret);
+			return IRQ_NONE;
+		}
+
+		gpio_direction_input(max77686->irq_gpio);
+		val = gpio_get_value(max77686->irq_gpio);
+		gpio_free(max77686->irq_gpio);
+		pr_info("%s: gpio_irq=%x\n", __func__, val);
+	}
+
+	/* Mask individual interrupt sources */
+	for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++) {
+		max77686->irq_masks_cur[i] = 0xff;
+		max77686->irq_masks_cache[i] = 0xff;
+		map = max77686_get_regmap(max77686, i);
+
+		if (IS_ERR_OR_NULL(map))
+			continue;
+		if (max77686_mask_reg[i] == MAX77686_REG_INVALID)
+			continue;
+
+		regmap_write(map, max77686_mask_reg[i], 0xff);
+	}
+	domain = irq_domain_add_linear(NULL, MAX77686_IRQ_NR,
+					&max77686_irq_domain_ops, max77686);
+	if (!domain) {
+		dev_err(max77686->dev, "could not create irq domain\n");
+		return -ENODEV;
+	}
+	max77686->irq_domain = domain;
+
+	ret = request_threaded_irq(max77686->irq, NULL, max77686_irq_thread,
+				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				   "max77686-irq", max77686);
+
+	if (ret)
+		dev_err(max77686->dev, "Failed to request IRQ %d: %d\n",
+			max77686->irq, ret);
+
+
+	if (debug_mask & MAX77686_DEBUG_IRQ_INFO)
+		pr_info("%s-\n", __func__);
+
+	return 0;
+}
+
+void max77686_irq_exit(struct max77686_dev *max77686)
+{
+	if (max77686->irq)
+		free_irq(max77686->irq, max77686);
+}
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c
new file mode 100644
index 0000000..11e5601
--- /dev/null
+++ b/drivers/mfd/max77686.c
@@ -0,0 +1,156 @@
+/*
+ * max77686.c - mfd core driver for the Maxim 77686
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Chiwoong Byun <woong.byun@smasung.com>
+ * Jonghwa Lee <jonghwa3.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8997.c
+ */
+
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max77686.h>
+#include <linux/mfd/max77686-private.h>
+#include <linux/err.h>
+
+#define I2C_ADDR_RTC	(0x0C >> 1)
+
+static struct mfd_cell max77686_devs[] = {
+	{ .name = "max77686-pmic", },
+	{ .name = "max77686-rtc", },
+};
+
+static struct regmap_config max77686_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int max77686_i2c_probe(struct i2c_client *i2c,
+			      const struct i2c_device_id *id)
+{
+	struct max77686_dev *max77686;
+	struct max77686_platform_data *pdata = i2c->dev.platform_data;
+	unsigned int data;
+	int ret = 0;
+
+	max77686 = kzalloc(sizeof(struct max77686_dev), GFP_KERNEL);
+	if (max77686 == NULL)
+		return -ENOMEM;
+
+	max77686->regmap = regmap_init_i2c(i2c, &max77686_regmap_config);
+	if (IS_ERR(max77686->regmap)) {
+		ret = PTR_ERR(max77686->regmap);
+		dev_err(max77686->dev, "Failed to allocate register map: %d\n",
+				ret);
+		kfree(max77686);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, max77686);
+	max77686->dev = &i2c->dev;
+	max77686->i2c = i2c;
+	max77686->type = id->driver_data;
+
+	if (!pdata) {
+		ret = -EIO;
+		goto err;
+	}
+
+	max77686->wakeup = pdata->wakeup;
+	max77686->irq_gpio = pdata->irq_gpio;
+
+	mutex_init(&max77686->iolock);
+
+	if (regmap_read(max77686->regmap,
+			 MAX77686_REG_DEVICE_ID, &data) < 0) {
+		dev_err(max77686->dev,
+			"device not found on this channel (this is not an error)\n");
+		ret = -ENODEV;
+		goto err;
+	} else
+		dev_info(max77686->dev, "device found\n");
+
+	max77686->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
+	i2c_set_clientdata(max77686->rtc, max77686);
+
+	max77686_irq_init(max77686);
+
+	ret = mfd_add_devices(max77686->dev, -1, max77686_devs,
+			      ARRAY_SIZE(max77686_devs), NULL, 0);
+
+	if (ret < 0)
+		goto err_mfd;
+
+	return ret;
+
+err_mfd:
+	mfd_remove_devices(max77686->dev);
+	i2c_unregister_device(max77686->rtc);
+err:
+	kfree(max77686);
+	return ret;
+}
+
+static int max77686_i2c_remove(struct i2c_client *i2c)
+{
+	struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
+
+	mfd_remove_devices(max77686->dev);
+	i2c_unregister_device(max77686->rtc);
+	kfree(max77686);
+
+	return 0;
+}
+
+static const struct i2c_device_id max77686_i2c_id[] = {
+	{ "max77686", TYPE_MAX77686 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max77686_i2c_id);
+
+static struct i2c_driver max77686_i2c_driver = {
+	.driver = {
+		   .name = "max77686",
+		   .owner = THIS_MODULE,
+	},
+	.probe = max77686_i2c_probe,
+	.remove = max77686_i2c_remove,
+	.id_table = max77686_i2c_id,
+};
+
+static int __init max77686_i2c_init(void)
+{
+	return i2c_add_driver(&max77686_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(max77686_i2c_init);
+
+static void __exit max77686_i2c_exit(void)
+{
+	i2c_del_driver(&max77686_i2c_driver);
+}
+module_exit(max77686_i2c_exit);
+
+MODULE_DESCRIPTION("MAXIM 77686 multi-function core driver");
+MODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 6fc90be..269b296 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -716,8 +716,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
 		static struct regulator_consumer_supply usb1v8 = {
 			.supply =	"usb1v8",
 		};
-		static struct regulator_consumer_supply usb3v1 = {
-			.supply =	"usb3v1",
+		static struct regulator_consumer_supply usb3v1[] = {
+			{ .supply =	"usb3v1" },
+			{ .supply =	"bci3v1" },
 		};
 
 	/* First add the regulators so that they can be used by transceiver */
@@ -745,7 +746,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
 				return PTR_ERR(child);
 
 			child = add_regulator_linked(TWL4030_REG_VUSB3V1,
-						      &usb_fixed, &usb3v1, 1,
+						      &usb_fixed, usb3v1, 2,
 						      features);
 			if (IS_ERR(child))
 				return PTR_ERR(child);
@@ -766,7 +767,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
 		if (twl_has_regulator() && child) {
 			usb1v5.dev_name = dev_name(child);
 			usb1v8.dev_name = dev_name(child);
-			usb3v1.dev_name = dev_name(child);
+			usb3v1[0].dev_name = dev_name(child);
 		}
 	}
 	if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c
index 85cc771..9d5eed7 100644
--- a/drivers/misc/cb710/core.c
+++ b/drivers/misc/cb710/core.c
@@ -180,7 +180,7 @@ static int cb710_suspend(struct pci_dev *pdev, pm_message_t state)
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
 	if (state.event & PM_EVENT_SLEEP)
-		pci_set_power_state(pdev, PCI_D3cold);
+		pci_set_power_state(pdev, PCI_D3hot);
 	return 0;
 }
 
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 0842c29..25003d6 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -19,7 +19,7 @@
 
 #include <linux/spi/spi.h>
 #include <linux/spi/eeprom.h>
-
+#include <linux/of.h>
 
 /*
  * NOTE: this is an *EEPROM* driver.  The vagaries of product naming
@@ -305,25 +305,54 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,
 static int at25_probe(struct spi_device *spi)
 {
 	struct at25_data	*at25 = NULL;
-	const struct spi_eeprom *chip;
+	struct spi_eeprom	chip;
+	struct device_node	*np = spi->dev.of_node;
 	int			err;
 	int			sr;
 	int			addrlen;
 
 	/* Chip description */
-	chip = spi->dev.platform_data;
-	if (!chip) {
-		dev_dbg(&spi->dev, "no chip description\n");
-		err = -ENODEV;
-		goto fail;
-	}
+	if (!spi->dev.platform_data) {
+		if (np) {
+			u32 val;
+
+			memset(&chip, 0, sizeof(chip));
+			strncpy(chip.name, np->name, 10);
+
+			err = of_property_read_u32(np, "at25,byte-len", &val);
+			if (err) {
+				dev_dbg(&spi->dev, "invalid chip dt description\n");
+				goto fail;
+			}
+			chip.byte_len = val;
+
+			err = of_property_read_u32(np, "at25,addr-mode", &val);
+			if (err) {
+				dev_dbg(&spi->dev, "invalid chip dt description\n");
+				goto fail;
+			}
+			chip.flags = (u16)val;
+
+			err = of_property_read_u32(np, "at25,page-size", &val);
+			if (err) {
+				dev_dbg(&spi->dev, "invalid chip dt description\n");
+				goto fail;
+			}
+			chip.page_size = (u16)val;
+		} else {
+			dev_dbg(&spi->dev, "no chip description\n");
+			err = -ENODEV;
+			goto fail;
+		}
+	} else
+		chip = *(struct spi_eeprom *)spi->dev.platform_data;
 
 	/* For now we only support 8/16/24 bit addressing */
-	if (chip->flags & EE_ADDR1)
+	if (chip.flags & EE_ADDR1)
 		addrlen = 1;
-	else if (chip->flags & EE_ADDR2)
+	else if (chip.flags & EE_ADDR2)
 		addrlen = 2;
-	else if (chip->flags & EE_ADDR3)
+	else if (chip.flags & EE_ADDR3)
 		addrlen = 3;
 	else {
 		dev_dbg(&spi->dev, "unsupported address type\n");
@@ -348,7 +377,7 @@ static int at25_probe(struct spi_device *spi)
 	}
 
 	mutex_init(&at25->lock);
-	at25->chip = *chip;
+	at25->chip = chip;
 	at25->spi = spi_dev_get(spi);
 	dev_set_drvdata(&spi->dev, at25);
 	at25->addrlen = addrlen;
@@ -369,7 +398,7 @@ static int at25_probe(struct spi_device *spi)
 	at25->mem.read = at25_mem_read;
 
 	at25->bin.size = at25->chip.byte_len;
-	if (!(chip->flags & EE_READONLY)) {
+	if (!(chip.flags & EE_READONLY)) {
 		at25->bin.write = at25_bin_write;
 		at25->bin.attr.mode |= S_IWUSR;
 		at25->mem.write = at25_mem_write;
@@ -379,8 +408,8 @@ static int at25_probe(struct spi_device *spi)
 	if (err)
 		goto fail;
 
-	if (chip->setup)
-		chip->setup(&at25->mem, chip->context);
+	if (chip.setup)
+		chip.setup(&at25->mem, chip.context);
 
 	dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
 		(at25->bin.size < 1024)
@@ -388,7 +417,7 @@ static int at25_probe(struct spi_device *spi)
 			: (at25->bin.size / 1024),
 		(at25->bin.size < 1024) ? "Byte" : "KByte",
 		at25->chip.name,
-		(chip->flags & EE_READONLY) ? " (readonly)" : "",
+		(chip.flags & EE_READONLY) ? " (readonly)" : "",
 		at25->chip.page_size);
 	return 0;
 fail:
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index fffc227..6df0da4 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -30,6 +30,7 @@
 
 static struct class *ilo_class;
 static unsigned int ilo_major;
+static unsigned int max_ccb = MIN_CCB;
 static char ilo_hwdev[MAX_ILO_DEV];
 
 static inline int get_entry_id(int entry)
@@ -424,7 +425,7 @@ static void ilo_set_reset(struct ilo_hwinfo *hw)
 	 * Mapped memory is zeroed on ilo reset, so set a per ccb flag
 	 * to indicate that this ccb needs to be closed and reopened.
 	 */
-	for (slot = 0; slot < MAX_CCB; slot++) {
+	for (slot = 0; slot < max_ccb; slot++) {
 		if (!hw->ccb_alloc[slot])
 			continue;
 		set_channel_reset(&hw->ccb_alloc[slot]->driver_ccb);
@@ -535,7 +536,7 @@ static int ilo_close(struct inode *ip, struct file *fp)
 	struct ilo_hwinfo *hw;
 	unsigned long flags;
 
-	slot = iminor(ip) % MAX_CCB;
+	slot = iminor(ip) % max_ccb;
 	hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
 
 	spin_lock(&hw->open_lock);
@@ -566,7 +567,7 @@ static int ilo_open(struct inode *ip, struct file *fp)
 	struct ilo_hwinfo *hw;
 	unsigned long flags;
 
-	slot = iminor(ip) % MAX_CCB;
+	slot = iminor(ip) % max_ccb;
 	hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
 
 	/* new ccb allocation */
@@ -663,7 +664,7 @@ static irqreturn_t ilo_isr(int irq, void *data)
 		ilo_set_reset(hw);
 	}
 
-	for (i = 0; i < MAX_CCB; i++) {
+	for (i = 0; i < max_ccb; i++) {
 		if (!hw->ccb_alloc[i])
 			continue;
 		if (pending & (1 << i))
@@ -697,14 +698,14 @@ static int __devinit ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
 	}
 
 	/* map the adapter shared memory region */
-	hw->ram_vaddr = pci_iomap(pdev, 2, MAX_CCB * ILOHW_CCB_SZ);
+	hw->ram_vaddr = pci_iomap(pdev, 2, max_ccb * ILOHW_CCB_SZ);
 	if (hw->ram_vaddr == NULL) {
 		dev_err(&pdev->dev, "Error mapping shared mem\n");
 		goto mmio_free;
 	}
 
 	/* map the doorbell aperture */
-	hw->db_vaddr = pci_iomap(pdev, 3, MAX_CCB * ONE_DB_SIZE);
+	hw->db_vaddr = pci_iomap(pdev, 3, max_ccb * ONE_DB_SIZE);
 	if (hw->db_vaddr == NULL) {
 		dev_err(&pdev->dev, "Error mapping doorbell\n");
 		goto ram_free;
@@ -727,7 +728,7 @@ static void ilo_remove(struct pci_dev *pdev)
 	clear_device(ilo_hw);
 
 	minor = MINOR(ilo_hw->cdev.dev);
-	for (i = minor; i < minor + MAX_CCB; i++)
+	for (i = minor; i < minor + max_ccb; i++)
 		device_destroy(ilo_class, MKDEV(ilo_major, i));
 
 	cdev_del(&ilo_hw->cdev);
@@ -737,7 +738,7 @@ static void ilo_remove(struct pci_dev *pdev)
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	kfree(ilo_hw);
-	ilo_hwdev[(minor / MAX_CCB)] = 0;
+	ilo_hwdev[(minor / max_ccb)] = 0;
 }
 
 static int __devinit ilo_probe(struct pci_dev *pdev,
@@ -746,6 +747,11 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
 	int devnum, minor, start, error;
 	struct ilo_hwinfo *ilo_hw;
 
+	if (max_ccb > MAX_CCB)
+		max_ccb = MAX_CCB;
+	else if (max_ccb < MIN_CCB)
+		max_ccb = MIN_CCB;
+
 	/* find a free range for device files */
 	for (devnum = 0; devnum < MAX_ILO_DEV; devnum++) {
 		if (ilo_hwdev[devnum] == 0) {
@@ -795,14 +801,14 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
 
 	cdev_init(&ilo_hw->cdev, &ilo_fops);
 	ilo_hw->cdev.owner = THIS_MODULE;
-	start = devnum * MAX_CCB;
-	error = cdev_add(&ilo_hw->cdev, MKDEV(ilo_major, start), MAX_CCB);
+	start = devnum * max_ccb;
+	error = cdev_add(&ilo_hw->cdev, MKDEV(ilo_major, start), max_ccb);
 	if (error) {
 		dev_err(&pdev->dev, "Could not add cdev\n");
 		goto remove_isr;
 	}
 
-	for (minor = 0 ; minor < MAX_CCB; minor++) {
+	for (minor = 0 ; minor < max_ccb; minor++) {
 		struct device *dev;
 		dev = device_create(ilo_class, &pdev->dev,
 				    MKDEV(ilo_major, minor), NULL,
@@ -879,11 +885,14 @@ static void __exit ilo_exit(void)
 	class_destroy(ilo_class);
 }
 
-MODULE_VERSION("1.2");
+MODULE_VERSION("1.3");
 MODULE_ALIAS(ILO_NAME);
 MODULE_DESCRIPTION(ILO_NAME);
 MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
 MODULE_LICENSE("GPL v2");
 
+module_param(max_ccb, uint, 0444);
+MODULE_PARM_DESC(max_ccb, "Maximum number of HP iLO channels to attach (8)");
+
 module_init(ilo_init);
 module_exit(ilo_exit);
diff --git a/drivers/misc/hpilo.h b/drivers/misc/hpilo.h
index 54e43ad..b97672e 100644
--- a/drivers/misc/hpilo.h
+++ b/drivers/misc/hpilo.h
@@ -14,7 +14,9 @@
 #define ILO_NAME "hpilo"
 
 /* max number of open channel control blocks per device, hw limited to 32 */
-#define MAX_CCB		8
+#define MAX_CCB	       24
+/* min number of open channel control blocks per device, hw limited to 32 */
+#define MIN_CCB		8
 /* max number of supported devices */
 #define MAX_ILO_DEV	1
 /* max number of files */
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index a7d0bb0..d39b277 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -162,6 +162,9 @@ int mei_hw_init(struct mei_device *dev)
 	if ((dev->host_hw_state & H_IS) == H_IS)
 		mei_reg_write(dev, H_CSR, dev->host_hw_state);
 
+	/* Doesn't change in runtime */
+	dev->hbuf_depth = (dev->host_hw_state & H_CBD) >> 24;
+
 	dev->recvd_msg = false;
 	dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
 
diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c
index 428d21e..88ada64 100644
--- a/drivers/misc/mei/interface.c
+++ b/drivers/misc/mei/interface.c
@@ -58,16 +58,18 @@ void mei_disable_interrupts(struct mei_device *dev)
 }
 
 /**
- * _host_get_filled_slots - gets number of device filled buffer slots
+ * mei_hbuf_filled_slots - gets number of device filled buffer slots
  *
  * @device: the device structure
  *
  * returns number of filled slots
  */
-static unsigned char _host_get_filled_slots(const struct mei_device *dev)
+static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
 {
 	char read_ptr, write_ptr;
 
+	dev->host_hw_state = mei_hcsr_read(dev);
+
 	read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8);
 	write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16);
 
@@ -75,43 +77,33 @@ static unsigned char _host_get_filled_slots(const struct mei_device *dev)
 }
 
 /**
- * mei_host_buffer_is_empty - checks if host buffer is empty.
+ * mei_hbuf_is_empty - checks if host buffer is empty.
  *
  * @dev: the device structure
  *
- * returns 1 if empty, 0 - otherwise.
+ * returns true if empty, false - otherwise.
  */
-int mei_host_buffer_is_empty(struct mei_device *dev)
+bool mei_hbuf_is_empty(struct mei_device *dev)
 {
-	unsigned char filled_slots;
-
-	dev->host_hw_state = mei_hcsr_read(dev);
-	filled_slots = _host_get_filled_slots(dev);
-
-	if (filled_slots == 0)
-		return 1;
-
-	return 0;
+	return mei_hbuf_filled_slots(dev) == 0;
 }
 
 /**
- * mei_count_empty_write_slots - counts write empty slots.
+ * mei_hbuf_empty_slots - counts write empty slots.
  *
  * @dev: the device structure
  *
  * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
  */
-int mei_count_empty_write_slots(struct mei_device *dev)
+int mei_hbuf_empty_slots(struct mei_device *dev)
 {
-	unsigned char buffer_depth, filled_slots, empty_slots;
+	unsigned char filled_slots, empty_slots;
 
-	dev->host_hw_state = mei_hcsr_read(dev);
-	buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
-	filled_slots = _host_get_filled_slots(dev);
-	empty_slots = buffer_depth - filled_slots;
+	filled_slots = mei_hbuf_filled_slots(dev);
+	empty_slots = dev->hbuf_depth - filled_slots;
 
 	/* check for overflow */
-	if (filled_slots > buffer_depth)
+	if (filled_slots > dev->hbuf_depth)
 		return -EOVERFLOW;
 
 	return empty_slots;
@@ -127,52 +119,39 @@ int mei_count_empty_write_slots(struct mei_device *dev)
  *
  * This function returns -EIO if write has failed
  */
-int mei_write_message(struct mei_device *dev,
-		      struct mei_msg_hdr *header,
-		      unsigned char *write_buffer,
-		      unsigned long write_length)
+int mei_write_message(struct mei_device *dev, struct mei_msg_hdr *header,
+		      unsigned char *buf, unsigned long length)
 {
-	u32 temp_msg = 0;
-	unsigned long bytes_written = 0;
-	unsigned char buffer_depth, filled_slots, empty_slots;
-	unsigned long dw_to_write;
-
-	dev->host_hw_state = mei_hcsr_read(dev);
+	unsigned long rem, dw_cnt;
+	u32 *reg_buf = (u32 *)buf;
+	int i;
+	int empty_slots;
 
-	dev_dbg(&dev->pdev->dev,
-			"host_hw_state = 0x%08x.\n",
-			dev->host_hw_state);
 
 	dev_dbg(&dev->pdev->dev,
 			"mei_write_message header=%08x.\n",
 			*((u32 *) header));
 
-	buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
-	filled_slots = _host_get_filled_slots(dev);
-	empty_slots = buffer_depth - filled_slots;
-	dev_dbg(&dev->pdev->dev,
-			"filled = %hu, empty = %hu.\n",
-			filled_slots, empty_slots);
-
-	dw_to_write = ((write_length + 3) / 4);
+	empty_slots = mei_hbuf_empty_slots(dev);
+	dev_dbg(&dev->pdev->dev, "empty slots = %hu.\n", empty_slots);
 
-	if (dw_to_write > empty_slots)
+	dw_cnt = (length + sizeof(*header) + 3) / 4;
+	if (empty_slots < 0 || dw_cnt > empty_slots)
 		return -EIO;
 
 	mei_reg_write(dev, H_CB_WW, *((u32 *) header));
 
-	while (write_length >= 4) {
-		mei_reg_write(dev, H_CB_WW,
-				*(u32 *) (write_buffer + bytes_written));
-		bytes_written += 4;
-		write_length -= 4;
-	}
+	for (i = 0; i < length / 4; i++)
+		mei_reg_write(dev, H_CB_WW, reg_buf[i]);
 
-	if (write_length > 0) {
-		memcpy(&temp_msg, &write_buffer[bytes_written], write_length);
-		mei_reg_write(dev, H_CB_WW, temp_msg);
+	rem = length & 0x3;
+	if (rem > 0) {
+		u32 reg = 0;
+		memcpy(&reg, &buf[length - rem], rem);
+		mei_reg_write(dev, H_CB_WW, reg);
 	}
 
+	dev->host_hw_state = mei_hcsr_read(dev);
 	dev->host_hw_state |= H_IG;
 	mei_hcsr_set(dev);
 	dev->me_hw_state = mei_mecsr_read(dev);
diff --git a/drivers/misc/mei/interface.h b/drivers/misc/mei/interface.h
index ddff5d1..cd9b778 100644
--- a/drivers/misc/mei/interface.h
+++ b/drivers/misc/mei/interface.h
@@ -41,14 +41,22 @@ int mei_write_message(struct mei_device *dev,
 			     unsigned char *write_buffer,
 			     unsigned long write_length);
 
-int mei_host_buffer_is_empty(struct mei_device *dev);
+bool mei_hbuf_is_empty(struct mei_device *dev);
+
+int mei_hbuf_empty_slots(struct mei_device *dev);
+
+static inline size_t mei_hbuf_max_data(const struct mei_device *dev)
+{
+	return dev->hbuf_depth * sizeof(u32) - sizeof(struct mei_msg_hdr);
+}
 
 int mei_count_full_read_slots(struct mei_device *dev);
 
-int mei_count_empty_write_slots(struct mei_device *dev);
 
 int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
 
+
+
 int mei_wd_send(struct mei_device *dev);
 int mei_wd_stop(struct mei_device *dev, bool preserve);
 int mei_wd_host_init(struct mei_device *dev);
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 23f5463..013641d 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -280,7 +280,7 @@ static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots)
 	dev->iamthif_msg_buf_index = 0;
 	dev->iamthif_msg_buf_size = 0;
 	dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
-	dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
+	dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev);
 	return 0;
 }
 
@@ -951,7 +951,7 @@ static int _mei_irq_thread_cmpl(struct mei_device *dev,	s32 *slots,
 			list_move_tail(&cb_pos->cb_list,
 				&dev->write_waiting_list.mei_cb.cb_list);
 		}
-	} else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
+	} else if (*slots == dev->hbuf_depth) {
 		/* buffer is still empty */
 		mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
 		mei_hdr->host_addr = cl->host_client_id;
@@ -1046,8 +1046,8 @@ static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots,
 				&dev->write_waiting_list.mei_cb.cb_list);
 
 		}
-	} else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
-			/* buffer is still empty */
+	} else if (*slots == dev->hbuf_depth) {
+		/* buffer is still empty */
 		mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
 		mei_hdr->host_addr = cl->host_client_id;
 		mei_hdr->me_addr = cl->me_client_id;
@@ -1199,11 +1199,14 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
 	struct mei_io_list *list;
 	int ret;
 
-	if (!mei_host_buffer_is_empty(dev)) {
+	if (!mei_hbuf_is_empty(dev)) {
 		dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
 		return 0;
 	}
-	*slots = mei_count_empty_write_slots(dev);
+	*slots = mei_hbuf_empty_slots(dev);
+	if (*slots <= 0)
+		return -EMSGSIZE;
+
 	/* complete all waiting for write CB */
 	dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
 
@@ -1326,7 +1329,7 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
 			continue;
 
 		if (cl != &dev->iamthif_cl) {
-			if (!mei_flow_ctrl_creds(dev, cl)) {
+			if (mei_flow_ctrl_creds(dev, cl) <= 0) {
 				dev_dbg(&dev->pdev->dev,
 					"No flow control"
 				    " credentials for client"
@@ -1343,7 +1346,7 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
 		} else if (cl == &dev->iamthif_cl) {
 			/* IAMTHIF IOCTL */
 			dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n");
-			if (!mei_flow_ctrl_creds(dev, cl)) {
+			if (mei_flow_ctrl_creds(dev, cl) <= 0) {
 				dev_dbg(&dev->pdev->dev,
 					"No flow control"
 				    " credentials for amthi"
@@ -1555,7 +1558,7 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
 end:
 	dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
 	dev->host_hw_state = mei_hcsr_read(dev);
-	dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
+	dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev);
 
 	bus_message_received = false;
 	if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c
index f9cced6..50f52e2 100644
--- a/drivers/misc/mei/iorw.c
+++ b/drivers/misc/mei/iorw.c
@@ -481,12 +481,8 @@ int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
 	if (ret && dev->mei_host_buffer_is_empty) {
 		ret = 0;
 		dev->mei_host_buffer_is_empty = false;
-		if (cb->request_buffer.size >
-			(((dev->host_hw_state & H_CBD) >> 24) * sizeof(u32))
-				-sizeof(struct mei_msg_hdr)) {
-			mei_hdr.length =
-			    (((dev->host_hw_state & H_CBD) >> 24) *
-			    sizeof(u32)) - sizeof(struct mei_msg_hdr);
+		if (cb->request_buffer.size > mei_hbuf_max_data(dev)) {
+			mei_hdr.length = mei_hbuf_max_data(dev);
 			mei_hdr.msg_complete = 0;
 		} else {
 			mei_hdr.length = cb->request_buffer.size;
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 7de1389..1c1df04 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -714,13 +714,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 	if (rets && dev->mei_host_buffer_is_empty) {
 		rets = 0;
 		dev->mei_host_buffer_is_empty = false;
-		if (length > ((((dev->host_hw_state & H_CBD) >> 24) *
-			sizeof(u32)) - sizeof(struct mei_msg_hdr))) {
-
-			mei_hdr.length =
-				(((dev->host_hw_state & H_CBD) >> 24) *
-				sizeof(u32)) -
-				sizeof(struct mei_msg_hdr);
+		if (length >  mei_hbuf_max_data(dev)) {
+			mei_hdr.length = mei_hbuf_max_data(dev);
 			mei_hdr.msg_complete = 0;
 		} else {
 			mei_hdr.length = length;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 63d7ee9..d60250d 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -167,7 +167,10 @@ struct mei_io_list {
 	struct mei_cl_cb mei_cb;
 };
 
-/* MEI private device struct */
+/**
+ * struct mei_deive -  MEI private device struct
+ * @hbuf_depth - depth of host(write) buffer
+ */
 struct mei_device {
 	struct pci_dev *pdev;	/* pointer to pci device struct */
 	/*
@@ -205,6 +208,7 @@ struct mei_device {
 	 */
 	u32 host_hw_state;
 	u32 me_hw_state;
+	u8  hbuf_depth;
 	/*
 	 * waiting queue for receive message from FW
 	 */
@@ -237,6 +241,7 @@ struct mei_device {
 	bool mei_host_buffer_is_empty;
 
 	struct mei_cl wd_cl;
+	bool wd_interface_reg;
 	bool wd_pending;
 	bool wd_stopped;
 	bool wd_bypass;	/* if false, don't refresh watchdog ME client */
@@ -245,7 +250,6 @@ struct mei_device {
 	unsigned char wd_data[MEI_START_WD_DATA_SIZE];
 
 
-
 	struct file *iamthif_file_object;
 	struct mei_cl iamthif_cl;
 	struct mei_cl_cb *iamthif_current_cb;
@@ -259,8 +263,6 @@ struct mei_device {
 	bool iamthif_flow_control_pending;
 	bool iamthif_ioctl;
 	bool iamthif_canceled;
-
-	bool wd_interface_reg;
 };
 
 
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index dd2d374..f1c84de 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -554,7 +554,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
-	unsigned int timeout_us;
 
 	struct scatterlist sg;
 
@@ -574,23 +573,12 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 	cmd.arg = 0;
 	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
-	data.timeout_ns = card->csd.tacc_ns * 100;
-	data.timeout_clks = card->csd.tacc_clks * 100;
-
-	timeout_us = data.timeout_ns / 1000;
-	timeout_us += data.timeout_clks * 1000 /
-		(card->host->ios.clock / 1000);
-
-	if (timeout_us > 100000) {
-		data.timeout_ns = 100000000;
-		data.timeout_clks = 0;
-	}
-
 	data.blksz = 4;
 	data.blocks = 1;
 	data.flags = MMC_DATA_READ;
 	data.sg = &sg;
 	data.sg_len = 1;
+	mmc_set_data_timeout(&data, card);
 
 	mrq.cmd = &cmd;
 	mrq.data = &data;
@@ -862,9 +850,7 @@ out:
 		goto retry;
 	if (!err)
 		mmc_blk_reset_success(md, type);
-	spin_lock_irq(&md->lock);
-	__blk_end_request(req, err, blk_rq_bytes(req));
-	spin_unlock_irq(&md->lock);
+	blk_end_request(req, err, blk_rq_bytes(req));
 
 	return err ? 0 : 1;
 }
@@ -946,9 +932,7 @@ out_retry:
 	if (!err)
 		mmc_blk_reset_success(md, type);
 out:
-	spin_lock_irq(&md->lock);
-	__blk_end_request(req, err, blk_rq_bytes(req));
-	spin_unlock_irq(&md->lock);
+	blk_end_request(req, err, blk_rq_bytes(req));
 
 	return err ? 0 : 1;
 }
@@ -963,9 +947,7 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 	if (ret)
 		ret = -EIO;
 
-	spin_lock_irq(&md->lock);
-	__blk_end_request_all(req, ret);
-	spin_unlock_irq(&md->lock);
+	blk_end_request_all(req, ret);
 
 	return ret ? 0 : 1;
 }
@@ -1264,14 +1246,10 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
 
 		blocks = mmc_sd_num_wr_blocks(card);
 		if (blocks != (u32)-1) {
-			spin_lock_irq(&md->lock);
-			ret = __blk_end_request(req, 0, blocks << 9);
-			spin_unlock_irq(&md->lock);
+			ret = blk_end_request(req, 0, blocks << 9);
 		}
 	} else {
-		spin_lock_irq(&md->lock);
-		ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
-		spin_unlock_irq(&md->lock);
+		ret = blk_end_request(req, 0, brq->data.bytes_xfered);
 	}
 	return ret;
 }
@@ -1323,10 +1301,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 			 * A block was successfully transferred.
 			 */
 			mmc_blk_reset_success(md, type);
-			spin_lock_irq(&md->lock);
-			ret = __blk_end_request(req, 0,
+			ret = blk_end_request(req, 0,
 						brq->data.bytes_xfered);
-			spin_unlock_irq(&md->lock);
 			/*
 			 * If the blk_end_request function returns non-zero even
 			 * though all data has been transferred and no errors
@@ -1376,10 +1352,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 			 * time, so we only reach here after trying to
 			 * read a single sector.
 			 */
-			spin_lock_irq(&md->lock);
-			ret = __blk_end_request(req, -EIO,
+			ret = blk_end_request(req, -EIO,
 						brq->data.blksz);
-			spin_unlock_irq(&md->lock);
 			if (!ret)
 				goto start_new_req;
 			break;
@@ -1400,12 +1374,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 	return 1;
 
  cmd_abort:
-	spin_lock_irq(&md->lock);
 	if (mmc_card_removed(card))
 		req->cmd_flags |= REQ_QUIET;
 	while (ret)
-		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
-	spin_unlock_irq(&md->lock);
+		ret = blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
 
  start_new_req:
 	if (rqc) {
@@ -1429,9 +1401,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 	ret = mmc_blk_part_switch(card, md);
 	if (ret) {
 		if (req) {
-			spin_lock_irq(&md->lock);
-			__blk_end_request_all(req, -EIO);
-			spin_unlock_irq(&md->lock);
+			blk_end_request_all(req, -EIO);
 		}
 		ret = 0;
 		goto out;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 0b6141d..f11de40 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -404,6 +404,7 @@ int mmc_interrupt_hpi(struct mmc_card *card)
 {
 	int err;
 	u32 status;
+	unsigned long prg_wait;
 
 	BUG_ON(!card);
 
@@ -419,30 +420,38 @@ int mmc_interrupt_hpi(struct mmc_card *card)
 		goto out;
 	}
 
-	/*
-	 * If the card status is in PRG-state, we can send the HPI command.
-	 */
-	if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
-		do {
-			/*
-			 * We don't know when the HPI command will finish
-			 * processing, so we need to resend HPI until out
-			 * of prg-state, and keep checking the card status
-			 * with SEND_STATUS.  If a timeout error occurs when
-			 * sending the HPI command, we are already out of
-			 * prg-state.
-			 */
-			err = mmc_send_hpi_cmd(card, &status);
-			if (err)
-				pr_debug("%s: abort HPI (%d error)\n",
-					 mmc_hostname(card->host), err);
+	switch (R1_CURRENT_STATE(status)) {
+	case R1_STATE_IDLE:
+	case R1_STATE_READY:
+	case R1_STATE_STBY:
+		/*
+		 * In idle states, HPI is not needed and the caller
+		 * can issue the next intended command immediately
+		 */
+		goto out;
+	case R1_STATE_PRG:
+		break;
+	default:
+		/* In all other states, it's illegal to issue HPI */
+		pr_debug("%s: HPI cannot be sent. Card state=%d\n",
+			mmc_hostname(card->host), R1_CURRENT_STATE(status));
+		err = -EINVAL;
+		goto out;
+	}
 
-			err = mmc_send_status(card, &status);
-			if (err)
-				break;
-		} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
-	} else
-		pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
+	err = mmc_send_hpi_cmd(card, &status);
+	if (err)
+		goto out;
+
+	prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time);
+	do {
+		err = mmc_send_status(card, &status);
+
+		if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN)
+			break;
+		if (time_after(jiffies, prg_wait))
+			err = -ETIMEDOUT;
+	} while (!err);
 
 out:
 	mmc_release_host(card->host);
@@ -941,7 +950,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply)
 
 	return result;
 }
-EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
+EXPORT_SYMBOL_GPL(mmc_regulator_get_ocrmask);
 
 /**
  * mmc_regulator_set_ocr - set regulator to match host->ios voltage
@@ -1011,7 +1020,31 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
 			"could not set regulator OCR (%d)\n", result);
 	return result;
 }
-EXPORT_SYMBOL(mmc_regulator_set_ocr);
+EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr);
+
+int mmc_regulator_get_supply(struct mmc_host *mmc)
+{
+	struct device *dev = mmc_dev(mmc);
+	struct regulator *supply;
+	int ret;
+
+	supply = devm_regulator_get(dev, "vmmc");
+
+	if (IS_ERR(supply))
+		return PTR_ERR(supply);
+
+	mmc->supply.vmmc = supply;
+	mmc->supply.vqmmc = devm_regulator_get(dev, "vqmmc");
+
+	ret = mmc_regulator_get_ocrmask(supply);
+	if (ret > 0)
+		mmc->ocr_avail = ret;
+	else
+		dev_warn(mmc_dev(mmc), "Failed getting OCR mask: %d\n", ret);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
 
 #endif /* CONFIG_REGULATOR */
 
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 69370f4..0ed2cc5 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -569,7 +569,6 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
 
 	cmd.opcode = opcode;
 	cmd.arg = card->rca << 16 | 1;
-	cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, 0);
 	if (err) {
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 1ca5e72..72dc3cd 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -405,11 +405,23 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
 static int dw_mci_idmac_init(struct dw_mci *host)
 {
 	struct idmac_desc *p;
-	int i;
+	int i, dma_support;
 
 	/* Number of descriptors in the ring buffer */
 	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
 
+	/* Check if Hardware Configuration Register has support for DMA */
+	dma_support = (mci_readl(host, HCON) >> 16) & 0x3;
+
+	if (!dma_support || dma_support > 2) {
+		dev_err(&host->dev,
+			"Host Controller does not support IDMA Tx.\n");
+		host->dma_ops = NULL;
+		return -ENODEV;
+	}
+
+	dev_info(&host->dev, "Using internal DMA controller.\n");
+
 	/* Forward link the descriptor list */
 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
 		p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
@@ -1876,7 +1888,6 @@ static void dw_mci_init_dma(struct dw_mci *host)
 	/* Determine which DMA interface to use */
 #ifdef CONFIG_MMC_DW_IDMAC
 	host->dma_ops = &dw_mci_idmac_ops;
-	dev_info(&host->dev, "Using internal DMA controller.\n");
 #endif
 
 	if (!host->dma_ops)
@@ -2175,7 +2186,7 @@ int dw_mci_resume(struct dw_mci *host)
 		return ret;
 	}
 
-	if (host->dma_ops->init)
+	if (host->use_dma && host->dma_ops->init)
 		host->dma_ops->init(host);
 
 	/* Restore the old value at FIFOTH register */
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 9a7a60a..389a3ee 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -85,7 +85,6 @@
 #define BRR_ENABLE		(1 << 5)
 #define DTO_ENABLE		(1 << 20)
 #define INIT_STREAM		(1 << 1)
-#define ACEN_ACMD12		(1 << 2)
 #define DP_SELECT		(1 << 21)
 #define DDIR			(1 << 4)
 #define DMA_EN			0x1
@@ -117,7 +116,6 @@
 #define OMAP_MMC_MAX_CLOCK	52000000
 #define DRIVER_NAME		"omap_hsmmc"
 
-#define AUTO_CMD12		(1 << 0)	/* Auto CMD12 support */
 /*
  * One controller can have multiple slots, like on some omap boards using
  * omap.c controller driver. Luckily this is not currently done on any known
@@ -177,7 +175,6 @@ struct omap_hsmmc_host {
 	int			reqs_blocked;
 	int			use_reg;
 	int			req_in_progress;
-	unsigned int		flags;
 	struct omap_hsmmc_next	next_data;
 
 	struct	omap_mmc_platform_data	*pdata;
@@ -773,8 +770,6 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
 		cmdtype = 0x3;
 
 	cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
-	if ((host->flags & AUTO_CMD12) && mmc_op_multi(cmd->opcode))
-		cmdreg |= ACEN_ACMD12;
 
 	if (data) {
 		cmdreg |= DP_SELECT | MSBS | BCE;
@@ -847,14 +842,11 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
 	else
 		data->bytes_xfered = 0;
 
-	if (data->stop && ((!(host->flags & AUTO_CMD12)) || data->error)) {
-		omap_hsmmc_start_command(host, data->stop, NULL);
-	} else {
-		if (data->stop)
-			data->stop->resp[0] = OMAP_HSMMC_READ(host->base,
-							RSP76);
+	if (!data->stop) {
 		omap_hsmmc_request_done(host, data->mrq);
+		return;
 	}
+	omap_hsmmc_start_command(host, data->stop, NULL);
 }
 
 /*
@@ -1859,7 +1851,6 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
 	host->mapbase	= res->start + pdata->reg_offset;
 	host->base	= ioremap(host->mapbase, SZ_4K);
 	host->power_mode = MMC_POWER_OFF;
-	host->flags	= AUTO_CMD12;
 	host->next_data.cookie = 1;
 
 	platform_set_drvdata(pdev, host);
diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
index dbb75bf..b6ee885 100644
--- a/drivers/mmc/host/sdhci-pxav2.c
+++ b/drivers/mmc/host/sdhci-pxav2.c
@@ -28,6 +28,9 @@
 #include <linux/mmc/host.h>
 #include <linux/platform_data/pxa_sdhci.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 
@@ -121,6 +124,48 @@ static struct sdhci_ops pxav2_sdhci_ops = {
 	.platform_8bit_width = pxav2_mmc_set_width,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id sdhci_pxav2_of_match[] = {
+	{
+		.compatible = "mrvl,pxav2-mmc",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, sdhci_pxav2_of_match);
+
+static struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev)
+{
+	struct sdhci_pxa_platdata *pdata;
+	struct device_node *np = dev->of_node;
+	u32 bus_width;
+	u32 clk_delay_cycles;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	if (of_find_property(np, "non-removable", NULL))
+		pdata->flags |= PXA_FLAG_CARD_PERMANENT;
+
+	of_property_read_u32(np, "bus-width", &bus_width);
+	if (bus_width == 8)
+		pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT;
+
+	of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles);
+	if (clk_delay_cycles > 0) {
+		pdata->clk_delay_sel = 1;
+		pdata->clk_delay_cycles = clk_delay_cycles;
+	}
+
+	return pdata;
+}
+#else
+static inline struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev)
+{
+	return NULL;
+}
+#endif
+
 static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
 {
 	struct sdhci_pltfm_host *pltfm_host;
@@ -128,6 +173,8 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct sdhci_host *host = NULL;
 	struct sdhci_pxa *pxa = NULL;
+	const struct of_device_id *match;
+
 	int ret;
 	struct clk *clk;
 
@@ -156,6 +203,10 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
 		| SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
 		| SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
 
+	match = of_match_device(of_match_ptr(sdhci_pxav2_of_match), &pdev->dev);
+	if (match) {
+		pdata = pxav2_get_mmc_pdata(dev);
+	}
 	if (pdata) {
 		if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
 			/* on-chip device */
@@ -218,6 +269,9 @@ static struct platform_driver sdhci_pxav2_driver = {
 	.driver		= {
 		.name	= "sdhci-pxav2",
 		.owner	= THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = sdhci_pxav2_of_match,
+#endif
 		.pm	= SDHCI_PLTFM_PMOPS,
 	},
 	.probe		= sdhci_pxav2_probe,
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index f296956..cb8be1d 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -28,6 +28,9 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 
@@ -164,6 +167,46 @@ static struct sdhci_ops pxav3_sdhci_ops = {
 	.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id sdhci_pxav3_of_match[] = {
+	{
+		.compatible = "mrvl,pxav3-mmc",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match);
+
+static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
+{
+	struct sdhci_pxa_platdata *pdata;
+	struct device_node *np = dev->of_node;
+	u32 bus_width;
+	u32 clk_delay_cycles;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	if (of_find_property(np, "non-removable", NULL))
+		pdata->flags |= PXA_FLAG_CARD_PERMANENT;
+
+	of_property_read_u32(np, "bus-width", &bus_width);
+	if (bus_width == 8)
+		pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT;
+
+	of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles);
+	if (clk_delay_cycles > 0)
+		pdata->clk_delay_cycles = clk_delay_cycles;
+
+	return pdata;
+}
+#else
+static inline struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
+{
+	return NULL;
+}
+#endif
+
 static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
 {
 	struct sdhci_pltfm_host *pltfm_host;
@@ -171,6 +214,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct sdhci_host *host = NULL;
 	struct sdhci_pxa *pxa = NULL;
+	const struct of_device_id *match;
+
 	int ret;
 	struct clk *clk;
 
@@ -202,6 +247,10 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
 	/* enable 1/8V DDR capable */
 	host->mmc->caps |= MMC_CAP_1_8V_DDR;
 
+	match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev);
+	if (match)
+		pdata = pxav3_get_mmc_pdata(dev);
+
 	if (pdata) {
 		if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
 			/* on-chip device */
@@ -263,6 +312,9 @@ static int __devexit sdhci_pxav3_remove(struct platform_device *pdev)
 static struct platform_driver sdhci_pxav3_driver = {
 	.driver		= {
 		.name	= "sdhci-pxav3",
+#ifdef CONfIG_OF
+		.of_match_table = sdhci_pxav3_of_match,
+#endif
 		.owner	= THIS_MODULE,
 		.pm	= SDHCI_PLTFM_PMOPS,
 	},
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index b38d8a7..0810ccc 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -223,6 +223,7 @@ static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata(
 {
 	struct tegra_sdhci_platform_data *plat;
 	struct device_node *np = pdev->dev.of_node;
+	u32 bus_width;
 
 	if (!np)
 		return NULL;
@@ -236,7 +237,9 @@ static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata(
 	plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
 	plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
 	plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0);
-	if (of_find_property(np, "support-8bit", NULL))
+
+	if (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
+	    bus_width == 8)
 		plat->is_8bit = 1;
 
 	return plat;
@@ -334,7 +337,7 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
 		rc = PTR_ERR(clk);
 		goto err_clk_get;
 	}
-	clk_enable(clk);
+	clk_prepare_enable(clk);
 	pltfm_host->clk = clk;
 
 	host->mmc->pm_caps = plat->pm_flags;
@@ -349,7 +352,7 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
 	return 0;
 
 err_add_host:
-	clk_disable(pltfm_host->clk);
+	clk_disable_unprepare(pltfm_host->clk);
 	clk_put(pltfm_host->clk);
 err_clk_get:
 	if (gpio_is_valid(plat->wp_gpio))
@@ -390,7 +393,7 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
 	if (gpio_is_valid(plat->power_gpio))
 		gpio_free(plat->power_gpio);
 
-	clk_disable(pltfm_host->clk);
+	clk_disable_unprepare(pltfm_host->clk);
 	clk_put(pltfm_host->clk);
 
 	sdhci_pltfm_free(pdev);
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 724b35e..e32da11 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -892,21 +892,15 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
 	switch (mrq->cmd->opcode) {
 	/* MMCIF does not support SD/SDIO command */
-	case SD_IO_SEND_OP_COND:
+	case MMC_SLEEP_AWAKE: /* = SD_IO_SEND_OP_COND (5) */
+	case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
+		if ((mrq->cmd->flags & MMC_CMD_MASK) != MMC_CMD_BCR)
+			break;
 	case MMC_APP_CMD:
 		host->state = STATE_IDLE;
 		mrq->cmd->error = -ETIMEDOUT;
 		mmc_request_done(mmc, mrq);
 		return;
-	case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
-		if (!mrq->data) {
-			/* send_if_cond cmd (not support) */
-			host->state = STATE_IDLE;
-			mrq->cmd->error = -ETIMEDOUT;
-			mmc_request_done(mmc, mrq);
-			return;
-		}
-		break;
 	default:
 		break;
 	}
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 934b68e..42f07fa 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -39,22 +39,39 @@ struct sh_mobile_sdhi {
 	struct tmio_mmc_dma dma_priv;
 };
 
+static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f)
+{
+	struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+	int ret = clk_enable(priv->clk);
+	if (ret < 0)
+		return ret;
+
+	*f = clk_get_rate(priv->clk);
+	return 0;
+}
+
+static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev)
+{
+	struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+	clk_disable(priv->clk);
+}
+
 static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state)
 {
 	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
 
-	if (p && p->set_pwr)
-		p->set_pwr(pdev, state);
+	p->set_pwr(pdev, state);
 }
 
 static int sh_mobile_sdhi_get_cd(struct platform_device *pdev)
 {
 	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
 
-	if (p && p->get_cd)
-		return p->get_cd(pdev);
-	else
-		return -ENOSYS;
+	return p->get_cd(pdev);
 }
 
 static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
@@ -132,9 +149,12 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
 		goto eclkget;
 	}
 
-	mmc_data->hclk = clk_get_rate(priv->clk);
-	mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
-	mmc_data->get_cd = sh_mobile_sdhi_get_cd;
+	if (p->set_pwr)
+		mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
+	if (p->get_cd)
+		mmc_data->get_cd = sh_mobile_sdhi_get_cd;
+	mmc_data->clk_enable = sh_mobile_sdhi_clk_enable;
+	mmc_data->clk_disable = sh_mobile_sdhi_clk_disable;
 	mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
 	if (p) {
 		mmc_data->flags = p->tmio_flags;
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 9a7996a..d68ae59 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -36,6 +36,7 @@
 #include <linux/mfd/tmio.h>
 #include <linux/mmc/cd-gpio.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/tmio.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
@@ -305,8 +306,8 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
 	int c = cmd->opcode;
 	u32 irq_mask = TMIO_MASK_CMD;
 
-	/* Command 12 is handled by hardware */
-	if (cmd->opcode == 12 && !cmd->arg) {
+	/* CMD12 is handled by hardware */
+	if (cmd->opcode == MMC_STOP_TRANSMISSION && !cmd->arg) {
 		sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001);
 		return 0;
 	}
@@ -449,7 +450,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
 	}
 
 	if (stop) {
-		if (stop->opcode == 12 && !stop->arg)
+		if (stop->opcode == MMC_STOP_TRANSMISSION && !stop->arg)
 			sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000);
 		else
 			BUG();
@@ -751,6 +752,34 @@ fail:
 	mmc_request_done(mmc, mrq);
 }
 
+static int tmio_mmc_clk_update(struct mmc_host *mmc)
+{
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	struct tmio_mmc_data *pdata = host->pdata;
+	int ret;
+
+	if (!pdata->clk_enable)
+		return -ENOTSUPP;
+
+	ret = pdata->clk_enable(host->pdev, &mmc->f_max);
+	if (!ret)
+		mmc->f_min = mmc->f_max / 512;
+
+	return ret;
+}
+
+static void tmio_mmc_set_power(struct tmio_mmc_host *host, struct mmc_ios *ios)
+{
+	struct mmc_host *mmc = host->mmc;
+
+	if (host->set_pwr)
+		host->set_pwr(host->pdev, ios->power_mode != MMC_POWER_OFF);
+	if (!IS_ERR(mmc->supply.vmmc))
+		/* Errors ignored... */
+		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
+				      ios->power_mode ? ios->vdd : 0);
+}
+
 /* Set MMC clock / power.
  * Note: This controller uses a simple divider scheme therefore it cannot
  * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
@@ -797,32 +826,37 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	 */
 	if (ios->power_mode == MMC_POWER_ON && ios->clock) {
 		if (!host->power) {
+			tmio_mmc_clk_update(mmc);
 			pm_runtime_get_sync(dev);
 			host->power = true;
 		}
 		tmio_mmc_set_clock(host, ios->clock);
 		/* power up SD bus */
-		if (host->set_pwr)
-			host->set_pwr(host->pdev, 1);
+		tmio_mmc_set_power(host, ios);
 		/* start bus clock */
 		tmio_mmc_clk_start(host);
 	} else if (ios->power_mode != MMC_POWER_UP) {
-		if (host->set_pwr && ios->power_mode == MMC_POWER_OFF)
-			host->set_pwr(host->pdev, 0);
+		if (ios->power_mode == MMC_POWER_OFF)
+			tmio_mmc_set_power(host, ios);
 		if (host->power) {
+			struct tmio_mmc_data *pdata = host->pdata;
+			tmio_mmc_clk_stop(host);
 			host->power = false;
 			pm_runtime_put(dev);
+			if (pdata->clk_disable)
+				pdata->clk_disable(host->pdev);
 		}
-		tmio_mmc_clk_stop(host);
 	}
 
-	switch (ios->bus_width) {
-	case MMC_BUS_WIDTH_1:
-		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
-	break;
-	case MMC_BUS_WIDTH_4:
-		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
-	break;
+	if (host->power) {
+		switch (ios->bus_width) {
+		case MMC_BUS_WIDTH_1:
+			sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
+		break;
+		case MMC_BUS_WIDTH_4:
+			sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
+		break;
+		}
 	}
 
 	/* Let things settle. delay taken from winCE driver */
@@ -865,6 +899,19 @@ static const struct mmc_host_ops tmio_mmc_ops = {
 	.enable_sdio_irq = tmio_mmc_enable_sdio_irq,
 };
 
+static void tmio_mmc_init_ocr(struct tmio_mmc_host *host)
+{
+	struct tmio_mmc_data *pdata = host->pdata;
+	struct mmc_host *mmc = host->mmc;
+
+	mmc_regulator_get_supply(mmc);
+
+	if (!mmc->ocr_avail)
+		mmc->ocr_avail = pdata->ocr_mask ? : MMC_VDD_32_33 | MMC_VDD_33_34;
+	else if (pdata->ocr_mask)
+		dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");
+}
+
 int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 				  struct platform_device *pdev,
 				  struct tmio_mmc_data *pdata)
@@ -904,18 +951,13 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 
 	mmc->ops = &tmio_mmc_ops;
 	mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities;
-	mmc->f_max = pdata->hclk;
-	mmc->f_min = mmc->f_max / 512;
 	mmc->max_segs = 32;
 	mmc->max_blk_size = 512;
 	mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) *
 		mmc->max_segs;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_seg_size = mmc->max_req_size;
-	if (pdata->ocr_mask)
-		mmc->ocr_avail = pdata->ocr_mask;
-	else
-		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+	tmio_mmc_init_ocr(_host);
 
 	_host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
 				  mmc->caps & MMC_CAP_NEEDS_POLL ||
@@ -927,6 +969,11 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 	if (ret < 0)
 		goto pm_disable;
 
+	if (tmio_mmc_clk_update(mmc) < 0) {
+		mmc->f_max = pdata->hclk;
+		mmc->f_min = mmc->f_max / 512;
+	}
+
 	/*
 	 * There are 4 different scenarios for the card detection:
 	 *  1) an external gpio irq handles the cd (best for power savings)
@@ -937,7 +984,6 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 	 *  While we increment the runtime PM counter for all scenarios when
 	 *  the mmc core activates us by calling an appropriate set_ios(), we
 	 *  must additionally ensure that in case 2) the tmio mmc hardware stays
-	 *  additionally ensure that in case 2) the tmio mmc hardware stays
 	 *  powered on during runtime for the card detection to work.
 	 */
 	if (_host->native_hotplug)
@@ -948,6 +994,17 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 
 	_host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK);
 	tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
+
+	/* Unmask the IRQs we want to know about */
+	if (!_host->chan_rx)
+		irq_mask |= TMIO_MASK_READOP;
+	if (!_host->chan_tx)
+		irq_mask |= TMIO_MASK_WRITEOP;
+	if (!_host->native_hotplug)
+		irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
+
+	_host->sdcard_irq_mask &= ~irq_mask;
+
 	if (pdata->flags & TMIO_MMC_SDIO_IRQ)
 		tmio_mmc_enable_sdio_irq(mmc, 0);
 
@@ -961,20 +1018,16 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 	/* See if we also get DMA */
 	tmio_mmc_request_dma(_host, pdata);
 
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (pdata->clk_disable)
+		pdata->clk_disable(pdev);
+	if (ret < 0) {
+		tmio_mmc_host_remove(_host);
+		return ret;
+	}
 
 	dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
 
-	/* Unmask the IRQs we want to know about */
-	if (!_host->chan_rx)
-		irq_mask |= TMIO_MASK_READOP;
-	if (!_host->chan_tx)
-		irq_mask |= TMIO_MASK_WRITEOP;
-	if (!_host->native_hotplug)
-		irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
-
-	tmio_mmc_enable_mmc_irqs(_host, irq_mask);
-
 	if (pdata->flags & TMIO_MMC_USE_GPIO_CD) {
 		ret = mmc_cd_gpio_request(mmc, pdata->cd_gpio);
 		if (ret < 0) {
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 5d0d68c..afa77c0 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -646,6 +646,7 @@ static const struct spi_device_id m25p_ids[] = {
 	{ "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
 	{ "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
 	{ "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
+	{ "n25q064",  INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
 
 	/* Macronix */
 	{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
@@ -714,6 +715,7 @@ static const struct spi_device_id m25p_ids[] = {
 	{ "m45pe80", INFO(0x204014,  0, 64 * 1024,   16, 0) },
 	{ "m45pe16", INFO(0x204015,  0, 64 * 1024,   32, 0) },
 
+	{ "m25pe20", INFO(0x208012,  0, 64 * 1024,  4,       0) },
 	{ "m25pe80", INFO(0x208014,  0, 64 * 1024, 16,       0) },
 	{ "m25pe16", INFO(0x208015,  0, 64 * 1024, 32, SECT_4K) },
 
@@ -730,6 +732,7 @@ static const struct spi_device_id m25p_ids[] = {
 	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
 	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
 	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
+	{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K) },
 	{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
 	{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
 	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 5ba2458..185454a 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -443,7 +443,7 @@ config MTD_GPIO_ADDR
 
 config MTD_UCLINUX
 	bool "Generic uClinux RAM/ROM filesystem support"
-	depends on MTD_RAM=y && !MMU
+	depends on MTD_RAM=y && (!MMU || COLDFIRE)
 	help
 	  Map driver to support image based filesystems for uClinux.
 
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
index cfff454..ded7916 100644
--- a/drivers/mtd/maps/uclinux.c
+++ b/drivers/mtd/maps/uclinux.c
@@ -12,13 +12,10 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/mm.h>
-#include <linux/major.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
-#include <asm/io.h>
 
 /****************************************************************************/
 
@@ -46,11 +43,11 @@ static int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
 	size_t *retlen, void **virt, resource_size_t *phys)
 {
 	struct map_info *map = mtd->priv;
-	*virt = map->virt + from;
+	*virt = (void *)(unsigned long)map->virt + from;
 	if (phys)
 		*phys = map->phys + from;
 	*retlen = len;
-	return(0);
+	return 0;
 }
 
 /****************************************************************************/
@@ -65,23 +62,22 @@ static int __init uclinux_mtd_init(void)
 		mapp->size = PAGE_ALIGN(ntohl(*((unsigned long *)(mapp->phys + 8))));
 	mapp->bankwidth = 4;
 
-	printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
-	       	(int) mapp->phys, (int) mapp->size);
+	printk(KERN_NOTICE "uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
+	       (int)mapp->phys, (int)mapp->size);
 
-	mapp->virt = ioremap_nocache(mapp->phys, mapp->size);
+	mapp->virt = (void __iomem *)(unsigned long)phys_to_virt(mapp->phys);
 
-	if (mapp->virt == 0) {
-		printk("uclinux[mtd]: ioremap_nocache() failed\n");
-		return(-EIO);
+	if (mapp->virt == NULL) {
+		printk(KERN_ERR "uclinux[mtd]: no virtual mapping?\n");
+		return -EIO;
 	}
 
 	simple_map_init(mapp);
 
 	mtd = do_map_probe("map_ram", mapp);
 	if (!mtd) {
-		printk("uclinux[mtd]: failed to find a mapping?\n");
-		iounmap(mapp->virt);
-		return(-ENXIO);
+		printk(KERN_ERR "uclinux[mtd]: failed to find a mapping?\n");
+		return -ENXIO;
 	}
 
 	mtd->owner = THIS_MODULE;
@@ -91,22 +87,15 @@ static int __init uclinux_mtd_init(void)
 	uclinux_ram_mtdinfo = mtd;
 	mtd_device_register(mtd, uclinux_romfs, NUM_PARTITIONS);
 
-	return(0);
+	return 0;
 }
 
 /****************************************************************************/
 
 static void __exit uclinux_mtd_cleanup(void)
 {
-	if (uclinux_ram_mtdinfo) {
-		mtd_device_unregister(uclinux_ram_mtdinfo);
-		map_destroy(uclinux_ram_mtdinfo);
-		uclinux_ram_mtdinfo = NULL;
-	}
-	if (uclinux_ram_map.virt) {
-		iounmap((void *) uclinux_ram_map.virt);
-		uclinux_ram_map.virt = 0;
-	}
+	mtd_device_unregister(uclinux_ram_mtdinfo);
+	map_destroy(uclinux_ram_mtdinfo);
 }
 
 /****************************************************************************/
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 551e316..788f00b 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -169,14 +169,7 @@ static void mtdoops_workfunc_erase(struct work_struct *work)
 			cxt->nextpage = 0;
 	}
 
-	while (1) {
-		ret = mtd_block_isbad(mtd, cxt->nextpage * record_size);
-		if (!ret)
-			break;
-		if (ret < 0) {
-			printk(KERN_ERR "mtdoops: block_isbad failed, aborting\n");
-			return;
-		}
+	while ((ret = mtd_block_isbad(mtd, cxt->nextpage * record_size)) > 0) {
 badblock:
 		printk(KERN_WARNING "mtdoops: bad block at %08lx\n",
 		       cxt->nextpage * record_size);
@@ -190,6 +183,11 @@ badblock:
 		}
 	}
 
+	if (ret < 0) {
+		printk(KERN_ERR "mtdoops: mtd_block_isbad failed, aborting\n");
+		return;
+	}
+
 	for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
 		ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size);
 
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 31bb7e5..b28b57e 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -454,6 +454,17 @@ config MTD_NAND_PXA3xx
 	  This enables the driver for the NAND flash device found on
 	  PXA3xx processors
 
+config MTD_NAND_SLC_LPC32XX
+	tristate "NXP LPC32xx SLC Controller"
+	depends on ARCH_LPC32XX
+	help
+	  Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
+	  chips) NAND controller. This is the default for the PHYTEC 3250
+	  reference board which contains a NAND256R3A2CZA6 chip.
+
+	  Please check the actual NAND chip connected and its support
+	  by the SLC NAND controller.
+
 config MTD_NAND_CM_X270
 	tristate "Support for NAND Flash on CM-X270 modules"
 	depends on MACH_ARMCORE
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index d4b4d87..d29a893 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
+obj-$(CONFIG_MTD_NAND_SLC_LPC32XX)      += lpc32xx_slc.o
 obj-$(CONFIG_MTD_NAND_SH_FLCTL)		+= sh_flctl.o
 obj-$(CONFIG_MTD_NAND_MXC)		+= mxc_nand.o
 obj-$(CONFIG_MTD_NAND_SOCRATES)		+= socrates_nand.o
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index 41371ba..ac0d967 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -102,7 +102,7 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 static int cafe_device_ready(struct mtd_info *mtd)
 {
 	struct cafe_priv *cafe = mtd->priv;
-	int result = !!(cafe_readl(cafe, NAND_STATUS) | 0x40000000);
+	int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000);
 	uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
 
 	cafe_writel(cafe, irqs, NAND_IRQ);
@@ -377,7 +377,7 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
  * @buf:	buffer to store read data
  * @oob_required:	caller expects OOB data read to chip->oob_poi
  *
- * The hw generator calculates the error syndrome automatically. Therefor
+ * The hw generator calculates the error syndrome automatically. Therefore
  * we need a special oob layout and handling.
  */
 static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 7842938..22bb5e6 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -805,7 +805,6 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
 	chip->bbt_md = &bbt_mirror_descr;
 
 	/* set up nand options */
-	chip->options = NAND_NO_READRDY;
 	chip->bbt_options = NAND_BBT_USE_FLASH;
 
 	chip->controller = &elbc_fcm_ctrl->controller;
@@ -916,7 +915,8 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
 	elbc_fcm_ctrl->chips[bank] = priv;
 	priv->bank = bank;
 	priv->ctrl = fsl_lbc_ctrl_dev;
-	priv->dev = dev;
+	priv->dev = &pdev->dev;
+	dev_set_drvdata(priv->dev, priv);
 
 	priv->vbase = ioremap(res.start, resource_size(&res));
 	if (!priv->vbase) {
@@ -963,11 +963,10 @@ err:
 
 static int fsl_elbc_nand_remove(struct platform_device *pdev)
 {
-	int i;
 	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
-	for (i = 0; i < MAX_BANKS; i++)
-		if (elbc_fcm_ctrl->chips[i])
-			fsl_elbc_chip_remove(elbc_fcm_ctrl->chips[i]);
+	struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
+
+	fsl_elbc_chip_remove(priv);
 
 	mutex_lock(&fsl_elbc_nand_mutex);
 	elbc_fcm_ctrl->counter--;
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 9602c1b..c5d7f38 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -805,7 +805,6 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 	out_be32(&ifc->ifc_nand.ncfgr, 0x0);
 
 	/* set up nand options */
-	chip->options = NAND_NO_READRDY;
 	chip->bbt_options = NAND_BBT_USE_FLASH;
 
 
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index a05b7b4..a5deb70 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1064,6 +1064,9 @@ exit_auxiliary:
  * ECC-based or raw view of the page is implicit in which function it calls
  * (there is a similar pair of ECC-based/raw functions for writing).
  *
+ * FIXME: The following paragraph is incorrect, now that there exist
+ * ecc.read_oob_raw and ecc.write_oob_raw functions.
+ *
  * Since MTD assumes the OOB is not covered by ECC, there is no pair of
  * ECC-based/raw functions for reading or or writing the OOB. The fact that the
  * caller wants an ECC-based or raw view of the page is not propagated down to
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index a6fa884..100b677 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -52,9 +52,10 @@
 
 #define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1)
 #define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1)
+#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa
 
-#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
 #define JZ_NAND_MEM_CMD_OFFSET 0x08000
+#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
 
 struct jz_nand {
 	struct mtd_info mtd;
@@ -62,8 +63,11 @@ struct jz_nand {
 	void __iomem *base;
 	struct resource *mem;
 
-	void __iomem *bank_base;
-	struct resource *bank_mem;
+	unsigned char banks[JZ_NAND_NUM_BANKS];
+	void __iomem *bank_base[JZ_NAND_NUM_BANKS];
+	struct resource *bank_mem[JZ_NAND_NUM_BANKS];
+
+	int selected_bank;
 
 	struct jz_nand_platform_data *pdata;
 	bool is_reading;
@@ -74,26 +78,50 @@ static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
 	return container_of(mtd, struct jz_nand, mtd);
 }
 
+static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
+{
+	struct jz_nand *nand = mtd_to_jz_nand(mtd);
+	struct nand_chip *chip = mtd->priv;
+	uint32_t ctrl;
+	int banknr;
+
+	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
+	ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK;
+
+	if (chipnr == -1) {
+		banknr = -1;
+	} else {
+		banknr = nand->banks[chipnr] - 1;
+		chip->IO_ADDR_R = nand->bank_base[banknr];
+		chip->IO_ADDR_W = nand->bank_base[banknr];
+	}
+	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+
+	nand->selected_bank = banknr;
+}
+
 static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
 {
 	struct jz_nand *nand = mtd_to_jz_nand(mtd);
 	struct nand_chip *chip = mtd->priv;
 	uint32_t reg;
+	void __iomem *bank_base = nand->bank_base[nand->selected_bank];
+
+	BUG_ON(nand->selected_bank < 0);
 
 	if (ctrl & NAND_CTRL_CHANGE) {
 		BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
 		if (ctrl & NAND_ALE)
-			chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_ADDR_OFFSET;
+			bank_base += JZ_NAND_MEM_ADDR_OFFSET;
 		else if (ctrl & NAND_CLE)
-			chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_CMD_OFFSET;
-		else
-			chip->IO_ADDR_W = nand->bank_base;
+			bank_base += JZ_NAND_MEM_CMD_OFFSET;
+		chip->IO_ADDR_W = bank_base;
 
 		reg = readl(nand->base + JZ_REG_NAND_CTRL);
 		if (ctrl & NAND_NCE)
-			reg |= JZ_NAND_CTRL_ASSERT_CHIP(0);
+			reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
 		else
-			reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0);
+			reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
 		writel(reg, nand->base + JZ_REG_NAND_CTRL);
 	}
 	if (dat != NAND_CMD_NONE)
@@ -252,7 +280,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
 }
 
 static int jz_nand_ioremap_resource(struct platform_device *pdev,
-	const char *name, struct resource **res, void __iomem **base)
+	const char *name, struct resource **res, void *__iomem *base)
 {
 	int ret;
 
@@ -288,6 +316,90 @@ err:
 	return ret;
 }
 
+static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base)
+{
+	iounmap(base);
+	release_mem_region(res->start, resource_size(res));
+}
+
+static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) {
+	int ret;
+	int gpio;
+	char gpio_name[9];
+	char res_name[6];
+	uint32_t ctrl;
+	struct mtd_info *mtd = &nand->mtd;
+	struct nand_chip *chip = &nand->chip;
+
+	/* Request GPIO port. */
+	gpio = JZ_GPIO_MEM_CS0 + bank - 1;
+	sprintf(gpio_name, "NAND CS%d", bank);
+	ret = gpio_request(gpio, gpio_name);
+	if (ret) {
+		dev_warn(&pdev->dev,
+			"Failed to request %s gpio %d: %d\n",
+			gpio_name, gpio, ret);
+		goto notfound_gpio;
+	}
+
+	/* Request I/O resource. */
+	sprintf(res_name, "bank%d", bank);
+	ret = jz_nand_ioremap_resource(pdev, res_name,
+					&nand->bank_mem[bank - 1],
+					&nand->bank_base[bank - 1]);
+	if (ret)
+		goto notfound_resource;
+
+	/* Enable chip in bank. */
+	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0);
+	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
+	ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
+	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+
+	if (chipnr == 0) {
+		/* Detect first chip. */
+		ret = nand_scan_ident(mtd, 1, NULL);
+		if (ret)
+			goto notfound_id;
+
+		/* Retrieve the IDs from the first chip. */
+		chip->select_chip(mtd, 0);
+		chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+		*nand_maf_id = chip->read_byte(mtd);
+		*nand_dev_id = chip->read_byte(mtd);
+	} else {
+		/* Detect additional chip. */
+		chip->select_chip(mtd, chipnr);
+		chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+		if (*nand_maf_id != chip->read_byte(mtd)
+		 || *nand_dev_id != chip->read_byte(mtd)) {
+			ret = -ENODEV;
+			goto notfound_id;
+		}
+
+		/* Update size of the MTD. */
+		chip->numchips++;
+		mtd->size += chip->chipsize;
+	}
+
+	dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank);
+	return 0;
+
+notfound_id:
+	dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
+	ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
+	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
+	jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+				 nand->bank_base[bank - 1]);
+notfound_resource:
+	gpio_free(gpio);
+notfound_gpio:
+	return ret;
+}
+
 static int __devinit jz_nand_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -295,6 +407,8 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
 	struct nand_chip *chip;
 	struct mtd_info *mtd;
 	struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
+	size_t chipnr, bank_idx;
+	uint8_t nand_maf_id = 0, nand_dev_id = 0;
 
 	nand = kzalloc(sizeof(*nand), GFP_KERNEL);
 	if (!nand) {
@@ -305,10 +419,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
 	ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
 	if (ret)
 		goto err_free;
-	ret = jz_nand_ioremap_resource(pdev, "bank", &nand->bank_mem,
-			&nand->bank_base);
-	if (ret)
-		goto err_iounmap_mmio;
 
 	if (pdata && gpio_is_valid(pdata->busy_gpio)) {
 		ret = gpio_request(pdata->busy_gpio, "NAND busy pin");
@@ -316,7 +426,7 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev,
 				"Failed to request busy gpio %d: %d\n",
 				pdata->busy_gpio, ret);
-			goto err_iounmap_mem;
+			goto err_iounmap_mmio;
 		}
 	}
 
@@ -339,22 +449,51 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
 
 	chip->chip_delay = 50;
 	chip->cmd_ctrl = jz_nand_cmd_ctrl;
+	chip->select_chip = jz_nand_select_chip;
 
 	if (pdata && gpio_is_valid(pdata->busy_gpio))
 		chip->dev_ready = jz_nand_dev_ready;
 
-	chip->IO_ADDR_R = nand->bank_base;
-	chip->IO_ADDR_W = nand->bank_base;
-
 	nand->pdata = pdata;
 	platform_set_drvdata(pdev, nand);
 
-	writel(JZ_NAND_CTRL_ENABLE_CHIP(0), nand->base + JZ_REG_NAND_CTRL);
-
-	ret = nand_scan_ident(mtd, 1, NULL);
-	if (ret) {
-		dev_err(&pdev->dev,  "Failed to scan nand\n");
-		goto err_gpio_free;
+	/* We are going to autodetect NAND chips in the banks specified in the
+	 * platform data. Although nand_scan_ident() can detect multiple chips,
+	 * it requires those chips to be numbered consecuitively, which is not
+	 * always the case for external memory banks. And a fixed chip-to-bank
+	 * mapping is not practical either, since for example Dingoo units
+	 * produced at different times have NAND chips in different banks.
+	 */
+	chipnr = 0;
+	for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) {
+		unsigned char bank;
+
+		/* If there is no platform data, look for NAND in bank 1,
+		 * which is the most likely bank since it is the only one
+		 * that can be booted from.
+		 */
+		bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1;
+		if (bank == 0)
+			break;
+		if (bank > JZ_NAND_NUM_BANKS) {
+			dev_warn(&pdev->dev,
+				"Skipping non-existing bank: %d\n", bank);
+			continue;
+		}
+		/* The detection routine will directly or indirectly call
+		 * jz_nand_select_chip(), so nand->banks has to contain the
+		 * bank we're checking.
+		 */
+		nand->banks[chipnr] = bank;
+		if (jz_nand_detect_bank(pdev, nand, bank, chipnr,
+					&nand_maf_id, &nand_dev_id) == 0)
+			chipnr++;
+		else
+			nand->banks[chipnr] = 0;
+	}
+	if (chipnr == 0) {
+		dev_err(&pdev->dev, "No NAND chips found\n");
+		goto err_gpio_busy;
 	}
 
 	if (pdata && pdata->ident_callback) {
@@ -364,8 +503,8 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
 
 	ret = nand_scan_tail(mtd);
 	if (ret) {
-		dev_err(&pdev->dev,  "Failed to scan nand\n");
-		goto err_gpio_free;
+		dev_err(&pdev->dev,  "Failed to scan NAND\n");
+		goto err_unclaim_banks;
 	}
 
 	ret = mtd_device_parse_register(mtd, NULL, NULL,
@@ -382,14 +521,21 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
 	return 0;
 
 err_nand_release:
-	nand_release(&nand->mtd);
-err_gpio_free:
+	nand_release(mtd);
+err_unclaim_banks:
+	while (chipnr--) {
+		unsigned char bank = nand->banks[chipnr];
+		gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
+		jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+					 nand->bank_base[bank - 1]);
+	}
+	writel(0, nand->base + JZ_REG_NAND_CTRL);
+err_gpio_busy:
+	if (pdata && gpio_is_valid(pdata->busy_gpio))
+		gpio_free(pdata->busy_gpio);
 	platform_set_drvdata(pdev, NULL);
-	gpio_free(pdata->busy_gpio);
-err_iounmap_mem:
-	iounmap(nand->bank_base);
 err_iounmap_mmio:
-	iounmap(nand->base);
+	jz_nand_iounmap_resource(nand->mem, nand->base);
 err_free:
 	kfree(nand);
 	return ret;
@@ -398,16 +544,26 @@ err_free:
 static int __devexit jz_nand_remove(struct platform_device *pdev)
 {
 	struct jz_nand *nand = platform_get_drvdata(pdev);
+	struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
+	size_t i;
 
 	nand_release(&nand->mtd);
 
 	/* Deassert and disable all chips */
 	writel(0, nand->base + JZ_REG_NAND_CTRL);
 
-	iounmap(nand->bank_base);
-	release_mem_region(nand->bank_mem->start, resource_size(nand->bank_mem));
-	iounmap(nand->base);
-	release_mem_region(nand->mem->start, resource_size(nand->mem));
+	for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) {
+		unsigned char bank = nand->banks[i];
+		if (bank != 0) {
+			jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+						 nand->bank_base[bank - 1]);
+			gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
+		}
+	}
+	if (pdata && gpio_is_valid(pdata->busy_gpio))
+		gpio_free(pdata->busy_gpio);
+
+	jz_nand_iounmap_resource(nand->mem, nand->base);
 
 	platform_set_drvdata(pdev, NULL);
 	kfree(nand);
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
new file mode 100644
index 0000000..796e37b
--- /dev/null
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -0,0 +1,1060 @@
+/*
+ * NXP LPC32XX NAND SLC driver
+ *
+ * Authors:
+ *    Kevin Wells <kevin.wells@nxp.com>
+ *    Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright (C) 2011 NXP Semiconductors
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_mtd.h>
+#include <linux/of_gpio.h>
+#include <linux/amba/pl08x.h>
+
+#define LPC32XX_MODNAME		"lpc32xx-nand"
+
+/**********************************************************************
+* SLC NAND controller register offsets
+**********************************************************************/
+
+#define SLC_DATA(x)		(x + 0x000)
+#define SLC_ADDR(x)		(x + 0x004)
+#define SLC_CMD(x)		(x + 0x008)
+#define SLC_STOP(x)		(x + 0x00C)
+#define SLC_CTRL(x)		(x + 0x010)
+#define SLC_CFG(x)		(x + 0x014)
+#define SLC_STAT(x)		(x + 0x018)
+#define SLC_INT_STAT(x)		(x + 0x01C)
+#define SLC_IEN(x)		(x + 0x020)
+#define SLC_ISR(x)		(x + 0x024)
+#define SLC_ICR(x)		(x + 0x028)
+#define SLC_TAC(x)		(x + 0x02C)
+#define SLC_TC(x)		(x + 0x030)
+#define SLC_ECC(x)		(x + 0x034)
+#define SLC_DMA_DATA(x)		(x + 0x038)
+
+/**********************************************************************
+* slc_ctrl register definitions
+**********************************************************************/
+#define SLCCTRL_SW_RESET	(1 << 2) /* Reset the NAND controller bit */
+#define SLCCTRL_ECC_CLEAR	(1 << 1) /* Reset ECC bit */
+#define SLCCTRL_DMA_START	(1 << 0) /* Start DMA channel bit */
+
+/**********************************************************************
+* slc_cfg register definitions
+**********************************************************************/
+#define SLCCFG_CE_LOW		(1 << 5) /* Force CE low bit */
+#define SLCCFG_DMA_ECC		(1 << 4) /* Enable DMA ECC bit */
+#define SLCCFG_ECC_EN		(1 << 3) /* ECC enable bit */
+#define SLCCFG_DMA_BURST	(1 << 2) /* DMA burst bit */
+#define SLCCFG_DMA_DIR		(1 << 1) /* DMA write(0)/read(1) bit */
+#define SLCCFG_WIDTH		(1 << 0) /* External device width, 0=8bit */
+
+/**********************************************************************
+* slc_stat register definitions
+**********************************************************************/
+#define SLCSTAT_DMA_FIFO	(1 << 2) /* DMA FIFO has data bit */
+#define SLCSTAT_SLC_FIFO	(1 << 1) /* SLC FIFO has data bit */
+#define SLCSTAT_NAND_READY	(1 << 0) /* NAND device is ready bit */
+
+/**********************************************************************
+* slc_int_stat, slc_ien, slc_isr, and slc_icr register definitions
+**********************************************************************/
+#define SLCSTAT_INT_TC		(1 << 1) /* Transfer count bit */
+#define SLCSTAT_INT_RDY_EN	(1 << 0) /* Ready interrupt bit */
+
+/**********************************************************************
+* slc_tac register definitions
+**********************************************************************/
+/* Clock setting for RDY write sample wait time in 2*n clocks */
+#define SLCTAC_WDR(n)		(((n) & 0xF) << 28)
+/* Write pulse width in clock cycles, 1 to 16 clocks */
+#define SLCTAC_WWIDTH(n)	(((n) & 0xF) << 24)
+/* Write hold time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_WHOLD(n)		(((n) & 0xF) << 20)
+/* Write setup time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_WSETUP(n)	(((n) & 0xF) << 16)
+/* Clock setting for RDY read sample wait time in 2*n clocks */
+#define SLCTAC_RDR(n)		(((n) & 0xF) << 12)
+/* Read pulse width in clock cycles, 1 to 16 clocks */
+#define SLCTAC_RWIDTH(n)	(((n) & 0xF) << 8)
+/* Read hold time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_RHOLD(n)		(((n) & 0xF) << 4)
+/* Read setup time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_RSETUP(n)	(((n) & 0xF) << 0)
+
+/**********************************************************************
+* slc_ecc register definitions
+**********************************************************************/
+/* ECC line party fetch macro */
+#define SLCECC_TO_LINEPAR(n)	(((n) >> 6) & 0x7FFF)
+#define SLCECC_TO_COLPAR(n)	((n) & 0x3F)
+
+/*
+ * DMA requires storage space for the DMA local buffer and the hardware ECC
+ * storage area. The DMA local buffer is only used if DMA mapping fails
+ * during runtime.
+ */
+#define LPC32XX_DMA_DATA_SIZE		4096
+#define LPC32XX_ECC_SAVE_SIZE		((4096 / 256) * 4)
+
+/* Number of bytes used for ECC stored in NAND per 256 bytes */
+#define LPC32XX_SLC_DEV_ECC_BYTES	3
+
+/*
+ * If the NAND base clock frequency can't be fetched, this frequency will be
+ * used instead as the base. This rate is used to setup the timing registers
+ * used for NAND accesses.
+ */
+#define LPC32XX_DEF_BUS_RATE		133250000
+
+/* Milliseconds for DMA FIFO timeout (unlikely anyway) */
+#define LPC32XX_DMA_TIMEOUT		100
+
+/*
+ * NAND ECC Layout for small page NAND devices
+ * Note: For large and huge page devices, the default layouts are used
+ */
+static struct nand_ecclayout lpc32xx_nand_oob_16 = {
+	.eccbytes = 6,
+	.eccpos = {10, 11, 12, 13, 14, 15},
+	.oobfree = {
+		{ .offset = 0, .length = 4 },
+		{ .offset = 6, .length = 4 },
+	},
+};
+
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+/*
+ * Small page FLASH BBT descriptors, marker at offset 0, version at offset 6
+ * Note: Large page devices used the default layout
+ */
+static struct nand_bbt_descr bbt_smallpage_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs =	0,
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_smallpage_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs =	0,
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = mirror_pattern
+};
+
+/*
+ * NAND platform configuration structure
+ */
+struct lpc32xx_nand_cfg_slc {
+	u32     wdr_clks;
+	u32     wwidth;
+	u32     whold;
+	u32     wsetup;
+	u32     rdr_clks;
+	u32     rwidth;
+	u32     rhold;
+	u32     rsetup;
+	bool    use_bbt;
+	unsigned wp_gpio;
+	struct mtd_partition *parts;
+	unsigned num_parts;
+};
+
+struct lpc32xx_nand_host {
+	struct nand_chip	nand_chip;
+	struct clk		*clk;
+	struct mtd_info		mtd;
+	void __iomem		*io_base;
+	struct lpc32xx_nand_cfg_slc *ncfg;
+
+	struct completion	comp;
+	struct dma_chan		*dma_chan;
+	u32			dma_buf_len;
+	struct dma_slave_config	dma_slave_config;
+	struct scatterlist	sgl;
+
+	/*
+	 * DMA and CPU addresses of ECC work area and data buffer
+	 */
+	u32			*ecc_buf;
+	u8			*data_buf;
+	dma_addr_t		io_base_dma;
+};
+
+static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
+{
+	u32 clkrate, tmp;
+
+	/* Reset SLC controller */
+	writel(SLCCTRL_SW_RESET, SLC_CTRL(host->io_base));
+	udelay(1000);
+
+	/* Basic setup */
+	writel(0, SLC_CFG(host->io_base));
+	writel(0, SLC_IEN(host->io_base));
+	writel((SLCSTAT_INT_TC | SLCSTAT_INT_RDY_EN),
+		SLC_ICR(host->io_base));
+
+	/* Get base clock for SLC block */
+	clkrate = clk_get_rate(host->clk);
+	if (clkrate == 0)
+		clkrate = LPC32XX_DEF_BUS_RATE;
+
+	/* Compute clock setup values */
+	tmp = SLCTAC_WDR(host->ncfg->wdr_clks) |
+		SLCTAC_WWIDTH(1 + (clkrate / host->ncfg->wwidth)) |
+		SLCTAC_WHOLD(1 + (clkrate / host->ncfg->whold)) |
+		SLCTAC_WSETUP(1 + (clkrate / host->ncfg->wsetup)) |
+		SLCTAC_RDR(host->ncfg->rdr_clks) |
+		SLCTAC_RWIDTH(1 + (clkrate / host->ncfg->rwidth)) |
+		SLCTAC_RHOLD(1 + (clkrate / host->ncfg->rhold)) |
+		SLCTAC_RSETUP(1 + (clkrate / host->ncfg->rsetup));
+	writel(tmp, SLC_TAC(host->io_base));
+}
+
+/*
+ * Hardware specific access to control lines
+ */
+static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+	unsigned int ctrl)
+{
+	u32 tmp;
+	struct nand_chip *chip = mtd->priv;
+	struct lpc32xx_nand_host *host = chip->priv;
+
+	/* Does CE state need to be changed? */
+	tmp = readl(SLC_CFG(host->io_base));
+	if (ctrl & NAND_NCE)
+		tmp |= SLCCFG_CE_LOW;
+	else
+		tmp &= ~SLCCFG_CE_LOW;
+	writel(tmp, SLC_CFG(host->io_base));
+
+	if (cmd != NAND_CMD_NONE) {
+		if (ctrl & NAND_CLE)
+			writel(cmd, SLC_CMD(host->io_base));
+		else
+			writel(cmd, SLC_ADDR(host->io_base));
+	}
+}
+
+/*
+ * Read the Device Ready pin
+ */
+static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct lpc32xx_nand_host *host = chip->priv;
+	int rdy = 0;
+
+	if ((readl(SLC_STAT(host->io_base)) & SLCSTAT_NAND_READY) != 0)
+		rdy = 1;
+
+	return rdy;
+}
+
+/*
+ * Enable NAND write protect
+ */
+static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
+{
+	gpio_set_value(host->ncfg->wp_gpio, 0);
+}
+
+/*
+ * Disable NAND write protect
+ */
+static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
+{
+	gpio_set_value(host->ncfg->wp_gpio, 1);
+}
+
+/*
+ * Prepares SLC for transfers with H/W ECC enabled
+ */
+static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
+{
+	/* Hardware ECC is enabled automatically in hardware as needed */
+}
+
+/*
+ * Calculates the ECC for the data
+ */
+static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
+				      const unsigned char *buf,
+				      unsigned char *code)
+{
+	/*
+	 * ECC is calculated automatically in hardware during syndrome read
+	 * and write operations, so it doesn't need to be calculated here.
+	 */
+	return 0;
+}
+
+/*
+ * Read a single byte from NAND device
+ */
+static u8 lpc32xx_nand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct lpc32xx_nand_host *host = chip->priv;
+
+	return (u8)readl(SLC_DATA(host->io_base));
+}
+
+/*
+ * Simple device read without ECC
+ */
+static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct lpc32xx_nand_host *host = chip->priv;
+
+	/* Direct device read with no ECC */
+	while (len-- > 0)
+		*buf++ = (u8)readl(SLC_DATA(host->io_base));
+}
+
+/*
+ * Simple device write without ECC
+ */
+static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct lpc32xx_nand_host *host = chip->priv;
+
+	/* Direct device write with no ECC */
+	while (len-- > 0)
+		writel((u32)*buf++, SLC_DATA(host->io_base));
+}
+
+/*
+ * Verify data in buffer to data on device
+ */
+static int lpc32xx_verify_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct lpc32xx_nand_host *host = chip->priv;
+	int i;
+
+	/* DATA register must be read as 32 bits or it will fail */
+	for (i = 0; i < len; i++) {
+		if (buf[i] != (u8)readl(SLC_DATA(host->io_base)))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*
+ * Read the OOB data from the device without ECC using FIFO method
+ */
+static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
+					  struct nand_chip *chip, int page)
+{
+	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return 0;
+}
+
+/*
+ * Write the OOB data to the device without ECC using FIFO method
+ */
+static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
+	struct nand_chip *chip, int page)
+{
+	int status;
+
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	/* Send command to program the OOB data */
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+	status = chip->waitfunc(mtd, chip);
+
+	return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+/*
+ * Fills in the ECC fields in the OOB buffer with the hardware generated ECC
+ */
+static void lpc32xx_slc_ecc_copy(u8 *spare, const u32 *ecc, int count)
+{
+	int i;
+
+	for (i = 0; i < (count * 3); i += 3) {
+		u32 ce = ecc[i / 3];
+		ce = ~(ce << 2) & 0xFFFFFF;
+		spare[i + 2] = (u8)(ce & 0xFF);
+		ce >>= 8;
+		spare[i + 1] = (u8)(ce & 0xFF);
+		ce >>= 8;
+		spare[i] = (u8)(ce & 0xFF);
+	}
+}
+
+static void lpc32xx_dma_complete_func(void *completion)
+{
+	complete(completion);
+}
+
+static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma,
+			    void *mem, int len, enum dma_transfer_direction dir)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct lpc32xx_nand_host *host = chip->priv;
+	struct dma_async_tx_descriptor *desc;
+	int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+	int res;
+
+	host->dma_slave_config.direction = dir;
+	host->dma_slave_config.src_addr = dma;
+	host->dma_slave_config.dst_addr = dma;
+	host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	host->dma_slave_config.src_maxburst = 4;
+	host->dma_slave_config.dst_maxburst = 4;
+	/* DMA controller does flow control: */
+	host->dma_slave_config.device_fc = false;
+	if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
+		dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
+		return -ENXIO;
+	}
+
+	sg_init_one(&host->sgl, mem, len);
+
+	res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
+			 DMA_BIDIRECTIONAL);
+	if (res != 1) {
+		dev_err(mtd->dev.parent, "Failed to map sg list\n");
+		return -ENXIO;
+	}
+	desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
+				       flags);
+	if (!desc) {
+		dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
+		goto out1;
+	}
+
+	init_completion(&host->comp);
+	desc->callback = lpc32xx_dma_complete_func;
+	desc->callback_param = &host->comp;
+
+	dmaengine_submit(desc);
+	dma_async_issue_pending(host->dma_chan);
+
+	wait_for_completion_timeout(&host->comp, msecs_to_jiffies(1000));
+
+	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+		     DMA_BIDIRECTIONAL);
+
+	return 0;
+out1:
+	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+		     DMA_BIDIRECTIONAL);
+	return -ENXIO;
+}
+
+/*
+ * DMA read/write transfers with ECC support
+ */
+static int lpc32xx_xfer(struct mtd_info *mtd, u8 *buf, int eccsubpages,
+			int read)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct lpc32xx_nand_host *host = chip->priv;
+	int i, status = 0;
+	unsigned long timeout;
+	int res;
+	enum dma_transfer_direction dir =
+		read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
+	u8 *dma_buf;
+	bool dma_mapped;
+
+	if ((void *)buf <= high_memory) {
+		dma_buf = buf;
+		dma_mapped = true;
+	} else {
+		dma_buf = host->data_buf;
+		dma_mapped = false;
+		if (!read)
+			memcpy(host->data_buf, buf, mtd->writesize);
+	}
+
+	if (read) {
+		writel(readl(SLC_CFG(host->io_base)) |
+		       SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
+		       SLCCFG_DMA_BURST, SLC_CFG(host->io_base));
+	} else {
+		writel((readl(SLC_CFG(host->io_base)) |
+			SLCCFG_ECC_EN | SLCCFG_DMA_ECC | SLCCFG_DMA_BURST) &
+		       ~SLCCFG_DMA_DIR,
+			SLC_CFG(host->io_base));
+	}
+
+	/* Clear initial ECC */
+	writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base));
+
+	/* Transfer size is data area only */
+	writel(mtd->writesize, SLC_TC(host->io_base));
+
+	/* Start transfer in the NAND controller */
+	writel(readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START,
+	       SLC_CTRL(host->io_base));
+
+	for (i = 0; i < chip->ecc.steps; i++) {
+		/* Data */
+		res = lpc32xx_xmit_dma(mtd, SLC_DMA_DATA(host->io_base_dma),
+				       dma_buf + i * chip->ecc.size,
+				       mtd->writesize / chip->ecc.steps, dir);
+		if (res)
+			return res;
+
+		/* Always _read_ ECC */
+		if (i == chip->ecc.steps - 1)
+			break;
+		if (!read) /* ECC availability delayed on write */
+			udelay(10);
+		res = lpc32xx_xmit_dma(mtd, SLC_ECC(host->io_base_dma),
+				       &host->ecc_buf[i], 4, DMA_DEV_TO_MEM);
+		if (res)
+			return res;
+	}
+
+	/*
+	 * According to NXP, the DMA can be finished here, but the NAND
+	 * controller may still have buffered data. After porting to using the
+	 * dmaengine DMA driver (amba-pl080), the condition (DMA_FIFO empty)
+	 * appears to be always true, according to tests. Keeping the check for
+	 * safety reasons for now.
+	 */
+	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) {
+		dev_warn(mtd->dev.parent, "FIFO not empty!\n");
+		timeout = jiffies + msecs_to_jiffies(LPC32XX_DMA_TIMEOUT);
+		while ((readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) &&
+		       time_before(jiffies, timeout))
+			cpu_relax();
+		if (!time_before(jiffies, timeout)) {
+			dev_err(mtd->dev.parent, "FIFO held data too long\n");
+			status = -EIO;
+		}
+	}
+
+	/* Read last calculated ECC value */
+	if (!read)
+		udelay(10);
+	host->ecc_buf[chip->ecc.steps - 1] =
+		readl(SLC_ECC(host->io_base));
+
+	/* Flush DMA */
+	dmaengine_terminate_all(host->dma_chan);
+
+	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO ||
+	    readl(SLC_TC(host->io_base))) {
+		/* Something is left in the FIFO, something is wrong */
+		dev_err(mtd->dev.parent, "DMA FIFO failure\n");
+		status = -EIO;
+	}
+
+	/* Stop DMA & HW ECC */
+	writel(readl(SLC_CTRL(host->io_base)) & ~SLCCTRL_DMA_START,
+	       SLC_CTRL(host->io_base));
+	writel(readl(SLC_CFG(host->io_base)) &
+	       ~(SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
+		 SLCCFG_DMA_BURST), SLC_CFG(host->io_base));
+
+	if (!dma_mapped && read)
+		memcpy(buf, host->data_buf, mtd->writesize);
+
+	return status;
+}
+
+/*
+ * Read the data and OOB data from the device, use ECC correction with the
+ * data, disable ECC for the OOB data
+ */
+static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
+					   struct nand_chip *chip, u8 *buf,
+					   int oob_required, int page)
+{
+	struct lpc32xx_nand_host *host = chip->priv;
+	int stat, i, status;
+	u8 *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE];
+
+	/* Issue read command */
+	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+	/* Read data and oob, calculate ECC */
+	status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
+
+	/* Get OOB data */
+	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	/* Convert to stored ECC format */
+	lpc32xx_slc_ecc_copy(tmpecc, (u32 *) host->ecc_buf, chip->ecc.steps);
+
+	/* Pointer to ECC data retrieved from NAND spare area */
+	oobecc = chip->oob_poi + chip->ecc.layout->eccpos[0];
+
+	for (i = 0; i < chip->ecc.steps; i++) {
+		stat = chip->ecc.correct(mtd, buf, oobecc,
+					 &tmpecc[i * chip->ecc.bytes]);
+		if (stat < 0)
+			mtd->ecc_stats.failed++;
+		else
+			mtd->ecc_stats.corrected += stat;
+
+		buf += chip->ecc.size;
+		oobecc += chip->ecc.bytes;
+	}
+
+	return status;
+}
+
+/*
+ * Read the data and OOB data from the device, no ECC correction with the
+ * data or OOB data
+ */
+static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
+					       struct nand_chip *chip,
+					       u8 *buf, int oob_required,
+					       int page)
+{
+	/* Issue read command */
+	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+	/* Raw reads can just use the FIFO interface */
+	chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
+	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return 0;
+}
+
+/*
+ * Write the data and OOB data to the device, use ECC with the data,
+ * disable ECC for the OOB data
+ */
+static void lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
+					     struct nand_chip *chip,
+					     const u8 *buf, int oob_required)
+{
+	struct lpc32xx_nand_host *host = chip->priv;
+	u8 *pb = chip->oob_poi + chip->ecc.layout->eccpos[0];
+
+	/* Write data, calculate ECC on outbound data */
+	lpc32xx_xfer(mtd, (u8 *)buf, chip->ecc.steps, 0);
+
+	/*
+	 * The calculated ECC needs some manual work done to it before
+	 * committing it to NAND. Process the calculated ECC and place
+	 * the resultant values directly into the OOB buffer. */
+	lpc32xx_slc_ecc_copy(pb, (u32 *)host->ecc_buf, chip->ecc.steps);
+
+	/* Write ECC data to device */
+	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
+
+/*
+ * Write the data and OOB data to the device, no ECC correction with the
+ * data or OOB data
+ */
+static void lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
+						 struct nand_chip *chip,
+						 const u8 *buf,
+						 int oob_required)
+{
+	/* Raw writes can just use the FIFO interface */
+	chip->write_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
+	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
+
+static bool lpc32xx_dma_filter(struct dma_chan *chan, void *param)
+{
+	struct pl08x_dma_chan *ch =
+		container_of(chan, struct pl08x_dma_chan, chan);
+
+	/* In LPC32xx's PL080 DMA wiring, the SLC NAND DMA signal is #1 */
+	if (ch->cd->min_signal == 1)
+		return true;
+	return false;
+}
+
+static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host)
+{
+	struct mtd_info *mtd = &host->mtd;
+	dma_cap_mask_t mask;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	host->dma_chan = dma_request_channel(mask, lpc32xx_dma_filter, NULL);
+	if (!host->dma_chan) {
+		dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
+{
+	struct lpc32xx_nand_cfg_slc *pdata;
+	struct device_node *np = dev->of_node;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "could not allocate memory for platform data\n");
+		return NULL;
+	}
+
+	of_property_read_u32(np, "nxp,wdr-clks", &pdata->wdr_clks);
+	of_property_read_u32(np, "nxp,wwidth", &pdata->wwidth);
+	of_property_read_u32(np, "nxp,whold", &pdata->whold);
+	of_property_read_u32(np, "nxp,wsetup", &pdata->wsetup);
+	of_property_read_u32(np, "nxp,rdr-clks", &pdata->rdr_clks);
+	of_property_read_u32(np, "nxp,rwidth", &pdata->rwidth);
+	of_property_read_u32(np, "nxp,rhold", &pdata->rhold);
+	of_property_read_u32(np, "nxp,rsetup", &pdata->rsetup);
+
+	if (!pdata->wdr_clks || !pdata->wwidth || !pdata->whold ||
+	    !pdata->wsetup || !pdata->rdr_clks || !pdata->rwidth ||
+	    !pdata->rhold || !pdata->rsetup) {
+		dev_err(dev, "chip parameters not specified correctly\n");
+		return NULL;
+	}
+
+	pdata->use_bbt = of_get_nand_on_flash_bbt(np);
+	pdata->wp_gpio = of_get_named_gpio_flags(np, "gpios", 0, NULL);
+
+	return pdata;
+}
+#else
+static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
+{
+	return NULL;
+}
+#endif
+
+/*
+ * Probe for NAND controller
+ */
+static int __devinit lpc32xx_nand_probe(struct platform_device *pdev)
+{
+	struct lpc32xx_nand_host *host;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+	struct resource *rc;
+	struct mtd_part_parser_data ppdata = {};
+	int res;
+
+	rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (rc == NULL) {
+		dev_err(&pdev->dev, "No memory resource found for device\n");
+		return -EBUSY;
+	}
+
+	/* Allocate memory for the device structure (and zero it) */
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+	if (!host) {
+		dev_err(&pdev->dev, "failed to allocate device structure\n");
+		return -ENOMEM;
+	}
+	host->io_base_dma = rc->start;
+
+	host->io_base = devm_request_and_ioremap(&pdev->dev, rc);
+	if (host->io_base == NULL) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		return -ENOMEM;
+	}
+
+	if (pdev->dev.of_node)
+		host->ncfg = lpc32xx_parse_dt(&pdev->dev);
+	else
+		host->ncfg = pdev->dev.platform_data;
+	if (!host->ncfg) {
+		dev_err(&pdev->dev, "Missing platform data\n");
+		return -ENOENT;
+	}
+	if (gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
+		dev_err(&pdev->dev, "GPIO not available\n");
+		return -EBUSY;
+	}
+	lpc32xx_wp_disable(host);
+
+	mtd = &host->mtd;
+	chip = &host->nand_chip;
+	chip->priv = host;
+	mtd->priv = chip;
+	mtd->owner = THIS_MODULE;
+	mtd->dev.parent = &pdev->dev;
+
+	/* Get NAND clock */
+	host->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(host->clk)) {
+		dev_err(&pdev->dev, "Clock failure\n");
+		res = -ENOENT;
+		goto err_exit1;
+	}
+	clk_enable(host->clk);
+
+	/* Set NAND IO addresses and command/ready functions */
+	chip->IO_ADDR_R = SLC_DATA(host->io_base);
+	chip->IO_ADDR_W = SLC_DATA(host->io_base);
+	chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+	chip->dev_ready = lpc32xx_nand_device_ready;
+	chip->chip_delay = 20; /* 20us command delay time */
+
+	/* Init NAND controller */
+	lpc32xx_nand_setup(host);
+
+	platform_set_drvdata(pdev, host);
+
+	/* NAND callbacks for LPC32xx SLC hardware */
+	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+	chip->read_byte = lpc32xx_nand_read_byte;
+	chip->read_buf = lpc32xx_nand_read_buf;
+	chip->write_buf = lpc32xx_nand_write_buf;
+	chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome;
+	chip->ecc.read_page = lpc32xx_nand_read_page_syndrome;
+	chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome;
+	chip->ecc.write_page = lpc32xx_nand_write_page_syndrome;
+	chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome;
+	chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome;
+	chip->ecc.calculate = lpc32xx_nand_ecc_calculate;
+	chip->ecc.correct = nand_correct_data;
+	chip->ecc.strength = 1;
+	chip->ecc.hwctl = lpc32xx_nand_ecc_enable;
+	chip->verify_buf = lpc32xx_verify_buf;
+
+	/* bitflip_threshold's default is defined as ecc_strength anyway.
+	 * Unfortunately, it is set only later at add_mtd_device(). Meanwhile
+	 * being 0, it causes bad block table scanning errors in
+	 * nand_scan_tail(), so preparing it here already. */
+	mtd->bitflip_threshold = chip->ecc.strength;
+
+	/*
+	 * Allocate a large enough buffer for a single huge page plus
+	 * extra space for the spare area and ECC storage area
+	 */
+	host->dma_buf_len = LPC32XX_DMA_DATA_SIZE + LPC32XX_ECC_SAVE_SIZE;
+	host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len,
+				      GFP_KERNEL);
+	if (host->data_buf == NULL) {
+		dev_err(&pdev->dev, "Error allocating memory\n");
+		res = -ENOMEM;
+		goto err_exit2;
+	}
+
+	res = lpc32xx_nand_dma_setup(host);
+	if (res) {
+		res = -EIO;
+		goto err_exit2;
+	}
+
+	/* Find NAND device */
+	if (nand_scan_ident(mtd, 1, NULL)) {
+		res = -ENXIO;
+		goto err_exit3;
+	}
+
+	/* OOB and ECC CPU and DMA work areas */
+	host->ecc_buf = (u32 *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
+
+	/*
+	 * Small page FLASH has a unique OOB layout, but large and huge
+	 * page FLASH use the standard layout. Small page FLASH uses a
+	 * custom BBT marker layout.
+	 */
+	if (mtd->writesize <= 512)
+		chip->ecc.layout = &lpc32xx_nand_oob_16;
+
+	/* These sizes remain the same regardless of page size */
+	chip->ecc.size = 256;
+	chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
+	chip->ecc.prepad = chip->ecc.postpad = 0;
+
+	/* Avoid extra scan if using BBT, setup BBT support */
+	if (host->ncfg->use_bbt) {
+		chip->options |= NAND_SKIP_BBTSCAN;
+		chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+		/*
+		 * Use a custom BBT marker setup for small page FLASH that
+		 * won't interfere with the ECC layout. Large and huge page
+		 * FLASH use the standard layout.
+		 */
+		if (mtd->writesize <= 512) {
+			chip->bbt_td = &bbt_smallpage_main_descr;
+			chip->bbt_md = &bbt_smallpage_mirror_descr;
+		}
+	}
+
+	/*
+	 * Fills out all the uninitialized function pointers with the defaults
+	 */
+	if (nand_scan_tail(mtd)) {
+		res = -ENXIO;
+		goto err_exit3;
+	}
+
+	/* Standard layout in FLASH for bad block tables */
+	if (host->ncfg->use_bbt) {
+		if (nand_default_bbt(mtd) < 0)
+			dev_err(&pdev->dev,
+			       "Error initializing default bad block tables\n");
+	}
+
+	mtd->name = "nxp_lpc3220_slc";
+	ppdata.of_node = pdev->dev.of_node;
+	res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts,
+					host->ncfg->num_parts);
+	if (!res)
+		return res;
+
+	nand_release(mtd);
+
+err_exit3:
+	dma_release_channel(host->dma_chan);
+err_exit2:
+	clk_disable(host->clk);
+	clk_put(host->clk);
+	platform_set_drvdata(pdev, NULL);
+err_exit1:
+	lpc32xx_wp_enable(host);
+	gpio_free(host->ncfg->wp_gpio);
+
+	return res;
+}
+
+/*
+ * Remove NAND device.
+ */
+static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
+{
+	u32 tmp;
+	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+	struct mtd_info *mtd = &host->mtd;
+
+	nand_release(mtd);
+	dma_release_channel(host->dma_chan);
+
+	/* Force CE high */
+	tmp = readl(SLC_CTRL(host->io_base));
+	tmp &= ~SLCCFG_CE_LOW;
+	writel(tmp, SLC_CTRL(host->io_base));
+
+	clk_disable(host->clk);
+	clk_put(host->clk);
+	platform_set_drvdata(pdev, NULL);
+	lpc32xx_wp_enable(host);
+	gpio_free(host->ncfg->wp_gpio);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_nand_resume(struct platform_device *pdev)
+{
+	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+	/* Re-enable NAND clock */
+	clk_enable(host->clk);
+
+	/* Fresh init of NAND controller */
+	lpc32xx_nand_setup(host);
+
+	/* Disable write protect */
+	lpc32xx_wp_disable(host);
+
+	return 0;
+}
+
+static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
+{
+	u32 tmp;
+	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+	/* Force CE high */
+	tmp = readl(SLC_CTRL(host->io_base));
+	tmp &= ~SLCCFG_CE_LOW;
+	writel(tmp, SLC_CTRL(host->io_base));
+
+	/* Enable write protect for safety */
+	lpc32xx_wp_enable(host);
+
+	/* Disable clock */
+	clk_disable(host->clk);
+
+	return 0;
+}
+
+#else
+#define lpc32xx_nand_resume NULL
+#define lpc32xx_nand_suspend NULL
+#endif
+
+#if defined(CONFIG_OF)
+static const struct of_device_id lpc32xx_nand_match[] = {
+	{ .compatible = "nxp,lpc3220-slc" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
+#endif
+
+static struct platform_driver lpc32xx_nand_driver = {
+	.probe		= lpc32xx_nand_probe,
+	.remove		= __devexit_p(lpc32xx_nand_remove),
+	.resume		= lpc32xx_nand_resume,
+	.suspend	= lpc32xx_nand_suspend,
+	.driver		= {
+		.name	= LPC32XX_MODNAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(lpc32xx_nand_match),
+	},
+};
+
+module_platform_driver(lpc32xx_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX SLC controller");
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index c58e6a9..df8489a 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -43,8 +43,8 @@
 
 #define nfc_is_v21()		(cpu_is_mx25() || cpu_is_mx35())
 #define nfc_is_v1()		(cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21())
-#define nfc_is_v3_2()		(cpu_is_mx51() || cpu_is_mx53())
-#define nfc_is_v3()		nfc_is_v3_2()
+#define nfc_is_v3_2a()		cpu_is_mx51()
+#define nfc_is_v3_2b()		cpu_is_mx53()
 
 /* Addresses for NFC registers */
 #define NFC_V1_V2_BUF_SIZE		(host->regs + 0x00)
@@ -122,7 +122,7 @@
 #define NFC_V3_CONFIG2_2CMD_PHASES		(1 << 4)
 #define NFC_V3_CONFIG2_NUM_ADDR_PHASE0		(1 << 5)
 #define NFC_V3_CONFIG2_ECC_MODE_8		(1 << 6)
-#define NFC_V3_CONFIG2_PPB(x)			(((x) & 0x3) << 7)
+#define NFC_V3_CONFIG2_PPB(x, shift)		(((x) & 0x3) << shift)
 #define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x)	(((x) & 0x3) << 12)
 #define NFC_V3_CONFIG2_INT_MSK			(1 << 15)
 #define NFC_V3_CONFIG2_ST_CMD(x)		(((x) & 0xff) << 24)
@@ -174,6 +174,7 @@ struct mxc_nand_devtype_data {
 	int spare_len;
 	int eccbytes;
 	int eccsize;
+	int ppb_shift;
 };
 
 struct mxc_nand_host {
@@ -764,7 +765,7 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
 	if (chip == -1) {
 		/* Disable the NFC clock */
 		if (host->clk_act) {
-			clk_disable(host->clk);
+			clk_disable_unprepare(host->clk);
 			host->clk_act = 0;
 		}
 		return;
@@ -772,7 +773,7 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
 
 	if (!host->clk_act) {
 		/* Enable the NFC clock */
-		clk_enable(host->clk);
+		clk_prepare_enable(host->clk);
 		host->clk_act = 1;
 	}
 
@@ -1001,7 +1002,9 @@ static void preset_v3(struct mtd_info *mtd)
 	}
 
 	if (mtd->writesize) {
-		config2 |= NFC_V3_CONFIG2_PPB(ffs(mtd->erasesize / mtd->writesize) - 6);
+		config2 |= NFC_V3_CONFIG2_PPB(
+				ffs(mtd->erasesize / mtd->writesize) - 6,
+				host->devtype_data->ppb_shift);
 		host->eccsize = get_eccsize(mtd);
 		if (host->eccsize == 8)
 			config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
@@ -1213,7 +1216,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
 	.eccsize = 0,
 };
 
-/* v3: i.MX51, i.MX53 */
+/* v3.2a: i.MX51 */
 static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
 	.preset = preset_v3,
 	.send_cmd = send_cmd_v3,
@@ -1237,6 +1240,34 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
 	.spare_len = 64,
 	.eccbytes = 0,
 	.eccsize = 0,
+	.ppb_shift = 7,
+};
+
+/* v3.2b: i.MX53 */
+static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
+	.preset = preset_v3,
+	.send_cmd = send_cmd_v3,
+	.send_addr = send_addr_v3,
+	.send_page = send_page_v3,
+	.send_read_id = send_read_id_v3,
+	.get_dev_status = get_dev_status_v3,
+	.check_int = check_int_v3,
+	.irq_control = irq_control_v3,
+	.get_ecc_status = get_ecc_status_v3,
+	.ecclayout_512 = &nandv2_hw_eccoob_smallpage,
+	.ecclayout_2k = &nandv2_hw_eccoob_largepage,
+	.ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
+	.select_chip = mxc_nand_select_chip_v1_v3,
+	.correct_data = mxc_nand_correct_data_v2_v3,
+	.irqpending_quirk = 0,
+	.needs_ip = 1,
+	.regs_offset = 0,
+	.spare0_offset = 0x1000,
+	.axi_offset = 0x1e00,
+	.spare_len = 64,
+	.eccbytes = 0,
+	.eccsize = 0,
+	.ppb_shift = 8,
 };
 
 #ifdef CONFIG_OF_MTD
@@ -1253,6 +1284,9 @@ static const struct of_device_id mxcnd_dt_ids[] = {
 	}, {
 		.compatible = "fsl,imx51-nand",
 		.data = &imx51_nand_devtype_data,
+	}, {
+		.compatible = "fsl,imx53-nand",
+		.data = &imx53_nand_devtype_data,
 	},
 	{ /* sentinel */ }
 };
@@ -1306,8 +1340,10 @@ static int __init mxcnd_probe_pdata(struct mxc_nand_host *host)
 			host->devtype_data = &imx27_nand_devtype_data;
 	} else if (nfc_is_v21()) {
 		host->devtype_data = &imx25_nand_devtype_data;
-	} else if (nfc_is_v3_2()) {
+	} else if (nfc_is_v3_2a()) {
 		host->devtype_data = &imx51_nand_devtype_data;
+	} else if (nfc_is_v3_2b()) {
+		host->devtype_data = &imx53_nand_devtype_data;
 	} else
 		BUG();
 
@@ -1323,8 +1359,8 @@ static int __init mxcnd_probe(struct platform_device *pdev)
 	int err = 0;
 
 	/* Allocate memory for MTD device structure and private data */
-	host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE +
-			NAND_MAX_OOBSIZE, GFP_KERNEL);
+	host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host) +
+			NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL);
 	if (!host)
 		return -ENOMEM;
 
@@ -1351,34 +1387,37 @@ static int __init mxcnd_probe(struct platform_device *pdev)
 	this->read_buf = mxc_nand_read_buf;
 	this->verify_buf = mxc_nand_verify_buf;
 
-	host->clk = clk_get(&pdev->dev, "nfc");
-	if (IS_ERR(host->clk)) {
-		err = PTR_ERR(host->clk);
-		goto eclk;
-	}
+	host->clk = devm_clk_get(&pdev->dev, "nfc");
+	if (IS_ERR(host->clk))
+		return PTR_ERR(host->clk);
 
-	clk_prepare_enable(host->clk);
-	host->clk_act = 1;
+	err = mxcnd_probe_dt(host);
+	if (err > 0)
+		err = mxcnd_probe_pdata(host);
+	if (err < 0)
+		return err;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		err = -ENODEV;
-		goto eres;
-	}
+	if (host->devtype_data->needs_ip) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!res)
+			return -ENODEV;
+		host->regs_ip = devm_request_and_ioremap(&pdev->dev, res);
+		if (!host->regs_ip)
+			return -ENOMEM;
 
-	host->base = ioremap(res->start, resource_size(res));
-	if (!host->base) {
-		err = -ENOMEM;
-		goto eres;
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	} else {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	}
 
-	host->main_area0 = host->base;
+	if (!res)
+		return -ENODEV;
 
-	err = mxcnd_probe_dt(host);
-	if (err > 0)
-		err = mxcnd_probe_pdata(host);
-	if (err < 0)
-		goto eirq;
+	host->base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!host->base)
+		return -ENOMEM;
+
+	host->main_area0 = host->base;
 
 	if (host->devtype_data->regs_offset)
 		host->regs = host->base + host->devtype_data->regs_offset;
@@ -1393,19 +1432,6 @@ static int __init mxcnd_probe(struct platform_device *pdev)
 	this->ecc.size = 512;
 	this->ecc.layout = host->devtype_data->ecclayout_512;
 
-	if (host->devtype_data->needs_ip) {
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-		if (!res) {
-			err = -ENODEV;
-			goto eirq;
-		}
-		host->regs_ip = ioremap(res->start, resource_size(res));
-		if (!host->regs_ip) {
-			err = -ENOMEM;
-			goto eirq;
-		}
-	}
-
 	if (host->pdata.hw_ecc) {
 		this->ecc.calculate = mxc_nand_calculate_ecc;
 		this->ecc.hwctl = mxc_nand_enable_hwecc;
@@ -1437,9 +1463,13 @@ static int __init mxcnd_probe(struct platform_device *pdev)
 	 */
 	host->devtype_data->irq_control(host, 0);
 
-	err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host);
+	err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
+			IRQF_DISABLED, DRIVER_NAME, host);
 	if (err)
-		goto eirq;
+		return err;
+
+	clk_prepare_enable(host->clk);
+	host->clk_act = 1;
 
 	/*
 	 * Now that we "own" the interrupt make sure the interrupt mask bit is
@@ -1491,15 +1521,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
 	return 0;
 
 escan:
-	free_irq(host->irq, host);
-eirq:
-	if (host->regs_ip)
-		iounmap(host->regs_ip);
-	iounmap(host->base);
-eres:
-	clk_put(host->clk);
-eclk:
-	kfree(host);
+	clk_disable_unprepare(host->clk);
 
 	return err;
 }
@@ -1508,16 +1530,9 @@ static int __devexit mxcnd_remove(struct platform_device *pdev)
 {
 	struct mxc_nand_host *host = platform_get_drvdata(pdev);
 
-	clk_put(host->clk);
-
 	platform_set_drvdata(pdev, NULL);
 
 	nand_release(&host->mtd);
-	free_irq(host->irq, host);
-	if (host->regs_ip)
-		iounmap(host->regs_ip);
-	iounmap(host->base);
-	kfree(host);
 
 	return 0;
 }
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index d47586c..0a8724e 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1565,14 +1565,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 					oobreadlen -= toread;
 				}
 			}
-
-			if (!(chip->options & NAND_NO_READRDY)) {
-				/* Apply delay or wait for ready/busy pin */
-				if (!chip->dev_ready)
-					udelay(chip->chip_delay);
-				else
-					nand_wait_ready(mtd);
-			}
 		} else {
 			memcpy(buf, chip->buffers->databuf + col, bytes);
 			buf += bytes;
@@ -1837,14 +1829,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 		len = min(len, readlen);
 		buf = nand_transfer_oob(chip, buf, ops, len);
 
-		if (!(chip->options & NAND_NO_READRDY)) {
-			/* Apply delay or wait for ready/busy pin */
-			if (!chip->dev_ready)
-				udelay(chip->chip_delay);
-			else
-				nand_wait_ready(mtd);
-		}
-
 		readlen -= len;
 		if (!readlen)
 			break;
@@ -2915,7 +2899,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
 		*busw = NAND_BUSWIDTH_16;
 
 	chip->options &= ~NAND_CHIPOPTIONS_MSK;
-	chip->options |= NAND_NO_READRDY & NAND_CHIPOPTIONS_MSK;
 
 	pr_info("ONFI flash detected\n");
 	return 1;
@@ -3501,6 +3484,13 @@ int nand_scan_tail(struct mtd_info *mtd)
 	/* propagate ecc info to mtd_info */
 	mtd->ecclayout = chip->ecc.layout;
 	mtd->ecc_strength = chip->ecc.strength;
+	/*
+	 * Initialize bitflip_threshold to its default prior scan_bbt() call.
+	 * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
+	 * properly set.
+	 */
+	if (!mtd->bitflip_threshold)
+		mtd->bitflip_threshold = mtd->ecc_strength;
 
 	/* Check, if we should skip the bad block table scan */
 	if (chip->options & NAND_SKIP_BBTSCAN)
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 30d1319..c126469 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -390,7 +390,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
 	/* Read the mirror version, if available */
 	if (md && (md->options & NAND_BBT_VERSION)) {
 		scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
-			      mtd->writesize, td);
+			      mtd->writesize, md);
 		md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
 		pr_info("Bad block table at page %d, version 0x%02X\n",
 			 md->pages[0], md->version[0]);
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 621b70b..e04c675 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -70,7 +70,7 @@ struct nand_flash_dev nand_flash_ids[] = {
 	 * These are the new chips with large page size. The pagesize and the
 	 * erasesize is determined from the extended id bytes
 	 */
-#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY)
+#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
 #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
 
 	/* 512 Megabit */
@@ -157,7 +157,7 @@ struct nand_flash_dev nand_flash_ids[] = {
 	 * writes possible, but not implemented now
 	 */
 	{"AND 128MiB 3,3V 8-bit",	0x01, 2048, 128, 0x4000,
-	 NAND_IS_AND | NAND_NO_READRDY | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
+	 NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
 
 	{NULL,}
 };
@@ -176,6 +176,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
 	{NAND_MFR_MICRON, "Micron"},
 	{NAND_MFR_AMD, "AMD"},
 	{NAND_MFR_MACRONIX, "Macronix"},
+	{NAND_MFR_EON, "Eon"},
 	{0x0, "Unknown"}
 };
 
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 6cc8fbf..cf0cd31 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -28,7 +28,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/vmalloc.h>
-#include <asm/div64.h>
+#include <linux/math64.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -546,12 +546,6 @@ static char *get_partition_name(int i)
 	return kstrdup(buf, GFP_KERNEL);
 }
 
-static uint64_t divide(uint64_t n, uint32_t d)
-{
-	do_div(n, d);
-	return n;
-}
-
 /*
  * Initialize the nandsim structure.
  *
@@ -580,7 +574,7 @@ static int init_nandsim(struct mtd_info *mtd)
 	ns->geom.oobsz    = mtd->oobsize;
 	ns->geom.secsz    = mtd->erasesize;
 	ns->geom.pgszoob  = ns->geom.pgsz + ns->geom.oobsz;
-	ns->geom.pgnum    = divide(ns->geom.totsz, ns->geom.pgsz);
+	ns->geom.pgnum    = div_u64(ns->geom.totsz, ns->geom.pgsz);
 	ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
 	ns->geom.secshift = ffs(ns->geom.secsz) - 1;
 	ns->geom.pgshift  = chip->page_shift;
@@ -921,7 +915,7 @@ static int setup_wear_reporting(struct mtd_info *mtd)
 
 	if (!rptwear)
 		return 0;
-	wear_eb_count = divide(mtd->size, mtd->erasesize);
+	wear_eb_count = div_u64(mtd->size, mtd->erasesize);
 	mem = wear_eb_count * sizeof(unsigned long);
 	if (mem / sizeof(unsigned long) != wear_eb_count) {
 		NS_ERR("Too many erase blocks for wear reporting\n");
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 252aaef..afc4681 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -1005,7 +1005,6 @@ KEEP_CONFIG:
 	chip->ecc.size = host->page_size;
 	chip->ecc.strength = 1;
 
-	chip->options |= NAND_NO_READRDY;
 	if (host->reg_ndcr & NDCR_DWIDTH_M)
 		chip->options |= NAND_BUSWIDTH_16;
 
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index aa9b8a5..2eb1541 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -43,11 +44,17 @@ static struct nand_ecclayout flctl_4secc_oob_16 = {
 };
 
 static struct nand_ecclayout flctl_4secc_oob_64 = {
-	.eccbytes = 10,
-	.eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57},
+	.eccbytes = 4 * 10,
+	.eccpos = {
+		 6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+		22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+		38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+		54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
 	.oobfree = {
-		{.offset = 60,
-		. length = 4} },
+		{.offset =  2, .length = 4},
+		{.offset = 16, .length = 6},
+		{.offset = 32, .length = 6},
+		{.offset = 48, .length = 6} },
 };
 
 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
@@ -61,15 +68,15 @@ static struct nand_bbt_descr flctl_4secc_smallpage = {
 
 static struct nand_bbt_descr flctl_4secc_largepage = {
 	.options = NAND_BBT_SCAN2NDPAGE,
-	.offs = 58,
+	.offs = 0,
 	.len = 2,
 	.pattern = scan_ff_pattern,
 };
 
 static void empty_fifo(struct sh_flctl *flctl)
 {
-	writel(0x000c0000, FLINTDMACR(flctl));	/* FIFO Clear */
-	writel(0x00000000, FLINTDMACR(flctl));	/* Clear Error flags */
+	writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl));
+	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
 }
 
 static void start_translation(struct sh_flctl *flctl)
@@ -158,27 +165,56 @@ static void wait_wfifo_ready(struct sh_flctl *flctl)
 	timeout_error(flctl, __func__);
 }
 
-static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
+static enum flctl_ecc_res_t wait_recfifo_ready
+		(struct sh_flctl *flctl, int sector_number)
 {
 	uint32_t timeout = LOOP_TIMEOUT_MAX;
-	int checked[4];
 	void __iomem *ecc_reg[4];
 	int i;
+	int state = FL_SUCCESS;
 	uint32_t data, size;
 
-	memset(checked, 0, sizeof(checked));
-
+	/*
+	 * First this loops checks in FLDTCNTR if we are ready to read out the
+	 * oob data. This is the case if either all went fine without errors or
+	 * if the bottom part of the loop corrected the errors or marked them as
+	 * uncorrectable and the controller is given time to push the data into
+	 * the FIFO.
+	 */
 	while (timeout--) {
+		/* check if all is ok and we can read out the OOB */
 		size = readl(FLDTCNTR(flctl)) >> 24;
-		if (size & 0xFF)
-			return 0;	/* success */
+		if ((size & 0xFF) == 4)
+			return state;
+
+		/* check if a correction code has been calculated */
+		if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) {
+			/*
+			 * either we wait for the fifo to be filled or a
+			 * correction pattern is being generated
+			 */
+			udelay(1);
+			continue;
+		}
+
+		/* check for an uncorrectable error */
+		if (readl(FL4ECCCR(flctl)) & _4ECCFA) {
+			/* check if we face a non-empty page */
+			for (i = 0; i < 512; i++) {
+				if (flctl->done_buff[i] != 0xff) {
+					state = FL_ERROR; /* can't correct */
+					break;
+				}
+			}
 
-		if (readl(FL4ECCCR(flctl)) & _4ECCFA)
-			return 1;	/* can't correct */
+			if (state == FL_SUCCESS)
+				dev_dbg(&flctl->pdev->dev,
+				"reading empty sector %d, ecc error ignored\n",
+				sector_number);
 
-		udelay(1);
-		if (!(readl(FL4ECCCR(flctl)) & _4ECCEND))
+			writel(0, FL4ECCCR(flctl));
 			continue;
+		}
 
 		/* start error correction */
 		ecc_reg[0] = FL4ECCRESULT0(flctl);
@@ -187,28 +223,26 @@ static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
 		ecc_reg[3] = FL4ECCRESULT3(flctl);
 
 		for (i = 0; i < 3; i++) {
+			uint8_t org;
+			int index;
+
 			data = readl(ecc_reg[i]);
-			if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) {
-				uint8_t org;
-				int index;
-
-				if (flctl->page_size)
-					index = (512 * sector_number) +
-						(data >> 16);
-				else
-					index = data >> 16;
-
-				org = flctl->done_buff[index];
-				flctl->done_buff[index] = org ^ (data & 0xFF);
-				checked[i] = 1;
-			}
-		}
 
+			if (flctl->page_size)
+				index = (512 * sector_number) +
+					(data >> 16);
+			else
+				index = data >> 16;
+
+			org = flctl->done_buff[index];
+			flctl->done_buff[index] = org ^ (data & 0xFF);
+		}
+		state = FL_REPAIRABLE;
 		writel(0, FL4ECCCR(flctl));
 	}
 
 	timeout_error(flctl, __func__);
-	return 1;	/* timeout */
+	return FL_TIMEOUT;	/* timeout */
 }
 
 static void wait_wecfifo_ready(struct sh_flctl *flctl)
@@ -241,31 +275,33 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
 {
 	int i, len_4align;
 	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
-	void *fifo_addr = (void *)FLDTFIFO(flctl);
 
 	len_4align = (rlen + 3) / 4;
 
 	for (i = 0; i < len_4align; i++) {
 		wait_rfifo_ready(flctl);
-		buf[i] = readl(fifo_addr);
+		buf[i] = readl(FLDTFIFO(flctl));
 		buf[i] = be32_to_cpu(buf[i]);
 	}
 }
 
-static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff, int sector)
+static enum flctl_ecc_res_t read_ecfiforeg
+		(struct sh_flctl *flctl, uint8_t *buff, int sector)
 {
 	int i;
+	enum flctl_ecc_res_t res;
 	unsigned long *ecc_buf = (unsigned long *)buff;
-	void *fifo_addr = (void *)FLECFIFO(flctl);
 
-	for (i = 0; i < 4; i++) {
-		if (wait_recfifo_ready(flctl , sector))
-			return 1;
-		ecc_buf[i] = readl(fifo_addr);
-		ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
+	res = wait_recfifo_ready(flctl , sector);
+
+	if (res != FL_ERROR) {
+		for (i = 0; i < 4; i++) {
+			ecc_buf[i] = readl(FLECFIFO(flctl));
+			ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
+		}
 	}
 
-	return 0;
+	return res;
 }
 
 static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
@@ -281,6 +317,18 @@ static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
 	}
 }
 
+static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+{
+	int i, len_4align;
+	unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
+
+	len_4align = (rlen + 3) / 4;
+	for (i = 0; i < len_4align; i++) {
+		wait_wecfifo_ready(flctl);
+		writel(cpu_to_be32(data[i]), FLECFIFO(flctl));
+	}
+}
+
 static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
 {
 	struct sh_flctl *flctl = mtd_to_flctl(mtd);
@@ -346,73 +394,63 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
 static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 				uint8_t *buf, int oob_required, int page)
 {
-	int i, eccsize = chip->ecc.size;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	uint8_t *p = buf;
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-		chip->read_buf(mtd, p, eccsize);
-
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-		if (flctl->hwecc_cant_correct[i])
-			mtd->ecc_stats.failed++;
-		else
-			mtd->ecc_stats.corrected += 0; /* FIXME */
-	}
-
+	chip->read_buf(mtd, buf, mtd->writesize);
+	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
 	return 0;
 }
 
 static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 				   const uint8_t *buf, int oob_required)
 {
-	int i, eccsize = chip->ecc.size;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	const uint8_t *p = buf;
-
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-		chip->write_buf(mtd, p, eccsize);
+	chip->write_buf(mtd, buf, mtd->writesize);
+	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
 }
 
 static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
 {
 	struct sh_flctl *flctl = mtd_to_flctl(mtd);
 	int sector, page_sectors;
+	enum flctl_ecc_res_t ecc_result;
 
-	if (flctl->page_size)
-		page_sectors = 4;
-	else
-		page_sectors = 1;
-
-	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
-		 FLCMNCR(flctl));
+	page_sectors = flctl->page_size ? 4 : 1;
 
 	set_cmd_regs(mtd, NAND_CMD_READ0,
 		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
 
-	for (sector = 0; sector < page_sectors; sector++) {
-		int ret;
+	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
+		 FLCMNCR(flctl));
+	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
+	writel(page_addr << 2, FLADR(flctl));
 
-		empty_fifo(flctl);
-		writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
-		writel(page_addr << 2 | sector, FLADR(flctl));
+	empty_fifo(flctl);
+	start_translation(flctl);
 
-		start_translation(flctl);
+	for (sector = 0; sector < page_sectors; sector++) {
 		read_fiforeg(flctl, 512, 512 * sector);
 
-		ret = read_ecfiforeg(flctl,
+		ecc_result = read_ecfiforeg(flctl,
 			&flctl->done_buff[mtd->writesize + 16 * sector],
 			sector);
 
-		if (ret)
-			flctl->hwecc_cant_correct[sector] = 1;
-
-		writel(0x0, FL4ECCCR(flctl));
-		wait_completion(flctl);
+		switch (ecc_result) {
+		case FL_REPAIRABLE:
+			dev_info(&flctl->pdev->dev,
+				"applied ecc on page 0x%x", page_addr);
+			flctl->mtd.ecc_stats.corrected++;
+			break;
+		case FL_ERROR:
+			dev_warn(&flctl->pdev->dev,
+				"page 0x%x contains corrupted data\n",
+				page_addr);
+			flctl->mtd.ecc_stats.failed++;
+			break;
+		default:
+			;
+		}
 	}
+
+	wait_completion(flctl);
+
 	writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
 			FLCMNCR(flctl));
 }
@@ -420,30 +458,20 @@ static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
 static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
 {
 	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	int page_sectors = flctl->page_size ? 4 : 1;
+	int i;
 
 	set_cmd_regs(mtd, NAND_CMD_READ0,
 		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
 
 	empty_fifo(flctl);
-	if (flctl->page_size) {
-		int i;
-		/* In case that the page size is 2k */
-		for (i = 0; i < 16 * 3; i++)
-			flctl->done_buff[i] = 0xFF;
-
-		set_addr(mtd, 3 * 528 + 512, page_addr);
-		writel(16, FLDTCNTR(flctl));
 
-		start_translation(flctl);
-		read_fiforeg(flctl, 16, 16 * 3);
-		wait_completion(flctl);
-	} else {
-		/* In case that the page size is 512b */
-		set_addr(mtd, 512, page_addr);
+	for (i = 0; i < page_sectors; i++) {
+		set_addr(mtd, (512 + 16) * i + 512 , page_addr);
 		writel(16, FLDTCNTR(flctl));
 
 		start_translation(flctl);
-		read_fiforeg(flctl, 16, 0);
+		read_fiforeg(flctl, 16, 16 * i);
 		wait_completion(flctl);
 	}
 }
@@ -451,34 +479,26 @@ static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
 static void execmd_write_page_sector(struct mtd_info *mtd)
 {
 	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	int i, page_addr = flctl->seqin_page_addr;
+	int page_addr = flctl->seqin_page_addr;
 	int sector, page_sectors;
 
-	if (flctl->page_size)
-		page_sectors = 4;
-	else
-		page_sectors = 1;
-
-	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
+	page_sectors = flctl->page_size ? 4 : 1;
 
 	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
 			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
 
-	for (sector = 0; sector < page_sectors; sector++) {
-		empty_fifo(flctl);
-		writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
-		writel(page_addr << 2 | sector, FLADR(flctl));
+	empty_fifo(flctl);
+	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
+	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
+	writel(page_addr << 2, FLADR(flctl));
+	start_translation(flctl);
 
-		start_translation(flctl);
+	for (sector = 0; sector < page_sectors; sector++) {
 		write_fiforeg(flctl, 512, 512 * sector);
-
-		for (i = 0; i < 4; i++) {
-			wait_wecfifo_ready(flctl); /* wait for write ready */
-			writel(0xFFFFFFFF, FLECFIFO(flctl));
-		}
-		wait_completion(flctl);
+		write_ec_fiforeg(flctl, 16, mtd->writesize + 16 * sector);
 	}
 
+	wait_completion(flctl);
 	writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
 }
 
@@ -488,18 +508,12 @@ static void execmd_write_oob(struct mtd_info *mtd)
 	int page_addr = flctl->seqin_page_addr;
 	int sector, page_sectors;
 
-	if (flctl->page_size) {
-		sector = 3;
-		page_sectors = 4;
-	} else {
-		sector = 0;
-		page_sectors = 1;
-	}
+	page_sectors = flctl->page_size ? 4 : 1;
 
 	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
 			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
 
-	for (; sector < page_sectors; sector++) {
+	for (sector = 0; sector < page_sectors; sector++) {
 		empty_fifo(flctl);
 		set_addr(mtd, sector * 528 + 512, page_addr);
 		writel(16, FLDTCNTR(flctl));	/* set read size */
@@ -831,7 +845,7 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
 		chip->ecc.mode = NAND_ECC_HW;
 
 		/* 4 symbols ECC enabled */
-		flctl->flcmncr_base |= _4ECCEN | ECCPOS2 | ECCPOS_02;
+		flctl->flcmncr_base |= _4ECCEN;
 	} else {
 		chip->ecc.mode = NAND_ECC_SOFT;
 	}
@@ -839,6 +853,16 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
 	return 0;
 }
 
+static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
+{
+	struct sh_flctl *flctl = dev_id;
+
+	dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl)));
+	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
+
+	return IRQ_HANDLED;
+}
+
 static int __devinit flctl_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -847,6 +871,7 @@ static int __devinit flctl_probe(struct platform_device *pdev)
 	struct nand_chip *nand;
 	struct sh_flctl_platform_data *pdata;
 	int ret = -ENXIO;
+	int irq;
 
 	pdata = pdev->dev.platform_data;
 	if (pdata == NULL) {
@@ -872,14 +897,27 @@ static int __devinit flctl_probe(struct platform_device *pdev)
 		goto err_iomap;
 	}
 
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "failed to get flste irq data\n");
+		goto err_flste;
+	}
+
+	ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl);
+	if (ret) {
+		dev_err(&pdev->dev, "request interrupt failed.\n");
+		goto err_flste;
+	}
+
 	platform_set_drvdata(pdev, flctl);
 	flctl_mtd = &flctl->mtd;
 	nand = &flctl->chip;
 	flctl_mtd->priv = nand;
 	flctl->pdev = pdev;
-	flctl->flcmncr_base = pdata->flcmncr_val;
 	flctl->hwecc = pdata->has_hwecc;
 	flctl->holden = pdata->use_holden;
+	flctl->flcmncr_base = pdata->flcmncr_val;
+	flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
 
 	/* Set address of hardware control function */
 	/* 20 us command delay time */
@@ -918,6 +956,9 @@ static int __devinit flctl_probe(struct platform_device *pdev)
 
 err_chip:
 	pm_runtime_disable(&pdev->dev);
+	free_irq(irq, flctl);
+err_flste:
+	iounmap(flctl->reg);
 err_iomap:
 	kfree(flctl);
 	return ret;
@@ -929,6 +970,8 @@ static int __devexit flctl_remove(struct platform_device *pdev)
 
 	nand_release(&flctl->mtd);
 	pm_runtime_disable(&pdev->dev);
+	free_irq(platform_get_irq(pdev, 0), flctl);
+	iounmap(flctl->reg);
 	kfree(flctl);
 
 	return 0;
diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c
index 2aec4f3..42b0f74 100644
--- a/drivers/mtd/tests/mtd_speedtest.c
+++ b/drivers/mtd/tests/mtd_speedtest.c
@@ -26,6 +26,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/random.h>
 
 #define PRINT_PREF KERN_INFO "mtd_speedtest: "
 
@@ -47,25 +48,13 @@ static int ebcnt;
 static int pgcnt;
 static int goodebcnt;
 static struct timeval start, finish;
-static unsigned long next = 1;
-
-static inline unsigned int simple_rand(void)
-{
-	next = next * 1103515245 + 12345;
-	return (unsigned int)((next / 65536) % 32768);
-}
-
-static inline void simple_srand(unsigned long seed)
-{
-	next = seed;
-}
 
 static void set_random_data(unsigned char *buf, size_t len)
 {
 	size_t i;
 
 	for (i = 0; i < len; ++i)
-		buf[i] = simple_rand();
+		buf[i] = random32();
 }
 
 static int erase_eraseblock(int ebnum)
@@ -407,7 +396,6 @@ static int __init mtd_speedtest_init(void)
 		goto out;
 	}
 
-	simple_srand(1);
 	set_random_data(iobuf, mtd->erasesize);
 
 	err = scan_for_bad_eraseblocks();
diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c
index 7b33f22..cb268ce 100644
--- a/drivers/mtd/tests/mtd_stresstest.c
+++ b/drivers/mtd/tests/mtd_stresstest.c
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/vmalloc.h>
+#include <linux/random.h>
 
 #define PRINT_PREF KERN_INFO "mtd_stresstest: "
 
@@ -48,28 +49,13 @@ static int pgsize;
 static int bufsize;
 static int ebcnt;
 static int pgcnt;
-static unsigned long next = 1;
-
-static inline unsigned int simple_rand(void)
-{
-	next = next * 1103515245 + 12345;
-	return (unsigned int)((next / 65536) % 32768);
-}
-
-static inline void simple_srand(unsigned long seed)
-{
-	next = seed;
-}
 
 static int rand_eb(void)
 {
-	int eb;
+	unsigned int eb;
 
 again:
-	if (ebcnt < 32768)
-		eb = simple_rand();
-	else
-		eb = (simple_rand() << 15) | simple_rand();
+	eb = random32();
 	/* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
 	eb %= (ebcnt - 1);
 	if (bbt[eb])
@@ -79,24 +65,18 @@ again:
 
 static int rand_offs(void)
 {
-	int offs;
+	unsigned int offs;
 
-	if (bufsize < 32768)
-		offs = simple_rand();
-	else
-		offs = (simple_rand() << 15) | simple_rand();
+	offs = random32();
 	offs %= bufsize;
 	return offs;
 }
 
 static int rand_len(int offs)
 {
-	int len;
+	unsigned int len;
 
-	if (bufsize < 32768)
-		len = simple_rand();
-	else
-		len = (simple_rand() << 15) | simple_rand();
+	len = random32();
 	len %= (bufsize - offs);
 	return len;
 }
@@ -211,7 +191,7 @@ static int do_write(void)
 
 static int do_operation(void)
 {
-	if (simple_rand() & 1)
+	if (random32() & 1)
 		return do_read();
 	else
 		return do_write();
@@ -302,9 +282,8 @@ static int __init mtd_stresstest_init(void)
 	}
 	for (i = 0; i < ebcnt; i++)
 		offsets[i] = mtd->erasesize;
-	simple_srand(current->pid);
 	for (i = 0; i < bufsize; i++)
-		writebuf[i] = simple_rand();
+		writebuf[i] = random32();
 
 	err = scan_for_bad_eraseblocks();
 	if (err)
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index dd5e048..545c09e 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -936,7 +936,7 @@ static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
         struct cops_local *lp = netdev_priv(dev);
         struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr;
-        struct atalk_addr *aa = (struct atalk_addr *)&lp->node_addr;
+        struct atalk_addr *aa = &lp->node_addr;
 
         switch(cmd)
         {
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 3463b46..a030e63 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2454,24 +2454,27 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
 out:
 	if (res) {
 		/* no suitable interface, frame not sent */
-		dev_kfree_skb(skb);
+		kfree_skb(skb);
 	}
 
 	return NETDEV_TX_OK;
 }
 
-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
-			  struct slave *slave)
+int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
+			 struct slave *slave)
 {
 	int ret = RX_HANDLER_ANOTHER;
+	struct lacpdu *lacpdu, _lacpdu;
+
 	if (skb->protocol != PKT_TYPE_LACPDU)
 		return ret;
 
-	if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
+	lacpdu = skb_header_pointer(skb, 0, sizeof(_lacpdu), &_lacpdu);
+	if (!lacpdu)
 		return ret;
 
 	read_lock(&bond->lock);
-	ret = bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len);
+	ret = bond_3ad_rx_indication(lacpdu, slave, skb->len);
 	read_unlock(&bond->lock);
 	return ret;
 }
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 5ee7e3c..0cfaa4a 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -274,8 +274,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave);
 void bond_3ad_handle_link_change(struct slave *slave, char link);
 int  bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
 int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
-			  struct slave *slave);
+int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
+			 struct slave *slave);
 int bond_3ad_set_carrier(struct bonding *bond);
 void bond_3ad_update_lacp_rate(struct bonding *bond);
 #endif //__BOND_3AD_H__
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 0f59c15..e15cc11 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -342,27 +342,17 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
 	_unlock_rx_hashtbl_bh(bond);
 }
 
-static int rlb_arp_recv(struct sk_buff *skb, struct bonding *bond,
-			 struct slave *slave)
+static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond,
+			struct slave *slave)
 {
-	struct arp_pkt *arp;
+	struct arp_pkt *arp, _arp;
 
 	if (skb->protocol != cpu_to_be16(ETH_P_ARP))
 		goto out;
 
-	arp = (struct arp_pkt *) skb->data;
-	if (!arp) {
-		pr_debug("Packet has no ARP data\n");
+	arp = skb_header_pointer(skb, 0, sizeof(_arp), &_arp);
+	if (!arp)
 		goto out;
-	}
-
-	if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
-		goto out;
-
-	if (skb->len < sizeof(struct arp_pkt)) {
-		pr_debug("Packet is too small to be an ARP\n");
-		goto out;
-	}
 
 	if (arp->op_code == htons(ARPOP_REPLY)) {
 		/* update rx hash table for this ARP */
@@ -1356,12 +1346,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
 		}
 	}
 
+	read_unlock(&bond->curr_slave_lock);
+
 	if (res) {
 		/* no suitable interface, frame not sent */
-		dev_kfree_skb(skb);
+		kfree_skb(skb);
 	}
-	read_unlock(&bond->curr_slave_lock);
-
 	return NETDEV_TX_OK;
 }
 
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b9c2ae6..f5a40b9 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1445,8 +1445,8 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
 	struct sk_buff *skb = *pskb;
 	struct slave *slave;
 	struct bonding *bond;
-	int (*recv_probe)(struct sk_buff *, struct bonding *,
-				struct slave *);
+	int (*recv_probe)(const struct sk_buff *, struct bonding *,
+			  struct slave *);
 	int ret = RX_HANDLER_ANOTHER;
 
 	skb = skb_share_check(skb, GFP_ATOMIC);
@@ -1463,15 +1463,10 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
 
 	recv_probe = ACCESS_ONCE(bond->recv_probe);
 	if (recv_probe) {
-		struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
-
-		if (likely(nskb)) {
-			ret = recv_probe(nskb, bond, slave);
-			dev_kfree_skb(nskb);
-			if (ret == RX_HANDLER_CONSUMED) {
-				consume_skb(skb);
-				return ret;
-			}
+		ret = recv_probe(skb, bond, slave);
+		if (ret == RX_HANDLER_CONSUMED) {
+			consume_skb(skb);
+			return ret;
 		}
 	}
 
@@ -2738,25 +2733,31 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
 	}
 }
 
-static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
-			 struct slave *slave)
+static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
+			struct slave *slave)
 {
-	struct arphdr *arp;
+	struct arphdr *arp = (struct arphdr *)skb->data;
 	unsigned char *arp_ptr;
 	__be32 sip, tip;
+	int alen;
 
 	if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
 		return RX_HANDLER_ANOTHER;
 
 	read_lock(&bond->lock);
+	alen = arp_hdr_len(bond->dev);
 
 	pr_debug("bond_arp_rcv: bond %s skb->dev %s\n",
 		 bond->dev->name, skb->dev->name);
 
-	if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
-		goto out_unlock;
+	if (alen > skb_headlen(skb)) {
+		arp = kmalloc(alen, GFP_ATOMIC);
+		if (!arp)
+			goto out_unlock;
+		if (skb_copy_bits(skb, 0, arp, alen) < 0)
+			goto out_unlock;
+	}
 
-	arp = arp_hdr(skb);
 	if (arp->ar_hln != bond->dev->addr_len ||
 	    skb->pkt_type == PACKET_OTHERHOST ||
 	    skb->pkt_type == PACKET_LOOPBACK ||
@@ -2791,6 +2792,8 @@ static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
 
 out_unlock:
 	read_unlock(&bond->lock);
+	if (arp != (struct arphdr *)skb->data)
+		kfree(arp);
 	return RX_HANDLER_ANOTHER;
 }
 
@@ -3987,7 +3990,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
 out:
 	if (res) {
 		/* no suitable interface, frame not sent */
-		dev_kfree_skb(skb);
+		kfree_skb(skb);
 	}
 
 	return NETDEV_TX_OK;
@@ -4009,11 +4012,11 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
 		res = bond_dev_queue_xmit(bond, skb,
 			bond->curr_active_slave->dev);
 
+	read_unlock(&bond->curr_slave_lock);
+
 	if (res)
 		/* no suitable interface, frame not sent */
-		dev_kfree_skb(skb);
-
-	read_unlock(&bond->curr_slave_lock);
+		kfree_skb(skb);
 
 	return NETDEV_TX_OK;
 }
@@ -4052,7 +4055,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
 
 	if (res) {
 		/* no suitable interface, frame not sent */
-		dev_kfree_skb(skb);
+		kfree_skb(skb);
 	}
 
 	return NETDEV_TX_OK;
@@ -4090,7 +4093,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
 
 				res = bond_dev_queue_xmit(bond, skb2, tx_dev);
 				if (res) {
-					dev_kfree_skb(skb2);
+					kfree_skb(skb2);
 					continue;
 				}
 			}
@@ -4104,7 +4107,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
 out:
 	if (res)
 		/* no suitable interface, frame not sent */
-		dev_kfree_skb(skb);
+		kfree_skb(skb);
 
 	/* frame sent to all suitable interfaces */
 	return NETDEV_TX_OK;
@@ -4210,7 +4213,7 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev
 		pr_err("%s: Error: Unknown bonding mode %d\n",
 		       dev->name, bond->params.mode);
 		WARN_ON_ONCE(1);
-		dev_kfree_skb(skb);
+		kfree_skb(skb);
 		return NETDEV_TX_OK;
 	}
 }
@@ -4232,7 +4235,7 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (bond->slave_cnt)
 		ret = __bond_start_xmit(skb, dev);
 	else
-		dev_kfree_skb(skb);
+		kfree_skb(skb);
 
 	read_unlock(&bond->lock);
 
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index ad284ba..3cea38d 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -150,14 +150,25 @@ static void bond_info_show_master(struct seq_file *seq)
 	}
 }
 
+static const char *bond_slave_link_status(s8 link)
+{
+	static const char * const status[] = {
+		[BOND_LINK_UP] = "up",
+		[BOND_LINK_FAIL] = "going down",
+		[BOND_LINK_DOWN] = "down",
+		[BOND_LINK_BACK] = "going back",
+	};
+
+	return status[link];
+}
+
 static void bond_info_show_slave(struct seq_file *seq,
 				 const struct slave *slave)
 {
 	struct bonding *bond = seq->private;
 
 	seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
-	seq_printf(seq, "MII Status: %s\n",
-		   (slave->link == BOND_LINK_UP) ?  "up" : "down");
+	seq_printf(seq, "MII Status: %s\n", bond_slave_link_status(slave->link));
 	if (slave->speed == SPEED_UNKNOWN)
 		seq_printf(seq, "Speed: %s\n", "Unknown");
 	else
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 4581aa5..f8af2fc 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -218,8 +218,8 @@ struct bonding {
 	struct   slave *primary_slave;
 	bool     force_primary;
 	s32      slave_cnt; /* never change this value outside the attach/detach wrappers */
-	int     (*recv_probe)(struct sk_buff *, struct bonding *,
-			       struct slave *);
+	int     (*recv_probe)(const struct sk_buff *, struct bonding *,
+			      struct slave *);
 	rwlock_t lock;
 	rwlock_t curr_slave_lock;
 	u8	 send_peer_notif;
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
index 1520814..0def8b3 100644
--- a/drivers/net/caif/caif_hsi.c
+++ b/drivers/net/caif/caif_hsi.c
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
-#include <linux/platform_device.h>
 #include <linux/netdevice.h>
 #include <linux/string.h>
 #include <linux/list.h>
@@ -20,7 +19,7 @@
 #include <linux/sched.h>
 #include <linux/if_arp.h>
 #include <linux/timer.h>
-#include <linux/rtnetlink.h>
+#include <net/rtnetlink.h>
 #include <linux/pkt_sched.h>
 #include <net/caif/caif_layer.h>
 #include <net/caif/caif_hsi.h>
@@ -33,59 +32,46 @@ MODULE_DESCRIPTION("CAIF HSI driver");
 #define PAD_POW2(x, pow) ((((x)&((pow)-1)) == 0) ? 0 :\
 				(((pow)-((x)&((pow)-1)))))
 
-static int inactivity_timeout = 1000;
-module_param(inactivity_timeout, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(inactivity_timeout, "Inactivity timeout on HSI, ms.");
+static const struct cfhsi_config  hsi_default_config = {
 
-static int aggregation_timeout = 1;
-module_param(aggregation_timeout, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(aggregation_timeout, "Aggregation timeout on HSI, ms.");
+	/* Inactivity timeout on HSI, ms */
+	.inactivity_timeout = HZ,
 
-/*
- * HSI padding options.
- * Warning: must be a base of 2 (& operation used) and can not be zero !
- */
-static int hsi_head_align = 4;
-module_param(hsi_head_align, int, S_IRUGO);
-MODULE_PARM_DESC(hsi_head_align, "HSI head alignment.");
+	/* Aggregation timeout (ms) of zero means no aggregation is done*/
+	.aggregation_timeout = 1,
 
-static int hsi_tail_align = 4;
-module_param(hsi_tail_align, int, S_IRUGO);
-MODULE_PARM_DESC(hsi_tail_align, "HSI tail alignment.");
-
-/*
- * HSI link layer flowcontrol thresholds.
- * Warning: A high threshold value migth increase throughput but it will at
- * the same time prevent channel prioritization and increase the risk of
- * flooding the modem. The high threshold should be above the low.
- */
-static int hsi_high_threshold = 100;
-module_param(hsi_high_threshold, int, S_IRUGO);
-MODULE_PARM_DESC(hsi_high_threshold, "HSI high threshold (FLOW OFF).");
+	/*
+	 * HSI link layer flow-control thresholds.
+	 * Threshold values for the HSI packet queue. Flow-control will be
+	 * asserted when the number of packets exceeds q_high_mark. It will
+	 * not be de-asserted before the number of packets drops below
+	 * q_low_mark.
+	 * Warning: A high threshold value might increase throughput but it
+	 * will at the same time prevent channel prioritization and increase
+	 * the risk of flooding the modem. The high threshold should be above
+	 * the low.
+	 */
+	.q_high_mark = 100,
+	.q_low_mark = 50,
 
-static int hsi_low_threshold = 50;
-module_param(hsi_low_threshold, int, S_IRUGO);
-MODULE_PARM_DESC(hsi_low_threshold, "HSI high threshold (FLOW ON).");
+	/*
+	 * HSI padding options.
+	 * Warning: must be a base of 2 (& operation used) and can not be zero !
+	 */
+	.head_align = 4,
+	.tail_align = 4,
+};
 
 #define ON 1
 #define OFF 0
 
-/*
- * Threshold values for the HSI packet queue. Flowcontrol will be asserted
- * when the number of packets exceeds HIGH_WATER_MARK. It will not be
- * de-asserted before the number of packets drops below LOW_WATER_MARK.
- */
-#define LOW_WATER_MARK   hsi_low_threshold
-#define HIGH_WATER_MARK  hsi_high_threshold
-
 static LIST_HEAD(cfhsi_list);
-static spinlock_t cfhsi_list_lock;
 
 static void cfhsi_inactivity_tout(unsigned long arg)
 {
 	struct cfhsi *cfhsi = (struct cfhsi *)arg;
 
-	dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+	netdev_dbg(cfhsi->ndev, "%s.\n",
 		__func__);
 
 	/* Schedule power down work queue. */
@@ -101,8 +87,8 @@ static void cfhsi_update_aggregation_stats(struct cfhsi *cfhsi,
 	int hpad, tpad, len;
 
 	info = (struct caif_payload_info *)&skb->cb;
-	hpad = 1 + PAD_POW2((info->hdr_len + 1), hsi_head_align);
-	tpad = PAD_POW2((skb->len + hpad), hsi_tail_align);
+	hpad = 1 + PAD_POW2((info->hdr_len + 1), cfhsi->cfg.head_align);
+	tpad = PAD_POW2((skb->len + hpad), cfhsi->cfg.tail_align);
 	len = skb->len + hpad + tpad;
 
 	if (direction > 0)
@@ -115,7 +101,7 @@ static bool cfhsi_can_send_aggregate(struct cfhsi *cfhsi)
 {
 	int i;
 
-	if (cfhsi->aggregation_timeout < 0)
+	if (cfhsi->cfg.aggregation_timeout == 0)
 		return true;
 
 	for (i = 0; i < CFHSI_PRIO_BEBK; ++i) {
@@ -171,7 +157,7 @@ static void cfhsi_abort_tx(struct cfhsi *cfhsi)
 	cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
 	if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
 		mod_timer(&cfhsi->inactivity_timer,
-			jiffies + cfhsi->inactivity_timeout);
+			jiffies + cfhsi->cfg.inactivity_timeout);
 	spin_unlock_bh(&cfhsi->lock);
 }
 
@@ -181,14 +167,14 @@ static int cfhsi_flush_fifo(struct cfhsi *cfhsi)
 	size_t fifo_occupancy;
 	int ret;
 
-	dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+	netdev_dbg(cfhsi->ndev, "%s.\n",
 		__func__);
 
 	do {
-		ret = cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
+		ret = cfhsi->ops->cfhsi_fifo_occupancy(cfhsi->ops,
 				&fifo_occupancy);
 		if (ret) {
-			dev_warn(&cfhsi->ndev->dev,
+			netdev_warn(cfhsi->ndev,
 				"%s: can't get FIFO occupancy: %d.\n",
 				__func__, ret);
 			break;
@@ -198,11 +184,11 @@ static int cfhsi_flush_fifo(struct cfhsi *cfhsi)
 
 		fifo_occupancy = min(sizeof(buffer), fifo_occupancy);
 		set_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits);
-		ret = cfhsi->dev->cfhsi_rx(buffer, fifo_occupancy,
-				cfhsi->dev);
+		ret = cfhsi->ops->cfhsi_rx(buffer, fifo_occupancy,
+				cfhsi->ops);
 		if (ret) {
 			clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits);
-			dev_warn(&cfhsi->ndev->dev,
+			netdev_warn(cfhsi->ndev,
 				"%s: can't read data: %d.\n",
 				__func__, ret);
 			break;
@@ -213,13 +199,13 @@ static int cfhsi_flush_fifo(struct cfhsi *cfhsi)
 			 !test_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits), ret);
 
 		if (ret < 0) {
-			dev_warn(&cfhsi->ndev->dev,
+			netdev_warn(cfhsi->ndev,
 				"%s: can't wait for flush complete: %d.\n",
 				__func__, ret);
 			break;
 		} else if (!ret) {
 			ret = -ETIMEDOUT;
-			dev_warn(&cfhsi->ndev->dev,
+			netdev_warn(cfhsi->ndev,
 				"%s: timeout waiting for flush complete.\n",
 				__func__);
 			break;
@@ -246,14 +232,14 @@ static int cfhsi_tx_frm(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 	/* Check if we can embed a CAIF frame. */
 	if (skb->len < CFHSI_MAX_EMB_FRM_SZ) {
 		struct caif_payload_info *info;
-		int hpad = 0;
-		int tpad = 0;
+		int hpad;
+		int tpad;
 
 		/* Calculate needed head alignment and tail alignment. */
 		info = (struct caif_payload_info *)&skb->cb;
 
-		hpad = 1 + PAD_POW2((info->hdr_len + 1), hsi_head_align);
-		tpad = PAD_POW2((skb->len + hpad), hsi_tail_align);
+		hpad = 1 + PAD_POW2((info->hdr_len + 1), cfhsi->cfg.head_align);
+		tpad = PAD_POW2((skb->len + hpad), cfhsi->cfg.tail_align);
 
 		/* Check if frame still fits with added alignment. */
 		if ((skb->len + hpad + tpad) <= CFHSI_MAX_EMB_FRM_SZ) {
@@ -282,8 +268,8 @@ static int cfhsi_tx_frm(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 	pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ;
 	while (nfrms < CFHSI_MAX_PKTS) {
 		struct caif_payload_info *info;
-		int hpad = 0;
-		int tpad = 0;
+		int hpad;
+		int tpad;
 
 		if (!skb)
 			skb = cfhsi_dequeue(cfhsi);
@@ -294,8 +280,8 @@ static int cfhsi_tx_frm(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 		/* Calculate needed head alignment and tail alignment. */
 		info = (struct caif_payload_info *)&skb->cb;
 
-		hpad = 1 + PAD_POW2((info->hdr_len + 1), hsi_head_align);
-		tpad = PAD_POW2((skb->len + hpad), hsi_tail_align);
+		hpad = 1 + PAD_POW2((info->hdr_len + 1), cfhsi->cfg.head_align);
+		tpad = PAD_POW2((skb->len + hpad), cfhsi->cfg.tail_align);
 
 		/* Fill in CAIF frame length in descriptor. */
 		desc->cffrm_len[nfrms] = hpad + skb->len + tpad;
@@ -348,7 +334,7 @@ static void cfhsi_start_tx(struct cfhsi *cfhsi)
 	struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf;
 	int len, res;
 
-	dev_dbg(&cfhsi->ndev->dev, "%s.\n", __func__);
+	netdev_dbg(cfhsi->ndev, "%s.\n", __func__);
 
 	if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
 		return;
@@ -366,22 +352,22 @@ static void cfhsi_start_tx(struct cfhsi *cfhsi)
 			cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
 			/* Start inactivity timer. */
 			mod_timer(&cfhsi->inactivity_timer,
-				jiffies + cfhsi->inactivity_timeout);
+				jiffies + cfhsi->cfg.inactivity_timeout);
 			spin_unlock_bh(&cfhsi->lock);
 			break;
 		}
 
 		/* Set up new transfer. */
-		res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev);
+		res = cfhsi->ops->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->ops);
 		if (WARN_ON(res < 0))
-			dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n",
+			netdev_err(cfhsi->ndev, "%s: TX error %d.\n",
 				__func__, res);
 	} while (res < 0);
 }
 
 static void cfhsi_tx_done(struct cfhsi *cfhsi)
 {
-	dev_dbg(&cfhsi->ndev->dev, "%s.\n", __func__);
+	netdev_dbg(cfhsi->ndev, "%s.\n", __func__);
 
 	if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
 		return;
@@ -392,7 +378,7 @@ static void cfhsi_tx_done(struct cfhsi *cfhsi)
 	 */
 	spin_lock_bh(&cfhsi->lock);
 	if (cfhsi->flow_off_sent &&
-			cfhsi_tx_queue_len(cfhsi) <= cfhsi->q_low_mark &&
+			cfhsi_tx_queue_len(cfhsi) <= cfhsi->cfg.q_low_mark &&
 			cfhsi->cfdev.flowctrl) {
 
 		cfhsi->flow_off_sent = 0;
@@ -404,19 +390,19 @@ static void cfhsi_tx_done(struct cfhsi *cfhsi)
 		cfhsi_start_tx(cfhsi);
 	} else {
 		mod_timer(&cfhsi->aggregation_timer,
-			jiffies + cfhsi->aggregation_timeout);
+			jiffies + cfhsi->cfg.aggregation_timeout);
 		spin_unlock_bh(&cfhsi->lock);
 	}
 
 	return;
 }
 
-static void cfhsi_tx_done_cb(struct cfhsi_drv *drv)
+static void cfhsi_tx_done_cb(struct cfhsi_cb_ops *cb_ops)
 {
 	struct cfhsi *cfhsi;
 
-	cfhsi = container_of(drv, struct cfhsi, drv);
-	dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+	cfhsi = container_of(cb_ops, struct cfhsi, cb_ops);
+	netdev_dbg(cfhsi->ndev, "%s.\n",
 		__func__);
 
 	if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
@@ -433,7 +419,7 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 
 	if ((desc->header & ~CFHSI_PIGGY_DESC) ||
 			(desc->offset > CFHSI_MAX_EMB_FRM_SZ)) {
-		dev_err(&cfhsi->ndev->dev, "%s: Invalid descriptor.\n",
+		netdev_err(cfhsi->ndev, "%s: Invalid descriptor.\n",
 			__func__);
 		return -EPROTO;
 	}
@@ -455,7 +441,7 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 
 		/* Sanity check length of CAIF frame. */
 		if (unlikely(len > CFHSI_MAX_CAIF_FRAME_SZ)) {
-			dev_err(&cfhsi->ndev->dev, "%s: Invalid length.\n",
+			netdev_err(cfhsi->ndev, "%s: Invalid length.\n",
 				__func__);
 			return -EPROTO;
 		}
@@ -463,7 +449,7 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 		/* Allocate SKB (OK even in IRQ context). */
 		skb = alloc_skb(len + 1, GFP_ATOMIC);
 		if (!skb) {
-			dev_err(&cfhsi->ndev->dev, "%s: Out of memory !\n",
+			netdev_err(cfhsi->ndev, "%s: Out of memory !\n",
 				__func__);
 			return -ENOMEM;
 		}
@@ -477,8 +463,8 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 		skb->dev = cfhsi->ndev;
 
 		/*
-		 * We are called from a arch specific platform device.
-		 * Unfortunately we don't know what context we're
+		 * We are in a callback handler and
+		 * unfortunately we don't know what context we're
 		 * running in.
 		 */
 		if (in_interrupt())
@@ -504,7 +490,7 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 		xfer_sz += CFHSI_DESC_SZ;
 
 	if ((xfer_sz % 4) || (xfer_sz > (CFHSI_BUF_SZ_RX - CFHSI_DESC_SZ))) {
-		dev_err(&cfhsi->ndev->dev,
+		netdev_err(cfhsi->ndev,
 				"%s: Invalid payload len: %d, ignored.\n",
 			__func__, xfer_sz);
 		return -EPROTO;
@@ -551,7 +537,7 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 	/* Sanity check header and offset. */
 	if (WARN_ON((desc->header & ~CFHSI_PIGGY_DESC) ||
 			(desc->offset > CFHSI_MAX_EMB_FRM_SZ))) {
-		dev_err(&cfhsi->ndev->dev, "%s: Invalid descriptor.\n",
+		netdev_err(cfhsi->ndev, "%s: Invalid descriptor.\n",
 			__func__);
 		return -EPROTO;
 	}
@@ -573,7 +559,7 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 		struct sk_buff *skb;
 		u8 *dst = NULL;
 		u8 *pcffrm = NULL;
-		int len = 0;
+		int len;
 
 		/* CAIF frame starts after head padding. */
 		pcffrm = pfrm + *pfrm + 1;
@@ -585,7 +571,7 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 
 		/* Sanity check length of CAIF frames. */
 		if (unlikely(len > CFHSI_MAX_CAIF_FRAME_SZ)) {
-			dev_err(&cfhsi->ndev->dev, "%s: Invalid length.\n",
+			netdev_err(cfhsi->ndev, "%s: Invalid length.\n",
 				__func__);
 			return -EPROTO;
 		}
@@ -593,7 +579,7 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 		/* Allocate SKB (OK even in IRQ context). */
 		skb = alloc_skb(len + 1, GFP_ATOMIC);
 		if (!skb) {
-			dev_err(&cfhsi->ndev->dev, "%s: Out of memory !\n",
+			netdev_err(cfhsi->ndev, "%s: Out of memory !\n",
 				__func__);
 			cfhsi->rx_state.nfrms = nfrms;
 			return -ENOMEM;
@@ -608,7 +594,7 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
 		skb->dev = cfhsi->ndev;
 
 		/*
-		 * We're called from a platform device,
+		 * We're called in callback from HSI
 		 * and don't know the context we're running in.
 		 */
 		if (in_interrupt())
@@ -639,7 +625,7 @@ static void cfhsi_rx_done(struct cfhsi *cfhsi)
 
 	desc = (struct cfhsi_desc *)cfhsi->rx_buf;
 
-	dev_dbg(&cfhsi->ndev->dev, "%s\n", __func__);
+	netdev_dbg(cfhsi->ndev, "%s\n", __func__);
 
 	if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
 		return;
@@ -647,7 +633,7 @@ static void cfhsi_rx_done(struct cfhsi *cfhsi)
 	/* Update inactivity timer if pending. */
 	spin_lock_bh(&cfhsi->lock);
 	mod_timer_pending(&cfhsi->inactivity_timer,
-			jiffies + cfhsi->inactivity_timeout);
+			jiffies + cfhsi->cfg.inactivity_timeout);
 	spin_unlock_bh(&cfhsi->lock);
 
 	if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) {
@@ -680,12 +666,11 @@ static void cfhsi_rx_done(struct cfhsi *cfhsi)
 			if (desc_pld_len < 0)
 				goto out_of_sync;
 
-			if (desc_pld_len > 0)
+			if (desc_pld_len > 0) {
 				rx_len = desc_pld_len;
-
-			if (desc_pld_len > 0 &&
-					(piggy_desc->header & CFHSI_PIGGY_DESC))
-				rx_len += CFHSI_DESC_SZ;
+				if (piggy_desc->header & CFHSI_PIGGY_DESC)
+					rx_len += CFHSI_DESC_SZ;
+			}
 
 			/*
 			 * Copy needed information from the piggy-backed
@@ -693,10 +678,6 @@ static void cfhsi_rx_done(struct cfhsi *cfhsi)
 			 */
 			memcpy(rx_buf, (u8 *)piggy_desc,
 					CFHSI_DESC_SHORT_SZ);
-			/* Mark no embedded frame here */
-			piggy_desc->offset = 0;
-			if (desc_pld_len == -EPROTO)
-				goto out_of_sync;
 		}
 	}
 
@@ -712,13 +693,13 @@ static void cfhsi_rx_done(struct cfhsi *cfhsi)
 	/* Initiate next read */
 	if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) {
 		/* Set up new transfer. */
-		dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n",
+		netdev_dbg(cfhsi->ndev, "%s: Start RX.\n",
 				__func__);
 
-		res = cfhsi->dev->cfhsi_rx(rx_ptr, rx_len,
-				cfhsi->dev);
+		res = cfhsi->ops->cfhsi_rx(rx_ptr, rx_len,
+				cfhsi->ops);
 		if (WARN_ON(res < 0)) {
-			dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n",
+			netdev_err(cfhsi->ndev, "%s: RX error %d.\n",
 				__func__, res);
 			cfhsi->ndev->stats.rx_errors++;
 			cfhsi->ndev->stats.rx_dropped++;
@@ -737,6 +718,8 @@ static void cfhsi_rx_done(struct cfhsi *cfhsi)
 			/* Extract any payload in piggyback descriptor. */
 			if (cfhsi_rx_desc(piggy_desc, cfhsi) < 0)
 				goto out_of_sync;
+			/* Mark no embedded frame after extracting it */
+			piggy_desc->offset = 0;
 		}
 	}
 
@@ -753,7 +736,7 @@ static void cfhsi_rx_done(struct cfhsi *cfhsi)
 	return;
 
 out_of_sync:
-	dev_err(&cfhsi->ndev->dev, "%s: Out of sync.\n", __func__);
+	netdev_err(cfhsi->ndev, "%s: Out of sync.\n", __func__);
 	print_hex_dump_bytes("--> ", DUMP_PREFIX_NONE,
 			cfhsi->rx_buf, CFHSI_DESC_SZ);
 	schedule_work(&cfhsi->out_of_sync_work);
@@ -763,18 +746,18 @@ static void cfhsi_rx_slowpath(unsigned long arg)
 {
 	struct cfhsi *cfhsi = (struct cfhsi *)arg;
 
-	dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+	netdev_dbg(cfhsi->ndev, "%s.\n",
 		__func__);
 
 	cfhsi_rx_done(cfhsi);
 }
 
-static void cfhsi_rx_done_cb(struct cfhsi_drv *drv)
+static void cfhsi_rx_done_cb(struct cfhsi_cb_ops *cb_ops)
 {
 	struct cfhsi *cfhsi;
 
-	cfhsi = container_of(drv, struct cfhsi, drv);
-	dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+	cfhsi = container_of(cb_ops, struct cfhsi, cb_ops);
+	netdev_dbg(cfhsi->ndev, "%s.\n",
 		__func__);
 
 	if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
@@ -807,9 +790,9 @@ static void cfhsi_wake_up(struct work_struct *work)
 	}
 
 	/* Activate wake line. */
-	cfhsi->dev->cfhsi_wake_up(cfhsi->dev);
+	cfhsi->ops->cfhsi_wake_up(cfhsi->ops);
 
-	dev_dbg(&cfhsi->ndev->dev, "%s: Start waiting.\n",
+	netdev_dbg(cfhsi->ndev, "%s: Start waiting.\n",
 		__func__);
 
 	/* Wait for acknowledge. */
@@ -819,33 +802,33 @@ static void cfhsi_wake_up(struct work_struct *work)
 							&cfhsi->bits), ret);
 	if (unlikely(ret < 0)) {
 		/* Interrupted by signal. */
-		dev_err(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n",
+		netdev_err(cfhsi->ndev, "%s: Signalled: %ld.\n",
 			__func__, ret);
 
 		clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
-		cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
+		cfhsi->ops->cfhsi_wake_down(cfhsi->ops);
 		return;
 	} else if (!ret) {
 		bool ca_wake = false;
 		size_t fifo_occupancy = 0;
 
 		/* Wakeup timeout */
-		dev_dbg(&cfhsi->ndev->dev, "%s: Timeout.\n",
+		netdev_dbg(cfhsi->ndev, "%s: Timeout.\n",
 			__func__);
 
 		/* Check FIFO to check if modem has sent something. */
-		WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
+		WARN_ON(cfhsi->ops->cfhsi_fifo_occupancy(cfhsi->ops,
 					&fifo_occupancy));
 
-		dev_dbg(&cfhsi->ndev->dev, "%s: Bytes in FIFO: %u.\n",
+		netdev_dbg(cfhsi->ndev, "%s: Bytes in FIFO: %u.\n",
 				__func__, (unsigned) fifo_occupancy);
 
 		/* Check if we misssed the interrupt. */
-		WARN_ON(cfhsi->dev->cfhsi_get_peer_wake(cfhsi->dev,
+		WARN_ON(cfhsi->ops->cfhsi_get_peer_wake(cfhsi->ops,
 							&ca_wake));
 
 		if (ca_wake) {
-			dev_err(&cfhsi->ndev->dev, "%s: CA Wake missed !.\n",
+			netdev_err(cfhsi->ndev, "%s: CA Wake missed !.\n",
 				__func__);
 
 			/* Clear the CFHSI_WAKE_UP_ACK bit to prevent race. */
@@ -856,11 +839,11 @@ static void cfhsi_wake_up(struct work_struct *work)
 		}
 
 		clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
-		cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
+		cfhsi->ops->cfhsi_wake_down(cfhsi->ops);
 		return;
 	}
 wake_ack:
-	dev_dbg(&cfhsi->ndev->dev, "%s: Woken.\n",
+	netdev_dbg(cfhsi->ndev, "%s: Woken.\n",
 		__func__);
 
 	/* Clear power up bit. */
@@ -868,11 +851,11 @@ wake_ack:
 	clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
 
 	/* Resume read operation. */
-	dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n", __func__);
-	res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len, cfhsi->dev);
+	netdev_dbg(cfhsi->ndev, "%s: Start RX.\n", __func__);
+	res = cfhsi->ops->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len, cfhsi->ops);
 
 	if (WARN_ON(res < 0))
-		dev_err(&cfhsi->ndev->dev, "%s: RX err %d.\n", __func__, res);
+		netdev_err(cfhsi->ndev, "%s: RX err %d.\n", __func__, res);
 
 	/* Clear power up acknowledment. */
 	clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
@@ -881,16 +864,16 @@ wake_ack:
 
 	/* Resume transmit if queues are not empty. */
 	if (!cfhsi_tx_queue_len(cfhsi)) {
-		dev_dbg(&cfhsi->ndev->dev, "%s: Peer wake, start timer.\n",
+		netdev_dbg(cfhsi->ndev, "%s: Peer wake, start timer.\n",
 			__func__);
 		/* Start inactivity timer. */
 		mod_timer(&cfhsi->inactivity_timer,
-				jiffies + cfhsi->inactivity_timeout);
+				jiffies + cfhsi->cfg.inactivity_timeout);
 		spin_unlock_bh(&cfhsi->lock);
 		return;
 	}
 
-	dev_dbg(&cfhsi->ndev->dev, "%s: Host wake.\n",
+	netdev_dbg(cfhsi->ndev, "%s: Host wake.\n",
 		__func__);
 
 	spin_unlock_bh(&cfhsi->lock);
@@ -900,14 +883,14 @@ wake_ack:
 
 	if (likely(len > 0)) {
 		/* Set up new transfer. */
-		res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev);
+		res = cfhsi->ops->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->ops);
 		if (WARN_ON(res < 0)) {
-			dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n",
+			netdev_err(cfhsi->ndev, "%s: TX error %d.\n",
 				__func__, res);
 			cfhsi_abort_tx(cfhsi);
 		}
 	} else {
-		dev_err(&cfhsi->ndev->dev,
+		netdev_err(cfhsi->ndev,
 				"%s: Failed to create HSI frame: %d.\n",
 				__func__, len);
 	}
@@ -921,13 +904,13 @@ static void cfhsi_wake_down(struct work_struct *work)
 	int retry = CFHSI_WAKE_TOUT;
 
 	cfhsi = container_of(work, struct cfhsi, wake_down_work);
-	dev_dbg(&cfhsi->ndev->dev, "%s.\n", __func__);
+	netdev_dbg(cfhsi->ndev, "%s.\n", __func__);
 
 	if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
 		return;
 
 	/* Deactivate wake line. */
-	cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
+	cfhsi->ops->cfhsi_wake_down(cfhsi->ops);
 
 	/* Wait for acknowledge. */
 	ret = CFHSI_WAKE_TOUT;
@@ -936,26 +919,26 @@ static void cfhsi_wake_down(struct work_struct *work)
 							&cfhsi->bits), ret);
 	if (ret < 0) {
 		/* Interrupted by signal. */
-		dev_err(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n",
+		netdev_err(cfhsi->ndev, "%s: Signalled: %ld.\n",
 			__func__, ret);
 		return;
 	} else if (!ret) {
 		bool ca_wake = true;
 
 		/* Timeout */
-		dev_err(&cfhsi->ndev->dev, "%s: Timeout.\n", __func__);
+		netdev_err(cfhsi->ndev, "%s: Timeout.\n", __func__);
 
 		/* Check if we misssed the interrupt. */
-		WARN_ON(cfhsi->dev->cfhsi_get_peer_wake(cfhsi->dev,
+		WARN_ON(cfhsi->ops->cfhsi_get_peer_wake(cfhsi->ops,
 							&ca_wake));
 		if (!ca_wake)
-			dev_err(&cfhsi->ndev->dev, "%s: CA Wake missed !.\n",
+			netdev_err(cfhsi->ndev, "%s: CA Wake missed !.\n",
 				__func__);
 	}
 
 	/* Check FIFO occupancy. */
 	while (retry) {
-		WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
+		WARN_ON(cfhsi->ops->cfhsi_fifo_occupancy(cfhsi->ops,
 							&fifo_occupancy));
 
 		if (!fifo_occupancy)
@@ -967,14 +950,13 @@ static void cfhsi_wake_down(struct work_struct *work)
 	}
 
 	if (!retry)
-		dev_err(&cfhsi->ndev->dev, "%s: FIFO Timeout.\n", __func__);
+		netdev_err(cfhsi->ndev, "%s: FIFO Timeout.\n", __func__);
 
 	/* Clear AWAKE condition. */
 	clear_bit(CFHSI_AWAKE, &cfhsi->bits);
 
 	/* Cancel pending RX requests. */
-	cfhsi->dev->cfhsi_rx_cancel(cfhsi->dev);
-
+	cfhsi->ops->cfhsi_rx_cancel(cfhsi->ops);
 }
 
 static void cfhsi_out_of_sync(struct work_struct *work)
@@ -988,12 +970,12 @@ static void cfhsi_out_of_sync(struct work_struct *work)
 	rtnl_unlock();
 }
 
-static void cfhsi_wake_up_cb(struct cfhsi_drv *drv)
+static void cfhsi_wake_up_cb(struct cfhsi_cb_ops *cb_ops)
 {
 	struct cfhsi *cfhsi = NULL;
 
-	cfhsi = container_of(drv, struct cfhsi, drv);
-	dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+	cfhsi = container_of(cb_ops, struct cfhsi, cb_ops);
+	netdev_dbg(cfhsi->ndev, "%s.\n",
 		__func__);
 
 	set_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
@@ -1007,12 +989,12 @@ static void cfhsi_wake_up_cb(struct cfhsi_drv *drv)
 		queue_work(cfhsi->wq, &cfhsi->wake_up_work);
 }
 
-static void cfhsi_wake_down_cb(struct cfhsi_drv *drv)
+static void cfhsi_wake_down_cb(struct cfhsi_cb_ops *cb_ops)
 {
 	struct cfhsi *cfhsi = NULL;
 
-	cfhsi = container_of(drv, struct cfhsi, drv);
-	dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+	cfhsi = container_of(cb_ops, struct cfhsi, cb_ops);
+	netdev_dbg(cfhsi->ndev, "%s.\n",
 		__func__);
 
 	/* Initiating low power is only permitted by the host (us). */
@@ -1024,7 +1006,7 @@ static void cfhsi_aggregation_tout(unsigned long arg)
 {
 	struct cfhsi *cfhsi = (struct cfhsi *)arg;
 
-	dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+	netdev_dbg(cfhsi->ndev, "%s.\n",
 		__func__);
 
 	cfhsi_start_tx(cfhsi);
@@ -1077,7 +1059,7 @@ static int cfhsi_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	/* Send flow off if number of packets is above high water mark. */
 	if (!cfhsi->flow_off_sent &&
-		cfhsi_tx_queue_len(cfhsi) > cfhsi->q_high_mark &&
+		cfhsi_tx_queue_len(cfhsi) > cfhsi->cfg.q_high_mark &&
 		cfhsi->cfdev.flowctrl) {
 		cfhsi->flow_off_sent = 1;
 		cfhsi->cfdev.flowctrl(cfhsi->ndev, OFF);
@@ -1114,9 +1096,9 @@ static int cfhsi_xmit(struct sk_buff *skb, struct net_device *dev)
 		WARN_ON(!len);
 
 		/* Set up new transfer. */
-		res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev);
+		res = cfhsi->ops->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->ops);
 		if (WARN_ON(res < 0)) {
-			dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n",
+			netdev_err(cfhsi->ndev, "%s: TX error %d.\n",
 				__func__, res);
 			cfhsi_abort_tx(cfhsi);
 		}
@@ -1129,19 +1111,19 @@ static int cfhsi_xmit(struct sk_buff *skb, struct net_device *dev)
 	return 0;
 }
 
-static const struct net_device_ops cfhsi_ops;
+static const struct net_device_ops cfhsi_netdevops;
 
 static void cfhsi_setup(struct net_device *dev)
 {
 	int i;
 	struct cfhsi *cfhsi = netdev_priv(dev);
 	dev->features = 0;
-	dev->netdev_ops = &cfhsi_ops;
 	dev->type = ARPHRD_CAIF;
 	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
 	dev->mtu = CFHSI_MAX_CAIF_FRAME_SZ;
 	dev->tx_queue_len = 0;
 	dev->destructor = free_netdev;
+	dev->netdev_ops = &cfhsi_netdevops;
 	for (i = 0; i < CFHSI_PRIO_LAST; ++i)
 		skb_queue_head_init(&cfhsi->qhead[i]);
 	cfhsi->cfdev.link_select = CAIF_LINK_HIGH_BANDW;
@@ -1149,42 +1131,7 @@ static void cfhsi_setup(struct net_device *dev)
 	cfhsi->cfdev.use_stx = false;
 	cfhsi->cfdev.use_fcs = false;
 	cfhsi->ndev = dev;
-}
-
-int cfhsi_probe(struct platform_device *pdev)
-{
-	struct cfhsi *cfhsi = NULL;
-	struct net_device *ndev;
-
-	int res;
-
-	ndev = alloc_netdev(sizeof(struct cfhsi), "cfhsi%d", cfhsi_setup);
-	if (!ndev)
-		return -ENODEV;
-
-	cfhsi = netdev_priv(ndev);
-	cfhsi->ndev = ndev;
-	cfhsi->pdev = pdev;
-
-	/* Assign the HSI device. */
-	cfhsi->dev = pdev->dev.platform_data;
-
-	/* Assign the driver to this HSI device. */
-	cfhsi->dev->drv = &cfhsi->drv;
-
-	/* Register network device. */
-	res = register_netdev(ndev);
-	if (res) {
-		dev_err(&ndev->dev, "%s: Registration error: %d.\n",
-			__func__, res);
-		free_netdev(ndev);
-	}
-	/* Add CAIF HSI device to list. */
-	spin_lock(&cfhsi_list_lock);
-	list_add_tail(&cfhsi->list, &cfhsi_list);
-	spin_unlock(&cfhsi_list_lock);
-
-	return res;
+	cfhsi->cfg = hsi_default_config;
 }
 
 static int cfhsi_open(struct net_device *ndev)
@@ -1200,9 +1147,6 @@ static int cfhsi_open(struct net_device *ndev)
 
 	/* Set flow info */
 	cfhsi->flow_off_sent = 0;
-	cfhsi->q_low_mark = LOW_WATER_MARK;
-	cfhsi->q_high_mark = HIGH_WATER_MARK;
-
 
 	/*
 	 * Allocate a TX buffer with the size of a HSI packet descriptors
@@ -1230,20 +1174,8 @@ static int cfhsi_open(struct net_device *ndev)
 		goto err_alloc_rx_flip;
 	}
 
-	/* Pre-calculate inactivity timeout. */
-	if (inactivity_timeout != -1) {
-		cfhsi->inactivity_timeout =
-				inactivity_timeout * HZ / 1000;
-		if (!cfhsi->inactivity_timeout)
-			cfhsi->inactivity_timeout = 1;
-		else if (cfhsi->inactivity_timeout > NEXT_TIMER_MAX_DELTA)
-			cfhsi->inactivity_timeout = NEXT_TIMER_MAX_DELTA;
-	} else {
-		cfhsi->inactivity_timeout = NEXT_TIMER_MAX_DELTA;
-	}
-
 	/* Initialize aggregation timeout */
-	cfhsi->aggregation_timeout = aggregation_timeout;
+	cfhsi->cfg.aggregation_timeout = hsi_default_config.aggregation_timeout;
 
 	/* Initialize recieve vaiables. */
 	cfhsi->rx_ptr = cfhsi->rx_buf;
@@ -1253,10 +1185,10 @@ static int cfhsi_open(struct net_device *ndev)
 	spin_lock_init(&cfhsi->lock);
 
 	/* Set up the driver. */
-	cfhsi->drv.tx_done_cb = cfhsi_tx_done_cb;
-	cfhsi->drv.rx_done_cb = cfhsi_rx_done_cb;
-	cfhsi->drv.wake_up_cb = cfhsi_wake_up_cb;
-	cfhsi->drv.wake_down_cb = cfhsi_wake_down_cb;
+	cfhsi->cb_ops.tx_done_cb = cfhsi_tx_done_cb;
+	cfhsi->cb_ops.rx_done_cb = cfhsi_rx_done_cb;
+	cfhsi->cb_ops.wake_up_cb = cfhsi_wake_up_cb;
+	cfhsi->cb_ops.wake_down_cb = cfhsi_wake_down_cb;
 
 	/* Initialize the work queues. */
 	INIT_WORK(&cfhsi->wake_up_work, cfhsi_wake_up);
@@ -1270,9 +1202,9 @@ static int cfhsi_open(struct net_device *ndev)
 	clear_bit(CFHSI_AWAKE, &cfhsi->bits);
 
 	/* Create work thread. */
-	cfhsi->wq = create_singlethread_workqueue(cfhsi->pdev->name);
+	cfhsi->wq = create_singlethread_workqueue(cfhsi->ndev->name);
 	if (!cfhsi->wq) {
-		dev_err(&cfhsi->ndev->dev, "%s: Failed to create work queue.\n",
+		netdev_err(cfhsi->ndev, "%s: Failed to create work queue.\n",
 			__func__);
 		res = -ENODEV;
 		goto err_create_wq;
@@ -1297,9 +1229,9 @@ static int cfhsi_open(struct net_device *ndev)
 	cfhsi->aggregation_timer.function = cfhsi_aggregation_tout;
 
 	/* Activate HSI interface. */
-	res = cfhsi->dev->cfhsi_up(cfhsi->dev);
+	res = cfhsi->ops->cfhsi_up(cfhsi->ops);
 	if (res) {
-		dev_err(&cfhsi->ndev->dev,
+		netdev_err(cfhsi->ndev,
 			"%s: can't activate HSI interface: %d.\n",
 			__func__, res);
 		goto err_activate;
@@ -1308,14 +1240,14 @@ static int cfhsi_open(struct net_device *ndev)
 	/* Flush FIFO */
 	res = cfhsi_flush_fifo(cfhsi);
 	if (res) {
-		dev_err(&cfhsi->ndev->dev, "%s: Can't flush FIFO: %d.\n",
+		netdev_err(cfhsi->ndev, "%s: Can't flush FIFO: %d.\n",
 			__func__, res);
 		goto err_net_reg;
 	}
 	return res;
 
  err_net_reg:
-	cfhsi->dev->cfhsi_down(cfhsi->dev);
+	cfhsi->ops->cfhsi_down(cfhsi->ops);
  err_activate:
 	destroy_workqueue(cfhsi->wq);
  err_create_wq:
@@ -1345,7 +1277,7 @@ static int cfhsi_close(struct net_device *ndev)
 	del_timer_sync(&cfhsi->aggregation_timer);
 
 	/* Cancel pending RX request (if any) */
-	cfhsi->dev->cfhsi_rx_cancel(cfhsi->dev);
+	cfhsi->ops->cfhsi_rx_cancel(cfhsi->ops);
 
 	/* Destroy workqueue */
 	destroy_workqueue(cfhsi->wq);
@@ -1358,7 +1290,7 @@ static int cfhsi_close(struct net_device *ndev)
 	cfhsi_abort_tx(cfhsi);
 
 	/* Deactivate interface */
-	cfhsi->dev->cfhsi_down(cfhsi->dev);
+	cfhsi->ops->cfhsi_down(cfhsi->ops);
 
 	/* Free buffers. */
 	kfree(tx_buf);
@@ -1367,85 +1299,184 @@ static int cfhsi_close(struct net_device *ndev)
 	return 0;
 }
 
-static const struct net_device_ops cfhsi_ops = {
+static void cfhsi_uninit(struct net_device *dev)
+{
+	struct cfhsi *cfhsi = netdev_priv(dev);
+	ASSERT_RTNL();
+	symbol_put(cfhsi_get_device);
+	list_del(&cfhsi->list);
+}
+
+static const struct net_device_ops cfhsi_netdevops = {
+	.ndo_uninit = cfhsi_uninit,
 	.ndo_open = cfhsi_open,
 	.ndo_stop = cfhsi_close,
 	.ndo_start_xmit = cfhsi_xmit
 };
 
-int cfhsi_remove(struct platform_device *pdev)
+static void cfhsi_netlink_parms(struct nlattr *data[], struct cfhsi *cfhsi)
 {
-	struct list_head *list_node;
-	struct list_head *n;
-	struct cfhsi *cfhsi = NULL;
-	struct cfhsi_dev *dev;
+	int i;
 
-	dev = (struct cfhsi_dev *)pdev->dev.platform_data;
-	spin_lock(&cfhsi_list_lock);
-	list_for_each_safe(list_node, n, &cfhsi_list) {
-		cfhsi = list_entry(list_node, struct cfhsi, list);
-		/* Find the corresponding device. */
-		if (cfhsi->dev == dev) {
-			/* Remove from list. */
-			list_del(list_node);
-			spin_unlock(&cfhsi_list_lock);
-			return 0;
-		}
+	if (!data) {
+		pr_debug("no params data found\n");
+		return;
 	}
-	spin_unlock(&cfhsi_list_lock);
-	return -ENODEV;
+
+	i = __IFLA_CAIF_HSI_INACTIVITY_TOUT;
+	/*
+	 * Inactivity timeout in millisecs. Lowest possible value is 1,
+	 * and highest possible is NEXT_TIMER_MAX_DELTA.
+	 */
+	if (data[i]) {
+		u32 inactivity_timeout = nla_get_u32(data[i]);
+		/* Pre-calculate inactivity timeout. */
+		cfhsi->cfg.inactivity_timeout =	inactivity_timeout * HZ / 1000;
+		if (cfhsi->cfg.inactivity_timeout == 0)
+			cfhsi->cfg.inactivity_timeout = 1;
+		else if (cfhsi->cfg.inactivity_timeout > NEXT_TIMER_MAX_DELTA)
+			cfhsi->cfg.inactivity_timeout = NEXT_TIMER_MAX_DELTA;
+	}
+
+	i = __IFLA_CAIF_HSI_AGGREGATION_TOUT;
+	if (data[i])
+		cfhsi->cfg.aggregation_timeout = nla_get_u32(data[i]);
+
+	i = __IFLA_CAIF_HSI_HEAD_ALIGN;
+	if (data[i])
+		cfhsi->cfg.head_align = nla_get_u32(data[i]);
+
+	i = __IFLA_CAIF_HSI_TAIL_ALIGN;
+	if (data[i])
+		cfhsi->cfg.tail_align = nla_get_u32(data[i]);
+
+	i = __IFLA_CAIF_HSI_QHIGH_WATERMARK;
+	if (data[i])
+		cfhsi->cfg.q_high_mark = nla_get_u32(data[i]);
+
+	i = __IFLA_CAIF_HSI_QLOW_WATERMARK;
+	if (data[i])
+		cfhsi->cfg.q_low_mark = nla_get_u32(data[i]);
+}
+
+static int caif_hsi_changelink(struct net_device *dev, struct nlattr *tb[],
+				struct nlattr *data[])
+{
+	cfhsi_netlink_parms(data, netdev_priv(dev));
+	netdev_state_change(dev);
+	return 0;
 }
 
-struct platform_driver cfhsi_plat_drv = {
-	.probe = cfhsi_probe,
-	.remove = cfhsi_remove,
-	.driver = {
-		   .name = "cfhsi",
-		   .owner = THIS_MODULE,
-		   },
+static const struct nla_policy caif_hsi_policy[__IFLA_CAIF_HSI_MAX + 1] = {
+	[__IFLA_CAIF_HSI_INACTIVITY_TOUT] = { .type = NLA_U32, .len = 4 },
+	[__IFLA_CAIF_HSI_AGGREGATION_TOUT] = { .type = NLA_U32, .len = 4 },
+	[__IFLA_CAIF_HSI_HEAD_ALIGN] = { .type = NLA_U32, .len = 4 },
+	[__IFLA_CAIF_HSI_TAIL_ALIGN] = { .type = NLA_U32, .len = 4 },
+	[__IFLA_CAIF_HSI_QHIGH_WATERMARK] = { .type = NLA_U32, .len = 4 },
+	[__IFLA_CAIF_HSI_QLOW_WATERMARK] = { .type = NLA_U32, .len = 4 },
 };
 
-static void __exit cfhsi_exit_module(void)
+static size_t caif_hsi_get_size(const struct net_device *dev)
+{
+	int i;
+	size_t s = 0;
+	for (i = __IFLA_CAIF_HSI_UNSPEC + 1; i < __IFLA_CAIF_HSI_MAX; i++)
+		s += nla_total_size(caif_hsi_policy[i].len);
+	return s;
+}
+
+static int caif_hsi_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+	struct cfhsi *cfhsi = netdev_priv(dev);
+
+	if (nla_put_u32(skb, __IFLA_CAIF_HSI_INACTIVITY_TOUT,
+			cfhsi->cfg.inactivity_timeout) ||
+	    nla_put_u32(skb, __IFLA_CAIF_HSI_AGGREGATION_TOUT,
+			cfhsi->cfg.aggregation_timeout) ||
+	    nla_put_u32(skb, __IFLA_CAIF_HSI_HEAD_ALIGN,
+			cfhsi->cfg.head_align) ||
+	    nla_put_u32(skb, __IFLA_CAIF_HSI_TAIL_ALIGN,
+			cfhsi->cfg.tail_align) ||
+	    nla_put_u32(skb, __IFLA_CAIF_HSI_QHIGH_WATERMARK,
+			cfhsi->cfg.q_high_mark) ||
+	    nla_put_u32(skb, __IFLA_CAIF_HSI_QLOW_WATERMARK,
+			cfhsi->cfg.q_low_mark))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int caif_hsi_newlink(struct net *src_net, struct net_device *dev,
+			  struct nlattr *tb[], struct nlattr *data[])
 {
-	struct list_head *list_node;
-	struct list_head *n;
 	struct cfhsi *cfhsi = NULL;
+	struct cfhsi_ops *(*get_ops)(void);
 
-	spin_lock(&cfhsi_list_lock);
-	list_for_each_safe(list_node, n, &cfhsi_list) {
-		cfhsi = list_entry(list_node, struct cfhsi, list);
+	ASSERT_RTNL();
 
-		/* Remove from list. */
-		list_del(list_node);
-		spin_unlock(&cfhsi_list_lock);
+	cfhsi = netdev_priv(dev);
+	cfhsi_netlink_parms(data, cfhsi);
+	dev_net_set(cfhsi->ndev, src_net);
+
+	get_ops = symbol_get(cfhsi_get_ops);
+	if (!get_ops) {
+		pr_err("%s: failed to get the cfhsi_ops\n", __func__);
+		return -ENODEV;
+	}
 
-		unregister_netdevice(cfhsi->ndev);
+	/* Assign the HSI device. */
+	cfhsi->ops = (*get_ops)();
+	if (!cfhsi->ops) {
+		pr_err("%s: failed to get the cfhsi_ops\n", __func__);
+		goto err;
+	}
 
-		spin_lock(&cfhsi_list_lock);
+	/* Assign the driver to this HSI device. */
+	cfhsi->ops->cb_ops = &cfhsi->cb_ops;
+	if (register_netdevice(dev)) {
+		pr_warn("%s: caif_hsi device registration failed\n", __func__);
+		goto err;
 	}
-	spin_unlock(&cfhsi_list_lock);
+	/* Add CAIF HSI device to list. */
+	list_add_tail(&cfhsi->list, &cfhsi_list);
 
-	/* Unregister platform driver. */
-	platform_driver_unregister(&cfhsi_plat_drv);
+	return 0;
+err:
+	symbol_put(cfhsi_get_ops);
+	return -ENODEV;
 }
 
-static int __init cfhsi_init_module(void)
+static struct rtnl_link_ops caif_hsi_link_ops __read_mostly = {
+	.kind		= "cfhsi",
+	.priv_size	= sizeof(struct cfhsi),
+	.setup		= cfhsi_setup,
+	.maxtype	= __IFLA_CAIF_HSI_MAX,
+	.policy	= caif_hsi_policy,
+	.newlink	= caif_hsi_newlink,
+	.changelink	= caif_hsi_changelink,
+	.get_size	= caif_hsi_get_size,
+	.fill_info	= caif_hsi_fill_info,
+};
+
+static void __exit cfhsi_exit_module(void)
 {
-	int result;
+	struct list_head *list_node;
+	struct list_head *n;
+	struct cfhsi *cfhsi;
 
-	/* Initialize spin lock. */
-	spin_lock_init(&cfhsi_list_lock);
+	rtnl_link_unregister(&caif_hsi_link_ops);
 
-	/* Register platform driver. */
-	result = platform_driver_register(&cfhsi_plat_drv);
-	if (result) {
-		printk(KERN_ERR "Could not register platform HSI driver: %d.\n",
-			result);
-		goto err_dev_register;
+	rtnl_lock();
+	list_for_each_safe(list_node, n, &cfhsi_list) {
+		cfhsi = list_entry(list_node, struct cfhsi, list);
+		unregister_netdev(cfhsi->ndev);
 	}
+	rtnl_unlock();
+}
 
- err_dev_register:
-	return result;
+static int __init cfhsi_init_module(void)
+{
+	return rtnl_link_register(&caif_hsi_link_ops);
 }
 
 module_init(cfhsi_init_module);
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c
index 3f88473..ea31438 100644
--- a/drivers/net/can/bfin_can.c
+++ b/drivers/net/can/bfin_can.c
@@ -597,7 +597,7 @@ static int __devinit bfin_can_probe(struct platform_device *pdev)
 	dev_info(&pdev->dev,
 		"%s device registered"
 		"(&reg_base=%p, rx_irq=%d, tx_irq=%d, err_irq=%d, sclk=%d)\n",
-		DRV_NAME, (void *)priv->membase, priv->rx_irq,
+		DRV_NAME, priv->membase, priv->rx_irq,
 		priv->tx_irq, priv->err_irq, priv->can.clock.freq);
 	return 0;
 
diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig
index ffb9773..3b83baf 100644
--- a/drivers/net/can/c_can/Kconfig
+++ b/drivers/net/can/c_can/Kconfig
@@ -1,15 +1,23 @@
 menuconfig CAN_C_CAN
-	tristate "Bosch C_CAN devices"
+	tristate "Bosch C_CAN/D_CAN devices"
 	depends on CAN_DEV && HAS_IOMEM
 
 if CAN_C_CAN
 
 config CAN_C_CAN_PLATFORM
-	tristate "Generic Platform Bus based C_CAN driver"
+	tristate "Generic Platform Bus based C_CAN/D_CAN driver"
 	---help---
-	  This driver adds support for the C_CAN chips connected to
-	  the "platform bus" (Linux abstraction for directly to the
+	  This driver adds support for the C_CAN/D_CAN chips connected
+	  to the "platform bus" (Linux abstraction for directly to the
 	  processor attached devices) which can be found on various
-	  boards from ST Microelectronics (http://www.st.com)
-	  like the SPEAr1310 and SPEAr320 evaluation boards.
+	  boards from ST Microelectronics (http://www.st.com) like the
+	  SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com)
+	  boards like am335x, dm814x, dm813x and dm811x.
+
+config CAN_C_CAN_PCI
+	tristate "Generic PCI Bus based C_CAN/D_CAN driver"
+	depends on PCI
+	---help---
+	  This driver adds support for the C_CAN/D_CAN chips connected
+	  to the PCI bus.
 endif
diff --git a/drivers/net/can/c_can/Makefile b/drivers/net/can/c_can/Makefile
index 9273f6d..ad1cc84 100644
--- a/drivers/net/can/c_can/Makefile
+++ b/drivers/net/can/c_can/Makefile
@@ -4,5 +4,6 @@
 
 obj-$(CONFIG_CAN_C_CAN) += c_can.o
 obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
+obj-$(CONFIG_CAN_C_CAN_PCI) += c_can_pci.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index 8dc84d6..eea6608 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -41,6 +41,10 @@
 
 #include "c_can.h"
 
+/* Number of interface registers */
+#define IF_ENUM_REG_LEN		11
+#define C_CAN_IFACE(reg, iface)	(C_CAN_IF1_##reg + (iface) * IF_ENUM_REG_LEN)
+
 /* control register */
 #define CONTROL_TEST		BIT(7)
 #define CONTROL_CCE		BIT(6)
@@ -209,10 +213,10 @@ static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv)
 			C_CAN_MSG_OBJ_TX_FIRST;
 }
 
-static u32 c_can_read_reg32(struct c_can_priv *priv, void *reg)
+static u32 c_can_read_reg32(struct c_can_priv *priv, enum reg index)
 {
-	u32 val = priv->read_reg(priv, reg);
-	val |= ((u32) priv->read_reg(priv, reg + 2)) << 16;
+	u32 val = priv->read_reg(priv, index);
+	val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
 	return val;
 }
 
@@ -220,14 +224,14 @@ static void c_can_enable_all_interrupts(struct c_can_priv *priv,
 						int enable)
 {
 	unsigned int cntrl_save = priv->read_reg(priv,
-						&priv->regs->control);
+						C_CAN_CTRL_REG);
 
 	if (enable)
 		cntrl_save |= (CONTROL_SIE | CONTROL_EIE | CONTROL_IE);
 	else
 		cntrl_save &= ~(CONTROL_EIE | CONTROL_IE | CONTROL_SIE);
 
-	priv->write_reg(priv, &priv->regs->control, cntrl_save);
+	priv->write_reg(priv, C_CAN_CTRL_REG, cntrl_save);
 }
 
 static inline int c_can_msg_obj_is_busy(struct c_can_priv *priv, int iface)
@@ -235,7 +239,7 @@ static inline int c_can_msg_obj_is_busy(struct c_can_priv *priv, int iface)
 	int count = MIN_TIMEOUT_VALUE;
 
 	while (count && priv->read_reg(priv,
-				&priv->regs->ifregs[iface].com_req) &
+				C_CAN_IFACE(COMREQ_REG, iface)) &
 				IF_COMR_BUSY) {
 		count--;
 		udelay(1);
@@ -258,9 +262,9 @@ static inline void c_can_object_get(struct net_device *dev,
 	 * register and message RAM must be complete in 6 CAN-CLK
 	 * period.
 	 */
-	priv->write_reg(priv, &priv->regs->ifregs[iface].com_mask,
+	priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
 			IFX_WRITE_LOW_16BIT(mask));
-	priv->write_reg(priv, &priv->regs->ifregs[iface].com_req,
+	priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
 			IFX_WRITE_LOW_16BIT(objno));
 
 	if (c_can_msg_obj_is_busy(priv, iface))
@@ -278,9 +282,9 @@ static inline void c_can_object_put(struct net_device *dev,
 	 * register and message RAM must be complete in 6 CAN-CLK
 	 * period.
 	 */
-	priv->write_reg(priv, &priv->regs->ifregs[iface].com_mask,
+	priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
 			(IF_COMM_WR | IFX_WRITE_LOW_16BIT(mask)));
-	priv->write_reg(priv, &priv->regs->ifregs[iface].com_req,
+	priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
 			IFX_WRITE_LOW_16BIT(objno));
 
 	if (c_can_msg_obj_is_busy(priv, iface))
@@ -306,18 +310,18 @@ static void c_can_write_msg_object(struct net_device *dev,
 
 	flags |= IF_ARB_MSGVAL;
 
-	priv->write_reg(priv, &priv->regs->ifregs[iface].arb1,
+	priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
 				IFX_WRITE_LOW_16BIT(id));
-	priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, flags |
+	priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), flags |
 				IFX_WRITE_HIGH_16BIT(id));
 
 	for (i = 0; i < frame->can_dlc; i += 2) {
-		priv->write_reg(priv, &priv->regs->ifregs[iface].data[i / 2],
+		priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2,
 				frame->data[i] | (frame->data[i + 1] << 8));
 	}
 
 	/* enable interrupt for this message object */
-	priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl,
+	priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
 			IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB |
 			frame->can_dlc);
 	c_can_object_put(dev, iface, objno, IF_COMM_ALL);
@@ -329,7 +333,7 @@ static inline void c_can_mark_rx_msg_obj(struct net_device *dev,
 {
 	struct c_can_priv *priv = netdev_priv(dev);
 
-	priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl,
+	priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
 			ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND));
 	c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
 
@@ -343,7 +347,7 @@ static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
 	struct c_can_priv *priv = netdev_priv(dev);
 
 	for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
-		priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl,
+		priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
 				ctrl_mask & ~(IF_MCONT_MSGLST |
 					IF_MCONT_INTPND | IF_MCONT_NEWDAT));
 		c_can_object_put(dev, iface, i, IF_COMM_CONTROL);
@@ -356,7 +360,7 @@ static inline void c_can_activate_rx_msg_obj(struct net_device *dev,
 {
 	struct c_can_priv *priv = netdev_priv(dev);
 
-	priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl,
+	priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
 			ctrl_mask & ~(IF_MCONT_MSGLST |
 				IF_MCONT_INTPND | IF_MCONT_NEWDAT));
 	c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
@@ -374,7 +378,7 @@ static void c_can_handle_lost_msg_obj(struct net_device *dev,
 
 	c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
 
-	priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl,
+	priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
 			IF_MCONT_CLR_MSGLST);
 
 	c_can_object_put(dev, 0, objno, IF_COMM_CONTROL);
@@ -410,8 +414,8 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
 
 	frame->can_dlc = get_can_dlc(ctrl & 0x0F);
 
-	flags =	priv->read_reg(priv, &priv->regs->ifregs[iface].arb2);
-	val = priv->read_reg(priv, &priv->regs->ifregs[iface].arb1) |
+	flags =	priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface));
+	val = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface)) |
 		(flags << 16);
 
 	if (flags & IF_ARB_MSGXTD)
@@ -424,7 +428,7 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
 	else {
 		for (i = 0; i < frame->can_dlc; i += 2) {
 			data = priv->read_reg(priv,
-				&priv->regs->ifregs[iface].data[i / 2]);
+				C_CAN_IFACE(DATA1_REG, iface) + i / 2);
 			frame->data[i] = data;
 			frame->data[i + 1] = data >> 8;
 		}
@@ -444,40 +448,40 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface,
 {
 	struct c_can_priv *priv = netdev_priv(dev);
 
-	priv->write_reg(priv, &priv->regs->ifregs[iface].mask1,
+	priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface),
 			IFX_WRITE_LOW_16BIT(mask));
-	priv->write_reg(priv, &priv->regs->ifregs[iface].mask2,
+	priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface),
 			IFX_WRITE_HIGH_16BIT(mask));
 
-	priv->write_reg(priv, &priv->regs->ifregs[iface].arb1,
+	priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
 			IFX_WRITE_LOW_16BIT(id));
-	priv->write_reg(priv, &priv->regs->ifregs[iface].arb2,
+	priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface),
 			(IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id)));
 
-	priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, mcont);
+	priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont);
 	c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
 
 	netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
-			c_can_read_reg32(priv, &priv->regs->msgval1));
+			c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
 }
 
 static void c_can_inval_msg_object(struct net_device *dev, int iface, int objno)
 {
 	struct c_can_priv *priv = netdev_priv(dev);
 
-	priv->write_reg(priv, &priv->regs->ifregs[iface].arb1, 0);
-	priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, 0);
-	priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, 0);
+	priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
+	priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0);
+	priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0);
 
 	c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL);
 
 	netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
-			c_can_read_reg32(priv, &priv->regs->msgval1));
+			c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
 }
 
 static inline int c_can_is_next_tx_obj_busy(struct c_can_priv *priv, int objno)
 {
-	int val = c_can_read_reg32(priv, &priv->regs->txrqst1);
+	int val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
 
 	/*
 	 * as transmission request register's bit n-1 corresponds to
@@ -540,12 +544,12 @@ static int c_can_set_bittiming(struct net_device *dev)
 	netdev_info(dev,
 		"setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
 
-	ctrl_save = priv->read_reg(priv, &priv->regs->control);
-	priv->write_reg(priv, &priv->regs->control,
+	ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG);
+	priv->write_reg(priv, C_CAN_CTRL_REG,
 			ctrl_save | CONTROL_CCE | CONTROL_INIT);
-	priv->write_reg(priv, &priv->regs->btr, reg_btr);
-	priv->write_reg(priv, &priv->regs->brp_ext, reg_brpe);
-	priv->write_reg(priv, &priv->regs->control, ctrl_save);
+	priv->write_reg(priv, C_CAN_BTR_REG, reg_btr);
+	priv->write_reg(priv, C_CAN_BRPEXT_REG, reg_brpe);
+	priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save);
 
 	return 0;
 }
@@ -587,36 +591,36 @@ static void c_can_chip_config(struct net_device *dev)
 	struct c_can_priv *priv = netdev_priv(dev);
 
 	/* enable automatic retransmission */
-	priv->write_reg(priv, &priv->regs->control,
+	priv->write_reg(priv, C_CAN_CTRL_REG,
 			CONTROL_ENABLE_AR);
 
-	if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY &
-					CAN_CTRLMODE_LOOPBACK)) {
+	if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) &&
+	    (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) {
 		/* loopback + silent mode : useful for hot self-test */
-		priv->write_reg(priv, &priv->regs->control, CONTROL_EIE |
+		priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
 				CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
-		priv->write_reg(priv, &priv->regs->test,
+		priv->write_reg(priv, C_CAN_TEST_REG,
 				TEST_LBACK | TEST_SILENT);
 	} else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
 		/* loopback mode : useful for self-test function */
-		priv->write_reg(priv, &priv->regs->control, CONTROL_EIE |
+		priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
 				CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
-		priv->write_reg(priv, &priv->regs->test, TEST_LBACK);
+		priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK);
 	} else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
 		/* silent mode : bus-monitoring mode */
-		priv->write_reg(priv, &priv->regs->control, CONTROL_EIE |
+		priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
 				CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
-		priv->write_reg(priv, &priv->regs->test, TEST_SILENT);
+		priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT);
 	} else
 		/* normal mode*/
-		priv->write_reg(priv, &priv->regs->control,
+		priv->write_reg(priv, C_CAN_CTRL_REG,
 				CONTROL_EIE | CONTROL_SIE | CONTROL_IE);
 
 	/* configure message objects */
 	c_can_configure_msg_objects(dev);
 
 	/* set a `lec` value so that we can check for updates later */
-	priv->write_reg(priv, &priv->regs->status, LEC_UNUSED);
+	priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
 
 	/* set bittiming params */
 	c_can_set_bittiming(dev);
@@ -669,7 +673,7 @@ static int c_can_get_berr_counter(const struct net_device *dev,
 	unsigned int reg_err_counter;
 	struct c_can_priv *priv = netdev_priv(dev);
 
-	reg_err_counter = priv->read_reg(priv, &priv->regs->err_cnt);
+	reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
 	bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
 				ERR_CNT_REC_SHIFT;
 	bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK;
@@ -697,12 +701,12 @@ static void c_can_do_tx(struct net_device *dev)
 
 	for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
 		msg_obj_no = get_tx_echo_msg_obj(priv);
-		val = c_can_read_reg32(priv, &priv->regs->txrqst1);
+		val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
 		if (!(val & (1 << (msg_obj_no - 1)))) {
 			can_get_echo_skb(dev,
 					msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
 			stats->tx_bytes += priv->read_reg(priv,
-					&priv->regs->ifregs[0].msg_cntrl)
+					C_CAN_IFACE(MSGCTRL_REG, 0))
 					& IF_MCONT_DLC_MASK;
 			stats->tx_packets++;
 			c_can_inval_msg_object(dev, 0, msg_obj_no);
@@ -744,11 +748,11 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
 	u32 num_rx_pkts = 0;
 	unsigned int msg_obj, msg_ctrl_save;
 	struct c_can_priv *priv = netdev_priv(dev);
-	u32 val = c_can_read_reg32(priv, &priv->regs->intpnd1);
+	u32 val = c_can_read_reg32(priv, C_CAN_INTPND1_REG);
 
 	for (msg_obj = C_CAN_MSG_OBJ_RX_FIRST;
 			msg_obj <= C_CAN_MSG_OBJ_RX_LAST && quota > 0;
-			val = c_can_read_reg32(priv, &priv->regs->intpnd1),
+			val = c_can_read_reg32(priv, C_CAN_INTPND1_REG),
 			msg_obj++) {
 		/*
 		 * as interrupt pending register's bit n-1 corresponds to
@@ -758,7 +762,7 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
 			c_can_object_get(dev, 0, msg_obj, IF_COMM_ALL &
 					~IF_COMM_TXRQST);
 			msg_ctrl_save = priv->read_reg(priv,
-					&priv->regs->ifregs[0].msg_cntrl);
+					C_CAN_IFACE(MSGCTRL_REG, 0));
 
 			if (msg_ctrl_save & IF_MCONT_EOB)
 				return num_rx_pkts;
@@ -819,7 +823,7 @@ static int c_can_handle_state_change(struct net_device *dev,
 		return 0;
 
 	c_can_get_berr_counter(dev, &bec);
-	reg_err_counter = priv->read_reg(priv, &priv->regs->err_cnt);
+	reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
 	rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
 				ERR_CNT_RP_SHIFT;
 
@@ -935,7 +939,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
 	}
 
 	/* set a `lec` value so that we can check for updates later */
-	priv->write_reg(priv, &priv->regs->status, LEC_UNUSED);
+	priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
 
 	netif_receive_skb(skb);
 	stats->rx_packets++;
@@ -959,15 +963,15 @@ static int c_can_poll(struct napi_struct *napi, int quota)
 	/* status events have the highest priority */
 	if (irqstatus == STATUS_INTERRUPT) {
 		priv->current_status = priv->read_reg(priv,
-					&priv->regs->status);
+					C_CAN_STS_REG);
 
 		/* handle Tx/Rx events */
 		if (priv->current_status & STATUS_TXOK)
-			priv->write_reg(priv, &priv->regs->status,
+			priv->write_reg(priv, C_CAN_STS_REG,
 					priv->current_status & ~STATUS_TXOK);
 
 		if (priv->current_status & STATUS_RXOK)
-			priv->write_reg(priv, &priv->regs->status,
+			priv->write_reg(priv, C_CAN_STS_REG,
 					priv->current_status & ~STATUS_RXOK);
 
 		/* handle state changes */
@@ -1033,7 +1037,7 @@ static irqreturn_t c_can_isr(int irq, void *dev_id)
 	struct net_device *dev = (struct net_device *)dev_id;
 	struct c_can_priv *priv = netdev_priv(dev);
 
-	priv->irqstatus = priv->read_reg(priv, &priv->regs->interrupt);
+	priv->irqstatus = priv->read_reg(priv, C_CAN_INT_REG);
 	if (!priv->irqstatus)
 		return IRQ_NONE;
 
diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
index 5f32d34..01a7049 100644
--- a/drivers/net/can/c_can/c_can.h
+++ b/drivers/net/can/c_can/c_can.h
@@ -22,43 +22,129 @@
 #ifndef C_CAN_H
 #define C_CAN_H
 
-/* c_can IF registers */
-struct c_can_if_regs {
-	u16 com_req;
-	u16 com_mask;
-	u16 mask1;
-	u16 mask2;
-	u16 arb1;
-	u16 arb2;
-	u16 msg_cntrl;
-	u16 data[4];
-	u16 _reserved[13];
+enum reg {
+	C_CAN_CTRL_REG = 0,
+	C_CAN_STS_REG,
+	C_CAN_ERR_CNT_REG,
+	C_CAN_BTR_REG,
+	C_CAN_INT_REG,
+	C_CAN_TEST_REG,
+	C_CAN_BRPEXT_REG,
+	C_CAN_IF1_COMREQ_REG,
+	C_CAN_IF1_COMMSK_REG,
+	C_CAN_IF1_MASK1_REG,
+	C_CAN_IF1_MASK2_REG,
+	C_CAN_IF1_ARB1_REG,
+	C_CAN_IF1_ARB2_REG,
+	C_CAN_IF1_MSGCTRL_REG,
+	C_CAN_IF1_DATA1_REG,
+	C_CAN_IF1_DATA2_REG,
+	C_CAN_IF1_DATA3_REG,
+	C_CAN_IF1_DATA4_REG,
+	C_CAN_IF2_COMREQ_REG,
+	C_CAN_IF2_COMMSK_REG,
+	C_CAN_IF2_MASK1_REG,
+	C_CAN_IF2_MASK2_REG,
+	C_CAN_IF2_ARB1_REG,
+	C_CAN_IF2_ARB2_REG,
+	C_CAN_IF2_MSGCTRL_REG,
+	C_CAN_IF2_DATA1_REG,
+	C_CAN_IF2_DATA2_REG,
+	C_CAN_IF2_DATA3_REG,
+	C_CAN_IF2_DATA4_REG,
+	C_CAN_TXRQST1_REG,
+	C_CAN_TXRQST2_REG,
+	C_CAN_NEWDAT1_REG,
+	C_CAN_NEWDAT2_REG,
+	C_CAN_INTPND1_REG,
+	C_CAN_INTPND2_REG,
+	C_CAN_MSGVAL1_REG,
+	C_CAN_MSGVAL2_REG,
 };
 
-/* c_can hardware registers */
-struct c_can_regs {
-	u16 control;
-	u16 status;
-	u16 err_cnt;
-	u16 btr;
-	u16 interrupt;
-	u16 test;
-	u16 brp_ext;
-	u16 _reserved1;
-	struct c_can_if_regs ifregs[2]; /* [0] = IF1 and [1] = IF2 */
-	u16 _reserved2[8];
-	u16 txrqst1;
-	u16 txrqst2;
-	u16 _reserved3[6];
-	u16 newdat1;
-	u16 newdat2;
-	u16 _reserved4[6];
-	u16 intpnd1;
-	u16 intpnd2;
-	u16 _reserved5[6];
-	u16 msgval1;
-	u16 msgval2;
-	u16 _reserved6[6];
+static const u16 reg_map_c_can[] = {
+	[C_CAN_CTRL_REG]	= 0x00,
+	[C_CAN_STS_REG]		= 0x02,
+	[C_CAN_ERR_CNT_REG]	= 0x04,
+	[C_CAN_BTR_REG]		= 0x06,
+	[C_CAN_INT_REG]		= 0x08,
+	[C_CAN_TEST_REG]	= 0x0A,
+	[C_CAN_BRPEXT_REG]	= 0x0C,
+	[C_CAN_IF1_COMREQ_REG]	= 0x10,
+	[C_CAN_IF1_COMMSK_REG]	= 0x12,
+	[C_CAN_IF1_MASK1_REG]	= 0x14,
+	[C_CAN_IF1_MASK2_REG]	= 0x16,
+	[C_CAN_IF1_ARB1_REG]	= 0x18,
+	[C_CAN_IF1_ARB2_REG]	= 0x1A,
+	[C_CAN_IF1_MSGCTRL_REG]	= 0x1C,
+	[C_CAN_IF1_DATA1_REG]	= 0x1E,
+	[C_CAN_IF1_DATA2_REG]	= 0x20,
+	[C_CAN_IF1_DATA3_REG]	= 0x22,
+	[C_CAN_IF1_DATA4_REG]	= 0x24,
+	[C_CAN_IF2_COMREQ_REG]	= 0x40,
+	[C_CAN_IF2_COMMSK_REG]	= 0x42,
+	[C_CAN_IF2_MASK1_REG]	= 0x44,
+	[C_CAN_IF2_MASK2_REG]	= 0x46,
+	[C_CAN_IF2_ARB1_REG]	= 0x48,
+	[C_CAN_IF2_ARB2_REG]	= 0x4A,
+	[C_CAN_IF2_MSGCTRL_REG]	= 0x4C,
+	[C_CAN_IF2_DATA1_REG]	= 0x4E,
+	[C_CAN_IF2_DATA2_REG]	= 0x50,
+	[C_CAN_IF2_DATA3_REG]	= 0x52,
+	[C_CAN_IF2_DATA4_REG]	= 0x54,
+	[C_CAN_TXRQST1_REG]	= 0x80,
+	[C_CAN_TXRQST2_REG]	= 0x82,
+	[C_CAN_NEWDAT1_REG]	= 0x90,
+	[C_CAN_NEWDAT2_REG]	= 0x92,
+	[C_CAN_INTPND1_REG]	= 0xA0,
+	[C_CAN_INTPND2_REG]	= 0xA2,
+	[C_CAN_MSGVAL1_REG]	= 0xB0,
+	[C_CAN_MSGVAL2_REG]	= 0xB2,
+};
+
+static const u16 reg_map_d_can[] = {
+	[C_CAN_CTRL_REG]	= 0x00,
+	[C_CAN_STS_REG]		= 0x04,
+	[C_CAN_ERR_CNT_REG]	= 0x08,
+	[C_CAN_BTR_REG]		= 0x0C,
+	[C_CAN_BRPEXT_REG]	= 0x0E,
+	[C_CAN_INT_REG]		= 0x10,
+	[C_CAN_TEST_REG]	= 0x14,
+	[C_CAN_TXRQST1_REG]	= 0x88,
+	[C_CAN_TXRQST2_REG]	= 0x8A,
+	[C_CAN_NEWDAT1_REG]	= 0x9C,
+	[C_CAN_NEWDAT2_REG]	= 0x9E,
+	[C_CAN_INTPND1_REG]	= 0xB0,
+	[C_CAN_INTPND2_REG]	= 0xB2,
+	[C_CAN_MSGVAL1_REG]	= 0xC4,
+	[C_CAN_MSGVAL2_REG]	= 0xC6,
+	[C_CAN_IF1_COMREQ_REG]	= 0x100,
+	[C_CAN_IF1_COMMSK_REG]	= 0x102,
+	[C_CAN_IF1_MASK1_REG]	= 0x104,
+	[C_CAN_IF1_MASK2_REG]	= 0x106,
+	[C_CAN_IF1_ARB1_REG]	= 0x108,
+	[C_CAN_IF1_ARB2_REG]	= 0x10A,
+	[C_CAN_IF1_MSGCTRL_REG]	= 0x10C,
+	[C_CAN_IF1_DATA1_REG]	= 0x110,
+	[C_CAN_IF1_DATA2_REG]	= 0x112,
+	[C_CAN_IF1_DATA3_REG]	= 0x114,
+	[C_CAN_IF1_DATA4_REG]	= 0x116,
+	[C_CAN_IF2_COMREQ_REG]	= 0x120,
+	[C_CAN_IF2_COMMSK_REG]	= 0x122,
+	[C_CAN_IF2_MASK1_REG]	= 0x124,
+	[C_CAN_IF2_MASK2_REG]	= 0x126,
+	[C_CAN_IF2_ARB1_REG]	= 0x128,
+	[C_CAN_IF2_ARB2_REG]	= 0x12A,
+	[C_CAN_IF2_MSGCTRL_REG]	= 0x12C,
+	[C_CAN_IF2_DATA1_REG]	= 0x130,
+	[C_CAN_IF2_DATA2_REG]	= 0x132,
+	[C_CAN_IF2_DATA3_REG]	= 0x134,
+	[C_CAN_IF2_DATA4_REG]	= 0x136,
+};
+
+enum c_can_dev_id {
+	C_CAN_DEVTYPE,
+	D_CAN_DEVTYPE,
 };
 
 /* c_can private data structure */
@@ -69,9 +155,10 @@ struct c_can_priv {
 	int tx_object;
 	int current_status;
 	int last_status;
-	u16 (*read_reg) (struct c_can_priv *priv, void *reg);
-	void (*write_reg) (struct c_can_priv *priv, void *reg, u16 val);
-	struct c_can_regs __iomem *regs;
+	u16 (*read_reg) (struct c_can_priv *priv, enum reg index);
+	void (*write_reg) (struct c_can_priv *priv, enum reg index, u16 val);
+	void __iomem *base;
+	const u16 *regs;
 	unsigned long irq_flags; /* for request_irq() */
 	unsigned int tx_next;
 	unsigned int tx_echo;
diff --git a/drivers/net/can/c_can/c_can_pci.c b/drivers/net/can/c_can/c_can_pci.c
new file mode 100644
index 0000000..1011146
--- /dev/null
+++ b/drivers/net/can/c_can/c_can_pci.c
@@ -0,0 +1,221 @@
+/*
+ * PCI bus driver for Bosch C_CAN/D_CAN controller
+ *
+ * Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com>
+ *
+ * Borrowed from c_can_platform.c
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+
+#include <linux/can/dev.h>
+
+#include "c_can.h"
+
+enum c_can_pci_reg_align {
+	C_CAN_REG_ALIGN_16,
+	C_CAN_REG_ALIGN_32,
+};
+
+struct c_can_pci_data {
+	/* Specify if is C_CAN or D_CAN */
+	enum c_can_dev_id type;
+	/* Set the register alignment in the memory */
+	enum c_can_pci_reg_align reg_align;
+	/* Set the frequency */
+	unsigned int freq;
+};
+
+/*
+ * 16-bit c_can registers can be arranged differently in the memory
+ * architecture of different implementations. For example: 16-bit
+ * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
+ * Handle the same by providing a common read/write interface.
+ */
+static u16 c_can_pci_read_reg_aligned_to_16bit(struct c_can_priv *priv,
+						enum reg index)
+{
+	return readw(priv->base + priv->regs[index]);
+}
+
+static void c_can_pci_write_reg_aligned_to_16bit(struct c_can_priv *priv,
+						enum reg index, u16 val)
+{
+	writew(val, priv->base + priv->regs[index]);
+}
+
+static u16 c_can_pci_read_reg_aligned_to_32bit(struct c_can_priv *priv,
+						enum reg index)
+{
+	return readw(priv->base + 2 * priv->regs[index]);
+}
+
+static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv,
+						enum reg index, u16 val)
+{
+	writew(val, priv->base + 2 * priv->regs[index]);
+}
+
+static int __devinit c_can_pci_probe(struct pci_dev *pdev,
+				     const struct pci_device_id *ent)
+{
+	struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data;
+	struct c_can_priv *priv;
+	struct net_device *dev;
+	void __iomem *addr;
+	int ret;
+
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "pci_enable_device FAILED\n");
+		goto out;
+	}
+
+	ret = pci_request_regions(pdev, KBUILD_MODNAME);
+	if (ret) {
+		dev_err(&pdev->dev, "pci_request_regions FAILED\n");
+		goto out_disable_device;
+	}
+
+	pci_set_master(pdev);
+	pci_enable_msi(pdev);
+
+	addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+	if (!addr) {
+		dev_err(&pdev->dev,
+			"device has no PCI memory resources, "
+			"failing adapter\n");
+		ret = -ENOMEM;
+		goto out_release_regions;
+	}
+
+	/* allocate the c_can device */
+	dev = alloc_c_can_dev();
+	if (!dev) {
+		ret = -ENOMEM;
+		goto out_iounmap;
+	}
+
+	priv = netdev_priv(dev);
+	pci_set_drvdata(pdev, dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	dev->irq = pdev->irq;
+	priv->base = addr;
+
+	if (!c_can_pci_data->freq) {
+		dev_err(&pdev->dev, "no clock frequency defined\n");
+		ret = -ENODEV;
+		goto out_free_c_can;
+	} else {
+		priv->can.clock.freq = c_can_pci_data->freq;
+	}
+
+	/* Configure CAN type */
+	switch (c_can_pci_data->type) {
+	case C_CAN_DEVTYPE:
+		priv->regs = reg_map_c_can;
+		break;
+	case D_CAN_DEVTYPE:
+		priv->regs = reg_map_d_can;
+		priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+		break;
+	default:
+		ret = -EINVAL;
+		goto out_free_c_can;
+	}
+
+	/* Configure access to registers */
+	switch (c_can_pci_data->reg_align) {
+	case C_CAN_REG_ALIGN_32:
+		priv->read_reg = c_can_pci_read_reg_aligned_to_32bit;
+		priv->write_reg = c_can_pci_write_reg_aligned_to_32bit;
+		break;
+	case C_CAN_REG_ALIGN_16:
+		priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
+		priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
+		break;
+	default:
+		ret = -EINVAL;
+		goto out_free_c_can;
+	}
+
+	ret = register_c_can_dev(dev);
+	if (ret) {
+		dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+			KBUILD_MODNAME, ret);
+		goto out_free_c_can;
+	}
+
+	dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
+		 KBUILD_MODNAME, priv->regs, dev->irq);
+
+	return 0;
+
+out_free_c_can:
+	pci_set_drvdata(pdev, NULL);
+	free_c_can_dev(dev);
+out_iounmap:
+	pci_iounmap(pdev, addr);
+out_release_regions:
+	pci_disable_msi(pdev);
+	pci_clear_master(pdev);
+	pci_release_regions(pdev);
+out_disable_device:
+	pci_disable_device(pdev);
+out:
+	return ret;
+}
+
+static void __devexit c_can_pci_remove(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	unregister_c_can_dev(dev);
+
+	pci_set_drvdata(pdev, NULL);
+	free_c_can_dev(dev);
+
+	pci_iounmap(pdev, priv->base);
+	pci_disable_msi(pdev);
+	pci_clear_master(pdev);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static struct c_can_pci_data c_can_sta2x11= {
+	.type = C_CAN_DEVTYPE,
+	.reg_align = C_CAN_REG_ALIGN_32,
+	.freq = 52000000, /* 52 Mhz */
+};
+
+#define C_CAN_ID(_vend, _dev, _driverdata) {		\
+	PCI_DEVICE(_vend, _dev),			\
+	.driver_data = (unsigned long)&_driverdata,	\
+}
+static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
+	C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
+		 c_can_sta2x11),
+	{},
+};
+static struct pci_driver c_can_pci_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = c_can_pci_tbl,
+	.probe = c_can_pci_probe,
+	.remove = __devexit_p(c_can_pci_remove),
+};
+
+module_pci_driver(c_can_pci_driver);
+
+MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller");
+MODULE_DEVICE_TABLE(pci, c_can_pci_tbl);
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
index 5e1a5ff..6ff7ad0 100644
--- a/drivers/net/can/c_can/c_can_platform.c
+++ b/drivers/net/can/c_can/c_can_platform.c
@@ -42,27 +42,27 @@
  * Handle the same by providing a common read/write interface.
  */
 static u16 c_can_plat_read_reg_aligned_to_16bit(struct c_can_priv *priv,
-						void *reg)
+						enum reg index)
 {
-	return readw(reg);
+	return readw(priv->base + priv->regs[index]);
 }
 
 static void c_can_plat_write_reg_aligned_to_16bit(struct c_can_priv *priv,
-						void *reg, u16 val)
+						enum reg index, u16 val)
 {
-	writew(val, reg);
+	writew(val, priv->base + priv->regs[index]);
 }
 
 static u16 c_can_plat_read_reg_aligned_to_32bit(struct c_can_priv *priv,
-						void *reg)
+						enum reg index)
 {
-	return readw(reg + (long)reg - (long)priv->regs);
+	return readw(priv->base + 2 * priv->regs[index]);
 }
 
 static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
-						void *reg, u16 val)
+						enum reg index, u16 val)
 {
-	writew(val, reg + (long)reg - (long)priv->regs);
+	writew(val, priv->base + 2 * priv->regs[index]);
 }
 
 static int __devinit c_can_plat_probe(struct platform_device *pdev)
@@ -71,9 +71,9 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
 	void __iomem *addr;
 	struct net_device *dev;
 	struct c_can_priv *priv;
+	const struct platform_device_id *id;
 	struct resource *mem;
 	int irq;
-#ifdef CONFIG_HAVE_CLK
 	struct clk *clk;
 
 	/* get the appropriate clk */
@@ -83,7 +83,6 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
 		ret = -ENODEV;
 		goto exit;
 	}
-#endif
 
 	/* get the platform data */
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -115,26 +114,38 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
 	}
 
 	priv = netdev_priv(dev);
-
-	dev->irq = irq;
-	priv->regs = addr;
-#ifdef CONFIG_HAVE_CLK
-	priv->can.clock.freq = clk_get_rate(clk);
-	priv->priv = clk;
-#endif
-
-	switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
-	case IORESOURCE_MEM_32BIT:
-		priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
-		priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
+	id = platform_get_device_id(pdev);
+	switch (id->driver_data) {
+	case C_CAN_DEVTYPE:
+		priv->regs = reg_map_c_can;
+		switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
+		case IORESOURCE_MEM_32BIT:
+			priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
+			priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
+			break;
+		case IORESOURCE_MEM_16BIT:
+		default:
+			priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
+			priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
+			break;
+		}
 		break;
-	case IORESOURCE_MEM_16BIT:
-	default:
+	case D_CAN_DEVTYPE:
+		priv->regs = reg_map_d_can;
+		priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
 		priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
 		priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
 		break;
+	default:
+		ret = -EINVAL;
+		goto exit_free_device;
 	}
 
+	dev->irq = irq;
+	priv->base = addr;
+	priv->can.clock.freq = clk_get_rate(clk);
+	priv->priv = clk;
+
 	platform_set_drvdata(pdev, dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -146,7 +157,7 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
 	}
 
 	dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
-		 KBUILD_MODNAME, priv->regs, dev->irq);
+		 KBUILD_MODNAME, priv->base, dev->irq);
 	return 0;
 
 exit_free_device:
@@ -157,10 +168,8 @@ exit_iounmap:
 exit_release_mem:
 	release_mem_region(mem->start, resource_size(mem));
 exit_free_clk:
-#ifdef CONFIG_HAVE_CLK
 	clk_put(clk);
 exit:
-#endif
 	dev_err(&pdev->dev, "probe failed\n");
 
 	return ret;
@@ -176,18 +185,30 @@ static int __devexit c_can_plat_remove(struct platform_device *pdev)
 	platform_set_drvdata(pdev, NULL);
 
 	free_c_can_dev(dev);
-	iounmap(priv->regs);
+	iounmap(priv->base);
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	release_mem_region(mem->start, resource_size(mem));
 
-#ifdef CONFIG_HAVE_CLK
 	clk_put(priv->priv);
-#endif
 
 	return 0;
 }
 
+static const struct platform_device_id c_can_id_table[] = {
+	{
+		.name = KBUILD_MODNAME,
+		.driver_data = C_CAN_DEVTYPE,
+	}, {
+		.name = "c_can",
+		.driver_data = C_CAN_DEVTYPE,
+	}, {
+		.name = "d_can",
+		.driver_data = D_CAN_DEVTYPE,
+	}, {
+	}
+};
+
 static struct platform_driver c_can_plat_driver = {
 	.driver = {
 		.name = KBUILD_MODNAME,
@@ -195,6 +216,7 @@ static struct platform_driver c_can_plat_driver = {
 	},
 	.probe = c_can_plat_probe,
 	.remove = __devexit_p(c_can_plat_remove),
+	.id_table = c_can_id_table,
 };
 
 module_platform_driver(c_can_plat_driver);
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index f03d7a4..239e4dd 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -33,6 +33,39 @@ MODULE_DESCRIPTION(MOD_DESC);
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
 
+/* CAN DLC to real data length conversion helpers */
+
+static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
+			     8, 12, 16, 20, 24, 32, 48, 64};
+
+/* get data length from can_dlc with sanitized can_dlc */
+u8 can_dlc2len(u8 can_dlc)
+{
+	return dlc2len[can_dlc & 0x0F];
+}
+EXPORT_SYMBOL_GPL(can_dlc2len);
+
+static const u8 len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8,		/* 0 - 8 */
+			     9, 9, 9, 9,			/* 9 - 12 */
+			     10, 10, 10, 10,			/* 13 - 16 */
+			     11, 11, 11, 11,			/* 17 - 20 */
+			     12, 12, 12, 12,			/* 21 - 24 */
+			     13, 13, 13, 13, 13, 13, 13, 13,	/* 25 - 32 */
+			     14, 14, 14, 14, 14, 14, 14, 14,	/* 33 - 40 */
+			     14, 14, 14, 14, 14, 14, 14, 14,	/* 41 - 48 */
+			     15, 15, 15, 15, 15, 15, 15, 15,	/* 49 - 56 */
+			     15, 15, 15, 15, 15, 15, 15, 15};	/* 57 - 64 */
+
+/* map the sanitized data length to an appropriate data length code */
+u8 can_len2dlc(u8 len)
+{
+	if (unlikely(len > 64))
+		return 0xF;
+
+	return len2dlc[len];
+}
+EXPORT_SYMBOL_GPL(can_len2dlc);
+
 #ifdef CONFIG_CAN_CALC_BITTIMING
 #define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
 
@@ -454,7 +487,7 @@ EXPORT_SYMBOL_GPL(can_bus_off);
 static void can_setup(struct net_device *dev)
 {
 	dev->type = ARPHRD_CAN;
-	dev->mtu = sizeof(struct can_frame);
+	dev->mtu = CAN_MTU;
 	dev->hard_header_len = 0;
 	dev->addr_len = 0;
 	dev->tx_queue_len = 10;
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 38c0690..d465fd4 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -1056,6 +1056,42 @@ static struct of_device_id flexcan_of_match[] = {
 	{},
 };
 
+#ifdef CONFIG_PM
+static int flexcan_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct flexcan_priv *priv = netdev_priv(dev);
+
+	flexcan_chip_disable(priv);
+
+	if (netif_running(dev)) {
+		netif_stop_queue(dev);
+		netif_device_detach(dev);
+	}
+	priv->can.state = CAN_STATE_SLEEPING;
+
+	return 0;
+}
+
+static int flexcan_resume(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct flexcan_priv *priv = netdev_priv(dev);
+
+	priv->can.state = CAN_STATE_ERROR_ACTIVE;
+	if (netif_running(dev)) {
+		netif_device_attach(dev);
+		netif_start_queue(dev);
+	}
+	flexcan_chip_enable(priv);
+
+	return 0;
+}
+#else
+#define flexcan_suspend NULL
+#define flexcan_resume NULL
+#endif
+
 static struct platform_driver flexcan_driver = {
 	.driver = {
 		.name = DRV_NAME,
@@ -1064,6 +1100,8 @@ static struct platform_driver flexcan_driver = {
 	},
 	.probe = flexcan_probe,
 	.remove = __devexit_p(flexcan_remove),
+	.suspend = flexcan_suspend,
+	.resume = flexcan_resume,
 };
 
 module_platform_driver(flexcan_driver);
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index 346785c..9120a36 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -1020,8 +1020,7 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
 						      GFP_DMA);
 
 		if (priv->spi_tx_buf) {
-			priv->spi_rx_buf = (u8 *)(priv->spi_tx_buf +
-						  (PAGE_SIZE / 2));
+			priv->spi_rx_buf = (priv->spi_tx_buf + (PAGE_SIZE / 2));
 			priv->spi_rx_dma = (dma_addr_t)(priv->spi_tx_dma +
 							(PAGE_SIZE / 2));
 		} else {
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index ea2d942..4f93c0b 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -70,13 +70,12 @@ MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
 
 static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct can_frame *cf = (struct can_frame *)skb->data;
+	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
 	struct net_device_stats *stats = &dev->stats;
 
 	stats->rx_packets++;
-	stats->rx_bytes += cf->can_dlc;
+	stats->rx_bytes += cfd->len;
 
-	skb->protocol  = htons(ETH_P_CAN);
 	skb->pkt_type  = PACKET_BROADCAST;
 	skb->dev       = dev;
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -86,7 +85,7 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 
 static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct can_frame *cf = (struct can_frame *)skb->data;
+	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
 	struct net_device_stats *stats = &dev->stats;
 	int loop;
 
@@ -94,7 +93,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
 		return NETDEV_TX_OK;
 
 	stats->tx_packets++;
-	stats->tx_bytes += cf->can_dlc;
+	stats->tx_bytes += cfd->len;
 
 	/* set flag whether this packet has to be looped back */
 	loop = skb->pkt_type == PACKET_LOOPBACK;
@@ -108,7 +107,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
 			 * CAN core already did the echo for us
 			 */
 			stats->rx_packets++;
-			stats->rx_bytes += cf->can_dlc;
+			stats->rx_bytes += cfd->len;
 		}
 		kfree_skb(skb);
 		return NETDEV_TX_OK;
@@ -133,14 +132,28 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
 	return NETDEV_TX_OK;
 }
 
+static int vcan_change_mtu(struct net_device *dev, int new_mtu)
+{
+	/* Do not allow changing the MTU while running */
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+
+	if (new_mtu != CAN_MTU && new_mtu != CANFD_MTU)
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+	return 0;
+}
+
 static const struct net_device_ops vcan_netdev_ops = {
 	.ndo_start_xmit = vcan_tx,
+	.ndo_change_mtu = vcan_change_mtu,
 };
 
 static void vcan_setup(struct net_device *dev)
 {
 	dev->type		= ARPHRD_CAN;
-	dev->mtu		= sizeof(struct can_frame);
+	dev->mtu		= CAN_MTU;
 	dev->hard_header_len	= 0;
 	dev->addr_len		= 0;
 	dev->tx_queue_len	= 0;
diff --git a/drivers/net/ethernet/8390/apne.c b/drivers/net/ethernet/8390/apne.c
index 9239592..912ed7a 100644
--- a/drivers/net/ethernet/8390/apne.c
+++ b/drivers/net/ethernet/8390/apne.c
@@ -454,7 +454,7 @@ apne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int rin
 	buf[count-1] = inb(NE_BASE + NE_DATAPORT);
       }
     } else {
-      ptrc = (char*)buf;
+      ptrc = buf;
       for (cnt = 0; cnt < count; cnt++)
         *ptrc++ = inb(NE_BASE + NE_DATAPORT);
     }
diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c
index 3485011..9c77c73 100644
--- a/drivers/net/ethernet/aeroflex/greth.c
+++ b/drivers/net/ethernet/aeroflex/greth.c
@@ -1014,7 +1014,7 @@ static int greth_set_mac_add(struct net_device *dev, void *p)
 	struct greth_regs *regs;
 
 	greth = netdev_priv(dev);
-	regs = (struct greth_regs *) greth->regs;
+	regs = greth->regs;
 
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
@@ -1036,7 +1036,7 @@ static void greth_set_hash_filter(struct net_device *dev)
 {
 	struct netdev_hw_addr *ha;
 	struct greth_private *greth = netdev_priv(dev);
-	struct greth_regs *regs = (struct greth_regs *) greth->regs;
+	struct greth_regs *regs = greth->regs;
 	u32 mc_filter[2];
 	unsigned int bitnr;
 
@@ -1055,7 +1055,7 @@ static void greth_set_multicast_list(struct net_device *dev)
 {
 	int cfg;
 	struct greth_private *greth = netdev_priv(dev);
-	struct greth_regs *regs = (struct greth_regs *) greth->regs;
+	struct greth_regs *regs = greth->regs;
 
 	cfg = GRETH_REGLOAD(regs->control);
 	if (dev->flags & IFF_PROMISC)
@@ -1414,7 +1414,7 @@ static int __devinit greth_of_probe(struct platform_device *ofdev)
 		goto error1;
 	}
 
-	regs = (struct greth_regs *) greth->regs;
+	regs = greth->regs;
 	greth->irq = ofdev->archdata.irqs[0];
 
 	dev_set_drvdata(greth->dev, dev);
diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c
index 75299f5..7203b52 100644
--- a/drivers/net/ethernet/amd/declance.c
+++ b/drivers/net/ethernet/amd/declance.c
@@ -623,7 +623,7 @@ static int lance_rx(struct net_device *dev)
 			skb_put(skb, len);	/* make room */
 
 			cp_from_buf(lp->type, skb->data,
-				    (char *)lp->rx_buf_ptr_cpu[entry], len);
+				    lp->rx_buf_ptr_cpu[entry], len);
 
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
@@ -919,7 +919,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	*lib_ptr(ib, btx_ring[entry].length, lp->type) = (-len);
 	*lib_ptr(ib, btx_ring[entry].misc, lp->type) = 0;
 
-	cp_to_buf(lp->type, (char *)lp->tx_buf_ptr_cpu[entry], skb->data, len);
+	cp_to_buf(lp->type, lp->tx_buf_ptr_cpu[entry], skb->data, len);
 
 	/* Now, give the packet to the lance */
 	*lib_ptr(ib, btx_ring[entry].tmd1, lp->type) =
diff --git a/drivers/net/ethernet/apple/macmace.c b/drivers/net/ethernet/apple/macmace.c
index ab7ff86..a92ddee7 100644
--- a/drivers/net/ethernet/apple/macmace.c
+++ b/drivers/net/ethernet/apple/macmace.c
@@ -228,7 +228,7 @@ static int __devinit mace_probe(struct platform_device *pdev)
 	 * bits are reversed.
 	 */
 
-	addr = (void *)MACE_PROM;
+	addr = MACE_PROM;
 
 	for (j = 0; j < 6; ++j) {
 		u8 v = bitrev8(addr[j<<4]);
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
index ff9c738..801f012 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
@@ -602,7 +602,7 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
 
 int atl1c_phy_init(struct atl1c_hw *hw)
 {
-	struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+	struct atl1c_adapter *adapter = hw->adapter;
 	struct pci_dev *pdev = adapter->pdev;
 	int ret_val;
 	u16 mii_bmcr_data = BMCR_RESET;
@@ -696,7 +696,7 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
 /* select one link mode to get lower power consumption */
 int atl1c_phy_to_ps_link(struct atl1c_hw *hw)
 {
-	struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+	struct atl1c_adapter *adapter = hw->adapter;
 	struct pci_dev *pdev = adapter->pdev;
 	int ret = 0;
 	u16 autoneg_advertised = ADVERTISED_10baseT_Half;
@@ -768,7 +768,7 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw)
 
 int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc)
 {
-	struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+	struct atl1c_adapter *adapter = hw->adapter;
 	struct pci_dev *pdev = adapter->pdev;
 	u32 master_ctrl, mac_ctrl, phy_ctrl;
 	u32 wol_ctrl, speed;
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 9cc1570..85717cb 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -989,12 +989,12 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter)
 	}
 	for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
 		tpd_ring[i].buffer_info =
-			(struct atl1c_buffer *) (tpd_ring->buffer_info + count);
+			(tpd_ring->buffer_info + count);
 		count += tpd_ring[i].count;
 	}
 
 	rfd_ring->buffer_info =
-		(struct atl1c_buffer *) (tpd_ring->buffer_info + count);
+		(tpd_ring->buffer_info + count);
 	count += rfd_ring->count;
 	rx_desc_count += rfd_ring->count;
 
@@ -1227,7 +1227,7 @@ static void atl1c_start_mac(struct atl1c_adapter *adapter)
  */
 static int atl1c_reset_mac(struct atl1c_hw *hw)
 {
-	struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+	struct atl1c_adapter *adapter = hw->adapter;
 	struct pci_dev *pdev = adapter->pdev;
 	u32 ctrl_data = 0;
 
@@ -1531,8 +1531,7 @@ static inline void atl1c_clear_phy_int(struct atl1c_adapter *adapter)
 static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter,
 				enum atl1c_trans_queue type)
 {
-	struct atl1c_tpd_ring *tpd_ring = (struct atl1c_tpd_ring *)
-				&adapter->tpd_ring[type];
+	struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
 	struct atl1c_buffer *buffer_info;
 	struct pci_dev *pdev = adapter->pdev;
 	u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c b/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c
index 6e61f9f..82b2386 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c
@@ -268,7 +268,7 @@ static int atl1e_set_eeprom(struct net_device *netdev,
 	if (eeprom_buff == NULL)
 		return -ENOMEM;
 
-	ptr = (u32 *)eeprom_buff;
+	ptr = eeprom_buff;
 
 	if (eeprom->offset & 3) {
 		/* need read/modify/write of first changed EEPROM word */
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index 1220e51..0aed82e 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -641,8 +641,7 @@ static int __devinit atl1e_sw_init(struct atl1e_adapter *adapter)
  */
 static void atl1e_clean_tx_ring(struct atl1e_adapter *adapter)
 {
-	struct atl1e_tx_ring *tx_ring = (struct atl1e_tx_ring *)
-				&adapter->tx_ring;
+	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
 	struct atl1e_tx_buffer *tx_buffer = NULL;
 	struct pci_dev *pdev = adapter->pdev;
 	u16 index, ring_count;
@@ -686,7 +685,7 @@ static void atl1e_clean_tx_ring(struct atl1e_adapter *adapter)
 static void atl1e_clean_rx_ring(struct atl1e_adapter *adapter)
 {
 	struct atl1e_rx_ring *rx_ring =
-		(struct atl1e_rx_ring *)&adapter->rx_ring;
+		&adapter->rx_ring;
 	struct atl1e_rx_page_desc *rx_page_desc = rx_ring->rx_page_desc;
 	u16 i, j;
 
@@ -884,14 +883,12 @@ failed:
 	return err;
 }
 
-static inline void atl1e_configure_des_ring(const struct atl1e_adapter *adapter)
+static inline void atl1e_configure_des_ring(struct atl1e_adapter *adapter)
 {
 
-	struct atl1e_hw *hw = (struct atl1e_hw *)&adapter->hw;
-	struct atl1e_rx_ring *rx_ring =
-			(struct atl1e_rx_ring *)&adapter->rx_ring;
-	struct atl1e_tx_ring *tx_ring =
-			(struct atl1e_tx_ring *)&adapter->tx_ring;
+	struct atl1e_hw *hw = &adapter->hw;
+	struct atl1e_rx_ring *rx_ring = &adapter->rx_ring;
+	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
 	struct atl1e_rx_page_desc *rx_page_desc = NULL;
 	int i, j;
 
@@ -932,7 +929,7 @@ static inline void atl1e_configure_des_ring(const struct atl1e_adapter *adapter)
 
 static inline void atl1e_configure_tx(struct atl1e_adapter *adapter)
 {
-	struct atl1e_hw *hw = (struct atl1e_hw *)&adapter->hw;
+	struct atl1e_hw *hw = &adapter->hw;
 	u32 dev_ctrl_data = 0;
 	u32 max_pay_load = 0;
 	u32 jumbo_thresh = 0;
@@ -975,7 +972,7 @@ static inline void atl1e_configure_tx(struct atl1e_adapter *adapter)
 
 static inline void atl1e_configure_rx(struct atl1e_adapter *adapter)
 {
-	struct atl1e_hw *hw = (struct atl1e_hw *)&adapter->hw;
+	struct atl1e_hw *hw = &adapter->hw;
 	u32 rxf_len  = 0;
 	u32 rxf_low  = 0;
 	u32 rxf_high = 0;
@@ -1224,8 +1221,7 @@ static inline void atl1e_clear_phy_int(struct atl1e_adapter *adapter)
 
 static bool atl1e_clean_tx_irq(struct atl1e_adapter *adapter)
 {
-	struct atl1e_tx_ring *tx_ring = (struct atl1e_tx_ring *)
-					&adapter->tx_ring;
+	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
 	struct atl1e_tx_buffer *tx_buffer = NULL;
 	u16 hw_next_to_clean = AT_READ_REGW(&adapter->hw, REG_TPD_CONS_IDX);
 	u16 next_to_clean = atomic_read(&tx_ring->next_to_clean);
@@ -1384,15 +1380,14 @@ static struct atl1e_rx_page *atl1e_get_rx_page(struct atl1e_adapter *adapter,
 		(struct atl1e_rx_page_desc *) adapter->rx_ring.rx_page_desc;
 	u8 rx_using = rx_page_desc[que].rx_using;
 
-	return (struct atl1e_rx_page *)&(rx_page_desc[que].rx_page[rx_using]);
+	return &(rx_page_desc[que].rx_page[rx_using]);
 }
 
 static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que,
 		   int *work_done, int work_to_do)
 {
 	struct net_device *netdev  = adapter->netdev;
-	struct atl1e_rx_ring *rx_ring = (struct atl1e_rx_ring *)
-					 &adapter->rx_ring;
+	struct atl1e_rx_ring *rx_ring = &adapter->rx_ring;
 	struct atl1e_rx_page_desc *rx_page_desc =
 		(struct atl1e_rx_page_desc *) rx_ring->rx_page_desc;
 	struct sk_buff *skb = NULL;
@@ -1576,7 +1571,7 @@ static struct atl1e_tpd_desc *atl1e_get_tpd(struct atl1e_adapter *adapter)
 		tx_ring->next_to_use = 0;
 
 	memset(&tx_ring->desc[next_to_use], 0, sizeof(struct atl1e_tpd_desc));
-	return (struct atl1e_tpd_desc *)&tx_ring->desc[next_to_use];
+	return &tx_ring->desc[next_to_use];
 }
 
 static struct atl1e_tx_buffer *
@@ -2061,8 +2056,8 @@ static int atl1e_suspend(struct pci_dev *pdev, pm_message_t state)
 
 	if (wufc) {
 		/* get link status */
-		atl1e_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
-		atl1e_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
+		atl1e_read_phy_reg(hw, MII_BMSR, &mii_bmsr_data);
+		atl1e_read_phy_reg(hw, MII_BMSR, &mii_bmsr_data);
 
 		mii_advertise_data = ADVERTISE_10HALF;
 
@@ -2086,7 +2081,7 @@ static int atl1e_suspend(struct pci_dev *pdev, pm_message_t state)
 				for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
 					msleep(100);
 					atl1e_read_phy_reg(hw, MII_BMSR,
-							(u16 *)&mii_bmsr_data);
+							&mii_bmsr_data);
 					if (mii_bmsr_data & BMSR_LSTATUS)
 						break;
 				}
diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index 5d10884..149a294 100644
--- a/drivers/net/ethernet/atheros/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -1061,7 +1061,7 @@ static s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
 		goto err_nomem;
 	}
 	rfd_ring->buffer_info =
-		(struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count);
+		(tpd_ring->buffer_info + tpd_ring->count);
 
 	/*
 	 * real ring DMA buffer
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index ac7b744..9b69a62 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 
+#include <linux/stringify.h>
 #include <linux/kernel.h>
 #include <linux/timer.h>
 #include <linux/errno.h>
@@ -57,8 +58,8 @@
 #include "bnx2_fw.h"
 
 #define DRV_MODULE_NAME		"bnx2"
-#define DRV_MODULE_VERSION	"2.2.1"
-#define DRV_MODULE_RELDATE	"Dec 18, 2011"
+#define DRV_MODULE_VERSION	"2.2.2"
+#define DRV_MODULE_RELDATE	"June 16, 2012"
 #define FW_MIPS_FILE_06		"bnx2/bnx2-mips-06-6.2.3.fw"
 #define FW_RV2P_FILE_06		"bnx2/bnx2-rv2p-06-6.0.15.fw"
 #define FW_MIPS_FILE_09		"bnx2/bnx2-mips-09-6.2.1b.fw"
@@ -872,8 +873,7 @@ bnx2_alloc_mem(struct bnx2 *bp)
 
 			bnapi = &bp->bnx2_napi[i];
 
-			sblk = (void *) (status_blk +
-					 BNX2_SBLK_MSIX_ALIGN_SIZE * i);
+			sblk = (status_blk + BNX2_SBLK_MSIX_ALIGN_SIZE * i);
 			bnapi->status_blk.msix = sblk;
 			bnapi->hw_tx_cons_ptr =
 				&sblk->status_tx_quick_consumer_index;
@@ -2473,6 +2473,7 @@ bnx2_dump_mcp_state(struct bnx2 *bp)
 		   bnx2_shmem_rd(bp, BNX2_BC_STATE_RESET_TYPE));
 	pr_cont(" condition[%08x]\n",
 		bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION));
+	DP_SHMEM_LINE(bp, BNX2_BC_RESET_TYPE);
 	DP_SHMEM_LINE(bp, 0x3cc);
 	DP_SHMEM_LINE(bp, 0x3dc);
 	DP_SHMEM_LINE(bp, 0x3ec);
@@ -6406,6 +6407,75 @@ bnx2_reset_task(struct work_struct *work)
 	rtnl_unlock();
 }
 
+#define BNX2_FTQ_ENTRY(ftq) { __stringify(ftq##FTQ_CTL), BNX2_##ftq##FTQ_CTL }
+
+static void
+bnx2_dump_ftq(struct bnx2 *bp)
+{
+	int i;
+	u32 reg, bdidx, cid, valid;
+	struct net_device *dev = bp->dev;
+	static const struct ftq_reg {
+		char *name;
+		u32 off;
+	} ftq_arr[] = {
+		BNX2_FTQ_ENTRY(RV2P_P),
+		BNX2_FTQ_ENTRY(RV2P_T),
+		BNX2_FTQ_ENTRY(RV2P_M),
+		BNX2_FTQ_ENTRY(TBDR_),
+		BNX2_FTQ_ENTRY(TDMA_),
+		BNX2_FTQ_ENTRY(TXP_),
+		BNX2_FTQ_ENTRY(TXP_),
+		BNX2_FTQ_ENTRY(TPAT_),
+		BNX2_FTQ_ENTRY(RXP_C),
+		BNX2_FTQ_ENTRY(RXP_),
+		BNX2_FTQ_ENTRY(COM_COMXQ_),
+		BNX2_FTQ_ENTRY(COM_COMTQ_),
+		BNX2_FTQ_ENTRY(COM_COMQ_),
+		BNX2_FTQ_ENTRY(CP_CPQ_),
+	};
+
+	netdev_err(dev, "<--- start FTQ dump --->\n");
+	for (i = 0; i < ARRAY_SIZE(ftq_arr); i++)
+		netdev_err(dev, "%s %08x\n", ftq_arr[i].name,
+			   bnx2_reg_rd_ind(bp, ftq_arr[i].off));
+
+	netdev_err(dev, "CPU states:\n");
+	for (reg = BNX2_TXP_CPU_MODE; reg <= BNX2_CP_CPU_MODE; reg += 0x40000)
+		netdev_err(dev, "%06x mode %x state %x evt_mask %x pc %x pc %x instr %x\n",
+			   reg, bnx2_reg_rd_ind(bp, reg),
+			   bnx2_reg_rd_ind(bp, reg + 4),
+			   bnx2_reg_rd_ind(bp, reg + 8),
+			   bnx2_reg_rd_ind(bp, reg + 0x1c),
+			   bnx2_reg_rd_ind(bp, reg + 0x1c),
+			   bnx2_reg_rd_ind(bp, reg + 0x20));
+
+	netdev_err(dev, "<--- end FTQ dump --->\n");
+	netdev_err(dev, "<--- start TBDC dump --->\n");
+	netdev_err(dev, "TBDC free cnt: %ld\n",
+		   REG_RD(bp, BNX2_TBDC_STATUS) & BNX2_TBDC_STATUS_FREE_CNT);
+	netdev_err(dev, "LINE     CID  BIDX   CMD  VALIDS\n");
+	for (i = 0; i < 0x20; i++) {
+		int j = 0;
+
+		REG_WR(bp, BNX2_TBDC_BD_ADDR, i);
+		REG_WR(bp, BNX2_TBDC_CAM_OPCODE,
+		       BNX2_TBDC_CAM_OPCODE_OPCODE_CAM_READ);
+		REG_WR(bp, BNX2_TBDC_COMMAND, BNX2_TBDC_COMMAND_CMD_REG_ARB);
+		while ((REG_RD(bp, BNX2_TBDC_COMMAND) &
+			BNX2_TBDC_COMMAND_CMD_REG_ARB) && j < 100)
+			j++;
+
+		cid = REG_RD(bp, BNX2_TBDC_CID);
+		bdidx = REG_RD(bp, BNX2_TBDC_BIDX);
+		valid = REG_RD(bp, BNX2_TBDC_CAM_OPCODE);
+		netdev_err(dev, "%02x    %06x  %04lx   %02x    [%x]\n",
+			   i, cid, bdidx & BNX2_TBDC_BDIDX_BDIDX,
+			   bdidx >> 24, (valid >> 8) & 0x0ff);
+	}
+	netdev_err(dev, "<--- end TBDC dump --->\n");
+}
+
 static void
 bnx2_dump_state(struct bnx2 *bp)
 {
@@ -6435,6 +6505,7 @@ bnx2_tx_timeout(struct net_device *dev)
 {
 	struct bnx2 *bp = netdev_priv(dev);
 
+	bnx2_dump_ftq(bp);
 	bnx2_dump_state(bp);
 	bnx2_dump_mcp_state(bp);
 
@@ -7832,7 +7903,7 @@ bnx2_get_5709_media(struct bnx2 *bp)
 	else
 		strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
 
-	if (PCI_FUNC(bp->pdev->devfn) == 0) {
+	if (bp->func == 0) {
 		switch (strap) {
 		case 0x4:
 		case 0x5:
@@ -8131,9 +8202,12 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
 	reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
 
+	if (bnx2_reg_rd_ind(bp, BNX2_MCP_TOE_ID) & BNX2_MCP_TOE_ID_FUNCTION_ID)
+		bp->func = 1;
+
 	if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
 	    BNX2_SHM_HDR_SIGNATURE_SIG) {
-		u32 off = PCI_FUNC(pdev->devfn) << 2;
+		u32 off = bp->func << 2;
 
 		bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
 	} else
diff --git a/drivers/net/ethernet/broadcom/bnx2.h b/drivers/net/ethernet/broadcom/bnx2.h
index dc06bda..af6451d 100644
--- a/drivers/net/ethernet/broadcom/bnx2.h
+++ b/drivers/net/ethernet/broadcom/bnx2.h
@@ -4642,6 +4642,47 @@ struct l2_fhdr {
 #define BNX2_TBDR_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
 
 
+/*
+ *  tbdc definition
+ *  offset: 0x5400
+ */
+#define BNX2_TBDC_COMMAND                               0x5400
+#define BNX2_TBDC_COMMAND_CMD_ENABLED                    (1UL<<0)
+#define BNX2_TBDC_COMMAND_CMD_FLUSH                      (1UL<<1)
+#define BNX2_TBDC_COMMAND_CMD_SOFT_RST                   (1UL<<2)
+#define BNX2_TBDC_COMMAND_CMD_REG_ARB                    (1UL<<3)
+#define BNX2_TBDC_COMMAND_WRCHK_RANGE_ERROR              (1UL<<4)
+#define BNX2_TBDC_COMMAND_WRCHK_ALL_ONES_ERROR           (1UL<<5)
+#define BNX2_TBDC_COMMAND_WRCHK_ALL_ZEROS_ERROR          (1UL<<6)
+#define BNX2_TBDC_COMMAND_WRCHK_ANY_ONES_ERROR           (1UL<<7)
+#define BNX2_TBDC_COMMAND_WRCHK_ANY_ZEROS_ERROR          (1UL<<8)
+
+#define BNX2_TBDC_STATUS				0x5404
+#define BNX2_TBDC_STATUS_FREE_CNT                        (0x3fUL<<0)
+
+#define BNX2_TBDC_BD_ADDR                               0x5424
+
+#define BNX2_TBDC_BIDX                                  0x542c
+#define BNX2_TBDC_BDIDX_BDIDX                            (0xffffUL<<0)
+#define BNX2_TBDC_BDIDX_CMD                              (0xffUL<<24)
+
+#define BNX2_TBDC_CID                                   0x5430
+
+#define BNX2_TBDC_CAM_OPCODE                            0x5434
+#define BNX2_TBDC_CAM_OPCODE_OPCODE                      (0x7UL<<0)
+#define BNX2_TBDC_CAM_OPCODE_OPCODE_SEARCH               (0UL<<0)
+#define BNX2_TBDC_CAM_OPCODE_OPCODE_CACHE_WRITE          (1UL<<0)
+#define BNX2_TBDC_CAM_OPCODE_OPCODE_INVALIDATE           (2UL<<0)
+#define BNX2_TBDC_CAM_OPCODE_OPCODE_CAM_WRITE            (4UL<<0)
+#define BNX2_TBDC_CAM_OPCODE_OPCODE_CAM_READ             (5UL<<0)
+#define BNX2_TBDC_CAM_OPCODE_OPCODE_RAM_WRITE            (6UL<<0)
+#define BNX2_TBDC_CAM_OPCODE_OPCODE_RAM_READ             (7UL<<0)
+#define BNX2_TBDC_CAM_OPCODE_SMASK_BDIDX                 (1UL<<4)
+#define BNX2_TBDC_CAM_OPCODE_SMASK_CID                   (1UL<<5)
+#define BNX2_TBDC_CAM_OPCODE_SMASK_CMD                   (1UL<<6)
+#define BNX2_TBDC_CAM_OPCODE_WMT_FAILED                  (1UL<<7)
+#define BNX2_TBDC_CAM_OPCODE_CAM_VALIDS                  (0xffUL<<8)
+
 
 /*
  *  tdma_reg definition
@@ -6930,6 +6971,8 @@ struct bnx2 {
 	struct bnx2_irq		irq_tbl[BNX2_MAX_MSIX_VEC];
 	int			irq_nvecs;
 
+	u8			func;
+
 	u8			num_tx_rings;
 	u8			num_rx_rings;
 
@@ -7314,6 +7357,8 @@ struct bnx2_rv2p_fw_file {
 #define BNX2_BC_STATE_RESET_TYPE_VALUE(msg) (BNX2_BC_STATE_RESET_TYPE_SIG | \
 					     (msg))
 
+#define BNX2_BC_RESET_TYPE			0x000001c0
+
 #define BNX2_BC_STATE				0x000001c4
 #define BNX2_BC_STATE_ERR_MASK			 0x0000ff00
 #define BNX2_BC_STATE_SIGN			 0x42530000
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index 7de8241..7211cb0 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -23,8 +23,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.72.50-0"
-#define DRV_MODULE_RELDATE      "2012/04/23"
+#define DRV_MODULE_VERSION      "1.72.51-0"
+#define DRV_MODULE_RELDATE      "2012/06/18"
 #define BNX2X_BC_VER            0x040200
 
 #if defined(CONFIG_DCB)
@@ -248,13 +248,12 @@ enum {
 	BNX2X_MAX_CNIC_ETH_CL_ID_IDX,
 };
 
-#define BNX2X_CNIC_START_ETH_CID	48
-enum {
+#define BNX2X_CNIC_START_ETH_CID(bp)	(BNX2X_NUM_NON_CNIC_QUEUES(bp) *\
+					 (bp)->max_cos)
 	/* iSCSI L2 */
-	BNX2X_ISCSI_ETH_CID = BNX2X_CNIC_START_ETH_CID,
+#define	BNX2X_ISCSI_ETH_CID(bp)		(BNX2X_CNIC_START_ETH_CID(bp))
 	/* FCoE L2 */
-	BNX2X_FCOE_ETH_CID,
-};
+#define	BNX2X_FCOE_ETH_CID(bp)		(BNX2X_CNIC_START_ETH_CID(bp) + 1)
 
 /** Additional rings budgeting */
 #ifdef BCM_CNIC
@@ -276,29 +275,30 @@ enum {
 #define FIRST_TX_ONLY_COS_INDEX		1
 #define FIRST_TX_COS_INDEX		0
 
-/* defines for decodeing the fastpath index and the cos index out of the
- * transmission queue index
- */
-#define MAX_TXQS_PER_COS	FP_SB_MAX_E1x
-
-#define TXQ_TO_FP(txq_index)	((txq_index) % MAX_TXQS_PER_COS)
-#define TXQ_TO_COS(txq_index)	((txq_index) / MAX_TXQS_PER_COS)
-
 /* rules for calculating the cids of tx-only connections */
-#define CID_TO_FP(cid)		((cid) % MAX_TXQS_PER_COS)
-#define CID_COS_TO_TX_ONLY_CID(cid, cos)	(cid + cos * MAX_TXQS_PER_COS)
+#define CID_TO_FP(cid, bp)		((cid) % BNX2X_NUM_NON_CNIC_QUEUES(bp))
+#define CID_COS_TO_TX_ONLY_CID(cid, cos, bp) \
+				(cid + cos * BNX2X_NUM_NON_CNIC_QUEUES(bp))
 
 /* fp index inside class of service range */
-#define FP_COS_TO_TXQ(fp, cos)    ((fp)->index + cos * MAX_TXQS_PER_COS)
-
-/*
- * 0..15 eth cos0
- * 16..31 eth cos1 if applicable
- * 32..47 eth cos2 If applicable
- * fcoe queue follows eth queues (16, 32, 48 depending on cos)
+#define FP_COS_TO_TXQ(fp, cos, bp) \
+			((fp)->index + cos * BNX2X_NUM_NON_CNIC_QUEUES(bp))
+
+/* Indexes for transmission queues array:
+ * txdata for RSS i CoS j is at location i + (j * num of RSS)
+ * txdata for FCoE (if exist) is at location max cos * num of RSS
+ * txdata for FWD (if exist) is one location after FCoE
+ * txdata for OOO (if exist) is one location after FWD
  */
-#define MAX_ETH_TXQ_IDX(bp)	(MAX_TXQS_PER_COS * (bp)->max_cos)
-#define FCOE_TXQ_IDX(bp)	(MAX_ETH_TXQ_IDX(bp))
+enum {
+	FCOE_TXQ_IDX_OFFSET,
+	FWD_TXQ_IDX_OFFSET,
+	OOO_TXQ_IDX_OFFSET,
+};
+#define MAX_ETH_TXQ_IDX(bp)	(BNX2X_NUM_NON_CNIC_QUEUES(bp) * (bp)->max_cos)
+#ifdef BCM_CNIC
+#define FCOE_TXQ_IDX(bp)	(MAX_ETH_TXQ_IDX(bp) + FCOE_TXQ_IDX_OFFSET)
+#endif
 
 /* fast path */
 /*
@@ -481,6 +481,8 @@ struct bnx2x_fp_txdata {
 	__le16			*tx_cons_sb;
 
 	int			txq_index;
+	struct bnx2x_fastpath	*parent_fp;
+	int			tx_ring_size;
 };
 
 enum bnx2x_tpa_mode_t {
@@ -507,7 +509,7 @@ struct bnx2x_fastpath {
 	enum bnx2x_tpa_mode_t	mode;
 
 	u8			max_cos; /* actual number of active tx coses */
-	struct bnx2x_fp_txdata	txdata[BNX2X_MULTI_TX_COS];
+	struct bnx2x_fp_txdata	*txdata_ptr[BNX2X_MULTI_TX_COS];
 
 	struct sw_rx_bd		*rx_buf_ring;	/* BDs mappings ring */
 	struct sw_rx_page	*rx_page_ring;	/* SGE pages mappings ring */
@@ -547,51 +549,45 @@ struct bnx2x_fastpath {
 				rx_calls;
 
 	/* TPA related */
-	struct bnx2x_agg_info	tpa_info[ETH_MAX_AGGREGATION_QUEUES_E1H_E2];
+	struct bnx2x_agg_info	*tpa_info;
 	u8			disable_tpa;
 #ifdef BNX2X_STOP_ON_ERROR
 	u64			tpa_queue_used;
 #endif
-
-	struct tstorm_per_queue_stats old_tclient;
-	struct ustorm_per_queue_stats old_uclient;
-	struct xstorm_per_queue_stats old_xclient;
-	struct bnx2x_eth_q_stats eth_q_stats;
-	struct bnx2x_eth_q_stats_old eth_q_stats_old;
-
 	/* The size is calculated using the following:
 	     sizeof name field from netdev structure +
 	     4 ('-Xx-' string) +
 	     4 (for the digits and to make it DWORD aligned) */
 #define FP_NAME_SIZE		(sizeof(((struct net_device *)0)->name) + 8)
 	char			name[FP_NAME_SIZE];
-
-	/* MACs object */
-	struct bnx2x_vlan_mac_obj mac_obj;
-
-	/* Queue State object */
-	struct bnx2x_queue_sp_obj q_obj;
-
 };
 
-#define bnx2x_fp(bp, nr, var)		(bp->fp[nr].var)
+#define bnx2x_fp(bp, nr, var)	((bp)->fp[(nr)].var)
+#define bnx2x_sp_obj(bp, fp)	((bp)->sp_objs[(fp)->index])
+#define bnx2x_fp_stats(bp, fp)	(&((bp)->fp_stats[(fp)->index]))
+#define bnx2x_fp_qstats(bp, fp)	(&((bp)->fp_stats[(fp)->index].eth_q_stats))
 
 /* Use 2500 as a mini-jumbo MTU for FCoE */
 #define BNX2X_FCOE_MINI_JUMBO_MTU	2500
 
-/* FCoE L2 `fastpath' entry is right after the eth entries */
-#define FCOE_IDX			BNX2X_NUM_ETH_QUEUES(bp)
-#define bnx2x_fcoe_fp(bp)		(&bp->fp[FCOE_IDX])
-#define bnx2x_fcoe(bp, var)		(bnx2x_fcoe_fp(bp)->var)
-#define bnx2x_fcoe_tx(bp, var)		(bnx2x_fcoe_fp(bp)-> \
-						txdata[FIRST_TX_COS_INDEX].var)
+#define	FCOE_IDX_OFFSET		0
+
+#define FCOE_IDX(bp)		(BNX2X_NUM_NON_CNIC_QUEUES(bp) + \
+				 FCOE_IDX_OFFSET)
+#define bnx2x_fcoe_fp(bp)	(&bp->fp[FCOE_IDX(bp)])
+#define bnx2x_fcoe(bp, var)	(bnx2x_fcoe_fp(bp)->var)
+#define bnx2x_fcoe_inner_sp_obj(bp)	(&bp->sp_objs[FCOE_IDX(bp)])
+#define bnx2x_fcoe_sp_obj(bp, var)	(bnx2x_fcoe_inner_sp_obj(bp)->var)
+#define bnx2x_fcoe_tx(bp, var)	(bnx2x_fcoe_fp(bp)-> \
+						txdata_ptr[FIRST_TX_COS_INDEX] \
+						->var)
 
 
 #define IS_ETH_FP(fp)			(fp->index < \
 					 BNX2X_NUM_ETH_QUEUES(fp->bp))
 #ifdef BCM_CNIC
-#define IS_FCOE_FP(fp)			(fp->index == FCOE_IDX)
-#define IS_FCOE_IDX(idx)		((idx) == FCOE_IDX)
+#define IS_FCOE_FP(fp)			(fp->index == FCOE_IDX(fp->bp))
+#define IS_FCOE_IDX(idx)		((idx) == FCOE_IDX(bp))
 #else
 #define IS_FCOE_FP(fp)		false
 #define IS_FCOE_IDX(idx)	false
@@ -978,8 +974,8 @@ union cdu_context {
 };
 
 /* CDU host DB constants */
-#define CDU_ILT_PAGE_SZ_HW	3
-#define CDU_ILT_PAGE_SZ		(8192 << CDU_ILT_PAGE_SZ_HW) /* 64K */
+#define CDU_ILT_PAGE_SZ_HW	2
+#define CDU_ILT_PAGE_SZ		(8192 << CDU_ILT_PAGE_SZ_HW) /* 32K */
 #define ILT_PAGE_CIDS		(CDU_ILT_PAGE_SZ / sizeof(union cdu_context))
 
 #ifdef BCM_CNIC
@@ -1182,11 +1178,31 @@ struct bnx2x_prev_path_list {
 	struct list_head list;
 };
 
+struct bnx2x_sp_objs {
+	/* MACs object */
+	struct bnx2x_vlan_mac_obj mac_obj;
+
+	/* Queue State object */
+	struct bnx2x_queue_sp_obj q_obj;
+};
+
+struct bnx2x_fp_stats {
+	struct tstorm_per_queue_stats old_tclient;
+	struct ustorm_per_queue_stats old_uclient;
+	struct xstorm_per_queue_stats old_xclient;
+	struct bnx2x_eth_q_stats eth_q_stats;
+	struct bnx2x_eth_q_stats_old eth_q_stats_old;
+};
+
 struct bnx2x {
 	/* Fields used in the tx and intr/napi performance paths
 	 * are grouped together in the beginning of the structure
 	 */
 	struct bnx2x_fastpath	*fp;
+	struct bnx2x_sp_objs	*sp_objs;
+	struct bnx2x_fp_stats	*fp_stats;
+	struct bnx2x_fp_txdata	*bnx2x_txq;
+	int			bnx2x_txq_size;
 	void __iomem		*regview;
 	void __iomem		*doorbells;
 	u16			db_size;
@@ -1302,6 +1318,7 @@ struct bnx2x {
 #define NO_FCOE_FLAG			(1 << 15)
 #define BC_SUPPORTS_PFC_STATS		(1 << 17)
 #define USING_SINGLE_MSIX_FLAG		(1 << 20)
+#define BC_SUPPORTS_DCBX_MSG_NON_PMF	(1 << 21)
 
 #define NO_ISCSI(bp)		((bp)->flags & NO_ISCSI_FLAG)
 #define NO_ISCSI_OOO(bp)	((bp)->flags & NO_ISCSI_OOO_FLAG)
@@ -1377,6 +1394,7 @@ struct bnx2x {
 #define BNX2X_MAX_COS			3
 #define BNX2X_MAX_TX_COS		2
 	int			num_queues;
+	int			num_napi_queues;
 	int			disable_tpa;
 
 	u32			rx_mode;
@@ -1389,6 +1407,7 @@ struct bnx2x {
 	u8			igu_dsb_id;
 	u8			igu_base_sb;
 	u8			igu_sb_cnt;
+
 	dma_addr_t		def_status_blk_mapping;
 
 	struct bnx2x_slowpath	*slowpath;
@@ -1420,7 +1439,11 @@ struct bnx2x {
 	dma_addr_t			fw_stats_data_mapping;
 	int				fw_stats_data_sz;
 
-	struct hw_context	context;
+	/* For max 196 cids (64*3 + non-eth), 32KB ILT page size and 1KB
+	 * context size we need 8 ILT entries.
+	 */
+#define ILT_MAX_L2_LINES	8
+	struct hw_context	context[ILT_MAX_L2_LINES];
 
 	struct bnx2x_ilt	*ilt;
 #define BP_ILT(bp)		((bp)->ilt)
@@ -1433,13 +1456,14 @@ struct bnx2x {
 
 /*
  * Maximum CID count that might be required by the bnx2x:
- * Max Tss * Max_Tx_Multi_Cos + CNIC L2 Clients (FCoE and iSCSI related)
+ * Max RSS * Max_Tx_Multi_Cos + FCoE + iSCSI
  */
-#define BNX2X_L2_CID_COUNT(bp)	(MAX_TXQS_PER_COS * BNX2X_MULTI_TX_COS +\
-					NON_ETH_CONTEXT_USE + CNIC_PRESENT)
+#define BNX2X_L2_CID_COUNT(bp)	(BNX2X_NUM_ETH_QUEUES(bp) * BNX2X_MULTI_TX_COS \
+				+ NON_ETH_CONTEXT_USE + CNIC_PRESENT)
+#define BNX2X_L2_MAX_CID(bp)	(BNX2X_MAX_RSS_COUNT(bp) * BNX2X_MULTI_TX_COS \
+				+ NON_ETH_CONTEXT_USE + CNIC_PRESENT)
 #define L2_ILT_LINES(bp)	(DIV_ROUND_UP(BNX2X_L2_CID_COUNT(bp),\
 					ILT_PAGE_CIDS))
-#define BNX2X_DB_SIZE(bp)	(BNX2X_L2_CID_COUNT(bp) * (1 << BNX2X_DB_SHIFT))
 
 	int			qm_cid_count;
 
@@ -1598,6 +1622,8 @@ struct bnx2x {
 extern int num_queues;
 #define BNX2X_NUM_QUEUES(bp)	(bp->num_queues)
 #define BNX2X_NUM_ETH_QUEUES(bp) (BNX2X_NUM_QUEUES(bp) - NON_ETH_CONTEXT_USE)
+#define BNX2X_NUM_NON_CNIC_QUEUES(bp)	(BNX2X_NUM_QUEUES(bp) - \
+					 NON_ETH_CONTEXT_USE)
 #define BNX2X_NUM_RX_QUEUES(bp)	BNX2X_NUM_QUEUES(bp)
 
 #define is_multi(bp)		(BNX2X_NUM_QUEUES(bp) > 1)
@@ -1656,6 +1682,9 @@ struct bnx2x_func_init_params {
 			continue;		\
 		else
 
+#define for_each_napi_rx_queue(bp, var) \
+	for ((var) = 0; (var) < bp->num_napi_queues; (var)++)
+
 /* Skip OOO FP */
 #define for_each_tx_queue(bp, var) \
 	for ((var) = 0; (var) < BNX2X_NUM_QUEUES(bp); (var)++) \
@@ -1817,6 +1846,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define LOAD_NORMAL			0
 #define LOAD_OPEN			1
 #define LOAD_DIAG			2
+#define LOAD_LOOPBACK_EXT		3
 #define UNLOAD_NORMAL			0
 #define UNLOAD_CLOSE			1
 #define UNLOAD_RECOVERY			2
@@ -1899,13 +1929,17 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define PCICFG_LINK_SPEED		0xf0000
 #define PCICFG_LINK_SPEED_SHIFT		16
 
-
-#define BNX2X_NUM_TESTS			7
+#define BNX2X_NUM_TESTS_SF		7
+#define BNX2X_NUM_TESTS_MF		3
+#define BNX2X_NUM_TESTS(bp)		(IS_MF(bp) ? BNX2X_NUM_TESTS_MF : \
+						     BNX2X_NUM_TESTS_SF)
 
 #define BNX2X_PHY_LOOPBACK		0
 #define BNX2X_MAC_LOOPBACK		1
+#define BNX2X_EXT_LOOPBACK		2
 #define BNX2X_PHY_LOOPBACK_FAILED	1
 #define BNX2X_MAC_LOOPBACK_FAILED	2
+#define BNX2X_EXT_LOOPBACK_FAILED	3
 #define BNX2X_LOOPBACK_FAILED		(BNX2X_MAC_LOOPBACK_FAILED | \
 					 BNX2X_PHY_LOOPBACK_FAILED)
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index cbc56f2..00951b3 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -40,12 +40,19 @@
  * Makes sure the contents of the bp->fp[to].napi is kept
  * intact. This is done by first copying the napi struct from
  * the target to the source, and then mem copying the entire
- * source onto the target
+ * source onto the target. Update txdata pointers and related
+ * content.
  */
 static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
 {
 	struct bnx2x_fastpath *from_fp = &bp->fp[from];
 	struct bnx2x_fastpath *to_fp = &bp->fp[to];
+	struct bnx2x_sp_objs *from_sp_objs = &bp->sp_objs[from];
+	struct bnx2x_sp_objs *to_sp_objs = &bp->sp_objs[to];
+	struct bnx2x_fp_stats *from_fp_stats = &bp->fp_stats[from];
+	struct bnx2x_fp_stats *to_fp_stats = &bp->fp_stats[to];
+	int old_max_eth_txqs, new_max_eth_txqs;
+	int old_txdata_index = 0, new_txdata_index = 0;
 
 	/* Copy the NAPI object as it has been already initialized */
 	from_fp->napi = to_fp->napi;
@@ -53,6 +60,30 @@ static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
 	/* Move bnx2x_fastpath contents */
 	memcpy(to_fp, from_fp, sizeof(*to_fp));
 	to_fp->index = to;
+
+	/* move sp_objs contents as well, as their indices match fp ones */
+	memcpy(to_sp_objs, from_sp_objs, sizeof(*to_sp_objs));
+
+	/* move fp_stats contents as well, as their indices match fp ones */
+	memcpy(to_fp_stats, from_fp_stats, sizeof(*to_fp_stats));
+
+	/* Update txdata pointers in fp and move txdata content accordingly:
+	 * Each fp consumes 'max_cos' txdata structures, so the index should be
+	 * decremented by max_cos x delta.
+	 */
+
+	old_max_eth_txqs = BNX2X_NUM_ETH_QUEUES(bp) * (bp)->max_cos;
+	new_max_eth_txqs = (BNX2X_NUM_ETH_QUEUES(bp) - from + to) *
+				(bp)->max_cos;
+	if (from == FCOE_IDX(bp)) {
+		old_txdata_index = old_max_eth_txqs + FCOE_TXQ_IDX_OFFSET;
+		new_txdata_index = new_max_eth_txqs + FCOE_TXQ_IDX_OFFSET;
+	}
+
+	memcpy(&bp->bnx2x_txq[old_txdata_index],
+	       &bp->bnx2x_txq[new_txdata_index],
+	       sizeof(struct bnx2x_fp_txdata));
+	to_fp->txdata_ptr[0] = &bp->bnx2x_txq[new_txdata_index];
 }
 
 int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */
@@ -190,7 +221,7 @@ int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata)
 
 		if ((netif_tx_queue_stopped(txq)) &&
 		    (bp->state == BNX2X_STATE_OPEN) &&
-		    (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 3))
+		    (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 4))
 			netif_tx_wake_queue(txq);
 
 		__netif_tx_unlock(txq);
@@ -479,7 +510,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
 		   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++;
+			bnx2x_fp_qstats(bp, fp)->rx_skb_alloc_failed++;
 			return err;
 		}
 
@@ -584,7 +615,7 @@ drop:
 	/* drop the packet and keep the buffer in the bin */
 	DP(NETIF_MSG_RX_STATUS,
 	   "Failed to allocate or map a new skb - dropping packet!\n");
-	fp->eth_q_stats.rx_skb_alloc_failed++;
+	bnx2x_fp_stats(bp, fp)->eth_q_stats.rx_skb_alloc_failed++;
 }
 
 static int bnx2x_alloc_rx_data(struct bnx2x *bp,
@@ -617,8 +648,10 @@ static int bnx2x_alloc_rx_data(struct bnx2x *bp,
 	return 0;
 }
 
-static void bnx2x_csum_validate(struct sk_buff *skb, union eth_rx_cqe *cqe,
-				struct bnx2x_fastpath *fp)
+static
+void bnx2x_csum_validate(struct sk_buff *skb, union eth_rx_cqe *cqe,
+				 struct bnx2x_fastpath *fp,
+				 struct bnx2x_eth_q_stats *qstats)
 {
 	/* Do nothing if no IP/L4 csum validation was done */
 
@@ -632,7 +665,7 @@ static void bnx2x_csum_validate(struct sk_buff *skb, union eth_rx_cqe *cqe,
 	if (cqe->fast_path_cqe.type_error_flags &
 	    (ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG |
 	     ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG))
-		fp->eth_q_stats.hw_csum_err++;
+		qstats->hw_csum_err++;
 	else
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 }
@@ -776,7 +809,7 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
 			DP(NETIF_MSG_RX_ERR | NETIF_MSG_RX_STATUS,
 			   "ERROR  flags %x  rx packet %u\n",
 			   cqe_fp_flags, sw_comp_cons);
-			fp->eth_q_stats.rx_err_discard_pkt++;
+			bnx2x_fp_qstats(bp, fp)->rx_err_discard_pkt++;
 			goto reuse_rx;
 		}
 
@@ -789,7 +822,7 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
 			if (skb == NULL) {
 				DP(NETIF_MSG_RX_ERR | NETIF_MSG_RX_STATUS,
 				   "ERROR  packet dropped because of alloc failure\n");
-				fp->eth_q_stats.rx_skb_alloc_failed++;
+				bnx2x_fp_qstats(bp, fp)->rx_skb_alloc_failed++;
 				goto reuse_rx;
 			}
 			memcpy(skb->data, data + pad, len);
@@ -803,14 +836,15 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
 				skb = build_skb(data, 0);
 				if (unlikely(!skb)) {
 					kfree(data);
-					fp->eth_q_stats.rx_skb_alloc_failed++;
+					bnx2x_fp_qstats(bp, fp)->
+							rx_skb_alloc_failed++;
 					goto next_rx;
 				}
 				skb_reserve(skb, pad);
 			} else {
 				DP(NETIF_MSG_RX_ERR | NETIF_MSG_RX_STATUS,
 				   "ERROR  packet dropped because of alloc failure\n");
-				fp->eth_q_stats.rx_skb_alloc_failed++;
+				bnx2x_fp_qstats(bp, fp)->rx_skb_alloc_failed++;
 reuse_rx:
 				bnx2x_reuse_rx_data(fp, bd_cons, bd_prod);
 				goto next_rx;
@@ -826,8 +860,8 @@ reuse_rx:
 		skb_checksum_none_assert(skb);
 
 		if (bp->dev->features & NETIF_F_RXCSUM)
-			bnx2x_csum_validate(skb, cqe, fp);
-
+			bnx2x_csum_validate(skb, cqe, fp,
+					    bnx2x_fp_qstats(bp, fp));
 
 		skb_record_rx_queue(skb, fp->rx_queue);
 
@@ -888,7 +922,7 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
 	prefetch(fp->rx_cons_sb);
 
 	for_each_cos_in_tx_queue(fp, cos)
-		prefetch(fp->txdata[cos].tx_cons_sb);
+		prefetch(fp->txdata_ptr[cos]->tx_cons_sb);
 
 	prefetch(&fp->sb_running_index[SM_RX_ID]);
 	napi_schedule(&bnx2x_fp(bp, fp->index, napi));
@@ -1205,7 +1239,7 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp)
 	for_each_tx_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 		for_each_cos_in_tx_queue(fp, cos) {
-			struct bnx2x_fp_txdata *txdata = &fp->txdata[cos];
+			struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];
 			unsigned pkts_compl = 0, bytes_compl = 0;
 
 			u16 sw_prod = txdata->tx_pkt_prod;
@@ -1217,7 +1251,8 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp)
 				sw_cons++;
 			}
 			netdev_tx_reset_queue(
-			    netdev_get_tx_queue(bp->dev, txdata->txq_index));
+				netdev_get_tx_queue(bp->dev,
+						    txdata->txq_index));
 		}
 	}
 }
@@ -1325,7 +1360,7 @@ void bnx2x_free_irq(struct bnx2x *bp)
 		free_irq(bp->dev->irq, bp->dev);
 }
 
-int __devinit bnx2x_enable_msix(struct bnx2x *bp)
+int bnx2x_enable_msix(struct bnx2x *bp)
 {
 	int msix_vec = 0, i, rc, req_cnt;
 
@@ -1579,6 +1614,8 @@ void bnx2x_set_num_queues(struct bnx2x *bp)
 #endif
 	/* Add special queues */
 	bp->num_queues += NON_ETH_CONTEXT_USE;
+
+	BNX2X_DEV_INFO("set number of queues to %d\n", bp->num_queues);
 }
 
 /**
@@ -1607,8 +1644,8 @@ static int bnx2x_set_real_num_queues(struct bnx2x *bp)
 {
 	int rc, tx, rx;
 
-	tx = MAX_TXQS_PER_COS * bp->max_cos;
-	rx = BNX2X_NUM_ETH_QUEUES(bp);
+	tx = BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos;
+	rx = BNX2X_NUM_QUEUES(bp) - NON_ETH_CONTEXT_USE;
 
 /* account for fcoe queue */
 #ifdef BCM_CNIC
@@ -1666,14 +1703,13 @@ static void bnx2x_set_rx_buf_size(struct bnx2x *bp)
 static int bnx2x_init_rss_pf(struct bnx2x *bp)
 {
 	int i;
-	u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};
 	u8 num_eth_queues = BNX2X_NUM_ETH_QUEUES(bp);
 
 	/* Prepare the initial contents fo the indirection table if RSS is
 	 * enabled
 	 */
-	for (i = 0; i < sizeof(ind_table); i++)
-		ind_table[i] =
+	for (i = 0; i < sizeof(bp->rss_conf_obj.ind_table); i++)
+		bp->rss_conf_obj.ind_table[i] =
 			bp->fp->cl_id +
 			ethtool_rxfh_indir_default(i, num_eth_queues);
 
@@ -1685,12 +1721,11 @@ static int bnx2x_init_rss_pf(struct bnx2x *bp)
 	 * For 57712 and newer on the other hand it's a per-function
 	 * configuration.
 	 */
-	return bnx2x_config_rss_eth(bp, ind_table,
-				    bp->port.pmf || !CHIP_IS_E1x(bp));
+	return bnx2x_config_rss_eth(bp, bp->port.pmf || !CHIP_IS_E1x(bp));
 }
 
 int bnx2x_config_rss_pf(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
-			u8 *ind_table, bool config_hash)
+			bool config_hash)
 {
 	struct bnx2x_config_rss_params params = {NULL};
 	int i;
@@ -1713,11 +1748,15 @@ int bnx2x_config_rss_pf(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
 	__set_bit(BNX2X_RSS_IPV4_TCP, &params.rss_flags);
 	__set_bit(BNX2X_RSS_IPV6, &params.rss_flags);
 	__set_bit(BNX2X_RSS_IPV6_TCP, &params.rss_flags);
+	if (rss_obj->udp_rss_v4)
+		__set_bit(BNX2X_RSS_IPV4_UDP, &params.rss_flags);
+	if (rss_obj->udp_rss_v6)
+		__set_bit(BNX2X_RSS_IPV6_UDP, &params.rss_flags);
 
 	/* Hash bits */
 	params.rss_result_mask = MULTI_MASK;
 
-	memcpy(params.ind_table, ind_table, sizeof(params.ind_table));
+	memcpy(params.ind_table, rss_obj->ind_table, sizeof(params.ind_table));
 
 	if (config_hash) {
 		/* RSS keys */
@@ -1754,7 +1793,7 @@ static void bnx2x_squeeze_objects(struct bnx2x *bp)
 	int rc;
 	unsigned long ramrod_flags = 0, vlan_mac_flags = 0;
 	struct bnx2x_mcast_ramrod_params rparam = {NULL};
-	struct bnx2x_vlan_mac_obj *mac_obj = &bp->fp->mac_obj;
+	struct bnx2x_vlan_mac_obj *mac_obj = &bp->sp_objs->mac_obj;
 
 	/***************** Cleanup MACs' object first *************************/
 
@@ -1765,7 +1804,7 @@ static void bnx2x_squeeze_objects(struct bnx2x *bp)
 
 	/* Clean ETH primary MAC */
 	__set_bit(BNX2X_ETH_MAC, &vlan_mac_flags);
-	rc = mac_obj->delete_all(bp, &bp->fp->mac_obj, &vlan_mac_flags,
+	rc = mac_obj->delete_all(bp, &bp->sp_objs->mac_obj, &vlan_mac_flags,
 				 &ramrod_flags);
 	if (rc != 0)
 		BNX2X_ERR("Failed to clean ETH MACs: %d\n", rc);
@@ -1851,11 +1890,16 @@ bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err)
 static void bnx2x_bz_fp(struct bnx2x *bp, int index)
 {
 	struct bnx2x_fastpath *fp = &bp->fp[index];
+	struct bnx2x_fp_stats *fp_stats = &bp->fp_stats[index];
+
+	int cos;
 	struct napi_struct orig_napi = fp->napi;
+	struct bnx2x_agg_info *orig_tpa_info = fp->tpa_info;
 	/* bzero bnx2x_fastpath contents */
-	if (bp->stats_init)
+	if (bp->stats_init) {
+		memset(fp->tpa_info, 0, sizeof(*fp->tpa_info));
 		memset(fp, 0, sizeof(*fp));
-	else {
+	} else {
 		/* Keep Queue statistics */
 		struct bnx2x_eth_q_stats *tmp_eth_q_stats;
 		struct bnx2x_eth_q_stats_old *tmp_eth_q_stats_old;
@@ -1863,26 +1907,27 @@ static void bnx2x_bz_fp(struct bnx2x *bp, int index)
 		tmp_eth_q_stats = kzalloc(sizeof(struct bnx2x_eth_q_stats),
 					  GFP_KERNEL);
 		if (tmp_eth_q_stats)
-			memcpy(tmp_eth_q_stats, &fp->eth_q_stats,
+			memcpy(tmp_eth_q_stats, &fp_stats->eth_q_stats,
 			       sizeof(struct bnx2x_eth_q_stats));
 
 		tmp_eth_q_stats_old =
 			kzalloc(sizeof(struct bnx2x_eth_q_stats_old),
 				GFP_KERNEL);
 		if (tmp_eth_q_stats_old)
-			memcpy(tmp_eth_q_stats_old, &fp->eth_q_stats_old,
+			memcpy(tmp_eth_q_stats_old, &fp_stats->eth_q_stats_old,
 			       sizeof(struct bnx2x_eth_q_stats_old));
 
+		memset(fp->tpa_info, 0, sizeof(*fp->tpa_info));
 		memset(fp, 0, sizeof(*fp));
 
 		if (tmp_eth_q_stats) {
-			memcpy(&fp->eth_q_stats, tmp_eth_q_stats,
-				   sizeof(struct bnx2x_eth_q_stats));
+			memcpy(&fp_stats->eth_q_stats, tmp_eth_q_stats,
+			       sizeof(struct bnx2x_eth_q_stats));
 			kfree(tmp_eth_q_stats);
 		}
 
 		if (tmp_eth_q_stats_old) {
-			memcpy(&fp->eth_q_stats_old, tmp_eth_q_stats_old,
+			memcpy(&fp_stats->eth_q_stats_old, tmp_eth_q_stats_old,
 			       sizeof(struct bnx2x_eth_q_stats_old));
 			kfree(tmp_eth_q_stats_old);
 		}
@@ -1891,7 +1936,7 @@ static void bnx2x_bz_fp(struct bnx2x *bp, int index)
 
 	/* Restore the NAPI object as it has been already initialized */
 	fp->napi = orig_napi;
-
+	fp->tpa_info = orig_tpa_info;
 	fp->bp = bp;
 	fp->index = index;
 	if (IS_ETH_FP(fp))
@@ -1900,6 +1945,16 @@ static void bnx2x_bz_fp(struct bnx2x *bp, int index)
 		/* Special queues support only one CoS */
 		fp->max_cos = 1;
 
+	/* Init txdata pointers */
+#ifdef BCM_CNIC
+	if (IS_FCOE_FP(fp))
+		fp->txdata_ptr[0] = &bp->bnx2x_txq[FCOE_TXQ_IDX(bp)];
+#endif
+	if (IS_ETH_FP(fp))
+		for_each_cos_in_tx_queue(fp, cos)
+			fp->txdata_ptr[cos] = &bp->bnx2x_txq[cos *
+				BNX2X_NUM_ETH_QUEUES(bp) + index];
+
 	/*
 	 * set the tpa flag for each queue. The tpa flag determines the queue
 	 * minimal size so it must be set prior to queue memory allocation
@@ -1949,11 +2004,13 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 	/*
 	 * Zero fastpath structures preserving invariants like napi, which are
 	 * allocated only once, fp index, max_cos, bp pointer.
-	 * Also set fp->disable_tpa.
+	 * Also set fp->disable_tpa and txdata_ptr.
 	 */
 	DP(NETIF_MSG_IFUP, "num queues: %d", bp->num_queues);
 	for_each_queue(bp, i)
 		bnx2x_bz_fp(bp, i);
+	memset(bp->bnx2x_txq, 0, bp->bnx2x_txq_size *
+	       sizeof(struct bnx2x_fp_txdata));
 
 
 	/* Set the receive queues buffer size */
@@ -2176,6 +2233,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 		break;
 
 	case LOAD_DIAG:
+	case LOAD_LOOPBACK_EXT:
 		bp->state = BNX2X_STATE_DIAG;
 		break;
 
@@ -2195,6 +2253,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 	/* re-read iscsi info */
 	bnx2x_get_iscsi_info(bp);
 	bnx2x_setup_cnic_irq_info(bp);
+	bnx2x_setup_cnic_info(bp);
 	if (bp->state == BNX2X_STATE_OPEN)
 		bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
 #endif
@@ -2215,7 +2274,10 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 		return -EBUSY;
 	}
 
-	bnx2x_dcbx_init(bp);
+	/* If PMF - send ADMIN DCBX msg to MFW to initiate DCBX FSM */
+	if (bp->port.pmf && (bp->state != BNX2X_STATE_DIAG))
+		bnx2x_dcbx_init(bp, false);
+
 	return 0;
 
 #ifndef BNX2X_STOP_ON_ERROR
@@ -2298,6 +2360,7 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
 
 	/* Stop Tx */
 	bnx2x_tx_disable(bp);
+	netdev_reset_tc(bp->dev);
 
 #ifdef BCM_CNIC
 	bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
@@ -2456,8 +2519,8 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
 #endif
 
 		for_each_cos_in_tx_queue(fp, cos)
-			if (bnx2x_tx_queue_has_work(&fp->txdata[cos]))
-				bnx2x_tx_int(bp, &fp->txdata[cos]);
+			if (bnx2x_tx_queue_has_work(fp->txdata_ptr[cos]))
+				bnx2x_tx_int(bp, fp->txdata_ptr[cos]);
 
 
 		if (bnx2x_has_rx_work(fp)) {
@@ -2516,8 +2579,6 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
 /* 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_fp_txdata *txdata,
@@ -2836,7 +2897,6 @@ 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 bnx2x_fp_txdata *txdata;
 	struct sw_tx_bd *tx_buf;
@@ -2846,7 +2906,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	struct eth_tx_parse_bd_e2 *pbd_e2 = NULL;
 	u32 pbd_e2_parsing_data = 0;
 	u16 pkt_prod, bd_prod;
-	int nbd, txq_index, fp_index, txdata_index;
+	int nbd, txq_index;
 	dma_addr_t mapping;
 	u32 xmit_type = bnx2x_xmit_type(bp, skb);
 	int i;
@@ -2865,31 +2925,12 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	BUG_ON(txq_index >= MAX_ETH_TXQ_IDX(bp) + FCOE_PRESENT);
 
-	/* decode the fastpath index and the cos index from the txq */
-	fp_index = TXQ_TO_FP(txq_index);
-	txdata_index = TXQ_TO_COS(txq_index);
-
-#ifdef BCM_CNIC
-	/*
-	 * Override the above for the FCoE queue:
-	 *   - FCoE fp entry is right after the ETH entries.
-	 *   - FCoE L2 queue uses bp->txdata[0] only.
-	 */
-	if (unlikely(!NO_FCOE(bp) && (txq_index ==
-				      bnx2x_fcoe_tx(bp, txq_index)))) {
-		fp_index = FCOE_IDX;
-		txdata_index = 0;
-	}
-#endif
+	txdata = &bp->bnx2x_txq[txq_index];
 
 	/* enable this debug print to view the transmission queue being used
 	DP(NETIF_MSG_TX_QUEUED, "indices: txq %d, fp %d, txdata %d\n",
 	   txq_index, fp_index, txdata_index); */
 
-	/* locate the fastpath and the txdata */
-	fp = &bp->fp[fp_index];
-	txdata = &fp->txdata[txdata_index];
-
 	/* enable this debug print to view the tranmission details
 	DP(NETIF_MSG_TX_QUEUED,
 	   "transmitting packet cid %d fp index %d txdata_index %d tx_data ptr %p fp pointer %p\n",
@@ -2897,7 +2938,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	if (unlikely(bnx2x_tx_avail(bp, txdata) <
 		     (skb_shinfo(skb)->nr_frags + 3))) {
-		fp->eth_q_stats.driver_xoff++;
+		bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++;
 		netif_tx_stop_queue(txq);
 		BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
 		return NETDEV_TX_BUSY;
@@ -3171,7 +3212,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	txdata->tx_bd_prod += nbd;
 
-	if (unlikely(bnx2x_tx_avail(bp, txdata) < MAX_SKB_FRAGS + 3)) {
+	if (unlikely(bnx2x_tx_avail(bp, txdata) < MAX_SKB_FRAGS + 4)) {
 		netif_tx_stop_queue(txq);
 
 		/* paired memory barrier is in bnx2x_tx_int(), we have to keep
@@ -3179,8 +3220,8 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		 * fp->bd_tx_cons */
 		smp_mb();
 
-		fp->eth_q_stats.driver_xoff++;
-		if (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 3)
+		bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++;
+		if (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 4)
 			netif_tx_wake_queue(txq);
 	}
 	txdata->tx_pkt++;
@@ -3245,7 +3286,7 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
 	/* configure traffic class to transmission queue mapping */
 	for (cos = 0; cos < bp->max_cos; cos++) {
 		count = BNX2X_NUM_ETH_QUEUES(bp);
-		offset = cos * MAX_TXQS_PER_COS;
+		offset = cos * BNX2X_NUM_NON_CNIC_QUEUES(bp);
 		netdev_set_tc_queue(dev, cos, count, offset);
 		DP(BNX2X_MSG_SP | NETIF_MSG_IFUP,
 		   "mapping tc %d to offset %d count %d\n",
@@ -3344,7 +3385,7 @@ static void bnx2x_free_fp_mem_at(struct bnx2x *bp, int fp_index)
 	if (!skip_tx_queue(bp, fp_index)) {
 		/* fastpath tx rings: tx_buf tx_desc */
 		for_each_cos_in_tx_queue(fp, cos) {
-			struct bnx2x_fp_txdata *txdata = &fp->txdata[cos];
+			struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];
 
 			DP(NETIF_MSG_IFDOWN,
 			   "freeing tx memory of fp %d cos %d cid %d\n",
@@ -3416,7 +3457,7 @@ static int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp,
 			       cqe_ring_prod);
 	fp->rx_pkt = fp->rx_calls = 0;
 
-	fp->eth_q_stats.rx_skb_alloc_failed += failure_cnt;
+	bnx2x_fp_stats(bp, fp)->eth_q_stats.rx_skb_alloc_failed += failure_cnt;
 
 	return i - failure_cnt;
 }
@@ -3501,7 +3542,7 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
 	if (!skip_tx_queue(bp, index)) {
 		/* fastpath tx rings: tx_buf tx_desc */
 		for_each_cos_in_tx_queue(fp, cos) {
-			struct bnx2x_fp_txdata *txdata = &fp->txdata[cos];
+			struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];
 
 			DP(NETIF_MSG_IFUP,
 			   "allocating tx memory of fp %d cos %d\n",
@@ -3584,7 +3625,7 @@ int bnx2x_alloc_fp_mem(struct bnx2x *bp)
 #ifdef BCM_CNIC
 	if (!NO_FCOE(bp))
 		/* FCoE */
-		if (bnx2x_alloc_fp_mem_at(bp, FCOE_IDX))
+		if (bnx2x_alloc_fp_mem_at(bp, FCOE_IDX(bp)))
 			/* we will fail load process instead of mark
 			 * NO_FCOE_FLAG
 			 */
@@ -3609,7 +3650,7 @@ int bnx2x_alloc_fp_mem(struct bnx2x *bp)
 		 */
 
 		/* move FCoE fp even NO_FCOE_FLAG is on */
-		bnx2x_move_fp(bp, FCOE_IDX, FCOE_IDX - delta);
+		bnx2x_move_fp(bp, FCOE_IDX(bp), FCOE_IDX(bp) - delta);
 #endif
 		bp->num_queues -= delta;
 		BNX2X_ERR("Adjusted num of queues from %d to %d\n",
@@ -3621,7 +3662,11 @@ int bnx2x_alloc_fp_mem(struct bnx2x *bp)
 
 void bnx2x_free_mem_bp(struct bnx2x *bp)
 {
+	kfree(bp->fp->tpa_info);
 	kfree(bp->fp);
+	kfree(bp->sp_objs);
+	kfree(bp->fp_stats);
+	kfree(bp->bnx2x_txq);
 	kfree(bp->msix_table);
 	kfree(bp->ilt);
 }
@@ -3632,6 +3677,8 @@ int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp)
 	struct msix_entry *tbl;
 	struct bnx2x_ilt *ilt;
 	int msix_table_size = 0;
+	int fp_array_size;
+	int i;
 
 	/*
 	 * The biggest MSI-X table we might need is as a maximum number of fast
@@ -3640,12 +3687,44 @@ int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp)
 	msix_table_size = bp->igu_sb_cnt + 1;
 
 	/* fp array: RSS plus CNIC related L2 queues */
-	fp = kcalloc(BNX2X_MAX_RSS_COUNT(bp) + NON_ETH_CONTEXT_USE,
-		     sizeof(*fp), GFP_KERNEL);
+	fp_array_size = BNX2X_MAX_RSS_COUNT(bp) + NON_ETH_CONTEXT_USE;
+	BNX2X_DEV_INFO("fp_array_size %d", fp_array_size);
+
+	fp = kcalloc(fp_array_size, sizeof(*fp), GFP_KERNEL);
 	if (!fp)
 		goto alloc_err;
+	for (i = 0; i < fp_array_size; i++) {
+		fp[i].tpa_info =
+			kcalloc(ETH_MAX_AGGREGATION_QUEUES_E1H_E2,
+				sizeof(struct bnx2x_agg_info), GFP_KERNEL);
+		if (!(fp[i].tpa_info))
+			goto alloc_err;
+	}
+
 	bp->fp = fp;
 
+	/* allocate sp objs */
+	bp->sp_objs = kcalloc(fp_array_size, sizeof(struct bnx2x_sp_objs),
+			      GFP_KERNEL);
+	if (!bp->sp_objs)
+		goto alloc_err;
+
+	/* allocate fp_stats */
+	bp->fp_stats = kcalloc(fp_array_size, sizeof(struct bnx2x_fp_stats),
+			       GFP_KERNEL);
+	if (!bp->fp_stats)
+		goto alloc_err;
+
+	/* Allocate memory for the transmission queues array */
+	bp->bnx2x_txq_size = BNX2X_MAX_RSS_COUNT(bp) * BNX2X_MULTI_TX_COS;
+#ifdef BCM_CNIC
+	bp->bnx2x_txq_size++;
+#endif
+	bp->bnx2x_txq = kcalloc(bp->bnx2x_txq_size,
+				sizeof(struct bnx2x_fp_txdata), GFP_KERNEL);
+	if (!bp->bnx2x_txq)
+		goto alloc_err;
+
 	/* msix table */
 	tbl = kcalloc(msix_table_size, sizeof(*tbl), GFP_KERNEL);
 	if (!tbl)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 7cd99b7..daa894b 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -29,6 +29,7 @@
 extern int load_count[2][3]; /* per-path: 0-common, 1-port0, 2-port1 */
 
 extern int num_queues;
+extern int int_mode;
 
 /************************ Macros ********************************/
 #define BNX2X_PCI_FREE(x, y, size) \
@@ -94,7 +95,7 @@ void bnx2x_send_unload_done(struct bnx2x *bp);
  * @config_hash:	re-configure RSS hash keys configuration
  */
 int bnx2x_config_rss_pf(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
-			u8 *ind_table, bool config_hash);
+			bool config_hash);
 
 /**
  * bnx2x__init_func_obj - init function object
@@ -244,6 +245,14 @@ int bnx2x_cnic_notify(struct bnx2x *bp, int cmd);
  * @bp:		driver handle
  */
 void bnx2x_setup_cnic_irq_info(struct bnx2x *bp);
+
+/**
+ * bnx2x_setup_cnic_info - provides cnic with updated info
+ *
+ * @bp:		driver handle
+ */
+void bnx2x_setup_cnic_info(struct bnx2x *bp);
+
 #endif
 
 /**
@@ -409,7 +418,7 @@ void bnx2x_ilt_set_info(struct bnx2x *bp);
  *
  * @bp:		driver handle
  */
-void bnx2x_dcbx_init(struct bnx2x *bp);
+void bnx2x_dcbx_init(struct bnx2x *bp, bool update_shmem);
 
 /**
  * bnx2x_set_power_state - set power state to the requested value.
@@ -487,7 +496,7 @@ void bnx2x_netif_start(struct bnx2x *bp);
  * fills msix_table, requests vectors, updates num_queues
  * according to number of available vectors.
  */
-int __devinit bnx2x_enable_msix(struct bnx2x *bp);
+int bnx2x_enable_msix(struct bnx2x *bp);
 
 /**
  * bnx2x_enable_msi - request msi mode from OS, updated internals accordingly
@@ -728,7 +737,7 @@ static inline bool bnx2x_has_tx_work(struct bnx2x_fastpath *fp)
 {
 	u8 cos;
 	for_each_cos_in_tx_queue(fp, cos)
-		if (bnx2x_tx_queue_has_work(&fp->txdata[cos]))
+		if (bnx2x_tx_queue_has_work(fp->txdata_ptr[cos]))
 			return true;
 	return false;
 }
@@ -780,8 +789,10 @@ static inline void bnx2x_add_all_napi(struct bnx2x *bp)
 {
 	int i;
 
+	bp->num_napi_queues = bp->num_queues;
+
 	/* Add NAPI objects */
-	for_each_rx_queue(bp, i)
+	for_each_napi_rx_queue(bp, i)
 		netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
 			       bnx2x_poll, BNX2X_NAPI_WEIGHT);
 }
@@ -790,10 +801,12 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp)
 {
 	int i;
 
-	for_each_rx_queue(bp, i)
+	for_each_napi_rx_queue(bp, i)
 		netif_napi_del(&bnx2x_fp(bp, i, napi));
 }
 
+void bnx2x_set_int_mode(struct bnx2x *bp);
+
 static inline void bnx2x_disable_msi(struct bnx2x *bp)
 {
 	if (bp->flags & USING_MSIX_FLAG) {
@@ -865,11 +878,9 @@ static inline int func_by_vn(struct bnx2x *bp, int vn)
 	return 2 * vn + BP_PORT(bp);
 }
 
-static inline int bnx2x_config_rss_eth(struct bnx2x *bp, u8 *ind_table,
-				       bool config_hash)
+static inline int bnx2x_config_rss_eth(struct bnx2x *bp, bool config_hash)
 {
-	return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, ind_table,
-				   config_hash);
+	return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, config_hash);
 }
 
 /**
@@ -975,8 +986,8 @@ static inline void bnx2x_init_vlan_mac_fp_objs(struct bnx2x_fastpath *fp,
 	struct bnx2x *bp = fp->bp;
 
 	/* Configure classification DBs */
-	bnx2x_init_mac_obj(bp, &fp->mac_obj, fp->cl_id, fp->cid,
-			   BP_FUNC(bp), bnx2x_sp(bp, mac_rdata),
+	bnx2x_init_mac_obj(bp, &bnx2x_sp_obj(bp, fp).mac_obj, fp->cl_id,
+			   fp->cid, BP_FUNC(bp), bnx2x_sp(bp, mac_rdata),
 			   bnx2x_sp_mapping(bp, mac_rdata),
 			   BNX2X_FILTER_MAC_PENDING,
 			   &bp->sp_state, obj_type,
@@ -1068,12 +1079,14 @@ static inline u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
 }
 
 static inline void bnx2x_init_txdata(struct bnx2x *bp,
-	struct bnx2x_fp_txdata *txdata, u32 cid, int txq_index,
-	__le16 *tx_cons_sb)
+				     struct bnx2x_fp_txdata *txdata, u32 cid,
+				     int txq_index, __le16 *tx_cons_sb,
+				     struct bnx2x_fastpath *fp)
 {
 	txdata->cid = cid;
 	txdata->txq_index = txq_index;
 	txdata->tx_cons_sb = tx_cons_sb;
+	txdata->parent_fp = fp;
 
 	DP(NETIF_MSG_IFUP, "created tx data cid %d, txq %d\n",
 	   txdata->cid, txdata->txq_index);
@@ -1107,18 +1120,13 @@ static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp)
 	bnx2x_fcoe(bp, rx_queue) = BNX2X_NUM_ETH_QUEUES(bp);
 	bnx2x_fcoe(bp, cl_id) = bnx2x_cnic_eth_cl_id(bp,
 						     BNX2X_FCOE_ETH_CL_ID_IDX);
-	/** Current BNX2X_FCOE_ETH_CID deffinition implies not more than
-	 *  16 ETH clients per function when CNIC is enabled!
-	 *
-	 *  Fix it ASAP!!!
-	 */
-	bnx2x_fcoe(bp, cid) = BNX2X_FCOE_ETH_CID;
+	bnx2x_fcoe(bp, cid) = BNX2X_FCOE_ETH_CID(bp);
 	bnx2x_fcoe(bp, fw_sb_id) = DEF_SB_ID;
 	bnx2x_fcoe(bp, igu_sb_id) = bp->igu_dsb_id;
 	bnx2x_fcoe(bp, rx_cons_sb) = BNX2X_FCOE_L2_RX_INDEX;
-
-	bnx2x_init_txdata(bp, &bnx2x_fcoe(bp, txdata[0]),
-			  fp->cid, FCOE_TXQ_IDX(bp), BNX2X_FCOE_L2_TX_INDEX);
+	bnx2x_init_txdata(bp, bnx2x_fcoe(bp, txdata_ptr[0]),
+			  fp->cid, FCOE_TXQ_IDX(bp), BNX2X_FCOE_L2_TX_INDEX,
+			  fp);
 
 	DP(NETIF_MSG_IFUP, "created fcoe tx data (fp index %d)\n", fp->index);
 
@@ -1135,8 +1143,8 @@ static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp)
 	/* No multi-CoS for FCoE L2 client */
 	BUG_ON(fp->max_cos != 1);
 
-	bnx2x_init_queue_obj(bp, &fp->q_obj, fp->cl_id, &fp->cid, 1,
-			     BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
+	bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id,
+			     &fp->cid, 1, BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
 			     bnx2x_sp_mapping(bp, q_rdata), q_type);
 
 	DP(NETIF_MSG_IFUP,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index 4f9244b..8a73374 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -972,23 +972,26 @@ void bnx2x_dcbx_init_params(struct bnx2x *bp)
 	bp->dcbx_config_params.admin_default_priority = 0;
 }
 
-void bnx2x_dcbx_init(struct bnx2x *bp)
+void bnx2x_dcbx_init(struct bnx2x *bp, bool update_shmem)
 {
 	u32 dcbx_lldp_params_offset = SHMEM_LLDP_DCBX_PARAMS_NONE;
 
+	/* only PMF can send ADMIN msg to MFW in old MFW versions */
+	if ((!bp->port.pmf) && (!(bp->flags & BC_SUPPORTS_DCBX_MSG_NON_PMF)))
+		return;
+
 	if (bp->dcbx_enabled <= 0)
 		return;
 
 	/* validate:
 	 * chip of good for dcbx version,
 	 * dcb is wanted
-	 * the function is pmf
 	 * shmem2 contains DCBX support fields
 	 */
 	DP(BNX2X_MSG_DCB, "dcb_state %d bp->port.pmf %d\n",
 	   bp->dcb_state, bp->port.pmf);
 
-	if (bp->dcb_state == BNX2X_DCB_STATE_ON && bp->port.pmf &&
+	if (bp->dcb_state == BNX2X_DCB_STATE_ON &&
 	    SHMEM2_HAS(bp, dcbx_lldp_params_offset)) {
 		dcbx_lldp_params_offset =
 			SHMEM2_RD(bp, dcbx_lldp_params_offset);
@@ -999,12 +1002,23 @@ void bnx2x_dcbx_init(struct bnx2x *bp)
 		bnx2x_update_drv_flags(bp, 1 << DRV_FLAGS_DCB_CONFIGURED, 0);
 
 		if (SHMEM_LLDP_DCBX_PARAMS_NONE != dcbx_lldp_params_offset) {
-			bnx2x_dcbx_admin_mib_updated_params(bp,
-				dcbx_lldp_params_offset);
+			/* need HW lock to avoid scenario of two drivers
+			 * writing in parallel to shmem
+			 */
+			bnx2x_acquire_hw_lock(bp,
+					      HW_LOCK_RESOURCE_DCBX_ADMIN_MIB);
+			if (update_shmem)
+				bnx2x_dcbx_admin_mib_updated_params(bp,
+					dcbx_lldp_params_offset);
 
 			/* Let HW start negotiation */
 			bnx2x_fw_command(bp,
 					 DRV_MSG_CODE_DCBX_ADMIN_PMF_MSG, 0);
+			/* release HW lock only after MFW acks that it finished
+			 * reading values from shmem
+			 */
+			bnx2x_release_hw_lock(bp,
+					      HW_LOCK_RESOURCE_DCBX_ADMIN_MIB);
 		}
 	}
 }
@@ -2063,10 +2077,8 @@ static u8 bnx2x_dcbnl_set_all(struct net_device *netdev)
 			   "Handling parity error recovery. Try again later\n");
 		return 1;
 	}
-	if (netif_running(bp->dev)) {
-		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
-		rc = bnx2x_nic_load(bp, LOAD_NORMAL);
-	}
+	if (netif_running(bp->dev))
+		bnx2x_dcbx_init(bp, true);
 	DP(BNX2X_MSG_DCB, "set_dcbx_params done (%d)\n", rc);
 	if (rc)
 		return 1;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index ddc18ee..1f8c156 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -177,6 +177,8 @@ static const struct {
 			4, STATS_FLAGS_FUNC, "recoverable_errors" },
 	{ STATS_OFFSET32(unrecoverable_error),
 			4, STATS_FLAGS_FUNC, "unrecoverable_errors" },
+	{ STATS_OFFSET32(eee_tx_lpi),
+			4, STATS_FLAGS_PORT, "Tx LPI entry count"}
 };
 
 #define BNX2X_NUM_STATS		ARRAY_SIZE(bnx2x_stats_arr)
@@ -185,7 +187,8 @@ static int bnx2x_get_port_type(struct bnx2x *bp)
 	int port_type;
 	u32 phy_idx = bnx2x_get_cur_phy_idx(bp);
 	switch (bp->link_params.phy[phy_idx].media_type) {
-	case ETH_PHY_SFP_FIBER:
+	case ETH_PHY_SFPP_10G_FIBER:
+	case ETH_PHY_SFP_1G_FIBER:
 	case ETH_PHY_XFP_FIBER:
 	case ETH_PHY_KR:
 	case ETH_PHY_CX4:
@@ -218,6 +221,11 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 		(bp->port.supported[cfg_idx ^ 1] &
 		 (SUPPORTED_TP | SUPPORTED_FIBRE));
 	cmd->advertising = bp->port.advertising[cfg_idx];
+	if (bp->link_params.phy[bnx2x_get_cur_phy_idx(bp)].media_type ==
+	    ETH_PHY_SFP_1G_FIBER) {
+		cmd->supported &= ~(SUPPORTED_10000baseT_Full);
+		cmd->advertising &= ~(ADVERTISED_10000baseT_Full);
+	}
 
 	if ((bp->state == BNX2X_STATE_OPEN) && (bp->link_vars.link_up)) {
 		if (!(bp->flags & MF_FUNC_DIS)) {
@@ -293,7 +301,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct bnx2x *bp = netdev_priv(dev);
 	u32 advertising, cfg_idx, old_multi_phy_config, new_multi_phy_config;
-	u32 speed;
+	u32 speed, phy_idx;
 
 	if (IS_MF_SD(bp))
 		return 0;
@@ -548,9 +556,11 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 				   "10G half not supported\n");
 				return -EINVAL;
 			}
-
+			phy_idx = bnx2x_get_cur_phy_idx(bp);
 			if (!(bp->port.supported[cfg_idx]
-			      & SUPPORTED_10000baseT_Full)) {
+			      & SUPPORTED_10000baseT_Full) ||
+			    (bp->link_params.phy[phy_idx].media_type ==
+			     ETH_PHY_SFP_1G_FIBER)) {
 				DP(BNX2X_MSG_ETHTOOL,
 				   "10G full not supported\n");
 				return -EINVAL;
@@ -824,7 +834,7 @@ static void bnx2x_get_drvinfo(struct net_device *dev,
 		 ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
 	strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
 	info->n_stats = BNX2X_NUM_STATS;
-	info->testinfo_len = BNX2X_NUM_TESTS;
+	info->testinfo_len = BNX2X_NUM_TESTS(bp);
 	info->eedump_len = bp->common.flash_size;
 	info->regdump_len = bnx2x_get_regs_len(dev);
 }
@@ -1150,6 +1160,65 @@ static int bnx2x_get_eeprom(struct net_device *dev,
 	return rc;
 }
 
+static int bnx2x_get_module_eeprom(struct net_device *dev,
+				   struct ethtool_eeprom *ee,
+				   u8 *data)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int rc = 0, phy_idx;
+	u8 *user_data = data;
+	int remaining_len = ee->len, xfer_size;
+	unsigned int page_off = ee->offset;
+
+	if (!netif_running(dev)) {
+		DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
+		   "cannot access eeprom when the interface is down\n");
+		return -EAGAIN;
+	}
+
+	phy_idx = bnx2x_get_cur_phy_idx(bp);
+	bnx2x_acquire_phy_lock(bp);
+	while (!rc && remaining_len > 0) {
+		xfer_size = (remaining_len > SFP_EEPROM_PAGE_SIZE) ?
+			SFP_EEPROM_PAGE_SIZE : remaining_len;
+		rc = bnx2x_read_sfp_module_eeprom(&bp->link_params.phy[phy_idx],
+						  &bp->link_params,
+						  page_off,
+						  xfer_size,
+						  user_data);
+		remaining_len -= xfer_size;
+		user_data += xfer_size;
+		page_off += xfer_size;
+	}
+
+	bnx2x_release_phy_lock(bp);
+	return rc;
+}
+
+static int bnx2x_get_module_info(struct net_device *dev,
+				 struct ethtool_modinfo *modinfo)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int phy_idx;
+	if (!netif_running(dev)) {
+		DP(BNX2X_MSG_ETHTOOL  | BNX2X_MSG_NVM,
+		   "cannot access eeprom when the interface is down\n");
+		return -EAGAIN;
+	}
+
+	phy_idx = bnx2x_get_cur_phy_idx(bp);
+	switch (bp->link_params.phy[phy_idx].media_type) {
+	case ETH_PHY_SFPP_10G_FIBER:
+	case ETH_PHY_SFP_1G_FIBER:
+	case ETH_PHY_DA_TWINAX:
+		modinfo->type = ETH_MODULE_SFF_8079;
+		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val,
 				   u32 cmd_flags)
 {
@@ -1531,18 +1600,146 @@ static int bnx2x_set_pauseparam(struct net_device *dev,
 	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)" }
+char *bnx2x_tests_str_arr[BNX2X_NUM_TESTS_SF] = {
+	"register_test (offline)    ",
+	"memory_test (offline)      ",
+	"int_loopback_test (offline)",
+	"ext_loopback_test (offline)",
+	"nvram_test (online)        ",
+	"interrupt_test (online)    ",
+	"link_test (online)         "
 };
 
+static u32 bnx2x_eee_to_adv(u32 eee_adv)
+{
+	u32 modes = 0;
+
+	if (eee_adv & SHMEM_EEE_100M_ADV)
+		modes |= ADVERTISED_100baseT_Full;
+	if (eee_adv & SHMEM_EEE_1G_ADV)
+		modes |= ADVERTISED_1000baseT_Full;
+	if (eee_adv & SHMEM_EEE_10G_ADV)
+		modes |= ADVERTISED_10000baseT_Full;
+
+	return modes;
+}
+
+static u32 bnx2x_adv_to_eee(u32 modes, u32 shift)
+{
+	u32 eee_adv = 0;
+	if (modes & ADVERTISED_100baseT_Full)
+		eee_adv |= SHMEM_EEE_100M_ADV;
+	if (modes & ADVERTISED_1000baseT_Full)
+		eee_adv |= SHMEM_EEE_1G_ADV;
+	if (modes & ADVERTISED_10000baseT_Full)
+		eee_adv |= SHMEM_EEE_10G_ADV;
+
+	return eee_adv << shift;
+}
+
+static int bnx2x_get_eee(struct net_device *dev, struct ethtool_eee *edata)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	u32 eee_cfg;
+
+	if (!SHMEM2_HAS(bp, eee_status[BP_PORT(bp)])) {
+		DP(BNX2X_MSG_ETHTOOL, "BC Version does not support EEE\n");
+		return -EOPNOTSUPP;
+	}
+
+	eee_cfg = SHMEM2_RD(bp, eee_status[BP_PORT(bp)]);
+
+	edata->supported =
+		bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_SUPPORTED_MASK) >>
+				 SHMEM_EEE_SUPPORTED_SHIFT);
+
+	edata->advertised =
+		bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_ADV_STATUS_MASK) >>
+				 SHMEM_EEE_ADV_STATUS_SHIFT);
+	edata->lp_advertised =
+		bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_LP_ADV_STATUS_MASK) >>
+				 SHMEM_EEE_LP_ADV_STATUS_SHIFT);
+
+	/* SHMEM value is in 16u units --> Convert to 1u units. */
+	edata->tx_lpi_timer = (eee_cfg & SHMEM_EEE_TIMER_MASK) << 4;
+
+	edata->eee_enabled    = (eee_cfg & SHMEM_EEE_REQUESTED_BIT)	? 1 : 0;
+	edata->eee_active     = (eee_cfg & SHMEM_EEE_ACTIVE_BIT)	? 1 : 0;
+	edata->tx_lpi_enabled = (eee_cfg & SHMEM_EEE_LPI_REQUESTED_BIT) ? 1 : 0;
+
+	return 0;
+}
+
+static int bnx2x_set_eee(struct net_device *dev, struct ethtool_eee *edata)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	u32 eee_cfg;
+	u32 advertised;
+
+	if (IS_MF(bp))
+		return 0;
+
+	if (!SHMEM2_HAS(bp, eee_status[BP_PORT(bp)])) {
+		DP(BNX2X_MSG_ETHTOOL, "BC Version does not support EEE\n");
+		return -EOPNOTSUPP;
+	}
+
+	eee_cfg = SHMEM2_RD(bp, eee_status[BP_PORT(bp)]);
+
+	if (!(eee_cfg & SHMEM_EEE_SUPPORTED_MASK)) {
+		DP(BNX2X_MSG_ETHTOOL, "Board does not support EEE!\n");
+		return -EOPNOTSUPP;
+	}
+
+	advertised = bnx2x_adv_to_eee(edata->advertised,
+				      SHMEM_EEE_ADV_STATUS_SHIFT);
+	if ((advertised != (eee_cfg & SHMEM_EEE_ADV_STATUS_MASK))) {
+		DP(BNX2X_MSG_ETHTOOL,
+		   "Direct manipulation of EEE advertisment is not supported\n");
+		return -EINVAL;
+	}
+
+	if (edata->tx_lpi_timer > EEE_MODE_TIMER_MASK) {
+		DP(BNX2X_MSG_ETHTOOL,
+		   "Maximal Tx Lpi timer supported is %x(u)\n",
+		   EEE_MODE_TIMER_MASK);
+		return -EINVAL;
+	}
+	if (edata->tx_lpi_enabled &&
+	    (edata->tx_lpi_timer < EEE_MODE_NVRAM_AGGRESSIVE_TIME)) {
+		DP(BNX2X_MSG_ETHTOOL,
+		   "Minimal Tx Lpi timer supported is %d(u)\n",
+		   EEE_MODE_NVRAM_AGGRESSIVE_TIME);
+		return -EINVAL;
+	}
+
+	/* All is well; Apply changes*/
+	if (edata->eee_enabled)
+		bp->link_params.eee_mode |= EEE_MODE_ADV_LPI;
+	else
+		bp->link_params.eee_mode &= ~EEE_MODE_ADV_LPI;
+
+	if (edata->tx_lpi_enabled)
+		bp->link_params.eee_mode |= EEE_MODE_ENABLE_LPI;
+	else
+		bp->link_params.eee_mode &= ~EEE_MODE_ENABLE_LPI;
+
+	bp->link_params.eee_mode &= ~EEE_MODE_TIMER_MASK;
+	bp->link_params.eee_mode |= (edata->tx_lpi_timer &
+				    EEE_MODE_TIMER_MASK) |
+				    EEE_MODE_OVERRIDE_NVRAM |
+				    EEE_MODE_OUTPUT_TIME;
+
+	/* Restart link to propogate changes */
+	if (netif_running(dev)) {
+		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+		bnx2x_link_set(bp);
+	}
+
+	return 0;
+}
+
+
 enum {
 	BNX2X_CHIP_E1_OFST = 0,
 	BNX2X_CHIP_E1H_OFST,
@@ -1811,6 +2008,14 @@ static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up, u8 is_serdes)
 
 		if (cnt <= 0 && bnx2x_link_test(bp, is_serdes))
 			DP(BNX2X_MSG_ETHTOOL, "Timeout waiting for link up\n");
+
+		cnt = 1400;
+		while (!bp->link_vars.link_up && cnt--)
+			msleep(20);
+
+		if (cnt <= 0 && !bp->link_vars.link_up)
+			DP(BNX2X_MSG_ETHTOOL,
+			   "Timeout waiting for link init\n");
 	}
 }
 
@@ -1821,7 +2026,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode)
 	unsigned char *packet;
 	struct bnx2x_fastpath *fp_rx = &bp->fp[0];
 	struct bnx2x_fastpath *fp_tx = &bp->fp[0];
-	struct bnx2x_fp_txdata *txdata = &fp_tx->txdata[0];
+	struct bnx2x_fp_txdata *txdata = fp_tx->txdata_ptr[0];
 	u16 tx_start_idx, tx_idx;
 	u16 rx_start_idx, rx_idx;
 	u16 pkt_prod, bd_prod;
@@ -1836,13 +2041,16 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode)
 	u16 len;
 	int rc = -ENODEV;
 	u8 *data;
-	struct netdev_queue *txq = netdev_get_tx_queue(bp->dev, txdata->txq_index);
+	struct netdev_queue *txq = netdev_get_tx_queue(bp->dev,
+						       txdata->txq_index);
 
 	/* check the loopback mode */
 	switch (loopback_mode) {
 	case BNX2X_PHY_LOOPBACK:
-		if (bp->link_params.loopback_mode != LOOPBACK_XGXS)
+		if (bp->link_params.loopback_mode != LOOPBACK_XGXS) {
+			DP(BNX2X_MSG_ETHTOOL, "PHY loopback not supported\n");
 			return -EINVAL;
+		}
 		break;
 	case BNX2X_MAC_LOOPBACK:
 		if (CHIP_IS_E3(bp)) {
@@ -1859,6 +2067,13 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode)
 
 		bnx2x_phy_init(&bp->link_params, &bp->link_vars);
 		break;
+	case BNX2X_EXT_LOOPBACK:
+		if (bp->link_params.loopback_mode != LOOPBACK_EXT) {
+			DP(BNX2X_MSG_ETHTOOL,
+			   "Can't configure external loopback\n");
+			return -EINVAL;
+		}
+		break;
 	default:
 		DP(BNX2X_MSG_ETHTOOL, "Command parameters not supported\n");
 		return -EINVAL;
@@ -2030,6 +2245,38 @@ static int bnx2x_test_loopback(struct bnx2x *bp)
 	return rc;
 }
 
+static int bnx2x_test_ext_loopback(struct bnx2x *bp)
+{
+	int rc;
+	u8 is_serdes =
+		(bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) > 0;
+
+	if (BP_NOMCP(bp))
+		return -ENODEV;
+
+	if (!netif_running(bp->dev))
+		return BNX2X_EXT_LOOPBACK_FAILED;
+
+	bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+	rc = bnx2x_nic_load(bp, LOAD_LOOPBACK_EXT);
+	if (rc) {
+		DP(BNX2X_MSG_ETHTOOL,
+		   "Can't perform self-test, nic_load (for external lb) failed\n");
+		return -ENODEV;
+	}
+	bnx2x_wait_for_link(bp, 1, is_serdes);
+
+	bnx2x_netif_stop(bp, 1);
+
+	rc = bnx2x_run_loopback(bp, BNX2X_EXT_LOOPBACK);
+	if (rc)
+		DP(BNX2X_MSG_ETHTOOL, "EXT loopback failed  (res %d)\n", rc);
+
+	bnx2x_netif_start(bp);
+
+	return rc;
+}
+
 #define CRC32_RESIDUAL			0xdebb20e3
 
 static int bnx2x_test_nvram(struct bnx2x *bp)
@@ -2112,7 +2359,7 @@ static int bnx2x_test_intr(struct bnx2x *bp)
 		return -ENODEV;
 	}
 
-	params.q_obj = &bp->fp->q_obj;
+	params.q_obj = &bp->sp_objs->q_obj;
 	params.cmd = BNX2X_Q_CMD_EMPTY;
 
 	__set_bit(RAMROD_COMP_WAIT, &params.ramrod_flags);
@@ -2125,24 +2372,31 @@ static void bnx2x_self_test(struct net_device *dev,
 {
 	struct bnx2x *bp = netdev_priv(dev);
 	u8 is_serdes;
+	int rc;
+
 	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
 		netdev_err(bp->dev,
 			   "Handling parity error recovery. Try again later\n");
 		etest->flags |= ETH_TEST_FL_FAILED;
 		return;
 	}
+	DP(BNX2X_MSG_ETHTOOL,
+	   "Self-test command parameters: offline = %d, external_lb = %d\n",
+	   (etest->flags & ETH_TEST_FL_OFFLINE),
+	   (etest->flags & ETH_TEST_FL_EXTERNAL_LB)>>2);
 
-	memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS);
+	memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS(bp));
 
-	if (!netif_running(dev))
+	if (!netif_running(dev)) {
+		DP(BNX2X_MSG_ETHTOOL,
+		   "Can't perform self-test when interface is down\n");
 		return;
+	}
 
-	/* offline tests are not supported in MF mode */
-	if (IS_MF(bp))
-		etest->flags &= ~ETH_TEST_FL_OFFLINE;
 	is_serdes = (bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) > 0;
 
-	if (etest->flags & ETH_TEST_FL_OFFLINE) {
+	/* offline tests are not supported in MF mode */
+	if ((etest->flags & ETH_TEST_FL_OFFLINE) && !IS_MF(bp)) {
 		int port = BP_PORT(bp);
 		u32 val;
 		u8 link_up;
@@ -2155,7 +2409,14 @@ static void bnx2x_self_test(struct net_device *dev,
 		link_up = bp->link_vars.link_up;
 
 		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
-		bnx2x_nic_load(bp, LOAD_DIAG);
+		rc = bnx2x_nic_load(bp, LOAD_DIAG);
+		if (rc) {
+			etest->flags |= ETH_TEST_FL_FAILED;
+			DP(BNX2X_MSG_ETHTOOL,
+			   "Can't perform self-test, nic_load (for offline) failed\n");
+			return;
+		}
+
 		/* wait until link state is restored */
 		bnx2x_wait_for_link(bp, 1, is_serdes);
 
@@ -2168,30 +2429,51 @@ static void bnx2x_self_test(struct net_device *dev,
 			etest->flags |= ETH_TEST_FL_FAILED;
 		}
 
-		buf[2] = bnx2x_test_loopback(bp);
+		buf[2] = bnx2x_test_loopback(bp); /* internal LB */
 		if (buf[2] != 0)
 			etest->flags |= ETH_TEST_FL_FAILED;
 
+		if (etest->flags & ETH_TEST_FL_EXTERNAL_LB) {
+			buf[3] = bnx2x_test_ext_loopback(bp); /* external LB */
+			if (buf[3] != 0)
+				etest->flags |= ETH_TEST_FL_FAILED;
+			etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
+		}
+
 		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);
+		rc = bnx2x_nic_load(bp, LOAD_NORMAL);
+		if (rc) {
+			etest->flags |= ETH_TEST_FL_FAILED;
+			DP(BNX2X_MSG_ETHTOOL,
+			   "Can't perform self-test, nic_load (for online) failed\n");
+			return;
+		}
 		/* wait until link state is restored */
 		bnx2x_wait_for_link(bp, link_up, is_serdes);
 	}
 	if (bnx2x_test_nvram(bp) != 0) {
-		buf[3] = 1;
+		if (!IS_MF(bp))
+			buf[4] = 1;
+		else
+			buf[0] = 1;
 		etest->flags |= ETH_TEST_FL_FAILED;
 	}
 	if (bnx2x_test_intr(bp) != 0) {
-		buf[4] = 1;
+		if (!IS_MF(bp))
+			buf[5] = 1;
+		else
+			buf[1] = 1;
 		etest->flags |= ETH_TEST_FL_FAILED;
 	}
 
 	if (bnx2x_link_test(bp, is_serdes) != 0) {
-		buf[5] = 1;
+		if (!IS_MF(bp))
+			buf[6] = 1;
+		else
+			buf[2] = 1;
 		etest->flags |= ETH_TEST_FL_FAILED;
 	}
 
@@ -2236,7 +2518,7 @@ static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
 		return num_stats;
 
 	case ETH_SS_TEST:
-		return BNX2X_NUM_TESTS;
+		return BNX2X_NUM_TESTS(bp);
 
 	default:
 		return -EINVAL;
@@ -2246,7 +2528,7 @@ static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
 static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
 {
 	struct bnx2x *bp = netdev_priv(dev);
-	int i, j, k;
+	int i, j, k, offset, start;
 	char queue_name[MAX_QUEUE_NAME_LEN+1];
 
 	switch (stringset) {
@@ -2277,7 +2559,17 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
 		break;
 
 	case ETH_SS_TEST:
-		memcpy(buf, bnx2x_tests_str_arr, sizeof(bnx2x_tests_str_arr));
+		/* First 4 tests cannot be done in MF mode */
+		if (!IS_MF(bp))
+			start = 0;
+		else
+			start = 4;
+		for (i = 0, j = start; j < (start + BNX2X_NUM_TESTS(bp));
+		     i++, j++) {
+			offset = sprintf(buf+32*i, "%s",
+					 bnx2x_tests_str_arr[j]);
+			*(buf+offset) = '\0';
+		}
 		break;
 	}
 }
@@ -2291,7 +2583,7 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev,
 
 	if (is_multi(bp)) {
 		for_each_eth_queue(bp, i) {
-			hw_stats = (u32 *)&bp->fp[i].eth_q_stats;
+			hw_stats = (u32 *)&bp->fp_stats[i].eth_q_stats;
 			for (j = 0; j < BNX2X_NUM_Q_STATS; j++) {
 				if (bnx2x_q_stats_arr[j].size == 0) {
 					/* skip this counter */
@@ -2375,6 +2667,41 @@ static int bnx2x_set_phys_id(struct net_device *dev,
 	return 0;
 }
 
+static int bnx2x_get_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
+{
+
+	switch (info->flow_type) {
+	case TCP_V4_FLOW:
+	case TCP_V6_FLOW:
+		info->data = RXH_IP_SRC | RXH_IP_DST |
+			     RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		break;
+	case UDP_V4_FLOW:
+		if (bp->rss_conf_obj.udp_rss_v4)
+			info->data = RXH_IP_SRC | RXH_IP_DST |
+				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		else
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+		break;
+	case UDP_V6_FLOW:
+		if (bp->rss_conf_obj.udp_rss_v6)
+			info->data = RXH_IP_SRC | RXH_IP_DST |
+				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		else
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+		break;
+	case IPV4_FLOW:
+	case IPV6_FLOW:
+		info->data = RXH_IP_SRC | RXH_IP_DST;
+		break;
+	default:
+		info->data = 0;
+		break;
+	}
+
+	return 0;
+}
+
 static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
 			   u32 *rules __always_unused)
 {
@@ -2384,7 +2711,102 @@ static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
 	case ETHTOOL_GRXRINGS:
 		info->data = BNX2X_NUM_ETH_QUEUES(bp);
 		return 0;
+	case ETHTOOL_GRXFH:
+		return bnx2x_get_rss_flags(bp, info);
+	default:
+		DP(BNX2X_MSG_ETHTOOL, "Command parameters not supported\n");
+		return -EOPNOTSUPP;
+	}
+}
+
+static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
+{
+	int udp_rss_requested;
+
+	DP(BNX2X_MSG_ETHTOOL,
+	   "Set rss flags command parameters: flow type = %d, data = %llu\n",
+	   info->flow_type, info->data);
+
+	switch (info->flow_type) {
+	case TCP_V4_FLOW:
+	case TCP_V6_FLOW:
+		/* For TCP only 4-tupple hash is supported */
+		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST |
+				  RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+			DP(BNX2X_MSG_ETHTOOL,
+			   "Command parameters not supported\n");
+			return -EINVAL;
+		} else {
+			return 0;
+		}
 
+	case UDP_V4_FLOW:
+	case UDP_V6_FLOW:
+		/* For UDP either 2-tupple hash or 4-tupple hash is supported */
+		if (info->data == (RXH_IP_SRC | RXH_IP_DST |
+				 RXH_L4_B_0_1 | RXH_L4_B_2_3))
+			udp_rss_requested = 1;
+		else if (info->data == (RXH_IP_SRC | RXH_IP_DST))
+			udp_rss_requested = 0;
+		else
+			return -EINVAL;
+		if ((info->flow_type == UDP_V4_FLOW) &&
+		    (bp->rss_conf_obj.udp_rss_v4 != udp_rss_requested)) {
+			bp->rss_conf_obj.udp_rss_v4 = udp_rss_requested;
+			DP(BNX2X_MSG_ETHTOOL,
+			   "rss re-configured, UDP 4-tupple %s\n",
+			   udp_rss_requested ? "enabled" : "disabled");
+			return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0);
+		} else if ((info->flow_type == UDP_V6_FLOW) &&
+			   (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) {
+			bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested;
+			return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0);
+			DP(BNX2X_MSG_ETHTOOL,
+			   "rss re-configured, UDP 4-tupple %s\n",
+			   udp_rss_requested ? "enabled" : "disabled");
+		} else {
+			return 0;
+		}
+	case IPV4_FLOW:
+	case IPV6_FLOW:
+		/* For IP only 2-tupple hash is supported */
+		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) {
+			DP(BNX2X_MSG_ETHTOOL,
+			   "Command parameters not supported\n");
+			return -EINVAL;
+		} else {
+			return 0;
+		}
+	case SCTP_V4_FLOW:
+	case AH_ESP_V4_FLOW:
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+	case SCTP_V6_FLOW:
+	case AH_ESP_V6_FLOW:
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+	case IP_USER_FLOW:
+	case ETHER_FLOW:
+		/* RSS is not supported for these protocols */
+		if (info->data) {
+			DP(BNX2X_MSG_ETHTOOL,
+			   "Command parameters not supported\n");
+			return -EINVAL;
+		} else {
+			return 0;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int bnx2x_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	switch (info->cmd) {
+	case ETHTOOL_SRXFH:
+		return bnx2x_set_rss_flags(bp, info);
 	default:
 		DP(BNX2X_MSG_ETHTOOL, "Command parameters not supported\n");
 		return -EOPNOTSUPP;
@@ -2424,7 +2846,6 @@ static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir)
 {
 	struct bnx2x *bp = netdev_priv(dev);
 	size_t i;
-	u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};
 
 	for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) {
 		/*
@@ -2436,10 +2857,88 @@ static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir)
 		 * align the received table to the Client ID of the leading RSS
 		 * queue
 		 */
-		ind_table[i] = indir[i] + bp->fp->cl_id;
+		bp->rss_conf_obj.ind_table[i] = indir[i] + bp->fp->cl_id;
 	}
 
-	return bnx2x_config_rss_eth(bp, ind_table, false);
+	return bnx2x_config_rss_eth(bp, false);
+}
+
+/**
+ * bnx2x_get_channels - gets the number of RSS queues.
+ *
+ * @dev:		net device
+ * @channels:		returns the number of max / current queues
+ */
+static void bnx2x_get_channels(struct net_device *dev,
+			       struct ethtool_channels *channels)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	channels->max_combined = BNX2X_MAX_RSS_COUNT(bp);
+	channels->combined_count = BNX2X_NUM_ETH_QUEUES(bp);
+}
+
+/**
+ * bnx2x_change_num_queues - change the number of RSS queues.
+ *
+ * @bp:			bnx2x private structure
+ *
+ * Re-configure interrupt mode to get the new number of MSI-X
+ * vectors and re-add NAPI objects.
+ */
+static void bnx2x_change_num_queues(struct bnx2x *bp, int num_rss)
+{
+	bnx2x_del_all_napi(bp);
+	bnx2x_disable_msi(bp);
+	BNX2X_NUM_QUEUES(bp) = num_rss + NON_ETH_CONTEXT_USE;
+	bnx2x_set_int_mode(bp);
+	bnx2x_add_all_napi(bp);
+}
+
+/**
+ * bnx2x_set_channels - sets the number of RSS queues.
+ *
+ * @dev:		net device
+ * @channels:		includes the number of queues requested
+ */
+static int bnx2x_set_channels(struct net_device *dev,
+			      struct ethtool_channels *channels)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+
+	DP(BNX2X_MSG_ETHTOOL,
+	   "set-channels command parameters: rx = %d, tx = %d, other = %d, combined = %d\n",
+	   channels->rx_count, channels->tx_count, channels->other_count,
+	   channels->combined_count);
+
+	/* We don't support separate rx / tx channels.
+	 * We don't allow setting 'other' channels.
+	 */
+	if (channels->rx_count || channels->tx_count || channels->other_count
+	    || (channels->combined_count == 0) ||
+	    (channels->combined_count > BNX2X_MAX_RSS_COUNT(bp))) {
+		DP(BNX2X_MSG_ETHTOOL, "command parameters not supported\n");
+		return -EINVAL;
+	}
+
+	/* Check if there was a change in the active parameters */
+	if (channels->combined_count == BNX2X_NUM_ETH_QUEUES(bp)) {
+		DP(BNX2X_MSG_ETHTOOL, "No change in active parameters\n");
+		return 0;
+	}
+
+	/* Set the requested number of queues in bp context.
+	 * Note that the actual number of queues created during load may be
+	 * less than requested if memory is low.
+	 */
+	if (unlikely(!netif_running(dev))) {
+		bnx2x_change_num_queues(bp, channels->combined_count);
+		return 0;
+	}
+	bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+	bnx2x_change_num_queues(bp, channels->combined_count);
+	return bnx2x_nic_load(bp, LOAD_NORMAL);
 }
 
 static const struct ethtool_ops bnx2x_ethtool_ops = {
@@ -2469,9 +2968,16 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
 	.set_phys_id		= bnx2x_set_phys_id,
 	.get_ethtool_stats	= bnx2x_get_ethtool_stats,
 	.get_rxnfc		= bnx2x_get_rxnfc,
+	.set_rxnfc		= bnx2x_set_rxnfc,
 	.get_rxfh_indir_size	= bnx2x_get_rxfh_indir_size,
 	.get_rxfh_indir		= bnx2x_get_rxfh_indir,
 	.set_rxfh_indir		= bnx2x_set_rxfh_indir,
+	.get_channels		= bnx2x_get_channels,
+	.set_channels		= bnx2x_set_channels,
+	.get_module_info	= bnx2x_get_module_info,
+	.get_module_eeprom	= bnx2x_get_module_eeprom,
+	.get_eee		= bnx2x_get_eee,
+	.set_eee		= bnx2x_set_eee,
 };
 
 void bnx2x_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
index a440a8b..e7c390c 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
@@ -1067,8 +1067,18 @@ struct port_feat_cfg {		    /* port 0: 0x454  port 1: 0x4c8 */
 	   uses the same defines as link_config */
 	u32 mfw_wol_link_cfg2;				    /* 0x480 */
 
-	u32 Reserved2[17];				    /* 0x484 */
 
+	/*  EEE power saving mode */
+	u32 eee_power_mode;                                 /* 0x484 */
+	#define PORT_FEAT_CFG_EEE_POWER_MODE_MASK                     0x000000FF
+	#define PORT_FEAT_CFG_EEE_POWER_MODE_SHIFT                    0
+	#define PORT_FEAT_CFG_EEE_POWER_MODE_DISABLED                 0x00000000
+	#define PORT_FEAT_CFG_EEE_POWER_MODE_BALANCED                 0x00000001
+	#define PORT_FEAT_CFG_EEE_POWER_MODE_AGGRESSIVE               0x00000002
+	#define PORT_FEAT_CFG_EEE_POWER_MODE_LOW_LATENCY              0x00000003
+
+
+	u32 Reserved2[16];                                  /* 0x488 */
 };
 
 
@@ -1140,6 +1150,7 @@ struct drv_port_mb {
 	u32 link_status;
 	/* Driver should update this field on any link change event */
 
+	#define LINK_STATUS_NONE				(0<<0)
 	#define LINK_STATUS_LINK_FLAG_MASK			0x00000001
 	#define LINK_STATUS_LINK_UP				0x00000001
 	#define LINK_STATUS_SPEED_AND_DUPLEX_MASK		0x0000001E
@@ -1197,6 +1208,7 @@ struct drv_port_mb {
 	#define LINK_STATUS_PFC_ENABLED				0x20000000
 
 	#define LINK_STATUS_PHYSICAL_LINK_FLAG			0x40000000
+	#define LINK_STATUS_SFP_TX_FAULT			0x80000000
 
 	u32 port_stx;
 
@@ -1243,6 +1255,7 @@ struct drv_func_mb {
 
 	#define DRV_MSG_CODE_DCBX_ADMIN_PMF_MSG         0xb0000000
 	#define DRV_MSG_CODE_DCBX_PMF_DRV_OK            0xb2000000
+	#define REQ_BC_VER_4_DCBX_ADMIN_MSG_NON_PMF     0x00070401
 
 	#define DRV_MSG_CODE_VF_DISABLED_DONE           0xc0000000
 
@@ -1255,6 +1268,8 @@ struct drv_func_mb {
 	#define DRV_MSG_CODE_DRV_INFO_ACK               0xd8000000
 	#define DRV_MSG_CODE_DRV_INFO_NACK              0xd9000000
 
+	#define DRV_MSG_CODE_EEE_RESULTS_ACK            0xda000000
+
 	#define DRV_MSG_CODE_SET_MF_BW                  0xe0000000
 	#define REQ_BC_VER_4_SET_MF_BW                  0x00060202
 	#define DRV_MSG_CODE_SET_MF_BW_ACK              0xe1000000
@@ -1320,6 +1335,8 @@ struct drv_func_mb {
 	#define FW_MSG_CODE_DRV_INFO_ACK                0xd8100000
 	#define FW_MSG_CODE_DRV_INFO_NACK               0xd9100000
 
+	#define FW_MSG_CODE_EEE_RESULS_ACK              0xda100000
+
 	#define FW_MSG_CODE_SET_MF_BW_SENT              0xe0000000
 	#define FW_MSG_CODE_SET_MF_BW_DONE              0xe1000000
 
@@ -1383,6 +1400,8 @@ struct drv_func_mb {
 
 	#define DRV_STATUS_DRV_INFO_REQ                 0x04000000
 
+	#define DRV_STATUS_EEE_NEGOTIATION_RESULTS      0x08000000
+
 	u32 virt_mac_upper;
 	#define VIRT_MAC_SIGN_MASK                      0xffff0000
 	#define VIRT_MAC_SIGNATURE                      0x564d0000
@@ -1613,6 +1632,11 @@ struct fw_flr_mb {
 	struct fw_flr_ack ack;
 };
 
+struct eee_remote_vals {
+	u32         tx_tw;
+	u32         rx_tw;
+};
+
 /**** SUPPORT FOR SHMEM ARRRAYS ***
  * The SHMEM HSI is aligned on 32 bit boundaries which makes it difficult to
  * define arrays with storage types smaller then unsigned dwords.
@@ -2053,6 +2077,41 @@ struct shmem2_region {
 #define DRV_INFO_CONTROL_OP_CODE_MASK      0x0000ff00
 #define DRV_INFO_CONTROL_OP_CODE_SHIFT     8
 	u32 ibft_host_addr; /* initialized by option ROM */
+	struct eee_remote_vals eee_remote_vals[PORT_MAX];
+	u32 reserved[E2_FUNC_MAX];
+
+
+	/* the status of EEE auto-negotiation
+	 * bits 15:0 the configured tx-lpi entry timer value. Depends on bit 31.
+	 * bits 19:16 the supported modes for EEE.
+	 * bits 23:20 the speeds advertised for EEE.
+	 * bits 27:24 the speeds the Link partner advertised for EEE.
+	 * The supported/adv. modes in bits 27:19 originate from the
+	 * SHMEM_EEE_XXX_ADV definitions (where XXX is replaced by speed).
+	 * bit 28 when 1'b1 EEE was requested.
+	 * bit 29 when 1'b1 tx lpi was requested.
+	 * bit 30 when 1'b1 EEE was negotiated. Tx lpi will be asserted iff
+	 * 30:29 are 2'b11.
+	 * bit 31 when 1'b0 bits 15:0 contain a PORT_FEAT_CFG_EEE_ define as
+	 * value. When 1'b1 those bits contains a value times 16 microseconds.
+	 */
+	u32 eee_status[PORT_MAX];
+	#define SHMEM_EEE_TIMER_MASK		   0x0000ffff
+	#define SHMEM_EEE_SUPPORTED_MASK	   0x000f0000
+	#define SHMEM_EEE_SUPPORTED_SHIFT	   16
+	#define SHMEM_EEE_ADV_STATUS_MASK	   0x00f00000
+		#define SHMEM_EEE_100M_ADV	   (1<<0)
+		#define SHMEM_EEE_1G_ADV	   (1<<1)
+		#define SHMEM_EEE_10G_ADV	   (1<<2)
+	#define SHMEM_EEE_ADV_STATUS_SHIFT	   20
+	#define	SHMEM_EEE_LP_ADV_STATUS_MASK	   0x0f000000
+	#define SHMEM_EEE_LP_ADV_STATUS_SHIFT	   24
+	#define SHMEM_EEE_REQUESTED_BIT		   0x10000000
+	#define SHMEM_EEE_LPI_REQUESTED_BIT	   0x20000000
+	#define SHMEM_EEE_ACTIVE_BIT		   0x40000000
+	#define SHMEM_EEE_TIME_OUTPUT_BIT	   0x80000000
+
+	u32 sizeof_port_stats;
 };
 
 
@@ -2599,6 +2658,9 @@ struct host_port_stats {
 	u32            pfc_frames_tx_lo;
 	u32            pfc_frames_rx_hi;
 	u32            pfc_frames_rx_lo;
+
+	u32            eee_lpi_count_hi;
+	u32            eee_lpi_count_lo;
 };
 
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index a3fb721..e04b282 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -40,6 +40,7 @@
 #define I2C_BSC0			0
 #define I2C_BSC1			1
 #define I2C_WA_RETRY_CNT		3
+#define I2C_WA_PWR_ITER			(I2C_WA_RETRY_CNT - 1)
 #define MCPR_IMC_COMMAND_READ_OP	1
 #define MCPR_IMC_COMMAND_WRITE_OP	2
 
@@ -284,7 +285,6 @@
 #define ETS_E3B0_PBF_MIN_W_VAL				(10000)
 
 #define MAX_PACKET_SIZE					(9700)
-#define WC_UC_TIMEOUT					100
 #define MAX_KR_LINK_RETRY				4
 
 /**********************************************************/
@@ -1305,6 +1305,94 @@ int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
 
 	return 0;
 }
+
+/******************************************************************/
+/*			EEE section				   */
+/******************************************************************/
+static u8 bnx2x_eee_has_cap(struct link_params *params)
+{
+	struct bnx2x *bp = params->bp;
+
+	if (REG_RD(bp, params->shmem2_base) <=
+		   offsetof(struct shmem2_region, eee_status[params->port]))
+		return 0;
+
+	return 1;
+}
+
+static int bnx2x_eee_nvram_to_time(u32 nvram_mode, u32 *idle_timer)
+{
+	switch (nvram_mode) {
+	case PORT_FEAT_CFG_EEE_POWER_MODE_BALANCED:
+		*idle_timer = EEE_MODE_NVRAM_BALANCED_TIME;
+		break;
+	case PORT_FEAT_CFG_EEE_POWER_MODE_AGGRESSIVE:
+		*idle_timer = EEE_MODE_NVRAM_AGGRESSIVE_TIME;
+		break;
+	case PORT_FEAT_CFG_EEE_POWER_MODE_LOW_LATENCY:
+		*idle_timer = EEE_MODE_NVRAM_LATENCY_TIME;
+		break;
+	default:
+		*idle_timer = 0;
+		break;
+	}
+
+	return 0;
+}
+
+static int bnx2x_eee_time_to_nvram(u32 idle_timer, u32 *nvram_mode)
+{
+	switch (idle_timer) {
+	case EEE_MODE_NVRAM_BALANCED_TIME:
+		*nvram_mode = PORT_FEAT_CFG_EEE_POWER_MODE_BALANCED;
+		break;
+	case EEE_MODE_NVRAM_AGGRESSIVE_TIME:
+		*nvram_mode = PORT_FEAT_CFG_EEE_POWER_MODE_AGGRESSIVE;
+		break;
+	case EEE_MODE_NVRAM_LATENCY_TIME:
+		*nvram_mode = PORT_FEAT_CFG_EEE_POWER_MODE_LOW_LATENCY;
+		break;
+	default:
+		*nvram_mode = PORT_FEAT_CFG_EEE_POWER_MODE_DISABLED;
+		break;
+	}
+
+	return 0;
+}
+
+static u32 bnx2x_eee_calc_timer(struct link_params *params)
+{
+	u32 eee_mode, eee_idle;
+	struct bnx2x *bp = params->bp;
+
+	if (params->eee_mode & EEE_MODE_OVERRIDE_NVRAM) {
+		if (params->eee_mode & EEE_MODE_OUTPUT_TIME) {
+			/* time value in eee_mode --> used directly*/
+			eee_idle = params->eee_mode & EEE_MODE_TIMER_MASK;
+		} else {
+			/* hsi value in eee_mode --> time */
+			if (bnx2x_eee_nvram_to_time(params->eee_mode &
+						    EEE_MODE_NVRAM_MASK,
+						    &eee_idle))
+				return 0;
+		}
+	} else {
+		/* hsi values in nvram --> time*/
+		eee_mode = ((REG_RD(bp, params->shmem_base +
+				    offsetof(struct shmem_region, dev_info.
+				    port_feature_config[params->port].
+				    eee_power_mode)) &
+			     PORT_FEAT_CFG_EEE_POWER_MODE_MASK) >>
+			    PORT_FEAT_CFG_EEE_POWER_MODE_SHIFT);
+
+		if (bnx2x_eee_nvram_to_time(eee_mode, &eee_idle))
+			return 0;
+	}
+
+	return eee_idle;
+}
+
+
 /******************************************************************/
 /*			PFC section				  */
 /******************************************************************/
@@ -1539,7 +1627,7 @@ static void bnx2x_umac_enable(struct link_params *params,
 	/* Reset UMAC */
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
 	       (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port));
-	usleep_range(1000, 1000);
+	usleep_range(1000, 2000);
 
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
 	       (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port));
@@ -1641,7 +1729,7 @@ static void bnx2x_xmac_init(struct link_params *params, u32 max_speed)
 	/* Hard reset */
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
 	       MISC_REGISTERS_RESET_REG_2_XMAC);
-	usleep_range(1000, 1000);
+	usleep_range(1000, 2000);
 
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
 	       MISC_REGISTERS_RESET_REG_2_XMAC);
@@ -1671,7 +1759,7 @@ static void bnx2x_xmac_init(struct link_params *params, u32 max_speed)
 	/* Soft reset */
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
 	       MISC_REGISTERS_RESET_REG_2_XMAC_SOFT);
-	usleep_range(1000, 1000);
+	usleep_range(1000, 2000);
 
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
 	       MISC_REGISTERS_RESET_REG_2_XMAC_SOFT);
@@ -1729,6 +1817,14 @@ static int bnx2x_xmac_enable(struct link_params *params,
 	/* update PFC */
 	bnx2x_update_pfc_xmac(params, vars, 0);
 
+	if (vars->eee_status & SHMEM_EEE_ADV_STATUS_MASK) {
+		DP(NETIF_MSG_LINK, "Setting XMAC for EEE\n");
+		REG_WR(bp, xmac_base + XMAC_REG_EEE_TIMERS_HI, 0x1380008);
+		REG_WR(bp, xmac_base + XMAC_REG_EEE_CTRL, 0x1);
+	} else {
+		REG_WR(bp, xmac_base + XMAC_REG_EEE_CTRL, 0x0);
+	}
+
 	/* Enable TX and RX */
 	val = XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN;
 
@@ -1784,11 +1880,6 @@ static int bnx2x_emac_enable(struct link_params *params,
 	bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
 		      EMAC_TX_MODE_RESET);
 
-	if (CHIP_REV_IS_SLOW(bp)) {
-		/* config GMII mode */
-		val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
-		EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII));
-	} else { /* ASIC */
 		/* pause enable/disable */
 		bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
 			       EMAC_RX_MODE_FLOW_EN);
@@ -1811,7 +1902,6 @@ static int bnx2x_emac_enable(struct link_params *params,
 		} else
 			bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
 				      EMAC_TX_MODE_FLOW_EN);
-	}
 
 	/* KEEP_VLAN_TAG, promiscuous */
 	val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
@@ -1850,23 +1940,23 @@ static int bnx2x_emac_enable(struct link_params *params,
 		val &= ~0x810;
 	EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
 
-	/* enable emac */
+	/* Enable emac */
 	REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
 
-	/* enable emac for jumbo packets */
+	/* Enable emac for jumbo packets */
 	EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
 		(EMAC_RX_MTU_SIZE_JUMBO_ENA |
 		 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
 
-	/* strip CRC */
+	/* Strip CRC */
 	REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
 
-	/* disable the NIG in/out to the bmac */
+	/* Disable the NIG in/out to the bmac */
 	REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
 	REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
 	REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
 
-	/* enable the NIG in/out to the emac */
+	/* Enable the NIG in/out to the emac */
 	REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
 	val = 0;
 	if ((params->feature_config_flags &
@@ -1901,7 +1991,7 @@ static void bnx2x_update_pfc_bmac1(struct link_params *params,
 	wb_data[1] = 0;
 	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2);
 
-	/* tx control */
+	/* TX control */
 	val = 0xc0;
 	if (!(params->feature_config_flags &
 	      FEATURE_CONFIG_PFC_ENABLED) &&
@@ -1961,7 +2051,7 @@ static void bnx2x_update_pfc_bmac2(struct link_params *params,
 		wb_data[0] &= ~(1<<2);
 	} else {
 		DP(NETIF_MSG_LINK, "PFC is disabled\n");
-		/* disable PFC RX & TX & STATS and set 8 COS */
+		/* Disable PFC RX & TX & STATS and set 8 COS */
 		wb_data[0] = 0x8;
 		wb_data[1] = 0;
 	}
@@ -2055,7 +2145,7 @@ static int bnx2x_pfc_brb_get_config_params(
 			PFC_E2_BRB_MAC_FULL_XOFF_THR_PAUSE;
 		config_val->pauseable_th.full_xon =
 			PFC_E2_BRB_MAC_FULL_XON_THR_PAUSE;
-		/* non pause able*/
+		/* Non pause able*/
 		config_val->non_pauseable_th.pause_xoff =
 			PFC_E2_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
 		config_val->non_pauseable_th.pause_xon =
@@ -2083,7 +2173,7 @@ static int bnx2x_pfc_brb_get_config_params(
 			PFC_E3A0_BRB_MAC_FULL_XOFF_THR_PAUSE;
 		config_val->pauseable_th.full_xon =
 			PFC_E3A0_BRB_MAC_FULL_XON_THR_PAUSE;
-		/* non pause able*/
+		/* Non pause able*/
 		config_val->non_pauseable_th.pause_xoff =
 			PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
 		config_val->non_pauseable_th.pause_xon =
@@ -2113,7 +2203,7 @@ static int bnx2x_pfc_brb_get_config_params(
 				PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_PAUSE;
 			config_val->pauseable_th.full_xon =
 				PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_PAUSE;
-			/* non pause able*/
+			/* Non pause able*/
 			config_val->non_pauseable_th.pause_xoff =
 			PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
 			config_val->non_pauseable_th.pause_xon =
@@ -2131,7 +2221,7 @@ static int bnx2x_pfc_brb_get_config_params(
 				PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_PAUSE;
 			config_val->pauseable_th.full_xon =
 				PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_PAUSE;
-			/* non pause able*/
+			/* Non pause able*/
 			config_val->non_pauseable_th.pause_xoff =
 				PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
 			config_val->non_pauseable_th.pause_xon =
@@ -2188,7 +2278,7 @@ static void bnx2x_pfc_brb_get_e3b0_config_params(
 
 			if (pfc_params->cos0_pauseable !=
 				pfc_params->cos1_pauseable) {
-				/* nonpauseable= Lossy + pauseable = Lossless*/
+				/* Nonpauseable= Lossy + pauseable = Lossless*/
 				e3b0_val->lb_guarantied =
 					PFC_E3B0_2P_MIX_PAUSE_LB_GUART;
 				e3b0_val->mac_0_class_t_guarantied =
@@ -2387,9 +2477,9 @@ static int bnx2x_update_pfc_brb(struct link_params *params,
 *  This function is needed because NIG ARB_CREDIT_WEIGHT_X are
 *  not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable.
 ******************************************************************************/
-int bnx2x_pfc_nig_rx_priority_mask(struct bnx2x *bp,
-					      u8 cos_entry,
-					      u32 priority_mask, u8 port)
+static int bnx2x_pfc_nig_rx_priority_mask(struct bnx2x *bp,
+					   u8 cos_entry,
+					   u32 priority_mask, u8 port)
 {
 	u32 nig_reg_rx_priority_mask_add = 0;
 
@@ -2439,6 +2529,16 @@ static void bnx2x_update_mng(struct link_params *params, u32 link_status)
 			port_mb[params->port].link_status), link_status);
 }
 
+static void bnx2x_update_mng_eee(struct link_params *params, u32 eee_status)
+{
+	struct bnx2x *bp = params->bp;
+
+	if (bnx2x_eee_has_cap(params))
+		REG_WR(bp, params->shmem2_base +
+		       offsetof(struct shmem2_region,
+				eee_status[params->port]), eee_status);
+}
+
 static void bnx2x_update_pfc_nig(struct link_params *params,
 		struct link_vars *vars,
 		struct bnx2x_nig_brb_pfc_port_params *nig_params)
@@ -2506,7 +2606,7 @@ static void bnx2x_update_pfc_nig(struct link_params *params,
 	REG_WR(bp, port ? NIG_REG_LLFC_EGRESS_SRC_ENABLE_1 :
 	       NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
 
-	/* output enable for RX_XCM # IF */
+	/* Output enable for RX_XCM # IF */
 	REG_WR(bp, port ? NIG_REG_XCM1_OUT_EN :
 	       NIG_REG_XCM0_OUT_EN, xcm_out_en);
 
@@ -2555,10 +2655,10 @@ int bnx2x_update_pfc(struct link_params *params,
 
 	bnx2x_update_mng(params, vars->link_status);
 
-	/* update NIG params */
+	/* Update NIG params */
 	bnx2x_update_pfc_nig(params, vars, pfc_params);
 
-	/* update BRB params */
+	/* Update BRB params */
 	bnx2x_status = bnx2x_update_pfc_brb(params, vars, pfc_params);
 	if (bnx2x_status)
 		return bnx2x_status;
@@ -2613,7 +2713,7 @@ static int bnx2x_bmac1_enable(struct link_params *params,
 	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
 		    wb_data, 2);
 
-	/* tx MAC SA */
+	/* TX MAC SA */
 	wb_data[0] = ((params->mac_addr[2] << 24) |
 		       (params->mac_addr[3] << 16) |
 		       (params->mac_addr[4] << 8) |
@@ -2622,7 +2722,7 @@ static int bnx2x_bmac1_enable(struct link_params *params,
 			params->mac_addr[1]);
 	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2);
 
-	/* mac control */
+	/* MAC control */
 	val = 0x3;
 	if (is_lb) {
 		val |= 0x4;
@@ -2632,24 +2732,24 @@ static int bnx2x_bmac1_enable(struct link_params *params,
 	wb_data[1] = 0;
 	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2);
 
-	/* set rx mtu */
+	/* Set rx mtu */
 	wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
 	wb_data[1] = 0;
 	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2);
 
 	bnx2x_update_pfc_bmac1(params, vars);
 
-	/* set tx mtu */
+	/* Set tx mtu */
 	wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
 	wb_data[1] = 0;
 	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_data, 2);
 
-	/* set cnt max size */
+	/* Set cnt max size */
 	wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
 	wb_data[1] = 0;
 	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, wb_data, 2);
 
-	/* configure safc */
+	/* Configure SAFC */
 	wb_data[0] = 0x1000200;
 	wb_data[1] = 0;
 	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
@@ -2683,7 +2783,7 @@ static int bnx2x_bmac2_enable(struct link_params *params,
 
 	udelay(30);
 
-	/* tx MAC SA */
+	/* TX MAC SA */
 	wb_data[0] = ((params->mac_addr[2] << 24) |
 		       (params->mac_addr[3] << 16) |
 		       (params->mac_addr[4] << 8) |
@@ -2702,18 +2802,18 @@ static int bnx2x_bmac2_enable(struct link_params *params,
 		    wb_data, 2);
 	udelay(30);
 
-	/* set rx mtu */
+	/* Set RX MTU */
 	wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
 	wb_data[1] = 0;
 	REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, wb_data, 2);
 	udelay(30);
 
-	/* set tx mtu */
+	/* Set TX MTU */
 	wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
 	wb_data[1] = 0;
 	REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, wb_data, 2);
 	udelay(30);
-	/* set cnt max size */
+	/* Set cnt max size */
 	wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2;
 	wb_data[1] = 0;
 	REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2);
@@ -2731,15 +2831,15 @@ static int bnx2x_bmac_enable(struct link_params *params,
 	u8 port = params->port;
 	struct bnx2x *bp = params->bp;
 	u32 val;
-	/* reset and unreset the BigMac */
+	/* Reset and unreset the BigMac */
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
 	       (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
-	msleep(1);
+	usleep_range(1000, 2000);
 
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
 	       (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
 
-	/* enable access for bmac registers */
+	/* Enable access for bmac registers */
 	REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
 
 	/* Enable BMAC according to BMAC type*/
@@ -2797,7 +2897,7 @@ static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
 					BIGMAC_REGISTER_BMAC_CONTROL,
 					wb_data, 2);
 		}
-		msleep(1);
+		usleep_range(1000, 2000);
 	}
 }
 
@@ -2809,17 +2909,16 @@ static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
 	u32 init_crd, crd;
 	u32 count = 1000;
 
-	/* disable port */
+	/* Disable port */
 	REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
 
-	/* wait for init credit */
+	/* Wait for init credit */
 	init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
 	crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
 	DP(NETIF_MSG_LINK, "init_crd 0x%x  crd 0x%x\n", init_crd, crd);
 
 	while ((init_crd != crd) && count) {
-		msleep(5);
-
+		usleep_range(5000, 10000);
 		crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
 		count--;
 	}
@@ -2836,18 +2935,18 @@ static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
 	    line_speed == SPEED_1000 ||
 	    line_speed == SPEED_2500) {
 		REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
-		/* update threshold */
+		/* Update threshold */
 		REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
-		/* update init credit */
+		/* Update init credit */
 		init_crd = 778;		/* (800-18-4) */
 
 	} else {
 		u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
 			      ETH_OVREHEAD)/16;
 		REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
-		/* update threshold */
+		/* Update threshold */
 		REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
-		/* update init credit */
+		/* Update init credit */
 		switch (line_speed) {
 		case SPEED_10000:
 			init_crd = thresh + 553 - 22;
@@ -2862,12 +2961,12 @@ static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
 	DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
 		 line_speed, init_crd);
 
-	/* probe the credit changes */
+	/* Probe the credit changes */
 	REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
-	msleep(5);
+	usleep_range(5000, 10000);
 	REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
 
-	/* enable port */
+	/* Enable port */
 	REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
 	return 0;
 }
@@ -2934,7 +3033,7 @@ static int bnx2x_cl22_write(struct bnx2x *bp,
 	REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE,
 	       mode & ~EMAC_MDIO_MODE_CLAUSE_45);
 
-	/* address */
+	/* Address */
 	tmp = ((phy->addr << 21) | (reg << 16) | val |
 	       EMAC_MDIO_COMM_COMMAND_WRITE_22 |
 	       EMAC_MDIO_COMM_START_BUSY);
@@ -2970,7 +3069,7 @@ static int bnx2x_cl22_read(struct bnx2x *bp,
 	REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE,
 	       mode & ~EMAC_MDIO_MODE_CLAUSE_45);
 
-	/* address */
+	/* Address */
 	val = ((phy->addr << 21) | (reg << 16) |
 	       EMAC_MDIO_COMM_COMMAND_READ_22 |
 	       EMAC_MDIO_COMM_START_BUSY);
@@ -3008,7 +3107,7 @@ static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
 	if (phy->flags & FLAGS_MDC_MDIO_WA_B0)
 		bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS,
 			      EMAC_MDIO_STATUS_10MB);
-	/* address */
+	/* Address */
 	val = ((phy->addr << 21) | (devad << 16) | reg |
 	       EMAC_MDIO_COMM_COMMAND_ADDRESS |
 	       EMAC_MDIO_COMM_START_BUSY);
@@ -3029,7 +3128,7 @@ static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
 		*ret_val = 0;
 		rc = -EFAULT;
 	} else {
-		/* data */
+		/* Data */
 		val = ((phy->addr << 21) | (devad << 16) |
 		       EMAC_MDIO_COMM_COMMAND_READ_45 |
 		       EMAC_MDIO_COMM_START_BUSY);
@@ -3077,7 +3176,7 @@ static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
 		bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS,
 			      EMAC_MDIO_STATUS_10MB);
 
-	/* address */
+	/* Address */
 	tmp = ((phy->addr << 21) | (devad << 16) | reg |
 	       EMAC_MDIO_COMM_COMMAND_ADDRESS |
 	       EMAC_MDIO_COMM_START_BUSY);
@@ -3097,7 +3196,7 @@ static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
 		netdev_err(bp->dev,  "MDC/MDIO access timeout\n");
 		rc = -EFAULT;
 	} else {
-		/* data */
+		/* Data */
 		tmp = ((phy->addr << 21) | (devad << 16) | val |
 		       EMAC_MDIO_COMM_COMMAND_WRITE_45 |
 		       EMAC_MDIO_COMM_START_BUSY);
@@ -3187,23 +3286,23 @@ static int bnx2x_bsc_read(struct link_params *params,
 
 	xfer_cnt = 16 - lc_addr;
 
-	/* enable the engine */
+	/* Enable the engine */
 	val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
 	val |= MCPR_IMC_COMMAND_ENABLE;
 	REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
 
-	/* program slave device ID */
+	/* Program slave device ID */
 	val = (sl_devid << 16) | sl_addr;
 	REG_WR(bp, MCP_REG_MCPR_IMC_SLAVE_CONTROL, val);
 
-	/* start xfer with 0 byte to update the address pointer ???*/
+	/* Start xfer with 0 byte to update the address pointer ???*/
 	val = (MCPR_IMC_COMMAND_ENABLE) |
 	      (MCPR_IMC_COMMAND_WRITE_OP <<
 		MCPR_IMC_COMMAND_OPERATION_BITSHIFT) |
 		(lc_addr << MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT) | (0);
 	REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
 
-	/* poll for completion */
+	/* Poll for completion */
 	i = 0;
 	val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
 	while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) {
@@ -3219,7 +3318,7 @@ static int bnx2x_bsc_read(struct link_params *params,
 	if (rc == -EFAULT)
 		return rc;
 
-	/* start xfer with read op */
+	/* Start xfer with read op */
 	val = (MCPR_IMC_COMMAND_ENABLE) |
 		(MCPR_IMC_COMMAND_READ_OP <<
 		MCPR_IMC_COMMAND_OPERATION_BITSHIFT) |
@@ -3227,7 +3326,7 @@ static int bnx2x_bsc_read(struct link_params *params,
 		  (xfer_cnt);
 	REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
 
-	/* poll for completion */
+	/* Poll for completion */
 	i = 0;
 	val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
 	while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) {
@@ -3330,7 +3429,7 @@ static u8 bnx2x_get_warpcore_lane(struct bnx2x_phy *phy,
 			port = port ^ 1;
 
 		lane = (port<<1) + path;
-	} else { /* two port mode - no port swap */
+	} else { /* Two port mode - no port swap */
 
 		/* Figure out path swap value */
 		path_swap_ovr =
@@ -3408,7 +3507,7 @@ static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
 
 	val = SERDES_RESET_BITS << (port*16);
 
-	/* reset and unreset the SerDes/XGXS */
+	/* Reset and unreset the SerDes/XGXS */
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
 	udelay(500);
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
@@ -3429,7 +3528,7 @@ static void bnx2x_xgxs_deassert(struct link_params *params)
 
 	val = XGXS_RESET_BITS << (port*16);
 
-	/* reset and unreset the SerDes/XGXS */
+	/* Reset and unreset the SerDes/XGXS */
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
 	udelay(500);
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
@@ -3521,7 +3620,7 @@ static void bnx2x_ext_phy_set_pause(struct link_params *params,
 {
 	u16 val;
 	struct bnx2x *bp = params->bp;
-	/* read modify write pause advertizing */
+	/* Read modify write pause advertizing */
 	bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
 
 	val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
@@ -3656,44 +3755,35 @@ static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
 static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
 					struct link_params *params,
 					struct link_vars *vars) {
-	u16 val16 = 0, lane, bam37 = 0;
-	struct bnx2x *bp = params->bp;
+	u16 val16 = 0, lane, i;
+	struct bnx2x *bp = params->bp;
+	static struct bnx2x_reg_set reg_set[] = {
+		{MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7},
+		{MDIO_AN_DEVAD, MDIO_WC_REG_PAR_DET_10G_CTRL, 0},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0xff},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0x5555},
+		{MDIO_PMA_DEVAD, MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0x0},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_RX66_CONTROL, 0x7415},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x6190},
+		/* Disable Autoneg: re-enable it after adv is done. */
+		{MDIO_AN_DEVAD, MDIO_WC_REG_IEEE0BLK_MIICNTL, 0}
+	};
 	DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
 	/* Set to default registers that may be overriden by 10G force */
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7);
-	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
-			 MDIO_WC_REG_PAR_DET_10G_CTRL, 0);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0xff);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0x5555);
-	bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
-			 MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0x0);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_RX66_CONTROL, 0x7415);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x6190);
-	/* Disable Autoneg: re-enable it after adv is done. */
-	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
-			 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0);
+	for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+		bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
+				 reg_set[i].val);
 
 	/* Check adding advertisement for 1G KX */
 	if (((vars->line_speed == SPEED_AUTO_NEG) &&
 	     (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
 	    (vars->line_speed == SPEED_1000)) {
-		u16 sd_digital;
+		u32 addr = MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2;
 		val16 |= (1<<5);
 
 		/* Enable CL37 1G Parallel Detect */
-		bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &sd_digital);
-		bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
-				 (sd_digital | 0x1));
-
+		bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD, addr, 0x1);
 		DP(NETIF_MSG_LINK, "Advertize 1G\n");
 	}
 	if (((vars->line_speed == SPEED_AUTO_NEG) &&
@@ -3703,7 +3793,7 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
 		val16 |= (1<<7);
 		/* Enable 10G Parallel Detect */
 		bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
-				MDIO_WC_REG_PAR_DET_10G_CTRL, 1);
+				 MDIO_WC_REG_PAR_DET_10G_CTRL, 1);
 
 		DP(NETIF_MSG_LINK, "Advertize 10G\n");
 	}
@@ -3737,10 +3827,9 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
 		   offsetof(struct shmem_region, dev_info.
 			    port_hw_config[params->port].default_cfg)) &
 	    PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
-		bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-				MDIO_WC_REG_DIGITAL6_MP5_NEXTPAGECTRL, &bam37);
-		bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_DIGITAL6_MP5_NEXTPAGECTRL, bam37 | 1);
+		bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+					 MDIO_WC_REG_DIGITAL6_MP5_NEXTPAGECTRL,
+					 1);
 		DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
 	}
 
@@ -3754,11 +3843,8 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
 		DP(NETIF_MSG_LINK, "Enable AN KR work-around\n");
 		vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
 	}
-	bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_DIGITAL5_MISC7, &val16);
-
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_DIGITAL5_MISC7, val16 | 0x100);
+	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+				 MDIO_WC_REG_DIGITAL5_MISC7, 0x100);
 
 	/* Over 1G - AN local device user page 1 */
 	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
@@ -3775,50 +3861,35 @@ static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
 				      struct link_vars *vars)
 {
 	struct bnx2x *bp = params->bp;
-	u16 val;
-
-	/* Disable Autoneg */
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7);
-
-	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
-			 MDIO_WC_REG_PAR_DET_10G_CTRL, 0);
-
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0x3f00);
-
-	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
-			 MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, 0);
-
-	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
-			 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0);
-
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_DIGITAL3_UP1, 0x1);
-
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_DIGITAL5_MISC7, 0xa);
-
-	/* Disable CL36 PCS Tx */
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0x0);
-
-	/* Double Wide Single Data Rate @ pll rate */
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0xFFFF);
-
-	/* Leave cl72 training enable, needed for KR */
-	bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
+	u16 i;
+	static struct bnx2x_reg_set reg_set[] = {
+		/* Disable Autoneg */
+		{MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7},
+		{MDIO_AN_DEVAD, MDIO_WC_REG_PAR_DET_10G_CTRL, 0},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
+			0x3f00},
+		{MDIO_AN_DEVAD, MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, 0},
+		{MDIO_AN_DEVAD, MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_DIGITAL3_UP1, 0x1},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_DIGITAL5_MISC7, 0xa},
+		/* Disable CL36 PCS Tx */
+		{MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0x0},
+		/* Double Wide Single Data Rate @ pll rate */
+		{MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0xFFFF},
+		/* Leave cl72 training enable, needed for KR */
+		{MDIO_PMA_DEVAD,
 		MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150,
-		0x2);
+		0x2}
+	};
+
+	for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+		bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
+				 reg_set[i].val);
 
 	/* Leave CL72 enabled */
-	bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
-			 &val);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
-			 val | 0x3800);
+	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+				 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
+				 0x3800);
 
 	/* Set speed via PMA/PMD register */
 	bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
@@ -3839,7 +3910,7 @@ static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
 	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
 				 MDIO_WC_REG_RX66_CONTROL, 0xF9);
 
-	/* set and clear loopback to cause a reset to 64/66 decoder */
+	/* Set and clear loopback to cause a reset to 64/66 decoder */
 	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
 			 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x4000);
 	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
@@ -3854,16 +3925,12 @@ static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy,
 	struct bnx2x *bp = params->bp;
 	u16 misc1_val, tap_val, tx_driver_val, lane, val;
 	/* Hold rxSeqStart */
-	bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, &val);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, (val | 0x8000));
+	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+				 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, 0x8000);
 
 	/* Hold tx_fifo_reset */
-	bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, &val);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, (val | 0x1));
+	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+				 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, 0x1);
 
 	/* Disable CL73 AN */
 	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0);
@@ -3875,10 +3942,8 @@ static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy,
 			 MDIO_WC_REG_FX100_CTRL1, (val & 0xFFFA));
 
 	/* Disable 100FX Idle detect */
-	bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_FX100_CTRL3, &val);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_FX100_CTRL3, (val | 0x0080));
+	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+				 MDIO_WC_REG_FX100_CTRL3, 0x0080);
 
 	/* Set Block address to Remote PHY & Clear forced_speed[5] */
 	bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
@@ -3939,16 +4004,20 @@ static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy,
 			 tx_driver_val);
 
 	/* Enable fiber mode, enable and invert sig_det */
-	bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &val);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, val | 0xd);
+	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+				 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, 0xd);
 
 	/* Set Block address to Remote PHY & Set forced_speed[5], 40bit mode */
-	bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_DIGITAL4_MISC3, &val);
+	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+				 MDIO_WC_REG_DIGITAL4_MISC3, 0x8080);
+
+	/* Enable LPI pass through */
+	DP(NETIF_MSG_LINK, "Configure WC for LPI pass through\n");
 	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_DIGITAL4_MISC3, val | 0x8080);
+			 MDIO_WC_REG_EEE_COMBO_CONTROL0,
+			 0x7c);
+	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+				 MDIO_WC_REG_DIGITAL4_MISC5, 0xc000);
 
 	/* 10G XFI Full Duplex */
 	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
@@ -4138,40 +4207,35 @@ static void bnx2x_warpcore_clear_regs(struct bnx2x_phy *phy,
 				      u16 lane)
 {
 	struct bnx2x *bp = params->bp;
-	u16 val16;
-
+	u16 i;
+	static struct bnx2x_reg_set wc_regs[] = {
+		{MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_FX100_CTRL1, 0x014a},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_FX100_CTRL3, 0x0800},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_DIGITAL4_MISC3, 0x8008},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
+			0x0195},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
+			0x0007},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3,
+			0x0002},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6000},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_TX_FIR_TAP, 0x0000},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040},
+		{MDIO_WC_DEVAD, MDIO_WC_REG_COMBO_IEEE0_MIICTRL, 0x0140}
+	};
 	/* Set XFI clock comp as default. */
-	bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-			MDIO_WC_REG_RX66_CONTROL, &val16);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_RX66_CONTROL, val16 | (3<<13));
+	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+				 MDIO_WC_REG_RX66_CONTROL, (3<<13));
+
+	for (i = 0; i < sizeof(wc_regs)/sizeof(struct bnx2x_reg_set); i++)
+		bnx2x_cl45_write(bp, phy, wc_regs[i].devad, wc_regs[i].reg,
+				 wc_regs[i].val);
 
-	bnx2x_warpcore_reset_lane(bp, phy, 1);
-	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_FX100_CTRL1, 0x014a);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_FX100_CTRL3, 0x0800);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_DIGITAL4_MISC3, 0x8008);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, 0x0195);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x0007);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, 0x0002);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6000);
 	lane = bnx2x_get_warpcore_lane(phy, params);
 	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_TX_FIR_TAP, 0x0000);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
 			 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane, 0x0990);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040);
-	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-			 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, 0x0140);
-	bnx2x_warpcore_reset_lane(bp, phy, 0);
+
 }
 
 static int bnx2x_get_mod_abs_int_cfg(struct bnx2x *bp,
@@ -4259,7 +4323,7 @@ static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
 	if (!vars->turn_to_run_wc_rt)
 		return;
 
-	/* return if there is no link partner */
+	/* Return if there is no link partner */
 	if (!(bnx2x_warpcore_get_sigdet(phy, params))) {
 		DP(NETIF_MSG_LINK, "bnx2x_warpcore_get_sigdet false\n");
 		return;
@@ -4293,7 +4357,7 @@ static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
 				bnx2x_warpcore_reset_lane(bp, phy, 1);
 				bnx2x_warpcore_reset_lane(bp, phy, 0);
 
-				/* restart Autoneg */
+				/* Restart Autoneg */
 				bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
 					MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1200);
 
@@ -4310,6 +4374,23 @@ static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
 	} /*params->rx_tx_asic_rst*/
 
 }
+static void bnx2x_warpcore_config_sfi(struct bnx2x_phy *phy,
+				      struct link_params *params)
+{
+	u16 lane = bnx2x_get_warpcore_lane(phy, params);
+	struct bnx2x *bp = params->bp;
+	bnx2x_warpcore_clear_regs(phy, params, lane);
+	if ((params->req_line_speed[LINK_CONFIG_IDX(INT_PHY)] ==
+	     SPEED_10000) &&
+	    (phy->media_type != ETH_PHY_SFP_1G_FIBER)) {
+		DP(NETIF_MSG_LINK, "Setting 10G SFI\n");
+		bnx2x_warpcore_set_10G_XFI(phy, params, 0);
+	} else {
+		DP(NETIF_MSG_LINK, "Setting 1G Fiber\n");
+		bnx2x_warpcore_set_sgmii_speed(phy, params, 1, 0);
+	}
+}
+
 static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
 				       struct link_params *params,
 				       struct link_vars *vars)
@@ -4370,19 +4451,11 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
 			break;
 
 		case PORT_HW_CFG_NET_SERDES_IF_SFI:
-
-			bnx2x_warpcore_clear_regs(phy, params, lane);
-			if (vars->line_speed == SPEED_10000) {
-				DP(NETIF_MSG_LINK, "Setting 10G SFI\n");
-				bnx2x_warpcore_set_10G_XFI(phy, params, 0);
-			} else if (vars->line_speed == SPEED_1000) {
-				DP(NETIF_MSG_LINK, "Setting 1G Fiber\n");
-				bnx2x_warpcore_set_sgmii_speed(
-						phy, params, 1, 0);
-			}
 			/* Issue Module detection */
 			if (bnx2x_is_sfp_module_plugged(phy, params))
 				bnx2x_sfp_module_detection(phy, params);
+
+			bnx2x_warpcore_config_sfi(phy, params);
 			break;
 
 		case PORT_HW_CFG_NET_SERDES_IF_DXGXS:
@@ -4499,12 +4572,9 @@ static void bnx2x_set_warpcore_loopback(struct bnx2x_phy *phy,
 		CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
 				  MDIO_AER_BLOCK_AER_REG, 0);
 		/* Enable 1G MDIO (1-copy) */
-		bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-				MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
-				&val16);
-		bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-				MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
-				val16 | 0x10);
+		bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+					 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
+					 0x10);
 		/* Set 1G loopback based on lane (1-copy) */
 		lane = bnx2x_get_warpcore_lane(phy, params);
 		bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
@@ -4517,22 +4587,19 @@ static void bnx2x_set_warpcore_loopback(struct bnx2x_phy *phy,
 		bnx2x_set_aer_mmd(params, phy);
 	} else {
 		/* 10G & 20G */
-		bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-				MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
-		bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-				MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 |
-				 0x4000);
+		bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+					 MDIO_WC_REG_COMBO_IEEE0_MIICTRL,
+					 0x4000);
 
-		bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-				MDIO_WC_REG_IEEE0BLK_MIICNTL, &val16);
-		bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-				MDIO_WC_REG_IEEE0BLK_MIICNTL, val16 | 0x1);
+		bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+					 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1);
 	}
 }
 
 
-void bnx2x_sync_link(struct link_params *params,
-			   struct link_vars *vars)
+
+static void bnx2x_sync_link(struct link_params *params,
+			     struct link_vars *vars)
 {
 	struct bnx2x *bp = params->bp;
 	u8 link_10g_plus;
@@ -4605,7 +4672,7 @@ void bnx2x_sync_link(struct link_params *params,
 		    USES_WARPCORE(bp) &&
 		    (vars->line_speed == SPEED_1000))
 			vars->phy_flags |= PHY_SGMII_FLAG;
-		/* anything 10 and over uses the bmac */
+		/* Anything 10 and over uses the bmac */
 		link_10g_plus = (vars->line_speed >= SPEED_10000);
 
 		if (link_10g_plus) {
@@ -4619,7 +4686,7 @@ void bnx2x_sync_link(struct link_params *params,
 			else
 				vars->mac_type = MAC_TYPE_EMAC;
 		}
-	} else { /* link down */
+	} else { /* Link down */
 		DP(NETIF_MSG_LINK, "phy link down\n");
 
 		vars->phy_link_up = 0;
@@ -4628,10 +4695,12 @@ void bnx2x_sync_link(struct link_params *params,
 		vars->duplex = DUPLEX_FULL;
 		vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 
-		/* indicate no mac active */
+		/* Indicate no mac active */
 		vars->mac_type = MAC_TYPE_NONE;
 		if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG)
 			vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG;
+		if (vars->link_status & LINK_STATUS_SFP_TX_FAULT)
+			vars->phy_flags |= PHY_SFP_TX_FAULT_FLAG;
 	}
 }
 
@@ -4697,7 +4766,7 @@ static void bnx2x_set_master_ln(struct link_params *params,
 		     PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
 		    PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
 
-	/* set the master_ln for AN */
+	/* Set the master_ln for AN */
 	CL22_RD_OVER_CL45(bp, phy,
 			  MDIO_REG_BANK_XGXS_BLOCK2,
 			  MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
@@ -4720,7 +4789,7 @@ static int bnx2x_reset_unicore(struct link_params *params,
 			  MDIO_REG_BANK_COMBO_IEEE0,
 			  MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
 
-	/* reset the unicore */
+	/* Reset the unicore */
 	CL22_WR_OVER_CL45(bp, phy,
 			  MDIO_REG_BANK_COMBO_IEEE0,
 			  MDIO_COMBO_IEEE0_MII_CONTROL,
@@ -4729,11 +4798,11 @@ static int bnx2x_reset_unicore(struct link_params *params,
 	if (set_serdes)
 		bnx2x_set_serdes_access(bp, params->port);
 
-	/* wait for the reset to self clear */
+	/* Wait for the reset to self clear */
 	for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
 		udelay(5);
 
-		/* the reset erased the previous bank value */
+		/* The reset erased the previous bank value */
 		CL22_RD_OVER_CL45(bp, phy,
 				  MDIO_REG_BANK_COMBO_IEEE0,
 				  MDIO_COMBO_IEEE0_MII_CONTROL,
@@ -4951,7 +5020,7 @@ static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
 			  MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
 }
 
-/* program SerDes, forced speed */
+/* Program SerDes, forced speed */
 static void bnx2x_program_serdes(struct bnx2x_phy *phy,
 				 struct link_params *params,
 				 struct link_vars *vars)
@@ -4959,7 +5028,7 @@ static void bnx2x_program_serdes(struct bnx2x_phy *phy,
 	struct bnx2x *bp = params->bp;
 	u16 reg_val;
 
-	/* program duplex, disable autoneg and sgmii*/
+	/* Program duplex, disable autoneg and sgmii*/
 	CL22_RD_OVER_CL45(bp, phy,
 			  MDIO_REG_BANK_COMBO_IEEE0,
 			  MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
@@ -4978,7 +5047,7 @@ static void bnx2x_program_serdes(struct bnx2x_phy *phy,
 	CL22_RD_OVER_CL45(bp, phy,
 			  MDIO_REG_BANK_SERDES_DIGITAL,
 			  MDIO_SERDES_DIGITAL_MISC1, &reg_val);
-	/* clearing the speed value before setting the right speed */
+	/* Clearing the speed value before setting the right speed */
 	DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
 
 	reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
@@ -5007,7 +5076,7 @@ static void bnx2x_set_brcm_cl37_advertisement(struct bnx2x_phy *phy,
 	struct bnx2x *bp = params->bp;
 	u16 val = 0;
 
-	/* set extended capabilities */
+	/* Set extended capabilities */
 	if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
 		val |= MDIO_OVER_1G_UP1_2_5G;
 	if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
@@ -5027,7 +5096,7 @@ static void bnx2x_set_ieee_aneg_advertisement(struct bnx2x_phy *phy,
 {
 	struct bnx2x *bp = params->bp;
 	u16 val;
-	/* for AN, we are always publishing full duplex */
+	/* For AN, we are always publishing full duplex */
 
 	CL22_WR_OVER_CL45(bp, phy,
 			  MDIO_REG_BANK_COMBO_IEEE0,
@@ -5089,14 +5158,14 @@ static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
 	struct bnx2x *bp = params->bp;
 	u16 control1;
 
-	/* in SGMII mode, the unicore is always slave */
+	/* In SGMII mode, the unicore is always slave */
 
 	CL22_RD_OVER_CL45(bp, phy,
 			  MDIO_REG_BANK_SERDES_DIGITAL,
 			  MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
 			  &control1);
 	control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
-	/* set sgmii mode (and not fiber) */
+	/* Set sgmii mode (and not fiber) */
 	control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
 		      MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
 		      MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
@@ -5105,9 +5174,9 @@ static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
 			  MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
 			  control1);
 
-	/* if forced speed */
+	/* If forced speed */
 	if (!(vars->line_speed == SPEED_AUTO_NEG)) {
-		/* set speed, disable autoneg */
+		/* Set speed, disable autoneg */
 		u16 mii_control;
 
 		CL22_RD_OVER_CL45(bp, phy,
@@ -5128,16 +5197,16 @@ static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
 				MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
 			break;
 		case SPEED_10:
-			/* there is nothing to set for 10M */
+			/* There is nothing to set for 10M */
 			break;
 		default:
-			/* invalid speed for SGMII */
+			/* Invalid speed for SGMII */
 			DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
 				  vars->line_speed);
 			break;
 		}
 
-		/* setting the full duplex */
+		/* Setting the full duplex */
 		if (phy->req_duplex == DUPLEX_FULL)
 			mii_control |=
 				MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
@@ -5147,7 +5216,7 @@ static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
 				  mii_control);
 
 	} else { /* AN mode */
-		/* enable and restart AN */
+		/* Enable and restart AN */
 		bnx2x_restart_autoneg(phy, params, 0);
 	}
 }
@@ -5243,7 +5312,7 @@ static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
 	struct bnx2x *bp = params->bp;
 	vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 
-	/* resolve from gp_status in case of AN complete and not sgmii */
+	/* Resolve from gp_status in case of AN complete and not sgmii */
 	if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO) {
 		/* Update the advertised flow-controled of LD/LP in AN */
 		if (phy->req_line_speed == SPEED_AUTO_NEG)
@@ -5467,7 +5536,7 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
 				bnx2x_xgxs_an_resolve(phy, params, vars,
 						      gp_status);
 		}
-	} else { /* link_down */
+	} else { /* Link_down */
 		if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
 		    SINGLE_MEDIA_DIRECT(params)) {
 			/* Check signal is detected */
@@ -5616,12 +5685,12 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params)
 	u16 tx_driver;
 	u16 bank;
 
-	/* read precomp */
+	/* Read precomp */
 	CL22_RD_OVER_CL45(bp, phy,
 			  MDIO_REG_BANK_OVER_1G,
 			  MDIO_OVER_1G_LP_UP2, &lp_up2);
 
-	/* bits [10:7] at lp_up2, positioned at [15:12] */
+	/* Bits [10:7] at lp_up2, positioned at [15:12] */
 	lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
 		   MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
 		  MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
@@ -5635,7 +5704,7 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params)
 				  bank,
 				  MDIO_TX0_TX_DRIVER, &tx_driver);
 
-		/* replace tx_driver bits [15:12] */
+		/* Replace tx_driver bits [15:12] */
 		if (lp_up2 !=
 		    (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
 			tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
@@ -5731,16 +5800,16 @@ static void bnx2x_xgxs_config_init(struct bnx2x_phy *phy,
 		     FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
 			bnx2x_set_preemphasis(phy, params);
 
-		/* forced speed requested? */
+		/* Forced speed requested? */
 		if (vars->line_speed != SPEED_AUTO_NEG ||
 		    (SINGLE_MEDIA_DIRECT(params) &&
 		     params->loopback_mode == LOOPBACK_EXT)) {
 			DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
 
-			/* disable autoneg */
+			/* Disable autoneg */
 			bnx2x_set_autoneg(phy, params, vars, 0);
 
-			/* program speed and duplex */
+			/* Program speed and duplex */
 			bnx2x_program_serdes(phy, params, vars);
 
 		} else { /* AN_mode */
@@ -5749,14 +5818,14 @@ static void bnx2x_xgxs_config_init(struct bnx2x_phy *phy,
 			/* AN enabled */
 			bnx2x_set_brcm_cl37_advertisement(phy, params);
 
-			/* program duplex & pause advertisement (for aneg) */
+			/* Program duplex & pause advertisement (for aneg) */
 			bnx2x_set_ieee_aneg_advertisement(phy, params,
 							  vars->ieee_fc);
 
-			/* enable autoneg */
+			/* Enable autoneg */
 			bnx2x_set_autoneg(phy, params, vars, enable_cl73);
 
-			/* enable and restart AN */
+			/* Enable and restart AN */
 			bnx2x_restart_autoneg(phy, params, enable_cl73);
 		}
 
@@ -5792,12 +5861,12 @@ static int bnx2x_prepare_xgxs(struct bnx2x_phy *phy,
 		bnx2x_set_master_ln(params, phy);
 
 	rc = bnx2x_reset_unicore(params, phy, 0);
-	/* reset the SerDes and wait for reset bit return low */
-	if (rc != 0)
+	/* Reset the SerDes and wait for reset bit return low */
+	if (rc)
 		return rc;
 
 	bnx2x_set_aer_mmd(params, phy);
-	/* setting the masterLn_def again after the reset */
+	/* Setting the masterLn_def again after the reset */
 	if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
 		bnx2x_set_master_ln(params, phy);
 		bnx2x_set_swap_lanes(params, phy);
@@ -5822,7 +5891,7 @@ static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
 				MDIO_PMA_REG_CTRL, &ctrl);
 		if (!(ctrl & (1<<15)))
 			break;
-		msleep(1);
+		usleep_range(1000, 2000);
 	}
 
 	if (cnt == 1000)
@@ -6053,7 +6122,7 @@ static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
 		DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
 
 		if (!CHIP_IS_E3(bp)) {
-			/* change the uni_phy_addr in the nig */
+			/* Change the uni_phy_addr in the nig */
 			md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
 					       port*0x18));
 
@@ -6073,11 +6142,11 @@ static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
 				  (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
 				 0x6041);
 		msleep(200);
-		/* set aer mmd back */
+		/* Set aer mmd back */
 		bnx2x_set_aer_mmd(params, phy);
 
 		if (!CHIP_IS_E3(bp)) {
-			/* and md_devad */
+			/* And md_devad */
 			REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
 			       md_devad);
 		}
@@ -6274,7 +6343,7 @@ int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
 			  MDIO_REG_BANK_GP_STATUS,
 			  MDIO_GP_STATUS_TOP_AN_STATUS1,
 			  &gp_status);
-	/* link is up only if both local phy and external phy are up */
+	/* Link is up only if both local phy and external phy are up */
 	if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
 		return -ESRCH;
 	}
@@ -6295,7 +6364,9 @@ int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
 		for (phy_index = EXT_PHY1; phy_index < params->num_phys;
 		      phy_index++) {
 			serdes_phy_type = ((params->phy[phy_index].media_type ==
-					    ETH_PHY_SFP_FIBER) ||
+					    ETH_PHY_SFPP_10G_FIBER) ||
+					   (params->phy[phy_index].media_type ==
+					    ETH_PHY_SFP_1G_FIBER) ||
 					   (params->phy[phy_index].media_type ==
 					    ETH_PHY_XFP_FIBER) ||
 					   (params->phy[phy_index].media_type ==
@@ -6396,7 +6467,7 @@ static int bnx2x_link_initialize(struct link_params *params,
 static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
 				 struct link_params *params)
 {
-	/* reset the SerDes/XGXS */
+	/* Reset the SerDes/XGXS */
 	REG_WR(params->bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
 	       (0x1ff << (params->port*16)));
 }
@@ -6429,10 +6500,10 @@ static int bnx2x_update_link_down(struct link_params *params,
 	DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
 	bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
 	vars->phy_flags &= ~PHY_PHYSICAL_LINK_FLAG;
-	/* indicate no mac active */
+	/* Indicate no mac active */
 	vars->mac_type = MAC_TYPE_NONE;
 
-	/* update shared memory */
+	/* Update shared memory */
 	vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK |
 			       LINK_STATUS_LINK_UP |
 			       LINK_STATUS_PHYSICAL_LINK_FLAG |
@@ -6445,15 +6516,15 @@ static int bnx2x_update_link_down(struct link_params *params,
 	vars->line_speed = 0;
 	bnx2x_update_mng(params, vars->link_status);
 
-	/* activate nig drain */
+	/* Activate nig drain */
 	REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
 
-	/* disable emac */
+	/* Disable emac */
 	if (!CHIP_IS_E3(bp))
 		REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
 
-	msleep(10);
-	/* reset BigMac/Xmac */
+	usleep_range(10000, 20000);
+	/* Reset BigMac/Xmac */
 	if (CHIP_IS_E1x(bp) ||
 	    CHIP_IS_E2(bp)) {
 		bnx2x_bmac_rx_disable(bp, params->port);
@@ -6462,6 +6533,16 @@ static int bnx2x_update_link_down(struct link_params *params,
 	       (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
 	}
 	if (CHIP_IS_E3(bp)) {
+		/* Prevent LPI Generation by chip */
+		REG_WR(bp, MISC_REG_CPMU_LP_FW_ENABLE_P0 + (params->port << 2),
+		       0);
+		REG_WR(bp, MISC_REG_CPMU_LP_DR_ENABLE, 0);
+		REG_WR(bp, MISC_REG_CPMU_LP_MASK_ENT_P0 + (params->port << 2),
+		       0);
+		vars->eee_status &= ~(SHMEM_EEE_LP_ADV_STATUS_MASK |
+				      SHMEM_EEE_ACTIVE_BIT);
+
+		bnx2x_update_mng_eee(params, vars->eee_status);
 		bnx2x_xmac_disable(params);
 		bnx2x_umac_disable(params);
 	}
@@ -6501,6 +6582,16 @@ static int bnx2x_update_link_up(struct link_params *params,
 			bnx2x_umac_enable(params, vars, 0);
 		bnx2x_set_led(params, vars,
 			      LED_MODE_OPER, vars->line_speed);
+
+		if ((vars->eee_status & SHMEM_EEE_ACTIVE_BIT) &&
+		    (vars->eee_status & SHMEM_EEE_LPI_REQUESTED_BIT)) {
+			DP(NETIF_MSG_LINK, "Enabling LPI assertion\n");
+			REG_WR(bp, MISC_REG_CPMU_LP_FW_ENABLE_P0 +
+			       (params->port << 2), 1);
+			REG_WR(bp, MISC_REG_CPMU_LP_DR_ENABLE, 1);
+			REG_WR(bp, MISC_REG_CPMU_LP_MASK_ENT_P0 +
+			       (params->port << 2), 0xfc20);
+		}
 	}
 	if ((CHIP_IS_E1x(bp) ||
 	     CHIP_IS_E2(bp))) {
@@ -6533,12 +6624,12 @@ static int bnx2x_update_link_up(struct link_params *params,
 		rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
 				       vars->line_speed);
 
-	/* disable drain */
+	/* Disable drain */
 	REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
 
-	/* update shared memory */
+	/* Update shared memory */
 	bnx2x_update_mng(params, vars->link_status);
-
+	bnx2x_update_mng_eee(params, vars->eee_status);
 	/* Check remote fault */
 	for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
 		if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) {
@@ -6582,6 +6673,8 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
 		phy_vars[phy_index].phy_link_up = 0;
 		phy_vars[phy_index].link_up = 0;
 		phy_vars[phy_index].fault_detected = 0;
+		/* different consideration, since vars holds inner state */
+		phy_vars[phy_index].eee_status = vars->eee_status;
 	}
 
 	if (USES_WARPCORE(bp))
@@ -6602,7 +6695,7 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
 	  REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
 	  REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
 
-	/* disable emac */
+	/* Disable emac */
 	if (!CHIP_IS_E3(bp))
 		REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
 
@@ -6711,6 +6804,9 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
 			vars->link_status |= LINK_STATUS_SERDES_LINK;
 		else
 			vars->link_status &= ~LINK_STATUS_SERDES_LINK;
+
+		vars->eee_status = phy_vars[active_external_phy].eee_status;
+
 		DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
 			   active_external_phy);
 	}
@@ -6744,11 +6840,11 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
 		} else if (prev_line_speed != vars->line_speed) {
 			REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4,
 			       0);
-			msleep(1);
+			 usleep_range(1000, 2000);
 		}
 	}
 
-	/* anything 10 and over uses the bmac */
+	/* Anything 10 and over uses the bmac */
 	link_10g_plus = (vars->line_speed >= SPEED_10000);
 
 	bnx2x_link_int_ack(params, vars, link_10g_plus);
@@ -6814,7 +6910,7 @@ void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
 {
 	bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
 		       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
-	msleep(1);
+	 usleep_range(1000, 2000);
 	bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
 		       MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
 }
@@ -6911,7 +7007,7 @@ static int bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
 			 MDIO_PMA_REG_GEN_CTRL,
 			 0x0001);
 
-	/* ucode reboot and rst */
+	/* Ucode reboot and rst */
 	bnx2x_cl45_write(bp, phy,
 			 MDIO_PMA_DEVAD,
 			 MDIO_PMA_REG_GEN_CTRL,
@@ -6955,7 +7051,7 @@ static int bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
 				MDIO_PMA_DEVAD,
 				MDIO_PMA_REG_M8051_MSGOUT_REG, &fw_msgout);
 
-		msleep(1);
+		 usleep_range(1000, 2000);
 	} while (fw_ver1 == 0 || fw_ver1 == 0x4321 ||
 			((fw_msgout & 0xff) != 0x03 && (phy->type ==
 			PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)));
@@ -7049,11 +7145,11 @@ static int bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
 					  "XAUI workaround has completed\n");
 					return 0;
 				 }
-				 msleep(3);
+				 usleep_range(3000, 6000);
 			}
 			break;
 		}
-		msleep(3);
+		usleep_range(3000, 6000);
 	}
 	DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
 	return -EINVAL;
@@ -7127,7 +7223,7 @@ static int bnx2x_8073_config_init(struct bnx2x_phy *phy,
 	bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
 		       MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
 
-	/* enable LASI */
+	/* Enable LASI */
 	bnx2x_cl45_write(bp, phy,
 			 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL, (1<<2));
 	bnx2x_cl45_write(bp, phy,
@@ -7275,7 +7371,7 @@ static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
 
 	DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
 
-	/* clear the interrupt LASI status register */
+	/* Clear the interrupt LASI status register */
 	bnx2x_cl45_read(bp, phy,
 			MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
 	bnx2x_cl45_read(bp, phy,
@@ -7600,7 +7696,7 @@ static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
 	struct bnx2x *bp = params->bp;
 	u16 val = 0;
 	u16 i;
-	if (byte_cnt > 16) {
+	if (byte_cnt > SFP_EEPROM_PAGE_SIZE) {
 		DP(NETIF_MSG_LINK,
 		   "Reading from eeprom is limited to 0xf\n");
 		return -EINVAL;
@@ -7654,11 +7750,33 @@ static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
 		if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
 		    MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
 			return 0;
-		msleep(1);
+		 usleep_range(1000, 2000);
 	}
 	return -EINVAL;
 }
 
+static void bnx2x_warpcore_power_module(struct link_params *params,
+					struct bnx2x_phy *phy,
+					u8 power)
+{
+	u32 pin_cfg;
+	struct bnx2x *bp = params->bp;
+
+	pin_cfg = (REG_RD(bp, params->shmem_base +
+			  offsetof(struct shmem_region,
+			dev_info.port_hw_config[params->port].e3_sfp_ctrl)) &
+			PORT_HW_CFG_E3_PWR_DIS_MASK) >>
+			PORT_HW_CFG_E3_PWR_DIS_SHIFT;
+
+	if (pin_cfg == PIN_CFG_NA)
+		return;
+	DP(NETIF_MSG_LINK, "Setting SFP+ module power to %d using pin cfg %d\n",
+		       power, pin_cfg);
+	/* Low ==> corresponding SFP+ module is powered
+	 * high ==> the SFP+ module is powered down
+	 */
+	bnx2x_set_cfg_pin(bp, pin_cfg, power ^ 1);
+}
 static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
 						 struct link_params *params,
 						 u16 addr, u8 byte_cnt,
@@ -7669,7 +7787,8 @@ static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
 	u32 data_array[4];
 	u16 addr32;
 	struct bnx2x *bp = params->bp;
-	if (byte_cnt > 16) {
+
+	if (byte_cnt > SFP_EEPROM_PAGE_SIZE) {
 		DP(NETIF_MSG_LINK,
 		   "Reading from eeprom is limited to 16 bytes\n");
 		return -EINVAL;
@@ -7678,6 +7797,12 @@ static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
 	/* 4 byte aligned address */
 	addr32 = addr & (~0x3);
 	do {
+		if (cnt == I2C_WA_PWR_ITER) {
+			bnx2x_warpcore_power_module(params, phy, 0);
+			/* Note that 100us are not enough here */
+			usleep_range(1000,1000);
+			bnx2x_warpcore_power_module(params, phy, 1);
+		}
 		rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt,
 				    data_array);
 	} while ((rc != 0) && (++cnt < I2C_WA_RETRY_CNT));
@@ -7699,7 +7824,7 @@ static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
 	struct bnx2x *bp = params->bp;
 	u16 val, i;
 
-	if (byte_cnt > 16) {
+	if (byte_cnt > SFP_EEPROM_PAGE_SIZE) {
 		DP(NETIF_MSG_LINK,
 		   "Reading from eeprom is limited to 0xf\n");
 		return -EINVAL;
@@ -7736,7 +7861,7 @@ static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
 	/* Wait appropriate time for two-wire command to finish before
 	 * polling the status register
 	 */
-	msleep(1);
+	 usleep_range(1000, 2000);
 
 	/* Wait up to 500us for command complete status */
 	for (i = 0; i < 100; i++) {
@@ -7772,7 +7897,7 @@ static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
 		if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
 		    MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
 			return 0;
-		msleep(1);
+		 usleep_range(1000, 2000);
 	}
 
 	return -EINVAL;
@@ -7782,7 +7907,7 @@ int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
 				 struct link_params *params, u16 addr,
 				 u8 byte_cnt, u8 *o_buf)
 {
-	int rc = -EINVAL;
+	int rc = -EOPNOTSUPP;
 	switch (phy->type) {
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
 		rc = bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
@@ -7807,7 +7932,7 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
 {
 	struct bnx2x *bp = params->bp;
 	u32 sync_offset = 0, phy_idx, media_types;
-	u8 val, check_limiting_mode = 0;
+	u8 val[2], check_limiting_mode = 0;
 	*edc_mode = EDC_MODE_LIMITING;
 
 	phy->media_type = ETH_PHY_UNSPECIFIED;
@@ -7815,13 +7940,13 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
 	if (bnx2x_read_sfp_module_eeprom(phy,
 					 params,
 					 SFP_EEPROM_CON_TYPE_ADDR,
-					 1,
-					 &val) != 0) {
+					 2,
+					 (u8 *)val) != 0) {
 		DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
 		return -EINVAL;
 	}
 
-	switch (val) {
+	switch (val[0]) {
 	case SFP_EEPROM_CON_TYPE_VAL_COPPER:
 	{
 		u8 copper_module_type;
@@ -7859,13 +7984,29 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
 		break;
 	}
 	case SFP_EEPROM_CON_TYPE_VAL_LC:
-		phy->media_type = ETH_PHY_SFP_FIBER;
-		DP(NETIF_MSG_LINK, "Optic module detected\n");
 		check_limiting_mode = 1;
+		if ((val[1] & (SFP_EEPROM_COMP_CODE_SR_MASK |
+			       SFP_EEPROM_COMP_CODE_LR_MASK |
+			       SFP_EEPROM_COMP_CODE_LRM_MASK)) == 0) {
+			DP(NETIF_MSG_LINK, "1G Optic module detected\n");
+			phy->media_type = ETH_PHY_SFP_1G_FIBER;
+			phy->req_line_speed = SPEED_1000;
+		} else {
+			int idx, cfg_idx = 0;
+			DP(NETIF_MSG_LINK, "10G Optic module detected\n");
+			for (idx = INT_PHY; idx < MAX_PHYS; idx++) {
+				if (params->phy[idx].type == phy->type) {
+					cfg_idx = LINK_CONFIG_IDX(idx);
+					break;
+				}
+			}
+			phy->media_type = ETH_PHY_SFPP_10G_FIBER;
+			phy->req_line_speed = params->req_line_speed[cfg_idx];
+		}
 		break;
 	default:
 		DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
-			 val);
+			 val[0]);
 		return -EINVAL;
 	}
 	sync_offset = params->shmem_base +
@@ -7951,7 +8092,7 @@ static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
 		return 0;
 	}
 
-	/* format the warning message */
+	/* Format the warning message */
 	if (bnx2x_read_sfp_module_eeprom(phy,
 					 params,
 					 SFP_EEPROM_VENDOR_NAME_ADDR,
@@ -7997,7 +8138,7 @@ static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
 			   timeout * 5);
 			return 0;
 		}
-		msleep(5);
+		usleep_range(5000, 10000);
 	}
 	return -EINVAL;
 }
@@ -8200,29 +8341,6 @@ static void bnx2x_set_sfp_module_fault_led(struct link_params *params,
 		bnx2x_set_e1e2_module_fault_led(params, gpio_mode);
 }
 
-static void bnx2x_warpcore_power_module(struct link_params *params,
-					struct bnx2x_phy *phy,
-					u8 power)
-{
-	u32 pin_cfg;
-	struct bnx2x *bp = params->bp;
-
-	pin_cfg = (REG_RD(bp, params->shmem_base +
-			  offsetof(struct shmem_region,
-			dev_info.port_hw_config[params->port].e3_sfp_ctrl)) &
-			PORT_HW_CFG_E3_PWR_DIS_MASK) >>
-			PORT_HW_CFG_E3_PWR_DIS_SHIFT;
-
-	if (pin_cfg == PIN_CFG_NA)
-		return;
-	DP(NETIF_MSG_LINK, "Setting SFP+ module power to %d using pin cfg %d\n",
-		       power, pin_cfg);
-	/* Low ==> corresponding SFP+ module is powered
-	 * high ==> the SFP+ module is powered down
-	 */
-	bnx2x_set_cfg_pin(bp, pin_cfg, power ^ 1);
-}
-
 static void bnx2x_warpcore_hw_reset(struct bnx2x_phy *phy,
 				    struct link_params *params)
 {
@@ -8332,7 +8450,7 @@ int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
 		DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
 		return -EINVAL;
 	} else if (bnx2x_verify_sfp_module(phy, params) != 0) {
-		/* check SFP+ module compatibility */
+		/* Check SFP+ module compatibility */
 		DP(NETIF_MSG_LINK, "Module verification failed!!\n");
 		rc = -EINVAL;
 		/* Turn on fault module-detected led */
@@ -8395,14 +8513,34 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
 
 	/* Call the handling function in case module is detected */
 	if (gpio_val == 0) {
+		bnx2x_set_mdio_clk(bp, params->chip_id, params->port);
+		bnx2x_set_aer_mmd(params, phy);
+
 		bnx2x_power_sfp_module(params, phy, 1);
 		bnx2x_set_gpio_int(bp, gpio_num,
 				   MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
 				   gpio_port);
-		if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
+		if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0) {
 			bnx2x_sfp_module_detection(phy, params);
-		else
+			if (CHIP_IS_E3(bp)) {
+				u16 rx_tx_in_reset;
+				/* In case WC is out of reset, reconfigure the
+				 * link speed while taking into account 1G
+				 * module limitation.
+				 */
+				bnx2x_cl45_read(bp, phy,
+						MDIO_WC_DEVAD,
+						MDIO_WC_REG_DIGITAL5_MISC6,
+						&rx_tx_in_reset);
+				if (!rx_tx_in_reset) {
+					bnx2x_warpcore_reset_lane(bp, phy, 1);
+					bnx2x_warpcore_config_sfi(phy, params);
+					bnx2x_warpcore_reset_lane(bp, phy, 0);
+				}
+			}
+		} else {
 			DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
+		}
 	} else {
 		u32 val = REG_RD(bp, params->shmem_base +
 				 offsetof(struct shmem_region, dev_info.
@@ -8463,7 +8601,7 @@ static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
 	bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_LASI_TXSTAT,
 			     MDIO_PMA_LASI_TXCTRL);
 
-	/* clear LASI indication*/
+	/* Clear LASI indication*/
 	bnx2x_cl45_read(bp, phy,
 			MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val1);
 	bnx2x_cl45_read(bp, phy,
@@ -8531,7 +8669,7 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
 				MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
 		if (val)
 			break;
-		msleep(10);
+		usleep_range(10000, 20000);
 	}
 	DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
 	if ((params->feature_config_flags &
@@ -8660,7 +8798,7 @@ static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
 			 MDIO_PMA_REG_GEN_CTRL,
 			 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
 
-	/* wait for 150ms for microcode load */
+	/* Wait for 150ms for microcode load */
 	msleep(150);
 
 	/* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
@@ -8854,6 +8992,63 @@ static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
 		       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
 }
 
+static void bnx2x_8727_config_speed(struct bnx2x_phy *phy,
+				    struct link_params *params)
+{
+	struct bnx2x *bp = params->bp;
+	u16 tmp1, val;
+	/* Set option 1G speed */
+	if ((phy->req_line_speed == SPEED_1000) ||
+	    (phy->media_type == ETH_PHY_SFP_1G_FIBER)) {
+		DP(NETIF_MSG_LINK, "Setting 1G force\n");
+		bnx2x_cl45_write(bp, phy,
+				 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
+		bnx2x_cl45_write(bp, phy,
+				 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
+		bnx2x_cl45_read(bp, phy,
+				MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
+		DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
+		/* Power down the XAUI until link is up in case of dual-media
+		 * and 1G
+		 */
+		if (DUAL_MEDIA(params)) {
+			bnx2x_cl45_read(bp, phy,
+					MDIO_PMA_DEVAD,
+					MDIO_PMA_REG_8727_PCS_GP, &val);
+			val |= (3<<10);
+			bnx2x_cl45_write(bp, phy,
+					 MDIO_PMA_DEVAD,
+					 MDIO_PMA_REG_8727_PCS_GP, val);
+		}
+	} else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
+		   ((phy->speed_cap_mask &
+		     PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
+		   ((phy->speed_cap_mask &
+		      PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
+		   PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
+
+		DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
+		bnx2x_cl45_write(bp, phy,
+				 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
+		bnx2x_cl45_write(bp, phy,
+				 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
+	} else {
+		/* Since the 8727 has only single reset pin, need to set the 10G
+		 * registers although it is default
+		 */
+		bnx2x_cl45_write(bp, phy,
+				 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
+				 0x0020);
+		bnx2x_cl45_write(bp, phy,
+				 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
+		bnx2x_cl45_write(bp, phy,
+				 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
+		bnx2x_cl45_write(bp, phy,
+				 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
+				 0x0008);
+	}
+}
+
 static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
 				  struct link_params *params,
 				  struct link_vars *vars)
@@ -8871,7 +9066,7 @@ static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
 	lasi_ctrl_val = 0x0006;
 
 	DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
-	/* enable LASI */
+	/* Enable LASI */
 	bnx2x_cl45_write(bp, phy,
 			 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL,
 			 rx_alarm_ctrl_val);
@@ -8923,56 +9118,7 @@ static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
 	bnx2x_cl45_read(bp, phy,
 			MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT, &tmp1);
 
-	/* Set option 1G speed */
-	if (phy->req_line_speed == SPEED_1000) {
-		DP(NETIF_MSG_LINK, "Setting 1G force\n");
-		bnx2x_cl45_write(bp, phy,
-				 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
-		bnx2x_cl45_write(bp, phy,
-				 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
-		bnx2x_cl45_read(bp, phy,
-				MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
-		DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
-		/* Power down the XAUI until link is up in case of dual-media
-		 * and 1G
-		 */
-		if (DUAL_MEDIA(params)) {
-			bnx2x_cl45_read(bp, phy,
-					MDIO_PMA_DEVAD,
-					MDIO_PMA_REG_8727_PCS_GP, &val);
-			val |= (3<<10);
-			bnx2x_cl45_write(bp, phy,
-					 MDIO_PMA_DEVAD,
-					 MDIO_PMA_REG_8727_PCS_GP, val);
-		}
-	} else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
-		   ((phy->speed_cap_mask &
-		     PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
-		   ((phy->speed_cap_mask &
-		      PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
-		   PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
-
-		DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
-		bnx2x_cl45_write(bp, phy,
-				 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
-		bnx2x_cl45_write(bp, phy,
-				 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
-	} else {
-		/* Since the 8727 has only single reset pin, need to set the 10G
-		 * registers although it is default
-		 */
-		bnx2x_cl45_write(bp, phy,
-				 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
-				 0x0020);
-		bnx2x_cl45_write(bp, phy,
-				 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
-		bnx2x_cl45_write(bp, phy,
-				 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
-		bnx2x_cl45_write(bp, phy,
-				 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
-				 0x0008);
-	}
-
+	bnx2x_8727_config_speed(phy, params);
 	/* Set 2-wire transfer rate of SFP+ module EEPROM
 	 * to 100Khz since some DACs(direct attached cables) do
 	 * not work at 400Khz.
@@ -9099,6 +9245,9 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
 			bnx2x_sfp_module_detection(phy, params);
 		else
 			DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
+
+		/* Reconfigure link speed based on module type limitations */
+		bnx2x_8727_config_speed(phy, params);
 	}
 
 	DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
@@ -9579,9 +9728,9 @@ static int bnx2x_8481_config_init(struct bnx2x_phy *phy,
 static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
 				   struct link_params *params,
 		   u16 fw_cmd,
-		   u16 cmd_args[])
+		   u16 cmd_args[], int argc)
 {
-	u32 idx;
+	int idx;
 	u16 val;
 	struct bnx2x *bp = params->bp;
 	/* Write CMD_OPEN_OVERRIDE to STATUS reg */
@@ -9593,7 +9742,7 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
 				MDIO_84833_CMD_HDLR_STATUS, &val);
 		if (val == PHY84833_STATUS_CMD_OPEN_FOR_CMDS)
 			break;
-		msleep(1);
+		 usleep_range(1000, 2000);
 	}
 	if (idx >= PHY84833_CMDHDLR_WAIT) {
 		DP(NETIF_MSG_LINK, "FW cmd: FW not ready.\n");
@@ -9601,7 +9750,7 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
 	}
 
 	/* Prepare argument(s) and issue command */
-	for (idx = 0; idx < PHY84833_CMDHDLR_MAX_ARGS; idx++) {
+	for (idx = 0; idx < argc; idx++) {
 		bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
 				MDIO_84833_CMD_HDLR_DATA1 + idx,
 				cmd_args[idx]);
@@ -9614,7 +9763,7 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
 		if ((val == PHY84833_STATUS_CMD_COMPLETE_PASS) ||
 			(val == PHY84833_STATUS_CMD_COMPLETE_ERROR))
 			break;
-		msleep(1);
+		 usleep_range(1000, 2000);
 	}
 	if ((idx >= PHY84833_CMDHDLR_WAIT) ||
 		(val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) {
@@ -9622,7 +9771,7 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
 		return -EINVAL;
 	}
 	/* Gather returning data */
-	for (idx = 0; idx < PHY84833_CMDHDLR_MAX_ARGS; idx++) {
+	for (idx = 0; idx < argc; idx++) {
 		bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
 				MDIO_84833_CMD_HDLR_DATA1 + idx,
 				&cmd_args[idx]);
@@ -9656,7 +9805,7 @@ static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy,
 	data[1] = (u16)pair_swap;
 
 	status = bnx2x_84833_cmd_hdlr(phy, params,
-		PHY84833_CMD_SET_PAIR_SWAP, data);
+		PHY84833_CMD_SET_PAIR_SWAP, data, PHY84833_CMDHDLR_MAX_ARGS);
 	if (status == 0)
 		DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data[1]);
 
@@ -9734,6 +9883,95 @@ static int bnx2x_84833_hw_reset_phy(struct bnx2x_phy *phy,
 	return 0;
 }
 
+static int bnx2x_8483x_eee_timers(struct link_params *params,
+				   struct link_vars *vars)
+{
+	u32 eee_idle = 0, eee_mode;
+	struct bnx2x *bp = params->bp;
+
+	eee_idle = bnx2x_eee_calc_timer(params);
+
+	if (eee_idle) {
+		REG_WR(bp, MISC_REG_CPMU_LP_IDLE_THR_P0 + (params->port << 2),
+		       eee_idle);
+	} else if ((params->eee_mode & EEE_MODE_ENABLE_LPI) &&
+		   (params->eee_mode & EEE_MODE_OVERRIDE_NVRAM) &&
+		   (params->eee_mode & EEE_MODE_OUTPUT_TIME)) {
+		DP(NETIF_MSG_LINK, "Error: Tx LPI is enabled with timer 0\n");
+		return -EINVAL;
+	}
+
+	vars->eee_status &= ~(SHMEM_EEE_TIMER_MASK | SHMEM_EEE_TIME_OUTPUT_BIT);
+	if (params->eee_mode & EEE_MODE_OUTPUT_TIME) {
+		/* eee_idle in 1u --> eee_status in 16u */
+		eee_idle >>= 4;
+		vars->eee_status |= (eee_idle & SHMEM_EEE_TIMER_MASK) |
+				    SHMEM_EEE_TIME_OUTPUT_BIT;
+	} else {
+		if (bnx2x_eee_time_to_nvram(eee_idle, &eee_mode))
+			return -EINVAL;
+		vars->eee_status |= eee_mode;
+	}
+
+	return 0;
+}
+
+static int bnx2x_8483x_disable_eee(struct bnx2x_phy *phy,
+				   struct link_params *params,
+				   struct link_vars *vars)
+{
+	int rc;
+	struct bnx2x *bp = params->bp;
+	u16 cmd_args = 0;
+
+	DP(NETIF_MSG_LINK, "Don't Advertise 10GBase-T EEE\n");
+
+	/* Make Certain LPI is disabled */
+	REG_WR(bp, MISC_REG_CPMU_LP_FW_ENABLE_P0 + (params->port << 2), 0);
+	REG_WR(bp, MISC_REG_CPMU_LP_DR_ENABLE, 0);
+
+	/* Prevent Phy from working in EEE and advertising it */
+	rc = bnx2x_84833_cmd_hdlr(phy, params,
+		PHY84833_CMD_SET_EEE_MODE, &cmd_args, 1);
+	if (rc) {
+		DP(NETIF_MSG_LINK, "EEE disable failed.\n");
+		return rc;
+	}
+
+	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_EEE_ADV, 0);
+	vars->eee_status &= ~SHMEM_EEE_ADV_STATUS_MASK;
+
+	return 0;
+}
+
+static int bnx2x_8483x_enable_eee(struct bnx2x_phy *phy,
+				   struct link_params *params,
+				   struct link_vars *vars)
+{
+	int rc;
+	struct bnx2x *bp = params->bp;
+	u16 cmd_args = 1;
+
+	DP(NETIF_MSG_LINK, "Advertise 10GBase-T EEE\n");
+
+	rc = bnx2x_84833_cmd_hdlr(phy, params,
+		PHY84833_CMD_SET_EEE_MODE, &cmd_args, 1);
+	if (rc) {
+		DP(NETIF_MSG_LINK, "EEE enable failed.\n");
+		return rc;
+	}
+
+	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_EEE_ADV, 0x8);
+
+	/* Mask events preventing LPI generation */
+	REG_WR(bp, MISC_REG_CPMU_LP_MASK_EXT_P0 + (params->port << 2), 0xfc20);
+
+	vars->eee_status &= ~SHMEM_EEE_ADV_STATUS_MASK;
+	vars->eee_status |= (SHMEM_EEE_10G_ADV << SHMEM_EEE_ADV_STATUS_SHIFT);
+
+	return 0;
+}
+
 #define PHY84833_CONSTANT_LATENCY 1193
 static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
 				   struct link_params *params,
@@ -9746,9 +9984,9 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
 	u16 cmd_args[PHY84833_CMDHDLR_MAX_ARGS];
 	int rc = 0;
 
-	msleep(1);
+	 usleep_range(1000, 2000);
 
-	if (!(CHIP_IS_E1(bp)))
+	if (!(CHIP_IS_E1x(bp)))
 		port = BP_PATH(bp);
 	else
 		port = params->port;
@@ -9833,8 +10071,9 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
 		cmd_args[2] = PHY84833_CONSTANT_LATENCY + 1;
 		cmd_args[3] = PHY84833_CONSTANT_LATENCY;
 		rc = bnx2x_84833_cmd_hdlr(phy, params,
-			PHY84833_CMD_SET_EEE_MODE, cmd_args);
-		if (rc != 0)
+			PHY84833_CMD_SET_EEE_MODE, cmd_args,
+			PHY84833_CMDHDLR_MAX_ARGS);
+		if (rc)
 			DP(NETIF_MSG_LINK, "Cfg AutogrEEEn failed.\n");
 	}
 	if (initialize)
@@ -9858,6 +10097,48 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
 				 MDIO_CTL_REG_84823_USER_CTRL_REG, val);
 	}
 
+	bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
+			MDIO_84833_TOP_CFG_FW_REV, &val);
+
+	/* Configure EEE support */
+	if ((val >= MDIO_84833_TOP_CFG_FW_EEE) && bnx2x_eee_has_cap(params)) {
+		phy->flags |= FLAGS_EEE_10GBT;
+		vars->eee_status |= SHMEM_EEE_10G_ADV <<
+				    SHMEM_EEE_SUPPORTED_SHIFT;
+		/* Propogate params' bits --> vars (for migration exposure) */
+		if (params->eee_mode & EEE_MODE_ENABLE_LPI)
+			vars->eee_status |= SHMEM_EEE_LPI_REQUESTED_BIT;
+		else
+			vars->eee_status &= ~SHMEM_EEE_LPI_REQUESTED_BIT;
+
+		if (params->eee_mode & EEE_MODE_ADV_LPI)
+			vars->eee_status |= SHMEM_EEE_REQUESTED_BIT;
+		else
+			vars->eee_status &= ~SHMEM_EEE_REQUESTED_BIT;
+
+		rc = bnx2x_8483x_eee_timers(params, vars);
+		if (rc) {
+			DP(NETIF_MSG_LINK, "Failed to configure EEE timers\n");
+			bnx2x_8483x_disable_eee(phy, params, vars);
+			return rc;
+		}
+
+		if ((params->req_duplex[actual_phy_selection] == DUPLEX_FULL) &&
+		    (params->eee_mode & EEE_MODE_ADV_LPI) &&
+		    (bnx2x_eee_calc_timer(params) ||
+		     !(params->eee_mode & EEE_MODE_ENABLE_LPI)))
+			rc = bnx2x_8483x_enable_eee(phy, params, vars);
+		else
+			rc = bnx2x_8483x_disable_eee(phy, params, vars);
+		if (rc) {
+			DP(NETIF_MSG_LINK, "Failed to set EEE advertisment\n");
+			return rc;
+		}
+	} else {
+		phy->flags &= ~FLAGS_EEE_10GBT;
+		vars->eee_status &= ~SHMEM_EEE_SUPPORTED_MASK;
+	}
+
 	if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
 		/* Bring PHY out of super isolate mode as the final step. */
 		bnx2x_cl45_read(bp, phy,
@@ -9912,17 +10193,19 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
 		DP(NETIF_MSG_LINK, "Legacy speed status = 0x%x\n",
 		   legacy_status);
 		link_up = ((legacy_status & (1<<11)) == (1<<11));
-		if (link_up) {
-			legacy_speed = (legacy_status & (3<<9));
-			if (legacy_speed == (0<<9))
-				vars->line_speed = SPEED_10;
-			else if (legacy_speed == (1<<9))
-				vars->line_speed = SPEED_100;
-			else if (legacy_speed == (2<<9))
-				vars->line_speed = SPEED_1000;
-			else /* Should not happen */
-				vars->line_speed = 0;
+		legacy_speed = (legacy_status & (3<<9));
+		if (legacy_speed == (0<<9))
+			vars->line_speed = SPEED_10;
+		else if (legacy_speed == (1<<9))
+			vars->line_speed = SPEED_100;
+		else if (legacy_speed == (2<<9))
+			vars->line_speed = SPEED_1000;
+		else { /* Should not happen: Treat as link down */
+			vars->line_speed = 0;
+			link_up = 0;
+		}
 
+		if (link_up) {
 			if (legacy_status & (1<<8))
 				vars->duplex = DUPLEX_FULL;
 			else
@@ -9950,7 +10233,7 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
 		}
 	}
 	if (link_up) {
-		DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
+		DP(NETIF_MSG_LINK, "BCM848x3: link speed is %d\n",
 			   vars->line_speed);
 		bnx2x_ext_phy_resolve_fc(phy, params, vars);
 
@@ -9989,6 +10272,31 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
 		if (val & (1<<11))
 			vars->link_status |=
 				LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
+
+		/* Determine if EEE was negotiated */
+		if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
+			u32 eee_shmem = 0;
+
+			bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+					MDIO_AN_REG_EEE_ADV, &val1);
+			bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+					MDIO_AN_REG_LP_EEE_ADV, &val2);
+			if ((val1 & val2) & 0x8) {
+				DP(NETIF_MSG_LINK, "EEE negotiated\n");
+				vars->eee_status |= SHMEM_EEE_ACTIVE_BIT;
+			}
+
+			if (val2 & 0x12)
+				eee_shmem |= SHMEM_EEE_100M_ADV;
+			if (val2 & 0x4)
+				eee_shmem |= SHMEM_EEE_1G_ADV;
+			if (val2 & 0x68)
+				eee_shmem |= SHMEM_EEE_10G_ADV;
+
+			vars->eee_status &= ~SHMEM_EEE_LP_ADV_STATUS_MASK;
+			vars->eee_status |= (eee_shmem <<
+					     SHMEM_EEE_LP_ADV_STATUS_SHIFT);
+		}
 	}
 
 	return link_up;
@@ -10267,7 +10575,7 @@ static int bnx2x_54618se_config_init(struct bnx2x_phy *phy,
 	u32 cfg_pin;
 
 	DP(NETIF_MSG_LINK, "54618SE cfg init\n");
-	usleep_range(1000, 1000);
+	usleep_range(1000, 2000);
 
 	/* This works with E3 only, no need to check the chip
 	 * before determining the port.
@@ -10336,7 +10644,7 @@ static int bnx2x_54618se_config_init(struct bnx2x_phy *phy,
 			MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH)
 		fc_val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
 
-	/* read all advertisement */
+	/* Read all advertisement */
 	bnx2x_cl22_read(bp, phy,
 			0x09,
 			&an_1000_val);
@@ -10373,7 +10681,7 @@ static int bnx2x_54618se_config_init(struct bnx2x_phy *phy,
 			0x09,
 			&an_1000_val);
 
-	/* set 100 speed advertisement */
+	/* Set 100 speed advertisement */
 	if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
 			(phy->speed_cap_mask &
 			(PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
@@ -10387,7 +10695,7 @@ static int bnx2x_54618se_config_init(struct bnx2x_phy *phy,
 		DP(NETIF_MSG_LINK, "Advertising 100M\n");
 	}
 
-	/* set 10 speed advertisement */
+	/* Set 10 speed advertisement */
 	if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
 			(phy->speed_cap_mask &
 			(PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
@@ -10526,7 +10834,7 @@ static u8 bnx2x_54618se_read_status(struct bnx2x_phy *phy,
 
 	/* Get speed operation status */
 	bnx2x_cl22_read(bp, phy,
-			0x19,
+			MDIO_REG_GPHY_AUX_STATUS,
 			&legacy_status);
 	DP(NETIF_MSG_LINK, "54618SE read_status: 0x%x\n", legacy_status);
 
@@ -10753,7 +11061,7 @@ static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
 	DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
 		   val2, val1);
 	link_up = ((val1 & 4) == 4);
-	/* if link is up print the AN outcome of the SFX7101 PHY */
+	/* If link is up print the AN outcome of the SFX7101 PHY */
 	if (link_up) {
 		bnx2x_cl45_read(bp, phy,
 				MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
@@ -10765,7 +11073,7 @@ static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
 		bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
 		bnx2x_ext_phy_resolve_fc(phy, params, vars);
 
-		/* read LP advertised speeds */
+		/* Read LP advertised speeds */
 		if (val2 & (1<<11))
 			vars->link_status |=
 				LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
@@ -11084,7 +11392,7 @@ static struct bnx2x_phy phy_8706 = {
 			   SUPPORTED_FIBRE |
 			   SUPPORTED_Pause |
 			   SUPPORTED_Asym_Pause),
-	.media_type	= ETH_PHY_SFP_FIBER,
+	.media_type	= ETH_PHY_SFPP_10G_FIBER,
 	.ver_addr	= 0,
 	.req_flow_ctrl	= 0,
 	.req_line_speed	= 0,
@@ -11243,7 +11551,8 @@ static struct bnx2x_phy phy_84833 = {
 	.def_md_devad	= 0,
 	.flags		= (FLAGS_FAN_FAILURE_DET_REQ |
 			   FLAGS_REARM_LATCH_SIGNAL |
-			   FLAGS_TX_ERROR_CHECK),
+			   FLAGS_TX_ERROR_CHECK |
+			   FLAGS_EEE_10GBT),
 	.rx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
 	.tx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
 	.mdio_ctrl	= 0,
@@ -11422,7 +11731,7 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
 					   SUPPORTED_FIBRE |
 					   SUPPORTED_Pause |
 					   SUPPORTED_Asym_Pause);
-			phy->media_type = ETH_PHY_SFP_FIBER;
+			phy->media_type = ETH_PHY_SFPP_10G_FIBER;
 			break;
 		case PORT_HW_CFG_NET_SERDES_IF_KR:
 			phy->media_type = ETH_PHY_KR;
@@ -11962,7 +12271,7 @@ int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
 	vars->mac_type = MAC_TYPE_NONE;
 	vars->phy_flags = 0;
 
-	/* disable attentions */
+	/* Disable attentions */
 	bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
 		       (NIG_MASK_XGXS0_LINK_STATUS |
 			NIG_MASK_XGXS0_LINK10G |
@@ -12011,6 +12320,8 @@ int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
 		break;
 	}
 	bnx2x_update_mng(params, vars->link_status);
+
+	bnx2x_update_mng_eee(params, vars->eee_status);
 	return 0;
 }
 
@@ -12020,19 +12331,22 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
 	struct bnx2x *bp = params->bp;
 	u8 phy_index, port = params->port, clear_latch_ind = 0;
 	DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
-	/* disable attentions */
+	/* Disable attentions */
 	vars->link_status = 0;
 	bnx2x_update_mng(params, vars->link_status);
+	vars->eee_status &= ~(SHMEM_EEE_LP_ADV_STATUS_MASK |
+			      SHMEM_EEE_ACTIVE_BIT);
+	bnx2x_update_mng_eee(params, vars->eee_status);
 	bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
 		       (NIG_MASK_XGXS0_LINK_STATUS |
 			NIG_MASK_XGXS0_LINK10G |
 			NIG_MASK_SERDES0_LINK_STATUS |
 			NIG_MASK_MI_INT));
 
-	/* activate nig drain */
+	/* Activate nig drain */
 	REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
 
-	/* disable nig egress interface */
+	/* Disable nig egress interface */
 	if (!CHIP_IS_E3(bp)) {
 		REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
 		REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
@@ -12045,15 +12359,15 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
 		bnx2x_xmac_disable(params);
 		bnx2x_umac_disable(params);
 	}
-	/* disable emac */
+	/* Disable emac */
 	if (!CHIP_IS_E3(bp))
 		REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
 
-	msleep(10);
+	usleep_range(10000, 20000);
 	/* The PHY reset is controlled by GPIO 1
 	 * Hold it as vars low
 	 */
-	 /* clear link led */
+	 /* Clear link led */
 	bnx2x_set_mdio_clk(bp, params->chip_id, port);
 	bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
 
@@ -12083,9 +12397,9 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
 		params->phy[INT_PHY].link_reset(
 			&params->phy[INT_PHY], params);
 
-	/* disable nig ingress interface */
+	/* Disable nig ingress interface */
 	if (!CHIP_IS_E3(bp)) {
-		/* reset BigMac */
+		/* Reset BigMac */
 		REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
 		       (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
 		REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
@@ -12142,7 +12456,7 @@ static int bnx2x_8073_common_init_phy(struct bnx2x *bp,
 			DP(NETIF_MSG_LINK, "populate_phy failed\n");
 			return -EINVAL;
 		}
-		/* disable attentions */
+		/* Disable attentions */
 		bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
 			       port_of_path*4,
 			       (NIG_MASK_XGXS0_LINK_STATUS |
@@ -12216,7 +12530,7 @@ static int bnx2x_8073_common_init_phy(struct bnx2x *bp,
 		bnx2x_cl45_write(bp, phy_blk[port],
 				MDIO_PMA_DEVAD,
 				MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
-		msleep(15);
+		usleep_range(15000, 30000);
 
 		/* Read modify write the SPI-ROM version select register */
 		bnx2x_cl45_read(bp, phy_blk[port],
@@ -12248,7 +12562,7 @@ static int bnx2x_8726_common_init_phy(struct bnx2x *bp,
 	REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
 
 	bnx2x_ext_phy_hw_reset(bp, 0);
-	msleep(5);
+	usleep_range(5000, 10000);
 	for (port = 0; port < PORT_MAX; port++) {
 		u32 shmem_base, shmem2_base;
 
@@ -12355,11 +12669,11 @@ static int bnx2x_8727_common_init_phy(struct bnx2x *bp,
 	/* Initiate PHY reset*/
 	bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_LOW,
 		       port);
-	msleep(1);
+	 usleep_range(1000, 2000);
 	bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_HIGH,
 		       port);
 
-	msleep(5);
+	usleep_range(5000, 10000);
 
 	/* PART1 - Reset both phys */
 	for (port = PORT_MAX - 1; port >= PORT_0; port--) {
@@ -12453,7 +12767,7 @@ static int bnx2x_84833_pre_init_phy(struct bnx2x *bp,
 				MDIO_PMA_REG_CTRL, &val);
 		if (!(val & (1<<15)))
 			break;
-		msleep(1);
+		 usleep_range(1000, 2000);
 	}
 	if (cnt >= 1500) {
 		DP(NETIF_MSG_LINK, "84833 reset timeout\n");
@@ -12543,7 +12857,7 @@ static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
 		break;
 	}
 
-	if (rc != 0)
+	if (rc)
 		netdev_err(bp->dev,  "Warning: PHY was not initialized,"
 				      " Port %d\n",
 			 0);
@@ -12624,30 +12938,41 @@ static void bnx2x_check_over_curr(struct link_params *params,
 		vars->phy_flags &= ~PHY_OVER_CURRENT_FLAG;
 }
 
-static void bnx2x_analyze_link_error(struct link_params *params,
-				     struct link_vars *vars, u32 lss_status,
-				     u8 notify)
+/* Returns 0 if no change occured since last check; 1 otherwise. */
+static u8 bnx2x_analyze_link_error(struct link_params *params,
+				    struct link_vars *vars, u32 status,
+				    u32 phy_flag, u32 link_flag, u8 notify)
 {
 	struct bnx2x *bp = params->bp;
 	/* Compare new value with previous value */
 	u8 led_mode;
-	u32 half_open_conn = (vars->phy_flags & PHY_HALF_OPEN_CONN_FLAG) > 0;
+	u32 old_status = (vars->phy_flags & phy_flag) ? 1 : 0;
 
-	if ((lss_status ^ half_open_conn) == 0)
-		return;
+	if ((status ^ old_status) == 0)
+		return 0;
 
 	/* If values differ */
-	DP(NETIF_MSG_LINK, "Link changed:%x %x->%x\n", vars->link_up,
-		       half_open_conn, lss_status);
+	switch (phy_flag) {
+	case PHY_HALF_OPEN_CONN_FLAG:
+		DP(NETIF_MSG_LINK, "Analyze Remote Fault\n");
+		break;
+	case PHY_SFP_TX_FAULT_FLAG:
+		DP(NETIF_MSG_LINK, "Analyze TX Fault\n");
+		break;
+	default:
+		DP(NETIF_MSG_LINK, "Analyze UNKOWN\n");
+	}
+	DP(NETIF_MSG_LINK, "Link changed:[%x %x]->%x\n", vars->link_up,
+	   old_status, status);
 
 	/* a. Update shmem->link_status accordingly
 	 * b. Update link_vars->link_up
 	 */
-	if (lss_status) {
-		DP(NETIF_MSG_LINK, "Remote Fault detected !!!\n");
+	if (status) {
 		vars->link_status &= ~LINK_STATUS_LINK_UP;
+		vars->link_status |= link_flag;
 		vars->link_up = 0;
-		vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG;
+		vars->phy_flags |= phy_flag;
 
 		/* activate nig drain */
 		REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 1);
@@ -12656,10 +12981,10 @@ static void bnx2x_analyze_link_error(struct link_params *params,
 		 */
 		led_mode = LED_MODE_OFF;
 	} else {
-		DP(NETIF_MSG_LINK, "Remote Fault cleared\n");
 		vars->link_status |= LINK_STATUS_LINK_UP;
+		vars->link_status &= ~link_flag;
 		vars->link_up = 1;
-		vars->phy_flags &= ~PHY_HALF_OPEN_CONN_FLAG;
+		vars->phy_flags &= ~phy_flag;
 		led_mode = LED_MODE_OPER;
 
 		/* Clear nig drain */
@@ -12676,6 +13001,8 @@ static void bnx2x_analyze_link_error(struct link_params *params,
 	vars->periodic_flags |= PERIODIC_FLAGS_LINK_EVENT;
 	if (notify)
 		bnx2x_notify_link_changed(bp);
+
+	return 1;
 }
 
 /******************************************************************************
@@ -12717,7 +13044,9 @@ int bnx2x_check_half_open_conn(struct link_params *params,
 		if (REG_RD(bp, mac_base + XMAC_REG_RX_LSS_STATUS))
 			lss_status = 1;
 
-		bnx2x_analyze_link_error(params, vars, lss_status, notify);
+		bnx2x_analyze_link_error(params, vars, lss_status,
+					 PHY_HALF_OPEN_CONN_FLAG,
+					 LINK_STATUS_NONE, notify);
 	} else if (REG_RD(bp, MISC_REG_RESET_REG_2) &
 		   (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) {
 		/* Check E1X / E2 BMAC */
@@ -12734,11 +13063,55 @@ int bnx2x_check_half_open_conn(struct link_params *params,
 		REG_RD_DMAE(bp, mac_base + lss_status_reg, wb_data, 2);
 		lss_status = (wb_data[0] > 0);
 
-		bnx2x_analyze_link_error(params, vars, lss_status, notify);
+		bnx2x_analyze_link_error(params, vars, lss_status,
+					 PHY_HALF_OPEN_CONN_FLAG,
+					 LINK_STATUS_NONE, notify);
 	}
 	return 0;
 }
+static void bnx2x_sfp_tx_fault_detection(struct bnx2x_phy *phy,
+					 struct link_params *params,
+					 struct link_vars *vars)
+{
+	struct bnx2x *bp = params->bp;
+	u32 cfg_pin, value = 0;
+	u8 led_change, port = params->port;
+
+	/* Get The SFP+ TX_Fault controlling pin ([eg]pio) */
+	cfg_pin = (REG_RD(bp, params->shmem_base + offsetof(struct shmem_region,
+			  dev_info.port_hw_config[port].e3_cmn_pin_cfg)) &
+		   PORT_HW_CFG_E3_TX_FAULT_MASK) >>
+		  PORT_HW_CFG_E3_TX_FAULT_SHIFT;
 
+	if (bnx2x_get_cfg_pin(bp, cfg_pin, &value)) {
+		DP(NETIF_MSG_LINK, "Failed to read pin 0x%02x\n", cfg_pin);
+		return;
+	}
+
+	led_change = bnx2x_analyze_link_error(params, vars, value,
+					      PHY_SFP_TX_FAULT_FLAG,
+					      LINK_STATUS_SFP_TX_FAULT, 1);
+
+	if (led_change) {
+		/* Change TX_Fault led, set link status for further syncs */
+		u8 led_mode;
+
+		if (vars->phy_flags & PHY_SFP_TX_FAULT_FLAG) {
+			led_mode = MISC_REGISTERS_GPIO_HIGH;
+			vars->link_status |= LINK_STATUS_SFP_TX_FAULT;
+		} else {
+			led_mode = MISC_REGISTERS_GPIO_LOW;
+			vars->link_status &= ~LINK_STATUS_SFP_TX_FAULT;
+		}
+
+		/* If module is unapproved, led should be on regardless */
+		if (!(phy->flags & FLAGS_SFP_NOT_APPROVED)) {
+			DP(NETIF_MSG_LINK, "Change TX_Fault LED: ->%x\n",
+			   led_mode);
+			bnx2x_set_e3_module_fault_led(params, led_mode);
+		}
+	}
+}
 void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
 {
 	u16 phy_idx;
@@ -12757,7 +13130,26 @@ void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
 		struct bnx2x_phy *phy = &params->phy[INT_PHY];
 		bnx2x_set_aer_mmd(params, phy);
 		bnx2x_check_over_curr(params, vars);
-		bnx2x_warpcore_config_runtime(phy, params, vars);
+		if (vars->rx_tx_asic_rst)
+			bnx2x_warpcore_config_runtime(phy, params, vars);
+
+		if ((REG_RD(bp, params->shmem_base +
+			    offsetof(struct shmem_region, dev_info.
+				port_hw_config[params->port].default_cfg))
+		    & PORT_HW_CFG_NET_SERDES_IF_MASK) ==
+		    PORT_HW_CFG_NET_SERDES_IF_SFI) {
+			if (bnx2x_is_sfp_module_plugged(phy, params)) {
+				bnx2x_sfp_tx_fault_detection(phy, params, vars);
+			} else if (vars->link_status &
+				LINK_STATUS_SFP_TX_FAULT) {
+				/* Clean trail, interrupt corrects the leds */
+				vars->link_status &= ~LINK_STATUS_SFP_TX_FAULT;
+				vars->phy_flags &= ~PHY_SFP_TX_FAULT_FLAG;
+				/* Update link status in the shared memory */
+				bnx2x_update_mng(params, vars->link_status);
+			}
+		}
+
 	}
 
 }
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
index ea4371f..c05f9d9 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
@@ -41,6 +41,7 @@
 #define SPEED_AUTO_NEG		0
 #define SPEED_20000		20000
 
+#define SFP_EEPROM_PAGE_SIZE			16
 #define SFP_EEPROM_VENDOR_NAME_ADDR		0x14
 #define SFP_EEPROM_VENDOR_NAME_SIZE		16
 #define SFP_EEPROM_VENDOR_OUI_ADDR		0x25
@@ -125,6 +126,11 @@ typedef void (*set_link_led_t)(struct bnx2x_phy *phy,
 			       struct link_params *params, u8 mode);
 typedef void (*phy_specific_func_t)(struct bnx2x_phy *phy,
 				    struct link_params *params, u32 action);
+struct bnx2x_reg_set {
+	u8  devad;
+	u16 reg;
+	u16 val;
+};
 
 struct bnx2x_phy {
 	u32 type;
@@ -149,6 +155,7 @@ struct bnx2x_phy {
 #define FLAGS_DUMMY_READ		(1<<9)
 #define FLAGS_MDC_MDIO_WA_B0		(1<<10)
 #define FLAGS_TX_ERROR_CHECK		(1<<12)
+#define FLAGS_EEE_10GBT			(1<<13)
 
 	/* preemphasis values for the rx side */
 	u16 rx_preemphasis[4];
@@ -162,14 +169,15 @@ struct bnx2x_phy {
 	u32 supported;
 
 	u32 media_type;
-#define	ETH_PHY_UNSPECIFIED 0x0
-#define	ETH_PHY_SFP_FIBER   0x1
-#define	ETH_PHY_XFP_FIBER   0x2
-#define	ETH_PHY_DA_TWINAX   0x3
-#define	ETH_PHY_BASE_T      0x4
-#define	ETH_PHY_KR          0xf0
-#define	ETH_PHY_CX4         0xf1
-#define	ETH_PHY_NOT_PRESENT 0xff
+#define	ETH_PHY_UNSPECIFIED	0x0
+#define	ETH_PHY_SFPP_10G_FIBER	0x1
+#define	ETH_PHY_XFP_FIBER		0x2
+#define	ETH_PHY_DA_TWINAX		0x3
+#define	ETH_PHY_BASE_T		0x4
+#define	ETH_PHY_SFP_1G_FIBER	0x5
+#define	ETH_PHY_KR		0xf0
+#define	ETH_PHY_CX4		0xf1
+#define	ETH_PHY_NOT_PRESENT	0xff
 
 	/* The address in which version is located*/
 	u32 ver_addr;
@@ -265,6 +273,30 @@ struct link_params {
 	u8 num_phys;
 
 	u8 rsrv;
+
+	/* Used to configure the EEE Tx LPI timer, has several modes of
+	 * operation, according to bits 29:28 -
+	 * 2'b00: Timer will be configured by nvram, output will be the value
+	 *        from nvram.
+	 * 2'b01: Timer will be configured by nvram, output will be in
+	 *        microseconds.
+	 * 2'b10: bits 1:0 contain an nvram value which will be used instead
+	 *        of the one located in the nvram. Output will be that value.
+	 * 2'b11: bits 19:0 contain the idle timer in microseconds; output
+	 *        will be in microseconds.
+	 * Bits 31:30 should be 2'b11 in order for EEE to be enabled.
+	 */
+	u32 eee_mode;
+#define EEE_MODE_NVRAM_BALANCED_TIME		(0xa00)
+#define EEE_MODE_NVRAM_AGGRESSIVE_TIME		(0x100)
+#define EEE_MODE_NVRAM_LATENCY_TIME		(0x6000)
+#define EEE_MODE_NVRAM_MASK		(0x3)
+#define EEE_MODE_TIMER_MASK		(0xfffff)
+#define EEE_MODE_OUTPUT_TIME		(1<<28)
+#define EEE_MODE_OVERRIDE_NVRAM		(1<<29)
+#define EEE_MODE_ENABLE_LPI		(1<<30)
+#define EEE_MODE_ADV_LPI			(1<<31)
+
 	u16 hw_led_mode; /* part of the hw_config read from the shmem */
 	u32 multi_phy_config;
 
@@ -282,6 +314,7 @@ struct link_vars {
 #define PHY_PHYSICAL_LINK_FLAG		(1<<2)
 #define PHY_HALF_OPEN_CONN_FLAG		(1<<3)
 #define PHY_OVER_CURRENT_FLAG		(1<<4)
+#define PHY_SFP_TX_FAULT_FLAG		(1<<5)
 
 	u8 mac_type;
 #define MAC_TYPE_NONE		0
@@ -301,6 +334,7 @@ struct link_vars {
 
 	/* The same definitions as the shmem parameter */
 	u32 link_status;
+	u32 eee_status;
 	u8 fault_detected;
 	u8 rsrv1;
 	u16 periodic_flags;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index f755a66..8ddc78e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -104,7 +104,7 @@ MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
 
 #define INT_MODE_INTx			1
 #define INT_MODE_MSI			2
-static int int_mode;
+int int_mode;
 module_param(int_mode, int, 0);
 MODULE_PARM_DESC(int_mode, " Force interrupt mode other than MSI-X "
 				"(1 INT#x; 2 MSI)");
@@ -758,7 +758,7 @@ void bnx2x_panic_dump(struct bnx2x *bp)
 		/* Tx */
 		for_each_cos_in_tx_queue(fp, cos)
 		{
-			txdata = fp->txdata[cos];
+			txdata = *fp->txdata_ptr[cos];
 			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, txdata.tx_pkt_prod,
 				  txdata.tx_pkt_cons, txdata.tx_bd_prod,
@@ -876,7 +876,7 @@ void bnx2x_panic_dump(struct bnx2x *bp)
 	for_each_tx_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 		for_each_cos_in_tx_queue(fp, cos) {
-			struct bnx2x_fp_txdata *txdata = &fp->txdata[cos];
+			struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];
 
 			start = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) - 10);
 			end = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) + 245);
@@ -1583,7 +1583,7 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
 	int cid = SW_CID(rr_cqe->ramrod_cqe.conn_and_cmd_data);
 	int command = CQE_CMD(rr_cqe->ramrod_cqe.conn_and_cmd_data);
 	enum bnx2x_queue_cmd drv_cmd = BNX2X_Q_CMD_MAX;
-	struct bnx2x_queue_sp_obj *q_obj = &fp->q_obj;
+	struct bnx2x_queue_sp_obj *q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
 
 	DP(BNX2X_MSG_SP,
 	   "fp %d  cid %d  got ramrod #%d  state is %x  type is %d\n",
@@ -1710,7 +1710,7 @@ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
 			/* Handle Rx or Tx according to SB id */
 			prefetch(fp->rx_cons_sb);
 			for_each_cos_in_tx_queue(fp, cos)
-				prefetch(fp->txdata[cos].tx_cons_sb);
+				prefetch(fp->txdata_ptr[cos]->tx_cons_sb);
 			prefetch(&fp->sb_running_index[SM_RX_ID]);
 			napi_schedule(&bnx2x_fp(bp, fp->index, napi));
 			status &= ~mask;
@@ -2124,6 +2124,11 @@ u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
 			}
 		}
 
+		if (load_mode == LOAD_LOOPBACK_EXT) {
+			struct link_params *lp = &bp->link_params;
+			lp->loopback_mode = LOOPBACK_EXT;
+		}
+
 		rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars);
 
 		bnx2x_release_phy_lock(bp);
@@ -2916,7 +2921,7 @@ static void bnx2x_pf_tx_q_prep(struct bnx2x *bp,
 	struct bnx2x_fastpath *fp, struct bnx2x_txq_setup_params *txq_init,
 	u8 cos)
 {
-	txq_init->dscr_map = fp->txdata[cos].tx_desc_mapping;
+	txq_init->dscr_map = fp->txdata_ptr[cos]->tx_desc_mapping;
 	txq_init->sb_cq_index = HC_INDEX_ETH_FIRST_TX_CQ_CONS + cos;
 	txq_init->traffic_type = LLFC_TRAFFIC_TYPE_NW;
 	txq_init->fw_sb_id = fp->fw_sb_id;
@@ -3030,9 +3035,9 @@ static void bnx2x_drv_info_ether_stat(struct bnx2x *bp)
 	memcpy(ether_stat->version, DRV_MODULE_VERSION,
 	       ETH_STAT_INFO_VERSION_LEN - 1);
 
-	bp->fp[0].mac_obj.get_n_elements(bp, &bp->fp[0].mac_obj,
-					 DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED,
-					 ether_stat->mac_local);
+	bp->sp_objs[0].mac_obj.get_n_elements(bp, &bp->sp_objs[0].mac_obj,
+					DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED,
+					ether_stat->mac_local);
 
 	ether_stat->mtu_size = bp->dev->mtu;
 
@@ -3063,11 +3068,11 @@ static void bnx2x_drv_info_fcoe_stat(struct bnx2x *bp)
 	/* insert FCoE stats from ramrod response */
 	if (!NO_FCOE(bp)) {
 		struct tstorm_per_queue_stats *fcoe_q_tstorm_stats =
-			&bp->fw_stats_data->queue_stats[FCOE_IDX].
+			&bp->fw_stats_data->queue_stats[FCOE_IDX(bp)].
 			tstorm_queue_statistics;
 
 		struct xstorm_per_queue_stats *fcoe_q_xstorm_stats =
-			&bp->fw_stats_data->queue_stats[FCOE_IDX].
+			&bp->fw_stats_data->queue_stats[FCOE_IDX(bp)].
 			xstorm_queue_statistics;
 
 		struct fcoe_statistics_params *fw_fcoe_stat =
@@ -3176,6 +3181,12 @@ static void bnx2x_set_mf_bw(struct bnx2x *bp)
 	bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW_ACK, 0);
 }
 
+static void bnx2x_handle_eee_event(struct bnx2x *bp)
+{
+	DP(BNX2X_MSG_MCP, "EEE - LLDP event\n");
+	bnx2x_fw_command(bp, DRV_MSG_CODE_EEE_RESULTS_ACK, 0);
+}
+
 static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
 {
 	enum drv_info_opcode op_code;
@@ -3742,6 +3753,8 @@ static void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
 			if (val & DRV_STATUS_AFEX_EVENT_MASK)
 				bnx2x_handle_afex_cmd(bp,
 					val & DRV_STATUS_AFEX_EVENT_MASK);
+			if (val & DRV_STATUS_EEE_NEGOTIATION_RESULTS)
+				bnx2x_handle_eee_event(bp);
 			if (bp->link_vars.periodic_flags &
 			    PERIODIC_FLAGS_LINK_EVENT) {
 				/*  sync with link */
@@ -4615,11 +4628,11 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp,
 	case BNX2X_FILTER_MAC_PENDING:
 		DP(BNX2X_MSG_SP, "Got SETUP_MAC completions\n");
 #ifdef BCM_CNIC
-		if (cid == BNX2X_ISCSI_ETH_CID)
+		if (cid == BNX2X_ISCSI_ETH_CID(bp))
 			vlan_mac_obj = &bp->iscsi_l2_mac_obj;
 		else
 #endif
-			vlan_mac_obj = &bp->fp[cid].mac_obj;
+			vlan_mac_obj = &bp->sp_objs[cid].mac_obj;
 
 		break;
 	case BNX2X_FILTER_MCAST_PENDING:
@@ -4717,7 +4730,7 @@ static void bnx2x_after_function_update(struct bnx2x *bp)
 	for_each_eth_queue(bp, q) {
 		/* Set the appropriate Queue object */
 		fp = &bp->fp[q];
-		queue_params.q_obj = &fp->q_obj;
+		queue_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
 
 		/* send the ramrod */
 		rc = bnx2x_queue_state_change(bp, &queue_params);
@@ -4728,8 +4741,8 @@ static void bnx2x_after_function_update(struct bnx2x *bp)
 
 #ifdef BCM_CNIC
 	if (!NO_FCOE(bp)) {
-		fp = &bp->fp[FCOE_IDX];
-		queue_params.q_obj = &fp->q_obj;
+		fp = &bp->fp[FCOE_IDX(bp)];
+		queue_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
 
 		/* clear pending completion bit */
 		__clear_bit(RAMROD_COMP_WAIT, &queue_params.ramrod_flags);
@@ -4761,11 +4774,11 @@ static struct bnx2x_queue_sp_obj *bnx2x_cid_to_q_obj(
 {
 	DP(BNX2X_MSG_SP, "retrieving fp from cid %d\n", cid);
 #ifdef BCM_CNIC
-	if (cid == BNX2X_FCOE_ETH_CID)
-		return &bnx2x_fcoe(bp, q_obj);
+	if (cid == BNX2X_FCOE_ETH_CID(bp))
+		return &bnx2x_fcoe_sp_obj(bp, q_obj);
 	else
 #endif
-		return &bnx2x_fp(bp, CID_TO_FP(cid), q_obj);
+		return &bp->sp_objs[CID_TO_FP(cid, bp)].q_obj;
 }
 
 static void bnx2x_eq_int(struct bnx2x *bp)
@@ -5647,15 +5660,15 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
 
 	/* init tx data */
 	for_each_cos_in_tx_queue(fp, cos) {
-		bnx2x_init_txdata(bp, &fp->txdata[cos],
-				  CID_COS_TO_TX_ONLY_CID(fp->cid, cos),
-				  FP_COS_TO_TXQ(fp, cos),
-				  BNX2X_TX_SB_INDEX_BASE + cos);
-		cids[cos] = fp->txdata[cos].cid;
+		bnx2x_init_txdata(bp, fp->txdata_ptr[cos],
+				  CID_COS_TO_TX_ONLY_CID(fp->cid, cos, bp),
+				  FP_COS_TO_TXQ(fp, cos, bp),
+				  BNX2X_TX_SB_INDEX_BASE + cos, fp);
+		cids[cos] = fp->txdata_ptr[cos]->cid;
 	}
 
-	bnx2x_init_queue_obj(bp, &fp->q_obj, fp->cl_id, cids, fp->max_cos,
-			     BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
+	bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id, cids,
+			     fp->max_cos, BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
 			     bnx2x_sp_mapping(bp, q_rdata), q_type);
 
 	/**
@@ -5706,7 +5719,7 @@ static void bnx2x_init_tx_rings(struct bnx2x *bp)
 
 	for_each_tx_queue(bp, i)
 		for_each_cos_in_tx_queue(&bp->fp[i], cos)
-			bnx2x_init_tx_ring_one(&bp->fp[i].txdata[cos]);
+			bnx2x_init_tx_ring_one(bp->fp[i].txdata_ptr[cos]);
 }
 
 void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
@@ -7055,12 +7068,10 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
 	cdu_ilt_start = ilt->clients[ILT_CLIENT_CDU].start;
 
 	for (i = 0; i < L2_ILT_LINES(bp); i++) {
-		ilt->lines[cdu_ilt_start + i].page =
-			bp->context.vcxt + (ILT_PAGE_CIDS * i);
+		ilt->lines[cdu_ilt_start + i].page = bp->context[i].vcxt;
 		ilt->lines[cdu_ilt_start + i].page_mapping =
-			bp->context.cxt_mapping + (CDU_ILT_PAGE_SZ * i);
-		/* cdu ilt pages are allocated manually so there's no need to
-		set the size */
+			bp->context[i].cxt_mapping;
+		ilt->lines[cdu_ilt_start + i].size = bp->context[i].size;
 	}
 	bnx2x_ilt_init_op(bp, INITOP_SET);
 
@@ -7327,6 +7338,8 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
 
 void bnx2x_free_mem(struct bnx2x *bp)
 {
+	int i;
+
 	/* fastpath */
 	bnx2x_free_fp_mem(bp);
 	/* end of fastpath */
@@ -7340,9 +7353,9 @@ void bnx2x_free_mem(struct bnx2x *bp)
 	BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping,
 		       sizeof(struct bnx2x_slowpath));
 
-	BNX2X_PCI_FREE(bp->context.vcxt, bp->context.cxt_mapping,
-		       bp->context.size);
-
+	for (i = 0; i < L2_ILT_LINES(bp); i++)
+		BNX2X_PCI_FREE(bp->context[i].vcxt, bp->context[i].cxt_mapping,
+			       bp->context[i].size);
 	bnx2x_ilt_mem_op(bp, ILT_MEMOP_FREE);
 
 	BNX2X_FREE(bp->ilt->lines);
@@ -7428,6 +7441,8 @@ alloc_mem_err:
 
 int bnx2x_alloc_mem(struct bnx2x *bp)
 {
+	int i, allocated, context_size;
+
 #ifdef BCM_CNIC
 	if (!CHIP_IS_E1x(bp))
 		/* size = the status block + ramrod buffers */
@@ -7457,11 +7472,29 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
 	if (bnx2x_alloc_fw_stats_mem(bp))
 		goto alloc_mem_err;
 
-	bp->context.size = sizeof(union cdu_context) * BNX2X_L2_CID_COUNT(bp);
-
-	BNX2X_PCI_ALLOC(bp->context.vcxt, &bp->context.cxt_mapping,
-			bp->context.size);
+	/* Allocate memory for CDU context:
+	 * This memory is allocated separately and not in the generic ILT
+	 * functions because CDU differs in few aspects:
+	 * 1. There are multiple entities allocating memory for context -
+	 * 'regular' driver, CNIC and SRIOV driver. Each separately controls
+	 * its own ILT lines.
+	 * 2. Since CDU page-size is not a single 4KB page (which is the case
+	 * for the other ILT clients), to be efficient we want to support
+	 * allocation of sub-page-size in the last entry.
+	 * 3. Context pointers are used by the driver to pass to FW / update
+	 * the context (for the other ILT clients the pointers are used just to
+	 * free the memory during unload).
+	 */
+	context_size = sizeof(union cdu_context) * BNX2X_L2_CID_COUNT(bp);
 
+	for (i = 0, allocated = 0; allocated < context_size; i++) {
+		bp->context[i].size = min(CDU_ILT_PAGE_SZ,
+					  (context_size - allocated));
+		BNX2X_PCI_ALLOC(bp->context[i].vcxt,
+				&bp->context[i].cxt_mapping,
+				bp->context[i].size);
+		allocated += bp->context[i].size;
+	}
 	BNX2X_ALLOC(bp->ilt->lines, sizeof(struct ilt_line) * ILT_MAX_LINES);
 
 	if (bnx2x_ilt_mem_op(bp, ILT_MEMOP_ALLOC))
@@ -7563,8 +7596,8 @@ int bnx2x_set_eth_mac(struct bnx2x *bp, bool set)
 
 	__set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
 	/* Eth MAC is set on RSS leading client (fp[0]) */
-	return bnx2x_set_mac_one(bp, bp->dev->dev_addr, &bp->fp->mac_obj, set,
-				 BNX2X_ETH_MAC, &ramrod_flags);
+	return bnx2x_set_mac_one(bp, bp->dev->dev_addr, &bp->sp_objs->mac_obj,
+				 set, BNX2X_ETH_MAC, &ramrod_flags);
 }
 
 int bnx2x_setup_leading(struct bnx2x *bp)
@@ -7579,7 +7612,7 @@ int bnx2x_setup_leading(struct bnx2x *bp)
  *
  * In case of MSI-X it will also try to enable MSI-X.
  */
-static void __devinit bnx2x_set_int_mode(struct bnx2x *bp)
+void bnx2x_set_int_mode(struct bnx2x *bp)
 {
 	switch (int_mode) {
 	case INT_MODE_MSI:
@@ -7590,11 +7623,6 @@ static void __devinit bnx2x_set_int_mode(struct bnx2x *bp)
 		BNX2X_DEV_INFO("set number of queues to 1\n");
 		break;
 	default:
-		/* Set number of queues for MSI-X mode */
-		bnx2x_set_num_queues(bp);
-
-		BNX2X_DEV_INFO("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
@@ -7735,6 +7763,8 @@ static void bnx2x_pf_q_prep_init(struct bnx2x *bp,
 {
 
 	u8 cos;
+	int cxt_index, cxt_offset;
+
 	/* FCoE Queue uses Default SB, thus has no HC capabilities */
 	if (!IS_FCOE_FP(fp)) {
 		__set_bit(BNX2X_Q_FLG_HC, &init_params->rx.flags);
@@ -7771,9 +7801,13 @@ static void bnx2x_pf_q_prep_init(struct bnx2x *bp,
 	    fp->index, init_params->max_cos);
 
 	/* set the context pointers queue object */
-	for (cos = FIRST_TX_COS_INDEX; cos < init_params->max_cos; cos++)
+	for (cos = FIRST_TX_COS_INDEX; cos < init_params->max_cos; cos++) {
+		cxt_index = fp->txdata_ptr[cos]->cid / ILT_PAGE_CIDS;
+		cxt_offset = fp->txdata_ptr[cos]->cid - (cxt_index *
+				ILT_PAGE_CIDS);
 		init_params->cxts[cos] =
-			&bp->context.vcxt[fp->txdata[cos].cid].eth;
+			&bp->context[cxt_index].vcxt[cxt_offset].eth;
+	}
 }
 
 int bnx2x_setup_tx_only(struct bnx2x *bp, struct bnx2x_fastpath *fp,
@@ -7838,7 +7872,7 @@ int bnx2x_setup_queue(struct bnx2x *bp, struct bnx2x_fastpath *fp,
 		bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0,
 			     IGU_INT_ENABLE, 0);
 
-	q_params.q_obj = &fp->q_obj;
+	q_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
 	/* We want to wait for completion in this context */
 	__set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
 
@@ -7911,7 +7945,7 @@ static int bnx2x_stop_queue(struct bnx2x *bp, int index)
 
 	DP(NETIF_MSG_IFDOWN, "stopping queue %d cid %d\n", index, fp->cid);
 
-	q_params.q_obj = &fp->q_obj;
+	q_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
 	/* We want to wait for completion in this context */
 	__set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
 
@@ -7922,7 +7956,7 @@ static int bnx2x_stop_queue(struct bnx2x *bp, int index)
 	     tx_index++){
 
 		/* ascertain this is a normal queue*/
-		txdata = &fp->txdata[tx_index];
+		txdata = fp->txdata_ptr[tx_index];
 
 		DP(NETIF_MSG_IFDOWN, "stopping tx-only queue %d\n",
 							txdata->txq_index);
@@ -8289,7 +8323,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 
 		for_each_cos_in_tx_queue(fp, cos)
-			rc = bnx2x_clean_tx_queue(bp, &fp->txdata[cos]);
+			rc = bnx2x_clean_tx_queue(bp, fp->txdata_ptr[cos]);
 #ifdef BNX2X_STOP_ON_ERROR
 		if (rc)
 			return;
@@ -8300,12 +8334,13 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
 	usleep_range(1000, 1000);
 
 	/* Clean all ETH MACs */
-	rc = bnx2x_del_all_macs(bp, &bp->fp[0].mac_obj, BNX2X_ETH_MAC, false);
+	rc = bnx2x_del_all_macs(bp, &bp->sp_objs[0].mac_obj, BNX2X_ETH_MAC,
+				false);
 	if (rc < 0)
 		BNX2X_ERR("Failed to delete all ETH macs: %d\n", rc);
 
 	/* Clean up UC list  */
-	rc = bnx2x_del_all_macs(bp, &bp->fp[0].mac_obj, BNX2X_UC_LIST_MAC,
+	rc = bnx2x_del_all_macs(bp, &bp->sp_objs[0].mac_obj, BNX2X_UC_LIST_MAC,
 				true);
 	if (rc < 0)
 		BNX2X_ERR("Failed to schedule DEL commands for UC MACs list: %d\n",
@@ -9697,6 +9732,8 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
 	bp->flags |= (val >= REQ_BC_VER_4_PFC_STATS_SUPPORTED) ?
 			BC_SUPPORTS_PFC_STATS : 0;
 
+	bp->flags |= (val >= REQ_BC_VER_4_DCBX_ADMIN_MSG_NON_PMF) ?
+			BC_SUPPORTS_DCBX_MSG_NON_PMF : 0;
 	boot_mode = SHMEM_RD(bp,
 			dev_info.port_feature_config[BP_PORT(bp)].mba_config) &
 			PORT_FEATURE_MBA_BOOT_AGENT_TYPE_MASK;
@@ -10082,7 +10119,7 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
 {
 	int port = BP_PORT(bp);
 	u32 config;
-	u32 ext_phy_type, ext_phy_config;
+	u32 ext_phy_type, ext_phy_config, eee_mode;
 
 	bp->link_params.bp = bp;
 	bp->link_params.port = port;
@@ -10149,6 +10186,19 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
 		bp->port.need_hw_lock = bnx2x_hw_lock_required(bp,
 							bp->common.shmem_base,
 							bp->common.shmem2_base);
+
+	/* Configure link feature according to nvram value */
+	eee_mode = (((SHMEM_RD(bp, dev_info.
+		      port_feature_config[port].eee_power_mode)) &
+		     PORT_FEAT_CFG_EEE_POWER_MODE_MASK) >>
+		    PORT_FEAT_CFG_EEE_POWER_MODE_SHIFT);
+	if (eee_mode != PORT_FEAT_CFG_EEE_POWER_MODE_DISABLED) {
+		bp->link_params.eee_mode = EEE_MODE_ADV_LPI |
+					   EEE_MODE_ENABLE_LPI |
+					   EEE_MODE_OUTPUT_TIME;
+	} else {
+		bp->link_params.eee_mode = 0;
+	}
 }
 
 void bnx2x_get_iscsi_info(struct bnx2x *bp)
@@ -10997,7 +11047,7 @@ static int bnx2x_set_uc_list(struct bnx2x *bp)
 	int rc;
 	struct net_device *dev = bp->dev;
 	struct netdev_hw_addr *ha;
-	struct bnx2x_vlan_mac_obj *mac_obj = &bp->fp->mac_obj;
+	struct bnx2x_vlan_mac_obj *mac_obj = &bp->sp_objs->mac_obj;
 	unsigned long ramrod_flags = 0;
 
 	/* First schedule a cleanup up of old configuration */
@@ -11672,7 +11722,7 @@ void bnx2x__init_func_obj(struct bnx2x *bp)
 /* must be called after sriov-enable */
 static int bnx2x_set_qm_cid_count(struct bnx2x *bp)
 {
-	int cid_count = BNX2X_L2_CID_COUNT(bp);
+	int cid_count = BNX2X_L2_MAX_CID(bp);
 
 #ifdef BCM_CNIC
 	cid_count += CNIC_CID_MAX;
@@ -11717,7 +11767,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
 	struct bnx2x *bp;
 	int pcie_width, pcie_speed;
 	int rc, max_non_def_sbs;
-	int rx_count, tx_count, rss_count;
+	int rx_count, tx_count, rss_count, doorbell_size;
 	/*
 	 * An estimated maximum supported CoS number according to the chip
 	 * version.
@@ -11760,13 +11810,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
 
 	max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev);
 
-	/* !!! FIXME !!!
-	 * Do not allow the maximum SB count to grow above 16
-	 * since Special CIDs starts from 16*BNX2X_MULTI_TX_COS=48.
-	 * We will use the FP_SB_MAX_E1x macro for this matter.
-	 */
-	max_non_def_sbs = min_t(int, FP_SB_MAX_E1x, max_non_def_sbs);
-
 	WARN_ON(!max_non_def_sbs);
 
 	/* Maximum number of RSS queues: one IGU SB goes to CNIC */
@@ -11777,9 +11820,9 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
 
 	/*
 	 * Maximum number of netdev Tx queues:
-	 *      Maximum TSS queues * Maximum supported number of CoS  + FCoE L2
+	 * Maximum TSS queues * Maximum supported number of CoS  + FCoE L2
 	 */
-	tx_count = MAX_TXQS_PER_COS * max_cos_est + FCOE_PRESENT;
+	tx_count = rss_count * max_cos_est + FCOE_PRESENT;
 
 	/* dev zeroed in init_etherdev */
 	dev = alloc_etherdev_mqs(sizeof(*bp), tx_count, rx_count);
@@ -11788,9 +11831,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
 
 	bp = netdev_priv(dev);
 
-	BNX2X_DEV_INFO("Allocated netdev with %d tx and %d rx queues\n",
-			  tx_count, rx_count);
-
 	bp->igu_sb_cnt = max_non_def_sbs;
 	bp->msg_enable = debug;
 	pci_set_drvdata(pdev, dev);
@@ -11803,6 +11843,9 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
 
 	BNX2X_DEV_INFO("max_non_def_sbs %d\n", max_non_def_sbs);
 
+	BNX2X_DEV_INFO("Allocated netdev with %d tx and %d rx queues\n",
+			  tx_count, rx_count);
+
 	rc = bnx2x_init_bp(bp);
 	if (rc)
 		goto init_one_exit;
@@ -11811,9 +11854,15 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
 	 * Map doorbels here as we need the real value of bp->max_cos which
 	 * is initialized in bnx2x_init_bp().
 	 */
+	doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
+	if (doorbell_size > pci_resource_len(pdev, 2)) {
+		dev_err(&bp->pdev->dev,
+			"Cannot map doorbells, bar size too small, aborting\n");
+		rc = -ENOMEM;
+		goto init_one_exit;
+	}
 	bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
-					min_t(u64, BNX2X_DB_SIZE(bp),
-					      pci_resource_len(pdev, 2)));
+					doorbell_size);
 	if (!bp->doorbells) {
 		dev_err(&bp->pdev->dev,
 			"Cannot map doorbell space, aborting\n");
@@ -11831,8 +11880,12 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
 
 #endif
 
+
+	/* Set bp->num_queues for MSI-X mode*/
+	bnx2x_set_num_queues(bp);
+
 	/* Configure interrupt mode: try to enable MSI-X/MSI if
-	 * needed, set bp->num_queues appropriately.
+	 * needed.
 	 */
 	bnx2x_set_int_mode(bp);
 
@@ -12176,6 +12229,7 @@ static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp)
 static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count)
 {
 	struct eth_spe *spe;
+	int cxt_index, cxt_offset;
 
 #ifdef BNX2X_STOP_ON_ERROR
 	if (unlikely(bp->panic))
@@ -12198,10 +12252,16 @@ static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count)
 		 *  ramrod
 		 */
 		if (type == ETH_CONNECTION_TYPE) {
-			if (cmd == RAMROD_CMD_ID_ETH_CLIENT_SETUP)
-				bnx2x_set_ctx_validation(bp, &bp->context.
-					vcxt[BNX2X_ISCSI_ETH_CID].eth,
-					BNX2X_ISCSI_ETH_CID);
+			if (cmd == RAMROD_CMD_ID_ETH_CLIENT_SETUP) {
+				cxt_index = BNX2X_ISCSI_ETH_CID(bp) /
+					ILT_PAGE_CIDS;
+				cxt_offset = BNX2X_ISCSI_ETH_CID(bp) -
+					(cxt_index * ILT_PAGE_CIDS);
+				bnx2x_set_ctx_validation(bp,
+					&bp->context[cxt_index].
+							 vcxt[cxt_offset].eth,
+					BNX2X_ISCSI_ETH_CID(bp));
+			}
 		}
 
 		/*
@@ -12554,6 +12614,21 @@ void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
 	cp->num_irq = 2;
 }
 
+void bnx2x_setup_cnic_info(struct bnx2x *bp)
+{
+	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+
+	cp->ctx_tbl_offset = FUNC_ILT_BASE(BP_FUNC(bp)) +
+			     bnx2x_cid_ilt_lines(bp);
+	cp->starting_cid = bnx2x_cid_ilt_lines(bp) * ILT_PAGE_CIDS;
+	cp->fcoe_init_cid = BNX2X_FCOE_ETH_CID(bp);
+	cp->iscsi_l2_cid = BNX2X_ISCSI_ETH_CID(bp);
+
+	if (NO_ISCSI_OOO(bp))
+		cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI_OOO;
+}
+
 static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops,
 			       void *data)
 {
@@ -12632,10 +12707,10 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
 	cp->drv_ctl = bnx2x_drv_ctl;
 	cp->drv_register_cnic = bnx2x_register_cnic;
 	cp->drv_unregister_cnic = bnx2x_unregister_cnic;
-	cp->fcoe_init_cid = BNX2X_FCOE_ETH_CID;
+	cp->fcoe_init_cid = BNX2X_FCOE_ETH_CID(bp);
 	cp->iscsi_l2_client_id =
 		bnx2x_cnic_eth_cl_id(bp, BNX2X_ISCSI_ETH_CL_ID_IDX);
-	cp->iscsi_l2_cid = BNX2X_ISCSI_ETH_CID;
+	cp->iscsi_l2_cid = BNX2X_ISCSI_ETH_CID(bp);
 
 	if (NO_ISCSI_OOO(bp))
 		cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI_OOO;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
index bbd3874..f371e3c 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
@@ -1488,6 +1488,121 @@
  * 2:1 - otp_misc_do[51:50]; 0 - otp_misc_do[1]. */
 #define MISC_REG_CHIP_TYPE					 0xac60
 #define MISC_REG_CHIP_TYPE_57811_MASK				 (1<<1)
+#define MISC_REG_CPMU_LP_DR_ENABLE				 0xa858
+/* [RW 1] FW EEE LPI Enable. When 1 indicates that EEE LPI mode is enabled
+ * by FW. When 0 indicates that the EEE LPI mode is disabled by FW. Clk
+ * 25MHz. Reset on hard reset. */
+#define MISC_REG_CPMU_LP_FW_ENABLE_P0				 0xa84c
+/* [RW 32] EEE LPI Idle Threshold. The threshold value for the idle EEE LPI
+ * counter. Timer tick is 1 us. Clock 25MHz. Reset on hard reset. */
+#define MISC_REG_CPMU_LP_IDLE_THR_P0				 0xa8a0
+/* [RW 18] LPI entry events mask. [0] - Vmain SM Mask. When 1 indicates that
+ * the Vmain SM end state is disabled. When 0 indicates that the Vmain SM
+ * end state is enabled. [1] - FW Queues Empty Mask. When 1 indicates that
+ * the FW command that all Queues are empty is disabled. When 0 indicates
+ * that the FW command that all Queues are empty is enabled. [2] - FW Early
+ * Exit Mask / Reserved (Entry mask). When 1 indicates that the FW Early
+ * Exit command is disabled. When 0 indicates that the FW Early Exit command
+ * is enabled. This bit applicable only in the EXIT Events Mask registers.
+ * [3] - PBF Request Mask. When 1 indicates that the PBF Request indication
+ * is disabled. When 0 indicates that the PBF Request indication is enabled.
+ * [4] - Tx Request Mask. When =1 indicates that the Tx other Than PBF
+ * Request indication is disabled. When 0 indicates that the Tx Other Than
+ * PBF Request indication is enabled. [5] - Rx EEE LPI Status Mask. When 1
+ * indicates that the RX EEE LPI Status indication is disabled. When 0
+ * indicates that the RX EEE LPI Status indication is enabled. In the EXIT
+ * Events Masks registers; this bit masks the falling edge detect of the LPI
+ * Status (Rx LPI is on - off). [6] - Tx Pause Mask. When 1 indicates that
+ * the Tx Pause indication is disabled. When 0 indicates that the Tx Pause
+ * indication is enabled. [7] - BRB1 Empty Mask. When 1 indicates that the
+ * BRB1 EMPTY indication is disabled. When 0 indicates that the BRB1 EMPTY
+ * indication is enabled. [8] - QM Idle Mask. When 1 indicates that the QM
+ * IDLE indication is disabled. When 0 indicates that the QM IDLE indication
+ * is enabled. (One bit for both VOQ0 and VOQ1). [9] - QM LB Idle Mask. When
+ * 1 indicates that the QM IDLE indication for LOOPBACK is disabled. When 0
+ * indicates that the QM IDLE indication for LOOPBACK is enabled. [10] - L1
+ * Status Mask. When 1 indicates that the L1 Status indication from the PCIE
+ * CORE is disabled. When 0 indicates that the RX EEE LPI Status indication
+ * from the PCIE CORE is enabled. In the EXIT Events Masks registers; this
+ * bit masks the falling edge detect of the L1 status (L1 is on - off). [11]
+ * - P0 E0 EEE EEE LPI REQ Mask. When =1 indicates that the P0 E0 EEE EEE
+ * LPI REQ indication is disabled. When =0 indicates that the P0 E0 EEE LPI
+ * REQ indication is enabled. [12] - P1 E0 EEE LPI REQ Mask. When =1
+ * indicates that the P0 EEE LPI REQ indication is disabled. When =0
+ * indicates that the P0 EEE LPI REQ indication is enabled. [13] - P0 E1 EEE
+ * LPI REQ Mask. When =1 indicates that the P0 EEE LPI REQ indication is
+ * disabled. When =0 indicates that the P0 EEE LPI REQ indication is
+ * enabled. [14] - P1 E1 EEE LPI REQ Mask. When =1 indicates that the P0 EEE
+ * LPI REQ indication is disabled. When =0 indicates that the P0 EEE LPI REQ
+ * indication is enabled. [15] - L1 REQ Mask. When =1 indicates that the L1
+ * REQ indication is disabled. When =0 indicates that the L1 indication is
+ * enabled. [16] - Rx EEE LPI Status Edge Detect Mask. When =1 indicates
+ * that the RX EEE LPI Status Falling Edge Detect indication is disabled (Rx
+ * EEE LPI is on - off). When =0 indicates that the RX EEE LPI Status
+ * Falling Edge Detec indication is enabled (Rx EEE LPI is on - off). This
+ * bit is applicable only in the EXIT Events Masks registers. [17] - L1
+ * Status Edge Detect Mask. When =1 indicates that the L1 Status Falling
+ * Edge Detect indication from the PCIE CORE is disabled (L1 is on - off).
+ * When =0 indicates that the L1 Status Falling Edge Detect indication from
+ * the PCIE CORE is enabled (L1 is on - off). This bit is applicable only in
+ * the EXIT Events Masks registers. Clock 25MHz. Reset on hard reset. */
+#define MISC_REG_CPMU_LP_MASK_ENT_P0				 0xa880
+/* [RW 18] EEE LPI exit events mask. [0] - Vmain SM Mask. When 1 indicates
+ * that the Vmain SM end state is disabled. When 0 indicates that the Vmain
+ * SM end state is enabled. [1] - FW Queues Empty Mask. When 1 indicates
+ * that the FW command that all Queues are empty is disabled. When 0
+ * indicates that the FW command that all Queues are empty is enabled. [2] -
+ * FW Early Exit Mask / Reserved (Entry mask). When 1 indicates that the FW
+ * Early Exit command is disabled. When 0 indicates that the FW Early Exit
+ * command is enabled. This bit applicable only in the EXIT Events Mask
+ * registers. [3] - PBF Request Mask. When 1 indicates that the PBF Request
+ * indication is disabled. When 0 indicates that the PBF Request indication
+ * is enabled. [4] - Tx Request Mask. When =1 indicates that the Tx other
+ * Than PBF Request indication is disabled. When 0 indicates that the Tx
+ * Other Than PBF Request indication is enabled. [5] - Rx EEE LPI Status
+ * Mask. When 1 indicates that the RX EEE LPI Status indication is disabled.
+ * When 0 indicates that the RX LPI Status indication is enabled. In the
+ * EXIT Events Masks registers; this bit masks the falling edge detect of
+ * the EEE LPI Status (Rx EEE LPI is on - off). [6] - Tx Pause Mask. When 1
+ * indicates that the Tx Pause indication is disabled. When 0 indicates that
+ * the Tx Pause indication is enabled. [7] - BRB1 Empty Mask. When 1
+ * indicates that the BRB1 EMPTY indication is disabled. When 0 indicates
+ * that the BRB1 EMPTY indication is enabled. [8] - QM Idle Mask. When 1
+ * indicates that the QM IDLE indication is disabled. When 0 indicates that
+ * the QM IDLE indication is enabled. (One bit for both VOQ0 and VOQ1). [9]
+ * - QM LB Idle Mask. When 1 indicates that the QM IDLE indication for
+ * LOOPBACK is disabled. When 0 indicates that the QM IDLE indication for
+ * LOOPBACK is enabled. [10] - L1 Status Mask. When 1 indicates that the L1
+ * Status indication from the PCIE CORE is disabled. When 0 indicates that
+ * the RX EEE LPI Status indication from the PCIE CORE is enabled. In the
+ * EXIT Events Masks registers; this bit masks the falling edge detect of
+ * the L1 status (L1 is on - off). [11] - P0 E0 EEE EEE LPI REQ Mask. When
+ * =1 indicates that the P0 E0 EEE EEE LPI REQ indication is disabled. When
+ * =0 indicates that the P0 E0 EEE LPI REQ indication is enabled. [12] - P1
+ * E0 EEE LPI REQ Mask. When =1 indicates that the P0 EEE LPI REQ indication
+ * is disabled. When =0 indicates that the P0 EEE LPI REQ indication is
+ * enabled. [13] - P0 E1 EEE LPI REQ Mask. When =1 indicates that the P0 EEE
+ * LPI REQ indication is disabled. When =0 indicates that the P0 EEE LPI REQ
+ * indication is enabled. [14] - P1 E1 EEE LPI REQ Mask. When =1 indicates
+ * that the P0 EEE LPI REQ indication is disabled. When =0 indicates that
+ * the P0 EEE LPI REQ indication is enabled. [15] - L1 REQ Mask. When =1
+ * indicates that the L1 REQ indication is disabled. When =0 indicates that
+ * the L1 indication is enabled. [16] - Rx EEE LPI Status Edge Detect Mask.
+ * When =1 indicates that the RX EEE LPI Status Falling Edge Detect
+ * indication is disabled (Rx EEE LPI is on - off). When =0 indicates that
+ * the RX EEE LPI Status Falling Edge Detec indication is enabled (Rx EEE
+ * LPI is on - off). This bit is applicable only in the EXIT Events Masks
+ * registers. [17] - L1 Status Edge Detect Mask. When =1 indicates that the
+ * L1 Status Falling Edge Detect indication from the PCIE CORE is disabled
+ * (L1 is on - off). When =0 indicates that the L1 Status Falling Edge
+ * Detect indication from the PCIE CORE is enabled (L1 is on - off). This
+ * bit is applicable only in the EXIT Events Masks registers.Clock 25MHz.
+ * Reset on hard reset. */
+#define MISC_REG_CPMU_LP_MASK_EXT_P0				 0xa888
+/* [RW 16] EEE LPI Entry Events Counter. A statistic counter with the number
+ * of counts that the SM entered the EEE LPI state. Clock 25MHz. Read only
+ * register. Reset on hard reset. */
+#define MISC_REG_CPMU_LP_SM_ENT_CNT_P0				 0xa8b8
 /* [RW 32] The following driver registers(1...16) represent 16 drivers and
    32 clients. Each client can be controlled by one driver only. One in each
    bit represent that this driver control the appropriate client (Ex: bit 5
@@ -5372,6 +5487,8 @@
 /* [RW 32] Lower 48 bits of ctrl_sa register. Used as the SA in PAUSE/PFC
  * packets transmitted by the MAC */
 #define XMAC_REG_CTRL_SA_LO					 0x28
+#define XMAC_REG_EEE_CTRL					 0xd8
+#define XMAC_REG_EEE_TIMERS_HI					 0xe4
 #define XMAC_REG_PAUSE_CTRL					 0x68
 #define XMAC_REG_PFC_CTRL					 0x70
 #define XMAC_REG_PFC_CTRL_HI					 0x74
@@ -5796,6 +5913,7 @@
 #define MISC_REGISTERS_SPIO_OUTPUT_LOW				 0
 #define MISC_REGISTERS_SPIO_SET_POS				 8
 #define HW_LOCK_MAX_RESOURCE_VALUE				 31
+#define HW_LOCK_RESOURCE_DCBX_ADMIN_MIB				 13
 #define HW_LOCK_RESOURCE_DRV_FLAGS				 10
 #define HW_LOCK_RESOURCE_GPIO					 1
 #define HW_LOCK_RESOURCE_MDIO					 0
@@ -6813,6 +6931,8 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_AN_REG_LP_AUTO_NEG		0x0013
 #define MDIO_AN_REG_LP_AUTO_NEG2	0x0014
 #define MDIO_AN_REG_MASTER_STATUS	0x0021
+#define MDIO_AN_REG_EEE_ADV		0x003c
+#define MDIO_AN_REG_LP_EEE_ADV		0x003d
 /*bcm*/
 #define MDIO_AN_REG_LINK_STATUS 	0x8304
 #define MDIO_AN_REG_CL37_CL73		0x8370
@@ -6866,6 +6986,8 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_PMA_REG_84823_LED3_STRETCH_EN			0x0080
 
 /* BCM84833 only */
+#define MDIO_84833_TOP_CFG_FW_REV			0x400f
+#define MDIO_84833_TOP_CFG_FW_EEE		0x10b1
 #define MDIO_84833_TOP_CFG_XGPHY_STRAP1			0x401a
 #define MDIO_84833_SUPER_ISOLATE		0x8000
 /* These are mailbox register set used by 84833. */
@@ -6993,11 +7115,13 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_WC_REG_DIGITAL3_UP1			0x8329
 #define MDIO_WC_REG_DIGITAL3_LP_UP1			 0x832c
 #define MDIO_WC_REG_DIGITAL4_MISC3			0x833c
+#define MDIO_WC_REG_DIGITAL4_MISC5			0x833e
 #define MDIO_WC_REG_DIGITAL5_MISC6			0x8345
 #define MDIO_WC_REG_DIGITAL5_MISC7			0x8349
 #define MDIO_WC_REG_DIGITAL5_ACTUAL_SPEED		0x834e
 #define MDIO_WC_REG_DIGITAL6_MP5_NEXTPAGECTRL		0x8350
 #define MDIO_WC_REG_CL49_USERB0_CTRL			0x8368
+#define MDIO_WC_REG_EEE_COMBO_CONTROL0			0x8390
 #define MDIO_WC_REG_TX66_CONTROL			0x83b0
 #define MDIO_WC_REG_RX66_CONTROL			0x83c0
 #define MDIO_WC_REG_RX66_SCW0				0x83c2
@@ -7036,6 +7160,7 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_REG_GPHY_EEE_1G		(0x1 << 2)
 #define MDIO_REG_GPHY_EEE_100		(0x1 << 1)
 #define MDIO_REG_GPHY_EEE_RESOLVED		0x803e
+#define MDIO_REG_GPHY_AUX_STATUS			0x19
 #define MDIO_REG_INTR_STATUS				0x1a
 #define MDIO_REG_INTR_MASK				0x1b
 #define MDIO_REG_INTR_MASK_LINK_STATUS			(0x1 << 1)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 6c14b4a..734fd87 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -4107,6 +4107,10 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
 		data->capabilities |=
 			ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY;
 
+	if (test_bit(BNX2X_RSS_IPV4_UDP, &p->rss_flags))
+		data->capabilities |=
+			ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY;
+
 	if (test_bit(BNX2X_RSS_IPV6, &p->rss_flags))
 		data->capabilities |=
 			ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY;
@@ -4115,6 +4119,10 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
 		data->capabilities |=
 			ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY;
 
+	if (test_bit(BNX2X_RSS_IPV6_UDP, &p->rss_flags))
+		data->capabilities |=
+			ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY;
+
 	/* Hashing mask */
 	data->rss_result_mask = p->rss_result_mask;
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
index efd80bd..76818ef 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
@@ -694,8 +694,10 @@ enum {
 
 	BNX2X_RSS_IPV4,
 	BNX2X_RSS_IPV4_TCP,
+	BNX2X_RSS_IPV4_UDP,
 	BNX2X_RSS_IPV6,
 	BNX2X_RSS_IPV6_TCP,
+	BNX2X_RSS_IPV6_UDP,
 };
 
 struct bnx2x_config_rss_params {
@@ -729,6 +731,10 @@ struct bnx2x_rss_config_obj {
 	/* Last configured indirection table */
 	u8			ind_table[T_ETH_INDIRECTION_TABLE_SIZE];
 
+	/* flags for enabling 4-tupple hash on UDP */
+	u8			udp_rss_v4;
+	u8			udp_rss_v6;
+
 	int (*config_rss)(struct bnx2x *bp,
 			  struct bnx2x_config_rss_params *p);
 };
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 1e2785c..514a528 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -785,6 +785,10 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
 
 	pstats->host_port_stats_counter++;
 
+	if (CHIP_IS_E3(bp))
+		estats->eee_tx_lpi += REG_RD(bp,
+					     MISC_REG_CPMU_LP_SM_ENT_CNT_P0);
+
 	if (!BP_NOMCP(bp)) {
 		u32 nig_timer_max =
 			SHMEM_RD(bp, port_mb[BP_PORT(bp)].stat_nig_timer);
@@ -855,17 +859,22 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
 		struct tstorm_per_queue_stats *tclient =
 			&bp->fw_stats_data->queue_stats[i].
 			tstorm_queue_statistics;
-		struct tstorm_per_queue_stats *old_tclient = &fp->old_tclient;
+		struct tstorm_per_queue_stats *old_tclient =
+			&bnx2x_fp_stats(bp, fp)->old_tclient;
 		struct ustorm_per_queue_stats *uclient =
 			&bp->fw_stats_data->queue_stats[i].
 			ustorm_queue_statistics;
-		struct ustorm_per_queue_stats *old_uclient = &fp->old_uclient;
+		struct ustorm_per_queue_stats *old_uclient =
+			&bnx2x_fp_stats(bp, fp)->old_uclient;
 		struct xstorm_per_queue_stats *xclient =
 			&bp->fw_stats_data->queue_stats[i].
 			xstorm_queue_statistics;
-		struct xstorm_per_queue_stats *old_xclient = &fp->old_xclient;
-		struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
-		struct bnx2x_eth_q_stats_old *qstats_old = &fp->eth_q_stats_old;
+		struct xstorm_per_queue_stats *old_xclient =
+			&bnx2x_fp_stats(bp, fp)->old_xclient;
+		struct bnx2x_eth_q_stats *qstats =
+			&bnx2x_fp_stats(bp, fp)->eth_q_stats;
+		struct bnx2x_eth_q_stats_old *qstats_old =
+			&bnx2x_fp_stats(bp, fp)->eth_q_stats_old;
 
 		u32 diff;
 
@@ -1048,8 +1057,11 @@ static void bnx2x_net_stats_update(struct bnx2x *bp)
 	nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi);
 
 	tmp = estats->mac_discard;
-	for_each_rx_queue(bp, i)
-		tmp += le32_to_cpu(bp->fp[i].old_tclient.checksum_discard);
+	for_each_rx_queue(bp, i) {
+		struct tstorm_per_queue_stats *old_tclient =
+			&bp->fp_stats[i].old_tclient;
+		tmp += le32_to_cpu(old_tclient->checksum_discard);
+	}
 	nstats->rx_dropped = tmp + bp->net_stats_old.rx_dropped;
 
 	nstats->tx_dropped = 0;
@@ -1099,9 +1111,9 @@ static void bnx2x_drv_stats_update(struct bnx2x *bp)
 	int i;
 
 	for_each_queue(bp, i) {
-		struct bnx2x_eth_q_stats *qstats = &bp->fp[i].eth_q_stats;
+		struct bnx2x_eth_q_stats *qstats = &bp->fp_stats[i].eth_q_stats;
 		struct bnx2x_eth_q_stats_old *qstats_old =
-						&bp->fp[i].eth_q_stats_old;
+			&bp->fp_stats[i].eth_q_stats_old;
 
 		UPDATE_ESTAT_QSTAT(driver_xoff);
 		UPDATE_ESTAT_QSTAT(rx_err_discard_pkt);
@@ -1428,7 +1440,7 @@ static void bnx2x_prep_fw_stats_req(struct bnx2x *bp)
 					query[first_queue_query_index + i];
 
 		cur_query_entry->kind = STATS_TYPE_QUEUE;
-		cur_query_entry->index = bnx2x_stats_id(&bp->fp[FCOE_IDX]);
+		cur_query_entry->index = bnx2x_stats_id(&bp->fp[FCOE_IDX(bp)]);
 		cur_query_entry->funcID = cpu_to_le16(BP_FUNC(bp));
 		cur_query_entry->address.hi =
 			cpu_to_le32(U64_HI(cur_data_offset));
@@ -1479,15 +1491,19 @@ void bnx2x_stats_init(struct bnx2x *bp)
 
 	/* function stats */
 	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		memset(&fp->old_tclient, 0, sizeof(fp->old_tclient));
-		memset(&fp->old_uclient, 0, sizeof(fp->old_uclient));
-		memset(&fp->old_xclient, 0, sizeof(fp->old_xclient));
+		struct bnx2x_fp_stats *fp_stats = &bp->fp_stats[i];
+
+		memset(&fp_stats->old_tclient, 0,
+		       sizeof(fp_stats->old_tclient));
+		memset(&fp_stats->old_uclient, 0,
+		       sizeof(fp_stats->old_uclient));
+		memset(&fp_stats->old_xclient, 0,
+		       sizeof(fp_stats->old_xclient));
 		if (bp->stats_init) {
-			memset(&fp->eth_q_stats, 0, sizeof(fp->eth_q_stats));
-			memset(&fp->eth_q_stats_old, 0,
-			       sizeof(fp->eth_q_stats_old));
+			memset(&fp_stats->eth_q_stats, 0,
+			       sizeof(fp_stats->eth_q_stats));
+			memset(&fp_stats->eth_q_stats_old, 0,
+			       sizeof(fp_stats->eth_q_stats_old));
 		}
 	}
 
@@ -1529,8 +1545,10 @@ void bnx2x_save_statistics(struct bnx2x *bp)
 	/* save queue statistics */
 	for_each_eth_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
-		struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
-		struct bnx2x_eth_q_stats_old *qstats_old = &fp->eth_q_stats_old;
+		struct bnx2x_eth_q_stats *qstats =
+			&bnx2x_fp_stats(bp, fp)->eth_q_stats;
+		struct bnx2x_eth_q_stats_old *qstats_old =
+			&bnx2x_fp_stats(bp, fp)->eth_q_stats_old;
 
 		UPDATE_QSTAT_OLD(total_unicast_bytes_received_hi);
 		UPDATE_QSTAT_OLD(total_unicast_bytes_received_lo);
@@ -1569,7 +1587,7 @@ void bnx2x_afex_collect_stats(struct bnx2x *bp, void *void_afex_stats,
 	struct afex_stats *afex_stats = (struct afex_stats *)void_afex_stats;
 	struct bnx2x_eth_stats *estats = &bp->eth_stats;
 	struct per_queue_stats *fcoe_q_stats =
-		&bp->fw_stats_data->queue_stats[FCOE_IDX];
+		&bp->fw_stats_data->queue_stats[FCOE_IDX(bp)];
 
 	struct tstorm_per_queue_stats *fcoe_q_tstorm_stats =
 		&fcoe_q_stats->tstorm_queue_statistics;
@@ -1586,8 +1604,7 @@ void bnx2x_afex_collect_stats(struct bnx2x *bp, void *void_afex_stats,
 	memset(afex_stats, 0, sizeof(struct afex_stats));
 
 	for_each_eth_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-		struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
+		struct bnx2x_eth_q_stats *qstats = &bp->fp_stats[i].eth_q_stats;
 
 		ADD_64(afex_stats->rx_unicast_bytes_hi,
 		       qstats->total_unicast_bytes_received_hi,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
index 93e689fd..24b8e50 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
@@ -203,6 +203,8 @@ struct bnx2x_eth_stats {
 	/* Recovery */
 	u32 recoverable_error;
 	u32 unrecoverable_error;
+	/* src: Clear-on-Read register; Will not survive PMF Migration */
+	u32 eee_tx_lpi;
 };
 
 
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index c95e7b5..65e66ca 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -2585,7 +2585,7 @@ static void cnic_bnx2x_kwqe_err(struct cnic_dev *dev, struct kwqe *kwqe)
 		return;
 	}
 
-	cqes[0] = (struct kcqe *) &kcqe;
+	cqes[0] = &kcqe;
 	cnic_reply_bnx2x_kcqes(dev, ulp_type, cqes, 1);
 }
 
@@ -4665,9 +4665,9 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
 
 	cp->kcq1.sw_prod_idx = 0;
 	cp->kcq1.hw_prod_idx_ptr =
-		(u16 *) &sblk->status_completion_producer_index;
+		&sblk->status_completion_producer_index;
 
-	cp->kcq1.status_idx_ptr = (u16 *) &sblk->status_idx;
+	cp->kcq1.status_idx_ptr = &sblk->status_idx;
 
 	/* Initialize the kernel complete queue context. */
 	val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
@@ -4693,9 +4693,9 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
 		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;
+			&msblk->status_completion_producer_index;
+		cp->kcq1.status_idx_ptr = &msblk->status_idx;
+		cp->kwq_con_idx_ptr = &msblk->status_cmd_consumer_index;
 		cp->int_num = sb_id << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT;
 		cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
 		cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index e47ff8b..149a3a7 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -14168,7 +14168,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
 			if (bridge->subordinate &&
 			    (bridge->subordinate->number <=
 			     tp->pdev->bus->number) &&
-			    (bridge->subordinate->subordinate >=
+			    (bridge->subordinate->busn_res.end >=
 			     tp->pdev->bus->number)) {
 				tg3_flag_set(tp, 5701_DMA_BUG);
 				pci_dev_put(bridge);
@@ -14196,7 +14196,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
 			if (bridge && bridge->subordinate &&
 			    (bridge->subordinate->number <=
 			     tp->pdev->bus->number) &&
-			    (bridge->subordinate->subordinate >=
+			    (bridge->subordinate->busn_res.end >=
 			     tp->pdev->bus->number)) {
 				tg3_flag_set(tp, 40BIT_DMA_BUG);
 				pci_dev_put(bridge);
diff --git a/drivers/net/ethernet/brocade/bna/cna_fwimg.c b/drivers/net/ethernet/brocade/bna/cna_fwimg.c
index cfc22a6..6a68e8d 100644
--- a/drivers/net/ethernet/brocade/bna/cna_fwimg.c
+++ b/drivers/net/ethernet/brocade/bna/cna_fwimg.c
@@ -67,10 +67,10 @@ bfa_cb_image_get_chunk(enum bfi_asic_gen asic_gen, u32 off)
 {
 	switch (asic_gen) {
 	case BFI_ASIC_GEN_CT:
-		return (u32 *)(bfi_image_ct_cna + off);
+		return (bfi_image_ct_cna + off);
 		break;
 	case BFI_ASIC_GEN_CT2:
-		return (u32 *)(bfi_image_ct2_cna + off);
+		return (bfi_image_ct2_cna + off);
 		break;
 	default:
 		return NULL;
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
index 65e4b28..55cf72a 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
@@ -575,7 +575,7 @@ static void t3_process_tid_release_list(struct work_struct *work)
 		if (!skb) {
 			spin_lock_bh(&td->tid_release_lock);
 			p->ctx = (void *)td->tid_release_list;
-			td->tid_release_list = (struct t3c_tid_entry *)p;
+			td->tid_release_list = p;
 			break;
 		}
 		mk_tid_release(skb, p - td->tid_maps.tid_tab);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index e111d97..8596aca 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -753,7 +753,7 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *q,
 		end = (void *)q->desc + part1;
 	}
 	if ((uintptr_t)end & 8)           /* 0-pad to multiple of 16 */
-		*(u64 *)end = 0;
+		*end = 0;
 }
 
 /**
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index 25e3308..9dad561 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -418,7 +418,7 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp,
 		 * restart a TX Ethernet Queue which was stopped for lack of
 		 * free TX Queue Descriptors ...
 		 */
-		const struct cpl_sge_egr_update *p = (void *)cpl;
+		const struct cpl_sge_egr_update *p = cpl;
 		unsigned int qid = EGR_QID(be32_to_cpu(p->opcode_qid));
 		struct sge *s = &adapter->sge;
 		struct sge_txq *tq;
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index 0bd585b..f2d1ecd 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -934,7 +934,7 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq,
 		end = (void *)tq->desc + part1;
 	}
 	if ((uintptr_t)end & 8)           /* 0-pad to multiple of 16 */
-		*(u64 *)end = 0;
+		*end = 0;
 }
 
 /**
@@ -1323,8 +1323,7 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
 		 */
 		if (unlikely((void *)sgl == (void *)tq->stat)) {
 			sgl = (void *)tq->desc;
-			end = (void *)((void *)tq->desc +
-				       ((void *)end - (void *)tq->stat));
+			end = ((void *)tq->desc + ((void *)end - (void *)tq->stat));
 		}
 
 		write_sgl(skb, tq, sgl, end, 0, addr);
diff --git a/drivers/net/ethernet/dec/tulip/de4x5.c b/drivers/net/ethernet/dec/tulip/de4x5.c
index d3cd489..f879e92 100644
--- a/drivers/net/ethernet/dec/tulip/de4x5.c
+++ b/drivers/net/ethernet/dec/tulip/de4x5.c
@@ -3973,7 +3973,7 @@ DevicePresent(struct net_device *dev, u_long aprom_addr)
 	    tmp = srom_rd(aprom_addr, i);
 	    *p++ = cpu_to_le16(tmp);
 	}
-	de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
+	de4x5_dbg_srom(&lp->srom);
     }
 }
 
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index c5c4c0e..7b5cc2b 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -34,7 +34,7 @@
 #include "be_hw.h"
 #include "be_roce.h"
 
-#define DRV_VER			"4.2.220u"
+#define DRV_VER			"4.2.248.0u"
 #define DRV_NAME		"be2net"
 #define BE_NAME			"ServerEngines BladeEngine2 10Gbps NIC"
 #define BE3_NAME		"ServerEngines BladeEngine3 10Gbps NIC"
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 8d06ea3..5eab791 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -122,15 +122,15 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
 			goto done;
 
 		if (compl_status == MCC_STATUS_UNAUTHORIZED_REQUEST) {
-			dev_warn(&adapter->pdev->dev, "This domain(VM) is not "
-				"permitted to execute this cmd (opcode %d)\n",
-				opcode);
+			dev_warn(&adapter->pdev->dev,
+				 "opcode %d-%d is not permitted\n",
+				 opcode, subsystem);
 		} else {
 			extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
 					CQE_STATUS_EXTD_MASK;
-			dev_err(&adapter->pdev->dev, "Cmd (opcode %d) failed:"
-				"status %d, extd-status %d\n",
-				opcode, compl_status, extd_status);
+			dev_err(&adapter->pdev->dev,
+				"opcode %d-%d failed:status %d-%d\n",
+				opcode, subsystem, compl_status, extd_status);
 		}
 	}
 done:
@@ -1132,7 +1132,7 @@ err:
  * Uses MCCQ
  */
 int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
-		u8 *mac, u32 *if_handle, u32 *pmac_id, u32 domain)
+		     u32 *if_handle, u32 domain)
 {
 	struct be_mcc_wrb *wrb;
 	struct be_cmd_req_if_create *req;
@@ -1152,17 +1152,13 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
 	req->hdr.domain = domain;
 	req->capability_flags = cpu_to_le32(cap_flags);
 	req->enable_flags = cpu_to_le32(en_flags);
-	if (mac)
-		memcpy(req->mac_addr, mac, ETH_ALEN);
-	else
-		req->pmac_invalid = true;
+
+	req->pmac_invalid = true;
 
 	status = be_mcc_notify_wait(adapter);
 	if (!status) {
 		struct be_cmd_resp_if_create *resp = embedded_payload(wrb);
 		*if_handle = le32_to_cpu(resp->interface_id);
-		if (mac)
-			*pmac_id = le32_to_cpu(resp->pmac_id);
 	}
 
 err:
@@ -2330,8 +2326,8 @@ err:
 }
 
 /* Uses synchronous MCCQ */
-int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain,
-			bool *pmac_id_active, u32 *pmac_id, u8 *mac)
+int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
+			     bool *pmac_id_active, u32 *pmac_id, u8 domain)
 {
 	struct be_mcc_wrb *wrb;
 	struct be_cmd_req_get_mac_list *req;
@@ -2376,8 +2372,9 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain,
 						get_mac_list_cmd.va;
 		mac_count = resp->true_mac_count + resp->pseudo_mac_count;
 		/* Mac list returned could contain one or more active mac_ids
-		 * or one or more pseudo permanant mac addresses. If an active
-		 * mac_id is present, return first active mac_id found
+		 * or one or more true or pseudo permanant mac addresses.
+		 * If an active mac_id is present, return first active mac_id
+		 * found.
 		 */
 		for (i = 0; i < mac_count; i++) {
 			struct get_list_macaddr *mac_entry;
@@ -2396,7 +2393,7 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain,
 				goto out;
 			}
 		}
-		/* If no active mac_id found, return first pseudo mac addr */
+		/* If no active mac_id found, return first mac addr */
 		*pmac_id_active = false;
 		memcpy(mac, resp->macaddr_list[0].mac_addr_id.macaddr,
 								ETH_ALEN);
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 9625bf4..3c938f5 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -1566,7 +1566,7 @@ struct be_hw_stats_v1 {
 	u32 rsvd0[BE_TXP_SW_SZ];
 	struct be_erx_stats_v1 erx;
 	struct be_pmem_stats pmem;
-	u32 rsvd1[3];
+	u32 rsvd1[18];
 };
 
 struct be_cmd_req_get_stats_v1 {
@@ -1664,8 +1664,7 @@ extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
 extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id,
 			int pmac_id, u32 domain);
 extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags,
-			u32 en_flags, u8 *mac, u32 *if_handle, u32 *pmac_id,
-			u32 domain);
+			    u32 en_flags, u32 *if_handle, u32 domain);
 extern int be_cmd_if_destroy(struct be_adapter *adapter, int if_handle,
 			u32 domain);
 extern int be_cmd_eq_create(struct be_adapter *adapter,
@@ -1751,8 +1750,9 @@ extern int be_cmd_get_cntl_attributes(struct be_adapter *adapter);
 extern int be_cmd_req_native_mode(struct be_adapter *adapter);
 extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size);
 extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf);
-extern int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain,
-				bool *pmac_id_active, u32 *pmac_id, u8 *mac);
+extern int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
+				    bool *pmac_id_active, u32 *pmac_id,
+				    u8 domain);
 extern int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array,
 						u8 mac_count, u32 domain);
 extern int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid,
diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
index d9fb0c5..7c8a710 100644
--- a/drivers/net/ethernet/emulex/benet/be_hw.h
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
@@ -58,8 +58,6 @@
 
 #define SLI_PORT_CONTROL_IP_MASK	0x08000000
 
-#define PCICFG_CUST_SCRATCHPAD_CSR	0x1EC
-
 /********* Memory BAR register ************/
 #define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 	0xfc
 /* Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index fdb50ce..a28896d 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -558,6 +558,7 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
 	wrb->frag_pa_hi = upper_32_bits(addr);
 	wrb->frag_pa_lo = addr & 0xFFFFFFFF;
 	wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
+	wrb->rsvd0 = 0;
 }
 
 static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
@@ -719,8 +720,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
 	 * 60 bytes long.
 	 * As a workaround disable TX vlan offloading in such cases.
 	 */
-	if (unlikely(vlan_tx_tag_present(skb) &&
-		     (skb->ip_summed != CHECKSUM_PARTIAL || skb->len <= 60))) {
+	if (vlan_tx_tag_present(skb) &&
+	    (skb->ip_summed != CHECKSUM_PARTIAL || skb->len <= 60)) {
 		skb = skb_share_check(skb, GFP_ATOMIC);
 		if (unlikely(!skb))
 			goto tx_drop;
@@ -786,19 +787,12 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu)
  * 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, bool vf, u32 vf_num)
+static int be_vid_config(struct be_adapter *adapter)
 {
-	struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf_num];
-	u16 vtag[BE_NUM_VLANS_SUPPORTED];
-	u16 ntags = 0, i;
+	u16 vids[BE_NUM_VLANS_SUPPORTED];
+	u16 num = 0, i;
 	int status = 0;
 
-	if (vf) {
-		vtag[0] = cpu_to_le16(vf_cfg->vlan_tag);
-		status = be_cmd_vlan_config(adapter, vf_cfg->if_handle, vtag,
-					    1, 1, 0);
-	}
-
 	/* No need to further configure vids if in promiscuous mode */
 	if (adapter->promiscuous)
 		return 0;
@@ -809,10 +803,10 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
 	/* Construct VLAN Table to give to HW */
 	for (i = 0; i < VLAN_N_VID; i++)
 		if (adapter->vlan_tag[i])
-			vtag[ntags++] = cpu_to_le16(i);
+			vids[num++] = cpu_to_le16(i);
 
 	status = be_cmd_vlan_config(adapter, adapter->if_handle,
-				    vtag, ntags, 1, 0);
+				    vids, num, 1, 0);
 
 	/* Set to VLAN promisc mode as setting VLAN filter failed */
 	if (status) {
@@ -841,7 +835,7 @@ static int be_vlan_add_vid(struct net_device *netdev, u16 vid)
 
 	adapter->vlan_tag[vid] = 1;
 	if (adapter->vlans_added <= (adapter->max_vlans + 1))
-		status = be_vid_config(adapter, false, 0);
+		status = be_vid_config(adapter);
 
 	if (!status)
 		adapter->vlans_added++;
@@ -863,7 +857,7 @@ static int be_vlan_rem_vid(struct net_device *netdev, u16 vid)
 
 	adapter->vlan_tag[vid] = 0;
 	if (adapter->vlans_added <= adapter->max_vlans)
-		status = be_vid_config(adapter, false, 0);
+		status = be_vid_config(adapter);
 
 	if (!status)
 		adapter->vlans_added--;
@@ -890,7 +884,7 @@ static void be_set_rx_mode(struct net_device *netdev)
 		be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
 
 		if (adapter->vlans_added)
-			be_vid_config(adapter, false, 0);
+			be_vid_config(adapter);
 	}
 
 	/* Enable multicast promisc if num configured exceeds what we support */
@@ -1057,13 +1051,16 @@ static int be_find_vfs(struct be_adapter *adapter, int vf_state)
 	u16 offset, stride;
 
 	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+	if (!pos)
+		return 0;
 	pci_read_config_word(pdev, pos + PCI_SRIOV_VF_OFFSET, &offset);
 	pci_read_config_word(pdev, pos + PCI_SRIOV_VF_STRIDE, &stride);
 
 	dev = pci_get_device(pdev->vendor, PCI_ANY_ID, NULL);
 	while (dev) {
 		vf_fn = (pdev->devfn + offset + stride * vfs) & 0xFFFF;
-		if (dev->is_virtfn && dev->devfn == vf_fn) {
+		if (dev->is_virtfn && dev->devfn == vf_fn &&
+			dev->bus->number == pdev->bus->number) {
 			vfs++;
 			if (dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
 				assigned_vfs++;
@@ -1898,6 +1895,12 @@ static int be_rx_cqs_create(struct be_adapter *adapter)
 	 */
 	adapter->num_rx_qs = (num_irqs(adapter) > 1) ?
 				num_irqs(adapter) + 1 : 1;
+	if (adapter->num_rx_qs != MAX_RX_QS) {
+		rtnl_lock();
+		netif_set_real_num_rx_queues(adapter->netdev,
+					     adapter->num_rx_qs);
+		rtnl_unlock();
+	}
 
 	adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
 	for_all_rx_queues(adapter, rxo, i) {
@@ -2544,7 +2547,6 @@ static int be_clear(struct be_adapter *adapter)
 	be_cmd_fw_clean(adapter);
 
 	be_msix_disable(adapter);
-	pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 0);
 	return 0;
 }
 
@@ -2602,8 +2604,8 @@ static int be_vf_setup(struct be_adapter *adapter)
 	cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
 				BE_IF_FLAGS_MULTICAST;
 	for_all_vfs(adapter, vf_cfg, vf) {
-		status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL,
-					  &vf_cfg->if_handle, NULL, vf + 1);
+		status = be_cmd_if_create(adapter, cap_flags, en_flags,
+					  &vf_cfg->if_handle, vf + 1);
 		if (status)
 			goto err;
 	}
@@ -2643,29 +2645,43 @@ static void be_setup_init(struct be_adapter *adapter)
 	adapter->phy.forced_port_speed = -1;
 }
 
-static int be_add_mac_from_list(struct be_adapter *adapter, u8 *mac)
+static int be_get_mac_addr(struct be_adapter *adapter, u8 *mac, u32 if_handle,
+			   bool *active_mac, u32 *pmac_id)
 {
-	u32 pmac_id;
-	int status;
-	bool pmac_id_active;
+	int status = 0;
 
-	status = be_cmd_get_mac_from_list(adapter, 0, &pmac_id_active,
-							&pmac_id, mac);
-	if (status != 0)
-		goto do_none;
+	if (!is_zero_ether_addr(adapter->netdev->perm_addr)) {
+		memcpy(mac, adapter->netdev->dev_addr, ETH_ALEN);
+		if (!lancer_chip(adapter) && !be_physfn(adapter))
+			*active_mac = true;
+		else
+			*active_mac = false;
 
-	if (pmac_id_active) {
-		status = be_cmd_mac_addr_query(adapter, mac,
-				MAC_ADDRESS_TYPE_NETWORK,
-				false, adapter->if_handle, pmac_id);
+		return status;
+	}
 
-		if (!status)
-			adapter->pmac_id[0] = pmac_id;
+	if (lancer_chip(adapter)) {
+		status = be_cmd_get_mac_from_list(adapter, mac,
+						  active_mac, pmac_id, 0);
+		if (*active_mac) {
+			status = be_cmd_mac_addr_query(adapter, mac,
+						       MAC_ADDRESS_TYPE_NETWORK,
+						       false, if_handle,
+						       *pmac_id);
+		}
+	} else if (be_physfn(adapter)) {
+		/* For BE3, for PF get permanent MAC */
+		status = be_cmd_mac_addr_query(adapter, mac,
+					       MAC_ADDRESS_TYPE_NETWORK, true,
+					       0, 0);
+		*active_mac = false;
 	} else {
-		status = be_cmd_pmac_add(adapter, mac,
-				adapter->if_handle, &adapter->pmac_id[0], 0);
+		/* For BE3, for VF get soft MAC assigned by PF*/
+		status = be_cmd_mac_addr_query(adapter, mac,
+					       MAC_ADDRESS_TYPE_NETWORK, false,
+					       if_handle, 0);
+		*active_mac = true;
 	}
-do_none:
 	return status;
 }
 
@@ -2686,12 +2702,12 @@ static int be_get_config(struct be_adapter *adapter)
 
 static int be_setup(struct be_adapter *adapter)
 {
-	struct net_device *netdev = adapter->netdev;
 	struct device *dev = &adapter->pdev->dev;
 	u32 cap_flags, en_flags;
 	u32 tx_fc, rx_fc;
 	int status;
 	u8 mac[ETH_ALEN];
+	bool active_mac;
 
 	be_setup_init(adapter);
 
@@ -2717,14 +2733,6 @@ static int be_setup(struct be_adapter *adapter)
 	if (status)
 		goto err;
 
-	memset(mac, 0, ETH_ALEN);
-	status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK,
-			true /*permanent */, 0, 0);
-	if (status)
-		return status;
-	memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
-	memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
-
 	en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
 			BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS;
 	cap_flags = en_flags | BE_IF_FLAGS_MCAST_PROMISCUOUS |
@@ -2734,27 +2742,29 @@ static int be_setup(struct be_adapter *adapter)
 		cap_flags |= BE_IF_FLAGS_RSS;
 		en_flags |= BE_IF_FLAGS_RSS;
 	}
+
 	status = be_cmd_if_create(adapter, cap_flags, en_flags,
-			netdev->dev_addr, &adapter->if_handle,
-			&adapter->pmac_id[0], 0);
+				  &adapter->if_handle, 0);
 	if (status != 0)
 		goto err;
 
-	 /* The VF's permanent mac queried from card is incorrect.
-	  * For BEx: Query the mac configued by the PF using if_handle
-	  * For Lancer: Get and use mac_list to obtain mac address.
-	  */
-	if (!be_physfn(adapter)) {
-		if (lancer_chip(adapter))
-			status = be_add_mac_from_list(adapter, mac);
-		else
-			status = be_cmd_mac_addr_query(adapter, mac,
-					MAC_ADDRESS_TYPE_NETWORK, false,
-					adapter->if_handle, 0);
-		if (!status) {
-			memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
-			memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
-		}
+	memset(mac, 0, ETH_ALEN);
+	active_mac = false;
+	status = be_get_mac_addr(adapter, mac, adapter->if_handle,
+				 &active_mac, &adapter->pmac_id[0]);
+	if (status != 0)
+		goto err;
+
+	if (!active_mac) {
+		status = be_cmd_pmac_add(adapter, mac, adapter->if_handle,
+					 &adapter->pmac_id[0], 0);
+		if (status != 0)
+			goto err;
+	}
+
+	if (is_zero_ether_addr(adapter->netdev->dev_addr)) {
+		memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
+		memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
 	}
 
 	status = be_tx_qs_create(adapter);
@@ -2763,7 +2773,8 @@ static int be_setup(struct be_adapter *adapter)
 
 	be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL);
 
-	be_vid_config(adapter, false, 0);
+	if (adapter->vlans_added)
+		be_vid_config(adapter);
 
 	be_set_rx_mode(adapter->netdev);
 
@@ -2773,8 +2784,6 @@ static int be_setup(struct be_adapter *adapter)
 		be_cmd_set_flow_control(adapter, adapter->tx_fc,
 					adapter->rx_fc);
 
-	pcie_set_readrq(adapter->pdev, 4096);
-
 	if (be_physfn(adapter) && num_vfs) {
 		if (adapter->dev_num_vfs)
 			be_vf_setup(adapter);
@@ -2788,8 +2797,6 @@ static int be_setup(struct be_adapter *adapter)
 
 	schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
 	adapter->flags |= BE_FLAGS_WORKER_SCHEDULED;
-
-	pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 1);
 	return 0;
 err:
 	be_clear(adapter);
@@ -3237,7 +3244,7 @@ static void be_netdev_init(struct net_device *netdev)
 
 	netdev->flags |= IFF_MULTICAST;
 
-	netif_set_gso_max_size(netdev, 65535);
+	netif_set_gso_max_size(netdev, 65535 - ETH_HLEN);
 
 	netdev->netdev_ops = &be_netdev_ops;
 
@@ -3727,10 +3734,7 @@ reschedule:
 
 static bool be_reset_required(struct be_adapter *adapter)
 {
-	u32 reg;
-
-	pci_read_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, &reg);
-	return reg;
+	return be_find_vfs(adapter, ENABLED) > 0 ? false : true;
 }
 
 static int __devinit be_probe(struct pci_dev *pdev,
@@ -3749,7 +3753,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
 		goto disable_dev;
 	pci_set_master(pdev);
 
-	netdev = alloc_etherdev_mq(sizeof(struct be_adapter), MAX_TX_QS);
+	netdev = alloc_etherdev_mqs(sizeof(*adapter), MAX_TX_QS, MAX_RX_QS);
 	if (netdev == NULL) {
 		status = -ENOMEM;
 		goto rel_reg;
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 0741ade..f00a095 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -1,5 +1,4 @@
-/*
- * drivers/net/ethernet/freescale/gianfar.c
+/* drivers/net/ethernet/freescale/gianfar.c
  *
  * Gianfar Ethernet Driver
  * This driver is designed for the non-CPM ethernet controllers
@@ -114,7 +113,7 @@ static void gfar_timeout(struct net_device *dev);
 static int gfar_close(struct net_device *dev);
 struct sk_buff *gfar_new_skb(struct net_device *dev);
 static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
-		struct sk_buff *skb);
+			   struct sk_buff *skb);
 static int gfar_set_mac_address(struct net_device *dev);
 static int gfar_change_mtu(struct net_device *dev, int new_mtu);
 static irqreturn_t gfar_error(int irq, void *dev_id);
@@ -266,8 +265,8 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
 		tx_queue->tx_bd_dma_base = addr;
 		tx_queue->dev = ndev;
 		/* enet DMA only understands physical addresses */
-		addr    += sizeof(struct txbd8) *tx_queue->tx_ring_size;
-		vaddr   += sizeof(struct txbd8) *tx_queue->tx_ring_size;
+		addr  += sizeof(struct txbd8) * tx_queue->tx_ring_size;
+		vaddr += sizeof(struct txbd8) * tx_queue->tx_ring_size;
 	}
 
 	/* Start the rx descriptor ring where the tx ring leaves off */
@@ -276,15 +275,16 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
 		rx_queue->rx_bd_base = vaddr;
 		rx_queue->rx_bd_dma_base = addr;
 		rx_queue->dev = ndev;
-		addr    += sizeof (struct rxbd8) * rx_queue->rx_ring_size;
-		vaddr   += sizeof (struct rxbd8) * rx_queue->rx_ring_size;
+		addr  += sizeof(struct rxbd8) * rx_queue->rx_ring_size;
+		vaddr += sizeof(struct rxbd8) * rx_queue->rx_ring_size;
 	}
 
 	/* Setup the skbuff rings */
 	for (i = 0; i < priv->num_tx_queues; i++) {
 		tx_queue = priv->tx_queue[i];
 		tx_queue->tx_skbuff = kmalloc(sizeof(*tx_queue->tx_skbuff) *
-				  tx_queue->tx_ring_size, GFP_KERNEL);
+					      tx_queue->tx_ring_size,
+					      GFP_KERNEL);
 		if (!tx_queue->tx_skbuff) {
 			netif_err(priv, ifup, ndev,
 				  "Could not allocate tx_skbuff\n");
@@ -298,7 +298,8 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
 	for (i = 0; i < priv->num_rx_queues; i++) {
 		rx_queue = priv->rx_queue[i];
 		rx_queue->rx_skbuff = kmalloc(sizeof(*rx_queue->rx_skbuff) *
-				  rx_queue->rx_ring_size, GFP_KERNEL);
+					      rx_queue->rx_ring_size,
+					      GFP_KERNEL);
 
 		if (!rx_queue->rx_skbuff) {
 			netif_err(priv, ifup, ndev,
@@ -327,15 +328,15 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv)
 	int i;
 
 	baddr = &regs->tbase0;
-	for(i = 0; i < priv->num_tx_queues; i++) {
+	for (i = 0; i < priv->num_tx_queues; i++) {
 		gfar_write(baddr, priv->tx_queue[i]->tx_bd_dma_base);
-		baddr	+= 2;
+		baddr += 2;
 	}
 
 	baddr = &regs->rbase0;
-	for(i = 0; i < priv->num_rx_queues; i++) {
+	for (i = 0; i < priv->num_rx_queues; i++) {
 		gfar_write(baddr, priv->rx_queue[i]->rx_bd_dma_base);
-		baddr   += 2;
+		baddr += 2;
 	}
 }
 
@@ -405,7 +406,8 @@ static void gfar_init_mac(struct net_device *ndev)
 	gfar_write(&regs->attreli, attrs);
 
 	/* Start with defaults, and add stashing or locking
-	 * depending on the approprate variables */
+	 * depending on the approprate variables
+	 */
 	attrs = ATTR_INIT_SETTINGS;
 
 	if (priv->bd_stash_en)
@@ -426,16 +428,16 @@ static struct net_device_stats *gfar_get_stats(struct net_device *dev)
 	struct gfar_private *priv = netdev_priv(dev);
 	unsigned long rx_packets = 0, rx_bytes = 0, rx_dropped = 0;
 	unsigned long tx_packets = 0, tx_bytes = 0;
-	int i = 0;
+	int i;
 
 	for (i = 0; i < priv->num_rx_queues; i++) {
 		rx_packets += priv->rx_queue[i]->stats.rx_packets;
-		rx_bytes += priv->rx_queue[i]->stats.rx_bytes;
+		rx_bytes   += priv->rx_queue[i]->stats.rx_bytes;
 		rx_dropped += priv->rx_queue[i]->stats.rx_dropped;
 	}
 
 	dev->stats.rx_packets = rx_packets;
-	dev->stats.rx_bytes = rx_bytes;
+	dev->stats.rx_bytes   = rx_bytes;
 	dev->stats.rx_dropped = rx_dropped;
 
 	for (i = 0; i < priv->num_tx_queues; i++) {
@@ -443,7 +445,7 @@ static struct net_device_stats *gfar_get_stats(struct net_device *dev)
 		tx_packets += priv->tx_queue[i]->stats.tx_packets;
 	}
 
-	dev->stats.tx_bytes = tx_bytes;
+	dev->stats.tx_bytes   = tx_bytes;
 	dev->stats.tx_packets = tx_packets;
 
 	return &dev->stats;
@@ -468,7 +470,7 @@ static const struct net_device_ops gfar_netdev_ops = {
 
 void lock_rx_qs(struct gfar_private *priv)
 {
-	int i = 0x0;
+	int i;
 
 	for (i = 0; i < priv->num_rx_queues; i++)
 		spin_lock(&priv->rx_queue[i]->rxlock);
@@ -476,7 +478,7 @@ void lock_rx_qs(struct gfar_private *priv)
 
 void lock_tx_qs(struct gfar_private *priv)
 {
-	int i = 0x0;
+	int i;
 
 	for (i = 0; i < priv->num_tx_queues; i++)
 		spin_lock(&priv->tx_queue[i]->txlock);
@@ -484,7 +486,7 @@ void lock_tx_qs(struct gfar_private *priv)
 
 void unlock_rx_qs(struct gfar_private *priv)
 {
-	int i = 0x0;
+	int i;
 
 	for (i = 0; i < priv->num_rx_queues; i++)
 		spin_unlock(&priv->rx_queue[i]->rxlock);
@@ -492,7 +494,7 @@ void unlock_rx_qs(struct gfar_private *priv)
 
 void unlock_tx_qs(struct gfar_private *priv)
 {
-	int i = 0x0;
+	int i;
 
 	for (i = 0; i < priv->num_tx_queues; i++)
 		spin_unlock(&priv->tx_queue[i]->txlock);
@@ -508,13 +510,13 @@ static bool gfar_is_vlan_on(struct gfar_private *priv)
 static inline int gfar_uses_fcb(struct gfar_private *priv)
 {
 	return gfar_is_vlan_on(priv) ||
-		(priv->ndev->features & NETIF_F_RXCSUM) ||
-		(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER);
+	       (priv->ndev->features & NETIF_F_RXCSUM) ||
+	       (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER);
 }
 
 static void free_tx_pointers(struct gfar_private *priv)
 {
-	int i = 0;
+	int i;
 
 	for (i = 0; i < priv->num_tx_queues; i++)
 		kfree(priv->tx_queue[i]);
@@ -522,7 +524,7 @@ static void free_tx_pointers(struct gfar_private *priv)
 
 static void free_rx_pointers(struct gfar_private *priv)
 {
-	int i = 0;
+	int i;
 
 	for (i = 0; i < priv->num_rx_queues; i++)
 		kfree(priv->rx_queue[i]);
@@ -530,7 +532,7 @@ static void free_rx_pointers(struct gfar_private *priv)
 
 static void unmap_group_regs(struct gfar_private *priv)
 {
-	int i = 0;
+	int i;
 
 	for (i = 0; i < MAXGROUPS; i++)
 		if (priv->gfargrp[i].regs)
@@ -539,7 +541,7 @@ static void unmap_group_regs(struct gfar_private *priv)
 
 static void disable_napi(struct gfar_private *priv)
 {
-	int i = 0;
+	int i;
 
 	for (i = 0; i < priv->num_grps; i++)
 		napi_disable(&priv->gfargrp[i].napi);
@@ -547,14 +549,14 @@ static void disable_napi(struct gfar_private *priv)
 
 static void enable_napi(struct gfar_private *priv)
 {
-	int i = 0;
+	int i;
 
 	for (i = 0; i < priv->num_grps; i++)
 		napi_enable(&priv->gfargrp[i].napi);
 }
 
 static int gfar_parse_group(struct device_node *np,
-		struct gfar_private *priv, const char *model)
+			    struct gfar_private *priv, const char *model)
 {
 	u32 *queue_mask;
 
@@ -580,15 +582,13 @@ static int gfar_parse_group(struct device_node *np,
 	priv->gfargrp[priv->num_grps].grp_id = priv->num_grps;
 	priv->gfargrp[priv->num_grps].priv = priv;
 	spin_lock_init(&priv->gfargrp[priv->num_grps].grplock);
-	if(priv->mode == MQ_MG_MODE) {
-		queue_mask = (u32 *)of_get_property(np,
-					"fsl,rx-bit-map", NULL);
-		priv->gfargrp[priv->num_grps].rx_bit_map =
-			queue_mask ?  *queue_mask :(DEFAULT_MAPPING >> priv->num_grps);
-		queue_mask = (u32 *)of_get_property(np,
-					"fsl,tx-bit-map", NULL);
-		priv->gfargrp[priv->num_grps].tx_bit_map =
-			queue_mask ? *queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
+	if (priv->mode == MQ_MG_MODE) {
+		queue_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL);
+		priv->gfargrp[priv->num_grps].rx_bit_map = queue_mask ?
+			*queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
+		queue_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL);
+		priv->gfargrp[priv->num_grps].tx_bit_map = queue_mask ?
+			*queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
 	} else {
 		priv->gfargrp[priv->num_grps].rx_bit_map = 0xFF;
 		priv->gfargrp[priv->num_grps].tx_bit_map = 0xFF;
@@ -652,7 +652,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 	priv->num_rx_queues = num_rx_qs;
 	priv->num_grps = 0x0;
 
-	/* Init Rx queue filer rule set linked list*/
+	/* Init Rx queue filer rule set linked list */
 	INIT_LIST_HEAD(&priv->rx_list.list);
 	priv->rx_list.count = 0;
 	mutex_init(&priv->rx_queue_access);
@@ -673,7 +673,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 	} else {
 		priv->mode = SQ_SG_MODE;
 		err = gfar_parse_group(np, priv, model);
-		if(err)
+		if (err)
 			goto err_grp_init;
 	}
 
@@ -730,27 +730,27 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 		priv->device_flags |= FSL_GIANFAR_DEV_HAS_BUF_STASHING;
 
 	mac_addr = of_get_mac_address(np);
+
 	if (mac_addr)
 		memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
 
 	if (model && !strcasecmp(model, "TSEC"))
-		priv->device_flags =
-			FSL_GIANFAR_DEV_HAS_GIGABIT |
-			FSL_GIANFAR_DEV_HAS_COALESCE |
-			FSL_GIANFAR_DEV_HAS_RMON |
-			FSL_GIANFAR_DEV_HAS_MULTI_INTR;
+		priv->device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+				     FSL_GIANFAR_DEV_HAS_COALESCE |
+				     FSL_GIANFAR_DEV_HAS_RMON |
+				     FSL_GIANFAR_DEV_HAS_MULTI_INTR;
+
 	if (model && !strcasecmp(model, "eTSEC"))
-		priv->device_flags =
-			FSL_GIANFAR_DEV_HAS_GIGABIT |
-			FSL_GIANFAR_DEV_HAS_COALESCE |
-			FSL_GIANFAR_DEV_HAS_RMON |
-			FSL_GIANFAR_DEV_HAS_MULTI_INTR |
-			FSL_GIANFAR_DEV_HAS_PADDING |
-			FSL_GIANFAR_DEV_HAS_CSUM |
-			FSL_GIANFAR_DEV_HAS_VLAN |
-			FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
-			FSL_GIANFAR_DEV_HAS_EXTENDED_HASH |
-			FSL_GIANFAR_DEV_HAS_TIMER;
+		priv->device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+				     FSL_GIANFAR_DEV_HAS_COALESCE |
+				     FSL_GIANFAR_DEV_HAS_RMON |
+				     FSL_GIANFAR_DEV_HAS_MULTI_INTR |
+				     FSL_GIANFAR_DEV_HAS_PADDING |
+				     FSL_GIANFAR_DEV_HAS_CSUM |
+				     FSL_GIANFAR_DEV_HAS_VLAN |
+				     FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
+				     FSL_GIANFAR_DEV_HAS_EXTENDED_HASH |
+				     FSL_GIANFAR_DEV_HAS_TIMER;
 
 	ctype = of_get_property(np, "phy-connection-type", NULL);
 
@@ -781,7 +781,7 @@ err_grp_init:
 }
 
 static int gfar_hwtstamp_ioctl(struct net_device *netdev,
-			struct ifreq *ifr, int cmd)
+			       struct ifreq *ifr, int cmd)
 {
 	struct hwtstamp_config config;
 	struct gfar_private *priv = netdev_priv(netdev);
@@ -851,6 +851,7 @@ static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs)
 {
 	unsigned int new_bit_map = 0x0;
 	int mask = 0x1 << (max_qs - 1), i;
+
 	for (i = 0; i < max_qs; i++) {
 		if (bit_map & mask)
 			new_bit_map = new_bit_map + (1 << i);
@@ -936,22 +937,22 @@ static void gfar_detect_errata(struct gfar_private *priv)
 
 	/* MPC8313 Rev 2.0 and higher; All MPC837x */
 	if ((pvr == 0x80850010 && mod == 0x80b0 && rev >= 0x0020) ||
-			(pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
+	    (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))
+	    (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))
+	    (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
 		priv->errata |= GFAR_ERRATA_A002;
 
 	/* MPC8313 Rev < 2.0, MPC8548 rev 2.0 */
 	if ((pvr == 0x80850010 && mod == 0x80b0 && rev < 0x0020) ||
-			(pvr == 0x80210020 && mod == 0x8030 && rev == 0x0020))
+	    (pvr == 0x80210020 && mod == 0x8030 && rev == 0x0020))
 		priv->errata |= GFAR_ERRATA_12;
 
 	if (priv->errata)
@@ -960,7 +961,8 @@ static void gfar_detect_errata(struct gfar_private *priv)
 }
 
 /* Set up the ethernet device structure, private data,
- * and anything else we need before we start */
+ * and anything else we need before we start
+ */
 static int gfar_probe(struct platform_device *ofdev)
 {
 	u32 tempval;
@@ -991,8 +993,9 @@ static int gfar_probe(struct platform_device *ofdev)
 
 	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). */
+	/* Stop the DMA engine now, in case it was running before
+	 * (The firmware could have used it, and left it running).
+	 */
 	gfar_halt(dev);
 
 	/* Reset MAC layer */
@@ -1026,13 +1029,14 @@ static int gfar_probe(struct platform_device *ofdev)
 
 	/* Register for napi ...We are registering NAPI for each grp */
 	for (i = 0; i < priv->num_grps; i++)
-		netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll, GFAR_DEV_WEIGHT);
+		netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll,
+			       GFAR_DEV_WEIGHT);
 
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
 		dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
-			NETIF_F_RXCSUM;
+				   NETIF_F_RXCSUM;
 		dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG |
-			NETIF_F_RXCSUM | NETIF_F_HIGHDMA;
+				 NETIF_F_RXCSUM | NETIF_F_HIGHDMA;
 	}
 
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
@@ -1081,7 +1085,7 @@ static int gfar_probe(struct platform_device *ofdev)
 		priv->padding = 0;
 
 	if (dev->features & NETIF_F_IP_CSUM ||
-			priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
+	    priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
 		dev->needed_headroom = GMAC_FCB_LEN;
 
 	/* Program the isrg regs only if number of grps > 1 */
@@ -1098,28 +1102,32 @@ static int gfar_probe(struct platform_device *ofdev)
 
 	/* Need to reverse the bit maps as  bit_map's MSB is q0
 	 * but, for_each_set_bit parses from right to left, which
-	 * basically reverses the queue numbers */
+	 * basically reverses the queue numbers
+	 */
 	for (i = 0; i< priv->num_grps; i++) {
-		priv->gfargrp[i].tx_bit_map = reverse_bitmap(
-				priv->gfargrp[i].tx_bit_map, MAX_TX_QS);
-		priv->gfargrp[i].rx_bit_map = reverse_bitmap(
-				priv->gfargrp[i].rx_bit_map, MAX_RX_QS);
+		priv->gfargrp[i].tx_bit_map =
+			reverse_bitmap(priv->gfargrp[i].tx_bit_map, MAX_TX_QS);
+		priv->gfargrp[i].rx_bit_map =
+			reverse_bitmap(priv->gfargrp[i].rx_bit_map, MAX_RX_QS);
 	}
 
 	/* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values,
-	 * also assign queues to groups */
+	 * also assign queues to groups
+	 */
 	for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) {
 		priv->gfargrp[grp_idx].num_rx_queues = 0x0;
+
 		for_each_set_bit(i, &priv->gfargrp[grp_idx].rx_bit_map,
-				priv->num_rx_queues) {
+				 priv->num_rx_queues) {
 			priv->gfargrp[grp_idx].num_rx_queues++;
 			priv->rx_queue[i]->grp = &priv->gfargrp[grp_idx];
 			rstat = rstat | (RSTAT_CLEAR_RHALT >> i);
 			rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i);
 		}
 		priv->gfargrp[grp_idx].num_tx_queues = 0x0;
+
 		for_each_set_bit(i, &priv->gfargrp[grp_idx].tx_bit_map,
-				priv->num_tx_queues) {
+				 priv->num_tx_queues) {
 			priv->gfargrp[grp_idx].num_tx_queues++;
 			priv->tx_queue[i]->grp = &priv->gfargrp[grp_idx];
 			tstat = tstat | (TSTAT_CLEAR_THALT >> i);
@@ -1149,7 +1157,7 @@ static int gfar_probe(struct platform_device *ofdev)
 		priv->rx_queue[i]->rxic = DEFAULT_RXIC;
 	}
 
-	/* always enable rx filer*/
+	/* always enable rx filer */
 	priv->rx_filer_enable = 1;
 	/* Enable most messages by default */
 	priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
@@ -1165,7 +1173,8 @@ static int gfar_probe(struct platform_device *ofdev)
 	}
 
 	device_init_wakeup(&dev->dev,
-		priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+			   priv->device_flags &
+			   FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
 	/* fill out IRQ number and name fields */
 	for (i = 0; i < priv->num_grps; i++) {
@@ -1189,13 +1198,14 @@ static int gfar_probe(struct platform_device *ofdev)
 	/* Print out the device info */
 	netdev_info(dev, "mac: %pM\n", dev->dev_addr);
 
-	/* Even more device info helps when determining which kernel */
-	/* provided which set of benchmarks. */
+	/* Even more device info helps when determining which kernel
+	 * provided which set of benchmarks.
+	 */
 	netdev_info(dev, "Running with NAPI enabled\n");
 	for (i = 0; i < priv->num_rx_queues; i++)
 		netdev_info(dev, "RX BD ring size for Q[%d]: %d\n",
 			    i, priv->rx_queue[i]->rx_ring_size);
-	for(i = 0; i < priv->num_tx_queues; i++)
+	for (i = 0; i < priv->num_tx_queues; i++)
 		netdev_info(dev, "TX BD ring size for Q[%d]: %d\n",
 			    i, priv->tx_queue[i]->tx_ring_size);
 
@@ -1242,7 +1252,8 @@ static int gfar_suspend(struct device *dev)
 	u32 tempval;
 
 	int magic_packet = priv->wol_en &&
-		(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+			   (priv->device_flags &
+			    FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
 	netif_device_detach(ndev);
 
@@ -1294,7 +1305,8 @@ static int gfar_resume(struct device *dev)
 	unsigned long flags;
 	u32 tempval;
 	int magic_packet = priv->wol_en &&
-		(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+			   (priv->device_flags &
+			    FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
 	if (!netif_running(ndev)) {
 		netif_device_attach(ndev);
@@ -1393,13 +1405,13 @@ static phy_interface_t gfar_get_interface(struct net_device *dev)
 	}
 
 	if (ecntrl & ECNTRL_REDUCED_MODE) {
-		if (ecntrl & ECNTRL_REDUCED_MII_MODE)
+		if (ecntrl & ECNTRL_REDUCED_MII_MODE) {
 			return PHY_INTERFACE_MODE_RMII;
+		}
 		else {
 			phy_interface_t interface = priv->interface;
 
-			/*
-			 * This isn't autodetected right now, so it must
+			/* This isn't autodetected right now, so it must
 			 * be set by the device tree or platform code.
 			 */
 			if (interface == PHY_INTERFACE_MODE_RGMII_ID)
@@ -1453,8 +1465,7 @@ static int init_phy(struct net_device *dev)
 	return 0;
 }
 
-/*
- * Initialize TBI PHY interface for communicating with the
+/* Initialize TBI PHY interface for communicating with the
  * SERDES lynx PHY on the chip.  We communicate with this PHY
  * through the MDIO bus on each controller, treating it as a
  * "normal" PHY at the address found in the TBIPA register.  We assume
@@ -1479,8 +1490,7 @@ static void gfar_configure_serdes(struct net_device *dev)
 		return;
 	}
 
-	/*
-	 * If the link is already up, we must already be ok, and don't need to
+	/* If the link is already up, we must already be ok, and don't need to
 	 * configure and reset the TBI<->SerDes link.  Maybe U-Boot configured
 	 * everything for us?  Resetting it takes the link down and requires
 	 * several seconds for it to come back.
@@ -1492,18 +1502,19 @@ static void gfar_configure_serdes(struct net_device *dev)
 	phy_write(tbiphy, MII_TBICON, TBICON_CLK_SELECT);
 
 	phy_write(tbiphy, MII_ADVERTISE,
-			ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
-			ADVERTISE_1000XPSE_ASYM);
+		  ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
+		  ADVERTISE_1000XPSE_ASYM);
 
-	phy_write(tbiphy, MII_BMCR, BMCR_ANENABLE |
-			BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000);
+	phy_write(tbiphy, MII_BMCR,
+		  BMCR_ANENABLE | BMCR_ANRESTART | BMCR_FULLDPLX |
+		  BMCR_SPEED1000);
 }
 
 static void init_registers(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar __iomem *regs = NULL;
-	int i = 0;
+	int i;
 
 	for (i = 0; i < priv->num_grps; i++) {
 		regs = priv->gfargrp[i].regs;
@@ -1554,15 +1565,13 @@ static int __gfar_is_rx_idle(struct gfar_private *priv)
 {
 	u32 res;
 
-	/*
-	 * Normaly TSEC should not hang on GRS commands, so we should
+	/* 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
+	/* 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.
 	 */
@@ -1580,7 +1589,7 @@ static void gfar_halt_nodisable(struct net_device *dev)
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar __iomem *regs = NULL;
 	u32 tempval;
-	int i = 0;
+	int i;
 
 	for (i = 0; i < priv->num_grps; i++) {
 		regs = priv->gfargrp[i].regs;
@@ -1594,8 +1603,8 @@ static void gfar_halt_nodisable(struct net_device *dev)
 	regs = priv->gfargrp[0].regs;
 	/* Stop the DMA, and wait for it to stop */
 	tempval = gfar_read(&regs->dmactrl);
-	if ((tempval & (DMACTRL_GRS | DMACTRL_GTS))
-	    != (DMACTRL_GRS | DMACTRL_GTS)) {
+	if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) !=
+	    (DMACTRL_GRS | DMACTRL_GTS)) {
 		int ret;
 
 		tempval |= (DMACTRL_GRS | DMACTRL_GTS);
@@ -1660,7 +1669,7 @@ void stop_gfar(struct net_device *dev)
 	} else {
 		for (i = 0; i < priv->num_grps; i++)
 			free_irq(priv->gfargrp[i].interruptTransmit,
-					&priv->gfargrp[i]);
+				 &priv->gfargrp[i]);
 	}
 
 	free_skb_resources(priv);
@@ -1679,13 +1688,13 @@ static void free_skb_tx_queue(struct gfar_priv_tx_q *tx_queue)
 			continue;
 
 		dma_unmap_single(&priv->ofdev->dev, txbdp->bufPtr,
-				txbdp->length, DMA_TO_DEVICE);
+				 txbdp->length, DMA_TO_DEVICE);
 		txbdp->lstatus = 0;
 		for (j = 0; j < skb_shinfo(tx_queue->tx_skbuff[i])->nr_frags;
-				j++) {
+		     j++) {
 			txbdp++;
 			dma_unmap_page(&priv->ofdev->dev, txbdp->bufPtr,
-					txbdp->length, DMA_TO_DEVICE);
+				       txbdp->length, DMA_TO_DEVICE);
 		}
 		txbdp++;
 		dev_kfree_skb_any(tx_queue->tx_skbuff[i]);
@@ -1705,8 +1714,8 @@ static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue)
 	for (i = 0; i < rx_queue->rx_ring_size; i++) {
 		if (rx_queue->rx_skbuff[i]) {
 			dma_unmap_single(&priv->ofdev->dev,
-					rxbdp->bufPtr, priv->rx_buffer_size,
-					DMA_FROM_DEVICE);
+					 rxbdp->bufPtr, priv->rx_buffer_size,
+					 DMA_FROM_DEVICE);
 			dev_kfree_skb_any(rx_queue->rx_skbuff[i]);
 			rx_queue->rx_skbuff[i] = NULL;
 		}
@@ -1718,7 +1727,8 @@ static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue)
 }
 
 /* If there are any tx skbs or rx skbs still around, free them.
- * Then free tx_skbuff and rx_skbuff */
+ * Then free tx_skbuff and rx_skbuff
+ */
 static void free_skb_resources(struct gfar_private *priv)
 {
 	struct gfar_priv_tx_q *tx_queue = NULL;
@@ -1728,24 +1738,25 @@ static void free_skb_resources(struct gfar_private *priv)
 	/* Go through all the buffer descriptors and free their data buffers */
 	for (i = 0; i < priv->num_tx_queues; i++) {
 		struct netdev_queue *txq;
+
 		tx_queue = priv->tx_queue[i];
 		txq = netdev_get_tx_queue(tx_queue->dev, tx_queue->qindex);
-		if(tx_queue->tx_skbuff)
+		if (tx_queue->tx_skbuff)
 			free_skb_tx_queue(tx_queue);
 		netdev_tx_reset_queue(txq);
 	}
 
 	for (i = 0; i < priv->num_rx_queues; i++) {
 		rx_queue = priv->rx_queue[i];
-		if(rx_queue->rx_skbuff)
+		if (rx_queue->rx_skbuff)
 			free_skb_rx_queue(rx_queue);
 	}
 
 	dma_free_coherent(&priv->ofdev->dev,
-			sizeof(struct txbd8) * priv->total_tx_ring_size +
-			sizeof(struct rxbd8) * priv->total_rx_ring_size,
-			priv->tx_queue[0]->tx_bd_base,
-			priv->tx_queue[0]->tx_bd_dma_base);
+			  sizeof(struct txbd8) * priv->total_tx_ring_size +
+			  sizeof(struct rxbd8) * priv->total_rx_ring_size,
+			  priv->tx_queue[0]->tx_bd_base,
+			  priv->tx_queue[0]->tx_bd_dma_base);
 	skb_queue_purge(&priv->rx_recycle);
 }
 
@@ -1784,7 +1795,7 @@ void gfar_start(struct net_device *dev)
 }
 
 void gfar_configure_coalescing(struct gfar_private *priv,
-	unsigned long tx_mask, unsigned long rx_mask)
+			       unsigned long tx_mask, unsigned long rx_mask)
 {
 	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	u32 __iomem *baddr;
@@ -1794,11 +1805,11 @@ void gfar_configure_coalescing(struct gfar_private *priv,
 	 * multiple queues, there's only single reg to program
 	 */
 	gfar_write(&regs->txic, 0);
-	if(likely(priv->tx_queue[0]->txcoalescing))
+	if (likely(priv->tx_queue[0]->txcoalescing))
 		gfar_write(&regs->txic, priv->tx_queue[0]->txic);
 
 	gfar_write(&regs->rxic, 0);
-	if(unlikely(priv->rx_queue[0]->rxcoalescing))
+	if (unlikely(priv->rx_queue[0]->rxcoalescing))
 		gfar_write(&regs->rxic, priv->rx_queue[0]->rxic);
 
 	if (priv->mode == MQ_MG_MODE) {
@@ -1827,12 +1838,14 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
 	int err;
 
 	/* If the device has multiple interrupts, register for
-	 * them.  Otherwise, only register for the one */
+	 * them.  Otherwise, only register for the one
+	 */
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
 		/* Install our interrupt handlers for Error,
-		 * Transmit, and Receive */
-		if ((err = request_irq(grp->interruptError, gfar_error, 0,
-				grp->int_name_er,grp)) < 0) {
+		 * Transmit, and Receive
+		 */
+		if ((err = request_irq(grp->interruptError, gfar_error,
+				       0, grp->int_name_er, grp)) < 0) {
 			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
 				  grp->interruptError);
 
@@ -1840,21 +1853,21 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
 		}
 
 		if ((err = request_irq(grp->interruptTransmit, gfar_transmit,
-				0, grp->int_name_tx, grp)) < 0) {
+				       0, grp->int_name_tx, grp)) < 0) {
 			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
 				  grp->interruptTransmit);
 			goto tx_irq_fail;
 		}
 
-		if ((err = request_irq(grp->interruptReceive, gfar_receive, 0,
-				grp->int_name_rx, grp)) < 0) {
+		if ((err = request_irq(grp->interruptReceive, gfar_receive,
+				       0, grp->int_name_rx, grp)) < 0) {
 			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
 				  grp->interruptReceive);
 			goto rx_irq_fail;
 		}
 	} else {
-		if ((err = request_irq(grp->interruptTransmit, gfar_interrupt, 0,
-				grp->int_name_tx, grp)) < 0) {
+		if ((err = request_irq(grp->interruptTransmit, gfar_interrupt,
+				       0, grp->int_name_tx, grp)) < 0) {
 			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
 				  grp->interruptTransmit);
 			goto err_irq_fail;
@@ -1914,8 +1927,9 @@ irq_fail:
 	return err;
 }
 
-/* Called when something needs to use the ethernet device */
-/* Returns 0 for success. */
+/* Called when something needs to use the ethernet device
+ * Returns 0 for success.
+ */
 static int gfar_enet_open(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
@@ -1960,18 +1974,17 @@ static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb)
 }
 
 static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb,
-		int fcb_length)
+				    int fcb_length)
 {
-	u8 flags = 0;
-
 	/* If we're here, it's a IP packet with a TCP or UDP
 	 * payload.  We set it to checksum, using a pseudo-header
 	 * we provide
 	 */
-	flags = TXFCB_DEFAULT;
+	u8 flags = TXFCB_DEFAULT;
 
-	/* Tell the controller what the protocol is */
-	/* And provide the already calculated phcs */
+	/* Tell the controller what the protocol is
+	 * And provide the already calculated phcs
+	 */
 	if (ip_hdr(skb)->protocol == IPPROTO_UDP) {
 		flags |= TXFCB_UDP;
 		fcb->phcs = udp_hdr(skb)->check;
@@ -1981,7 +1994,8 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb,
 	/* l3os is the distance between the start of the
 	 * frame (skb->data) and the start of the IP hdr.
 	 * l4os is the distance between the start of the
-	 * l3 hdr and the l4 hdr */
+	 * l3 hdr and the l4 hdr
+	 */
 	fcb->l3os = (u16)(skb_network_offset(skb) - fcb_length);
 	fcb->l4os = skb_network_header_len(skb);
 
@@ -1995,7 +2009,7 @@ void inline gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
 }
 
 static inline struct txbd8 *skip_txbd(struct txbd8 *bdp, int stride,
-			       struct txbd8 *base, int ring_size)
+				      struct txbd8 *base, int ring_size)
 {
 	struct txbd8 *new_bd = bdp + stride;
 
@@ -2003,13 +2017,14 @@ static inline struct txbd8 *skip_txbd(struct txbd8 *bdp, int stride,
 }
 
 static inline struct txbd8 *next_txbd(struct txbd8 *bdp, struct txbd8 *base,
-		int ring_size)
+				      int ring_size)
 {
 	return skip_txbd(bdp, 1, base, ring_size);
 }
 
-/* This is called by the kernel when a frame is ready for transmission. */
-/* It is pointed to by the dev->hard_start_xmit function pointer */
+/* This is called by the kernel when a frame is ready for transmission.
+ * It is pointed to by the dev->hard_start_xmit function pointer
+ */
 static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
@@ -2024,13 +2039,12 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	unsigned long flags;
 	unsigned int nr_frags, nr_txbds, length, fcb_length = GMAC_FCB_LEN;
 
-	/*
-	 * TOE=1 frames larger than 2500 bytes may see excess delays
+	/* 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)) {
+		     skb->ip_summed == CHECKSUM_PARTIAL &&
+		     skb->len > 2500)) {
 		int ret;
 
 		ret = skb_checksum_help(skb);
@@ -2046,16 +2060,16 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	/* check if time stamp should be generated */
 	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
-			priv->hwts_tx_en)) {
+		     priv->hwts_tx_en)) {
 		do_tstamp = 1;
 		fcb_length = GMAC_FCB_LEN + GMAC_TXPAL_LEN;
 	}
 
 	/* make space for additional header when fcb is needed */
 	if (((skb->ip_summed == CHECKSUM_PARTIAL) ||
-			vlan_tx_tag_present(skb) ||
-			unlikely(do_tstamp)) &&
-			(skb_headroom(skb) < fcb_length)) {
+	     vlan_tx_tag_present(skb) ||
+	     unlikely(do_tstamp)) &&
+	    (skb_headroom(skb) < fcb_length)) {
 		struct sk_buff *skb_new;
 
 		skb_new = skb_realloc_headroom(skb, fcb_length);
@@ -2099,12 +2113,12 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* Time stamp insertion requires one additional TxBD */
 	if (unlikely(do_tstamp))
 		txbdp_tstamp = txbdp = next_txbd(txbdp, base,
-				tx_queue->tx_ring_size);
+						 tx_queue->tx_ring_size);
 
 	if (nr_frags == 0) {
 		if (unlikely(do_tstamp))
 			txbdp_tstamp->lstatus |= BD_LFLAG(TXBD_LAST |
-					TXBD_INTERRUPT);
+							  TXBD_INTERRUPT);
 		else
 			lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
 	} else {
@@ -2116,7 +2130,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 			length = skb_shinfo(skb)->frags[i].size;
 
 			lstatus = txbdp->lstatus | length |
-				BD_LFLAG(TXBD_READY);
+				  BD_LFLAG(TXBD_READY);
 
 			/* Handle the last BD specially */
 			if (i == nr_frags - 1)
@@ -2146,8 +2160,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (CHECKSUM_PARTIAL == skb->ip_summed) {
 		fcb = gfar_add_fcb(skb);
 		/* as specified by errata */
-		if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_12)
-			     && ((unsigned long)fcb % 0x20) > 0x18)) {
+		if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_12) &&
+			     ((unsigned long)fcb % 0x20) > 0x18)) {
 			__skb_pull(skb, GMAC_FCB_LEN);
 			skb_checksum_help(skb);
 		} else {
@@ -2175,10 +2189,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 
 	txbdp_start->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data,
-			skb_headlen(skb), DMA_TO_DEVICE);
+					     skb_headlen(skb), DMA_TO_DEVICE);
 
-	/*
-	 * If time stamping is requested one additional TxBD must be set up. The
+	/* If time stamping is requested one additional TxBD must be set up. The
 	 * first TxBD points to the FCB and must have a data length of
 	 * GMAC_FCB_LEN. The second TxBD points to the actual frame data with
 	 * the full frame length.
@@ -2186,7 +2199,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (unlikely(do_tstamp)) {
 		txbdp_tstamp->bufPtr = txbdp_start->bufPtr + fcb_length;
 		txbdp_tstamp->lstatus |= BD_LFLAG(TXBD_READY) |
-				(skb_headlen(skb) - fcb_length);
+					 (skb_headlen(skb) - fcb_length);
 		lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN;
 	} else {
 		lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
@@ -2194,8 +2207,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	netdev_tx_sent_queue(txq, skb->len);
 
-	/*
-	 * We can work in parallel with gfar_clean_tx_ring(), except
+	/* We can work in parallel with gfar_clean_tx_ring(), except
 	 * when modifying num_txbdfree. Note that we didn't grab the lock
 	 * when we were reading the num_txbdfree and checking for available
 	 * space, that's because outside of this function it can only grow,
@@ -2208,8 +2220,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	 */
 	spin_lock_irqsave(&tx_queue->txlock, flags);
 
-	/*
-	 * The powerpc-specific eieio() is used, as wmb() has too strong
+	/* The powerpc-specific eieio() is used, as wmb() has too strong
 	 * semantics (it requires synchronization between cacheable and
 	 * uncacheable mappings, which eieio doesn't provide and which we
 	 * don't need), thus requiring a more expensive sync instruction.  At
@@ -2225,9 +2236,10 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	tx_queue->tx_skbuff[tx_queue->skb_curtx] = skb;
 
 	/* Update the current skb pointer to the next entry we will use
-	 * (wrapping if necessary) */
+	 * (wrapping if necessary)
+	 */
 	tx_queue->skb_curtx = (tx_queue->skb_curtx + 1) &
-		TX_RING_MOD_MASK(tx_queue->tx_ring_size);
+			      TX_RING_MOD_MASK(tx_queue->tx_ring_size);
 
 	tx_queue->cur_tx = next_txbd(txbdp, base, tx_queue->tx_ring_size);
 
@@ -2235,7 +2247,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	tx_queue->num_txbdfree -= (nr_txbds);
 
 	/* If the next BD still needs to be cleaned up, then the bds
-	   are full.  We need to tell the kernel to stop sending us stuff. */
+	 * are full.  We need to tell the kernel to stop sending us stuff.
+	 */
 	if (!tx_queue->num_txbdfree) {
 		netif_tx_stop_queue(txq);
 
@@ -2360,12 +2373,12 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 
 	frame_size += priv->padding;
 
-	tempsize =
-	    (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) +
-	    INCREMENTAL_BUFFER_SIZE;
+	tempsize = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) +
+		   INCREMENTAL_BUFFER_SIZE;
 
 	/* Only stop and start the controller if it isn't already
-	 * stopped, and we changed something */
+	 * stopped, and we changed something
+	 */
 	if ((oldsize != tempsize) && (dev->flags & IFF_UP))
 		stop_gfar(dev);
 
@@ -2378,11 +2391,12 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 
 	/* If the mtu is larger than the max size for standard
 	 * ethernet frames (ie, a jumbo frame), then set maccfg2
-	 * to allow huge frames, and to check the length */
+	 * to allow huge frames, and to check the length
+	 */
 	tempval = gfar_read(&regs->maccfg2);
 
 	if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
-			gfar_has_errata(priv, GFAR_ERRATA_74))
+	    gfar_has_errata(priv, GFAR_ERRATA_74))
 		tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
 	else
 		tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
@@ -2403,7 +2417,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 static void gfar_reset_task(struct work_struct *work)
 {
 	struct gfar_private *priv = container_of(work, struct gfar_private,
-			reset_task);
+						 reset_task);
 	struct net_device *dev = priv->ndev;
 
 	if (dev->flags & IFF_UP) {
@@ -2430,7 +2444,7 @@ static void gfar_align_skb(struct sk_buff *skb)
 	 * as many bytes as needed to align the data properly
 	 */
 	skb_reserve(skb, RXBUF_ALIGNMENT -
-		(((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1)));
+		    (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1)));
 }
 
 /* Interrupt Handler for Transmit complete */
@@ -2464,8 +2478,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 
 		frags = skb_shinfo(skb)->nr_frags;
 
-		/*
-		 * When time stamping, one additional TxBD must be freed.
+		/* When time stamping, one additional TxBD must be freed.
 		 * Also, we need to dma_unmap_single() the TxPAL.
 		 */
 		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))
@@ -2479,7 +2492,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 
 		/* Only clean completed frames */
 		if ((lstatus & BD_LFLAG(TXBD_READY)) &&
-				(lstatus & BD_LENGTH_MASK))
+		    (lstatus & BD_LENGTH_MASK))
 			break;
 
 		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
@@ -2489,11 +2502,12 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 			buflen = bdp->length;
 
 		dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr,
-				buflen, DMA_TO_DEVICE);
+				 buflen, DMA_TO_DEVICE);
 
 		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
 			struct skb_shared_hwtstamps shhwtstamps;
 			u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7);
+
 			memset(&shhwtstamps, 0, sizeof(shhwtstamps));
 			shhwtstamps.hwtstamp = ns_to_ktime(*ns);
 			skb_pull(skb, GMAC_FCB_LEN + GMAC_TXPAL_LEN);
@@ -2506,23 +2520,20 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 		bdp = next_txbd(bdp, base, tx_ring_size);
 
 		for (i = 0; i < frags; i++) {
-			dma_unmap_page(&priv->ofdev->dev,
-					bdp->bufPtr,
-					bdp->length,
-					DMA_TO_DEVICE);
+			dma_unmap_page(&priv->ofdev->dev, bdp->bufPtr,
+				       bdp->length, DMA_TO_DEVICE);
 			bdp->lstatus &= BD_LFLAG(TXBD_WRAP);
 			bdp = next_txbd(bdp, base, tx_ring_size);
 		}
 
 		bytes_sent += skb->len;
 
-		/*
-		 * If there's room in the queue (limit it to rx_buffer_size)
+		/* If there's room in the queue (limit it to rx_buffer_size)
 		 * we add this skb back into the pool, if it's the right size
 		 */
 		if (skb_queue_len(&priv->rx_recycle) < rx_queue->rx_ring_size &&
-				skb_recycle_check(skb, priv->rx_buffer_size +
-					RXBUF_ALIGNMENT)) {
+		    skb_recycle_check(skb, priv->rx_buffer_size +
+				      RXBUF_ALIGNMENT)) {
 			gfar_align_skb(skb);
 			skb_queue_head(&priv->rx_recycle, skb);
 		} else
@@ -2531,7 +2542,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 		tx_queue->tx_skbuff[skb_dirtytx] = NULL;
 
 		skb_dirtytx = (skb_dirtytx + 1) &
-			TX_RING_MOD_MASK(tx_ring_size);
+			      TX_RING_MOD_MASK(tx_ring_size);
 
 		howmany++;
 		spin_lock_irqsave(&tx_queue->txlock, flags);
@@ -2561,8 +2572,7 @@ static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp)
 		gfar_write(&gfargrp->regs->imask, IMASK_RTX_DISABLED);
 		__napi_schedule(&gfargrp->napi);
 	} else {
-		/*
-		 * Clear IEVENT, so interrupts aren't called again
+		/* Clear IEVENT, so interrupts aren't called again
 		 * because of the packets that have already arrived.
 		 */
 		gfar_write(&gfargrp->regs->ievent, IEVENT_RTX_MASK);
@@ -2579,7 +2589,7 @@ static irqreturn_t gfar_transmit(int irq, void *grp_id)
 }
 
 static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
-		struct sk_buff *skb)
+			   struct sk_buff *skb)
 {
 	struct net_device *dev = rx_queue->dev;
 	struct gfar_private *priv = netdev_priv(dev);
@@ -2590,7 +2600,7 @@ static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
 	gfar_init_rxbdp(rx_queue, bdp, buf);
 }
 
-static struct sk_buff * gfar_alloc_skb(struct net_device *dev)
+static struct sk_buff *gfar_alloc_skb(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct sk_buff *skb = NULL;
@@ -2604,7 +2614,7 @@ static struct sk_buff * gfar_alloc_skb(struct net_device *dev)
 	return skb;
 }
 
-struct sk_buff * gfar_new_skb(struct net_device *dev)
+struct sk_buff *gfar_new_skb(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct sk_buff *skb = NULL;
@@ -2622,8 +2632,7 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
 	struct net_device_stats *stats = &dev->stats;
 	struct gfar_extra_stats *estats = &priv->extra_stats;
 
-	/* If the packet was truncated, none of the other errors
-	 * matter */
+	/* If the packet was truncated, none of the other errors matter */
 	if (status & RXBD_TRUNCATED) {
 		stats->rx_length_errors++;
 
@@ -2664,7 +2673,8 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
 {
 	/* If valid headers were found, and valid sums
 	 * were verified, then we tell the kernel that no
-	 * checksumming is necessary.  Otherwise, it is */
+	 * checksumming is necessary.  Otherwise, it is [FIXME]
+	 */
 	if ((fcb->flags & RXFCB_CSUM_MASK) == (RXFCB_CIP | RXFCB_CTU))
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	else
@@ -2672,8 +2682,7 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
 }
 
 
-/* gfar_process_frame() -- handle one incoming packet if skb
- * isn't NULL.  */
+/* gfar_process_frame() -- handle one incoming packet if skb isn't NULL. */
 static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
 			      int amount_pull, struct napi_struct *napi)
 {
@@ -2685,8 +2694,9 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
 	/* fcb is at the beginning if exists */
 	fcb = (struct rxfcb *)skb->data;
 
-	/* Remove the FCB from the skb */
-	/* Remove the padded bytes, if there are any */
+	/* Remove the FCB from the skb
+	 * Remove the padded bytes, if there are any
+	 */
 	if (amount_pull) {
 		skb_record_rx_queue(skb, fcb->rq);
 		skb_pull(skb, amount_pull);
@@ -2696,6 +2706,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
 	if (priv->hwts_rx_en) {
 		struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
 		u64 *ns = (u64 *) skb->data;
+
 		memset(shhwtstamps, 0, sizeof(*shhwtstamps));
 		shhwtstamps->hwtstamp = ns_to_ktime(*ns);
 	}
@@ -2709,8 +2720,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
 	/* Tell the skb what kind of packet this is */
 	skb->protocol = eth_type_trans(skb, dev);
 
-	/*
-	 * There's need to check for NETIF_F_HW_VLAN_RX here.
+	/* There's need to check for NETIF_F_HW_VLAN_RX here.
 	 * Even if vlan rx accel is disabled, on some chips
 	 * RXFCB_VLN is pseudo randomly set.
 	 */
@@ -2728,8 +2738,8 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
 }
 
 /* gfar_clean_rx_ring() -- Processes each frame in the rx ring
- *   until the budget/quota has been reached. Returns the number
- *   of frames handled
+ * until the budget/quota has been reached. Returns the number
+ * of frames handled
  */
 int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
 {
@@ -2749,6 +2759,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
 
 	while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
 		struct sk_buff *newskb;
+
 		rmb();
 
 		/* Add another skb for the future */
@@ -2757,15 +2768,15 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
 		skb = rx_queue->rx_skbuff[rx_queue->skb_currx];
 
 		dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr,
-				priv->rx_buffer_size, DMA_FROM_DEVICE);
+				 priv->rx_buffer_size, DMA_FROM_DEVICE);
 
 		if (unlikely(!(bdp->status & RXBD_ERR) &&
-				bdp->length > priv->rx_buffer_size))
+			     bdp->length > priv->rx_buffer_size))
 			bdp->status = RXBD_LARGE;
 
 		/* We drop the frame if we failed to allocate a new buffer */
 		if (unlikely(!newskb || !(bdp->status & RXBD_LAST) ||
-				 bdp->status & RXBD_ERR)) {
+			     bdp->status & RXBD_ERR)) {
 			count_errors(bdp->status, dev);
 
 			if (unlikely(!newskb))
@@ -2784,7 +2795,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
 				rx_queue->stats.rx_bytes += pkt_len;
 				skb_record_rx_queue(skb, rx_queue->qindex);
 				gfar_process_frame(dev, skb, amount_pull,
-						&rx_queue->grp->napi);
+						   &rx_queue->grp->napi);
 
 			} else {
 				netif_warn(priv, rx_err, dev, "Missing skb!\n");
@@ -2803,9 +2814,8 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
 		bdp = next_bd(bdp, base, rx_queue->rx_ring_size);
 
 		/* update to point at the next skb */
-		rx_queue->skb_currx =
-		    (rx_queue->skb_currx + 1) &
-		    RX_RING_MOD_MASK(rx_queue->rx_ring_size);
+		rx_queue->skb_currx = (rx_queue->skb_currx + 1) &
+				      RX_RING_MOD_MASK(rx_queue->rx_ring_size);
 	}
 
 	/* Update the current rxbd pointer to be the next one */
@@ -2816,8 +2826,8 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
 
 static int gfar_poll(struct napi_struct *napi, int budget)
 {
-	struct gfar_priv_grp *gfargrp = container_of(napi,
-			struct gfar_priv_grp, napi);
+	struct gfar_priv_grp *gfargrp =
+		container_of(napi, struct gfar_priv_grp, napi);
 	struct gfar_private *priv = gfargrp->priv;
 	struct gfar __iomem *regs = gfargrp->regs;
 	struct gfar_priv_tx_q *tx_queue = NULL;
@@ -2831,11 +2841,11 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 	budget_per_queue = budget/num_queues;
 
 	/* Clear IEVENT, so interrupts aren't called again
-	 * because of the packets that have already arrived */
+	 * because of the packets that have already arrived
+	 */
 	gfar_write(&regs->ievent, IEVENT_RTX_MASK);
 
 	while (num_queues && left_over_budget) {
-
 		budget_per_queue = left_over_budget/num_queues;
 		left_over_budget = 0;
 
@@ -2846,12 +2856,13 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 			tx_queue = priv->tx_queue[rx_queue->qindex];
 
 			tx_cleaned += gfar_clean_tx_ring(tx_queue);
-			rx_cleaned_per_queue = gfar_clean_rx_ring(rx_queue,
-							budget_per_queue);
+			rx_cleaned_per_queue =
+				gfar_clean_rx_ring(rx_queue, budget_per_queue);
 			rx_cleaned += rx_cleaned_per_queue;
-			if(rx_cleaned_per_queue < budget_per_queue) {
+			if (rx_cleaned_per_queue < budget_per_queue) {
 				left_over_budget = left_over_budget +
-					(budget_per_queue - rx_cleaned_per_queue);
+					(budget_per_queue -
+					 rx_cleaned_per_queue);
 				set_bit(i, &serviced_queues);
 				num_queues--;
 			}
@@ -2869,25 +2880,25 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 
 		gfar_write(&regs->imask, IMASK_DEFAULT);
 
-		/* If we are coalescing interrupts, update the timer */
-		/* Otherwise, clear it */
-		gfar_configure_coalescing(priv,
-				gfargrp->rx_bit_map, gfargrp->tx_bit_map);
+		/* If we are coalescing interrupts, update the timer
+		 * Otherwise, clear it
+		 */
+		gfar_configure_coalescing(priv, gfargrp->rx_bit_map,
+					  gfargrp->tx_bit_map);
 	}
 
 	return rx_cleaned;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling 'interrupt' - used by things like netconsole to send skbs
+/* Polling 'interrupt' - used by things like netconsole to send skbs
  * without having to re-enable interrupts. It's not called while
  * the interrupt routine is executing.
  */
 static void gfar_netpoll(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	int i = 0;
+	int i;
 
 	/* If the device has multiple interrupts, run tx/rx */
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
@@ -2896,7 +2907,7 @@ static void gfar_netpoll(struct net_device *dev)
 			disable_irq(priv->gfargrp[i].interruptReceive);
 			disable_irq(priv->gfargrp[i].interruptError);
 			gfar_interrupt(priv->gfargrp[i].interruptTransmit,
-						&priv->gfargrp[i]);
+				       &priv->gfargrp[i]);
 			enable_irq(priv->gfargrp[i].interruptError);
 			enable_irq(priv->gfargrp[i].interruptReceive);
 			enable_irq(priv->gfargrp[i].interruptTransmit);
@@ -2905,7 +2916,7 @@ static void gfar_netpoll(struct net_device *dev)
 		for (i = 0; i < priv->num_grps; i++) {
 			disable_irq(priv->gfargrp[i].interruptTransmit);
 			gfar_interrupt(priv->gfargrp[i].interruptTransmit,
-						&priv->gfargrp[i]);
+				       &priv->gfargrp[i]);
 			enable_irq(priv->gfargrp[i].interruptTransmit);
 		}
 	}
@@ -2957,7 +2968,8 @@ static void adjust_link(struct net_device *dev)
 		u32 ecntrl = gfar_read(&regs->ecntrl);
 
 		/* Now we make sure that we can be in full duplex mode.
-		 * If not, we operate in half-duplex mode. */
+		 * If not, we operate in half-duplex mode.
+		 */
 		if (phydev->duplex != priv->oldduplex) {
 			new_state = 1;
 			if (!(phydev->duplex))
@@ -2983,7 +2995,8 @@ static void adjust_link(struct net_device *dev)
 				    ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);
 
 				/* Reduced mode distinguishes
-				 * between 10 and 100 */
+				 * between 10 and 100
+				 */
 				if (phydev->speed == SPEED_100)
 					ecntrl |= ECNTRL_R100;
 				else
@@ -3022,7 +3035,8 @@ static void adjust_link(struct net_device *dev)
 /* Update the hash table based on the current list of multicast
  * addresses we subscribe to.  Also, change the promiscuity of
  * the device based on the flags (this function is called
- * whenever dev->flags is changed */
+ * whenever dev->flags is changed
+ */
 static void gfar_set_multi(struct net_device *dev)
 {
 	struct netdev_hw_addr *ha;
@@ -3084,7 +3098,8 @@ static void gfar_set_multi(struct net_device *dev)
 
 		/* If we have extended hash tables, we need to
 		 * clear the exact match registers to prepare for
-		 * setting them */
+		 * setting them
+		 */
 		if (priv->extended_hash) {
 			em_num = GFAR_EM_NUM + 1;
 			gfar_clear_exact_match(dev);
@@ -3110,13 +3125,14 @@ static void gfar_set_multi(struct net_device *dev)
 
 
 /* Clears each of the exact match registers to zero, so they
- * don't interfere with normal reception */
+ * don't interfere with normal reception
+ */
 static void gfar_clear_exact_match(struct net_device *dev)
 {
 	int idx;
 	static const u8 zero_arr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
 
-	for(idx = 1;idx < GFAR_EM_NUM + 1;idx++)
+	for (idx = 1; idx < GFAR_EM_NUM + 1; idx++)
 		gfar_set_mac_for_addr(dev, idx, zero_arr);
 }
 
@@ -3132,7 +3148,8 @@ static void gfar_clear_exact_match(struct net_device *dev)
  * hash index which gaddr register to use, and the 5 other bits
  * indicate which bit (assuming an IBM numbering scheme, which
  * for PowerPC (tm) is usually the case) in the register holds
- * the entry. */
+ * the entry.
+ */
 static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
 {
 	u32 tempval;
@@ -3164,8 +3181,9 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num,
 
 	macptr += num*2;
 
-	/* Now copy it into the mac registers backwards, cuz */
-	/* little endian is silly */
+	/* Now copy it into the mac registers backwards, cuz
+	 * little endian is silly
+	 */
 	for (idx = 0; idx < ETH_ALEN; idx++)
 		tmpbuf[ETH_ALEN - 1 - idx] = addr[idx];
 
@@ -3197,7 +3215,8 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
 
 	/* Hmm... */
 	if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
-		netdev_dbg(dev, "error interrupt (ievent=0x%08x imask=0x%08x)\n",
+		netdev_dbg(dev,
+			   "error interrupt (ievent=0x%08x imask=0x%08x)\n",
 			   events, gfar_read(&regs->imask));
 
 	/* Update the error counters */
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 8a02557..8971921 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -46,18 +46,24 @@
 #include "gianfar.h"
 
 extern void gfar_start(struct net_device *dev);
-extern int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit);
+extern int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue,
+			      int rx_work_limit);
 
 #define GFAR_MAX_COAL_USECS 0xffff
 #define GFAR_MAX_COAL_FRAMES 0xff
 static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
-		     u64 * buf);
+			    u64 *buf);
 static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
-static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-static void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
+static int gfar_gcoalesce(struct net_device *dev,
+			  struct ethtool_coalesce *cvals);
+static int gfar_scoalesce(struct net_device *dev,
+			  struct ethtool_coalesce *cvals);
+static void gfar_gringparam(struct net_device *dev,
+			    struct ethtool_ringparam *rvals);
+static int gfar_sringparam(struct net_device *dev,
+			   struct ethtool_ringparam *rvals);
+static void gfar_gdrvinfo(struct net_device *dev,
+			  struct ethtool_drvinfo *drvinfo);
 
 static const char stat_gstrings[][ETH_GSTRING_LEN] = {
 	"rx-dropped-by-kernel",
@@ -130,14 +136,15 @@ static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
 		memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
 	else
 		memcpy(buf, stat_gstrings,
-				GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+		       GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
 }
 
 /* Fill in an array of 64-bit statistics from various sources.
  * This array will be appended to the end of the ethtool_stats
  * structure, and returned to user space
  */
-static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
+			    u64 *buf)
 {
 	int i;
 	struct gfar_private *priv = netdev_priv(dev);
@@ -174,8 +181,8 @@ static int gfar_sset_count(struct net_device *dev, int sset)
 }
 
 /* Fills in the drvinfo structure with some basic info */
-static void gfar_gdrvinfo(struct net_device *dev, struct
-	      ethtool_drvinfo *drvinfo)
+static void gfar_gdrvinfo(struct net_device *dev,
+			  struct ethtool_drvinfo *drvinfo)
 {
 	strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
 	strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN);
@@ -226,7 +233,8 @@ static int gfar_reglen(struct net_device *dev)
 }
 
 /* Return a dump of the GFAR register space */
-static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
+static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+			  void *regbuf)
 {
 	int i;
 	struct gfar_private *priv = netdev_priv(dev);
@@ -239,7 +247,8 @@ static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, voi
 
 /* Convert microseconds to ethernet clock ticks, which changes
  * depending on what speed the controller is running at */
-static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs)
+static unsigned int gfar_usecs2ticks(struct gfar_private *priv,
+				     unsigned int usecs)
 {
 	unsigned int count;
 
@@ -263,7 +272,8 @@ static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int use
 }
 
 /* Convert ethernet clock ticks to microseconds */
-static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int ticks)
+static unsigned int gfar_ticks2usecs(struct gfar_private *priv,
+				     unsigned int ticks)
 {
 	unsigned int count;
 
@@ -288,7 +298,8 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
 
 /* Get the coalescing parameters, and put them in the cvals
  * structure.  */
-static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_gcoalesce(struct net_device *dev,
+			  struct ethtool_coalesce *cvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar_priv_rx_q *rx_queue = NULL;
@@ -353,7 +364,8 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
  * Both cvals->*_usecs and cvals->*_frames have to be > 0
  * in order for coalescing to be active
  */
-static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_scoalesce(struct net_device *dev,
+			  struct ethtool_coalesce *cvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	int i = 0;
@@ -364,7 +376,8 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 	/* Set up rx coalescing */
 	/* As of now, we will enable/disable coalescing for all
 	 * queues together in case of eTSEC2, this will be modified
-	 * along with the ethtool interface */
+	 * along with the ethtool interface
+	 */
 	if ((cvals->rx_coalesce_usecs == 0) ||
 	    (cvals->rx_max_coalesced_frames == 0)) {
 		for (i = 0; i < priv->num_rx_queues; i++)
@@ -433,7 +446,8 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 /* Fills in rvals with the current ring parameters.  Currently,
  * rx, rx_mini, and rx_jumbo rings are the same size, as mini and
  * jumbo are ignored by the driver */
-static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static void gfar_gringparam(struct net_device *dev,
+			    struct ethtool_ringparam *rvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar_priv_tx_q *tx_queue = NULL;
@@ -459,8 +473,10 @@ static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rv
 /* Change the current ring parameters, stopping the controller if
  * necessary so that we don't mess things up while we're in
  * motion.  We wait for the ring to be clean before reallocating
- * the rings. */
-static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+ * the rings.
+ */
+static int gfar_sringparam(struct net_device *dev,
+			   struct ethtool_ringparam *rvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	int err = 0, i = 0;
@@ -486,7 +502,8 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
 		unsigned long flags;
 
 		/* Halt TX and RX, and process the frames which
-		 * have already been received */
+		 * have already been received
+		 */
 		local_irq_save(flags);
 		lock_tx_qs(priv);
 		lock_rx_qs(priv);
@@ -499,7 +516,7 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
 
 		for (i = 0; i < priv->num_rx_queues; i++)
 			gfar_clean_rx_ring(priv->rx_queue[i],
-					priv->rx_queue[i]->rx_ring_size);
+					   priv->rx_queue[i]->rx_ring_size);
 
 		/* Now we take down the rings to rebuild them */
 		stop_gfar(dev);
@@ -509,7 +526,8 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
 	for (i = 0; i < priv->num_rx_queues; i++) {
 		priv->rx_queue[i]->rx_ring_size = rvals->rx_pending;
 		priv->tx_queue[i]->tx_ring_size = rvals->tx_pending;
-		priv->tx_queue[i]->num_txbdfree = priv->tx_queue[i]->tx_ring_size;
+		priv->tx_queue[i]->num_txbdfree =
+			priv->tx_queue[i]->tx_ring_size;
 	}
 
 	/* Rebuild the rings with the new size */
@@ -535,7 +553,8 @@ int gfar_set_features(struct net_device *dev, netdev_features_t features)
 
 	if (dev->flags & IFF_UP) {
 		/* Halt TX and RX, and process the frames which
-		 * have already been received */
+		 * have already been received
+		 */
 		local_irq_save(flags);
 		lock_tx_qs(priv);
 		lock_rx_qs(priv);
@@ -548,7 +567,7 @@ int gfar_set_features(struct net_device *dev, netdev_features_t features)
 
 		for (i = 0; i < priv->num_rx_queues; i++)
 			gfar_clean_rx_ring(priv->rx_queue[i],
-					priv->rx_queue[i]->rx_ring_size);
+					   priv->rx_queue[i]->rx_ring_size);
 
 		/* Now we take down the rings to rebuild them */
 		stop_gfar(dev);
@@ -564,12 +583,14 @@ int gfar_set_features(struct net_device *dev, netdev_features_t features)
 static uint32_t gfar_get_msglevel(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+
 	return priv->msg_enable;
 }
 
 static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+
 	priv->msg_enable = data;
 }
 
@@ -614,14 +635,14 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
 
 	if (ethflow & RXH_L2DA) {
 		fcr = RQFCR_PID_DAH |RQFCR_CMP_NOMATCH |
-			RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
+		      RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
 		priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
 		priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
 		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
 		priv->cur_filer_idx = priv->cur_filer_idx - 1;
 
 		fcr = RQFCR_PID_DAL | RQFCR_AND | RQFCR_CMP_NOMATCH |
-				RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
+		      RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
 		priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
 		priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
 		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
@@ -630,7 +651,7 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
 
 	if (ethflow & RXH_VLAN) {
 		fcr = RQFCR_PID_VID | RQFCR_CMP_NOMATCH | RQFCR_HASH |
-				RQFCR_AND | RQFCR_HASHTBL_0;
+		      RQFCR_AND | RQFCR_HASHTBL_0;
 		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
 		priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
 		priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
@@ -639,7 +660,7 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
 
 	if (ethflow & RXH_IP_SRC) {
 		fcr = RQFCR_PID_SIA | RQFCR_CMP_NOMATCH | RQFCR_HASH |
-			RQFCR_AND | RQFCR_HASHTBL_0;
+		      RQFCR_AND | RQFCR_HASHTBL_0;
 		priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
 		priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
 		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
@@ -648,7 +669,7 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
 
 	if (ethflow & (RXH_IP_DST)) {
 		fcr = RQFCR_PID_DIA | RQFCR_CMP_NOMATCH | RQFCR_HASH |
-			RQFCR_AND | RQFCR_HASHTBL_0;
+		      RQFCR_AND | RQFCR_HASHTBL_0;
 		priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
 		priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
 		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
@@ -657,7 +678,7 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
 
 	if (ethflow & RXH_L3_PROTO) {
 		fcr = RQFCR_PID_L4P | RQFCR_CMP_NOMATCH | RQFCR_HASH |
-			RQFCR_AND | RQFCR_HASHTBL_0;
+		      RQFCR_AND | RQFCR_HASHTBL_0;
 		priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
 		priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
 		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
@@ -666,7 +687,7 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
 
 	if (ethflow & RXH_L4_B_0_1) {
 		fcr = RQFCR_PID_SPT | RQFCR_CMP_NOMATCH | RQFCR_HASH |
-			RQFCR_AND | RQFCR_HASHTBL_0;
+		      RQFCR_AND | RQFCR_HASHTBL_0;
 		priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
 		priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
 		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
@@ -675,7 +696,7 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
 
 	if (ethflow & RXH_L4_B_2_3) {
 		fcr = RQFCR_PID_DPT | RQFCR_CMP_NOMATCH | RQFCR_HASH |
-			RQFCR_AND | RQFCR_HASHTBL_0;
+		      RQFCR_AND | RQFCR_HASHTBL_0;
 		priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
 		priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
 		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
@@ -683,7 +704,8 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
 	}
 }
 
-static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u64 class)
+static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow,
+				       u64 class)
 {
 	unsigned int last_rule_idx = priv->cur_filer_idx;
 	unsigned int cmp_rqfpr;
@@ -694,9 +716,9 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
 	int ret = 1;
 
 	local_rqfpr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
-		GFP_KERNEL);
+			      GFP_KERNEL);
 	local_rqfcr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
-		GFP_KERNEL);
+			      GFP_KERNEL);
 	if (!local_rqfpr || !local_rqfcr) {
 		pr_err("Out of memory\n");
 		ret = 0;
@@ -726,9 +748,9 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
 		local_rqfpr[j] = priv->ftp_rqfpr[i];
 		local_rqfcr[j] = priv->ftp_rqfcr[i];
 		j--;
-		if ((priv->ftp_rqfcr[i] == (RQFCR_PID_PARSE |
-			RQFCR_CLE |RQFCR_AND)) &&
-			(priv->ftp_rqfpr[i] == cmp_rqfpr))
+		if ((priv->ftp_rqfcr[i] ==
+		     (RQFCR_PID_PARSE | RQFCR_CLE | RQFCR_AND)) &&
+		    (priv->ftp_rqfpr[i] == cmp_rqfpr))
 			break;
 	}
 
@@ -743,12 +765,12 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
 	 */
 	for (l = i+1; l < MAX_FILER_IDX; l++) {
 		if ((priv->ftp_rqfcr[l] & RQFCR_CLE) &&
-			!(priv->ftp_rqfcr[l] & RQFCR_AND)) {
+		    !(priv->ftp_rqfcr[l] & RQFCR_AND)) {
 			priv->ftp_rqfcr[l] = RQFCR_CLE | RQFCR_CMP_EXACT |
-				RQFCR_HASHTBL_0 | RQFCR_PID_MASK;
+					     RQFCR_HASHTBL_0 | RQFCR_PID_MASK;
 			priv->ftp_rqfpr[l] = FPR_FILER_MASK;
 			gfar_write_filer(priv, l, priv->ftp_rqfcr[l],
-				priv->ftp_rqfpr[l]);
+					 priv->ftp_rqfpr[l]);
 			break;
 		}
 
@@ -773,7 +795,7 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
 		priv->ftp_rqfpr[priv->cur_filer_idx] = local_rqfpr[k];
 		priv->ftp_rqfcr[priv->cur_filer_idx] = local_rqfcr[k];
 		gfar_write_filer(priv, priv->cur_filer_idx,
-				local_rqfcr[k], local_rqfpr[k]);
+				 local_rqfcr[k], local_rqfpr[k]);
 		if (!priv->cur_filer_idx)
 			break;
 		priv->cur_filer_idx = priv->cur_filer_idx - 1;
@@ -785,7 +807,8 @@ err:
 	return ret;
 }
 
-static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd)
+static int gfar_set_hash_opts(struct gfar_private *priv,
+			      struct ethtool_rxnfc *cmd)
 {
 	/* write the filer rules here */
 	if (!gfar_ethflow_to_filer_table(priv, cmd->data, cmd->flow_type))
@@ -810,10 +833,10 @@ static int gfar_check_filer_hardware(struct gfar_private *priv)
 		i &= RCTRL_PRSDEP_MASK | RCTRL_PRSFM;
 		if (i == (RCTRL_PRSDEP_MASK | RCTRL_PRSFM)) {
 			netdev_info(priv->ndev,
-					"Receive Queue Filtering enabled\n");
+				    "Receive Queue Filtering enabled\n");
 		} else {
 			netdev_warn(priv->ndev,
-					"Receive Queue Filtering disabled\n");
+				    "Receive Queue Filtering disabled\n");
 			return -EOPNOTSUPP;
 		}
 	}
@@ -823,16 +846,17 @@ static int gfar_check_filer_hardware(struct gfar_private *priv)
 		i &= RCTRL_PRSDEP_MASK;
 		if (i == RCTRL_PRSDEP_MASK) {
 			netdev_info(priv->ndev,
-					"Receive Queue Filtering enabled\n");
+				    "Receive Queue Filtering enabled\n");
 		} else {
 			netdev_warn(priv->ndev,
-					"Receive Queue Filtering disabled\n");
+				    "Receive Queue Filtering disabled\n");
 			return -EOPNOTSUPP;
 		}
 	}
 
 	/* Sets the properties for arbitrary filer rule
-	 * to the first 4 Layer 4 Bytes */
+	 * to the first 4 Layer 4 Bytes
+	 */
 	regs->rbifx = 0xC0C1C2C3;
 	return 0;
 }
@@ -870,14 +894,14 @@ static void gfar_set_mask(u32 mask, struct filer_table *tab)
 static void gfar_set_parse_bits(u32 value, u32 mask, struct filer_table *tab)
 {
 	gfar_set_mask(mask, tab);
-	tab->fe[tab->index].ctrl = RQFCR_CMP_EXACT | RQFCR_PID_PARSE
-			| RQFCR_AND;
+	tab->fe[tab->index].ctrl = RQFCR_CMP_EXACT | RQFCR_PID_PARSE |
+				   RQFCR_AND;
 	tab->fe[tab->index].prop = value;
 	tab->index++;
 }
 
 static void gfar_set_general_attribute(u32 value, u32 mask, u32 flag,
-		struct filer_table *tab)
+				       struct filer_table *tab)
 {
 	gfar_set_mask(mask, tab);
 	tab->fe[tab->index].ctrl = RQFCR_CMP_EXACT | RQFCR_AND | flag;
@@ -885,8 +909,7 @@ static void gfar_set_general_attribute(u32 value, u32 mask, u32 flag,
 	tab->index++;
 }
 
-/*
- * For setting a tuple of value and mask of type flag
+/* For setting a tuple of value and mask of type flag
  * Example:
  * IP-Src = 10.0.0.0/255.0.0.0
  * value: 0x0A000000 mask: FF000000 flag: RQFPR_IPV4
@@ -901,7 +924,7 @@ static void gfar_set_general_attribute(u32 value, u32 mask, u32 flag,
  * Further the all masks are one-padded for better hardware efficiency.
  */
 static void gfar_set_attribute(u32 value, u32 mask, u32 flag,
-		struct filer_table *tab)
+			       struct filer_table *tab)
 {
 	switch (flag) {
 		/* 3bit */
@@ -959,7 +982,8 @@ static void gfar_set_attribute(u32 value, u32 mask, u32 flag,
 
 /* Translates value and mask for UDP, TCP or SCTP */
 static void gfar_set_basic_ip(struct ethtool_tcpip4_spec *value,
-		struct ethtool_tcpip4_spec *mask, struct filer_table *tab)
+			      struct ethtool_tcpip4_spec *mask,
+			      struct filer_table *tab)
 {
 	gfar_set_attribute(value->ip4src, mask->ip4src, RQFCR_PID_SIA, tab);
 	gfar_set_attribute(value->ip4dst, mask->ip4dst, RQFCR_PID_DIA, tab);
@@ -970,97 +994,92 @@ static void gfar_set_basic_ip(struct ethtool_tcpip4_spec *value,
 
 /* Translates value and mask for RAW-IP4 */
 static void gfar_set_user_ip(struct ethtool_usrip4_spec *value,
-		struct ethtool_usrip4_spec *mask, struct filer_table *tab)
+			     struct ethtool_usrip4_spec *mask,
+			     struct filer_table *tab)
 {
 	gfar_set_attribute(value->ip4src, mask->ip4src, RQFCR_PID_SIA, tab);
 	gfar_set_attribute(value->ip4dst, mask->ip4dst, RQFCR_PID_DIA, tab);
 	gfar_set_attribute(value->tos, mask->tos, RQFCR_PID_TOS, tab);
 	gfar_set_attribute(value->proto, mask->proto, RQFCR_PID_L4P, tab);
 	gfar_set_attribute(value->l4_4_bytes, mask->l4_4_bytes, RQFCR_PID_ARB,
-			tab);
+			   tab);
 
 }
 
 /* Translates value and mask for ETHER spec */
 static void gfar_set_ether(struct ethhdr *value, struct ethhdr *mask,
-		struct filer_table *tab)
+			   struct filer_table *tab)
 {
 	u32 upper_temp_mask = 0;
 	u32 lower_temp_mask = 0;
+
 	/* Source address */
 	if (!is_broadcast_ether_addr(mask->h_source)) {
-
 		if (is_zero_ether_addr(mask->h_source)) {
 			upper_temp_mask = 0xFFFFFFFF;
 			lower_temp_mask = 0xFFFFFFFF;
 		} else {
-			upper_temp_mask = mask->h_source[0] << 16
-					| mask->h_source[1] << 8
-					| mask->h_source[2];
-			lower_temp_mask = mask->h_source[3] << 16
-					| mask->h_source[4] << 8
-					| mask->h_source[5];
+			upper_temp_mask = mask->h_source[0] << 16 |
+					  mask->h_source[1] << 8  |
+					  mask->h_source[2];
+			lower_temp_mask = mask->h_source[3] << 16 |
+					  mask->h_source[4] << 8  |
+					  mask->h_source[5];
 		}
 		/* Upper 24bit */
-		gfar_set_attribute(
-				value->h_source[0] << 16 | value->h_source[1]
-						<< 8 | value->h_source[2],
-				upper_temp_mask, RQFCR_PID_SAH, tab);
+		gfar_set_attribute(value->h_source[0] << 16 |
+				   value->h_source[1] << 8  |
+				   value->h_source[2],
+				   upper_temp_mask, RQFCR_PID_SAH, tab);
 		/* And the same for the lower part */
-		gfar_set_attribute(
-				value->h_source[3] << 16 | value->h_source[4]
-						<< 8 | value->h_source[5],
-				lower_temp_mask, RQFCR_PID_SAL, tab);
+		gfar_set_attribute(value->h_source[3] << 16 |
+				   value->h_source[4] << 8  |
+				   value->h_source[5],
+				   lower_temp_mask, RQFCR_PID_SAL, tab);
 	}
 	/* Destination address */
 	if (!is_broadcast_ether_addr(mask->h_dest)) {
-
 		/* Special for destination is limited broadcast */
-		if ((is_broadcast_ether_addr(value->h_dest)
-				&& is_zero_ether_addr(mask->h_dest))) {
+		if ((is_broadcast_ether_addr(value->h_dest) &&
+		    is_zero_ether_addr(mask->h_dest))) {
 			gfar_set_parse_bits(RQFPR_EBC, RQFPR_EBC, tab);
 		} else {
-
 			if (is_zero_ether_addr(mask->h_dest)) {
 				upper_temp_mask = 0xFFFFFFFF;
 				lower_temp_mask = 0xFFFFFFFF;
 			} else {
-				upper_temp_mask = mask->h_dest[0] << 16
-						| mask->h_dest[1] << 8
-						| mask->h_dest[2];
-				lower_temp_mask = mask->h_dest[3] << 16
-						| mask->h_dest[4] << 8
-						| mask->h_dest[5];
+				upper_temp_mask = mask->h_dest[0] << 16 |
+						  mask->h_dest[1] << 8  |
+						  mask->h_dest[2];
+				lower_temp_mask = mask->h_dest[3] << 16 |
+						  mask->h_dest[4] << 8  |
+						  mask->h_dest[5];
 			}
 
 			/* Upper 24bit */
-			gfar_set_attribute(
-					value->h_dest[0] << 16
-							| value->h_dest[1] << 8
-							| value->h_dest[2],
-					upper_temp_mask, RQFCR_PID_DAH, tab);
+			gfar_set_attribute(value->h_dest[0] << 16 |
+					   value->h_dest[1] << 8  |
+					   value->h_dest[2],
+					   upper_temp_mask, RQFCR_PID_DAH, tab);
 			/* And the same for the lower part */
-			gfar_set_attribute(
-					value->h_dest[3] << 16
-							| value->h_dest[4] << 8
-							| value->h_dest[5],
-					lower_temp_mask, RQFCR_PID_DAL, tab);
+			gfar_set_attribute(value->h_dest[3] << 16 |
+					   value->h_dest[4] << 8  |
+					   value->h_dest[5],
+					   lower_temp_mask, RQFCR_PID_DAL, tab);
 		}
 	}
 
 	gfar_set_attribute(value->h_proto, mask->h_proto, RQFCR_PID_ETY, tab);
-
 }
 
 /* Convert a rule to binary filter format of gianfar */
 static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule,
-		struct filer_table *tab)
+				 struct filer_table *tab)
 {
 	u32 vlan = 0, vlan_mask = 0;
 	u32 id = 0, id_mask = 0;
 	u32 cfi = 0, cfi_mask = 0;
 	u32 prio = 0, prio_mask = 0;
-
 	u32 old_index = tab->index;
 
 	/* Check if vlan is wanted */
@@ -1076,13 +1095,16 @@ static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule,
 		id_mask = rule->m_ext.vlan_tci & VLAN_VID_MASK;
 		cfi = rule->h_ext.vlan_tci & VLAN_CFI_MASK;
 		cfi_mask = rule->m_ext.vlan_tci & VLAN_CFI_MASK;
-		prio = (rule->h_ext.vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
-		prio_mask = (rule->m_ext.vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
+		prio = (rule->h_ext.vlan_tci & VLAN_PRIO_MASK) >>
+		       VLAN_PRIO_SHIFT;
+		prio_mask = (rule->m_ext.vlan_tci & VLAN_PRIO_MASK) >>
+			    VLAN_PRIO_SHIFT;
 
 		if (cfi == VLAN_TAG_PRESENT && cfi_mask == VLAN_TAG_PRESENT) {
 			vlan |= RQFPR_CFI;
 			vlan_mask |= RQFPR_CFI;
-		} else if (cfi != VLAN_TAG_PRESENT && cfi_mask == VLAN_TAG_PRESENT) {
+		} else if (cfi != VLAN_TAG_PRESENT &&
+			   cfi_mask == VLAN_TAG_PRESENT) {
 			vlan_mask |= RQFPR_CFI;
 		}
 	}
@@ -1090,34 +1112,36 @@ static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule,
 	switch (rule->flow_type & ~FLOW_EXT) {
 	case TCP_V4_FLOW:
 		gfar_set_parse_bits(RQFPR_IPV4 | RQFPR_TCP | vlan,
-				RQFPR_IPV4 | RQFPR_TCP | vlan_mask, tab);
+				    RQFPR_IPV4 | RQFPR_TCP | vlan_mask, tab);
 		gfar_set_basic_ip(&rule->h_u.tcp_ip4_spec,
-				&rule->m_u.tcp_ip4_spec, tab);
+				  &rule->m_u.tcp_ip4_spec, tab);
 		break;
 	case UDP_V4_FLOW:
 		gfar_set_parse_bits(RQFPR_IPV4 | RQFPR_UDP | vlan,
-				RQFPR_IPV4 | RQFPR_UDP | vlan_mask, tab);
+				    RQFPR_IPV4 | RQFPR_UDP | vlan_mask, tab);
 		gfar_set_basic_ip(&rule->h_u.udp_ip4_spec,
-				&rule->m_u.udp_ip4_spec, tab);
+				  &rule->m_u.udp_ip4_spec, tab);
 		break;
 	case SCTP_V4_FLOW:
 		gfar_set_parse_bits(RQFPR_IPV4 | vlan, RQFPR_IPV4 | vlan_mask,
-				tab);
+				    tab);
 		gfar_set_attribute(132, 0, RQFCR_PID_L4P, tab);
-		gfar_set_basic_ip((struct ethtool_tcpip4_spec *) &rule->h_u,
-				(struct ethtool_tcpip4_spec *) &rule->m_u, tab);
+		gfar_set_basic_ip((struct ethtool_tcpip4_spec *)&rule->h_u,
+				  (struct ethtool_tcpip4_spec *)&rule->m_u,
+				  tab);
 		break;
 	case IP_USER_FLOW:
 		gfar_set_parse_bits(RQFPR_IPV4 | vlan, RQFPR_IPV4 | vlan_mask,
-				tab);
+				    tab);
 		gfar_set_user_ip((struct ethtool_usrip4_spec *) &rule->h_u,
-				(struct ethtool_usrip4_spec *) &rule->m_u, tab);
+				 (struct ethtool_usrip4_spec *) &rule->m_u,
+				 tab);
 		break;
 	case ETHER_FLOW:
 		if (vlan)
 			gfar_set_parse_bits(vlan, vlan_mask, tab);
 		gfar_set_ether((struct ethhdr *) &rule->h_u,
-				(struct ethhdr *) &rule->m_u, tab);
+			       (struct ethhdr *) &rule->m_u, tab);
 		break;
 	default:
 		return -1;
@@ -1152,7 +1176,9 @@ static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule,
 		tab->fe[tab->index - 1].ctrl |= RQFCR_CLE;
 	}
 
-	/* In rare cases the cache can be full while there is free space in hw */
+	/* In rare cases the cache can be full while there is
+	 * free space in hw
+	 */
 	if (tab->index > MAX_FILER_CACHE_IDX - 1)
 		return -EBUSY;
 
@@ -1161,7 +1187,7 @@ static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule,
 
 /* Copy size filer entries */
 static void gfar_copy_filer_entries(struct gfar_filer_entry dst[0],
-		struct gfar_filer_entry src[0], s32 size)
+				    struct gfar_filer_entry src[0], s32 size)
 {
 	while (size > 0) {
 		size--;
@@ -1171,10 +1197,12 @@ static void gfar_copy_filer_entries(struct gfar_filer_entry dst[0],
 }
 
 /* Delete the contents of the filer-table between start and end
- * and collapse them */
+ * and collapse them
+ */
 static int gfar_trim_filer_entries(u32 begin, u32 end, struct filer_table *tab)
 {
 	int length;
+
 	if (end > MAX_FILER_CACHE_IDX || end < begin)
 		return -EINVAL;
 
@@ -1200,14 +1228,14 @@ static int gfar_trim_filer_entries(u32 begin, u32 end, struct filer_table *tab)
 
 /* Make space on the wanted location */
 static int gfar_expand_filer_entries(u32 begin, u32 length,
-		struct filer_table *tab)
+				     struct filer_table *tab)
 {
-	if (length == 0 || length + tab->index > MAX_FILER_CACHE_IDX || begin
-			> MAX_FILER_CACHE_IDX)
+	if (length == 0 || length + tab->index > MAX_FILER_CACHE_IDX ||
+	    begin > MAX_FILER_CACHE_IDX)
 		return -EINVAL;
 
 	gfar_copy_filer_entries(&(tab->fe[begin + length]), &(tab->fe[begin]),
-			tab->index - length + 1);
+				tab->index - length + 1);
 
 	tab->index += length;
 	return 0;
@@ -1215,9 +1243,10 @@ static int gfar_expand_filer_entries(u32 begin, u32 length,
 
 static int gfar_get_next_cluster_start(int start, struct filer_table *tab)
 {
-	for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1); start++) {
-		if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE))
-				== (RQFCR_AND | RQFCR_CLE))
+	for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1);
+	     start++) {
+		if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE)) ==
+		    (RQFCR_AND | RQFCR_CLE))
 			return start;
 	}
 	return -1;
@@ -1225,16 +1254,16 @@ static int gfar_get_next_cluster_start(int start, struct filer_table *tab)
 
 static int gfar_get_next_cluster_end(int start, struct filer_table *tab)
 {
-	for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1); start++) {
-		if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE))
-				== (RQFCR_CLE))
+	for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1);
+	     start++) {
+		if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE)) ==
+		    (RQFCR_CLE))
 			return start;
 	}
 	return -1;
 }
 
-/*
- * Uses hardwares clustering option to reduce
+/* Uses hardwares clustering option to reduce
  * the number of filer table entries
  */
 static void gfar_cluster_filer(struct filer_table *tab)
@@ -1244,8 +1273,7 @@ static void gfar_cluster_filer(struct filer_table *tab)
 	while ((i = gfar_get_next_cluster_start(++i, tab)) != -1) {
 		j = i;
 		while ((j = gfar_get_next_cluster_start(++j, tab)) != -1) {
-			/*
-			 * The cluster entries self and the previous one
+			/* The cluster entries self and the previous one
 			 * (a mask) must be identical!
 			 */
 			if (tab->fe[i].ctrl != tab->fe[j].ctrl)
@@ -1260,21 +1288,21 @@ static void gfar_cluster_filer(struct filer_table *tab)
 			jend = gfar_get_next_cluster_end(j, tab);
 			if (jend == -1 || iend == -1)
 				break;
-			/*
-			 * First we make some free space, where our cluster
+
+			/* First we make some free space, where our cluster
 			 * element should be. Then we copy it there and finally
 			 * delete in from its old location.
 			 */
-
-			if (gfar_expand_filer_entries(iend, (jend - j), tab)
-					== -EINVAL)
+			if (gfar_expand_filer_entries(iend, (jend - j), tab) ==
+			    -EINVAL)
 				break;
 
 			gfar_copy_filer_entries(&(tab->fe[iend + 1]),
-					&(tab->fe[jend + 1]), jend - j);
+						&(tab->fe[jend + 1]), jend - j);
 
 			if (gfar_trim_filer_entries(jend - 1,
-					jend + (jend - j), tab) == -EINVAL)
+						    jend + (jend - j),
+						    tab) == -EINVAL)
 				return;
 
 			/* Mask out cluster bit */
@@ -1285,8 +1313,9 @@ static void gfar_cluster_filer(struct filer_table *tab)
 
 /* Swaps the masked bits of a1<>a2 and b1<>b2 */
 static void gfar_swap_bits(struct gfar_filer_entry *a1,
-		struct gfar_filer_entry *a2, struct gfar_filer_entry *b1,
-		struct gfar_filer_entry *b2, u32 mask)
+			   struct gfar_filer_entry *a2,
+			   struct gfar_filer_entry *b1,
+			   struct gfar_filer_entry *b2, u32 mask)
 {
 	u32 temp[4];
 	temp[0] = a1->ctrl & mask;
@@ -1305,13 +1334,12 @@ static void gfar_swap_bits(struct gfar_filer_entry *a1,
 	b2->ctrl |= temp[2];
 }
 
-/*
- * Generate a list consisting of masks values with their start and
+/* Generate a list consisting of masks values with their start and
  * end of validity and block as indicator for parts belonging
  * together (glued by ANDs) in mask_table
  */
 static u32 gfar_generate_mask_table(struct gfar_mask_entry *mask_table,
-		struct filer_table *tab)
+				    struct filer_table *tab)
 {
 	u32 i, and_index = 0, block_index = 1;
 
@@ -1327,13 +1355,13 @@ static u32 gfar_generate_mask_table(struct gfar_mask_entry *mask_table,
 			and_index++;
 		}
 		/* cluster starts and ends will be separated because they should
-		 * hold their position */
+		 * hold their position
+		 */
 		if (tab->fe[i].ctrl & RQFCR_CLE)
 			block_index++;
 		/* A not set AND indicates the end of a depended block */
 		if (!(tab->fe[i].ctrl & RQFCR_AND))
 			block_index++;
-
 	}
 
 	mask_table[and_index - 1].end = i - 1;
@@ -1341,14 +1369,13 @@ static u32 gfar_generate_mask_table(struct gfar_mask_entry *mask_table,
 	return and_index;
 }
 
-/*
- * Sorts the entries of mask_table by the values of the masks.
+/* Sorts the entries of mask_table by the values of the masks.
  * Important: The 0xFF80 flags of the first and last entry of a
  * block must hold their position (which queue, CLusterEnable, ReJEct,
  * AND)
  */
 static void gfar_sort_mask_table(struct gfar_mask_entry *mask_table,
-		struct filer_table *temp_table, u32 and_index)
+				 struct filer_table *temp_table, u32 and_index)
 {
 	/* Pointer to compare function (_asc or _desc) */
 	int (*gfar_comp)(const void *, const void *);
@@ -1359,16 +1386,16 @@ static void gfar_sort_mask_table(struct gfar_mask_entry *mask_table,
 	gfar_comp = &gfar_comp_desc;
 
 	for (i = 0; i < and_index; i++) {
-
 		if (prev != mask_table[i].block) {
 			old_first = mask_table[start].start + 1;
 			old_last = mask_table[i - 1].end;
 			sort(mask_table + start, size,
-					sizeof(struct gfar_mask_entry),
-					gfar_comp, &gfar_swap);
+			     sizeof(struct gfar_mask_entry),
+			     gfar_comp, &gfar_swap);
 
 			/* Toggle order for every block. This makes the
-			 * thing more efficient! */
+			 * thing more efficient!
+			 */
 			if (gfar_comp == gfar_comp_desc)
 				gfar_comp = &gfar_comp_asc;
 			else
@@ -1378,12 +1405,11 @@ static void gfar_sort_mask_table(struct gfar_mask_entry *mask_table,
 			new_last = mask_table[i - 1].end;
 
 			gfar_swap_bits(&temp_table->fe[new_first],
-					&temp_table->fe[old_first],
-					&temp_table->fe[new_last],
-					&temp_table->fe[old_last],
-					RQFCR_QUEUE | RQFCR_CLE |
-						RQFCR_RJE | RQFCR_AND
-					);
+				       &temp_table->fe[old_first],
+				       &temp_table->fe[new_last],
+				       &temp_table->fe[old_last],
+				       RQFCR_QUEUE | RQFCR_CLE |
+				       RQFCR_RJE | RQFCR_AND);
 
 			start = i;
 			size = 0;
@@ -1391,11 +1417,9 @@ static void gfar_sort_mask_table(struct gfar_mask_entry *mask_table,
 		size++;
 		prev = mask_table[i].block;
 	}
-
 }
 
-/*
- * Reduces the number of masks needed in the filer table to save entries
+/* Reduces the number of masks needed in the filer table to save entries
  * This is done by sorting the masks of a depended block. A depended block is
  * identified by gluing ANDs or CLE. The sorting order toggles after every
  * block. Of course entries in scope of a mask must change their location with
@@ -1410,13 +1434,14 @@ static int gfar_optimize_filer_masks(struct filer_table *tab)
 	s32 ret = 0;
 
 	/* We need a copy of the filer table because
-	 * we want to change its order */
+	 * we want to change its order
+	 */
 	temp_table = kmemdup(tab, sizeof(*temp_table), GFP_KERNEL);
 	if (temp_table == NULL)
 		return -ENOMEM;
 
 	mask_table = kcalloc(MAX_FILER_CACHE_IDX / 2 + 1,
-			sizeof(struct gfar_mask_entry), GFP_KERNEL);
+			     sizeof(struct gfar_mask_entry), GFP_KERNEL);
 
 	if (mask_table == NULL) {
 		ret = -ENOMEM;
@@ -1428,7 +1453,8 @@ static int gfar_optimize_filer_masks(struct filer_table *tab)
 	gfar_sort_mask_table(mask_table, temp_table, and_index);
 
 	/* Now we can copy the data from our duplicated filer table to
-	 * the real one in the order the mask table says */
+	 * the real one in the order the mask table says
+	 */
 	for (i = 0; i < and_index; i++) {
 		size = mask_table[i].end - mask_table[i].start + 1;
 		gfar_copy_filer_entries(&(tab->fe[j]),
@@ -1437,7 +1463,8 @@ static int gfar_optimize_filer_masks(struct filer_table *tab)
 	}
 
 	/* And finally we just have to check for duplicated masks and drop the
-	 * second ones */
+	 * second ones
+	 */
 	for (i = 0; i < tab->index && i < MAX_FILER_CACHE_IDX; i++) {
 		if (tab->fe[i].ctrl == 0x80) {
 			previous_mask = i++;
@@ -1448,7 +1475,8 @@ static int gfar_optimize_filer_masks(struct filer_table *tab)
 		if (tab->fe[i].ctrl == 0x80) {
 			if (tab->fe[i].prop == tab->fe[previous_mask].prop) {
 				/* Two identical ones found!
-				 * So drop the second one! */
+				 * So drop the second one!
+				 */
 				gfar_trim_filer_entries(i, i, tab);
 			} else
 				/* Not identical! */
@@ -1463,7 +1491,7 @@ end:	kfree(temp_table);
 
 /* Write the bit-pattern from software's buffer to hardware registers */
 static int gfar_write_filer_table(struct gfar_private *priv,
-		struct filer_table *tab)
+				  struct filer_table *tab)
 {
 	u32 i = 0;
 	if (tab->index > MAX_FILER_IDX - 1)
@@ -1473,13 +1501,15 @@ static int gfar_write_filer_table(struct gfar_private *priv,
 	lock_rx_qs(priv);
 
 	/* Fill regular entries */
-	for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].ctrl); i++)
+	for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].ctrl);
+	     i++)
 		gfar_write_filer(priv, i, tab->fe[i].ctrl, tab->fe[i].prop);
 	/* Fill the rest with fall-troughs */
 	for (; i < MAX_FILER_IDX - 1; i++)
 		gfar_write_filer(priv, i, 0x60, 0xFFFFFFFF);
 	/* Last entry must be default accept
-	 * because that's what people expect */
+	 * because that's what people expect
+	 */
 	gfar_write_filer(priv, i, 0x20, 0x0);
 
 	unlock_rx_qs(priv);
@@ -1488,21 +1518,21 @@ static int gfar_write_filer_table(struct gfar_private *priv,
 }
 
 static int gfar_check_capability(struct ethtool_rx_flow_spec *flow,
-		struct gfar_private *priv)
+				 struct gfar_private *priv)
 {
 
 	if (flow->flow_type & FLOW_EXT)	{
 		if (~flow->m_ext.data[0] || ~flow->m_ext.data[1])
 			netdev_warn(priv->ndev,
-					"User-specific data not supported!\n");
+				    "User-specific data not supported!\n");
 		if (~flow->m_ext.vlan_etype)
 			netdev_warn(priv->ndev,
-					"VLAN-etype not supported!\n");
+				    "VLAN-etype not supported!\n");
 	}
 	if (flow->flow_type == IP_USER_FLOW)
 		if (flow->h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4)
 			netdev_warn(priv->ndev,
-					"IP-Version differing from IPv4 not supported!\n");
+				    "IP-Version differing from IPv4 not supported!\n");
 
 	return 0;
 }
@@ -1520,15 +1550,18 @@ static int gfar_process_filer_changes(struct gfar_private *priv)
 		return -ENOMEM;
 
 	/* Now convert the existing filer data from flow_spec into
-	 * filer tables binary format */
+	 * filer tables binary format
+	 */
 	list_for_each_entry(j, &priv->rx_list.list, list) {
 		ret = gfar_convert_to_filer(&j->fs, tab);
 		if (ret == -EBUSY) {
-			netdev_err(priv->ndev, "Rule not added: No free space!\n");
+			netdev_err(priv->ndev,
+				   "Rule not added: No free space!\n");
 			goto end;
 		}
 		if (ret == -1) {
-			netdev_err(priv->ndev, "Rule not added: Unsupported Flow-type!\n");
+			netdev_err(priv->ndev,
+				   "Rule not added: Unsupported Flow-type!\n");
 			goto end;
 		}
 	}
@@ -1540,9 +1573,9 @@ static int gfar_process_filer_changes(struct gfar_private *priv)
 	gfar_optimize_filer_masks(tab);
 
 	pr_debug("\n\tSummary:\n"
-		"\tData on hardware: %d\n"
-		"\tCompression rate: %d%%\n",
-		tab->index, 100 - (100 * tab->index) / i);
+		 "\tData on hardware: %d\n"
+		 "\tCompression rate: %d%%\n",
+		 tab->index, 100 - (100 * tab->index) / i);
 
 	/* Write everything to hardware */
 	ret = gfar_write_filer_table(priv, tab);
@@ -1551,7 +1584,8 @@ static int gfar_process_filer_changes(struct gfar_private *priv)
 		goto end;
 	}
 
-end:	kfree(tab);
+end:
+	kfree(tab);
 	return ret;
 }
 
@@ -1569,7 +1603,7 @@ static void gfar_invert_masks(struct ethtool_rx_flow_spec *flow)
 }
 
 static int gfar_add_cls(struct gfar_private *priv,
-		struct ethtool_rx_flow_spec *flow)
+			struct ethtool_rx_flow_spec *flow)
 {
 	struct ethtool_flow_spec_container *temp, *comp;
 	int ret = 0;
@@ -1591,7 +1625,6 @@ static int gfar_add_cls(struct gfar_private *priv,
 		list_add(&temp->list, &priv->rx_list.list);
 		goto process;
 	} else {
-
 		list_for_each_entry(comp, &priv->rx_list.list, list) {
 			if (comp->fs.location > flow->location) {
 				list_add_tail(&temp->list, &comp->list);
@@ -1599,8 +1632,8 @@ static int gfar_add_cls(struct gfar_private *priv,
 			}
 			if (comp->fs.location == flow->location) {
 				netdev_err(priv->ndev,
-						"Rule not added: ID %d not free!\n",
-					flow->location);
+					   "Rule not added: ID %d not free!\n",
+					   flow->location);
 				ret = -EBUSY;
 				goto clean_mem;
 			}
@@ -1642,7 +1675,6 @@ static int gfar_del_cls(struct gfar_private *priv, u32 loc)
 	}
 
 	return ret;
-
 }
 
 static int gfar_get_cls(struct gfar_private *priv, struct ethtool_rxnfc *cmd)
@@ -1663,7 +1695,7 @@ static int gfar_get_cls(struct gfar_private *priv, struct ethtool_rxnfc *cmd)
 }
 
 static int gfar_get_cls_all(struct gfar_private *priv,
-		struct ethtool_rxnfc *cmd, u32 *rule_locs)
+			    struct ethtool_rxnfc *cmd, u32 *rule_locs)
 {
 	struct ethtool_flow_spec_container *comp;
 	u32 i = 0;
@@ -1714,7 +1746,7 @@ static int gfar_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
 }
 
 static int gfar_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
-		u32 *rule_locs)
+			u32 *rule_locs)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	int ret = 0;
@@ -1748,23 +1780,19 @@ static int gfar_get_ts_info(struct net_device *dev,
 	struct gfar_private *priv = netdev_priv(dev);
 
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)) {
-		info->so_timestamping =
-			SOF_TIMESTAMPING_RX_SOFTWARE |
-			SOF_TIMESTAMPING_SOFTWARE;
+		info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
+					SOF_TIMESTAMPING_SOFTWARE;
 		info->phc_index = -1;
 		return 0;
 	}
-	info->so_timestamping =
-		SOF_TIMESTAMPING_TX_HARDWARE |
-		SOF_TIMESTAMPING_RX_HARDWARE |
-		SOF_TIMESTAMPING_RAW_HARDWARE;
+	info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+				SOF_TIMESTAMPING_RX_HARDWARE |
+				SOF_TIMESTAMPING_RAW_HARDWARE;
 	info->phc_index = gfar_phc_index;
-	info->tx_types =
-		(1 << HWTSTAMP_TX_OFF) |
-		(1 << HWTSTAMP_TX_ON);
-	info->rx_filters =
-		(1 << HWTSTAMP_FILTER_NONE) |
-		(1 << HWTSTAMP_FILTER_ALL);
+	info->tx_types = (1 << HWTSTAMP_TX_OFF) |
+			 (1 << HWTSTAMP_TX_ON);
+	info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+			   (1 << HWTSTAMP_FILTER_ALL);
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index 9ac14f8..21c6574 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -185,7 +185,7 @@ static void mem_disp(u8 *addr, int size)
 	for (; (u32) i < (u32) addr + size4Aling; i += 4)
 		printk("%08x ", *((u32 *) (i)));
 	for (; (u32) i < (u32) addr + size; i++)
-		printk("%02x", *((u8 *) (i)));
+		printk("%02x", *((i)));
 	if (notAlign == 1)
 		printk("\r\n");
 }
diff --git a/drivers/net/ethernet/hp/hp100.c b/drivers/net/ethernet/hp/hp100.c
index d496673..3f4391b 100644
--- a/drivers/net/ethernet/hp/hp100.c
+++ b/drivers/net/ethernet/hp/hp100.c
@@ -1217,7 +1217,7 @@ static int hp100_init_rxpdl(struct net_device *dev,
 
 	ringptr->pdl = pdlptr + 1;
 	ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr + 1);
-	ringptr->skb = (void *) NULL;
+	ringptr->skb = NULL;
 
 	/*
 	 * Write address and length of first PDL Fragment (which is used for
@@ -1243,7 +1243,7 @@ static int hp100_init_txpdl(struct net_device *dev,
 
 	ringptr->pdl = pdlptr;	/* +1; */
 	ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr);	/* +1 */
-	ringptr->skb = (void *) NULL;
+	ringptr->skb = NULL;
 
 	return roundup(MAX_TX_FRAG * 2 + 2, 4);
 }
@@ -1628,7 +1628,7 @@ static void hp100_clean_txring(struct net_device *dev)
 		/* Conversion to new PCI API : NOP */
 		pci_unmap_single(lp->pci_dev, (dma_addr_t) lp->txrhead->pdl[1], lp->txrhead->pdl[2], PCI_DMA_TODEVICE);
 		dev_kfree_skb_any(lp->txrhead->skb);
-		lp->txrhead->skb = (void *) NULL;
+		lp->txrhead->skb = NULL;
 		lp->txrhead = lp->txrhead->next;
 		lp->txrcommit--;
 	}
diff --git a/drivers/net/ethernet/i825xx/lp486e.c b/drivers/net/ethernet/i825xx/lp486e.c
index 6c2952c..3735bfa 100644
--- a/drivers/net/ethernet/i825xx/lp486e.c
+++ b/drivers/net/ethernet/i825xx/lp486e.c
@@ -629,10 +629,10 @@ init_i596(struct net_device *dev) {
 
 	memcpy ((void *)lp->eth_addr, dev->dev_addr, 6);
 	lp->set_add.command = CmdIASetup;
-	i596_add_cmd(dev, (struct i596_cmd *)&lp->set_add);
+	i596_add_cmd(dev, &lp->set_add);
 
 	lp->tdr.command = CmdTDR;
-	i596_add_cmd(dev, (struct i596_cmd *)&lp->tdr);
+	i596_add_cmd(dev, &lp->tdr);
 
 	if (lp->scb.command && i596_timeout(dev, "i82596 init", 200))
 		return 1;
@@ -737,7 +737,7 @@ i596_cleanup_cmd(struct net_device *dev) {
 
 	lp = netdev_priv(dev);
 	while (lp->cmd_head) {
-		cmd = (struct i596_cmd *)lp->cmd_head;
+		cmd = lp->cmd_head;
 
 		lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
 		lp->cmd_backlog--;
@@ -1281,7 +1281,7 @@ static void set_multicast_list(struct net_device *dev) {
 			lp->i596_config[8] |= 0x01;
 		}
 
-		i596_add_cmd(dev, (struct i596_cmd *) &lp->set_conf);
+		i596_add_cmd(dev, &lp->set_conf);
 	}
 }
 
diff --git a/drivers/net/ethernet/i825xx/sun3_82586.c b/drivers/net/ethernet/i825xx/sun3_82586.c
index cae17f4..353f57f6 100644
--- a/drivers/net/ethernet/i825xx/sun3_82586.c
+++ b/drivers/net/ethernet/i825xx/sun3_82586.c
@@ -571,7 +571,7 @@ static int init586(struct net_device *dev)
 	}
 #endif
 
-	ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
+	ptr = alloc_rfa(dev,ptr); /* init receive-frame-area */
 
 	/*
 	 * alloc xmit-buffs / init xmit_cmds
@@ -584,7 +584,7 @@ static int init586(struct net_device *dev)
 		ptr = (char *) ptr + XMIT_BUFF_SIZE;
 		p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
 		ptr = (char *) ptr + sizeof(struct tbd_struct);
-		if((void *)ptr > (void *)dev->mem_end)
+		if(ptr > (void *)dev->mem_end)
 		{
 			printk("%s: not enough shared-mem for your configuration!\n",dev->name);
 			return 1;
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 79b07ec..0cafe4f 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -122,8 +122,10 @@ config IGB_DCA
 
 config IGB_PTP
 	bool "PTP Hardware Clock (PHC)"
-	default y
-	depends on IGB && PTP_1588_CLOCK
+	default n
+	depends on IGB && EXPERIMENTAL
+	select PPS
+	select PTP_1588_CLOCK
 	---help---
 	  Say Y here if you want to use PTP Hardware Clock (PHC) in the
 	  driver.  Only the basic clock operations have been implemented.
@@ -223,7 +225,9 @@ config IXGBE_DCB
 config IXGBE_PTP
 	bool "PTP Clock Support"
 	default n
-	depends on IXGBE && PTP_1588_CLOCK
+	depends on IXGBE && EXPERIMENTAL
+	select PPS
+	select PTP_1588_CLOCK
 	---help---
 	  Say Y here if you want support for 1588 Timestamping with a
 	  PHC device, using the PTP 1588 Clock support. This is
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 7483ca0..183a4a3 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -1078,18 +1078,18 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 	netdev->priv_flags |= IFF_SUPP_NOFCS;
 
 	netdev->features |= netdev->hw_features;
-	netdev->hw_features |= NETIF_F_RXCSUM;
-	netdev->hw_features |= NETIF_F_RXALL;
-	netdev->hw_features |= NETIF_F_RXFCS;
+	netdev->hw_features |= (NETIF_F_RXCSUM |
+				NETIF_F_RXALL |
+				NETIF_F_RXFCS);
 
 	if (pci_using_dac) {
 		netdev->features |= NETIF_F_HIGHDMA;
 		netdev->vlan_features |= NETIF_F_HIGHDMA;
 	}
 
-	netdev->vlan_features |= NETIF_F_TSO;
-	netdev->vlan_features |= NETIF_F_HW_CSUM;
-	netdev->vlan_features |= NETIF_F_SG;
+	netdev->vlan_features |= (NETIF_F_TSO |
+				  NETIF_F_HW_CSUM |
+				  NETIF_F_SG);
 
 	netdev->priv_flags |= IFF_UNICAST_FLT;
 
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 31d37a2..ba86b3f 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -6238,7 +6238,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 	}
 
 	if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(hw))
-		e_info("PHY reset is blocked due to SOL/IDER session.\n");
+		dev_info(&pdev->dev,
+			 "PHY reset is blocked due to SOL/IDER session.\n");
 
 	/* Set initial default active device features */
 	netdev->features = (NETIF_F_SG |
@@ -6288,7 +6289,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 		if (e1000_validate_nvm_checksum(&adapter->hw) >= 0)
 			break;
 		if (i == 2) {
-			e_err("The NVM Checksum Is Not Valid\n");
+			dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n");
 			err = -EIO;
 			goto err_eeprom;
 		}
@@ -6298,13 +6299,15 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 
 	/* copy the MAC address */
 	if (e1000e_read_mac_addr(&adapter->hw))
-		e_err("NVM Read Error while reading MAC address\n");
+		dev_err(&pdev->dev,
+			"NVM Read Error while reading MAC address\n");
 
 	memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
 	memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
 
 	if (!is_valid_ether_addr(netdev->perm_addr)) {
-		e_err("Invalid MAC Address: %pM\n", netdev->perm_addr);
+		dev_err(&pdev->dev, "Invalid MAC Address: %pM\n",
+			netdev->perm_addr);
 		err = -EIO;
 		goto err_eeprom;
 	}
diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c
index 55cc156..dfbfa7f 100644
--- a/drivers/net/ethernet/intel/e1000e/param.c
+++ b/drivers/net/ethernet/intel/e1000e/param.c
@@ -199,16 +199,19 @@ static int __devinit e1000_validate_option(unsigned int *value,
 	case enable_option:
 		switch (*value) {
 		case OPTION_ENABLED:
-			e_info("%s Enabled\n", opt->name);
+			dev_info(&adapter->pdev->dev, "%s Enabled\n",
+				 opt->name);
 			return 0;
 		case OPTION_DISABLED:
-			e_info("%s Disabled\n", opt->name);
+			dev_info(&adapter->pdev->dev, "%s Disabled\n",
+				 opt->name);
 			return 0;
 		}
 		break;
 	case range_option:
 		if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
-			e_info("%s set to %i\n", opt->name, *value);
+			dev_info(&adapter->pdev->dev, "%s set to %i\n",
+				 opt->name, *value);
 			return 0;
 		}
 		break;
@@ -220,7 +223,8 @@ static int __devinit e1000_validate_option(unsigned int *value,
 			ent = &opt->arg.l.p[i];
 			if (*value == ent->i) {
 				if (ent->str[0] != '\0')
-					e_info("%s\n", ent->str);
+					dev_info(&adapter->pdev->dev, "%s\n",
+						 ent->str);
 				return 0;
 			}
 		}
@@ -230,8 +234,8 @@ static int __devinit e1000_validate_option(unsigned int *value,
 		BUG();
 	}
 
-	e_info("Invalid %s value specified (%i) %s\n", opt->name, *value,
-	       opt->err);
+	dev_info(&adapter->pdev->dev, "Invalid %s value specified (%i) %s\n",
+		 opt->name, *value, opt->err);
 	*value = opt->def;
 	return -1;
 }
@@ -251,8 +255,10 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
 	int bd = adapter->bd_number;
 
 	if (bd >= E1000_MAX_NIC) {
-		e_notice("Warning: no configuration for board #%i\n", bd);
-		e_notice("Using defaults for all values\n");
+		dev_notice(&adapter->pdev->dev,
+			   "Warning: no configuration for board #%i\n", bd);
+		dev_notice(&adapter->pdev->dev,
+			   "Using defaults for all values\n");
 	}
 
 	{ /* Transmit Interrupt Delay */
@@ -366,27 +372,32 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
 			 * default values
 			 */
 			if (adapter->itr > 4)
-				e_info("%s set to default %d\n", opt.name,
-				       adapter->itr);
+				dev_info(&adapter->pdev->dev,
+					 "%s set to default %d\n", opt.name,
+					 adapter->itr);
 		}
 
 		adapter->itr_setting = adapter->itr;
 		switch (adapter->itr) {
 		case 0:
-			e_info("%s turned off\n", opt.name);
+			dev_info(&adapter->pdev->dev, "%s turned off\n",
+				 opt.name);
 			break;
 		case 1:
-			e_info("%s set to dynamic mode\n", opt.name);
+			dev_info(&adapter->pdev->dev,
+				 "%s set to dynamic mode\n", opt.name);
 			adapter->itr = 20000;
 			break;
 		case 3:
-			e_info("%s set to dynamic conservative mode\n",
-			       opt.name);
+			dev_info(&adapter->pdev->dev,
+				 "%s set to dynamic conservative mode\n",
+				 opt.name);
 			adapter->itr = 20000;
 			break;
 		case 4:
-			e_info("%s set to simplified (2000-8000 ints) mode\n",
-			       opt.name);
+			dev_info(&adapter->pdev->dev,
+				 "%s set to simplified (2000-8000 ints) mode\n",
+				 opt.name);
 			break;
 		default:
 			/*
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index e650839..5e84eaa 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -206,8 +206,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
 		mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
 		break;
 	case e1000_i350:
-	case e1000_i210:
-	case e1000_i211:
 		mac->rar_entry_count = E1000_RAR_ENTRIES_I350;
 		break;
 	default:
diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h
index 35d1e4f..10efcd8 100644
--- a/drivers/net/ethernet/intel/igb/e1000_regs.h
+++ b/drivers/net/ethernet/intel/igb/e1000_regs.h
@@ -117,6 +117,7 @@
 
 /* TX Rate Limit Registers */
 #define E1000_RTTDQSEL	0x3604	/* Tx Desc Plane Queue Select - WO */
+#define E1000_RTTBCNRM	0x3690	/* Tx BCN Rate-scheduler MMW */
 #define E1000_RTTBCNRC	0x36B0	/* Tx BCN Rate-Scheduler Config - WO */
 
 /* Split and Replication RX Control - RW */
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index ae6d3f3..9e572dd 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -65,19 +65,30 @@ struct igb_adapter;
 #define MAX_Q_VECTORS                      8
 
 /* Transmit and receive queues */
-#define IGB_MAX_RX_QUEUES		((adapter->vfs_allocated_count ? 2 : \
-					(hw->mac.type > e1000_82575 ? 8 : 4)))
-#define IGB_MAX_RX_QUEUES_I210             4
+#define IGB_MAX_RX_QUEUES                  8
+#define IGB_MAX_RX_QUEUES_82575            4
 #define IGB_MAX_RX_QUEUES_I211             2
-#define IGB_MAX_TX_QUEUES                  16
-#define IGB_MAX_TX_QUEUES_I210             4
-#define IGB_MAX_TX_QUEUES_I211             2
+#define IGB_MAX_TX_QUEUES                  8
 #define IGB_MAX_VF_MC_ENTRIES              30
 #define IGB_MAX_VF_FUNCTIONS               8
 #define IGB_MAX_VFTA_ENTRIES               128
 #define IGB_82576_VF_DEV_ID                0x10CA
 #define IGB_I350_VF_DEV_ID                 0x1520
 
+/* NVM version defines */
+#define IGB_MAJOR_MASK			0xF000
+#define IGB_MINOR_MASK			0x0FF0
+#define IGB_BUILD_MASK			0x000F
+#define IGB_COMB_VER_MASK		0x00FF
+#define IGB_MAJOR_SHIFT			12
+#define IGB_MINOR_SHIFT			4
+#define IGB_COMB_VER_SHFT		8
+#define IGB_NVM_VER_INVALID		0xFFFF
+#define IGB_ETRACK_SHIFT		16
+#define NVM_ETRACK_WORD			0x0042
+#define NVM_COMB_VER_OFF		0x0083
+#define NVM_COMB_VER_PTR		0x003d
+
 struct vf_data_storage {
 	unsigned char vf_mac_addresses[ETH_ALEN];
 	u16 vf_mc_hashes[IGB_MAX_VF_MC_ENTRIES];
@@ -371,6 +382,7 @@ struct igb_adapter {
 	spinlock_t tmreg_lock;
 	struct cyclecounter cc;
 	struct timecounter tc;
+	char fw_version[32];
 };
 
 #define IGB_FLAG_HAS_MSI           (1 << 0)
@@ -420,6 +432,7 @@ extern void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *);
 extern bool igb_has_link(struct igb_adapter *adapter);
 extern void igb_set_ethtool_ops(struct net_device *);
 extern void igb_power_up_link(struct igb_adapter *);
+extern void igb_set_fw_version(struct igb_adapter *);
 #ifdef CONFIG_IGB_PTP
 extern void igb_ptp_init(struct igb_adapter *adapter);
 extern void igb_ptp_remove(struct igb_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 812d4f9..a19c84c 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -710,6 +710,7 @@ static int igb_set_eeprom(struct net_device *netdev,
 	if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG)))
 		hw->nvm.ops.update(hw);
 
+	igb_set_fw_version(adapter);
 	kfree(eeprom_buff);
 	return ret_val;
 }
@@ -718,20 +719,16 @@ static void igb_get_drvinfo(struct net_device *netdev,
 			    struct ethtool_drvinfo *drvinfo)
 {
 	struct igb_adapter *adapter = netdev_priv(netdev);
-	u16 eeprom_data;
 
 	strlcpy(drvinfo->driver,  igb_driver_name, sizeof(drvinfo->driver));
 	strlcpy(drvinfo->version, igb_driver_version, sizeof(drvinfo->version));
 
-	/* EEPROM image version # is reported as firmware version # for
-	 * 82575 controllers */
-	adapter->hw.nvm.ops.read(&adapter->hw, 5, 1, &eeprom_data);
-	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
-		"%d.%d-%d",
-		(eeprom_data & 0xF000) >> 12,
-		(eeprom_data & 0x0FF0) >> 4,
-		eeprom_data & 0x000F);
-
+	/*
+	 * EEPROM image version # is reported as firmware version # for
+	 * 82575 controllers
+	 */
+	strlcpy(drvinfo->fw_version, adapter->fw_version,
+		sizeof(drvinfo->fw_version));
 	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
 		sizeof(drvinfo->bus_info));
 	drvinfo->n_stats = IGB_STATS_LEN;
@@ -2271,6 +2268,38 @@ static void igb_ethtool_complete(struct net_device *netdev)
 	pm_runtime_put(&adapter->pdev->dev);
 }
 
+#ifdef CONFIG_IGB_PTP
+static int igb_ethtool_get_ts_info(struct net_device *dev,
+				   struct ethtool_ts_info *info)
+{
+	struct igb_adapter *adapter = netdev_priv(dev);
+
+	info->so_timestamping =
+		SOF_TIMESTAMPING_TX_HARDWARE |
+		SOF_TIMESTAMPING_RX_HARDWARE |
+		SOF_TIMESTAMPING_RAW_HARDWARE;
+
+	if (adapter->ptp_clock)
+		info->phc_index = ptp_clock_index(adapter->ptp_clock);
+	else
+		info->phc_index = -1;
+
+	info->tx_types =
+		(1 << HWTSTAMP_TX_OFF) |
+		(1 << HWTSTAMP_TX_ON);
+
+	info->rx_filters =
+		(1 << HWTSTAMP_FILTER_NONE) |
+		(1 << HWTSTAMP_FILTER_ALL) |
+		(1 << HWTSTAMP_FILTER_SOME) |
+		(1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+		(1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
+
+	return 0;
+}
+
+#endif
 static const struct ethtool_ops igb_ethtool_ops = {
 	.get_settings           = igb_get_settings,
 	.set_settings           = igb_set_settings,
@@ -2299,6 +2328,9 @@ static const struct ethtool_ops igb_ethtool_ops = {
 	.set_coalesce           = igb_set_coalesce,
 	.begin			= igb_ethtool_begin,
 	.complete		= igb_ethtool_complete,
+#ifdef CONFIG_IGB_PTP
+	.get_ts_info		= igb_ethtool_get_ts_info,
+#endif
 };
 
 void igb_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index dd3bfe8..01ced68 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -59,9 +59,9 @@
 #endif
 #include "igb.h"
 
-#define MAJ 3
-#define MIN 4
-#define BUILD 7
+#define MAJ 4
+#define MIN 0
+#define BUILD 1
 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
 __stringify(BUILD) "-k"
 char igb_driver_name[] = "igb";
@@ -1048,11 +1048,6 @@ static int igb_set_interrupt_capability(struct igb_adapter *adapter)
 	if (!(adapter->flags & IGB_FLAG_QUEUE_PAIRS))
 		numvecs += adapter->num_tx_queues;
 
-	/* i210 and i211 can only have 4 MSIX vectors for rx/tx queues. */
-	if ((adapter->hw.mac.type == e1000_i210)
-		|| (adapter->hw.mac.type == e1000_i211))
-		numvecs = 4;
-
 	/* store the number of vectors reserved for queues */
 	adapter->num_q_vectors = numvecs;
 
@@ -1821,6 +1816,69 @@ static const struct net_device_ops igb_netdev_ops = {
 };
 
 /**
+ * igb_set_fw_version - Configure version string for ethtool
+ * @adapter: adapter struct
+ *
+ **/
+void igb_set_fw_version(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u16 eeprom_verh, eeprom_verl, comb_verh, comb_verl, comb_offset;
+	u16 major, build, patch, fw_version;
+	u32 etrack_id;
+
+	hw->nvm.ops.read(hw, 5, 1, &fw_version);
+	if (adapter->hw.mac.type != e1000_i211) {
+		hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verh);
+		hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verl);
+		etrack_id = (eeprom_verh << IGB_ETRACK_SHIFT) | eeprom_verl;
+
+		/* combo image version needs to be found */
+		hw->nvm.ops.read(hw, NVM_COMB_VER_PTR, 1, &comb_offset);
+		if ((comb_offset != 0x0) &&
+		    (comb_offset != IGB_NVM_VER_INVALID)) {
+			hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset
+					 + 1), 1, &comb_verh);
+			hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset),
+					 1, &comb_verl);
+
+			/* Only display Option Rom if it exists and is valid */
+			if ((comb_verh && comb_verl) &&
+			    ((comb_verh != IGB_NVM_VER_INVALID) &&
+			     (comb_verl != IGB_NVM_VER_INVALID))) {
+				major = comb_verl >> IGB_COMB_VER_SHFT;
+				build = (comb_verl << IGB_COMB_VER_SHFT) |
+					(comb_verh >> IGB_COMB_VER_SHFT);
+				patch = comb_verh & IGB_COMB_VER_MASK;
+				snprintf(adapter->fw_version,
+					 sizeof(adapter->fw_version),
+					 "%d.%d%d, 0x%08x, %d.%d.%d",
+					 (fw_version & IGB_MAJOR_MASK) >>
+					 IGB_MAJOR_SHIFT,
+					 (fw_version & IGB_MINOR_MASK) >>
+					 IGB_MINOR_SHIFT,
+					 (fw_version & IGB_BUILD_MASK),
+					 etrack_id, major, build, patch);
+				goto out;
+			}
+		}
+		snprintf(adapter->fw_version, sizeof(adapter->fw_version),
+			 "%d.%d%d, 0x%08x",
+			 (fw_version & IGB_MAJOR_MASK) >> IGB_MAJOR_SHIFT,
+			 (fw_version & IGB_MINOR_MASK) >> IGB_MINOR_SHIFT,
+			 (fw_version & IGB_BUILD_MASK), etrack_id);
+	} else {
+		snprintf(adapter->fw_version, sizeof(adapter->fw_version),
+			 "%d.%d%d",
+			 (fw_version & IGB_MAJOR_MASK) >> IGB_MAJOR_SHIFT,
+			 (fw_version & IGB_MINOR_MASK) >> IGB_MINOR_SHIFT,
+			 (fw_version & IGB_BUILD_MASK));
+	}
+out:
+	return;
+}
+
+/**
  * igb_probe - Device Initialization Routine
  * @pdev: PCI device information struct
  * @ent: entry in igb_pci_tbl
@@ -2030,6 +2088,9 @@ static int __devinit igb_probe(struct pci_dev *pdev,
 		goto err_eeprom;
 	}
 
+	/* get firmware version for ethtool -i */
+	igb_set_fw_version(adapter);
+
 	setup_timer(&adapter->watchdog_timer, igb_watchdog,
 	            (unsigned long) adapter);
 	setup_timer(&adapter->phy_info_timer, igb_update_phy_info,
@@ -2338,6 +2399,7 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
 	struct e1000_hw *hw = &adapter->hw;
 	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
+	u32 max_rss_queues;
 
 	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
 
@@ -2370,40 +2432,69 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
 		} else
 			adapter->vfs_allocated_count = max_vfs;
 		break;
-	case e1000_i210:
-	case e1000_i211:
-		adapter->vfs_allocated_count = 0;
-		break;
 	default:
 		break;
 	}
 #endif /* CONFIG_PCI_IOV */
+
+	/* Determine the maximum number of RSS queues supported. */
 	switch (hw->mac.type) {
+	case e1000_i211:
+		max_rss_queues = IGB_MAX_RX_QUEUES_I211;
+		break;
+	case e1000_82575:
 	case e1000_i210:
-		adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES_I210,
-			num_online_cpus());
+		max_rss_queues = IGB_MAX_RX_QUEUES_82575;
+		break;
+	case e1000_i350:
+		/* I350 cannot do RSS and SR-IOV at the same time */
+		if (!!adapter->vfs_allocated_count) {
+			max_rss_queues = 1;
+			break;
+		}
+		/* fall through */
+	case e1000_82576:
+		if (!!adapter->vfs_allocated_count) {
+			max_rss_queues = 2;
+			break;
+		}
+		/* fall through */
+	case e1000_82580:
+	default:
+		max_rss_queues = IGB_MAX_RX_QUEUES;
 		break;
+	}
+
+	adapter->rss_queues = min_t(u32, max_rss_queues, num_online_cpus());
+
+	/* Determine if we need to pair queues. */
+	switch (hw->mac.type) {
+	case e1000_82575:
 	case e1000_i211:
-		adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES_I211,
-			num_online_cpus());
+		/* Device supports enough interrupts without queue pairing. */
 		break;
+	case e1000_82576:
+		/*
+		 * If VFs are going to be allocated with RSS queues then we
+		 * should pair the queues in order to conserve interrupts due
+		 * to limited supply.
+		 */
+		if ((adapter->rss_queues > 1) &&
+		    (adapter->vfs_allocated_count > 6))
+			adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
+		/* fall through */
+	case e1000_82580:
+	case e1000_i350:
+	case e1000_i210:
 	default:
-		adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES,
-		num_online_cpus());
+		/*
+		 * If rss_queues > half of max_rss_queues, pair the queues in
+		 * order to conserve interrupts due to limited supply.
+		 */
+		if (adapter->rss_queues > (max_rss_queues / 2))
+			adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
 		break;
 	}
-	/* i350 cannot do RSS and SR-IOV at the same time */
-	if (hw->mac.type == e1000_i350 && adapter->vfs_allocated_count)
-		adapter->rss_queues = 1;
-
-	/*
-	 * if rss_queues > 4 or vfs are going to be allocated with rss_queues
-	 * then we should combine the queues into a queue pair in order to
-	 * conserve interrupts due to limited supply
-	 */
-	if ((adapter->rss_queues > 4) ||
-	    ((adapter->rss_queues > 1) && (adapter->vfs_allocated_count > 6)))
-		adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
 
 	/* Setup and initialize a copy of the hw vlan table array */
 	adapter->shadow_vfta = kzalloc(sizeof(u32) *
@@ -6997,6 +7088,11 @@ static void igb_set_vf_rate_limit(struct e1000_hw *hw, int vf, int tx_rate,
 	}
 
 	wr32(E1000_RTTDQSEL, vf); /* vf X uses queue X */
+	/*
+	 * Set global transmit compensation time to the MMW_SIZE in RTTBCNRM
+	 * register. MMW_SIZE=0x014 if 9728-byte jumbo is supported.
+	 */
+	wr32(E1000_RTTBCNRM, 0x14);
 	wr32(E1000_RTTBCNRC, bcnrc_val);
 }
 
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index d5ee7fa..c846ea9 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -330,7 +330,17 @@ void igb_ptp_init(struct igb_adapter *adapter)
 
 void igb_ptp_remove(struct igb_adapter *adapter)
 {
-	cancel_delayed_work_sync(&adapter->overflow_work);
+	switch (adapter->hw.mac.type) {
+	case e1000_i211:
+	case e1000_i210:
+	case e1000_i350:
+	case e1000_82580:
+	case e1000_82576:
+		cancel_delayed_work_sync(&adapter->overflow_work);
+		break;
+	default:
+		return;
+	}
 
 	if (adapter->ptp_clock) {
 		ptp_clock_unregister(adapter->ptp_clock);
diff --git a/drivers/net/ethernet/intel/ixgbe/Makefile b/drivers/net/ethernet/intel/ixgbe/Makefile
index 0bdf06b..5fd5d04c 100644
--- a/drivers/net/ethernet/intel/ixgbe/Makefile
+++ b/drivers/net/ethernet/intel/ixgbe/Makefile
@@ -34,11 +34,11 @@ obj-$(CONFIG_IXGBE) += ixgbe.o
 
 ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
               ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \
-              ixgbe_mbx.o ixgbe_x540.o ixgbe_sysfs.o ixgbe_lib.o
+              ixgbe_mbx.o ixgbe_x540.o ixgbe_lib.o
 
 ixgbe-$(CONFIG_IXGBE_DCB) +=  ixgbe_dcb.o ixgbe_dcb_82598.o \
                               ixgbe_dcb_82599.o ixgbe_dcb_nl.o
 
 ixgbe-$(CONFIG_IXGBE_PTP) += ixgbe_ptp.o
-
+ixgbe-$(CONFIG_IXGBE_HWMON) += ixgbe_sysfs.o
 ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 3ef3c52..41f9f6e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -561,6 +561,7 @@ struct ixgbe_adapter {
 	spinlock_t tmreg_lock;
 	struct cyclecounter cc;
 	struct timecounter tc;
+	int rx_hwtstamp_filter;
 	u32 base_incval;
 	u32 cycle_speed;
 #endif /* CONFIG_IXGBE_PTP */
@@ -718,6 +719,7 @@ extern void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter);
 extern void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector,
 				  struct sk_buff *skb);
 extern void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
+				  union ixgbe_adv_rx_desc *rx_desc,
 				  struct sk_buff *skb);
 extern int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
 				    struct ifreq *ifr, int cmd);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index dee64d2..e7dddfd 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -241,7 +241,9 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
 
 	/* 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) {
+	    hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
+	    hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
+	    hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
 		*speed = IXGBE_LINK_SPEED_1GB_FULL;
 		*negotiation = true;
 		goto out;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 3178f1e..bbc7da5 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -154,100 +154,60 @@ static int ixgbe_get_settings(struct net_device *netdev,
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
+	ixgbe_link_speed supported_link;
 	u32 link_speed = 0;
+	bool autoneg;
 	bool link_up;
 
-	ecmd->supported = SUPPORTED_10000baseT_Full;
-	ecmd->autoneg = AUTONEG_ENABLE;
-	ecmd->transceiver = XCVR_EXTERNAL;
-	if ((hw->phy.media_type == ixgbe_media_type_copper) ||
-	    (hw->phy.multispeed_fiber)) {
-		ecmd->supported |= (SUPPORTED_1000baseT_Full |
-		                    SUPPORTED_Autoneg);
-
-		switch (hw->mac.type) {
-		case ixgbe_mac_X540:
-			ecmd->supported |= SUPPORTED_100baseT_Full;
-			break;
-		default:
-			break;
-		}
-
-		ecmd->advertising = ADVERTISED_Autoneg;
-		if (hw->phy.autoneg_advertised) {
-			if (hw->phy.autoneg_advertised &
-			    IXGBE_LINK_SPEED_100_FULL)
-				ecmd->advertising |= ADVERTISED_100baseT_Full;
-			if (hw->phy.autoneg_advertised &
-			    IXGBE_LINK_SPEED_10GB_FULL)
-				ecmd->advertising |= ADVERTISED_10000baseT_Full;
-			if (hw->phy.autoneg_advertised &
-			    IXGBE_LINK_SPEED_1GB_FULL)
-				ecmd->advertising |= ADVERTISED_1000baseT_Full;
-		} else {
-			/*
-			 * Default advertised modes in case
-			 * phy.autoneg_advertised isn't set.
-			 */
-			ecmd->advertising |= (ADVERTISED_10000baseT_Full |
-					      ADVERTISED_1000baseT_Full);
-			if (hw->mac.type == ixgbe_mac_X540)
-				ecmd->advertising |= ADVERTISED_100baseT_Full;
-		}
-
-		if (hw->phy.media_type == ixgbe_media_type_copper) {
-			ecmd->supported |= SUPPORTED_TP;
-			ecmd->advertising |= ADVERTISED_TP;
-			ecmd->port = PORT_TP;
-		} else {
-			ecmd->supported |= SUPPORTED_FIBRE;
-			ecmd->advertising |= ADVERTISED_FIBRE;
-			ecmd->port = PORT_FIBRE;
-		}
-	} else if (hw->phy.media_type == ixgbe_media_type_backplane) {
-		/* Set as FIBRE until SERDES defined in kernel */
-		if (hw->device_id == IXGBE_DEV_ID_82598_BX) {
-			ecmd->supported = (SUPPORTED_1000baseT_Full |
-					   SUPPORTED_FIBRE);
-			ecmd->advertising = (ADVERTISED_1000baseT_Full |
-					     ADVERTISED_FIBRE);
-			ecmd->port = PORT_FIBRE;
-			ecmd->autoneg = AUTONEG_DISABLE;
-		} else if ((hw->device_id == IXGBE_DEV_ID_82599_COMBO_BACKPLANE) ||
-			   (hw->device_id == IXGBE_DEV_ID_82599_KX4_MEZZ)) {
-			ecmd->supported |= (SUPPORTED_1000baseT_Full |
-					    SUPPORTED_Autoneg |
-					    SUPPORTED_FIBRE);
-			ecmd->advertising = (ADVERTISED_10000baseT_Full |
-					     ADVERTISED_1000baseT_Full |
-					     ADVERTISED_Autoneg |
-					     ADVERTISED_FIBRE);
-			ecmd->port = PORT_FIBRE;
-		} else {
-			ecmd->supported |= (SUPPORTED_1000baseT_Full |
-					    SUPPORTED_FIBRE);
-			ecmd->advertising = (ADVERTISED_10000baseT_Full |
-					     ADVERTISED_1000baseT_Full |
-					     ADVERTISED_FIBRE);
-			ecmd->port = PORT_FIBRE;
-		}
+	hw->mac.ops.get_link_capabilities(hw, &supported_link, &autoneg);
+
+	/* set the supported link speeds */
+	if (supported_link & IXGBE_LINK_SPEED_10GB_FULL)
+		ecmd->supported |= SUPPORTED_10000baseT_Full;
+	if (supported_link & IXGBE_LINK_SPEED_1GB_FULL)
+		ecmd->supported |= SUPPORTED_1000baseT_Full;
+	if (supported_link & IXGBE_LINK_SPEED_100_FULL)
+		ecmd->supported |= SUPPORTED_100baseT_Full;
+
+	/* set the advertised speeds */
+	if (hw->phy.autoneg_advertised) {
+		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
+			ecmd->advertising |= ADVERTISED_100baseT_Full;
+		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
+			ecmd->advertising |= ADVERTISED_10000baseT_Full;
+		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
+			ecmd->advertising |= ADVERTISED_1000baseT_Full;
 	} else {
-		ecmd->supported |= SUPPORTED_FIBRE;
-		ecmd->advertising = (ADVERTISED_10000baseT_Full |
-		                     ADVERTISED_FIBRE);
-		ecmd->port = PORT_FIBRE;
-		ecmd->autoneg = AUTONEG_DISABLE;
+		/* default modes in case phy.autoneg_advertised isn't set */
+		if (supported_link & IXGBE_LINK_SPEED_10GB_FULL)
+			ecmd->advertising |= ADVERTISED_10000baseT_Full;
+		if (supported_link & IXGBE_LINK_SPEED_1GB_FULL)
+			ecmd->advertising |= ADVERTISED_1000baseT_Full;
+		if (supported_link & IXGBE_LINK_SPEED_100_FULL)
+			ecmd->advertising |= ADVERTISED_100baseT_Full;
 	}
 
-	/* Get PHY type */
+	if (autoneg) {
+		ecmd->supported |= SUPPORTED_Autoneg;
+		ecmd->advertising |= ADVERTISED_Autoneg;
+		ecmd->autoneg = AUTONEG_ENABLE;
+	} else
+		ecmd->autoneg = AUTONEG_DISABLE;
+
+	ecmd->transceiver = XCVR_EXTERNAL;
+
+	/* Determine the remaining settings based on the PHY type. */
 	switch (adapter->hw.phy.type) {
 	case ixgbe_phy_tn:
 	case ixgbe_phy_aq:
 	case ixgbe_phy_cu_unknown:
-		/* Copper 10G-BASET */
+		ecmd->supported |= SUPPORTED_TP;
+		ecmd->advertising |= ADVERTISED_TP;
 		ecmd->port = PORT_TP;
 		break;
 	case ixgbe_phy_qt:
+		ecmd->supported |= SUPPORTED_FIBRE;
+		ecmd->advertising |= ADVERTISED_FIBRE;
 		ecmd->port = PORT_FIBRE;
 		break;
 	case ixgbe_phy_nl:
@@ -257,42 +217,59 @@ static int ixgbe_get_settings(struct net_device *netdev,
 	case ixgbe_phy_sfp_avago:
 	case ixgbe_phy_sfp_intel:
 	case ixgbe_phy_sfp_unknown:
-		switch (adapter->hw.phy.sfp_type) {
 		/* SFP+ devices, further checking needed */
+		switch (adapter->hw.phy.sfp_type) {
 		case ixgbe_sfp_type_da_cu:
 		case ixgbe_sfp_type_da_cu_core0:
 		case ixgbe_sfp_type_da_cu_core1:
+			ecmd->supported |= SUPPORTED_FIBRE;
+			ecmd->advertising |= ADVERTISED_FIBRE;
 			ecmd->port = PORT_DA;
 			break;
 		case ixgbe_sfp_type_sr:
 		case ixgbe_sfp_type_lr:
 		case ixgbe_sfp_type_srlr_core0:
 		case ixgbe_sfp_type_srlr_core1:
+			ecmd->supported |= SUPPORTED_FIBRE;
+			ecmd->advertising |= ADVERTISED_FIBRE;
 			ecmd->port = PORT_FIBRE;
 			break;
 		case ixgbe_sfp_type_not_present:
+			ecmd->supported |= SUPPORTED_FIBRE;
+			ecmd->advertising |= ADVERTISED_FIBRE;
 			ecmd->port = PORT_NONE;
 			break;
 		case ixgbe_sfp_type_1g_cu_core0:
 		case ixgbe_sfp_type_1g_cu_core1:
+			ecmd->supported |= SUPPORTED_TP;
+			ecmd->advertising |= ADVERTISED_TP;
 			ecmd->port = PORT_TP;
-			ecmd->supported = SUPPORTED_TP;
-			ecmd->advertising = (ADVERTISED_1000baseT_Full |
-			                     ADVERTISED_TP);
+			break;
+		case ixgbe_sfp_type_1g_sx_core0:
+		case ixgbe_sfp_type_1g_sx_core1:
+			ecmd->supported |= SUPPORTED_FIBRE;
+			ecmd->advertising |= ADVERTISED_FIBRE;
+			ecmd->port = PORT_FIBRE;
 			break;
 		case ixgbe_sfp_type_unknown:
 		default:
+			ecmd->supported |= SUPPORTED_FIBRE;
+			ecmd->advertising |= ADVERTISED_FIBRE;
 			ecmd->port = PORT_OTHER;
 			break;
 		}
 		break;
 	case ixgbe_phy_xaui:
+		ecmd->supported |= SUPPORTED_FIBRE;
+		ecmd->advertising |= ADVERTISED_FIBRE;
 		ecmd->port = PORT_NONE;
 		break;
 	case ixgbe_phy_unknown:
 	case ixgbe_phy_generic:
 	case ixgbe_phy_sfp_unsupported:
 	default:
+		ecmd->supported |= SUPPORTED_FIBRE;
+		ecmd->advertising |= ADVERTISED_FIBRE;
 		ecmd->port = PORT_OTHER;
 		break;
 	}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 17ad6a3..21e083c 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -790,12 +790,10 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
 		total_packets += tx_buffer->gso_segs;
 
 #ifdef CONFIG_IXGBE_PTP
-		if (unlikely(tx_buffer->tx_flags &
-			     IXGBE_TX_FLAGS_TSTAMP))
-			ixgbe_ptp_tx_hwtstamp(q_vector,
-					      tx_buffer->skb);
-
+		if (unlikely(tx_buffer->tx_flags & IXGBE_TX_FLAGS_TSTAMP))
+			ixgbe_ptp_tx_hwtstamp(q_vector, tx_buffer->skb);
 #endif
+
 		/* free the skb */
 		dev_kfree_skb_any(tx_buffer->skb);
 
@@ -1148,7 +1146,7 @@ static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring,
 
 	/* alloc new page for storage */
 	if (likely(!page)) {
-		page = alloc_pages(GFP_ATOMIC | __GFP_COLD,
+		page = alloc_pages(GFP_ATOMIC | __GFP_COLD | __GFP_COMP,
 				   ixgbe_rx_pg_order(rx_ring));
 		if (unlikely(!page)) {
 			rx_ring->rx_stats.alloc_rx_page_failed++;
@@ -1399,8 +1397,7 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
 	ixgbe_rx_checksum(rx_ring, rx_desc, skb);
 
 #ifdef CONFIG_IXGBE_PTP
-	if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS))
-		ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, skb);
+	ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, rx_desc, skb);
 #endif
 
 	if ((dev->features & NETIF_F_HW_VLAN_RX) &&
@@ -6383,17 +6380,12 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_ring *tx_ring;
 
-	if (skb->len <= 0) {
-		dev_kfree_skb_any(skb);
-		return NETDEV_TX_OK;
-	}
-
 	/*
 	 * The minimum packet size for olinfo paylen is 17 so pad the skb
 	 * in order to meet this minimum size requirement.
 	 */
-	if (skb->len < 17) {
-		if (skb_padto(skb, 17))
+	if (unlikely(skb->len < 17)) {
+		if (skb_pad(skb, 17 - skb->len))
 			return NETDEV_TX_OK;
 		skb->len = 17;
 	}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index 2411770..71659ed 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -907,6 +907,8 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
 		  * 8   SFP_act_lmt_DA_CORE1 - 82599-specific
 		  * 9   SFP_1g_cu_CORE0 - 82599-specific
 		  * 10  SFP_1g_cu_CORE1 - 82599-specific
+		  * 11  SFP_1g_sx_CORE0 - 82599-specific
+		  * 12  SFP_1g_sx_CORE1 - 82599-specific
 		  */
 		if (hw->mac.type == ixgbe_mac_82598EB) {
 			if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
@@ -957,6 +959,13 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
 				else
 					hw->phy.sfp_type =
 						ixgbe_sfp_type_1g_cu_core1;
+			} else if (comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) {
+				if (hw->bus.lan_id == 0)
+					hw->phy.sfp_type =
+						ixgbe_sfp_type_1g_sx_core0;
+				else
+					hw->phy.sfp_type =
+						ixgbe_sfp_type_1g_sx_core1;
 			} else {
 				hw->phy.sfp_type = ixgbe_sfp_type_unknown;
 			}
@@ -1049,7 +1058,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
 		/* 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.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
+		      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
+		      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
 			hw->phy.type = ixgbe_phy_sfp_unsupported;
 			status = IXGBE_ERR_SFP_NOT_SUPPORTED;
 			goto out;
@@ -1064,7 +1075,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
 		hw->mac.ops.get_device_caps(hw, &enforce_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))) {
+		      (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1) ||
+		      (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0) ||
+		      (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1))) {
 			/* Make sure we're a supported PHY type */
 			if (hw->phy.type == ixgbe_phy_sfp_intel) {
 				status = 0;
@@ -1128,10 +1141,12 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
 	 * 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_1g_cu_core0 ||
+	    sfp_type == ixgbe_sfp_type_1g_sx_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_1g_cu_core1 ||
+		 sfp_type == ixgbe_sfp_type_1g_sx_core1)
 		sfp_type = ixgbe_sfp_type_srlr_core1;
 
 	/* Read offset to PHY init contents */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index ddc6a4d..daddd84 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -26,6 +26,7 @@
 *******************************************************************************/
 #include "ixgbe.h"
 #include <linux/export.h>
+#include <linux/ptp_classify.h>
 
 /*
  * The 82599 and the X540 do not have true 64bit nanosecond scale
@@ -100,6 +101,10 @@
 #define NSECS_PER_SEC 1000000000ULL
 #endif
 
+static struct sock_filter ptp_filter[] = {
+	PTP_FILTER
+};
+
 /**
  * ixgbe_ptp_read - read raw cycle counter (to be used by time counter)
  * @cc - the cyclecounter structure
@@ -307,13 +312,14 @@ void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr)
 	    !(adapter->flags2 & IXGBE_FLAG2_PTP_PPS_ENABLED))
 		return;
 
-	switch (hw->mac.type) {
-	case ixgbe_mac_X540:
-		if (eicr & IXGBE_EICR_TIMESYNC)
+	if (unlikely(eicr & IXGBE_EICR_TIMESYNC)) {
+		switch (hw->mac.type) {
+		case ixgbe_mac_X540:
 			ptp_clock_event(adapter->ptp_clock, &event);
-		break;
-	default:
-		break;
+			break;
+		default:
+			break;
+		}
 	}
 }
 
@@ -425,6 +431,68 @@ void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter)
 }
 
 /**
+ * ixgbe_ptp_match - determine if this skb matches a ptp packet
+ * @skb: pointer to the skb
+ * @hwtstamp: pointer to the hwtstamp_config to check
+ *
+ * Determine whether the skb should have been timestamped, assuming the
+ * hwtstamp was set via the hwtstamp ioctl. Returns non-zero when the packet
+ * should have a timestamp waiting in the registers, and 0 otherwise.
+ *
+ * V1 packets have to check the version type to determine whether they are
+ * correct. However, we can't directly access the data because it might be
+ * fragmented in the SKB, in paged memory. In order to work around this, we
+ * use skb_copy_bits which will properly copy the data whether it is in the
+ * paged memory fragments or not. We have to copy the IP header as well as the
+ * message type.
+ */
+static int ixgbe_ptp_match(struct sk_buff *skb, int rx_filter)
+{
+	struct iphdr iph;
+	u8 msgtype;
+	unsigned int type, offset;
+
+	if (rx_filter == HWTSTAMP_FILTER_NONE)
+		return 0;
+
+	type = sk_run_filter(skb, ptp_filter);
+
+	if (likely(rx_filter == HWTSTAMP_FILTER_PTP_V2_EVENT))
+		return type & PTP_CLASS_V2;
+
+	/* For the remaining cases actually check message type */
+	switch (type) {
+	case PTP_CLASS_V1_IPV4:
+		skb_copy_bits(skb, OFF_IHL, &iph, sizeof(iph));
+		offset = ETH_HLEN + (iph.ihl << 2) + UDP_HLEN + OFF_PTP_CONTROL;
+		break;
+	case PTP_CLASS_V1_IPV6:
+		offset = OFF_PTP6 + OFF_PTP_CONTROL;
+		break;
+	default:
+		/* other cases invalid or handled above */
+		return 0;
+	}
+
+	/* Make sure our buffer is long enough */
+	if (skb->len < offset)
+		return 0;
+
+	skb_copy_bits(skb, offset, &msgtype, sizeof(msgtype));
+
+	switch (rx_filter) {
+	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+		return (msgtype == IXGBE_RXMTRL_V1_SYNC_MSG);
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+		return (msgtype == IXGBE_RXMTRL_V1_DELAY_REQ_MSG);
+		break;
+	default:
+		return 0;
+	}
+}
+
+/**
  * ixgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp
  * @q_vector: structure containing interrupt and ring information
  * @skb: particular skb to send timestamp with
@@ -473,6 +541,7 @@ void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector,
 /**
  * ixgbe_ptp_rx_hwtstamp - utility function which checks for RX time stamp
  * @q_vector: structure containing interrupt and ring information
+ * @rx_desc: the rx descriptor
  * @skb: particular skb to send timestamp with
  *
  * if the timestamp is valid, we convert it into the timecounter ns
@@ -480,6 +549,7 @@ void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector,
  * is passed up the network stack
  */
 void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
+			   union ixgbe_adv_rx_desc *rx_desc,
 			   struct sk_buff *skb)
 {
 	struct ixgbe_adapter *adapter;
@@ -497,21 +567,33 @@ void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
 	hw = &adapter->hw;
 
 	tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
+
+	/* Check if we have a valid timestamp and make sure the skb should
+	 * have been timestamped */
+	if (likely(!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID) ||
+		   !ixgbe_ptp_match(skb, adapter->rx_hwtstamp_filter)))
+		return;
+
+	/*
+	 * Always read the registers, in order to clear a possible fault
+	 * because of stagnant RX timestamp values for a packet that never
+	 * reached the queue.
+	 */
 	regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPL);
 	regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPH) << 32;
 
 	/*
-	 * If this bit is set, then the RX registers contain the time stamp. No
-	 * other packet will be time stamped until we read these registers, so
-	 * read the registers to make them available again. Because only one
-	 * packet can be time stamped at a time, we know that the register
-	 * values must belong to this one here and therefore we don't need to
-	 * compare any of the additional attributes stored for it.
+	 * If the timestamp bit is set in the packet's descriptor, we know the
+	 * timestamp belongs to this packet. No other packet can be
+	 * timestamped until the registers for timestamping have been read.
+	 * Therefor only one packet with this bit can be in the queue at a
+	 * time, and the rx timestamp values that were in the registers belong
+	 * to this packet.
 	 *
 	 * If nothing went wrong, then it should have a skb_shared_tx that we
 	 * can turn into a skb_shared_hwtstamps.
 	 */
-	if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID))
+	if (unlikely(!ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)))
 		return;
 
 	spin_lock_irqsave(&adapter->tmreg_lock, flags);
@@ -539,6 +621,11 @@ void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
  * type has to be specified. Matching the kind of event packet is
  * not supported, with the exception of "all V2 events regardless of
  * level 2 or 4".
+ *
+ * Since hardware always timestamps Path delay packets when timestamping V2
+ * packets, regardless of the type specified in the register, only use V2
+ * Event mode. This more accurately tells the user what the hardware is going
+ * to do anyways.
  */
 int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
 			     struct ifreq *ifr, int cmd)
@@ -582,41 +669,30 @@ int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
 		tsync_rx_mtrl = IXGBE_RXMTRL_V1_DELAY_REQ_MSG;
 		is_l4 = true;
 		break;
+	case HWTSTAMP_FILTER_PTP_V2_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
 	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
 	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
-		tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L2_L4_V2;
-		tsync_rx_mtrl = IXGBE_RXMTRL_V2_SYNC_MSG;
-		is_l2 = true;
-		is_l4 = true;
-		config.rx_filter = HWTSTAMP_FILTER_SOME;
-		break;
 	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
 	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
 	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
-		tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L2_L4_V2;
-		tsync_rx_mtrl = IXGBE_RXMTRL_V2_DELAY_REQ_MSG;
-		is_l2 = true;
-		is_l4 = true;
-		config.rx_filter = HWTSTAMP_FILTER_SOME;
-		break;
-	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
-	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
-	case HWTSTAMP_FILTER_PTP_V2_EVENT:
 		tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_EVENT_V2;
-		config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
 		is_l2 = true;
 		is_l4 = true;
+		config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
 		break;
 	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
 	case HWTSTAMP_FILTER_ALL:
 	default:
 		/*
-		 * register RXMTRL must be set, therefore it is not
-		 * possible to time stamp both V1 Sync and Delay_Req messages
-		 * and hardware does not support timestamping all packets
-		 * => return error
+		 * register RXMTRL must be set in order to do V1 packets,
+		 * therefore it is not possible to time stamp both V1 Sync and
+		 * Delay_Req messages and hardware does not support
+		 * timestamping all packets => return error
 		 */
+		config.rx_filter = HWTSTAMP_FILTER_NONE;
 		return -ERANGE;
 	}
 
@@ -626,6 +702,9 @@ int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
 		return 0;
 	}
 
+	/* Store filter value for later use */
+	adapter->rx_hwtstamp_filter = config.rx_filter;
+
 	/* define ethertype filter for timestamped packets */
 	if (is_l2)
 		IXGBE_WRITE_REG(hw, IXGBE_ETQF(3),
@@ -708,6 +787,7 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
 	u32 incval = 0;
+	u32 timinca = 0;
 	u32 shift = 0;
 	u32 cycle_speed;
 	unsigned long flags;
@@ -730,8 +810,16 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
 		break;
 	}
 
-	/* Bail if the cycle speed didn't change */
-	if (adapter->cycle_speed == cycle_speed)
+	/*
+	 * grab the current TIMINCA value from the register so that it can be
+	 * double checked. If the register value has been cleared, it must be
+	 * reset to the correct value for generating a cyclecounter. If
+	 * TIMINCA is zero, the SYSTIME registers do not increment at all.
+	 */
+	timinca = IXGBE_READ_REG(hw, IXGBE_TIMINCA);
+
+	/* Bail if the cycle speed didn't change and TIMINCA is non-zero */
+	if (adapter->cycle_speed == cycle_speed && timinca)
 		return;
 
 	/* disable the SDP clock out */
@@ -861,6 +949,10 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
 		return;
 	}
 
+	/* initialize the ptp filter */
+	if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter)))
+		e_dev_warn("ptp_filter_init failed\n");
+
 	spin_lock_init(&adapter->tmreg_lock);
 
 	ixgbe_ptp_start_cyclecounter(adapter);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
index 1d80b1c..2334fce 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
@@ -37,7 +37,6 @@
 #include <linux/netdevice.h>
 #include <linux/hwmon.h>
 
-#ifdef CONFIG_IXGBE_HWMON
 /* hwmon callback functions */
 static ssize_t ixgbe_hwmon_show_location(struct device *dev,
 					 struct device_attribute *attr,
@@ -241,5 +240,4 @@ err:
 exit:
 	return rc;
 }
-#endif /* CONFIG_IXGBE_HWMON */
 
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 204848d..7416d22 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -2419,7 +2419,7 @@ typedef u32 ixgbe_physical_layer;
  */
 
 /* BitTimes (BT) conversion */
-#define IXGBE_BT2KB(BT) ((BT + 1023) / (8 * 1024))
+#define IXGBE_BT2KB(BT) ((BT + (8 * 1024 - 1)) / (8 * 1024))
 #define IXGBE_B2BT(BT) (BT * 8)
 
 /* Calculate Delay to respond to PFC */
@@ -2450,24 +2450,31 @@ typedef u32 ixgbe_physical_layer;
 #define IXGBE_PCI_DELAY	10000
 
 /* Calculate X540 delay value in bit times */
-#define IXGBE_FILL_RATE (36 / 25)
-
-#define IXGBE_DV_X540(LINK, TC) (IXGBE_FILL_RATE * \
-				 (IXGBE_B2BT(LINK) + IXGBE_PFC_D + \
-				 (2 * IXGBE_CABLE_DC) + \
-				 (2 * IXGBE_ID_X540) + \
-				 IXGBE_HD + IXGBE_B2BT(TC)))
+#define IXGBE_DV_X540(_max_frame_link, _max_frame_tc) \
+			((36 * \
+			  (IXGBE_B2BT(_max_frame_link) + \
+			   IXGBE_PFC_D + \
+			   (2 * IXGBE_CABLE_DC) + \
+			   (2 * IXGBE_ID_X540) + \
+			   IXGBE_HD) / 25 + 1) + \
+			 2 * IXGBE_B2BT(_max_frame_tc))
 
 /* Calculate 82599, 82598 delay value in bit times */
-#define IXGBE_DV(LINK, TC) (IXGBE_FILL_RATE * \
-			    (IXGBE_B2BT(LINK) + IXGBE_PFC_D + \
-			    (2 * IXGBE_CABLE_DC) + (2 * IXGBE_ID) + \
-			    IXGBE_HD + IXGBE_B2BT(TC)))
+#define IXGBE_DV(_max_frame_link, _max_frame_tc) \
+			((36 * \
+			  (IXGBE_B2BT(_max_frame_link) + \
+			   IXGBE_PFC_D + \
+			   (2 * IXGBE_CABLE_DC) + \
+			   (2 * IXGBE_ID) + \
+			   IXGBE_HD) / 25 + 1) + \
+			 2 * IXGBE_B2BT(_max_frame_tc))
 
 /* Calculate low threshold delay values */
-#define IXGBE_LOW_DV_X540(TC) (2 * IXGBE_B2BT(TC) + \
-			       (IXGBE_FILL_RATE * IXGBE_PCI_DELAY))
-#define IXGBE_LOW_DV(TC)      (2 * IXGBE_LOW_DV_X540(TC))
+#define IXGBE_LOW_DV_X540(_max_frame_tc) \
+			(2 * IXGBE_B2BT(_max_frame_tc) + \
+			(36 * IXGBE_PCI_DELAY / 25) + 1)
+#define IXGBE_LOW_DV(_max_frame_tc) \
+			(2 * IXGBE_LOW_DV_X540(_max_frame_tc))
 
 /* Software ATR hash keys */
 #define IXGBE_ATR_BUCKET_HASH_KEY    0x3DAD14E2
@@ -2597,6 +2604,8 @@ enum ixgbe_sfp_type {
 	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_1g_sx_core0 = 11,
+	ixgbe_sfp_type_1g_sx_core1 = 12,
 	ixgbe_sfp_type_not_present = 0xFFFE,
 	ixgbe_sfp_type_unknown = 0xFFFF
 };
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index f0f06b2..770ee55 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -1896,7 +1896,7 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index)
 		goto out_free;
 	}
 
-	rx_desc = (struct rx_desc *)rxq->rx_desc_area;
+	rx_desc = rxq->rx_desc_area;
 	for (i = 0; i < rxq->rx_ring_size; i++) {
 		int nexti;
 
@@ -2001,7 +2001,7 @@ static int txq_init(struct mv643xx_eth_private *mp, int index)
 
 	txq->tx_desc_area_size = size;
 
-	tx_desc = (struct tx_desc *)txq->tx_desc_area;
+	tx_desc = txq->tx_desc_area;
 	for (i = 0; i < txq->tx_ring_size; i++) {
 		struct tx_desc *txd = tx_desc + i;
 		int nexti;
diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index 1db023b..5948972 100644
--- a/drivers/net/ethernet/marvell/pxa168_eth.c
+++ b/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -1032,7 +1032,7 @@ static int rxq_init(struct net_device *dev)
 	}
 	memset((void *)pep->p_rx_desc_area, 0, size);
 	/* initialize the next_desc_ptr links in the Rx descriptors ring */
-	p_rx_desc = (struct rx_desc *)pep->p_rx_desc_area;
+	p_rx_desc = pep->p_rx_desc_area;
 	for (i = 0; i < rx_desc_num; i++) {
 		p_rx_desc[i].next_desc_ptr = pep->rx_desc_dma +
 		    ((i + 1) % rx_desc_num) * sizeof(struct rx_desc);
@@ -1095,7 +1095,7 @@ static int txq_init(struct net_device *dev)
 	}
 	memset((void *)pep->p_tx_desc_area, 0, pep->tx_desc_area_size);
 	/* Initialize the next_desc_ptr links in the Tx descriptors ring */
-	p_tx_desc = (struct tx_desc *)pep->p_tx_desc_area;
+	p_tx_desc = pep->p_tx_desc_area;
 	for (i = 0; i < tx_desc_num; i++) {
 		p_tx_desc[i].next_desc_ptr = pep->tx_desc_dma +
 		    ((i + 1) % tx_desc_num) * sizeof(struct tx_desc);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 926d8aa..073b85b 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -929,15 +929,20 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv)
 		if (priv->rx_cq[i].buf)
 			mlx4_en_destroy_cq(priv, &priv->rx_cq[i]);
 	}
+
+	if (priv->base_tx_qpn) {
+		mlx4_qp_release_range(priv->mdev->dev, priv->base_tx_qpn, priv->tx_ring_num);
+		priv->base_tx_qpn = 0;
+	}
 }
 
 int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
 {
 	struct mlx4_en_port_profile *prof = priv->prof;
 	int i;
-	int base_tx_qpn, err;
+	int err;
 
-	err = mlx4_qp_reserve_range(priv->mdev->dev, priv->tx_ring_num, 256, &base_tx_qpn);
+	err = mlx4_qp_reserve_range(priv->mdev->dev, priv->tx_ring_num, 256, &priv->base_tx_qpn);
 	if (err) {
 		en_err(priv, "failed reserving range for TX rings\n");
 		return err;
@@ -949,7 +954,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
 				      prof->tx_ring_size, i, TX))
 			goto err;
 
-		if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], base_tx_qpn + i,
+		if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], priv->base_tx_qpn + i,
 					   prof->tx_ring_size, TXBB_SIZE))
 			goto err;
 	}
@@ -969,7 +974,6 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
 
 err:
 	en_err(priv, "Failed to allocate NIC resources\n");
-	mlx4_qp_release_range(priv->mdev->dev, base_tx_qpn, priv->tx_ring_num);
 	return -ENOMEM;
 }
 
@@ -1204,9 +1208,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 	en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
 
 	/* Configure port */
+	mlx4_en_calc_rx_buf(dev);
 	err = mlx4_SET_PORT_general(mdev->dev, priv->port,
-				    MLX4_EN_MIN_MTU,
-				    0, 0, 0, 0);
+				    priv->rx_skb_size + ETH_FCS_LEN,
+				    prof->tx_pause, prof->tx_ppp,
+				    prof->rx_pause, prof->rx_ppp);
 	if (err) {
 		en_err(priv, "Failed setting port general configurations "
 		       "for port %d, with error %d\n", priv->port, err);
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index ee6f4fe..a0313de 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -1975,6 +1975,8 @@ slave_start:
 	if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X) &&
 	    !mlx4_is_mfunc(dev)) {
 		dev->flags &= ~MLX4_FLAG_MSI_X;
+		dev->caps.num_comp_vectors = 1;
+		dev->caps.comp_pool	   = 0;
 		pci_disable_msix(pdev);
 		err = mlx4_setup_hca(dev);
 	}
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 6ae3509..225c20d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -495,6 +495,7 @@ struct mlx4_en_priv {
 	int vids[128];
 	bool wol;
 	struct device *ddev;
+	int base_tx_qpn;
 
 #ifdef CONFIG_MLX4_EN_DCB
 	struct ieee_ets ets;
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index b45d0e7..766b8c5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -779,7 +779,7 @@ static int qp_res_start_move_to(struct mlx4_dev *dev, int slave, int qpn,
 			r->com.to_state = state;
 			r->com.state = RES_QP_BUSY;
 			if (qp)
-				*qp = (struct res_qp *)r;
+				*qp = r;
 		}
 	}
 
@@ -832,7 +832,7 @@ static int mr_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
 			r->com.to_state = state;
 			r->com.state = RES_MPT_BUSY;
 			if (mpt)
-				*mpt = (struct res_mpt *)r;
+				*mpt = r;
 		}
 	}
 
diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c
index 5ffde23..875dd5e 100644
--- a/drivers/net/ethernet/micrel/ks8851_mll.c
+++ b/drivers/net/ethernet/micrel/ks8851_mll.c
@@ -35,7 +35,7 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <asm/io.h>
+#include <linux/ks8851_mll.h>
 
 #define	DRV_NAME	"ks8851_mll"
 
@@ -1515,6 +1515,7 @@ static int __devinit ks8851_probe(struct platform_device *pdev)
 	struct net_device *netdev;
 	struct ks_net *ks;
 	u16 id, data;
+	struct ks8851_mll_platform_data *pdata;
 
 	io_d = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	io_c = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1596,17 +1597,27 @@ static int __devinit ks8851_probe(struct platform_device *pdev)
 	ks_disable_qmu(ks);
 	ks_setup(ks);
 	ks_setup_int(ks);
-	memcpy(netdev->dev_addr, ks->mac_addr, 6);
 
 	data = ks_rdreg16(ks, KS_OBCR);
 	ks_wrreg16(ks, KS_OBCR, data | OBCR_ODS_16MA);
 
-	/**
-	 * If you want to use the default MAC addr,
-	 * comment out the 2 functions below.
-	 */
+	/* overwriting the default MAC address */
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		netdev_err(netdev, "No platform data\n");
+		err = -ENODEV;
+		goto err_pdata;
+	}
+	memcpy(ks->mac_addr, pdata->mac_addr, 6);
+	if (!is_valid_ether_addr(ks->mac_addr)) {
+		/* Use random MAC address if none passed */
+		random_ether_addr(ks->mac_addr);
+		netdev_info(netdev, "Using random mac address\n");
+	}
+	netdev_info(netdev, "Mac address is: %pM\n", ks->mac_addr);
+
+	memcpy(netdev->dev_addr, ks->mac_addr, 6);
 
-	random_ether_addr(netdev->dev_addr);
 	ks_set_mac(ks, netdev->dev_addr);
 
 	id = ks_rdreg16(ks, KS_CIDER);
@@ -1615,6 +1626,8 @@ static int __devinit ks8851_probe(struct platform_device *pdev)
 		    (id >> 8) & 0xff, (id >> 4) & 0xf, (id >> 1) & 0x7);
 	return 0;
 
+err_pdata:
+	unregister_netdev(netdev);
 err_register:
 err_get_irq:
 	iounmap(ks->hw_addr_cmd);
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index bb36758..e7cd587 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -6946,9 +6946,9 @@ static  int rxd_owner_bit_reset(struct s2io_nic *sp)
 				if (sp->rxd_mode == RXD_MODE_3B)
 					ba = &ring->ba[j][k];
 				if (set_rxd_buffer_pointer(sp, rxdp, ba, &skb,
-							   (u64 *)&temp0_64,
-							   (u64 *)&temp1_64,
-							   (u64 *)&temp2_64,
+							   &temp0_64,
+							   &temp1_64,
+							   &temp2_64,
 							   size) == -ENOMEM) {
 					return 0;
 				}
@@ -7149,7 +7149,7 @@ static int s2io_card_up(struct s2io_nic *sp)
 	int i, ret = 0;
 	struct config_param *config;
 	struct mac_info *mac_control;
-	struct net_device *dev = (struct net_device *)sp->dev;
+	struct net_device *dev = sp->dev;
 	u16 interruptible;
 
 	/* Initialize the H/W I/O registers */
@@ -7325,7 +7325,7 @@ static void s2io_tx_watchdog(struct net_device *dev)
 static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
 {
 	struct s2io_nic *sp = ring_data->nic;
-	struct net_device *dev = (struct net_device *)ring_data->dev;
+	struct net_device *dev = ring_data->dev;
 	struct sk_buff *skb = (struct sk_buff *)
 		((unsigned long)rxdp->Host_Control);
 	int ring_no = ring_data->ring_no;
@@ -7508,7 +7508,7 @@ aggregate:
 
 static void s2io_link(struct s2io_nic *sp, int link)
 {
-	struct net_device *dev = (struct net_device *)sp->dev;
+	struct net_device *dev = sp->dev;
 	struct swStat *swstats = &sp->mac_control.stats_info->sw_stat;
 
 	if (link != sp->last_link_state) {
@@ -8280,7 +8280,7 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
 		return -1;
 	}
 
-	*ip = (struct iphdr *)((u8 *)buffer + ip_off);
+	*ip = (struct iphdr *)(buffer + ip_off);
 	ip_len = (u8)((*ip)->ihl);
 	ip_len <<= 2;
 	*tcp = (struct tcphdr *)((unsigned long)*ip + ip_len);
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c
index 98e2c10..32d0682 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-config.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c
@@ -2346,7 +2346,7 @@ void __vxge_hw_blockpool_blocks_add(struct __vxge_hw_blockpool *blockpool)
 
 	for (i = 0; i < nreq; i++)
 		vxge_os_dma_malloc_async(
-			((struct __vxge_hw_device *)blockpool->hldev)->pdev,
+			(blockpool->hldev)->pdev,
 			blockpool->hldev, VXGE_HW_BLOCK_SIZE);
 }
 
@@ -2428,13 +2428,13 @@ __vxge_hw_blockpool_blocks_remove(struct __vxge_hw_blockpool *blockpool)
 			break;
 
 		pci_unmap_single(
-			((struct __vxge_hw_device *)blockpool->hldev)->pdev,
+			(blockpool->hldev)->pdev,
 			((struct __vxge_hw_blockpool_entry *)p)->dma_addr,
 			((struct __vxge_hw_blockpool_entry *)p)->length,
 			PCI_DMA_BIDIRECTIONAL);
 
 		vxge_os_dma_free(
-			((struct __vxge_hw_device *)blockpool->hldev)->pdev,
+			(blockpool->hldev)->pdev,
 			((struct __vxge_hw_blockpool_entry *)p)->memblock,
 			&((struct __vxge_hw_blockpool_entry *)p)->acc_handle);
 
@@ -4059,7 +4059,7 @@ __vxge_hw_vpath_sw_reset(struct __vxge_hw_device *hldev, u32 vp_id)
 	enum vxge_hw_status status = VXGE_HW_OK;
 	struct __vxge_hw_virtualpath *vpath;
 
-	vpath = (struct __vxge_hw_virtualpath *)&hldev->virtual_paths[vp_id];
+	vpath = &hldev->virtual_paths[vp_id];
 
 	if (vpath->ringh) {
 		status = __vxge_hw_ring_reset(vpath->ringh);
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.h b/drivers/net/ethernet/neterion/vxge/vxge-config.h
index 5046a64..9e0c1ee 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-config.h
+++ b/drivers/net/ethernet/neterion/vxge/vxge-config.h
@@ -1922,7 +1922,7 @@ realloc:
 		/* misaligned, free current one and try allocating
 		 * size + VXGE_CACHE_LINE_SIZE memory
 		 */
-		kfree((void *) vaddr);
+		kfree(vaddr);
 		size += VXGE_CACHE_LINE_SIZE;
 		realloc_flag = 1;
 		goto realloc;
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c
index 51387c3..2578eb1 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-main.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -1134,7 +1134,7 @@ static void vxge_set_multicast(struct net_device *dev)
 		"%s:%d", __func__, __LINE__);
 
 	vdev = netdev_priv(dev);
-	hldev = (struct __vxge_hw_device  *)vdev->devh;
+	hldev = vdev->devh;
 
 	if (unlikely(!is_vxge_card_up(vdev)))
 		return;
@@ -3989,16 +3989,16 @@ static void __devinit vxge_print_parm(struct vxgedev *vdev, u64 vpath_mask)
 			continue;
 		vxge_debug_ll_config(VXGE_TRACE,
 			"%s: MTU size - %d", vdev->ndev->name,
-			((struct __vxge_hw_device  *)(vdev->devh))->
+			((vdev->devh))->
 				config.vp_config[i].mtu);
 		vxge_debug_init(VXGE_TRACE,
 			"%s: VLAN tag stripping %s", vdev->ndev->name,
-			((struct __vxge_hw_device  *)(vdev->devh))->
+			((vdev->devh))->
 				config.vp_config[i].rpa_strip_vlan_tag
 			? "Enabled" : "Disabled");
 		vxge_debug_ll_config(VXGE_TRACE,
 			"%s: Max frags : %d", vdev->ndev->name,
-			((struct __vxge_hw_device  *)(vdev->devh))->
+			((vdev->devh))->
 				config.vp_config[i].fifo.max_frags);
 		break;
 	}
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-traffic.c b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
index 5954fa2..99749bd 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
@@ -533,8 +533,7 @@ __vxge_hw_device_handle_error(struct __vxge_hw_device *hldev, u32 vp_id,
 
 	/* notify driver */
 	if (hldev->uld_callbacks->crit_err)
-		hldev->uld_callbacks->crit_err(
-			(struct __vxge_hw_device *)hldev,
+		hldev->uld_callbacks->crit_err(hldev,
 			type, vp_id);
 out:
 
@@ -1322,7 +1321,7 @@ enum vxge_hw_status vxge_hw_ring_rxd_next_completed(
 	/* check whether it is not the end */
 	if (!own || *t_code == VXGE_HW_RING_T_CODE_FRM_DROP) {
 
-		vxge_assert(((struct vxge_hw_ring_rxd_1 *)rxdp)->host_control !=
+		vxge_assert((rxdp)->host_control !=
 				0);
 
 		++ring->cmpl_cnt;
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index 083d671..e7d2496 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -52,7 +52,6 @@
 
 #define MODNAME "lpc-eth"
 #define DRV_VERSION "1.00"
-#define PHYDEF_ADDR 0x00
 
 #define ENET_MAXF_SIZE 1536
 #define ENET_RX_DESC 48
@@ -416,9 +415,6 @@ static bool use_iram_for_net(struct device *dev)
 #define TXDESC_CONTROL_LAST		(1 << 30)
 #define TXDESC_CONTROL_INT		(1 << 31)
 
-static int lpc_eth_hard_start_xmit(struct sk_buff *skb,
-				   struct net_device *ndev);
-
 /*
  * Structure of a TX/RX descriptors and RX status
  */
@@ -440,7 +436,7 @@ struct netdata_local {
 	spinlock_t		lock;
 	void __iomem		*net_base;
 	u32			msg_enable;
-	struct sk_buff		*skb[ENET_TX_DESC];
+	unsigned int		skblen[ENET_TX_DESC];
 	unsigned int		last_tx_idx;
 	unsigned int		num_used_tx_buffs;
 	struct mii_bus		*mii_bus;
@@ -903,12 +899,11 @@ err_out:
 static void __lpc_handle_xmit(struct net_device *ndev)
 {
 	struct netdata_local *pldat = netdev_priv(ndev);
-	struct sk_buff *skb;
 	u32 txcidx, *ptxstat, txstat;
 
 	txcidx = readl(LPC_ENET_TXCONSUMEINDEX(pldat->net_base));
 	while (pldat->last_tx_idx != txcidx) {
-		skb = pldat->skb[pldat->last_tx_idx];
+		unsigned int skblen = pldat->skblen[pldat->last_tx_idx];
 
 		/* A buffer is available, get buffer status */
 		ptxstat = &pldat->tx_stat_v[pldat->last_tx_idx];
@@ -945,9 +940,8 @@ static void __lpc_handle_xmit(struct net_device *ndev)
 		} else {
 			/* Update stats */
 			ndev->stats.tx_packets++;
-			ndev->stats.tx_bytes += skb->len;
+			ndev->stats.tx_bytes += skblen;
 		}
-		dev_kfree_skb_irq(skb);
 
 		txcidx = readl(LPC_ENET_TXCONSUMEINDEX(pldat->net_base));
 	}
@@ -1132,7 +1126,7 @@ static int lpc_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	memcpy(pldat->tx_buff_v + txidx * ENET_MAXF_SIZE, skb->data, len);
 
 	/* Save the buffer and increment the buffer counter */
-	pldat->skb[txidx] = skb;
+	pldat->skblen[txidx] = len;
 	pldat->num_used_tx_buffs++;
 
 	/* Start transmit */
@@ -1147,6 +1141,7 @@ static int lpc_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
 	spin_unlock_irq(&pldat->lock);
 
+	dev_kfree_skb(skb);
 	return NETDEV_TX_OK;
 }
 
@@ -1442,7 +1437,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
 			res->start);
 	netdev_dbg(ndev, "IO address size      :%d\n",
 			res->end - res->start + 1);
-	netdev_err(ndev, "IO address (mapped)  :0x%p\n",
+	netdev_dbg(ndev, "IO address (mapped)  :0x%p\n",
 			pldat->net_base);
 	netdev_dbg(ndev, "IRQ number           :%d\n", ndev->irq);
 	netdev_dbg(ndev, "DMA buffer size      :%d\n", pldat->dma_buff_size);
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
index 3973040..9103e3e 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
@@ -489,7 +489,7 @@ netxen_nic_get_pauseparam(struct net_device *dev,
 	int port = adapter->physical_port;
 
 	if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
-		if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+		if ((port < 0) || (port >= NETXEN_NIU_MAX_GBE_PORTS))
 			return;
 		/* get flow control settings */
 		val = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port));
@@ -511,7 +511,7 @@ netxen_nic_get_pauseparam(struct net_device *dev,
 				break;
 		}
 	} else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
-		if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
+		if ((port < 0) || (port >= NETXEN_NIU_MAX_XG_PORTS))
 			return;
 		pause->rx_pause = 1;
 		val = NXRD32(adapter, NETXEN_NIU_XG_PAUSE_CTL);
@@ -534,7 +534,7 @@ netxen_nic_set_pauseparam(struct net_device *dev,
 	int port = adapter->physical_port;
 	/* read mode */
 	if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
-		if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+		if ((port < 0) || (port >= NETXEN_NIU_MAX_GBE_PORTS))
 			return -EIO;
 		/* set flow control */
 		val = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port));
@@ -577,7 +577,7 @@ netxen_nic_set_pauseparam(struct net_device *dev,
 		}
 		NXWR32(adapter, NETXEN_NIU_GB_PAUSE_CTL, val);
 	} else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
-		if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
+		if ((port < 0) || (port >= NETXEN_NIU_MAX_XG_PORTS))
 			return -EIO;
 		val = NXRD32(adapter, NETXEN_NIU_XG_PAUSE_CTL);
 		if (port == 0) {
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c
index de96a94..946160f 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c
@@ -365,7 +365,7 @@ static int netxen_niu_disable_xg_port(struct netxen_adapter *adapter)
 	if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
 		return 0;
 
-	if (port > NETXEN_NIU_MAX_XG_PORTS)
+	if (port >= NETXEN_NIU_MAX_XG_PORTS)
 		return -EINVAL;
 
 	mac_cfg = 0;
@@ -392,7 +392,7 @@ static int netxen_p2_nic_set_promisc(struct netxen_adapter *adapter, u32 mode)
 	u32 port = adapter->physical_port;
 	u16 board_type = adapter->ahw.board_type;
 
-	if (port > NETXEN_NIU_MAX_XG_PORTS)
+	if (port >= NETXEN_NIU_MAX_XG_PORTS)
 		return -EINVAL;
 
 	mac_cfg = NXRD32(adapter, NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port));
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 8680a5d..eaa1db9 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -36,8 +36,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 28
-#define QLCNIC_LINUX_VERSIONID  "5.0.28"
+#define _QLCNIC_LINUX_SUBVERSION 29
+#define QLCNIC_LINUX_VERSIONID  "5.0.29"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
 		 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -258,6 +258,8 @@ struct rcv_desc {
 	(((sts_data) >> 52) & 0x1)
 #define qlcnic_get_lro_sts_seq_number(sts_data)		\
 	((sts_data) & 0x0FFFFFFFF)
+#define qlcnic_get_lro_sts_mss(sts_data1)		\
+	((sts_data1 >> 32) & 0x0FFFF)
 
 
 struct status_desc {
@@ -610,7 +612,11 @@ struct qlcnic_recv_context {
 #define QLCNIC_CDRP_CMD_GET_MAC_STATS		0x00000037
 
 #define QLCNIC_RCODE_SUCCESS		0
+#define QLCNIC_RCODE_INVALID_ARGS	6
 #define QLCNIC_RCODE_NOT_SUPPORTED	9
+#define QLCNIC_RCODE_NOT_PERMITTED	10
+#define QLCNIC_RCODE_NOT_IMPL		15
+#define QLCNIC_RCODE_INVALID		16
 #define QLCNIC_RCODE_TIMEOUT		17
 #define QLCNIC_DESTROY_CTX_RESET	0
 
@@ -623,6 +629,7 @@ struct qlcnic_recv_context {
 #define QLCNIC_CAP0_JUMBO_CONTIGUOUS	(1 << 7)
 #define QLCNIC_CAP0_LRO_CONTIGUOUS	(1 << 8)
 #define QLCNIC_CAP0_VALIDOFF		(1 << 11)
+#define QLCNIC_CAP0_LRO_MSS		(1 << 21)
 
 /*
  * Context state
@@ -829,6 +836,9 @@ struct qlcnic_mac_list_s {
 #define QLCNIC_FW_CAPABILITY_FVLANTX		BIT_9
 #define QLCNIC_FW_CAPABILITY_HW_LRO		BIT_10
 #define QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK	BIT_27
+#define QLCNIC_FW_CAPABILITY_MORE_CAPS		BIT_31
+
+#define QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG	BIT_2
 
 /* module types */
 #define LINKEVENT_MODULE_NOT_PRESENT			1
@@ -918,6 +928,7 @@ struct qlcnic_ipaddr {
 #define QLCNIC_NEED_FLR			0x1000
 #define QLCNIC_FW_RESET_OWNER		0x2000
 #define QLCNIC_FW_HANG			0x4000
+#define QLCNIC_FW_LRO_MSS_CAP		0x8000
 #define QLCNIC_IS_MSI_FAMILY(adapter) \
 	((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
 
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index 8db8524..b8ead69 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -53,12 +53,39 @@ qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *cmd)
 	rsp = qlcnic_poll_rsp(adapter);
 
 	if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) {
-		dev_err(&pdev->dev, "card response timeout.\n");
+		dev_err(&pdev->dev, "CDRP response timeout.\n");
 		cmd->rsp.cmd = QLCNIC_RCODE_TIMEOUT;
 	} else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
 		cmd->rsp.cmd = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
-		dev_err(&pdev->dev, "failed card response code:0x%x\n",
+		switch (cmd->rsp.cmd) {
+		case QLCNIC_RCODE_INVALID_ARGS:
+			dev_err(&pdev->dev, "CDRP invalid args: 0x%x.\n",
 				cmd->rsp.cmd);
+			break;
+		case QLCNIC_RCODE_NOT_SUPPORTED:
+		case QLCNIC_RCODE_NOT_IMPL:
+			dev_err(&pdev->dev,
+				"CDRP command not supported: 0x%x.\n",
+				cmd->rsp.cmd);
+			break;
+		case QLCNIC_RCODE_NOT_PERMITTED:
+			dev_err(&pdev->dev,
+				"CDRP requested action not permitted: 0x%x.\n",
+				cmd->rsp.cmd);
+			break;
+		case QLCNIC_RCODE_INVALID:
+			dev_err(&pdev->dev,
+				"CDRP invalid or unknown cmd received: 0x%x.\n",
+				cmd->rsp.cmd);
+			break;
+		case QLCNIC_RCODE_TIMEOUT:
+			dev_err(&pdev->dev, "CDRP command timeout: 0x%x.\n",
+				cmd->rsp.cmd);
+			break;
+		default:
+			dev_err(&pdev->dev, "CDRP command failed: 0x%x.\n",
+				cmd->rsp.cmd);
+		}
 	} else if (rsp == QLCNIC_CDRP_RSP_OK) {
 		cmd->rsp.cmd = QLCNIC_RCODE_SUCCESS;
 		if (cmd->rsp.arg2)
@@ -237,6 +264,9 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
 						| QLCNIC_CAP0_VALIDOFF);
 	cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
 
+	if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+		cap |= QLCNIC_CAP0_LRO_MSS;
+
 	prq->valid_field_offset = offsetof(struct qlcnic_hostrq_rx_ctx,
 							 msix_handler);
 	prq->txrx_sds_binding = nsds_rings - 1;
@@ -954,9 +984,6 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
 		mac_stats->mac_rx_jabber = le64_to_cpu(stats->mac_rx_jabber);
 		mac_stats->mac_rx_dropped = le64_to_cpu(stats->mac_rx_dropped);
 		mac_stats->mac_rx_crc_error = le64_to_cpu(stats->mac_rx_crc_error);
-	} else {
-		dev_info(&adapter->pdev->dev,
-			"%s: Get mac stats failed =%d.\n", __func__, err);
 	}
 
 	dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
index 6ced319..28a6b28 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
@@ -588,6 +588,7 @@ enum {
 #define CRB_DRIVER_VERSION		(QLCNIC_REG(0x2a0))
 
 #define CRB_FW_CAPABILITIES_1		(QLCNIC_CAM_RAM(0x128))
+#define CRB_FW_CAPABILITIES_2		(QLCNIC_CAM_RAM(0x12c))
 #define CRB_MAC_BLOCK_START		(QLCNIC_CAM_RAM(0x1c0))
 
 /*
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index 799fd40..8620b69 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -1653,6 +1653,9 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
 
 	length = skb->len;
 
+	if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+		skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1);
+
 	if (vid != 0xffff)
 		__vlan_hwaccel_put_tag(skb, vid);
 	netif_receive_skb(skb);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 46e77a2..212c121 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -479,7 +479,7 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 
 	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
 		pfn = pci_info[i].id;
-		if (pfn > QLCNIC_MAX_PCI_FUNC) {
+		if (pfn >= QLCNIC_MAX_PCI_FUNC) {
 			ret = QL_STATUS_INVALID_PARAM;
 			goto err_eswitch;
 		}
@@ -1136,6 +1136,8 @@ static int
 __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
 	int ring;
+	u32 capab2;
+
 	struct qlcnic_host_rds_ring *rds_ring;
 
 	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
@@ -1146,6 +1148,12 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 	if (qlcnic_set_eswitch_port_config(adapter))
 		return -EIO;
 
+	if (adapter->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
+		capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+		if (capab2 & QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
+			adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
+	}
+
 	if (qlcnic_fw_create_ctx(adapter))
 		return -EIO;
 
@@ -1215,6 +1223,7 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
 	qlcnic_napi_disable(adapter);
 
 	qlcnic_fw_destroy_ctx(adapter);
+	adapter->flags &= ~QLCNIC_FW_LRO_MSS_CAP;
 
 	qlcnic_reset_rx_buffers_list(adapter);
 	qlcnic_release_tx_buffers(adapter);
@@ -2024,6 +2033,7 @@ qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
 		vh = (struct vlan_ethhdr *)skb->data;
 		flags = FLAGS_VLAN_TAGGED;
 		vlan_tci = vh->h_vlan_TCI;
+		protocol = ntohs(vh->h_vlan_encapsulated_proto);
 	} else if (vlan_tx_tag_present(skb)) {
 		flags = FLAGS_VLAN_OOB;
 		vlan_tci = vlan_tx_tag_get(skb);
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 7260aa7..d7a04e0 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -3894,6 +3894,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_22:
 	case RTL_GIGA_MAC_VER_23:
 	case RTL_GIGA_MAC_VER_24:
+	case RTL_GIGA_MAC_VER_34:
 		RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
 		break;
 	default:
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 667169b..326cb91 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -49,6 +49,34 @@
 		NETIF_MSG_RX_ERR| \
 		NETIF_MSG_TX_ERR)
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7734) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+	defined(CONFIG_ARCH_R8A7740)
+static void sh_eth_select_mii(struct net_device *ndev)
+{
+	u32 value = 0x0;
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+
+	switch (mdp->phy_interface) {
+	case PHY_INTERFACE_MODE_GMII:
+		value = 0x2;
+		break;
+	case PHY_INTERFACE_MODE_MII:
+		value = 0x1;
+		break;
+	case PHY_INTERFACE_MODE_RMII:
+		value = 0x0;
+		break;
+	default:
+		pr_warn("PHY interface mode was not setup. Set to MII.\n");
+		value = 0x1;
+		break;
+	}
+
+	sh_eth_write(ndev, value, RMII_MII);
+}
+#endif
+
 /* There is CPU dependent code */
 #if defined(CONFIG_CPU_SUBTYPE_SH7724)
 #define SH_ETH_RESET_DEFAULT	1
@@ -102,6 +130,8 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
 #elif defined(CONFIG_CPU_SUBTYPE_SH7757)
 #define SH_ETH_HAS_BOTH_MODULES	1
 #define SH_ETH_HAS_TSU	1
+static int sh_eth_check_reset(struct net_device *ndev);
+
 static void sh_eth_set_duplex(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -176,23 +206,19 @@ static void sh_eth_chip_reset_giga(struct net_device *ndev)
 }
 
 static int sh_eth_is_gether(struct sh_eth_private *mdp);
-static void sh_eth_reset(struct net_device *ndev)
+static int sh_eth_reset(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	int cnt = 100;
+	int ret = 0;
 
 	if (sh_eth_is_gether(mdp)) {
 		sh_eth_write(ndev, 0x03, EDSR);
 		sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER,
 				EDMR);
-		while (cnt > 0) {
-			if (!(sh_eth_read(ndev, EDMR) & 0x3))
-				break;
-			mdelay(1);
-			cnt--;
-		}
-		if (cnt < 0)
-			printk(KERN_ERR "Device reset fail\n");
+
+		ret = sh_eth_check_reset(ndev);
+		if (ret)
+			goto out;
 
 		/* Table Init */
 		sh_eth_write(ndev, 0x0, TDLAR);
@@ -210,6 +236,9 @@ static void sh_eth_reset(struct net_device *ndev)
 		sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST_ETHER,
 				EDMR);
 	}
+
+out:
+	return ret;
 }
 
 static void sh_eth_set_duplex_giga(struct net_device *ndev)
@@ -282,7 +311,9 @@ static struct sh_eth_cpu_data *sh_eth_get_cpu_data(struct sh_eth_private *mdp)
 
 #elif defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763)
 #define SH_ETH_HAS_TSU	1
+static int sh_eth_check_reset(struct net_device *ndev);
 static void sh_eth_reset_hw_crc(struct net_device *ndev);
+
 static void sh_eth_chip_reset(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -292,35 +323,6 @@ static void sh_eth_chip_reset(struct net_device *ndev)
 	mdelay(1);
 }
 
-static void sh_eth_reset(struct net_device *ndev)
-{
-	int cnt = 100;
-
-	sh_eth_write(ndev, EDSR_ENALL, EDSR);
-	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR);
-	while (cnt > 0) {
-		if (!(sh_eth_read(ndev, EDMR) & 0x3))
-			break;
-		mdelay(1);
-		cnt--;
-	}
-	if (cnt == 0)
-		printk(KERN_ERR "Device reset fail\n");
-
-	/* Table Init */
-	sh_eth_write(ndev, 0x0, TDLAR);
-	sh_eth_write(ndev, 0x0, TDFAR);
-	sh_eth_write(ndev, 0x0, TDFXR);
-	sh_eth_write(ndev, 0x0, TDFFR);
-	sh_eth_write(ndev, 0x0, RDLAR);
-	sh_eth_write(ndev, 0x0, RDFAR);
-	sh_eth_write(ndev, 0x0, RDFXR);
-	sh_eth_write(ndev, 0x0, RDFFR);
-
-	/* Reset HW CRC register */
-	sh_eth_reset_hw_crc(ndev);
-}
-
 static void sh_eth_set_duplex(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -377,9 +379,41 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
 	.tsu		= 1,
 #if defined(CONFIG_CPU_SUBTYPE_SH7734)
 	.hw_crc     = 1,
+	.select_mii = 1,
 #endif
 };
 
+static int sh_eth_reset(struct net_device *ndev)
+{
+	int ret = 0;
+
+	sh_eth_write(ndev, EDSR_ENALL, EDSR);
+	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR);
+
+	ret = sh_eth_check_reset(ndev);
+	if (ret)
+		goto out;
+
+	/* Table Init */
+	sh_eth_write(ndev, 0x0, TDLAR);
+	sh_eth_write(ndev, 0x0, TDFAR);
+	sh_eth_write(ndev, 0x0, TDFXR);
+	sh_eth_write(ndev, 0x0, TDFFR);
+	sh_eth_write(ndev, 0x0, RDLAR);
+	sh_eth_write(ndev, 0x0, RDFAR);
+	sh_eth_write(ndev, 0x0, RDFXR);
+	sh_eth_write(ndev, 0x0, RDFFR);
+
+	/* Reset HW CRC register */
+	sh_eth_reset_hw_crc(ndev);
+
+	/* Select MII mode */
+	if (sh_eth_my_cpu_data.select_mii)
+		sh_eth_select_mii(ndev);
+out:
+	return ret;
+}
+
 static void sh_eth_reset_hw_crc(struct net_device *ndev)
 {
 	if (sh_eth_my_cpu_data.hw_crc)
@@ -388,44 +422,29 @@ static void sh_eth_reset_hw_crc(struct net_device *ndev)
 
 #elif defined(CONFIG_ARCH_R8A7740)
 #define SH_ETH_HAS_TSU	1
+static int sh_eth_check_reset(struct net_device *ndev);
+
 static void sh_eth_chip_reset(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	unsigned long mii;
 
 	/* reset device */
 	sh_eth_tsu_write(mdp, ARSTR_ARSTR, ARSTR);
 	mdelay(1);
 
-	switch (mdp->phy_interface) {
-	case PHY_INTERFACE_MODE_GMII:
-		mii = 2;
-		break;
-	case PHY_INTERFACE_MODE_MII:
-		mii = 1;
-		break;
-	case PHY_INTERFACE_MODE_RMII:
-	default:
-		mii = 0;
-		break;
-	}
-	sh_eth_write(ndev, mii, RMII_MII);
+	sh_eth_select_mii(ndev);
 }
 
-static void sh_eth_reset(struct net_device *ndev)
+static int sh_eth_reset(struct net_device *ndev)
 {
-	int cnt = 100;
+	int ret = 0;
 
 	sh_eth_write(ndev, EDSR_ENALL, EDSR);
 	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR);
-	while (cnt > 0) {
-		if (!(sh_eth_read(ndev, EDMR) & 0x3))
-			break;
-		mdelay(1);
-		cnt--;
-	}
-	if (cnt == 0)
-		printk(KERN_ERR "Device reset fail\n");
+
+	ret = sh_eth_check_reset(ndev);
+	if (ret)
+		goto out;
 
 	/* Table Init */
 	sh_eth_write(ndev, 0x0, TDLAR);
@@ -436,6 +455,9 @@ static void sh_eth_reset(struct net_device *ndev)
 	sh_eth_write(ndev, 0x0, RDFAR);
 	sh_eth_write(ndev, 0x0, RDFXR);
 	sh_eth_write(ndev, 0x0, RDFFR);
+
+out:
+	return ret;
 }
 
 static void sh_eth_set_duplex(struct net_device *ndev)
@@ -492,6 +514,7 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
 	.no_trimd	= 1,
 	.no_ade		= 1,
 	.tsu		= 1,
+	.select_mii	= 1,
 };
 
 #elif defined(CONFIG_CPU_SUBTYPE_SH7619)
@@ -543,11 +566,31 @@ static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd)
 
 #if defined(SH_ETH_RESET_DEFAULT)
 /* Chip Reset */
-static void sh_eth_reset(struct net_device *ndev)
+static int  sh_eth_reset(struct net_device *ndev)
 {
 	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_ETHER, EDMR);
 	mdelay(3);
 	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST_ETHER, EDMR);
+
+	return 0;
+}
+#else
+static int sh_eth_check_reset(struct net_device *ndev)
+{
+	int ret = 0;
+	int cnt = 100;
+
+	while (cnt > 0) {
+		if (!(sh_eth_read(ndev, EDMR) & 0x3))
+			break;
+		mdelay(1);
+		cnt--;
+	}
+	if (cnt < 0) {
+		printk(KERN_ERR "Device reset fail\n");
+		ret = -ETIMEDOUT;
+	}
+	return ret;
 }
 #endif
 
@@ -902,7 +945,9 @@ static int sh_eth_dev_init(struct net_device *ndev)
 	u32 val;
 
 	/* Soft Reset */
-	sh_eth_reset(ndev);
+	ret = sh_eth_reset(ndev);
+	if (ret)
+		goto out;
 
 	/* Descriptor format */
 	sh_eth_ring_format(ndev);
@@ -976,6 +1021,7 @@ static int sh_eth_dev_init(struct net_device *ndev)
 
 	netif_start_queue(ndev);
 
+out:
 	return ret;
 }
 
@@ -1011,7 +1057,7 @@ static int sh_eth_txfree(struct net_device *ndev)
 }
 
 /* Packet receive function */
-static int sh_eth_rx(struct net_device *ndev)
+static int sh_eth_rx(struct net_device *ndev, u32 intr_status)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
 	struct sh_eth_rxdesc *rxdesc;
@@ -1102,9 +1148,11 @@ static int sh_eth_rx(struct net_device *ndev)
 	/* Restart Rx engine if stopped. */
 	/* If we don't need to check status, don't. -KDU */
 	if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) {
-		/* fix the values for the next receiving */
-		mdp->cur_rx = mdp->dirty_rx = (sh_eth_read(ndev, RDFAR) -
-					       sh_eth_read(ndev, RDLAR)) >> 4;
+		/* fix the values for the next receiving if RDE is set */
+		if (intr_status & EESR_RDE)
+			mdp->cur_rx = mdp->dirty_rx =
+				(sh_eth_read(ndev, RDFAR) -
+				 sh_eth_read(ndev, RDLAR)) >> 4;
 		sh_eth_write(ndev, EDRRR_R, EDRRR);
 	}
 
@@ -1273,7 +1321,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
 			EESR_RTSF | /* short frame recv */
 			EESR_PRE  | /* PHY-LSI recv error */
 			EESR_CERF)){ /* recv frame CRC error */
-		sh_eth_rx(ndev);
+		sh_eth_rx(ndev, intr_status);
 	}
 
 	/* Tx Check */
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index 57b8e1f..d6763b1392 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -757,6 +757,7 @@ struct sh_eth_cpu_data {
 	unsigned no_trimd:1;		/* E-DMAC DO NOT have TRIMD */
 	unsigned no_ade:1;	/* E-DMAC DO NOT have ADE bit in EESR */
 	unsigned hw_crc:1;	/* E-DMAC have CSMR */
+	unsigned select_mii:1;	/* EtherC have RMII_MII (MII select register) */
 };
 
 struct sh_eth_private {
diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
index ac149d9..b5ba308 100644
--- a/drivers/net/ethernet/sgi/ioc3-eth.c
+++ b/drivers/net/ethernet/sgi/ioc3-eth.c
@@ -583,7 +583,7 @@ static inline void ioc3_rx(struct net_device *dev)
 	unsigned long *rxr;
 	u32 w0, err;
 
-	rxr = (unsigned long *) ip->rxr;		/* Ring base */
+	rxr = ip->rxr;		/* Ring base */
 	rx_entry = ip->rx_ci;				/* RX consume index */
 	n_entry = ip->rx_pi;
 
@@ -903,7 +903,7 @@ static void ioc3_alloc_rings(struct net_device *dev)
 	if (ip->rxr == NULL) {
 		/* Allocate and initialize rx ring.  4kb = 512 entries  */
 		ip->rxr = (unsigned long *) get_zeroed_page(GFP_ATOMIC);
-		rxr = (unsigned long *) ip->rxr;
+		rxr = ip->rxr;
 		if (!rxr)
 			printk("ioc3_alloc_rings(): get_zeroed_page() failed!\n");
 
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index 1466e5d..54ca99d 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -1442,6 +1442,14 @@ smsc911x_set_hw_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6])
 	smsc911x_mac_write(pdata, ADDRL, mac_low32);
 }
 
+static void smsc911x_disable_irq_chip(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+
+	smsc911x_reg_write(pdata, INT_EN, 0);
+	smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
+}
+
 static int smsc911x_open(struct net_device *dev)
 {
 	struct smsc911x_data *pdata = netdev_priv(dev);
@@ -1494,8 +1502,7 @@ static int smsc911x_open(struct net_device *dev)
 	spin_unlock_irq(&pdata->mac_lock);
 
 	/* Initialise irqs, but leave all sources disabled */
-	smsc911x_reg_write(pdata, INT_EN, 0);
-	smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
+	smsc911x_disable_irq_chip(dev);
 
 	/* Set interrupt deassertion to 100uS */
 	intcfg = ((10 << 24) | INT_CFG_IRQ_EN_);
@@ -2215,9 +2222,6 @@ static int __devinit smsc911x_init(struct net_device *dev)
 	if (smsc911x_soft_reset(pdata))
 		return -ENODEV;
 
-	/* Disable all interrupt sources until we bring the device up */
-	smsc911x_reg_write(pdata, INT_EN, 0);
-
 	ether_setup(dev);
 	dev->flags |= IFF_MULTICAST;
 	netif_napi_add(dev, &pdata->napi, smsc911x_poll, SMSC_NAPI_WEIGHT);
@@ -2434,8 +2438,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
 	smsc911x_reg_write(pdata, INT_CFG, intcfg);
 
 	/* Ensure interrupts are globally disabled before connecting ISR */
-	smsc911x_reg_write(pdata, INT_EN, 0);
-	smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
+	smsc911x_disable_irq_chip(dev);
 
 	retval = request_irq(dev->irq, smsc911x_irqhandler,
 			     irq_flags | IRQF_SHARED, dev->name, dev);
diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c
index fd33b21..1fcd914e 100644
--- a/drivers/net/ethernet/smsc/smsc9420.c
+++ b/drivers/net/ethernet/smsc/smsc9420.c
@@ -1640,8 +1640,7 @@ smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto out_free_io_4;
 
 	/* descriptors are aligned due to the nature of pci_alloc_consistent */
-	pd->tx_ring = (struct smsc9420_dma_desc *)
-	    (pd->rx_ring + RX_RING_SIZE);
+	pd->tx_ring = (pd->rx_ring + RX_RING_SIZE);
 	pd->tx_dma_addr = pd->rx_dma_addr +
 	    sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE;
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index dc20c56..900c5e6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -82,9 +82,7 @@ struct stmmac_priv {
 	struct stmmac_counters mmc;
 	struct dma_features dma_cap;
 	int hw_cap_support;
-#ifdef CONFIG_HAVE_CLK
 	struct clk *stmmac_clk;
-#endif
 	int clk_csr;
 	int synopsys_id;
 };
@@ -105,46 +103,6 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 				     struct plat_stmmacenet_data *plat_dat,
 				     void __iomem *addr);
 
-#ifdef CONFIG_HAVE_CLK
-static inline int stmmac_clk_enable(struct stmmac_priv *priv)
-{
-	if (!IS_ERR(priv->stmmac_clk))
-		return clk_prepare_enable(priv->stmmac_clk);
-
-	return 0;
-}
-
-static inline void stmmac_clk_disable(struct stmmac_priv *priv)
-{
-	if (IS_ERR(priv->stmmac_clk))
-		return;
-
-	clk_disable_unprepare(priv->stmmac_clk);
-}
-static inline int stmmac_clk_get(struct stmmac_priv *priv)
-{
-	priv->stmmac_clk = clk_get(priv->device, NULL);
-
-	if (IS_ERR(priv->stmmac_clk))
-		return PTR_ERR(priv->stmmac_clk);
-
-	return 0;
-}
-#else
-static inline int stmmac_clk_enable(struct stmmac_priv *priv)
-{
-	return 0;
-}
-static inline void stmmac_clk_disable(struct stmmac_priv *priv)
-{
-}
-static inline int stmmac_clk_get(struct stmmac_priv *priv)
-{
-	return 0;
-}
-#endif /* CONFIG_HAVE_CLK */
-
-
 #ifdef CONFIG_STMMAC_PLATFORM
 extern struct platform_driver stmmac_pltfr_driver;
 static inline int stmmac_register_platform(void)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 51b3b68..42aeb48 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -28,6 +28,7 @@
 	https://bugzilla.stlinux.com/
 *******************************************************************************/
 
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/ip.h>
@@ -165,12 +166,8 @@ static void stmmac_verify_args(void)
 
 static void stmmac_clk_csr_set(struct stmmac_priv *priv)
 {
-#ifdef CONFIG_HAVE_CLK
 	u32 clk_rate;
 
-	if (IS_ERR(priv->stmmac_clk))
-		return;
-
 	clk_rate = clk_get_rate(priv->stmmac_clk);
 
 	/* Platform provided default clk_csr would be assumed valid
@@ -192,7 +189,6 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)
 	   * we can not estimate the proper divider as it is not known
 	   * the frequency of clk_csr_i. So we do not change the default
 	   * divider. */
-#endif
 }
 
 #if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG)
@@ -677,7 +673,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
 
 		priv->hw->desc->release_tx_desc(p);
 
-		entry = (++priv->dirty_tx) % txsize;
+		priv->dirty_tx++;
 	}
 	if (unlikely(netif_queue_stopped(priv->dev) &&
 		     stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) {
@@ -974,7 +970,7 @@ static int stmmac_open(struct net_device *dev)
 	} else
 		priv->tm->enable = 1;
 #endif
-	stmmac_clk_enable(priv);
+	clk_enable(priv->stmmac_clk);
 
 	stmmac_check_ether_addr(priv);
 
@@ -1078,7 +1074,7 @@ open_error:
 	if (priv->phydev)
 		phy_disconnect(priv->phydev);
 
-	stmmac_clk_disable(priv);
+	clk_disable(priv->stmmac_clk);
 
 	return ret;
 }
@@ -1131,7 +1127,7 @@ static int stmmac_release(struct net_device *dev)
 #ifdef CONFIG_STMMAC_DEBUG_FS
 	stmmac_exit_fs();
 #endif
-	stmmac_clk_disable(priv);
+	clk_disable(priv->stmmac_clk);
 
 	return 0;
 }
@@ -1308,7 +1304,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 		display_ring(priv->dma_rx, rxsize);
 	}
 #endif
-	count = 0;
 	while (!priv->hw->desc->get_rx_owner(p)) {
 		int status;
 
@@ -1927,11 +1922,14 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 	ret = register_netdev(ndev);
 	if (ret) {
 		pr_err("%s: ERROR %i registering the device\n", __func__, ret);
-		goto error;
+		goto error_netdev_register;
 	}
 
-	if (stmmac_clk_get(priv))
+	priv->stmmac_clk = clk_get(priv->device, NULL);
+	if (IS_ERR(priv->stmmac_clk)) {
 		pr_warning("%s: warning: cannot get CSR clock\n", __func__);
+		goto error_clk_get;
+	}
 
 	/* If a specific clk_csr value is passed from the platform
 	 * this means that the CSR Clock Range selection cannot be
@@ -1949,15 +1947,17 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 	if (ret < 0) {
 		pr_debug("%s: MDIO bus (id: %d) registration failed",
 			 __func__, priv->plat->bus_id);
-		goto error;
+		goto error_mdio_register;
 	}
 
 	return priv;
 
-error:
-	netif_napi_del(&priv->napi);
-
+error_mdio_register:
+	clk_put(priv->stmmac_clk);
+error_clk_get:
 	unregister_netdev(ndev);
+error_netdev_register:
+	netif_napi_del(&priv->napi);
 	free_netdev(ndev);
 
 	return NULL;
@@ -2026,7 +2026,7 @@ int stmmac_suspend(struct net_device *ndev)
 	else {
 		stmmac_set_mac(priv->ioaddr, false);
 		/* Disable clock in case of PWM is off */
-		stmmac_clk_disable(priv);
+		clk_disable(priv->stmmac_clk);
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 	return 0;
@@ -2051,7 +2051,7 @@ int stmmac_resume(struct net_device *ndev)
 		priv->hw->mac->pmt(priv->ioaddr, 0);
 	else
 		/* enable the clk prevously disabled */
-		stmmac_clk_enable(priv);
+		clk_enable(priv->stmmac_clk);
 
 	netif_device_attach(ndev);
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 680d2b8..20eb502 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -190,7 +190,7 @@ static int stmmac_pltfr_remove(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, NULL);
 
-	iounmap((void *)priv->ioaddr);
+	iounmap((void __force __iomem *)priv->ioaddr);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	release_mem_region(res->start, resource_size(res));
 
diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c
index 7d4a040..aeded7f 100644
--- a/drivers/net/ethernet/sun/sunqe.c
+++ b/drivers/net/ethernet/sun/sunqe.c
@@ -441,7 +441,7 @@ static void qe_rx(struct sunqe *qep)
 			} else {
 				skb_reserve(skb, 2);
 				skb_put(skb, len);
-				skb_copy_to_linear_data(skb, (unsigned char *) this_qbuf,
+				skb_copy_to_linear_data(skb, this_qbuf,
 						 len);
 				skb->protocol = eth_type_trans(skb, qep->dev);
 				netif_rx(skb);
diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c
index ea3e0a2..a46c198 100644
--- a/drivers/net/ethernet/via/via-velocity.c
+++ b/drivers/net/ethernet/via/via-velocity.c
@@ -486,7 +486,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
 	velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname);
 	velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname);
 	velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname);
-	velocity_set_int_opt((int *) &opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname);
+	velocity_set_int_opt(&opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname);
 	opts->numrx = (opts->numrx & ~3);
 }
 
diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c
index 4ad80f7..6695a1d 100644
--- a/drivers/net/fddi/defxx.c
+++ b/drivers/net/fddi/defxx.c
@@ -2962,7 +2962,7 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers)
 			bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP |
 				((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN));
 			bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX));
-			bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX));
+			bp->p_rcv_buff_va[i+j] = (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX));
 			}
 #endif
 	}
@@ -3030,7 +3030,7 @@ static void dfx_rcv_queue_process(
 #ifdef DYNAMIC_BUFFERS
 		p_buff = (char *) (((struct sk_buff *)bp->p_rcv_buff_va[entry])->data);
 #else
-		p_buff = (char *) bp->p_rcv_buff_va[entry];
+		p_buff = bp->p_rcv_buff_va[entry];
 #endif
 		memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32));
 
diff --git a/drivers/net/fddi/skfp/pmf.c b/drivers/net/fddi/skfp/pmf.c
index 9ac4665..24d8566 100644
--- a/drivers/net/fddi/skfp/pmf.c
+++ b/drivers/net/fddi/skfp/pmf.c
@@ -1242,7 +1242,7 @@ static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
 			if (len < 8)
 				goto len_error ;
 			if (set)
-				memcpy((char *) to,(char *) from+2,6) ;
+				memcpy(to,from+2,6) ;
 			to += 8 ;
 			from += 8 ;
 			len -= 8 ;
@@ -1251,7 +1251,7 @@ static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
 			if (len < 4)
 				goto len_error ;
 			if (set)
-				memcpy((char *) to,(char *) from,4) ;
+				memcpy(to,from,4) ;
 			to += 4 ;
 			from += 4 ;
 			len -= 4 ;
@@ -1260,7 +1260,7 @@ static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
 			if (len < 8)
 				goto len_error ;
 			if (set)
-				memcpy((char *) to,(char *) from,8) ;
+				memcpy(to,from,8) ;
 			to += 8 ;
 			from += 8 ;
 			len -= 8 ;
@@ -1269,7 +1269,7 @@ static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
 			if (len < 32)
 				goto len_error ;
 			if (set)
-				memcpy((char *) to,(char *) from,32) ;
+				memcpy(to,from,32) ;
 			to += 32 ;
 			from += 32 ;
 			len -= 32 ;
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index aed1a61..2c0894a 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -485,7 +485,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
 
 			return;
 		default:
-			count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
+			count = kiss_esc(p, ax->xbuff, len);
 		}
 	} else {
 		unsigned short crc;
@@ -497,7 +497,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
 		case CRC_MODE_SMACK:
 			*p |= 0x80;
 			crc = swab16(crc16(0, p, len));
-			count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2);
+			count = kiss_esc_crc(p, ax->xbuff, crc, len+2);
 			break;
 		case CRC_MODE_FLEX_TEST:
 			ax->crcmode = CRC_MODE_NONE;
@@ -506,11 +506,11 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
 		case CRC_MODE_FLEX:
 			*p |= 0x20;
 			crc = calc_crc_flex(p, len);
-			count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2);
+			count = kiss_esc_crc(p, ax->xbuff, crc, len+2);
 			break;
 
 		default:
-			count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
+			count = kiss_esc(p, ax->xbuff, len);
 		}
   	}
 	spin_unlock_bh(&ax->buflock);
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 0c56983..6cee291 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -614,7 +614,7 @@ retry_send_cmplt:
 static void netvsc_receive_completion(void *context)
 {
 	struct hv_netvsc_packet *packet = context;
-	struct hv_device *device = (struct hv_device *)packet->device;
+	struct hv_device *device = packet->device;
 	struct netvsc_device *net_device;
 	u64 transaction_id = 0;
 	bool fsend_receive_comp = false;
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index dcc80d6..8487204 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -1017,7 +1017,7 @@ static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud)
 {
 		
 	int iobase; 
-	struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv;
+	struct ali_ircc_cb *self = priv;
 	struct net_device *dev;
 
 	IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ );
@@ -1052,7 +1052,7 @@ static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud)
  */
 static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed)
 {
-	struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv;
+	struct ali_ircc_cb *self = priv;
 	unsigned long flags;
 	int iobase; 
 	int fcr;    /* FIFO control reg */
@@ -1121,7 +1121,7 @@ static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed)
 static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed)
 {
 	
-	struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv;
+	struct ali_ircc_cb *self = priv;
 	int iobase,dongle_id;
 	int tmp = 0;
 			
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index fc503aa..e09417d 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -794,7 +794,7 @@ static int __devinit au1k_irda_net_init(struct net_device *dev)
 
 	/* allocate the data buffers */
 	aup->db[0].vaddr =
-		(void *)dma_alloc(MAX_BUF_SIZE * 2 * NUM_IR_DESC, &temp);
+		dma_alloc(MAX_BUF_SIZE * 2 * NUM_IR_DESC, &temp);
 	if (!aup->db[0].vaddr)
 		goto out3;
 
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 2ee56de..0737bd4 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -847,13 +847,12 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb,
 			       const struct iovec *iv, unsigned long len,
 			       int noblock)
 {
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 	struct sk_buff *skb;
 	ssize_t ret = 0;
 
-	add_wait_queue(sk_sleep(&q->sk), &wait);
 	while (len) {
-		current->state = TASK_INTERRUPTIBLE;
+		prepare_to_wait(sk_sleep(&q->sk), &wait, TASK_INTERRUPTIBLE);
 
 		/* Read frames from the queue */
 		skb = skb_dequeue(&q->sk.sk_receive_queue);
@@ -875,8 +874,7 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb,
 		break;
 	}
 
-	current->state = TASK_RUNNING;
-	remove_wait_queue(sk_sleep(&q->sk), &wait);
+	finish_wait(sk_sleep(&q->sk), &wait);
 	return ret;
 }
 
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index 940b290..b0da022 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -17,6 +17,9 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/ethtool.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -453,16 +456,16 @@ static void enable_status_frames(struct phy_device *phydev, bool on)
 	ext_write(0, phydev, PAGE6, PSF_CFG1, ver);
 
 	if (!phydev->attached_dev) {
-		pr_warning("dp83640: expected to find an attached netdevice\n");
+		pr_warn("expected to find an attached netdevice\n");
 		return;
 	}
 
 	if (on) {
 		if (dev_mc_add(phydev->attached_dev, status_frame_dst))
-			pr_warning("dp83640: failed to add mc address\n");
+			pr_warn("failed to add mc address\n");
 	} else {
 		if (dev_mc_del(phydev->attached_dev, status_frame_dst))
-			pr_warning("dp83640: failed to delete mc address\n");
+			pr_warn("failed to delete mc address\n");
 	}
 }
 
@@ -582,9 +585,9 @@ static void recalibrate(struct dp83640_clock *clock)
 	 * read out and correct offsets
 	 */
 	val = ext_read(master, PAGE4, PTP_STS);
-	pr_info("master PTP_STS  0x%04hx", val);
+	pr_info("master PTP_STS  0x%04hx\n", val);
 	val = ext_read(master, PAGE4, PTP_ESTS);
-	pr_info("master PTP_ESTS 0x%04hx", val);
+	pr_info("master PTP_ESTS 0x%04hx\n", val);
 	event_ts.ns_lo  = ext_read(master, PAGE4, PTP_EDATA);
 	event_ts.ns_hi  = ext_read(master, PAGE4, PTP_EDATA);
 	event_ts.sec_lo = ext_read(master, PAGE4, PTP_EDATA);
@@ -594,9 +597,9 @@ static void recalibrate(struct dp83640_clock *clock)
 	list_for_each(this, &clock->phylist) {
 		tmp = list_entry(this, struct dp83640_private, list);
 		val = ext_read(tmp->phydev, PAGE4, PTP_STS);
-		pr_info("slave  PTP_STS  0x%04hx", val);
+		pr_info("slave  PTP_STS  0x%04hx\n", val);
 		val = ext_read(tmp->phydev, PAGE4, PTP_ESTS);
-		pr_info("slave  PTP_ESTS 0x%04hx", val);
+		pr_info("slave  PTP_ESTS 0x%04hx\n", val);
 		event_ts.ns_lo  = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
 		event_ts.ns_hi  = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
 		event_ts.sec_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
@@ -686,7 +689,7 @@ static void decode_rxts(struct dp83640_private *dp83640,
 	prune_rx_ts(dp83640);
 
 	if (list_empty(&dp83640->rxpool)) {
-		pr_debug("dp83640: rx timestamp pool is empty\n");
+		pr_debug("rx timestamp pool is empty\n");
 		goto out;
 	}
 	rxts = list_first_entry(&dp83640->rxpool, struct rxts, list);
@@ -709,7 +712,7 @@ static void decode_txts(struct dp83640_private *dp83640,
 	skb = skb_dequeue(&dp83640->tx_queue);
 
 	if (!skb) {
-		pr_debug("dp83640: have timestamp but tx_queue empty\n");
+		pr_debug("have timestamp but tx_queue empty\n");
 		return;
 	}
 	ns = phy2txts(phy_txts);
@@ -847,7 +850,7 @@ static void dp83640_free_clocks(void)
 	list_for_each_safe(this, next, &phyter_clocks) {
 		clock = list_entry(this, struct dp83640_clock, list);
 		if (!list_empty(&clock->phylist)) {
-			pr_warning("phy list non-empty while unloading");
+			pr_warn("phy list non-empty while unloading\n");
 			BUG();
 		}
 		list_del(&clock->list);
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index 633680d..ba55adf 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -70,7 +70,7 @@ static int fixed_phy_update_regs(struct fixed_phy *fp)
 			lpa |= LPA_10FULL;
 			break;
 		default:
-			printk(KERN_WARNING "fixed phy: unknown speed\n");
+			pr_warn("fixed phy: unknown speed\n");
 			return -EINVAL;
 		}
 	} else {
@@ -90,7 +90,7 @@ static int fixed_phy_update_regs(struct fixed_phy *fp)
 			lpa |= LPA_10HALF;
 			break;
 		default:
-			printk(KERN_WARNING "fixed phy: unknown speed\n");
+			pr_warn("fixed phy: unknown speed\n");
 			return -EINVAL;
 		}
 	}
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 5061608..31470b0 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -13,6 +13,9 @@
  * option) any later version.
  *
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
@@ -148,7 +151,7 @@ int mdiobus_register(struct mii_bus *bus)
 
 	err = device_register(&bus->dev);
 	if (err) {
-		printk(KERN_ERR "mii_bus %s failed to register\n", bus->id);
+		pr_err("mii_bus %s failed to register\n", bus->id);
 		return -EINVAL;
 	}
 
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 590f902..9d6c80c 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -161,7 +161,7 @@ static struct phy_driver ks8051_driver = {
 static struct phy_driver ks8001_driver = {
 	.phy_id		= PHY_ID_KS8001,
 	.name		= "Micrel KS8001 or KS8721",
-	.phy_id_mask	= 0x00fffff0,
+	.phy_id_mask	= 0x00ffffff,
 	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 	.config_init	= kszphy_config_init,
@@ -174,7 +174,7 @@ static struct phy_driver ks8001_driver = {
 
 static struct phy_driver ksz9021_driver = {
 	.phy_id		= PHY_ID_KSZ9021,
-	.phy_id_mask	= 0x000fff10,
+	.phy_id_mask	= 0x000ffffe,
 	.name		= "Micrel KSZ9021 Gigabit PHY",
 	.features	= (PHY_GBIT_FEATURES | SUPPORTED_Pause
 				| SUPPORTED_Asym_Pause),
@@ -240,8 +240,8 @@ MODULE_AUTHOR("David J. Choi");
 MODULE_LICENSE("GPL");
 
 static struct mdio_device_id __maybe_unused micrel_tbl[] = {
-	{ PHY_ID_KSZ9021, 0x000fff10 },
-	{ PHY_ID_KS8001, 0x00fffff0 },
+	{ PHY_ID_KSZ9021, 0x000ffffe },
+	{ PHY_ID_KS8001, 0x00ffffff },
 	{ PHY_ID_KS8737, 0x00fffff0 },
 	{ PHY_ID_KS8041, 0x00fffff0 },
 	{ PHY_ID_KS8051, 0x00fffff0 },
diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c
index 04bb8fc..9a5f234 100644
--- a/drivers/net/phy/national.c
+++ b/drivers/net/phy/national.c
@@ -15,6 +15,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mii.h>
@@ -22,6 +24,8 @@
 #include <linux/phy.h>
 #include <linux/netdevice.h>
 
+#define DEBUG
+
 /* DP83865 phy identifier values */
 #define DP83865_PHY_ID	0x20005c7a
 
@@ -112,8 +116,8 @@ static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable)
 		ns_exp_write(phydev, 0x1c0,
 			     ns_exp_read(phydev, 0x1c0) & 0xfffe);
 
-	printk(KERN_DEBUG "DP83865 PHY: 10BASE-T HDX loopback %s\n",
-	       (ns_exp_read(phydev, 0x1c0) & 0x0001) ? "off" : "on");
+	pr_debug("10BASE-T HDX loopback %s\n",
+		 (ns_exp_read(phydev, 0x1c0) & 0x0001) ? "off" : "on");
 }
 
 static int ns_config_init(struct phy_device *phydev)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 3cbda08..2e1c237 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -15,6 +15,9 @@
  * option) any later version.
  *
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
@@ -44,18 +47,16 @@
  */
 void phy_print_status(struct phy_device *phydev)
 {
-	pr_info("PHY: %s - Link is %s", dev_name(&phydev->dev),
-			phydev->link ? "Up" : "Down");
 	if (phydev->link)
-		printk(KERN_CONT " - %d/%s", phydev->speed,
-				DUPLEX_FULL == phydev->duplex ?
-				"Full" : "Half");
-
-	printk(KERN_CONT "\n");
+		pr_info("%s - Link is Up - %d/%s\n",
+			dev_name(&phydev->dev),
+			phydev->speed,
+			DUPLEX_FULL == phydev->duplex ? "Full" : "Half");
+	else
+		pr_info("%s - Link is Down\n", dev_name(&phydev->dev));
 }
 EXPORT_SYMBOL(phy_print_status);
 
-
 /**
  * phy_clear_interrupt - Ack the phy device's interrupt
  * @phydev: the phy_device struct
@@ -482,9 +483,8 @@ static void phy_force_reduction(struct phy_device *phydev)
 	phydev->speed = settings[idx].speed;
 	phydev->duplex = settings[idx].duplex;
 
-	pr_info("Trying %d/%s\n", phydev->speed,
-			DUPLEX_FULL == phydev->duplex ?
-			"FULL" : "HALF");
+	pr_info("Trying %d/%s\n",
+		phydev->speed, DUPLEX_FULL == phydev->duplex ? "FULL" : "HALF");
 }
 
 
@@ -598,9 +598,8 @@ int phy_start_interrupts(struct phy_device *phydev)
 				IRQF_SHARED,
 				"phy_interrupt",
 				phydev) < 0) {
-		printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n",
-				phydev->bus->name,
-				phydev->irq);
+		pr_warn("%s: Can't get IRQ %d (PHY)\n",
+			phydev->bus->name, phydev->irq);
 		phydev->irq = PHY_POLL;
 		return 0;
 	}
@@ -838,10 +837,10 @@ void phy_state_machine(struct work_struct *work)
 
 				phydev->autoneg = AUTONEG_DISABLE;
 
-				pr_info("Trying %d/%s\n", phydev->speed,
-						DUPLEX_FULL ==
-						phydev->duplex ?
-						"FULL" : "HALF");
+				pr_info("Trying %d/%s\n",
+					phydev->speed,
+					DUPLEX_FULL == phydev->duplex ?
+					"FULL" : "HALF");
 			}
 			break;
 		case PHY_NOLINK:
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index de86a55..18ab0da 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -14,6 +14,9 @@
  * option) any later version.
  *
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
@@ -975,8 +978,8 @@ int phy_driver_register(struct phy_driver *new_driver)
 	retval = driver_register(&new_driver->driver);
 
 	if (retval) {
-		printk(KERN_ERR "%s: Error %d in registering driver\n",
-				new_driver->name, retval);
+		pr_err("%s: Error %d in registering driver\n",
+		       new_driver->name, retval);
 
 		return retval;
 	}
diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c
index 4eb98bc..1c3abce 100644
--- a/drivers/net/phy/spi_ks8995.c
+++ b/drivers/net/phy/spi_ks8995.c
@@ -11,6 +11,8 @@
  * by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -356,7 +358,7 @@ static struct spi_driver ks8995_driver = {
 
 static int __init ks8995_init(void)
 {
-	printk(KERN_INFO DRV_DESC " version " DRV_VERSION"\n");
+	pr_info(DRV_DESC " version " DRV_VERSION "\n");
 
 	return spi_register_driver(&ks8995_driver);
 }
diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c
index d4c9db3..a34d6bf 100644
--- a/drivers/net/slip/slip.c
+++ b/drivers/net/slip/slip.c
@@ -390,10 +390,10 @@ static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
 #endif
 #ifdef CONFIG_SLIP_MODE_SLIP6
 	if (sl->mode & SL_MODE_SLIP6)
-		count = slip_esc6(p, (unsigned char *) sl->xbuff, len);
+		count = slip_esc6(p, sl->xbuff, len);
 	else
 #endif
-		count = slip_esc(p, (unsigned char *) sl->xbuff, len);
+		count = slip_esc(p, sl->xbuff, len);
 
 	/* Order of next two lines is *very* important.
 	 * When we are sending a little amount of data,
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index c61ae35..3a4a74b 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1,5 +1,5 @@
 /*
- * net/drivers/team/team.c - Network team device driver
+ * drivers/net/team/team.c - Network team device driver
  * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -82,14 +82,16 @@ static void team_refresh_port_linkup(struct team_port *port)
 						   port->state.linkup;
 }
 
+
 /*******************
  * Options handling
  *******************/
 
 struct team_option_inst { /* One for each option instance */
 	struct list_head list;
+	struct list_head tmp_list;
 	struct team_option *option;
-	struct team_port *port; /* != NULL if per-port */
+	struct team_option_inst_info info;
 	bool changed;
 	bool removed;
 };
@@ -106,22 +108,6 @@ static struct team_option *__team_find_option(struct team *team,
 	return NULL;
 }
 
-static int __team_option_inst_add(struct team *team, struct team_option *option,
-				  struct team_port *port)
-{
-	struct team_option_inst *opt_inst;
-
-	opt_inst = kmalloc(sizeof(*opt_inst), GFP_KERNEL);
-	if (!opt_inst)
-		return -ENOMEM;
-	opt_inst->option = option;
-	opt_inst->port = port;
-	opt_inst->changed = true;
-	opt_inst->removed = false;
-	list_add_tail(&opt_inst->list, &team->option_inst_list);
-	return 0;
-}
-
 static void __team_option_inst_del(struct team_option_inst *opt_inst)
 {
 	list_del(&opt_inst->list);
@@ -139,14 +125,49 @@ static void __team_option_inst_del_option(struct team *team,
 	}
 }
 
+static int __team_option_inst_add(struct team *team, struct team_option *option,
+				  struct team_port *port)
+{
+	struct team_option_inst *opt_inst;
+	unsigned int array_size;
+	unsigned int i;
+	int err;
+
+	array_size = option->array_size;
+	if (!array_size)
+		array_size = 1; /* No array but still need one instance */
+
+	for (i = 0; i < array_size; i++) {
+		opt_inst = kmalloc(sizeof(*opt_inst), GFP_KERNEL);
+		if (!opt_inst)
+			return -ENOMEM;
+		opt_inst->option = option;
+		opt_inst->info.port = port;
+		opt_inst->info.array_index = i;
+		opt_inst->changed = true;
+		opt_inst->removed = false;
+		list_add_tail(&opt_inst->list, &team->option_inst_list);
+		if (option->init) {
+			err = option->init(team, &opt_inst->info);
+			if (err)
+				return err;
+		}
+
+	}
+	return 0;
+}
+
 static int __team_option_inst_add_option(struct team *team,
 					 struct team_option *option)
 {
 	struct team_port *port;
 	int err;
 
-	if (!option->per_port)
-		return __team_option_inst_add(team, option, 0);
+	if (!option->per_port) {
+		err = __team_option_inst_add(team, option, NULL);
+		if (err)
+			goto inst_del_option;
+	}
 
 	list_for_each_entry(port, &team->port_list, list) {
 		err = __team_option_inst_add(team, option, port);
@@ -180,7 +201,7 @@ static void __team_option_inst_del_port(struct team *team,
 
 	list_for_each_entry_safe(opt_inst, tmp, &team->option_inst_list, list) {
 		if (opt_inst->option->per_port &&
-		    opt_inst->port == port)
+		    opt_inst->info.port == port)
 			__team_option_inst_del(opt_inst);
 	}
 }
@@ -211,7 +232,7 @@ static void __team_option_inst_mark_removed_port(struct team *team,
 	struct team_option_inst *opt_inst;
 
 	list_for_each_entry(opt_inst, &team->option_inst_list, list) {
-		if (opt_inst->port == port) {
+		if (opt_inst->info.port == port) {
 			opt_inst->changed = true;
 			opt_inst->removed = true;
 		}
@@ -324,28 +345,12 @@ void team_options_unregister(struct team *team,
 }
 EXPORT_SYMBOL(team_options_unregister);
 
-static int team_option_port_add(struct team *team, struct team_port *port)
-{
-	int err;
-
-	err = __team_option_inst_add_port(team, port);
-	if (err)
-		return err;
-	__team_options_change_check(team);
-	return 0;
-}
-
-static void team_option_port_del(struct team *team, struct team_port *port)
-{
-	__team_option_inst_mark_removed_port(team, port);
-	__team_options_change_check(team);
-	__team_option_inst_del_port(team, port);
-}
-
 static int team_option_get(struct team *team,
 			   struct team_option_inst *opt_inst,
 			   struct team_gsetter_ctx *ctx)
 {
+	if (!opt_inst->option->getter)
+		return -EOPNOTSUPP;
 	return opt_inst->option->getter(team, ctx);
 }
 
@@ -353,16 +358,26 @@ static int team_option_set(struct team *team,
 			   struct team_option_inst *opt_inst,
 			   struct team_gsetter_ctx *ctx)
 {
-	int err;
+	if (!opt_inst->option->setter)
+		return -EOPNOTSUPP;
+	return opt_inst->option->setter(team, ctx);
+}
 
-	err = opt_inst->option->setter(team, ctx);
-	if (err)
-		return err;
+void team_option_inst_set_change(struct team_option_inst_info *opt_inst_info)
+{
+	struct team_option_inst *opt_inst;
 
+	opt_inst = container_of(opt_inst_info, struct team_option_inst, info);
 	opt_inst->changed = true;
+}
+EXPORT_SYMBOL(team_option_inst_set_change);
+
+void team_options_change_check(struct team *team)
+{
 	__team_options_change_check(team);
-	return err;
 }
+EXPORT_SYMBOL(team_options_change_check);
+
 
 /****************
  * Mode handling
@@ -371,13 +386,18 @@ static int team_option_set(struct team *team,
 static LIST_HEAD(mode_list);
 static DEFINE_SPINLOCK(mode_list_lock);
 
-static struct team_mode *__find_mode(const char *kind)
+struct team_mode_item {
+	struct list_head list;
+	const struct team_mode *mode;
+};
+
+static struct team_mode_item *__find_mode(const char *kind)
 {
-	struct team_mode *mode;
+	struct team_mode_item *mitem;
 
-	list_for_each_entry(mode, &mode_list, list) {
-		if (strcmp(mode->kind, kind) == 0)
-			return mode;
+	list_for_each_entry(mitem, &mode_list, list) {
+		if (strcmp(mitem->mode->kind, kind) == 0)
+			return mitem;
 	}
 	return NULL;
 }
@@ -392,49 +412,65 @@ static bool is_good_mode_name(const char *name)
 	return true;
 }
 
-int team_mode_register(struct team_mode *mode)
+int team_mode_register(const struct team_mode *mode)
 {
 	int err = 0;
+	struct team_mode_item *mitem;
 
 	if (!is_good_mode_name(mode->kind) ||
 	    mode->priv_size > TEAM_MODE_PRIV_SIZE)
 		return -EINVAL;
+
+	mitem = kmalloc(sizeof(*mitem), GFP_KERNEL);
+	if (!mitem)
+		return -ENOMEM;
+
 	spin_lock(&mode_list_lock);
 	if (__find_mode(mode->kind)) {
 		err = -EEXIST;
+		kfree(mitem);
 		goto unlock;
 	}
-	list_add_tail(&mode->list, &mode_list);
+	mitem->mode = mode;
+	list_add_tail(&mitem->list, &mode_list);
 unlock:
 	spin_unlock(&mode_list_lock);
 	return err;
 }
 EXPORT_SYMBOL(team_mode_register);
 
-int team_mode_unregister(struct team_mode *mode)
+void team_mode_unregister(const struct team_mode *mode)
 {
+	struct team_mode_item *mitem;
+
 	spin_lock(&mode_list_lock);
-	list_del_init(&mode->list);
+	mitem = __find_mode(mode->kind);
+	if (mitem) {
+		list_del_init(&mitem->list);
+		kfree(mitem);
+	}
 	spin_unlock(&mode_list_lock);
-	return 0;
 }
 EXPORT_SYMBOL(team_mode_unregister);
 
-static struct team_mode *team_mode_get(const char *kind)
+static const struct team_mode *team_mode_get(const char *kind)
 {
-	struct team_mode *mode;
+	struct team_mode_item *mitem;
+	const struct team_mode *mode = NULL;
 
 	spin_lock(&mode_list_lock);
-	mode = __find_mode(kind);
-	if (!mode) {
+	mitem = __find_mode(kind);
+	if (!mitem) {
 		spin_unlock(&mode_list_lock);
 		request_module("team-mode-%s", kind);
 		spin_lock(&mode_list_lock);
-		mode = __find_mode(kind);
+		mitem = __find_mode(kind);
 	}
-	if (mode)
+	if (mitem) {
+		mode = mitem->mode;
 		if (!try_module_get(mode->owner))
 			mode = NULL;
+	}
 
 	spin_unlock(&mode_list_lock);
 	return mode;
@@ -458,6 +494,20 @@ rx_handler_result_t team_dummy_receive(struct team *team,
 	return RX_HANDLER_ANOTHER;
 }
 
+static const struct team_mode __team_no_mode = {
+	.kind		= "*NOMODE*",
+};
+
+static bool team_is_mode_set(struct team *team)
+{
+	return team->mode != &__team_no_mode;
+}
+
+static void team_set_no_mode(struct team *team)
+{
+	team->mode = &__team_no_mode;
+}
+
 static void team_adjust_ops(struct team *team)
 {
 	/*
@@ -466,13 +516,13 @@ static void team_adjust_ops(struct team *team)
 	 */
 
 	if (list_empty(&team->port_list) ||
-	    !team->mode || !team->mode->ops->transmit)
+	    !team_is_mode_set(team) || !team->mode->ops->transmit)
 		team->ops.transmit = team_dummy_transmit;
 	else
 		team->ops.transmit = team->mode->ops->transmit;
 
 	if (list_empty(&team->port_list) ||
-	    !team->mode || !team->mode->ops->receive)
+	    !team_is_mode_set(team) || !team->mode->ops->receive)
 		team->ops.receive = team_dummy_receive;
 	else
 		team->ops.receive = team->mode->ops->receive;
@@ -487,7 +537,7 @@ static int __team_change_mode(struct team *team,
 			      const struct team_mode *new_mode)
 {
 	/* Check if mode was previously set and do cleanup if so */
-	if (team->mode) {
+	if (team_is_mode_set(team)) {
 		void (*exit_op)(struct team *team) = team->ops.exit;
 
 		/* Clear ops area so no callback is called any longer */
@@ -497,7 +547,7 @@ static int __team_change_mode(struct team *team,
 		if (exit_op)
 			exit_op(team);
 		team_mode_put(team->mode);
-		team->mode = NULL;
+		team_set_no_mode(team);
 		/* zero private data area */
 		memset(&team->mode_priv, 0,
 		       sizeof(struct team) - offsetof(struct team, mode_priv));
@@ -523,7 +573,7 @@ static int __team_change_mode(struct team *team,
 
 static int team_change_mode(struct team *team, const char *kind)
 {
-	struct team_mode *new_mode;
+	const struct team_mode *new_mode;
 	struct net_device *dev = team->dev;
 	int err;
 
@@ -532,7 +582,7 @@ static int team_change_mode(struct team *team, const char *kind)
 		return -EBUSY;
 	}
 
-	if (team->mode && strcmp(team->mode->kind, kind) == 0) {
+	if (team_is_mode_set(team) && strcmp(team->mode->kind, kind) == 0) {
 		netdev_err(dev, "Unable to change to the same mode the team is in\n");
 		return -EINVAL;
 	}
@@ -637,6 +687,8 @@ static void team_port_enable(struct team *team,
 	port->index = team->en_port_count++;
 	hlist_add_head_rcu(&port->hlist,
 			   team_port_index_hash(team, port->index));
+	if (team->ops.port_enabled)
+		team->ops.port_enabled(team, port);
 }
 
 static void __reconstruct_port_hlist(struct team *team, int rm_index)
@@ -660,6 +712,8 @@ static void team_port_disable(struct team *team,
 
 	if (!team_port_enabled(port))
 		return;
+	if (team->ops.port_disabled)
+		team->ops.port_disabled(team, port);
 	hlist_del_rcu(&port->hlist);
 	__reconstruct_port_hlist(team, rm_index);
 	team->en_port_count--;
@@ -758,7 +812,8 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
 		return -EBUSY;
 	}
 
-	port = kzalloc(sizeof(struct team_port), GFP_KERNEL);
+	port = kzalloc(sizeof(struct team_port) + team->mode->port_priv_size,
+		       GFP_KERNEL);
 	if (!port)
 		return -ENOMEM;
 
@@ -809,7 +864,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
 		goto err_handler_register;
 	}
 
-	err = team_option_port_add(team, port);
+	err = __team_option_inst_add_port(team, port);
 	if (err) {
 		netdev_err(dev, "Device %s failed to add per-port options\n",
 			   portname);
@@ -822,6 +877,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
 	team_adjust_ops(team);
 	__team_compute_features(team);
 	__team_port_change_check(port, !!netif_carrier_ok(port_dev));
+	__team_options_change_check(team);
 
 	netdev_info(dev, "Port device %s added\n", portname);
 
@@ -865,12 +921,14 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
 		return -ENOENT;
 	}
 
+	__team_option_inst_mark_removed_port(team, port);
+	__team_options_change_check(team);
+	__team_option_inst_del_port(team, port);
 	port->removed = true;
 	__team_port_change_check(port, false);
 	team_port_disable(team, port);
 	list_del_rcu(&port->list);
 	team_adjust_ops(team);
-	team_option_port_del(team, port);
 	netdev_rx_handler_unregister(port_dev);
 	netdev_set_master(port_dev, NULL);
 	vlan_vids_del_by_dev(port_dev, dev);
@@ -891,11 +949,9 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
  * Net device ops
  *****************/
 
-static const char team_no_mode_kind[] = "*NOMODE*";
-
 static int team_mode_option_get(struct team *team, struct team_gsetter_ctx *ctx)
 {
-	ctx->data.str_val = team->mode ? team->mode->kind : team_no_mode_kind;
+	ctx->data.str_val = team->mode->kind;
 	return 0;
 }
 
@@ -907,39 +963,47 @@ static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx)
 static int team_port_en_option_get(struct team *team,
 				   struct team_gsetter_ctx *ctx)
 {
-	ctx->data.bool_val = team_port_enabled(ctx->port);
+	struct team_port *port = ctx->info->port;
+
+	ctx->data.bool_val = team_port_enabled(port);
 	return 0;
 }
 
 static int team_port_en_option_set(struct team *team,
 				   struct team_gsetter_ctx *ctx)
 {
+	struct team_port *port = ctx->info->port;
+
 	if (ctx->data.bool_val)
-		team_port_enable(team, ctx->port);
+		team_port_enable(team, port);
 	else
-		team_port_disable(team, ctx->port);
+		team_port_disable(team, port);
 	return 0;
 }
 
 static int team_user_linkup_option_get(struct team *team,
 				       struct team_gsetter_ctx *ctx)
 {
-	ctx->data.bool_val = ctx->port->user.linkup;
+	struct team_port *port = ctx->info->port;
+
+	ctx->data.bool_val = port->user.linkup;
 	return 0;
 }
 
 static int team_user_linkup_option_set(struct team *team,
 				       struct team_gsetter_ctx *ctx)
 {
-	ctx->port->user.linkup = ctx->data.bool_val;
-	team_refresh_port_linkup(ctx->port);
+	struct team_port *port = ctx->info->port;
+
+	port->user.linkup = ctx->data.bool_val;
+	team_refresh_port_linkup(port);
 	return 0;
 }
 
 static int team_user_linkup_en_option_get(struct team *team,
 					  struct team_gsetter_ctx *ctx)
 {
-	struct team_port *port = ctx->port;
+	struct team_port *port = ctx->info->port;
 
 	ctx->data.bool_val = port->user.linkup_enabled;
 	return 0;
@@ -948,10 +1012,10 @@ static int team_user_linkup_en_option_get(struct team *team,
 static int team_user_linkup_en_option_set(struct team *team,
 					  struct team_gsetter_ctx *ctx)
 {
-	struct team_port *port = ctx->port;
+	struct team_port *port = ctx->info->port;
 
 	port->user.linkup_enabled = ctx->data.bool_val;
-	team_refresh_port_linkup(ctx->port);
+	team_refresh_port_linkup(port);
 	return 0;
 }
 
@@ -993,6 +1057,7 @@ static int team_init(struct net_device *dev)
 
 	team->dev = dev;
 	mutex_init(&team->lock);
+	team_set_no_mode(team);
 
 	team->pcpu_stats = alloc_percpu(struct team_pcpu_stats);
 	if (!team->pcpu_stats)
@@ -1482,16 +1547,128 @@ err_fill:
 	return err;
 }
 
-static int team_nl_fill_options_get(struct sk_buff *skb,
-				    u32 pid, u32 seq, int flags,
-				    struct team *team, bool fillall)
+typedef int team_nl_send_func_t(struct sk_buff *skb,
+				struct team *team, u32 pid);
+
+static int team_nl_send_unicast(struct sk_buff *skb, struct team *team, u32 pid)
+{
+	return genlmsg_unicast(dev_net(team->dev), skb, pid);
+}
+
+static int team_nl_fill_one_option_get(struct sk_buff *skb, struct team *team,
+				       struct team_option_inst *opt_inst)
+{
+	struct nlattr *option_item;
+	struct team_option *option = opt_inst->option;
+	struct team_option_inst_info *opt_inst_info = &opt_inst->info;
+	struct team_gsetter_ctx ctx;
+	int err;
+
+	ctx.info = opt_inst_info;
+	err = team_option_get(team, opt_inst, &ctx);
+	if (err)
+		return err;
+
+	option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION);
+	if (!option_item)
+		return -EMSGSIZE;
+
+	if (nla_put_string(skb, TEAM_ATTR_OPTION_NAME, option->name))
+		goto nest_cancel;
+	if (opt_inst_info->port &&
+	    nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX,
+			opt_inst_info->port->dev->ifindex))
+		goto nest_cancel;
+	if (opt_inst->option->array_size &&
+	    nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX,
+			opt_inst_info->array_index))
+		goto nest_cancel;
+
+	switch (option->type) {
+	case TEAM_OPTION_TYPE_U32:
+		if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32))
+			goto nest_cancel;
+		if (nla_put_u32(skb, TEAM_ATTR_OPTION_DATA, ctx.data.u32_val))
+			goto nest_cancel;
+		break;
+	case TEAM_OPTION_TYPE_STRING:
+		if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING))
+			goto nest_cancel;
+		if (nla_put_string(skb, TEAM_ATTR_OPTION_DATA,
+				   ctx.data.str_val))
+			goto nest_cancel;
+		break;
+	case TEAM_OPTION_TYPE_BINARY:
+		if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_BINARY))
+			goto nest_cancel;
+		if (nla_put(skb, TEAM_ATTR_OPTION_DATA, ctx.data.bin_val.len,
+			    ctx.data.bin_val.ptr))
+			goto nest_cancel;
+		break;
+	case TEAM_OPTION_TYPE_BOOL:
+		if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_FLAG))
+			goto nest_cancel;
+		if (ctx.data.bool_val &&
+		    nla_put_flag(skb, TEAM_ATTR_OPTION_DATA))
+			goto nest_cancel;
+		break;
+	default:
+		BUG();
+	}
+	if (opt_inst->removed && nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED))
+		goto nest_cancel;
+	if (opt_inst->changed) {
+		if (nla_put_flag(skb, TEAM_ATTR_OPTION_CHANGED))
+			goto nest_cancel;
+		opt_inst->changed = false;
+	}
+	nla_nest_end(skb, option_item);
+	return 0;
+
+nest_cancel:
+	nla_nest_cancel(skb, option_item);
+	return -EMSGSIZE;
+}
+
+static int __send_and_alloc_skb(struct sk_buff **pskb,
+				struct team *team, u32 pid,
+				team_nl_send_func_t *send_func)
+{
+	int err;
+
+	if (*pskb) {
+		err = send_func(*pskb, team, pid);
+		if (err)
+			return err;
+	}
+	*pskb = genlmsg_new(NLMSG_DEFAULT_SIZE - GENL_HDRLEN, GFP_KERNEL);
+	if (!*pskb)
+		return -ENOMEM;
+	return 0;
+}
+
+static int team_nl_send_options_get(struct team *team, u32 pid, u32 seq,
+				    int flags, team_nl_send_func_t *send_func,
+				    struct list_head *sel_opt_inst_list)
 {
 	struct nlattr *option_list;
+	struct nlmsghdr *nlh;
 	void *hdr;
 	struct team_option_inst *opt_inst;
 	int err;
+	struct sk_buff *skb = NULL;
+	bool incomplete;
+	int i;
 
-	hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
+	opt_inst = list_first_entry(sel_opt_inst_list,
+				    struct team_option_inst, tmp_list);
+
+start_again:
+	err = __send_and_alloc_skb(&skb, team, pid, send_func);
+	if (err)
+		return err;
+
+	hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags | NLM_F_MULTI,
 			  TEAM_CMD_OPTIONS_GET);
 	if (IS_ERR(hdr))
 		return PTR_ERR(hdr);
@@ -1500,122 +1677,80 @@ static int team_nl_fill_options_get(struct sk_buff *skb,
 		goto nla_put_failure;
 	option_list = nla_nest_start(skb, TEAM_ATTR_LIST_OPTION);
 	if (!option_list)
-		return -EMSGSIZE;
-
-	list_for_each_entry(opt_inst, &team->option_inst_list, list) {
-		struct nlattr *option_item;
-		struct team_option *option = opt_inst->option;
-		struct team_gsetter_ctx ctx;
+		goto nla_put_failure;
 
-		/* Include only changed options if fill all mode is not on */
-		if (!fillall && !opt_inst->changed)
-			continue;
-		option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION);
-		if (!option_item)
-			goto nla_put_failure;
-		if (nla_put_string(skb, TEAM_ATTR_OPTION_NAME, option->name))
-			goto nla_put_failure;
-		if (opt_inst->changed) {
-			if (nla_put_flag(skb, TEAM_ATTR_OPTION_CHANGED))
-				goto nla_put_failure;
-			opt_inst->changed = false;
-		}
-		if (opt_inst->removed &&
-		    nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED))
-			goto nla_put_failure;
-		if (opt_inst->port &&
-		    nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX,
-				opt_inst->port->dev->ifindex))
-			goto nla_put_failure;
-		ctx.port = opt_inst->port;
-		switch (option->type) {
-		case TEAM_OPTION_TYPE_U32:
-			if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32))
-				goto nla_put_failure;
-			err = team_option_get(team, opt_inst, &ctx);
-			if (err)
-				goto errout;
-			if (nla_put_u32(skb, TEAM_ATTR_OPTION_DATA,
-					ctx.data.u32_val))
-				goto nla_put_failure;
-			break;
-		case TEAM_OPTION_TYPE_STRING:
-			if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING))
-				goto nla_put_failure;
-			err = team_option_get(team, opt_inst, &ctx);
-			if (err)
-				goto errout;
-			if (nla_put_string(skb, TEAM_ATTR_OPTION_DATA,
-					   ctx.data.str_val))
-				goto nla_put_failure;
-			break;
-		case TEAM_OPTION_TYPE_BINARY:
-			if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_BINARY))
-				goto nla_put_failure;
-			err = team_option_get(team, opt_inst, &ctx);
-			if (err)
-				goto errout;
-			if (nla_put(skb, TEAM_ATTR_OPTION_DATA,
-				    ctx.data.bin_val.len, ctx.data.bin_val.ptr))
-				goto nla_put_failure;
-			break;
-		case TEAM_OPTION_TYPE_BOOL:
-			if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_FLAG))
-				goto nla_put_failure;
-			err = team_option_get(team, opt_inst, &ctx);
-			if (err)
-				goto errout;
-			if (ctx.data.bool_val &&
-			    nla_put_flag(skb, TEAM_ATTR_OPTION_DATA))
-				goto nla_put_failure;
-			break;
-		default:
-			BUG();
+	i = 0;
+	incomplete = false;
+	list_for_each_entry_from(opt_inst, sel_opt_inst_list, tmp_list) {
+		err = team_nl_fill_one_option_get(skb, team, opt_inst);
+		if (err) {
+			if (err == -EMSGSIZE) {
+				if (!i)
+					goto errout;
+				incomplete = true;
+				break;
+			}
+			goto errout;
 		}
-		nla_nest_end(skb, option_item);
+		i++;
 	}
 
 	nla_nest_end(skb, option_list);
-	return genlmsg_end(skb, hdr);
+	genlmsg_end(skb, hdr);
+	if (incomplete)
+		goto start_again;
+
+send_done:
+	nlh = nlmsg_put(skb, pid, seq, NLMSG_DONE, 0, flags | NLM_F_MULTI);
+	if (!nlh) {
+		err = __send_and_alloc_skb(&skb, team, pid, send_func);
+		if (err)
+			goto errout;
+		goto send_done;
+	}
+
+	return send_func(skb, team, pid);
 
 nla_put_failure:
 	err = -EMSGSIZE;
 errout:
 	genlmsg_cancel(skb, hdr);
+	nlmsg_free(skb);
 	return err;
 }
 
-static int team_nl_fill_options_get_all(struct sk_buff *skb,
-					struct genl_info *info, int flags,
-					struct team *team)
-{
-	return team_nl_fill_options_get(skb, info->snd_pid,
-					info->snd_seq, NLM_F_ACK,
-					team, true);
-}
-
 static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info)
 {
 	struct team *team;
+	struct team_option_inst *opt_inst;
 	int err;
+	LIST_HEAD(sel_opt_inst_list);
 
 	team = team_nl_team_get(info);
 	if (!team)
 		return -EINVAL;
 
-	err = team_nl_send_generic(info, team, team_nl_fill_options_get_all);
+	list_for_each_entry(opt_inst, &team->option_inst_list, list)
+		list_add_tail(&opt_inst->tmp_list, &sel_opt_inst_list);
+	err = team_nl_send_options_get(team, info->snd_pid, info->snd_seq,
+				       NLM_F_ACK, team_nl_send_unicast,
+				       &sel_opt_inst_list);
 
 	team_nl_team_put(team);
 
 	return err;
 }
 
+static int team_nl_send_event_options_get(struct team *team,
+					  struct list_head *sel_opt_inst_list);
+
 static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
 {
 	struct team *team;
 	int err = 0;
 	int i;
 	struct nlattr *nl_option;
+	LIST_HEAD(opt_inst_list);
 
 	team = team_nl_team_get(info);
 	if (!team)
@@ -1629,10 +1764,12 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
 
 	nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) {
 		struct nlattr *opt_attrs[TEAM_ATTR_OPTION_MAX + 1];
-		struct nlattr *attr_port_ifindex;
+		struct nlattr *attr;
 		struct nlattr *attr_data;
 		enum team_option_type opt_type;
 		int opt_port_ifindex = 0; /* != 0 for per-port options */
+		u32 opt_array_index = 0;
+		bool opt_is_array = false;
 		struct team_option_inst *opt_inst;
 		char *opt_name;
 		bool opt_found = false;
@@ -1674,23 +1811,33 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
 		}
 
 		opt_name = nla_data(opt_attrs[TEAM_ATTR_OPTION_NAME]);
-		attr_port_ifindex = opt_attrs[TEAM_ATTR_OPTION_PORT_IFINDEX];
-		if (attr_port_ifindex)
-			opt_port_ifindex = nla_get_u32(attr_port_ifindex);
+		attr = opt_attrs[TEAM_ATTR_OPTION_PORT_IFINDEX];
+		if (attr)
+			opt_port_ifindex = nla_get_u32(attr);
+
+		attr = opt_attrs[TEAM_ATTR_OPTION_ARRAY_INDEX];
+		if (attr) {
+			opt_is_array = true;
+			opt_array_index = nla_get_u32(attr);
+		}
 
 		list_for_each_entry(opt_inst, &team->option_inst_list, list) {
 			struct team_option *option = opt_inst->option;
 			struct team_gsetter_ctx ctx;
+			struct team_option_inst_info *opt_inst_info;
 			int tmp_ifindex;
 
-			tmp_ifindex = opt_inst->port ?
-				      opt_inst->port->dev->ifindex : 0;
+			opt_inst_info = &opt_inst->info;
+			tmp_ifindex = opt_inst_info->port ?
+				      opt_inst_info->port->dev->ifindex : 0;
 			if (option->type != opt_type ||
 			    strcmp(option->name, opt_name) ||
-			    tmp_ifindex != opt_port_ifindex)
+			    tmp_ifindex != opt_port_ifindex ||
+			    (option->array_size && !opt_is_array) ||
+			    opt_inst_info->array_index != opt_array_index)
 				continue;
 			opt_found = true;
-			ctx.port = opt_inst->port;
+			ctx.info = opt_inst_info;
 			switch (opt_type) {
 			case TEAM_OPTION_TYPE_U32:
 				ctx.data.u32_val = nla_get_u32(attr_data);
@@ -1715,6 +1862,8 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
 			err = team_option_set(team, opt_inst, &ctx);
 			if (err)
 				goto team_put;
+			opt_inst->changed = true;
+			list_add(&opt_inst->tmp_list, &opt_inst_list);
 		}
 		if (!opt_found) {
 			err = -ENOENT;
@@ -1722,6 +1871,8 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
 		}
 	}
 
+	err = team_nl_send_event_options_get(team, &opt_inst_list);
+
 team_put:
 	team_nl_team_put(team);
 
@@ -1746,7 +1897,7 @@ static int team_nl_fill_port_list_get(struct sk_buff *skb,
 		goto nla_put_failure;
 	port_list = nla_nest_start(skb, TEAM_ATTR_LIST_PORT);
 	if (!port_list)
-		return -EMSGSIZE;
+		goto nla_put_failure;
 
 	list_for_each_entry(port, &team->port_list, list) {
 		struct nlattr *port_item;
@@ -1838,27 +1989,18 @@ static struct genl_multicast_group team_change_event_mcgrp = {
 	.name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME,
 };
 
-static int team_nl_send_event_options_get(struct team *team)
+static int team_nl_send_multicast(struct sk_buff *skb,
+				  struct team *team, u32 pid)
 {
-	struct sk_buff *skb;
-	int err;
-	struct net *net = dev_net(team->dev);
-
-	skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-	if (!skb)
-		return -ENOMEM;
-
-	err = team_nl_fill_options_get(skb, 0, 0, 0, team, false);
-	if (err < 0)
-		goto err_fill;
-
-	err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
-				      GFP_KERNEL);
-	return err;
+	return genlmsg_multicast_netns(dev_net(team->dev), skb, 0,
+				       team_change_event_mcgrp.id, GFP_KERNEL);
+}
 
-err_fill:
-	nlmsg_free(skb);
-	return err;
+static int team_nl_send_event_options_get(struct team *team,
+					  struct list_head *sel_opt_inst_list)
+{
+	return team_nl_send_options_get(team, 0, 0, 0, team_nl_send_multicast,
+					sel_opt_inst_list);
 }
 
 static int team_nl_send_event_port_list_get(struct team *team)
@@ -1918,10 +2060,17 @@ static void team_nl_fini(void)
 static void __team_options_change_check(struct team *team)
 {
 	int err;
+	struct team_option_inst *opt_inst;
+	LIST_HEAD(sel_opt_inst_list);
 
-	err = team_nl_send_event_options_get(team);
+	list_for_each_entry(opt_inst, &team->option_inst_list, list) {
+		if (opt_inst->changed)
+			list_add_tail(&opt_inst->tmp_list, &sel_opt_inst_list);
+	}
+	err = team_nl_send_event_options_get(team, &sel_opt_inst_list);
 	if (err)
-		netdev_warn(team->dev, "Failed to send options change via netlink\n");
+		netdev_warn(team->dev, "Failed to send options change via netlink (err %d)\n",
+			    err);
 }
 
 /* rtnl lock is held */
@@ -1965,6 +2114,7 @@ static void team_port_change_check(struct team_port *port, bool linkup)
 	mutex_unlock(&team->lock);
 }
 
+
 /************************************
  * Net device notifier event handler
  ************************************/
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
index fd6bd03..253b8a5 100644
--- a/drivers/net/team/team_mode_activebackup.c
+++ b/drivers/net/team/team_mode_activebackup.c
@@ -1,5 +1,5 @@
 /*
- * net/drivers/team/team_mode_activebackup.c - Active-backup mode for team
+ * drivers/net/team/team_mode_activebackup.c - Active-backup mode for team
  * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -40,7 +40,7 @@ static bool ab_transmit(struct team *team, struct sk_buff *skb)
 {
 	struct team_port *active_port;
 
-	active_port = rcu_dereference(ab_priv(team)->active_port);
+	active_port = rcu_dereference_bh(ab_priv(team)->active_port);
 	if (unlikely(!active_port))
 		goto drop;
 	skb->dev = active_port->dev;
@@ -61,8 +61,12 @@ static void ab_port_leave(struct team *team, struct team_port *port)
 
 static int ab_active_port_get(struct team *team, struct team_gsetter_ctx *ctx)
 {
-	if (ab_priv(team)->active_port)
-		ctx->data.u32_val = ab_priv(team)->active_port->dev->ifindex;
+	struct team_port *active_port;
+
+	active_port = rcu_dereference_protected(ab_priv(team)->active_port,
+						lockdep_is_held(&team->lock));
+	if (active_port)
+		ctx->data.u32_val = active_port->dev->ifindex;
 	else
 		ctx->data.u32_val = 0;
 	return 0;
@@ -108,7 +112,7 @@ static const struct team_mode_ops ab_mode_ops = {
 	.port_leave		= ab_port_leave,
 };
 
-static struct team_mode ab_mode = {
+static const struct team_mode ab_mode = {
 	.kind		= "activebackup",
 	.owner		= THIS_MODULE,
 	.priv_size	= sizeof(struct ab_priv),
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index 86e8183..c92fa02 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -17,34 +17,210 @@
 #include <linux/filter.h>
 #include <linux/if_team.h>
 
+struct lb_priv;
+
+typedef struct team_port *lb_select_tx_port_func_t(struct team *,
+						   struct lb_priv *,
+						   struct sk_buff *,
+						   unsigned char);
+
+#define LB_TX_HASHTABLE_SIZE 256 /* hash is a char */
+
+struct lb_stats {
+	u64 tx_bytes;
+};
+
+struct lb_pcpu_stats {
+	struct lb_stats hash_stats[LB_TX_HASHTABLE_SIZE];
+	struct u64_stats_sync syncp;
+};
+
+struct lb_stats_info {
+	struct lb_stats stats;
+	struct lb_stats last_stats;
+	struct team_option_inst_info *opt_inst_info;
+};
+
+struct lb_port_mapping {
+	struct team_port __rcu *port;
+	struct team_option_inst_info *opt_inst_info;
+};
+
+struct lb_priv_ex {
+	struct team *team;
+	struct lb_port_mapping tx_hash_to_port_mapping[LB_TX_HASHTABLE_SIZE];
+	struct sock_fprog *orig_fprog;
+	struct {
+		unsigned int refresh_interval; /* in tenths of second */
+		struct delayed_work refresh_dw;
+		struct lb_stats_info info[LB_TX_HASHTABLE_SIZE];
+	} stats;
+};
+
 struct lb_priv {
 	struct sk_filter __rcu *fp;
-	struct sock_fprog *orig_fprog;
+	lb_select_tx_port_func_t __rcu *select_tx_port_func;
+	struct lb_pcpu_stats __percpu *pcpu_stats;
+	struct lb_priv_ex *ex; /* priv extension */
 };
 
-static struct lb_priv *lb_priv(struct team *team)
+static struct lb_priv *get_lb_priv(struct team *team)
 {
 	return (struct lb_priv *) &team->mode_priv;
 }
 
-static bool lb_transmit(struct team *team, struct sk_buff *skb)
+struct lb_port_priv {
+	struct lb_stats __percpu *pcpu_stats;
+	struct lb_stats_info stats_info;
+};
+
+static struct lb_port_priv *get_lb_port_priv(struct team_port *port)
+{
+	return (struct lb_port_priv *) &port->mode_priv;
+}
+
+#define LB_HTPM_PORT_BY_HASH(lp_priv, hash) \
+	(lb_priv)->ex->tx_hash_to_port_mapping[hash].port
+
+#define LB_HTPM_OPT_INST_INFO_BY_HASH(lp_priv, hash) \
+	(lb_priv)->ex->tx_hash_to_port_mapping[hash].opt_inst_info
+
+static void lb_tx_hash_to_port_mapping_null_port(struct team *team,
+						 struct team_port *port)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	bool changed = false;
+	int i;
+
+	for (i = 0; i < LB_TX_HASHTABLE_SIZE; i++) {
+		struct lb_port_mapping *pm;
+
+		pm = &lb_priv->ex->tx_hash_to_port_mapping[i];
+		if (rcu_access_pointer(pm->port) == port) {
+			RCU_INIT_POINTER(pm->port, NULL);
+			team_option_inst_set_change(pm->opt_inst_info);
+			changed = true;
+		}
+	}
+	if (changed)
+		team_options_change_check(team);
+}
+
+/* Basic tx selection based solely by hash */
+static struct team_port *lb_hash_select_tx_port(struct team *team,
+						struct lb_priv *lb_priv,
+						struct sk_buff *skb,
+						unsigned char hash)
 {
-	struct sk_filter *fp;
-	struct team_port *port;
-	unsigned int hash;
 	int port_index;
 
-	fp = rcu_dereference(lb_priv(team)->fp);
-	if (unlikely(!fp))
-		goto drop;
-	hash = SK_RUN_FILTER(fp, skb);
 	port_index = hash % team->en_port_count;
-	port = team_get_port_by_index_rcu(team, port_index);
+	return team_get_port_by_index_rcu(team, port_index);
+}
+
+/* Hash to port mapping select tx port */
+static struct team_port *lb_htpm_select_tx_port(struct team *team,
+						struct lb_priv *lb_priv,
+						struct sk_buff *skb,
+						unsigned char hash)
+{
+	return rcu_dereference_bh(LB_HTPM_PORT_BY_HASH(lb_priv, hash));
+}
+
+struct lb_select_tx_port {
+	char *name;
+	lb_select_tx_port_func_t *func;
+};
+
+static const struct lb_select_tx_port lb_select_tx_port_list[] = {
+	{
+		.name = "hash",
+		.func = lb_hash_select_tx_port,
+	},
+	{
+		.name = "hash_to_port_mapping",
+		.func = lb_htpm_select_tx_port,
+	},
+};
+#define LB_SELECT_TX_PORT_LIST_COUNT ARRAY_SIZE(lb_select_tx_port_list)
+
+static char *lb_select_tx_port_get_name(lb_select_tx_port_func_t *func)
+{
+	int i;
+
+	for (i = 0; i < LB_SELECT_TX_PORT_LIST_COUNT; i++) {
+		const struct lb_select_tx_port *item;
+
+		item = &lb_select_tx_port_list[i];
+		if (item->func == func)
+			return item->name;
+	}
+	return NULL;
+}
+
+static lb_select_tx_port_func_t *lb_select_tx_port_get_func(const char *name)
+{
+	int i;
+
+	for (i = 0; i < LB_SELECT_TX_PORT_LIST_COUNT; i++) {
+		const struct lb_select_tx_port *item;
+
+		item = &lb_select_tx_port_list[i];
+		if (!strcmp(item->name, name))
+			return item->func;
+	}
+	return NULL;
+}
+
+static unsigned int lb_get_skb_hash(struct lb_priv *lb_priv,
+				    struct sk_buff *skb)
+{
+	struct sk_filter *fp;
+	uint32_t lhash;
+	unsigned char *c;
+
+	fp = rcu_dereference_bh(lb_priv->fp);
+	if (unlikely(!fp))
+		return 0;
+	lhash = SK_RUN_FILTER(fp, skb);
+	c = (char *) &lhash;
+	return c[0] ^ c[1] ^ c[2] ^ c[3];
+}
+
+static void lb_update_tx_stats(unsigned int tx_bytes, struct lb_priv *lb_priv,
+			       struct lb_port_priv *lb_port_priv,
+			       unsigned char hash)
+{
+	struct lb_pcpu_stats *pcpu_stats;
+	struct lb_stats *port_stats;
+	struct lb_stats *hash_stats;
+
+	pcpu_stats = this_cpu_ptr(lb_priv->pcpu_stats);
+	port_stats = this_cpu_ptr(lb_port_priv->pcpu_stats);
+	hash_stats = &pcpu_stats->hash_stats[hash];
+	u64_stats_update_begin(&pcpu_stats->syncp);
+	port_stats->tx_bytes += tx_bytes;
+	hash_stats->tx_bytes += tx_bytes;
+	u64_stats_update_end(&pcpu_stats->syncp);
+}
+
+static bool lb_transmit(struct team *team, struct sk_buff *skb)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	lb_select_tx_port_func_t *select_tx_port_func;
+	struct team_port *port;
+	unsigned char hash;
+	unsigned int tx_bytes = skb->len;
+
+	hash = lb_get_skb_hash(lb_priv, skb);
+	select_tx_port_func = rcu_dereference_bh(lb_priv->select_tx_port_func);
+	port = select_tx_port_func(team, lb_priv, skb, hash);
 	if (unlikely(!port))
 		goto drop;
 	skb->dev = port->dev;
 	if (dev_queue_xmit(skb))
 		return false;
+	lb_update_tx_stats(tx_bytes, lb_priv, get_lb_port_priv(port), hash);
 	return true;
 
 drop:
@@ -54,14 +230,16 @@ drop:
 
 static int lb_bpf_func_get(struct team *team, struct team_gsetter_ctx *ctx)
 {
-	if (!lb_priv(team)->orig_fprog) {
+	struct lb_priv *lb_priv = get_lb_priv(team);
+
+	if (!lb_priv->ex->orig_fprog) {
 		ctx->data.bin_val.len = 0;
 		ctx->data.bin_val.ptr = NULL;
 		return 0;
 	}
-	ctx->data.bin_val.len = lb_priv(team)->orig_fprog->len *
+	ctx->data.bin_val.len = lb_priv->ex->orig_fprog->len *
 				sizeof(struct sock_filter);
-	ctx->data.bin_val.ptr = lb_priv(team)->orig_fprog->filter;
+	ctx->data.bin_val.ptr = lb_priv->ex->orig_fprog->filter;
 	return 0;
 }
 
@@ -94,7 +272,9 @@ static void __fprog_destroy(struct sock_fprog *fprog)
 
 static int lb_bpf_func_set(struct team *team, struct team_gsetter_ctx *ctx)
 {
+	struct lb_priv *lb_priv = get_lb_priv(team);
 	struct sk_filter *fp = NULL;
+	struct sk_filter *orig_fp;
 	struct sock_fprog *fprog = NULL;
 	int err;
 
@@ -110,14 +290,237 @@ static int lb_bpf_func_set(struct team *team, struct team_gsetter_ctx *ctx)
 		}
 	}
 
-	if (lb_priv(team)->orig_fprog) {
+	if (lb_priv->ex->orig_fprog) {
 		/* Clear old filter data */
-		__fprog_destroy(lb_priv(team)->orig_fprog);
-		sk_unattached_filter_destroy(lb_priv(team)->fp);
+		__fprog_destroy(lb_priv->ex->orig_fprog);
+		orig_fp = rcu_dereference_protected(lb_priv->fp,
+						lockdep_is_held(&team->lock));
+		sk_unattached_filter_destroy(orig_fp);
 	}
 
-	rcu_assign_pointer(lb_priv(team)->fp, fp);
-	lb_priv(team)->orig_fprog = fprog;
+	rcu_assign_pointer(lb_priv->fp, fp);
+	lb_priv->ex->orig_fprog = fprog;
+	return 0;
+}
+
+static int lb_tx_method_get(struct team *team, struct team_gsetter_ctx *ctx)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	lb_select_tx_port_func_t *func;
+	char *name;
+
+	func = rcu_dereference_protected(lb_priv->select_tx_port_func,
+					 lockdep_is_held(&team->lock));
+	name = lb_select_tx_port_get_name(func);
+	BUG_ON(!name);
+	ctx->data.str_val = name;
+	return 0;
+}
+
+static int lb_tx_method_set(struct team *team, struct team_gsetter_ctx *ctx)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	lb_select_tx_port_func_t *func;
+
+	func = lb_select_tx_port_get_func(ctx->data.str_val);
+	if (!func)
+		return -EINVAL;
+	rcu_assign_pointer(lb_priv->select_tx_port_func, func);
+	return 0;
+}
+
+static int lb_tx_hash_to_port_mapping_init(struct team *team,
+					   struct team_option_inst_info *info)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	unsigned char hash = info->array_index;
+
+	LB_HTPM_OPT_INST_INFO_BY_HASH(lb_priv, hash) = info;
+	return 0;
+}
+
+static int lb_tx_hash_to_port_mapping_get(struct team *team,
+					  struct team_gsetter_ctx *ctx)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	struct team_port *port;
+	unsigned char hash = ctx->info->array_index;
+
+	port = LB_HTPM_PORT_BY_HASH(lb_priv, hash);
+	ctx->data.u32_val = port ? port->dev->ifindex : 0;
+	return 0;
+}
+
+static int lb_tx_hash_to_port_mapping_set(struct team *team,
+					  struct team_gsetter_ctx *ctx)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	struct team_port *port;
+	unsigned char hash = ctx->info->array_index;
+
+	list_for_each_entry(port, &team->port_list, list) {
+		if (ctx->data.u32_val == port->dev->ifindex) {
+			rcu_assign_pointer(LB_HTPM_PORT_BY_HASH(lb_priv, hash),
+					   port);
+			return 0;
+		}
+	}
+	return -ENODEV;
+}
+
+static int lb_hash_stats_init(struct team *team,
+			      struct team_option_inst_info *info)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	unsigned char hash = info->array_index;
+
+	lb_priv->ex->stats.info[hash].opt_inst_info = info;
+	return 0;
+}
+
+static int lb_hash_stats_get(struct team *team, struct team_gsetter_ctx *ctx)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	unsigned char hash = ctx->info->array_index;
+
+	ctx->data.bin_val.ptr = &lb_priv->ex->stats.info[hash].stats;
+	ctx->data.bin_val.len = sizeof(struct lb_stats);
+	return 0;
+}
+
+static int lb_port_stats_init(struct team *team,
+			      struct team_option_inst_info *info)
+{
+	struct team_port *port = info->port;
+	struct lb_port_priv *lb_port_priv = get_lb_port_priv(port);
+
+	lb_port_priv->stats_info.opt_inst_info = info;
+	return 0;
+}
+
+static int lb_port_stats_get(struct team *team, struct team_gsetter_ctx *ctx)
+{
+	struct team_port *port = ctx->info->port;
+	struct lb_port_priv *lb_port_priv = get_lb_port_priv(port);
+
+	ctx->data.bin_val.ptr = &lb_port_priv->stats_info.stats;
+	ctx->data.bin_val.len = sizeof(struct lb_stats);
+	return 0;
+}
+
+static void __lb_stats_info_refresh_prepare(struct lb_stats_info *s_info)
+{
+	memcpy(&s_info->last_stats, &s_info->stats, sizeof(struct lb_stats));
+	memset(&s_info->stats, 0, sizeof(struct lb_stats));
+}
+
+static bool __lb_stats_info_refresh_check(struct lb_stats_info *s_info,
+					  struct team *team)
+{
+	if (memcmp(&s_info->last_stats, &s_info->stats,
+	    sizeof(struct lb_stats))) {
+		team_option_inst_set_change(s_info->opt_inst_info);
+		return true;
+	}
+	return false;
+}
+
+static void __lb_one_cpu_stats_add(struct lb_stats *acc_stats,
+				   struct lb_stats *cpu_stats,
+				   struct u64_stats_sync *syncp)
+{
+	unsigned int start;
+	struct lb_stats tmp;
+
+	do {
+		start = u64_stats_fetch_begin_bh(syncp);
+		tmp.tx_bytes = cpu_stats->tx_bytes;
+	} while (u64_stats_fetch_retry_bh(syncp, start));
+	acc_stats->tx_bytes += tmp.tx_bytes;
+}
+
+static void lb_stats_refresh(struct work_struct *work)
+{
+	struct team *team;
+	struct lb_priv *lb_priv;
+	struct lb_priv_ex *lb_priv_ex;
+	struct lb_pcpu_stats *pcpu_stats;
+	struct lb_stats *stats;
+	struct lb_stats_info *s_info;
+	struct team_port *port;
+	bool changed = false;
+	int i;
+	int j;
+
+	lb_priv_ex = container_of(work, struct lb_priv_ex,
+				  stats.refresh_dw.work);
+
+	team = lb_priv_ex->team;
+	lb_priv = get_lb_priv(team);
+
+	if (!mutex_trylock(&team->lock)) {
+		schedule_delayed_work(&lb_priv_ex->stats.refresh_dw, 0);
+		return;
+	}
+
+	for (j = 0; j < LB_TX_HASHTABLE_SIZE; j++) {
+		s_info = &lb_priv->ex->stats.info[j];
+		__lb_stats_info_refresh_prepare(s_info);
+		for_each_possible_cpu(i) {
+			pcpu_stats = per_cpu_ptr(lb_priv->pcpu_stats, i);
+			stats = &pcpu_stats->hash_stats[j];
+			__lb_one_cpu_stats_add(&s_info->stats, stats,
+					       &pcpu_stats->syncp);
+		}
+		changed |= __lb_stats_info_refresh_check(s_info, team);
+	}
+
+	list_for_each_entry(port, &team->port_list, list) {
+		struct lb_port_priv *lb_port_priv = get_lb_port_priv(port);
+
+		s_info = &lb_port_priv->stats_info;
+		__lb_stats_info_refresh_prepare(s_info);
+		for_each_possible_cpu(i) {
+			pcpu_stats = per_cpu_ptr(lb_priv->pcpu_stats, i);
+			stats = per_cpu_ptr(lb_port_priv->pcpu_stats, i);
+			__lb_one_cpu_stats_add(&s_info->stats, stats,
+					       &pcpu_stats->syncp);
+		}
+		changed |= __lb_stats_info_refresh_check(s_info, team);
+	}
+
+	if (changed)
+		team_options_change_check(team);
+
+	schedule_delayed_work(&lb_priv_ex->stats.refresh_dw,
+			      (lb_priv_ex->stats.refresh_interval * HZ) / 10);
+
+	mutex_unlock(&team->lock);
+}
+
+static int lb_stats_refresh_interval_get(struct team *team,
+					 struct team_gsetter_ctx *ctx)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+
+	ctx->data.u32_val = lb_priv->ex->stats.refresh_interval;
+	return 0;
+}
+
+static int lb_stats_refresh_interval_set(struct team *team,
+					 struct team_gsetter_ctx *ctx)
+{
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	unsigned int interval;
+
+	interval = ctx->data.u32_val;
+	if (lb_priv->ex->stats.refresh_interval == interval)
+		return 0;
+	lb_priv->ex->stats.refresh_interval = interval;
+	if (interval)
+		schedule_delayed_work(&lb_priv->ex->stats.refresh_dw, 0);
+	else
+		cancel_delayed_work(&lb_priv->ex->stats.refresh_dw);
 	return 0;
 }
 
@@ -128,30 +531,125 @@ static const struct team_option lb_options[] = {
 		.getter = lb_bpf_func_get,
 		.setter = lb_bpf_func_set,
 	},
+	{
+		.name = "lb_tx_method",
+		.type = TEAM_OPTION_TYPE_STRING,
+		.getter = lb_tx_method_get,
+		.setter = lb_tx_method_set,
+	},
+	{
+		.name = "lb_tx_hash_to_port_mapping",
+		.array_size = LB_TX_HASHTABLE_SIZE,
+		.type = TEAM_OPTION_TYPE_U32,
+		.init = lb_tx_hash_to_port_mapping_init,
+		.getter = lb_tx_hash_to_port_mapping_get,
+		.setter = lb_tx_hash_to_port_mapping_set,
+	},
+	{
+		.name = "lb_hash_stats",
+		.array_size = LB_TX_HASHTABLE_SIZE,
+		.type = TEAM_OPTION_TYPE_BINARY,
+		.init = lb_hash_stats_init,
+		.getter = lb_hash_stats_get,
+	},
+	{
+		.name = "lb_port_stats",
+		.per_port = true,
+		.type = TEAM_OPTION_TYPE_BINARY,
+		.init = lb_port_stats_init,
+		.getter = lb_port_stats_get,
+	},
+	{
+		.name = "lb_stats_refresh_interval",
+		.type = TEAM_OPTION_TYPE_U32,
+		.getter = lb_stats_refresh_interval_get,
+		.setter = lb_stats_refresh_interval_set,
+	},
 };
 
 static int lb_init(struct team *team)
 {
-	return team_options_register(team, lb_options,
-				     ARRAY_SIZE(lb_options));
+	struct lb_priv *lb_priv = get_lb_priv(team);
+	lb_select_tx_port_func_t *func;
+	int err;
+
+	/* set default tx port selector */
+	func = lb_select_tx_port_get_func("hash");
+	BUG_ON(!func);
+	rcu_assign_pointer(lb_priv->select_tx_port_func, func);
+
+	lb_priv->ex = kzalloc(sizeof(*lb_priv->ex), GFP_KERNEL);
+	if (!lb_priv->ex)
+		return -ENOMEM;
+	lb_priv->ex->team = team;
+
+	lb_priv->pcpu_stats = alloc_percpu(struct lb_pcpu_stats);
+	if (!lb_priv->pcpu_stats) {
+		err = -ENOMEM;
+		goto err_alloc_pcpu_stats;
+	}
+
+	INIT_DELAYED_WORK(&lb_priv->ex->stats.refresh_dw, lb_stats_refresh);
+
+	err = team_options_register(team, lb_options, ARRAY_SIZE(lb_options));
+	if (err)
+		goto err_options_register;
+	return 0;
+
+err_options_register:
+	free_percpu(lb_priv->pcpu_stats);
+err_alloc_pcpu_stats:
+	kfree(lb_priv->ex);
+	return err;
 }
 
 static void lb_exit(struct team *team)
 {
+	struct lb_priv *lb_priv = get_lb_priv(team);
+
 	team_options_unregister(team, lb_options,
 				ARRAY_SIZE(lb_options));
+	cancel_delayed_work_sync(&lb_priv->ex->stats.refresh_dw);
+	free_percpu(lb_priv->pcpu_stats);
+	kfree(lb_priv->ex);
+}
+
+static int lb_port_enter(struct team *team, struct team_port *port)
+{
+	struct lb_port_priv *lb_port_priv = get_lb_port_priv(port);
+
+	lb_port_priv->pcpu_stats = alloc_percpu(struct lb_stats);
+	if (!lb_port_priv->pcpu_stats)
+		return -ENOMEM;
+	return 0;
+}
+
+static void lb_port_leave(struct team *team, struct team_port *port)
+{
+	struct lb_port_priv *lb_port_priv = get_lb_port_priv(port);
+
+	free_percpu(lb_port_priv->pcpu_stats);
+}
+
+static void lb_port_disabled(struct team *team, struct team_port *port)
+{
+	lb_tx_hash_to_port_mapping_null_port(team, port);
 }
 
 static const struct team_mode_ops lb_mode_ops = {
 	.init			= lb_init,
 	.exit			= lb_exit,
+	.port_enter		= lb_port_enter,
+	.port_leave		= lb_port_leave,
+	.port_disabled		= lb_port_disabled,
 	.transmit		= lb_transmit,
 };
 
-static struct team_mode lb_mode = {
+static const struct team_mode lb_mode = {
 	.kind		= "loadbalance",
 	.owner		= THIS_MODULE,
 	.priv_size	= sizeof(struct lb_priv),
+	.port_priv_size	= sizeof(struct lb_port_priv),
 	.ops		= &lb_mode_ops,
 };
 
diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c
index 6abfbdc..52dd0ec 100644
--- a/drivers/net/team/team_mode_roundrobin.c
+++ b/drivers/net/team/team_mode_roundrobin.c
@@ -1,5 +1,5 @@
 /*
- * net/drivers/team/team_mode_roundrobin.c - Round-robin mode for team
+ * drivers/net/team/team_mode_roundrobin.c - Round-robin mode for team
  * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -81,7 +81,7 @@ static const struct team_mode_ops rr_mode_ops = {
 	.port_change_mac	= rr_port_change_mac,
 };
 
-static struct team_mode rr_mode = {
+static const struct team_mode rr_mode = {
 	.kind		= "roundrobin",
 	.owner		= THIS_MODULE,
 	.priv_size	= sizeof(struct rr_priv),
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 987aeef..c4459e0 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -100,6 +100,8 @@ do {								\
 } while (0)
 #endif
 
+#define GOODCOPY_LEN 128
+
 #define FLT_EXACT_COUNT 8
 struct tap_filter {
 	unsigned int    count;    /* Number of addrs. Zero means disabled */
@@ -414,6 +416,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	/* Orphan the skb - required as we might hang on to it
 	 * for indefinite time. */
+	if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
+		goto drop;
 	skb_orphan(skb);
 
 	/* Enqueue packet */
@@ -600,8 +604,86 @@ static struct sk_buff *tun_alloc_skb(struct tun_struct *tun,
 	return skb;
 }
 
+/* set skb frags from iovec, this can move to core network code for reuse */
+static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
+				  int offset, size_t count)
+{
+	int len = iov_length(from, count) - offset;
+	int copy = skb_headlen(skb);
+	int size, offset1 = 0;
+	int i = 0;
+
+	/* Skip over from offset */
+	while (count && (offset >= from->iov_len)) {
+		offset -= from->iov_len;
+		++from;
+		--count;
+	}
+
+	/* copy up to skb headlen */
+	while (count && (copy > 0)) {
+		size = min_t(unsigned int, copy, from->iov_len - offset);
+		if (copy_from_user(skb->data + offset1, from->iov_base + offset,
+				   size))
+			return -EFAULT;
+		if (copy > size) {
+			++from;
+			--count;
+			offset = 0;
+		} else
+			offset += size;
+		copy -= size;
+		offset1 += size;
+	}
+
+	if (len == offset1)
+		return 0;
+
+	while (count--) {
+		struct page *page[MAX_SKB_FRAGS];
+		int num_pages;
+		unsigned long base;
+		unsigned long truesize;
+
+		len = from->iov_len - offset;
+		if (!len) {
+			offset = 0;
+			++from;
+			continue;
+		}
+		base = (unsigned long)from->iov_base + offset;
+		size = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT;
+		if (i + size > MAX_SKB_FRAGS)
+			return -EMSGSIZE;
+		num_pages = get_user_pages_fast(base, size, 0, &page[i]);
+		if (num_pages != size) {
+			for (i = 0; i < num_pages; i++)
+				put_page(page[i]);
+			return -EFAULT;
+		}
+		truesize = size * PAGE_SIZE;
+		skb->data_len += len;
+		skb->len += len;
+		skb->truesize += truesize;
+		atomic_add(truesize, &skb->sk->sk_wmem_alloc);
+		while (len) {
+			int off = base & ~PAGE_MASK;
+			int size = min_t(int, len, PAGE_SIZE - off);
+			__skb_fill_page_desc(skb, i, page[i], off, size);
+			skb_shinfo(skb)->nr_frags++;
+			/* increase sk_wmem_alloc */
+			base += size;
+			len -= size;
+			i++;
+		}
+		offset = 0;
+		++from;
+	}
+	return 0;
+}
+
 /* Get packet from user space buffer */
-static ssize_t tun_get_user(struct tun_struct *tun,
+static ssize_t tun_get_user(struct tun_struct *tun, void *msg_control,
 			    const struct iovec *iv, size_t count,
 			    int noblock)
 {
@@ -610,6 +692,9 @@ static ssize_t tun_get_user(struct tun_struct *tun,
 	size_t len = count, align = NET_SKB_PAD;
 	struct virtio_net_hdr gso = { 0 };
 	int offset = 0;
+	int copylen;
+	bool zerocopy = false;
+	int err;
 
 	if (!(tun->flags & TUN_NO_PI)) {
 		if ((len -= sizeof(pi)) > count)
@@ -643,14 +728,46 @@ static ssize_t tun_get_user(struct tun_struct *tun,
 			return -EINVAL;
 	}
 
-	skb = tun_alloc_skb(tun, align, len, gso.hdr_len, noblock);
+	if (msg_control)
+		zerocopy = true;
+
+	if (zerocopy) {
+		/* Userspace may produce vectors with count greater than
+		 * MAX_SKB_FRAGS, so we need to linearize parts of the skb
+		 * to let the rest of data to be fit in the frags.
+		 */
+		if (count > MAX_SKB_FRAGS) {
+			copylen = iov_length(iv, count - MAX_SKB_FRAGS);
+			if (copylen < offset)
+				copylen = 0;
+			else
+				copylen -= offset;
+		} else
+				copylen = 0;
+		/* There are 256 bytes to be copied in skb, so there is enough
+		 * room for skb expand head in case it is used.
+		 * The rest of the buffer is mapped from userspace.
+		 */
+		if (copylen < gso.hdr_len)
+			copylen = gso.hdr_len;
+		if (!copylen)
+			copylen = GOODCOPY_LEN;
+	} else
+		copylen = len;
+
+	skb = tun_alloc_skb(tun, align, copylen, gso.hdr_len, noblock);
 	if (IS_ERR(skb)) {
 		if (PTR_ERR(skb) != -EAGAIN)
 			tun->dev->stats.rx_dropped++;
 		return PTR_ERR(skb);
 	}
 
-	if (skb_copy_datagram_from_iovec(skb, 0, iv, offset, len)) {
+	if (zerocopy)
+		err = zerocopy_sg_from_iovec(skb, iv, offset, count);
+	else
+		err = skb_copy_datagram_from_iovec(skb, 0, iv, offset, len);
+
+	if (err) {
 		tun->dev->stats.rx_dropped++;
 		kfree_skb(skb);
 		return -EFAULT;
@@ -724,6 +841,12 @@ static ssize_t tun_get_user(struct tun_struct *tun,
 		skb_shinfo(skb)->gso_segs = 0;
 	}
 
+	/* copy skb_ubuf_info for callback when skb has no error */
+	if (zerocopy) {
+		skb_shinfo(skb)->destructor_arg = msg_control;
+		skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+	}
+
 	netif_rx_ni(skb);
 
 	tun->dev->stats.rx_packets++;
@@ -744,7 +867,7 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,
 
 	tun_debug(KERN_INFO, tun, "tun_chr_write %ld\n", count);
 
-	result = tun_get_user(tun, iv, iov_length(iv, count),
+	result = tun_get_user(tun, NULL, iv, iov_length(iv, count),
 			      file->f_flags & O_NONBLOCK);
 
 	tun_put(tun);
@@ -958,7 +1081,7 @@ static int tun_sendmsg(struct kiocb *iocb, struct socket *sock,
 		       struct msghdr *m, size_t total_len)
 {
 	struct tun_struct *tun = container_of(sock, struct tun_struct, socket);
-	return tun_get_user(tun, m->msg_iov, total_len,
+	return tun_get_user(tun, m->msg_control, m->msg_iov, total_len,
 			    m->msg_flags & MSG_DONTWAIT);
 }
 
@@ -1128,6 +1251,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 		sock_init_data(&tun->socket, sk);
 		sk->sk_write_space = tun_sock_write_space;
 		sk->sk_sndbuf = INT_MAX;
+		sock_set_flag(sk, SOCK_ZEROCOPY);
 
 		tun_sk(sk)->tun = tun;
 
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
index d848d4d..187c144 100644
--- a/drivers/net/usb/cdc-phonet.c
+++ b/drivers/net/usb/cdc-phonet.c
@@ -394,7 +394,7 @@ int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	SET_NETDEV_DEV(dev, &intf->dev);
 
 	pnd->dev = dev;
-	pnd->usb = usb_get_dev(usbdev);
+	pnd->usb = usbdev;
 	pnd->intf = intf;
 	pnd->data_intf = data_intf;
 	spin_lock_init(&pnd->tx_lock);
@@ -440,7 +440,6 @@ out:
 static void usbpn_disconnect(struct usb_interface *intf)
 {
 	struct usbpn_dev *pnd = usb_get_intfdata(intf);
-	struct usb_device *usb = pnd->usb;
 
 	if (pnd->disconnected)
 		return;
@@ -449,7 +448,6 @@ static void usbpn_disconnect(struct usb_interface *intf)
 	usb_driver_release_interface(&usbpn_driver,
 			(pnd->intf == intf) ? pnd->data_intf : pnd->intf);
 	unregister_netdev(pnd->dev);
-	usb_put_dev(usb);
 }
 
 static struct usb_driver usbpn_driver = {
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index 964031e..a28a983 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -59,6 +59,7 @@
 #define USB_PRODUCT_IPHONE_3G   0x1292
 #define USB_PRODUCT_IPHONE_3GS  0x1294
 #define USB_PRODUCT_IPHONE_4	0x1297
+#define USB_PRODUCT_IPAD 0x129a
 #define USB_PRODUCT_IPHONE_4_VZW 0x129c
 #define USB_PRODUCT_IPHONE_4S	0x12a0
 
@@ -101,6 +102,10 @@ static struct usb_device_id ipheth_table[] = {
 		IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
 		IPHETH_USBINTF_PROTO) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(
+		USB_VENDOR_APPLE, USB_PRODUCT_IPAD,
+		IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
+		IPHETH_USBINTF_PROTO) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(
 		USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW,
 		IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
 		IPHETH_USBINTF_PROTO) },
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 7023220..a0b5807 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -1329,8 +1329,6 @@ static int pegasus_probe(struct usb_interface *intf,
 	}
 	pegasus_count++;
 
-	usb_get_dev(dev);
-
 	net = alloc_etherdev(sizeof(struct pegasus));
 	if (!net)
 		goto out;
@@ -1407,7 +1405,6 @@ out2:
 out1:
 	free_netdev(net);
 out:
-	usb_put_dev(dev);
 	pegasus_dec_workqueue();
 	return res;
 }
@@ -1425,7 +1422,6 @@ static void pegasus_disconnect(struct usb_interface *intf)
 	pegasus->flags |= PEGASUS_UNPLUG;
 	cancel_delayed_work(&pegasus->carrier_check);
 	unregister_netdev(pegasus->net);
-	usb_put_dev(interface_to_usbdev(intf));
 	unlink_all_urbs(pegasus);
 	free_all_urbs(pegasus);
 	free_skb_pool(pegasus);
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 3b20678..68ca676 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -1,6 +1,10 @@
 /*
  * Copyright (c) 2012  Bjørn Mork <bjorn@mork.no>
  *
+ * The probing code is heavily inspired by cdc_ether, which is:
+ * Copyright (C) 2003-2005 by David Brownell
+ * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
@@ -15,11 +19,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/usb/cdc-wdm.h>
 
-/* The name of the CDC Device Management driver */
-#define DM_DRIVER "cdc_wdm"
-
-/*
- * This driver supports wwan (3G/LTE/?) devices using a vendor
+/* This driver supports wwan (3G/LTE/?) devices using a vendor
  * specific management protocol called Qualcomm MSM Interface (QMI) -
  * in addition to the more common AT commands over serial interface
  * management
@@ -31,33 +31,99 @@
  * management protocol is used in place of the standard CDC
  * notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE
  *
+ * Alternatively, control and data functions can be combined in a
+ * single USB interface.
+ *
  * Handling a protocol like QMI is out of the scope for any driver.
- * It can be exported as a character device using the cdc-wdm driver,
- * which will enable userspace applications ("modem managers") to
- * handle it.  This may be required to use the network interface
- * provided by the driver.
+ * It is exported as a character device using the cdc-wdm driver as
+ * a subdriver, enabling userspace applications ("modem managers") to
+ * handle it.
  *
  * These devices may alternatively/additionally be configured using AT
- * commands on any of the serial interfaces driven by the option driver
- *
- * This driver binds only to the data ("slave") interface to enable
- * the cdc-wdm driver to bind to the control interface.  It still
- * parses the CDC functional descriptors on the control interface to
- *  a) verify that this is indeed a handled interface (CDC Union
- *     header lists it as slave)
- *  b) get MAC address and other ethernet config from the CDC Ethernet
- *     header
- *  c) enable user bind requests against the control interface, which
- *     is the common way to bind to CDC Ethernet Control Model type
- *     interfaces
- *  d) provide a hint to the user about which interface is the
- *     corresponding management interface
+ * commands on a serial interface
  */
 
+/* driver specific data */
+struct qmi_wwan_state {
+	struct usb_driver *subdriver;
+	atomic_t pmcount;
+	unsigned long unused;
+	struct usb_interface *control;
+	struct usb_interface *data;
+};
+
+/* using a counter to merge subdriver requests with our own into a combined state */
+static int qmi_wwan_manage_power(struct usbnet *dev, int on)
+{
+	struct qmi_wwan_state *info = (void *)&dev->data;
+	int rv = 0;
+
+	dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(&info->pmcount), on);
+
+	if ((on && atomic_add_return(1, &info->pmcount) == 1) || (!on && atomic_dec_and_test(&info->pmcount))) {
+		/* need autopm_get/put here to ensure the usbcore sees the new value */
+		rv = usb_autopm_get_interface(dev->intf);
+		if (rv < 0)
+			goto err;
+		dev->intf->needs_remote_wakeup = on;
+		usb_autopm_put_interface(dev->intf);
+	}
+err:
+	return rv;
+}
+
+static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on)
+{
+	struct usbnet *dev = usb_get_intfdata(intf);
+	return qmi_wwan_manage_power(dev, on);
+}
+
+/* collect all three endpoints and register subdriver */
+static int qmi_wwan_register_subdriver(struct usbnet *dev)
+{
+	int rv;
+	struct usb_driver *subdriver = NULL;
+	struct qmi_wwan_state *info = (void *)&dev->data;
+
+	/* collect bulk endpoints */
+	rv = usbnet_get_endpoints(dev, info->data);
+	if (rv < 0)
+		goto err;
+
+	/* update status endpoint if separate control interface */
+	if (info->control != info->data)
+		dev->status = &info->control->cur_altsetting->endpoint[0];
+
+	/* require interrupt endpoint for subdriver */
+	if (!dev->status) {
+		rv = -EINVAL;
+		goto err;
+	}
+
+	/* for subdriver power management */
+	atomic_set(&info->pmcount, 0);
+
+	/* register subdriver */
+	subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power);
+	if (IS_ERR(subdriver)) {
+		dev_err(&info->control->dev, "subdriver registration failed\n");
+		rv = PTR_ERR(subdriver);
+		goto err;
+	}
+
+	/* prevent usbnet from using status endpoint */
+	dev->status = NULL;
+
+	/* save subdriver struct for suspend/resume wrappers */
+	info->subdriver = subdriver;
+
+err:
+	return rv;
+}
+
 static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
 {
 	int status = -1;
-	struct usb_interface *control = NULL;
 	u8 *buf = intf->cur_altsetting->extra;
 	int len = intf->cur_altsetting->extralen;
 	struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
@@ -65,25 +131,14 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
 	struct usb_cdc_ether_desc *cdc_ether = NULL;
 	u32 required = 1 << USB_CDC_HEADER_TYPE | 1 << USB_CDC_UNION_TYPE;
 	u32 found = 0;
-	atomic_t *pmcount = (void *)&dev->data[1];
+	struct usb_driver *driver = driver_of(intf);
+	struct qmi_wwan_state *info = (void *)&dev->data;
 
-	atomic_set(pmcount, 0);
+	BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < sizeof(struct qmi_wwan_state)));
 
-	/*
-	 * assume a data interface has no additional descriptors and
-	 * that the control and data interface are numbered
-	 * consecutively - this holds for the Huawei device at least
-	 */
-	if (len == 0 && desc->bInterfaceNumber > 0) {
-		control = usb_ifnum_to_if(dev->udev, desc->bInterfaceNumber - 1);
-		if (!control)
-			goto err;
-
-		buf = control->cur_altsetting->extra;
-		len = control->cur_altsetting->extralen;
-		dev_dbg(&intf->dev, "guessing \"control\" => %s, \"data\" => this\n",
-			dev_name(&control->dev));
-	}
+	/* require a single interrupt status endpoint for subdriver */
+	if (intf->cur_altsetting->desc.bNumEndpoints != 1)
+		goto err;
 
 	while (len > 3) {
 		struct usb_descriptor_header *h = (void *)buf;
@@ -147,10 +202,17 @@ next_desc:
 		goto err;
 	}
 
-	/* give the user a helpful hint if trying to bind to the wrong interface */
-	if (cdc_union && desc->bInterfaceNumber == cdc_union->bMasterInterface0) {
-		dev_err(&intf->dev, "leaving \"control\" interface for " DM_DRIVER " - try binding to %s instead!\n",
-			dev_name(&usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0)->dev));
+	/* verify CDC Union */
+	if (desc->bInterfaceNumber != cdc_union->bMasterInterface0) {
+		dev_err(&intf->dev, "bogus CDC Union: master=%u\n", cdc_union->bMasterInterface0);
+		goto err;
+	}
+
+	/* need to save these for unbind */
+	info->control = intf;
+	info->data = usb_ifnum_to_if(dev->udev,	cdc_union->bSlaveInterface0);
+	if (!info->data) {
+		dev_err(&intf->dev, "bogus CDC Union: slave=%u\n", cdc_union->bSlaveInterface0);
 		goto err;
 	}
 
@@ -160,59 +222,29 @@ next_desc:
 		usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress);
 	}
 
-	/* success! point the user to the management interface */
-	if (control)
-		dev_info(&intf->dev, "Use \"" DM_DRIVER "\" for QMI interface %s\n",
-			dev_name(&control->dev));
-
-	/* XXX: add a sysfs symlink somewhere to help management applications find it? */
+	/* claim data interface and set it up */
+	status = usb_driver_claim_interface(driver, info->data, dev);
+	if (status < 0)
+		goto err;
 
-	/* collect bulk endpoints now that we know intf == "data" interface */
-	status = usbnet_get_endpoints(dev, intf);
+	status = qmi_wwan_register_subdriver(dev);
+	if (status < 0) {
+		usb_set_intfdata(info->data, NULL);
+		usb_driver_release_interface(driver, info->data);
+	}
 
 err:
 	return status;
 }
 
-/* using a counter to merge subdriver requests with our own into a combined state */
-static int qmi_wwan_manage_power(struct usbnet *dev, int on)
-{
-	atomic_t *pmcount = (void *)&dev->data[1];
-	int rv = 0;
-
-	dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(pmcount), on);
-
-	if ((on && atomic_add_return(1, pmcount) == 1) || (!on && atomic_dec_and_test(pmcount))) {
-		/* need autopm_get/put here to ensure the usbcore sees the new value */
-		rv = usb_autopm_get_interface(dev->intf);
-		if (rv < 0)
-			goto err;
-		dev->intf->needs_remote_wakeup = on;
-		usb_autopm_put_interface(dev->intf);
-	}
-err:
-	return rv;
-}
-
-static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on)
-{
-	struct usbnet *dev = usb_get_intfdata(intf);
-	return qmi_wwan_manage_power(dev, on);
-}
-
 /* Some devices combine the "control" and "data" functions into a
  * single interface with all three endpoints: interrupt + bulk in and
  * out
- *
- * Setting up cdc-wdm as a subdriver owning the interrupt endpoint
- * will let it provide userspace access to the encapsulated QMI
- * protocol without interfering with the usbnet operations.
-  */
+ */
 static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf)
 {
 	int rv;
-	struct usb_driver *subdriver = NULL;
-	atomic_t *pmcount = (void *)&dev->data[1];
+	struct qmi_wwan_state *info = (void *)&dev->data;
 
 	/* ZTE makes devices where the interface descriptors and endpoint
 	 * configurations of two or more interfaces are identical, even
@@ -228,66 +260,39 @@ static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf)
 		goto err;
 	}
 
-	atomic_set(pmcount, 0);
-
-	/* collect all three endpoints */
-	rv = usbnet_get_endpoints(dev, intf);
-	if (rv < 0)
-		goto err;
-
-	/* require interrupt endpoint for subdriver */
-	if (!dev->status) {
-		rv = -EINVAL;
-		goto err;
-	}
-
-	subdriver = usb_cdc_wdm_register(intf, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power);
-	if (IS_ERR(subdriver)) {
-		rv = PTR_ERR(subdriver);
-		goto err;
-	}
-
-	/* can't let usbnet use the interrupt endpoint */
-	dev->status = NULL;
-
-	/* save subdriver struct for suspend/resume wrappers */
-	dev->data[0] = (unsigned long)subdriver;
-
-err:
-	return rv;
-}
-
-/* Gobi devices uses identical class/protocol codes for all interfaces regardless
- * of function. Some of these are CDC ACM like and have the exact same endpoints
- * we are looking for. This leaves two possible strategies for identifying the
- * correct interface:
- *   a) hardcoding interface number, or
- *   b) use the fact that the wwan interface is the only one lacking additional
- *      (CDC functional) descriptors
- *
- * Let's see if we can get away with the generic b) solution.
- */
-static int qmi_wwan_bind_gobi(struct usbnet *dev, struct usb_interface *intf)
-{
-	int rv = -EINVAL;
+	/*  control and data is shared */
+	info->control = intf;
+	info->data = intf;
+	rv = qmi_wwan_register_subdriver(dev);
 
-	/* ignore any interface with additional descriptors */
-	if (intf->cur_altsetting->extralen)
-		goto err;
-
-	rv = qmi_wwan_bind_shared(dev, intf);
 err:
 	return rv;
 }
 
-static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *intf)
+static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf)
 {
-	struct usb_driver *subdriver = (void *)dev->data[0];
-
-	if (subdriver && subdriver->disconnect)
-		subdriver->disconnect(intf);
+	struct qmi_wwan_state *info = (void *)&dev->data;
+	struct usb_driver *driver = driver_of(intf);
+	struct usb_interface *other;
+
+	if (info->subdriver && info->subdriver->disconnect)
+		info->subdriver->disconnect(info->control);
+
+	/* allow user to unbind using either control or data */
+	if (intf == info->control)
+		other = info->data;
+	else
+		other = info->control;
+
+	/* only if not shared */
+	if (other && intf != other) {
+		usb_set_intfdata(other, NULL);
+		usb_driver_release_interface(driver, other);
+	}
 
-	dev->data[0] = (unsigned long)NULL;
+	info->subdriver = NULL;
+	info->data = NULL;
+	info->control = NULL;
 }
 
 /* suspend/resume wrappers calling both usbnet and the cdc-wdm
@@ -299,15 +304,15 @@ static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *int
 static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct usbnet *dev = usb_get_intfdata(intf);
-	struct usb_driver *subdriver = (void *)dev->data[0];
+	struct qmi_wwan_state *info = (void *)&dev->data;
 	int ret;
 
 	ret = usbnet_suspend(intf, message);
 	if (ret < 0)
 		goto err;
 
-	if (subdriver && subdriver->suspend)
-		ret = subdriver->suspend(intf, message);
+	if (info->subdriver && info->subdriver->suspend)
+		ret = info->subdriver->suspend(intf, message);
 	if (ret < 0)
 		usbnet_resume(intf);
 err:
@@ -317,59 +322,68 @@ err:
 static int qmi_wwan_resume(struct usb_interface *intf)
 {
 	struct usbnet *dev = usb_get_intfdata(intf);
-	struct usb_driver *subdriver = (void *)dev->data[0];
+	struct qmi_wwan_state *info = (void *)&dev->data;
 	int ret = 0;
 
-	if (subdriver && subdriver->resume)
-		ret = subdriver->resume(intf);
+	if (info->subdriver && info->subdriver->resume)
+		ret = info->subdriver->resume(intf);
 	if (ret < 0)
 		goto err;
 	ret = usbnet_resume(intf);
-	if (ret < 0 && subdriver && subdriver->resume && subdriver->suspend)
-		subdriver->suspend(intf, PMSG_SUSPEND);
+	if (ret < 0 && info->subdriver && info->subdriver->resume && info->subdriver->suspend)
+		info->subdriver->suspend(intf, PMSG_SUSPEND);
 err:
 	return ret;
 }
 
-
 static const struct driver_info	qmi_wwan_info = {
-	.description	= "QMI speaking wwan device",
+	.description	= "WWAN/QMI device",
 	.flags		= FLAG_WWAN,
 	.bind		= qmi_wwan_bind,
+	.unbind		= qmi_wwan_unbind,
 	.manage_power	= qmi_wwan_manage_power,
 };
 
 static const struct driver_info	qmi_wwan_shared = {
-	.description	= "QMI speaking wwan device with combined interface",
+	.description	= "WWAN/QMI device",
 	.flags		= FLAG_WWAN,
 	.bind		= qmi_wwan_bind_shared,
-	.unbind		= qmi_wwan_unbind_shared,
+	.unbind		= qmi_wwan_unbind,
 	.manage_power	= qmi_wwan_manage_power,
 };
 
-static const struct driver_info	qmi_wwan_gobi = {
-	.description	= "Qualcomm Gobi wwan/QMI device",
+static const struct driver_info	qmi_wwan_force_int0 = {
+	.description	= "Qualcomm WWAN/QMI device",
 	.flags		= FLAG_WWAN,
-	.bind		= qmi_wwan_bind_gobi,
-	.unbind		= qmi_wwan_unbind_shared,
+	.bind		= qmi_wwan_bind_shared,
+	.unbind		= qmi_wwan_unbind,
 	.manage_power	= qmi_wwan_manage_power,
+	.data		= BIT(0), /* interface whitelist bitmap */
 };
 
-/* ZTE suck at making USB descriptors */
 static const struct driver_info	qmi_wwan_force_int1 = {
 	.description	= "Qualcomm WWAN/QMI device",
 	.flags		= FLAG_WWAN,
 	.bind		= qmi_wwan_bind_shared,
-	.unbind		= qmi_wwan_unbind_shared,
+	.unbind		= qmi_wwan_unbind,
 	.manage_power	= qmi_wwan_manage_power,
 	.data		= BIT(1), /* interface whitelist bitmap */
 };
 
+static const struct driver_info	qmi_wwan_force_int3 = {
+	.description	= "Qualcomm WWAN/QMI device",
+	.flags		= FLAG_WWAN,
+	.bind		= qmi_wwan_bind_shared,
+	.unbind		= qmi_wwan_unbind,
+	.manage_power	= qmi_wwan_manage_power,
+	.data		= BIT(3), /* interface whitelist bitmap */
+};
+
 static const struct driver_info	qmi_wwan_force_int4 = {
 	.description	= "Qualcomm WWAN/QMI device",
 	.flags		= FLAG_WWAN,
 	.bind		= qmi_wwan_bind_shared,
-	.unbind		= qmi_wwan_unbind_shared,
+	.unbind		= qmi_wwan_unbind,
 	.manage_power	= qmi_wwan_manage_power,
 	.data		= BIT(4), /* interface whitelist bitmap */
 };
@@ -390,16 +404,23 @@ static const struct driver_info	qmi_wwan_force_int4 = {
 static const struct driver_info	qmi_wwan_sierra = {
 	.description	= "Sierra Wireless wwan/QMI device",
 	.flags		= FLAG_WWAN,
-	.bind		= qmi_wwan_bind_gobi,
-	.unbind		= qmi_wwan_unbind_shared,
+	.bind		= qmi_wwan_bind_shared,
+	.unbind		= qmi_wwan_unbind,
 	.manage_power	= qmi_wwan_manage_power,
 	.data		= BIT(8) | BIT(19), /* interface whitelist bitmap */
 };
 
 #define HUAWEI_VENDOR_ID	0x12D1
+
+/* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */
+#define QMI_GOBI1K_DEVICE(vend, prod) \
+	USB_DEVICE(vend, prod), \
+	.driver_info = (unsigned long)&qmi_wwan_force_int3
+
+/* Gobi 2000 and Gobi 3000 QMI/wwan interface number is 0 according to qcserial */
 #define QMI_GOBI_DEVICE(vend, prod) \
 	USB_DEVICE(vend, prod), \
-	.driver_info = (unsigned long)&qmi_wwan_gobi
+	.driver_info = (unsigned long)&qmi_wwan_force_int0
 
 static const struct usb_device_id products[] = {
 	{	/* Huawei E392, E398 and possibly others sharing both device id and more... */
@@ -407,7 +428,7 @@ static const struct usb_device_id products[] = {
 		.idVendor           = HUAWEI_VENDOR_ID,
 		.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
 		.bInterfaceSubClass = 1,
-		.bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */
+		.bInterfaceProtocol = 9, /* CDC Ethernet *control* interface */
 		.driver_info        = (unsigned long)&qmi_wwan_info,
 	},
 	{	/* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */
@@ -415,7 +436,7 @@ static const struct usb_device_id products[] = {
 		.idVendor           = HUAWEI_VENDOR_ID,
 		.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
 		.bInterfaceSubClass = 1,
-		.bInterfaceProtocol = 56, /* NOTE: This is the *slave* interface of the CDC Union! */
+		.bInterfaceProtocol = 57, /* CDC Ethernet *control* interface */
 		.driver_info        = (unsigned long)&qmi_wwan_info,
 	},
 	{	/* Huawei E392, E398 and possibly others in "Windows mode"
@@ -510,20 +531,24 @@ static const struct usb_device_id products[] = {
 		.bInterfaceProtocol = 0xff,
 		.driver_info        = (unsigned long)&qmi_wwan_sierra,
 	},
-	{QMI_GOBI_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
-	{QMI_GOBI_DEVICE(0x03f0, 0x1f1d)},	/* HP un2400 Gobi Modem Device */
-	{QMI_GOBI_DEVICE(0x03f0, 0x371d)},	/* HP un2430 Mobile Broadband Module */
-	{QMI_GOBI_DEVICE(0x04da, 0x250d)},	/* Panasonic Gobi Modem device */
-	{QMI_GOBI_DEVICE(0x413c, 0x8172)},	/* Dell Gobi Modem device */
-	{QMI_GOBI_DEVICE(0x1410, 0xa001)},	/* Novatel Gobi Modem device */
-	{QMI_GOBI_DEVICE(0x0b05, 0x1776)},	/* Asus Gobi Modem device */
-	{QMI_GOBI_DEVICE(0x19d2, 0xfff3)},	/* ONDA Gobi Modem device */
-	{QMI_GOBI_DEVICE(0x05c6, 0x9001)},	/* Generic Gobi Modem device */
-	{QMI_GOBI_DEVICE(0x05c6, 0x9002)},	/* Generic Gobi Modem device */
-	{QMI_GOBI_DEVICE(0x05c6, 0x9202)},	/* Generic Gobi Modem device */
-	{QMI_GOBI_DEVICE(0x05c6, 0x9203)},	/* Generic Gobi Modem device */
-	{QMI_GOBI_DEVICE(0x05c6, 0x9222)},	/* Generic Gobi Modem device */
-	{QMI_GOBI_DEVICE(0x05c6, 0x9009)},	/* Generic Gobi Modem device */
+
+	/* Gobi 1000 devices */
+	{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
+	{QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)},	/* HP un2400 Gobi Modem Device */
+	{QMI_GOBI1K_DEVICE(0x03f0, 0x371d)},	/* HP un2430 Mobile Broadband Module */
+	{QMI_GOBI1K_DEVICE(0x04da, 0x250d)},	/* Panasonic Gobi Modem device */
+	{QMI_GOBI1K_DEVICE(0x413c, 0x8172)},	/* Dell Gobi Modem device */
+	{QMI_GOBI1K_DEVICE(0x1410, 0xa001)},	/* Novatel Gobi Modem device */
+	{QMI_GOBI1K_DEVICE(0x0b05, 0x1776)},	/* Asus Gobi Modem device */
+	{QMI_GOBI1K_DEVICE(0x19d2, 0xfff3)},	/* ONDA Gobi Modem device */
+	{QMI_GOBI1K_DEVICE(0x05c6, 0x9001)},	/* Generic Gobi Modem device */
+	{QMI_GOBI1K_DEVICE(0x05c6, 0x9002)},	/* Generic Gobi Modem device */
+	{QMI_GOBI1K_DEVICE(0x05c6, 0x9202)},	/* Generic Gobi Modem device */
+	{QMI_GOBI1K_DEVICE(0x05c6, 0x9203)},	/* Generic Gobi Modem device */
+	{QMI_GOBI1K_DEVICE(0x05c6, 0x9222)},	/* Generic Gobi Modem device */
+	{QMI_GOBI1K_DEVICE(0x05c6, 0x9009)},	/* Generic Gobi Modem device */
+
+	/* Gobi 2000 and 3000 devices */
 	{QMI_GOBI_DEVICE(0x413c, 0x8186)},	/* Dell Gobi 2000 Modem device (N0218, VU936) */
 	{QMI_GOBI_DEVICE(0x05c6, 0x920b)},	/* Generic Gobi 2000 Modem device */
 	{QMI_GOBI_DEVICE(0x05c6, 0x9225)},	/* Sony Gobi 2000 Modem device (N0279, VU730) */
@@ -565,17 +590,7 @@ static struct usb_driver qmi_wwan_driver = {
 	.disable_hub_initiated_lpm = 1,
 };
 
-static int __init qmi_wwan_init(void)
-{
-	return usb_register(&qmi_wwan_driver);
-}
-module_init(qmi_wwan_init);
-
-static void __exit qmi_wwan_exit(void)
-{
-	usb_deregister(&qmi_wwan_driver);
-}
-module_exit(qmi_wwan_exit);
+module_usb_driver(qmi_wwan_driver);
 
 MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>");
 MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver");
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 9f58330..e92c057 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -180,7 +180,40 @@ int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress)
 }
 EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr);
 
-static void intr_complete (struct urb *urb);
+static void intr_complete (struct urb *urb)
+{
+	struct usbnet	*dev = urb->context;
+	int		status = urb->status;
+
+	switch (status) {
+	/* success */
+	case 0:
+		dev->driver_info->status(dev, urb);
+		break;
+
+	/* software-driven interface shutdown */
+	case -ENOENT:		/* urb killed */
+	case -ESHUTDOWN:	/* hardware gone */
+		netif_dbg(dev, ifdown, dev->net,
+			  "intr shutdown, code %d\n", status);
+		return;
+
+	/* NOTE:  not throttling like RX/TX, since this endpoint
+	 * already polls infrequently
+	 */
+	default:
+		netdev_dbg(dev->net, "intr status %d\n", status);
+		break;
+	}
+
+	if (!netif_running (dev->net))
+		return;
+
+	status = usb_submit_urb (urb, GFP_ATOMIC);
+	if (status != 0)
+		netif_err(dev, timer, dev->net,
+			  "intr resubmit --> %d\n", status);
+}
 
 static int init_status (struct usbnet *dev, struct usb_interface *intf)
 {
@@ -519,42 +552,6 @@ block:
 	netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n");
 }
 
-static void intr_complete (struct urb *urb)
-{
-	struct usbnet	*dev = urb->context;
-	int		status = urb->status;
-
-	switch (status) {
-	/* success */
-	case 0:
-		dev->driver_info->status(dev, urb);
-		break;
-
-	/* software-driven interface shutdown */
-	case -ENOENT:		/* urb killed */
-	case -ESHUTDOWN:	/* hardware gone */
-		netif_dbg(dev, ifdown, dev->net,
-			  "intr shutdown, code %d\n", status);
-		return;
-
-	/* NOTE:  not throttling like RX/TX, since this endpoint
-	 * already polls infrequently
-	 */
-	default:
-		netdev_dbg(dev->net, "intr status %d\n", status);
-		break;
-	}
-
-	if (!netif_running (dev->net))
-		return;
-
-	memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
-	status = usb_submit_urb (urb, GFP_ATOMIC);
-	if (status != 0)
-		netif_err(dev, timer, dev->net,
-			  "intr resubmit --> %d\n", status);
-}
-
 /*-------------------------------------------------------------------------*/
 void usbnet_pause_rx(struct usbnet *dev)
 {
@@ -796,11 +793,13 @@ int usbnet_open (struct net_device *net)
 	if (info->manage_power) {
 		retval = info->manage_power(dev, 1);
 		if (retval < 0)
-			goto done;
+			goto done_manage_power_error;
 		usb_autopm_put_interface(dev->intf);
 	}
 	return retval;
 
+done_manage_power_error:
+	clear_bit(EVENT_DEV_OPEN, &dev->flags);
 done:
 	usb_autopm_put_interface(dev->intf);
 done_nopm:
@@ -876,9 +875,9 @@ void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
 {
 	struct usbnet *dev = netdev_priv(net);
 
-	strncpy (info->driver, dev->driver_name, sizeof info->driver);
-	strncpy (info->version, DRIVER_VERSION, sizeof info->version);
-	strncpy (info->fw_version, dev->driver_info->description,
+	strlcpy (info->driver, dev->driver_name, sizeof info->driver);
+	strlcpy (info->version, DRIVER_VERSION, sizeof info->version);
+	strlcpy (info->fw_version, dev->driver_info->description,
 		sizeof info->fw_version);
 	usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info);
 }
@@ -1202,6 +1201,21 @@ deferred:
 }
 EXPORT_SYMBOL_GPL(usbnet_start_xmit);
 
+static void rx_alloc_submit(struct usbnet *dev, gfp_t flags)
+{
+	struct urb	*urb;
+	int		i;
+
+	/* don't refill the queue all at once */
+	for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) {
+		urb = usb_alloc_urb(0, flags);
+		if (urb != NULL) {
+			if (rx_submit(dev, urb, flags) == -ENOLINK)
+				return;
+		}
+	}
+}
+
 /*-------------------------------------------------------------------------*/
 
 // tasklet (work deferred from completions, in_irq) or timer
@@ -1241,26 +1255,14 @@ static void usbnet_bh (unsigned long param)
 		   !timer_pending (&dev->delay) &&
 		   !test_bit (EVENT_RX_HALT, &dev->flags)) {
 		int	temp = dev->rxq.qlen;
-		int	qlen = RX_QLEN (dev);
-
-		if (temp < qlen) {
-			struct urb	*urb;
-			int		i;
-
-			// don't refill the queue all at once
-			for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) {
-				urb = usb_alloc_urb (0, GFP_ATOMIC);
-				if (urb != NULL) {
-					if (rx_submit (dev, urb, GFP_ATOMIC) ==
-					    -ENOLINK)
-						return;
-				}
-			}
+
+		if (temp < RX_QLEN(dev)) {
+			rx_alloc_submit(dev, GFP_ATOMIC);
 			if (temp != dev->rxq.qlen)
 				netif_dbg(dev, link, dev->net,
 					  "rxqlen %d --> %d\n",
 					  temp, dev->rxq.qlen);
-			if (dev->rxq.qlen < qlen)
+			if (dev->rxq.qlen < RX_QLEN(dev))
 				tasklet_schedule (&dev->bh);
 		}
 		if (dev->txq.qlen < TX_QLEN (dev))
@@ -1307,7 +1309,6 @@ void usbnet_disconnect (struct usb_interface *intf)
 	usb_free_urb(dev->interrupt);
 
 	free_netdev(net);
-	usb_put_dev (xdev);
 }
 EXPORT_SYMBOL_GPL(usbnet_disconnect);
 
@@ -1363,8 +1364,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 	xdev = interface_to_usbdev (udev);
 	interface = udev->cur_altsetting;
 
-	usb_get_dev (xdev);
-
 	status = -ENOMEM;
 
 	// set up our own records
@@ -1493,7 +1492,6 @@ out3:
 out1:
 	free_netdev(net);
 out:
-	usb_put_dev(xdev);
 	return status;
 }
 EXPORT_SYMBOL_GPL(usbnet_probe);
@@ -1513,6 +1511,7 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
 		spin_lock_irq(&dev->txq.lock);
 		/* don't autosuspend while transmitting */
 		if (dev->txq.qlen && PMSG_IS_AUTO(message)) {
+			dev->suspend_count--;
 			spin_unlock_irq(&dev->txq.lock);
 			return -EBUSY;
 		} else {
@@ -1569,6 +1568,13 @@ int usbnet_resume (struct usb_interface *intf)
 		spin_unlock_irq(&dev->txq.lock);
 
 		if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
+			/* handle remote wakeup ASAP */
+			if (!dev->wait &&
+				netif_device_present(dev->net) &&
+				!timer_pending(&dev->delay) &&
+				!test_bit(EVENT_RX_HALT, &dev->flags))
+					rx_alloc_submit(dev, GFP_KERNEL);
+
 			if (!(dev->txq.qlen >= TX_QLEN(dev)))
 				netif_tx_wake_all_queues(dev->net);
 			tasklet_schedule (&dev->bh);
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 3f04ba0..93e0cfb 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1037,7 +1037,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
 #endif
 	dev_dbg(&adapter->netdev->dev,
 		"txd[%u]: SOP 0x%Lx 0x%x 0x%x\n",
-		(u32)((union Vmxnet3_GenericDesc *)ctx.sop_txd -
+		(u32)(ctx.sop_txd -
 		tq->tx_ring.base), le64_to_cpu(gdesc->txd.addr),
 		le32_to_cpu(gdesc->dword[2]), le32_to_cpu(gdesc->dword[3]));
 
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index d7a65e1..44db8b7 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -231,7 +231,7 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len)
 	}
 
 	p = icp;
-	count = x25_asy_esc(p, (unsigned char *) sl->xbuff, len);
+	count = x25_asy_esc(p, sl->xbuff, len);
 
 	/* Order of next two lines is *very* important.
 	 * When we are sending a little amount of data,
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 7cbd7d2..d09e449 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -1268,7 +1268,7 @@ int i2400m_fw_check(struct i2400m *i2400m, const void *bcf, size_t bcf_size)
 		size_t leftover, offset, header_len, size;
 
 		leftover = top - itr;
-		offset = itr - (const void *) bcf;
+		offset = itr - bcf;
 		if (leftover <= sizeof(*bcf_hdr)) {
 			dev_err(dev, "firmware %s: %zu B left at @%zx, "
 				"not enough for BCF header\n",
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 0ac09a2..97afcec 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -1738,8 +1738,7 @@ static int adm8211_alloc_rings(struct ieee80211_hw *dev)
 		return -ENOMEM;
 	}
 
-	priv->tx_ring = (struct adm8211_desc *)(priv->rx_ring +
-						priv->rx_ring_size);
+	priv->tx_ring = priv->rx_ring + priv->rx_ring_size;
 	priv->tx_ring_dma = priv->rx_ring_dma +
 			    sizeof(struct adm8211_desc) * priv->rx_ring_size;
 
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 520a4b2..f9f15bb 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1997,7 +1997,7 @@ static int mpi_send_packet (struct net_device *dev)
  *                         ------------------------------------------------
  */
 
-	memcpy((char *)ai->txfids[0].virtual_host_addr,
+	memcpy(ai->txfids[0].virtual_host_addr,
 		(char *)&wifictlhdr8023, sizeof(wifictlhdr8023));
 
 	payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr +
@@ -4212,7 +4212,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
 			airo_print_err(ai->dev->name, "%s: len=%d", __func__, len);
 			rc = -1;
 		} else {
-			memcpy((char *)ai->config_desc.virtual_host_addr,
+			memcpy(ai->config_desc.virtual_host_addr,
 				pBuf, len);
 
 			rc = issuecommand(ai, &cmd, &rsp);
@@ -7233,8 +7233,8 @@ static int airo_get_aplist(struct net_device *dev,
 		}
 	} else {
 		dwrq->flags = 1; /* Should be define'd */
-		memcpy(extra + sizeof(struct sockaddr)*i,
-		       &qual,  sizeof(struct iw_quality)*i);
+		memcpy(extra + sizeof(struct sockaddr) * i, qual,
+		       sizeof(struct iw_quality) * i);
 	}
 	dwrq->length = i;
 
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index c54b7d37..420d69b 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -143,6 +143,7 @@ struct ath_common {
 	u32 keymax;
 	DECLARE_BITMAP(keymap, ATH_KEYMAX);
 	DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX);
+	DECLARE_BITMAP(ccmp_keymap, ATH_KEYMAX);
 	enum ath_crypt_caps crypt_caps;
 
 	unsigned int clockrate;
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index fbaa309..44ad6fe 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1045,11 +1045,11 @@ ath5k_drain_tx_buffs(struct ath5k_hw *ah)
 
 				ath5k_txbuf_free_skb(ah, bf);
 
-				spin_lock_bh(&ah->txbuflock);
+				spin_lock(&ah->txbuflock);
 				list_move_tail(&bf->list, &ah->txbuf);
 				ah->txbuf_len++;
 				txq->txq_len--;
-				spin_unlock_bh(&ah->txbuflock);
+				spin_unlock(&ah->txbuflock);
 			}
 			txq->link = NULL;
 			txq->txq_poll_mark = false;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index b869a35..fd7dbd4 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -53,6 +53,11 @@
 
 #define DEFAULT_BG_SCAN_PERIOD 60
 
+struct ath6kl_cfg80211_match_probe_ssid {
+	struct cfg80211_ssid ssid;
+	u8 flag;
+};
+
 static struct ieee80211_rate ath6kl_rates[] = {
 	RATETAB_ENT(10, 0x1, 0),
 	RATETAB_ENT(20, 0x2, 0),
@@ -576,6 +581,9 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 
 	vif->nw_type = vif->next_mode;
 
+	/* enable enhanced bmiss detection if applicable */
+	ath6kl_cfg80211_sta_bmiss_enhance(vif, true);
+
 	if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
 		nw_subtype = SUBTYPE_P2PCLIENT;
 
@@ -852,20 +860,6 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
 		}
 	}
 
-	/*
-	 * Send a disconnect command to target when a disconnect event is
-	 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
-	 * request from host) to make the firmware stop trying to connect even
-	 * after giving disconnect event. There will be one more disconnect
-	 * event for this disconnect command with reason code DISCONNECT_CMD
-	 * which will be notified to cfg80211.
-	 */
-
-	if (reason != DISCONNECT_CMD) {
-		ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
-		return;
-	}
-
 	clear_bit(CONNECT_PEND, &vif->flags);
 
 	if (vif->sme_state == SME_CONNECTING) {
@@ -875,32 +869,96 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
 					WLAN_STATUS_UNSPECIFIED_FAILURE,
 					GFP_KERNEL);
 	} else if (vif->sme_state == SME_CONNECTED) {
-		cfg80211_disconnected(vif->ndev, reason,
+		cfg80211_disconnected(vif->ndev, proto_reason,
 				      NULL, 0, GFP_KERNEL);
 	}
 
 	vif->sme_state = SME_DISCONNECTED;
+
+	/*
+	 * Send a disconnect command to target when a disconnect event is
+	 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
+	 * request from host) to make the firmware stop trying to connect even
+	 * after giving disconnect event. There will be one more disconnect
+	 * event for this disconnect command with reason code DISCONNECT_CMD
+	 * which won't be notified to cfg80211.
+	 */
+	if (reason != DISCONNECT_CMD)
+		ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
 }
 
 static int ath6kl_set_probed_ssids(struct ath6kl *ar,
 				   struct ath6kl_vif *vif,
-				   struct cfg80211_ssid *ssids, int n_ssids)
+				   struct cfg80211_ssid *ssids, int n_ssids,
+				   struct cfg80211_match_set *match_set,
+				   int n_match_ssid)
 {
-	u8 i;
+	u8 i, j, index_to_add, ssid_found = false;
+	struct ath6kl_cfg80211_match_probe_ssid ssid_list[MAX_PROBED_SSIDS];
 
-	if (n_ssids > MAX_PROBED_SSID_INDEX)
+	memset(ssid_list, 0, sizeof(ssid_list));
+
+	if (n_ssids > MAX_PROBED_SSIDS ||
+	    n_match_ssid > MAX_PROBED_SSIDS)
 		return -EINVAL;
 
 	for (i = 0; i < n_ssids; i++) {
+		memcpy(ssid_list[i].ssid.ssid,
+		       ssids[i].ssid,
+		       ssids[i].ssid_len);
+		ssid_list[i].ssid.ssid_len = ssids[i].ssid_len;
+
+		if (ssids[i].ssid_len)
+			ssid_list[i].flag = SPECIFIC_SSID_FLAG;
+		else
+			ssid_list[i].flag = ANY_SSID_FLAG;
+
+		if (n_match_ssid == 0)
+			ssid_list[i].flag |= MATCH_SSID_FLAG;
+	}
+
+	index_to_add = i;
+
+	for (i = 0; i < n_match_ssid; i++) {
+		ssid_found = false;
+
+		for (j = 0; j < n_ssids; j++) {
+			if ((match_set[i].ssid.ssid_len ==
+			     ssid_list[j].ssid.ssid_len) &&
+			    (!memcmp(ssid_list[j].ssid.ssid,
+				     match_set[i].ssid.ssid,
+				     match_set[i].ssid.ssid_len))) {
+				ssid_list[j].flag |= MATCH_SSID_FLAG;
+				ssid_found = true;
+				break;
+			}
+		}
+
+		if (ssid_found)
+			continue;
+
+		if (index_to_add >= MAX_PROBED_SSIDS)
+			continue;
+
+		ssid_list[index_to_add].ssid.ssid_len =
+			match_set[i].ssid.ssid_len;
+		memcpy(ssid_list[index_to_add].ssid.ssid,
+		       match_set[i].ssid.ssid,
+		       match_set[i].ssid.ssid_len);
+		ssid_list[index_to_add].flag |= MATCH_SSID_FLAG;
+		index_to_add++;
+	}
+
+	for (i = 0; i < index_to_add; i++) {
 		ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
-					  ssids[i].ssid_len ?
-					  SPECIFIC_SSID_FLAG : ANY_SSID_FLAG,
-					  ssids[i].ssid_len,
-					  ssids[i].ssid);
+					  ssid_list[i].flag,
+					  ssid_list[i].ssid.ssid_len,
+					  ssid_list[i].ssid.ssid);
+
 	}
 
 	/* Make sure no old entries are left behind */
-	for (i = n_ssids; i < MAX_PROBED_SSID_INDEX; i++) {
+	for (i = index_to_add; i < MAX_PROBED_SSIDS; i++) {
 		ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
 					  DISABLE_SSID_FLAG, 0, NULL);
 	}
@@ -934,7 +992,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
 	}
 
 	ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
-				      request->n_ssids);
+				      request->n_ssids, NULL, 0);
 	if (ret < 0)
 		return ret;
 
@@ -943,7 +1001,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
 				       WMI_FRAME_PROBE_REQ,
 				       request->ie, request->ie_len);
 	if (ret) {
-		ath6kl_err("failed to set Probe Request appie for scan");
+		ath6kl_err("failed to set Probe Request appie for scan\n");
 		return ret;
 	}
 
@@ -1512,6 +1570,9 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
 		}
 	}
 
+	/* need to clean up enhanced bmiss detection fw state */
+	ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
+
 set_iface_type:
 	switch (type) {
 	case NL80211_IFTYPE_STATION:
@@ -2074,7 +2135,9 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
 	if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
 		return -EINVAL;
 
-	if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) {
+	if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) &&
+	    test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+		     ar->fw_capabilities)) {
 		ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
 						vif->fw_vif_idx, false);
 		if (ret)
@@ -2209,7 +2272,9 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
 
 	ar->state = ATH6KL_STATE_ON;
 
-	if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) {
+	if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) &&
+	    test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+		     ar->fw_capabilities)) {
 		ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
 					vif->fw_vif_idx, true);
 		if (ret)
@@ -2475,7 +2540,7 @@ void ath6kl_check_wow_status(struct ath6kl *ar)
 static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band,
 			    bool ht_enable)
 {
-	struct ath6kl_htcap *htcap = &vif->htcap;
+	struct ath6kl_htcap *htcap = &vif->htcap[band];
 
 	if (htcap->ht_enable == ht_enable)
 		return 0;
@@ -2585,33 +2650,28 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
 	return 0;
 }
 
-static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
-			      struct ieee80211_channel *chan,
-			      enum nl80211_channel_type channel_type)
+void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable)
 {
-	struct ath6kl_vif *vif;
+	int err;
 
-	/*
-	 * 'dev' could be NULL if a channel change is required for the hardware
-	 * device itself, instead of a particular VIF.
-	 *
-	 * FIXME: To be handled properly when monitor mode is supported.
-	 */
-	if (!dev)
-		return -EBUSY;
+	if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
+		return;
 
-	vif = netdev_priv(dev);
+	if (vif->nw_type != INFRA_NETWORK)
+		return;
 
-	if (!ath6kl_cfg80211_ready(vif))
-		return -EIO;
+	if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
+		      vif->ar->fw_capabilities))
+		return;
 
-	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
-		   __func__, chan->center_freq, chan->hw_value);
-	vif->next_chan = chan->center_freq;
-	vif->next_ch_type = channel_type;
-	vif->next_ch_band = chan->band;
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
+		   enable ? "enable" : "disable");
 
-	return 0;
+	err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
+					       vif->fw_vif_idx, enable);
+	if (err)
+		ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
+			   enable ? "enable" : "disable", err);
 }
 
 static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
@@ -2694,9 +2754,15 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
 
 	/* TODO:
 	 * info->interval
-	 * info->dtim_period
 	 */
 
+	ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx,
+					 info->dtim_period);
+
+	/* ignore error, just print a warning and continue normally */
+	if (ret)
+		ath6kl_warn("Failed to set dtim_period in beacon: %d\n", ret);
+
 	if (info->beacon.head == NULL)
 		return -EINVAL;
 	mgmt = (struct ieee80211_mgmt *) info->beacon.head;
@@ -2791,7 +2857,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
 	p.ssid_len = vif->ssid_len;
 	memcpy(p.ssid, vif->ssid, vif->ssid_len);
 	p.dot11_auth_mode = vif->dot11_auth_mode;
-	p.ch = cpu_to_le16(vif->next_chan);
+	p.ch = cpu_to_le16(info->channel->center_freq);
 
 	/* Enable uAPSD support by default */
 	res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
@@ -2815,8 +2881,8 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
 			return res;
 	}
 
-	if (ath6kl_set_htcap(vif, vif->next_ch_band,
-			     vif->next_ch_type != NL80211_CHAN_NO_HT))
+	if (ath6kl_set_htcap(vif, info->channel->band,
+			     info->channel_type != NL80211_CHAN_NO_HT))
 		return -EIO;
 
 	/*
@@ -3160,10 +3226,24 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
 	ath6kl_cfg80211_scan_complete_event(vif, true);
 
 	ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
-				      request->n_ssids);
+				      request->n_ssids,
+				      request->match_sets,
+				      request->n_match_sets);
 	if (ret < 0)
 		return ret;
 
+	if (!request->n_match_sets) {
+		ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
+					       ALL_BSS_FILTER, 0);
+		if (ret < 0)
+			return ret;
+	} else {
+		 ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
+						MATCHED_SSID_FILTER, 0);
+		if (ret < 0)
+			return ret;
+	}
+
 	/* fw uses seconds, also make sure that it's >0 */
 	interval = max_t(u16, 1, request->interval / 1000);
 
@@ -3185,7 +3265,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
 				       WMI_FRAME_PROBE_REQ,
 				       request->ie, request->ie_len);
 	if (ret) {
-		ath6kl_warn("Failed to set probe request IE for scheduled scan: %d",
+		ath6kl_warn("Failed to set probe request IE for scheduled scan: %d\n",
 			    ret);
 		return ret;
 	}
@@ -3217,6 +3297,18 @@ static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
 	return 0;
 }
 
+static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
+				       struct net_device *dev,
+				       const u8 *addr,
+				       const struct cfg80211_bitrate_mask *mask)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+	struct ath6kl_vif *vif = netdev_priv(dev);
+
+	return ath6kl_wmi_set_bitrate_mask(ar->wmi, vif->fw_vif_idx,
+					   mask);
+}
+
 static const struct ieee80211_txrx_stypes
 ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
 	[NL80211_IFTYPE_STATION] = {
@@ -3271,7 +3363,6 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
 	.suspend = __ath6kl_cfg80211_suspend,
 	.resume = __ath6kl_cfg80211_resume,
 #endif
-	.set_channel = ath6kl_set_channel,
 	.start_ap = ath6kl_start_ap,
 	.change_beacon = ath6kl_change_beacon,
 	.stop_ap = ath6kl_stop_ap,
@@ -3283,6 +3374,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
 	.mgmt_frame_register = ath6kl_mgmt_frame_register,
 	.sched_scan_start = ath6kl_cfg80211_sscan_start,
 	.sched_scan_stop = ath6kl_cfg80211_sscan_stop,
+	.set_bitrate_mask = ath6kl_cfg80211_set_bitrate,
 };
 
 void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
@@ -3410,7 +3502,8 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
 	vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
 	vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
 	vif->bg_scan_period = 0;
-	vif->htcap.ht_enable = true;
+	vif->htcap[IEEE80211_BAND_2GHZ].ht_enable = true;
+	vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true;
 
 	memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
 	if (fw_vif_idx != 0)
@@ -3470,7 +3563,13 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
 	}
 
 	/* max num of ssids that can be probed during scanning */
-	wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
+	wiphy->max_scan_ssids = MAX_PROBED_SSIDS;
+
+	/* max num of ssids that can be matched after scan */
+	if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
+		     ar->fw_capabilities))
+		wiphy->max_match_sets = MAX_PROBED_SSIDS;
+
 	wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
 	switch (ar->hw.cap) {
 	case WMI_11AN_CAP:
@@ -3507,6 +3606,17 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
 		ath6kl_band_5ghz.ht_cap.cap = 0;
 		ath6kl_band_5ghz.ht_cap.ht_supported = false;
 	}
+
+	if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) {
+		ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+		ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+		ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
+		ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff;
+	} else {
+		ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+		ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+	}
+
 	if (band_2gig)
 		wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
 	if (band_5gig)
@@ -3527,7 +3637,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
 	wiphy->wowlan.pattern_min_len = 1;
 	wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
 
-	wiphy->max_sched_scan_ssids = MAX_PROBED_SSID_INDEX;
+	wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS;
 
 	ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
 			    WIPHY_FLAG_HAVE_AP_SME |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
index 5ea8cbb..b992046 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.h
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -62,5 +62,7 @@ void ath6kl_cfg80211_cleanup(struct ath6kl *ar);
 
 struct ath6kl *ath6kl_cfg80211_create(void);
 void ath6kl_cfg80211_destroy(struct ath6kl *ar);
+/* TODO: remove this once ath6kl_vif_cleanup() is moved to cfg80211.c */
+void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable);
 
 #endif /* ATH6KL_CFG80211_H */
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 4d9c6f1..d38a31d 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -100,6 +100,21 @@ enum ath6kl_fw_capability {
 	/* Firmware has support to override rsn cap of rsn ie */
 	ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
 
+	/*
+	 * Multicast support in WOW and host awake mode.
+	 * Allow all multicast in host awake mode.
+	 * Apply multicast filter in WOW mode.
+	 */
+	ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+
+	/* Firmware supports enhanced bmiss detection */
+	ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
+
+	/*
+	 * FW supports matching of ssid in schedule scan
+	 */
+	ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
+
 	/* this needs to be last */
 	ATH6KL_FW_CAPABILITY_MAX,
 };
@@ -112,6 +127,10 @@ struct ath6kl_fw_ie {
 	u8 data[0];
 };
 
+enum ath6kl_hw_flags {
+	ATH6KL_HW_FLAG_64BIT_RATES	= BIT(0),
+};
+
 #define ATH6KL_FW_API2_FILE "fw-2.bin"
 #define ATH6KL_FW_API3_FILE "fw-3.bin"
 
@@ -196,7 +215,7 @@ struct ath6kl_fw_ie {
 
 #define AGGR_NUM_OF_FREE_NETBUFS    16
 
-#define AGGR_RX_TIMEOUT     400	/* in ms */
+#define AGGR_RX_TIMEOUT     100	/* in ms */
 
 #define WMI_TIMEOUT (2 * HZ)
 
@@ -245,7 +264,6 @@ struct skb_hold_q {
 
 struct rxtid {
 	bool aggr;
-	bool progress;
 	bool timer_mon;
 	u16 win_sz;
 	u16 seq_next;
@@ -254,9 +272,15 @@ struct rxtid {
 	struct sk_buff_head q;
 
 	/*
-	 * FIXME: No clue what this should protect. Apparently it should
-	 * protect some of the fields above but they are also accessed
-	 * without taking the lock.
+	 * lock mainly protects seq_next and hold_q. Movement of seq_next
+	 * needs to be protected between aggr_timeout() and
+	 * aggr_process_recv_frm(). hold_q will be holding the pending
+	 * reorder frames and it's access should also be protected.
+	 * Some of the other fields like hold_q_sz, win_sz and aggr are
+	 * initialized/reset when receiving addba/delba req, also while
+	 * deleting aggr state all the pending buffers are flushed before
+	 * resetting these fields, so there should not be any race in accessing
+	 * these fields.
 	 */
 	spinlock_t lock;
 };
@@ -541,7 +565,7 @@ struct ath6kl_vif {
 	struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
 	struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
 	struct aggr_info *aggr_cntxt;
-	struct ath6kl_htcap htcap;
+	struct ath6kl_htcap htcap[IEEE80211_NUM_BANDS];
 
 	struct timer_list disconnect_timer;
 	struct timer_list sched_scan_timer;
@@ -553,9 +577,6 @@ struct ath6kl_vif {
 	u32 last_cancel_roc_id;
 	u32 send_action_id;
 	bool probe_req_report;
-	u16 next_chan;
-	enum nl80211_channel_type next_ch_type;
-	enum ieee80211_band next_ch_band;
 	u16 assoc_bss_beacon_int;
 	u16 listen_intvl_t;
 	u16 bmiss_time_t;
@@ -687,6 +708,8 @@ struct ath6kl {
 		u32 testscript_addr;
 		enum wmi_phy_cap cap;
 
+		u32 flags;
+
 		struct ath6kl_hw_fw {
 			const char *dir;
 			const char *otp;
diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c
index 2798624d..cd0e1ba 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c
@@ -1309,7 +1309,7 @@ static int ath6kl_htc_rx_packet(struct htc_target *target,
 	}
 
 	ath6kl_dbg(ATH6KL_DBG_HTC,
-		   "htc rx 0x%p hdr x%x len %d mbox 0x%x\n",
+		   "htc rx 0x%p hdr 0x%x len %d mbox 0x%x\n",
 		   packet, packet->info.rx.exp_hdr,
 		   padded_len, dev->ar->mbox_info.htc_addr);
 
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 7eb0515..f90b5db 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -42,6 +42,7 @@ static const struct ath6kl_hw hw_list[] = {
 		.reserved_ram_size		= 6912,
 		.refclk_hz			= 26000000,
 		.uarttx_pin			= 8,
+		.flags				= 0,
 
 		/* hw2.0 needs override address hardcoded */
 		.app_start_override_addr	= 0x944C00,
@@ -67,6 +68,7 @@ static const struct ath6kl_hw hw_list[] = {
 		.refclk_hz			= 26000000,
 		.uarttx_pin			= 8,
 		.testscript_addr		= 0x57ef74,
+		.flags				= 0,
 
 		.fw = {
 			.dir		= AR6003_HW_2_1_1_FW_DIR,
@@ -91,6 +93,7 @@ static const struct ath6kl_hw hw_list[] = {
 		.board_addr			= 0x433900,
 		.refclk_hz			= 26000000,
 		.uarttx_pin			= 11,
+		.flags				= ATH6KL_HW_FLAG_64BIT_RATES,
 
 		.fw = {
 			.dir		= AR6004_HW_1_0_FW_DIR,
@@ -110,6 +113,7 @@ static const struct ath6kl_hw hw_list[] = {
 		.board_addr			= 0x43d400,
 		.refclk_hz			= 40000000,
 		.uarttx_pin			= 11,
+		.flags				= ATH6KL_HW_FLAG_64BIT_RATES,
 
 		.fw = {
 			.dir		= AR6004_HW_1_1_FW_DIR,
@@ -129,6 +133,7 @@ static const struct ath6kl_hw hw_list[] = {
 		.board_addr			= 0x435c00,
 		.refclk_hz			= 40000000,
 		.uarttx_pin			= 11,
+		.flags				= ATH6KL_HW_FLAG_64BIT_RATES,
 
 		.fw = {
 			.dir		= AR6004_HW_1_2_FW_DIR,
@@ -938,6 +943,14 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
 		}
 
 		switch (ie_id) {
+		case ATH6KL_FW_IE_FW_VERSION:
+			strlcpy(ar->wiphy->fw_version, data,
+				sizeof(ar->wiphy->fw_version));
+
+			ath6kl_dbg(ATH6KL_DBG_BOOT,
+				   "found fw version %s\n",
+				    ar->wiphy->fw_version);
+			break;
 		case ATH6KL_FW_IE_OTP_IMAGE:
 			ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n",
 				   ie_len);
@@ -991,9 +1004,6 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
 				   ar->hw.reserved_ram_size);
 			break;
 		case ATH6KL_FW_IE_CAPABILITIES:
-			if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8))
-				break;
-
 			ath6kl_dbg(ATH6KL_DBG_BOOT,
 				   "found firmware capabilities ie (%zd B)\n",
 				   ie_len);
@@ -1002,6 +1012,9 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
 				index = i / 8;
 				bit = i % 8;
 
+				if (index == ie_len)
+					break;
+
 				if (data[index] & (1 << bit))
 					__set_bit(i, ar->fw_capabilities);
 			}
@@ -1392,6 +1405,12 @@ static int ath6kl_init_upload(struct ath6kl *ar)
 	    ar->version.target_ver == AR6003_HW_2_1_1_VERSION) {
 		ath6kl_err("temporary war to avoid sdio crc error\n");
 
+		param = 0x28;
+		address = GPIO_BASE_ADDRESS + GPIO_PIN9_ADDRESS;
+		status = ath6kl_bmi_reg_write(ar, address, param);
+		if (status)
+			return status;
+
 		param = 0x20;
 
 		address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;
@@ -1659,6 +1678,9 @@ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
 		cfg80211_scan_done(vif->scan_req, true);
 		vif->scan_req = NULL;
 	}
+
+	/* need to clean up enhanced bmiss detection fw state */
+	ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
 }
 
 void ath6kl_stop_txrx(struct ath6kl *ar)
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index e552447..c189e28 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -554,20 +554,24 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver,
 	struct ath6kl *ar = devt;
 
 	memcpy(ar->mac_addr, datap, ETH_ALEN);
-	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: mac addr = %pM\n",
-		   __func__, ar->mac_addr);
+
+	ath6kl_dbg(ATH6KL_DBG_BOOT,
+		   "ready event mac addr %pM sw_ver 0x%x abi_ver 0x%x cap 0x%x\n",
+		   ar->mac_addr, sw_ver, abi_ver, cap);
 
 	ar->version.wlan_ver = sw_ver;
 	ar->version.abi_ver = abi_ver;
 	ar->hw.cap = cap;
 
-	snprintf(ar->wiphy->fw_version,
-		 sizeof(ar->wiphy->fw_version),
-		 "%u.%u.%u.%u",
-		 (ar->version.wlan_ver & 0xf0000000) >> 28,
-		 (ar->version.wlan_ver & 0x0f000000) >> 24,
-		 (ar->version.wlan_ver & 0x00ff0000) >> 16,
-		 (ar->version.wlan_ver & 0x0000ffff));
+	if (strlen(ar->wiphy->fw_version) == 0) {
+		snprintf(ar->wiphy->fw_version,
+			 sizeof(ar->wiphy->fw_version),
+			 "%u.%u.%u.%u",
+			 (ar->version.wlan_ver & 0xf0000000) >> 28,
+			 (ar->version.wlan_ver & 0x0f000000) >> 24,
+			 (ar->version.wlan_ver & 0x00ff0000) >> 16,
+			 (ar->version.wlan_ver & 0x0000ffff));
+	}
 
 	/* indicate to the waiting thread that the ready event was received */
 	set_bit(WMI_READY, &ar->flag);
@@ -598,7 +602,6 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
 
 	struct ath6kl *ar = vif->ar;
 
-	vif->next_chan = channel;
 	vif->profile.ch = cpu_to_le16(channel);
 
 	switch (vif->nw_type) {
@@ -1167,7 +1170,10 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
 	else
 		clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
 
-	mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
+	if (test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+		     vif->ar->fw_capabilities)) {
+		mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
+	}
 
 	if (!(ndev->flags & IFF_MULTICAST)) {
 		mc_all_on = false;
diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h
index 78e0ef4..a98c12b 100644
--- a/drivers/net/wireless/ath/ath6kl/target.h
+++ b/drivers/net/wireless/ath/ath6kl/target.h
@@ -45,6 +45,7 @@
 #define LPO_CAL_ENABLE_S		20
 #define LPO_CAL_ENABLE			0x00100000
 
+#define GPIO_PIN9_ADDRESS		0x0000004c
 #define GPIO_PIN10_ADDRESS		0x00000050
 #define GPIO_PIN11_ADDRESS		0x00000054
 #define GPIO_PIN12_ADDRESS		0x00000058
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
index 67206ae..7dfa0fd 100644
--- a/drivers/net/wireless/ath/ath6kl/txrx.c
+++ b/drivers/net/wireless/ath/ath6kl/txrx.c
@@ -1036,6 +1036,7 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
 	rxtid = &agg_conn->rx_tid[tid];
 	stats = &agg_conn->stat[tid];
 
+	spin_lock_bh(&rxtid->lock);
 	idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
 
 	/*
@@ -1054,8 +1055,6 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
 	seq_end = seq_no ? seq_no : rxtid->seq_next;
 	idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz);
 
-	spin_lock_bh(&rxtid->lock);
-
 	do {
 		node = &rxtid->hold_q[idx];
 		if ((order == 1) && (!node->skb))
@@ -1127,11 +1126,13 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
 		    ((end > extended_end) && (cur > extended_end) &&
 		     (cur < end))) {
 			aggr_deque_frms(agg_conn, tid, 0, 0);
+			spin_lock_bh(&rxtid->lock);
 			if (cur >= rxtid->hold_q_sz - 1)
 				rxtid->seq_next = cur - (rxtid->hold_q_sz - 1);
 			else
 				rxtid->seq_next = ATH6KL_MAX_SEQ_NO -
 						  (rxtid->hold_q_sz - 2 - cur);
+			spin_unlock_bh(&rxtid->lock);
 		} else {
 			/*
 			 * Dequeue only those frames that are outside the
@@ -1185,25 +1186,25 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
 	aggr_deque_frms(agg_conn, tid, 0, 1);
 
 	if (agg_conn->timer_scheduled)
-		rxtid->progress = true;
-	else
-		for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
-			if (rxtid->hold_q[idx].skb) {
-				/*
-				 * There is a frame in the queue and no
-				 * timer so start a timer to ensure that
-				 * the frame doesn't remain stuck
-				 * forever.
-				 */
-				agg_conn->timer_scheduled = true;
-				mod_timer(&agg_conn->timer,
-					  (jiffies +
-					   HZ * (AGGR_RX_TIMEOUT) / 1000));
-				rxtid->progress = false;
-				rxtid->timer_mon = true;
-				break;
-			}
+		return is_queued;
+
+	spin_lock_bh(&rxtid->lock);
+	for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
+		if (rxtid->hold_q[idx].skb) {
+			/*
+			 * There is a frame in the queue and no
+			 * timer so start a timer to ensure that
+			 * the frame doesn't remain stuck
+			 * forever.
+			 */
+			agg_conn->timer_scheduled = true;
+			mod_timer(&agg_conn->timer,
+				  (jiffies + (HZ * AGGR_RX_TIMEOUT) / 1000));
+			rxtid->timer_mon = true;
+			break;
 		}
+	}
+	spin_unlock_bh(&rxtid->lock);
 
 	return is_queued;
 }
@@ -1608,7 +1609,7 @@ static void aggr_timeout(unsigned long arg)
 		rxtid = &aggr_conn->rx_tid[i];
 		stats = &aggr_conn->stat[i];
 
-		if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress)
+		if (!rxtid->aggr || !rxtid->timer_mon)
 			continue;
 
 		stats->num_timeouts++;
@@ -1626,14 +1627,15 @@ static void aggr_timeout(unsigned long arg)
 		rxtid = &aggr_conn->rx_tid[i];
 
 		if (rxtid->aggr && rxtid->hold_q) {
+			spin_lock_bh(&rxtid->lock);
 			for (j = 0; j < rxtid->hold_q_sz; j++) {
 				if (rxtid->hold_q[j].skb) {
 					aggr_conn->timer_scheduled = true;
 					rxtid->timer_mon = true;
-					rxtid->progress = false;
 					break;
 				}
 			}
+			spin_unlock_bh(&rxtid->lock);
 
 			if (j >= rxtid->hold_q_sz)
 				rxtid->timer_mon = false;
@@ -1660,7 +1662,6 @@ static void aggr_delete_tid_state(struct aggr_info_conn *aggr_conn, u8 tid)
 		aggr_deque_frms(aggr_conn, tid, 0, 0);
 
 	rxtid->aggr = false;
-	rxtid->progress = false;
 	rxtid->timer_mon = false;
 	rxtid->win_sz = 0;
 	rxtid->seq_next = 0;
@@ -1739,7 +1740,6 @@ void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info,
 	for (i = 0; i < NUM_OF_TIDS; i++) {
 		rxtid = &aggr_conn->rx_tid[i];
 		rxtid->aggr = false;
-		rxtid->progress = false;
 		rxtid->timer_mon = false;
 		skb_queue_head_init(&rxtid->q);
 		spin_lock_init(&rxtid->lock);
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index ee8ec23..a6caa67 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -743,7 +743,6 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
 		return -ENOMEM;
 
 	cmd = (struct roam_ctrl_cmd *) skb->data;
-	memset(cmd, 0, sizeof(*cmd));
 
 	memcpy(cmd->info.bssid, bssid, ETH_ALEN);
 	cmd->roam_ctrl = WMI_FORCE_ROAM;
@@ -753,6 +752,22 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
 				   NO_SYNC_WMIFLAG);
 }
 
+int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period)
+{
+	struct sk_buff *skb;
+	struct set_dtim_cmd *cmd;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct set_dtim_cmd *) skb->data;
+
+	cmd->dtim_period = cpu_to_le32(dtim_period);
+	return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+				   WMI_AP_SET_DTIM_CMDID, NO_SYNC_WMIFLAG);
+}
+
 int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
 {
 	struct sk_buff *skb;
@@ -763,7 +778,6 @@ int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
 		return -ENOMEM;
 
 	cmd = (struct roam_ctrl_cmd *) skb->data;
-	memset(cmd, 0, sizeof(*cmd));
 
 	cmd->info.roam_mode = mode;
 	cmd->roam_ctrl = WMI_SET_ROAM_MODE;
@@ -1995,7 +2009,7 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag,
 	struct wmi_probed_ssid_cmd *cmd;
 	int ret;
 
-	if (index > MAX_PROBED_SSID_INDEX)
+	if (index >= MAX_PROBED_SSIDS)
 		return -EINVAL;
 
 	if (ssid_len > sizeof(cmd->ssid))
@@ -2599,6 +2613,115 @@ static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi)
 	spin_unlock_bh(&wmi->lock);
 }
 
+static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
+				     const struct cfg80211_bitrate_mask *mask)
+{
+	struct sk_buff *skb;
+	int ret, mode, band;
+	u64 mcsrate, ratemask[IEEE80211_NUM_BANDS];
+	struct wmi_set_tx_select_rates64_cmd *cmd;
+
+	memset(&ratemask, 0, sizeof(ratemask));
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		/* copy legacy rate mask */
+		ratemask[band] = mask->control[band].legacy;
+		if (band == IEEE80211_BAND_5GHZ)
+			ratemask[band] =
+				mask->control[band].legacy << 4;
+
+		/* copy mcs rate mask */
+		mcsrate = mask->control[band].mcs[1];
+		mcsrate <<= 8;
+		mcsrate |= mask->control[band].mcs[0];
+		ratemask[band] |= mcsrate << 12;
+		ratemask[band] |= mcsrate << 28;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_WMI,
+		   "Ratemask 64 bit: 2.4:%llx 5:%llx\n",
+		   ratemask[0], ratemask[1]);
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_set_tx_select_rates64_cmd *) skb->data;
+	for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
+		/* A mode operate in 5GHZ band */
+		if (mode == WMI_RATES_MODE_11A ||
+		    mode == WMI_RATES_MODE_11A_HT20 ||
+		    mode == WMI_RATES_MODE_11A_HT40)
+			band = IEEE80211_BAND_5GHZ;
+		else
+			band = IEEE80211_BAND_2GHZ;
+		cmd->ratemask[mode] = cpu_to_le64(ratemask[band]);
+	}
+
+	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+				  WMI_SET_TX_SELECT_RATES_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
+				     const struct cfg80211_bitrate_mask *mask)
+{
+	struct sk_buff *skb;
+	int ret, mode, band;
+	u32 mcsrate, ratemask[IEEE80211_NUM_BANDS];
+	struct wmi_set_tx_select_rates32_cmd *cmd;
+
+	memset(&ratemask, 0, sizeof(ratemask));
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		/* copy legacy rate mask */
+		ratemask[band] = mask->control[band].legacy;
+		if (band == IEEE80211_BAND_5GHZ)
+			ratemask[band] =
+				mask->control[band].legacy << 4;
+
+		/* copy mcs rate mask */
+		mcsrate = mask->control[band].mcs[0];
+		ratemask[band] |= mcsrate << 12;
+		ratemask[band] |= mcsrate << 20;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_WMI,
+		   "Ratemask 32 bit: 2.4:%x 5:%x\n",
+		   ratemask[0], ratemask[1]);
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_set_tx_select_rates32_cmd *) skb->data;
+	for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
+		/* A mode operate in 5GHZ band */
+		if (mode == WMI_RATES_MODE_11A ||
+		    mode == WMI_RATES_MODE_11A_HT20 ||
+		    mode == WMI_RATES_MODE_11A_HT40)
+			band = IEEE80211_BAND_5GHZ;
+		else
+			band = IEEE80211_BAND_2GHZ;
+		cmd->ratemask[mode] = cpu_to_le32(ratemask[band]);
+	}
+
+	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+				  WMI_SET_TX_SELECT_RATES_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
+				const struct cfg80211_bitrate_mask *mask)
+{
+	struct ath6kl *ar = wmi->parent_dev;
+
+	if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES)
+		return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);
+	else
+		return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);
+}
+
 int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
 				       enum ath6kl_host_mode host_mode)
 {
@@ -2997,6 +3120,25 @@ int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
 	return ret;
 }
 
+int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance)
+{
+	struct sk_buff *skb;
+	struct wmi_sta_bmiss_enhance_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_sta_bmiss_enhance_cmd *) skb->data;
+	cmd->enable = enhance ? 1 : 0;
+
+	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+				  WMI_STA_BMISS_ENHANCE_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
 s32 ath6kl_wmi_get_rate(s8 rate_index)
 {
 	if (rate_index == RATE_AUTO)
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 9076bec..43339ac 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -624,6 +624,10 @@ enum wmi_cmd_id {
 	WMI_SEND_MGMT_CMDID,
 	WMI_BEGIN_SCAN_CMDID,
 
+	WMI_SET_BLACK_LIST,
+	WMI_SET_MCASTRATE,
+
+	WMI_STA_BMISS_ENHANCE_CMDID,
 };
 
 enum wmi_mgmt_frame_type {
@@ -960,6 +964,9 @@ enum wmi_bss_filter {
 	/* beacons matching probed ssid */
 	PROBED_SSID_FILTER,
 
+	/* beacons matching matched ssid */
+	MATCHED_SSID_FILTER,
+
 	/* marker only */
 	LAST_BSS_FILTER,
 };
@@ -978,7 +985,7 @@ struct wmi_bss_filter_cmd {
 } __packed;
 
 /* WMI_SET_PROBED_SSID_CMDID */
-#define MAX_PROBED_SSID_INDEX   9
+#define MAX_PROBED_SSIDS   16
 
 enum wmi_ssid_flag {
 	/* disables entry */
@@ -989,10 +996,13 @@ enum wmi_ssid_flag {
 
 	/* probes for any ssid */
 	ANY_SSID_FLAG = 0x02,
+
+	/* match for ssid */
+	MATCH_SSID_FLAG = 0x08,
 };
 
 struct wmi_probed_ssid_cmd {
-	/* 0 to MAX_PROBED_SSID_INDEX */
+	/* 0 to MAX_PROBED_SSIDS - 1 */
 	u8 entry_index;
 
 	/* see, enum wmi_ssid_flg */
@@ -1017,6 +1027,11 @@ struct wmi_bmiss_time_cmd {
 	__le16 num_beacons;
 };
 
+/* WMI_STA_ENHANCE_BMISS_CMDID */
+struct wmi_sta_bmiss_enhance_cmd {
+	u8 enable;
+} __packed;
+
 /* WMI_SET_POWER_MODE_CMDID */
 enum wmi_power_mode {
 	REC_POWER = 0x01,
@@ -1048,6 +1063,36 @@ struct wmi_power_params_cmd {
 	__le16 ps_fail_event_policy;
 } __packed;
 
+/*
+ * Ratemask for below modes should be passed
+ * to WMI_SET_TX_SELECT_RATES_CMDID.
+ * AR6003 has 32 bit mask for each modes.
+ * First 12 bits for legacy rates, 13 to 20
+ * bits for HT 20 rates and 21 to 28 bits for
+ * HT 40 rates
+ */
+enum wmi_mode_phy {
+	WMI_RATES_MODE_11A = 0,
+	WMI_RATES_MODE_11G,
+	WMI_RATES_MODE_11B,
+	WMI_RATES_MODE_11GONLY,
+	WMI_RATES_MODE_11A_HT20,
+	WMI_RATES_MODE_11G_HT20,
+	WMI_RATES_MODE_11A_HT40,
+	WMI_RATES_MODE_11G_HT40,
+	WMI_RATES_MODE_MAX
+};
+
+/* WMI_SET_TX_SELECT_RATES_CMDID */
+struct wmi_set_tx_select_rates32_cmd {
+	__le32 ratemask[WMI_RATES_MODE_MAX];
+} __packed;
+
+/* WMI_SET_TX_SELECT_RATES_CMDID */
+struct wmi_set_tx_select_rates64_cmd {
+	__le64 ratemask[WMI_RATES_MODE_MAX];
+} __packed;
+
 /* WMI_SET_DISC_TIMEOUT_CMDID */
 struct wmi_disc_timeout_cmd {
 	/* seconds */
@@ -1572,6 +1617,10 @@ struct roam_ctrl_cmd {
 	u8 roam_ctrl;
 } __packed;
 
+struct set_dtim_cmd {
+	__le32 dtim_period;
+} __packed;
+
 /* BSS INFO HDR version 2.0 */
 struct wmi_bss_info_hdr2 {
 	__le16 ch; /* frequency in MHz */
@@ -2532,6 +2581,8 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx,
 			  __be32 ips0, __be32 ips1);
 int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
 				       enum ath6kl_host_mode host_mode);
+int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
+				const struct cfg80211_bitrate_mask *mask);
 int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
 				enum ath6kl_wow_mode wow_mode,
 				u32 filter, u16 host_req_delay);
@@ -2542,11 +2593,14 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
 int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
 				   u16 list_id, u16 filter_id);
 int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
+int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);
 int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
 int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode);
 int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);
 int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
 					u8 *filter, bool add_filter);
+int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable);
+
 /* AP mode uAPSD */
 int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable);
 
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 3f0b8472..9c41232 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -3,7 +3,9 @@ ath9k-y +=	beacon.o \
 		init.o \
 		main.o \
 		recv.o \
-		xmit.o
+		xmit.o \
+		link.o \
+		antenna.o
 
 ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
 ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 5e47ca6..4a4e8a2 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -126,7 +126,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
 	sc->irq = irq;
 
 	/* Will be cleared in ath9k_start() */
-	sc->sc_flags |= SC_OP_INVALID;
+	set_bit(SC_OP_INVALID, &sc->sc_flags);
 
 	ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
 	if (ret) {
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index b4c77f9..7ebc346 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -104,11 +104,6 @@ static const struct ani_cck_level_entry cck_level_table[] = {
 #define ATH9K_ANI_CCK_DEF_LEVEL \
 	2 /* default level - matches the INI settings */
 
-static bool use_new_ani(struct ath_hw *ah)
-{
-	return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani;
-}
-
 static void ath9k_hw_update_mibstats(struct ath_hw *ah,
 				     struct ath9k_mib_stats *stats)
 {
@@ -122,8 +117,6 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah,
 static void ath9k_ani_restart(struct ath_hw *ah)
 {
 	struct ar5416AniState *aniState;
-	struct ath_common *common = ath9k_hw_common(ah);
-	u32 ofdm_base = 0, cck_base = 0;
 
 	if (!DO_ANI(ah))
 		return;
@@ -131,18 +124,10 @@ static void ath9k_ani_restart(struct ath_hw *ah)
 	aniState = &ah->curchan->ani;
 	aniState->listenTime = 0;
 
-	if (!use_new_ani(ah)) {
-		ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
-		cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
-	}
-
-	ath_dbg(common, ANI, "Writing ofdmbase=%u   cckbase=%u\n",
-		ofdm_base, cck_base);
-
 	ENABLE_REGWRITE_BUFFER(ah);
 
-	REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
-	REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
+	REG_WRITE(ah, AR_PHY_ERR_1, 0);
+	REG_WRITE(ah, AR_PHY_ERR_2, 0);
 	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);
 
@@ -154,110 +139,6 @@ static void ath9k_ani_restart(struct ath_hw *ah)
 	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;
-	int32_t rssi;
-
-	aniState = &ah->curchan->ani;
-
-	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
-		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-					 aniState->noiseImmunityLevel + 1)) {
-			return;
-		}
-	}
-
-	if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
-		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-					 aniState->spurImmunityLevel + 1)) {
-			return;
-		}
-	}
-
-	if (ah->opmode == NL80211_IFTYPE_AP) {
-		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-					     aniState->firstepLevel + 1);
-		}
-		return;
-	}
-	rssi = BEACON_RSSI(ah);
-	if (rssi > aniState->rssiThrHigh) {
-		if (!aniState->ofdmWeakSigDetectOff) {
-			if (ath9k_hw_ani_control(ah,
-					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-					 false)) {
-				ath9k_hw_ani_control(ah,
-					ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
-				return;
-			}
-		}
-		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-					     aniState->firstepLevel + 1);
-			return;
-		}
-	} else if (rssi > aniState->rssiThrLow) {
-		if (aniState->ofdmWeakSigDetectOff)
-			ath9k_hw_ani_control(ah,
-				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-				     true);
-		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
-			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-					     aniState->firstepLevel + 1);
-		return;
-	} else {
-		if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
-		    !conf_is_ht(conf)) {
-			if (!aniState->ofdmWeakSigDetectOff)
-				ath9k_hw_ani_control(ah,
-				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-				     false);
-			if (aniState->firstepLevel > 0)
-				ath9k_hw_ani_control(ah,
-					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
-			return;
-		}
-	}
-}
-
-static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
-{
-	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
-	struct ar5416AniState *aniState;
-	int32_t rssi;
-
-	aniState = &ah->curchan->ani;
-	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
-		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-					 aniState->noiseImmunityLevel + 1)) {
-			return;
-		}
-	}
-	if (ah->opmode == NL80211_IFTYPE_AP) {
-		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-					     aniState->firstepLevel + 1);
-		}
-		return;
-	}
-	rssi = BEACON_RSSI(ah);
-	if (rssi > aniState->rssiThrLow) {
-		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
-			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-					     aniState->firstepLevel + 1);
-	} else {
-		if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
-		    !conf_is_ht(conf)) {
-			if (aniState->firstepLevel > 0)
-				ath9k_hw_ani_control(ah,
-					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
-		}
-	}
-}
-
 /* Adjust the OFDM Noise Immunity Level */
 static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
 {
@@ -265,18 +146,15 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
 	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);
+	bool weak_sig;
 
 	ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
 		aniState->ofdmNoiseImmunityLevel,
-		immunityLevel, aniState->noiseFloor,
+		immunityLevel, BEACON_RSSI(ah),
 		aniState->rssiThrLow, aniState->rssiThrHigh);
 
 	if (aniState->update_ani)
-		aniState->ofdmNoiseImmunityLevel =
-			(immunityLevel > ATH9K_ANI_OFDM_DEF_LEVEL) ?
-			immunityLevel : ATH9K_ANI_OFDM_DEF_LEVEL;
+		aniState->ofdmNoiseImmunityLevel = immunityLevel;
 
 	entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
 	entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
@@ -292,12 +170,22 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
 				     ATH9K_ANI_FIRSTEP_LEVEL,
 				     entry_ofdm->fir_step_level);
 
-	if ((aniState->noiseFloor >= aniState->rssiThrHigh) &&
-	    (!aniState->ofdmWeakSigDetectOff !=
-	     entry_ofdm->ofdm_weak_signal_on)) {
+	weak_sig = entry_ofdm->ofdm_weak_signal_on;
+	if (ah->opmode == NL80211_IFTYPE_STATION &&
+	    BEACON_RSSI(ah) <= aniState->rssiThrHigh)
+		weak_sig = true;
+
+	if (aniState->ofdmWeakSigDetect != weak_sig)
 			ath9k_hw_ani_control(ah,
 				ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 				entry_ofdm->ofdm_weak_signal_on);
+
+	if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
+		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
+		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI;
+	} else {
+		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI;
+		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
 	}
 }
 
@@ -308,11 +196,6 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
 	if (!DO_ANI(ah))
 		return;
 
-	if (!use_new_ani(ah)) {
-		ath9k_hw_ani_ofdm_err_trigger_old(ah);
-		return;
-	}
-
 	aniState = &ah->curchan->ani;
 
 	if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
@@ -329,22 +212,18 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
 	const struct ani_ofdm_level_entry *entry_ofdm;
 	const struct ani_cck_level_entry *entry_cck;
 
-	aniState->noiseFloor = BEACON_RSSI(ah);
 	ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
 		aniState->cckNoiseImmunityLevel, immunityLevel,
-		aniState->noiseFloor, aniState->rssiThrLow,
+		BEACON_RSSI(ah), aniState->rssiThrLow,
 		aniState->rssiThrHigh);
 
-	if ((ah->opmode == NL80211_IFTYPE_STATION ||
-	     ah->opmode == NL80211_IFTYPE_ADHOC) &&
-	    aniState->noiseFloor <= aniState->rssiThrLow &&
+	if (ah->opmode == NL80211_IFTYPE_STATION &&
+	    BEACON_RSSI(ah) <= aniState->rssiThrLow &&
 	    immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
 		immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
 
 	if (aniState->update_ani)
-		aniState->cckNoiseImmunityLevel =
-			(immunityLevel > ATH9K_ANI_CCK_DEF_LEVEL) ?
-			immunityLevel : ATH9K_ANI_CCK_DEF_LEVEL;
+		aniState->cckNoiseImmunityLevel = immunityLevel;
 
 	entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
 	entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
@@ -359,7 +238,7 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
 	if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah))
 		return;
 
-	if (aniState->mrcCCKOff == entry_cck->mrc_cck_on)
+	if (aniState->mrcCCK != entry_cck->mrc_cck_on)
 		ath9k_hw_ani_control(ah,
 				     ATH9K_ANI_MRC_CCK,
 				     entry_cck->mrc_cck_on);
@@ -372,70 +251,12 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
 	if (!DO_ANI(ah))
 		return;
 
-	if (!use_new_ani(ah)) {
-		ath9k_hw_ani_cck_err_trigger_old(ah);
-		return;
-	}
-
 	aniState = &ah->curchan->ani;
 
 	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;
-
-	aniState = &ah->curchan->ani;
-
-	if (ah->opmode == NL80211_IFTYPE_AP) {
-		if (aniState->firstepLevel > 0) {
-			if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-						 aniState->firstepLevel - 1))
-				return;
-		}
-	} else {
-		rssi = BEACON_RSSI(ah);
-		if (rssi > aniState->rssiThrHigh) {
-			/* XXX: Handle me */
-		} else if (rssi > aniState->rssiThrLow) {
-			if (aniState->ofdmWeakSigDetectOff) {
-				if (ath9k_hw_ani_control(ah,
-					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-					 true))
-					return;
-			}
-			if (aniState->firstepLevel > 0) {
-				if (ath9k_hw_ani_control(ah,
-					 ATH9K_ANI_FIRSTEP_LEVEL,
-					 aniState->firstepLevel - 1))
-					return;
-			}
-		} else {
-			if (aniState->firstepLevel > 0) {
-				if (ath9k_hw_ani_control(ah,
-					 ATH9K_ANI_FIRSTEP_LEVEL,
-					 aniState->firstepLevel - 1))
-					return;
-			}
-		}
-	}
-
-	if (aniState->spurImmunityLevel > 0) {
-		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-					 aniState->spurImmunityLevel - 1))
-			return;
-	}
-
-	if (aniState->noiseImmunityLevel > 0) {
-		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-				     aniState->noiseImmunityLevel - 1);
-		return;
-	}
-}
-
 /*
  * only lower either OFDM or CCK errors per turn
  * we lower the other one next time
@@ -446,11 +267,6 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
 
 	aniState = &ah->curchan->ani;
 
-	if (!use_new_ani(ah)) {
-		ath9k_hw_ani_lower_immunity_old(ah);
-		return;
-	}
-
 	/* lower OFDM noise immunity */
 	if (aniState->ofdmNoiseImmunityLevel > 0 &&
 	    (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) {
@@ -463,72 +279,6 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
 		ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1);
 }
 
-static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
-{
-	struct ar5416AniState *aniState;
-	struct ath9k_channel *chan = ah->curchan;
-	struct ath_common *common = ath9k_hw_common(ah);
-
-	if (!DO_ANI(ah))
-		return;
-
-	aniState = &ah->curchan->ani;
-
-	if (ah->opmode != NL80211_IFTYPE_STATION
-	    && ah->opmode != NL80211_IFTYPE_ADHOC) {
-		ath_dbg(common, ANI, "Reset ANI state opmode %u\n", ah->opmode);
-		ah->stats.ast_ani_reset++;
-
-		if (ah->opmode == NL80211_IFTYPE_AP) {
-			/*
-			 * ath9k_hw_ani_control() will only process items set on
-			 * ah->ani_function
-			 */
-			if (IS_CHAN_2GHZ(chan))
-				ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
-						    ATH9K_ANI_FIRSTEP_LEVEL);
-			else
-				ah->ani_function = 0;
-		}
-
-		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
-		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
-		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
-		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-				     !ATH9K_ANI_USE_OFDM_WEAK_SIG);
-		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
-				     ATH9K_ANI_CCK_WEAK_SIG_THR);
-
-		ath9k_ani_restart(ah);
-		return;
-	}
-
-	if (aniState->noiseImmunityLevel != 0)
-		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-				     aniState->noiseImmunityLevel);
-	if (aniState->spurImmunityLevel != 0)
-		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-				     aniState->spurImmunityLevel);
-	if (aniState->ofdmWeakSigDetectOff)
-		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-				     !aniState->ofdmWeakSigDetectOff);
-	if (aniState->cckWeakSigThreshold)
-		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
-				     aniState->cckWeakSigThreshold);
-	if (aniState->firstepLevel != 0)
-		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-				     aniState->firstepLevel);
-
-	ath9k_ani_restart(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);
-}
-
 /*
  * Restore the ANI parameters in the HAL and reset the statistics.
  * This routine should be called for every hardware reset and for
@@ -539,13 +289,11 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
 	struct ar5416AniState *aniState = &ah->curchan->ani;
 	struct ath9k_channel *chan = ah->curchan;
 	struct ath_common *common = ath9k_hw_common(ah);
+	int ofdm_nil, cck_nil;
 
 	if (!DO_ANI(ah))
 		return;
 
-	if (!use_new_ani(ah))
-		return ath9k_ani_reset_old(ah, is_scanning);
-
 	BUG_ON(aniState == NULL);
 	ah->stats.ast_ani_reset++;
 
@@ -563,6 +311,11 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
 	/* always allow mode (on/off) to be controlled */
 	ah->ani_function |= ATH9K_ANI_MODE;
 
+	ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL,
+			 aniState->ofdmNoiseImmunityLevel);
+	cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL,
+			 aniState->cckNoiseImmunityLevel);
+
 	if (is_scanning ||
 	    (ah->opmode != NL80211_IFTYPE_STATION &&
 	     ah->opmode != NL80211_IFTYPE_ADHOC)) {
@@ -586,8 +339,8 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
 				aniState->cckNoiseImmunityLevel);
 
 			aniState->update_ani = false;
-			ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
-			ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
+			ofdm_nil = ATH9K_ANI_OFDM_DEF_LEVEL;
+			cck_nil = ATH9K_ANI_CCK_DEF_LEVEL;
 		}
 	} else {
 		/*
@@ -603,11 +356,9 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
 			aniState->cckNoiseImmunityLevel);
 
 			aniState->update_ani = true;
-			ath9k_hw_set_ofdm_nil(ah,
-					      aniState->ofdmNoiseImmunityLevel);
-			ath9k_hw_set_cck_nil(ah,
-					     aniState->cckNoiseImmunityLevel);
 	}
+	ath9k_hw_set_ofdm_nil(ah, ofdm_nil);
+	ath9k_hw_set_cck_nil(ah, cck_nil);
 
 	/*
 	 * enable phy counters if hw supports or if not, enable phy
@@ -627,9 +378,6 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ar5416AniState *aniState = &ah->curchan->ani;
-	u32 ofdm_base = 0;
-	u32 cck_base = 0;
-	u32 ofdmPhyErrCnt, cckPhyErrCnt;
 	u32 phyCnt1, phyCnt2;
 	int32_t listenTime;
 
@@ -642,11 +390,6 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
 		return false;
 	}
 
-	if (!use_new_ani(ah)) {
-		ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
-		cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
-	}
-
 	aniState->listenTime += listenTime;
 
 	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
@@ -654,35 +397,12 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
 	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
 	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
 
-	if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) {
-		if (phyCnt1 < ofdm_base) {
-			ath_dbg(common, ANI,
-				"phyCnt1 0x%x, resetting counter value to 0x%x\n",
-				phyCnt1, ofdm_base);
-			REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
-			REG_WRITE(ah, AR_PHY_ERR_MASK_1,
-				  AR_PHY_ERR_OFDM_TIMING);
-		}
-		if (phyCnt2 < cck_base) {
-			ath_dbg(common, ANI,
-				"phyCnt2 0x%x, resetting counter value to 0x%x\n",
-				phyCnt2, cck_base);
-			REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
-			REG_WRITE(ah, AR_PHY_ERR_MASK_2,
-				  AR_PHY_ERR_CCK_TIMING);
-		}
-		return false;
-	}
+	ah->stats.ast_ani_ofdmerrs += phyCnt1 - aniState->ofdmPhyErrCount;
+	aniState->ofdmPhyErrCount = phyCnt1;
 
-	ofdmPhyErrCnt = phyCnt1 - ofdm_base;
-	ah->stats.ast_ani_ofdmerrs +=
-		ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
-	aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+	ah->stats.ast_ani_cckerrs += phyCnt2 - aniState->cckPhyErrCount;
+	aniState->cckPhyErrCount = phyCnt2;
 
-	cckPhyErrCnt = phyCnt2 - cck_base;
-	ah->stats.ast_ani_cckerrs +=
-		cckPhyErrCnt - aniState->cckPhyErrCount;
-	aniState->cckPhyErrCount = cckPhyErrCnt;
 	return true;
 }
 
@@ -716,21 +436,10 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
 
 	if (aniState->listenTime > ah->aniperiod) {
 		if (cckPhyErrRate < ah->config.cck_trig_low &&
-		    ((ofdmPhyErrRate < ah->config.ofdm_trig_low &&
-		      aniState->ofdmNoiseImmunityLevel <
-		      ATH9K_ANI_OFDM_DEF_LEVEL) ||
-		     (ofdmPhyErrRate < ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI &&
-		      aniState->ofdmNoiseImmunityLevel >=
-		      ATH9K_ANI_OFDM_DEF_LEVEL))) {
+		    ofdmPhyErrRate < ah->config.ofdm_trig_low) {
 			ath9k_hw_ani_lower_immunity(ah);
 			aniState->ofdmsTurn = !aniState->ofdmsTurn;
-		} else if ((ofdmPhyErrRate > ah->config.ofdm_trig_high &&
-			    aniState->ofdmNoiseImmunityLevel >=
-			    ATH9K_ANI_OFDM_DEF_LEVEL) ||
-			   (ofdmPhyErrRate >
-			    ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI &&
-			    aniState->ofdmNoiseImmunityLevel <
-			    ATH9K_ANI_OFDM_DEF_LEVEL)) {
+		} else if (ofdmPhyErrRate > ah->config.ofdm_trig_high) {
 			ath9k_hw_ani_ofdm_err_trigger(ah);
 			aniState->ofdmsTurn = false;
 		} else if (cckPhyErrRate > ah->config.cck_trig_high) {
@@ -778,49 +487,6 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
 
-/*
- * Process a MIB interrupt.  We may potentially be invoked because
- * any of the MIB counters overflow/trigger so don't assume we're
- * here because a PHY error counter triggered.
- */
-void ath9k_hw_proc_mib_event(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);
-	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
-	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
-
-		if (!use_new_ani(ah))
-			ath9k_hw_ani_read_counters(ah);
-
-		/* NB: always restart to insure the h/w counters are reset */
-		ath9k_ani_restart(ah);
-	}
-}
-EXPORT_SYMBOL(ath9k_hw_proc_mib_event);
-
 void ath9k_hw_ani_setup(struct ath_hw *ah)
 {
 	int i;
@@ -845,50 +511,27 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
 
 	ath_dbg(common, ANI, "Initialize ANI\n");
 
-	if (use_new_ani(ah)) {
-		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
-		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
+	ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
+	ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
 
-		ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
-		ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW;
-	} else {
-		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
-		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
-
-		ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
-		ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
-	}
+	ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
+	ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
 
 	for (i = 0; i < ARRAY_SIZE(ah->channels); i++) {
 		struct ath9k_channel *chan = &ah->channels[i];
 		struct ar5416AniState *ani = &chan->ani;
 
-		if (use_new_ani(ah)) {
-			ani->spurImmunityLevel =
-				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+		ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
 
-			ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+		ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
 
-			if (AR_SREV_9300_20_OR_LATER(ah))
-				ani->mrcCCKOff =
-					!ATH9K_ANI_ENABLE_MRC_CCK;
-			else
-				ani->mrcCCKOff = true;
-
-			ani->ofdmsTurn = true;
-		} else {
-			ani->spurImmunityLevel =
-				ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
-			ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
-
-			ani->cckWeakSigThreshold =
-				ATH9K_ANI_CCK_WEAK_SIG_THR;
-		}
+		ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false;
+
+		ani->ofdmsTurn = true;
 
 		ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
 		ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
-		ani->ofdmWeakSigDetectOff =
-			!ATH9K_ANI_USE_OFDM_WEAK_SIG;
+		ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
 		ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
 		ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
 		ani->update_ani = false;
@@ -898,13 +541,8 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
 	 * since we expect some ongoing maintenance on the tables, let's sanity
 	 * check here default level should not modify INI setting.
 	 */
-	if (use_new_ani(ah)) {
-		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;
-	}
+	ah->aniperiod = ATH9K_ANI_PERIOD;
+	ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL;
 
 	if (ah->config.enable_ani)
 		ah->proc_phyerr |= HAL_PROCESS_ANI;
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index 72e2b87..e9d841b 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -24,42 +24,34 @@
 #define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
 
 /* units are errors per second */
-#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD      500
-#define ATH9K_ANI_OFDM_TRIG_HIGH_NEW      3500
+#define ATH9K_ANI_OFDM_TRIG_HIGH          3500
 #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000
 
 /* units are errors per second */
-#define ATH9K_ANI_OFDM_TRIG_LOW_OLD       200
-#define ATH9K_ANI_OFDM_TRIG_LOW_NEW       400
+#define ATH9K_ANI_OFDM_TRIG_LOW           400
 #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900
 
 /* units are errors per second */
-#define ATH9K_ANI_CCK_TRIG_HIGH_OLD       200
-#define ATH9K_ANI_CCK_TRIG_HIGH_NEW       600
+#define ATH9K_ANI_CCK_TRIG_HIGH           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_CCK_TRIG_LOW            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_OLD     7
-#define ATH9K_ANI_SPUR_IMMUNE_LVL_NEW     3
+#define ATH9K_ANI_SPUR_IMMUNE_LVL         3
 
-#define ATH9K_ANI_FIRSTEP_LVL_OLD         0
-#define ATH9K_ANI_FIRSTEP_LVL_NEW         2
+#define ATH9K_ANI_FIRSTEP_LVL             2
 
 #define ATH9K_ANI_RSSI_THR_HIGH           40
 #define ATH9K_ANI_RSSI_THR_LOW            7
 
-#define ATH9K_ANI_PERIOD_OLD              100
-#define ATH9K_ANI_PERIOD_NEW              300
+#define ATH9K_ANI_PERIOD                  300
 
 /* in ms */
-#define ATH9K_ANI_POLLINTERVAL_OLD        100
-#define ATH9K_ANI_POLLINTERVAL_NEW        1000
+#define ATH9K_ANI_POLLINTERVAL            1000
 
 #define HAL_NOISE_IMMUNE_MAX              4
 #define HAL_SPUR_IMMUNE_MAX               7
@@ -70,8 +62,6 @@
 #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 {
@@ -119,16 +109,15 @@ struct ar5416AniState {
 	u8 ofdmNoiseImmunityLevel;
 	u8 cckNoiseImmunityLevel;
 	bool ofdmsTurn;
-	u8 mrcCCKOff;
+	u8 mrcCCK;
 	u8 spurImmunityLevel;
 	u8 firstepLevel;
-	u8 ofdmWeakSigDetectOff;
+	u8 ofdmWeakSigDetect;
 	u8 cckWeakSigThreshold;
 	bool update_ani;
 	u32 listenTime;
 	int32_t rssiThrLow;
 	int32_t rssiThrHigh;
-	u32 noiseFloor;
 	u32 ofdmPhyErrCount;
 	u32 cckPhyErrCount;
 	int16_t pktRssi[2];
diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c
new file mode 100644
index 0000000..bbcfeb3
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/antenna.c
@@ -0,0 +1,776 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, 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 "ath9k.h"
+
+static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
+					       int mindelta, int main_rssi_avg,
+					       int alt_rssi_avg, int pkt_count)
+{
+	return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+		 (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
+		(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
+}
+
+static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
+					      int curr_main_set, int curr_alt_set,
+					      int alt_rssi_avg, int main_rssi_avg)
+{
+	bool result = false;
+	switch (div_group) {
+	case 0:
+		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+			result = true;
+		break;
+	case 1:
+	case 2:
+		if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
+		      (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
+		      (alt_rssi_avg >= (main_rssi_avg - 5))) ||
+		     ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
+		      (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
+		      (alt_rssi_avg >= (main_rssi_avg - 2)))) &&
+		    (alt_rssi_avg >= 4))
+			result = true;
+		else
+			result = false;
+		break;
+	}
+
+	return result;
+}
+
+static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
+				      struct ath_hw_antcomb_conf ant_conf,
+				      int main_rssi_avg)
+{
+	antcomb->quick_scan_cnt = 0;
+
+	if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
+		antcomb->rssi_lna2 = main_rssi_avg;
+	else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
+		antcomb->rssi_lna1 = main_rssi_avg;
+
+	switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
+	case 0x10: /* LNA2 A-B */
+		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+		antcomb->first_quick_scan_conf =
+			ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+		antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
+		break;
+	case 0x20: /* LNA1 A-B */
+		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+		antcomb->first_quick_scan_conf =
+			ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+		antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
+		break;
+	case 0x21: /* LNA1 LNA2 */
+		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
+		antcomb->first_quick_scan_conf =
+			ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+		antcomb->second_quick_scan_conf =
+			ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+		break;
+	case 0x12: /* LNA2 LNA1 */
+		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
+		antcomb->first_quick_scan_conf =
+			ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+		antcomb->second_quick_scan_conf =
+			ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+		break;
+	case 0x13: /* LNA2 A+B */
+		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+		antcomb->first_quick_scan_conf =
+			ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+		antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
+		break;
+	case 0x23: /* LNA1 A+B */
+		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+		antcomb->first_quick_scan_conf =
+			ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+		antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
+		break;
+	default:
+		break;
+	}
+}
+
+static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
+				       struct ath_hw_antcomb_conf *div_ant_conf,
+				       int main_rssi_avg, int alt_rssi_avg,
+				       int alt_ratio)
+{
+	/* alt_good */
+	switch (antcomb->quick_scan_cnt) {
+	case 0:
+		/* set alt to main, and alt to first conf */
+		div_ant_conf->main_lna_conf = antcomb->main_conf;
+		div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
+		break;
+	case 1:
+		/* set alt to main, and alt to first conf */
+		div_ant_conf->main_lna_conf = antcomb->main_conf;
+		div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
+		antcomb->rssi_first = main_rssi_avg;
+		antcomb->rssi_second = alt_rssi_avg;
+
+		if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+			/* main is LNA1 */
+			if (ath_is_alt_ant_ratio_better(alt_ratio,
+						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+						main_rssi_avg, alt_rssi_avg,
+						antcomb->total_pkt_count))
+				antcomb->first_ratio = true;
+			else
+				antcomb->first_ratio = false;
+		} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+			if (ath_is_alt_ant_ratio_better(alt_ratio,
+						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+						main_rssi_avg, alt_rssi_avg,
+						antcomb->total_pkt_count))
+				antcomb->first_ratio = true;
+			else
+				antcomb->first_ratio = false;
+		} else {
+			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+			      (alt_rssi_avg > main_rssi_avg +
+			       ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+			     (alt_rssi_avg > main_rssi_avg)) &&
+			    (antcomb->total_pkt_count > 50))
+				antcomb->first_ratio = true;
+			else
+				antcomb->first_ratio = false;
+		}
+		break;
+	case 2:
+		antcomb->alt_good = false;
+		antcomb->scan_not_start = false;
+		antcomb->scan = false;
+		antcomb->rssi_first = main_rssi_avg;
+		antcomb->rssi_third = alt_rssi_avg;
+
+		if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
+			antcomb->rssi_lna1 = alt_rssi_avg;
+		else if (antcomb->second_quick_scan_conf ==
+			 ATH_ANT_DIV_COMB_LNA2)
+			antcomb->rssi_lna2 = alt_rssi_avg;
+		else if (antcomb->second_quick_scan_conf ==
+			 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
+			if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
+				antcomb->rssi_lna2 = main_rssi_avg;
+			else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
+				antcomb->rssi_lna1 = main_rssi_avg;
+		}
+
+		if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
+		    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
+			div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+		else
+			div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+
+		if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+			if (ath_is_alt_ant_ratio_better(alt_ratio,
+						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+						main_rssi_avg, alt_rssi_avg,
+						antcomb->total_pkt_count))
+				antcomb->second_ratio = true;
+			else
+				antcomb->second_ratio = false;
+		} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+			if (ath_is_alt_ant_ratio_better(alt_ratio,
+						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+						main_rssi_avg, alt_rssi_avg,
+						antcomb->total_pkt_count))
+				antcomb->second_ratio = true;
+			else
+				antcomb->second_ratio = false;
+		} else {
+			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+			      (alt_rssi_avg > main_rssi_avg +
+			       ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+			     (alt_rssi_avg > main_rssi_avg)) &&
+			    (antcomb->total_pkt_count > 50))
+				antcomb->second_ratio = true;
+			else
+				antcomb->second_ratio = false;
+		}
+
+		/* set alt to the conf with maximun ratio */
+		if (antcomb->first_ratio && antcomb->second_ratio) {
+			if (antcomb->rssi_second > antcomb->rssi_third) {
+				/* first alt*/
+				if ((antcomb->first_quick_scan_conf ==
+				    ATH_ANT_DIV_COMB_LNA1) ||
+				    (antcomb->first_quick_scan_conf ==
+				    ATH_ANT_DIV_COMB_LNA2))
+					/* Set alt LNA1 or LNA2*/
+					if (div_ant_conf->main_lna_conf ==
+					    ATH_ANT_DIV_COMB_LNA2)
+						div_ant_conf->alt_lna_conf =
+							ATH_ANT_DIV_COMB_LNA1;
+					else
+						div_ant_conf->alt_lna_conf =
+							ATH_ANT_DIV_COMB_LNA2;
+				else
+					/* Set alt to A+B or A-B */
+					div_ant_conf->alt_lna_conf =
+						antcomb->first_quick_scan_conf;
+			} else if ((antcomb->second_quick_scan_conf ==
+				   ATH_ANT_DIV_COMB_LNA1) ||
+				   (antcomb->second_quick_scan_conf ==
+				   ATH_ANT_DIV_COMB_LNA2)) {
+				/* Set alt LNA1 or LNA2 */
+				if (div_ant_conf->main_lna_conf ==
+				    ATH_ANT_DIV_COMB_LNA2)
+					div_ant_conf->alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				else
+					div_ant_conf->alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+			} else {
+				/* Set alt to A+B or A-B */
+				div_ant_conf->alt_lna_conf =
+					antcomb->second_quick_scan_conf;
+			}
+		} else if (antcomb->first_ratio) {
+			/* first alt */
+			if ((antcomb->first_quick_scan_conf ==
+			    ATH_ANT_DIV_COMB_LNA1) ||
+			    (antcomb->first_quick_scan_conf ==
+			    ATH_ANT_DIV_COMB_LNA2))
+					/* Set alt LNA1 or LNA2 */
+				if (div_ant_conf->main_lna_conf ==
+				    ATH_ANT_DIV_COMB_LNA2)
+					div_ant_conf->alt_lna_conf =
+							ATH_ANT_DIV_COMB_LNA1;
+				else
+					div_ant_conf->alt_lna_conf =
+							ATH_ANT_DIV_COMB_LNA2;
+			else
+				/* Set alt to A+B or A-B */
+				div_ant_conf->alt_lna_conf =
+						antcomb->first_quick_scan_conf;
+		} else if (antcomb->second_ratio) {
+				/* second alt */
+			if ((antcomb->second_quick_scan_conf ==
+			    ATH_ANT_DIV_COMB_LNA1) ||
+			    (antcomb->second_quick_scan_conf ==
+			    ATH_ANT_DIV_COMB_LNA2))
+				/* Set alt LNA1 or LNA2 */
+				if (div_ant_conf->main_lna_conf ==
+				    ATH_ANT_DIV_COMB_LNA2)
+					div_ant_conf->alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				else
+					div_ant_conf->alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+			else
+				/* Set alt to A+B or A-B */
+				div_ant_conf->alt_lna_conf =
+						antcomb->second_quick_scan_conf;
+		} else {
+			/* main is largest */
+			if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
+			    (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
+				/* Set alt LNA1 or LNA2 */
+				if (div_ant_conf->main_lna_conf ==
+				    ATH_ANT_DIV_COMB_LNA2)
+					div_ant_conf->alt_lna_conf =
+							ATH_ANT_DIV_COMB_LNA1;
+				else
+					div_ant_conf->alt_lna_conf =
+							ATH_ANT_DIV_COMB_LNA2;
+			else
+				/* Set alt to A+B or A-B */
+				div_ant_conf->alt_lna_conf = antcomb->main_conf;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
+					  struct ath_ant_comb *antcomb,
+					  int alt_ratio)
+{
+	if (ant_conf->div_group == 0) {
+		/* Adjust the fast_div_bias based on main and alt lna conf */
+		switch ((ant_conf->main_lna_conf << 4) |
+				ant_conf->alt_lna_conf) {
+		case 0x01: /* A-B LNA2 */
+			ant_conf->fast_div_bias = 0x3b;
+			break;
+		case 0x02: /* A-B LNA1 */
+			ant_conf->fast_div_bias = 0x3d;
+			break;
+		case 0x03: /* A-B A+B */
+			ant_conf->fast_div_bias = 0x1;
+			break;
+		case 0x10: /* LNA2 A-B */
+			ant_conf->fast_div_bias = 0x7;
+			break;
+		case 0x12: /* LNA2 LNA1 */
+			ant_conf->fast_div_bias = 0x2;
+			break;
+		case 0x13: /* LNA2 A+B */
+			ant_conf->fast_div_bias = 0x7;
+			break;
+		case 0x20: /* LNA1 A-B */
+			ant_conf->fast_div_bias = 0x6;
+			break;
+		case 0x21: /* LNA1 LNA2 */
+			ant_conf->fast_div_bias = 0x0;
+			break;
+		case 0x23: /* LNA1 A+B */
+			ant_conf->fast_div_bias = 0x6;
+			break;
+		case 0x30: /* A+B A-B */
+			ant_conf->fast_div_bias = 0x1;
+			break;
+		case 0x31: /* A+B LNA2 */
+			ant_conf->fast_div_bias = 0x3b;
+			break;
+		case 0x32: /* A+B LNA1 */
+			ant_conf->fast_div_bias = 0x3d;
+			break;
+		default:
+			break;
+		}
+	} else if (ant_conf->div_group == 1) {
+		/* Adjust the fast_div_bias based on main and alt_lna_conf */
+		switch ((ant_conf->main_lna_conf << 4) |
+			ant_conf->alt_lna_conf) {
+		case 0x01: /* A-B LNA2 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x02: /* A-B LNA1 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x03: /* A-B A+B */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x10: /* LNA2 A-B */
+			if (!(antcomb->scan) &&
+			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+				ant_conf->fast_div_bias = 0x3f;
+			else
+				ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x12: /* LNA2 LNA1 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x13: /* LNA2 A+B */
+			if (!(antcomb->scan) &&
+			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+				ant_conf->fast_div_bias = 0x3f;
+			else
+				ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x20: /* LNA1 A-B */
+			if (!(antcomb->scan) &&
+			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+				ant_conf->fast_div_bias = 0x3f;
+			else
+				ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x21: /* LNA1 LNA2 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x23: /* LNA1 A+B */
+			if (!(antcomb->scan) &&
+			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+				ant_conf->fast_div_bias = 0x3f;
+			else
+				ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x30: /* A+B A-B */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x31: /* A+B LNA2 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x32: /* A+B LNA1 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		default:
+			break;
+		}
+	} else if (ant_conf->div_group == 2) {
+		/* Adjust the fast_div_bias based on main and alt_lna_conf */
+		switch ((ant_conf->main_lna_conf << 4) |
+				ant_conf->alt_lna_conf) {
+		case 0x01: /* A-B LNA2 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x02: /* A-B LNA1 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x03: /* A-B A+B */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x10: /* LNA2 A-B */
+			if (!(antcomb->scan) &&
+				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+				ant_conf->fast_div_bias = 0x1;
+			else
+				ant_conf->fast_div_bias = 0x2;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x12: /* LNA2 LNA1 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x13: /* LNA2 A+B */
+			if (!(antcomb->scan) &&
+				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+				ant_conf->fast_div_bias = 0x1;
+			else
+				ant_conf->fast_div_bias = 0x2;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x20: /* LNA1 A-B */
+			if (!(antcomb->scan) &&
+				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+				ant_conf->fast_div_bias = 0x1;
+			else
+				ant_conf->fast_div_bias = 0x2;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x21: /* LNA1 LNA2 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x23: /* LNA1 A+B */
+			if (!(antcomb->scan) &&
+				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+				ant_conf->fast_div_bias = 0x1;
+			else
+				ant_conf->fast_div_bias = 0x2;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x30: /* A+B A-B */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x31: /* A+B LNA2 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		case 0x32: /* A+B LNA1 */
+			ant_conf->fast_div_bias = 0x1;
+			ant_conf->main_gaintb = 0;
+			ant_conf->alt_gaintb = 0;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
+{
+	struct ath_hw_antcomb_conf div_ant_conf;
+	struct ath_ant_comb *antcomb = &sc->ant_comb;
+	int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
+	int curr_main_set;
+	int main_rssi = rs->rs_rssi_ctl0;
+	int alt_rssi = rs->rs_rssi_ctl1;
+	int rx_ant_conf,  main_ant_conf;
+	bool short_scan = false;
+
+	rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
+		       ATH_ANT_RX_MASK;
+	main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
+			 ATH_ANT_RX_MASK;
+
+	/* Record packet only when both main_rssi and  alt_rssi is positive */
+	if (main_rssi > 0 && alt_rssi > 0) {
+		antcomb->total_pkt_count++;
+		antcomb->main_total_rssi += main_rssi;
+		antcomb->alt_total_rssi  += alt_rssi;
+		if (main_ant_conf == rx_ant_conf)
+			antcomb->main_recv_cnt++;
+		else
+			antcomb->alt_recv_cnt++;
+	}
+
+	/* Short scan check */
+	if (antcomb->scan && antcomb->alt_good) {
+		if (time_after(jiffies, antcomb->scan_start_time +
+		    msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
+			short_scan = true;
+		else
+			if (antcomb->total_pkt_count ==
+			    ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
+				alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+					    antcomb->total_pkt_count);
+				if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+					short_scan = true;
+			}
+	}
+
+	if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
+	    rs->rs_moreaggr) && !short_scan)
+		return;
+
+	if (antcomb->total_pkt_count) {
+		alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+			     antcomb->total_pkt_count);
+		main_rssi_avg = (antcomb->main_total_rssi /
+				 antcomb->total_pkt_count);
+		alt_rssi_avg = (antcomb->alt_total_rssi /
+				 antcomb->total_pkt_count);
+	}
+
+
+	ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
+	curr_alt_set = div_ant_conf.alt_lna_conf;
+	curr_main_set = div_ant_conf.main_lna_conf;
+
+	antcomb->count++;
+
+	if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
+		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
+			ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
+						  main_rssi_avg);
+			antcomb->alt_good = true;
+		} else {
+			antcomb->alt_good = false;
+		}
+
+		antcomb->count = 0;
+		antcomb->scan = true;
+		antcomb->scan_not_start = true;
+	}
+
+	if (!antcomb->scan) {
+		if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
+					alt_ratio, curr_main_set, curr_alt_set,
+					alt_rssi_avg, main_rssi_avg)) {
+			if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
+				/* Switch main and alt LNA */
+				div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+				div_ant_conf.alt_lna_conf  =
+						ATH_ANT_DIV_COMB_LNA1;
+			} else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
+				div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				div_ant_conf.alt_lna_conf  =
+						ATH_ANT_DIV_COMB_LNA2;
+			}
+
+			goto div_comb_done;
+		} else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
+			   (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
+			/* Set alt to another LNA */
+			if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
+				div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+			else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
+				div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+
+			goto div_comb_done;
+		}
+
+		if ((alt_rssi_avg < (main_rssi_avg +
+				     div_ant_conf.lna1_lna2_delta)))
+			goto div_comb_done;
+	}
+
+	if (!antcomb->scan_not_start) {
+		switch (curr_alt_set) {
+		case ATH_ANT_DIV_COMB_LNA2:
+			antcomb->rssi_lna2 = alt_rssi_avg;
+			antcomb->rssi_lna1 = main_rssi_avg;
+			antcomb->scan = true;
+			/* set to A+B */
+			div_ant_conf.main_lna_conf =
+				ATH_ANT_DIV_COMB_LNA1;
+			div_ant_conf.alt_lna_conf  =
+				ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+			break;
+		case ATH_ANT_DIV_COMB_LNA1:
+			antcomb->rssi_lna1 = alt_rssi_avg;
+			antcomb->rssi_lna2 = main_rssi_avg;
+			antcomb->scan = true;
+			/* set to A+B */
+			div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+			div_ant_conf.alt_lna_conf  =
+				ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+			break;
+		case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
+			antcomb->rssi_add = alt_rssi_avg;
+			antcomb->scan = true;
+			/* set to A-B */
+			div_ant_conf.alt_lna_conf =
+				ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+			break;
+		case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
+			antcomb->rssi_sub = alt_rssi_avg;
+			antcomb->scan = false;
+			if (antcomb->rssi_lna2 >
+			    (antcomb->rssi_lna1 +
+			    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
+				/* use LNA2 as main LNA */
+				if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
+				    (antcomb->rssi_add > antcomb->rssi_sub)) {
+					/* set to A+B */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+					div_ant_conf.alt_lna_conf  =
+						ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+				} else if (antcomb->rssi_sub >
+					   antcomb->rssi_lna1) {
+					/* set to A-B */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+				} else {
+					/* set to LNA1 */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				}
+			} else {
+				/* use LNA1 as main LNA */
+				if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
+				    (antcomb->rssi_add > antcomb->rssi_sub)) {
+					/* set to A+B */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+					div_ant_conf.alt_lna_conf  =
+						ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+				} else if (antcomb->rssi_sub >
+					   antcomb->rssi_lna1) {
+					/* set to A-B */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+				} else {
+					/* set to LNA2 */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	} else {
+		if (!antcomb->alt_good) {
+			antcomb->scan_not_start = false;
+			/* Set alt to another LNA */
+			if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
+				div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+				div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+			} else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
+				div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+			}
+			goto div_comb_done;
+		}
+	}
+
+	ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
+					   main_rssi_avg, alt_rssi_avg,
+					   alt_ratio);
+
+	antcomb->quick_scan_cnt++;
+
+div_comb_done:
+	ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
+	ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
+
+	antcomb->scan_start_time = jiffies;
+	antcomb->total_pkt_count = 0;
+	antcomb->main_total_rssi = 0;
+	antcomb->alt_total_rssi = 0;
+	antcomb->main_recv_cnt = 0;
+	antcomb->alt_recv_cnt = 0;
+}
+
+void ath_ant_comb_update(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_hw_antcomb_conf div_ant_conf;
+	u8 lna_conf;
+
+	ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
+
+	if (sc->ant_rx == 1)
+		lna_conf = ATH_ANT_DIV_COMB_LNA1;
+	else
+		lna_conf = ATH_ANT_DIV_COMB_LNA2;
+
+	div_ant_conf.main_lna_conf = lna_conf;
+	div_ant_conf.alt_lna_conf = lna_conf;
+
+	ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index c7492c6..874186b 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -995,141 +995,6 @@ static u32 ar5008_hw_compute_pll_control(struct ath_hw *ah,
 	return pll;
 }
 
-static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
-				      enum ath9k_ani_cmd cmd,
-				      int param)
-{
-	struct ar5416AniState *aniState = &ah->curchan->ani;
-	struct ath_common *common = ath9k_hw_common(ah);
-
-	switch (cmd & ah->ani_function) {
-	case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
-		u32 level = param;
-
-		if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
-			ath_dbg(common, ANI, "level out of range (%u > %zu)\n",
-				level, 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_CTL1,
-			      AR_PHY_AGC_CTL1_COARSE_LOW,
-			      ah->coarse_low[level]);
-		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
-			      AR_PHY_AGC_CTL1_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:{
-		u32 on = param ? 1 : 0;
-
-		if (on)
-			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
-				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
-		else
-			REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
-				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
-
-		if (!on != aniState->ofdmWeakSigDetectOff) {
-			if (on)
-				ah->stats.ast_ani_ofdmon++;
-			else
-				ah->stats.ast_ani_ofdmoff++;
-			aniState->ofdmWeakSigDetectOff = !on;
-		}
-		break;
-	}
-	case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
-		static 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:{
-		static const int firstep[] = { 0, 4, 8 };
-		u32 level = param;
-
-		if (level >= ARRAY_SIZE(firstep)) {
-			ath_dbg(common, ANI, "level out of range (%u > %zu)\n",
-				level, ARRAY_SIZE(firstep));
-			return false;
-		}
-		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;
-		break;
-	}
-	case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
-		static const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
-		u32 level = param;
-
-		if (level >= ARRAY_SIZE(cycpwrThr1)) {
-			ath_dbg(common, ANI, "level out of range (%u > %zu)\n",
-				level, ARRAY_SIZE(cycpwrThr1));
-			return false;
-		}
-		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;
-		break;
-	}
-	case ATH9K_ANI_PRESENT:
-		break;
-	default:
-		ath_dbg(common, ANI, "invalid cmd %u\n", cmd);
-		return false;
-	}
-
-	ath_dbg(common, ANI, "ANI parameters:\n");
-	ath_dbg(common, ANI,
-		"noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetectOff=%d\n",
-		aniState->noiseImmunityLevel,
-		aniState->spurImmunityLevel,
-		!aniState->ofdmWeakSigDetectOff);
-	ath_dbg(common, ANI,
-		"cckWeakSigThreshold=%d, firstepLevel=%d, listenTime=%d\n",
-		aniState->cckWeakSigThreshold,
-		aniState->firstepLevel,
-		aniState->listenTime);
-	ath_dbg(common, ANI, "ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
-		aniState->ofdmPhyErrCount,
-		aniState->cckPhyErrCount);
-
-	return true;
-}
-
 static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 				      enum ath9k_ani_cmd cmd,
 				      int param)
@@ -1206,18 +1071,18 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 			REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
 				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
 
-		if (!on != aniState->ofdmWeakSigDetectOff) {
+		if (on != aniState->ofdmWeakSigDetect) {
 			ath_dbg(common, ANI,
 				"** ch %d: ofdm weak signal: %s=>%s\n",
 				chan->channel,
-				!aniState->ofdmWeakSigDetectOff ?
+				aniState->ofdmWeakSigDetect ?
 				"on" : "off",
 				on ? "on" : "off");
 			if (on)
 				ah->stats.ast_ani_ofdmon++;
 			else
 				ah->stats.ast_ani_ofdmoff++;
-			aniState->ofdmWeakSigDetectOff = !on;
+			aniState->ofdmWeakSigDetect = on;
 		}
 		break;
 	}
@@ -1236,7 +1101,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 		 * from INI file & cap value
 		 */
 		value = firstep_table[level] -
-			firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
 			aniState->iniDef.firstep;
 		if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
 			value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
@@ -1251,7 +1116,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 		 * from INI file & cap value
 		 */
 		value2 = firstep_table[level] -
-			 firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			 firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
 			 aniState->iniDef.firstepLow;
 		if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
 			value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
@@ -1267,7 +1132,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 				chan->channel,
 				aniState->firstepLevel,
 				level,
-				ATH9K_ANI_FIRSTEP_LVL_NEW,
+				ATH9K_ANI_FIRSTEP_LVL,
 				value,
 				aniState->iniDef.firstep);
 			ath_dbg(common, ANI,
@@ -1275,7 +1140,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 				chan->channel,
 				aniState->firstepLevel,
 				level,
-				ATH9K_ANI_FIRSTEP_LVL_NEW,
+				ATH9K_ANI_FIRSTEP_LVL,
 				value2,
 				aniState->iniDef.firstepLow);
 			if (level > aniState->firstepLevel)
@@ -1300,7 +1165,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 		 * from INI file & cap value
 		 */
 		value = cycpwrThr1_table[level] -
-			cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
 			aniState->iniDef.cycpwrThr1;
 		if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
 			value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
@@ -1316,7 +1181,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 		 * from INI file & cap value
 		 */
 		value2 = cycpwrThr1_table[level] -
-			 cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			 cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
 			 aniState->iniDef.cycpwrThr1Ext;
 		if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
 			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
@@ -1331,7 +1196,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 				chan->channel,
 				aniState->spurImmunityLevel,
 				level,
-				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				ATH9K_ANI_SPUR_IMMUNE_LVL,
 				value,
 				aniState->iniDef.cycpwrThr1);
 			ath_dbg(common, ANI,
@@ -1339,7 +1204,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 				chan->channel,
 				aniState->spurImmunityLevel,
 				level,
-				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				ATH9K_ANI_SPUR_IMMUNE_LVL,
 				value2,
 				aniState->iniDef.cycpwrThr1Ext);
 			if (level > aniState->spurImmunityLevel)
@@ -1367,9 +1232,9 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 	ath_dbg(common, ANI,
 		"ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n",
 		aniState->spurImmunityLevel,
-		!aniState->ofdmWeakSigDetectOff ? "on" : "off",
+		aniState->ofdmWeakSigDetect ? "on" : "off",
 		aniState->firstepLevel,
-		!aniState->mrcCCKOff ? "on" : "off",
+		aniState->mrcCCK ? "on" : "off",
 		aniState->listenTime,
 		aniState->ofdmPhyErrCount,
 		aniState->cckPhyErrCount);
@@ -1454,10 +1319,10 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
 					       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->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+	aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+	aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
+	aniState->mrcCCK = false; /* not available on pre AR9003 */
 }
 
 static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
@@ -1545,11 +1410,8 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
 	priv_ops->do_getnf = ar5008_hw_do_getnf;
 	priv_ops->set_radar_params = ar5008_hw_set_radar_params;
 
-	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;
+	priv_ops->ani_control = ar5008_hw_ani_control_new;
+	priv_ops->ani_cache_ini_regs = ar5008_hw_ani_cache_ini_regs;
 
 	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah))
 		priv_ops->compute_pll_control = ar9160_hw_compute_pll_control;
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index d9a69fc..edf21ea 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -21,10 +21,6 @@
 #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(force_new_ani, "Force new ANI for AR5008, AR9001, AR9002");
-
 /* General hardware code for the A5008/AR9001/AR9002 hadware families */
 
 static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 9fdd70f..d7deb8c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -653,7 +653,6 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
 }
 
 static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
-						 u8 num_chains,
 						 struct coeff *coeff,
 						 bool is_reusable)
 {
@@ -677,7 +676,9 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
 	}
 
 	/* Load the average of 2 passes */
-	for (i = 0; i < num_chains; i++) {
+	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+		if (!(ah->txchainmask & (1 << i)))
+			continue;
 		nmeasurement = REG_READ_FIELD(ah,
 				AR_PHY_TX_IQCAL_STATUS_B0,
 				AR_PHY_CALIBRATED_GAINS_0);
@@ -767,16 +768,13 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
 	};
 	struct coeff coeff;
 	s32 iq_res[6];
-	u8 num_chains = 0;
 	int i, im, j;
 	int nmeasurement;
 
 	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-		if (ah->txchainmask & (1 << i))
-			num_chains++;
-	}
+		if (!(ah->txchainmask & (1 << i)))
+			continue;
 
-	for (i = 0; i < num_chains; i++) {
 		nmeasurement = REG_READ_FIELD(ah,
 				AR_PHY_TX_IQCAL_STATUS_B0,
 				AR_PHY_CALIBRATED_GAINS_0);
@@ -839,8 +837,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
 				coeff.phs_coeff[i][im] -= 128;
 		}
 	}
-	ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains,
-					     &coeff, is_reusable);
+	ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable);
 
 	return;
 
@@ -901,7 +898,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 	bool is_reusable = true, status = true;
 	bool run_rtt_cal = false, run_agc_cal;
 	bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
-	bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
 	u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
 					  AR_PHY_AGC_CONTROL_FLTR_CAL   |
 					  AR_PHY_AGC_CONTROL_PKDET_CAL;
@@ -970,7 +966,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 	} else if (caldata && !caldata->done_txiqcal_once)
 		run_agc_cal = true;
 
-	if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
+	if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
 		ar9003_mci_init_cal_req(ah, &is_reusable);
 
 	if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
@@ -993,7 +989,7 @@ skip_tx_iqcal:
 				       0, AH_WAIT_TIMEOUT);
 	}
 
-	if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
+	if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
 		ar9003_mci_init_cal_done(ah);
 
 	if (rtt && !run_rtt_cal) {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index dfb0441..b1e5923 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -3178,7 +3178,7 @@ static int ar9300_compress_decision(struct ath_hw *ah,
 				mdata_size, length);
 			return -1;
 		}
-		memcpy(mptr, (u8 *) (word + COMP_HDR_LEN), length);
+		memcpy(mptr, word + COMP_HDR_LEN, length);
 		ath_dbg(common, EEPROM,
 			"restored eeprom %d: uncompressed, length %d\n",
 			it, length);
@@ -3199,7 +3199,7 @@ static int ar9300_compress_decision(struct ath_hw *ah,
 			"restore eeprom %d: block, reference %d, length %d\n",
 			it, reference, length);
 		ar9300_uncompress_block(ah, mptr, mdata_size,
-					(u8 *) (word + COMP_HDR_LEN), length);
+					(word + COMP_HDR_LEN), length);
 		break;
 	default:
 		ath_dbg(common, EEPROM, "unknown compression code %d\n", code);
@@ -3412,11 +3412,11 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
 	if (!dump_base_hdr) {
 		len += snprintf(buf + len, size - len,
 				"%20s :\n", "2GHz modal Header");
-		len += ar9003_dump_modal_eeprom(buf, len, size,
+		len = ar9003_dump_modal_eeprom(buf, len, size,
 						&eep->modalHeader2G);
 		len += snprintf(buf + len, size - len,
 				"%20s :\n", "5GHz modal Header");
-		len += ar9003_dump_modal_eeprom(buf, len, size,
+		len = ar9003_dump_modal_eeprom(buf, len, size,
 						&eep->modalHeader5G);
 		goto out;
 	}
@@ -3613,6 +3613,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
 		value = ar9003_switch_com_spdt_get(ah, is2ghz);
 		REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
 				AR_SWITCH_TABLE_COM_SPDT_ALL, value);
+		REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_SPDT_ENABLE);
 	}
 
 	value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index d9e0824..78816b8 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -181,11 +181,14 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
 	u32 mask2 = 0;
 	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath_common *common = ath9k_hw_common(ah);
-	u32 sync_cause = 0, async_cause;
+	u32 sync_cause = 0, async_cause, async_mask = AR_INTR_MAC_IRQ;
+
+	if (ath9k_hw_mci_is_enabled(ah))
+		async_mask |= AR_INTR_ASYNC_MASK_MCI;
 
 	async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
 
-	if (async_cause & (AR_INTR_MAC_IRQ | AR_INTR_ASYNC_MASK_MCI)) {
+	if (async_cause & async_mask) {
 		if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
 				== AR_RTC_STATUS_ON)
 			isr = REG_READ(ah, AR_ISR);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
index ffbb180..6155837 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
@@ -35,31 +35,30 @@ static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address,
 	struct ath_common *common = ath9k_hw_common(ah);
 
 	while (time_out) {
-		if (REG_READ(ah, address) & bit_position) {
-			REG_WRITE(ah, address, bit_position);
-
-			if (address == AR_MCI_INTERRUPT_RX_MSG_RAW) {
-				if (bit_position &
-				    AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
-					ar9003_mci_reset_req_wakeup(ah);
-
-				if (bit_position &
-				    (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |
-				     AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))
-					REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
-					AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
-
-				REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
-					  AR_MCI_INTERRUPT_RX_MSG);
-			}
-			break;
-		}
+		if (!(REG_READ(ah, address) & bit_position)) {
+			udelay(10);
+			time_out -= 10;
 
-		udelay(10);
-		time_out -= 10;
+			if (time_out < 0)
+				break;
+			else
+				continue;
+		}
+		REG_WRITE(ah, address, bit_position);
 
-		if (time_out < 0)
+		if (address != AR_MCI_INTERRUPT_RX_MSG_RAW)
 			break;
+
+		if (bit_position & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
+			ar9003_mci_reset_req_wakeup(ah);
+
+		if (bit_position & (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |
+				    AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))
+			REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+				  AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
+
+		REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_RX_MSG);
+		break;
 	}
 
 	if (time_out <= 0) {
@@ -127,14 +126,13 @@ static void ar9003_mci_send_coex_version_query(struct ath_hw *ah,
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 payload[4] = {0, 0, 0, 0};
 
-	if (!mci->bt_version_known &&
-	    (mci->bt_state != MCI_BT_SLEEP)) {
-		MCI_GPM_SET_TYPE_OPCODE(payload,
-					MCI_GPM_COEX_AGENT,
-					MCI_GPM_COEX_VERSION_QUERY);
-		ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
-					wait_done, true);
-	}
+	if (mci->bt_version_known ||
+	    (mci->bt_state == MCI_BT_SLEEP))
+		return;
+
+	MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+				MCI_GPM_COEX_VERSION_QUERY);
+	ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
 }
 
 static void ar9003_mci_send_coex_version_response(struct ath_hw *ah,
@@ -158,15 +156,14 @@ static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah,
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 *payload = &mci->wlan_channels[0];
 
-	if ((mci->wlan_channels_update == true) &&
-	    (mci->bt_state != MCI_BT_SLEEP)) {
-		MCI_GPM_SET_TYPE_OPCODE(payload,
-					MCI_GPM_COEX_AGENT,
-					MCI_GPM_COEX_WLAN_CHANNELS);
-		ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
-					wait_done, true);
-		MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
-	}
+	if (!mci->wlan_channels_update ||
+	    (mci->bt_state == MCI_BT_SLEEP))
+		return;
+
+	MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+				MCI_GPM_COEX_WLAN_CHANNELS);
+	ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
+	MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
 }
 
 static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
@@ -174,29 +171,30 @@ static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
 {
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 payload[4] = {0, 0, 0, 0};
-	bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
-					     MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
+	bool query_btinfo;
 
-	if (mci->bt_state != MCI_BT_SLEEP) {
-
-		MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
-					MCI_GPM_COEX_STATUS_QUERY);
+	if (mci->bt_state == MCI_BT_SLEEP)
+		return;
 
-		*(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
+	query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
+					MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
+	MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+				MCI_GPM_COEX_STATUS_QUERY);
 
-		/*
-		 * If bt_status_query message is  not sent successfully,
-		 * then need_flush_btinfo should be set again.
-		 */
-		if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
-					     wait_done, true)) {
-			if (query_btinfo)
-				mci->need_flush_btinfo = true;
-		}
+	*(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
 
+	/*
+	 * If bt_status_query message is  not sent successfully,
+	 * then need_flush_btinfo should be set again.
+	 */
+	if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
+				wait_done, true)) {
 		if (query_btinfo)
-			mci->query_bt = false;
+			mci->need_flush_btinfo = true;
 	}
+
+	if (query_btinfo)
+		mci->query_bt = false;
 }
 
 static void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
@@ -241,73 +239,73 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah)
 	ar9003_mci_remote_reset(ah, true);
 	ar9003_mci_send_req_wake(ah, true);
 
-	if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-				  AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) {
+	if (!ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+				  AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500))
+		goto clear_redunt;
 
-		mci->bt_state = MCI_BT_AWAKE;
+	mci->bt_state = MCI_BT_AWAKE;
 
-		/*
-		 * we don't need to send more remote_reset at this moment.
-		 * If BT receive first remote_reset, then BT HW will
-		 * be cleaned up and will be able to receive req_wake
-		 * and BT HW will respond sys_waking.
-		 * In this case, WLAN will receive BT's HW sys_waking.
-		 * Otherwise, if BT SW missed initial remote_reset,
-		 * that remote_reset will still clean up BT MCI RX,
-		 * and the req_wake will wake BT up,
-		 * and BT SW will respond this req_wake with a remote_reset and
-		 * sys_waking. In this case, WLAN will receive BT's SW
-		 * sys_waking. In either case, BT's RX is cleaned up. So we
-		 * don't need to reply BT's remote_reset now, if any.
-		 * Similarly, if in any case, WLAN can receive BT's sys_waking,
-		 * that means WLAN's RX is also fine.
-		 */
-		ar9003_mci_send_sys_waking(ah, true);
-		udelay(10);
+	/*
+	 * we don't need to send more remote_reset at this moment.
+	 * If BT receive first remote_reset, then BT HW will
+	 * be cleaned up and will be able to receive req_wake
+	 * and BT HW will respond sys_waking.
+	 * In this case, WLAN will receive BT's HW sys_waking.
+	 * Otherwise, if BT SW missed initial remote_reset,
+	 * that remote_reset will still clean up BT MCI RX,
+	 * and the req_wake will wake BT up,
+	 * and BT SW will respond this req_wake with a remote_reset and
+	 * sys_waking. In this case, WLAN will receive BT's SW
+	 * sys_waking. In either case, BT's RX is cleaned up. So we
+	 * don't need to reply BT's remote_reset now, if any.
+	 * Similarly, if in any case, WLAN can receive BT's sys_waking,
+	 * that means WLAN's RX is also fine.
+	 */
+	ar9003_mci_send_sys_waking(ah, true);
+	udelay(10);
 
-		/*
-		 * Set BT priority interrupt value to be 0xff to
-		 * avoid having too many BT PRIORITY interrupts.
-		 */
-		REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
-		REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
-		REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
-		REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
-		REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
+	/*
+	 * Set BT priority interrupt value to be 0xff to
+	 * avoid having too many BT PRIORITY interrupts.
+	 */
+	REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
+	REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
+	REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
+	REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
+	REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
 
-		/*
-		 * A contention reset will be received after send out
-		 * sys_waking. Also BT priority interrupt bits will be set.
-		 * Clear those bits before the next step.
-		 */
+	/*
+	 * A contention reset will be received after send out
+	 * sys_waking. Also BT priority interrupt bits will be set.
+	 * Clear those bits before the next step.
+	 */
 
-		REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-			  AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
-		REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
-			  AR_MCI_INTERRUPT_BT_PRI);
+	REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+		  AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
+	REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI);
 
-		if (mci->is_2g) {
-			ar9003_mci_send_lna_transfer(ah, true);
-			udelay(5);
-		}
+	if (mci->is_2g) {
+		ar9003_mci_send_lna_transfer(ah, true);
+		udelay(5);
+	}
 
-		if ((mci->is_2g && !mci->update_2g5g)) {
-			if (ar9003_mci_wait_for_interrupt(ah,
-					  AR_MCI_INTERRUPT_RX_MSG_RAW,
-					  AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
-					  mci_timeout))
-				ath_dbg(common, MCI,
-					"MCI WLAN has control over the LNA & BT obeys it\n");
-			else
-				ath_dbg(common, MCI,
-					"MCI BT didn't respond to LNA_TRANS\n");
-		}
+	if ((mci->is_2g && !mci->update_2g5g)) {
+		if (ar9003_mci_wait_for_interrupt(ah,
+					AR_MCI_INTERRUPT_RX_MSG_RAW,
+					AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
+					mci_timeout))
+			ath_dbg(common, MCI,
+				"MCI WLAN has control over the LNA & BT obeys it\n");
+		else
+			ath_dbg(common, MCI,
+				"MCI BT didn't respond to LNA_TRANS\n");
 	}
 
+clear_redunt:
 	/* Clear the extra redundant SYS_WAKING from BT */
 	if ((mci->bt_state == MCI_BT_AWAKE) &&
-		(REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-				AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
+	    (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+			    AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
 	    (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
 			    AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
 		REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
@@ -323,14 +321,13 @@ void ar9003_mci_set_full_sleep(struct ath_hw *ah)
 {
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
-	if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
+	if (ar9003_mci_state(ah, MCI_STATE_ENABLE) &&
 	    (mci->bt_state != MCI_BT_SLEEP) &&
 	    !mci->halted_bt_gpm) {
 		ar9003_mci_send_coex_halt_bt_gpm(ah, true, true);
 	}
 
 	mci->ready = false;
-	REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
 }
 
 static void ar9003_mci_disable_interrupt(struct ath_hw *ah)
@@ -487,7 +484,7 @@ static void ar9003_mci_sync_bt_state(struct ath_hw *ah)
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 cur_bt_state;
 
-	cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL);
+	cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP);
 
 	if (mci->bt_state != cur_bt_state)
 		mci->bt_state = cur_bt_state;
@@ -596,8 +593,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
 		if (!time_out)
 			break;
 
-		offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
-					  &more_data);
+		offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data);
 
 		if (offset == MCI_GPM_INVALID)
 			continue;
@@ -615,9 +611,9 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
 				}
 				break;
 			}
-		} else if ((recv_type == gpm_type) && (recv_opcode == gpm_opcode)) {
+		} else if ((recv_type == gpm_type) &&
+			   (recv_opcode == gpm_opcode))
 			break;
-		}
 
 		/*
 		 * check if it's cal_grant
@@ -661,8 +657,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
 		time_out = 0;
 
 	while (more_data == MCI_GPM_MORE) {
-		offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
-					  &more_data);
+		offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data);
 		if (offset == MCI_GPM_INVALID)
 			break;
 
@@ -731,38 +726,38 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP))
 		goto exit;
 
-	if (ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
-	    ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
+	if (!ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) &&
+	    !ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE))
+		goto exit;
 
-		/*
-		 * BT is sleeping. Check if BT wakes up during
-		 * WLAN calibration. If BT wakes up during
-		 * WLAN calibration, need to go through all
-		 * message exchanges again and recal.
-		 */
-		REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-			  AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
-			  AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
+	/*
+	 * BT is sleeping. Check if BT wakes up during
+	 * WLAN calibration. If BT wakes up during
+	 * WLAN calibration, need to go through all
+	 * message exchanges again and recal.
+	 */
+	REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+		  (AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
+		   AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE));
 
-		ar9003_mci_remote_reset(ah, true);
-		ar9003_mci_send_sys_waking(ah, true);
-		udelay(1);
+	ar9003_mci_remote_reset(ah, true);
+	ar9003_mci_send_sys_waking(ah, true);
+	udelay(1);
 
-		if (IS_CHAN_2GHZ(chan))
-			ar9003_mci_send_lna_transfer(ah, true);
+	if (IS_CHAN_2GHZ(chan))
+		ar9003_mci_send_lna_transfer(ah, true);
 
-		mci_hw->bt_state = MCI_BT_AWAKE;
+	mci_hw->bt_state = MCI_BT_AWAKE;
 
-		if (caldata) {
-			caldata->done_txiqcal_once = false;
-			caldata->done_txclcal_once = false;
-			caldata->rtt_done = false;
-		}
+	if (caldata) {
+		caldata->done_txiqcal_once = false;
+		caldata->done_txclcal_once = false;
+		caldata->rtt_done = false;
+	}
 
-		if (!ath9k_hw_init_cal(ah, chan))
-			return -EIO;
+	if (!ath9k_hw_init_cal(ah, chan))
+		return -EIO;
 
-	}
 exit:
 	ar9003_mci_enable_interrupt(ah);
 	return 0;
@@ -772,10 +767,6 @@ static void ar9003_mci_mute_bt(struct ath_hw *ah)
 {
 	/* disable all MCI messages */
 	REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000);
-	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff);
-	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff);
-	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff);
-	REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff);
 	REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
 
 	/* wait pending HW messages to flush out */
@@ -798,29 +789,27 @@ static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable)
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 thresh;
 
-	if (enable) {
-		REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
-			      AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
-		REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
-			      AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
-
-		if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
-			thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);
-			REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
-				      AR_BTCOEX_CTRL_AGGR_THRESH, thresh);
-			REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
-				      AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1);
-		} else {
-			REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
-				      AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0);
-		}
-
-		REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
-			      AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);
-	} else {
+	if (!enable) {
 		REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
 			    AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+		return;
 	}
+	REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
+	REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
+		      AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
+
+	if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
+		thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);
+		REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+			      AR_BTCOEX_CTRL_AGGR_THRESH, thresh);
+		REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+			      AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1);
+	} else
+		REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+			      AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0);
+
+	REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+		      AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);
 }
 
 void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
@@ -898,13 +887,16 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
 		udelay(100);
 	}
 
+	/* Check pending GPM msg before MCI Reset Rx */
+	ar9003_mci_check_gpm_offset(ah);
+
 	regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
 	REG_WRITE(ah, AR_MCI_COMMAND2, regval);
 	udelay(1);
 	regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX);
 	REG_WRITE(ah, AR_MCI_COMMAND2, regval);
 
-	ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
+	ar9003_mci_get_next_gpm_offset(ah, true, NULL);
 
 	REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE,
 		  (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) |
@@ -943,26 +935,27 @@ static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	u32 new_flags, to_set, to_clear;
 
-	if (mci->update_2g5g && (mci->bt_state != MCI_BT_SLEEP)) {
-		if (mci->is_2g) {
-			new_flags = MCI_2G_FLAGS;
-			to_clear = MCI_2G_FLAGS_CLEAR_MASK;
-			to_set = MCI_2G_FLAGS_SET_MASK;
-		} else {
-			new_flags = MCI_5G_FLAGS;
-			to_clear = MCI_5G_FLAGS_CLEAR_MASK;
-			to_set = MCI_5G_FLAGS_SET_MASK;
-		}
+	if (!mci->update_2g5g || (mci->bt_state == MCI_BT_SLEEP))
+		return;
+
+	if (mci->is_2g) {
+		new_flags = MCI_2G_FLAGS;
+		to_clear = MCI_2G_FLAGS_CLEAR_MASK;
+		to_set = MCI_2G_FLAGS_SET_MASK;
+	} else {
+		new_flags = MCI_5G_FLAGS;
+		to_clear = MCI_5G_FLAGS_CLEAR_MASK;
+		to_set = MCI_5G_FLAGS_SET_MASK;
+	}
 
-		if (to_clear)
-			ar9003_mci_send_coex_bt_flags(ah, wait_done,
+	if (to_clear)
+		ar9003_mci_send_coex_bt_flags(ah, wait_done,
 					      MCI_GPM_COEX_BT_FLAGS_CLEAR,
 					      to_clear);
-		if (to_set)
-			ar9003_mci_send_coex_bt_flags(ah, wait_done,
+	if (to_set)
+		ar9003_mci_send_coex_bt_flags(ah, wait_done,
 					      MCI_GPM_COEX_BT_FLAGS_SET,
 					      to_set);
-	}
 }
 
 static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
@@ -1014,38 +1007,42 @@ static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
 	}
 }
 
-void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force)
 {
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
-	if (mci->update_2g5g) {
-		if (mci->is_2g) {
+	if (!mci->update_2g5g && !force)
+		return;
+
+	if (mci->is_2g) {
+		if (!force) {
 			ar9003_mci_send_2g5g_status(ah, true);
+
 			ar9003_mci_send_lna_transfer(ah, true);
 			udelay(5);
+		}
 
-			REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
-				    AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
-			REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
-				    AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+		REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
+			    AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+		REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
+			    AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
 
-			if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) {
-				REG_SET_BIT(ah, AR_BTCOEX_CTRL,
-					    AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
-			}
-		} else {
+		if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
+			ar9003_mci_osla_setup(ah, true);
+	} else {
+		if (!force) {
 			ar9003_mci_send_lna_take(ah, true);
 			udelay(5);
+		}
 
-			REG_SET_BIT(ah, AR_MCI_TX_CTRL,
-				    AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
-			REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
-				    AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
-			REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
-				    AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+		REG_SET_BIT(ah, AR_MCI_TX_CTRL,
+			    AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+		REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
+			    AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
 
+		ar9003_mci_osla_setup(ah, false);
+		if (!force)
 			ar9003_mci_send_2g5g_status(ah, true);
-		}
 	}
 }
 
@@ -1132,7 +1129,7 @@ void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable)
 	if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) {
 		ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n");
 	} else {
-		is_reusable = false;
+		*is_reusable = false;
 		ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n");
 	}
 }
@@ -1173,11 +1170,10 @@ void ar9003_mci_cleanup(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ar9003_mci_cleanup);
 
-u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
+u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-	u32 value = 0, more_gpm = 0, gpm_ptr;
+	u32 value = 0;
 	u8 query_type;
 
 	switch (state_type) {
@@ -1190,81 +1186,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
 		}
 		value &= AR_BTCOEX_CTRL_MCI_MODE_EN;
 		break;
-	case MCI_STATE_INIT_GPM_OFFSET:
-		value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
-		mci->gpm_idx = value;
-		break;
-	case MCI_STATE_NEXT_GPM_OFFSET:
-	case MCI_STATE_LAST_GPM_OFFSET:
-		/*
-		* This could be useful to avoid new GPM message interrupt which
-		* may lead to spurious interrupt after power sleep, or multiple
-		* entry of ath_mci_intr().
-		* Adding empty GPM check by returning HAL_MCI_GPM_INVALID can
-		* alleviate this effect, but clearing GPM RX interrupt bit is
-		* safe, because whether this is called from hw or driver code
-		* there must be an interrupt bit set/triggered initially
-		*/
-		REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-			  AR_MCI_INTERRUPT_RX_MSG_GPM);
-
-		gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
-		value = gpm_ptr;
-
-		if (value == 0)
-			value = mci->gpm_len - 1;
-		else if (value >= mci->gpm_len) {
-			if (value != 0xFFFF)
-				value = 0;
-		} else {
-			value--;
-		}
-
-		if (value == 0xFFFF) {
-			value = MCI_GPM_INVALID;
-			more_gpm = MCI_GPM_NOMORE;
-		} else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) {
-			if (gpm_ptr == mci->gpm_idx) {
-				value = MCI_GPM_INVALID;
-				more_gpm = MCI_GPM_NOMORE;
-			} else {
-				for (;;) {
-					u32 temp_index;
-
-					/* skip reserved GPM if any */
-
-					if (value != mci->gpm_idx)
-						more_gpm = MCI_GPM_MORE;
-					else
-						more_gpm = MCI_GPM_NOMORE;
-
-					temp_index = mci->gpm_idx;
-					mci->gpm_idx++;
-
-					if (mci->gpm_idx >=
-					    mci->gpm_len)
-						mci->gpm_idx = 0;
-
-					if (ar9003_mci_is_gpm_valid(ah,
-								    temp_index)) {
-						value = temp_index;
-						break;
-					}
-
-					if (more_gpm == MCI_GPM_NOMORE) {
-						value = MCI_GPM_INVALID;
-						break;
-					}
-				}
-			}
-			if (p_data)
-				*p_data = more_gpm;
-			}
-
-			if (value != MCI_GPM_INVALID)
-				value <<= 4;
-
-			break;
 	case MCI_STATE_LAST_SCHD_MSG_OFFSET:
 		value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
 				    AR_MCI_RX_LAST_SCHD_MSG_INDEX);
@@ -1276,21 +1197,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
 			   AR_MCI_RX_REMOTE_SLEEP) ?
 			MCI_BT_SLEEP : MCI_BT_AWAKE;
 		break;
-	case MCI_STATE_CONT_RSSI_POWER:
-		value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER);
-		break;
-	case MCI_STATE_CONT_PRIORITY:
-		value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY);
-		break;
-	case MCI_STATE_CONT_TXRX:
-		value = MS(mci->cont_status, AR_MCI_CONT_TXRX);
-		break;
-	case MCI_STATE_BT:
-		value = mci->bt_state;
-		break;
-	case MCI_STATE_SET_BT_SLEEP:
-		mci->bt_state = MCI_BT_SLEEP;
-		break;
 	case MCI_STATE_SET_BT_AWAKE:
 		mci->bt_state = MCI_BT_AWAKE;
 		ar9003_mci_send_coex_version_query(ah, true);
@@ -1299,7 +1205,7 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
 		if (mci->unhalt_bt_gpm)
 			ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
 
-		ar9003_mci_2g5g_switch(ah, true);
+		ar9003_mci_2g5g_switch(ah, false);
 		break;
 	case MCI_STATE_SET_BT_CAL_START:
 		mci->bt_state = MCI_BT_CAL_START;
@@ -1323,34 +1229,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
 	case MCI_STATE_SEND_WLAN_COEX_VERSION:
 		ar9003_mci_send_coex_version_response(ah, true);
 		break;
-	case MCI_STATE_SET_BT_COEX_VERSION:
-		if (!p_data)
-			ath_dbg(common, MCI,
-				"MCI Set BT Coex version with NULL data!!\n");
-		else {
-			mci->bt_ver_major = (*p_data >> 8) & 0xff;
-			mci->bt_ver_minor = (*p_data) & 0xff;
-			mci->bt_version_known = true;
-			ath_dbg(common, MCI, "MCI BT version set: %d.%d\n",
-				mci->bt_ver_major, mci->bt_ver_minor);
-		}
-		break;
-	case MCI_STATE_SEND_WLAN_CHANNELS:
-		if (p_data) {
-			if (((mci->wlan_channels[1] & 0xffff0000) ==
-			     (*(p_data + 1) & 0xffff0000)) &&
-			    (mci->wlan_channels[2] == *(p_data + 2)) &&
-			    (mci->wlan_channels[3] == *(p_data + 3)))
-				break;
-
-			mci->wlan_channels[0] = *p_data++;
-			mci->wlan_channels[1] = *p_data++;
-			mci->wlan_channels[2] = *p_data++;
-			mci->wlan_channels[3] = *p_data++;
-		}
-		mci->wlan_channels_update = true;
-		ar9003_mci_send_coex_wlan_channels(ah, true);
-		break;
 	case MCI_STATE_SEND_VERSION_QUERY:
 		ar9003_mci_send_coex_version_query(ah, true);
 		break;
@@ -1358,38 +1236,16 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
 		query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY;
 		ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
 		break;
-	case MCI_STATE_NEED_FLUSH_BT_INFO:
-			/*
-			 * btcoex_hw.mci.unhalt_bt_gpm means whether it's
-			 * needed to send UNHALT message. It's set whenever
-			 * there's a request to send HALT message.
-			 * mci_halted_bt_gpm means whether HALT message is sent
-			 * out successfully.
-			 *
-			 * Checking (mci_unhalt_bt_gpm == false) instead of
-			 * checking (ah->mci_halted_bt_gpm == false) will make
-			 * sure currently is in UNHALT-ed mode and BT can
-			 * respond to status query.
-			 */
-			value = (!mci->unhalt_bt_gpm &&
-				 mci->need_flush_btinfo) ? 1 : 0;
-			if (p_data)
-				mci->need_flush_btinfo =
-					(*p_data != 0) ? true : false;
-			break;
 	case MCI_STATE_RECOVER_RX:
 		ar9003_mci_prep_interface(ah);
 		mci->query_bt = true;
 		mci->need_flush_btinfo = true;
 		ar9003_mci_send_coex_wlan_channels(ah, true);
-		ar9003_mci_2g5g_switch(ah, true);
+		ar9003_mci_2g5g_switch(ah, false);
 		break;
 	case MCI_STATE_NEED_FTP_STOMP:
 		value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
 		break;
-	case MCI_STATE_NEED_TUNING:
-		value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING);
-		break;
 	default:
 		break;
 	}
@@ -1397,3 +1253,173 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
 	return value;
 }
 EXPORT_SYMBOL(ar9003_mci_state);
+
+void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+	ath_dbg(common, MCI, "Give LNA and SPDT control to BT\n");
+
+	ar9003_mci_send_lna_take(ah, true);
+	udelay(50);
+
+	REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+	mci->is_2g = false;
+	mci->update_2g5g = true;
+	ar9003_mci_send_2g5g_status(ah, true);
+
+	/* Force another 2g5g update at next scanning */
+	mci->update_2g5g = true;
+}
+
+void ar9003_mci_set_power_awake(struct ath_hw *ah)
+{
+	u32 btcoex_ctrl2, diag_sw;
+	int i;
+	u8 lna_ctrl, bt_sleep;
+
+	for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
+		btcoex_ctrl2 = REG_READ(ah, AR_BTCOEX_CTRL2);
+		if (btcoex_ctrl2 != 0xdeadbeef)
+			break;
+		udelay(AH_TIME_QUANTUM);
+	}
+	REG_WRITE(ah, AR_BTCOEX_CTRL2, (btcoex_ctrl2 | BIT(23)));
+
+	for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
+		diag_sw = REG_READ(ah, AR_DIAG_SW);
+		if (diag_sw != 0xdeadbeef)
+			break;
+		udelay(AH_TIME_QUANTUM);
+	}
+	REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18)));
+	lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3;
+	bt_sleep = REG_READ(ah, AR_MCI_RX_STATUS) & AR_MCI_RX_REMOTE_SLEEP;
+
+	REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2);
+	REG_WRITE(ah, AR_DIAG_SW, diag_sw);
+
+	if (bt_sleep && (lna_ctrl == 2)) {
+		REG_SET_BIT(ah, AR_BTCOEX_RC, 0x1);
+		REG_CLR_BIT(ah, AR_BTCOEX_RC, 0x1);
+		udelay(50);
+	}
+}
+
+void ar9003_mci_check_gpm_offset(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+	u32 offset;
+
+	/*
+	 * This should only be called before "MAC Warm Reset" or "MCI Reset Rx".
+	 */
+	offset = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+	if (mci->gpm_idx == offset)
+		return;
+	ath_dbg(common, MCI, "GPM cached write pointer mismatch %d %d\n",
+		mci->gpm_idx, offset);
+	mci->query_bt = true;
+	mci->need_flush_btinfo = true;
+	mci->gpm_idx = 0;
+}
+
+u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more)
+{
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+	u32 offset, more_gpm = 0, gpm_ptr;
+
+	if (first) {
+		gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+		mci->gpm_idx = gpm_ptr;
+		return gpm_ptr;
+	}
+
+	/*
+	 * This could be useful to avoid new GPM message interrupt which
+	 * may lead to spurious interrupt after power sleep, or multiple
+	 * entry of ath_mci_intr().
+	 * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can
+	 * alleviate this effect, but clearing GPM RX interrupt bit is
+	 * safe, because whether this is called from hw or driver code
+	 * there must be an interrupt bit set/triggered initially
+	 */
+	REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+			AR_MCI_INTERRUPT_RX_MSG_GPM);
+
+	gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+	offset = gpm_ptr;
+
+	if (!offset)
+		offset = mci->gpm_len - 1;
+	else if (offset >= mci->gpm_len) {
+		if (offset != 0xFFFF)
+			offset = 0;
+	} else {
+		offset--;
+	}
+
+	if ((offset == 0xFFFF) || (gpm_ptr == mci->gpm_idx)) {
+		offset = MCI_GPM_INVALID;
+		more_gpm = MCI_GPM_NOMORE;
+		goto out;
+	}
+	for (;;) {
+		u32 temp_index;
+
+		/* skip reserved GPM if any */
+
+		if (offset != mci->gpm_idx)
+			more_gpm = MCI_GPM_MORE;
+		else
+			more_gpm = MCI_GPM_NOMORE;
+
+		temp_index = mci->gpm_idx;
+		mci->gpm_idx++;
+
+		if (mci->gpm_idx >= mci->gpm_len)
+			mci->gpm_idx = 0;
+
+		if (ar9003_mci_is_gpm_valid(ah, temp_index)) {
+			offset = temp_index;
+			break;
+		}
+
+		if (more_gpm == MCI_GPM_NOMORE) {
+			offset = MCI_GPM_INVALID;
+			break;
+		}
+	}
+
+	if (offset != MCI_GPM_INVALID)
+		offset <<= 4;
+out:
+	if (more)
+		*more = more_gpm;
+
+	return offset;
+}
+EXPORT_SYMBOL(ar9003_mci_get_next_gpm_offset);
+
+void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor)
+{
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+	mci->bt_ver_major = major;
+	mci->bt_ver_minor = minor;
+	mci->bt_version_known = true;
+	ath_dbg(ath9k_hw_common(ah), MCI, "MCI BT version set: %d.%d\n",
+		mci->bt_ver_major, mci->bt_ver_minor);
+}
+EXPORT_SYMBOL(ar9003_mci_set_bt_version);
+
+void ar9003_mci_send_wlan_channels(struct ath_hw *ah)
+{
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+	mci->wlan_channels_update = true;
+	ar9003_mci_send_coex_wlan_channels(ah, true);
+}
+EXPORT_SYMBOL(ar9003_mci_send_wlan_channels);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
index 4842f6c..d33b8e1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
@@ -189,30 +189,18 @@ enum mci_bt_state {
 /* Type of state query */
 enum mci_state_type {
 	MCI_STATE_ENABLE,
-	MCI_STATE_INIT_GPM_OFFSET,
-	MCI_STATE_NEXT_GPM_OFFSET,
-	MCI_STATE_LAST_GPM_OFFSET,
-	MCI_STATE_BT,
-	MCI_STATE_SET_BT_SLEEP,
 	MCI_STATE_SET_BT_AWAKE,
 	MCI_STATE_SET_BT_CAL_START,
 	MCI_STATE_SET_BT_CAL,
 	MCI_STATE_LAST_SCHD_MSG_OFFSET,
 	MCI_STATE_REMOTE_SLEEP,
-	MCI_STATE_CONT_RSSI_POWER,
-	MCI_STATE_CONT_PRIORITY,
-	MCI_STATE_CONT_TXRX,
 	MCI_STATE_RESET_REQ_WAKE,
 	MCI_STATE_SEND_WLAN_COEX_VERSION,
-	MCI_STATE_SET_BT_COEX_VERSION,
-	MCI_STATE_SEND_WLAN_CHANNELS,
 	MCI_STATE_SEND_VERSION_QUERY,
 	MCI_STATE_SEND_STATUS_QUERY,
-	MCI_STATE_NEED_FLUSH_BT_INFO,
 	MCI_STATE_SET_CONCUR_TX_PRI,
 	MCI_STATE_RECOVER_RX,
 	MCI_STATE_NEED_FTP_STOMP,
-	MCI_STATE_NEED_TUNING,
 	MCI_STATE_DEBUG,
 	MCI_STATE_MAX
 };
@@ -260,28 +248,26 @@ enum mci_gpm_coex_opcode {
 bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
 			     u32 *payload, u8 len, bool wait_done,
 			     bool check_bt);
-u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data);
+u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type);
 void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
 		      u16 len, u32 sched_addr);
 void ar9003_mci_cleanup(struct ath_hw *ah);
 void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
 			      u32 *rx_msg_intr);
-
+u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more);
+void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor);
+void ar9003_mci_send_wlan_channels(struct ath_hw *ah);
 /*
  * These functions are used by ath9k_hw.
  */
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 
-static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
-{
-	return ah->btcoex_hw.mci.ready;
-}
 void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep);
 void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable);
 void ar9003_mci_init_cal_done(struct ath_hw *ah);
 void ar9003_mci_set_full_sleep(struct ath_hw *ah);
-void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force);
 void ar9003_mci_check_bt(struct ath_hw *ah);
 bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan);
 int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
@@ -289,13 +275,12 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
 		      bool is_full_sleep);
 void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);
+void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);
+void ar9003_mci_set_power_awake(struct ath_hw *ah);
+void ar9003_mci_check_gpm_offset(struct ath_hw *ah);
 
 #else
 
-static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
-{
-	return false;
-}
 static inline void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)
 {
 }
@@ -330,6 +315,15 @@ static inline void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
 static inline void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
 {
 }
+static inline void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah)
+{
+}
+static inline void ar9003_mci_set_power_awake(struct ath_hw *ah)
+{
+}
+static inline void ar9003_mci_check_gpm_offset(struct ath_hw *ah)
+{
+}
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 11abb97..6b91ebb 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -173,7 +173,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
 	int cur_bb_spur, negative = 0, cck_spur_freq;
 	int i;
 	int range, max_spur_cnts, synth_freq;
-	u8 *spur_fbin_ptr = NULL;
+	u8 *spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah, IS_CHAN_2GHZ(chan));
 
 	/*
 	 * Need to verify range +/- 10 MHz in control channel, otherwise spur
@@ -181,8 +181,6 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
 	 */
 
 	if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah)) {
-		spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah,
-							 IS_CHAN_2GHZ(chan));
 		if (spur_fbin_ptr[0] == 0) /* No spur */
 			return;
 		max_spur_cnts = 5;
@@ -676,6 +674,10 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
 	if (chan->channel == 2484)
 		ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1);
 
+	if (AR_SREV_9462(ah))
+		REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
+			  AR_GLB_SWREG_DISCONT_EN_BT_WLAN);
+
 	ah->modes_index = modesIndex;
 	ar9003_hw_override_ini(ah);
 	ar9003_hw_set_channel_regs(ah, chan);
@@ -821,18 +823,18 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 			REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
 				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
 
-		if (!on != aniState->ofdmWeakSigDetectOff) {
+		if (on != aniState->ofdmWeakSigDetect) {
 			ath_dbg(common, ANI,
 				"** ch %d: ofdm weak signal: %s=>%s\n",
 				chan->channel,
-				!aniState->ofdmWeakSigDetectOff ?
+				aniState->ofdmWeakSigDetect ?
 				"on" : "off",
 				on ? "on" : "off");
 			if (on)
 				ah->stats.ast_ani_ofdmon++;
 			else
 				ah->stats.ast_ani_ofdmoff++;
-			aniState->ofdmWeakSigDetectOff = !on;
+			aniState->ofdmWeakSigDetect = on;
 		}
 		break;
 	}
@@ -851,7 +853,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 		 * from INI file & cap value
 		 */
 		value = firstep_table[level] -
-			firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
 			aniState->iniDef.firstep;
 		if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
 			value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
@@ -866,7 +868,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 		 * from INI file & cap value
 		 */
 		value2 = firstep_table[level] -
-			 firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			 firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
 			 aniState->iniDef.firstepLow;
 		if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
 			value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
@@ -882,7 +884,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 				chan->channel,
 				aniState->firstepLevel,
 				level,
-				ATH9K_ANI_FIRSTEP_LVL_NEW,
+				ATH9K_ANI_FIRSTEP_LVL,
 				value,
 				aniState->iniDef.firstep);
 			ath_dbg(common, ANI,
@@ -890,7 +892,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 				chan->channel,
 				aniState->firstepLevel,
 				level,
-				ATH9K_ANI_FIRSTEP_LVL_NEW,
+				ATH9K_ANI_FIRSTEP_LVL,
 				value2,
 				aniState->iniDef.firstepLow);
 			if (level > aniState->firstepLevel)
@@ -915,7 +917,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 		 * from INI file & cap value
 		 */
 		value = cycpwrThr1_table[level] -
-			cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
 			aniState->iniDef.cycpwrThr1;
 		if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
 			value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
@@ -931,7 +933,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 		 * from INI file & cap value
 		 */
 		value2 = cycpwrThr1_table[level] -
-			 cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			 cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
 			 aniState->iniDef.cycpwrThr1Ext;
 		if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
 			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
@@ -946,7 +948,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 				chan->channel,
 				aniState->spurImmunityLevel,
 				level,
-				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				ATH9K_ANI_SPUR_IMMUNE_LVL,
 				value,
 				aniState->iniDef.cycpwrThr1);
 			ath_dbg(common, ANI,
@@ -954,7 +956,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 				chan->channel,
 				aniState->spurImmunityLevel,
 				level,
-				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				ATH9K_ANI_SPUR_IMMUNE_LVL,
 				value2,
 				aniState->iniDef.cycpwrThr1Ext);
 			if (level > aniState->spurImmunityLevel)
@@ -975,16 +977,16 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 			      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) {
+		if (is_on != aniState->mrcCCK) {
 			ath_dbg(common, ANI, "** ch %d: MRC CCK: %s=>%s\n",
 				chan->channel,
-				!aniState->mrcCCKOff ? "on" : "off",
+				aniState->mrcCCK ? "on" : "off",
 				is_on ? "on" : "off");
 		if (is_on)
 			ah->stats.ast_ani_ccklow++;
 		else
 			ah->stats.ast_ani_cckhigh++;
-		aniState->mrcCCKOff = !is_on;
+		aniState->mrcCCK = is_on;
 		}
 	break;
 	}
@@ -998,9 +1000,9 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 	ath_dbg(common, ANI,
 		"ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n",
 		aniState->spurImmunityLevel,
-		!aniState->ofdmWeakSigDetectOff ? "on" : "off",
+		aniState->ofdmWeakSigDetect ? "on" : "off",
 		aniState->firstepLevel,
-		!aniState->mrcCCKOff ? "on" : "off",
+		aniState->mrcCCK ? "on" : "off",
 		aniState->listenTime,
 		aniState->ofdmPhyErrCount,
 		aniState->cckPhyErrCount);
@@ -1107,10 +1109,10 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
 					       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->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+	aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+	aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
+	aniState->mrcCCK = true;
 }
 
 static void ar9003_hw_set_radar_params(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 7268a48..ed662c3 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -820,18 +820,26 @@
 #define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK         0x0001
 #define AR_PHY_RX_DELAY_DELAY   0x00003FFF
 #define AR_PHY_CCK_TX_CTRL_JAPAN    0x00000010
-#define AR_PHY_SPECTRAL_SCAN_ENABLE         0x00000001
-#define AR_PHY_SPECTRAL_SCAN_ENABLE_S       0
-#define AR_PHY_SPECTRAL_SCAN_ACTIVE         0x00000002
-#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S       1
-#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD     0x000000F0
-#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S   4
-#define AR_PHY_SPECTRAL_SCAN_PERIOD         0x0000FF00
-#define AR_PHY_SPECTRAL_SCAN_PERIOD_S       8
-#define AR_PHY_SPECTRAL_SCAN_COUNT          0x00FF0000
-#define AR_PHY_SPECTRAL_SCAN_COUNT_S        16
-#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT   0x01000000
-#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24
+
+#define AR_PHY_SPECTRAL_SCAN_ENABLE           0x00000001
+#define AR_PHY_SPECTRAL_SCAN_ENABLE_S         0
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE           0x00000002
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S         1
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD       0x000000F0
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S     4
+#define AR_PHY_SPECTRAL_SCAN_PERIOD           0x0000FF00
+#define AR_PHY_SPECTRAL_SCAN_PERIOD_S         8
+#define AR_PHY_SPECTRAL_SCAN_COUNT            0x0FFF0000
+#define AR_PHY_SPECTRAL_SCAN_COUNT_S          16
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT     0x10000000
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S   28
+#define AR_PHY_SPECTRAL_SCAN_PRIORITY         0x20000000
+#define AR_PHY_SPECTRAL_SCAN_PRIORITY_S       29
+#define AR_PHY_SPECTRAL_SCAN_USE_ERR5         0x40000000
+#define AR_PHY_SPECTRAL_SCAN_USE_ERR5_S       30
+#define AR_PHY_SPECTRAL_SCAN_COMPRESSED_RPT   0x80000000
+#define AR_PHY_SPECTRAL_SCAN_COMPRESSED_RPT_S 31
+
 #define AR_PHY_CHANNEL_STATUS_RX_CLEAR      0x00000004
 #define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION     0x00000001
 #define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION_S   0
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
index 1d6658e..bbf48918a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
@@ -52,7 +52,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
 	{0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
 	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8},
 	{0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e},
-	{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x33795d5e},
+	{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x32395d5e},
 	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
 	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
@@ -61,7 +61,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
 	{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
 	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
 	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
-	{0x0000a204, 0x013187c0, 0x013187c4, 0x013187c4, 0x013187c0},
+	{0x0000a204, 0x01318fc0, 0x01318fc4, 0x01318fc4, 0x01318fc0},
 	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
 	{0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f},
 	{0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
@@ -958,7 +958,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
 	{0x0001604c, 0x2699e04f},
 	{0x00016050, 0x6db6db6c},
 	{0x00016058, 0x6c200000},
-	{0x00016080, 0x00040000},
+	{0x00016080, 0x000c0000},
 	{0x00016084, 0x9a68048c},
 	{0x00016088, 0x54214514},
 	{0x0001608c, 0x1203040b},
@@ -981,7 +981,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
 	{0x00016144, 0x02084080},
 	{0x00016148, 0x000080c0},
 	{0x00016280, 0x050a0001},
-	{0x00016284, 0x3d841400},
+	{0x00016284, 0x3d841418},
 	{0x00016288, 0x00000000},
 	{0x0001628c, 0xe3000000},
 	{0x00016290, 0xa1005080},
@@ -1007,6 +1007,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
 
 static const u32 ar9462_2p0_soc_preamble[][2] = {
 	/* Addr      allmodes  */
+	{0x000040a4 ,0x00a0c1c9},
 	{0x00007020, 0x00000000},
 	{0x00007034, 0x00000002},
 	{0x00007038, 0x000004c2},
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index a277cf6..fe39eb4 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -214,6 +214,7 @@ struct ath_frame_info {
 	enum ath9k_key_type keytype;
 	u8 keyix;
 	u8 retries;
+	u8 rtscts_rate;
 };
 
 struct ath_buf_state {
@@ -307,6 +308,7 @@ struct ath_rx {
 	u8 defant;
 	u8 rxotherant;
 	u32 *rxlink;
+	u32 num_pkts;
 	unsigned int rxfilter;
 	spinlock_t rxbuflock;
 	struct list_head rxbuf;
@@ -325,6 +327,9 @@ int ath_rx_init(struct ath_softc *sc, int nbufs);
 void ath_rx_cleanup(struct ath_softc *sc);
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp);
 struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
+void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq);
+void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq);
+void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq);
 void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
 bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
 void ath_draintxq(struct ath_softc *sc,
@@ -414,9 +419,9 @@ int ath_beaconq_config(struct ath_softc *sc);
 void ath_set_beacon(struct ath_softc *sc);
 void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
 
-/*******/
-/* ANI */
-/*******/
+/*******************/
+/* Link Monitoring */
+/*******************/
 
 #define ATH_STA_SHORT_CALINTERVAL 1000    /* 1 second */
 #define ATH_AP_SHORT_CALINTERVAL  100     /* 100 ms */
@@ -427,7 +432,9 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
 #define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
 
 #define ATH_PAPRD_TIMEOUT	100 /* msecs */
+#define ATH_PLL_WORK_INTERVAL   100
 
+void ath_tx_complete_poll_work(struct work_struct *work);
 void ath_reset_work(struct work_struct *work);
 void ath_hw_check(struct work_struct *work);
 void ath_hw_pll_work(struct work_struct *work);
@@ -436,22 +443,31 @@ void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon);
 void ath_paprd_calibrate(struct work_struct *work);
 void ath_ani_calibrate(unsigned long data);
 void ath_start_ani(struct ath_common *common);
+int ath_update_survey_stats(struct ath_softc *sc);
+void ath_update_survey_nf(struct ath_softc *sc, int channel);
 
 /**********/
 /* BTCOEX */
 /**********/
 
+enum bt_op_flags {
+	BT_OP_PRIORITY_DETECTED,
+	BT_OP_SCAN,
+};
+
 struct ath_btcoex {
 	bool hw_timer_enabled;
 	spinlock_t btcoex_lock;
 	struct timer_list period_timer; /* Timer for BT period */
 	u32 bt_priority_cnt;
 	unsigned long bt_priority_time;
+	unsigned long op_flags;
 	int bt_stomp_type; /* Types of BT stomping */
 	u32 btcoex_no_stomp; /* in usec */
 	u32 btcoex_period; /* in usec */
 	u32 btscan_no_stomp; /* in usec */
 	u32 duty_cycle;
+	u32 bt_wait_time;
 	struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
 	struct ath_mci_profile mci;
 };
@@ -513,8 +529,10 @@ static inline void ath_deinit_leds(struct ath_softc *sc)
 }
 #endif
 
-
+/*******************************/
 /* Antenna diversity/combining */
+/*******************************/
+
 #define ATH_ANT_RX_CURRENT_SHIFT 4
 #define ATH_ANT_RX_MAIN_SHIFT 2
 #define ATH_ANT_RX_MASK 0x3
@@ -567,6 +585,9 @@ struct ath_ant_comb {
 	unsigned long scan_start_time;
 };
 
+void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
+void ath_ant_comb_update(struct ath_softc *sc);
+
 /********************/
 /* Main driver core */
 /********************/
@@ -584,15 +605,15 @@ struct ath_ant_comb {
 #define ATH_TXPOWER_MAX         100     /* .5 dBm units */
 #define ATH_RATE_DUMMY_MARKER   0
 
-#define SC_OP_INVALID                BIT(0)
-#define SC_OP_BEACONS                BIT(1)
-#define SC_OP_OFFCHANNEL             BIT(2)
-#define SC_OP_RXFLUSH                BIT(3)
-#define SC_OP_TSF_RESET              BIT(4)
-#define SC_OP_BT_PRIORITY_DETECTED   BIT(5)
-#define SC_OP_BT_SCAN                BIT(6)
-#define SC_OP_ANI_RUN                BIT(7)
-#define SC_OP_PRIM_STA_VIF           BIT(8)
+enum sc_op_flags {
+	SC_OP_INVALID,
+	SC_OP_BEACONS,
+	SC_OP_RXFLUSH,
+	SC_OP_TSF_RESET,
+	SC_OP_ANI_RUN,
+	SC_OP_PRIM_STA_VIF,
+	SC_OP_HW_RESET,
+};
 
 /* Powersave flags */
 #define PS_WAIT_FOR_BEACON        BIT(0)
@@ -638,9 +659,9 @@ struct ath_softc {
 	struct completion paprd_complete;
 
 	unsigned int hw_busy_count;
+	unsigned long sc_flags;
 
 	u32 intrstatus;
-	u32 sc_flags; /* SC_OP_* */
 	u16 ps_flags; /* PS_* */
 	u16 curtxpow;
 	bool ps_enabled;
@@ -678,6 +699,7 @@ struct ath_softc {
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 	struct ath_btcoex btcoex;
 	struct ath_mci_coex mci_coex;
+	struct work_struct mci_work;
 #endif
 
 	struct ath_descdma txsdma;
@@ -700,6 +722,7 @@ extern int ath9k_modparam_nohwcrypt;
 extern int led_blink;
 extern bool is_ath9k_unloaded;
 
+u8 ath9k_parse_mpdudensity(u8 mpdudensity);
 irqreturn_t ath_isr(int irq, void *dev);
 int ath9k_init_device(u16 devid, struct ath_softc *sc,
 		    const struct ath_bus_ops *bus_ops);
@@ -736,5 +759,4 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
 			       struct ieee80211_vif *vif,
 			       struct ath9k_vif_iter_data *iter_data);
 
-
 #endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 11bc55e..40775da 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -48,7 +48,10 @@ int ath_beaconq_config(struct ath_softc *sc)
 		txq = sc->tx.txq_map[WME_AC_BE];
 		ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
 		qi.tqi_aifs = qi_be.tqi_aifs;
-		qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
+		if (ah->slottime == ATH9K_SLOT_TIME_20)
+			qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
+		else
+			qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
 		qi.tqi_cwmax = qi_be.tqi_cwmax;
 	}
 
@@ -387,7 +390,7 @@ void ath_beacon_tasklet(unsigned long data)
 		} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
 			ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
 			sc->beacon.bmisscnt = 0;
-			sc->sc_flags |= SC_OP_TSF_RESET;
+			set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
 			ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
 		}
 
@@ -477,16 +480,16 @@ static void ath9k_beacon_init(struct ath_softc *sc,
 			      u32 next_beacon,
 			      u32 beacon_period)
 {
-	if (sc->sc_flags & SC_OP_TSF_RESET) {
+	if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
 		ath9k_ps_wakeup(sc);
 		ath9k_hw_reset_tsf(sc->sc_ah);
 	}
 
 	ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
 
-	if (sc->sc_flags & SC_OP_TSF_RESET) {
+	if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
 		ath9k_ps_restore(sc);
-		sc->sc_flags &= ~SC_OP_TSF_RESET;
+		clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
 	}
 }
 
@@ -516,7 +519,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
 	/* Set the computed AP beacon timers */
 
 	ath9k_hw_disable_interrupts(ah);
-	sc->sc_flags |= SC_OP_TSF_RESET;
+	set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
 	ath9k_beacon_init(sc, nexttbtt, intval);
 	sc->beacon.bmisscnt = 0;
 	ath9k_hw_set_interrupts(ah);
@@ -659,7 +662,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
 	u32 tsf, intval, nexttbtt;
 
 	ath9k_reset_beacon_status(sc);
-	if (!(sc->sc_flags & SC_OP_BEACONS))
+	if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
 		ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp);
 
 	intval = TU_TO_USEC(conf->beacon_interval);
@@ -724,7 +727,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
 	 */
 	if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
 	    (vif->type == NL80211_IFTYPE_STATION) &&
-	    (sc->sc_flags & SC_OP_BEACONS) &&
+	    test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
 	    !avp->primary_sta_vif) {
 		ath_dbg(common, CONFIG,
 			"Beacon already configured for a station interface\n");
@@ -810,7 +813,7 @@ void ath_set_beacon(struct ath_softc *sc)
 		return;
 	}
 
-	sc->sc_flags |= SC_OP_BEACONS;
+	set_bit(SC_OP_BEACONS, &sc->sc_flags);
 }
 
 void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
@@ -818,7 +821,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
 	struct ath_hw *ah = sc->sc_ah;
 
 	if (!ath_has_valid_bslot(sc)) {
-		sc->sc_flags &= ~SC_OP_BEACONS;
+		clear_bit(SC_OP_BEACONS, &sc->sc_flags);
 		return;
 	}
 
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index 1ca6da8..acd4373 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -336,10 +336,16 @@ static void ar9003_btcoex_bt_stomp(struct ath_hw *ah,
 			 enum ath_stomp_type stomp_type)
 {
 	struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
-	const u32 *weight = AR_SREV_9462(ah) ? ar9003_wlan_weights[stomp_type] :
-					       ar9462_wlan_weights[stomp_type];
+	const u32 *weight = ar9003_wlan_weights[stomp_type];
 	int i;
 
+	if (AR_SREV_9462(ah)) {
+		if ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
+		    btcoex->mci.stomp_ftp)
+			stomp_type = ATH_BTCOEX_STOMP_LOW_FTP;
+		weight = ar9462_wlan_weights[stomp_type];
+	}
+
 	for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
 		btcoex->bt_weight[i] = AR9300_BT_WGHT;
 		btcoex->wlan_weight[i] = weight[i];
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 3a1e1cf..20092f9 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -36,6 +36,9 @@
 #define ATH_BT_CNT_THRESHOLD	       3
 #define ATH_BT_CNT_SCAN_THRESHOLD      15
 
+#define ATH_BTCOEX_RX_WAIT_TIME       100
+#define ATH_BTCOEX_STOMP_FTP_THRESH   5
+
 #define AR9300_NUM_BT_WEIGHTS   4
 #define AR9300_NUM_WLAN_WEIGHTS 4
 /* Defines the BT AR_BT_COEX_WGHT used */
@@ -80,6 +83,7 @@ struct ath9k_hw_mci {
 	u8 bt_ver_major;
 	u8 bt_ver_minor;
 	u8 bt_state;
+	u8 stomp_ftp;
 };
 
 struct ath_btcoex_hw {
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index fde700c..5c3192f 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -205,10 +205,10 @@ static ssize_t write_file_disable_ani(struct file *file,
 	common->disable_ani = !!disable_ani;
 
 	if (disable_ani) {
-		sc->sc_flags &= ~SC_OP_ANI_RUN;
+		clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
 		del_timer_sync(&common->ani.timer);
 	} else {
-		sc->sc_flags |= SC_OP_ANI_RUN;
+		set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
 		ath_start_ani(common);
 	}
 
@@ -348,8 +348,6 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
 		sc->debug.stats.istats.txok++;
 	if (status & ATH9K_INT_TXURN)
 		sc->debug.stats.istats.txurn++;
-	if (status & ATH9K_INT_MIB)
-		sc->debug.stats.istats.mib++;
 	if (status & ATH9K_INT_RXPHY)
 		sc->debug.stats.istats.rxphyerr++;
 	if (status & ATH9K_INT_RXKCM)
@@ -374,6 +372,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
 		sc->debug.stats.istats.dtim++;
 	if (status & ATH9K_INT_TSFOOR)
 		sc->debug.stats.istats.tsfoor++;
+	if (status & ATH9K_INT_MCI)
+		sc->debug.stats.istats.mci++;
 }
 
 static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
@@ -418,6 +418,7 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
 	PR_IS("DTIMSYNC", dtimsync);
 	PR_IS("DTIM", dtim);
 	PR_IS("TSFOOR", tsfoor);
+	PR_IS("MCI", mci);
 	PR_IS("TOTAL", total);
 
 	len += snprintf(buf + len, mxlen - len,
@@ -1318,7 +1319,7 @@ static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
 	u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
 	u8 nread;
 
-	if (sc->sc_flags & SC_OP_INVALID)
+	if (test_bit(SC_OP_INVALID, &sc->sc_flags))
 		return -EAGAIN;
 
 	buf = vmalloc(size);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index c34da09..d0f851c 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -86,6 +86,7 @@ struct ath_interrupt_stats {
 	u32 dtim;
 	u32 bb_watchdog;
 	u32 tsfoor;
+	u32 mci;
 
 	/* Sync-cause stats */
 	u32 sync_cause_all;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 4322ac8..7d07510 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -135,7 +135,7 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
 	if (!dump_base_hdr) {
 		len += snprintf(buf + len, size - len,
 				"%20s :\n", "2GHz modal Header");
-		len += ath9k_dump_4k_modal_eeprom(buf, len, size,
+		len = ath9k_dump_4k_modal_eeprom(buf, len, size,
 						  &eep->modalHeader);
 		goto out;
 	}
@@ -188,8 +188,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
 {
 #define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
 	struct ath_common *common = ath9k_hw_common(ah);
-	struct ar5416_eeprom_4k *eep =
-		(struct ar5416_eeprom_4k *) &ah->eeprom.map4k;
+	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
 	u16 *eepdata, temp, magic, magic2;
 	u32 sum = 0, el;
 	bool need_swap = false;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index aa61476..cd742fb 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -132,7 +132,7 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
 	if (!dump_base_hdr) {
 		len += snprintf(buf + len, size - len,
 				"%20s :\n", "2GHz modal Header");
-		len += ar9287_dump_modal_eeprom(buf, len, size,
+		len = ar9287_dump_modal_eeprom(buf, len, size,
 						&eep->modalHeader);
 		goto out;
 	}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index b5fba8b..a8ac30a 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -211,11 +211,11 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
 	if (!dump_base_hdr) {
 		len += snprintf(buf + len, size - len,
 				"%20s :\n", "2GHz modal Header");
-		len += ath9k_def_dump_modal_eeprom(buf, len, size,
+		len = ath9k_def_dump_modal_eeprom(buf, len, size,
 						   &eep->modalHeader[0]);
 		len += snprintf(buf + len, size - len,
 				"%20s :\n", "5GHz modal Header");
-		len += ath9k_def_dump_modal_eeprom(buf, len, size,
+		len = ath9k_def_dump_modal_eeprom(buf, len, size,
 						   &eep->modalHeader[1]);
 		goto out;
 	}
@@ -264,8 +264,7 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
 
 static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
 {
-	struct ar5416_eeprom_def *eep =
-		(struct ar5416_eeprom_def *) &ah->eeprom.def;
+	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
 	struct ath_common *common = ath9k_hw_common(ah);
 	u16 *eepdata, temp, magic, magic2;
 	u32 sum = 0, el;
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 281a9af..26032cb 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -132,17 +132,18 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
 
 	if (time_after(jiffies, btcoex->bt_priority_time +
 			msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
-		sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
+		clear_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
+		clear_bit(BT_OP_SCAN, &btcoex->op_flags);
 		/* Detect if colocated bt started scanning */
 		if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
 			ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
 				"BT scan detected\n");
-			sc->sc_flags |= (SC_OP_BT_SCAN |
-					 SC_OP_BT_PRIORITY_DETECTED);
+			set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
+			set_bit(BT_OP_SCAN, &btcoex->op_flags);
 		} else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
 			ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
 				"BT priority traffic detected\n");
-			sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
+			set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
 		}
 
 		btcoex->bt_priority_cnt = 0;
@@ -190,13 +191,26 @@ static void ath_btcoex_period_timer(unsigned long data)
 	struct ath_softc *sc = (struct ath_softc *) data;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_btcoex *btcoex = &sc->btcoex;
+	struct ath_mci_profile *mci = &btcoex->mci;
 	u32 timer_period;
 	bool is_btscan;
 
 	ath9k_ps_wakeup(sc);
 	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
 		ath_detect_bt_priority(sc);
-	is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
+	is_btscan = test_bit(BT_OP_SCAN, &btcoex->op_flags);
+
+	btcoex->bt_wait_time += btcoex->btcoex_period;
+	if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) {
+		if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) &&
+		    (mci->num_pan || mci->num_other_acl))
+			ah->btcoex_hw.mci.stomp_ftp =
+				(sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH);
+		else
+			ah->btcoex_hw.mci.stomp_ftp = false;
+		btcoex->bt_wait_time = 0;
+		sc->rx.num_pkts = 0;
+	}
 
 	spin_lock_bh(&btcoex->btcoex_lock);
 
@@ -218,9 +232,8 @@ static void ath_btcoex_period_timer(unsigned long data)
 	}
 
 	ath9k_ps_restore(sc);
-	timer_period = btcoex->btcoex_period / 1000;
-	mod_timer(&btcoex->period_timer, jiffies +
-				  msecs_to_jiffies(timer_period));
+	timer_period = btcoex->btcoex_period;
+	mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period));
 }
 
 /*
@@ -233,14 +246,14 @@ static void ath_btcoex_no_stomp_timer(void *arg)
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_btcoex *btcoex = &sc->btcoex;
 	struct ath_common *common = ath9k_hw_common(ah);
-	bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
 
 	ath_dbg(common, BTCOEX, "no stomp timer running\n");
 
 	ath9k_ps_wakeup(sc);
 	spin_lock_bh(&btcoex->btcoex_lock);
 
-	if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
+	if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW ||
+	    test_bit(BT_OP_SCAN, &btcoex->op_flags))
 		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
 	 else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
 		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
@@ -254,10 +267,10 @@ static int ath_init_btcoex_timer(struct ath_softc *sc)
 {
 	struct ath_btcoex *btcoex = &sc->btcoex;
 
-	btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
-	btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+	btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
+	btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 1000 *
 		btcoex->btcoex_period / 100;
-	btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
+	btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * 1000 *
 				   btcoex->btcoex_period / 100;
 
 	setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
@@ -292,7 +305,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
 
 	btcoex->bt_priority_cnt = 0;
 	btcoex->bt_priority_time = jiffies;
-	sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
+	btcoex->op_flags &= ~(BT_OP_PRIORITY_DETECTED | BT_OP_SCAN);
 
 	mod_timer(&btcoex->period_timer, jiffies);
 }
@@ -316,12 +329,13 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc)
 
 u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
 {
+	struct ath_btcoex *btcoex = &sc->btcoex;
 	struct ath_mci_profile *mci = &sc->btcoex.mci;
 	u16 aggr_limit = 0;
 
 	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
 		aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4;
-	else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
+	else if (test_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags))
 		aggr_limit = min((max_4ms_framelen * 3) / 8,
 				 (u32)ATH_AMPDU_LIMIT_MAX);
 
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 1357952..936e920 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -453,7 +453,6 @@ struct ath9k_htc_priv {
 	u8 num_sta_assoc_vif;
 	u8 num_ap_vif;
 
-	u16 op_flags;
 	u16 curtxpow;
 	u16 txpowlimit;
 	u16 nvifs;
@@ -461,6 +460,7 @@ struct ath9k_htc_priv {
 	bool rearm_ani;
 	bool reconfig_beacon;
 	unsigned int rxfilter;
+	unsigned long op_flags;
 
 	struct ath9k_hw_cal_data caldata;
 	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
@@ -572,8 +572,6 @@ bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
 
 void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv);
 void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw);
-void ath9k_htc_radio_enable(struct ieee80211_hw *hw);
-void ath9k_htc_radio_disable(struct ieee80211_hw *hw);
 
 #ifdef CONFIG_MAC80211_LEDS
 void ath9k_init_leds(struct ath9k_htc_priv *priv);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index 2eadffb..77d541f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -207,9 +207,9 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
 	else
 		priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
 
-	if (priv->op_flags & OP_TSF_RESET) {
+	if (test_bit(OP_TSF_RESET, &priv->op_flags)) {
 		ath9k_hw_reset_tsf(priv->ah);
-		priv->op_flags &= ~OP_TSF_RESET;
+		clear_bit(OP_TSF_RESET, &priv->op_flags);
 	} else {
 		/*
 		 * Pull nexttbtt forward to reflect the current TSF.
@@ -221,7 +221,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
 		} while (nexttbtt < tsftu);
 	}
 
-	if (priv->op_flags & OP_ENABLE_BEACON)
+	if (test_bit(OP_ENABLE_BEACON, &priv->op_flags))
 		imask |= ATH9K_INT_SWBA;
 
 	ath_dbg(common, CONFIG,
@@ -269,7 +269,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
 	else
 		priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
 
-	if (priv->op_flags & OP_ENABLE_BEACON)
+	if (test_bit(OP_ENABLE_BEACON, &priv->op_flags))
 		imask |= ATH9K_INT_SWBA;
 
 	ath_dbg(common, CONFIG,
@@ -365,7 +365,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
 	vif = priv->cur_beacon_conf.bslot[slot];
 	avp = (struct ath9k_htc_vif *)vif->drv_priv;
 
-	if (unlikely(priv->op_flags & OP_SCANNING)) {
+	if (unlikely(test_bit(OP_SCANNING, &priv->op_flags))) {
 		spin_unlock_bh(&priv->beacon_lock);
 		return;
 	}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index 1c10e2e..07df279 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -37,17 +37,18 @@ static void ath_detect_bt_priority(struct ath9k_htc_priv *priv)
 
 	if (time_after(jiffies, btcoex->bt_priority_time +
 			msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
-		priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
+		clear_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
+		clear_bit(OP_BT_SCAN, &priv->op_flags);
 		/* Detect if colocated bt started scanning */
 		if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
 			ath_dbg(ath9k_hw_common(ah), BTCOEX,
 				"BT scan detected\n");
-			priv->op_flags |= (OP_BT_SCAN |
-					 OP_BT_PRIORITY_DETECTED);
+			set_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
+			set_bit(OP_BT_SCAN, &priv->op_flags);
 		} else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
 			ath_dbg(ath9k_hw_common(ah), BTCOEX,
 				"BT priority traffic detected\n");
-			priv->op_flags |= OP_BT_PRIORITY_DETECTED;
+			set_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
 		}
 
 		btcoex->bt_priority_cnt = 0;
@@ -67,26 +68,23 @@ static void ath_btcoex_period_work(struct work_struct *work)
 	struct ath_btcoex *btcoex = &priv->btcoex;
 	struct ath_common *common = ath9k_hw_common(priv->ah);
 	u32 timer_period;
-	bool is_btscan;
 	int ret;
 
 	ath_detect_bt_priority(priv);
 
-	is_btscan = !!(priv->op_flags & OP_BT_SCAN);
-
 	ret = ath9k_htc_update_cap_target(priv,
-				  !!(priv->op_flags & OP_BT_PRIORITY_DETECTED));
+			  test_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags));
 	if (ret) {
 		ath_err(common, "Unable to set BTCOEX parameters\n");
 		return;
 	}
 
-	ath9k_hw_btcoex_bt_stomp(priv->ah, is_btscan ? ATH_BTCOEX_STOMP_ALL :
-			btcoex->bt_stomp_type);
+	ath9k_hw_btcoex_bt_stomp(priv->ah, test_bit(OP_BT_SCAN, &priv->op_flags) ?
+				 ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type);
 
 	ath9k_hw_btcoex_enable(priv->ah);
-	timer_period = is_btscan ? btcoex->btscan_no_stomp :
-		btcoex->btcoex_no_stomp;
+	timer_period = test_bit(OP_BT_SCAN, &priv->op_flags) ?
+		btcoex->btscan_no_stomp : btcoex->btcoex_no_stomp;
 	ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work,
 				     msecs_to_jiffies(timer_period));
 	ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work,
@@ -104,14 +102,15 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work)
 	struct ath_hw *ah = priv->ah;
 	struct ath_btcoex *btcoex = &priv->btcoex;
 	struct ath_common *common = ath9k_hw_common(ah);
-	bool is_btscan = priv->op_flags & OP_BT_SCAN;
 
 	ath_dbg(common, BTCOEX, "time slice work for bt and wlan\n");
 
-	if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
+	if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW ||
+	    test_bit(OP_BT_SCAN, &priv->op_flags))
 		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
 	else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
 		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
+
 	ath9k_hw_btcoex_enable(priv->ah);
 }
 
@@ -141,7 +140,8 @@ static void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
 
 	btcoex->bt_priority_cnt = 0;
 	btcoex->bt_priority_time = jiffies;
-	priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
+	clear_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
+	clear_bit(OP_BT_SCAN, &priv->op_flags);
 	ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0);
 }
 
@@ -310,95 +310,3 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
 	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		wiphy_rfkill_start_polling(priv->hw->wiphy);
 }
-
-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, ah->caldata, false);
-	if (ret) {
-		ath_err(common,
-			"Unable to reset hardware; reset status %d (freq %u MHz)\n",
-			ret, ah->curchan->channel);
-	}
-
-	ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit,
-			       &priv->curtxpow);
-
-	/* Start RX */
-	WMI_CMD(WMI_START_RECV_CMDID);
-	ath9k_host_rx_init(priv);
-
-	/* Start TX */
-	htc_start(priv->htc);
-	spin_lock_bh(&priv->tx.tx_lock);
-	priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
-	spin_unlock_bh(&priv->tx.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);
-}
-
-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);
-	ath9k_htc_tx_drain(priv);
-	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
-
-	/* Stop RX */
-	WMI_CMD(WMI_STOP_RECV_CMDID);
-
-	/* Clear the WMI event queue */
-	ath9k_wmi_event_drain(priv);
-
-	/*
-	 * 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, ah->caldata, false);
-	if (ret) {
-		ath_err(common,
-			"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);
-}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 25213d5..a035a38 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -611,7 +611,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
 	struct ath_common *common;
 	int i, ret = 0, csz = 0;
 
-	priv->op_flags |= OP_INVALID;
+	set_bit(OP_INVALID, &priv->op_flags);
 
 	ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
 	if (!ah)
@@ -718,7 +718,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
 
 	hw->queues = 4;
 	hw->channel_change_time = 5000;
-	hw->max_listen_interval = 10;
+	hw->max_listen_interval = 1;
 
 	hw->vif_data_size = sizeof(struct ath9k_htc_vif);
 	hw->sta_data_size = sizeof(struct ath9k_htc_sta);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 2b8f61c..374c32e 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -75,14 +75,19 @@ unlock:
 
 void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv)
 {
+	bool reset;
+
 	mutex_lock(&priv->htc_pm_lock);
 	if (--priv->ps_usecount != 0)
 		goto unlock;
 
-	if (priv->ps_idle)
+	if (priv->ps_idle) {
+		ath9k_hw_setrxabort(priv->ah, true);
+		ath9k_hw_stopdmarecv(priv->ah, &reset);
 		ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP);
-	else if (priv->ps_enabled)
+	} else if (priv->ps_enabled) {
 		ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
+	}
 
 unlock:
 	mutex_unlock(&priv->htc_pm_lock);
@@ -250,7 +255,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
 	u8 cmd_rsp;
 	int ret;
 
-	if (priv->op_flags & OP_INVALID)
+	if (test_bit(OP_INVALID, &priv->op_flags))
 		return -EIO;
 
 	fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
@@ -304,7 +309,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
 
 	htc_start(priv->htc);
 
-	if (!(priv->op_flags & OP_SCANNING) &&
+	if (!test_bit(OP_SCANNING, &priv->op_flags) &&
 	    !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
 		ath9k_htc_vif_reconfig(priv);
 
@@ -750,7 +755,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)
 	common->ani.shortcal_timer = timestamp;
 	common->ani.checkani_timer = timestamp;
 
-	priv->op_flags |= OP_ANI_RUNNING;
+	set_bit(OP_ANI_RUNNING, &priv->op_flags);
 
 	ieee80211_queue_delayed_work(common->hw, &priv->ani_work,
 				     msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
@@ -759,7 +764,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)
 void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv)
 {
 	cancel_delayed_work_sync(&priv->ani_work);
-	priv->op_flags &= ~OP_ANI_RUNNING;
+	clear_bit(OP_ANI_RUNNING, &priv->op_flags);
 }
 
 void ath9k_htc_ani_work(struct work_struct *work)
@@ -944,7 +949,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
 		ath_dbg(common, CONFIG,
 			"Failed to update capability in target\n");
 
-	priv->op_flags &= ~OP_INVALID;
+	clear_bit(OP_INVALID, &priv->op_flags);
 	htc_start(priv->htc);
 
 	spin_lock_bh(&priv->tx.tx_lock);
@@ -973,7 +978,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
 
 	mutex_lock(&priv->mutex);
 
-	if (priv->op_flags & OP_INVALID) {
+	if (test_bit(OP_INVALID, &priv->op_flags)) {
 		ath_dbg(common, ANY, "Device not present\n");
 		mutex_unlock(&priv->mutex);
 		return;
@@ -1015,7 +1020,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
 	ath9k_htc_ps_restore(priv);
 	ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
 
-	priv->op_flags |= OP_INVALID;
+	set_bit(OP_INVALID, &priv->op_flags);
 
 	ath_dbg(common, CONFIG, "Driver halt\n");
 	mutex_unlock(&priv->mutex);
@@ -1105,7 +1110,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
 	ath9k_htc_set_opmode(priv);
 
 	if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
-	    !(priv->op_flags & OP_ANI_RUNNING)) {
+	    !test_bit(OP_ANI_RUNNING, &priv->op_flags)) {
 		ath9k_hw_set_tsfadjust(priv->ah, 1);
 		ath9k_htc_start_ani(priv);
 	}
@@ -1178,24 +1183,20 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
 	struct ath9k_htc_priv *priv = hw->priv;
 	struct ath_common *common = ath9k_hw_common(priv->ah);
 	struct ieee80211_conf *conf = &hw->conf;
+	bool chip_reset = false;
+	int ret = 0;
 
 	mutex_lock(&priv->mutex);
+	ath9k_htc_ps_wakeup(priv);
 
 	if (changed & IEEE80211_CONF_CHANGE_IDLE) {
-		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) {
-			ath_dbg(common, CONFIG, "not-idle: enabling radio\n");
-			ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
-			ath9k_htc_radio_enable(hw);
-		}
+		priv->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
+		if (priv->ps_idle)
+			chip_reset = true;
+
+		mutex_unlock(&priv->htc_pm_lock);
 	}
 
 	/*
@@ -1210,7 +1211,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
 			ath9k_htc_remove_monitor_interface(priv);
 	}
 
-	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+	if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || chip_reset) {
 		struct ieee80211_channel *curchan = hw->conf.channel;
 		int pos = curchan->hw_value;
 
@@ -1223,8 +1224,8 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
 
 		if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
 			ath_err(common, "Unable to set channel\n");
-			mutex_unlock(&priv->mutex);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 
 	}
@@ -1246,21 +1247,10 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
 				       priv->txpowlimit, &priv->curtxpow);
 	}
 
-	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_dbg(common, CONFIG, "idle: disabling radio\n");
-		ath9k_htc_radio_disable(hw);
-	}
-
 out:
+	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
-	return 0;
+	return ret;
 }
 
 #define SUPPORTED_FILTERS			\
@@ -1285,7 +1275,7 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
 	changed_flags &= SUPPORTED_FILTERS;
 	*total_flags &= SUPPORTED_FILTERS;
 
-	if (priv->op_flags & OP_INVALID) {
+	if (test_bit(OP_INVALID, &priv->op_flags)) {
 		ath_dbg(ath9k_hw_common(priv->ah), ANY,
 			"Unable to configure filter on invalid state\n");
 		mutex_unlock(&priv->mutex);
@@ -1496,6 +1486,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
 			priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--;
 
 		if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
+			ath9k_htc_choose_set_bssid(priv);
 			if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1))
 				ath9k_htc_start_ani(priv);
 			else if (priv->num_sta_assoc_vif == 0)
@@ -1503,13 +1494,11 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
 		}
 	}
 
-	if (changed & BSS_CHANGED_BSSID) {
+	if (changed & BSS_CHANGED_IBSS) {
 		if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
 			common->curaid = bss_conf->aid;
 			memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
 			ath9k_htc_set_bssid(priv);
-		} else if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
-			ath9k_htc_choose_set_bssid(priv);
 		}
 	}
 
@@ -1517,7 +1506,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
 		ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n",
 			bss_conf->bssid);
 		ath9k_htc_set_tsfadjust(priv, vif);
-		priv->op_flags |= OP_ENABLE_BEACON;
+		set_bit(OP_ENABLE_BEACON, &priv->op_flags);
 		ath9k_htc_beacon_config(priv, vif);
 	}
 
@@ -1530,7 +1519,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
 			ath_dbg(common, CONFIG,
 				"Beacon disabled for BSS: %pM\n",
 				bss_conf->bssid);
-			priv->op_flags &= ~OP_ENABLE_BEACON;
+			clear_bit(OP_ENABLE_BEACON, &priv->op_flags);
 			ath9k_htc_beacon_config(priv, vif);
 		}
 	}
@@ -1543,7 +1532,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
 		    (priv->nvifs == 1) &&
 		    (priv->num_ap_vif == 1) &&
 		    (vif->type == NL80211_IFTYPE_AP)) {
-			priv->op_flags |= OP_TSF_RESET;
+			set_bit(OP_TSF_RESET, &priv->op_flags);
 		}
 		ath_dbg(common, CONFIG,
 			"Beacon interval changed for BSS: %pM\n",
@@ -1655,7 +1644,7 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
 
 	mutex_lock(&priv->mutex);
 	spin_lock_bh(&priv->beacon_lock);
-	priv->op_flags |= OP_SCANNING;
+	set_bit(OP_SCANNING, &priv->op_flags);
 	spin_unlock_bh(&priv->beacon_lock);
 	cancel_work_sync(&priv->ps_work);
 	ath9k_htc_stop_ani(priv);
@@ -1668,7 +1657,7 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
 
 	mutex_lock(&priv->mutex);
 	spin_lock_bh(&priv->beacon_lock);
-	priv->op_flags &= ~OP_SCANNING;
+	clear_bit(OP_SCANNING, &priv->op_flags);
 	spin_unlock_bh(&priv->beacon_lock);
 	ath9k_htc_ps_wakeup(priv);
 	ath9k_htc_vif_reconfig(priv);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 3e40a64..47e61d0 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -916,7 +916,7 @@ void ath9k_host_rx_init(struct ath9k_htc_priv *priv)
 {
 	ath9k_hw_rxena(priv->ah);
 	ath9k_htc_opmode_init(priv);
-	ath9k_hw_startpcureceive(priv->ah, (priv->op_flags & OP_SCANNING));
+	ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags));
 	priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 7db1890..a42c26f 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -390,14 +390,6 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
 	REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 }
 
-static void ath9k_hw_aspm_init(struct ath_hw *ah)
-{
-	struct ath_common *common = ath9k_hw_common(ah);
-
-	if (common->bus_ops->aspm_init)
-		common->bus_ops->aspm_init(common);
-}
-
 /* This should work for all families including legacy */
 static bool ath9k_hw_chip_test(struct ath_hw *ah)
 {
@@ -693,9 +685,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 	if (r)
 		return r;
 
-	if (ah->is_pciexpress)
-		ath9k_hw_aspm_init(ah);
-
 	r = ath9k_hw_init_macaddr(ah);
 	if (r) {
 		ath_err(common, "Failed to initialize MAC address\n");
@@ -784,13 +773,25 @@ static void ath9k_hw_init_qos(struct ath_hw *ah)
 
 u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
 {
+	struct ath_common *common = ath9k_hw_common(ah);
+	int i = 0;
+
 	REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK);
 	udelay(100);
 	REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK);
 
-	while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0)
+	while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) {
+
 		udelay(100);
 
+		if (WARN_ON_ONCE(i >= 100)) {
+			ath_err(common, "PLL4 meaurement not done\n");
+			break;
+		}
+
+		i++;
+	}
+
 	return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3;
 }
 EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc);
@@ -1359,6 +1360,9 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
 		}
 	}
 
+	if (ath9k_hw_mci_is_enabled(ah))
+		ar9003_mci_check_gpm_offset(ah);
+
 	REG_WRITE(ah, AR_RTC_RC, rst_flags);
 
 	REGWRITE_BUFFER_FLUSH(ah);
@@ -1443,9 +1447,6 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 		break;
 	}
 
-	if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
-		REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
-
 	return ret;
 }
 
@@ -1721,8 +1722,8 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
 	ath9k_hw_loadnf(ah, ah->curchan);
 	ath9k_hw_start_nfcal(ah, true);
 
-	if ((ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && ar9003_mci_is_ready(ah))
-		ar9003_mci_2g5g_switch(ah, true);
+	if (ath9k_hw_mci_is_enabled(ah))
+		ar9003_mci_2g5g_switch(ah, false);
 
 	if (AR_SREV_9271(ah))
 		ar9002_hw_load_ani_reg(ah, chan);
@@ -1742,10 +1743,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	u64 tsf = 0;
 	int i, r;
 	bool start_mci_reset = false;
-	bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
 	bool save_fullsleep = ah->chip_fullsleep;
 
-	if (mci) {
+	if (ath9k_hw_mci_is_enabled(ah)) {
 		start_mci_reset = ar9003_mci_start_reset(ah, chan);
 		if (start_mci_reset)
 			return 0;
@@ -1774,7 +1774,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 			return r;
 	}
 
-	if (mci)
+	if (ath9k_hw_mci_is_enabled(ah))
 		ar9003_mci_stop_bt(ah, save_fullsleep);
 
 	saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
@@ -1832,7 +1832,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	if (r)
 		return r;
 
-	if (mci)
+	if (ath9k_hw_mci_is_enabled(ah))
 		ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep);
 
 	/*
@@ -1927,7 +1927,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
 	ath9k_hw_set_dma(ah);
 
-	REG_WRITE(ah, AR_OBS, 8);
+	if (!ath9k_hw_mci_is_enabled(ah))
+		REG_WRITE(ah, AR_OBS, 8);
 
 	if (ah->config.rx_intr_mitigation) {
 		REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
@@ -1951,7 +1952,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	ath9k_hw_loadnf(ah, chan);
 	ath9k_hw_start_nfcal(ah, true);
 
-	if (mci && ar9003_mci_end_reset(ah, chan, caldata))
+	if (ath9k_hw_mci_is_enabled(ah) && ar9003_mci_end_reset(ah, chan, caldata))
 		return -EIO;
 
 	ENABLE_REGWRITE_BUFFER(ah);
@@ -1996,7 +1997,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	if (ath9k_hw_btcoex_is_enabled(ah))
 		ath9k_hw_btcoex_enable(ah);
 
-	if (mci)
+	if (ath9k_hw_mci_is_enabled(ah))
 		ar9003_mci_check_bt(ah);
 
 	if (AR_SREV_9300_20_OR_LATER(ah)) {
@@ -2019,39 +2020,35 @@ EXPORT_SYMBOL(ath9k_hw_reset);
  * Notify Power Mgt is disabled in self-generated frames.
  * If requested, force chip to sleep.
  */
-static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
+static void ath9k_set_power_sleep(struct ath_hw *ah)
 {
 	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
-	if (setChip) {
-		if (AR_SREV_9462(ah)) {
-			REG_WRITE(ah, AR_TIMER_MODE,
-				  REG_READ(ah, AR_TIMER_MODE) & 0xFFFFFF00);
-			REG_WRITE(ah, AR_NDP2_TIMER_MODE, REG_READ(ah,
-				  AR_NDP2_TIMER_MODE) & 0xFFFFFF00);
-			REG_WRITE(ah, AR_SLP32_INC,
-				  REG_READ(ah, AR_SLP32_INC) & 0xFFF00000);
-			/* xxx Required for WLAN only case ? */
-			REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
-			udelay(100);
-		}
 
-		/*
-		 * Clear the RTC force wake bit to allow the
-		 * mac to go to sleep.
-		 */
-		REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
+	if (AR_SREV_9462(ah)) {
+		REG_CLR_BIT(ah, AR_TIMER_MODE, 0xff);
+		REG_CLR_BIT(ah, AR_NDP2_TIMER_MODE, 0xff);
+		REG_CLR_BIT(ah, AR_SLP32_INC, 0xfffff);
+		/* xxx Required for WLAN only case ? */
+		REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
+		udelay(100);
+	}
 
-		if (AR_SREV_9462(ah))
-			udelay(100);
+	/*
+	 * Clear the RTC force wake bit to allow the
+	 * mac to go to sleep.
+	 */
+	REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
 
-		if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
-			REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+	if (ath9k_hw_mci_is_enabled(ah))
+		udelay(100);
 
-		/* Shutdown chip. Active low */
-		if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) {
-			REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
-			udelay(2);
-		}
+	if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
+		REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+
+	/* Shutdown chip. Active low */
+	if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) {
+		REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
+		udelay(2);
 	}
 
 	/* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
@@ -2064,44 +2061,38 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
  * frames. If request, set power mode of chip to
  * auto/normal.  Duration in units of 128us (1/8 TU).
  */
-static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
+static void ath9k_set_power_network_sleep(struct ath_hw *ah)
 {
-	u32 val;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 
 	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
-	if (setChip) {
-		struct ath9k_hw_capabilities *pCap = &ah->caps;
 
-		if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
-			/* Set WakeOnInterrupt bit; clear ForceWake bit */
-			REG_WRITE(ah, AR_RTC_FORCE_WAKE,
-				  AR_RTC_FORCE_WAKE_ON_INT);
-		} else {
+	if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+		/* Set WakeOnInterrupt bit; clear ForceWake bit */
+		REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+			  AR_RTC_FORCE_WAKE_ON_INT);
+	} else {
 
-			/* When chip goes into network sleep, it could be waken
-			 * up by MCI_INT interrupt caused by BT's HW messages
-			 * (LNA_xxx, CONT_xxx) which chould be in a very fast
-			 * rate (~100us). This will cause chip to leave and
-			 * re-enter network sleep mode frequently, which in
-			 * consequence will have WLAN MCI HW to generate lots of
-			 * SYS_WAKING and SYS_SLEEPING messages which will make
-			 * BT CPU to busy to process.
-			 */
-			if (AR_SREV_9462(ah)) {
-				val = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_EN) &
-					~AR_MCI_INTERRUPT_RX_HW_MSG_MASK;
-				REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, val);
-			}
-			/*
-			 * Clear the RTC force wake bit to allow the
-			 * mac to go to sleep.
-			 */
-			REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
-				    AR_RTC_FORCE_WAKE_EN);
-
-			if (AR_SREV_9462(ah))
-				udelay(30);
-		}
+		/* When chip goes into network sleep, it could be waken
+		 * up by MCI_INT interrupt caused by BT's HW messages
+		 * (LNA_xxx, CONT_xxx) which chould be in a very fast
+		 * rate (~100us). This will cause chip to leave and
+		 * re-enter network sleep mode frequently, which in
+		 * consequence will have WLAN MCI HW to generate lots of
+		 * SYS_WAKING and SYS_SLEEPING messages which will make
+		 * BT CPU to busy to process.
+		 */
+		if (ath9k_hw_mci_is_enabled(ah))
+			REG_CLR_BIT(ah, AR_MCI_INTERRUPT_RX_MSG_EN,
+				    AR_MCI_INTERRUPT_RX_HW_MSG_MASK);
+		/*
+		 * Clear the RTC force wake bit to allow the
+		 * mac to go to sleep.
+		 */
+		REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
+
+		if (ath9k_hw_mci_is_enabled(ah))
+			udelay(30);
 	}
 
 	/* Clear Bit 14 of AR_WA after putting chip into Net Sleep mode. */
@@ -2109,7 +2100,7 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
 		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)
+static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
 {
 	u32 val;
 	int i;
@@ -2120,37 +2111,38 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
 		udelay(10);
 	}
 
-	if (setChip) {
-		if ((REG_READ(ah, AR_RTC_STATUS) &
-		     AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
-			if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
-				return false;
-			}
-			if (!AR_SREV_9300_20_OR_LATER(ah))
-				ath9k_hw_init_pll(ah, NULL);
+	if ((REG_READ(ah, AR_RTC_STATUS) &
+	     AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
+		if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
+			return false;
 		}
-		if (AR_SREV_9100(ah))
-			REG_SET_BIT(ah, AR_RTC_RESET,
-				    AR_RTC_RESET_EN);
+		if (!AR_SREV_9300_20_OR_LATER(ah))
+			ath9k_hw_init_pll(ah, NULL);
+	}
+	if (AR_SREV_9100(ah))
+		REG_SET_BIT(ah, AR_RTC_RESET,
+			    AR_RTC_RESET_EN);
+
+	REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+		    AR_RTC_FORCE_WAKE_EN);
+	udelay(50);
 
+	if (ath9k_hw_mci_is_enabled(ah))
+		ar9003_mci_set_power_awake(ah);
+
+	for (i = POWER_UP_TIME / 50; i > 0; i--) {
+		val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
+		if (val == AR_RTC_STATUS_ON)
+			break;
+		udelay(50);
 		REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
 			    AR_RTC_FORCE_WAKE_EN);
-		udelay(50);
-
-		for (i = POWER_UP_TIME / 50; i > 0; i--) {
-			val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
-			if (val == AR_RTC_STATUS_ON)
-				break;
-			udelay(50);
-			REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
-				    AR_RTC_FORCE_WAKE_EN);
-		}
-		if (i == 0) {
-			ath_err(ath9k_hw_common(ah),
-				"Failed to wakeup in %uus\n",
-				POWER_UP_TIME / 20);
-			return false;
-		}
+	}
+	if (i == 0) {
+		ath_err(ath9k_hw_common(ah),
+			"Failed to wakeup in %uus\n",
+			POWER_UP_TIME / 20);
+		return false;
 	}
 
 	REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
@@ -2161,7 +2153,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
 bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
-	int status = true, setChip = true;
+	int status = true;
 	static const char *modes[] = {
 		"AWAKE",
 		"FULL-SLEEP",
@@ -2177,25 +2169,17 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 
 	switch (mode) {
 	case ATH9K_PM_AWAKE:
-		status = ath9k_hw_set_power_awake(ah, setChip);
-
-		if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
-			REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
-
+		status = ath9k_hw_set_power_awake(ah);
 		break;
 	case ATH9K_PM_FULL_SLEEP:
-		if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+		if (ath9k_hw_mci_is_enabled(ah))
 			ar9003_mci_set_full_sleep(ah);
 
-		ath9k_set_power_sleep(ah, setChip);
+		ath9k_set_power_sleep(ah);
 		ah->chip_fullsleep = true;
 		break;
 	case ATH9K_PM_NETWORK_SLEEP:
-
-		if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
-			REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
-
-		ath9k_set_power_network_sleep(ah, setChip);
+		ath9k_set_power_network_sleep(ah);
 		break;
 	default:
 		ath_err(common, "Unknown power mode %u\n", mode);
@@ -2765,6 +2749,9 @@ EXPORT_SYMBOL(ath9k_hw_setrxfilter);
 
 bool ath9k_hw_phy_disable(struct ath_hw *ah)
 {
+	if (ath9k_hw_mci_is_enabled(ah))
+		ar9003_mci_bt_gain_ctrl(ah);
+
 	if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
 		return false;
 
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index b620c55..9409660 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -824,7 +824,6 @@ struct ath_hw {
 	struct ar5416IniArray ini_japan2484;
 	struct ar5416IniArray iniModes_9271_ANI_reg;
 	struct ar5416IniArray ini_radio_post_sys2ant;
-	struct ar5416IniArray ini_BTCOEX_MAX_TXPWR;
 
 	struct ar5416IniArray iniMac[ATH_INI_NUM_SPLIT];
 	struct ar5416IniArray iniBB[ATH_INI_NUM_SPLIT];
@@ -1020,16 +1019,8 @@ void ar9002_hw_attach_ops(struct ath_hw *ah);
 void ar9003_hw_attach_ops(struct ath_hw *ah);
 
 void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
-/*
- * 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_ani_reset(struct ath_hw *ah, bool is_scanning);
-void ath9k_hw_proc_mib_event(struct ath_hw *ah);
 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
@@ -1037,6 +1028,12 @@ static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
 {
 	return ah->btcoex_hw.enabled;
 }
+static inline bool ath9k_hw_mci_is_enabled(struct ath_hw *ah)
+{
+	return ah->common.btcoex_enabled &&
+	       (ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
+
+}
 void ath9k_hw_btcoex_enable(struct ath_hw *ah);
 static inline enum ath_btcoex_scheme
 ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
@@ -1048,6 +1045,10 @@ static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
 {
 	return false;
 }
+static inline bool ath9k_hw_mci_is_enabled(struct ath_hw *ah)
+{
+	return false;
+}
 static inline void ath9k_hw_btcoex_enable(struct ath_hw *ah)
 {
 }
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index dee9e09..9dfce1a 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -489,6 +489,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
 
 	setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
 
+	sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
 	sc->config.txpowlimit = ATH_TXPOWER_MAX;
 	memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
 	sc->beacon.slottime = ATH9K_SLOT_TIME_9;
@@ -560,6 +561,12 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 	tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
 		     (unsigned long)sc);
 
+	INIT_WORK(&sc->hw_reset_work, ath_reset_work);
+	INIT_WORK(&sc->hw_check_work, ath_hw_check);
+	INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
+	INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
+	setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);
+
 	/*
 	 * Cache line size is used to size and align various
 	 * structures used to communicate with the hardware.
@@ -590,6 +597,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 	ath9k_cmn_init_crypto(sc->sc_ah);
 	ath9k_init_misc(sc);
 
+	if (common->bus_ops->aspm_init)
+		common->bus_ops->aspm_init(common);
+
 	return 0;
 
 err_btcoex:
@@ -782,11 +792,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
 		ARRAY_SIZE(ath9k_tpt_blink));
 #endif
 
-	INIT_WORK(&sc->hw_reset_work, ath_reset_work);
-	INIT_WORK(&sc->hw_check_work, ath_hw_check);
-	INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
-	INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
-
 	/* Register with mac80211 */
 	error = ieee80211_register_hw(hw);
 	if (error)
@@ -805,9 +810,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
 			goto error_world;
 	}
 
-	setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);
-	sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
-
 	ath_init_leds(sc);
 	ath_start_rfkill_poll(sc);
 
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
new file mode 100644
index 0000000..91650fe
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, 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 "ath9k.h"
+
+/*
+ * TX polling - checks if the TX engine is stuck somewhere
+ * and issues a chip reset if so.
+ */
+void ath_tx_complete_poll_work(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc,
+					    tx_complete_work.work);
+	struct ath_txq *txq;
+	int i;
+	bool needreset = false;
+#ifdef CONFIG_ATH9K_DEBUGFS
+	sc->tx_complete_poll_work_seen++;
+#endif
+
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+		if (ATH_TXQ_SETUP(sc, i)) {
+			txq = &sc->tx.txq[i];
+			ath_txq_lock(sc, txq);
+			if (txq->axq_depth) {
+				if (txq->axq_tx_inprogress) {
+					needreset = true;
+					ath_txq_unlock(sc, txq);
+					break;
+				} else {
+					txq->axq_tx_inprogress = true;
+				}
+			}
+			ath_txq_unlock_complete(sc, txq);
+		}
+
+	if (needreset) {
+		ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
+			"tx hung, resetting the chip\n");
+		RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
+		ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+		return;
+	}
+
+	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
+				     msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
+}
+
+/*
+ * Checks if the BB/MAC is hung.
+ */
+void ath_hw_check(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	unsigned long flags;
+	int busy;
+	u8 is_alive, nbeacon = 1;
+
+	ath9k_ps_wakeup(sc);
+	is_alive = ath9k_hw_check_alive(sc->sc_ah);
+
+	if (is_alive && !AR_SREV_9300(sc->sc_ah))
+		goto out;
+	else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
+		ath_dbg(common, RESET,
+			"DCU stuck is detected. Schedule chip reset\n");
+		RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
+		goto sched_reset;
+	}
+
+	spin_lock_irqsave(&common->cc_lock, flags);
+	busy = ath_update_survey_stats(sc);
+	spin_unlock_irqrestore(&common->cc_lock, flags);
+
+	ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
+		busy, sc->hw_busy_count + 1);
+	if (busy >= 99) {
+		if (++sc->hw_busy_count >= 3) {
+			RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
+			goto sched_reset;
+		}
+	} else if (busy >= 0) {
+		sc->hw_busy_count = 0;
+		nbeacon = 3;
+	}
+
+	ath_start_rx_poll(sc, nbeacon);
+	goto out;
+
+sched_reset:
+	ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+out:
+	ath9k_ps_restore(sc);
+}
+
+/*
+ * PLL-WAR for AR9485/AR9340
+ */
+static bool ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
+{
+	static int count;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	if (pll_sqsum >= 0x40000) {
+		count++;
+		if (count == 3) {
+			ath_dbg(common, RESET, "PLL WAR, resetting the chip\n");
+			RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
+			ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+			count = 0;
+			return true;
+		}
+	} else {
+		count = 0;
+	}
+
+	return false;
+}
+
+void ath_hw_pll_work(struct work_struct *work)
+{
+	u32 pll_sqsum;
+	struct ath_softc *sc = container_of(work, struct ath_softc,
+					    hw_pll_work.work);
+	/*
+	 * ensure that the PLL WAR is executed only
+	 * after the STA is associated (or) if the
+	 * beaconing had started in interfaces that
+	 * uses beacons.
+	 */
+	if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
+		return;
+
+	ath9k_ps_wakeup(sc);
+	pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
+	ath9k_ps_restore(sc);
+	if (ath_hw_pll_rx_hang_check(sc, pll_sqsum))
+		return;
+
+	ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
+				     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
+}
+
+/*
+ * RX Polling - monitors baseband hangs.
+ */
+void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
+{
+	if (!AR_SREV_9300(sc->sc_ah))
+		return;
+
+	if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
+		return;
+
+	mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
+		  (nbeacon * sc->cur_beacon_conf.beacon_interval));
+}
+
+void ath_rx_poll(unsigned long data)
+{
+	struct ath_softc *sc = (struct ath_softc *)data;
+
+	ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+}
+
+/*
+ * PA Pre-distortion.
+ */
+static void ath_paprd_activate(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
+	int chain;
+
+	if (!caldata || !caldata->paprd_done)
+		return;
+
+	ath9k_ps_wakeup(sc);
+	ar9003_paprd_enable(ah, false);
+	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+		if (!(ah->txchainmask & BIT(chain)))
+			continue;
+
+		ar9003_paprd_populate_single_table(ah, caldata, chain);
+	}
+
+	ar9003_paprd_enable(ah, true);
+	ath9k_ps_restore(sc);
+}
+
+static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
+{
+	struct ieee80211_hw *hw = sc->hw;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath_tx_control txctl;
+	int time_left;
+
+	memset(&txctl, 0, sizeof(txctl));
+	txctl.txq = sc->tx.txq_map[WME_AC_BE];
+
+	memset(tx_info, 0, sizeof(*tx_info));
+	tx_info->band = hw->conf.channel->band;
+	tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
+	tx_info->control.rates[0].idx = 0;
+	tx_info->control.rates[0].count = 1;
+	tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
+	tx_info->control.rates[1].idx = -1;
+
+	init_completion(&sc->paprd_complete);
+	txctl.paprd = BIT(chain);
+
+	if (ath_tx_start(hw, skb, &txctl) != 0) {
+		ath_dbg(common, CALIBRATE, "PAPRD TX failed\n");
+		dev_kfree_skb_any(skb);
+		return false;
+	}
+
+	time_left = wait_for_completion_timeout(&sc->paprd_complete,
+			msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
+
+	if (!time_left)
+		ath_dbg(common, CALIBRATE,
+			"Timeout waiting for paprd training on TX chain %d\n",
+			chain);
+
+	return !!time_left;
+}
+
+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 ath9k_hw_cal_data *caldata = ah->caldata;
+	struct ath_common *common = ath9k_hw_common(ah);
+	int ftype;
+	int chain_ok = 0;
+	int chain;
+	int len = 1800;
+
+	if (!caldata)
+		return;
+
+	ath9k_ps_wakeup(sc);
+
+	if (ar9003_paprd_init_table(ah) < 0)
+		goto fail_paprd;
+
+	skb = alloc_skb(len, GFP_KERNEL);
+	if (!skb)
+		goto fail_paprd;
+
+	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);
+
+	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+		if (!(ah->txchainmask & BIT(chain)))
+			continue;
+
+		chain_ok = 0;
+
+		ath_dbg(common, CALIBRATE,
+			"Sending PAPRD frame for thermal measurement on chain %d\n",
+			chain);
+		if (!ath_paprd_send_frame(sc, skb, chain))
+			goto fail_paprd;
+
+		ar9003_paprd_setup_gain_table(ah, chain);
+
+		ath_dbg(common, CALIBRATE,
+			"Sending PAPRD training frame on chain %d\n", chain);
+		if (!ath_paprd_send_frame(sc, skb, chain))
+			goto fail_paprd;
+
+		if (!ar9003_paprd_is_done(ah)) {
+			ath_dbg(common, CALIBRATE,
+				"PAPRD not yet done on chain %d\n", chain);
+			break;
+		}
+
+		if (ar9003_paprd_create_curve(ah, caldata, chain)) {
+			ath_dbg(common, CALIBRATE,
+				"PAPRD create curve failed on chain %d\n",
+				chain);
+			break;
+		}
+
+		chain_ok = 1;
+	}
+	kfree_skb(skb);
+
+	if (chain_ok) {
+		caldata->paprd_done = true;
+		ath_paprd_activate(sc);
+	}
+
+fail_paprd:
+	ath9k_ps_restore(sc);
+}
+
+/*
+ *  ANI performs periodic noise floor calibration
+ *  that is used to adjust and optimize the chip performance.  This
+ *  takes environmental changes (location, temperature) into account.
+ *  When the task is complete, it reschedules itself depending on the
+ *  appropriate interval that was calculated.
+ */
+void ath_ani_calibrate(unsigned long data)
+{
+	struct ath_softc *sc = (struct ath_softc *)data;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	bool longcal = false;
+	bool shortcal = false;
+	bool aniflag = false;
+	unsigned int timestamp = jiffies_to_msecs(jiffies);
+	u32 cal_interval, short_cal_interval, long_cal_interval;
+	unsigned long flags;
+
+	if (ah->caldata && ah->caldata->nfcal_interference)
+		long_cal_interval = ATH_LONG_CALINTERVAL_INT;
+	else
+		long_cal_interval = ATH_LONG_CALINTERVAL;
+
+	short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
+		ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
+
+	/* Only calibrate if awake */
+	if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
+		goto set_timer;
+
+	ath9k_ps_wakeup(sc);
+
+	/* Long calibration runs independently of short calibration. */
+	if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
+		longcal = true;
+		common->ani.longcal_timer = timestamp;
+	}
+
+	/* Short calibration applies only while caldone is false */
+	if (!common->ani.caldone) {
+		if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
+			shortcal = true;
+			common->ani.shortcal_timer = timestamp;
+			common->ani.resetcal_timer = timestamp;
+		}
+	} else {
+		if ((timestamp - common->ani.resetcal_timer) >=
+		    ATH_RESTART_CALINTERVAL) {
+			common->ani.caldone = ath9k_hw_reset_calvalid(ah);
+			if (common->ani.caldone)
+				common->ani.resetcal_timer = timestamp;
+		}
+	}
+
+	/* Verify whether we must check ANI */
+	if (sc->sc_ah->config.enable_ani
+	    && (timestamp - common->ani.checkani_timer) >=
+	    ah->config.ani_poll_interval) {
+		aniflag = true;
+		common->ani.checkani_timer = timestamp;
+	}
+
+	/* Call ANI routine if necessary */
+	if (aniflag) {
+		spin_lock_irqsave(&common->cc_lock, flags);
+		ath9k_hw_ani_monitor(ah, ah->curchan);
+		ath_update_survey_stats(sc);
+		spin_unlock_irqrestore(&common->cc_lock, flags);
+	}
+
+	/* Perform calibration if necessary */
+	if (longcal || shortcal) {
+		common->ani.caldone =
+			ath9k_hw_calibrate(ah, ah->curchan,
+					   ah->rxchainmask, longcal);
+	}
+
+	ath_dbg(common, ANI,
+		"Calibration @%lu finished: %s %s %s, caldone: %s\n",
+		jiffies,
+		longcal ? "long" : "", shortcal ? "short" : "",
+		aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
+
+	ath9k_debug_samp_bb_mac(sc);
+	ath9k_ps_restore(sc);
+
+set_timer:
+	/*
+	* Set timer interval based on previous results.
+	* The interval must be the shortest necessary to satisfy ANI,
+	* short calibration and long calibration.
+	*/
+	cal_interval = ATH_LONG_CALINTERVAL;
+	if (sc->sc_ah->config.enable_ani)
+		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) && ah->caldata) {
+		if (!ah->caldata->paprd_done)
+			ieee80211_queue_work(sc->hw, &sc->paprd_work);
+		else if (!ah->paprd_table_write_done)
+			ath_paprd_activate(sc);
+	}
+}
+
+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;
+
+	if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags))
+		return;
+
+	if (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
+		return;
+
+	common->ani.longcal_timer = timestamp;
+	common->ani.shortcal_timer = timestamp;
+	common->ani.checkani_timer = timestamp;
+
+	mod_timer(&common->ani.timer,
+		  jiffies + msecs_to_jiffies((u32)ah->config.ani_poll_interval));
+}
+
+void ath_update_survey_nf(struct ath_softc *sc, int channel)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath9k_channel *chan = &ah->channels[channel];
+	struct survey_info *survey = &sc->survey[channel];
+
+	if (chan->noisefloor) {
+		survey->filled |= SURVEY_INFO_NOISE_DBM;
+		survey->noise = ath9k_hw_getchan_noise(ah, chan);
+	}
+}
+
+/*
+ * Updates the survey statistics and returns the busy time since last
+ * update in %, if the measurement duration was long enough for the
+ * result to be useful, -1 otherwise.
+ */
+int ath_update_survey_stats(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	int pos = ah->curchan - &ah->channels[0];
+	struct survey_info *survey = &sc->survey[pos];
+	struct ath_cycle_counters *cc = &common->cc_survey;
+	unsigned int div = common->clockrate * 1000;
+	int ret = 0;
+
+	if (!ah->curchan)
+		return -1;
+
+	if (ah->power_mode == ATH9K_PM_AWAKE)
+		ath_hw_cycle_counters_update(common);
+
+	if (cc->cycles > 0) {
+		survey->filled |= SURVEY_INFO_CHANNEL_TIME |
+			SURVEY_INFO_CHANNEL_TIME_BUSY |
+			SURVEY_INFO_CHANNEL_TIME_RX |
+			SURVEY_INFO_CHANNEL_TIME_TX;
+		survey->channel_time += cc->cycles / div;
+		survey->channel_time_busy += cc->rx_busy / div;
+		survey->channel_time_rx += cc->rx_frame / div;
+		survey->channel_time_tx += cc->tx_frame / div;
+	}
+
+	if (cc->cycles < div)
+		return -1;
+
+	if (cc->cycles > 0)
+		ret = cc->rx_busy * 100 / cc->cycles;
+
+	memset(cc, 0, sizeof(*cc));
+
+	ath_update_survey_nf(sc, pos);
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 4de4473..c14cf5a 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -19,7 +19,7 @@
 #include "ath9k.h"
 #include "btcoex.h"
 
-static u8 parse_mpdudensity(u8 mpdudensity)
+u8 ath9k_parse_mpdudensity(u8 mpdudensity)
 {
 	/*
 	 * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
@@ -101,6 +101,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
 		spin_lock(&common->cc_lock);
 		ath_hw_cycle_counters_update(common);
 		memset(&common->cc_survey, 0, sizeof(common->cc_survey));
+		memset(&common->cc_ani, 0, sizeof(common->cc_ani));
 		spin_unlock(&common->cc_lock);
 	}
 
@@ -143,90 +144,15 @@ void ath9k_ps_restore(struct ath_softc *sc)
 	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 }
 
-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;
-
-	if (!(sc->sc_flags & SC_OP_ANI_RUN))
-		return;
-
-	if (sc->sc_flags & SC_OP_OFFCHANNEL)
-		return;
-
-	common->ani.longcal_timer = timestamp;
-	common->ani.shortcal_timer = timestamp;
-	common->ani.checkani_timer = timestamp;
-
-	mod_timer(&common->ani.timer,
-		  jiffies +
-			msecs_to_jiffies((u32)ah->config.ani_poll_interval));
-}
-
-static void ath_update_survey_nf(struct ath_softc *sc, int channel)
-{
-	struct ath_hw *ah = sc->sc_ah;
-	struct ath9k_channel *chan = &ah->channels[channel];
-	struct survey_info *survey = &sc->survey[channel];
-
-	if (chan->noisefloor) {
-		survey->filled |= SURVEY_INFO_NOISE_DBM;
-		survey->noise = ath9k_hw_getchan_noise(ah, chan);
-	}
-}
-
-/*
- * Updates the survey statistics and returns the busy time since last
- * update in %, if the measurement duration was long enough for the
- * result to be useful, -1 otherwise.
- */
-static int ath_update_survey_stats(struct ath_softc *sc)
-{
-	struct ath_hw *ah = sc->sc_ah;
-	struct ath_common *common = ath9k_hw_common(ah);
-	int pos = ah->curchan - &ah->channels[0];
-	struct survey_info *survey = &sc->survey[pos];
-	struct ath_cycle_counters *cc = &common->cc_survey;
-	unsigned int div = common->clockrate * 1000;
-	int ret = 0;
-
-	if (!ah->curchan)
-		return -1;
-
-	if (ah->power_mode == ATH9K_PM_AWAKE)
-		ath_hw_cycle_counters_update(common);
-
-	if (cc->cycles > 0) {
-		survey->filled |= SURVEY_INFO_CHANNEL_TIME |
-			SURVEY_INFO_CHANNEL_TIME_BUSY |
-			SURVEY_INFO_CHANNEL_TIME_RX |
-			SURVEY_INFO_CHANNEL_TIME_TX;
-		survey->channel_time += cc->cycles / div;
-		survey->channel_time_busy += cc->rx_busy / div;
-		survey->channel_time_rx += cc->rx_frame / div;
-		survey->channel_time_tx += cc->tx_frame / div;
-	}
-
-	if (cc->cycles < div)
-		return -1;
-
-	if (cc->cycles > 0)
-		ret = cc->rx_busy * 100 / cc->cycles;
-
-	memset(cc, 0, sizeof(*cc));
-
-	ath_update_survey_nf(sc, pos);
-
-	return ret;
-}
-
 static void __ath_cancel_work(struct ath_softc *sc)
 {
 	cancel_work_sync(&sc->paprd_work);
 	cancel_work_sync(&sc->hw_check_work);
 	cancel_delayed_work_sync(&sc->tx_complete_work);
 	cancel_delayed_work_sync(&sc->hw_pll_work);
+
+	if (ath9k_hw_mci_is_enabled(sc->sc_ah))
+		cancel_work_sync(&sc->mci_work);
 }
 
 static void ath_cancel_work(struct ath_softc *sc)
@@ -235,6 +161,22 @@ static void ath_cancel_work(struct ath_softc *sc)
 	cancel_work_sync(&sc->hw_reset_work);
 }
 
+static void ath_restart_work(struct ath_softc *sc)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+
+	if (AR_SREV_9485(sc->sc_ah) || AR_SREV_9340(sc->sc_ah))
+		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
+				     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
+
+	ath_start_rx_poll(sc, 3);
+
+	if (!common->disable_ani)
+		ath_start_ani(common);
+}
+
 static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
 {
 	struct ath_hw *ah = sc->sc_ah;
@@ -271,6 +213,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
 {
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
+	unsigned long flags;
 
 	if (ath_startrecv(sc) != 0) {
 		ath_err(common, "Unable to restart recv logic\n");
@@ -279,36 +222,30 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
 
 	ath9k_cmn_update_txpow(ah, sc->curtxpow,
 			       sc->config.txpowlimit, &sc->curtxpow);
+
+	clear_bit(SC_OP_HW_RESET, &sc->sc_flags);
 	ath9k_hw_set_interrupts(ah);
 	ath9k_hw_enable_interrupts(ah);
 
-	if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) {
-		if (sc->sc_flags & SC_OP_BEACONS)
-			ath_set_beacon(sc);
-
-		ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
-		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
-		ath_start_rx_poll(sc, 3);
-		if (!common->disable_ani)
-			ath_start_ani(common);
-	}
-
-	if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) {
-		struct ath_hw_antcomb_conf div_ant_conf;
-		u8 lna_conf;
-
-		ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
+	if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) {
+		if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
+			goto work;
 
-		if (sc->ant_rx == 1)
-			lna_conf = ATH_ANT_DIV_COMB_LNA1;
-		else
-			lna_conf = ATH_ANT_DIV_COMB_LNA2;
-		div_ant_conf.main_lna_conf = lna_conf;
-		div_ant_conf.alt_lna_conf = lna_conf;
+		ath_set_beacon(sc);
 
-		ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
+		if (ah->opmode == NL80211_IFTYPE_STATION &&
+		    test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
+			spin_lock_irqsave(&sc->sc_pm_lock, flags);
+			sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+			spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+		}
+	work:
+		ath_restart_work(sc);
 	}
 
+	if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3)
+		ath_ant_comb_update(sc);
+
 	ieee80211_wake_queues(sc->hw);
 
 	return true;
@@ -328,7 +265,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
 
 	spin_lock_bh(&sc->sc_pcu_lock);
 
-	if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) {
+	if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) {
 		fastcc = false;
 		caldata = &sc->caldata;
 	}
@@ -371,7 +308,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 {
 	int r;
 
-	if (sc->sc_flags & SC_OP_INVALID)
+	if (test_bit(SC_OP_INVALID, &sc->sc_flags))
 		return -EIO;
 
 	r = ath_reset_internal(sc, hchan, false);
@@ -379,262 +316,11 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	return r;
 }
 
-static void ath_paprd_activate(struct ath_softc *sc)
-{
-	struct ath_hw *ah = sc->sc_ah;
-	struct ath9k_hw_cal_data *caldata = ah->caldata;
-	int chain;
-
-	if (!caldata || !caldata->paprd_done)
-		return;
-
-	ath9k_ps_wakeup(sc);
-	ar9003_paprd_enable(ah, false);
-	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
-		if (!(ah->txchainmask & BIT(chain)))
-			continue;
-
-		ar9003_paprd_populate_single_table(ah, caldata, chain);
-	}
-
-	ar9003_paprd_enable(ah, true);
-	ath9k_ps_restore(sc);
-}
-
-static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
-{
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct ath_hw *ah = sc->sc_ah;
-	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath_tx_control txctl;
-	int time_left;
-
-	memset(&txctl, 0, sizeof(txctl));
-	txctl.txq = sc->tx.txq_map[WME_AC_BE];
-
-	memset(tx_info, 0, sizeof(*tx_info));
-	tx_info->band = hw->conf.channel->band;
-	tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
-	tx_info->control.rates[0].idx = 0;
-	tx_info->control.rates[0].count = 1;
-	tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
-	tx_info->control.rates[1].idx = -1;
-
-	init_completion(&sc->paprd_complete);
-	txctl.paprd = BIT(chain);
-
-	if (ath_tx_start(hw, skb, &txctl) != 0) {
-		ath_dbg(common, CALIBRATE, "PAPRD TX failed\n");
-		dev_kfree_skb_any(skb);
-		return false;
-	}
-
-	time_left = wait_for_completion_timeout(&sc->paprd_complete,
-			msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
-
-	if (!time_left)
-		ath_dbg(common, CALIBRATE,
-			"Timeout waiting for paprd training on TX chain %d\n",
-			chain);
-
-	return !!time_left;
-}
-
-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 ath9k_hw_cal_data *caldata = ah->caldata;
-	struct ath_common *common = ath9k_hw_common(ah);
-	int ftype;
-	int chain_ok = 0;
-	int chain;
-	int len = 1800;
-
-	if (!caldata)
-		return;
-
-	ath9k_ps_wakeup(sc);
-
-	if (ar9003_paprd_init_table(ah) < 0)
-		goto fail_paprd;
-
-	skb = alloc_skb(len, GFP_KERNEL);
-	if (!skb)
-		goto fail_paprd;
-
-	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);
-
-	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
-		if (!(ah->txchainmask & BIT(chain)))
-			continue;
-
-		chain_ok = 0;
-
-		ath_dbg(common, CALIBRATE,
-			"Sending PAPRD frame for thermal measurement on chain %d\n",
-			chain);
-		if (!ath_paprd_send_frame(sc, skb, chain))
-			goto fail_paprd;
-
-		ar9003_paprd_setup_gain_table(ah, chain);
-
-		ath_dbg(common, CALIBRATE,
-			"Sending PAPRD training frame on chain %d\n", chain);
-		if (!ath_paprd_send_frame(sc, skb, chain))
-			goto fail_paprd;
-
-		if (!ar9003_paprd_is_done(ah)) {
-			ath_dbg(common, CALIBRATE,
-				"PAPRD not yet done on chain %d\n", chain);
-			break;
-		}
-
-		if (ar9003_paprd_create_curve(ah, caldata, chain)) {
-			ath_dbg(common, CALIBRATE,
-				"PAPRD create curve failed on chain %d\n",
-								   chain);
-			break;
-		}
-
-		chain_ok = 1;
-	}
-	kfree_skb(skb);
-
-	if (chain_ok) {
-		caldata->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
- *  takes environmental changes (location, temperature) into account.
- *  When the task is complete, it reschedules itself depending on the
- *  appropriate interval that was calculated.
- */
-void ath_ani_calibrate(unsigned long data)
-{
-	struct ath_softc *sc = (struct ath_softc *)data;
-	struct ath_hw *ah = sc->sc_ah;
-	struct ath_common *common = ath9k_hw_common(ah);
-	bool longcal = false;
-	bool shortcal = false;
-	bool aniflag = false;
-	unsigned int timestamp = jiffies_to_msecs(jiffies);
-	u32 cal_interval, short_cal_interval, long_cal_interval;
-	unsigned long flags;
-
-	if (ah->caldata && ah->caldata->nfcal_interference)
-		long_cal_interval = ATH_LONG_CALINTERVAL_INT;
-	else
-		long_cal_interval = ATH_LONG_CALINTERVAL;
-
-	short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
-		ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
-
-	/* Only calibrate if awake */
-	if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
-		goto set_timer;
-
-	ath9k_ps_wakeup(sc);
-
-	/* Long calibration runs independently of short calibration. */
-	if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
-		longcal = true;
-		common->ani.longcal_timer = timestamp;
-	}
-
-	/* Short calibration applies only while caldone is false */
-	if (!common->ani.caldone) {
-		if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
-			shortcal = true;
-			common->ani.shortcal_timer = timestamp;
-			common->ani.resetcal_timer = timestamp;
-		}
-	} else {
-		if ((timestamp - common->ani.resetcal_timer) >=
-		    ATH_RESTART_CALINTERVAL) {
-			common->ani.caldone = ath9k_hw_reset_calvalid(ah);
-			if (common->ani.caldone)
-				common->ani.resetcal_timer = timestamp;
-		}
-	}
-
-	/* Verify whether we must check ANI */
-	if (sc->sc_ah->config.enable_ani
-	    && (timestamp - common->ani.checkani_timer) >=
-	    ah->config.ani_poll_interval) {
-		aniflag = true;
-		common->ani.checkani_timer = timestamp;
-	}
-
-	/* Call ANI routine if necessary */
-	if (aniflag) {
-		spin_lock_irqsave(&common->cc_lock, flags);
-		ath9k_hw_ani_monitor(ah, ah->curchan);
-		ath_update_survey_stats(sc);
-		spin_unlock_irqrestore(&common->cc_lock, flags);
-	}
-
-	/* Perform calibration if necessary */
-	if (longcal || shortcal) {
-		common->ani.caldone =
-			ath9k_hw_calibrate(ah, ah->curchan,
-						ah->rxchainmask, longcal);
-	}
-
-	ath_dbg(common, ANI,
-		"Calibration @%lu finished: %s %s %s, caldone: %s\n",
-		jiffies,
-		longcal ? "long" : "", shortcal ? "short" : "",
-		aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
-
-	ath9k_ps_restore(sc);
-
-set_timer:
-	/*
-	* Set timer interval based on previous results.
-	* The interval must be the shortest necessary to satisfy ANI,
-	* short calibration and long calibration.
-	*/
-	ath9k_debug_samp_bb_mac(sc);
-	cal_interval = ATH_LONG_CALINTERVAL;
-	if (sc->sc_ah->config.enable_ani)
-		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) && ah->caldata) {
-		if (!ah->caldata->paprd_done)
-			ieee80211_queue_work(sc->hw, &sc->paprd_work);
-		else if (!ah->paprd_table_write_done)
-			ath_paprd_activate(sc);
-	}
-}
-
 static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
 			    struct ieee80211_vif *vif)
 {
 	struct ath_node *an;
+	u8 density;
 	an = (struct ath_node *)sta->drv_priv;
 
 #ifdef CONFIG_ATH9K_DEBUGFS
@@ -649,7 +335,8 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
 		ath_tx_node_init(sc, an);
 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
 				     sta->ht_cap.ampdu_factor);
-		an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+		density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
+		an->mpdudensity = density;
 	}
 }
 
@@ -668,13 +355,12 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
 		ath_tx_node_cleanup(sc, an);
 }
 
-
 void ath9k_tasklet(unsigned long data)
 {
 	struct ath_softc *sc = (struct ath_softc *)data;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
-
+	unsigned long flags;
 	u32 status = sc->intrstatus;
 	u32 rxmask;
 
@@ -693,10 +379,12 @@ void ath9k_tasklet(unsigned long data)
 
 		RESET_STAT_INC(sc, type);
 #endif
+		set_bit(SC_OP_HW_RESET, &sc->sc_flags);
 		ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
 		goto out;
 	}
 
+	spin_lock_irqsave(&sc->sc_pm_lock, flags);
 	if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
 		/*
 		 * TSF sync does not look correct; remain awake to sync with
@@ -705,6 +393,7 @@ void ath9k_tasklet(unsigned long data)
 		ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n");
 		sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
 	}
+	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
 	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
 		rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
@@ -766,15 +455,17 @@ irqreturn_t ath_isr(int irq, void *dev)
 	 * touch anything. Note this can happen early
 	 * on if the IRQ is shared.
 	 */
-	if (sc->sc_flags & SC_OP_INVALID)
+	if (test_bit(SC_OP_INVALID, &sc->sc_flags))
 		return IRQ_NONE;
 
-
 	/* shared irq, not for us */
 
 	if (!ath9k_hw_intrpend(ah))
 		return IRQ_NONE;
 
+	if(test_bit(SC_OP_HW_RESET, &sc->sc_flags))
+		return IRQ_HANDLED;
+
 	/*
 	 * Figure out the reason(s) for the interrupt.  Note
 	 * that the hal returns a pseudo-ISR that may include
@@ -827,24 +518,6 @@ irqreturn_t ath_isr(int irq, void *dev)
 		ath9k_hw_set_interrupts(ah);
 	}
 
-	if (status & ATH9K_INT_MIB) {
-		/*
-		 * Disable interrupts until we service the MIB
-		 * interrupt; otherwise it will continue to
-		 * fire.
-		 */
-		ath9k_hw_disable_interrupts(ah);
-		/*
-		 * Let the hal handle the event. We assume
-		 * it will clear whatever condition caused
-		 * the interrupt.
-		 */
-		spin_lock(&common->cc_lock);
-		ath9k_hw_proc_mib_event(ah);
-		spin_unlock(&common->cc_lock);
-		ath9k_hw_enable_interrupts(ah);
-	}
-
 	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
 		if (status & ATH9K_INT_TIM_TIMER) {
 			if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle))
@@ -852,8 +525,10 @@ irqreturn_t ath_isr(int irq, void *dev)
 			/* Clear RxAbort bit so that we can
 			 * receive frames */
 			ath9k_setpower(sc, ATH9K_PM_AWAKE);
+			spin_lock(&sc->sc_pm_lock);
 			ath9k_hw_setrxabort(sc->sc_ah, 0);
 			sc->ps_flags |= PS_WAIT_FOR_BEACON;
+			spin_unlock(&sc->sc_pm_lock);
 		}
 
 chip_reset:
@@ -902,87 +577,6 @@ void ath_reset_work(struct work_struct *work)
 	ath_reset(sc, true);
 }
 
-void ath_hw_check(struct work_struct *work)
-{
-	struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	unsigned long flags;
-	int busy;
-	u8 is_alive, nbeacon = 1;
-
-	ath9k_ps_wakeup(sc);
-	is_alive = ath9k_hw_check_alive(sc->sc_ah);
-
-	if (is_alive && !AR_SREV_9300(sc->sc_ah))
-		goto out;
-	else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
-		ath_dbg(common, RESET,
-			"DCU stuck is detected. Schedule chip reset\n");
-		RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
-		goto sched_reset;
-	}
-
-	spin_lock_irqsave(&common->cc_lock, flags);
-	busy = ath_update_survey_stats(sc);
-	spin_unlock_irqrestore(&common->cc_lock, flags);
-
-	ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
-		busy, sc->hw_busy_count + 1);
-	if (busy >= 99) {
-		if (++sc->hw_busy_count >= 3) {
-			RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
-			goto sched_reset;
-		}
-	} else if (busy >= 0) {
-		sc->hw_busy_count = 0;
-		nbeacon = 3;
-	}
-
-	ath_start_rx_poll(sc, nbeacon);
-	goto out;
-
-sched_reset:
-	ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-out:
-	ath9k_ps_restore(sc);
-}
-
-static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
-{
-	static int count;
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
-	if (pll_sqsum >= 0x40000) {
-		count++;
-		if (count == 3) {
-			/* Rx is hung for more than 500ms. Reset it */
-			ath_dbg(common, RESET, "Possible RX hang, resetting\n");
-			RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
-			ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-			count = 0;
-		}
-	} else
-		count = 0;
-}
-
-void ath_hw_pll_work(struct work_struct *work)
-{
-	struct ath_softc *sc = container_of(work, struct ath_softc,
-					    hw_pll_work.work);
-	u32 pll_sqsum;
-
-	if (AR_SREV_9485(sc->sc_ah)) {
-
-		ath9k_ps_wakeup(sc);
-		pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
-		ath9k_ps_restore(sc);
-
-		ath_hw_pll_rx_hang_check(sc, pll_sqsum);
-
-		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
-	}
-}
-
 /**********************/
 /* mac80211 callbacks */
 /**********************/
@@ -1045,10 +639,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
 		ah->imask |= ATH9K_INT_CST;
 
-	if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
-		ah->imask |= ATH9K_INT_MCI;
+	ath_mci_enable(sc);
 
-	sc->sc_flags &= ~SC_OP_INVALID;
+	clear_bit(SC_OP_INVALID, &sc->sc_flags);
 	sc->sc_ah->is_monitoring = false;
 
 	if (!ath_complete_reset(sc, false)) {
@@ -1090,6 +683,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_tx_control txctl;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	unsigned long flags;
 
 	if (sc->ps_enabled) {
 		/*
@@ -1112,6 +706,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 		 * completed and if needed, also for RX of buffered frames.
 		 */
 		ath9k_ps_wakeup(sc);
+		spin_lock_irqsave(&sc->sc_pm_lock, flags);
 		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)) {
@@ -1127,6 +722,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 		 * the ps_flags bit is cleared. We are just dropping
 		 * the ps_usecount here.
 		 */
+		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 		ath9k_ps_restore(sc);
 	}
 
@@ -1167,7 +763,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 	ath_cancel_work(sc);
 	del_timer_sync(&sc->rx_poll_timer);
 
-	if (sc->sc_flags & SC_OP_INVALID) {
+	if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
 		ath_dbg(common, ANY, "Device not present\n");
 		mutex_unlock(&sc->mutex);
 		return;
@@ -1224,7 +820,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
 	ath9k_ps_restore(sc);
 
-	sc->sc_flags |= SC_OP_INVALID;
+	set_bit(SC_OP_INVALID, &sc->sc_flags);
 	sc->ps_idle = prev_idle;
 
 	mutex_unlock(&sc->mutex);
@@ -1328,11 +924,11 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
 	/* Set op-mode & TSF */
 	if (iter_data.naps > 0) {
 		ath9k_hw_set_tsfadjust(ah, 1);
-		sc->sc_flags |= SC_OP_TSF_RESET;
+		set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
 		ah->opmode = NL80211_IFTYPE_AP;
 	} else {
 		ath9k_hw_set_tsfadjust(ah, 0);
-		sc->sc_flags &= ~SC_OP_TSF_RESET;
+		clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
 
 		if (iter_data.nmeshes)
 			ah->opmode = NL80211_IFTYPE_MESH_POINT;
@@ -1347,14 +943,10 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
 	/*
 	 * Enable MIB interrupts when there are hardware phy counters.
 	 */
-	if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) {
-		if (ah->config.enable_ani)
-			ah->imask |= ATH9K_INT_MIB;
+	if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0)
 		ah->imask |= ATH9K_INT_TSFOOR;
-	} else {
-		ah->imask &= ~ATH9K_INT_MIB;
+	else
 		ah->imask &= ~ATH9K_INT_TSFOOR;
-	}
 
 	ath9k_hw_set_interrupts(ah);
 
@@ -1363,12 +955,12 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
 		sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
 
 		if (!common->disable_ani) {
-			sc->sc_flags |= SC_OP_ANI_RUN;
+			set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
 			ath_start_ani(common);
 		}
 
 	} else {
-		sc->sc_flags &= ~SC_OP_ANI_RUN;
+		clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
 		del_timer_sync(&common->ani.timer);
 	}
 }
@@ -1389,25 +981,6 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
 	}
 }
 
-void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
-{
-	if (!AR_SREV_9300(sc->sc_ah))
-		return;
-
-	if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF))
-		return;
-
-	mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
-			(nbeacon * sc->cur_beacon_conf.beacon_interval));
-}
-
-void ath_rx_poll(unsigned long data)
-{
-	struct ath_softc *sc = (struct ath_softc *)data;
-
-	ieee80211_queue_work(sc->hw, &sc->hw_check_work);
-}
-
 static int ath9k_add_interface(struct ieee80211_hw *hw,
 			       struct ieee80211_vif *vif)
 {
@@ -1443,15 +1016,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 		}
 	}
 
-	if ((ah->opmode == NL80211_IFTYPE_ADHOC) ||
-	    ((vif->type == NL80211_IFTYPE_ADHOC) &&
-	     sc->nvifs > 0)) {
-		ath_err(common, "Cannot create ADHOC interface when other"
-			" interfaces already exist.\n");
-		ret = -EINVAL;
-		goto out;
-	}
-
 	ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
 
 	sc->nvifs++;
@@ -1476,15 +1040,6 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
 	mutex_lock(&sc->mutex);
 	ath9k_ps_wakeup(sc);
 
-	/* See if new interface type is valid. */
-	if ((new_type == NL80211_IFTYPE_ADHOC) &&
-	    (sc->nvifs > 1)) {
-		ath_err(common, "When using ADHOC, it must be the only"
-			" interface.\n");
-		ret = -EINVAL;
-		goto out;
-	}
-
 	if (ath9k_uses_beacons(new_type) &&
 	    !ath9k_uses_beacons(vif->type)) {
 		if (sc->nbcnvifs >= ATH_BCBUF) {
@@ -1627,11 +1182,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 		if (ah->curchan)
 			old_pos = ah->curchan - &ah->channels[0];
 
-		if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
-			sc->sc_flags |= SC_OP_OFFCHANNEL;
-		else
-			sc->sc_flags &= ~SC_OP_OFFCHANNEL;
-
 		ath_dbg(common, CONFIG, "Set channel: %d MHz type: %d\n",
 			curchan->center_freq, conf->channel_type);
 
@@ -1673,6 +1223,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 		if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
 			ath_err(common, "Unable to set channel\n");
 			mutex_unlock(&sc->mutex);
+			ath9k_ps_restore(sc);
 			return -EINVAL;
 		}
 
@@ -1911,16 +1462,16 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 	struct ath_vif *avp = (void *)vif->drv_priv;
-
+	unsigned long flags;
 	/*
 	 * Skip iteration if primary station vif's bss info
 	 * was not changed
 	 */
-	if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
+	if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
 		return;
 
 	if (bss_conf->assoc) {
-		sc->sc_flags |= SC_OP_PRIM_STA_VIF;
+		set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
 		avp->primary_sta_vif = true;
 		memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
 		common->curaid = bss_conf->aid;
@@ -1933,7 +1484,10 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 		 * on the receipt of the first Beacon frame (i.e.,
 		 * after time sync with the AP).
 		 */
+		spin_lock_irqsave(&sc->sc_pm_lock, flags);
 		sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+
 		/* Reset rssi stats */
 		sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
 		sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
@@ -1941,7 +1495,7 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 		ath_start_rx_poll(sc, 3);
 
 		if (!common->disable_ani) {
-			sc->sc_flags |= SC_OP_ANI_RUN;
+			set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
 			ath_start_ani(common);
 		}
 
@@ -1961,7 +1515,8 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
 	if (avp->primary_sta_vif && !bss_conf->assoc) {
 		ath_dbg(common, CONFIG, "Bss Info DISASSOC %d, bssid %pM\n",
 			common->curaid, common->curbssid);
-		sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
+		clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
+		clear_bit(SC_OP_BEACONS, &sc->sc_flags);
 		avp->primary_sta_vif = false;
 		memset(common->curbssid, 0, ETH_ALEN);
 		common->curaid = 0;
@@ -1974,10 +1529,9 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
 	 * None of station vifs are associated.
 	 * Clear bssid & aid
 	 */
-	if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
+	if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
 		ath9k_hw_write_associd(sc->sc_ah);
-		/* Stop ANI */
-		sc->sc_flags &= ~SC_OP_ANI_RUN;
+		clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
 		del_timer_sync(&common->ani.timer);
 		del_timer_sync(&sc->rx_poll_timer);
 		memset(&sc->caldata, 0, sizeof(sc->caldata));
@@ -2015,12 +1569,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
 			sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
 
 			if (!common->disable_ani) {
-				sc->sc_flags |= SC_OP_ANI_RUN;
+				set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
 				ath_start_ani(common);
 			}
 
 		} else {
-			sc->sc_flags &= ~SC_OP_ANI_RUN;
+			clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
 			del_timer_sync(&common->ani.timer);
 			del_timer_sync(&sc->rx_poll_timer);
 		}
@@ -2032,7 +1586,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
 	 */
 	if ((changed & BSS_CHANGED_BEACON_INT) &&
 	    (vif->type == NL80211_IFTYPE_AP))
-		sc->sc_flags |= SC_OP_TSF_RESET;
+		set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
 
 	/* Configure beaconing (AP, IBSS, MESH) */
 	if (ath9k_uses_beacons(vif->type) &&
@@ -2224,7 +1778,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
 		return;
 	}
 
-	if (sc->sc_flags & SC_OP_INVALID) {
+	if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
 		ath_dbg(common, ANY, "Device not present\n");
 		mutex_unlock(&sc->mutex);
 		return;
@@ -2389,6 +1943,134 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
 	return 0;
 }
 
+#ifdef CONFIG_ATH9K_DEBUGFS
+
+/* Ethtool support for get-stats */
+
+#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
+static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
+	"tx_pkts_nic",
+	"tx_bytes_nic",
+	"rx_pkts_nic",
+	"rx_bytes_nic",
+	AMKSTR(d_tx_pkts),
+	AMKSTR(d_tx_bytes),
+	AMKSTR(d_tx_mpdus_queued),
+	AMKSTR(d_tx_mpdus_completed),
+	AMKSTR(d_tx_mpdu_xretries),
+	AMKSTR(d_tx_aggregates),
+	AMKSTR(d_tx_ampdus_queued_hw),
+	AMKSTR(d_tx_ampdus_queued_sw),
+	AMKSTR(d_tx_ampdus_completed),
+	AMKSTR(d_tx_ampdu_retries),
+	AMKSTR(d_tx_ampdu_xretries),
+	AMKSTR(d_tx_fifo_underrun),
+	AMKSTR(d_tx_op_exceeded),
+	AMKSTR(d_tx_timer_expiry),
+	AMKSTR(d_tx_desc_cfg_err),
+	AMKSTR(d_tx_data_underrun),
+	AMKSTR(d_tx_delim_underrun),
+
+	"d_rx_decrypt_crc_err",
+	"d_rx_phy_err",
+	"d_rx_mic_err",
+	"d_rx_pre_delim_crc_err",
+	"d_rx_post_delim_crc_err",
+	"d_rx_decrypt_busy_err",
+
+	"d_rx_phyerr_radar",
+	"d_rx_phyerr_ofdm_timing",
+	"d_rx_phyerr_cck_timing",
+
+};
+#define ATH9K_SSTATS_LEN ARRAY_SIZE(ath9k_gstrings_stats)
+
+static void ath9k_get_et_strings(struct ieee80211_hw *hw,
+				 struct ieee80211_vif *vif,
+				 u32 sset, u8 *data)
+{
+	if (sset == ETH_SS_STATS)
+		memcpy(data, *ath9k_gstrings_stats,
+		       sizeof(ath9k_gstrings_stats));
+}
+
+static int ath9k_get_et_sset_count(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif, int sset)
+{
+	if (sset == ETH_SS_STATS)
+		return ATH9K_SSTATS_LEN;
+	return 0;
+}
+
+#define PR_QNUM(_n) (sc->tx.txq_map[_n]->axq_qnum)
+#define AWDATA(elem)							\
+	do {								\
+		data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem; \
+		data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem; \
+		data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem; \
+		data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem; \
+	} while (0)
+
+#define AWDATA_RX(elem)						\
+	do {							\
+		data[i++] = sc->debug.stats.rxstats.elem;	\
+	} while (0)
+
+static void ath9k_get_et_stats(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
+			       struct ethtool_stats *stats, u64 *data)
+{
+	struct ath_softc *sc = hw->priv;
+	int i = 0;
+
+	data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_pkts_all +
+		     sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_pkts_all +
+		     sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_pkts_all +
+		     sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_pkts_all);
+	data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_bytes_all +
+		     sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_bytes_all +
+		     sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_bytes_all +
+		     sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_bytes_all);
+	AWDATA_RX(rx_pkts_all);
+	AWDATA_RX(rx_bytes_all);
+
+	AWDATA(tx_pkts_all);
+	AWDATA(tx_bytes_all);
+	AWDATA(queued);
+	AWDATA(completed);
+	AWDATA(xretries);
+	AWDATA(a_aggr);
+	AWDATA(a_queued_hw);
+	AWDATA(a_queued_sw);
+	AWDATA(a_completed);
+	AWDATA(a_retries);
+	AWDATA(a_xretries);
+	AWDATA(fifo_underrun);
+	AWDATA(xtxop);
+	AWDATA(timer_exp);
+	AWDATA(desc_cfg_err);
+	AWDATA(data_underrun);
+	AWDATA(delim_underrun);
+
+	AWDATA_RX(decrypt_crc_err);
+	AWDATA_RX(phy_err);
+	AWDATA_RX(mic_err);
+	AWDATA_RX(pre_delim_crc_err);
+	AWDATA_RX(post_delim_crc_err);
+	AWDATA_RX(decrypt_busy_err);
+
+	AWDATA_RX(phy_err_stats[ATH9K_PHYERR_RADAR]);
+	AWDATA_RX(phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]);
+	AWDATA_RX(phy_err_stats[ATH9K_PHYERR_CCK_TIMING]);
+
+	WARN_ON(i != ATH9K_SSTATS_LEN);
+}
+
+/* End of ethtool get-stats functions */
+
+#endif
+
+
 struct ieee80211_ops ath9k_ops = {
 	.tx 		    = ath9k_tx,
 	.start 		    = ath9k_start,
@@ -2417,4 +2099,10 @@ struct ieee80211_ops ath9k_ops = {
 	.get_stats	    = ath9k_get_stats,
 	.set_antenna	    = ath9k_set_antenna,
 	.get_antenna	    = ath9k_get_antenna,
+
+#ifdef CONFIG_ATH9K_DEBUGFS
+	.get_et_sset_count  = ath9k_get_et_sset_count,
+	.get_et_stats  = ath9k_get_et_stats,
+	.get_et_strings  = ath9k_get_et_strings,
+#endif
 };
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
index 29fe52d..c40e568 100644
--- a/drivers/net/wireless/ath/ath9k/mci.c
+++ b/drivers/net/wireless/ath/ath9k/mci.c
@@ -20,7 +20,7 @@
 #include "ath9k.h"
 #include "mci.h"
 
-static const u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 };
+static const u8 ath_mci_duty_cycle[] = { 55, 50, 60, 70, 80, 85, 90, 95, 98 };
 
 static struct ath_mci_profile_info*
 ath_mci_find_profile(struct ath_mci_profile *mci,
@@ -28,11 +28,14 @@ ath_mci_find_profile(struct ath_mci_profile *mci,
 {
 	struct ath_mci_profile_info *entry;
 
+	if (list_empty(&mci->info))
+		return NULL;
+
 	list_for_each_entry(entry, &mci->info, list) {
 		if (entry->conn_handle == info->conn_handle)
-			break;
+			return entry;
 	}
-	return entry;
+	return NULL;
 }
 
 static bool ath_mci_add_profile(struct ath_common *common,
@@ -49,31 +52,21 @@ static bool ath_mci_add_profile(struct ath_common *common,
 	    (info->type != MCI_GPM_COEX_PROFILE_VOICE))
 		return false;
 
-	entry = ath_mci_find_profile(mci, info);
-
-	if (entry) {
-		memcpy(entry, info, 10);
-	} else {
-		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-		if (!entry)
-			return false;
+	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+	if (!entry)
+		return false;
 
-		memcpy(entry, info, 10);
-		INC_PROF(mci, info);
-		list_add_tail(&info->list, &mci->info);
-	}
+	memcpy(entry, info, 10);
+	INC_PROF(mci, info);
+	list_add_tail(&entry->list, &mci->info);
 
 	return true;
 }
 
 static void ath_mci_del_profile(struct ath_common *common,
 				struct ath_mci_profile *mci,
-				struct ath_mci_profile_info *info)
+				struct ath_mci_profile_info *entry)
 {
-	struct ath_mci_profile_info *entry;
-
-	entry = ath_mci_find_profile(mci, info);
-
 	if (!entry)
 		return;
 
@@ -86,12 +79,16 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci)
 {
 	struct ath_mci_profile_info *info, *tinfo;
 
+	mci->aggr_limit = 0;
+
+	if (list_empty(&mci->info))
+		return;
+
 	list_for_each_entry_safe(info, tinfo, &mci->info, list) {
 		list_del(&info->list);
 		DEC_PROF(mci, info);
 		kfree(info);
 	}
-	mci->aggr_limit = 0;
 }
 
 static void ath_mci_adjust_aggr_limit(struct ath_btcoex *btcoex)
@@ -116,42 +113,60 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_btcoex *btcoex = &sc->btcoex;
 	struct ath_mci_profile *mci = &btcoex->mci;
+	struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
 	struct ath_mci_profile_info *info;
 	u32 num_profile = NUM_PROF(mci);
 
+	if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING)
+		goto skip_tuning;
+
+	btcoex->duty_cycle = ath_mci_duty_cycle[num_profile];
+
 	if (num_profile == 1) {
 		info = list_first_entry(&mci->info,
 					struct ath_mci_profile_info,
 					list);
-		if (mci->num_sco && info->T == 12) {
-			mci->aggr_limit = 8;
+		if (mci->num_sco) {
+			if (info->T == 12)
+				mci->aggr_limit = 8;
+			else if (info->T == 6) {
+				mci->aggr_limit = 6;
+				btcoex->duty_cycle = 30;
+			}
 			ath_dbg(common, MCI,
-				"Single SCO, aggregation limit 2 ms\n");
-		} else if ((info->type == MCI_GPM_COEX_PROFILE_BNEP) &&
-			   !info->master) {
-			btcoex->btcoex_period = 60;
+				"Single SCO, aggregation limit %d 1/4 ms\n",
+				mci->aggr_limit);
+		} else if (mci->num_pan || mci->num_other_acl) {
+			/*
+			 * For single PAN/FTP profile, allocate 35% for BT
+			 * to improve WLAN throughput.
+			 */
+			btcoex->duty_cycle = 35;
+			btcoex->btcoex_period = 53;
 			ath_dbg(common, MCI,
-				"Single slave PAN/FTP, bt period 60 ms\n");
-		} else if ((info->type == MCI_GPM_COEX_PROFILE_HID) &&
-			 (info->T > 0 && info->T < 50) &&
-			 (info->A > 1 || info->W > 1)) {
+				"Single PAN/FTP bt period %d ms dutycycle %d\n",
+				btcoex->duty_cycle, btcoex->btcoex_period);
+		} else if (mci->num_hid) {
 			btcoex->duty_cycle = 30;
-			mci->aggr_limit = 8;
+			mci->aggr_limit = 6;
 			ath_dbg(common, MCI,
 				"Multiple attempt/timeout single HID "
-				"aggregation limit 2 ms dutycycle 30%%\n");
+				"aggregation limit 1.5 ms dutycycle 30%%\n");
 		}
-	} else if ((num_profile == 2) && (mci->num_hid == 2)) {
-		btcoex->duty_cycle = 30;
-		mci->aggr_limit = 8;
-		ath_dbg(common, MCI,
-			"Two HIDs aggregation limit 2 ms dutycycle 30%%\n");
-	} else if (num_profile > 3) {
+	} else if (num_profile == 2) {
+		if (mci->num_hid == 2)
+			btcoex->duty_cycle = 30;
 		mci->aggr_limit = 6;
 		ath_dbg(common, MCI,
-			"Three or more profiles aggregation limit 1.5 ms\n");
+			"Two BT profiles aggr limit 1.5 ms dutycycle %d%%\n",
+			btcoex->duty_cycle);
+	} else if (num_profile >= 3) {
+		mci->aggr_limit = 4;
+		ath_dbg(common, MCI,
+			"Three or more profiles aggregation limit 1 ms\n");
 	}
 
+skip_tuning:
 	if (IS_CHAN_2GHZ(sc->sc_ah->curchan)) {
 		if (IS_CHAN_HT(sc->sc_ah->curchan))
 			ath_mci_adjust_aggr_limit(btcoex);
@@ -165,12 +180,11 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
 	if (IS_CHAN_5GHZ(sc->sc_ah->curchan))
 		return;
 
-	btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_MAX_DUTY_CYCLE : 0);
+	btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_BDR_DUTY_CYCLE : 0);
 	if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)
 		btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE;
 
-	btcoex->btcoex_period *= 1000;
-	btcoex->btcoex_no_stomp =  btcoex->btcoex_period *
+	btcoex->btcoex_no_stomp =  btcoex->btcoex_period * 1000 *
 		(100 - btcoex->duty_cycle) / 100;
 
 	ath9k_hw_btcoex_enable(sc->sc_ah);
@@ -181,20 +195,16 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 {
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
 	u32 payload[4] = {0, 0, 0, 0};
 
 	switch (opcode) {
 	case MCI_GPM_BT_CAL_REQ:
-		if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
-			ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL);
+		if (mci_hw->bt_state == MCI_BT_AWAKE) {
+			ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START);
 			ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-		} else {
-			ath_dbg(common, MCI, "MCI State mismatch: %d\n",
-				ar9003_mci_state(ah, MCI_STATE_BT, NULL));
 		}
-		break;
-	case MCI_GPM_BT_CAL_DONE:
-		ar9003_mci_state(ah, MCI_STATE_BT, NULL);
+		ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state);
 		break;
 	case MCI_GPM_BT_CAL_GRANT:
 		MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);
@@ -207,32 +217,55 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 	}
 }
 
+static void ath9k_mci_work(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc, mci_work);
+
+	ath_mci_update_scheme(sc);
+}
+
 static void ath_mci_process_profile(struct ath_softc *sc,
 				    struct ath_mci_profile_info *info)
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_btcoex *btcoex = &sc->btcoex;
 	struct ath_mci_profile *mci = &btcoex->mci;
+	struct ath_mci_profile_info *entry = NULL;
+
+	entry = ath_mci_find_profile(mci, info);
+	if (entry) {
+		/*
+		 * Two MCI interrupts are generated while connecting to
+		 * headset and A2DP profile, but only one MCI interrupt
+		 * is generated with last added profile type while disconnecting
+		 * both profiles.
+		 * So while adding second profile type decrement
+		 * the first one.
+		 */
+		if (entry->type != info->type) {
+			DEC_PROF(mci, entry);
+			INC_PROF(mci, info);
+		}
+		memcpy(entry, info, 10);
+	}
 
 	if (info->start) {
-		if (!ath_mci_add_profile(common, mci, info))
+		if (!entry && !ath_mci_add_profile(common, mci, info))
 			return;
 	} else
-		ath_mci_del_profile(common, mci, info);
+		ath_mci_del_profile(common, mci, entry);
 
 	btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
 	mci->aggr_limit = mci->num_sco ? 6 : 0;
 
-	if (NUM_PROF(mci)) {
+	btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
+	if (NUM_PROF(mci))
 		btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
-		btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
-	} else {
+	else
 		btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL :
 							ATH_BTCOEX_STOMP_LOW;
-		btcoex->duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
-	}
 
-	ath_mci_update_scheme(sc);
+	ieee80211_queue_work(sc->hw, &sc->mci_work);
 }
 
 static void ath_mci_process_status(struct ath_softc *sc,
@@ -247,8 +280,6 @@ static void ath_mci_process_status(struct ath_softc *sc,
 	if (status->is_link)
 		return;
 
-	memset(&info, 0, sizeof(struct ath_mci_profile_info));
-
 	info.conn_handle = status->conn_handle;
 	if (ath_mci_find_profile(mci, &info))
 		return;
@@ -268,7 +299,7 @@ static void ath_mci_process_status(struct ath_softc *sc,
 	} while (++i < ATH_MCI_MAX_PROFILE);
 
 	if (old_num_mgmt != mci->num_mgmt)
-		ath_mci_update_scheme(sc);
+		ieee80211_queue_work(sc->hw, &sc->mci_work);
 }
 
 static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
@@ -277,25 +308,20 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 	struct ath_mci_profile_info profile_info;
 	struct ath_mci_profile_status profile_status;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	u32 version;
-	u8 major;
-	u8 minor;
+	u8 major, minor;
 	u32 seq_num;
 
 	switch (opcode) {
 	case MCI_GPM_COEX_VERSION_QUERY:
-		version = ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION,
-					   NULL);
+		ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION);
 		break;
 	case MCI_GPM_COEX_VERSION_RESPONSE:
 		major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION);
 		minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION);
-		version = (major << 8) + minor;
-		version = ar9003_mci_state(ah, MCI_STATE_SET_BT_COEX_VERSION,
-					   &version);
+		ar9003_mci_set_bt_version(ah, major, minor);
 		break;
 	case MCI_GPM_COEX_STATUS_QUERY:
-		ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_CHANNELS, NULL);
+		ar9003_mci_send_wlan_channels(ah);
 		break;
 	case MCI_GPM_COEX_BT_PROFILE_INFO:
 		memcpy(&profile_info,
@@ -362,6 +388,7 @@ int ath_mci_setup(struct ath_softc *sc)
 			 mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4),
 			 mci->sched_buf.bf_paddr);
 
+	INIT_WORK(&sc->mci_work, ath9k_mci_work);
 	ath_dbg(common, MCI, "MCI Initialized\n");
 
 	return 0;
@@ -389,6 +416,7 @@ void ath_mci_intr(struct ath_softc *sc)
 	struct ath_mci_coex *mci = &sc->mci_coex;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
 	u32 mci_int, mci_int_rxmsg;
 	u32 offset, subtype, opcode;
 	u32 *pgpm;
@@ -397,8 +425,8 @@ void ath_mci_intr(struct ath_softc *sc)
 
 	ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg);
 
-	if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) {
-		ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
+	if (ar9003_mci_state(ah, MCI_STATE_ENABLE) == 0) {
+		ar9003_mci_get_next_gpm_offset(ah, true, NULL);
 		return;
 	}
 
@@ -417,46 +445,41 @@ void ath_mci_intr(struct ath_softc *sc)
 					NULL, 0, true, false);
 
 		mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE;
-		ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE, NULL);
+		ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE);
 
 		/*
 		 * always do this for recovery and 2G/5G toggling and LNA_TRANS
 		 */
-		ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL);
+		ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE);
 	}
 
 	if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) {
 		mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING;
 
-		if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) {
-			if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) !=
-			    MCI_BT_SLEEP)
-				ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE,
-						 NULL);
-		}
+		if ((mci_hw->bt_state == MCI_BT_SLEEP) &&
+		    (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP) !=
+		     MCI_BT_SLEEP))
+			ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE);
 	}
 
 	if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) {
 		mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING;
 
-		if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
-			if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) !=
-			    MCI_BT_AWAKE)
-				ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP,
-						 NULL);
-		}
+		if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
+		    (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP) !=
+		     MCI_BT_AWAKE))
+			mci_hw->bt_state = MCI_BT_SLEEP;
 	}
 
 	if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
 	    (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
-		ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL);
+		ar9003_mci_state(ah, MCI_STATE_RECOVER_RX);
 		skip_gpm = true;
 	}
 
 	if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) {
 		mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO;
-		offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET,
-					  NULL);
+		offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET);
 	}
 
 	if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) {
@@ -465,8 +488,8 @@ void ath_mci_intr(struct ath_softc *sc)
 		while (more_data == MCI_GPM_MORE) {
 
 			pgpm = mci->gpm_buf.bf_addr;
-			offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
-						  &more_data);
+			offset = ar9003_mci_get_next_gpm_offset(ah, false,
+								&more_data);
 
 			if (offset == MCI_GPM_INVALID)
 				break;
@@ -507,23 +530,17 @@ void ath_mci_intr(struct ath_softc *sc)
 			mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO;
 
 		if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) {
-			int value_dbm = ar9003_mci_state(ah,
-						 MCI_STATE_CONT_RSSI_POWER, NULL);
+			int value_dbm = MS(mci_hw->cont_status,
+					   AR_MCI_CONT_RSSI_POWER);
 
 			mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO;
 
-			if (ar9003_mci_state(ah, MCI_STATE_CONT_TXRX, NULL))
-				ath_dbg(common, MCI,
-					"MCI CONT_INFO: (tx) pri = %d, pwr = %d dBm\n",
-					ar9003_mci_state(ah,
-						 MCI_STATE_CONT_PRIORITY, NULL),
-					value_dbm);
-			else
-				ath_dbg(common, MCI,
-					"MCI CONT_INFO: (rx) pri = %d,pwr = %d dBm\n",
-					ar9003_mci_state(ah,
-						 MCI_STATE_CONT_PRIORITY, NULL),
-					value_dbm);
+			ath_dbg(common, MCI,
+				"MCI CONT_INFO: (%s) pri = %d pwr = %d dBm\n",
+				MS(mci_hw->cont_status, AR_MCI_CONT_TXRX) ?
+				"tx" : "rx",
+				MS(mci_hw->cont_status, AR_MCI_CONT_PRIORITY),
+				value_dbm);
 		}
 
 		if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK)
@@ -538,3 +555,14 @@ void ath_mci_intr(struct ath_softc *sc)
 		mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR |
 			     AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT);
 }
+
+void ath_mci_enable(struct ath_softc *sc)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	if (!common->btcoex_enabled)
+		return;
+
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+		sc->sc_ah->imask |= ATH9K_INT_MCI;
+}
diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h
index c841444..fc14eea 100644
--- a/drivers/net/wireless/ath/ath9k/mci.h
+++ b/drivers/net/wireless/ath/ath9k/mci.h
@@ -130,4 +130,13 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci);
 int ath_mci_setup(struct ath_softc *sc);
 void ath_mci_cleanup(struct ath_softc *sc);
 void ath_mci_intr(struct ath_softc *sc);
-#endif
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+void ath_mci_enable(struct ath_softc *sc);
+#else
+static inline void ath_mci_enable(struct ath_softc *sc)
+{
+}
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
+
+#endif /* MCI_H*/
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index a856b51..aa0e83a 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -115,6 +115,9 @@ static void ath_pci_aspm_init(struct ath_common *common)
 	int pos;
 	u8 aspm;
 
+	if (!ah->is_pciexpress)
+		return;
+
 	pos = pci_pcie_cap(pdev);
 	if (!pos)
 		return;
@@ -138,6 +141,7 @@ static void ath_pci_aspm_init(struct ath_common *common)
 		aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 		pci_write_config_byte(parent, pos + PCI_EXP_LNKCTL, aspm);
 
+		ath_info(common, "Disabling ASPM since BTCOEX is enabled\n");
 		return;
 	}
 
@@ -147,6 +151,7 @@ static void ath_pci_aspm_init(struct ath_common *common)
 		ah->aspm_enabled = true;
 		/* Initialize PCIe PM and SERDES registers. */
 		ath9k_hw_configpcipowersave(ah, false);
+		ath_info(common, "ASPM enabled: 0x%x\n", aspm);
 	}
 }
 
@@ -246,7 +251,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	sc->mem = mem;
 
 	/* Will be cleared in ath9k_start() */
-	sc->sc_flags |= SC_OP_INVALID;
+	set_bit(SC_OP_INVALID, &sc->sc_flags);
 
 	ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);
 	if (ret) {
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 92a6c0a..e034add 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -770,7 +770,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	struct ieee80211_tx_rate *rates = tx_info->control.rates;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	__le16 fc = hdr->frame_control;
-	u8 try_per_rate, i = 0, rix, high_rix;
+	u8 try_per_rate, i = 0, rix;
 	int is_probe = 0;
 
 	if (rate_control_send_low(sta, priv_sta, txrc))
@@ -791,7 +791,6 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	rate_table = ath_rc_priv->rate_table;
 	rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
 				     &is_probe, false);
-	high_rix = rix;
 
 	/*
 	 * If we're in HT mode and both us and our peer supports LDPC.
@@ -839,16 +838,16 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	try_per_rate = 8;
 
 	/*
-	 * Use a legacy rate as last retry to ensure that the frame
-	 * is tried in both MCS and legacy rates.
+	 * If the last rate in the rate series is MCS and has
+	 * more than 80% of per thresh, then use a legacy rate
+	 * as last retry to ensure that the frame is tried in both
+	 * MCS and legacy rate.
 	 */
-	if ((rates[2].flags & IEEE80211_TX_RC_MCS) &&
-	    (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) ||
-	    (ath_rc_priv->per[high_rix] > 45)))
+	ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
+	if (WLAN_RC_PHY_HT(rate_table->info[rix].phy) &&
+	    (ath_rc_priv->per[rix] > 45))
 		rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
 				&is_probe, true);
-	else
-		ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
 
 	/* All other rates in the series have RTS enabled */
 	ath_rc_rate_set_series(rate_table, &rates[i], txrc,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index e1fcc68..05185fc 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -20,43 +20,6 @@
 
 #define SKB_CB_ATHBUF(__skb)	(*((struct ath_buf **)__skb->cb))
 
-static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
-					       int mindelta, int main_rssi_avg,
-					       int alt_rssi_avg, int pkt_count)
-{
-	return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
-		(alt_rssi_avg > main_rssi_avg + maxdelta)) ||
-		(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
-}
-
-static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
-					int curr_main_set, int curr_alt_set,
-					int alt_rssi_avg, int main_rssi_avg)
-{
-	bool result = false;
-	switch (div_group) {
-	case 0:
-		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
-			result = true;
-		break;
-	case 1:
-	case 2:
-		if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
-			(curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
-				(alt_rssi_avg >= (main_rssi_avg - 5))) ||
-			((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
-			(curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
-				(alt_rssi_avg >= (main_rssi_avg - 2)))) &&
-							(alt_rssi_avg >= 4))
-			result = true;
-		else
-			result = false;
-		break;
-	}
-
-	return result;
-}
-
 static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
 {
 	return sc->ps_enabled &&
@@ -303,7 +266,7 @@ static void ath_edma_start_recv(struct ath_softc *sc)
 
 	ath_opmode_init(sc);
 
-	ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
+	ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
 
 	spin_unlock_bh(&sc->rx.rxbuflock);
 }
@@ -322,8 +285,8 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
 	int error = 0;
 
 	spin_lock_init(&sc->sc_pcu_lock);
-	sc->sc_flags &= ~SC_OP_RXFLUSH;
 	spin_lock_init(&sc->rx.rxbuflock);
+	clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
 
 	common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
 			     sc->sc_ah->caps.rx_status_len;
@@ -500,7 +463,7 @@ int ath_startrecv(struct ath_softc *sc)
 
 start_recv:
 	ath_opmode_init(sc);
-	ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
+	ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
 
 	spin_unlock_bh(&sc->rx.rxbuflock);
 
@@ -535,11 +498,11 @@ bool ath_stoprecv(struct ath_softc *sc)
 
 void ath_flushrecv(struct ath_softc *sc)
 {
-	sc->sc_flags |= SC_OP_RXFLUSH;
+	set_bit(SC_OP_RXFLUSH, &sc->sc_flags);
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
 		ath_rx_tasklet(sc, 1, true);
 	ath_rx_tasklet(sc, 1, false);
-	sc->sc_flags &= ~SC_OP_RXFLUSH;
+	clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
 }
 
 static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
@@ -624,13 +587,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon)
 
 	/* Process Beacon and CAB receive in PS state */
 	if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc))
-	    && mybeacon)
+	    && mybeacon) {
 		ath_rx_ps_beacon(sc, skb);
-	else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
-		 (ieee80211_is_data(hdr->frame_control) ||
-		  ieee80211_is_action(hdr->frame_control)) &&
-		 is_multicast_ether_addr(hdr->addr1) &&
-		 !ieee80211_has_moredata(hdr->frame_control)) {
+	} else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
+		   (ieee80211_is_data(hdr->frame_control) ||
+		    ieee80211_is_action(hdr->frame_control)) &&
+		   is_multicast_ether_addr(hdr->addr1) &&
+		   !ieee80211_has_moredata(hdr->frame_control)) {
 		/*
 		 * No more broadcast/multicast frames to be received at this
 		 * point.
@@ -822,7 +785,8 @@ static bool ath9k_rx_accept(struct ath_common *common,
 	 * descriptor does contain a valid key index. This has been observed
 	 * mostly with CCMP encryption.
 	 */
-	if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID)
+	if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID ||
+	    !test_bit(rx_stats->rs_keyix, common->ccmp_keymap))
 		rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS;
 
 	if (!rx_stats->rs_datalen) {
@@ -1067,709 +1031,6 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
 		rxs->flag &= ~RX_FLAG_DECRYPTED;
 }
 
-static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
-				      struct ath_hw_antcomb_conf ant_conf,
-				      int main_rssi_avg)
-{
-	antcomb->quick_scan_cnt = 0;
-
-	if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
-		antcomb->rssi_lna2 = main_rssi_avg;
-	else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
-		antcomb->rssi_lna1 = main_rssi_avg;
-
-	switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
-	case 0x10: /* LNA2 A-B */
-		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-		antcomb->first_quick_scan_conf =
-			ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-		antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
-		break;
-	case 0x20: /* LNA1 A-B */
-		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-		antcomb->first_quick_scan_conf =
-			ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-		antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
-		break;
-	case 0x21: /* LNA1 LNA2 */
-		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
-		antcomb->first_quick_scan_conf =
-			ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-		antcomb->second_quick_scan_conf =
-			ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-		break;
-	case 0x12: /* LNA2 LNA1 */
-		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
-		antcomb->first_quick_scan_conf =
-			ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-		antcomb->second_quick_scan_conf =
-			ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-		break;
-	case 0x13: /* LNA2 A+B */
-		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-		antcomb->first_quick_scan_conf =
-			ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-		antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
-		break;
-	case 0x23: /* LNA1 A+B */
-		antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-		antcomb->first_quick_scan_conf =
-			ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-		antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
-		break;
-	default:
-		break;
-	}
-}
-
-static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
-				struct ath_hw_antcomb_conf *div_ant_conf,
-				int main_rssi_avg, int alt_rssi_avg,
-				int alt_ratio)
-{
-	/* alt_good */
-	switch (antcomb->quick_scan_cnt) {
-	case 0:
-		/* set alt to main, and alt to first conf */
-		div_ant_conf->main_lna_conf = antcomb->main_conf;
-		div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
-		break;
-	case 1:
-		/* set alt to main, and alt to first conf */
-		div_ant_conf->main_lna_conf = antcomb->main_conf;
-		div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
-		antcomb->rssi_first = main_rssi_avg;
-		antcomb->rssi_second = alt_rssi_avg;
-
-		if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
-			/* main is LNA1 */
-			if (ath_is_alt_ant_ratio_better(alt_ratio,
-						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
-						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
-						main_rssi_avg, alt_rssi_avg,
-						antcomb->total_pkt_count))
-				antcomb->first_ratio = true;
-			else
-				antcomb->first_ratio = false;
-		} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
-			if (ath_is_alt_ant_ratio_better(alt_ratio,
-						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
-						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
-						main_rssi_avg, alt_rssi_avg,
-						antcomb->total_pkt_count))
-				antcomb->first_ratio = true;
-			else
-				antcomb->first_ratio = false;
-		} else {
-			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
-			    (alt_rssi_avg > main_rssi_avg +
-			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
-			    (alt_rssi_avg > main_rssi_avg)) &&
-			    (antcomb->total_pkt_count > 50))
-				antcomb->first_ratio = true;
-			else
-				antcomb->first_ratio = false;
-		}
-		break;
-	case 2:
-		antcomb->alt_good = false;
-		antcomb->scan_not_start = false;
-		antcomb->scan = false;
-		antcomb->rssi_first = main_rssi_avg;
-		antcomb->rssi_third = alt_rssi_avg;
-
-		if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
-			antcomb->rssi_lna1 = alt_rssi_avg;
-		else if (antcomb->second_quick_scan_conf ==
-			 ATH_ANT_DIV_COMB_LNA2)
-			antcomb->rssi_lna2 = alt_rssi_avg;
-		else if (antcomb->second_quick_scan_conf ==
-			 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
-			if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
-				antcomb->rssi_lna2 = main_rssi_avg;
-			else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
-				antcomb->rssi_lna1 = main_rssi_avg;
-		}
-
-		if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
-		    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
-			div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
-		else
-			div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
-
-		if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
-			if (ath_is_alt_ant_ratio_better(alt_ratio,
-						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
-						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
-						main_rssi_avg, alt_rssi_avg,
-						antcomb->total_pkt_count))
-				antcomb->second_ratio = true;
-			else
-				antcomb->second_ratio = false;
-		} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
-			if (ath_is_alt_ant_ratio_better(alt_ratio,
-						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
-						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
-						main_rssi_avg, alt_rssi_avg,
-						antcomb->total_pkt_count))
-				antcomb->second_ratio = true;
-			else
-				antcomb->second_ratio = false;
-		} else {
-			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
-			    (alt_rssi_avg > main_rssi_avg +
-			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
-			    (alt_rssi_avg > main_rssi_avg)) &&
-			    (antcomb->total_pkt_count > 50))
-				antcomb->second_ratio = true;
-			else
-				antcomb->second_ratio = false;
-		}
-
-		/* set alt to the conf with maximun ratio */
-		if (antcomb->first_ratio && antcomb->second_ratio) {
-			if (antcomb->rssi_second > antcomb->rssi_third) {
-				/* first alt*/
-				if ((antcomb->first_quick_scan_conf ==
-				    ATH_ANT_DIV_COMB_LNA1) ||
-				    (antcomb->first_quick_scan_conf ==
-				    ATH_ANT_DIV_COMB_LNA2))
-					/* Set alt LNA1 or LNA2*/
-					if (div_ant_conf->main_lna_conf ==
-					    ATH_ANT_DIV_COMB_LNA2)
-						div_ant_conf->alt_lna_conf =
-							ATH_ANT_DIV_COMB_LNA1;
-					else
-						div_ant_conf->alt_lna_conf =
-							ATH_ANT_DIV_COMB_LNA2;
-				else
-					/* Set alt to A+B or A-B */
-					div_ant_conf->alt_lna_conf =
-						antcomb->first_quick_scan_conf;
-			} else if ((antcomb->second_quick_scan_conf ==
-				   ATH_ANT_DIV_COMB_LNA1) ||
-				   (antcomb->second_quick_scan_conf ==
-				   ATH_ANT_DIV_COMB_LNA2)) {
-				/* Set alt LNA1 or LNA2 */
-				if (div_ant_conf->main_lna_conf ==
-				    ATH_ANT_DIV_COMB_LNA2)
-					div_ant_conf->alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1;
-				else
-					div_ant_conf->alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA2;
-			} else {
-				/* Set alt to A+B or A-B */
-				div_ant_conf->alt_lna_conf =
-					antcomb->second_quick_scan_conf;
-			}
-		} else if (antcomb->first_ratio) {
-			/* first alt */
-			if ((antcomb->first_quick_scan_conf ==
-			    ATH_ANT_DIV_COMB_LNA1) ||
-			    (antcomb->first_quick_scan_conf ==
-			    ATH_ANT_DIV_COMB_LNA2))
-					/* Set alt LNA1 or LNA2 */
-				if (div_ant_conf->main_lna_conf ==
-				    ATH_ANT_DIV_COMB_LNA2)
-					div_ant_conf->alt_lna_conf =
-							ATH_ANT_DIV_COMB_LNA1;
-				else
-					div_ant_conf->alt_lna_conf =
-							ATH_ANT_DIV_COMB_LNA2;
-			else
-				/* Set alt to A+B or A-B */
-				div_ant_conf->alt_lna_conf =
-						antcomb->first_quick_scan_conf;
-		} else if (antcomb->second_ratio) {
-				/* second alt */
-			if ((antcomb->second_quick_scan_conf ==
-			    ATH_ANT_DIV_COMB_LNA1) ||
-			    (antcomb->second_quick_scan_conf ==
-			    ATH_ANT_DIV_COMB_LNA2))
-				/* Set alt LNA1 or LNA2 */
-				if (div_ant_conf->main_lna_conf ==
-				    ATH_ANT_DIV_COMB_LNA2)
-					div_ant_conf->alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1;
-				else
-					div_ant_conf->alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA2;
-			else
-				/* Set alt to A+B or A-B */
-				div_ant_conf->alt_lna_conf =
-						antcomb->second_quick_scan_conf;
-		} else {
-			/* main is largest */
-			if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
-			    (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
-				/* Set alt LNA1 or LNA2 */
-				if (div_ant_conf->main_lna_conf ==
-				    ATH_ANT_DIV_COMB_LNA2)
-					div_ant_conf->alt_lna_conf =
-							ATH_ANT_DIV_COMB_LNA1;
-				else
-					div_ant_conf->alt_lna_conf =
-							ATH_ANT_DIV_COMB_LNA2;
-			else
-				/* Set alt to A+B or A-B */
-				div_ant_conf->alt_lna_conf = antcomb->main_conf;
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
-		struct ath_ant_comb *antcomb, int alt_ratio)
-{
-	if (ant_conf->div_group == 0) {
-		/* Adjust the fast_div_bias based on main and alt lna conf */
-		switch ((ant_conf->main_lna_conf << 4) |
-				ant_conf->alt_lna_conf) {
-		case 0x01: /* A-B LNA2 */
-			ant_conf->fast_div_bias = 0x3b;
-			break;
-		case 0x02: /* A-B LNA1 */
-			ant_conf->fast_div_bias = 0x3d;
-			break;
-		case 0x03: /* A-B A+B */
-			ant_conf->fast_div_bias = 0x1;
-			break;
-		case 0x10: /* LNA2 A-B */
-			ant_conf->fast_div_bias = 0x7;
-			break;
-		case 0x12: /* LNA2 LNA1 */
-			ant_conf->fast_div_bias = 0x2;
-			break;
-		case 0x13: /* LNA2 A+B */
-			ant_conf->fast_div_bias = 0x7;
-			break;
-		case 0x20: /* LNA1 A-B */
-			ant_conf->fast_div_bias = 0x6;
-			break;
-		case 0x21: /* LNA1 LNA2 */
-			ant_conf->fast_div_bias = 0x0;
-			break;
-		case 0x23: /* LNA1 A+B */
-			ant_conf->fast_div_bias = 0x6;
-			break;
-		case 0x30: /* A+B A-B */
-			ant_conf->fast_div_bias = 0x1;
-			break;
-		case 0x31: /* A+B LNA2 */
-			ant_conf->fast_div_bias = 0x3b;
-			break;
-		case 0x32: /* A+B LNA1 */
-			ant_conf->fast_div_bias = 0x3d;
-			break;
-		default:
-			break;
-		}
-	} else if (ant_conf->div_group == 1) {
-		/* Adjust the fast_div_bias based on main and alt_lna_conf */
-		switch ((ant_conf->main_lna_conf << 4) |
-			ant_conf->alt_lna_conf) {
-		case 0x01: /* A-B LNA2 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x02: /* A-B LNA1 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x03: /* A-B A+B */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x10: /* LNA2 A-B */
-			if (!(antcomb->scan) &&
-			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-				ant_conf->fast_div_bias = 0x3f;
-			else
-				ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x12: /* LNA2 LNA1 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x13: /* LNA2 A+B */
-			if (!(antcomb->scan) &&
-			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-				ant_conf->fast_div_bias = 0x3f;
-			else
-				ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x20: /* LNA1 A-B */
-			if (!(antcomb->scan) &&
-			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-				ant_conf->fast_div_bias = 0x3f;
-			else
-				ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x21: /* LNA1 LNA2 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x23: /* LNA1 A+B */
-			if (!(antcomb->scan) &&
-			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-				ant_conf->fast_div_bias = 0x3f;
-			else
-				ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x30: /* A+B A-B */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x31: /* A+B LNA2 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x32: /* A+B LNA1 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		default:
-			break;
-		}
-	} else if (ant_conf->div_group == 2) {
-		/* Adjust the fast_div_bias based on main and alt_lna_conf */
-		switch ((ant_conf->main_lna_conf << 4) |
-				ant_conf->alt_lna_conf) {
-		case 0x01: /* A-B LNA2 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x02: /* A-B LNA1 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x03: /* A-B A+B */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x10: /* LNA2 A-B */
-			if (!(antcomb->scan) &&
-				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-				ant_conf->fast_div_bias = 0x1;
-			else
-				ant_conf->fast_div_bias = 0x2;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x12: /* LNA2 LNA1 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x13: /* LNA2 A+B */
-			if (!(antcomb->scan) &&
-				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-				ant_conf->fast_div_bias = 0x1;
-			else
-				ant_conf->fast_div_bias = 0x2;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x20: /* LNA1 A-B */
-			if (!(antcomb->scan) &&
-				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-				ant_conf->fast_div_bias = 0x1;
-			else
-				ant_conf->fast_div_bias = 0x2;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x21: /* LNA1 LNA2 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x23: /* LNA1 A+B */
-			if (!(antcomb->scan) &&
-				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-				ant_conf->fast_div_bias = 0x1;
-			else
-				ant_conf->fast_div_bias = 0x2;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x30: /* A+B A-B */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x31: /* A+B LNA2 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		case 0x32: /* A+B LNA1 */
-			ant_conf->fast_div_bias = 0x1;
-			ant_conf->main_gaintb = 0;
-			ant_conf->alt_gaintb = 0;
-			break;
-		default:
-			break;
-		}
-	}
-}
-
-/* Antenna diversity and combining */
-static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
-{
-	struct ath_hw_antcomb_conf div_ant_conf;
-	struct ath_ant_comb *antcomb = &sc->ant_comb;
-	int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
-	int curr_main_set;
-	int main_rssi = rs->rs_rssi_ctl0;
-	int alt_rssi = rs->rs_rssi_ctl1;
-	int rx_ant_conf,  main_ant_conf;
-	bool short_scan = false;
-
-	rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
-		       ATH_ANT_RX_MASK;
-	main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
-			 ATH_ANT_RX_MASK;
-
-	/* Record packet only when both main_rssi and  alt_rssi is positive */
-	if (main_rssi > 0 && alt_rssi > 0) {
-		antcomb->total_pkt_count++;
-		antcomb->main_total_rssi += main_rssi;
-		antcomb->alt_total_rssi  += alt_rssi;
-		if (main_ant_conf == rx_ant_conf)
-			antcomb->main_recv_cnt++;
-		else
-			antcomb->alt_recv_cnt++;
-	}
-
-	/* Short scan check */
-	if (antcomb->scan && antcomb->alt_good) {
-		if (time_after(jiffies, antcomb->scan_start_time +
-		    msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
-			short_scan = true;
-		else
-			if (antcomb->total_pkt_count ==
-			    ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
-				alt_ratio = ((antcomb->alt_recv_cnt * 100) /
-					    antcomb->total_pkt_count);
-				if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
-					short_scan = true;
-			}
-	}
-
-	if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
-	    rs->rs_moreaggr) && !short_scan)
-		return;
-
-	if (antcomb->total_pkt_count) {
-		alt_ratio = ((antcomb->alt_recv_cnt * 100) /
-			     antcomb->total_pkt_count);
-		main_rssi_avg = (antcomb->main_total_rssi /
-				 antcomb->total_pkt_count);
-		alt_rssi_avg = (antcomb->alt_total_rssi /
-				 antcomb->total_pkt_count);
-	}
-
-
-	ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
-	curr_alt_set = div_ant_conf.alt_lna_conf;
-	curr_main_set = div_ant_conf.main_lna_conf;
-
-	antcomb->count++;
-
-	if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
-		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
-			ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
-						  main_rssi_avg);
-			antcomb->alt_good = true;
-		} else {
-			antcomb->alt_good = false;
-		}
-
-		antcomb->count = 0;
-		antcomb->scan = true;
-		antcomb->scan_not_start = true;
-	}
-
-	if (!antcomb->scan) {
-		if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
-					alt_ratio, curr_main_set, curr_alt_set,
-					alt_rssi_avg, main_rssi_avg)) {
-			if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
-				/* Switch main and alt LNA */
-				div_ant_conf.main_lna_conf =
-						ATH_ANT_DIV_COMB_LNA2;
-				div_ant_conf.alt_lna_conf  =
-						ATH_ANT_DIV_COMB_LNA1;
-			} else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
-				div_ant_conf.main_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1;
-				div_ant_conf.alt_lna_conf  =
-						ATH_ANT_DIV_COMB_LNA2;
-			}
-
-			goto div_comb_done;
-		} else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
-			   (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
-			/* Set alt to another LNA */
-			if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
-				div_ant_conf.alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1;
-			else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
-				div_ant_conf.alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA2;
-
-			goto div_comb_done;
-		}
-
-		if ((alt_rssi_avg < (main_rssi_avg +
-						div_ant_conf.lna1_lna2_delta)))
-			goto div_comb_done;
-	}
-
-	if (!antcomb->scan_not_start) {
-		switch (curr_alt_set) {
-		case ATH_ANT_DIV_COMB_LNA2:
-			antcomb->rssi_lna2 = alt_rssi_avg;
-			antcomb->rssi_lna1 = main_rssi_avg;
-			antcomb->scan = true;
-			/* set to A+B */
-			div_ant_conf.main_lna_conf =
-				ATH_ANT_DIV_COMB_LNA1;
-			div_ant_conf.alt_lna_conf  =
-				ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-			break;
-		case ATH_ANT_DIV_COMB_LNA1:
-			antcomb->rssi_lna1 = alt_rssi_avg;
-			antcomb->rssi_lna2 = main_rssi_avg;
-			antcomb->scan = true;
-			/* set to A+B */
-			div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
-			div_ant_conf.alt_lna_conf  =
-				ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-			break;
-		case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
-			antcomb->rssi_add = alt_rssi_avg;
-			antcomb->scan = true;
-			/* set to A-B */
-			div_ant_conf.alt_lna_conf =
-				ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-			break;
-		case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
-			antcomb->rssi_sub = alt_rssi_avg;
-			antcomb->scan = false;
-			if (antcomb->rssi_lna2 >
-			    (antcomb->rssi_lna1 +
-			    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
-				/* use LNA2 as main LNA */
-				if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
-				    (antcomb->rssi_add > antcomb->rssi_sub)) {
-					/* set to A+B */
-					div_ant_conf.main_lna_conf =
-						ATH_ANT_DIV_COMB_LNA2;
-					div_ant_conf.alt_lna_conf  =
-						ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-				} else if (antcomb->rssi_sub >
-					   antcomb->rssi_lna1) {
-					/* set to A-B */
-					div_ant_conf.main_lna_conf =
-						ATH_ANT_DIV_COMB_LNA2;
-					div_ant_conf.alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-				} else {
-					/* set to LNA1 */
-					div_ant_conf.main_lna_conf =
-						ATH_ANT_DIV_COMB_LNA2;
-					div_ant_conf.alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1;
-				}
-			} else {
-				/* use LNA1 as main LNA */
-				if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
-				    (antcomb->rssi_add > antcomb->rssi_sub)) {
-					/* set to A+B */
-					div_ant_conf.main_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1;
-					div_ant_conf.alt_lna_conf  =
-						ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-				} else if (antcomb->rssi_sub >
-					   antcomb->rssi_lna1) {
-					/* set to A-B */
-					div_ant_conf.main_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1;
-					div_ant_conf.alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-				} else {
-					/* set to LNA2 */
-					div_ant_conf.main_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1;
-					div_ant_conf.alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA2;
-				}
-			}
-			break;
-		default:
-			break;
-		}
-	} else {
-		if (!antcomb->alt_good) {
-			antcomb->scan_not_start = false;
-			/* Set alt to another LNA */
-			if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
-				div_ant_conf.main_lna_conf =
-						ATH_ANT_DIV_COMB_LNA2;
-				div_ant_conf.alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1;
-			} else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
-				div_ant_conf.main_lna_conf =
-						ATH_ANT_DIV_COMB_LNA1;
-				div_ant_conf.alt_lna_conf =
-						ATH_ANT_DIV_COMB_LNA2;
-			}
-			goto div_comb_done;
-		}
-	}
-
-	ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
-					   main_rssi_avg, alt_rssi_avg,
-					   alt_ratio);
-
-	antcomb->quick_scan_cnt++;
-
-div_comb_done:
-	ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
-	ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
-
-	antcomb->scan_start_time = jiffies;
-	antcomb->total_pkt_count = 0;
-	antcomb->main_total_rssi = 0;
-	antcomb->alt_total_rssi = 0;
-	antcomb->main_recv_cnt = 0;
-	antcomb->alt_recv_cnt = 0;
-}
-
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 {
 	struct ath_buf *bf;
@@ -1803,7 +1064,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 
 	do {
 		/* If handling rx interrupt and flush is in progress => exit */
-		if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
+		if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0))
 			break;
 
 		memset(&rs, 0, sizeof(rs));
@@ -1841,13 +1102,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		else
 			rs.is_mybeacon = false;
 
+		sc->rx.num_pkts++;
 		ath_debug_stat_rx(sc, &rs);
 
 		/*
 		 * If we're asked to flush receive queue, directly
 		 * chain it back at the queue without processing it.
 		 */
-		if (sc->sc_flags & SC_OP_RXFLUSH) {
+		if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) {
 			RX_STAT_INC(rx_drop_rxflush);
 			goto requeue_drop_frag;
 		}
@@ -1968,7 +1230,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 			skb_trim(skb, skb->len - 8);
 
 		spin_lock_irqsave(&sc->sc_pm_lock, flags);
-
 		if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
 				     PS_WAIT_FOR_CAB |
 				     PS_WAIT_FOR_PSPOLL_DATA)) ||
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 458f81b..5046b28 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -2098,8 +2098,8 @@ enum {
 #define AR_MCI_CONT_STATUS			0x1848
 #define AR_MCI_CONT_RSSI_POWER			0x000000FF
 #define AR_MCI_CONT_RSSI_POWER_S		0
-#define AR_MCI_CONT_RRIORITY			0x0000FF00
-#define AR_MCI_CONT_RRIORITY_S			8
+#define AR_MCI_CONT_PRIORITY			0x0000FF00
+#define AR_MCI_CONT_PRIORITY_S			8
 #define AR_MCI_CONT_TXRX			0x00010000
 #define AR_MCI_CONT_TXRX_S			16
 
@@ -2162,10 +2162,6 @@ enum {
 #define AR_BTCOEX_CTRL_SPDT_POLARITY			0x80000000
 #define AR_BTCOEX_CTRL_SPDT_POLARITY_S			31
 
-#define AR_BTCOEX_WL_WEIGHTS0				0x18b0
-#define AR_BTCOEX_WL_WEIGHTS1				0x18b4
-#define AR_BTCOEX_WL_WEIGHTS2				0x18b8
-#define AR_BTCOEX_WL_WEIGHTS3				0x18bc
 #define AR_BTCOEX_MAX_TXPWR(_x)				(0x18c0 + ((_x) << 2))
 #define AR_BTCOEX_WL_LNA				0x1940
 #define AR_BTCOEX_RFGAIN_CTRL				0x1944
@@ -2211,5 +2207,7 @@ enum {
 #define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT	0x00000fff
 #define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S	0
 
+#define AR_GLB_SWREG_DISCONT_MODE         0x2002c
+#define AR_GLB_SWREG_DISCONT_EN_BT_WLAN   0x3
 
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index d59dd01..cafb4a0 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -105,19 +105,19 @@ static int ath_max_4ms_framelen[4][32] = {
 /* Aggregation logic */
 /*********************/
 
-static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
 	__acquires(&txq->axq_lock)
 {
 	spin_lock_bh(&txq->axq_lock);
 }
 
-static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
 	__releases(&txq->axq_lock)
 {
 	spin_unlock_bh(&txq->axq_lock);
 }
 
-static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
 	__releases(&txq->axq_lock)
 {
 	struct sk_buff_head q;
@@ -938,6 +938,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
 	struct ieee80211_tx_rate *rates;
 	const struct ieee80211_rate *rate;
 	struct ieee80211_hdr *hdr;
+	struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
 	int i;
 	u8 rix = 0;
 
@@ -948,18 +949,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
 
 	/* set dur_update_en for l-sig computation except for PS-Poll frames */
 	info->dur_update = !ieee80211_is_pspoll(hdr->frame_control);
-
-	/*
-	 * We check if Short Preamble is needed for the CTS rate by
-	 * checking the BSS's global flag.
-	 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
-	 */
-	rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
-	info->rtscts_rate = rate->hw_value;
-
-	if (tx_info->control.vif &&
-	    tx_info->control.vif->bss_conf.use_short_preamble)
-		info->rtscts_rate |= rate->hw_value_short;
+	info->rtscts_rate = fi->rtscts_rate;
 
 	for (i = 0; i < 4; i++) {
 		bool is_40, is_sgi, is_sp;
@@ -1001,13 +991,13 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
 		}
 
 		/* legacy rates */
+		rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
 		if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
 		    !(rate->flags & IEEE80211_RATE_ERP_G))
 			phy = WLAN_RC_PHY_CCK;
 		else
 			phy = WLAN_RC_PHY_OFDM;
 
-		rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
 		info->rates[i].Rate = rate->hw_value;
 		if (rate->hw_value_short) {
 			if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
@@ -1175,6 +1165,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 {
 	struct ath_atx_tid *txtid;
 	struct ath_node *an;
+	u8 density;
 
 	an = (struct ath_node *)sta->drv_priv;
 	txtid = ATH_AN_2_TID(an, tid);
@@ -1182,6 +1173,17 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 	if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
 		return -EAGAIN;
 
+	/* update ampdu factor/density, they may have changed. This may happen
+	 * in HT IBSS when a beacon with HT-info is received after the station
+	 * has already been added.
+	 */
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
+				     sta->ht_cap.ampdu_factor);
+		density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
+		an->mpdudensity = density;
+	}
+
 	txtid->state |= AGGR_ADDBA_PROGRESS;
 	txtid->paused = true;
 	*ssn = txtid->seq_start = txtid->seq_next;
@@ -1536,7 +1538,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
 	int i;
 	u32 npend = 0;
 
-	if (sc->sc_flags & SC_OP_INVALID)
+	if (test_bit(SC_OP_INVALID, &sc->sc_flags))
 		return true;
 
 	ath9k_hw_abort_tx_dma(ah);
@@ -1776,10 +1778,22 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
 	struct ieee80211_sta *sta = tx_info->control.sta;
 	struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	const struct ieee80211_rate *rate;
 	struct ath_frame_info *fi = get_frame_info(skb);
 	struct ath_node *an = NULL;
 	enum ath9k_key_type keytype;
+	bool short_preamble = false;
 
+	/*
+	 * We check if Short Preamble is needed for the CTS rate by
+	 * checking the BSS's global flag.
+	 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
+	 */
+	if (tx_info->control.vif &&
+	    tx_info->control.vif->bss_conf.use_short_preamble)
+		short_preamble = true;
+
+	rate = ieee80211_get_rts_cts_rate(hw, tx_info);
 	keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
 
 	if (sta)
@@ -1794,6 +1808,9 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
 		fi->keyix = ATH9K_TXKEYIX_INVALID;
 	fi->keytype = keytype;
 	fi->framelen = framelen;
+	fi->rtscts_rate = rate->hw_value;
+	if (short_preamble)
+		fi->rtscts_rate |= rate->hw_value_short;
 }
 
 u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
@@ -1994,6 +2011,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
 	int q, padpos, padsize;
+	unsigned long flags;
 
 	ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
 
@@ -2012,6 +2030,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 		skb_pull(skb, padsize);
 	}
 
+	spin_lock_irqsave(&sc->sc_pm_lock, flags);
 	if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
 		sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
 		ath_dbg(common, PS,
@@ -2021,6 +2040,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 					PS_WAIT_FOR_PSPOLL_DATA |
 					PS_WAIT_FOR_TX_ACK));
 	}
+	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
 	q = skb_get_queue_mapping(skb);
 	if (txq == sc->tx.txq_map[q]) {
@@ -2231,46 +2251,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 	ath_txq_unlock_complete(sc, txq);
 }
 
-static void ath_tx_complete_poll_work(struct work_struct *work)
-{
-	struct ath_softc *sc = container_of(work, struct ath_softc,
-			tx_complete_work.work);
-	struct ath_txq *txq;
-	int i;
-	bool needreset = false;
-#ifdef CONFIG_ATH9K_DEBUGFS
-	sc->tx_complete_poll_work_seen++;
-#endif
-
-	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-		if (ATH_TXQ_SETUP(sc, i)) {
-			txq = &sc->tx.txq[i];
-			ath_txq_lock(sc, txq);
-			if (txq->axq_depth) {
-				if (txq->axq_tx_inprogress) {
-					needreset = true;
-					ath_txq_unlock(sc, txq);
-					break;
-				} else {
-					txq->axq_tx_inprogress = true;
-				}
-			}
-			ath_txq_unlock_complete(sc, txq);
-		}
-
-	if (needreset) {
-		ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
-			"tx hung, resetting the chip\n");
-		RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
-		ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-	}
-
-	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
-			msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
-}
-
-
-
 void ath_tx_tasklet(struct ath_softc *sc)
 {
 	struct ath_hw *ah = sc->sc_ah;
diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c
index 195dc65..39a6387 100644
--- a/drivers/net/wireless/ath/carl9170/cmd.c
+++ b/drivers/net/wireless/ath/carl9170/cmd.c
@@ -138,7 +138,7 @@ int carl9170_reboot(struct ar9170 *ar)
 	if (!cmd)
 		return -ENOMEM;
 
-	err = __carl9170_exec_cmd(ar, (struct carl9170_cmd *)cmd, true);
+	err = __carl9170_exec_cmd(ar, cmd, true);
 	return err;
 }
 
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 84b22ee..7a8e90e 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -161,7 +161,7 @@ static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
 
 void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
 {
-	struct carl9170_rsp *cmd = (void *) buf;
+	struct carl9170_rsp *cmd = buf;
 	struct ieee80211_vif *vif;
 
 	if (carl9170_check_sequence(ar, cmd->hdr.seq))
@@ -520,7 +520,7 @@ static u8 *carl9170_find_ie(u8 *data, unsigned int len, u8 ie)
  */
 static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
 {
-	struct ieee80211_hdr *hdr = (void *) data;
+	struct ieee80211_hdr *hdr = data;
 	struct ieee80211_tim_ie *tim_ie;
 	u8 *tim;
 	u8 tim_len;
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c
index 0e81904..5c54aa4 100644
--- a/drivers/net/wireless/ath/key.c
+++ b/drivers/net/wireless/ath/key.c
@@ -556,6 +556,9 @@ int ath_key_config(struct ath_common *common,
 		return -EIO;
 
 	set_bit(idx, common->keymap);
+	if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
+		set_bit(idx, common->ccmp_keymap);
+
 	if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
 		set_bit(idx + 64, common->keymap);
 		set_bit(idx, common->tkip_keymap);
@@ -582,6 +585,7 @@ void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
 		return;
 
 	clear_bit(key->hw_key_idx, common->keymap);
+	clear_bit(key->hw_key_idx, common->ccmp_keymap);
 	if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
 		return;
 
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index d07c030..4a4e98f 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -2952,10 +2952,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
 	/* current AP address - only in reassoc frame */
 	if (is_reassoc) {
 		memcpy(body.ap, priv->CurrentBSSID, 6);
-		ssid_el_p = (u8 *)&body.ssid_el_id;
+		ssid_el_p = &body.ssid_el_id;
 		bodysize = 18 + priv->SSID_size;
 	} else {
-		ssid_el_p = (u8 *)&body.ap[0];
+		ssid_el_p = &body.ap[0];
 		bodysize = 12 + priv->SSID_size;
 	}
 
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index f1f8bd0..ff50cb4 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -52,7 +52,7 @@ struct b43legacy_dmadesc32 *op32_idx2desc(struct b43legacy_dmaring *ring,
 	desc = ring->descbase;
 	desc = &(desc[slot]);
 
-	return (struct b43legacy_dmadesc32 *)desc;
+	return desc;
 }
 
 static void op32_fill_descriptor(struct b43legacy_dmaring *ring,
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index eae691e..8156135 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1508,7 +1508,7 @@ static void b43legacy_release_firmware(struct b43legacy_wldev *dev)
 
 static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl)
 {
-	b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/"
+	b43legacyerr(wl, "You must go to http://wireless.kernel.org/en/users/"
 		     "Drivers/b43#devicefirmware "
 		     "and download the correct firmware (version 3).\n");
 }
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index a8012f2..b8ffea6 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -269,8 +269,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
 	b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
 				    (&txhdr->plcp), plcp_fragment_len,
 				    rate);
-	b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
-				    (&txhdr->plcp_fb), plcp_fragment_len,
+	b43legacy_generate_plcp_hdr(&txhdr->plcp_fb, plcp_fragment_len,
 				    rate_fb->hw_value);
 
 	/* PHY TX Control word */
@@ -340,8 +339,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
 		b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
 					    (&txhdr->rts_plcp),
 					    len, rts_rate);
-		b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
-					    (&txhdr->rts_plcp_fb),
+		b43legacy_generate_plcp_hdr(&txhdr->rts_plcp_fb,
 					    len, rts_rate_fb);
 		hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
 		txhdr->rts_dur_fb = hdr->duration_id;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index abb4803..9d5170b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -34,3 +34,5 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
 		sdio_chip.o
 brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
 		usb.o
+brcmfmac-$(CONFIG_BRCMDBG) += \
+		dhd_dbg.o
\ No newline at end of file
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index 9f63701..a11fe54 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -613,6 +613,9 @@ struct brcmf_pub {
 	struct work_struct multicast_work;
 	u8 macvalue[ETH_ALEN];
 	atomic_t pend_8021x_cnt;
+#ifdef DEBUG
+	struct dentry *dbgfs_dir;
+#endif
 };
 
 struct brcmf_if_event {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
new file mode 100644
index 0000000..7f89540
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * 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 <linux/debugfs.h>
+#include <linux/if_ether.h>
+#include <linux/if.h>
+#include <linux/ieee80211.h>
+#include <linux/module.h>
+
+#include <defs.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include "dhd.h"
+#include "dhd_bus.h"
+#include "dhd_dbg.h"
+
+static struct dentry *root_folder;
+
+void brcmf_debugfs_init(void)
+{
+	root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	if (IS_ERR(root_folder))
+		root_folder = NULL;
+}
+
+void brcmf_debugfs_exit(void)
+{
+	if (!root_folder)
+		return;
+
+	debugfs_remove_recursive(root_folder);
+	root_folder = NULL;
+}
+
+int brcmf_debugfs_attach(struct brcmf_pub *drvr)
+{
+	if (!root_folder)
+		return -ENODEV;
+
+	drvr->dbgfs_dir = debugfs_create_dir(dev_name(drvr->dev), root_folder);
+	return PTR_RET(drvr->dbgfs_dir);
+}
+
+void brcmf_debugfs_detach(struct brcmf_pub *drvr)
+{
+	if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
+		debugfs_remove_recursive(drvr->dbgfs_dir);
+}
+
+struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
+{
+	return drvr->dbgfs_dir;
+}
+
+static
+ssize_t brcmf_debugfs_sdio_counter_read(struct file *f, char __user *data,
+					size_t count, loff_t *ppos)
+{
+	struct brcmf_sdio_count *sdcnt = f->private_data;
+	char buf[750];
+	int res;
+
+	/* only allow read from start */
+	if (*ppos > 0)
+		return 0;
+
+	res = scnprintf(buf, sizeof(buf),
+			"intrcount:    %u\nlastintrs:    %u\n"
+			"pollcnt:      %u\nregfails:     %u\n"
+			"tx_sderrs:    %u\nfcqueued:     %u\n"
+			"rxrtx:        %u\nrx_toolong:   %u\n"
+			"rxc_errors:   %u\nrx_hdrfail:   %u\n"
+			"rx_badhdr:    %u\nrx_badseq:    %u\n"
+			"fc_rcvd:      %u\nfc_xoff:      %u\n"
+			"fc_xon:       %u\nrxglomfail:   %u\n"
+			"rxglomframes: %u\nrxglompkts:   %u\n"
+			"f2rxhdrs:     %u\nf2rxdata:     %u\n"
+			"f2txdata:     %u\nf1regdata:    %u\n"
+			"tickcnt:      %u\ntx_ctlerrs:   %lu\n"
+			"tx_ctlpkts:   %lu\nrx_ctlerrs:   %lu\n"
+			"rx_ctlpkts:   %lu\nrx_readahead: %lu\n",
+			sdcnt->intrcount, sdcnt->lastintrs,
+			sdcnt->pollcnt, sdcnt->regfails,
+			sdcnt->tx_sderrs, sdcnt->fcqueued,
+			sdcnt->rxrtx, sdcnt->rx_toolong,
+			sdcnt->rxc_errors, sdcnt->rx_hdrfail,
+			sdcnt->rx_badhdr, sdcnt->rx_badseq,
+			sdcnt->fc_rcvd, sdcnt->fc_xoff,
+			sdcnt->fc_xon, sdcnt->rxglomfail,
+			sdcnt->rxglomframes, sdcnt->rxglompkts,
+			sdcnt->f2rxhdrs, sdcnt->f2rxdata,
+			sdcnt->f2txdata, sdcnt->f1regdata,
+			sdcnt->tickcnt, sdcnt->tx_ctlerrs,
+			sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs,
+			sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt);
+
+	return simple_read_from_buffer(data, count, ppos, buf, res);
+}
+
+static const struct file_operations brcmf_debugfs_sdio_counter_ops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = brcmf_debugfs_sdio_counter_read
+};
+
+void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
+				     struct brcmf_sdio_count *sdcnt)
+{
+	struct dentry *dentry = drvr->dbgfs_dir;
+
+	if (!IS_ERR_OR_NULL(dentry))
+		debugfs_create_file("counters", S_IRUGO, dentry,
+				    sdcnt, &brcmf_debugfs_sdio_counter_ops);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
index a2c4576..b784920 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -76,4 +76,63 @@ do {									\
 
 extern int brcmf_msg_level;
 
+/*
+ * hold counter variables used in brcmfmac sdio driver.
+ */
+struct brcmf_sdio_count {
+	uint intrcount;		/* Count of device interrupt callbacks */
+	uint lastintrs;		/* Count as of last watchdog timer */
+	uint pollcnt;		/* Count of active polls */
+	uint regfails;		/* Count of R_REG failures */
+	uint tx_sderrs;		/* Count of tx attempts with sd errors */
+	uint fcqueued;		/* Tx packets that got queued */
+	uint rxrtx;		/* Count of rtx requests (NAK to dongle) */
+	uint rx_toolong;	/* Receive frames too long to receive */
+	uint rxc_errors;	/* SDIO errors when reading control frames */
+	uint rx_hdrfail;	/* SDIO errors on header reads */
+	uint rx_badhdr;		/* Bad received headers (roosync?) */
+	uint rx_badseq;		/* Mismatched rx sequence number */
+	uint fc_rcvd;		/* Number of flow-control events received */
+	uint fc_xoff;		/* Number which turned on flow-control */
+	uint fc_xon;		/* Number which turned off flow-control */
+	uint rxglomfail;	/* Failed deglom attempts */
+	uint rxglomframes;	/* Number of glom frames (superframes) */
+	uint rxglompkts;	/* Number of packets from glom frames */
+	uint f2rxhdrs;		/* Number of header reads */
+	uint f2rxdata;		/* Number of frame data reads */
+	uint f2txdata;		/* Number of f2 frame writes */
+	uint f1regdata;		/* Number of f1 register accesses */
+	uint tickcnt;		/* Number of watchdog been schedule */
+	ulong tx_ctlerrs;	/* Err of sending ctrl frames */
+	ulong tx_ctlpkts;	/* Ctrl frames sent to dongle */
+	ulong rx_ctlerrs;	/* Err of processing rx ctrl frames */
+	ulong rx_ctlpkts;	/* Ctrl frames processed from dongle */
+	ulong rx_readahead_cnt;	/* packets where header read-ahead was used */
+};
+
+struct brcmf_pub;
+#ifdef DEBUG
+void brcmf_debugfs_init(void);
+void brcmf_debugfs_exit(void);
+int brcmf_debugfs_attach(struct brcmf_pub *drvr);
+void brcmf_debugfs_detach(struct brcmf_pub *drvr);
+struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
+void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
+				     struct brcmf_sdio_count *sdcnt);
+#else
+static inline void brcmf_debugfs_init(void)
+{
+}
+static inline void brcmf_debugfs_exit(void)
+{
+}
+static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
+{
+	return 0;
+}
+static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
+{
+}
+#endif
+
 #endif				/* _BRCMF_DBG_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index 8933f9b..01cf6c0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -1007,6 +1007,9 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
 	drvr->bus_if->drvr = drvr;
 	drvr->dev = dev;
 
+	/* create device debugfs folder */
+	brcmf_debugfs_attach(drvr);
+
 	/* Attach and link in the protocol */
 	ret = brcmf_proto_attach(drvr);
 	if (ret != 0) {
@@ -1123,6 +1126,7 @@ void brcmf_detach(struct device *dev)
 		brcmf_proto_detach(drvr);
 	}
 
+	brcmf_debugfs_detach(drvr);
 	bus_if->drvr = NULL;
 	kfree(drvr);
 }
@@ -1192,6 +1196,8 @@ exit:
 
 static void brcmf_driver_init(struct work_struct *work)
 {
+	brcmf_debugfs_init();
+
 #ifdef CONFIG_BRCMFMAC_SDIO
 	brcmf_sdio_init();
 #endif
@@ -1219,6 +1225,7 @@ static void __exit brcmfmac_module_exit(void)
 #ifdef CONFIG_BRCMFMAC_USB
 	brcmf_usb_exit();
 #endif
+	brcmf_debugfs_exit();
 }
 
 module_init(brcmfmac_module_init);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 1dbf2be..0deca00 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -31,6 +31,8 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/bcma/bcma.h>
+#include <linux/debugfs.h>
+#include <linux/vmalloc.h>
 #include <asm/unaligned.h>
 #include <defs.h>
 #include <brcmu_wifi.h>
@@ -48,6 +50,9 @@
 
 #define CBUF_LEN	(128)
 
+/* Device console log buffer state */
+#define CONSOLE_BUFFER_MAX	2024
+
 struct rte_log_le {
 	__le32 buf;		/* Can't be pointer on (64-bit) hosts */
 	__le32 buf_size;
@@ -281,7 +286,7 @@ struct rte_console {
  * Shared structure between dongle and the host.
  * The structure contains pointers to trap or assert information.
  */
-#define SDPCM_SHARED_VERSION       0x0002
+#define SDPCM_SHARED_VERSION       0x0003
 #define SDPCM_SHARED_VERSION_MASK  0x00FF
 #define SDPCM_SHARED_ASSERT_BUILT  0x0100
 #define SDPCM_SHARED_ASSERT        0x0200
@@ -428,6 +433,29 @@ struct brcmf_console {
 	u8 *buf;		/* Log buffer (host copy) */
 	uint last;		/* Last buffer read index */
 };
+
+struct brcmf_trap_info {
+	__le32		type;
+	__le32		epc;
+	__le32		cpsr;
+	__le32		spsr;
+	__le32		r0;	/* a1 */
+	__le32		r1;	/* a2 */
+	__le32		r2;	/* a3 */
+	__le32		r3;	/* a4 */
+	__le32		r4;	/* v1 */
+	__le32		r5;	/* v2 */
+	__le32		r6;	/* v3 */
+	__le32		r7;	/* v4 */
+	__le32		r8;	/* v5 */
+	__le32		r9;	/* sb/v6 */
+	__le32		r10;	/* sl/v7 */
+	__le32		r11;	/* fp/v8 */
+	__le32		r12;	/* ip */
+	__le32		r13;	/* sp */
+	__le32		r14;	/* lr */
+	__le32		pc;	/* r15 */
+};
 #endif				/* DEBUG */
 
 struct sdpcm_shared {
@@ -439,6 +467,7 @@ struct sdpcm_shared {
 	u32 console_addr;	/* Address of struct rte_console */
 	u32 msgtrace_addr;
 	u8 tag[32];
+	u32 brpt_addr;
 };
 
 struct sdpcm_shared_le {
@@ -450,6 +479,7 @@ struct sdpcm_shared_le {
 	__le32 console_addr;	/* Address of struct rte_console */
 	__le32 msgtrace_addr;
 	u8 tag[32];
+	__le32 brpt_addr;
 };
 
 
@@ -502,12 +532,9 @@ struct brcmf_sdio {
 	bool intr;		/* Use interrupts */
 	bool poll;		/* Use polling */
 	bool ipend;		/* Device interrupt is pending */
-	uint intrcount;		/* Count of device interrupt callbacks */
-	uint lastintrs;		/* Count as of last watchdog timer */
 	uint spurious;		/* Count of spurious interrupts */
 	uint pollrate;		/* Ticks between device polls */
 	uint polltick;		/* Tick counter */
-	uint pollcnt;		/* Count of active polls */
 
 #ifdef DEBUG
 	uint console_interval;
@@ -515,8 +542,6 @@ struct brcmf_sdio {
 	uint console_addr;	/* Console address from shared struct */
 #endif				/* DEBUG */
 
-	uint regfails;		/* Count of R_REG failures */
-
 	uint clkstate;		/* State of sd and backplane clock(s) */
 	bool activity;		/* Activity flag for clock down */
 	s32 idletime;		/* Control for activity timeout */
@@ -531,33 +556,6 @@ struct brcmf_sdio {
 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
 	bool usebufpool;
 
-	/* Some additional counters */
-	uint tx_sderrs;		/* Count of tx attempts with sd errors */
-	uint fcqueued;		/* Tx packets that got queued */
-	uint rxrtx;		/* Count of rtx requests (NAK to dongle) */
-	uint rx_toolong;	/* Receive frames too long to receive */
-	uint rxc_errors;	/* SDIO errors when reading control frames */
-	uint rx_hdrfail;	/* SDIO errors on header reads */
-	uint rx_badhdr;		/* Bad received headers (roosync?) */
-	uint rx_badseq;		/* Mismatched rx sequence number */
-	uint fc_rcvd;		/* Number of flow-control events received */
-	uint fc_xoff;		/* Number which turned on flow-control */
-	uint fc_xon;		/* Number which turned off flow-control */
-	uint rxglomfail;	/* Failed deglom attempts */
-	uint rxglomframes;	/* Number of glom frames (superframes) */
-	uint rxglompkts;	/* Number of packets from glom frames */
-	uint f2rxhdrs;		/* Number of header reads */
-	uint f2rxdata;		/* Number of frame data reads */
-	uint f2txdata;		/* Number of f2 frame writes */
-	uint f1regdata;		/* Number of f1 register accesses */
-	uint tickcnt;		/* Number of watchdog been schedule */
-	unsigned long tx_ctlerrs;	/* Err of sending ctrl frames */
-	unsigned long tx_ctlpkts;	/* Ctrl frames sent to dongle */
-	unsigned long rx_ctlerrs;	/* Err of processing rx ctrl frames */
-	unsigned long rx_ctlpkts;	/* Ctrl frames processed from dongle */
-	unsigned long rx_readahead_cnt;	/* Number of packets where header
-					 * read-ahead was used. */
-
 	u8 *ctrl_frame_buf;
 	u32 ctrl_frame_len;
 	bool ctrl_frame_stat;
@@ -583,6 +581,7 @@ struct brcmf_sdio {
 	u32 fw_ptr;
 
 	bool txoff;		/* Transmit flow-controlled */
+	struct brcmf_sdio_count sdcnt;
 };
 
 /* clkstate */
@@ -945,7 +944,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
 	if (ret == 0)
 		w_sdreg32(bus, SMB_INT_ACK,
 			  offsetof(struct sdpcmd_regs, tosbmailbox));
-	bus->f1regdata += 2;
+	bus->sdcnt.f1regdata += 2;
 
 	/* Dongle recomposed rx frames, accept them again */
 	if (hmb_data & HMB_DATA_NAKHANDLED) {
@@ -984,12 +983,12 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
 							HMB_DATA_FCDATA_SHIFT;
 
 		if (fcbits & ~bus->flowcontrol)
-			bus->fc_xoff++;
+			bus->sdcnt.fc_xoff++;
 
 		if (bus->flowcontrol & ~fcbits)
-			bus->fc_xon++;
+			bus->sdcnt.fc_xon++;
 
-		bus->fc_rcvd++;
+		bus->sdcnt.fc_rcvd++;
 		bus->flowcontrol = fcbits;
 	}
 
@@ -1021,7 +1020,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 
 	brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
 			 SFC_RF_TERM, &err);
-	bus->f1regdata++;
+	bus->sdcnt.f1regdata++;
 
 	/* Wait until the packet has been flushed (device/FIFO stable) */
 	for (lastrbc = retries = 0xffff; retries > 0; retries--) {
@@ -1029,7 +1028,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 				      SBSDIO_FUNC1_RFRAMEBCHI, &err);
 		lo = brcmf_sdio_regrb(bus->sdiodev,
 				      SBSDIO_FUNC1_RFRAMEBCLO, &err);
-		bus->f1regdata += 2;
+		bus->sdcnt.f1regdata += 2;
 
 		if ((hi == 0) && (lo == 0))
 			break;
@@ -1047,11 +1046,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 		brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries);
 
 	if (rtx) {
-		bus->rxrtx++;
+		bus->sdcnt.rxrtx++;
 		err = w_sdreg32(bus, SMB_NAK,
 				offsetof(struct sdpcmd_regs, tosbmailbox));
 
-		bus->f1regdata++;
+		bus->sdcnt.f1regdata++;
 		if (err == 0)
 			bus->rxskip = true;
 	}
@@ -1243,7 +1242,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 				  dlen);
 			errcode = -1;
 		}
-		bus->f2rxdata++;
+		bus->sdcnt.f2rxdata++;
 
 		/* On failure, kill the superframe, allow a couple retries */
 		if (errcode < 0) {
@@ -1256,7 +1255,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			} else {
 				bus->glomerr = 0;
 				brcmf_sdbrcm_rxfail(bus, true, false);
-				bus->rxglomfail++;
+				bus->sdcnt.rxglomfail++;
 				brcmf_sdbrcm_free_glom(bus);
 			}
 			return 0;
@@ -1312,7 +1311,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 		if (rxseq != seq) {
 			brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n",
 				  seq, rxseq);
-			bus->rx_badseq++;
+			bus->sdcnt.rx_badseq++;
 			rxseq = seq;
 		}
 
@@ -1376,7 +1375,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			} else {
 				bus->glomerr = 0;
 				brcmf_sdbrcm_rxfail(bus, true, false);
-				bus->rxglomfail++;
+				bus->sdcnt.rxglomfail++;
 				brcmf_sdbrcm_free_glom(bus);
 			}
 			bus->nextlen = 0;
@@ -1402,7 +1401,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			if (rxseq != seq) {
 				brcmf_dbg(GLOM, "rx_seq %d, expected %d\n",
 					  seq, rxseq);
-				bus->rx_badseq++;
+				bus->sdcnt.rx_badseq++;
 				rxseq = seq;
 			}
 			rxseq++;
@@ -1441,8 +1440,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			down(&bus->sdsem);
 		}
 
-		bus->rxglomframes++;
-		bus->rxglompkts += bus->glom.qlen;
+		bus->sdcnt.rxglomframes++;
+		bus->sdcnt.rxglompkts += bus->glom.qlen;
 	}
 	return num;
 }
@@ -1526,7 +1525,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
 		brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
 			  len, len - doff, bus->sdiodev->bus_if->maxctl);
 		bus->sdiodev->bus_if->dstats.rx_errors++;
-		bus->rx_toolong++;
+		bus->sdcnt.rx_toolong++;
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		goto done;
 	}
@@ -1536,13 +1535,13 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
 				bus->sdiodev->sbwad,
 				SDIO_FUNC_2,
 				F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen);
-	bus->f2rxdata++;
+	bus->sdcnt.f2rxdata++;
 
 	/* Control frame failures need retransmission */
 	if (sdret < 0) {
 		brcmf_dbg(ERROR, "read %d control bytes failed: %d\n",
 			  rdlen, sdret);
-		bus->rxc_errors++;
+		bus->sdcnt.rxc_errors++;
 		brcmf_sdbrcm_rxfail(bus, true, true);
 		goto done;
 	}
@@ -1589,7 +1588,7 @@ brcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen,
 	/* Read the entire frame */
 	sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
 				      SDIO_FUNC_2, F2SYNC, *pkt);
-	bus->f2rxdata++;
+	bus->sdcnt.f2rxdata++;
 
 	if (sdret < 0) {
 		brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n",
@@ -1630,7 +1629,7 @@ brcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf,
 	if ((u16)~(*len ^ check)) {
 		brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n",
 			  nextlen, *len, check);
-		bus->rx_badhdr++;
+		bus->sdcnt.rx_badhdr++;
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		goto fail;
 	}
@@ -1746,7 +1745,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 				bus->nextlen = 0;
 			}
 
-			bus->rx_readahead_cnt++;
+			bus->sdcnt.rx_readahead_cnt++;
 
 			/* Handle Flow Control */
 			fcbits = SDPCM_FCMASK_VALUE(
@@ -1754,12 +1753,12 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 
 			if (bus->flowcontrol != fcbits) {
 				if (~bus->flowcontrol & fcbits)
-					bus->fc_xoff++;
+					bus->sdcnt.fc_xoff++;
 
 				if (bus->flowcontrol & ~fcbits)
-					bus->fc_xon++;
+					bus->sdcnt.fc_xon++;
 
-				bus->fc_rcvd++;
+				bus->sdcnt.fc_rcvd++;
 				bus->flowcontrol = fcbits;
 			}
 
@@ -1767,7 +1766,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 			if (rxseq != seq) {
 				brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n",
 					  seq, rxseq);
-				bus->rx_badseq++;
+				bus->sdcnt.rx_badseq++;
 				rxseq = seq;
 			}
 
@@ -1814,11 +1813,11 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 		sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
 					      SDIO_FUNC_2, F2SYNC, bus->rxhdr,
 					      BRCMF_FIRSTREAD);
-		bus->f2rxhdrs++;
+		bus->sdcnt.f2rxhdrs++;
 
 		if (sdret < 0) {
 			brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret);
-			bus->rx_hdrfail++;
+			bus->sdcnt.rx_hdrfail++;
 			brcmf_sdbrcm_rxfail(bus, true, true);
 			continue;
 		}
@@ -1840,7 +1839,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 		if ((u16) ~(len ^ check)) {
 			brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n",
 				  len, check);
-			bus->rx_badhdr++;
+			bus->sdcnt.rx_badhdr++;
 			brcmf_sdbrcm_rxfail(bus, false, false);
 			continue;
 		}
@@ -1861,7 +1860,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 		if ((doff < SDPCM_HDRLEN) || (doff > len)) {
 			brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n",
 				  doff, len, SDPCM_HDRLEN, seq);
-			bus->rx_badhdr++;
+			bus->sdcnt.rx_badhdr++;
 			brcmf_sdbrcm_rxfail(bus, false, false);
 			continue;
 		}
@@ -1880,19 +1879,19 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 
 		if (bus->flowcontrol != fcbits) {
 			if (~bus->flowcontrol & fcbits)
-				bus->fc_xoff++;
+				bus->sdcnt.fc_xoff++;
 
 			if (bus->flowcontrol & ~fcbits)
-				bus->fc_xon++;
+				bus->sdcnt.fc_xon++;
 
-			bus->fc_rcvd++;
+			bus->sdcnt.fc_rcvd++;
 			bus->flowcontrol = fcbits;
 		}
 
 		/* Check and update sequence number */
 		if (rxseq != seq) {
 			brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq);
-			bus->rx_badseq++;
+			bus->sdcnt.rx_badseq++;
 			rxseq = seq;
 		}
 
@@ -1937,7 +1936,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 			brcmf_dbg(ERROR, "too long: len %d rdlen %d\n",
 				  len, rdlen);
 			bus->sdiodev->bus_if->dstats.rx_errors++;
-			bus->rx_toolong++;
+			bus->sdcnt.rx_toolong++;
 			brcmf_sdbrcm_rxfail(bus, false, false);
 			continue;
 		}
@@ -1960,7 +1959,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 		/* Read the remaining frame data */
 		sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
 					      SDIO_FUNC_2, F2SYNC, pkt);
-		bus->f2rxdata++;
+		bus->sdcnt.f2rxdata++;
 
 		if (sdret < 0) {
 			brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen,
@@ -2147,18 +2146,18 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
 
 	ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
 				    SDIO_FUNC_2, F2SYNC, pkt);
-	bus->f2txdata++;
+	bus->sdcnt.f2txdata++;
 
 	if (ret < 0) {
 		/* On failure, abort the command and terminate the frame */
 		brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
 			  ret);
-		bus->tx_sderrs++;
+		bus->sdcnt.tx_sderrs++;
 
 		brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
 		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
 				 SFC_WF_TERM, NULL);
-		bus->f1regdata++;
+		bus->sdcnt.f1regdata++;
 
 		for (i = 0; i < 3; i++) {
 			u8 hi, lo;
@@ -2166,7 +2165,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
 					      SBSDIO_FUNC1_WFRAMEBCHI, NULL);
 			lo = brcmf_sdio_regrb(bus->sdiodev,
 					      SBSDIO_FUNC1_WFRAMEBCLO, NULL);
-			bus->f1regdata += 2;
+			bus->sdcnt.f1regdata += 2;
 			if ((hi == 0) && (lo == 0))
 				break;
 		}
@@ -2224,7 +2223,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 			ret = r_sdreg32(bus, &intstatus,
 					offsetof(struct sdpcmd_regs,
 						 intstatus));
-			bus->f2txdata++;
+			bus->sdcnt.f2txdata++;
 			if (ret != 0)
 				break;
 			if (intstatus & bus->hostintmask)
@@ -2417,7 +2416,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 		bus->ipend = false;
 		err = r_sdreg32(bus, &newstatus,
 				offsetof(struct sdpcmd_regs, intstatus));
-		bus->f1regdata++;
+		bus->sdcnt.f1regdata++;
 		if (err != 0)
 			newstatus = 0;
 		newstatus &= bus->hostintmask;
@@ -2426,7 +2425,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 			err = w_sdreg32(bus, newstatus,
 					offsetof(struct sdpcmd_regs,
 						 intstatus));
-			bus->f1regdata++;
+			bus->sdcnt.f1regdata++;
 		}
 	}
 
@@ -2445,7 +2444,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 
 		err = r_sdreg32(bus, &newstatus,
 				offsetof(struct sdpcmd_regs, intstatus));
-		bus->f1regdata += 2;
+		bus->sdcnt.f1regdata += 2;
 		bus->fcstate =
 		    !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
 		intstatus |= (newstatus & bus->hostintmask);
@@ -2502,7 +2501,7 @@ clkwait:
 		int ret, i;
 
 		ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
-			SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf,
+			SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf,
 			(u32) bus->ctrl_frame_len);
 
 		if (ret < 0) {
@@ -2510,13 +2509,13 @@ clkwait:
 				terminate the frame */
 			brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
 				  ret);
-			bus->tx_sderrs++;
+			bus->sdcnt.tx_sderrs++;
 
 			brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
 
 			brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
 					 SFC_WF_TERM, &err);
-			bus->f1regdata++;
+			bus->sdcnt.f1regdata++;
 
 			for (i = 0; i < 3; i++) {
 				u8 hi, lo;
@@ -2526,7 +2525,7 @@ clkwait:
 				lo = brcmf_sdio_regrb(bus->sdiodev,
 						      SBSDIO_FUNC1_WFRAMEBCLO,
 						      &err);
-				bus->f1regdata += 2;
+				bus->sdcnt.f1regdata += 2;
 				if ((hi == 0) && (lo == 0))
 					break;
 			}
@@ -2657,7 +2656,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
 	/* Check for existing queue, current flow-control,
 			 pending event, or pending clock */
 	brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq));
-	bus->fcqueued++;
+	bus->sdcnt.fcqueued++;
 
 	/* Priority based enq */
 	spin_lock_bh(&bus->txqlock);
@@ -2845,13 +2844,13 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
 		/* On failure, abort the command and terminate the frame */
 		brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
 			  ret);
-		bus->tx_sderrs++;
+		bus->sdcnt.tx_sderrs++;
 
 		brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
 
 		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
 				 SFC_WF_TERM, NULL);
-		bus->f1regdata++;
+		bus->sdcnt.f1regdata++;
 
 		for (i = 0; i < 3; i++) {
 			u8 hi, lo;
@@ -2859,7 +2858,7 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
 					      SBSDIO_FUNC1_WFRAMEBCHI, NULL);
 			lo = brcmf_sdio_regrb(bus->sdiodev,
 					      SBSDIO_FUNC1_WFRAMEBCLO, NULL);
-			bus->f1regdata += 2;
+			bus->sdcnt.f1regdata += 2;
 			if (hi == 0 && lo == 0)
 				break;
 		}
@@ -2976,13 +2975,324 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 	up(&bus->sdsem);
 
 	if (ret)
-		bus->tx_ctlerrs++;
+		bus->sdcnt.tx_ctlerrs++;
 	else
-		bus->tx_ctlpkts++;
+		bus->sdcnt.tx_ctlpkts++;
 
 	return ret ? -EIO : 0;
 }
 
+#ifdef DEBUG
+static inline bool brcmf_sdio_valid_shared_address(u32 addr)
+{
+	return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff));
+}
+
+static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
+				 struct sdpcm_shared *sh)
+{
+	u32 addr;
+	int rv;
+	u32 shaddr = 0;
+	struct sdpcm_shared_le sh_le;
+	__le32 addr_le;
+
+	shaddr = bus->ramsize - 4;
+
+	/*
+	 * Read last word in socram to determine
+	 * address of sdpcm_shared structure
+	 */
+	rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
+				   (u8 *)&addr_le, 4);
+	if (rv < 0)
+		return rv;
+
+	addr = le32_to_cpu(addr_le);
+
+	brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr);
+
+	/*
+	 * Check if addr is valid.
+	 * NVRAM length at the end of memory should have been overwritten.
+	 */
+	if (!brcmf_sdio_valid_shared_address(addr)) {
+			brcmf_dbg(ERROR, "invalid sdpcm_shared address 0x%08X\n",
+				  addr);
+			return -EINVAL;
+	}
+
+	/* Read hndrte_shared structure */
+	rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
+				   sizeof(struct sdpcm_shared_le));
+	if (rv < 0)
+		return rv;
+
+	/* Endianness */
+	sh->flags = le32_to_cpu(sh_le.flags);
+	sh->trap_addr = le32_to_cpu(sh_le.trap_addr);
+	sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr);
+	sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr);
+	sh->assert_line = le32_to_cpu(sh_le.assert_line);
+	sh->console_addr = le32_to_cpu(sh_le.console_addr);
+	sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);
+
+	if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
+		brcmf_dbg(ERROR,
+			  "sdpcm_shared version mismatch: dhd %d dongle %d\n",
+			  SDPCM_SHARED_VERSION,
+			  sh->flags & SDPCM_SHARED_VERSION_MASK);
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
+				   struct sdpcm_shared *sh, char __user *data,
+				   size_t count)
+{
+	u32 addr, console_ptr, console_size, console_index;
+	char *conbuf = NULL;
+	__le32 sh_val;
+	int rv;
+	loff_t pos = 0;
+	int nbytes = 0;
+
+	/* obtain console information from device memory */
+	addr = sh->console_addr + offsetof(struct rte_console, log_le);
+	rv = brcmf_sdbrcm_membytes(bus, false, addr,
+			(u8 *)&sh_val, sizeof(u32));
+	if (rv < 0)
+		return rv;
+	console_ptr = le32_to_cpu(sh_val);
+
+	addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size);
+	rv = brcmf_sdbrcm_membytes(bus, false, addr,
+			(u8 *)&sh_val, sizeof(u32));
+	if (rv < 0)
+		return rv;
+	console_size = le32_to_cpu(sh_val);
+
+	addr = sh->console_addr + offsetof(struct rte_console, log_le.idx);
+	rv = brcmf_sdbrcm_membytes(bus, false, addr,
+			(u8 *)&sh_val, sizeof(u32));
+	if (rv < 0)
+		return rv;
+	console_index = le32_to_cpu(sh_val);
+
+	/* allocate buffer for console data */
+	if (console_size <= CONSOLE_BUFFER_MAX)
+		conbuf = vzalloc(console_size+1);
+
+	if (!conbuf)
+		return -ENOMEM;
+
+	/* obtain the console data from device */
+	conbuf[console_size] = '\0';
+	rv = brcmf_sdbrcm_membytes(bus, false, console_ptr, (u8 *)conbuf,
+				   console_size);
+	if (rv < 0)
+		goto done;
+
+	rv = simple_read_from_buffer(data, count, &pos,
+				     conbuf + console_index,
+				     console_size - console_index);
+	if (rv < 0)
+		goto done;
+
+	nbytes = rv;
+	if (console_index > 0) {
+		pos = 0;
+		rv = simple_read_from_buffer(data+nbytes, count, &pos,
+					     conbuf, console_index - 1);
+		if (rv < 0)
+			goto done;
+		rv += nbytes;
+	}
+done:
+	vfree(conbuf);
+	return rv;
+}
+
+static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
+				char __user *data, size_t count)
+{
+	int error, res;
+	char buf[350];
+	struct brcmf_trap_info tr;
+	int nbytes;
+	loff_t pos = 0;
+
+	if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
+		return 0;
+
+	error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
+				      sizeof(struct brcmf_trap_info));
+	if (error < 0)
+		return error;
+
+	nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
+	if (nbytes < 0)
+		return nbytes;
+
+	res = scnprintf(buf, sizeof(buf),
+			"dongle trap info: type 0x%x @ epc 0x%08x\n"
+			"  cpsr 0x%08x spsr 0x%08x sp 0x%08x\n"
+			"  lr   0x%08x pc   0x%08x offset 0x%x\n"
+			"  r0   0x%08x r1   0x%08x r2 0x%08x r3 0x%08x\n"
+			"  r4   0x%08x r5   0x%08x r6 0x%08x r7 0x%08x\n",
+			le32_to_cpu(tr.type), le32_to_cpu(tr.epc),
+			le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr),
+			le32_to_cpu(tr.r13), le32_to_cpu(tr.r14),
+			le32_to_cpu(tr.pc), le32_to_cpu(sh->trap_addr),
+			le32_to_cpu(tr.r0), le32_to_cpu(tr.r1),
+			le32_to_cpu(tr.r2), le32_to_cpu(tr.r3),
+			le32_to_cpu(tr.r4), le32_to_cpu(tr.r5),
+			le32_to_cpu(tr.r6), le32_to_cpu(tr.r7));
+
+	error = simple_read_from_buffer(data+nbytes, count, &pos, buf, res);
+	if (error < 0)
+		return error;
+
+	nbytes += error;
+	return nbytes;
+}
+
+static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
+				  struct sdpcm_shared *sh, char __user *data,
+				  size_t count)
+{
+	int error = 0;
+	char buf[200];
+	char file[80] = "?";
+	char expr[80] = "<???>";
+	int res;
+	loff_t pos = 0;
+
+	if ((sh->flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
+		brcmf_dbg(INFO, "firmware not built with -assert\n");
+		return 0;
+	} else if ((sh->flags & SDPCM_SHARED_ASSERT) == 0) {
+		brcmf_dbg(INFO, "no assert in dongle\n");
+		return 0;
+	}
+
+	if (sh->assert_file_addr != 0) {
+		error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr,
+					      (u8 *)file, 80);
+		if (error < 0)
+			return error;
+	}
+	if (sh->assert_exp_addr != 0) {
+		error = brcmf_sdbrcm_membytes(bus, false, sh->assert_exp_addr,
+					      (u8 *)expr, 80);
+		if (error < 0)
+			return error;
+	}
+
+	res = scnprintf(buf, sizeof(buf),
+			"dongle assert: %s:%d: assert(%s)\n",
+			file, sh->assert_line, expr);
+	return simple_read_from_buffer(data, count, &pos, buf, res);
+}
+
+static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
+{
+	int error;
+	struct sdpcm_shared sh;
+
+	down(&bus->sdsem);
+	error = brcmf_sdio_readshared(bus, &sh);
+	up(&bus->sdsem);
+
+	if (error < 0)
+		return error;
+
+	if ((sh.flags & SDPCM_SHARED_ASSERT_BUILT) == 0)
+		brcmf_dbg(INFO, "firmware not built with -assert\n");
+	else if (sh.flags & SDPCM_SHARED_ASSERT)
+		brcmf_dbg(ERROR, "assertion in dongle\n");
+
+	if (sh.flags & SDPCM_SHARED_TRAP)
+		brcmf_dbg(ERROR, "firmware trap in dongle\n");
+
+	return 0;
+}
+
+static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
+				  size_t count, loff_t *ppos)
+{
+	int error = 0;
+	struct sdpcm_shared sh;
+	int nbytes = 0;
+	loff_t pos = *ppos;
+
+	if (pos != 0)
+		return 0;
+
+	down(&bus->sdsem);
+	error = brcmf_sdio_readshared(bus, &sh);
+	if (error < 0)
+		goto done;
+
+	error = brcmf_sdio_assert_info(bus, &sh, data, count);
+	if (error < 0)
+		goto done;
+
+	nbytes = error;
+	error = brcmf_sdio_trap_info(bus, &sh, data, count);
+	if (error < 0)
+		goto done;
+
+	error += nbytes;
+	*ppos += error;
+done:
+	up(&bus->sdsem);
+	return error;
+}
+
+static ssize_t brcmf_sdio_forensic_read(struct file *f, char __user *data,
+					size_t count, loff_t *ppos)
+{
+	struct brcmf_sdio *bus = f->private_data;
+	int res;
+
+	res = brcmf_sdbrcm_died_dump(bus, data, count, ppos);
+	if (res > 0)
+		*ppos += res;
+	return (ssize_t)res;
+}
+
+static const struct file_operations brcmf_sdio_forensic_ops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = brcmf_sdio_forensic_read
+};
+
+static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
+{
+	struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr;
+	struct dentry *dentry = brcmf_debugfs_get_devdir(drvr);
+
+	if (IS_ERR_OR_NULL(dentry))
+		return;
+
+	debugfs_create_file("forensics", S_IRUGO, dentry, bus,
+			    &brcmf_sdio_forensic_ops);
+	brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt);
+}
+#else
+static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
+{
+	return 0;
+}
+
+static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
+{
+}
+#endif /* DEBUG */
+
 static int
 brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
 {
@@ -3009,17 +3319,19 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
 			  rxlen, msglen);
 	} else if (timeleft == 0) {
 		brcmf_dbg(ERROR, "resumed on timeout\n");
+		brcmf_sdbrcm_checkdied(bus);
 	} else if (pending) {
 		brcmf_dbg(CTL, "cancelled\n");
 		return -ERESTARTSYS;
 	} else {
 		brcmf_dbg(CTL, "resumed for unknown reason?\n");
+		brcmf_sdbrcm_checkdied(bus);
 	}
 
 	if (rxlen)
-		bus->rx_ctlpkts++;
+		bus->sdcnt.rx_ctlpkts++;
 	else
-		bus->rx_ctlerrs++;
+		bus->sdcnt.rx_ctlerrs++;
 
 	return rxlen ? (int)rxlen : -ETIMEDOUT;
 }
@@ -3327,7 +3639,7 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
 	len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus);
 
 	if (len > 0 && len < MEMBLOCK) {
-		bufp = (char *)memblock;
+		bufp = memblock;
 		bufp[len] = 0;
 		len = brcmf_process_nvram_vars(bufp, len);
 		bufp += len;
@@ -3419,7 +3731,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
 		return 0;
 
 	/* Start the watchdog timer */
-	bus->tickcnt = 0;
+	bus->sdcnt.tickcnt = 0;
 	brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
 
 	down(&bus->sdsem);
@@ -3512,7 +3824,7 @@ void brcmf_sdbrcm_isr(void *arg)
 		return;
 	}
 	/* Count the interrupt call */
-	bus->intrcount++;
+	bus->sdcnt.intrcount++;
 	bus->ipend = true;
 
 	/* Shouldn't get this interrupt if we're sleeping? */
@@ -3554,7 +3866,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
 		bus->polltick = 0;
 
 		/* Check device if no interrupts */
-		if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
+		if (!bus->intr ||
+		    (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) {
 
 			if (!bus->dpc_sched) {
 				u8 devpend;
@@ -3569,7 +3882,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
 			/* If there is something, make like the ISR and
 				 schedule the DPC */
 			if (intstatus) {
-				bus->pollcnt++;
+				bus->sdcnt.pollcnt++;
 				bus->ipend = true;
 
 				bus->dpc_sched = true;
@@ -3581,7 +3894,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
 		}
 
 		/* Update interrupt tracking */
-		bus->lastintrs = bus->intrcount;
+		bus->sdcnt.lastintrs = bus->sdcnt.intrcount;
 	}
 #ifdef DEBUG
 	/* Poll for console output periodically */
@@ -3793,7 +4106,7 @@ brcmf_sdbrcm_watchdog_thread(void *data)
 		if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
 			brcmf_sdbrcm_bus_watchdog(bus);
 			/* Count the tick for reference */
-			bus->tickcnt++;
+			bus->sdcnt.tickcnt++;
 		} else
 			break;
 	}
@@ -3938,6 +4251,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
 		goto fail;
 	}
 
+	brcmf_sdio_debugfs_create(bus);
 	brcmf_dbg(INFO, "completed!!\n");
 
 	/* if firmware path present try to download and bring up bus */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
index 6d8b721..3c6f9b1 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
@@ -631,9 +631,8 @@ uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val)
 	cc = sii->icbus->drv_cc.core;
 
 	/* mask and set */
-	if (mask || val) {
+	if (mask || val)
 		bcma_maskset32(cc, regoff, ~mask, val);
-	}
 
 	/* readback */
 	w = bcma_read32(cc, regoff);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
index d9f04a6..d6fa982 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
@@ -193,7 +193,7 @@ extern void ai_detach(struct si_pub *sih);
 extern uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val);
 extern void ai_clkctl_init(struct si_pub *sih);
 extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih);
-extern bool ai_clkctl_cc(struct si_pub *sih, uint mode);
+extern bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode);
 extern bool ai_deviceremoved(struct si_pub *sih);
 
 extern void ai_pci_down(struct si_pub *sih);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
index 95b5902..01b190a 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
@@ -735,10 +735,8 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
 		 * a candidate for aggregation
 		 */
 		p = pktq_ppeek(&qi->q, prec);
-		/* tx_info must be checked with current p */
-		tx_info = IEEE80211_SKB_CB(p);
-
 		if (p) {
+			tx_info = IEEE80211_SKB_CB(p);
 			if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
 			    ((u8) (p->priority) == tid)) {
 				plen = p->len + AMPDU_MAX_MPDU_OVERHEAD;
@@ -759,6 +757,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
 					p = NULL;
 					continue;
 				}
+				/* next packet fit for aggregation so dequeue */
 				p = brcmu_pktq_pdeq(&qi->q, prec);
 			} else {
 				p = NULL;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
index eb77ac3..2d365d3 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
@@ -15,7 +15,9 @@
  */
 
 #include <linux/types.h>
+#include <net/cfg80211.h>
 #include <net/mac80211.h>
+#include <net/regulatory.h>
 
 #include <defs.h>
 #include "pub.h"
@@ -23,73 +25,17 @@
 #include "main.h"
 #include "stf.h"
 #include "channel.h"
+#include "mac80211_if.h"
 
 /* QDB() macro takes a dB value and converts to a quarter dB value */
 #define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
 
-#define  LOCALE_CHAN_01_11	 (1<<0)
-#define  LOCALE_CHAN_12_13	 (1<<1)
-#define  LOCALE_CHAN_14		 (1<<2)
-#define  LOCALE_SET_5G_LOW_JP1   (1<<3)	/* 34-48, step 2 */
-#define  LOCALE_SET_5G_LOW_JP2   (1<<4)	/* 34-46, step 4 */
-#define  LOCALE_SET_5G_LOW1      (1<<5)	/* 36-48, step 4 */
-#define  LOCALE_SET_5G_LOW2      (1<<6)	/* 52 */
-#define  LOCALE_SET_5G_LOW3      (1<<7)	/* 56-64, step 4 */
-#define  LOCALE_SET_5G_MID1      (1<<8)	/* 100-116, step 4 */
-#define  LOCALE_SET_5G_MID2	 (1<<9)	/* 120-124, step 4 */
-#define  LOCALE_SET_5G_MID3      (1<<10)	/* 128 */
-#define  LOCALE_SET_5G_HIGH1     (1<<11)	/* 132-140, step 4 */
-#define  LOCALE_SET_5G_HIGH2     (1<<12)	/* 149-161, step 4 */
-#define  LOCALE_SET_5G_HIGH3     (1<<13)	/* 165 */
-#define  LOCALE_CHAN_52_140_ALL  (1<<14)
-#define  LOCALE_SET_5G_HIGH4     (1<<15)	/* 184-216 */
-
-#define  LOCALE_CHAN_36_64	(LOCALE_SET_5G_LOW1 | \
-				 LOCALE_SET_5G_LOW2 | \
-				 LOCALE_SET_5G_LOW3)
-#define  LOCALE_CHAN_52_64	(LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
-#define  LOCALE_CHAN_100_124	(LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2)
-#define  LOCALE_CHAN_100_140	(LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | \
-				  LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1)
-#define  LOCALE_CHAN_149_165	(LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3)
-#define  LOCALE_CHAN_184_216	LOCALE_SET_5G_HIGH4
-
-#define  LOCALE_CHAN_01_14	(LOCALE_CHAN_01_11 | \
-				 LOCALE_CHAN_12_13 | \
-				 LOCALE_CHAN_14)
-
-#define  LOCALE_RADAR_SET_NONE		  0
-#define  LOCALE_RADAR_SET_1		  1
-
-#define  LOCALE_RESTRICTED_NONE		  0
-#define  LOCALE_RESTRICTED_SET_2G_SHORT   1
-#define  LOCALE_RESTRICTED_CHAN_165       2
-#define  LOCALE_CHAN_ALL_5G		  3
-#define  LOCALE_RESTRICTED_JAPAN_LEGACY   4
-#define  LOCALE_RESTRICTED_11D_2G	  5
-#define  LOCALE_RESTRICTED_11D_5G	  6
-#define  LOCALE_RESTRICTED_LOW_HI	  7
-#define  LOCALE_RESTRICTED_12_13_14	  8
-
-#define LOCALE_2G_IDX_i			0
-#define LOCALE_5G_IDX_11		0
 #define LOCALE_MIMO_IDX_bn		0
 #define LOCALE_MIMO_IDX_11n		0
 
-/* max of BAND_5G_PWR_LVLS and 6 for 2.4 GHz */
-#define BRCMS_MAXPWR_TBL_SIZE		6
 /* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */
 #define BRCMS_MAXPWR_MIMO_TBL_SIZE	14
 
-/* power level in group of 2.4GHz band channels:
- * maxpwr[0] - CCK  channels [1]
- * maxpwr[1] - CCK  channels [2-10]
- * maxpwr[2] - CCK  channels [11-14]
- * maxpwr[3] - OFDM channels [1]
- * maxpwr[4] - OFDM channels [2-10]
- * maxpwr[5] - OFDM channels [11-14]
- */
-
 /* maxpwr mapping to 5GHz band channels:
  * maxpwr[0] - channels [34-48]
  * maxpwr[1] - channels [52-60]
@@ -101,16 +47,8 @@
 
 #define LC(id)	LOCALE_MIMO_IDX_ ## id
 
-#define LC_2G(id)	LOCALE_2G_IDX_ ## id
-
-#define LC_5G(id)	LOCALE_5G_IDX_ ## id
-
-#define LOCALES(band2, band5, mimo2, mimo5) \
-		{LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)}
-
-/* macro to get 2.4 GHz channel group index for tx power */
-#define CHANNEL_POWER_IDX_2G_CCK(c) (((c) < 2) ? 0 : (((c) < 11) ? 1 : 2))
-#define CHANNEL_POWER_IDX_2G_OFDM(c) (((c) < 2) ? 3 : (((c) < 11) ? 4 : 5))
+#define LOCALES(mimo2, mimo5) \
+		{LC(mimo2), LC(mimo5)}
 
 /* macro to get 5 GHz channel group index for tx power */
 #define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \
@@ -118,18 +56,37 @@
 				 (((c) < 100) ? 2 : \
 				 (((c) < 149) ? 3 : 4))))
 
-#define ISDFS_EU(fl)		(((fl) & BRCMS_DFS_EU) == BRCMS_DFS_EU)
-
-struct brcms_cm_band {
-	/* struct locale_info flags */
-	u8 locale_flags;
-	/* List of valid channels in the country */
-	struct brcms_chanvec valid_channels;
-	/* List of restricted use channels */
-	const struct brcms_chanvec *restricted_channels;
-	/* List of radar sensitive channels */
-	const struct brcms_chanvec *radar_channels;
-	u8 PAD[8];
+#define BRCM_2GHZ_2412_2462	REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
+#define BRCM_2GHZ_2467_2472	REG_RULE(2467-10, 2472+10, 20, 0, 19, \
+					 NL80211_RRF_PASSIVE_SCAN | \
+					 NL80211_RRF_NO_IBSS)
+
+#define BRCM_5GHZ_5180_5240	REG_RULE(5180-10, 5240+10, 40, 0, 21, \
+					 NL80211_RRF_PASSIVE_SCAN | \
+					 NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5260_5320	REG_RULE(5260-10, 5320+10, 40, 0, 21, \
+					 NL80211_RRF_PASSIVE_SCAN | \
+					 NL80211_RRF_DFS | \
+					 NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5500_5700	REG_RULE(5500-10, 5700+10, 40, 0, 21, \
+					 NL80211_RRF_PASSIVE_SCAN | \
+					 NL80211_RRF_DFS | \
+					 NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5745_5825	REG_RULE(5745-10, 5825+10, 40, 0, 21, \
+					 NL80211_RRF_PASSIVE_SCAN | \
+					 NL80211_RRF_NO_IBSS)
+
+static const struct ieee80211_regdomain brcms_regdom_x2 = {
+	.n_reg_rules = 7,
+	.alpha2 = "X2",
+	.reg_rules = {
+		BRCM_2GHZ_2412_2462,
+		BRCM_2GHZ_2467_2472,
+		BRCM_5GHZ_5180_5240,
+		BRCM_5GHZ_5260_5320,
+		BRCM_5GHZ_5500_5700,
+		BRCM_5GHZ_5745_5825,
+	}
 };
 
  /* locale per-channel tx power limits for MIMO frames
@@ -141,337 +98,23 @@ struct locale_mimo_info {
 	s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE];
 	/* tx 40 MHz power limits, qdBm units */
 	s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE];
-	u8 flags;
 };
 
 /* Country names and abbreviations with locale defined from ISO 3166 */
 struct country_info {
-	const u8 locale_2G;	/* 2.4G band locale */
-	const u8 locale_5G;	/* 5G band locale */
 	const u8 locale_mimo_2G;	/* 2.4G mimo info */
 	const u8 locale_mimo_5G;	/* 5G mimo info */
 };
 
+struct brcms_regd {
+	struct country_info country;
+	const struct ieee80211_regdomain *regdomain;
+};
+
 struct brcms_cm_info {
 	struct brcms_pub *pub;
 	struct brcms_c_info *wlc;
-	char srom_ccode[BRCM_CNTRY_BUF_SZ];	/* Country Code in SROM */
-	uint srom_regrev;	/* Regulatory Rev for the SROM ccode */
-	const struct country_info *country;	/* current country def */
-	char ccode[BRCM_CNTRY_BUF_SZ];	/* current internal Country Code */
-	uint regrev;		/* current Regulatory Revision */
-	char country_abbrev[BRCM_CNTRY_BUF_SZ];	/* current advertised ccode */
-	/* per-band state (one per phy/radio) */
-	struct brcms_cm_band bandstate[MAXBANDS];
-	/* quiet channels currently for radar sensitivity or 11h support */
-	/* channels on which we cannot transmit */
-	struct brcms_chanvec quiet_channels;
-};
-
-/* locale channel and power info. */
-struct locale_info {
-	u32 valid_channels;
-	/* List of radar sensitive channels */
-	u8 radar_channels;
-	/* List of channels used only if APs are detected */
-	u8 restricted_channels;
-	/* Max tx pwr in qdBm for each sub-band */
-	s8 maxpwr[BRCMS_MAXPWR_TBL_SIZE];
-	/* Country IE advertised max tx pwr in dBm per sub-band */
-	s8 pub_maxpwr[BAND_5G_PWR_LVLS];
-	u8 flags;
-};
-
-/* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */
-
-/*
- * Some common channel sets
- */
-
-/* No channels */
-static const struct brcms_chanvec chanvec_none = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-/* All 2.4 GHz HW channels */
-static const struct brcms_chanvec chanvec_all_2G = {
-	{0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-/* All 5 GHz HW channels */
-static const struct brcms_chanvec chanvec_all_5G = {
-	{0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x11, 0x11,
-	 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11,
-	 0x11, 0x11, 0x20, 0x22, 0x22, 0x00, 0x00, 0x11,
-	 0x11, 0x11, 0x11, 0x01}
-};
-
-/*
- * Radar channel sets
- */
-
-/* Channels 52 - 64, 100 - 140 */
-static const struct brcms_chanvec radar_set1 = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,  /* 52 - 60 */
-	 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11,  /* 64, 100 - 124 */
-	 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 128 - 140 */
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-/*
- * Restricted channel sets
- */
-
-/* Channels 34, 38, 42, 46 */
-static const struct brcms_chanvec restricted_set_japan_legacy = {
-	{0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 12, 13 */
-static const struct brcms_chanvec restricted_set_2g_short = {
-	{0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channel 165 */
-static const struct brcms_chanvec restricted_chan_165 = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 36 - 48 & 149 - 165 */
-static const struct brcms_chanvec restricted_low_hi = {
-	{0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x20, 0x22, 0x22, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 12 - 14 */
-static const struct brcms_chanvec restricted_set_12_13_14 = {
-	{0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-/* global memory to provide working buffer for expanded locale */
-
-static const struct brcms_chanvec *g_table_radar_set[] = {
-	&chanvec_none,
-	&radar_set1
-};
-
-static const struct brcms_chanvec *g_table_restricted_chan[] = {
-	&chanvec_none,		/* restricted_set_none */
-	&restricted_set_2g_short,
-	&restricted_chan_165,
-	&chanvec_all_5G,
-	&restricted_set_japan_legacy,
-	&chanvec_all_2G,	/* restricted_set_11d_2G */
-	&chanvec_all_5G,	/* restricted_set_11d_5G */
-	&restricted_low_hi,
-	&restricted_set_12_13_14
-};
-
-static const struct brcms_chanvec locale_2g_01_11 = {
-	{0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_2g_12_13 = {
-	{0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_2g_14 = {
-	{0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW_JP1 = {
-	{0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW_JP2 = {
-	{0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW1 = {
-	{0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW2 = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW3 = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
-	 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID1 = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID2 = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID3 = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH1 = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH2 = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH3 = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_52_140_ALL = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
-	 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
-	 0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH4 = {
-	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
-	 0x11, 0x11, 0x11, 0x11}
-};
-
-static const struct brcms_chanvec *g_table_locale_base[] = {
-	&locale_2g_01_11,
-	&locale_2g_12_13,
-	&locale_2g_14,
-	&locale_5g_LOW_JP1,
-	&locale_5g_LOW_JP2,
-	&locale_5g_LOW1,
-	&locale_5g_LOW2,
-	&locale_5g_LOW3,
-	&locale_5g_MID1,
-	&locale_5g_MID2,
-	&locale_5g_MID3,
-	&locale_5g_HIGH1,
-	&locale_5g_HIGH2,
-	&locale_5g_HIGH3,
-	&locale_5g_52_140_ALL,
-	&locale_5g_HIGH4
-};
-
-static void brcms_c_locale_add_channels(struct brcms_chanvec *target,
-				    const struct brcms_chanvec *channels)
-{
-	u8 i;
-	for (i = 0; i < sizeof(struct brcms_chanvec); i++)
-		target->vec[i] |= channels->vec[i];
-}
-
-static void brcms_c_locale_get_channels(const struct locale_info *locale,
-				    struct brcms_chanvec *channels)
-{
-	u8 i;
-
-	memset(channels, 0, sizeof(struct brcms_chanvec));
-
-	for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) {
-		if (locale->valid_channels & (1 << i))
-			brcms_c_locale_add_channels(channels,
-						g_table_locale_base[i]);
-	}
-}
-
-/*
- * Locale Definitions - 2.4 GHz
- */
-static const struct locale_info locale_i = {	/* locale i. channel 1 - 13 */
-	LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13,
-	LOCALE_RADAR_SET_NONE,
-	LOCALE_RESTRICTED_SET_2G_SHORT,
-	{QDB(19), QDB(19), QDB(19),
-	 QDB(19), QDB(19), QDB(19)},
-	{20, 20, 20, 0},
-	BRCMS_EIRP
-};
-
-/*
- * Locale Definitions - 5 GHz
- */
-static const struct locale_info locale_11 = {
-	/* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */
-	LOCALE_CHAN_36_64 | LOCALE_CHAN_100_140 | LOCALE_CHAN_149_165,
-	LOCALE_RADAR_SET_1,
-	LOCALE_RESTRICTED_NONE,
-	{QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)},
-	{23, 23, 23, 30, 30},
-	BRCMS_EIRP | BRCMS_DFS_EU
-};
-
-static const struct locale_info *g_locale_2g_table[] = {
-	&locale_i
-};
-
-static const struct locale_info *g_locale_5g_table[] = {
-	&locale_11
+	const struct brcms_regd *world_regd;
 };
 
 /*
@@ -484,7 +127,6 @@ static const struct locale_mimo_info locale_bn = {
 	{0, 0, QDB(13), QDB(13), QDB(13),
 	 QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
 	 QDB(13), 0, 0},
-	0
 };
 
 static const struct locale_mimo_info *g_mimo_2g_table[] = {
@@ -497,114 +139,20 @@ static const struct locale_mimo_info *g_mimo_2g_table[] = {
 static const struct locale_mimo_info locale_11n = {
 	{ /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)},
 	{QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)},
-	0
 };
 
 static const struct locale_mimo_info *g_mimo_5g_table[] = {
 	&locale_11n
 };
 
-static const struct {
-	char abbrev[BRCM_CNTRY_BUF_SZ];	/* country abbreviation */
-	struct country_info country;
-} cntry_locales[] = {
+static const struct brcms_regd cntry_locales[] = {
+	/* Worldwide RoW 2, must always be at index 0 */
 	{
-	"X2", LOCALES(i, 11, bn, 11n)},	/* Worldwide RoW 2 */
-};
-
-#ifdef SUPPORT_40MHZ
-/* 20MHz channel info for 40MHz pairing support */
-struct chan20_info {
-	u8 sb;
-	u8 adj_sbs;
+		.country = LOCALES(bn, 11n),
+		.regdomain = &brcms_regdom_x2,
+	},
 };
 
-/* indicates adjacent channels that are allowed for a 40 Mhz channel and
- * those that permitted by the HT
- */
-struct chan20_info chan20_info[] = {
-	/* 11b/11g */
-/* 0 */ {1, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 1 */ {2, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 2 */ {3, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 3 */ {4, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 4 */ {5, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 5 */ {6, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 6 */ {7, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 7 */ {8, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 8 */ {9, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 9 */ {10, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 10 */ {11, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 11 */ {12, (CH_LOWER_SB)},
-/* 12 */ {13, (CH_LOWER_SB)},
-/* 13 */ {14, (CH_LOWER_SB)},
-
-/* 11a japan high */
-/* 14 */ {34, (CH_UPPER_SB)},
-/* 15 */ {38, (CH_LOWER_SB)},
-/* 16 */ {42, (CH_LOWER_SB)},
-/* 17 */ {46, (CH_LOWER_SB)},
-
-/* 11a usa low */
-/* 18 */ {36, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 19 */ {40, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 20 */ {44, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 21 */ {48, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 22 */ {52, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 23 */ {56, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 24 */ {60, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 25 */ {64, (CH_LOWER_SB | CH_EWA_VALID)},
-
-/* 11a Europe */
-/* 26 */ {100, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 27 */ {104, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 28 */ {108, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 29 */ {112, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 30 */ {116, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 31 */ {120, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 32 */ {124, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 33 */ {128, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 34 */ {132, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 35 */ {136, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 36 */ {140, (CH_LOWER_SB)},
-
-/* 11a usa high, ref5 only */
-/* The 0x80 bit in pdiv means these are REF5, other entries are REF20 */
-/* 37 */ {149, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 38 */ {153, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 39 */ {157, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 40 */ {161, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 41 */ {165, (CH_LOWER_SB)},
-
-/* 11a japan */
-/* 42 */ {184, (CH_UPPER_SB)},
-/* 43 */ {188, (CH_LOWER_SB)},
-/* 44 */ {192, (CH_UPPER_SB)},
-/* 45 */ {196, (CH_LOWER_SB)},
-/* 46 */ {200, (CH_UPPER_SB)},
-/* 47 */ {204, (CH_LOWER_SB)},
-/* 48 */ {208, (CH_UPPER_SB)},
-/* 49 */ {212, (CH_LOWER_SB)},
-/* 50 */ {216, (CH_LOWER_SB)}
-};
-#endif				/* SUPPORT_40MHZ */
-
-static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx)
-{
-	if (locale_idx >= ARRAY_SIZE(g_locale_2g_table))
-		return NULL; /* error condition */
-
-	return g_locale_2g_table[locale_idx];
-}
-
-static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx)
-{
-	if (locale_idx >= ARRAY_SIZE(g_locale_5g_table))
-		return NULL; /* error condition */
-
-	return g_locale_5g_table[locale_idx];
-}
-
 static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx)
 {
 	if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table))
@@ -621,13 +169,6 @@ static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx)
 	return g_mimo_5g_table[locale_idx];
 }
 
-static int
-brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode,
-			  char *mapped_ccode, uint *mapped_regrev)
-{
-	return false;
-}
-
 /*
  * Indicates whether the country provided is valid to pass
  * to cfg80211 or not.
@@ -662,155 +203,24 @@ static bool brcms_c_country_valid(const char *ccode)
 	return true;
 }
 
-/* Lookup a country info structure from a null terminated country
- * abbreviation and regrev directly with no translation.
- */
-static const struct country_info *
-brcms_c_country_lookup_direct(const char *ccode, uint regrev)
+static const struct brcms_regd *brcms_world_regd(const char *regdom, int len)
 {
-	uint size, i;
-
-	/* Should just return 0 for single locale driver. */
-	/* Keep it this way in case we add more locales. (for now anyway) */
-
-	/*
-	 * all other country def arrays are for regrev == 0, so if
-	 * regrev is non-zero, fail
-	 */
-	if (regrev > 0)
-		return NULL;
-
-	/* find matched table entry from country code */
-	size = ARRAY_SIZE(cntry_locales);
-	for (i = 0; i < size; i++) {
-		if (strcmp(ccode, cntry_locales[i].abbrev) == 0)
-			return &cntry_locales[i].country;
-	}
-	return NULL;
-}
-
-static const struct country_info *
-brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm, const char *ccode,
-			char *mapped_ccode, uint *mapped_regrev)
-{
-	struct brcms_c_info *wlc = wlc_cm->wlc;
-	const struct country_info *country;
-	uint srom_regrev = wlc_cm->srom_regrev;
-	const char *srom_ccode = wlc_cm->srom_ccode;
-	int mapped;
-
-	/* check for currently supported ccode size */
-	if (strlen(ccode) > (BRCM_CNTRY_BUF_SZ - 1)) {
-		wiphy_err(wlc->wiphy, "wl%d: %s: ccode \"%s\" too long for "
-			  "match\n", wlc->pub->unit, __func__, ccode);
-		return NULL;
-	}
-
-	/* default mapping is the given ccode and regrev 0 */
-	strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
-	*mapped_regrev = 0;
-
-	/* If the desired country code matches the srom country code,
-	 * then the mapped country is the srom regulatory rev.
-	 * Otherwise look for an aggregate mapping.
-	 */
-	if (!strcmp(srom_ccode, ccode)) {
-		*mapped_regrev = srom_regrev;
-		mapped = 0;
-		wiphy_err(wlc->wiphy, "srom_code == ccode %s\n", __func__);
-	} else {
-		mapped =
-		    brcms_c_country_aggregate_map(wlc_cm, ccode, mapped_ccode,
-					      mapped_regrev);
-	}
-
-	/* find the matching built-in country definition */
-	country = brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
-
-	/* if there is not an exact rev match, default to rev zero */
-	if (country == NULL && *mapped_regrev != 0) {
-		*mapped_regrev = 0;
-		country =
-		    brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
-	}
-
-	return country;
-}
-
-/* Lookup a country info structure from a null terminated country code
- * The lookup is case sensitive.
- */
-static const struct country_info *
-brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode)
-{
-	const struct country_info *country;
-	char mapped_ccode[BRCM_CNTRY_BUF_SZ];
-	uint mapped_regrev;
-
-	/*
-	 * map the country code to a built-in country code, regrev, and
-	 * country_info struct
-	 */
-	country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode,
-					  &mapped_regrev);
-
-	return country;
-}
-
-/*
- * reset the quiet channels vector to the union
- * of the restricted and radar channel sets
- */
-static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm)
-{
-	struct brcms_c_info *wlc = wlc_cm->wlc;
-	uint i, j;
-	struct brcms_band *band;
-	const struct brcms_chanvec *chanvec;
-
-	memset(&wlc_cm->quiet_channels, 0, sizeof(struct brcms_chanvec));
-
-	band = wlc->band;
-	for (i = 0; i < wlc->pub->_nbands;
-	     i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
-
-		/* initialize quiet channels for restricted channels */
-		chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels;
-		for (j = 0; j < sizeof(struct brcms_chanvec); j++)
-			wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j];
+	const struct brcms_regd *regd = NULL;
+	int i;
 
+	for (i = 0; i < ARRAY_SIZE(cntry_locales); i++) {
+		if (!strncmp(regdom, cntry_locales[i].regdomain->alpha2, len)) {
+			regd = &cntry_locales[i];
+			break;
+		}
 	}
-}
-
-/* Is the channel valid for the current locale and current band? */
-static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val)
-{
-	struct brcms_c_info *wlc = wlc_cm->wlc;
 
-	return ((val < MAXCHANNEL) &&
-		isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec,
-		      val));
+	return regd;
 }
 
-/* Is the channel valid for the current locale and specified band? */
-static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm,
-					    uint bandunit, uint val)
-{
-	return ((val < MAXCHANNEL)
-		&& isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val));
-}
-
-/* Is the channel valid for the current locale? (but don't consider channels not
- *   available due to bandlocking)
- */
-static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val)
+static const struct brcms_regd *brcms_default_world_regd(void)
 {
-	struct brcms_c_info *wlc = wlc_cm->wlc;
-
-	return brcms_c_valid_channel20(wlc->cmi, val) ||
-		(!wlc->bandlocked
-		 && brcms_c_valid_channel20_in_band(wlc->cmi,
-						    OTHERBANDUNIT(wlc), val));
+	return &cntry_locales[0];
 }
 
 /* JP, J1 - J10 are Japan ccodes */
@@ -820,12 +230,6 @@ static bool brcms_c_japan_ccode(const char *ccode)
 		(ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
 }
 
-/* Returns true if currently set country is Japan or variant */
-static bool brcms_c_japan(struct brcms_c_info *wlc)
-{
-	return brcms_c_japan_ccode(wlc->cmi->country_abbrev);
-}
-
 static void
 brcms_c_channel_min_txpower_limits_with_local_constraint(
 		struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,
@@ -901,140 +305,16 @@ brcms_c_channel_min_txpower_limits_with_local_constraint(
 
 }
 
-/* Update the radio state (enable/disable) and tx power targets
- * based on a new set of channel/regulatory information
- */
-static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm)
-{
-	struct brcms_c_info *wlc = wlc_cm->wlc;
-	uint chan;
-	struct txpwr_limits txpwr;
-
-	/* search for the existence of any valid channel */
-	for (chan = 0; chan < MAXCHANNEL; chan++) {
-		if (brcms_c_valid_channel20_db(wlc->cmi, chan))
-			break;
-	}
-	if (chan == MAXCHANNEL)
-		chan = INVCHANNEL;
-
-	/*
-	 * based on the channel search above, set or
-	 * clear WL_RADIO_COUNTRY_DISABLE.
-	 */
-	if (chan == INVCHANNEL) {
-		/*
-		 * country/locale with no valid channels, set
-		 * the radio disable bit
-		 */
-		mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
-		wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" "
-			  "nbands %d bandlocked %d\n", wlc->pub->unit,
-			  __func__, wlc_cm->country_abbrev, wlc->pub->_nbands,
-			  wlc->bandlocked);
-	} else if (mboolisset(wlc->pub->radio_disabled,
-			      WL_RADIO_COUNTRY_DISABLE)) {
-		/*
-		 * country/locale with valid channel, clear
-		 * the radio disable bit
-		 */
-		mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
-	}
-
-	/*
-	 * Now that the country abbreviation is set, if the radio supports 2G,
-	 * then set channel 14 restrictions based on the new locale.
-	 */
-	if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
-		wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
-						     brcms_c_japan(wlc) ? true :
-						     false);
-
-	if (wlc->pub->up && chan != INVCHANNEL) {
-		brcms_c_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr);
-		brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm,
-			&txpwr, BRCMS_TXPWR_MAX);
-		wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec);
-	}
-}
-
-static int
-brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
-		      const struct country_info *country)
-{
-	struct brcms_c_info *wlc = wlc_cm->wlc;
-	uint i, j;
-	struct brcms_band *band;
-	const struct locale_info *li;
-	struct brcms_chanvec sup_chan;
-	const struct locale_mimo_info *li_mimo;
-
-	band = wlc->band;
-	for (i = 0; i < wlc->pub->_nbands;
-	     i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
-
-		li = (band->bandtype == BRCM_BAND_5G) ?
-		    brcms_c_get_locale_5g(country->locale_5G) :
-		    brcms_c_get_locale_2g(country->locale_2G);
-		wlc_cm->bandstate[band->bandunit].locale_flags = li->flags;
-		li_mimo = (band->bandtype == BRCM_BAND_5G) ?
-		    brcms_c_get_mimo_5g(country->locale_mimo_5G) :
-		    brcms_c_get_mimo_2g(country->locale_mimo_2G);
-
-		/* merge the mimo non-mimo locale flags */
-		wlc_cm->bandstate[band->bandunit].locale_flags |=
-		    li_mimo->flags;
-
-		wlc_cm->bandstate[band->bandunit].restricted_channels =
-		    g_table_restricted_chan[li->restricted_channels];
-		wlc_cm->bandstate[band->bandunit].radar_channels =
-		    g_table_radar_set[li->radar_channels];
-
-		/*
-		 * set the channel availability, masking out the channels
-		 * that may not be supported on this phy.
-		 */
-		wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
-					      &sup_chan);
-		brcms_c_locale_get_channels(li,
-					&wlc_cm->bandstate[band->bandunit].
-					valid_channels);
-		for (j = 0; j < sizeof(struct brcms_chanvec); j++)
-			wlc_cm->bandstate[band->bandunit].valid_channels.
-			    vec[j] &= sup_chan.vec[j];
-	}
-
-	brcms_c_quiet_channels_reset(wlc_cm);
-	brcms_c_channels_commit(wlc_cm);
-
-	return 0;
-}
-
 /*
  * set the driver's current country and regulatory information
  * using a country code as the source. Look up built in country
  * information found with the country code.
  */
 static void
-brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
-		       const char *country_abbrev,
-		       const char *ccode, uint regrev,
-		       const struct country_info *country)
+brcms_c_set_country(struct brcms_cm_info *wlc_cm,
+		    const struct brcms_regd *regd)
 {
-	const struct locale_info *locale;
 	struct brcms_c_info *wlc = wlc_cm->wlc;
-	char prev_country_abbrev[BRCM_CNTRY_BUF_SZ];
-
-	/* save current country state */
-	wlc_cm->country = country;
-
-	memset(&prev_country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
-	strncpy(prev_country_abbrev, wlc_cm->country_abbrev,
-		BRCM_CNTRY_BUF_SZ - 1);
-
-	strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
-	strncpy(wlc_cm->ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
-	wlc_cm->regrev = regrev;
 
 	if ((wlc->pub->_n_enab & SUPPORT_11N) !=
 	    wlc->protection->nmode_user)
@@ -1042,75 +322,19 @@ brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
 
 	brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
 	brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
-	/* set or restore gmode as required by regulatory */
-	locale = brcms_c_get_locale_2g(country->locale_2G);
-	if (locale && (locale->flags & BRCMS_NO_OFDM))
-		brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
-	else
-		brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
 
-	brcms_c_channels_init(wlc_cm, country);
+	brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
 
 	return;
 }
 
-static int
-brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm,
-			const char *country_abbrev,
-			const char *ccode, int regrev)
-{
-	const struct country_info *country;
-	char mapped_ccode[BRCM_CNTRY_BUF_SZ];
-	uint mapped_regrev;
-
-	/* if regrev is -1, lookup the mapped country code,
-	 * otherwise use the ccode and regrev directly
-	 */
-	if (regrev == -1) {
-		/*
-		 * map the country code to a built-in country
-		 * code, regrev, and country_info
-		 */
-		country =
-		    brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode,
-					&mapped_regrev);
-	} else {
-		/* find the matching built-in country definition */
-		country = brcms_c_country_lookup_direct(ccode, regrev);
-		strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
-		mapped_regrev = regrev;
-	}
-
-	if (country == NULL)
-		return -EINVAL;
-
-	/* set the driver state for the country */
-	brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode,
-			       mapped_regrev, country);
-
-	return 0;
-}
-
-/*
- * set the driver's current country and regulatory information using
- * a country code as the source. Lookup built in country information
- * found with the country code.
- */
-static int
-brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode)
-{
-	char country_abbrev[BRCM_CNTRY_BUF_SZ];
-	strncpy(country_abbrev, ccode, BRCM_CNTRY_BUF_SZ);
-	return brcms_c_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1);
-}
-
 struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
 {
 	struct brcms_cm_info *wlc_cm;
-	char country_abbrev[BRCM_CNTRY_BUF_SZ];
-	const struct country_info *country;
 	struct brcms_pub *pub = wlc->pub;
 	struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
+	const char *ccode = sprom->alpha2;
+	int ccode_len = sizeof(sprom->alpha2);
 
 	BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
 
@@ -1122,24 +346,27 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
 	wlc->cmi = wlc_cm;
 
 	/* store the country code for passing up as a regulatory hint */
-	if (sprom->alpha2 && brcms_c_country_valid(sprom->alpha2))
-		strncpy(wlc->pub->srom_ccode, sprom->alpha2, sizeof(sprom->alpha2));
+	wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len);
+	if (brcms_c_country_valid(ccode))
+		strncpy(wlc->pub->srom_ccode, ccode, ccode_len);
 
 	/*
-	 * internal country information which must match
-	 * regulatory constraints in firmware
+	 * If no custom world domain is found in the SROM, use the
+	 * default "X2" domain.
 	 */
-	memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
-	strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1);
-	country = brcms_c_country_lookup(wlc, country_abbrev);
+	if (!wlc_cm->world_regd) {
+		wlc_cm->world_regd = brcms_default_world_regd();
+		ccode = wlc_cm->world_regd->regdomain->alpha2;
+		ccode_len = BRCM_CNTRY_BUF_SZ - 1;
+	}
 
 	/* save default country for exiting 11d regulatory mode */
-	strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
+	strncpy(wlc->country_default, ccode, ccode_len);
 
 	/* initialize autocountry_default to driver default */
-	strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1);
+	strncpy(wlc->autocountry_default, ccode, ccode_len);
 
-	brcms_c_set_countrycode(wlc_cm, country_abbrev);
+	brcms_c_set_country(wlc_cm, wlc_cm->world_regd);
 
 	return wlc_cm;
 }
@@ -1149,31 +376,15 @@ void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)
 	kfree(wlc_cm);
 }
 
-u8
-brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
-				     uint bandunit)
-{
-	return wlc_cm->bandstate[bandunit].locale_flags;
-}
-
-static bool
-brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, u16 chspec)
-{
-	return (wlc_cm->wlc->pub->_n_enab & SUPPORT_11N) &&
-		CHSPEC_IS40(chspec) ?
-		(isset(wlc_cm->quiet_channels.vec,
-		       lower_20_sb(CHSPEC_CHANNEL(chspec))) ||
-		 isset(wlc_cm->quiet_channels.vec,
-		       upper_20_sb(CHSPEC_CHANNEL(chspec)))) :
-		isset(wlc_cm->quiet_channels.vec, CHSPEC_CHANNEL(chspec));
-}
-
 void
 brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
 			 u8 local_constraint_qdbm)
 {
 	struct brcms_c_info *wlc = wlc_cm->wlc;
+	struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
+	const struct ieee80211_reg_rule *reg_rule;
 	struct txpwr_limits txpwr;
+	int ret;
 
 	brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
 
@@ -1181,8 +392,15 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
 		wlc_cm, &txpwr, local_constraint_qdbm
 	);
 
+	/* set or restore gmode as required by regulatory */
+	ret = freq_reg_info(wlc->wiphy, ch->center_freq, 0, &reg_rule);
+	if (!ret && (reg_rule->flags & NL80211_RRF_NO_OFDM))
+		brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
+	else
+		brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
+
 	brcms_b_set_chanspec(wlc->hw, chanspec,
-			      (brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0),
+			      !!(ch->flags & IEEE80211_CHAN_PASSIVE_SCAN),
 			      &txpwr);
 }
 
@@ -1191,15 +409,14 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
 		       struct txpwr_limits *txpwr)
 {
 	struct brcms_c_info *wlc = wlc_cm->wlc;
+	struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
 	uint i;
 	uint chan;
 	int maxpwr;
 	int delta;
 	const struct country_info *country;
 	struct brcms_band *band;
-	const struct locale_info *li;
 	int conducted_max = BRCMS_TXPWR_MAX;
-	int conducted_ofdm_max = BRCMS_TXPWR_MAX;
 	const struct locale_mimo_info *li_mimo;
 	int maxpwr20, maxpwr40;
 	int maxpwr_idx;
@@ -1207,67 +424,35 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
 
 	memset(txpwr, 0, sizeof(struct txpwr_limits));
 
-	if (!brcms_c_valid_chanspec_db(wlc_cm, chanspec)) {
-		country = brcms_c_country_lookup(wlc, wlc->autocountry_default);
-		if (country == NULL)
-			return;
-	} else {
-		country = wlc_cm->country;
-	}
+	if (WARN_ON(!ch))
+		return;
+
+	country = &wlc_cm->world_regd->country;
 
 	chan = CHSPEC_CHANNEL(chanspec);
 	band = wlc->bandstate[chspec_bandunit(chanspec)];
-	li = (band->bandtype == BRCM_BAND_5G) ?
-	    brcms_c_get_locale_5g(country->locale_5G) :
-	    brcms_c_get_locale_2g(country->locale_2G);
-
 	li_mimo = (band->bandtype == BRCM_BAND_5G) ?
 	    brcms_c_get_mimo_5g(country->locale_mimo_5G) :
 	    brcms_c_get_mimo_2g(country->locale_mimo_2G);
 
-	if (li->flags & BRCMS_EIRP) {
-		delta = band->antgain;
-	} else {
-		delta = 0;
-		if (band->antgain > QDB(6))
-			delta = band->antgain - QDB(6);	/* Excess over 6 dB */
-	}
+	delta = band->antgain;
 
-	if (li == &locale_i) {
+	if (band->bandtype == BRCM_BAND_2G)
 		conducted_max = QDB(22);
-		conducted_ofdm_max = QDB(22);
-	}
+
+	maxpwr = QDB(ch->max_power) - delta;
+	maxpwr = max(maxpwr, 0);
+	maxpwr = min(maxpwr, conducted_max);
 
 	/* CCK txpwr limits for 2.4G band */
 	if (band->bandtype == BRCM_BAND_2G) {
-		maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)];
-
-		maxpwr = maxpwr - delta;
-		maxpwr = max(maxpwr, 0);
-		maxpwr = min(maxpwr, conducted_max);
-
 		for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
 			txpwr->cck[i] = (u8) maxpwr;
 	}
 
-	/* OFDM txpwr limits for 2.4G or 5G bands */
-	if (band->bandtype == BRCM_BAND_2G)
-		maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)];
-	else
-		maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)];
-
-	maxpwr = maxpwr - delta;
-	maxpwr = max(maxpwr, 0);
-	maxpwr = min(maxpwr, conducted_ofdm_max);
-
-	/* Keep OFDM lmit below CCK limit */
-	if (band->bandtype == BRCM_BAND_2G)
-		maxpwr = min_t(int, maxpwr, txpwr->cck[0]);
-
-	for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
+	for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
 		txpwr->ofdm[i] = (u8) maxpwr;
 
-	for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
 		/*
 		 * OFDM 40 MHz SISO has the same power as the corresponding
 		 * MCS0-7 rate unless overriden by the locale specific code.
@@ -1282,14 +467,9 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
 		txpwr->ofdm_40_cdd[i] = 0;
 	}
 
-	/* MIMO/HT specific limits */
-	if (li_mimo->flags & BRCMS_EIRP) {
-		delta = band->antgain;
-	} else {
-		delta = 0;
-		if (band->antgain > QDB(6))
-			delta = band->antgain - QDB(6);	/* Excess over 6 dB */
-	}
+	delta = 0;
+	if (band->antgain > QDB(6))
+		delta = band->antgain - QDB(6);	/* Excess over 6 dB */
 
 	if (band->bandtype == BRCM_BAND_2G)
 		maxpwr_idx = (chan - 1);
@@ -1431,8 +611,7 @@ static bool brcms_c_chspec_malformed(u16 chanspec)
  * and they are also a legal HT combination
  */
 static bool
-brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec,
-			   bool dualband)
+brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec)
 {
 	struct brcms_c_info *wlc = wlc_cm->wlc;
 	u8 channel = CHSPEC_CHANNEL(chspec);
@@ -1448,59 +627,166 @@ brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec,
 	    chspec_bandunit(chspec))
 		return false;
 
-	/* Check a 20Mhz channel */
-	if (CHSPEC_IS20(chspec)) {
-		if (dualband)
-			return brcms_c_valid_channel20_db(wlc_cm->wlc->cmi,
-							  channel);
-		else
-			return brcms_c_valid_channel20(wlc_cm->wlc->cmi,
-						       channel);
+	return true;
+}
+
+bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
+{
+	return brcms_c_valid_chanspec_ext(wlc_cm, chspec);
+}
+
+static bool brcms_is_radar_freq(u16 center_freq)
+{
+	return center_freq >= 5260 && center_freq <= 5700;
+}
+
+static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)
+{
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *ch;
+	int i;
+
+	sband = wiphy->bands[IEEE80211_BAND_5GHZ];
+	if (!sband)
+		return;
+
+	for (i = 0; i < sband->n_channels; i++) {
+		ch = &sband->channels[i];
+
+		if (!brcms_is_radar_freq(ch->center_freq))
+			continue;
+
+		/*
+		 * All channels in this range should be passive and have
+		 * DFS enabled.
+		 */
+		if (!(ch->flags & IEEE80211_CHAN_DISABLED))
+			ch->flags |= IEEE80211_CHAN_RADAR |
+				     IEEE80211_CHAN_NO_IBSS |
+				     IEEE80211_CHAN_PASSIVE_SCAN;
 	}
-#ifdef SUPPORT_40MHZ
-	/*
-	 * We know we are now checking a 40MHZ channel, so we should
-	 * only be here for NPHYS
-	 */
-	if (BRCMS_ISNPHY(wlc->band) || BRCMS_ISSSLPNPHY(wlc->band)) {
-		u8 upper_sideband = 0, idx;
-		u8 num_ch20_entries =
-		    sizeof(chan20_info) / sizeof(struct chan20_info);
-
-		if (!VALID_40CHANSPEC_IN_BAND(wlc, chspec_bandunit(chspec)))
-			return false;
-
-		if (dualband) {
-			if (!brcms_c_valid_channel20_db(wlc->cmi,
-							lower_20_sb(channel)) ||
-			    !brcms_c_valid_channel20_db(wlc->cmi,
-							upper_20_sb(channel)))
-				return false;
-		} else {
-			if (!brcms_c_valid_channel20(wlc->cmi,
-						     lower_20_sb(channel)) ||
-			    !brcms_c_valid_channel20(wlc->cmi,
-						     upper_20_sb(channel)))
-				return false;
+}
+
+static void
+brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
+				enum nl80211_reg_initiator initiator)
+{
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *ch;
+	const struct ieee80211_reg_rule *rule;
+	int band, i, ret;
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		sband = wiphy->bands[band];
+		if (!sband)
+			continue;
+
+		for (i = 0; i < sband->n_channels; i++) {
+			ch = &sband->channels[i];
+
+			if (ch->flags &
+			    (IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR))
+				continue;
+
+			if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+				ret = freq_reg_info(wiphy, ch->center_freq,
+						    0, &rule);
+				if (ret)
+					continue;
+
+				if (!(rule->flags & NL80211_RRF_NO_IBSS))
+					ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
+				if (!(rule->flags & NL80211_RRF_PASSIVE_SCAN))
+					ch->flags &=
+						~IEEE80211_CHAN_PASSIVE_SCAN;
+			} else if (ch->beacon_found) {
+				ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
+					       IEEE80211_CHAN_PASSIVE_SCAN);
+			}
 		}
+	}
+}
 
-		/* find the lower sideband info in the sideband array */
-		for (idx = 0; idx < num_ch20_entries; idx++) {
-			if (chan20_info[idx].sb == lower_20_sb(channel))
-				upper_sideband = chan20_info[idx].adj_sbs;
+static int brcms_reg_notifier(struct wiphy *wiphy,
+			      struct regulatory_request *request)
+{
+	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+	struct brcms_info *wl = hw->priv;
+	struct brcms_c_info *wlc = wl->wlc;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *ch;
+	int band, i;
+	bool ch_found = false;
+
+	brcms_reg_apply_radar_flags(wiphy);
+
+	if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
+		brcms_reg_apply_beaconing_flags(wiphy, request->initiator);
+
+	/* Disable radio if all channels disallowed by regulatory */
+	for (band = 0; !ch_found && band < IEEE80211_NUM_BANDS; band++) {
+		sband = wiphy->bands[band];
+		if (!sband)
+			continue;
+
+		for (i = 0; !ch_found && i < sband->n_channels; i++) {
+			ch = &sband->channels[i];
+
+			if (!(ch->flags & IEEE80211_CHAN_DISABLED))
+				ch_found = true;
 		}
-		/* check that the lower sideband allows an upper sideband */
-		if ((upper_sideband & (CH_UPPER_SB | CH_EWA_VALID)) ==
-		    (CH_UPPER_SB | CH_EWA_VALID))
-			return true;
-		return false;
 	}
-#endif				/* 40 MHZ */
 
-	return false;
+	if (ch_found) {
+		mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
+	} else {
+		mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
+		wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\"\n",
+			  wlc->pub->unit, __func__, request->alpha2);
+	}
+
+	if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
+		wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
+					brcms_c_japan_ccode(request->alpha2));
+
+	return 0;
 }
 
-bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
+void brcms_c_regd_init(struct brcms_c_info *wlc)
 {
-	return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true);
+	struct wiphy *wiphy = wlc->wiphy;
+	const struct brcms_regd *regd = wlc->cmi->world_regd;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *ch;
+	struct brcms_chanvec sup_chan;
+	struct brcms_band *band;
+	int band_idx, i;
+
+	/* Disable any channels not supported by the phy */
+	for (band_idx = 0; band_idx < IEEE80211_NUM_BANDS; band_idx++) {
+		if (band_idx == IEEE80211_BAND_2GHZ)
+			band = wlc->bandstate[BAND_2G_INDEX];
+		else
+			band = wlc->bandstate[BAND_5G_INDEX];
+
+		/* skip if band not initialized */
+		if (band->pi == NULL)
+			continue;
+
+		wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
+					      &sup_chan);
+
+		sband = wiphy->bands[band_idx];
+		for (i = 0; i < sband->n_channels; i++) {
+			ch = &sband->channels[i];
+			if (!isset(sup_chan.vec, ch->hw_value))
+				ch->flags |= IEEE80211_CHAN_DISABLED;
+		}
+	}
+
+	wlc->wiphy->reg_notifier = brcms_reg_notifier;
+	wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
+			     WIPHY_FLAG_STRICT_REGULATORY;
+	wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);
+	brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER);
 }
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.h b/drivers/net/wireless/brcm80211/brcmsmac/channel.h
index 808cb4f..006483a 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.h
@@ -37,9 +37,6 @@ brcms_c_channel_mgr_attach(struct brcms_c_info *wlc);
 
 extern void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm);
 
-extern u8 brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
-					   uint bandunit);
-
 extern bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm,
 				      u16 chspec);
 
@@ -49,5 +46,6 @@ extern void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm,
 extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm,
 				     u16 chanspec,
 				     u8 local_constraint_qdbm);
+extern void brcms_c_regd_init(struct brcms_c_info *wlc);
 
 #endif				/* _WLC_CHANNEL_H */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
index 11054ae..7516639 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
@@ -1433,7 +1433,7 @@ void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc)
 	struct ieee80211_tx_info *tx_info;
 
 	while (i != end) {
-		skb = (struct sk_buff *)di->txp[i];
+		skb = di->txp[i];
 		if (skb != NULL) {
 			tx_info = (struct ieee80211_tx_info *)skb->cb;
 			(callback_fnc)(tx_info, arg_a);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 50f92a0..2d5a404 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -721,14 +721,6 @@ static const struct ieee80211_ops brcms_ops = {
 	.flush = brcms_ops_flush,
 };
 
-/*
- * is called in brcms_bcma_probe() context, therefore no locking required.
- */
-static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
-{
-	return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
-}
-
 void brcms_dpc(unsigned long data)
 {
 	struct brcms_info *wl;
@@ -1058,6 +1050,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
 		goto fail;
 	}
 
+	brcms_c_regd_init(wl->wlc);
+
 	memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN);
 	if (WARN_ON(!is_valid_ether_addr(perm)))
 		goto fail;
@@ -1068,9 +1062,9 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
 		wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status"
 			  "%d\n", __func__, err);
 
-	if (wl->pub->srom_ccode[0] && brcms_set_hint(wl, wl->pub->srom_ccode))
-		wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
-			  __func__, err);
+	if (wl->pub->srom_ccode[0] &&
+	    regulatory_hint(wl->wiphy, wl->pub->srom_ccode))
+		wiphy_err(wl->wiphy, "%s: regulatory hint failed\n", __func__);
 
 	n_adapters_found++;
 	return wl;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 19db405..bb00b65 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -18,6 +18,7 @@
 
 #include <linux/pci_ids.h>
 #include <linux/if_ether.h>
+#include <net/cfg80211.h>
 #include <net/mac80211.h>
 #include <brcm_hw_ids.h>
 #include <aiutils.h>
@@ -3139,20 +3140,6 @@ void brcms_c_reset(struct brcms_c_info *wlc)
 	brcms_b_reset(wlc->hw);
 }
 
-/* Return the channel the driver should initialize during brcms_c_init.
- * the channel may have to be changed from the currently configured channel
- * if other configurations are in conflict (bandlocked, 11n mode disabled,
- * invalid channel for current country, etc.)
- */
-static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc)
-{
-	u16 chanspec =
-	    1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE |
-	    WL_CHANSPEC_BAND_2G;
-
-	return chanspec;
-}
-
 void brcms_c_init_scb(struct scb *scb)
 {
 	int i;
@@ -5129,6 +5116,8 @@ static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
 /* make interface operational */
 int brcms_c_up(struct brcms_c_info *wlc)
 {
+	struct ieee80211_channel *ch;
+
 	BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
 
 	/* HW is turned off so don't try to access it */
@@ -5195,8 +5184,9 @@ int brcms_c_up(struct brcms_c_info *wlc)
 	wlc->pub->up = true;
 
 	if (wlc->bandinit_pending) {
+		ch = wlc->pub->ieee_hw->conf.channel;
 		brcms_c_suspend_mac_and_wait(wlc);
-		brcms_c_set_chanspec(wlc, wlc->default_bss->chanspec);
+		brcms_c_set_chanspec(wlc, ch20mhz_chspec(ch->hw_value));
 		wlc->bandinit_pending = false;
 		brcms_c_enable_mac(wlc);
 	}
@@ -5397,11 +5387,6 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
 	else
 		return -EINVAL;
 
-	/* Legacy or bust when no OFDM is supported by regulatory */
-	if ((brcms_c_channel_locale_flags_in_band(wlc->cmi, band->bandunit) &
-	     BRCMS_NO_OFDM) && (gmode != GMODE_LEGACY_B))
-		return -EINVAL;
-
 	/* update configuration value */
 	if (config)
 		brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode);
@@ -8201,19 +8186,12 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
 void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
 {
 	struct bcma_device *core = wlc->hw->d11core;
+	struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
 	u16 chanspec;
 
 	BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
 
-	/*
-	 * This will happen if a big-hammer was executed. In
-	 * that case, we want to go back to the channel that
-	 * we were on and not new channel
-	 */
-	if (wlc->pub->associated)
-		chanspec = wlc->home_chanspec;
-	else
-		chanspec = brcms_c_init_chanspec(wlc);
+	chanspec = ch20mhz_chspec(ch->hw_value);
 
 	brcms_b_init(wlc->hw, chanspec);
 
@@ -8318,7 +8296,7 @@ brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit,
 	struct brcms_pub *pub;
 
 	/* allocate struct brcms_c_info state and its substructures */
-	wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, 0);
+	wlc = brcms_c_attach_malloc(unit, &err, 0);
 	if (wlc == NULL)
 		goto fail;
 	wlc->wiphy = wl->wiphy;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
index 13b2615..3667181 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
@@ -14358,7 +14358,7 @@ void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs)
 
 	wlc_phy_write_txmacreg_nphy(pi, holdoff, delay);
 
-	if (pi && pi->sh && (pi->sh->_rifs_phy != rifs))
+	if (pi->sh && (pi->sh->_rifs_phy != rifs))
 		pi->sh->_rifs_phy = rifs;
 }
 
diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c
index b45ab34..3e6405e 100644
--- a/drivers/net/wireless/brcm80211/brcmutil/utils.c
+++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c
@@ -43,6 +43,8 @@ EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);
 /* Free the driver packet. Free the tag if present */
 void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
 {
+	if (!skb)
+		return;
 	WARN_ON(skb->next);
 	if (skb->destructor)
 		/* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
index 75ef8f0..dc447c1 100644
--- a/drivers/net/wireless/hostap/hostap_proc.c
+++ b/drivers/net/wireless/hostap/hostap_proc.c
@@ -58,8 +58,7 @@ static int prism2_stats_proc_read(char *page, char **start, off_t off,
 {
 	char *p = page;
 	local_info_t *local = (local_info_t *) data;
-	struct comm_tallies_sums *sums = (struct comm_tallies_sums *)
-		&local->comm_tallies;
+	struct comm_tallies_sums *sums = &local->comm_tallies;
 
 	if (off != 0) {
 		*eof = 1;
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 0036737..0df4591 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -2701,6 +2701,20 @@ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
 	memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6);
 }
 
+static void ipw_read_eeprom(struct ipw_priv *priv)
+{
+	int i;
+	__le16 *eeprom = (__le16 *) priv->eeprom;
+
+	IPW_DEBUG_TRACE(">>\n");
+
+	/* read entire contents of eeprom into private buffer */
+	for (i = 0; i < 128; i++)
+		eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
+
+	IPW_DEBUG_TRACE("<<\n");
+}
+
 /*
  * Either the device driver (i.e. the host) or the firmware can
  * load eeprom data into the designated region in SRAM.  If neither
@@ -2712,14 +2726,9 @@ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
 static void ipw_eeprom_init_sram(struct ipw_priv *priv)
 {
 	int i;
-	__le16 *eeprom = (__le16 *) priv->eeprom;
 
 	IPW_DEBUG_TRACE(">>\n");
 
-	/* read entire contents of eeprom into private buffer */
-	for (i = 0; i < 128; i++)
-		eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
-
 	/*
 	   If the data looks correct, then copy it to our private
 	   copy.  Otherwise let the firmware know to perform the operation
@@ -3643,8 +3652,10 @@ static int ipw_load(struct ipw_priv *priv)
 	/* ack fw init done interrupt */
 	ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
 
-	/* read eeprom data and initialize the eeprom region of sram */
+	/* read eeprom data */
 	priv->eeprom_delay = 1;
+	ipw_read_eeprom(priv);
+	/* initialize the eeprom region of sram */
 	ipw_eeprom_init_sram(priv);
 
 	/* enable interrupts */
@@ -7069,9 +7080,7 @@ static int ipw_qos_activate(struct ipw_priv *priv,
 	}
 
 	IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n");
-	err = ipw_send_qos_params_command(priv,
-					  (struct libipw_qos_parameters *)
-					  &(qos_parameters[0]));
+	err = ipw_send_qos_params_command(priv, &qos_parameters[0]);
 	if (err)
 		IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n");
 
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 509301a..d24eaf8 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -5724,7 +5724,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
 	    BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
 
 	hw->wiphy->flags |=
-	    WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS;
+	    WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
+	    WIPHY_FLAG_IBSS_RSN;
 
 	/*
 	 * For now, disable PS by default because it affects
@@ -5873,6 +5874,16 @@ il4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 		return -EOPNOTSUPP;
 	}
 
+	/*
+	 * To support IBSS RSN, don't program group keys in IBSS, the
+	 * hardware will then not attempt to decrypt the frames.
+	 */
+	if (vif->type == NL80211_IFTYPE_ADHOC &&
+	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+		D_MAC80211("leave - ad-hoc group key\n");
+		return -EOPNOTSUPP;
+	}
+
 	sta_id = il_sta_id_or_broadcast(il, sta);
 	if (sta_id == IL_INVALID_STATION)
 		return -EINVAL;
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 2463c06..727fbb5 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -6,6 +6,7 @@ config IWLWIFI
 	select LEDS_CLASS
 	select LEDS_TRIGGERS
 	select MAC80211_LEDS
+	select IWLDVM
 	---help---
 	  Select to build the driver supporting the:
 
@@ -41,6 +42,10 @@ config IWLWIFI
 	  say M here and read <file:Documentation/kbuild/modules.txt>.  The
 	  module will be called iwlwifi.
 
+config IWLDVM
+	tristate "Intel Wireless WiFi"
+	depends on IWLWIFI
+
 menu "Debugging Options"
 	depends on IWLWIFI
 
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index d615eac..170ec33 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,27 +1,19 @@
-# WIFI
+# common
 obj-$(CONFIG_IWLWIFI)	+= iwlwifi.o
-iwlwifi-objs		:= iwl-agn.o iwl-agn-rs.o iwl-mac80211.o
-iwlwifi-objs		+= iwl-ucode.o iwl-agn-tx.o iwl-debug.o
-iwlwifi-objs		+= iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
-iwlwifi-objs		+= iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
-
-iwlwifi-objs		+= iwl-eeprom.o iwl-power.o
-iwlwifi-objs		+= iwl-scan.o iwl-led.o
-iwlwifi-objs		+= iwl-agn-rxon.o iwl-agn-devices.o
-iwlwifi-objs		+= iwl-5000.o
-iwlwifi-objs		+= iwl-6000.o
-iwlwifi-objs		+= iwl-1000.o
-iwlwifi-objs		+= iwl-2000.o
-iwlwifi-objs		+= iwl-pci.o
+iwlwifi-objs		+= iwl-io.o
 iwlwifi-objs		+= iwl-drv.o
+iwlwifi-objs		+= iwl-debug.o
 iwlwifi-objs		+= iwl-notif-wait.o
-iwlwifi-objs		+= iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
-
+iwlwifi-objs		+= iwl-eeprom-read.o iwl-eeprom-parse.o
+iwlwifi-objs		+= pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
+iwlwifi-objs		+= pcie/1000.o pcie/2000.o pcie/5000.o pcie/6000.o
 
-iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
 iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
-iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-testmode.o
+iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-test.o
 
-CFLAGS_iwl-devtrace.o := -I$(src)
+ccflags-y += -D__CHECK_ENDIAN__ -I$(src)
 
-ccflags-y += -D__CHECK_ENDIAN__
+
+obj-$(CONFIG_IWLDVM)	+= dvm/
+
+CFLAGS_iwl-devtrace.o := -I$(src)
diff --git a/drivers/net/wireless/iwlwifi/dvm/Makefile b/drivers/net/wireless/iwlwifi/dvm/Makefile
new file mode 100644
index 0000000..5ff76b2
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/Makefile
@@ -0,0 +1,13 @@
+# DVM
+obj-$(CONFIG_IWLDVM)	+= iwldvm.o
+iwldvm-objs		+= main.o rs.o mac80211.o ucode.o tx.o
+iwldvm-objs		+= lib.o calib.o tt.o sta.o rx.o
+
+iwldvm-objs		+= power.o
+iwldvm-objs		+= scan.o led.o
+iwldvm-objs		+= rxon.o devices.o
+
+iwldvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
+iwldvm-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += testmode.o
+
+ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h
new file mode 100644
index 0000000..9bb16bd
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/agn.h
@@ -0,0 +1,529 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_agn_h__
+#define __iwl_agn_h__
+
+#include "iwl-config.h"
+
+#include "dev.h"
+
+/* The first 11 queues (0-10) are used otherwise */
+#define IWLAGN_FIRST_AMPDU_QUEUE	11
+
+/* AUX (TX during scan dwell) queue */
+#define IWL_AUX_QUEUE		10
+
+/* device operations */
+extern struct iwl_lib_ops iwl1000_lib;
+extern struct iwl_lib_ops iwl2000_lib;
+extern struct iwl_lib_ops iwl2030_lib;
+extern struct iwl_lib_ops iwl5000_lib;
+extern struct iwl_lib_ops iwl5150_lib;
+extern struct iwl_lib_ops iwl6000_lib;
+extern struct iwl_lib_ops iwl6030_lib;
+
+
+#define TIME_UNIT		1024
+
+/*****************************************************
+* DRIVER STATUS FUNCTIONS
+******************************************************/
+#define STATUS_RF_KILL_HW	0
+#define STATUS_CT_KILL		1
+#define STATUS_ALIVE		2
+#define STATUS_READY		3
+#define STATUS_EXIT_PENDING	5
+#define STATUS_STATISTICS	6
+#define STATUS_SCANNING		7
+#define STATUS_SCAN_ABORTING	8
+#define STATUS_SCAN_HW		9
+#define STATUS_FW_ERROR		10
+#define STATUS_CHANNEL_SWITCH_PENDING 11
+#define STATUS_SCAN_COMPLETE	12
+#define STATUS_POWER_PMI	13
+#define STATUS_SCAN_ROC_EXPIRED 14
+
+struct iwl_ucode_capabilities;
+
+extern struct ieee80211_ops iwlagn_hw_ops;
+
+static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
+{
+	hdr->op_code = cmd;
+	hdr->first_group = 0;
+	hdr->groups_num = 1;
+	hdr->data_valid = 1;
+}
+
+void iwl_down(struct iwl_priv *priv);
+void iwl_cancel_deferred_work(struct iwl_priv *priv);
+void iwlagn_prepare_restart(struct iwl_priv *priv);
+int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode,
+				 struct iwl_rx_cmd_buffer *rxb,
+				 struct iwl_device_cmd *cmd);
+
+bool iwl_check_for_ct_kill(struct iwl_priv *priv);
+
+void iwlagn_lift_passive_no_rx(struct iwl_priv *priv);
+
+/* MAC80211 */
+struct ieee80211_hw *iwl_alloc_all(void);
+int iwlagn_mac_setup_register(struct iwl_priv *priv,
+			      const struct iwl_ucode_capabilities *capa);
+void iwlagn_mac_unregister(struct iwl_priv *priv);
+
+/* commands */
+int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
+			 u32 flags, u16 len, const void *data);
+
+/* RXON */
+void iwl_connection_init_rx_config(struct iwl_priv *priv,
+				   struct iwl_rxon_context *ctx);
+int iwlagn_set_pan_params(struct iwl_priv *priv);
+int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed);
+void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
+			     struct ieee80211_vif *vif,
+			     struct ieee80211_bss_conf *bss_conf,
+			     u32 changes);
+void iwlagn_config_ht40(struct ieee80211_conf *conf,
+			struct iwl_rxon_context *ctx);
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
+void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+			 struct iwl_rxon_context *ctx);
+void iwl_set_flags_for_band(struct iwl_priv *priv,
+			    struct iwl_rxon_context *ctx,
+			    enum ieee80211_band band,
+			    struct ieee80211_vif *vif);
+
+/* uCode */
+int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
+void iwl_send_prio_tbl(struct iwl_priv *priv);
+int iwl_init_alive_start(struct iwl_priv *priv);
+int iwl_run_init_ucode(struct iwl_priv *priv);
+int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
+			      enum iwl_ucode_type ucode_type);
+int iwl_send_calib_results(struct iwl_priv *priv);
+int iwl_calib_set(struct iwl_priv *priv,
+		  const struct iwl_calib_hdr *cmd, int len);
+void iwl_calib_free_results(struct iwl_priv *priv);
+int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+			    char **buf, bool display);
+int iwlagn_hw_valid_rtc_data_addr(u32 addr);
+
+/* lib */
+int iwlagn_send_tx_power(struct iwl_priv *priv);
+void iwlagn_temperature(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);
+int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
+int iwl_send_statistics_request(struct iwl_priv *priv,
+				u8 flags, bool clear);
+
+static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
+			struct iwl_priv *priv, enum ieee80211_band band)
+{
+	return priv->hw->wiphy->bands[band];
+}
+
+#ifdef CONFIG_PM_SLEEP
+int iwlagn_send_patterns(struct iwl_priv *priv,
+			 struct cfg80211_wowlan *wowlan);
+int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan);
+#endif
+
+/* rx */
+int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
+void iwl_setup_rx_handlers(struct iwl_priv *priv);
+void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
+
+
+/* tx */
+int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
+int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta, u16 tid, u8 buf_size);
+int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
+		       struct ieee80211_sta *sta, u16 tid);
+int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+				   struct iwl_rx_cmd_buffer *rxb,
+				   struct iwl_device_cmd *cmd);
+int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+			       struct iwl_device_cmd *cmd);
+
+static inline u32 iwl_tx_status_to_mac80211(u32 status)
+{
+	status &= TX_STATUS_MSK;
+
+	switch (status) {
+	case TX_STATUS_SUCCESS:
+	case TX_STATUS_DIRECT_DONE:
+		return IEEE80211_TX_STAT_ACK;
+	case TX_STATUS_FAIL_DEST_PS:
+	case TX_STATUS_FAIL_PASSIVE_NO_RX:
+		return IEEE80211_TX_STAT_TX_FILTERED;
+	default:
+		return 0;
+	}
+}
+
+static inline bool iwl_is_tx_success(u32 status)
+{
+	status &= TX_STATUS_MSK;
+	return (status == TX_STATUS_SUCCESS) ||
+	       (status == TX_STATUS_DIRECT_DONE);
+}
+
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
+
+/* scan */
+void iwlagn_post_scan(struct iwl_priv *priv);
+void iwlagn_disable_roc(struct iwl_priv *priv);
+int iwl_force_rf_reset(struct iwl_priv *priv, bool external);
+void iwl_init_scan_params(struct iwl_priv *priv);
+int iwl_scan_cancel(struct iwl_priv *priv);
+void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
+void iwl_force_scan_end(struct iwl_priv *priv);
+void iwl_internal_short_hw_scan(struct iwl_priv *priv);
+void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
+void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
+void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
+int __must_check iwl_scan_initiate(struct iwl_priv *priv,
+				   struct ieee80211_vif *vif,
+				   enum iwl_scan_type scan_type,
+				   enum ieee80211_band band);
+
+void iwl_scan_roc_expired(struct iwl_priv *priv);
+void iwl_scan_offchannel_skb(struct iwl_priv *priv);
+void iwl_scan_offchannel_skb_status(struct iwl_priv *priv);
+
+/* For faster active scanning, scan will move to the next channel if fewer than
+ * PLCP_QUIET_THRESH packets are heard on this channel within
+ * ACTIVE_QUIET_TIME after sending probe request.  This shortens the dwell
+ * time if it's a quiet channel (nothing responded to our probe, and there's
+ * no other traffic).
+ * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
+#define IWL_ACTIVE_QUIET_TIME       cpu_to_le16(10)  /* msec */
+#define IWL_PLCP_QUIET_THRESH       cpu_to_le16(1)  /* packets */
+
+#define IWL_SCAN_CHECK_WATCHDOG		(HZ * 15)
+
+
+/* bt coex */
+void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
+int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+				  struct iwl_rx_cmd_buffer *rxb,
+				  struct iwl_device_cmd *cmd);
+void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);
+void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);
+void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
+void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv);
+void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena);
+
+static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
+{
+	return priv->cfg->bt_params &&
+	       priv->cfg->bt_params->advanced_bt_coexist;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+const char *iwl_get_tx_fail_reason(u32 status);
+const char *iwl_get_agg_tx_fail_reason(u16 status);
+#else
+static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
+static inline const char *iwl_get_agg_tx_fail_reason(u16 status) { return ""; }
+#endif
+
+
+/* station management */
+int iwlagn_manage_ibss_station(struct iwl_priv *priv,
+			       struct ieee80211_vif *vif, bool add);
+#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
+#define IWL_STA_UCODE_ACTIVE  BIT(1) /* ucode entry is active */
+#define IWL_STA_UCODE_INPROGRESS  BIT(2) /* ucode entry is in process of
+					    being activated */
+#define IWL_STA_LOCAL BIT(3) /* station state not directed by mac80211;
+				(this is for the IBSS BSSID stations) */
+#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */
+
+
+void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+void iwl_clear_ucode_stations(struct iwl_priv *priv,
+			      struct iwl_rxon_context *ctx);
+void iwl_dealloc_bcast_stations(struct iwl_priv *priv);
+int iwl_get_free_ucode_key_offset(struct iwl_priv *priv);
+int iwl_send_add_sta(struct iwl_priv *priv,
+		     struct iwl_addsta_cmd *sta, u8 flags);
+int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+			   const u8 *addr, bool is_ap,
+			   struct ieee80211_sta *sta, u8 *sta_id_r);
+int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
+		       const u8 *addr);
+void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
+			    const u8 *addr);
+u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+		    const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
+
+int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+		    struct iwl_link_quality_cmd *lq, u8 flags, bool init);
+int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+			       struct iwl_device_cmd *cmd);
+int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+		      struct ieee80211_sta *sta);
+
+bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
+			    struct iwl_rxon_context *ctx,
+			    struct ieee80211_sta_ht_cap *ht_cap);
+
+static inline int iwl_sta_id(struct ieee80211_sta *sta)
+{
+	if (WARN_ON(!sta))
+		return IWL_INVALID_STATION;
+
+	return ((struct iwl_station_priv *)sta->drv_priv)->sta_id;
+}
+
+int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
+			       struct iwl_rxon_context *ctx);
+int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+			     const u8 *addr, u8 *sta_id_r);
+int iwl_remove_default_wep_key(struct iwl_priv *priv,
+			       struct iwl_rxon_context *ctx,
+			       struct ieee80211_key_conf *key);
+int iwl_set_default_wep_key(struct iwl_priv *priv,
+			    struct iwl_rxon_context *ctx,
+			    struct ieee80211_key_conf *key);
+int iwl_restore_default_wep_keys(struct iwl_priv *priv,
+				 struct iwl_rxon_context *ctx);
+int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+			struct ieee80211_key_conf *key,
+			struct ieee80211_sta *sta);
+int iwl_remove_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+			   struct ieee80211_key_conf *key,
+			   struct ieee80211_sta *sta);
+void iwl_update_tkip_key(struct iwl_priv *priv,
+			 struct ieee80211_vif *vif,
+			 struct ieee80211_key_conf *keyconf,
+			 struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
+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,
+			int tid);
+void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
+int iwl_update_bcast_station(struct iwl_priv *priv,
+			     struct iwl_rxon_context *ctx);
+int iwl_update_bcast_stations(struct iwl_priv *priv);
+
+/* rate */
+static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
+{
+	return BIT(ant_idx) << RATE_MCS_ANT_POS;
+}
+
+static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
+{
+	return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK;
+}
+
+static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
+{
+	return cpu_to_le32(flags|(u32)rate);
+}
+
+extern int iwl_alive_start(struct iwl_priv *priv);
+
+/* testmode support */
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+
+extern int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data,
+				   int len);
+extern int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw,
+				    struct sk_buff *skb,
+				    struct netlink_callback *cb,
+				    void *data, int len);
+extern void iwl_testmode_init(struct iwl_priv *priv);
+extern void iwl_testmode_free(struct iwl_priv *priv);
+
+#else
+
+static inline
+int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
+{
+	return -ENOSYS;
+}
+
+static inline
+int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
+		      struct netlink_callback *cb,
+		      void *data, int len)
+{
+	return -ENOSYS;
+}
+
+static inline void iwl_testmode_init(struct iwl_priv *priv)
+{
+}
+
+static inline void iwl_testmode_free(struct iwl_priv *priv)
+{
+}
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+			     enum iwl_rxon_context_id ctxid);
+#else
+static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+					   enum iwl_rxon_context_id ctxid)
+{
+}
+#endif
+
+/* status checks */
+
+static inline int iwl_is_ready(struct iwl_priv *priv)
+{
+	/* The adapter is 'ready' if READY EXIT_PENDING is not set */
+	return test_bit(STATUS_READY, &priv->status) &&
+	       !test_bit(STATUS_EXIT_PENDING, &priv->status);
+}
+
+static inline int iwl_is_alive(struct iwl_priv *priv)
+{
+	return test_bit(STATUS_ALIVE, &priv->status);
+}
+
+static inline int iwl_is_rfkill(struct iwl_priv *priv)
+{
+	return test_bit(STATUS_RF_KILL_HW, &priv->status);
+}
+
+static inline int iwl_is_ctkill(struct iwl_priv *priv)
+{
+	return test_bit(STATUS_CT_KILL, &priv->status);
+}
+
+static inline int iwl_is_ready_rf(struct iwl_priv *priv)
+{
+	if (iwl_is_rfkill(priv))
+		return 0;
+
+	return iwl_is_ready(priv);
+}
+
+static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state)
+{
+	if (state)
+		set_bit(STATUS_POWER_PMI, &priv->status);
+	else
+		clear_bit(STATUS_POWER_PMI, &priv->status);
+	iwl_trans_set_pmi(priv->trans, state);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+int iwl_dbgfs_register(struct iwl_priv *priv, const char *name);
+void iwl_dbgfs_unregister(struct iwl_priv *priv);
+#else
+static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
+{
+	return 0;
+}
+static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
+{
+}
+#endif /* CONFIG_IWLWIFI_DEBUGFS */
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)	\
+do {									\
+	if (!iwl_is_rfkill((m)))					\
+		IWL_ERR(m, fmt, ##args);				\
+	else								\
+		__iwl_err((m)->dev, true,				\
+			  !iwl_have_debug_level(IWL_DL_RADIO),		\
+			  fmt, ##args);					\
+} while (0)
+#else
+#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)	\
+do {									\
+	if (!iwl_is_rfkill((m)))					\
+		IWL_ERR(m, fmt, ##args);				\
+	else								\
+		__iwl_err((m)->dev, true, true, fmt, ##args);	\
+} while (0)
+#endif				/* CONFIG_IWLWIFI_DEBUG */
+
+extern const char *iwl_dvm_cmd_strings[REPLY_MAX];
+
+static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
+{
+	const char *s = iwl_dvm_cmd_strings[cmd];
+	if (s)
+		return s;
+	return "UNKNOWN";
+}
+#endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.c b/drivers/net/wireless/iwlwifi/dvm/calib.c
new file mode 100644
index 0000000..f2dd671
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/calib.c
@@ -0,0 +1,1114 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <linux/slab.h>
+#include <net/mac80211.h>
+
+#include "iwl-trans.h"
+
+#include "dev.h"
+#include "calib.h"
+#include "agn.h"
+
+/*****************************************************************************
+ * INIT calibrations framework
+ *****************************************************************************/
+
+/* Opaque calibration results */
+struct iwl_calib_result {
+	struct list_head list;
+	size_t cmd_len;
+	struct iwl_calib_hdr hdr;
+	/* data follows */
+};
+
+struct statistics_general_data {
+	u32 beacon_silence_rssi_a;
+	u32 beacon_silence_rssi_b;
+	u32 beacon_silence_rssi_c;
+	u32 beacon_energy_a;
+	u32 beacon_energy_b;
+	u32 beacon_energy_c;
+};
+
+int iwl_send_calib_results(struct iwl_priv *priv)
+{
+	struct iwl_host_cmd hcmd = {
+		.id = REPLY_PHY_CALIBRATION_CMD,
+		.flags = CMD_SYNC,
+	};
+	struct iwl_calib_result *res;
+
+	list_for_each_entry(res, &priv->calib_results, list) {
+		int ret;
+
+		hcmd.len[0] = res->cmd_len;
+		hcmd.data[0] = &res->hdr;
+		hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+		ret = iwl_dvm_send_cmd(priv, &hcmd);
+		if (ret) {
+			IWL_ERR(priv, "Error %d on calib cmd %d\n",
+				ret, res->hdr.op_code);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int iwl_calib_set(struct iwl_priv *priv,
+		  const struct iwl_calib_hdr *cmd, int len)
+{
+	struct iwl_calib_result *res, *tmp;
+
+	res = kmalloc(sizeof(*res) + len - sizeof(struct iwl_calib_hdr),
+		      GFP_ATOMIC);
+	if (!res)
+		return -ENOMEM;
+	memcpy(&res->hdr, cmd, len);
+	res->cmd_len = len;
+
+	list_for_each_entry(tmp, &priv->calib_results, list) {
+		if (tmp->hdr.op_code == res->hdr.op_code) {
+			list_replace(&tmp->list, &res->list);
+			kfree(tmp);
+			return 0;
+		}
+	}
+
+	/* wasn't in list already */
+	list_add_tail(&res->list, &priv->calib_results);
+
+	return 0;
+}
+
+void iwl_calib_free_results(struct iwl_priv *priv)
+{
+	struct iwl_calib_result *res, *tmp;
+
+	list_for_each_entry_safe(res, tmp, &priv->calib_results, list) {
+		list_del(&res->list);
+		kfree(res);
+	}
+}
+
+/*****************************************************************************
+ * RUNTIME calibrations framework
+ *****************************************************************************/
+
+/* "false alarms" are signals that our DSP tries to lock onto,
+ *   but then determines that they are either noise, or transmissions
+ *   from a distant wireless network (also "noise", really) that get
+ *   "stepped on" by stronger transmissions within our own network.
+ * This algorithm attempts to set a sensitivity level that is high
+ *   enough to receive all of our own network traffic, but not so
+ *   high that our DSP gets too busy trying to lock onto non-network
+ *   activity/noise. */
+static int iwl_sens_energy_cck(struct iwl_priv *priv,
+				   u32 norm_fa,
+				   u32 rx_enable_time,
+				   struct statistics_general_data *rx_info)
+{
+	u32 max_nrg_cck = 0;
+	int i = 0;
+	u8 max_silence_rssi = 0;
+	u32 silence_ref = 0;
+	u8 silence_rssi_a = 0;
+	u8 silence_rssi_b = 0;
+	u8 silence_rssi_c = 0;
+	u32 val;
+
+	/* "false_alarms" values below are cross-multiplications to assess the
+	 *   numbers of false alarms within the measured period of actual Rx
+	 *   (Rx is off when we're txing), vs the min/max expected false alarms
+	 *   (some should be expected if rx is sensitive enough) in a
+	 *   hypothetical listening period of 200 time units (TU), 204.8 msec:
+	 *
+	 * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
+	 *
+	 * */
+	u32 false_alarms = norm_fa * 200 * 1024;
+	u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
+	u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
+	struct iwl_sensitivity_data *data = NULL;
+	const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+	data = &(priv->sensitivity_data);
+
+	data->nrg_auto_corr_silence_diff = 0;
+
+	/* Find max silence rssi among all 3 receivers.
+	 * This is background noise, which may include transmissions from other
+	 *    networks, measured during silence before our network's beacon */
+	silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
+			    ALL_BAND_FILTER) >> 8);
+	silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
+			    ALL_BAND_FILTER) >> 8);
+	silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
+			    ALL_BAND_FILTER) >> 8);
+
+	val = max(silence_rssi_b, silence_rssi_c);
+	max_silence_rssi = max(silence_rssi_a, (u8) val);
+
+	/* Store silence rssi in 20-beacon history table */
+	data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
+	data->nrg_silence_idx++;
+	if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
+		data->nrg_silence_idx = 0;
+
+	/* Find max silence rssi across 20 beacon history */
+	for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
+		val = data->nrg_silence_rssi[i];
+		silence_ref = max(silence_ref, val);
+	}
+	IWL_DEBUG_CALIB(priv, "silence a %u, b %u, c %u, 20-bcn max %u\n",
+			silence_rssi_a, silence_rssi_b, silence_rssi_c,
+			silence_ref);
+
+	/* Find max rx energy (min value!) among all 3 receivers,
+	 *   measured during beacon frame.
+	 * Save it in 10-beacon history table. */
+	i = data->nrg_energy_idx;
+	val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
+	data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
+
+	data->nrg_energy_idx++;
+	if (data->nrg_energy_idx >= 10)
+		data->nrg_energy_idx = 0;
+
+	/* Find min rx energy (max value) across 10 beacon history.
+	 * This is the minimum signal level that we want to receive well.
+	 * Add backoff (margin so we don't miss slightly lower energy frames).
+	 * This establishes an upper bound (min value) for energy threshold. */
+	max_nrg_cck = data->nrg_value[0];
+	for (i = 1; i < 10; i++)
+		max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
+	max_nrg_cck += 6;
+
+	IWL_DEBUG_CALIB(priv, "rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
+			rx_info->beacon_energy_a, rx_info->beacon_energy_b,
+			rx_info->beacon_energy_c, max_nrg_cck - 6);
+
+	/* Count number of consecutive beacons with fewer-than-desired
+	 *   false alarms. */
+	if (false_alarms < min_false_alarms)
+		data->num_in_cck_no_fa++;
+	else
+		data->num_in_cck_no_fa = 0;
+	IWL_DEBUG_CALIB(priv, "consecutive bcns with few false alarms = %u\n",
+			data->num_in_cck_no_fa);
+
+	/* If we got too many false alarms this time, reduce sensitivity */
+	if ((false_alarms > max_false_alarms) &&
+		(data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK)) {
+		IWL_DEBUG_CALIB(priv, "norm FA %u > max FA %u\n",
+		     false_alarms, max_false_alarms);
+		IWL_DEBUG_CALIB(priv, "... reducing sensitivity\n");
+		data->nrg_curr_state = IWL_FA_TOO_MANY;
+		/* Store for "fewer than desired" on later beacon */
+		data->nrg_silence_ref = silence_ref;
+
+		/* increase energy threshold (reduce nrg value)
+		 *   to decrease sensitivity */
+		data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK;
+	/* Else if we got fewer than desired, increase sensitivity */
+	} else if (false_alarms < min_false_alarms) {
+		data->nrg_curr_state = IWL_FA_TOO_FEW;
+
+		/* Compare silence level with silence level for most recent
+		 *   healthy number or too many false alarms */
+		data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
+						   (s32)silence_ref;
+
+		IWL_DEBUG_CALIB(priv, "norm FA %u < min FA %u, silence diff %d\n",
+			 false_alarms, min_false_alarms,
+			 data->nrg_auto_corr_silence_diff);
+
+		/* Increase value to increase sensitivity, but only if:
+		 * 1a) previous beacon did *not* have *too many* false alarms
+		 * 1b) AND there's a significant difference in Rx levels
+		 *      from a previous beacon with too many, or healthy # FAs
+		 * OR 2) We've seen a lot of beacons (100) with too few
+		 *       false alarms */
+		if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
+			((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
+			(data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
+
+			IWL_DEBUG_CALIB(priv, "... increasing sensitivity\n");
+			/* Increase nrg value to increase sensitivity */
+			val = data->nrg_th_cck + NRG_STEP_CCK;
+			data->nrg_th_cck = min((u32)ranges->min_nrg_cck, val);
+		} else {
+			IWL_DEBUG_CALIB(priv, "... but not changing sensitivity\n");
+		}
+
+	/* Else we got a healthy number of false alarms, keep status quo */
+	} else {
+		IWL_DEBUG_CALIB(priv, " FA in safe zone\n");
+		data->nrg_curr_state = IWL_FA_GOOD_RANGE;
+
+		/* Store for use in "fewer than desired" with later beacon */
+		data->nrg_silence_ref = silence_ref;
+
+		/* If previous beacon had too many false alarms,
+		 *   give it some extra margin by reducing sensitivity again
+		 *   (but don't go below measured energy of desired Rx) */
+		if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
+			IWL_DEBUG_CALIB(priv, "... increasing margin\n");
+			if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN))
+				data->nrg_th_cck -= NRG_MARGIN;
+			else
+				data->nrg_th_cck = max_nrg_cck;
+		}
+	}
+
+	/* Make sure the energy threshold does not go above the measured
+	 * energy of the desired Rx signals (reduced by backoff margin),
+	 * or else we might start missing Rx frames.
+	 * Lower value is higher energy, so we use max()!
+	 */
+	data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
+	IWL_DEBUG_CALIB(priv, "new nrg_th_cck %u\n", data->nrg_th_cck);
+
+	data->nrg_prev_state = data->nrg_curr_state;
+
+	/* Auto-correlation CCK algorithm */
+	if (false_alarms > min_false_alarms) {
+
+		/* increase auto_corr values to decrease sensitivity
+		 * so the DSP won't be disturbed by the noise
+		 */
+		if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
+			data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1;
+		else {
+			val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
+			data->auto_corr_cck =
+				min((u32)ranges->auto_corr_max_cck, val);
+		}
+		val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
+		data->auto_corr_cck_mrc =
+			min((u32)ranges->auto_corr_max_cck_mrc, val);
+	} else if ((false_alarms < min_false_alarms) &&
+	   ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
+	   (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
+
+		/* Decrease auto_corr values to increase sensitivity */
+		val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
+		data->auto_corr_cck =
+			max((u32)ranges->auto_corr_min_cck, val);
+		val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
+		data->auto_corr_cck_mrc =
+			max((u32)ranges->auto_corr_min_cck_mrc, val);
+	}
+
+	return 0;
+}
+
+
+static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
+				       u32 norm_fa,
+				       u32 rx_enable_time)
+{
+	u32 val;
+	u32 false_alarms = norm_fa * 200 * 1024;
+	u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
+	u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
+	struct iwl_sensitivity_data *data = NULL;
+	const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+	data = &(priv->sensitivity_data);
+
+	/* If we got too many false alarms this time, reduce sensitivity */
+	if (false_alarms > max_false_alarms) {
+
+		IWL_DEBUG_CALIB(priv, "norm FA %u > max FA %u)\n",
+			     false_alarms, max_false_alarms);
+
+		val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm =
+			min((u32)ranges->auto_corr_max_ofdm, val);
+
+		val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_mrc =
+			min((u32)ranges->auto_corr_max_ofdm_mrc, val);
+
+		val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_x1 =
+			min((u32)ranges->auto_corr_max_ofdm_x1, val);
+
+		val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_mrc_x1 =
+			min((u32)ranges->auto_corr_max_ofdm_mrc_x1, val);
+	}
+
+	/* Else if we got fewer than desired, increase sensitivity */
+	else if (false_alarms < min_false_alarms) {
+
+		IWL_DEBUG_CALIB(priv, "norm FA %u < min FA %u\n",
+			     false_alarms, min_false_alarms);
+
+		val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm =
+			max((u32)ranges->auto_corr_min_ofdm, val);
+
+		val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_mrc =
+			max((u32)ranges->auto_corr_min_ofdm_mrc, val);
+
+		val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_x1 =
+			max((u32)ranges->auto_corr_min_ofdm_x1, val);
+
+		val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_mrc_x1 =
+			max((u32)ranges->auto_corr_min_ofdm_mrc_x1, val);
+	} else {
+		IWL_DEBUG_CALIB(priv, "min FA %u < norm FA %u < max FA %u OK\n",
+			 min_false_alarms, false_alarms, max_false_alarms);
+	}
+	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_data *data = NULL;
+	struct iwl_host_cmd cmd_out = {
+		.id = SENSITIVITY_CMD,
+		.len = { sizeof(struct iwl_sensitivity_cmd), },
+		.flags = CMD_ASYNC,
+		.data = { &cmd, },
+	};
+
+	data = &(priv->sensitivity_data);
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	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;
+
+	/* Don't send command to uCode if nothing has changed */
+	if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
+		    sizeof(u16)*HD_TABLE_SIZE)) {
+		IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n");
+		return 0;
+	}
+
+	/* Copy table for comparison next time */
+	memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
+	       sizeof(u16)*HD_TABLE_SIZE);
+
+	return iwl_dvm_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]);
+
+	if (priv->cfg->base_params->hd_v2) {
+		cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
+			HD_INA_NON_SQUARE_DET_OFDM_DATA_V2;
+		cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
+			HD_INA_NON_SQUARE_DET_CCK_DATA_V2;
+		cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
+			HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+			HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+			HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
+			HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
+			HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2;
+	} else {
+		cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
+			HD_INA_NON_SQUARE_DET_OFDM_DATA_V1;
+		cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
+			HD_INA_NON_SQUARE_DET_CCK_DATA_V1;
+		cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
+			HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+			HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+			HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
+			HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
+			HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1;
+	}
+
+	/* 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_dvm_send_cmd(priv, &cmd_out);
+}
+
+void iwl_init_sensitivity(struct iwl_priv *priv)
+{
+	int ret = 0;
+	int i;
+	struct iwl_sensitivity_data *data = NULL;
+	const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+	if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED)
+		return;
+
+	IWL_DEBUG_CALIB(priv, "Start iwl_init_sensitivity\n");
+
+	/* Clear driver's sensitivity algo data */
+	data = &(priv->sensitivity_data);
+
+	if (ranges == NULL)
+		return;
+
+	memset(data, 0, sizeof(struct iwl_sensitivity_data));
+
+	data->num_in_cck_no_fa = 0;
+	data->nrg_curr_state = IWL_FA_TOO_MANY;
+	data->nrg_prev_state = IWL_FA_TOO_MANY;
+	data->nrg_silence_ref = 0;
+	data->nrg_silence_idx = 0;
+	data->nrg_energy_idx = 0;
+
+	for (i = 0; i < 10; i++)
+		data->nrg_value[i] = 0;
+
+	for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
+		data->nrg_silence_rssi[i] = 0;
+
+	data->auto_corr_ofdm =  ranges->auto_corr_min_ofdm;
+	data->auto_corr_ofdm_mrc = ranges->auto_corr_min_ofdm_mrc;
+	data->auto_corr_ofdm_x1  = ranges->auto_corr_min_ofdm_x1;
+	data->auto_corr_ofdm_mrc_x1 = ranges->auto_corr_min_ofdm_mrc_x1;
+	data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF;
+	data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc;
+	data->nrg_th_cck = ranges->nrg_th_cck;
+	data->nrg_th_ofdm = ranges->nrg_th_ofdm;
+	data->barker_corr_th_min = ranges->barker_corr_th_min;
+	data->barker_corr_th_min_mrc = ranges->barker_corr_th_min_mrc;
+	data->nrg_th_cca = ranges->nrg_th_cca;
+
+	data->last_bad_plcp_cnt_ofdm = 0;
+	data->last_fa_cnt_ofdm = 0;
+	data->last_bad_plcp_cnt_cck = 0;
+	data->last_fa_cnt_cck = 0;
+
+	if (priv->fw->enhance_sensitivity_table)
+		ret |= iwl_enhance_sensitivity_write(priv);
+	else
+		ret |= iwl_sensitivity_write(priv);
+	IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
+}
+
+void iwl_sensitivity_calibration(struct iwl_priv *priv)
+{
+	u32 rx_enable_time;
+	u32 fa_cck;
+	u32 fa_ofdm;
+	u32 bad_plcp_cck;
+	u32 bad_plcp_ofdm;
+	u32 norm_fa_ofdm;
+	u32 norm_fa_cck;
+	struct iwl_sensitivity_data *data = NULL;
+	struct statistics_rx_non_phy *rx_info;
+	struct statistics_rx_phy *ofdm, *cck;
+	struct statistics_general_data statis;
+
+	if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED)
+		return;
+
+	data = &(priv->sensitivity_data);
+
+	if (!iwl_is_any_associated(priv)) {
+		IWL_DEBUG_CALIB(priv, "<< - not associated\n");
+		return;
+	}
+
+	spin_lock_bh(&priv->statistics.lock);
+	rx_info = &priv->statistics.rx_non_phy;
+	ofdm = &priv->statistics.rx_ofdm;
+	cck = &priv->statistics.rx_cck;
+	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+		IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
+		spin_unlock_bh(&priv->statistics.lock);
+		return;
+	}
+
+	/* Extract Statistics: */
+	rx_enable_time = le32_to_cpu(rx_info->channel_load);
+	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(rx_info->beacon_silence_rssi_a);
+	statis.beacon_silence_rssi_b =
+			le32_to_cpu(rx_info->beacon_silence_rssi_b);
+	statis.beacon_silence_rssi_c =
+			le32_to_cpu(rx_info->beacon_silence_rssi_c);
+	statis.beacon_energy_a =
+			le32_to_cpu(rx_info->beacon_energy_a);
+	statis.beacon_energy_b =
+			le32_to_cpu(rx_info->beacon_energy_b);
+	statis.beacon_energy_c =
+			le32_to_cpu(rx_info->beacon_energy_c);
+
+	spin_unlock_bh(&priv->statistics.lock);
+
+	IWL_DEBUG_CALIB(priv, "rx_enable_time = %u usecs\n", rx_enable_time);
+
+	if (!rx_enable_time) {
+		IWL_DEBUG_CALIB(priv, "<< RX Enable Time == 0!\n");
+		return;
+	}
+
+	/* These statistics increase monotonically, and do not reset
+	 *   at each beacon.  Calculate difference from last value, or just
+	 *   use the new statistics value if it has reset or wrapped around. */
+	if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
+		data->last_bad_plcp_cnt_cck = bad_plcp_cck;
+	else {
+		bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
+		data->last_bad_plcp_cnt_cck += bad_plcp_cck;
+	}
+
+	if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm)
+		data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm;
+	else {
+		bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm;
+		data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm;
+	}
+
+	if (data->last_fa_cnt_ofdm > fa_ofdm)
+		data->last_fa_cnt_ofdm = fa_ofdm;
+	else {
+		fa_ofdm -= data->last_fa_cnt_ofdm;
+		data->last_fa_cnt_ofdm += fa_ofdm;
+	}
+
+	if (data->last_fa_cnt_cck > fa_cck)
+		data->last_fa_cnt_cck = fa_cck;
+	else {
+		fa_cck -= data->last_fa_cnt_cck;
+		data->last_fa_cnt_cck += fa_cck;
+	}
+
+	/* Total aborted signal locks */
+	norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm;
+	norm_fa_cck = fa_cck + bad_plcp_cck;
+
+	IWL_DEBUG_CALIB(priv, "cck: fa %u badp %u  ofdm: fa %u badp %u\n", fa_cck,
+			bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
+
+	iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
+	iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
+	if (priv->fw->enhance_sensitivity_table)
+		iwl_enhance_sensitivity_write(priv);
+	else
+		iwl_sensitivity_write(priv);
+}
+
+static inline u8 find_first_chain(u8 mask)
+{
+	if (mask & ANT_A)
+		return CHAIN_A;
+	if (mask & ANT_B)
+		return CHAIN_B;
+	return CHAIN_C;
+}
+
+/**
+ * Run disconnected antenna algorithm to find out which antennas are
+ * disconnected.
+ */
+static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
+				     struct iwl_chain_noise_data *data)
+{
+	u32 active_chains = 0;
+	u32 max_average_sig;
+	u16 max_average_sig_antenna_i;
+	u8 num_tx_chains;
+	u8 first_chain;
+	u16 i = 0;
+
+	average_sig[0] = data->chain_signal_a / IWL_CAL_NUM_BEACONS;
+	average_sig[1] = data->chain_signal_b / IWL_CAL_NUM_BEACONS;
+	average_sig[2] = data->chain_signal_c / IWL_CAL_NUM_BEACONS;
+
+	if (average_sig[0] >= average_sig[1]) {
+		max_average_sig = average_sig[0];
+		max_average_sig_antenna_i = 0;
+		active_chains = (1 << max_average_sig_antenna_i);
+	} else {
+		max_average_sig = average_sig[1];
+		max_average_sig_antenna_i = 1;
+		active_chains = (1 << max_average_sig_antenna_i);
+	}
+
+	if (average_sig[2] >= max_average_sig) {
+		max_average_sig = average_sig[2];
+		max_average_sig_antenna_i = 2;
+		active_chains = (1 << max_average_sig_antenna_i);
+	}
+
+	IWL_DEBUG_CALIB(priv, "average_sig: a %d b %d c %d\n",
+		     average_sig[0], average_sig[1], average_sig[2]);
+	IWL_DEBUG_CALIB(priv, "max_average_sig = %d, antenna %d\n",
+		     max_average_sig, max_average_sig_antenna_i);
+
+	/* Compare signal strengths for all 3 receivers. */
+	for (i = 0; i < NUM_RX_CHAINS; i++) {
+		if (i != max_average_sig_antenna_i) {
+			s32 rssi_delta = (max_average_sig - average_sig[i]);
+
+			/* If signal is very weak, compared with
+			 * strongest, mark it as disconnected. */
+			if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
+				data->disconn_array[i] = 1;
+			else
+				active_chains |= (1 << i);
+			IWL_DEBUG_CALIB(priv, "i = %d  rssiDelta = %d  "
+			     "disconn_array[i] = %d\n",
+			     i, rssi_delta, data->disconn_array[i]);
+		}
+	}
+
+	/*
+	 * The above algorithm sometimes fails when the ucode
+	 * reports 0 for all chains. It's not clear why that
+	 * happens to start with, but it is then causing trouble
+	 * because this can make us enable more chains than the
+	 * hardware really has.
+	 *
+	 * To be safe, simply mask out any chains that we know
+	 * are not on the device.
+	 */
+	active_chains &= priv->eeprom_data->valid_rx_ant;
+
+	num_tx_chains = 0;
+	for (i = 0; i < NUM_RX_CHAINS; i++) {
+		/* loops on all the bits of
+		 * priv->hw_setting.valid_tx_ant */
+		u8 ant_msk = (1 << i);
+		if (!(priv->eeprom_data->valid_tx_ant & ant_msk))
+			continue;
+
+		num_tx_chains++;
+		if (data->disconn_array[i] == 0)
+			/* there is a Tx antenna connected */
+			break;
+		if (num_tx_chains == priv->hw_params.tx_chains_num &&
+		    data->disconn_array[i]) {
+			/*
+			 * If all chains are disconnected
+			 * connect the first valid tx chain
+			 */
+			first_chain =
+				find_first_chain(priv->eeprom_data->valid_tx_ant);
+			data->disconn_array[first_chain] = 0;
+			active_chains |= BIT(first_chain);
+			IWL_DEBUG_CALIB(priv,
+					"All Tx chains are disconnected W/A - declare %d as connected\n",
+					first_chain);
+			break;
+		}
+	}
+
+	if (active_chains != priv->eeprom_data->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->eeprom_data->valid_rx_ant);
+
+	/* Save for use within RXON, TX, SCAN commands, etc. */
+	data->active_chains = active_chains;
+	IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
+			active_chains);
+}
+
+static void iwlagn_gain_computation(struct iwl_priv *priv,
+				    u32 average_noise[NUM_RX_CHAINS],
+				    u8 default_chain)
+{
+	int i;
+	s32 delta_g;
+	struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+
+	/*
+	 * Find Gain Code for the chains based on "default chain"
+	 */
+	for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) {
+		if ((data->disconn_array[i])) {
+			data->delta_gain_code[i] = 0;
+			continue;
+		}
+
+		delta_g = (priv->cfg->base_params->chain_noise_scale *
+			((s32)average_noise[default_chain] -
+			(s32)average_noise[i])) / 1500;
+
+		/* bound gain by 2 bits value max, 3rd bit is sign */
+		data->delta_gain_code[i] =
+			min(abs(delta_g),
+			(long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
+
+		if (delta_g < 0)
+			/*
+			 * set negative sign ...
+			 * note to Intel developers:  This is uCode API format,
+			 *   not the format of any internal device registers.
+			 *   Do not change this format for e.g. 6050 or similar
+			 *   devices.  Change format only if more resolution
+			 *   (i.e. more than 2 bits magnitude) is needed.
+			 */
+			data->delta_gain_code[i] |= (1 << 2);
+	}
+
+	IWL_DEBUG_CALIB(priv, "Delta gains: ANT_B = %d  ANT_C = %d\n",
+			data->delta_gain_code[1], data->delta_gain_code[2]);
+
+	if (!data->radio_write) {
+		struct iwl_calib_chain_noise_gain_cmd cmd;
+
+		memset(&cmd, 0, sizeof(cmd));
+
+		iwl_set_calib_hdr(&cmd.hdr,
+			priv->phy_calib_chain_noise_gain_cmd);
+		cmd.delta_gain_1 = data->delta_gain_code[1];
+		cmd.delta_gain_2 = data->delta_gain_code[2];
+		iwl_dvm_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+			CMD_ASYNC, sizeof(cmd), &cmd);
+
+		data->radio_write = 1;
+		data->state = IWL_CHAIN_NOISE_CALIBRATED;
+	}
+}
+
+/*
+ * Accumulate 16 beacons of signal and noise statistics for each of
+ *   3 receivers/antennas/rx-chains, then figure out:
+ * 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_chain_noise_data *data = NULL;
+
+	u32 chain_noise_a;
+	u32 chain_noise_b;
+	u32 chain_noise_c;
+	u32 chain_sig_a;
+	u32 chain_sig_b;
+	u32 chain_sig_c;
+	u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+	u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+	u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
+	u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
+	u16 i = 0;
+	u16 rxon_chnum = INITIALIZATION_VALUE;
+	u16 stat_chnum = INITIALIZATION_VALUE;
+	u8 rxon_band24;
+	u8 stat_band24;
+	struct statistics_rx_non_phy *rx_info;
+
+	/*
+	 * MULTI-FIXME:
+	 * When we support multiple interfaces on different channels,
+	 * this must be modified/fixed.
+	 */
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
+	if (priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED)
+		return;
+
+	data = &(priv->chain_noise_data);
+
+	/*
+	 * Accumulate just the first "chain_noise_num_beacons" after
+	 * the first association, then we're done forever.
+	 */
+	if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
+		if (data->state == IWL_CHAIN_NOISE_ALIVE)
+			IWL_DEBUG_CALIB(priv, "Wait for noise calib reset\n");
+		return;
+	}
+
+	spin_lock_bh(&priv->statistics.lock);
+
+	rx_info = &priv->statistics.rx_non_phy;
+
+	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+		IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
+		spin_unlock_bh(&priv->statistics.lock);
+		return;
+	}
+
+	rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
+	rxon_chnum = le16_to_cpu(ctx->staging.channel);
+	stat_band24 =
+		!!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
+	stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16;
+
+	/* Make sure we accumulate data for just the associated channel
+	 *   (even if scanning). */
+	if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) {
+		IWL_DEBUG_CALIB(priv, "Stats not from chan=%d, band24=%d\n",
+				rxon_chnum, rxon_band24);
+		spin_unlock_bh(&priv->statistics.lock);
+		return;
+	}
+
+	/*
+	 *  Accumulate beacon statistics values across
+	 * "chain_noise_num_beacons"
+	 */
+	chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
+				IN_BAND_FILTER;
+	chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
+				IN_BAND_FILTER;
+	chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
+				IN_BAND_FILTER;
+
+	chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
+	chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
+	chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
+
+	spin_unlock_bh(&priv->statistics.lock);
+
+	data->beacon_count++;
+
+	data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
+	data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
+	data->chain_noise_c = (chain_noise_c + data->chain_noise_c);
+
+	data->chain_signal_a = (chain_sig_a + data->chain_signal_a);
+	data->chain_signal_b = (chain_sig_b + data->chain_signal_b);
+	data->chain_signal_c = (chain_sig_c + data->chain_signal_c);
+
+	IWL_DEBUG_CALIB(priv, "chan=%d, band24=%d, beacon=%d\n",
+			rxon_chnum, rxon_band24, data->beacon_count);
+	IWL_DEBUG_CALIB(priv, "chain_sig: a %d b %d c %d\n",
+			chain_sig_a, chain_sig_b, chain_sig_c);
+	IWL_DEBUG_CALIB(priv, "chain_noise: a %d b %d c %d\n",
+			chain_noise_a, chain_noise_b, chain_noise_c);
+
+	/* If this is the "chain_noise_num_beacons", determine:
+	 * 1)  Disconnected antennas (using signal strengths)
+	 * 2)  Differential gain (using silence noise) to balance receivers */
+	if (data->beacon_count != IWL_CAL_NUM_BEACONS)
+		return;
+
+	/* Analyze signal for disconnected antenna */
+	if (priv->cfg->bt_params &&
+	    priv->cfg->bt_params->advanced_bt_coexist) {
+		/* Disable disconnected antenna algorithm for advanced
+		   bt coex, assuming valid antennas are connected */
+		data->active_chains = priv->eeprom_data->valid_rx_ant;
+		for (i = 0; i < NUM_RX_CHAINS; i++)
+			if (!(data->active_chains & (1<<i)))
+				data->disconn_array[i] = 1;
+	} else
+		iwl_find_disconn_antenna(priv, average_sig, data);
+
+	/* Analyze noise for rx balance */
+	average_noise[0] = data->chain_noise_a / IWL_CAL_NUM_BEACONS;
+	average_noise[1] = data->chain_noise_b / IWL_CAL_NUM_BEACONS;
+	average_noise[2] = data->chain_noise_c / IWL_CAL_NUM_BEACONS;
+
+	for (i = 0; i < NUM_RX_CHAINS; i++) {
+		if (!(data->disconn_array[i]) &&
+		   (average_noise[i] <= min_average_noise)) {
+			/* This means that chain i is active and has
+			 * lower noise values so far: */
+			min_average_noise = average_noise[i];
+			min_average_noise_antenna_i = i;
+		}
+	}
+
+	IWL_DEBUG_CALIB(priv, "average_noise: a %d b %d c %d\n",
+			average_noise[0], average_noise[1],
+			average_noise[2]);
+
+	IWL_DEBUG_CALIB(priv, "min_average_noise = %d, antenna %d\n",
+			min_average_noise, min_average_noise_antenna_i);
+
+	iwlagn_gain_computation(
+		priv, average_noise,
+		find_first_chain(priv->eeprom_data->valid_rx_ant));
+
+	/* Some power changes may have been made during the calibration.
+	 * Update and commit the RXON
+	 */
+	iwl_update_chain_flags(priv);
+
+	data->state = IWL_CHAIN_NOISE_DONE;
+	iwl_power_update_mode(priv, false);
+}
+
+void iwl_reset_run_time_calib(struct iwl_priv *priv)
+{
+	int i;
+	memset(&(priv->sensitivity_data), 0,
+	       sizeof(struct iwl_sensitivity_data));
+	memset(&(priv->chain_noise_data), 0,
+	       sizeof(struct iwl_chain_noise_data));
+	for (i = 0; i < NUM_RX_CHAINS; i++)
+		priv->chain_noise_data.delta_gain_code[i] =
+				CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
+
+	/* Ask for statistics now, the uCode will send notification
+	 * periodically after association */
+	iwl_send_statistics_request(priv, CMD_ASYNC, true);
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.h b/drivers/net/wireless/iwlwifi/dvm/calib.h
new file mode 100644
index 0000000..2349f39
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/calib.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#ifndef __iwl_calib_h__
+#define __iwl_calib_h__
+
+#include "dev.h"
+#include "commands.h"
+
+void iwl_chain_noise_calibration(struct iwl_priv *priv);
+void iwl_sensitivity_calibration(struct iwl_priv *priv);
+
+void iwl_init_sensitivity(struct iwl_priv *priv);
+void iwl_reset_run_time_calib(struct iwl_priv *priv);
+
+#endif /* __iwl_calib_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h
new file mode 100644
index 0000000..64811cd
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/commands.h
@@ -0,0 +1,3958 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+/*
+ * Please use this file (commands.h) only for uCode API definitions.
+ * Please use iwl-xxxx-hw.h for hardware-related definitions.
+ * Please use dev.h for driver implementation definitions.
+ */
+
+#ifndef __iwl_commands_h__
+#define __iwl_commands_h__
+
+#include <linux/ieee80211.h>
+#include <linux/types.h>
+
+
+enum {
+	REPLY_ALIVE = 0x1,
+	REPLY_ERROR = 0x2,
+	REPLY_ECHO = 0x3,		/* test command */
+
+	/* RXON and QOS commands */
+	REPLY_RXON = 0x10,
+	REPLY_RXON_ASSOC = 0x11,
+	REPLY_QOS_PARAM = 0x13,
+	REPLY_RXON_TIMING = 0x14,
+
+	/* Multi-Station support */
+	REPLY_ADD_STA = 0x18,
+	REPLY_REMOVE_STA = 0x19,
+	REPLY_REMOVE_ALL_STA = 0x1a,	/* not used */
+	REPLY_TXFIFO_FLUSH = 0x1e,
+
+	/* Security */
+	REPLY_WEPKEY = 0x20,
+
+	/* RX, TX, LEDs */
+	REPLY_TX = 0x1c,
+	REPLY_LEDS_CMD = 0x48,
+	REPLY_TX_LINK_QUALITY_CMD = 0x4e,
+
+	/* WiMAX coexistence */
+	COEX_PRIORITY_TABLE_CMD = 0x5a,
+	COEX_MEDIUM_NOTIFICATION = 0x5b,
+	COEX_EVENT_CMD = 0x5c,
+
+	/* Calibration */
+	TEMPERATURE_NOTIFICATION = 0x62,
+	CALIBRATION_CFG_CMD = 0x65,
+	CALIBRATION_RES_NOTIFICATION = 0x66,
+	CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
+
+	/* 802.11h related */
+	REPLY_QUIET_CMD = 0x71,		/* not used */
+	REPLY_CHANNEL_SWITCH = 0x72,
+	CHANNEL_SWITCH_NOTIFICATION = 0x73,
+	REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
+	SPECTRUM_MEASURE_NOTIFICATION = 0x75,
+
+	/* Power Management */
+	POWER_TABLE_CMD = 0x77,
+	PM_SLEEP_NOTIFICATION = 0x7A,
+	PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
+
+	/* Scan commands and notifications */
+	REPLY_SCAN_CMD = 0x80,
+	REPLY_SCAN_ABORT_CMD = 0x81,
+	SCAN_START_NOTIFICATION = 0x82,
+	SCAN_RESULTS_NOTIFICATION = 0x83,
+	SCAN_COMPLETE_NOTIFICATION = 0x84,
+
+	/* IBSS/AP commands */
+	BEACON_NOTIFICATION = 0x90,
+	REPLY_TX_BEACON = 0x91,
+	WHO_IS_AWAKE_NOTIFICATION = 0x94,	/* not used */
+
+	/* Miscellaneous commands */
+	REPLY_TX_POWER_DBM_CMD = 0x95,
+	QUIET_NOTIFICATION = 0x96,		/* not used */
+	REPLY_TX_PWR_TABLE_CMD = 0x97,
+	REPLY_TX_POWER_DBM_CMD_V1 = 0x98,	/* old version of API */
+	TX_ANT_CONFIGURATION_CMD = 0x98,
+	MEASURE_ABORT_NOTIFICATION = 0x99,	/* not used */
+
+	/* Bluetooth device coexistence config command */
+	REPLY_BT_CONFIG = 0x9b,
+
+	/* Statistics */
+	REPLY_STATISTICS_CMD = 0x9c,
+	STATISTICS_NOTIFICATION = 0x9d,
+
+	/* RF-KILL commands and notifications */
+	REPLY_CARD_STATE_CMD = 0xa0,
+	CARD_STATE_NOTIFICATION = 0xa1,
+
+	/* Missed beacons notification */
+	MISSED_BEACONS_NOTIFICATION = 0xa2,
+
+	REPLY_CT_KILL_CONFIG_CMD = 0xa4,
+	SENSITIVITY_CMD = 0xa8,
+	REPLY_PHY_CALIBRATION_CMD = 0xb0,
+	REPLY_RX_PHY_CMD = 0xc0,
+	REPLY_RX_MPDU_CMD = 0xc1,
+	REPLY_RX = 0xc3,
+	REPLY_COMPRESSED_BA = 0xc5,
+
+	/* BT Coex */
+	REPLY_BT_COEX_PRIO_TABLE = 0xcc,
+	REPLY_BT_COEX_PROT_ENV = 0xcd,
+	REPLY_BT_COEX_PROFILE_NOTIF = 0xce,
+
+	/* PAN commands */
+	REPLY_WIPAN_PARAMS = 0xb2,
+	REPLY_WIPAN_RXON = 0xb3,	/* use REPLY_RXON structure */
+	REPLY_WIPAN_RXON_TIMING = 0xb4,	/* use REPLY_RXON_TIMING structure */
+	REPLY_WIPAN_RXON_ASSOC = 0xb6,	/* use REPLY_RXON_ASSOC structure */
+	REPLY_WIPAN_QOS_PARAM = 0xb7,	/* use REPLY_QOS_PARAM structure */
+	REPLY_WIPAN_WEPKEY = 0xb8,	/* use REPLY_WEPKEY structure */
+	REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9,
+	REPLY_WIPAN_NOA_NOTIFICATION = 0xbc,
+	REPLY_WIPAN_DEACTIVATION_COMPLETE = 0xbd,
+
+	REPLY_WOWLAN_PATTERNS = 0xe0,
+	REPLY_WOWLAN_WAKEUP_FILTER = 0xe1,
+	REPLY_WOWLAN_TSC_RSC_PARAMS = 0xe2,
+	REPLY_WOWLAN_TKIP_PARAMS = 0xe3,
+	REPLY_WOWLAN_KEK_KCK_MATERIAL = 0xe4,
+	REPLY_WOWLAN_GET_STATUS = 0xe5,
+	REPLY_D3_CONFIG = 0xd3,
+
+	REPLY_MAX = 0xff
+};
+
+/******************************************************************************
+ * (0)
+ * Commonly used structures and definitions:
+ * Command header, rate_n_flags, txpower
+ *
+ *****************************************************************************/
+
+/**
+ * iwlagn rate_n_flags bit fields
+ *
+ * rate_n_flags format is used in following iwlagn commands:
+ *  REPLY_RX (response only)
+ *  REPLY_RX_MPDU (response only)
+ *  REPLY_TX (both command and response)
+ *  REPLY_TX_LINK_QUALITY_CMD
+ *
+ * High-throughput (HT) rate format for bits 7:0 (bit 8 must be "1"):
+ *  2-0:  0)   6 Mbps
+ *        1)  12 Mbps
+ *        2)  18 Mbps
+ *        3)  24 Mbps
+ *        4)  36 Mbps
+ *        5)  48 Mbps
+ *        6)  54 Mbps
+ *        7)  60 Mbps
+ *
+ *  4-3:  0)  Single stream (SISO)
+ *        1)  Dual stream (MIMO)
+ *        2)  Triple stream (MIMO)
+ *
+ *    5:  Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data
+ *
+ * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"):
+ *  3-0:  0xD)   6 Mbps
+ *        0xF)   9 Mbps
+ *        0x5)  12 Mbps
+ *        0x7)  18 Mbps
+ *        0x9)  24 Mbps
+ *        0xB)  36 Mbps
+ *        0x1)  48 Mbps
+ *        0x3)  54 Mbps
+ *
+ * Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"):
+ *  6-0:   10)  1 Mbps
+ *         20)  2 Mbps
+ *         55)  5.5 Mbps
+ *        110)  11 Mbps
+ */
+#define RATE_MCS_CODE_MSK 0x7
+#define RATE_MCS_SPATIAL_POS 3
+#define RATE_MCS_SPATIAL_MSK 0x18
+#define RATE_MCS_HT_DUP_POS 5
+#define RATE_MCS_HT_DUP_MSK 0x20
+/* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */
+#define RATE_MCS_RATE_MSK 0xff
+
+/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */
+#define RATE_MCS_FLAGS_POS 8
+#define RATE_MCS_HT_POS 8
+#define RATE_MCS_HT_MSK 0x100
+
+/* Bit 9: (1) CCK, (0) OFDM.  HT (bit 8) must be "0" for this bit to be valid */
+#define RATE_MCS_CCK_POS 9
+#define RATE_MCS_CCK_MSK 0x200
+
+/* Bit 10: (1) Use Green Field preamble */
+#define RATE_MCS_GF_POS 10
+#define RATE_MCS_GF_MSK 0x400
+
+/* Bit 11: (1) Use 40Mhz HT40 chnl width, (0) use 20 MHz legacy chnl width */
+#define RATE_MCS_HT40_POS 11
+#define RATE_MCS_HT40_MSK 0x800
+
+/* Bit 12: (1) Duplicate data on both 20MHz chnls. HT40 (bit 11) must be set. */
+#define RATE_MCS_DUP_POS 12
+#define RATE_MCS_DUP_MSK 0x1000
+
+/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */
+#define RATE_MCS_SGI_POS 13
+#define RATE_MCS_SGI_MSK 0x2000
+
+/**
+ * rate_n_flags Tx antenna masks
+ * 4965 has 2 transmitters
+ * 5100 has 1 transmitter B
+ * 5150 has 1 transmitter A
+ * 5300 has 3 transmitters
+ * 5350 has 3 transmitters
+ * bit14:16
+ */
+#define RATE_MCS_ANT_POS	14
+#define RATE_MCS_ANT_A_MSK	0x04000
+#define RATE_MCS_ANT_B_MSK	0x08000
+#define RATE_MCS_ANT_C_MSK	0x10000
+#define RATE_MCS_ANT_AB_MSK	(RATE_MCS_ANT_A_MSK | RATE_MCS_ANT_B_MSK)
+#define RATE_MCS_ANT_ABC_MSK	(RATE_MCS_ANT_AB_MSK | RATE_MCS_ANT_C_MSK)
+#define RATE_ANT_NUM 3
+
+#define POWER_TABLE_NUM_ENTRIES			33
+#define POWER_TABLE_NUM_HT_OFDM_ENTRIES		32
+#define POWER_TABLE_CCK_ENTRY			32
+
+#define IWL_PWR_NUM_HT_OFDM_ENTRIES		24
+#define IWL_PWR_CCK_ENTRIES			2
+
+/**
+ * struct tx_power_dual_stream
+ *
+ * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ *
+ * Same format as iwl_tx_power_dual_stream, but __le32
+ */
+struct tx_power_dual_stream {
+	__le32 dw;
+} __packed;
+
+/**
+ * Command REPLY_TX_POWER_DBM_CMD = 0x98
+ * struct iwlagn_tx_power_dbm_cmd
+ */
+#define IWLAGN_TX_POWER_AUTO 0x7f
+#define IWLAGN_TX_POWER_NO_CLOSED (0x1 << 6)
+
+struct iwlagn_tx_power_dbm_cmd {
+	s8 global_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
+	u8 flags;
+	s8 srv_chan_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
+	u8 reserved;
+} __packed;
+
+/**
+ * Command TX_ANT_CONFIGURATION_CMD = 0x98
+ * This command is used to configure valid Tx antenna.
+ * By default uCode concludes the valid antenna according to the radio flavor.
+ * This command enables the driver to override/modify this conclusion.
+ */
+struct iwl_tx_ant_config_cmd {
+	__le32 valid;
+} __packed;
+
+/******************************************************************************
+ * (0a)
+ * Alive and Error Commands & Responses:
+ *
+ *****************************************************************************/
+
+#define UCODE_VALID_OK	cpu_to_le32(0x1)
+
+/**
+ * REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "alive" notification once the runtime image is ready
+ * to receive commands from the driver.  This is the *second* "alive"
+ * notification that the driver will receive after rebooting uCode;
+ * this "alive" is indicated by subtype field != 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
+ *
+ * This response includes two pointers to structures within the device's
+ * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging:
+ *
+ * 1)  log_event_table_ptr indicates base of the event log.  This traces
+ *     a 256-entry history of uCode execution within a circular buffer.
+ *     Its header format is:
+ *
+ *	__le32 log_size;     log capacity (in number of entries)
+ *	__le32 type;         (1) timestamp with each entry, (0) no timestamp
+ *	__le32 wraps;        # times uCode has wrapped to top of circular buffer
+ *      __le32 write_index;  next circular buffer entry that uCode would fill
+ *
+ *     The header is followed by the circular buffer of log entries.  Entries
+ *     with timestamps have the following format:
+ *
+ *	__le32 event_id;     range 0 - 1500
+ *	__le32 timestamp;    low 32 bits of TSF (of network, if associated)
+ *	__le32 data;         event_id-specific data value
+ *
+ *     Entries without timestamps contain only event_id and data.
+ *
+ *
+ * 2)  error_event_table_ptr indicates base of the error log.  This contains
+ *     information about any uCode error that occurs.  For agn, the format
+ *     of the error log is defined by struct iwl_error_event_table.
+ *
+ * The Linux driver can print both logs to the system log when a uCode error
+ * occurs.
+ */
+
+/*
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_error_event_table {
+	u32 valid;		/* (nonzero) valid, (0) log is empty */
+	u32 error_id;		/* type of error */
+	u32 pc;			/* program counter */
+	u32 blink1;		/* branch link */
+	u32 blink2;		/* branch link */
+	u32 ilink1;		/* interrupt link */
+	u32 ilink2;		/* interrupt link */
+	u32 data1;		/* error-specific data */
+	u32 data2;		/* error-specific data */
+	u32 line;		/* source code line of error */
+	u32 bcon_time;		/* beacon timer */
+	u32 tsf_low;		/* network timestamp function timer */
+	u32 tsf_hi;		/* network timestamp function timer */
+	u32 gp1;		/* GP1 timer register */
+	u32 gp2;		/* GP2 timer register */
+	u32 gp3;		/* GP3 timer register */
+	u32 ucode_ver;		/* uCode version */
+	u32 hw_ver;		/* HW Silicon version */
+	u32 brd_ver;		/* HW board version */
+	u32 log_pc;		/* log program counter */
+	u32 frame_ptr;		/* frame pointer */
+	u32 stack_ptr;		/* stack pointer */
+	u32 hcmd;		/* last host command header */
+	u32 isr0;		/* isr status register LMPM_NIC_ISR0:
+				 * rxtx_flag */
+	u32 isr1;		/* isr status register LMPM_NIC_ISR1:
+				 * host_flag */
+	u32 isr2;		/* isr status register LMPM_NIC_ISR2:
+				 * enc_flag */
+	u32 isr3;		/* isr status register LMPM_NIC_ISR3:
+				 * time_flag */
+	u32 isr4;		/* isr status register LMPM_NIC_ISR4:
+				 * wico interrupt */
+	u32 isr_pref;		/* isr status register LMPM_NIC_PREF_STAT */
+	u32 wait_event;		/* wait event() caller address */
+	u32 l2p_control;	/* L2pControlField */
+	u32 l2p_duration;	/* L2pDurationField */
+	u32 l2p_mhvalid;	/* L2pMhValidBits */
+	u32 l2p_addr_match;	/* L2pAddrMatchStat */
+	u32 lmpm_pmg_sel;	/* indicate which clocks are turned on
+				 * (LMPM_PMG_SEL) */
+	u32 u_timestamp;	/* indicate when the date and time of the
+				 * compilation */
+	u32 flow_handler;	/* FH read/write pointers, RX credit */
+} __packed;
+
+struct iwl_alive_resp {
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 reserved1;
+	u8 sw_rev[8];
+	u8 ver_type;
+	u8 ver_subtype;			/* not "9" for runtime alive */
+	__le16 reserved2;
+	__le32 log_event_table_ptr;	/* SRAM address for event log */
+	__le32 error_event_table_ptr;	/* SRAM address for error log */
+	__le32 timestamp;
+	__le32 is_valid;
+} __packed;
+
+/*
+ * REPLY_ERROR = 0x2 (response only, not a command)
+ */
+struct iwl_error_resp {
+	__le32 error_type;
+	u8 cmd_id;
+	u8 reserved1;
+	__le16 bad_cmd_seq_num;
+	__le32 error_info;
+	__le64 timestamp;
+} __packed;
+
+/******************************************************************************
+ * (1)
+ * RXON Commands & Responses:
+ *
+ *****************************************************************************/
+
+/*
+ * Rx config defines & structure
+ */
+/* rx_config device types  */
+enum {
+	RXON_DEV_TYPE_AP = 1,
+	RXON_DEV_TYPE_ESS = 3,
+	RXON_DEV_TYPE_IBSS = 4,
+	RXON_DEV_TYPE_SNIFFER = 6,
+	RXON_DEV_TYPE_CP = 7,
+	RXON_DEV_TYPE_2STA = 8,
+	RXON_DEV_TYPE_P2P = 9,
+};
+
+
+#define RXON_RX_CHAIN_DRIVER_FORCE_MSK		cpu_to_le16(0x1 << 0)
+#define RXON_RX_CHAIN_DRIVER_FORCE_POS		(0)
+#define RXON_RX_CHAIN_VALID_MSK			cpu_to_le16(0x7 << 1)
+#define RXON_RX_CHAIN_VALID_POS			(1)
+#define RXON_RX_CHAIN_FORCE_SEL_MSK		cpu_to_le16(0x7 << 4)
+#define RXON_RX_CHAIN_FORCE_SEL_POS		(4)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK	cpu_to_le16(0x7 << 7)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS	(7)
+#define RXON_RX_CHAIN_CNT_MSK			cpu_to_le16(0x3 << 10)
+#define RXON_RX_CHAIN_CNT_POS			(10)
+#define RXON_RX_CHAIN_MIMO_CNT_MSK		cpu_to_le16(0x3 << 12)
+#define RXON_RX_CHAIN_MIMO_CNT_POS		(12)
+#define RXON_RX_CHAIN_MIMO_FORCE_MSK		cpu_to_le16(0x1 << 14)
+#define RXON_RX_CHAIN_MIMO_FORCE_POS		(14)
+
+/* rx_config flags */
+/* band & modulation selection */
+#define RXON_FLG_BAND_24G_MSK           cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK                cpu_to_le32(1 << 1)
+/* auto detection enable */
+#define RXON_FLG_AUTO_DETECT_MSK        cpu_to_le32(1 << 2)
+/* TGg protection when tx */
+#define RXON_FLG_TGG_PROTECT_MSK        cpu_to_le32(1 << 3)
+/* cck short slot & preamble */
+#define RXON_FLG_SHORT_SLOT_MSK          cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK     cpu_to_le32(1 << 5)
+/* antenna selection */
+#define RXON_FLG_DIS_DIV_MSK            cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK            cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK              cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK              cpu_to_le32(1 << 9)
+/* radar detection enable */
+#define RXON_FLG_RADAR_DETECT_MSK       cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK    cpu_to_le32(1 << 13)
+/* rx response to host with 8-byte TSF
+* (according to ON_AIR deassertion) */
+#define RXON_FLG_TSF2HOST_MSK           cpu_to_le32(1 << 15)
+
+
+/* HT flags */
+#define RXON_FLG_CTRL_CHANNEL_LOC_POS		(22)
+#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK	cpu_to_le32(0x1 << 22)
+
+#define RXON_FLG_HT_OPERATING_MODE_POS		(23)
+
+#define RXON_FLG_HT_PROT_MSK			cpu_to_le32(0x1 << 23)
+#define RXON_FLG_HT40_PROT_MSK			cpu_to_le32(0x2 << 23)
+
+#define RXON_FLG_CHANNEL_MODE_POS		(25)
+#define RXON_FLG_CHANNEL_MODE_MSK		cpu_to_le32(0x3 << 25)
+
+/* channel mode */
+enum {
+	CHANNEL_MODE_LEGACY = 0,
+	CHANNEL_MODE_PURE_40 = 1,
+	CHANNEL_MODE_MIXED = 2,
+	CHANNEL_MODE_RESERVED = 3,
+};
+#define RXON_FLG_CHANNEL_MODE_LEGACY	cpu_to_le32(CHANNEL_MODE_LEGACY << RXON_FLG_CHANNEL_MODE_POS)
+#define RXON_FLG_CHANNEL_MODE_PURE_40	cpu_to_le32(CHANNEL_MODE_PURE_40 << RXON_FLG_CHANNEL_MODE_POS)
+#define RXON_FLG_CHANNEL_MODE_MIXED	cpu_to_le32(CHANNEL_MODE_MIXED << RXON_FLG_CHANNEL_MODE_POS)
+
+/* CTS to self (if spec allows) flag */
+#define RXON_FLG_SELF_CTS_EN			cpu_to_le32(0x1<<30)
+
+/* rx_config filter flags */
+/* accept all data frames */
+#define RXON_FILTER_PROMISC_MSK         cpu_to_le32(1 << 0)
+/* pass control & management to host */
+#define RXON_FILTER_CTL2HOST_MSK        cpu_to_le32(1 << 1)
+/* accept multi-cast */
+#define RXON_FILTER_ACCEPT_GRP_MSK      cpu_to_le32(1 << 2)
+/* don't decrypt uni-cast frames */
+#define RXON_FILTER_DIS_DECRYPT_MSK     cpu_to_le32(1 << 3)
+/* don't decrypt multi-cast frames */
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4)
+/* STA is associated */
+#define RXON_FILTER_ASSOC_MSK           cpu_to_le32(1 << 5)
+/* transfer to host non bssid beacons in associated state */
+#define RXON_FILTER_BCON_AWARE_MSK      cpu_to_le32(1 << 6)
+
+/**
+ * REPLY_RXON = 0x10 (command, has simple generic response)
+ *
+ * RXON tunes the radio tuner to a service channel, and sets up a number
+ * of parameters that are used primarily for Rx, but also for Tx operations.
+ *
+ * NOTE:  When tuning to a new channel, driver must set the
+ *        RXON_FILTER_ASSOC_MSK to 0.  This will clear station-dependent
+ *        info within the device, including the station tables, tx retry
+ *        rate tables, and txpower tables.  Driver must build a new station
+ *        table and txpower table before transmitting anything on the RXON
+ *        channel.
+ *
+ * NOTE:  All RXONs wipe clean the internal txpower table.  Driver must
+ *        issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10),
+ *        regardless of whether RXON_FILTER_ASSOC_MSK is set.
+ */
+
+struct iwl_rxon_cmd {
+	u8 node_addr[6];
+	__le16 reserved1;
+	u8 bssid_addr[6];
+	__le16 reserved2;
+	u8 wlap_bssid_addr[6];
+	__le16 reserved3;
+	u8 dev_type;
+	u8 air_propagation;
+	__le16 rx_chain;
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+	__le16 assoc_id;
+	__le32 flags;
+	__le32 filter_flags;
+	__le16 channel;
+	u8 ofdm_ht_single_stream_basic_rates;
+	u8 ofdm_ht_dual_stream_basic_rates;
+	u8 ofdm_ht_triple_stream_basic_rates;
+	u8 reserved5;
+	__le16 acquisition_data;
+	__le16 reserved6;
+} __packed;
+
+/*
+ * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
+ */
+struct iwl_rxon_assoc_cmd {
+	__le32 flags;
+	__le32 filter_flags;
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+	__le16 reserved1;
+	u8 ofdm_ht_single_stream_basic_rates;
+	u8 ofdm_ht_dual_stream_basic_rates;
+	u8 ofdm_ht_triple_stream_basic_rates;
+	u8 reserved2;
+	__le16 rx_chain_select_flags;
+	__le16 acquisition_data;
+	__le32 reserved3;
+} __packed;
+
+#define IWL_CONN_MAX_LISTEN_INTERVAL	10
+#define IWL_MAX_UCODE_BEACON_INTERVAL	4 /* 4096 */
+
+/*
+ * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
+ */
+struct iwl_rxon_time_cmd {
+	__le64 timestamp;
+	__le16 beacon_interval;
+	__le16 atim_window;
+	__le32 beacon_init_val;
+	__le16 listen_interval;
+	u8 dtim_period;
+	u8 delta_cp_bss_tbtts;
+} __packed;
+
+/*
+ * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
+ */
+/**
+ * struct iwl5000_channel_switch_cmd
+ * @band: 0- 5.2GHz, 1- 2.4GHz
+ * @expect_beacon: 0- resume transmits after channel switch
+ *		   1- wait for beacon to resume transmits
+ * @channel: new channel number
+ * @rxon_flags: Rx on flags
+ * @rxon_filter_flags: filtering parameters
+ * @switch_time: switch time in extended beacon format
+ * @reserved: reserved bytes
+ */
+struct iwl5000_channel_switch_cmd {
+	u8 band;
+	u8 expect_beacon;
+	__le16 channel;
+	__le32 rxon_flags;
+	__le32 rxon_filter_flags;
+	__le32 switch_time;
+	__le32 reserved[2][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
+} __packed;
+
+/**
+ * struct iwl6000_channel_switch_cmd
+ * @band: 0- 5.2GHz, 1- 2.4GHz
+ * @expect_beacon: 0- resume transmits after channel switch
+ *		   1- wait for beacon to resume transmits
+ * @channel: new channel number
+ * @rxon_flags: Rx on flags
+ * @rxon_filter_flags: filtering parameters
+ * @switch_time: switch time in extended beacon format
+ * @reserved: reserved bytes
+ */
+struct iwl6000_channel_switch_cmd {
+	u8 band;
+	u8 expect_beacon;
+	__le16 channel;
+	__le32 rxon_flags;
+	__le32 rxon_filter_flags;
+	__le32 switch_time;
+	__le32 reserved[3][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
+} __packed;
+
+/*
+ * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
+ */
+struct iwl_csa_notification {
+	__le16 band;
+	__le16 channel;
+	__le32 status;		/* 0 - OK, 1 - fail */
+} __packed;
+
+/******************************************************************************
+ * (2)
+ * Quality-of-Service (QOS) Commands & Responses:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM
+ * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd
+ *
+ * @cw_min: Contention window, start value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x0f.
+ * @cw_max: Contention window, max value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x3f.
+ * @aifsn:  Number of slots in Arbitration Interframe Space (before
+ *          performing random backoff timing prior to Tx).  Device default 1.
+ * @edca_txop:  Length of Tx opportunity, in uSecs.  Device default is 0.
+ *
+ * Device will automatically increase contention window by (2*CW) + 1 for each
+ * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
+ * value, to cap the CW value.
+ */
+struct iwl_ac_qos {
+	__le16 cw_min;
+	__le16 cw_max;
+	u8 aifsn;
+	u8 reserved1;
+	__le16 edca_txop;
+} __packed;
+
+/* QoS flags defines */
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK	cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK		cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK	cpu_to_le32(0x10)
+
+/* Number of Access Categories (AC) (EDCA), queues 0..3 */
+#define AC_NUM                4
+
+/*
+ * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
+ *
+ * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
+ * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
+ */
+struct iwl_qosparam_cmd {
+	__le32 qos_flags;
+	struct iwl_ac_qos ac[AC_NUM];
+} __packed;
+
+/******************************************************************************
+ * (3)
+ * Add/Modify Stations Commands & Responses:
+ *
+ *****************************************************************************/
+/*
+ * Multi station support
+ */
+
+/* Special, dedicated locations within device's station table */
+#define	IWL_AP_ID		0
+#define	IWL_AP_ID_PAN		1
+#define	IWL_STA_ID		2
+#define IWLAGN_PAN_BCAST_ID	14
+#define IWLAGN_BROADCAST_ID	15
+#define	IWLAGN_STATION_COUNT	16
+
+#define	IWL_INVALID_STATION 	255
+#define IWL_MAX_TID_COUNT	8
+#define IWL_TID_NON_QOS IWL_MAX_TID_COUNT
+
+#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_PAN_STATION		cpu_to_le32(1 << 13)
+#define STA_FLG_RTS_MIMO_PROT_MSK	cpu_to_le32(1 << 17)
+#define STA_FLG_AGG_MPDU_8US_MSK	cpu_to_le32(1 << 18)
+#define STA_FLG_MAX_AGG_SIZE_POS	(19)
+#define STA_FLG_MAX_AGG_SIZE_MSK	cpu_to_le32(3 << 19)
+#define STA_FLG_HT40_EN_MSK		cpu_to_le32(1 << 21)
+#define STA_FLG_MIMO_DIS_MSK		cpu_to_le32(1 << 22)
+#define STA_FLG_AGG_MPDU_DENSITY_POS	(23)
+#define STA_FLG_AGG_MPDU_DENSITY_MSK	cpu_to_le32(7 << 23)
+
+/* Use in mode field.  1: modify existing entry, 0: add new station entry */
+#define STA_CONTROL_MODIFY_MSK		0x01
+
+/* key flags __le16*/
+#define STA_KEY_FLG_ENCRYPT_MSK	cpu_to_le16(0x0007)
+#define STA_KEY_FLG_NO_ENC	cpu_to_le16(0x0000)
+#define STA_KEY_FLG_WEP		cpu_to_le16(0x0001)
+#define STA_KEY_FLG_CCMP	cpu_to_le16(0x0002)
+#define STA_KEY_FLG_TKIP	cpu_to_le16(0x0003)
+
+#define STA_KEY_FLG_KEYID_POS	8
+#define STA_KEY_FLG_INVALID 	cpu_to_le16(0x0800)
+/* wep key is either from global key (0) or from station info array (1) */
+#define STA_KEY_FLG_MAP_KEY_MSK	cpu_to_le16(0x0008)
+
+/* wep key in STA: 5-bytes (0) or 13-bytes (1) */
+#define STA_KEY_FLG_KEY_SIZE_MSK     cpu_to_le16(0x1000)
+#define STA_KEY_MULTICAST_MSK        cpu_to_le16(0x4000)
+#define STA_KEY_MAX_NUM		8
+#define STA_KEY_MAX_NUM_PAN	16
+/* must not match WEP_INVALID_OFFSET */
+#define IWLAGN_HW_KEY_DEFAULT	0xfe
+
+/* Flags indicate whether to modify vs. don't change various station params */
+#define	STA_MODIFY_KEY_MASK		0x01
+#define	STA_MODIFY_TID_DISABLE_TX	0x02
+#define	STA_MODIFY_TX_RATE_MSK		0x04
+#define STA_MODIFY_ADDBA_TID_MSK	0x08
+#define STA_MODIFY_DELBA_TID_MSK	0x10
+#define STA_MODIFY_SLEEP_TX_COUNT_MSK	0x20
+
+/* Receiver address (actually, Rx station's index into station table),
+ * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
+#define BUILD_RAxTID(sta_id, tid)	(((sta_id) << 4) + (tid))
+
+/* agn */
+struct iwl_keyinfo {
+	__le16 key_flags;
+	u8 tkip_rx_tsc_byte2;	/* TSC[2] for key mix ph1 detection */
+	u8 reserved1;
+	__le16 tkip_rx_ttak[5];	/* 10-byte unicast TKIP TTAK */
+	u8 key_offset;
+	u8 reserved2;
+	u8 key[16];		/* 16-byte unicast decryption key */
+	__le64 tx_secur_seq_cnt;
+	__le64 hw_tkip_mic_rx_key;
+	__le64 hw_tkip_mic_tx_key;
+} __packed;
+
+/**
+ * struct sta_id_modify
+ * @addr[ETH_ALEN]: station's MAC address
+ * @sta_id: index of station in uCode's station table
+ * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change
+ *
+ * Driver selects unused table index when adding new station,
+ * or the index to a pre-existing station entry when modifying that station.
+ * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP).
+ *
+ * modify_mask flags select which parameters to modify vs. leave alone.
+ */
+struct sta_id_modify {
+	u8 addr[ETH_ALEN];
+	__le16 reserved1;
+	u8 sta_id;
+	u8 modify_mask;
+	__le16 reserved2;
+} __packed;
+
+/*
+ * REPLY_ADD_STA = 0x18 (command)
+ *
+ * The device contains an internal table of per-station information,
+ * with info on security keys, aggregation parameters, and Tx rates for
+ * initial Tx attempt and any retries (agn devices uses
+ * REPLY_TX_LINK_QUALITY_CMD,
+ *
+ * REPLY_ADD_STA sets up the table entry for one station, either creating
+ * a new entry, or modifying a pre-existing one.
+ *
+ * NOTE:  RXON command (without "associated" bit set) wipes the station table
+ *        clean.  Moving into RF_KILL state does this also.  Driver must set up
+ *        new station table before transmitting anything on the RXON channel
+ *        (except active scans or active measurements; those commands carry
+ *        their own txpower/rate setup data).
+ *
+ *        When getting started on a new channel, driver must set up the
+ *        IWL_BROADCAST_ID entry (last entry in the table).  For a client
+ *        station in a BSS, once an AP is selected, driver sets up the AP STA
+ *        in the IWL_AP_ID entry (1st entry in the table).  BROADCAST and AP
+ *        are all that are needed for a BSS client station.  If the device is
+ *        used as AP, or in an IBSS network, driver must set up station table
+ *        entries for all STAs in network, starting with index IWL_STA_ID.
+ */
+
+struct iwl_addsta_cmd {
+	u8 mode;		/* 1: modify existing, 0: add new station */
+	u8 reserved[3];
+	struct sta_id_modify sta;
+	struct iwl_keyinfo key;
+	__le32 station_flags;		/* STA_FLG_* */
+	__le32 station_flags_msk;	/* STA_FLG_* */
+
+	/* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
+	 * corresponding to bit (e.g. bit 5 controls TID 5).
+	 * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
+	__le16 tid_disable_tx;
+	__le16 legacy_reserved;
+
+	/* TID for which to add block-ack support.
+	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+	u8 add_immediate_ba_tid;
+
+	/* TID for which to remove block-ack support.
+	 * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
+	u8 remove_immediate_ba_tid;
+
+	/* 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;
+
+	/*
+	 * Number of packets OK to transmit to station even though
+	 * it is asleep -- used to synchronise PS-poll and u-APSD
+	 * responses while ucode keeps track of STA sleep state.
+	 */
+	__le16 sleep_tx_count;
+
+	__le16 reserved2;
+} __packed;
+
+
+#define ADD_STA_SUCCESS_MSK		0x1
+#define ADD_STA_NO_ROOM_IN_TABLE	0x2
+#define ADD_STA_NO_BLOCK_ACK_RESOURCE	0x4
+#define ADD_STA_MODIFY_NON_EXIST_STA	0x8
+/*
+ * REPLY_ADD_STA = 0x18 (response)
+ */
+struct iwl_add_sta_resp {
+	u8 status;	/* ADD_STA_* */
+} __packed;
+
+#define REM_STA_SUCCESS_MSK              0x1
+/*
+ *  REPLY_REM_STA = 0x19 (response)
+ */
+struct iwl_rem_sta_resp {
+	u8 status;
+} __packed;
+
+/*
+ *  REPLY_REM_STA = 0x19 (command)
+ */
+struct iwl_rem_sta_cmd {
+	u8 num_sta;     /* number of removed stations */
+	u8 reserved[3];
+	u8 addr[ETH_ALEN]; /* MAC addr of the first station */
+	u8 reserved2[2];
+} __packed;
+
+
+/* WiFi queues mask */
+#define IWL_SCD_BK_MSK			cpu_to_le32(BIT(0))
+#define IWL_SCD_BE_MSK			cpu_to_le32(BIT(1))
+#define IWL_SCD_VI_MSK			cpu_to_le32(BIT(2))
+#define IWL_SCD_VO_MSK			cpu_to_le32(BIT(3))
+#define IWL_SCD_MGMT_MSK		cpu_to_le32(BIT(3))
+
+/* PAN queues mask */
+#define IWL_PAN_SCD_BK_MSK		cpu_to_le32(BIT(4))
+#define IWL_PAN_SCD_BE_MSK		cpu_to_le32(BIT(5))
+#define IWL_PAN_SCD_VI_MSK		cpu_to_le32(BIT(6))
+#define IWL_PAN_SCD_VO_MSK		cpu_to_le32(BIT(7))
+#define IWL_PAN_SCD_MGMT_MSK		cpu_to_le32(BIT(7))
+#define IWL_PAN_SCD_MULTICAST_MSK	cpu_to_le32(BIT(8))
+
+#define IWL_AGG_TX_QUEUE_MSK		cpu_to_le32(0xffc00)
+
+#define IWL_DROP_SINGLE		0
+#define IWL_DROP_ALL		(BIT(IWL_RXON_CTX_BSS) | BIT(IWL_RXON_CTX_PAN))
+
+/*
+ * 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
+ */
+struct iwl_wep_key {
+	u8 key_index;
+	u8 key_offset;
+	u8 reserved1[2];
+	u8 key_size;
+	u8 reserved2[3];
+	u8 key[16];
+} __packed;
+
+struct iwl_wep_cmd {
+	u8 num_keys;
+	u8 global_key_type;
+	u8 flags;
+	u8 reserved;
+	struct iwl_wep_key key[0];
+} __packed;
+
+#define WEP_KEY_WEP_TYPE 1
+#define WEP_KEYS_MAX 4
+#define WEP_INVALID_OFFSET 0xff
+#define WEP_KEY_LEN_64 5
+#define WEP_KEY_LEN_128 13
+
+/******************************************************************************
+ * (4)
+ * Rx Responses:
+ *
+ *****************************************************************************/
+
+#define RX_RES_STATUS_NO_CRC32_ERROR	cpu_to_le32(1 << 0)
+#define RX_RES_STATUS_NO_RXE_OVERFLOW	cpu_to_le32(1 << 1)
+
+#define RX_RES_PHY_FLAGS_BAND_24_MSK	cpu_to_le16(1 << 0)
+#define RX_RES_PHY_FLAGS_MOD_CCK_MSK		cpu_to_le16(1 << 1)
+#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	cpu_to_le16(1 << 2)
+#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK	cpu_to_le16(1 << 3)
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK		0xf0
+#define RX_RES_PHY_FLAGS_ANTENNA_POS		4
+
+#define RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
+#define RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
+#define RX_RES_STATUS_SEC_TYPE_WEP	(0x1 << 8)
+#define RX_RES_STATUS_SEC_TYPE_CCMP	(0x2 << 8)
+#define RX_RES_STATUS_SEC_TYPE_TKIP	(0x3 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_ERR	(0x7 << 8)
+
+#define RX_RES_STATUS_STATION_FOUND	(1<<6)
+#define RX_RES_STATUS_NO_STATION_INFO_MISMATCH	(1<<7)
+
+#define RX_RES_STATUS_DECRYPT_TYPE_MSK	(0x3 << 11)
+#define RX_RES_STATUS_NOT_DECRYPT	(0x0 << 11)
+#define RX_RES_STATUS_DECRYPT_OK	(0x3 << 11)
+#define RX_RES_STATUS_BAD_ICV_MIC	(0x1 << 11)
+#define RX_RES_STATUS_BAD_KEY_TTAK	(0x2 << 11)
+
+#define RX_MPDU_RES_STATUS_ICV_OK	(0x20)
+#define RX_MPDU_RES_STATUS_MIC_OK	(0x40)
+#define RX_MPDU_RES_STATUS_TTAK_OK	(1 << 7)
+#define RX_MPDU_RES_STATUS_DEC_DONE_MSK	(0x800)
+
+
+#define IWLAGN_RX_RES_PHY_CNT 8
+#define IWLAGN_RX_RES_AGC_IDX     1
+#define IWLAGN_RX_RES_RSSI_AB_IDX 2
+#define IWLAGN_RX_RES_RSSI_C_IDX  3
+#define IWLAGN_OFDM_AGC_MSK 0xfe00
+#define IWLAGN_OFDM_AGC_BIT_POS 9
+#define IWLAGN_OFDM_RSSI_INBAND_A_BITMSK 0x00ff
+#define IWLAGN_OFDM_RSSI_ALLBAND_A_BITMSK 0xff00
+#define IWLAGN_OFDM_RSSI_A_BIT_POS 0
+#define IWLAGN_OFDM_RSSI_INBAND_B_BITMSK 0xff0000
+#define IWLAGN_OFDM_RSSI_ALLBAND_B_BITMSK 0xff000000
+#define IWLAGN_OFDM_RSSI_B_BIT_POS 16
+#define IWLAGN_OFDM_RSSI_INBAND_C_BITMSK 0x00ff
+#define IWLAGN_OFDM_RSSI_ALLBAND_C_BITMSK 0xff00
+#define IWLAGN_OFDM_RSSI_C_BIT_POS 0
+
+struct iwlagn_non_cfg_phy {
+	__le32 non_cfg_phy[IWLAGN_RX_RES_PHY_CNT];  /* up to 8 phy entries */
+} __packed;
+
+
+/*
+ * REPLY_RX = 0xc3 (response only, not a command)
+ * Used only for legacy (non 11n) frames.
+ */
+struct iwl_rx_phy_res {
+	u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
+	u8 cfg_phy_cnt;		/* configurable DSP phy data byte count */
+	u8 stat_id;		/* configurable DSP phy data set ID */
+	u8 reserved1;
+	__le64 timestamp;	/* TSF at on air rise */
+	__le32 beacon_time_stamp; /* beacon at on-air rise */
+	__le16 phy_flags;	/* general phy flags: band, modulation, ... */
+	__le16 channel;		/* channel number */
+	u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */
+	__le32 rate_n_flags;	/* RATE_MCS_* */
+	__le16 byte_count;	/* frame's byte-count */
+	__le16 frame_time;	/* frame's time on the air */
+} __packed;
+
+struct iwl_rx_mpdu_res_start {
+	__le16 byte_count;
+	__le16 reserved;
+} __packed;
+
+
+/******************************************************************************
+ * (5)
+ * Tx Commands & Responses:
+ *
+ * Driver must place each REPLY_TX command into one of the prioritized Tx
+ * queues in host DRAM, shared between driver and device (see comments for
+ * SCD registers and Tx/Rx Queues).  When the device's Tx scheduler and uCode
+ * are preparing to transmit, the device pulls the Tx command over the PCI
+ * bus via one of the device's Tx DMA channels, to fill an internal FIFO
+ * from which data will be transmitted.
+ *
+ * uCode handles all timing and protocol related to control frames
+ * (RTS/CTS/ACK), based on flags in the Tx command.  uCode and Tx scheduler
+ * handle reception of block-acks; uCode updates the host driver via
+ * REPLY_COMPRESSED_BA.
+ *
+ * uCode handles retrying Tx when an ACK is expected but not received.
+ * This includes trying lower data rates than the one requested in the Tx
+ * command, as set up by the REPLY_TX_LINK_QUALITY_CMD (agn).
+ *
+ * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
+ * This command must be executed after every RXON command, before Tx can occur.
+ *****************************************************************************/
+
+/* REPLY_TX Tx flags field */
+
+/*
+ * 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_PROT_REQUIRE_MSK cpu_to_le32(1 << 0)
+
+/* 1: Expect ACK from receiving station
+ * 0: Don't expect ACK (MAC header's duration field s/b 0)
+ * Set this for unicast frames, but not broadcast/multicast. */
+#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3)
+
+/* For agn devices:
+ * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
+ *    Tx command's initial_rate_index indicates first rate to try;
+ *    uCode walks through table for additional Tx attempts.
+ * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
+ *    This rate will be used for all Tx attempts; it will not be scaled. */
+#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4)
+
+/* 1: Expect immediate block-ack.
+ * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
+#define TX_CMD_FLG_IMM_BA_RSP_MASK  cpu_to_le32(1 << 6)
+
+/* Tx antenna selection field; reserved (0) for agn devices. */
+#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00)
+
+/* 1: Ignore Bluetooth priority for this frame.
+ * 0: Delay Tx until Bluetooth device is done (normal usage). */
+#define TX_CMD_FLG_IGNORE_BT cpu_to_le32(1 << 12)
+
+/* 1: uCode overrides sequence control field in MAC header.
+ * 0: Driver provides sequence control field in MAC header.
+ * Set this for management frames, non-QOS data frames, non-unicast frames,
+ * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
+#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13)
+
+/* 1: This frame is non-last MPDU; more fragments are coming.
+ * 0: Last fragment, or not using fragmentation. */
+#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14)
+
+/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
+ * 0: No TSF required in outgoing frame.
+ * Set this for transmitting beacons and probe responses. */
+#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16)
+
+/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
+ *    alignment of frame's payload data field.
+ * 0: No pad
+ * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
+ * field (but not both).  Driver must align frame data (i.e. data following
+ * MAC header) to DWORD boundary. */
+#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20)
+
+/* accelerate aggregation support
+ * 0 - no CCMP encryption; 1 - CCMP encryption */
+#define TX_CMD_FLG_AGG_CCMP_MSK cpu_to_le32(1 << 22)
+
+/* HCCA-AP - disable duration overwriting. */
+#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25)
+
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP  	0x01
+#define TX_CMD_SEC_CCM  	0x02
+#define TX_CMD_SEC_TKIP		0x03
+#define TX_CMD_SEC_MSK		0x03
+#define TX_CMD_SEC_SHIFT	6
+#define TX_CMD_SEC_KEY128	0x08
+
+/*
+ * security overhead sizes
+ */
+#define WEP_IV_LEN 4
+#define WEP_ICV_LEN 4
+#define CCMP_MIC_LEN 8
+#define TKIP_ICV_LEN 4
+
+/*
+ * REPLY_TX = 0x1c (command)
+ */
+
+/*
+ * 4965 uCode updates these Tx attempt count values in host DRAM.
+ * Used for managing Tx retries when expecting block-acks.
+ * Driver should set these fields to 0.
+ */
+struct iwl_dram_scratch {
+	u8 try_cnt;		/* Tx attempts */
+	u8 bt_kill_cnt;		/* Tx attempts blocked by Bluetooth device */
+	__le16 reserved;
+} __packed;
+
+struct iwl_tx_cmd {
+	/*
+	 * MPDU byte count:
+	 * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
+	 * + 8 byte IV for CCM or TKIP (not used for WEP)
+	 * + Data payload
+	 * + 8-byte MIC (not used for CCM/WEP)
+	 * NOTE:  Does not include Tx command bytes, post-MAC pad bytes,
+	 *        MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
+	 * Range: 14-2342 bytes.
+	 */
+	__le16 len;
+
+	/*
+	 * MPDU or MSDU byte count for next frame.
+	 * Used for fragmentation and bursting, but not 11n aggregation.
+	 * Same as "len", but for next frame.  Set to 0 if not applicable.
+	 */
+	__le16 next_frame_len;
+
+	__le32 tx_flags;	/* TX_CMD_FLG_* */
+
+	/* uCode may modify this field of the Tx command (in host DRAM!).
+	 * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */
+	struct iwl_dram_scratch scratch;
+
+	/* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */
+	__le32 rate_n_flags;	/* RATE_MCS_* */
+
+	/* Index of destination station in uCode's station table */
+	u8 sta_id;
+
+	/* Type of security encryption:  CCM or TKIP */
+	u8 sec_ctl;		/* TX_CMD_SEC_* */
+
+	/*
+	 * Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial
+	 * Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set.  Normally "0" for
+	 * data frames, this field may be used to selectively reduce initial
+	 * rate (via non-0 value) for special frames (e.g. management), while
+	 * still supporting rate scaling for all frames.
+	 */
+	u8 initial_rate_index;
+	u8 reserved;
+	u8 key[16];
+	__le16 next_frame_flags;
+	__le16 reserved2;
+	union {
+		__le32 life_time;
+		__le32 attempt;
+	} stop_time;
+
+	/* Host DRAM physical address pointer to "scratch" in this command.
+	 * Must be dword aligned.  "0" in dram_lsb_ptr disables usage. */
+	__le32 dram_lsb_ptr;
+	u8 dram_msb_ptr;
+
+	u8 rts_retry_limit;	/*byte 50 */
+	u8 data_retry_limit;	/*byte 51 */
+	u8 tid_tspec;
+	union {
+		__le16 pm_frame_timeout;
+		__le16 attempt_duration;
+	} timeout;
+
+	/*
+	 * Duration of EDCA burst Tx Opportunity, in 32-usec units.
+	 * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
+	 */
+	__le16 driver_txop;
+
+	/*
+	 * MAC header goes here, followed by 2 bytes padding if MAC header
+	 * length is 26 or 30 bytes, followed by payload data
+	 */
+	u8 payload[0];
+	struct ieee80211_hdr hdr[0];
+} __packed;
+
+/*
+ * TX command response is sent after *agn* transmission attempts.
+ *
+ * both postpone and abort status are expected behavior from uCode. there is
+ * no special operation required from driver; except for RFKILL_FLUSH,
+ * which required tx flush host command to flush all the tx frames in queues
+ */
+enum {
+	TX_STATUS_SUCCESS = 0x01,
+	TX_STATUS_DIRECT_DONE = 0x02,
+	/* postpone TX */
+	TX_STATUS_POSTPONE_DELAY = 0x40,
+	TX_STATUS_POSTPONE_FEW_BYTES = 0x41,
+	TX_STATUS_POSTPONE_BT_PRIO = 0x42,
+	TX_STATUS_POSTPONE_QUIET_PERIOD = 0x43,
+	TX_STATUS_POSTPONE_CALC_TTAK = 0x44,
+	/* abort TX */
+	TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY = 0x81,
+	TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
+	TX_STATUS_FAIL_LONG_LIMIT = 0x83,
+	TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
+	TX_STATUS_FAIL_DRAIN_FLOW = 0x85,
+	TX_STATUS_FAIL_RFKILL_FLUSH = 0x86,
+	TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+	TX_STATUS_FAIL_DEST_PS = 0x88,
+	TX_STATUS_FAIL_HOST_ABORTED = 0x89,
+	TX_STATUS_FAIL_BT_RETRY = 0x8a,
+	TX_STATUS_FAIL_STA_INVALID = 0x8b,
+	TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+	TX_STATUS_FAIL_TID_DISABLE = 0x8d,
+	TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e,
+	TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
+	TX_STATUS_FAIL_PASSIVE_NO_RX = 0x90,
+	TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+};
+
+#define	TX_PACKET_MODE_REGULAR		0x0000
+#define	TX_PACKET_MODE_BURST_SEQ	0x0100
+#define	TX_PACKET_MODE_BURST_FIRST	0x0200
+
+enum {
+	TX_POWER_PA_NOT_ACTIVE = 0x0,
+};
+
+enum {
+	TX_STATUS_MSK = 0x000000ff,		/* bits 0:7 */
+	TX_STATUS_DELAY_MSK = 0x00000040,
+	TX_STATUS_ABORT_MSK = 0x00000080,
+	TX_PACKET_MODE_MSK = 0x0000ff00,	/* bits 8:15 */
+	TX_FIFO_NUMBER_MSK = 0x00070000,	/* bits 16:18 */
+	TX_RESERVED = 0x00780000,		/* bits 19:22 */
+	TX_POWER_PA_DETECT_MSK = 0x7f800000,	/* bits 23:30 */
+	TX_ABORT_REQUIRED_MSK = 0x80000000,	/* bits 31:31 */
+};
+
+/* *******************************
+ * TX aggregation status
+ ******************************* */
+
+enum {
+	AGG_TX_STATE_TRANSMITTED = 0x00,
+	AGG_TX_STATE_UNDERRUN_MSK = 0x01,
+	AGG_TX_STATE_BT_PRIO_MSK = 0x02,
+	AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
+	AGG_TX_STATE_ABORT_MSK = 0x08,
+	AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
+	AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
+	AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
+	AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
+	AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
+	AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
+	AGG_TX_STATE_DUMP_TX_MSK = 0x200,
+	AGG_TX_STATE_DELAY_TX_MSK = 0x400
+};
+
+#define AGG_TX_STATUS_MSK	0x00000fff	/* bits 0:11 */
+#define AGG_TX_TRY_MSK		0x0000f000	/* bits 12:15 */
+
+#define AGG_TX_STATE_LAST_SENT_MSK  (AGG_TX_STATE_LAST_SENT_TTL_MSK | \
+				     AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
+				     AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
+
+/* # tx attempts for first frame in aggregation */
+#define AGG_TX_STATE_TRY_CNT_POS 12
+#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
+
+/* Command ID and sequence number of Tx command for this frame */
+#define AGG_TX_STATE_SEQ_NUM_POS 16
+#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
+
+/*
+ * REPLY_TX = 0x1c (response)
+ *
+ * This response may be in one of two slightly different formats, indicated
+ * by the frame_count field:
+ *
+ * 1)  No aggregation (frame_count == 1).  This reports Tx results for
+ *     a single frame.  Multiple attempts, at various bit rates, may have
+ *     been made for this frame.
+ *
+ * 2)  Aggregation (frame_count > 1).  This reports Tx results for
+ *     2 or more frames that used block-acknowledge.  All frames were
+ *     transmitted at same rate.  Rate scaling may have been used if first
+ *     frame in this new agg block failed in previous agg block(s).
+ *
+ *     Note that, for aggregation, ACK (block-ack) status is not delivered here;
+ *     block-ack has not been received by the time the agn device records
+ *     this status.
+ *     This status relates to reasons the tx might have been blocked or aborted
+ *     within the sending station (this agn device), rather than whether it was
+ *     received successfully by the destination station.
+ */
+struct agg_tx_status {
+	__le16 status;
+	__le16 sequence;
+} __packed;
+
+/*
+ * definitions for initial rate index field
+ * bits [3:0] initial rate index
+ * bits [6:4] rate table color, used for the initial rate
+ * bit-7 invalid rate indication
+ *   i.e. rate was not chosen from rate table
+ *   or rate table color was changed during frame retries
+ * refer tlc rate info
+ */
+
+#define IWL50_TX_RES_INIT_RATE_INDEX_POS	0
+#define IWL50_TX_RES_INIT_RATE_INDEX_MSK	0x0f
+#define IWL50_TX_RES_RATE_TABLE_COLOR_POS	4
+#define IWL50_TX_RES_RATE_TABLE_COLOR_MSK	0x70
+#define IWL50_TX_RES_INV_RATE_INDEX_MSK	0x80
+
+/* refer to ra_tid */
+#define IWLAGN_TX_RES_TID_POS	0
+#define IWLAGN_TX_RES_TID_MSK	0x0f
+#define IWLAGN_TX_RES_RA_POS	4
+#define IWLAGN_TX_RES_RA_MSK	0xf0
+
+struct iwlagn_tx_resp {
+	u8 frame_count;		/* 1 no aggregation, >1 aggregation */
+	u8 bt_kill_count;	/* # blocked by bluetooth (unused for agg) */
+	u8 failure_rts;		/* # failures due to unsuccessful RTS */
+	u8 failure_frame;	/* # failures due to no ACK (unused for agg) */
+
+	/* For non-agg:  Rate at which frame was successful.
+	 * For agg:  Rate at which all frames were transmitted. */
+	__le32 rate_n_flags;	/* RATE_MCS_*  */
+
+	/* For non-agg:  RTS + CTS + frame tx attempts time + ACK.
+	 * For agg:  RTS + CTS + aggregation tx time + block-ack time. */
+	__le16 wireless_media_time;	/* uSecs */
+
+	u8 pa_status;		/* RF power amplifier measurement (not used) */
+	u8 pa_integ_res_a[3];
+	u8 pa_integ_res_b[3];
+	u8 pa_integ_res_C[3];
+
+	__le32 tfd_info;
+	__le16 seq_ctl;
+	__le16 byte_cnt;
+	u8 tlc_info;
+	u8 ra_tid;		/* tid (0:3), sta_id (4:7) */
+	__le16 frame_ctrl;
+	/*
+	 * For non-agg:  frame status TX_STATUS_*
+	 * For agg:  status of 1st frame, AGG_TX_STATE_*; other frame status
+	 *           fields follow this one, up to frame_count.
+	 *           Bit fields:
+	 *           11- 0:  AGG_TX_STATE_* status code
+	 *           15-12:  Retry count for 1st frame in aggregation (retries
+	 *                   occur if tx failed for this frame when it was a
+	 *                   member of a previous aggregation block).  If rate
+	 *                   scaling is used, retry count indicates the rate
+	 *                   table entry used for all frames in the new agg.
+	 *           31-16:  Sequence # for this frame's Tx cmd (not SSN!)
+	 */
+	struct agg_tx_status status;	/* TX status (in aggregation -
+					 * status of 1st frame) */
+} __packed;
+/*
+ * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
+ *
+ * Reports Block-Acknowledge from recipient station
+ */
+struct iwl_compressed_ba_resp {
+	__le32 sta_addr_lo32;
+	__le16 sta_addr_hi16;
+	__le16 reserved;
+
+	/* Index of recipient (BA-sending) station in uCode's station table */
+	u8 sta_id;
+	u8 tid;
+	__le16 seq_ctl;
+	__le64 bitmap;
+	__le16 scd_flow;
+	__le16 scd_ssn;
+	u8 txed;	/* number of frames sent */
+	u8 txed_2_done; /* number of frames acked */
+} __packed;
+
+/*
+ * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
+ *
+ */
+
+/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
+#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK	(1 << 0)
+
+/* # of EDCA prioritized tx fifos */
+#define  LINK_QUAL_AC_NUM AC_NUM
+
+/* # entries in rate scale table to support Tx retries */
+#define  LINK_QUAL_MAX_RETRY_NUM 16
+
+/* Tx antenna selection values */
+#define  LINK_QUAL_ANT_A_MSK (1 << 0)
+#define  LINK_QUAL_ANT_B_MSK (1 << 1)
+#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
+
+
+/**
+ * struct iwl_link_qual_general_params
+ *
+ * Used in REPLY_TX_LINK_QUALITY_CMD
+ */
+struct iwl_link_qual_general_params {
+	u8 flags;
+
+	/* No entries at or above this (driver chosen) index contain MIMO */
+	u8 mimo_delimiter;
+
+	/* Best single antenna to use for single stream (legacy, SISO). */
+	u8 single_stream_ant_msk;	/* LINK_QUAL_ANT_* */
+
+	/* Best antennas to use for MIMO (unused for 4965, assumes both). */
+	u8 dual_stream_ant_msk;		/* LINK_QUAL_ANT_* */
+
+	/*
+	 * If driver needs to use different initial rates for different
+	 * EDCA QOS access categories (as implemented by tx fifos 0-3),
+	 * this table will set that up, by indicating the indexes in the
+	 * rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table at which to start.
+	 * Otherwise, driver should set all entries to 0.
+	 *
+	 * Entry usage:
+	 * 0 = Background, 1 = Best Effort (normal), 2 = Video, 3 = Voice
+	 * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3.
+	 */
+	u8 start_rate_index[LINK_QUAL_AC_NUM];
+} __packed;
+
+#define LINK_QUAL_AGG_TIME_LIMIT_DEF	(4000) /* 4 milliseconds */
+#define LINK_QUAL_AGG_TIME_LIMIT_MAX	(8000)
+#define LINK_QUAL_AGG_TIME_LIMIT_MIN	(100)
+
+#define LINK_QUAL_AGG_DISABLE_START_DEF	(3)
+#define LINK_QUAL_AGG_DISABLE_START_MAX	(255)
+#define LINK_QUAL_AGG_DISABLE_START_MIN	(0)
+
+#define LINK_QUAL_AGG_FRAME_LIMIT_DEF	(63)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MAX	(63)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MIN	(0)
+
+/**
+ * struct iwl_link_qual_agg_params
+ *
+ * Used in REPLY_TX_LINK_QUALITY_CMD
+ */
+struct iwl_link_qual_agg_params {
+
+	/*
+	 *Maximum number of uSec in aggregation.
+	 * default set to 4000 (4 milliseconds) if not configured in .cfg
+	 */
+	__le16 agg_time_limit;
+
+	/*
+	 * Number of Tx retries allowed for a frame, before that frame will
+	 * no longer be considered for the start of an aggregation sequence
+	 * (scheduler will then try to tx it as single frame).
+	 * Driver should set this to 3.
+	 */
+	u8 agg_dis_start_th;
+
+	/*
+	 * Maximum number of frames in aggregation.
+	 * 0 = no limit (default).  1 = no aggregation.
+	 * Other values = max # frames in aggregation.
+	 */
+	u8 agg_frame_cnt_limit;
+
+	__le32 reserved;
+} __packed;
+
+/*
+ * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
+ *
+ * For agn devices
+ *
+ * Each station in the agn device's internal station table has its own table
+ * of 16
+ * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when
+ * an ACK is not received.  This command replaces the entire table for
+ * one station.
+ *
+ * NOTE:  Station must already be in agn device's station table.
+ *	  Use REPLY_ADD_STA.
+ *
+ * The rate scaling procedures described below work well.  Of course, other
+ * procedures are possible, and may work better for particular environments.
+ *
+ *
+ * FILLING THE RATE TABLE
+ *
+ * Given a particular initial rate and mode, as determined by the rate
+ * scaling algorithm described below, the Linux driver uses the following
+ * formula to fill the rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table in the
+ * Link Quality command:
+ *
+ *
+ * 1)  If using High-throughput (HT) (SISO or MIMO) initial rate:
+ *     a) Use this same initial rate for first 3 entries.
+ *     b) Find next lower available rate using same mode (SISO or MIMO),
+ *        use for next 3 entries.  If no lower rate available, switch to
+ *        legacy mode (no HT40 channel, no MIMO, no short guard interval).
+ *     c) If using MIMO, set command's mimo_delimiter to number of entries
+ *        using MIMO (3 or 6).
+ *     d) After trying 2 HT rates, switch to legacy mode (no HT40 channel,
+ *        no MIMO, no short guard interval), at the next lower bit rate
+ *        (e.g. if second HT bit rate was 54, try 48 legacy), and follow
+ *        legacy procedure for remaining table entries.
+ *
+ * 2)  If using legacy initial rate:
+ *     a) Use the initial rate for only one entry.
+ *     b) For each following entry, reduce the rate to next lower available
+ *        rate, until reaching the lowest available rate.
+ *     c) When reducing rate, also switch antenna selection.
+ *     d) Once lowest available rate is reached, repeat this rate until
+ *        rate table is filled (16 entries), switching antenna each entry.
+ *
+ *
+ * ACCUMULATING HISTORY
+ *
+ * The rate scaling algorithm for agn devices, as implemented in Linux driver,
+ * uses two sets of frame Tx success history:  One for the current/active
+ * modulation mode, and one for a speculative/search mode that is being
+ * attempted. If the speculative mode turns out to be more effective (i.e.
+ * actual transfer rate is better), then the driver continues to use the
+ * speculative mode as the new current active mode.
+ *
+ * Each history set contains, separately for each possible rate, data for a
+ * sliding window of the 62 most recent tx attempts at that rate.  The data
+ * includes a shifting bitmap of success(1)/failure(0), and sums of successful
+ * and attempted frames, from which the driver can additionally calculate a
+ * success ratio (success / attempted) and number of failures
+ * (attempted - success), and control the size of the window (attempted).
+ * The driver uses the bit map to remove successes from the success sum, as
+ * the oldest tx attempts fall out of the window.
+ *
+ * When the agn device makes multiple tx attempts for a given frame, each
+ * attempt might be at a different rate, and have different modulation
+ * characteristics (e.g. antenna, fat channel, short guard interval), as set
+ * up in the rate scaling table in the Link Quality command.  The driver must
+ * determine which rate table entry was used for each tx attempt, to determine
+ * which rate-specific history to update, and record only those attempts that
+ * match the modulation characteristics of the history set.
+ *
+ * When using block-ack (aggregation), all frames are transmitted at the same
+ * rate, since there is no per-attempt acknowledgment from the destination
+ * station.  The Tx response struct iwl_tx_resp indicates the Tx rate in
+ * rate_n_flags field.  After receiving a block-ack, the driver can update
+ * history for the entire block all at once.
+ *
+ *
+ * FINDING BEST STARTING RATE:
+ *
+ * When working with a selected initial modulation mode (see below), the
+ * driver attempts to find a best initial rate.  The initial rate is the
+ * first entry in the Link Quality command's rate table.
+ *
+ * 1)  Calculate actual throughput (success ratio * expected throughput, see
+ *     table below) for current initial rate.  Do this only if enough frames
+ *     have been attempted to make the value meaningful:  at least 6 failed
+ *     tx attempts, or at least 8 successes.  If not enough, don't try rate
+ *     scaling yet.
+ *
+ * 2)  Find available rates adjacent to current initial rate.  Available means:
+ *     a)  supported by hardware &&
+ *     b)  supported by association &&
+ *     c)  within any constraints selected by user
+ *
+ * 3)  Gather measured throughputs for adjacent rates.  These might not have
+ *     enough history to calculate a throughput.  That's okay, we might try
+ *     using one of them anyway!
+ *
+ * 4)  Try decreasing rate if, for current rate:
+ *     a)  success ratio is < 15% ||
+ *     b)  lower adjacent rate has better measured throughput ||
+ *     c)  higher adjacent rate has worse throughput, and lower is unmeasured
+ *
+ *     As a sanity check, if decrease was determined above, leave rate
+ *     unchanged if:
+ *     a)  lower rate unavailable
+ *     b)  success ratio at current rate > 85% (very good)
+ *     c)  current measured throughput is better than expected throughput
+ *         of lower rate (under perfect 100% tx conditions, see table below)
+ *
+ * 5)  Try increasing rate if, for current rate:
+ *     a)  success ratio is < 15% ||
+ *     b)  both adjacent rates' throughputs are unmeasured (try it!) ||
+ *     b)  higher adjacent rate has better measured throughput ||
+ *     c)  lower adjacent rate has worse throughput, and higher is unmeasured
+ *
+ *     As a sanity check, if increase was determined above, leave rate
+ *     unchanged if:
+ *     a)  success ratio at current rate < 70%.  This is not particularly
+ *         good performance; higher rate is sure to have poorer success.
+ *
+ * 6)  Re-evaluate the rate after each tx frame.  If working with block-
+ *     acknowledge, history and statistics may be calculated for the entire
+ *     block (including prior history that fits within the history windows),
+ *     before re-evaluation.
+ *
+ * FINDING BEST STARTING MODULATION MODE:
+ *
+ * After working with a modulation mode for a "while" (and doing rate scaling),
+ * the driver searches for a new initial mode in an attempt to improve
+ * throughput.  The "while" is measured by numbers of attempted frames:
+ *
+ * For legacy mode, search for new mode after:
+ *   480 successful frames, or 160 failed frames
+ * For high-throughput modes (SISO or MIMO), search for new mode after:
+ *   4500 successful frames, or 400 failed frames
+ *
+ * Mode switch possibilities are (3 for each mode):
+ *
+ * For legacy:
+ *   Change antenna, try SISO (if HT association), try MIMO (if HT association)
+ * For SISO:
+ *   Change antenna, try MIMO, try shortened guard interval (SGI)
+ * For MIMO:
+ *   Try SISO antenna A, SISO antenna B, try shortened guard interval (SGI)
+ *
+ * When trying a new mode, use the same bit rate as the old/current mode when
+ * trying antenna switches and shortened guard interval.  When switching to
+ * SISO from MIMO or legacy, or to MIMO from SISO or legacy, use a rate
+ * for which the expected throughput (under perfect conditions) is about the
+ * same or slightly better than the actual measured throughput delivered by
+ * the old/current mode.
+ *
+ * Actual throughput can be estimated by multiplying the expected throughput
+ * by the success ratio (successful / attempted tx frames).  Frame size is
+ * not considered in this calculation; it assumes that frame size will average
+ * out to be fairly consistent over several samples.  The following are
+ * metric values for expected throughput assuming 100% success ratio.
+ * Only G band has support for CCK rates:
+ *
+ *           RATE:  1    2    5   11    6   9   12   18   24   36   48   54   60
+ *
+ *              G:  7   13   35   58   40  57   72   98  121  154  177  186  186
+ *              A:  0    0    0    0   40  57   72   98  121  154  177  186  186
+ *     SISO 20MHz:  0    0    0    0   42  42   76  102  124  159  183  193  202
+ * SGI SISO 20MHz:  0    0    0    0   46  46   82  110  132  168  192  202  211
+ *     MIMO 20MHz:  0    0    0    0   74  74  123  155  179  214  236  244  251
+ * SGI MIMO 20MHz:  0    0    0    0   81  81  131  164  188  222  243  251  257
+ *     SISO 40MHz:  0    0    0    0   77  77  127  160  184  220  242  250  257
+ * SGI SISO 40MHz:  0    0    0    0   83  83  135  169  193  229  250  257  264
+ *     MIMO 40MHz:  0    0    0    0  123 123  182  214  235  264  279  285  289
+ * SGI MIMO 40MHz:  0    0    0    0  131 131  191  222  242  270  284  289  293
+ *
+ * After the new mode has been tried for a short while (minimum of 6 failed
+ * frames or 8 successful frames), compare success ratio and actual throughput
+ * estimate of the new mode with the old.  If either is better with the new
+ * mode, continue to use the new mode.
+ *
+ * Continue comparing modes until all 3 possibilities have been tried.
+ * If moving from legacy to HT, try all 3 possibilities from the new HT
+ * mode.  After trying all 3, a best mode is found.  Continue to use this mode
+ * for the longer "while" described above (e.g. 480 successful frames for
+ * legacy), and then repeat the search process.
+ *
+ */
+struct iwl_link_quality_cmd {
+
+	/* Index of destination/recipient station in uCode's station table */
+	u8 sta_id;
+	u8 reserved1;
+	__le16 control;		/* not used */
+	struct iwl_link_qual_general_params general_params;
+	struct iwl_link_qual_agg_params agg_params;
+
+	/*
+	 * Rate info; when using rate-scaling, Tx command's initial_rate_index
+	 * specifies 1st Tx rate attempted, via index into this table.
+	 * agn devices works its way through table when retrying Tx.
+	 */
+	struct {
+		__le32 rate_n_flags;	/* RATE_MCS_*, IWL_RATE_* */
+	} rs_table[LINK_QUAL_MAX_RETRY_NUM];
+	__le32 reserved2;
+} __packed;
+
+/*
+ * BT configuration enable flags:
+ *   bit 0 - 1: BT channel announcement enabled
+ *           0: disable
+ *   bit 1 - 1: priority of BT device enabled
+ *           0: disable
+ *   bit 2 - 1: BT 2 wire support enabled
+ *           0: disable
+ */
+#define BT_COEX_DISABLE (0x0)
+#define BT_ENABLE_CHANNEL_ANNOUNCE BIT(0)
+#define BT_ENABLE_PRIORITY	   BIT(1)
+#define BT_ENABLE_2_WIRE	   BIT(2)
+
+#define BT_COEX_DISABLE (0x0)
+#define BT_COEX_ENABLE  (BT_ENABLE_CHANNEL_ANNOUNCE | BT_ENABLE_PRIORITY)
+
+#define BT_LEAD_TIME_MIN (0x0)
+#define BT_LEAD_TIME_DEF (0x1E)
+#define BT_LEAD_TIME_MAX (0xFF)
+
+#define BT_MAX_KILL_MIN (0x1)
+#define BT_MAX_KILL_DEF (0x5)
+#define BT_MAX_KILL_MAX (0xFF)
+
+#define BT_DURATION_LIMIT_DEF	625
+#define BT_DURATION_LIMIT_MAX	1250
+#define BT_DURATION_LIMIT_MIN	625
+
+#define BT_ON_THRESHOLD_DEF	4
+#define BT_ON_THRESHOLD_MAX	1000
+#define BT_ON_THRESHOLD_MIN	1
+
+#define BT_FRAG_THRESHOLD_DEF	0
+#define BT_FRAG_THRESHOLD_MAX	0
+#define BT_FRAG_THRESHOLD_MIN	0
+
+#define BT_AGG_THRESHOLD_DEF	1200
+#define BT_AGG_THRESHOLD_MAX	8000
+#define BT_AGG_THRESHOLD_MIN	400
+
+/*
+ * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
+ *
+ * agn devices support hardware handshake with Bluetooth device on
+ * same platform.  Bluetooth device alerts wireless device when it will Tx;
+ * wireless device can delay or kill its own Tx to accommodate.
+ */
+struct iwl_bt_cmd {
+	u8 flags;
+	u8 lead_time;
+	u8 max_kill;
+	u8 reserved;
+	__le32 kill_ack_mask;
+	__le32 kill_cts_mask;
+} __packed;
+
+#define IWLAGN_BT_FLAG_CHANNEL_INHIBITION	BIT(0)
+
+#define IWLAGN_BT_FLAG_COEX_MODE_MASK		(BIT(3)|BIT(4)|BIT(5))
+#define IWLAGN_BT_FLAG_COEX_MODE_SHIFT		3
+#define IWLAGN_BT_FLAG_COEX_MODE_DISABLED	0
+#define IWLAGN_BT_FLAG_COEX_MODE_LEGACY_2W	1
+#define IWLAGN_BT_FLAG_COEX_MODE_3W		2
+#define IWLAGN_BT_FLAG_COEX_MODE_4W		3
+
+#define IWLAGN_BT_FLAG_UCODE_DEFAULT		BIT(6)
+/* Disable Sync PSPoll on SCO/eSCO */
+#define IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE	BIT(7)
+
+#define IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD	-75 /* dBm */
+#define IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD	-65 /* dBm */
+
+#define IWLAGN_BT_PRIO_BOOST_MAX	0xFF
+#define IWLAGN_BT_PRIO_BOOST_MIN	0x00
+#define IWLAGN_BT_PRIO_BOOST_DEFAULT	0xF0
+
+#define IWLAGN_BT_MAX_KILL_DEFAULT	5
+
+#define IWLAGN_BT3_T7_DEFAULT		1
+
+enum iwl_bt_kill_idx {
+	IWL_BT_KILL_DEFAULT = 0,
+	IWL_BT_KILL_OVERRIDE = 1,
+	IWL_BT_KILL_REDUCE = 2,
+};
+
+#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT	cpu_to_le32(0xffff0000)
+#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT	cpu_to_le32(0xffff0000)
+#define IWLAGN_BT_KILL_ACK_CTS_MASK_SCO	cpu_to_le32(0xffffffff)
+#define IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE	cpu_to_le32(0)
+
+#define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT	2
+
+#define IWLAGN_BT3_T2_DEFAULT		0xc
+
+#define IWLAGN_BT_VALID_ENABLE_FLAGS	cpu_to_le16(BIT(0))
+#define IWLAGN_BT_VALID_BOOST		cpu_to_le16(BIT(1))
+#define IWLAGN_BT_VALID_MAX_KILL	cpu_to_le16(BIT(2))
+#define IWLAGN_BT_VALID_3W_TIMERS	cpu_to_le16(BIT(3))
+#define IWLAGN_BT_VALID_KILL_ACK_MASK	cpu_to_le16(BIT(4))
+#define IWLAGN_BT_VALID_KILL_CTS_MASK	cpu_to_le16(BIT(5))
+#define IWLAGN_BT_VALID_REDUCED_TX_PWR	cpu_to_le16(BIT(6))
+#define IWLAGN_BT_VALID_3W_LUT		cpu_to_le16(BIT(7))
+
+#define IWLAGN_BT_ALL_VALID_MSK		(IWLAGN_BT_VALID_ENABLE_FLAGS | \
+					IWLAGN_BT_VALID_BOOST | \
+					IWLAGN_BT_VALID_MAX_KILL | \
+					IWLAGN_BT_VALID_3W_TIMERS | \
+					IWLAGN_BT_VALID_KILL_ACK_MASK | \
+					IWLAGN_BT_VALID_KILL_CTS_MASK | \
+					IWLAGN_BT_VALID_REDUCED_TX_PWR | \
+					IWLAGN_BT_VALID_3W_LUT)
+
+#define IWLAGN_BT_REDUCED_TX_PWR	BIT(0)
+
+#define IWLAGN_BT_DECISION_LUT_SIZE	12
+
+struct iwl_basic_bt_cmd {
+	u8 flags;
+	u8 ledtime; /* unused */
+	u8 max_kill;
+	u8 bt3_timer_t7_value;
+	__le32 kill_ack_mask;
+	__le32 kill_cts_mask;
+	u8 bt3_prio_sample_time;
+	u8 bt3_timer_t2_value;
+	__le16 bt4_reaction_time; /* unused */
+	__le32 bt3_lookup_table[IWLAGN_BT_DECISION_LUT_SIZE];
+	/*
+	 * bit 0: use reduced tx power for control frame
+	 * bit 1 - 7: reserved
+	 */
+	u8 reduce_txpower;
+	u8 reserved;
+	__le16 valid;
+};
+
+struct iwl_bt_cmd_v1 {
+	struct iwl_basic_bt_cmd basic;
+	u8 prio_boost;
+	/*
+	 * set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask
+	 * if configure the following patterns
+	 */
+	u8 tx_prio_boost;	/* SW boost of WiFi tx priority */
+	__le16 rx_prio_boost;	/* SW boost of WiFi rx priority */
+};
+
+struct iwl_bt_cmd_v2 {
+	struct iwl_basic_bt_cmd basic;
+	__le32 prio_boost;
+	/*
+	 * set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask
+	 * if configure the following patterns
+	 */
+	u8 reserved;
+	u8 tx_prio_boost;	/* SW boost of WiFi tx priority */
+	__le16 rx_prio_boost;	/* SW boost of WiFi rx priority */
+};
+
+#define IWLAGN_BT_SCO_ACTIVE	cpu_to_le32(BIT(0))
+
+struct iwlagn_bt_sco_cmd {
+	__le32 flags;
+};
+
+/******************************************************************************
+ * (6)
+ * Spectrum Management (802.11h) Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * Spectrum Management
+ */
+#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
+				 RXON_FILTER_CTL2HOST_MSK        | \
+				 RXON_FILTER_ACCEPT_GRP_MSK      | \
+				 RXON_FILTER_DIS_DECRYPT_MSK     | \
+				 RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
+				 RXON_FILTER_ASSOC_MSK           | \
+				 RXON_FILTER_BCON_AWARE_MSK)
+
+struct iwl_measure_channel {
+	__le32 duration;	/* measurement duration in extended beacon
+				 * format */
+	u8 channel;		/* channel to measure */
+	u8 type;		/* see enum iwl_measure_type */
+	__le16 reserved;
+} __packed;
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
+ */
+struct iwl_spectrum_cmd {
+	__le16 len;		/* number of bytes starting from token */
+	u8 token;		/* token id */
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 origin;		/* 0 = TGh, 1 = other, 2 = TGk */
+	u8 periodic;		/* 1 = periodic */
+	__le16 path_loss_timeout;
+	__le32 start_time;	/* start time in extended beacon format */
+	__le32 reserved2;
+	__le32 flags;		/* rxon flags */
+	__le32 filter_flags;	/* rxon filter flags */
+	__le16 channel_count;	/* minimum 1, maximum 10 */
+	__le16 reserved3;
+	struct iwl_measure_channel channels[10];
+} __packed;
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
+ */
+struct iwl_spectrum_resp {
+	u8 token;
+	u8 id;			/* id of the prior command replaced, or 0xff */
+	__le16 status;		/* 0 - command will be handled
+				 * 1 - cannot handle (conflicts with another
+				 *     measurement) */
+} __packed;
+
+enum iwl_measurement_state {
+	IWL_MEASUREMENT_START = 0,
+	IWL_MEASUREMENT_STOP = 1,
+};
+
+enum iwl_measurement_status {
+	IWL_MEASUREMENT_OK = 0,
+	IWL_MEASUREMENT_CONCURRENT = 1,
+	IWL_MEASUREMENT_CSA_CONFLICT = 2,
+	IWL_MEASUREMENT_TGH_CONFLICT = 3,
+	/* 4-5 reserved */
+	IWL_MEASUREMENT_STOPPED = 6,
+	IWL_MEASUREMENT_TIMEOUT = 7,
+	IWL_MEASUREMENT_PERIODIC_FAILED = 8,
+};
+
+#define NUM_ELEMENTS_IN_HISTOGRAM 8
+
+struct iwl_measurement_histogram {
+	__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 0.8usec counts */
+	__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 1usec counts */
+} __packed;
+
+/* clear channel availability counters */
+struct iwl_measurement_cca_counters {
+	__le32 ofdm;
+	__le32 cck;
+} __packed;
+
+enum iwl_measure_type {
+	IWL_MEASURE_BASIC = (1 << 0),
+	IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
+	IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
+	IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
+	IWL_MEASURE_FRAME = (1 << 4),
+	/* bits 5:6 are reserved */
+	IWL_MEASURE_IDLE = (1 << 7),
+};
+
+/*
+ * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
+ */
+struct iwl_spectrum_notification {
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 token;
+	u8 channel_index;	/* index in measurement channel list */
+	u8 state;		/* 0 - start, 1 - stop */
+	__le32 start_time;	/* lower 32-bits of TSF */
+	u8 band;		/* 0 - 5.2GHz, 1 - 2.4GHz */
+	u8 channel;
+	u8 type;		/* see enum iwl_measurement_type */
+	u8 reserved1;
+	/* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
+	 * valid if applicable for measurement type requested. */
+	__le32 cca_ofdm;	/* cca fraction time in 40Mhz clock periods */
+	__le32 cca_cck;		/* cca fraction time in 44Mhz clock periods */
+	__le32 cca_time;	/* channel load time in usecs */
+	u8 basic_type;		/* 0 - bss, 1 - ofdm preamble, 2 -
+				 * unidentified */
+	u8 reserved2[3];
+	struct iwl_measurement_histogram histogram;
+	__le32 stop_time;	/* lower 32-bits of TSF */
+	__le32 status;		/* see iwl_measurement_status */
+} __packed;
+
+/******************************************************************************
+ * (7)
+ * Power Management Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl_powertable_cmd - Power Table Command
+ * @flags: See below:
+ *
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
+ *
+ * PM allow:
+ *   bit 0 - '0' Driver not allow power management
+ *           '1' Driver allow PM (use rest of parameters)
+ *
+ * uCode send sleep notifications:
+ *   bit 1 - '0' Don't send sleep notification
+ *           '1' send sleep notification (SEND_PM_NOTIFICATION)
+ *
+ * Sleep over DTIM
+ *   bit 2 - '0' PM have to walk up every DTIM
+ *           '1' PM could sleep over DTIM till listen Interval.
+ *
+ * PCI power managed
+ *   bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1)
+ *           '1' !(PCI_CFG_LINK_CTRL & 0x1)
+ *
+ * Fast PD
+ *   bit 4 - '1' Put radio to sleep when receiving frame for others
+ *
+ * Force sleep Modes
+ *   bit 31/30- '00' use both mac/xtal sleeps
+ *              '01' force Mac sleep
+ *              '10' force xtal sleep
+ *              '11' Illegal set
+ *
+ * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
+ * ucode assume sleep over DTIM is allowed and we don't need to wake up
+ * for every DTIM.
+ */
+#define IWL_POWER_VEC_SIZE 5
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	cpu_to_le16(BIT(0))
+#define IWL_POWER_POWER_SAVE_ENA_MSK		cpu_to_le16(BIT(0))
+#define IWL_POWER_POWER_MANAGEMENT_ENA_MSK	cpu_to_le16(BIT(1))
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK		cpu_to_le16(BIT(2))
+#define IWL_POWER_PCI_PM_MSK			cpu_to_le16(BIT(3))
+#define IWL_POWER_FAST_PD			cpu_to_le16(BIT(4))
+#define IWL_POWER_BEACON_FILTERING		cpu_to_le16(BIT(5))
+#define IWL_POWER_SHADOW_REG_ENA		cpu_to_le16(BIT(6))
+#define IWL_POWER_CT_KILL_SET			cpu_to_le16(BIT(7))
+#define IWL_POWER_BT_SCO_ENA			cpu_to_le16(BIT(8))
+#define IWL_POWER_ADVANCE_PM_ENA_MSK		cpu_to_le16(BIT(9))
+
+struct iwl_powertable_cmd {
+	__le16 flags;
+	u8 keep_alive_seconds;
+	u8 debug_flags;
+	__le32 rx_data_timeout;
+	__le32 tx_data_timeout;
+	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
+	__le32 keep_alive_beacons;
+} __packed;
+
+/*
+ * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
+ * all devices identical.
+ */
+struct iwl_sleep_notification {
+	u8 pm_sleep_mode;
+	u8 pm_wakeup_src;
+	__le16 reserved;
+	__le32 sleep_time;
+	__le32 tsf_low;
+	__le32 bcon_timer;
+} __packed;
+
+/* Sleep states.  all devices identical. */
+enum {
+	IWL_PM_NO_SLEEP = 0,
+	IWL_PM_SLP_MAC = 1,
+	IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
+	IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
+	IWL_PM_SLP_PHY = 4,
+	IWL_PM_SLP_REPENT = 5,
+	IWL_PM_WAKEUP_BY_TIMER = 6,
+	IWL_PM_WAKEUP_BY_DRIVER = 7,
+	IWL_PM_WAKEUP_BY_RFKILL = 8,
+	/* 3 reserved */
+	IWL_PM_NUM_OF_MODES = 12,
+};
+
+/*
+ * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
+ */
+#define CARD_STATE_CMD_DISABLE 0x00	/* Put card to sleep */
+#define CARD_STATE_CMD_ENABLE  0x01	/* Wake up card */
+#define CARD_STATE_CMD_HALT    0x02	/* Power down permanently */
+struct iwl_card_state_cmd {
+	__le32 status;		/* CARD_STATE_CMD_* request new power state */
+} __packed;
+
+/*
+ * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
+ */
+struct iwl_card_state_notif {
+	__le32 flags;
+} __packed;
+
+#define HW_CARD_DISABLED   0x01
+#define SW_CARD_DISABLED   0x02
+#define CT_CARD_DISABLED   0x04
+#define RXON_CARD_DISABLED 0x10
+
+struct iwl_ct_kill_config {
+	__le32   reserved;
+	__le32   critical_temperature_M;
+	__le32   critical_temperature_R;
+}  __packed;
+
+/* 1000, and 6x00 */
+struct iwl_ct_kill_throttling_config {
+	__le32   critical_temperature_exit;
+	__le32   reserved;
+	__le32   critical_temperature_enter;
+}  __packed;
+
+/******************************************************************************
+ * (8)
+ * Scan Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+#define SCAN_CHANNEL_TYPE_PASSIVE cpu_to_le32(0)
+#define SCAN_CHANNEL_TYPE_ACTIVE  cpu_to_le32(1)
+
+/**
+ * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
+ *
+ * One for each channel in the scan list.
+ * Each channel can independently select:
+ * 1)  SSID for directed active scans
+ * 2)  Txpower setting (for rate specified within Tx command)
+ * 3)  How long to stay on-channel (behavior may be modified by quiet_time,
+ *     quiet_plcp_th, good_CRC_th)
+ *
+ * To avoid uCode errors, make sure the following are true (see comments
+ * under struct iwl_scan_cmd about max_out_time and quiet_time):
+ * 1)  If using passive_dwell (i.e. passive_dwell != 0):
+ *     active_dwell <= passive_dwell (< max_out_time if max_out_time != 0)
+ * 2)  quiet_time <= active_dwell
+ * 3)  If restricting off-channel time (i.e. max_out_time !=0):
+ *     passive_dwell < max_out_time
+ *     active_dwell < max_out_time
+ */
+
+struct iwl_scan_channel {
+	/*
+	 * type is defined as:
+	 * 0:0 1 = active, 0 = passive
+	 * 1:20 SSID direct bit map; if a bit is set, then corresponding
+	 *     SSID IE is transmitted in probe request.
+	 * 21:31 reserved
+	 */
+	__le32 type;
+	__le16 channel;	/* band is selected by iwl_scan_cmd "flags" field */
+	u8 tx_gain;		/* gain for analog radio */
+	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 */
+} __packed;
+
+/* set number of direct probes __le32 type */
+#define IWL_SCAN_PROBE_MASK(n) 	cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
+
+/**
+ * struct iwl_ssid_ie - directed scan network information element
+ *
+ * Up to 20 of these may appear in REPLY_SCAN_CMD,
+ * selected by "type" bit field in struct iwl_scan_channel;
+ * each channel may select different ssids from among the 20 entries.
+ * SSID IEs get transmitted in reverse order of entry.
+ */
+struct iwl_ssid_ie {
+	u8 id;
+	u8 len;
+	u8 ssid[32];
+} __packed;
+
+#define PROBE_OPTION_MAX		20
+#define TX_CMD_LIFE_TIME_INFINITE	cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH_DISABLED	0
+#define IWL_GOOD_CRC_TH_DEFAULT		cpu_to_le16(1)
+#define IWL_GOOD_CRC_TH_NEVER		cpu_to_le16(0xffff)
+#define IWL_MAX_CMD_SIZE 4096
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (command)
+ *
+ * The hardware scan command is very powerful; the driver can set it up to
+ * maintain (relatively) normal network traffic while doing a scan in the
+ * background.  The max_out_time and suspend_time control the ratio of how
+ * long the device stays on an associated network channel ("service channel")
+ * vs. how long it's away from the service channel, i.e. tuned to other channels
+ * for scanning.
+ *
+ * max_out_time is the max time off-channel (in usec), and suspend_time
+ * is how long (in "extended beacon" format) that the scan is "suspended"
+ * after returning to the service channel.  That is, suspend_time is the
+ * time that we stay on the service channel, doing normal work, between
+ * scan segments.  The driver may set these parameters differently to support
+ * scanning when associated vs. not associated, and light vs. heavy traffic
+ * loads when associated.
+ *
+ * After receiving this command, the device's scan engine does the following;
+ *
+ * 1)  Sends SCAN_START notification to driver
+ * 2)  Checks to see if it has time to do scan for one channel
+ * 3)  Sends NULL packet, with power-save (PS) bit set to 1,
+ *     to tell AP that we're going off-channel
+ * 4)  Tunes to first channel in scan list, does active or passive scan
+ * 5)  Sends SCAN_RESULT notification to driver
+ * 6)  Checks to see if it has time to do scan on *next* channel in list
+ * 7)  Repeats 4-6 until it no longer has time to scan the next channel
+ *     before max_out_time expires
+ * 8)  Returns to service channel
+ * 9)  Sends NULL packet with PS=0 to tell AP that we're back
+ * 10) Stays on service channel until suspend_time expires
+ * 11) Repeats entire process 2-10 until list is complete
+ * 12) Sends SCAN_COMPLETE notification
+ *
+ * For fast, efficient scans, the scan command also has support for staying on
+ * a channel for just a short time, if doing active scanning and getting no
+ * responses to the transmitted probe request.  This time is controlled by
+ * quiet_time, and the number of received packets below which a channel is
+ * considered "quiet" is controlled by quiet_plcp_threshold.
+ *
+ * For active scanning on channels that have regulatory restrictions against
+ * blindly transmitting, the scan can listen before transmitting, to make sure
+ * that there is already legitimate activity on the channel.  If enough
+ * packets are cleanly received on the channel (controlled by good_CRC_th,
+ * typical value 1), the scan engine starts transmitting probe requests.
+ *
+ * Driver must use separate scan commands for 2.4 vs. 5 GHz bands.
+ *
+ * To avoid uCode errors, see timing restrictions described under
+ * struct iwl_scan_channel.
+ */
+
+enum iwl_scan_flags {
+	/* BIT(0) currently unused */
+	IWL_SCAN_FLAGS_ACTION_FRAME_TX	= BIT(1),
+	/* bits 2-7 reserved */
+};
+
+struct iwl_scan_cmd {
+	__le16 len;
+	u8 scan_flags;		/* scan flags: see enum iwl_scan_flags */
+	u8 channel_count;	/* # channels in channel list */
+	__le16 quiet_time;	/* dwell only this # millisecs on quiet channel
+				 * (only for active scan) */
+	__le16 quiet_plcp_th;	/* quiet chnl is < this # pkts (typ. 1) */
+	__le16 good_CRC_th;	/* passive -> active promotion threshold */
+	__le16 rx_chain;	/* RXON_RX_CHAIN_* */
+	__le32 max_out_time;	/* max usec to be away from associated (service)
+				 * channel */
+	__le32 suspend_time;	/* pause scan this long (in "extended beacon
+				 * format") when returning to service chnl:
+				 */
+	__le32 flags;		/* RXON_FLG_* */
+	__le32 filter_flags;	/* RXON_FILTER_* */
+
+	/* For active scans (set to all-0s for passive scans).
+	 * Does not include payload.  Must specify Tx rate; no rate scaling. */
+	struct iwl_tx_cmd tx_cmd;
+
+	/* For directed active scans (set to all-0s otherwise) */
+	struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
+
+	/*
+	 * Probe request frame, followed by channel list.
+	 *
+	 * Size of probe request frame is specified by byte count in tx_cmd.
+	 * Channel list follows immediately after probe request frame.
+	 * Number of channels in list is specified by channel_count.
+	 * Each channel in list is of type:
+	 *
+	 * struct iwl_scan_channel channels[0];
+	 *
+	 * NOTE:  Only one band of channels can be scanned per pass.  You
+	 * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
+	 * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
+	 * before requesting another scan.
+	 */
+	u8 data[0];
+} __packed;
+
+/* Can abort will notify by complete notification with abort status. */
+#define CAN_ABORT_STATUS	cpu_to_le32(0x1)
+/* complete notification statuses */
+#define ABORT_STATUS            0x2
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (response)
+ */
+struct iwl_scanreq_notification {
+	__le32 status;		/* 1: okay, 2: cannot fulfill request */
+} __packed;
+
+/*
+ * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
+ */
+struct iwl_scanstart_notification {
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 beacon_timer;
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 status;
+} __packed;
+
+#define  SCAN_OWNER_STATUS 0x1
+#define  MEASURE_OWNER_STATUS 0x2
+
+#define IWL_PROBE_STATUS_OK		0
+#define IWL_PROBE_STATUS_TX_FAILED	BIT(0)
+/* error statuses combined with TX_FAILED */
+#define IWL_PROBE_STATUS_FAIL_TTL	BIT(1)
+#define IWL_PROBE_STATUS_FAIL_BT	BIT(2)
+
+#define NUMBER_OF_STATISTICS 1	/* first __le32 is good CRC */
+/*
+ * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
+ */
+struct iwl_scanresults_notification {
+	u8 channel;
+	u8 band;
+	u8 probe_status;
+	u8 num_probe_not_sent; /* not enough time to send */
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 statistics[NUMBER_OF_STATISTICS];
+} __packed;
+
+/*
+ * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
+ */
+struct iwl_scancomplete_notification {
+	u8 scanned_channels;
+	u8 status;
+	u8 bt_status;	/* BT On/Off status */
+	u8 last_channel;
+	__le32 tsf_low;
+	__le32 tsf_high;
+} __packed;
+
+
+/******************************************************************************
+ * (9)
+ * IBSS/AP Commands and Notifications:
+ *
+ *****************************************************************************/
+
+enum iwl_ibss_manager {
+	IWL_NOT_IBSS_MANAGER = 0,
+	IWL_IBSS_MANAGER = 1,
+};
+
+/*
+ * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
+ */
+
+struct iwlagn_beacon_notif {
+	struct iwlagn_tx_resp beacon_notify_hdr;
+	__le32 low_tsf;
+	__le32 high_tsf;
+	__le32 ibss_mgr_status;
+} __packed;
+
+/*
+ * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
+ */
+
+struct iwl_tx_beacon_cmd {
+	struct iwl_tx_cmd tx;
+	__le16 tim_idx;
+	u8 tim_size;
+	u8 reserved1;
+	struct ieee80211_hdr frame[0];	/* beacon frame */
+} __packed;
+
+/******************************************************************************
+ * (10)
+ * Statistics Commands and Notifications:
+ *
+ *****************************************************************************/
+
+#define IWL_TEMP_CONVERT 260
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/* Used for passing to driver number of successes and failures per rate */
+struct rate_histogram {
+	union {
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} success;
+	union {
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} failed;
+} __packed;
+
+/* statistics command response */
+
+struct statistics_dbg {
+	__le32 burst_check;
+	__le32 burst_count;
+	__le32 wait_for_silence_timeout_cnt;
+	__le32 reserved[3];
+} __packed;
+
+struct statistics_rx_phy {
+	__le32 ina_cnt;
+	__le32 fina_cnt;
+	__le32 plcp_err;
+	__le32 crc32_err;
+	__le32 overrun_err;
+	__le32 early_overrun_err;
+	__le32 crc32_good;
+	__le32 false_alarm_cnt;
+	__le32 fina_sync_err_cnt;
+	__le32 sfd_timeout;
+	__le32 fina_timeout;
+	__le32 unresponded_rts;
+	__le32 rxe_frame_limit_overrun;
+	__le32 sent_ack_cnt;
+	__le32 sent_cts_cnt;
+	__le32 sent_ba_rsp_cnt;
+	__le32 dsp_self_kill;
+	__le32 mh_format_err;
+	__le32 re_acq_main_rssi_sum;
+	__le32 reserved3;
+} __packed;
+
+struct statistics_rx_ht_phy {
+	__le32 plcp_err;
+	__le32 overrun_err;
+	__le32 early_overrun_err;
+	__le32 crc32_good;
+	__le32 crc32_err;
+	__le32 mh_format_err;
+	__le32 agg_crc32_good;
+	__le32 agg_mpdu_cnt;
+	__le32 agg_cnt;
+	__le32 unsupport_mcs;
+} __packed;
+
+#define INTERFERENCE_DATA_AVAILABLE      cpu_to_le32(1)
+
+struct statistics_rx_non_phy {
+	__le32 bogus_cts;	/* CTS received when not expecting CTS */
+	__le32 bogus_ack;	/* ACK received when not expecting ACK */
+	__le32 non_bssid_frames;	/* number of frames with BSSID that
+					 * doesn't belong to the STA BSSID */
+	__le32 filtered_frames;	/* count frames that were dumped in the
+				 * filtering process */
+	__le32 non_channel_beacons;	/* beacons with our bss id but not on
+					 * our serving channel */
+	__le32 channel_beacons;	/* beacons with our bss id and in our
+				 * serving channel */
+	__le32 num_missed_bcon;	/* number of missed beacons */
+	__le32 adc_rx_saturation_time;	/* count in 0.8us units the time the
+					 * ADC was in saturation */
+	__le32 ina_detection_search_time;/* total time (in 0.8us) searched
+					  * for INA */
+	__le32 beacon_silence_rssi_a;	/* RSSI silence after beacon frame */
+	__le32 beacon_silence_rssi_b;	/* RSSI silence after beacon frame */
+	__le32 beacon_silence_rssi_c;	/* RSSI silence after beacon frame */
+	__le32 interference_data_flag;	/* flag for interference data
+					 * availability. 1 when data is
+					 * available. */
+	__le32 channel_load;		/* counts RX Enable time in uSec */
+	__le32 dsp_false_alarms;	/* DSP false alarm (both OFDM
+					 * and CCK) counter */
+	__le32 beacon_rssi_a;
+	__le32 beacon_rssi_b;
+	__le32 beacon_rssi_c;
+	__le32 beacon_energy_a;
+	__le32 beacon_energy_b;
+	__le32 beacon_energy_c;
+} __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;
+} __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
+ *
+ * @ant_a: current tx power on chain a in 1/2 dB step
+ * @ant_b: current tx power on chain b in 1/2 dB step
+ * @ant_c: current tx power on chain c in 1/2 dB step
+ */
+struct statistics_tx_power {
+	u8 ant_a;
+	u8 ant_b;
+	u8 ant_c;
+	u8 reserved;
+} __packed;
+
+struct statistics_tx_non_phy_agg {
+	__le32 ba_timeout;
+	__le32 ba_reschedule_frames;
+	__le32 scd_query_agg_frame_cnt;
+	__le32 scd_query_no_agg;
+	__le32 scd_query_agg;
+	__le32 scd_query_mismatch;
+	__le32 frame_not_ready;
+	__le32 underrun;
+	__le32 bt_prio_kill;
+	__le32 rx_ba_rsp_cnt;
+} __packed;
+
+struct statistics_tx {
+	__le32 preamble_cnt;
+	__le32 rx_detected_cnt;
+	__le32 bt_prio_defer_cnt;
+	__le32 bt_prio_kill_cnt;
+	__le32 few_bytes_cnt;
+	__le32 cts_timeout;
+	__le32 ack_timeout;
+	__le32 expected_ack_cnt;
+	__le32 actual_ack_cnt;
+	__le32 dump_msdu_cnt;
+	__le32 burst_abort_next_frame_mismatch_cnt;
+	__le32 burst_abort_missing_next_frame_cnt;
+	__le32 cts_timeout_collision;
+	__le32 ack_or_ba_timeout_collision;
+	struct statistics_tx_non_phy_agg agg;
+	/*
+	 * "tx_power" are optional parameters provided by uCode,
+	 * 6000 series is the only device provide the information,
+	 * Those are reserved fields for all the other devices
+	 */
+	struct statistics_tx_power tx_power;
+	__le32 reserved1;
+} __packed;
+
+
+struct statistics_div {
+	__le32 tx_on_a;
+	__le32 tx_on_b;
+	__le32 exec_time;
+	__le32 probe_time;
+	__le32 reserved1;
+	__le32 reserved2;
+} __packed;
+
+struct statistics_general_common {
+	__le32 temperature;   /* radio temperature */
+	__le32 temperature_m; /* radio voltage */
+	struct statistics_dbg dbg;
+	__le32 sleep_time;
+	__le32 slots_out;
+	__le32 slots_idle;
+	__le32 ttl_timestamp;
+	struct statistics_div div;
+	__le32 rx_enable_counter;
+	/*
+	 * num_of_sos_states:
+	 *  count the number of times we have to re-tune
+	 *  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;
+} __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)
+#define UCODE_STATISTICS_NARROW_BAND_MSK	(0x1 << 2)
+
+/*
+ * REPLY_STATISTICS_CMD = 0x9c,
+ * all devices identical.
+ *
+ * This command triggers an immediate response containing uCode statistics.
+ * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
+ *
+ * If the CLEAR_STATS configuration flag is set, uCode will clear its
+ * internal copy of the statistics (counters) after issuing the response.
+ * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
+ *
+ * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
+ * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
+ * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
+ */
+#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1)	/* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */
+struct iwl_statistics_cmd {
+	__le32 configuration_flags;	/* IWL_STATS_CONF_* */
+} __packed;
+
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
+ *
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated.  To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
+ *
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans.  uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
+ */
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK         cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_HT40_MODE_MSK        cpu_to_le32(0x8)
+
+struct iwl_notif_statistics {
+	__le32 flag;
+	struct statistics_rx rx;
+	struct statistics_tx tx;
+	struct statistics_general general;
+} __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)
+ *
+ * uCode send MISSED_BEACONS_NOTIFICATION to driver when detect beacon missed
+ * in regardless of how many missed beacons, which mean when driver receive the
+ * notification, inside the command, it can find all the beacons information
+ * which include number of total missed beacons, number of consecutive missed
+ * beacons, number of beacons received and number of beacons expected to
+ * receive.
+ *
+ * If uCode detected consecutive_missed_beacons > 5, it will reset the radio
+ * in order to bring the radio/PHY back to working state; which has no relation
+ * to when driver will perform sensitivity calibration.
+ *
+ * Driver should set it own missed_beacon_threshold to decide when to perform
+ * sensitivity calibration based on number of consecutive missed beacons in
+ * order to improve overall performance, especially in noisy environment.
+ *
+ */
+
+#define IWL_MISSED_BEACON_THRESHOLD_MIN	(1)
+#define IWL_MISSED_BEACON_THRESHOLD_DEF	(5)
+#define IWL_MISSED_BEACON_THRESHOLD_MAX	IWL_MISSED_BEACON_THRESHOLD_DEF
+
+struct iwl_missed_beacon_notif {
+	__le32 consecutive_missed_beacons;
+	__le32 total_missed_becons;
+	__le32 num_expected_beacons;
+	__le32 num_recvd_beacons;
+} __packed;
+
+
+/******************************************************************************
+ * (11)
+ * Rx Calibration Commands:
+ *
+ * With the uCode used for open source drivers, most Tx calibration (except
+ * for Tx Power) and most Rx calibration is done by uCode during the
+ * "initialize" phase of uCode boot.  Driver must calibrate only:
+ *
+ * 1)  Tx power (depends on temperature), described elsewhere
+ * 2)  Receiver gain balance (optimize MIMO, and detect disconnected antennas)
+ * 3)  Receiver sensitivity (to optimize signal detection)
+ *
+ *****************************************************************************/
+
+/**
+ * SENSITIVITY_CMD = 0xa8 (command, has simple generic response)
+ *
+ * This command sets up the Rx signal detector for a sensitivity level that
+ * is high enough to lock onto all signals within the associated network,
+ * but low enough to ignore signals that are below a certain threshold, so as
+ * not to have too many "false alarms".  False alarms are signals that the
+ * Rx DSP tries to lock onto, but then discards after determining that they
+ * are noise.
+ *
+ * The optimum number of false alarms is between 5 and 50 per 200 TUs
+ * (200 * 1024 uSecs, i.e. 204.8 milliseconds) of actual Rx time (i.e.
+ * time listening, not transmitting).  Driver must adjust sensitivity so that
+ * the ratio of actual false alarms to actual Rx time falls within this range.
+ *
+ * While associated, uCode delivers STATISTICS_NOTIFICATIONs after each
+ * received beacon.  These provide information to the driver to analyze the
+ * sensitivity.  Don't analyze statistics that come in from scanning, or any
+ * other non-associated-network source.  Pertinent statistics include:
+ *
+ * From "general" statistics (struct statistics_rx_non_phy):
+ *
+ * (beacon_energy_[abc] & 0x0FF00) >> 8 (unsigned, higher value is lower level)
+ *   Measure of energy of desired signal.  Used for establishing a level
+ *   below which the device does not detect signals.
+ *
+ * (beacon_silence_rssi_[abc] & 0x0FF00) >> 8 (unsigned, units in dB)
+ *   Measure of background noise in silent period after beacon.
+ *
+ * channel_load
+ *   uSecs of actual Rx time during beacon period (varies according to
+ *   how much time was spent transmitting).
+ *
+ * From "cck" and "ofdm" statistics (struct statistics_rx_phy), separately:
+ *
+ * false_alarm_cnt
+ *   Signal locks abandoned early (before phy-level header).
+ *
+ * plcp_err
+ *   Signal locks abandoned late (during phy-level header).
+ *
+ * NOTE:  Both false_alarm_cnt and plcp_err increment monotonically from
+ *        beacon to beacon, i.e. each value is an accumulation of all errors
+ *        before and including the latest beacon.  Values will wrap around to 0
+ *        after counting up to 2^32 - 1.  Driver must differentiate vs.
+ *        previous beacon's values to determine # false alarms in the current
+ *        beacon period.
+ *
+ * Total number of false alarms = false_alarms + plcp_errs
+ *
+ * For OFDM, adjust the following table entries in struct iwl_sensitivity_cmd
+ * (notice that the start points for OFDM are at or close to settings for
+ * maximum sensitivity):
+ *
+ *                                             START  /  MIN  /  MAX
+ *   HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          90   /   85  /  120
+ *   HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX     170   /  170  /  210
+ *   HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX         105   /  105  /  140
+ *   HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX     220   /  220  /  270
+ *
+ *   If actual rate of OFDM false alarms (+ plcp_errors) is too high
+ *   (greater than 50 for each 204.8 msecs listening), reduce sensitivity
+ *   by *adding* 1 to all 4 of the table entries above, up to the max for
+ *   each entry.  Conversely, if false alarm rate is too low (less than 5
+ *   for each 204.8 msecs listening), *subtract* 1 from each entry to
+ *   increase sensitivity.
+ *
+ * For CCK sensitivity, keep track of the following:
+ *
+ *   1).  20-beacon history of maximum background noise, indicated by
+ *        (beacon_silence_rssi_[abc] & 0x0FF00), units in dB, across the
+ *        3 receivers.  For any given beacon, the "silence reference" is
+ *        the maximum of last 60 samples (20 beacons * 3 receivers).
+ *
+ *   2).  10-beacon history of strongest signal level, as indicated
+ *        by (beacon_energy_[abc] & 0x0FF00) >> 8, across the 3 receivers,
+ *        i.e. the strength of the signal through the best receiver at the
+ *        moment.  These measurements are "upside down", with lower values
+ *        for stronger signals, so max energy will be *minimum* value.
+ *
+ *        Then for any given beacon, the driver must determine the *weakest*
+ *        of the strongest signals; this is the minimum level that needs to be
+ *        successfully detected, when using the best receiver at the moment.
+ *        "Max cck energy" is the maximum (higher value means lower energy!)
+ *        of the last 10 minima.  Once this is determined, driver must add
+ *        a little margin by adding "6" to it.
+ *
+ *   3).  Number of consecutive beacon periods with too few false alarms.
+ *        Reset this to 0 at the first beacon period that falls within the
+ *        "good" range (5 to 50 false alarms per 204.8 milliseconds rx).
+ *
+ * Then, adjust the following CCK table entries in struct iwl_sensitivity_cmd
+ * (notice that the start points for CCK are at maximum sensitivity):
+ *
+ *                                             START  /  MIN  /  MAX
+ *   HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX         125   /  125  /  200
+ *   HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX     200   /  200  /  400
+ *   HD_MIN_ENERGY_CCK_DET_INDEX                100   /    0  /  100
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is too high
+ *   (greater than 50 for each 204.8 msecs listening), method for reducing
+ *   sensitivity is:
+ *
+ *   1)  *Add* 3 to value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
+ *       up to max 400.
+ *
+ *   2)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is < 160,
+ *       sensitivity has been reduced a significant amount; bring it up to
+ *       a moderate 161.  Otherwise, *add* 3, up to max 200.
+ *
+ *   3)  a)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is > 160,
+ *       sensitivity has been reduced only a moderate or small amount;
+ *       *subtract* 2 from value in HD_MIN_ENERGY_CCK_DET_INDEX,
+ *       down to min 0.  Otherwise (if gain has been significantly reduced),
+ *       don't change the HD_MIN_ENERGY_CCK_DET_INDEX value.
+ *
+ *       b)  Save a snapshot of the "silence reference".
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is too low
+ *   (less than 5 for each 204.8 msecs listening), method for increasing
+ *   sensitivity is used only if:
+ *
+ *   1a)  Previous beacon did not have too many false alarms
+ *   1b)  AND difference between previous "silence reference" and current
+ *        "silence reference" (prev - current) is 2 or more,
+ *   OR 2)  100 or more consecutive beacon periods have had rate of
+ *          less than 5 false alarms per 204.8 milliseconds rx time.
+ *
+ *   Method for increasing sensitivity:
+ *
+ *   1)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX,
+ *       down to min 125.
+ *
+ *   2)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
+ *       down to min 200.
+ *
+ *   3)  *Add* 2 to value in HD_MIN_ENERGY_CCK_DET_INDEX, up to max 100.
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is within good range
+ *   (between 5 and 50 for each 204.8 msecs listening):
+ *
+ *   1)  Save a snapshot of the silence reference.
+ *
+ *   2)  If previous beacon had too many CCK false alarms (+ plcp_errors),
+ *       give some extra margin to energy threshold by *subtracting* 8
+ *       from value in HD_MIN_ENERGY_CCK_DET_INDEX.
+ *
+ *   For all cases (too few, too many, good range), make sure that the CCK
+ *   detection threshold (energy) is below the energy level for robust
+ *   detection over the past 10 beacon periods, the "Max cck energy".
+ *   Lower values mean higher energy; this means making sure that the value
+ *   in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy".
+ *
+ */
+
+/*
+ * Table entries in SENSITIVITY_CMD (struct iwl_sensitivity_cmd)
+ */
+#define HD_TABLE_SIZE  (11)	/* number of entries */
+#define HD_MIN_ENERGY_CCK_DET_INDEX                 (0)	/* table indexes */
+#define HD_MIN_ENERGY_OFDM_DET_INDEX                (1)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          (2)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX      (3)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX      (4)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX          (5)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX      (6)
+#define HD_BARKER_CORR_TH_ADD_MIN_INDEX             (7)
+#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX         (8)
+#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_V1		cpu_to_le16(0)
+#define HD_INA_NON_SQUARE_DET_CCK_DATA_V1		cpu_to_le16(0)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1		cpu_to_le16(0)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1	cpu_to_le16(668)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1	cpu_to_le16(4)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1		cpu_to_le16(486)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1	cpu_to_le16(37)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1		cpu_to_le16(853)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1	cpu_to_le16(4)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1		cpu_to_le16(476)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1		cpu_to_le16(99)
+
+#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V2		cpu_to_le16(1)
+#define HD_INA_NON_SQUARE_DET_CCK_DATA_V2		cpu_to_le16(1)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2		cpu_to_le16(1)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2	cpu_to_le16(600)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2	cpu_to_le16(40)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2		cpu_to_le16(486)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2	cpu_to_le16(45)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2		cpu_to_le16(853)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2	cpu_to_le16(60)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2		cpu_to_le16(476)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2		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)
+
+/**
+ * struct iwl_sensitivity_cmd
+ * @control:  (1) updates working table, (0) updates default table
+ * @table:  energy threshold values, use HD_* as index into table
+ *
+ * Always use "1" in "control" to update uCode's working table and DSP.
+ */
+struct iwl_sensitivity_cmd {
+	__le16 control;			/* always use "1" */
+	__le16 table[HD_TABLE_SIZE];	/* use HD_* as index */
+} __packed;
+
+/*
+ *
+ */
+struct iwl_enhance_sensitivity_cmd {
+	__le16 control;			/* always use "1" */
+	__le16 enhance_table[ENHANCE_HD_TABLE_SIZE];	/* use HD_* as index */
+} __packed;
+
+
+/**
+ * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)
+ *
+ * This command sets the relative gains of agn device's 3 radio receiver chains.
+ *
+ * After the first association, driver should accumulate signal and noise
+ * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20
+ * beacons from the associated network (don't collect statistics that come
+ * in from scanning, or any other non-network source).
+ *
+ * DISCONNECTED ANTENNA:
+ *
+ * Driver should determine which antennas are actually connected, by comparing
+ * average beacon signal levels for the 3 Rx chains.  Accumulate (add) the
+ * following values over 20 beacons, one accumulator for each of the chains
+ * a/b/c, from struct statistics_rx_non_phy:
+ *
+ * beacon_rssi_[abc] & 0x0FF (unsigned, units in dB)
+ *
+ * Find the strongest signal from among a/b/c.  Compare the other two to the
+ * strongest.  If any signal is more than 15 dB (times 20, unless you
+ * divide the accumulated values by 20) below the strongest, the driver
+ * considers that antenna to be disconnected, and should not try to use that
+ * antenna/chain for Rx or Tx.  If both A and B seem to be disconnected,
+ * driver should declare the stronger one as connected, and attempt to use it
+ * (A and B are the only 2 Tx chains!).
+ *
+ *
+ * RX BALANCE:
+ *
+ * Driver should balance the 3 receivers (but just the ones that are connected
+ * to antennas, see above) for gain, by comparing the average signal levels
+ * detected during the silence after each beacon (background noise).
+ * Accumulate (add) the following values over 20 beacons, one accumulator for
+ * each of the chains a/b/c, from struct statistics_rx_non_phy:
+ *
+ * beacon_silence_rssi_[abc] & 0x0FF (unsigned, units in dB)
+ *
+ * Find the weakest background noise level from among a/b/c.  This Rx chain
+ * will be the reference, with 0 gain adjustment.  Attenuate other channels by
+ * finding noise difference:
+ *
+ * (accum_noise[i] - accum_noise[reference]) / 30
+ *
+ * The "30" adjusts the dB in the 20 accumulated samples to units of 1.5 dB.
+ * For use in diff_gain_[abc] fields of struct iwl_calibration_cmd, the
+ * driver should limit the difference results to a range of 0-3 (0-4.5 dB),
+ * and set bit 2 to indicate "reduce gain".  The value for the reference
+ * (weakest) chain should be "0".
+ *
+ * diff_gain_[abc] bit fields:
+ *   2: (1) reduce gain, (0) increase gain
+ * 1-0: amount of gain, units of 1.5 dB
+ */
+
+/* Phy calibration command for series */
+enum {
+	IWL_PHY_CALIBRATE_DC_CMD		= 8,
+	IWL_PHY_CALIBRATE_LO_CMD		= 9,
+	IWL_PHY_CALIBRATE_TX_IQ_CMD		= 11,
+	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_TEMP_OFFSET_CMD	= 18,
+};
+
+/* This enum defines the bitmap of various calibrations to enable in both
+ * init ucode and runtime ucode through CALIBRATION_CFG_CMD.
+ */
+enum iwl_ucode_calib_cfg {
+	IWL_CALIB_CFG_RX_BB_IDX			= BIT(0),
+	IWL_CALIB_CFG_DC_IDX			= BIT(1),
+	IWL_CALIB_CFG_LO_IDX			= BIT(2),
+	IWL_CALIB_CFG_TX_IQ_IDX			= BIT(3),
+	IWL_CALIB_CFG_RX_IQ_IDX			= BIT(4),
+	IWL_CALIB_CFG_NOISE_IDX			= BIT(5),
+	IWL_CALIB_CFG_CRYSTAL_IDX		= BIT(6),
+	IWL_CALIB_CFG_TEMPERATURE_IDX		= BIT(7),
+	IWL_CALIB_CFG_PAPD_IDX			= BIT(8),
+	IWL_CALIB_CFG_SENSITIVITY_IDX		= BIT(9),
+	IWL_CALIB_CFG_TX_PWR_IDX		= BIT(10),
+};
+
+#define IWL_CALIB_INIT_CFG_ALL	cpu_to_le32(IWL_CALIB_CFG_RX_BB_IDX |	\
+					IWL_CALIB_CFG_DC_IDX |		\
+					IWL_CALIB_CFG_LO_IDX |		\
+					IWL_CALIB_CFG_TX_IQ_IDX |	\
+					IWL_CALIB_CFG_RX_IQ_IDX |	\
+					IWL_CALIB_CFG_CRYSTAL_IDX)
+
+#define IWL_CALIB_RT_CFG_ALL	cpu_to_le32(IWL_CALIB_CFG_RX_BB_IDX |	\
+					IWL_CALIB_CFG_DC_IDX |		\
+					IWL_CALIB_CFG_LO_IDX |		\
+					IWL_CALIB_CFG_TX_IQ_IDX |	\
+					IWL_CALIB_CFG_RX_IQ_IDX |	\
+					IWL_CALIB_CFG_TEMPERATURE_IDX |	\
+					IWL_CALIB_CFG_PAPD_IDX |	\
+					IWL_CALIB_CFG_TX_PWR_IDX |	\
+					IWL_CALIB_CFG_CRYSTAL_IDX)
+
+#define IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK	cpu_to_le32(BIT(0))
+
+struct iwl_calib_cfg_elmnt_s {
+	__le32 is_enable;
+	__le32 start;
+	__le32 send_res;
+	__le32 apply_res;
+	__le32 reserved;
+} __packed;
+
+struct iwl_calib_cfg_status_s {
+	struct iwl_calib_cfg_elmnt_s once;
+	struct iwl_calib_cfg_elmnt_s perd;
+	__le32 flags;
+} __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;
+} __packed;
+
+struct iwl_calib_hdr {
+	u8 op_code;
+	u8 first_group;
+	u8 groups_num;
+	u8 data_valid;
+} __packed;
+
+struct iwl_calib_cmd {
+	struct iwl_calib_hdr hdr;
+	u8 data[0];
+} __packed;
+
+struct iwl_calib_xtal_freq_cmd {
+	struct iwl_calib_hdr hdr;
+	u8 cap_pin1;
+	u8 cap_pin2;
+	u8 pad[2];
+} __packed;
+
+#define DEFAULT_RADIO_SENSOR_OFFSET    cpu_to_le16(2700)
+struct iwl_calib_temperature_offset_cmd {
+	struct iwl_calib_hdr hdr;
+	__le16 radio_sensor_offset;
+	__le16 reserved;
+} __packed;
+
+struct iwl_calib_temperature_offset_v2_cmd {
+	struct iwl_calib_hdr hdr;
+	__le16 radio_sensor_offset_high;
+	__le16 radio_sensor_offset_low;
+	__le16 burntVoltageRef;
+	__le16 reserved;
+} __packed;
+
+/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
+struct iwl_calib_chain_noise_reset_cmd {
+	struct iwl_calib_hdr hdr;
+	u8 data[0];
+};
+
+/* IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */
+struct iwl_calib_chain_noise_gain_cmd {
+	struct iwl_calib_hdr hdr;
+	u8 delta_gain_1;
+	u8 delta_gain_2;
+	u8 pad[2];
+} __packed;
+
+/******************************************************************************
+ * (12)
+ * Miscellaneous Commands:
+ *
+ *****************************************************************************/
+
+/*
+ * LEDs Command & Response
+ * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
+ *
+ * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
+ * this command turns it on or off, or sets up a periodic blinking cycle.
+ */
+struct iwl_led_cmd {
+	__le32 interval;	/* "interval" in uSec */
+	u8 id;			/* 1: Activity, 2: Link, 3: Tech */
+	u8 off;			/* # intervals off while blinking;
+				 * "0", with >0 "on" value, turns LED on */
+	u8 on;			/* # intervals on while blinking;
+				 * "0", regardless of "off", turns LED off */
+	u8 reserved;
+} __packed;
+
+/*
+ * station priority table entries
+ * also used as potential "events" value for both
+ * COEX_MEDIUM_NOTIFICATION and COEX_EVENT_CMD
+ */
+
+/*
+ * COEX events entry flag masks
+ * RP - Requested Priority
+ * WP - Win Medium Priority: priority assigned when the contention has been won
+ */
+#define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG        (0x1)
+#define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG        (0x2)
+#define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG  (0x4)
+
+#define COEX_CU_UNASSOC_IDLE_RP               4
+#define COEX_CU_UNASSOC_MANUAL_SCAN_RP        4
+#define COEX_CU_UNASSOC_AUTO_SCAN_RP          4
+#define COEX_CU_CALIBRATION_RP                4
+#define COEX_CU_PERIODIC_CALIBRATION_RP       4
+#define COEX_CU_CONNECTION_ESTAB_RP           4
+#define COEX_CU_ASSOCIATED_IDLE_RP            4
+#define COEX_CU_ASSOC_MANUAL_SCAN_RP          4
+#define COEX_CU_ASSOC_AUTO_SCAN_RP            4
+#define COEX_CU_ASSOC_ACTIVE_LEVEL_RP         4
+#define COEX_CU_RF_ON_RP                      6
+#define COEX_CU_RF_OFF_RP                     4
+#define COEX_CU_STAND_ALONE_DEBUG_RP          6
+#define COEX_CU_IPAN_ASSOC_LEVEL_RP           4
+#define COEX_CU_RSRVD1_RP                     4
+#define COEX_CU_RSRVD2_RP                     4
+
+#define COEX_CU_UNASSOC_IDLE_WP               3
+#define COEX_CU_UNASSOC_MANUAL_SCAN_WP        3
+#define COEX_CU_UNASSOC_AUTO_SCAN_WP          3
+#define COEX_CU_CALIBRATION_WP                3
+#define COEX_CU_PERIODIC_CALIBRATION_WP       3
+#define COEX_CU_CONNECTION_ESTAB_WP           3
+#define COEX_CU_ASSOCIATED_IDLE_WP            3
+#define COEX_CU_ASSOC_MANUAL_SCAN_WP          3
+#define COEX_CU_ASSOC_AUTO_SCAN_WP            3
+#define COEX_CU_ASSOC_ACTIVE_LEVEL_WP         3
+#define COEX_CU_RF_ON_WP                      3
+#define COEX_CU_RF_OFF_WP                     3
+#define COEX_CU_STAND_ALONE_DEBUG_WP          6
+#define COEX_CU_IPAN_ASSOC_LEVEL_WP           3
+#define COEX_CU_RSRVD1_WP                     3
+#define COEX_CU_RSRVD2_WP                     3
+
+#define COEX_UNASSOC_IDLE_FLAGS                     0
+#define COEX_UNASSOC_MANUAL_SCAN_FLAGS		\
+	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
+	COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_UNASSOC_AUTO_SCAN_FLAGS		\
+	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
+	COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_CALIBRATION_FLAGS			\
+	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
+	COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_PERIODIC_CALIBRATION_FLAGS             0
+/*
+ * COEX_CONNECTION_ESTAB:
+ * we need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network.
+ */
+#define COEX_CONNECTION_ESTAB_FLAGS		\
+	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
+	COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |	\
+	COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
+#define COEX_ASSOCIATED_IDLE_FLAGS                  0
+#define COEX_ASSOC_MANUAL_SCAN_FLAGS		\
+	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
+	COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_ASSOC_AUTO_SCAN_FLAGS		\
+	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
+	 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_ASSOC_ACTIVE_LEVEL_FLAGS               0
+#define COEX_RF_ON_FLAGS                            0
+#define COEX_RF_OFF_FLAGS                           0
+#define COEX_STAND_ALONE_DEBUG_FLAGS		\
+	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
+	 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_IPAN_ASSOC_LEVEL_FLAGS		\
+	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
+	 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |	\
+	 COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
+#define COEX_RSRVD1_FLAGS                           0
+#define COEX_RSRVD2_FLAGS                           0
+/*
+ * COEX_CU_RF_ON is the event wrapping all radio ownership.
+ * We need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network.
+ */
+#define COEX_CU_RF_ON_FLAGS			\
+	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
+	 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |	\
+	 COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
+
+
+enum {
+	/* un-association part */
+	COEX_UNASSOC_IDLE		= 0,
+	COEX_UNASSOC_MANUAL_SCAN	= 1,
+	COEX_UNASSOC_AUTO_SCAN		= 2,
+	/* calibration */
+	COEX_CALIBRATION		= 3,
+	COEX_PERIODIC_CALIBRATION	= 4,
+	/* connection */
+	COEX_CONNECTION_ESTAB		= 5,
+	/* association part */
+	COEX_ASSOCIATED_IDLE		= 6,
+	COEX_ASSOC_MANUAL_SCAN		= 7,
+	COEX_ASSOC_AUTO_SCAN		= 8,
+	COEX_ASSOC_ACTIVE_LEVEL		= 9,
+	/* RF ON/OFF */
+	COEX_RF_ON			= 10,
+	COEX_RF_OFF			= 11,
+	COEX_STAND_ALONE_DEBUG		= 12,
+	/* IPAN */
+	COEX_IPAN_ASSOC_LEVEL		= 13,
+	/* reserved */
+	COEX_RSRVD1			= 14,
+	COEX_RSRVD2			= 15,
+	COEX_NUM_OF_EVENTS		= 16
+};
+
+/*
+ * Coexistence WIFI/WIMAX  Command
+ * COEX_PRIORITY_TABLE_CMD = 0x5a
+ *
+ */
+struct iwl_wimax_coex_event_entry {
+	u8 request_prio;
+	u8 win_medium_prio;
+	u8 reserved;
+	u8 flags;
+} __packed;
+
+/* COEX flag masks */
+
+/* Station table is valid */
+#define COEX_FLAGS_STA_TABLE_VALID_MSK      (0x1)
+/* UnMask wake up src at unassociated sleep */
+#define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK    (0x4)
+/* UnMask wake up src at associated sleep */
+#define COEX_FLAGS_ASSOC_WA_UNMASK_MSK      (0x8)
+/* Enable CoEx feature. */
+#define COEX_FLAGS_COEX_ENABLE_MSK          (0x80)
+
+struct iwl_wimax_coex_cmd {
+	u8 flags;
+	u8 reserved[3];
+	struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS];
+} __packed;
+
+/*
+ * Coexistence MEDIUM NOTIFICATION
+ * COEX_MEDIUM_NOTIFICATION = 0x5b
+ *
+ * notification from uCode to host to indicate medium changes
+ *
+ */
+/*
+ * status field
+ * bit 0 - 2: medium status
+ * bit 3: medium change indication
+ * bit 4 - 31: reserved
+ */
+/* status option values, (0 - 2 bits) */
+#define COEX_MEDIUM_BUSY	(0x0) /* radio belongs to WiMAX */
+#define COEX_MEDIUM_ACTIVE	(0x1) /* radio belongs to WiFi */
+#define COEX_MEDIUM_PRE_RELEASE	(0x2) /* received radio release */
+#define COEX_MEDIUM_MSK		(0x7)
+
+/* send notification status (1 bit) */
+#define COEX_MEDIUM_CHANGED	(0x8)
+#define COEX_MEDIUM_CHANGED_MSK	(0x8)
+#define COEX_MEDIUM_SHIFT	(3)
+
+struct iwl_coex_medium_notification {
+	__le32 status;
+	__le32 events;
+} __packed;
+
+/*
+ * Coexistence EVENT  Command
+ * COEX_EVENT_CMD = 0x5c
+ *
+ * send from host to uCode for coex event request.
+ */
+/* flags options */
+#define COEX_EVENT_REQUEST_MSK	(0x1)
+
+struct iwl_coex_event_cmd {
+	u8 flags;
+	u8 event;
+	__le16 reserved;
+} __packed;
+
+struct iwl_coex_event_resp {
+	__le32 status;
+} __packed;
+
+
+/******************************************************************************
+ * Bluetooth Coexistence commands
+ *
+ *****************************************************************************/
+
+/*
+ * BT Status notification
+ * REPLY_BT_COEX_PROFILE_NOTIF = 0xce
+ */
+enum iwl_bt_coex_profile_traffic_load {
+	IWL_BT_COEX_TRAFFIC_LOAD_NONE = 	0,
+	IWL_BT_COEX_TRAFFIC_LOAD_LOW =		1,
+	IWL_BT_COEX_TRAFFIC_LOAD_HIGH = 	2,
+	IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS =	3,
+/*
+ * There are no more even though below is a u8, the
+ * indication from the BT device only has two bits.
+ */
+};
+
+#define BT_SESSION_ACTIVITY_1_UART_MSG		0x1
+#define BT_SESSION_ACTIVITY_2_UART_MSG		0x2
+
+/* BT UART message - Share Part (BT -> WiFi) */
+#define BT_UART_MSG_FRAME1MSGTYPE_POS		(0)
+#define BT_UART_MSG_FRAME1MSGTYPE_MSK		\
+		(0x7 << BT_UART_MSG_FRAME1MSGTYPE_POS)
+#define BT_UART_MSG_FRAME1SSN_POS		(3)
+#define BT_UART_MSG_FRAME1SSN_MSK		\
+		(0x3 << BT_UART_MSG_FRAME1SSN_POS)
+#define BT_UART_MSG_FRAME1UPDATEREQ_POS		(5)
+#define BT_UART_MSG_FRAME1UPDATEREQ_MSK		\
+		(0x1 << BT_UART_MSG_FRAME1UPDATEREQ_POS)
+#define BT_UART_MSG_FRAME1RESERVED_POS		(6)
+#define BT_UART_MSG_FRAME1RESERVED_MSK		\
+		(0x3 << BT_UART_MSG_FRAME1RESERVED_POS)
+
+#define BT_UART_MSG_FRAME2OPENCONNECTIONS_POS	(0)
+#define BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK	\
+		(0x3 << BT_UART_MSG_FRAME2OPENCONNECTIONS_POS)
+#define BT_UART_MSG_FRAME2TRAFFICLOAD_POS	(2)
+#define BT_UART_MSG_FRAME2TRAFFICLOAD_MSK	\
+		(0x3 << BT_UART_MSG_FRAME2TRAFFICLOAD_POS)
+#define BT_UART_MSG_FRAME2CHLSEQN_POS		(4)
+#define BT_UART_MSG_FRAME2CHLSEQN_MSK		\
+		(0x1 << BT_UART_MSG_FRAME2CHLSEQN_POS)
+#define BT_UART_MSG_FRAME2INBAND_POS		(5)
+#define BT_UART_MSG_FRAME2INBAND_MSK		\
+		(0x1 << BT_UART_MSG_FRAME2INBAND_POS)
+#define BT_UART_MSG_FRAME2RESERVED_POS		(6)
+#define BT_UART_MSG_FRAME2RESERVED_MSK		\
+		(0x3 << BT_UART_MSG_FRAME2RESERVED_POS)
+
+#define BT_UART_MSG_FRAME3SCOESCO_POS		(0)
+#define BT_UART_MSG_FRAME3SCOESCO_MSK		\
+		(0x1 << BT_UART_MSG_FRAME3SCOESCO_POS)
+#define BT_UART_MSG_FRAME3SNIFF_POS		(1)
+#define BT_UART_MSG_FRAME3SNIFF_MSK		\
+		(0x1 << BT_UART_MSG_FRAME3SNIFF_POS)
+#define BT_UART_MSG_FRAME3A2DP_POS		(2)
+#define BT_UART_MSG_FRAME3A2DP_MSK		\
+		(0x1 << BT_UART_MSG_FRAME3A2DP_POS)
+#define BT_UART_MSG_FRAME3ACL_POS		(3)
+#define BT_UART_MSG_FRAME3ACL_MSK		\
+		(0x1 << BT_UART_MSG_FRAME3ACL_POS)
+#define BT_UART_MSG_FRAME3MASTER_POS		(4)
+#define BT_UART_MSG_FRAME3MASTER_MSK		\
+		(0x1 << BT_UART_MSG_FRAME3MASTER_POS)
+#define BT_UART_MSG_FRAME3OBEX_POS		(5)
+#define BT_UART_MSG_FRAME3OBEX_MSK		\
+		(0x1 << BT_UART_MSG_FRAME3OBEX_POS)
+#define BT_UART_MSG_FRAME3RESERVED_POS		(6)
+#define BT_UART_MSG_FRAME3RESERVED_MSK		\
+		(0x3 << BT_UART_MSG_FRAME3RESERVED_POS)
+
+#define BT_UART_MSG_FRAME4IDLEDURATION_POS	(0)
+#define BT_UART_MSG_FRAME4IDLEDURATION_MSK	\
+		(0x3F << BT_UART_MSG_FRAME4IDLEDURATION_POS)
+#define BT_UART_MSG_FRAME4RESERVED_POS		(6)
+#define BT_UART_MSG_FRAME4RESERVED_MSK		\
+		(0x3 << BT_UART_MSG_FRAME4RESERVED_POS)
+
+#define BT_UART_MSG_FRAME5TXACTIVITY_POS	(0)
+#define BT_UART_MSG_FRAME5TXACTIVITY_MSK	\
+		(0x3 << BT_UART_MSG_FRAME5TXACTIVITY_POS)
+#define BT_UART_MSG_FRAME5RXACTIVITY_POS	(2)
+#define BT_UART_MSG_FRAME5RXACTIVITY_MSK	\
+		(0x3 << BT_UART_MSG_FRAME5RXACTIVITY_POS)
+#define BT_UART_MSG_FRAME5ESCORETRANSMIT_POS	(4)
+#define BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK	\
+		(0x3 << BT_UART_MSG_FRAME5ESCORETRANSMIT_POS)
+#define BT_UART_MSG_FRAME5RESERVED_POS		(6)
+#define BT_UART_MSG_FRAME5RESERVED_MSK		\
+		(0x3 << BT_UART_MSG_FRAME5RESERVED_POS)
+
+#define BT_UART_MSG_FRAME6SNIFFINTERVAL_POS	(0)
+#define BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK	\
+		(0x1F << BT_UART_MSG_FRAME6SNIFFINTERVAL_POS)
+#define BT_UART_MSG_FRAME6DISCOVERABLE_POS	(5)
+#define BT_UART_MSG_FRAME6DISCOVERABLE_MSK	\
+		(0x1 << BT_UART_MSG_FRAME6DISCOVERABLE_POS)
+#define BT_UART_MSG_FRAME6RESERVED_POS		(6)
+#define BT_UART_MSG_FRAME6RESERVED_MSK		\
+		(0x3 << BT_UART_MSG_FRAME6RESERVED_POS)
+
+#define BT_UART_MSG_FRAME7SNIFFACTIVITY_POS	(0)
+#define BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK	\
+		(0x7 << BT_UART_MSG_FRAME7SNIFFACTIVITY_POS)
+#define BT_UART_MSG_FRAME7PAGE_POS		(3)
+#define BT_UART_MSG_FRAME7PAGE_MSK		\
+		(0x1 << BT_UART_MSG_FRAME7PAGE_POS)
+#define BT_UART_MSG_FRAME7INQUIRY_POS		(4)
+#define BT_UART_MSG_FRAME7INQUIRY_MSK		\
+		(0x1 << BT_UART_MSG_FRAME7INQUIRY_POS)
+#define BT_UART_MSG_FRAME7CONNECTABLE_POS	(5)
+#define BT_UART_MSG_FRAME7CONNECTABLE_MSK	\
+		(0x1 << BT_UART_MSG_FRAME7CONNECTABLE_POS)
+#define BT_UART_MSG_FRAME7RESERVED_POS		(6)
+#define BT_UART_MSG_FRAME7RESERVED_MSK		\
+		(0x3 << BT_UART_MSG_FRAME7RESERVED_POS)
+
+/* BT Session Activity 2 UART message (BT -> WiFi) */
+#define BT_UART_MSG_2_FRAME1RESERVED1_POS	(5)
+#define BT_UART_MSG_2_FRAME1RESERVED1_MSK	\
+		(0x1<<BT_UART_MSG_2_FRAME1RESERVED1_POS)
+#define BT_UART_MSG_2_FRAME1RESERVED2_POS	(6)
+#define BT_UART_MSG_2_FRAME1RESERVED2_MSK	\
+		(0x3<<BT_UART_MSG_2_FRAME1RESERVED2_POS)
+
+#define BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_POS	(0)
+#define BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_MSK	\
+		(0x3F<<BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_POS)
+#define BT_UART_MSG_2_FRAME2RESERVED_POS	(6)
+#define BT_UART_MSG_2_FRAME2RESERVED_MSK	\
+		(0x3<<BT_UART_MSG_2_FRAME2RESERVED_POS)
+
+#define BT_UART_MSG_2_FRAME3BRLASTTXPOWER_POS	(0)
+#define BT_UART_MSG_2_FRAME3BRLASTTXPOWER_MSK	\
+		(0xF<<BT_UART_MSG_2_FRAME3BRLASTTXPOWER_POS)
+#define BT_UART_MSG_2_FRAME3INQPAGESRMODE_POS	(4)
+#define BT_UART_MSG_2_FRAME3INQPAGESRMODE_MSK	\
+		(0x1<<BT_UART_MSG_2_FRAME3INQPAGESRMODE_POS)
+#define BT_UART_MSG_2_FRAME3LEMASTER_POS	(5)
+#define BT_UART_MSG_2_FRAME3LEMASTER_MSK	\
+		(0x1<<BT_UART_MSG_2_FRAME3LEMASTER_POS)
+#define BT_UART_MSG_2_FRAME3RESERVED_POS	(6)
+#define BT_UART_MSG_2_FRAME3RESERVED_MSK	\
+		(0x3<<BT_UART_MSG_2_FRAME3RESERVED_POS)
+
+#define BT_UART_MSG_2_FRAME4LELASTTXPOWER_POS	(0)
+#define BT_UART_MSG_2_FRAME4LELASTTXPOWER_MSK	\
+		(0xF<<BT_UART_MSG_2_FRAME4LELASTTXPOWER_POS)
+#define BT_UART_MSG_2_FRAME4NUMLECONN_POS	(4)
+#define BT_UART_MSG_2_FRAME4NUMLECONN_MSK	\
+		(0x3<<BT_UART_MSG_2_FRAME4NUMLECONN_POS)
+#define BT_UART_MSG_2_FRAME4RESERVED_POS	(6)
+#define BT_UART_MSG_2_FRAME4RESERVED_MSK	\
+		(0x3<<BT_UART_MSG_2_FRAME4RESERVED_POS)
+
+#define BT_UART_MSG_2_FRAME5BTMINRSSI_POS	(0)
+#define BT_UART_MSG_2_FRAME5BTMINRSSI_MSK	\
+		(0xF<<BT_UART_MSG_2_FRAME5BTMINRSSI_POS)
+#define BT_UART_MSG_2_FRAME5LESCANINITMODE_POS	(4)
+#define BT_UART_MSG_2_FRAME5LESCANINITMODE_MSK	\
+		(0x1<<BT_UART_MSG_2_FRAME5LESCANINITMODE_POS)
+#define BT_UART_MSG_2_FRAME5LEADVERMODE_POS	(5)
+#define BT_UART_MSG_2_FRAME5LEADVERMODE_MSK	\
+		(0x1<<BT_UART_MSG_2_FRAME5LEADVERMODE_POS)
+#define BT_UART_MSG_2_FRAME5RESERVED_POS	(6)
+#define BT_UART_MSG_2_FRAME5RESERVED_MSK	\
+		(0x3<<BT_UART_MSG_2_FRAME5RESERVED_POS)
+
+#define BT_UART_MSG_2_FRAME6LECONNINTERVAL_POS	(0)
+#define BT_UART_MSG_2_FRAME6LECONNINTERVAL_MSK	\
+		(0x1F<<BT_UART_MSG_2_FRAME6LECONNINTERVAL_POS)
+#define BT_UART_MSG_2_FRAME6RFU_POS		(5)
+#define BT_UART_MSG_2_FRAME6RFU_MSK		\
+		(0x1<<BT_UART_MSG_2_FRAME6RFU_POS)
+#define BT_UART_MSG_2_FRAME6RESERVED_POS	(6)
+#define BT_UART_MSG_2_FRAME6RESERVED_MSK	\
+		(0x3<<BT_UART_MSG_2_FRAME6RESERVED_POS)
+
+#define BT_UART_MSG_2_FRAME7LECONNSLAVELAT_POS	(0)
+#define BT_UART_MSG_2_FRAME7LECONNSLAVELAT_MSK	\
+		(0x7<<BT_UART_MSG_2_FRAME7LECONNSLAVELAT_POS)
+#define BT_UART_MSG_2_FRAME7LEPROFILE1_POS	(3)
+#define BT_UART_MSG_2_FRAME7LEPROFILE1_MSK	\
+		(0x1<<BT_UART_MSG_2_FRAME7LEPROFILE1_POS)
+#define BT_UART_MSG_2_FRAME7LEPROFILE2_POS	(4)
+#define BT_UART_MSG_2_FRAME7LEPROFILE2_MSK	\
+		(0x1<<BT_UART_MSG_2_FRAME7LEPROFILE2_POS)
+#define BT_UART_MSG_2_FRAME7LEPROFILEOTHER_POS	(5)
+#define BT_UART_MSG_2_FRAME7LEPROFILEOTHER_MSK	\
+		(0x1<<BT_UART_MSG_2_FRAME7LEPROFILEOTHER_POS)
+#define BT_UART_MSG_2_FRAME7RESERVED_POS	(6)
+#define BT_UART_MSG_2_FRAME7RESERVED_MSK	\
+		(0x3<<BT_UART_MSG_2_FRAME7RESERVED_POS)
+
+
+#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD	(-62)
+#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD	(-65)
+
+struct iwl_bt_uart_msg {
+	u8 header;
+	u8 frame1;
+	u8 frame2;
+	u8 frame3;
+	u8 frame4;
+	u8 frame5;
+	u8 frame6;
+	u8 frame7;
+} __attribute__((packed));
+
+struct iwl_bt_coex_profile_notif {
+	struct iwl_bt_uart_msg last_bt_uart_msg;
+	u8 bt_status; /* 0 - off, 1 - on */
+	u8 bt_traffic_load; /* 0 .. 3? */
+	u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
+	u8 reserved;
+} __attribute__((packed));
+
+#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS	0
+#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK	0x1
+#define IWL_BT_COEX_PRIO_TBL_PRIO_POS		1
+#define IWL_BT_COEX_PRIO_TBL_PRIO_MASK		0x0e
+#define IWL_BT_COEX_PRIO_TBL_RESERVED_POS	4
+#define IWL_BT_COEX_PRIO_TBL_RESERVED_MASK	0xf0
+#define IWL_BT_COEX_PRIO_TBL_PRIO_SHIFT		1
+
+/*
+ * BT Coexistence Priority table
+ * REPLY_BT_COEX_PRIO_TABLE = 0xcc
+ */
+enum bt_coex_prio_table_events {
+	BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0,
+	BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1,
+	BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2,
+	BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3, /* DC calib */
+	BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4,
+	BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5,
+	BT_COEX_PRIO_TBL_EVT_DTIM = 6,
+	BT_COEX_PRIO_TBL_EVT_SCAN52 = 7,
+	BT_COEX_PRIO_TBL_EVT_SCAN24 = 8,
+	BT_COEX_PRIO_TBL_EVT_RESERVED0 = 9,
+	BT_COEX_PRIO_TBL_EVT_RESERVED1 = 10,
+	BT_COEX_PRIO_TBL_EVT_RESERVED2 = 11,
+	BT_COEX_PRIO_TBL_EVT_RESERVED3 = 12,
+	BT_COEX_PRIO_TBL_EVT_RESERVED4 = 13,
+	BT_COEX_PRIO_TBL_EVT_RESERVED5 = 14,
+	BT_COEX_PRIO_TBL_EVT_RESERVED6 = 15,
+	/* BT_COEX_PRIO_TBL_EVT_MAX should always be last */
+	BT_COEX_PRIO_TBL_EVT_MAX,
+};
+
+enum bt_coex_prio_table_priorities {
+	BT_COEX_PRIO_TBL_DISABLED = 0,
+	BT_COEX_PRIO_TBL_PRIO_LOW = 1,
+	BT_COEX_PRIO_TBL_PRIO_HIGH = 2,
+	BT_COEX_PRIO_TBL_PRIO_BYPASS = 3,
+	BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4,
+	BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5,
+	BT_COEX_PRIO_TBL_PRIO_RSRVD1 = 6,
+	BT_COEX_PRIO_TBL_PRIO_RSRVD2 = 7,
+	BT_COEX_PRIO_TBL_MAX,
+};
+
+struct iwl_bt_coex_prio_table_cmd {
+	u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
+} __attribute__((packed));
+
+#define IWL_BT_COEX_ENV_CLOSE	0
+#define IWL_BT_COEX_ENV_OPEN	1
+/*
+ * BT Protection Envelope
+ * REPLY_BT_COEX_PROT_ENV = 0xcd
+ */
+struct iwl_bt_coex_prot_env_cmd {
+	u8 action; /* 0 = closed, 1 = open */
+	u8 type; /* 0 .. 15 */
+	u8 reserved[2];
+} __attribute__((packed));
+
+/*
+ * REPLY_D3_CONFIG
+ */
+enum iwlagn_d3_wakeup_filters {
+	IWLAGN_D3_WAKEUP_RFKILL		= BIT(0),
+	IWLAGN_D3_WAKEUP_SYSASSERT	= BIT(1),
+};
+
+struct iwlagn_d3_config_cmd {
+	__le32 min_sleep_time;
+	__le32 wakeup_flags;
+} __packed;
+
+/*
+ * REPLY_WOWLAN_PATTERNS
+ */
+#define IWLAGN_WOWLAN_MIN_PATTERN_LEN	16
+#define IWLAGN_WOWLAN_MAX_PATTERN_LEN	128
+
+struct iwlagn_wowlan_pattern {
+	u8 mask[IWLAGN_WOWLAN_MAX_PATTERN_LEN / 8];
+	u8 pattern[IWLAGN_WOWLAN_MAX_PATTERN_LEN];
+	u8 mask_size;
+	u8 pattern_size;
+	__le16 reserved;
+} __packed;
+
+#define IWLAGN_WOWLAN_MAX_PATTERNS	20
+
+struct iwlagn_wowlan_patterns_cmd {
+	__le32 n_patterns;
+	struct iwlagn_wowlan_pattern patterns[];
+} __packed;
+
+/*
+ * REPLY_WOWLAN_WAKEUP_FILTER
+ */
+enum iwlagn_wowlan_wakeup_filters {
+	IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET	= BIT(0),
+	IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH	= BIT(1),
+	IWLAGN_WOWLAN_WAKEUP_BEACON_MISS	= BIT(2),
+	IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE	= BIT(3),
+	IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL	= BIT(4),
+	IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ	= BIT(5),
+	IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE	= BIT(6),
+	IWLAGN_WOWLAN_WAKEUP_ALWAYS		= BIT(7),
+	IWLAGN_WOWLAN_WAKEUP_ENABLE_NET_DETECT	= BIT(8),
+};
+
+struct iwlagn_wowlan_wakeup_filter_cmd {
+	__le32 enabled;
+	__le16 non_qos_seq;
+	__le16 reserved;
+	__le16 qos_seq[8];
+};
+
+/*
+ * REPLY_WOWLAN_TSC_RSC_PARAMS
+ */
+#define IWLAGN_NUM_RSC	16
+
+struct tkip_sc {
+	__le16 iv16;
+	__le16 pad;
+	__le32 iv32;
+} __packed;
+
+struct iwlagn_tkip_rsc_tsc {
+	struct tkip_sc unicast_rsc[IWLAGN_NUM_RSC];
+	struct tkip_sc multicast_rsc[IWLAGN_NUM_RSC];
+	struct tkip_sc tsc;
+} __packed;
+
+struct aes_sc {
+	__le64 pn;
+} __packed;
+
+struct iwlagn_aes_rsc_tsc {
+	struct aes_sc unicast_rsc[IWLAGN_NUM_RSC];
+	struct aes_sc multicast_rsc[IWLAGN_NUM_RSC];
+	struct aes_sc tsc;
+} __packed;
+
+union iwlagn_all_tsc_rsc {
+	struct iwlagn_tkip_rsc_tsc tkip;
+	struct iwlagn_aes_rsc_tsc aes;
+};
+
+struct iwlagn_wowlan_rsc_tsc_params_cmd {
+	union iwlagn_all_tsc_rsc all_tsc_rsc;
+} __packed;
+
+/*
+ * REPLY_WOWLAN_TKIP_PARAMS
+ */
+#define IWLAGN_MIC_KEY_SIZE	8
+#define IWLAGN_P1K_SIZE		5
+struct iwlagn_mic_keys {
+	u8 tx[IWLAGN_MIC_KEY_SIZE];
+	u8 rx_unicast[IWLAGN_MIC_KEY_SIZE];
+	u8 rx_mcast[IWLAGN_MIC_KEY_SIZE];
+} __packed;
+
+struct iwlagn_p1k_cache {
+	__le16 p1k[IWLAGN_P1K_SIZE];
+} __packed;
+
+#define IWLAGN_NUM_RX_P1K_CACHE	2
+
+struct iwlagn_wowlan_tkip_params_cmd {
+	struct iwlagn_mic_keys mic_keys;
+	struct iwlagn_p1k_cache tx;
+	struct iwlagn_p1k_cache rx_uni[IWLAGN_NUM_RX_P1K_CACHE];
+	struct iwlagn_p1k_cache rx_multi[IWLAGN_NUM_RX_P1K_CACHE];
+} __packed;
+
+/*
+ * REPLY_WOWLAN_KEK_KCK_MATERIAL
+ */
+
+#define IWLAGN_KCK_MAX_SIZE	32
+#define IWLAGN_KEK_MAX_SIZE	32
+
+struct iwlagn_wowlan_kek_kck_material_cmd {
+	u8	kck[IWLAGN_KCK_MAX_SIZE];
+	u8	kek[IWLAGN_KEK_MAX_SIZE];
+	__le16	kck_len;
+	__le16	kek_len;
+	__le64	replay_ctr;
+} __packed;
+
+/*
+ * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
+ */
+
+/*
+ * Minimum slot time in TU
+ */
+#define IWL_MIN_SLOT_TIME	20
+
+/**
+ * struct iwl_wipan_slot
+ * @width: Time in TU
+ * @type:
+ *   0 - BSS
+ *   1 - PAN
+ */
+struct iwl_wipan_slot {
+	__le16 width;
+	u8 type;
+	u8 reserved;
+} __packed;
+
+#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_CTS		BIT(1)	/* reserved */
+#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_QUIET	BIT(2)	/* reserved */
+#define IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE		BIT(3)	/* reserved */
+#define IWL_WIPAN_PARAMS_FLG_FILTER_BEACON_NOTIF	BIT(4)
+#define IWL_WIPAN_PARAMS_FLG_FULL_SLOTTED_MODE		BIT(5)
+
+/**
+ * struct iwl_wipan_params_cmd
+ * @flags:
+ *   bit0: reserved
+ *   bit1: CP leave channel with CTS
+ *   bit2: CP leave channel qith Quiet
+ *   bit3: slotted mode
+ *     1 - work in slotted mode
+ *     0 - work in non slotted mode
+ *   bit4: filter beacon notification
+ *   bit5: full tx slotted mode. if this flag is set,
+ *         uCode will perform leaving channel methods in context switch
+ *         also when working in same channel mode
+ * @num_slots: 1 - 10
+ */
+struct iwl_wipan_params_cmd {
+	__le16 flags;
+	u8 reserved;
+	u8 num_slots;
+	struct iwl_wipan_slot slots[10];
+} __packed;
+
+/*
+ * REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9
+ *
+ * TODO: Figure out what this is used for,
+ *	 it can only switch between 2.4 GHz
+ *	 channels!!
+ */
+
+struct iwl_wipan_p2p_channel_switch_cmd {
+	__le16 channel;
+	__le16 reserved;
+};
+
+/*
+ * REPLY_WIPAN_NOA_NOTIFICATION = 0xbc
+ *
+ * This is used by the device to notify us of the
+ * NoA schedule it determined so we can forward it
+ * to userspace for inclusion in probe responses.
+ *
+ * In beacons, the NoA schedule is simply appended
+ * to the frame we give the device.
+ */
+
+struct iwl_wipan_noa_descriptor {
+	u8 count;
+	__le32 duration;
+	__le32 interval;
+	__le32 starttime;
+} __packed;
+
+struct iwl_wipan_noa_attribute {
+	u8 id;
+	__le16 length;
+	u8 index;
+	u8 ct_window;
+	struct iwl_wipan_noa_descriptor descr0, descr1;
+	u8 reserved;
+} __packed;
+
+struct iwl_wipan_noa_notification {
+	u32 noa_active;
+	struct iwl_wipan_noa_attribute noa_attribute;
+} __packed;
+
+#endif				/* __iwl_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c
new file mode 100644
index 0000000..b0eff1c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c
@@ -0,0 +1,2432 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "iwl-debug.h"
+#include "iwl-io.h"
+#include "dev.h"
+#include "agn.h"
+
+/* create and remove of files */
+#define DEBUGFS_ADD_FILE(name, parent, mode) do {			\
+	if (!debugfs_create_file(#name, mode, parent, priv,		\
+				 &iwl_dbgfs_##name##_ops))		\
+		goto err;						\
+} while (0)
+
+#define DEBUGFS_ADD_BOOL(name, parent, ptr) do {			\
+	struct dentry *__tmp;						\
+	__tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR,		\
+				    parent, ptr);			\
+	if (IS_ERR(__tmp) || !__tmp)					\
+		goto err;						\
+} while (0)
+
+#define DEBUGFS_ADD_X32(name, parent, ptr) do {				\
+	struct dentry *__tmp;						\
+	__tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR,		\
+				   parent, ptr);			\
+	if (IS_ERR(__tmp) || !__tmp)					\
+		goto err;						\
+} while (0)
+
+#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do {			\
+	struct dentry *__tmp;						\
+	__tmp = debugfs_create_u32(#name, mode,				\
+				   parent, ptr);			\
+	if (IS_ERR(__tmp) || !__tmp)					\
+		goto err;						\
+} while (0)
+
+/* file operation */
+#define DEBUGFS_READ_FUNC(name)                                         \
+static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
+					char __user *user_buf,          \
+					size_t count, loff_t *ppos);
+
+#define DEBUGFS_WRITE_FUNC(name)                                        \
+static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
+					const char __user *user_buf,    \
+					size_t count, loff_t *ppos);
+
+
+#define DEBUGFS_READ_FILE_OPS(name)                                     \
+	DEBUGFS_READ_FUNC(name);                                        \
+static const struct file_operations iwl_dbgfs_##name##_ops = {          \
+	.read = iwl_dbgfs_##name##_read,                       		\
+	.open = simple_open,						\
+	.llseek = generic_file_llseek,					\
+};
+
+#define DEBUGFS_WRITE_FILE_OPS(name)                                    \
+	DEBUGFS_WRITE_FUNC(name);                                       \
+static const struct file_operations iwl_dbgfs_##name##_ops = {          \
+	.write = iwl_dbgfs_##name##_write,                              \
+	.open = simple_open,						\
+	.llseek = generic_file_llseek,					\
+};
+
+
+#define DEBUGFS_READ_WRITE_FILE_OPS(name)                               \
+	DEBUGFS_READ_FUNC(name);                                        \
+	DEBUGFS_WRITE_FUNC(name);                                       \
+static const struct file_operations iwl_dbgfs_##name##_ops = {          \
+	.write = iwl_dbgfs_##name##_write,                              \
+	.read = iwl_dbgfs_##name##_read,                                \
+	.open = simple_open,						\
+	.llseek = generic_file_llseek,					\
+};
+
+static ssize_t iwl_dbgfs_sram_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	u32 val = 0;
+	char *buf;
+	ssize_t ret;
+	int i = 0;
+	bool device_format = false;
+	int offset = 0;
+	int len = 0;
+	int pos = 0;
+	int sram;
+	struct iwl_priv *priv = file->private_data;
+	const struct fw_img *img;
+	size_t bufsz;
+
+	/* default is to dump the entire data segment */
+	if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
+		priv->dbgfs_sram_offset = 0x800000;
+		if (!priv->ucode_loaded)
+			return -EINVAL;
+		img = &priv->fw->img[priv->cur_ucode];
+		priv->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
+	}
+	len = priv->dbgfs_sram_len;
+
+	if (len == -4) {
+		device_format = true;
+		len = 4;
+	}
+
+	bufsz =  50 + len * 4;
+	buf = kmalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
+			 len);
+	pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
+			priv->dbgfs_sram_offset);
+
+	/* adjust sram address since reads are only on even u32 boundaries */
+	offset = priv->dbgfs_sram_offset & 0x3;
+	sram = priv->dbgfs_sram_offset & ~0x3;
+
+	/* read the first u32 from sram */
+	val = iwl_read_targ_mem(priv->trans, sram);
+
+	for (; len; len--) {
+		/* put the address at the start of every line */
+		if (i == 0)
+			pos += scnprintf(buf + pos, bufsz - pos,
+				"%08X: ", sram + offset);
+
+		if (device_format)
+			pos += scnprintf(buf + pos, bufsz - pos,
+				"%02x", (val >> (8 * (3 - offset))) & 0xff);
+		else
+			pos += scnprintf(buf + pos, bufsz - pos,
+				"%02x ", (val >> (8 * offset)) & 0xff);
+
+		/* if all bytes processed, read the next u32 from sram */
+		if (++offset == 4) {
+			sram += 4;
+			offset = 0;
+			val = iwl_read_targ_mem(priv->trans, sram);
+		}
+
+		/* put in extra spaces and split lines for human readability */
+		if (++i == 16) {
+			i = 0;
+			pos += scnprintf(buf + pos, bufsz - pos, "\n");
+		} else if (!(i & 7)) {
+			pos += scnprintf(buf + pos, bufsz - pos, "   ");
+		} else if (!(i & 3)) {
+			pos += scnprintf(buf + pos, bufsz - pos, " ");
+		}
+	}
+	if (i)
+		pos += scnprintf(buf + pos, bufsz - pos, "\n");
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_sram_write(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	char buf[64];
+	int buf_size;
+	u32 offset, len;
+
+	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, "%x,%x", &offset, &len) == 2) {
+		priv->dbgfs_sram_offset = offset;
+		priv->dbgfs_sram_len = len;
+	} else if (sscanf(buf, "%x", &offset) == 1) {
+		priv->dbgfs_sram_offset = offset;
+		priv->dbgfs_sram_len = -4;
+	} else {
+		priv->dbgfs_sram_offset = 0;
+		priv->dbgfs_sram_len = 0;
+	}
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file,
+					  char __user *user_buf,
+					  size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	const struct fw_img *img = &priv->fw->img[IWL_UCODE_WOWLAN];
+
+	if (!priv->wowlan_sram)
+		return -ENODATA;
+
+	return simple_read_from_buffer(user_buf, count, ppos,
+				       priv->wowlan_sram,
+				       img->sec[IWL_UCODE_SECTION_DATA].len);
+}
+static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	struct iwl_station_entry *station;
+	struct iwl_tid_data *tid_data;
+	char *buf;
+	int i, j, pos = 0;
+	ssize_t ret;
+	/* Add 30 for initial string */
+	const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
+
+	buf = kmalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
+			priv->num_stations);
+
+	for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+		station = &priv->stations[i];
+		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 seqno  next_rclmd "
+				"rate_n_flags state txq\n");
+
+		for (j = 0; j < IWL_MAX_TID_COUNT; j++) {
+			tid_data = &priv->tid_data[i][j];
+			pos += scnprintf(buf + pos, bufsz - pos,
+				"%d:  0x%.4x 0x%.4x     0x%.8x   "
+				"%d     %.2d",
+				j, tid_data->seq_number,
+				tid_data->next_reclaimed,
+				tid_data->agg.rate_n_flags,
+				tid_data->agg.state,
+				tid_data->agg.txq_id);
+
+			if (tid_data->agg.wait_for_ba)
+				pos += scnprintf(buf + pos, bufsz - pos,
+						 " - 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);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_nvm_read(struct file *file,
+				       char __user *user_buf,
+				       size_t count,
+				       loff_t *ppos)
+{
+	ssize_t ret;
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0, ofs = 0, buf_size = 0;
+	const u8 *ptr;
+	char *buf;
+	u16 eeprom_ver;
+	size_t eeprom_len = priv->eeprom_blob_size;
+	buf_size = 4 * eeprom_len + 256;
+
+	if (eeprom_len % 16)
+		return -ENODATA;
+
+	ptr = priv->eeprom_blob;
+	if (!ptr)
+		return -ENOMEM;
+
+	/* 4 characters for byte 0xYY */
+	buf = kzalloc(buf_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	eeprom_ver = priv->eeprom_data->eeprom_version;
+	pos += scnprintf(buf + pos, buf_size - pos,
+			 "NVM version: 0x%x\n", eeprom_ver);
+	for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
+		pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
+		hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
+				   buf_size - pos, 0);
+		pos += strlen(buf + pos);
+		if (buf_size - pos > 0)
+			buf[pos++] = '\n';
+	}
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	struct ieee80211_channel *channels = NULL;
+	const struct ieee80211_supported_band *supp_band = NULL;
+	int pos = 0, i, bufsz = PAGE_SIZE;
+	char *buf;
+	ssize_t ret;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
+	if (supp_band) {
+		channels = supp_band->channels;
+
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"Displaying %d channels in 2.4GHz band 802.11bg):\n",
+				supp_band->n_channels);
+
+		for (i = 0; i < supp_band->n_channels; i++)
+			pos += scnprintf(buf + pos, bufsz - pos,
+					"%d: %ddBm: BSS%s%s, %s.\n",
+					channels[i].hw_value,
+					channels[i].max_power,
+					channels[i].flags & IEEE80211_CHAN_RADAR ?
+					" (IEEE 802.11h required)" : "",
+					((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+					|| (channels[i].flags &
+					IEEE80211_CHAN_RADAR)) ? "" :
+					", IBSS",
+					channels[i].flags &
+					IEEE80211_CHAN_PASSIVE_SCAN ?
+					"passive only" : "active/passive");
+	}
+	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
+	if (supp_band) {
+		channels = supp_band->channels;
+
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"Displaying %d channels in 5.2GHz band (802.11a)\n",
+				supp_band->n_channels);
+
+		for (i = 0; i < supp_band->n_channels; i++)
+			pos += scnprintf(buf + pos, bufsz - pos,
+					"%d: %ddBm: BSS%s%s, %s.\n",
+					channels[i].hw_value,
+					channels[i].max_power,
+					channels[i].flags & IEEE80211_CHAN_RADAR ?
+					" (IEEE 802.11h required)" : "",
+					((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+					|| (channels[i].flags &
+					IEEE80211_CHAN_RADAR)) ? "" :
+					", IBSS",
+					channels[i].flags &
+					IEEE80211_CHAN_PASSIVE_SCAN ?
+					"passive only" : "active/passive");
+	}
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_status_read(struct file *file,
+						char __user *user_buf,
+						size_t count, loff_t *ppos) {
+
+	struct iwl_priv *priv = file->private_data;
+	char buf[512];
+	int pos = 0;
+	const size_t bufsz = sizeof(buf);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
+		test_bit(STATUS_RF_KILL_HW, &priv->status));
+	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
+		test_bit(STATUS_CT_KILL, &priv->status));
+	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
+		test_bit(STATUS_ALIVE, &priv->status));
+	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
+		test_bit(STATUS_READY, &priv->status));
+	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
+		test_bit(STATUS_EXIT_PENDING, &priv->status));
+	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
+		test_bit(STATUS_STATISTICS, &priv->status));
+	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
+		test_bit(STATUS_SCANNING, &priv->status));
+	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
+		test_bit(STATUS_SCAN_ABORTING, &priv->status));
+	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
+		test_bit(STATUS_SCAN_HW, &priv->status));
+	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
+		test_bit(STATUS_POWER_PMI, &priv->status));
+	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
+		test_bit(STATUS_FW_ERROR, &priv->status));
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_rx_handlers_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos) {
+
+	struct iwl_priv *priv = file->private_data;
+
+	int pos = 0;
+	int cnt = 0;
+	char *buf;
+	int bufsz = 24 * 64; /* 24 items * 64 char per item */
+	ssize_t ret;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (cnt = 0; cnt < REPLY_MAX; cnt++) {
+		if (priv->rx_handlers_stats[cnt] > 0)
+			pos += scnprintf(buf + pos, bufsz - pos,
+				"\tRx handler[%36s]:\t\t %u\n",
+				iwl_dvm_get_cmd_string(cnt),
+				priv->rx_handlers_stats[cnt]);
+	}
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_rx_handlers_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;
+	u32 reset_flag;
+
+	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, "%x", &reset_flag) != 1)
+		return -EFAULT;
+	if (reset_flag == 0)
+		memset(&priv->rx_handlers_stats[0], 0,
+			sizeof(priv->rx_handlers_stats));
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	struct iwl_rxon_context *ctx;
+	int pos = 0, i;
+	char buf[256 * NUM_IWL_RXON_CTX];
+	const size_t bufsz = sizeof(buf);
+
+	for_each_context(priv, ctx) {
+		pos += scnprintf(buf + pos, bufsz - pos, "context %d:\n",
+				 ctx->ctxid);
+		for (i = 0; i < AC_NUM; i++) {
+			pos += scnprintf(buf + pos, bufsz - pos,
+				"\tcw_min\tcw_max\taifsn\ttxop\n");
+			pos += scnprintf(buf + pos, bufsz - pos,
+				"AC[%d]\t%u\t%u\t%u\t%u\n", i,
+				ctx->qos_data.def_qos_parm.ac[i].cw_min,
+				ctx->qos_data.def_qos_parm.ac[i].cw_max,
+				ctx->qos_data.def_qos_parm.ac[i].aifsn,
+				ctx->qos_data.def_qos_parm.ac[i].edca_txop);
+		}
+		pos += scnprintf(buf + pos, bufsz - pos, "\n");
+	}
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
+				char __user *user_buf,
+				size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+	struct iwl_tt_restriction *restriction;
+	char buf[100];
+	int pos = 0;
+	const size_t bufsz = sizeof(buf);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"Thermal Throttling Mode: %s\n",
+			tt->advanced_tt ? "Advance" : "Legacy");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"Thermal Throttling State: %d\n",
+			tt->state);
+	if (tt->advanced_tt) {
+		restriction = tt->restriction + tt->state;
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"Tx mode: %d\n",
+				restriction->tx_stream);
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"Rx mode: %d\n",
+				restriction->rx_stream);
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"HT mode: %d\n",
+				restriction->is_ht);
+	}
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_disable_ht40_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 ht40;
+
+	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", &ht40) != 1)
+		return -EFAULT;
+	if (!iwl_is_any_associated(priv))
+		priv->disable_ht40 = ht40 ? true : false;
+	else
+		return -EINVAL;
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	char buf[100];
+	int pos = 0;
+	const size_t bufsz = sizeof(buf);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"11n 40MHz Mode: %s\n",
+			priv->disable_ht40 ? "Disabled" : "Enabled");
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_temperature_read(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	char buf[8];
+	int pos = 0;
+	const size_t bufsz = sizeof(buf);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "%d\n", priv->temperature);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+
+static ssize_t iwl_dbgfs_sleep_level_override_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 value;
+
+	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", &value) != 1)
+		return -EINVAL;
+
+	/*
+	 * Our users expect 0 to be "CAM", but 0 isn't actually
+	 * valid here. However, let's not confuse them and present
+	 * IWL_POWER_INDEX_1 as "1", not "0".
+	 */
+	if (value == 0)
+		return -EINVAL;
+	else if (value > 0)
+		value -= 1;
+
+	if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
+		return -EINVAL;
+
+	if (!iwl_is_ready_rf(priv))
+		return -EAGAIN;
+
+	priv->power_data.debug_sleep_level_override = value;
+
+	mutex_lock(&priv->mutex);
+	iwl_power_update_mode(priv, true);
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file,
+						   char __user *user_buf,
+						   size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	char buf[10];
+	int pos, value;
+	const size_t bufsz = sizeof(buf);
+
+	/* see the write function */
+	value = priv->power_data.debug_sleep_level_override;
+	if (value >= 0)
+		value += 1;
+
+	pos = scnprintf(buf, bufsz, "%d\n", value);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
+						    char __user *user_buf,
+						    size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	char buf[200];
+	int pos = 0, i;
+	const size_t bufsz = sizeof(buf);
+	struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd;
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "flags: %#.2x\n", le16_to_cpu(cmd->flags));
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "RX/TX timeout: %d/%d usec\n",
+			 le32_to_cpu(cmd->rx_data_timeout),
+			 le32_to_cpu(cmd->tx_data_timeout));
+	for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
+		pos += scnprintf(buf + pos, bufsz - pos,
+				 "sleep_interval[%d]: %d\n", i,
+				 le32_to_cpu(cmd->sleep_interval[i]));
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+DEBUGFS_READ_WRITE_FILE_OPS(sram);
+DEBUGFS_READ_FILE_OPS(wowlan_sram);
+DEBUGFS_READ_FILE_OPS(nvm);
+DEBUGFS_READ_FILE_OPS(stations);
+DEBUGFS_READ_FILE_OPS(channels);
+DEBUGFS_READ_FILE_OPS(status);
+DEBUGFS_READ_WRITE_FILE_OPS(rx_handlers);
+DEBUGFS_READ_FILE_OPS(qos);
+DEBUGFS_READ_FILE_OPS(thermal_throttling);
+DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
+DEBUGFS_READ_FILE_OPS(temperature);
+DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
+DEBUGFS_READ_FILE_OPS(current_sleep_command);
+
+static const char *fmt_value = "  %-30s %10u\n";
+static const char *fmt_hex   = "  %-30s       0x%02X\n";
+static const char *fmt_table = "  %-30s %10u  %10u  %10u  %10u\n";
+static const char *fmt_header =
+	"%-32s    current  cumulative       delta         max\n";
+
+static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
+{
+	int p = 0;
+	u32 flag;
+
+	lockdep_assert_held(&priv->statistics.lock);
+
+	flag = le32_to_cpu(priv->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;
+}
+
+static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	char *buf;
+	int bufsz = sizeof(struct statistics_rx_phy) * 40 +
+		    sizeof(struct statistics_rx_non_phy) * 40 +
+		    sizeof(struct statistics_rx_ht_phy) * 40 + 400;
+	ssize_t ret;
+	struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
+	struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
+	struct statistics_rx_non_phy *general, *accum_general;
+	struct statistics_rx_non_phy *delta_general, *max_general;
+	struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/*
+	 * the statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	spin_lock_bh(&priv->statistics.lock);
+	ofdm = &priv->statistics.rx_ofdm;
+	cck = &priv->statistics.rx_cck;
+	general = &priv->statistics.rx_non_phy;
+	ht = &priv->statistics.rx_ofdm_ht;
+	accum_ofdm = &priv->accum_stats.rx_ofdm;
+	accum_cck = &priv->accum_stats.rx_cck;
+	accum_general = &priv->accum_stats.rx_non_phy;
+	accum_ht = &priv->accum_stats.rx_ofdm_ht;
+	delta_ofdm = &priv->delta_stats.rx_ofdm;
+	delta_cck = &priv->delta_stats.rx_cck;
+	delta_general = &priv->delta_stats.rx_non_phy;
+	delta_ht = &priv->delta_stats.rx_ofdm_ht;
+	max_ofdm = &priv->max_delta_stats.rx_ofdm;
+	max_cck = &priv->max_delta_stats.rx_cck;
+	max_general = &priv->max_delta_stats.rx_non_phy;
+	max_ht = &priv->max_delta_stats.rx_ofdm_ht;
+
+	pos += iwl_statistics_flag(priv, buf, bufsz);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_Rx - OFDM:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "ina_cnt:",
+			 le32_to_cpu(ofdm->ina_cnt),
+			 accum_ofdm->ina_cnt,
+			 delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_cnt:",
+			 le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
+			 delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "plcp_err:",
+			 le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
+			 delta_ofdm->plcp_err, max_ofdm->plcp_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_err:",
+			 le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
+			 delta_ofdm->crc32_err, max_ofdm->crc32_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "overrun_err:",
+			 le32_to_cpu(ofdm->overrun_err),
+			 accum_ofdm->overrun_err, delta_ofdm->overrun_err,
+			 max_ofdm->overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "early_overrun_err:",
+			 le32_to_cpu(ofdm->early_overrun_err),
+			 accum_ofdm->early_overrun_err,
+			 delta_ofdm->early_overrun_err,
+			 max_ofdm->early_overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_good:",
+			 le32_to_cpu(ofdm->crc32_good),
+			 accum_ofdm->crc32_good, delta_ofdm->crc32_good,
+			 max_ofdm->crc32_good);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "false_alarm_cnt:",
+			 le32_to_cpu(ofdm->false_alarm_cnt),
+			 accum_ofdm->false_alarm_cnt,
+			 delta_ofdm->false_alarm_cnt,
+			 max_ofdm->false_alarm_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_sync_err_cnt:",
+			 le32_to_cpu(ofdm->fina_sync_err_cnt),
+			 accum_ofdm->fina_sync_err_cnt,
+			 delta_ofdm->fina_sync_err_cnt,
+			 max_ofdm->fina_sync_err_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sfd_timeout:",
+			 le32_to_cpu(ofdm->sfd_timeout),
+			 accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
+			 max_ofdm->sfd_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_timeout:",
+			 le32_to_cpu(ofdm->fina_timeout),
+			 accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
+			 max_ofdm->fina_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "unresponded_rts:",
+			 le32_to_cpu(ofdm->unresponded_rts),
+			 accum_ofdm->unresponded_rts,
+			 delta_ofdm->unresponded_rts,
+			 max_ofdm->unresponded_rts);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "rxe_frame_lmt_ovrun:",
+			 le32_to_cpu(ofdm->rxe_frame_limit_overrun),
+			 accum_ofdm->rxe_frame_limit_overrun,
+			 delta_ofdm->rxe_frame_limit_overrun,
+			 max_ofdm->rxe_frame_limit_overrun);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_ack_cnt:",
+			 le32_to_cpu(ofdm->sent_ack_cnt),
+			 accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
+			 max_ofdm->sent_ack_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_cts_cnt:",
+			 le32_to_cpu(ofdm->sent_cts_cnt),
+			 accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
+			 max_ofdm->sent_cts_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_ba_rsp_cnt:",
+			 le32_to_cpu(ofdm->sent_ba_rsp_cnt),
+			 accum_ofdm->sent_ba_rsp_cnt,
+			 delta_ofdm->sent_ba_rsp_cnt,
+			 max_ofdm->sent_ba_rsp_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "dsp_self_kill:",
+			 le32_to_cpu(ofdm->dsp_self_kill),
+			 accum_ofdm->dsp_self_kill,
+			 delta_ofdm->dsp_self_kill,
+			 max_ofdm->dsp_self_kill);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "mh_format_err:",
+			 le32_to_cpu(ofdm->mh_format_err),
+			 accum_ofdm->mh_format_err,
+			 delta_ofdm->mh_format_err,
+			 max_ofdm->mh_format_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "re_acq_main_rssi_sum:",
+			 le32_to_cpu(ofdm->re_acq_main_rssi_sum),
+			 accum_ofdm->re_acq_main_rssi_sum,
+			 delta_ofdm->re_acq_main_rssi_sum,
+			 max_ofdm->re_acq_main_rssi_sum);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_Rx - CCK:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "ina_cnt:",
+			 le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
+			 delta_cck->ina_cnt, max_cck->ina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_cnt:",
+			 le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
+			 delta_cck->fina_cnt, max_cck->fina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "plcp_err:",
+			 le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
+			 delta_cck->plcp_err, max_cck->plcp_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_err:",
+			 le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
+			 delta_cck->crc32_err, max_cck->crc32_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "overrun_err:",
+			 le32_to_cpu(cck->overrun_err),
+			 accum_cck->overrun_err, delta_cck->overrun_err,
+			 max_cck->overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "early_overrun_err:",
+			 le32_to_cpu(cck->early_overrun_err),
+			 accum_cck->early_overrun_err,
+			 delta_cck->early_overrun_err,
+			 max_cck->early_overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_good:",
+			 le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
+			 delta_cck->crc32_good, max_cck->crc32_good);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "false_alarm_cnt:",
+			 le32_to_cpu(cck->false_alarm_cnt),
+			 accum_cck->false_alarm_cnt,
+			 delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_sync_err_cnt:",
+			 le32_to_cpu(cck->fina_sync_err_cnt),
+			 accum_cck->fina_sync_err_cnt,
+			 delta_cck->fina_sync_err_cnt,
+			 max_cck->fina_sync_err_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sfd_timeout:",
+			 le32_to_cpu(cck->sfd_timeout),
+			 accum_cck->sfd_timeout, delta_cck->sfd_timeout,
+			 max_cck->sfd_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_timeout:",
+			 le32_to_cpu(cck->fina_timeout),
+			 accum_cck->fina_timeout, delta_cck->fina_timeout,
+			 max_cck->fina_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "unresponded_rts:",
+			 le32_to_cpu(cck->unresponded_rts),
+			 accum_cck->unresponded_rts, delta_cck->unresponded_rts,
+			 max_cck->unresponded_rts);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "rxe_frame_lmt_ovrun:",
+			 le32_to_cpu(cck->rxe_frame_limit_overrun),
+			 accum_cck->rxe_frame_limit_overrun,
+			 delta_cck->rxe_frame_limit_overrun,
+			 max_cck->rxe_frame_limit_overrun);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_ack_cnt:",
+			 le32_to_cpu(cck->sent_ack_cnt),
+			 accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
+			 max_cck->sent_ack_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_cts_cnt:",
+			 le32_to_cpu(cck->sent_cts_cnt),
+			 accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
+			 max_cck->sent_cts_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_ba_rsp_cnt:",
+			 le32_to_cpu(cck->sent_ba_rsp_cnt),
+			 accum_cck->sent_ba_rsp_cnt,
+			 delta_cck->sent_ba_rsp_cnt,
+			 max_cck->sent_ba_rsp_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "dsp_self_kill:",
+			 le32_to_cpu(cck->dsp_self_kill),
+			 accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
+			 max_cck->dsp_self_kill);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "mh_format_err:",
+			 le32_to_cpu(cck->mh_format_err),
+			 accum_cck->mh_format_err, delta_cck->mh_format_err,
+			 max_cck->mh_format_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "re_acq_main_rssi_sum:",
+			 le32_to_cpu(cck->re_acq_main_rssi_sum),
+			 accum_cck->re_acq_main_rssi_sum,
+			 delta_cck->re_acq_main_rssi_sum,
+			 max_cck->re_acq_main_rssi_sum);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_Rx - GENERAL:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "bogus_cts:",
+			 le32_to_cpu(general->bogus_cts),
+			 accum_general->bogus_cts, delta_general->bogus_cts,
+			 max_general->bogus_cts);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "bogus_ack:",
+			 le32_to_cpu(general->bogus_ack),
+			 accum_general->bogus_ack, delta_general->bogus_ack,
+			 max_general->bogus_ack);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "non_bssid_frames:",
+			 le32_to_cpu(general->non_bssid_frames),
+			 accum_general->non_bssid_frames,
+			 delta_general->non_bssid_frames,
+			 max_general->non_bssid_frames);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "filtered_frames:",
+			 le32_to_cpu(general->filtered_frames),
+			 accum_general->filtered_frames,
+			 delta_general->filtered_frames,
+			 max_general->filtered_frames);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "non_channel_beacons:",
+			 le32_to_cpu(general->non_channel_beacons),
+			 accum_general->non_channel_beacons,
+			 delta_general->non_channel_beacons,
+			 max_general->non_channel_beacons);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "channel_beacons:",
+			 le32_to_cpu(general->channel_beacons),
+			 accum_general->channel_beacons,
+			 delta_general->channel_beacons,
+			 max_general->channel_beacons);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "num_missed_bcon:",
+			 le32_to_cpu(general->num_missed_bcon),
+			 accum_general->num_missed_bcon,
+			 delta_general->num_missed_bcon,
+			 max_general->num_missed_bcon);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "adc_rx_saturation_time:",
+			 le32_to_cpu(general->adc_rx_saturation_time),
+			 accum_general->adc_rx_saturation_time,
+			 delta_general->adc_rx_saturation_time,
+			 max_general->adc_rx_saturation_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "ina_detect_search_tm:",
+			 le32_to_cpu(general->ina_detection_search_time),
+			 accum_general->ina_detection_search_time,
+			 delta_general->ina_detection_search_time,
+			 max_general->ina_detection_search_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_silence_rssi_a:",
+			 le32_to_cpu(general->beacon_silence_rssi_a),
+			 accum_general->beacon_silence_rssi_a,
+			 delta_general->beacon_silence_rssi_a,
+			 max_general->beacon_silence_rssi_a);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_silence_rssi_b:",
+			 le32_to_cpu(general->beacon_silence_rssi_b),
+			 accum_general->beacon_silence_rssi_b,
+			 delta_general->beacon_silence_rssi_b,
+			 max_general->beacon_silence_rssi_b);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_silence_rssi_c:",
+			 le32_to_cpu(general->beacon_silence_rssi_c),
+			 accum_general->beacon_silence_rssi_c,
+			 delta_general->beacon_silence_rssi_c,
+			 max_general->beacon_silence_rssi_c);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "interference_data_flag:",
+			 le32_to_cpu(general->interference_data_flag),
+			 accum_general->interference_data_flag,
+			 delta_general->interference_data_flag,
+			 max_general->interference_data_flag);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "channel_load:",
+			 le32_to_cpu(general->channel_load),
+			 accum_general->channel_load,
+			 delta_general->channel_load,
+			 max_general->channel_load);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "dsp_false_alarms:",
+			 le32_to_cpu(general->dsp_false_alarms),
+			 accum_general->dsp_false_alarms,
+			 delta_general->dsp_false_alarms,
+			 max_general->dsp_false_alarms);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_rssi_a:",
+			 le32_to_cpu(general->beacon_rssi_a),
+			 accum_general->beacon_rssi_a,
+			 delta_general->beacon_rssi_a,
+			 max_general->beacon_rssi_a);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_rssi_b:",
+			 le32_to_cpu(general->beacon_rssi_b),
+			 accum_general->beacon_rssi_b,
+			 delta_general->beacon_rssi_b,
+			 max_general->beacon_rssi_b);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_rssi_c:",
+			 le32_to_cpu(general->beacon_rssi_c),
+			 accum_general->beacon_rssi_c,
+			 delta_general->beacon_rssi_c,
+			 max_general->beacon_rssi_c);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_energy_a:",
+			 le32_to_cpu(general->beacon_energy_a),
+			 accum_general->beacon_energy_a,
+			 delta_general->beacon_energy_a,
+			 max_general->beacon_energy_a);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_energy_b:",
+			 le32_to_cpu(general->beacon_energy_b),
+			 accum_general->beacon_energy_b,
+			 delta_general->beacon_energy_b,
+			 max_general->beacon_energy_b);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_energy_c:",
+			 le32_to_cpu(general->beacon_energy_c),
+			 accum_general->beacon_energy_c,
+			 delta_general->beacon_energy_c,
+			 max_general->beacon_energy_c);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_Rx - OFDM_HT:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "plcp_err:",
+			 le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
+			 delta_ht->plcp_err, max_ht->plcp_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "overrun_err:",
+			 le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
+			 delta_ht->overrun_err, max_ht->overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "early_overrun_err:",
+			 le32_to_cpu(ht->early_overrun_err),
+			 accum_ht->early_overrun_err,
+			 delta_ht->early_overrun_err,
+			 max_ht->early_overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_good:",
+			 le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
+			 delta_ht->crc32_good, max_ht->crc32_good);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_err:",
+			 le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
+			 delta_ht->crc32_err, max_ht->crc32_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "mh_format_err:",
+			 le32_to_cpu(ht->mh_format_err),
+			 accum_ht->mh_format_err,
+			 delta_ht->mh_format_err, max_ht->mh_format_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg_crc32_good:",
+			 le32_to_cpu(ht->agg_crc32_good),
+			 accum_ht->agg_crc32_good,
+			 delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg_mpdu_cnt:",
+			 le32_to_cpu(ht->agg_mpdu_cnt),
+			 accum_ht->agg_mpdu_cnt,
+			 delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg_cnt:",
+			 le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
+			 delta_ht->agg_cnt, max_ht->agg_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "unsupport_mcs:",
+			 le32_to_cpu(ht->unsupport_mcs),
+			 accum_ht->unsupport_mcs,
+			 delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
+
+	spin_unlock_bh(&priv->statistics.lock);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	char *buf;
+	int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
+	ssize_t ret;
+	struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/* the statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	spin_lock_bh(&priv->statistics.lock);
+
+	tx = &priv->statistics.tx;
+	accum_tx = &priv->accum_stats.tx;
+	delta_tx = &priv->delta_stats.tx;
+	max_tx = &priv->max_delta_stats.tx;
+
+	pos += iwl_statistics_flag(priv, buf, bufsz);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_Tx:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "preamble:",
+			 le32_to_cpu(tx->preamble_cnt),
+			 accum_tx->preamble_cnt,
+			 delta_tx->preamble_cnt, max_tx->preamble_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "rx_detected_cnt:",
+			 le32_to_cpu(tx->rx_detected_cnt),
+			 accum_tx->rx_detected_cnt,
+			 delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "bt_prio_defer_cnt:",
+			 le32_to_cpu(tx->bt_prio_defer_cnt),
+			 accum_tx->bt_prio_defer_cnt,
+			 delta_tx->bt_prio_defer_cnt,
+			 max_tx->bt_prio_defer_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "bt_prio_kill_cnt:",
+			 le32_to_cpu(tx->bt_prio_kill_cnt),
+			 accum_tx->bt_prio_kill_cnt,
+			 delta_tx->bt_prio_kill_cnt,
+			 max_tx->bt_prio_kill_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "few_bytes_cnt:",
+			 le32_to_cpu(tx->few_bytes_cnt),
+			 accum_tx->few_bytes_cnt,
+			 delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "cts_timeout:",
+			 le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
+			 delta_tx->cts_timeout, max_tx->cts_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "ack_timeout:",
+			 le32_to_cpu(tx->ack_timeout),
+			 accum_tx->ack_timeout,
+			 delta_tx->ack_timeout, max_tx->ack_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "expected_ack_cnt:",
+			 le32_to_cpu(tx->expected_ack_cnt),
+			 accum_tx->expected_ack_cnt,
+			 delta_tx->expected_ack_cnt,
+			 max_tx->expected_ack_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "actual_ack_cnt:",
+			 le32_to_cpu(tx->actual_ack_cnt),
+			 accum_tx->actual_ack_cnt,
+			 delta_tx->actual_ack_cnt,
+			 max_tx->actual_ack_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "dump_msdu_cnt:",
+			 le32_to_cpu(tx->dump_msdu_cnt),
+			 accum_tx->dump_msdu_cnt,
+			 delta_tx->dump_msdu_cnt,
+			 max_tx->dump_msdu_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "abort_nxt_frame_mismatch:",
+			 le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
+			 accum_tx->burst_abort_next_frame_mismatch_cnt,
+			 delta_tx->burst_abort_next_frame_mismatch_cnt,
+			 max_tx->burst_abort_next_frame_mismatch_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "abort_missing_nxt_frame:",
+			 le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
+			 accum_tx->burst_abort_missing_next_frame_cnt,
+			 delta_tx->burst_abort_missing_next_frame_cnt,
+			 max_tx->burst_abort_missing_next_frame_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "cts_timeout_collision:",
+			 le32_to_cpu(tx->cts_timeout_collision),
+			 accum_tx->cts_timeout_collision,
+			 delta_tx->cts_timeout_collision,
+			 max_tx->cts_timeout_collision);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "ack_ba_timeout_collision:",
+			 le32_to_cpu(tx->ack_or_ba_timeout_collision),
+			 accum_tx->ack_or_ba_timeout_collision,
+			 delta_tx->ack_or_ba_timeout_collision,
+			 max_tx->ack_or_ba_timeout_collision);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg ba_timeout:",
+			 le32_to_cpu(tx->agg.ba_timeout),
+			 accum_tx->agg.ba_timeout,
+			 delta_tx->agg.ba_timeout,
+			 max_tx->agg.ba_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg ba_resched_frames:",
+			 le32_to_cpu(tx->agg.ba_reschedule_frames),
+			 accum_tx->agg.ba_reschedule_frames,
+			 delta_tx->agg.ba_reschedule_frames,
+			 max_tx->agg.ba_reschedule_frames);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg scd_query_agg_frame:",
+			 le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
+			 accum_tx->agg.scd_query_agg_frame_cnt,
+			 delta_tx->agg.scd_query_agg_frame_cnt,
+			 max_tx->agg.scd_query_agg_frame_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg scd_query_no_agg:",
+			 le32_to_cpu(tx->agg.scd_query_no_agg),
+			 accum_tx->agg.scd_query_no_agg,
+			 delta_tx->agg.scd_query_no_agg,
+			 max_tx->agg.scd_query_no_agg);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg scd_query_agg:",
+			 le32_to_cpu(tx->agg.scd_query_agg),
+			 accum_tx->agg.scd_query_agg,
+			 delta_tx->agg.scd_query_agg,
+			 max_tx->agg.scd_query_agg);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg scd_query_mismatch:",
+			 le32_to_cpu(tx->agg.scd_query_mismatch),
+			 accum_tx->agg.scd_query_mismatch,
+			 delta_tx->agg.scd_query_mismatch,
+			 max_tx->agg.scd_query_mismatch);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg frame_not_ready:",
+			 le32_to_cpu(tx->agg.frame_not_ready),
+			 accum_tx->agg.frame_not_ready,
+			 delta_tx->agg.frame_not_ready,
+			 max_tx->agg.frame_not_ready);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg underrun:",
+			 le32_to_cpu(tx->agg.underrun),
+			 accum_tx->agg.underrun,
+			 delta_tx->agg.underrun, max_tx->agg.underrun);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg bt_prio_kill:",
+			 le32_to_cpu(tx->agg.bt_prio_kill),
+			 accum_tx->agg.bt_prio_kill,
+			 delta_tx->agg.bt_prio_kill,
+			 max_tx->agg.bt_prio_kill);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg rx_ba_rsp_cnt:",
+			 le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
+			 accum_tx->agg.rx_ba_rsp_cnt,
+			 delta_tx->agg.rx_ba_rsp_cnt,
+			 max_tx->agg.rx_ba_rsp_cnt);
+
+	if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
+		pos += scnprintf(buf + pos, bufsz - pos,
+			"tx power: (1/2 dB step)\n");
+		if ((priv->eeprom_data->valid_tx_ant & ANT_A) &&
+		    tx->tx_power.ant_a)
+			pos += scnprintf(buf + pos, bufsz - pos,
+					fmt_hex, "antenna A:",
+					tx->tx_power.ant_a);
+		if ((priv->eeprom_data->valid_tx_ant & ANT_B) &&
+		    tx->tx_power.ant_b)
+			pos += scnprintf(buf + pos, bufsz - pos,
+					fmt_hex, "antenna B:",
+					tx->tx_power.ant_b);
+		if ((priv->eeprom_data->valid_tx_ant & ANT_C) &&
+		    tx->tx_power.ant_c)
+			pos += scnprintf(buf + pos, bufsz - pos,
+					fmt_hex, "antenna C:",
+					tx->tx_power.ant_c);
+	}
+
+	spin_unlock_bh(&priv->statistics.lock);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	char *buf;
+	int bufsz = sizeof(struct statistics_general) * 10 + 300;
+	ssize_t ret;
+	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;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/* the statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+
+	spin_lock_bh(&priv->statistics.lock);
+
+	general = &priv->statistics.common;
+	dbg = &priv->statistics.common.dbg;
+	div = &priv->statistics.common.div;
+	accum_general = &priv->accum_stats.common;
+	accum_dbg = &priv->accum_stats.common.dbg;
+	accum_div = &priv->accum_stats.common.div;
+	delta_general = &priv->delta_stats.common;
+	max_general = &priv->max_delta_stats.common;
+	delta_dbg = &priv->delta_stats.common.dbg;
+	max_dbg = &priv->max_delta_stats.common.dbg;
+	delta_div = &priv->delta_stats.common.div;
+	max_div = &priv->max_delta_stats.common.div;
+
+	pos += iwl_statistics_flag(priv, buf, bufsz);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_General:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_value, "temperature:",
+			 le32_to_cpu(general->temperature));
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_value, "temperature_m:",
+			 le32_to_cpu(general->temperature_m));
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_value, "ttl_timestamp:",
+			 le32_to_cpu(general->ttl_timestamp));
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "burst_check:",
+			 le32_to_cpu(dbg->burst_check),
+			 accum_dbg->burst_check,
+			 delta_dbg->burst_check, max_dbg->burst_check);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "burst_count:",
+			 le32_to_cpu(dbg->burst_count),
+			 accum_dbg->burst_count,
+			 delta_dbg->burst_count, max_dbg->burst_count);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "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,
+			 fmt_table, "sleep_time:",
+			 le32_to_cpu(general->sleep_time),
+			 accum_general->sleep_time,
+			 delta_general->sleep_time, max_general->sleep_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "slots_out:",
+			 le32_to_cpu(general->slots_out),
+			 accum_general->slots_out,
+			 delta_general->slots_out, max_general->slots_out);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "slots_idle:",
+			 le32_to_cpu(general->slots_idle),
+			 accum_general->slots_idle,
+			 delta_general->slots_idle, max_general->slots_idle);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "tx_on_a:",
+			 le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
+			 delta_div->tx_on_a, max_div->tx_on_a);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "tx_on_b:",
+			 le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
+			 delta_div->tx_on_b, max_div->tx_on_b);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "exec_time:",
+			 le32_to_cpu(div->exec_time), accum_div->exec_time,
+			 delta_div->exec_time, max_div->exec_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "probe_time:",
+			 le32_to_cpu(div->probe_time), accum_div->probe_time,
+			 delta_div->probe_time, max_div->probe_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "rx_enable_counter:",
+			 le32_to_cpu(general->rx_enable_counter),
+			 accum_general->rx_enable_counter,
+			 delta_general->rx_enable_counter,
+			 max_general->rx_enable_counter);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "num_of_sos_states:",
+			 le32_to_cpu(general->num_of_sos_states),
+			 accum_general->num_of_sos_states,
+			 delta_general->num_of_sos_states,
+			 max_general->num_of_sos_states);
+
+	spin_unlock_bh(&priv->statistics.lock);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+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;
+	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;
+
+	if (!priv->bt_enable_flag)
+		return -EINVAL;
+
+	/* 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)
+		return -EAGAIN;
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/*
+	 * the statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+
+	spin_lock_bh(&priv->statistics.lock);
+
+	bt = &priv->statistics.bt_activity;
+	accum_bt = &priv->accum_stats.bt_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_tx_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->statistics.num_bt_kills),
+			 priv->statistics.accum_num_bt_kills);
+
+	spin_unlock_bh(&priv->statistics.lock);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_reply_tx_error_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 reply_tx_error_statistics) * 24) +
+		(sizeof(struct reply_agg_tx_error_statistics) * 24) + 200;
+	ssize_t ret;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n");
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY),
+			 priv->reply_tx_stats.pp_delay);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES),
+			 priv->reply_tx_stats.pp_few_bytes);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO),
+			 priv->reply_tx_stats.pp_bt_prio);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD),
+			 priv->reply_tx_stats.pp_quiet_period);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK),
+			 priv->reply_tx_stats.pp_calc_ttak);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_tx_fail_reason(
+				TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY),
+			 priv->reply_tx_stats.int_crossed_retry);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT),
+			 priv->reply_tx_stats.short_limit);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT),
+			 priv->reply_tx_stats.long_limit);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN),
+			 priv->reply_tx_stats.fifo_underrun);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW),
+			 priv->reply_tx_stats.drain_flow);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH),
+			 priv->reply_tx_stats.rfkill_flush);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE),
+			 priv->reply_tx_stats.life_expire);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS),
+			 priv->reply_tx_stats.dest_ps);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED),
+			 priv->reply_tx_stats.host_abort);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY),
+			 priv->reply_tx_stats.pp_delay);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID),
+			 priv->reply_tx_stats.sta_invalid);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED),
+			 priv->reply_tx_stats.frag_drop);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE),
+			 priv->reply_tx_stats.tid_disable);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED),
+			 priv->reply_tx_stats.fifo_flush);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_tx_fail_reason(
+				TX_STATUS_FAIL_INSUFFICIENT_CF_POLL),
+			 priv->reply_tx_stats.insuff_cf_poll);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX),
+			 priv->reply_tx_stats.fail_hw_drop);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_tx_fail_reason(
+				TX_STATUS_FAIL_NO_BEACON_ON_RADAR),
+			 priv->reply_tx_stats.sta_color_mismatch);
+	pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
+			 priv->reply_tx_stats.unknown);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "\nStatistics_Agg_TX_Error:\n");
+
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK),
+			 priv->reply_agg_tx_stats.underrun);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK),
+			 priv->reply_agg_tx_stats.bt_prio);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK),
+			 priv->reply_agg_tx_stats.few_bytes);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK),
+			 priv->reply_agg_tx_stats.abort);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(
+				AGG_TX_STATE_LAST_SENT_TTL_MSK),
+			 priv->reply_agg_tx_stats.last_sent_ttl);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(
+				AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK),
+			 priv->reply_agg_tx_stats.last_sent_try);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(
+				AGG_TX_STATE_LAST_SENT_BT_KILL_MSK),
+			 priv->reply_agg_tx_stats.last_sent_bt_kill);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK),
+			 priv->reply_agg_tx_stats.scd_query);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(
+				AGG_TX_STATE_TEST_BAD_CRC32_MSK),
+			 priv->reply_agg_tx_stats.bad_crc32);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK),
+			 priv->reply_agg_tx_stats.response);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK),
+			 priv->reply_agg_tx_stats.dump_tx);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK),
+			 priv->reply_agg_tx_stats.delay_tx);
+	pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
+			 priv->reply_agg_tx_stats.unknown);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos) {
+
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	int cnt = 0;
+	char *buf;
+	int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100;
+	ssize_t ret;
+	struct iwl_sensitivity_data *data;
+
+	data = &priv->sensitivity_data;
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
+			data->auto_corr_ofdm);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"auto_corr_ofdm_mrc:\t\t %u\n",
+			data->auto_corr_ofdm_mrc);
+	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
+			data->auto_corr_ofdm_x1);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"auto_corr_ofdm_mrc_x1:\t\t %u\n",
+			data->auto_corr_ofdm_mrc_x1);
+	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
+			data->auto_corr_cck);
+	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
+			data->auto_corr_cck_mrc);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"last_bad_plcp_cnt_ofdm:\t\t %u\n",
+			data->last_bad_plcp_cnt_ofdm);
+	pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
+			data->last_fa_cnt_ofdm);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"last_bad_plcp_cnt_cck:\t\t %u\n",
+			data->last_bad_plcp_cnt_cck);
+	pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
+			data->last_fa_cnt_cck);
+	pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
+			data->nrg_curr_state);
+	pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
+			data->nrg_prev_state);
+	pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
+	for (cnt = 0; cnt < 10; cnt++) {
+		pos += scnprintf(buf + pos, bufsz - pos, " %u",
+				data->nrg_value[cnt]);
+	}
+	pos += scnprintf(buf + pos, bufsz - pos, "\n");
+	pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
+	for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
+		pos += scnprintf(buf + pos, bufsz - pos, " %u",
+				data->nrg_silence_rssi[cnt]);
+	}
+	pos += scnprintf(buf + pos, bufsz - pos, "\n");
+	pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
+			data->nrg_silence_ref);
+	pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
+			data->nrg_energy_idx);
+	pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
+			data->nrg_silence_idx);
+	pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
+			data->nrg_th_cck);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"nrg_auto_corr_silence_diff:\t %u\n",
+			data->nrg_auto_corr_silence_diff);
+	pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
+			data->num_in_cck_no_fa);
+	pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
+			data->nrg_th_ofdm);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+
+static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos) {
+
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	int cnt = 0;
+	char *buf;
+	int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100;
+	ssize_t ret;
+	struct iwl_chain_noise_data *data;
+
+	data = &priv->chain_noise_data;
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
+			data->active_chains);
+	pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
+			data->chain_noise_a);
+	pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
+			data->chain_noise_b);
+	pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
+			data->chain_noise_c);
+	pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
+			data->chain_signal_a);
+	pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
+			data->chain_signal_b);
+	pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
+			data->chain_signal_c);
+	pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
+			data->beacon_count);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
+	for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
+		pos += scnprintf(buf + pos, bufsz - pos, " %u",
+				data->disconn_array[cnt]);
+	}
+	pos += scnprintf(buf + pos, bufsz - pos, "\n");
+	pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
+	for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
+		pos += scnprintf(buf + pos, bufsz - pos, " %u",
+				data->delta_gain_code[cnt]);
+	}
+	pos += scnprintf(buf + pos, bufsz - pos, "\n");
+	pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
+			data->radio_write);
+	pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
+			data->state);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
+						    char __user *user_buf,
+						    size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	char buf[60];
+	int pos = 0;
+	const size_t bufsz = sizeof(buf);
+	u32 pwrsave_status;
+
+	pwrsave_status = iwl_read32(priv->trans, CSR_GP_CNTRL) &
+			CSR_GP_REG_POWER_SAVE_STATUS_MSK;
+
+	pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
+	pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
+		(pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
+		(pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
+		(pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
+		"error");
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_clear_ucode_statistics_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 clear;
+
+	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", &clear) != 1)
+		return -EFAULT;
+
+	/* make request to uCode to retrieve statistics information */
+	mutex_lock(&priv->mutex);
+	iwl_send_statistics_request(priv, CMD_SYNC, true);
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos) {
+
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	char buf[128];
+	const size_t bufsz = sizeof(buf);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
+			priv->event_log.ucode_trace ? "On" : "Off");
+	pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
+			priv->event_log.non_wraps_count);
+	pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
+			priv->event_log.wraps_once_count);
+	pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
+			priv->event_log.wraps_more_count);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_ucode_tracing_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 trace;
+
+	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", &trace) != 1)
+		return -EFAULT;
+
+	if (trace) {
+		priv->event_log.ucode_trace = true;
+		if (iwl_is_alive(priv)) {
+			/* start collecting data now */
+			mod_timer(&priv->ucode_trace, jiffies);
+		}
+	} else {
+		priv->event_log.ucode_trace = false;
+		del_timer_sync(&priv->ucode_trace);
+	}
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_rxon_flags_read(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos) {
+
+	struct iwl_priv *priv = file->private_data;
+	int len = 0;
+	char buf[20];
+
+	len = sprintf(buf, "0x%04X\n",
+		le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.flags));
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file,
+						char __user *user_buf,
+						size_t count, loff_t *ppos) {
+
+	struct iwl_priv *priv = file->private_data;
+	int len = 0;
+	char buf[20];
+
+	len = sprintf(buf, "0x%04X\n",
+		le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags));
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos) {
+
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	char buf[12];
+	const size_t bufsz = sizeof(buf);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
+			priv->missed_beacon_threshold);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_missed_beacon_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 missed;
+
+	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", &missed) != 1)
+		return -EINVAL;
+
+	if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
+	    missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
+		priv->missed_beacon_threshold =
+			IWL_MISSED_BEACON_THRESHOLD_DEF;
+	else
+		priv->missed_beacon_threshold = missed;
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos) {
+
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	char buf[12];
+	const size_t bufsz = sizeof(buf);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
+			priv->plcp_delta_threshold);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_plcp_delta_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 plcp;
+
+	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", &plcp) != 1)
+		return -EINVAL;
+	if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
+		(plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
+		priv->plcp_delta_threshold =
+			IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE;
+	else
+		priv->plcp_delta_threshold = plcp;
+	return count;
+}
+
+static ssize_t iwl_dbgfs_rf_reset_read(struct file *file,
+				       char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	char buf[300];
+	const size_t bufsz = sizeof(buf);
+	struct iwl_rf_reset *rf_reset = &priv->rf_reset;
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"RF reset statistics\n");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"\tnumber of reset request: %d\n",
+			rf_reset->reset_request_count);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"\tnumber of reset request success: %d\n",
+			rf_reset->reset_success_count);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"\tnumber of reset request reject: %d\n",
+			rf_reset->reset_reject_count);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_rf_reset_write(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos) {
+
+	struct iwl_priv *priv = file->private_data;
+	int ret;
+
+	ret = iwl_force_rf_reset(priv, true);
+	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;
+
+	iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_bt_traffic_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[200];
+	const size_t bufsz = sizeof(buf);
+
+	if (!priv->bt_enable_flag) {
+		pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n");
+		return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	}
+	pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n",
+		priv->bt_enable_flag);
+	pos += scnprintf(buf + pos, bufsz - pos, "BT in %s mode\n",
+		priv->bt_full_concurrent ? "full concurrency" : "3-wire");
+	pos += scnprintf(buf + pos, bufsz - pos, "BT status: %s, "
+			 "last traffic notif: %d\n",
+		priv->bt_status ? "On" : "Off", priv->last_bt_traffic_load);
+	pos += scnprintf(buf + pos, bufsz - pos, "ch_announcement: %d, "
+			 "kill_ack_mask: %x, kill_cts_mask: %x\n",
+		priv->bt_ch_announce, priv->kill_ack_mask,
+		priv->kill_cts_mask);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "bluetooth traffic load: ");
+	switch (priv->bt_traffic_load) {
+	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+		pos += scnprintf(buf + pos, bufsz - pos, "Continuous\n");
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+		pos += scnprintf(buf + pos, bufsz - pos, "High\n");
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+		pos += scnprintf(buf + pos, bufsz - pos, "Low\n");
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+	default:
+		pos += scnprintf(buf + pos, bufsz - pos, "None\n");
+		break;
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_protection_mode_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[40];
+	const size_t bufsz = sizeof(buf);
+
+	if (priv->cfg->ht_params)
+		pos += scnprintf(buf + pos, bufsz - pos,
+			 "use %s for aggregation\n",
+			 (priv->hw_params.use_rts_for_aggregation) ?
+				"rts/cts" : "cts-to-self");
+	else
+		pos += scnprintf(buf + pos, bufsz - pos, "N/A");
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_protection_mode_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 rts;
+
+	if (!priv->cfg->ht_params)
+		return -EINVAL;
+
+	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", &rts) != 1)
+		return -EINVAL;
+	if (rts)
+		priv->hw_params.use_rts_for_aggregation = true;
+	else
+		priv->hw_params.use_rts_for_aggregation = false;
+	return count;
+}
+
+static int iwl_cmd_echo_test(struct iwl_priv *priv)
+{
+	int ret;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_ECHO,
+		.len = { 0 },
+		.flags = CMD_SYNC,
+	};
+
+	ret = iwl_dvm_send_cmd(priv, &cmd);
+	if (ret)
+		IWL_ERR(priv, "echo testing fail: 0X%x\n", ret);
+	else
+		IWL_DEBUG_INFO(priv, "echo testing pass\n");
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_echo_test_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;
+
+	memset(buf, 0, sizeof(buf));
+	buf_size = min(count, sizeof(buf) -  1);
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	iwl_cmd_echo_test(priv);
+	return count;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static ssize_t iwl_dbgfs_log_event_read(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	char *buf;
+	int pos = 0;
+	ssize_t ret = -ENOMEM;
+
+	ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true);
+	if (buf) {
+		ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+		kfree(buf);
+	}
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_log_event_write(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	u32 event_log_flag;
+	char buf[8];
+	int buf_size;
+
+	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", &event_log_flag) != 1)
+		return -EFAULT;
+	if (event_log_flag == 1)
+		iwl_dump_nic_event_log(priv, true, NULL, false);
+
+	return count;
+}
+#endif
+
+static ssize_t iwl_dbgfs_calib_disabled_read(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	char buf[120];
+	int pos = 0;
+	const size_t bufsz = sizeof(buf);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "Sensitivity calibrations %s\n",
+			 (priv->calib_disabled &
+					IWL_SENSITIVITY_CALIB_DISABLED) ?
+			 "DISABLED" : "ENABLED");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "Chain noise calibrations %s\n",
+			 (priv->calib_disabled &
+					IWL_CHAIN_NOISE_CALIB_DISABLED) ?
+			 "DISABLED" : "ENABLED");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "Tx power calibrations %s\n",
+			 (priv->calib_disabled &
+					IWL_TX_POWER_CALIB_DISABLED) ?
+			 "DISABLED" : "ENABLED");
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_calib_disabled_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];
+	u32 calib_disabled;
+	int buf_size;
+
+	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, "%x", &calib_disabled) != 1)
+		return -EFAULT;
+
+	priv->calib_disabled = calib_disabled;
+
+	return count;
+}
+
+DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
+DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
+DEBUGFS_READ_FILE_OPS(ucode_general_stats);
+DEBUGFS_READ_FILE_OPS(sensitivity);
+DEBUGFS_READ_FILE_OPS(chain_noise);
+DEBUGFS_READ_FILE_OPS(power_save_status);
+DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
+DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
+DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
+DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
+DEBUGFS_READ_WRITE_FILE_OPS(rf_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);
+DEBUGFS_READ_FILE_OPS(bt_traffic);
+DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
+DEBUGFS_READ_FILE_OPS(reply_tx_error);
+DEBUGFS_WRITE_FILE_OPS(echo_test);
+#ifdef CONFIG_IWLWIFI_DEBUG
+DEBUGFS_READ_WRITE_FILE_OPS(log_event);
+#endif
+DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled);
+
+/*
+ * Create the debugfs files and directories
+ *
+ */
+int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
+{
+	struct dentry *phyd = priv->hw->wiphy->debugfsdir;
+	struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
+
+	dir_drv = debugfs_create_dir(name, phyd);
+	if (!dir_drv)
+		return -ENOMEM;
+
+	priv->debugfs_dir = dir_drv;
+
+	dir_data = debugfs_create_dir("data", dir_drv);
+	if (!dir_data)
+		goto err;
+	dir_rf = debugfs_create_dir("rf", dir_drv);
+	if (!dir_rf)
+		goto err;
+	dir_debug = debugfs_create_dir("debug", dir_drv);
+	if (!dir_debug)
+		goto err;
+
+	DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
+	DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(wowlan_sram, dir_data, S_IRUSR);
+	DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
+	DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
+	DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
+	DEBUGFS_ADD_FILE(rx_handlers, dir_data, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
+	DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
+	DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
+	DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(temperature, dir_data, S_IRUSR);
+
+	DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
+	DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
+	DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
+	DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(rf_reset, dir_debug, S_IWUSR | S_IRUSR);
+	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);
+	DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
+	DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
+	DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
+	DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
+	DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
+	DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
+	DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
+	DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR);
+#ifdef CONFIG_IWLWIFI_DEBUG
+	DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR);
+#endif
+
+	if (iwl_advanced_bt_coexist(priv))
+		DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
+
+	/* Calibrations disabled/enabled status*/
+	DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR);
+
+	if (iwl_trans_dbgfs_register(priv->trans, dir_debug))
+		goto err;
+	return 0;
+
+err:
+	IWL_ERR(priv, "Can't create the debugfs directory\n");
+	iwl_dbgfs_unregister(priv);
+	return -ENOMEM;
+}
+
+/**
+ * Remove the debugfs files and directories
+ *
+ */
+void iwl_dbgfs_unregister(struct iwl_priv *priv)
+{
+	if (!priv->debugfs_dir)
+		return;
+
+	debugfs_remove_recursive(priv->debugfs_dir);
+	priv->debugfs_dir = NULL;
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h
new file mode 100644
index 0000000..54cf085
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/dev.h
@@ -0,0 +1,933 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 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.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+/*
+ * Please use this file (dev.h) for driver implementation definitions.
+ * Please use commands.h for uCode API definitions.
+ */
+
+#ifndef __iwl_dev_h__
+#define __iwl_dev_h__
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+
+#include "iwl-fw.h"
+#include "iwl-eeprom-parse.h"
+#include "iwl-csr.h"
+#include "iwl-debug.h"
+#include "iwl-agn-hw.h"
+#include "iwl-op-mode.h"
+#include "iwl-notif-wait.h"
+#include "iwl-trans.h"
+
+#include "led.h"
+#include "power.h"
+#include "rs.h"
+#include "tt.h"
+
+#include "iwl-test.h"
+
+/* CT-KILL constants */
+#define CT_KILL_THRESHOLD_LEGACY   110 /* in Celsius */
+#define CT_KILL_THRESHOLD	   114 /* in Celsius */
+#define CT_KILL_EXIT_THRESHOLD     95  /* in Celsius */
+
+/* Default noise level to report when noise measurement is not available.
+ *   This may be because we're:
+ *   1)  Not associated  no beacon statistics being sent to driver)
+ *   2)  Scanning (noise measurement does not apply to associated channel)
+ * Use default noise value of -127 ... this is below the range of measurable
+ *   Rx dBm for all agn devices, so it can indicate "unmeasurable" to user.
+ *   Also, -127 works better than 0 when averaging frames with/without
+ *   noise info (e.g. averaging might be done in app); measured dBm values are
+ *   always negative ... using a negative value as the default keeps all
+ *   averages within an s8's (used in some apps) range of negative values. */
+#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
+
+/*
+ * RTS threshold here is total size [2347] minus 4 FCS bytes
+ * Per spec:
+ *   a value of 0 means RTS on all data/management packets
+ *   a value > max MSDU size means no RTS
+ * else RTS for data/management frames where MPDU is larger
+ *   than RTS value.
+ */
+#define DEFAULT_RTS_THRESHOLD     2347U
+#define MIN_RTS_THRESHOLD         0U
+#define MAX_RTS_THRESHOLD         2347U
+#define MAX_MSDU_SIZE		  2304U
+#define MAX_MPDU_SIZE		  2346U
+#define DEFAULT_BEACON_INTERVAL   200U
+#define	DEFAULT_SHORT_RETRY_LIMIT 7U
+#define	DEFAULT_LONG_RETRY_LIMIT  4U
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+/*
+ * Minimum number of queues. MAX_NUM is defined in hw specific files.
+ * Set the minimum to accommodate
+ *  - 4 standard TX queues
+ *  - the command queue
+ *  - 4 PAN TX queues
+ *  - the PAN multicast queue, and
+ *  - the AUX (TX during scan dwell) queue.
+ */
+#define IWL_MIN_NUM_QUEUES	11
+
+/*
+ * Command queue depends on iPAN support.
+ */
+#define IWL_DEFAULT_CMD_QUEUE_NUM	4
+#define IWL_IPAN_CMD_QUEUE_NUM		9
+
+#define IEEE80211_DATA_LEN              2304
+#define IEEE80211_4ADDR_LEN             30
+#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
+#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+#define IWL_SUPPORTED_RATES_IE_LEN         8
+
+#define IWL_INVALID_RATE     0xFF
+#define IWL_INVALID_VALUE    -1
+
+union iwl_ht_rate_supp {
+	u16 rates;
+	struct {
+		u8 siso_rate;
+		u8 mimo_rate;
+	};
+};
+
+struct iwl_ht_config {
+	bool single_chain_sufficient;
+	enum ieee80211_smps_mode smps; /* current smps mode */
+};
+
+/* QoS structures */
+struct iwl_qos_info {
+	int qos_active;
+	struct iwl_qosparam_cmd def_qos_parm;
+};
+
+/**
+ * enum iwl_agg_state
+ *
+ * The state machine of the BA agreement establishment / tear down.
+ * These states relate to a specific RA / TID.
+ *
+ * @IWL_AGG_OFF: aggregation is not used
+ * @IWL_AGG_STARTING: aggregation are starting (between start and oper)
+ * @IWL_AGG_ON: aggregation session is up
+ * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the
+ *	HW queue to be empty from packets for this RA /TID.
+ * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the
+ *	HW queue to be empty from packets for this RA /TID.
+ */
+enum iwl_agg_state {
+	IWL_AGG_OFF = 0,
+	IWL_AGG_STARTING,
+	IWL_AGG_ON,
+	IWL_EMPTYING_HW_QUEUE_ADDBA,
+	IWL_EMPTYING_HW_QUEUE_DELBA,
+};
+
+/**
+ * struct iwl_ht_agg - aggregation state machine
+
+ * This structs holds the states for the BA agreement establishment and tear
+ * down. It also holds the state during the BA session itself. This struct is
+ * duplicated for each RA / TID.
+
+ * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the
+ *	Tx response (REPLY_TX), and the block ack notification
+ *	(REPLY_COMPRESSED_BA).
+ * @state: state of the BA agreement establishment / tear down.
+ * @txq_id: Tx queue used by the BA session
+ * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or
+ *	the first packet to be sent in legacy HW queue in Tx AGG stop flow.
+ *	Basically when next_reclaimed reaches ssn, we can tell mac80211 that
+ *	we are ready to finish the Tx AGG stop / start flow.
+ * @wait_for_ba: Expect block-ack before next Tx reply
+ */
+struct iwl_ht_agg {
+	u32 rate_n_flags;
+	enum iwl_agg_state state;
+	u16 txq_id;
+	u16 ssn;
+	bool wait_for_ba;
+};
+
+/**
+ * struct iwl_tid_data - one for each RA / TID
+
+ * This structs holds the states for each RA / TID.
+
+ * @seq_number: the next WiFi sequence number to use
+ * @next_reclaimed: the WiFi sequence number of the next packet to be acked.
+ *	This is basically (last acked packet++).
+ * @agg: aggregation state machine
+ */
+struct iwl_tid_data {
+	u16 seq_number;
+	u16 next_reclaimed;
+	struct iwl_ht_agg agg;
+};
+
+/*
+ * Structure should be accessed with sta_lock held. When station addition
+ * is in progress (IWL_STA_UCODE_INPROGRESS) it is possible to access only
+ * the commands (iwl_addsta_cmd and iwl_link_quality_cmd) without sta_lock
+ * held.
+ */
+struct iwl_station_entry {
+	struct iwl_addsta_cmd sta;
+	u8 used, ctxid;
+	struct iwl_link_quality_cmd *lq;
+};
+
+/*
+ * iwl_station_priv: Driver's private station information
+ *
+ * When mac80211 creates a station it reserves some space (hw->sta_data_size)
+ * in the structure for use by driver. This structure is places in that
+ * space.
+ */
+struct iwl_station_priv {
+	struct iwl_rxon_context *ctx;
+	struct iwl_lq_sta lq_sta;
+	atomic_t pending_frames;
+	bool client;
+	bool asleep;
+	u8 max_agg_bufsize;
+	u8 sta_id;
+};
+
+/**
+ * struct iwl_vif_priv - driver's private per-interface information
+ *
+ * When mac80211 allocates a virtual interface, it can allocate
+ * space for us to put data into.
+ */
+struct iwl_vif_priv {
+	struct iwl_rxon_context *ctx;
+	u8 ibss_bssid_sta_id;
+};
+
+struct iwl_sensitivity_ranges {
+	u16 min_nrg_cck;
+
+	u16 nrg_th_cck;
+	u16 nrg_th_ofdm;
+
+	u16 auto_corr_min_ofdm;
+	u16 auto_corr_min_ofdm_mrc;
+	u16 auto_corr_min_ofdm_x1;
+	u16 auto_corr_min_ofdm_mrc_x1;
+
+	u16 auto_corr_max_ofdm;
+	u16 auto_corr_max_ofdm_mrc;
+	u16 auto_corr_max_ofdm_x1;
+	u16 auto_corr_max_ofdm_mrc_x1;
+
+	u16 auto_corr_max_cck;
+	u16 auto_corr_max_cck_mrc;
+	u16 auto_corr_min_cck;
+	u16 auto_corr_min_cck_mrc;
+
+	u16 barker_corr_th_min;
+	u16 barker_corr_th_min_mrc;
+	u16 nrg_th_cca;
+};
+
+
+#define KELVIN_TO_CELSIUS(x) ((x)-273)
+#define CELSIUS_TO_KELVIN(x) ((x)+273)
+
+
+/******************************************************************************
+ *
+ * Functions implemented in core module which are forward declared here
+ * for use by iwl-[4-5].c
+ *
+ * NOTE:  The implementation of these functions are not hardware specific
+ * which is why they are in the core module files.
+ *
+ * Naming convention --
+ * iwl_         <-- Is part of iwlwifi
+ * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
+ *
+ ****************************************************************************/
+extern void iwl_update_chain_flags(struct iwl_priv *priv);
+extern const u8 iwl_bcast_addr[ETH_ALEN];
+
+#define IWL_OPERATION_MODE_AUTO     0
+#define IWL_OPERATION_MODE_HT_ONLY  1
+#define IWL_OPERATION_MODE_MIXED    2
+#define IWL_OPERATION_MODE_20MHZ    3
+
+#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
+
+/* Sensitivity and chain noise calibration */
+#define INITIALIZATION_VALUE		0xFFFF
+#define IWL_CAL_NUM_BEACONS		16
+#define MAXIMUM_ALLOWED_PATHLOSS	15
+
+#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
+
+#define MAX_FA_OFDM  50
+#define MIN_FA_OFDM  5
+#define MAX_FA_CCK   50
+#define MIN_FA_CCK   5
+
+#define AUTO_CORR_STEP_OFDM       1
+
+#define AUTO_CORR_STEP_CCK     3
+#define AUTO_CORR_MAX_TH_CCK   160
+
+#define NRG_DIFF               2
+#define NRG_STEP_CCK           2
+#define NRG_MARGIN             8
+#define MAX_NUMBER_CCK_NO_FA 100
+
+#define AUTO_CORR_CCK_MIN_VAL_DEF    (125)
+
+#define CHAIN_A             0
+#define CHAIN_B             1
+#define CHAIN_C             2
+#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4
+#define ALL_BAND_FILTER			0xFF00
+#define IN_BAND_FILTER			0xFF
+#define MIN_AVERAGE_NOISE_MAX_VALUE	0xFFFFFFFF
+
+#define NRG_NUM_PREV_STAT_L     20
+#define NUM_RX_CHAINS           3
+
+enum iwlagn_false_alarm_state {
+	IWL_FA_TOO_MANY = 0,
+	IWL_FA_TOO_FEW = 1,
+	IWL_FA_GOOD_RANGE = 2,
+};
+
+enum iwlagn_chain_noise_state {
+	IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
+	IWL_CHAIN_NOISE_ACCUMULATE,
+	IWL_CHAIN_NOISE_CALIBRATED,
+	IWL_CHAIN_NOISE_DONE,
+};
+
+/* Sensitivity calib data */
+struct iwl_sensitivity_data {
+	u32 auto_corr_ofdm;
+	u32 auto_corr_ofdm_mrc;
+	u32 auto_corr_ofdm_x1;
+	u32 auto_corr_ofdm_mrc_x1;
+	u32 auto_corr_cck;
+	u32 auto_corr_cck_mrc;
+
+	u32 last_bad_plcp_cnt_ofdm;
+	u32 last_fa_cnt_ofdm;
+	u32 last_bad_plcp_cnt_cck;
+	u32 last_fa_cnt_cck;
+
+	u32 nrg_curr_state;
+	u32 nrg_prev_state;
+	u32 nrg_value[10];
+	u8  nrg_silence_rssi[NRG_NUM_PREV_STAT_L];
+	u32 nrg_silence_ref;
+	u32 nrg_energy_idx;
+	u32 nrg_silence_idx;
+	u32 nrg_th_cck;
+	s32 nrg_auto_corr_silence_diff;
+	u32 num_in_cck_no_fa;
+	u32 nrg_th_ofdm;
+
+	u16 barker_corr_th_min;
+	u16 barker_corr_th_min_mrc;
+	u16 nrg_th_cca;
+};
+
+/* Chain noise (differential Rx gain) calib data */
+struct iwl_chain_noise_data {
+	u32 active_chains;
+	u32 chain_noise_a;
+	u32 chain_noise_b;
+	u32 chain_noise_c;
+	u32 chain_signal_a;
+	u32 chain_signal_b;
+	u32 chain_signal_c;
+	u16 beacon_count;
+	u8 disconn_array[NUM_RX_CHAINS];
+	u8 delta_gain_code[NUM_RX_CHAINS];
+	u8 radio_write;
+	u8 state;
+};
+
+enum {
+	MEASUREMENT_READY = (1 << 0),
+	MEASUREMENT_ACTIVE = (1 << 1),
+};
+
+/* reply_tx_statistics (for _agn devices) */
+struct reply_tx_error_statistics {
+	u32 pp_delay;
+	u32 pp_few_bytes;
+	u32 pp_bt_prio;
+	u32 pp_quiet_period;
+	u32 pp_calc_ttak;
+	u32 int_crossed_retry;
+	u32 short_limit;
+	u32 long_limit;
+	u32 fifo_underrun;
+	u32 drain_flow;
+	u32 rfkill_flush;
+	u32 life_expire;
+	u32 dest_ps;
+	u32 host_abort;
+	u32 bt_retry;
+	u32 sta_invalid;
+	u32 frag_drop;
+	u32 tid_disable;
+	u32 fifo_flush;
+	u32 insuff_cf_poll;
+	u32 fail_hw_drop;
+	u32 sta_color_mismatch;
+	u32 unknown;
+};
+
+/* reply_agg_tx_statistics (for _agn devices) */
+struct reply_agg_tx_error_statistics {
+	u32 underrun;
+	u32 bt_prio;
+	u32 few_bytes;
+	u32 abort;
+	u32 last_sent_ttl;
+	u32 last_sent_try;
+	u32 last_sent_bt_kill;
+	u32 scd_query;
+	u32 bad_crc32;
+	u32 response;
+	u32 dump_tx;
+	u32 delay_tx;
+	u32 unknown;
+};
+
+/*
+ * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
+ * to perform continuous uCode event logging operation if enabled
+ */
+#define UCODE_TRACE_PERIOD (10)
+
+/*
+ * iwl_event_log: current uCode event log position
+ *
+ * @ucode_trace: enable/disable ucode continuous trace timer
+ * @num_wraps: how many times the event buffer wraps
+ * @next_entry:  the entry just before the next one that uCode would fill
+ * @non_wraps_count: counter for no wrap detected when dump ucode events
+ * @wraps_once_count: counter for wrap once detected when dump ucode events
+ * @wraps_more_count: counter for wrap more than once detected
+ *		      when dump ucode events
+ */
+struct iwl_event_log {
+	bool ucode_trace;
+	u32 num_wraps;
+	u32 next_entry;
+	int non_wraps_count;
+	int wraps_once_count;
+	int wraps_more_count;
+};
+
+#define IWL_DELAY_NEXT_FORCE_RF_RESET  (HZ*3)
+
+/* BT Antenna Coupling Threshold (dB) */
+#define IWL_BT_ANTENNA_COUPLING_THRESHOLD	(35)
+
+/* Firmware reload counter and Timestamp */
+#define IWL_MIN_RELOAD_DURATION		1000 /* 1000 ms */
+#define IWL_MAX_CONTINUE_RELOAD_CNT	4
+
+
+struct iwl_rf_reset {
+	int reset_request_count;
+	int reset_success_count;
+	int reset_reject_count;
+	unsigned long last_reset_jiffies;
+};
+
+enum iwl_rxon_context_id {
+	IWL_RXON_CTX_BSS,
+	IWL_RXON_CTX_PAN,
+
+	NUM_IWL_RXON_CTX
+};
+
+/* extend beacon time format bit shifting  */
+/*
+ * for _agn devices
+ * bits 31:22 - extended
+ * bits 21:0  - interval
+ */
+#define IWLAGN_EXT_BEACON_TIME_POS	22
+
+struct iwl_rxon_context {
+	struct ieee80211_vif *vif;
+
+	u8 mcast_queue;
+	u8 ac_to_queue[IEEE80211_NUM_ACS];
+	u8 ac_to_fifo[IEEE80211_NUM_ACS];
+
+	/*
+	 * We could use the vif to indicate active, but we
+	 * also need it to be active during disabling when
+	 * we already removed the vif for type setting.
+	 */
+	bool always_active, is_active;
+
+	bool ht_need_multiple_chains;
+
+	enum iwl_rxon_context_id ctxid;
+
+	u32 interface_modes, exclusive_interface_modes;
+	u8 unused_devtype, ap_devtype, ibss_devtype, station_devtype;
+
+	/*
+	 * We declare this const so it can only be
+	 * changed via explicit cast within the
+	 * routines that actually update the physical
+	 * hardware.
+	 */
+	const struct iwl_rxon_cmd active;
+	struct iwl_rxon_cmd staging;
+
+	struct iwl_rxon_time_cmd timing;
+
+	struct iwl_qos_info qos_data;
+
+	u8 bcast_sta_id, ap_sta_id;
+
+	u8 rxon_cmd, rxon_assoc_cmd, rxon_timing_cmd;
+	u8 qos_cmd;
+	u8 wep_key_cmd;
+
+	struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
+	u8 key_mapping_keys;
+
+	__le32 station_flags;
+
+	int beacon_int;
+
+	struct {
+		bool non_gf_sta_present;
+		u8 protection;
+		bool enabled, is_40mhz;
+		u8 extension_chan_offset;
+	} ht;
+};
+
+enum iwl_scan_type {
+	IWL_SCAN_NORMAL,
+	IWL_SCAN_RADIO_RESET,
+	IWL_SCAN_ROC,
+};
+
+/**
+ * struct iwl_hw_params
+ *
+ * Holds the module parameters
+ *
+ * @tx_chains_num: Number of TX chains
+ * @rx_chains_num: Number of RX chains
+ * @ct_kill_threshold: temperature threshold - in hw dependent unit
+ * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
+ *	relevant for 1000, 6000 and up
+ * @struct iwl_sensitivity_ranges: range of sensitivity values
+ * @use_rts_for_aggregation: use rts/cts protection for HT traffic
+ */
+struct iwl_hw_params {
+	u8  tx_chains_num;
+	u8  rx_chains_num;
+	bool use_rts_for_aggregation;
+	u32 ct_kill_threshold;
+	u32 ct_kill_exit_threshold;
+
+	const struct iwl_sensitivity_ranges *sens;
+};
+
+struct iwl_lib_ops {
+	/* set hw dependent parameters */
+	void (*set_hw_params)(struct iwl_priv *priv);
+	int (*set_channel_switch)(struct iwl_priv *priv,
+				  struct ieee80211_channel_switch *ch_switch);
+	/* device specific configuration */
+	void (*nic_config)(struct iwl_priv *priv);
+
+	/* temperature */
+	void (*temperature)(struct iwl_priv *priv);
+};
+
+struct iwl_wipan_noa_data {
+	struct rcu_head rcu_head;
+	u32 length;
+	u8 data[];
+};
+
+/* Calibration disabling bit mask */
+enum {
+	IWL_CALIB_ENABLE_ALL			= 0,
+
+	IWL_SENSITIVITY_CALIB_DISABLED		= BIT(0),
+	IWL_CHAIN_NOISE_CALIB_DISABLED		= BIT(1),
+	IWL_TX_POWER_CALIB_DISABLED		= BIT(2),
+
+	IWL_CALIB_DISABLE_ALL			= 0xFFFFFFFF,
+};
+
+#define IWL_OP_MODE_GET_DVM(_iwl_op_mode) \
+	((struct iwl_priv *) ((_iwl_op_mode)->op_mode_specific))
+
+#define IWL_MAC80211_GET_DVM(_hw) \
+	((struct iwl_priv *) ((struct iwl_op_mode *) \
+	(_hw)->priv)->op_mode_specific)
+
+struct iwl_priv {
+
+	struct iwl_trans *trans;
+	struct device *dev;		/* for debug prints only */
+	const struct iwl_cfg *cfg;
+	const struct iwl_fw *fw;
+	const struct iwl_lib_ops *lib;
+	unsigned long status;
+
+	spinlock_t sta_lock;
+	struct mutex mutex;
+
+	unsigned long transport_queue_stop;
+	bool passive_no_rx;
+#define IWL_INVALID_MAC80211_QUEUE	0xff
+	u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
+	atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
+
+	unsigned long agg_q_alloc[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
+
+	/* ieee device used by generic ieee processing code */
+	struct ieee80211_hw *hw;
+
+	struct list_head calib_results;
+
+	struct workqueue_struct *workqueue;
+
+	struct iwl_hw_params hw_params;
+
+	enum ieee80211_band band;
+	u8 valid_contexts;
+
+	int (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
+				       struct iwl_rx_cmd_buffer *rxb,
+				       struct iwl_device_cmd *cmd);
+
+	struct iwl_notif_wait_data notif_wait;
+
+	/* spectrum measurement report caching */
+	struct iwl_spectrum_notification measure_report;
+	u8 measurement_status;
+
+#define IWL_OWNERSHIP_DRIVER	0
+#define IWL_OWNERSHIP_TM	1
+	u8 ucode_owner;
+
+	/* ucode beacon time */
+	u32 ucode_beacon_time;
+	int missed_beacon_threshold;
+
+	/* track IBSS manager (last beacon) status */
+	u32 ibss_manager;
+
+	/* jiffies when last recovery from statistics was performed */
+	unsigned long rx_statistics_jiffies;
+
+	/*counters */
+	u32 rx_handlers_stats[REPLY_MAX];
+
+	/* rf reset */
+	struct iwl_rf_reset rf_reset;
+
+	/* firmware reload counter and timestamp */
+	unsigned long reload_jiffies;
+	int reload_count;
+	bool ucode_loaded;
+	bool init_ucode_run;		/* Don't run init uCode again */
+
+	u8 plcp_delta_threshold;
+
+	/* thermal calibration */
+	s32 temperature;	/* Celsius */
+	s32 last_temperature;
+
+	struct iwl_wipan_noa_data __rcu *noa_data;
+
+	/* Scan related variables */
+	unsigned long scan_start;
+	unsigned long scan_start_tsf;
+	void *scan_cmd;
+	enum ieee80211_band scan_band;
+	struct cfg80211_scan_request *scan_request;
+	struct ieee80211_vif *scan_vif;
+	enum iwl_scan_type scan_type;
+	u8 scan_tx_ant[IEEE80211_NUM_BANDS];
+	u8 mgmt_tx_ant;
+
+	/* max number of station keys */
+	u8 sta_key_max_num;
+
+	bool new_scan_threshold_behaviour;
+
+	bool wowlan;
+
+	/* EEPROM MAC addresses */
+	struct mac_address addresses[2];
+
+	struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
+
+	__le16 switch_channel;
+
+	u8 start_calib;
+	struct iwl_sensitivity_data sensitivity_data;
+	struct iwl_chain_noise_data chain_noise_data;
+	__le16 sensitivity_tbl[HD_TABLE_SIZE];
+	__le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES];
+
+	struct iwl_ht_config current_ht_config;
+
+	/* Rate scaling data */
+	u8 retry_rate;
+
+	int activity_timer_active;
+
+	struct iwl_power_mgr power_data;
+	struct iwl_tt_mgmt thermal_throttle;
+
+	/* station table variables */
+	int num_stations;
+	struct iwl_station_entry stations[IWLAGN_STATION_COUNT];
+	unsigned long ucode_key_table;
+	struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT];
+	atomic_t num_aux_in_flight;
+
+	u8 mac80211_registered;
+
+	/* Indication if ieee80211_ops->open has been called */
+	u8 is_open;
+
+	enum nl80211_iftype iw_mode;
+
+	/* Last Rx'd beacon timestamp */
+	u64 timestamp;
+
+	struct {
+		__le32 flag;
+		struct statistics_general_common common;
+		struct statistics_rx_non_phy rx_non_phy;
+		struct statistics_rx_phy rx_ofdm;
+		struct statistics_rx_ht_phy rx_ofdm_ht;
+		struct statistics_rx_phy rx_cck;
+		struct statistics_tx tx;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+		struct statistics_bt_activity bt_activity;
+		__le32 num_bt_kills, accum_num_bt_kills;
+#endif
+		spinlock_t lock;
+	} statistics;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	struct {
+		struct statistics_general_common common;
+		struct statistics_rx_non_phy rx_non_phy;
+		struct statistics_rx_phy rx_ofdm;
+		struct statistics_rx_ht_phy rx_ofdm_ht;
+		struct statistics_rx_phy rx_cck;
+		struct statistics_tx tx;
+		struct statistics_bt_activity bt_activity;
+	} accum_stats, delta_stats, max_delta_stats;
+#endif
+
+	/*
+	 * reporting the number of tids has AGG on. 0 means
+	 * no AGGREGATION
+	 */
+	u8 agg_tids_count;
+
+	struct iwl_rx_phy_res last_phy_res;
+	bool last_phy_res_valid;
+
+	/*
+	 * 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;
+
+	/* counts reply_tx error */
+	struct reply_tx_error_statistics reply_tx_stats;
+	struct reply_agg_tx_error_statistics reply_agg_tx_stats;
+
+	/* remain-on-channel offload support */
+	struct ieee80211_channel *hw_roc_channel;
+	struct delayed_work hw_roc_disable_work;
+	enum nl80211_channel_type hw_roc_chantype;
+	int hw_roc_duration;
+	bool hw_roc_setup, hw_roc_start_notified;
+
+	/* bt coex */
+	u8 bt_enable_flag;
+	u8 bt_status;
+	u8 bt_traffic_load, last_bt_traffic_load;
+	bool bt_ch_announce;
+	bool bt_full_concurrent;
+	bool bt_ant_couple_ok;
+	__le32 kill_ack_mask;
+	__le32 kill_cts_mask;
+	__le16 bt_valid;
+	bool reduced_txpower;
+	u16 bt_on_thresh;
+	u16 bt_duration;
+	u16 dynamic_frag_thresh;
+	u8 bt_ci_compliance;
+	struct work_struct bt_traffic_change_work;
+	bool bt_enable_pspoll;
+	struct iwl_rxon_context *cur_rssi_ctx;
+	bool bt_is_sco;
+
+	struct work_struct restart;
+	struct work_struct scan_completed;
+	struct work_struct abort_scan;
+
+	struct work_struct beacon_update;
+	struct iwl_rxon_context *beacon_ctx;
+	struct sk_buff *beacon_skb;
+	void *beacon_cmd;
+
+	struct work_struct tt_work;
+	struct work_struct ct_enter;
+	struct work_struct ct_exit;
+	struct work_struct start_internal_scan;
+	struct work_struct tx_flush;
+	struct work_struct bt_full_concurrency;
+	struct work_struct bt_runtime_config;
+
+	struct delayed_work scan_check;
+
+	/* TX Power settings */
+	s8 tx_power_user_lmt;
+	s8 tx_power_next;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	/* debugfs */
+	struct dentry *debugfs_dir;
+	u32 dbgfs_sram_offset, dbgfs_sram_len;
+	bool disable_ht40;
+	void *wowlan_sram;
+#endif /* CONFIG_IWLWIFI_DEBUGFS */
+
+	struct iwl_eeprom_data *eeprom_data;
+	/* eeprom blob for debugfs/testmode */
+	u8 *eeprom_blob;
+	size_t eeprom_blob_size;
+
+	struct work_struct txpower_work;
+	u32 calib_disabled;
+	struct work_struct run_time_calib_work;
+	struct timer_list statistics_periodic;
+	struct timer_list ucode_trace;
+
+	struct iwl_event_log event_log;
+
+	struct led_classdev led;
+	unsigned long blink_on, blink_off;
+	bool led_registered;
+
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+	struct iwl_test tst;
+	u32 tm_fixed_rate;
+#endif
+
+	/* WoWLAN GTK rekey data */
+	u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN];
+	__le64 replay_ctr;
+	__le16 last_seq_ctl;
+	bool have_rekey_data;
+
+	/* device_pointers: pointers to ucode event tables */
+	struct {
+		u32 error_event_table;
+		u32 log_event_table;
+	} device_pointers;
+
+	/* indicator of loaded ucode image */
+	enum iwl_ucode_type cur_ucode;
+}; /*iwl_priv */
+
+static inline struct iwl_rxon_context *
+iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif)
+{
+	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
+	return vif_priv->ctx;
+}
+
+#define for_each_context(priv, ctx)				\
+	for (ctx = &priv->contexts[IWL_RXON_CTX_BSS];		\
+	     ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++)	\
+		if (priv->valid_contexts & BIT(ctx->ctxid))
+
+static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
+{
+	return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+static inline int iwl_is_associated(struct iwl_priv *priv,
+				    enum iwl_rxon_context_id ctxid)
+{
+	return iwl_is_associated_ctx(&priv->contexts[ctxid]);
+}
+
+static inline int iwl_is_any_associated(struct iwl_priv *priv)
+{
+	struct iwl_rxon_context *ctx;
+	for_each_context(priv, ctx)
+		if (iwl_is_associated_ctx(ctx))
+			return true;
+	return false;
+}
+
+#endif				/* __iwl_dev_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c
new file mode 100644
index 0000000..349c205
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/devices.c
@@ -0,0 +1,588 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2012 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.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+/*
+ * DVM device-specific data & functions
+ */
+#include "iwl-io.h"
+#include "iwl-prph.h"
+#include "iwl-eeprom-parse.h"
+
+#include "agn.h"
+#include "dev.h"
+#include "commands.h"
+
+
+/*
+ * 1000 series
+ * ===========
+ */
+
+/*
+ * For 1000, use advance thermal throttling critical temperature threshold,
+ * but legacy thermal management implementation for now.
+ * This is for the reason of 1000 uCode using advance thermal throttling API
+ * but not implement ct_kill_exit based on ct_kill exit temperature
+ * so the thermal throttling will still based on legacy thermal throttling
+ * management.
+ * The code here need to be modified once 1000 uCode has the advanced thermal
+ * throttling algorithm in place
+ */
+static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
+{
+	/* want Celsius */
+	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
+	priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+/* NIC configuration for 1000 series */
+static void iwl1000_nic_config(struct iwl_priv *priv)
+{
+	/* Setting digital SVR for 1000 card to 1.32V */
+	/* locking is acquired in iwl_set_bits_mask_prph() function */
+	iwl_set_bits_mask_prph(priv->trans, APMG_DIGITAL_SVR_REG,
+				APMG_SVR_DIGITAL_VOLTAGE_1_32,
+				~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
+}
+
+/**
+ * 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;
+}
+
+/*
+ * 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
+ */
+static 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, IWLAGN_EXT_BEACON_TIME_POS) >>
+		IWLAGN_EXT_BEACON_TIME_POS);
+	rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
+				   IWLAGN_EXT_BEACON_TIME_POS);
+
+	return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem;
+}
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+static __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
+			   u32 addon, u32 beacon_interval)
+{
+	u32 base_low = base & iwl_beacon_time_mask_low(priv,
+				IWLAGN_EXT_BEACON_TIME_POS);
+	u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
+				IWLAGN_EXT_BEACON_TIME_POS);
+	u32 interval = beacon_interval * TIME_UNIT;
+	u32 res = (base & iwl_beacon_time_mask_high(priv,
+				IWLAGN_EXT_BEACON_TIME_POS)) +
+				(addon & iwl_beacon_time_mask_high(priv,
+				IWLAGN_EXT_BEACON_TIME_POS));
+
+	if (base_low > addon_low)
+		res += base_low - addon_low;
+	else if (base_low < addon_low) {
+		res += interval + base_low - addon_low;
+		res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
+	} else
+		res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
+
+	return cpu_to_le32(res);
+}
+
+static const struct iwl_sensitivity_ranges iwl1000_sensitivity = {
+	.min_nrg_cck = 95,
+	.auto_corr_min_ofdm = 90,
+	.auto_corr_min_ofdm_mrc = 170,
+	.auto_corr_min_ofdm_x1 = 120,
+	.auto_corr_min_ofdm_mrc_x1 = 240,
+
+	.auto_corr_max_ofdm = 120,
+	.auto_corr_max_ofdm_mrc = 210,
+	.auto_corr_max_ofdm_x1 = 155,
+	.auto_corr_max_ofdm_mrc_x1 = 290,
+
+	.auto_corr_min_cck = 125,
+	.auto_corr_max_cck = 200,
+	.auto_corr_min_cck_mrc = 170,
+	.auto_corr_max_cck_mrc = 400,
+	.nrg_th_cck = 95,
+	.nrg_th_ofdm = 95,
+
+	.barker_corr_th_min = 190,
+	.barker_corr_th_min_mrc = 390,
+	.nrg_th_cca = 62,
+};
+
+static void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
+{
+	iwl1000_set_ct_threshold(priv);
+
+	/* Set initial sensitivity parameters */
+	priv->hw_params.sens = &iwl1000_sensitivity;
+}
+
+struct iwl_lib_ops iwl1000_lib = {
+	.set_hw_params = iwl1000_hw_set_hw_params,
+	.nic_config = iwl1000_nic_config,
+	.temperature = iwlagn_temperature,
+};
+
+
+/*
+ * 2000 series
+ * ===========
+ */
+
+static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
+{
+	/* want Celsius */
+	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+	priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+/* NIC configuration for 2000 series */
+static void iwl2000_nic_config(struct iwl_priv *priv)
+{
+	iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
+		    CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
+}
+
+static const struct iwl_sensitivity_ranges iwl2000_sensitivity = {
+	.min_nrg_cck = 97,
+	.auto_corr_min_ofdm = 80,
+	.auto_corr_min_ofdm_mrc = 128,
+	.auto_corr_min_ofdm_x1 = 105,
+	.auto_corr_min_ofdm_mrc_x1 = 192,
+
+	.auto_corr_max_ofdm = 145,
+	.auto_corr_max_ofdm_mrc = 232,
+	.auto_corr_max_ofdm_x1 = 110,
+	.auto_corr_max_ofdm_mrc_x1 = 232,
+
+	.auto_corr_min_cck = 125,
+	.auto_corr_max_cck = 175,
+	.auto_corr_min_cck_mrc = 160,
+	.auto_corr_max_cck_mrc = 310,
+	.nrg_th_cck = 97,
+	.nrg_th_ofdm = 100,
+
+	.barker_corr_th_min = 190,
+	.barker_corr_th_min_mrc = 390,
+	.nrg_th_cca = 62,
+};
+
+static void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
+{
+	iwl2000_set_ct_threshold(priv);
+
+	/* Set initial sensitivity parameters */
+	priv->hw_params.sens = &iwl2000_sensitivity;
+}
+
+struct iwl_lib_ops iwl2000_lib = {
+	.set_hw_params = iwl2000_hw_set_hw_params,
+	.nic_config = iwl2000_nic_config,
+	.temperature = iwlagn_temperature,
+};
+
+struct iwl_lib_ops iwl2030_lib = {
+	.set_hw_params = iwl2000_hw_set_hw_params,
+	.nic_config = iwl2000_nic_config,
+	.temperature = iwlagn_temperature,
+};
+
+/*
+ * 5000 series
+ * ===========
+ */
+
+/* NIC configuration for 5000 series */
+static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
+	.min_nrg_cck = 100,
+	.auto_corr_min_ofdm = 90,
+	.auto_corr_min_ofdm_mrc = 170,
+	.auto_corr_min_ofdm_x1 = 105,
+	.auto_corr_min_ofdm_mrc_x1 = 220,
+
+	.auto_corr_max_ofdm = 120,
+	.auto_corr_max_ofdm_mrc = 210,
+	.auto_corr_max_ofdm_x1 = 120,
+	.auto_corr_max_ofdm_mrc_x1 = 240,
+
+	.auto_corr_min_cck = 125,
+	.auto_corr_max_cck = 200,
+	.auto_corr_min_cck_mrc = 200,
+	.auto_corr_max_cck_mrc = 400,
+	.nrg_th_cck = 100,
+	.nrg_th_ofdm = 100,
+
+	.barker_corr_th_min = 190,
+	.barker_corr_th_min_mrc = 390,
+	.nrg_th_cca = 62,
+};
+
+static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
+	.min_nrg_cck = 95,
+	.auto_corr_min_ofdm = 90,
+	.auto_corr_min_ofdm_mrc = 170,
+	.auto_corr_min_ofdm_x1 = 105,
+	.auto_corr_min_ofdm_mrc_x1 = 220,
+
+	.auto_corr_max_ofdm = 120,
+	.auto_corr_max_ofdm_mrc = 210,
+	/* max = min for performance bug in 5150 DSP */
+	.auto_corr_max_ofdm_x1 = 105,
+	.auto_corr_max_ofdm_mrc_x1 = 220,
+
+	.auto_corr_min_cck = 125,
+	.auto_corr_max_cck = 200,
+	.auto_corr_min_cck_mrc = 170,
+	.auto_corr_max_cck_mrc = 400,
+	.nrg_th_cck = 95,
+	.nrg_th_ofdm = 95,
+
+	.barker_corr_th_min = 190,
+	.barker_corr_th_min_mrc = 390,
+	.nrg_th_cca = 62,
+};
+
+#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF	(-5)
+
+static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
+{
+	u16 temperature, voltage;
+
+	temperature = le16_to_cpu(priv->eeprom_data->kelvin_temperature);
+	voltage = le16_to_cpu(priv->eeprom_data->kelvin_voltage);
+
+	/* offset = temp - volt / coeff */
+	return (s32)(temperature -
+			voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
+}
+
+static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
+{
+	const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
+	s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
+			iwl_temp_calib_to_offset(priv);
+
+	priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
+}
+
+static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
+{
+	/* want Celsius */
+	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
+}
+
+static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
+{
+	iwl5000_set_ct_threshold(priv);
+
+	/* Set initial sensitivity parameters */
+	priv->hw_params.sens = &iwl5000_sensitivity;
+}
+
+static void iwl5150_hw_set_hw_params(struct iwl_priv *priv)
+{
+	iwl5150_set_ct_threshold(priv);
+
+	/* Set initial sensitivity parameters */
+	priv->hw_params.sens = &iwl5150_sensitivity;
+}
+
+static void iwl5150_temperature(struct iwl_priv *priv)
+{
+	u32 vt = 0;
+	s32 offset =  iwl_temp_calib_to_offset(priv);
+
+	vt = le32_to_cpu(priv->statistics.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,
+				     struct ieee80211_channel_switch *ch_switch)
+{
+	/*
+	 * MULTI-FIXME
+	 * See iwlagn_mac_channel_switch.
+	 */
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+	struct iwl5000_channel_switch_cmd cmd;
+	u32 switch_time_in_usec, ucode_switch_time;
+	u16 ch;
+	u32 tsf_low;
+	u8 switch_count;
+	u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+	struct ieee80211_vif *vif = ctx->vif;
+	struct iwl_host_cmd hcmd = {
+		.id = REPLY_CHANNEL_SWITCH,
+		.len = { sizeof(cmd), },
+		.flags = CMD_SYNC,
+		.data = { &cmd, },
+	};
+
+	cmd.band = priv->band == IEEE80211_BAND_2GHZ;
+	ch = ch_switch->channel->hw_value;
+	IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
+		      ctx->active.channel, ch);
+	cmd.channel = cpu_to_le16(ch);
+	cmd.rxon_flags = ctx->staging.flags;
+	cmd.rxon_filter_flags = ctx->staging.filter_flags;
+	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);
+	cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
+
+	return iwl_dvm_send_cmd(priv, &hcmd);
+}
+
+struct iwl_lib_ops iwl5000_lib = {
+	.set_hw_params = iwl5000_hw_set_hw_params,
+	.set_channel_switch = iwl5000_hw_channel_switch,
+	.temperature = iwlagn_temperature,
+};
+
+struct iwl_lib_ops iwl5150_lib = {
+	.set_hw_params = iwl5150_hw_set_hw_params,
+	.set_channel_switch = iwl5000_hw_channel_switch,
+	.temperature = iwl5150_temperature,
+};
+
+
+
+/*
+ * 6000 series
+ * ===========
+ */
+
+static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
+{
+	/* want Celsius */
+	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+	priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+/* NIC configuration for 6000 series */
+static void iwl6000_nic_config(struct iwl_priv *priv)
+{
+	switch (priv->cfg->device_family) {
+	case IWL_DEVICE_FAMILY_6005:
+	case IWL_DEVICE_FAMILY_6030:
+	case IWL_DEVICE_FAMILY_6000:
+		break;
+	case IWL_DEVICE_FAMILY_6000i:
+		/* 2x2 IPA phy type */
+		iwl_write32(priv->trans, CSR_GP_DRIVER_REG,
+			     CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
+		break;
+	case IWL_DEVICE_FAMILY_6050:
+		/* Indicate calibration version to uCode. */
+		if (priv->eeprom_data->calib_version >= 6)
+			iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
+					CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
+		break;
+	case IWL_DEVICE_FAMILY_6150:
+		/* Indicate calibration version to uCode. */
+		if (priv->eeprom_data->calib_version >= 6)
+			iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
+					CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
+		iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
+			    CSR_GP_DRIVER_REG_BIT_6050_1x2);
+		break;
+	default:
+		WARN_ON(1);
+	}
+}
+
+static const struct iwl_sensitivity_ranges iwl6000_sensitivity = {
+	.min_nrg_cck = 110,
+	.auto_corr_min_ofdm = 80,
+	.auto_corr_min_ofdm_mrc = 128,
+	.auto_corr_min_ofdm_x1 = 105,
+	.auto_corr_min_ofdm_mrc_x1 = 192,
+
+	.auto_corr_max_ofdm = 145,
+	.auto_corr_max_ofdm_mrc = 232,
+	.auto_corr_max_ofdm_x1 = 110,
+	.auto_corr_max_ofdm_mrc_x1 = 232,
+
+	.auto_corr_min_cck = 125,
+	.auto_corr_max_cck = 175,
+	.auto_corr_min_cck_mrc = 160,
+	.auto_corr_max_cck_mrc = 310,
+	.nrg_th_cck = 110,
+	.nrg_th_ofdm = 110,
+
+	.barker_corr_th_min = 190,
+	.barker_corr_th_min_mrc = 336,
+	.nrg_th_cca = 62,
+};
+
+static void iwl6000_hw_set_hw_params(struct iwl_priv *priv)
+{
+	iwl6000_set_ct_threshold(priv);
+
+	/* Set initial sensitivity parameters */
+	priv->hw_params.sens = &iwl6000_sensitivity;
+
+}
+
+static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
+				     struct ieee80211_channel_switch *ch_switch)
+{
+	/*
+	 * MULTI-FIXME
+	 * See iwlagn_mac_channel_switch.
+	 */
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+	struct iwl6000_channel_switch_cmd cmd;
+	u32 switch_time_in_usec, ucode_switch_time;
+	u16 ch;
+	u32 tsf_low;
+	u8 switch_count;
+	u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+	struct ieee80211_vif *vif = ctx->vif;
+	struct iwl_host_cmd hcmd = {
+		.id = REPLY_CHANNEL_SWITCH,
+		.len = { sizeof(cmd), },
+		.flags = CMD_SYNC,
+		.data = { &cmd, },
+	};
+
+	cmd.band = priv->band == IEEE80211_BAND_2GHZ;
+	ch = ch_switch->channel->hw_value;
+	IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
+		      ctx->active.channel, ch);
+	cmd.channel = cpu_to_le16(ch);
+	cmd.rxon_flags = ctx->staging.flags;
+	cmd.rxon_filter_flags = ctx->staging.filter_flags;
+	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);
+	cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
+
+	return iwl_dvm_send_cmd(priv, &hcmd);
+}
+
+struct iwl_lib_ops iwl6000_lib = {
+	.set_hw_params = iwl6000_hw_set_hw_params,
+	.set_channel_switch = iwl6000_hw_channel_switch,
+	.nic_config = iwl6000_nic_config,
+	.temperature = iwlagn_temperature,
+};
+
+struct iwl_lib_ops iwl6030_lib = {
+	.set_hw_params = iwl6000_hw_set_hw_params,
+	.set_channel_switch = iwl6000_hw_channel_switch,
+	.nic_config = iwl6000_nic_config,
+	.temperature = iwlagn_temperature,
+};
diff --git a/drivers/net/wireless/iwlwifi/dvm/led.c b/drivers/net/wireless/iwlwifi/dvm/led.c
new file mode 100644
index 0000000..bf479f7
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/led.c
@@ -0,0 +1,224 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 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.
+ *
+ * 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/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/mac80211.h>
+#include <linux/etherdevice.h>
+#include <asm/unaligned.h>
+#include "iwl-io.h"
+#include "iwl-trans.h"
+#include "iwl-modparams.h"
+#include "dev.h"
+#include "agn.h"
+
+/* Throughput		OFF time(ms)	ON time (ms)
+ *	>300			25		25
+ *	>200 to 300		40		40
+ *	>100 to 200		55		55
+ *	>70 to 100		65		65
+ *	>50 to 70		75		75
+ *	>20 to 50		85		85
+ *	>10 to 20		95		95
+ *	>5 to 10		110		110
+ *	>1 to 5			130		130
+ *	>0 to 1			167		167
+ *	<=0					SOLID ON
+ */
+static const struct ieee80211_tpt_blink iwl_blink[] = {
+	{ .throughput = 0, .blink_time = 334 },
+	{ .throughput = 1 * 1024 - 1, .blink_time = 260 },
+	{ .throughput = 5 * 1024 - 1, .blink_time = 220 },
+	{ .throughput = 10 * 1024 - 1, .blink_time = 190 },
+	{ .throughput = 20 * 1024 - 1, .blink_time = 170 },
+	{ .throughput = 50 * 1024 - 1, .blink_time = 150 },
+	{ .throughput = 70 * 1024 - 1, .blink_time = 130 },
+	{ .throughput = 100 * 1024 - 1, .blink_time = 110 },
+	{ .throughput = 200 * 1024 - 1, .blink_time = 80 },
+	{ .throughput = 300 * 1024 - 1, .blink_time = 50 },
+};
+
+/* Set led register off */
+void iwlagn_led_enable(struct iwl_priv *priv)
+{
+	iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
+}
+
+/*
+ * Adjust led blink rate to compensate on a MAC Clock difference on every HW
+ * Led blink rate analysis showed an average deviation of 20% on 5000 series
+ * and up.
+ * Need to compensate on the led on/off time per HW according to the deviation
+ * to achieve the desired led frequency
+ * The calculation is: (100-averageDeviation)/100 * blinkTime
+ * For code efficiency the calculation will be:
+ *     compensation = (100 - averageDeviation) * 64 / 100
+ *     NewBlinkTime = (compensation * BlinkTime) / 64
+ */
+static inline u8 iwl_blink_compensation(struct iwl_priv *priv,
+				    u8 time, u16 compensation)
+{
+	if (!compensation) {
+		IWL_ERR(priv, "undefined blink compensation: "
+			"use pre-defined blinking time\n");
+		return time;
+	}
+
+	return (u8)((time * compensation) >> 6);
+}
+
+static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
+{
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_LEDS_CMD,
+		.len = { sizeof(struct iwl_led_cmd), },
+		.data = { led_cmd, },
+		.flags = CMD_ASYNC,
+	};
+	u32 reg;
+
+	reg = iwl_read32(priv->trans, CSR_LED_REG);
+	if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
+		iwl_write32(priv->trans, CSR_LED_REG,
+			    reg & CSR_LED_BSM_CTRL_MSK);
+
+	return iwl_dvm_send_cmd(priv, &cmd);
+}
+
+/* Set led pattern command */
+static int iwl_led_cmd(struct iwl_priv *priv,
+		       unsigned long on,
+		       unsigned long off)
+{
+	struct iwl_led_cmd led_cmd = {
+		.id = IWL_LED_LINK,
+		.interval = IWL_DEF_LED_INTRVL
+	};
+	int ret;
+
+	if (!test_bit(STATUS_READY, &priv->status))
+		return -EBUSY;
+
+	if (priv->blink_on == on && priv->blink_off == off)
+		return 0;
+
+	if (off == 0) {
+		/* led is SOLID_ON */
+		on = IWL_LED_SOLID;
+	}
+
+	IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n",
+			priv->cfg->base_params->led_compensation);
+	led_cmd.on = iwl_blink_compensation(priv, on,
+				priv->cfg->base_params->led_compensation);
+	led_cmd.off = iwl_blink_compensation(priv, off,
+				priv->cfg->base_params->led_compensation);
+
+	ret = iwl_send_led_cmd(priv, &led_cmd);
+	if (!ret) {
+		priv->blink_on = on;
+		priv->blink_off = off;
+	}
+	return ret;
+}
+
+static void iwl_led_brightness_set(struct led_classdev *led_cdev,
+				   enum led_brightness brightness)
+{
+	struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
+	unsigned long on = 0;
+
+	if (brightness > 0)
+		on = IWL_LED_SOLID;
+
+	iwl_led_cmd(priv, on, 0);
+}
+
+static int iwl_led_blink_set(struct led_classdev *led_cdev,
+			     unsigned long *delay_on,
+			     unsigned long *delay_off)
+{
+	struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
+
+	return iwl_led_cmd(priv, *delay_on, *delay_off);
+}
+
+void iwl_leds_init(struct iwl_priv *priv)
+{
+	int mode = iwlwifi_mod_params.led_mode;
+	int ret;
+
+	if (mode == IWL_LED_DISABLE) {
+		IWL_INFO(priv, "Led disabled\n");
+		return;
+	}
+	if (mode == IWL_LED_DEFAULT)
+		mode = priv->cfg->led_mode;
+
+	priv->led.name = kasprintf(GFP_KERNEL, "%s-led",
+				   wiphy_name(priv->hw->wiphy));
+	priv->led.brightness_set = iwl_led_brightness_set;
+	priv->led.blink_set = iwl_led_blink_set;
+	priv->led.max_brightness = 1;
+
+	switch (mode) {
+	case IWL_LED_DEFAULT:
+		WARN_ON(1);
+		break;
+	case IWL_LED_BLINK:
+		priv->led.default_trigger =
+			ieee80211_create_tpt_led_trigger(priv->hw,
+					IEEE80211_TPT_LEDTRIG_FL_CONNECTED,
+					iwl_blink, ARRAY_SIZE(iwl_blink));
+		break;
+	case IWL_LED_RF_STATE:
+		priv->led.default_trigger =
+			ieee80211_get_radio_led_name(priv->hw);
+		break;
+	}
+
+	ret = led_classdev_register(priv->trans->dev, &priv->led);
+	if (ret) {
+		kfree(priv->led.name);
+		return;
+	}
+
+	priv->led_registered = true;
+}
+
+void iwl_leds_exit(struct iwl_priv *priv)
+{
+	if (!priv->led_registered)
+		return;
+
+	led_classdev_unregister(&priv->led);
+	kfree(priv->led.name);
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/led.h b/drivers/net/wireless/iwlwifi/dvm/led.h
new file mode 100644
index 0000000..b02a853
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/led.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 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.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_leds_h__
+#define __iwl_leds_h__
+
+
+struct iwl_priv;
+
+#define IWL_LED_SOLID 11
+#define IWL_DEF_LED_INTRVL cpu_to_le32(1000)
+
+#define IWL_LED_ACTIVITY       (0<<1)
+#define IWL_LED_LINK           (1<<1)
+
+void iwlagn_led_enable(struct iwl_priv *priv);
+void iwl_leds_init(struct iwl_priv *priv);
+void iwl_leds_exit(struct iwl_priv *priv);
+
+#endif /* __iwl_leds_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c
new file mode 100644
index 0000000..207ae91
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/lib.c
@@ -0,0 +1,1291 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <net/mac80211.h>
+
+#include "iwl-io.h"
+#include "iwl-agn-hw.h"
+#include "iwl-trans.h"
+#include "iwl-modparams.h"
+
+#include "dev.h"
+#include "agn.h"
+
+int iwlagn_hw_valid_rtc_data_addr(u32 addr)
+{
+	return (addr >= IWLAGN_RTC_DATA_LOWER_BOUND) &&
+		(addr < IWLAGN_RTC_DATA_UPPER_BOUND);
+}
+
+int iwlagn_send_tx_power(struct iwl_priv *priv)
+{
+	struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
+	u8 tx_ant_cfg_cmd;
+
+	if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status),
+		      "TX Power requested while scanning!\n"))
+		return -EAGAIN;
+
+	/* half dBm need to multiply */
+	tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
+
+	if (tx_power_cmd.global_lmt > priv->eeprom_data->max_tx_pwr_half_dbm) {
+		/*
+		 * For the newer devices which using enhanced/extend tx power
+		 * table in EEPROM, the format is in half dBm. driver need to
+		 * convert to dBm format before report to mac80211.
+		 * By doing so, there is a possibility of 1/2 dBm resolution
+		 * lost. driver will perform "round-up" operation before
+		 * reporting, but it will cause 1/2 dBm tx power over the
+		 * regulatory limit. Perform the checking here, if the
+		 * "tx_power_user_lmt" is higher than EEPROM value (in
+		 * half-dBm format), lower the tx power based on EEPROM
+		 */
+		tx_power_cmd.global_lmt =
+			priv->eeprom_data->max_tx_pwr_half_dbm;
+	}
+	tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
+	tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
+
+	if (IWL_UCODE_API(priv->fw->ucode_ver) == 1)
+		tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
+	else
+		tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
+
+	return iwl_dvm_send_cmd_pdu(priv, tx_ant_cfg_cmd, CMD_SYNC,
+			sizeof(tx_power_cmd), &tx_power_cmd);
+}
+
+void iwlagn_temperature(struct iwl_priv *priv)
+{
+	lockdep_assert_held(&priv->statistics.lock);
+
+	/* store temperature from correct statistics (in Celsius) */
+	priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
+	iwl_tt_handler(priv);
+}
+
+int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
+{
+	int idx = 0;
+	int band_offset = 0;
+
+	/* HT rate format: mac80211 wants an MCS number, which is just LSB */
+	if (rate_n_flags & RATE_MCS_HT_MSK) {
+		idx = (rate_n_flags & 0xff);
+		return idx;
+	/* Legacy rate format, search for match in table */
+	} else {
+		if (band == IEEE80211_BAND_5GHZ)
+			band_offset = IWL_FIRST_OFDM_RATE;
+		for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
+			if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
+				return idx - band_offset;
+	}
+
+	return -1;
+}
+
+int iwlagn_manage_ibss_station(struct iwl_priv *priv,
+			       struct ieee80211_vif *vif, bool add)
+{
+	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
+	if (add)
+		return iwlagn_add_bssid_station(priv, vif_priv->ctx,
+						vif->bss_conf.bssid,
+						&vif_priv->ibss_bssid_sta_id);
+	return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
+				  vif->bss_conf.bssid);
+}
+
+/**
+ * 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));
+	if (flush_control & BIT(IWL_RXON_CTX_BSS))
+		flush_cmd.fifo_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK |
+				 IWL_SCD_BE_MSK | IWL_SCD_BK_MSK |
+				 IWL_SCD_MGMT_MSK;
+	if ((flush_control & BIT(IWL_RXON_CTX_PAN)) &&
+	    (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)))
+		flush_cmd.fifo_control |= IWL_PAN_SCD_VO_MSK |
+				IWL_PAN_SCD_VI_MSK | IWL_PAN_SCD_BE_MSK |
+				IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK |
+				IWL_PAN_SCD_MULTICAST_MSK;
+
+	if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE)
+		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_dvm_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 (iwlagn_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");
+	iwl_trans_wait_tx_queue_empty(priv->trans);
+done:
+	ieee80211_wake_queues(priv->hw);
+	mutex_unlock(&priv->mutex);
+}
+
+/*
+ * BT coex
+ */
+/* Notmal TDM */
+static const __le32 iwlagn_def_3w_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xaeaaaaaa),
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xcc00ff28),
+	cpu_to_le32(0x0000aaaa),
+	cpu_to_le32(0xcc00aaaa),
+	cpu_to_le32(0x0000aaaa),
+	cpu_to_le32(0xc0004000),
+	cpu_to_le32(0x00004000),
+	cpu_to_le32(0xf0005000),
+	cpu_to_le32(0xf0005000),
+};
+
+
+/* Loose Coex */
+static const __le32 iwlagn_loose_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xaeaaaaaa),
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xcc00ff28),
+	cpu_to_le32(0x0000aaaa),
+	cpu_to_le32(0xcc00aaaa),
+	cpu_to_le32(0x0000aaaa),
+	cpu_to_le32(0x00000000),
+	cpu_to_le32(0x00000000),
+	cpu_to_le32(0xf0005000),
+	cpu_to_le32(0xf0005000),
+};
+
+/* Full concurrency */
+static const __le32 iwlagn_concurrent_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0xaaaaaaaa),
+	cpu_to_le32(0x00000000),
+	cpu_to_le32(0x00000000),
+	cpu_to_le32(0x00000000),
+	cpu_to_le32(0x00000000),
+};
+
+void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
+{
+	struct iwl_basic_bt_cmd basic = {
+		.max_kill = IWLAGN_BT_MAX_KILL_DEFAULT,
+		.bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT,
+		.bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT,
+		.bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT,
+	};
+	struct iwl_bt_cmd_v1 bt_cmd_v1;
+	struct iwl_bt_cmd_v2 bt_cmd_v2;
+	int ret;
+
+	BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
+			sizeof(basic.bt3_lookup_table));
+
+	if (priv->cfg->bt_params) {
+		/*
+		 * newer generation of devices (2000 series and newer)
+		 * use the version 2 of the bt command
+		 * we need to make sure sending the host command
+		 * with correct data structure to avoid uCode assert
+		 */
+		if (priv->cfg->bt_params->bt_session_2) {
+			bt_cmd_v2.prio_boost = cpu_to_le32(
+				priv->cfg->bt_params->bt_prio_boost);
+			bt_cmd_v2.tx_prio_boost = 0;
+			bt_cmd_v2.rx_prio_boost = 0;
+		} else {
+			bt_cmd_v1.prio_boost =
+				priv->cfg->bt_params->bt_prio_boost;
+			bt_cmd_v1.tx_prio_boost = 0;
+			bt_cmd_v1.rx_prio_boost = 0;
+		}
+	} else {
+		IWL_ERR(priv, "failed to construct BT Coex Config\n");
+		return;
+	}
+
+	/*
+	 * Possible situations when BT needs to take over for receive,
+	 * at the same time where STA needs to response to AP's frame(s),
+	 * reduce the tx power of the required response frames, by that,
+	 * allow the concurrent BT receive & WiFi transmit
+	 * (BT - ANT A, WiFi -ANT B), without interference to one another
+	 *
+	 * Reduced tx power apply to control frames only (ACK/Back/CTS)
+	 * when indicated by the BT config command
+	 */
+	basic.kill_ack_mask = priv->kill_ack_mask;
+	basic.kill_cts_mask = priv->kill_cts_mask;
+	if (priv->reduced_txpower)
+		basic.reduce_txpower = IWLAGN_BT_REDUCED_TX_PWR;
+	basic.valid = priv->bt_valid;
+
+	/*
+	 * Configure BT coex mode to "no coexistence" when the
+	 * user disabled BT coexistence, we have no interface
+	 * (might be in monitor mode), or the interface is in
+	 * IBSS mode (no proper uCode support for coex then).
+	 */
+	if (!iwlwifi_mod_params.bt_coex_active ||
+	    priv->iw_mode == NL80211_IFTYPE_ADHOC) {
+		basic.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED;
+	} else {
+		basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
+					IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
+
+		if (!priv->bt_enable_pspoll)
+			basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
+		else
+			basic.flags &= ~IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
+
+		if (priv->bt_ch_announce)
+			basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
+		IWL_DEBUG_COEX(priv, "BT coex flag: 0X%x\n", basic.flags);
+	}
+	priv->bt_enable_flag = basic.flags;
+	if (priv->bt_full_concurrent)
+		memcpy(basic.bt3_lookup_table, iwlagn_concurrent_lookup,
+			sizeof(iwlagn_concurrent_lookup));
+	else
+		memcpy(basic.bt3_lookup_table, iwlagn_def_3w_lookup,
+			sizeof(iwlagn_def_3w_lookup));
+
+	IWL_DEBUG_COEX(priv, "BT coex %s in %s mode\n",
+		       basic.flags ? "active" : "disabled",
+		       priv->bt_full_concurrent ?
+		       "full concurrency" : "3-wire");
+
+	if (priv->cfg->bt_params->bt_session_2) {
+		memcpy(&bt_cmd_v2.basic, &basic,
+			sizeof(basic));
+		ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+			CMD_SYNC, sizeof(bt_cmd_v2), &bt_cmd_v2);
+	} else {
+		memcpy(&bt_cmd_v1.basic, &basic,
+			sizeof(basic));
+		ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+			CMD_SYNC, sizeof(bt_cmd_v1), &bt_cmd_v1);
+	}
+	if (ret)
+		IWL_ERR(priv, "failed to send BT Coex Config\n");
+
+}
+
+void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena)
+{
+	struct iwl_rxon_context *ctx, *found_ctx = NULL;
+	bool found_ap = false;
+
+	lockdep_assert_held(&priv->mutex);
+
+	/* Check whether AP or GO mode is active. */
+	if (rssi_ena) {
+		for_each_context(priv, ctx) {
+			if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_AP &&
+			    iwl_is_associated_ctx(ctx)) {
+				found_ap = true;
+				break;
+			}
+		}
+	}
+
+	/*
+	 * If disable was received or If GO/AP mode, disable RSSI
+	 * measurements.
+	 */
+	if (!rssi_ena || found_ap) {
+		if (priv->cur_rssi_ctx) {
+			ctx = priv->cur_rssi_ctx;
+			ieee80211_disable_rssi_reports(ctx->vif);
+			priv->cur_rssi_ctx = NULL;
+		}
+		return;
+	}
+
+	/*
+	 * If rssi measurements need to be enabled, consider all cases now.
+	 * Figure out how many contexts are active.
+	 */
+	for_each_context(priv, ctx) {
+		if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
+		    iwl_is_associated_ctx(ctx)) {
+			found_ctx = ctx;
+			break;
+		}
+	}
+
+	/*
+	 * rssi monitor already enabled for the correct interface...nothing
+	 * to do.
+	 */
+	if (found_ctx == priv->cur_rssi_ctx)
+		return;
+
+	/*
+	 * Figure out if rssi monitor is currently enabled, and needs
+	 * to be changed. If rssi monitor is already enabled, disable
+	 * it first else just enable rssi measurements on the
+	 * interface found above.
+	 */
+	if (priv->cur_rssi_ctx) {
+		ctx = priv->cur_rssi_ctx;
+		if (ctx->vif)
+			ieee80211_disable_rssi_reports(ctx->vif);
+	}
+
+	priv->cur_rssi_ctx = found_ctx;
+
+	if (!found_ctx)
+		return;
+
+	ieee80211_enable_rssi_reports(found_ctx->vif,
+			IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD,
+			IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD);
+}
+
+static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
+{
+	return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >>
+			BT_UART_MSG_FRAME3SCOESCO_POS;
+}
+
+static void iwlagn_bt_traffic_change_work(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+		container_of(work, struct iwl_priv, bt_traffic_change_work);
+	struct iwl_rxon_context *ctx;
+	int smps_request = -1;
+
+	if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
+		/* bt coex disabled */
+		return;
+	}
+
+	/*
+	 * Note: bt_traffic_load can be overridden by scan complete and
+	 * coex profile notifications. Ignore that since only bad consequence
+	 * can be not matching debug print with actual state.
+	 */
+	IWL_DEBUG_COEX(priv, "BT traffic load changes: %d\n",
+		       priv->bt_traffic_load);
+
+	switch (priv->bt_traffic_load) {
+	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+		if (priv->bt_status)
+			smps_request = IEEE80211_SMPS_DYNAMIC;
+		else
+			smps_request = IEEE80211_SMPS_AUTOMATIC;
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+		smps_request = IEEE80211_SMPS_DYNAMIC;
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+		smps_request = IEEE80211_SMPS_STATIC;
+		break;
+	default:
+		IWL_ERR(priv, "Invalid BT traffic load: %d\n",
+			priv->bt_traffic_load);
+		break;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	/*
+	 * We can not send command to firmware while scanning. When the scan
+	 * complete we will schedule this work again. We do check with mutex
+	 * locked to prevent new scan request to arrive. We do not check
+	 * STATUS_SCANNING to avoid race when queue_work two times from
+	 * different notifications, but quit and not perform any work at all.
+	 */
+	if (test_bit(STATUS_SCAN_HW, &priv->status))
+		goto out;
+
+	iwl_update_chain_flags(priv);
+
+	if (smps_request != -1) {
+		priv->current_ht_config.smps = smps_request;
+		for_each_context(priv, ctx) {
+			if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION)
+				ieee80211_request_smps(ctx->vif, smps_request);
+		}
+	}
+
+	/*
+	 * Dynamic PS poll related functionality. Adjust RSSI measurements if
+	 * necessary.
+	 */
+	iwlagn_bt_coex_rssi_monitor(priv);
+out:
+	mutex_unlock(&priv->mutex);
+}
+
+/*
+ * If BT sco traffic, and RSSI monitor is enabled, move measurements to the
+ * correct interface or disable it if this is the last interface to be
+ * removed.
+ */
+void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv)
+{
+	if (priv->bt_is_sco &&
+	    priv->bt_traffic_load == IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS)
+		iwlagn_bt_adjust_rssi_monitor(priv, true);
+	else
+		iwlagn_bt_adjust_rssi_monitor(priv, false);
+}
+
+static void iwlagn_print_uartmsg(struct iwl_priv *priv,
+				struct iwl_bt_uart_msg *uart_msg)
+{
+	IWL_DEBUG_COEX(priv, "Message Type = 0x%X, SSN = 0x%X, "
+			"Update Req = 0x%X\n",
+		(BT_UART_MSG_FRAME1MSGTYPE_MSK & uart_msg->frame1) >>
+			BT_UART_MSG_FRAME1MSGTYPE_POS,
+		(BT_UART_MSG_FRAME1SSN_MSK & uart_msg->frame1) >>
+			BT_UART_MSG_FRAME1SSN_POS,
+		(BT_UART_MSG_FRAME1UPDATEREQ_MSK & uart_msg->frame1) >>
+			BT_UART_MSG_FRAME1UPDATEREQ_POS);
+
+	IWL_DEBUG_COEX(priv, "Open connections = 0x%X, Traffic load = 0x%X, "
+			"Chl_SeqN = 0x%X, In band = 0x%X\n",
+		(BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK & uart_msg->frame2) >>
+			BT_UART_MSG_FRAME2OPENCONNECTIONS_POS,
+		(BT_UART_MSG_FRAME2TRAFFICLOAD_MSK & uart_msg->frame2) >>
+			BT_UART_MSG_FRAME2TRAFFICLOAD_POS,
+		(BT_UART_MSG_FRAME2CHLSEQN_MSK & uart_msg->frame2) >>
+			BT_UART_MSG_FRAME2CHLSEQN_POS,
+		(BT_UART_MSG_FRAME2INBAND_MSK & uart_msg->frame2) >>
+			BT_UART_MSG_FRAME2INBAND_POS);
+
+	IWL_DEBUG_COEX(priv, "SCO/eSCO = 0x%X, Sniff = 0x%X, A2DP = 0x%X, "
+			"ACL = 0x%X, Master = 0x%X, OBEX = 0x%X\n",
+		(BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
+			BT_UART_MSG_FRAME3SCOESCO_POS,
+		(BT_UART_MSG_FRAME3SNIFF_MSK & uart_msg->frame3) >>
+			BT_UART_MSG_FRAME3SNIFF_POS,
+		(BT_UART_MSG_FRAME3A2DP_MSK & uart_msg->frame3) >>
+			BT_UART_MSG_FRAME3A2DP_POS,
+		(BT_UART_MSG_FRAME3ACL_MSK & uart_msg->frame3) >>
+			BT_UART_MSG_FRAME3ACL_POS,
+		(BT_UART_MSG_FRAME3MASTER_MSK & uart_msg->frame3) >>
+			BT_UART_MSG_FRAME3MASTER_POS,
+		(BT_UART_MSG_FRAME3OBEX_MSK & uart_msg->frame3) >>
+			BT_UART_MSG_FRAME3OBEX_POS);
+
+	IWL_DEBUG_COEX(priv, "Idle duration = 0x%X\n",
+		(BT_UART_MSG_FRAME4IDLEDURATION_MSK & uart_msg->frame4) >>
+			BT_UART_MSG_FRAME4IDLEDURATION_POS);
+
+	IWL_DEBUG_COEX(priv, "Tx Activity = 0x%X, Rx Activity = 0x%X, "
+			"eSCO Retransmissions = 0x%X\n",
+		(BT_UART_MSG_FRAME5TXACTIVITY_MSK & uart_msg->frame5) >>
+			BT_UART_MSG_FRAME5TXACTIVITY_POS,
+		(BT_UART_MSG_FRAME5RXACTIVITY_MSK & uart_msg->frame5) >>
+			BT_UART_MSG_FRAME5RXACTIVITY_POS,
+		(BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK & uart_msg->frame5) >>
+			BT_UART_MSG_FRAME5ESCORETRANSMIT_POS);
+
+	IWL_DEBUG_COEX(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X\n",
+		(BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK & uart_msg->frame6) >>
+			BT_UART_MSG_FRAME6SNIFFINTERVAL_POS,
+		(BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >>
+			BT_UART_MSG_FRAME6DISCOVERABLE_POS);
+
+	IWL_DEBUG_COEX(priv, "Sniff Activity = 0x%X, Page = "
+			"0x%X, Inquiry = 0x%X, Connectable = 0x%X\n",
+		(BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >>
+			BT_UART_MSG_FRAME7SNIFFACTIVITY_POS,
+		(BT_UART_MSG_FRAME7PAGE_MSK & uart_msg->frame7) >>
+			BT_UART_MSG_FRAME7PAGE_POS,
+		(BT_UART_MSG_FRAME7INQUIRY_MSK & uart_msg->frame7) >>
+			BT_UART_MSG_FRAME7INQUIRY_POS,
+		(BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >>
+			BT_UART_MSG_FRAME7CONNECTABLE_POS);
+}
+
+static bool iwlagn_set_kill_msk(struct iwl_priv *priv,
+				struct iwl_bt_uart_msg *uart_msg)
+{
+	bool need_update = false;
+	u8 kill_msk = IWL_BT_KILL_REDUCE;
+	static const __le32 bt_kill_ack_msg[3] = {
+		IWLAGN_BT_KILL_ACK_MASK_DEFAULT,
+		IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
+		IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
+	static const __le32 bt_kill_cts_msg[3] = {
+		IWLAGN_BT_KILL_CTS_MASK_DEFAULT,
+		IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
+		IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
+
+	if (!priv->reduced_txpower)
+		kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3)
+			? IWL_BT_KILL_OVERRIDE : IWL_BT_KILL_DEFAULT;
+	if (priv->kill_ack_mask != bt_kill_ack_msg[kill_msk] ||
+	    priv->kill_cts_mask != bt_kill_cts_msg[kill_msk]) {
+		priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK;
+		priv->kill_ack_mask = bt_kill_ack_msg[kill_msk];
+		priv->bt_valid |= IWLAGN_BT_VALID_KILL_CTS_MASK;
+		priv->kill_cts_mask = bt_kill_cts_msg[kill_msk];
+		need_update = true;
+	}
+	return need_update;
+}
+
+/*
+ * Upon RSSI changes, sends a bt config command with following changes
+ *  1. enable/disable "reduced control frames tx power
+ *  2. update the "kill)ack_mask" and "kill_cts_mask"
+ *
+ * If "reduced tx power" is enabled, uCode shall
+ *  1. ACK/Back/CTS rate shall reduced to 6Mbps
+ *  2. not use duplciate 20/40MHz mode
+ */
+static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
+				struct iwl_bt_uart_msg *uart_msg)
+{
+	bool need_update = false;
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+	int ave_rssi;
+
+	if (!ctx->vif || (ctx->vif->type != NL80211_IFTYPE_STATION)) {
+		IWL_DEBUG_INFO(priv, "BSS ctx not active or not in sta mode\n");
+		return false;
+	}
+
+	ave_rssi = ieee80211_ave_rssi(ctx->vif);
+	if (!ave_rssi) {
+		/* no rssi data, no changes to reduce tx power */
+		IWL_DEBUG_COEX(priv, "no rssi data available\n");
+		return need_update;
+	}
+	if (!priv->reduced_txpower &&
+	    !iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
+	    (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) &&
+	    (uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
+	    BT_UART_MSG_FRAME3OBEX_MSK)) &&
+	    !(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
+	    BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK))) {
+		/* enabling reduced tx power */
+		priv->reduced_txpower = true;
+		priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
+		need_update = true;
+	} else if (priv->reduced_txpower &&
+		   (iwl_is_associated(priv, IWL_RXON_CTX_PAN) ||
+		   (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) ||
+		   (uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
+		   BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK)) ||
+		   !(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
+		   BT_UART_MSG_FRAME3OBEX_MSK)))) {
+		/* disable reduced tx power */
+		priv->reduced_txpower = false;
+		priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
+		need_update = true;
+	}
+
+	return need_update;
+}
+
+int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+				  struct iwl_rx_cmd_buffer *rxb,
+				  struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_bt_coex_profile_notif *coex = (void *)pkt->data;
+	struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg;
+
+	if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
+		/* bt coex disabled */
+		return 0;
+	}
+
+	IWL_DEBUG_COEX(priv, "BT Coex notification:\n");
+	IWL_DEBUG_COEX(priv, "    status: %d\n", coex->bt_status);
+	IWL_DEBUG_COEX(priv, "    traffic load: %d\n", coex->bt_traffic_load);
+	IWL_DEBUG_COEX(priv, "    CI compliance: %d\n",
+			coex->bt_ci_compliance);
+	iwlagn_print_uartmsg(priv, uart_msg);
+
+	priv->last_bt_traffic_load = priv->bt_traffic_load;
+	priv->bt_is_sco = iwlagn_bt_traffic_is_sco(uart_msg);
+
+	if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+		if (priv->bt_status != coex->bt_status ||
+		    priv->last_bt_traffic_load != coex->bt_traffic_load) {
+			if (coex->bt_status) {
+				/* BT on */
+				if (!priv->bt_ch_announce)
+					priv->bt_traffic_load =
+						IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+				else
+					priv->bt_traffic_load =
+						coex->bt_traffic_load;
+			} else {
+				/* BT off */
+				priv->bt_traffic_load =
+					IWL_BT_COEX_TRAFFIC_LOAD_NONE;
+			}
+			priv->bt_status = coex->bt_status;
+			queue_work(priv->workqueue,
+				   &priv->bt_traffic_change_work);
+		}
+	}
+
+	/* schedule to send runtime bt_config */
+	/* check reduce power before change ack/cts kill mask */
+	if (iwlagn_fill_txpower_mode(priv, uart_msg) ||
+	    iwlagn_set_kill_msk(priv, uart_msg))
+		queue_work(priv->workqueue, &priv->bt_runtime_config);
+
+
+	/* FIXME: based on notification, adjust the prio_boost */
+
+	priv->bt_ci_compliance = coex->bt_ci_compliance;
+	return 0;
+}
+
+void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv)
+{
+	priv->rx_handlers[REPLY_BT_COEX_PROFILE_NOTIF] =
+		iwlagn_bt_coex_profile_notif;
+}
+
+void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv)
+{
+	INIT_WORK(&priv->bt_traffic_change_work,
+		  iwlagn_bt_traffic_change_work);
+}
+
+void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv)
+{
+	cancel_work_sync(&priv->bt_traffic_change_work);
+}
+
+static bool is_single_rx_stream(struct iwl_priv *priv)
+{
+	return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
+	       priv->current_ht_config.single_chain_sufficient;
+}
+
+#define IWL_NUM_RX_CHAINS_MULTIPLE	3
+#define IWL_NUM_RX_CHAINS_SINGLE	2
+#define IWL_NUM_IDLE_CHAINS_DUAL	2
+#define IWL_NUM_IDLE_CHAINS_SINGLE	1
+
+/*
+ * Determine how many receiver/antenna chains to use.
+ *
+ * More provides better reception via diversity.  Fewer saves power
+ * at the expense of throughput, but only when not in powersave to
+ * start with.
+ *
+ * MIMO (dual stream) requires at least 2, but works better with 3.
+ * This does not determine *which* chains to use, just how many.
+ */
+static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
+{
+	if (priv->cfg->bt_params &&
+	    priv->cfg->bt_params->advanced_bt_coexist &&
+	    (priv->bt_full_concurrent ||
+	     priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
+		/*
+		 * only use chain 'A' in bt high traffic load or
+		 * full concurrency mode
+		 */
+		return IWL_NUM_RX_CHAINS_SINGLE;
+	}
+	/* # of Rx chains to use when expecting MIMO. */
+	if (is_single_rx_stream(priv))
+		return IWL_NUM_RX_CHAINS_SINGLE;
+	else
+		return IWL_NUM_RX_CHAINS_MULTIPLE;
+}
+
+/*
+ * When we are in power saving mode, unless device support spatial
+ * multiplexing power save, use the active count for rx chain count.
+ */
+static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
+{
+	/* # Rx chains when idling, depending on SMPS mode */
+	switch (priv->current_ht_config.smps) {
+	case IEEE80211_SMPS_STATIC:
+	case IEEE80211_SMPS_DYNAMIC:
+		return IWL_NUM_IDLE_CHAINS_SINGLE;
+	case IEEE80211_SMPS_AUTOMATIC:
+	case IEEE80211_SMPS_OFF:
+		return active_cnt;
+	default:
+		WARN(1, "invalid SMPS mode %d",
+		     priv->current_ht_config.smps);
+		return active_cnt;
+	}
+}
+
+/* up to 4 chains */
+static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
+{
+	u8 res;
+	res = (chain_bitmap & BIT(0)) >> 0;
+	res += (chain_bitmap & BIT(1)) >> 1;
+	res += (chain_bitmap & BIT(2)) >> 2;
+	res += (chain_bitmap & BIT(3)) >> 3;
+	return res;
+}
+
+/**
+ * iwlagn_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
+ *
+ * Selects how many and which Rx receivers/antennas/chains to use.
+ * This should not be used for scan command ... it puts data in wrong place.
+ */
+void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+	bool is_single = is_single_rx_stream(priv);
+	bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
+	u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt;
+	u32 active_chains;
+	u16 rx_chain;
+
+	/* Tell uCode which antennas are actually connected.
+	 * Before first association, we assume all antennas are connected.
+	 * Just after first association, iwl_chain_noise_calibration()
+	 *    checks which antennas actually *are* connected. */
+	if (priv->chain_noise_data.active_chains)
+		active_chains = priv->chain_noise_data.active_chains;
+	else
+		active_chains = priv->eeprom_data->valid_rx_ant;
+
+	if (priv->cfg->bt_params &&
+	    priv->cfg->bt_params->advanced_bt_coexist &&
+	    (priv->bt_full_concurrent ||
+	     priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
+		/*
+		 * only use chain 'A' in bt high traffic load or
+		 * full concurrency mode
+		 */
+		active_chains = first_antenna(active_chains);
+	}
+
+	rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
+
+	/* How many receivers should we use? */
+	active_rx_cnt = iwl_get_active_rx_chain_count(priv);
+	idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
+
+
+	/* correct rx chain count according hw settings
+	 * and chain noise calibration
+	 */
+	valid_rx_cnt = iwl_count_chain_bitmap(active_chains);
+	if (valid_rx_cnt < active_rx_cnt)
+		active_rx_cnt = valid_rx_cnt;
+
+	if (valid_rx_cnt < idle_rx_cnt)
+		idle_rx_cnt = valid_rx_cnt;
+
+	rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
+	rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
+
+	ctx->staging.rx_chain = cpu_to_le16(rx_chain);
+
+	if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
+		ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
+	else
+		ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
+
+	IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n",
+			ctx->staging.rx_chain,
+			active_rx_cnt, idle_rx_cnt);
+
+	WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
+		active_rx_cnt < idle_rx_cnt);
+}
+
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
+{
+	int i;
+	u8 ind = ant;
+
+	if (priv->band == IEEE80211_BAND_2GHZ &&
+	    priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
+		return 0;
+
+	for (i = 0; i < RATE_ANT_NUM - 1; i++) {
+		ind = (ind + 1) < RATE_ANT_NUM ?  ind + 1 : 0;
+		if (valid & BIT(ind))
+			return ind;
+	}
+	return ant;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
+{
+	int i;
+
+	for (i = 0; i < IWLAGN_P1K_SIZE; i++)
+		out[i] = cpu_to_le16(p1k[i]);
+}
+
+struct wowlan_key_data {
+	struct iwl_rxon_context *ctx;
+	struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
+	struct iwlagn_wowlan_tkip_params_cmd *tkip;
+	const u8 *bssid;
+	bool error, use_rsc_tsc, use_tkip;
+};
+
+
+static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
+			       struct ieee80211_sta *sta,
+			       struct ieee80211_key_conf *key,
+			       void *_data)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct wowlan_key_data *data = _data;
+	struct iwl_rxon_context *ctx = data->ctx;
+	struct aes_sc *aes_sc, *aes_tx_sc = NULL;
+	struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
+	struct iwlagn_p1k_cache *rx_p1ks;
+	u8 *rx_mic_key;
+	struct ieee80211_key_seq seq;
+	u32 cur_rx_iv32 = 0;
+	u16 p1k[IWLAGN_P1K_SIZE];
+	int ret, i;
+
+	mutex_lock(&priv->mutex);
+
+	if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+	     key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+	     !sta && !ctx->key_mapping_keys)
+		ret = iwl_set_default_wep_key(priv, ctx, key);
+	else
+		ret = iwl_set_dynamic_key(priv, ctx, key, sta);
+
+	if (ret) {
+		IWL_ERR(priv, "Error setting key during suspend!\n");
+		data->error = true;
+	}
+
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_TKIP:
+		if (sta) {
+			tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
+			tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
+
+			rx_p1ks = data->tkip->rx_uni;
+
+			ieee80211_get_key_tx_seq(key, &seq);
+			tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
+			tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+
+			ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
+			iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
+
+			memcpy(data->tkip->mic_keys.tx,
+			       &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
+			       IWLAGN_MIC_KEY_SIZE);
+
+			rx_mic_key = data->tkip->mic_keys.rx_unicast;
+		} else {
+			tkip_sc =
+				data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
+			rx_p1ks = data->tkip->rx_multi;
+			rx_mic_key = data->tkip->mic_keys.rx_mcast;
+		}
+
+		/*
+		 * For non-QoS this relies on the fact that both the uCode and
+		 * mac80211 use TID 0 (as they need to to avoid replay attacks)
+		 * for checking the IV in the frames.
+		 */
+		for (i = 0; i < IWLAGN_NUM_RSC; i++) {
+			ieee80211_get_key_rx_seq(key, i, &seq);
+			tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
+			tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
+			/* wrapping isn't allowed, AP must rekey */
+			if (seq.tkip.iv32 > cur_rx_iv32)
+				cur_rx_iv32 = seq.tkip.iv32;
+		}
+
+		ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
+		iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
+		ieee80211_get_tkip_rx_p1k(key, data->bssid,
+					  cur_rx_iv32 + 1, p1k);
+		iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
+
+		memcpy(rx_mic_key,
+		       &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
+		       IWLAGN_MIC_KEY_SIZE);
+
+		data->use_tkip = true;
+		data->use_rsc_tsc = true;
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		if (sta) {
+			u8 *pn = seq.ccmp.pn;
+
+			aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
+			aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
+
+			ieee80211_get_key_tx_seq(key, &seq);
+			aes_tx_sc->pn = cpu_to_le64(
+					(u64)pn[5] |
+					((u64)pn[4] << 8) |
+					((u64)pn[3] << 16) |
+					((u64)pn[2] << 24) |
+					((u64)pn[1] << 32) |
+					((u64)pn[0] << 40));
+		} else
+			aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
+
+		/*
+		 * For non-QoS this relies on the fact that both the uCode and
+		 * mac80211 use TID 0 for checking the IV in the frames.
+		 */
+		for (i = 0; i < IWLAGN_NUM_RSC; i++) {
+			u8 *pn = seq.ccmp.pn;
+
+			ieee80211_get_key_rx_seq(key, i, &seq);
+			aes_sc->pn = cpu_to_le64(
+					(u64)pn[5] |
+					((u64)pn[4] << 8) |
+					((u64)pn[3] << 16) |
+					((u64)pn[2] << 24) |
+					((u64)pn[1] << 32) |
+					((u64)pn[0] << 40));
+		}
+		data->use_rsc_tsc = true;
+		break;
+	}
+
+	mutex_unlock(&priv->mutex);
+}
+
+int iwlagn_send_patterns(struct iwl_priv *priv,
+			struct cfg80211_wowlan *wowlan)
+{
+	struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_WOWLAN_PATTERNS,
+		.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+		.flags = CMD_SYNC,
+	};
+	int i, err;
+
+	if (!wowlan->n_patterns)
+		return 0;
+
+	cmd.len[0] = sizeof(*pattern_cmd) +
+		wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
+
+	pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
+	if (!pattern_cmd)
+		return -ENOMEM;
+
+	pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+
+	for (i = 0; i < wowlan->n_patterns; i++) {
+		int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
+
+		memcpy(&pattern_cmd->patterns[i].mask,
+			wowlan->patterns[i].mask, mask_len);
+		memcpy(&pattern_cmd->patterns[i].pattern,
+			wowlan->patterns[i].pattern,
+			wowlan->patterns[i].pattern_len);
+		pattern_cmd->patterns[i].mask_size = mask_len;
+		pattern_cmd->patterns[i].pattern_size =
+			wowlan->patterns[i].pattern_len;
+	}
+
+	cmd.data[0] = pattern_cmd;
+	err = iwl_dvm_send_cmd(priv, &cmd);
+	kfree(pattern_cmd);
+	return err;
+}
+
+int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
+{
+	struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
+	struct iwl_rxon_cmd rxon;
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+	struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
+	struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
+	struct iwlagn_d3_config_cmd d3_cfg_cmd = {};
+	struct wowlan_key_data key_data = {
+		.ctx = ctx,
+		.bssid = ctx->active.bssid_addr,
+		.use_rsc_tsc = false,
+		.tkip = &tkip_cmd,
+		.use_tkip = false,
+	};
+	int ret, i;
+	u16 seq;
+
+	key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
+	if (!key_data.rsc_tsc)
+		return -ENOMEM;
+
+	memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
+
+	/*
+	 * We know the last used seqno, and the uCode expects to know that
+	 * one, it will increment before TX.
+	 */
+	seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
+	wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
+
+	/*
+	 * For QoS counters, we store the one to use next, so subtract 0x10
+	 * since the uCode will add 0x10 before using the value.
+	 */
+	for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+		seq = priv->tid_data[IWL_AP_ID][i].seq_number;
+		seq -= 0x10;
+		wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
+	}
+
+	if (wowlan->disconnect)
+		wakeup_filter_cmd.enabled |=
+			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
+				    IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
+	if (wowlan->magic_pkt)
+		wakeup_filter_cmd.enabled |=
+			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
+	if (wowlan->gtk_rekey_failure)
+		wakeup_filter_cmd.enabled |=
+			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
+	if (wowlan->eap_identity_req)
+		wakeup_filter_cmd.enabled |=
+			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
+	if (wowlan->four_way_handshake)
+		wakeup_filter_cmd.enabled |=
+			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
+	if (wowlan->n_patterns)
+		wakeup_filter_cmd.enabled |=
+			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
+
+	if (wowlan->rfkill_release)
+		d3_cfg_cmd.wakeup_flags |=
+			cpu_to_le32(IWLAGN_D3_WAKEUP_RFKILL);
+
+	iwl_scan_cancel_timeout(priv, 200);
+
+	memcpy(&rxon, &ctx->active, sizeof(rxon));
+
+	priv->ucode_loaded = false;
+	iwl_trans_stop_device(priv->trans);
+
+	priv->wowlan = true;
+
+	ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
+	if (ret)
+		goto out;
+
+	/* now configure WoWLAN ucode */
+	ret = iwl_alive_start(priv);
+	if (ret)
+		goto out;
+
+	memcpy(&ctx->staging, &rxon, sizeof(rxon));
+	ret = iwlagn_commit_rxon(priv, ctx);
+	if (ret)
+		goto out;
+
+	ret = iwl_power_update_mode(priv, true);
+	if (ret)
+		goto out;
+
+	if (!iwlwifi_mod_params.sw_crypto) {
+		/* mark all keys clear */
+		priv->ucode_key_table = 0;
+		ctx->key_mapping_keys = 0;
+
+		/*
+		 * This needs to be unlocked due to lock ordering
+		 * constraints. Since we're in the suspend path
+		 * that isn't really a problem though.
+		 */
+		mutex_unlock(&priv->mutex);
+		ieee80211_iter_keys(priv->hw, ctx->vif,
+				    iwlagn_wowlan_program_keys,
+				    &key_data);
+		mutex_lock(&priv->mutex);
+		if (key_data.error) {
+			ret = -EIO;
+			goto out;
+		}
+
+		if (key_data.use_rsc_tsc) {
+			struct iwl_host_cmd rsc_tsc_cmd = {
+				.id = REPLY_WOWLAN_TSC_RSC_PARAMS,
+				.flags = CMD_SYNC,
+				.data[0] = key_data.rsc_tsc,
+				.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+				.len[0] = sizeof(*key_data.rsc_tsc),
+			};
+
+			ret = iwl_dvm_send_cmd(priv, &rsc_tsc_cmd);
+			if (ret)
+				goto out;
+		}
+
+		if (key_data.use_tkip) {
+			ret = iwl_dvm_send_cmd_pdu(priv,
+						 REPLY_WOWLAN_TKIP_PARAMS,
+						 CMD_SYNC, sizeof(tkip_cmd),
+						 &tkip_cmd);
+			if (ret)
+				goto out;
+		}
+
+		if (priv->have_rekey_data) {
+			memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
+			memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
+			kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
+			memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
+			kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
+			kek_kck_cmd.replay_ctr = priv->replay_ctr;
+
+			ret = iwl_dvm_send_cmd_pdu(priv,
+						 REPLY_WOWLAN_KEK_KCK_MATERIAL,
+						 CMD_SYNC, sizeof(kek_kck_cmd),
+						 &kek_kck_cmd);
+			if (ret)
+				goto out;
+		}
+	}
+
+	ret = iwl_dvm_send_cmd_pdu(priv, REPLY_D3_CONFIG, CMD_SYNC,
+				     sizeof(d3_cfg_cmd), &d3_cfg_cmd);
+	if (ret)
+		goto out;
+
+	ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_WAKEUP_FILTER,
+				 CMD_SYNC, sizeof(wakeup_filter_cmd),
+				 &wakeup_filter_cmd);
+	if (ret)
+		goto out;
+
+	ret = iwlagn_send_patterns(priv, wowlan);
+ out:
+	kfree(key_data.rsc_tsc);
+	return ret;
+}
+#endif
+
+int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+	if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
+		IWL_WARN(priv, "Not sending command - %s KILL\n",
+			 iwl_is_rfkill(priv) ? "RF" : "CT");
+		return -EIO;
+	}
+
+	if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+		IWL_ERR(priv, "Command %s failed: FW Error\n",
+			iwl_dvm_get_cmd_string(cmd->id));
+		return -EIO;
+	}
+
+	/*
+	 * Synchronous commands from this op-mode must hold
+	 * the mutex, this ensures we don't try to send two
+	 * (or more) synchronous commands at a time.
+	 */
+	if (!(cmd->flags & CMD_ASYNC))
+		lockdep_assert_held(&priv->mutex);
+
+	if (priv->ucode_owner == IWL_OWNERSHIP_TM &&
+	    !(cmd->flags & CMD_ON_DEMAND)) {
+		IWL_DEBUG_HC(priv, "tm own the uCode, no regular hcmd send\n");
+		return -EIO;
+	}
+
+	return iwl_trans_send_cmd(priv->trans, cmd);
+}
+
+int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
+			 u32 flags, u16 len, const void *data)
+{
+	struct iwl_host_cmd cmd = {
+		.id = id,
+		.len = { len, },
+		.data = { data, },
+		.flags = flags,
+	};
+
+	return iwl_dvm_send_cmd(priv, &cmd);
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
new file mode 100644
index 0000000..a5f7bce
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -0,0 +1,1652 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee80211_radiotap.h>
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#include "iwl-io.h"
+#include "iwl-trans.h"
+#include "iwl-op-mode.h"
+#include "iwl-modparams.h"
+
+#include "dev.h"
+#include "calib.h"
+#include "agn.h"
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_STATION),
+	},
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_AP),
+	},
+};
+
+static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
+	{
+		.max = 2,
+		.types = BIT(NL80211_IFTYPE_STATION),
+	},
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_STATION),
+	},
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_P2P_GO) |
+			 BIT(NL80211_IFTYPE_AP),
+	},
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
+	{
+		.max = 2,
+		.types = BIT(NL80211_IFTYPE_STATION),
+	},
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_P2P_CLIENT),
+	},
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_dualmode[] = {
+	{ .num_different_channels = 1,
+	  .max_interfaces = 2,
+	  .beacon_int_infra_match = true,
+	  .limits = iwlagn_sta_ap_limits,
+	  .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
+	},
+	{ .num_different_channels = 1,
+	  .max_interfaces = 2,
+	  .limits = iwlagn_2sta_limits,
+	  .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
+	},
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_p2p[] = {
+	{ .num_different_channels = 1,
+	  .max_interfaces = 2,
+	  .beacon_int_infra_match = true,
+	  .limits = iwlagn_p2p_sta_go_limits,
+	  .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
+	},
+	{ .num_different_channels = 1,
+	  .max_interfaces = 2,
+	  .limits = iwlagn_p2p_2sta_limits,
+	  .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
+	},
+};
+
+/*
+ * Not a mac80211 entry point function, but it fits in with all the
+ * other mac80211 functions grouped here.
+ */
+int iwlagn_mac_setup_register(struct iwl_priv *priv,
+			      const struct iwl_ucode_capabilities *capa)
+{
+	int ret;
+	struct ieee80211_hw *hw = priv->hw;
+	struct iwl_rxon_context *ctx;
+
+	hw->rate_control_algorithm = "iwl-agn-rs";
+
+	/* Tell mac80211 our characteristics */
+	hw->flags = IEEE80211_HW_SIGNAL_DBM |
+		    IEEE80211_HW_AMPDU_AGGREGATION |
+		    IEEE80211_HW_NEED_DTIM_PERIOD |
+		    IEEE80211_HW_SPECTRUM_MGMT |
+		    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+		    IEEE80211_HW_QUEUE_CONTROL |
+		    IEEE80211_HW_SUPPORTS_PS |
+		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
+		    IEEE80211_HW_WANT_MONITOR_VIF |
+		    IEEE80211_HW_SCAN_WHILE_IDLE;
+
+	hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
+	hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
+
+	/*
+	 * Including the following line will crash some AP's.  This
+	 * workaround removes the stimulus which causes the crash until
+	 * the AP software can be fixed.
+	hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+	 */
+
+	if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE)
+		hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+			     IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+
+#ifndef CONFIG_IWLWIFI_EXPERIMENTAL_MFP
+	/* enable 11w if the uCode advertise */
+	if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
+#endif /* !CONFIG_IWLWIFI_EXPERIMENTAL_MFP */
+		hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
+	hw->sta_data_size = sizeof(struct iwl_station_priv);
+	hw->vif_data_size = sizeof(struct iwl_vif_priv);
+
+	for_each_context(priv, ctx) {
+		hw->wiphy->interface_modes |= ctx->interface_modes;
+		hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
+	}
+
+	BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+	if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
+		hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
+		hw->wiphy->n_iface_combinations =
+			ARRAY_SIZE(iwlagn_iface_combinations_p2p);
+	} else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
+		hw->wiphy->iface_combinations =
+			iwlagn_iface_combinations_dualmode;
+		hw->wiphy->n_iface_combinations =
+			ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
+	}
+
+	hw->wiphy->max_remain_on_channel_duration = 1000;
+
+	hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
+			    WIPHY_FLAG_DISABLE_BEACON_HINTS |
+			    WIPHY_FLAG_IBSS_RSN;
+
+#ifdef CONFIG_PM_SLEEP
+	if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
+	    priv->trans->ops->wowlan_suspend &&
+	    device_can_wakeup(priv->trans->dev)) {
+		hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
+					  WIPHY_WOWLAN_DISCONNECT |
+					  WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+					  WIPHY_WOWLAN_RFKILL_RELEASE;
+		if (!iwlwifi_mod_params.sw_crypto)
+			hw->wiphy->wowlan.flags |=
+				WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+				WIPHY_WOWLAN_GTK_REKEY_FAILURE;
+
+		hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
+		hw->wiphy->wowlan.pattern_min_len =
+					IWLAGN_WOWLAN_MIN_PATTERN_LEN;
+		hw->wiphy->wowlan.pattern_max_len =
+					IWLAGN_WOWLAN_MAX_PATTERN_LEN;
+	}
+#endif
+
+	if (iwlwifi_mod_params.power_save)
+		hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+	else
+		hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+	hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+	/* we create the 802.11 header and a max-length SSID element */
+	hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 34;
+
+	/*
+	 * We don't use all queues: 4 and 9 are unused and any
+	 * aggregation queue gets mapped down to the AC queue.
+	 */
+	hw->queues = IWLAGN_FIRST_AMPDU_QUEUE;
+
+	hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+
+	if (priv->eeprom_data->bands[IEEE80211_BAND_2GHZ].n_channels)
+		priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+			&priv->eeprom_data->bands[IEEE80211_BAND_2GHZ];
+	if (priv->eeprom_data->bands[IEEE80211_BAND_5GHZ].n_channels)
+		priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+			&priv->eeprom_data->bands[IEEE80211_BAND_5GHZ];
+
+	hw->wiphy->hw_version = priv->trans->hw_id;
+
+	iwl_leds_init(priv);
+
+	ret = ieee80211_register_hw(priv->hw);
+	if (ret) {
+		IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
+		iwl_leds_exit(priv);
+		return ret;
+	}
+	priv->mac80211_registered = 1;
+
+	return 0;
+}
+
+void iwlagn_mac_unregister(struct iwl_priv *priv)
+{
+	if (!priv->mac80211_registered)
+		return;
+	iwl_leds_exit(priv);
+	ieee80211_unregister_hw(priv->hw);
+	priv->mac80211_registered = 0;
+}
+
+static int __iwl_up(struct iwl_priv *priv)
+{
+	struct iwl_rxon_context *ctx;
+	int ret;
+
+	lockdep_assert_held(&priv->mutex);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
+		return -EIO;
+	}
+
+	for_each_context(priv, ctx) {
+		ret = iwlagn_alloc_bcast_station(priv, ctx);
+		if (ret) {
+			iwl_dealloc_bcast_stations(priv);
+			return ret;
+		}
+	}
+
+	ret = iwl_run_init_ucode(priv);
+	if (ret) {
+		IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
+		goto error;
+	}
+
+	ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
+	if (ret) {
+		IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
+		goto error;
+	}
+
+	ret = iwl_alive_start(priv);
+	if (ret)
+		goto error;
+	return 0;
+
+ error:
+	set_bit(STATUS_EXIT_PENDING, &priv->status);
+	iwl_down(priv);
+	clear_bit(STATUS_EXIT_PENDING, &priv->status);
+
+	IWL_ERR(priv, "Unable to initialize device.\n");
+	return ret;
+}
+
+static int iwlagn_mac_start(struct ieee80211_hw *hw)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	int ret;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	/* we should be verifying the device is ready to be opened */
+	mutex_lock(&priv->mutex);
+	ret = __iwl_up(priv);
+	mutex_unlock(&priv->mutex);
+	if (ret)
+		return ret;
+
+	IWL_DEBUG_INFO(priv, "Start UP work done.\n");
+
+	/* Now we should be done, and the READY bit should be set. */
+	if (WARN_ON(!test_bit(STATUS_READY, &priv->status)))
+		ret = -EIO;
+
+	iwlagn_led_enable(priv);
+
+	priv->is_open = 1;
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+	return 0;
+}
+
+static void iwlagn_mac_stop(struct ieee80211_hw *hw)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	if (!priv->is_open)
+		return;
+
+	priv->is_open = 0;
+
+	mutex_lock(&priv->mutex);
+	iwl_down(priv);
+	mutex_unlock(&priv->mutex);
+
+	iwl_cancel_deferred_work(priv);
+
+	flush_workqueue(priv->workqueue);
+
+	/* User space software may expect getting rfkill changes
+	 * even if interface is down, trans->down will leave the RF
+	 * kill interrupt enabled
+	 */
+	iwl_trans_stop_hw(priv->trans, false);
+
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif,
+				      struct cfg80211_gtk_rekey_data *data)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+	if (iwlwifi_mod_params.sw_crypto)
+		return;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+	mutex_lock(&priv->mutex);
+
+	if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
+		goto out;
+
+	memcpy(priv->kek, data->kek, NL80211_KEK_LEN);
+	memcpy(priv->kck, data->kck, NL80211_KCK_LEN);
+	priv->replay_ctr =
+		cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
+	priv->have_rekey_data = true;
+
+ out:
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
+			      struct cfg80211_wowlan *wowlan)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+	int ret;
+
+	if (WARN_ON(!wowlan))
+		return -EINVAL;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+	mutex_lock(&priv->mutex);
+
+	/* Don't attempt WoWLAN when not associated, tear down instead. */
+	if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
+	    !iwl_is_associated_ctx(ctx)) {
+		ret = 1;
+		goto out;
+	}
+
+	ret = iwlagn_suspend(priv, wowlan);
+	if (ret)
+		goto error;
+
+	iwl_trans_wowlan_suspend(priv->trans);
+
+	goto out;
+
+ error:
+	priv->wowlan = false;
+	iwlagn_prepare_restart(priv);
+	ieee80211_restart_hw(priv->hw);
+ out:
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+
+	return ret;
+}
+
+static int iwlagn_mac_resume(struct ieee80211_hw *hw)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+	struct ieee80211_vif *vif;
+	unsigned long flags;
+	u32 base, status = 0xffffffff;
+	int ret = -EIO;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+	mutex_lock(&priv->mutex);
+
+	iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
+			  CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+	base = priv->device_pointers.error_event_table;
+	if (iwlagn_hw_valid_rtc_data_addr(base)) {
+		spin_lock_irqsave(&priv->trans->reg_lock, flags);
+		ret = iwl_grab_nic_access_silent(priv->trans);
+		if (likely(ret == 0)) {
+			iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
+			status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+			iwl_release_nic_access(priv->trans);
+		}
+		spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+		if (ret == 0) {
+			const struct fw_img *img;
+
+			img = &(priv->fw->img[IWL_UCODE_WOWLAN]);
+			if (!priv->wowlan_sram) {
+				priv->wowlan_sram =
+				   kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
+						GFP_KERNEL);
+			}
+
+			if (priv->wowlan_sram)
+				_iwl_read_targ_mem_dwords(
+				      priv->trans, 0x800000,
+				      priv->wowlan_sram,
+				      img->sec[IWL_UCODE_SECTION_DATA].len / 4);
+		}
+#endif
+	}
+
+	/* we'll clear ctx->vif during iwlagn_prepare_restart() */
+	vif = ctx->vif;
+
+	priv->wowlan = false;
+
+	iwlagn_prepare_restart(priv);
+
+	memset((void *)&ctx->active, 0, sizeof(ctx->active));
+	iwl_connection_init_rx_config(priv, ctx);
+	iwlagn_set_rxon_chain(priv, ctx);
+
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+
+	ieee80211_resume_disconnect(vif);
+
+	return 1;
+}
+
+static void iwlagn_mac_set_wakeup(struct ieee80211_hw *hw, bool enabled)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+	device_set_wakeup_enable(priv->trans->dev, enabled);
+}
+#endif
+
+static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+	IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+		     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
+
+	if (iwlagn_tx_skb(priv, skb))
+		dev_kfree_skb_any(skb);
+}
+
+static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
+				       struct ieee80211_vif *vif,
+				       struct ieee80211_key_conf *keyconf,
+				       struct ieee80211_sta *sta,
+				       u32 iv32, u16 *phase1key)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+	iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
+}
+
+static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			      struct ieee80211_vif *vif,
+			      struct ieee80211_sta *sta,
+			      struct ieee80211_key_conf *key)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+	struct iwl_rxon_context *ctx = vif_priv->ctx;
+	int ret;
+	bool is_default_wep_key = false;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	if (iwlwifi_mod_params.sw_crypto) {
+		IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
+		return -EOPNOTSUPP;
+	}
+
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_TKIP:
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+		/* fall through */
+	case WLAN_CIPHER_SUITE_CCMP:
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * We could program these keys into the hardware as well, but we
+	 * don't expect much multicast traffic in IBSS and having keys
+	 * for more stations is probably more useful.
+	 *
+	 * Mark key TX-only and return 0.
+	 */
+	if (vif->type == NL80211_IFTYPE_ADHOC &&
+	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+		key->hw_key_idx = WEP_INVALID_OFFSET;
+		return 0;
+	}
+
+	/* If they key was TX-only, accept deletion */
+	if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
+		return 0;
+
+	mutex_lock(&priv->mutex);
+	iwl_scan_cancel_timeout(priv, 100);
+
+	BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
+
+	/*
+	 * If we are getting WEP group key and we didn't receive any key mapping
+	 * so far, we are in legacy wep mode (group key only), otherwise we are
+	 * in 1X mode.
+	 * In legacy wep mode, we use another host command to the uCode.
+	 */
+	if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+	     key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
+		if (cmd == SET_KEY)
+			is_default_wep_key = !ctx->key_mapping_keys;
+		else
+			is_default_wep_key =
+				key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
+	}
+
+
+	switch (cmd) {
+	case SET_KEY:
+		if (is_default_wep_key) {
+			ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
+			break;
+		}
+		ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
+		if (ret) {
+			/*
+			 * can't add key for RX, but we don't need it
+			 * in the device for TX so still return 0
+			 */
+			ret = 0;
+			key->hw_key_idx = WEP_INVALID_OFFSET;
+		}
+
+		IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
+		break;
+	case DISABLE_KEY:
+		if (is_default_wep_key)
+			ret = iwl_remove_default_wep_key(priv, ctx, key);
+		else
+			ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
+
+		IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+
+	return ret;
+}
+
+static int iwlagn_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,
+				   u8 buf_size)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	int ret = -EINVAL;
+	struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
+
+	IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
+		     sta->addr, tid);
+
+	if (!(priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE))
+		return -EACCES;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+	mutex_lock(&priv->mutex);
+
+	switch (action) {
+	case IEEE80211_AMPDU_RX_START:
+		if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
+			break;
+		IWL_DEBUG_HT(priv, "start Rx\n");
+		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);
+		break;
+	case IEEE80211_AMPDU_TX_START:
+		if (!priv->trans->ops->txq_enable)
+			break;
+		if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
+			break;
+		IWL_DEBUG_HT(priv, "start Tx\n");
+		ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
+		break;
+	case IEEE80211_AMPDU_TX_STOP:
+		IWL_DEBUG_HT(priv, "stop Tx\n");
+		ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
+		if ((ret == 0) && (priv->agg_tids_count > 0)) {
+			priv->agg_tids_count--;
+			IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
+				     priv->agg_tids_count);
+		}
+		if (!priv->agg_tids_count &&
+		    priv->hw_params.use_rts_for_aggregation) {
+			/*
+			 * switch off RTS/CTS if it was previously enabled
+			 */
+			sta_priv->lq_sta.lq.general_params.flags &=
+				~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+			iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+					&sta_priv->lq_sta.lq, CMD_ASYNC, false);
+		}
+		break;
+	case IEEE80211_AMPDU_TX_OPERATIONAL:
+		ret = iwlagn_tx_agg_oper(priv, vif, sta, tid, buf_size);
+		break;
+	}
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+	return ret;
+}
+
+static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif,
+			      struct ieee80211_sta *sta)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+	bool is_ap = vif->type == NL80211_IFTYPE_STATION;
+	int ret;
+	u8 sta_id;
+
+	IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
+			sta->addr);
+	sta_priv->sta_id = IWL_INVALID_STATION;
+
+	atomic_set(&sta_priv->pending_frames, 0);
+	if (vif->type == NL80211_IFTYPE_AP)
+		sta_priv->client = true;
+
+	ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
+				     is_ap, sta, &sta_id);
+	if (ret) {
+		IWL_ERR(priv, "Unable to add station %pM (%d)\n",
+			sta->addr, ret);
+		/* Should we return success if return code is EEXIST ? */
+		return ret;
+	}
+
+	sta_priv->sta_id = sta_id;
+
+	return 0;
+}
+
+static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
+				 struct ieee80211_vif *vif,
+				 struct ieee80211_sta *sta)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+	int ret;
+
+	IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", sta->addr);
+
+	if (vif->type == NL80211_IFTYPE_STATION) {
+		/*
+		 * Station will be removed from device when the RXON
+		 * is set to unassociated -- just deactivate it here
+		 * to avoid re-programming it.
+		 */
+		ret = 0;
+		iwl_deactivate_station(priv, sta_priv->sta_id, sta->addr);
+	} else {
+		ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
+		if (ret)
+			IWL_DEBUG_QUIET_RFKILL(priv,
+				"Error removing station %pM\n", sta->addr);
+	}
+	return ret;
+}
+
+static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
+				struct ieee80211_vif *vif,
+				struct ieee80211_sta *sta,
+				enum ieee80211_sta_state old_state,
+				enum ieee80211_sta_state new_state)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+	enum {
+		NONE, ADD, REMOVE, HT_RATE_INIT, ADD_RATE_INIT,
+	} op = NONE;
+	int ret;
+
+	IWL_DEBUG_MAC80211(priv, "station %pM state change %d->%d\n",
+			   sta->addr, old_state, new_state);
+
+	mutex_lock(&priv->mutex);
+	if (vif->type == NL80211_IFTYPE_STATION) {
+		if (old_state == IEEE80211_STA_NOTEXIST &&
+		    new_state == IEEE80211_STA_NONE)
+			op = ADD;
+		else if (old_state == IEEE80211_STA_NONE &&
+			 new_state == IEEE80211_STA_NOTEXIST)
+			op = REMOVE;
+		else if (old_state == IEEE80211_STA_AUTH &&
+			 new_state == IEEE80211_STA_ASSOC)
+			op = HT_RATE_INIT;
+	} else {
+		if (old_state == IEEE80211_STA_AUTH &&
+		    new_state == IEEE80211_STA_ASSOC)
+			op = ADD_RATE_INIT;
+		else if (old_state == IEEE80211_STA_ASSOC &&
+			 new_state == IEEE80211_STA_AUTH)
+			op = REMOVE;
+	}
+
+	switch (op) {
+	case ADD:
+		ret = iwlagn_mac_sta_add(hw, vif, sta);
+		if (ret)
+			break;
+		/*
+		 * Clear the in-progress flag, the AP station entry was added
+		 * but we'll initialize LQ only when we've associated (which
+		 * would also clear the in-progress flag). This is necessary
+		 * in case we never initialize LQ because association fails.
+		 */
+		spin_lock_bh(&priv->sta_lock);
+		priv->stations[iwl_sta_id(sta)].used &=
+			~IWL_STA_UCODE_INPROGRESS;
+		spin_unlock_bh(&priv->sta_lock);
+		break;
+	case REMOVE:
+		ret = iwlagn_mac_sta_remove(hw, vif, sta);
+		break;
+	case ADD_RATE_INIT:
+		ret = iwlagn_mac_sta_add(hw, vif, sta);
+		if (ret)
+			break;
+		/* Initialize rate scaling */
+		IWL_DEBUG_INFO(priv,
+			       "Initializing rate scaling for station %pM\n",
+			       sta->addr);
+		iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
+		ret = 0;
+		break;
+	case HT_RATE_INIT:
+		/* Initialize rate scaling */
+		ret = iwl_sta_update_ht(priv, vif_priv->ctx, sta);
+		if (ret)
+			break;
+		IWL_DEBUG_INFO(priv,
+			       "Initializing rate scaling for station %pM\n",
+			       sta->addr);
+		iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
+		ret = 0;
+		break;
+	default:
+		ret = 0;
+		break;
+	}
+
+	/*
+	 * mac80211 might WARN if we fail, but due the way we
+	 * (badly) handle hard rfkill, we might fail here
+	 */
+	if (iwl_is_rfkill(priv))
+		ret = 0;
+
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+
+	return ret;
+}
+
+static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+				      struct ieee80211_channel_switch *ch_switch)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct ieee80211_conf *conf = &hw->conf;
+	struct ieee80211_channel *channel = ch_switch->channel;
+	struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+	/*
+	 * MULTI-FIXME
+	 * When we add support for multiple interfaces, we need to
+	 * revisit this. The channel switch command in the device
+	 * only affects the BSS context, but what does that really
+	 * mean? And what if we get a CSA on the second interface?
+	 * This needs a lot of work.
+	 */
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+	u16 ch;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	mutex_lock(&priv->mutex);
+
+	if (iwl_is_rfkill(priv))
+		goto out;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+	    test_bit(STATUS_SCANNING, &priv->status) ||
+	    test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+		goto out;
+
+	if (!iwl_is_associated_ctx(ctx))
+		goto out;
+
+	if (!priv->lib->set_channel_switch)
+		goto out;
+
+	ch = channel->hw_value;
+	if (le16_to_cpu(ctx->active.channel) == ch)
+		goto out;
+
+	priv->current_ht_config.smps = conf->smps_mode;
+
+	/* Configure HT40 channels */
+	ctx->ht.enabled = conf_is_ht(conf);
+	if (ctx->ht.enabled)
+		iwlagn_config_ht40(conf, ctx);
+	else
+		ctx->ht.is_40mhz = false;
+
+	if ((le16_to_cpu(ctx->staging.channel) != ch))
+		ctx->staging.flags = 0;
+
+	iwl_set_rxon_channel(priv, channel, ctx);
+	iwl_set_rxon_ht(priv, ht_conf);
+	iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
+
+	/*
+	 * at this point, staging_rxon has the
+	 * configuration for channel switch
+	 */
+	set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
+	priv->switch_channel = cpu_to_le16(ch);
+	if (priv->lib->set_channel_switch(priv, ch_switch)) {
+		clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
+		priv->switch_channel = 0;
+		ieee80211_chswitch_done(ctx->vif, false);
+	}
+
+out:
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
+{
+	/*
+	 * MULTI-FIXME
+	 * See iwlagn_mac_channel_switch.
+	 */
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+		ieee80211_chswitch_done(ctx->vif, is_success);
+}
+
+static void iwlagn_configure_filter(struct ieee80211_hw *hw,
+				    unsigned int changed_flags,
+				    unsigned int *total_flags,
+				    u64 multicast)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	__le32 filter_or = 0, filter_nand = 0;
+	struct iwl_rxon_context *ctx;
+
+#define CHK(test, flag)	do { \
+	if (*total_flags & (test))		\
+		filter_or |= (flag);		\
+	else					\
+		filter_nand |= (flag);		\
+	} while (0)
+
+	IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
+			changed_flags, *total_flags);
+
+	CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+	/* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
+	CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
+	CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
+
+#undef CHK
+
+	mutex_lock(&priv->mutex);
+
+	for_each_context(priv, ctx) {
+		ctx->staging.filter_flags &= ~filter_nand;
+		ctx->staging.filter_flags |= filter_or;
+
+		/*
+		 * Not committing directly because hardware can perform a scan,
+		 * but we'll eventually commit the filter flags change anyway.
+		 */
+	}
+
+	mutex_unlock(&priv->mutex);
+
+	/*
+	 * Receiving all multicast frames is always enabled by the
+	 * default flags setup in iwl_connection_init_rx_config()
+	 * since we currently do not support programming multicast
+	 * filters into the device.
+	 */
+	*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+			FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
+}
+
+static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	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 (iwlagn_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");
+	iwl_trans_wait_tx_queue_empty(priv->trans);
+done:
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
+				     struct ieee80211_channel *channel,
+				     enum nl80211_channel_type channel_type,
+				     int duration)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
+	int err = 0;
+
+	if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+		return -EOPNOTSUPP;
+
+	if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
+		return -EOPNOTSUPP;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+	mutex_lock(&priv->mutex);
+
+	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+		/* mac80211 should not scan while ROC or ROC while scanning */
+		if (WARN_ON_ONCE(priv->scan_type != IWL_SCAN_RADIO_RESET)) {
+			err = -EBUSY;
+			goto out;
+		}
+
+		iwl_scan_cancel_timeout(priv, 100);
+
+		if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+			err = -EBUSY;
+			goto out;
+		}
+	}
+
+	priv->hw_roc_channel = channel;
+	priv->hw_roc_chantype = channel_type;
+	/* convert from ms to TU */
+	priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024);
+	priv->hw_roc_start_notified = false;
+	cancel_delayed_work(&priv->hw_roc_disable_work);
+
+	if (!ctx->is_active) {
+		static const struct iwl_qos_info default_qos_data = {
+			.def_qos_parm = {
+				.ac[0] = {
+					.cw_min = cpu_to_le16(3),
+					.cw_max = cpu_to_le16(7),
+					.aifsn = 2,
+					.edca_txop = cpu_to_le16(1504),
+				},
+				.ac[1] = {
+					.cw_min = cpu_to_le16(7),
+					.cw_max = cpu_to_le16(15),
+					.aifsn = 2,
+					.edca_txop = cpu_to_le16(3008),
+				},
+				.ac[2] = {
+					.cw_min = cpu_to_le16(15),
+					.cw_max = cpu_to_le16(1023),
+					.aifsn = 3,
+				},
+				.ac[3] = {
+					.cw_min = cpu_to_le16(15),
+					.cw_max = cpu_to_le16(1023),
+					.aifsn = 7,
+				},
+			},
+		};
+
+		ctx->is_active = true;
+		ctx->qos_data = default_qos_data;
+		ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+		memcpy(ctx->staging.node_addr,
+		       priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+		       ETH_ALEN);
+		memcpy(ctx->staging.bssid_addr,
+		       priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+		       ETH_ALEN);
+		err = iwlagn_commit_rxon(priv, ctx);
+		if (err)
+			goto out;
+		ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
+					     RXON_FILTER_PROMISC_MSK |
+					     RXON_FILTER_CTL2HOST_MSK;
+
+		err = iwlagn_commit_rxon(priv, ctx);
+		if (err) {
+			iwlagn_disable_roc(priv);
+			goto out;
+		}
+		priv->hw_roc_setup = true;
+	}
+
+	err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
+	if (err)
+		iwlagn_disable_roc(priv);
+
+ out:
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+
+	return err;
+}
+
+static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+	if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+		return -EOPNOTSUPP;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+	mutex_lock(&priv->mutex);
+	iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
+	iwlagn_disable_roc(priv);
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+
+	return 0;
+}
+
+static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
+				     enum ieee80211_rssi_event rssi_event)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+	mutex_lock(&priv->mutex);
+
+	if (priv->cfg->bt_params &&
+			priv->cfg->bt_params->advanced_bt_coexist) {
+		if (rssi_event == RSSI_EVENT_LOW)
+			priv->bt_enable_pspoll = true;
+		else if (rssi_event == RSSI_EVENT_HIGH)
+			priv->bt_enable_pspoll = false;
+
+		iwlagn_send_advance_bt_config(priv);
+	} else {
+		IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
+				"ignoring RSSI callback\n");
+	}
+
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
+			      struct ieee80211_sta *sta, bool set)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+	queue_work(priv->workqueue, &priv->beacon_update);
+
+	return 0;
+}
+
+static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif, u16 queue,
+			      const struct ieee80211_tx_queue_params *params)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+	struct iwl_rxon_context *ctx = vif_priv->ctx;
+	int q;
+
+	if (WARN_ON(!ctx))
+		return -EINVAL;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+		return -EIO;
+	}
+
+	if (queue >= AC_NUM) {
+		IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
+		return 0;
+	}
+
+	q = AC_NUM - 1 - queue;
+
+	mutex_lock(&priv->mutex);
+
+	ctx->qos_data.def_qos_parm.ac[q].cw_min =
+		cpu_to_le16(params->cw_min);
+	ctx->qos_data.def_qos_parm.ac[q].cw_max =
+		cpu_to_le16(params->cw_max);
+	ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+	ctx->qos_data.def_qos_parm.ac[q].edca_txop =
+			cpu_to_le16((params->txop * 32));
+
+	ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+	return 0;
+}
+
+static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+	return priv->ibss_manager == IWL_IBSS_MANAGER;
+}
+
+static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+	iwl_connection_init_rx_config(priv, ctx);
+
+	iwlagn_set_rxon_chain(priv, ctx);
+
+	return iwlagn_commit_rxon(priv, ctx);
+}
+
+static int iwl_setup_interface(struct iwl_priv *priv,
+			       struct iwl_rxon_context *ctx)
+{
+	struct ieee80211_vif *vif = ctx->vif;
+	int err, ac;
+
+	lockdep_assert_held(&priv->mutex);
+
+	/*
+	 * This variable will be correct only when there's just
+	 * a single context, but all code using it is for hardware
+	 * that supports only one context.
+	 */
+	priv->iw_mode = vif->type;
+
+	ctx->is_active = true;
+
+	err = iwl_set_mode(priv, ctx);
+	if (err) {
+		if (!ctx->always_active)
+			ctx->is_active = false;
+		return err;
+	}
+
+	if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
+	    vif->type == NL80211_IFTYPE_ADHOC) {
+		/*
+		 * pretend to have high BT traffic as long as we
+		 * are operating in IBSS mode, as this will cause
+		 * the rate scaling etc. to behave as intended.
+		 */
+		priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+	}
+
+	/* set up queue mappings */
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+		vif->hw_queue[ac] = ctx->ac_to_queue[ac];
+
+	if (vif->type == NL80211_IFTYPE_AP)
+		vif->cab_queue = ctx->mcast_queue;
+	else
+		vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+
+	return 0;
+}
+
+static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+	struct iwl_rxon_context *tmp, *ctx = NULL;
+	int err;
+	enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
+	bool reset = false;
+
+	IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
+			   viftype, vif->addr);
+
+	cancel_delayed_work_sync(&priv->hw_roc_disable_work);
+
+	mutex_lock(&priv->mutex);
+
+	iwlagn_disable_roc(priv);
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_WARN(priv, "Try to add interface when device not ready\n");
+		err = -EINVAL;
+		goto out;
+	}
+
+	for_each_context(priv, tmp) {
+		u32 possible_modes =
+			tmp->interface_modes | tmp->exclusive_interface_modes;
+
+		if (tmp->vif) {
+			/* On reset we need to add the same interface again */
+			if (tmp->vif == vif) {
+				reset = true;
+				ctx = tmp;
+				break;
+			}
+
+			/* check if this busy context is exclusive */
+			if (tmp->exclusive_interface_modes &
+						BIT(tmp->vif->type)) {
+				err = -EINVAL;
+				goto out;
+			}
+			continue;
+		}
+
+		if (!(possible_modes & BIT(viftype)))
+			continue;
+
+		/* have maybe usable context w/o interface */
+		ctx = tmp;
+		break;
+	}
+
+	if (!ctx) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	vif_priv->ctx = ctx;
+	ctx->vif = vif;
+
+	err = iwl_setup_interface(priv, ctx);
+	if (!err || reset)
+		goto out;
+
+	ctx->vif = NULL;
+	priv->iw_mode = NL80211_IFTYPE_STATION;
+ out:
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+	return err;
+}
+
+static void iwl_teardown_interface(struct iwl_priv *priv,
+				   struct ieee80211_vif *vif,
+				   bool mode_change)
+{
+	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+	lockdep_assert_held(&priv->mutex);
+
+	if (priv->scan_vif == vif) {
+		iwl_scan_cancel_timeout(priv, 200);
+		iwl_force_scan_end(priv);
+	}
+
+	if (!mode_change) {
+		iwl_set_mode(priv, ctx);
+		if (!ctx->always_active)
+			ctx->is_active = false;
+	}
+
+	/*
+	 * When removing the IBSS interface, overwrite the
+	 * BT traffic load with the stored one from the last
+	 * notification, if any. If this is a device that
+	 * doesn't implement this, this has no effect since
+	 * both values are the same and zero.
+	 */
+	if (vif->type == NL80211_IFTYPE_ADHOC)
+		priv->bt_traffic_load = priv->last_bt_traffic_load;
+}
+
+static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	mutex_lock(&priv->mutex);
+
+	if (WARN_ON(ctx->vif != vif)) {
+		struct iwl_rxon_context *tmp;
+		IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
+		for_each_context(priv, tmp)
+			IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
+				tmp->ctxid, tmp, tmp->vif);
+	}
+	ctx->vif = NULL;
+
+	iwl_teardown_interface(priv, vif, false);
+
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+
+}
+
+static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
+				       struct ieee80211_vif *vif,
+				       enum nl80211_iftype newtype, bool newp2p)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_rxon_context *ctx, *tmp;
+	enum nl80211_iftype newviftype = newtype;
+	u32 interface_modes;
+	int err;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	newtype = ieee80211_iftype_p2p(newtype, newp2p);
+
+	mutex_lock(&priv->mutex);
+
+	ctx = iwl_rxon_ctx_from_vif(vif);
+
+	/*
+	 * To simplify this code, only support changes on the
+	 * BSS context. The PAN context is usually reassigned
+	 * by creating/removing P2P interfaces anyway.
+	 */
+	if (ctx->ctxid != IWL_RXON_CTX_BSS) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	if (!ctx->vif || !iwl_is_ready_rf(priv)) {
+		/*
+		 * Huh? But wait ... this can maybe happen when
+		 * we're in the middle of a firmware restart!
+		 */
+		err = -EBUSY;
+		goto out;
+	}
+
+	/* Check if the switch is supported in the same context */
+	interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
+	if (!(interface_modes & BIT(newtype))) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	if (ctx->exclusive_interface_modes & BIT(newtype)) {
+		for_each_context(priv, tmp) {
+			if (ctx == tmp)
+				continue;
+
+			if (!tmp->is_active)
+				continue;
+
+			/*
+			 * The current mode switch would be exclusive, but
+			 * another context is active ... refuse the switch.
+			 */
+			err = -EBUSY;
+			goto out;
+		}
+	}
+
+	/* success */
+	iwl_teardown_interface(priv, vif, true);
+	vif->type = newviftype;
+	vif->p2p = newp2p;
+	err = iwl_setup_interface(priv, ctx);
+	WARN_ON(err);
+	/*
+	 * We've switched internally, but submitting to the
+	 * device may have failed for some reason. Mask this
+	 * error, because otherwise mac80211 will not switch
+	 * (and set the interface type back) and we'll be
+	 * out of sync with it.
+	 */
+	err = 0;
+
+ out:
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+
+	return err;
+}
+
+static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif,
+			      struct cfg80211_scan_request *req)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	int ret;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	if (req->n_channels == 0)
+		return -EINVAL;
+
+	mutex_lock(&priv->mutex);
+
+	/*
+	 * If an internal scan is in progress, just set
+	 * up the scan_request as per above.
+	 */
+	if (priv->scan_type != IWL_SCAN_NORMAL) {
+		IWL_DEBUG_SCAN(priv,
+			       "SCAN request during internal scan - defer\n");
+		priv->scan_request = req;
+		priv->scan_vif = vif;
+		ret = 0;
+	} else {
+		priv->scan_request = req;
+		priv->scan_vif = vif;
+		/*
+		 * mac80211 will only ask for one band at a time
+		 * so using channels[0] here is ok
+		 */
+		ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
+					req->channels[0]->band);
+		if (ret) {
+			priv->scan_request = NULL;
+			priv->scan_vif = NULL;
+		}
+	}
+
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+
+	mutex_unlock(&priv->mutex);
+
+	return ret;
+}
+
+static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+	struct iwl_addsta_cmd cmd = {
+		.mode = STA_CONTROL_MODIFY_MSK,
+		.station_flags_msk = STA_FLG_PWR_SAVE_MSK,
+		.sta.sta_id = sta_id,
+	};
+
+	iwl_send_add_sta(priv, &cmd, CMD_ASYNC);
+}
+
+static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
+				  struct ieee80211_vif *vif,
+				  enum sta_notify_cmd cmd,
+				  struct ieee80211_sta *sta)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+	int sta_id;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	switch (cmd) {
+	case STA_NOTIFY_SLEEP:
+		WARN_ON(!sta_priv->client);
+		sta_priv->asleep = true;
+		if (atomic_read(&sta_priv->pending_frames) > 0)
+			ieee80211_sta_block_awake(hw, sta, true);
+		break;
+	case STA_NOTIFY_AWAKE:
+		WARN_ON(!sta_priv->client);
+		if (!sta_priv->asleep)
+			break;
+		sta_priv->asleep = false;
+		sta_id = iwl_sta_id(sta);
+		if (sta_id != IWL_INVALID_STATION)
+			iwl_sta_modify_ps_wake(priv, sta_id);
+		break;
+	default:
+		break;
+	}
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+struct ieee80211_ops iwlagn_hw_ops = {
+	.tx = iwlagn_mac_tx,
+	.start = iwlagn_mac_start,
+	.stop = iwlagn_mac_stop,
+#ifdef CONFIG_PM_SLEEP
+	.suspend = iwlagn_mac_suspend,
+	.resume = iwlagn_mac_resume,
+	.set_wakeup = iwlagn_mac_set_wakeup,
+#endif
+	.add_interface = iwlagn_mac_add_interface,
+	.remove_interface = iwlagn_mac_remove_interface,
+	.change_interface = iwlagn_mac_change_interface,
+	.config = iwlagn_mac_config,
+	.configure_filter = iwlagn_configure_filter,
+	.set_key = iwlagn_mac_set_key,
+	.update_tkip_key = iwlagn_mac_update_tkip_key,
+	.set_rekey_data = iwlagn_mac_set_rekey_data,
+	.conf_tx = iwlagn_mac_conf_tx,
+	.bss_info_changed = iwlagn_bss_info_changed,
+	.ampdu_action = iwlagn_mac_ampdu_action,
+	.hw_scan = iwlagn_mac_hw_scan,
+	.sta_notify = iwlagn_mac_sta_notify,
+	.sta_state = iwlagn_mac_sta_state,
+	.channel_switch = iwlagn_mac_channel_switch,
+	.flush = iwlagn_mac_flush,
+	.tx_last_beacon = iwlagn_mac_tx_last_beacon,
+	.remain_on_channel = iwlagn_mac_remain_on_channel,
+	.cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
+	.rssi_callback = iwlagn_mac_rssi_callback,
+	CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
+	CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
+	.set_tim = iwlagn_mac_set_tim,
+};
+
+/* This function both allocates and initializes hw and priv. */
+struct ieee80211_hw *iwl_alloc_all(void)
+{
+	struct iwl_priv *priv;
+	struct iwl_op_mode *op_mode;
+	/* mac80211 allocates memory for this device instance, including
+	 *   space for this driver's private structure */
+	struct ieee80211_hw *hw;
+
+	hw = ieee80211_alloc_hw(sizeof(struct iwl_priv) +
+				sizeof(struct iwl_op_mode), &iwlagn_hw_ops);
+	if (!hw)
+		goto out;
+
+	op_mode = hw->priv;
+	priv = IWL_OP_MODE_GET_DVM(op_mode);
+	priv->hw = hw;
+
+out:
+	return hw;
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
new file mode 100644
index 0000000..abfd791
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -0,0 +1,2226 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#include "iwl-eeprom-read.h"
+#include "iwl-eeprom-parse.h"
+#include "iwl-io.h"
+#include "iwl-trans.h"
+#include "iwl-op-mode.h"
+#include "iwl-drv.h"
+#include "iwl-modparams.h"
+#include "iwl-prph.h"
+
+#include "dev.h"
+#include "calib.h"
+#include "agn.h"
+
+
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/*
+ * module name, copyright, version, etc.
+ */
+#define DRV_DESCRIPTION	"Intel(R) Wireless WiFi Link AGN driver for Linux"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#define DRV_VERSION     IWLWIFI_VERSION VD
+
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
+MODULE_LICENSE("GPL");
+
+static const struct iwl_op_mode_ops iwl_dvm_ops;
+
+void iwl_update_chain_flags(struct iwl_priv *priv)
+{
+	struct iwl_rxon_context *ctx;
+
+	for_each_context(priv, ctx) {
+		iwlagn_set_rxon_chain(priv, ctx);
+		if (ctx->active.rx_chain != ctx->staging.rx_chain)
+			iwlagn_commit_rxon(priv, ctx);
+	}
+}
+
+/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */
+static void iwl_set_beacon_tim(struct iwl_priv *priv,
+			       struct iwl_tx_beacon_cmd *tx_beacon_cmd,
+			       u8 *beacon, u32 frame_size)
+{
+	u16 tim_idx;
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
+
+	/*
+	 * The index is relative to frame start but we start looking at the
+	 * variable-length part of the beacon.
+	 */
+	tim_idx = mgmt->u.beacon.variable - beacon;
+
+	/* Parse variable-length elements of beacon to find WLAN_EID_TIM */
+	while ((tim_idx < (frame_size - 2)) &&
+			(beacon[tim_idx] != WLAN_EID_TIM))
+		tim_idx += beacon[tim_idx+1] + 2;
+
+	/* If TIM field was found, set variables */
+	if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) {
+		tx_beacon_cmd->tim_idx = cpu_to_le16(tim_idx);
+		tx_beacon_cmd->tim_size = beacon[tim_idx+1];
+	} else
+		IWL_WARN(priv, "Unable to find TIM Element in beacon\n");
+}
+
+int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
+{
+	struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_TX_BEACON,
+		.flags = CMD_SYNC,
+	};
+	struct ieee80211_tx_info *info;
+	u32 frame_size;
+	u32 rate_flags;
+	u32 rate;
+
+	/*
+	 * We have to set up the TX command, the TX Beacon command, and the
+	 * beacon contents.
+	 */
+
+	lockdep_assert_held(&priv->mutex);
+
+	if (!priv->beacon_ctx) {
+		IWL_ERR(priv, "trying to build beacon w/o beacon context!\n");
+		return 0;
+	}
+
+	if (WARN_ON(!priv->beacon_skb))
+		return -EINVAL;
+
+	/* Allocate beacon command */
+	if (!priv->beacon_cmd)
+		priv->beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd), GFP_KERNEL);
+	tx_beacon_cmd = priv->beacon_cmd;
+	if (!tx_beacon_cmd)
+		return -ENOMEM;
+
+	frame_size = priv->beacon_skb->len;
+
+	/* Set up TX command fields */
+	tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+	tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id;
+	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+	tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
+		TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
+
+	/* Set up TX beacon command fields */
+	iwl_set_beacon_tim(priv, tx_beacon_cmd, priv->beacon_skb->data,
+			   frame_size);
+
+	/* Set up packet rate and flags */
+	info = IEEE80211_SKB_CB(priv->beacon_skb);
+
+	/*
+	 * Let's set up the rate at least somewhat correctly;
+	 * it will currently not actually be used by the uCode,
+	 * it uses the broadcast station's rate instead.
+	 */
+	if (info->control.rates[0].idx < 0 ||
+	    info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
+		rate = 0;
+	else
+		rate = info->control.rates[0].idx;
+
+	priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+					      priv->eeprom_data->valid_tx_ant);
+	rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
+
+	/* In mac80211, rates for 5 GHz start at 0 */
+	if (info->band == IEEE80211_BAND_5GHZ)
+		rate += IWL_FIRST_OFDM_RATE;
+	else if (rate >= IWL_FIRST_CCK_RATE && rate <= IWL_LAST_CCK_RATE)
+		rate_flags |= RATE_MCS_CCK_MSK;
+
+	tx_beacon_cmd->tx.rate_n_flags =
+			iwl_hw_set_rate_n_flags(rate, rate_flags);
+
+	/* Submit command */
+	cmd.len[0] = sizeof(*tx_beacon_cmd);
+	cmd.data[0] = tx_beacon_cmd;
+	cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+	cmd.len[1] = frame_size;
+	cmd.data[1] = priv->beacon_skb->data;
+	cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
+
+	return iwl_dvm_send_cmd(priv, &cmd);
+}
+
+static void iwl_bg_beacon_update(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+		container_of(work, struct iwl_priv, beacon_update);
+	struct sk_buff *beacon;
+
+	mutex_lock(&priv->mutex);
+	if (!priv->beacon_ctx) {
+		IWL_ERR(priv, "updating beacon w/o beacon context!\n");
+		goto out;
+	}
+
+	if (priv->beacon_ctx->vif->type != NL80211_IFTYPE_AP) {
+		/*
+		 * The ucode will send beacon notifications even in
+		 * IBSS mode, but we don't want to process them. But
+		 * we need to defer the type check to here due to
+		 * requiring locking around the beacon_ctx access.
+		 */
+		goto out;
+	}
+
+	/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+	beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif);
+	if (!beacon) {
+		IWL_ERR(priv, "update beacon failed -- keeping old\n");
+		goto out;
+	}
+
+	/* new beacon skb is allocated every time; dispose previous.*/
+	dev_kfree_skb(priv->beacon_skb);
+
+	priv->beacon_skb = beacon;
+
+	iwlagn_send_beacon_cmd(priv);
+ out:
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_bt_runtime_config(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+		container_of(work, struct iwl_priv, bt_runtime_config);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	/* dont send host command if rf-kill is on */
+	if (!iwl_is_ready_rf(priv))
+		return;
+	iwlagn_send_advance_bt_config(priv);
+}
+
+static void iwl_bg_bt_full_concurrency(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+		container_of(work, struct iwl_priv, bt_full_concurrency);
+	struct iwl_rxon_context *ctx;
+
+	mutex_lock(&priv->mutex);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		goto out;
+
+	/* dont send host command if rf-kill is on */
+	if (!iwl_is_ready_rf(priv))
+		goto out;
+
+	IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
+		       priv->bt_full_concurrent ?
+		       "full concurrency" : "3-wire");
+
+	/*
+	 * LQ & RXON updated cmds must be sent before BT Config cmd
+	 * to avoid 3-wire collisions
+	 */
+	for_each_context(priv, ctx) {
+		iwlagn_set_rxon_chain(priv, ctx);
+		iwlagn_commit_rxon(priv, ctx);
+	}
+
+	iwlagn_send_advance_bt_config(priv);
+out:
+	mutex_unlock(&priv->mutex);
+}
+
+int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
+{
+	struct iwl_statistics_cmd statistics_cmd = {
+		.configuration_flags =
+			clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
+	};
+
+	if (flags & CMD_ASYNC)
+		return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
+					CMD_ASYNC,
+					sizeof(struct iwl_statistics_cmd),
+					&statistics_cmd);
+	else
+		return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
+					CMD_SYNC,
+					sizeof(struct iwl_statistics_cmd),
+					&statistics_cmd);
+}
+
+/**
+ * iwl_bg_statistics_periodic - Timer callback to queue statistics
+ *
+ * This callback is provided in order to send a statistics request.
+ *
+ * This timer function is continually reset to execute within
+ * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
+ * was received.  We need to ensure we receive the statistics in order
+ * to update the temperature used for calibrating the TXPOWER.
+ */
+static void iwl_bg_statistics_periodic(unsigned long data)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)data;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	/* dont send host command if rf-kill is on */
+	if (!iwl_is_ready_rf(priv))
+		return;
+
+	iwl_send_statistics_request(priv, CMD_ASYNC, false);
+}
+
+
+static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
+					u32 start_idx, u32 num_events,
+					u32 capacity, u32 mode)
+{
+	u32 i;
+	u32 ptr;        /* SRAM byte address of log data */
+	u32 ev, time, data; /* event log data */
+	unsigned long reg_flags;
+
+	if (mode == 0)
+		ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32));
+	else
+		ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
+
+	/* Make sure device is powered up for SRAM reads */
+	spin_lock_irqsave(&priv->trans->reg_lock, reg_flags);
+	if (unlikely(!iwl_grab_nic_access(priv->trans))) {
+		spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
+		return;
+	}
+
+	/* Set starting address; reads will auto-increment */
+	iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr);
+
+	/*
+	 * Refuse to read more than would have fit into the log from
+	 * the current start_idx. This used to happen due to the race
+	 * described below, but now WARN because the code below should
+	 * prevent it from happening here.
+	 */
+	if (WARN_ON(num_events > capacity - start_idx))
+		num_events = capacity - start_idx;
+
+	/*
+	 * "time" is actually "data" for mode 0 (no timestamp).
+	 * place event id # at far right for easier visual parsing.
+	 */
+	for (i = 0; i < num_events; i++) {
+		ev = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+		time = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+		if (mode == 0) {
+			trace_iwlwifi_dev_ucode_cont_event(
+					priv->trans->dev, 0, time, ev);
+		} else {
+			data = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+			trace_iwlwifi_dev_ucode_cont_event(
+					priv->trans->dev, time, data, ev);
+		}
+	}
+	/* Allow device to power down */
+	iwl_release_nic_access(priv->trans);
+	spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
+}
+
+static void iwl_continuous_event_trace(struct iwl_priv *priv)
+{
+	u32 capacity;   /* event log capacity in # entries */
+	struct {
+		u32 capacity;
+		u32 mode;
+		u32 wrap_counter;
+		u32 write_counter;
+	} __packed read;
+	u32 base;       /* SRAM byte address of event log header */
+	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+	u32 num_wraps;  /* # times uCode wrapped to top of log */
+	u32 next_entry; /* index of next entry to be written by uCode */
+
+	base = priv->device_pointers.log_event_table;
+	if (iwlagn_hw_valid_rtc_data_addr(base)) {
+		iwl_read_targ_mem_bytes(priv->trans, base, &read, sizeof(read));
+		capacity = read.capacity;
+		mode = read.mode;
+		num_wraps = read.wrap_counter;
+		next_entry = read.write_counter;
+	} else
+		return;
+
+	/*
+	 * Unfortunately, the uCode doesn't use temporary variables.
+	 * Therefore, it can happen that we read next_entry == capacity,
+	 * which really means next_entry == 0.
+	 */
+	if (unlikely(next_entry == capacity))
+		next_entry = 0;
+	/*
+	 * Additionally, the uCode increases the write pointer before
+	 * the wraps counter, so if the write pointer is smaller than
+	 * the old write pointer (wrap occurred) but we read that no
+	 * wrap occurred, we actually read between the next_entry and
+	 * num_wraps update (this does happen in practice!!) -- take
+	 * that into account by increasing num_wraps.
+	 */
+	if (unlikely(next_entry < priv->event_log.next_entry &&
+		     num_wraps == priv->event_log.num_wraps))
+		num_wraps++;
+
+	if (num_wraps == priv->event_log.num_wraps) {
+		iwl_print_cont_event_trace(
+			priv, base, priv->event_log.next_entry,
+			next_entry - priv->event_log.next_entry,
+			capacity, mode);
+
+		priv->event_log.non_wraps_count++;
+	} else {
+		if (num_wraps - priv->event_log.num_wraps > 1)
+			priv->event_log.wraps_more_count++;
+		else
+			priv->event_log.wraps_once_count++;
+
+		trace_iwlwifi_dev_ucode_wrap_event(priv->trans->dev,
+				num_wraps - priv->event_log.num_wraps,
+				next_entry, priv->event_log.next_entry);
+
+		if (next_entry < priv->event_log.next_entry) {
+			iwl_print_cont_event_trace(
+				priv, base, priv->event_log.next_entry,
+				capacity - priv->event_log.next_entry,
+				capacity, mode);
+
+			iwl_print_cont_event_trace(
+				priv, base, 0, next_entry, capacity, mode);
+		} else {
+			iwl_print_cont_event_trace(
+				priv, base, next_entry,
+				capacity - next_entry,
+				capacity, mode);
+
+			iwl_print_cont_event_trace(
+				priv, base, 0, next_entry, capacity, mode);
+		}
+	}
+
+	priv->event_log.num_wraps = num_wraps;
+	priv->event_log.next_entry = next_entry;
+}
+
+/**
+ * iwl_bg_ucode_trace - Timer callback to log ucode event
+ *
+ * The timer is continually set to execute every
+ * UCODE_TRACE_PERIOD milliseconds after the last timer expired
+ * this function is to perform continuous uCode event logging operation
+ * if enabled
+ */
+static void iwl_bg_ucode_trace(unsigned long data)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)data;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (priv->event_log.ucode_trace) {
+		iwl_continuous_event_trace(priv);
+		/* Reschedule the timer to occur in UCODE_TRACE_PERIOD */
+		mod_timer(&priv->ucode_trace,
+			 jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
+	}
+}
+
+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;
+
+	IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
+	iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
+}
+
+/*
+ * queue/FIFO/AC mapping definitions
+ */
+
+#define IWL_TX_FIFO_BK		0	/* shared */
+#define IWL_TX_FIFO_BE		1
+#define IWL_TX_FIFO_VI		2	/* shared */
+#define IWL_TX_FIFO_VO		3
+#define IWL_TX_FIFO_BK_IPAN	IWL_TX_FIFO_BK
+#define IWL_TX_FIFO_BE_IPAN	4
+#define IWL_TX_FIFO_VI_IPAN	IWL_TX_FIFO_VI
+#define IWL_TX_FIFO_VO_IPAN	5
+/* re-uses the VO FIFO, uCode will properly flush/schedule */
+#define IWL_TX_FIFO_AUX		5
+#define IWL_TX_FIFO_UNUSED	-1
+
+#define IWLAGN_CMD_FIFO_NUM	7
+
+/*
+ * This queue number is required for proper operation
+ * because the ucode will stop/start the scheduler as
+ * required.
+ */
+#define IWL_IPAN_MCAST_QUEUE	8
+
+static const u8 iwlagn_default_queue_to_tx_fifo[] = {
+	IWL_TX_FIFO_VO,
+	IWL_TX_FIFO_VI,
+	IWL_TX_FIFO_BE,
+	IWL_TX_FIFO_BK,
+	IWLAGN_CMD_FIFO_NUM,
+};
+
+static const u8 iwlagn_ipan_queue_to_tx_fifo[] = {
+	IWL_TX_FIFO_VO,
+	IWL_TX_FIFO_VI,
+	IWL_TX_FIFO_BE,
+	IWL_TX_FIFO_BK,
+	IWL_TX_FIFO_BK_IPAN,
+	IWL_TX_FIFO_BE_IPAN,
+	IWL_TX_FIFO_VI_IPAN,
+	IWL_TX_FIFO_VO_IPAN,
+	IWL_TX_FIFO_BE_IPAN,
+	IWLAGN_CMD_FIFO_NUM,
+	IWL_TX_FIFO_AUX,
+};
+
+static const u8 iwlagn_bss_ac_to_fifo[] = {
+	IWL_TX_FIFO_VO,
+	IWL_TX_FIFO_VI,
+	IWL_TX_FIFO_BE,
+	IWL_TX_FIFO_BK,
+};
+
+static const u8 iwlagn_bss_ac_to_queue[] = {
+	0, 1, 2, 3,
+};
+
+static const u8 iwlagn_pan_ac_to_fifo[] = {
+	IWL_TX_FIFO_VO_IPAN,
+	IWL_TX_FIFO_VI_IPAN,
+	IWL_TX_FIFO_BE_IPAN,
+	IWL_TX_FIFO_BK_IPAN,
+};
+
+static const u8 iwlagn_pan_ac_to_queue[] = {
+	7, 6, 5, 4,
+};
+
+static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
+{
+	int i;
+
+	/*
+	 * The default context is always valid,
+	 * the PAN context depends on uCode.
+	 */
+	priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
+	if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN)
+		priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
+
+	for (i = 0; i < NUM_IWL_RXON_CTX; i++)
+		priv->contexts[i].ctxid = i;
+
+	priv->contexts[IWL_RXON_CTX_BSS].always_active = true;
+	priv->contexts[IWL_RXON_CTX_BSS].is_active = true;
+	priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
+	priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
+	priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
+	priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
+	priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
+	priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
+	priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
+	priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
+		BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MONITOR);
+	priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
+		BIT(NL80211_IFTYPE_STATION);
+	priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
+	priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
+	priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
+	priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
+	memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue,
+	       iwlagn_bss_ac_to_queue, sizeof(iwlagn_bss_ac_to_queue));
+	memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo,
+	       iwlagn_bss_ac_to_fifo, sizeof(iwlagn_bss_ac_to_fifo));
+
+	priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
+	priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd =
+		REPLY_WIPAN_RXON_TIMING;
+	priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd =
+		REPLY_WIPAN_RXON_ASSOC;
+	priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM;
+	priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN;
+	priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY;
+	priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID;
+	priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION;
+	priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
+		BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
+
+	if (ucode_flags & IWL_UCODE_TLV_FLAGS_P2P)
+		priv->contexts[IWL_RXON_CTX_PAN].interface_modes |=
+			BIT(NL80211_IFTYPE_P2P_CLIENT) |
+			BIT(NL80211_IFTYPE_P2P_GO);
+
+	priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
+	priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
+	priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
+	memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue,
+	       iwlagn_pan_ac_to_queue, sizeof(iwlagn_pan_ac_to_queue));
+	memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo,
+	       iwlagn_pan_ac_to_fifo, sizeof(iwlagn_pan_ac_to_fifo));
+	priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
+
+	BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+}
+
+static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
+{
+	struct iwl_ct_kill_config cmd;
+	struct iwl_ct_kill_throttling_config adv_cmd;
+	int ret = 0;
+
+	iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+
+	priv->thermal_throttle.ct_kill_toggle = false;
+
+	if (priv->cfg->base_params->support_ct_kill_exit) {
+		adv_cmd.critical_temperature_enter =
+			cpu_to_le32(priv->hw_params.ct_kill_threshold);
+		adv_cmd.critical_temperature_exit =
+			cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
+
+		ret = iwl_dvm_send_cmd_pdu(priv,
+				       REPLY_CT_KILL_CONFIG_CMD,
+				       CMD_SYNC, sizeof(adv_cmd), &adv_cmd);
+		if (ret)
+			IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
+		else
+			IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
+				"succeeded, critical temperature enter is %d,"
+				"exit is %d\n",
+				priv->hw_params.ct_kill_threshold,
+				priv->hw_params.ct_kill_exit_threshold);
+	} else {
+		cmd.critical_temperature_R =
+			cpu_to_le32(priv->hw_params.ct_kill_threshold);
+
+		ret = iwl_dvm_send_cmd_pdu(priv,
+				       REPLY_CT_KILL_CONFIG_CMD,
+				       CMD_SYNC, sizeof(cmd), &cmd);
+		if (ret)
+			IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
+		else
+			IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
+				"succeeded, "
+				"critical temperature is %d\n",
+				priv->hw_params.ct_kill_threshold);
+	}
+}
+
+static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
+{
+	struct iwl_calib_cfg_cmd calib_cfg_cmd;
+	struct iwl_host_cmd cmd = {
+		.id = CALIBRATION_CFG_CMD,
+		.len = { sizeof(struct iwl_calib_cfg_cmd), },
+		.data = { &calib_cfg_cmd, },
+	};
+
+	memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
+	calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_RT_CFG_ALL;
+	calib_cfg_cmd.ucd_calib_cfg.once.start = cpu_to_le32(cfg);
+
+	return iwl_dvm_send_cmd(priv, &cmd);
+}
+
+
+static 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),
+	};
+
+	if (IWL_UCODE_API(priv->fw->ucode_ver) > 1) {
+		IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
+		return iwl_dvm_send_cmd_pdu(priv,
+					TX_ANT_CONFIGURATION_CMD,
+					CMD_SYNC,
+					sizeof(struct iwl_tx_ant_config_cmd),
+					&tx_ant_cmd);
+	} else {
+		IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n");
+		return -EOPNOTSUPP;
+	}
+}
+
+static void iwl_send_bt_config(struct iwl_priv *priv)
+{
+	struct iwl_bt_cmd bt_cmd = {
+		.lead_time = BT_LEAD_TIME_DEF,
+		.max_kill = BT_MAX_KILL_DEF,
+		.kill_ack_mask = 0,
+		.kill_cts_mask = 0,
+	};
+
+	if (!iwlwifi_mod_params.bt_coex_active)
+		bt_cmd.flags = BT_COEX_DISABLE;
+	else
+		bt_cmd.flags = BT_COEX_ENABLE;
+
+	priv->bt_enable_flag = bt_cmd.flags;
+	IWL_DEBUG_INFO(priv, "BT coex %s\n",
+		(bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
+
+	if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+			     CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
+		IWL_ERR(priv, "failed to send BT Coex Config\n");
+}
+
+/**
+ * iwl_alive_start - called after REPLY_ALIVE notification received
+ *                   from protocol/runtime uCode (initialization uCode's
+ *                   Alive gets handled by iwl_init_alive_start()).
+ */
+int iwl_alive_start(struct iwl_priv *priv)
+{
+	int ret = 0;
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
+	IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
+
+	/* After the ALIVE response, we can send host commands to the uCode */
+	set_bit(STATUS_ALIVE, &priv->status);
+
+	if (iwl_is_rfkill(priv))
+		return -ERFKILL;
+
+	if (priv->event_log.ucode_trace) {
+		/* start collecting data now */
+		mod_timer(&priv->ucode_trace, jiffies);
+	}
+
+	/* download priority table before any calibration request */
+	if (priv->cfg->bt_params &&
+	    priv->cfg->bt_params->advanced_bt_coexist) {
+		/* Configure Bluetooth device coexistence support */
+		if (priv->cfg->bt_params->bt_sco_disable)
+			priv->bt_enable_pspoll = false;
+		else
+			priv->bt_enable_pspoll = true;
+
+		priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+		priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+		priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+		iwlagn_send_advance_bt_config(priv);
+		priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
+		priv->cur_rssi_ctx = NULL;
+
+		iwl_send_prio_tbl(priv);
+
+		/* FIXME: w/a to force change uCode BT state machine */
+		ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+					 BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+		if (ret)
+			return ret;
+		ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
+					 BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+		if (ret)
+			return ret;
+	} else {
+		/*
+		 * default is 2-wire BT coexexistence support
+		 */
+		iwl_send_bt_config(priv);
+	}
+
+	/*
+	 * Perform runtime calibrations, including DC calibration.
+	 */
+	iwlagn_send_calib_cfg_rt(priv, IWL_CALIB_CFG_DC_IDX);
+
+	ieee80211_wake_queues(priv->hw);
+
+	/* Configure Tx antenna selection based on H/W config */
+	iwlagn_send_tx_ant_config(priv, priv->eeprom_data->valid_tx_ant);
+
+	if (iwl_is_associated_ctx(ctx) && !priv->wowlan) {
+		struct iwl_rxon_cmd *active_rxon =
+				(struct iwl_rxon_cmd *)&ctx->active;
+		/* apply any changes in staging */
+		ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	} else {
+		struct iwl_rxon_context *tmp;
+		/* Initialize our rx_config data */
+		for_each_context(priv, tmp)
+			iwl_connection_init_rx_config(priv, tmp);
+
+		iwlagn_set_rxon_chain(priv, ctx);
+	}
+
+	if (!priv->wowlan) {
+		/* WoWLAN ucode will not reply in the same way, skip it */
+		iwl_reset_run_time_calib(priv);
+	}
+
+	set_bit(STATUS_READY, &priv->status);
+
+	/* Configure the adapter for unassociated operation */
+	ret = iwlagn_commit_rxon(priv, ctx);
+	if (ret)
+		return ret;
+
+	/* At this point, the NIC is initialized and operational */
+	iwl_rf_kill_ct_config(priv);
+
+	IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
+
+	return iwl_power_update_mode(priv, true);
+}
+
+/**
+ * iwl_clear_driver_stations - clear knowledge of all stations from driver
+ * @priv: iwl priv struct
+ *
+ * This is called during iwl_down() to make sure that in the case
+ * we're coming there from a hardware restart mac80211 will be
+ * able to reconfigure stations -- if we're getting there in the
+ * normal down flow then the stations will already be cleared.
+ */
+static void iwl_clear_driver_stations(struct iwl_priv *priv)
+{
+	struct iwl_rxon_context *ctx;
+
+	spin_lock_bh(&priv->sta_lock);
+	memset(priv->stations, 0, sizeof(priv->stations));
+	priv->num_stations = 0;
+
+	priv->ucode_key_table = 0;
+
+	for_each_context(priv, ctx) {
+		/*
+		 * Remove all key information that is not stored as part
+		 * of station information since mac80211 may not have had
+		 * a chance to remove all the keys. When device is
+		 * reconfigured by mac80211 after an error all keys will
+		 * be reconfigured.
+		 */
+		memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys));
+		ctx->key_mapping_keys = 0;
+	}
+
+	spin_unlock_bh(&priv->sta_lock);
+}
+
+void iwl_down(struct iwl_priv *priv)
+{
+	int exit_pending;
+
+	IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
+
+	lockdep_assert_held(&priv->mutex);
+
+	iwl_scan_cancel_timeout(priv, 200);
+
+	/*
+	 * If active, scanning won't cancel it, so say it expired.
+	 * No race since we hold the mutex here and a new one
+	 * can't come in at this time.
+	 */
+	ieee80211_remain_on_channel_expired(priv->hw);
+
+	exit_pending =
+		test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+	iwl_clear_ucode_stations(priv, NULL);
+	iwl_dealloc_bcast_stations(priv);
+	iwl_clear_driver_stations(priv);
+
+	/* reset BT coex data */
+	priv->bt_status = 0;
+	priv->cur_rssi_ctx = NULL;
+	priv->bt_is_sco = 0;
+	if (priv->cfg->bt_params)
+		priv->bt_traffic_load =
+			 priv->cfg->bt_params->bt_init_traffic_load;
+	else
+		priv->bt_traffic_load = 0;
+	priv->bt_full_concurrent = false;
+	priv->bt_ci_compliance = 0;
+
+	/* Wipe out the EXIT_PENDING status bit if we are not actually
+	 * exiting the module */
+	if (!exit_pending)
+		clear_bit(STATUS_EXIT_PENDING, &priv->status);
+
+	if (priv->mac80211_registered)
+		ieee80211_stop_queues(priv->hw);
+
+	priv->ucode_loaded = false;
+	iwl_trans_stop_device(priv->trans);
+
+	/* Set num_aux_in_flight must be done after the transport is stopped */
+	atomic_set(&priv->num_aux_in_flight, 0);
+
+	/* Clear out all status bits but a few that are stable across reset */
+	priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+				STATUS_RF_KILL_HW |
+			test_bit(STATUS_FW_ERROR, &priv->status) <<
+				STATUS_FW_ERROR |
+			test_bit(STATUS_EXIT_PENDING, &priv->status) <<
+				STATUS_EXIT_PENDING;
+
+	dev_kfree_skb(priv->beacon_skb);
+	priv->beacon_skb = NULL;
+}
+
+/*****************************************************************************
+ *
+ * Workqueue callbacks
+ *
+ *****************************************************************************/
+
+static void iwl_bg_run_time_calib_work(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+			run_time_calib_work);
+
+	mutex_lock(&priv->mutex);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+	    test_bit(STATUS_SCANNING, &priv->status)) {
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	if (priv->start_calib) {
+		iwl_chain_noise_calibration(priv);
+		iwl_sensitivity_calibration(priv);
+	}
+
+	mutex_unlock(&priv->mutex);
+}
+
+void iwlagn_prepare_restart(struct iwl_priv *priv)
+{
+	bool bt_full_concurrent;
+	u8 bt_ci_compliance;
+	u8 bt_load;
+	u8 bt_status;
+	bool bt_is_sco;
+	int i;
+
+	lockdep_assert_held(&priv->mutex);
+
+	priv->is_open = 0;
+
+	/*
+	 * __iwl_down() will clear the BT status variables,
+	 * which is correct, but when we restart we really
+	 * want to keep them so restore them afterwards.
+	 *
+	 * The restart process will later pick them up and
+	 * re-configure the hw when we reconfigure the BT
+	 * command.
+	 */
+	bt_full_concurrent = priv->bt_full_concurrent;
+	bt_ci_compliance = priv->bt_ci_compliance;
+	bt_load = priv->bt_traffic_load;
+	bt_status = priv->bt_status;
+	bt_is_sco = priv->bt_is_sco;
+
+	iwl_down(priv);
+
+	priv->bt_full_concurrent = bt_full_concurrent;
+	priv->bt_ci_compliance = bt_ci_compliance;
+	priv->bt_traffic_load = bt_load;
+	priv->bt_status = bt_status;
+	priv->bt_is_sco = bt_is_sco;
+
+	/* reset aggregation queues */
+	for (i = IWLAGN_FIRST_AMPDU_QUEUE; i < IWL_MAX_HW_QUEUES; i++)
+		priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
+	/* and stop counts */
+	for (i = 0; i < IWL_MAX_HW_QUEUES; i++)
+		atomic_set(&priv->queue_stop_count[i], 0);
+
+	memset(priv->agg_q_alloc, 0, sizeof(priv->agg_q_alloc));
+}
+
+static void iwl_bg_restart(struct work_struct *data)
+{
+	struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
+		mutex_lock(&priv->mutex);
+		iwlagn_prepare_restart(priv);
+		mutex_unlock(&priv->mutex);
+		iwl_cancel_deferred_work(priv);
+		ieee80211_restart_hw(priv->hw);
+	} else {
+		WARN_ON(1);
+	}
+}
+
+
+
+
+void iwlagn_disable_roc(struct iwl_priv *priv)
+{
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
+
+	lockdep_assert_held(&priv->mutex);
+
+	if (!priv->hw_roc_setup)
+		return;
+
+	ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+	ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+	priv->hw_roc_channel = NULL;
+
+	memset(ctx->staging.node_addr, 0, ETH_ALEN);
+
+	iwlagn_commit_rxon(priv, ctx);
+
+	ctx->is_active = false;
+	priv->hw_roc_setup = false;
+}
+
+static void iwlagn_disable_roc_work(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+					     hw_roc_disable_work.work);
+
+	mutex_lock(&priv->mutex);
+	iwlagn_disable_roc(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl_setup_deferred_work(struct iwl_priv *priv)
+{
+	priv->workqueue = create_singlethread_workqueue(DRV_NAME);
+
+	INIT_WORK(&priv->restart, iwl_bg_restart);
+	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_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
+	INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
+	INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
+			  iwlagn_disable_roc_work);
+
+	iwl_setup_scan_deferred_work(priv);
+
+	if (priv->cfg->bt_params)
+		iwlagn_bt_setup_deferred_work(priv);
+
+	init_timer(&priv->statistics_periodic);
+	priv->statistics_periodic.data = (unsigned long)priv;
+	priv->statistics_periodic.function = iwl_bg_statistics_periodic;
+
+	init_timer(&priv->ucode_trace);
+	priv->ucode_trace.data = (unsigned long)priv;
+	priv->ucode_trace.function = iwl_bg_ucode_trace;
+}
+
+void iwl_cancel_deferred_work(struct iwl_priv *priv)
+{
+	if (priv->cfg->bt_params)
+		iwlagn_bt_cancel_deferred_work(priv);
+
+	cancel_work_sync(&priv->run_time_calib_work);
+	cancel_work_sync(&priv->beacon_update);
+
+	iwl_cancel_scan_deferred_work(priv);
+
+	cancel_work_sync(&priv->bt_full_concurrency);
+	cancel_work_sync(&priv->bt_runtime_config);
+	cancel_delayed_work_sync(&priv->hw_roc_disable_work);
+
+	del_timer_sync(&priv->statistics_periodic);
+	del_timer_sync(&priv->ucode_trace);
+}
+
+static int iwl_init_drv(struct iwl_priv *priv)
+{
+	spin_lock_init(&priv->sta_lock);
+
+	mutex_init(&priv->mutex);
+
+	INIT_LIST_HEAD(&priv->calib_results);
+
+	priv->band = IEEE80211_BAND_2GHZ;
+
+	priv->plcp_delta_threshold =
+		priv->cfg->base_params->plcp_delta_threshold;
+
+	priv->iw_mode = NL80211_IFTYPE_STATION;
+	priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
+	priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
+	priv->agg_tids_count = 0;
+
+	priv->ucode_owner = IWL_OWNERSHIP_DRIVER;
+
+	priv->rx_statistics_jiffies = jiffies;
+
+	/* Choose which receivers/antennas to use */
+	iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
+
+	iwl_init_scan_params(priv);
+
+	/* init bt coex */
+	if (priv->cfg->bt_params &&
+	    priv->cfg->bt_params->advanced_bt_coexist) {
+		priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+		priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+		priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+		priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
+		priv->bt_duration = BT_DURATION_LIMIT_DEF;
+		priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
+	}
+
+	return 0;
+}
+
+static void iwl_uninit_drv(struct iwl_priv *priv)
+{
+	kfree(priv->scan_cmd);
+	kfree(priv->beacon_cmd);
+	kfree(rcu_dereference_raw(priv->noa_data));
+	iwl_calib_free_results(priv);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	kfree(priv->wowlan_sram);
+#endif
+}
+
+static void iwl_set_hw_params(struct iwl_priv *priv)
+{
+	if (priv->cfg->ht_params)
+		priv->hw_params.use_rts_for_aggregation =
+			priv->cfg->ht_params->use_rts_for_aggregation;
+
+	/* Device-specific setup */
+	priv->lib->set_hw_params(priv);
+}
+
+
+
+/* show what optional capabilities we have */
+static void iwl_option_config(struct iwl_priv *priv)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG enabled\n");
+#else
+	IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG disabled\n");
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS enabled\n");
+#else
+	IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS disabled\n");
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+	IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING enabled\n");
+#else
+	IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING disabled\n");
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+	IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE enabled\n");
+#else
+	IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE disabled\n");
+#endif
+
+#ifdef CONFIG_IWLWIFI_P2P
+	IWL_INFO(priv, "CONFIG_IWLWIFI_P2P enabled\n");
+#else
+	IWL_INFO(priv, "CONFIG_IWLWIFI_P2P disabled\n");
+#endif
+}
+
+static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
+{
+	u16 radio_cfg;
+
+	priv->eeprom_data->sku = priv->eeprom_data->sku;
+
+	if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE &&
+	    !priv->cfg->ht_params) {
+		IWL_ERR(priv, "Invalid 11n configuration\n");
+		return -EINVAL;
+	}
+
+	if (!priv->eeprom_data->sku) {
+		IWL_ERR(priv, "Invalid device sku\n");
+		return -EINVAL;
+	}
+
+	IWL_INFO(priv, "Device SKU: 0x%X\n", priv->eeprom_data->sku);
+
+	radio_cfg = priv->eeprom_data->radio_cfg;
+
+	priv->hw_params.tx_chains_num =
+		num_of_ant(priv->eeprom_data->valid_tx_ant);
+	if (priv->cfg->rx_with_siso_diversity)
+		priv->hw_params.rx_chains_num = 1;
+	else
+		priv->hw_params.rx_chains_num =
+			num_of_ant(priv->eeprom_data->valid_rx_ant);
+
+	IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n",
+		 priv->eeprom_data->valid_tx_ant,
+		 priv->eeprom_data->valid_rx_ant);
+
+	return 0;
+}
+
+static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
+						 const struct iwl_cfg *cfg,
+						 const struct iwl_fw *fw)
+{
+	struct iwl_priv *priv;
+	struct ieee80211_hw *hw;
+	struct iwl_op_mode *op_mode;
+	u16 num_mac;
+	u32 ucode_flags;
+	struct iwl_trans_config trans_cfg;
+	static const u8 no_reclaim_cmds[] = {
+		REPLY_RX_PHY_CMD,
+		REPLY_RX,
+		REPLY_RX_MPDU_CMD,
+		REPLY_COMPRESSED_BA,
+		STATISTICS_NOTIFICATION,
+		REPLY_TX,
+	};
+	int i;
+
+	/************************
+	 * 1. Allocating HW data
+	 ************************/
+	hw = iwl_alloc_all();
+	if (!hw) {
+		pr_err("%s: Cannot allocate network device\n", cfg->name);
+		goto out;
+	}
+
+	op_mode = hw->priv;
+	op_mode->ops = &iwl_dvm_ops;
+	priv = IWL_OP_MODE_GET_DVM(op_mode);
+	priv->trans = trans;
+	priv->dev = trans->dev;
+	priv->cfg = cfg;
+	priv->fw = fw;
+
+	switch (priv->cfg->device_family) {
+	case IWL_DEVICE_FAMILY_1000:
+	case IWL_DEVICE_FAMILY_100:
+		priv->lib = &iwl1000_lib;
+		break;
+	case IWL_DEVICE_FAMILY_2000:
+	case IWL_DEVICE_FAMILY_105:
+		priv->lib = &iwl2000_lib;
+		break;
+	case IWL_DEVICE_FAMILY_2030:
+	case IWL_DEVICE_FAMILY_135:
+		priv->lib = &iwl2030_lib;
+		break;
+	case IWL_DEVICE_FAMILY_5000:
+		priv->lib = &iwl5000_lib;
+		break;
+	case IWL_DEVICE_FAMILY_5150:
+		priv->lib = &iwl5150_lib;
+		break;
+	case IWL_DEVICE_FAMILY_6000:
+	case IWL_DEVICE_FAMILY_6005:
+	case IWL_DEVICE_FAMILY_6000i:
+	case IWL_DEVICE_FAMILY_6050:
+	case IWL_DEVICE_FAMILY_6150:
+		priv->lib = &iwl6000_lib;
+		break;
+	case IWL_DEVICE_FAMILY_6030:
+		priv->lib = &iwl6030_lib;
+		break;
+	default:
+		break;
+	}
+
+	if (WARN_ON(!priv->lib))
+		goto out_free_hw;
+
+	/*
+	 * Populate the state variables that the transport layer needs
+	 * to know about.
+	 */
+	trans_cfg.op_mode = op_mode;
+	trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
+	trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
+	trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
+	if (!iwlwifi_mod_params.wd_disable)
+		trans_cfg.queue_watchdog_timeout =
+			priv->cfg->base_params->wd_timeout;
+	else
+		trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED;
+	trans_cfg.command_names = iwl_dvm_cmd_strings;
+
+	WARN_ON(sizeof(priv->transport_queue_stop) * BITS_PER_BYTE <
+		priv->cfg->base_params->num_of_queues);
+
+	ucode_flags = fw->ucode_capa.flags;
+
+#ifndef CONFIG_IWLWIFI_P2P
+	ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
+#endif
+
+	if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) {
+		priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
+		trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
+		trans_cfg.queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
+		trans_cfg.n_queue_to_fifo =
+			ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo);
+	} else {
+		priv->sta_key_max_num = STA_KEY_MAX_NUM;
+		trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+		trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
+		trans_cfg.n_queue_to_fifo =
+			ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
+	}
+
+	/* Configure transport layer */
+	iwl_trans_configure(priv->trans, &trans_cfg);
+
+	/* At this point both hw and priv are allocated. */
+
+	SET_IEEE80211_DEV(priv->hw, priv->trans->dev);
+
+	iwl_option_config(priv);
+
+	IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
+
+	/* is antenna coupling more than 35dB ? */
+	priv->bt_ant_couple_ok =
+		(iwlwifi_mod_params.ant_coupling >
+			IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
+			true : false;
+
+	/* enable/disable bt channel inhibition */
+	priv->bt_ch_announce = iwlwifi_mod_params.bt_ch_announce;
+	IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n",
+		       (priv->bt_ch_announce) ? "On" : "Off");
+
+	/* these spin locks will be used in apm_ops.init and EEPROM access
+	 * we should init now
+	 */
+	spin_lock_init(&priv->statistics.lock);
+
+	/***********************
+	 * 2. Read REV register
+	 ***********************/
+	IWL_INFO(priv, "Detected %s, REV=0x%X\n",
+		priv->cfg->name, priv->trans->hw_rev);
+
+	if (iwl_trans_start_hw(priv->trans))
+		goto out_free_hw;
+
+	/* Read the EEPROM */
+	if (iwl_read_eeprom(priv->trans, &priv->eeprom_blob,
+			    &priv->eeprom_blob_size)) {
+		IWL_ERR(priv, "Unable to init EEPROM\n");
+		goto out_free_hw;
+	}
+
+	/* Reset chip to save power until we load uCode during "up". */
+	iwl_trans_stop_hw(priv->trans, false);
+
+	priv->eeprom_data = iwl_parse_eeprom_data(priv->trans->dev, priv->cfg,
+						  priv->eeprom_blob,
+						  priv->eeprom_blob_size);
+	if (!priv->eeprom_data)
+		goto out_free_eeprom_blob;
+
+	if (iwl_eeprom_check_version(priv->eeprom_data, priv->trans))
+		goto out_free_eeprom;
+
+	if (iwl_eeprom_init_hw_params(priv))
+		goto out_free_eeprom;
+
+	/* extract MAC Address */
+	memcpy(priv->addresses[0].addr, priv->eeprom_data->hw_addr, ETH_ALEN);
+	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 = priv->eeprom_data->n_hw_addrs;
+	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++;
+	}
+
+	/************************
+	 * 4. Setup HW constants
+	 ************************/
+	iwl_set_hw_params(priv);
+
+	if (!(priv->eeprom_data->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) {
+		IWL_DEBUG_INFO(priv, "Your EEPROM disabled PAN");
+		ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
+		/*
+		 * if not PAN, then don't support P2P -- might be a uCode
+		 * packaging bug or due to the eeprom check above
+		 */
+		ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
+		priv->sta_key_max_num = STA_KEY_MAX_NUM;
+		trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+		trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
+		trans_cfg.n_queue_to_fifo =
+			ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
+
+		/* Configure transport layer again*/
+		iwl_trans_configure(priv->trans, &trans_cfg);
+	}
+
+	/*******************
+	 * 5. Setup priv
+	 *******************/
+	for (i = 0; i < IWL_MAX_HW_QUEUES; i++) {
+		priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
+		if (i < IWLAGN_FIRST_AMPDU_QUEUE &&
+		    i != IWL_DEFAULT_CMD_QUEUE_NUM &&
+		    i != IWL_IPAN_CMD_QUEUE_NUM)
+			priv->queue_to_mac80211[i] = i;
+		atomic_set(&priv->queue_stop_count[i], 0);
+	}
+
+	WARN_ON(trans_cfg.queue_to_fifo[trans_cfg.cmd_queue] !=
+						IWLAGN_CMD_FIFO_NUM);
+
+	if (iwl_init_drv(priv))
+		goto out_free_eeprom;
+
+	/* At this point both hw and priv are initialized. */
+
+	/********************
+	 * 6. Setup services
+	 ********************/
+	iwl_setup_deferred_work(priv);
+	iwl_setup_rx_handlers(priv);
+	iwl_testmode_init(priv);
+
+	iwl_power_initialize(priv);
+	iwl_tt_initialize(priv);
+
+	snprintf(priv->hw->wiphy->fw_version,
+		 sizeof(priv->hw->wiphy->fw_version),
+		 "%s", fw->fw_version);
+
+	priv->new_scan_threshold_behaviour =
+		!!(ucode_flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
+
+	priv->phy_calib_chain_noise_reset_cmd =
+		fw->ucode_capa.standard_phy_calibration_size;
+	priv->phy_calib_chain_noise_gain_cmd =
+		fw->ucode_capa.standard_phy_calibration_size + 1;
+
+	/* initialize all valid contexts */
+	iwl_init_context(priv, ucode_flags);
+
+	/**************************************************
+	 * This is still part of probe() in a sense...
+	 *
+	 * 7. Setup and register with mac80211 and debugfs
+	 **************************************************/
+	if (iwlagn_mac_setup_register(priv, &fw->ucode_capa))
+		goto out_destroy_workqueue;
+
+	if (iwl_dbgfs_register(priv, DRV_NAME))
+		IWL_ERR(priv,
+			"failed to create debugfs files. Ignoring error\n");
+
+	return op_mode;
+
+out_destroy_workqueue:
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
+	iwl_uninit_drv(priv);
+out_free_eeprom_blob:
+	kfree(priv->eeprom_blob);
+out_free_eeprom:
+	iwl_free_eeprom_data(priv->eeprom_data);
+out_free_hw:
+	ieee80211_free_hw(priv->hw);
+out:
+	op_mode = NULL;
+	return op_mode;
+}
+
+static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+	IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
+
+	iwl_dbgfs_unregister(priv);
+
+	iwl_testmode_free(priv);
+	iwlagn_mac_unregister(priv);
+
+	iwl_tt_exit(priv);
+
+	/*This will stop the queues, move the device to low power state */
+	priv->ucode_loaded = false;
+	iwl_trans_stop_device(priv->trans);
+
+	kfree(priv->eeprom_blob);
+	iwl_free_eeprom_data(priv->eeprom_data);
+
+	/*netif_stop_queue(dev); */
+	flush_workqueue(priv->workqueue);
+
+	/* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes
+	 * priv->workqueue... so we can't take down the workqueue
+	 * until now... */
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
+
+	iwl_uninit_drv(priv);
+
+	dev_kfree_skb(priv->beacon_skb);
+
+	iwl_trans_stop_hw(priv->trans, true);
+	ieee80211_free_hw(priv->hw);
+}
+
+static const char * const desc_lookup_text[] = {
+	"OK",
+	"FAIL",
+	"BAD_PARAM",
+	"BAD_CHECKSUM",
+	"NMI_INTERRUPT_WDG",
+	"SYSASSERT",
+	"FATAL_ERROR",
+	"BAD_COMMAND",
+	"HW_ERROR_TUNE_LOCK",
+	"HW_ERROR_TEMPERATURE",
+	"ILLEGAL_CHAN_FREQ",
+	"VCC_NOT_STABLE",
+	"FH_ERROR",
+	"NMI_INTERRUPT_HOST",
+	"NMI_INTERRUPT_ACTION_PT",
+	"NMI_INTERRUPT_UNKNOWN",
+	"UCODE_VERSION_MISMATCH",
+	"HW_ERROR_ABS_LOCK",
+	"HW_ERROR_CAL_LOCK_FAIL",
+	"NMI_INTERRUPT_INST_ACTION_PT",
+	"NMI_INTERRUPT_DATA_ACTION_PT",
+	"NMI_TRM_HW_ER",
+	"NMI_INTERRUPT_TRM",
+	"NMI_INTERRUPT_BREAK_POINT",
+	"DEBUG_0",
+	"DEBUG_1",
+	"DEBUG_2",
+	"DEBUG_3",
+};
+
+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 i;
+	int max = ARRAY_SIZE(desc_lookup_text);
+
+	if (num < max)
+		return desc_lookup_text[num];
+
+	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))
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+	struct iwl_trans *trans = priv->trans;
+	u32 base;
+	struct iwl_error_event_table table;
+
+	base = priv->device_pointers.error_event_table;
+	if (priv->cur_ucode == IWL_UCODE_INIT) {
+		if (!base)
+			base = priv->fw->init_errlog_ptr;
+	} else {
+		if (!base)
+			base = priv->fw->inst_errlog_ptr;
+	}
+
+	if (!iwlagn_hw_valid_rtc_data_addr(base)) {
+		IWL_ERR(priv,
+			"Not valid error log pointer 0x%08X for %s uCode\n",
+			base,
+			(priv->cur_ucode == IWL_UCODE_INIT)
+					? "Init" : "RT");
+		return;
+	}
+
+	/*TODO: Update dbgfs with ISR error stats obtained below */
+	iwl_read_targ_mem_bytes(trans, base, &table, sizeof(table));
+
+	if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+		IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+		IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
+			priv->status, table.valid);
+	}
+
+	trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
+				      table.data1, table.data2, table.line,
+				      table.blink1, table.blink2, table.ilink1,
+				      table.ilink2, table.bcon_time, table.gp1,
+				      table.gp2, table.gp3, table.ucode_ver,
+				      table.hw_ver, table.brd_ver);
+	IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
+		desc_lookup(table.error_id));
+	IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
+	IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1);
+	IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2);
+	IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1);
+	IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2);
+	IWL_ERR(priv, "0x%08X | data1\n", table.data1);
+	IWL_ERR(priv, "0x%08X | data2\n", table.data2);
+	IWL_ERR(priv, "0x%08X | line\n", table.line);
+	IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time);
+	IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low);
+	IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi);
+	IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1);
+	IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2);
+	IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3);
+	IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver);
+	IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver);
+	IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver);
+	IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd);
+	IWL_ERR(priv, "0x%08X | isr0\n", table.isr0);
+	IWL_ERR(priv, "0x%08X | isr1\n", table.isr1);
+	IWL_ERR(priv, "0x%08X | isr2\n", table.isr2);
+	IWL_ERR(priv, "0x%08X | isr3\n", table.isr3);
+	IWL_ERR(priv, "0x%08X | isr4\n", table.isr4);
+	IWL_ERR(priv, "0x%08X | isr_pref\n", table.isr_pref);
+	IWL_ERR(priv, "0x%08X | wait_event\n", table.wait_event);
+	IWL_ERR(priv, "0x%08X | l2p_control\n", table.l2p_control);
+	IWL_ERR(priv, "0x%08X | l2p_duration\n", table.l2p_duration);
+	IWL_ERR(priv, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
+	IWL_ERR(priv, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
+	IWL_ERR(priv, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
+	IWL_ERR(priv, "0x%08X | timestamp\n", table.u_timestamp);
+	IWL_ERR(priv, "0x%08X | flow_handler\n", table.flow_handler);
+}
+
+#define EVENT_START_OFFSET  (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ */
+static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+			       u32 num_events, u32 mode,
+			       int pos, char **buf, size_t bufsz)
+{
+	u32 i;
+	u32 base;       /* SRAM byte address of event log header */
+	u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+	u32 ptr;        /* SRAM byte address of log data */
+	u32 ev, time, data; /* event log data */
+	unsigned long reg_flags;
+
+	struct iwl_trans *trans = priv->trans;
+
+	if (num_events == 0)
+		return pos;
+
+	base = priv->device_pointers.log_event_table;
+	if (priv->cur_ucode == IWL_UCODE_INIT) {
+		if (!base)
+			base = priv->fw->init_evtlog_ptr;
+	} else {
+		if (!base)
+			base = priv->fw->inst_evtlog_ptr;
+	}
+
+	if (mode == 0)
+		event_size = 2 * sizeof(u32);
+	else
+		event_size = 3 * sizeof(u32);
+
+	ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+	/* Make sure device is powered up for SRAM reads */
+	spin_lock_irqsave(&trans->reg_lock, reg_flags);
+	if (unlikely(!iwl_grab_nic_access(trans)))
+		goto out_unlock;
+
+	/* Set starting address; reads will auto-increment */
+	iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr);
+
+	/* "time" is actually "data" for mode 0 (no timestamp).
+	* place event id # at far right for easier visual parsing. */
+	for (i = 0; i < num_events; i++) {
+		ev = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+		time = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+		if (mode == 0) {
+			/* data, ev */
+			if (bufsz) {
+				pos += scnprintf(*buf + pos, bufsz - pos,
+						"EVT_LOG:0x%08x:%04u\n",
+						time, ev);
+			} else {
+				trace_iwlwifi_dev_ucode_event(trans->dev, 0,
+					time, ev);
+				IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
+					time, ev);
+			}
+		} else {
+			data = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+			if (bufsz) {
+				pos += scnprintf(*buf + pos, bufsz - pos,
+						"EVT_LOGT:%010u:0x%08x:%04u\n",
+						 time, data, ev);
+			} else {
+				IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
+					time, data, ev);
+				trace_iwlwifi_dev_ucode_event(trans->dev, time,
+					data, ev);
+			}
+		}
+	}
+
+	/* Allow device to power down */
+	iwl_release_nic_access(trans);
+out_unlock:
+	spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
+	return pos;
+}
+
+/**
+ * iwl_print_last_event_logs - Dump the newest # of event log to syslog
+ */
+static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+				    u32 num_wraps, u32 next_entry,
+				    u32 size, u32 mode,
+				    int pos, char **buf, size_t bufsz)
+{
+	/*
+	 * display the newest DEFAULT_LOG_ENTRIES entries
+	 * i.e the entries just before the next ont that uCode would fill.
+	 */
+	if (num_wraps) {
+		if (next_entry < size) {
+			pos = iwl_print_event_log(priv,
+						capacity - (size - next_entry),
+						size - next_entry, mode,
+						pos, buf, bufsz);
+			pos = iwl_print_event_log(priv, 0,
+						  next_entry, mode,
+						  pos, buf, bufsz);
+		} else
+			pos = iwl_print_event_log(priv, next_entry - size,
+						  size, mode, pos, buf, bufsz);
+	} else {
+		if (next_entry < size) {
+			pos = iwl_print_event_log(priv, 0, next_entry,
+						  mode, pos, buf, bufsz);
+		} else {
+			pos = iwl_print_event_log(priv, next_entry - size,
+						  size, mode, pos, buf, bufsz);
+		}
+	}
+	return pos;
+}
+
+#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
+
+int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+			    char **buf, bool display)
+{
+	u32 base;       /* SRAM byte address of event log header */
+	u32 capacity;   /* event log capacity in # entries */
+	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+	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;
+	struct iwl_trans *trans = priv->trans;
+
+	base = priv->device_pointers.log_event_table;
+	if (priv->cur_ucode == IWL_UCODE_INIT) {
+		logsize = priv->fw->init_evtlog_size;
+		if (!base)
+			base = priv->fw->init_evtlog_ptr;
+	} else {
+		logsize = priv->fw->inst_evtlog_size;
+		if (!base)
+			base = priv->fw->inst_evtlog_ptr;
+	}
+
+	if (!iwlagn_hw_valid_rtc_data_addr(base)) {
+		IWL_ERR(priv,
+			"Invalid event log pointer 0x%08X for %s uCode\n",
+			base,
+			(priv->cur_ucode == IWL_UCODE_INIT)
+					? "Init" : "RT");
+		return -EINVAL;
+	}
+
+	/* event log header */
+	capacity = iwl_read_targ_mem(trans, base);
+	mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32)));
+	num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32)));
+	next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32)));
+
+	if (capacity > logsize) {
+		IWL_ERR(priv, "Log capacity %d is bogus, limit to %d "
+			"entries\n", capacity, logsize);
+		capacity = logsize;
+	}
+
+	if (next_entry > logsize) {
+		IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
+			next_entry, logsize);
+		next_entry = logsize;
+	}
+
+	size = num_wraps ? capacity : next_entry;
+
+	/* bail out if nothing in log */
+	if (size == 0) {
+		IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n");
+		return pos;
+	}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (!(iwl_have_debug_level(IWL_DL_FW_ERRORS)) && !full_log)
+		size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
+			? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
+#else
+	size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
+		? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
+#endif
+	IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n",
+		size);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (display) {
+		if (full_log)
+			bufsz = capacity * 48;
+		else
+			bufsz = size * 48;
+		*buf = kmalloc(bufsz, GFP_KERNEL);
+		if (!*buf)
+			return -ENOMEM;
+	}
+	if (iwl_have_debug_level(IWL_DL_FW_ERRORS) || full_log) {
+		/*
+		 * if uCode has wrapped back to top of log,
+		 * start at the oldest entry,
+		 * i.e the next one that uCode would fill.
+		 */
+		if (num_wraps)
+			pos = iwl_print_event_log(priv, next_entry,
+						capacity - next_entry, mode,
+						pos, buf, bufsz);
+		/* (then/else) start at top of log */
+		pos = iwl_print_event_log(priv, 0,
+					  next_entry, mode, pos, buf, bufsz);
+	} else
+		pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+						next_entry, size, mode,
+						pos, buf, bufsz);
+#else
+	pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+					next_entry, size, mode,
+					pos, buf, bufsz);
+#endif
+	return pos;
+}
+
+static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
+{
+	unsigned int reload_msec;
+	unsigned long reload_jiffies;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_have_debug_level(IWL_DL_FW_ERRORS))
+		iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
+#endif
+
+	/* uCode is no longer loaded. */
+	priv->ucode_loaded = false;
+
+	/* Set the FW error flag -- cleared on iwl_down */
+	set_bit(STATUS_FW_ERROR, &priv->status);
+
+	iwl_abort_notification_waits(&priv->notif_wait);
+
+	/* Keep the restart process from trying to send host
+	 * commands by clearing the ready bit */
+	clear_bit(STATUS_READY, &priv->status);
+
+	wake_up(&priv->trans->wait_command_queue);
+
+	if (!ondemand) {
+		/*
+		 * If firmware keep reloading, then it indicate something
+		 * serious wrong and firmware having problem to recover
+		 * from it. Instead of keep trying which will fill the syslog
+		 * and hang the system, let's just stop it
+		 */
+		reload_jiffies = jiffies;
+		reload_msec = jiffies_to_msecs((long) reload_jiffies -
+					(long) priv->reload_jiffies);
+		priv->reload_jiffies = reload_jiffies;
+		if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
+			priv->reload_count++;
+			if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
+				IWL_ERR(priv, "BUG_ON, Stop restarting\n");
+				return;
+			}
+		} else
+			priv->reload_count = 0;
+	}
+
+	if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		if (iwlwifi_mod_params.restart_fw) {
+			IWL_DEBUG_FW_ERRORS(priv,
+				  "Restarting adapter due to uCode error.\n");
+			queue_work(priv->workqueue, &priv->restart);
+		} else
+			IWL_DEBUG_FW_ERRORS(priv,
+				  "Detected FW error, but not restarting\n");
+	}
+}
+
+static void iwl_nic_error(struct iwl_op_mode *op_mode)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+	IWL_ERR(priv, "Loaded firmware version: %s\n",
+		priv->fw->fw_version);
+
+	iwl_dump_nic_error_log(priv);
+	iwl_dump_nic_event_log(priv, false, NULL, false);
+
+	iwlagn_fw_error(priv, false);
+}
+
+static void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+	if (!iwl_check_for_ct_kill(priv)) {
+		IWL_ERR(priv, "Restarting adapter queue is full\n");
+		iwlagn_fw_error(priv, false);
+	}
+}
+
+#define EEPROM_RF_CONFIG_TYPE_MAX      0x3
+
+static void iwl_nic_config(struct iwl_op_mode *op_mode)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+	u16 radio_cfg = priv->eeprom_data->radio_cfg;
+
+	/* SKU Control */
+	iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
+			  CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
+			  CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP,
+			  (CSR_HW_REV_STEP(priv->trans->hw_rev) <<
+				CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) |
+			  (CSR_HW_REV_DASH(priv->trans->hw_rev) <<
+				CSR_HW_IF_CONFIG_REG_POS_MAC_DASH));
+
+	/* write radio config values to register */
+	if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) {
+		u32 reg_val =
+			EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <<
+				CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE |
+			EEPROM_RF_CFG_STEP_MSK(radio_cfg) <<
+				CSR_HW_IF_CONFIG_REG_POS_PHY_STEP |
+			EEPROM_RF_CFG_DASH_MSK(radio_cfg) <<
+				CSR_HW_IF_CONFIG_REG_POS_PHY_DASH;
+
+		iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
+				  CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE |
+				  CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
+				  CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH, reg_val);
+
+		IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n",
+			 EEPROM_RF_CFG_TYPE_MSK(radio_cfg),
+			 EEPROM_RF_CFG_STEP_MSK(radio_cfg),
+			 EEPROM_RF_CFG_DASH_MSK(radio_cfg));
+	} else {
+		WARN_ON(1);
+	}
+
+	/* set CSR_HW_CONFIG_REG for uCode use */
+	iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG,
+		    CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+		    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
+
+	/* W/A : NIC is stuck in a reset state after Early PCIe power off
+	 * (PCIe power is lost before PERST# is asserted),
+	 * causing ME FW to lose ownership and not being able to obtain it back.
+	 */
+	iwl_set_bits_mask_prph(priv->trans, APMG_PS_CTRL_REG,
+			       APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
+			       ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+
+	if (priv->lib->nic_config)
+		priv->lib->nic_config(priv);
+}
+
+static void iwl_wimax_active(struct iwl_op_mode *op_mode)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+	clear_bit(STATUS_READY, &priv->status);
+	IWL_ERR(priv, "RF is used by WiMAX\n");
+}
+
+static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+	int mq = priv->queue_to_mac80211[queue];
+
+	if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
+		return;
+
+	if (atomic_inc_return(&priv->queue_stop_count[mq]) > 1) {
+		IWL_DEBUG_TX_QUEUES(priv,
+			"queue %d (mac80211 %d) already stopped\n",
+			queue, mq);
+		return;
+	}
+
+	set_bit(mq, &priv->transport_queue_stop);
+	ieee80211_stop_queue(priv->hw, mq);
+}
+
+static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+	int mq = priv->queue_to_mac80211[queue];
+
+	if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
+		return;
+
+	if (atomic_dec_return(&priv->queue_stop_count[mq]) > 0) {
+		IWL_DEBUG_TX_QUEUES(priv,
+			"queue %d (mac80211 %d) already awake\n",
+			queue, mq);
+		return;
+	}
+
+	clear_bit(mq, &priv->transport_queue_stop);
+
+	if (!priv->passive_no_rx)
+		ieee80211_wake_queue(priv->hw, mq);
+}
+
+void iwlagn_lift_passive_no_rx(struct iwl_priv *priv)
+{
+	int mq;
+
+	if (!priv->passive_no_rx)
+		return;
+
+	for (mq = 0; mq < IWLAGN_FIRST_AMPDU_QUEUE; mq++) {
+		if (!test_bit(mq, &priv->transport_queue_stop)) {
+			IWL_DEBUG_TX_QUEUES(priv, "Wake queue %d", mq);
+			ieee80211_wake_queue(priv->hw, mq);
+		} else {
+			IWL_DEBUG_TX_QUEUES(priv, "Don't wake queue %d", mq);
+		}
+	}
+
+	priv->passive_no_rx = false;
+}
+
+static void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+	struct ieee80211_tx_info *info;
+
+	info = IEEE80211_SKB_CB(skb);
+	iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
+	dev_kfree_skb_any(skb);
+}
+
+static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+	if (state)
+		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, state);
+}
+
+static const struct iwl_op_mode_ops iwl_dvm_ops = {
+	.start = iwl_op_mode_dvm_start,
+	.stop = iwl_op_mode_dvm_stop,
+	.rx = iwl_rx_dispatch,
+	.queue_full = iwl_stop_sw_queue,
+	.queue_not_full = iwl_wake_sw_queue,
+	.hw_rf_kill = iwl_set_hw_rfkill_state,
+	.free_skb = iwl_free_skb,
+	.nic_error = iwl_nic_error,
+	.cmd_queue_full = iwl_cmd_queue_full,
+	.nic_config = iwl_nic_config,
+	.wimax_active = iwl_wimax_active,
+};
+
+/*****************************************************************************
+ *
+ * driver and module entry point
+ *
+ *****************************************************************************/
+static int __init iwl_init(void)
+{
+
+	int ret;
+	pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+	pr_info(DRV_COPYRIGHT "\n");
+
+	ret = iwlagn_rate_control_register();
+	if (ret) {
+		pr_err("Unable to register rate control algorithm: %d\n", ret);
+		return ret;
+	}
+
+	ret = iwl_opmode_register("iwldvm", &iwl_dvm_ops);
+	if (ret) {
+		pr_err("Unable to register op_mode: %d\n", ret);
+		iwlagn_rate_control_unregister();
+	}
+
+	return ret;
+}
+module_init(iwl_init);
+
+static void __exit iwl_exit(void)
+{
+	iwl_opmode_deregister("iwldvm");
+	iwlagn_rate_control_unregister();
+}
+module_exit(iwl_exit);
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c
new file mode 100644
index 0000000..518cf37
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/power.c
@@ -0,0 +1,387 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <net/mac80211.h>
+#include "iwl-io.h"
+#include "iwl-debug.h"
+#include "iwl-trans.h"
+#include "iwl-modparams.h"
+#include "dev.h"
+#include "agn.h"
+#include "commands.h"
+#include "power.h"
+
+/*
+ * Setting power level allows the card to go to sleep when not busy.
+ *
+ * We calculate a sleep command based on the required latency, which
+ * we get from mac80211. In order to handle thermal throttling, we can
+ * also use pre-defined power levels.
+ */
+
+/*
+ * This defines the old power levels. They are still used by default
+ * (level 1) and for thermal throttle (levels 3 through 5)
+ */
+
+struct iwl_power_vec_entry {
+	struct iwl_powertable_cmd cmd;
+	u8 no_dtim;	/* number of skip dtim */
+};
+
+#define IWL_DTIM_RANGE_0_MAX	2
+#define IWL_DTIM_RANGE_1_MAX	10
+
+#define NOSLP cpu_to_le16(0), 0, 0
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
+#define ASLP (IWL_POWER_POWER_SAVE_ENA_MSK |	\
+		IWL_POWER_POWER_MANAGEMENT_ENA_MSK | \
+		IWL_POWER_ADVANCE_PM_ENA_MSK)
+#define ASLP_TOUT(T) cpu_to_le32(T)
+#define TU_TO_USEC 1024
+#define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \
+				     cpu_to_le32(X1), \
+				     cpu_to_le32(X2), \
+				     cpu_to_le32(X3), \
+				     cpu_to_le32(X4)}
+/* default power management (not Tx power) table values */
+/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */
+/* DTIM 0 - 2 */
+static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
+	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 1, 2, 2, 0xFF)}, 0},
+	{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
+	{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0},
+	{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1},
+	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 2, 4, 6, 0xFF)}, 2}
+};
+
+
+/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
+/* DTIM 3 - 10 */
+static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
+	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
+	{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
+	{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0},
+	{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1},
+	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 6, 10, 10)}, 2}
+};
+
+/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
+/* DTIM 11 - */
+static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
+	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
+	{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
+	{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+	{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
+};
+
+/* advance power management */
+/* DTIM 0 - 2 */
+static const struct iwl_power_vec_entry apm_range_0[IWL_POWER_NUM] = {
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
+};
+
+
+/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
+/* DTIM 3 - 10 */
+static const struct iwl_power_vec_entry apm_range_1[IWL_POWER_NUM] = {
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 6, 8, 0xFF), 0}, 2}
+};
+
+/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
+/* DTIM 11 - */
+static const struct iwl_power_vec_entry apm_range_2[IWL_POWER_NUM] = {
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+		SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
+};
+
+static void iwl_static_sleep_cmd(struct iwl_priv *priv,
+				 struct iwl_powertable_cmd *cmd,
+				 enum iwl_power_level lvl, int period)
+{
+	const struct iwl_power_vec_entry *table;
+	int max_sleep[IWL_POWER_VEC_SIZE] = { 0 };
+	int i;
+	u8 skip;
+	u32 slp_itrvl;
+
+	if (priv->cfg->adv_pm) {
+		table = apm_range_2;
+		if (period <= IWL_DTIM_RANGE_1_MAX)
+			table = apm_range_1;
+		if (period <= IWL_DTIM_RANGE_0_MAX)
+			table = apm_range_0;
+	} else {
+		table = range_2;
+		if (period <= IWL_DTIM_RANGE_1_MAX)
+			table = range_1;
+		if (period <= IWL_DTIM_RANGE_0_MAX)
+			table = range_0;
+	}
+
+	if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM))
+		memset(cmd, 0, sizeof(*cmd));
+	else
+		*cmd = table[lvl].cmd;
+
+	if (period == 0) {
+		skip = 0;
+		period = 1;
+		for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
+			max_sleep[i] =  1;
+
+	} else {
+		skip = table[lvl].no_dtim;
+		for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
+			max_sleep[i] = le32_to_cpu(cmd->sleep_interval[i]);
+		max_sleep[IWL_POWER_VEC_SIZE - 1] = skip + 1;
+	}
+
+	slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
+	/* figure out the listen interval based on dtim period and skip */
+	if (slp_itrvl == 0xFF)
+		cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
+			cpu_to_le32(period * (skip + 1));
+
+	slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
+	if (slp_itrvl > period)
+		cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
+			cpu_to_le32((slp_itrvl / period) * period);
+
+	if (skip)
+		cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
+	else
+		cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+
+	if (priv->cfg->base_params->shadow_reg_enable)
+		cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
+	else
+		cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
+
+	if (iwl_advanced_bt_coexist(priv)) {
+		if (!priv->cfg->bt_params->bt_sco_disable)
+			cmd->flags |= IWL_POWER_BT_SCO_ENA;
+		else
+			cmd->flags &= ~IWL_POWER_BT_SCO_ENA;
+	}
+
+
+	slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
+	if (slp_itrvl > IWL_CONN_MAX_LISTEN_INTERVAL)
+		cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
+			cpu_to_le32(IWL_CONN_MAX_LISTEN_INTERVAL);
+
+	/* enforce max sleep interval */
+	for (i = IWL_POWER_VEC_SIZE - 1; i >= 0 ; i--) {
+		if (le32_to_cpu(cmd->sleep_interval[i]) >
+		    (max_sleep[i] * period))
+			cmd->sleep_interval[i] =
+				cpu_to_le32(max_sleep[i] * period);
+		if (i != (IWL_POWER_VEC_SIZE - 1)) {
+			if (le32_to_cpu(cmd->sleep_interval[i]) >
+			    le32_to_cpu(cmd->sleep_interval[i+1]))
+				cmd->sleep_interval[i] =
+					cmd->sleep_interval[i+1];
+		}
+	}
+
+	if (priv->power_data.bus_pm)
+		cmd->flags |= IWL_POWER_PCI_PM_MSK;
+	else
+		cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+
+	IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n",
+			skip, period);
+	/* The power level here is 0-4 (used as array index), but user expects
+	to see 1-5 (according to spec). */
+	IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
+}
+
+static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv,
+				    struct iwl_powertable_cmd *cmd)
+{
+	memset(cmd, 0, sizeof(*cmd));
+
+	if (priv->power_data.bus_pm)
+		cmd->flags |= IWL_POWER_PCI_PM_MSK;
+
+	IWL_DEBUG_POWER(priv, "Sleep command for CAM\n");
+}
+
+static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
+{
+	IWL_DEBUG_POWER(priv, "Sending power/sleep command\n");
+	IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags);
+	IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
+	IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
+	IWL_DEBUG_POWER(priv, "Sleep interval vector = { %d , %d , %d , %d , %d }\n",
+			le32_to_cpu(cmd->sleep_interval[0]),
+			le32_to_cpu(cmd->sleep_interval[1]),
+			le32_to_cpu(cmd->sleep_interval[2]),
+			le32_to_cpu(cmd->sleep_interval[3]),
+			le32_to_cpu(cmd->sleep_interval[4]));
+
+	return iwl_dvm_send_cmd_pdu(priv, POWER_TABLE_CMD, CMD_SYNC,
+				sizeof(struct iwl_powertable_cmd), cmd);
+}
+
+static void iwl_power_build_cmd(struct iwl_priv *priv,
+				struct iwl_powertable_cmd *cmd)
+{
+	bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
+	int dtimper;
+
+	dtimper = priv->hw->conf.ps_dtim_period ?: 1;
+
+	if (priv->wowlan)
+		iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper);
+	else if (!priv->cfg->base_params->no_idle_support &&
+		 priv->hw->conf.flags & IEEE80211_CONF_IDLE)
+		iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
+	else if (iwl_tt_is_low_power_state(priv)) {
+		/* in thermal throttling low power state */
+		iwl_static_sleep_cmd(priv, cmd,
+		    iwl_tt_current_power_mode(priv), dtimper);
+	} else if (!enabled)
+		iwl_power_sleep_cam_cmd(priv, cmd);
+	else if (priv->power_data.debug_sleep_level_override >= 0)
+		iwl_static_sleep_cmd(priv, cmd,
+				     priv->power_data.debug_sleep_level_override,
+				     dtimper);
+	else {
+		/* Note that the user parameter is 1-5 (according to spec),
+		but we pass 0-4 because it acts as an array index. */
+		if (iwlwifi_mod_params.power_level > IWL_POWER_INDEX_1 &&
+		    iwlwifi_mod_params.power_level <= IWL_POWER_NUM)
+			iwl_static_sleep_cmd(priv, cmd,
+				iwlwifi_mod_params.power_level - 1, dtimper);
+		else
+			iwl_static_sleep_cmd(priv, cmd,
+				IWL_POWER_INDEX_1, dtimper);
+	}
+}
+
+int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
+		       bool force)
+{
+	int ret;
+	bool update_chains;
+
+	lockdep_assert_held(&priv->mutex);
+
+	/* Don't update the RX chain when chain noise calibration is running */
+	update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
+			priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
+
+	if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force)
+		return 0;
+
+	if (!iwl_is_ready_rf(priv))
+		return -EIO;
+
+	/* scan complete use sleep_power_next, need to be updated */
+	memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd));
+	if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
+		IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
+		return 0;
+	}
+
+	if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
+		iwl_dvm_set_pmi(priv, true);
+
+	ret = iwl_set_power(priv, cmd);
+	if (!ret) {
+		if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
+			iwl_dvm_set_pmi(priv, false);
+
+		if (update_chains)
+			iwl_update_chain_flags(priv);
+		else
+			IWL_DEBUG_POWER(priv,
+					"Cannot update the power, chain noise "
+					"calibration running: %d\n",
+					priv->chain_noise_data.state);
+
+		memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd));
+	} else
+		IWL_ERR(priv, "set power fail, ret = %d", ret);
+
+	return ret;
+}
+
+int iwl_power_update_mode(struct iwl_priv *priv, bool force)
+{
+	struct iwl_powertable_cmd cmd;
+
+	iwl_power_build_cmd(priv, &cmd);
+	return iwl_power_set_mode(priv, &cmd, force);
+}
+
+/* initialize to default */
+void iwl_power_initialize(struct iwl_priv *priv)
+{
+	priv->power_data.bus_pm = priv->trans->pm_support;
+
+	priv->power_data.debug_sleep_level_override = -1;
+
+	memset(&priv->power_data.sleep_cmd, 0,
+		sizeof(priv->power_data.sleep_cmd));
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.h b/drivers/net/wireless/iwlwifi/dvm/power.h
new file mode 100644
index 0000000..a2cee7f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/power.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+#ifndef __iwl_power_setting_h__
+#define __iwl_power_setting_h__
+
+#include "commands.h"
+
+struct iwl_power_mgr {
+	struct iwl_powertable_cmd sleep_cmd;
+	struct iwl_powertable_cmd sleep_cmd_next;
+	int debug_sleep_level_override;
+	bool bus_pm;
+};
+
+int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
+		       bool force);
+int iwl_power_update_mode(struct iwl_priv *priv, bool force);
+void iwl_power_initialize(struct iwl_priv *priv);
+
+extern bool no_sleep_autoadjust;
+
+#endif  /* __iwl_power_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c
new file mode 100644
index 0000000..6fddd27
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/rs.c
@@ -0,0 +1,3367 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2012 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.
+ *
+ * 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/init.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <net/mac80211.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#include <linux/workqueue.h>
+
+#include "dev.h"
+#include "agn.h"
+
+#define RS_NAME "iwl-agn-rs"
+
+#define NUM_TRY_BEFORE_ANT_TOGGLE 1
+#define IWL_NUMBER_TRY      1
+#define IWL_HT_NUMBER_TRY   3
+
+#define IWL_RATE_MAX_WINDOW		62	/* # tx in history window */
+#define IWL_RATE_MIN_FAILURE_TH		6	/* min failures to calc tpt */
+#define IWL_RATE_MIN_SUCCESS_TH		8	/* min successes to calc tpt */
+
+/* max allowed rate miss before sync LQ cmd */
+#define IWL_MISSED_RATE_MAX		15
+/* max time to accum history 2 seconds */
+#define IWL_RATE_SCALE_FLUSH_INTVL   (3*HZ)
+
+static u8 rs_ht_to_legacy[] = {
+	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+	IWL_RATE_6M_INDEX,
+	IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX,
+	IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX,
+	IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX,
+	IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
+};
+
+static const u8 ant_toggle_lookup[] = {
+	/*ANT_NONE -> */ ANT_NONE,
+	/*ANT_A    -> */ ANT_B,
+	/*ANT_B    -> */ ANT_C,
+	/*ANT_AB   -> */ ANT_BC,
+	/*ANT_C    -> */ ANT_A,
+	/*ANT_AC   -> */ ANT_AB,
+	/*ANT_BC   -> */ ANT_AC,
+	/*ANT_ABC  -> */ ANT_ABC,
+};
+
+#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
+	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
+				    IWL_RATE_SISO_##s##M_PLCP, \
+				    IWL_RATE_MIMO2_##s##M_PLCP,\
+				    IWL_RATE_MIMO3_##s##M_PLCP,\
+				    IWL_RATE_##r##M_IEEE,      \
+				    IWL_RATE_##ip##M_INDEX,    \
+				    IWL_RATE_##in##M_INDEX,    \
+				    IWL_RATE_##rp##M_INDEX,    \
+				    IWL_RATE_##rn##M_INDEX,    \
+				    IWL_RATE_##pp##M_INDEX,    \
+				    IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+	IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
+	IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
+	IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
+	IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */
+	IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
+	IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */
+	IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
+	IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
+	IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
+	IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
+	IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
+	IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+	IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
+	/* FIXME:RS:          ^^    should be INV (legacy) */
+};
+
+static inline u8 rs_extract_rate(u32 rate_n_flags)
+{
+	return (u8)(rate_n_flags & RATE_MCS_RATE_MSK);
+}
+
+static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
+{
+	int idx = 0;
+
+	/* HT rate format */
+	if (rate_n_flags & RATE_MCS_HT_MSK) {
+		idx = rs_extract_rate(rate_n_flags);
+
+		if (idx >= IWL_RATE_MIMO3_6M_PLCP)
+			idx = idx - IWL_RATE_MIMO3_6M_PLCP;
+		else if (idx >= IWL_RATE_MIMO2_6M_PLCP)
+			idx = idx - IWL_RATE_MIMO2_6M_PLCP;
+
+		idx += IWL_FIRST_OFDM_RATE;
+		/* skip 9M not supported in ht*/
+		if (idx >= IWL_RATE_9M_INDEX)
+			idx += 1;
+		if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE))
+			return idx;
+
+	/* legacy rate format, search for match in table */
+	} else {
+		for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
+			if (iwl_rates[idx].plcp ==
+					rs_extract_rate(rate_n_flags))
+				return idx;
+	}
+
+	return -1;
+}
+
+static void rs_rate_scale_perform(struct iwl_priv *priv,
+				   struct sk_buff *skb,
+				   struct ieee80211_sta *sta,
+				   struct iwl_lq_sta *lq_sta);
+static void rs_fill_link_cmd(struct iwl_priv *priv,
+			     struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
+
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+			     u32 *rate_n_flags, int index);
+#else
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+			     u32 *rate_n_flags, int index)
+{}
+#endif
+
+/**
+ * The following tables contain the expected throughput metrics for all rates
+ *
+ *	1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
+ *
+ * where invalid entries are zeros.
+ *
+ * CCK rates are only valid in legacy table and will only be used in G
+ * (2.4 GHz) band.
+ */
+
+static s32 expected_tpt_legacy[IWL_RATE_COUNT] = {
+	7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0
+};
+
+static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0, 42, 0,  76, 102, 124, 159, 183, 193, 202}, /* Norm */
+	{0, 0, 0, 0, 46, 0,  82, 110, 132, 168, 192, 202, 210}, /* SGI */
+	{0, 0, 0, 0, 47, 0,  91, 133, 171, 242, 305, 334, 362}, /* AGG */
+	{0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0,  77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */
+	{0, 0, 0, 0,  83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */
+	{0, 0, 0, 0,  94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */
+	{0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0,  74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */
+	{0, 0, 0, 0,  81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */
+	{0, 0, 0, 0,  89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */
+	{0, 0, 0, 0,  97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/
+};
+
+static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */
+	{0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */
+	{0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */
+	{0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0,  99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */
+	{0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */
+	{0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */
+	{0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0, 152, 0, 211, 239, 255, 279,  290,  294,  297}, /* Norm */
+	{0, 0, 0, 0, 160, 0, 219, 245, 261, 284,  294,  297,  300}, /* SGI */
+	{0, 0, 0, 0, 254, 0, 443, 584, 695, 868,  984, 1030, 1070}, /* AGG */
+	{0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */
+};
+
+/* mbps, mcs */
+static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
+	{  "1", "BPSK DSSS"},
+	{  "2", "QPSK DSSS"},
+	{"5.5", "BPSK CCK"},
+	{ "11", "QPSK CCK"},
+	{  "6", "BPSK 1/2"},
+	{  "9", "BPSK 1/2"},
+	{ "12", "QPSK 1/2"},
+	{ "18", "QPSK 3/4"},
+	{ "24", "16QAM 1/2"},
+	{ "36", "16QAM 3/4"},
+	{ "48", "64QAM 2/3"},
+	{ "54", "64QAM 3/4"},
+	{ "60", "64QAM 5/6"},
+};
+
+#define MCS_INDEX_PER_STREAM	(8)
+
+static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
+{
+	window->data = 0;
+	window->success_counter = 0;
+	window->success_ratio = IWL_INVALID_VALUE;
+	window->counter = 0;
+	window->average_tpt = IWL_INVALID_VALUE;
+	window->stamp = 0;
+}
+
+static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
+{
+	return (ant_type & valid_antenna) == ant_type;
+}
+
+/*
+ *	removes the old data from the statistics. All data that is older than
+ *	TID_MAX_TIME_DIFF, will be deleted.
+ */
+static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time)
+{
+	/* The oldest age we want to keep */
+	u32 oldest_time = curr_time - TID_MAX_TIME_DIFF;
+
+	while (tl->queue_count &&
+	       (tl->time_stamp < oldest_time)) {
+		tl->total -= tl->packet_count[tl->head];
+		tl->packet_count[tl->head] = 0;
+		tl->time_stamp += TID_QUEUE_CELL_SPACING;
+		tl->queue_count--;
+		tl->head++;
+		if (tl->head >= TID_QUEUE_MAX_SIZE)
+			tl->head = 0;
+	}
+}
+
+/*
+ *	increment traffic load value for tid and also remove
+ *	any old values if passed the certain time period
+ */
+static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
+			   struct ieee80211_hdr *hdr)
+{
+	u32 curr_time = jiffies_to_msecs(jiffies);
+	u32 time_diff;
+	s32 index;
+	struct iwl_traffic_load *tl = NULL;
+	u8 tid;
+
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		u8 *qc = ieee80211_get_qos_ctl(hdr);
+		tid = qc[0] & 0xf;
+	} else
+		return IWL_MAX_TID_COUNT;
+
+	if (unlikely(tid >= IWL_MAX_TID_COUNT))
+		return IWL_MAX_TID_COUNT;
+
+	tl = &lq_data->load[tid];
+
+	curr_time -= curr_time % TID_ROUND_VALUE;
+
+	/* Happens only for the first packet. Initialize the data */
+	if (!(tl->queue_count)) {
+		tl->total = 1;
+		tl->time_stamp = curr_time;
+		tl->queue_count = 1;
+		tl->head = 0;
+		tl->packet_count[0] = 1;
+		return IWL_MAX_TID_COUNT;
+	}
+
+	time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
+	index = time_diff / TID_QUEUE_CELL_SPACING;
+
+	/* The history is too long: remove data that is older than */
+	/* TID_MAX_TIME_DIFF */
+	if (index >= TID_QUEUE_MAX_SIZE)
+		rs_tl_rm_old_stats(tl, curr_time);
+
+	index = (tl->head + index) % TID_QUEUE_MAX_SIZE;
+	tl->packet_count[index] = tl->packet_count[index] + 1;
+	tl->total = tl->total + 1;
+
+	if ((index + 1) > tl->queue_count)
+		tl->queue_count = index + 1;
+
+	return tid;
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+/**
+ * Program the device to use fixed rate for frame transmit
+ * This is for debugging/testing only
+ * once the device start use fixed rate, we need to reload the module
+ * to being back the normal operation.
+ */
+static void rs_program_fix_rate(struct iwl_priv *priv,
+				struct iwl_lq_sta *lq_sta)
+{
+	struct iwl_station_priv *sta_priv =
+		container_of(lq_sta, struct iwl_station_priv, lq_sta);
+	struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+	lq_sta->active_legacy_rate = 0x0FFF;	/* 1 - 54 MBits, includes CCK */
+	lq_sta->active_siso_rate   = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
+	lq_sta->active_mimo2_rate  = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
+	lq_sta->active_mimo3_rate  = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
+
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+	/* testmode has higher priority to overwirte the fixed rate */
+	if (priv->tm_fixed_rate)
+		lq_sta->dbg_fixed_rate = priv->tm_fixed_rate;
+#endif
+
+	IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
+		lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
+
+	if (lq_sta->dbg_fixed_rate) {
+		rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
+		iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
+				false);
+	}
+}
+#endif
+
+/*
+	get the traffic load value for tid
+*/
+static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid)
+{
+	u32 curr_time = jiffies_to_msecs(jiffies);
+	u32 time_diff;
+	s32 index;
+	struct iwl_traffic_load *tl = NULL;
+
+	if (tid >= IWL_MAX_TID_COUNT)
+		return 0;
+
+	tl = &(lq_data->load[tid]);
+
+	curr_time -= curr_time % TID_ROUND_VALUE;
+
+	if (!(tl->queue_count))
+		return 0;
+
+	time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
+	index = time_diff / TID_QUEUE_CELL_SPACING;
+
+	/* The history is too long: remove data that is older than */
+	/* TID_MAX_TIME_DIFF */
+	if (index >= TID_QUEUE_MAX_SIZE)
+		rs_tl_rm_old_stats(tl, curr_time);
+
+	return tl->total;
+}
+
+static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
+				      struct iwl_lq_sta *lq_data, u8 tid,
+				      struct ieee80211_sta *sta)
+{
+	int ret = -EAGAIN;
+	u32 load;
+
+	/*
+	 * Don't create TX aggregation sessions when in high
+	 * BT traffic, as they would just be disrupted by BT.
+	 */
+	if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) {
+		IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n",
+			priv->bt_traffic_load);
+		return ret;
+	}
+
+	load = rs_tl_get_load(lq_data, tid);
+
+	if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) {
+		IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
+				sta->addr, tid);
+		ret = ieee80211_start_tx_ba_session(sta, tid, 5000);
+		if (ret == -EAGAIN) {
+			/*
+			 * driver and mac80211 is out of sync
+			 * this might be cause by reloading firmware
+			 * stop the tx ba session here
+			 */
+			IWL_ERR(priv, "Fail start Tx agg on tid: %d\n",
+				tid);
+			ieee80211_stop_tx_ba_session(sta, tid);
+		}
+	} else {
+		IWL_DEBUG_HT(priv, "Aggregation not enabled for tid %d "
+			"because load = %u\n", tid, load);
+	}
+	return ret;
+}
+
+static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
+			      struct iwl_lq_sta *lq_data,
+			      struct ieee80211_sta *sta)
+{
+	if (tid < IWL_MAX_TID_COUNT)
+		rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
+	else
+		IWL_ERR(priv, "tid exceeds max TID count: %d/%d\n",
+			tid, IWL_MAX_TID_COUNT);
+}
+
+static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
+{
+	return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
+	       !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
+	       !!(rate_n_flags & RATE_MCS_ANT_C_MSK);
+}
+
+/*
+ * Static function to get the expected throughput from an iwl_scale_tbl_info
+ * that wraps a NULL pointer check
+ */
+static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
+{
+	if (tbl->expected_tpt)
+		return tbl->expected_tpt[rs_index];
+	return 0;
+}
+
+/**
+ * rs_collect_tx_data - Update the success/failure sliding window
+ *
+ * We keep a sliding window of the last 62 packets transmitted
+ * at this rate.  window->data contains the bitmask of successful
+ * packets.
+ */
+static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
+			      int scale_index, int attempts, int successes)
+{
+	struct iwl_rate_scale_data *window = NULL;
+	static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
+	s32 fail_count, tpt;
+
+	if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
+		return -EINVAL;
+
+	/* Select window for current tx bit rate */
+	window = &(tbl->win[scale_index]);
+
+	/* Get expected throughput */
+	tpt = get_expected_tpt(tbl, scale_index);
+
+	/*
+	 * Keep track of only the latest 62 tx frame attempts in this rate's
+	 * history window; anything older isn't really relevant any more.
+	 * If we have filled up the sliding window, drop the oldest attempt;
+	 * if the oldest attempt (highest bit in bitmap) shows "success",
+	 * subtract "1" from the success counter (this is the main reason
+	 * we keep these bitmaps!).
+	 */
+	while (attempts > 0) {
+		if (window->counter >= IWL_RATE_MAX_WINDOW) {
+
+			/* remove earliest */
+			window->counter = IWL_RATE_MAX_WINDOW - 1;
+
+			if (window->data & mask) {
+				window->data &= ~mask;
+				window->success_counter--;
+			}
+		}
+
+		/* Increment frames-attempted counter */
+		window->counter++;
+
+		/* Shift bitmap by one frame to throw away oldest history */
+		window->data <<= 1;
+
+		/* Mark the most recent #successes attempts as successful */
+		if (successes > 0) {
+			window->success_counter++;
+			window->data |= 0x1;
+			successes--;
+		}
+
+		attempts--;
+	}
+
+	/* Calculate current success ratio, avoid divide-by-0! */
+	if (window->counter > 0)
+		window->success_ratio = 128 * (100 * window->success_counter)
+					/ window->counter;
+	else
+		window->success_ratio = IWL_INVALID_VALUE;
+
+	fail_count = window->counter - window->success_counter;
+
+	/* Calculate average throughput, if we have enough history. */
+	if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
+	    (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
+		window->average_tpt = (window->success_ratio * tpt + 64) / 128;
+	else
+		window->average_tpt = IWL_INVALID_VALUE;
+
+	/* Tag this window as having been updated */
+	window->stamp = jiffies;
+
+	return 0;
+}
+
+/*
+ * Fill uCode API rate_n_flags field, based on "search" or "active" table.
+ */
+/* FIXME:RS:remove this function and put the flags statically in the table */
+static u32 rate_n_flags_from_tbl(struct iwl_priv *priv,
+				 struct iwl_scale_tbl_info *tbl,
+				 int index, u8 use_green)
+{
+	u32 rate_n_flags = 0;
+
+	if (is_legacy(tbl->lq_type)) {
+		rate_n_flags = iwl_rates[index].plcp;
+		if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
+			rate_n_flags |= RATE_MCS_CCK_MSK;
+
+	} else if (is_Ht(tbl->lq_type)) {
+		if (index > IWL_LAST_OFDM_RATE) {
+			IWL_ERR(priv, "Invalid HT rate index %d\n", index);
+			index = IWL_LAST_OFDM_RATE;
+		}
+		rate_n_flags = RATE_MCS_HT_MSK;
+
+		if (is_siso(tbl->lq_type))
+			rate_n_flags |=	iwl_rates[index].plcp_siso;
+		else if (is_mimo2(tbl->lq_type))
+			rate_n_flags |=	iwl_rates[index].plcp_mimo2;
+		else
+			rate_n_flags |=	iwl_rates[index].plcp_mimo3;
+	} else {
+		IWL_ERR(priv, "Invalid tbl->lq_type %d\n", tbl->lq_type);
+	}
+
+	rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) &
+						     RATE_MCS_ANT_ABC_MSK);
+
+	if (is_Ht(tbl->lq_type)) {
+		if (tbl->is_ht40) {
+			if (tbl->is_dup)
+				rate_n_flags |= RATE_MCS_DUP_MSK;
+			else
+				rate_n_flags |= RATE_MCS_HT40_MSK;
+		}
+		if (tbl->is_SGI)
+			rate_n_flags |= RATE_MCS_SGI_MSK;
+
+		if (use_green) {
+			rate_n_flags |= RATE_MCS_GF_MSK;
+			if (is_siso(tbl->lq_type) && tbl->is_SGI) {
+				rate_n_flags &= ~RATE_MCS_SGI_MSK;
+				IWL_ERR(priv, "GF was set with SGI:SISO\n");
+			}
+		}
+	}
+	return rate_n_flags;
+}
+
+/*
+ * Interpret uCode API's rate_n_flags format,
+ * fill "search" or "active" tx mode table.
+ */
+static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
+				    enum ieee80211_band band,
+				    struct iwl_scale_tbl_info *tbl,
+				    int *rate_idx)
+{
+	u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK);
+	u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
+	u8 mcs;
+
+	memset(tbl, 0, sizeof(struct iwl_scale_tbl_info));
+	*rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
+
+	if (*rate_idx  == IWL_RATE_INVALID) {
+		*rate_idx = -1;
+		return -EINVAL;
+	}
+	tbl->is_SGI = 0;	/* default legacy setup */
+	tbl->is_ht40 = 0;
+	tbl->is_dup = 0;
+	tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
+	tbl->lq_type = LQ_NONE;
+	tbl->max_search = IWL_MAX_SEARCH;
+
+	/* legacy rate format */
+	if (!(rate_n_flags & RATE_MCS_HT_MSK)) {
+		if (num_of_ant == 1) {
+			if (band == IEEE80211_BAND_5GHZ)
+				tbl->lq_type = LQ_A;
+			else
+				tbl->lq_type = LQ_G;
+		}
+	/* HT rate format */
+	} else {
+		if (rate_n_flags & RATE_MCS_SGI_MSK)
+			tbl->is_SGI = 1;
+
+		if ((rate_n_flags & RATE_MCS_HT40_MSK) ||
+		    (rate_n_flags & RATE_MCS_DUP_MSK))
+			tbl->is_ht40 = 1;
+
+		if (rate_n_flags & RATE_MCS_DUP_MSK)
+			tbl->is_dup = 1;
+
+		mcs = rs_extract_rate(rate_n_flags);
+
+		/* SISO */
+		if (mcs <= IWL_RATE_SISO_60M_PLCP) {
+			if (num_of_ant == 1)
+				tbl->lq_type = LQ_SISO; /*else NONE*/
+		/* MIMO2 */
+		} else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) {
+			if (num_of_ant == 2)
+				tbl->lq_type = LQ_MIMO2;
+		/* MIMO3 */
+		} else {
+			if (num_of_ant == 3) {
+				tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
+				tbl->lq_type = LQ_MIMO3;
+			}
+		}
+	}
+	return 0;
+}
+
+/* switch to another antenna/antennas and return 1 */
+/* if no other valid antenna found, return 0 */
+static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
+			     struct iwl_scale_tbl_info *tbl)
+{
+	u8 new_ant_type;
+
+	if (!tbl->ant_type || tbl->ant_type > ANT_ABC)
+		return 0;
+
+	if (!rs_is_valid_ant(valid_ant, tbl->ant_type))
+		return 0;
+
+	new_ant_type = ant_toggle_lookup[tbl->ant_type];
+
+	while ((new_ant_type != tbl->ant_type) &&
+	       !rs_is_valid_ant(valid_ant, new_ant_type))
+		new_ant_type = ant_toggle_lookup[new_ant_type];
+
+	if (new_ant_type == tbl->ant_type)
+		return 0;
+
+	tbl->ant_type = new_ant_type;
+	*rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK;
+	*rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS;
+	return 1;
+}
+
+/**
+ * Green-field mode is valid if the station supports it and
+ * there are no non-GF stations present in the BSS.
+ */
+static bool rs_use_green(struct ieee80211_sta *sta)
+{
+	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+	struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+	return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
+		!(ctx->ht.non_gf_sta_present);
+}
+
+/**
+ * rs_get_supported_rates - get the available rates
+ *
+ * if management frame or broadcast frame only return
+ * basic available rates.
+ *
+ */
+static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
+				  struct ieee80211_hdr *hdr,
+				  enum iwl_table_type rate_type)
+{
+	if (is_legacy(rate_type)) {
+		return lq_sta->active_legacy_rate;
+	} else {
+		if (is_siso(rate_type))
+			return lq_sta->active_siso_rate;
+		else if (is_mimo2(rate_type))
+			return lq_sta->active_mimo2_rate;
+		else
+			return lq_sta->active_mimo3_rate;
+	}
+}
+
+static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,
+				int rate_type)
+{
+	u8 high = IWL_RATE_INVALID;
+	u8 low = IWL_RATE_INVALID;
+
+	/* 802.11A or ht walks to the next literal adjacent rate in
+	 * the rate table */
+	if (is_a_band(rate_type) || !is_legacy(rate_type)) {
+		int i;
+		u32 mask;
+
+		/* Find the previous rate that is in the rate mask */
+		i = index - 1;
+		for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+			if (rate_mask & mask) {
+				low = i;
+				break;
+			}
+		}
+
+		/* Find the next rate that is in the rate mask */
+		i = index + 1;
+		for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
+			if (rate_mask & mask) {
+				high = i;
+				break;
+			}
+		}
+
+		return (high << 8) | low;
+	}
+
+	low = index;
+	while (low != IWL_RATE_INVALID) {
+		low = iwl_rates[low].prev_rs;
+		if (low == IWL_RATE_INVALID)
+			break;
+		if (rate_mask & (1 << low))
+			break;
+		IWL_DEBUG_RATE(priv, "Skipping masked lower rate: %d\n", low);
+	}
+
+	high = index;
+	while (high != IWL_RATE_INVALID) {
+		high = iwl_rates[high].next_rs;
+		if (high == IWL_RATE_INVALID)
+			break;
+		if (rate_mask & (1 << high))
+			break;
+		IWL_DEBUG_RATE(priv, "Skipping masked higher rate: %d\n", high);
+	}
+
+	return (high << 8) | low;
+}
+
+static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
+			     struct iwl_scale_tbl_info *tbl,
+			     u8 scale_index, u8 ht_possible)
+{
+	s32 low;
+	u16 rate_mask;
+	u16 high_low;
+	u8 switch_to_legacy = 0;
+	u8 is_green = lq_sta->is_green;
+	struct iwl_priv *priv = lq_sta->drv;
+
+	/* check if we need to switch from HT to legacy rates.
+	 * assumption is that mandatory rates (1Mbps or 6Mbps)
+	 * are always supported (spec demand) */
+	if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
+		switch_to_legacy = 1;
+		scale_index = rs_ht_to_legacy[scale_index];
+		if (lq_sta->band == IEEE80211_BAND_5GHZ)
+			tbl->lq_type = LQ_A;
+		else
+			tbl->lq_type = LQ_G;
+
+		if (num_of_ant(tbl->ant_type) > 1)
+			tbl->ant_type =
+			    first_antenna(priv->eeprom_data->valid_tx_ant);
+
+		tbl->is_ht40 = 0;
+		tbl->is_SGI = 0;
+		tbl->max_search = IWL_MAX_SEARCH;
+	}
+
+	rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type);
+
+	/* Mask with station rate restriction */
+	if (is_legacy(tbl->lq_type)) {
+		/* supp_rates has no CCK bits in A mode */
+		if (lq_sta->band == IEEE80211_BAND_5GHZ)
+			rate_mask  = (u16)(rate_mask &
+			   (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
+		else
+			rate_mask = (u16)(rate_mask & lq_sta->supp_rates);
+	}
+
+	/* If we switched from HT to legacy, check current rate */
+	if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
+		low = scale_index;
+		goto out;
+	}
+
+	high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask,
+					tbl->lq_type);
+	low = high_low & 0xff;
+
+	if (low == IWL_RATE_INVALID)
+		low = scale_index;
+
+out:
+	return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green);
+}
+
+/*
+ * Simple function to compare two rate scale table types
+ */
+static bool table_type_matches(struct iwl_scale_tbl_info *a,
+			       struct iwl_scale_tbl_info *b)
+{
+	return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) &&
+		(a->is_SGI == b->is_SGI);
+}
+
+static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+			    struct iwl_lq_sta *lq_sta)
+{
+	struct iwl_scale_tbl_info *tbl;
+	bool full_concurrent = priv->bt_full_concurrent;
+
+	if (priv->bt_ant_couple_ok) {
+		/*
+		 * Is there a need to switch between
+		 * full concurrency and 3-wire?
+		 */
+		if (priv->bt_ci_compliance && priv->bt_ant_couple_ok)
+			full_concurrent = true;
+		else
+			full_concurrent = false;
+	}
+	if ((priv->bt_traffic_load != priv->last_bt_traffic_load) ||
+	    (priv->bt_full_concurrent != full_concurrent)) {
+		priv->bt_full_concurrent = full_concurrent;
+		priv->last_bt_traffic_load = priv->bt_traffic_load;
+
+		/* Update uCode's rate table. */
+		tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+		rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
+		iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
+
+		queue_work(priv->workqueue, &priv->bt_full_concurrency);
+	}
+}
+
+/*
+ * mac80211 sends us Tx status
+ */
+static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
+			 struct ieee80211_sta *sta, void *priv_sta,
+			 struct sk_buff *skb)
+{
+	int legacy_success;
+	int retries;
+	int rs_index, mac_index, i;
+	struct iwl_lq_sta *lq_sta = priv_sta;
+	struct iwl_link_quality_cmd *table;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct iwl_op_mode *op_mode = (struct iwl_op_mode *)priv_r;
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	enum mac80211_rate_control_flags mac_flags;
+	u32 tx_rate;
+	struct iwl_scale_tbl_info tbl_type;
+	struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
+	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+	struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+	IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
+
+	/* Treat uninitialized rate scaling data same as non-existing. */
+	if (!lq_sta) {
+		IWL_DEBUG_RATE(priv, "Station rate scaling not created yet.\n");
+		return;
+	} else if (!lq_sta->drv) {
+		IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n");
+		return;
+	}
+
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    info->flags & IEEE80211_TX_CTL_NO_ACK)
+		return;
+
+	/* This packet was aggregated but doesn't carry status info */
+	if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+	    !(info->flags & IEEE80211_TX_STAT_AMPDU))
+		return;
+
+	/*
+	 * Ignore this Tx frame response if its initial rate doesn't match
+	 * that of latest Link Quality command.  There may be stragglers
+	 * from a previous Link Quality command, but we're no longer interested
+	 * in those; they're either from the "active" mode while we're trying
+	 * to check "search" mode, or a prior "search" mode after we've moved
+	 * to a new "search" mode (which might become the new "active" mode).
+	 */
+	table = &lq_sta->lq;
+	tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
+	rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
+	if (priv->band == IEEE80211_BAND_5GHZ)
+		rs_index -= IWL_FIRST_OFDM_RATE;
+	mac_flags = info->status.rates[0].flags;
+	mac_index = info->status.rates[0].idx;
+	/* For HT packets, map MCS to PLCP */
+	if (mac_flags & IEEE80211_TX_RC_MCS) {
+		mac_index &= RATE_MCS_CODE_MSK;	/* Remove # of streams */
+		if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE))
+			mac_index++;
+		/*
+		 * mac80211 HT index is always zero-indexed; we need to move
+		 * HT OFDM rates after CCK rates in 2.4 GHz band
+		 */
+		if (priv->band == IEEE80211_BAND_2GHZ)
+			mac_index += IWL_FIRST_OFDM_RATE;
+	}
+	/* Here we actually compare this rate to the latest LQ command */
+	if ((mac_index < 0) ||
+	    (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
+	    (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
+	    (tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA)) ||
+	    (tbl_type.ant_type != info->status.antenna) ||
+	    (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) ||
+	    (!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
+	    (rs_index != mac_index)) {
+		IWL_DEBUG_RATE(priv, "initial rate %d does not match %d (0x%x)\n", mac_index, rs_index, tx_rate);
+		/*
+		 * Since rates mis-match, the last LQ command may have failed.
+		 * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
+		 * ... driver.
+		 */
+		lq_sta->missed_rate_counter++;
+		if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
+			lq_sta->missed_rate_counter = 0;
+			iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
+		}
+		/* Regardless, ignore this status info for outdated rate */
+		return;
+	} else
+		/* Rate did match, so reset the missed_rate_counter */
+		lq_sta->missed_rate_counter = 0;
+
+	/* Figure out if rate scale algorithm is in active or search table */
+	if (table_type_matches(&tbl_type,
+				&(lq_sta->lq_info[lq_sta->active_tbl]))) {
+		curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+		other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+	} else if (table_type_matches(&tbl_type,
+				&lq_sta->lq_info[1 - lq_sta->active_tbl])) {
+		curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+		other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+	} else {
+		IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");
+		tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+		IWL_DEBUG_RATE(priv, "active- lq:%x, ant:%x, SGI:%d\n",
+			tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
+		tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+		IWL_DEBUG_RATE(priv, "search- lq:%x, ant:%x, SGI:%d\n",
+			tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
+		IWL_DEBUG_RATE(priv, "actual- lq:%x, ant:%x, SGI:%d\n",
+			tbl_type.lq_type, tbl_type.ant_type, tbl_type.is_SGI);
+		/*
+		 * no matching table found, let's by-pass the data collection
+		 * and continue to perform rate scale to find the rate table
+		 */
+		rs_stay_in_table(lq_sta, true);
+		goto done;
+	}
+
+	/*
+	 * Updating the frame history depends on whether packets were
+	 * aggregated.
+	 *
+	 * For aggregation, all packets were transmitted at the same rate, the
+	 * first index into rate scale table.
+	 */
+	if (info->flags & IEEE80211_TX_STAT_AMPDU) {
+		tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
+		rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type,
+				&rs_index);
+		rs_collect_tx_data(curr_tbl, rs_index,
+				   info->status.ampdu_len,
+				   info->status.ampdu_ack_len);
+
+		/* Update success/fail counts if not searching for new mode */
+		if (lq_sta->stay_in_tbl) {
+			lq_sta->total_success += info->status.ampdu_ack_len;
+			lq_sta->total_failed += (info->status.ampdu_len -
+					info->status.ampdu_ack_len);
+		}
+	} else {
+	/*
+	 * For legacy, update frame history with for each Tx retry.
+	 */
+		retries = info->status.rates[0].count - 1;
+		/* HW doesn't send more than 15 retries */
+		retries = min(retries, 15);
+
+		/* The last transmission may have been successful */
+		legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+		/* Collect data for each rate used during failed TX attempts */
+		for (i = 0; i <= retries; ++i) {
+			tx_rate = le32_to_cpu(table->rs_table[i].rate_n_flags);
+			rs_get_tbl_info_from_mcs(tx_rate, priv->band,
+					&tbl_type, &rs_index);
+			/*
+			 * Only collect stats if retried rate is in the same RS
+			 * table as active/search.
+			 */
+			if (table_type_matches(&tbl_type, curr_tbl))
+				tmp_tbl = curr_tbl;
+			else if (table_type_matches(&tbl_type, other_tbl))
+				tmp_tbl = other_tbl;
+			else
+				continue;
+			rs_collect_tx_data(tmp_tbl, rs_index, 1,
+					   i < retries ? 0 : legacy_success);
+		}
+
+		/* Update success/fail counts if not searching for new mode */
+		if (lq_sta->stay_in_tbl) {
+			lq_sta->total_success += legacy_success;
+			lq_sta->total_failed += retries + (1 - legacy_success);
+		}
+	}
+	/* The last TX rate is cached in lq_sta; it's set in if/else above */
+	lq_sta->last_rate_n_flags = tx_rate;
+done:
+	/* See if there's a better rate or modulation mode to try. */
+	if (sta && sta->supp_rates[sband->band])
+		rs_rate_scale_perform(priv, skb, sta, lq_sta);
+
+#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_IWLWIFI_DEVICE_TESTMODE)
+	if ((priv->tm_fixed_rate) &&
+	    (priv->tm_fixed_rate != lq_sta->dbg_fixed_rate))
+		rs_program_fix_rate(priv, lq_sta);
+#endif
+	if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
+		rs_bt_update_lq(priv, ctx, lq_sta);
+}
+
+/*
+ * Begin a period of staying with a selected modulation mode.
+ * Set "stay_in_tbl" flag to prevent any mode switches.
+ * Set frame tx success limits according to legacy vs. high-throughput,
+ * and reset overall (spanning all rates) tx success history statistics.
+ * These control how long we stay using same modulation mode before
+ * searching for a new mode.
+ */
+static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
+				 struct iwl_lq_sta *lq_sta)
+{
+	IWL_DEBUG_RATE(priv, "we are staying in the same table\n");
+	lq_sta->stay_in_tbl = 1;	/* only place this gets set */
+	if (is_legacy) {
+		lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
+		lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
+		lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
+	} else {
+		lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
+		lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
+		lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
+	}
+	lq_sta->table_count = 0;
+	lq_sta->total_failed = 0;
+	lq_sta->total_success = 0;
+	lq_sta->flush_timer = jiffies;
+	lq_sta->action_counter = 0;
+}
+
+/*
+ * Find correct throughput table for given mode of modulation
+ */
+static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
+				      struct iwl_scale_tbl_info *tbl)
+{
+	/* Used to choose among HT tables */
+	s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
+
+	/* Check for invalid LQ type */
+	if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) {
+		tbl->expected_tpt = expected_tpt_legacy;
+		return;
+	}
+
+	/* Legacy rates have only one table */
+	if (is_legacy(tbl->lq_type)) {
+		tbl->expected_tpt = expected_tpt_legacy;
+		return;
+	}
+
+	/* Choose among many HT tables depending on number of streams
+	 * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation
+	 * status */
+	if (is_siso(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
+		ht_tbl_pointer = expected_tpt_siso20MHz;
+	else if (is_siso(tbl->lq_type))
+		ht_tbl_pointer = expected_tpt_siso40MHz;
+	else if (is_mimo2(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
+		ht_tbl_pointer = expected_tpt_mimo2_20MHz;
+	else if (is_mimo2(tbl->lq_type))
+		ht_tbl_pointer = expected_tpt_mimo2_40MHz;
+	else if (is_mimo3(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
+		ht_tbl_pointer = expected_tpt_mimo3_20MHz;
+	else /* if (is_mimo3(tbl->lq_type)) <-- must be true */
+		ht_tbl_pointer = expected_tpt_mimo3_40MHz;
+
+	if (!tbl->is_SGI && !lq_sta->is_agg)		/* Normal */
+		tbl->expected_tpt = ht_tbl_pointer[0];
+	else if (tbl->is_SGI && !lq_sta->is_agg)	/* SGI */
+		tbl->expected_tpt = ht_tbl_pointer[1];
+	else if (!tbl->is_SGI && lq_sta->is_agg)	/* AGG */
+		tbl->expected_tpt = ht_tbl_pointer[2];
+	else						/* AGG+SGI */
+		tbl->expected_tpt = ht_tbl_pointer[3];
+}
+
+/*
+ * Find starting rate for new "search" high-throughput mode of modulation.
+ * Goal is to find lowest expected rate (under perfect conditions) that is
+ * above the current measured throughput of "active" mode, to give new mode
+ * a fair chance to prove itself without too many challenges.
+ *
+ * This gets called when transitioning to more aggressive modulation
+ * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive
+ * (i.e. MIMO to SISO).  When moving to MIMO, bit rate will typically need
+ * to decrease to match "active" throughput.  When moving from MIMO to SISO,
+ * bit rate will typically need to increase, but not if performance was bad.
+ */
+static s32 rs_get_best_rate(struct iwl_priv *priv,
+			    struct iwl_lq_sta *lq_sta,
+			    struct iwl_scale_tbl_info *tbl,	/* "search" */
+			    u16 rate_mask, s8 index)
+{
+	/* "active" values */
+	struct iwl_scale_tbl_info *active_tbl =
+	    &(lq_sta->lq_info[lq_sta->active_tbl]);
+	s32 active_sr = active_tbl->win[index].success_ratio;
+	s32 active_tpt = active_tbl->expected_tpt[index];
+
+	/* expected "search" throughput */
+	s32 *tpt_tbl = tbl->expected_tpt;
+
+	s32 new_rate, high, low, start_hi;
+	u16 high_low;
+	s8 rate = index;
+
+	new_rate = high = low = start_hi = IWL_RATE_INVALID;
+
+	for (; ;) {
+		high_low = rs_get_adjacent_rate(priv, rate, rate_mask,
+						tbl->lq_type);
+
+		low = high_low & 0xff;
+		high = (high_low >> 8) & 0xff;
+
+		/*
+		 * Lower the "search" bit rate, to give new "search" mode
+		 * approximately the same throughput as "active" if:
+		 *
+		 * 1) "Active" mode has been working modestly well (but not
+		 *    great), and expected "search" throughput (under perfect
+		 *    conditions) at candidate rate is above the actual
+		 *    measured "active" throughput (but less than expected
+		 *    "active" throughput under perfect conditions).
+		 * OR
+		 * 2) "Active" mode has been working perfectly or very well
+		 *    and expected "search" throughput (under perfect
+		 *    conditions) at candidate rate is above expected
+		 *    "active" throughput (under perfect conditions).
+		 */
+		if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) &&
+		     ((active_sr > IWL_RATE_DECREASE_TH) &&
+		      (active_sr <= IWL_RATE_HIGH_TH) &&
+		      (tpt_tbl[rate] <= active_tpt))) ||
+		    ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
+		     (tpt_tbl[rate] > active_tpt))) {
+
+			/* (2nd or later pass)
+			 * If we've already tried to raise the rate, and are
+			 * now trying to lower it, use the higher rate. */
+			if (start_hi != IWL_RATE_INVALID) {
+				new_rate = start_hi;
+				break;
+			}
+
+			new_rate = rate;
+
+			/* Loop again with lower rate */
+			if (low != IWL_RATE_INVALID)
+				rate = low;
+
+			/* Lower rate not available, use the original */
+			else
+				break;
+
+		/* Else try to raise the "search" rate to match "active" */
+		} else {
+			/* (2nd or later pass)
+			 * If we've already tried to lower the rate, and are
+			 * now trying to raise it, use the lower rate. */
+			if (new_rate != IWL_RATE_INVALID)
+				break;
+
+			/* Loop again with higher rate */
+			else if (high != IWL_RATE_INVALID) {
+				start_hi = high;
+				rate = high;
+
+			/* Higher rate not available, use the original */
+			} else {
+				new_rate = rate;
+				break;
+			}
+		}
+	}
+
+	return new_rate;
+}
+
+/*
+ * Set up search table for MIMO2
+ */
+static int rs_switch_to_mimo2(struct iwl_priv *priv,
+			     struct iwl_lq_sta *lq_sta,
+			     struct ieee80211_conf *conf,
+			     struct ieee80211_sta *sta,
+			     struct iwl_scale_tbl_info *tbl, int index)
+{
+	u16 rate_mask;
+	s32 rate;
+	s8 is_green = lq_sta->is_green;
+	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+	struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
+		return -1;
+
+	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
+						== WLAN_HT_CAP_SM_PS_STATIC)
+		return -1;
+
+	/* Need both Tx chains/antennas to support MIMO */
+	if (priv->hw_params.tx_chains_num < 2)
+		return -1;
+
+	IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO2\n");
+
+	tbl->lq_type = LQ_MIMO2;
+	tbl->is_dup = lq_sta->is_dup;
+	tbl->action = 0;
+	tbl->max_search = IWL_MAX_SEARCH;
+	rate_mask = lq_sta->active_mimo2_rate;
+
+	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+		tbl->is_ht40 = 1;
+	else
+		tbl->is_ht40 = 0;
+
+	rs_set_expected_tpt_table(lq_sta, tbl);
+
+	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
+
+	IWL_DEBUG_RATE(priv, "LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask);
+	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+		IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
+						rate, rate_mask);
+		return -1;
+	}
+	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
+
+	IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
+		     tbl->current_rate, is_green);
+	return 0;
+}
+
+/*
+ * Set up search table for MIMO3
+ */
+static int rs_switch_to_mimo3(struct iwl_priv *priv,
+			     struct iwl_lq_sta *lq_sta,
+			     struct ieee80211_conf *conf,
+			     struct ieee80211_sta *sta,
+			     struct iwl_scale_tbl_info *tbl, int index)
+{
+	u16 rate_mask;
+	s32 rate;
+	s8 is_green = lq_sta->is_green;
+	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+	struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
+		return -1;
+
+	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
+						== WLAN_HT_CAP_SM_PS_STATIC)
+		return -1;
+
+	/* Need both Tx chains/antennas to support MIMO */
+	if (priv->hw_params.tx_chains_num < 3)
+		return -1;
+
+	IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n");
+
+	tbl->lq_type = LQ_MIMO3;
+	tbl->is_dup = lq_sta->is_dup;
+	tbl->action = 0;
+	tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
+	rate_mask = lq_sta->active_mimo3_rate;
+
+	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+		tbl->is_ht40 = 1;
+	else
+		tbl->is_ht40 = 0;
+
+	rs_set_expected_tpt_table(lq_sta, tbl);
+
+	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
+
+	IWL_DEBUG_RATE(priv, "LQ: MIMO3 best rate %d mask %X\n",
+		rate, rate_mask);
+	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+		IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
+						rate, rate_mask);
+		return -1;
+	}
+	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
+
+	IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
+		     tbl->current_rate, is_green);
+	return 0;
+}
+
+/*
+ * Set up search table for SISO
+ */
+static int rs_switch_to_siso(struct iwl_priv *priv,
+			     struct iwl_lq_sta *lq_sta,
+			     struct ieee80211_conf *conf,
+			     struct ieee80211_sta *sta,
+			     struct iwl_scale_tbl_info *tbl, int index)
+{
+	u16 rate_mask;
+	u8 is_green = lq_sta->is_green;
+	s32 rate;
+	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+	struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
+		return -1;
+
+	IWL_DEBUG_RATE(priv, "LQ: try to switch to SISO\n");
+
+	tbl->is_dup = lq_sta->is_dup;
+	tbl->lq_type = LQ_SISO;
+	tbl->action = 0;
+	tbl->max_search = IWL_MAX_SEARCH;
+	rate_mask = lq_sta->active_siso_rate;
+
+	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+		tbl->is_ht40 = 1;
+	else
+		tbl->is_ht40 = 0;
+
+	if (is_green)
+		tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/
+
+	rs_set_expected_tpt_table(lq_sta, tbl);
+	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
+
+	IWL_DEBUG_RATE(priv, "LQ: get best rate %d mask %X\n", rate, rate_mask);
+	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+		IWL_DEBUG_RATE(priv, "can not switch with index %d rate mask %x\n",
+			     rate, rate_mask);
+		return -1;
+	}
+	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
+	IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
+		     tbl->current_rate, is_green);
+	return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from legacy
+ */
+static int rs_move_legacy_other(struct iwl_priv *priv,
+				struct iwl_lq_sta *lq_sta,
+				struct ieee80211_conf *conf,
+				struct ieee80211_sta *sta,
+				int index)
+{
+	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+	struct iwl_scale_tbl_info *search_tbl =
+				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u8 start_action;
+	u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+	u8 tx_chains_num = priv->hw_params.tx_chains_num;
+	int ret = 0;
+	u8 update_search_tbl_counter = 0;
+
+	switch (priv->bt_traffic_load) {
+	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+		/* nothing */
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+		/* avoid antenna B unless MIMO */
+		if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2)
+			tbl->action = IWL_LEGACY_SWITCH_SISO;
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+		/* avoid antenna B and MIMO */
+		valid_tx_ant =
+			first_antenna(priv->eeprom_data->valid_tx_ant);
+		if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 &&
+		    tbl->action != IWL_LEGACY_SWITCH_SISO)
+			tbl->action = IWL_LEGACY_SWITCH_SISO;
+		break;
+	default:
+		IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+		break;
+	}
+
+	if (!iwl_ht_enabled(priv))
+		/* stay in Legacy */
+		tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+	else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
+		   tbl->action > IWL_LEGACY_SWITCH_SISO)
+		tbl->action = IWL_LEGACY_SWITCH_SISO;
+
+	/* configure as 1x1 if bt full concurrency */
+	if (priv->bt_full_concurrent) {
+		if (!iwl_ht_enabled(priv))
+			tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+		else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
+			tbl->action = IWL_LEGACY_SWITCH_SISO;
+		valid_tx_ant =
+			first_antenna(priv->eeprom_data->valid_tx_ant);
+	}
+
+	start_action = tbl->action;
+	for (; ;) {
+		lq_sta->action_counter++;
+		switch (tbl->action) {
+		case IWL_LEGACY_SWITCH_ANTENNA1:
+		case IWL_LEGACY_SWITCH_ANTENNA2:
+			IWL_DEBUG_RATE(priv, "LQ: Legacy toggle Antenna\n");
+
+			if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 &&
+							tx_chains_num <= 1) ||
+			    (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 &&
+							tx_chains_num <= 2))
+				break;
+
+			/* Don't change antenna if success has been great */
+			if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
+			    !priv->bt_full_concurrent &&
+			    priv->bt_traffic_load ==
+					IWL_BT_COEX_TRAFFIC_LOAD_NONE)
+				break;
+
+			/* Set up search table to try other antenna */
+			memcpy(search_tbl, tbl, sz);
+
+			if (rs_toggle_antenna(valid_tx_ant,
+				&search_tbl->current_rate, search_tbl)) {
+				update_search_tbl_counter = 1;
+				rs_set_expected_tpt_table(lq_sta, search_tbl);
+				goto out;
+			}
+			break;
+		case IWL_LEGACY_SWITCH_SISO:
+			IWL_DEBUG_RATE(priv, "LQ: Legacy switch to SISO\n");
+
+			/* Set up search table to try SISO */
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret) {
+				lq_sta->action_counter = 0;
+				goto out;
+			}
+
+			break;
+		case IWL_LEGACY_SWITCH_MIMO2_AB:
+		case IWL_LEGACY_SWITCH_MIMO2_AC:
+		case IWL_LEGACY_SWITCH_MIMO2_BC:
+			IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO2\n");
+
+			/* Set up search table to try MIMO */
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+
+			if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB)
+				search_tbl->ant_type = ANT_AB;
+			else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC)
+				search_tbl->ant_type = ANT_AC;
+			else
+				search_tbl->ant_type = ANT_BC;
+
+			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret) {
+				lq_sta->action_counter = 0;
+				goto out;
+			}
+			break;
+
+		case IWL_LEGACY_SWITCH_MIMO3_ABC:
+			IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO3\n");
+
+			/* Set up search table to try MIMO3 */
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+
+			search_tbl->ant_type = ANT_ABC;
+
+			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret) {
+				lq_sta->action_counter = 0;
+				goto out;
+			}
+			break;
+		}
+		tbl->action++;
+		if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+			tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+
+		if (tbl->action == start_action)
+			break;
+
+	}
+	search_tbl->lq_type = LQ_NONE;
+	return 0;
+
+out:
+	lq_sta->search_better_tbl = 1;
+	tbl->action++;
+	if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+		tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+	if (update_search_tbl_counter)
+		search_tbl->action = tbl->action;
+	return 0;
+
+}
+
+/*
+ * Try to switch to new modulation mode from SISO
+ */
+static int rs_move_siso_to_other(struct iwl_priv *priv,
+				 struct iwl_lq_sta *lq_sta,
+				 struct ieee80211_conf *conf,
+				 struct ieee80211_sta *sta, int index)
+{
+	u8 is_green = lq_sta->is_green;
+	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+	struct iwl_scale_tbl_info *search_tbl =
+				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u8 start_action;
+	u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+	u8 tx_chains_num = priv->hw_params.tx_chains_num;
+	u8 update_search_tbl_counter = 0;
+	int ret;
+
+	switch (priv->bt_traffic_load) {
+	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+		/* nothing */
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+		/* avoid antenna B unless MIMO */
+		if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
+			tbl->action = IWL_SISO_SWITCH_MIMO2_AB;
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+		/* avoid antenna B and MIMO */
+		valid_tx_ant =
+			first_antenna(priv->eeprom_data->valid_tx_ant);
+		if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
+			tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+		break;
+	default:
+		IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+		break;
+	}
+
+	if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
+	    tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
+		/* stay in SISO */
+		tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+	}
+
+	/* configure as 1x1 if bt full concurrency */
+	if (priv->bt_full_concurrent) {
+		valid_tx_ant =
+			first_antenna(priv->eeprom_data->valid_tx_ant);
+		if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
+			tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+	}
+
+	start_action = tbl->action;
+	for (;;) {
+		lq_sta->action_counter++;
+		switch (tbl->action) {
+		case IWL_SISO_SWITCH_ANTENNA1:
+		case IWL_SISO_SWITCH_ANTENNA2:
+			IWL_DEBUG_RATE(priv, "LQ: SISO toggle Antenna\n");
+			if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 &&
+						tx_chains_num <= 1) ||
+			    (tbl->action == IWL_SISO_SWITCH_ANTENNA2 &&
+						tx_chains_num <= 2))
+				break;
+
+			if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
+			    !priv->bt_full_concurrent &&
+			    priv->bt_traffic_load ==
+					IWL_BT_COEX_TRAFFIC_LOAD_NONE)
+				break;
+
+			memcpy(search_tbl, tbl, sz);
+			if (rs_toggle_antenna(valid_tx_ant,
+				       &search_tbl->current_rate, search_tbl)) {
+				update_search_tbl_counter = 1;
+				goto out;
+			}
+			break;
+		case IWL_SISO_SWITCH_MIMO2_AB:
+		case IWL_SISO_SWITCH_MIMO2_AC:
+		case IWL_SISO_SWITCH_MIMO2_BC:
+			IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO2\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+
+			if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB)
+				search_tbl->ant_type = ANT_AB;
+			else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC)
+				search_tbl->ant_type = ANT_AC;
+			else
+				search_tbl->ant_type = ANT_BC;
+
+			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret)
+				goto out;
+			break;
+		case IWL_SISO_SWITCH_GI:
+			if (!tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_20))
+				break;
+			if (tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_40))
+				break;
+
+			IWL_DEBUG_RATE(priv, "LQ: SISO toggle SGI/NGI\n");
+
+			memcpy(search_tbl, tbl, sz);
+			if (is_green) {
+				if (!tbl->is_SGI)
+					break;
+				else
+					IWL_ERR(priv,
+						"SGI was set in GF+SISO\n");
+			}
+			search_tbl->is_SGI = !tbl->is_SGI;
+			rs_set_expected_tpt_table(lq_sta, search_tbl);
+			if (tbl->is_SGI) {
+				s32 tpt = lq_sta->last_tpt / 100;
+				if (tpt >= search_tbl->expected_tpt[index])
+					break;
+			}
+			search_tbl->current_rate =
+				rate_n_flags_from_tbl(priv, search_tbl,
+						      index, is_green);
+			update_search_tbl_counter = 1;
+			goto out;
+		case IWL_SISO_SWITCH_MIMO3_ABC:
+			IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO3\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+			search_tbl->ant_type = ANT_ABC;
+
+			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret)
+				goto out;
+			break;
+		}
+		tbl->action++;
+		if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+			tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+
+		if (tbl->action == start_action)
+			break;
+	}
+	search_tbl->lq_type = LQ_NONE;
+	return 0;
+
+ out:
+	lq_sta->search_better_tbl = 1;
+	tbl->action++;
+	if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC)
+		tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+	if (update_search_tbl_counter)
+		search_tbl->action = tbl->action;
+
+	return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from MIMO2
+ */
+static int rs_move_mimo2_to_other(struct iwl_priv *priv,
+				 struct iwl_lq_sta *lq_sta,
+				 struct ieee80211_conf *conf,
+				 struct ieee80211_sta *sta, int index)
+{
+	s8 is_green = lq_sta->is_green;
+	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+	struct iwl_scale_tbl_info *search_tbl =
+				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u8 start_action;
+	u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+	u8 tx_chains_num = priv->hw_params.tx_chains_num;
+	u8 update_search_tbl_counter = 0;
+	int ret;
+
+	switch (priv->bt_traffic_load) {
+	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+		/* nothing */
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+		/* avoid antenna B and MIMO */
+		if (tbl->action != IWL_MIMO2_SWITCH_SISO_A)
+			tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+		/* avoid antenna B unless MIMO */
+		if (tbl->action == IWL_MIMO2_SWITCH_SISO_B ||
+		    tbl->action == IWL_MIMO2_SWITCH_SISO_C)
+			tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+		break;
+	default:
+		IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+		break;
+	}
+
+	if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
+	    (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
+	     tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
+		/* switch in SISO */
+		tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+	}
+
+	/* configure as 1x1 if bt full concurrency */
+	if (priv->bt_full_concurrent &&
+	    (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
+	     tbl->action > IWL_MIMO2_SWITCH_SISO_C))
+		tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+
+	start_action = tbl->action;
+	for (;;) {
+		lq_sta->action_counter++;
+		switch (tbl->action) {
+		case IWL_MIMO2_SWITCH_ANTENNA1:
+		case IWL_MIMO2_SWITCH_ANTENNA2:
+			IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle Antennas\n");
+
+			if (tx_chains_num <= 2)
+				break;
+
+			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+				break;
+
+			memcpy(search_tbl, tbl, sz);
+			if (rs_toggle_antenna(valid_tx_ant,
+				       &search_tbl->current_rate, search_tbl)) {
+				update_search_tbl_counter = 1;
+				goto out;
+			}
+			break;
+		case IWL_MIMO2_SWITCH_SISO_A:
+		case IWL_MIMO2_SWITCH_SISO_B:
+		case IWL_MIMO2_SWITCH_SISO_C:
+			IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to SISO\n");
+
+			/* Set up new search table for SISO */
+			memcpy(search_tbl, tbl, sz);
+
+			if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
+				search_tbl->ant_type = ANT_A;
+			else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B)
+				search_tbl->ant_type = ANT_B;
+			else
+				search_tbl->ant_type = ANT_C;
+
+			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret)
+				goto out;
+
+			break;
+
+		case IWL_MIMO2_SWITCH_GI:
+			if (!tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_20))
+				break;
+			if (tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_40))
+				break;
+
+			IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n");
+
+			/* Set up new search table for MIMO2 */
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = !tbl->is_SGI;
+			rs_set_expected_tpt_table(lq_sta, search_tbl);
+			/*
+			 * If active table already uses the fastest possible
+			 * modulation (dual stream with short guard interval),
+			 * and it's working well, there's no need to look
+			 * for a better type of modulation!
+			 */
+			if (tbl->is_SGI) {
+				s32 tpt = lq_sta->last_tpt / 100;
+				if (tpt >= search_tbl->expected_tpt[index])
+					break;
+			}
+			search_tbl->current_rate =
+				rate_n_flags_from_tbl(priv, search_tbl,
+						      index, is_green);
+			update_search_tbl_counter = 1;
+			goto out;
+
+		case IWL_MIMO2_SWITCH_MIMO3_ABC:
+			IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to MIMO3\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+			search_tbl->ant_type = ANT_ABC;
+
+			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret)
+				goto out;
+
+			break;
+		}
+		tbl->action++;
+		if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
+			tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
+
+		if (tbl->action == start_action)
+			break;
+	}
+	search_tbl->lq_type = LQ_NONE;
+	return 0;
+ out:
+	lq_sta->search_better_tbl = 1;
+	tbl->action++;
+	if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
+		tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
+	if (update_search_tbl_counter)
+		search_tbl->action = tbl->action;
+
+	return 0;
+
+}
+
+/*
+ * Try to switch to new modulation mode from MIMO3
+ */
+static int rs_move_mimo3_to_other(struct iwl_priv *priv,
+				 struct iwl_lq_sta *lq_sta,
+				 struct ieee80211_conf *conf,
+				 struct ieee80211_sta *sta, int index)
+{
+	s8 is_green = lq_sta->is_green;
+	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+	struct iwl_scale_tbl_info *search_tbl =
+				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u8 start_action;
+	u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+	u8 tx_chains_num = priv->hw_params.tx_chains_num;
+	int ret;
+	u8 update_search_tbl_counter = 0;
+
+	switch (priv->bt_traffic_load) {
+	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+		/* nothing */
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+		/* avoid antenna B and MIMO */
+		if (tbl->action != IWL_MIMO3_SWITCH_SISO_A)
+			tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+		break;
+	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+		/* avoid antenna B unless MIMO */
+		if (tbl->action == IWL_MIMO3_SWITCH_SISO_B ||
+		    tbl->action == IWL_MIMO3_SWITCH_SISO_C)
+			tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+		break;
+	default:
+		IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+		break;
+	}
+
+	if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
+	    (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
+	     tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
+		/* switch in SISO */
+		tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+	}
+
+	/* configure as 1x1 if bt full concurrency */
+	if (priv->bt_full_concurrent &&
+	    (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
+	     tbl->action > IWL_MIMO3_SWITCH_SISO_C))
+		tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+
+	start_action = tbl->action;
+	for (;;) {
+		lq_sta->action_counter++;
+		switch (tbl->action) {
+		case IWL_MIMO3_SWITCH_ANTENNA1:
+		case IWL_MIMO3_SWITCH_ANTENNA2:
+			IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle Antennas\n");
+
+			if (tx_chains_num <= 3)
+				break;
+
+			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+				break;
+
+			memcpy(search_tbl, tbl, sz);
+			if (rs_toggle_antenna(valid_tx_ant,
+				       &search_tbl->current_rate, search_tbl))
+				goto out;
+			break;
+		case IWL_MIMO3_SWITCH_SISO_A:
+		case IWL_MIMO3_SWITCH_SISO_B:
+		case IWL_MIMO3_SWITCH_SISO_C:
+			IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to SISO\n");
+
+			/* Set up new search table for SISO */
+			memcpy(search_tbl, tbl, sz);
+
+			if (tbl->action == IWL_MIMO3_SWITCH_SISO_A)
+				search_tbl->ant_type = ANT_A;
+			else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B)
+				search_tbl->ant_type = ANT_B;
+			else
+				search_tbl->ant_type = ANT_C;
+
+			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret)
+				goto out;
+
+			break;
+
+		case IWL_MIMO3_SWITCH_MIMO2_AB:
+		case IWL_MIMO3_SWITCH_MIMO2_AC:
+		case IWL_MIMO3_SWITCH_MIMO2_BC:
+			IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to MIMO2\n");
+
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+			if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB)
+				search_tbl->ant_type = ANT_AB;
+			else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC)
+				search_tbl->ant_type = ANT_AC;
+			else
+				search_tbl->ant_type = ANT_BC;
+
+			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret)
+				goto out;
+
+			break;
+
+		case IWL_MIMO3_SWITCH_GI:
+			if (!tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_20))
+				break;
+			if (tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_40))
+				break;
+
+			IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n");
+
+			/* Set up new search table for MIMO */
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = !tbl->is_SGI;
+			rs_set_expected_tpt_table(lq_sta, search_tbl);
+			/*
+			 * If active table already uses the fastest possible
+			 * modulation (dual stream with short guard interval),
+			 * and it's working well, there's no need to look
+			 * for a better type of modulation!
+			 */
+			if (tbl->is_SGI) {
+				s32 tpt = lq_sta->last_tpt / 100;
+				if (tpt >= search_tbl->expected_tpt[index])
+					break;
+			}
+			search_tbl->current_rate =
+				rate_n_flags_from_tbl(priv, search_tbl,
+						      index, is_green);
+			update_search_tbl_counter = 1;
+			goto out;
+		}
+		tbl->action++;
+		if (tbl->action > IWL_MIMO3_SWITCH_GI)
+			tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+
+		if (tbl->action == start_action)
+			break;
+	}
+	search_tbl->lq_type = LQ_NONE;
+	return 0;
+ out:
+	lq_sta->search_better_tbl = 1;
+	tbl->action++;
+	if (tbl->action > IWL_MIMO3_SWITCH_GI)
+		tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+	if (update_search_tbl_counter)
+		search_tbl->action = tbl->action;
+
+	return 0;
+
+}
+
+/*
+ * Check whether we should continue using same modulation mode, or
+ * begin search for a new mode, based on:
+ * 1) # tx successes or failures while using this mode
+ * 2) # times calling this function
+ * 3) elapsed time in this mode (not used, for now)
+ */
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
+{
+	struct iwl_scale_tbl_info *tbl;
+	int i;
+	int active_tbl;
+	int flush_interval_passed = 0;
+	struct iwl_priv *priv;
+
+	priv = lq_sta->drv;
+	active_tbl = lq_sta->active_tbl;
+
+	tbl = &(lq_sta->lq_info[active_tbl]);
+
+	/* If we've been disallowing search, see if we should now allow it */
+	if (lq_sta->stay_in_tbl) {
+
+		/* Elapsed time using current modulation mode */
+		if (lq_sta->flush_timer)
+			flush_interval_passed =
+			time_after(jiffies,
+					(unsigned long)(lq_sta->flush_timer +
+					IWL_RATE_SCALE_FLUSH_INTVL));
+
+		/*
+		 * Check if we should allow search for new modulation mode.
+		 * If many frames have failed or succeeded, or we've used
+		 * this same modulation for a long time, allow search, and
+		 * reset history stats that keep track of whether we should
+		 * allow a new search.  Also (below) reset all bitmaps and
+		 * stats in active history.
+		 */
+		if (force_search ||
+		    (lq_sta->total_failed > lq_sta->max_failure_limit) ||
+		    (lq_sta->total_success > lq_sta->max_success_limit) ||
+		    ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
+		     && (flush_interval_passed))) {
+			IWL_DEBUG_RATE(priv, "LQ: stay is expired %d %d %d\n",
+				     lq_sta->total_failed,
+				     lq_sta->total_success,
+				     flush_interval_passed);
+
+			/* Allow search for new mode */
+			lq_sta->stay_in_tbl = 0;	/* only place reset */
+			lq_sta->total_failed = 0;
+			lq_sta->total_success = 0;
+			lq_sta->flush_timer = 0;
+
+		/*
+		 * Else if we've used this modulation mode enough repetitions
+		 * (regardless of elapsed time or success/failure), reset
+		 * history bitmaps and rate-specific stats for all rates in
+		 * active table.
+		 */
+		} else {
+			lq_sta->table_count++;
+			if (lq_sta->table_count >=
+			    lq_sta->table_count_limit) {
+				lq_sta->table_count = 0;
+
+				IWL_DEBUG_RATE(priv, "LQ: stay in table clear win\n");
+				for (i = 0; i < IWL_RATE_COUNT; i++)
+					rs_rate_scale_clear_window(
+						&(tbl->win[i]));
+			}
+		}
+
+		/* If transitioning to allow "search", reset all history
+		 * bitmaps and stats in active table (this will become the new
+		 * "search" table). */
+		if (!lq_sta->stay_in_tbl) {
+			for (i = 0; i < IWL_RATE_COUNT; i++)
+				rs_rate_scale_clear_window(&(tbl->win[i]));
+		}
+	}
+}
+
+/*
+ * setup rate table in uCode
+ */
+static void rs_update_rate_tbl(struct iwl_priv *priv,
+			       struct iwl_rxon_context *ctx,
+			       struct iwl_lq_sta *lq_sta,
+			       struct iwl_scale_tbl_info *tbl,
+			       int index, u8 is_green)
+{
+	u32 rate;
+
+	/* Update uCode's rate table. */
+	rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
+	rs_fill_link_cmd(priv, lq_sta, rate);
+	iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
+}
+
+/*
+ * Do rate scaling and search for new modulation mode.
+ */
+static void rs_rate_scale_perform(struct iwl_priv *priv,
+				  struct sk_buff *skb,
+				  struct ieee80211_sta *sta,
+				  struct iwl_lq_sta *lq_sta)
+{
+	struct ieee80211_hw *hw = priv->hw;
+	struct ieee80211_conf *conf = &hw->conf;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	int low = IWL_RATE_INVALID;
+	int high = IWL_RATE_INVALID;
+	int index;
+	int i;
+	struct iwl_rate_scale_data *window = NULL;
+	int current_tpt = IWL_INVALID_VALUE;
+	int low_tpt = IWL_INVALID_VALUE;
+	int high_tpt = IWL_INVALID_VALUE;
+	u32 fail_count;
+	s8 scale_action = 0;
+	u16 rate_mask;
+	u8 update_lq = 0;
+	struct iwl_scale_tbl_info *tbl, *tbl1;
+	u16 rate_scale_index_msk = 0;
+	u8 is_green = 0;
+	u8 active_tbl = 0;
+	u8 done_search = 0;
+	u16 high_low;
+	s32 sr;
+	u8 tid = IWL_MAX_TID_COUNT;
+	struct iwl_tid_data *tid_data;
+	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+	struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+	IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n");
+
+	/* Send management frames and NO_ACK data using lowest rate. */
+	/* TODO: this could probably be improved.. */
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    info->flags & IEEE80211_TX_CTL_NO_ACK)
+		return;
+
+	lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
+
+	tid = rs_tl_add_packet(lq_sta, hdr);
+	if ((tid != IWL_MAX_TID_COUNT) &&
+	    (lq_sta->tx_agg_tid_en & (1 << tid))) {
+		tid_data = &priv->tid_data[lq_sta->lq.sta_id][tid];
+		if (tid_data->agg.state == IWL_AGG_OFF)
+			lq_sta->is_agg = 0;
+		else
+			lq_sta->is_agg = 1;
+	} else
+		lq_sta->is_agg = 0;
+
+	/*
+	 * Select rate-scale / modulation-mode table to work with in
+	 * the rest of this function:  "search" if searching for better
+	 * modulation mode, or "active" if doing rate scaling within a mode.
+	 */
+	if (!lq_sta->search_better_tbl)
+		active_tbl = lq_sta->active_tbl;
+	else
+		active_tbl = 1 - lq_sta->active_tbl;
+
+	tbl = &(lq_sta->lq_info[active_tbl]);
+	if (is_legacy(tbl->lq_type))
+		lq_sta->is_green = 0;
+	else
+		lq_sta->is_green = rs_use_green(sta);
+	is_green = lq_sta->is_green;
+
+	/* current tx rate */
+	index = lq_sta->last_txrate_idx;
+
+	IWL_DEBUG_RATE(priv, "Rate scale index %d for type %d\n", index,
+		       tbl->lq_type);
+
+	/* rates available for this association, and for modulation mode */
+	rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
+
+	IWL_DEBUG_RATE(priv, "mask 0x%04X\n", rate_mask);
+
+	/* mask with station rate restriction */
+	if (is_legacy(tbl->lq_type)) {
+		if (lq_sta->band == IEEE80211_BAND_5GHZ)
+			/* supp_rates has no CCK bits in A mode */
+			rate_scale_index_msk = (u16) (rate_mask &
+				(lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
+		else
+			rate_scale_index_msk = (u16) (rate_mask &
+						      lq_sta->supp_rates);
+
+	} else
+		rate_scale_index_msk = rate_mask;
+
+	if (!rate_scale_index_msk)
+		rate_scale_index_msk = rate_mask;
+
+	if (!((1 << index) & rate_scale_index_msk)) {
+		IWL_ERR(priv, "Current Rate is not valid\n");
+		if (lq_sta->search_better_tbl) {
+			/* revert to active table if search table is not valid*/
+			tbl->lq_type = LQ_NONE;
+			lq_sta->search_better_tbl = 0;
+			tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+			/* get "active" rate info */
+			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+			rs_update_rate_tbl(priv, ctx, lq_sta, tbl,
+					   index, is_green);
+		}
+		return;
+	}
+
+	/* Get expected throughput table and history window for current rate */
+	if (!tbl->expected_tpt) {
+		IWL_ERR(priv, "tbl->expected_tpt is NULL\n");
+		return;
+	}
+
+	/* force user max rate if set by user */
+	if ((lq_sta->max_rate_idx != -1) &&
+	    (lq_sta->max_rate_idx < index)) {
+		index = lq_sta->max_rate_idx;
+		update_lq = 1;
+		window = &(tbl->win[index]);
+		goto lq_update;
+	}
+
+	window = &(tbl->win[index]);
+
+	/*
+	 * If there is not enough history to calculate actual average
+	 * throughput, keep analyzing results of more tx frames, without
+	 * changing rate or mode (bypass most of the rest of this function).
+	 * Set up new rate table in uCode only if old rate is not supported
+	 * in current association (use new rate found above).
+	 */
+	fail_count = window->counter - window->success_counter;
+	if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
+			(window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
+		IWL_DEBUG_RATE(priv, "LQ: still below TH. succ=%d total=%d "
+			       "for index %d\n",
+			       window->success_counter, window->counter, index);
+
+		/* Can't calculate this yet; not enough history */
+		window->average_tpt = IWL_INVALID_VALUE;
+
+		/* Should we stay with this modulation mode,
+		 * or search for a new one? */
+		rs_stay_in_table(lq_sta, false);
+
+		goto out;
+	}
+	/* Else we have enough samples; calculate estimate of
+	 * actual average throughput */
+	if (window->average_tpt != ((window->success_ratio *
+			tbl->expected_tpt[index] + 64) / 128)) {
+		IWL_ERR(priv, "expected_tpt should have been calculated by now\n");
+		window->average_tpt = ((window->success_ratio *
+					tbl->expected_tpt[index] + 64) / 128);
+	}
+
+	/* If we are searching for better modulation mode, check success. */
+	if (lq_sta->search_better_tbl &&
+	    (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI)) {
+		/* If good success, continue using the "search" mode;
+		 * no need to send new link quality command, since we're
+		 * continuing to use the setup that we've been trying. */
+		if (window->average_tpt > lq_sta->last_tpt) {
+
+			IWL_DEBUG_RATE(priv, "LQ: SWITCHING TO NEW TABLE "
+					"suc=%d cur-tpt=%d old-tpt=%d\n",
+					window->success_ratio,
+					window->average_tpt,
+					lq_sta->last_tpt);
+
+			if (!is_legacy(tbl->lq_type))
+				lq_sta->enable_counter = 1;
+
+			/* Swap tables; "search" becomes "active" */
+			lq_sta->active_tbl = active_tbl;
+			current_tpt = window->average_tpt;
+
+		/* Else poor success; go back to mode in "active" table */
+		} else {
+
+			IWL_DEBUG_RATE(priv, "LQ: GOING BACK TO THE OLD TABLE "
+					"suc=%d cur-tpt=%d old-tpt=%d\n",
+					window->success_ratio,
+					window->average_tpt,
+					lq_sta->last_tpt);
+
+			/* Nullify "search" table */
+			tbl->lq_type = LQ_NONE;
+
+			/* Revert to "active" table */
+			active_tbl = lq_sta->active_tbl;
+			tbl = &(lq_sta->lq_info[active_tbl]);
+
+			/* Revert to "active" rate and throughput info */
+			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+			current_tpt = lq_sta->last_tpt;
+
+			/* Need to set up a new rate table in uCode */
+			update_lq = 1;
+		}
+
+		/* Either way, we've made a decision; modulation mode
+		 * search is done, allow rate adjustment next time. */
+		lq_sta->search_better_tbl = 0;
+		done_search = 1;	/* Don't switch modes below! */
+		goto lq_update;
+	}
+
+	/* (Else) not in search of better modulation mode, try for better
+	 * starting rate, while staying in this mode. */
+	high_low = rs_get_adjacent_rate(priv, index, rate_scale_index_msk,
+					tbl->lq_type);
+	low = high_low & 0xff;
+	high = (high_low >> 8) & 0xff;
+
+	/* If user set max rate, dont allow higher than user constrain */
+	if ((lq_sta->max_rate_idx != -1) &&
+	    (lq_sta->max_rate_idx < high))
+		high = IWL_RATE_INVALID;
+
+	sr = window->success_ratio;
+
+	/* Collect measured throughputs for current and adjacent rates */
+	current_tpt = window->average_tpt;
+	if (low != IWL_RATE_INVALID)
+		low_tpt = tbl->win[low].average_tpt;
+	if (high != IWL_RATE_INVALID)
+		high_tpt = tbl->win[high].average_tpt;
+
+	scale_action = 0;
+
+	/* Too many failures, decrease rate */
+	if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
+		IWL_DEBUG_RATE(priv, "decrease rate because of low success_ratio\n");
+		scale_action = -1;
+
+	/* No throughput measured yet for adjacent rates; try increase. */
+	} else if ((low_tpt == IWL_INVALID_VALUE) &&
+		   (high_tpt == IWL_INVALID_VALUE)) {
+
+		if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
+			scale_action = 1;
+		else if (low != IWL_RATE_INVALID)
+			scale_action = 0;
+	}
+
+	/* Both adjacent throughputs are measured, but neither one has better
+	 * throughput; we're using the best rate, don't change it! */
+	else if ((low_tpt != IWL_INVALID_VALUE) &&
+		 (high_tpt != IWL_INVALID_VALUE) &&
+		 (low_tpt < current_tpt) &&
+		 (high_tpt < current_tpt))
+		scale_action = 0;
+
+	/* At least one adjacent rate's throughput is measured,
+	 * and may have better performance. */
+	else {
+		/* Higher adjacent rate's throughput is measured */
+		if (high_tpt != IWL_INVALID_VALUE) {
+			/* Higher rate has better throughput */
+			if (high_tpt > current_tpt &&
+					sr >= IWL_RATE_INCREASE_TH) {
+				scale_action = 1;
+			} else {
+				scale_action = 0;
+			}
+
+		/* Lower adjacent rate's throughput is measured */
+		} else if (low_tpt != IWL_INVALID_VALUE) {
+			/* Lower rate has better throughput */
+			if (low_tpt > current_tpt) {
+				IWL_DEBUG_RATE(priv,
+				    "decrease rate because of low tpt\n");
+				scale_action = -1;
+			} else if (sr >= IWL_RATE_INCREASE_TH) {
+				scale_action = 1;
+			}
+		}
+	}
+
+	/* Sanity check; asked for decrease, but success rate or throughput
+	 * has been good at old rate.  Don't change it. */
+	if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
+		    ((sr > IWL_RATE_HIGH_TH) ||
+		     (current_tpt > (100 * tbl->expected_tpt[low]))))
+		scale_action = 0;
+	if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type))
+		scale_action = -1;
+	if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI &&
+		(is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
+		scale_action = -1;
+
+	if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+	     (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+		if (lq_sta->last_bt_traffic > priv->bt_traffic_load) {
+			/*
+			 * don't set scale_action, don't want to scale up if
+			 * the rate scale doesn't otherwise think that is a
+			 * good idea.
+			 */
+		} else if (lq_sta->last_bt_traffic <= priv->bt_traffic_load) {
+			scale_action = -1;
+		}
+	}
+	lq_sta->last_bt_traffic = priv->bt_traffic_load;
+
+	if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+	     (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+		/* search for a new modulation */
+		rs_stay_in_table(lq_sta, true);
+		goto lq_update;
+	}
+
+	switch (scale_action) {
+	case -1:
+		/* Decrease starting rate, update uCode's rate table */
+		if (low != IWL_RATE_INVALID) {
+			update_lq = 1;
+			index = low;
+		}
+
+		break;
+	case 1:
+		/* Increase starting rate, update uCode's rate table */
+		if (high != IWL_RATE_INVALID) {
+			update_lq = 1;
+			index = high;
+		}
+
+		break;
+	case 0:
+		/* No change */
+	default:
+		break;
+	}
+
+	IWL_DEBUG_RATE(priv, "choose rate scale index %d action %d low %d "
+		    "high %d type %d\n",
+		     index, scale_action, low, high, tbl->lq_type);
+
+lq_update:
+	/* Replace uCode's rate table for the destination station. */
+	if (update_lq)
+		rs_update_rate_tbl(priv, ctx, lq_sta, tbl, index, is_green);
+
+	if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
+		/* Should we stay with this modulation mode,
+		 * or search for a new one? */
+	  rs_stay_in_table(lq_sta, false);
+	}
+	/*
+	 * Search for new modulation mode if we're:
+	 * 1)  Not changing rates right now
+	 * 2)  Not just finishing up a search
+	 * 3)  Allowing a new search
+	 */
+	if (!update_lq && !done_search && !lq_sta->stay_in_tbl && window->counter) {
+		/* Save current throughput to compare with "search" throughput*/
+		lq_sta->last_tpt = current_tpt;
+
+		/* Select a new "search" modulation mode to try.
+		 * If one is found, set up the new "search" table. */
+		if (is_legacy(tbl->lq_type))
+			rs_move_legacy_other(priv, lq_sta, conf, sta, index);
+		else if (is_siso(tbl->lq_type))
+			rs_move_siso_to_other(priv, lq_sta, conf, sta, index);
+		else if (is_mimo2(tbl->lq_type))
+			rs_move_mimo2_to_other(priv, lq_sta, conf, sta, index);
+		else
+			rs_move_mimo3_to_other(priv, lq_sta, conf, sta, index);
+
+		/* If new "search" mode was selected, set up in uCode table */
+		if (lq_sta->search_better_tbl) {
+			/* Access the "search" table, clear its history. */
+			tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+			for (i = 0; i < IWL_RATE_COUNT; i++)
+				rs_rate_scale_clear_window(&(tbl->win[i]));
+
+			/* Use new "search" start rate */
+			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+
+			IWL_DEBUG_RATE(priv, "Switch current  mcs: %X index: %d\n",
+				     tbl->current_rate, index);
+			rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
+			iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
+		} else
+			done_search = 1;
+	}
+
+	if (done_search && !lq_sta->stay_in_tbl) {
+		/* If the "active" (non-search) mode was legacy,
+		 * and we've tried switching antennas,
+		 * but we haven't been able to try HT modes (not available),
+		 * stay with best antenna legacy modulation for a while
+		 * before next round of mode comparisons. */
+		tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
+		if (is_legacy(tbl1->lq_type) && !conf_is_ht(conf) &&
+		    lq_sta->action_counter > tbl1->max_search) {
+			IWL_DEBUG_RATE(priv, "LQ: STAY in legacy table\n");
+			rs_set_stay_in_table(priv, 1, lq_sta);
+		}
+
+		/* If we're in an HT mode, and all 3 mode switch actions
+		 * have been tried and compared, stay in this best modulation
+		 * mode for a while before next round of mode comparisons. */
+		if (lq_sta->enable_counter &&
+		    (lq_sta->action_counter >= tbl1->max_search) &&
+		    iwl_ht_enabled(priv)) {
+			if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
+			    (lq_sta->tx_agg_tid_en & (1 << tid)) &&
+			    (tid != IWL_MAX_TID_COUNT)) {
+				u8 sta_id = lq_sta->lq.sta_id;
+				tid_data = &priv->tid_data[sta_id][tid];
+				if (tid_data->agg.state == IWL_AGG_OFF) {
+					IWL_DEBUG_RATE(priv,
+						       "try to aggregate tid %d\n",
+						       tid);
+					rs_tl_turn_on_agg(priv, tid,
+							  lq_sta, sta);
+				}
+			}
+			rs_set_stay_in_table(priv, 0, lq_sta);
+		}
+	}
+
+out:
+	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
+	lq_sta->last_txrate_idx = index;
+}
+
+/**
+ * rs_initialize_lq - Initialize a station's hardware rate table
+ *
+ * The uCode's station table contains a table of fallback rates
+ * for automatic fallback during transmission.
+ *
+ * NOTE: This sets up a default set of values.  These will be replaced later
+ *       if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
+ *       rc80211_simple.
+ *
+ * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
+ *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
+ *       which requires station table entry to exist).
+ */
+static void rs_initialize_lq(struct iwl_priv *priv,
+			     struct ieee80211_sta *sta,
+			     struct iwl_lq_sta *lq_sta)
+{
+	struct iwl_scale_tbl_info *tbl;
+	int rate_idx;
+	int i;
+	u32 rate;
+	u8 use_green = rs_use_green(sta);
+	u8 active_tbl = 0;
+	u8 valid_tx_ant;
+	struct iwl_station_priv *sta_priv;
+	struct iwl_rxon_context *ctx;
+
+	if (!sta || !lq_sta)
+		return;
+
+	sta_priv = (void *)sta->drv_priv;
+	ctx = sta_priv->ctx;
+
+	i = lq_sta->last_txrate_idx;
+
+	valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+
+	if (!lq_sta->search_better_tbl)
+		active_tbl = lq_sta->active_tbl;
+	else
+		active_tbl = 1 - lq_sta->active_tbl;
+
+	tbl = &(lq_sta->lq_info[active_tbl]);
+
+	if ((i < 0) || (i >= IWL_RATE_COUNT))
+		i = 0;
+
+	rate = iwl_rates[i].plcp;
+	tbl->ant_type = first_antenna(valid_tx_ant);
+	rate |= tbl->ant_type << RATE_MCS_ANT_POS;
+
+	if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
+		rate |= RATE_MCS_CCK_MSK;
+
+	rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx);
+	if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
+	    rs_toggle_antenna(valid_tx_ant, &rate, tbl);
+
+	rate = rate_n_flags_from_tbl(priv, tbl, rate_idx, use_green);
+	tbl->current_rate = rate;
+	rs_set_expected_tpt_table(lq_sta, tbl);
+	rs_fill_link_cmd(NULL, lq_sta, rate);
+	priv->stations[lq_sta->lq.sta_id].lq = &lq_sta->lq;
+	iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_SYNC, true);
+}
+
+static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
+			struct ieee80211_tx_rate_control *txrc)
+{
+
+	struct sk_buff *skb = txrc->skb;
+	struct ieee80211_supported_band *sband = txrc->sband;
+	struct iwl_op_mode *op_mode __maybe_unused =
+			(struct iwl_op_mode *)priv_r;
+	struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct iwl_lq_sta *lq_sta = priv_sta;
+	int rate_idx;
+
+	IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n");
+
+	/* Get max rate if user set max rate */
+	if (lq_sta) {
+		lq_sta->max_rate_idx = txrc->max_rate_idx;
+		if ((sband->band == IEEE80211_BAND_5GHZ) &&
+		    (lq_sta->max_rate_idx != -1))
+			lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE;
+		if ((lq_sta->max_rate_idx < 0) ||
+		    (lq_sta->max_rate_idx >= IWL_RATE_COUNT))
+			lq_sta->max_rate_idx = -1;
+	}
+
+	/* Treat uninitialized rate scaling data same as non-existing. */
+	if (lq_sta && !lq_sta->drv) {
+		IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n");
+		priv_sta = NULL;
+	}
+
+	/* Send management frames and NO_ACK data using lowest rate. */
+	if (rate_control_send_low(sta, priv_sta, txrc))
+		return;
+
+	rate_idx  = lq_sta->last_txrate_idx;
+
+	if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) {
+		rate_idx -= IWL_FIRST_OFDM_RATE;
+		/* 6M and 9M shared same MCS index */
+		rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0;
+		if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
+		    IWL_RATE_MIMO3_6M_PLCP)
+			rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM);
+		else if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
+			 IWL_RATE_MIMO2_6M_PLCP)
+			rate_idx = rate_idx + MCS_INDEX_PER_STREAM;
+		info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
+		if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK)
+			info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
+		if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK)
+			info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA;
+		if (lq_sta->last_rate_n_flags & RATE_MCS_HT40_MSK)
+			info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+		if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK)
+			info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
+	} else {
+		/* Check for invalid rates */
+		if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) ||
+				((sband->band == IEEE80211_BAND_5GHZ) &&
+				 (rate_idx < IWL_FIRST_OFDM_RATE)))
+			rate_idx = rate_lowest_index(sband, sta);
+		/* On valid 5 GHz rate, adjust index */
+		else if (sband->band == IEEE80211_BAND_5GHZ)
+			rate_idx -= IWL_FIRST_OFDM_RATE;
+		info->control.rates[0].flags = 0;
+	}
+	info->control.rates[0].idx = rate_idx;
+
+}
+
+static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
+			  gfp_t gfp)
+{
+	struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv;
+	struct iwl_op_mode *op_mode __maybe_unused =
+			(struct iwl_op_mode *)priv_rate;
+	struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
+
+	IWL_DEBUG_RATE(priv, "create station rate scale window\n");
+
+	return &sta_priv->lq_sta;
+}
+
+/*
+ * Called after adding a new station to initialize rate scaling
+ */
+void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id)
+{
+	int i, j;
+	struct ieee80211_hw *hw = priv->hw;
+	struct ieee80211_conf *conf = &priv->hw->conf;
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+	struct iwl_station_priv *sta_priv;
+	struct iwl_lq_sta *lq_sta;
+	struct ieee80211_supported_band *sband;
+	unsigned long supp; /* must be unsigned long for for_each_set_bit */
+
+	sta_priv = (struct iwl_station_priv *) sta->drv_priv;
+	lq_sta = &sta_priv->lq_sta;
+	sband = hw->wiphy->bands[conf->channel->band];
+
+
+	lq_sta->lq.sta_id = sta_id;
+
+	for (j = 0; j < LQ_SIZE; j++)
+		for (i = 0; i < IWL_RATE_COUNT; i++)
+			rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
+
+	lq_sta->flush_timer = 0;
+	lq_sta->supp_rates = sta->supp_rates[sband->band];
+	for (j = 0; j < LQ_SIZE; j++)
+		for (i = 0; i < IWL_RATE_COUNT; i++)
+			rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
+
+	IWL_DEBUG_RATE(priv, "LQ: *** rate scale station global init for station %d ***\n",
+		       sta_id);
+	/* TODO: what is a good starting rate for STA? About middle? Maybe not
+	 * the lowest or the highest rate.. Could consider using RSSI from
+	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
+	 * after assoc.. */
+
+	lq_sta->is_dup = 0;
+	lq_sta->max_rate_idx = -1;
+	lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
+	lq_sta->is_green = rs_use_green(sta);
+	lq_sta->band = sband->band;
+	/*
+	 * active legacy rates as per supported rates bitmap
+	 */
+	supp = sta->supp_rates[sband->band];
+	lq_sta->active_legacy_rate = 0;
+	for_each_set_bit(i, &supp, BITS_PER_LONG)
+		lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value);
+
+	/*
+	 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
+	 * supp_rates[] does not; shift to convert format, force 9 MBits off.
+	 */
+	lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
+	lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
+	lq_sta->active_siso_rate &= ~((u16)0x2);
+	lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
+
+	/* Same here */
+	lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
+	lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
+	lq_sta->active_mimo2_rate &= ~((u16)0x2);
+	lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
+
+	lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1;
+	lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1;
+	lq_sta->active_mimo3_rate &= ~((u16)0x2);
+	lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
+
+	IWL_DEBUG_RATE(priv, "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n",
+		     lq_sta->active_siso_rate,
+		     lq_sta->active_mimo2_rate,
+		     lq_sta->active_mimo3_rate);
+
+	/* These values will be overridden later */
+	lq_sta->lq.general_params.single_stream_ant_msk =
+		first_antenna(priv->eeprom_data->valid_tx_ant);
+	lq_sta->lq.general_params.dual_stream_ant_msk =
+		priv->eeprom_data->valid_tx_ant &
+		~first_antenna(priv->eeprom_data->valid_tx_ant);
+	if (!lq_sta->lq.general_params.dual_stream_ant_msk) {
+		lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
+	} else if (num_of_ant(priv->eeprom_data->valid_tx_ant) == 2) {
+		lq_sta->lq.general_params.dual_stream_ant_msk =
+			priv->eeprom_data->valid_tx_ant;
+	}
+
+	/* as default allow aggregation for all tids */
+	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
+	lq_sta->drv = priv;
+
+	/* Set last_txrate_idx to lowest rate */
+	lq_sta->last_txrate_idx = rate_lowest_index(sband, sta);
+	if (sband->band == IEEE80211_BAND_5GHZ)
+		lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+	lq_sta->is_agg = 0;
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+	priv->tm_fixed_rate = 0;
+#endif
+#ifdef CONFIG_MAC80211_DEBUGFS
+	lq_sta->dbg_fixed_rate = 0;
+#endif
+
+	rs_initialize_lq(priv, sta, lq_sta);
+}
+
+static void rs_fill_link_cmd(struct iwl_priv *priv,
+			     struct iwl_lq_sta *lq_sta, u32 new_rate)
+{
+	struct iwl_scale_tbl_info tbl_type;
+	int index = 0;
+	int rate_idx;
+	int repeat_rate = 0;
+	u8 ant_toggle_cnt = 0;
+	u8 use_ht_possible = 1;
+	u8 valid_tx_ant = 0;
+	struct iwl_station_priv *sta_priv =
+		container_of(lq_sta, struct iwl_station_priv, lq_sta);
+	struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq;
+
+	/* Override starting rate (index 0) if needed for debug purposes */
+	rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+	/* Interpret new_rate (rate_n_flags) */
+	rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
+				  &tbl_type, &rate_idx);
+
+	if (priv && priv->bt_full_concurrent) {
+		/* 1x1 only */
+		tbl_type.ant_type =
+			first_antenna(priv->eeprom_data->valid_tx_ant);
+	}
+
+	/* How many times should we repeat the initial rate? */
+	if (is_legacy(tbl_type.lq_type)) {
+		ant_toggle_cnt = 1;
+		repeat_rate = IWL_NUMBER_TRY;
+	} else {
+		repeat_rate = min(IWL_HT_NUMBER_TRY,
+				  LINK_QUAL_AGG_DISABLE_START_DEF - 1);
+	}
+
+	lq_cmd->general_params.mimo_delimiter =
+			is_mimo(tbl_type.lq_type) ? 1 : 0;
+
+	/* Fill 1st table entry (index 0) */
+	lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
+
+	if (num_of_ant(tbl_type.ant_type) == 1) {
+		lq_cmd->general_params.single_stream_ant_msk =
+						tbl_type.ant_type;
+	} else if (num_of_ant(tbl_type.ant_type) == 2) {
+		lq_cmd->general_params.dual_stream_ant_msk =
+						tbl_type.ant_type;
+	} /* otherwise we don't modify the existing value */
+
+	index++;
+	repeat_rate--;
+	if (priv) {
+		if (priv->bt_full_concurrent)
+			valid_tx_ant = ANT_A;
+		else
+			valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+	}
+
+	/* Fill rest of rate table */
+	while (index < LINK_QUAL_MAX_RETRY_NUM) {
+		/* Repeat initial/next rate.
+		 * For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
+		 * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
+		while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
+			if (is_legacy(tbl_type.lq_type)) {
+				if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
+					ant_toggle_cnt++;
+				else if (priv &&
+					 rs_toggle_antenna(valid_tx_ant,
+							&new_rate, &tbl_type))
+					ant_toggle_cnt = 1;
+			}
+
+			/* Override next rate if needed for debug purposes */
+			rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+			/* Fill next table entry */
+			lq_cmd->rs_table[index].rate_n_flags =
+					cpu_to_le32(new_rate);
+			repeat_rate--;
+			index++;
+		}
+
+		rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
+						&rate_idx);
+
+		if (priv && priv->bt_full_concurrent) {
+			/* 1x1 only */
+			tbl_type.ant_type =
+			    first_antenna(priv->eeprom_data->valid_tx_ant);
+		}
+
+		/* Indicate to uCode which entries might be MIMO.
+		 * If initial rate was MIMO, this will finally end up
+		 * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
+		if (is_mimo(tbl_type.lq_type))
+			lq_cmd->general_params.mimo_delimiter = index;
+
+		/* Get next rate */
+		new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
+					     use_ht_possible);
+
+		/* How many times should we repeat the next rate? */
+		if (is_legacy(tbl_type.lq_type)) {
+			if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
+				ant_toggle_cnt++;
+			else if (priv &&
+				 rs_toggle_antenna(valid_tx_ant,
+						   &new_rate, &tbl_type))
+				ant_toggle_cnt = 1;
+
+			repeat_rate = IWL_NUMBER_TRY;
+		} else {
+			repeat_rate = IWL_HT_NUMBER_TRY;
+		}
+
+		/* Don't allow HT rates after next pass.
+		 * rs_get_lower_rate() will change type to LQ_A or LQ_G. */
+		use_ht_possible = 0;
+
+		/* Override next rate if needed for debug purposes */
+		rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+		/* Fill next table entry */
+		lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
+
+		index++;
+		repeat_rate--;
+	}
+
+	lq_cmd->agg_params.agg_frame_cnt_limit =
+		sta_priv->max_agg_bufsize ?: LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+	lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+
+	lq_cmd->agg_params.agg_time_limit =
+		cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+	/*
+	 * overwrite if needed, pass aggregation time limit
+	 * to uCode in uSec
+	 */
+	if (priv && priv->cfg->bt_params &&
+	    priv->cfg->bt_params->agg_time_limit &&
+	    priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
+		lq_cmd->agg_params.agg_time_limit =
+			cpu_to_le16(priv->cfg->bt_params->agg_time_limit);
+}
+
+static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+{
+	return hw->priv;
+}
+/* rate scale requires free function to be implemented */
+static void rs_free(void *priv_rate)
+{
+	return;
+}
+
+static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
+			void *priv_sta)
+{
+	struct iwl_op_mode *op_mode __maybe_unused = priv_r;
+	struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
+
+	IWL_DEBUG_RATE(priv, "enter\n");
+	IWL_DEBUG_RATE(priv, "leave\n");
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+			     u32 *rate_n_flags, int index)
+{
+	struct iwl_priv *priv;
+	u8 valid_tx_ant;
+	u8 ant_sel_tx;
+
+	priv = lq_sta->drv;
+	valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+	if (lq_sta->dbg_fixed_rate) {
+		ant_sel_tx =
+		  ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
+		  >> RATE_MCS_ANT_POS);
+		if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) {
+			*rate_n_flags = lq_sta->dbg_fixed_rate;
+			IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
+		} else {
+			lq_sta->dbg_fixed_rate = 0;
+			IWL_ERR(priv,
+			    "Invalid antenna selection 0x%X, Valid is 0x%X\n",
+			    ant_sel_tx, valid_tx_ant);
+			IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
+		}
+	} else {
+		IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
+	}
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
+			const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct iwl_lq_sta *lq_sta = file->private_data;
+	struct iwl_priv *priv;
+	char buf[64];
+	size_t buf_size;
+	u32 parsed_rate;
+
+
+	priv = lq_sta->drv;
+	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, "%x", &parsed_rate) == 1)
+		lq_sta->dbg_fixed_rate = parsed_rate;
+	else
+		lq_sta->dbg_fixed_rate = 0;
+
+	rs_program_fix_rate(priv, lq_sta);
+
+	return count;
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
+			char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char *buff;
+	int desc = 0;
+	int i = 0;
+	int index = 0;
+	ssize_t ret;
+
+	struct iwl_lq_sta *lq_sta = file->private_data;
+	struct iwl_priv *priv;
+	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+
+	priv = lq_sta->drv;
+	buff = kmalloc(1024, GFP_KERNEL);
+	if (!buff)
+		return -ENOMEM;
+
+	desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
+	desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
+			lq_sta->total_failed, lq_sta->total_success,
+			lq_sta->active_legacy_rate);
+	desc += sprintf(buff+desc, "fixed rate 0x%X\n",
+			lq_sta->dbg_fixed_rate);
+	desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
+	    (priv->eeprom_data->valid_tx_ant & ANT_A) ? "ANT_A," : "",
+	    (priv->eeprom_data->valid_tx_ant & ANT_B) ? "ANT_B," : "",
+	    (priv->eeprom_data->valid_tx_ant & ANT_C) ? "ANT_C" : "");
+	desc += sprintf(buff+desc, "lq type %s\n",
+	   (is_legacy(tbl->lq_type)) ? "legacy" : "HT");
+	if (is_Ht(tbl->lq_type)) {
+		desc += sprintf(buff+desc, " %s",
+		   (is_siso(tbl->lq_type)) ? "SISO" :
+		   ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
+		   desc += sprintf(buff+desc, " %s",
+		   (tbl->is_ht40) ? "40MHz" : "20MHz");
+		   desc += sprintf(buff+desc, " %s %s %s\n", (tbl->is_SGI) ? "SGI" : "",
+		   (lq_sta->is_green) ? "GF enabled" : "",
+		   (lq_sta->is_agg) ? "AGG on" : "");
+	}
+	desc += sprintf(buff+desc, "last tx rate=0x%X\n",
+		lq_sta->last_rate_n_flags);
+	desc += sprintf(buff+desc, "general:"
+		"flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
+		lq_sta->lq.general_params.flags,
+		lq_sta->lq.general_params.mimo_delimiter,
+		lq_sta->lq.general_params.single_stream_ant_msk,
+		lq_sta->lq.general_params.dual_stream_ant_msk);
+
+	desc += sprintf(buff+desc, "agg:"
+			"time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
+			le16_to_cpu(lq_sta->lq.agg_params.agg_time_limit),
+			lq_sta->lq.agg_params.agg_dis_start_th,
+			lq_sta->lq.agg_params.agg_frame_cnt_limit);
+
+	desc += sprintf(buff+desc,
+			"Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
+			lq_sta->lq.general_params.start_rate_index[0],
+			lq_sta->lq.general_params.start_rate_index[1],
+			lq_sta->lq.general_params.start_rate_index[2],
+			lq_sta->lq.general_params.start_rate_index[3]);
+
+	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+		index = iwl_hwrate_to_plcp_idx(
+			le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
+		if (is_legacy(tbl->lq_type)) {
+			desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n",
+				i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
+				iwl_rate_mcs[index].mbps);
+		} else {
+			desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps (%s)\n",
+				i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
+				iwl_rate_mcs[index].mbps, iwl_rate_mcs[index].mcs);
+		}
+	}
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+	kfree(buff);
+	return ret;
+}
+
+static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
+	.write = rs_sta_dbgfs_scale_table_write,
+	.read = rs_sta_dbgfs_scale_table_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
+			char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char *buff;
+	int desc = 0;
+	int i, j;
+	ssize_t ret;
+
+	struct iwl_lq_sta *lq_sta = file->private_data;
+
+	buff = kmalloc(1024, GFP_KERNEL);
+	if (!buff)
+		return -ENOMEM;
+
+	for (i = 0; i < LQ_SIZE; i++) {
+		desc += sprintf(buff+desc,
+				"%s type=%d SGI=%d HT40=%d DUP=%d GF=%d\n"
+				"rate=0x%X\n",
+				lq_sta->active_tbl == i ? "*" : "x",
+				lq_sta->lq_info[i].lq_type,
+				lq_sta->lq_info[i].is_SGI,
+				lq_sta->lq_info[i].is_ht40,
+				lq_sta->lq_info[i].is_dup,
+				lq_sta->is_green,
+				lq_sta->lq_info[i].current_rate);
+		for (j = 0; j < IWL_RATE_COUNT; j++) {
+			desc += sprintf(buff+desc,
+				"counter=%d success=%d %%=%d\n",
+				lq_sta->lq_info[i].win[j].counter,
+				lq_sta->lq_info[i].win[j].success_counter,
+				lq_sta->lq_info[i].win[j].success_ratio);
+		}
+	}
+	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+	kfree(buff);
+	return ret;
+}
+
+static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
+	.read = rs_sta_dbgfs_stats_table_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
+			char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct iwl_lq_sta *lq_sta = file->private_data;
+	struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
+	char buff[120];
+	int desc = 0;
+
+	if (is_Ht(tbl->lq_type))
+		desc += sprintf(buff+desc,
+				"Bit Rate= %d Mb/s\n",
+				tbl->expected_tpt[lq_sta->last_txrate_idx]);
+	else
+		desc += sprintf(buff+desc,
+				"Bit Rate= %d Mb/s\n",
+				iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
+	.read = rs_sta_dbgfs_rate_scale_data_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+static void rs_add_debugfs(void *priv, void *priv_sta,
+					struct dentry *dir)
+{
+	struct iwl_lq_sta *lq_sta = priv_sta;
+	lq_sta->rs_sta_dbgfs_scale_table_file =
+		debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
+				lq_sta, &rs_sta_dbgfs_scale_table_ops);
+	lq_sta->rs_sta_dbgfs_stats_table_file =
+		debugfs_create_file("rate_stats_table", S_IRUSR, dir,
+			lq_sta, &rs_sta_dbgfs_stats_table_ops);
+	lq_sta->rs_sta_dbgfs_rate_scale_data_file =
+		debugfs_create_file("rate_scale_data", S_IRUSR, dir,
+			lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
+	lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
+		debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
+		&lq_sta->tx_agg_tid_en);
+
+}
+
+static void rs_remove_debugfs(void *priv, void *priv_sta)
+{
+	struct iwl_lq_sta *lq_sta = priv_sta;
+	debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
+	debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
+	debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file);
+	debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
+}
+#endif
+
+/*
+ * Initialization of rate scaling information is done by driver after
+ * the station is added. Since mac80211 calls this function before a
+ * station is added we ignore it.
+ */
+static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband,
+			 struct ieee80211_sta *sta, void *priv_sta)
+{
+}
+static struct rate_control_ops rs_ops = {
+	.module = NULL,
+	.name = RS_NAME,
+	.tx_status = rs_tx_status,
+	.get_rate = rs_get_rate,
+	.rate_init = rs_rate_init_stub,
+	.alloc = rs_alloc,
+	.free = rs_free,
+	.alloc_sta = rs_alloc_sta,
+	.free_sta = rs_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+	.add_sta_debugfs = rs_add_debugfs,
+	.remove_sta_debugfs = rs_remove_debugfs,
+#endif
+};
+
+int iwlagn_rate_control_register(void)
+{
+	return ieee80211_rate_control_register(&rs_ops);
+}
+
+void iwlagn_rate_control_unregister(void)
+{
+	ieee80211_rate_control_unregister(&rs_ops);
+}
+
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.h b/drivers/net/wireless/iwlwifi/dvm/rs.h
new file mode 100644
index 0000000..ad3aea8
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/rs.h
@@ -0,0 +1,433 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 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.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_agn_rs_h__
+#define __iwl_agn_rs_h__
+
+#include <net/mac80211.h>
+
+#include "iwl-config.h"
+
+#include "commands.h"
+
+struct iwl_rate_info {
+	u8 plcp;	/* uCode API:  IWL_RATE_6M_PLCP, etc. */
+	u8 plcp_siso;	/* uCode API:  IWL_RATE_SISO_6M_PLCP, etc. */
+	u8 plcp_mimo2;	/* uCode API:  IWL_RATE_MIMO2_6M_PLCP, etc. */
+	u8 plcp_mimo3;  /* uCode API:  IWL_RATE_MIMO3_6M_PLCP, etc. */
+	u8 ieee;	/* MAC header:  IWL_RATE_6M_IEEE, etc. */
+	u8 prev_ieee;    /* previous rate in IEEE speeds */
+	u8 next_ieee;    /* next rate in IEEE speeds */
+	u8 prev_rs;      /* previous rate used in rs algo */
+	u8 next_rs;      /* next rate used in rs algo */
+	u8 prev_rs_tgg;  /* previous rate used in TGG rs algo */
+	u8 next_rs_tgg;  /* next rate used in TGG rs algo */
+};
+
+/*
+ * These serve as indexes into
+ * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+ */
+enum {
+	IWL_RATE_1M_INDEX = 0,
+	IWL_RATE_2M_INDEX,
+	IWL_RATE_5M_INDEX,
+	IWL_RATE_11M_INDEX,
+	IWL_RATE_6M_INDEX,
+	IWL_RATE_9M_INDEX,
+	IWL_RATE_12M_INDEX,
+	IWL_RATE_18M_INDEX,
+	IWL_RATE_24M_INDEX,
+	IWL_RATE_36M_INDEX,
+	IWL_RATE_48M_INDEX,
+	IWL_RATE_54M_INDEX,
+	IWL_RATE_60M_INDEX,
+	IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/
+	IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1,	/* Excluding 60M */
+	IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
+	IWL_RATE_INVALID = IWL_RATE_COUNT,
+};
+
+enum {
+	IWL_RATE_6M_INDEX_TABLE = 0,
+	IWL_RATE_9M_INDEX_TABLE,
+	IWL_RATE_12M_INDEX_TABLE,
+	IWL_RATE_18M_INDEX_TABLE,
+	IWL_RATE_24M_INDEX_TABLE,
+	IWL_RATE_36M_INDEX_TABLE,
+	IWL_RATE_48M_INDEX_TABLE,
+	IWL_RATE_54M_INDEX_TABLE,
+	IWL_RATE_1M_INDEX_TABLE,
+	IWL_RATE_2M_INDEX_TABLE,
+	IWL_RATE_5M_INDEX_TABLE,
+	IWL_RATE_11M_INDEX_TABLE,
+	IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX - 1,
+};
+
+enum {
+	IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
+	IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
+	IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
+	IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
+};
+
+/* #define vs. enum to keep from defaulting to 'large integer' */
+#define	IWL_RATE_6M_MASK   (1 << IWL_RATE_6M_INDEX)
+#define	IWL_RATE_9M_MASK   (1 << IWL_RATE_9M_INDEX)
+#define	IWL_RATE_12M_MASK  (1 << IWL_RATE_12M_INDEX)
+#define	IWL_RATE_18M_MASK  (1 << IWL_RATE_18M_INDEX)
+#define	IWL_RATE_24M_MASK  (1 << IWL_RATE_24M_INDEX)
+#define	IWL_RATE_36M_MASK  (1 << IWL_RATE_36M_INDEX)
+#define	IWL_RATE_48M_MASK  (1 << IWL_RATE_48M_INDEX)
+#define	IWL_RATE_54M_MASK  (1 << IWL_RATE_54M_INDEX)
+#define IWL_RATE_60M_MASK  (1 << IWL_RATE_60M_INDEX)
+#define	IWL_RATE_1M_MASK   (1 << IWL_RATE_1M_INDEX)
+#define	IWL_RATE_2M_MASK   (1 << IWL_RATE_2M_INDEX)
+#define	IWL_RATE_5M_MASK   (1 << IWL_RATE_5M_INDEX)
+#define	IWL_RATE_11M_MASK  (1 << IWL_RATE_11M_INDEX)
+
+/* uCode API values for legacy bit rates, both OFDM and CCK */
+enum {
+	IWL_RATE_6M_PLCP  = 13,
+	IWL_RATE_9M_PLCP  = 15,
+	IWL_RATE_12M_PLCP = 5,
+	IWL_RATE_18M_PLCP = 7,
+	IWL_RATE_24M_PLCP = 9,
+	IWL_RATE_36M_PLCP = 11,
+	IWL_RATE_48M_PLCP = 1,
+	IWL_RATE_54M_PLCP = 3,
+	IWL_RATE_60M_PLCP = 3,/*FIXME:RS:should be removed*/
+	IWL_RATE_1M_PLCP  = 10,
+	IWL_RATE_2M_PLCP  = 20,
+	IWL_RATE_5M_PLCP  = 55,
+	IWL_RATE_11M_PLCP = 110,
+	/*FIXME:RS:change to IWL_RATE_LEGACY_??M_PLCP */
+	/*FIXME:RS:add IWL_RATE_LEGACY_INVM_PLCP = 0,*/
+};
+
+/* uCode API values for OFDM high-throughput (HT) bit rates */
+enum {
+	IWL_RATE_SISO_6M_PLCP = 0,
+	IWL_RATE_SISO_12M_PLCP = 1,
+	IWL_RATE_SISO_18M_PLCP = 2,
+	IWL_RATE_SISO_24M_PLCP = 3,
+	IWL_RATE_SISO_36M_PLCP = 4,
+	IWL_RATE_SISO_48M_PLCP = 5,
+	IWL_RATE_SISO_54M_PLCP = 6,
+	IWL_RATE_SISO_60M_PLCP = 7,
+	IWL_RATE_MIMO2_6M_PLCP  = 0x8,
+	IWL_RATE_MIMO2_12M_PLCP = 0x9,
+	IWL_RATE_MIMO2_18M_PLCP = 0xa,
+	IWL_RATE_MIMO2_24M_PLCP = 0xb,
+	IWL_RATE_MIMO2_36M_PLCP = 0xc,
+	IWL_RATE_MIMO2_48M_PLCP = 0xd,
+	IWL_RATE_MIMO2_54M_PLCP = 0xe,
+	IWL_RATE_MIMO2_60M_PLCP = 0xf,
+	IWL_RATE_MIMO3_6M_PLCP  = 0x10,
+	IWL_RATE_MIMO3_12M_PLCP = 0x11,
+	IWL_RATE_MIMO3_18M_PLCP = 0x12,
+	IWL_RATE_MIMO3_24M_PLCP = 0x13,
+	IWL_RATE_MIMO3_36M_PLCP = 0x14,
+	IWL_RATE_MIMO3_48M_PLCP = 0x15,
+	IWL_RATE_MIMO3_54M_PLCP = 0x16,
+	IWL_RATE_MIMO3_60M_PLCP = 0x17,
+	IWL_RATE_SISO_INVM_PLCP,
+	IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+	IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+};
+
+/* MAC header values for bit rates */
+enum {
+	IWL_RATE_6M_IEEE  = 12,
+	IWL_RATE_9M_IEEE  = 18,
+	IWL_RATE_12M_IEEE = 24,
+	IWL_RATE_18M_IEEE = 36,
+	IWL_RATE_24M_IEEE = 48,
+	IWL_RATE_36M_IEEE = 72,
+	IWL_RATE_48M_IEEE = 96,
+	IWL_RATE_54M_IEEE = 108,
+	IWL_RATE_60M_IEEE = 120,
+	IWL_RATE_1M_IEEE  = 2,
+	IWL_RATE_2M_IEEE  = 4,
+	IWL_RATE_5M_IEEE  = 11,
+	IWL_RATE_11M_IEEE = 22,
+};
+
+#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
+
+#define IWL_INVALID_VALUE    -1
+
+#define IWL_MIN_RSSI_VAL                 -100
+#define IWL_MAX_RSSI_VAL                    0
+
+/* These values specify how many Tx frame attempts before
+ * searching for a new modulation mode */
+#define IWL_LEGACY_FAILURE_LIMIT	160
+#define IWL_LEGACY_SUCCESS_LIMIT	480
+#define IWL_LEGACY_TABLE_COUNT		160
+
+#define IWL_NONE_LEGACY_FAILURE_LIMIT	400
+#define IWL_NONE_LEGACY_SUCCESS_LIMIT	4500
+#define IWL_NONE_LEGACY_TABLE_COUNT	1500
+
+/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */
+#define IWL_RS_GOOD_RATIO		12800	/* 100% */
+#define IWL_RATE_SCALE_SWITCH		10880	/*  85% */
+#define IWL_RATE_HIGH_TH		10880	/*  85% */
+#define IWL_RATE_INCREASE_TH		6400	/*  50% */
+#define IWL_RATE_DECREASE_TH		1920	/*  15% */
+
+/* possible actions when in legacy mode */
+#define IWL_LEGACY_SWITCH_ANTENNA1      0
+#define IWL_LEGACY_SWITCH_ANTENNA2      1
+#define IWL_LEGACY_SWITCH_SISO          2
+#define IWL_LEGACY_SWITCH_MIMO2_AB      3
+#define IWL_LEGACY_SWITCH_MIMO2_AC      4
+#define IWL_LEGACY_SWITCH_MIMO2_BC      5
+#define IWL_LEGACY_SWITCH_MIMO3_ABC     6
+
+/* possible actions when in siso mode */
+#define IWL_SISO_SWITCH_ANTENNA1        0
+#define IWL_SISO_SWITCH_ANTENNA2        1
+#define IWL_SISO_SWITCH_MIMO2_AB        2
+#define IWL_SISO_SWITCH_MIMO2_AC        3
+#define IWL_SISO_SWITCH_MIMO2_BC        4
+#define IWL_SISO_SWITCH_GI              5
+#define IWL_SISO_SWITCH_MIMO3_ABC       6
+
+
+/* possible actions when in mimo mode */
+#define IWL_MIMO2_SWITCH_ANTENNA1       0
+#define IWL_MIMO2_SWITCH_ANTENNA2       1
+#define IWL_MIMO2_SWITCH_SISO_A         2
+#define IWL_MIMO2_SWITCH_SISO_B         3
+#define IWL_MIMO2_SWITCH_SISO_C         4
+#define IWL_MIMO2_SWITCH_GI             5
+#define IWL_MIMO2_SWITCH_MIMO3_ABC      6
+
+
+/* possible actions when in mimo3 mode */
+#define IWL_MIMO3_SWITCH_ANTENNA1       0
+#define IWL_MIMO3_SWITCH_ANTENNA2       1
+#define IWL_MIMO3_SWITCH_SISO_A         2
+#define IWL_MIMO3_SWITCH_SISO_B         3
+#define IWL_MIMO3_SWITCH_SISO_C         4
+#define IWL_MIMO3_SWITCH_MIMO2_AB       5
+#define IWL_MIMO3_SWITCH_MIMO2_AC       6
+#define IWL_MIMO3_SWITCH_MIMO2_BC       7
+#define IWL_MIMO3_SWITCH_GI             8
+
+
+#define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI
+#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC
+
+/*FIXME:RS:add possible actions for MIMO3*/
+
+#define IWL_ACTION_LIMIT		3	/* # possible actions */
+
+#define LQ_SIZE		2	/* 2 mode tables:  "Active" and "Search" */
+
+/* load per tid defines for A-MPDU activation */
+#define IWL_AGG_TPT_THREHOLD	0
+#define IWL_AGG_LOAD_THRESHOLD	10
+#define IWL_AGG_ALL_TID		0xff
+#define TID_QUEUE_CELL_SPACING	50	/*mS */
+#define TID_QUEUE_MAX_SIZE	20
+#define TID_ROUND_VALUE		5	/* mS */
+
+#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
+#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
+
+extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+
+enum iwl_table_type {
+	LQ_NONE,
+	LQ_G,		/* legacy types */
+	LQ_A,
+	LQ_SISO,	/* high-throughput types */
+	LQ_MIMO2,
+	LQ_MIMO3,
+	LQ_MAX,
+};
+
+#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
+#define is_siso(tbl) ((tbl) == LQ_SISO)
+#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
+#define is_mimo3(tbl) ((tbl) == LQ_MIMO3)
+#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl))
+#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
+#define is_a_band(tbl) ((tbl) == LQ_A)
+#define is_g_and(tbl) ((tbl) == LQ_G)
+
+#define IWL_MAX_MCS_DISPLAY_SIZE	12
+
+struct iwl_rate_mcs_info {
+	char	mbps[IWL_MAX_MCS_DISPLAY_SIZE];
+	char	mcs[IWL_MAX_MCS_DISPLAY_SIZE];
+};
+
+/**
+ * struct iwl_rate_scale_data -- tx success history for one rate
+ */
+struct iwl_rate_scale_data {
+	u64 data;		/* bitmap of successful frames */
+	s32 success_counter;	/* number of frames successful */
+	s32 success_ratio;	/* per-cent * 128  */
+	s32 counter;		/* number of frames attempted */
+	s32 average_tpt;	/* success ratio * expected throughput */
+	unsigned long stamp;
+};
+
+/**
+ * struct iwl_scale_tbl_info -- tx params and success history for all rates
+ *
+ * There are two of these in struct iwl_lq_sta,
+ * one for "active", and one for "search".
+ */
+struct iwl_scale_tbl_info {
+	enum iwl_table_type lq_type;
+	u8 ant_type;
+	u8 is_SGI;	/* 1 = short guard interval */
+	u8 is_ht40;	/* 1 = 40 MHz channel width */
+	u8 is_dup;	/* 1 = duplicated data streams */
+	u8 action;	/* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
+	u8 max_search;	/* maximun number of tables we can search */
+	s32 *expected_tpt;	/* throughput metrics; expected_tpt_G, etc. */
+	u32 current_rate;  /* rate_n_flags, uCode API format */
+	struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
+};
+
+struct iwl_traffic_load {
+	unsigned long time_stamp;	/* age of the oldest statistics */
+	u32 packet_count[TID_QUEUE_MAX_SIZE];   /* packet count in this time
+						 * slice */
+	u32 total;			/* total num of packets during the
+					 * last TID_MAX_TIME_DIFF */
+	u8 queue_count;			/* number of queues that has
+					 * been used since the last cleanup */
+	u8 head;			/* start of the circular buffer */
+};
+
+/**
+ * struct iwl_lq_sta -- driver's rate scaling private structure
+ *
+ * Pointer to this gets passed back and forth between driver and mac80211.
+ */
+struct iwl_lq_sta {
+	u8 active_tbl;		/* index of active table, range 0-1 */
+	u8 enable_counter;	/* indicates HT mode */
+	u8 stay_in_tbl;		/* 1: disallow, 0: allow search for new mode */
+	u8 search_better_tbl;	/* 1: currently trying alternate mode */
+	s32 last_tpt;
+
+	/* The following determine when to search for a new mode */
+	u32 table_count_limit;
+	u32 max_failure_limit;	/* # failed frames before new search */
+	u32 max_success_limit;	/* # successful frames before new search */
+	u32 table_count;
+	u32 total_failed;	/* total failed frames, any/all rates */
+	u32 total_success;	/* total successful frames, any/all rates */
+	u64 flush_timer;	/* time staying in mode before new search */
+
+	u8 action_counter;	/* # mode-switch actions tried */
+	u8 is_green;
+	u8 is_dup;
+	enum ieee80211_band band;
+
+	/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
+	u32 supp_rates;
+	u16 active_legacy_rate;
+	u16 active_siso_rate;
+	u16 active_mimo2_rate;
+	u16 active_mimo3_rate;
+	s8 max_rate_idx;     /* Max rate set by user */
+	u8 missed_rate_counter;
+
+	struct iwl_link_quality_cmd lq;
+	struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
+	struct iwl_traffic_load load[IWL_MAX_TID_COUNT];
+	u8 tx_agg_tid_en;
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct dentry *rs_sta_dbgfs_scale_table_file;
+	struct dentry *rs_sta_dbgfs_stats_table_file;
+	struct dentry *rs_sta_dbgfs_rate_scale_data_file;
+	struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
+	u32 dbg_fixed_rate;
+#endif
+	struct iwl_priv *drv;
+
+	/* used to be in sta_info */
+	int last_txrate_idx;
+	/* last tx rate_n_flags */
+	u32 last_rate_n_flags;
+	/* packets destined for this STA are aggregated */
+	u8 is_agg;
+	/* BT traffic this sta was last updated in */
+	u8 last_bt_traffic;
+};
+
+static inline u8 num_of_ant(u8 mask)
+{
+	return  !!((mask) & ANT_A) +
+		!!((mask) & ANT_B) +
+		!!((mask) & ANT_C);
+}
+
+static inline u8 first_antenna(u8 mask)
+{
+	if (mask & ANT_A)
+		return ANT_A;
+	if (mask & ANT_B)
+		return ANT_B;
+	return ANT_C;
+}
+
+
+/* Initialize station's rate scaling information after adding station */
+extern void iwl_rs_rate_init(struct iwl_priv *priv,
+			     struct ieee80211_sta *sta, u8 sta_id);
+
+/**
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
+ *
+ * Since the rate control algorithm is hardware specific, there is no need
+ * or reason to place it as a stand alone module.  The driver can call
+ * iwl_rate_control_register in order to register the rate control callbacks
+ * with the mac80211 subsystem.  This should be performed prior to calling
+ * ieee80211_register_hw
+ *
+ */
+extern int iwlagn_rate_control_register(void);
+
+/**
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
+ *
+ * This should be called after calling ieee80211_unregister_hw, but before
+ * the driver is unloaded.
+ */
+extern void iwlagn_rate_control_unregister(void);
+
+#endif /* __iwl_agn__rs__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c
new file mode 100644
index 0000000..c1f7a18
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/rx.c
@@ -0,0 +1,1164 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portionhelp of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/etherdevice.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <net/mac80211.h>
+#include <asm/unaligned.h>
+#include "iwl-io.h"
+#include "dev.h"
+#include "calib.h"
+#include "agn.h"
+
+#define IWL_CMD_ENTRY(x) [x] = #x
+
+const char *iwl_dvm_cmd_strings[REPLY_MAX] = {
+	IWL_CMD_ENTRY(REPLY_ALIVE),
+	IWL_CMD_ENTRY(REPLY_ERROR),
+	IWL_CMD_ENTRY(REPLY_ECHO),
+	IWL_CMD_ENTRY(REPLY_RXON),
+	IWL_CMD_ENTRY(REPLY_RXON_ASSOC),
+	IWL_CMD_ENTRY(REPLY_QOS_PARAM),
+	IWL_CMD_ENTRY(REPLY_RXON_TIMING),
+	IWL_CMD_ENTRY(REPLY_ADD_STA),
+	IWL_CMD_ENTRY(REPLY_REMOVE_STA),
+	IWL_CMD_ENTRY(REPLY_REMOVE_ALL_STA),
+	IWL_CMD_ENTRY(REPLY_TXFIFO_FLUSH),
+	IWL_CMD_ENTRY(REPLY_WEPKEY),
+	IWL_CMD_ENTRY(REPLY_TX),
+	IWL_CMD_ENTRY(REPLY_LEDS_CMD),
+	IWL_CMD_ENTRY(REPLY_TX_LINK_QUALITY_CMD),
+	IWL_CMD_ENTRY(COEX_PRIORITY_TABLE_CMD),
+	IWL_CMD_ENTRY(COEX_MEDIUM_NOTIFICATION),
+	IWL_CMD_ENTRY(COEX_EVENT_CMD),
+	IWL_CMD_ENTRY(REPLY_QUIET_CMD),
+	IWL_CMD_ENTRY(REPLY_CHANNEL_SWITCH),
+	IWL_CMD_ENTRY(CHANNEL_SWITCH_NOTIFICATION),
+	IWL_CMD_ENTRY(REPLY_SPECTRUM_MEASUREMENT_CMD),
+	IWL_CMD_ENTRY(SPECTRUM_MEASURE_NOTIFICATION),
+	IWL_CMD_ENTRY(POWER_TABLE_CMD),
+	IWL_CMD_ENTRY(PM_SLEEP_NOTIFICATION),
+	IWL_CMD_ENTRY(PM_DEBUG_STATISTIC_NOTIFIC),
+	IWL_CMD_ENTRY(REPLY_SCAN_CMD),
+	IWL_CMD_ENTRY(REPLY_SCAN_ABORT_CMD),
+	IWL_CMD_ENTRY(SCAN_START_NOTIFICATION),
+	IWL_CMD_ENTRY(SCAN_RESULTS_NOTIFICATION),
+	IWL_CMD_ENTRY(SCAN_COMPLETE_NOTIFICATION),
+	IWL_CMD_ENTRY(BEACON_NOTIFICATION),
+	IWL_CMD_ENTRY(REPLY_TX_BEACON),
+	IWL_CMD_ENTRY(WHO_IS_AWAKE_NOTIFICATION),
+	IWL_CMD_ENTRY(QUIET_NOTIFICATION),
+	IWL_CMD_ENTRY(REPLY_TX_PWR_TABLE_CMD),
+	IWL_CMD_ENTRY(MEASURE_ABORT_NOTIFICATION),
+	IWL_CMD_ENTRY(REPLY_BT_CONFIG),
+	IWL_CMD_ENTRY(REPLY_STATISTICS_CMD),
+	IWL_CMD_ENTRY(STATISTICS_NOTIFICATION),
+	IWL_CMD_ENTRY(REPLY_CARD_STATE_CMD),
+	IWL_CMD_ENTRY(CARD_STATE_NOTIFICATION),
+	IWL_CMD_ENTRY(MISSED_BEACONS_NOTIFICATION),
+	IWL_CMD_ENTRY(REPLY_CT_KILL_CONFIG_CMD),
+	IWL_CMD_ENTRY(SENSITIVITY_CMD),
+	IWL_CMD_ENTRY(REPLY_PHY_CALIBRATION_CMD),
+	IWL_CMD_ENTRY(REPLY_RX_PHY_CMD),
+	IWL_CMD_ENTRY(REPLY_RX_MPDU_CMD),
+	IWL_CMD_ENTRY(REPLY_RX),
+	IWL_CMD_ENTRY(REPLY_COMPRESSED_BA),
+	IWL_CMD_ENTRY(CALIBRATION_CFG_CMD),
+	IWL_CMD_ENTRY(CALIBRATION_RES_NOTIFICATION),
+	IWL_CMD_ENTRY(CALIBRATION_COMPLETE_NOTIFICATION),
+	IWL_CMD_ENTRY(REPLY_TX_POWER_DBM_CMD),
+	IWL_CMD_ENTRY(TEMPERATURE_NOTIFICATION),
+	IWL_CMD_ENTRY(TX_ANT_CONFIGURATION_CMD),
+	IWL_CMD_ENTRY(REPLY_BT_COEX_PROFILE_NOTIF),
+	IWL_CMD_ENTRY(REPLY_BT_COEX_PRIO_TABLE),
+	IWL_CMD_ENTRY(REPLY_BT_COEX_PROT_ENV),
+	IWL_CMD_ENTRY(REPLY_WIPAN_PARAMS),
+	IWL_CMD_ENTRY(REPLY_WIPAN_RXON),
+	IWL_CMD_ENTRY(REPLY_WIPAN_RXON_TIMING),
+	IWL_CMD_ENTRY(REPLY_WIPAN_RXON_ASSOC),
+	IWL_CMD_ENTRY(REPLY_WIPAN_QOS_PARAM),
+	IWL_CMD_ENTRY(REPLY_WIPAN_WEPKEY),
+	IWL_CMD_ENTRY(REPLY_WIPAN_P2P_CHANNEL_SWITCH),
+	IWL_CMD_ENTRY(REPLY_WIPAN_NOA_NOTIFICATION),
+	IWL_CMD_ENTRY(REPLY_WIPAN_DEACTIVATION_COMPLETE),
+	IWL_CMD_ENTRY(REPLY_WOWLAN_PATTERNS),
+	IWL_CMD_ENTRY(REPLY_WOWLAN_WAKEUP_FILTER),
+	IWL_CMD_ENTRY(REPLY_WOWLAN_TSC_RSC_PARAMS),
+	IWL_CMD_ENTRY(REPLY_WOWLAN_TKIP_PARAMS),
+	IWL_CMD_ENTRY(REPLY_WOWLAN_KEK_KCK_MATERIAL),
+	IWL_CMD_ENTRY(REPLY_WOWLAN_GET_STATUS),
+	IWL_CMD_ENTRY(REPLY_D3_CONFIG),
+};
+#undef IWL_CMD_ENTRY
+
+/******************************************************************************
+ *
+ * Generic RX handler implementations
+ *
+ ******************************************************************************/
+
+static int iwlagn_rx_reply_error(struct iwl_priv *priv,
+			       struct iwl_rx_cmd_buffer *rxb,
+			       struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_error_resp *err_resp = (void *)pkt->data;
+
+	IWL_ERR(priv, "Error Reply type 0x%08X cmd REPLY_ERROR (0x%02X) "
+		"seq 0x%04X ser 0x%08X\n",
+		le32_to_cpu(err_resp->error_type),
+		err_resp->cmd_id,
+		le16_to_cpu(err_resp->bad_cmd_seq_num),
+		le32_to_cpu(err_resp->error_info));
+	return 0;
+}
+
+static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+			       struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_csa_notification *csa = (void *)pkt->data;
+	/*
+	 * MULTI-FIXME
+	 * See iwlagn_mac_channel_switch.
+	 */
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+	struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
+
+	if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+		return 0;
+
+	if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
+		rxon->channel = csa->channel;
+		ctx->staging.channel = csa->channel;
+		IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
+			      le16_to_cpu(csa->channel));
+		iwl_chswitch_done(priv, true);
+	} else {
+		IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
+			le16_to_cpu(csa->channel));
+		iwl_chswitch_done(priv, false);
+	}
+	return 0;
+}
+
+
+static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv,
+					  struct iwl_rx_cmd_buffer *rxb,
+					  struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_spectrum_notification *report = (void *)pkt->data;
+
+	if (!report->state) {
+		IWL_DEBUG_11H(priv,
+			"Spectrum Measure Notification: Start\n");
+		return 0;
+	}
+
+	memcpy(&priv->measure_report, report, sizeof(*report));
+	priv->measurement_status |= MEASUREMENT_READY;
+	return 0;
+}
+
+static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv,
+				  struct iwl_rx_cmd_buffer *rxb,
+				  struct iwl_device_cmd *cmd)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_sleep_notification *sleep = (void *)pkt->data;
+	IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
+		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+	return 0;
+}
+
+static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+					     struct iwl_rx_cmd_buffer *rxb,
+					     struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	u32 __maybe_unused len =
+		le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+	IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
+			"notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len);
+	iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len);
+	return 0;
+}
+
+static int iwlagn_rx_beacon_notif(struct iwl_priv *priv,
+				struct iwl_rx_cmd_buffer *rxb,
+				struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwlagn_beacon_notif *beacon = (void *)pkt->data;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	u16 status = le16_to_cpu(beacon->beacon_notify_hdr.status.status);
+	u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
+
+	IWL_DEBUG_RX(priv, "beacon status %#x, retries:%d ibssmgr:%d "
+		"tsf:0x%.8x%.8x rate:%d\n",
+		status & TX_STATUS_MSK,
+		beacon->beacon_notify_hdr.failure_frame,
+		le32_to_cpu(beacon->ibss_mgr_status),
+		le32_to_cpu(beacon->high_tsf),
+		le32_to_cpu(beacon->low_tsf), rate);
+#endif
+
+	priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
+
+	return 0;
+}
+
+/**
+ * iwl_good_plcp_health - checks for plcp error.
+ *
+ * When the plcp error is exceeding the thresholds, reset the radio
+ * to improve the throughput.
+ */
+static bool iwlagn_good_plcp_health(struct iwl_priv *priv,
+				 struct statistics_rx_phy *cur_ofdm,
+				 struct statistics_rx_ht_phy *cur_ofdm_ht,
+				 unsigned int msecs)
+{
+	int delta;
+	int threshold = priv->plcp_delta_threshold;
+
+	if (threshold == IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
+		IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
+		return true;
+	}
+
+	delta = le32_to_cpu(cur_ofdm->plcp_err) -
+		le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) +
+		le32_to_cpu(cur_ofdm_ht->plcp_err) -
+		le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err);
+
+	/* Can be negative if firmware reset statistics */
+	if (delta <= 0)
+		return true;
+
+	if ((delta * 100 / msecs) > threshold) {
+		IWL_DEBUG_RADIO(priv,
+				"plcp health threshold %u delta %d msecs %u\n",
+				threshold, delta, msecs);
+		return false;
+	}
+
+	return true;
+}
+
+int iwl_force_rf_reset(struct iwl_priv *priv, bool external)
+{
+	struct iwl_rf_reset *rf_reset;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return -EAGAIN;
+
+	if (!iwl_is_any_associated(priv)) {
+		IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
+		return -ENOLINK;
+	}
+
+	rf_reset = &priv->rf_reset;
+	rf_reset->reset_request_count++;
+	if (!external && rf_reset->last_reset_jiffies &&
+	    time_after(rf_reset->last_reset_jiffies +
+		       IWL_DELAY_NEXT_FORCE_RF_RESET, jiffies)) {
+		IWL_DEBUG_INFO(priv, "RF reset rejected\n");
+		rf_reset->reset_reject_count++;
+		return -EAGAIN;
+	}
+	rf_reset->reset_success_count++;
+	rf_reset->last_reset_jiffies = jiffies;
+
+	/*
+	 * There is no easy and better way to force reset the radio,
+	 * the only known method is switching channel which will force to
+	 * reset and tune the radio.
+	 * Use internal short scan (single channel) operation to should
+	 * achieve this objective.
+	 * Driver should reset the radio when number of consecutive missed
+	 * beacon, or any other uCode error condition detected.
+	 */
+	IWL_DEBUG_INFO(priv, "perform radio reset.\n");
+	iwl_internal_short_hw_scan(priv);
+	return 0;
+}
+
+
+static void iwlagn_recover_from_statistics(struct iwl_priv *priv,
+				struct statistics_rx_phy *cur_ofdm,
+				struct statistics_rx_ht_phy *cur_ofdm_ht,
+				struct statistics_tx *tx,
+				unsigned long stamp)
+{
+	unsigned int msecs;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies);
+
+	/* Only gather statistics and update time stamp when not associated */
+	if (!iwl_is_any_associated(priv))
+		return;
+
+	/* Do not check/recover when do not have enough statistics data */
+	if (msecs < 99)
+		return;
+
+	if (iwlwifi_mod_params.plcp_check &&
+	    !iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
+		iwl_force_rf_reset(priv, false);
+}
+
+/* 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 iwlagn_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;
+
+	rx_info = &priv->statistics.rx_non_phy;
+
+	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 accum_stats(__le32 *prev, __le32 *cur, __le32 *delta,
+			__le32 *max_delta, __le32 *accum, int size)
+{
+	int i;
+
+	for (i = 0;
+	     i < size / sizeof(__le32);
+	     i++, prev++, cur++, delta++, max_delta++, accum++) {
+		if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) {
+			*delta = cpu_to_le32(
+				le32_to_cpu(*cur) - le32_to_cpu(*prev));
+			le32_add_cpu(accum, le32_to_cpu(*delta));
+			if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta))
+				*max_delta = *delta;
+		}
+	}
+}
+
+static void
+iwlagn_accumulative_statistics(struct iwl_priv *priv,
+			    struct statistics_general_common *common,
+			    struct statistics_rx_non_phy *rx_non_phy,
+			    struct statistics_rx_phy *rx_ofdm,
+			    struct statistics_rx_ht_phy *rx_ofdm_ht,
+			    struct statistics_rx_phy *rx_cck,
+			    struct statistics_tx *tx,
+			    struct statistics_bt_activity *bt_activity)
+{
+#define ACCUM(_name)	\
+	accum_stats((__le32 *)&priv->statistics._name,		\
+		    (__le32 *)_name,				\
+		    (__le32 *)&priv->delta_stats._name,		\
+		    (__le32 *)&priv->max_delta_stats._name,	\
+		    (__le32 *)&priv->accum_stats._name,		\
+		    sizeof(*_name));
+
+	ACCUM(common);
+	ACCUM(rx_non_phy);
+	ACCUM(rx_ofdm);
+	ACCUM(rx_ofdm_ht);
+	ACCUM(rx_cck);
+	ACCUM(tx);
+	if (bt_activity)
+		ACCUM(bt_activity);
+#undef ACCUM
+}
+#else
+static inline void
+iwlagn_accumulative_statistics(struct iwl_priv *priv,
+			    struct statistics_general_common *common,
+			    struct statistics_rx_non_phy *rx_non_phy,
+			    struct statistics_rx_phy *rx_ofdm,
+			    struct statistics_rx_ht_phy *rx_ofdm_ht,
+			    struct statistics_rx_phy *rx_cck,
+			    struct statistics_tx *tx,
+			    struct statistics_bt_activity *bt_activity)
+{
+}
+#endif
+
+static int iwlagn_rx_statistics(struct iwl_priv *priv,
+			      struct iwl_rx_cmd_buffer *rxb,
+			      struct iwl_device_cmd *cmd)
+{
+	unsigned long stamp = jiffies;
+	const int reg_recalib_period = 60;
+	int change;
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+	__le32 *flag;
+	struct statistics_general_common *common;
+	struct statistics_rx_non_phy *rx_non_phy;
+	struct statistics_rx_phy *rx_ofdm;
+	struct statistics_rx_ht_phy *rx_ofdm_ht;
+	struct statistics_rx_phy *rx_cck;
+	struct statistics_tx *tx;
+	struct statistics_bt_activity *bt_activity;
+
+	len -= sizeof(struct iwl_cmd_header); /* skip header */
+
+	IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n",
+		     len);
+
+	spin_lock(&priv->statistics.lock);
+
+	if (len == sizeof(struct iwl_bt_notif_statistics)) {
+		struct iwl_bt_notif_statistics *stats;
+		stats = (void *)&pkt->data;
+		flag = &stats->flag;
+		common = &stats->general.common;
+		rx_non_phy = &stats->rx.general.common;
+		rx_ofdm = &stats->rx.ofdm;
+		rx_ofdm_ht = &stats->rx.ofdm_ht;
+		rx_cck = &stats->rx.cck;
+		tx = &stats->tx;
+		bt_activity = &stats->general.activity;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+		/* handle this exception directly */
+		priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills;
+		le32_add_cpu(&priv->statistics.accum_num_bt_kills,
+			     le32_to_cpu(stats->rx.general.num_bt_kills));
+#endif
+	} else if (len == sizeof(struct iwl_notif_statistics)) {
+		struct iwl_notif_statistics *stats;
+		stats = (void *)&pkt->data;
+		flag = &stats->flag;
+		common = &stats->general.common;
+		rx_non_phy = &stats->rx.general;
+		rx_ofdm = &stats->rx.ofdm;
+		rx_ofdm_ht = &stats->rx.ofdm_ht;
+		rx_cck = &stats->rx.cck;
+		tx = &stats->tx;
+		bt_activity = NULL;
+	} else {
+		WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n",
+			  len, sizeof(struct iwl_bt_notif_statistics),
+			  sizeof(struct iwl_notif_statistics));
+		spin_unlock(&priv->statistics.lock);
+		return 0;
+	}
+
+	change = common->temperature != priv->statistics.common.temperature ||
+		 (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
+		 (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK);
+
+	iwlagn_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm,
+				    rx_ofdm_ht, rx_cck, tx, bt_activity);
+
+	iwlagn_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp);
+
+	priv->statistics.flag = *flag;
+	memcpy(&priv->statistics.common, common, sizeof(*common));
+	memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy));
+	memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm));
+	memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht));
+	memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck));
+	memcpy(&priv->statistics.tx, tx, sizeof(*tx));
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	if (bt_activity)
+		memcpy(&priv->statistics.bt_activity, bt_activity,
+			sizeof(*bt_activity));
+#endif
+
+	priv->rx_statistics_jiffies = stamp;
+
+	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)) {
+		iwlagn_rx_calc_noise(priv);
+		queue_work(priv->workqueue, &priv->run_time_calib_work);
+	}
+	if (priv->lib->temperature && change)
+		priv->lib->temperature(priv);
+
+	spin_unlock(&priv->statistics.lock);
+
+	return 0;
+}
+
+static int iwlagn_rx_reply_statistics(struct iwl_priv *priv,
+				    struct iwl_rx_cmd_buffer *rxb,
+				    struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_notif_statistics *stats = (void *)pkt->data;
+
+	if (le32_to_cpu(stats->flag) & UCODE_STATISTICS_CLEAR_MSK) {
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+		memset(&priv->accum_stats, 0,
+			sizeof(priv->accum_stats));
+		memset(&priv->delta_stats, 0,
+			sizeof(priv->delta_stats));
+		memset(&priv->max_delta_stats, 0,
+			sizeof(priv->max_delta_stats));
+#endif
+		IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
+	}
+	iwlagn_rx_statistics(priv, rxb, cmd);
+	return 0;
+}
+
+/* Handle notification from uCode that card's power state is changing
+ * due to software, hardware, or critical temperature RFKILL */
+static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,
+				    struct iwl_rx_cmd_buffer *rxb,
+				    struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_card_state_notif *card_state_notif = (void *)pkt->data;
+	u32 flags = le32_to_cpu(card_state_notif->flags);
+	unsigned long status = priv->status;
+
+	IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n",
+			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+			  (flags & SW_CARD_DISABLED) ? "Kill" : "On",
+			  (flags & CT_CARD_DISABLED) ?
+			  "Reached" : "Not reached");
+
+	if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
+		     CT_CARD_DISABLED)) {
+
+		iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
+			    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+		iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C,
+					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+
+		if (!(flags & RXON_CARD_DISABLED)) {
+			iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
+				    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+			iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C,
+					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+		}
+		if (flags & CT_CARD_DISABLED)
+			iwl_tt_enter_ct_kill(priv);
+	}
+	if (!(flags & CT_CARD_DISABLED))
+		iwl_tt_exit_ct_kill(priv);
+
+	if (flags & HW_CARD_DISABLED)
+		set_bit(STATUS_RF_KILL_HW, &priv->status);
+	else
+		clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+
+	if (!(flags & RXON_CARD_DISABLED))
+		iwl_scan_cancel(priv);
+
+	if ((test_bit(STATUS_RF_KILL_HW, &status) !=
+	     test_bit(STATUS_RF_KILL_HW, &priv->status)))
+		wiphy_rfkill_set_hw_state(priv->hw->wiphy,
+			test_bit(STATUS_RF_KILL_HW, &priv->status));
+	else
+		wake_up(&priv->trans->wait_command_queue);
+	return 0;
+}
+
+static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv,
+				       struct iwl_rx_cmd_buffer *rxb,
+				       struct iwl_device_cmd *cmd)
+
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_missed_beacon_notif *missed_beacon = (void *)pkt->data;
+
+	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);
+	}
+	return 0;
+}
+
+/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
+ * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
+static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
+				struct iwl_rx_cmd_buffer *rxb,
+				struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+	priv->last_phy_res_valid = true;
+	memcpy(&priv->last_phy_res, pkt->data,
+	       sizeof(struct iwl_rx_phy_res));
+	return 0;
+}
+
+/*
+ * returns non-zero if packet should be dropped
+ */
+static int iwlagn_set_decrypted_flag(struct iwl_priv *priv,
+				  struct ieee80211_hdr *hdr,
+				  u32 decrypt_res,
+				  struct ieee80211_rx_status *stats)
+{
+	u16 fc = le16_to_cpu(hdr->frame_control);
+
+	/*
+	 * All contexts have the same setting here due to it being
+	 * a module parameter, so OK to check any context.
+	 */
+	if (priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags &
+						RXON_FILTER_DIS_DECRYPT_MSK)
+		return 0;
+
+	if (!(fc & IEEE80211_FCTL_PROTECTED))
+		return 0;
+
+	IWL_DEBUG_RX(priv, "decrypt_res:0x%x\n", decrypt_res);
+	switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+	case RX_RES_STATUS_SEC_TYPE_TKIP:
+		/* The uCode has got a bad phase 1 Key, pushes the packet.
+		 * Decryption will be done in SW. */
+		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+		    RX_RES_STATUS_BAD_KEY_TTAK)
+			break;
+
+	case RX_RES_STATUS_SEC_TYPE_WEP:
+		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+		    RX_RES_STATUS_BAD_ICV_MIC) {
+			/* bad ICV, the packet is destroyed since the
+			 * decryption is inplace, drop it */
+			IWL_DEBUG_RX(priv, "Packet destroyed\n");
+			return -1;
+		}
+	case RX_RES_STATUS_SEC_TYPE_CCMP:
+		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+		    RX_RES_STATUS_DECRYPT_OK) {
+			IWL_DEBUG_RX(priv, "hw decrypt successfully!!!\n");
+			stats->flag |= RX_FLAG_DECRYPTED;
+		}
+		break;
+
+	default:
+		break;
+	}
+	return 0;
+}
+
+static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
+					struct ieee80211_hdr *hdr,
+					u16 len,
+					u32 ampdu_status,
+					struct iwl_rx_cmd_buffer *rxb,
+					struct ieee80211_rx_status *stats)
+{
+	struct sk_buff *skb;
+	__le16 fc = hdr->frame_control;
+	struct iwl_rxon_context *ctx;
+	unsigned int hdrlen, fraglen;
+
+	/* We only process data packets if the interface is open */
+	if (unlikely(!priv->is_open)) {
+		IWL_DEBUG_DROP_LIMIT(priv,
+		    "Dropping packet while interface is not open.\n");
+		return;
+	}
+
+	/* In case of HW accelerated crypto and bad decryption, drop */
+	if (!iwlwifi_mod_params.sw_crypto &&
+	    iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats))
+		return;
+
+	/* Dont use dev_alloc_skb(), we'll have enough headroom once
+	 * ieee80211_hdr pulled.
+	 */
+	skb = alloc_skb(128, GFP_ATOMIC);
+	if (!skb) {
+		IWL_ERR(priv, "alloc_skb failed\n");
+		return;
+	}
+	/* If frame is small enough to fit in skb->head, pull it completely.
+	 * If not, only pull ieee80211_hdr so that splice() or TCP coalesce
+	 * are more efficient.
+	 */
+	hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr);
+
+	memcpy(skb_put(skb, hdrlen), hdr, hdrlen);
+	fraglen = len - hdrlen;
+
+	if (fraglen) {
+		int offset = (void *)hdr + hdrlen -
+			     rxb_addr(rxb) + rxb_offset(rxb);
+
+		skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
+				fraglen, rxb->truesize);
+	}
+
+	/*
+	* Wake any queues that were stopped due to a passive channel tx
+	* failure. This can happen because the regulatory enforcement in
+	* the device waits for a beacon before allowing transmission,
+	* sometimes even after already having transmitted frames for the
+	* association because the new RXON may reset the information.
+	*/
+	if (unlikely(ieee80211_is_beacon(fc) && priv->passive_no_rx)) {
+		for_each_context(priv, ctx) {
+			if (!ether_addr_equal(hdr->addr3,
+					      ctx->active.bssid_addr))
+				continue;
+			iwlagn_lift_passive_no_rx(priv);
+		}
+	}
+
+	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
+
+	ieee80211_rx(priv->hw, skb);
+}
+
+static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
+{
+	u32 decrypt_out = 0;
+
+	if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
+					RX_RES_STATUS_STATION_FOUND)
+		decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
+				RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
+
+	decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
+
+	/* packet was not encrypted */
+	if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
+					RX_RES_STATUS_SEC_TYPE_NONE)
+		return decrypt_out;
+
+	/* packet was encrypted with unknown alg */
+	if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
+					RX_RES_STATUS_SEC_TYPE_ERR)
+		return decrypt_out;
+
+	/* decryption was not done in HW */
+	if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
+					RX_MPDU_RES_STATUS_DEC_DONE_MSK)
+		return decrypt_out;
+
+	switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
+
+	case RX_RES_STATUS_SEC_TYPE_CCMP:
+		/* alg is CCM: check MIC only */
+		if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
+			/* Bad MIC */
+			decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
+		else
+			decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
+
+		break;
+
+	case RX_RES_STATUS_SEC_TYPE_TKIP:
+		if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
+			/* Bad TTAK */
+			decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
+			break;
+		}
+		/* fall through if TTAK OK */
+	default:
+		if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
+			decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
+		else
+			decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
+		break;
+	}
+
+	IWL_DEBUG_RX(priv, "decrypt_in:0x%x  decrypt_out = 0x%x\n",
+					decrypt_in, decrypt_out);
+
+	return decrypt_out;
+}
+
+/* Calc max signal level (dBm) among 3 possible receivers */
+static int iwlagn_calc_rssi(struct iwl_priv *priv,
+			     struct iwl_rx_phy_res *rx_resp)
+{
+	/* data from PHY/DSP regarding signal strength, etc.,
+	 *   contents are always there, not configurable by host
+	 */
+	struct iwlagn_non_cfg_phy *ncphy =
+		(struct iwlagn_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
+	u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
+	u8 agc;
+
+	val  = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_AGC_IDX]);
+	agc = (val & IWLAGN_OFDM_AGC_MSK) >> IWLAGN_OFDM_AGC_BIT_POS;
+
+	/* Find max rssi among 3 possible receivers.
+	 * These values are measured by the digital signal processor (DSP).
+	 * They should stay fairly constant even as the signal strength varies,
+	 *   if the radio's automatic gain control (AGC) is working right.
+	 * AGC value (see below) will provide the "interesting" info.
+	 */
+	val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_AB_IDX]);
+	rssi_a = (val & IWLAGN_OFDM_RSSI_INBAND_A_BITMSK) >>
+		IWLAGN_OFDM_RSSI_A_BIT_POS;
+	rssi_b = (val & IWLAGN_OFDM_RSSI_INBAND_B_BITMSK) >>
+		IWLAGN_OFDM_RSSI_B_BIT_POS;
+	val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_C_IDX]);
+	rssi_c = (val & IWLAGN_OFDM_RSSI_INBAND_C_BITMSK) >>
+		IWLAGN_OFDM_RSSI_C_BIT_POS;
+
+	max_rssi = max_t(u32, rssi_a, rssi_b);
+	max_rssi = max_t(u32, max_rssi, rssi_c);
+
+	IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+		rssi_a, rssi_b, rssi_c, max_rssi, agc);
+
+	/* dBm = max_rssi dB - agc dB - constant.
+	 * Higher AGC (higher radio gain) means lower signal. */
+	return max_rssi - agc - IWLAGN_RSSI_OFFSET;
+}
+
+/* Called for REPLY_RX (legacy ABG frames), or
+ * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
+static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
+			    struct iwl_rx_cmd_buffer *rxb,
+			    struct iwl_device_cmd *cmd)
+{
+	struct ieee80211_hdr *header;
+	struct ieee80211_rx_status rx_status;
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_rx_phy_res *phy_res;
+	__le32 rx_pkt_status;
+	struct iwl_rx_mpdu_res_start *amsdu;
+	u32 len;
+	u32 ampdu_status;
+	u32 rate_n_flags;
+
+	/**
+	 * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
+	 *	REPLY_RX: physical layer info is in this buffer
+	 *	REPLY_RX_MPDU_CMD: physical layer info was sent in separate
+	 *		command and cached in priv->last_phy_res
+	 *
+	 * Here we set up local variables depending on which command is
+	 * received.
+	 */
+	if (pkt->hdr.cmd == REPLY_RX) {
+		phy_res = (struct iwl_rx_phy_res *)pkt->data;
+		header = (struct ieee80211_hdr *)(pkt->data + sizeof(*phy_res)
+				+ phy_res->cfg_phy_cnt);
+
+		len = le16_to_cpu(phy_res->byte_count);
+		rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*phy_res) +
+				phy_res->cfg_phy_cnt + len);
+		ampdu_status = le32_to_cpu(rx_pkt_status);
+	} else {
+		if (!priv->last_phy_res_valid) {
+			IWL_ERR(priv, "MPDU frame without cached PHY data\n");
+			return 0;
+		}
+		phy_res = &priv->last_phy_res;
+		amsdu = (struct iwl_rx_mpdu_res_start *)pkt->data;
+		header = (struct ieee80211_hdr *)(pkt->data + sizeof(*amsdu));
+		len = le16_to_cpu(amsdu->byte_count);
+		rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*amsdu) + len);
+		ampdu_status = iwlagn_translate_rx_status(priv,
+						le32_to_cpu(rx_pkt_status));
+	}
+
+	if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
+		IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d\n",
+				phy_res->cfg_phy_cnt);
+		return 0;
+	}
+
+	if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
+	    !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+		IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
+				le32_to_cpu(rx_pkt_status));
+		return 0;
+	}
+
+	/* This will be used in several places later */
+	rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
+
+	/* rx_status carries information about the packet to mac80211 */
+	rx_status.mactime = le64_to_cpu(phy_res->timestamp);
+	rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+	rx_status.freq =
+		ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel),
+					       rx_status.band);
+	rx_status.rate_idx =
+		iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
+	rx_status.flag = 0;
+
+	/* TSF isn't reliable. In order to allow smooth user experience,
+	 * this W/A doesn't propagate it to the mac80211 */
+	/*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/
+
+	priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
+
+	/* Find max signal strength (dBm) among 3 antenna/receiver chains */
+	rx_status.signal = iwlagn_calc_rssi(priv, phy_res);
+
+	IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n",
+		rx_status.signal, (unsigned long long)rx_status.mactime);
+
+	/*
+	 * "antenna number"
+	 *
+	 * It seems that the antenna field in the phy flags value
+	 * is actually a bit field. This is undefined by radiotap,
+	 * it wants an actual antenna number but I always get "7"
+	 * for most legacy frames I receive indicating that the
+	 * same frame was received on all three RX chains.
+	 *
+	 * I think this field should be removed in favor of a
+	 * new 802.11n radiotap field "RX chains" that is defined
+	 * as a bitmask.
+	 */
+	rx_status.antenna =
+		(le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK)
+		>> RX_RES_PHY_FLAGS_ANTENNA_POS;
+
+	/* set the preamble flag if appropriate */
+	if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+		rx_status.flag |= RX_FLAG_SHORTPRE;
+
+	/* Set up the HT phy flags */
+	if (rate_n_flags & RATE_MCS_HT_MSK)
+		rx_status.flag |= RX_FLAG_HT;
+	if (rate_n_flags & RATE_MCS_HT40_MSK)
+		rx_status.flag |= RX_FLAG_40MHZ;
+	if (rate_n_flags & RATE_MCS_SGI_MSK)
+		rx_status.flag |= RX_FLAG_SHORT_GI;
+	if (rate_n_flags & RATE_MCS_GF_MSK)
+		rx_status.flag |= RX_FLAG_HT_GF;
+
+	iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status,
+				    rxb, &rx_status);
+	return 0;
+}
+
+static int iwlagn_rx_noa_notification(struct iwl_priv *priv,
+				      struct iwl_rx_cmd_buffer *rxb,
+				      struct iwl_device_cmd *cmd)
+{
+	struct iwl_wipan_noa_data *new_data, *old_data;
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->data;
+
+	/* no condition -- we're in softirq */
+	old_data = rcu_dereference_protected(priv->noa_data, true);
+
+	if (noa_notif->noa_active) {
+		u32 len = le16_to_cpu(noa_notif->noa_attribute.length);
+		u32 copylen = len;
+
+		/* EID, len, OUI, subtype */
+		len += 1 + 1 + 3 + 1;
+		/* P2P id, P2P length */
+		len += 1 + 2;
+		copylen += 1 + 2;
+
+		new_data = kmalloc(sizeof(*new_data) + len, GFP_ATOMIC);
+		if (new_data) {
+			new_data->length = len;
+			new_data->data[0] = WLAN_EID_VENDOR_SPECIFIC;
+			new_data->data[1] = len - 2; /* not counting EID, len */
+			new_data->data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
+			new_data->data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
+			new_data->data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
+			new_data->data[5] = WLAN_OUI_TYPE_WFA_P2P;
+			memcpy(&new_data->data[6], &noa_notif->noa_attribute,
+			       copylen);
+		}
+	} else
+		new_data = NULL;
+
+	rcu_assign_pointer(priv->noa_data, new_data);
+
+	if (old_data)
+		kfree_rcu(old_data, rcu_head);
+
+	return 0;
+}
+
+/**
+ * iwl_setup_rx_handlers - Initialize Rx handler callbacks
+ *
+ * Setup the RX handlers for each of the reply types sent from the uCode
+ * to the host.
+ */
+void iwl_setup_rx_handlers(struct iwl_priv *priv)
+{
+	int (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+			       struct iwl_device_cmd *cmd);
+
+	handlers = priv->rx_handlers;
+
+	handlers[REPLY_ERROR]			= iwlagn_rx_reply_error;
+	handlers[CHANNEL_SWITCH_NOTIFICATION]	= iwlagn_rx_csa;
+	handlers[SPECTRUM_MEASURE_NOTIFICATION]	=
+		iwlagn_rx_spectrum_measure_notif;
+	handlers[PM_SLEEP_NOTIFICATION]		= iwlagn_rx_pm_sleep_notif;
+	handlers[PM_DEBUG_STATISTIC_NOTIFIC]	=
+		iwlagn_rx_pm_debug_statistics_notif;
+	handlers[BEACON_NOTIFICATION]		= iwlagn_rx_beacon_notif;
+	handlers[REPLY_ADD_STA]			= iwl_add_sta_callback;
+
+	handlers[REPLY_WIPAN_NOA_NOTIFICATION]	= iwlagn_rx_noa_notification;
+
+	/*
+	 * The same handler is used for both the REPLY to a discrete
+	 * statistics request from the host as well as for the periodic
+	 * statistics notifications (after received beacons) from the uCode.
+	 */
+	handlers[REPLY_STATISTICS_CMD]		= iwlagn_rx_reply_statistics;
+	handlers[STATISTICS_NOTIFICATION]	= iwlagn_rx_statistics;
+
+	iwl_setup_rx_scan_handlers(priv);
+
+	handlers[CARD_STATE_NOTIFICATION]	= iwlagn_rx_card_state_notif;
+	handlers[MISSED_BEACONS_NOTIFICATION]	=
+		iwlagn_rx_missed_beacon_notif;
+
+	/* Rx handlers */
+	handlers[REPLY_RX_PHY_CMD]		= iwlagn_rx_reply_rx_phy;
+	handlers[REPLY_RX_MPDU_CMD]		= iwlagn_rx_reply_rx;
+
+	/* block ack */
+	handlers[REPLY_COMPRESSED_BA]		=
+		iwlagn_rx_reply_compressed_ba;
+
+	priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
+
+	/* set up notification wait support */
+	iwl_notification_wait_init(&priv->notif_wait);
+
+	/* Set up BT Rx handlers */
+	if (priv->cfg->bt_params)
+		iwlagn_bt_rx_handler_setup(priv);
+}
+
+int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
+		    struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+	int err = 0;
+
+	/*
+	 * Do the notification wait before RX handlers so
+	 * even if the RX handler consumes the RXB we have
+	 * access to it in the notification wait entry.
+	 */
+	iwl_notification_wait_notify(&priv->notif_wait, pkt);
+
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+	/*
+	 * RX data may be forwarded to userspace in one
+	 * of two cases: the user owns the fw through testmode or when
+	 * the user requested to monitor the rx w/o affecting the regular flow.
+	 * In these cases the iwl_test object will handle forwarding the rx
+	 * data to user space.
+	 * Note that if the ownership flag != IWL_OWNERSHIP_TM the flow
+	 * continues.
+	 */
+	iwl_test_rx(&priv->tst, rxb);
+#endif
+
+	if (priv->ucode_owner != IWL_OWNERSHIP_TM) {
+		/* Based on type of command response or notification,
+		 *   handle those that need handling via function in
+		 *   rx_handlers table.  See iwl_setup_rx_handlers() */
+		if (priv->rx_handlers[pkt->hdr.cmd]) {
+			priv->rx_handlers_stats[pkt->hdr.cmd]++;
+			err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd);
+		} else {
+			/* No handling needed */
+			IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n",
+				     iwl_dvm_get_cmd_string(pkt->hdr.cmd),
+				     pkt->hdr.cmd);
+		}
+	}
+	return err;
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c
new file mode 100644
index 0000000..6ee940f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c
@@ -0,0 +1,1577 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 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.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/etherdevice.h>
+#include "iwl-trans.h"
+#include "iwl-modparams.h"
+#include "dev.h"
+#include "agn.h"
+#include "calib.h"
+
+/*
+ * initialize rxon structure with default values from eeprom
+ */
+void iwl_connection_init_rx_config(struct iwl_priv *priv,
+				   struct iwl_rxon_context *ctx)
+{
+	memset(&ctx->staging, 0, sizeof(ctx->staging));
+
+	if (!ctx->vif) {
+		ctx->staging.dev_type = ctx->unused_devtype;
+	} else
+	switch (ctx->vif->type) {
+	case NL80211_IFTYPE_AP:
+		ctx->staging.dev_type = ctx->ap_devtype;
+		break;
+
+	case NL80211_IFTYPE_STATION:
+		ctx->staging.dev_type = ctx->station_devtype;
+		ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+
+	case NL80211_IFTYPE_ADHOC:
+		ctx->staging.dev_type = ctx->ibss_devtype;
+		ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+		ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+						  RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+
+	case NL80211_IFTYPE_MONITOR:
+		ctx->staging.dev_type = RXON_DEV_TYPE_SNIFFER;
+		break;
+
+	default:
+		IWL_ERR(priv, "Unsupported interface type %d\n",
+			ctx->vif->type);
+		break;
+	}
+
+#if 0
+	/* TODO:  Figure out when short_preamble would be set and cache from
+	 * that */
+	if (!hw_to_local(priv->hw)->short_preamble)
+		ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+	else
+		ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+#endif
+
+	ctx->staging.channel = cpu_to_le16(priv->hw->conf.channel->hw_value);
+	priv->band = priv->hw->conf.channel->band;
+
+	iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
+
+	/* clear both MIX and PURE40 mode flag */
+	ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
+					RXON_FLG_CHANNEL_MODE_PURE_40);
+	if (ctx->vif)
+		memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);
+
+	ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff;
+	ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff;
+	ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff;
+}
+
+static int iwlagn_disable_bss(struct iwl_priv *priv,
+			      struct iwl_rxon_context *ctx,
+			      struct iwl_rxon_cmd *send)
+{
+	__le32 old_filter = send->filter_flags;
+	int ret;
+
+	send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
+				CMD_SYNC, sizeof(*send), send);
+
+	send->filter_flags = old_filter;
+
+	if (ret)
+		IWL_DEBUG_QUIET_RFKILL(priv,
+			"Error clearing ASSOC_MSK on BSS (%d)\n", ret);
+
+	return ret;
+}
+
+static int iwlagn_disable_pan(struct iwl_priv *priv,
+			      struct iwl_rxon_context *ctx,
+			      struct iwl_rxon_cmd *send)
+{
+	struct iwl_notification_wait disable_wait;
+	__le32 old_filter = send->filter_flags;
+	u8 old_dev_type = send->dev_type;
+	int ret;
+	static const u8 deactivate_cmd[] = {
+		REPLY_WIPAN_DEACTIVATION_COMPLETE
+	};
+
+	iwl_init_notification_wait(&priv->notif_wait, &disable_wait,
+				   deactivate_cmd, ARRAY_SIZE(deactivate_cmd),
+				   NULL, NULL);
+
+	send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	send->dev_type = RXON_DEV_TYPE_P2P;
+	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
+				CMD_SYNC, sizeof(*send), send);
+
+	send->filter_flags = old_filter;
+	send->dev_type = old_dev_type;
+
+	if (ret) {
+		IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
+		iwl_remove_notification(&priv->notif_wait, &disable_wait);
+	} else {
+		ret = iwl_wait_notification(&priv->notif_wait,
+					    &disable_wait, HZ);
+		if (ret)
+			IWL_ERR(priv, "Timed out waiting for PAN disable\n");
+	}
+
+	return ret;
+}
+
+static int iwlagn_disconn_pan(struct iwl_priv *priv,
+			      struct iwl_rxon_context *ctx,
+			      struct iwl_rxon_cmd *send)
+{
+	__le32 old_filter = send->filter_flags;
+	int ret;
+
+	send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
+				sizeof(*send), send);
+
+	send->filter_flags = old_filter;
+
+	return ret;
+}
+
+static void iwlagn_update_qos(struct iwl_priv *priv,
+			      struct iwl_rxon_context *ctx)
+{
+	int ret;
+
+	if (!ctx->is_active)
+		return;
+
+	ctx->qos_data.def_qos_parm.qos_flags = 0;
+
+	if (ctx->qos_data.qos_active)
+		ctx->qos_data.def_qos_parm.qos_flags |=
+			QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+	if (ctx->ht.enabled)
+		ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
+
+	IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+		      ctx->qos_data.qos_active,
+		      ctx->qos_data.def_qos_parm.qos_flags);
+
+	ret = iwl_dvm_send_cmd_pdu(priv, ctx->qos_cmd, CMD_SYNC,
+			       sizeof(struct iwl_qosparam_cmd),
+			       &ctx->qos_data.def_qos_parm);
+	if (ret)
+		IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
+}
+
+static int iwlagn_update_beacon(struct iwl_priv *priv,
+				struct ieee80211_vif *vif)
+{
+	lockdep_assert_held(&priv->mutex);
+
+	dev_kfree_skb(priv->beacon_skb);
+	priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif);
+	if (!priv->beacon_skb)
+		return -ENOMEM;
+	return iwlagn_send_beacon_cmd(priv);
+}
+
+static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
+				  struct iwl_rxon_context *ctx)
+{
+	int ret = 0;
+	struct iwl_rxon_assoc_cmd rxon_assoc;
+	const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+	const struct iwl_rxon_cmd *rxon2 = &ctx->active;
+
+	if ((rxon1->flags == rxon2->flags) &&
+	    (rxon1->filter_flags == rxon2->filter_flags) &&
+	    (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+	    (rxon1->ofdm_ht_single_stream_basic_rates ==
+	     rxon2->ofdm_ht_single_stream_basic_rates) &&
+	    (rxon1->ofdm_ht_dual_stream_basic_rates ==
+	     rxon2->ofdm_ht_dual_stream_basic_rates) &&
+	    (rxon1->ofdm_ht_triple_stream_basic_rates ==
+	     rxon2->ofdm_ht_triple_stream_basic_rates) &&
+	    (rxon1->acquisition_data == rxon2->acquisition_data) &&
+	    (rxon1->rx_chain == rxon2->rx_chain) &&
+	    (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+		IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC.  Not resending.\n");
+		return 0;
+	}
+
+	rxon_assoc.flags = ctx->staging.flags;
+	rxon_assoc.filter_flags = ctx->staging.filter_flags;
+	rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+	rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
+	rxon_assoc.reserved1 = 0;
+	rxon_assoc.reserved2 = 0;
+	rxon_assoc.reserved3 = 0;
+	rxon_assoc.ofdm_ht_single_stream_basic_rates =
+	    ctx->staging.ofdm_ht_single_stream_basic_rates;
+	rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+	    ctx->staging.ofdm_ht_dual_stream_basic_rates;
+	rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
+	rxon_assoc.ofdm_ht_triple_stream_basic_rates =
+		 ctx->staging.ofdm_ht_triple_stream_basic_rates;
+	rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
+
+	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_assoc_cmd,
+				CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc);
+	return ret;
+}
+
+static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
+{
+	u16 new_val;
+	u16 beacon_factor;
+
+	/*
+	 * If mac80211 hasn't given us a beacon interval, program
+	 * the default into the device (not checking this here
+	 * would cause the adjustment below to return the maximum
+	 * value, which may break PAN.)
+	 */
+	if (!beacon_val)
+		return DEFAULT_BEACON_INTERVAL;
+
+	/*
+	 * If the beacon interval we obtained from the peer
+	 * is too large, we'll have to wake up more often
+	 * (and in IBSS case, we'll beacon too much)
+	 *
+	 * For example, if max_beacon_val is 4096, and the
+	 * requested beacon interval is 7000, we'll have to
+	 * use 3500 to be able to wake up on the beacons.
+	 *
+	 * This could badly influence beacon detection stats.
+	 */
+
+	beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
+	new_val = beacon_val / beacon_factor;
+
+	if (!new_val)
+		new_val = max_beacon_val;
+
+	return new_val;
+}
+
+static int iwl_send_rxon_timing(struct iwl_priv *priv,
+				struct iwl_rxon_context *ctx)
+{
+	u64 tsf;
+	s32 interval_tm, rem;
+	struct ieee80211_conf *conf = NULL;
+	u16 beacon_int;
+	struct ieee80211_vif *vif = ctx->vif;
+
+	conf = &priv->hw->conf;
+
+	lockdep_assert_held(&priv->mutex);
+
+	memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));
+
+	ctx->timing.timestamp = cpu_to_le64(priv->timestamp);
+	ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval);
+
+	beacon_int = vif ? vif->bss_conf.beacon_int : 0;
+
+	/*
+	 * TODO: For IBSS we need to get atim_window from mac80211,
+	 *	 for now just always use 0
+	 */
+	ctx->timing.atim_window = 0;
+
+	if (ctx->ctxid == IWL_RXON_CTX_PAN &&
+	    (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) &&
+	    iwl_is_associated(priv, IWL_RXON_CTX_BSS) &&
+	    priv->contexts[IWL_RXON_CTX_BSS].vif &&
+	    priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) {
+		ctx->timing.beacon_interval =
+			priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval;
+		beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
+	} else if (ctx->ctxid == IWL_RXON_CTX_BSS &&
+		   iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
+		   priv->contexts[IWL_RXON_CTX_PAN].vif &&
+		   priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int &&
+		   (!iwl_is_associated_ctx(ctx) || !ctx->vif ||
+		    !ctx->vif->bss_conf.beacon_int)) {
+		ctx->timing.beacon_interval =
+			priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval;
+		beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
+	} else {
+		beacon_int = iwl_adjust_beacon_interval(beacon_int,
+			IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT);
+		ctx->timing.beacon_interval = cpu_to_le16(beacon_int);
+	}
+
+	ctx->beacon_int = beacon_int;
+
+	tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
+	interval_tm = beacon_int * TIME_UNIT;
+	rem = do_div(tsf, interval_tm);
+	ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+	ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1;
+
+	IWL_DEBUG_ASSOC(priv,
+			"beacon interval %d beacon timer %d beacon tim %d\n",
+			le16_to_cpu(ctx->timing.beacon_interval),
+			le32_to_cpu(ctx->timing.beacon_init_val),
+			le16_to_cpu(ctx->timing.atim_window));
+
+	return iwl_dvm_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
+				CMD_SYNC, sizeof(ctx->timing), &ctx->timing);
+}
+
+static int iwlagn_rxon_disconn(struct iwl_priv *priv,
+			       struct iwl_rxon_context *ctx)
+{
+	int ret;
+	struct iwl_rxon_cmd *active = (void *)&ctx->active;
+
+	if (ctx->ctxid == IWL_RXON_CTX_BSS) {
+		ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
+	} else {
+		ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
+		if (ret)
+			return ret;
+		if (ctx->vif) {
+			ret = iwl_send_rxon_timing(priv, ctx);
+			if (ret) {
+				IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+				return ret;
+			}
+			ret = iwlagn_disconn_pan(priv, ctx, &ctx->staging);
+		}
+	}
+	if (ret)
+		return ret;
+
+	/*
+	 * Un-assoc RXON clears the station table and WEP
+	 * keys, so we have to restore those afterwards.
+	 */
+	iwl_clear_ucode_stations(priv, ctx);
+	/* update -- might need P2P now */
+	iwl_update_bcast_station(priv, ctx);
+	iwl_restore_stations(priv, ctx);
+	ret = iwl_restore_default_wep_keys(priv, ctx);
+	if (ret) {
+		IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
+		return ret;
+	}
+
+	memcpy(active, &ctx->staging, sizeof(*active));
+	return 0;
+}
+
+static int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
+{
+	int ret;
+	s8 prev_tx_power;
+	bool defer;
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
+	if (priv->calib_disabled & IWL_TX_POWER_CALIB_DISABLED)
+		return 0;
+
+	lockdep_assert_held(&priv->mutex);
+
+	if (priv->tx_power_user_lmt == tx_power && !force)
+		return 0;
+
+	if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
+		IWL_WARN(priv,
+			 "Requested user TXPOWER %d below lower limit %d.\n",
+			 tx_power,
+			 IWLAGN_TX_POWER_TARGET_POWER_MIN);
+		return -EINVAL;
+	}
+
+	if (tx_power > DIV_ROUND_UP(priv->eeprom_data->max_tx_pwr_half_dbm, 2)) {
+		IWL_WARN(priv,
+			"Requested user TXPOWER %d above upper limit %d.\n",
+			 tx_power, priv->eeprom_data->max_tx_pwr_half_dbm);
+		return -EINVAL;
+	}
+
+	if (!iwl_is_ready_rf(priv))
+		return -EIO;
+
+	/* scan complete and commit_rxon use tx_power_next value,
+	 * it always need to be updated for newest request */
+	priv->tx_power_next = tx_power;
+
+	/* do not set tx power when scanning or channel changing */
+	defer = test_bit(STATUS_SCANNING, &priv->status) ||
+		memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
+	if (defer && !force) {
+		IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
+		return 0;
+	}
+
+	prev_tx_power = priv->tx_power_user_lmt;
+	priv->tx_power_user_lmt = tx_power;
+
+	ret = iwlagn_send_tx_power(priv);
+
+	/* if fail to set tx_power, restore the orig. tx power */
+	if (ret) {
+		priv->tx_power_user_lmt = prev_tx_power;
+		priv->tx_power_next = prev_tx_power;
+	}
+	return ret;
+}
+
+static int iwlagn_rxon_connect(struct iwl_priv *priv,
+			       struct iwl_rxon_context *ctx)
+{
+	int ret;
+	struct iwl_rxon_cmd *active = (void *)&ctx->active;
+
+	/* RXON timing must be before associated RXON */
+	if (ctx->ctxid == IWL_RXON_CTX_BSS) {
+		ret = iwl_send_rxon_timing(priv, ctx);
+		if (ret) {
+			IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+			return ret;
+		}
+	}
+	/* QoS info may be cleared by previous un-assoc RXON */
+	iwlagn_update_qos(priv, ctx);
+
+	/*
+	 * We'll run into this code path when beaconing is
+	 * enabled, but then we also need to send the beacon
+	 * to the device.
+	 */
+	if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
+		ret = iwlagn_update_beacon(priv, ctx->vif);
+		if (ret) {
+			IWL_ERR(priv,
+				"Error sending required beacon (%d)!\n",
+				ret);
+			return ret;
+		}
+	}
+
+	priv->start_calib = 0;
+	/*
+	 * Apply the new configuration.
+	 *
+	 * Associated RXON doesn't clear the station table in uCode,
+	 * so we don't need to restore stations etc. after this.
+	 */
+	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
+		      sizeof(struct iwl_rxon_cmd), &ctx->staging);
+	if (ret) {
+		IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
+		return ret;
+	}
+	memcpy(active, &ctx->staging, sizeof(*active));
+
+	/* IBSS beacon needs to be sent after setting assoc */
+	if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
+		if (iwlagn_update_beacon(priv, ctx->vif))
+			IWL_ERR(priv, "Error sending IBSS beacon\n");
+	iwl_init_sensitivity(priv);
+
+	/*
+	 * If we issue a new RXON command which required a tune then
+	 * we must send a new TXPOWER command or we won't be able to
+	 * Tx any frames.
+	 *
+	 * It's expected we set power here if channel is changing.
+	 */
+	ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
+	if (ret) {
+		IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
+		return ret;
+	}
+
+	if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
+	    priv->cfg->ht_params && priv->cfg->ht_params->smps_mode)
+		ieee80211_request_smps(ctx->vif,
+				       priv->cfg->ht_params->smps_mode);
+
+	return 0;
+}
+
+int iwlagn_set_pan_params(struct iwl_priv *priv)
+{
+	struct iwl_wipan_params_cmd cmd;
+	struct iwl_rxon_context *ctx_bss, *ctx_pan;
+	int slot0 = 300, slot1 = 0;
+	int ret;
+
+	if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS))
+		return 0;
+
+	BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+	lockdep_assert_held(&priv->mutex);
+
+	ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
+	ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
+
+	/*
+	 * If the PAN context is inactive, then we don't need
+	 * to update the PAN parameters, the last thing we'll
+	 * have done before it goes inactive is making the PAN
+	 * parameters be WLAN-only.
+	 */
+	if (!ctx_pan->is_active)
+		return 0;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	/* only 2 slots are currently allowed */
+	cmd.num_slots = 2;
+
+	cmd.slots[0].type = 0; /* BSS */
+	cmd.slots[1].type = 1; /* PAN */
+
+	if (priv->hw_roc_setup) {
+		/* both contexts must be used for this to happen */
+		slot1 = IWL_MIN_SLOT_TIME;
+		slot0 = 3000;
+	} else if (ctx_bss->vif && ctx_pan->vif) {
+		int bcnint = ctx_pan->beacon_int;
+		int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1;
+
+		/* should be set, but seems unused?? */
+		cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE);
+
+		if (ctx_pan->vif->type == NL80211_IFTYPE_AP &&
+		    bcnint &&
+		    bcnint != ctx_bss->beacon_int) {
+			IWL_ERR(priv,
+				"beacon intervals don't match (%d, %d)\n",
+				ctx_bss->beacon_int, ctx_pan->beacon_int);
+		} else
+			bcnint = max_t(int, bcnint,
+				       ctx_bss->beacon_int);
+		if (!bcnint)
+			bcnint = DEFAULT_BEACON_INTERVAL;
+		slot0 = bcnint / 2;
+		slot1 = bcnint - slot0;
+
+		if (test_bit(STATUS_SCAN_HW, &priv->status) ||
+		    (!ctx_bss->vif->bss_conf.idle &&
+		     !ctx_bss->vif->bss_conf.assoc)) {
+			slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
+			slot1 = IWL_MIN_SLOT_TIME;
+		} else if (!ctx_pan->vif->bss_conf.idle &&
+			   !ctx_pan->vif->bss_conf.assoc) {
+			slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
+			slot0 = IWL_MIN_SLOT_TIME;
+		}
+	} else if (ctx_pan->vif) {
+		slot0 = 0;
+		slot1 = max_t(int, 1, ctx_pan->vif->bss_conf.dtim_period) *
+					ctx_pan->beacon_int;
+		slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1);
+
+		if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+			slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME;
+			slot1 = IWL_MIN_SLOT_TIME;
+		}
+	}
+
+	cmd.slots[0].width = cpu_to_le16(slot0);
+	cmd.slots[1].width = cpu_to_le16(slot1);
+
+	ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, CMD_SYNC,
+			sizeof(cmd), &cmd);
+	if (ret)
+		IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
+
+	return ret;
+}
+
+static void _iwl_set_rxon_ht(struct iwl_priv *priv,
+			     struct iwl_ht_config *ht_conf,
+			     struct iwl_rxon_context *ctx)
+{
+	struct iwl_rxon_cmd *rxon = &ctx->staging;
+
+	if (!ctx->ht.enabled) {
+		rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
+			RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
+			RXON_FLG_HT40_PROT_MSK |
+			RXON_FLG_HT_PROT_MSK);
+		return;
+	}
+
+	/* FIXME: if the definition of ht.protection changed, the "translation"
+	 * will be needed for rxon->flags
+	 */
+	rxon->flags |= cpu_to_le32(ctx->ht.protection <<
+				   RXON_FLG_HT_OPERATING_MODE_POS);
+
+	/* Set up channel bandwidth:
+	 * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
+	/* clear the HT channel mode before set the mode */
+	rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
+			 RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+	if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) {
+		/* pure ht40 */
+		if (ctx->ht.protection ==
+		    IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
+			rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
+			/*
+			 * Note: control channel is opposite of extension
+			 * channel
+			 */
+			switch (ctx->ht.extension_chan_offset) {
+			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+				rxon->flags &=
+					~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+				break;
+			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+				rxon->flags |=
+					RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+				break;
+			}
+		} else {
+			/*
+			 * Note: control channel is opposite of extension
+			 * channel
+			 */
+			switch (ctx->ht.extension_chan_offset) {
+			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+				rxon->flags &=
+					~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+				rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
+				break;
+			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+				rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+				rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
+				break;
+			case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+			default:
+				/*
+				 * channel location only valid if in Mixed
+				 * mode
+				 */
+				IWL_ERR(priv,
+					"invalid extension channel offset\n");
+				break;
+			}
+		}
+	} else {
+		rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
+	}
+
+	iwlagn_set_rxon_chain(priv, ctx);
+
+	IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
+			"extension channel offset 0x%x\n",
+			le32_to_cpu(rxon->flags), ctx->ht.protection,
+			ctx->ht.extension_chan_offset);
+}
+
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
+{
+	struct iwl_rxon_context *ctx;
+
+	for_each_context(priv, ctx)
+		_iwl_set_rxon_ht(priv, ht_conf, ctx);
+}
+
+/**
+ * iwl_set_rxon_channel - Set the band and channel values in staging RXON
+ * @ch: requested channel as a pointer to struct ieee80211_channel
+
+ * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
+ * in the staging RXON flag structure based on the ch->band
+ */
+void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+			 struct iwl_rxon_context *ctx)
+{
+	enum ieee80211_band band = ch->band;
+	u16 channel = ch->hw_value;
+
+	if ((le16_to_cpu(ctx->staging.channel) == channel) &&
+	    (priv->band == band))
+		return;
+
+	ctx->staging.channel = cpu_to_le16(channel);
+	if (band == IEEE80211_BAND_5GHZ)
+		ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK;
+	else
+		ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
+
+	priv->band = band;
+
+	IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band);
+
+}
+
+void iwl_set_flags_for_band(struct iwl_priv *priv,
+			    struct iwl_rxon_context *ctx,
+			    enum ieee80211_band band,
+			    struct ieee80211_vif *vif)
+{
+	if (band == IEEE80211_BAND_5GHZ) {
+		ctx->staging.flags &=
+		    ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
+		      | RXON_FLG_CCK_MSK);
+		ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
+	} else {
+		/* Copied from iwl_post_associate() */
+		if (vif && vif->bss_conf.use_short_slot)
+			ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
+		else
+			ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
+		ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK;
+		ctx->staging.flags &= ~RXON_FLG_CCK_MSK;
+	}
+}
+
+static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv,
+				  struct iwl_rxon_context *ctx, int hw_decrypt)
+{
+	struct iwl_rxon_cmd *rxon = &ctx->staging;
+
+	if (hw_decrypt)
+		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+	else
+		rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+}
+
+/* validate RXON structure is valid */
+static int iwl_check_rxon_cmd(struct iwl_priv *priv,
+			      struct iwl_rxon_context *ctx)
+{
+	struct iwl_rxon_cmd *rxon = &ctx->staging;
+	u32 errors = 0;
+
+	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+		if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) {
+			IWL_WARN(priv, "check 2.4G: wrong narrow\n");
+			errors |= BIT(0);
+		}
+		if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) {
+			IWL_WARN(priv, "check 2.4G: wrong radar\n");
+			errors |= BIT(1);
+		}
+	} else {
+		if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) {
+			IWL_WARN(priv, "check 5.2G: not short slot!\n");
+			errors |= BIT(2);
+		}
+		if (rxon->flags & RXON_FLG_CCK_MSK) {
+			IWL_WARN(priv, "check 5.2G: CCK!\n");
+			errors |= BIT(3);
+		}
+	}
+	if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) {
+		IWL_WARN(priv, "mac/bssid mcast!\n");
+		errors |= BIT(4);
+	}
+
+	/* make sure basic rates 6Mbps and 1Mbps are supported */
+	if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 &&
+	    (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) {
+		IWL_WARN(priv, "neither 1 nor 6 are basic\n");
+		errors |= BIT(5);
+	}
+
+	if (le16_to_cpu(rxon->assoc_id) > 2007) {
+		IWL_WARN(priv, "aid > 2007\n");
+		errors |= BIT(6);
+	}
+
+	if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) {
+		IWL_WARN(priv, "CCK and short slot\n");
+		errors |= BIT(7);
+	}
+
+	if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) {
+		IWL_WARN(priv, "CCK and auto detect");
+		errors |= BIT(8);
+	}
+
+	if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+			    RXON_FLG_TGG_PROTECT_MSK)) ==
+			    RXON_FLG_TGG_PROTECT_MSK) {
+		IWL_WARN(priv, "TGg but no auto-detect\n");
+		errors |= BIT(9);
+	}
+
+	if (rxon->channel == 0) {
+		IWL_WARN(priv, "zero channel is invalid\n");
+		errors |= BIT(10);
+	}
+
+	WARN(errors, "Invalid RXON (%#x), channel %d",
+	     errors, le16_to_cpu(rxon->channel));
+
+	return errors ? -EINVAL : 0;
+}
+
+/**
+ * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
+ * @priv: staging_rxon is compared to active_rxon
+ *
+ * If the RXON structure is changing enough to require a new tune,
+ * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
+ * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
+ */
+static int iwl_full_rxon_required(struct iwl_priv *priv,
+				  struct iwl_rxon_context *ctx)
+{
+	const struct iwl_rxon_cmd *staging = &ctx->staging;
+	const struct iwl_rxon_cmd *active = &ctx->active;
+
+#define CHK(cond)							\
+	if ((cond)) {							\
+		IWL_DEBUG_INFO(priv, "need full RXON - " #cond "\n");	\
+		return 1;						\
+	}
+
+#define CHK_NEQ(c1, c2)						\
+	if ((c1) != (c2)) {					\
+		IWL_DEBUG_INFO(priv, "need full RXON - "	\
+			       #c1 " != " #c2 " - %d != %d\n",	\
+			       (c1), (c2));			\
+		return 1;					\
+	}
+
+	/* These items are only settable from the full RXON command */
+	CHK(!iwl_is_associated_ctx(ctx));
+	CHK(!ether_addr_equal(staging->bssid_addr, active->bssid_addr));
+	CHK(!ether_addr_equal(staging->node_addr, active->node_addr));
+	CHK(!ether_addr_equal(staging->wlap_bssid_addr,
+			      active->wlap_bssid_addr));
+	CHK_NEQ(staging->dev_type, active->dev_type);
+	CHK_NEQ(staging->channel, active->channel);
+	CHK_NEQ(staging->air_propagation, active->air_propagation);
+	CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates,
+		active->ofdm_ht_single_stream_basic_rates);
+	CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates,
+		active->ofdm_ht_dual_stream_basic_rates);
+	CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates,
+		active->ofdm_ht_triple_stream_basic_rates);
+	CHK_NEQ(staging->assoc_id, active->assoc_id);
+
+	/* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
+	 * be updated with the RXON_ASSOC command -- however only some
+	 * flag transitions are allowed using RXON_ASSOC */
+
+	/* Check if we are not switching bands */
+	CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK,
+		active->flags & RXON_FLG_BAND_24G_MSK);
+
+	/* Check if we are switching association toggle */
+	CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK,
+		active->filter_flags & RXON_FILTER_ASSOC_MSK);
+
+#undef CHK
+#undef CHK_NEQ
+
+	return 0;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+			     enum iwl_rxon_context_id ctxid)
+{
+	struct iwl_rxon_context *ctx = &priv->contexts[ctxid];
+	struct iwl_rxon_cmd *rxon = &ctx->staging;
+
+	IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
+	iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+	IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n",
+			le16_to_cpu(rxon->channel));
+	IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n",
+			le32_to_cpu(rxon->flags));
+	IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
+			le32_to_cpu(rxon->filter_flags));
+	IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type);
+	IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n",
+			rxon->ofdm_basic_rates);
+	IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n",
+			rxon->cck_basic_rates);
+	IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr);
+	IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
+	IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n",
+			le16_to_cpu(rxon->assoc_id));
+}
+#endif
+
+static void iwl_calc_basic_rates(struct iwl_priv *priv,
+				 struct iwl_rxon_context *ctx)
+{
+	int lowest_present_ofdm = 100;
+	int lowest_present_cck = 100;
+	u8 cck = 0;
+	u8 ofdm = 0;
+
+	if (ctx->vif) {
+		struct ieee80211_supported_band *sband;
+		unsigned long basic = ctx->vif->bss_conf.basic_rates;
+		int i;
+
+		sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
+
+		for_each_set_bit(i, &basic, BITS_PER_LONG) {
+			int hw = sband->bitrates[i].hw_value;
+			if (hw >= IWL_FIRST_OFDM_RATE) {
+				ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE);
+				if (lowest_present_ofdm > hw)
+					lowest_present_ofdm = hw;
+			} else {
+				BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
+
+				cck |= BIT(hw);
+				if (lowest_present_cck > hw)
+					lowest_present_cck = hw;
+			}
+		}
+	}
+
+	/*
+	 * Now we've got the basic rates as bitmaps in the ofdm and cck
+	 * variables. This isn't sufficient though, as there might not
+	 * be all the right rates in the bitmap. E.g. if the only basic
+	 * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps
+	 * and 6 Mbps because the 802.11-2007 standard says in 9.6:
+	 *
+	 *    [...] a STA responding to a received frame shall transmit
+	 *    its Control Response frame [...] at the highest rate in the
+	 *    BSSBasicRateSet parameter that is less than or equal to the
+	 *    rate of the immediately previous frame in the frame exchange
+	 *    sequence ([...]) and that is of the same modulation class
+	 *    ([...]) as the received frame. If no rate contained in the
+	 *    BSSBasicRateSet parameter meets these conditions, then the
+	 *    control frame sent in response to a received frame shall be
+	 *    transmitted at the highest mandatory rate of the PHY that is
+	 *    less than or equal to the rate of the received frame, and
+	 *    that is of the same modulation class as the received frame.
+	 *
+	 * As a consequence, we need to add all mandatory rates that are
+	 * lower than all of the basic rates to these bitmaps.
+	 */
+
+	if (IWL_RATE_24M_INDEX < lowest_present_ofdm)
+		ofdm |= IWL_RATE_24M_MASK >> IWL_FIRST_OFDM_RATE;
+	if (IWL_RATE_12M_INDEX < lowest_present_ofdm)
+		ofdm |= IWL_RATE_12M_MASK >> IWL_FIRST_OFDM_RATE;
+	/* 6M already there or needed so always add */
+	ofdm |= IWL_RATE_6M_MASK >> IWL_FIRST_OFDM_RATE;
+
+	/*
+	 * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP.
+	 * Note, however:
+	 *  - if no CCK rates are basic, it must be ERP since there must
+	 *    be some basic rates at all, so they're OFDM => ERP PHY
+	 *    (or we're in 5 GHz, and the cck bitmap will never be used)
+	 *  - if 11M is a basic rate, it must be ERP as well, so add 5.5M
+	 *  - if 5.5M is basic, 1M and 2M are mandatory
+	 *  - if 2M is basic, 1M is mandatory
+	 *  - if 1M is basic, that's the only valid ACK rate.
+	 * As a consequence, it's not as complicated as it sounds, just add
+	 * any lower rates to the ACK rate bitmap.
+	 */
+	if (IWL_RATE_11M_INDEX < lowest_present_ofdm)
+		ofdm |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE;
+	if (IWL_RATE_5M_INDEX < lowest_present_ofdm)
+		ofdm |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE;
+	if (IWL_RATE_2M_INDEX < lowest_present_ofdm)
+		ofdm |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE;
+	/* 1M already there or needed so always add */
+	cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE;
+
+	IWL_DEBUG_RATE(priv, "Set basic rates cck:0x%.2x ofdm:0x%.2x\n",
+		       cck, ofdm);
+
+	/* "basic_rates" is a misnomer here -- should be called ACK rates */
+	ctx->staging.cck_basic_rates = cck;
+	ctx->staging.ofdm_basic_rates = ofdm;
+}
+
+/**
+ * iwlagn_commit_rxon - commit staging_rxon to hardware
+ *
+ * The RXON command in staging_rxon is committed to the hardware and
+ * the active_rxon structure is updated with the new data.  This
+ * function correctly transitions out of the RXON_ASSOC_MSK state if
+ * a HW tune is required based on the RXON structure changes.
+ *
+ * The connect/disconnect flow should be as the following:
+ *
+ * 1. make sure send RXON command with association bit unset if not connect
+ *	this should include the channel and the band for the candidate
+ *	to be connected to
+ * 2. Add Station before RXON association with the AP
+ * 3. RXON_timing has to send before RXON for connection
+ * 4. full RXON command - associated bit set
+ * 5. use RXON_ASSOC command to update any flags changes
+ */
+int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+	/* cast away the const for active_rxon in this function */
+	struct iwl_rxon_cmd *active = (void *)&ctx->active;
+	bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
+	int ret;
+
+	lockdep_assert_held(&priv->mutex);
+
+	if (!iwl_is_alive(priv))
+		return -EBUSY;
+
+	/* This function hardcodes a bunch of dual-mode assumptions */
+	BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+	if (!ctx->is_active)
+		return 0;
+
+	/* always get timestamp with Rx frame */
+	ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
+
+	/* recalculate basic rates */
+	iwl_calc_basic_rates(priv, ctx);
+
+	/*
+	 * force CTS-to-self frames protection if RTS-CTS is not preferred
+	 * one aggregation protection method
+	 */
+	if (!priv->hw_params.use_rts_for_aggregation)
+		ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+
+	if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
+	    !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
+		ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
+	else
+		ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+	iwl_print_rx_config_cmd(priv, ctx->ctxid);
+	ret = iwl_check_rxon_cmd(priv, ctx);
+	if (ret) {
+		IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * receive commit_rxon request
+	 * abort any previous channel switch if still in process
+	 */
+	if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) &&
+	    (priv->switch_channel != ctx->staging.channel)) {
+		IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
+			      le16_to_cpu(priv->switch_channel));
+		iwl_chswitch_done(priv, false);
+	}
+
+	/*
+	 * If we don't need to send a full RXON, we can use
+	 * iwl_rxon_assoc_cmd which is used to reconfigure filter
+	 * and other flags for the current radio configuration.
+	 */
+	if (!iwl_full_rxon_required(priv, ctx)) {
+		ret = iwlagn_send_rxon_assoc(priv, ctx);
+		if (ret) {
+			IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
+			return ret;
+		}
+
+		memcpy(active, &ctx->staging, sizeof(*active));
+		/*
+		 * We do not commit tx power settings while channel changing,
+		 * do it now if after settings changed.
+		 */
+		iwl_set_tx_power(priv, priv->tx_power_next, false);
+
+		/* make sure we are in the right PS state */
+		iwl_power_update_mode(priv, true);
+
+		return 0;
+	}
+
+	iwl_set_rxon_hwcrypto(priv, ctx, !iwlwifi_mod_params.sw_crypto);
+
+	IWL_DEBUG_INFO(priv,
+		       "Going to commit RXON\n"
+		       "  * with%s RXON_FILTER_ASSOC_MSK\n"
+		       "  * channel = %d\n"
+		       "  * bssid = %pM\n",
+		       (new_assoc ? "" : "out"),
+		       le16_to_cpu(ctx->staging.channel),
+		       ctx->staging.bssid_addr);
+
+	/*
+	 * Always clear associated first, but with the correct config.
+	 * This is required as for example station addition for the
+	 * AP station must be done after the BSSID is set to correctly
+	 * set up filters in the device.
+	 */
+	ret = iwlagn_rxon_disconn(priv, ctx);
+	if (ret)
+		return ret;
+
+	ret = iwlagn_set_pan_params(priv);
+	if (ret)
+		return ret;
+
+	if (new_assoc)
+		return iwlagn_rxon_connect(priv, ctx);
+
+	return 0;
+}
+
+void iwlagn_config_ht40(struct ieee80211_conf *conf,
+	struct iwl_rxon_context *ctx)
+{
+	if (conf_is_ht40_minus(conf)) {
+		ctx->ht.extension_chan_offset =
+			IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+		ctx->ht.is_40mhz = true;
+	} else if (conf_is_ht40_plus(conf)) {
+		ctx->ht.extension_chan_offset =
+			IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+		ctx->ht.is_40mhz = true;
+	} else {
+		ctx->ht.extension_chan_offset =
+			IEEE80211_HT_PARAM_CHA_SEC_NONE;
+		ctx->ht.is_40mhz = false;
+	}
+}
+
+int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_rxon_context *ctx;
+	struct ieee80211_conf *conf = &hw->conf;
+	struct ieee80211_channel *channel = conf->channel;
+	int ret = 0;
+
+	IWL_DEBUG_MAC80211(priv, "enter: changed %#x\n", changed);
+
+	mutex_lock(&priv->mutex);
+
+	if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+		IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
+		goto out;
+	}
+
+	if (!iwl_is_ready(priv)) {
+		IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+		goto out;
+	}
+
+	if (changed & (IEEE80211_CONF_CHANGE_SMPS |
+		       IEEE80211_CONF_CHANGE_CHANNEL)) {
+		/* mac80211 uses static for non-HT which is what we want */
+		priv->current_ht_config.smps = conf->smps_mode;
+
+		/*
+		 * Recalculate chain counts.
+		 *
+		 * If monitor mode is enabled then mac80211 will
+		 * set up the SM PS mode to OFF if an HT channel is
+		 * configured.
+		 */
+		for_each_context(priv, ctx)
+			iwlagn_set_rxon_chain(priv, ctx);
+	}
+
+	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+		for_each_context(priv, ctx) {
+			/* Configure HT40 channels */
+			if (ctx->ht.enabled != conf_is_ht(conf))
+				ctx->ht.enabled = conf_is_ht(conf);
+
+			if (ctx->ht.enabled) {
+				/* if HT40 is used, it should not change
+				 * after associated except channel switch */
+				if (!ctx->ht.is_40mhz ||
+						!iwl_is_associated_ctx(ctx))
+					iwlagn_config_ht40(conf, ctx);
+			} else
+				ctx->ht.is_40mhz = false;
+
+			/*
+			 * Default to no protection. Protection mode will
+			 * later be set from BSS config in iwl_ht_conf
+			 */
+			ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
+
+			/* 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(ctx->staging.channel) !=
+			    channel->hw_value)
+				ctx->staging.flags = 0;
+
+			iwl_set_rxon_channel(priv, channel, ctx);
+			iwl_set_rxon_ht(priv, &priv->current_ht_config);
+
+			iwl_set_flags_for_band(priv, ctx, channel->band,
+					       ctx->vif);
+		}
+
+		iwl_update_bcast_stations(priv);
+	}
+
+	if (changed & (IEEE80211_CONF_CHANGE_PS |
+			IEEE80211_CONF_CHANGE_IDLE)) {
+		ret = iwl_power_update_mode(priv, false);
+		if (ret)
+			IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
+	}
+
+	if (changed & IEEE80211_CONF_CHANGE_POWER) {
+		IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
+			priv->tx_power_user_lmt, conf->power_level);
+
+		iwl_set_tx_power(priv, conf->power_level, false);
+	}
+
+	for_each_context(priv, ctx) {
+		if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+			continue;
+		iwlagn_commit_rxon(priv, ctx);
+	}
+ out:
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+
+	return ret;
+}
+
+static void iwlagn_check_needed_chains(struct iwl_priv *priv,
+				       struct iwl_rxon_context *ctx,
+				       struct ieee80211_bss_conf *bss_conf)
+{
+	struct ieee80211_vif *vif = ctx->vif;
+	struct iwl_rxon_context *tmp;
+	struct ieee80211_sta *sta;
+	struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+	struct ieee80211_sta_ht_cap *ht_cap;
+	bool need_multiple;
+
+	lockdep_assert_held(&priv->mutex);
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+		rcu_read_lock();
+		sta = ieee80211_find_sta(vif, bss_conf->bssid);
+		if (!sta) {
+			/*
+			 * If at all, this can only happen through a race
+			 * when the AP disconnects us while we're still
+			 * setting up the connection, in that case mac80211
+			 * will soon tell us about that.
+			 */
+			need_multiple = false;
+			rcu_read_unlock();
+			break;
+		}
+
+		ht_cap = &sta->ht_cap;
+
+		need_multiple = true;
+
+		/*
+		 * If the peer advertises no support for receiving 2 and 3
+		 * stream MCS rates, it can't be transmitting them either.
+		 */
+		if (ht_cap->mcs.rx_mask[1] == 0 &&
+		    ht_cap->mcs.rx_mask[2] == 0) {
+			need_multiple = false;
+		} else if (!(ht_cap->mcs.tx_params &
+						IEEE80211_HT_MCS_TX_DEFINED)) {
+			/* If it can't TX MCS at all ... */
+			need_multiple = false;
+		} else if (ht_cap->mcs.tx_params &
+						IEEE80211_HT_MCS_TX_RX_DIFF) {
+			int maxstreams;
+
+			/*
+			 * But if it can receive them, it might still not
+			 * be able to transmit them, which is what we need
+			 * to check here -- so check the number of streams
+			 * it advertises for TX (if different from RX).
+			 */
+
+			maxstreams = (ht_cap->mcs.tx_params &
+				 IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK);
+			maxstreams >>=
+				IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+			maxstreams += 1;
+
+			if (maxstreams <= 1)
+				need_multiple = false;
+		}
+
+		rcu_read_unlock();
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		/* currently */
+		need_multiple = false;
+		break;
+	default:
+		/* only AP really */
+		need_multiple = true;
+		break;
+	}
+
+	ctx->ht_need_multiple_chains = need_multiple;
+
+	if (!need_multiple) {
+		/* check all contexts */
+		for_each_context(priv, tmp) {
+			if (!tmp->vif)
+				continue;
+			if (tmp->ht_need_multiple_chains) {
+				need_multiple = true;
+				break;
+			}
+		}
+	}
+
+	ht_conf->single_chain_sufficient = !need_multiple;
+}
+
+static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
+{
+	struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+	int ret;
+
+	if (!(priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED))
+		return;
+
+	if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
+	    iwl_is_any_associated(priv)) {
+		struct iwl_calib_chain_noise_reset_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));
+		iwl_set_calib_hdr(&cmd.hdr,
+			priv->phy_calib_chain_noise_reset_cmd);
+		ret = iwl_dvm_send_cmd_pdu(priv,
+					REPLY_PHY_CALIBRATION_CMD,
+					CMD_SYNC, sizeof(cmd), &cmd);
+		if (ret)
+			IWL_ERR(priv,
+				"Could not send REPLY_PHY_CALIBRATION_CMD\n");
+		data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+		IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
+	}
+}
+
+void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
+			     struct ieee80211_vif *vif,
+			     struct ieee80211_bss_conf *bss_conf,
+			     u32 changes)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+	int ret;
+	bool force = false;
+
+	mutex_lock(&priv->mutex);
+
+	if (unlikely(!iwl_is_ready(priv))) {
+		IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+		mutex_unlock(&priv->mutex);
+		return;
+        }
+
+	if (unlikely(!ctx->vif)) {
+		IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	if (changes & BSS_CHANGED_BEACON_INT)
+		force = true;
+
+	if (changes & BSS_CHANGED_QOS) {
+		ctx->qos_data.qos_active = bss_conf->qos;
+		iwlagn_update_qos(priv, ctx);
+	}
+
+	ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+	if (vif->bss_conf.use_short_preamble)
+		ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+	else
+		ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+	if (changes & BSS_CHANGED_ASSOC) {
+		if (bss_conf->assoc) {
+			priv->timestamp = bss_conf->last_tsf;
+			ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+		} else {
+			/*
+			 * If we disassociate while there are pending
+			 * frames, just wake up the queues and let the
+			 * frames "escape" ... This shouldn't really
+			 * be happening to start with, but we should
+			 * not get stuck in this case either since it
+			 * can happen if userspace gets confused.
+			 */
+			iwlagn_lift_passive_no_rx(priv);
+
+			ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+			if (ctx->ctxid == IWL_RXON_CTX_BSS)
+				priv->have_rekey_data = false;
+		}
+
+		iwlagn_bt_coex_rssi_monitor(priv);
+	}
+
+	if (ctx->ht.enabled) {
+		ctx->ht.protection = bss_conf->ht_operation_mode &
+					IEEE80211_HT_OP_MODE_PROTECTION;
+		ctx->ht.non_gf_sta_present = !!(bss_conf->ht_operation_mode &
+					IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+		iwlagn_check_needed_chains(priv, ctx, bss_conf);
+		iwl_set_rxon_ht(priv, &priv->current_ht_config);
+	}
+
+	iwlagn_set_rxon_chain(priv, ctx);
+
+	if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
+		ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
+	else
+		ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+
+	if (bss_conf->use_cts_prot)
+		ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+	else
+		ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
+
+	memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN);
+
+	if (vif->type == NL80211_IFTYPE_AP ||
+	    vif->type == NL80211_IFTYPE_ADHOC) {
+		if (vif->bss_conf.enable_beacon) {
+			ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+			priv->beacon_ctx = ctx;
+		} else {
+			ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+			priv->beacon_ctx = NULL;
+		}
+	}
+
+	/*
+	 * If the ucode decides to do beacon filtering before
+	 * association, it will lose beacons that are needed
+	 * before sending frames out on passive channels. This
+	 * causes association failures on those channels. Enable
+	 * receiving beacons in such cases.
+	 */
+
+	if (vif->type == NL80211_IFTYPE_STATION) {
+		if (!bss_conf->assoc)
+			ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+		else
+			ctx->staging.filter_flags &=
+						    ~RXON_FILTER_BCON_AWARE_MSK;
+	}
+
+	if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+		iwlagn_commit_rxon(priv, ctx);
+
+	if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) {
+		/*
+		 * The chain noise calibration will enable PM upon
+		 * completion. If calibration has already been run
+		 * then we need to enable power management here.
+		 */
+		if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
+			iwl_power_update_mode(priv, false);
+
+		/* Enable RX differential gain and sensitivity calibrations */
+		iwlagn_chain_noise_reset(priv);
+		priv->start_calib = 1;
+	}
+
+	if (changes & BSS_CHANGED_IBSS) {
+		ret = iwlagn_manage_ibss_station(priv, vif,
+						 bss_conf->ibss_joined);
+		if (ret)
+			IWL_ERR(priv, "failed to %s IBSS station %pM\n",
+				bss_conf->ibss_joined ? "add" : "remove",
+				bss_conf->bssid);
+	}
+
+	if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC &&
+	    priv->beacon_ctx) {
+		if (iwlagn_update_beacon(priv, vif))
+			IWL_ERR(priv, "Error sending IBSS beacon\n");
+	}
+
+	mutex_unlock(&priv->mutex);
+}
+
+void iwlagn_post_scan(struct iwl_priv *priv)
+{
+	struct iwl_rxon_context *ctx;
+
+	/*
+	 * We do not commit power settings while scan is pending,
+	 * do it now if the settings changed.
+	 */
+	iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false);
+	iwl_set_tx_power(priv, priv->tx_power_next, false);
+
+	/*
+	 * Since setting the RXON may have been deferred while
+	 * performing the scan, fire one off if needed
+	 */
+	for_each_context(priv, ctx)
+		if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+			iwlagn_commit_rxon(priv, ctx);
+
+	iwlagn_set_pan_params(priv);
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c
new file mode 100644
index 0000000..6633074
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/scan.c
@@ -0,0 +1,1170 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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/slab.h>
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+
+#include "dev.h"
+#include "agn.h"
+
+/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+ * sending probe req.  This should be set long enough to hear probe responses
+ * from more than one AP.  */
+#define IWL_ACTIVE_DWELL_TIME_24    (30)       /* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52    (20)
+
+#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
+#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
+
+/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
+ * Must be set longer than active dwell time.
+ * For the most reliable scan, set > AP beacon interval (typically 100msec). */
+#define IWL_PASSIVE_DWELL_TIME_24   (20)       /* all times in msec */
+#define IWL_PASSIVE_DWELL_TIME_52   (10)
+#define IWL_PASSIVE_DWELL_BASE      (100)
+#define IWL_CHANNEL_TUNE_TIME       5
+#define MAX_SCAN_CHANNEL	    50
+
+/* For reset radio, need minimal dwell time only */
+#define IWL_RADIO_RESET_DWELL_TIME	5
+
+static int iwl_send_scan_abort(struct iwl_priv *priv)
+{
+	int ret;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_SCAN_ABORT_CMD,
+		.flags = CMD_SYNC | CMD_WANT_SKB,
+	};
+	__le32 *status;
+
+	/* Exit instantly with error when device is not ready
+	 * to receive scan abort command or it does not perform
+	 * hardware scan currently */
+	if (!test_bit(STATUS_READY, &priv->status) ||
+	    !test_bit(STATUS_SCAN_HW, &priv->status) ||
+	    test_bit(STATUS_FW_ERROR, &priv->status))
+		return -EIO;
+
+	ret = iwl_dvm_send_cmd(priv, &cmd);
+	if (ret)
+		return ret;
+
+	status = (void *)cmd.resp_pkt->data;
+	if (*status != CAN_ABORT_STATUS) {
+		/* The scan abort will return 1 for success or
+		 * 2 for "failure".  A failure condition can be
+		 * due to simply not being in an active scan which
+		 * can occur if we send the scan abort before we
+		 * the microcode has notified us that a scan is
+		 * completed. */
+		IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n",
+			       le32_to_cpu(*status));
+		ret = -EIO;
+	}
+
+	iwl_free_resp(&cmd);
+	return ret;
+}
+
+static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
+{
+	/* check if scan was requested from mac80211 */
+	if (priv->scan_request) {
+		IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
+		ieee80211_scan_completed(priv->hw, aborted);
+	}
+
+	if (priv->scan_type == IWL_SCAN_ROC)
+		iwl_scan_roc_expired(priv);
+
+	priv->scan_type = IWL_SCAN_NORMAL;
+	priv->scan_vif = NULL;
+	priv->scan_request = NULL;
+}
+
+static void iwl_process_scan_complete(struct iwl_priv *priv)
+{
+	bool aborted;
+
+	lockdep_assert_held(&priv->mutex);
+
+	if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->status))
+		return;
+
+	IWL_DEBUG_SCAN(priv, "Completed scan.\n");
+
+	cancel_delayed_work(&priv->scan_check);
+
+	aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+	if (aborted)
+		IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
+
+	if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) {
+		IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
+		goto out_settings;
+	}
+
+	if (priv->scan_type == IWL_SCAN_ROC)
+		iwl_scan_roc_expired(priv);
+
+	if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
+		int err;
+
+		/* Check if mac80211 requested scan during our internal scan */
+		if (priv->scan_request == NULL)
+			goto out_complete;
+
+		/* If so request a new scan */
+		err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
+					priv->scan_request->channels[0]->band);
+		if (err) {
+			IWL_DEBUG_SCAN(priv,
+				"failed to initiate pending scan: %d\n", err);
+			aborted = true;
+			goto out_complete;
+		}
+
+		return;
+	}
+
+out_complete:
+	iwl_complete_scan(priv, aborted);
+
+out_settings:
+	/* Can we still talk to firmware ? */
+	if (!iwl_is_ready_rf(priv))
+		return;
+
+	iwlagn_post_scan(priv);
+}
+
+void iwl_force_scan_end(struct iwl_priv *priv)
+{
+	lockdep_assert_held(&priv->mutex);
+
+	if (!test_bit(STATUS_SCANNING, &priv->status)) {
+		IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n");
+		return;
+	}
+
+	IWL_DEBUG_SCAN(priv, "Forcing scan end\n");
+	clear_bit(STATUS_SCANNING, &priv->status);
+	clear_bit(STATUS_SCAN_HW, &priv->status);
+	clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+	clear_bit(STATUS_SCAN_COMPLETE, &priv->status);
+	iwl_complete_scan(priv, true);
+}
+
+static void iwl_do_scan_abort(struct iwl_priv *priv)
+{
+	int ret;
+
+	lockdep_assert_held(&priv->mutex);
+
+	if (!test_bit(STATUS_SCANNING, &priv->status)) {
+		IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n");
+		return;
+	}
+
+	if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_SCAN(priv, "Scan abort in progress\n");
+		return;
+	}
+
+	ret = iwl_send_scan_abort(priv);
+	if (ret) {
+		IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret);
+		iwl_force_scan_end(priv);
+	} else
+		IWL_DEBUG_SCAN(priv, "Successfully send scan abort\n");
+}
+
+/**
+ * iwl_scan_cancel - Cancel any currently executing HW scan
+ */
+int iwl_scan_cancel(struct iwl_priv *priv)
+{
+	IWL_DEBUG_SCAN(priv, "Queuing abort scan\n");
+	queue_work(priv->workqueue, &priv->abort_scan);
+	return 0;
+}
+
+/**
+ * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
+ * @ms: amount of time to wait (in milliseconds) for scan to abort
+ *
+ */
+void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(ms);
+
+	lockdep_assert_held(&priv->mutex);
+
+	IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n");
+
+	iwl_do_scan_abort(priv);
+
+	while (time_before_eq(jiffies, timeout)) {
+		if (!test_bit(STATUS_SCAN_HW, &priv->status))
+			goto finished;
+		msleep(20);
+	}
+
+	return;
+
+ finished:
+	/*
+	 * Now STATUS_SCAN_HW is clear. This means that the
+	 * device finished, but the background work is going
+	 * to execute at best as soon as we release the mutex.
+	 * Since we need to be able to issue a new scan right
+	 * after this function returns, run the complete here.
+	 * The STATUS_SCAN_COMPLETE bit will then be cleared
+	 * and prevent the background work from "completing"
+	 * a possible new scan.
+	 */
+	iwl_process_scan_complete(priv);
+}
+
+/* Service response to REPLY_SCAN_CMD (0x80) */
+static int iwl_rx_reply_scan(struct iwl_priv *priv,
+			      struct iwl_rx_cmd_buffer *rxb,
+			      struct iwl_device_cmd *cmd)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_scanreq_notification *notif = (void *)pkt->data;
+
+	IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status);
+#endif
+	return 0;
+}
+
+/* Service SCAN_START_NOTIFICATION (0x82) */
+static int iwl_rx_scan_start_notif(struct iwl_priv *priv,
+				    struct iwl_rx_cmd_buffer *rxb,
+				    struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_scanstart_notification *notif = (void *)pkt->data;
+
+	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
+	IWL_DEBUG_SCAN(priv, "Scan start: "
+		       "%d [802.11%s] "
+		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
+		       notif->channel,
+		       notif->band ? "bg" : "a",
+		       le32_to_cpu(notif->tsf_high),
+		       le32_to_cpu(notif->tsf_low),
+		       notif->status, notif->beacon_timer);
+
+	if (priv->scan_type == IWL_SCAN_ROC &&
+	    !priv->hw_roc_start_notified) {
+		ieee80211_ready_on_channel(priv->hw);
+		priv->hw_roc_start_notified = true;
+	}
+
+	return 0;
+}
+
+/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
+static int iwl_rx_scan_results_notif(struct iwl_priv *priv,
+				      struct iwl_rx_cmd_buffer *rxb,
+				      struct iwl_device_cmd *cmd)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_scanresults_notification *notif = (void *)pkt->data;
+
+	IWL_DEBUG_SCAN(priv, "Scan ch.res: "
+		       "%d [802.11%s] "
+		       "probe status: %u:%u "
+		       "(TSF: 0x%08X:%08X) - %d "
+		       "elapsed=%lu usec\n",
+		       notif->channel,
+		       notif->band ? "bg" : "a",
+		       notif->probe_status, notif->num_probe_not_sent,
+		       le32_to_cpu(notif->tsf_high),
+		       le32_to_cpu(notif->tsf_low),
+		       le32_to_cpu(notif->statistics[0]),
+		       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
+#endif
+	return 0;
+}
+
+/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
+static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+				       struct iwl_rx_cmd_buffer *rxb,
+				       struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_scancomplete_notification *scan_notif = (void *)pkt->data;
+
+	IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
+		       scan_notif->scanned_channels,
+		       scan_notif->tsf_low,
+		       scan_notif->tsf_high, scan_notif->status);
+
+	IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
+		       (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
+		       jiffies_to_msecs(jiffies - priv->scan_start));
+
+	/*
+	 * When aborting, we run the scan completed background work inline
+	 * and the background work must then do nothing. The SCAN_COMPLETE
+	 * bit helps implement that logic and thus needs to be set before
+	 * queueing the work. Also, since the scan abort waits for SCAN_HW
+	 * to clear, we need to set SCAN_COMPLETE before clearing SCAN_HW
+	 * to avoid a race there.
+	 */
+	set_bit(STATUS_SCAN_COMPLETE, &priv->status);
+	clear_bit(STATUS_SCAN_HW, &priv->status);
+	queue_work(priv->workqueue, &priv->scan_completed);
+
+	if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
+	    iwl_advanced_bt_coexist(priv) &&
+	    priv->bt_status != scan_notif->bt_status) {
+		if (scan_notif->bt_status) {
+			/* BT on */
+			if (!priv->bt_ch_announce)
+				priv->bt_traffic_load =
+					IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+			/*
+			 * otherwise, no traffic load information provided
+			 * no changes made
+			 */
+		} else {
+			/* BT off */
+			priv->bt_traffic_load =
+				IWL_BT_COEX_TRAFFIC_LOAD_NONE;
+		}
+		priv->bt_status = scan_notif->bt_status;
+		queue_work(priv->workqueue,
+			   &priv->bt_traffic_change_work);
+	}
+	return 0;
+}
+
+void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
+{
+	/* scan handlers */
+	priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
+	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
+	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
+					iwl_rx_scan_results_notif;
+	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
+					iwl_rx_scan_complete_notif;
+}
+
+static u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
+				     enum ieee80211_band band, u8 n_probes)
+{
+	if (band == IEEE80211_BAND_5GHZ)
+		return IWL_ACTIVE_DWELL_TIME_52 +
+			IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
+	else
+		return IWL_ACTIVE_DWELL_TIME_24 +
+			IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
+}
+
+static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time)
+{
+	struct iwl_rxon_context *ctx;
+
+	/*
+	 * If we're associated, we clamp the dwell time 98%
+	 * of the smallest beacon interval (minus 2 * channel
+	 * tune time)
+	 */
+	for_each_context(priv, ctx) {
+		u16 value;
+
+		switch (ctx->staging.dev_type) {
+		case RXON_DEV_TYPE_P2P:
+			/* no timing constraints */
+			continue;
+		case RXON_DEV_TYPE_ESS:
+		default:
+			/* timing constraints if associated */
+			if (!iwl_is_associated_ctx(ctx))
+				continue;
+			break;
+		case RXON_DEV_TYPE_CP:
+		case RXON_DEV_TYPE_2STA:
+			/*
+			 * These seem to always have timers for TBTT
+			 * active in uCode even when not associated yet.
+			 */
+			break;
+		}
+
+		value = ctx->beacon_int;
+		if (!value)
+			value = IWL_PASSIVE_DWELL_BASE;
+		value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+		dwell_time = min(value, dwell_time);
+	}
+
+	return dwell_time;
+}
+
+static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
+				      enum ieee80211_band band)
+{
+	u16 passive = (band == IEEE80211_BAND_2GHZ) ?
+	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
+	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
+
+	return iwl_limit_dwell(priv, passive);
+}
+
+/* Return valid, unused, channel for a passive scan to reset the RF */
+static u8 iwl_get_single_channel_number(struct iwl_priv *priv,
+					enum ieee80211_band band)
+{
+	struct ieee80211_supported_band *sband = priv->hw->wiphy->bands[band];
+	struct iwl_rxon_context *ctx;
+	int i;
+
+	for (i = 0; i < sband->n_channels; i++) {
+		bool busy = false;
+
+		for_each_context(priv, ctx) {
+			busy = sband->channels[i].hw_value ==
+				le16_to_cpu(ctx->staging.channel);
+			if (busy)
+				break;
+		}
+
+		if (busy)
+			continue;
+
+		if (!(sband->channels[i].flags & IEEE80211_CHAN_DISABLED))
+			return sband->channels[i].hw_value;
+	}
+
+	return 0;
+}
+
+static int iwl_get_channel_for_reset_scan(struct iwl_priv *priv,
+					  struct ieee80211_vif *vif,
+					  enum ieee80211_band band,
+					  struct iwl_scan_channel *scan_ch)
+{
+	const struct ieee80211_supported_band *sband;
+	u16 channel;
+
+	sband = iwl_get_hw_mode(priv, band);
+	if (!sband) {
+		IWL_ERR(priv, "invalid band\n");
+		return 0;
+	}
+
+	channel = iwl_get_single_channel_number(priv, band);
+	if (channel) {
+		scan_ch->channel = cpu_to_le16(channel);
+		scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+		scan_ch->active_dwell =
+			cpu_to_le16(IWL_RADIO_RESET_DWELL_TIME);
+		scan_ch->passive_dwell =
+			cpu_to_le16(IWL_RADIO_RESET_DWELL_TIME);
+		/* Set txpower levels to defaults */
+		scan_ch->dsp_atten = 110;
+		if (band == IEEE80211_BAND_5GHZ)
+			scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+		else
+			scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+		return 1;
+	}
+
+	IWL_ERR(priv, "no valid channel found\n");
+	return 0;
+}
+
+static int iwl_get_channels_for_scan(struct iwl_priv *priv,
+				     struct ieee80211_vif *vif,
+				     enum ieee80211_band band,
+				     u8 is_active, u8 n_probes,
+				     struct iwl_scan_channel *scan_ch)
+{
+	struct ieee80211_channel *chan;
+	const struct ieee80211_supported_band *sband;
+	u16 passive_dwell = 0;
+	u16 active_dwell = 0;
+	int added, i;
+	u16 channel;
+
+	sband = iwl_get_hw_mode(priv, band);
+	if (!sband)
+		return 0;
+
+	active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
+	passive_dwell = iwl_get_passive_dwell_time(priv, band);
+
+	if (passive_dwell <= active_dwell)
+		passive_dwell = active_dwell + 1;
+
+	for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+		chan = priv->scan_request->channels[i];
+
+		if (chan->band != band)
+			continue;
+
+		channel = chan->hw_value;
+		scan_ch->channel = cpu_to_le16(channel);
+
+		if (!is_active || (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
+			scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+		else
+			scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
+
+		if (n_probes)
+			scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
+
+		scan_ch->active_dwell = cpu_to_le16(active_dwell);
+		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+		/* Set txpower levels to defaults */
+		scan_ch->dsp_atten = 110;
+
+		/* NOTE: if we were doing 6Mb OFDM for scans we'd use
+		 * power level:
+		 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
+		 */
+		if (band == IEEE80211_BAND_5GHZ)
+			scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+		else
+			scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+
+		IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n",
+			       channel, le32_to_cpu(scan_ch->type),
+			       (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+				"ACTIVE" : "PASSIVE",
+			       (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+			       active_dwell : passive_dwell);
+
+		scan_ch++;
+		added++;
+	}
+
+	IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
+	return added;
+}
+
+/**
+ * iwl_fill_probe_req - fill in all required fields and IE for probe request
+ */
+
+static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
+			      const u8 *ies, int ie_len, const u8 *ssid,
+			      u8 ssid_len, int left)
+{
+	int len = 0;
+	u8 *pos = NULL;
+
+	/* Make sure there is enough space for the probe request,
+	 * two mandatory IEs and the data */
+	left -= 24;
+	if (left < 0)
+		return 0;
+
+	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+	memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
+	memcpy(frame->sa, ta, ETH_ALEN);
+	memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
+	frame->seq_ctrl = 0;
+
+	len += 24;
+
+	/* ...next IE... */
+	pos = &frame->u.probe_req.variable[0];
+
+	/* fill in our SSID IE */
+	left -= ssid_len + 2;
+	if (left < 0)
+		return 0;
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = ssid_len;
+	if (ssid && ssid_len) {
+		memcpy(pos, ssid, ssid_len);
+		pos += ssid_len;
+	}
+
+	len += ssid_len + 2;
+
+	if (WARN_ON(left < ie_len))
+		return len;
+
+	if (ies && ie_len) {
+		memcpy(pos, ies, ie_len);
+		len += ie_len;
+	}
+
+	return (u16)len;
+}
+
+static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
+{
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_SCAN_CMD,
+		.len = { sizeof(struct iwl_scan_cmd), },
+		.flags = CMD_SYNC,
+	};
+	struct iwl_scan_cmd *scan;
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+	u32 rate_flags = 0;
+	u16 cmd_len = 0;
+	u16 rx_chain = 0;
+	enum ieee80211_band band;
+	u8 n_probes = 0;
+	u8 rx_ant = priv->eeprom_data->valid_rx_ant;
+	u8 rate;
+	bool is_active = false;
+	int  chan_mod;
+	u8 active_chains;
+	u8 scan_tx_antennas = priv->eeprom_data->valid_tx_ant;
+	int ret;
+	int scan_cmd_size = sizeof(struct iwl_scan_cmd) +
+			    MAX_SCAN_CHANNEL * sizeof(struct iwl_scan_channel) +
+			    priv->fw->ucode_capa.max_probe_length;
+	const u8 *ssid = NULL;
+	u8 ssid_len = 0;
+
+	if (WARN_ON_ONCE(priv->scan_request &&
+			 priv->scan_request->n_channels > MAX_SCAN_CHANNEL))
+		return -EINVAL;
+
+	lockdep_assert_held(&priv->mutex);
+
+	if (vif)
+		ctx = iwl_rxon_ctx_from_vif(vif);
+
+	if (!priv->scan_cmd) {
+		priv->scan_cmd = kmalloc(scan_cmd_size, GFP_KERNEL);
+		if (!priv->scan_cmd) {
+			IWL_DEBUG_SCAN(priv,
+				       "fail to allocate memory for scan\n");
+			return -ENOMEM;
+		}
+	}
+	scan = priv->scan_cmd;
+	memset(scan, 0, scan_cmd_size);
+
+	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+	if (priv->scan_type != IWL_SCAN_ROC &&
+	    iwl_is_any_associated(priv)) {
+		u16 interval = 0;
+		u32 extra;
+		u32 suspend_time = 100;
+		u32 scan_suspend_time = 100;
+
+		IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
+		switch (priv->scan_type) {
+		case IWL_SCAN_ROC:
+			WARN_ON(1);
+			break;
+		case IWL_SCAN_RADIO_RESET:
+			interval = 0;
+			break;
+		case IWL_SCAN_NORMAL:
+			interval = vif->bss_conf.beacon_int;
+			break;
+		}
+
+		scan->suspend_time = 0;
+		scan->max_out_time = cpu_to_le32(200 * 1024);
+		if (!interval)
+			interval = suspend_time;
+
+		extra = (suspend_time / interval) << 22;
+		scan_suspend_time = (extra |
+		    ((suspend_time % interval) * 1024));
+		scan->suspend_time = cpu_to_le32(scan_suspend_time);
+		IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
+			       scan_suspend_time, interval);
+	} else if (priv->scan_type == IWL_SCAN_ROC) {
+		scan->suspend_time = 0;
+		scan->max_out_time = 0;
+		scan->quiet_time = 0;
+		scan->quiet_plcp_th = 0;
+	}
+
+	switch (priv->scan_type) {
+	case IWL_SCAN_RADIO_RESET:
+		IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
+		/*
+		 * Override quiet time as firmware checks that active
+		 * dwell is >= quiet; since we use passive scan it'll
+		 * not actually be used.
+		 */
+		scan->quiet_time = cpu_to_le16(IWL_RADIO_RESET_DWELL_TIME);
+		break;
+	case IWL_SCAN_NORMAL:
+		if (priv->scan_request->n_ssids) {
+			int i, p = 0;
+			IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
+			/*
+			 * The highest priority SSID is inserted to the
+			 * probe request template.
+			 */
+			ssid_len = priv->scan_request->ssids[0].ssid_len;
+			ssid = priv->scan_request->ssids[0].ssid;
+
+			/*
+			 * Invert the order of ssids, the firmware will invert
+			 * it back.
+			 */
+			for (i = priv->scan_request->n_ssids - 1; i >= 1; i--) {
+				scan->direct_scan[p].id = WLAN_EID_SSID;
+				scan->direct_scan[p].len =
+					priv->scan_request->ssids[i].ssid_len;
+				memcpy(scan->direct_scan[p].ssid,
+				       priv->scan_request->ssids[i].ssid,
+				       priv->scan_request->ssids[i].ssid_len);
+				n_probes++;
+				p++;
+			}
+			is_active = true;
+		} else
+			IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
+		break;
+	case IWL_SCAN_ROC:
+		IWL_DEBUG_SCAN(priv, "Start ROC scan.\n");
+		break;
+	}
+
+	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
+	scan->tx_cmd.sta_id = ctx->bcast_sta_id;
+	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+	switch (priv->scan_band) {
+	case IEEE80211_BAND_2GHZ:
+		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+		chan_mod = le32_to_cpu(
+			priv->contexts[IWL_RXON_CTX_BSS].active.flags &
+						RXON_FLG_CHANNEL_MODE_MSK)
+				       >> RXON_FLG_CHANNEL_MODE_POS;
+		if ((priv->scan_request && priv->scan_request->no_cck) ||
+		    chan_mod == CHANNEL_MODE_PURE_40) {
+			rate = IWL_RATE_6M_PLCP;
+		} else {
+			rate = IWL_RATE_1M_PLCP;
+			rate_flags = RATE_MCS_CCK_MSK;
+		}
+		/*
+		 * Internal scans are passive, so we can indiscriminately set
+		 * the BT ignore flag on 2.4 GHz since it applies to TX only.
+		 */
+		if (priv->cfg->bt_params &&
+		    priv->cfg->bt_params->advanced_bt_coexist)
+			scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
+		break;
+	case IEEE80211_BAND_5GHZ:
+		rate = IWL_RATE_6M_PLCP;
+		break;
+	default:
+		IWL_WARN(priv, "Invalid scan band\n");
+		return -EIO;
+	}
+
+	/*
+	 * If active scanning is requested but a certain channel is
+	 * marked passive, we can do active scanning if we detect
+	 * transmissions.
+	 *
+	 * There is an issue with some firmware versions that triggers
+	 * a sysassert on a "good CRC threshold" of zero (== disabled),
+	 * on a radar channel even though this means that we should NOT
+	 * send probes.
+	 *
+	 * The "good CRC threshold" is the number of frames that we
+	 * need to receive during our dwell time on a channel before
+	 * sending out probes -- setting this to a huge value will
+	 * mean we never reach it, but at the same time work around
+	 * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
+	 * here instead of IWL_GOOD_CRC_TH_DISABLED.
+	 *
+	 * This was fixed in later versions along with some other
+	 * scan changes, and the threshold behaves as a flag in those
+	 * versions.
+	 */
+	if (priv->new_scan_threshold_behaviour)
+		scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+						IWL_GOOD_CRC_TH_DISABLED;
+	else
+		scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+						IWL_GOOD_CRC_TH_NEVER;
+
+	band = priv->scan_band;
+
+	if (band == IEEE80211_BAND_2GHZ &&
+	    priv->cfg->bt_params &&
+	    priv->cfg->bt_params->advanced_bt_coexist) {
+		/* transmit 2.4 GHz probes only on first antenna */
+		scan_tx_antennas = first_antenna(scan_tx_antennas);
+	}
+
+	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);
+
+	/*
+	 * In power save mode while associated use one chain,
+	 * otherwise use all chains
+	 */
+	if (test_bit(STATUS_POWER_PMI, &priv->status) &&
+	    !(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) {
+		/* rx_ant has been set to all valid chains previously */
+		active_chains = rx_ant &
+				((u8)(priv->chain_noise_data.active_chains));
+		if (!active_chains)
+			active_chains = rx_ant;
+
+		IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n",
+				priv->chain_noise_data.active_chains);
+
+		rx_ant = first_antenna(active_chains);
+	}
+	if (priv->cfg->bt_params &&
+	    priv->cfg->bt_params->advanced_bt_coexist &&
+	    priv->bt_full_concurrent) {
+		/* operated as 1x1 in full concurrency mode */
+		rx_ant = first_antenna(rx_ant);
+	}
+
+	/* MIMO is not used here, but value is required */
+	rx_chain |=
+		priv->eeprom_data->valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
+	rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
+	rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
+	rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
+	scan->rx_chain = cpu_to_le16(rx_chain);
+	switch (priv->scan_type) {
+	case IWL_SCAN_NORMAL:
+		cmd_len = iwl_fill_probe_req(
+					(struct ieee80211_mgmt *)scan->data,
+					vif->addr,
+					priv->scan_request->ie,
+					priv->scan_request->ie_len,
+					ssid, ssid_len,
+					scan_cmd_size - sizeof(*scan));
+		break;
+	case IWL_SCAN_RADIO_RESET:
+	case IWL_SCAN_ROC:
+		/* use bcast addr, will not be transmitted but must be valid */
+		cmd_len = iwl_fill_probe_req(
+					(struct ieee80211_mgmt *)scan->data,
+					iwl_bcast_addr, NULL, 0,
+					NULL, 0,
+					scan_cmd_size - sizeof(*scan));
+		break;
+	default:
+		BUG();
+	}
+	scan->tx_cmd.len = cpu_to_le16(cmd_len);
+
+	scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
+			       RXON_FILTER_BCON_AWARE_MSK);
+
+	switch (priv->scan_type) {
+	case IWL_SCAN_RADIO_RESET:
+		scan->channel_count =
+			iwl_get_channel_for_reset_scan(priv, vif, band,
+				(void *)&scan->data[cmd_len]);
+		break;
+	case IWL_SCAN_NORMAL:
+		scan->channel_count =
+			iwl_get_channels_for_scan(priv, vif, band,
+				is_active, n_probes,
+				(void *)&scan->data[cmd_len]);
+		break;
+	case IWL_SCAN_ROC: {
+		struct iwl_scan_channel *scan_ch;
+		int n_chan, i;
+		u16 dwell;
+
+		dwell = iwl_limit_dwell(priv, priv->hw_roc_duration);
+		n_chan = DIV_ROUND_UP(priv->hw_roc_duration, dwell);
+
+		scan->channel_count = n_chan;
+
+		scan_ch = (void *)&scan->data[cmd_len];
+
+		for (i = 0; i < n_chan; i++) {
+			scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+			scan_ch->channel =
+				cpu_to_le16(priv->hw_roc_channel->hw_value);
+
+			if (i == n_chan - 1)
+				dwell = priv->hw_roc_duration - i * dwell;
+
+			scan_ch->active_dwell =
+			scan_ch->passive_dwell = cpu_to_le16(dwell);
+
+			/* Set txpower levels to defaults */
+			scan_ch->dsp_atten = 110;
+
+			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
+			 * power level:
+			 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
+			 */
+			if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ)
+				scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+			else
+				scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+
+			scan_ch++;
+		}
+		}
+
+		break;
+	}
+
+	if (scan->channel_count == 0) {
+		IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
+		return -EIO;
+	}
+
+	cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
+	    scan->channel_count * sizeof(struct iwl_scan_channel);
+	cmd.data[0] = scan;
+	cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+	scan->len = cpu_to_le16(cmd.len[0]);
+
+	/* set scan bit here for PAN params */
+	set_bit(STATUS_SCAN_HW, &priv->status);
+
+	ret = iwlagn_set_pan_params(priv);
+	if (ret) {
+		clear_bit(STATUS_SCAN_HW, &priv->status);
+		return ret;
+	}
+
+	ret = iwl_dvm_send_cmd(priv, &cmd);
+	if (ret) {
+		clear_bit(STATUS_SCAN_HW, &priv->status);
+		iwlagn_set_pan_params(priv);
+	}
+
+	return ret;
+}
+
+void iwl_init_scan_params(struct iwl_priv *priv)
+{
+	u8 ant_idx = fls(priv->eeprom_data->valid_tx_ant) - 1;
+	if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
+		priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
+	if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
+		priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
+}
+
+int __must_check iwl_scan_initiate(struct iwl_priv *priv,
+				   struct ieee80211_vif *vif,
+				   enum iwl_scan_type scan_type,
+				   enum ieee80211_band band)
+{
+	int ret;
+
+	lockdep_assert_held(&priv->mutex);
+
+	cancel_delayed_work(&priv->scan_check);
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_WARN(priv, "Request scan called when driver not ready.\n");
+		return -EIO;
+	}
+
+	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+		IWL_DEBUG_SCAN(priv,
+			"Multiple concurrent scan requests in parallel.\n");
+		return -EBUSY;
+	}
+
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n");
+		return -EBUSY;
+	}
+
+	IWL_DEBUG_SCAN(priv, "Starting %sscan...\n",
+			scan_type == IWL_SCAN_NORMAL ? "" :
+			scan_type == IWL_SCAN_ROC ? "remain-on-channel " :
+			"internal short ");
+
+	set_bit(STATUS_SCANNING, &priv->status);
+	priv->scan_type = scan_type;
+	priv->scan_start = jiffies;
+	priv->scan_band = band;
+
+	ret = iwlagn_request_scan(priv, vif);
+	if (ret) {
+		clear_bit(STATUS_SCANNING, &priv->status);
+		priv->scan_type = IWL_SCAN_NORMAL;
+		return ret;
+	}
+
+	queue_delayed_work(priv->workqueue, &priv->scan_check,
+			   IWL_SCAN_CHECK_WATCHDOG);
+
+	return 0;
+}
+
+
+/*
+ * internal short scan, this function should only been called while associated.
+ * It will reset and tune the radio to prevent possible RF related problem
+ */
+void iwl_internal_short_hw_scan(struct iwl_priv *priv)
+{
+	queue_work(priv->workqueue, &priv->start_internal_scan);
+}
+
+static void iwl_bg_start_internal_scan(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+		container_of(work, struct iwl_priv, start_internal_scan);
+
+	IWL_DEBUG_SCAN(priv, "Start internal scan\n");
+
+	mutex_lock(&priv->mutex);
+
+	if (priv->scan_type == IWL_SCAN_RADIO_RESET) {
+		IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
+		goto unlock;
+	}
+
+	if (test_bit(STATUS_SCANNING, &priv->status)) {
+		IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
+		goto unlock;
+	}
+
+	if (iwl_scan_initiate(priv, NULL, IWL_SCAN_RADIO_RESET, priv->band))
+		IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n");
+ unlock:
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_scan_check(struct work_struct *data)
+{
+	struct iwl_priv *priv =
+	    container_of(data, struct iwl_priv, scan_check.work);
+
+	IWL_DEBUG_SCAN(priv, "Scan check work\n");
+
+	/* Since we are here firmware does not finish scan and
+	 * most likely is in bad shape, so we don't bother to
+	 * send abort command, just force scan complete to mac80211 */
+	mutex_lock(&priv->mutex);
+	iwl_force_scan_end(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_abort_scan(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
+
+	IWL_DEBUG_SCAN(priv, "Abort scan work\n");
+
+	/* We keep scan_check work queued in case when firmware will not
+	 * report back scan completed notification */
+	mutex_lock(&priv->mutex);
+	iwl_scan_cancel_timeout(priv, 200);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_scan_completed(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+		container_of(work, struct iwl_priv, scan_completed);
+
+	mutex_lock(&priv->mutex);
+	iwl_process_scan_complete(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
+{
+	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
+	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
+	INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
+	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
+}
+
+void iwl_cancel_scan_deferred_work(struct iwl_priv *priv)
+{
+	cancel_work_sync(&priv->start_internal_scan);
+	cancel_work_sync(&priv->abort_scan);
+	cancel_work_sync(&priv->scan_completed);
+
+	if (cancel_delayed_work_sync(&priv->scan_check)) {
+		mutex_lock(&priv->mutex);
+		iwl_force_scan_end(priv);
+		mutex_unlock(&priv->mutex);
+	}
+}
+
+void iwl_scan_roc_expired(struct iwl_priv *priv)
+{
+	/*
+	 * The status bit should be set here, to prevent a race
+	 * where the atomic_read returns 1, but before the execution continues
+	 * iwl_scan_offchannel_skb_status() checks if the status bit is set
+	 */
+	set_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status);
+
+	if (atomic_read(&priv->num_aux_in_flight) == 0) {
+		ieee80211_remain_on_channel_expired(priv->hw);
+		priv->hw_roc_channel = NULL;
+		schedule_delayed_work(&priv->hw_roc_disable_work,
+				      10 * HZ);
+
+		clear_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status);
+	} else {
+		IWL_DEBUG_SCAN(priv, "ROC done with %d frames in aux\n",
+			       atomic_read(&priv->num_aux_in_flight));
+	}
+}
+
+void iwl_scan_offchannel_skb(struct iwl_priv *priv)
+{
+	WARN_ON(!priv->hw_roc_start_notified);
+	atomic_inc(&priv->num_aux_in_flight);
+}
+
+void iwl_scan_offchannel_skb_status(struct iwl_priv *priv)
+{
+	if (atomic_dec_return(&priv->num_aux_in_flight) == 0 &&
+	    test_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status)) {
+		IWL_DEBUG_SCAN(priv, "0 aux frames. Calling ROC expired\n");
+		iwl_scan_roc_expired(priv);
+	}
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c
new file mode 100644
index 0000000..b29b798
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/sta.c
@@ -0,0 +1,1485 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+#include "iwl-trans.h"
+#include "dev.h"
+#include "agn.h"
+
+const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
+{
+	lockdep_assert_held(&priv->sta_lock);
+
+	if (sta_id >= IWLAGN_STATION_COUNT) {
+		IWL_ERR(priv, "invalid sta_id %u", sta_id);
+		return -EINVAL;
+	}
+	if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
+		IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u "
+			"addr %pM\n",
+			sta_id, priv->stations[sta_id].sta.sta.addr);
+
+	if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) {
+		IWL_DEBUG_ASSOC(priv,
+				"STA id %u addr %pM already present in uCode "
+				"(according to driver)\n",
+				sta_id, priv->stations[sta_id].sta.sta.addr);
+	} else {
+		priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
+		IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n",
+				sta_id, priv->stations[sta_id].sta.sta.addr);
+	}
+	return 0;
+}
+
+static int iwl_process_add_sta_resp(struct iwl_priv *priv,
+				    struct iwl_addsta_cmd *addsta,
+				    struct iwl_rx_packet *pkt)
+{
+	struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data;
+	u8 sta_id = addsta->sta.sta_id;
+	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 ret;
+	}
+
+	IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
+		       sta_id);
+
+	spin_lock(&priv->sta_lock);
+
+	switch (add_sta_resp->status) {
+	case ADD_STA_SUCCESS_MSK:
+		IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
+		ret = iwl_sta_ucode_activate(priv, sta_id);
+		break;
+	case ADD_STA_NO_ROOM_IN_TABLE:
+		IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
+			sta_id);
+		break;
+	case ADD_STA_NO_BLOCK_ACK_RESOURCE:
+		IWL_ERR(priv, "Adding station %d failed, no block ack "
+			"resource.\n", sta_id);
+		break;
+	case ADD_STA_MODIFY_NON_EXIST_STA:
+		IWL_ERR(priv, "Attempting to modify non-existing station %d\n",
+			sta_id);
+		break;
+	default:
+		IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
+				add_sta_resp->status);
+		break;
+	}
+
+	IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n",
+		       priv->stations[sta_id].sta.mode ==
+		       STA_CONTROL_MODIFY_MSK ?  "Modified" : "Added",
+		       sta_id, priv->stations[sta_id].sta.sta.addr);
+
+	/*
+	 * XXX: The MAC address in the command buffer is often changed from
+	 * the original sent to the device. That is, the MAC address
+	 * written to the command buffer often is not the same MAC address
+	 * read from the command buffer when the command returns. This
+	 * issue has not yet been resolved and this debugging is left to
+	 * observe the problem.
+	 */
+	IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n",
+		       priv->stations[sta_id].sta.mode ==
+		       STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
+		       addsta->sta.addr);
+	spin_unlock(&priv->sta_lock);
+
+	return ret;
+}
+
+int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+			       struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_addsta_cmd *addsta =
+		(struct iwl_addsta_cmd *) cmd->payload;
+
+	return iwl_process_add_sta_resp(priv, addsta, pkt);
+}
+
+int iwl_send_add_sta(struct iwl_priv *priv,
+		     struct iwl_addsta_cmd *sta, u8 flags)
+{
+	int ret = 0;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_ADD_STA,
+		.flags = flags,
+		.data = { sta, },
+		.len = { sizeof(*sta), },
+	};
+	u8 sta_id __maybe_unused = sta->sta.sta_id;
+
+	IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n",
+		       sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : "");
+
+	if (!(flags & CMD_ASYNC)) {
+		cmd.flags |= CMD_WANT_SKB;
+		might_sleep();
+	}
+
+	ret = iwl_dvm_send_cmd(priv, &cmd);
+
+	if (ret || (flags & CMD_ASYNC))
+		return ret;
+	/*else the command was successfully sent in SYNC mode, need to free
+	 * the reply page */
+
+	iwl_free_resp(&cmd);
+
+	if (cmd.handler_status)
+		IWL_ERR(priv, "%s - error in the CMD response %d", __func__,
+			cmd.handler_status);
+
+	return cmd.handler_status;
+}
+
+bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
+			    struct iwl_rxon_context *ctx,
+			    struct ieee80211_sta_ht_cap *ht_cap)
+{
+	if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
+		return false;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	if (priv->disable_ht40)
+		return false;
+#endif
+
+	/*
+	 * Remainder of this function checks ht_cap, but if it's
+	 * NULL then we can do HT40 (special case for RXON)
+	 */
+	if (!ht_cap)
+		return true;
+
+	if (!ht_cap->ht_supported)
+		return false;
+
+	if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+		return false;
+
+	return true;
+}
+
+static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
+				  struct ieee80211_sta *sta,
+				  struct iwl_rxon_context *ctx,
+				  __le32 *flags, __le32 *mask)
+{
+	struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
+	u8 mimo_ps_mode;
+
+	*mask = STA_FLG_RTS_MIMO_PROT_MSK |
+		STA_FLG_MIMO_DIS_MSK |
+		STA_FLG_HT40_EN_MSK |
+		STA_FLG_MAX_AGG_SIZE_MSK |
+		STA_FLG_AGG_MPDU_DENSITY_MSK;
+	*flags = 0;
+
+	if (!sta || !sta_ht_inf->ht_supported)
+		return;
+
+	mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
+
+	IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n",
+			sta->addr,
+			(mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
+			"static" :
+			(mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
+			"dynamic" : "disabled");
+
+	switch (mimo_ps_mode) {
+	case WLAN_HT_CAP_SM_PS_STATIC:
+		*flags |= STA_FLG_MIMO_DIS_MSK;
+		break;
+	case WLAN_HT_CAP_SM_PS_DYNAMIC:
+		*flags |= STA_FLG_RTS_MIMO_PROT_MSK;
+		break;
+	case WLAN_HT_CAP_SM_PS_DISABLED:
+		break;
+	default:
+		IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode);
+		break;
+	}
+
+	*flags |= cpu_to_le32(
+		(u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
+
+	*flags |= cpu_to_le32(
+		(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
+
+	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+		*flags |= STA_FLG_HT40_EN_MSK;
+}
+
+int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+		      struct ieee80211_sta *sta)
+{
+	u8 sta_id = iwl_sta_id(sta);
+	__le32 flags, mask;
+	struct iwl_addsta_cmd cmd;
+
+	if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
+		return -EINVAL;
+
+	iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
+
+	spin_lock_bh(&priv->sta_lock);
+	priv->stations[sta_id].sta.station_flags &= ~mask;
+	priv->stations[sta_id].sta.station_flags |= flags;
+	spin_unlock_bh(&priv->sta_lock);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.mode = STA_CONTROL_MODIFY_MSK;
+	cmd.station_flags_msk = mask;
+	cmd.station_flags = flags;
+	cmd.sta.sta_id = sta_id;
+
+	return iwl_send_add_sta(priv, &cmd, CMD_SYNC);
+}
+
+static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
+				   struct ieee80211_sta *sta,
+				   struct iwl_rxon_context *ctx)
+{
+	__le32 flags, mask;
+
+	iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
+
+	lockdep_assert_held(&priv->sta_lock);
+	priv->stations[index].sta.station_flags &= ~mask;
+	priv->stations[index].sta.station_flags |= flags;
+}
+
+/**
+ * iwl_prep_station - Prepare station information for addition
+ *
+ * should be called with sta_lock held
+ */
+u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+		    const u8 *addr, bool is_ap, struct ieee80211_sta *sta)
+{
+	struct iwl_station_entry *station;
+	int i;
+	u8 sta_id = IWL_INVALID_STATION;
+
+	if (is_ap)
+		sta_id = ctx->ap_sta_id;
+	else if (is_broadcast_ether_addr(addr))
+		sta_id = ctx->bcast_sta_id;
+	else
+		for (i = IWL_STA_ID; i < IWLAGN_STATION_COUNT; i++) {
+			if (ether_addr_equal(priv->stations[i].sta.sta.addr,
+					     addr)) {
+				sta_id = i;
+				break;
+			}
+
+			if (!priv->stations[i].used &&
+			    sta_id == IWL_INVALID_STATION)
+				sta_id = i;
+		}
+
+	/*
+	 * These two conditions have the same outcome, but keep them
+	 * separate
+	 */
+	if (unlikely(sta_id == IWL_INVALID_STATION))
+		return sta_id;
+
+	/*
+	 * uCode is not able to deal with multiple requests to add a
+	 * station. Keep track if one is in progress so that we do not send
+	 * another.
+	 */
+	if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
+		IWL_DEBUG_INFO(priv, "STA %d already in process of being "
+			       "added.\n", sta_id);
+		return sta_id;
+	}
+
+	if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
+	    (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) &&
+	    ether_addr_equal(priv->stations[sta_id].sta.sta.addr, addr)) {
+		IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not "
+				"adding again.\n", sta_id, addr);
+		return sta_id;
+	}
+
+	station = &priv->stations[sta_id];
+	station->used = IWL_STA_DRIVER_ACTIVE;
+	IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n",
+			sta_id, addr);
+	priv->num_stations++;
+
+	/* Set up the REPLY_ADD_STA command to send to device */
+	memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+	memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+	station->sta.mode = 0;
+	station->sta.sta.sta_id = sta_id;
+	station->sta.station_flags = ctx->station_flags;
+	station->ctxid = ctx->ctxid;
+
+	if (sta) {
+		struct iwl_station_priv *sta_priv;
+
+		sta_priv = (void *)sta->drv_priv;
+		sta_priv->ctx = ctx;
+	}
+
+	/*
+	 * OK to call unconditionally, since local stations (IBSS BSSID
+	 * STA and broadcast STA) pass in a NULL sta, and mac80211
+	 * doesn't allow HT IBSS.
+	 */
+	iwl_set_ht_add_station(priv, sta_id, sta, ctx);
+
+	return sta_id;
+
+}
+
+#define STA_WAIT_TIMEOUT (HZ/2)
+
+/**
+ * iwl_add_station_common -
+ */
+int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+			   const u8 *addr, bool is_ap,
+			   struct ieee80211_sta *sta, u8 *sta_id_r)
+{
+	int ret = 0;
+	u8 sta_id;
+	struct iwl_addsta_cmd sta_cmd;
+
+	*sta_id_r = 0;
+	spin_lock_bh(&priv->sta_lock);
+	sta_id = iwl_prep_station(priv, ctx, addr, is_ap, sta);
+	if (sta_id == IWL_INVALID_STATION) {
+		IWL_ERR(priv, "Unable to prepare station %pM for addition\n",
+			addr);
+		spin_unlock_bh(&priv->sta_lock);
+		return -EINVAL;
+	}
+
+	/*
+	 * uCode is not able to deal with multiple requests to add a
+	 * station. Keep track if one is in progress so that we do not send
+	 * another.
+	 */
+	if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
+		IWL_DEBUG_INFO(priv, "STA %d already in process of being "
+			       "added.\n", sta_id);
+		spin_unlock_bh(&priv->sta_lock);
+		return -EEXIST;
+	}
+
+	if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
+	    (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
+		IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not "
+				"adding again.\n", sta_id, addr);
+		spin_unlock_bh(&priv->sta_lock);
+		return -EEXIST;
+	}
+
+	priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta,
+	       sizeof(struct iwl_addsta_cmd));
+	spin_unlock_bh(&priv->sta_lock);
+
+	/* Add station to device's station table */
+	ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+	if (ret) {
+		spin_lock_bh(&priv->sta_lock);
+		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_bh(&priv->sta_lock);
+	}
+	*sta_id_r = sta_id;
+	return ret;
+}
+
+/**
+ * iwl_sta_ucode_deactivate - deactivate ucode status for a station
+ */
+static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
+{
+	lockdep_assert_held(&priv->sta_lock);
+
+	/* Ucode must be active and driver must be non active */
+	if ((priv->stations[sta_id].used &
+	     (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) !=
+	      IWL_STA_UCODE_ACTIVE)
+		IWL_ERR(priv, "removed non active STA %u\n", sta_id);
+
+	priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
+
+	memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry));
+	IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id);
+}
+
+static int iwl_send_remove_station(struct iwl_priv *priv,
+				   const u8 *addr, int sta_id,
+				   bool temporary)
+{
+	struct iwl_rx_packet *pkt;
+	int ret;
+	struct iwl_rem_sta_cmd rm_sta_cmd;
+
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_REMOVE_STA,
+		.len = { sizeof(struct iwl_rem_sta_cmd), },
+		.flags = CMD_SYNC,
+		.data = { &rm_sta_cmd, },
+	};
+
+	memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
+	rm_sta_cmd.num_sta = 1;
+	memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
+
+	cmd.flags |= CMD_WANT_SKB;
+
+	ret = iwl_dvm_send_cmd(priv, &cmd);
+
+	if (ret)
+		return ret;
+
+	pkt = cmd.resp_pkt;
+	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
+			  pkt->hdr.flags);
+		ret = -EIO;
+	}
+
+	if (!ret) {
+		struct iwl_rem_sta_resp *rem_sta_resp = (void *)pkt->data;
+		switch (rem_sta_resp->status) {
+		case REM_STA_SUCCESS_MSK:
+			if (!temporary) {
+				spin_lock_bh(&priv->sta_lock);
+				iwl_sta_ucode_deactivate(priv, sta_id);
+				spin_unlock_bh(&priv->sta_lock);
+			}
+			IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
+			break;
+		default:
+			ret = -EIO;
+			IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
+			break;
+		}
+	}
+	iwl_free_resp(&cmd);
+
+	return ret;
+}
+
+/**
+ * iwl_remove_station - Remove driver's knowledge of station.
+ */
+int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
+		       const u8 *addr)
+{
+	u8 tid;
+
+	if (!iwl_is_ready(priv)) {
+		IWL_DEBUG_INFO(priv,
+			"Unable to remove station %pM, device not ready.\n",
+			addr);
+		/*
+		 * It is typical for stations to be removed when we are
+		 * going down. Return success since device will be down
+		 * soon anyway
+		 */
+		return 0;
+	}
+
+	IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d  %pM\n",
+			sta_id, addr);
+
+	if (WARN_ON(sta_id == IWL_INVALID_STATION))
+		return -EINVAL;
+
+	spin_lock_bh(&priv->sta_lock);
+
+	if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
+		IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n",
+				addr);
+		goto out_err;
+	}
+
+	if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
+		IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n",
+				addr);
+		goto out_err;
+	}
+
+	if (priv->stations[sta_id].used & IWL_STA_LOCAL) {
+		kfree(priv->stations[sta_id].lq);
+		priv->stations[sta_id].lq = NULL;
+	}
+
+	for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
+		memset(&priv->tid_data[sta_id][tid], 0,
+			sizeof(priv->tid_data[sta_id][tid]));
+
+	priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+
+	priv->num_stations--;
+
+	if (WARN_ON(priv->num_stations < 0))
+		priv->num_stations = 0;
+
+	spin_unlock_bh(&priv->sta_lock);
+
+	return iwl_send_remove_station(priv, addr, sta_id, false);
+out_err:
+	spin_unlock_bh(&priv->sta_lock);
+	return -EINVAL;
+}
+
+void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
+			    const u8 *addr)
+{
+	u8 tid;
+
+	if (!iwl_is_ready(priv)) {
+		IWL_DEBUG_INFO(priv,
+			"Unable to remove station %pM, device not ready.\n",
+			addr);
+		return;
+	}
+
+	IWL_DEBUG_ASSOC(priv, "Deactivating STA: %pM (%d)\n", addr, sta_id);
+
+	if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
+		return;
+
+	spin_lock_bh(&priv->sta_lock);
+
+	WARN_ON_ONCE(!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE));
+
+	for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
+		memset(&priv->tid_data[sta_id][tid], 0,
+			sizeof(priv->tid_data[sta_id][tid]));
+
+	priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+
+	priv->num_stations--;
+
+	if (WARN_ON_ONCE(priv->num_stations < 0))
+		priv->num_stations = 0;
+
+	spin_unlock_bh(&priv->sta_lock);
+}
+
+static void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+			    u8 sta_id, struct iwl_link_quality_cmd *link_cmd)
+{
+	int i, r;
+	u32 rate_flags = 0;
+	__le32 rate_n_flags;
+
+	lockdep_assert_held(&priv->mutex);
+
+	memset(link_cmd, 0, sizeof(*link_cmd));
+
+	/* Set up the rate scaling to start at selected rate, fall back
+	 * all the way down to 1M in IEEE order, and then spin on 1M */
+	if (priv->band == IEEE80211_BAND_5GHZ)
+		r = IWL_RATE_6M_INDEX;
+	else if (ctx && ctx->vif && ctx->vif->p2p)
+		r = IWL_RATE_6M_INDEX;
+	else
+		r = IWL_RATE_1M_INDEX;
+
+	if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
+		rate_flags |= RATE_MCS_CCK_MSK;
+
+	rate_flags |= first_antenna(priv->eeprom_data->valid_tx_ant) <<
+				RATE_MCS_ANT_POS;
+	rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
+	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+		link_cmd->rs_table[i].rate_n_flags = rate_n_flags;
+
+	link_cmd->general_params.single_stream_ant_msk =
+			first_antenna(priv->eeprom_data->valid_tx_ant);
+
+	link_cmd->general_params.dual_stream_ant_msk =
+		priv->eeprom_data->valid_tx_ant &
+		~first_antenna(priv->eeprom_data->valid_tx_ant);
+	if (!link_cmd->general_params.dual_stream_ant_msk) {
+		link_cmd->general_params.dual_stream_ant_msk = ANT_AB;
+	} else if (num_of_ant(priv->eeprom_data->valid_tx_ant) == 2) {
+		link_cmd->general_params.dual_stream_ant_msk =
+			priv->eeprom_data->valid_tx_ant;
+	}
+
+	link_cmd->agg_params.agg_dis_start_th =
+		LINK_QUAL_AGG_DISABLE_START_DEF;
+	link_cmd->agg_params.agg_time_limit =
+		cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+
+	link_cmd->sta_id = sta_id;
+}
+
+/**
+ * iwl_clear_ucode_stations - clear ucode station table bits
+ *
+ * This function clears all the bits in the driver indicating
+ * which stations are active in the ucode. Call when something
+ * other than explicit station management would cause this in
+ * the ucode, e.g. unassociated RXON.
+ */
+void iwl_clear_ucode_stations(struct iwl_priv *priv,
+			      struct iwl_rxon_context *ctx)
+{
+	int i;
+	bool cleared = false;
+
+	IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n");
+
+	spin_lock_bh(&priv->sta_lock);
+	for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+		if (ctx && ctx->ctxid != priv->stations[i].ctxid)
+			continue;
+
+		if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
+			IWL_DEBUG_INFO(priv,
+				"Clearing ucode active for station %d\n", i);
+			priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
+			cleared = true;
+		}
+	}
+	spin_unlock_bh(&priv->sta_lock);
+
+	if (!cleared)
+		IWL_DEBUG_INFO(priv,
+			       "No active stations found to be cleared\n");
+}
+
+/**
+ * iwl_restore_stations() - Restore driver known stations to device
+ *
+ * All stations considered active by driver, but not present in ucode, is
+ * restored.
+ *
+ * Function sleeps.
+ */
+void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+	struct iwl_addsta_cmd sta_cmd;
+	struct iwl_link_quality_cmd lq;
+	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");
+		return;
+	}
+
+	IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n");
+	spin_lock_bh(&priv->sta_lock);
+	for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+		if (ctx->ctxid != priv->stations[i].ctxid)
+			continue;
+		if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) &&
+			    !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) {
+			IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n",
+					priv->stations[i].sta.sta.addr);
+			priv->stations[i].sta.mode = 0;
+			priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS;
+			found = true;
+		}
+	}
+
+	for (i = 0; i < IWLAGN_STATION_COUNT; 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) {
+				if (priv->wowlan)
+					iwl_sta_fill_lq(priv, ctx, i, &lq);
+				else
+					memcpy(&lq, priv->stations[i].lq,
+					       sizeof(struct iwl_link_quality_cmd));
+				send_lq = true;
+			}
+			spin_unlock_bh(&priv->sta_lock);
+			ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+			if (ret) {
+				spin_lock_bh(&priv->sta_lock);
+				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;
+				continue;
+			}
+			/*
+			 * Rate scaling has already been initialized, send
+			 * current LQ command
+			 */
+			if (send_lq)
+				iwl_send_lq_cmd(priv, ctx, &lq,
+						CMD_SYNC, true);
+			spin_lock_bh(&priv->sta_lock);
+			priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
+		}
+	}
+
+	spin_unlock_bh(&priv->sta_lock);
+	if (!found)
+		IWL_DEBUG_INFO(priv, "Restoring all known stations .... "
+			"no stations to be restored.\n");
+	else
+		IWL_DEBUG_INFO(priv, "Restoring all known stations .... "
+			"complete.\n");
+}
+
+int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
+{
+	int i;
+
+	for (i = 0; i < priv->sta_key_max_num; i++)
+		if (!test_and_set_bit(i, &priv->ucode_key_table))
+			return i;
+
+	return WEP_INVALID_OFFSET;
+}
+
+void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
+{
+	int i;
+
+	spin_lock_bh(&priv->sta_lock);
+	for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+		if (!(priv->stations[i].used & IWL_STA_BCAST))
+			continue;
+
+		priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
+		priv->num_stations--;
+		if (WARN_ON(priv->num_stations < 0))
+			priv->num_stations = 0;
+		kfree(priv->stations[i].lq);
+		priv->stations[i].lq = NULL;
+	}
+	spin_unlock_bh(&priv->sta_lock);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void iwl_dump_lq_cmd(struct iwl_priv *priv,
+			   struct iwl_link_quality_cmd *lq)
+{
+	int i;
+	IWL_DEBUG_RATE(priv, "lq station id 0x%x\n", lq->sta_id);
+	IWL_DEBUG_RATE(priv, "lq ant 0x%X 0x%X\n",
+		       lq->general_params.single_stream_ant_msk,
+		       lq->general_params.dual_stream_ant_msk);
+
+	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+		IWL_DEBUG_RATE(priv, "lq index %d 0x%X\n",
+			       i, lq->rs_table[i].rate_n_flags);
+}
+#else
+static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
+				   struct iwl_link_quality_cmd *lq)
+{
+}
+#endif
+
+/**
+ * is_lq_table_valid() - Test one aspect of LQ cmd for validity
+ *
+ * It sometimes happens when a HT rate has been in use and we
+ * loose connectivity with AP then mac80211 will first tell us that the
+ * current channel is not HT anymore before removing the station. In such a
+ * scenario the RXON flags will be updated to indicate we are not
+ * communicating HT anymore, but the LQ command may still contain HT rates.
+ * Test for this to prevent driver from sending LQ command between the time
+ * RXON flags are updated and when LQ command is updated.
+ */
+static bool is_lq_table_valid(struct iwl_priv *priv,
+			      struct iwl_rxon_context *ctx,
+			      struct iwl_link_quality_cmd *lq)
+{
+	int i;
+
+	if (ctx->ht.enabled)
+		return true;
+
+	IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
+		       ctx->active.channel);
+	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+		if (le32_to_cpu(lq->rs_table[i].rate_n_flags) &
+		    RATE_MCS_HT_MSK) {
+			IWL_DEBUG_INFO(priv,
+				       "index %d of LQ expects HT channel\n",
+				       i);
+			return false;
+		}
+	}
+	return true;
+}
+
+/**
+ * iwl_send_lq_cmd() - Send link quality command
+ * @init: This command is sent as part of station initialization right
+ *        after station has been added.
+ *
+ * The link quality command is sent as the last step of station creation.
+ * This is the special case in which init is set and we call a callback in
+ * this case to clear the state indicating that station creation is in
+ * progress.
+ */
+int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+		    struct iwl_link_quality_cmd *lq, u8 flags, bool init)
+{
+	int ret = 0;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_TX_LINK_QUALITY_CMD,
+		.len = { sizeof(struct iwl_link_quality_cmd), },
+		.flags = flags,
+		.data = { lq, },
+	};
+
+	if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
+		return -EINVAL;
+
+
+	spin_lock_bh(&priv->sta_lock);
+	if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
+		spin_unlock_bh(&priv->sta_lock);
+		return -EINVAL;
+	}
+	spin_unlock_bh(&priv->sta_lock);
+
+	iwl_dump_lq_cmd(priv, lq);
+	if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
+		return -EINVAL;
+
+	if (is_lq_table_valid(priv, ctx, lq))
+		ret = iwl_dvm_send_cmd(priv, &cmd);
+	else
+		ret = -EINVAL;
+
+	if (cmd.flags & CMD_ASYNC)
+		return ret;
+
+	if (init) {
+		IWL_DEBUG_INFO(priv, "init LQ command complete, "
+			       "clearing sta addition status for sta %d\n",
+			       lq->sta_id);
+		spin_lock_bh(&priv->sta_lock);
+		priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
+		spin_unlock_bh(&priv->sta_lock);
+	}
+	return ret;
+}
+
+
+static struct iwl_link_quality_cmd *
+iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+		 u8 sta_id)
+{
+	struct iwl_link_quality_cmd *link_cmd;
+
+	link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL);
+	if (!link_cmd) {
+		IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n");
+		return NULL;
+	}
+
+	iwl_sta_fill_lq(priv, ctx, sta_id, link_cmd);
+
+	return link_cmd;
+}
+
+/*
+ * iwlagn_add_bssid_station - Add the special IBSS BSSID station
+ *
+ * Function sleeps.
+ */
+int iwlagn_add_bssid_station(struct iwl_priv *priv,
+			     struct iwl_rxon_context *ctx,
+			     const u8 *addr, u8 *sta_id_r)
+{
+	int ret;
+	u8 sta_id;
+	struct iwl_link_quality_cmd *link_cmd;
+
+	if (sta_id_r)
+		*sta_id_r = IWL_INVALID_STATION;
+
+	ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id);
+	if (ret) {
+		IWL_ERR(priv, "Unable to add station %pM\n", addr);
+		return ret;
+	}
+
+	if (sta_id_r)
+		*sta_id_r = sta_id;
+
+	spin_lock_bh(&priv->sta_lock);
+	priv->stations[sta_id].used |= IWL_STA_LOCAL;
+	spin_unlock_bh(&priv->sta_lock);
+
+	/* Set up default rate scaling table in device's station table */
+	link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
+	if (!link_cmd) {
+		IWL_ERR(priv,
+			"Unable to initialize rate scaling for station %pM.\n",
+			addr);
+		return -ENOMEM;
+	}
+
+	ret = iwl_send_lq_cmd(priv, ctx, link_cmd, CMD_SYNC, true);
+	if (ret)
+		IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
+
+	spin_lock_bh(&priv->sta_lock);
+	priv->stations[sta_id].lq = link_cmd;
+	spin_unlock_bh(&priv->sta_lock);
+
+	return 0;
+}
+
+/*
+ * static WEP keys
+ *
+ * For each context, the device has a table of 4 static WEP keys
+ * (one for each key index) that is updated with the following
+ * commands.
+ */
+
+static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
+				      struct iwl_rxon_context *ctx,
+				      bool send_if_empty)
+{
+	int i, not_empty = 0;
+	u8 buff[sizeof(struct iwl_wep_cmd) +
+		sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
+	struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
+	size_t cmd_size  = sizeof(struct iwl_wep_cmd);
+	struct iwl_host_cmd cmd = {
+		.id = ctx->wep_key_cmd,
+		.data = { wep_cmd, },
+		.flags = CMD_SYNC,
+	};
+
+	might_sleep();
+
+	memset(wep_cmd, 0, cmd_size +
+			(sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
+
+	for (i = 0; i < WEP_KEYS_MAX ; i++) {
+		wep_cmd->key[i].key_index = i;
+		if (ctx->wep_keys[i].key_size) {
+			wep_cmd->key[i].key_offset = i;
+			not_empty = 1;
+		} else {
+			wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
+		}
+
+		wep_cmd->key[i].key_size = ctx->wep_keys[i].key_size;
+		memcpy(&wep_cmd->key[i].key[3], ctx->wep_keys[i].key,
+				ctx->wep_keys[i].key_size);
+	}
+
+	wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
+	wep_cmd->num_keys = WEP_KEYS_MAX;
+
+	cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
+
+	cmd.len[0] = cmd_size;
+
+	if (not_empty || send_if_empty)
+		return iwl_dvm_send_cmd(priv, &cmd);
+	else
+		return 0;
+}
+
+int iwl_restore_default_wep_keys(struct iwl_priv *priv,
+				 struct iwl_rxon_context *ctx)
+{
+	lockdep_assert_held(&priv->mutex);
+
+	return iwl_send_static_wepkey_cmd(priv, ctx, false);
+}
+
+int iwl_remove_default_wep_key(struct iwl_priv *priv,
+			       struct iwl_rxon_context *ctx,
+			       struct ieee80211_key_conf *keyconf)
+{
+	int ret;
+
+	lockdep_assert_held(&priv->mutex);
+
+	IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
+		      keyconf->keyidx);
+
+	memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0]));
+	if (iwl_is_rfkill(priv)) {
+		IWL_DEBUG_WEP(priv,
+			"Not sending REPLY_WEPKEY command due to RFKILL.\n");
+		/* but keys in device are clear anyway so return success */
+		return 0;
+	}
+	ret = iwl_send_static_wepkey_cmd(priv, ctx, 1);
+	IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
+		      keyconf->keyidx, ret);
+
+	return ret;
+}
+
+int iwl_set_default_wep_key(struct iwl_priv *priv,
+			    struct iwl_rxon_context *ctx,
+			    struct ieee80211_key_conf *keyconf)
+{
+	int ret;
+
+	lockdep_assert_held(&priv->mutex);
+
+	if (keyconf->keylen != WEP_KEY_LEN_128 &&
+	    keyconf->keylen != WEP_KEY_LEN_64) {
+		IWL_DEBUG_WEP(priv,
+			      "Bad WEP key length %d\n", keyconf->keylen);
+		return -EINVAL;
+	}
+
+	keyconf->hw_key_idx = IWLAGN_HW_KEY_DEFAULT;
+
+	ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
+	memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key,
+							keyconf->keylen);
+
+	ret = iwl_send_static_wepkey_cmd(priv, ctx, false);
+	IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
+		keyconf->keylen, keyconf->keyidx, ret);
+
+	return ret;
+}
+
+/*
+ * dynamic (per-station) keys
+ *
+ * The dynamic keys are a little more complicated. The device has
+ * a key cache of up to STA_KEY_MAX_NUM/STA_KEY_MAX_NUM_PAN keys.
+ * These are linked to stations by a table that contains an index
+ * into the key table for each station/key index/{mcast,unicast},
+ * i.e. it's basically an array of pointers like this:
+ *	key_offset_t key_mapping[NUM_STATIONS][4][2];
+ * (it really works differently, but you can think of it as such)
+ *
+ * The key uploading and linking happens in the same command, the
+ * add station command with STA_MODIFY_KEY_MASK.
+ */
+
+static u8 iwlagn_key_sta_id(struct iwl_priv *priv,
+			    struct ieee80211_vif *vif,
+			    struct ieee80211_sta *sta)
+{
+	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
+	if (sta)
+		return iwl_sta_id(sta);
+
+	/*
+	 * The device expects GTKs for station interfaces to be
+	 * installed as GTKs for the AP station. If we have no
+	 * station ID, then use the ap_sta_id in that case.
+	 */
+	if (vif->type == NL80211_IFTYPE_STATION && vif_priv->ctx)
+		return vif_priv->ctx->ap_sta_id;
+
+	return IWL_INVALID_STATION;
+}
+
+static int iwlagn_send_sta_key(struct iwl_priv *priv,
+			       struct ieee80211_key_conf *keyconf,
+			       u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k,
+			       u32 cmd_flags)
+{
+	__le16 key_flags;
+	struct iwl_addsta_cmd sta_cmd;
+	int i;
+
+	spin_lock_bh(&priv->sta_lock);
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
+	spin_unlock_bh(&priv->sta_lock);
+
+	key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+	key_flags |= STA_KEY_FLG_MAP_KEY_MSK;
+
+	switch (keyconf->cipher) {
+	case WLAN_CIPHER_SUITE_CCMP:
+		key_flags |= STA_KEY_FLG_CCMP;
+		memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen);
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+		key_flags |= STA_KEY_FLG_TKIP;
+		sta_cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;
+		for (i = 0; i < 5; i++)
+			sta_cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]);
+		memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen);
+		break;
+	case WLAN_CIPHER_SUITE_WEP104:
+		key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
+		/* fall through */
+	case WLAN_CIPHER_SUITE_WEP40:
+		key_flags |= STA_KEY_FLG_WEP;
+		memcpy(&sta_cmd.key.key[3], keyconf->key, keyconf->keylen);
+		break;
+	default:
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+		key_flags |= STA_KEY_MULTICAST_MSK;
+
+	/* key pointer (offset) */
+	sta_cmd.key.key_offset = keyconf->hw_key_idx;
+
+	sta_cmd.key.key_flags = key_flags;
+	sta_cmd.mode = STA_CONTROL_MODIFY_MSK;
+	sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK;
+
+	return iwl_send_add_sta(priv, &sta_cmd, cmd_flags);
+}
+
+void iwl_update_tkip_key(struct iwl_priv *priv,
+			 struct ieee80211_vif *vif,
+			 struct ieee80211_key_conf *keyconf,
+			 struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
+{
+	u8 sta_id = iwlagn_key_sta_id(priv, vif, sta);
+
+	if (sta_id == IWL_INVALID_STATION)
+		return;
+
+	if (iwl_scan_cancel(priv)) {
+		/* cancel scan failed, just live w/ bad key and rely
+		   briefly on SW decryption */
+		return;
+	}
+
+	iwlagn_send_sta_key(priv, keyconf, sta_id,
+			    iv32, phase1key, CMD_ASYNC);
+}
+
+int iwl_remove_dynamic_key(struct iwl_priv *priv,
+			   struct iwl_rxon_context *ctx,
+			   struct ieee80211_key_conf *keyconf,
+			   struct ieee80211_sta *sta)
+{
+	struct iwl_addsta_cmd sta_cmd;
+	u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta);
+	__le16 key_flags;
+
+	/* if station isn't there, neither is the key */
+	if (sta_id == IWL_INVALID_STATION)
+		return -ENOENT;
+
+	spin_lock_bh(&priv->sta_lock);
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
+	if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE))
+		sta_id = IWL_INVALID_STATION;
+	spin_unlock_bh(&priv->sta_lock);
+
+	if (sta_id == IWL_INVALID_STATION)
+		return 0;
+
+	lockdep_assert_held(&priv->mutex);
+
+	ctx->key_mapping_keys--;
+
+	IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n",
+		      keyconf->keyidx, sta_id);
+
+	if (!test_and_clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table))
+		IWL_ERR(priv, "offset %d not used in uCode key table.\n",
+			keyconf->hw_key_idx);
+
+	key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+	key_flags |= STA_KEY_FLG_MAP_KEY_MSK | STA_KEY_FLG_NO_ENC |
+		     STA_KEY_FLG_INVALID;
+
+	if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+		key_flags |= STA_KEY_MULTICAST_MSK;
+
+	sta_cmd.key.key_flags = key_flags;
+	sta_cmd.key.key_offset = keyconf->hw_key_idx;
+	sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK;
+	sta_cmd.mode = STA_CONTROL_MODIFY_MSK;
+
+	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+int iwl_set_dynamic_key(struct iwl_priv *priv,
+			struct iwl_rxon_context *ctx,
+			struct ieee80211_key_conf *keyconf,
+			struct ieee80211_sta *sta)
+{
+	struct ieee80211_key_seq seq;
+	u16 p1k[5];
+	int ret;
+	u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta);
+	const u8 *addr;
+
+	if (sta_id == IWL_INVALID_STATION)
+		return -EINVAL;
+
+	lockdep_assert_held(&priv->mutex);
+
+	keyconf->hw_key_idx = iwl_get_free_ucode_key_offset(priv);
+	if (keyconf->hw_key_idx == WEP_INVALID_OFFSET)
+		return -ENOSPC;
+
+	ctx->key_mapping_keys++;
+
+	switch (keyconf->cipher) {
+	case WLAN_CIPHER_SUITE_TKIP:
+		if (sta)
+			addr = sta->addr;
+		else /* station mode case only */
+			addr = ctx->active.bssid_addr;
+
+		/* pre-fill phase 1 key into device cache */
+		ieee80211_get_key_rx_seq(keyconf, 0, &seq);
+		ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
+		ret = iwlagn_send_sta_key(priv, keyconf, sta_id,
+					  seq.tkip.iv32, p1k, CMD_SYNC);
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+		ret = iwlagn_send_sta_key(priv, keyconf, sta_id,
+					  0, NULL, CMD_SYNC);
+		break;
+	default:
+		IWL_ERR(priv, "Unknown cipher %x\n", keyconf->cipher);
+		ret = -EINVAL;
+	}
+
+	if (ret) {
+		ctx->key_mapping_keys--;
+		clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table);
+	}
+
+	IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
+		      keyconf->cipher, keyconf->keylen, keyconf->keyidx,
+		      sta ? sta->addr : NULL, ret);
+
+	return ret;
+}
+
+/**
+ * iwlagn_alloc_bcast_station - add broadcast station into driver's station table.
+ *
+ * This adds the broadcast station into the driver's station table
+ * and marks it driver active, so that it will be restored to the
+ * device at the next best time.
+ */
+int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
+			       struct iwl_rxon_context *ctx)
+{
+	struct iwl_link_quality_cmd *link_cmd;
+	u8 sta_id;
+
+	spin_lock_bh(&priv->sta_lock);
+	sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL);
+	if (sta_id == IWL_INVALID_STATION) {
+		IWL_ERR(priv, "Unable to prepare broadcast station\n");
+		spin_unlock_bh(&priv->sta_lock);
+
+		return -EINVAL;
+	}
+
+	priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
+	priv->stations[sta_id].used |= IWL_STA_BCAST;
+	spin_unlock_bh(&priv->sta_lock);
+
+	link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
+	if (!link_cmd) {
+		IWL_ERR(priv,
+			"Unable to initialize rate scaling for bcast station.\n");
+		return -ENOMEM;
+	}
+
+	spin_lock_bh(&priv->sta_lock);
+	priv->stations[sta_id].lq = link_cmd;
+	spin_unlock_bh(&priv->sta_lock);
+
+	return 0;
+}
+
+/**
+ * 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,
+			     struct iwl_rxon_context *ctx)
+{
+	struct iwl_link_quality_cmd *link_cmd;
+	u8 sta_id = ctx->bcast_sta_id;
+
+	link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
+	if (!link_cmd) {
+		IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n");
+		return -ENOMEM;
+	}
+
+	spin_lock_bh(&priv->sta_lock);
+	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_bh(&priv->sta_lock);
+
+	return 0;
+}
+
+int iwl_update_bcast_stations(struct iwl_priv *priv)
+{
+	struct iwl_rxon_context *ctx;
+	int ret = 0;
+
+	for_each_context(priv, ctx) {
+		ret = iwl_update_bcast_station(priv, ctx);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+/**
+ * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
+ */
+int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
+{
+	struct iwl_addsta_cmd sta_cmd;
+
+	lockdep_assert_held(&priv->mutex);
+
+	/* Remove "disable" flag, to enable Tx for this TID */
+	spin_lock_bh(&priv->sta_lock);
+	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_bh(&priv->sta_lock);
+
+	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
+			 int tid, u16 ssn)
+{
+	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)
+		return -ENXIO;
+
+	spin_lock_bh(&priv->sta_lock);
+	priv->stations[sta_id].sta.station_flags_msk = 0;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
+	priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
+	priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
+	spin_unlock_bh(&priv->sta_lock);
+
+	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
+			int tid)
+{
+	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) {
+		IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
+		return -ENXIO;
+	}
+
+	spin_lock_bh(&priv->sta_lock);
+	priv->stations[sta_id].sta.station_flags_msk = 0;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
+	priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
+	spin_unlock_bh(&priv->sta_lock);
+
+	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+
+
+void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
+{
+	struct iwl_addsta_cmd cmd = {
+		.mode = STA_CONTROL_MODIFY_MSK,
+		.station_flags = STA_FLG_PWR_SAVE_MSK,
+		.station_flags_msk = STA_FLG_PWR_SAVE_MSK,
+		.sta.sta_id = sta_id,
+		.sta.modify_mask = STA_MODIFY_SLEEP_TX_COUNT_MSK,
+		.sleep_tx_count = cpu_to_le16(cnt),
+	};
+
+	iwl_send_add_sta(priv, &cmd, CMD_ASYNC);
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/testmode.c b/drivers/net/wireless/iwlwifi/dvm/testmode.c
new file mode 100644
index 0000000..57b918c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/testmode.c
@@ -0,0 +1,471 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2010 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <net/net_namespace.h>
+#include <linux/netdevice.h>
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include <net/netlink.h>
+
+#include "iwl-debug.h"
+#include "iwl-trans.h"
+#include "dev.h"
+#include "agn.h"
+#include "iwl-test.h"
+#include "iwl-testmode.h"
+
+static int iwl_testmode_send_cmd(struct iwl_op_mode *op_mode,
+				 struct iwl_host_cmd *cmd)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+	return iwl_dvm_send_cmd(priv, cmd);
+}
+
+static bool iwl_testmode_valid_hw_addr(u32 addr)
+{
+	if (iwlagn_hw_valid_rtc_data_addr(addr))
+		return true;
+
+	if (IWLAGN_RTC_INST_LOWER_BOUND <= addr &&
+	    addr < IWLAGN_RTC_INST_UPPER_BOUND)
+		return true;
+
+	return false;
+}
+
+static u32 iwl_testmode_get_fw_ver(struct iwl_op_mode *op_mode)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+	return priv->fw->ucode_ver;
+}
+
+static struct sk_buff*
+iwl_testmode_alloc_reply(struct iwl_op_mode *op_mode, int len)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+	return cfg80211_testmode_alloc_reply_skb(priv->hw->wiphy, len);
+}
+
+static int iwl_testmode_reply(struct iwl_op_mode *op_mode, struct sk_buff *skb)
+{
+	return cfg80211_testmode_reply(skb);
+}
+
+static struct sk_buff *iwl_testmode_alloc_event(struct iwl_op_mode *op_mode,
+						int len)
+{
+	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+	return cfg80211_testmode_alloc_event_skb(priv->hw->wiphy, len,
+						 GFP_ATOMIC);
+}
+
+static void iwl_testmode_event(struct iwl_op_mode *op_mode, struct sk_buff *skb)
+{
+	return cfg80211_testmode_event(skb, GFP_ATOMIC);
+}
+
+static struct iwl_test_ops tst_ops = {
+	.send_cmd = iwl_testmode_send_cmd,
+	.valid_hw_addr = iwl_testmode_valid_hw_addr,
+	.get_fw_ver = iwl_testmode_get_fw_ver,
+	.alloc_reply = iwl_testmode_alloc_reply,
+	.reply = iwl_testmode_reply,
+	.alloc_event = iwl_testmode_alloc_event,
+	.event = iwl_testmode_event,
+};
+
+void iwl_testmode_init(struct iwl_priv *priv)
+{
+	iwl_test_init(&priv->tst, priv->trans, &tst_ops);
+}
+
+void iwl_testmode_free(struct iwl_priv *priv)
+{
+	iwl_test_free(&priv->tst);
+}
+
+static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
+{
+	struct iwl_notification_wait calib_wait;
+	static const u8 calib_complete[] = {
+		CALIBRATION_COMPLETE_NOTIFICATION
+	};
+	int ret;
+
+	iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
+				   calib_complete, ARRAY_SIZE(calib_complete),
+				   NULL, NULL);
+	ret = iwl_init_alive_start(priv);
+	if (ret) {
+		IWL_ERR(priv, "Fail init calibration: %d\n", ret);
+		goto cfg_init_calib_error;
+	}
+
+	ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, 2 * HZ);
+	if (ret)
+		IWL_ERR(priv, "Error detecting"
+			" CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
+	return ret;
+
+cfg_init_calib_error:
+	iwl_remove_notification(&priv->notif_wait, &calib_wait);
+	return ret;
+}
+
+/*
+ * This function handles the user application commands for driver.
+ *
+ * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
+ * handlers respectively.
+ *
+ * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
+ * value of the actual command execution is replied to the user application.
+ *
+ * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
+ * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
+ * IWL_TM_CMD_DEV2APP_SYNC_RSP.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	struct iwl_trans *trans = priv->trans;
+	struct sk_buff *skb;
+	unsigned char *rsp_data_ptr = NULL;
+	int status = 0, rsp_data_len = 0;
+	u32 inst_size = 0, data_size = 0;
+	const struct fw_img *img;
+
+	switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+	case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
+		rsp_data_ptr = (unsigned char *)priv->cfg->name;
+		rsp_data_len = strlen(priv->cfg->name);
+		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+							rsp_data_len + 20);
+		if (!skb) {
+			IWL_ERR(priv, "Memory allocation fail\n");
+			return -ENOMEM;
+		}
+		if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
+				IWL_TM_CMD_DEV2APP_SYNC_RSP) ||
+		    nla_put(skb, IWL_TM_ATTR_SYNC_RSP,
+			    rsp_data_len, rsp_data_ptr))
+			goto nla_put_failure;
+		status = cfg80211_testmode_reply(skb);
+		if (status < 0)
+			IWL_ERR(priv, "Error sending msg : %d\n", status);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
+		status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
+		if (status)
+			IWL_ERR(priv, "Error loading init ucode: %d\n", status);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
+		iwl_testmode_cfg_init_calib(priv);
+		priv->ucode_loaded = false;
+		iwl_trans_stop_device(trans);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
+		status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
+		if (status) {
+			IWL_ERR(priv,
+				"Error loading runtime ucode: %d\n", status);
+			break;
+		}
+		status = iwl_alive_start(priv);
+		if (status)
+			IWL_ERR(priv,
+				"Error starting the device: %d\n", status);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
+		iwl_scan_cancel_timeout(priv, 200);
+		priv->ucode_loaded = false;
+		iwl_trans_stop_device(trans);
+		status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
+		if (status) {
+			IWL_ERR(priv,
+				"Error loading WOWLAN ucode: %d\n", status);
+			break;
+		}
+		status = iwl_alive_start(priv);
+		if (status)
+			IWL_ERR(priv,
+				"Error starting the device: %d\n", status);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_GET_EEPROM:
+		if (priv->eeprom_blob) {
+			skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+				priv->eeprom_blob_size + 20);
+			if (!skb) {
+				IWL_ERR(priv, "Memory allocation fail\n");
+				return -ENOMEM;
+			}
+			if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
+					IWL_TM_CMD_DEV2APP_EEPROM_RSP) ||
+			    nla_put(skb, IWL_TM_ATTR_EEPROM,
+				    priv->eeprom_blob_size,
+				    priv->eeprom_blob))
+				goto nla_put_failure;
+			status = cfg80211_testmode_reply(skb);
+			if (status < 0)
+				IWL_ERR(priv, "Error sending msg : %d\n",
+					status);
+		} else
+			return -ENODATA;
+		break;
+
+	case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
+		if (!tb[IWL_TM_ATTR_FIXRATE]) {
+			IWL_ERR(priv, "Missing fixrate setting\n");
+			return -ENOMSG;
+		}
+		priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
+		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8);
+		if (!skb) {
+			IWL_ERR(priv, "Memory allocation fail\n");
+			return -ENOMEM;
+		}
+		if (!priv->ucode_loaded) {
+			IWL_ERR(priv, "No uCode has not been loaded\n");
+			return -EINVAL;
+		} else {
+			img = &priv->fw->img[priv->cur_ucode];
+			inst_size = img->sec[IWL_UCODE_SECTION_INST].len;
+			data_size = img->sec[IWL_UCODE_SECTION_DATA].len;
+		}
+		if (nla_put_u32(skb, IWL_TM_ATTR_FW_TYPE, priv->cur_ucode) ||
+		    nla_put_u32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size) ||
+		    nla_put_u32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size))
+			goto nla_put_failure;
+		status = cfg80211_testmode_reply(skb);
+		if (status < 0)
+			IWL_ERR(priv, "Error sending msg : %d\n", status);
+		break;
+
+	default:
+		IWL_ERR(priv, "Unknown testmode driver command ID\n");
+		return -ENOSYS;
+	}
+	return status;
+
+nla_put_failure:
+	kfree_skb(skb);
+	return -EMSGSIZE;
+}
+
+/*
+ * This function handles the user application switch ucode ownership.
+ *
+ * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_OWNER and
+ * decide who the current owner of the uCode
+ *
+ * If the current owner is OWNERSHIP_TM, then the only host command
+ * can deliver to uCode is from testmode, all the other host commands
+ * will dropped.
+ *
+ * default driver is the owner of uCode in normal operational mode
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	u8 owner;
+
+	if (!tb[IWL_TM_ATTR_UCODE_OWNER]) {
+		IWL_ERR(priv, "Missing ucode owner\n");
+		return -ENOMSG;
+	}
+
+	owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
+	if (owner == IWL_OWNERSHIP_DRIVER) {
+		priv->ucode_owner = owner;
+		iwl_test_enable_notifications(&priv->tst, false);
+	} else if (owner == IWL_OWNERSHIP_TM) {
+		priv->ucode_owner = owner;
+		iwl_test_enable_notifications(&priv->tst, true);
+	} else {
+		IWL_ERR(priv, "Invalid owner\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* The testmode gnl message handler that takes the gnl message from the
+ * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
+ * invoke the corresponding handlers.
+ *
+ * This function is invoked when there is user space application sending
+ * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated
+ * by nl80211.
+ *
+ * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before
+ * dispatching it to the corresponding handler.
+ *
+ * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application;
+ * -ENOSYS is replied to the user application if the command is unknown;
+ * Otherwise, the command is dispatched to the respective handler.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @data: pointer to user space message
+ * @len: length in byte of @data
+ */
+int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
+{
+	struct nlattr *tb[IWL_TM_ATTR_MAX];
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	int result;
+
+	result = iwl_test_parse(&priv->tst, tb, data, len);
+	if (result)
+		return result;
+
+	/* in case multiple accesses to the device happens */
+	mutex_lock(&priv->mutex);
+	switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+	case IWL_TM_CMD_APP2DEV_UCODE:
+	case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
+	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
+	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
+	case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
+	case IWL_TM_CMD_APP2DEV_END_TRACE:
+	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ:
+	case IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
+	case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
+	case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
+	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE:
+		result = iwl_test_handle_cmd(&priv->tst, tb);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
+	case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
+	case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
+	case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
+	case IWL_TM_CMD_APP2DEV_GET_EEPROM:
+	case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
+	case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
+	case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
+		IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
+		result = iwl_testmode_driver(hw, tb);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_OWNERSHIP:
+		IWL_DEBUG_INFO(priv, "testmode change uCode ownership\n");
+		result = iwl_testmode_ownership(hw, tb);
+		break;
+
+	default:
+		IWL_ERR(priv, "Unknown testmode command\n");
+		result = -ENOSYS;
+		break;
+	}
+	mutex_unlock(&priv->mutex);
+
+	if (result)
+		IWL_ERR(priv, "Test cmd failed result=%d\n", result);
+	return result;
+}
+
+int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
+		      struct netlink_callback *cb,
+		      void *data, int len)
+{
+	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+	int result;
+	u32 cmd;
+
+	if (cb->args[3]) {
+		/* offset by 1 since commands start at 0 */
+		cmd = cb->args[3] - 1;
+	} else {
+		struct nlattr *tb[IWL_TM_ATTR_MAX];
+
+		result = iwl_test_parse(&priv->tst, tb, data, len);
+		if (result)
+			return result;
+
+		cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
+		cb->args[3] = cmd + 1;
+	}
+
+	/* in case multiple accesses to the device happens */
+	mutex_lock(&priv->mutex);
+	result = iwl_test_dump(&priv->tst, cmd, skb, cb);
+	mutex_unlock(&priv->mutex);
+	return result;
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c
new file mode 100644
index 0000000..eb86443
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/tt.c
@@ -0,0 +1,693 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <net/mac80211.h>
+#include "iwl-io.h"
+#include "iwl-modparams.h"
+#include "iwl-debug.h"
+#include "agn.h"
+#include "dev.h"
+#include "commands.h"
+#include "tt.h"
+
+/* default Thermal Throttling transaction table
+ * Current state   |         Throttling Down               |  Throttling Up
+ *=============================================================================
+ *                 Condition Nxt State  Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
+ *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
+ *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
+ *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
+ *=============================================================================
+ */
+static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
+	{IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
+	{IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
+	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
+	{IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
+	{IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
+	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
+	{IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
+	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
+	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
+	{IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
+	{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
+	{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+
+/* Advance Thermal Throttling default restriction table */
+static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
+	{IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
+	{IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
+	{IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
+	{IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
+};
+
+bool iwl_tt_is_low_power_state(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+	if (tt->state >= IWL_TI_1)
+		return true;
+	return false;
+}
+
+u8 iwl_tt_current_power_mode(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+	return tt->tt_power_mode;
+}
+
+bool iwl_ht_enabled(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+	struct iwl_tt_restriction *restriction;
+
+	if (!priv->thermal_throttle.advanced_tt)
+		return true;
+	restriction = tt->restriction + tt->state;
+	return restriction->is_ht;
+}
+
+static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
+{
+	s32 temp = priv->temperature; /* degrees CELSIUS except specified */
+	bool within_margin = false;
+
+	if (!priv->thermal_throttle.advanced_tt)
+		within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
+				CT_KILL_THRESHOLD_LEGACY) ? true : false;
+	else
+		within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
+				CT_KILL_THRESHOLD) ? true : false;
+	return within_margin;
+}
+
+bool iwl_check_for_ct_kill(struct iwl_priv *priv)
+{
+	bool is_ct_kill = false;
+
+	if (iwl_within_ct_kill_margin(priv)) {
+		iwl_tt_enter_ct_kill(priv);
+		is_ct_kill = true;
+	}
+	return is_ct_kill;
+}
+
+enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+	struct iwl_tt_restriction *restriction;
+
+	if (!priv->thermal_throttle.advanced_tt)
+		return IWL_ANT_OK_MULTI;
+	restriction = tt->restriction + tt->state;
+	return restriction->tx_stream;
+}
+
+enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+	struct iwl_tt_restriction *restriction;
+
+	if (!priv->thermal_throttle.advanced_tt)
+		return IWL_ANT_OK_MULTI;
+	restriction = tt->restriction + tt->state;
+	return restriction->rx_stream;
+}
+
+#define CT_KILL_EXIT_DURATION (5)	/* 5 seconds duration */
+#define CT_KILL_WAITING_DURATION (300)	/* 300ms duration */
+
+/*
+ * toggle the bit to wake up uCode and check the temperature
+ * if the temperature is below CT, uCode will stay awake and send card
+ * state notification with CT_KILL bit clear to inform Thermal Throttling
+ * Management to change state. Otherwise, uCode will go back to sleep
+ * without doing anything, driver should continue the 5 seconds timer
+ * to wake up uCode for temperature check until temperature drop below CT
+ */
+static void iwl_tt_check_exit_ct_kill(unsigned long data)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)data;
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+	unsigned long flags;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (tt->state == IWL_TI_CT_KILL) {
+		if (priv->thermal_throttle.ct_kill_toggle) {
+			iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
+				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+			priv->thermal_throttle.ct_kill_toggle = false;
+		} else {
+			iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
+				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+			priv->thermal_throttle.ct_kill_toggle = true;
+		}
+		iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
+		spin_lock_irqsave(&priv->trans->reg_lock, flags);
+		if (likely(iwl_grab_nic_access(priv->trans)))
+			iwl_release_nic_access(priv->trans);
+		spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
+
+		/* Reschedule the ct_kill timer to occur in
+		 * CT_KILL_EXIT_DURATION seconds to ensure we get a
+		 * thermal update */
+		IWL_DEBUG_TEMP(priv, "schedule ct_kill exit timer\n");
+		mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
+			  jiffies + CT_KILL_EXIT_DURATION * HZ);
+	}
+}
+
+static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
+			   bool stop)
+{
+	if (stop) {
+		IWL_DEBUG_TEMP(priv, "Stop all queues\n");
+		if (priv->mac80211_registered)
+			ieee80211_stop_queues(priv->hw);
+		IWL_DEBUG_TEMP(priv,
+				"Schedule 5 seconds CT_KILL Timer\n");
+		mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
+			  jiffies + CT_KILL_EXIT_DURATION * HZ);
+	} else {
+		IWL_DEBUG_TEMP(priv, "Wake all queues\n");
+		if (priv->mac80211_registered)
+			ieee80211_wake_queues(priv->hw);
+	}
+}
+
+static void iwl_tt_ready_for_ct_kill(unsigned long data)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)data;
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	/* temperature timer expired, ready to go into CT_KILL state */
+	if (tt->state != IWL_TI_CT_KILL) {
+		IWL_DEBUG_TEMP(priv, "entering CT_KILL state when "
+				"temperature timer expired\n");
+		tt->state = IWL_TI_CT_KILL;
+		set_bit(STATUS_CT_KILL, &priv->status);
+		iwl_perform_ct_kill_task(priv, true);
+	}
+}
+
+static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
+{
+	IWL_DEBUG_TEMP(priv, "Prepare to enter IWL_TI_CT_KILL\n");
+	/* make request to retrieve statistics information */
+	iwl_send_statistics_request(priv, CMD_SYNC, false);
+	/* Reschedule the ct_kill wait timer */
+	mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
+		 jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
+}
+
+#define IWL_MINIMAL_POWER_THRESHOLD		(CT_KILL_THRESHOLD_LEGACY)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2	(100)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1	(90)
+
+/*
+ * Legacy thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ *	Chip will identify dangerously high temperatures that can
+ *	harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ *	Throttle early enough to lower the power consumption before
+ *	drastic steps are needed
+ */
+static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
+{
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+	enum iwl_tt_state old_state;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if ((tt->tt_previous_temp) &&
+	    (temp > tt->tt_previous_temp) &&
+	    ((temp - tt->tt_previous_temp) >
+	    IWL_TT_INCREASE_MARGIN)) {
+		IWL_DEBUG_TEMP(priv,
+			"Temperature increase %d degree Celsius\n",
+			(temp - tt->tt_previous_temp));
+	}
+#endif
+	old_state = tt->state;
+	/* in Celsius */
+	if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
+		tt->state = IWL_TI_CT_KILL;
+	else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
+		tt->state = IWL_TI_2;
+	else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
+		tt->state = IWL_TI_1;
+	else
+		tt->state = IWL_TI_0;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	tt->tt_previous_temp = temp;
+#endif
+	/* stop ct_kill_waiting_tm timer */
+	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
+	if (tt->state != old_state) {
+		switch (tt->state) {
+		case IWL_TI_0:
+			/*
+			 * When the system is ready to go back to IWL_TI_0
+			 * we only have to call iwl_power_update_mode() to
+			 * do so.
+			 */
+			break;
+		case IWL_TI_1:
+			tt->tt_power_mode = IWL_POWER_INDEX_3;
+			break;
+		case IWL_TI_2:
+			tt->tt_power_mode = IWL_POWER_INDEX_4;
+			break;
+		default:
+			tt->tt_power_mode = IWL_POWER_INDEX_5;
+			break;
+		}
+		mutex_lock(&priv->mutex);
+		if (old_state == IWL_TI_CT_KILL)
+			clear_bit(STATUS_CT_KILL, &priv->status);
+		if (tt->state != IWL_TI_CT_KILL &&
+		    iwl_power_update_mode(priv, true)) {
+			/* TT state not updated
+			 * try again during next temperature read
+			 */
+			if (old_state == IWL_TI_CT_KILL)
+				set_bit(STATUS_CT_KILL, &priv->status);
+			tt->state = old_state;
+			IWL_ERR(priv, "Cannot update power mode, "
+					"TT state not updated\n");
+		} else {
+			if (tt->state == IWL_TI_CT_KILL) {
+				if (force) {
+					set_bit(STATUS_CT_KILL, &priv->status);
+					iwl_perform_ct_kill_task(priv, true);
+				} else {
+					iwl_prepare_ct_kill_task(priv);
+					tt->state = old_state;
+				}
+			} else if (old_state == IWL_TI_CT_KILL &&
+				 tt->state != IWL_TI_CT_KILL)
+				iwl_perform_ct_kill_task(priv, false);
+			IWL_DEBUG_TEMP(priv, "Temperature state changed %u\n",
+					tt->state);
+			IWL_DEBUG_TEMP(priv, "Power Index change to %u\n",
+					tt->tt_power_mode);
+		}
+		mutex_unlock(&priv->mutex);
+	}
+}
+
+/*
+ * Advance thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ *	Chip will identify dangerously high temperatures that can
+ *	harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ *	Throttle early enough to lower the power consumption before
+ *	drastic steps are needed
+ *	Actions include relaxing the power down sleep thresholds and
+ *	decreasing the number of TX streams
+ * 3) Avoid throughput performance impact as much as possible
+ *
+ *=============================================================================
+ *                 Condition Nxt State  Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
+ *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
+ *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
+ *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
+ *=============================================================================
+ */
+static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
+{
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+	int i;
+	bool changed = false;
+	enum iwl_tt_state old_state;
+	struct iwl_tt_trans *transaction;
+
+	old_state = tt->state;
+	for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
+		/* based on the current TT state,
+		 * find the curresponding transaction table
+		 * each table has (IWL_TI_STATE_MAX - 1) entries
+		 * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
+		 * will advance to the correct table.
+		 * then based on the current temperature
+		 * find the next state need to transaction to
+		 * go through all the possible (IWL_TI_STATE_MAX - 1) entries
+		 * in the current table to see if transaction is needed
+		 */
+		transaction = tt->transaction +
+			((old_state * (IWL_TI_STATE_MAX - 1)) + i);
+		if (temp >= transaction->tt_low &&
+		    temp <= transaction->tt_high) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+			if ((tt->tt_previous_temp) &&
+			    (temp > tt->tt_previous_temp) &&
+			    ((temp - tt->tt_previous_temp) >
+			    IWL_TT_INCREASE_MARGIN)) {
+				IWL_DEBUG_TEMP(priv,
+					"Temperature increase %d "
+					"degree Celsius\n",
+					(temp - tt->tt_previous_temp));
+			}
+			tt->tt_previous_temp = temp;
+#endif
+			if (old_state !=
+			    transaction->next_state) {
+				changed = true;
+				tt->state =
+					transaction->next_state;
+			}
+			break;
+		}
+	}
+	/* stop ct_kill_waiting_tm timer */
+	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
+	if (changed) {
+		if (tt->state >= IWL_TI_1) {
+			/* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
+			tt->tt_power_mode = IWL_POWER_INDEX_5;
+
+			if (!iwl_ht_enabled(priv)) {
+				struct iwl_rxon_context *ctx;
+
+				for_each_context(priv, ctx) {
+					struct iwl_rxon_cmd *rxon;
+
+					rxon = &ctx->staging;
+
+					/* disable HT */
+					rxon->flags &= ~(
+						RXON_FLG_CHANNEL_MODE_MSK |
+						RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
+						RXON_FLG_HT40_PROT_MSK |
+						RXON_FLG_HT_PROT_MSK);
+				}
+			} else {
+				/* check HT capability and set
+				 * according to the system HT capability
+				 * in case get disabled before */
+				iwl_set_rxon_ht(priv, &priv->current_ht_config);
+			}
+
+		} else {
+			/*
+			 * restore system power setting -- it will be
+			 * recalculated automatically.
+			 */
+
+			/* check HT capability and set
+			 * according to the system HT capability
+			 * in case get disabled before */
+			iwl_set_rxon_ht(priv, &priv->current_ht_config);
+		}
+		mutex_lock(&priv->mutex);
+		if (old_state == IWL_TI_CT_KILL)
+			clear_bit(STATUS_CT_KILL, &priv->status);
+		if (tt->state != IWL_TI_CT_KILL &&
+		    iwl_power_update_mode(priv, true)) {
+			/* TT state not updated
+			 * try again during next temperature read
+			 */
+			IWL_ERR(priv, "Cannot update power mode, "
+					"TT state not updated\n");
+			if (old_state == IWL_TI_CT_KILL)
+				set_bit(STATUS_CT_KILL, &priv->status);
+			tt->state = old_state;
+		} else {
+			IWL_DEBUG_TEMP(priv,
+					"Thermal Throttling to new state: %u\n",
+					tt->state);
+			if (old_state != IWL_TI_CT_KILL &&
+			    tt->state == IWL_TI_CT_KILL) {
+				if (force) {
+					IWL_DEBUG_TEMP(priv,
+						"Enter IWL_TI_CT_KILL\n");
+					set_bit(STATUS_CT_KILL, &priv->status);
+					iwl_perform_ct_kill_task(priv, true);
+				} else {
+					iwl_prepare_ct_kill_task(priv);
+					tt->state = old_state;
+				}
+			} else if (old_state == IWL_TI_CT_KILL &&
+				  tt->state != IWL_TI_CT_KILL) {
+				IWL_DEBUG_TEMP(priv, "Exit IWL_TI_CT_KILL\n");
+				iwl_perform_ct_kill_task(priv, false);
+			}
+		}
+		mutex_unlock(&priv->mutex);
+	}
+}
+
+/* Card State Notification indicated reach critical temperature
+ * if PSP not enable, no Thermal Throttling function will be performed
+ * just set the GP1 bit to acknowledge the event
+ * otherwise, go into IWL_TI_CT_KILL state
+ * since Card State Notification will not provide any temperature reading
+ * for Legacy mode
+ * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
+ * for advance mode
+ * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
+ */
+static void iwl_bg_ct_enter(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (!iwl_is_ready(priv))
+		return;
+
+	if (tt->state != IWL_TI_CT_KILL) {
+		IWL_ERR(priv, "Device reached critical temperature "
+			      "- ucode going to sleep!\n");
+		if (!priv->thermal_throttle.advanced_tt)
+			iwl_legacy_tt_handler(priv,
+					      IWL_MINIMAL_POWER_THRESHOLD,
+					      true);
+		else
+			iwl_advance_tt_handler(priv,
+					       CT_KILL_THRESHOLD + 1, true);
+	}
+}
+
+/* Card State Notification indicated out of critical temperature
+ * since Card State Notification will not provide any temperature reading
+ * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
+ * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
+ */
+static void iwl_bg_ct_exit(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (!iwl_is_ready(priv))
+		return;
+
+	/* stop ct_kill_exit_tm timer */
+	del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
+
+	if (tt->state == IWL_TI_CT_KILL) {
+		IWL_ERR(priv,
+			"Device temperature below critical"
+			"- ucode awake!\n");
+		/*
+		 * exit from CT_KILL state
+		 * reset the current temperature reading
+		 */
+		priv->temperature = 0;
+		if (!priv->thermal_throttle.advanced_tt)
+			iwl_legacy_tt_handler(priv,
+				      IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
+				      true);
+		else
+			iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
+					       true);
+	}
+}
+
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
+{
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n");
+	queue_work(priv->workqueue, &priv->ct_enter);
+}
+
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
+{
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n");
+	queue_work(priv->workqueue, &priv->ct_exit);
+}
+
+static void iwl_bg_tt_work(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
+	s32 temp = priv->temperature; /* degrees CELSIUS except specified */
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (!priv->thermal_throttle.advanced_tt)
+		iwl_legacy_tt_handler(priv, temp, false);
+	else
+		iwl_advance_tt_handler(priv, temp, false);
+}
+
+void iwl_tt_handler(struct iwl_priv *priv)
+{
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n");
+	queue_work(priv->workqueue, &priv->tt_work);
+}
+
+/* Thermal throttling initialization
+ * For advance thermal throttling:
+ *     Initialize Thermal Index and temperature threshold table
+ *     Initialize thermal throttling restriction table
+ */
+void iwl_tt_initialize(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+	int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
+	struct iwl_tt_trans *transaction;
+
+	IWL_DEBUG_TEMP(priv, "Initialize Thermal Throttling\n");
+
+	memset(tt, 0, sizeof(struct iwl_tt_mgmt));
+
+	tt->state = IWL_TI_0;
+	init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
+	priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
+	priv->thermal_throttle.ct_kill_exit_tm.function =
+		iwl_tt_check_exit_ct_kill;
+	init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
+	priv->thermal_throttle.ct_kill_waiting_tm.data =
+		(unsigned long)priv;
+	priv->thermal_throttle.ct_kill_waiting_tm.function =
+		iwl_tt_ready_for_ct_kill;
+	/* setup deferred ct kill work */
+	INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
+	INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
+	INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
+
+	if (priv->cfg->base_params->adv_thermal_throttle) {
+		IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n");
+		tt->restriction = kcalloc(IWL_TI_STATE_MAX,
+					  sizeof(struct iwl_tt_restriction),
+					  GFP_KERNEL);
+		tt->transaction = kcalloc(IWL_TI_STATE_MAX *
+					  (IWL_TI_STATE_MAX - 1),
+					  sizeof(struct iwl_tt_trans),
+					  GFP_KERNEL);
+		if (!tt->restriction || !tt->transaction) {
+			IWL_ERR(priv, "Fallback to Legacy Throttling\n");
+			priv->thermal_throttle.advanced_tt = false;
+			kfree(tt->restriction);
+			tt->restriction = NULL;
+			kfree(tt->transaction);
+			tt->transaction = NULL;
+		} else {
+			transaction = tt->transaction +
+				(IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
+			memcpy(transaction, &tt_range_0[0], size);
+			transaction = tt->transaction +
+				(IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
+			memcpy(transaction, &tt_range_1[0], size);
+			transaction = tt->transaction +
+				(IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
+			memcpy(transaction, &tt_range_2[0], size);
+			transaction = tt->transaction +
+				(IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
+			memcpy(transaction, &tt_range_3[0], size);
+			size = sizeof(struct iwl_tt_restriction) *
+				IWL_TI_STATE_MAX;
+			memcpy(tt->restriction,
+				&restriction_range[0], size);
+			priv->thermal_throttle.advanced_tt = true;
+		}
+	} else {
+		IWL_DEBUG_TEMP(priv, "Legacy Thermal Throttling\n");
+		priv->thermal_throttle.advanced_tt = false;
+	}
+}
+
+/* cleanup thermal throttling management related memory and timer */
+void iwl_tt_exit(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+	/* stop ct_kill_exit_tm timer if activated */
+	del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
+	/* stop ct_kill_waiting_tm timer if activated */
+	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
+	cancel_work_sync(&priv->tt_work);
+	cancel_work_sync(&priv->ct_enter);
+	cancel_work_sync(&priv->ct_exit);
+
+	if (priv->thermal_throttle.advanced_tt) {
+		/* free advance thermal throttling memory */
+		kfree(tt->restriction);
+		tt->restriction = NULL;
+		kfree(tt->transaction);
+		tt->transaction = NULL;
+	}
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.h b/drivers/net/wireless/iwlwifi/dvm/tt.h
new file mode 100644
index 0000000..44c7c8f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/tt.h
@@ -0,0 +1,128 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+#ifndef __iwl_tt_setting_h__
+#define __iwl_tt_setting_h__
+
+#include "commands.h"
+
+#define IWL_ABSOLUTE_ZERO		0
+#define IWL_ABSOLUTE_MAX		0xFFFFFFFF
+#define IWL_TT_INCREASE_MARGIN	5
+#define IWL_TT_CT_KILL_MARGIN	3
+
+enum iwl_antenna_ok {
+	IWL_ANT_OK_NONE,
+	IWL_ANT_OK_SINGLE,
+	IWL_ANT_OK_MULTI,
+};
+
+/* Thermal Throttling State Machine states */
+enum  iwl_tt_state {
+	IWL_TI_0,	/* normal temperature, system power state */
+	IWL_TI_1,	/* high temperature detect, low power state */
+	IWL_TI_2,	/* higher temperature detected, lower power state */
+	IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
+	IWL_TI_STATE_MAX
+};
+
+/**
+ * struct iwl_tt_restriction - Thermal Throttling restriction table
+ * @tx_stream: number of tx stream allowed
+ * @is_ht: ht enable/disable
+ * @rx_stream: number of rx stream allowed
+ *
+ * This table is used by advance thermal throttling management
+ * based on the current thermal throttling state, and determines
+ * the number of tx/rx streams and the status of HT operation.
+ */
+struct iwl_tt_restriction {
+	enum iwl_antenna_ok tx_stream;
+	enum iwl_antenna_ok rx_stream;
+	bool is_ht;
+};
+
+/**
+ * struct iwl_tt_trans - Thermal Throttling transaction table
+ * @next_state:  next thermal throttling mode
+ * @tt_low: low temperature threshold to change state
+ * @tt_high: high temperature threshold to change state
+ *
+ * This is used by the advanced thermal throttling algorithm
+ * to determine the next thermal state to go based on the
+ * current temperature.
+ */
+struct iwl_tt_trans {
+	enum iwl_tt_state next_state;
+	u32 tt_low;
+	u32 tt_high;
+};
+
+/**
+ * struct iwl_tt_mgnt - Thermal Throttling Management structure
+ * @advanced_tt:    advanced thermal throttle required
+ * @state:          current Thermal Throttling state
+ * @tt_power_mode:  Thermal Throttling power mode index
+ *		    being used to set power level when
+ *		    when thermal throttling state != IWL_TI_0
+ *		    the tt_power_mode should set to different
+ *		    power mode based on the current tt state
+ * @tt_previous_temperature: last measured temperature
+ * @iwl_tt_restriction: ptr to restriction tbl, used by advance
+ *		    thermal throttling to determine how many tx/rx streams
+ *		    should be used in tt state; and can HT be enabled or not
+ * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
+ *		    state transaction
+ * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
+ * @ct_kill_exit_tm: timer to exit thermal kill
+ */
+struct iwl_tt_mgmt {
+	enum iwl_tt_state state;
+	bool advanced_tt;
+	u8 tt_power_mode;
+	bool ct_kill_toggle;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	s32 tt_previous_temp;
+#endif
+	struct iwl_tt_restriction *restriction;
+	struct iwl_tt_trans *transaction;
+	struct timer_list ct_kill_exit_tm;
+	struct timer_list ct_kill_waiting_tm;
+};
+
+u8 iwl_tt_current_power_mode(struct iwl_priv *priv);
+bool iwl_tt_is_low_power_state(struct iwl_priv *priv);
+bool iwl_ht_enabled(struct iwl_priv *priv);
+enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv);
+enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv);
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
+void iwl_tt_handler(struct iwl_priv *priv);
+void iwl_tt_initialize(struct iwl_priv *priv);
+void iwl_tt_exit(struct iwl_priv *priv);
+
+#endif  /* __iwl_tt_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
new file mode 100644
index 0000000..5971a23
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -0,0 +1,1388 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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 <linux/ieee80211.h>
+#include "iwl-io.h"
+#include "iwl-trans.h"
+#include "iwl-agn-hw.h"
+#include "dev.h"
+#include "agn.h"
+
+static const u8 tid_to_ac[] = {
+	IEEE80211_AC_BE,
+	IEEE80211_AC_BK,
+	IEEE80211_AC_BK,
+	IEEE80211_AC_BE,
+	IEEE80211_AC_VI,
+	IEEE80211_AC_VI,
+	IEEE80211_AC_VO,
+	IEEE80211_AC_VO,
+};
+
+static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
+				     struct ieee80211_tx_info *info,
+				     __le16 fc, __le32 *tx_flags)
+{
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
+	    info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT ||
+	    info->flags & IEEE80211_TX_CTL_AMPDU)
+		*tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
+				      struct sk_buff *skb,
+				      struct iwl_tx_cmd *tx_cmd,
+				      struct ieee80211_tx_info *info,
+				      struct ieee80211_hdr *hdr, u8 sta_id)
+{
+	__le16 fc = hdr->frame_control;
+	__le32 tx_flags = tx_cmd->tx_flags;
+
+	tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+		tx_flags |= TX_CMD_FLG_ACK_MSK;
+	else
+		tx_flags &= ~TX_CMD_FLG_ACK_MSK;
+
+	if (ieee80211_is_probe_resp(fc))
+		tx_flags |= TX_CMD_FLG_TSF_MSK;
+	else if (ieee80211_is_back_req(fc))
+		tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+	else if (info->band == IEEE80211_BAND_2GHZ &&
+		 priv->cfg->bt_params &&
+		 priv->cfg->bt_params->advanced_bt_coexist &&
+		 (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) ||
+		 ieee80211_is_reassoc_req(fc) ||
+		 skb->protocol == cpu_to_be16(ETH_P_PAE)))
+		tx_flags |= TX_CMD_FLG_IGNORE_BT;
+
+
+	tx_cmd->sta_id = sta_id;
+	if (ieee80211_has_morefrags(fc))
+		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+	if (ieee80211_is_data_qos(fc)) {
+		u8 *qc = ieee80211_get_qos_ctl(hdr);
+		tx_cmd->tid_tspec = qc[0] & 0xf;
+		tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+	} else {
+		tx_cmd->tid_tspec = IWL_TID_NON_QOS;
+		if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+			tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+		else
+			tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+	}
+
+	iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags);
+
+	tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+	if (ieee80211_is_mgmt(fc)) {
+		if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
+			tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
+		else
+			tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
+	} else {
+		tx_cmd->timeout.pm_frame_timeout = 0;
+	}
+
+	tx_cmd->driver_txop = 0;
+	tx_cmd->tx_flags = tx_flags;
+	tx_cmd->next_frame_len = 0;
+}
+
+static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
+				     struct iwl_tx_cmd *tx_cmd,
+				     struct ieee80211_tx_info *info,
+				     __le16 fc)
+{
+	u32 rate_flags;
+	int rate_idx;
+	u8 rts_retry_limit;
+	u8 data_retry_limit;
+	u8 rate_plcp;
+
+	if (priv->wowlan) {
+		rts_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
+		data_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
+	} else {
+		/* Set retry limit on RTS packets */
+		rts_retry_limit = IWLAGN_RTS_DFAULT_RETRY_LIMIT;
+
+		/* Set retry limit on DATA packets and Probe Responses*/
+		if (ieee80211_is_probe_resp(fc)) {
+			data_retry_limit = IWLAGN_MGMT_DFAULT_RETRY_LIMIT;
+			rts_retry_limit =
+				min(data_retry_limit, rts_retry_limit);
+		} else if (ieee80211_is_back_req(fc))
+			data_retry_limit = IWLAGN_BAR_DFAULT_RETRY_LIMIT;
+		else
+			data_retry_limit = IWLAGN_DEFAULT_TX_RETRY;
+	}
+
+	tx_cmd->data_retry_limit = data_retry_limit;
+	tx_cmd->rts_retry_limit = rts_retry_limit;
+
+	/* DATA packets will use the uCode station table for rate/antenna
+	 * selection */
+	if (ieee80211_is_data(fc)) {
+		tx_cmd->initial_rate_index = 0;
+		tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+		if (priv->tm_fixed_rate) {
+			/*
+			 * rate overwrite by testmode
+			 * we not only send lq command to change rate
+			 * we also re-enforce per data pkt base.
+			 */
+			tx_cmd->tx_flags &= ~TX_CMD_FLG_STA_RATE_MSK;
+			memcpy(&tx_cmd->rate_n_flags, &priv->tm_fixed_rate,
+			       sizeof(tx_cmd->rate_n_flags));
+		}
+#endif
+		return;
+	} else if (ieee80211_is_back_req(fc))
+		tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+
+	/**
+	 * If the current TX rate stored in mac80211 has the MCS bit set, it's
+	 * not really a TX rate.  Thus, we use the lowest supported rate for
+	 * this band.  Also use the lowest supported rate if the stored rate
+	 * index is invalid.
+	 */
+	rate_idx = info->control.rates[0].idx;
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
+			(rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
+		rate_idx = rate_lowest_index(
+				&priv->eeprom_data->bands[info->band],
+				info->control.sta);
+	/* For 5 GHZ band, remap mac80211 rate indices into driver indices */
+	if (info->band == IEEE80211_BAND_5GHZ)
+		rate_idx += IWL_FIRST_OFDM_RATE;
+	/* Get PLCP rate for tx_cmd->rate_n_flags */
+	rate_plcp = iwl_rates[rate_idx].plcp;
+	/* Zero out flags for this packet */
+	rate_flags = 0;
+
+	/* Set CCK flag as needed */
+	if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
+		rate_flags |= RATE_MCS_CCK_MSK;
+
+	/* Set up antennas */
+	 if (priv->cfg->bt_params &&
+	     priv->cfg->bt_params->advanced_bt_coexist &&
+	     priv->bt_full_concurrent) {
+		/* operated as 1x1 in full concurrency mode */
+		priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+				first_antenna(priv->eeprom_data->valid_tx_ant));
+	} else
+		priv->mgmt_tx_ant = iwl_toggle_tx_ant(
+					priv, priv->mgmt_tx_ant,
+					priv->eeprom_data->valid_tx_ant);
+	rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
+
+	/* Set the rate in the TX cmd */
+	tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags);
+}
+
+static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
+					 struct ieee80211_tx_info *info,
+					 struct iwl_tx_cmd *tx_cmd,
+					 struct sk_buff *skb_frag)
+{
+	struct ieee80211_key_conf *keyconf = info->control.hw_key;
+
+	switch (keyconf->cipher) {
+	case WLAN_CIPHER_SUITE_CCMP:
+		tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
+		memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
+		if (info->flags & IEEE80211_TX_CTL_AMPDU)
+			tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
+		IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
+		break;
+
+	case WLAN_CIPHER_SUITE_TKIP:
+		tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
+		ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
+		IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
+		break;
+
+	case WLAN_CIPHER_SUITE_WEP104:
+		tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+		/* fall through */
+	case WLAN_CIPHER_SUITE_WEP40:
+		tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
+			(keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
+
+		memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
+
+		IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
+			     "with key %d\n", keyconf->keyidx);
+		break;
+
+	default:
+		IWL_ERR(priv, "Unknown encode cipher %x\n", keyconf->cipher);
+		break;
+	}
+}
+
+/**
+ * iwl_sta_id_or_broadcast - return sta_id or broadcast sta
+ * @context: the current context
+ * @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 int iwl_sta_id_or_broadcast(struct iwl_rxon_context *context,
+				   struct ieee80211_sta *sta)
+{
+	int sta_id;
+
+	if (!sta)
+		return context->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;
+}
+
+/*
+ * start REPLY_TX command process
+ */
+int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct iwl_station_priv *sta_priv = NULL;
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+	struct iwl_device_cmd *dev_cmd;
+	struct iwl_tx_cmd *tx_cmd;
+	__le16 fc;
+	u8 hdr_len;
+	u16 len, seq_number = 0;
+	u8 sta_id, tid = IWL_MAX_TID_COUNT;
+	bool is_agg = false;
+	int txq_id;
+
+	if (info->control.vif)
+		ctx = iwl_rxon_ctx_from_vif(info->control.vif);
+
+	if (iwl_is_rfkill(priv)) {
+		IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
+		goto drop_unlock_priv;
+	}
+
+	fc = hdr->frame_control;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (ieee80211_is_auth(fc))
+		IWL_DEBUG_TX(priv, "Sending AUTH frame\n");
+	else if (ieee80211_is_assoc_req(fc))
+		IWL_DEBUG_TX(priv, "Sending ASSOC frame\n");
+	else if (ieee80211_is_reassoc_req(fc))
+		IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
+#endif
+
+	if (unlikely(ieee80211_is_probe_resp(fc))) {
+		struct iwl_wipan_noa_data *noa_data =
+			rcu_dereference(priv->noa_data);
+
+		if (noa_data &&
+		    pskb_expand_head(skb, 0, noa_data->length,
+				     GFP_ATOMIC) == 0) {
+			memcpy(skb_put(skb, noa_data->length),
+			       noa_data->data, noa_data->length);
+			hdr = (struct ieee80211_hdr *)skb->data;
+		}
+	}
+
+	hdr_len = ieee80211_hdrlen(fc);
+
+	/* For management frames use broadcast id to do not break aggregation */
+	if (!ieee80211_is_data(fc))
+		sta_id = ctx->bcast_sta_id;
+	else {
+		/* Find index into station table for destination station */
+		sta_id = iwl_sta_id_or_broadcast(ctx, info->control.sta);
+		if (sta_id == IWL_INVALID_STATION) {
+			IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
+				       hdr->addr1);
+			goto drop_unlock_priv;
+		}
+	}
+
+	IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
+
+	if (info->control.sta)
+		sta_priv = (void *)info->control.sta->drv_priv;
+
+	if (sta_priv && sta_priv->asleep &&
+	    (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
+		/*
+		 * This sends an asynchronous command to the device,
+		 * but we can rely on it being processed before the
+		 * next frame is processed -- and the next frame to
+		 * this station is the one that will consume this
+		 * counter.
+		 * For now set the counter to just 1 since we do not
+		 * support uAPSD yet.
+		 *
+		 * FIXME: If we get two non-bufferable frames one
+		 * after the other, we might only send out one of
+		 * them because this is racy.
+		 */
+		iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
+	}
+
+	if (info->flags & IEEE80211_TX_CTL_AMPDU)
+		is_agg = true;
+
+	dev_cmd = iwl_trans_alloc_tx_cmd(priv->trans);
+
+	if (unlikely(!dev_cmd))
+		goto drop_unlock_priv;
+
+	memset(dev_cmd, 0, sizeof(*dev_cmd));
+	tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
+
+	/* Total # bytes to be transmitted */
+	len = (u16)skb->len;
+	tx_cmd->len = cpu_to_le16(len);
+
+	if (info->control.hw_key)
+		iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb);
+
+	/* TODO need this for burst mode later on */
+	iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id);
+
+	iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc);
+
+	memset(&info->status, 0, sizeof(info->status));
+
+	info->driver_data[0] = ctx;
+	info->driver_data[1] = dev_cmd;
+	/* From now on, we cannot access info->control */
+
+	spin_lock(&priv->sta_lock);
+
+	if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
+		u8 *qc = NULL;
+		struct iwl_tid_data *tid_data;
+		qc = ieee80211_get_qos_ctl(hdr);
+		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+		if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
+			goto drop_unlock_sta;
+		tid_data = &priv->tid_data[sta_id][tid];
+
+		/* aggregation is on for this <sta,tid> */
+		if (info->flags & IEEE80211_TX_CTL_AMPDU &&
+		    tid_data->agg.state != IWL_AGG_ON) {
+			IWL_ERR(priv, "TX_CTL_AMPDU while not in AGG:"
+				" Tx flags = 0x%08x, agg.state = %d",
+				info->flags, tid_data->agg.state);
+			IWL_ERR(priv, "sta_id = %d, tid = %d seq_num = %d",
+				sta_id, tid, SEQ_TO_SN(tid_data->seq_number));
+			goto drop_unlock_sta;
+		}
+
+		/* We can receive packets from the stack in IWL_AGG_{ON,OFF}
+		 * only. Check this here.
+		 */
+		if (WARN_ONCE(tid_data->agg.state != IWL_AGG_ON &&
+		    tid_data->agg.state != IWL_AGG_OFF,
+		    "Tx while agg.state = %d", tid_data->agg.state))
+			goto drop_unlock_sta;
+
+		seq_number = tid_data->seq_number;
+		seq_number &= IEEE80211_SCTL_SEQ;
+		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+		hdr->seq_ctrl |= cpu_to_le16(seq_number);
+		seq_number += 0x10;
+	}
+
+	/* Copy MAC header from skb into command buffer */
+	memcpy(tx_cmd->hdr, hdr, hdr_len);
+
+	if (is_agg)
+		txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
+	else if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+		/*
+		 * Send this frame after DTIM -- there's a special queue
+		 * reserved for this for contexts that support AP mode.
+		 */
+		txq_id = ctx->mcast_queue;
+
+		/*
+		 * The microcode will clear the more data
+		 * bit in the last frame it transmits.
+		 */
+		hdr->frame_control |=
+			cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+	} else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+		txq_id = IWL_AUX_QUEUE;
+	else
+		txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)];
+
+	WARN_ON_ONCE(!is_agg && txq_id != info->hw_queue);
+	WARN_ON_ONCE(is_agg &&
+		     priv->queue_to_mac80211[txq_id] != info->hw_queue);
+
+	if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id))
+		goto drop_unlock_sta;
+
+	if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc) &&
+	    !ieee80211_has_morefrags(fc))
+		priv->tid_data[sta_id][tid].seq_number = seq_number;
+
+	spin_unlock(&priv->sta_lock);
+
+	/*
+	 * Avoid atomic ops if it isn't an associated client.
+	 * Also, if this is a packet for aggregation, don't
+	 * increase the counter because the ucode will stop
+	 * aggregation queues when their respective station
+	 * goes to sleep.
+	 */
+	if (sta_priv && sta_priv->client && !is_agg)
+		atomic_inc(&sta_priv->pending_frames);
+
+	if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+		iwl_scan_offchannel_skb(priv);
+
+	return 0;
+
+drop_unlock_sta:
+	if (dev_cmd)
+		iwl_trans_free_tx_cmd(priv->trans, dev_cmd);
+	spin_unlock(&priv->sta_lock);
+drop_unlock_priv:
+	return -1;
+}
+
+static int iwlagn_alloc_agg_txq(struct iwl_priv *priv, int mq)
+{
+	int q;
+
+	for (q = IWLAGN_FIRST_AMPDU_QUEUE;
+	     q < priv->cfg->base_params->num_of_queues; q++) {
+		if (!test_and_set_bit(q, priv->agg_q_alloc)) {
+			priv->queue_to_mac80211[q] = mq;
+			return q;
+		}
+	}
+
+	return -ENOSPC;
+}
+
+static void iwlagn_dealloc_agg_txq(struct iwl_priv *priv, int q)
+{
+	clear_bit(q, priv->agg_q_alloc);
+	priv->queue_to_mac80211[q] = IWL_INVALID_MAC80211_QUEUE;
+}
+
+int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta, u16 tid)
+{
+	struct iwl_tid_data *tid_data;
+	int sta_id, txq_id;
+	enum iwl_agg_state agg_state;
+
+	sta_id = iwl_sta_id(sta);
+
+	if (sta_id == IWL_INVALID_STATION) {
+		IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
+		return -ENXIO;
+	}
+
+	spin_lock_bh(&priv->sta_lock);
+
+	tid_data = &priv->tid_data[sta_id][tid];
+	txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
+
+	switch (priv->tid_data[sta_id][tid].agg.state) {
+	case IWL_EMPTYING_HW_QUEUE_ADDBA:
+		/*
+		* This can happen if the peer stops aggregation
+		* again before we've had a chance to drain the
+		* queue we selected previously, i.e. before the
+		* session was really started completely.
+		*/
+		IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
+		goto turn_off;
+	case IWL_AGG_STARTING:
+		/*
+		 * This can happen when the session is stopped before
+		 * we receive ADDBA response
+		 */
+		IWL_DEBUG_HT(priv, "AGG stop before AGG became operational\n");
+		goto turn_off;
+	case IWL_AGG_ON:
+		break;
+	default:
+		IWL_WARN(priv, "Stopping AGG while state not ON "
+			 "or starting for %d on %d (%d)\n", sta_id, tid,
+			 priv->tid_data[sta_id][tid].agg.state);
+		spin_unlock_bh(&priv->sta_lock);
+		return 0;
+	}
+
+	tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
+
+	/* There are still packets for this RA / TID in the HW */
+	if (!test_bit(txq_id, priv->agg_q_alloc)) {
+		IWL_DEBUG_TX_QUEUES(priv,
+			"stopping AGG on STA/TID %d/%d but hwq %d not used\n",
+			sta_id, tid, txq_id);
+	} else if (tid_data->agg.ssn != tid_data->next_reclaimed) {
+		IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
+				    "next_recl = %d\n",
+				    tid_data->agg.ssn,
+				    tid_data->next_reclaimed);
+		priv->tid_data[sta_id][tid].agg.state =
+			IWL_EMPTYING_HW_QUEUE_DELBA;
+		spin_unlock_bh(&priv->sta_lock);
+		return 0;
+	}
+
+	IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
+			    tid_data->agg.ssn);
+turn_off:
+	agg_state = priv->tid_data[sta_id][tid].agg.state;
+	priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
+
+	spin_unlock_bh(&priv->sta_lock);
+
+	if (test_bit(txq_id, priv->agg_q_alloc)) {
+		/*
+		 * If the transport didn't know that we wanted to start
+		 * agreggation, don't tell it that we want to stop them.
+		 * This can happen when we don't get the addBA response on
+		 * time, or we hadn't time to drain the AC queues.
+		 */
+		if (agg_state == IWL_AGG_ON)
+			iwl_trans_txq_disable(priv->trans, txq_id);
+		else
+			IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
+					    agg_state);
+		iwlagn_dealloc_agg_txq(priv, txq_id);
+	}
+
+	ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+
+	return 0;
+}
+
+int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+	struct iwl_tid_data *tid_data;
+	int sta_id, txq_id, ret;
+
+	IWL_DEBUG_HT(priv, "TX AGG request on ra = %pM tid = %d\n",
+		     sta->addr, tid);
+
+	sta_id = iwl_sta_id(sta);
+	if (sta_id == IWL_INVALID_STATION) {
+		IWL_ERR(priv, "Start AGG on invalid station\n");
+		return -ENXIO;
+	}
+	if (unlikely(tid >= IWL_MAX_TID_COUNT))
+		return -EINVAL;
+
+	if (priv->tid_data[sta_id][tid].agg.state != IWL_AGG_OFF) {
+		IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
+		return -ENXIO;
+	}
+
+	txq_id = iwlagn_alloc_agg_txq(priv, ctx->ac_to_queue[tid_to_ac[tid]]);
+	if (txq_id < 0) {
+		IWL_DEBUG_TX_QUEUES(priv,
+			"No free aggregation queue for %pM/%d\n",
+			sta->addr, tid);
+		return txq_id;
+	}
+
+	ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+	if (ret)
+		return ret;
+
+	spin_lock_bh(&priv->sta_lock);
+	tid_data = &priv->tid_data[sta_id][tid];
+	tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
+	tid_data->agg.txq_id = txq_id;
+
+	*ssn = tid_data->agg.ssn;
+
+	if (*ssn == tid_data->next_reclaimed) {
+		IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
+				    tid_data->agg.ssn);
+		tid_data->agg.state = IWL_AGG_STARTING;
+		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+	} else {
+		IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
+				    "next_reclaimed = %d\n",
+				    tid_data->agg.ssn,
+				    tid_data->next_reclaimed);
+		tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
+	}
+	spin_unlock_bh(&priv->sta_lock);
+
+	return ret;
+}
+
+int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta, u16 tid, u8 buf_size)
+{
+	struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
+	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+	int q, fifo;
+	u16 ssn;
+
+	buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
+
+	spin_lock_bh(&priv->sta_lock);
+	ssn = priv->tid_data[sta_priv->sta_id][tid].agg.ssn;
+	q = priv->tid_data[sta_priv->sta_id][tid].agg.txq_id;
+	priv->tid_data[sta_priv->sta_id][tid].agg.state = IWL_AGG_ON;
+	spin_unlock_bh(&priv->sta_lock);
+
+	fifo = ctx->ac_to_fifo[tid_to_ac[tid]];
+
+	iwl_trans_txq_enable(priv->trans, q, fifo, sta_priv->sta_id, tid,
+			     buf_size, ssn);
+
+	/*
+	 * If the limit is 0, then it wasn't initialised yet,
+	 * use the default. We can do that since we take the
+	 * minimum below, and we don't want to go above our
+	 * default due to hardware restrictions.
+	 */
+	if (sta_priv->max_agg_bufsize == 0)
+		sta_priv->max_agg_bufsize =
+			LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+
+	/*
+	 * Even though in theory the peer could have different
+	 * aggregation reorder buffer sizes for different sessions,
+	 * our ucode doesn't allow for that and has a global limit
+	 * for each station. Therefore, use the minimum of all the
+	 * aggregation sessions and our default value.
+	 */
+	sta_priv->max_agg_bufsize =
+		min(sta_priv->max_agg_bufsize, buf_size);
+
+	if (priv->hw_params.use_rts_for_aggregation) {
+		/*
+		 * switch to RTS/CTS if it is the prefer protection
+		 * method for HT traffic
+		 */
+
+		sta_priv->lq_sta.lq.general_params.flags |=
+			LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+	}
+	priv->agg_tids_count++;
+	IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
+		     priv->agg_tids_count);
+
+	sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
+		sta_priv->max_agg_bufsize;
+
+	IWL_DEBUG_HT(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
+		 sta->addr, tid);
+
+	return iwl_send_lq_cmd(priv, ctx,
+			&sta_priv->lq_sta.lq, CMD_ASYNC, false);
+}
+
+static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid)
+{
+	struct iwl_tid_data *tid_data = &priv->tid_data[sta_id][tid];
+	enum iwl_rxon_context_id ctx;
+	struct ieee80211_vif *vif;
+	u8 *addr;
+
+	lockdep_assert_held(&priv->sta_lock);
+
+	addr = priv->stations[sta_id].sta.sta.addr;
+	ctx = priv->stations[sta_id].ctxid;
+	vif = priv->contexts[ctx].vif;
+
+	switch (priv->tid_data[sta_id][tid].agg.state) {
+	case IWL_EMPTYING_HW_QUEUE_DELBA:
+		/* There are no packets for this RA / TID in the HW any more */
+		if (tid_data->agg.ssn == tid_data->next_reclaimed) {
+			IWL_DEBUG_TX_QUEUES(priv,
+				"Can continue DELBA flow ssn = next_recl ="
+				" %d", tid_data->next_reclaimed);
+			iwl_trans_txq_disable(priv->trans,
+					      tid_data->agg.txq_id);
+			iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id);
+			tid_data->agg.state = IWL_AGG_OFF;
+			ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
+		}
+		break;
+	case IWL_EMPTYING_HW_QUEUE_ADDBA:
+		/* There are no packets for this RA / TID in the HW any more */
+		if (tid_data->agg.ssn == tid_data->next_reclaimed) {
+			IWL_DEBUG_TX_QUEUES(priv,
+				"Can continue ADDBA flow ssn = next_recl ="
+				" %d", tid_data->next_reclaimed);
+			tid_data->agg.state = IWL_AGG_STARTING;
+			ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void iwlagn_non_agg_tx_status(struct iwl_priv *priv,
+				     struct iwl_rxon_context *ctx,
+				     const u8 *addr1)
+{
+	struct ieee80211_sta *sta;
+	struct iwl_station_priv *sta_priv;
+
+	rcu_read_lock();
+	sta = ieee80211_find_sta(ctx->vif, addr1);
+	if (sta) {
+		sta_priv = (void *)sta->drv_priv;
+		/* avoid atomic ops if this isn't a client */
+		if (sta_priv->client &&
+		    atomic_dec_return(&sta_priv->pending_frames) == 0)
+			ieee80211_sta_block_awake(priv->hw, sta, false);
+	}
+	rcu_read_unlock();
+}
+
+/**
+ * translate ucode response to mac80211 tx status control values
+ */
+static void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
+				  struct ieee80211_tx_info *info)
+{
+	struct ieee80211_tx_rate *r = &info->status.rates[0];
+
+	info->status.antenna =
+		((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
+	if (rate_n_flags & RATE_MCS_HT_MSK)
+		r->flags |= IEEE80211_TX_RC_MCS;
+	if (rate_n_flags & RATE_MCS_GF_MSK)
+		r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+	if (rate_n_flags & RATE_MCS_HT40_MSK)
+		r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+	if (rate_n_flags & RATE_MCS_DUP_MSK)
+		r->flags |= IEEE80211_TX_RC_DUP_DATA;
+	if (rate_n_flags & RATE_MCS_SGI_MSK)
+		r->flags |= IEEE80211_TX_RC_SHORT_GI;
+	r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+const char *iwl_get_tx_fail_reason(u32 status)
+{
+#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
+
+	switch (status & TX_STATUS_MSK) {
+	case TX_STATUS_SUCCESS:
+		return "SUCCESS";
+	TX_STATUS_POSTPONE(DELAY);
+	TX_STATUS_POSTPONE(FEW_BYTES);
+	TX_STATUS_POSTPONE(BT_PRIO);
+	TX_STATUS_POSTPONE(QUIET_PERIOD);
+	TX_STATUS_POSTPONE(CALC_TTAK);
+	TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY);
+	TX_STATUS_FAIL(SHORT_LIMIT);
+	TX_STATUS_FAIL(LONG_LIMIT);
+	TX_STATUS_FAIL(FIFO_UNDERRUN);
+	TX_STATUS_FAIL(DRAIN_FLOW);
+	TX_STATUS_FAIL(RFKILL_FLUSH);
+	TX_STATUS_FAIL(LIFE_EXPIRE);
+	TX_STATUS_FAIL(DEST_PS);
+	TX_STATUS_FAIL(HOST_ABORTED);
+	TX_STATUS_FAIL(BT_RETRY);
+	TX_STATUS_FAIL(STA_INVALID);
+	TX_STATUS_FAIL(FRAG_DROPPED);
+	TX_STATUS_FAIL(TID_DISABLE);
+	TX_STATUS_FAIL(FIFO_FLUSHED);
+	TX_STATUS_FAIL(INSUFFICIENT_CF_POLL);
+	TX_STATUS_FAIL(PASSIVE_NO_RX);
+	TX_STATUS_FAIL(NO_BEACON_ON_RADAR);
+	}
+
+	return "UNKNOWN";
+
+#undef TX_STATUS_FAIL
+#undef TX_STATUS_POSTPONE
+}
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
+{
+	status &= AGG_TX_STATUS_MSK;
+
+	switch (status) {
+	case AGG_TX_STATE_UNDERRUN_MSK:
+		priv->reply_agg_tx_stats.underrun++;
+		break;
+	case AGG_TX_STATE_BT_PRIO_MSK:
+		priv->reply_agg_tx_stats.bt_prio++;
+		break;
+	case AGG_TX_STATE_FEW_BYTES_MSK:
+		priv->reply_agg_tx_stats.few_bytes++;
+		break;
+	case AGG_TX_STATE_ABORT_MSK:
+		priv->reply_agg_tx_stats.abort++;
+		break;
+	case AGG_TX_STATE_LAST_SENT_TTL_MSK:
+		priv->reply_agg_tx_stats.last_sent_ttl++;
+		break;
+	case AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK:
+		priv->reply_agg_tx_stats.last_sent_try++;
+		break;
+	case AGG_TX_STATE_LAST_SENT_BT_KILL_MSK:
+		priv->reply_agg_tx_stats.last_sent_bt_kill++;
+		break;
+	case AGG_TX_STATE_SCD_QUERY_MSK:
+		priv->reply_agg_tx_stats.scd_query++;
+		break;
+	case AGG_TX_STATE_TEST_BAD_CRC32_MSK:
+		priv->reply_agg_tx_stats.bad_crc32++;
+		break;
+	case AGG_TX_STATE_RESPONSE_MSK:
+		priv->reply_agg_tx_stats.response++;
+		break;
+	case AGG_TX_STATE_DUMP_TX_MSK:
+		priv->reply_agg_tx_stats.dump_tx++;
+		break;
+	case AGG_TX_STATE_DELAY_TX_MSK:
+		priv->reply_agg_tx_stats.delay_tx++;
+		break;
+	default:
+		priv->reply_agg_tx_stats.unknown++;
+		break;
+	}
+}
+
+static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
+				struct iwlagn_tx_resp *tx_resp)
+{
+	struct agg_tx_status *frame_status = &tx_resp->status;
+	int tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
+		IWLAGN_TX_RES_TID_POS;
+	int sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
+		IWLAGN_TX_RES_RA_POS;
+	struct iwl_ht_agg *agg = &priv->tid_data[sta_id][tid].agg;
+	u32 status = le16_to_cpu(tx_resp->status.status);
+	int i;
+
+	WARN_ON(tid == IWL_TID_NON_QOS);
+
+	if (agg->wait_for_ba)
+		IWL_DEBUG_TX_REPLY(priv,
+			"got tx response w/o block-ack\n");
+
+	agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+	agg->wait_for_ba = (tx_resp->frame_count > 1);
+
+	/*
+	 * If the BT kill count is non-zero, we'll get this
+	 * notification again.
+	 */
+	if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 &&
+	    priv->cfg->bt_params &&
+	    priv->cfg->bt_params->advanced_bt_coexist) {
+		IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n");
+	}
+
+	if (tx_resp->frame_count == 1)
+		return;
+
+	/* Construct bit-map of pending frames within Tx window */
+	for (i = 0; i < tx_resp->frame_count; i++) {
+		u16 fstatus = le16_to_cpu(frame_status[i].status);
+
+		if (status & AGG_TX_STATUS_MSK)
+			iwlagn_count_agg_tx_err_status(priv, fstatus);
+
+		if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+			      AGG_TX_STATE_ABORT_MSK))
+			continue;
+
+		IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
+				   "try-count (0x%08x)\n",
+				   iwl_get_agg_tx_fail_reason(fstatus),
+				   fstatus & AGG_TX_STATUS_MSK,
+				   fstatus & AGG_TX_TRY_MSK);
+	}
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define AGG_TX_STATE_FAIL(x) case AGG_TX_STATE_ ## x: return #x
+
+const char *iwl_get_agg_tx_fail_reason(u16 status)
+{
+	status &= AGG_TX_STATUS_MSK;
+	switch (status) {
+	case AGG_TX_STATE_TRANSMITTED:
+		return "SUCCESS";
+		AGG_TX_STATE_FAIL(UNDERRUN_MSK);
+		AGG_TX_STATE_FAIL(BT_PRIO_MSK);
+		AGG_TX_STATE_FAIL(FEW_BYTES_MSK);
+		AGG_TX_STATE_FAIL(ABORT_MSK);
+		AGG_TX_STATE_FAIL(LAST_SENT_TTL_MSK);
+		AGG_TX_STATE_FAIL(LAST_SENT_TRY_CNT_MSK);
+		AGG_TX_STATE_FAIL(LAST_SENT_BT_KILL_MSK);
+		AGG_TX_STATE_FAIL(SCD_QUERY_MSK);
+		AGG_TX_STATE_FAIL(TEST_BAD_CRC32_MSK);
+		AGG_TX_STATE_FAIL(RESPONSE_MSK);
+		AGG_TX_STATE_FAIL(DUMP_TX_MSK);
+		AGG_TX_STATE_FAIL(DELAY_TX_MSK);
+	}
+
+	return "UNKNOWN";
+}
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
+{
+	return le32_to_cpup((__le32 *)&tx_resp->status +
+			    tx_resp->frame_count) & MAX_SN;
+}
+
+static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)
+{
+	status &= TX_STATUS_MSK;
+
+	switch (status) {
+	case TX_STATUS_POSTPONE_DELAY:
+		priv->reply_tx_stats.pp_delay++;
+		break;
+	case TX_STATUS_POSTPONE_FEW_BYTES:
+		priv->reply_tx_stats.pp_few_bytes++;
+		break;
+	case TX_STATUS_POSTPONE_BT_PRIO:
+		priv->reply_tx_stats.pp_bt_prio++;
+		break;
+	case TX_STATUS_POSTPONE_QUIET_PERIOD:
+		priv->reply_tx_stats.pp_quiet_period++;
+		break;
+	case TX_STATUS_POSTPONE_CALC_TTAK:
+		priv->reply_tx_stats.pp_calc_ttak++;
+		break;
+	case TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY:
+		priv->reply_tx_stats.int_crossed_retry++;
+		break;
+	case TX_STATUS_FAIL_SHORT_LIMIT:
+		priv->reply_tx_stats.short_limit++;
+		break;
+	case TX_STATUS_FAIL_LONG_LIMIT:
+		priv->reply_tx_stats.long_limit++;
+		break;
+	case TX_STATUS_FAIL_FIFO_UNDERRUN:
+		priv->reply_tx_stats.fifo_underrun++;
+		break;
+	case TX_STATUS_FAIL_DRAIN_FLOW:
+		priv->reply_tx_stats.drain_flow++;
+		break;
+	case TX_STATUS_FAIL_RFKILL_FLUSH:
+		priv->reply_tx_stats.rfkill_flush++;
+		break;
+	case TX_STATUS_FAIL_LIFE_EXPIRE:
+		priv->reply_tx_stats.life_expire++;
+		break;
+	case TX_STATUS_FAIL_DEST_PS:
+		priv->reply_tx_stats.dest_ps++;
+		break;
+	case TX_STATUS_FAIL_HOST_ABORTED:
+		priv->reply_tx_stats.host_abort++;
+		break;
+	case TX_STATUS_FAIL_BT_RETRY:
+		priv->reply_tx_stats.bt_retry++;
+		break;
+	case TX_STATUS_FAIL_STA_INVALID:
+		priv->reply_tx_stats.sta_invalid++;
+		break;
+	case TX_STATUS_FAIL_FRAG_DROPPED:
+		priv->reply_tx_stats.frag_drop++;
+		break;
+	case TX_STATUS_FAIL_TID_DISABLE:
+		priv->reply_tx_stats.tid_disable++;
+		break;
+	case TX_STATUS_FAIL_FIFO_FLUSHED:
+		priv->reply_tx_stats.fifo_flush++;
+		break;
+	case TX_STATUS_FAIL_INSUFFICIENT_CF_POLL:
+		priv->reply_tx_stats.insuff_cf_poll++;
+		break;
+	case TX_STATUS_FAIL_PASSIVE_NO_RX:
+		priv->reply_tx_stats.fail_hw_drop++;
+		break;
+	case TX_STATUS_FAIL_NO_BEACON_ON_RADAR:
+		priv->reply_tx_stats.sta_color_mismatch++;
+		break;
+	default:
+		priv->reply_tx_stats.unknown++;
+		break;
+	}
+}
+
+static void iwlagn_set_tx_status(struct iwl_priv *priv,
+				 struct ieee80211_tx_info *info,
+				 struct iwlagn_tx_resp *tx_resp,
+				 bool is_agg)
+{
+	u16  status = le16_to_cpu(tx_resp->status.status);
+
+	info->status.rates[0].count = tx_resp->failure_frame + 1;
+	if (is_agg)
+		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+	info->flags |= iwl_tx_status_to_mac80211(status);
+	iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
+				    info);
+	if (!iwl_is_tx_success(status))
+		iwlagn_count_tx_err_status(priv, status);
+}
+
+static void iwl_check_abort_status(struct iwl_priv *priv,
+			    u8 frame_count, u32 status)
+{
+	if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
+		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);
+	}
+}
+
+static int iwl_reclaim(struct iwl_priv *priv, int sta_id, int tid,
+		       int txq_id, int ssn, struct sk_buff_head *skbs)
+{
+	if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE &&
+		     tid != IWL_TID_NON_QOS &&
+		     txq_id != priv->tid_data[sta_id][tid].agg.txq_id)) {
+		/*
+		 * FIXME: this is a uCode bug which need to be addressed,
+		 * log the information and return for now.
+		 * Since it is can possibly happen very often and in order
+		 * not to fill the syslog, don't use IWL_ERR or IWL_WARN
+		 */
+		IWL_DEBUG_TX_QUEUES(priv,
+			"Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n",
+			txq_id, sta_id, tid,
+			priv->tid_data[sta_id][tid].agg.txq_id);
+		return 1;
+	}
+
+	iwl_trans_reclaim(priv->trans, txq_id, ssn, skbs);
+	return 0;
+}
+
+int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+			       struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	int cmd_index __maybe_unused = SEQ_TO_INDEX(sequence);
+	struct iwlagn_tx_resp *tx_resp = (void *)pkt->data;
+	struct ieee80211_hdr *hdr;
+	u32 status = le16_to_cpu(tx_resp->status.status);
+	u16 ssn = iwlagn_get_scd_ssn(tx_resp);
+	int tid;
+	int sta_id;
+	int freed;
+	struct ieee80211_tx_info *info;
+	struct sk_buff_head skbs;
+	struct sk_buff *skb;
+	struct iwl_rxon_context *ctx;
+	bool is_agg = (txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
+	bool is_offchannel_skb;
+
+	tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
+		IWLAGN_TX_RES_TID_POS;
+	sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
+		IWLAGN_TX_RES_RA_POS;
+
+	spin_lock(&priv->sta_lock);
+
+	if (is_agg)
+		iwl_rx_reply_tx_agg(priv, tx_resp);
+
+	__skb_queue_head_init(&skbs);
+
+	is_offchannel_skb = false;
+
+	if (tx_resp->frame_count == 1) {
+		u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl);
+		next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10);
+
+		if (is_agg) {
+			/* If this is an aggregation queue, we can rely on the
+			 * ssn since the wifi sequence number corresponds to
+			 * the index in the TFD ring (%256).
+			 * The seq_ctl is the sequence control of the packet
+			 * to which this Tx response relates. But if there is a
+			 * hole in the bitmap of the BA we received, this Tx
+			 * response may allow to reclaim the hole and all the
+			 * subsequent packets that were already acked.
+			 * In that case, seq_ctl != ssn, and the next packet
+			 * to be reclaimed will be ssn and not seq_ctl.
+			 */
+			next_reclaimed = ssn;
+		}
+
+		if (tid != IWL_TID_NON_QOS) {
+			priv->tid_data[sta_id][tid].next_reclaimed =
+				next_reclaimed;
+			IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n",
+						  next_reclaimed);
+		}
+
+		/*we can free until ssn % q.n_bd not inclusive */
+		WARN_ON_ONCE(iwl_reclaim(priv, sta_id, tid,
+					 txq_id, ssn, &skbs));
+		iwlagn_check_ratid_empty(priv, sta_id, tid);
+		freed = 0;
+
+		/* process frames */
+		skb_queue_walk(&skbs, skb) {
+			hdr = (struct ieee80211_hdr *)skb->data;
+
+			if (!ieee80211_is_data_qos(hdr->frame_control))
+				priv->last_seq_ctl = tx_resp->seq_ctl;
+
+			info = IEEE80211_SKB_CB(skb);
+			ctx = info->driver_data[0];
+			iwl_trans_free_tx_cmd(priv->trans,
+					      info->driver_data[1]);
+
+			memset(&info->status, 0, sizeof(info->status));
+
+			if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
+			    iwl_is_associated_ctx(ctx) && ctx->vif &&
+			    ctx->vif->type == NL80211_IFTYPE_STATION) {
+				/* block and stop all queues */
+				priv->passive_no_rx = true;
+				IWL_DEBUG_TX_QUEUES(priv, "stop all queues: "
+						    "passive channel");
+				ieee80211_stop_queues(priv->hw);
+
+				IWL_DEBUG_TX_REPLY(priv,
+					   "TXQ %d status %s (0x%08x) "
+					   "rate_n_flags 0x%x retries %d\n",
+					   txq_id,
+					   iwl_get_tx_fail_reason(status),
+					   status,
+					   le32_to_cpu(tx_resp->rate_n_flags),
+					   tx_resp->failure_frame);
+
+				IWL_DEBUG_TX_REPLY(priv,
+					   "FrameCnt = %d, idx=%d\n",
+					   tx_resp->frame_count, cmd_index);
+			}
+
+			/* check if BAR is needed */
+			if (is_agg && !iwl_is_tx_success(status))
+				info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+			iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(skb),
+				     tx_resp, is_agg);
+			if (!is_agg)
+				iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1);
+
+			is_offchannel_skb =
+				(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN);
+			freed++;
+		}
+
+		WARN_ON(!is_agg && freed != 1);
+
+		/*
+		 * An offchannel frame can be send only on the AUX queue, where
+		 * there is no aggregation (and reordering) so it only is single
+		 * skb is expected to be processed.
+		 */
+		WARN_ON(is_offchannel_skb && freed != 1);
+	}
+
+	iwl_check_abort_status(priv, tx_resp->frame_count, status);
+	spin_unlock(&priv->sta_lock);
+
+	while (!skb_queue_empty(&skbs)) {
+		skb = __skb_dequeue(&skbs);
+		ieee80211_tx_status(priv->hw, skb);
+	}
+
+	if (is_offchannel_skb)
+		iwl_scan_offchannel_skb_status(priv);
+
+	return 0;
+}
+
+/**
+ * iwlagn_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
+ *
+ * Handles block-acknowledge notification from device, which reports success
+ * of frames sent via aggregation.
+ */
+int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+				   struct iwl_rx_cmd_buffer *rxb,
+				   struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data;
+	struct iwl_ht_agg *agg;
+	struct sk_buff_head reclaimed_skbs;
+	struct ieee80211_tx_info *info;
+	struct ieee80211_hdr *hdr;
+	struct sk_buff *skb;
+	int sta_id;
+	int tid;
+	int freed;
+
+	/* "flow" corresponds to Tx queue */
+	u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
+
+	/* "ssn" is start of block-ack Tx window, corresponds to index
+	 * (in Tx queue's circular buffer) of first TFD/frame in window */
+	u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
+
+	if (scd_flow >= priv->cfg->base_params->num_of_queues) {
+		IWL_ERR(priv,
+			"BUG_ON scd_flow is bigger than number of queues\n");
+		return 0;
+	}
+
+	sta_id = ba_resp->sta_id;
+	tid = ba_resp->tid;
+	agg = &priv->tid_data[sta_id][tid].agg;
+
+	spin_lock(&priv->sta_lock);
+
+	if (unlikely(!agg->wait_for_ba)) {
+		if (unlikely(ba_resp->bitmap))
+			IWL_ERR(priv, "Received BA when not expected\n");
+		spin_unlock(&priv->sta_lock);
+		return 0;
+	}
+
+	__skb_queue_head_init(&reclaimed_skbs);
+
+	/* Release all TFDs before the SSN, i.e. all TFDs in front of
+	 * block-ack window (we assume that they've been successfully
+	 * transmitted ... if not, it's too late anyway). */
+	if (iwl_reclaim(priv, sta_id, tid, scd_flow,
+			ba_resp_scd_ssn, &reclaimed_skbs)) {
+		spin_unlock(&priv->sta_lock);
+		return 0;
+	}
+
+	IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
+			   "sta_id = %d\n",
+			   agg->wait_for_ba,
+			   (u8 *) &ba_resp->sta_addr_lo32,
+			   ba_resp->sta_id);
+	IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, "
+			   "scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n",
+			   ba_resp->tid, le16_to_cpu(ba_resp->seq_ctl),
+			   (unsigned long long)le64_to_cpu(ba_resp->bitmap),
+			   scd_flow, ba_resp_scd_ssn, ba_resp->txed,
+			   ba_resp->txed_2_done);
+
+	/* Mark that the expected block-ack response arrived */
+	agg->wait_for_ba = false;
+
+	/* Sanity check values reported by uCode */
+	if (ba_resp->txed_2_done > ba_resp->txed) {
+		IWL_DEBUG_TX_REPLY(priv,
+			"bogus sent(%d) and ack(%d) count\n",
+			ba_resp->txed, ba_resp->txed_2_done);
+		/*
+		 * set txed_2_done = txed,
+		 * so it won't impact rate scale
+		 */
+		ba_resp->txed = ba_resp->txed_2_done;
+	}
+
+	priv->tid_data[sta_id][tid].next_reclaimed = ba_resp_scd_ssn;
+
+	iwlagn_check_ratid_empty(priv, sta_id, tid);
+	freed = 0;
+
+	skb_queue_walk(&reclaimed_skbs, skb) {
+		hdr = (struct ieee80211_hdr *)skb->data;
+
+		if (ieee80211_is_data_qos(hdr->frame_control))
+			freed++;
+		else
+			WARN_ON_ONCE(1);
+
+		info = IEEE80211_SKB_CB(skb);
+		iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
+
+		if (freed == 1) {
+			/* this is the first skb we deliver in this batch */
+			/* put the rate scaling data there */
+			info = IEEE80211_SKB_CB(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 = ba_resp->txed_2_done;
+			info->status.ampdu_len = ba_resp->txed;
+			iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags,
+						    info);
+		}
+	}
+
+	spin_unlock(&priv->sta_lock);
+
+	while (!skb_queue_empty(&reclaimed_skbs)) {
+		skb = __skb_dequeue(&reclaimed_skbs);
+		ieee80211_tx_status(priv->hw, skb);
+	}
+
+	return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c
new file mode 100644
index 0000000..b3a314b
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c
@@ -0,0 +1,520 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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/init.h>
+
+#include "iwl-io.h"
+#include "iwl-agn-hw.h"
+#include "iwl-trans.h"
+#include "iwl-fh.h"
+#include "iwl-op-mode.h"
+
+#include "dev.h"
+#include "agn.h"
+#include "calib.h"
+
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static inline const struct fw_img *
+iwl_get_ucode_image(struct iwl_priv *priv, enum iwl_ucode_type ucode_type)
+{
+	if (ucode_type >= IWL_UCODE_TYPE_MAX)
+		return NULL;
+
+	return &priv->fw->img[ucode_type];
+}
+
+/*
+ *  Calibration
+ */
+static int iwl_set_Xtal_calib(struct iwl_priv *priv)
+{
+	struct iwl_calib_xtal_freq_cmd cmd;
+	__le16 *xtal_calib = priv->eeprom_data->xtal_calib;
+
+	iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD);
+	cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
+	cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
+	return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
+}
+
+static int iwl_set_temperature_offset_calib(struct iwl_priv *priv)
+{
+	struct iwl_calib_temperature_offset_cmd cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
+	cmd.radio_sensor_offset = priv->eeprom_data->raw_temperature;
+	if (!(cmd.radio_sensor_offset))
+		cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET;
+
+	IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n",
+			le16_to_cpu(cmd.radio_sensor_offset));
+	return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
+}
+
+static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv)
+{
+	struct iwl_calib_temperature_offset_v2_cmd cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
+	cmd.radio_sensor_offset_high = priv->eeprom_data->kelvin_temperature;
+	cmd.radio_sensor_offset_low = priv->eeprom_data->raw_temperature;
+	if (!cmd.radio_sensor_offset_low) {
+		IWL_DEBUG_CALIB(priv, "no info in EEPROM, use default\n");
+		cmd.radio_sensor_offset_low = DEFAULT_RADIO_SENSOR_OFFSET;
+		cmd.radio_sensor_offset_high = DEFAULT_RADIO_SENSOR_OFFSET;
+	}
+	cmd.burntVoltageRef = priv->eeprom_data->calib_voltage;
+
+	IWL_DEBUG_CALIB(priv, "Radio sensor offset high: %d\n",
+			le16_to_cpu(cmd.radio_sensor_offset_high));
+	IWL_DEBUG_CALIB(priv, "Radio sensor offset low: %d\n",
+			le16_to_cpu(cmd.radio_sensor_offset_low));
+	IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n",
+			le16_to_cpu(cmd.burntVoltageRef));
+
+	return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
+}
+
+static int iwl_send_calib_cfg(struct iwl_priv *priv)
+{
+	struct iwl_calib_cfg_cmd calib_cfg_cmd;
+	struct iwl_host_cmd cmd = {
+		.id = CALIBRATION_CFG_CMD,
+		.len = { sizeof(struct iwl_calib_cfg_cmd), },
+		.data = { &calib_cfg_cmd, },
+	};
+
+	memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
+	calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
+	calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
+	calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
+	calib_cfg_cmd.ucd_calib_cfg.flags =
+		IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK;
+
+	return iwl_dvm_send_cmd(priv, &cmd);
+}
+
+int iwl_init_alive_start(struct iwl_priv *priv)
+{
+	int ret;
+
+	if (priv->cfg->bt_params &&
+	    priv->cfg->bt_params->advanced_bt_coexist) {
+		/*
+		 * Tell uCode we are ready to perform calibration
+		 * need to perform this before any calibration
+		 * no need to close the envlope since we are going
+		 * to load the runtime uCode later.
+		 */
+		ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+			BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+		if (ret)
+			return ret;
+
+	}
+
+	ret = iwl_send_calib_cfg(priv);
+	if (ret)
+		return ret;
+
+	/**
+	 * temperature offset calibration is only needed for runtime ucode,
+	 * so prepare the value now.
+	 */
+	if (priv->cfg->need_temp_offset_calib) {
+		if (priv->cfg->temp_offset_v2)
+			return iwl_set_temperature_offset_calib_v2(priv);
+		else
+			return iwl_set_temperature_offset_calib(priv);
+	}
+
+	return 0;
+}
+
+static int iwl_send_wimax_coex(struct iwl_priv *priv)
+{
+	struct iwl_wimax_coex_cmd coex_cmd;
+
+	/* coexistence is disabled */
+	memset(&coex_cmd, 0, sizeof(coex_cmd));
+
+	return iwl_dvm_send_cmd_pdu(priv,
+				COEX_PRIORITY_TABLE_CMD, CMD_SYNC,
+				sizeof(coex_cmd), &coex_cmd);
+}
+
+static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
+	((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+	((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+		(1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+	((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+	((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+		(1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+	((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+	((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+		(1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+	((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+	((BT_COEX_PRIO_TBL_PRIO_COEX_OFF << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+	((BT_COEX_PRIO_TBL_PRIO_COEX_ON << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+	0, 0, 0, 0, 0, 0, 0
+};
+
+void iwl_send_prio_tbl(struct iwl_priv *priv)
+{
+	struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd;
+
+	memcpy(prio_tbl_cmd.prio_tbl, iwl_bt_prio_tbl,
+		sizeof(iwl_bt_prio_tbl));
+	if (iwl_dvm_send_cmd_pdu(priv,
+				REPLY_BT_COEX_PRIO_TABLE, CMD_SYNC,
+				sizeof(prio_tbl_cmd), &prio_tbl_cmd))
+		IWL_ERR(priv, "failed to send BT prio tbl command\n");
+}
+
+int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
+{
+	struct iwl_bt_coex_prot_env_cmd env_cmd;
+	int ret;
+
+	env_cmd.action = action;
+	env_cmd.type = type;
+	ret = iwl_dvm_send_cmd_pdu(priv,
+			       REPLY_BT_COEX_PROT_ENV, CMD_SYNC,
+			       sizeof(env_cmd), &env_cmd);
+	if (ret)
+		IWL_ERR(priv, "failed to send BT env command\n");
+	return ret;
+}
+
+
+static int iwl_alive_notify(struct iwl_priv *priv)
+{
+	int ret;
+
+	iwl_trans_fw_alive(priv->trans);
+
+	priv->passive_no_rx = false;
+	priv->transport_queue_stop = 0;
+
+	ret = iwl_send_wimax_coex(priv);
+	if (ret)
+		return ret;
+
+	if (!priv->cfg->no_xtal_calib) {
+		ret = iwl_set_Xtal_calib(priv);
+		if (ret)
+			return ret;
+	}
+
+	return iwl_send_calib_results(priv);
+}
+
+
+/**
+ * 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 iwl_verify_sec_sparse(struct iwl_priv *priv,
+				  const struct fw_desc *fw_desc)
+{
+	__le32 *image = (__le32 *)fw_desc->v_addr;
+	u32 len = fw_desc->len;
+	u32 val;
+	u32 i;
+
+	IWL_DEBUG_FW(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->trans, HBUS_TARG_MEM_RADDR,
+			i + fw_desc->offset);
+		val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+		if (val != le32_to_cpu(*image))
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static void iwl_print_mismatch_sec(struct iwl_priv *priv,
+				    const struct fw_desc *fw_desc)
+{
+	__le32 *image = (__le32 *)fw_desc->v_addr;
+	u32 len = fw_desc->len;
+	u32 val;
+	u32 offs;
+	int errors = 0;
+
+	IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
+
+	iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
+				fw_desc->offset);
+
+	for (offs = 0;
+	     offs < len && errors < 20;
+	     offs += sizeof(u32), image++) {
+		/* read data comes through single port, auto-incr addr */
+		val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+		if (val != le32_to_cpu(*image)) {
+			IWL_ERR(priv, "uCode INST section at "
+				"offset 0x%x, is 0x%x, s/b 0x%x\n",
+				offs, val, le32_to_cpu(*image));
+			errors++;
+		}
+	}
+}
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ *    and verify its contents
+ */
+static int iwl_verify_ucode(struct iwl_priv *priv,
+			    enum iwl_ucode_type ucode_type)
+{
+	const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type);
+
+	if (!img) {
+		IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type);
+		return -EINVAL;
+	}
+
+	if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) {
+		IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
+
+	iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]);
+	return -EIO;
+}
+
+struct iwl_alive_data {
+	bool valid;
+	u8 subtype;
+};
+
+static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
+			 struct iwl_rx_packet *pkt, void *data)
+{
+	struct iwl_priv *priv =
+		container_of(notif_wait, struct iwl_priv, notif_wait);
+	struct iwl_alive_data *alive_data = data;
+	struct iwl_alive_resp *palive;
+
+	palive = (void *)pkt->data;
+
+	IWL_DEBUG_FW(priv, "Alive ucode status 0x%08X revision "
+		       "0x%01X 0x%01X\n",
+		       palive->is_valid, palive->ver_type,
+		       palive->ver_subtype);
+
+	priv->device_pointers.error_event_table =
+		le32_to_cpu(palive->error_event_table_ptr);
+	priv->device_pointers.log_event_table =
+		le32_to_cpu(palive->log_event_table_ptr);
+
+	alive_data->subtype = palive->ver_subtype;
+	alive_data->valid = palive->is_valid == UCODE_VALID_OK;
+
+	return true;
+}
+
+#define UCODE_ALIVE_TIMEOUT	HZ
+#define UCODE_CALIB_TIMEOUT	(2*HZ)
+
+int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
+				 enum iwl_ucode_type ucode_type)
+{
+	struct iwl_notification_wait alive_wait;
+	struct iwl_alive_data alive_data;
+	const struct fw_img *fw;
+	int ret;
+	enum iwl_ucode_type old_type;
+	static const u8 alive_cmd[] = { REPLY_ALIVE };
+
+	old_type = priv->cur_ucode;
+	priv->cur_ucode = ucode_type;
+	fw = iwl_get_ucode_image(priv, ucode_type);
+
+	priv->ucode_loaded = false;
+
+	if (!fw)
+		return -EINVAL;
+
+	iwl_init_notification_wait(&priv->notif_wait, &alive_wait,
+				   alive_cmd, ARRAY_SIZE(alive_cmd),
+				   iwl_alive_fn, &alive_data);
+
+	ret = iwl_trans_start_fw(priv->trans, fw);
+	if (ret) {
+		priv->cur_ucode = old_type;
+		iwl_remove_notification(&priv->notif_wait, &alive_wait);
+		return ret;
+	}
+
+	/*
+	 * Some things may run in the background now, but we
+	 * just wait for the ALIVE notification here.
+	 */
+	ret = iwl_wait_notification(&priv->notif_wait, &alive_wait,
+					UCODE_ALIVE_TIMEOUT);
+	if (ret) {
+		priv->cur_ucode = old_type;
+		return ret;
+	}
+
+	if (!alive_data.valid) {
+		IWL_ERR(priv, "Loaded ucode is not valid!\n");
+		priv->cur_ucode = old_type;
+		return -EIO;
+	}
+
+	/*
+	 * This step takes a long time (60-80ms!!) and
+	 * WoWLAN image should be loaded quickly, so
+	 * skip it for WoWLAN.
+	 */
+	if (ucode_type != IWL_UCODE_WOWLAN) {
+		ret = iwl_verify_ucode(priv, ucode_type);
+		if (ret) {
+			priv->cur_ucode = old_type;
+			return ret;
+		}
+
+		/* delay a bit to give rfkill time to run */
+		msleep(5);
+	}
+
+	ret = iwl_alive_notify(priv);
+	if (ret) {
+		IWL_WARN(priv,
+			"Could not complete ALIVE transition: %d\n", ret);
+		priv->cur_ucode = old_type;
+		return ret;
+	}
+
+	priv->ucode_loaded = true;
+
+	return 0;
+}
+
+static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait,
+			      struct iwl_rx_packet *pkt, void *data)
+{
+	struct iwl_priv *priv = data;
+	struct iwl_calib_hdr *hdr;
+	int len;
+
+	if (pkt->hdr.cmd != CALIBRATION_RES_NOTIFICATION) {
+		WARN_ON(pkt->hdr.cmd != CALIBRATION_COMPLETE_NOTIFICATION);
+		return true;
+	}
+
+	hdr = (struct iwl_calib_hdr *)pkt->data;
+	len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+
+	/* reduce the size by the length field itself */
+	len -= sizeof(__le32);
+
+	if (iwl_calib_set(priv, hdr, len))
+		IWL_ERR(priv, "Failed to record calibration data %d\n",
+			hdr->op_code);
+
+	return false;
+}
+
+int iwl_run_init_ucode(struct iwl_priv *priv)
+{
+	struct iwl_notification_wait calib_wait;
+	static const u8 calib_complete[] = {
+		CALIBRATION_RES_NOTIFICATION,
+		CALIBRATION_COMPLETE_NOTIFICATION
+	};
+	int ret;
+
+	lockdep_assert_held(&priv->mutex);
+
+	/* No init ucode required? Curious, but maybe ok */
+	if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len)
+		return 0;
+
+	if (priv->init_ucode_run)
+		return 0;
+
+	iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
+				   calib_complete, ARRAY_SIZE(calib_complete),
+				   iwlagn_wait_calib, priv);
+
+	/* Will also start the device */
+	ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
+	if (ret)
+		goto error;
+
+	ret = iwl_init_alive_start(priv);
+	if (ret)
+		goto error;
+
+	/*
+	 * Some things may run in the background now, but we
+	 * just wait for the calibration complete notification.
+	 */
+	ret = iwl_wait_notification(&priv->notif_wait, &calib_wait,
+					UCODE_CALIB_TIMEOUT);
+	if (!ret)
+		priv->init_ucode_run = true;
+
+	goto out;
+
+ error:
+	iwl_remove_notification(&priv->notif_wait, &calib_wait);
+ out:
+	/* Whatever happened, stop the device */
+	iwl_trans_stop_device(priv->trans);
+	priv->ucode_loaded = false;
+
+	return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
deleted file mode 100644
index 2629a66..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2012 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.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-cfg.h"
-#include "iwl-csr.h"
-#include "iwl-agn-hw.h"
-
-/* Highest firmware API version supported */
-#define IWL1000_UCODE_API_MAX 5
-#define IWL100_UCODE_API_MAX 5
-
-/* Oldest version we won't warn about */
-#define IWL1000_UCODE_API_OK 5
-#define IWL100_UCODE_API_OK 5
-
-/* Lowest firmware API version supported */
-#define IWL1000_UCODE_API_MIN 1
-#define IWL100_UCODE_API_MIN 5
-
-/* EEPROM version */
-#define EEPROM_1000_TX_POWER_VERSION	(4)
-#define EEPROM_1000_EEPROM_VERSION	(0x15C)
-
-#define IWL1000_FW_PRE "iwlwifi-1000-"
-#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL100_FW_PRE "iwlwifi-100-"
-#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode"
-
-
-static const struct iwl_base_params iwl1000_base_params = {
-	.num_of_queues = IWLAGN_NUM_QUEUES,
-	.eeprom_size = OTP_LOW_IMAGE_SIZE,
-	.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-	.max_ll_items = OTP_MAX_LL_ITEMS_1000,
-	.shadow_ram_support = false,
-	.led_compensation = 51,
-	.support_ct_kill_exit = true,
-	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
-	.chain_noise_scale = 1000,
-	.wd_timeout = IWL_WATCHHDOG_DISABLED,
-	.max_event_log_size = 128,
-};
-
-static const struct iwl_ht_params iwl1000_ht_params = {
-	.ht_greenfield_support = true,
-	.use_rts_for_aggregation = true, /* use rts/cts protection */
-};
-
-#define IWL_DEVICE_1000						\
-	.fw_name_pre = IWL1000_FW_PRE,				\
-	.ucode_api_max = IWL1000_UCODE_API_MAX,			\
-	.ucode_api_ok = IWL1000_UCODE_API_OK,			\
-	.ucode_api_min = IWL1000_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_1000,		\
-	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
-	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_1000_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,	\
-	.base_params = &iwl1000_base_params,			\
-	.led_mode = IWL_LED_BLINK
-
-const struct iwl_cfg iwl1000_bgn_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
-	IWL_DEVICE_1000,
-	.ht_params = &iwl1000_ht_params,
-};
-
-const struct iwl_cfg iwl1000_bg_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 1000 BG",
-	IWL_DEVICE_1000,
-};
-
-#define IWL_DEVICE_100						\
-	.fw_name_pre = IWL100_FW_PRE,				\
-	.ucode_api_max = IWL100_UCODE_API_MAX,			\
-	.ucode_api_ok = IWL100_UCODE_API_OK,			\
-	.ucode_api_min = IWL100_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_100,			\
-	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
-	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_1000_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,	\
-	.base_params = &iwl1000_base_params,			\
-	.led_mode = IWL_LED_RF_STATE,				\
-	.rx_with_siso_diversity = true
-
-const struct iwl_cfg iwl100_bgn_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
-	IWL_DEVICE_100,
-	.ht_params = &iwl1000_ht_params,
-};
-
-const struct iwl_cfg iwl100_bg_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 100 BG",
-	IWL_DEVICE_100,
-};
-
-MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
deleted file mode 100644
index 8133105..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-2000.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2012 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.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-cfg.h"
-#include "iwl-agn-hw.h"
-#include "iwl-commands.h" /* needed for BT for now */
-
-/* Highest firmware API version supported */
-#define IWL2030_UCODE_API_MAX 6
-#define IWL2000_UCODE_API_MAX 6
-#define IWL105_UCODE_API_MAX 6
-#define IWL135_UCODE_API_MAX 6
-
-/* Oldest version we won't warn about */
-#define IWL2030_UCODE_API_OK 6
-#define IWL2000_UCODE_API_OK 6
-#define IWL105_UCODE_API_OK 6
-#define IWL135_UCODE_API_OK 6
-
-/* Lowest firmware API version supported */
-#define IWL2030_UCODE_API_MIN 5
-#define IWL2000_UCODE_API_MIN 5
-#define IWL105_UCODE_API_MIN 5
-#define IWL135_UCODE_API_MIN 5
-
-/* EEPROM version */
-#define EEPROM_2000_TX_POWER_VERSION	(6)
-#define EEPROM_2000_EEPROM_VERSION	(0x805)
-
-
-#define IWL2030_FW_PRE "iwlwifi-2030-"
-#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode"
-
-#define IWL2000_FW_PRE "iwlwifi-2000-"
-#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL105_FW_PRE "iwlwifi-105-"
-#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode"
-
-#define IWL135_FW_PRE "iwlwifi-135-"
-#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode"
-
-static const struct iwl_base_params iwl2000_base_params = {
-	.eeprom_size = OTP_LOW_IMAGE_SIZE,
-	.num_of_queues = IWLAGN_NUM_QUEUES,
-	.pll_cfg_val = 0,
-	.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
-	.shadow_ram_support = true,
-	.led_compensation = 51,
-	.adv_thermal_throttle = true,
-	.support_ct_kill_exit = true,
-	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-	.chain_noise_scale = 1000,
-	.wd_timeout = IWL_DEF_WD_TIMEOUT,
-	.max_event_log_size = 512,
-	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-	.hd_v2 = true,
-};
-
-
-static const struct iwl_base_params iwl2030_base_params = {
-	.eeprom_size = OTP_LOW_IMAGE_SIZE,
-	.num_of_queues = IWLAGN_NUM_QUEUES,
-	.pll_cfg_val = 0,
-	.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
-	.shadow_ram_support = true,
-	.led_compensation = 57,
-	.adv_thermal_throttle = true,
-	.support_ct_kill_exit = true,
-	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-	.chain_noise_scale = 1000,
-	.wd_timeout = IWL_LONG_WD_TIMEOUT,
-	.max_event_log_size = 512,
-	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-	.hd_v2 = true,
-};
-
-static const struct iwl_ht_params iwl2000_ht_params = {
-	.ht_greenfield_support = true,
-	.use_rts_for_aggregation = true, /* use rts/cts protection */
-};
-
-static const struct iwl_bt_params iwl2030_bt_params = {
-	/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
-	.advanced_bt_coexist = true,
-	.agg_time_limit = BT_AGG_THRESHOLD_DEF,
-	.bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-	.bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
-	.bt_sco_disable = true,
-	.bt_session_2 = true,
-};
-
-#define IWL_DEVICE_2000						\
-	.fw_name_pre = IWL2000_FW_PRE,				\
-	.ucode_api_max = IWL2000_UCODE_API_MAX,			\
-	.ucode_api_ok = IWL2000_UCODE_API_OK,			\
-	.ucode_api_min = IWL2000_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_2000,		\
-	.max_inst_size = IWL60_RTC_INST_SIZE,			\
-	.max_data_size = IWL60_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
-	.base_params = &iwl2000_base_params,			\
-	.need_temp_offset_calib = true,				\
-	.temp_offset_v2 = true,					\
-	.led_mode = IWL_LED_RF_STATE
-
-const struct iwl_cfg iwl2000_2bgn_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
-	IWL_DEVICE_2000,
-	.ht_params = &iwl2000_ht_params,
-};
-
-const struct iwl_cfg iwl2000_2bgn_d_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 2200D BGN",
-	IWL_DEVICE_2000,
-	.ht_params = &iwl2000_ht_params,
-};
-
-#define IWL_DEVICE_2030						\
-	.fw_name_pre = IWL2030_FW_PRE,				\
-	.ucode_api_max = IWL2030_UCODE_API_MAX,			\
-	.ucode_api_ok = IWL2030_UCODE_API_OK,			\
-	.ucode_api_min = IWL2030_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_2030,		\
-	.max_inst_size = IWL60_RTC_INST_SIZE,			\
-	.max_data_size = IWL60_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
-	.base_params = &iwl2030_base_params,			\
-	.bt_params = &iwl2030_bt_params,			\
-	.need_temp_offset_calib = true,				\
-	.temp_offset_v2 = true,					\
-	.led_mode = IWL_LED_RF_STATE,				\
-	.adv_pm = true
-
-const struct iwl_cfg iwl2030_2bgn_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
-	IWL_DEVICE_2030,
-	.ht_params = &iwl2000_ht_params,
-};
-
-#define IWL_DEVICE_105						\
-	.fw_name_pre = IWL105_FW_PRE,				\
-	.ucode_api_max = IWL105_UCODE_API_MAX,			\
-	.ucode_api_ok = IWL105_UCODE_API_OK,			\
-	.ucode_api_min = IWL105_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_105,			\
-	.max_inst_size = IWL60_RTC_INST_SIZE,			\
-	.max_data_size = IWL60_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
-	.base_params = &iwl2000_base_params,			\
-	.need_temp_offset_calib = true,				\
-	.temp_offset_v2 = true,					\
-	.led_mode = IWL_LED_RF_STATE,				\
-	.adv_pm = true,						\
-	.rx_with_siso_diversity = true
-
-const struct iwl_cfg iwl105_bgn_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
-	IWL_DEVICE_105,
-	.ht_params = &iwl2000_ht_params,
-};
-
-const struct iwl_cfg iwl105_bgn_d_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 105D BGN",
-	IWL_DEVICE_105,
-	.ht_params = &iwl2000_ht_params,
-};
-
-#define IWL_DEVICE_135						\
-	.fw_name_pre = IWL135_FW_PRE,				\
-	.ucode_api_max = IWL135_UCODE_API_MAX,			\
-	.ucode_api_ok = IWL135_UCODE_API_OK,			\
-	.ucode_api_min = IWL135_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_135,			\
-	.max_inst_size = IWL60_RTC_INST_SIZE,			\
-	.max_data_size = IWL60_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
-	.base_params = &iwl2030_base_params,			\
-	.bt_params = &iwl2030_bt_params,			\
-	.need_temp_offset_calib = true,				\
-	.temp_offset_v2 = true,					\
-	.led_mode = IWL_LED_RF_STATE,				\
-	.adv_pm = true,						\
-	.rx_with_siso_diversity = true
-
-const struct iwl_cfg iwl135_bgn_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
-	IWL_DEVICE_135,
-	.ht_params = &iwl2000_ht_params,
-};
-
-MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_OK));
-MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_OK));
-MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
deleted file mode 100644
index 8e26bc8..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 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.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-cfg.h"
-#include "iwl-agn-hw.h"
-#include "iwl-csr.h"
-
-/* Highest firmware API version supported */
-#define IWL5000_UCODE_API_MAX 5
-#define IWL5150_UCODE_API_MAX 2
-
-/* Oldest version we won't warn about */
-#define IWL5000_UCODE_API_OK 5
-#define IWL5150_UCODE_API_OK 2
-
-/* Lowest firmware API version supported */
-#define IWL5000_UCODE_API_MIN 1
-#define IWL5150_UCODE_API_MIN 1
-
-/* EEPROM versions */
-#define EEPROM_5000_TX_POWER_VERSION	(4)
-#define EEPROM_5000_EEPROM_VERSION	(0x11A)
-#define EEPROM_5050_TX_POWER_VERSION	(4)
-#define EEPROM_5050_EEPROM_VERSION	(0x21E)
-
-#define IWL5000_FW_PRE "iwlwifi-5000-"
-#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL5150_FW_PRE "iwlwifi-5150-"
-#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode"
-
-static const struct iwl_base_params iwl5000_base_params = {
-	.eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
-	.num_of_queues = IWLAGN_NUM_QUEUES,
-	.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-	.led_compensation = 51,
-	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
-	.chain_noise_scale = 1000,
-	.wd_timeout = IWL_WATCHHDOG_DISABLED,
-	.max_event_log_size = 512,
-	.no_idle_support = true,
-};
-
-static const struct iwl_ht_params iwl5000_ht_params = {
-	.ht_greenfield_support = true,
-};
-
-#define IWL_DEVICE_5000						\
-	.fw_name_pre = IWL5000_FW_PRE,				\
-	.ucode_api_max = IWL5000_UCODE_API_MAX,			\
-	.ucode_api_ok = IWL5000_UCODE_API_OK,			\
-	.ucode_api_min = IWL5000_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_5000,		\
-	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
-	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,	\
-	.base_params = &iwl5000_base_params,			\
-	.led_mode = IWL_LED_BLINK
-
-const struct iwl_cfg iwl5300_agn_cfg = {
-	.name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
-	IWL_DEVICE_5000,
-	/* at least EEPROM 0x11A has wrong info */
-	.valid_tx_ant = ANT_ABC,	/* .cfg overwrite */
-	.valid_rx_ant = ANT_ABC,	/* .cfg overwrite */
-	.ht_params = &iwl5000_ht_params,
-};
-
-const struct iwl_cfg iwl5100_bgn_cfg = {
-	.name = "Intel(R) WiFi Link 5100 BGN",
-	IWL_DEVICE_5000,
-	.valid_tx_ant = ANT_B,		/* .cfg overwrite */
-	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */
-	.ht_params = &iwl5000_ht_params,
-};
-
-const struct iwl_cfg iwl5100_abg_cfg = {
-	.name = "Intel(R) WiFi Link 5100 ABG",
-	IWL_DEVICE_5000,
-	.valid_tx_ant = ANT_B,		/* .cfg overwrite */
-	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */
-};
-
-const struct iwl_cfg iwl5100_agn_cfg = {
-	.name = "Intel(R) WiFi Link 5100 AGN",
-	IWL_DEVICE_5000,
-	.valid_tx_ant = ANT_B,		/* .cfg overwrite */
-	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */
-	.ht_params = &iwl5000_ht_params,
-};
-
-const struct iwl_cfg iwl5350_agn_cfg = {
-	.name = "Intel(R) WiMAX/WiFi Link 5350 AGN",
-	.fw_name_pre = IWL5000_FW_PRE,
-	.ucode_api_max = IWL5000_UCODE_API_MAX,
-	.ucode_api_ok = IWL5000_UCODE_API_OK,
-	.ucode_api_min = IWL5000_UCODE_API_MIN,
-	.device_family = IWL_DEVICE_FAMILY_5000,
-	.max_inst_size = IWLAGN_RTC_INST_SIZE,
-	.max_data_size = IWLAGN_RTC_DATA_SIZE,
-	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
-	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-	.base_params = &iwl5000_base_params,
-	.ht_params = &iwl5000_ht_params,
-	.led_mode = IWL_LED_BLINK,
-	.internal_wimax_coex = true,
-};
-
-#define IWL_DEVICE_5150						\
-	.fw_name_pre = IWL5150_FW_PRE,				\
-	.ucode_api_max = IWL5150_UCODE_API_MAX,			\
-	.ucode_api_ok = IWL5150_UCODE_API_OK,			\
-	.ucode_api_min = IWL5150_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_5150,		\
-	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
-	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,	\
-	.base_params = &iwl5000_base_params,			\
-	.no_xtal_calib = true,					\
-	.led_mode = IWL_LED_BLINK,				\
-	.internal_wimax_coex = true
-
-const struct iwl_cfg iwl5150_agn_cfg = {
-	.name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
-	IWL_DEVICE_5150,
-	.ht_params = &iwl5000_ht_params,
-
-};
-
-const struct iwl_cfg iwl5150_abg_cfg = {
-	.name = "Intel(R) WiMAX/WiFi Link 5150 ABG",
-	IWL_DEVICE_5150,
-};
-
-MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
deleted file mode 100644
index e5e8ada..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2012 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.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-cfg.h"
-#include "iwl-agn-hw.h"
-#include "iwl-commands.h" /* needed for BT for now */
-
-/* Highest firmware API version supported */
-#define IWL6000_UCODE_API_MAX 6
-#define IWL6050_UCODE_API_MAX 5
-#define IWL6000G2_UCODE_API_MAX 6
-#define IWL6035_UCODE_API_MAX 6
-
-/* Oldest version we won't warn about */
-#define IWL6000_UCODE_API_OK 4
-#define IWL6000G2_UCODE_API_OK 5
-#define IWL6050_UCODE_API_OK 5
-#define IWL6000G2B_UCODE_API_OK 6
-#define IWL6035_UCODE_API_OK 6
-
-/* Lowest firmware API version supported */
-#define IWL6000_UCODE_API_MIN 4
-#define IWL6050_UCODE_API_MIN 4
-#define IWL6000G2_UCODE_API_MIN 5
-#define IWL6035_UCODE_API_MIN 6
-
-/* EEPROM versions */
-#define EEPROM_6000_TX_POWER_VERSION	(4)
-#define EEPROM_6000_EEPROM_VERSION	(0x423)
-#define EEPROM_6050_TX_POWER_VERSION	(4)
-#define EEPROM_6050_EEPROM_VERSION	(0x532)
-#define EEPROM_6150_TX_POWER_VERSION	(6)
-#define EEPROM_6150_EEPROM_VERSION	(0x553)
-#define EEPROM_6005_TX_POWER_VERSION	(6)
-#define EEPROM_6005_EEPROM_VERSION	(0x709)
-#define EEPROM_6030_TX_POWER_VERSION	(6)
-#define EEPROM_6030_EEPROM_VERSION	(0x709)
-#define EEPROM_6035_TX_POWER_VERSION	(6)
-#define EEPROM_6035_EEPROM_VERSION	(0x753)
-
-#define IWL6000_FW_PRE "iwlwifi-6000-"
-#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL6050_FW_PRE "iwlwifi-6050-"
-#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE __stringify(api) ".ucode"
-
-#define IWL6005_FW_PRE "iwlwifi-6000g2a-"
-#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE __stringify(api) ".ucode"
-
-#define IWL6030_FW_PRE "iwlwifi-6000g2b-"
-#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode"
-
-static const struct iwl_base_params iwl6000_base_params = {
-	.eeprom_size = OTP_LOW_IMAGE_SIZE,
-	.num_of_queues = IWLAGN_NUM_QUEUES,
-	.pll_cfg_val = 0,
-	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-	.shadow_ram_support = true,
-	.led_compensation = 51,
-	.adv_thermal_throttle = true,
-	.support_ct_kill_exit = true,
-	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-	.chain_noise_scale = 1000,
-	.wd_timeout = IWL_DEF_WD_TIMEOUT,
-	.max_event_log_size = 512,
-	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-};
-
-static const struct iwl_base_params iwl6050_base_params = {
-	.eeprom_size = OTP_LOW_IMAGE_SIZE,
-	.num_of_queues = IWLAGN_NUM_QUEUES,
-	.pll_cfg_val = 0,
-	.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
-	.shadow_ram_support = true,
-	.led_compensation = 51,
-	.adv_thermal_throttle = true,
-	.support_ct_kill_exit = true,
-	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-	.chain_noise_scale = 1500,
-	.wd_timeout = IWL_DEF_WD_TIMEOUT,
-	.max_event_log_size = 1024,
-	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-};
-
-static const struct iwl_base_params iwl6000_g2_base_params = {
-	.eeprom_size = OTP_LOW_IMAGE_SIZE,
-	.num_of_queues = IWLAGN_NUM_QUEUES,
-	.pll_cfg_val = 0,
-	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-	.shadow_ram_support = true,
-	.led_compensation = 57,
-	.adv_thermal_throttle = true,
-	.support_ct_kill_exit = true,
-	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-	.chain_noise_scale = 1000,
-	.wd_timeout = IWL_LONG_WD_TIMEOUT,
-	.max_event_log_size = 512,
-	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-};
-
-static const struct iwl_ht_params iwl6000_ht_params = {
-	.ht_greenfield_support = true,
-	.use_rts_for_aggregation = true, /* use rts/cts protection */
-};
-
-static const struct iwl_bt_params iwl6000_bt_params = {
-	/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
-	.advanced_bt_coexist = true,
-	.agg_time_limit = BT_AGG_THRESHOLD_DEF,
-	.bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-	.bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
-	.bt_sco_disable = true,
-};
-
-#define IWL_DEVICE_6005						\
-	.fw_name_pre = IWL6005_FW_PRE,				\
-	.ucode_api_max = IWL6000G2_UCODE_API_MAX,		\
-	.ucode_api_ok = IWL6000G2_UCODE_API_OK,			\
-	.ucode_api_min = IWL6000G2_UCODE_API_MIN,		\
-	.device_family = IWL_DEVICE_FAMILY_6005,		\
-	.max_inst_size = IWL60_RTC_INST_SIZE,			\
-	.max_data_size = IWL60_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_6005_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION,	\
-	.base_params = &iwl6000_g2_base_params,			\
-	.need_temp_offset_calib = true,				\
-	.led_mode = IWL_LED_RF_STATE
-
-const struct iwl_cfg iwl6005_2agn_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
-	IWL_DEVICE_6005,
-	.ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2abg_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6205 ABG",
-	IWL_DEVICE_6005,
-};
-
-const struct iwl_cfg iwl6005_2bg_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6205 BG",
-	IWL_DEVICE_6005,
-};
-
-const struct iwl_cfg iwl6005_2agn_sff_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6205S AGN",
-	IWL_DEVICE_6005,
-	.ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2agn_d_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6205D AGN",
-	IWL_DEVICE_6005,
-	.ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2agn_mow1_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6206 AGN",
-	IWL_DEVICE_6005,
-	.ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6207 AGN",
-	IWL_DEVICE_6005,
-	.ht_params = &iwl6000_ht_params,
-};
-
-#define IWL_DEVICE_6030						\
-	.fw_name_pre = IWL6030_FW_PRE,				\
-	.ucode_api_max = IWL6000G2_UCODE_API_MAX,		\
-	.ucode_api_ok = IWL6000G2B_UCODE_API_OK,		\
-	.ucode_api_min = IWL6000G2_UCODE_API_MIN,		\
-	.device_family = IWL_DEVICE_FAMILY_6030,		\
-	.max_inst_size = IWL60_RTC_INST_SIZE,			\
-	.max_data_size = IWL60_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_6030_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,	\
-	.base_params = &iwl6000_g2_base_params,			\
-	.bt_params = &iwl6000_bt_params,			\
-	.need_temp_offset_calib = true,				\
-	.led_mode = IWL_LED_RF_STATE,				\
-	.adv_pm = true						\
-
-const struct iwl_cfg iwl6030_2agn_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
-	IWL_DEVICE_6030,
-	.ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6030_2abg_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6230 ABG",
-	IWL_DEVICE_6030,
-};
-
-const struct iwl_cfg iwl6030_2bgn_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6230 BGN",
-	IWL_DEVICE_6030,
-	.ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6030_2bg_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6230 BG",
-	IWL_DEVICE_6030,
-};
-
-#define IWL_DEVICE_6035						\
-	.fw_name_pre = IWL6030_FW_PRE,				\
-	.ucode_api_max = IWL6035_UCODE_API_MAX,			\
-	.ucode_api_ok = IWL6035_UCODE_API_OK,			\
-	.ucode_api_min = IWL6035_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_6030,		\
-	.max_inst_size = IWL60_RTC_INST_SIZE,			\
-	.max_data_size = IWL60_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_6030_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,	\
-	.base_params = &iwl6000_g2_base_params,			\
-	.bt_params = &iwl6000_bt_params,			\
-	.need_temp_offset_calib = true,				\
-	.led_mode = IWL_LED_RF_STATE,				\
-	.adv_pm = true
-
-const struct iwl_cfg iwl6035_2agn_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
-	IWL_DEVICE_6035,
-	.ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl1030_bgn_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
-	IWL_DEVICE_6030,
-	.ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl1030_bg_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 1030 BG",
-	IWL_DEVICE_6030,
-};
-
-const struct iwl_cfg iwl130_bgn_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 130 BGN",
-	IWL_DEVICE_6030,
-	.ht_params = &iwl6000_ht_params,
-	.rx_with_siso_diversity = true,
-};
-
-const struct iwl_cfg iwl130_bg_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N 130 BG",
-	IWL_DEVICE_6030,
-	.rx_with_siso_diversity = true,
-};
-
-/*
- * "i": Internal configuration, use internal Power Amplifier
- */
-#define IWL_DEVICE_6000i					\
-	.fw_name_pre = IWL6000_FW_PRE,				\
-	.ucode_api_max = IWL6000_UCODE_API_MAX,			\
-	.ucode_api_ok = IWL6000_UCODE_API_OK,			\
-	.ucode_api_min = IWL6000_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_6000i,		\
-	.max_inst_size = IWL60_RTC_INST_SIZE,			\
-	.max_data_size = IWL60_RTC_DATA_SIZE,			\
-	.valid_tx_ant = ANT_BC,		/* .cfg overwrite */	\
-	.valid_rx_ant = ANT_BC,		/* .cfg overwrite */	\
-	.eeprom_ver = EEPROM_6000_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,	\
-	.base_params = &iwl6000_base_params,			\
-	.led_mode = IWL_LED_BLINK
-
-const struct iwl_cfg iwl6000i_2agn_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
-	IWL_DEVICE_6000i,
-	.ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6000i_2abg_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6200 ABG",
-	IWL_DEVICE_6000i,
-};
-
-const struct iwl_cfg iwl6000i_2bg_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N 6200 BG",
-	IWL_DEVICE_6000i,
-};
-
-#define IWL_DEVICE_6050						\
-	.fw_name_pre = IWL6050_FW_PRE,				\
-	.ucode_api_max = IWL6050_UCODE_API_MAX,			\
-	.ucode_api_min = IWL6050_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_6050,		\
-	.max_inst_size = IWL60_RTC_INST_SIZE,			\
-	.max_data_size = IWL60_RTC_DATA_SIZE,			\
-	.valid_tx_ant = ANT_AB,		/* .cfg overwrite */	\
-	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */	\
-	.eeprom_ver = EEPROM_6050_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,	\
-	.base_params = &iwl6050_base_params,			\
-	.led_mode = IWL_LED_BLINK,				\
-	.internal_wimax_coex = true
-
-const struct iwl_cfg iwl6050_2agn_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
-	IWL_DEVICE_6050,
-	.ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6050_2abg_cfg = {
-	.name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG",
-	IWL_DEVICE_6050,
-};
-
-#define IWL_DEVICE_6150						\
-	.fw_name_pre = IWL6050_FW_PRE,				\
-	.ucode_api_max = IWL6050_UCODE_API_MAX,			\
-	.ucode_api_min = IWL6050_UCODE_API_MIN,			\
-	.device_family = IWL_DEVICE_FAMILY_6150,		\
-	.max_inst_size = IWL60_RTC_INST_SIZE,			\
-	.max_data_size = IWL60_RTC_DATA_SIZE,			\
-	.eeprom_ver = EEPROM_6150_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION,	\
-	.base_params = &iwl6050_base_params,			\
-	.led_mode = IWL_LED_BLINK,				\
-	.internal_wimax_coex = true
-
-const struct iwl_cfg iwl6150_bgn_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
-	IWL_DEVICE_6150,
-	.ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6150_bg_cfg = {
-	.name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BG",
-	IWL_DEVICE_6150,
-};
-
-const struct iwl_cfg iwl6000_3agn_cfg = {
-	.name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN",
-	.fw_name_pre = IWL6000_FW_PRE,
-	.ucode_api_max = IWL6000_UCODE_API_MAX,
-	.ucode_api_ok = IWL6000_UCODE_API_OK,
-	.ucode_api_min = IWL6000_UCODE_API_MIN,
-	.device_family = IWL_DEVICE_FAMILY_6000,
-	.max_inst_size = IWL60_RTC_INST_SIZE,
-	.max_data_size = IWL60_RTC_DATA_SIZE,
-	.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
-	.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
-	.base_params = &iwl6000_base_params,
-	.ht_params = &iwl6000_ht_params,
-	.led_mode = IWL_LED_BLINK,
-};
-
-MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_OK));
-MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_OK));
-MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2B_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
deleted file mode 100644
index 95f27f1..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ /dev/null
@@ -1,1112 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-#include <linux/slab.h>
-#include <net/mac80211.h>
-
-#include "iwl-dev.h"
-#include "iwl-agn-calib.h"
-#include "iwl-trans.h"
-#include "iwl-agn.h"
-
-/*****************************************************************************
- * INIT calibrations framework
- *****************************************************************************/
-
-/* Opaque calibration results */
-struct iwl_calib_result {
-	struct list_head list;
-	size_t cmd_len;
-	struct iwl_calib_hdr hdr;
-	/* data follows */
-};
-
-struct statistics_general_data {
-	u32 beacon_silence_rssi_a;
-	u32 beacon_silence_rssi_b;
-	u32 beacon_silence_rssi_c;
-	u32 beacon_energy_a;
-	u32 beacon_energy_b;
-	u32 beacon_energy_c;
-};
-
-int iwl_send_calib_results(struct iwl_priv *priv)
-{
-	struct iwl_host_cmd hcmd = {
-		.id = REPLY_PHY_CALIBRATION_CMD,
-		.flags = CMD_SYNC,
-	};
-	struct iwl_calib_result *res;
-
-	list_for_each_entry(res, &priv->calib_results, list) {
-		int ret;
-
-		hcmd.len[0] = res->cmd_len;
-		hcmd.data[0] = &res->hdr;
-		hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-		ret = iwl_dvm_send_cmd(priv, &hcmd);
-		if (ret) {
-			IWL_ERR(priv, "Error %d on calib cmd %d\n",
-				ret, res->hdr.op_code);
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-int iwl_calib_set(struct iwl_priv *priv,
-		  const struct iwl_calib_hdr *cmd, int len)
-{
-	struct iwl_calib_result *res, *tmp;
-
-	res = kmalloc(sizeof(*res) + len - sizeof(struct iwl_calib_hdr),
-		      GFP_ATOMIC);
-	if (!res)
-		return -ENOMEM;
-	memcpy(&res->hdr, cmd, len);
-	res->cmd_len = len;
-
-	list_for_each_entry(tmp, &priv->calib_results, list) {
-		if (tmp->hdr.op_code == res->hdr.op_code) {
-			list_replace(&tmp->list, &res->list);
-			kfree(tmp);
-			return 0;
-		}
-	}
-
-	/* wasn't in list already */
-	list_add_tail(&res->list, &priv->calib_results);
-
-	return 0;
-}
-
-void iwl_calib_free_results(struct iwl_priv *priv)
-{
-	struct iwl_calib_result *res, *tmp;
-
-	list_for_each_entry_safe(res, tmp, &priv->calib_results, list) {
-		list_del(&res->list);
-		kfree(res);
-	}
-}
-
-/*****************************************************************************
- * RUNTIME calibrations framework
- *****************************************************************************/
-
-/* "false alarms" are signals that our DSP tries to lock onto,
- *   but then determines that they are either noise, or transmissions
- *   from a distant wireless network (also "noise", really) that get
- *   "stepped on" by stronger transmissions within our own network.
- * This algorithm attempts to set a sensitivity level that is high
- *   enough to receive all of our own network traffic, but not so
- *   high that our DSP gets too busy trying to lock onto non-network
- *   activity/noise. */
-static int iwl_sens_energy_cck(struct iwl_priv *priv,
-				   u32 norm_fa,
-				   u32 rx_enable_time,
-				   struct statistics_general_data *rx_info)
-{
-	u32 max_nrg_cck = 0;
-	int i = 0;
-	u8 max_silence_rssi = 0;
-	u32 silence_ref = 0;
-	u8 silence_rssi_a = 0;
-	u8 silence_rssi_b = 0;
-	u8 silence_rssi_c = 0;
-	u32 val;
-
-	/* "false_alarms" values below are cross-multiplications to assess the
-	 *   numbers of false alarms within the measured period of actual Rx
-	 *   (Rx is off when we're txing), vs the min/max expected false alarms
-	 *   (some should be expected if rx is sensitive enough) in a
-	 *   hypothetical listening period of 200 time units (TU), 204.8 msec:
-	 *
-	 * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
-	 *
-	 * */
-	u32 false_alarms = norm_fa * 200 * 1024;
-	u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
-	u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
-	struct iwl_sensitivity_data *data = NULL;
-	const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
-
-	data = &(priv->sensitivity_data);
-
-	data->nrg_auto_corr_silence_diff = 0;
-
-	/* Find max silence rssi among all 3 receivers.
-	 * This is background noise, which may include transmissions from other
-	 *    networks, measured during silence before our network's beacon */
-	silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
-			    ALL_BAND_FILTER) >> 8);
-	silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
-			    ALL_BAND_FILTER) >> 8);
-	silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
-			    ALL_BAND_FILTER) >> 8);
-
-	val = max(silence_rssi_b, silence_rssi_c);
-	max_silence_rssi = max(silence_rssi_a, (u8) val);
-
-	/* Store silence rssi in 20-beacon history table */
-	data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
-	data->nrg_silence_idx++;
-	if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
-		data->nrg_silence_idx = 0;
-
-	/* Find max silence rssi across 20 beacon history */
-	for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
-		val = data->nrg_silence_rssi[i];
-		silence_ref = max(silence_ref, val);
-	}
-	IWL_DEBUG_CALIB(priv, "silence a %u, b %u, c %u, 20-bcn max %u\n",
-			silence_rssi_a, silence_rssi_b, silence_rssi_c,
-			silence_ref);
-
-	/* Find max rx energy (min value!) among all 3 receivers,
-	 *   measured during beacon frame.
-	 * Save it in 10-beacon history table. */
-	i = data->nrg_energy_idx;
-	val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
-	data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
-
-	data->nrg_energy_idx++;
-	if (data->nrg_energy_idx >= 10)
-		data->nrg_energy_idx = 0;
-
-	/* Find min rx energy (max value) across 10 beacon history.
-	 * This is the minimum signal level that we want to receive well.
-	 * Add backoff (margin so we don't miss slightly lower energy frames).
-	 * This establishes an upper bound (min value) for energy threshold. */
-	max_nrg_cck = data->nrg_value[0];
-	for (i = 1; i < 10; i++)
-		max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
-	max_nrg_cck += 6;
-
-	IWL_DEBUG_CALIB(priv, "rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
-			rx_info->beacon_energy_a, rx_info->beacon_energy_b,
-			rx_info->beacon_energy_c, max_nrg_cck - 6);
-
-	/* Count number of consecutive beacons with fewer-than-desired
-	 *   false alarms. */
-	if (false_alarms < min_false_alarms)
-		data->num_in_cck_no_fa++;
-	else
-		data->num_in_cck_no_fa = 0;
-	IWL_DEBUG_CALIB(priv, "consecutive bcns with few false alarms = %u\n",
-			data->num_in_cck_no_fa);
-
-	/* If we got too many false alarms this time, reduce sensitivity */
-	if ((false_alarms > max_false_alarms) &&
-		(data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK)) {
-		IWL_DEBUG_CALIB(priv, "norm FA %u > max FA %u\n",
-		     false_alarms, max_false_alarms);
-		IWL_DEBUG_CALIB(priv, "... reducing sensitivity\n");
-		data->nrg_curr_state = IWL_FA_TOO_MANY;
-		/* Store for "fewer than desired" on later beacon */
-		data->nrg_silence_ref = silence_ref;
-
-		/* increase energy threshold (reduce nrg value)
-		 *   to decrease sensitivity */
-		data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK;
-	/* Else if we got fewer than desired, increase sensitivity */
-	} else if (false_alarms < min_false_alarms) {
-		data->nrg_curr_state = IWL_FA_TOO_FEW;
-
-		/* Compare silence level with silence level for most recent
-		 *   healthy number or too many false alarms */
-		data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
-						   (s32)silence_ref;
-
-		IWL_DEBUG_CALIB(priv, "norm FA %u < min FA %u, silence diff %d\n",
-			 false_alarms, min_false_alarms,
-			 data->nrg_auto_corr_silence_diff);
-
-		/* Increase value to increase sensitivity, but only if:
-		 * 1a) previous beacon did *not* have *too many* false alarms
-		 * 1b) AND there's a significant difference in Rx levels
-		 *      from a previous beacon with too many, or healthy # FAs
-		 * OR 2) We've seen a lot of beacons (100) with too few
-		 *       false alarms */
-		if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
-			((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
-			(data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
-
-			IWL_DEBUG_CALIB(priv, "... increasing sensitivity\n");
-			/* Increase nrg value to increase sensitivity */
-			val = data->nrg_th_cck + NRG_STEP_CCK;
-			data->nrg_th_cck = min((u32)ranges->min_nrg_cck, val);
-		} else {
-			IWL_DEBUG_CALIB(priv, "... but not changing sensitivity\n");
-		}
-
-	/* Else we got a healthy number of false alarms, keep status quo */
-	} else {
-		IWL_DEBUG_CALIB(priv, " FA in safe zone\n");
-		data->nrg_curr_state = IWL_FA_GOOD_RANGE;
-
-		/* Store for use in "fewer than desired" with later beacon */
-		data->nrg_silence_ref = silence_ref;
-
-		/* If previous beacon had too many false alarms,
-		 *   give it some extra margin by reducing sensitivity again
-		 *   (but don't go below measured energy of desired Rx) */
-		if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
-			IWL_DEBUG_CALIB(priv, "... increasing margin\n");
-			if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN))
-				data->nrg_th_cck -= NRG_MARGIN;
-			else
-				data->nrg_th_cck = max_nrg_cck;
-		}
-	}
-
-	/* Make sure the energy threshold does not go above the measured
-	 * energy of the desired Rx signals (reduced by backoff margin),
-	 * or else we might start missing Rx frames.
-	 * Lower value is higher energy, so we use max()!
-	 */
-	data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
-	IWL_DEBUG_CALIB(priv, "new nrg_th_cck %u\n", data->nrg_th_cck);
-
-	data->nrg_prev_state = data->nrg_curr_state;
-
-	/* Auto-correlation CCK algorithm */
-	if (false_alarms > min_false_alarms) {
-
-		/* increase auto_corr values to decrease sensitivity
-		 * so the DSP won't be disturbed by the noise
-		 */
-		if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
-			data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1;
-		else {
-			val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
-			data->auto_corr_cck =
-				min((u32)ranges->auto_corr_max_cck, val);
-		}
-		val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
-		data->auto_corr_cck_mrc =
-			min((u32)ranges->auto_corr_max_cck_mrc, val);
-	} else if ((false_alarms < min_false_alarms) &&
-	   ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
-	   (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
-
-		/* Decrease auto_corr values to increase sensitivity */
-		val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
-		data->auto_corr_cck =
-			max((u32)ranges->auto_corr_min_cck, val);
-		val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
-		data->auto_corr_cck_mrc =
-			max((u32)ranges->auto_corr_min_cck_mrc, val);
-	}
-
-	return 0;
-}
-
-
-static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
-				       u32 norm_fa,
-				       u32 rx_enable_time)
-{
-	u32 val;
-	u32 false_alarms = norm_fa * 200 * 1024;
-	u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
-	u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
-	struct iwl_sensitivity_data *data = NULL;
-	const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
-
-	data = &(priv->sensitivity_data);
-
-	/* If we got too many false alarms this time, reduce sensitivity */
-	if (false_alarms > max_false_alarms) {
-
-		IWL_DEBUG_CALIB(priv, "norm FA %u > max FA %u)\n",
-			     false_alarms, max_false_alarms);
-
-		val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM;
-		data->auto_corr_ofdm =
-			min((u32)ranges->auto_corr_max_ofdm, val);
-
-		val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM;
-		data->auto_corr_ofdm_mrc =
-			min((u32)ranges->auto_corr_max_ofdm_mrc, val);
-
-		val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM;
-		data->auto_corr_ofdm_x1 =
-			min((u32)ranges->auto_corr_max_ofdm_x1, val);
-
-		val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM;
-		data->auto_corr_ofdm_mrc_x1 =
-			min((u32)ranges->auto_corr_max_ofdm_mrc_x1, val);
-	}
-
-	/* Else if we got fewer than desired, increase sensitivity */
-	else if (false_alarms < min_false_alarms) {
-
-		IWL_DEBUG_CALIB(priv, "norm FA %u < min FA %u\n",
-			     false_alarms, min_false_alarms);
-
-		val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM;
-		data->auto_corr_ofdm =
-			max((u32)ranges->auto_corr_min_ofdm, val);
-
-		val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM;
-		data->auto_corr_ofdm_mrc =
-			max((u32)ranges->auto_corr_min_ofdm_mrc, val);
-
-		val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM;
-		data->auto_corr_ofdm_x1 =
-			max((u32)ranges->auto_corr_min_ofdm_x1, val);
-
-		val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM;
-		data->auto_corr_ofdm_mrc_x1 =
-			max((u32)ranges->auto_corr_min_ofdm_mrc_x1, val);
-	} else {
-		IWL_DEBUG_CALIB(priv, "min FA %u < norm FA %u < max FA %u OK\n",
-			 min_false_alarms, false_alarms, max_false_alarms);
-	}
-	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_data *data = NULL;
-	struct iwl_host_cmd cmd_out = {
-		.id = SENSITIVITY_CMD,
-		.len = { sizeof(struct iwl_sensitivity_cmd), },
-		.flags = CMD_ASYNC,
-		.data = { &cmd, },
-	};
-
-	data = &(priv->sensitivity_data);
-
-	memset(&cmd, 0, sizeof(cmd));
-
-	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;
-
-	/* Don't send command to uCode if nothing has changed */
-	if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
-		    sizeof(u16)*HD_TABLE_SIZE)) {
-		IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n");
-		return 0;
-	}
-
-	/* Copy table for comparison next time */
-	memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
-	       sizeof(u16)*HD_TABLE_SIZE);
-
-	return iwl_dvm_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]);
-
-	if (priv->cfg->base_params->hd_v2) {
-		cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
-			HD_INA_NON_SQUARE_DET_OFDM_DATA_V2;
-		cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
-			HD_INA_NON_SQUARE_DET_CCK_DATA_V2;
-		cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
-			HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2;
-		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
-			HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
-		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
-			HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
-		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
-			HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2;
-		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
-			HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2;
-		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
-			HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
-		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
-			HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
-		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
-			HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2;
-		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
-			HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2;
-	} else {
-		cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
-			HD_INA_NON_SQUARE_DET_OFDM_DATA_V1;
-		cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
-			HD_INA_NON_SQUARE_DET_CCK_DATA_V1;
-		cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
-			HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1;
-		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
-			HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
-		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
-			HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
-		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
-			HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1;
-		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
-			HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1;
-		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
-			HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
-		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
-			HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
-		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
-			HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1;
-		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
-			HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1;
-	}
-
-	/* 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_dvm_send_cmd(priv, &cmd_out);
-}
-
-void iwl_init_sensitivity(struct iwl_priv *priv)
-{
-	int ret = 0;
-	int i;
-	struct iwl_sensitivity_data *data = NULL;
-	const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
-
-	if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED)
-		return;
-
-	IWL_DEBUG_CALIB(priv, "Start iwl_init_sensitivity\n");
-
-	/* Clear driver's sensitivity algo data */
-	data = &(priv->sensitivity_data);
-
-	if (ranges == NULL)
-		return;
-
-	memset(data, 0, sizeof(struct iwl_sensitivity_data));
-
-	data->num_in_cck_no_fa = 0;
-	data->nrg_curr_state = IWL_FA_TOO_MANY;
-	data->nrg_prev_state = IWL_FA_TOO_MANY;
-	data->nrg_silence_ref = 0;
-	data->nrg_silence_idx = 0;
-	data->nrg_energy_idx = 0;
-
-	for (i = 0; i < 10; i++)
-		data->nrg_value[i] = 0;
-
-	for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
-		data->nrg_silence_rssi[i] = 0;
-
-	data->auto_corr_ofdm =  ranges->auto_corr_min_ofdm;
-	data->auto_corr_ofdm_mrc = ranges->auto_corr_min_ofdm_mrc;
-	data->auto_corr_ofdm_x1  = ranges->auto_corr_min_ofdm_x1;
-	data->auto_corr_ofdm_mrc_x1 = ranges->auto_corr_min_ofdm_mrc_x1;
-	data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF;
-	data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc;
-	data->nrg_th_cck = ranges->nrg_th_cck;
-	data->nrg_th_ofdm = ranges->nrg_th_ofdm;
-	data->barker_corr_th_min = ranges->barker_corr_th_min;
-	data->barker_corr_th_min_mrc = ranges->barker_corr_th_min_mrc;
-	data->nrg_th_cca = ranges->nrg_th_cca;
-
-	data->last_bad_plcp_cnt_ofdm = 0;
-	data->last_fa_cnt_ofdm = 0;
-	data->last_bad_plcp_cnt_cck = 0;
-	data->last_fa_cnt_cck = 0;
-
-	if (priv->fw->enhance_sensitivity_table)
-		ret |= iwl_enhance_sensitivity_write(priv);
-	else
-		ret |= iwl_sensitivity_write(priv);
-	IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
-}
-
-void iwl_sensitivity_calibration(struct iwl_priv *priv)
-{
-	u32 rx_enable_time;
-	u32 fa_cck;
-	u32 fa_ofdm;
-	u32 bad_plcp_cck;
-	u32 bad_plcp_ofdm;
-	u32 norm_fa_ofdm;
-	u32 norm_fa_cck;
-	struct iwl_sensitivity_data *data = NULL;
-	struct statistics_rx_non_phy *rx_info;
-	struct statistics_rx_phy *ofdm, *cck;
-	struct statistics_general_data statis;
-
-	if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED)
-		return;
-
-	data = &(priv->sensitivity_data);
-
-	if (!iwl_is_any_associated(priv)) {
-		IWL_DEBUG_CALIB(priv, "<< - not associated\n");
-		return;
-	}
-
-	spin_lock_bh(&priv->statistics.lock);
-	rx_info = &priv->statistics.rx_non_phy;
-	ofdm = &priv->statistics.rx_ofdm;
-	cck = &priv->statistics.rx_cck;
-	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
-		IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
-		spin_unlock_bh(&priv->statistics.lock);
-		return;
-	}
-
-	/* Extract Statistics: */
-	rx_enable_time = le32_to_cpu(rx_info->channel_load);
-	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(rx_info->beacon_silence_rssi_a);
-	statis.beacon_silence_rssi_b =
-			le32_to_cpu(rx_info->beacon_silence_rssi_b);
-	statis.beacon_silence_rssi_c =
-			le32_to_cpu(rx_info->beacon_silence_rssi_c);
-	statis.beacon_energy_a =
-			le32_to_cpu(rx_info->beacon_energy_a);
-	statis.beacon_energy_b =
-			le32_to_cpu(rx_info->beacon_energy_b);
-	statis.beacon_energy_c =
-			le32_to_cpu(rx_info->beacon_energy_c);
-
-	spin_unlock_bh(&priv->statistics.lock);
-
-	IWL_DEBUG_CALIB(priv, "rx_enable_time = %u usecs\n", rx_enable_time);
-
-	if (!rx_enable_time) {
-		IWL_DEBUG_CALIB(priv, "<< RX Enable Time == 0!\n");
-		return;
-	}
-
-	/* These statistics increase monotonically, and do not reset
-	 *   at each beacon.  Calculate difference from last value, or just
-	 *   use the new statistics value if it has reset or wrapped around. */
-	if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
-		data->last_bad_plcp_cnt_cck = bad_plcp_cck;
-	else {
-		bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
-		data->last_bad_plcp_cnt_cck += bad_plcp_cck;
-	}
-
-	if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm)
-		data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm;
-	else {
-		bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm;
-		data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm;
-	}
-
-	if (data->last_fa_cnt_ofdm > fa_ofdm)
-		data->last_fa_cnt_ofdm = fa_ofdm;
-	else {
-		fa_ofdm -= data->last_fa_cnt_ofdm;
-		data->last_fa_cnt_ofdm += fa_ofdm;
-	}
-
-	if (data->last_fa_cnt_cck > fa_cck)
-		data->last_fa_cnt_cck = fa_cck;
-	else {
-		fa_cck -= data->last_fa_cnt_cck;
-		data->last_fa_cnt_cck += fa_cck;
-	}
-
-	/* Total aborted signal locks */
-	norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm;
-	norm_fa_cck = fa_cck + bad_plcp_cck;
-
-	IWL_DEBUG_CALIB(priv, "cck: fa %u badp %u  ofdm: fa %u badp %u\n", fa_cck,
-			bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
-
-	iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
-	iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
-	if (priv->fw->enhance_sensitivity_table)
-		iwl_enhance_sensitivity_write(priv);
-	else
-		iwl_sensitivity_write(priv);
-}
-
-static inline u8 find_first_chain(u8 mask)
-{
-	if (mask & ANT_A)
-		return CHAIN_A;
-	if (mask & ANT_B)
-		return CHAIN_B;
-	return CHAIN_C;
-}
-
-/**
- * Run disconnected antenna algorithm to find out which antennas are
- * disconnected.
- */
-static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
-				     struct iwl_chain_noise_data *data)
-{
-	u32 active_chains = 0;
-	u32 max_average_sig;
-	u16 max_average_sig_antenna_i;
-	u8 num_tx_chains;
-	u8 first_chain;
-	u16 i = 0;
-
-	average_sig[0] = data->chain_signal_a / IWL_CAL_NUM_BEACONS;
-	average_sig[1] = data->chain_signal_b / IWL_CAL_NUM_BEACONS;
-	average_sig[2] = data->chain_signal_c / IWL_CAL_NUM_BEACONS;
-
-	if (average_sig[0] >= average_sig[1]) {
-		max_average_sig = average_sig[0];
-		max_average_sig_antenna_i = 0;
-		active_chains = (1 << max_average_sig_antenna_i);
-	} else {
-		max_average_sig = average_sig[1];
-		max_average_sig_antenna_i = 1;
-		active_chains = (1 << max_average_sig_antenna_i);
-	}
-
-	if (average_sig[2] >= max_average_sig) {
-		max_average_sig = average_sig[2];
-		max_average_sig_antenna_i = 2;
-		active_chains = (1 << max_average_sig_antenna_i);
-	}
-
-	IWL_DEBUG_CALIB(priv, "average_sig: a %d b %d c %d\n",
-		     average_sig[0], average_sig[1], average_sig[2]);
-	IWL_DEBUG_CALIB(priv, "max_average_sig = %d, antenna %d\n",
-		     max_average_sig, max_average_sig_antenna_i);
-
-	/* Compare signal strengths for all 3 receivers. */
-	for (i = 0; i < NUM_RX_CHAINS; i++) {
-		if (i != max_average_sig_antenna_i) {
-			s32 rssi_delta = (max_average_sig - average_sig[i]);
-
-			/* If signal is very weak, compared with
-			 * strongest, mark it as disconnected. */
-			if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
-				data->disconn_array[i] = 1;
-			else
-				active_chains |= (1 << i);
-			IWL_DEBUG_CALIB(priv, "i = %d  rssiDelta = %d  "
-			     "disconn_array[i] = %d\n",
-			     i, rssi_delta, data->disconn_array[i]);
-		}
-	}
-
-	/*
-	 * The above algorithm sometimes fails when the ucode
-	 * reports 0 for all chains. It's not clear why that
-	 * happens to start with, but it is then causing trouble
-	 * because this can make us enable more chains than the
-	 * hardware really has.
-	 *
-	 * To be safe, simply mask out any chains that we know
-	 * are not on the device.
-	 */
-	active_chains &= priv->hw_params.valid_rx_ant;
-
-	num_tx_chains = 0;
-	for (i = 0; i < NUM_RX_CHAINS; i++) {
-		/* loops on all the bits of
-		 * priv->hw_setting.valid_tx_ant */
-		u8 ant_msk = (1 << i);
-		if (!(priv->hw_params.valid_tx_ant & ant_msk))
-			continue;
-
-		num_tx_chains++;
-		if (data->disconn_array[i] == 0)
-			/* there is a Tx antenna connected */
-			break;
-		if (num_tx_chains == priv->hw_params.tx_chains_num &&
-		    data->disconn_array[i]) {
-			/*
-			 * If all chains are disconnected
-			 * connect the first valid tx chain
-			 */
-			first_chain =
-				find_first_chain(priv->hw_params.valid_tx_ant);
-			data->disconn_array[first_chain] = 0;
-			active_chains |= BIT(first_chain);
-			IWL_DEBUG_CALIB(priv,
-					"All Tx chains are disconnected W/A - declare %d as connected\n",
-					first_chain);
-			break;
-		}
-	}
-
-	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. */
-	data->active_chains = active_chains;
-	IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
-			active_chains);
-}
-
-static void iwlagn_gain_computation(struct iwl_priv *priv,
-				    u32 average_noise[NUM_RX_CHAINS],
-				    u8 default_chain)
-{
-	int i;
-	s32 delta_g;
-	struct iwl_chain_noise_data *data = &priv->chain_noise_data;
-
-	/*
-	 * Find Gain Code for the chains based on "default chain"
-	 */
-	for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) {
-		if ((data->disconn_array[i])) {
-			data->delta_gain_code[i] = 0;
-			continue;
-		}
-
-		delta_g = (priv->cfg->base_params->chain_noise_scale *
-			((s32)average_noise[default_chain] -
-			(s32)average_noise[i])) / 1500;
-
-		/* bound gain by 2 bits value max, 3rd bit is sign */
-		data->delta_gain_code[i] =
-			min(abs(delta_g),
-			(long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
-
-		if (delta_g < 0)
-			/*
-			 * set negative sign ...
-			 * note to Intel developers:  This is uCode API format,
-			 *   not the format of any internal device registers.
-			 *   Do not change this format for e.g. 6050 or similar
-			 *   devices.  Change format only if more resolution
-			 *   (i.e. more than 2 bits magnitude) is needed.
-			 */
-			data->delta_gain_code[i] |= (1 << 2);
-	}
-
-	IWL_DEBUG_CALIB(priv, "Delta gains: ANT_B = %d  ANT_C = %d\n",
-			data->delta_gain_code[1], data->delta_gain_code[2]);
-
-	if (!data->radio_write) {
-		struct iwl_calib_chain_noise_gain_cmd cmd;
-
-		memset(&cmd, 0, sizeof(cmd));
-
-		iwl_set_calib_hdr(&cmd.hdr,
-			priv->phy_calib_chain_noise_gain_cmd);
-		cmd.delta_gain_1 = data->delta_gain_code[1];
-		cmd.delta_gain_2 = data->delta_gain_code[2];
-		iwl_dvm_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
-			CMD_ASYNC, sizeof(cmd), &cmd);
-
-		data->radio_write = 1;
-		data->state = IWL_CHAIN_NOISE_CALIBRATED;
-	}
-}
-
-/*
- * Accumulate 16 beacons of signal and noise statistics for each of
- *   3 receivers/antennas/rx-chains, then figure out:
- * 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_chain_noise_data *data = NULL;
-
-	u32 chain_noise_a;
-	u32 chain_noise_b;
-	u32 chain_noise_c;
-	u32 chain_sig_a;
-	u32 chain_sig_b;
-	u32 chain_sig_c;
-	u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
-	u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
-	u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
-	u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
-	u16 i = 0;
-	u16 rxon_chnum = INITIALIZATION_VALUE;
-	u16 stat_chnum = INITIALIZATION_VALUE;
-	u8 rxon_band24;
-	u8 stat_band24;
-	struct statistics_rx_non_phy *rx_info;
-
-	/*
-	 * MULTI-FIXME:
-	 * When we support multiple interfaces on different channels,
-	 * this must be modified/fixed.
-	 */
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-
-	if (priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED)
-		return;
-
-	data = &(priv->chain_noise_data);
-
-	/*
-	 * Accumulate just the first "chain_noise_num_beacons" after
-	 * the first association, then we're done forever.
-	 */
-	if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
-		if (data->state == IWL_CHAIN_NOISE_ALIVE)
-			IWL_DEBUG_CALIB(priv, "Wait for noise calib reset\n");
-		return;
-	}
-
-	spin_lock_bh(&priv->statistics.lock);
-
-	rx_info = &priv->statistics.rx_non_phy;
-
-	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
-		IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
-		spin_unlock_bh(&priv->statistics.lock);
-		return;
-	}
-
-	rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
-	rxon_chnum = le16_to_cpu(ctx->staging.channel);
-	stat_band24 =
-		!!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
-	stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16;
-
-	/* Make sure we accumulate data for just the associated channel
-	 *   (even if scanning). */
-	if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) {
-		IWL_DEBUG_CALIB(priv, "Stats not from chan=%d, band24=%d\n",
-				rxon_chnum, rxon_band24);
-		spin_unlock_bh(&priv->statistics.lock);
-		return;
-	}
-
-	/*
-	 *  Accumulate beacon statistics values across
-	 * "chain_noise_num_beacons"
-	 */
-	chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
-				IN_BAND_FILTER;
-	chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
-				IN_BAND_FILTER;
-	chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
-				IN_BAND_FILTER;
-
-	chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
-	chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
-	chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
-
-	spin_unlock_bh(&priv->statistics.lock);
-
-	data->beacon_count++;
-
-	data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
-	data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
-	data->chain_noise_c = (chain_noise_c + data->chain_noise_c);
-
-	data->chain_signal_a = (chain_sig_a + data->chain_signal_a);
-	data->chain_signal_b = (chain_sig_b + data->chain_signal_b);
-	data->chain_signal_c = (chain_sig_c + data->chain_signal_c);
-
-	IWL_DEBUG_CALIB(priv, "chan=%d, band24=%d, beacon=%d\n",
-			rxon_chnum, rxon_band24, data->beacon_count);
-	IWL_DEBUG_CALIB(priv, "chain_sig: a %d b %d c %d\n",
-			chain_sig_a, chain_sig_b, chain_sig_c);
-	IWL_DEBUG_CALIB(priv, "chain_noise: a %d b %d c %d\n",
-			chain_noise_a, chain_noise_b, chain_noise_c);
-
-	/* If this is the "chain_noise_num_beacons", determine:
-	 * 1)  Disconnected antennas (using signal strengths)
-	 * 2)  Differential gain (using silence noise) to balance receivers */
-	if (data->beacon_count != IWL_CAL_NUM_BEACONS)
-		return;
-
-	/* Analyze signal for disconnected antenna */
-	if (priv->cfg->bt_params &&
-	    priv->cfg->bt_params->advanced_bt_coexist) {
-		/* Disable disconnected antenna algorithm for advanced
-		   bt coex, assuming valid antennas are connected */
-		data->active_chains = priv->hw_params.valid_rx_ant;
-		for (i = 0; i < NUM_RX_CHAINS; i++)
-			if (!(data->active_chains & (1<<i)))
-				data->disconn_array[i] = 1;
-	} else
-		iwl_find_disconn_antenna(priv, average_sig, data);
-
-	/* Analyze noise for rx balance */
-	average_noise[0] = data->chain_noise_a / IWL_CAL_NUM_BEACONS;
-	average_noise[1] = data->chain_noise_b / IWL_CAL_NUM_BEACONS;
-	average_noise[2] = data->chain_noise_c / IWL_CAL_NUM_BEACONS;
-
-	for (i = 0; i < NUM_RX_CHAINS; i++) {
-		if (!(data->disconn_array[i]) &&
-		   (average_noise[i] <= min_average_noise)) {
-			/* This means that chain i is active and has
-			 * lower noise values so far: */
-			min_average_noise = average_noise[i];
-			min_average_noise_antenna_i = i;
-		}
-	}
-
-	IWL_DEBUG_CALIB(priv, "average_noise: a %d b %d c %d\n",
-			average_noise[0], average_noise[1],
-			average_noise[2]);
-
-	IWL_DEBUG_CALIB(priv, "min_average_noise = %d, antenna %d\n",
-			min_average_noise, min_average_noise_antenna_i);
-
-	iwlagn_gain_computation(priv, average_noise,
-				find_first_chain(priv->hw_params.valid_rx_ant));
-
-	/* Some power changes may have been made during the calibration.
-	 * Update and commit the RXON
-	 */
-	iwl_update_chain_flags(priv);
-
-	data->state = IWL_CHAIN_NOISE_DONE;
-	iwl_power_update_mode(priv, false);
-}
-
-void iwl_reset_run_time_calib(struct iwl_priv *priv)
-{
-	int i;
-	memset(&(priv->sensitivity_data), 0,
-	       sizeof(struct iwl_sensitivity_data));
-	memset(&(priv->chain_noise_data), 0,
-	       sizeof(struct iwl_chain_noise_data));
-	for (i = 0; i < NUM_RX_CHAINS; i++)
-		priv->chain_noise_data.delta_gain_code[i] =
-				CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
-
-	/* Ask for statistics now, the uCode will send notification
-	 * periodically after association */
-	iwl_send_statistics_request(priv, CMD_ASYNC, true);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
deleted file mode 100644
index dbe1378..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-#ifndef __iwl_calib_h__
-#define __iwl_calib_h__
-
-#include "iwl-dev.h"
-#include "iwl-commands.h"
-
-void iwl_chain_noise_calibration(struct iwl_priv *priv);
-void iwl_sensitivity_calibration(struct iwl_priv *priv);
-
-void iwl_init_sensitivity(struct iwl_priv *priv);
-void iwl_reset_run_time_calib(struct iwl_priv *priv);
-
-#endif /* __iwl_calib_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-devices.c b/drivers/net/wireless/iwlwifi/iwl-agn-devices.c
deleted file mode 100644
index 48533b3..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-devices.c
+++ /dev/null
@@ -1,755 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2012 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.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-/*
- * DVM device-specific data & functions
- */
-#include "iwl-agn.h"
-#include "iwl-dev.h"
-#include "iwl-commands.h"
-#include "iwl-io.h"
-#include "iwl-prph.h"
-
-/*
- * 1000 series
- * ===========
- */
-
-/*
- * For 1000, use advance thermal throttling critical temperature threshold,
- * but legacy thermal management implementation for now.
- * This is for the reason of 1000 uCode using advance thermal throttling API
- * but not implement ct_kill_exit based on ct_kill exit temperature
- * so the thermal throttling will still based on legacy thermal throttling
- * management.
- * The code here need to be modified once 1000 uCode has the advanced thermal
- * throttling algorithm in place
- */
-static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
-{
-	/* want Celsius */
-	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
-	priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
-}
-
-/* NIC configuration for 1000 series */
-static void iwl1000_nic_config(struct iwl_priv *priv)
-{
-	/* set CSR_HW_CONFIG_REG for uCode use */
-	iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG,
-		    CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
-		    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
-
-	/* Setting digital SVR for 1000 card to 1.32V */
-	/* locking is acquired in iwl_set_bits_mask_prph() function */
-	iwl_set_bits_mask_prph(priv->trans, APMG_DIGITAL_SVR_REG,
-				APMG_SVR_DIGITAL_VOLTAGE_1_32,
-				~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
-}
-
-/**
- * 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;
-}
-
-/*
- * 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
- */
-static 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, IWLAGN_EXT_BEACON_TIME_POS) >>
-		IWLAGN_EXT_BEACON_TIME_POS);
-	rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
-				   IWLAGN_EXT_BEACON_TIME_POS);
-
-	return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem;
-}
-
-/* base is usually what we get from ucode with each received frame,
- * the same as HW timer counter counting down
- */
-static __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
-			   u32 addon, u32 beacon_interval)
-{
-	u32 base_low = base & iwl_beacon_time_mask_low(priv,
-				IWLAGN_EXT_BEACON_TIME_POS);
-	u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
-				IWLAGN_EXT_BEACON_TIME_POS);
-	u32 interval = beacon_interval * TIME_UNIT;
-	u32 res = (base & iwl_beacon_time_mask_high(priv,
-				IWLAGN_EXT_BEACON_TIME_POS)) +
-				(addon & iwl_beacon_time_mask_high(priv,
-				IWLAGN_EXT_BEACON_TIME_POS));
-
-	if (base_low > addon_low)
-		res += base_low - addon_low;
-	else if (base_low < addon_low) {
-		res += interval + base_low - addon_low;
-		res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
-	} else
-		res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
-
-	return cpu_to_le32(res);
-}
-
-static const struct iwl_sensitivity_ranges iwl1000_sensitivity = {
-	.min_nrg_cck = 95,
-	.auto_corr_min_ofdm = 90,
-	.auto_corr_min_ofdm_mrc = 170,
-	.auto_corr_min_ofdm_x1 = 120,
-	.auto_corr_min_ofdm_mrc_x1 = 240,
-
-	.auto_corr_max_ofdm = 120,
-	.auto_corr_max_ofdm_mrc = 210,
-	.auto_corr_max_ofdm_x1 = 155,
-	.auto_corr_max_ofdm_mrc_x1 = 290,
-
-	.auto_corr_min_cck = 125,
-	.auto_corr_max_cck = 200,
-	.auto_corr_min_cck_mrc = 170,
-	.auto_corr_max_cck_mrc = 400,
-	.nrg_th_cck = 95,
-	.nrg_th_ofdm = 95,
-
-	.barker_corr_th_min = 190,
-	.barker_corr_th_min_mrc = 390,
-	.nrg_th_cca = 62,
-};
-
-static void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
-{
-	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
-
-	priv->hw_params.tx_chains_num =
-		num_of_ant(priv->hw_params.valid_tx_ant);
-	if (priv->cfg->rx_with_siso_diversity)
-		priv->hw_params.rx_chains_num = 1;
-	else
-		priv->hw_params.rx_chains_num =
-			num_of_ant(priv->hw_params.valid_rx_ant);
-
-	iwl1000_set_ct_threshold(priv);
-
-	/* Set initial sensitivity parameters */
-	priv->hw_params.sens = &iwl1000_sensitivity;
-}
-
-struct iwl_lib_ops iwl1000_lib = {
-	.set_hw_params = iwl1000_hw_set_hw_params,
-	.nic_config = iwl1000_nic_config,
-	.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_REG_BAND_24_HT40_CHANNELS,
-			EEPROM_REGULATORY_BAND_NO_HT40,
-		},
-	},
-	.temperature = iwlagn_temperature,
-};
-
-
-/*
- * 2000 series
- * ===========
- */
-
-static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
-{
-	/* want Celsius */
-	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
-	priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
-}
-
-/* NIC configuration for 2000 series */
-static void iwl2000_nic_config(struct iwl_priv *priv)
-{
-	iwl_rf_config(priv);
-
-	iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
-		    CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
-}
-
-static const struct iwl_sensitivity_ranges iwl2000_sensitivity = {
-	.min_nrg_cck = 97,
-	.auto_corr_min_ofdm = 80,
-	.auto_corr_min_ofdm_mrc = 128,
-	.auto_corr_min_ofdm_x1 = 105,
-	.auto_corr_min_ofdm_mrc_x1 = 192,
-
-	.auto_corr_max_ofdm = 145,
-	.auto_corr_max_ofdm_mrc = 232,
-	.auto_corr_max_ofdm_x1 = 110,
-	.auto_corr_max_ofdm_mrc_x1 = 232,
-
-	.auto_corr_min_cck = 125,
-	.auto_corr_max_cck = 175,
-	.auto_corr_min_cck_mrc = 160,
-	.auto_corr_max_cck_mrc = 310,
-	.nrg_th_cck = 97,
-	.nrg_th_ofdm = 100,
-
-	.barker_corr_th_min = 190,
-	.barker_corr_th_min_mrc = 390,
-	.nrg_th_cca = 62,
-};
-
-static void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
-{
-	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
-
-	priv->hw_params.tx_chains_num =
-		num_of_ant(priv->hw_params.valid_tx_ant);
-	if (priv->cfg->rx_with_siso_diversity)
-		priv->hw_params.rx_chains_num = 1;
-	else
-		priv->hw_params.rx_chains_num =
-			num_of_ant(priv->hw_params.valid_rx_ant);
-
-	iwl2000_set_ct_threshold(priv);
-
-	/* Set initial sensitivity parameters */
-	priv->hw_params.sens = &iwl2000_sensitivity;
-}
-
-struct iwl_lib_ops iwl2000_lib = {
-	.set_hw_params = iwl2000_hw_set_hw_params,
-	.nic_config = iwl2000_nic_config,
-	.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_REGULATORY_BAND_NO_HT40,
-		},
-		.enhanced_txpower = true,
-	},
-	.temperature = iwlagn_temperature,
-};
-
-struct iwl_lib_ops iwl2030_lib = {
-	.set_hw_params = iwl2000_hw_set_hw_params,
-	.nic_config = iwl2000_nic_config,
-	.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_REGULATORY_BAND_NO_HT40,
-		},
-		.enhanced_txpower = true,
-	},
-	.temperature = iwlagn_temperature,
-};
-
-/*
- * 5000 series
- * ===========
- */
-
-/* NIC configuration for 5000 series */
-static void iwl5000_nic_config(struct iwl_priv *priv)
-{
-	iwl_rf_config(priv);
-
-	/* W/A : NIC is stuck in a reset state after Early PCIe power off
-	 * (PCIe power is lost before PERST# is asserted),
-	 * causing ME FW to lose ownership and not being able to obtain it back.
-	 */
-	iwl_set_bits_mask_prph(priv->trans, APMG_PS_CTRL_REG,
-				APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
-				~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
-}
-
-static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
-	.min_nrg_cck = 100,
-	.auto_corr_min_ofdm = 90,
-	.auto_corr_min_ofdm_mrc = 170,
-	.auto_corr_min_ofdm_x1 = 105,
-	.auto_corr_min_ofdm_mrc_x1 = 220,
-
-	.auto_corr_max_ofdm = 120,
-	.auto_corr_max_ofdm_mrc = 210,
-	.auto_corr_max_ofdm_x1 = 120,
-	.auto_corr_max_ofdm_mrc_x1 = 240,
-
-	.auto_corr_min_cck = 125,
-	.auto_corr_max_cck = 200,
-	.auto_corr_min_cck_mrc = 200,
-	.auto_corr_max_cck_mrc = 400,
-	.nrg_th_cck = 100,
-	.nrg_th_ofdm = 100,
-
-	.barker_corr_th_min = 190,
-	.barker_corr_th_min_mrc = 390,
-	.nrg_th_cca = 62,
-};
-
-static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
-	.min_nrg_cck = 95,
-	.auto_corr_min_ofdm = 90,
-	.auto_corr_min_ofdm_mrc = 170,
-	.auto_corr_min_ofdm_x1 = 105,
-	.auto_corr_min_ofdm_mrc_x1 = 220,
-
-	.auto_corr_max_ofdm = 120,
-	.auto_corr_max_ofdm_mrc = 210,
-	/* max = min for performance bug in 5150 DSP */
-	.auto_corr_max_ofdm_x1 = 105,
-	.auto_corr_max_ofdm_mrc_x1 = 220,
-
-	.auto_corr_min_cck = 125,
-	.auto_corr_max_cck = 200,
-	.auto_corr_min_cck_mrc = 170,
-	.auto_corr_max_cck_mrc = 400,
-	.nrg_th_cck = 95,
-	.nrg_th_ofdm = 95,
-
-	.barker_corr_th_min = 190,
-	.barker_corr_th_min_mrc = 390,
-	.nrg_th_cca = 62,
-};
-
-#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF	(-5)
-
-static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
-{
-	u16 temperature, voltage;
-	__le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(priv,
-				EEPROM_KELVIN_TEMPERATURE);
-
-	temperature = le16_to_cpu(temp_calib[0]);
-	voltage = le16_to_cpu(temp_calib[1]);
-
-	/* offset = temp - volt / coeff */
-	return (s32)(temperature -
-			voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
-}
-
-static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
-{
-	const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
-	s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
-			iwl_temp_calib_to_offset(priv);
-
-	priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
-}
-
-static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
-{
-	/* want Celsius */
-	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
-}
-
-static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
-{
-	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
-					BIT(IEEE80211_BAND_5GHZ);
-
-	priv->hw_params.tx_chains_num =
-		num_of_ant(priv->hw_params.valid_tx_ant);
-	priv->hw_params.rx_chains_num =
-		num_of_ant(priv->hw_params.valid_rx_ant);
-
-	iwl5000_set_ct_threshold(priv);
-
-	/* Set initial sensitivity parameters */
-	priv->hw_params.sens = &iwl5000_sensitivity;
-}
-
-static void iwl5150_hw_set_hw_params(struct iwl_priv *priv)
-{
-	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
-					BIT(IEEE80211_BAND_5GHZ);
-
-	priv->hw_params.tx_chains_num =
-		num_of_ant(priv->hw_params.valid_tx_ant);
-	priv->hw_params.rx_chains_num =
-		num_of_ant(priv->hw_params.valid_rx_ant);
-
-	iwl5150_set_ct_threshold(priv);
-
-	/* Set initial sensitivity parameters */
-	priv->hw_params.sens = &iwl5150_sensitivity;
-}
-
-static void iwl5150_temperature(struct iwl_priv *priv)
-{
-	u32 vt = 0;
-	s32 offset =  iwl_temp_calib_to_offset(priv);
-
-	vt = le32_to_cpu(priv->statistics.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,
-				     struct ieee80211_channel_switch *ch_switch)
-{
-	/*
-	 * MULTI-FIXME
-	 * See iwlagn_mac_channel_switch.
-	 */
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-	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(ctx->timing.beacon_interval);
-	struct ieee80211_vif *vif = ctx->vif;
-	struct iwl_host_cmd hcmd = {
-		.id = REPLY_CHANNEL_SWITCH,
-		.len = { sizeof(cmd), },
-		.flags = CMD_SYNC,
-		.data = { &cmd, },
-	};
-
-	cmd.band = priv->band == IEEE80211_BAND_2GHZ;
-	ch = ch_switch->channel->hw_value;
-	IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
-		      ctx->active.channel, ch);
-	cmd.channel = cpu_to_le16(ch);
-	cmd.rxon_flags = ctx->staging.flags;
-	cmd.rxon_filter_flags = ctx->staging.filter_flags;
-	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",
-			ctx->active.channel, ch);
-		return -EFAULT;
-	}
-
-	return iwl_dvm_send_cmd(priv, &hcmd);
-}
-
-struct iwl_lib_ops iwl5000_lib = {
-	.set_hw_params = iwl5000_hw_set_hw_params,
-	.set_channel_switch = iwl5000_hw_channel_switch,
-	.nic_config = iwl5000_nic_config,
-	.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_REG_BAND_24_HT40_CHANNELS,
-			EEPROM_REG_BAND_52_HT40_CHANNELS
-		},
-	},
-	.temperature = iwlagn_temperature,
-};
-
-struct iwl_lib_ops iwl5150_lib = {
-	.set_hw_params = iwl5150_hw_set_hw_params,
-	.set_channel_switch = iwl5000_hw_channel_switch,
-	.nic_config = iwl5000_nic_config,
-	.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_REG_BAND_24_HT40_CHANNELS,
-			EEPROM_REG_BAND_52_HT40_CHANNELS
-		},
-	},
-	.temperature = iwl5150_temperature,
-};
-
-
-
-/*
- * 6000 series
- * ===========
- */
-
-static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
-{
-	/* want Celsius */
-	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
-	priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
-}
-
-/* NIC configuration for 6000 series */
-static void iwl6000_nic_config(struct iwl_priv *priv)
-{
-	iwl_rf_config(priv);
-
-	switch (priv->cfg->device_family) {
-	case IWL_DEVICE_FAMILY_6005:
-	case IWL_DEVICE_FAMILY_6030:
-	case IWL_DEVICE_FAMILY_6000:
-		break;
-	case IWL_DEVICE_FAMILY_6000i:
-		/* 2x2 IPA phy type */
-		iwl_write32(priv->trans, CSR_GP_DRIVER_REG,
-			     CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
-		break;
-	case IWL_DEVICE_FAMILY_6050:
-		/* Indicate calibration version to uCode. */
-		if (iwl_eeprom_calib_version(priv) >= 6)
-			iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
-					CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
-		break;
-	case IWL_DEVICE_FAMILY_6150:
-		/* Indicate calibration version to uCode. */
-		if (iwl_eeprom_calib_version(priv) >= 6)
-			iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
-					CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
-		iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
-			    CSR_GP_DRIVER_REG_BIT_6050_1x2);
-		break;
-	default:
-		WARN_ON(1);
-	}
-}
-
-static const struct iwl_sensitivity_ranges iwl6000_sensitivity = {
-	.min_nrg_cck = 110,
-	.auto_corr_min_ofdm = 80,
-	.auto_corr_min_ofdm_mrc = 128,
-	.auto_corr_min_ofdm_x1 = 105,
-	.auto_corr_min_ofdm_mrc_x1 = 192,
-
-	.auto_corr_max_ofdm = 145,
-	.auto_corr_max_ofdm_mrc = 232,
-	.auto_corr_max_ofdm_x1 = 110,
-	.auto_corr_max_ofdm_mrc_x1 = 232,
-
-	.auto_corr_min_cck = 125,
-	.auto_corr_max_cck = 175,
-	.auto_corr_min_cck_mrc = 160,
-	.auto_corr_max_cck_mrc = 310,
-	.nrg_th_cck = 110,
-	.nrg_th_ofdm = 110,
-
-	.barker_corr_th_min = 190,
-	.barker_corr_th_min_mrc = 336,
-	.nrg_th_cca = 62,
-};
-
-static void iwl6000_hw_set_hw_params(struct iwl_priv *priv)
-{
-	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
-					BIT(IEEE80211_BAND_5GHZ);
-
-	priv->hw_params.tx_chains_num =
-		num_of_ant(priv->hw_params.valid_tx_ant);
-	if (priv->cfg->rx_with_siso_diversity)
-		priv->hw_params.rx_chains_num = 1;
-	else
-		priv->hw_params.rx_chains_num =
-			num_of_ant(priv->hw_params.valid_rx_ant);
-
-	iwl6000_set_ct_threshold(priv);
-
-	/* Set initial sensitivity parameters */
-	priv->hw_params.sens = &iwl6000_sensitivity;
-
-}
-
-static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
-				     struct ieee80211_channel_switch *ch_switch)
-{
-	/*
-	 * MULTI-FIXME
-	 * See iwlagn_mac_channel_switch.
-	 */
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-	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(ctx->timing.beacon_interval);
-	struct ieee80211_vif *vif = ctx->vif;
-	struct iwl_host_cmd hcmd = {
-		.id = REPLY_CHANNEL_SWITCH,
-		.len = { sizeof(cmd), },
-		.flags = CMD_SYNC,
-		.data = { &cmd, },
-	};
-
-	cmd.band = priv->band == IEEE80211_BAND_2GHZ;
-	ch = ch_switch->channel->hw_value;
-	IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
-		      ctx->active.channel, ch);
-	cmd.channel = cpu_to_le16(ch);
-	cmd.rxon_flags = ctx->staging.flags;
-	cmd.rxon_filter_flags = ctx->staging.filter_flags;
-	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",
-			ctx->active.channel, ch);
-		return -EFAULT;
-	}
-
-	return iwl_dvm_send_cmd(priv, &hcmd);
-}
-
-struct iwl_lib_ops iwl6000_lib = {
-	.set_hw_params = iwl6000_hw_set_hw_params,
-	.set_channel_switch = iwl6000_hw_channel_switch,
-	.nic_config = iwl6000_nic_config,
-	.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
-		},
-		.enhanced_txpower = true,
-	},
-	.temperature = iwlagn_temperature,
-};
-
-struct iwl_lib_ops iwl6030_lib = {
-	.set_hw_params = iwl6000_hw_set_hw_params,
-	.set_channel_switch = iwl6000_hw_channel_switch,
-	.nic_config = iwl6000_nic_config,
-	.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
-		},
-		.enhanced_txpower = true,
-	},
-	.temperature = iwlagn_temperature,
-};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
deleted file mode 100644
index e55ec6c..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ /dev/null
@@ -1,1285 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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/etherdevice.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <net/mac80211.h>
-
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-hw.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-#include "iwl-modparams.h"
-
-int iwlagn_hw_valid_rtc_data_addr(u32 addr)
-{
-	return (addr >= IWLAGN_RTC_DATA_LOWER_BOUND) &&
-		(addr < IWLAGN_RTC_DATA_UPPER_BOUND);
-}
-
-int iwlagn_send_tx_power(struct iwl_priv *priv)
-{
-	struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
-	u8 tx_ant_cfg_cmd;
-
-	if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status),
-		      "TX Power requested while scanning!\n"))
-		return -EAGAIN;
-
-	/* half dBm need to multiply */
-	tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
-
-	if (priv->tx_power_lmt_in_half_dbm &&
-	    priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
-		/*
-		 * For the newer devices which using enhanced/extend tx power
-		 * table in EEPROM, the format is in half dBm. driver need to
-		 * convert to dBm format before report to mac80211.
-		 * By doing so, there is a possibility of 1/2 dBm resolution
-		 * lost. driver will perform "round-up" operation before
-		 * reporting, but it will cause 1/2 dBm tx power over the
-		 * regulatory limit. Perform the checking here, if the
-		 * "tx_power_user_lmt" is higher than EEPROM value (in
-		 * half-dBm format), lower the tx power based on EEPROM
-		 */
-		tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
-	}
-	tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
-	tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
-
-	if (IWL_UCODE_API(priv->fw->ucode_ver) == 1)
-		tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
-	else
-		tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
-
-	return iwl_dvm_send_cmd_pdu(priv, tx_ant_cfg_cmd, CMD_SYNC,
-			sizeof(tx_power_cmd), &tx_power_cmd);
-}
-
-void iwlagn_temperature(struct iwl_priv *priv)
-{
-	lockdep_assert_held(&priv->statistics.lock);
-
-	/* store temperature from correct statistics (in Celsius) */
-	priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
-	iwl_tt_handler(priv);
-}
-
-int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
-{
-	int idx = 0;
-	int band_offset = 0;
-
-	/* HT rate format: mac80211 wants an MCS number, which is just LSB */
-	if (rate_n_flags & RATE_MCS_HT_MSK) {
-		idx = (rate_n_flags & 0xff);
-		return idx;
-	/* Legacy rate format, search for match in table */
-	} else {
-		if (band == IEEE80211_BAND_5GHZ)
-			band_offset = IWL_FIRST_OFDM_RATE;
-		for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
-			if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
-				return idx - band_offset;
-	}
-
-	return -1;
-}
-
-int iwlagn_manage_ibss_station(struct iwl_priv *priv,
-			       struct ieee80211_vif *vif, bool add)
-{
-	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-
-	if (add)
-		return iwlagn_add_bssid_station(priv, vif_priv->ctx,
-						vif->bss_conf.bssid,
-						&vif_priv->ibss_bssid_sta_id);
-	return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
-				  vif->bss_conf.bssid);
-}
-
-/**
- * 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));
-	if (flush_control & BIT(IWL_RXON_CTX_BSS))
-		flush_cmd.fifo_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK |
-				 IWL_SCD_BE_MSK | IWL_SCD_BK_MSK |
-				 IWL_SCD_MGMT_MSK;
-	if ((flush_control & BIT(IWL_RXON_CTX_PAN)) &&
-	    (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)))
-		flush_cmd.fifo_control |= IWL_PAN_SCD_VO_MSK |
-				IWL_PAN_SCD_VI_MSK | IWL_PAN_SCD_BE_MSK |
-				IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK |
-				IWL_PAN_SCD_MULTICAST_MSK;
-
-	if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
-		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_dvm_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 (iwlagn_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");
-	iwl_trans_wait_tx_queue_empty(priv->trans);
-done:
-	ieee80211_wake_queues(priv->hw);
-	mutex_unlock(&priv->mutex);
-}
-
-/*
- * BT coex
- */
-/* Notmal TDM */
-static const __le32 iwlagn_def_3w_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xaeaaaaaa),
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xcc00ff28),
-	cpu_to_le32(0x0000aaaa),
-	cpu_to_le32(0xcc00aaaa),
-	cpu_to_le32(0x0000aaaa),
-	cpu_to_le32(0xc0004000),
-	cpu_to_le32(0x00004000),
-	cpu_to_le32(0xf0005000),
-	cpu_to_le32(0xf0005000),
-};
-
-
-/* Loose Coex */
-static const __le32 iwlagn_loose_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xaeaaaaaa),
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xcc00ff28),
-	cpu_to_le32(0x0000aaaa),
-	cpu_to_le32(0xcc00aaaa),
-	cpu_to_le32(0x0000aaaa),
-	cpu_to_le32(0x00000000),
-	cpu_to_le32(0x00000000),
-	cpu_to_le32(0xf0005000),
-	cpu_to_le32(0xf0005000),
-};
-
-/* Full concurrency */
-static const __le32 iwlagn_concurrent_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0xaaaaaaaa),
-	cpu_to_le32(0x00000000),
-	cpu_to_le32(0x00000000),
-	cpu_to_le32(0x00000000),
-	cpu_to_le32(0x00000000),
-};
-
-void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
-{
-	struct iwl_basic_bt_cmd basic = {
-		.max_kill = IWLAGN_BT_MAX_KILL_DEFAULT,
-		.bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT,
-		.bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT,
-		.bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT,
-	};
-	struct iwl_bt_cmd_v1 bt_cmd_v1;
-	struct iwl_bt_cmd_v2 bt_cmd_v2;
-	int ret;
-
-	BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
-			sizeof(basic.bt3_lookup_table));
-
-	if (priv->cfg->bt_params) {
-		/*
-		 * newer generation of devices (2000 series and newer)
-		 * use the version 2 of the bt command
-		 * we need to make sure sending the host command
-		 * with correct data structure to avoid uCode assert
-		 */
-		if (priv->cfg->bt_params->bt_session_2) {
-			bt_cmd_v2.prio_boost = cpu_to_le32(
-				priv->cfg->bt_params->bt_prio_boost);
-			bt_cmd_v2.tx_prio_boost = 0;
-			bt_cmd_v2.rx_prio_boost = 0;
-		} else {
-			bt_cmd_v1.prio_boost =
-				priv->cfg->bt_params->bt_prio_boost;
-			bt_cmd_v1.tx_prio_boost = 0;
-			bt_cmd_v1.rx_prio_boost = 0;
-		}
-	} else {
-		IWL_ERR(priv, "failed to construct BT Coex Config\n");
-		return;
-	}
-
-	/*
-	 * Possible situations when BT needs to take over for receive,
-	 * at the same time where STA needs to response to AP's frame(s),
-	 * reduce the tx power of the required response frames, by that,
-	 * allow the concurrent BT receive & WiFi transmit
-	 * (BT - ANT A, WiFi -ANT B), without interference to one another
-	 *
-	 * Reduced tx power apply to control frames only (ACK/Back/CTS)
-	 * when indicated by the BT config command
-	 */
-	basic.kill_ack_mask = priv->kill_ack_mask;
-	basic.kill_cts_mask = priv->kill_cts_mask;
-	if (priv->reduced_txpower)
-		basic.reduce_txpower = IWLAGN_BT_REDUCED_TX_PWR;
-	basic.valid = priv->bt_valid;
-
-	/*
-	 * Configure BT coex mode to "no coexistence" when the
-	 * user disabled BT coexistence, we have no interface
-	 * (might be in monitor mode), or the interface is in
-	 * IBSS mode (no proper uCode support for coex then).
-	 */
-	if (!iwlwifi_mod_params.bt_coex_active ||
-	    priv->iw_mode == NL80211_IFTYPE_ADHOC) {
-		basic.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED;
-	} else {
-		basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
-					IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
-
-		if (!priv->bt_enable_pspoll)
-			basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
-		else
-			basic.flags &= ~IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
-
-		if (priv->bt_ch_announce)
-			basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
-		IWL_DEBUG_COEX(priv, "BT coex flag: 0X%x\n", basic.flags);
-	}
-	priv->bt_enable_flag = basic.flags;
-	if (priv->bt_full_concurrent)
-		memcpy(basic.bt3_lookup_table, iwlagn_concurrent_lookup,
-			sizeof(iwlagn_concurrent_lookup));
-	else
-		memcpy(basic.bt3_lookup_table, iwlagn_def_3w_lookup,
-			sizeof(iwlagn_def_3w_lookup));
-
-	IWL_DEBUG_COEX(priv, "BT coex %s in %s mode\n",
-		       basic.flags ? "active" : "disabled",
-		       priv->bt_full_concurrent ?
-		       "full concurrency" : "3-wire");
-
-	if (priv->cfg->bt_params->bt_session_2) {
-		memcpy(&bt_cmd_v2.basic, &basic,
-			sizeof(basic));
-		ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-			CMD_SYNC, sizeof(bt_cmd_v2), &bt_cmd_v2);
-	} else {
-		memcpy(&bt_cmd_v1.basic, &basic,
-			sizeof(basic));
-		ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-			CMD_SYNC, sizeof(bt_cmd_v1), &bt_cmd_v1);
-	}
-	if (ret)
-		IWL_ERR(priv, "failed to send BT Coex Config\n");
-
-}
-
-void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena)
-{
-	struct iwl_rxon_context *ctx, *found_ctx = NULL;
-	bool found_ap = false;
-
-	lockdep_assert_held(&priv->mutex);
-
-	/* Check whether AP or GO mode is active. */
-	if (rssi_ena) {
-		for_each_context(priv, ctx) {
-			if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_AP &&
-			    iwl_is_associated_ctx(ctx)) {
-				found_ap = true;
-				break;
-			}
-		}
-	}
-
-	/*
-	 * If disable was received or If GO/AP mode, disable RSSI
-	 * measurements.
-	 */
-	if (!rssi_ena || found_ap) {
-		if (priv->cur_rssi_ctx) {
-			ctx = priv->cur_rssi_ctx;
-			ieee80211_disable_rssi_reports(ctx->vif);
-			priv->cur_rssi_ctx = NULL;
-		}
-		return;
-	}
-
-	/*
-	 * If rssi measurements need to be enabled, consider all cases now.
-	 * Figure out how many contexts are active.
-	 */
-	for_each_context(priv, ctx) {
-		if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
-		    iwl_is_associated_ctx(ctx)) {
-			found_ctx = ctx;
-			break;
-		}
-	}
-
-	/*
-	 * rssi monitor already enabled for the correct interface...nothing
-	 * to do.
-	 */
-	if (found_ctx == priv->cur_rssi_ctx)
-		return;
-
-	/*
-	 * Figure out if rssi monitor is currently enabled, and needs
-	 * to be changed. If rssi monitor is already enabled, disable
-	 * it first else just enable rssi measurements on the
-	 * interface found above.
-	 */
-	if (priv->cur_rssi_ctx) {
-		ctx = priv->cur_rssi_ctx;
-		if (ctx->vif)
-			ieee80211_disable_rssi_reports(ctx->vif);
-	}
-
-	priv->cur_rssi_ctx = found_ctx;
-
-	if (!found_ctx)
-		return;
-
-	ieee80211_enable_rssi_reports(found_ctx->vif,
-			IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD,
-			IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD);
-}
-
-static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
-{
-	return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >>
-			BT_UART_MSG_FRAME3SCOESCO_POS;
-}
-
-static void iwlagn_bt_traffic_change_work(struct work_struct *work)
-{
-	struct iwl_priv *priv =
-		container_of(work, struct iwl_priv, bt_traffic_change_work);
-	struct iwl_rxon_context *ctx;
-	int smps_request = -1;
-
-	if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
-		/* bt coex disabled */
-		return;
-	}
-
-	/*
-	 * Note: bt_traffic_load can be overridden by scan complete and
-	 * coex profile notifications. Ignore that since only bad consequence
-	 * can be not matching debug print with actual state.
-	 */
-	IWL_DEBUG_COEX(priv, "BT traffic load changes: %d\n",
-		       priv->bt_traffic_load);
-
-	switch (priv->bt_traffic_load) {
-	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-		if (priv->bt_status)
-			smps_request = IEEE80211_SMPS_DYNAMIC;
-		else
-			smps_request = IEEE80211_SMPS_AUTOMATIC;
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-		smps_request = IEEE80211_SMPS_DYNAMIC;
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-		smps_request = IEEE80211_SMPS_STATIC;
-		break;
-	default:
-		IWL_ERR(priv, "Invalid BT traffic load: %d\n",
-			priv->bt_traffic_load);
-		break;
-	}
-
-	mutex_lock(&priv->mutex);
-
-	/*
-	 * We can not send command to firmware while scanning. When the scan
-	 * complete we will schedule this work again. We do check with mutex
-	 * locked to prevent new scan request to arrive. We do not check
-	 * STATUS_SCANNING to avoid race when queue_work two times from
-	 * different notifications, but quit and not perform any work at all.
-	 */
-	if (test_bit(STATUS_SCAN_HW, &priv->status))
-		goto out;
-
-	iwl_update_chain_flags(priv);
-
-	if (smps_request != -1) {
-		priv->current_ht_config.smps = smps_request;
-		for_each_context(priv, ctx) {
-			if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION)
-				ieee80211_request_smps(ctx->vif, smps_request);
-		}
-	}
-
-	/*
-	 * Dynamic PS poll related functionality. Adjust RSSI measurements if
-	 * necessary.
-	 */
-	iwlagn_bt_coex_rssi_monitor(priv);
-out:
-	mutex_unlock(&priv->mutex);
-}
-
-/*
- * If BT sco traffic, and RSSI monitor is enabled, move measurements to the
- * correct interface or disable it if this is the last interface to be
- * removed.
- */
-void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv)
-{
-	if (priv->bt_is_sco &&
-	    priv->bt_traffic_load == IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS)
-		iwlagn_bt_adjust_rssi_monitor(priv, true);
-	else
-		iwlagn_bt_adjust_rssi_monitor(priv, false);
-}
-
-static void iwlagn_print_uartmsg(struct iwl_priv *priv,
-				struct iwl_bt_uart_msg *uart_msg)
-{
-	IWL_DEBUG_COEX(priv, "Message Type = 0x%X, SSN = 0x%X, "
-			"Update Req = 0x%X\n",
-		(BT_UART_MSG_FRAME1MSGTYPE_MSK & uart_msg->frame1) >>
-			BT_UART_MSG_FRAME1MSGTYPE_POS,
-		(BT_UART_MSG_FRAME1SSN_MSK & uart_msg->frame1) >>
-			BT_UART_MSG_FRAME1SSN_POS,
-		(BT_UART_MSG_FRAME1UPDATEREQ_MSK & uart_msg->frame1) >>
-			BT_UART_MSG_FRAME1UPDATEREQ_POS);
-
-	IWL_DEBUG_COEX(priv, "Open connections = 0x%X, Traffic load = 0x%X, "
-			"Chl_SeqN = 0x%X, In band = 0x%X\n",
-		(BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK & uart_msg->frame2) >>
-			BT_UART_MSG_FRAME2OPENCONNECTIONS_POS,
-		(BT_UART_MSG_FRAME2TRAFFICLOAD_MSK & uart_msg->frame2) >>
-			BT_UART_MSG_FRAME2TRAFFICLOAD_POS,
-		(BT_UART_MSG_FRAME2CHLSEQN_MSK & uart_msg->frame2) >>
-			BT_UART_MSG_FRAME2CHLSEQN_POS,
-		(BT_UART_MSG_FRAME2INBAND_MSK & uart_msg->frame2) >>
-			BT_UART_MSG_FRAME2INBAND_POS);
-
-	IWL_DEBUG_COEX(priv, "SCO/eSCO = 0x%X, Sniff = 0x%X, A2DP = 0x%X, "
-			"ACL = 0x%X, Master = 0x%X, OBEX = 0x%X\n",
-		(BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
-			BT_UART_MSG_FRAME3SCOESCO_POS,
-		(BT_UART_MSG_FRAME3SNIFF_MSK & uart_msg->frame3) >>
-			BT_UART_MSG_FRAME3SNIFF_POS,
-		(BT_UART_MSG_FRAME3A2DP_MSK & uart_msg->frame3) >>
-			BT_UART_MSG_FRAME3A2DP_POS,
-		(BT_UART_MSG_FRAME3ACL_MSK & uart_msg->frame3) >>
-			BT_UART_MSG_FRAME3ACL_POS,
-		(BT_UART_MSG_FRAME3MASTER_MSK & uart_msg->frame3) >>
-			BT_UART_MSG_FRAME3MASTER_POS,
-		(BT_UART_MSG_FRAME3OBEX_MSK & uart_msg->frame3) >>
-			BT_UART_MSG_FRAME3OBEX_POS);
-
-	IWL_DEBUG_COEX(priv, "Idle duration = 0x%X\n",
-		(BT_UART_MSG_FRAME4IDLEDURATION_MSK & uart_msg->frame4) >>
-			BT_UART_MSG_FRAME4IDLEDURATION_POS);
-
-	IWL_DEBUG_COEX(priv, "Tx Activity = 0x%X, Rx Activity = 0x%X, "
-			"eSCO Retransmissions = 0x%X\n",
-		(BT_UART_MSG_FRAME5TXACTIVITY_MSK & uart_msg->frame5) >>
-			BT_UART_MSG_FRAME5TXACTIVITY_POS,
-		(BT_UART_MSG_FRAME5RXACTIVITY_MSK & uart_msg->frame5) >>
-			BT_UART_MSG_FRAME5RXACTIVITY_POS,
-		(BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK & uart_msg->frame5) >>
-			BT_UART_MSG_FRAME5ESCORETRANSMIT_POS);
-
-	IWL_DEBUG_COEX(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X\n",
-		(BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK & uart_msg->frame6) >>
-			BT_UART_MSG_FRAME6SNIFFINTERVAL_POS,
-		(BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >>
-			BT_UART_MSG_FRAME6DISCOVERABLE_POS);
-
-	IWL_DEBUG_COEX(priv, "Sniff Activity = 0x%X, Page = "
-			"0x%X, Inquiry = 0x%X, Connectable = 0x%X\n",
-		(BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >>
-			BT_UART_MSG_FRAME7SNIFFACTIVITY_POS,
-		(BT_UART_MSG_FRAME7PAGE_MSK & uart_msg->frame7) >>
-			BT_UART_MSG_FRAME7PAGE_POS,
-		(BT_UART_MSG_FRAME7INQUIRY_MSK & uart_msg->frame7) >>
-			BT_UART_MSG_FRAME7INQUIRY_POS,
-		(BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >>
-			BT_UART_MSG_FRAME7CONNECTABLE_POS);
-}
-
-static bool iwlagn_set_kill_msk(struct iwl_priv *priv,
-				struct iwl_bt_uart_msg *uart_msg)
-{
-	bool need_update = false;
-	u8 kill_msk = IWL_BT_KILL_REDUCE;
-	static const __le32 bt_kill_ack_msg[3] = {
-		IWLAGN_BT_KILL_ACK_MASK_DEFAULT,
-		IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
-		IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
-	static const __le32 bt_kill_cts_msg[3] = {
-		IWLAGN_BT_KILL_CTS_MASK_DEFAULT,
-		IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
-		IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
-
-	if (!priv->reduced_txpower)
-		kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3)
-			? IWL_BT_KILL_OVERRIDE : IWL_BT_KILL_DEFAULT;
-	if (priv->kill_ack_mask != bt_kill_ack_msg[kill_msk] ||
-	    priv->kill_cts_mask != bt_kill_cts_msg[kill_msk]) {
-		priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK;
-		priv->kill_ack_mask = bt_kill_ack_msg[kill_msk];
-		priv->bt_valid |= IWLAGN_BT_VALID_KILL_CTS_MASK;
-		priv->kill_cts_mask = bt_kill_cts_msg[kill_msk];
-		need_update = true;
-	}
-	return need_update;
-}
-
-/*
- * Upon RSSI changes, sends a bt config command with following changes
- *  1. enable/disable "reduced control frames tx power
- *  2. update the "kill)ack_mask" and "kill_cts_mask"
- *
- * If "reduced tx power" is enabled, uCode shall
- *  1. ACK/Back/CTS rate shall reduced to 6Mbps
- *  2. not use duplciate 20/40MHz mode
- */
-static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
-				struct iwl_bt_uart_msg *uart_msg)
-{
-	bool need_update = false;
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-	int ave_rssi;
-
-	ave_rssi = ieee80211_ave_rssi(ctx->vif);
-	if (!ave_rssi) {
-		/* no rssi data, no changes to reduce tx power */
-		IWL_DEBUG_COEX(priv, "no rssi data available\n");
-		return need_update;
-	}
-	if (!priv->reduced_txpower &&
-	    !iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
-	    (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) &&
-	    (uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
-	    BT_UART_MSG_FRAME3OBEX_MSK)) &&
-	    !(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
-	    BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK))) {
-		/* enabling reduced tx power */
-		priv->reduced_txpower = true;
-		priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
-		need_update = true;
-	} else if (priv->reduced_txpower &&
-		   (iwl_is_associated(priv, IWL_RXON_CTX_PAN) ||
-		   (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) ||
-		   (uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
-		   BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK)) ||
-		   !(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
-		   BT_UART_MSG_FRAME3OBEX_MSK)))) {
-		/* disable reduced tx power */
-		priv->reduced_txpower = false;
-		priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
-		need_update = true;
-	}
-
-	return need_update;
-}
-
-int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
-				  struct iwl_rx_cmd_buffer *rxb,
-				  struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_bt_coex_profile_notif *coex = (void *)pkt->data;
-	struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg;
-
-	if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
-		/* bt coex disabled */
-		return 0;
-	}
-
-	IWL_DEBUG_COEX(priv, "BT Coex notification:\n");
-	IWL_DEBUG_COEX(priv, "    status: %d\n", coex->bt_status);
-	IWL_DEBUG_COEX(priv, "    traffic load: %d\n", coex->bt_traffic_load);
-	IWL_DEBUG_COEX(priv, "    CI compliance: %d\n",
-			coex->bt_ci_compliance);
-	iwlagn_print_uartmsg(priv, uart_msg);
-
-	priv->last_bt_traffic_load = priv->bt_traffic_load;
-	priv->bt_is_sco = iwlagn_bt_traffic_is_sco(uart_msg);
-
-	if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
-		if (priv->bt_status != coex->bt_status ||
-		    priv->last_bt_traffic_load != coex->bt_traffic_load) {
-			if (coex->bt_status) {
-				/* BT on */
-				if (!priv->bt_ch_announce)
-					priv->bt_traffic_load =
-						IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
-				else
-					priv->bt_traffic_load =
-						coex->bt_traffic_load;
-			} else {
-				/* BT off */
-				priv->bt_traffic_load =
-					IWL_BT_COEX_TRAFFIC_LOAD_NONE;
-			}
-			priv->bt_status = coex->bt_status;
-			queue_work(priv->workqueue,
-				   &priv->bt_traffic_change_work);
-		}
-	}
-
-	/* schedule to send runtime bt_config */
-	/* check reduce power before change ack/cts kill mask */
-	if (iwlagn_fill_txpower_mode(priv, uart_msg) ||
-	    iwlagn_set_kill_msk(priv, uart_msg))
-		queue_work(priv->workqueue, &priv->bt_runtime_config);
-
-
-	/* FIXME: based on notification, adjust the prio_boost */
-
-	priv->bt_ci_compliance = coex->bt_ci_compliance;
-	return 0;
-}
-
-void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv)
-{
-	priv->rx_handlers[REPLY_BT_COEX_PROFILE_NOTIF] =
-		iwlagn_bt_coex_profile_notif;
-}
-
-void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv)
-{
-	INIT_WORK(&priv->bt_traffic_change_work,
-		  iwlagn_bt_traffic_change_work);
-}
-
-void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv)
-{
-	cancel_work_sync(&priv->bt_traffic_change_work);
-}
-
-static bool is_single_rx_stream(struct iwl_priv *priv)
-{
-	return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
-	       priv->current_ht_config.single_chain_sufficient;
-}
-
-#define IWL_NUM_RX_CHAINS_MULTIPLE	3
-#define IWL_NUM_RX_CHAINS_SINGLE	2
-#define IWL_NUM_IDLE_CHAINS_DUAL	2
-#define IWL_NUM_IDLE_CHAINS_SINGLE	1
-
-/*
- * Determine how many receiver/antenna chains to use.
- *
- * More provides better reception via diversity.  Fewer saves power
- * at the expense of throughput, but only when not in powersave to
- * start with.
- *
- * MIMO (dual stream) requires at least 2, but works better with 3.
- * This does not determine *which* chains to use, just how many.
- */
-static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
-{
-	if (priv->cfg->bt_params &&
-	    priv->cfg->bt_params->advanced_bt_coexist &&
-	    (priv->bt_full_concurrent ||
-	     priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
-		/*
-		 * only use chain 'A' in bt high traffic load or
-		 * full concurrency mode
-		 */
-		return IWL_NUM_RX_CHAINS_SINGLE;
-	}
-	/* # of Rx chains to use when expecting MIMO. */
-	if (is_single_rx_stream(priv))
-		return IWL_NUM_RX_CHAINS_SINGLE;
-	else
-		return IWL_NUM_RX_CHAINS_MULTIPLE;
-}
-
-/*
- * When we are in power saving mode, unless device support spatial
- * multiplexing power save, use the active count for rx chain count.
- */
-static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
-{
-	/* # Rx chains when idling, depending on SMPS mode */
-	switch (priv->current_ht_config.smps) {
-	case IEEE80211_SMPS_STATIC:
-	case IEEE80211_SMPS_DYNAMIC:
-		return IWL_NUM_IDLE_CHAINS_SINGLE;
-	case IEEE80211_SMPS_AUTOMATIC:
-	case IEEE80211_SMPS_OFF:
-		return active_cnt;
-	default:
-		WARN(1, "invalid SMPS mode %d",
-		     priv->current_ht_config.smps);
-		return active_cnt;
-	}
-}
-
-/* up to 4 chains */
-static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
-{
-	u8 res;
-	res = (chain_bitmap & BIT(0)) >> 0;
-	res += (chain_bitmap & BIT(1)) >> 1;
-	res += (chain_bitmap & BIT(2)) >> 2;
-	res += (chain_bitmap & BIT(3)) >> 3;
-	return res;
-}
-
-/**
- * iwlagn_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
- *
- * Selects how many and which Rx receivers/antennas/chains to use.
- * This should not be used for scan command ... it puts data in wrong place.
- */
-void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-	bool is_single = is_single_rx_stream(priv);
-	bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
-	u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt;
-	u32 active_chains;
-	u16 rx_chain;
-
-	/* Tell uCode which antennas are actually connected.
-	 * Before first association, we assume all antennas are connected.
-	 * Just after first association, iwl_chain_noise_calibration()
-	 *    checks which antennas actually *are* connected. */
-	if (priv->chain_noise_data.active_chains)
-		active_chains = priv->chain_noise_data.active_chains;
-	else
-		active_chains = priv->hw_params.valid_rx_ant;
-
-	if (priv->cfg->bt_params &&
-	    priv->cfg->bt_params->advanced_bt_coexist &&
-	    (priv->bt_full_concurrent ||
-	     priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
-		/*
-		 * only use chain 'A' in bt high traffic load or
-		 * full concurrency mode
-		 */
-		active_chains = first_antenna(active_chains);
-	}
-
-	rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
-
-	/* How many receivers should we use? */
-	active_rx_cnt = iwl_get_active_rx_chain_count(priv);
-	idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
-
-
-	/* correct rx chain count according hw settings
-	 * and chain noise calibration
-	 */
-	valid_rx_cnt = iwl_count_chain_bitmap(active_chains);
-	if (valid_rx_cnt < active_rx_cnt)
-		active_rx_cnt = valid_rx_cnt;
-
-	if (valid_rx_cnt < idle_rx_cnt)
-		idle_rx_cnt = valid_rx_cnt;
-
-	rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
-	rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
-
-	ctx->staging.rx_chain = cpu_to_le16(rx_chain);
-
-	if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
-		ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
-	else
-		ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
-
-	IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n",
-			ctx->staging.rx_chain,
-			active_rx_cnt, idle_rx_cnt);
-
-	WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
-		active_rx_cnt < idle_rx_cnt);
-}
-
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
-{
-	int i;
-	u8 ind = ant;
-
-	if (priv->band == IEEE80211_BAND_2GHZ &&
-	    priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
-		return 0;
-
-	for (i = 0; i < RATE_ANT_NUM - 1; i++) {
-		ind = (ind + 1) < RATE_ANT_NUM ?  ind + 1 : 0;
-		if (valid & BIT(ind))
-			return ind;
-	}
-	return ant;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
-{
-	int i;
-
-	for (i = 0; i < IWLAGN_P1K_SIZE; i++)
-		out[i] = cpu_to_le16(p1k[i]);
-}
-
-struct wowlan_key_data {
-	struct iwl_rxon_context *ctx;
-	struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
-	struct iwlagn_wowlan_tkip_params_cmd *tkip;
-	const u8 *bssid;
-	bool error, use_rsc_tsc, use_tkip;
-};
-
-
-static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
-			       struct ieee80211_vif *vif,
-			       struct ieee80211_sta *sta,
-			       struct ieee80211_key_conf *key,
-			       void *_data)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct wowlan_key_data *data = _data;
-	struct iwl_rxon_context *ctx = data->ctx;
-	struct aes_sc *aes_sc, *aes_tx_sc = NULL;
-	struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
-	struct iwlagn_p1k_cache *rx_p1ks;
-	u8 *rx_mic_key;
-	struct ieee80211_key_seq seq;
-	u32 cur_rx_iv32 = 0;
-	u16 p1k[IWLAGN_P1K_SIZE];
-	int ret, i;
-
-	mutex_lock(&priv->mutex);
-
-	if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-	     key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
-	     !sta && !ctx->key_mapping_keys)
-		ret = iwl_set_default_wep_key(priv, ctx, key);
-	else
-		ret = iwl_set_dynamic_key(priv, ctx, key, sta);
-
-	if (ret) {
-		IWL_ERR(priv, "Error setting key during suspend!\n");
-		data->error = true;
-	}
-
-	switch (key->cipher) {
-	case WLAN_CIPHER_SUITE_TKIP:
-		if (sta) {
-			tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
-			tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
-
-			rx_p1ks = data->tkip->rx_uni;
-
-			ieee80211_get_key_tx_seq(key, &seq);
-			tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
-			tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
-
-			ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
-			iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
-
-			memcpy(data->tkip->mic_keys.tx,
-			       &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
-			       IWLAGN_MIC_KEY_SIZE);
-
-			rx_mic_key = data->tkip->mic_keys.rx_unicast;
-		} else {
-			tkip_sc =
-				data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
-			rx_p1ks = data->tkip->rx_multi;
-			rx_mic_key = data->tkip->mic_keys.rx_mcast;
-		}
-
-		/*
-		 * For non-QoS this relies on the fact that both the uCode and
-		 * mac80211 use TID 0 (as they need to to avoid replay attacks)
-		 * for checking the IV in the frames.
-		 */
-		for (i = 0; i < IWLAGN_NUM_RSC; i++) {
-			ieee80211_get_key_rx_seq(key, i, &seq);
-			tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
-			tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
-			/* wrapping isn't allowed, AP must rekey */
-			if (seq.tkip.iv32 > cur_rx_iv32)
-				cur_rx_iv32 = seq.tkip.iv32;
-		}
-
-		ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
-		iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
-		ieee80211_get_tkip_rx_p1k(key, data->bssid,
-					  cur_rx_iv32 + 1, p1k);
-		iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
-
-		memcpy(rx_mic_key,
-		       &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
-		       IWLAGN_MIC_KEY_SIZE);
-
-		data->use_tkip = true;
-		data->use_rsc_tsc = true;
-		break;
-	case WLAN_CIPHER_SUITE_CCMP:
-		if (sta) {
-			u8 *pn = seq.ccmp.pn;
-
-			aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
-			aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
-
-			ieee80211_get_key_tx_seq(key, &seq);
-			aes_tx_sc->pn = cpu_to_le64(
-					(u64)pn[5] |
-					((u64)pn[4] << 8) |
-					((u64)pn[3] << 16) |
-					((u64)pn[2] << 24) |
-					((u64)pn[1] << 32) |
-					((u64)pn[0] << 40));
-		} else
-			aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
-
-		/*
-		 * For non-QoS this relies on the fact that both the uCode and
-		 * mac80211 use TID 0 for checking the IV in the frames.
-		 */
-		for (i = 0; i < IWLAGN_NUM_RSC; i++) {
-			u8 *pn = seq.ccmp.pn;
-
-			ieee80211_get_key_rx_seq(key, i, &seq);
-			aes_sc->pn = cpu_to_le64(
-					(u64)pn[5] |
-					((u64)pn[4] << 8) |
-					((u64)pn[3] << 16) |
-					((u64)pn[2] << 24) |
-					((u64)pn[1] << 32) |
-					((u64)pn[0] << 40));
-		}
-		data->use_rsc_tsc = true;
-		break;
-	}
-
-	mutex_unlock(&priv->mutex);
-}
-
-int iwlagn_send_patterns(struct iwl_priv *priv,
-			struct cfg80211_wowlan *wowlan)
-{
-	struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_WOWLAN_PATTERNS,
-		.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-		.flags = CMD_SYNC,
-	};
-	int i, err;
-
-	if (!wowlan->n_patterns)
-		return 0;
-
-	cmd.len[0] = sizeof(*pattern_cmd) +
-		wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
-
-	pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
-	if (!pattern_cmd)
-		return -ENOMEM;
-
-	pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
-
-	for (i = 0; i < wowlan->n_patterns; i++) {
-		int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
-
-		memcpy(&pattern_cmd->patterns[i].mask,
-			wowlan->patterns[i].mask, mask_len);
-		memcpy(&pattern_cmd->patterns[i].pattern,
-			wowlan->patterns[i].pattern,
-			wowlan->patterns[i].pattern_len);
-		pattern_cmd->patterns[i].mask_size = mask_len;
-		pattern_cmd->patterns[i].pattern_size =
-			wowlan->patterns[i].pattern_len;
-	}
-
-	cmd.data[0] = pattern_cmd;
-	err = iwl_dvm_send_cmd(priv, &cmd);
-	kfree(pattern_cmd);
-	return err;
-}
-
-int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
-{
-	struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
-	struct iwl_rxon_cmd rxon;
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-	struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
-	struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
-	struct iwlagn_d3_config_cmd d3_cfg_cmd = {};
-	struct wowlan_key_data key_data = {
-		.ctx = ctx,
-		.bssid = ctx->active.bssid_addr,
-		.use_rsc_tsc = false,
-		.tkip = &tkip_cmd,
-		.use_tkip = false,
-	};
-	int ret, i;
-	u16 seq;
-
-	key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
-	if (!key_data.rsc_tsc)
-		return -ENOMEM;
-
-	memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
-
-	/*
-	 * We know the last used seqno, and the uCode expects to know that
-	 * one, it will increment before TX.
-	 */
-	seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
-	wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
-
-	/*
-	 * For QoS counters, we store the one to use next, so subtract 0x10
-	 * since the uCode will add 0x10 before using the value.
-	 */
-	for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
-		seq = priv->tid_data[IWL_AP_ID][i].seq_number;
-		seq -= 0x10;
-		wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
-	}
-
-	if (wowlan->disconnect)
-		wakeup_filter_cmd.enabled |=
-			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
-				    IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
-	if (wowlan->magic_pkt)
-		wakeup_filter_cmd.enabled |=
-			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
-	if (wowlan->gtk_rekey_failure)
-		wakeup_filter_cmd.enabled |=
-			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
-	if (wowlan->eap_identity_req)
-		wakeup_filter_cmd.enabled |=
-			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
-	if (wowlan->four_way_handshake)
-		wakeup_filter_cmd.enabled |=
-			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
-	if (wowlan->n_patterns)
-		wakeup_filter_cmd.enabled |=
-			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
-
-	if (wowlan->rfkill_release)
-		d3_cfg_cmd.wakeup_flags |=
-			cpu_to_le32(IWLAGN_D3_WAKEUP_RFKILL);
-
-	iwl_scan_cancel_timeout(priv, 200);
-
-	memcpy(&rxon, &ctx->active, sizeof(rxon));
-
-	priv->ucode_loaded = false;
-	iwl_trans_stop_device(priv->trans);
-
-	priv->wowlan = true;
-
-	ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
-	if (ret)
-		goto out;
-
-	/* now configure WoWLAN ucode */
-	ret = iwl_alive_start(priv);
-	if (ret)
-		goto out;
-
-	memcpy(&ctx->staging, &rxon, sizeof(rxon));
-	ret = iwlagn_commit_rxon(priv, ctx);
-	if (ret)
-		goto out;
-
-	ret = iwl_power_update_mode(priv, true);
-	if (ret)
-		goto out;
-
-	if (!iwlwifi_mod_params.sw_crypto) {
-		/* mark all keys clear */
-		priv->ucode_key_table = 0;
-		ctx->key_mapping_keys = 0;
-
-		/*
-		 * This needs to be unlocked due to lock ordering
-		 * constraints. Since we're in the suspend path
-		 * that isn't really a problem though.
-		 */
-		mutex_unlock(&priv->mutex);
-		ieee80211_iter_keys(priv->hw, ctx->vif,
-				    iwlagn_wowlan_program_keys,
-				    &key_data);
-		mutex_lock(&priv->mutex);
-		if (key_data.error) {
-			ret = -EIO;
-			goto out;
-		}
-
-		if (key_data.use_rsc_tsc) {
-			struct iwl_host_cmd rsc_tsc_cmd = {
-				.id = REPLY_WOWLAN_TSC_RSC_PARAMS,
-				.flags = CMD_SYNC,
-				.data[0] = key_data.rsc_tsc,
-				.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-				.len[0] = sizeof(*key_data.rsc_tsc),
-			};
-
-			ret = iwl_dvm_send_cmd(priv, &rsc_tsc_cmd);
-			if (ret)
-				goto out;
-		}
-
-		if (key_data.use_tkip) {
-			ret = iwl_dvm_send_cmd_pdu(priv,
-						 REPLY_WOWLAN_TKIP_PARAMS,
-						 CMD_SYNC, sizeof(tkip_cmd),
-						 &tkip_cmd);
-			if (ret)
-				goto out;
-		}
-
-		if (priv->have_rekey_data) {
-			memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
-			memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
-			kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
-			memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
-			kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
-			kek_kck_cmd.replay_ctr = priv->replay_ctr;
-
-			ret = iwl_dvm_send_cmd_pdu(priv,
-						 REPLY_WOWLAN_KEK_KCK_MATERIAL,
-						 CMD_SYNC, sizeof(kek_kck_cmd),
-						 &kek_kck_cmd);
-			if (ret)
-				goto out;
-		}
-	}
-
-	ret = iwl_dvm_send_cmd_pdu(priv, REPLY_D3_CONFIG, CMD_SYNC,
-				     sizeof(d3_cfg_cmd), &d3_cfg_cmd);
-	if (ret)
-		goto out;
-
-	ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_WAKEUP_FILTER,
-				 CMD_SYNC, sizeof(wakeup_filter_cmd),
-				 &wakeup_filter_cmd);
-	if (ret)
-		goto out;
-
-	ret = iwlagn_send_patterns(priv, wowlan);
- out:
-	kfree(key_data.rsc_tsc);
-	return ret;
-}
-#endif
-
-int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
-{
-	if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
-		IWL_WARN(priv, "Not sending command - %s KILL\n",
-			 iwl_is_rfkill(priv) ? "RF" : "CT");
-		return -EIO;
-	}
-
-	if (test_bit(STATUS_FW_ERROR, &priv->status)) {
-		IWL_ERR(priv, "Command %s failed: FW Error\n",
-			iwl_dvm_get_cmd_string(cmd->id));
-		return -EIO;
-	}
-
-	/*
-	 * Synchronous commands from this op-mode must hold
-	 * the mutex, this ensures we don't try to send two
-	 * (or more) synchronous commands at a time.
-	 */
-	if (cmd->flags & CMD_SYNC)
-		lockdep_assert_held(&priv->mutex);
-
-	if (priv->ucode_owner == IWL_OWNERSHIP_TM &&
-	    !(cmd->flags & CMD_ON_DEMAND)) {
-		IWL_DEBUG_HC(priv, "tm own the uCode, no regular hcmd send\n");
-		return -EIO;
-	}
-
-	return iwl_trans_send_cmd(priv->trans, cmd);
-}
-
-int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
-			 u32 flags, u16 len, const void *data)
-{
-	struct iwl_host_cmd cmd = {
-		.id = id,
-		.len = { len, },
-		.data = { data, },
-		.flags = flags,
-	};
-
-	return iwl_dvm_send_cmd(priv, &cmd);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
deleted file mode 100644
index 8cebd7c..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ /dev/null
@@ -1,3369 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2005 - 2012 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.
- *
- * 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/init.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <net/mac80211.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-
-#include <linux/workqueue.h>
-
-#include "iwl-dev.h"
-#include "iwl-agn.h"
-#include "iwl-op-mode.h"
-#include "iwl-modparams.h"
-
-#define RS_NAME "iwl-agn-rs"
-
-#define NUM_TRY_BEFORE_ANT_TOGGLE 1
-#define IWL_NUMBER_TRY      1
-#define IWL_HT_NUMBER_TRY   3
-
-#define IWL_RATE_MAX_WINDOW		62	/* # tx in history window */
-#define IWL_RATE_MIN_FAILURE_TH		6	/* min failures to calc tpt */
-#define IWL_RATE_MIN_SUCCESS_TH		8	/* min successes to calc tpt */
-
-/* max allowed rate miss before sync LQ cmd */
-#define IWL_MISSED_RATE_MAX		15
-/* max time to accum history 2 seconds */
-#define IWL_RATE_SCALE_FLUSH_INTVL   (3*HZ)
-
-static u8 rs_ht_to_legacy[] = {
-	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
-	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
-	IWL_RATE_6M_INDEX,
-	IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX,
-	IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX,
-	IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX,
-	IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
-};
-
-static const u8 ant_toggle_lookup[] = {
-	/*ANT_NONE -> */ ANT_NONE,
-	/*ANT_A    -> */ ANT_B,
-	/*ANT_B    -> */ ANT_C,
-	/*ANT_AB   -> */ ANT_BC,
-	/*ANT_C    -> */ ANT_A,
-	/*ANT_AC   -> */ ANT_AB,
-	/*ANT_BC   -> */ ANT_AC,
-	/*ANT_ABC  -> */ ANT_ABC,
-};
-
-#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
-	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
-				    IWL_RATE_SISO_##s##M_PLCP, \
-				    IWL_RATE_MIMO2_##s##M_PLCP,\
-				    IWL_RATE_MIMO3_##s##M_PLCP,\
-				    IWL_RATE_##r##M_IEEE,      \
-				    IWL_RATE_##ip##M_INDEX,    \
-				    IWL_RATE_##in##M_INDEX,    \
-				    IWL_RATE_##rp##M_INDEX,    \
-				    IWL_RATE_##rn##M_INDEX,    \
-				    IWL_RATE_##pp##M_INDEX,    \
-				    IWL_RATE_##np##M_INDEX }
-
-/*
- * Parameter order:
- *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
- *
- * If there isn't a valid next or previous rate then INV is used which
- * maps to IWL_RATE_INVALID
- *
- */
-const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
-	IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
-	IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
-	IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
-	IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */
-	IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
-	IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */
-	IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
-	IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
-	IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
-	IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
-	IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
-	IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
-	IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
-	/* FIXME:RS:          ^^    should be INV (legacy) */
-};
-
-static inline u8 rs_extract_rate(u32 rate_n_flags)
-{
-	return (u8)(rate_n_flags & RATE_MCS_RATE_MSK);
-}
-
-static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
-{
-	int idx = 0;
-
-	/* HT rate format */
-	if (rate_n_flags & RATE_MCS_HT_MSK) {
-		idx = rs_extract_rate(rate_n_flags);
-
-		if (idx >= IWL_RATE_MIMO3_6M_PLCP)
-			idx = idx - IWL_RATE_MIMO3_6M_PLCP;
-		else if (idx >= IWL_RATE_MIMO2_6M_PLCP)
-			idx = idx - IWL_RATE_MIMO2_6M_PLCP;
-
-		idx += IWL_FIRST_OFDM_RATE;
-		/* skip 9M not supported in ht*/
-		if (idx >= IWL_RATE_9M_INDEX)
-			idx += 1;
-		if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE))
-			return idx;
-
-	/* legacy rate format, search for match in table */
-	} else {
-		for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
-			if (iwl_rates[idx].plcp ==
-					rs_extract_rate(rate_n_flags))
-				return idx;
-	}
-
-	return -1;
-}
-
-static void rs_rate_scale_perform(struct iwl_priv *priv,
-				   struct sk_buff *skb,
-				   struct ieee80211_sta *sta,
-				   struct iwl_lq_sta *lq_sta);
-static void rs_fill_link_cmd(struct iwl_priv *priv,
-			     struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
-static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
-
-
-#ifdef CONFIG_MAC80211_DEBUGFS
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-			     u32 *rate_n_flags, int index);
-#else
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-			     u32 *rate_n_flags, int index)
-{}
-#endif
-
-/**
- * The following tables contain the expected throughput metrics for all rates
- *
- *	1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
- *
- * where invalid entries are zeros.
- *
- * CCK rates are only valid in legacy table and will only be used in G
- * (2.4 GHz) band.
- */
-
-static s32 expected_tpt_legacy[IWL_RATE_COUNT] = {
-	7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0
-};
-
-static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = {
-	{0, 0, 0, 0, 42, 0,  76, 102, 124, 159, 183, 193, 202}, /* Norm */
-	{0, 0, 0, 0, 46, 0,  82, 110, 132, 168, 192, 202, 210}, /* SGI */
-	{0, 0, 0, 0, 47, 0,  91, 133, 171, 242, 305, 334, 362}, /* AGG */
-	{0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */
-};
-
-static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = {
-	{0, 0, 0, 0,  77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */
-	{0, 0, 0, 0,  83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */
-	{0, 0, 0, 0,  94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */
-	{0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */
-};
-
-static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
-	{0, 0, 0, 0,  74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */
-	{0, 0, 0, 0,  81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */
-	{0, 0, 0, 0,  89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */
-	{0, 0, 0, 0,  97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/
-};
-
-static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = {
-	{0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */
-	{0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */
-	{0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */
-	{0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */
-};
-
-static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = {
-	{0, 0, 0, 0,  99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */
-	{0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */
-	{0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */
-	{0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */
-};
-
-static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = {
-	{0, 0, 0, 0, 152, 0, 211, 239, 255, 279,  290,  294,  297}, /* Norm */
-	{0, 0, 0, 0, 160, 0, 219, 245, 261, 284,  294,  297,  300}, /* SGI */
-	{0, 0, 0, 0, 254, 0, 443, 584, 695, 868,  984, 1030, 1070}, /* AGG */
-	{0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */
-};
-
-/* mbps, mcs */
-static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
-	{  "1", "BPSK DSSS"},
-	{  "2", "QPSK DSSS"},
-	{"5.5", "BPSK CCK"},
-	{ "11", "QPSK CCK"},
-	{  "6", "BPSK 1/2"},
-	{  "9", "BPSK 1/2"},
-	{ "12", "QPSK 1/2"},
-	{ "18", "QPSK 3/4"},
-	{ "24", "16QAM 1/2"},
-	{ "36", "16QAM 3/4"},
-	{ "48", "64QAM 2/3"},
-	{ "54", "64QAM 3/4"},
-	{ "60", "64QAM 5/6"},
-};
-
-#define MCS_INDEX_PER_STREAM	(8)
-
-static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
-{
-	window->data = 0;
-	window->success_counter = 0;
-	window->success_ratio = IWL_INVALID_VALUE;
-	window->counter = 0;
-	window->average_tpt = IWL_INVALID_VALUE;
-	window->stamp = 0;
-}
-
-static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
-{
-	return (ant_type & valid_antenna) == ant_type;
-}
-
-/*
- *	removes the old data from the statistics. All data that is older than
- *	TID_MAX_TIME_DIFF, will be deleted.
- */
-static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time)
-{
-	/* The oldest age we want to keep */
-	u32 oldest_time = curr_time - TID_MAX_TIME_DIFF;
-
-	while (tl->queue_count &&
-	       (tl->time_stamp < oldest_time)) {
-		tl->total -= tl->packet_count[tl->head];
-		tl->packet_count[tl->head] = 0;
-		tl->time_stamp += TID_QUEUE_CELL_SPACING;
-		tl->queue_count--;
-		tl->head++;
-		if (tl->head >= TID_QUEUE_MAX_SIZE)
-			tl->head = 0;
-	}
-}
-
-/*
- *	increment traffic load value for tid and also remove
- *	any old values if passed the certain time period
- */
-static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
-			   struct ieee80211_hdr *hdr)
-{
-	u32 curr_time = jiffies_to_msecs(jiffies);
-	u32 time_diff;
-	s32 index;
-	struct iwl_traffic_load *tl = NULL;
-	u8 tid;
-
-	if (ieee80211_is_data_qos(hdr->frame_control)) {
-		u8 *qc = ieee80211_get_qos_ctl(hdr);
-		tid = qc[0] & 0xf;
-	} else
-		return IWL_MAX_TID_COUNT;
-
-	if (unlikely(tid >= IWL_MAX_TID_COUNT))
-		return IWL_MAX_TID_COUNT;
-
-	tl = &lq_data->load[tid];
-
-	curr_time -= curr_time % TID_ROUND_VALUE;
-
-	/* Happens only for the first packet. Initialize the data */
-	if (!(tl->queue_count)) {
-		tl->total = 1;
-		tl->time_stamp = curr_time;
-		tl->queue_count = 1;
-		tl->head = 0;
-		tl->packet_count[0] = 1;
-		return IWL_MAX_TID_COUNT;
-	}
-
-	time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
-	index = time_diff / TID_QUEUE_CELL_SPACING;
-
-	/* The history is too long: remove data that is older than */
-	/* TID_MAX_TIME_DIFF */
-	if (index >= TID_QUEUE_MAX_SIZE)
-		rs_tl_rm_old_stats(tl, curr_time);
-
-	index = (tl->head + index) % TID_QUEUE_MAX_SIZE;
-	tl->packet_count[index] = tl->packet_count[index] + 1;
-	tl->total = tl->total + 1;
-
-	if ((index + 1) > tl->queue_count)
-		tl->queue_count = index + 1;
-
-	return tid;
-}
-
-#ifdef CONFIG_MAC80211_DEBUGFS
-/**
- * Program the device to use fixed rate for frame transmit
- * This is for debugging/testing only
- * once the device start use fixed rate, we need to reload the module
- * to being back the normal operation.
- */
-static void rs_program_fix_rate(struct iwl_priv *priv,
-				struct iwl_lq_sta *lq_sta)
-{
-	struct iwl_station_priv *sta_priv =
-		container_of(lq_sta, struct iwl_station_priv, lq_sta);
-	struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-	lq_sta->active_legacy_rate = 0x0FFF;	/* 1 - 54 MBits, includes CCK */
-	lq_sta->active_siso_rate   = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
-	lq_sta->active_mimo2_rate  = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
-	lq_sta->active_mimo3_rate  = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
-
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-	/* testmode has higher priority to overwirte the fixed rate */
-	if (priv->tm_fixed_rate)
-		lq_sta->dbg_fixed_rate = priv->tm_fixed_rate;
-#endif
-
-	IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
-		lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
-
-	if (lq_sta->dbg_fixed_rate) {
-		rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
-		iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
-				false);
-	}
-}
-#endif
-
-/*
-	get the traffic load value for tid
-*/
-static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid)
-{
-	u32 curr_time = jiffies_to_msecs(jiffies);
-	u32 time_diff;
-	s32 index;
-	struct iwl_traffic_load *tl = NULL;
-
-	if (tid >= IWL_MAX_TID_COUNT)
-		return 0;
-
-	tl = &(lq_data->load[tid]);
-
-	curr_time -= curr_time % TID_ROUND_VALUE;
-
-	if (!(tl->queue_count))
-		return 0;
-
-	time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
-	index = time_diff / TID_QUEUE_CELL_SPACING;
-
-	/* The history is too long: remove data that is older than */
-	/* TID_MAX_TIME_DIFF */
-	if (index >= TID_QUEUE_MAX_SIZE)
-		rs_tl_rm_old_stats(tl, curr_time);
-
-	return tl->total;
-}
-
-static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
-				      struct iwl_lq_sta *lq_data, u8 tid,
-				      struct ieee80211_sta *sta)
-{
-	int ret = -EAGAIN;
-	u32 load;
-
-	/*
-	 * Don't create TX aggregation sessions when in high
-	 * BT traffic, as they would just be disrupted by BT.
-	 */
-	if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) {
-		IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n",
-			priv->bt_traffic_load);
-		return ret;
-	}
-
-	load = rs_tl_get_load(lq_data, tid);
-
-	if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) {
-		IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
-				sta->addr, tid);
-		ret = ieee80211_start_tx_ba_session(sta, tid, 5000);
-		if (ret == -EAGAIN) {
-			/*
-			 * driver and mac80211 is out of sync
-			 * this might be cause by reloading firmware
-			 * stop the tx ba session here
-			 */
-			IWL_ERR(priv, "Fail start Tx agg on tid: %d\n",
-				tid);
-			ieee80211_stop_tx_ba_session(sta, tid);
-		}
-	} else {
-		IWL_DEBUG_HT(priv, "Aggregation not enabled for tid %d "
-			"because load = %u\n", tid, load);
-	}
-	return ret;
-}
-
-static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
-			      struct iwl_lq_sta *lq_data,
-			      struct ieee80211_sta *sta)
-{
-	if (tid < IWL_MAX_TID_COUNT)
-		rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
-	else
-		IWL_ERR(priv, "tid exceeds max TID count: %d/%d\n",
-			tid, IWL_MAX_TID_COUNT);
-}
-
-static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
-{
-	return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
-	       !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
-	       !!(rate_n_flags & RATE_MCS_ANT_C_MSK);
-}
-
-/*
- * Static function to get the expected throughput from an iwl_scale_tbl_info
- * that wraps a NULL pointer check
- */
-static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
-{
-	if (tbl->expected_tpt)
-		return tbl->expected_tpt[rs_index];
-	return 0;
-}
-
-/**
- * rs_collect_tx_data - Update the success/failure sliding window
- *
- * We keep a sliding window of the last 62 packets transmitted
- * at this rate.  window->data contains the bitmask of successful
- * packets.
- */
-static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
-			      int scale_index, int attempts, int successes)
-{
-	struct iwl_rate_scale_data *window = NULL;
-	static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
-	s32 fail_count, tpt;
-
-	if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
-		return -EINVAL;
-
-	/* Select window for current tx bit rate */
-	window = &(tbl->win[scale_index]);
-
-	/* Get expected throughput */
-	tpt = get_expected_tpt(tbl, scale_index);
-
-	/*
-	 * Keep track of only the latest 62 tx frame attempts in this rate's
-	 * history window; anything older isn't really relevant any more.
-	 * If we have filled up the sliding window, drop the oldest attempt;
-	 * if the oldest attempt (highest bit in bitmap) shows "success",
-	 * subtract "1" from the success counter (this is the main reason
-	 * we keep these bitmaps!).
-	 */
-	while (attempts > 0) {
-		if (window->counter >= IWL_RATE_MAX_WINDOW) {
-
-			/* remove earliest */
-			window->counter = IWL_RATE_MAX_WINDOW - 1;
-
-			if (window->data & mask) {
-				window->data &= ~mask;
-				window->success_counter--;
-			}
-		}
-
-		/* Increment frames-attempted counter */
-		window->counter++;
-
-		/* Shift bitmap by one frame to throw away oldest history */
-		window->data <<= 1;
-
-		/* Mark the most recent #successes attempts as successful */
-		if (successes > 0) {
-			window->success_counter++;
-			window->data |= 0x1;
-			successes--;
-		}
-
-		attempts--;
-	}
-
-	/* Calculate current success ratio, avoid divide-by-0! */
-	if (window->counter > 0)
-		window->success_ratio = 128 * (100 * window->success_counter)
-					/ window->counter;
-	else
-		window->success_ratio = IWL_INVALID_VALUE;
-
-	fail_count = window->counter - window->success_counter;
-
-	/* Calculate average throughput, if we have enough history. */
-	if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
-	    (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
-		window->average_tpt = (window->success_ratio * tpt + 64) / 128;
-	else
-		window->average_tpt = IWL_INVALID_VALUE;
-
-	/* Tag this window as having been updated */
-	window->stamp = jiffies;
-
-	return 0;
-}
-
-/*
- * Fill uCode API rate_n_flags field, based on "search" or "active" table.
- */
-/* FIXME:RS:remove this function and put the flags statically in the table */
-static u32 rate_n_flags_from_tbl(struct iwl_priv *priv,
-				 struct iwl_scale_tbl_info *tbl,
-				 int index, u8 use_green)
-{
-	u32 rate_n_flags = 0;
-
-	if (is_legacy(tbl->lq_type)) {
-		rate_n_flags = iwl_rates[index].plcp;
-		if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
-			rate_n_flags |= RATE_MCS_CCK_MSK;
-
-	} else if (is_Ht(tbl->lq_type)) {
-		if (index > IWL_LAST_OFDM_RATE) {
-			IWL_ERR(priv, "Invalid HT rate index %d\n", index);
-			index = IWL_LAST_OFDM_RATE;
-		}
-		rate_n_flags = RATE_MCS_HT_MSK;
-
-		if (is_siso(tbl->lq_type))
-			rate_n_flags |=	iwl_rates[index].plcp_siso;
-		else if (is_mimo2(tbl->lq_type))
-			rate_n_flags |=	iwl_rates[index].plcp_mimo2;
-		else
-			rate_n_flags |=	iwl_rates[index].plcp_mimo3;
-	} else {
-		IWL_ERR(priv, "Invalid tbl->lq_type %d\n", tbl->lq_type);
-	}
-
-	rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) &
-						     RATE_MCS_ANT_ABC_MSK);
-
-	if (is_Ht(tbl->lq_type)) {
-		if (tbl->is_ht40) {
-			if (tbl->is_dup)
-				rate_n_flags |= RATE_MCS_DUP_MSK;
-			else
-				rate_n_flags |= RATE_MCS_HT40_MSK;
-		}
-		if (tbl->is_SGI)
-			rate_n_flags |= RATE_MCS_SGI_MSK;
-
-		if (use_green) {
-			rate_n_flags |= RATE_MCS_GF_MSK;
-			if (is_siso(tbl->lq_type) && tbl->is_SGI) {
-				rate_n_flags &= ~RATE_MCS_SGI_MSK;
-				IWL_ERR(priv, "GF was set with SGI:SISO\n");
-			}
-		}
-	}
-	return rate_n_flags;
-}
-
-/*
- * Interpret uCode API's rate_n_flags format,
- * fill "search" or "active" tx mode table.
- */
-static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
-				    enum ieee80211_band band,
-				    struct iwl_scale_tbl_info *tbl,
-				    int *rate_idx)
-{
-	u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK);
-	u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
-	u8 mcs;
-
-	memset(tbl, 0, sizeof(struct iwl_scale_tbl_info));
-	*rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
-
-	if (*rate_idx  == IWL_RATE_INVALID) {
-		*rate_idx = -1;
-		return -EINVAL;
-	}
-	tbl->is_SGI = 0;	/* default legacy setup */
-	tbl->is_ht40 = 0;
-	tbl->is_dup = 0;
-	tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
-	tbl->lq_type = LQ_NONE;
-	tbl->max_search = IWL_MAX_SEARCH;
-
-	/* legacy rate format */
-	if (!(rate_n_flags & RATE_MCS_HT_MSK)) {
-		if (num_of_ant == 1) {
-			if (band == IEEE80211_BAND_5GHZ)
-				tbl->lq_type = LQ_A;
-			else
-				tbl->lq_type = LQ_G;
-		}
-	/* HT rate format */
-	} else {
-		if (rate_n_flags & RATE_MCS_SGI_MSK)
-			tbl->is_SGI = 1;
-
-		if ((rate_n_flags & RATE_MCS_HT40_MSK) ||
-		    (rate_n_flags & RATE_MCS_DUP_MSK))
-			tbl->is_ht40 = 1;
-
-		if (rate_n_flags & RATE_MCS_DUP_MSK)
-			tbl->is_dup = 1;
-
-		mcs = rs_extract_rate(rate_n_flags);
-
-		/* SISO */
-		if (mcs <= IWL_RATE_SISO_60M_PLCP) {
-			if (num_of_ant == 1)
-				tbl->lq_type = LQ_SISO; /*else NONE*/
-		/* MIMO2 */
-		} else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) {
-			if (num_of_ant == 2)
-				tbl->lq_type = LQ_MIMO2;
-		/* MIMO3 */
-		} else {
-			if (num_of_ant == 3) {
-				tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
-				tbl->lq_type = LQ_MIMO3;
-			}
-		}
-	}
-	return 0;
-}
-
-/* switch to another antenna/antennas and return 1 */
-/* if no other valid antenna found, return 0 */
-static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
-			     struct iwl_scale_tbl_info *tbl)
-{
-	u8 new_ant_type;
-
-	if (!tbl->ant_type || tbl->ant_type > ANT_ABC)
-		return 0;
-
-	if (!rs_is_valid_ant(valid_ant, tbl->ant_type))
-		return 0;
-
-	new_ant_type = ant_toggle_lookup[tbl->ant_type];
-
-	while ((new_ant_type != tbl->ant_type) &&
-	       !rs_is_valid_ant(valid_ant, new_ant_type))
-		new_ant_type = ant_toggle_lookup[new_ant_type];
-
-	if (new_ant_type == tbl->ant_type)
-		return 0;
-
-	tbl->ant_type = new_ant_type;
-	*rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK;
-	*rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS;
-	return 1;
-}
-
-/**
- * Green-field mode is valid if the station supports it and
- * there are no non-GF stations present in the BSS.
- */
-static bool rs_use_green(struct ieee80211_sta *sta)
-{
-	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-	struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-	return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
-		!(ctx->ht.non_gf_sta_present);
-}
-
-/**
- * rs_get_supported_rates - get the available rates
- *
- * if management frame or broadcast frame only return
- * basic available rates.
- *
- */
-static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
-				  struct ieee80211_hdr *hdr,
-				  enum iwl_table_type rate_type)
-{
-	if (is_legacy(rate_type)) {
-		return lq_sta->active_legacy_rate;
-	} else {
-		if (is_siso(rate_type))
-			return lq_sta->active_siso_rate;
-		else if (is_mimo2(rate_type))
-			return lq_sta->active_mimo2_rate;
-		else
-			return lq_sta->active_mimo3_rate;
-	}
-}
-
-static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,
-				int rate_type)
-{
-	u8 high = IWL_RATE_INVALID;
-	u8 low = IWL_RATE_INVALID;
-
-	/* 802.11A or ht walks to the next literal adjacent rate in
-	 * the rate table */
-	if (is_a_band(rate_type) || !is_legacy(rate_type)) {
-		int i;
-		u32 mask;
-
-		/* Find the previous rate that is in the rate mask */
-		i = index - 1;
-		for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
-			if (rate_mask & mask) {
-				low = i;
-				break;
-			}
-		}
-
-		/* Find the next rate that is in the rate mask */
-		i = index + 1;
-		for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
-			if (rate_mask & mask) {
-				high = i;
-				break;
-			}
-		}
-
-		return (high << 8) | low;
-	}
-
-	low = index;
-	while (low != IWL_RATE_INVALID) {
-		low = iwl_rates[low].prev_rs;
-		if (low == IWL_RATE_INVALID)
-			break;
-		if (rate_mask & (1 << low))
-			break;
-		IWL_DEBUG_RATE(priv, "Skipping masked lower rate: %d\n", low);
-	}
-
-	high = index;
-	while (high != IWL_RATE_INVALID) {
-		high = iwl_rates[high].next_rs;
-		if (high == IWL_RATE_INVALID)
-			break;
-		if (rate_mask & (1 << high))
-			break;
-		IWL_DEBUG_RATE(priv, "Skipping masked higher rate: %d\n", high);
-	}
-
-	return (high << 8) | low;
-}
-
-static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
-			     struct iwl_scale_tbl_info *tbl,
-			     u8 scale_index, u8 ht_possible)
-{
-	s32 low;
-	u16 rate_mask;
-	u16 high_low;
-	u8 switch_to_legacy = 0;
-	u8 is_green = lq_sta->is_green;
-	struct iwl_priv *priv = lq_sta->drv;
-
-	/* check if we need to switch from HT to legacy rates.
-	 * assumption is that mandatory rates (1Mbps or 6Mbps)
-	 * are always supported (spec demand) */
-	if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
-		switch_to_legacy = 1;
-		scale_index = rs_ht_to_legacy[scale_index];
-		if (lq_sta->band == IEEE80211_BAND_5GHZ)
-			tbl->lq_type = LQ_A;
-		else
-			tbl->lq_type = LQ_G;
-
-		if (num_of_ant(tbl->ant_type) > 1)
-			tbl->ant_type =
-			    first_antenna(priv->hw_params.valid_tx_ant);
-
-		tbl->is_ht40 = 0;
-		tbl->is_SGI = 0;
-		tbl->max_search = IWL_MAX_SEARCH;
-	}
-
-	rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type);
-
-	/* Mask with station rate restriction */
-	if (is_legacy(tbl->lq_type)) {
-		/* supp_rates has no CCK bits in A mode */
-		if (lq_sta->band == IEEE80211_BAND_5GHZ)
-			rate_mask  = (u16)(rate_mask &
-			   (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
-		else
-			rate_mask = (u16)(rate_mask & lq_sta->supp_rates);
-	}
-
-	/* If we switched from HT to legacy, check current rate */
-	if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
-		low = scale_index;
-		goto out;
-	}
-
-	high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask,
-					tbl->lq_type);
-	low = high_low & 0xff;
-
-	if (low == IWL_RATE_INVALID)
-		low = scale_index;
-
-out:
-	return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green);
-}
-
-/*
- * Simple function to compare two rate scale table types
- */
-static bool table_type_matches(struct iwl_scale_tbl_info *a,
-			       struct iwl_scale_tbl_info *b)
-{
-	return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) &&
-		(a->is_SGI == b->is_SGI);
-}
-
-static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-			    struct iwl_lq_sta *lq_sta)
-{
-	struct iwl_scale_tbl_info *tbl;
-	bool full_concurrent = priv->bt_full_concurrent;
-
-	if (priv->bt_ant_couple_ok) {
-		/*
-		 * Is there a need to switch between
-		 * full concurrency and 3-wire?
-		 */
-		if (priv->bt_ci_compliance && priv->bt_ant_couple_ok)
-			full_concurrent = true;
-		else
-			full_concurrent = false;
-	}
-	if ((priv->bt_traffic_load != priv->last_bt_traffic_load) ||
-	    (priv->bt_full_concurrent != full_concurrent)) {
-		priv->bt_full_concurrent = full_concurrent;
-		priv->last_bt_traffic_load = priv->bt_traffic_load;
-
-		/* Update uCode's rate table. */
-		tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-		rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
-		iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
-
-		queue_work(priv->workqueue, &priv->bt_full_concurrency);
-	}
-}
-
-/*
- * mac80211 sends us Tx status
- */
-static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
-			 struct ieee80211_sta *sta, void *priv_sta,
-			 struct sk_buff *skb)
-{
-	int legacy_success;
-	int retries;
-	int rs_index, mac_index, i;
-	struct iwl_lq_sta *lq_sta = priv_sta;
-	struct iwl_link_quality_cmd *table;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct iwl_op_mode *op_mode = (struct iwl_op_mode *)priv_r;
-	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	enum mac80211_rate_control_flags mac_flags;
-	u32 tx_rate;
-	struct iwl_scale_tbl_info tbl_type;
-	struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
-	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-	struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-	IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
-
-	/* Treat uninitialized rate scaling data same as non-existing. */
-	if (!lq_sta) {
-		IWL_DEBUG_RATE(priv, "Station rate scaling not created yet.\n");
-		return;
-	} else if (!lq_sta->drv) {
-		IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n");
-		return;
-	}
-
-	if (!ieee80211_is_data(hdr->frame_control) ||
-	    info->flags & IEEE80211_TX_CTL_NO_ACK)
-		return;
-
-	/* This packet was aggregated but doesn't carry status info */
-	if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
-	    !(info->flags & IEEE80211_TX_STAT_AMPDU))
-		return;
-
-	/*
-	 * Ignore this Tx frame response if its initial rate doesn't match
-	 * that of latest Link Quality command.  There may be stragglers
-	 * from a previous Link Quality command, but we're no longer interested
-	 * in those; they're either from the "active" mode while we're trying
-	 * to check "search" mode, or a prior "search" mode after we've moved
-	 * to a new "search" mode (which might become the new "active" mode).
-	 */
-	table = &lq_sta->lq;
-	tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
-	rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
-	if (priv->band == IEEE80211_BAND_5GHZ)
-		rs_index -= IWL_FIRST_OFDM_RATE;
-	mac_flags = info->status.rates[0].flags;
-	mac_index = info->status.rates[0].idx;
-	/* For HT packets, map MCS to PLCP */
-	if (mac_flags & IEEE80211_TX_RC_MCS) {
-		mac_index &= RATE_MCS_CODE_MSK;	/* Remove # of streams */
-		if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE))
-			mac_index++;
-		/*
-		 * mac80211 HT index is always zero-indexed; we need to move
-		 * HT OFDM rates after CCK rates in 2.4 GHz band
-		 */
-		if (priv->band == IEEE80211_BAND_2GHZ)
-			mac_index += IWL_FIRST_OFDM_RATE;
-	}
-	/* Here we actually compare this rate to the latest LQ command */
-	if ((mac_index < 0) ||
-	    (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
-	    (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
-	    (tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA)) ||
-	    (tbl_type.ant_type != info->status.antenna) ||
-	    (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) ||
-	    (!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
-	    (rs_index != mac_index)) {
-		IWL_DEBUG_RATE(priv, "initial rate %d does not match %d (0x%x)\n", mac_index, rs_index, tx_rate);
-		/*
-		 * Since rates mis-match, the last LQ command may have failed.
-		 * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
-		 * ... driver.
-		 */
-		lq_sta->missed_rate_counter++;
-		if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
-			lq_sta->missed_rate_counter = 0;
-			iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
-		}
-		/* Regardless, ignore this status info for outdated rate */
-		return;
-	} else
-		/* Rate did match, so reset the missed_rate_counter */
-		lq_sta->missed_rate_counter = 0;
-
-	/* Figure out if rate scale algorithm is in active or search table */
-	if (table_type_matches(&tbl_type,
-				&(lq_sta->lq_info[lq_sta->active_tbl]))) {
-		curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-		other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
-	} else if (table_type_matches(&tbl_type,
-				&lq_sta->lq_info[1 - lq_sta->active_tbl])) {
-		curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
-		other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-	} else {
-		IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");
-		tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-		IWL_DEBUG_RATE(priv, "active- lq:%x, ant:%x, SGI:%d\n",
-			tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
-		tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
-		IWL_DEBUG_RATE(priv, "search- lq:%x, ant:%x, SGI:%d\n",
-			tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
-		IWL_DEBUG_RATE(priv, "actual- lq:%x, ant:%x, SGI:%d\n",
-			tbl_type.lq_type, tbl_type.ant_type, tbl_type.is_SGI);
-		/*
-		 * no matching table found, let's by-pass the data collection
-		 * and continue to perform rate scale to find the rate table
-		 */
-		rs_stay_in_table(lq_sta, true);
-		goto done;
-	}
-
-	/*
-	 * Updating the frame history depends on whether packets were
-	 * aggregated.
-	 *
-	 * For aggregation, all packets were transmitted at the same rate, the
-	 * first index into rate scale table.
-	 */
-	if (info->flags & IEEE80211_TX_STAT_AMPDU) {
-		tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
-		rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type,
-				&rs_index);
-		rs_collect_tx_data(curr_tbl, rs_index,
-				   info->status.ampdu_len,
-				   info->status.ampdu_ack_len);
-
-		/* Update success/fail counts if not searching for new mode */
-		if (lq_sta->stay_in_tbl) {
-			lq_sta->total_success += info->status.ampdu_ack_len;
-			lq_sta->total_failed += (info->status.ampdu_len -
-					info->status.ampdu_ack_len);
-		}
-	} else {
-	/*
-	 * For legacy, update frame history with for each Tx retry.
-	 */
-		retries = info->status.rates[0].count - 1;
-		/* HW doesn't send more than 15 retries */
-		retries = min(retries, 15);
-
-		/* The last transmission may have been successful */
-		legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
-		/* Collect data for each rate used during failed TX attempts */
-		for (i = 0; i <= retries; ++i) {
-			tx_rate = le32_to_cpu(table->rs_table[i].rate_n_flags);
-			rs_get_tbl_info_from_mcs(tx_rate, priv->band,
-					&tbl_type, &rs_index);
-			/*
-			 * Only collect stats if retried rate is in the same RS
-			 * table as active/search.
-			 */
-			if (table_type_matches(&tbl_type, curr_tbl))
-				tmp_tbl = curr_tbl;
-			else if (table_type_matches(&tbl_type, other_tbl))
-				tmp_tbl = other_tbl;
-			else
-				continue;
-			rs_collect_tx_data(tmp_tbl, rs_index, 1,
-					   i < retries ? 0 : legacy_success);
-		}
-
-		/* Update success/fail counts if not searching for new mode */
-		if (lq_sta->stay_in_tbl) {
-			lq_sta->total_success += legacy_success;
-			lq_sta->total_failed += retries + (1 - legacy_success);
-		}
-	}
-	/* The last TX rate is cached in lq_sta; it's set in if/else above */
-	lq_sta->last_rate_n_flags = tx_rate;
-done:
-	/* See if there's a better rate or modulation mode to try. */
-	if (sta && sta->supp_rates[sband->band])
-		rs_rate_scale_perform(priv, skb, sta, lq_sta);
-
-#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_IWLWIFI_DEVICE_TESTMODE)
-	if ((priv->tm_fixed_rate) &&
-	    (priv->tm_fixed_rate != lq_sta->dbg_fixed_rate))
-		rs_program_fix_rate(priv, lq_sta);
-#endif
-	if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
-		rs_bt_update_lq(priv, ctx, lq_sta);
-}
-
-/*
- * Begin a period of staying with a selected modulation mode.
- * Set "stay_in_tbl" flag to prevent any mode switches.
- * Set frame tx success limits according to legacy vs. high-throughput,
- * and reset overall (spanning all rates) tx success history statistics.
- * These control how long we stay using same modulation mode before
- * searching for a new mode.
- */
-static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
-				 struct iwl_lq_sta *lq_sta)
-{
-	IWL_DEBUG_RATE(priv, "we are staying in the same table\n");
-	lq_sta->stay_in_tbl = 1;	/* only place this gets set */
-	if (is_legacy) {
-		lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
-		lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
-		lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
-	} else {
-		lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
-		lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
-		lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
-	}
-	lq_sta->table_count = 0;
-	lq_sta->total_failed = 0;
-	lq_sta->total_success = 0;
-	lq_sta->flush_timer = jiffies;
-	lq_sta->action_counter = 0;
-}
-
-/*
- * Find correct throughput table for given mode of modulation
- */
-static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
-				      struct iwl_scale_tbl_info *tbl)
-{
-	/* Used to choose among HT tables */
-	s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
-
-	/* Check for invalid LQ type */
-	if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) {
-		tbl->expected_tpt = expected_tpt_legacy;
-		return;
-	}
-
-	/* Legacy rates have only one table */
-	if (is_legacy(tbl->lq_type)) {
-		tbl->expected_tpt = expected_tpt_legacy;
-		return;
-	}
-
-	/* Choose among many HT tables depending on number of streams
-	 * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation
-	 * status */
-	if (is_siso(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
-		ht_tbl_pointer = expected_tpt_siso20MHz;
-	else if (is_siso(tbl->lq_type))
-		ht_tbl_pointer = expected_tpt_siso40MHz;
-	else if (is_mimo2(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
-		ht_tbl_pointer = expected_tpt_mimo2_20MHz;
-	else if (is_mimo2(tbl->lq_type))
-		ht_tbl_pointer = expected_tpt_mimo2_40MHz;
-	else if (is_mimo3(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
-		ht_tbl_pointer = expected_tpt_mimo3_20MHz;
-	else /* if (is_mimo3(tbl->lq_type)) <-- must be true */
-		ht_tbl_pointer = expected_tpt_mimo3_40MHz;
-
-	if (!tbl->is_SGI && !lq_sta->is_agg)		/* Normal */
-		tbl->expected_tpt = ht_tbl_pointer[0];
-	else if (tbl->is_SGI && !lq_sta->is_agg)	/* SGI */
-		tbl->expected_tpt = ht_tbl_pointer[1];
-	else if (!tbl->is_SGI && lq_sta->is_agg)	/* AGG */
-		tbl->expected_tpt = ht_tbl_pointer[2];
-	else						/* AGG+SGI */
-		tbl->expected_tpt = ht_tbl_pointer[3];
-}
-
-/*
- * Find starting rate for new "search" high-throughput mode of modulation.
- * Goal is to find lowest expected rate (under perfect conditions) that is
- * above the current measured throughput of "active" mode, to give new mode
- * a fair chance to prove itself without too many challenges.
- *
- * This gets called when transitioning to more aggressive modulation
- * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive
- * (i.e. MIMO to SISO).  When moving to MIMO, bit rate will typically need
- * to decrease to match "active" throughput.  When moving from MIMO to SISO,
- * bit rate will typically need to increase, but not if performance was bad.
- */
-static s32 rs_get_best_rate(struct iwl_priv *priv,
-			    struct iwl_lq_sta *lq_sta,
-			    struct iwl_scale_tbl_info *tbl,	/* "search" */
-			    u16 rate_mask, s8 index)
-{
-	/* "active" values */
-	struct iwl_scale_tbl_info *active_tbl =
-	    &(lq_sta->lq_info[lq_sta->active_tbl]);
-	s32 active_sr = active_tbl->win[index].success_ratio;
-	s32 active_tpt = active_tbl->expected_tpt[index];
-
-	/* expected "search" throughput */
-	s32 *tpt_tbl = tbl->expected_tpt;
-
-	s32 new_rate, high, low, start_hi;
-	u16 high_low;
-	s8 rate = index;
-
-	new_rate = high = low = start_hi = IWL_RATE_INVALID;
-
-	for (; ;) {
-		high_low = rs_get_adjacent_rate(priv, rate, rate_mask,
-						tbl->lq_type);
-
-		low = high_low & 0xff;
-		high = (high_low >> 8) & 0xff;
-
-		/*
-		 * Lower the "search" bit rate, to give new "search" mode
-		 * approximately the same throughput as "active" if:
-		 *
-		 * 1) "Active" mode has been working modestly well (but not
-		 *    great), and expected "search" throughput (under perfect
-		 *    conditions) at candidate rate is above the actual
-		 *    measured "active" throughput (but less than expected
-		 *    "active" throughput under perfect conditions).
-		 * OR
-		 * 2) "Active" mode has been working perfectly or very well
-		 *    and expected "search" throughput (under perfect
-		 *    conditions) at candidate rate is above expected
-		 *    "active" throughput (under perfect conditions).
-		 */
-		if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) &&
-		     ((active_sr > IWL_RATE_DECREASE_TH) &&
-		      (active_sr <= IWL_RATE_HIGH_TH) &&
-		      (tpt_tbl[rate] <= active_tpt))) ||
-		    ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
-		     (tpt_tbl[rate] > active_tpt))) {
-
-			/* (2nd or later pass)
-			 * If we've already tried to raise the rate, and are
-			 * now trying to lower it, use the higher rate. */
-			if (start_hi != IWL_RATE_INVALID) {
-				new_rate = start_hi;
-				break;
-			}
-
-			new_rate = rate;
-
-			/* Loop again with lower rate */
-			if (low != IWL_RATE_INVALID)
-				rate = low;
-
-			/* Lower rate not available, use the original */
-			else
-				break;
-
-		/* Else try to raise the "search" rate to match "active" */
-		} else {
-			/* (2nd or later pass)
-			 * If we've already tried to lower the rate, and are
-			 * now trying to raise it, use the lower rate. */
-			if (new_rate != IWL_RATE_INVALID)
-				break;
-
-			/* Loop again with higher rate */
-			else if (high != IWL_RATE_INVALID) {
-				start_hi = high;
-				rate = high;
-
-			/* Higher rate not available, use the original */
-			} else {
-				new_rate = rate;
-				break;
-			}
-		}
-	}
-
-	return new_rate;
-}
-
-/*
- * Set up search table for MIMO2
- */
-static int rs_switch_to_mimo2(struct iwl_priv *priv,
-			     struct iwl_lq_sta *lq_sta,
-			     struct ieee80211_conf *conf,
-			     struct ieee80211_sta *sta,
-			     struct iwl_scale_tbl_info *tbl, int index)
-{
-	u16 rate_mask;
-	s32 rate;
-	s8 is_green = lq_sta->is_green;
-	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-	struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
-		return -1;
-
-	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
-						== WLAN_HT_CAP_SM_PS_STATIC)
-		return -1;
-
-	/* Need both Tx chains/antennas to support MIMO */
-	if (priv->hw_params.tx_chains_num < 2)
-		return -1;
-
-	IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO2\n");
-
-	tbl->lq_type = LQ_MIMO2;
-	tbl->is_dup = lq_sta->is_dup;
-	tbl->action = 0;
-	tbl->max_search = IWL_MAX_SEARCH;
-	rate_mask = lq_sta->active_mimo2_rate;
-
-	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
-		tbl->is_ht40 = 1;
-	else
-		tbl->is_ht40 = 0;
-
-	rs_set_expected_tpt_table(lq_sta, tbl);
-
-	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
-
-	IWL_DEBUG_RATE(priv, "LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask);
-	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
-		IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
-						rate, rate_mask);
-		return -1;
-	}
-	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
-
-	IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
-		     tbl->current_rate, is_green);
-	return 0;
-}
-
-/*
- * Set up search table for MIMO3
- */
-static int rs_switch_to_mimo3(struct iwl_priv *priv,
-			     struct iwl_lq_sta *lq_sta,
-			     struct ieee80211_conf *conf,
-			     struct ieee80211_sta *sta,
-			     struct iwl_scale_tbl_info *tbl, int index)
-{
-	u16 rate_mask;
-	s32 rate;
-	s8 is_green = lq_sta->is_green;
-	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-	struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
-		return -1;
-
-	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
-						== WLAN_HT_CAP_SM_PS_STATIC)
-		return -1;
-
-	/* Need both Tx chains/antennas to support MIMO */
-	if (priv->hw_params.tx_chains_num < 3)
-		return -1;
-
-	IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n");
-
-	tbl->lq_type = LQ_MIMO3;
-	tbl->is_dup = lq_sta->is_dup;
-	tbl->action = 0;
-	tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
-	rate_mask = lq_sta->active_mimo3_rate;
-
-	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
-		tbl->is_ht40 = 1;
-	else
-		tbl->is_ht40 = 0;
-
-	rs_set_expected_tpt_table(lq_sta, tbl);
-
-	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
-
-	IWL_DEBUG_RATE(priv, "LQ: MIMO3 best rate %d mask %X\n",
-		rate, rate_mask);
-	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
-		IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
-						rate, rate_mask);
-		return -1;
-	}
-	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
-
-	IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
-		     tbl->current_rate, is_green);
-	return 0;
-}
-
-/*
- * Set up search table for SISO
- */
-static int rs_switch_to_siso(struct iwl_priv *priv,
-			     struct iwl_lq_sta *lq_sta,
-			     struct ieee80211_conf *conf,
-			     struct ieee80211_sta *sta,
-			     struct iwl_scale_tbl_info *tbl, int index)
-{
-	u16 rate_mask;
-	u8 is_green = lq_sta->is_green;
-	s32 rate;
-	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-	struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
-		return -1;
-
-	IWL_DEBUG_RATE(priv, "LQ: try to switch to SISO\n");
-
-	tbl->is_dup = lq_sta->is_dup;
-	tbl->lq_type = LQ_SISO;
-	tbl->action = 0;
-	tbl->max_search = IWL_MAX_SEARCH;
-	rate_mask = lq_sta->active_siso_rate;
-
-	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
-		tbl->is_ht40 = 1;
-	else
-		tbl->is_ht40 = 0;
-
-	if (is_green)
-		tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/
-
-	rs_set_expected_tpt_table(lq_sta, tbl);
-	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
-
-	IWL_DEBUG_RATE(priv, "LQ: get best rate %d mask %X\n", rate, rate_mask);
-	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
-		IWL_DEBUG_RATE(priv, "can not switch with index %d rate mask %x\n",
-			     rate, rate_mask);
-		return -1;
-	}
-	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
-	IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
-		     tbl->current_rate, is_green);
-	return 0;
-}
-
-/*
- * Try to switch to new modulation mode from legacy
- */
-static int rs_move_legacy_other(struct iwl_priv *priv,
-				struct iwl_lq_sta *lq_sta,
-				struct ieee80211_conf *conf,
-				struct ieee80211_sta *sta,
-				int index)
-{
-	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-	struct iwl_scale_tbl_info *search_tbl =
-				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
-	struct iwl_rate_scale_data *window = &(tbl->win[index]);
-	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-	u8 start_action;
-	u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
-	u8 tx_chains_num = priv->hw_params.tx_chains_num;
-	int ret = 0;
-	u8 update_search_tbl_counter = 0;
-
-	switch (priv->bt_traffic_load) {
-	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-		/* nothing */
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-		/* avoid antenna B unless MIMO */
-		if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2)
-			tbl->action = IWL_LEGACY_SWITCH_SISO;
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-		/* avoid antenna B and MIMO */
-		valid_tx_ant =
-			first_antenna(priv->hw_params.valid_tx_ant);
-		if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 &&
-		    tbl->action != IWL_LEGACY_SWITCH_SISO)
-			tbl->action = IWL_LEGACY_SWITCH_SISO;
-		break;
-	default:
-		IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
-		break;
-	}
-
-	if (!iwl_ht_enabled(priv))
-		/* stay in Legacy */
-		tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
-	else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
-		   tbl->action > IWL_LEGACY_SWITCH_SISO)
-		tbl->action = IWL_LEGACY_SWITCH_SISO;
-
-	/* configure as 1x1 if bt full concurrency */
-	if (priv->bt_full_concurrent) {
-		if (!iwl_ht_enabled(priv))
-			tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
-		else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
-			tbl->action = IWL_LEGACY_SWITCH_SISO;
-		valid_tx_ant =
-			first_antenna(priv->hw_params.valid_tx_ant);
-	}
-
-	start_action = tbl->action;
-	for (; ;) {
-		lq_sta->action_counter++;
-		switch (tbl->action) {
-		case IWL_LEGACY_SWITCH_ANTENNA1:
-		case IWL_LEGACY_SWITCH_ANTENNA2:
-			IWL_DEBUG_RATE(priv, "LQ: Legacy toggle Antenna\n");
-
-			if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 &&
-							tx_chains_num <= 1) ||
-			    (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 &&
-							tx_chains_num <= 2))
-				break;
-
-			/* Don't change antenna if success has been great */
-			if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
-			    !priv->bt_full_concurrent &&
-			    priv->bt_traffic_load ==
-					IWL_BT_COEX_TRAFFIC_LOAD_NONE)
-				break;
-
-			/* Set up search table to try other antenna */
-			memcpy(search_tbl, tbl, sz);
-
-			if (rs_toggle_antenna(valid_tx_ant,
-				&search_tbl->current_rate, search_tbl)) {
-				update_search_tbl_counter = 1;
-				rs_set_expected_tpt_table(lq_sta, search_tbl);
-				goto out;
-			}
-			break;
-		case IWL_LEGACY_SWITCH_SISO:
-			IWL_DEBUG_RATE(priv, "LQ: Legacy switch to SISO\n");
-
-			/* Set up search table to try SISO */
-			memcpy(search_tbl, tbl, sz);
-			search_tbl->is_SGI = 0;
-			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
-						 search_tbl, index);
-			if (!ret) {
-				lq_sta->action_counter = 0;
-				goto out;
-			}
-
-			break;
-		case IWL_LEGACY_SWITCH_MIMO2_AB:
-		case IWL_LEGACY_SWITCH_MIMO2_AC:
-		case IWL_LEGACY_SWITCH_MIMO2_BC:
-			IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO2\n");
-
-			/* Set up search table to try MIMO */
-			memcpy(search_tbl, tbl, sz);
-			search_tbl->is_SGI = 0;
-
-			if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB)
-				search_tbl->ant_type = ANT_AB;
-			else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC)
-				search_tbl->ant_type = ANT_AC;
-			else
-				search_tbl->ant_type = ANT_BC;
-
-			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-				break;
-
-			ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
-						 search_tbl, index);
-			if (!ret) {
-				lq_sta->action_counter = 0;
-				goto out;
-			}
-			break;
-
-		case IWL_LEGACY_SWITCH_MIMO3_ABC:
-			IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO3\n");
-
-			/* Set up search table to try MIMO3 */
-			memcpy(search_tbl, tbl, sz);
-			search_tbl->is_SGI = 0;
-
-			search_tbl->ant_type = ANT_ABC;
-
-			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-				break;
-
-			ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
-						 search_tbl, index);
-			if (!ret) {
-				lq_sta->action_counter = 0;
-				goto out;
-			}
-			break;
-		}
-		tbl->action++;
-		if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
-			tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
-
-		if (tbl->action == start_action)
-			break;
-
-	}
-	search_tbl->lq_type = LQ_NONE;
-	return 0;
-
-out:
-	lq_sta->search_better_tbl = 1;
-	tbl->action++;
-	if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
-		tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
-	if (update_search_tbl_counter)
-		search_tbl->action = tbl->action;
-	return 0;
-
-}
-
-/*
- * Try to switch to new modulation mode from SISO
- */
-static int rs_move_siso_to_other(struct iwl_priv *priv,
-				 struct iwl_lq_sta *lq_sta,
-				 struct ieee80211_conf *conf,
-				 struct ieee80211_sta *sta, int index)
-{
-	u8 is_green = lq_sta->is_green;
-	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-	struct iwl_scale_tbl_info *search_tbl =
-				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
-	struct iwl_rate_scale_data *window = &(tbl->win[index]);
-	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-	u8 start_action;
-	u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
-	u8 tx_chains_num = priv->hw_params.tx_chains_num;
-	u8 update_search_tbl_counter = 0;
-	int ret;
-
-	switch (priv->bt_traffic_load) {
-	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-		/* nothing */
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-		/* avoid antenna B unless MIMO */
-		if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
-			tbl->action = IWL_SISO_SWITCH_MIMO2_AB;
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-		/* avoid antenna B and MIMO */
-		valid_tx_ant =
-			first_antenna(priv->hw_params.valid_tx_ant);
-		if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
-			tbl->action = IWL_SISO_SWITCH_ANTENNA1;
-		break;
-	default:
-		IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
-		break;
-	}
-
-	if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
-	    tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
-		/* stay in SISO */
-		tbl->action = IWL_SISO_SWITCH_ANTENNA1;
-	}
-
-	/* configure as 1x1 if bt full concurrency */
-	if (priv->bt_full_concurrent) {
-		valid_tx_ant =
-			first_antenna(priv->hw_params.valid_tx_ant);
-		if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
-			tbl->action = IWL_SISO_SWITCH_ANTENNA1;
-	}
-
-	start_action = tbl->action;
-	for (;;) {
-		lq_sta->action_counter++;
-		switch (tbl->action) {
-		case IWL_SISO_SWITCH_ANTENNA1:
-		case IWL_SISO_SWITCH_ANTENNA2:
-			IWL_DEBUG_RATE(priv, "LQ: SISO toggle Antenna\n");
-			if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 &&
-						tx_chains_num <= 1) ||
-			    (tbl->action == IWL_SISO_SWITCH_ANTENNA2 &&
-						tx_chains_num <= 2))
-				break;
-
-			if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
-			    !priv->bt_full_concurrent &&
-			    priv->bt_traffic_load ==
-					IWL_BT_COEX_TRAFFIC_LOAD_NONE)
-				break;
-
-			memcpy(search_tbl, tbl, sz);
-			if (rs_toggle_antenna(valid_tx_ant,
-				       &search_tbl->current_rate, search_tbl)) {
-				update_search_tbl_counter = 1;
-				goto out;
-			}
-			break;
-		case IWL_SISO_SWITCH_MIMO2_AB:
-		case IWL_SISO_SWITCH_MIMO2_AC:
-		case IWL_SISO_SWITCH_MIMO2_BC:
-			IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO2\n");
-			memcpy(search_tbl, tbl, sz);
-			search_tbl->is_SGI = 0;
-
-			if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB)
-				search_tbl->ant_type = ANT_AB;
-			else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC)
-				search_tbl->ant_type = ANT_AC;
-			else
-				search_tbl->ant_type = ANT_BC;
-
-			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-				break;
-
-			ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
-						 search_tbl, index);
-			if (!ret)
-				goto out;
-			break;
-		case IWL_SISO_SWITCH_GI:
-			if (!tbl->is_ht40 && !(ht_cap->cap &
-						IEEE80211_HT_CAP_SGI_20))
-				break;
-			if (tbl->is_ht40 && !(ht_cap->cap &
-						IEEE80211_HT_CAP_SGI_40))
-				break;
-
-			IWL_DEBUG_RATE(priv, "LQ: SISO toggle SGI/NGI\n");
-
-			memcpy(search_tbl, tbl, sz);
-			if (is_green) {
-				if (!tbl->is_SGI)
-					break;
-				else
-					IWL_ERR(priv,
-						"SGI was set in GF+SISO\n");
-			}
-			search_tbl->is_SGI = !tbl->is_SGI;
-			rs_set_expected_tpt_table(lq_sta, search_tbl);
-			if (tbl->is_SGI) {
-				s32 tpt = lq_sta->last_tpt / 100;
-				if (tpt >= search_tbl->expected_tpt[index])
-					break;
-			}
-			search_tbl->current_rate =
-				rate_n_flags_from_tbl(priv, search_tbl,
-						      index, is_green);
-			update_search_tbl_counter = 1;
-			goto out;
-		case IWL_SISO_SWITCH_MIMO3_ABC:
-			IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO3\n");
-			memcpy(search_tbl, tbl, sz);
-			search_tbl->is_SGI = 0;
-			search_tbl->ant_type = ANT_ABC;
-
-			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-				break;
-
-			ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
-						 search_tbl, index);
-			if (!ret)
-				goto out;
-			break;
-		}
-		tbl->action++;
-		if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
-			tbl->action = IWL_SISO_SWITCH_ANTENNA1;
-
-		if (tbl->action == start_action)
-			break;
-	}
-	search_tbl->lq_type = LQ_NONE;
-	return 0;
-
- out:
-	lq_sta->search_better_tbl = 1;
-	tbl->action++;
-	if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC)
-		tbl->action = IWL_SISO_SWITCH_ANTENNA1;
-	if (update_search_tbl_counter)
-		search_tbl->action = tbl->action;
-
-	return 0;
-}
-
-/*
- * Try to switch to new modulation mode from MIMO2
- */
-static int rs_move_mimo2_to_other(struct iwl_priv *priv,
-				 struct iwl_lq_sta *lq_sta,
-				 struct ieee80211_conf *conf,
-				 struct ieee80211_sta *sta, int index)
-{
-	s8 is_green = lq_sta->is_green;
-	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-	struct iwl_scale_tbl_info *search_tbl =
-				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
-	struct iwl_rate_scale_data *window = &(tbl->win[index]);
-	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-	u8 start_action;
-	u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
-	u8 tx_chains_num = priv->hw_params.tx_chains_num;
-	u8 update_search_tbl_counter = 0;
-	int ret;
-
-	switch (priv->bt_traffic_load) {
-	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-		/* nothing */
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-		/* avoid antenna B and MIMO */
-		if (tbl->action != IWL_MIMO2_SWITCH_SISO_A)
-			tbl->action = IWL_MIMO2_SWITCH_SISO_A;
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-		/* avoid antenna B unless MIMO */
-		if (tbl->action == IWL_MIMO2_SWITCH_SISO_B ||
-		    tbl->action == IWL_MIMO2_SWITCH_SISO_C)
-			tbl->action = IWL_MIMO2_SWITCH_SISO_A;
-		break;
-	default:
-		IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
-		break;
-	}
-
-	if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
-	    (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
-	     tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
-		/* switch in SISO */
-		tbl->action = IWL_MIMO2_SWITCH_SISO_A;
-	}
-
-	/* configure as 1x1 if bt full concurrency */
-	if (priv->bt_full_concurrent &&
-	    (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
-	     tbl->action > IWL_MIMO2_SWITCH_SISO_C))
-		tbl->action = IWL_MIMO2_SWITCH_SISO_A;
-
-	start_action = tbl->action;
-	for (;;) {
-		lq_sta->action_counter++;
-		switch (tbl->action) {
-		case IWL_MIMO2_SWITCH_ANTENNA1:
-		case IWL_MIMO2_SWITCH_ANTENNA2:
-			IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle Antennas\n");
-
-			if (tx_chains_num <= 2)
-				break;
-
-			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
-				break;
-
-			memcpy(search_tbl, tbl, sz);
-			if (rs_toggle_antenna(valid_tx_ant,
-				       &search_tbl->current_rate, search_tbl)) {
-				update_search_tbl_counter = 1;
-				goto out;
-			}
-			break;
-		case IWL_MIMO2_SWITCH_SISO_A:
-		case IWL_MIMO2_SWITCH_SISO_B:
-		case IWL_MIMO2_SWITCH_SISO_C:
-			IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to SISO\n");
-
-			/* Set up new search table for SISO */
-			memcpy(search_tbl, tbl, sz);
-
-			if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
-				search_tbl->ant_type = ANT_A;
-			else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B)
-				search_tbl->ant_type = ANT_B;
-			else
-				search_tbl->ant_type = ANT_C;
-
-			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-				break;
-
-			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
-						 search_tbl, index);
-			if (!ret)
-				goto out;
-
-			break;
-
-		case IWL_MIMO2_SWITCH_GI:
-			if (!tbl->is_ht40 && !(ht_cap->cap &
-						IEEE80211_HT_CAP_SGI_20))
-				break;
-			if (tbl->is_ht40 && !(ht_cap->cap &
-						IEEE80211_HT_CAP_SGI_40))
-				break;
-
-			IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n");
-
-			/* Set up new search table for MIMO2 */
-			memcpy(search_tbl, tbl, sz);
-			search_tbl->is_SGI = !tbl->is_SGI;
-			rs_set_expected_tpt_table(lq_sta, search_tbl);
-			/*
-			 * If active table already uses the fastest possible
-			 * modulation (dual stream with short guard interval),
-			 * and it's working well, there's no need to look
-			 * for a better type of modulation!
-			 */
-			if (tbl->is_SGI) {
-				s32 tpt = lq_sta->last_tpt / 100;
-				if (tpt >= search_tbl->expected_tpt[index])
-					break;
-			}
-			search_tbl->current_rate =
-				rate_n_flags_from_tbl(priv, search_tbl,
-						      index, is_green);
-			update_search_tbl_counter = 1;
-			goto out;
-
-		case IWL_MIMO2_SWITCH_MIMO3_ABC:
-			IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to MIMO3\n");
-			memcpy(search_tbl, tbl, sz);
-			search_tbl->is_SGI = 0;
-			search_tbl->ant_type = ANT_ABC;
-
-			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-				break;
-
-			ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
-						 search_tbl, index);
-			if (!ret)
-				goto out;
-
-			break;
-		}
-		tbl->action++;
-		if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
-			tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
-
-		if (tbl->action == start_action)
-			break;
-	}
-	search_tbl->lq_type = LQ_NONE;
-	return 0;
- out:
-	lq_sta->search_better_tbl = 1;
-	tbl->action++;
-	if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
-		tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
-	if (update_search_tbl_counter)
-		search_tbl->action = tbl->action;
-
-	return 0;
-
-}
-
-/*
- * Try to switch to new modulation mode from MIMO3
- */
-static int rs_move_mimo3_to_other(struct iwl_priv *priv,
-				 struct iwl_lq_sta *lq_sta,
-				 struct ieee80211_conf *conf,
-				 struct ieee80211_sta *sta, int index)
-{
-	s8 is_green = lq_sta->is_green;
-	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-	struct iwl_scale_tbl_info *search_tbl =
-				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
-	struct iwl_rate_scale_data *window = &(tbl->win[index]);
-	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-	u8 start_action;
-	u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
-	u8 tx_chains_num = priv->hw_params.tx_chains_num;
-	int ret;
-	u8 update_search_tbl_counter = 0;
-
-	switch (priv->bt_traffic_load) {
-	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-		/* nothing */
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-		/* avoid antenna B and MIMO */
-		if (tbl->action != IWL_MIMO3_SWITCH_SISO_A)
-			tbl->action = IWL_MIMO3_SWITCH_SISO_A;
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-		/* avoid antenna B unless MIMO */
-		if (tbl->action == IWL_MIMO3_SWITCH_SISO_B ||
-		    tbl->action == IWL_MIMO3_SWITCH_SISO_C)
-			tbl->action = IWL_MIMO3_SWITCH_SISO_A;
-		break;
-	default:
-		IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
-		break;
-	}
-
-	if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
-	    (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
-	     tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
-		/* switch in SISO */
-		tbl->action = IWL_MIMO3_SWITCH_SISO_A;
-	}
-
-	/* configure as 1x1 if bt full concurrency */
-	if (priv->bt_full_concurrent &&
-	    (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
-	     tbl->action > IWL_MIMO3_SWITCH_SISO_C))
-		tbl->action = IWL_MIMO3_SWITCH_SISO_A;
-
-	start_action = tbl->action;
-	for (;;) {
-		lq_sta->action_counter++;
-		switch (tbl->action) {
-		case IWL_MIMO3_SWITCH_ANTENNA1:
-		case IWL_MIMO3_SWITCH_ANTENNA2:
-			IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle Antennas\n");
-
-			if (tx_chains_num <= 3)
-				break;
-
-			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
-				break;
-
-			memcpy(search_tbl, tbl, sz);
-			if (rs_toggle_antenna(valid_tx_ant,
-				       &search_tbl->current_rate, search_tbl))
-				goto out;
-			break;
-		case IWL_MIMO3_SWITCH_SISO_A:
-		case IWL_MIMO3_SWITCH_SISO_B:
-		case IWL_MIMO3_SWITCH_SISO_C:
-			IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to SISO\n");
-
-			/* Set up new search table for SISO */
-			memcpy(search_tbl, tbl, sz);
-
-			if (tbl->action == IWL_MIMO3_SWITCH_SISO_A)
-				search_tbl->ant_type = ANT_A;
-			else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B)
-				search_tbl->ant_type = ANT_B;
-			else
-				search_tbl->ant_type = ANT_C;
-
-			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-				break;
-
-			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
-						 search_tbl, index);
-			if (!ret)
-				goto out;
-
-			break;
-
-		case IWL_MIMO3_SWITCH_MIMO2_AB:
-		case IWL_MIMO3_SWITCH_MIMO2_AC:
-		case IWL_MIMO3_SWITCH_MIMO2_BC:
-			IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to MIMO2\n");
-
-			memcpy(search_tbl, tbl, sz);
-			search_tbl->is_SGI = 0;
-			if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB)
-				search_tbl->ant_type = ANT_AB;
-			else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC)
-				search_tbl->ant_type = ANT_AC;
-			else
-				search_tbl->ant_type = ANT_BC;
-
-			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-				break;
-
-			ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
-						 search_tbl, index);
-			if (!ret)
-				goto out;
-
-			break;
-
-		case IWL_MIMO3_SWITCH_GI:
-			if (!tbl->is_ht40 && !(ht_cap->cap &
-						IEEE80211_HT_CAP_SGI_20))
-				break;
-			if (tbl->is_ht40 && !(ht_cap->cap &
-						IEEE80211_HT_CAP_SGI_40))
-				break;
-
-			IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n");
-
-			/* Set up new search table for MIMO */
-			memcpy(search_tbl, tbl, sz);
-			search_tbl->is_SGI = !tbl->is_SGI;
-			rs_set_expected_tpt_table(lq_sta, search_tbl);
-			/*
-			 * If active table already uses the fastest possible
-			 * modulation (dual stream with short guard interval),
-			 * and it's working well, there's no need to look
-			 * for a better type of modulation!
-			 */
-			if (tbl->is_SGI) {
-				s32 tpt = lq_sta->last_tpt / 100;
-				if (tpt >= search_tbl->expected_tpt[index])
-					break;
-			}
-			search_tbl->current_rate =
-				rate_n_flags_from_tbl(priv, search_tbl,
-						      index, is_green);
-			update_search_tbl_counter = 1;
-			goto out;
-		}
-		tbl->action++;
-		if (tbl->action > IWL_MIMO3_SWITCH_GI)
-			tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
-
-		if (tbl->action == start_action)
-			break;
-	}
-	search_tbl->lq_type = LQ_NONE;
-	return 0;
- out:
-	lq_sta->search_better_tbl = 1;
-	tbl->action++;
-	if (tbl->action > IWL_MIMO3_SWITCH_GI)
-		tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
-	if (update_search_tbl_counter)
-		search_tbl->action = tbl->action;
-
-	return 0;
-
-}
-
-/*
- * Check whether we should continue using same modulation mode, or
- * begin search for a new mode, based on:
- * 1) # tx successes or failures while using this mode
- * 2) # times calling this function
- * 3) elapsed time in this mode (not used, for now)
- */
-static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
-{
-	struct iwl_scale_tbl_info *tbl;
-	int i;
-	int active_tbl;
-	int flush_interval_passed = 0;
-	struct iwl_priv *priv;
-
-	priv = lq_sta->drv;
-	active_tbl = lq_sta->active_tbl;
-
-	tbl = &(lq_sta->lq_info[active_tbl]);
-
-	/* If we've been disallowing search, see if we should now allow it */
-	if (lq_sta->stay_in_tbl) {
-
-		/* Elapsed time using current modulation mode */
-		if (lq_sta->flush_timer)
-			flush_interval_passed =
-			time_after(jiffies,
-					(unsigned long)(lq_sta->flush_timer +
-					IWL_RATE_SCALE_FLUSH_INTVL));
-
-		/*
-		 * Check if we should allow search for new modulation mode.
-		 * If many frames have failed or succeeded, or we've used
-		 * this same modulation for a long time, allow search, and
-		 * reset history stats that keep track of whether we should
-		 * allow a new search.  Also (below) reset all bitmaps and
-		 * stats in active history.
-		 */
-		if (force_search ||
-		    (lq_sta->total_failed > lq_sta->max_failure_limit) ||
-		    (lq_sta->total_success > lq_sta->max_success_limit) ||
-		    ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
-		     && (flush_interval_passed))) {
-			IWL_DEBUG_RATE(priv, "LQ: stay is expired %d %d %d\n",
-				     lq_sta->total_failed,
-				     lq_sta->total_success,
-				     flush_interval_passed);
-
-			/* Allow search for new mode */
-			lq_sta->stay_in_tbl = 0;	/* only place reset */
-			lq_sta->total_failed = 0;
-			lq_sta->total_success = 0;
-			lq_sta->flush_timer = 0;
-
-		/*
-		 * Else if we've used this modulation mode enough repetitions
-		 * (regardless of elapsed time or success/failure), reset
-		 * history bitmaps and rate-specific stats for all rates in
-		 * active table.
-		 */
-		} else {
-			lq_sta->table_count++;
-			if (lq_sta->table_count >=
-			    lq_sta->table_count_limit) {
-				lq_sta->table_count = 0;
-
-				IWL_DEBUG_RATE(priv, "LQ: stay in table clear win\n");
-				for (i = 0; i < IWL_RATE_COUNT; i++)
-					rs_rate_scale_clear_window(
-						&(tbl->win[i]));
-			}
-		}
-
-		/* If transitioning to allow "search", reset all history
-		 * bitmaps and stats in active table (this will become the new
-		 * "search" table). */
-		if (!lq_sta->stay_in_tbl) {
-			for (i = 0; i < IWL_RATE_COUNT; i++)
-				rs_rate_scale_clear_window(&(tbl->win[i]));
-		}
-	}
-}
-
-/*
- * setup rate table in uCode
- */
-static void rs_update_rate_tbl(struct iwl_priv *priv,
-			       struct iwl_rxon_context *ctx,
-			       struct iwl_lq_sta *lq_sta,
-			       struct iwl_scale_tbl_info *tbl,
-			       int index, u8 is_green)
-{
-	u32 rate;
-
-	/* Update uCode's rate table. */
-	rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
-	rs_fill_link_cmd(priv, lq_sta, rate);
-	iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
-}
-
-/*
- * Do rate scaling and search for new modulation mode.
- */
-static void rs_rate_scale_perform(struct iwl_priv *priv,
-				  struct sk_buff *skb,
-				  struct ieee80211_sta *sta,
-				  struct iwl_lq_sta *lq_sta)
-{
-	struct ieee80211_hw *hw = priv->hw;
-	struct ieee80211_conf *conf = &hw->conf;
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	int low = IWL_RATE_INVALID;
-	int high = IWL_RATE_INVALID;
-	int index;
-	int i;
-	struct iwl_rate_scale_data *window = NULL;
-	int current_tpt = IWL_INVALID_VALUE;
-	int low_tpt = IWL_INVALID_VALUE;
-	int high_tpt = IWL_INVALID_VALUE;
-	u32 fail_count;
-	s8 scale_action = 0;
-	u16 rate_mask;
-	u8 update_lq = 0;
-	struct iwl_scale_tbl_info *tbl, *tbl1;
-	u16 rate_scale_index_msk = 0;
-	u8 is_green = 0;
-	u8 active_tbl = 0;
-	u8 done_search = 0;
-	u16 high_low;
-	s32 sr;
-	u8 tid = IWL_MAX_TID_COUNT;
-	struct iwl_tid_data *tid_data;
-	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-	struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-	IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n");
-
-	/* Send management frames and NO_ACK data using lowest rate. */
-	/* TODO: this could probably be improved.. */
-	if (!ieee80211_is_data(hdr->frame_control) ||
-	    info->flags & IEEE80211_TX_CTL_NO_ACK)
-		return;
-
-	lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
-
-	tid = rs_tl_add_packet(lq_sta, hdr);
-	if ((tid != IWL_MAX_TID_COUNT) &&
-	    (lq_sta->tx_agg_tid_en & (1 << tid))) {
-		tid_data = &priv->tid_data[lq_sta->lq.sta_id][tid];
-		if (tid_data->agg.state == IWL_AGG_OFF)
-			lq_sta->is_agg = 0;
-		else
-			lq_sta->is_agg = 1;
-	} else
-		lq_sta->is_agg = 0;
-
-	/*
-	 * Select rate-scale / modulation-mode table to work with in
-	 * the rest of this function:  "search" if searching for better
-	 * modulation mode, or "active" if doing rate scaling within a mode.
-	 */
-	if (!lq_sta->search_better_tbl)
-		active_tbl = lq_sta->active_tbl;
-	else
-		active_tbl = 1 - lq_sta->active_tbl;
-
-	tbl = &(lq_sta->lq_info[active_tbl]);
-	if (is_legacy(tbl->lq_type))
-		lq_sta->is_green = 0;
-	else
-		lq_sta->is_green = rs_use_green(sta);
-	is_green = lq_sta->is_green;
-
-	/* current tx rate */
-	index = lq_sta->last_txrate_idx;
-
-	IWL_DEBUG_RATE(priv, "Rate scale index %d for type %d\n", index,
-		       tbl->lq_type);
-
-	/* rates available for this association, and for modulation mode */
-	rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
-
-	IWL_DEBUG_RATE(priv, "mask 0x%04X\n", rate_mask);
-
-	/* mask with station rate restriction */
-	if (is_legacy(tbl->lq_type)) {
-		if (lq_sta->band == IEEE80211_BAND_5GHZ)
-			/* supp_rates has no CCK bits in A mode */
-			rate_scale_index_msk = (u16) (rate_mask &
-				(lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
-		else
-			rate_scale_index_msk = (u16) (rate_mask &
-						      lq_sta->supp_rates);
-
-	} else
-		rate_scale_index_msk = rate_mask;
-
-	if (!rate_scale_index_msk)
-		rate_scale_index_msk = rate_mask;
-
-	if (!((1 << index) & rate_scale_index_msk)) {
-		IWL_ERR(priv, "Current Rate is not valid\n");
-		if (lq_sta->search_better_tbl) {
-			/* revert to active table if search table is not valid*/
-			tbl->lq_type = LQ_NONE;
-			lq_sta->search_better_tbl = 0;
-			tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-			/* get "active" rate info */
-			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-			rs_update_rate_tbl(priv, ctx, lq_sta, tbl,
-					   index, is_green);
-		}
-		return;
-	}
-
-	/* Get expected throughput table and history window for current rate */
-	if (!tbl->expected_tpt) {
-		IWL_ERR(priv, "tbl->expected_tpt is NULL\n");
-		return;
-	}
-
-	/* force user max rate if set by user */
-	if ((lq_sta->max_rate_idx != -1) &&
-	    (lq_sta->max_rate_idx < index)) {
-		index = lq_sta->max_rate_idx;
-		update_lq = 1;
-		window = &(tbl->win[index]);
-		goto lq_update;
-	}
-
-	window = &(tbl->win[index]);
-
-	/*
-	 * If there is not enough history to calculate actual average
-	 * throughput, keep analyzing results of more tx frames, without
-	 * changing rate or mode (bypass most of the rest of this function).
-	 * Set up new rate table in uCode only if old rate is not supported
-	 * in current association (use new rate found above).
-	 */
-	fail_count = window->counter - window->success_counter;
-	if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
-			(window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
-		IWL_DEBUG_RATE(priv, "LQ: still below TH. succ=%d total=%d "
-			       "for index %d\n",
-			       window->success_counter, window->counter, index);
-
-		/* Can't calculate this yet; not enough history */
-		window->average_tpt = IWL_INVALID_VALUE;
-
-		/* Should we stay with this modulation mode,
-		 * or search for a new one? */
-		rs_stay_in_table(lq_sta, false);
-
-		goto out;
-	}
-	/* Else we have enough samples; calculate estimate of
-	 * actual average throughput */
-	if (window->average_tpt != ((window->success_ratio *
-			tbl->expected_tpt[index] + 64) / 128)) {
-		IWL_ERR(priv, "expected_tpt should have been calculated by now\n");
-		window->average_tpt = ((window->success_ratio *
-					tbl->expected_tpt[index] + 64) / 128);
-	}
-
-	/* If we are searching for better modulation mode, check success. */
-	if (lq_sta->search_better_tbl &&
-	    (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI)) {
-		/* If good success, continue using the "search" mode;
-		 * no need to send new link quality command, since we're
-		 * continuing to use the setup that we've been trying. */
-		if (window->average_tpt > lq_sta->last_tpt) {
-
-			IWL_DEBUG_RATE(priv, "LQ: SWITCHING TO NEW TABLE "
-					"suc=%d cur-tpt=%d old-tpt=%d\n",
-					window->success_ratio,
-					window->average_tpt,
-					lq_sta->last_tpt);
-
-			if (!is_legacy(tbl->lq_type))
-				lq_sta->enable_counter = 1;
-
-			/* Swap tables; "search" becomes "active" */
-			lq_sta->active_tbl = active_tbl;
-			current_tpt = window->average_tpt;
-
-		/* Else poor success; go back to mode in "active" table */
-		} else {
-
-			IWL_DEBUG_RATE(priv, "LQ: GOING BACK TO THE OLD TABLE "
-					"suc=%d cur-tpt=%d old-tpt=%d\n",
-					window->success_ratio,
-					window->average_tpt,
-					lq_sta->last_tpt);
-
-			/* Nullify "search" table */
-			tbl->lq_type = LQ_NONE;
-
-			/* Revert to "active" table */
-			active_tbl = lq_sta->active_tbl;
-			tbl = &(lq_sta->lq_info[active_tbl]);
-
-			/* Revert to "active" rate and throughput info */
-			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-			current_tpt = lq_sta->last_tpt;
-
-			/* Need to set up a new rate table in uCode */
-			update_lq = 1;
-		}
-
-		/* Either way, we've made a decision; modulation mode
-		 * search is done, allow rate adjustment next time. */
-		lq_sta->search_better_tbl = 0;
-		done_search = 1;	/* Don't switch modes below! */
-		goto lq_update;
-	}
-
-	/* (Else) not in search of better modulation mode, try for better
-	 * starting rate, while staying in this mode. */
-	high_low = rs_get_adjacent_rate(priv, index, rate_scale_index_msk,
-					tbl->lq_type);
-	low = high_low & 0xff;
-	high = (high_low >> 8) & 0xff;
-
-	/* If user set max rate, dont allow higher than user constrain */
-	if ((lq_sta->max_rate_idx != -1) &&
-	    (lq_sta->max_rate_idx < high))
-		high = IWL_RATE_INVALID;
-
-	sr = window->success_ratio;
-
-	/* Collect measured throughputs for current and adjacent rates */
-	current_tpt = window->average_tpt;
-	if (low != IWL_RATE_INVALID)
-		low_tpt = tbl->win[low].average_tpt;
-	if (high != IWL_RATE_INVALID)
-		high_tpt = tbl->win[high].average_tpt;
-
-	scale_action = 0;
-
-	/* Too many failures, decrease rate */
-	if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
-		IWL_DEBUG_RATE(priv, "decrease rate because of low success_ratio\n");
-		scale_action = -1;
-
-	/* No throughput measured yet for adjacent rates; try increase. */
-	} else if ((low_tpt == IWL_INVALID_VALUE) &&
-		   (high_tpt == IWL_INVALID_VALUE)) {
-
-		if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
-			scale_action = 1;
-		else if (low != IWL_RATE_INVALID)
-			scale_action = 0;
-	}
-
-	/* Both adjacent throughputs are measured, but neither one has better
-	 * throughput; we're using the best rate, don't change it! */
-	else if ((low_tpt != IWL_INVALID_VALUE) &&
-		 (high_tpt != IWL_INVALID_VALUE) &&
-		 (low_tpt < current_tpt) &&
-		 (high_tpt < current_tpt))
-		scale_action = 0;
-
-	/* At least one adjacent rate's throughput is measured,
-	 * and may have better performance. */
-	else {
-		/* Higher adjacent rate's throughput is measured */
-		if (high_tpt != IWL_INVALID_VALUE) {
-			/* Higher rate has better throughput */
-			if (high_tpt > current_tpt &&
-					sr >= IWL_RATE_INCREASE_TH) {
-				scale_action = 1;
-			} else {
-				scale_action = 0;
-			}
-
-		/* Lower adjacent rate's throughput is measured */
-		} else if (low_tpt != IWL_INVALID_VALUE) {
-			/* Lower rate has better throughput */
-			if (low_tpt > current_tpt) {
-				IWL_DEBUG_RATE(priv,
-				    "decrease rate because of low tpt\n");
-				scale_action = -1;
-			} else if (sr >= IWL_RATE_INCREASE_TH) {
-				scale_action = 1;
-			}
-		}
-	}
-
-	/* Sanity check; asked for decrease, but success rate or throughput
-	 * has been good at old rate.  Don't change it. */
-	if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
-		    ((sr > IWL_RATE_HIGH_TH) ||
-		     (current_tpt > (100 * tbl->expected_tpt[low]))))
-		scale_action = 0;
-	if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type))
-		scale_action = -1;
-	if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI &&
-		(is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
-		scale_action = -1;
-
-	if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
-	     (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
-		if (lq_sta->last_bt_traffic > priv->bt_traffic_load) {
-			/*
-			 * don't set scale_action, don't want to scale up if
-			 * the rate scale doesn't otherwise think that is a
-			 * good idea.
-			 */
-		} else if (lq_sta->last_bt_traffic <= priv->bt_traffic_load) {
-			scale_action = -1;
-		}
-	}
-	lq_sta->last_bt_traffic = priv->bt_traffic_load;
-
-	if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
-	     (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
-		/* search for a new modulation */
-		rs_stay_in_table(lq_sta, true);
-		goto lq_update;
-	}
-
-	switch (scale_action) {
-	case -1:
-		/* Decrease starting rate, update uCode's rate table */
-		if (low != IWL_RATE_INVALID) {
-			update_lq = 1;
-			index = low;
-		}
-
-		break;
-	case 1:
-		/* Increase starting rate, update uCode's rate table */
-		if (high != IWL_RATE_INVALID) {
-			update_lq = 1;
-			index = high;
-		}
-
-		break;
-	case 0:
-		/* No change */
-	default:
-		break;
-	}
-
-	IWL_DEBUG_RATE(priv, "choose rate scale index %d action %d low %d "
-		    "high %d type %d\n",
-		     index, scale_action, low, high, tbl->lq_type);
-
-lq_update:
-	/* Replace uCode's rate table for the destination station. */
-	if (update_lq)
-		rs_update_rate_tbl(priv, ctx, lq_sta, tbl, index, is_green);
-
-	if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
-		/* Should we stay with this modulation mode,
-		 * or search for a new one? */
-	  rs_stay_in_table(lq_sta, false);
-	}
-	/*
-	 * Search for new modulation mode if we're:
-	 * 1)  Not changing rates right now
-	 * 2)  Not just finishing up a search
-	 * 3)  Allowing a new search
-	 */
-	if (!update_lq && !done_search && !lq_sta->stay_in_tbl && window->counter) {
-		/* Save current throughput to compare with "search" throughput*/
-		lq_sta->last_tpt = current_tpt;
-
-		/* Select a new "search" modulation mode to try.
-		 * If one is found, set up the new "search" table. */
-		if (is_legacy(tbl->lq_type))
-			rs_move_legacy_other(priv, lq_sta, conf, sta, index);
-		else if (is_siso(tbl->lq_type))
-			rs_move_siso_to_other(priv, lq_sta, conf, sta, index);
-		else if (is_mimo2(tbl->lq_type))
-			rs_move_mimo2_to_other(priv, lq_sta, conf, sta, index);
-		else
-			rs_move_mimo3_to_other(priv, lq_sta, conf, sta, index);
-
-		/* If new "search" mode was selected, set up in uCode table */
-		if (lq_sta->search_better_tbl) {
-			/* Access the "search" table, clear its history. */
-			tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
-			for (i = 0; i < IWL_RATE_COUNT; i++)
-				rs_rate_scale_clear_window(&(tbl->win[i]));
-
-			/* Use new "search" start rate */
-			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-
-			IWL_DEBUG_RATE(priv, "Switch current  mcs: %X index: %d\n",
-				     tbl->current_rate, index);
-			rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
-			iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
-		} else
-			done_search = 1;
-	}
-
-	if (done_search && !lq_sta->stay_in_tbl) {
-		/* If the "active" (non-search) mode was legacy,
-		 * and we've tried switching antennas,
-		 * but we haven't been able to try HT modes (not available),
-		 * stay with best antenna legacy modulation for a while
-		 * before next round of mode comparisons. */
-		tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
-		if (is_legacy(tbl1->lq_type) && !conf_is_ht(conf) &&
-		    lq_sta->action_counter > tbl1->max_search) {
-			IWL_DEBUG_RATE(priv, "LQ: STAY in legacy table\n");
-			rs_set_stay_in_table(priv, 1, lq_sta);
-		}
-
-		/* If we're in an HT mode, and all 3 mode switch actions
-		 * have been tried and compared, stay in this best modulation
-		 * mode for a while before next round of mode comparisons. */
-		if (lq_sta->enable_counter &&
-		    (lq_sta->action_counter >= tbl1->max_search) &&
-		    iwl_ht_enabled(priv)) {
-			if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
-			    (lq_sta->tx_agg_tid_en & (1 << tid)) &&
-			    (tid != IWL_MAX_TID_COUNT)) {
-				u8 sta_id = lq_sta->lq.sta_id;
-				tid_data = &priv->tid_data[sta_id][tid];
-				if (tid_data->agg.state == IWL_AGG_OFF) {
-					IWL_DEBUG_RATE(priv,
-						       "try to aggregate tid %d\n",
-						       tid);
-					rs_tl_turn_on_agg(priv, tid,
-							  lq_sta, sta);
-				}
-			}
-			rs_set_stay_in_table(priv, 0, lq_sta);
-		}
-	}
-
-out:
-	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
-	lq_sta->last_txrate_idx = index;
-}
-
-/**
- * rs_initialize_lq - Initialize a station's hardware rate table
- *
- * The uCode's station table contains a table of fallback rates
- * for automatic fallback during transmission.
- *
- * NOTE: This sets up a default set of values.  These will be replaced later
- *       if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
- *       rc80211_simple.
- *
- * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
- *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
- *       which requires station table entry to exist).
- */
-static void rs_initialize_lq(struct iwl_priv *priv,
-			     struct ieee80211_sta *sta,
-			     struct iwl_lq_sta *lq_sta)
-{
-	struct iwl_scale_tbl_info *tbl;
-	int rate_idx;
-	int i;
-	u32 rate;
-	u8 use_green = rs_use_green(sta);
-	u8 active_tbl = 0;
-	u8 valid_tx_ant;
-	struct iwl_station_priv *sta_priv;
-	struct iwl_rxon_context *ctx;
-
-	if (!sta || !lq_sta)
-		return;
-
-	sta_priv = (void *)sta->drv_priv;
-	ctx = sta_priv->ctx;
-
-	i = lq_sta->last_txrate_idx;
-
-	valid_tx_ant = priv->hw_params.valid_tx_ant;
-
-	if (!lq_sta->search_better_tbl)
-		active_tbl = lq_sta->active_tbl;
-	else
-		active_tbl = 1 - lq_sta->active_tbl;
-
-	tbl = &(lq_sta->lq_info[active_tbl]);
-
-	if ((i < 0) || (i >= IWL_RATE_COUNT))
-		i = 0;
-
-	rate = iwl_rates[i].plcp;
-	tbl->ant_type = first_antenna(valid_tx_ant);
-	rate |= tbl->ant_type << RATE_MCS_ANT_POS;
-
-	if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
-		rate |= RATE_MCS_CCK_MSK;
-
-	rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx);
-	if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
-	    rs_toggle_antenna(valid_tx_ant, &rate, tbl);
-
-	rate = rate_n_flags_from_tbl(priv, tbl, rate_idx, use_green);
-	tbl->current_rate = rate;
-	rs_set_expected_tpt_table(lq_sta, tbl);
-	rs_fill_link_cmd(NULL, lq_sta, rate);
-	priv->stations[lq_sta->lq.sta_id].lq = &lq_sta->lq;
-	iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_SYNC, true);
-}
-
-static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
-			struct ieee80211_tx_rate_control *txrc)
-{
-
-	struct sk_buff *skb = txrc->skb;
-	struct ieee80211_supported_band *sband = txrc->sband;
-	struct iwl_op_mode *op_mode __maybe_unused =
-			(struct iwl_op_mode *)priv_r;
-	struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct iwl_lq_sta *lq_sta = priv_sta;
-	int rate_idx;
-
-	IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n");
-
-	/* Get max rate if user set max rate */
-	if (lq_sta) {
-		lq_sta->max_rate_idx = txrc->max_rate_idx;
-		if ((sband->band == IEEE80211_BAND_5GHZ) &&
-		    (lq_sta->max_rate_idx != -1))
-			lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE;
-		if ((lq_sta->max_rate_idx < 0) ||
-		    (lq_sta->max_rate_idx >= IWL_RATE_COUNT))
-			lq_sta->max_rate_idx = -1;
-	}
-
-	/* Treat uninitialized rate scaling data same as non-existing. */
-	if (lq_sta && !lq_sta->drv) {
-		IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n");
-		priv_sta = NULL;
-	}
-
-	/* Send management frames and NO_ACK data using lowest rate. */
-	if (rate_control_send_low(sta, priv_sta, txrc))
-		return;
-
-	rate_idx  = lq_sta->last_txrate_idx;
-
-	if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) {
-		rate_idx -= IWL_FIRST_OFDM_RATE;
-		/* 6M and 9M shared same MCS index */
-		rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0;
-		if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
-		    IWL_RATE_MIMO3_6M_PLCP)
-			rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM);
-		else if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
-			 IWL_RATE_MIMO2_6M_PLCP)
-			rate_idx = rate_idx + MCS_INDEX_PER_STREAM;
-		info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
-		if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK)
-			info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
-		if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK)
-			info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA;
-		if (lq_sta->last_rate_n_flags & RATE_MCS_HT40_MSK)
-			info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
-		if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK)
-			info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
-	} else {
-		/* Check for invalid rates */
-		if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) ||
-				((sband->band == IEEE80211_BAND_5GHZ) &&
-				 (rate_idx < IWL_FIRST_OFDM_RATE)))
-			rate_idx = rate_lowest_index(sband, sta);
-		/* On valid 5 GHz rate, adjust index */
-		else if (sband->band == IEEE80211_BAND_5GHZ)
-			rate_idx -= IWL_FIRST_OFDM_RATE;
-		info->control.rates[0].flags = 0;
-	}
-	info->control.rates[0].idx = rate_idx;
-
-}
-
-static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
-			  gfp_t gfp)
-{
-	struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv;
-	struct iwl_op_mode *op_mode __maybe_unused =
-			(struct iwl_op_mode *)priv_rate;
-	struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
-
-	IWL_DEBUG_RATE(priv, "create station rate scale window\n");
-
-	return &sta_priv->lq_sta;
-}
-
-/*
- * Called after adding a new station to initialize rate scaling
- */
-void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id)
-{
-	int i, j;
-	struct ieee80211_hw *hw = priv->hw;
-	struct ieee80211_conf *conf = &priv->hw->conf;
-	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-	struct iwl_station_priv *sta_priv;
-	struct iwl_lq_sta *lq_sta;
-	struct ieee80211_supported_band *sband;
-	unsigned long supp; /* must be unsigned long for for_each_set_bit */
-
-	sta_priv = (struct iwl_station_priv *) sta->drv_priv;
-	lq_sta = &sta_priv->lq_sta;
-	sband = hw->wiphy->bands[conf->channel->band];
-
-
-	lq_sta->lq.sta_id = sta_id;
-
-	for (j = 0; j < LQ_SIZE; j++)
-		for (i = 0; i < IWL_RATE_COUNT; i++)
-			rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
-
-	lq_sta->flush_timer = 0;
-	lq_sta->supp_rates = sta->supp_rates[sband->band];
-	for (j = 0; j < LQ_SIZE; j++)
-		for (i = 0; i < IWL_RATE_COUNT; i++)
-			rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
-
-	IWL_DEBUG_RATE(priv, "LQ: *** rate scale station global init for station %d ***\n",
-		       sta_id);
-	/* TODO: what is a good starting rate for STA? About middle? Maybe not
-	 * the lowest or the highest rate.. Could consider using RSSI from
-	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
-	 * after assoc.. */
-
-	lq_sta->is_dup = 0;
-	lq_sta->max_rate_idx = -1;
-	lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
-	lq_sta->is_green = rs_use_green(sta);
-	lq_sta->band = sband->band;
-	/*
-	 * active legacy rates as per supported rates bitmap
-	 */
-	supp = sta->supp_rates[sband->band];
-	lq_sta->active_legacy_rate = 0;
-	for_each_set_bit(i, &supp, BITS_PER_LONG)
-		lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value);
-
-	/*
-	 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
-	 * supp_rates[] does not; shift to convert format, force 9 MBits off.
-	 */
-	lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
-	lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
-	lq_sta->active_siso_rate &= ~((u16)0x2);
-	lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
-
-	/* Same here */
-	lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
-	lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
-	lq_sta->active_mimo2_rate &= ~((u16)0x2);
-	lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
-
-	lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1;
-	lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1;
-	lq_sta->active_mimo3_rate &= ~((u16)0x2);
-	lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
-
-	IWL_DEBUG_RATE(priv, "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n",
-		     lq_sta->active_siso_rate,
-		     lq_sta->active_mimo2_rate,
-		     lq_sta->active_mimo3_rate);
-
-	/* These values will be overridden later */
-	lq_sta->lq.general_params.single_stream_ant_msk =
-		first_antenna(priv->hw_params.valid_tx_ant);
-	lq_sta->lq.general_params.dual_stream_ant_msk =
-		priv->hw_params.valid_tx_ant &
-		~first_antenna(priv->hw_params.valid_tx_ant);
-	if (!lq_sta->lq.general_params.dual_stream_ant_msk) {
-		lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
-	} else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
-		lq_sta->lq.general_params.dual_stream_ant_msk =
-			priv->hw_params.valid_tx_ant;
-	}
-
-	/* as default allow aggregation for all tids */
-	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
-	lq_sta->drv = priv;
-
-	/* Set last_txrate_idx to lowest rate */
-	lq_sta->last_txrate_idx = rate_lowest_index(sband, sta);
-	if (sband->band == IEEE80211_BAND_5GHZ)
-		lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
-	lq_sta->is_agg = 0;
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-	priv->tm_fixed_rate = 0;
-#endif
-#ifdef CONFIG_MAC80211_DEBUGFS
-	lq_sta->dbg_fixed_rate = 0;
-#endif
-
-	rs_initialize_lq(priv, sta, lq_sta);
-}
-
-static void rs_fill_link_cmd(struct iwl_priv *priv,
-			     struct iwl_lq_sta *lq_sta, u32 new_rate)
-{
-	struct iwl_scale_tbl_info tbl_type;
-	int index = 0;
-	int rate_idx;
-	int repeat_rate = 0;
-	u8 ant_toggle_cnt = 0;
-	u8 use_ht_possible = 1;
-	u8 valid_tx_ant = 0;
-	struct iwl_station_priv *sta_priv =
-		container_of(lq_sta, struct iwl_station_priv, lq_sta);
-	struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq;
-
-	/* Override starting rate (index 0) if needed for debug purposes */
-	rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
-
-	/* Interpret new_rate (rate_n_flags) */
-	rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
-				  &tbl_type, &rate_idx);
-
-	if (priv && priv->bt_full_concurrent) {
-		/* 1x1 only */
-		tbl_type.ant_type =
-			first_antenna(priv->hw_params.valid_tx_ant);
-	}
-
-	/* How many times should we repeat the initial rate? */
-	if (is_legacy(tbl_type.lq_type)) {
-		ant_toggle_cnt = 1;
-		repeat_rate = IWL_NUMBER_TRY;
-	} else {
-		repeat_rate = min(IWL_HT_NUMBER_TRY,
-				  LINK_QUAL_AGG_DISABLE_START_DEF - 1);
-	}
-
-	lq_cmd->general_params.mimo_delimiter =
-			is_mimo(tbl_type.lq_type) ? 1 : 0;
-
-	/* Fill 1st table entry (index 0) */
-	lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
-
-	if (num_of_ant(tbl_type.ant_type) == 1) {
-		lq_cmd->general_params.single_stream_ant_msk =
-						tbl_type.ant_type;
-	} else if (num_of_ant(tbl_type.ant_type) == 2) {
-		lq_cmd->general_params.dual_stream_ant_msk =
-						tbl_type.ant_type;
-	} /* otherwise we don't modify the existing value */
-
-	index++;
-	repeat_rate--;
-	if (priv) {
-		if (priv->bt_full_concurrent)
-			valid_tx_ant = ANT_A;
-		else
-			valid_tx_ant = priv->hw_params.valid_tx_ant;
-	}
-
-	/* Fill rest of rate table */
-	while (index < LINK_QUAL_MAX_RETRY_NUM) {
-		/* Repeat initial/next rate.
-		 * For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
-		 * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
-		while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
-			if (is_legacy(tbl_type.lq_type)) {
-				if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
-					ant_toggle_cnt++;
-				else if (priv &&
-					 rs_toggle_antenna(valid_tx_ant,
-							&new_rate, &tbl_type))
-					ant_toggle_cnt = 1;
-			}
-
-			/* Override next rate if needed for debug purposes */
-			rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
-
-			/* Fill next table entry */
-			lq_cmd->rs_table[index].rate_n_flags =
-					cpu_to_le32(new_rate);
-			repeat_rate--;
-			index++;
-		}
-
-		rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
-						&rate_idx);
-
-		if (priv && priv->bt_full_concurrent) {
-			/* 1x1 only */
-			tbl_type.ant_type =
-			    first_antenna(priv->hw_params.valid_tx_ant);
-		}
-
-		/* Indicate to uCode which entries might be MIMO.
-		 * If initial rate was MIMO, this will finally end up
-		 * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
-		if (is_mimo(tbl_type.lq_type))
-			lq_cmd->general_params.mimo_delimiter = index;
-
-		/* Get next rate */
-		new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
-					     use_ht_possible);
-
-		/* How many times should we repeat the next rate? */
-		if (is_legacy(tbl_type.lq_type)) {
-			if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
-				ant_toggle_cnt++;
-			else if (priv &&
-				 rs_toggle_antenna(valid_tx_ant,
-						   &new_rate, &tbl_type))
-				ant_toggle_cnt = 1;
-
-			repeat_rate = IWL_NUMBER_TRY;
-		} else {
-			repeat_rate = IWL_HT_NUMBER_TRY;
-		}
-
-		/* Don't allow HT rates after next pass.
-		 * rs_get_lower_rate() will change type to LQ_A or LQ_G. */
-		use_ht_possible = 0;
-
-		/* Override next rate if needed for debug purposes */
-		rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
-
-		/* Fill next table entry */
-		lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
-
-		index++;
-		repeat_rate--;
-	}
-
-	lq_cmd->agg_params.agg_frame_cnt_limit =
-		sta_priv->max_agg_bufsize ?: LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-	lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
-
-	lq_cmd->agg_params.agg_time_limit =
-		cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
-	/*
-	 * overwrite if needed, pass aggregation time limit
-	 * to uCode in uSec
-	 */
-	if (priv && priv->cfg->bt_params &&
-	    priv->cfg->bt_params->agg_time_limit &&
-	    priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
-		lq_cmd->agg_params.agg_time_limit =
-			cpu_to_le16(priv->cfg->bt_params->agg_time_limit);
-}
-
-static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
-{
-	return hw->priv;
-}
-/* rate scale requires free function to be implemented */
-static void rs_free(void *priv_rate)
-{
-	return;
-}
-
-static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
-			void *priv_sta)
-{
-	struct iwl_op_mode *op_mode __maybe_unused = priv_r;
-	struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
-
-	IWL_DEBUG_RATE(priv, "enter\n");
-	IWL_DEBUG_RATE(priv, "leave\n");
-}
-
-#ifdef CONFIG_MAC80211_DEBUGFS
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-			     u32 *rate_n_flags, int index)
-{
-	struct iwl_priv *priv;
-	u8 valid_tx_ant;
-	u8 ant_sel_tx;
-
-	priv = lq_sta->drv;
-	valid_tx_ant = priv->hw_params.valid_tx_ant;
-	if (lq_sta->dbg_fixed_rate) {
-		ant_sel_tx =
-		  ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
-		  >> RATE_MCS_ANT_POS);
-		if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) {
-			*rate_n_flags = lq_sta->dbg_fixed_rate;
-			IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
-		} else {
-			lq_sta->dbg_fixed_rate = 0;
-			IWL_ERR(priv,
-			    "Invalid antenna selection 0x%X, Valid is 0x%X\n",
-			    ant_sel_tx, valid_tx_ant);
-			IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
-		}
-	} else {
-		IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
-	}
-}
-
-static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
-			const char __user *user_buf, size_t count, loff_t *ppos)
-{
-	struct iwl_lq_sta *lq_sta = file->private_data;
-	struct iwl_priv *priv;
-	char buf[64];
-	size_t buf_size;
-	u32 parsed_rate;
-
-
-	priv = lq_sta->drv;
-	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, "%x", &parsed_rate) == 1)
-		lq_sta->dbg_fixed_rate = parsed_rate;
-	else
-		lq_sta->dbg_fixed_rate = 0;
-
-	rs_program_fix_rate(priv, lq_sta);
-
-	return count;
-}
-
-static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
-			char __user *user_buf, size_t count, loff_t *ppos)
-{
-	char *buff;
-	int desc = 0;
-	int i = 0;
-	int index = 0;
-	ssize_t ret;
-
-	struct iwl_lq_sta *lq_sta = file->private_data;
-	struct iwl_priv *priv;
-	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-
-	priv = lq_sta->drv;
-	buff = kmalloc(1024, GFP_KERNEL);
-	if (!buff)
-		return -ENOMEM;
-
-	desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
-	desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
-			lq_sta->total_failed, lq_sta->total_success,
-			lq_sta->active_legacy_rate);
-	desc += sprintf(buff+desc, "fixed rate 0x%X\n",
-			lq_sta->dbg_fixed_rate);
-	desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
-	    (priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "",
-	    (priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "",
-	    (priv->hw_params.valid_tx_ant & ANT_C) ? "ANT_C" : "");
-	desc += sprintf(buff+desc, "lq type %s\n",
-	   (is_legacy(tbl->lq_type)) ? "legacy" : "HT");
-	if (is_Ht(tbl->lq_type)) {
-		desc += sprintf(buff+desc, " %s",
-		   (is_siso(tbl->lq_type)) ? "SISO" :
-		   ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
-		   desc += sprintf(buff+desc, " %s",
-		   (tbl->is_ht40) ? "40MHz" : "20MHz");
-		   desc += sprintf(buff+desc, " %s %s %s\n", (tbl->is_SGI) ? "SGI" : "",
-		   (lq_sta->is_green) ? "GF enabled" : "",
-		   (lq_sta->is_agg) ? "AGG on" : "");
-	}
-	desc += sprintf(buff+desc, "last tx rate=0x%X\n",
-		lq_sta->last_rate_n_flags);
-	desc += sprintf(buff+desc, "general:"
-		"flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
-		lq_sta->lq.general_params.flags,
-		lq_sta->lq.general_params.mimo_delimiter,
-		lq_sta->lq.general_params.single_stream_ant_msk,
-		lq_sta->lq.general_params.dual_stream_ant_msk);
-
-	desc += sprintf(buff+desc, "agg:"
-			"time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
-			le16_to_cpu(lq_sta->lq.agg_params.agg_time_limit),
-			lq_sta->lq.agg_params.agg_dis_start_th,
-			lq_sta->lq.agg_params.agg_frame_cnt_limit);
-
-	desc += sprintf(buff+desc,
-			"Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
-			lq_sta->lq.general_params.start_rate_index[0],
-			lq_sta->lq.general_params.start_rate_index[1],
-			lq_sta->lq.general_params.start_rate_index[2],
-			lq_sta->lq.general_params.start_rate_index[3]);
-
-	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
-		index = iwl_hwrate_to_plcp_idx(
-			le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
-		if (is_legacy(tbl->lq_type)) {
-			desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n",
-				i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
-				iwl_rate_mcs[index].mbps);
-		} else {
-			desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps (%s)\n",
-				i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
-				iwl_rate_mcs[index].mbps, iwl_rate_mcs[index].mcs);
-		}
-	}
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
-	kfree(buff);
-	return ret;
-}
-
-static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
-	.write = rs_sta_dbgfs_scale_table_write,
-	.read = rs_sta_dbgfs_scale_table_read,
-	.open = simple_open,
-	.llseek = default_llseek,
-};
-static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
-			char __user *user_buf, size_t count, loff_t *ppos)
-{
-	char *buff;
-	int desc = 0;
-	int i, j;
-	ssize_t ret;
-
-	struct iwl_lq_sta *lq_sta = file->private_data;
-
-	buff = kmalloc(1024, GFP_KERNEL);
-	if (!buff)
-		return -ENOMEM;
-
-	for (i = 0; i < LQ_SIZE; i++) {
-		desc += sprintf(buff+desc,
-				"%s type=%d SGI=%d HT40=%d DUP=%d GF=%d\n"
-				"rate=0x%X\n",
-				lq_sta->active_tbl == i ? "*" : "x",
-				lq_sta->lq_info[i].lq_type,
-				lq_sta->lq_info[i].is_SGI,
-				lq_sta->lq_info[i].is_ht40,
-				lq_sta->lq_info[i].is_dup,
-				lq_sta->is_green,
-				lq_sta->lq_info[i].current_rate);
-		for (j = 0; j < IWL_RATE_COUNT; j++) {
-			desc += sprintf(buff+desc,
-				"counter=%d success=%d %%=%d\n",
-				lq_sta->lq_info[i].win[j].counter,
-				lq_sta->lq_info[i].win[j].success_counter,
-				lq_sta->lq_info[i].win[j].success_ratio);
-		}
-	}
-	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
-	kfree(buff);
-	return ret;
-}
-
-static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
-	.read = rs_sta_dbgfs_stats_table_read,
-	.open = simple_open,
-	.llseek = default_llseek,
-};
-
-static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
-			char __user *user_buf, size_t count, loff_t *ppos)
-{
-	struct iwl_lq_sta *lq_sta = file->private_data;
-	struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
-	char buff[120];
-	int desc = 0;
-
-	if (is_Ht(tbl->lq_type))
-		desc += sprintf(buff+desc,
-				"Bit Rate= %d Mb/s\n",
-				tbl->expected_tpt[lq_sta->last_txrate_idx]);
-	else
-		desc += sprintf(buff+desc,
-				"Bit Rate= %d Mb/s\n",
-				iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
-
-	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
-}
-
-static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
-	.read = rs_sta_dbgfs_rate_scale_data_read,
-	.open = simple_open,
-	.llseek = default_llseek,
-};
-
-static void rs_add_debugfs(void *priv, void *priv_sta,
-					struct dentry *dir)
-{
-	struct iwl_lq_sta *lq_sta = priv_sta;
-	lq_sta->rs_sta_dbgfs_scale_table_file =
-		debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
-				lq_sta, &rs_sta_dbgfs_scale_table_ops);
-	lq_sta->rs_sta_dbgfs_stats_table_file =
-		debugfs_create_file("rate_stats_table", S_IRUSR, dir,
-			lq_sta, &rs_sta_dbgfs_stats_table_ops);
-	lq_sta->rs_sta_dbgfs_rate_scale_data_file =
-		debugfs_create_file("rate_scale_data", S_IRUSR, dir,
-			lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
-	lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
-		debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
-		&lq_sta->tx_agg_tid_en);
-
-}
-
-static void rs_remove_debugfs(void *priv, void *priv_sta)
-{
-	struct iwl_lq_sta *lq_sta = priv_sta;
-	debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
-	debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
-	debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file);
-	debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
-}
-#endif
-
-/*
- * Initialization of rate scaling information is done by driver after
- * the station is added. Since mac80211 calls this function before a
- * station is added we ignore it.
- */
-static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband,
-			 struct ieee80211_sta *sta, void *priv_sta)
-{
-}
-static struct rate_control_ops rs_ops = {
-	.module = NULL,
-	.name = RS_NAME,
-	.tx_status = rs_tx_status,
-	.get_rate = rs_get_rate,
-	.rate_init = rs_rate_init_stub,
-	.alloc = rs_alloc,
-	.free = rs_free,
-	.alloc_sta = rs_alloc_sta,
-	.free_sta = rs_free_sta,
-#ifdef CONFIG_MAC80211_DEBUGFS
-	.add_sta_debugfs = rs_add_debugfs,
-	.remove_sta_debugfs = rs_remove_debugfs,
-#endif
-};
-
-int iwlagn_rate_control_register(void)
-{
-	return ieee80211_rate_control_register(&rs_ops);
-}
-
-void iwlagn_rate_control_unregister(void)
-{
-	ieee80211_rate_control_unregister(&rs_ops);
-}
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
deleted file mode 100644
index 82d02e1..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ /dev/null
@@ -1,432 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 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.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#ifndef __iwl_agn_rs_h__
-#define __iwl_agn_rs_h__
-
-#include <net/mac80211.h>
-
-#include "iwl-commands.h"
-#include "iwl-config.h"
-
-struct iwl_rate_info {
-	u8 plcp;	/* uCode API:  IWL_RATE_6M_PLCP, etc. */
-	u8 plcp_siso;	/* uCode API:  IWL_RATE_SISO_6M_PLCP, etc. */
-	u8 plcp_mimo2;	/* uCode API:  IWL_RATE_MIMO2_6M_PLCP, etc. */
-	u8 plcp_mimo3;  /* uCode API:  IWL_RATE_MIMO3_6M_PLCP, etc. */
-	u8 ieee;	/* MAC header:  IWL_RATE_6M_IEEE, etc. */
-	u8 prev_ieee;    /* previous rate in IEEE speeds */
-	u8 next_ieee;    /* next rate in IEEE speeds */
-	u8 prev_rs;      /* previous rate used in rs algo */
-	u8 next_rs;      /* next rate used in rs algo */
-	u8 prev_rs_tgg;  /* previous rate used in TGG rs algo */
-	u8 next_rs_tgg;  /* next rate used in TGG rs algo */
-};
-
-/*
- * These serve as indexes into
- * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
- */
-enum {
-	IWL_RATE_1M_INDEX = 0,
-	IWL_RATE_2M_INDEX,
-	IWL_RATE_5M_INDEX,
-	IWL_RATE_11M_INDEX,
-	IWL_RATE_6M_INDEX,
-	IWL_RATE_9M_INDEX,
-	IWL_RATE_12M_INDEX,
-	IWL_RATE_18M_INDEX,
-	IWL_RATE_24M_INDEX,
-	IWL_RATE_36M_INDEX,
-	IWL_RATE_48M_INDEX,
-	IWL_RATE_54M_INDEX,
-	IWL_RATE_60M_INDEX,
-	IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/
-	IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1,	/* Excluding 60M */
-	IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
-	IWL_RATE_INVALID = IWL_RATE_COUNT,
-};
-
-enum {
-	IWL_RATE_6M_INDEX_TABLE = 0,
-	IWL_RATE_9M_INDEX_TABLE,
-	IWL_RATE_12M_INDEX_TABLE,
-	IWL_RATE_18M_INDEX_TABLE,
-	IWL_RATE_24M_INDEX_TABLE,
-	IWL_RATE_36M_INDEX_TABLE,
-	IWL_RATE_48M_INDEX_TABLE,
-	IWL_RATE_54M_INDEX_TABLE,
-	IWL_RATE_1M_INDEX_TABLE,
-	IWL_RATE_2M_INDEX_TABLE,
-	IWL_RATE_5M_INDEX_TABLE,
-	IWL_RATE_11M_INDEX_TABLE,
-	IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX - 1,
-};
-
-enum {
-	IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
-	IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
-	IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
-	IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
-};
-
-/* #define vs. enum to keep from defaulting to 'large integer' */
-#define	IWL_RATE_6M_MASK   (1 << IWL_RATE_6M_INDEX)
-#define	IWL_RATE_9M_MASK   (1 << IWL_RATE_9M_INDEX)
-#define	IWL_RATE_12M_MASK  (1 << IWL_RATE_12M_INDEX)
-#define	IWL_RATE_18M_MASK  (1 << IWL_RATE_18M_INDEX)
-#define	IWL_RATE_24M_MASK  (1 << IWL_RATE_24M_INDEX)
-#define	IWL_RATE_36M_MASK  (1 << IWL_RATE_36M_INDEX)
-#define	IWL_RATE_48M_MASK  (1 << IWL_RATE_48M_INDEX)
-#define	IWL_RATE_54M_MASK  (1 << IWL_RATE_54M_INDEX)
-#define IWL_RATE_60M_MASK  (1 << IWL_RATE_60M_INDEX)
-#define	IWL_RATE_1M_MASK   (1 << IWL_RATE_1M_INDEX)
-#define	IWL_RATE_2M_MASK   (1 << IWL_RATE_2M_INDEX)
-#define	IWL_RATE_5M_MASK   (1 << IWL_RATE_5M_INDEX)
-#define	IWL_RATE_11M_MASK  (1 << IWL_RATE_11M_INDEX)
-
-/* uCode API values for legacy bit rates, both OFDM and CCK */
-enum {
-	IWL_RATE_6M_PLCP  = 13,
-	IWL_RATE_9M_PLCP  = 15,
-	IWL_RATE_12M_PLCP = 5,
-	IWL_RATE_18M_PLCP = 7,
-	IWL_RATE_24M_PLCP = 9,
-	IWL_RATE_36M_PLCP = 11,
-	IWL_RATE_48M_PLCP = 1,
-	IWL_RATE_54M_PLCP = 3,
-	IWL_RATE_60M_PLCP = 3,/*FIXME:RS:should be removed*/
-	IWL_RATE_1M_PLCP  = 10,
-	IWL_RATE_2M_PLCP  = 20,
-	IWL_RATE_5M_PLCP  = 55,
-	IWL_RATE_11M_PLCP = 110,
-	/*FIXME:RS:change to IWL_RATE_LEGACY_??M_PLCP */
-	/*FIXME:RS:add IWL_RATE_LEGACY_INVM_PLCP = 0,*/
-};
-
-/* uCode API values for OFDM high-throughput (HT) bit rates */
-enum {
-	IWL_RATE_SISO_6M_PLCP = 0,
-	IWL_RATE_SISO_12M_PLCP = 1,
-	IWL_RATE_SISO_18M_PLCP = 2,
-	IWL_RATE_SISO_24M_PLCP = 3,
-	IWL_RATE_SISO_36M_PLCP = 4,
-	IWL_RATE_SISO_48M_PLCP = 5,
-	IWL_RATE_SISO_54M_PLCP = 6,
-	IWL_RATE_SISO_60M_PLCP = 7,
-	IWL_RATE_MIMO2_6M_PLCP  = 0x8,
-	IWL_RATE_MIMO2_12M_PLCP = 0x9,
-	IWL_RATE_MIMO2_18M_PLCP = 0xa,
-	IWL_RATE_MIMO2_24M_PLCP = 0xb,
-	IWL_RATE_MIMO2_36M_PLCP = 0xc,
-	IWL_RATE_MIMO2_48M_PLCP = 0xd,
-	IWL_RATE_MIMO2_54M_PLCP = 0xe,
-	IWL_RATE_MIMO2_60M_PLCP = 0xf,
-	IWL_RATE_MIMO3_6M_PLCP  = 0x10,
-	IWL_RATE_MIMO3_12M_PLCP = 0x11,
-	IWL_RATE_MIMO3_18M_PLCP = 0x12,
-	IWL_RATE_MIMO3_24M_PLCP = 0x13,
-	IWL_RATE_MIMO3_36M_PLCP = 0x14,
-	IWL_RATE_MIMO3_48M_PLCP = 0x15,
-	IWL_RATE_MIMO3_54M_PLCP = 0x16,
-	IWL_RATE_MIMO3_60M_PLCP = 0x17,
-	IWL_RATE_SISO_INVM_PLCP,
-	IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
-	IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
-};
-
-/* MAC header values for bit rates */
-enum {
-	IWL_RATE_6M_IEEE  = 12,
-	IWL_RATE_9M_IEEE  = 18,
-	IWL_RATE_12M_IEEE = 24,
-	IWL_RATE_18M_IEEE = 36,
-	IWL_RATE_24M_IEEE = 48,
-	IWL_RATE_36M_IEEE = 72,
-	IWL_RATE_48M_IEEE = 96,
-	IWL_RATE_54M_IEEE = 108,
-	IWL_RATE_60M_IEEE = 120,
-	IWL_RATE_1M_IEEE  = 2,
-	IWL_RATE_2M_IEEE  = 4,
-	IWL_RATE_5M_IEEE  = 11,
-	IWL_RATE_11M_IEEE = 22,
-};
-
-#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
-
-#define IWL_INVALID_VALUE    -1
-
-#define IWL_MIN_RSSI_VAL                 -100
-#define IWL_MAX_RSSI_VAL                    0
-
-/* These values specify how many Tx frame attempts before
- * searching for a new modulation mode */
-#define IWL_LEGACY_FAILURE_LIMIT	160
-#define IWL_LEGACY_SUCCESS_LIMIT	480
-#define IWL_LEGACY_TABLE_COUNT		160
-
-#define IWL_NONE_LEGACY_FAILURE_LIMIT	400
-#define IWL_NONE_LEGACY_SUCCESS_LIMIT	4500
-#define IWL_NONE_LEGACY_TABLE_COUNT	1500
-
-/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */
-#define IWL_RS_GOOD_RATIO		12800	/* 100% */
-#define IWL_RATE_SCALE_SWITCH		10880	/*  85% */
-#define IWL_RATE_HIGH_TH		10880	/*  85% */
-#define IWL_RATE_INCREASE_TH		6400	/*  50% */
-#define IWL_RATE_DECREASE_TH		1920	/*  15% */
-
-/* possible actions when in legacy mode */
-#define IWL_LEGACY_SWITCH_ANTENNA1      0
-#define IWL_LEGACY_SWITCH_ANTENNA2      1
-#define IWL_LEGACY_SWITCH_SISO          2
-#define IWL_LEGACY_SWITCH_MIMO2_AB      3
-#define IWL_LEGACY_SWITCH_MIMO2_AC      4
-#define IWL_LEGACY_SWITCH_MIMO2_BC      5
-#define IWL_LEGACY_SWITCH_MIMO3_ABC     6
-
-/* possible actions when in siso mode */
-#define IWL_SISO_SWITCH_ANTENNA1        0
-#define IWL_SISO_SWITCH_ANTENNA2        1
-#define IWL_SISO_SWITCH_MIMO2_AB        2
-#define IWL_SISO_SWITCH_MIMO2_AC        3
-#define IWL_SISO_SWITCH_MIMO2_BC        4
-#define IWL_SISO_SWITCH_GI              5
-#define IWL_SISO_SWITCH_MIMO3_ABC       6
-
-
-/* possible actions when in mimo mode */
-#define IWL_MIMO2_SWITCH_ANTENNA1       0
-#define IWL_MIMO2_SWITCH_ANTENNA2       1
-#define IWL_MIMO2_SWITCH_SISO_A         2
-#define IWL_MIMO2_SWITCH_SISO_B         3
-#define IWL_MIMO2_SWITCH_SISO_C         4
-#define IWL_MIMO2_SWITCH_GI             5
-#define IWL_MIMO2_SWITCH_MIMO3_ABC      6
-
-
-/* possible actions when in mimo3 mode */
-#define IWL_MIMO3_SWITCH_ANTENNA1       0
-#define IWL_MIMO3_SWITCH_ANTENNA2       1
-#define IWL_MIMO3_SWITCH_SISO_A         2
-#define IWL_MIMO3_SWITCH_SISO_B         3
-#define IWL_MIMO3_SWITCH_SISO_C         4
-#define IWL_MIMO3_SWITCH_MIMO2_AB       5
-#define IWL_MIMO3_SWITCH_MIMO2_AC       6
-#define IWL_MIMO3_SWITCH_MIMO2_BC       7
-#define IWL_MIMO3_SWITCH_GI             8
-
-
-#define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI
-#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC
-
-/*FIXME:RS:add possible actions for MIMO3*/
-
-#define IWL_ACTION_LIMIT		3	/* # possible actions */
-
-#define LQ_SIZE		2	/* 2 mode tables:  "Active" and "Search" */
-
-/* load per tid defines for A-MPDU activation */
-#define IWL_AGG_TPT_THREHOLD	0
-#define IWL_AGG_LOAD_THRESHOLD	10
-#define IWL_AGG_ALL_TID		0xff
-#define TID_QUEUE_CELL_SPACING	50	/*mS */
-#define TID_QUEUE_MAX_SIZE	20
-#define TID_ROUND_VALUE		5	/* mS */
-
-#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
-#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
-
-extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
-
-enum iwl_table_type {
-	LQ_NONE,
-	LQ_G,		/* legacy types */
-	LQ_A,
-	LQ_SISO,	/* high-throughput types */
-	LQ_MIMO2,
-	LQ_MIMO3,
-	LQ_MAX,
-};
-
-#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
-#define is_siso(tbl) ((tbl) == LQ_SISO)
-#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
-#define is_mimo3(tbl) ((tbl) == LQ_MIMO3)
-#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl))
-#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
-#define is_a_band(tbl) ((tbl) == LQ_A)
-#define is_g_and(tbl) ((tbl) == LQ_G)
-
-#define IWL_MAX_MCS_DISPLAY_SIZE	12
-
-struct iwl_rate_mcs_info {
-	char	mbps[IWL_MAX_MCS_DISPLAY_SIZE];
-	char	mcs[IWL_MAX_MCS_DISPLAY_SIZE];
-};
-
-/**
- * struct iwl_rate_scale_data -- tx success history for one rate
- */
-struct iwl_rate_scale_data {
-	u64 data;		/* bitmap of successful frames */
-	s32 success_counter;	/* number of frames successful */
-	s32 success_ratio;	/* per-cent * 128  */
-	s32 counter;		/* number of frames attempted */
-	s32 average_tpt;	/* success ratio * expected throughput */
-	unsigned long stamp;
-};
-
-/**
- * struct iwl_scale_tbl_info -- tx params and success history for all rates
- *
- * There are two of these in struct iwl_lq_sta,
- * one for "active", and one for "search".
- */
-struct iwl_scale_tbl_info {
-	enum iwl_table_type lq_type;
-	u8 ant_type;
-	u8 is_SGI;	/* 1 = short guard interval */
-	u8 is_ht40;	/* 1 = 40 MHz channel width */
-	u8 is_dup;	/* 1 = duplicated data streams */
-	u8 action;	/* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
-	u8 max_search;	/* maximun number of tables we can search */
-	s32 *expected_tpt;	/* throughput metrics; expected_tpt_G, etc. */
-	u32 current_rate;  /* rate_n_flags, uCode API format */
-	struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
-};
-
-struct iwl_traffic_load {
-	unsigned long time_stamp;	/* age of the oldest statistics */
-	u32 packet_count[TID_QUEUE_MAX_SIZE];   /* packet count in this time
-						 * slice */
-	u32 total;			/* total num of packets during the
-					 * last TID_MAX_TIME_DIFF */
-	u8 queue_count;			/* number of queues that has
-					 * been used since the last cleanup */
-	u8 head;			/* start of the circular buffer */
-};
-
-/**
- * struct iwl_lq_sta -- driver's rate scaling private structure
- *
- * Pointer to this gets passed back and forth between driver and mac80211.
- */
-struct iwl_lq_sta {
-	u8 active_tbl;		/* index of active table, range 0-1 */
-	u8 enable_counter;	/* indicates HT mode */
-	u8 stay_in_tbl;		/* 1: disallow, 0: allow search for new mode */
-	u8 search_better_tbl;	/* 1: currently trying alternate mode */
-	s32 last_tpt;
-
-	/* The following determine when to search for a new mode */
-	u32 table_count_limit;
-	u32 max_failure_limit;	/* # failed frames before new search */
-	u32 max_success_limit;	/* # successful frames before new search */
-	u32 table_count;
-	u32 total_failed;	/* total failed frames, any/all rates */
-	u32 total_success;	/* total successful frames, any/all rates */
-	u64 flush_timer;	/* time staying in mode before new search */
-
-	u8 action_counter;	/* # mode-switch actions tried */
-	u8 is_green;
-	u8 is_dup;
-	enum ieee80211_band band;
-
-	/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
-	u32 supp_rates;
-	u16 active_legacy_rate;
-	u16 active_siso_rate;
-	u16 active_mimo2_rate;
-	u16 active_mimo3_rate;
-	s8 max_rate_idx;     /* Max rate set by user */
-	u8 missed_rate_counter;
-
-	struct iwl_link_quality_cmd lq;
-	struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
-	struct iwl_traffic_load load[IWL_MAX_TID_COUNT];
-	u8 tx_agg_tid_en;
-#ifdef CONFIG_MAC80211_DEBUGFS
-	struct dentry *rs_sta_dbgfs_scale_table_file;
-	struct dentry *rs_sta_dbgfs_stats_table_file;
-	struct dentry *rs_sta_dbgfs_rate_scale_data_file;
-	struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
-	u32 dbg_fixed_rate;
-#endif
-	struct iwl_priv *drv;
-
-	/* used to be in sta_info */
-	int last_txrate_idx;
-	/* last tx rate_n_flags */
-	u32 last_rate_n_flags;
-	/* packets destined for this STA are aggregated */
-	u8 is_agg;
-	/* BT traffic this sta was last updated in */
-	u8 last_bt_traffic;
-};
-
-static inline u8 num_of_ant(u8 mask)
-{
-	return  !!((mask) & ANT_A) +
-		!!((mask) & ANT_B) +
-		!!((mask) & ANT_C);
-}
-
-static inline u8 first_antenna(u8 mask)
-{
-	if (mask & ANT_A)
-		return ANT_A;
-	if (mask & ANT_B)
-		return ANT_B;
-	return ANT_C;
-}
-
-
-/* Initialize station's rate scaling information after adding station */
-extern void iwl_rs_rate_init(struct iwl_priv *priv,
-			     struct ieee80211_sta *sta, u8 sta_id);
-
-/**
- * iwl_rate_control_register - Register the rate control algorithm callbacks
- *
- * Since the rate control algorithm is hardware specific, there is no need
- * or reason to place it as a stand alone module.  The driver can call
- * iwl_rate_control_register in order to register the rate control callbacks
- * with the mac80211 subsystem.  This should be performed prior to calling
- * ieee80211_register_hw
- *
- */
-extern int iwlagn_rate_control_register(void);
-
-/**
- * iwl_rate_control_unregister - Unregister the rate control callbacks
- *
- * This should be called after calling ieee80211_unregister_hw, but before
- * the driver is unloaded.
- */
-extern void iwlagn_rate_control_unregister(void);
-
-#endif /* __iwl_agn__rs__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
deleted file mode 100644
index 403de96..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
+++ /dev/null
@@ -1,1166 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portionhelp of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <net/mac80211.h>
-#include <asm/unaligned.h>
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-calib.h"
-#include "iwl-agn.h"
-#include "iwl-modparams.h"
-
-#define IWL_CMD_ENTRY(x) [x] = #x
-
-const char *iwl_dvm_cmd_strings[REPLY_MAX] = {
-	IWL_CMD_ENTRY(REPLY_ALIVE),
-	IWL_CMD_ENTRY(REPLY_ERROR),
-	IWL_CMD_ENTRY(REPLY_ECHO),
-	IWL_CMD_ENTRY(REPLY_RXON),
-	IWL_CMD_ENTRY(REPLY_RXON_ASSOC),
-	IWL_CMD_ENTRY(REPLY_QOS_PARAM),
-	IWL_CMD_ENTRY(REPLY_RXON_TIMING),
-	IWL_CMD_ENTRY(REPLY_ADD_STA),
-	IWL_CMD_ENTRY(REPLY_REMOVE_STA),
-	IWL_CMD_ENTRY(REPLY_REMOVE_ALL_STA),
-	IWL_CMD_ENTRY(REPLY_TXFIFO_FLUSH),
-	IWL_CMD_ENTRY(REPLY_WEPKEY),
-	IWL_CMD_ENTRY(REPLY_TX),
-	IWL_CMD_ENTRY(REPLY_LEDS_CMD),
-	IWL_CMD_ENTRY(REPLY_TX_LINK_QUALITY_CMD),
-	IWL_CMD_ENTRY(COEX_PRIORITY_TABLE_CMD),
-	IWL_CMD_ENTRY(COEX_MEDIUM_NOTIFICATION),
-	IWL_CMD_ENTRY(COEX_EVENT_CMD),
-	IWL_CMD_ENTRY(REPLY_QUIET_CMD),
-	IWL_CMD_ENTRY(REPLY_CHANNEL_SWITCH),
-	IWL_CMD_ENTRY(CHANNEL_SWITCH_NOTIFICATION),
-	IWL_CMD_ENTRY(REPLY_SPECTRUM_MEASUREMENT_CMD),
-	IWL_CMD_ENTRY(SPECTRUM_MEASURE_NOTIFICATION),
-	IWL_CMD_ENTRY(POWER_TABLE_CMD),
-	IWL_CMD_ENTRY(PM_SLEEP_NOTIFICATION),
-	IWL_CMD_ENTRY(PM_DEBUG_STATISTIC_NOTIFIC),
-	IWL_CMD_ENTRY(REPLY_SCAN_CMD),
-	IWL_CMD_ENTRY(REPLY_SCAN_ABORT_CMD),
-	IWL_CMD_ENTRY(SCAN_START_NOTIFICATION),
-	IWL_CMD_ENTRY(SCAN_RESULTS_NOTIFICATION),
-	IWL_CMD_ENTRY(SCAN_COMPLETE_NOTIFICATION),
-	IWL_CMD_ENTRY(BEACON_NOTIFICATION),
-	IWL_CMD_ENTRY(REPLY_TX_BEACON),
-	IWL_CMD_ENTRY(WHO_IS_AWAKE_NOTIFICATION),
-	IWL_CMD_ENTRY(QUIET_NOTIFICATION),
-	IWL_CMD_ENTRY(REPLY_TX_PWR_TABLE_CMD),
-	IWL_CMD_ENTRY(MEASURE_ABORT_NOTIFICATION),
-	IWL_CMD_ENTRY(REPLY_BT_CONFIG),
-	IWL_CMD_ENTRY(REPLY_STATISTICS_CMD),
-	IWL_CMD_ENTRY(STATISTICS_NOTIFICATION),
-	IWL_CMD_ENTRY(REPLY_CARD_STATE_CMD),
-	IWL_CMD_ENTRY(CARD_STATE_NOTIFICATION),
-	IWL_CMD_ENTRY(MISSED_BEACONS_NOTIFICATION),
-	IWL_CMD_ENTRY(REPLY_CT_KILL_CONFIG_CMD),
-	IWL_CMD_ENTRY(SENSITIVITY_CMD),
-	IWL_CMD_ENTRY(REPLY_PHY_CALIBRATION_CMD),
-	IWL_CMD_ENTRY(REPLY_RX_PHY_CMD),
-	IWL_CMD_ENTRY(REPLY_RX_MPDU_CMD),
-	IWL_CMD_ENTRY(REPLY_RX),
-	IWL_CMD_ENTRY(REPLY_COMPRESSED_BA),
-	IWL_CMD_ENTRY(CALIBRATION_CFG_CMD),
-	IWL_CMD_ENTRY(CALIBRATION_RES_NOTIFICATION),
-	IWL_CMD_ENTRY(CALIBRATION_COMPLETE_NOTIFICATION),
-	IWL_CMD_ENTRY(REPLY_TX_POWER_DBM_CMD),
-	IWL_CMD_ENTRY(TEMPERATURE_NOTIFICATION),
-	IWL_CMD_ENTRY(TX_ANT_CONFIGURATION_CMD),
-	IWL_CMD_ENTRY(REPLY_BT_COEX_PROFILE_NOTIF),
-	IWL_CMD_ENTRY(REPLY_BT_COEX_PRIO_TABLE),
-	IWL_CMD_ENTRY(REPLY_BT_COEX_PROT_ENV),
-	IWL_CMD_ENTRY(REPLY_WIPAN_PARAMS),
-	IWL_CMD_ENTRY(REPLY_WIPAN_RXON),
-	IWL_CMD_ENTRY(REPLY_WIPAN_RXON_TIMING),
-	IWL_CMD_ENTRY(REPLY_WIPAN_RXON_ASSOC),
-	IWL_CMD_ENTRY(REPLY_WIPAN_QOS_PARAM),
-	IWL_CMD_ENTRY(REPLY_WIPAN_WEPKEY),
-	IWL_CMD_ENTRY(REPLY_WIPAN_P2P_CHANNEL_SWITCH),
-	IWL_CMD_ENTRY(REPLY_WIPAN_NOA_NOTIFICATION),
-	IWL_CMD_ENTRY(REPLY_WIPAN_DEACTIVATION_COMPLETE),
-	IWL_CMD_ENTRY(REPLY_WOWLAN_PATTERNS),
-	IWL_CMD_ENTRY(REPLY_WOWLAN_WAKEUP_FILTER),
-	IWL_CMD_ENTRY(REPLY_WOWLAN_TSC_RSC_PARAMS),
-	IWL_CMD_ENTRY(REPLY_WOWLAN_TKIP_PARAMS),
-	IWL_CMD_ENTRY(REPLY_WOWLAN_KEK_KCK_MATERIAL),
-	IWL_CMD_ENTRY(REPLY_WOWLAN_GET_STATUS),
-	IWL_CMD_ENTRY(REPLY_D3_CONFIG),
-};
-#undef IWL_CMD_ENTRY
-
-/******************************************************************************
- *
- * Generic RX handler implementations
- *
- ******************************************************************************/
-
-static int iwlagn_rx_reply_error(struct iwl_priv *priv,
-			       struct iwl_rx_cmd_buffer *rxb,
-			       struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_error_resp *err_resp = (void *)pkt->data;
-
-	IWL_ERR(priv, "Error Reply type 0x%08X cmd REPLY_ERROR (0x%02X) "
-		"seq 0x%04X ser 0x%08X\n",
-		le32_to_cpu(err_resp->error_type),
-		err_resp->cmd_id,
-		le16_to_cpu(err_resp->bad_cmd_seq_num),
-		le32_to_cpu(err_resp->error_info));
-	return 0;
-}
-
-static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-			       struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_csa_notification *csa = (void *)pkt->data;
-	/*
-	 * MULTI-FIXME
-	 * See iwlagn_mac_channel_switch.
-	 */
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-	struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
-
-	if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
-		return 0;
-
-	if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
-		rxon->channel = csa->channel;
-		ctx->staging.channel = csa->channel;
-		IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
-			      le16_to_cpu(csa->channel));
-		iwl_chswitch_done(priv, true);
-	} else {
-		IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
-			le16_to_cpu(csa->channel));
-		iwl_chswitch_done(priv, false);
-	}
-	return 0;
-}
-
-
-static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv,
-					  struct iwl_rx_cmd_buffer *rxb,
-					  struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_spectrum_notification *report = (void *)pkt->data;
-
-	if (!report->state) {
-		IWL_DEBUG_11H(priv,
-			"Spectrum Measure Notification: Start\n");
-		return 0;
-	}
-
-	memcpy(&priv->measure_report, report, sizeof(*report));
-	priv->measurement_status |= MEASUREMENT_READY;
-	return 0;
-}
-
-static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv,
-				  struct iwl_rx_cmd_buffer *rxb,
-				  struct iwl_device_cmd *cmd)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_sleep_notification *sleep = (void *)pkt->data;
-	IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
-		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
-#endif
-	return 0;
-}
-
-static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-					     struct iwl_rx_cmd_buffer *rxb,
-					     struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	u32 __maybe_unused len =
-		le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-	IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
-			"notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len);
-	iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len);
-	return 0;
-}
-
-static int iwlagn_rx_beacon_notif(struct iwl_priv *priv,
-				struct iwl_rx_cmd_buffer *rxb,
-				struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwlagn_beacon_notif *beacon = (void *)pkt->data;
-#ifdef CONFIG_IWLWIFI_DEBUG
-	u16 status = le16_to_cpu(beacon->beacon_notify_hdr.status.status);
-	u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
-
-	IWL_DEBUG_RX(priv, "beacon status %#x, retries:%d ibssmgr:%d "
-		"tsf:0x%.8x%.8x rate:%d\n",
-		status & TX_STATUS_MSK,
-		beacon->beacon_notify_hdr.failure_frame,
-		le32_to_cpu(beacon->ibss_mgr_status),
-		le32_to_cpu(beacon->high_tsf),
-		le32_to_cpu(beacon->low_tsf), rate);
-#endif
-
-	priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
-
-	return 0;
-}
-
-/**
- * iwl_good_plcp_health - checks for plcp error.
- *
- * When the plcp error is exceeding the thresholds, reset the radio
- * to improve the throughput.
- */
-static bool iwlagn_good_plcp_health(struct iwl_priv *priv,
-				 struct statistics_rx_phy *cur_ofdm,
-				 struct statistics_rx_ht_phy *cur_ofdm_ht,
-				 unsigned int msecs)
-{
-	int delta;
-	int threshold = priv->plcp_delta_threshold;
-
-	if (threshold == IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
-		IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
-		return true;
-	}
-
-	delta = le32_to_cpu(cur_ofdm->plcp_err) -
-		le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) +
-		le32_to_cpu(cur_ofdm_ht->plcp_err) -
-		le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err);
-
-	/* Can be negative if firmware reset statistics */
-	if (delta <= 0)
-		return true;
-
-	if ((delta * 100 / msecs) > threshold) {
-		IWL_DEBUG_RADIO(priv,
-				"plcp health threshold %u delta %d msecs %u\n",
-				threshold, delta, msecs);
-		return false;
-	}
-
-	return true;
-}
-
-int iwl_force_rf_reset(struct iwl_priv *priv, bool external)
-{
-	struct iwl_rf_reset *rf_reset;
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return -EAGAIN;
-
-	if (!iwl_is_any_associated(priv)) {
-		IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
-		return -ENOLINK;
-	}
-
-	rf_reset = &priv->rf_reset;
-	rf_reset->reset_request_count++;
-	if (!external && rf_reset->last_reset_jiffies &&
-	    time_after(rf_reset->last_reset_jiffies +
-		       IWL_DELAY_NEXT_FORCE_RF_RESET, jiffies)) {
-		IWL_DEBUG_INFO(priv, "RF reset rejected\n");
-		rf_reset->reset_reject_count++;
-		return -EAGAIN;
-	}
-	rf_reset->reset_success_count++;
-	rf_reset->last_reset_jiffies = jiffies;
-
-	/*
-	 * There is no easy and better way to force reset the radio,
-	 * the only known method is switching channel which will force to
-	 * reset and tune the radio.
-	 * Use internal short scan (single channel) operation to should
-	 * achieve this objective.
-	 * Driver should reset the radio when number of consecutive missed
-	 * beacon, or any other uCode error condition detected.
-	 */
-	IWL_DEBUG_INFO(priv, "perform radio reset.\n");
-	iwl_internal_short_hw_scan(priv);
-	return 0;
-}
-
-
-static void iwlagn_recover_from_statistics(struct iwl_priv *priv,
-				struct statistics_rx_phy *cur_ofdm,
-				struct statistics_rx_ht_phy *cur_ofdm_ht,
-				struct statistics_tx *tx,
-				unsigned long stamp)
-{
-	unsigned int msecs;
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies);
-
-	/* Only gather statistics and update time stamp when not associated */
-	if (!iwl_is_any_associated(priv))
-		return;
-
-	/* Do not check/recover when do not have enough statistics data */
-	if (msecs < 99)
-		return;
-
-	if (iwlwifi_mod_params.plcp_check &&
-	    !iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
-		iwl_force_rf_reset(priv, false);
-}
-
-/* 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 iwlagn_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;
-
-	rx_info = &priv->statistics.rx_non_phy;
-
-	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 accum_stats(__le32 *prev, __le32 *cur, __le32 *delta,
-			__le32 *max_delta, __le32 *accum, int size)
-{
-	int i;
-
-	for (i = 0;
-	     i < size / sizeof(__le32);
-	     i++, prev++, cur++, delta++, max_delta++, accum++) {
-		if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) {
-			*delta = cpu_to_le32(
-				le32_to_cpu(*cur) - le32_to_cpu(*prev));
-			le32_add_cpu(accum, le32_to_cpu(*delta));
-			if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta))
-				*max_delta = *delta;
-		}
-	}
-}
-
-static void
-iwlagn_accumulative_statistics(struct iwl_priv *priv,
-			    struct statistics_general_common *common,
-			    struct statistics_rx_non_phy *rx_non_phy,
-			    struct statistics_rx_phy *rx_ofdm,
-			    struct statistics_rx_ht_phy *rx_ofdm_ht,
-			    struct statistics_rx_phy *rx_cck,
-			    struct statistics_tx *tx,
-			    struct statistics_bt_activity *bt_activity)
-{
-#define ACCUM(_name)	\
-	accum_stats((__le32 *)&priv->statistics._name,		\
-		    (__le32 *)_name,				\
-		    (__le32 *)&priv->delta_stats._name,		\
-		    (__le32 *)&priv->max_delta_stats._name,	\
-		    (__le32 *)&priv->accum_stats._name,		\
-		    sizeof(*_name));
-
-	ACCUM(common);
-	ACCUM(rx_non_phy);
-	ACCUM(rx_ofdm);
-	ACCUM(rx_ofdm_ht);
-	ACCUM(rx_cck);
-	ACCUM(tx);
-	if (bt_activity)
-		ACCUM(bt_activity);
-#undef ACCUM
-}
-#else
-static inline void
-iwlagn_accumulative_statistics(struct iwl_priv *priv,
-			    struct statistics_general_common *common,
-			    struct statistics_rx_non_phy *rx_non_phy,
-			    struct statistics_rx_phy *rx_ofdm,
-			    struct statistics_rx_ht_phy *rx_ofdm_ht,
-			    struct statistics_rx_phy *rx_cck,
-			    struct statistics_tx *tx,
-			    struct statistics_bt_activity *bt_activity)
-{
-}
-#endif
-
-static int iwlagn_rx_statistics(struct iwl_priv *priv,
-			      struct iwl_rx_cmd_buffer *rxb,
-			      struct iwl_device_cmd *cmd)
-{
-	unsigned long stamp = jiffies;
-	const int reg_recalib_period = 60;
-	int change;
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-	__le32 *flag;
-	struct statistics_general_common *common;
-	struct statistics_rx_non_phy *rx_non_phy;
-	struct statistics_rx_phy *rx_ofdm;
-	struct statistics_rx_ht_phy *rx_ofdm_ht;
-	struct statistics_rx_phy *rx_cck;
-	struct statistics_tx *tx;
-	struct statistics_bt_activity *bt_activity;
-
-	len -= sizeof(struct iwl_cmd_header); /* skip header */
-
-	IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n",
-		     len);
-
-	spin_lock(&priv->statistics.lock);
-
-	if (len == sizeof(struct iwl_bt_notif_statistics)) {
-		struct iwl_bt_notif_statistics *stats;
-		stats = (void *)&pkt->data;
-		flag = &stats->flag;
-		common = &stats->general.common;
-		rx_non_phy = &stats->rx.general.common;
-		rx_ofdm = &stats->rx.ofdm;
-		rx_ofdm_ht = &stats->rx.ofdm_ht;
-		rx_cck = &stats->rx.cck;
-		tx = &stats->tx;
-		bt_activity = &stats->general.activity;
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-		/* handle this exception directly */
-		priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills;
-		le32_add_cpu(&priv->statistics.accum_num_bt_kills,
-			     le32_to_cpu(stats->rx.general.num_bt_kills));
-#endif
-	} else if (len == sizeof(struct iwl_notif_statistics)) {
-		struct iwl_notif_statistics *stats;
-		stats = (void *)&pkt->data;
-		flag = &stats->flag;
-		common = &stats->general.common;
-		rx_non_phy = &stats->rx.general;
-		rx_ofdm = &stats->rx.ofdm;
-		rx_ofdm_ht = &stats->rx.ofdm_ht;
-		rx_cck = &stats->rx.cck;
-		tx = &stats->tx;
-		bt_activity = NULL;
-	} else {
-		WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n",
-			  len, sizeof(struct iwl_bt_notif_statistics),
-			  sizeof(struct iwl_notif_statistics));
-		spin_unlock(&priv->statistics.lock);
-		return 0;
-	}
-
-	change = common->temperature != priv->statistics.common.temperature ||
-		 (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
-		 (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK);
-
-	iwlagn_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm,
-				    rx_ofdm_ht, rx_cck, tx, bt_activity);
-
-	iwlagn_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp);
-
-	priv->statistics.flag = *flag;
-	memcpy(&priv->statistics.common, common, sizeof(*common));
-	memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy));
-	memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm));
-	memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht));
-	memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck));
-	memcpy(&priv->statistics.tx, tx, sizeof(*tx));
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-	if (bt_activity)
-		memcpy(&priv->statistics.bt_activity, bt_activity,
-			sizeof(*bt_activity));
-#endif
-
-	priv->rx_statistics_jiffies = stamp;
-
-	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)) {
-		iwlagn_rx_calc_noise(priv);
-		queue_work(priv->workqueue, &priv->run_time_calib_work);
-	}
-	if (priv->lib->temperature && change)
-		priv->lib->temperature(priv);
-
-	spin_unlock(&priv->statistics.lock);
-
-	return 0;
-}
-
-static int iwlagn_rx_reply_statistics(struct iwl_priv *priv,
-				    struct iwl_rx_cmd_buffer *rxb,
-				    struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_notif_statistics *stats = (void *)pkt->data;
-
-	if (le32_to_cpu(stats->flag) & UCODE_STATISTICS_CLEAR_MSK) {
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-		memset(&priv->accum_stats, 0,
-			sizeof(priv->accum_stats));
-		memset(&priv->delta_stats, 0,
-			sizeof(priv->delta_stats));
-		memset(&priv->max_delta_stats, 0,
-			sizeof(priv->max_delta_stats));
-#endif
-		IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
-	}
-	iwlagn_rx_statistics(priv, rxb, cmd);
-	return 0;
-}
-
-/* Handle notification from uCode that card's power state is changing
- * due to software, hardware, or critical temperature RFKILL */
-static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,
-				    struct iwl_rx_cmd_buffer *rxb,
-				    struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_card_state_notif *card_state_notif = (void *)pkt->data;
-	u32 flags = le32_to_cpu(card_state_notif->flags);
-	unsigned long status = priv->status;
-
-	IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n",
-			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
-			  (flags & SW_CARD_DISABLED) ? "Kill" : "On",
-			  (flags & CT_CARD_DISABLED) ?
-			  "Reached" : "Not reached");
-
-	if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
-		     CT_CARD_DISABLED)) {
-
-		iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
-			    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
-		iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C,
-					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
-
-		if (!(flags & RXON_CARD_DISABLED)) {
-			iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
-				    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-			iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C,
-					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
-		}
-		if (flags & CT_CARD_DISABLED)
-			iwl_tt_enter_ct_kill(priv);
-	}
-	if (!(flags & CT_CARD_DISABLED))
-		iwl_tt_exit_ct_kill(priv);
-
-	if (flags & HW_CARD_DISABLED)
-		set_bit(STATUS_RF_KILL_HW, &priv->status);
-	else
-		clear_bit(STATUS_RF_KILL_HW, &priv->status);
-
-
-	if (!(flags & RXON_CARD_DISABLED))
-		iwl_scan_cancel(priv);
-
-	if ((test_bit(STATUS_RF_KILL_HW, &status) !=
-	     test_bit(STATUS_RF_KILL_HW, &priv->status)))
-		wiphy_rfkill_set_hw_state(priv->hw->wiphy,
-			test_bit(STATUS_RF_KILL_HW, &priv->status));
-	else
-		wake_up(&priv->trans->wait_command_queue);
-	return 0;
-}
-
-static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv,
-				       struct iwl_rx_cmd_buffer *rxb,
-				       struct iwl_device_cmd *cmd)
-
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_missed_beacon_notif *missed_beacon = (void *)pkt->data;
-
-	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);
-	}
-	return 0;
-}
-
-/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
- * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
-static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
-				struct iwl_rx_cmd_buffer *rxb,
-				struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-
-	priv->last_phy_res_valid = true;
-	memcpy(&priv->last_phy_res, pkt->data,
-	       sizeof(struct iwl_rx_phy_res));
-	return 0;
-}
-
-/*
- * returns non-zero if packet should be dropped
- */
-static int iwlagn_set_decrypted_flag(struct iwl_priv *priv,
-				  struct ieee80211_hdr *hdr,
-				  u32 decrypt_res,
-				  struct ieee80211_rx_status *stats)
-{
-	u16 fc = le16_to_cpu(hdr->frame_control);
-
-	/*
-	 * All contexts have the same setting here due to it being
-	 * a module parameter, so OK to check any context.
-	 */
-	if (priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags &
-						RXON_FILTER_DIS_DECRYPT_MSK)
-		return 0;
-
-	if (!(fc & IEEE80211_FCTL_PROTECTED))
-		return 0;
-
-	IWL_DEBUG_RX(priv, "decrypt_res:0x%x\n", decrypt_res);
-	switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
-	case RX_RES_STATUS_SEC_TYPE_TKIP:
-		/* The uCode has got a bad phase 1 Key, pushes the packet.
-		 * Decryption will be done in SW. */
-		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
-		    RX_RES_STATUS_BAD_KEY_TTAK)
-			break;
-
-	case RX_RES_STATUS_SEC_TYPE_WEP:
-		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
-		    RX_RES_STATUS_BAD_ICV_MIC) {
-			/* bad ICV, the packet is destroyed since the
-			 * decryption is inplace, drop it */
-			IWL_DEBUG_RX(priv, "Packet destroyed\n");
-			return -1;
-		}
-	case RX_RES_STATUS_SEC_TYPE_CCMP:
-		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
-		    RX_RES_STATUS_DECRYPT_OK) {
-			IWL_DEBUG_RX(priv, "hw decrypt successfully!!!\n");
-			stats->flag |= RX_FLAG_DECRYPTED;
-		}
-		break;
-
-	default:
-		break;
-	}
-	return 0;
-}
-
-static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
-					struct ieee80211_hdr *hdr,
-					u16 len,
-					u32 ampdu_status,
-					struct iwl_rx_cmd_buffer *rxb,
-					struct ieee80211_rx_status *stats)
-{
-	struct sk_buff *skb;
-	__le16 fc = hdr->frame_control;
-	struct iwl_rxon_context *ctx;
-	unsigned int hdrlen, fraglen;
-
-	/* We only process data packets if the interface is open */
-	if (unlikely(!priv->is_open)) {
-		IWL_DEBUG_DROP_LIMIT(priv,
-		    "Dropping packet while interface is not open.\n");
-		return;
-	}
-
-	/* In case of HW accelerated crypto and bad decryption, drop */
-	if (!iwlwifi_mod_params.sw_crypto &&
-	    iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats))
-		return;
-
-	/* Dont use dev_alloc_skb(), we'll have enough headroom once
-	 * ieee80211_hdr pulled.
-	 */
-	skb = alloc_skb(128, GFP_ATOMIC);
-	if (!skb) {
-		IWL_ERR(priv, "alloc_skb failed\n");
-		return;
-	}
-	/* If frame is small enough to fit in skb->head, pull it completely.
-	 * If not, only pull ieee80211_hdr so that splice() or TCP coalesce
-	 * are more efficient.
-	 */
-	hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr);
-
-	memcpy(skb_put(skb, hdrlen), hdr, hdrlen);
-	fraglen = len - hdrlen;
-
-	if (fraglen) {
-		int offset = (void *)hdr + hdrlen -
-			     rxb_addr(rxb) + rxb_offset(rxb);
-
-		skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
-				fraglen, rxb->truesize);
-	}
-
-	/*
-	* Wake any queues that were stopped due to a passive channel tx
-	* failure. This can happen because the regulatory enforcement in
-	* the device waits for a beacon before allowing transmission,
-	* sometimes even after already having transmitted frames for the
-	* association because the new RXON may reset the information.
-	*/
-	if (unlikely(ieee80211_is_beacon(fc) && priv->passive_no_rx)) {
-		for_each_context(priv, ctx) {
-			if (!ether_addr_equal(hdr->addr3,
-					      ctx->active.bssid_addr))
-				continue;
-			iwlagn_lift_passive_no_rx(priv);
-		}
-	}
-
-	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
-
-	ieee80211_rx(priv->hw, skb);
-}
-
-static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
-{
-	u32 decrypt_out = 0;
-
-	if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
-					RX_RES_STATUS_STATION_FOUND)
-		decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
-				RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
-
-	decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
-
-	/* packet was not encrypted */
-	if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
-					RX_RES_STATUS_SEC_TYPE_NONE)
-		return decrypt_out;
-
-	/* packet was encrypted with unknown alg */
-	if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
-					RX_RES_STATUS_SEC_TYPE_ERR)
-		return decrypt_out;
-
-	/* decryption was not done in HW */
-	if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
-					RX_MPDU_RES_STATUS_DEC_DONE_MSK)
-		return decrypt_out;
-
-	switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
-
-	case RX_RES_STATUS_SEC_TYPE_CCMP:
-		/* alg is CCM: check MIC only */
-		if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
-			/* Bad MIC */
-			decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
-		else
-			decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
-
-		break;
-
-	case RX_RES_STATUS_SEC_TYPE_TKIP:
-		if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
-			/* Bad TTAK */
-			decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
-			break;
-		}
-		/* fall through if TTAK OK */
-	default:
-		if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
-			decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
-		else
-			decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
-		break;
-	}
-
-	IWL_DEBUG_RX(priv, "decrypt_in:0x%x  decrypt_out = 0x%x\n",
-					decrypt_in, decrypt_out);
-
-	return decrypt_out;
-}
-
-/* Calc max signal level (dBm) among 3 possible receivers */
-static int iwlagn_calc_rssi(struct iwl_priv *priv,
-			     struct iwl_rx_phy_res *rx_resp)
-{
-	/* data from PHY/DSP regarding signal strength, etc.,
-	 *   contents are always there, not configurable by host
-	 */
-	struct iwlagn_non_cfg_phy *ncphy =
-		(struct iwlagn_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
-	u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
-	u8 agc;
-
-	val  = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_AGC_IDX]);
-	agc = (val & IWLAGN_OFDM_AGC_MSK) >> IWLAGN_OFDM_AGC_BIT_POS;
-
-	/* Find max rssi among 3 possible receivers.
-	 * These values are measured by the digital signal processor (DSP).
-	 * They should stay fairly constant even as the signal strength varies,
-	 *   if the radio's automatic gain control (AGC) is working right.
-	 * AGC value (see below) will provide the "interesting" info.
-	 */
-	val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_AB_IDX]);
-	rssi_a = (val & IWLAGN_OFDM_RSSI_INBAND_A_BITMSK) >>
-		IWLAGN_OFDM_RSSI_A_BIT_POS;
-	rssi_b = (val & IWLAGN_OFDM_RSSI_INBAND_B_BITMSK) >>
-		IWLAGN_OFDM_RSSI_B_BIT_POS;
-	val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_C_IDX]);
-	rssi_c = (val & IWLAGN_OFDM_RSSI_INBAND_C_BITMSK) >>
-		IWLAGN_OFDM_RSSI_C_BIT_POS;
-
-	max_rssi = max_t(u32, rssi_a, rssi_b);
-	max_rssi = max_t(u32, max_rssi, rssi_c);
-
-	IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
-		rssi_a, rssi_b, rssi_c, max_rssi, agc);
-
-	/* dBm = max_rssi dB - agc dB - constant.
-	 * Higher AGC (higher radio gain) means lower signal. */
-	return max_rssi - agc - IWLAGN_RSSI_OFFSET;
-}
-
-/* Called for REPLY_RX (legacy ABG frames), or
- * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
-static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
-			    struct iwl_rx_cmd_buffer *rxb,
-			    struct iwl_device_cmd *cmd)
-{
-	struct ieee80211_hdr *header;
-	struct ieee80211_rx_status rx_status;
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_rx_phy_res *phy_res;
-	__le32 rx_pkt_status;
-	struct iwl_rx_mpdu_res_start *amsdu;
-	u32 len;
-	u32 ampdu_status;
-	u32 rate_n_flags;
-
-	/**
-	 * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
-	 *	REPLY_RX: physical layer info is in this buffer
-	 *	REPLY_RX_MPDU_CMD: physical layer info was sent in separate
-	 *		command and cached in priv->last_phy_res
-	 *
-	 * Here we set up local variables depending on which command is
-	 * received.
-	 */
-	if (pkt->hdr.cmd == REPLY_RX) {
-		phy_res = (struct iwl_rx_phy_res *)pkt->data;
-		header = (struct ieee80211_hdr *)(pkt->data + sizeof(*phy_res)
-				+ phy_res->cfg_phy_cnt);
-
-		len = le16_to_cpu(phy_res->byte_count);
-		rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*phy_res) +
-				phy_res->cfg_phy_cnt + len);
-		ampdu_status = le32_to_cpu(rx_pkt_status);
-	} else {
-		if (!priv->last_phy_res_valid) {
-			IWL_ERR(priv, "MPDU frame without cached PHY data\n");
-			return 0;
-		}
-		phy_res = &priv->last_phy_res;
-		amsdu = (struct iwl_rx_mpdu_res_start *)pkt->data;
-		header = (struct ieee80211_hdr *)(pkt->data + sizeof(*amsdu));
-		len = le16_to_cpu(amsdu->byte_count);
-		rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*amsdu) + len);
-		ampdu_status = iwlagn_translate_rx_status(priv,
-						le32_to_cpu(rx_pkt_status));
-	}
-
-	if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
-		IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d\n",
-				phy_res->cfg_phy_cnt);
-		return 0;
-	}
-
-	if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
-	    !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
-		IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
-				le32_to_cpu(rx_pkt_status));
-		return 0;
-	}
-
-	/* This will be used in several places later */
-	rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
-
-	/* rx_status carries information about the packet to mac80211 */
-	rx_status.mactime = le64_to_cpu(phy_res->timestamp);
-	rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
-				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
-	rx_status.freq =
-		ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel),
-					       rx_status.band);
-	rx_status.rate_idx =
-		iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
-	rx_status.flag = 0;
-
-	/* TSF isn't reliable. In order to allow smooth user experience,
-	 * this W/A doesn't propagate it to the mac80211 */
-	/*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/
-
-	priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
-
-	/* Find max signal strength (dBm) among 3 antenna/receiver chains */
-	rx_status.signal = iwlagn_calc_rssi(priv, phy_res);
-
-	IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n",
-		rx_status.signal, (unsigned long long)rx_status.mactime);
-
-	/*
-	 * "antenna number"
-	 *
-	 * It seems that the antenna field in the phy flags value
-	 * is actually a bit field. This is undefined by radiotap,
-	 * it wants an actual antenna number but I always get "7"
-	 * for most legacy frames I receive indicating that the
-	 * same frame was received on all three RX chains.
-	 *
-	 * I think this field should be removed in favor of a
-	 * new 802.11n radiotap field "RX chains" that is defined
-	 * as a bitmask.
-	 */
-	rx_status.antenna =
-		(le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK)
-		>> RX_RES_PHY_FLAGS_ANTENNA_POS;
-
-	/* set the preamble flag if appropriate */
-	if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
-		rx_status.flag |= RX_FLAG_SHORTPRE;
-
-	/* Set up the HT phy flags */
-	if (rate_n_flags & RATE_MCS_HT_MSK)
-		rx_status.flag |= RX_FLAG_HT;
-	if (rate_n_flags & RATE_MCS_HT40_MSK)
-		rx_status.flag |= RX_FLAG_40MHZ;
-	if (rate_n_flags & RATE_MCS_SGI_MSK)
-		rx_status.flag |= RX_FLAG_SHORT_GI;
-
-	iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status,
-				    rxb, &rx_status);
-	return 0;
-}
-
-static int iwlagn_rx_noa_notification(struct iwl_priv *priv,
-				      struct iwl_rx_cmd_buffer *rxb,
-				      struct iwl_device_cmd *cmd)
-{
-	struct iwl_wipan_noa_data *new_data, *old_data;
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->data;
-
-	/* no condition -- we're in softirq */
-	old_data = rcu_dereference_protected(priv->noa_data, true);
-
-	if (noa_notif->noa_active) {
-		u32 len = le16_to_cpu(noa_notif->noa_attribute.length);
-		u32 copylen = len;
-
-		/* EID, len, OUI, subtype */
-		len += 1 + 1 + 3 + 1;
-		/* P2P id, P2P length */
-		len += 1 + 2;
-		copylen += 1 + 2;
-
-		new_data = kmalloc(sizeof(*new_data) + len, GFP_ATOMIC);
-		if (new_data) {
-			new_data->length = len;
-			new_data->data[0] = WLAN_EID_VENDOR_SPECIFIC;
-			new_data->data[1] = len - 2; /* not counting EID, len */
-			new_data->data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
-			new_data->data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
-			new_data->data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
-			new_data->data[5] = WLAN_OUI_TYPE_WFA_P2P;
-			memcpy(&new_data->data[6], &noa_notif->noa_attribute,
-			       copylen);
-		}
-	} else
-		new_data = NULL;
-
-	rcu_assign_pointer(priv->noa_data, new_data);
-
-	if (old_data)
-		kfree_rcu(old_data, rcu_head);
-
-	return 0;
-}
-
-/**
- * iwl_setup_rx_handlers - Initialize Rx handler callbacks
- *
- * Setup the RX handlers for each of the reply types sent from the uCode
- * to the host.
- */
-void iwl_setup_rx_handlers(struct iwl_priv *priv)
-{
-	int (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-			       struct iwl_device_cmd *cmd);
-
-	handlers = priv->rx_handlers;
-
-	handlers[REPLY_ERROR]			= iwlagn_rx_reply_error;
-	handlers[CHANNEL_SWITCH_NOTIFICATION]	= iwlagn_rx_csa;
-	handlers[SPECTRUM_MEASURE_NOTIFICATION]	=
-		iwlagn_rx_spectrum_measure_notif;
-	handlers[PM_SLEEP_NOTIFICATION]		= iwlagn_rx_pm_sleep_notif;
-	handlers[PM_DEBUG_STATISTIC_NOTIFIC]	=
-		iwlagn_rx_pm_debug_statistics_notif;
-	handlers[BEACON_NOTIFICATION]		= iwlagn_rx_beacon_notif;
-	handlers[REPLY_ADD_STA]			= iwl_add_sta_callback;
-
-	handlers[REPLY_WIPAN_NOA_NOTIFICATION]	= iwlagn_rx_noa_notification;
-
-	/*
-	 * The same handler is used for both the REPLY to a discrete
-	 * statistics request from the host as well as for the periodic
-	 * statistics notifications (after received beacons) from the uCode.
-	 */
-	handlers[REPLY_STATISTICS_CMD]		= iwlagn_rx_reply_statistics;
-	handlers[STATISTICS_NOTIFICATION]	= iwlagn_rx_statistics;
-
-	iwl_setup_rx_scan_handlers(priv);
-
-	handlers[CARD_STATE_NOTIFICATION]	= iwlagn_rx_card_state_notif;
-	handlers[MISSED_BEACONS_NOTIFICATION]	=
-		iwlagn_rx_missed_beacon_notif;
-
-	/* Rx handlers */
-	handlers[REPLY_RX_PHY_CMD]		= iwlagn_rx_reply_rx_phy;
-	handlers[REPLY_RX_MPDU_CMD]		= iwlagn_rx_reply_rx;
-
-	/* block ack */
-	handlers[REPLY_COMPRESSED_BA]		=
-		iwlagn_rx_reply_compressed_ba;
-
-	priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
-
-	/* set up notification wait support */
-	iwl_notification_wait_init(&priv->notif_wait);
-
-	/* Set up BT Rx handlers */
-	if (priv->cfg->bt_params)
-		iwlagn_bt_rx_handler_setup(priv);
-}
-
-int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
-		    struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-	void (*pre_rx_handler)(struct iwl_priv *,
-			       struct iwl_rx_cmd_buffer *);
-	int err = 0;
-
-	/*
-	 * Do the notification wait before RX handlers so
-	 * even if the RX handler consumes the RXB we have
-	 * access to it in the notification wait entry.
-	 */
-	iwl_notification_wait_notify(&priv->notif_wait, pkt);
-
-	/* RX data may be forwarded to userspace (using pre_rx_handler) in one
-	 * of two cases: the first, that the user owns the uCode through
-	 * testmode - in such case the pre_rx_handler is set and no further
-	 * processing takes place. The other case is when the user want to
-	 * monitor the rx w/o affecting the regular flow - the pre_rx_handler
-	 * will be set but the ownership flag != IWL_OWNERSHIP_TM and the flow
-	 * continues.
-	 * We need to use ACCESS_ONCE to prevent a case where the handler
-	 * changes between the check and the call.
-	 */
-	pre_rx_handler = ACCESS_ONCE(priv->pre_rx_handler);
-	if (pre_rx_handler)
-		pre_rx_handler(priv, rxb);
-	if (priv->ucode_owner != IWL_OWNERSHIP_TM) {
-		/* Based on type of command response or notification,
-		 *   handle those that need handling via function in
-		 *   rx_handlers table.  See iwl_setup_rx_handlers() */
-		if (priv->rx_handlers[pkt->hdr.cmd]) {
-			priv->rx_handlers_stats[pkt->hdr.cmd]++;
-			err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd);
-		} else {
-			/* No handling needed */
-			IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n",
-				     iwl_dvm_get_cmd_string(pkt->hdr.cmd),
-				     pkt->hdr.cmd);
-		}
-	}
-	return err;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
deleted file mode 100644
index 0a3aa7c..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ /dev/null
@@ -1,1593 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 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.
- *
- * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/etherdevice.h>
-#include "iwl-dev.h"
-#include "iwl-agn.h"
-#include "iwl-agn-calib.h"
-#include "iwl-trans.h"
-#include "iwl-modparams.h"
-
-/*
- * initialize rxon structure with default values from eeprom
- */
-void iwl_connection_init_rx_config(struct iwl_priv *priv,
-				   struct iwl_rxon_context *ctx)
-{
-	const struct iwl_channel_info *ch_info;
-
-	memset(&ctx->staging, 0, sizeof(ctx->staging));
-
-	if (!ctx->vif) {
-		ctx->staging.dev_type = ctx->unused_devtype;
-	} else
-	switch (ctx->vif->type) {
-	case NL80211_IFTYPE_AP:
-		ctx->staging.dev_type = ctx->ap_devtype;
-		break;
-
-	case NL80211_IFTYPE_STATION:
-		ctx->staging.dev_type = ctx->station_devtype;
-		ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
-		break;
-
-	case NL80211_IFTYPE_ADHOC:
-		ctx->staging.dev_type = ctx->ibss_devtype;
-		ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
-		ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
-						  RXON_FILTER_ACCEPT_GRP_MSK;
-		break;
-
-	case NL80211_IFTYPE_MONITOR:
-		ctx->staging.dev_type = RXON_DEV_TYPE_SNIFFER;
-		break;
-
-	default:
-		IWL_ERR(priv, "Unsupported interface type %d\n",
-			ctx->vif->type);
-		break;
-	}
-
-#if 0
-	/* TODO:  Figure out when short_preamble would be set and cache from
-	 * that */
-	if (!hw_to_local(priv->hw)->short_preamble)
-		ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
-	else
-		ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
-#endif
-
-	ch_info = iwl_get_channel_info(priv, priv->band,
-				       le16_to_cpu(ctx->active.channel));
-
-	if (!ch_info)
-		ch_info = &priv->channel_info[0];
-
-	ctx->staging.channel = cpu_to_le16(ch_info->channel);
-	priv->band = ch_info->band;
-
-	iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
-
-	/* clear both MIX and PURE40 mode flag */
-	ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
-					RXON_FLG_CHANNEL_MODE_PURE_40);
-	if (ctx->vif)
-		memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);
-
-	ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff;
-	ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff;
-	ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff;
-}
-
-static int iwlagn_disable_bss(struct iwl_priv *priv,
-			      struct iwl_rxon_context *ctx,
-			      struct iwl_rxon_cmd *send)
-{
-	__le32 old_filter = send->filter_flags;
-	int ret;
-
-	send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
-				CMD_SYNC, sizeof(*send), send);
-
-	send->filter_flags = old_filter;
-
-	if (ret)
-		IWL_DEBUG_QUIET_RFKILL(priv,
-			"Error clearing ASSOC_MSK on BSS (%d)\n", ret);
-
-	return ret;
-}
-
-static int iwlagn_disable_pan(struct iwl_priv *priv,
-			      struct iwl_rxon_context *ctx,
-			      struct iwl_rxon_cmd *send)
-{
-	struct iwl_notification_wait disable_wait;
-	__le32 old_filter = send->filter_flags;
-	u8 old_dev_type = send->dev_type;
-	int ret;
-	static const u8 deactivate_cmd[] = {
-		REPLY_WIPAN_DEACTIVATION_COMPLETE
-	};
-
-	iwl_init_notification_wait(&priv->notif_wait, &disable_wait,
-				   deactivate_cmd, ARRAY_SIZE(deactivate_cmd),
-				   NULL, NULL);
-
-	send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	send->dev_type = RXON_DEV_TYPE_P2P;
-	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
-				CMD_SYNC, sizeof(*send), send);
-
-	send->filter_flags = old_filter;
-	send->dev_type = old_dev_type;
-
-	if (ret) {
-		IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
-		iwl_remove_notification(&priv->notif_wait, &disable_wait);
-	} else {
-		ret = iwl_wait_notification(&priv->notif_wait,
-					    &disable_wait, HZ);
-		if (ret)
-			IWL_ERR(priv, "Timed out waiting for PAN disable\n");
-	}
-
-	return ret;
-}
-
-static int iwlagn_disconn_pan(struct iwl_priv *priv,
-			      struct iwl_rxon_context *ctx,
-			      struct iwl_rxon_cmd *send)
-{
-	__le32 old_filter = send->filter_flags;
-	int ret;
-
-	send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
-				sizeof(*send), send);
-
-	send->filter_flags = old_filter;
-
-	return ret;
-}
-
-void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-	int ret;
-
-	if (!ctx->is_active)
-		return;
-
-	ctx->qos_data.def_qos_parm.qos_flags = 0;
-
-	if (ctx->qos_data.qos_active)
-		ctx->qos_data.def_qos_parm.qos_flags |=
-			QOS_PARAM_FLG_UPDATE_EDCA_MSK;
-
-	if (ctx->ht.enabled)
-		ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
-
-	IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
-		      ctx->qos_data.qos_active,
-		      ctx->qos_data.def_qos_parm.qos_flags);
-
-	ret = iwl_dvm_send_cmd_pdu(priv, ctx->qos_cmd, CMD_SYNC,
-			       sizeof(struct iwl_qosparam_cmd),
-			       &ctx->qos_data.def_qos_parm);
-	if (ret)
-		IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
-}
-
-int iwlagn_update_beacon(struct iwl_priv *priv,
-			 struct ieee80211_vif *vif)
-{
-	lockdep_assert_held(&priv->mutex);
-
-	dev_kfree_skb(priv->beacon_skb);
-	priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif);
-	if (!priv->beacon_skb)
-		return -ENOMEM;
-	return iwlagn_send_beacon_cmd(priv);
-}
-
-static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
-			   struct iwl_rxon_context *ctx)
-{
-	int ret = 0;
-	struct iwl_rxon_assoc_cmd rxon_assoc;
-	const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
-	const struct iwl_rxon_cmd *rxon2 = &ctx->active;
-
-	if ((rxon1->flags == rxon2->flags) &&
-	    (rxon1->filter_flags == rxon2->filter_flags) &&
-	    (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
-	    (rxon1->ofdm_ht_single_stream_basic_rates ==
-	     rxon2->ofdm_ht_single_stream_basic_rates) &&
-	    (rxon1->ofdm_ht_dual_stream_basic_rates ==
-	     rxon2->ofdm_ht_dual_stream_basic_rates) &&
-	    (rxon1->ofdm_ht_triple_stream_basic_rates ==
-	     rxon2->ofdm_ht_triple_stream_basic_rates) &&
-	    (rxon1->acquisition_data == rxon2->acquisition_data) &&
-	    (rxon1->rx_chain == rxon2->rx_chain) &&
-	    (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
-		IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC.  Not resending.\n");
-		return 0;
-	}
-
-	rxon_assoc.flags = ctx->staging.flags;
-	rxon_assoc.filter_flags = ctx->staging.filter_flags;
-	rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
-	rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
-	rxon_assoc.reserved1 = 0;
-	rxon_assoc.reserved2 = 0;
-	rxon_assoc.reserved3 = 0;
-	rxon_assoc.ofdm_ht_single_stream_basic_rates =
-	    ctx->staging.ofdm_ht_single_stream_basic_rates;
-	rxon_assoc.ofdm_ht_dual_stream_basic_rates =
-	    ctx->staging.ofdm_ht_dual_stream_basic_rates;
-	rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
-	rxon_assoc.ofdm_ht_triple_stream_basic_rates =
-		 ctx->staging.ofdm_ht_triple_stream_basic_rates;
-	rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
-
-	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_assoc_cmd,
-				CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc);
-	return ret;
-}
-
-static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
-{
-	u16 new_val;
-	u16 beacon_factor;
-
-	/*
-	 * If mac80211 hasn't given us a beacon interval, program
-	 * the default into the device (not checking this here
-	 * would cause the adjustment below to return the maximum
-	 * value, which may break PAN.)
-	 */
-	if (!beacon_val)
-		return DEFAULT_BEACON_INTERVAL;
-
-	/*
-	 * If the beacon interval we obtained from the peer
-	 * is too large, we'll have to wake up more often
-	 * (and in IBSS case, we'll beacon too much)
-	 *
-	 * For example, if max_beacon_val is 4096, and the
-	 * requested beacon interval is 7000, we'll have to
-	 * use 3500 to be able to wake up on the beacons.
-	 *
-	 * This could badly influence beacon detection stats.
-	 */
-
-	beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
-	new_val = beacon_val / beacon_factor;
-
-	if (!new_val)
-		new_val = max_beacon_val;
-
-	return new_val;
-}
-
-static int iwl_send_rxon_timing(struct iwl_priv *priv,
-				struct iwl_rxon_context *ctx)
-{
-	u64 tsf;
-	s32 interval_tm, rem;
-	struct ieee80211_conf *conf = NULL;
-	u16 beacon_int;
-	struct ieee80211_vif *vif = ctx->vif;
-
-	conf = &priv->hw->conf;
-
-	lockdep_assert_held(&priv->mutex);
-
-	memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));
-
-	ctx->timing.timestamp = cpu_to_le64(priv->timestamp);
-	ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval);
-
-	beacon_int = vif ? vif->bss_conf.beacon_int : 0;
-
-	/*
-	 * TODO: For IBSS we need to get atim_window from mac80211,
-	 *	 for now just always use 0
-	 */
-	ctx->timing.atim_window = 0;
-
-	if (ctx->ctxid == IWL_RXON_CTX_PAN &&
-	    (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) &&
-	    iwl_is_associated(priv, IWL_RXON_CTX_BSS) &&
-	    priv->contexts[IWL_RXON_CTX_BSS].vif &&
-	    priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) {
-		ctx->timing.beacon_interval =
-			priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval;
-		beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
-	} else if (ctx->ctxid == IWL_RXON_CTX_BSS &&
-		   iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
-		   priv->contexts[IWL_RXON_CTX_PAN].vif &&
-		   priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int &&
-		   (!iwl_is_associated_ctx(ctx) || !ctx->vif ||
-		    !ctx->vif->bss_conf.beacon_int)) {
-		ctx->timing.beacon_interval =
-			priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval;
-		beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
-	} else {
-		beacon_int = iwl_adjust_beacon_interval(beacon_int,
-			IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT);
-		ctx->timing.beacon_interval = cpu_to_le16(beacon_int);
-	}
-
-	ctx->beacon_int = beacon_int;
-
-	tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
-	interval_tm = beacon_int * TIME_UNIT;
-	rem = do_div(tsf, interval_tm);
-	ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
-
-	ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1;
-
-	IWL_DEBUG_ASSOC(priv,
-			"beacon interval %d beacon timer %d beacon tim %d\n",
-			le16_to_cpu(ctx->timing.beacon_interval),
-			le32_to_cpu(ctx->timing.beacon_init_val),
-			le16_to_cpu(ctx->timing.atim_window));
-
-	return iwl_dvm_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
-				CMD_SYNC, sizeof(ctx->timing), &ctx->timing);
-}
-
-static int iwlagn_rxon_disconn(struct iwl_priv *priv,
-			       struct iwl_rxon_context *ctx)
-{
-	int ret;
-	struct iwl_rxon_cmd *active = (void *)&ctx->active;
-
-	if (ctx->ctxid == IWL_RXON_CTX_BSS) {
-		ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
-	} else {
-		ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
-		if (ret)
-			return ret;
-		if (ctx->vif) {
-			ret = iwl_send_rxon_timing(priv, ctx);
-			if (ret) {
-				IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
-				return ret;
-			}
-			ret = iwlagn_disconn_pan(priv, ctx, &ctx->staging);
-		}
-	}
-	if (ret)
-		return ret;
-
-	/*
-	 * Un-assoc RXON clears the station table and WEP
-	 * keys, so we have to restore those afterwards.
-	 */
-	iwl_clear_ucode_stations(priv, ctx);
-	/* update -- might need P2P now */
-	iwl_update_bcast_station(priv, ctx);
-	iwl_restore_stations(priv, ctx);
-	ret = iwl_restore_default_wep_keys(priv, ctx);
-	if (ret) {
-		IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
-		return ret;
-	}
-
-	memcpy(active, &ctx->staging, sizeof(*active));
-	return 0;
-}
-
-static int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
-{
-	int ret;
-	s8 prev_tx_power;
-	bool defer;
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-
-	if (priv->calib_disabled & IWL_TX_POWER_CALIB_DISABLED)
-		return 0;
-
-	lockdep_assert_held(&priv->mutex);
-
-	if (priv->tx_power_user_lmt == tx_power && !force)
-		return 0;
-
-	if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
-		IWL_WARN(priv,
-			 "Requested user TXPOWER %d below lower limit %d.\n",
-			 tx_power,
-			 IWLAGN_TX_POWER_TARGET_POWER_MIN);
-		return -EINVAL;
-	}
-
-	if (tx_power > priv->tx_power_device_lmt) {
-		IWL_WARN(priv,
-			"Requested user TXPOWER %d above upper limit %d.\n",
-			 tx_power, priv->tx_power_device_lmt);
-		return -EINVAL;
-	}
-
-	if (!iwl_is_ready_rf(priv))
-		return -EIO;
-
-	/* scan complete and commit_rxon use tx_power_next value,
-	 * it always need to be updated for newest request */
-	priv->tx_power_next = tx_power;
-
-	/* do not set tx power when scanning or channel changing */
-	defer = test_bit(STATUS_SCANNING, &priv->status) ||
-		memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
-	if (defer && !force) {
-		IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
-		return 0;
-	}
-
-	prev_tx_power = priv->tx_power_user_lmt;
-	priv->tx_power_user_lmt = tx_power;
-
-	ret = iwlagn_send_tx_power(priv);
-
-	/* if fail to set tx_power, restore the orig. tx power */
-	if (ret) {
-		priv->tx_power_user_lmt = prev_tx_power;
-		priv->tx_power_next = prev_tx_power;
-	}
-	return ret;
-}
-
-static int iwlagn_rxon_connect(struct iwl_priv *priv,
-			       struct iwl_rxon_context *ctx)
-{
-	int ret;
-	struct iwl_rxon_cmd *active = (void *)&ctx->active;
-
-	/* RXON timing must be before associated RXON */
-	if (ctx->ctxid == IWL_RXON_CTX_BSS) {
-		ret = iwl_send_rxon_timing(priv, ctx);
-		if (ret) {
-			IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
-			return ret;
-		}
-	}
-	/* QoS info may be cleared by previous un-assoc RXON */
-	iwlagn_update_qos(priv, ctx);
-
-	/*
-	 * We'll run into this code path when beaconing is
-	 * enabled, but then we also need to send the beacon
-	 * to the device.
-	 */
-	if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
-		ret = iwlagn_update_beacon(priv, ctx->vif);
-		if (ret) {
-			IWL_ERR(priv,
-				"Error sending required beacon (%d)!\n",
-				ret);
-			return ret;
-		}
-	}
-
-	priv->start_calib = 0;
-	/*
-	 * Apply the new configuration.
-	 *
-	 * Associated RXON doesn't clear the station table in uCode,
-	 * so we don't need to restore stations etc. after this.
-	 */
-	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
-		      sizeof(struct iwl_rxon_cmd), &ctx->staging);
-	if (ret) {
-		IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
-		return ret;
-	}
-	memcpy(active, &ctx->staging, sizeof(*active));
-
-	/* IBSS beacon needs to be sent after setting assoc */
-	if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
-		if (iwlagn_update_beacon(priv, ctx->vif))
-			IWL_ERR(priv, "Error sending IBSS beacon\n");
-	iwl_init_sensitivity(priv);
-
-	/*
-	 * If we issue a new RXON command which required a tune then
-	 * we must send a new TXPOWER command or we won't be able to
-	 * Tx any frames.
-	 *
-	 * It's expected we set power here if channel is changing.
-	 */
-	ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
-	if (ret) {
-		IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
-		return ret;
-	}
-
-	if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
-	    priv->cfg->ht_params && priv->cfg->ht_params->smps_mode)
-		ieee80211_request_smps(ctx->vif,
-				       priv->cfg->ht_params->smps_mode);
-
-	return 0;
-}
-
-int iwlagn_set_pan_params(struct iwl_priv *priv)
-{
-	struct iwl_wipan_params_cmd cmd;
-	struct iwl_rxon_context *ctx_bss, *ctx_pan;
-	int slot0 = 300, slot1 = 0;
-	int ret;
-
-	if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS))
-		return 0;
-
-	BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-
-	lockdep_assert_held(&priv->mutex);
-
-	ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
-	ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
-
-	/*
-	 * If the PAN context is inactive, then we don't need
-	 * to update the PAN parameters, the last thing we'll
-	 * have done before it goes inactive is making the PAN
-	 * parameters be WLAN-only.
-	 */
-	if (!ctx_pan->is_active)
-		return 0;
-
-	memset(&cmd, 0, sizeof(cmd));
-
-	/* only 2 slots are currently allowed */
-	cmd.num_slots = 2;
-
-	cmd.slots[0].type = 0; /* BSS */
-	cmd.slots[1].type = 1; /* PAN */
-
-	if (priv->hw_roc_setup) {
-		/* both contexts must be used for this to happen */
-		slot1 = IWL_MIN_SLOT_TIME;
-		slot0 = 3000;
-	} else if (ctx_bss->vif && ctx_pan->vif) {
-		int bcnint = ctx_pan->beacon_int;
-		int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1;
-
-		/* should be set, but seems unused?? */
-		cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE);
-
-		if (ctx_pan->vif->type == NL80211_IFTYPE_AP &&
-		    bcnint &&
-		    bcnint != ctx_bss->beacon_int) {
-			IWL_ERR(priv,
-				"beacon intervals don't match (%d, %d)\n",
-				ctx_bss->beacon_int, ctx_pan->beacon_int);
-		} else
-			bcnint = max_t(int, bcnint,
-				       ctx_bss->beacon_int);
-		if (!bcnint)
-			bcnint = DEFAULT_BEACON_INTERVAL;
-		slot0 = bcnint / 2;
-		slot1 = bcnint - slot0;
-
-		if (test_bit(STATUS_SCAN_HW, &priv->status) ||
-		    (!ctx_bss->vif->bss_conf.idle &&
-		     !ctx_bss->vif->bss_conf.assoc)) {
-			slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
-			slot1 = IWL_MIN_SLOT_TIME;
-		} else if (!ctx_pan->vif->bss_conf.idle &&
-			   !ctx_pan->vif->bss_conf.assoc) {
-			slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
-			slot0 = IWL_MIN_SLOT_TIME;
-		}
-	} else if (ctx_pan->vif) {
-		slot0 = 0;
-		slot1 = max_t(int, 1, ctx_pan->vif->bss_conf.dtim_period) *
-					ctx_pan->beacon_int;
-		slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1);
-
-		if (test_bit(STATUS_SCAN_HW, &priv->status)) {
-			slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME;
-			slot1 = IWL_MIN_SLOT_TIME;
-		}
-	}
-
-	cmd.slots[0].width = cpu_to_le16(slot0);
-	cmd.slots[1].width = cpu_to_le16(slot1);
-
-	ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, CMD_SYNC,
-			sizeof(cmd), &cmd);
-	if (ret)
-		IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
-
-	return ret;
-}
-
-static void _iwl_set_rxon_ht(struct iwl_priv *priv,
-			     struct iwl_ht_config *ht_conf,
-			     struct iwl_rxon_context *ctx)
-{
-	struct iwl_rxon_cmd *rxon = &ctx->staging;
-
-	if (!ctx->ht.enabled) {
-		rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
-			RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
-			RXON_FLG_HT40_PROT_MSK |
-			RXON_FLG_HT_PROT_MSK);
-		return;
-	}
-
-	/* FIXME: if the definition of ht.protection changed, the "translation"
-	 * will be needed for rxon->flags
-	 */
-	rxon->flags |= cpu_to_le32(ctx->ht.protection <<
-				   RXON_FLG_HT_OPERATING_MODE_POS);
-
-	/* Set up channel bandwidth:
-	 * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
-	/* clear the HT channel mode before set the mode */
-	rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
-			 RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
-	if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) {
-		/* pure ht40 */
-		if (ctx->ht.protection ==
-		    IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
-			rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
-			/*
-			 * Note: control channel is opposite of extension
-			 * channel
-			 */
-			switch (ctx->ht.extension_chan_offset) {
-			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-				rxon->flags &=
-					~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
-				break;
-			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-				rxon->flags |=
-					RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
-				break;
-			}
-		} else {
-			/*
-			 * Note: control channel is opposite of extension
-			 * channel
-			 */
-			switch (ctx->ht.extension_chan_offset) {
-			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-				rxon->flags &=
-					~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
-				rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
-				break;
-			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-				rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
-				rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
-				break;
-			case IEEE80211_HT_PARAM_CHA_SEC_NONE:
-			default:
-				/*
-				 * channel location only valid if in Mixed
-				 * mode
-				 */
-				IWL_ERR(priv,
-					"invalid extension channel offset\n");
-				break;
-			}
-		}
-	} else {
-		rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
-	}
-
-	iwlagn_set_rxon_chain(priv, ctx);
-
-	IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
-			"extension channel offset 0x%x\n",
-			le32_to_cpu(rxon->flags), ctx->ht.protection,
-			ctx->ht.extension_chan_offset);
-}
-
-void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
-{
-	struct iwl_rxon_context *ctx;
-
-	for_each_context(priv, ctx)
-		_iwl_set_rxon_ht(priv, ht_conf, ctx);
-}
-
-/**
- * iwl_set_rxon_channel - Set the band and channel values in staging RXON
- * @ch: requested channel as a pointer to struct ieee80211_channel
-
- * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
- * in the staging RXON flag structure based on the ch->band
- */
-void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
-			 struct iwl_rxon_context *ctx)
-{
-	enum ieee80211_band band = ch->band;
-	u16 channel = ch->hw_value;
-
-	if ((le16_to_cpu(ctx->staging.channel) == channel) &&
-	    (priv->band == band))
-		return;
-
-	ctx->staging.channel = cpu_to_le16(channel);
-	if (band == IEEE80211_BAND_5GHZ)
-		ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK;
-	else
-		ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
-
-	priv->band = band;
-
-	IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band);
-
-}
-
-void iwl_set_flags_for_band(struct iwl_priv *priv,
-			    struct iwl_rxon_context *ctx,
-			    enum ieee80211_band band,
-			    struct ieee80211_vif *vif)
-{
-	if (band == IEEE80211_BAND_5GHZ) {
-		ctx->staging.flags &=
-		    ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
-		      | RXON_FLG_CCK_MSK);
-		ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
-	} else {
-		/* Copied from iwl_post_associate() */
-		if (vif && vif->bss_conf.use_short_slot)
-			ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
-		else
-			ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
-		ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
-		ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK;
-		ctx->staging.flags &= ~RXON_FLG_CCK_MSK;
-	}
-}
-
-static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv,
-				  struct iwl_rxon_context *ctx, int hw_decrypt)
-{
-	struct iwl_rxon_cmd *rxon = &ctx->staging;
-
-	if (hw_decrypt)
-		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
-	else
-		rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
-
-}
-
-/* validate RXON structure is valid */
-static int iwl_check_rxon_cmd(struct iwl_priv *priv,
-			      struct iwl_rxon_context *ctx)
-{
-	struct iwl_rxon_cmd *rxon = &ctx->staging;
-	u32 errors = 0;
-
-	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
-		if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) {
-			IWL_WARN(priv, "check 2.4G: wrong narrow\n");
-			errors |= BIT(0);
-		}
-		if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) {
-			IWL_WARN(priv, "check 2.4G: wrong radar\n");
-			errors |= BIT(1);
-		}
-	} else {
-		if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) {
-			IWL_WARN(priv, "check 5.2G: not short slot!\n");
-			errors |= BIT(2);
-		}
-		if (rxon->flags & RXON_FLG_CCK_MSK) {
-			IWL_WARN(priv, "check 5.2G: CCK!\n");
-			errors |= BIT(3);
-		}
-	}
-	if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) {
-		IWL_WARN(priv, "mac/bssid mcast!\n");
-		errors |= BIT(4);
-	}
-
-	/* make sure basic rates 6Mbps and 1Mbps are supported */
-	if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 &&
-	    (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) {
-		IWL_WARN(priv, "neither 1 nor 6 are basic\n");
-		errors |= BIT(5);
-	}
-
-	if (le16_to_cpu(rxon->assoc_id) > 2007) {
-		IWL_WARN(priv, "aid > 2007\n");
-		errors |= BIT(6);
-	}
-
-	if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
-			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) {
-		IWL_WARN(priv, "CCK and short slot\n");
-		errors |= BIT(7);
-	}
-
-	if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
-			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) {
-		IWL_WARN(priv, "CCK and auto detect");
-		errors |= BIT(8);
-	}
-
-	if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
-			    RXON_FLG_TGG_PROTECT_MSK)) ==
-			    RXON_FLG_TGG_PROTECT_MSK) {
-		IWL_WARN(priv, "TGg but no auto-detect\n");
-		errors |= BIT(9);
-	}
-
-	if (rxon->channel == 0) {
-		IWL_WARN(priv, "zero channel is invalid\n");
-		errors |= BIT(10);
-	}
-
-	WARN(errors, "Invalid RXON (%#x), channel %d",
-	     errors, le16_to_cpu(rxon->channel));
-
-	return errors ? -EINVAL : 0;
-}
-
-/**
- * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
- * @priv: staging_rxon is compared to active_rxon
- *
- * If the RXON structure is changing enough to require a new tune,
- * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
- * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
- */
-int iwl_full_rxon_required(struct iwl_priv *priv,
-			   struct iwl_rxon_context *ctx)
-{
-	const struct iwl_rxon_cmd *staging = &ctx->staging;
-	const struct iwl_rxon_cmd *active = &ctx->active;
-
-#define CHK(cond)							\
-	if ((cond)) {							\
-		IWL_DEBUG_INFO(priv, "need full RXON - " #cond "\n");	\
-		return 1;						\
-	}
-
-#define CHK_NEQ(c1, c2)						\
-	if ((c1) != (c2)) {					\
-		IWL_DEBUG_INFO(priv, "need full RXON - "	\
-			       #c1 " != " #c2 " - %d != %d\n",	\
-			       (c1), (c2));			\
-		return 1;					\
-	}
-
-	/* These items are only settable from the full RXON command */
-	CHK(!iwl_is_associated_ctx(ctx));
-	CHK(!ether_addr_equal(staging->bssid_addr, active->bssid_addr));
-	CHK(!ether_addr_equal(staging->node_addr, active->node_addr));
-	CHK(!ether_addr_equal(staging->wlap_bssid_addr,
-			      active->wlap_bssid_addr));
-	CHK_NEQ(staging->dev_type, active->dev_type);
-	CHK_NEQ(staging->channel, active->channel);
-	CHK_NEQ(staging->air_propagation, active->air_propagation);
-	CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates,
-		active->ofdm_ht_single_stream_basic_rates);
-	CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates,
-		active->ofdm_ht_dual_stream_basic_rates);
-	CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates,
-		active->ofdm_ht_triple_stream_basic_rates);
-	CHK_NEQ(staging->assoc_id, active->assoc_id);
-
-	/* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
-	 * be updated with the RXON_ASSOC command -- however only some
-	 * flag transitions are allowed using RXON_ASSOC */
-
-	/* Check if we are not switching bands */
-	CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK,
-		active->flags & RXON_FLG_BAND_24G_MSK);
-
-	/* Check if we are switching association toggle */
-	CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK,
-		active->filter_flags & RXON_FILTER_ASSOC_MSK);
-
-#undef CHK
-#undef CHK_NEQ
-
-	return 0;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv,
-			     enum iwl_rxon_context_id ctxid)
-{
-	struct iwl_rxon_context *ctx = &priv->contexts[ctxid];
-	struct iwl_rxon_cmd *rxon = &ctx->staging;
-
-	IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
-	iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
-	IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n",
-			le16_to_cpu(rxon->channel));
-	IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n",
-			le32_to_cpu(rxon->flags));
-	IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
-			le32_to_cpu(rxon->filter_flags));
-	IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type);
-	IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n",
-			rxon->ofdm_basic_rates);
-	IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n",
-			rxon->cck_basic_rates);
-	IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr);
-	IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
-	IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n",
-			le16_to_cpu(rxon->assoc_id));
-}
-#endif
-
-static void iwl_calc_basic_rates(struct iwl_priv *priv,
-				 struct iwl_rxon_context *ctx)
-{
-	int lowest_present_ofdm = 100;
-	int lowest_present_cck = 100;
-	u8 cck = 0;
-	u8 ofdm = 0;
-
-	if (ctx->vif) {
-		struct ieee80211_supported_band *sband;
-		unsigned long basic = ctx->vif->bss_conf.basic_rates;
-		int i;
-
-		sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
-
-		for_each_set_bit(i, &basic, BITS_PER_LONG) {
-			int hw = sband->bitrates[i].hw_value;
-			if (hw >= IWL_FIRST_OFDM_RATE) {
-				ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE);
-				if (lowest_present_ofdm > hw)
-					lowest_present_ofdm = hw;
-			} else {
-				BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
-
-				cck |= BIT(hw);
-				if (lowest_present_cck > hw)
-					lowest_present_cck = hw;
-			}
-		}
-	}
-
-	/*
-	 * Now we've got the basic rates as bitmaps in the ofdm and cck
-	 * variables. This isn't sufficient though, as there might not
-	 * be all the right rates in the bitmap. E.g. if the only basic
-	 * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps
-	 * and 6 Mbps because the 802.11-2007 standard says in 9.6:
-	 *
-	 *    [...] a STA responding to a received frame shall transmit
-	 *    its Control Response frame [...] at the highest rate in the
-	 *    BSSBasicRateSet parameter that is less than or equal to the
-	 *    rate of the immediately previous frame in the frame exchange
-	 *    sequence ([...]) and that is of the same modulation class
-	 *    ([...]) as the received frame. If no rate contained in the
-	 *    BSSBasicRateSet parameter meets these conditions, then the
-	 *    control frame sent in response to a received frame shall be
-	 *    transmitted at the highest mandatory rate of the PHY that is
-	 *    less than or equal to the rate of the received frame, and
-	 *    that is of the same modulation class as the received frame.
-	 *
-	 * As a consequence, we need to add all mandatory rates that are
-	 * lower than all of the basic rates to these bitmaps.
-	 */
-
-	if (IWL_RATE_24M_INDEX < lowest_present_ofdm)
-		ofdm |= IWL_RATE_24M_MASK >> IWL_FIRST_OFDM_RATE;
-	if (IWL_RATE_12M_INDEX < lowest_present_ofdm)
-		ofdm |= IWL_RATE_12M_MASK >> IWL_FIRST_OFDM_RATE;
-	/* 6M already there or needed so always add */
-	ofdm |= IWL_RATE_6M_MASK >> IWL_FIRST_OFDM_RATE;
-
-	/*
-	 * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP.
-	 * Note, however:
-	 *  - if no CCK rates are basic, it must be ERP since there must
-	 *    be some basic rates at all, so they're OFDM => ERP PHY
-	 *    (or we're in 5 GHz, and the cck bitmap will never be used)
-	 *  - if 11M is a basic rate, it must be ERP as well, so add 5.5M
-	 *  - if 5.5M is basic, 1M and 2M are mandatory
-	 *  - if 2M is basic, 1M is mandatory
-	 *  - if 1M is basic, that's the only valid ACK rate.
-	 * As a consequence, it's not as complicated as it sounds, just add
-	 * any lower rates to the ACK rate bitmap.
-	 */
-	if (IWL_RATE_11M_INDEX < lowest_present_ofdm)
-		ofdm |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE;
-	if (IWL_RATE_5M_INDEX < lowest_present_ofdm)
-		ofdm |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE;
-	if (IWL_RATE_2M_INDEX < lowest_present_ofdm)
-		ofdm |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE;
-	/* 1M already there or needed so always add */
-	cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE;
-
-	IWL_DEBUG_RATE(priv, "Set basic rates cck:0x%.2x ofdm:0x%.2x\n",
-		       cck, ofdm);
-
-	/* "basic_rates" is a misnomer here -- should be called ACK rates */
-	ctx->staging.cck_basic_rates = cck;
-	ctx->staging.ofdm_basic_rates = ofdm;
-}
-
-/**
- * iwlagn_commit_rxon - commit staging_rxon to hardware
- *
- * The RXON command in staging_rxon is committed to the hardware and
- * the active_rxon structure is updated with the new data.  This
- * function correctly transitions out of the RXON_ASSOC_MSK state if
- * a HW tune is required based on the RXON structure changes.
- *
- * The connect/disconnect flow should be as the following:
- *
- * 1. make sure send RXON command with association bit unset if not connect
- *	this should include the channel and the band for the candidate
- *	to be connected to
- * 2. Add Station before RXON association with the AP
- * 3. RXON_timing has to send before RXON for connection
- * 4. full RXON command - associated bit set
- * 5. use RXON_ASSOC command to update any flags changes
- */
-int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-	/* cast away the const for active_rxon in this function */
-	struct iwl_rxon_cmd *active = (void *)&ctx->active;
-	bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
-	int ret;
-
-	lockdep_assert_held(&priv->mutex);
-
-	if (!iwl_is_alive(priv))
-		return -EBUSY;
-
-	/* This function hardcodes a bunch of dual-mode assumptions */
-	BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-
-	if (!ctx->is_active)
-		return 0;
-
-	/* always get timestamp with Rx frame */
-	ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
-
-	/* recalculate basic rates */
-	iwl_calc_basic_rates(priv, ctx);
-
-	/*
-	 * force CTS-to-self frames protection if RTS-CTS is not preferred
-	 * one aggregation protection method
-	 */
-	if (!priv->hw_params.use_rts_for_aggregation)
-		ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
-
-	if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
-	    !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
-		ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
-	else
-		ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
-	iwl_print_rx_config_cmd(priv, ctx->ctxid);
-	ret = iwl_check_rxon_cmd(priv, ctx);
-	if (ret) {
-		IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
-		return -EINVAL;
-	}
-
-	/*
-	 * receive commit_rxon request
-	 * abort any previous channel switch if still in process
-	 */
-	if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) &&
-	    (priv->switch_channel != ctx->staging.channel)) {
-		IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
-			      le16_to_cpu(priv->switch_channel));
-		iwl_chswitch_done(priv, false);
-	}
-
-	/*
-	 * If we don't need to send a full RXON, we can use
-	 * iwl_rxon_assoc_cmd which is used to reconfigure filter
-	 * and other flags for the current radio configuration.
-	 */
-	if (!iwl_full_rxon_required(priv, ctx)) {
-		ret = iwlagn_send_rxon_assoc(priv, ctx);
-		if (ret) {
-			IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
-			return ret;
-		}
-
-		memcpy(active, &ctx->staging, sizeof(*active));
-		/*
-		 * We do not commit tx power settings while channel changing,
-		 * do it now if after settings changed.
-		 */
-		iwl_set_tx_power(priv, priv->tx_power_next, false);
-
-		/* make sure we are in the right PS state */
-		iwl_power_update_mode(priv, true);
-
-		return 0;
-	}
-
-	iwl_set_rxon_hwcrypto(priv, ctx, !iwlwifi_mod_params.sw_crypto);
-
-	IWL_DEBUG_INFO(priv,
-		       "Going to commit RXON\n"
-		       "  * with%s RXON_FILTER_ASSOC_MSK\n"
-		       "  * channel = %d\n"
-		       "  * bssid = %pM\n",
-		       (new_assoc ? "" : "out"),
-		       le16_to_cpu(ctx->staging.channel),
-		       ctx->staging.bssid_addr);
-
-	/*
-	 * Always clear associated first, but with the correct config.
-	 * This is required as for example station addition for the
-	 * AP station must be done after the BSSID is set to correctly
-	 * set up filters in the device.
-	 */
-	ret = iwlagn_rxon_disconn(priv, ctx);
-	if (ret)
-		return ret;
-
-	ret = iwlagn_set_pan_params(priv);
-	if (ret)
-		return ret;
-
-	if (new_assoc)
-		return iwlagn_rxon_connect(priv, ctx);
-
-	return 0;
-}
-
-void iwlagn_config_ht40(struct ieee80211_conf *conf,
-	struct iwl_rxon_context *ctx)
-{
-	if (conf_is_ht40_minus(conf)) {
-		ctx->ht.extension_chan_offset =
-			IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-		ctx->ht.is_40mhz = true;
-	} else if (conf_is_ht40_plus(conf)) {
-		ctx->ht.extension_chan_offset =
-			IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-		ctx->ht.is_40mhz = true;
-	} else {
-		ctx->ht.extension_chan_offset =
-			IEEE80211_HT_PARAM_CHA_SEC_NONE;
-		ctx->ht.is_40mhz = false;
-	}
-}
-
-int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_rxon_context *ctx;
-	struct ieee80211_conf *conf = &hw->conf;
-	struct ieee80211_channel *channel = conf->channel;
-	const struct iwl_channel_info *ch_info;
-	int ret = 0;
-
-	IWL_DEBUG_MAC80211(priv, "enter: changed %#x\n", changed);
-
-	mutex_lock(&priv->mutex);
-
-	if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
-		IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
-		goto out;
-	}
-
-	if (!iwl_is_ready(priv)) {
-		IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
-		goto out;
-	}
-
-	if (changed & (IEEE80211_CONF_CHANGE_SMPS |
-		       IEEE80211_CONF_CHANGE_CHANNEL)) {
-		/* mac80211 uses static for non-HT which is what we want */
-		priv->current_ht_config.smps = conf->smps_mode;
-
-		/*
-		 * Recalculate chain counts.
-		 *
-		 * If monitor mode is enabled then mac80211 will
-		 * set up the SM PS mode to OFF if an HT channel is
-		 * configured.
-		 */
-		for_each_context(priv, ctx)
-			iwlagn_set_rxon_chain(priv, ctx);
-	}
-
-	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-		ch_info = iwl_get_channel_info(priv, channel->band,
-					       channel->hw_value);
-		if (!is_channel_valid(ch_info)) {
-			IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
-			ret = -EINVAL;
-			goto out;
-		}
-
-		for_each_context(priv, ctx) {
-			/* Configure HT40 channels */
-			if (ctx->ht.enabled != conf_is_ht(conf))
-				ctx->ht.enabled = conf_is_ht(conf);
-
-			if (ctx->ht.enabled) {
-				/* if HT40 is used, it should not change
-				 * after associated except channel switch */
-				if (!ctx->ht.is_40mhz ||
-						!iwl_is_associated_ctx(ctx))
-					iwlagn_config_ht40(conf, ctx);
-			} else
-				ctx->ht.is_40mhz = false;
-
-			/*
-			 * Default to no protection. Protection mode will
-			 * later be set from BSS config in iwl_ht_conf
-			 */
-			ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
-
-			/* 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(ctx->staging.channel) !=
-			    channel->hw_value)
-				ctx->staging.flags = 0;
-
-			iwl_set_rxon_channel(priv, channel, ctx);
-			iwl_set_rxon_ht(priv, &priv->current_ht_config);
-
-			iwl_set_flags_for_band(priv, ctx, channel->band,
-					       ctx->vif);
-		}
-
-		iwl_update_bcast_stations(priv);
-	}
-
-	if (changed & (IEEE80211_CONF_CHANGE_PS |
-			IEEE80211_CONF_CHANGE_IDLE)) {
-		ret = iwl_power_update_mode(priv, false);
-		if (ret)
-			IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
-	}
-
-	if (changed & IEEE80211_CONF_CHANGE_POWER) {
-		IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
-			priv->tx_power_user_lmt, conf->power_level);
-
-		iwl_set_tx_power(priv, conf->power_level, false);
-	}
-
-	for_each_context(priv, ctx) {
-		if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
-			continue;
-		iwlagn_commit_rxon(priv, ctx);
-	}
- out:
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-
-	return ret;
-}
-
-void iwlagn_check_needed_chains(struct iwl_priv *priv,
-				struct iwl_rxon_context *ctx,
-				struct ieee80211_bss_conf *bss_conf)
-{
-	struct ieee80211_vif *vif = ctx->vif;
-	struct iwl_rxon_context *tmp;
-	struct ieee80211_sta *sta;
-	struct iwl_ht_config *ht_conf = &priv->current_ht_config;
-	struct ieee80211_sta_ht_cap *ht_cap;
-	bool need_multiple;
-
-	lockdep_assert_held(&priv->mutex);
-
-	switch (vif->type) {
-	case NL80211_IFTYPE_STATION:
-		rcu_read_lock();
-		sta = ieee80211_find_sta(vif, bss_conf->bssid);
-		if (!sta) {
-			/*
-			 * If at all, this can only happen through a race
-			 * when the AP disconnects us while we're still
-			 * setting up the connection, in that case mac80211
-			 * will soon tell us about that.
-			 */
-			need_multiple = false;
-			rcu_read_unlock();
-			break;
-		}
-
-		ht_cap = &sta->ht_cap;
-
-		need_multiple = true;
-
-		/*
-		 * If the peer advertises no support for receiving 2 and 3
-		 * stream MCS rates, it can't be transmitting them either.
-		 */
-		if (ht_cap->mcs.rx_mask[1] == 0 &&
-		    ht_cap->mcs.rx_mask[2] == 0) {
-			need_multiple = false;
-		} else if (!(ht_cap->mcs.tx_params &
-						IEEE80211_HT_MCS_TX_DEFINED)) {
-			/* If it can't TX MCS at all ... */
-			need_multiple = false;
-		} else if (ht_cap->mcs.tx_params &
-						IEEE80211_HT_MCS_TX_RX_DIFF) {
-			int maxstreams;
-
-			/*
-			 * But if it can receive them, it might still not
-			 * be able to transmit them, which is what we need
-			 * to check here -- so check the number of streams
-			 * it advertises for TX (if different from RX).
-			 */
-
-			maxstreams = (ht_cap->mcs.tx_params &
-				 IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK);
-			maxstreams >>=
-				IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
-			maxstreams += 1;
-
-			if (maxstreams <= 1)
-				need_multiple = false;
-		}
-
-		rcu_read_unlock();
-		break;
-	case NL80211_IFTYPE_ADHOC:
-		/* currently */
-		need_multiple = false;
-		break;
-	default:
-		/* only AP really */
-		need_multiple = true;
-		break;
-	}
-
-	ctx->ht_need_multiple_chains = need_multiple;
-
-	if (!need_multiple) {
-		/* check all contexts */
-		for_each_context(priv, tmp) {
-			if (!tmp->vif)
-				continue;
-			if (tmp->ht_need_multiple_chains) {
-				need_multiple = true;
-				break;
-			}
-		}
-	}
-
-	ht_conf->single_chain_sufficient = !need_multiple;
-}
-
-void iwlagn_chain_noise_reset(struct iwl_priv *priv)
-{
-	struct iwl_chain_noise_data *data = &priv->chain_noise_data;
-	int ret;
-
-	if (!(priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED))
-		return;
-
-	if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
-	    iwl_is_any_associated(priv)) {
-		struct iwl_calib_chain_noise_reset_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));
-		iwl_set_calib_hdr(&cmd.hdr,
-			priv->phy_calib_chain_noise_reset_cmd);
-		ret = iwl_dvm_send_cmd_pdu(priv,
-					REPLY_PHY_CALIBRATION_CMD,
-					CMD_SYNC, sizeof(cmd), &cmd);
-		if (ret)
-			IWL_ERR(priv,
-				"Could not send REPLY_PHY_CALIBRATION_CMD\n");
-		data->state = IWL_CHAIN_NOISE_ACCUMULATE;
-		IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
-	}
-}
-
-void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
-			     struct ieee80211_vif *vif,
-			     struct ieee80211_bss_conf *bss_conf,
-			     u32 changes)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-	int ret;
-	bool force = false;
-
-	mutex_lock(&priv->mutex);
-
-	if (unlikely(!iwl_is_ready(priv))) {
-		IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
-		mutex_unlock(&priv->mutex);
-		return;
-        }
-
-	if (unlikely(!ctx->vif)) {
-		IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n");
-		mutex_unlock(&priv->mutex);
-		return;
-	}
-
-	if (changes & BSS_CHANGED_BEACON_INT)
-		force = true;
-
-	if (changes & BSS_CHANGED_QOS) {
-		ctx->qos_data.qos_active = bss_conf->qos;
-		iwlagn_update_qos(priv, ctx);
-	}
-
-	ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
-	if (vif->bss_conf.use_short_preamble)
-		ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
-	else
-		ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
-
-	if (changes & BSS_CHANGED_ASSOC) {
-		if (bss_conf->assoc) {
-			priv->timestamp = bss_conf->last_tsf;
-			ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
-		} else {
-			/*
-			 * If we disassociate while there are pending
-			 * frames, just wake up the queues and let the
-			 * frames "escape" ... This shouldn't really
-			 * be happening to start with, but we should
-			 * not get stuck in this case either since it
-			 * can happen if userspace gets confused.
-			 */
-			iwlagn_lift_passive_no_rx(priv);
-
-			ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-
-			if (ctx->ctxid == IWL_RXON_CTX_BSS)
-				priv->have_rekey_data = false;
-		}
-
-		iwlagn_bt_coex_rssi_monitor(priv);
-	}
-
-	if (ctx->ht.enabled) {
-		ctx->ht.protection = bss_conf->ht_operation_mode &
-					IEEE80211_HT_OP_MODE_PROTECTION;
-		ctx->ht.non_gf_sta_present = !!(bss_conf->ht_operation_mode &
-					IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-		iwlagn_check_needed_chains(priv, ctx, bss_conf);
-		iwl_set_rxon_ht(priv, &priv->current_ht_config);
-	}
-
-	iwlagn_set_rxon_chain(priv, ctx);
-
-	if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
-		ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
-	else
-		ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
-
-	if (bss_conf->use_cts_prot)
-		ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
-	else
-		ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
-
-	memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN);
-
-	if (vif->type == NL80211_IFTYPE_AP ||
-	    vif->type == NL80211_IFTYPE_ADHOC) {
-		if (vif->bss_conf.enable_beacon) {
-			ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
-			priv->beacon_ctx = ctx;
-		} else {
-			ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-			priv->beacon_ctx = NULL;
-		}
-	}
-
-	/*
-	 * If the ucode decides to do beacon filtering before
-	 * association, it will lose beacons that are needed
-	 * before sending frames out on passive channels. This
-	 * causes association failures on those channels. Enable
-	 * receiving beacons in such cases.
-	 */
-
-	if (vif->type == NL80211_IFTYPE_STATION) {
-		if (!bss_conf->assoc)
-			ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
-		else
-			ctx->staging.filter_flags &=
-						    ~RXON_FILTER_BCON_AWARE_MSK;
-	}
-
-	if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
-		iwlagn_commit_rxon(priv, ctx);
-
-	if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) {
-		/*
-		 * The chain noise calibration will enable PM upon
-		 * completion. If calibration has already been run
-		 * then we need to enable power management here.
-		 */
-		if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
-			iwl_power_update_mode(priv, false);
-
-		/* Enable RX differential gain and sensitivity calibrations */
-		iwlagn_chain_noise_reset(priv);
-		priv->start_calib = 1;
-	}
-
-	if (changes & BSS_CHANGED_IBSS) {
-		ret = iwlagn_manage_ibss_station(priv, vif,
-						 bss_conf->ibss_joined);
-		if (ret)
-			IWL_ERR(priv, "failed to %s IBSS station %pM\n",
-				bss_conf->ibss_joined ? "add" : "remove",
-				bss_conf->bssid);
-	}
-
-	if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC &&
-	    priv->beacon_ctx) {
-		if (iwlagn_update_beacon(priv, vif))
-			IWL_ERR(priv, "Error sending IBSS beacon\n");
-	}
-
-	mutex_unlock(&priv->mutex);
-}
-
-void iwlagn_post_scan(struct iwl_priv *priv)
-{
-	struct iwl_rxon_context *ctx;
-
-	/*
-	 * We do not commit power settings while scan is pending,
-	 * do it now if the settings changed.
-	 */
-	iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false);
-	iwl_set_tx_power(priv, priv->tx_power_next, false);
-
-	/*
-	 * Since setting the RXON may have been deferred while
-	 * performing the scan, fire one off if needed
-	 */
-	for_each_context(priv, ctx)
-		if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
-			iwlagn_commit_rxon(priv, ctx);
-
-	iwlagn_set_pan_params(priv);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
deleted file mode 100644
index eb6a8ea..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
+++ /dev/null
@@ -1,1501 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-#include <linux/etherdevice.h>
-#include <net/mac80211.h>
-
-#include "iwl-dev.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-
-const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
-static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
-{
-	lockdep_assert_held(&priv->sta_lock);
-
-	if (sta_id >= IWLAGN_STATION_COUNT) {
-		IWL_ERR(priv, "invalid sta_id %u", sta_id);
-		return -EINVAL;
-	}
-	if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
-		IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u "
-			"addr %pM\n",
-			sta_id, priv->stations[sta_id].sta.sta.addr);
-
-	if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) {
-		IWL_DEBUG_ASSOC(priv,
-				"STA id %u addr %pM already present in uCode "
-				"(according to driver)\n",
-				sta_id, priv->stations[sta_id].sta.sta.addr);
-	} else {
-		priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
-		IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n",
-				sta_id, priv->stations[sta_id].sta.sta.addr);
-	}
-	return 0;
-}
-
-static int iwl_process_add_sta_resp(struct iwl_priv *priv,
-				    struct iwl_addsta_cmd *addsta,
-				    struct iwl_rx_packet *pkt)
-{
-	struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data;
-	u8 sta_id = addsta->sta.sta_id;
-	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 ret;
-	}
-
-	IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
-		       sta_id);
-
-	spin_lock(&priv->sta_lock);
-
-	switch (add_sta_resp->status) {
-	case ADD_STA_SUCCESS_MSK:
-		IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
-		ret = iwl_sta_ucode_activate(priv, sta_id);
-		break;
-	case ADD_STA_NO_ROOM_IN_TABLE:
-		IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
-			sta_id);
-		break;
-	case ADD_STA_NO_BLOCK_ACK_RESOURCE:
-		IWL_ERR(priv, "Adding station %d failed, no block ack "
-			"resource.\n", sta_id);
-		break;
-	case ADD_STA_MODIFY_NON_EXIST_STA:
-		IWL_ERR(priv, "Attempting to modify non-existing station %d\n",
-			sta_id);
-		break;
-	default:
-		IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
-				add_sta_resp->status);
-		break;
-	}
-
-	IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n",
-		       priv->stations[sta_id].sta.mode ==
-		       STA_CONTROL_MODIFY_MSK ?  "Modified" : "Added",
-		       sta_id, priv->stations[sta_id].sta.sta.addr);
-
-	/*
-	 * XXX: The MAC address in the command buffer is often changed from
-	 * the original sent to the device. That is, the MAC address
-	 * written to the command buffer often is not the same MAC address
-	 * read from the command buffer when the command returns. This
-	 * issue has not yet been resolved and this debugging is left to
-	 * observe the problem.
-	 */
-	IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n",
-		       priv->stations[sta_id].sta.mode ==
-		       STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
-		       addsta->sta.addr);
-	spin_unlock(&priv->sta_lock);
-
-	return ret;
-}
-
-int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-			       struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_addsta_cmd *addsta =
-		(struct iwl_addsta_cmd *) cmd->payload;
-
-	return iwl_process_add_sta_resp(priv, addsta, pkt);
-}
-
-int iwl_send_add_sta(struct iwl_priv *priv,
-		     struct iwl_addsta_cmd *sta, u8 flags)
-{
-	int ret = 0;
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_ADD_STA,
-		.flags = flags,
-		.data = { sta, },
-		.len = { sizeof(*sta), },
-	};
-	u8 sta_id __maybe_unused = sta->sta.sta_id;
-
-	IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n",
-		       sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : "");
-
-	if (!(flags & CMD_ASYNC)) {
-		cmd.flags |= CMD_WANT_SKB;
-		might_sleep();
-	}
-
-	ret = iwl_dvm_send_cmd(priv, &cmd);
-
-	if (ret || (flags & CMD_ASYNC))
-		return ret;
-	/*else the command was successfully sent in SYNC mode, need to free
-	 * the reply page */
-
-	iwl_free_resp(&cmd);
-
-	if (cmd.handler_status)
-		IWL_ERR(priv, "%s - error in the CMD response %d", __func__,
-			cmd.handler_status);
-
-	return cmd.handler_status;
-}
-
-static bool iwl_is_channel_extension(struct iwl_priv *priv,
-				     enum ieee80211_band band,
-				     u16 channel, u8 extension_chan_offset)
-{
-	const struct iwl_channel_info *ch_info;
-
-	ch_info = iwl_get_channel_info(priv, band, channel);
-	if (!is_channel_valid(ch_info))
-		return false;
-
-	if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
-		return !(ch_info->ht40_extension_channel &
-					IEEE80211_CHAN_NO_HT40PLUS);
-	else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
-		return !(ch_info->ht40_extension_channel &
-					IEEE80211_CHAN_NO_HT40MINUS);
-
-	return false;
-}
-
-bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
-			    struct iwl_rxon_context *ctx,
-			    struct ieee80211_sta_ht_cap *ht_cap)
-{
-	if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
-		return false;
-
-	/*
-	 * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
-	 * the bit will not set if it is pure 40MHz case
-	 */
-	if (ht_cap && !ht_cap->ht_supported)
-		return false;
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-	if (priv->disable_ht40)
-		return false;
-#endif
-
-	return iwl_is_channel_extension(priv, priv->band,
-			le16_to_cpu(ctx->staging.channel),
-			ctx->ht.extension_chan_offset);
-}
-
-static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
-				  struct ieee80211_sta *sta,
-				  struct iwl_rxon_context *ctx,
-				  __le32 *flags, __le32 *mask)
-{
-	struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
-	u8 mimo_ps_mode;
-
-	*mask = STA_FLG_RTS_MIMO_PROT_MSK |
-		STA_FLG_MIMO_DIS_MSK |
-		STA_FLG_HT40_EN_MSK |
-		STA_FLG_MAX_AGG_SIZE_MSK |
-		STA_FLG_AGG_MPDU_DENSITY_MSK;
-	*flags = 0;
-
-	if (!sta || !sta_ht_inf->ht_supported)
-		return;
-
-	mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
-
-	IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n",
-			(mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
-			"static" :
-			(mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
-			"dynamic" : "disabled");
-
-	switch (mimo_ps_mode) {
-	case WLAN_HT_CAP_SM_PS_STATIC:
-		*flags |= STA_FLG_MIMO_DIS_MSK;
-		break;
-	case WLAN_HT_CAP_SM_PS_DYNAMIC:
-		*flags |= STA_FLG_RTS_MIMO_PROT_MSK;
-		break;
-	case WLAN_HT_CAP_SM_PS_DISABLED:
-		break;
-	default:
-		IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode);
-		break;
-	}
-
-	*flags |= cpu_to_le32(
-		(u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
-
-	*flags |= cpu_to_le32(
-		(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
-
-	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
-		*flags |= STA_FLG_HT40_EN_MSK;
-}
-
-int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-		      struct ieee80211_sta *sta)
-{
-	u8 sta_id = iwl_sta_id(sta);
-	__le32 flags, mask;
-	struct iwl_addsta_cmd cmd;
-
-	if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
-		return -EINVAL;
-
-	iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
-
-	spin_lock_bh(&priv->sta_lock);
-	priv->stations[sta_id].sta.station_flags &= ~mask;
-	priv->stations[sta_id].sta.station_flags |= flags;
-	spin_unlock_bh(&priv->sta_lock);
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.mode = STA_CONTROL_MODIFY_MSK;
-	cmd.station_flags_msk = mask;
-	cmd.station_flags = flags;
-	cmd.sta.sta_id = sta_id;
-
-	return iwl_send_add_sta(priv, &cmd, CMD_SYNC);
-}
-
-static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
-				   struct ieee80211_sta *sta,
-				   struct iwl_rxon_context *ctx)
-{
-	__le32 flags, mask;
-
-	iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
-
-	lockdep_assert_held(&priv->sta_lock);
-	priv->stations[index].sta.station_flags &= ~mask;
-	priv->stations[index].sta.station_flags |= flags;
-}
-
-/**
- * iwl_prep_station - Prepare station information for addition
- *
- * should be called with sta_lock held
- */
-u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-		    const u8 *addr, bool is_ap, struct ieee80211_sta *sta)
-{
-	struct iwl_station_entry *station;
-	int i;
-	u8 sta_id = IWL_INVALID_STATION;
-
-	if (is_ap)
-		sta_id = ctx->ap_sta_id;
-	else if (is_broadcast_ether_addr(addr))
-		sta_id = ctx->bcast_sta_id;
-	else
-		for (i = IWL_STA_ID; i < IWLAGN_STATION_COUNT; i++) {
-			if (ether_addr_equal(priv->stations[i].sta.sta.addr,
-					     addr)) {
-				sta_id = i;
-				break;
-			}
-
-			if (!priv->stations[i].used &&
-			    sta_id == IWL_INVALID_STATION)
-				sta_id = i;
-		}
-
-	/*
-	 * These two conditions have the same outcome, but keep them
-	 * separate
-	 */
-	if (unlikely(sta_id == IWL_INVALID_STATION))
-		return sta_id;
-
-	/*
-	 * uCode is not able to deal with multiple requests to add a
-	 * station. Keep track if one is in progress so that we do not send
-	 * another.
-	 */
-	if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
-		IWL_DEBUG_INFO(priv, "STA %d already in process of being "
-			       "added.\n", sta_id);
-		return sta_id;
-	}
-
-	if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
-	    (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) &&
-	    ether_addr_equal(priv->stations[sta_id].sta.sta.addr, addr)) {
-		IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not "
-				"adding again.\n", sta_id, addr);
-		return sta_id;
-	}
-
-	station = &priv->stations[sta_id];
-	station->used = IWL_STA_DRIVER_ACTIVE;
-	IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n",
-			sta_id, addr);
-	priv->num_stations++;
-
-	/* Set up the REPLY_ADD_STA command to send to device */
-	memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
-	memcpy(station->sta.sta.addr, addr, ETH_ALEN);
-	station->sta.mode = 0;
-	station->sta.sta.sta_id = sta_id;
-	station->sta.station_flags = ctx->station_flags;
-	station->ctxid = ctx->ctxid;
-
-	if (sta) {
-		struct iwl_station_priv *sta_priv;
-
-		sta_priv = (void *)sta->drv_priv;
-		sta_priv->ctx = ctx;
-	}
-
-	/*
-	 * OK to call unconditionally, since local stations (IBSS BSSID
-	 * STA and broadcast STA) pass in a NULL sta, and mac80211
-	 * doesn't allow HT IBSS.
-	 */
-	iwl_set_ht_add_station(priv, sta_id, sta, ctx);
-
-	return sta_id;
-
-}
-
-#define STA_WAIT_TIMEOUT (HZ/2)
-
-/**
- * iwl_add_station_common -
- */
-int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-			   const u8 *addr, bool is_ap,
-			   struct ieee80211_sta *sta, u8 *sta_id_r)
-{
-	int ret = 0;
-	u8 sta_id;
-	struct iwl_addsta_cmd sta_cmd;
-
-	*sta_id_r = 0;
-	spin_lock_bh(&priv->sta_lock);
-	sta_id = iwl_prep_station(priv, ctx, addr, is_ap, sta);
-	if (sta_id == IWL_INVALID_STATION) {
-		IWL_ERR(priv, "Unable to prepare station %pM for addition\n",
-			addr);
-		spin_unlock_bh(&priv->sta_lock);
-		return -EINVAL;
-	}
-
-	/*
-	 * uCode is not able to deal with multiple requests to add a
-	 * station. Keep track if one is in progress so that we do not send
-	 * another.
-	 */
-	if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
-		IWL_DEBUG_INFO(priv, "STA %d already in process of being "
-			       "added.\n", sta_id);
-		spin_unlock_bh(&priv->sta_lock);
-		return -EEXIST;
-	}
-
-	if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
-	    (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
-		IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not "
-				"adding again.\n", sta_id, addr);
-		spin_unlock_bh(&priv->sta_lock);
-		return -EEXIST;
-	}
-
-	priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
-	memcpy(&sta_cmd, &priv->stations[sta_id].sta,
-	       sizeof(struct iwl_addsta_cmd));
-	spin_unlock_bh(&priv->sta_lock);
-
-	/* Add station to device's station table */
-	ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-	if (ret) {
-		spin_lock_bh(&priv->sta_lock);
-		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_bh(&priv->sta_lock);
-	}
-	*sta_id_r = sta_id;
-	return ret;
-}
-
-/**
- * iwl_sta_ucode_deactivate - deactivate ucode status for a station
- */
-static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
-{
-	lockdep_assert_held(&priv->sta_lock);
-
-	/* Ucode must be active and driver must be non active */
-	if ((priv->stations[sta_id].used &
-	     (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) !=
-	      IWL_STA_UCODE_ACTIVE)
-		IWL_ERR(priv, "removed non active STA %u\n", sta_id);
-
-	priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
-
-	memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry));
-	IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id);
-}
-
-static int iwl_send_remove_station(struct iwl_priv *priv,
-				   const u8 *addr, int sta_id,
-				   bool temporary)
-{
-	struct iwl_rx_packet *pkt;
-	int ret;
-	struct iwl_rem_sta_cmd rm_sta_cmd;
-
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_REMOVE_STA,
-		.len = { sizeof(struct iwl_rem_sta_cmd), },
-		.flags = CMD_SYNC,
-		.data = { &rm_sta_cmd, },
-	};
-
-	memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
-	rm_sta_cmd.num_sta = 1;
-	memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
-
-	cmd.flags |= CMD_WANT_SKB;
-
-	ret = iwl_dvm_send_cmd(priv, &cmd);
-
-	if (ret)
-		return ret;
-
-	pkt = cmd.resp_pkt;
-	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
-		IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
-			  pkt->hdr.flags);
-		ret = -EIO;
-	}
-
-	if (!ret) {
-		struct iwl_rem_sta_resp *rem_sta_resp = (void *)pkt->data;
-		switch (rem_sta_resp->status) {
-		case REM_STA_SUCCESS_MSK:
-			if (!temporary) {
-				spin_lock_bh(&priv->sta_lock);
-				iwl_sta_ucode_deactivate(priv, sta_id);
-				spin_unlock_bh(&priv->sta_lock);
-			}
-			IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
-			break;
-		default:
-			ret = -EIO;
-			IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
-			break;
-		}
-	}
-	iwl_free_resp(&cmd);
-
-	return ret;
-}
-
-/**
- * iwl_remove_station - Remove driver's knowledge of station.
- */
-int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
-		       const u8 *addr)
-{
-	u8 tid;
-
-	if (!iwl_is_ready(priv)) {
-		IWL_DEBUG_INFO(priv,
-			"Unable to remove station %pM, device not ready.\n",
-			addr);
-		/*
-		 * It is typical for stations to be removed when we are
-		 * going down. Return success since device will be down
-		 * soon anyway
-		 */
-		return 0;
-	}
-
-	IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d  %pM\n",
-			sta_id, addr);
-
-	if (WARN_ON(sta_id == IWL_INVALID_STATION))
-		return -EINVAL;
-
-	spin_lock_bh(&priv->sta_lock);
-
-	if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
-		IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n",
-				addr);
-		goto out_err;
-	}
-
-	if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
-		IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n",
-				addr);
-		goto out_err;
-	}
-
-	if (priv->stations[sta_id].used & IWL_STA_LOCAL) {
-		kfree(priv->stations[sta_id].lq);
-		priv->stations[sta_id].lq = NULL;
-	}
-
-	for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
-		memset(&priv->tid_data[sta_id][tid], 0,
-			sizeof(priv->tid_data[sta_id][tid]));
-
-	priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
-
-	priv->num_stations--;
-
-	if (WARN_ON(priv->num_stations < 0))
-		priv->num_stations = 0;
-
-	spin_unlock_bh(&priv->sta_lock);
-
-	return iwl_send_remove_station(priv, addr, sta_id, false);
-out_err:
-	spin_unlock_bh(&priv->sta_lock);
-	return -EINVAL;
-}
-
-void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
-			    const u8 *addr)
-{
-	u8 tid;
-
-	if (!iwl_is_ready(priv)) {
-		IWL_DEBUG_INFO(priv,
-			"Unable to remove station %pM, device not ready.\n",
-			addr);
-		return;
-	}
-
-	IWL_DEBUG_ASSOC(priv, "Deactivating STA: %pM (%d)\n", addr, sta_id);
-
-	if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
-		return;
-
-	spin_lock_bh(&priv->sta_lock);
-
-	WARN_ON_ONCE(!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE));
-
-	for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
-		memset(&priv->tid_data[sta_id][tid], 0,
-			sizeof(priv->tid_data[sta_id][tid]));
-
-	priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
-
-	priv->num_stations--;
-
-	if (WARN_ON_ONCE(priv->num_stations < 0))
-		priv->num_stations = 0;
-
-	spin_unlock_bh(&priv->sta_lock);
-}
-
-static void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-			    u8 sta_id, struct iwl_link_quality_cmd *link_cmd)
-{
-	int i, r;
-	u32 rate_flags = 0;
-	__le32 rate_n_flags;
-
-	lockdep_assert_held(&priv->mutex);
-
-	memset(link_cmd, 0, sizeof(*link_cmd));
-
-	/* Set up the rate scaling to start at selected rate, fall back
-	 * all the way down to 1M in IEEE order, and then spin on 1M */
-	if (priv->band == IEEE80211_BAND_5GHZ)
-		r = IWL_RATE_6M_INDEX;
-	else if (ctx && ctx->vif && ctx->vif->p2p)
-		r = IWL_RATE_6M_INDEX;
-	else
-		r = IWL_RATE_1M_INDEX;
-
-	if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
-		rate_flags |= RATE_MCS_CCK_MSK;
-
-	rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
-				RATE_MCS_ANT_POS;
-	rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
-	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
-		link_cmd->rs_table[i].rate_n_flags = rate_n_flags;
-
-	link_cmd->general_params.single_stream_ant_msk =
-			first_antenna(priv->hw_params.valid_tx_ant);
-
-	link_cmd->general_params.dual_stream_ant_msk =
-		priv->hw_params.valid_tx_ant &
-		~first_antenna(priv->hw_params.valid_tx_ant);
-	if (!link_cmd->general_params.dual_stream_ant_msk) {
-		link_cmd->general_params.dual_stream_ant_msk = ANT_AB;
-	} else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
-		link_cmd->general_params.dual_stream_ant_msk =
-			priv->hw_params.valid_tx_ant;
-	}
-
-	link_cmd->agg_params.agg_dis_start_th =
-		LINK_QUAL_AGG_DISABLE_START_DEF;
-	link_cmd->agg_params.agg_time_limit =
-		cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
-
-	link_cmd->sta_id = sta_id;
-}
-
-/**
- * iwl_clear_ucode_stations - clear ucode station table bits
- *
- * This function clears all the bits in the driver indicating
- * which stations are active in the ucode. Call when something
- * other than explicit station management would cause this in
- * the ucode, e.g. unassociated RXON.
- */
-void iwl_clear_ucode_stations(struct iwl_priv *priv,
-			      struct iwl_rxon_context *ctx)
-{
-	int i;
-	bool cleared = false;
-
-	IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n");
-
-	spin_lock_bh(&priv->sta_lock);
-	for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
-		if (ctx && ctx->ctxid != priv->stations[i].ctxid)
-			continue;
-
-		if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
-			IWL_DEBUG_INFO(priv,
-				"Clearing ucode active for station %d\n", i);
-			priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
-			cleared = true;
-		}
-	}
-	spin_unlock_bh(&priv->sta_lock);
-
-	if (!cleared)
-		IWL_DEBUG_INFO(priv,
-			       "No active stations found to be cleared\n");
-}
-
-/**
- * iwl_restore_stations() - Restore driver known stations to device
- *
- * All stations considered active by driver, but not present in ucode, is
- * restored.
- *
- * Function sleeps.
- */
-void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-	struct iwl_addsta_cmd sta_cmd;
-	struct iwl_link_quality_cmd lq;
-	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");
-		return;
-	}
-
-	IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n");
-	spin_lock_bh(&priv->sta_lock);
-	for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
-		if (ctx->ctxid != priv->stations[i].ctxid)
-			continue;
-		if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) &&
-			    !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) {
-			IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n",
-					priv->stations[i].sta.sta.addr);
-			priv->stations[i].sta.mode = 0;
-			priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS;
-			found = true;
-		}
-	}
-
-	for (i = 0; i < IWLAGN_STATION_COUNT; 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) {
-				if (priv->wowlan)
-					iwl_sta_fill_lq(priv, ctx, i, &lq);
-				else
-					memcpy(&lq, priv->stations[i].lq,
-					       sizeof(struct iwl_link_quality_cmd));
-				send_lq = true;
-			}
-			spin_unlock_bh(&priv->sta_lock);
-			ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-			if (ret) {
-				spin_lock_bh(&priv->sta_lock);
-				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;
-				continue;
-			}
-			/*
-			 * Rate scaling has already been initialized, send
-			 * current LQ command
-			 */
-			if (send_lq)
-				iwl_send_lq_cmd(priv, ctx, &lq,
-						CMD_SYNC, true);
-			spin_lock_bh(&priv->sta_lock);
-			priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
-		}
-	}
-
-	spin_unlock_bh(&priv->sta_lock);
-	if (!found)
-		IWL_DEBUG_INFO(priv, "Restoring all known stations .... "
-			"no stations to be restored.\n");
-	else
-		IWL_DEBUG_INFO(priv, "Restoring all known stations .... "
-			"complete.\n");
-}
-
-int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
-{
-	int i;
-
-	for (i = 0; i < priv->sta_key_max_num; i++)
-		if (!test_and_set_bit(i, &priv->ucode_key_table))
-			return i;
-
-	return WEP_INVALID_OFFSET;
-}
-
-void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
-{
-	int i;
-
-	spin_lock_bh(&priv->sta_lock);
-	for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
-		if (!(priv->stations[i].used & IWL_STA_BCAST))
-			continue;
-
-		priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
-		priv->num_stations--;
-		if (WARN_ON(priv->num_stations < 0))
-			priv->num_stations = 0;
-		kfree(priv->stations[i].lq);
-		priv->stations[i].lq = NULL;
-	}
-	spin_unlock_bh(&priv->sta_lock);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static void iwl_dump_lq_cmd(struct iwl_priv *priv,
-			   struct iwl_link_quality_cmd *lq)
-{
-	int i;
-	IWL_DEBUG_RATE(priv, "lq station id 0x%x\n", lq->sta_id);
-	IWL_DEBUG_RATE(priv, "lq ant 0x%X 0x%X\n",
-		       lq->general_params.single_stream_ant_msk,
-		       lq->general_params.dual_stream_ant_msk);
-
-	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
-		IWL_DEBUG_RATE(priv, "lq index %d 0x%X\n",
-			       i, lq->rs_table[i].rate_n_flags);
-}
-#else
-static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
-				   struct iwl_link_quality_cmd *lq)
-{
-}
-#endif
-
-/**
- * is_lq_table_valid() - Test one aspect of LQ cmd for validity
- *
- * It sometimes happens when a HT rate has been in use and we
- * loose connectivity with AP then mac80211 will first tell us that the
- * current channel is not HT anymore before removing the station. In such a
- * scenario the RXON flags will be updated to indicate we are not
- * communicating HT anymore, but the LQ command may still contain HT rates.
- * Test for this to prevent driver from sending LQ command between the time
- * RXON flags are updated and when LQ command is updated.
- */
-static bool is_lq_table_valid(struct iwl_priv *priv,
-			      struct iwl_rxon_context *ctx,
-			      struct iwl_link_quality_cmd *lq)
-{
-	int i;
-
-	if (ctx->ht.enabled)
-		return true;
-
-	IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
-		       ctx->active.channel);
-	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
-		if (le32_to_cpu(lq->rs_table[i].rate_n_flags) &
-		    RATE_MCS_HT_MSK) {
-			IWL_DEBUG_INFO(priv,
-				       "index %d of LQ expects HT channel\n",
-				       i);
-			return false;
-		}
-	}
-	return true;
-}
-
-/**
- * iwl_send_lq_cmd() - Send link quality command
- * @init: This command is sent as part of station initialization right
- *        after station has been added.
- *
- * The link quality command is sent as the last step of station creation.
- * This is the special case in which init is set and we call a callback in
- * this case to clear the state indicating that station creation is in
- * progress.
- */
-int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-		    struct iwl_link_quality_cmd *lq, u8 flags, bool init)
-{
-	int ret = 0;
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_TX_LINK_QUALITY_CMD,
-		.len = { sizeof(struct iwl_link_quality_cmd), },
-		.flags = flags,
-		.data = { lq, },
-	};
-
-	if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
-		return -EINVAL;
-
-
-	spin_lock_bh(&priv->sta_lock);
-	if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
-		spin_unlock_bh(&priv->sta_lock);
-		return -EINVAL;
-	}
-	spin_unlock_bh(&priv->sta_lock);
-
-	iwl_dump_lq_cmd(priv, lq);
-	if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
-		return -EINVAL;
-
-	if (is_lq_table_valid(priv, ctx, lq))
-		ret = iwl_dvm_send_cmd(priv, &cmd);
-	else
-		ret = -EINVAL;
-
-	if (cmd.flags & CMD_ASYNC)
-		return ret;
-
-	if (init) {
-		IWL_DEBUG_INFO(priv, "init LQ command complete, "
-			       "clearing sta addition status for sta %d\n",
-			       lq->sta_id);
-		spin_lock_bh(&priv->sta_lock);
-		priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
-		spin_unlock_bh(&priv->sta_lock);
-	}
-	return ret;
-}
-
-
-static struct iwl_link_quality_cmd *
-iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-		 u8 sta_id)
-{
-	struct iwl_link_quality_cmd *link_cmd;
-
-	link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL);
-	if (!link_cmd) {
-		IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n");
-		return NULL;
-	}
-
-	iwl_sta_fill_lq(priv, ctx, sta_id, link_cmd);
-
-	return link_cmd;
-}
-
-/*
- * iwlagn_add_bssid_station - Add the special IBSS BSSID station
- *
- * Function sleeps.
- */
-int iwlagn_add_bssid_station(struct iwl_priv *priv,
-			     struct iwl_rxon_context *ctx,
-			     const u8 *addr, u8 *sta_id_r)
-{
-	int ret;
-	u8 sta_id;
-	struct iwl_link_quality_cmd *link_cmd;
-
-	if (sta_id_r)
-		*sta_id_r = IWL_INVALID_STATION;
-
-	ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id);
-	if (ret) {
-		IWL_ERR(priv, "Unable to add station %pM\n", addr);
-		return ret;
-	}
-
-	if (sta_id_r)
-		*sta_id_r = sta_id;
-
-	spin_lock_bh(&priv->sta_lock);
-	priv->stations[sta_id].used |= IWL_STA_LOCAL;
-	spin_unlock_bh(&priv->sta_lock);
-
-	/* Set up default rate scaling table in device's station table */
-	link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
-	if (!link_cmd) {
-		IWL_ERR(priv,
-			"Unable to initialize rate scaling for station %pM.\n",
-			addr);
-		return -ENOMEM;
-	}
-
-	ret = iwl_send_lq_cmd(priv, ctx, link_cmd, CMD_SYNC, true);
-	if (ret)
-		IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
-
-	spin_lock_bh(&priv->sta_lock);
-	priv->stations[sta_id].lq = link_cmd;
-	spin_unlock_bh(&priv->sta_lock);
-
-	return 0;
-}
-
-/*
- * static WEP keys
- *
- * For each context, the device has a table of 4 static WEP keys
- * (one for each key index) that is updated with the following
- * commands.
- */
-
-static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
-				      struct iwl_rxon_context *ctx,
-				      bool send_if_empty)
-{
-	int i, not_empty = 0;
-	u8 buff[sizeof(struct iwl_wep_cmd) +
-		sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
-	struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
-	size_t cmd_size  = sizeof(struct iwl_wep_cmd);
-	struct iwl_host_cmd cmd = {
-		.id = ctx->wep_key_cmd,
-		.data = { wep_cmd, },
-		.flags = CMD_SYNC,
-	};
-
-	might_sleep();
-
-	memset(wep_cmd, 0, cmd_size +
-			(sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
-
-	for (i = 0; i < WEP_KEYS_MAX ; i++) {
-		wep_cmd->key[i].key_index = i;
-		if (ctx->wep_keys[i].key_size) {
-			wep_cmd->key[i].key_offset = i;
-			not_empty = 1;
-		} else {
-			wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
-		}
-
-		wep_cmd->key[i].key_size = ctx->wep_keys[i].key_size;
-		memcpy(&wep_cmd->key[i].key[3], ctx->wep_keys[i].key,
-				ctx->wep_keys[i].key_size);
-	}
-
-	wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
-	wep_cmd->num_keys = WEP_KEYS_MAX;
-
-	cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
-
-	cmd.len[0] = cmd_size;
-
-	if (not_empty || send_if_empty)
-		return iwl_dvm_send_cmd(priv, &cmd);
-	else
-		return 0;
-}
-
-int iwl_restore_default_wep_keys(struct iwl_priv *priv,
-				 struct iwl_rxon_context *ctx)
-{
-	lockdep_assert_held(&priv->mutex);
-
-	return iwl_send_static_wepkey_cmd(priv, ctx, false);
-}
-
-int iwl_remove_default_wep_key(struct iwl_priv *priv,
-			       struct iwl_rxon_context *ctx,
-			       struct ieee80211_key_conf *keyconf)
-{
-	int ret;
-
-	lockdep_assert_held(&priv->mutex);
-
-	IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
-		      keyconf->keyidx);
-
-	memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0]));
-	if (iwl_is_rfkill(priv)) {
-		IWL_DEBUG_WEP(priv,
-			"Not sending REPLY_WEPKEY command due to RFKILL.\n");
-		/* but keys in device are clear anyway so return success */
-		return 0;
-	}
-	ret = iwl_send_static_wepkey_cmd(priv, ctx, 1);
-	IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
-		      keyconf->keyidx, ret);
-
-	return ret;
-}
-
-int iwl_set_default_wep_key(struct iwl_priv *priv,
-			    struct iwl_rxon_context *ctx,
-			    struct ieee80211_key_conf *keyconf)
-{
-	int ret;
-
-	lockdep_assert_held(&priv->mutex);
-
-	if (keyconf->keylen != WEP_KEY_LEN_128 &&
-	    keyconf->keylen != WEP_KEY_LEN_64) {
-		IWL_DEBUG_WEP(priv,
-			      "Bad WEP key length %d\n", keyconf->keylen);
-		return -EINVAL;
-	}
-
-	keyconf->hw_key_idx = IWLAGN_HW_KEY_DEFAULT;
-
-	ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
-	memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key,
-							keyconf->keylen);
-
-	ret = iwl_send_static_wepkey_cmd(priv, ctx, false);
-	IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
-		keyconf->keylen, keyconf->keyidx, ret);
-
-	return ret;
-}
-
-/*
- * dynamic (per-station) keys
- *
- * The dynamic keys are a little more complicated. The device has
- * a key cache of up to STA_KEY_MAX_NUM/STA_KEY_MAX_NUM_PAN keys.
- * These are linked to stations by a table that contains an index
- * into the key table for each station/key index/{mcast,unicast},
- * i.e. it's basically an array of pointers like this:
- *	key_offset_t key_mapping[NUM_STATIONS][4][2];
- * (it really works differently, but you can think of it as such)
- *
- * The key uploading and linking happens in the same command, the
- * add station command with STA_MODIFY_KEY_MASK.
- */
-
-static u8 iwlagn_key_sta_id(struct iwl_priv *priv,
-			    struct ieee80211_vif *vif,
-			    struct ieee80211_sta *sta)
-{
-	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-
-	if (sta)
-		return iwl_sta_id(sta);
-
-	/*
-	 * The device expects GTKs for station interfaces to be
-	 * installed as GTKs for the AP station. If we have no
-	 * station ID, then use the ap_sta_id in that case.
-	 */
-	if (vif->type == NL80211_IFTYPE_STATION && vif_priv->ctx)
-		return vif_priv->ctx->ap_sta_id;
-
-	return IWL_INVALID_STATION;
-}
-
-static int iwlagn_send_sta_key(struct iwl_priv *priv,
-			       struct ieee80211_key_conf *keyconf,
-			       u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k,
-			       u32 cmd_flags)
-{
-	__le16 key_flags;
-	struct iwl_addsta_cmd sta_cmd;
-	int i;
-
-	spin_lock_bh(&priv->sta_lock);
-	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
-	spin_unlock_bh(&priv->sta_lock);
-
-	key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
-	key_flags |= STA_KEY_FLG_MAP_KEY_MSK;
-
-	switch (keyconf->cipher) {
-	case WLAN_CIPHER_SUITE_CCMP:
-		key_flags |= STA_KEY_FLG_CCMP;
-		memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen);
-		break;
-	case WLAN_CIPHER_SUITE_TKIP:
-		key_flags |= STA_KEY_FLG_TKIP;
-		sta_cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;
-		for (i = 0; i < 5; i++)
-			sta_cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]);
-		memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen);
-		break;
-	case WLAN_CIPHER_SUITE_WEP104:
-		key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
-		/* fall through */
-	case WLAN_CIPHER_SUITE_WEP40:
-		key_flags |= STA_KEY_FLG_WEP;
-		memcpy(&sta_cmd.key.key[3], keyconf->key, keyconf->keylen);
-		break;
-	default:
-		WARN_ON(1);
-		return -EINVAL;
-	}
-
-	if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
-		key_flags |= STA_KEY_MULTICAST_MSK;
-
-	/* key pointer (offset) */
-	sta_cmd.key.key_offset = keyconf->hw_key_idx;
-
-	sta_cmd.key.key_flags = key_flags;
-	sta_cmd.mode = STA_CONTROL_MODIFY_MSK;
-	sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK;
-
-	return iwl_send_add_sta(priv, &sta_cmd, cmd_flags);
-}
-
-void iwl_update_tkip_key(struct iwl_priv *priv,
-			 struct ieee80211_vif *vif,
-			 struct ieee80211_key_conf *keyconf,
-			 struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
-{
-	u8 sta_id = iwlagn_key_sta_id(priv, vif, sta);
-
-	if (sta_id == IWL_INVALID_STATION)
-		return;
-
-	if (iwl_scan_cancel(priv)) {
-		/* cancel scan failed, just live w/ bad key and rely
-		   briefly on SW decryption */
-		return;
-	}
-
-	iwlagn_send_sta_key(priv, keyconf, sta_id,
-			    iv32, phase1key, CMD_ASYNC);
-}
-
-int iwl_remove_dynamic_key(struct iwl_priv *priv,
-			   struct iwl_rxon_context *ctx,
-			   struct ieee80211_key_conf *keyconf,
-			   struct ieee80211_sta *sta)
-{
-	struct iwl_addsta_cmd sta_cmd;
-	u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta);
-	__le16 key_flags;
-
-	/* if station isn't there, neither is the key */
-	if (sta_id == IWL_INVALID_STATION)
-		return -ENOENT;
-
-	spin_lock_bh(&priv->sta_lock);
-	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
-	if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE))
-		sta_id = IWL_INVALID_STATION;
-	spin_unlock_bh(&priv->sta_lock);
-
-	if (sta_id == IWL_INVALID_STATION)
-		return 0;
-
-	lockdep_assert_held(&priv->mutex);
-
-	ctx->key_mapping_keys--;
-
-	IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n",
-		      keyconf->keyidx, sta_id);
-
-	if (!test_and_clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table))
-		IWL_ERR(priv, "offset %d not used in uCode key table.\n",
-			keyconf->hw_key_idx);
-
-	key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
-	key_flags |= STA_KEY_FLG_MAP_KEY_MSK | STA_KEY_FLG_NO_ENC |
-		     STA_KEY_FLG_INVALID;
-
-	if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
-		key_flags |= STA_KEY_MULTICAST_MSK;
-
-	sta_cmd.key.key_flags = key_flags;
-	sta_cmd.key.key_offset = keyconf->hw_key_idx;
-	sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK;
-	sta_cmd.mode = STA_CONTROL_MODIFY_MSK;
-
-	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-
-int iwl_set_dynamic_key(struct iwl_priv *priv,
-			struct iwl_rxon_context *ctx,
-			struct ieee80211_key_conf *keyconf,
-			struct ieee80211_sta *sta)
-{
-	struct ieee80211_key_seq seq;
-	u16 p1k[5];
-	int ret;
-	u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta);
-	const u8 *addr;
-
-	if (sta_id == IWL_INVALID_STATION)
-		return -EINVAL;
-
-	lockdep_assert_held(&priv->mutex);
-
-	keyconf->hw_key_idx = iwl_get_free_ucode_key_offset(priv);
-	if (keyconf->hw_key_idx == WEP_INVALID_OFFSET)
-		return -ENOSPC;
-
-	ctx->key_mapping_keys++;
-
-	switch (keyconf->cipher) {
-	case WLAN_CIPHER_SUITE_TKIP:
-		if (sta)
-			addr = sta->addr;
-		else /* station mode case only */
-			addr = ctx->active.bssid_addr;
-
-		/* pre-fill phase 1 key into device cache */
-		ieee80211_get_key_rx_seq(keyconf, 0, &seq);
-		ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
-		ret = iwlagn_send_sta_key(priv, keyconf, sta_id,
-					  seq.tkip.iv32, p1k, CMD_SYNC);
-		break;
-	case WLAN_CIPHER_SUITE_CCMP:
-	case WLAN_CIPHER_SUITE_WEP40:
-	case WLAN_CIPHER_SUITE_WEP104:
-		ret = iwlagn_send_sta_key(priv, keyconf, sta_id,
-					  0, NULL, CMD_SYNC);
-		break;
-	default:
-		IWL_ERR(priv, "Unknown cipher %x\n", keyconf->cipher);
-		ret = -EINVAL;
-	}
-
-	if (ret) {
-		ctx->key_mapping_keys--;
-		clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table);
-	}
-
-	IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
-		      keyconf->cipher, keyconf->keylen, keyconf->keyidx,
-		      sta ? sta->addr : NULL, ret);
-
-	return ret;
-}
-
-/**
- * iwlagn_alloc_bcast_station - add broadcast station into driver's station table.
- *
- * This adds the broadcast station into the driver's station table
- * and marks it driver active, so that it will be restored to the
- * device at the next best time.
- */
-int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
-			       struct iwl_rxon_context *ctx)
-{
-	struct iwl_link_quality_cmd *link_cmd;
-	u8 sta_id;
-
-	spin_lock_bh(&priv->sta_lock);
-	sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL);
-	if (sta_id == IWL_INVALID_STATION) {
-		IWL_ERR(priv, "Unable to prepare broadcast station\n");
-		spin_unlock_bh(&priv->sta_lock);
-
-		return -EINVAL;
-	}
-
-	priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
-	priv->stations[sta_id].used |= IWL_STA_BCAST;
-	spin_unlock_bh(&priv->sta_lock);
-
-	link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
-	if (!link_cmd) {
-		IWL_ERR(priv,
-			"Unable to initialize rate scaling for bcast station.\n");
-		return -ENOMEM;
-	}
-
-	spin_lock_bh(&priv->sta_lock);
-	priv->stations[sta_id].lq = link_cmd;
-	spin_unlock_bh(&priv->sta_lock);
-
-	return 0;
-}
-
-/**
- * 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,
-			     struct iwl_rxon_context *ctx)
-{
-	struct iwl_link_quality_cmd *link_cmd;
-	u8 sta_id = ctx->bcast_sta_id;
-
-	link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
-	if (!link_cmd) {
-		IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n");
-		return -ENOMEM;
-	}
-
-	spin_lock_bh(&priv->sta_lock);
-	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_bh(&priv->sta_lock);
-
-	return 0;
-}
-
-int iwl_update_bcast_stations(struct iwl_priv *priv)
-{
-	struct iwl_rxon_context *ctx;
-	int ret = 0;
-
-	for_each_context(priv, ctx) {
-		ret = iwl_update_bcast_station(priv, ctx);
-		if (ret)
-			break;
-	}
-
-	return ret;
-}
-
-/**
- * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
- */
-int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
-{
-	struct iwl_addsta_cmd sta_cmd;
-
-	lockdep_assert_held(&priv->mutex);
-
-	/* Remove "disable" flag, to enable Tx for this TID */
-	spin_lock_bh(&priv->sta_lock);
-	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_bh(&priv->sta_lock);
-
-	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-
-int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
-			 int tid, u16 ssn)
-{
-	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)
-		return -ENXIO;
-
-	spin_lock_bh(&priv->sta_lock);
-	priv->stations[sta_id].sta.station_flags_msk = 0;
-	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
-	priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
-	priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
-	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
-	spin_unlock_bh(&priv->sta_lock);
-
-	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-
-int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
-			int tid)
-{
-	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) {
-		IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
-		return -ENXIO;
-	}
-
-	spin_lock_bh(&priv->sta_lock);
-	priv->stations[sta_id].sta.station_flags_msk = 0;
-	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
-	priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
-	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
-	spin_unlock_bh(&priv->sta_lock);
-
-	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-
-
-
-void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
-{
-	struct iwl_addsta_cmd cmd = {
-		.mode = STA_CONTROL_MODIFY_MSK,
-		.station_flags = STA_FLG_PWR_SAVE_MSK,
-		.station_flags_msk = STA_FLG_PWR_SAVE_MSK,
-		.sta.sta_id = sta_id,
-		.sta.modify_mask = STA_MODIFY_SLEEP_TX_COUNT_MSK,
-		.sleep_tx_count = cpu_to_le16(cnt),
-	};
-
-	iwl_send_add_sta(priv, &cmd, CMD_ASYNC);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
deleted file mode 100644
index a5cfe0a..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
+++ /dev/null
@@ -1,696 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *****************************************************************************/
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-agn.h"
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-commands.h"
-#include "iwl-debug.h"
-#include "iwl-agn-tt.h"
-#include "iwl-modparams.h"
-
-/* default Thermal Throttling transaction table
- * Current state   |         Throttling Down               |  Throttling Up
- *=============================================================================
- *                 Condition Nxt State  Condition Nxt State Condition Nxt State
- *-----------------------------------------------------------------------------
- *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
- *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
- *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
- *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
- *=============================================================================
- */
-static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
-	{IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
-	{IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
-	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
-};
-static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
-	{IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
-	{IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
-	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
-};
-static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
-	{IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
-	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
-	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
-};
-static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
-	{IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
-	{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
-	{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
-};
-
-/* Advance Thermal Throttling default restriction table */
-static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
-	{IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
-	{IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
-	{IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
-	{IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
-};
-
-bool iwl_tt_is_low_power_state(struct iwl_priv *priv)
-{
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-	if (tt->state >= IWL_TI_1)
-		return true;
-	return false;
-}
-
-u8 iwl_tt_current_power_mode(struct iwl_priv *priv)
-{
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-	return tt->tt_power_mode;
-}
-
-bool iwl_ht_enabled(struct iwl_priv *priv)
-{
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-	struct iwl_tt_restriction *restriction;
-
-	if (!priv->thermal_throttle.advanced_tt)
-		return true;
-	restriction = tt->restriction + tt->state;
-	return restriction->is_ht;
-}
-
-static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
-{
-	s32 temp = priv->temperature; /* degrees CELSIUS except specified */
-	bool within_margin = false;
-
-	if (!priv->thermal_throttle.advanced_tt)
-		within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
-				CT_KILL_THRESHOLD_LEGACY) ? true : false;
-	else
-		within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
-				CT_KILL_THRESHOLD) ? true : false;
-	return within_margin;
-}
-
-bool iwl_check_for_ct_kill(struct iwl_priv *priv)
-{
-	bool is_ct_kill = false;
-
-	if (iwl_within_ct_kill_margin(priv)) {
-		iwl_tt_enter_ct_kill(priv);
-		is_ct_kill = true;
-	}
-	return is_ct_kill;
-}
-
-enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
-{
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-	struct iwl_tt_restriction *restriction;
-
-	if (!priv->thermal_throttle.advanced_tt)
-		return IWL_ANT_OK_MULTI;
-	restriction = tt->restriction + tt->state;
-	return restriction->tx_stream;
-}
-
-enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
-{
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-	struct iwl_tt_restriction *restriction;
-
-	if (!priv->thermal_throttle.advanced_tt)
-		return IWL_ANT_OK_MULTI;
-	restriction = tt->restriction + tt->state;
-	return restriction->rx_stream;
-}
-
-#define CT_KILL_EXIT_DURATION (5)	/* 5 seconds duration */
-#define CT_KILL_WAITING_DURATION (300)	/* 300ms duration */
-
-/*
- * toggle the bit to wake up uCode and check the temperature
- * if the temperature is below CT, uCode will stay awake and send card
- * state notification with CT_KILL bit clear to inform Thermal Throttling
- * Management to change state. Otherwise, uCode will go back to sleep
- * without doing anything, driver should continue the 5 seconds timer
- * to wake up uCode for temperature check until temperature drop below CT
- */
-static void iwl_tt_check_exit_ct_kill(unsigned long data)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)data;
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-	unsigned long flags;
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	if (tt->state == IWL_TI_CT_KILL) {
-		if (priv->thermal_throttle.ct_kill_toggle) {
-			iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
-				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-			priv->thermal_throttle.ct_kill_toggle = false;
-		} else {
-			iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
-				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-			priv->thermal_throttle.ct_kill_toggle = true;
-		}
-		iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
-		spin_lock_irqsave(&priv->trans->reg_lock, flags);
-		if (likely(iwl_grab_nic_access(priv->trans)))
-			iwl_release_nic_access(priv->trans);
-		spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
-
-		/* Reschedule the ct_kill timer to occur in
-		 * CT_KILL_EXIT_DURATION seconds to ensure we get a
-		 * thermal update */
-		IWL_DEBUG_TEMP(priv, "schedule ct_kill exit timer\n");
-		mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
-			  jiffies + CT_KILL_EXIT_DURATION * HZ);
-	}
-}
-
-static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
-			   bool stop)
-{
-	if (stop) {
-		IWL_DEBUG_TEMP(priv, "Stop all queues\n");
-		if (priv->mac80211_registered)
-			ieee80211_stop_queues(priv->hw);
-		IWL_DEBUG_TEMP(priv,
-				"Schedule 5 seconds CT_KILL Timer\n");
-		mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
-			  jiffies + CT_KILL_EXIT_DURATION * HZ);
-	} else {
-		IWL_DEBUG_TEMP(priv, "Wake all queues\n");
-		if (priv->mac80211_registered)
-			ieee80211_wake_queues(priv->hw);
-	}
-}
-
-static void iwl_tt_ready_for_ct_kill(unsigned long data)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)data;
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	/* temperature timer expired, ready to go into CT_KILL state */
-	if (tt->state != IWL_TI_CT_KILL) {
-		IWL_DEBUG_TEMP(priv, "entering CT_KILL state when "
-				"temperature timer expired\n");
-		tt->state = IWL_TI_CT_KILL;
-		set_bit(STATUS_CT_KILL, &priv->status);
-		iwl_perform_ct_kill_task(priv, true);
-	}
-}
-
-static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
-{
-	IWL_DEBUG_TEMP(priv, "Prepare to enter IWL_TI_CT_KILL\n");
-	/* make request to retrieve statistics information */
-	iwl_send_statistics_request(priv, CMD_SYNC, false);
-	/* Reschedule the ct_kill wait timer */
-	mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
-		 jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
-}
-
-#define IWL_MINIMAL_POWER_THRESHOLD		(CT_KILL_THRESHOLD_LEGACY)
-#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2	(100)
-#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1	(90)
-
-/*
- * Legacy thermal throttling
- * 1) Avoid NIC destruction due to high temperatures
- *	Chip will identify dangerously high temperatures that can
- *	harm the device and will power down
- * 2) Avoid the NIC power down due to high temperature
- *	Throttle early enough to lower the power consumption before
- *	drastic steps are needed
- */
-static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
-{
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-	enum iwl_tt_state old_state;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if ((tt->tt_previous_temp) &&
-	    (temp > tt->tt_previous_temp) &&
-	    ((temp - tt->tt_previous_temp) >
-	    IWL_TT_INCREASE_MARGIN)) {
-		IWL_DEBUG_TEMP(priv,
-			"Temperature increase %d degree Celsius\n",
-			(temp - tt->tt_previous_temp));
-	}
-#endif
-	old_state = tt->state;
-	/* in Celsius */
-	if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
-		tt->state = IWL_TI_CT_KILL;
-	else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
-		tt->state = IWL_TI_2;
-	else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
-		tt->state = IWL_TI_1;
-	else
-		tt->state = IWL_TI_0;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	tt->tt_previous_temp = temp;
-#endif
-	/* stop ct_kill_waiting_tm timer */
-	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
-	if (tt->state != old_state) {
-		switch (tt->state) {
-		case IWL_TI_0:
-			/*
-			 * When the system is ready to go back to IWL_TI_0
-			 * we only have to call iwl_power_update_mode() to
-			 * do so.
-			 */
-			break;
-		case IWL_TI_1:
-			tt->tt_power_mode = IWL_POWER_INDEX_3;
-			break;
-		case IWL_TI_2:
-			tt->tt_power_mode = IWL_POWER_INDEX_4;
-			break;
-		default:
-			tt->tt_power_mode = IWL_POWER_INDEX_5;
-			break;
-		}
-		mutex_lock(&priv->mutex);
-		if (old_state == IWL_TI_CT_KILL)
-			clear_bit(STATUS_CT_KILL, &priv->status);
-		if (tt->state != IWL_TI_CT_KILL &&
-		    iwl_power_update_mode(priv, true)) {
-			/* TT state not updated
-			 * try again during next temperature read
-			 */
-			if (old_state == IWL_TI_CT_KILL)
-				set_bit(STATUS_CT_KILL, &priv->status);
-			tt->state = old_state;
-			IWL_ERR(priv, "Cannot update power mode, "
-					"TT state not updated\n");
-		} else {
-			if (tt->state == IWL_TI_CT_KILL) {
-				if (force) {
-					set_bit(STATUS_CT_KILL, &priv->status);
-					iwl_perform_ct_kill_task(priv, true);
-				} else {
-					iwl_prepare_ct_kill_task(priv);
-					tt->state = old_state;
-				}
-			} else if (old_state == IWL_TI_CT_KILL &&
-				 tt->state != IWL_TI_CT_KILL)
-				iwl_perform_ct_kill_task(priv, false);
-			IWL_DEBUG_TEMP(priv, "Temperature state changed %u\n",
-					tt->state);
-			IWL_DEBUG_TEMP(priv, "Power Index change to %u\n",
-					tt->tt_power_mode);
-		}
-		mutex_unlock(&priv->mutex);
-	}
-}
-
-/*
- * Advance thermal throttling
- * 1) Avoid NIC destruction due to high temperatures
- *	Chip will identify dangerously high temperatures that can
- *	harm the device and will power down
- * 2) Avoid the NIC power down due to high temperature
- *	Throttle early enough to lower the power consumption before
- *	drastic steps are needed
- *	Actions include relaxing the power down sleep thresholds and
- *	decreasing the number of TX streams
- * 3) Avoid throughput performance impact as much as possible
- *
- *=============================================================================
- *                 Condition Nxt State  Condition Nxt State Condition Nxt State
- *-----------------------------------------------------------------------------
- *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
- *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
- *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
- *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
- *=============================================================================
- */
-static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
-{
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-	int i;
-	bool changed = false;
-	enum iwl_tt_state old_state;
-	struct iwl_tt_trans *transaction;
-
-	old_state = tt->state;
-	for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
-		/* based on the current TT state,
-		 * find the curresponding transaction table
-		 * each table has (IWL_TI_STATE_MAX - 1) entries
-		 * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
-		 * will advance to the correct table.
-		 * then based on the current temperature
-		 * find the next state need to transaction to
-		 * go through all the possible (IWL_TI_STATE_MAX - 1) entries
-		 * in the current table to see if transaction is needed
-		 */
-		transaction = tt->transaction +
-			((old_state * (IWL_TI_STATE_MAX - 1)) + i);
-		if (temp >= transaction->tt_low &&
-		    temp <= transaction->tt_high) {
-#ifdef CONFIG_IWLWIFI_DEBUG
-			if ((tt->tt_previous_temp) &&
-			    (temp > tt->tt_previous_temp) &&
-			    ((temp - tt->tt_previous_temp) >
-			    IWL_TT_INCREASE_MARGIN)) {
-				IWL_DEBUG_TEMP(priv,
-					"Temperature increase %d "
-					"degree Celsius\n",
-					(temp - tt->tt_previous_temp));
-			}
-			tt->tt_previous_temp = temp;
-#endif
-			if (old_state !=
-			    transaction->next_state) {
-				changed = true;
-				tt->state =
-					transaction->next_state;
-			}
-			break;
-		}
-	}
-	/* stop ct_kill_waiting_tm timer */
-	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
-	if (changed) {
-		if (tt->state >= IWL_TI_1) {
-			/* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
-			tt->tt_power_mode = IWL_POWER_INDEX_5;
-
-			if (!iwl_ht_enabled(priv)) {
-				struct iwl_rxon_context *ctx;
-
-				for_each_context(priv, ctx) {
-					struct iwl_rxon_cmd *rxon;
-
-					rxon = &ctx->staging;
-
-					/* disable HT */
-					rxon->flags &= ~(
-						RXON_FLG_CHANNEL_MODE_MSK |
-						RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
-						RXON_FLG_HT40_PROT_MSK |
-						RXON_FLG_HT_PROT_MSK);
-				}
-			} else {
-				/* check HT capability and set
-				 * according to the system HT capability
-				 * in case get disabled before */
-				iwl_set_rxon_ht(priv, &priv->current_ht_config);
-			}
-
-		} else {
-			/*
-			 * restore system power setting -- it will be
-			 * recalculated automatically.
-			 */
-
-			/* check HT capability and set
-			 * according to the system HT capability
-			 * in case get disabled before */
-			iwl_set_rxon_ht(priv, &priv->current_ht_config);
-		}
-		mutex_lock(&priv->mutex);
-		if (old_state == IWL_TI_CT_KILL)
-			clear_bit(STATUS_CT_KILL, &priv->status);
-		if (tt->state != IWL_TI_CT_KILL &&
-		    iwl_power_update_mode(priv, true)) {
-			/* TT state not updated
-			 * try again during next temperature read
-			 */
-			IWL_ERR(priv, "Cannot update power mode, "
-					"TT state not updated\n");
-			if (old_state == IWL_TI_CT_KILL)
-				set_bit(STATUS_CT_KILL, &priv->status);
-			tt->state = old_state;
-		} else {
-			IWL_DEBUG_TEMP(priv,
-					"Thermal Throttling to new state: %u\n",
-					tt->state);
-			if (old_state != IWL_TI_CT_KILL &&
-			    tt->state == IWL_TI_CT_KILL) {
-				if (force) {
-					IWL_DEBUG_TEMP(priv,
-						"Enter IWL_TI_CT_KILL\n");
-					set_bit(STATUS_CT_KILL, &priv->status);
-					iwl_perform_ct_kill_task(priv, true);
-				} else {
-					iwl_prepare_ct_kill_task(priv);
-					tt->state = old_state;
-				}
-			} else if (old_state == IWL_TI_CT_KILL &&
-				  tt->state != IWL_TI_CT_KILL) {
-				IWL_DEBUG_TEMP(priv, "Exit IWL_TI_CT_KILL\n");
-				iwl_perform_ct_kill_task(priv, false);
-			}
-		}
-		mutex_unlock(&priv->mutex);
-	}
-}
-
-/* Card State Notification indicated reach critical temperature
- * if PSP not enable, no Thermal Throttling function will be performed
- * just set the GP1 bit to acknowledge the event
- * otherwise, go into IWL_TI_CT_KILL state
- * since Card State Notification will not provide any temperature reading
- * for Legacy mode
- * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
- * for advance mode
- * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
- */
-static void iwl_bg_ct_enter(struct work_struct *work)
-{
-	struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	if (!iwl_is_ready(priv))
-		return;
-
-	if (tt->state != IWL_TI_CT_KILL) {
-		IWL_ERR(priv, "Device reached critical temperature "
-			      "- ucode going to sleep!\n");
-		if (!priv->thermal_throttle.advanced_tt)
-			iwl_legacy_tt_handler(priv,
-					      IWL_MINIMAL_POWER_THRESHOLD,
-					      true);
-		else
-			iwl_advance_tt_handler(priv,
-					       CT_KILL_THRESHOLD + 1, true);
-	}
-}
-
-/* Card State Notification indicated out of critical temperature
- * since Card State Notification will not provide any temperature reading
- * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
- * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
- */
-static void iwl_bg_ct_exit(struct work_struct *work)
-{
-	struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	if (!iwl_is_ready(priv))
-		return;
-
-	/* stop ct_kill_exit_tm timer */
-	del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
-
-	if (tt->state == IWL_TI_CT_KILL) {
-		IWL_ERR(priv,
-			"Device temperature below critical"
-			"- ucode awake!\n");
-		/*
-		 * exit from CT_KILL state
-		 * reset the current temperature reading
-		 */
-		priv->temperature = 0;
-		if (!priv->thermal_throttle.advanced_tt)
-			iwl_legacy_tt_handler(priv,
-				      IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
-				      true);
-		else
-			iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
-					       true);
-	}
-}
-
-void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
-{
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n");
-	queue_work(priv->workqueue, &priv->ct_enter);
-}
-
-void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
-{
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n");
-	queue_work(priv->workqueue, &priv->ct_exit);
-}
-
-static void iwl_bg_tt_work(struct work_struct *work)
-{
-	struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
-	s32 temp = priv->temperature; /* degrees CELSIUS except specified */
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	if (!priv->thermal_throttle.advanced_tt)
-		iwl_legacy_tt_handler(priv, temp, false);
-	else
-		iwl_advance_tt_handler(priv, temp, false);
-}
-
-void iwl_tt_handler(struct iwl_priv *priv)
-{
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n");
-	queue_work(priv->workqueue, &priv->tt_work);
-}
-
-/* Thermal throttling initialization
- * For advance thermal throttling:
- *     Initialize Thermal Index and temperature threshold table
- *     Initialize thermal throttling restriction table
- */
-void iwl_tt_initialize(struct iwl_priv *priv)
-{
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-	int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
-	struct iwl_tt_trans *transaction;
-
-	IWL_DEBUG_TEMP(priv, "Initialize Thermal Throttling\n");
-
-	memset(tt, 0, sizeof(struct iwl_tt_mgmt));
-
-	tt->state = IWL_TI_0;
-	init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
-	priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
-	priv->thermal_throttle.ct_kill_exit_tm.function =
-		iwl_tt_check_exit_ct_kill;
-	init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
-	priv->thermal_throttle.ct_kill_waiting_tm.data =
-		(unsigned long)priv;
-	priv->thermal_throttle.ct_kill_waiting_tm.function =
-		iwl_tt_ready_for_ct_kill;
-	/* setup deferred ct kill work */
-	INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
-	INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
-	INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
-
-	if (priv->cfg->base_params->adv_thermal_throttle) {
-		IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n");
-		tt->restriction = kcalloc(IWL_TI_STATE_MAX,
-					  sizeof(struct iwl_tt_restriction),
-					  GFP_KERNEL);
-		tt->transaction = kcalloc(IWL_TI_STATE_MAX *
-					  (IWL_TI_STATE_MAX - 1),
-					  sizeof(struct iwl_tt_trans),
-					  GFP_KERNEL);
-		if (!tt->restriction || !tt->transaction) {
-			IWL_ERR(priv, "Fallback to Legacy Throttling\n");
-			priv->thermal_throttle.advanced_tt = false;
-			kfree(tt->restriction);
-			tt->restriction = NULL;
-			kfree(tt->transaction);
-			tt->transaction = NULL;
-		} else {
-			transaction = tt->transaction +
-				(IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
-			memcpy(transaction, &tt_range_0[0], size);
-			transaction = tt->transaction +
-				(IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
-			memcpy(transaction, &tt_range_1[0], size);
-			transaction = tt->transaction +
-				(IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
-			memcpy(transaction, &tt_range_2[0], size);
-			transaction = tt->transaction +
-				(IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
-			memcpy(transaction, &tt_range_3[0], size);
-			size = sizeof(struct iwl_tt_restriction) *
-				IWL_TI_STATE_MAX;
-			memcpy(tt->restriction,
-				&restriction_range[0], size);
-			priv->thermal_throttle.advanced_tt = true;
-		}
-	} else {
-		IWL_DEBUG_TEMP(priv, "Legacy Thermal Throttling\n");
-		priv->thermal_throttle.advanced_tt = false;
-	}
-}
-
-/* cleanup thermal throttling management related memory and timer */
-void iwl_tt_exit(struct iwl_priv *priv)
-{
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-	/* stop ct_kill_exit_tm timer if activated */
-	del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
-	/* stop ct_kill_waiting_tm timer if activated */
-	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
-	cancel_work_sync(&priv->tt_work);
-	cancel_work_sync(&priv->ct_enter);
-	cancel_work_sync(&priv->ct_exit);
-
-	if (priv->thermal_throttle.advanced_tt) {
-		/* free advance thermal throttling memory */
-		kfree(tt->restriction);
-		tt->restriction = NULL;
-		kfree(tt->transaction);
-		tt->transaction = NULL;
-	}
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
deleted file mode 100644
index 86bbf47..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *****************************************************************************/
-#ifndef __iwl_tt_setting_h__
-#define __iwl_tt_setting_h__
-
-#include "iwl-commands.h"
-
-#define IWL_ABSOLUTE_ZERO		0
-#define IWL_ABSOLUTE_MAX		0xFFFFFFFF
-#define IWL_TT_INCREASE_MARGIN	5
-#define IWL_TT_CT_KILL_MARGIN	3
-
-enum iwl_antenna_ok {
-	IWL_ANT_OK_NONE,
-	IWL_ANT_OK_SINGLE,
-	IWL_ANT_OK_MULTI,
-};
-
-/* Thermal Throttling State Machine states */
-enum  iwl_tt_state {
-	IWL_TI_0,	/* normal temperature, system power state */
-	IWL_TI_1,	/* high temperature detect, low power state */
-	IWL_TI_2,	/* higher temperature detected, lower power state */
-	IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
-	IWL_TI_STATE_MAX
-};
-
-/**
- * struct iwl_tt_restriction - Thermal Throttling restriction table
- * @tx_stream: number of tx stream allowed
- * @is_ht: ht enable/disable
- * @rx_stream: number of rx stream allowed
- *
- * This table is used by advance thermal throttling management
- * based on the current thermal throttling state, and determines
- * the number of tx/rx streams and the status of HT operation.
- */
-struct iwl_tt_restriction {
-	enum iwl_antenna_ok tx_stream;
-	enum iwl_antenna_ok rx_stream;
-	bool is_ht;
-};
-
-/**
- * struct iwl_tt_trans - Thermal Throttling transaction table
- * @next_state:  next thermal throttling mode
- * @tt_low: low temperature threshold to change state
- * @tt_high: high temperature threshold to change state
- *
- * This is used by the advanced thermal throttling algorithm
- * to determine the next thermal state to go based on the
- * current temperature.
- */
-struct iwl_tt_trans {
-	enum iwl_tt_state next_state;
-	u32 tt_low;
-	u32 tt_high;
-};
-
-/**
- * struct iwl_tt_mgnt - Thermal Throttling Management structure
- * @advanced_tt:    advanced thermal throttle required
- * @state:          current Thermal Throttling state
- * @tt_power_mode:  Thermal Throttling power mode index
- *		    being used to set power level when
- *		    when thermal throttling state != IWL_TI_0
- *		    the tt_power_mode should set to different
- *		    power mode based on the current tt state
- * @tt_previous_temperature: last measured temperature
- * @iwl_tt_restriction: ptr to restriction tbl, used by advance
- *		    thermal throttling to determine how many tx/rx streams
- *		    should be used in tt state; and can HT be enabled or not
- * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
- *		    state transaction
- * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
- * @ct_kill_exit_tm: timer to exit thermal kill
- */
-struct iwl_tt_mgmt {
-	enum iwl_tt_state state;
-	bool advanced_tt;
-	u8 tt_power_mode;
-	bool ct_kill_toggle;
-#ifdef CONFIG_IWLWIFI_DEBUG
-	s32 tt_previous_temp;
-#endif
-	struct iwl_tt_restriction *restriction;
-	struct iwl_tt_trans *transaction;
-	struct timer_list ct_kill_exit_tm;
-	struct timer_list ct_kill_waiting_tm;
-};
-
-u8 iwl_tt_current_power_mode(struct iwl_priv *priv);
-bool iwl_tt_is_low_power_state(struct iwl_priv *priv);
-bool iwl_ht_enabled(struct iwl_priv *priv);
-enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv);
-enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv);
-void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
-void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
-void iwl_tt_handler(struct iwl_priv *priv);
-void iwl_tt_initialize(struct iwl_priv *priv);
-void iwl_tt_exit(struct iwl_priv *priv);
-
-#endif  /* __iwl_tt_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
deleted file mode 100644
index 3366e2e..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ /dev/null
@@ -1,1368 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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 <linux/ieee80211.h>
-
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-hw.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-
-static const u8 tid_to_ac[] = {
-	IEEE80211_AC_BE,
-	IEEE80211_AC_BK,
-	IEEE80211_AC_BK,
-	IEEE80211_AC_BE,
-	IEEE80211_AC_VI,
-	IEEE80211_AC_VI,
-	IEEE80211_AC_VO,
-	IEEE80211_AC_VO,
-};
-
-static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
-				     struct ieee80211_tx_info *info,
-				     __le16 fc, __le32 *tx_flags)
-{
-	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
-	    info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT ||
-	    info->flags & IEEE80211_TX_CTL_AMPDU)
-		*tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
-}
-
-/*
- * handle build REPLY_TX command notification.
- */
-static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
-				      struct sk_buff *skb,
-				      struct iwl_tx_cmd *tx_cmd,
-				      struct ieee80211_tx_info *info,
-				      struct ieee80211_hdr *hdr, u8 sta_id)
-{
-	__le16 fc = hdr->frame_control;
-	__le32 tx_flags = tx_cmd->tx_flags;
-
-	tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-
-	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
-		tx_flags |= TX_CMD_FLG_ACK_MSK;
-	else
-		tx_flags &= ~TX_CMD_FLG_ACK_MSK;
-
-	if (ieee80211_is_probe_resp(fc))
-		tx_flags |= TX_CMD_FLG_TSF_MSK;
-	else if (ieee80211_is_back_req(fc))
-		tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
-	else if (info->band == IEEE80211_BAND_2GHZ &&
-		 priv->cfg->bt_params &&
-		 priv->cfg->bt_params->advanced_bt_coexist &&
-		 (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) ||
-		 ieee80211_is_reassoc_req(fc) ||
-		 skb->protocol == cpu_to_be16(ETH_P_PAE)))
-		tx_flags |= TX_CMD_FLG_IGNORE_BT;
-
-
-	tx_cmd->sta_id = sta_id;
-	if (ieee80211_has_morefrags(fc))
-		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
-
-	if (ieee80211_is_data_qos(fc)) {
-		u8 *qc = ieee80211_get_qos_ctl(hdr);
-		tx_cmd->tid_tspec = qc[0] & 0xf;
-		tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
-	} else {
-		tx_cmd->tid_tspec = IWL_TID_NON_QOS;
-		if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
-			tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-		else
-			tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
-	}
-
-	iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags);
-
-	tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
-	if (ieee80211_is_mgmt(fc)) {
-		if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
-			tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
-		else
-			tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
-	} else {
-		tx_cmd->timeout.pm_frame_timeout = 0;
-	}
-
-	tx_cmd->driver_txop = 0;
-	tx_cmd->tx_flags = tx_flags;
-	tx_cmd->next_frame_len = 0;
-}
-
-static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
-				     struct iwl_tx_cmd *tx_cmd,
-				     struct ieee80211_tx_info *info,
-				     __le16 fc)
-{
-	u32 rate_flags;
-	int rate_idx;
-	u8 rts_retry_limit;
-	u8 data_retry_limit;
-	u8 rate_plcp;
-
-	if (priv->wowlan) {
-		rts_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
-		data_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
-	} else {
-		/* Set retry limit on RTS packets */
-		rts_retry_limit = IWLAGN_RTS_DFAULT_RETRY_LIMIT;
-
-		/* Set retry limit on DATA packets and Probe Responses*/
-		if (ieee80211_is_probe_resp(fc)) {
-			data_retry_limit = IWLAGN_MGMT_DFAULT_RETRY_LIMIT;
-			rts_retry_limit =
-				min(data_retry_limit, rts_retry_limit);
-		} else if (ieee80211_is_back_req(fc))
-			data_retry_limit = IWLAGN_BAR_DFAULT_RETRY_LIMIT;
-		else
-			data_retry_limit = IWLAGN_DEFAULT_TX_RETRY;
-	}
-
-	tx_cmd->data_retry_limit = data_retry_limit;
-	tx_cmd->rts_retry_limit = rts_retry_limit;
-
-	/* DATA packets will use the uCode station table for rate/antenna
-	 * selection */
-	if (ieee80211_is_data(fc)) {
-		tx_cmd->initial_rate_index = 0;
-		tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-		if (priv->tm_fixed_rate) {
-			/*
-			 * rate overwrite by testmode
-			 * we not only send lq command to change rate
-			 * we also re-enforce per data pkt base.
-			 */
-			tx_cmd->tx_flags &= ~TX_CMD_FLG_STA_RATE_MSK;
-			memcpy(&tx_cmd->rate_n_flags, &priv->tm_fixed_rate,
-			       sizeof(tx_cmd->rate_n_flags));
-		}
-#endif
-		return;
-	} else if (ieee80211_is_back_req(fc))
-		tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
-
-	/**
-	 * If the current TX rate stored in mac80211 has the MCS bit set, it's
-	 * not really a TX rate.  Thus, we use the lowest supported rate for
-	 * this band.  Also use the lowest supported rate if the stored rate
-	 * index is invalid.
-	 */
-	rate_idx = info->control.rates[0].idx;
-	if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
-			(rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
-		rate_idx = rate_lowest_index(&priv->bands[info->band],
-				info->control.sta);
-	/* For 5 GHZ band, remap mac80211 rate indices into driver indices */
-	if (info->band == IEEE80211_BAND_5GHZ)
-		rate_idx += IWL_FIRST_OFDM_RATE;
-	/* Get PLCP rate for tx_cmd->rate_n_flags */
-	rate_plcp = iwl_rates[rate_idx].plcp;
-	/* Zero out flags for this packet */
-	rate_flags = 0;
-
-	/* Set CCK flag as needed */
-	if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
-		rate_flags |= RATE_MCS_CCK_MSK;
-
-	/* Set up antennas */
-	 if (priv->cfg->bt_params &&
-	     priv->cfg->bt_params->advanced_bt_coexist &&
-	     priv->bt_full_concurrent) {
-		/* operated as 1x1 in full concurrency mode */
-		priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
-				first_antenna(priv->hw_params.valid_tx_ant));
-	} else
-		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 */
-	tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags);
-}
-
-static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
-					 struct ieee80211_tx_info *info,
-					 struct iwl_tx_cmd *tx_cmd,
-					 struct sk_buff *skb_frag)
-{
-	struct ieee80211_key_conf *keyconf = info->control.hw_key;
-
-	switch (keyconf->cipher) {
-	case WLAN_CIPHER_SUITE_CCMP:
-		tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
-		memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
-		if (info->flags & IEEE80211_TX_CTL_AMPDU)
-			tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
-		IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
-		break;
-
-	case WLAN_CIPHER_SUITE_TKIP:
-		tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
-		ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
-		IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
-		break;
-
-	case WLAN_CIPHER_SUITE_WEP104:
-		tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
-		/* fall through */
-	case WLAN_CIPHER_SUITE_WEP40:
-		tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
-			(keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
-
-		memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
-
-		IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
-			     "with key %d\n", keyconf->keyidx);
-		break;
-
-	default:
-		IWL_ERR(priv, "Unknown encode cipher %x\n", keyconf->cipher);
-		break;
-	}
-}
-
-/**
- * iwl_sta_id_or_broadcast - return sta_id or broadcast sta
- * @context: the current context
- * @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 int iwl_sta_id_or_broadcast(struct iwl_rxon_context *context,
-				   struct ieee80211_sta *sta)
-{
-	int sta_id;
-
-	if (!sta)
-		return context->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;
-}
-
-/*
- * start REPLY_TX command process
- */
-int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
-{
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct iwl_station_priv *sta_priv = NULL;
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-	struct iwl_device_cmd *dev_cmd = NULL;
-	struct iwl_tx_cmd *tx_cmd;
-	__le16 fc;
-	u8 hdr_len;
-	u16 len, seq_number = 0;
-	u8 sta_id, tid = IWL_MAX_TID_COUNT;
-	bool is_agg = false;
-	int txq_id;
-
-	if (info->control.vif)
-		ctx = iwl_rxon_ctx_from_vif(info->control.vif);
-
-	if (iwl_is_rfkill(priv)) {
-		IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
-		goto drop_unlock_priv;
-	}
-
-	fc = hdr->frame_control;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (ieee80211_is_auth(fc))
-		IWL_DEBUG_TX(priv, "Sending AUTH frame\n");
-	else if (ieee80211_is_assoc_req(fc))
-		IWL_DEBUG_TX(priv, "Sending ASSOC frame\n");
-	else if (ieee80211_is_reassoc_req(fc))
-		IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
-#endif
-
-	if (unlikely(ieee80211_is_probe_resp(fc))) {
-		struct iwl_wipan_noa_data *noa_data =
-			rcu_dereference(priv->noa_data);
-
-		if (noa_data &&
-		    pskb_expand_head(skb, 0, noa_data->length,
-				     GFP_ATOMIC) == 0) {
-			memcpy(skb_put(skb, noa_data->length),
-			       noa_data->data, noa_data->length);
-			hdr = (struct ieee80211_hdr *)skb->data;
-		}
-	}
-
-	hdr_len = ieee80211_hdrlen(fc);
-
-	/* For management frames use broadcast id to do not break aggregation */
-	if (!ieee80211_is_data(fc))
-		sta_id = ctx->bcast_sta_id;
-	else {
-		/* Find index into station table for destination station */
-		sta_id = iwl_sta_id_or_broadcast(ctx, info->control.sta);
-		if (sta_id == IWL_INVALID_STATION) {
-			IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
-				       hdr->addr1);
-			goto drop_unlock_priv;
-		}
-	}
-
-	IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
-
-	if (info->control.sta)
-		sta_priv = (void *)info->control.sta->drv_priv;
-
-	if (sta_priv && sta_priv->asleep &&
-	    (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
-		/*
-		 * This sends an asynchronous command to the device,
-		 * but we can rely on it being processed before the
-		 * next frame is processed -- and the next frame to
-		 * this station is the one that will consume this
-		 * counter.
-		 * For now set the counter to just 1 since we do not
-		 * support uAPSD yet.
-		 *
-		 * FIXME: If we get two non-bufferable frames one
-		 * after the other, we might only send out one of
-		 * them because this is racy.
-		 */
-		iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
-	}
-
-	if (info->flags & IEEE80211_TX_CTL_AMPDU)
-		is_agg = true;
-
-	dev_cmd = kmem_cache_alloc(iwl_tx_cmd_pool, GFP_ATOMIC);
-
-	if (unlikely(!dev_cmd))
-		goto drop_unlock_priv;
-
-	memset(dev_cmd, 0, sizeof(*dev_cmd));
-	tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
-
-	/* Total # bytes to be transmitted */
-	len = (u16)skb->len;
-	tx_cmd->len = cpu_to_le16(len);
-
-	if (info->control.hw_key)
-		iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb);
-
-	/* TODO need this for burst mode later on */
-	iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id);
-
-	iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc);
-
-	memset(&info->status, 0, sizeof(info->status));
-
-	info->driver_data[0] = ctx;
-	info->driver_data[1] = dev_cmd;
-
-	spin_lock(&priv->sta_lock);
-
-	if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
-		u8 *qc = NULL;
-		struct iwl_tid_data *tid_data;
-		qc = ieee80211_get_qos_ctl(hdr);
-		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-		if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
-			goto drop_unlock_sta;
-		tid_data = &priv->tid_data[sta_id][tid];
-
-		/* aggregation is on for this <sta,tid> */
-		if (info->flags & IEEE80211_TX_CTL_AMPDU &&
-		    tid_data->agg.state != IWL_AGG_ON) {
-			IWL_ERR(priv, "TX_CTL_AMPDU while not in AGG:"
-				" Tx flags = 0x%08x, agg.state = %d",
-				info->flags, tid_data->agg.state);
-			IWL_ERR(priv, "sta_id = %d, tid = %d seq_num = %d",
-				sta_id, tid, SEQ_TO_SN(tid_data->seq_number));
-			goto drop_unlock_sta;
-		}
-
-		/* We can receive packets from the stack in IWL_AGG_{ON,OFF}
-		 * only. Check this here.
-		 */
-		if (WARN_ONCE(tid_data->agg.state != IWL_AGG_ON &&
-		    tid_data->agg.state != IWL_AGG_OFF,
-		    "Tx while agg.state = %d", tid_data->agg.state))
-			goto drop_unlock_sta;
-
-		seq_number = tid_data->seq_number;
-		seq_number &= IEEE80211_SCTL_SEQ;
-		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-		hdr->seq_ctrl |= cpu_to_le16(seq_number);
-		seq_number += 0x10;
-	}
-
-	/* Copy MAC header from skb into command buffer */
-	memcpy(tx_cmd->hdr, hdr, hdr_len);
-
-	if (is_agg)
-		txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
-	else if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
-		/*
-		 * Send this frame after DTIM -- there's a special queue
-		 * reserved for this for contexts that support AP mode.
-		 */
-		txq_id = ctx->mcast_queue;
-
-		/*
-		 * The microcode will clear the more data
-		 * bit in the last frame it transmits.
-		 */
-		hdr->frame_control |=
-			cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-	} else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
-		txq_id = IWL_AUX_QUEUE;
-	else
-		txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)];
-
-	WARN_ON_ONCE(!is_agg && txq_id != info->hw_queue);
-	WARN_ON_ONCE(is_agg &&
-		     priv->queue_to_mac80211[txq_id] != info->hw_queue);
-
-	if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id))
-		goto drop_unlock_sta;
-
-	if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc) &&
-	    !ieee80211_has_morefrags(fc))
-		priv->tid_data[sta_id][tid].seq_number = seq_number;
-
-	spin_unlock(&priv->sta_lock);
-
-	/*
-	 * Avoid atomic ops if it isn't an associated client.
-	 * Also, if this is a packet for aggregation, don't
-	 * increase the counter because the ucode will stop
-	 * aggregation queues when their respective station
-	 * goes to sleep.
-	 */
-	if (sta_priv && sta_priv->client && !is_agg)
-		atomic_inc(&sta_priv->pending_frames);
-
-	return 0;
-
-drop_unlock_sta:
-	if (dev_cmd)
-		kmem_cache_free(iwl_tx_cmd_pool, dev_cmd);
-	spin_unlock(&priv->sta_lock);
-drop_unlock_priv:
-	return -1;
-}
-
-static int iwlagn_alloc_agg_txq(struct iwl_priv *priv, int mq)
-{
-	int q;
-
-	for (q = IWLAGN_FIRST_AMPDU_QUEUE;
-	     q < priv->cfg->base_params->num_of_queues; q++) {
-		if (!test_and_set_bit(q, priv->agg_q_alloc)) {
-			priv->queue_to_mac80211[q] = mq;
-			return q;
-		}
-	}
-
-	return -ENOSPC;
-}
-
-static void iwlagn_dealloc_agg_txq(struct iwl_priv *priv, int q)
-{
-	clear_bit(q, priv->agg_q_alloc);
-	priv->queue_to_mac80211[q] = IWL_INVALID_MAC80211_QUEUE;
-}
-
-int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
-			struct ieee80211_sta *sta, u16 tid)
-{
-	struct iwl_tid_data *tid_data;
-	int sta_id, txq_id;
-	enum iwl_agg_state agg_state;
-
-	sta_id = iwl_sta_id(sta);
-
-	if (sta_id == IWL_INVALID_STATION) {
-		IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
-		return -ENXIO;
-	}
-
-	spin_lock_bh(&priv->sta_lock);
-
-	tid_data = &priv->tid_data[sta_id][tid];
-	txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
-
-	switch (priv->tid_data[sta_id][tid].agg.state) {
-	case IWL_EMPTYING_HW_QUEUE_ADDBA:
-		/*
-		* This can happen if the peer stops aggregation
-		* again before we've had a chance to drain the
-		* queue we selected previously, i.e. before the
-		* session was really started completely.
-		*/
-		IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
-		goto turn_off;
-	case IWL_AGG_STARTING:
-		/*
-		 * This can happen when the session is stopped before
-		 * we receive ADDBA response
-		 */
-		IWL_DEBUG_HT(priv, "AGG stop before AGG became operational\n");
-		goto turn_off;
-	case IWL_AGG_ON:
-		break;
-	default:
-		IWL_WARN(priv, "Stopping AGG while state not ON "
-			 "or starting for %d on %d (%d)\n", sta_id, tid,
-			 priv->tid_data[sta_id][tid].agg.state);
-		spin_unlock_bh(&priv->sta_lock);
-		return 0;
-	}
-
-	tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
-
-	/* There are still packets for this RA / TID in the HW */
-	if (!test_bit(txq_id, priv->agg_q_alloc)) {
-		IWL_DEBUG_TX_QUEUES(priv,
-			"stopping AGG on STA/TID %d/%d but hwq %d not used\n",
-			sta_id, tid, txq_id);
-	} else if (tid_data->agg.ssn != tid_data->next_reclaimed) {
-		IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
-				    "next_recl = %d\n",
-				    tid_data->agg.ssn,
-				    tid_data->next_reclaimed);
-		priv->tid_data[sta_id][tid].agg.state =
-			IWL_EMPTYING_HW_QUEUE_DELBA;
-		spin_unlock_bh(&priv->sta_lock);
-		return 0;
-	}
-
-	IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
-			    tid_data->agg.ssn);
-turn_off:
-	agg_state = priv->tid_data[sta_id][tid].agg.state;
-	priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
-
-	spin_unlock_bh(&priv->sta_lock);
-
-	if (test_bit(txq_id, priv->agg_q_alloc)) {
-		/*
-		 * If the transport didn't know that we wanted to start
-		 * agreggation, don't tell it that we want to stop them.
-		 * This can happen when we don't get the addBA response on
-		 * time, or we hadn't time to drain the AC queues.
-		 */
-		if (agg_state == IWL_AGG_ON)
-			iwl_trans_tx_agg_disable(priv->trans, txq_id);
-		else
-			IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
-					    agg_state);
-		iwlagn_dealloc_agg_txq(priv, txq_id);
-	}
-
-	ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-
-	return 0;
-}
-
-int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
-			struct ieee80211_sta *sta, u16 tid, u16 *ssn)
-{
-	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-	struct iwl_tid_data *tid_data;
-	int sta_id, txq_id, ret;
-
-	IWL_DEBUG_HT(priv, "TX AGG request on ra = %pM tid = %d\n",
-		     sta->addr, tid);
-
-	sta_id = iwl_sta_id(sta);
-	if (sta_id == IWL_INVALID_STATION) {
-		IWL_ERR(priv, "Start AGG on invalid station\n");
-		return -ENXIO;
-	}
-	if (unlikely(tid >= IWL_MAX_TID_COUNT))
-		return -EINVAL;
-
-	if (priv->tid_data[sta_id][tid].agg.state != IWL_AGG_OFF) {
-		IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
-		return -ENXIO;
-	}
-
-	txq_id = iwlagn_alloc_agg_txq(priv, ctx->ac_to_queue[tid_to_ac[tid]]);
-	if (txq_id < 0) {
-		IWL_DEBUG_TX_QUEUES(priv,
-			"No free aggregation queue for %pM/%d\n",
-			sta->addr, tid);
-		return txq_id;
-	}
-
-	ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
-	if (ret)
-		return ret;
-
-	spin_lock_bh(&priv->sta_lock);
-	tid_data = &priv->tid_data[sta_id][tid];
-	tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
-	tid_data->agg.txq_id = txq_id;
-
-	*ssn = tid_data->agg.ssn;
-
-	if (*ssn == tid_data->next_reclaimed) {
-		IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
-				    tid_data->agg.ssn);
-		tid_data->agg.state = IWL_AGG_STARTING;
-		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-	} else {
-		IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
-				    "next_reclaimed = %d\n",
-				    tid_data->agg.ssn,
-				    tid_data->next_reclaimed);
-		tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
-	}
-	spin_unlock_bh(&priv->sta_lock);
-
-	return ret;
-}
-
-int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
-			struct ieee80211_sta *sta, u16 tid, u8 buf_size)
-{
-	struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
-	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-	int q, fifo;
-	u16 ssn;
-
-	buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
-
-	spin_lock_bh(&priv->sta_lock);
-	ssn = priv->tid_data[sta_priv->sta_id][tid].agg.ssn;
-	q = priv->tid_data[sta_priv->sta_id][tid].agg.txq_id;
-	priv->tid_data[sta_priv->sta_id][tid].agg.state = IWL_AGG_ON;
-	spin_unlock_bh(&priv->sta_lock);
-
-	fifo = ctx->ac_to_fifo[tid_to_ac[tid]];
-
-	iwl_trans_tx_agg_setup(priv->trans, q, fifo,
-			       sta_priv->sta_id, tid,
-			       buf_size, ssn);
-
-	/*
-	 * If the limit is 0, then it wasn't initialised yet,
-	 * use the default. We can do that since we take the
-	 * minimum below, and we don't want to go above our
-	 * default due to hardware restrictions.
-	 */
-	if (sta_priv->max_agg_bufsize == 0)
-		sta_priv->max_agg_bufsize =
-			LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-
-	/*
-	 * Even though in theory the peer could have different
-	 * aggregation reorder buffer sizes for different sessions,
-	 * our ucode doesn't allow for that and has a global limit
-	 * for each station. Therefore, use the minimum of all the
-	 * aggregation sessions and our default value.
-	 */
-	sta_priv->max_agg_bufsize =
-		min(sta_priv->max_agg_bufsize, buf_size);
-
-	if (priv->hw_params.use_rts_for_aggregation) {
-		/*
-		 * switch to RTS/CTS if it is the prefer protection
-		 * method for HT traffic
-		 */
-
-		sta_priv->lq_sta.lq.general_params.flags |=
-			LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-	}
-	priv->agg_tids_count++;
-	IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
-		     priv->agg_tids_count);
-
-	sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
-		sta_priv->max_agg_bufsize;
-
-	IWL_DEBUG_HT(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
-		 sta->addr, tid);
-
-	return iwl_send_lq_cmd(priv, ctx,
-			&sta_priv->lq_sta.lq, CMD_ASYNC, false);
-}
-
-static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid)
-{
-	struct iwl_tid_data *tid_data = &priv->tid_data[sta_id][tid];
-	enum iwl_rxon_context_id ctx;
-	struct ieee80211_vif *vif;
-	u8 *addr;
-
-	lockdep_assert_held(&priv->sta_lock);
-
-	addr = priv->stations[sta_id].sta.sta.addr;
-	ctx = priv->stations[sta_id].ctxid;
-	vif = priv->contexts[ctx].vif;
-
-	switch (priv->tid_data[sta_id][tid].agg.state) {
-	case IWL_EMPTYING_HW_QUEUE_DELBA:
-		/* There are no packets for this RA / TID in the HW any more */
-		if (tid_data->agg.ssn == tid_data->next_reclaimed) {
-			IWL_DEBUG_TX_QUEUES(priv,
-				"Can continue DELBA flow ssn = next_recl ="
-				" %d", tid_data->next_reclaimed);
-			iwl_trans_tx_agg_disable(priv->trans,
-						 tid_data->agg.txq_id);
-			iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id);
-			tid_data->agg.state = IWL_AGG_OFF;
-			ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
-		}
-		break;
-	case IWL_EMPTYING_HW_QUEUE_ADDBA:
-		/* There are no packets for this RA / TID in the HW any more */
-		if (tid_data->agg.ssn == tid_data->next_reclaimed) {
-			IWL_DEBUG_TX_QUEUES(priv,
-				"Can continue ADDBA flow ssn = next_recl ="
-				" %d", tid_data->next_reclaimed);
-			tid_data->agg.state = IWL_AGG_STARTING;
-			ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-static void iwlagn_non_agg_tx_status(struct iwl_priv *priv,
-				     struct iwl_rxon_context *ctx,
-				     const u8 *addr1)
-{
-	struct ieee80211_sta *sta;
-	struct iwl_station_priv *sta_priv;
-
-	rcu_read_lock();
-	sta = ieee80211_find_sta(ctx->vif, addr1);
-	if (sta) {
-		sta_priv = (void *)sta->drv_priv;
-		/* avoid atomic ops if this isn't a client */
-		if (sta_priv->client &&
-		    atomic_dec_return(&sta_priv->pending_frames) == 0)
-			ieee80211_sta_block_awake(priv->hw, sta, false);
-	}
-	rcu_read_unlock();
-}
-
-/**
- * translate ucode response to mac80211 tx status control values
- */
-static void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
-				  struct ieee80211_tx_info *info)
-{
-	struct ieee80211_tx_rate *r = &info->status.rates[0];
-
-	info->status.antenna =
-		((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
-	if (rate_n_flags & RATE_MCS_HT_MSK)
-		r->flags |= IEEE80211_TX_RC_MCS;
-	if (rate_n_flags & RATE_MCS_GF_MSK)
-		r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
-	if (rate_n_flags & RATE_MCS_HT40_MSK)
-		r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
-	if (rate_n_flags & RATE_MCS_DUP_MSK)
-		r->flags |= IEEE80211_TX_RC_DUP_DATA;
-	if (rate_n_flags & RATE_MCS_SGI_MSK)
-		r->flags |= IEEE80211_TX_RC_SHORT_GI;
-	r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-const char *iwl_get_tx_fail_reason(u32 status)
-{
-#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
-#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
-
-	switch (status & TX_STATUS_MSK) {
-	case TX_STATUS_SUCCESS:
-		return "SUCCESS";
-	TX_STATUS_POSTPONE(DELAY);
-	TX_STATUS_POSTPONE(FEW_BYTES);
-	TX_STATUS_POSTPONE(BT_PRIO);
-	TX_STATUS_POSTPONE(QUIET_PERIOD);
-	TX_STATUS_POSTPONE(CALC_TTAK);
-	TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY);
-	TX_STATUS_FAIL(SHORT_LIMIT);
-	TX_STATUS_FAIL(LONG_LIMIT);
-	TX_STATUS_FAIL(FIFO_UNDERRUN);
-	TX_STATUS_FAIL(DRAIN_FLOW);
-	TX_STATUS_FAIL(RFKILL_FLUSH);
-	TX_STATUS_FAIL(LIFE_EXPIRE);
-	TX_STATUS_FAIL(DEST_PS);
-	TX_STATUS_FAIL(HOST_ABORTED);
-	TX_STATUS_FAIL(BT_RETRY);
-	TX_STATUS_FAIL(STA_INVALID);
-	TX_STATUS_FAIL(FRAG_DROPPED);
-	TX_STATUS_FAIL(TID_DISABLE);
-	TX_STATUS_FAIL(FIFO_FLUSHED);
-	TX_STATUS_FAIL(INSUFFICIENT_CF_POLL);
-	TX_STATUS_FAIL(PASSIVE_NO_RX);
-	TX_STATUS_FAIL(NO_BEACON_ON_RADAR);
-	}
-
-	return "UNKNOWN";
-
-#undef TX_STATUS_FAIL
-#undef TX_STATUS_POSTPONE
-}
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
-{
-	status &= AGG_TX_STATUS_MSK;
-
-	switch (status) {
-	case AGG_TX_STATE_UNDERRUN_MSK:
-		priv->reply_agg_tx_stats.underrun++;
-		break;
-	case AGG_TX_STATE_BT_PRIO_MSK:
-		priv->reply_agg_tx_stats.bt_prio++;
-		break;
-	case AGG_TX_STATE_FEW_BYTES_MSK:
-		priv->reply_agg_tx_stats.few_bytes++;
-		break;
-	case AGG_TX_STATE_ABORT_MSK:
-		priv->reply_agg_tx_stats.abort++;
-		break;
-	case AGG_TX_STATE_LAST_SENT_TTL_MSK:
-		priv->reply_agg_tx_stats.last_sent_ttl++;
-		break;
-	case AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK:
-		priv->reply_agg_tx_stats.last_sent_try++;
-		break;
-	case AGG_TX_STATE_LAST_SENT_BT_KILL_MSK:
-		priv->reply_agg_tx_stats.last_sent_bt_kill++;
-		break;
-	case AGG_TX_STATE_SCD_QUERY_MSK:
-		priv->reply_agg_tx_stats.scd_query++;
-		break;
-	case AGG_TX_STATE_TEST_BAD_CRC32_MSK:
-		priv->reply_agg_tx_stats.bad_crc32++;
-		break;
-	case AGG_TX_STATE_RESPONSE_MSK:
-		priv->reply_agg_tx_stats.response++;
-		break;
-	case AGG_TX_STATE_DUMP_TX_MSK:
-		priv->reply_agg_tx_stats.dump_tx++;
-		break;
-	case AGG_TX_STATE_DELAY_TX_MSK:
-		priv->reply_agg_tx_stats.delay_tx++;
-		break;
-	default:
-		priv->reply_agg_tx_stats.unknown++;
-		break;
-	}
-}
-
-static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
-				struct iwlagn_tx_resp *tx_resp)
-{
-	struct agg_tx_status *frame_status = &tx_resp->status;
-	int tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
-		IWLAGN_TX_RES_TID_POS;
-	int sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
-		IWLAGN_TX_RES_RA_POS;
-	struct iwl_ht_agg *agg = &priv->tid_data[sta_id][tid].agg;
-	u32 status = le16_to_cpu(tx_resp->status.status);
-	int i;
-
-	WARN_ON(tid == IWL_TID_NON_QOS);
-
-	if (agg->wait_for_ba)
-		IWL_DEBUG_TX_REPLY(priv,
-			"got tx response w/o block-ack\n");
-
-	agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
-	agg->wait_for_ba = (tx_resp->frame_count > 1);
-
-	/*
-	 * If the BT kill count is non-zero, we'll get this
-	 * notification again.
-	 */
-	if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 &&
-	    priv->cfg->bt_params &&
-	    priv->cfg->bt_params->advanced_bt_coexist) {
-		IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n");
-	}
-
-	if (tx_resp->frame_count == 1)
-		return;
-
-	/* Construct bit-map of pending frames within Tx window */
-	for (i = 0; i < tx_resp->frame_count; i++) {
-		u16 fstatus = le16_to_cpu(frame_status[i].status);
-
-		if (status & AGG_TX_STATUS_MSK)
-			iwlagn_count_agg_tx_err_status(priv, fstatus);
-
-		if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
-			      AGG_TX_STATE_ABORT_MSK))
-			continue;
-
-		IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
-				   "try-count (0x%08x)\n",
-				   iwl_get_agg_tx_fail_reason(fstatus),
-				   fstatus & AGG_TX_STATUS_MSK,
-				   fstatus & AGG_TX_TRY_MSK);
-	}
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define AGG_TX_STATE_FAIL(x) case AGG_TX_STATE_ ## x: return #x
-
-const char *iwl_get_agg_tx_fail_reason(u16 status)
-{
-	status &= AGG_TX_STATUS_MSK;
-	switch (status) {
-	case AGG_TX_STATE_TRANSMITTED:
-		return "SUCCESS";
-		AGG_TX_STATE_FAIL(UNDERRUN_MSK);
-		AGG_TX_STATE_FAIL(BT_PRIO_MSK);
-		AGG_TX_STATE_FAIL(FEW_BYTES_MSK);
-		AGG_TX_STATE_FAIL(ABORT_MSK);
-		AGG_TX_STATE_FAIL(LAST_SENT_TTL_MSK);
-		AGG_TX_STATE_FAIL(LAST_SENT_TRY_CNT_MSK);
-		AGG_TX_STATE_FAIL(LAST_SENT_BT_KILL_MSK);
-		AGG_TX_STATE_FAIL(SCD_QUERY_MSK);
-		AGG_TX_STATE_FAIL(TEST_BAD_CRC32_MSK);
-		AGG_TX_STATE_FAIL(RESPONSE_MSK);
-		AGG_TX_STATE_FAIL(DUMP_TX_MSK);
-		AGG_TX_STATE_FAIL(DELAY_TX_MSK);
-	}
-
-	return "UNKNOWN";
-}
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
-{
-	return le32_to_cpup((__le32 *)&tx_resp->status +
-			    tx_resp->frame_count) & MAX_SN;
-}
-
-static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)
-{
-	status &= TX_STATUS_MSK;
-
-	switch (status) {
-	case TX_STATUS_POSTPONE_DELAY:
-		priv->reply_tx_stats.pp_delay++;
-		break;
-	case TX_STATUS_POSTPONE_FEW_BYTES:
-		priv->reply_tx_stats.pp_few_bytes++;
-		break;
-	case TX_STATUS_POSTPONE_BT_PRIO:
-		priv->reply_tx_stats.pp_bt_prio++;
-		break;
-	case TX_STATUS_POSTPONE_QUIET_PERIOD:
-		priv->reply_tx_stats.pp_quiet_period++;
-		break;
-	case TX_STATUS_POSTPONE_CALC_TTAK:
-		priv->reply_tx_stats.pp_calc_ttak++;
-		break;
-	case TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY:
-		priv->reply_tx_stats.int_crossed_retry++;
-		break;
-	case TX_STATUS_FAIL_SHORT_LIMIT:
-		priv->reply_tx_stats.short_limit++;
-		break;
-	case TX_STATUS_FAIL_LONG_LIMIT:
-		priv->reply_tx_stats.long_limit++;
-		break;
-	case TX_STATUS_FAIL_FIFO_UNDERRUN:
-		priv->reply_tx_stats.fifo_underrun++;
-		break;
-	case TX_STATUS_FAIL_DRAIN_FLOW:
-		priv->reply_tx_stats.drain_flow++;
-		break;
-	case TX_STATUS_FAIL_RFKILL_FLUSH:
-		priv->reply_tx_stats.rfkill_flush++;
-		break;
-	case TX_STATUS_FAIL_LIFE_EXPIRE:
-		priv->reply_tx_stats.life_expire++;
-		break;
-	case TX_STATUS_FAIL_DEST_PS:
-		priv->reply_tx_stats.dest_ps++;
-		break;
-	case TX_STATUS_FAIL_HOST_ABORTED:
-		priv->reply_tx_stats.host_abort++;
-		break;
-	case TX_STATUS_FAIL_BT_RETRY:
-		priv->reply_tx_stats.bt_retry++;
-		break;
-	case TX_STATUS_FAIL_STA_INVALID:
-		priv->reply_tx_stats.sta_invalid++;
-		break;
-	case TX_STATUS_FAIL_FRAG_DROPPED:
-		priv->reply_tx_stats.frag_drop++;
-		break;
-	case TX_STATUS_FAIL_TID_DISABLE:
-		priv->reply_tx_stats.tid_disable++;
-		break;
-	case TX_STATUS_FAIL_FIFO_FLUSHED:
-		priv->reply_tx_stats.fifo_flush++;
-		break;
-	case TX_STATUS_FAIL_INSUFFICIENT_CF_POLL:
-		priv->reply_tx_stats.insuff_cf_poll++;
-		break;
-	case TX_STATUS_FAIL_PASSIVE_NO_RX:
-		priv->reply_tx_stats.fail_hw_drop++;
-		break;
-	case TX_STATUS_FAIL_NO_BEACON_ON_RADAR:
-		priv->reply_tx_stats.sta_color_mismatch++;
-		break;
-	default:
-		priv->reply_tx_stats.unknown++;
-		break;
-	}
-}
-
-static void iwlagn_set_tx_status(struct iwl_priv *priv,
-				 struct ieee80211_tx_info *info,
-				 struct iwlagn_tx_resp *tx_resp,
-				 bool is_agg)
-{
-	u16  status = le16_to_cpu(tx_resp->status.status);
-
-	info->status.rates[0].count = tx_resp->failure_frame + 1;
-	if (is_agg)
-		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-	info->flags |= iwl_tx_status_to_mac80211(status);
-	iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
-				    info);
-	if (!iwl_is_tx_success(status))
-		iwlagn_count_tx_err_status(priv, status);
-}
-
-static void iwl_check_abort_status(struct iwl_priv *priv,
-			    u8 frame_count, u32 status)
-{
-	if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
-		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);
-	}
-}
-
-static int iwl_reclaim(struct iwl_priv *priv, int sta_id, int tid,
-		       int txq_id, int ssn, struct sk_buff_head *skbs)
-{
-	if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE &&
-		     tid != IWL_TID_NON_QOS &&
-		     txq_id != priv->tid_data[sta_id][tid].agg.txq_id)) {
-		/*
-		 * FIXME: this is a uCode bug which need to be addressed,
-		 * log the information and return for now.
-		 * Since it is can possibly happen very often and in order
-		 * not to fill the syslog, don't use IWL_ERR or IWL_WARN
-		 */
-		IWL_DEBUG_TX_QUEUES(priv,
-			"Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n",
-			txq_id, sta_id, tid,
-			priv->tid_data[sta_id][tid].agg.txq_id);
-		return 1;
-	}
-
-	iwl_trans_reclaim(priv->trans, txq_id, ssn, skbs);
-	return 0;
-}
-
-int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-			       struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
-	int txq_id = SEQ_TO_QUEUE(sequence);
-	int cmd_index __maybe_unused = SEQ_TO_INDEX(sequence);
-	struct iwlagn_tx_resp *tx_resp = (void *)pkt->data;
-	struct ieee80211_hdr *hdr;
-	u32 status = le16_to_cpu(tx_resp->status.status);
-	u16 ssn = iwlagn_get_scd_ssn(tx_resp);
-	int tid;
-	int sta_id;
-	int freed;
-	struct ieee80211_tx_info *info;
-	struct sk_buff_head skbs;
-	struct sk_buff *skb;
-	struct iwl_rxon_context *ctx;
-	bool is_agg = (txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
-
-	tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
-		IWLAGN_TX_RES_TID_POS;
-	sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
-		IWLAGN_TX_RES_RA_POS;
-
-	spin_lock(&priv->sta_lock);
-
-	if (is_agg)
-		iwl_rx_reply_tx_agg(priv, tx_resp);
-
-	__skb_queue_head_init(&skbs);
-
-	if (tx_resp->frame_count == 1) {
-		u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl);
-		next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10);
-
-		if (is_agg) {
-			/* If this is an aggregation queue, we can rely on the
-			 * ssn since the wifi sequence number corresponds to
-			 * the index in the TFD ring (%256).
-			 * The seq_ctl is the sequence control of the packet
-			 * to which this Tx response relates. But if there is a
-			 * hole in the bitmap of the BA we received, this Tx
-			 * response may allow to reclaim the hole and all the
-			 * subsequent packets that were already acked.
-			 * In that case, seq_ctl != ssn, and the next packet
-			 * to be reclaimed will be ssn and not seq_ctl.
-			 */
-			next_reclaimed = ssn;
-		}
-
-		if (tid != IWL_TID_NON_QOS) {
-			priv->tid_data[sta_id][tid].next_reclaimed =
-				next_reclaimed;
-			IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n",
-						  next_reclaimed);
-		}
-
-		/*we can free until ssn % q.n_bd not inclusive */
-		WARN_ON(iwl_reclaim(priv, sta_id, tid, txq_id, ssn, &skbs));
-		iwlagn_check_ratid_empty(priv, sta_id, tid);
-		freed = 0;
-
-		/* process frames */
-		skb_queue_walk(&skbs, skb) {
-			hdr = (struct ieee80211_hdr *)skb->data;
-
-			if (!ieee80211_is_data_qos(hdr->frame_control))
-				priv->last_seq_ctl = tx_resp->seq_ctl;
-
-			info = IEEE80211_SKB_CB(skb);
-			ctx = info->driver_data[0];
-			kmem_cache_free(iwl_tx_cmd_pool,
-					(info->driver_data[1]));
-
-			memset(&info->status, 0, sizeof(info->status));
-
-			if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
-			    iwl_is_associated_ctx(ctx) && ctx->vif &&
-			    ctx->vif->type == NL80211_IFTYPE_STATION) {
-				/* block and stop all queues */
-				priv->passive_no_rx = true;
-				IWL_DEBUG_TX_QUEUES(priv, "stop all queues: "
-						    "passive channel");
-				ieee80211_stop_queues(priv->hw);
-
-				IWL_DEBUG_TX_REPLY(priv,
-					   "TXQ %d status %s (0x%08x) "
-					   "rate_n_flags 0x%x retries %d\n",
-					   txq_id,
-					   iwl_get_tx_fail_reason(status),
-					   status,
-					   le32_to_cpu(tx_resp->rate_n_flags),
-					   tx_resp->failure_frame);
-
-				IWL_DEBUG_TX_REPLY(priv,
-					   "FrameCnt = %d, idx=%d\n",
-					   tx_resp->frame_count, cmd_index);
-			}
-
-			/* check if BAR is needed */
-			if (is_agg && !iwl_is_tx_success(status))
-				info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
-			iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(skb),
-				     tx_resp, is_agg);
-			if (!is_agg)
-				iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1);
-
-			freed++;
-		}
-
-		WARN_ON(!is_agg && freed != 1);
-	}
-
-	iwl_check_abort_status(priv, tx_resp->frame_count, status);
-	spin_unlock(&priv->sta_lock);
-
-	while (!skb_queue_empty(&skbs)) {
-		skb = __skb_dequeue(&skbs);
-		ieee80211_tx_status(priv->hw, skb);
-	}
-
-	return 0;
-}
-
-/**
- * iwlagn_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
- *
- * Handles block-acknowledge notification from device, which reports success
- * of frames sent via aggregation.
- */
-int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
-				   struct iwl_rx_cmd_buffer *rxb,
-				   struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data;
-	struct iwl_ht_agg *agg;
-	struct sk_buff_head reclaimed_skbs;
-	struct ieee80211_tx_info *info;
-	struct ieee80211_hdr *hdr;
-	struct sk_buff *skb;
-	int sta_id;
-	int tid;
-	int freed;
-
-	/* "flow" corresponds to Tx queue */
-	u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
-
-	/* "ssn" is start of block-ack Tx window, corresponds to index
-	 * (in Tx queue's circular buffer) of first TFD/frame in window */
-	u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
-
-	if (scd_flow >= priv->cfg->base_params->num_of_queues) {
-		IWL_ERR(priv,
-			"BUG_ON scd_flow is bigger than number of queues\n");
-		return 0;
-	}
-
-	sta_id = ba_resp->sta_id;
-	tid = ba_resp->tid;
-	agg = &priv->tid_data[sta_id][tid].agg;
-
-	spin_lock(&priv->sta_lock);
-
-	if (unlikely(!agg->wait_for_ba)) {
-		if (unlikely(ba_resp->bitmap))
-			IWL_ERR(priv, "Received BA when not expected\n");
-		spin_unlock(&priv->sta_lock);
-		return 0;
-	}
-
-	__skb_queue_head_init(&reclaimed_skbs);
-
-	/* Release all TFDs before the SSN, i.e. all TFDs in front of
-	 * block-ack window (we assume that they've been successfully
-	 * transmitted ... if not, it's too late anyway). */
-	if (iwl_reclaim(priv, sta_id, tid, scd_flow,
-			ba_resp_scd_ssn, &reclaimed_skbs)) {
-		spin_unlock(&priv->sta_lock);
-		return 0;
-	}
-
-	IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
-			   "sta_id = %d\n",
-			   agg->wait_for_ba,
-			   (u8 *) &ba_resp->sta_addr_lo32,
-			   ba_resp->sta_id);
-	IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, "
-			   "scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n",
-			   ba_resp->tid, le16_to_cpu(ba_resp->seq_ctl),
-			   (unsigned long long)le64_to_cpu(ba_resp->bitmap),
-			   scd_flow, ba_resp_scd_ssn, ba_resp->txed,
-			   ba_resp->txed_2_done);
-
-	/* Mark that the expected block-ack response arrived */
-	agg->wait_for_ba = false;
-
-	/* Sanity check values reported by uCode */
-	if (ba_resp->txed_2_done > ba_resp->txed) {
-		IWL_DEBUG_TX_REPLY(priv,
-			"bogus sent(%d) and ack(%d) count\n",
-			ba_resp->txed, ba_resp->txed_2_done);
-		/*
-		 * set txed_2_done = txed,
-		 * so it won't impact rate scale
-		 */
-		ba_resp->txed = ba_resp->txed_2_done;
-	}
-
-	priv->tid_data[sta_id][tid].next_reclaimed = ba_resp_scd_ssn;
-
-	iwlagn_check_ratid_empty(priv, sta_id, tid);
-	freed = 0;
-
-	skb_queue_walk(&reclaimed_skbs, skb) {
-		hdr = (struct ieee80211_hdr *)skb->data;
-
-		if (ieee80211_is_data_qos(hdr->frame_control))
-			freed++;
-		else
-			WARN_ON_ONCE(1);
-
-		info = IEEE80211_SKB_CB(skb);
-		kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1]));
-
-		if (freed == 1) {
-			/* this is the first skb we deliver in this batch */
-			/* put the rate scaling data there */
-			info = IEEE80211_SKB_CB(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 = ba_resp->txed_2_done;
-			info->status.ampdu_len = ba_resp->txed;
-			iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags,
-						    info);
-		}
-	}
-
-	spin_unlock(&priv->sta_lock);
-
-	while (!skb_queue_empty(&reclaimed_skbs)) {
-		skb = __skb_dequeue(&reclaimed_skbs);
-		ieee80211_tx_status(priv->hw, skb);
-	}
-
-	return 0;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
deleted file mode 100644
index ec36e2b..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ /dev/null
@@ -1,2367 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-
-#include <net/mac80211.h>
-
-#include <asm/div64.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-calib.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-#include "iwl-op-mode.h"
-#include "iwl-drv.h"
-#include "iwl-modparams.h"
-
-/******************************************************************************
- *
- * module boiler plate
- *
- ******************************************************************************/
-
-/*
- * module name, copyright, version, etc.
- */
-#define DRV_DESCRIPTION	"Intel(R) Wireless WiFi Link AGN driver for Linux"
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define VD "d"
-#else
-#define VD
-#endif
-
-#define DRV_VERSION     IWLWIFI_VERSION VD
-
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("iwlagn");
-
-void iwl_update_chain_flags(struct iwl_priv *priv)
-{
-	struct iwl_rxon_context *ctx;
-
-	for_each_context(priv, ctx) {
-		iwlagn_set_rxon_chain(priv, ctx);
-		if (ctx->active.rx_chain != ctx->staging.rx_chain)
-			iwlagn_commit_rxon(priv, ctx);
-	}
-}
-
-/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */
-static void iwl_set_beacon_tim(struct iwl_priv *priv,
-			       struct iwl_tx_beacon_cmd *tx_beacon_cmd,
-			       u8 *beacon, u32 frame_size)
-{
-	u16 tim_idx;
-	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
-
-	/*
-	 * The index is relative to frame start but we start looking at the
-	 * variable-length part of the beacon.
-	 */
-	tim_idx = mgmt->u.beacon.variable - beacon;
-
-	/* Parse variable-length elements of beacon to find WLAN_EID_TIM */
-	while ((tim_idx < (frame_size - 2)) &&
-			(beacon[tim_idx] != WLAN_EID_TIM))
-		tim_idx += beacon[tim_idx+1] + 2;
-
-	/* If TIM field was found, set variables */
-	if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) {
-		tx_beacon_cmd->tim_idx = cpu_to_le16(tim_idx);
-		tx_beacon_cmd->tim_size = beacon[tim_idx+1];
-	} else
-		IWL_WARN(priv, "Unable to find TIM Element in beacon\n");
-}
-
-int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
-{
-	struct iwl_tx_beacon_cmd *tx_beacon_cmd;
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_TX_BEACON,
-		.flags = CMD_SYNC,
-	};
-	struct ieee80211_tx_info *info;
-	u32 frame_size;
-	u32 rate_flags;
-	u32 rate;
-
-	/*
-	 * We have to set up the TX command, the TX Beacon command, and the
-	 * beacon contents.
-	 */
-
-	lockdep_assert_held(&priv->mutex);
-
-	if (!priv->beacon_ctx) {
-		IWL_ERR(priv, "trying to build beacon w/o beacon context!\n");
-		return 0;
-	}
-
-	if (WARN_ON(!priv->beacon_skb))
-		return -EINVAL;
-
-	/* Allocate beacon command */
-	if (!priv->beacon_cmd)
-		priv->beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd), GFP_KERNEL);
-	tx_beacon_cmd = priv->beacon_cmd;
-	if (!tx_beacon_cmd)
-		return -ENOMEM;
-
-	frame_size = priv->beacon_skb->len;
-
-	/* Set up TX command fields */
-	tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
-	tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id;
-	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-	tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
-		TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
-
-	/* Set up TX beacon command fields */
-	iwl_set_beacon_tim(priv, tx_beacon_cmd, priv->beacon_skb->data,
-			   frame_size);
-
-	/* Set up packet rate and flags */
-	info = IEEE80211_SKB_CB(priv->beacon_skb);
-
-	/*
-	 * Let's set up the rate at least somewhat correctly;
-	 * it will currently not actually be used by the uCode,
-	 * it uses the broadcast station's rate instead.
-	 */
-	if (info->control.rates[0].idx < 0 ||
-	    info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
-		rate = 0;
-	else
-		rate = info->control.rates[0].idx;
-
-	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);
-
-	/* In mac80211, rates for 5 GHz start at 0 */
-	if (info->band == IEEE80211_BAND_5GHZ)
-		rate += IWL_FIRST_OFDM_RATE;
-	else if (rate >= IWL_FIRST_CCK_RATE && rate <= IWL_LAST_CCK_RATE)
-		rate_flags |= RATE_MCS_CCK_MSK;
-
-	tx_beacon_cmd->tx.rate_n_flags =
-			iwl_hw_set_rate_n_flags(rate, rate_flags);
-
-	/* Submit command */
-	cmd.len[0] = sizeof(*tx_beacon_cmd);
-	cmd.data[0] = tx_beacon_cmd;
-	cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-	cmd.len[1] = frame_size;
-	cmd.data[1] = priv->beacon_skb->data;
-	cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
-
-	return iwl_dvm_send_cmd(priv, &cmd);
-}
-
-static void iwl_bg_beacon_update(struct work_struct *work)
-{
-	struct iwl_priv *priv =
-		container_of(work, struct iwl_priv, beacon_update);
-	struct sk_buff *beacon;
-
-	mutex_lock(&priv->mutex);
-	if (!priv->beacon_ctx) {
-		IWL_ERR(priv, "updating beacon w/o beacon context!\n");
-		goto out;
-	}
-
-	if (priv->beacon_ctx->vif->type != NL80211_IFTYPE_AP) {
-		/*
-		 * The ucode will send beacon notifications even in
-		 * IBSS mode, but we don't want to process them. But
-		 * we need to defer the type check to here due to
-		 * requiring locking around the beacon_ctx access.
-		 */
-		goto out;
-	}
-
-	/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-	beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif);
-	if (!beacon) {
-		IWL_ERR(priv, "update beacon failed -- keeping old\n");
-		goto out;
-	}
-
-	/* new beacon skb is allocated every time; dispose previous.*/
-	dev_kfree_skb(priv->beacon_skb);
-
-	priv->beacon_skb = beacon;
-
-	iwlagn_send_beacon_cmd(priv);
- out:
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_bt_runtime_config(struct work_struct *work)
-{
-	struct iwl_priv *priv =
-		container_of(work, struct iwl_priv, bt_runtime_config);
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	/* dont send host command if rf-kill is on */
-	if (!iwl_is_ready_rf(priv))
-		return;
-	iwlagn_send_advance_bt_config(priv);
-}
-
-static void iwl_bg_bt_full_concurrency(struct work_struct *work)
-{
-	struct iwl_priv *priv =
-		container_of(work, struct iwl_priv, bt_full_concurrency);
-	struct iwl_rxon_context *ctx;
-
-	mutex_lock(&priv->mutex);
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		goto out;
-
-	/* dont send host command if rf-kill is on */
-	if (!iwl_is_ready_rf(priv))
-		goto out;
-
-	IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
-		       priv->bt_full_concurrent ?
-		       "full concurrency" : "3-wire");
-
-	/*
-	 * LQ & RXON updated cmds must be sent before BT Config cmd
-	 * to avoid 3-wire collisions
-	 */
-	for_each_context(priv, ctx) {
-		iwlagn_set_rxon_chain(priv, ctx);
-		iwlagn_commit_rxon(priv, ctx);
-	}
-
-	iwlagn_send_advance_bt_config(priv);
-out:
-	mutex_unlock(&priv->mutex);
-}
-
-int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
-{
-	struct iwl_statistics_cmd statistics_cmd = {
-		.configuration_flags =
-			clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
-	};
-
-	if (flags & CMD_ASYNC)
-		return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
-					CMD_ASYNC,
-					sizeof(struct iwl_statistics_cmd),
-					&statistics_cmd);
-	else
-		return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
-					CMD_SYNC,
-					sizeof(struct iwl_statistics_cmd),
-					&statistics_cmd);
-}
-
-/**
- * iwl_bg_statistics_periodic - Timer callback to queue statistics
- *
- * This callback is provided in order to send a statistics request.
- *
- * This timer function is continually reset to execute within
- * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
- * was received.  We need to ensure we receive the statistics in order
- * to update the temperature used for calibrating the TXPOWER.
- */
-static void iwl_bg_statistics_periodic(unsigned long data)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)data;
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	/* dont send host command if rf-kill is on */
-	if (!iwl_is_ready_rf(priv))
-		return;
-
-	iwl_send_statistics_request(priv, CMD_ASYNC, false);
-}
-
-
-static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
-					u32 start_idx, u32 num_events,
-					u32 capacity, u32 mode)
-{
-	u32 i;
-	u32 ptr;        /* SRAM byte address of log data */
-	u32 ev, time, data; /* event log data */
-	unsigned long reg_flags;
-
-	if (mode == 0)
-		ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32));
-	else
-		ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
-
-	/* Make sure device is powered up for SRAM reads */
-	spin_lock_irqsave(&priv->trans->reg_lock, reg_flags);
-	if (unlikely(!iwl_grab_nic_access(priv->trans))) {
-		spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
-		return;
-	}
-
-	/* Set starting address; reads will auto-increment */
-	iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr);
-
-	/*
-	 * Refuse to read more than would have fit into the log from
-	 * the current start_idx. This used to happen due to the race
-	 * described below, but now WARN because the code below should
-	 * prevent it from happening here.
-	 */
-	if (WARN_ON(num_events > capacity - start_idx))
-		num_events = capacity - start_idx;
-
-	/*
-	 * "time" is actually "data" for mode 0 (no timestamp).
-	 * place event id # at far right for easier visual parsing.
-	 */
-	for (i = 0; i < num_events; i++) {
-		ev = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-		time = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-		if (mode == 0) {
-			trace_iwlwifi_dev_ucode_cont_event(
-					priv->trans->dev, 0, time, ev);
-		} else {
-			data = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-			trace_iwlwifi_dev_ucode_cont_event(
-					priv->trans->dev, time, data, ev);
-		}
-	}
-	/* Allow device to power down */
-	iwl_release_nic_access(priv->trans);
-	spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
-}
-
-static void iwl_continuous_event_trace(struct iwl_priv *priv)
-{
-	u32 capacity;   /* event log capacity in # entries */
-	struct {
-		u32 capacity;
-		u32 mode;
-		u32 wrap_counter;
-		u32 write_counter;
-	} __packed read;
-	u32 base;       /* SRAM byte address of event log header */
-	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
-	u32 num_wraps;  /* # times uCode wrapped to top of log */
-	u32 next_entry; /* index of next entry to be written by uCode */
-
-	base = priv->device_pointers.log_event_table;
-	if (iwlagn_hw_valid_rtc_data_addr(base)) {
-		iwl_read_targ_mem_words(priv->trans, base, &read, sizeof(read));
-		capacity = read.capacity;
-		mode = read.mode;
-		num_wraps = read.wrap_counter;
-		next_entry = read.write_counter;
-	} else
-		return;
-
-	/*
-	 * Unfortunately, the uCode doesn't use temporary variables.
-	 * Therefore, it can happen that we read next_entry == capacity,
-	 * which really means next_entry == 0.
-	 */
-	if (unlikely(next_entry == capacity))
-		next_entry = 0;
-	/*
-	 * Additionally, the uCode increases the write pointer before
-	 * the wraps counter, so if the write pointer is smaller than
-	 * the old write pointer (wrap occurred) but we read that no
-	 * wrap occurred, we actually read between the next_entry and
-	 * num_wraps update (this does happen in practice!!) -- take
-	 * that into account by increasing num_wraps.
-	 */
-	if (unlikely(next_entry < priv->event_log.next_entry &&
-		     num_wraps == priv->event_log.num_wraps))
-		num_wraps++;
-
-	if (num_wraps == priv->event_log.num_wraps) {
-		iwl_print_cont_event_trace(
-			priv, base, priv->event_log.next_entry,
-			next_entry - priv->event_log.next_entry,
-			capacity, mode);
-
-		priv->event_log.non_wraps_count++;
-	} else {
-		if (num_wraps - priv->event_log.num_wraps > 1)
-			priv->event_log.wraps_more_count++;
-		else
-			priv->event_log.wraps_once_count++;
-
-		trace_iwlwifi_dev_ucode_wrap_event(priv->trans->dev,
-				num_wraps - priv->event_log.num_wraps,
-				next_entry, priv->event_log.next_entry);
-
-		if (next_entry < priv->event_log.next_entry) {
-			iwl_print_cont_event_trace(
-				priv, base, priv->event_log.next_entry,
-				capacity - priv->event_log.next_entry,
-				capacity, mode);
-
-			iwl_print_cont_event_trace(
-				priv, base, 0, next_entry, capacity, mode);
-		} else {
-			iwl_print_cont_event_trace(
-				priv, base, next_entry,
-				capacity - next_entry,
-				capacity, mode);
-
-			iwl_print_cont_event_trace(
-				priv, base, 0, next_entry, capacity, mode);
-		}
-	}
-
-	priv->event_log.num_wraps = num_wraps;
-	priv->event_log.next_entry = next_entry;
-}
-
-/**
- * iwl_bg_ucode_trace - Timer callback to log ucode event
- *
- * The timer is continually set to execute every
- * UCODE_TRACE_PERIOD milliseconds after the last timer expired
- * this function is to perform continuous uCode event logging operation
- * if enabled
- */
-static void iwl_bg_ucode_trace(unsigned long data)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)data;
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	if (priv->event_log.ucode_trace) {
-		iwl_continuous_event_trace(priv);
-		/* Reschedule the timer to occur in UCODE_TRACE_PERIOD */
-		mod_timer(&priv->ucode_trace,
-			 jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
-	}
-}
-
-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;
-
-	IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
-	iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
-}
-
-/*
- * queue/FIFO/AC mapping definitions
- */
-
-#define IWL_TX_FIFO_BK		0	/* shared */
-#define IWL_TX_FIFO_BE		1
-#define IWL_TX_FIFO_VI		2	/* shared */
-#define IWL_TX_FIFO_VO		3
-#define IWL_TX_FIFO_BK_IPAN	IWL_TX_FIFO_BK
-#define IWL_TX_FIFO_BE_IPAN	4
-#define IWL_TX_FIFO_VI_IPAN	IWL_TX_FIFO_VI
-#define IWL_TX_FIFO_VO_IPAN	5
-/* re-uses the VO FIFO, uCode will properly flush/schedule */
-#define IWL_TX_FIFO_AUX		5
-#define IWL_TX_FIFO_UNUSED	-1
-
-#define IWLAGN_CMD_FIFO_NUM	7
-
-/*
- * This queue number is required for proper operation
- * because the ucode will stop/start the scheduler as
- * required.
- */
-#define IWL_IPAN_MCAST_QUEUE	8
-
-static const u8 iwlagn_default_queue_to_tx_fifo[] = {
-	IWL_TX_FIFO_VO,
-	IWL_TX_FIFO_VI,
-	IWL_TX_FIFO_BE,
-	IWL_TX_FIFO_BK,
-	IWLAGN_CMD_FIFO_NUM,
-};
-
-static const u8 iwlagn_ipan_queue_to_tx_fifo[] = {
-	IWL_TX_FIFO_VO,
-	IWL_TX_FIFO_VI,
-	IWL_TX_FIFO_BE,
-	IWL_TX_FIFO_BK,
-	IWL_TX_FIFO_BK_IPAN,
-	IWL_TX_FIFO_BE_IPAN,
-	IWL_TX_FIFO_VI_IPAN,
-	IWL_TX_FIFO_VO_IPAN,
-	IWL_TX_FIFO_BE_IPAN,
-	IWLAGN_CMD_FIFO_NUM,
-	IWL_TX_FIFO_AUX,
-};
-
-static const u8 iwlagn_bss_ac_to_fifo[] = {
-	IWL_TX_FIFO_VO,
-	IWL_TX_FIFO_VI,
-	IWL_TX_FIFO_BE,
-	IWL_TX_FIFO_BK,
-};
-
-static const u8 iwlagn_bss_ac_to_queue[] = {
-	0, 1, 2, 3,
-};
-
-static const u8 iwlagn_pan_ac_to_fifo[] = {
-	IWL_TX_FIFO_VO_IPAN,
-	IWL_TX_FIFO_VI_IPAN,
-	IWL_TX_FIFO_BE_IPAN,
-	IWL_TX_FIFO_BK_IPAN,
-};
-
-static const u8 iwlagn_pan_ac_to_queue[] = {
-	7, 6, 5, 4,
-};
-
-void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
-{
-	int i;
-
-	/*
-	 * The default context is always valid,
-	 * the PAN context depends on uCode.
-	 */
-	priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
-	if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN)
-		priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
-
-	for (i = 0; i < NUM_IWL_RXON_CTX; i++)
-		priv->contexts[i].ctxid = i;
-
-	priv->contexts[IWL_RXON_CTX_BSS].always_active = true;
-	priv->contexts[IWL_RXON_CTX_BSS].is_active = true;
-	priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
-	priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
-	priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
-	priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
-	priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
-	priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
-	priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
-	priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
-		BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MONITOR);
-	priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
-		BIT(NL80211_IFTYPE_STATION);
-	priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
-	priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
-	priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
-	priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
-	memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue,
-	       iwlagn_bss_ac_to_queue, sizeof(iwlagn_bss_ac_to_queue));
-	memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo,
-	       iwlagn_bss_ac_to_fifo, sizeof(iwlagn_bss_ac_to_fifo));
-
-	priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
-	priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd =
-		REPLY_WIPAN_RXON_TIMING;
-	priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd =
-		REPLY_WIPAN_RXON_ASSOC;
-	priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM;
-	priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN;
-	priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY;
-	priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID;
-	priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION;
-	priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
-		BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
-
-	if (ucode_flags & IWL_UCODE_TLV_FLAGS_P2P)
-		priv->contexts[IWL_RXON_CTX_PAN].interface_modes |=
-			BIT(NL80211_IFTYPE_P2P_CLIENT) |
-			BIT(NL80211_IFTYPE_P2P_GO);
-
-	priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
-	priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
-	priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
-	memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue,
-	       iwlagn_pan_ac_to_queue, sizeof(iwlagn_pan_ac_to_queue));
-	memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo,
-	       iwlagn_pan_ac_to_fifo, sizeof(iwlagn_pan_ac_to_fifo));
-	priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
-
-	BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-}
-
-void iwl_rf_kill_ct_config(struct iwl_priv *priv)
-{
-	struct iwl_ct_kill_config cmd;
-	struct iwl_ct_kill_throttling_config adv_cmd;
-	int ret = 0;
-
-	iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
-		    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-
-	priv->thermal_throttle.ct_kill_toggle = false;
-
-	if (priv->cfg->base_params->support_ct_kill_exit) {
-		adv_cmd.critical_temperature_enter =
-			cpu_to_le32(priv->hw_params.ct_kill_threshold);
-		adv_cmd.critical_temperature_exit =
-			cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
-
-		ret = iwl_dvm_send_cmd_pdu(priv,
-				       REPLY_CT_KILL_CONFIG_CMD,
-				       CMD_SYNC, sizeof(adv_cmd), &adv_cmd);
-		if (ret)
-			IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
-		else
-			IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
-				"succeeded, critical temperature enter is %d,"
-				"exit is %d\n",
-				priv->hw_params.ct_kill_threshold,
-				priv->hw_params.ct_kill_exit_threshold);
-	} else {
-		cmd.critical_temperature_R =
-			cpu_to_le32(priv->hw_params.ct_kill_threshold);
-
-		ret = iwl_dvm_send_cmd_pdu(priv,
-				       REPLY_CT_KILL_CONFIG_CMD,
-				       CMD_SYNC, sizeof(cmd), &cmd);
-		if (ret)
-			IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
-		else
-			IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
-				"succeeded, "
-				"critical temperature is %d\n",
-				priv->hw_params.ct_kill_threshold);
-	}
-}
-
-static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
-{
-	struct iwl_calib_cfg_cmd calib_cfg_cmd;
-	struct iwl_host_cmd cmd = {
-		.id = CALIBRATION_CFG_CMD,
-		.len = { sizeof(struct iwl_calib_cfg_cmd), },
-		.data = { &calib_cfg_cmd, },
-	};
-
-	memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
-	calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_RT_CFG_ALL;
-	calib_cfg_cmd.ucd_calib_cfg.once.start = cpu_to_le32(cfg);
-
-	return iwl_dvm_send_cmd(priv, &cmd);
-}
-
-
-static 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),
-	};
-
-	if (IWL_UCODE_API(priv->fw->ucode_ver) > 1) {
-		IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
-		return iwl_dvm_send_cmd_pdu(priv,
-					TX_ANT_CONFIGURATION_CMD,
-					CMD_SYNC,
-					sizeof(struct iwl_tx_ant_config_cmd),
-					&tx_ant_cmd);
-	} else {
-		IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n");
-		return -EOPNOTSUPP;
-	}
-}
-
-void iwl_send_bt_config(struct iwl_priv *priv)
-{
-	struct iwl_bt_cmd bt_cmd = {
-		.lead_time = BT_LEAD_TIME_DEF,
-		.max_kill = BT_MAX_KILL_DEF,
-		.kill_ack_mask = 0,
-		.kill_cts_mask = 0,
-	};
-
-	if (!iwlwifi_mod_params.bt_coex_active)
-		bt_cmd.flags = BT_COEX_DISABLE;
-	else
-		bt_cmd.flags = BT_COEX_ENABLE;
-
-	priv->bt_enable_flag = bt_cmd.flags;
-	IWL_DEBUG_INFO(priv, "BT coex %s\n",
-		(bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
-
-	if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-			     CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
-		IWL_ERR(priv, "failed to send BT Coex Config\n");
-}
-
-/**
- * iwl_alive_start - called after REPLY_ALIVE notification received
- *                   from protocol/runtime uCode (initialization uCode's
- *                   Alive gets handled by iwl_init_alive_start()).
- */
-int iwl_alive_start(struct iwl_priv *priv)
-{
-	int ret = 0;
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-
-	IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
-
-	/* After the ALIVE response, we can send host commands to the uCode */
-	set_bit(STATUS_ALIVE, &priv->status);
-
-	if (iwl_is_rfkill(priv))
-		return -ERFKILL;
-
-	if (priv->event_log.ucode_trace) {
-		/* start collecting data now */
-		mod_timer(&priv->ucode_trace, jiffies);
-	}
-
-	/* download priority table before any calibration request */
-	if (priv->cfg->bt_params &&
-	    priv->cfg->bt_params->advanced_bt_coexist) {
-		/* Configure Bluetooth device coexistence support */
-		if (priv->cfg->bt_params->bt_sco_disable)
-			priv->bt_enable_pspoll = false;
-		else
-			priv->bt_enable_pspoll = true;
-
-		priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
-		priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
-		priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
-		iwlagn_send_advance_bt_config(priv);
-		priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
-		priv->cur_rssi_ctx = NULL;
-
-		iwl_send_prio_tbl(priv);
-
-		/* FIXME: w/a to force change uCode BT state machine */
-		ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
-					 BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
-		if (ret)
-			return ret;
-		ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
-					 BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
-		if (ret)
-			return ret;
-	} else {
-		/*
-		 * default is 2-wire BT coexexistence support
-		 */
-		iwl_send_bt_config(priv);
-	}
-
-	/*
-	 * Perform runtime calibrations, including DC calibration.
-	 */
-	iwlagn_send_calib_cfg_rt(priv, IWL_CALIB_CFG_DC_IDX);
-
-	ieee80211_wake_queues(priv->hw);
-
-	/* Configure Tx antenna selection based on H/W config */
-	iwlagn_send_tx_ant_config(priv, priv->hw_params.valid_tx_ant);
-
-	if (iwl_is_associated_ctx(ctx) && !priv->wowlan) {
-		struct iwl_rxon_cmd *active_rxon =
-				(struct iwl_rxon_cmd *)&ctx->active;
-		/* apply any changes in staging */
-		ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
-		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	} else {
-		struct iwl_rxon_context *tmp;
-		/* Initialize our rx_config data */
-		for_each_context(priv, tmp)
-			iwl_connection_init_rx_config(priv, tmp);
-
-		iwlagn_set_rxon_chain(priv, ctx);
-	}
-
-	if (!priv->wowlan) {
-		/* WoWLAN ucode will not reply in the same way, skip it */
-		iwl_reset_run_time_calib(priv);
-	}
-
-	set_bit(STATUS_READY, &priv->status);
-
-	/* Configure the adapter for unassociated operation */
-	ret = iwlagn_commit_rxon(priv, ctx);
-	if (ret)
-		return ret;
-
-	/* At this point, the NIC is initialized and operational */
-	iwl_rf_kill_ct_config(priv);
-
-	IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
-
-	return iwl_power_update_mode(priv, true);
-}
-
-/**
- * iwl_clear_driver_stations - clear knowledge of all stations from driver
- * @priv: iwl priv struct
- *
- * This is called during iwl_down() to make sure that in the case
- * we're coming there from a hardware restart mac80211 will be
- * able to reconfigure stations -- if we're getting there in the
- * normal down flow then the stations will already be cleared.
- */
-static void iwl_clear_driver_stations(struct iwl_priv *priv)
-{
-	struct iwl_rxon_context *ctx;
-
-	spin_lock_bh(&priv->sta_lock);
-	memset(priv->stations, 0, sizeof(priv->stations));
-	priv->num_stations = 0;
-
-	priv->ucode_key_table = 0;
-
-	for_each_context(priv, ctx) {
-		/*
-		 * Remove all key information that is not stored as part
-		 * of station information since mac80211 may not have had
-		 * a chance to remove all the keys. When device is
-		 * reconfigured by mac80211 after an error all keys will
-		 * be reconfigured.
-		 */
-		memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys));
-		ctx->key_mapping_keys = 0;
-	}
-
-	spin_unlock_bh(&priv->sta_lock);
-}
-
-void iwl_down(struct iwl_priv *priv)
-{
-	int exit_pending;
-
-	IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
-
-	lockdep_assert_held(&priv->mutex);
-
-	iwl_scan_cancel_timeout(priv, 200);
-
-	/*
-	 * If active, scanning won't cancel it, so say it expired.
-	 * No race since we hold the mutex here and a new one
-	 * can't come in at this time.
-	 */
-	ieee80211_remain_on_channel_expired(priv->hw);
-
-	exit_pending =
-		test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
-
-	iwl_clear_ucode_stations(priv, NULL);
-	iwl_dealloc_bcast_stations(priv);
-	iwl_clear_driver_stations(priv);
-
-	/* reset BT coex data */
-	priv->bt_status = 0;
-	priv->cur_rssi_ctx = NULL;
-	priv->bt_is_sco = 0;
-	if (priv->cfg->bt_params)
-		priv->bt_traffic_load =
-			 priv->cfg->bt_params->bt_init_traffic_load;
-	else
-		priv->bt_traffic_load = 0;
-	priv->bt_full_concurrent = false;
-	priv->bt_ci_compliance = 0;
-
-	/* Wipe out the EXIT_PENDING status bit if we are not actually
-	 * exiting the module */
-	if (!exit_pending)
-		clear_bit(STATUS_EXIT_PENDING, &priv->status);
-
-	if (priv->mac80211_registered)
-		ieee80211_stop_queues(priv->hw);
-
-	priv->ucode_loaded = false;
-	iwl_trans_stop_device(priv->trans);
-
-	/* Clear out all status bits but a few that are stable across reset */
-	priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
-				STATUS_RF_KILL_HW |
-			test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
-				STATUS_GEO_CONFIGURED |
-			test_bit(STATUS_FW_ERROR, &priv->status) <<
-				STATUS_FW_ERROR |
-			test_bit(STATUS_EXIT_PENDING, &priv->status) <<
-				STATUS_EXIT_PENDING;
-
-	dev_kfree_skb(priv->beacon_skb);
-	priv->beacon_skb = NULL;
-}
-
-/*****************************************************************************
- *
- * Workqueue callbacks
- *
- *****************************************************************************/
-
-static void iwl_bg_run_time_calib_work(struct work_struct *work)
-{
-	struct iwl_priv *priv = container_of(work, struct iwl_priv,
-			run_time_calib_work);
-
-	mutex_lock(&priv->mutex);
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-	    test_bit(STATUS_SCANNING, &priv->status)) {
-		mutex_unlock(&priv->mutex);
-		return;
-	}
-
-	if (priv->start_calib) {
-		iwl_chain_noise_calibration(priv);
-		iwl_sensitivity_calibration(priv);
-	}
-
-	mutex_unlock(&priv->mutex);
-}
-
-void iwlagn_prepare_restart(struct iwl_priv *priv)
-{
-	bool bt_full_concurrent;
-	u8 bt_ci_compliance;
-	u8 bt_load;
-	u8 bt_status;
-	bool bt_is_sco;
-	int i;
-
-	lockdep_assert_held(&priv->mutex);
-
-	priv->is_open = 0;
-
-	/*
-	 * __iwl_down() will clear the BT status variables,
-	 * which is correct, but when we restart we really
-	 * want to keep them so restore them afterwards.
-	 *
-	 * The restart process will later pick them up and
-	 * re-configure the hw when we reconfigure the BT
-	 * command.
-	 */
-	bt_full_concurrent = priv->bt_full_concurrent;
-	bt_ci_compliance = priv->bt_ci_compliance;
-	bt_load = priv->bt_traffic_load;
-	bt_status = priv->bt_status;
-	bt_is_sco = priv->bt_is_sco;
-
-	iwl_down(priv);
-
-	priv->bt_full_concurrent = bt_full_concurrent;
-	priv->bt_ci_compliance = bt_ci_compliance;
-	priv->bt_traffic_load = bt_load;
-	priv->bt_status = bt_status;
-	priv->bt_is_sco = bt_is_sco;
-
-	/* reset aggregation queues */
-	for (i = IWLAGN_FIRST_AMPDU_QUEUE; i < IWL_MAX_HW_QUEUES; i++)
-		priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
-	/* and stop counts */
-	for (i = 0; i < IWL_MAX_HW_QUEUES; i++)
-		atomic_set(&priv->queue_stop_count[i], 0);
-
-	memset(priv->agg_q_alloc, 0, sizeof(priv->agg_q_alloc));
-}
-
-static void iwl_bg_restart(struct work_struct *data)
-{
-	struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
-		mutex_lock(&priv->mutex);
-		iwlagn_prepare_restart(priv);
-		mutex_unlock(&priv->mutex);
-		iwl_cancel_deferred_work(priv);
-		ieee80211_restart_hw(priv->hw);
-	} else {
-		WARN_ON(1);
-	}
-}
-
-
-
-
-void iwlagn_disable_roc(struct iwl_priv *priv)
-{
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-
-	lockdep_assert_held(&priv->mutex);
-
-	if (!priv->hw_roc_setup)
-		return;
-
-	ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
-	ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-
-	priv->hw_roc_channel = NULL;
-
-	memset(ctx->staging.node_addr, 0, ETH_ALEN);
-
-	iwlagn_commit_rxon(priv, ctx);
-
-	ctx->is_active = false;
-	priv->hw_roc_setup = false;
-}
-
-static void iwlagn_disable_roc_work(struct work_struct *work)
-{
-	struct iwl_priv *priv = container_of(work, struct iwl_priv,
-					     hw_roc_disable_work.work);
-
-	mutex_lock(&priv->mutex);
-	iwlagn_disable_roc(priv);
-	mutex_unlock(&priv->mutex);
-}
-
-/*****************************************************************************
- *
- * driver setup and teardown
- *
- *****************************************************************************/
-
-void iwl_setup_deferred_work(struct iwl_priv *priv)
-{
-	priv->workqueue = create_singlethread_workqueue(DRV_NAME);
-
-	INIT_WORK(&priv->restart, iwl_bg_restart);
-	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_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
-	INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
-	INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
-			  iwlagn_disable_roc_work);
-
-	iwl_setup_scan_deferred_work(priv);
-
-	if (priv->cfg->bt_params)
-		iwlagn_bt_setup_deferred_work(priv);
-
-	init_timer(&priv->statistics_periodic);
-	priv->statistics_periodic.data = (unsigned long)priv;
-	priv->statistics_periodic.function = iwl_bg_statistics_periodic;
-
-	init_timer(&priv->ucode_trace);
-	priv->ucode_trace.data = (unsigned long)priv;
-	priv->ucode_trace.function = iwl_bg_ucode_trace;
-}
-
-void iwl_cancel_deferred_work(struct iwl_priv *priv)
-{
-	if (priv->cfg->bt_params)
-		iwlagn_bt_cancel_deferred_work(priv);
-
-	cancel_work_sync(&priv->run_time_calib_work);
-	cancel_work_sync(&priv->beacon_update);
-
-	iwl_cancel_scan_deferred_work(priv);
-
-	cancel_work_sync(&priv->bt_full_concurrency);
-	cancel_work_sync(&priv->bt_runtime_config);
-	cancel_delayed_work_sync(&priv->hw_roc_disable_work);
-
-	del_timer_sync(&priv->statistics_periodic);
-	del_timer_sync(&priv->ucode_trace);
-}
-
-static void iwl_init_hw_rates(struct ieee80211_rate *rates)
-{
-	int i;
-
-	for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
-		rates[i].bitrate = iwl_rates[i].ieee * 5;
-		rates[i].hw_value = i; /* Rate scaling will work on indexes */
-		rates[i].hw_value_short = i;
-		rates[i].flags = 0;
-		if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
-			/*
-			 * If CCK != 1M then set short preamble rate flag.
-			 */
-			rates[i].flags |=
-				(iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
-					0 : IEEE80211_RATE_SHORT_PREAMBLE;
-		}
-	}
-}
-
-#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
-#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
-static void iwl_init_ht_hw_capab(const struct iwl_priv *priv,
-			      struct ieee80211_sta_ht_cap *ht_info,
-			      enum ieee80211_band band)
-{
-	u16 max_bit_rate = 0;
-	u8 rx_chains_num = priv->hw_params.rx_chains_num;
-	u8 tx_chains_num = priv->hw_params.tx_chains_num;
-
-	ht_info->cap = 0;
-	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
-
-	ht_info->ht_supported = true;
-
-	if (priv->cfg->ht_params &&
-	    priv->cfg->ht_params->ht_greenfield_support)
-		ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
-	ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
-	max_bit_rate = MAX_BIT_RATE_20_MHZ;
-	if (priv->hw_params.ht40_channel & BIT(band)) {
-		ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-		ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
-		ht_info->mcs.rx_mask[4] = 0x01;
-		max_bit_rate = MAX_BIT_RATE_40_MHZ;
-	}
-
-	if (iwlwifi_mod_params.amsdu_size_8K)
-		ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
-
-	ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
-	ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
-
-	ht_info->mcs.rx_mask[0] = 0xFF;
-	if (rx_chains_num >= 2)
-		ht_info->mcs.rx_mask[1] = 0xFF;
-	if (rx_chains_num >= 3)
-		ht_info->mcs.rx_mask[2] = 0xFF;
-
-	/* Highest supported Rx data rate */
-	max_bit_rate *= rx_chains_num;
-	WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK);
-	ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate);
-
-	/* Tx MCS capabilities */
-	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
-	if (tx_chains_num != rx_chains_num) {
-		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
-		ht_info->mcs.tx_params |= ((tx_chains_num - 1) <<
-				IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
-	}
-}
-
-/**
- * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
- */
-static int iwl_init_geos(struct iwl_priv *priv)
-{
-	struct iwl_channel_info *ch;
-	struct ieee80211_supported_band *sband;
-	struct ieee80211_channel *channels;
-	struct ieee80211_channel *geo_ch;
-	struct ieee80211_rate *rates;
-	int i = 0;
-	s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN;
-
-	if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
-	    priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
-		IWL_DEBUG_INFO(priv, "Geography modes already initialized.\n");
-		set_bit(STATUS_GEO_CONFIGURED, &priv->status);
-		return 0;
-	}
-
-	channels = kcalloc(priv->channel_count,
-			   sizeof(struct ieee80211_channel), GFP_KERNEL);
-	if (!channels)
-		return -ENOMEM;
-
-	rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate),
-			GFP_KERNEL);
-	if (!rates) {
-		kfree(channels);
-		return -ENOMEM;
-	}
-
-	/* 5.2GHz channels start after the 2.4GHz channels */
-	sband = &priv->bands[IEEE80211_BAND_5GHZ];
-	sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
-	/* just OFDM */
-	sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
-	sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;
-
-	if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
-		iwl_init_ht_hw_capab(priv, &sband->ht_cap,
-					 IEEE80211_BAND_5GHZ);
-
-	sband = &priv->bands[IEEE80211_BAND_2GHZ];
-	sband->channels = channels;
-	/* OFDM & CCK */
-	sband->bitrates = rates;
-	sband->n_bitrates = IWL_RATE_COUNT_LEGACY;
-
-	if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
-		iwl_init_ht_hw_capab(priv, &sband->ht_cap,
-					 IEEE80211_BAND_2GHZ);
-
-	priv->ieee_channels = channels;
-	priv->ieee_rates = rates;
-
-	for (i = 0;  i < priv->channel_count; i++) {
-		ch = &priv->channel_info[i];
-
-		/* FIXME: might be removed if scan is OK */
-		if (!is_channel_valid(ch))
-			continue;
-
-		sband =  &priv->bands[ch->band];
-
-		geo_ch = &sband->channels[sband->n_channels++];
-
-		geo_ch->center_freq =
-			ieee80211_channel_to_frequency(ch->channel, ch->band);
-		geo_ch->max_power = ch->max_power_avg;
-		geo_ch->max_antenna_gain = 0xff;
-		geo_ch->hw_value = ch->channel;
-
-		if (is_channel_valid(ch)) {
-			if (!(ch->flags & EEPROM_CHANNEL_IBSS))
-				geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
-
-			if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
-				geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
-
-			if (ch->flags & EEPROM_CHANNEL_RADAR)
-				geo_ch->flags |= IEEE80211_CHAN_RADAR;
-
-			geo_ch->flags |= ch->ht40_extension_channel;
-
-			if (ch->max_power_avg > max_tx_power)
-				max_tx_power = ch->max_power_avg;
-		} else {
-			geo_ch->flags |= IEEE80211_CHAN_DISABLED;
-		}
-
-		IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n",
-				ch->channel, geo_ch->center_freq,
-				is_channel_a_band(ch) ?  "5.2" : "2.4",
-				geo_ch->flags & IEEE80211_CHAN_DISABLED ?
-				"restricted" : "valid",
-				 geo_ch->flags);
-	}
-
-	priv->tx_power_device_lmt = max_tx_power;
-	priv->tx_power_user_lmt = max_tx_power;
-	priv->tx_power_next = max_tx_power;
-
-	if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
-	     priv->hw_params.sku & EEPROM_SKU_CAP_BAND_52GHZ) {
-		IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
-			"Please send your %s to maintainer.\n",
-			priv->trans->hw_id_str);
-		priv->hw_params.sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
-	}
-
-	if (iwlwifi_mod_params.disable_5ghz)
-		priv->bands[IEEE80211_BAND_5GHZ].n_channels = 0;
-
-	IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n",
-		   priv->bands[IEEE80211_BAND_2GHZ].n_channels,
-		   priv->bands[IEEE80211_BAND_5GHZ].n_channels);
-
-	set_bit(STATUS_GEO_CONFIGURED, &priv->status);
-
-	return 0;
-}
-
-/*
- * iwl_free_geos - undo allocations in iwl_init_geos
- */
-static void iwl_free_geos(struct iwl_priv *priv)
-{
-	kfree(priv->ieee_channels);
-	kfree(priv->ieee_rates);
-	clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
-}
-
-int iwl_init_drv(struct iwl_priv *priv)
-{
-	int ret;
-
-	spin_lock_init(&priv->sta_lock);
-
-	mutex_init(&priv->mutex);
-
-	INIT_LIST_HEAD(&priv->calib_results);
-
-	priv->ieee_channels = NULL;
-	priv->ieee_rates = NULL;
-	priv->band = IEEE80211_BAND_2GHZ;
-
-	priv->plcp_delta_threshold =
-		priv->cfg->base_params->plcp_delta_threshold;
-
-	priv->iw_mode = NL80211_IFTYPE_STATION;
-	priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
-	priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
-	priv->agg_tids_count = 0;
-
-	priv->ucode_owner = IWL_OWNERSHIP_DRIVER;
-
-	priv->rx_statistics_jiffies = jiffies;
-
-	/* Choose which receivers/antennas to use */
-	iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
-
-	iwl_init_scan_params(priv);
-
-	/* init bt coex */
-	if (priv->cfg->bt_params &&
-	    priv->cfg->bt_params->advanced_bt_coexist) {
-		priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
-		priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
-		priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
-		priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
-		priv->bt_duration = BT_DURATION_LIMIT_DEF;
-		priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
-	}
-
-	ret = iwl_init_channel_map(priv);
-	if (ret) {
-		IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
-		goto err;
-	}
-
-	ret = iwl_init_geos(priv);
-	if (ret) {
-		IWL_ERR(priv, "initializing geos failed: %d\n", ret);
-		goto err_free_channel_map;
-	}
-	iwl_init_hw_rates(priv->ieee_rates);
-
-	return 0;
-
-err_free_channel_map:
-	iwl_free_channel_map(priv);
-err:
-	return ret;
-}
-
-void iwl_uninit_drv(struct iwl_priv *priv)
-{
-	iwl_free_geos(priv);
-	iwl_free_channel_map(priv);
-	kfree(priv->scan_cmd);
-	kfree(priv->beacon_cmd);
-	kfree(rcu_dereference_raw(priv->noa_data));
-	iwl_calib_free_results(priv);
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-	kfree(priv->wowlan_sram);
-#endif
-}
-
-void iwl_set_hw_params(struct iwl_priv *priv)
-{
-	if (priv->cfg->ht_params)
-		priv->hw_params.use_rts_for_aggregation =
-			priv->cfg->ht_params->use_rts_for_aggregation;
-
-	if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
-		priv->hw_params.sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
-
-	/* Device-specific setup */
-	priv->lib->set_hw_params(priv);
-}
-
-
-
-/* show what optional capabilities we have */
-void iwl_option_config(struct iwl_priv *priv)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-	IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG enabled\n");
-#else
-	IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG disabled\n");
-#endif
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-	IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS enabled\n");
-#else
-	IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS disabled\n");
-#endif
-
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-	IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING enabled\n");
-#else
-	IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING disabled\n");
-#endif
-
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-	IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE enabled\n");
-#else
-	IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE disabled\n");
-#endif
-
-#ifdef CONFIG_IWLWIFI_P2P
-	IWL_INFO(priv, "CONFIG_IWLWIFI_P2P enabled\n");
-#else
-	IWL_INFO(priv, "CONFIG_IWLWIFI_P2P disabled\n");
-#endif
-}
-
-static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
-						 const struct iwl_cfg *cfg,
-						 const struct iwl_fw *fw)
-{
-	struct iwl_priv *priv;
-	struct ieee80211_hw *hw;
-	struct iwl_op_mode *op_mode;
-	u16 num_mac;
-	u32 ucode_flags;
-	struct iwl_trans_config trans_cfg;
-	static const u8 no_reclaim_cmds[] = {
-		REPLY_RX_PHY_CMD,
-		REPLY_RX,
-		REPLY_RX_MPDU_CMD,
-		REPLY_COMPRESSED_BA,
-		STATISTICS_NOTIFICATION,
-		REPLY_TX,
-	};
-	int i;
-
-	/************************
-	 * 1. Allocating HW data
-	 ************************/
-	hw = iwl_alloc_all();
-	if (!hw) {
-		pr_err("%s: Cannot allocate network device\n", cfg->name);
-		goto out;
-	}
-
-	op_mode = hw->priv;
-	op_mode->ops = &iwl_dvm_ops;
-	priv = IWL_OP_MODE_GET_DVM(op_mode);
-	priv->trans = trans;
-	priv->dev = trans->dev;
-	priv->cfg = cfg;
-	priv->fw = fw;
-
-	switch (priv->cfg->device_family) {
-	case IWL_DEVICE_FAMILY_1000:
-	case IWL_DEVICE_FAMILY_100:
-		priv->lib = &iwl1000_lib;
-		break;
-	case IWL_DEVICE_FAMILY_2000:
-	case IWL_DEVICE_FAMILY_105:
-		priv->lib = &iwl2000_lib;
-		break;
-	case IWL_DEVICE_FAMILY_2030:
-	case IWL_DEVICE_FAMILY_135:
-		priv->lib = &iwl2030_lib;
-		break;
-	case IWL_DEVICE_FAMILY_5000:
-		priv->lib = &iwl5000_lib;
-		break;
-	case IWL_DEVICE_FAMILY_5150:
-		priv->lib = &iwl5150_lib;
-		break;
-	case IWL_DEVICE_FAMILY_6000:
-	case IWL_DEVICE_FAMILY_6005:
-	case IWL_DEVICE_FAMILY_6000i:
-	case IWL_DEVICE_FAMILY_6050:
-	case IWL_DEVICE_FAMILY_6150:
-		priv->lib = &iwl6000_lib;
-		break;
-	case IWL_DEVICE_FAMILY_6030:
-		priv->lib = &iwl6030_lib;
-		break;
-	default:
-		break;
-	}
-
-	if (WARN_ON(!priv->lib))
-		goto out_free_hw;
-
-	/*
-	 * Populate the state variables that the transport layer needs
-	 * to know about.
-	 */
-	trans_cfg.op_mode = op_mode;
-	trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
-	trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
-	trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
-	if (!iwlwifi_mod_params.wd_disable)
-		trans_cfg.queue_watchdog_timeout =
-			priv->cfg->base_params->wd_timeout;
-	else
-		trans_cfg.queue_watchdog_timeout = IWL_WATCHHDOG_DISABLED;
-	trans_cfg.command_names = iwl_dvm_cmd_strings;
-
-	ucode_flags = fw->ucode_capa.flags;
-
-#ifndef CONFIG_IWLWIFI_P2P
-	ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
-#endif
-
-	if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) {
-		priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
-		trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
-		trans_cfg.queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
-		trans_cfg.n_queue_to_fifo =
-			ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo);
-	} else {
-		priv->sta_key_max_num = STA_KEY_MAX_NUM;
-		trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
-		trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
-		trans_cfg.n_queue_to_fifo =
-			ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
-	}
-
-	/* Configure transport layer */
-	iwl_trans_configure(priv->trans, &trans_cfg);
-
-	/* At this point both hw and priv are allocated. */
-
-	SET_IEEE80211_DEV(priv->hw, priv->trans->dev);
-
-	iwl_option_config(priv);
-
-	IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
-
-	/* is antenna coupling more than 35dB ? */
-	priv->bt_ant_couple_ok =
-		(iwlwifi_mod_params.ant_coupling >
-			IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
-			true : false;
-
-	/* enable/disable bt channel inhibition */
-	priv->bt_ch_announce = iwlwifi_mod_params.bt_ch_announce;
-	IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n",
-		       (priv->bt_ch_announce) ? "On" : "Off");
-
-	/* these spin locks will be used in apm_ops.init and EEPROM access
-	 * we should init now
-	 */
-	spin_lock_init(&priv->statistics.lock);
-
-	/***********************
-	 * 2. Read REV register
-	 ***********************/
-	IWL_INFO(priv, "Detected %s, REV=0x%X\n",
-		priv->cfg->name, priv->trans->hw_rev);
-
-	if (iwl_trans_start_hw(priv->trans))
-		goto out_free_hw;
-
-	/* Read the EEPROM */
-	if (iwl_eeprom_init(priv, priv->trans->hw_rev)) {
-		IWL_ERR(priv, "Unable to init EEPROM\n");
-		goto out_free_hw;
-	}
-	/* Reset chip to save power until we load uCode during "up". */
-	iwl_trans_stop_hw(priv->trans, false);
-
-	if (iwl_eeprom_check_version(priv))
-		goto out_free_eeprom;
-
-	if (iwl_eeprom_init_hw_params(priv))
-		goto out_free_eeprom;
-
-	/* extract MAC Address */
-	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++;
-	}
-
-	/************************
-	 * 4. Setup HW constants
-	 ************************/
-	iwl_set_hw_params(priv);
-
-	if (!(priv->hw_params.sku & EEPROM_SKU_CAP_IPAN_ENABLE)) {
-		IWL_DEBUG_INFO(priv, "Your EEPROM disabled PAN");
-		ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
-		/*
-		 * if not PAN, then don't support P2P -- might be a uCode
-		 * packaging bug or due to the eeprom check above
-		 */
-		ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
-		priv->sta_key_max_num = STA_KEY_MAX_NUM;
-		trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
-		trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
-		trans_cfg.n_queue_to_fifo =
-			ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
-
-		/* Configure transport layer again*/
-		iwl_trans_configure(priv->trans, &trans_cfg);
-	}
-
-	/*******************
-	 * 5. Setup priv
-	 *******************/
-	for (i = 0; i < IWL_MAX_HW_QUEUES; i++) {
-		priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
-		if (i < IWLAGN_FIRST_AMPDU_QUEUE &&
-		    i != IWL_DEFAULT_CMD_QUEUE_NUM &&
-		    i != IWL_IPAN_CMD_QUEUE_NUM)
-			priv->queue_to_mac80211[i] = i;
-		atomic_set(&priv->queue_stop_count[i], 0);
-	}
-
-	WARN_ON(trans_cfg.queue_to_fifo[trans_cfg.cmd_queue] !=
-						IWLAGN_CMD_FIFO_NUM);
-
-	if (iwl_init_drv(priv))
-		goto out_free_eeprom;
-
-	/* At this point both hw and priv are initialized. */
-
-	/********************
-	 * 6. Setup services
-	 ********************/
-	iwl_setup_deferred_work(priv);
-	iwl_setup_rx_handlers(priv);
-	iwl_testmode_init(priv);
-
-	iwl_power_initialize(priv);
-	iwl_tt_initialize(priv);
-
-	snprintf(priv->hw->wiphy->fw_version,
-		 sizeof(priv->hw->wiphy->fw_version),
-		 "%s", fw->fw_version);
-
-	priv->new_scan_threshold_behaviour =
-		!!(ucode_flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
-
-	priv->phy_calib_chain_noise_reset_cmd =
-		fw->ucode_capa.standard_phy_calibration_size;
-	priv->phy_calib_chain_noise_gain_cmd =
-		fw->ucode_capa.standard_phy_calibration_size + 1;
-
-	/* initialize all valid contexts */
-	iwl_init_context(priv, ucode_flags);
-
-	/**************************************************
-	 * This is still part of probe() in a sense...
-	 *
-	 * 7. Setup and register with mac80211 and debugfs
-	 **************************************************/
-	if (iwlagn_mac_setup_register(priv, &fw->ucode_capa))
-		goto out_destroy_workqueue;
-
-	if (iwl_dbgfs_register(priv, DRV_NAME))
-		IWL_ERR(priv,
-			"failed to create debugfs files. Ignoring error\n");
-
-	return op_mode;
-
-out_destroy_workqueue:
-	destroy_workqueue(priv->workqueue);
-	priv->workqueue = NULL;
-	iwl_uninit_drv(priv);
-out_free_eeprom:
-	iwl_eeprom_free(priv);
-out_free_hw:
-	ieee80211_free_hw(priv->hw);
-out:
-	op_mode = NULL;
-	return op_mode;
-}
-
-void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
-{
-	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-	IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
-
-	iwl_dbgfs_unregister(priv);
-
-	iwl_testmode_cleanup(priv);
-	iwlagn_mac_unregister(priv);
-
-	iwl_tt_exit(priv);
-
-	/*This will stop the queues, move the device to low power state */
-	priv->ucode_loaded = false;
-	iwl_trans_stop_device(priv->trans);
-
-	iwl_eeprom_free(priv);
-
-	/*netif_stop_queue(dev); */
-	flush_workqueue(priv->workqueue);
-
-	/* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes
-	 * priv->workqueue... so we can't take down the workqueue
-	 * until now... */
-	destroy_workqueue(priv->workqueue);
-	priv->workqueue = NULL;
-
-	iwl_uninit_drv(priv);
-
-	dev_kfree_skb(priv->beacon_skb);
-
-	iwl_trans_stop_hw(priv->trans, true);
-	ieee80211_free_hw(priv->hw);
-}
-
-static const char * const desc_lookup_text[] = {
-	"OK",
-	"FAIL",
-	"BAD_PARAM",
-	"BAD_CHECKSUM",
-	"NMI_INTERRUPT_WDG",
-	"SYSASSERT",
-	"FATAL_ERROR",
-	"BAD_COMMAND",
-	"HW_ERROR_TUNE_LOCK",
-	"HW_ERROR_TEMPERATURE",
-	"ILLEGAL_CHAN_FREQ",
-	"VCC_NOT_STABLE",
-	"FH_ERROR",
-	"NMI_INTERRUPT_HOST",
-	"NMI_INTERRUPT_ACTION_PT",
-	"NMI_INTERRUPT_UNKNOWN",
-	"UCODE_VERSION_MISMATCH",
-	"HW_ERROR_ABS_LOCK",
-	"HW_ERROR_CAL_LOCK_FAIL",
-	"NMI_INTERRUPT_INST_ACTION_PT",
-	"NMI_INTERRUPT_DATA_ACTION_PT",
-	"NMI_TRM_HW_ER",
-	"NMI_INTERRUPT_TRM",
-	"NMI_INTERRUPT_BREAK_POINT",
-	"DEBUG_0",
-	"DEBUG_1",
-	"DEBUG_2",
-	"DEBUG_3",
-};
-
-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 i;
-	int max = ARRAY_SIZE(desc_lookup_text);
-
-	if (num < max)
-		return desc_lookup_text[num];
-
-	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))
-#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
-
-static void iwl_dump_nic_error_log(struct iwl_priv *priv)
-{
-	struct iwl_trans *trans = priv->trans;
-	u32 base;
-	struct iwl_error_event_table table;
-
-	base = priv->device_pointers.error_event_table;
-	if (priv->cur_ucode == IWL_UCODE_INIT) {
-		if (!base)
-			base = priv->fw->init_errlog_ptr;
-	} else {
-		if (!base)
-			base = priv->fw->inst_errlog_ptr;
-	}
-
-	if (!iwlagn_hw_valid_rtc_data_addr(base)) {
-		IWL_ERR(priv,
-			"Not valid error log pointer 0x%08X for %s uCode\n",
-			base,
-			(priv->cur_ucode == IWL_UCODE_INIT)
-					? "Init" : "RT");
-		return;
-	}
-
-	/*TODO: Update dbgfs with ISR error stats obtained below */
-	iwl_read_targ_mem_words(trans, base, &table, sizeof(table));
-
-	if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
-		IWL_ERR(trans, "Start IWL Error Log Dump:\n");
-		IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
-			priv->status, table.valid);
-	}
-
-	trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
-				      table.data1, table.data2, table.line,
-				      table.blink1, table.blink2, table.ilink1,
-				      table.ilink2, table.bcon_time, table.gp1,
-				      table.gp2, table.gp3, table.ucode_ver,
-				      table.hw_ver, table.brd_ver);
-	IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
-		desc_lookup(table.error_id));
-	IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
-	IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1);
-	IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2);
-	IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1);
-	IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2);
-	IWL_ERR(priv, "0x%08X | data1\n", table.data1);
-	IWL_ERR(priv, "0x%08X | data2\n", table.data2);
-	IWL_ERR(priv, "0x%08X | line\n", table.line);
-	IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time);
-	IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low);
-	IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi);
-	IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1);
-	IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2);
-	IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3);
-	IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver);
-	IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver);
-	IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver);
-	IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd);
-	IWL_ERR(priv, "0x%08X | isr0\n", table.isr0);
-	IWL_ERR(priv, "0x%08X | isr1\n", table.isr1);
-	IWL_ERR(priv, "0x%08X | isr2\n", table.isr2);
-	IWL_ERR(priv, "0x%08X | isr3\n", table.isr3);
-	IWL_ERR(priv, "0x%08X | isr4\n", table.isr4);
-	IWL_ERR(priv, "0x%08X | isr_pref\n", table.isr_pref);
-	IWL_ERR(priv, "0x%08X | wait_event\n", table.wait_event);
-	IWL_ERR(priv, "0x%08X | l2p_control\n", table.l2p_control);
-	IWL_ERR(priv, "0x%08X | l2p_duration\n", table.l2p_duration);
-	IWL_ERR(priv, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
-	IWL_ERR(priv, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
-	IWL_ERR(priv, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
-	IWL_ERR(priv, "0x%08X | timestamp\n", table.u_timestamp);
-	IWL_ERR(priv, "0x%08X | flow_handler\n", table.flow_handler);
-}
-
-#define EVENT_START_OFFSET  (4 * sizeof(u32))
-
-/**
- * iwl_print_event_log - Dump error event log to syslog
- *
- */
-static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
-			       u32 num_events, u32 mode,
-			       int pos, char **buf, size_t bufsz)
-{
-	u32 i;
-	u32 base;       /* SRAM byte address of event log header */
-	u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
-	u32 ptr;        /* SRAM byte address of log data */
-	u32 ev, time, data; /* event log data */
-	unsigned long reg_flags;
-
-	struct iwl_trans *trans = priv->trans;
-
-	if (num_events == 0)
-		return pos;
-
-	base = priv->device_pointers.log_event_table;
-	if (priv->cur_ucode == IWL_UCODE_INIT) {
-		if (!base)
-			base = priv->fw->init_evtlog_ptr;
-	} else {
-		if (!base)
-			base = priv->fw->inst_evtlog_ptr;
-	}
-
-	if (mode == 0)
-		event_size = 2 * sizeof(u32);
-	else
-		event_size = 3 * sizeof(u32);
-
-	ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
-	/* Make sure device is powered up for SRAM reads */
-	spin_lock_irqsave(&trans->reg_lock, reg_flags);
-	if (unlikely(!iwl_grab_nic_access(trans)))
-		goto out_unlock;
-
-	/* Set starting address; reads will auto-increment */
-	iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr);
-
-	/* "time" is actually "data" for mode 0 (no timestamp).
-	* place event id # at far right for easier visual parsing. */
-	for (i = 0; i < num_events; i++) {
-		ev = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
-		time = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
-		if (mode == 0) {
-			/* data, ev */
-			if (bufsz) {
-				pos += scnprintf(*buf + pos, bufsz - pos,
-						"EVT_LOG:0x%08x:%04u\n",
-						time, ev);
-			} else {
-				trace_iwlwifi_dev_ucode_event(trans->dev, 0,
-					time, ev);
-				IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
-					time, ev);
-			}
-		} else {
-			data = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
-			if (bufsz) {
-				pos += scnprintf(*buf + pos, bufsz - pos,
-						"EVT_LOGT:%010u:0x%08x:%04u\n",
-						 time, data, ev);
-			} else {
-				IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
-					time, data, ev);
-				trace_iwlwifi_dev_ucode_event(trans->dev, time,
-					data, ev);
-			}
-		}
-	}
-
-	/* Allow device to power down */
-	iwl_release_nic_access(trans);
-out_unlock:
-	spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
-	return pos;
-}
-
-/**
- * iwl_print_last_event_logs - Dump the newest # of event log to syslog
- */
-static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
-				    u32 num_wraps, u32 next_entry,
-				    u32 size, u32 mode,
-				    int pos, char **buf, size_t bufsz)
-{
-	/*
-	 * display the newest DEFAULT_LOG_ENTRIES entries
-	 * i.e the entries just before the next ont that uCode would fill.
-	 */
-	if (num_wraps) {
-		if (next_entry < size) {
-			pos = iwl_print_event_log(priv,
-						capacity - (size - next_entry),
-						size - next_entry, mode,
-						pos, buf, bufsz);
-			pos = iwl_print_event_log(priv, 0,
-						  next_entry, mode,
-						  pos, buf, bufsz);
-		} else
-			pos = iwl_print_event_log(priv, next_entry - size,
-						  size, mode, pos, buf, bufsz);
-	} else {
-		if (next_entry < size) {
-			pos = iwl_print_event_log(priv, 0, next_entry,
-						  mode, pos, buf, bufsz);
-		} else {
-			pos = iwl_print_event_log(priv, next_entry - size,
-						  size, mode, pos, buf, bufsz);
-		}
-	}
-	return pos;
-}
-
-#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
-
-int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
-			    char **buf, bool display)
-{
-	u32 base;       /* SRAM byte address of event log header */
-	u32 capacity;   /* event log capacity in # entries */
-	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
-	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;
-	struct iwl_trans *trans = priv->trans;
-
-	base = priv->device_pointers.log_event_table;
-	if (priv->cur_ucode == IWL_UCODE_INIT) {
-		logsize = priv->fw->init_evtlog_size;
-		if (!base)
-			base = priv->fw->init_evtlog_ptr;
-	} else {
-		logsize = priv->fw->inst_evtlog_size;
-		if (!base)
-			base = priv->fw->inst_evtlog_ptr;
-	}
-
-	if (!iwlagn_hw_valid_rtc_data_addr(base)) {
-		IWL_ERR(priv,
-			"Invalid event log pointer 0x%08X for %s uCode\n",
-			base,
-			(priv->cur_ucode == IWL_UCODE_INIT)
-					? "Init" : "RT");
-		return -EINVAL;
-	}
-
-	/* event log header */
-	capacity = iwl_read_targ_mem(trans, base);
-	mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32)));
-	num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32)));
-	next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32)));
-
-	if (capacity > logsize) {
-		IWL_ERR(priv, "Log capacity %d is bogus, limit to %d "
-			"entries\n", capacity, logsize);
-		capacity = logsize;
-	}
-
-	if (next_entry > logsize) {
-		IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
-			next_entry, logsize);
-		next_entry = logsize;
-	}
-
-	size = num_wraps ? capacity : next_entry;
-
-	/* bail out if nothing in log */
-	if (size == 0) {
-		IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n");
-		return pos;
-	}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (!(iwl_have_debug_level(IWL_DL_FW_ERRORS)) && !full_log)
-		size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
-			? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
-#else
-	size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
-		? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
-#endif
-	IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n",
-		size);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (display) {
-		if (full_log)
-			bufsz = capacity * 48;
-		else
-			bufsz = size * 48;
-		*buf = kmalloc(bufsz, GFP_KERNEL);
-		if (!*buf)
-			return -ENOMEM;
-	}
-	if (iwl_have_debug_level(IWL_DL_FW_ERRORS) || full_log) {
-		/*
-		 * if uCode has wrapped back to top of log,
-		 * start at the oldest entry,
-		 * i.e the next one that uCode would fill.
-		 */
-		if (num_wraps)
-			pos = iwl_print_event_log(priv, next_entry,
-						capacity - next_entry, mode,
-						pos, buf, bufsz);
-		/* (then/else) start at top of log */
-		pos = iwl_print_event_log(priv, 0,
-					  next_entry, mode, pos, buf, bufsz);
-	} else
-		pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
-						next_entry, size, mode,
-						pos, buf, bufsz);
-#else
-	pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
-					next_entry, size, mode,
-					pos, buf, bufsz);
-#endif
-	return pos;
-}
-
-static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
-{
-	unsigned int reload_msec;
-	unsigned long reload_jiffies;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_have_debug_level(IWL_DL_FW_ERRORS))
-		iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
-#endif
-
-	/* uCode is no longer loaded. */
-	priv->ucode_loaded = false;
-
-	/* Set the FW error flag -- cleared on iwl_down */
-	set_bit(STATUS_FW_ERROR, &priv->status);
-
-	iwl_abort_notification_waits(&priv->notif_wait);
-
-	/* Keep the restart process from trying to send host
-	 * commands by clearing the ready bit */
-	clear_bit(STATUS_READY, &priv->status);
-
-	wake_up(&priv->trans->wait_command_queue);
-
-	if (!ondemand) {
-		/*
-		 * If firmware keep reloading, then it indicate something
-		 * serious wrong and firmware having problem to recover
-		 * from it. Instead of keep trying which will fill the syslog
-		 * and hang the system, let's just stop it
-		 */
-		reload_jiffies = jiffies;
-		reload_msec = jiffies_to_msecs((long) reload_jiffies -
-					(long) priv->reload_jiffies);
-		priv->reload_jiffies = reload_jiffies;
-		if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
-			priv->reload_count++;
-			if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
-				IWL_ERR(priv, "BUG_ON, Stop restarting\n");
-				return;
-			}
-		} else
-			priv->reload_count = 0;
-	}
-
-	if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-		if (iwlwifi_mod_params.restart_fw) {
-			IWL_DEBUG_FW_ERRORS(priv,
-				  "Restarting adapter due to uCode error.\n");
-			queue_work(priv->workqueue, &priv->restart);
-		} else
-			IWL_DEBUG_FW_ERRORS(priv,
-				  "Detected FW error, but not restarting\n");
-	}
-}
-
-void iwl_nic_error(struct iwl_op_mode *op_mode)
-{
-	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-	IWL_ERR(priv, "Loaded firmware version: %s\n",
-		priv->fw->fw_version);
-
-	iwl_dump_nic_error_log(priv);
-	iwl_dump_nic_event_log(priv, false, NULL, false);
-
-	iwlagn_fw_error(priv, false);
-}
-
-void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
-{
-	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-	if (!iwl_check_for_ct_kill(priv)) {
-		IWL_ERR(priv, "Restarting adapter queue is full\n");
-		iwlagn_fw_error(priv, false);
-	}
-}
-
-void iwl_nic_config(struct iwl_op_mode *op_mode)
-{
-	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-	priv->lib->nic_config(priv);
-}
-
-static void iwl_wimax_active(struct iwl_op_mode *op_mode)
-{
-	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-	clear_bit(STATUS_READY, &priv->status);
-	IWL_ERR(priv, "RF is used by WiMAX\n");
-}
-
-void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
-{
-	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-	int mq = priv->queue_to_mac80211[queue];
-
-	if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
-		return;
-
-	if (atomic_inc_return(&priv->queue_stop_count[mq]) > 1) {
-		IWL_DEBUG_TX_QUEUES(priv,
-			"queue %d (mac80211 %d) already stopped\n",
-			queue, mq);
-		return;
-	}
-
-	set_bit(mq, &priv->transport_queue_stop);
-	ieee80211_stop_queue(priv->hw, mq);
-}
-
-void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
-{
-	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-	int mq = priv->queue_to_mac80211[queue];
-
-	if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
-		return;
-
-	if (atomic_dec_return(&priv->queue_stop_count[mq]) > 0) {
-		IWL_DEBUG_TX_QUEUES(priv,
-			"queue %d (mac80211 %d) already awake\n",
-			queue, mq);
-		return;
-	}
-
-	clear_bit(mq, &priv->transport_queue_stop);
-
-	if (!priv->passive_no_rx)
-		ieee80211_wake_queue(priv->hw, mq);
-}
-
-void iwlagn_lift_passive_no_rx(struct iwl_priv *priv)
-{
-	int mq;
-
-	if (!priv->passive_no_rx)
-		return;
-
-	for (mq = 0; mq < IWLAGN_FIRST_AMPDU_QUEUE; mq++) {
-		if (!test_bit(mq, &priv->transport_queue_stop)) {
-			IWL_DEBUG_TX_QUEUES(priv, "Wake queue %d", mq);
-			ieee80211_wake_queue(priv->hw, mq);
-		} else {
-			IWL_DEBUG_TX_QUEUES(priv, "Don't wake queue %d", mq);
-		}
-	}
-
-	priv->passive_no_rx = false;
-}
-
-void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
-{
-	struct ieee80211_tx_info *info;
-
-	info = IEEE80211_SKB_CB(skb);
-	kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1]));
-	dev_kfree_skb_any(skb);
-}
-
-void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
-{
-	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-	if (state)
-		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, state);
-}
-
-const struct iwl_op_mode_ops iwl_dvm_ops = {
-	.start = iwl_op_mode_dvm_start,
-	.stop = iwl_op_mode_dvm_stop,
-	.rx = iwl_rx_dispatch,
-	.queue_full = iwl_stop_sw_queue,
-	.queue_not_full = iwl_wake_sw_queue,
-	.hw_rf_kill = iwl_set_hw_rfkill_state,
-	.free_skb = iwl_free_skb,
-	.nic_error = iwl_nic_error,
-	.cmd_queue_full = iwl_cmd_queue_full,
-	.nic_config = iwl_nic_config,
-	.wimax_active = iwl_wimax_active,
-};
-
-/*****************************************************************************
- *
- * driver and module entry point
- *
- *****************************************************************************/
-
-struct kmem_cache *iwl_tx_cmd_pool;
-
-static int __init iwl_init(void)
-{
-
-	int ret;
-	pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
-	pr_info(DRV_COPYRIGHT "\n");
-
-	iwl_tx_cmd_pool = kmem_cache_create("iwl_dev_cmd",
-					    sizeof(struct iwl_device_cmd),
-					    sizeof(void *), 0, NULL);
-	if (!iwl_tx_cmd_pool)
-		return -ENOMEM;
-
-	ret = iwlagn_rate_control_register();
-	if (ret) {
-		pr_err("Unable to register rate control algorithm: %d\n", ret);
-		goto error_rc_register;
-	}
-
-	ret = iwl_pci_register_driver();
-	if (ret)
-		goto error_pci_register;
-	return ret;
-
-error_pci_register:
-	iwlagn_rate_control_unregister();
-error_rc_register:
-	kmem_cache_destroy(iwl_tx_cmd_pool);
-	return ret;
-}
-
-static void __exit iwl_exit(void)
-{
-	iwl_pci_unregister_driver();
-	iwlagn_rate_control_unregister();
-	kmem_cache_destroy(iwl_tx_cmd_pool);
-}
-
-module_exit(iwl_exit);
-module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
deleted file mode 100644
index 79c0fe0..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ /dev/null
@@ -1,602 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-#ifndef __iwl_agn_h__
-#define __iwl_agn_h__
-
-#include "iwl-dev.h"
-#include "iwl-config.h"
-
-/* The first 11 queues (0-10) are used otherwise */
-#define IWLAGN_FIRST_AMPDU_QUEUE	11
-
-/* AUX (TX during scan dwell) queue */
-#define IWL_AUX_QUEUE		10
-
-/* device operations */
-extern struct iwl_lib_ops iwl1000_lib;
-extern struct iwl_lib_ops iwl2000_lib;
-extern struct iwl_lib_ops iwl2030_lib;
-extern struct iwl_lib_ops iwl5000_lib;
-extern struct iwl_lib_ops iwl5150_lib;
-extern struct iwl_lib_ops iwl6000_lib;
-extern struct iwl_lib_ops iwl6030_lib;
-
-
-#define TIME_UNIT		1024
-
-/*****************************************************
-* DRIVER STATUS FUNCTIONS
-******************************************************/
-#define STATUS_RF_KILL_HW	0
-#define STATUS_CT_KILL		1
-#define STATUS_ALIVE		2
-#define STATUS_READY		3
-#define STATUS_GEO_CONFIGURED	4
-#define STATUS_EXIT_PENDING	5
-#define STATUS_STATISTICS	6
-#define STATUS_SCANNING		7
-#define STATUS_SCAN_ABORTING	8
-#define STATUS_SCAN_HW		9
-#define STATUS_FW_ERROR		10
-#define STATUS_CHANNEL_SWITCH_PENDING 11
-#define STATUS_SCAN_COMPLETE	12
-#define STATUS_POWER_PMI	13
-
-struct iwl_ucode_capabilities;
-
-extern struct ieee80211_ops iwlagn_hw_ops;
-
-static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
-{
-	hdr->op_code = cmd;
-	hdr->first_group = 0;
-	hdr->groups_num = 1;
-	hdr->data_valid = 1;
-}
-
-void iwl_down(struct iwl_priv *priv);
-void iwl_cancel_deferred_work(struct iwl_priv *priv);
-void iwlagn_prepare_restart(struct iwl_priv *priv);
-int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode,
-				 struct iwl_rx_cmd_buffer *rxb,
-				 struct iwl_device_cmd *cmd);
-
-bool iwl_check_for_ct_kill(struct iwl_priv *priv);
-
-void iwlagn_lift_passive_no_rx(struct iwl_priv *priv);
-
-/* MAC80211 */
-struct ieee80211_hw *iwl_alloc_all(void);
-int iwlagn_mac_setup_register(struct iwl_priv *priv,
-			      const struct iwl_ucode_capabilities *capa);
-void iwlagn_mac_unregister(struct iwl_priv *priv);
-
-/* commands */
-int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
-int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
-			 u32 flags, u16 len, const void *data);
-
-/* RXON */
-void iwl_connection_init_rx_config(struct iwl_priv *priv,
-				   struct iwl_rxon_context *ctx);
-int iwlagn_set_pan_params(struct iwl_priv *priv);
-int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed);
-void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
-			     struct ieee80211_vif *vif,
-			     struct ieee80211_bss_conf *bss_conf,
-			     u32 changes);
-void iwlagn_config_ht40(struct ieee80211_conf *conf,
-			struct iwl_rxon_context *ctx);
-void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
-void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
-			 struct iwl_rxon_context *ctx);
-void iwl_set_flags_for_band(struct iwl_priv *priv,
-			    struct iwl_rxon_context *ctx,
-			    enum ieee80211_band band,
-			    struct ieee80211_vif *vif);
-
-/* uCode */
-int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
-void iwl_send_prio_tbl(struct iwl_priv *priv);
-int iwl_init_alive_start(struct iwl_priv *priv);
-int iwl_run_init_ucode(struct iwl_priv *priv);
-int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
-			      enum iwl_ucode_type ucode_type);
-int iwl_send_calib_results(struct iwl_priv *priv);
-int iwl_calib_set(struct iwl_priv *priv,
-		  const struct iwl_calib_hdr *cmd, int len);
-void iwl_calib_free_results(struct iwl_priv *priv);
-int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
-			    char **buf, bool display);
-int iwlagn_hw_valid_rtc_data_addr(u32 addr);
-
-/* lib */
-int iwlagn_send_tx_power(struct iwl_priv *priv);
-void iwlagn_temperature(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);
-int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
-int iwl_send_statistics_request(struct iwl_priv *priv,
-				u8 flags, bool clear);
-
-static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
-			struct iwl_priv *priv, enum ieee80211_band band)
-{
-	return priv->hw->wiphy->bands[band];
-}
-
-#ifdef CONFIG_PM_SLEEP
-int iwlagn_send_patterns(struct iwl_priv *priv,
-			 struct cfg80211_wowlan *wowlan);
-int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan);
-#endif
-
-/* rx */
-int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
-void iwl_setup_rx_handlers(struct iwl_priv *priv);
-void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
-
-
-/* tx */
-int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
-int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
-			struct ieee80211_sta *sta, u16 tid, u16 *ssn);
-int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
-			struct ieee80211_sta *sta, u16 tid, u8 buf_size);
-int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
-		       struct ieee80211_sta *sta, u16 tid);
-int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
-				   struct iwl_rx_cmd_buffer *rxb,
-				   struct iwl_device_cmd *cmd);
-int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-			       struct iwl_device_cmd *cmd);
-
-static inline u32 iwl_tx_status_to_mac80211(u32 status)
-{
-	status &= TX_STATUS_MSK;
-
-	switch (status) {
-	case TX_STATUS_SUCCESS:
-	case TX_STATUS_DIRECT_DONE:
-		return IEEE80211_TX_STAT_ACK;
-	case TX_STATUS_FAIL_DEST_PS:
-	case TX_STATUS_FAIL_PASSIVE_NO_RX:
-		return IEEE80211_TX_STAT_TX_FILTERED;
-	default:
-		return 0;
-	}
-}
-
-static inline bool iwl_is_tx_success(u32 status)
-{
-	status &= TX_STATUS_MSK;
-	return (status == TX_STATUS_SUCCESS) ||
-	       (status == TX_STATUS_DIRECT_DONE);
-}
-
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
-
-/* scan */
-void iwlagn_post_scan(struct iwl_priv *priv);
-void iwlagn_disable_roc(struct iwl_priv *priv);
-int iwl_force_rf_reset(struct iwl_priv *priv, bool external);
-void iwl_init_scan_params(struct iwl_priv *priv);
-int iwl_scan_cancel(struct iwl_priv *priv);
-void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
-void iwl_force_scan_end(struct iwl_priv *priv);
-void iwl_internal_short_hw_scan(struct iwl_priv *priv);
-void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
-void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
-void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
-int __must_check iwl_scan_initiate(struct iwl_priv *priv,
-				   struct ieee80211_vif *vif,
-				   enum iwl_scan_type scan_type,
-				   enum ieee80211_band band);
-
-/* For faster active scanning, scan will move to the next channel if fewer than
- * PLCP_QUIET_THRESH packets are heard on this channel within
- * ACTIVE_QUIET_TIME after sending probe request.  This shortens the dwell
- * time if it's a quiet channel (nothing responded to our probe, and there's
- * no other traffic).
- * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
-#define IWL_ACTIVE_QUIET_TIME       cpu_to_le16(10)  /* msec */
-#define IWL_PLCP_QUIET_THRESH       cpu_to_le16(1)  /* packets */
-
-#define IWL_SCAN_CHECK_WATCHDOG		(HZ * 7)
-
-
-/* bt coex */
-void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
-int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
-				  struct iwl_rx_cmd_buffer *rxb,
-				  struct iwl_device_cmd *cmd);
-void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);
-void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);
-void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
-void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv);
-void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena);
-
-static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
-{
-	return priv->cfg->bt_params &&
-	       priv->cfg->bt_params->advanced_bt_coexist;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-const char *iwl_get_tx_fail_reason(u32 status);
-const char *iwl_get_agg_tx_fail_reason(u16 status);
-#else
-static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
-static inline const char *iwl_get_agg_tx_fail_reason(u16 status) { return ""; }
-#endif
-
-
-/* station management */
-int iwlagn_manage_ibss_station(struct iwl_priv *priv,
-			       struct ieee80211_vif *vif, bool add);
-#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
-#define IWL_STA_UCODE_ACTIVE  BIT(1) /* ucode entry is active */
-#define IWL_STA_UCODE_INPROGRESS  BIT(2) /* ucode entry is in process of
-					    being activated */
-#define IWL_STA_LOCAL BIT(3) /* station state not directed by mac80211;
-				(this is for the IBSS BSSID stations) */
-#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */
-
-
-void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-void iwl_clear_ucode_stations(struct iwl_priv *priv,
-			      struct iwl_rxon_context *ctx);
-void iwl_dealloc_bcast_stations(struct iwl_priv *priv);
-int iwl_get_free_ucode_key_offset(struct iwl_priv *priv);
-int iwl_send_add_sta(struct iwl_priv *priv,
-		     struct iwl_addsta_cmd *sta, u8 flags);
-int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-			   const u8 *addr, bool is_ap,
-			   struct ieee80211_sta *sta, u8 *sta_id_r);
-int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
-		       const u8 *addr);
-void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
-			    const u8 *addr);
-u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-		    const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
-
-int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-		    struct iwl_link_quality_cmd *lq, u8 flags, bool init);
-int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-			       struct iwl_device_cmd *cmd);
-int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-		      struct ieee80211_sta *sta);
-
-bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
-			    struct iwl_rxon_context *ctx,
-			    struct ieee80211_sta_ht_cap *ht_cap);
-
-static inline int iwl_sta_id(struct ieee80211_sta *sta)
-{
-	if (WARN_ON(!sta))
-		return IWL_INVALID_STATION;
-
-	return ((struct iwl_station_priv *)sta->drv_priv)->sta_id;
-}
-
-int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
-			       struct iwl_rxon_context *ctx);
-int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-			     const u8 *addr, u8 *sta_id_r);
-int iwl_remove_default_wep_key(struct iwl_priv *priv,
-			       struct iwl_rxon_context *ctx,
-			       struct ieee80211_key_conf *key);
-int iwl_set_default_wep_key(struct iwl_priv *priv,
-			    struct iwl_rxon_context *ctx,
-			    struct ieee80211_key_conf *key);
-int iwl_restore_default_wep_keys(struct iwl_priv *priv,
-				 struct iwl_rxon_context *ctx);
-int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-			struct ieee80211_key_conf *key,
-			struct ieee80211_sta *sta);
-int iwl_remove_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-			   struct ieee80211_key_conf *key,
-			   struct ieee80211_sta *sta);
-void iwl_update_tkip_key(struct iwl_priv *priv,
-			 struct ieee80211_vif *vif,
-			 struct ieee80211_key_conf *keyconf,
-			 struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
-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,
-			int tid);
-void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
-int iwl_update_bcast_station(struct iwl_priv *priv,
-			     struct iwl_rxon_context *ctx);
-int iwl_update_bcast_stations(struct iwl_priv *priv);
-
-/* rate */
-static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
-{
-	return BIT(ant_idx) << RATE_MCS_ANT_POS;
-}
-
-static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
-{
-	return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK;
-}
-
-static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
-{
-	return cpu_to_le32(flags|(u32)rate);
-}
-
-extern int iwl_alive_start(struct iwl_priv *priv);
-/* svtool */
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-extern int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data,
-				   int len);
-extern int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw,
-				    struct sk_buff *skb,
-				    struct netlink_callback *cb,
-				    void *data, int len);
-extern void iwl_testmode_init(struct iwl_priv *priv);
-extern void iwl_testmode_cleanup(struct iwl_priv *priv);
-#else
-static inline
-int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
-{
-	return -ENOSYS;
-}
-static inline
-int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
-		      struct netlink_callback *cb,
-		      void *data, int len)
-{
-	return -ENOSYS;
-}
-static inline
-void iwl_testmode_init(struct iwl_priv *priv)
-{
-}
-static inline
-void iwl_testmode_cleanup(struct iwl_priv *priv)
-{
-}
-#endif
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv,
-			     enum iwl_rxon_context_id ctxid);
-#else
-static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
-					   enum iwl_rxon_context_id ctxid)
-{
-}
-#endif
-
-/* status checks */
-
-static inline int iwl_is_ready(struct iwl_priv *priv)
-{
-	/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
-	 * set but EXIT_PENDING is not */
-	return test_bit(STATUS_READY, &priv->status) &&
-	       test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
-	       !test_bit(STATUS_EXIT_PENDING, &priv->status);
-}
-
-static inline int iwl_is_alive(struct iwl_priv *priv)
-{
-	return test_bit(STATUS_ALIVE, &priv->status);
-}
-
-static inline int iwl_is_rfkill(struct iwl_priv *priv)
-{
-	return test_bit(STATUS_RF_KILL_HW, &priv->status);
-}
-
-static inline int iwl_is_ctkill(struct iwl_priv *priv)
-{
-	return test_bit(STATUS_CT_KILL, &priv->status);
-}
-
-static inline int iwl_is_ready_rf(struct iwl_priv *priv)
-{
-	if (iwl_is_rfkill(priv))
-		return 0;
-
-	return iwl_is_ready(priv);
-}
-
-static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state)
-{
-	if (state)
-		set_bit(STATUS_POWER_PMI, &priv->status);
-	else
-		clear_bit(STATUS_POWER_PMI, &priv->status);
-	iwl_trans_set_pmi(priv->trans, state);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-int iwl_dbgfs_register(struct iwl_priv *priv, const char *name);
-void iwl_dbgfs_unregister(struct iwl_priv *priv);
-#else
-static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
-{
-	return 0;
-}
-static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
-{
-}
-#endif /* CONFIG_IWLWIFI_DEBUGFS */
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)	\
-do {									\
-	if (!iwl_is_rfkill((m)))					\
-		IWL_ERR(m, fmt, ##args);				\
-	else								\
-		__iwl_err((m)->dev, true,				\
-			  !iwl_have_debug_level(IWL_DL_RADIO),		\
-			  fmt, ##args);					\
-} while (0)
-#else
-#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)	\
-do {									\
-	if (!iwl_is_rfkill((m)))					\
-		IWL_ERR(m, fmt, ##args);				\
-	else								\
-		__iwl_err((m)->dev, true, true, fmt, ##args);	\
-} while (0)
-#endif				/* CONFIG_IWLWIFI_DEBUG */
-
-extern const char *iwl_dvm_cmd_strings[REPLY_MAX];
-
-static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
-{
-	const char *s = iwl_dvm_cmd_strings[cmd];
-	if (s)
-		return s;
-	return "UNKNOWN";
-}
-
-/* API method exported for mvm hybrid state */
-void iwl_setup_deferred_work(struct iwl_priv *priv);
-int iwl_send_wimax_coex(struct iwl_priv *priv);
-int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
-void iwl_option_config(struct iwl_priv *priv);
-void iwl_set_hw_params(struct iwl_priv *priv);
-void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags);
-int iwl_init_drv(struct iwl_priv *priv);
-void iwl_uninit_drv(struct iwl_priv *priv);
-void iwl_send_bt_config(struct iwl_priv *priv);
-void iwl_rf_kill_ct_config(struct iwl_priv *priv);
-int iwl_setup_interface(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-void iwl_teardown_interface(struct iwl_priv *priv,
-			    struct ieee80211_vif *vif,
-			    bool mode_change);
-int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-void iwlagn_check_needed_chains(struct iwl_priv *priv,
-				struct iwl_rxon_context *ctx,
-				struct ieee80211_bss_conf *bss_conf);
-void iwlagn_chain_noise_reset(struct iwl_priv *priv);
-int iwlagn_update_beacon(struct iwl_priv *priv,
-			 struct ieee80211_vif *vif);
-void iwl_tt_handler(struct iwl_priv *priv);
-void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode);
-void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue);
-void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state);
-void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb);
-void iwl_nic_error(struct iwl_op_mode *op_mode);
-void iwl_cmd_queue_full(struct iwl_op_mode *op_mode);
-void iwl_nic_config(struct iwl_op_mode *op_mode);
-int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
-		       struct ieee80211_sta *sta, bool set);
-void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
-			      enum ieee80211_rssi_event rssi_event);
-int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw);
-int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw);
-void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop);
-void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue);
-void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
-			       struct ieee80211_channel_switch *ch_switch);
-int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
-			 struct ieee80211_vif *vif,
-			 struct ieee80211_sta *sta,
-			 enum ieee80211_sta_state old_state,
-			 enum ieee80211_sta_state new_state);
-int iwlagn_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,
-			    u8 buf_size);
-int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
-		       struct ieee80211_vif *vif,
-		       struct cfg80211_scan_request *req);
-void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
-			   struct ieee80211_vif *vif,
-			   enum sta_notify_cmd cmd,
-			   struct ieee80211_sta *sta);
-void iwlagn_configure_filter(struct ieee80211_hw *hw,
-			     unsigned int changed_flags,
-			     unsigned int *total_flags,
-			     u64 multicast);
-int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
-		       struct ieee80211_vif *vif, u16 queue,
-		       const struct ieee80211_tx_queue_params *params);
-void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
-			       struct ieee80211_vif *vif,
-			       struct cfg80211_gtk_rekey_data *data);
-void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
-				struct ieee80211_vif *vif,
-				struct ieee80211_key_conf *keyconf,
-				struct ieee80211_sta *sta,
-				u32 iv32, u16 *phase1key);
-int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
-		       struct ieee80211_vif *vif,
-		       struct ieee80211_sta *sta,
-		       struct ieee80211_key_conf *key);
-void iwlagn_mac_stop(struct ieee80211_hw *hw);
-void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
-int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
-#endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-cfg.h b/drivers/net/wireless/iwlwifi/iwl-cfg.h
deleted file mode 100644
index 82152311..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-cfg.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2007 - 2012 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
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#ifndef __iwl_pci_h__
-#define __iwl_pci_h__
-
-
-/*
- * This file declares the config structures for all devices.
- */
-
-extern const struct iwl_cfg iwl5300_agn_cfg;
-extern const struct iwl_cfg iwl5100_agn_cfg;
-extern const struct iwl_cfg iwl5350_agn_cfg;
-extern const struct iwl_cfg iwl5100_bgn_cfg;
-extern const struct iwl_cfg iwl5100_abg_cfg;
-extern const struct iwl_cfg iwl5150_agn_cfg;
-extern const struct iwl_cfg iwl5150_abg_cfg;
-extern const struct iwl_cfg iwl6005_2agn_cfg;
-extern const struct iwl_cfg iwl6005_2abg_cfg;
-extern const struct iwl_cfg iwl6005_2bg_cfg;
-extern const struct iwl_cfg iwl6005_2agn_sff_cfg;
-extern const struct iwl_cfg iwl6005_2agn_d_cfg;
-extern const struct iwl_cfg iwl6005_2agn_mow1_cfg;
-extern const struct iwl_cfg iwl6005_2agn_mow2_cfg;
-extern const struct iwl_cfg iwl1030_bgn_cfg;
-extern const struct iwl_cfg iwl1030_bg_cfg;
-extern const struct iwl_cfg iwl6030_2agn_cfg;
-extern const struct iwl_cfg iwl6030_2abg_cfg;
-extern const struct iwl_cfg iwl6030_2bgn_cfg;
-extern const struct iwl_cfg iwl6030_2bg_cfg;
-extern const struct iwl_cfg iwl6000i_2agn_cfg;
-extern const struct iwl_cfg iwl6000i_2abg_cfg;
-extern const struct iwl_cfg iwl6000i_2bg_cfg;
-extern const struct iwl_cfg iwl6000_3agn_cfg;
-extern const struct iwl_cfg iwl6050_2agn_cfg;
-extern const struct iwl_cfg iwl6050_2abg_cfg;
-extern const struct iwl_cfg iwl6150_bgn_cfg;
-extern const struct iwl_cfg iwl6150_bg_cfg;
-extern const struct iwl_cfg iwl1000_bgn_cfg;
-extern const struct iwl_cfg iwl1000_bg_cfg;
-extern const struct iwl_cfg iwl100_bgn_cfg;
-extern const struct iwl_cfg iwl100_bg_cfg;
-extern const struct iwl_cfg iwl130_bgn_cfg;
-extern const struct iwl_cfg iwl130_bg_cfg;
-extern const struct iwl_cfg iwl2000_2bgn_cfg;
-extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
-extern const struct iwl_cfg iwl2030_2bgn_cfg;
-extern const struct iwl_cfg iwl6035_2agn_cfg;
-extern const struct iwl_cfg iwl105_bgn_cfg;
-extern const struct iwl_cfg iwl105_bgn_d_cfg;
-extern const struct iwl_cfg iwl135_bgn_cfg;
-
-#endif /* __iwl_pci_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
deleted file mode 100644
index 9af6a23..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ /dev/null
@@ -1,3961 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2005 - 2012 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
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-/*
- * Please use this file (iwl-commands.h) only for uCode API definitions.
- * Please use iwl-xxxx-hw.h for hardware-related definitions.
- * Please use iwl-dev.h for driver implementation definitions.
- */
-
-#ifndef __iwl_commands_h__
-#define __iwl_commands_h__
-
-#include <linux/ieee80211.h>
-#include <linux/types.h>
-
-
-enum {
-	REPLY_ALIVE = 0x1,
-	REPLY_ERROR = 0x2,
-	REPLY_ECHO = 0x3,		/* test command */
-
-	/* RXON and QOS commands */
-	REPLY_RXON = 0x10,
-	REPLY_RXON_ASSOC = 0x11,
-	REPLY_QOS_PARAM = 0x13,
-	REPLY_RXON_TIMING = 0x14,
-
-	/* Multi-Station support */
-	REPLY_ADD_STA = 0x18,
-	REPLY_REMOVE_STA = 0x19,
-	REPLY_REMOVE_ALL_STA = 0x1a,	/* not used */
-	REPLY_TXFIFO_FLUSH = 0x1e,
-
-	/* Security */
-	REPLY_WEPKEY = 0x20,
-
-	/* RX, TX, LEDs */
-	REPLY_TX = 0x1c,
-	REPLY_LEDS_CMD = 0x48,
-	REPLY_TX_LINK_QUALITY_CMD = 0x4e,
-
-	/* WiMAX coexistence */
-	COEX_PRIORITY_TABLE_CMD = 0x5a,
-	COEX_MEDIUM_NOTIFICATION = 0x5b,
-	COEX_EVENT_CMD = 0x5c,
-
-	/* Calibration */
-	TEMPERATURE_NOTIFICATION = 0x62,
-	CALIBRATION_CFG_CMD = 0x65,
-	CALIBRATION_RES_NOTIFICATION = 0x66,
-	CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
-
-	/* 802.11h related */
-	REPLY_QUIET_CMD = 0x71,		/* not used */
-	REPLY_CHANNEL_SWITCH = 0x72,
-	CHANNEL_SWITCH_NOTIFICATION = 0x73,
-	REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
-	SPECTRUM_MEASURE_NOTIFICATION = 0x75,
-
-	/* Power Management */
-	POWER_TABLE_CMD = 0x77,
-	PM_SLEEP_NOTIFICATION = 0x7A,
-	PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
-
-	/* Scan commands and notifications */
-	REPLY_SCAN_CMD = 0x80,
-	REPLY_SCAN_ABORT_CMD = 0x81,
-	SCAN_START_NOTIFICATION = 0x82,
-	SCAN_RESULTS_NOTIFICATION = 0x83,
-	SCAN_COMPLETE_NOTIFICATION = 0x84,
-
-	/* IBSS/AP commands */
-	BEACON_NOTIFICATION = 0x90,
-	REPLY_TX_BEACON = 0x91,
-	WHO_IS_AWAKE_NOTIFICATION = 0x94,	/* not used */
-
-	/* Miscellaneous commands */
-	REPLY_TX_POWER_DBM_CMD = 0x95,
-	QUIET_NOTIFICATION = 0x96,		/* not used */
-	REPLY_TX_PWR_TABLE_CMD = 0x97,
-	REPLY_TX_POWER_DBM_CMD_V1 = 0x98,	/* old version of API */
-	TX_ANT_CONFIGURATION_CMD = 0x98,
-	MEASURE_ABORT_NOTIFICATION = 0x99,	/* not used */
-
-	/* Bluetooth device coexistence config command */
-	REPLY_BT_CONFIG = 0x9b,
-
-	/* Statistics */
-	REPLY_STATISTICS_CMD = 0x9c,
-	STATISTICS_NOTIFICATION = 0x9d,
-
-	/* RF-KILL commands and notifications */
-	REPLY_CARD_STATE_CMD = 0xa0,
-	CARD_STATE_NOTIFICATION = 0xa1,
-
-	/* Missed beacons notification */
-	MISSED_BEACONS_NOTIFICATION = 0xa2,
-
-	REPLY_CT_KILL_CONFIG_CMD = 0xa4,
-	SENSITIVITY_CMD = 0xa8,
-	REPLY_PHY_CALIBRATION_CMD = 0xb0,
-	REPLY_RX_PHY_CMD = 0xc0,
-	REPLY_RX_MPDU_CMD = 0xc1,
-	REPLY_RX = 0xc3,
-	REPLY_COMPRESSED_BA = 0xc5,
-
-	/* BT Coex */
-	REPLY_BT_COEX_PRIO_TABLE = 0xcc,
-	REPLY_BT_COEX_PROT_ENV = 0xcd,
-	REPLY_BT_COEX_PROFILE_NOTIF = 0xce,
-
-	/* PAN commands */
-	REPLY_WIPAN_PARAMS = 0xb2,
-	REPLY_WIPAN_RXON = 0xb3,	/* use REPLY_RXON structure */
-	REPLY_WIPAN_RXON_TIMING = 0xb4,	/* use REPLY_RXON_TIMING structure */
-	REPLY_WIPAN_RXON_ASSOC = 0xb6,	/* use REPLY_RXON_ASSOC structure */
-	REPLY_WIPAN_QOS_PARAM = 0xb7,	/* use REPLY_QOS_PARAM structure */
-	REPLY_WIPAN_WEPKEY = 0xb8,	/* use REPLY_WEPKEY structure */
-	REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9,
-	REPLY_WIPAN_NOA_NOTIFICATION = 0xbc,
-	REPLY_WIPAN_DEACTIVATION_COMPLETE = 0xbd,
-
-	REPLY_WOWLAN_PATTERNS = 0xe0,
-	REPLY_WOWLAN_WAKEUP_FILTER = 0xe1,
-	REPLY_WOWLAN_TSC_RSC_PARAMS = 0xe2,
-	REPLY_WOWLAN_TKIP_PARAMS = 0xe3,
-	REPLY_WOWLAN_KEK_KCK_MATERIAL = 0xe4,
-	REPLY_WOWLAN_GET_STATUS = 0xe5,
-	REPLY_D3_CONFIG = 0xd3,
-
-	REPLY_MAX = 0xff
-};
-
-/******************************************************************************
- * (0)
- * Commonly used structures and definitions:
- * Command header, rate_n_flags, txpower
- *
- *****************************************************************************/
-
-/* iwl_cmd_header flags value */
-#define IWL_CMD_FAILED_MSK 0x40
-
-/**
- * iwlagn rate_n_flags bit fields
- *
- * rate_n_flags format is used in following iwlagn commands:
- *  REPLY_RX (response only)
- *  REPLY_RX_MPDU (response only)
- *  REPLY_TX (both command and response)
- *  REPLY_TX_LINK_QUALITY_CMD
- *
- * High-throughput (HT) rate format for bits 7:0 (bit 8 must be "1"):
- *  2-0:  0)   6 Mbps
- *        1)  12 Mbps
- *        2)  18 Mbps
- *        3)  24 Mbps
- *        4)  36 Mbps
- *        5)  48 Mbps
- *        6)  54 Mbps
- *        7)  60 Mbps
- *
- *  4-3:  0)  Single stream (SISO)
- *        1)  Dual stream (MIMO)
- *        2)  Triple stream (MIMO)
- *
- *    5:  Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data
- *
- * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"):
- *  3-0:  0xD)   6 Mbps
- *        0xF)   9 Mbps
- *        0x5)  12 Mbps
- *        0x7)  18 Mbps
- *        0x9)  24 Mbps
- *        0xB)  36 Mbps
- *        0x1)  48 Mbps
- *        0x3)  54 Mbps
- *
- * Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"):
- *  6-0:   10)  1 Mbps
- *         20)  2 Mbps
- *         55)  5.5 Mbps
- *        110)  11 Mbps
- */
-#define RATE_MCS_CODE_MSK 0x7
-#define RATE_MCS_SPATIAL_POS 3
-#define RATE_MCS_SPATIAL_MSK 0x18
-#define RATE_MCS_HT_DUP_POS 5
-#define RATE_MCS_HT_DUP_MSK 0x20
-/* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */
-#define RATE_MCS_RATE_MSK 0xff
-
-/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */
-#define RATE_MCS_FLAGS_POS 8
-#define RATE_MCS_HT_POS 8
-#define RATE_MCS_HT_MSK 0x100
-
-/* Bit 9: (1) CCK, (0) OFDM.  HT (bit 8) must be "0" for this bit to be valid */
-#define RATE_MCS_CCK_POS 9
-#define RATE_MCS_CCK_MSK 0x200
-
-/* Bit 10: (1) Use Green Field preamble */
-#define RATE_MCS_GF_POS 10
-#define RATE_MCS_GF_MSK 0x400
-
-/* Bit 11: (1) Use 40Mhz HT40 chnl width, (0) use 20 MHz legacy chnl width */
-#define RATE_MCS_HT40_POS 11
-#define RATE_MCS_HT40_MSK 0x800
-
-/* Bit 12: (1) Duplicate data on both 20MHz chnls. HT40 (bit 11) must be set. */
-#define RATE_MCS_DUP_POS 12
-#define RATE_MCS_DUP_MSK 0x1000
-
-/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */
-#define RATE_MCS_SGI_POS 13
-#define RATE_MCS_SGI_MSK 0x2000
-
-/**
- * rate_n_flags Tx antenna masks
- * 4965 has 2 transmitters
- * 5100 has 1 transmitter B
- * 5150 has 1 transmitter A
- * 5300 has 3 transmitters
- * 5350 has 3 transmitters
- * bit14:16
- */
-#define RATE_MCS_ANT_POS	14
-#define RATE_MCS_ANT_A_MSK	0x04000
-#define RATE_MCS_ANT_B_MSK	0x08000
-#define RATE_MCS_ANT_C_MSK	0x10000
-#define RATE_MCS_ANT_AB_MSK	(RATE_MCS_ANT_A_MSK | RATE_MCS_ANT_B_MSK)
-#define RATE_MCS_ANT_ABC_MSK	(RATE_MCS_ANT_AB_MSK | RATE_MCS_ANT_C_MSK)
-#define RATE_ANT_NUM 3
-
-#define POWER_TABLE_NUM_ENTRIES			33
-#define POWER_TABLE_NUM_HT_OFDM_ENTRIES		32
-#define POWER_TABLE_CCK_ENTRY			32
-
-#define IWL_PWR_NUM_HT_OFDM_ENTRIES		24
-#define IWL_PWR_CCK_ENTRIES			2
-
-/**
- * struct tx_power_dual_stream
- *
- * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
- *
- * Same format as iwl_tx_power_dual_stream, but __le32
- */
-struct tx_power_dual_stream {
-	__le32 dw;
-} __packed;
-
-/**
- * Command REPLY_TX_POWER_DBM_CMD = 0x98
- * struct iwlagn_tx_power_dbm_cmd
- */
-#define IWLAGN_TX_POWER_AUTO 0x7f
-#define IWLAGN_TX_POWER_NO_CLOSED (0x1 << 6)
-
-struct iwlagn_tx_power_dbm_cmd {
-	s8 global_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
-	u8 flags;
-	s8 srv_chan_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
-	u8 reserved;
-} __packed;
-
-/**
- * Command TX_ANT_CONFIGURATION_CMD = 0x98
- * This command is used to configure valid Tx antenna.
- * By default uCode concludes the valid antenna according to the radio flavor.
- * This command enables the driver to override/modify this conclusion.
- */
-struct iwl_tx_ant_config_cmd {
-	__le32 valid;
-} __packed;
-
-/******************************************************************************
- * (0a)
- * Alive and Error Commands & Responses:
- *
- *****************************************************************************/
-
-#define UCODE_VALID_OK	cpu_to_le32(0x1)
-
-/**
- * REPLY_ALIVE = 0x1 (response only, not a command)
- *
- * uCode issues this "alive" notification once the runtime image is ready
- * to receive commands from the driver.  This is the *second* "alive"
- * notification that the driver will receive after rebooting uCode;
- * this "alive" is indicated by subtype field != 9.
- *
- * See comments documenting "BSM" (bootstrap state machine).
- *
- * This response includes two pointers to structures within the device's
- * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging:
- *
- * 1)  log_event_table_ptr indicates base of the event log.  This traces
- *     a 256-entry history of uCode execution within a circular buffer.
- *     Its header format is:
- *
- *	__le32 log_size;     log capacity (in number of entries)
- *	__le32 type;         (1) timestamp with each entry, (0) no timestamp
- *	__le32 wraps;        # times uCode has wrapped to top of circular buffer
- *      __le32 write_index;  next circular buffer entry that uCode would fill
- *
- *     The header is followed by the circular buffer of log entries.  Entries
- *     with timestamps have the following format:
- *
- *	__le32 event_id;     range 0 - 1500
- *	__le32 timestamp;    low 32 bits of TSF (of network, if associated)
- *	__le32 data;         event_id-specific data value
- *
- *     Entries without timestamps contain only event_id and data.
- *
- *
- * 2)  error_event_table_ptr indicates base of the error log.  This contains
- *     information about any uCode error that occurs.  For agn, the format
- *     of the error log is defined by struct iwl_error_event_table.
- *
- * The Linux driver can print both logs to the system log when a uCode error
- * occurs.
- */
-
-/*
- * Note: This structure is read from the device with IO accesses,
- * and the reading already does the endian conversion. As it is
- * read with u32-sized accesses, any members with a different size
- * need to be ordered correctly though!
- */
-struct iwl_error_event_table {
-	u32 valid;		/* (nonzero) valid, (0) log is empty */
-	u32 error_id;		/* type of error */
-	u32 pc;			/* program counter */
-	u32 blink1;		/* branch link */
-	u32 blink2;		/* branch link */
-	u32 ilink1;		/* interrupt link */
-	u32 ilink2;		/* interrupt link */
-	u32 data1;		/* error-specific data */
-	u32 data2;		/* error-specific data */
-	u32 line;		/* source code line of error */
-	u32 bcon_time;		/* beacon timer */
-	u32 tsf_low;		/* network timestamp function timer */
-	u32 tsf_hi;		/* network timestamp function timer */
-	u32 gp1;		/* GP1 timer register */
-	u32 gp2;		/* GP2 timer register */
-	u32 gp3;		/* GP3 timer register */
-	u32 ucode_ver;		/* uCode version */
-	u32 hw_ver;		/* HW Silicon version */
-	u32 brd_ver;		/* HW board version */
-	u32 log_pc;		/* log program counter */
-	u32 frame_ptr;		/* frame pointer */
-	u32 stack_ptr;		/* stack pointer */
-	u32 hcmd;		/* last host command header */
-	u32 isr0;		/* isr status register LMPM_NIC_ISR0:
-				 * rxtx_flag */
-	u32 isr1;		/* isr status register LMPM_NIC_ISR1:
-				 * host_flag */
-	u32 isr2;		/* isr status register LMPM_NIC_ISR2:
-				 * enc_flag */
-	u32 isr3;		/* isr status register LMPM_NIC_ISR3:
-				 * time_flag */
-	u32 isr4;		/* isr status register LMPM_NIC_ISR4:
-				 * wico interrupt */
-	u32 isr_pref;		/* isr status register LMPM_NIC_PREF_STAT */
-	u32 wait_event;		/* wait event() caller address */
-	u32 l2p_control;	/* L2pControlField */
-	u32 l2p_duration;	/* L2pDurationField */
-	u32 l2p_mhvalid;	/* L2pMhValidBits */
-	u32 l2p_addr_match;	/* L2pAddrMatchStat */
-	u32 lmpm_pmg_sel;	/* indicate which clocks are turned on
-				 * (LMPM_PMG_SEL) */
-	u32 u_timestamp;	/* indicate when the date and time of the
-				 * compilation */
-	u32 flow_handler;	/* FH read/write pointers, RX credit */
-} __packed;
-
-struct iwl_alive_resp {
-	u8 ucode_minor;
-	u8 ucode_major;
-	__le16 reserved1;
-	u8 sw_rev[8];
-	u8 ver_type;
-	u8 ver_subtype;			/* not "9" for runtime alive */
-	__le16 reserved2;
-	__le32 log_event_table_ptr;	/* SRAM address for event log */
-	__le32 error_event_table_ptr;	/* SRAM address for error log */
-	__le32 timestamp;
-	__le32 is_valid;
-} __packed;
-
-/*
- * REPLY_ERROR = 0x2 (response only, not a command)
- */
-struct iwl_error_resp {
-	__le32 error_type;
-	u8 cmd_id;
-	u8 reserved1;
-	__le16 bad_cmd_seq_num;
-	__le32 error_info;
-	__le64 timestamp;
-} __packed;
-
-/******************************************************************************
- * (1)
- * RXON Commands & Responses:
- *
- *****************************************************************************/
-
-/*
- * Rx config defines & structure
- */
-/* rx_config device types  */
-enum {
-	RXON_DEV_TYPE_AP = 1,
-	RXON_DEV_TYPE_ESS = 3,
-	RXON_DEV_TYPE_IBSS = 4,
-	RXON_DEV_TYPE_SNIFFER = 6,
-	RXON_DEV_TYPE_CP = 7,
-	RXON_DEV_TYPE_2STA = 8,
-	RXON_DEV_TYPE_P2P = 9,
-};
-
-
-#define RXON_RX_CHAIN_DRIVER_FORCE_MSK		cpu_to_le16(0x1 << 0)
-#define RXON_RX_CHAIN_DRIVER_FORCE_POS		(0)
-#define RXON_RX_CHAIN_VALID_MSK			cpu_to_le16(0x7 << 1)
-#define RXON_RX_CHAIN_VALID_POS			(1)
-#define RXON_RX_CHAIN_FORCE_SEL_MSK		cpu_to_le16(0x7 << 4)
-#define RXON_RX_CHAIN_FORCE_SEL_POS		(4)
-#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK	cpu_to_le16(0x7 << 7)
-#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS	(7)
-#define RXON_RX_CHAIN_CNT_MSK			cpu_to_le16(0x3 << 10)
-#define RXON_RX_CHAIN_CNT_POS			(10)
-#define RXON_RX_CHAIN_MIMO_CNT_MSK		cpu_to_le16(0x3 << 12)
-#define RXON_RX_CHAIN_MIMO_CNT_POS		(12)
-#define RXON_RX_CHAIN_MIMO_FORCE_MSK		cpu_to_le16(0x1 << 14)
-#define RXON_RX_CHAIN_MIMO_FORCE_POS		(14)
-
-/* rx_config flags */
-/* band & modulation selection */
-#define RXON_FLG_BAND_24G_MSK           cpu_to_le32(1 << 0)
-#define RXON_FLG_CCK_MSK                cpu_to_le32(1 << 1)
-/* auto detection enable */
-#define RXON_FLG_AUTO_DETECT_MSK        cpu_to_le32(1 << 2)
-/* TGg protection when tx */
-#define RXON_FLG_TGG_PROTECT_MSK        cpu_to_le32(1 << 3)
-/* cck short slot & preamble */
-#define RXON_FLG_SHORT_SLOT_MSK          cpu_to_le32(1 << 4)
-#define RXON_FLG_SHORT_PREAMBLE_MSK     cpu_to_le32(1 << 5)
-/* antenna selection */
-#define RXON_FLG_DIS_DIV_MSK            cpu_to_le32(1 << 7)
-#define RXON_FLG_ANT_SEL_MSK            cpu_to_le32(0x0f00)
-#define RXON_FLG_ANT_A_MSK              cpu_to_le32(1 << 8)
-#define RXON_FLG_ANT_B_MSK              cpu_to_le32(1 << 9)
-/* radar detection enable */
-#define RXON_FLG_RADAR_DETECT_MSK       cpu_to_le32(1 << 12)
-#define RXON_FLG_TGJ_NARROW_BAND_MSK    cpu_to_le32(1 << 13)
-/* rx response to host with 8-byte TSF
-* (according to ON_AIR deassertion) */
-#define RXON_FLG_TSF2HOST_MSK           cpu_to_le32(1 << 15)
-
-
-/* HT flags */
-#define RXON_FLG_CTRL_CHANNEL_LOC_POS		(22)
-#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK	cpu_to_le32(0x1 << 22)
-
-#define RXON_FLG_HT_OPERATING_MODE_POS		(23)
-
-#define RXON_FLG_HT_PROT_MSK			cpu_to_le32(0x1 << 23)
-#define RXON_FLG_HT40_PROT_MSK			cpu_to_le32(0x2 << 23)
-
-#define RXON_FLG_CHANNEL_MODE_POS		(25)
-#define RXON_FLG_CHANNEL_MODE_MSK		cpu_to_le32(0x3 << 25)
-
-/* channel mode */
-enum {
-	CHANNEL_MODE_LEGACY = 0,
-	CHANNEL_MODE_PURE_40 = 1,
-	CHANNEL_MODE_MIXED = 2,
-	CHANNEL_MODE_RESERVED = 3,
-};
-#define RXON_FLG_CHANNEL_MODE_LEGACY	cpu_to_le32(CHANNEL_MODE_LEGACY << RXON_FLG_CHANNEL_MODE_POS)
-#define RXON_FLG_CHANNEL_MODE_PURE_40	cpu_to_le32(CHANNEL_MODE_PURE_40 << RXON_FLG_CHANNEL_MODE_POS)
-#define RXON_FLG_CHANNEL_MODE_MIXED	cpu_to_le32(CHANNEL_MODE_MIXED << RXON_FLG_CHANNEL_MODE_POS)
-
-/* CTS to self (if spec allows) flag */
-#define RXON_FLG_SELF_CTS_EN			cpu_to_le32(0x1<<30)
-
-/* rx_config filter flags */
-/* accept all data frames */
-#define RXON_FILTER_PROMISC_MSK         cpu_to_le32(1 << 0)
-/* pass control & management to host */
-#define RXON_FILTER_CTL2HOST_MSK        cpu_to_le32(1 << 1)
-/* accept multi-cast */
-#define RXON_FILTER_ACCEPT_GRP_MSK      cpu_to_le32(1 << 2)
-/* don't decrypt uni-cast frames */
-#define RXON_FILTER_DIS_DECRYPT_MSK     cpu_to_le32(1 << 3)
-/* don't decrypt multi-cast frames */
-#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4)
-/* STA is associated */
-#define RXON_FILTER_ASSOC_MSK           cpu_to_le32(1 << 5)
-/* transfer to host non bssid beacons in associated state */
-#define RXON_FILTER_BCON_AWARE_MSK      cpu_to_le32(1 << 6)
-
-/**
- * REPLY_RXON = 0x10 (command, has simple generic response)
- *
- * RXON tunes the radio tuner to a service channel, and sets up a number
- * of parameters that are used primarily for Rx, but also for Tx operations.
- *
- * NOTE:  When tuning to a new channel, driver must set the
- *        RXON_FILTER_ASSOC_MSK to 0.  This will clear station-dependent
- *        info within the device, including the station tables, tx retry
- *        rate tables, and txpower tables.  Driver must build a new station
- *        table and txpower table before transmitting anything on the RXON
- *        channel.
- *
- * NOTE:  All RXONs wipe clean the internal txpower table.  Driver must
- *        issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10),
- *        regardless of whether RXON_FILTER_ASSOC_MSK is set.
- */
-
-struct iwl_rxon_cmd {
-	u8 node_addr[6];
-	__le16 reserved1;
-	u8 bssid_addr[6];
-	__le16 reserved2;
-	u8 wlap_bssid_addr[6];
-	__le16 reserved3;
-	u8 dev_type;
-	u8 air_propagation;
-	__le16 rx_chain;
-	u8 ofdm_basic_rates;
-	u8 cck_basic_rates;
-	__le16 assoc_id;
-	__le32 flags;
-	__le32 filter_flags;
-	__le16 channel;
-	u8 ofdm_ht_single_stream_basic_rates;
-	u8 ofdm_ht_dual_stream_basic_rates;
-	u8 ofdm_ht_triple_stream_basic_rates;
-	u8 reserved5;
-	__le16 acquisition_data;
-	__le16 reserved6;
-} __packed;
-
-/*
- * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
- */
-struct iwl_rxon_assoc_cmd {
-	__le32 flags;
-	__le32 filter_flags;
-	u8 ofdm_basic_rates;
-	u8 cck_basic_rates;
-	__le16 reserved1;
-	u8 ofdm_ht_single_stream_basic_rates;
-	u8 ofdm_ht_dual_stream_basic_rates;
-	u8 ofdm_ht_triple_stream_basic_rates;
-	u8 reserved2;
-	__le16 rx_chain_select_flags;
-	__le16 acquisition_data;
-	__le32 reserved3;
-} __packed;
-
-#define IWL_CONN_MAX_LISTEN_INTERVAL	10
-#define IWL_MAX_UCODE_BEACON_INTERVAL	4 /* 4096 */
-
-/*
- * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
- */
-struct iwl_rxon_time_cmd {
-	__le64 timestamp;
-	__le16 beacon_interval;
-	__le16 atim_window;
-	__le32 beacon_init_val;
-	__le16 listen_interval;
-	u8 dtim_period;
-	u8 delta_cp_bss_tbtts;
-} __packed;
-
-/*
- * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
- */
-/**
- * struct iwl5000_channel_switch_cmd
- * @band: 0- 5.2GHz, 1- 2.4GHz
- * @expect_beacon: 0- resume transmits after channel switch
- *		   1- wait for beacon to resume transmits
- * @channel: new channel number
- * @rxon_flags: Rx on flags
- * @rxon_filter_flags: filtering parameters
- * @switch_time: switch time in extended beacon format
- * @reserved: reserved bytes
- */
-struct iwl5000_channel_switch_cmd {
-	u8 band;
-	u8 expect_beacon;
-	__le16 channel;
-	__le32 rxon_flags;
-	__le32 rxon_filter_flags;
-	__le32 switch_time;
-	__le32 reserved[2][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
-} __packed;
-
-/**
- * struct iwl6000_channel_switch_cmd
- * @band: 0- 5.2GHz, 1- 2.4GHz
- * @expect_beacon: 0- resume transmits after channel switch
- *		   1- wait for beacon to resume transmits
- * @channel: new channel number
- * @rxon_flags: Rx on flags
- * @rxon_filter_flags: filtering parameters
- * @switch_time: switch time in extended beacon format
- * @reserved: reserved bytes
- */
-struct iwl6000_channel_switch_cmd {
-	u8 band;
-	u8 expect_beacon;
-	__le16 channel;
-	__le32 rxon_flags;
-	__le32 rxon_filter_flags;
-	__le32 switch_time;
-	__le32 reserved[3][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
-} __packed;
-
-/*
- * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
- */
-struct iwl_csa_notification {
-	__le16 band;
-	__le16 channel;
-	__le32 status;		/* 0 - OK, 1 - fail */
-} __packed;
-
-/******************************************************************************
- * (2)
- * Quality-of-Service (QOS) Commands & Responses:
- *
- *****************************************************************************/
-
-/**
- * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM
- * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd
- *
- * @cw_min: Contention window, start value in numbers of slots.
- *          Should be a power-of-2, minus 1.  Device's default is 0x0f.
- * @cw_max: Contention window, max value in numbers of slots.
- *          Should be a power-of-2, minus 1.  Device's default is 0x3f.
- * @aifsn:  Number of slots in Arbitration Interframe Space (before
- *          performing random backoff timing prior to Tx).  Device default 1.
- * @edca_txop:  Length of Tx opportunity, in uSecs.  Device default is 0.
- *
- * Device will automatically increase contention window by (2*CW) + 1 for each
- * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
- * value, to cap the CW value.
- */
-struct iwl_ac_qos {
-	__le16 cw_min;
-	__le16 cw_max;
-	u8 aifsn;
-	u8 reserved1;
-	__le16 edca_txop;
-} __packed;
-
-/* QoS flags defines */
-#define QOS_PARAM_FLG_UPDATE_EDCA_MSK	cpu_to_le32(0x01)
-#define QOS_PARAM_FLG_TGN_MSK		cpu_to_le32(0x02)
-#define QOS_PARAM_FLG_TXOP_TYPE_MSK	cpu_to_le32(0x10)
-
-/* Number of Access Categories (AC) (EDCA), queues 0..3 */
-#define AC_NUM                4
-
-/*
- * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
- *
- * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
- * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
- */
-struct iwl_qosparam_cmd {
-	__le32 qos_flags;
-	struct iwl_ac_qos ac[AC_NUM];
-} __packed;
-
-/******************************************************************************
- * (3)
- * Add/Modify Stations Commands & Responses:
- *
- *****************************************************************************/
-/*
- * Multi station support
- */
-
-/* Special, dedicated locations within device's station table */
-#define	IWL_AP_ID		0
-#define	IWL_AP_ID_PAN		1
-#define	IWL_STA_ID		2
-#define IWLAGN_PAN_BCAST_ID	14
-#define IWLAGN_BROADCAST_ID	15
-#define	IWLAGN_STATION_COUNT	16
-
-#define	IWL_INVALID_STATION 	255
-#define IWL_MAX_TID_COUNT	8
-#define IWL_TID_NON_QOS IWL_MAX_TID_COUNT
-
-#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_PAN_STATION		cpu_to_le32(1 << 13)
-#define STA_FLG_RTS_MIMO_PROT_MSK	cpu_to_le32(1 << 17)
-#define STA_FLG_AGG_MPDU_8US_MSK	cpu_to_le32(1 << 18)
-#define STA_FLG_MAX_AGG_SIZE_POS	(19)
-#define STA_FLG_MAX_AGG_SIZE_MSK	cpu_to_le32(3 << 19)
-#define STA_FLG_HT40_EN_MSK		cpu_to_le32(1 << 21)
-#define STA_FLG_MIMO_DIS_MSK		cpu_to_le32(1 << 22)
-#define STA_FLG_AGG_MPDU_DENSITY_POS	(23)
-#define STA_FLG_AGG_MPDU_DENSITY_MSK	cpu_to_le32(7 << 23)
-
-/* Use in mode field.  1: modify existing entry, 0: add new station entry */
-#define STA_CONTROL_MODIFY_MSK		0x01
-
-/* key flags __le16*/
-#define STA_KEY_FLG_ENCRYPT_MSK	cpu_to_le16(0x0007)
-#define STA_KEY_FLG_NO_ENC	cpu_to_le16(0x0000)
-#define STA_KEY_FLG_WEP		cpu_to_le16(0x0001)
-#define STA_KEY_FLG_CCMP	cpu_to_le16(0x0002)
-#define STA_KEY_FLG_TKIP	cpu_to_le16(0x0003)
-
-#define STA_KEY_FLG_KEYID_POS	8
-#define STA_KEY_FLG_INVALID 	cpu_to_le16(0x0800)
-/* wep key is either from global key (0) or from station info array (1) */
-#define STA_KEY_FLG_MAP_KEY_MSK	cpu_to_le16(0x0008)
-
-/* wep key in STA: 5-bytes (0) or 13-bytes (1) */
-#define STA_KEY_FLG_KEY_SIZE_MSK     cpu_to_le16(0x1000)
-#define STA_KEY_MULTICAST_MSK        cpu_to_le16(0x4000)
-#define STA_KEY_MAX_NUM		8
-#define STA_KEY_MAX_NUM_PAN	16
-/* must not match WEP_INVALID_OFFSET */
-#define IWLAGN_HW_KEY_DEFAULT	0xfe
-
-/* Flags indicate whether to modify vs. don't change various station params */
-#define	STA_MODIFY_KEY_MASK		0x01
-#define	STA_MODIFY_TID_DISABLE_TX	0x02
-#define	STA_MODIFY_TX_RATE_MSK		0x04
-#define STA_MODIFY_ADDBA_TID_MSK	0x08
-#define STA_MODIFY_DELBA_TID_MSK	0x10
-#define STA_MODIFY_SLEEP_TX_COUNT_MSK	0x20
-
-/* Receiver address (actually, Rx station's index into station table),
- * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
-#define BUILD_RAxTID(sta_id, tid)	(((sta_id) << 4) + (tid))
-
-/* agn */
-struct iwl_keyinfo {
-	__le16 key_flags;
-	u8 tkip_rx_tsc_byte2;	/* TSC[2] for key mix ph1 detection */
-	u8 reserved1;
-	__le16 tkip_rx_ttak[5];	/* 10-byte unicast TKIP TTAK */
-	u8 key_offset;
-	u8 reserved2;
-	u8 key[16];		/* 16-byte unicast decryption key */
-	__le64 tx_secur_seq_cnt;
-	__le64 hw_tkip_mic_rx_key;
-	__le64 hw_tkip_mic_tx_key;
-} __packed;
-
-/**
- * struct sta_id_modify
- * @addr[ETH_ALEN]: station's MAC address
- * @sta_id: index of station in uCode's station table
- * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change
- *
- * Driver selects unused table index when adding new station,
- * or the index to a pre-existing station entry when modifying that station.
- * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP).
- *
- * modify_mask flags select which parameters to modify vs. leave alone.
- */
-struct sta_id_modify {
-	u8 addr[ETH_ALEN];
-	__le16 reserved1;
-	u8 sta_id;
-	u8 modify_mask;
-	__le16 reserved2;
-} __packed;
-
-/*
- * REPLY_ADD_STA = 0x18 (command)
- *
- * The device contains an internal table of per-station information,
- * with info on security keys, aggregation parameters, and Tx rates for
- * initial Tx attempt and any retries (agn devices uses
- * REPLY_TX_LINK_QUALITY_CMD,
- *
- * REPLY_ADD_STA sets up the table entry for one station, either creating
- * a new entry, or modifying a pre-existing one.
- *
- * NOTE:  RXON command (without "associated" bit set) wipes the station table
- *        clean.  Moving into RF_KILL state does this also.  Driver must set up
- *        new station table before transmitting anything on the RXON channel
- *        (except active scans or active measurements; those commands carry
- *        their own txpower/rate setup data).
- *
- *        When getting started on a new channel, driver must set up the
- *        IWL_BROADCAST_ID entry (last entry in the table).  For a client
- *        station in a BSS, once an AP is selected, driver sets up the AP STA
- *        in the IWL_AP_ID entry (1st entry in the table).  BROADCAST and AP
- *        are all that are needed for a BSS client station.  If the device is
- *        used as AP, or in an IBSS network, driver must set up station table
- *        entries for all STAs in network, starting with index IWL_STA_ID.
- */
-
-struct iwl_addsta_cmd {
-	u8 mode;		/* 1: modify existing, 0: add new station */
-	u8 reserved[3];
-	struct sta_id_modify sta;
-	struct iwl_keyinfo key;
-	__le32 station_flags;		/* STA_FLG_* */
-	__le32 station_flags_msk;	/* STA_FLG_* */
-
-	/* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
-	 * corresponding to bit (e.g. bit 5 controls TID 5).
-	 * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
-	__le16 tid_disable_tx;
-	__le16 legacy_reserved;
-
-	/* TID for which to add block-ack support.
-	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
-	u8 add_immediate_ba_tid;
-
-	/* TID for which to remove block-ack support.
-	 * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
-	u8 remove_immediate_ba_tid;
-
-	/* 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;
-
-	/*
-	 * Number of packets OK to transmit to station even though
-	 * it is asleep -- used to synchronise PS-poll and u-APSD
-	 * responses while ucode keeps track of STA sleep state.
-	 */
-	__le16 sleep_tx_count;
-
-	__le16 reserved2;
-} __packed;
-
-
-#define ADD_STA_SUCCESS_MSK		0x1
-#define ADD_STA_NO_ROOM_IN_TABLE	0x2
-#define ADD_STA_NO_BLOCK_ACK_RESOURCE	0x4
-#define ADD_STA_MODIFY_NON_EXIST_STA	0x8
-/*
- * REPLY_ADD_STA = 0x18 (response)
- */
-struct iwl_add_sta_resp {
-	u8 status;	/* ADD_STA_* */
-} __packed;
-
-#define REM_STA_SUCCESS_MSK              0x1
-/*
- *  REPLY_REM_STA = 0x19 (response)
- */
-struct iwl_rem_sta_resp {
-	u8 status;
-} __packed;
-
-/*
- *  REPLY_REM_STA = 0x19 (command)
- */
-struct iwl_rem_sta_cmd {
-	u8 num_sta;     /* number of removed stations */
-	u8 reserved[3];
-	u8 addr[ETH_ALEN]; /* MAC addr of the first station */
-	u8 reserved2[2];
-} __packed;
-
-
-/* WiFi queues mask */
-#define IWL_SCD_BK_MSK			cpu_to_le32(BIT(0))
-#define IWL_SCD_BE_MSK			cpu_to_le32(BIT(1))
-#define IWL_SCD_VI_MSK			cpu_to_le32(BIT(2))
-#define IWL_SCD_VO_MSK			cpu_to_le32(BIT(3))
-#define IWL_SCD_MGMT_MSK		cpu_to_le32(BIT(3))
-
-/* PAN queues mask */
-#define IWL_PAN_SCD_BK_MSK		cpu_to_le32(BIT(4))
-#define IWL_PAN_SCD_BE_MSK		cpu_to_le32(BIT(5))
-#define IWL_PAN_SCD_VI_MSK		cpu_to_le32(BIT(6))
-#define IWL_PAN_SCD_VO_MSK		cpu_to_le32(BIT(7))
-#define IWL_PAN_SCD_MGMT_MSK		cpu_to_le32(BIT(7))
-#define IWL_PAN_SCD_MULTICAST_MSK	cpu_to_le32(BIT(8))
-
-#define IWL_AGG_TX_QUEUE_MSK		cpu_to_le32(0xffc00)
-
-#define IWL_DROP_SINGLE		0
-#define IWL_DROP_ALL		(BIT(IWL_RXON_CTX_BSS) | BIT(IWL_RXON_CTX_PAN))
-
-/*
- * 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
- */
-struct iwl_wep_key {
-	u8 key_index;
-	u8 key_offset;
-	u8 reserved1[2];
-	u8 key_size;
-	u8 reserved2[3];
-	u8 key[16];
-} __packed;
-
-struct iwl_wep_cmd {
-	u8 num_keys;
-	u8 global_key_type;
-	u8 flags;
-	u8 reserved;
-	struct iwl_wep_key key[0];
-} __packed;
-
-#define WEP_KEY_WEP_TYPE 1
-#define WEP_KEYS_MAX 4
-#define WEP_INVALID_OFFSET 0xff
-#define WEP_KEY_LEN_64 5
-#define WEP_KEY_LEN_128 13
-
-/******************************************************************************
- * (4)
- * Rx Responses:
- *
- *****************************************************************************/
-
-#define RX_RES_STATUS_NO_CRC32_ERROR	cpu_to_le32(1 << 0)
-#define RX_RES_STATUS_NO_RXE_OVERFLOW	cpu_to_le32(1 << 1)
-
-#define RX_RES_PHY_FLAGS_BAND_24_MSK	cpu_to_le16(1 << 0)
-#define RX_RES_PHY_FLAGS_MOD_CCK_MSK		cpu_to_le16(1 << 1)
-#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	cpu_to_le16(1 << 2)
-#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK	cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK		0xf0
-#define RX_RES_PHY_FLAGS_ANTENNA_POS		4
-
-#define RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
-#define RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
-#define RX_RES_STATUS_SEC_TYPE_WEP	(0x1 << 8)
-#define RX_RES_STATUS_SEC_TYPE_CCMP	(0x2 << 8)
-#define RX_RES_STATUS_SEC_TYPE_TKIP	(0x3 << 8)
-#define	RX_RES_STATUS_SEC_TYPE_ERR	(0x7 << 8)
-
-#define RX_RES_STATUS_STATION_FOUND	(1<<6)
-#define RX_RES_STATUS_NO_STATION_INFO_MISMATCH	(1<<7)
-
-#define RX_RES_STATUS_DECRYPT_TYPE_MSK	(0x3 << 11)
-#define RX_RES_STATUS_NOT_DECRYPT	(0x0 << 11)
-#define RX_RES_STATUS_DECRYPT_OK	(0x3 << 11)
-#define RX_RES_STATUS_BAD_ICV_MIC	(0x1 << 11)
-#define RX_RES_STATUS_BAD_KEY_TTAK	(0x2 << 11)
-
-#define RX_MPDU_RES_STATUS_ICV_OK	(0x20)
-#define RX_MPDU_RES_STATUS_MIC_OK	(0x40)
-#define RX_MPDU_RES_STATUS_TTAK_OK	(1 << 7)
-#define RX_MPDU_RES_STATUS_DEC_DONE_MSK	(0x800)
-
-
-#define IWLAGN_RX_RES_PHY_CNT 8
-#define IWLAGN_RX_RES_AGC_IDX     1
-#define IWLAGN_RX_RES_RSSI_AB_IDX 2
-#define IWLAGN_RX_RES_RSSI_C_IDX  3
-#define IWLAGN_OFDM_AGC_MSK 0xfe00
-#define IWLAGN_OFDM_AGC_BIT_POS 9
-#define IWLAGN_OFDM_RSSI_INBAND_A_BITMSK 0x00ff
-#define IWLAGN_OFDM_RSSI_ALLBAND_A_BITMSK 0xff00
-#define IWLAGN_OFDM_RSSI_A_BIT_POS 0
-#define IWLAGN_OFDM_RSSI_INBAND_B_BITMSK 0xff0000
-#define IWLAGN_OFDM_RSSI_ALLBAND_B_BITMSK 0xff000000
-#define IWLAGN_OFDM_RSSI_B_BIT_POS 16
-#define IWLAGN_OFDM_RSSI_INBAND_C_BITMSK 0x00ff
-#define IWLAGN_OFDM_RSSI_ALLBAND_C_BITMSK 0xff00
-#define IWLAGN_OFDM_RSSI_C_BIT_POS 0
-
-struct iwlagn_non_cfg_phy {
-	__le32 non_cfg_phy[IWLAGN_RX_RES_PHY_CNT];  /* up to 8 phy entries */
-} __packed;
-
-
-/*
- * REPLY_RX = 0xc3 (response only, not a command)
- * Used only for legacy (non 11n) frames.
- */
-struct iwl_rx_phy_res {
-	u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
-	u8 cfg_phy_cnt;		/* configurable DSP phy data byte count */
-	u8 stat_id;		/* configurable DSP phy data set ID */
-	u8 reserved1;
-	__le64 timestamp;	/* TSF at on air rise */
-	__le32 beacon_time_stamp; /* beacon at on-air rise */
-	__le16 phy_flags;	/* general phy flags: band, modulation, ... */
-	__le16 channel;		/* channel number */
-	u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */
-	__le32 rate_n_flags;	/* RATE_MCS_* */
-	__le16 byte_count;	/* frame's byte-count */
-	__le16 frame_time;	/* frame's time on the air */
-} __packed;
-
-struct iwl_rx_mpdu_res_start {
-	__le16 byte_count;
-	__le16 reserved;
-} __packed;
-
-
-/******************************************************************************
- * (5)
- * Tx Commands & Responses:
- *
- * Driver must place each REPLY_TX command into one of the prioritized Tx
- * queues in host DRAM, shared between driver and device (see comments for
- * SCD registers and Tx/Rx Queues).  When the device's Tx scheduler and uCode
- * are preparing to transmit, the device pulls the Tx command over the PCI
- * bus via one of the device's Tx DMA channels, to fill an internal FIFO
- * from which data will be transmitted.
- *
- * uCode handles all timing and protocol related to control frames
- * (RTS/CTS/ACK), based on flags in the Tx command.  uCode and Tx scheduler
- * handle reception of block-acks; uCode updates the host driver via
- * REPLY_COMPRESSED_BA.
- *
- * uCode handles retrying Tx when an ACK is expected but not received.
- * This includes trying lower data rates than the one requested in the Tx
- * command, as set up by the REPLY_TX_LINK_QUALITY_CMD (agn).
- *
- * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
- * This command must be executed after every RXON command, before Tx can occur.
- *****************************************************************************/
-
-/* REPLY_TX Tx flags field */
-
-/*
- * 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_PROT_REQUIRE_MSK cpu_to_le32(1 << 0)
-
-/* 1: Expect ACK from receiving station
- * 0: Don't expect ACK (MAC header's duration field s/b 0)
- * Set this for unicast frames, but not broadcast/multicast. */
-#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3)
-
-/* For agn devices:
- * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
- *    Tx command's initial_rate_index indicates first rate to try;
- *    uCode walks through table for additional Tx attempts.
- * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
- *    This rate will be used for all Tx attempts; it will not be scaled. */
-#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4)
-
-/* 1: Expect immediate block-ack.
- * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
-#define TX_CMD_FLG_IMM_BA_RSP_MASK  cpu_to_le32(1 << 6)
-
-/* Tx antenna selection field; reserved (0) for agn devices. */
-#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00)
-
-/* 1: Ignore Bluetooth priority for this frame.
- * 0: Delay Tx until Bluetooth device is done (normal usage). */
-#define TX_CMD_FLG_IGNORE_BT cpu_to_le32(1 << 12)
-
-/* 1: uCode overrides sequence control field in MAC header.
- * 0: Driver provides sequence control field in MAC header.
- * Set this for management frames, non-QOS data frames, non-unicast frames,
- * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
-#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13)
-
-/* 1: This frame is non-last MPDU; more fragments are coming.
- * 0: Last fragment, or not using fragmentation. */
-#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14)
-
-/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
- * 0: No TSF required in outgoing frame.
- * Set this for transmitting beacons and probe responses. */
-#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16)
-
-/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
- *    alignment of frame's payload data field.
- * 0: No pad
- * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
- * field (but not both).  Driver must align frame data (i.e. data following
- * MAC header) to DWORD boundary. */
-#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20)
-
-/* accelerate aggregation support
- * 0 - no CCMP encryption; 1 - CCMP encryption */
-#define TX_CMD_FLG_AGG_CCMP_MSK cpu_to_le32(1 << 22)
-
-/* HCCA-AP - disable duration overwriting. */
-#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25)
-
-
-/*
- * TX command security control
- */
-#define TX_CMD_SEC_WEP  	0x01
-#define TX_CMD_SEC_CCM  	0x02
-#define TX_CMD_SEC_TKIP		0x03
-#define TX_CMD_SEC_MSK		0x03
-#define TX_CMD_SEC_SHIFT	6
-#define TX_CMD_SEC_KEY128	0x08
-
-/*
- * security overhead sizes
- */
-#define WEP_IV_LEN 4
-#define WEP_ICV_LEN 4
-#define CCMP_MIC_LEN 8
-#define TKIP_ICV_LEN 4
-
-/*
- * REPLY_TX = 0x1c (command)
- */
-
-/*
- * 4965 uCode updates these Tx attempt count values in host DRAM.
- * Used for managing Tx retries when expecting block-acks.
- * Driver should set these fields to 0.
- */
-struct iwl_dram_scratch {
-	u8 try_cnt;		/* Tx attempts */
-	u8 bt_kill_cnt;		/* Tx attempts blocked by Bluetooth device */
-	__le16 reserved;
-} __packed;
-
-struct iwl_tx_cmd {
-	/*
-	 * MPDU byte count:
-	 * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
-	 * + 8 byte IV for CCM or TKIP (not used for WEP)
-	 * + Data payload
-	 * + 8-byte MIC (not used for CCM/WEP)
-	 * NOTE:  Does not include Tx command bytes, post-MAC pad bytes,
-	 *        MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
-	 * Range: 14-2342 bytes.
-	 */
-	__le16 len;
-
-	/*
-	 * MPDU or MSDU byte count for next frame.
-	 * Used for fragmentation and bursting, but not 11n aggregation.
-	 * Same as "len", but for next frame.  Set to 0 if not applicable.
-	 */
-	__le16 next_frame_len;
-
-	__le32 tx_flags;	/* TX_CMD_FLG_* */
-
-	/* uCode may modify this field of the Tx command (in host DRAM!).
-	 * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */
-	struct iwl_dram_scratch scratch;
-
-	/* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */
-	__le32 rate_n_flags;	/* RATE_MCS_* */
-
-	/* Index of destination station in uCode's station table */
-	u8 sta_id;
-
-	/* Type of security encryption:  CCM or TKIP */
-	u8 sec_ctl;		/* TX_CMD_SEC_* */
-
-	/*
-	 * Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial
-	 * Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set.  Normally "0" for
-	 * data frames, this field may be used to selectively reduce initial
-	 * rate (via non-0 value) for special frames (e.g. management), while
-	 * still supporting rate scaling for all frames.
-	 */
-	u8 initial_rate_index;
-	u8 reserved;
-	u8 key[16];
-	__le16 next_frame_flags;
-	__le16 reserved2;
-	union {
-		__le32 life_time;
-		__le32 attempt;
-	} stop_time;
-
-	/* Host DRAM physical address pointer to "scratch" in this command.
-	 * Must be dword aligned.  "0" in dram_lsb_ptr disables usage. */
-	__le32 dram_lsb_ptr;
-	u8 dram_msb_ptr;
-
-	u8 rts_retry_limit;	/*byte 50 */
-	u8 data_retry_limit;	/*byte 51 */
-	u8 tid_tspec;
-	union {
-		__le16 pm_frame_timeout;
-		__le16 attempt_duration;
-	} timeout;
-
-	/*
-	 * Duration of EDCA burst Tx Opportunity, in 32-usec units.
-	 * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
-	 */
-	__le16 driver_txop;
-
-	/*
-	 * MAC header goes here, followed by 2 bytes padding if MAC header
-	 * length is 26 or 30 bytes, followed by payload data
-	 */
-	u8 payload[0];
-	struct ieee80211_hdr hdr[0];
-} __packed;
-
-/*
- * TX command response is sent after *agn* transmission attempts.
- *
- * both postpone and abort status are expected behavior from uCode. there is
- * no special operation required from driver; except for RFKILL_FLUSH,
- * which required tx flush host command to flush all the tx frames in queues
- */
-enum {
-	TX_STATUS_SUCCESS = 0x01,
-	TX_STATUS_DIRECT_DONE = 0x02,
-	/* postpone TX */
-	TX_STATUS_POSTPONE_DELAY = 0x40,
-	TX_STATUS_POSTPONE_FEW_BYTES = 0x41,
-	TX_STATUS_POSTPONE_BT_PRIO = 0x42,
-	TX_STATUS_POSTPONE_QUIET_PERIOD = 0x43,
-	TX_STATUS_POSTPONE_CALC_TTAK = 0x44,
-	/* abort TX */
-	TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY = 0x81,
-	TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
-	TX_STATUS_FAIL_LONG_LIMIT = 0x83,
-	TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
-	TX_STATUS_FAIL_DRAIN_FLOW = 0x85,
-	TX_STATUS_FAIL_RFKILL_FLUSH = 0x86,
-	TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
-	TX_STATUS_FAIL_DEST_PS = 0x88,
-	TX_STATUS_FAIL_HOST_ABORTED = 0x89,
-	TX_STATUS_FAIL_BT_RETRY = 0x8a,
-	TX_STATUS_FAIL_STA_INVALID = 0x8b,
-	TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
-	TX_STATUS_FAIL_TID_DISABLE = 0x8d,
-	TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e,
-	TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
-	TX_STATUS_FAIL_PASSIVE_NO_RX = 0x90,
-	TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
-};
-
-#define	TX_PACKET_MODE_REGULAR		0x0000
-#define	TX_PACKET_MODE_BURST_SEQ	0x0100
-#define	TX_PACKET_MODE_BURST_FIRST	0x0200
-
-enum {
-	TX_POWER_PA_NOT_ACTIVE = 0x0,
-};
-
-enum {
-	TX_STATUS_MSK = 0x000000ff,		/* bits 0:7 */
-	TX_STATUS_DELAY_MSK = 0x00000040,
-	TX_STATUS_ABORT_MSK = 0x00000080,
-	TX_PACKET_MODE_MSK = 0x0000ff00,	/* bits 8:15 */
-	TX_FIFO_NUMBER_MSK = 0x00070000,	/* bits 16:18 */
-	TX_RESERVED = 0x00780000,		/* bits 19:22 */
-	TX_POWER_PA_DETECT_MSK = 0x7f800000,	/* bits 23:30 */
-	TX_ABORT_REQUIRED_MSK = 0x80000000,	/* bits 31:31 */
-};
-
-/* *******************************
- * TX aggregation status
- ******************************* */
-
-enum {
-	AGG_TX_STATE_TRANSMITTED = 0x00,
-	AGG_TX_STATE_UNDERRUN_MSK = 0x01,
-	AGG_TX_STATE_BT_PRIO_MSK = 0x02,
-	AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
-	AGG_TX_STATE_ABORT_MSK = 0x08,
-	AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
-	AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
-	AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
-	AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
-	AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
-	AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
-	AGG_TX_STATE_DUMP_TX_MSK = 0x200,
-	AGG_TX_STATE_DELAY_TX_MSK = 0x400
-};
-
-#define AGG_TX_STATUS_MSK	0x00000fff	/* bits 0:11 */
-#define AGG_TX_TRY_MSK		0x0000f000	/* bits 12:15 */
-
-#define AGG_TX_STATE_LAST_SENT_MSK  (AGG_TX_STATE_LAST_SENT_TTL_MSK | \
-				     AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
-				     AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
-
-/* # tx attempts for first frame in aggregation */
-#define AGG_TX_STATE_TRY_CNT_POS 12
-#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
-
-/* Command ID and sequence number of Tx command for this frame */
-#define AGG_TX_STATE_SEQ_NUM_POS 16
-#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
-
-/*
- * REPLY_TX = 0x1c (response)
- *
- * This response may be in one of two slightly different formats, indicated
- * by the frame_count field:
- *
- * 1)  No aggregation (frame_count == 1).  This reports Tx results for
- *     a single frame.  Multiple attempts, at various bit rates, may have
- *     been made for this frame.
- *
- * 2)  Aggregation (frame_count > 1).  This reports Tx results for
- *     2 or more frames that used block-acknowledge.  All frames were
- *     transmitted at same rate.  Rate scaling may have been used if first
- *     frame in this new agg block failed in previous agg block(s).
- *
- *     Note that, for aggregation, ACK (block-ack) status is not delivered here;
- *     block-ack has not been received by the time the agn device records
- *     this status.
- *     This status relates to reasons the tx might have been blocked or aborted
- *     within the sending station (this agn device), rather than whether it was
- *     received successfully by the destination station.
- */
-struct agg_tx_status {
-	__le16 status;
-	__le16 sequence;
-} __packed;
-
-/*
- * definitions for initial rate index field
- * bits [3:0] initial rate index
- * bits [6:4] rate table color, used for the initial rate
- * bit-7 invalid rate indication
- *   i.e. rate was not chosen from rate table
- *   or rate table color was changed during frame retries
- * refer tlc rate info
- */
-
-#define IWL50_TX_RES_INIT_RATE_INDEX_POS	0
-#define IWL50_TX_RES_INIT_RATE_INDEX_MSK	0x0f
-#define IWL50_TX_RES_RATE_TABLE_COLOR_POS	4
-#define IWL50_TX_RES_RATE_TABLE_COLOR_MSK	0x70
-#define IWL50_TX_RES_INV_RATE_INDEX_MSK	0x80
-
-/* refer to ra_tid */
-#define IWLAGN_TX_RES_TID_POS	0
-#define IWLAGN_TX_RES_TID_MSK	0x0f
-#define IWLAGN_TX_RES_RA_POS	4
-#define IWLAGN_TX_RES_RA_MSK	0xf0
-
-struct iwlagn_tx_resp {
-	u8 frame_count;		/* 1 no aggregation, >1 aggregation */
-	u8 bt_kill_count;	/* # blocked by bluetooth (unused for agg) */
-	u8 failure_rts;		/* # failures due to unsuccessful RTS */
-	u8 failure_frame;	/* # failures due to no ACK (unused for agg) */
-
-	/* For non-agg:  Rate at which frame was successful.
-	 * For agg:  Rate at which all frames were transmitted. */
-	__le32 rate_n_flags;	/* RATE_MCS_*  */
-
-	/* For non-agg:  RTS + CTS + frame tx attempts time + ACK.
-	 * For agg:  RTS + CTS + aggregation tx time + block-ack time. */
-	__le16 wireless_media_time;	/* uSecs */
-
-	u8 pa_status;		/* RF power amplifier measurement (not used) */
-	u8 pa_integ_res_a[3];
-	u8 pa_integ_res_b[3];
-	u8 pa_integ_res_C[3];
-
-	__le32 tfd_info;
-	__le16 seq_ctl;
-	__le16 byte_cnt;
-	u8 tlc_info;
-	u8 ra_tid;		/* tid (0:3), sta_id (4:7) */
-	__le16 frame_ctrl;
-	/*
-	 * For non-agg:  frame status TX_STATUS_*
-	 * For agg:  status of 1st frame, AGG_TX_STATE_*; other frame status
-	 *           fields follow this one, up to frame_count.
-	 *           Bit fields:
-	 *           11- 0:  AGG_TX_STATE_* status code
-	 *           15-12:  Retry count for 1st frame in aggregation (retries
-	 *                   occur if tx failed for this frame when it was a
-	 *                   member of a previous aggregation block).  If rate
-	 *                   scaling is used, retry count indicates the rate
-	 *                   table entry used for all frames in the new agg.
-	 *           31-16:  Sequence # for this frame's Tx cmd (not SSN!)
-	 */
-	struct agg_tx_status status;	/* TX status (in aggregation -
-					 * status of 1st frame) */
-} __packed;
-/*
- * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
- *
- * Reports Block-Acknowledge from recipient station
- */
-struct iwl_compressed_ba_resp {
-	__le32 sta_addr_lo32;
-	__le16 sta_addr_hi16;
-	__le16 reserved;
-
-	/* Index of recipient (BA-sending) station in uCode's station table */
-	u8 sta_id;
-	u8 tid;
-	__le16 seq_ctl;
-	__le64 bitmap;
-	__le16 scd_flow;
-	__le16 scd_ssn;
-	u8 txed;	/* number of frames sent */
-	u8 txed_2_done; /* number of frames acked */
-} __packed;
-
-/*
- * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
- *
- */
-
-/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
-#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK	(1 << 0)
-
-/* # of EDCA prioritized tx fifos */
-#define  LINK_QUAL_AC_NUM AC_NUM
-
-/* # entries in rate scale table to support Tx retries */
-#define  LINK_QUAL_MAX_RETRY_NUM 16
-
-/* Tx antenna selection values */
-#define  LINK_QUAL_ANT_A_MSK (1 << 0)
-#define  LINK_QUAL_ANT_B_MSK (1 << 1)
-#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
-
-
-/**
- * struct iwl_link_qual_general_params
- *
- * Used in REPLY_TX_LINK_QUALITY_CMD
- */
-struct iwl_link_qual_general_params {
-	u8 flags;
-
-	/* No entries at or above this (driver chosen) index contain MIMO */
-	u8 mimo_delimiter;
-
-	/* Best single antenna to use for single stream (legacy, SISO). */
-	u8 single_stream_ant_msk;	/* LINK_QUAL_ANT_* */
-
-	/* Best antennas to use for MIMO (unused for 4965, assumes both). */
-	u8 dual_stream_ant_msk;		/* LINK_QUAL_ANT_* */
-
-	/*
-	 * If driver needs to use different initial rates for different
-	 * EDCA QOS access categories (as implemented by tx fifos 0-3),
-	 * this table will set that up, by indicating the indexes in the
-	 * rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table at which to start.
-	 * Otherwise, driver should set all entries to 0.
-	 *
-	 * Entry usage:
-	 * 0 = Background, 1 = Best Effort (normal), 2 = Video, 3 = Voice
-	 * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3.
-	 */
-	u8 start_rate_index[LINK_QUAL_AC_NUM];
-} __packed;
-
-#define LINK_QUAL_AGG_TIME_LIMIT_DEF	(4000) /* 4 milliseconds */
-#define LINK_QUAL_AGG_TIME_LIMIT_MAX	(8000)
-#define LINK_QUAL_AGG_TIME_LIMIT_MIN	(100)
-
-#define LINK_QUAL_AGG_DISABLE_START_DEF	(3)
-#define LINK_QUAL_AGG_DISABLE_START_MAX	(255)
-#define LINK_QUAL_AGG_DISABLE_START_MIN	(0)
-
-#define LINK_QUAL_AGG_FRAME_LIMIT_DEF	(63)
-#define LINK_QUAL_AGG_FRAME_LIMIT_MAX	(63)
-#define LINK_QUAL_AGG_FRAME_LIMIT_MIN	(0)
-
-/**
- * struct iwl_link_qual_agg_params
- *
- * Used in REPLY_TX_LINK_QUALITY_CMD
- */
-struct iwl_link_qual_agg_params {
-
-	/*
-	 *Maximum number of uSec in aggregation.
-	 * default set to 4000 (4 milliseconds) if not configured in .cfg
-	 */
-	__le16 agg_time_limit;
-
-	/*
-	 * Number of Tx retries allowed for a frame, before that frame will
-	 * no longer be considered for the start of an aggregation sequence
-	 * (scheduler will then try to tx it as single frame).
-	 * Driver should set this to 3.
-	 */
-	u8 agg_dis_start_th;
-
-	/*
-	 * Maximum number of frames in aggregation.
-	 * 0 = no limit (default).  1 = no aggregation.
-	 * Other values = max # frames in aggregation.
-	 */
-	u8 agg_frame_cnt_limit;
-
-	__le32 reserved;
-} __packed;
-
-/*
- * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
- *
- * For agn devices
- *
- * Each station in the agn device's internal station table has its own table
- * of 16
- * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when
- * an ACK is not received.  This command replaces the entire table for
- * one station.
- *
- * NOTE:  Station must already be in agn device's station table.
- *	  Use REPLY_ADD_STA.
- *
- * The rate scaling procedures described below work well.  Of course, other
- * procedures are possible, and may work better for particular environments.
- *
- *
- * FILLING THE RATE TABLE
- *
- * Given a particular initial rate and mode, as determined by the rate
- * scaling algorithm described below, the Linux driver uses the following
- * formula to fill the rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table in the
- * Link Quality command:
- *
- *
- * 1)  If using High-throughput (HT) (SISO or MIMO) initial rate:
- *     a) Use this same initial rate for first 3 entries.
- *     b) Find next lower available rate using same mode (SISO or MIMO),
- *        use for next 3 entries.  If no lower rate available, switch to
- *        legacy mode (no HT40 channel, no MIMO, no short guard interval).
- *     c) If using MIMO, set command's mimo_delimiter to number of entries
- *        using MIMO (3 or 6).
- *     d) After trying 2 HT rates, switch to legacy mode (no HT40 channel,
- *        no MIMO, no short guard interval), at the next lower bit rate
- *        (e.g. if second HT bit rate was 54, try 48 legacy), and follow
- *        legacy procedure for remaining table entries.
- *
- * 2)  If using legacy initial rate:
- *     a) Use the initial rate for only one entry.
- *     b) For each following entry, reduce the rate to next lower available
- *        rate, until reaching the lowest available rate.
- *     c) When reducing rate, also switch antenna selection.
- *     d) Once lowest available rate is reached, repeat this rate until
- *        rate table is filled (16 entries), switching antenna each entry.
- *
- *
- * ACCUMULATING HISTORY
- *
- * The rate scaling algorithm for agn devices, as implemented in Linux driver,
- * uses two sets of frame Tx success history:  One for the current/active
- * modulation mode, and one for a speculative/search mode that is being
- * attempted. If the speculative mode turns out to be more effective (i.e.
- * actual transfer rate is better), then the driver continues to use the
- * speculative mode as the new current active mode.
- *
- * Each history set contains, separately for each possible rate, data for a
- * sliding window of the 62 most recent tx attempts at that rate.  The data
- * includes a shifting bitmap of success(1)/failure(0), and sums of successful
- * and attempted frames, from which the driver can additionally calculate a
- * success ratio (success / attempted) and number of failures
- * (attempted - success), and control the size of the window (attempted).
- * The driver uses the bit map to remove successes from the success sum, as
- * the oldest tx attempts fall out of the window.
- *
- * When the agn device makes multiple tx attempts for a given frame, each
- * attempt might be at a different rate, and have different modulation
- * characteristics (e.g. antenna, fat channel, short guard interval), as set
- * up in the rate scaling table in the Link Quality command.  The driver must
- * determine which rate table entry was used for each tx attempt, to determine
- * which rate-specific history to update, and record only those attempts that
- * match the modulation characteristics of the history set.
- *
- * When using block-ack (aggregation), all frames are transmitted at the same
- * rate, since there is no per-attempt acknowledgment from the destination
- * station.  The Tx response struct iwl_tx_resp indicates the Tx rate in
- * rate_n_flags field.  After receiving a block-ack, the driver can update
- * history for the entire block all at once.
- *
- *
- * FINDING BEST STARTING RATE:
- *
- * When working with a selected initial modulation mode (see below), the
- * driver attempts to find a best initial rate.  The initial rate is the
- * first entry in the Link Quality command's rate table.
- *
- * 1)  Calculate actual throughput (success ratio * expected throughput, see
- *     table below) for current initial rate.  Do this only if enough frames
- *     have been attempted to make the value meaningful:  at least 6 failed
- *     tx attempts, or at least 8 successes.  If not enough, don't try rate
- *     scaling yet.
- *
- * 2)  Find available rates adjacent to current initial rate.  Available means:
- *     a)  supported by hardware &&
- *     b)  supported by association &&
- *     c)  within any constraints selected by user
- *
- * 3)  Gather measured throughputs for adjacent rates.  These might not have
- *     enough history to calculate a throughput.  That's okay, we might try
- *     using one of them anyway!
- *
- * 4)  Try decreasing rate if, for current rate:
- *     a)  success ratio is < 15% ||
- *     b)  lower adjacent rate has better measured throughput ||
- *     c)  higher adjacent rate has worse throughput, and lower is unmeasured
- *
- *     As a sanity check, if decrease was determined above, leave rate
- *     unchanged if:
- *     a)  lower rate unavailable
- *     b)  success ratio at current rate > 85% (very good)
- *     c)  current measured throughput is better than expected throughput
- *         of lower rate (under perfect 100% tx conditions, see table below)
- *
- * 5)  Try increasing rate if, for current rate:
- *     a)  success ratio is < 15% ||
- *     b)  both adjacent rates' throughputs are unmeasured (try it!) ||
- *     b)  higher adjacent rate has better measured throughput ||
- *     c)  lower adjacent rate has worse throughput, and higher is unmeasured
- *
- *     As a sanity check, if increase was determined above, leave rate
- *     unchanged if:
- *     a)  success ratio at current rate < 70%.  This is not particularly
- *         good performance; higher rate is sure to have poorer success.
- *
- * 6)  Re-evaluate the rate after each tx frame.  If working with block-
- *     acknowledge, history and statistics may be calculated for the entire
- *     block (including prior history that fits within the history windows),
- *     before re-evaluation.
- *
- * FINDING BEST STARTING MODULATION MODE:
- *
- * After working with a modulation mode for a "while" (and doing rate scaling),
- * the driver searches for a new initial mode in an attempt to improve
- * throughput.  The "while" is measured by numbers of attempted frames:
- *
- * For legacy mode, search for new mode after:
- *   480 successful frames, or 160 failed frames
- * For high-throughput modes (SISO or MIMO), search for new mode after:
- *   4500 successful frames, or 400 failed frames
- *
- * Mode switch possibilities are (3 for each mode):
- *
- * For legacy:
- *   Change antenna, try SISO (if HT association), try MIMO (if HT association)
- * For SISO:
- *   Change antenna, try MIMO, try shortened guard interval (SGI)
- * For MIMO:
- *   Try SISO antenna A, SISO antenna B, try shortened guard interval (SGI)
- *
- * When trying a new mode, use the same bit rate as the old/current mode when
- * trying antenna switches and shortened guard interval.  When switching to
- * SISO from MIMO or legacy, or to MIMO from SISO or legacy, use a rate
- * for which the expected throughput (under perfect conditions) is about the
- * same or slightly better than the actual measured throughput delivered by
- * the old/current mode.
- *
- * Actual throughput can be estimated by multiplying the expected throughput
- * by the success ratio (successful / attempted tx frames).  Frame size is
- * not considered in this calculation; it assumes that frame size will average
- * out to be fairly consistent over several samples.  The following are
- * metric values for expected throughput assuming 100% success ratio.
- * Only G band has support for CCK rates:
- *
- *           RATE:  1    2    5   11    6   9   12   18   24   36   48   54   60
- *
- *              G:  7   13   35   58   40  57   72   98  121  154  177  186  186
- *              A:  0    0    0    0   40  57   72   98  121  154  177  186  186
- *     SISO 20MHz:  0    0    0    0   42  42   76  102  124  159  183  193  202
- * SGI SISO 20MHz:  0    0    0    0   46  46   82  110  132  168  192  202  211
- *     MIMO 20MHz:  0    0    0    0   74  74  123  155  179  214  236  244  251
- * SGI MIMO 20MHz:  0    0    0    0   81  81  131  164  188  222  243  251  257
- *     SISO 40MHz:  0    0    0    0   77  77  127  160  184  220  242  250  257
- * SGI SISO 40MHz:  0    0    0    0   83  83  135  169  193  229  250  257  264
- *     MIMO 40MHz:  0    0    0    0  123 123  182  214  235  264  279  285  289
- * SGI MIMO 40MHz:  0    0    0    0  131 131  191  222  242  270  284  289  293
- *
- * After the new mode has been tried for a short while (minimum of 6 failed
- * frames or 8 successful frames), compare success ratio and actual throughput
- * estimate of the new mode with the old.  If either is better with the new
- * mode, continue to use the new mode.
- *
- * Continue comparing modes until all 3 possibilities have been tried.
- * If moving from legacy to HT, try all 3 possibilities from the new HT
- * mode.  After trying all 3, a best mode is found.  Continue to use this mode
- * for the longer "while" described above (e.g. 480 successful frames for
- * legacy), and then repeat the search process.
- *
- */
-struct iwl_link_quality_cmd {
-
-	/* Index of destination/recipient station in uCode's station table */
-	u8 sta_id;
-	u8 reserved1;
-	__le16 control;		/* not used */
-	struct iwl_link_qual_general_params general_params;
-	struct iwl_link_qual_agg_params agg_params;
-
-	/*
-	 * Rate info; when using rate-scaling, Tx command's initial_rate_index
-	 * specifies 1st Tx rate attempted, via index into this table.
-	 * agn devices works its way through table when retrying Tx.
-	 */
-	struct {
-		__le32 rate_n_flags;	/* RATE_MCS_*, IWL_RATE_* */
-	} rs_table[LINK_QUAL_MAX_RETRY_NUM];
-	__le32 reserved2;
-} __packed;
-
-/*
- * BT configuration enable flags:
- *   bit 0 - 1: BT channel announcement enabled
- *           0: disable
- *   bit 1 - 1: priority of BT device enabled
- *           0: disable
- *   bit 2 - 1: BT 2 wire support enabled
- *           0: disable
- */
-#define BT_COEX_DISABLE (0x0)
-#define BT_ENABLE_CHANNEL_ANNOUNCE BIT(0)
-#define BT_ENABLE_PRIORITY	   BIT(1)
-#define BT_ENABLE_2_WIRE	   BIT(2)
-
-#define BT_COEX_DISABLE (0x0)
-#define BT_COEX_ENABLE  (BT_ENABLE_CHANNEL_ANNOUNCE | BT_ENABLE_PRIORITY)
-
-#define BT_LEAD_TIME_MIN (0x0)
-#define BT_LEAD_TIME_DEF (0x1E)
-#define BT_LEAD_TIME_MAX (0xFF)
-
-#define BT_MAX_KILL_MIN (0x1)
-#define BT_MAX_KILL_DEF (0x5)
-#define BT_MAX_KILL_MAX (0xFF)
-
-#define BT_DURATION_LIMIT_DEF	625
-#define BT_DURATION_LIMIT_MAX	1250
-#define BT_DURATION_LIMIT_MIN	625
-
-#define BT_ON_THRESHOLD_DEF	4
-#define BT_ON_THRESHOLD_MAX	1000
-#define BT_ON_THRESHOLD_MIN	1
-
-#define BT_FRAG_THRESHOLD_DEF	0
-#define BT_FRAG_THRESHOLD_MAX	0
-#define BT_FRAG_THRESHOLD_MIN	0
-
-#define BT_AGG_THRESHOLD_DEF	1200
-#define BT_AGG_THRESHOLD_MAX	8000
-#define BT_AGG_THRESHOLD_MIN	400
-
-/*
- * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
- *
- * agn devices support hardware handshake with Bluetooth device on
- * same platform.  Bluetooth device alerts wireless device when it will Tx;
- * wireless device can delay or kill its own Tx to accommodate.
- */
-struct iwl_bt_cmd {
-	u8 flags;
-	u8 lead_time;
-	u8 max_kill;
-	u8 reserved;
-	__le32 kill_ack_mask;
-	__le32 kill_cts_mask;
-} __packed;
-
-#define IWLAGN_BT_FLAG_CHANNEL_INHIBITION	BIT(0)
-
-#define IWLAGN_BT_FLAG_COEX_MODE_MASK		(BIT(3)|BIT(4)|BIT(5))
-#define IWLAGN_BT_FLAG_COEX_MODE_SHIFT		3
-#define IWLAGN_BT_FLAG_COEX_MODE_DISABLED	0
-#define IWLAGN_BT_FLAG_COEX_MODE_LEGACY_2W	1
-#define IWLAGN_BT_FLAG_COEX_MODE_3W		2
-#define IWLAGN_BT_FLAG_COEX_MODE_4W		3
-
-#define IWLAGN_BT_FLAG_UCODE_DEFAULT		BIT(6)
-/* Disable Sync PSPoll on SCO/eSCO */
-#define IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE	BIT(7)
-
-#define IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD	-75 /* dBm */
-#define IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD	-65 /* dBm */
-
-#define IWLAGN_BT_PRIO_BOOST_MAX	0xFF
-#define IWLAGN_BT_PRIO_BOOST_MIN	0x00
-#define IWLAGN_BT_PRIO_BOOST_DEFAULT	0xF0
-
-#define IWLAGN_BT_MAX_KILL_DEFAULT	5
-
-#define IWLAGN_BT3_T7_DEFAULT		1
-
-enum iwl_bt_kill_idx {
-	IWL_BT_KILL_DEFAULT = 0,
-	IWL_BT_KILL_OVERRIDE = 1,
-	IWL_BT_KILL_REDUCE = 2,
-};
-
-#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT	cpu_to_le32(0xffff0000)
-#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT	cpu_to_le32(0xffff0000)
-#define IWLAGN_BT_KILL_ACK_CTS_MASK_SCO	cpu_to_le32(0xffffffff)
-#define IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE	cpu_to_le32(0)
-
-#define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT	2
-
-#define IWLAGN_BT3_T2_DEFAULT		0xc
-
-#define IWLAGN_BT_VALID_ENABLE_FLAGS	cpu_to_le16(BIT(0))
-#define IWLAGN_BT_VALID_BOOST		cpu_to_le16(BIT(1))
-#define IWLAGN_BT_VALID_MAX_KILL	cpu_to_le16(BIT(2))
-#define IWLAGN_BT_VALID_3W_TIMERS	cpu_to_le16(BIT(3))
-#define IWLAGN_BT_VALID_KILL_ACK_MASK	cpu_to_le16(BIT(4))
-#define IWLAGN_BT_VALID_KILL_CTS_MASK	cpu_to_le16(BIT(5))
-#define IWLAGN_BT_VALID_REDUCED_TX_PWR	cpu_to_le16(BIT(6))
-#define IWLAGN_BT_VALID_3W_LUT		cpu_to_le16(BIT(7))
-
-#define IWLAGN_BT_ALL_VALID_MSK		(IWLAGN_BT_VALID_ENABLE_FLAGS | \
-					IWLAGN_BT_VALID_BOOST | \
-					IWLAGN_BT_VALID_MAX_KILL | \
-					IWLAGN_BT_VALID_3W_TIMERS | \
-					IWLAGN_BT_VALID_KILL_ACK_MASK | \
-					IWLAGN_BT_VALID_KILL_CTS_MASK | \
-					IWLAGN_BT_VALID_REDUCED_TX_PWR | \
-					IWLAGN_BT_VALID_3W_LUT)
-
-#define IWLAGN_BT_REDUCED_TX_PWR	BIT(0)
-
-#define IWLAGN_BT_DECISION_LUT_SIZE	12
-
-struct iwl_basic_bt_cmd {
-	u8 flags;
-	u8 ledtime; /* unused */
-	u8 max_kill;
-	u8 bt3_timer_t7_value;
-	__le32 kill_ack_mask;
-	__le32 kill_cts_mask;
-	u8 bt3_prio_sample_time;
-	u8 bt3_timer_t2_value;
-	__le16 bt4_reaction_time; /* unused */
-	__le32 bt3_lookup_table[IWLAGN_BT_DECISION_LUT_SIZE];
-	/*
-	 * bit 0: use reduced tx power for control frame
-	 * bit 1 - 7: reserved
-	 */
-	u8 reduce_txpower;
-	u8 reserved;
-	__le16 valid;
-};
-
-struct iwl_bt_cmd_v1 {
-	struct iwl_basic_bt_cmd basic;
-	u8 prio_boost;
-	/*
-	 * set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask
-	 * if configure the following patterns
-	 */
-	u8 tx_prio_boost;	/* SW boost of WiFi tx priority */
-	__le16 rx_prio_boost;	/* SW boost of WiFi rx priority */
-};
-
-struct iwl_bt_cmd_v2 {
-	struct iwl_basic_bt_cmd basic;
-	__le32 prio_boost;
-	/*
-	 * set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask
-	 * if configure the following patterns
-	 */
-	u8 reserved;
-	u8 tx_prio_boost;	/* SW boost of WiFi tx priority */
-	__le16 rx_prio_boost;	/* SW boost of WiFi rx priority */
-};
-
-#define IWLAGN_BT_SCO_ACTIVE	cpu_to_le32(BIT(0))
-
-struct iwlagn_bt_sco_cmd {
-	__le32 flags;
-};
-
-/******************************************************************************
- * (6)
- * Spectrum Management (802.11h) Commands, Responses, Notifications:
- *
- *****************************************************************************/
-
-/*
- * Spectrum Management
- */
-#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
-				 RXON_FILTER_CTL2HOST_MSK        | \
-				 RXON_FILTER_ACCEPT_GRP_MSK      | \
-				 RXON_FILTER_DIS_DECRYPT_MSK     | \
-				 RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
-				 RXON_FILTER_ASSOC_MSK           | \
-				 RXON_FILTER_BCON_AWARE_MSK)
-
-struct iwl_measure_channel {
-	__le32 duration;	/* measurement duration in extended beacon
-				 * format */
-	u8 channel;		/* channel to measure */
-	u8 type;		/* see enum iwl_measure_type */
-	__le16 reserved;
-} __packed;
-
-/*
- * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
- */
-struct iwl_spectrum_cmd {
-	__le16 len;		/* number of bytes starting from token */
-	u8 token;		/* token id */
-	u8 id;			/* measurement id -- 0 or 1 */
-	u8 origin;		/* 0 = TGh, 1 = other, 2 = TGk */
-	u8 periodic;		/* 1 = periodic */
-	__le16 path_loss_timeout;
-	__le32 start_time;	/* start time in extended beacon format */
-	__le32 reserved2;
-	__le32 flags;		/* rxon flags */
-	__le32 filter_flags;	/* rxon filter flags */
-	__le16 channel_count;	/* minimum 1, maximum 10 */
-	__le16 reserved3;
-	struct iwl_measure_channel channels[10];
-} __packed;
-
-/*
- * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
- */
-struct iwl_spectrum_resp {
-	u8 token;
-	u8 id;			/* id of the prior command replaced, or 0xff */
-	__le16 status;		/* 0 - command will be handled
-				 * 1 - cannot handle (conflicts with another
-				 *     measurement) */
-} __packed;
-
-enum iwl_measurement_state {
-	IWL_MEASUREMENT_START = 0,
-	IWL_MEASUREMENT_STOP = 1,
-};
-
-enum iwl_measurement_status {
-	IWL_MEASUREMENT_OK = 0,
-	IWL_MEASUREMENT_CONCURRENT = 1,
-	IWL_MEASUREMENT_CSA_CONFLICT = 2,
-	IWL_MEASUREMENT_TGH_CONFLICT = 3,
-	/* 4-5 reserved */
-	IWL_MEASUREMENT_STOPPED = 6,
-	IWL_MEASUREMENT_TIMEOUT = 7,
-	IWL_MEASUREMENT_PERIODIC_FAILED = 8,
-};
-
-#define NUM_ELEMENTS_IN_HISTOGRAM 8
-
-struct iwl_measurement_histogram {
-	__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 0.8usec counts */
-	__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 1usec counts */
-} __packed;
-
-/* clear channel availability counters */
-struct iwl_measurement_cca_counters {
-	__le32 ofdm;
-	__le32 cck;
-} __packed;
-
-enum iwl_measure_type {
-	IWL_MEASURE_BASIC = (1 << 0),
-	IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
-	IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
-	IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
-	IWL_MEASURE_FRAME = (1 << 4),
-	/* bits 5:6 are reserved */
-	IWL_MEASURE_IDLE = (1 << 7),
-};
-
-/*
- * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
- */
-struct iwl_spectrum_notification {
-	u8 id;			/* measurement id -- 0 or 1 */
-	u8 token;
-	u8 channel_index;	/* index in measurement channel list */
-	u8 state;		/* 0 - start, 1 - stop */
-	__le32 start_time;	/* lower 32-bits of TSF */
-	u8 band;		/* 0 - 5.2GHz, 1 - 2.4GHz */
-	u8 channel;
-	u8 type;		/* see enum iwl_measurement_type */
-	u8 reserved1;
-	/* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
-	 * valid if applicable for measurement type requested. */
-	__le32 cca_ofdm;	/* cca fraction time in 40Mhz clock periods */
-	__le32 cca_cck;		/* cca fraction time in 44Mhz clock periods */
-	__le32 cca_time;	/* channel load time in usecs */
-	u8 basic_type;		/* 0 - bss, 1 - ofdm preamble, 2 -
-				 * unidentified */
-	u8 reserved2[3];
-	struct iwl_measurement_histogram histogram;
-	__le32 stop_time;	/* lower 32-bits of TSF */
-	__le32 status;		/* see iwl_measurement_status */
-} __packed;
-
-/******************************************************************************
- * (7)
- * Power Management Commands, Responses, Notifications:
- *
- *****************************************************************************/
-
-/**
- * struct iwl_powertable_cmd - Power Table Command
- * @flags: See below:
- *
- * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
- *
- * PM allow:
- *   bit 0 - '0' Driver not allow power management
- *           '1' Driver allow PM (use rest of parameters)
- *
- * uCode send sleep notifications:
- *   bit 1 - '0' Don't send sleep notification
- *           '1' send sleep notification (SEND_PM_NOTIFICATION)
- *
- * Sleep over DTIM
- *   bit 2 - '0' PM have to walk up every DTIM
- *           '1' PM could sleep over DTIM till listen Interval.
- *
- * PCI power managed
- *   bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1)
- *           '1' !(PCI_CFG_LINK_CTRL & 0x1)
- *
- * Fast PD
- *   bit 4 - '1' Put radio to sleep when receiving frame for others
- *
- * Force sleep Modes
- *   bit 31/30- '00' use both mac/xtal sleeps
- *              '01' force Mac sleep
- *              '10' force xtal sleep
- *              '11' Illegal set
- *
- * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
- * ucode assume sleep over DTIM is allowed and we don't need to wake up
- * for every DTIM.
- */
-#define IWL_POWER_VEC_SIZE 5
-
-#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	cpu_to_le16(BIT(0))
-#define IWL_POWER_POWER_SAVE_ENA_MSK		cpu_to_le16(BIT(0))
-#define IWL_POWER_POWER_MANAGEMENT_ENA_MSK	cpu_to_le16(BIT(1))
-#define IWL_POWER_SLEEP_OVER_DTIM_MSK		cpu_to_le16(BIT(2))
-#define IWL_POWER_PCI_PM_MSK			cpu_to_le16(BIT(3))
-#define IWL_POWER_FAST_PD			cpu_to_le16(BIT(4))
-#define IWL_POWER_BEACON_FILTERING		cpu_to_le16(BIT(5))
-#define IWL_POWER_SHADOW_REG_ENA		cpu_to_le16(BIT(6))
-#define IWL_POWER_CT_KILL_SET			cpu_to_le16(BIT(7))
-#define IWL_POWER_BT_SCO_ENA			cpu_to_le16(BIT(8))
-#define IWL_POWER_ADVANCE_PM_ENA_MSK		cpu_to_le16(BIT(9))
-
-struct iwl_powertable_cmd {
-	__le16 flags;
-	u8 keep_alive_seconds;
-	u8 debug_flags;
-	__le32 rx_data_timeout;
-	__le32 tx_data_timeout;
-	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
-	__le32 keep_alive_beacons;
-} __packed;
-
-/*
- * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
- * all devices identical.
- */
-struct iwl_sleep_notification {
-	u8 pm_sleep_mode;
-	u8 pm_wakeup_src;
-	__le16 reserved;
-	__le32 sleep_time;
-	__le32 tsf_low;
-	__le32 bcon_timer;
-} __packed;
-
-/* Sleep states.  all devices identical. */
-enum {
-	IWL_PM_NO_SLEEP = 0,
-	IWL_PM_SLP_MAC = 1,
-	IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
-	IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
-	IWL_PM_SLP_PHY = 4,
-	IWL_PM_SLP_REPENT = 5,
-	IWL_PM_WAKEUP_BY_TIMER = 6,
-	IWL_PM_WAKEUP_BY_DRIVER = 7,
-	IWL_PM_WAKEUP_BY_RFKILL = 8,
-	/* 3 reserved */
-	IWL_PM_NUM_OF_MODES = 12,
-};
-
-/*
- * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
- */
-#define CARD_STATE_CMD_DISABLE 0x00	/* Put card to sleep */
-#define CARD_STATE_CMD_ENABLE  0x01	/* Wake up card */
-#define CARD_STATE_CMD_HALT    0x02	/* Power down permanently */
-struct iwl_card_state_cmd {
-	__le32 status;		/* CARD_STATE_CMD_* request new power state */
-} __packed;
-
-/*
- * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
- */
-struct iwl_card_state_notif {
-	__le32 flags;
-} __packed;
-
-#define HW_CARD_DISABLED   0x01
-#define SW_CARD_DISABLED   0x02
-#define CT_CARD_DISABLED   0x04
-#define RXON_CARD_DISABLED 0x10
-
-struct iwl_ct_kill_config {
-	__le32   reserved;
-	__le32   critical_temperature_M;
-	__le32   critical_temperature_R;
-}  __packed;
-
-/* 1000, and 6x00 */
-struct iwl_ct_kill_throttling_config {
-	__le32   critical_temperature_exit;
-	__le32   reserved;
-	__le32   critical_temperature_enter;
-}  __packed;
-
-/******************************************************************************
- * (8)
- * Scan Commands, Responses, Notifications:
- *
- *****************************************************************************/
-
-#define SCAN_CHANNEL_TYPE_PASSIVE cpu_to_le32(0)
-#define SCAN_CHANNEL_TYPE_ACTIVE  cpu_to_le32(1)
-
-/**
- * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
- *
- * One for each channel in the scan list.
- * Each channel can independently select:
- * 1)  SSID for directed active scans
- * 2)  Txpower setting (for rate specified within Tx command)
- * 3)  How long to stay on-channel (behavior may be modified by quiet_time,
- *     quiet_plcp_th, good_CRC_th)
- *
- * To avoid uCode errors, make sure the following are true (see comments
- * under struct iwl_scan_cmd about max_out_time and quiet_time):
- * 1)  If using passive_dwell (i.e. passive_dwell != 0):
- *     active_dwell <= passive_dwell (< max_out_time if max_out_time != 0)
- * 2)  quiet_time <= active_dwell
- * 3)  If restricting off-channel time (i.e. max_out_time !=0):
- *     passive_dwell < max_out_time
- *     active_dwell < max_out_time
- */
-
-struct iwl_scan_channel {
-	/*
-	 * type is defined as:
-	 * 0:0 1 = active, 0 = passive
-	 * 1:20 SSID direct bit map; if a bit is set, then corresponding
-	 *     SSID IE is transmitted in probe request.
-	 * 21:31 reserved
-	 */
-	__le32 type;
-	__le16 channel;	/* band is selected by iwl_scan_cmd "flags" field */
-	u8 tx_gain;		/* gain for analog radio */
-	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 */
-} __packed;
-
-/* set number of direct probes __le32 type */
-#define IWL_SCAN_PROBE_MASK(n) 	cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
-
-/**
- * struct iwl_ssid_ie - directed scan network information element
- *
- * Up to 20 of these may appear in REPLY_SCAN_CMD,
- * selected by "type" bit field in struct iwl_scan_channel;
- * each channel may select different ssids from among the 20 entries.
- * SSID IEs get transmitted in reverse order of entry.
- */
-struct iwl_ssid_ie {
-	u8 id;
-	u8 len;
-	u8 ssid[32];
-} __packed;
-
-#define PROBE_OPTION_MAX		20
-#define TX_CMD_LIFE_TIME_INFINITE	cpu_to_le32(0xFFFFFFFF)
-#define IWL_GOOD_CRC_TH_DISABLED	0
-#define IWL_GOOD_CRC_TH_DEFAULT		cpu_to_le16(1)
-#define IWL_GOOD_CRC_TH_NEVER		cpu_to_le16(0xffff)
-#define IWL_MAX_CMD_SIZE 4096
-
-/*
- * REPLY_SCAN_CMD = 0x80 (command)
- *
- * The hardware scan command is very powerful; the driver can set it up to
- * maintain (relatively) normal network traffic while doing a scan in the
- * background.  The max_out_time and suspend_time control the ratio of how
- * long the device stays on an associated network channel ("service channel")
- * vs. how long it's away from the service channel, i.e. tuned to other channels
- * for scanning.
- *
- * max_out_time is the max time off-channel (in usec), and suspend_time
- * is how long (in "extended beacon" format) that the scan is "suspended"
- * after returning to the service channel.  That is, suspend_time is the
- * time that we stay on the service channel, doing normal work, between
- * scan segments.  The driver may set these parameters differently to support
- * scanning when associated vs. not associated, and light vs. heavy traffic
- * loads when associated.
- *
- * After receiving this command, the device's scan engine does the following;
- *
- * 1)  Sends SCAN_START notification to driver
- * 2)  Checks to see if it has time to do scan for one channel
- * 3)  Sends NULL packet, with power-save (PS) bit set to 1,
- *     to tell AP that we're going off-channel
- * 4)  Tunes to first channel in scan list, does active or passive scan
- * 5)  Sends SCAN_RESULT notification to driver
- * 6)  Checks to see if it has time to do scan on *next* channel in list
- * 7)  Repeats 4-6 until it no longer has time to scan the next channel
- *     before max_out_time expires
- * 8)  Returns to service channel
- * 9)  Sends NULL packet with PS=0 to tell AP that we're back
- * 10) Stays on service channel until suspend_time expires
- * 11) Repeats entire process 2-10 until list is complete
- * 12) Sends SCAN_COMPLETE notification
- *
- * For fast, efficient scans, the scan command also has support for staying on
- * a channel for just a short time, if doing active scanning and getting no
- * responses to the transmitted probe request.  This time is controlled by
- * quiet_time, and the number of received packets below which a channel is
- * considered "quiet" is controlled by quiet_plcp_threshold.
- *
- * For active scanning on channels that have regulatory restrictions against
- * blindly transmitting, the scan can listen before transmitting, to make sure
- * that there is already legitimate activity on the channel.  If enough
- * packets are cleanly received on the channel (controlled by good_CRC_th,
- * typical value 1), the scan engine starts transmitting probe requests.
- *
- * Driver must use separate scan commands for 2.4 vs. 5 GHz bands.
- *
- * To avoid uCode errors, see timing restrictions described under
- * struct iwl_scan_channel.
- */
-
-enum iwl_scan_flags {
-	/* BIT(0) currently unused */
-	IWL_SCAN_FLAGS_ACTION_FRAME_TX	= BIT(1),
-	/* bits 2-7 reserved */
-};
-
-struct iwl_scan_cmd {
-	__le16 len;
-	u8 scan_flags;		/* scan flags: see enum iwl_scan_flags */
-	u8 channel_count;	/* # channels in channel list */
-	__le16 quiet_time;	/* dwell only this # millisecs on quiet channel
-				 * (only for active scan) */
-	__le16 quiet_plcp_th;	/* quiet chnl is < this # pkts (typ. 1) */
-	__le16 good_CRC_th;	/* passive -> active promotion threshold */
-	__le16 rx_chain;	/* RXON_RX_CHAIN_* */
-	__le32 max_out_time;	/* max usec to be away from associated (service)
-				 * channel */
-	__le32 suspend_time;	/* pause scan this long (in "extended beacon
-				 * format") when returning to service chnl:
-				 */
-	__le32 flags;		/* RXON_FLG_* */
-	__le32 filter_flags;	/* RXON_FILTER_* */
-
-	/* For active scans (set to all-0s for passive scans).
-	 * Does not include payload.  Must specify Tx rate; no rate scaling. */
-	struct iwl_tx_cmd tx_cmd;
-
-	/* For directed active scans (set to all-0s otherwise) */
-	struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
-
-	/*
-	 * Probe request frame, followed by channel list.
-	 *
-	 * Size of probe request frame is specified by byte count in tx_cmd.
-	 * Channel list follows immediately after probe request frame.
-	 * Number of channels in list is specified by channel_count.
-	 * Each channel in list is of type:
-	 *
-	 * struct iwl_scan_channel channels[0];
-	 *
-	 * NOTE:  Only one band of channels can be scanned per pass.  You
-	 * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
-	 * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
-	 * before requesting another scan.
-	 */
-	u8 data[0];
-} __packed;
-
-/* Can abort will notify by complete notification with abort status. */
-#define CAN_ABORT_STATUS	cpu_to_le32(0x1)
-/* complete notification statuses */
-#define ABORT_STATUS            0x2
-
-/*
- * REPLY_SCAN_CMD = 0x80 (response)
- */
-struct iwl_scanreq_notification {
-	__le32 status;		/* 1: okay, 2: cannot fulfill request */
-} __packed;
-
-/*
- * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
- */
-struct iwl_scanstart_notification {
-	__le32 tsf_low;
-	__le32 tsf_high;
-	__le32 beacon_timer;
-	u8 channel;
-	u8 band;
-	u8 reserved[2];
-	__le32 status;
-} __packed;
-
-#define  SCAN_OWNER_STATUS 0x1
-#define  MEASURE_OWNER_STATUS 0x2
-
-#define IWL_PROBE_STATUS_OK		0
-#define IWL_PROBE_STATUS_TX_FAILED	BIT(0)
-/* error statuses combined with TX_FAILED */
-#define IWL_PROBE_STATUS_FAIL_TTL	BIT(1)
-#define IWL_PROBE_STATUS_FAIL_BT	BIT(2)
-
-#define NUMBER_OF_STATISTICS 1	/* first __le32 is good CRC */
-/*
- * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
- */
-struct iwl_scanresults_notification {
-	u8 channel;
-	u8 band;
-	u8 probe_status;
-	u8 num_probe_not_sent; /* not enough time to send */
-	__le32 tsf_low;
-	__le32 tsf_high;
-	__le32 statistics[NUMBER_OF_STATISTICS];
-} __packed;
-
-/*
- * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
- */
-struct iwl_scancomplete_notification {
-	u8 scanned_channels;
-	u8 status;
-	u8 bt_status;	/* BT On/Off status */
-	u8 last_channel;
-	__le32 tsf_low;
-	__le32 tsf_high;
-} __packed;
-
-
-/******************************************************************************
- * (9)
- * IBSS/AP Commands and Notifications:
- *
- *****************************************************************************/
-
-enum iwl_ibss_manager {
-	IWL_NOT_IBSS_MANAGER = 0,
-	IWL_IBSS_MANAGER = 1,
-};
-
-/*
- * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
- */
-
-struct iwlagn_beacon_notif {
-	struct iwlagn_tx_resp beacon_notify_hdr;
-	__le32 low_tsf;
-	__le32 high_tsf;
-	__le32 ibss_mgr_status;
-} __packed;
-
-/*
- * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
- */
-
-struct iwl_tx_beacon_cmd {
-	struct iwl_tx_cmd tx;
-	__le16 tim_idx;
-	u8 tim_size;
-	u8 reserved1;
-	struct ieee80211_hdr frame[0];	/* beacon frame */
-} __packed;
-
-/******************************************************************************
- * (10)
- * Statistics Commands and Notifications:
- *
- *****************************************************************************/
-
-#define IWL_TEMP_CONVERT 260
-
-#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
-#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
-#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
-
-/* Used for passing to driver number of successes and failures per rate */
-struct rate_histogram {
-	union {
-		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
-		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
-		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
-	} success;
-	union {
-		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
-		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
-		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
-	} failed;
-} __packed;
-
-/* statistics command response */
-
-struct statistics_dbg {
-	__le32 burst_check;
-	__le32 burst_count;
-	__le32 wait_for_silence_timeout_cnt;
-	__le32 reserved[3];
-} __packed;
-
-struct statistics_rx_phy {
-	__le32 ina_cnt;
-	__le32 fina_cnt;
-	__le32 plcp_err;
-	__le32 crc32_err;
-	__le32 overrun_err;
-	__le32 early_overrun_err;
-	__le32 crc32_good;
-	__le32 false_alarm_cnt;
-	__le32 fina_sync_err_cnt;
-	__le32 sfd_timeout;
-	__le32 fina_timeout;
-	__le32 unresponded_rts;
-	__le32 rxe_frame_limit_overrun;
-	__le32 sent_ack_cnt;
-	__le32 sent_cts_cnt;
-	__le32 sent_ba_rsp_cnt;
-	__le32 dsp_self_kill;
-	__le32 mh_format_err;
-	__le32 re_acq_main_rssi_sum;
-	__le32 reserved3;
-} __packed;
-
-struct statistics_rx_ht_phy {
-	__le32 plcp_err;
-	__le32 overrun_err;
-	__le32 early_overrun_err;
-	__le32 crc32_good;
-	__le32 crc32_err;
-	__le32 mh_format_err;
-	__le32 agg_crc32_good;
-	__le32 agg_mpdu_cnt;
-	__le32 agg_cnt;
-	__le32 unsupport_mcs;
-} __packed;
-
-#define INTERFERENCE_DATA_AVAILABLE      cpu_to_le32(1)
-
-struct statistics_rx_non_phy {
-	__le32 bogus_cts;	/* CTS received when not expecting CTS */
-	__le32 bogus_ack;	/* ACK received when not expecting ACK */
-	__le32 non_bssid_frames;	/* number of frames with BSSID that
-					 * doesn't belong to the STA BSSID */
-	__le32 filtered_frames;	/* count frames that were dumped in the
-				 * filtering process */
-	__le32 non_channel_beacons;	/* beacons with our bss id but not on
-					 * our serving channel */
-	__le32 channel_beacons;	/* beacons with our bss id and in our
-				 * serving channel */
-	__le32 num_missed_bcon;	/* number of missed beacons */
-	__le32 adc_rx_saturation_time;	/* count in 0.8us units the time the
-					 * ADC was in saturation */
-	__le32 ina_detection_search_time;/* total time (in 0.8us) searched
-					  * for INA */
-	__le32 beacon_silence_rssi_a;	/* RSSI silence after beacon frame */
-	__le32 beacon_silence_rssi_b;	/* RSSI silence after beacon frame */
-	__le32 beacon_silence_rssi_c;	/* RSSI silence after beacon frame */
-	__le32 interference_data_flag;	/* flag for interference data
-					 * availability. 1 when data is
-					 * available. */
-	__le32 channel_load;		/* counts RX Enable time in uSec */
-	__le32 dsp_false_alarms;	/* DSP false alarm (both OFDM
-					 * and CCK) counter */
-	__le32 beacon_rssi_a;
-	__le32 beacon_rssi_b;
-	__le32 beacon_rssi_c;
-	__le32 beacon_energy_a;
-	__le32 beacon_energy_b;
-	__le32 beacon_energy_c;
-} __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;
-} __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
- *
- * @ant_a: current tx power on chain a in 1/2 dB step
- * @ant_b: current tx power on chain b in 1/2 dB step
- * @ant_c: current tx power on chain c in 1/2 dB step
- */
-struct statistics_tx_power {
-	u8 ant_a;
-	u8 ant_b;
-	u8 ant_c;
-	u8 reserved;
-} __packed;
-
-struct statistics_tx_non_phy_agg {
-	__le32 ba_timeout;
-	__le32 ba_reschedule_frames;
-	__le32 scd_query_agg_frame_cnt;
-	__le32 scd_query_no_agg;
-	__le32 scd_query_agg;
-	__le32 scd_query_mismatch;
-	__le32 frame_not_ready;
-	__le32 underrun;
-	__le32 bt_prio_kill;
-	__le32 rx_ba_rsp_cnt;
-} __packed;
-
-struct statistics_tx {
-	__le32 preamble_cnt;
-	__le32 rx_detected_cnt;
-	__le32 bt_prio_defer_cnt;
-	__le32 bt_prio_kill_cnt;
-	__le32 few_bytes_cnt;
-	__le32 cts_timeout;
-	__le32 ack_timeout;
-	__le32 expected_ack_cnt;
-	__le32 actual_ack_cnt;
-	__le32 dump_msdu_cnt;
-	__le32 burst_abort_next_frame_mismatch_cnt;
-	__le32 burst_abort_missing_next_frame_cnt;
-	__le32 cts_timeout_collision;
-	__le32 ack_or_ba_timeout_collision;
-	struct statistics_tx_non_phy_agg agg;
-	/*
-	 * "tx_power" are optional parameters provided by uCode,
-	 * 6000 series is the only device provide the information,
-	 * Those are reserved fields for all the other devices
-	 */
-	struct statistics_tx_power tx_power;
-	__le32 reserved1;
-} __packed;
-
-
-struct statistics_div {
-	__le32 tx_on_a;
-	__le32 tx_on_b;
-	__le32 exec_time;
-	__le32 probe_time;
-	__le32 reserved1;
-	__le32 reserved2;
-} __packed;
-
-struct statistics_general_common {
-	__le32 temperature;   /* radio temperature */
-	__le32 temperature_m; /* radio voltage */
-	struct statistics_dbg dbg;
-	__le32 sleep_time;
-	__le32 slots_out;
-	__le32 slots_idle;
-	__le32 ttl_timestamp;
-	struct statistics_div div;
-	__le32 rx_enable_counter;
-	/*
-	 * num_of_sos_states:
-	 *  count the number of times we have to re-tune
-	 *  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;
-} __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)
-#define UCODE_STATISTICS_NARROW_BAND_MSK	(0x1 << 2)
-
-/*
- * REPLY_STATISTICS_CMD = 0x9c,
- * all devices identical.
- *
- * This command triggers an immediate response containing uCode statistics.
- * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
- *
- * If the CLEAR_STATS configuration flag is set, uCode will clear its
- * internal copy of the statistics (counters) after issuing the response.
- * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
- *
- * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
- * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
- * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
- */
-#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1)	/* see above */
-#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */
-struct iwl_statistics_cmd {
-	__le32 configuration_flags;	/* IWL_STATS_CONF_* */
-} __packed;
-
-/*
- * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
- *
- * By default, uCode issues this notification after receiving a beacon
- * while associated.  To disable this behavior, set DISABLE_NOTIF flag in the
- * REPLY_STATISTICS_CMD 0x9c, above.
- *
- * Statistics counters continue to increment beacon after beacon, but are
- * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
- * 0x9c with CLEAR_STATS bit set (see above).
- *
- * uCode also issues this notification during scans.  uCode clears statistics
- * appropriately so that each notification contains statistics for only the
- * one channel that has just been scanned.
- */
-#define STATISTICS_REPLY_FLG_BAND_24G_MSK         cpu_to_le32(0x2)
-#define STATISTICS_REPLY_FLG_HT40_MODE_MSK        cpu_to_le32(0x8)
-
-struct iwl_notif_statistics {
-	__le32 flag;
-	struct statistics_rx rx;
-	struct statistics_tx tx;
-	struct statistics_general general;
-} __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)
- *
- * uCode send MISSED_BEACONS_NOTIFICATION to driver when detect beacon missed
- * in regardless of how many missed beacons, which mean when driver receive the
- * notification, inside the command, it can find all the beacons information
- * which include number of total missed beacons, number of consecutive missed
- * beacons, number of beacons received and number of beacons expected to
- * receive.
- *
- * If uCode detected consecutive_missed_beacons > 5, it will reset the radio
- * in order to bring the radio/PHY back to working state; which has no relation
- * to when driver will perform sensitivity calibration.
- *
- * Driver should set it own missed_beacon_threshold to decide when to perform
- * sensitivity calibration based on number of consecutive missed beacons in
- * order to improve overall performance, especially in noisy environment.
- *
- */
-
-#define IWL_MISSED_BEACON_THRESHOLD_MIN	(1)
-#define IWL_MISSED_BEACON_THRESHOLD_DEF	(5)
-#define IWL_MISSED_BEACON_THRESHOLD_MAX	IWL_MISSED_BEACON_THRESHOLD_DEF
-
-struct iwl_missed_beacon_notif {
-	__le32 consecutive_missed_beacons;
-	__le32 total_missed_becons;
-	__le32 num_expected_beacons;
-	__le32 num_recvd_beacons;
-} __packed;
-
-
-/******************************************************************************
- * (11)
- * Rx Calibration Commands:
- *
- * With the uCode used for open source drivers, most Tx calibration (except
- * for Tx Power) and most Rx calibration is done by uCode during the
- * "initialize" phase of uCode boot.  Driver must calibrate only:
- *
- * 1)  Tx power (depends on temperature), described elsewhere
- * 2)  Receiver gain balance (optimize MIMO, and detect disconnected antennas)
- * 3)  Receiver sensitivity (to optimize signal detection)
- *
- *****************************************************************************/
-
-/**
- * SENSITIVITY_CMD = 0xa8 (command, has simple generic response)
- *
- * This command sets up the Rx signal detector for a sensitivity level that
- * is high enough to lock onto all signals within the associated network,
- * but low enough to ignore signals that are below a certain threshold, so as
- * not to have too many "false alarms".  False alarms are signals that the
- * Rx DSP tries to lock onto, but then discards after determining that they
- * are noise.
- *
- * The optimum number of false alarms is between 5 and 50 per 200 TUs
- * (200 * 1024 uSecs, i.e. 204.8 milliseconds) of actual Rx time (i.e.
- * time listening, not transmitting).  Driver must adjust sensitivity so that
- * the ratio of actual false alarms to actual Rx time falls within this range.
- *
- * While associated, uCode delivers STATISTICS_NOTIFICATIONs after each
- * received beacon.  These provide information to the driver to analyze the
- * sensitivity.  Don't analyze statistics that come in from scanning, or any
- * other non-associated-network source.  Pertinent statistics include:
- *
- * From "general" statistics (struct statistics_rx_non_phy):
- *
- * (beacon_energy_[abc] & 0x0FF00) >> 8 (unsigned, higher value is lower level)
- *   Measure of energy of desired signal.  Used for establishing a level
- *   below which the device does not detect signals.
- *
- * (beacon_silence_rssi_[abc] & 0x0FF00) >> 8 (unsigned, units in dB)
- *   Measure of background noise in silent period after beacon.
- *
- * channel_load
- *   uSecs of actual Rx time during beacon period (varies according to
- *   how much time was spent transmitting).
- *
- * From "cck" and "ofdm" statistics (struct statistics_rx_phy), separately:
- *
- * false_alarm_cnt
- *   Signal locks abandoned early (before phy-level header).
- *
- * plcp_err
- *   Signal locks abandoned late (during phy-level header).
- *
- * NOTE:  Both false_alarm_cnt and plcp_err increment monotonically from
- *        beacon to beacon, i.e. each value is an accumulation of all errors
- *        before and including the latest beacon.  Values will wrap around to 0
- *        after counting up to 2^32 - 1.  Driver must differentiate vs.
- *        previous beacon's values to determine # false alarms in the current
- *        beacon period.
- *
- * Total number of false alarms = false_alarms + plcp_errs
- *
- * For OFDM, adjust the following table entries in struct iwl_sensitivity_cmd
- * (notice that the start points for OFDM are at or close to settings for
- * maximum sensitivity):
- *
- *                                             START  /  MIN  /  MAX
- *   HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          90   /   85  /  120
- *   HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX     170   /  170  /  210
- *   HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX         105   /  105  /  140
- *   HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX     220   /  220  /  270
- *
- *   If actual rate of OFDM false alarms (+ plcp_errors) is too high
- *   (greater than 50 for each 204.8 msecs listening), reduce sensitivity
- *   by *adding* 1 to all 4 of the table entries above, up to the max for
- *   each entry.  Conversely, if false alarm rate is too low (less than 5
- *   for each 204.8 msecs listening), *subtract* 1 from each entry to
- *   increase sensitivity.
- *
- * For CCK sensitivity, keep track of the following:
- *
- *   1).  20-beacon history of maximum background noise, indicated by
- *        (beacon_silence_rssi_[abc] & 0x0FF00), units in dB, across the
- *        3 receivers.  For any given beacon, the "silence reference" is
- *        the maximum of last 60 samples (20 beacons * 3 receivers).
- *
- *   2).  10-beacon history of strongest signal level, as indicated
- *        by (beacon_energy_[abc] & 0x0FF00) >> 8, across the 3 receivers,
- *        i.e. the strength of the signal through the best receiver at the
- *        moment.  These measurements are "upside down", with lower values
- *        for stronger signals, so max energy will be *minimum* value.
- *
- *        Then for any given beacon, the driver must determine the *weakest*
- *        of the strongest signals; this is the minimum level that needs to be
- *        successfully detected, when using the best receiver at the moment.
- *        "Max cck energy" is the maximum (higher value means lower energy!)
- *        of the last 10 minima.  Once this is determined, driver must add
- *        a little margin by adding "6" to it.
- *
- *   3).  Number of consecutive beacon periods with too few false alarms.
- *        Reset this to 0 at the first beacon period that falls within the
- *        "good" range (5 to 50 false alarms per 204.8 milliseconds rx).
- *
- * Then, adjust the following CCK table entries in struct iwl_sensitivity_cmd
- * (notice that the start points for CCK are at maximum sensitivity):
- *
- *                                             START  /  MIN  /  MAX
- *   HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX         125   /  125  /  200
- *   HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX     200   /  200  /  400
- *   HD_MIN_ENERGY_CCK_DET_INDEX                100   /    0  /  100
- *
- *   If actual rate of CCK false alarms (+ plcp_errors) is too high
- *   (greater than 50 for each 204.8 msecs listening), method for reducing
- *   sensitivity is:
- *
- *   1)  *Add* 3 to value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
- *       up to max 400.
- *
- *   2)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is < 160,
- *       sensitivity has been reduced a significant amount; bring it up to
- *       a moderate 161.  Otherwise, *add* 3, up to max 200.
- *
- *   3)  a)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is > 160,
- *       sensitivity has been reduced only a moderate or small amount;
- *       *subtract* 2 from value in HD_MIN_ENERGY_CCK_DET_INDEX,
- *       down to min 0.  Otherwise (if gain has been significantly reduced),
- *       don't change the HD_MIN_ENERGY_CCK_DET_INDEX value.
- *
- *       b)  Save a snapshot of the "silence reference".
- *
- *   If actual rate of CCK false alarms (+ plcp_errors) is too low
- *   (less than 5 for each 204.8 msecs listening), method for increasing
- *   sensitivity is used only if:
- *
- *   1a)  Previous beacon did not have too many false alarms
- *   1b)  AND difference between previous "silence reference" and current
- *        "silence reference" (prev - current) is 2 or more,
- *   OR 2)  100 or more consecutive beacon periods have had rate of
- *          less than 5 false alarms per 204.8 milliseconds rx time.
- *
- *   Method for increasing sensitivity:
- *
- *   1)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX,
- *       down to min 125.
- *
- *   2)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
- *       down to min 200.
- *
- *   3)  *Add* 2 to value in HD_MIN_ENERGY_CCK_DET_INDEX, up to max 100.
- *
- *   If actual rate of CCK false alarms (+ plcp_errors) is within good range
- *   (between 5 and 50 for each 204.8 msecs listening):
- *
- *   1)  Save a snapshot of the silence reference.
- *
- *   2)  If previous beacon had too many CCK false alarms (+ plcp_errors),
- *       give some extra margin to energy threshold by *subtracting* 8
- *       from value in HD_MIN_ENERGY_CCK_DET_INDEX.
- *
- *   For all cases (too few, too many, good range), make sure that the CCK
- *   detection threshold (energy) is below the energy level for robust
- *   detection over the past 10 beacon periods, the "Max cck energy".
- *   Lower values mean higher energy; this means making sure that the value
- *   in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy".
- *
- */
-
-/*
- * Table entries in SENSITIVITY_CMD (struct iwl_sensitivity_cmd)
- */
-#define HD_TABLE_SIZE  (11)	/* number of entries */
-#define HD_MIN_ENERGY_CCK_DET_INDEX                 (0)	/* table indexes */
-#define HD_MIN_ENERGY_OFDM_DET_INDEX                (1)
-#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          (2)
-#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX      (3)
-#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX      (4)
-#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX          (5)
-#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX      (6)
-#define HD_BARKER_CORR_TH_ADD_MIN_INDEX             (7)
-#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX         (8)
-#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_V1		cpu_to_le16(0)
-#define HD_INA_NON_SQUARE_DET_CCK_DATA_V1		cpu_to_le16(0)
-#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1		cpu_to_le16(0)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1	cpu_to_le16(668)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1	cpu_to_le16(4)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1		cpu_to_le16(486)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1	cpu_to_le16(37)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1		cpu_to_le16(853)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1	cpu_to_le16(4)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1		cpu_to_le16(476)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1		cpu_to_le16(99)
-
-#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V2		cpu_to_le16(1)
-#define HD_INA_NON_SQUARE_DET_CCK_DATA_V2		cpu_to_le16(1)
-#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2		cpu_to_le16(1)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2	cpu_to_le16(600)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2	cpu_to_le16(40)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2		cpu_to_le16(486)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2	cpu_to_le16(45)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2		cpu_to_le16(853)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2	cpu_to_le16(60)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2		cpu_to_le16(476)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2		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)
-
-/**
- * struct iwl_sensitivity_cmd
- * @control:  (1) updates working table, (0) updates default table
- * @table:  energy threshold values, use HD_* as index into table
- *
- * Always use "1" in "control" to update uCode's working table and DSP.
- */
-struct iwl_sensitivity_cmd {
-	__le16 control;			/* always use "1" */
-	__le16 table[HD_TABLE_SIZE];	/* use HD_* as index */
-} __packed;
-
-/*
- *
- */
-struct iwl_enhance_sensitivity_cmd {
-	__le16 control;			/* always use "1" */
-	__le16 enhance_table[ENHANCE_HD_TABLE_SIZE];	/* use HD_* as index */
-} __packed;
-
-
-/**
- * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)
- *
- * This command sets the relative gains of agn device's 3 radio receiver chains.
- *
- * After the first association, driver should accumulate signal and noise
- * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20
- * beacons from the associated network (don't collect statistics that come
- * in from scanning, or any other non-network source).
- *
- * DISCONNECTED ANTENNA:
- *
- * Driver should determine which antennas are actually connected, by comparing
- * average beacon signal levels for the 3 Rx chains.  Accumulate (add) the
- * following values over 20 beacons, one accumulator for each of the chains
- * a/b/c, from struct statistics_rx_non_phy:
- *
- * beacon_rssi_[abc] & 0x0FF (unsigned, units in dB)
- *
- * Find the strongest signal from among a/b/c.  Compare the other two to the
- * strongest.  If any signal is more than 15 dB (times 20, unless you
- * divide the accumulated values by 20) below the strongest, the driver
- * considers that antenna to be disconnected, and should not try to use that
- * antenna/chain for Rx or Tx.  If both A and B seem to be disconnected,
- * driver should declare the stronger one as connected, and attempt to use it
- * (A and B are the only 2 Tx chains!).
- *
- *
- * RX BALANCE:
- *
- * Driver should balance the 3 receivers (but just the ones that are connected
- * to antennas, see above) for gain, by comparing the average signal levels
- * detected during the silence after each beacon (background noise).
- * Accumulate (add) the following values over 20 beacons, one accumulator for
- * each of the chains a/b/c, from struct statistics_rx_non_phy:
- *
- * beacon_silence_rssi_[abc] & 0x0FF (unsigned, units in dB)
- *
- * Find the weakest background noise level from among a/b/c.  This Rx chain
- * will be the reference, with 0 gain adjustment.  Attenuate other channels by
- * finding noise difference:
- *
- * (accum_noise[i] - accum_noise[reference]) / 30
- *
- * The "30" adjusts the dB in the 20 accumulated samples to units of 1.5 dB.
- * For use in diff_gain_[abc] fields of struct iwl_calibration_cmd, the
- * driver should limit the difference results to a range of 0-3 (0-4.5 dB),
- * and set bit 2 to indicate "reduce gain".  The value for the reference
- * (weakest) chain should be "0".
- *
- * diff_gain_[abc] bit fields:
- *   2: (1) reduce gain, (0) increase gain
- * 1-0: amount of gain, units of 1.5 dB
- */
-
-/* Phy calibration command for series */
-enum {
-	IWL_PHY_CALIBRATE_DC_CMD		= 8,
-	IWL_PHY_CALIBRATE_LO_CMD		= 9,
-	IWL_PHY_CALIBRATE_TX_IQ_CMD		= 11,
-	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_TEMP_OFFSET_CMD	= 18,
-};
-
-/* This enum defines the bitmap of various calibrations to enable in both
- * init ucode and runtime ucode through CALIBRATION_CFG_CMD.
- */
-enum iwl_ucode_calib_cfg {
-	IWL_CALIB_CFG_RX_BB_IDX			= BIT(0),
-	IWL_CALIB_CFG_DC_IDX			= BIT(1),
-	IWL_CALIB_CFG_LO_IDX			= BIT(2),
-	IWL_CALIB_CFG_TX_IQ_IDX			= BIT(3),
-	IWL_CALIB_CFG_RX_IQ_IDX			= BIT(4),
-	IWL_CALIB_CFG_NOISE_IDX			= BIT(5),
-	IWL_CALIB_CFG_CRYSTAL_IDX		= BIT(6),
-	IWL_CALIB_CFG_TEMPERATURE_IDX		= BIT(7),
-	IWL_CALIB_CFG_PAPD_IDX			= BIT(8),
-	IWL_CALIB_CFG_SENSITIVITY_IDX		= BIT(9),
-	IWL_CALIB_CFG_TX_PWR_IDX		= BIT(10),
-};
-
-#define IWL_CALIB_INIT_CFG_ALL	cpu_to_le32(IWL_CALIB_CFG_RX_BB_IDX |	\
-					IWL_CALIB_CFG_DC_IDX |		\
-					IWL_CALIB_CFG_LO_IDX |		\
-					IWL_CALIB_CFG_TX_IQ_IDX |	\
-					IWL_CALIB_CFG_RX_IQ_IDX |	\
-					IWL_CALIB_CFG_CRYSTAL_IDX)
-
-#define IWL_CALIB_RT_CFG_ALL	cpu_to_le32(IWL_CALIB_CFG_RX_BB_IDX |	\
-					IWL_CALIB_CFG_DC_IDX |		\
-					IWL_CALIB_CFG_LO_IDX |		\
-					IWL_CALIB_CFG_TX_IQ_IDX |	\
-					IWL_CALIB_CFG_RX_IQ_IDX |	\
-					IWL_CALIB_CFG_TEMPERATURE_IDX |	\
-					IWL_CALIB_CFG_PAPD_IDX |	\
-					IWL_CALIB_CFG_TX_PWR_IDX |	\
-					IWL_CALIB_CFG_CRYSTAL_IDX)
-
-#define IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK	cpu_to_le32(BIT(0))
-
-struct iwl_calib_cfg_elmnt_s {
-	__le32 is_enable;
-	__le32 start;
-	__le32 send_res;
-	__le32 apply_res;
-	__le32 reserved;
-} __packed;
-
-struct iwl_calib_cfg_status_s {
-	struct iwl_calib_cfg_elmnt_s once;
-	struct iwl_calib_cfg_elmnt_s perd;
-	__le32 flags;
-} __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;
-} __packed;
-
-struct iwl_calib_hdr {
-	u8 op_code;
-	u8 first_group;
-	u8 groups_num;
-	u8 data_valid;
-} __packed;
-
-struct iwl_calib_cmd {
-	struct iwl_calib_hdr hdr;
-	u8 data[0];
-} __packed;
-
-struct iwl_calib_xtal_freq_cmd {
-	struct iwl_calib_hdr hdr;
-	u8 cap_pin1;
-	u8 cap_pin2;
-	u8 pad[2];
-} __packed;
-
-#define DEFAULT_RADIO_SENSOR_OFFSET    cpu_to_le16(2700)
-struct iwl_calib_temperature_offset_cmd {
-	struct iwl_calib_hdr hdr;
-	__le16 radio_sensor_offset;
-	__le16 reserved;
-} __packed;
-
-struct iwl_calib_temperature_offset_v2_cmd {
-	struct iwl_calib_hdr hdr;
-	__le16 radio_sensor_offset_high;
-	__le16 radio_sensor_offset_low;
-	__le16 burntVoltageRef;
-	__le16 reserved;
-} __packed;
-
-/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
-struct iwl_calib_chain_noise_reset_cmd {
-	struct iwl_calib_hdr hdr;
-	u8 data[0];
-};
-
-/* IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */
-struct iwl_calib_chain_noise_gain_cmd {
-	struct iwl_calib_hdr hdr;
-	u8 delta_gain_1;
-	u8 delta_gain_2;
-	u8 pad[2];
-} __packed;
-
-/******************************************************************************
- * (12)
- * Miscellaneous Commands:
- *
- *****************************************************************************/
-
-/*
- * LEDs Command & Response
- * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
- *
- * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
- * this command turns it on or off, or sets up a periodic blinking cycle.
- */
-struct iwl_led_cmd {
-	__le32 interval;	/* "interval" in uSec */
-	u8 id;			/* 1: Activity, 2: Link, 3: Tech */
-	u8 off;			/* # intervals off while blinking;
-				 * "0", with >0 "on" value, turns LED on */
-	u8 on;			/* # intervals on while blinking;
-				 * "0", regardless of "off", turns LED off */
-	u8 reserved;
-} __packed;
-
-/*
- * station priority table entries
- * also used as potential "events" value for both
- * COEX_MEDIUM_NOTIFICATION and COEX_EVENT_CMD
- */
-
-/*
- * COEX events entry flag masks
- * RP - Requested Priority
- * WP - Win Medium Priority: priority assigned when the contention has been won
- */
-#define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG        (0x1)
-#define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG        (0x2)
-#define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG  (0x4)
-
-#define COEX_CU_UNASSOC_IDLE_RP               4
-#define COEX_CU_UNASSOC_MANUAL_SCAN_RP        4
-#define COEX_CU_UNASSOC_AUTO_SCAN_RP          4
-#define COEX_CU_CALIBRATION_RP                4
-#define COEX_CU_PERIODIC_CALIBRATION_RP       4
-#define COEX_CU_CONNECTION_ESTAB_RP           4
-#define COEX_CU_ASSOCIATED_IDLE_RP            4
-#define COEX_CU_ASSOC_MANUAL_SCAN_RP          4
-#define COEX_CU_ASSOC_AUTO_SCAN_RP            4
-#define COEX_CU_ASSOC_ACTIVE_LEVEL_RP         4
-#define COEX_CU_RF_ON_RP                      6
-#define COEX_CU_RF_OFF_RP                     4
-#define COEX_CU_STAND_ALONE_DEBUG_RP          6
-#define COEX_CU_IPAN_ASSOC_LEVEL_RP           4
-#define COEX_CU_RSRVD1_RP                     4
-#define COEX_CU_RSRVD2_RP                     4
-
-#define COEX_CU_UNASSOC_IDLE_WP               3
-#define COEX_CU_UNASSOC_MANUAL_SCAN_WP        3
-#define COEX_CU_UNASSOC_AUTO_SCAN_WP          3
-#define COEX_CU_CALIBRATION_WP                3
-#define COEX_CU_PERIODIC_CALIBRATION_WP       3
-#define COEX_CU_CONNECTION_ESTAB_WP           3
-#define COEX_CU_ASSOCIATED_IDLE_WP            3
-#define COEX_CU_ASSOC_MANUAL_SCAN_WP          3
-#define COEX_CU_ASSOC_AUTO_SCAN_WP            3
-#define COEX_CU_ASSOC_ACTIVE_LEVEL_WP         3
-#define COEX_CU_RF_ON_WP                      3
-#define COEX_CU_RF_OFF_WP                     3
-#define COEX_CU_STAND_ALONE_DEBUG_WP          6
-#define COEX_CU_IPAN_ASSOC_LEVEL_WP           3
-#define COEX_CU_RSRVD1_WP                     3
-#define COEX_CU_RSRVD2_WP                     3
-
-#define COEX_UNASSOC_IDLE_FLAGS                     0
-#define COEX_UNASSOC_MANUAL_SCAN_FLAGS		\
-	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
-	COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_UNASSOC_AUTO_SCAN_FLAGS		\
-	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
-	COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_CALIBRATION_FLAGS			\
-	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
-	COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_PERIODIC_CALIBRATION_FLAGS             0
-/*
- * COEX_CONNECTION_ESTAB:
- * we need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network.
- */
-#define COEX_CONNECTION_ESTAB_FLAGS		\
-	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
-	COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |	\
-	COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
-#define COEX_ASSOCIATED_IDLE_FLAGS                  0
-#define COEX_ASSOC_MANUAL_SCAN_FLAGS		\
-	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
-	COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_ASSOC_AUTO_SCAN_FLAGS		\
-	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
-	 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_ASSOC_ACTIVE_LEVEL_FLAGS               0
-#define COEX_RF_ON_FLAGS                            0
-#define COEX_RF_OFF_FLAGS                           0
-#define COEX_STAND_ALONE_DEBUG_FLAGS		\
-	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
-	 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_IPAN_ASSOC_LEVEL_FLAGS		\
-	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
-	 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |	\
-	 COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
-#define COEX_RSRVD1_FLAGS                           0
-#define COEX_RSRVD2_FLAGS                           0
-/*
- * COEX_CU_RF_ON is the event wrapping all radio ownership.
- * We need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network.
- */
-#define COEX_CU_RF_ON_FLAGS			\
-	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |	\
-	 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |	\
-	 COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
-
-
-enum {
-	/* un-association part */
-	COEX_UNASSOC_IDLE		= 0,
-	COEX_UNASSOC_MANUAL_SCAN	= 1,
-	COEX_UNASSOC_AUTO_SCAN		= 2,
-	/* calibration */
-	COEX_CALIBRATION		= 3,
-	COEX_PERIODIC_CALIBRATION	= 4,
-	/* connection */
-	COEX_CONNECTION_ESTAB		= 5,
-	/* association part */
-	COEX_ASSOCIATED_IDLE		= 6,
-	COEX_ASSOC_MANUAL_SCAN		= 7,
-	COEX_ASSOC_AUTO_SCAN		= 8,
-	COEX_ASSOC_ACTIVE_LEVEL		= 9,
-	/* RF ON/OFF */
-	COEX_RF_ON			= 10,
-	COEX_RF_OFF			= 11,
-	COEX_STAND_ALONE_DEBUG		= 12,
-	/* IPAN */
-	COEX_IPAN_ASSOC_LEVEL		= 13,
-	/* reserved */
-	COEX_RSRVD1			= 14,
-	COEX_RSRVD2			= 15,
-	COEX_NUM_OF_EVENTS		= 16
-};
-
-/*
- * Coexistence WIFI/WIMAX  Command
- * COEX_PRIORITY_TABLE_CMD = 0x5a
- *
- */
-struct iwl_wimax_coex_event_entry {
-	u8 request_prio;
-	u8 win_medium_prio;
-	u8 reserved;
-	u8 flags;
-} __packed;
-
-/* COEX flag masks */
-
-/* Station table is valid */
-#define COEX_FLAGS_STA_TABLE_VALID_MSK      (0x1)
-/* UnMask wake up src at unassociated sleep */
-#define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK    (0x4)
-/* UnMask wake up src at associated sleep */
-#define COEX_FLAGS_ASSOC_WA_UNMASK_MSK      (0x8)
-/* Enable CoEx feature. */
-#define COEX_FLAGS_COEX_ENABLE_MSK          (0x80)
-
-struct iwl_wimax_coex_cmd {
-	u8 flags;
-	u8 reserved[3];
-	struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS];
-} __packed;
-
-/*
- * Coexistence MEDIUM NOTIFICATION
- * COEX_MEDIUM_NOTIFICATION = 0x5b
- *
- * notification from uCode to host to indicate medium changes
- *
- */
-/*
- * status field
- * bit 0 - 2: medium status
- * bit 3: medium change indication
- * bit 4 - 31: reserved
- */
-/* status option values, (0 - 2 bits) */
-#define COEX_MEDIUM_BUSY	(0x0) /* radio belongs to WiMAX */
-#define COEX_MEDIUM_ACTIVE	(0x1) /* radio belongs to WiFi */
-#define COEX_MEDIUM_PRE_RELEASE	(0x2) /* received radio release */
-#define COEX_MEDIUM_MSK		(0x7)
-
-/* send notification status (1 bit) */
-#define COEX_MEDIUM_CHANGED	(0x8)
-#define COEX_MEDIUM_CHANGED_MSK	(0x8)
-#define COEX_MEDIUM_SHIFT	(3)
-
-struct iwl_coex_medium_notification {
-	__le32 status;
-	__le32 events;
-} __packed;
-
-/*
- * Coexistence EVENT  Command
- * COEX_EVENT_CMD = 0x5c
- *
- * send from host to uCode for coex event request.
- */
-/* flags options */
-#define COEX_EVENT_REQUEST_MSK	(0x1)
-
-struct iwl_coex_event_cmd {
-	u8 flags;
-	u8 event;
-	__le16 reserved;
-} __packed;
-
-struct iwl_coex_event_resp {
-	__le32 status;
-} __packed;
-
-
-/******************************************************************************
- * Bluetooth Coexistence commands
- *
- *****************************************************************************/
-
-/*
- * BT Status notification
- * REPLY_BT_COEX_PROFILE_NOTIF = 0xce
- */
-enum iwl_bt_coex_profile_traffic_load {
-	IWL_BT_COEX_TRAFFIC_LOAD_NONE = 	0,
-	IWL_BT_COEX_TRAFFIC_LOAD_LOW =		1,
-	IWL_BT_COEX_TRAFFIC_LOAD_HIGH = 	2,
-	IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS =	3,
-/*
- * There are no more even though below is a u8, the
- * indication from the BT device only has two bits.
- */
-};
-
-#define BT_SESSION_ACTIVITY_1_UART_MSG		0x1
-#define BT_SESSION_ACTIVITY_2_UART_MSG		0x2
-
-/* BT UART message - Share Part (BT -> WiFi) */
-#define BT_UART_MSG_FRAME1MSGTYPE_POS		(0)
-#define BT_UART_MSG_FRAME1MSGTYPE_MSK		\
-		(0x7 << BT_UART_MSG_FRAME1MSGTYPE_POS)
-#define BT_UART_MSG_FRAME1SSN_POS		(3)
-#define BT_UART_MSG_FRAME1SSN_MSK		\
-		(0x3 << BT_UART_MSG_FRAME1SSN_POS)
-#define BT_UART_MSG_FRAME1UPDATEREQ_POS		(5)
-#define BT_UART_MSG_FRAME1UPDATEREQ_MSK		\
-		(0x1 << BT_UART_MSG_FRAME1UPDATEREQ_POS)
-#define BT_UART_MSG_FRAME1RESERVED_POS		(6)
-#define BT_UART_MSG_FRAME1RESERVED_MSK		\
-		(0x3 << BT_UART_MSG_FRAME1RESERVED_POS)
-
-#define BT_UART_MSG_FRAME2OPENCONNECTIONS_POS	(0)
-#define BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK	\
-		(0x3 << BT_UART_MSG_FRAME2OPENCONNECTIONS_POS)
-#define BT_UART_MSG_FRAME2TRAFFICLOAD_POS	(2)
-#define BT_UART_MSG_FRAME2TRAFFICLOAD_MSK	\
-		(0x3 << BT_UART_MSG_FRAME2TRAFFICLOAD_POS)
-#define BT_UART_MSG_FRAME2CHLSEQN_POS		(4)
-#define BT_UART_MSG_FRAME2CHLSEQN_MSK		\
-		(0x1 << BT_UART_MSG_FRAME2CHLSEQN_POS)
-#define BT_UART_MSG_FRAME2INBAND_POS		(5)
-#define BT_UART_MSG_FRAME2INBAND_MSK		\
-		(0x1 << BT_UART_MSG_FRAME2INBAND_POS)
-#define BT_UART_MSG_FRAME2RESERVED_POS		(6)
-#define BT_UART_MSG_FRAME2RESERVED_MSK		\
-		(0x3 << BT_UART_MSG_FRAME2RESERVED_POS)
-
-#define BT_UART_MSG_FRAME3SCOESCO_POS		(0)
-#define BT_UART_MSG_FRAME3SCOESCO_MSK		\
-		(0x1 << BT_UART_MSG_FRAME3SCOESCO_POS)
-#define BT_UART_MSG_FRAME3SNIFF_POS		(1)
-#define BT_UART_MSG_FRAME3SNIFF_MSK		\
-		(0x1 << BT_UART_MSG_FRAME3SNIFF_POS)
-#define BT_UART_MSG_FRAME3A2DP_POS		(2)
-#define BT_UART_MSG_FRAME3A2DP_MSK		\
-		(0x1 << BT_UART_MSG_FRAME3A2DP_POS)
-#define BT_UART_MSG_FRAME3ACL_POS		(3)
-#define BT_UART_MSG_FRAME3ACL_MSK		\
-		(0x1 << BT_UART_MSG_FRAME3ACL_POS)
-#define BT_UART_MSG_FRAME3MASTER_POS		(4)
-#define BT_UART_MSG_FRAME3MASTER_MSK		\
-		(0x1 << BT_UART_MSG_FRAME3MASTER_POS)
-#define BT_UART_MSG_FRAME3OBEX_POS		(5)
-#define BT_UART_MSG_FRAME3OBEX_MSK		\
-		(0x1 << BT_UART_MSG_FRAME3OBEX_POS)
-#define BT_UART_MSG_FRAME3RESERVED_POS		(6)
-#define BT_UART_MSG_FRAME3RESERVED_MSK		\
-		(0x3 << BT_UART_MSG_FRAME3RESERVED_POS)
-
-#define BT_UART_MSG_FRAME4IDLEDURATION_POS	(0)
-#define BT_UART_MSG_FRAME4IDLEDURATION_MSK	\
-		(0x3F << BT_UART_MSG_FRAME4IDLEDURATION_POS)
-#define BT_UART_MSG_FRAME4RESERVED_POS		(6)
-#define BT_UART_MSG_FRAME4RESERVED_MSK		\
-		(0x3 << BT_UART_MSG_FRAME4RESERVED_POS)
-
-#define BT_UART_MSG_FRAME5TXACTIVITY_POS	(0)
-#define BT_UART_MSG_FRAME5TXACTIVITY_MSK	\
-		(0x3 << BT_UART_MSG_FRAME5TXACTIVITY_POS)
-#define BT_UART_MSG_FRAME5RXACTIVITY_POS	(2)
-#define BT_UART_MSG_FRAME5RXACTIVITY_MSK	\
-		(0x3 << BT_UART_MSG_FRAME5RXACTIVITY_POS)
-#define BT_UART_MSG_FRAME5ESCORETRANSMIT_POS	(4)
-#define BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK	\
-		(0x3 << BT_UART_MSG_FRAME5ESCORETRANSMIT_POS)
-#define BT_UART_MSG_FRAME5RESERVED_POS		(6)
-#define BT_UART_MSG_FRAME5RESERVED_MSK		\
-		(0x3 << BT_UART_MSG_FRAME5RESERVED_POS)
-
-#define BT_UART_MSG_FRAME6SNIFFINTERVAL_POS	(0)
-#define BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK	\
-		(0x1F << BT_UART_MSG_FRAME6SNIFFINTERVAL_POS)
-#define BT_UART_MSG_FRAME6DISCOVERABLE_POS	(5)
-#define BT_UART_MSG_FRAME6DISCOVERABLE_MSK	\
-		(0x1 << BT_UART_MSG_FRAME6DISCOVERABLE_POS)
-#define BT_UART_MSG_FRAME6RESERVED_POS		(6)
-#define BT_UART_MSG_FRAME6RESERVED_MSK		\
-		(0x3 << BT_UART_MSG_FRAME6RESERVED_POS)
-
-#define BT_UART_MSG_FRAME7SNIFFACTIVITY_POS	(0)
-#define BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK	\
-		(0x7 << BT_UART_MSG_FRAME7SNIFFACTIVITY_POS)
-#define BT_UART_MSG_FRAME7PAGE_POS		(3)
-#define BT_UART_MSG_FRAME7PAGE_MSK		\
-		(0x1 << BT_UART_MSG_FRAME7PAGE_POS)
-#define BT_UART_MSG_FRAME7INQUIRY_POS		(4)
-#define BT_UART_MSG_FRAME7INQUIRY_MSK		\
-		(0x1 << BT_UART_MSG_FRAME7INQUIRY_POS)
-#define BT_UART_MSG_FRAME7CONNECTABLE_POS	(5)
-#define BT_UART_MSG_FRAME7CONNECTABLE_MSK	\
-		(0x1 << BT_UART_MSG_FRAME7CONNECTABLE_POS)
-#define BT_UART_MSG_FRAME7RESERVED_POS		(6)
-#define BT_UART_MSG_FRAME7RESERVED_MSK		\
-		(0x3 << BT_UART_MSG_FRAME7RESERVED_POS)
-
-/* BT Session Activity 2 UART message (BT -> WiFi) */
-#define BT_UART_MSG_2_FRAME1RESERVED1_POS	(5)
-#define BT_UART_MSG_2_FRAME1RESERVED1_MSK	\
-		(0x1<<BT_UART_MSG_2_FRAME1RESERVED1_POS)
-#define BT_UART_MSG_2_FRAME1RESERVED2_POS	(6)
-#define BT_UART_MSG_2_FRAME1RESERVED2_MSK	\
-		(0x3<<BT_UART_MSG_2_FRAME1RESERVED2_POS)
-
-#define BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_POS	(0)
-#define BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_MSK	\
-		(0x3F<<BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_POS)
-#define BT_UART_MSG_2_FRAME2RESERVED_POS	(6)
-#define BT_UART_MSG_2_FRAME2RESERVED_MSK	\
-		(0x3<<BT_UART_MSG_2_FRAME2RESERVED_POS)
-
-#define BT_UART_MSG_2_FRAME3BRLASTTXPOWER_POS	(0)
-#define BT_UART_MSG_2_FRAME3BRLASTTXPOWER_MSK	\
-		(0xF<<BT_UART_MSG_2_FRAME3BRLASTTXPOWER_POS)
-#define BT_UART_MSG_2_FRAME3INQPAGESRMODE_POS	(4)
-#define BT_UART_MSG_2_FRAME3INQPAGESRMODE_MSK	\
-		(0x1<<BT_UART_MSG_2_FRAME3INQPAGESRMODE_POS)
-#define BT_UART_MSG_2_FRAME3LEMASTER_POS	(5)
-#define BT_UART_MSG_2_FRAME3LEMASTER_MSK	\
-		(0x1<<BT_UART_MSG_2_FRAME3LEMASTER_POS)
-#define BT_UART_MSG_2_FRAME3RESERVED_POS	(6)
-#define BT_UART_MSG_2_FRAME3RESERVED_MSK	\
-		(0x3<<BT_UART_MSG_2_FRAME3RESERVED_POS)
-
-#define BT_UART_MSG_2_FRAME4LELASTTXPOWER_POS	(0)
-#define BT_UART_MSG_2_FRAME4LELASTTXPOWER_MSK	\
-		(0xF<<BT_UART_MSG_2_FRAME4LELASTTXPOWER_POS)
-#define BT_UART_MSG_2_FRAME4NUMLECONN_POS	(4)
-#define BT_UART_MSG_2_FRAME4NUMLECONN_MSK	\
-		(0x3<<BT_UART_MSG_2_FRAME4NUMLECONN_POS)
-#define BT_UART_MSG_2_FRAME4RESERVED_POS	(6)
-#define BT_UART_MSG_2_FRAME4RESERVED_MSK	\
-		(0x3<<BT_UART_MSG_2_FRAME4RESERVED_POS)
-
-#define BT_UART_MSG_2_FRAME5BTMINRSSI_POS	(0)
-#define BT_UART_MSG_2_FRAME5BTMINRSSI_MSK	\
-		(0xF<<BT_UART_MSG_2_FRAME5BTMINRSSI_POS)
-#define BT_UART_MSG_2_FRAME5LESCANINITMODE_POS	(4)
-#define BT_UART_MSG_2_FRAME5LESCANINITMODE_MSK	\
-		(0x1<<BT_UART_MSG_2_FRAME5LESCANINITMODE_POS)
-#define BT_UART_MSG_2_FRAME5LEADVERMODE_POS	(5)
-#define BT_UART_MSG_2_FRAME5LEADVERMODE_MSK	\
-		(0x1<<BT_UART_MSG_2_FRAME5LEADVERMODE_POS)
-#define BT_UART_MSG_2_FRAME5RESERVED_POS	(6)
-#define BT_UART_MSG_2_FRAME5RESERVED_MSK	\
-		(0x3<<BT_UART_MSG_2_FRAME5RESERVED_POS)
-
-#define BT_UART_MSG_2_FRAME6LECONNINTERVAL_POS	(0)
-#define BT_UART_MSG_2_FRAME6LECONNINTERVAL_MSK	\
-		(0x1F<<BT_UART_MSG_2_FRAME6LECONNINTERVAL_POS)
-#define BT_UART_MSG_2_FRAME6RFU_POS		(5)
-#define BT_UART_MSG_2_FRAME6RFU_MSK		\
-		(0x1<<BT_UART_MSG_2_FRAME6RFU_POS)
-#define BT_UART_MSG_2_FRAME6RESERVED_POS	(6)
-#define BT_UART_MSG_2_FRAME6RESERVED_MSK	\
-		(0x3<<BT_UART_MSG_2_FRAME6RESERVED_POS)
-
-#define BT_UART_MSG_2_FRAME7LECONNSLAVELAT_POS	(0)
-#define BT_UART_MSG_2_FRAME7LECONNSLAVELAT_MSK	\
-		(0x7<<BT_UART_MSG_2_FRAME7LECONNSLAVELAT_POS)
-#define BT_UART_MSG_2_FRAME7LEPROFILE1_POS	(3)
-#define BT_UART_MSG_2_FRAME7LEPROFILE1_MSK	\
-		(0x1<<BT_UART_MSG_2_FRAME7LEPROFILE1_POS)
-#define BT_UART_MSG_2_FRAME7LEPROFILE2_POS	(4)
-#define BT_UART_MSG_2_FRAME7LEPROFILE2_MSK	\
-		(0x1<<BT_UART_MSG_2_FRAME7LEPROFILE2_POS)
-#define BT_UART_MSG_2_FRAME7LEPROFILEOTHER_POS	(5)
-#define BT_UART_MSG_2_FRAME7LEPROFILEOTHER_MSK	\
-		(0x1<<BT_UART_MSG_2_FRAME7LEPROFILEOTHER_POS)
-#define BT_UART_MSG_2_FRAME7RESERVED_POS	(6)
-#define BT_UART_MSG_2_FRAME7RESERVED_MSK	\
-		(0x3<<BT_UART_MSG_2_FRAME7RESERVED_POS)
-
-
-#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD	(-62)
-#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD	(-65)
-
-struct iwl_bt_uart_msg {
-	u8 header;
-	u8 frame1;
-	u8 frame2;
-	u8 frame3;
-	u8 frame4;
-	u8 frame5;
-	u8 frame6;
-	u8 frame7;
-} __attribute__((packed));
-
-struct iwl_bt_coex_profile_notif {
-	struct iwl_bt_uart_msg last_bt_uart_msg;
-	u8 bt_status; /* 0 - off, 1 - on */
-	u8 bt_traffic_load; /* 0 .. 3? */
-	u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
-	u8 reserved;
-} __attribute__((packed));
-
-#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS	0
-#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK	0x1
-#define IWL_BT_COEX_PRIO_TBL_PRIO_POS		1
-#define IWL_BT_COEX_PRIO_TBL_PRIO_MASK		0x0e
-#define IWL_BT_COEX_PRIO_TBL_RESERVED_POS	4
-#define IWL_BT_COEX_PRIO_TBL_RESERVED_MASK	0xf0
-#define IWL_BT_COEX_PRIO_TBL_PRIO_SHIFT		1
-
-/*
- * BT Coexistence Priority table
- * REPLY_BT_COEX_PRIO_TABLE = 0xcc
- */
-enum bt_coex_prio_table_events {
-	BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0,
-	BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1,
-	BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2,
-	BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3, /* DC calib */
-	BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4,
-	BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5,
-	BT_COEX_PRIO_TBL_EVT_DTIM = 6,
-	BT_COEX_PRIO_TBL_EVT_SCAN52 = 7,
-	BT_COEX_PRIO_TBL_EVT_SCAN24 = 8,
-	BT_COEX_PRIO_TBL_EVT_RESERVED0 = 9,
-	BT_COEX_PRIO_TBL_EVT_RESERVED1 = 10,
-	BT_COEX_PRIO_TBL_EVT_RESERVED2 = 11,
-	BT_COEX_PRIO_TBL_EVT_RESERVED3 = 12,
-	BT_COEX_PRIO_TBL_EVT_RESERVED4 = 13,
-	BT_COEX_PRIO_TBL_EVT_RESERVED5 = 14,
-	BT_COEX_PRIO_TBL_EVT_RESERVED6 = 15,
-	/* BT_COEX_PRIO_TBL_EVT_MAX should always be last */
-	BT_COEX_PRIO_TBL_EVT_MAX,
-};
-
-enum bt_coex_prio_table_priorities {
-	BT_COEX_PRIO_TBL_DISABLED = 0,
-	BT_COEX_PRIO_TBL_PRIO_LOW = 1,
-	BT_COEX_PRIO_TBL_PRIO_HIGH = 2,
-	BT_COEX_PRIO_TBL_PRIO_BYPASS = 3,
-	BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4,
-	BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5,
-	BT_COEX_PRIO_TBL_PRIO_RSRVD1 = 6,
-	BT_COEX_PRIO_TBL_PRIO_RSRVD2 = 7,
-	BT_COEX_PRIO_TBL_MAX,
-};
-
-struct iwl_bt_coex_prio_table_cmd {
-	u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
-} __attribute__((packed));
-
-#define IWL_BT_COEX_ENV_CLOSE	0
-#define IWL_BT_COEX_ENV_OPEN	1
-/*
- * BT Protection Envelope
- * REPLY_BT_COEX_PROT_ENV = 0xcd
- */
-struct iwl_bt_coex_prot_env_cmd {
-	u8 action; /* 0 = closed, 1 = open */
-	u8 type; /* 0 .. 15 */
-	u8 reserved[2];
-} __attribute__((packed));
-
-/*
- * REPLY_D3_CONFIG
- */
-enum iwlagn_d3_wakeup_filters {
-	IWLAGN_D3_WAKEUP_RFKILL		= BIT(0),
-	IWLAGN_D3_WAKEUP_SYSASSERT	= BIT(1),
-};
-
-struct iwlagn_d3_config_cmd {
-	__le32 min_sleep_time;
-	__le32 wakeup_flags;
-} __packed;
-
-/*
- * REPLY_WOWLAN_PATTERNS
- */
-#define IWLAGN_WOWLAN_MIN_PATTERN_LEN	16
-#define IWLAGN_WOWLAN_MAX_PATTERN_LEN	128
-
-struct iwlagn_wowlan_pattern {
-	u8 mask[IWLAGN_WOWLAN_MAX_PATTERN_LEN / 8];
-	u8 pattern[IWLAGN_WOWLAN_MAX_PATTERN_LEN];
-	u8 mask_size;
-	u8 pattern_size;
-	__le16 reserved;
-} __packed;
-
-#define IWLAGN_WOWLAN_MAX_PATTERNS	20
-
-struct iwlagn_wowlan_patterns_cmd {
-	__le32 n_patterns;
-	struct iwlagn_wowlan_pattern patterns[];
-} __packed;
-
-/*
- * REPLY_WOWLAN_WAKEUP_FILTER
- */
-enum iwlagn_wowlan_wakeup_filters {
-	IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET	= BIT(0),
-	IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH	= BIT(1),
-	IWLAGN_WOWLAN_WAKEUP_BEACON_MISS	= BIT(2),
-	IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE	= BIT(3),
-	IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL	= BIT(4),
-	IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ	= BIT(5),
-	IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE	= BIT(6),
-	IWLAGN_WOWLAN_WAKEUP_ALWAYS		= BIT(7),
-	IWLAGN_WOWLAN_WAKEUP_ENABLE_NET_DETECT	= BIT(8),
-};
-
-struct iwlagn_wowlan_wakeup_filter_cmd {
-	__le32 enabled;
-	__le16 non_qos_seq;
-	__le16 reserved;
-	__le16 qos_seq[8];
-};
-
-/*
- * REPLY_WOWLAN_TSC_RSC_PARAMS
- */
-#define IWLAGN_NUM_RSC	16
-
-struct tkip_sc {
-	__le16 iv16;
-	__le16 pad;
-	__le32 iv32;
-} __packed;
-
-struct iwlagn_tkip_rsc_tsc {
-	struct tkip_sc unicast_rsc[IWLAGN_NUM_RSC];
-	struct tkip_sc multicast_rsc[IWLAGN_NUM_RSC];
-	struct tkip_sc tsc;
-} __packed;
-
-struct aes_sc {
-	__le64 pn;
-} __packed;
-
-struct iwlagn_aes_rsc_tsc {
-	struct aes_sc unicast_rsc[IWLAGN_NUM_RSC];
-	struct aes_sc multicast_rsc[IWLAGN_NUM_RSC];
-	struct aes_sc tsc;
-} __packed;
-
-union iwlagn_all_tsc_rsc {
-	struct iwlagn_tkip_rsc_tsc tkip;
-	struct iwlagn_aes_rsc_tsc aes;
-};
-
-struct iwlagn_wowlan_rsc_tsc_params_cmd {
-	union iwlagn_all_tsc_rsc all_tsc_rsc;
-} __packed;
-
-/*
- * REPLY_WOWLAN_TKIP_PARAMS
- */
-#define IWLAGN_MIC_KEY_SIZE	8
-#define IWLAGN_P1K_SIZE		5
-struct iwlagn_mic_keys {
-	u8 tx[IWLAGN_MIC_KEY_SIZE];
-	u8 rx_unicast[IWLAGN_MIC_KEY_SIZE];
-	u8 rx_mcast[IWLAGN_MIC_KEY_SIZE];
-} __packed;
-
-struct iwlagn_p1k_cache {
-	__le16 p1k[IWLAGN_P1K_SIZE];
-} __packed;
-
-#define IWLAGN_NUM_RX_P1K_CACHE	2
-
-struct iwlagn_wowlan_tkip_params_cmd {
-	struct iwlagn_mic_keys mic_keys;
-	struct iwlagn_p1k_cache tx;
-	struct iwlagn_p1k_cache rx_uni[IWLAGN_NUM_RX_P1K_CACHE];
-	struct iwlagn_p1k_cache rx_multi[IWLAGN_NUM_RX_P1K_CACHE];
-} __packed;
-
-/*
- * REPLY_WOWLAN_KEK_KCK_MATERIAL
- */
-
-#define IWLAGN_KCK_MAX_SIZE	32
-#define IWLAGN_KEK_MAX_SIZE	32
-
-struct iwlagn_wowlan_kek_kck_material_cmd {
-	u8	kck[IWLAGN_KCK_MAX_SIZE];
-	u8	kek[IWLAGN_KEK_MAX_SIZE];
-	__le16	kck_len;
-	__le16	kek_len;
-	__le64	replay_ctr;
-} __packed;
-
-/*
- * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
- */
-
-/*
- * Minimum slot time in TU
- */
-#define IWL_MIN_SLOT_TIME	20
-
-/**
- * struct iwl_wipan_slot
- * @width: Time in TU
- * @type:
- *   0 - BSS
- *   1 - PAN
- */
-struct iwl_wipan_slot {
-	__le16 width;
-	u8 type;
-	u8 reserved;
-} __packed;
-
-#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_CTS		BIT(1)	/* reserved */
-#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_QUIET	BIT(2)	/* reserved */
-#define IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE		BIT(3)	/* reserved */
-#define IWL_WIPAN_PARAMS_FLG_FILTER_BEACON_NOTIF	BIT(4)
-#define IWL_WIPAN_PARAMS_FLG_FULL_SLOTTED_MODE		BIT(5)
-
-/**
- * struct iwl_wipan_params_cmd
- * @flags:
- *   bit0: reserved
- *   bit1: CP leave channel with CTS
- *   bit2: CP leave channel qith Quiet
- *   bit3: slotted mode
- *     1 - work in slotted mode
- *     0 - work in non slotted mode
- *   bit4: filter beacon notification
- *   bit5: full tx slotted mode. if this flag is set,
- *         uCode will perform leaving channel methods in context switch
- *         also when working in same channel mode
- * @num_slots: 1 - 10
- */
-struct iwl_wipan_params_cmd {
-	__le16 flags;
-	u8 reserved;
-	u8 num_slots;
-	struct iwl_wipan_slot slots[10];
-} __packed;
-
-/*
- * REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9
- *
- * TODO: Figure out what this is used for,
- *	 it can only switch between 2.4 GHz
- *	 channels!!
- */
-
-struct iwl_wipan_p2p_channel_switch_cmd {
-	__le16 channel;
-	__le16 reserved;
-};
-
-/*
- * REPLY_WIPAN_NOA_NOTIFICATION = 0xbc
- *
- * This is used by the device to notify us of the
- * NoA schedule it determined so we can forward it
- * to userspace for inclusion in probe responses.
- *
- * In beacons, the NoA schedule is simply appended
- * to the frame we give the device.
- */
-
-struct iwl_wipan_noa_descriptor {
-	u8 count;
-	__le32 duration;
-	__le32 interval;
-	__le32 starttime;
-} __packed;
-
-struct iwl_wipan_noa_attribute {
-	u8 id;
-	__le16 length;
-	u8 index;
-	u8 ct_window;
-	struct iwl_wipan_noa_descriptor descr0, descr1;
-	u8 reserved;
-} __packed;
-
-struct iwl_wipan_noa_notification {
-	u32 noa_active;
-	struct iwl_wipan_noa_attribute noa_attribute;
-} __packed;
-
-#endif				/* __iwl_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 67b28aa..10e4793 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -113,7 +113,7 @@ enum iwl_led_mode {
 #define IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE	0
 
 /* TX queue watchdog timeouts in mSecs */
-#define IWL_WATCHHDOG_DISABLED	0
+#define IWL_WATCHDOG_DISABLED	0
 #define IWL_DEF_WD_TIMEOUT	2000
 #define IWL_LONG_WD_TIMEOUT	10000
 #define IWL_MAX_WD_TIMEOUT	120000
@@ -143,7 +143,7 @@ enum iwl_led_mode {
  * @chain_noise_scale: default chain noise scale used for gain computation
  * @wd_timeout: TX queues watchdog timeout
  * @max_event_log_size: size of event log buffer size for ucode event logging
- * @shadow_reg_enable: HW shadhow register bit
+ * @shadow_reg_enable: HW shadow register support
  * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
  * @no_idle_support: do not support idle mode
  */
@@ -182,13 +182,34 @@ struct iwl_bt_params {
 	bool bt_sco_disable;
 	bool bt_session_2;
 };
+
 /*
  * @use_rts_for_aggregation: use rts/cts protection for HT traffic
+ * @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
  */
 struct iwl_ht_params {
+	enum ieee80211_smps_mode smps_mode;
 	const bool ht_greenfield_support; /* if used set to true */
 	bool use_rts_for_aggregation;
-	enum ieee80211_smps_mode smps_mode;
+	u8 ht40_bands;
+};
+
+/*
+ * information on how to parse the EEPROM
+ */
+#define EEPROM_REG_BAND_1_CHANNELS		0x08
+#define EEPROM_REG_BAND_2_CHANNELS		0x26
+#define EEPROM_REG_BAND_3_CHANNELS		0x42
+#define EEPROM_REG_BAND_4_CHANNELS		0x5C
+#define EEPROM_REG_BAND_5_CHANNELS		0x74
+#define EEPROM_REG_BAND_24_HT40_CHANNELS	0x82
+#define EEPROM_REG_BAND_52_HT40_CHANNELS	0x92
+#define EEPROM_6000_REG_BAND_24_HT40_CHANNELS	0x80
+#define EEPROM_REGULATORY_BAND_NO_HT40		0
+
+struct iwl_eeprom_params {
+	const u8 regulatory_bands[7];
+	bool enhanced_txpower;
 };
 
 /**
@@ -243,6 +264,7 @@ struct iwl_cfg {
 	/* params likely to change within a device family */
 	const struct iwl_ht_params *ht_params;
 	const struct iwl_bt_params *bt_params;
+	const struct iwl_eeprom_params *eeprom_params;
 	const bool need_temp_offset_calib; /* if used set to true */
 	const bool no_xtal_calib;
 	enum iwl_led_mode led_mode;
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 5975054..34a5287 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -97,13 +97,10 @@
 /*
  * Hardware revision info
  * Bit fields:
- * 31-8:  Reserved
- *  7-4:  Type of device:  see CSR_HW_REV_TYPE_xxx definitions
+ * 31-16:  Reserved
+ *  15-4:  Type of device:  see CSR_HW_REV_TYPE_xxx definitions
  *  3-2:  Revision step:  0 = A, 1 = B, 2 = C, 3 = D
  *  1-0:  "Dash" (-) value, as in A-1, etc.
- *
- * NOTE:  Revision step affects calculation of CCK txpower for 4965.
- * NOTE:  See also CSR_HW_REV_WA_REG (work-around for bug in 4965).
  */
 #define CSR_HW_REV              (CSR_BASE+0x028)
 
@@ -155,9 +152,21 @@
 #define CSR_DBG_LINK_PWR_MGMT_REG	(CSR_BASE+0x250)
 
 /* Bits for CSR_HW_IF_CONFIG_REG */
-#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER	(0x00000C00)
-#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI 	(0x00000100)
+#define CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH	(0x00000003)
+#define CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP	(0x0000000C)
+#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER	(0x000000C0)
+#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI		(0x00000100)
 #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI	(0x00000200)
+#define CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE	(0x00000C00)
+#define CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH	(0x00003000)
+#define CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP	(0x0000C000)
+
+#define CSR_HW_IF_CONFIG_REG_POS_MAC_DASH	(0)
+#define CSR_HW_IF_CONFIG_REG_POS_MAC_STEP	(2)
+#define CSR_HW_IF_CONFIG_REG_POS_BOARD_VER	(6)
+#define CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE	(10)
+#define CSR_HW_IF_CONFIG_REG_POS_PHY_DASH	(12)
+#define CSR_HW_IF_CONFIG_REG_POS_PHY_STEP	(14)
 
 #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A	(0x00080000)
 #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM	(0x00200000)
@@ -270,7 +279,10 @@
 
 
 /* HW REV */
-#define CSR_HW_REV_TYPE_MSK            (0x00001F0)
+#define CSR_HW_REV_DASH(_val)          (((_val) & 0x0000003) >> 0)
+#define CSR_HW_REV_STEP(_val)          (((_val) & 0x000000C) >> 2)
+
+#define CSR_HW_REV_TYPE_MSK            (0x000FFF0)
 #define CSR_HW_REV_TYPE_5300           (0x0000020)
 #define CSR_HW_REV_TYPE_5350           (0x0000030)
 #define CSR_HW_REV_TYPE_5100           (0x0000050)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.c b/drivers/net/wireless/iwlwifi/iwl-debug.c
index 2d1b428..0f8fcd1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.c
@@ -62,6 +62,7 @@
  *****************************************************************************/
 
 #include <linux/interrupt.h>
+#include <linux/export.h>
 #include "iwl-debug.h"
 #include "iwl-devtrace.h"
 
@@ -81,8 +82,11 @@ void __iwl_ ##fn(struct device *dev, const char *fmt, ...)	\
 }
 
 __iwl_fn(warn)
+EXPORT_SYMBOL_GPL(__iwl_warn);
 __iwl_fn(info)
+EXPORT_SYMBOL_GPL(__iwl_info);
 __iwl_fn(crit)
+EXPORT_SYMBOL_GPL(__iwl_crit);
 
 void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
 		const char *fmt, ...)
@@ -103,6 +107,7 @@ void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
 	trace_iwlwifi_err(&vaf);
 	va_end(args);
 }
+EXPORT_SYMBOL_GPL(__iwl_err);
 
 #if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
 void __iwl_dbg(struct device *dev,
@@ -125,4 +130,5 @@ void __iwl_dbg(struct device *dev,
 	trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf);
 	va_end(args);
 }
+EXPORT_SYMBOL_GPL(__iwl_dbg);
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 8376b84..42b20b0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -38,13 +38,14 @@ static inline bool iwl_have_debug_level(u32 level)
 }
 
 void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace,
-		const char *fmt, ...);
-void __iwl_warn(struct device *dev, const char *fmt, ...);
-void __iwl_info(struct device *dev, const char *fmt, ...);
-void __iwl_crit(struct device *dev, const char *fmt, ...);
+		const char *fmt, ...) __printf(4, 5);
+void __iwl_warn(struct device *dev, const char *fmt, ...) __printf(2, 3);
+void __iwl_info(struct device *dev, const char *fmt, ...) __printf(2, 3);
+void __iwl_crit(struct device *dev, const char *fmt, ...) __printf(2, 3);
 
 /* No matter what is m (priv, bus, trans), this will work */
 #define IWL_ERR(m, f, a...) __iwl_err((m)->dev, false, false, f, ## a)
+#define IWL_ERR_DEV(d, f, a...) __iwl_err((d), false, false, f, ## a)
 #define IWL_WARN(m, f, a...) __iwl_warn((m)->dev, f, ## a)
 #define IWL_INFO(m, f, a...) __iwl_info((m)->dev, f, ## a)
 #define IWL_CRIT(m, f, a...) __iwl_crit((m)->dev, f, ## a)
@@ -52,9 +53,9 @@ void __iwl_crit(struct device *dev, const char *fmt, ...);
 #if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
 void __iwl_dbg(struct device *dev,
 	       u32 level, bool limit, const char *function,
-	       const char *fmt, ...);
+	       const char *fmt, ...) __printf(5, 6);
 #else
-static inline void
+__printf(5, 6) static inline void
 __iwl_dbg(struct device *dev,
 	  u32 level, bool limit, const char *function,
 	  const char *fmt, ...)
@@ -69,6 +70,8 @@ do {									\
 
 #define IWL_DEBUG(m, level, fmt, args...)				\
 	__iwl_dbg((m)->dev, level, false, __func__, fmt, ##args)
+#define IWL_DEBUG_DEV(dev, level, fmt, args...)				\
+	__iwl_dbg((dev), level, false, __func__, fmt, ##args)
 #define IWL_DEBUG_LIMIT(m, level, fmt, args...)				\
 	__iwl_dbg((m)->dev, level, true, __func__, fmt, ##args)
 
@@ -153,7 +156,7 @@ do {                                            			\
 #define IWL_DEBUG_LED(p, f, a...)	IWL_DEBUG(p, IWL_DL_LED, f, ## a)
 #define IWL_DEBUG_WEP(p, f, a...)	IWL_DEBUG(p, IWL_DL_WEP, f, ## a)
 #define IWL_DEBUG_HC(p, f, a...)	IWL_DEBUG(p, IWL_DL_HCMD, f, ## a)
-#define IWL_DEBUG_EEPROM(p, f, a...)	IWL_DEBUG(p, IWL_DL_EEPROM, f, ## a)
+#define IWL_DEBUG_EEPROM(d, f, a...)	IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a)
 #define IWL_DEBUG_CALIB(p, f, a...)	IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
 #define IWL_DEBUG_FW(p, f, a...)	IWL_DEBUG(p, IWL_DL_FW, f, ## a)
 #define IWL_DEBUG_RF_KILL(p, f, a...)	IWL_DEBUG(p, IWL_DL_RF_KILL, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
deleted file mode 100644
index e7c157e..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ /dev/null
@@ -1,2437 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-
-#include <linux/ieee80211.h>
-#include <net/mac80211.h>
-
-
-#include "iwl-dev.h"
-#include "iwl-debug.h"
-#include "iwl-io.h"
-#include "iwl-agn.h"
-#include "iwl-modparams.h"
-
-/* create and remove of files */
-#define DEBUGFS_ADD_FILE(name, parent, mode) do {			\
-	if (!debugfs_create_file(#name, mode, parent, priv,		\
-				 &iwl_dbgfs_##name##_ops))		\
-		goto err;						\
-} while (0)
-
-#define DEBUGFS_ADD_BOOL(name, parent, ptr) do {			\
-	struct dentry *__tmp;						\
-	__tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR,		\
-				    parent, ptr);			\
-	if (IS_ERR(__tmp) || !__tmp)					\
-		goto err;						\
-} while (0)
-
-#define DEBUGFS_ADD_X32(name, parent, ptr) do {				\
-	struct dentry *__tmp;						\
-	__tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR,		\
-				   parent, ptr);			\
-	if (IS_ERR(__tmp) || !__tmp)					\
-		goto err;						\
-} while (0)
-
-#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do {			\
-	struct dentry *__tmp;						\
-	__tmp = debugfs_create_u32(#name, mode,				\
-				   parent, ptr);			\
-	if (IS_ERR(__tmp) || !__tmp)					\
-		goto err;						\
-} while (0)
-
-/* file operation */
-#define DEBUGFS_READ_FUNC(name)                                         \
-static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
-					char __user *user_buf,          \
-					size_t count, loff_t *ppos);
-
-#define DEBUGFS_WRITE_FUNC(name)                                        \
-static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
-					const char __user *user_buf,    \
-					size_t count, loff_t *ppos);
-
-
-#define DEBUGFS_READ_FILE_OPS(name)                                     \
-	DEBUGFS_READ_FUNC(name);                                        \
-static const struct file_operations iwl_dbgfs_##name##_ops = {          \
-	.read = iwl_dbgfs_##name##_read,                       		\
-	.open = simple_open,						\
-	.llseek = generic_file_llseek,					\
-};
-
-#define DEBUGFS_WRITE_FILE_OPS(name)                                    \
-	DEBUGFS_WRITE_FUNC(name);                                       \
-static const struct file_operations iwl_dbgfs_##name##_ops = {          \
-	.write = iwl_dbgfs_##name##_write,                              \
-	.open = simple_open,						\
-	.llseek = generic_file_llseek,					\
-};
-
-
-#define DEBUGFS_READ_WRITE_FILE_OPS(name)                               \
-	DEBUGFS_READ_FUNC(name);                                        \
-	DEBUGFS_WRITE_FUNC(name);                                       \
-static const struct file_operations iwl_dbgfs_##name##_ops = {          \
-	.write = iwl_dbgfs_##name##_write,                              \
-	.read = iwl_dbgfs_##name##_read,                                \
-	.open = simple_open,						\
-	.llseek = generic_file_llseek,					\
-};
-
-static ssize_t iwl_dbgfs_sram_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos)
-{
-	u32 val = 0;
-	char *buf;
-	ssize_t ret;
-	int i = 0;
-	bool device_format = false;
-	int offset = 0;
-	int len = 0;
-	int pos = 0;
-	int sram;
-	struct iwl_priv *priv = file->private_data;
-	const struct fw_img *img;
-	size_t bufsz;
-
-	/* default is to dump the entire data segment */
-	if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
-		priv->dbgfs_sram_offset = 0x800000;
-		if (!priv->ucode_loaded)
-			return -EINVAL;
-		img = &priv->fw->img[priv->cur_ucode];
-		priv->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
-	}
-	len = priv->dbgfs_sram_len;
-
-	if (len == -4) {
-		device_format = true;
-		len = 4;
-	}
-
-	bufsz =  50 + len * 4;
-	buf = kmalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
-			 len);
-	pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
-			priv->dbgfs_sram_offset);
-
-	/* adjust sram address since reads are only on even u32 boundaries */
-	offset = priv->dbgfs_sram_offset & 0x3;
-	sram = priv->dbgfs_sram_offset & ~0x3;
-
-	/* read the first u32 from sram */
-	val = iwl_read_targ_mem(priv->trans, sram);
-
-	for (; len; len--) {
-		/* put the address at the start of every line */
-		if (i == 0)
-			pos += scnprintf(buf + pos, bufsz - pos,
-				"%08X: ", sram + offset);
-
-		if (device_format)
-			pos += scnprintf(buf + pos, bufsz - pos,
-				"%02x", (val >> (8 * (3 - offset))) & 0xff);
-		else
-			pos += scnprintf(buf + pos, bufsz - pos,
-				"%02x ", (val >> (8 * offset)) & 0xff);
-
-		/* if all bytes processed, read the next u32 from sram */
-		if (++offset == 4) {
-			sram += 4;
-			offset = 0;
-			val = iwl_read_targ_mem(priv->trans, sram);
-		}
-
-		/* put in extra spaces and split lines for human readability */
-		if (++i == 16) {
-			i = 0;
-			pos += scnprintf(buf + pos, bufsz - pos, "\n");
-		} else if (!(i & 7)) {
-			pos += scnprintf(buf + pos, bufsz - pos, "   ");
-		} else if (!(i & 3)) {
-			pos += scnprintf(buf + pos, bufsz - pos, " ");
-		}
-	}
-	if (i)
-		pos += scnprintf(buf + pos, bufsz - pos, "\n");
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_sram_write(struct file *file,
-					const char __user *user_buf,
-					size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	char buf[64];
-	int buf_size;
-	u32 offset, len;
-
-	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, "%x,%x", &offset, &len) == 2) {
-		priv->dbgfs_sram_offset = offset;
-		priv->dbgfs_sram_len = len;
-	} else if (sscanf(buf, "%x", &offset) == 1) {
-		priv->dbgfs_sram_offset = offset;
-		priv->dbgfs_sram_len = -4;
-	} else {
-		priv->dbgfs_sram_offset = 0;
-		priv->dbgfs_sram_len = 0;
-	}
-
-	return count;
-}
-
-static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file,
-					  char __user *user_buf,
-					  size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	const struct fw_img *img = &priv->fw->img[IWL_UCODE_WOWLAN];
-
-	if (!priv->wowlan_sram)
-		return -ENODATA;
-
-	return simple_read_from_buffer(user_buf, count, ppos,
-				       priv->wowlan_sram,
-				       img->sec[IWL_UCODE_SECTION_DATA].len);
-}
-static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
-					size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	struct iwl_station_entry *station;
-	struct iwl_tid_data *tid_data;
-	char *buf;
-	int i, j, pos = 0;
-	ssize_t ret;
-	/* Add 30 for initial string */
-	const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
-
-	buf = kmalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
-			priv->num_stations);
-
-	for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
-		station = &priv->stations[i];
-		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 seqno  next_rclmd "
-				"rate_n_flags state txq\n");
-
-		for (j = 0; j < IWL_MAX_TID_COUNT; j++) {
-			tid_data = &priv->tid_data[i][j];
-			pos += scnprintf(buf + pos, bufsz - pos,
-				"%d:  0x%.4x 0x%.4x     0x%.8x   "
-				"%d     %.2d",
-				j, tid_data->seq_number,
-				tid_data->next_reclaimed,
-				tid_data->agg.rate_n_flags,
-				tid_data->agg.state,
-				tid_data->agg.txq_id);
-
-			if (tid_data->agg.wait_for_ba)
-				pos += scnprintf(buf + pos, bufsz - pos,
-						 " - 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);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_nvm_read(struct file *file,
-				       char __user *user_buf,
-				       size_t count,
-				       loff_t *ppos)
-{
-	ssize_t ret;
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0, ofs = 0, buf_size = 0;
-	const u8 *ptr;
-	char *buf;
-	u16 eeprom_ver;
-	size_t eeprom_len = priv->cfg->base_params->eeprom_size;
-	buf_size = 4 * eeprom_len + 256;
-
-	if (eeprom_len % 16)
-		return -ENODATA;
-
-	ptr = priv->eeprom;
-	if (!ptr)
-		return -ENOMEM;
-
-	/* 4 characters for byte 0xYY */
-	buf = kzalloc(buf_size, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-	pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, "
-			"version: 0x%x\n",
-			(priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
-			 ? "OTP" : "EEPROM", eeprom_ver);
-	for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
-		pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
-		hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
-				   buf_size - pos, 0);
-		pos += strlen(buf + pos);
-		if (buf_size - pos > 0)
-			buf[pos++] = '\n';
-	}
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
-				       size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	struct ieee80211_channel *channels = NULL;
-	const struct ieee80211_supported_band *supp_band = NULL;
-	int pos = 0, i, bufsz = PAGE_SIZE;
-	char *buf;
-	ssize_t ret;
-
-	if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
-		return -EAGAIN;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
-	if (supp_band) {
-		channels = supp_band->channels;
-
-		pos += scnprintf(buf + pos, bufsz - pos,
-				"Displaying %d channels in 2.4GHz band 802.11bg):\n",
-				supp_band->n_channels);
-
-		for (i = 0; i < supp_band->n_channels; i++)
-			pos += scnprintf(buf + pos, bufsz - pos,
-					"%d: %ddBm: BSS%s%s, %s.\n",
-					channels[i].hw_value,
-					channels[i].max_power,
-					channels[i].flags & IEEE80211_CHAN_RADAR ?
-					" (IEEE 802.11h required)" : "",
-					((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
-					|| (channels[i].flags &
-					IEEE80211_CHAN_RADAR)) ? "" :
-					", IBSS",
-					channels[i].flags &
-					IEEE80211_CHAN_PASSIVE_SCAN ?
-					"passive only" : "active/passive");
-	}
-	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
-	if (supp_band) {
-		channels = supp_band->channels;
-
-		pos += scnprintf(buf + pos, bufsz - pos,
-				"Displaying %d channels in 5.2GHz band (802.11a)\n",
-				supp_band->n_channels);
-
-		for (i = 0; i < supp_band->n_channels; i++)
-			pos += scnprintf(buf + pos, bufsz - pos,
-					"%d: %ddBm: BSS%s%s, %s.\n",
-					channels[i].hw_value,
-					channels[i].max_power,
-					channels[i].flags & IEEE80211_CHAN_RADAR ?
-					" (IEEE 802.11h required)" : "",
-					((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
-					|| (channels[i].flags &
-					IEEE80211_CHAN_RADAR)) ? "" :
-					", IBSS",
-					channels[i].flags &
-					IEEE80211_CHAN_PASSIVE_SCAN ?
-					"passive only" : "active/passive");
-	}
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_status_read(struct file *file,
-						char __user *user_buf,
-						size_t count, loff_t *ppos) {
-
-	struct iwl_priv *priv = file->private_data;
-	char buf[512];
-	int pos = 0;
-	const size_t bufsz = sizeof(buf);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
-		test_bit(STATUS_RF_KILL_HW, &priv->status));
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
-		test_bit(STATUS_CT_KILL, &priv->status));
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
-		test_bit(STATUS_ALIVE, &priv->status));
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
-		test_bit(STATUS_READY, &priv->status));
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n",
-		test_bit(STATUS_GEO_CONFIGURED, &priv->status));
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
-		test_bit(STATUS_EXIT_PENDING, &priv->status));
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
-		test_bit(STATUS_STATISTICS, &priv->status));
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
-		test_bit(STATUS_SCANNING, &priv->status));
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
-		test_bit(STATUS_SCAN_ABORTING, &priv->status));
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
-		test_bit(STATUS_SCAN_HW, &priv->status));
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
-		test_bit(STATUS_POWER_PMI, &priv->status));
-	pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
-		test_bit(STATUS_FW_ERROR, &priv->status));
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_rx_handlers_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos) {
-
-	struct iwl_priv *priv = file->private_data;
-
-	int pos = 0;
-	int cnt = 0;
-	char *buf;
-	int bufsz = 24 * 64; /* 24 items * 64 char per item */
-	ssize_t ret;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	for (cnt = 0; cnt < REPLY_MAX; cnt++) {
-		if (priv->rx_handlers_stats[cnt] > 0)
-			pos += scnprintf(buf + pos, bufsz - pos,
-				"\tRx handler[%36s]:\t\t %u\n",
-				iwl_dvm_get_cmd_string(cnt),
-				priv->rx_handlers_stats[cnt]);
-	}
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_rx_handlers_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;
-	u32 reset_flag;
-
-	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, "%x", &reset_flag) != 1)
-		return -EFAULT;
-	if (reset_flag == 0)
-		memset(&priv->rx_handlers_stats[0], 0,
-			sizeof(priv->rx_handlers_stats));
-
-	return count;
-}
-
-static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
-				       size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	struct iwl_rxon_context *ctx;
-	int pos = 0, i;
-	char buf[256 * NUM_IWL_RXON_CTX];
-	const size_t bufsz = sizeof(buf);
-
-	for_each_context(priv, ctx) {
-		pos += scnprintf(buf + pos, bufsz - pos, "context %d:\n",
-				 ctx->ctxid);
-		for (i = 0; i < AC_NUM; i++) {
-			pos += scnprintf(buf + pos, bufsz - pos,
-				"\tcw_min\tcw_max\taifsn\ttxop\n");
-			pos += scnprintf(buf + pos, bufsz - pos,
-				"AC[%d]\t%u\t%u\t%u\t%u\n", i,
-				ctx->qos_data.def_qos_parm.ac[i].cw_min,
-				ctx->qos_data.def_qos_parm.ac[i].cw_max,
-				ctx->qos_data.def_qos_parm.ac[i].aifsn,
-				ctx->qos_data.def_qos_parm.ac[i].edca_txop);
-		}
-		pos += scnprintf(buf + pos, bufsz - pos, "\n");
-	}
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
-				char __user *user_buf,
-				size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-	struct iwl_tt_restriction *restriction;
-	char buf[100];
-	int pos = 0;
-	const size_t bufsz = sizeof(buf);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"Thermal Throttling Mode: %s\n",
-			tt->advanced_tt ? "Advance" : "Legacy");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"Thermal Throttling State: %d\n",
-			tt->state);
-	if (tt->advanced_tt) {
-		restriction = tt->restriction + tt->state;
-		pos += scnprintf(buf + pos, bufsz - pos,
-				"Tx mode: %d\n",
-				restriction->tx_stream);
-		pos += scnprintf(buf + pos, bufsz - pos,
-				"Rx mode: %d\n",
-				restriction->rx_stream);
-		pos += scnprintf(buf + pos, bufsz - pos,
-				"HT mode: %d\n",
-				restriction->is_ht);
-	}
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_disable_ht40_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 ht40;
-
-	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", &ht40) != 1)
-		return -EFAULT;
-	if (!iwl_is_any_associated(priv))
-		priv->disable_ht40 = ht40 ? true : false;
-	else
-		return -EINVAL;
-
-	return count;
-}
-
-static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
-					 char __user *user_buf,
-					 size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	char buf[100];
-	int pos = 0;
-	const size_t bufsz = sizeof(buf);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"11n 40MHz Mode: %s\n",
-			priv->disable_ht40 ? "Disabled" : "Enabled");
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_temperature_read(struct file *file,
-					 char __user *user_buf,
-					 size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	char buf[8];
-	int pos = 0;
-	const size_t bufsz = sizeof(buf);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "%d\n", priv->temperature);
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-
-static ssize_t iwl_dbgfs_sleep_level_override_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 value;
-
-	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", &value) != 1)
-		return -EINVAL;
-
-	/*
-	 * Our users expect 0 to be "CAM", but 0 isn't actually
-	 * valid here. However, let's not confuse them and present
-	 * IWL_POWER_INDEX_1 as "1", not "0".
-	 */
-	if (value == 0)
-		return -EINVAL;
-	else if (value > 0)
-		value -= 1;
-
-	if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
-		return -EINVAL;
-
-	if (!iwl_is_ready_rf(priv))
-		return -EAGAIN;
-
-	priv->power_data.debug_sleep_level_override = value;
-
-	mutex_lock(&priv->mutex);
-	iwl_power_update_mode(priv, true);
-	mutex_unlock(&priv->mutex);
-
-	return count;
-}
-
-static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file,
-						   char __user *user_buf,
-						   size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	char buf[10];
-	int pos, value;
-	const size_t bufsz = sizeof(buf);
-
-	/* see the write function */
-	value = priv->power_data.debug_sleep_level_override;
-	if (value >= 0)
-		value += 1;
-
-	pos = scnprintf(buf, bufsz, "%d\n", value);
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
-						    char __user *user_buf,
-						    size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	char buf[200];
-	int pos = 0, i;
-	const size_t bufsz = sizeof(buf);
-	struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd;
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "flags: %#.2x\n", le16_to_cpu(cmd->flags));
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "RX/TX timeout: %d/%d usec\n",
-			 le32_to_cpu(cmd->rx_data_timeout),
-			 le32_to_cpu(cmd->tx_data_timeout));
-	for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
-		pos += scnprintf(buf + pos, bufsz - pos,
-				 "sleep_interval[%d]: %d\n", i,
-				 le32_to_cpu(cmd->sleep_interval[i]));
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-DEBUGFS_READ_WRITE_FILE_OPS(sram);
-DEBUGFS_READ_FILE_OPS(wowlan_sram);
-DEBUGFS_READ_FILE_OPS(nvm);
-DEBUGFS_READ_FILE_OPS(stations);
-DEBUGFS_READ_FILE_OPS(channels);
-DEBUGFS_READ_FILE_OPS(status);
-DEBUGFS_READ_WRITE_FILE_OPS(rx_handlers);
-DEBUGFS_READ_FILE_OPS(qos);
-DEBUGFS_READ_FILE_OPS(thermal_throttling);
-DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
-DEBUGFS_READ_FILE_OPS(temperature);
-DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
-DEBUGFS_READ_FILE_OPS(current_sleep_command);
-
-static const char *fmt_value = "  %-30s %10u\n";
-static const char *fmt_hex   = "  %-30s       0x%02X\n";
-static const char *fmt_table = "  %-30s %10u  %10u  %10u  %10u\n";
-static const char *fmt_header =
-	"%-32s    current  cumulative       delta         max\n";
-
-static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
-{
-	int p = 0;
-	u32 flag;
-
-	lockdep_assert_held(&priv->statistics.lock);
-
-	flag = le32_to_cpu(priv->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;
-}
-
-static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	char *buf;
-	int bufsz = sizeof(struct statistics_rx_phy) * 40 +
-		    sizeof(struct statistics_rx_non_phy) * 40 +
-		    sizeof(struct statistics_rx_ht_phy) * 40 + 400;
-	ssize_t ret;
-	struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
-	struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
-	struct statistics_rx_non_phy *general, *accum_general;
-	struct statistics_rx_non_phy *delta_general, *max_general;
-	struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	/*
-	 * the statistic information display here is based on
-	 * the last statistics notification from uCode
-	 * might not reflect the current uCode activity
-	 */
-	spin_lock_bh(&priv->statistics.lock);
-	ofdm = &priv->statistics.rx_ofdm;
-	cck = &priv->statistics.rx_cck;
-	general = &priv->statistics.rx_non_phy;
-	ht = &priv->statistics.rx_ofdm_ht;
-	accum_ofdm = &priv->accum_stats.rx_ofdm;
-	accum_cck = &priv->accum_stats.rx_cck;
-	accum_general = &priv->accum_stats.rx_non_phy;
-	accum_ht = &priv->accum_stats.rx_ofdm_ht;
-	delta_ofdm = &priv->delta_stats.rx_ofdm;
-	delta_cck = &priv->delta_stats.rx_cck;
-	delta_general = &priv->delta_stats.rx_non_phy;
-	delta_ht = &priv->delta_stats.rx_ofdm_ht;
-	max_ofdm = &priv->max_delta_stats.rx_ofdm;
-	max_cck = &priv->max_delta_stats.rx_cck;
-	max_general = &priv->max_delta_stats.rx_non_phy;
-	max_ht = &priv->max_delta_stats.rx_ofdm_ht;
-
-	pos += iwl_statistics_flag(priv, buf, bufsz);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_Rx - OFDM:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "ina_cnt:",
-			 le32_to_cpu(ofdm->ina_cnt),
-			 accum_ofdm->ina_cnt,
-			 delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_cnt:",
-			 le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
-			 delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "plcp_err:",
-			 le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
-			 delta_ofdm->plcp_err, max_ofdm->plcp_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_err:",
-			 le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
-			 delta_ofdm->crc32_err, max_ofdm->crc32_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "overrun_err:",
-			 le32_to_cpu(ofdm->overrun_err),
-			 accum_ofdm->overrun_err, delta_ofdm->overrun_err,
-			 max_ofdm->overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "early_overrun_err:",
-			 le32_to_cpu(ofdm->early_overrun_err),
-			 accum_ofdm->early_overrun_err,
-			 delta_ofdm->early_overrun_err,
-			 max_ofdm->early_overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_good:",
-			 le32_to_cpu(ofdm->crc32_good),
-			 accum_ofdm->crc32_good, delta_ofdm->crc32_good,
-			 max_ofdm->crc32_good);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "false_alarm_cnt:",
-			 le32_to_cpu(ofdm->false_alarm_cnt),
-			 accum_ofdm->false_alarm_cnt,
-			 delta_ofdm->false_alarm_cnt,
-			 max_ofdm->false_alarm_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_sync_err_cnt:",
-			 le32_to_cpu(ofdm->fina_sync_err_cnt),
-			 accum_ofdm->fina_sync_err_cnt,
-			 delta_ofdm->fina_sync_err_cnt,
-			 max_ofdm->fina_sync_err_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sfd_timeout:",
-			 le32_to_cpu(ofdm->sfd_timeout),
-			 accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
-			 max_ofdm->sfd_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_timeout:",
-			 le32_to_cpu(ofdm->fina_timeout),
-			 accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
-			 max_ofdm->fina_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "unresponded_rts:",
-			 le32_to_cpu(ofdm->unresponded_rts),
-			 accum_ofdm->unresponded_rts,
-			 delta_ofdm->unresponded_rts,
-			 max_ofdm->unresponded_rts);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "rxe_frame_lmt_ovrun:",
-			 le32_to_cpu(ofdm->rxe_frame_limit_overrun),
-			 accum_ofdm->rxe_frame_limit_overrun,
-			 delta_ofdm->rxe_frame_limit_overrun,
-			 max_ofdm->rxe_frame_limit_overrun);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_ack_cnt:",
-			 le32_to_cpu(ofdm->sent_ack_cnt),
-			 accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
-			 max_ofdm->sent_ack_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_cts_cnt:",
-			 le32_to_cpu(ofdm->sent_cts_cnt),
-			 accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
-			 max_ofdm->sent_cts_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_ba_rsp_cnt:",
-			 le32_to_cpu(ofdm->sent_ba_rsp_cnt),
-			 accum_ofdm->sent_ba_rsp_cnt,
-			 delta_ofdm->sent_ba_rsp_cnt,
-			 max_ofdm->sent_ba_rsp_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "dsp_self_kill:",
-			 le32_to_cpu(ofdm->dsp_self_kill),
-			 accum_ofdm->dsp_self_kill,
-			 delta_ofdm->dsp_self_kill,
-			 max_ofdm->dsp_self_kill);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "mh_format_err:",
-			 le32_to_cpu(ofdm->mh_format_err),
-			 accum_ofdm->mh_format_err,
-			 delta_ofdm->mh_format_err,
-			 max_ofdm->mh_format_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "re_acq_main_rssi_sum:",
-			 le32_to_cpu(ofdm->re_acq_main_rssi_sum),
-			 accum_ofdm->re_acq_main_rssi_sum,
-			 delta_ofdm->re_acq_main_rssi_sum,
-			 max_ofdm->re_acq_main_rssi_sum);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_Rx - CCK:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "ina_cnt:",
-			 le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
-			 delta_cck->ina_cnt, max_cck->ina_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_cnt:",
-			 le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
-			 delta_cck->fina_cnt, max_cck->fina_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "plcp_err:",
-			 le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
-			 delta_cck->plcp_err, max_cck->plcp_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_err:",
-			 le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
-			 delta_cck->crc32_err, max_cck->crc32_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "overrun_err:",
-			 le32_to_cpu(cck->overrun_err),
-			 accum_cck->overrun_err, delta_cck->overrun_err,
-			 max_cck->overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "early_overrun_err:",
-			 le32_to_cpu(cck->early_overrun_err),
-			 accum_cck->early_overrun_err,
-			 delta_cck->early_overrun_err,
-			 max_cck->early_overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_good:",
-			 le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
-			 delta_cck->crc32_good, max_cck->crc32_good);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "false_alarm_cnt:",
-			 le32_to_cpu(cck->false_alarm_cnt),
-			 accum_cck->false_alarm_cnt,
-			 delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_sync_err_cnt:",
-			 le32_to_cpu(cck->fina_sync_err_cnt),
-			 accum_cck->fina_sync_err_cnt,
-			 delta_cck->fina_sync_err_cnt,
-			 max_cck->fina_sync_err_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sfd_timeout:",
-			 le32_to_cpu(cck->sfd_timeout),
-			 accum_cck->sfd_timeout, delta_cck->sfd_timeout,
-			 max_cck->sfd_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_timeout:",
-			 le32_to_cpu(cck->fina_timeout),
-			 accum_cck->fina_timeout, delta_cck->fina_timeout,
-			 max_cck->fina_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "unresponded_rts:",
-			 le32_to_cpu(cck->unresponded_rts),
-			 accum_cck->unresponded_rts, delta_cck->unresponded_rts,
-			 max_cck->unresponded_rts);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "rxe_frame_lmt_ovrun:",
-			 le32_to_cpu(cck->rxe_frame_limit_overrun),
-			 accum_cck->rxe_frame_limit_overrun,
-			 delta_cck->rxe_frame_limit_overrun,
-			 max_cck->rxe_frame_limit_overrun);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_ack_cnt:",
-			 le32_to_cpu(cck->sent_ack_cnt),
-			 accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
-			 max_cck->sent_ack_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_cts_cnt:",
-			 le32_to_cpu(cck->sent_cts_cnt),
-			 accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
-			 max_cck->sent_cts_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_ba_rsp_cnt:",
-			 le32_to_cpu(cck->sent_ba_rsp_cnt),
-			 accum_cck->sent_ba_rsp_cnt,
-			 delta_cck->sent_ba_rsp_cnt,
-			 max_cck->sent_ba_rsp_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "dsp_self_kill:",
-			 le32_to_cpu(cck->dsp_self_kill),
-			 accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
-			 max_cck->dsp_self_kill);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "mh_format_err:",
-			 le32_to_cpu(cck->mh_format_err),
-			 accum_cck->mh_format_err, delta_cck->mh_format_err,
-			 max_cck->mh_format_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "re_acq_main_rssi_sum:",
-			 le32_to_cpu(cck->re_acq_main_rssi_sum),
-			 accum_cck->re_acq_main_rssi_sum,
-			 delta_cck->re_acq_main_rssi_sum,
-			 max_cck->re_acq_main_rssi_sum);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_Rx - GENERAL:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "bogus_cts:",
-			 le32_to_cpu(general->bogus_cts),
-			 accum_general->bogus_cts, delta_general->bogus_cts,
-			 max_general->bogus_cts);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "bogus_ack:",
-			 le32_to_cpu(general->bogus_ack),
-			 accum_general->bogus_ack, delta_general->bogus_ack,
-			 max_general->bogus_ack);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "non_bssid_frames:",
-			 le32_to_cpu(general->non_bssid_frames),
-			 accum_general->non_bssid_frames,
-			 delta_general->non_bssid_frames,
-			 max_general->non_bssid_frames);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "filtered_frames:",
-			 le32_to_cpu(general->filtered_frames),
-			 accum_general->filtered_frames,
-			 delta_general->filtered_frames,
-			 max_general->filtered_frames);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "non_channel_beacons:",
-			 le32_to_cpu(general->non_channel_beacons),
-			 accum_general->non_channel_beacons,
-			 delta_general->non_channel_beacons,
-			 max_general->non_channel_beacons);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "channel_beacons:",
-			 le32_to_cpu(general->channel_beacons),
-			 accum_general->channel_beacons,
-			 delta_general->channel_beacons,
-			 max_general->channel_beacons);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "num_missed_bcon:",
-			 le32_to_cpu(general->num_missed_bcon),
-			 accum_general->num_missed_bcon,
-			 delta_general->num_missed_bcon,
-			 max_general->num_missed_bcon);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "adc_rx_saturation_time:",
-			 le32_to_cpu(general->adc_rx_saturation_time),
-			 accum_general->adc_rx_saturation_time,
-			 delta_general->adc_rx_saturation_time,
-			 max_general->adc_rx_saturation_time);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "ina_detect_search_tm:",
-			 le32_to_cpu(general->ina_detection_search_time),
-			 accum_general->ina_detection_search_time,
-			 delta_general->ina_detection_search_time,
-			 max_general->ina_detection_search_time);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_silence_rssi_a:",
-			 le32_to_cpu(general->beacon_silence_rssi_a),
-			 accum_general->beacon_silence_rssi_a,
-			 delta_general->beacon_silence_rssi_a,
-			 max_general->beacon_silence_rssi_a);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_silence_rssi_b:",
-			 le32_to_cpu(general->beacon_silence_rssi_b),
-			 accum_general->beacon_silence_rssi_b,
-			 delta_general->beacon_silence_rssi_b,
-			 max_general->beacon_silence_rssi_b);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_silence_rssi_c:",
-			 le32_to_cpu(general->beacon_silence_rssi_c),
-			 accum_general->beacon_silence_rssi_c,
-			 delta_general->beacon_silence_rssi_c,
-			 max_general->beacon_silence_rssi_c);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "interference_data_flag:",
-			 le32_to_cpu(general->interference_data_flag),
-			 accum_general->interference_data_flag,
-			 delta_general->interference_data_flag,
-			 max_general->interference_data_flag);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "channel_load:",
-			 le32_to_cpu(general->channel_load),
-			 accum_general->channel_load,
-			 delta_general->channel_load,
-			 max_general->channel_load);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "dsp_false_alarms:",
-			 le32_to_cpu(general->dsp_false_alarms),
-			 accum_general->dsp_false_alarms,
-			 delta_general->dsp_false_alarms,
-			 max_general->dsp_false_alarms);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_rssi_a:",
-			 le32_to_cpu(general->beacon_rssi_a),
-			 accum_general->beacon_rssi_a,
-			 delta_general->beacon_rssi_a,
-			 max_general->beacon_rssi_a);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_rssi_b:",
-			 le32_to_cpu(general->beacon_rssi_b),
-			 accum_general->beacon_rssi_b,
-			 delta_general->beacon_rssi_b,
-			 max_general->beacon_rssi_b);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_rssi_c:",
-			 le32_to_cpu(general->beacon_rssi_c),
-			 accum_general->beacon_rssi_c,
-			 delta_general->beacon_rssi_c,
-			 max_general->beacon_rssi_c);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_energy_a:",
-			 le32_to_cpu(general->beacon_energy_a),
-			 accum_general->beacon_energy_a,
-			 delta_general->beacon_energy_a,
-			 max_general->beacon_energy_a);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_energy_b:",
-			 le32_to_cpu(general->beacon_energy_b),
-			 accum_general->beacon_energy_b,
-			 delta_general->beacon_energy_b,
-			 max_general->beacon_energy_b);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_energy_c:",
-			 le32_to_cpu(general->beacon_energy_c),
-			 accum_general->beacon_energy_c,
-			 delta_general->beacon_energy_c,
-			 max_general->beacon_energy_c);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_Rx - OFDM_HT:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "plcp_err:",
-			 le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
-			 delta_ht->plcp_err, max_ht->plcp_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "overrun_err:",
-			 le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
-			 delta_ht->overrun_err, max_ht->overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "early_overrun_err:",
-			 le32_to_cpu(ht->early_overrun_err),
-			 accum_ht->early_overrun_err,
-			 delta_ht->early_overrun_err,
-			 max_ht->early_overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_good:",
-			 le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
-			 delta_ht->crc32_good, max_ht->crc32_good);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_err:",
-			 le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
-			 delta_ht->crc32_err, max_ht->crc32_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "mh_format_err:",
-			 le32_to_cpu(ht->mh_format_err),
-			 accum_ht->mh_format_err,
-			 delta_ht->mh_format_err, max_ht->mh_format_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg_crc32_good:",
-			 le32_to_cpu(ht->agg_crc32_good),
-			 accum_ht->agg_crc32_good,
-			 delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg_mpdu_cnt:",
-			 le32_to_cpu(ht->agg_mpdu_cnt),
-			 accum_ht->agg_mpdu_cnt,
-			 delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg_cnt:",
-			 le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
-			 delta_ht->agg_cnt, max_ht->agg_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "unsupport_mcs:",
-			 le32_to_cpu(ht->unsupport_mcs),
-			 accum_ht->unsupport_mcs,
-			 delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
-
-	spin_unlock_bh(&priv->statistics.lock);
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	char *buf;
-	int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
-	ssize_t ret;
-	struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	/* the statistic information display here is based on
-	 * the last statistics notification from uCode
-	 * might not reflect the current uCode activity
-	 */
-	spin_lock_bh(&priv->statistics.lock);
-
-	tx = &priv->statistics.tx;
-	accum_tx = &priv->accum_stats.tx;
-	delta_tx = &priv->delta_stats.tx;
-	max_tx = &priv->max_delta_stats.tx;
-
-	pos += iwl_statistics_flag(priv, buf, bufsz);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_Tx:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "preamble:",
-			 le32_to_cpu(tx->preamble_cnt),
-			 accum_tx->preamble_cnt,
-			 delta_tx->preamble_cnt, max_tx->preamble_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "rx_detected_cnt:",
-			 le32_to_cpu(tx->rx_detected_cnt),
-			 accum_tx->rx_detected_cnt,
-			 delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "bt_prio_defer_cnt:",
-			 le32_to_cpu(tx->bt_prio_defer_cnt),
-			 accum_tx->bt_prio_defer_cnt,
-			 delta_tx->bt_prio_defer_cnt,
-			 max_tx->bt_prio_defer_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "bt_prio_kill_cnt:",
-			 le32_to_cpu(tx->bt_prio_kill_cnt),
-			 accum_tx->bt_prio_kill_cnt,
-			 delta_tx->bt_prio_kill_cnt,
-			 max_tx->bt_prio_kill_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "few_bytes_cnt:",
-			 le32_to_cpu(tx->few_bytes_cnt),
-			 accum_tx->few_bytes_cnt,
-			 delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "cts_timeout:",
-			 le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
-			 delta_tx->cts_timeout, max_tx->cts_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "ack_timeout:",
-			 le32_to_cpu(tx->ack_timeout),
-			 accum_tx->ack_timeout,
-			 delta_tx->ack_timeout, max_tx->ack_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "expected_ack_cnt:",
-			 le32_to_cpu(tx->expected_ack_cnt),
-			 accum_tx->expected_ack_cnt,
-			 delta_tx->expected_ack_cnt,
-			 max_tx->expected_ack_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "actual_ack_cnt:",
-			 le32_to_cpu(tx->actual_ack_cnt),
-			 accum_tx->actual_ack_cnt,
-			 delta_tx->actual_ack_cnt,
-			 max_tx->actual_ack_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "dump_msdu_cnt:",
-			 le32_to_cpu(tx->dump_msdu_cnt),
-			 accum_tx->dump_msdu_cnt,
-			 delta_tx->dump_msdu_cnt,
-			 max_tx->dump_msdu_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "abort_nxt_frame_mismatch:",
-			 le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
-			 accum_tx->burst_abort_next_frame_mismatch_cnt,
-			 delta_tx->burst_abort_next_frame_mismatch_cnt,
-			 max_tx->burst_abort_next_frame_mismatch_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "abort_missing_nxt_frame:",
-			 le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
-			 accum_tx->burst_abort_missing_next_frame_cnt,
-			 delta_tx->burst_abort_missing_next_frame_cnt,
-			 max_tx->burst_abort_missing_next_frame_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "cts_timeout_collision:",
-			 le32_to_cpu(tx->cts_timeout_collision),
-			 accum_tx->cts_timeout_collision,
-			 delta_tx->cts_timeout_collision,
-			 max_tx->cts_timeout_collision);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "ack_ba_timeout_collision:",
-			 le32_to_cpu(tx->ack_or_ba_timeout_collision),
-			 accum_tx->ack_or_ba_timeout_collision,
-			 delta_tx->ack_or_ba_timeout_collision,
-			 max_tx->ack_or_ba_timeout_collision);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg ba_timeout:",
-			 le32_to_cpu(tx->agg.ba_timeout),
-			 accum_tx->agg.ba_timeout,
-			 delta_tx->agg.ba_timeout,
-			 max_tx->agg.ba_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg ba_resched_frames:",
-			 le32_to_cpu(tx->agg.ba_reschedule_frames),
-			 accum_tx->agg.ba_reschedule_frames,
-			 delta_tx->agg.ba_reschedule_frames,
-			 max_tx->agg.ba_reschedule_frames);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg scd_query_agg_frame:",
-			 le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
-			 accum_tx->agg.scd_query_agg_frame_cnt,
-			 delta_tx->agg.scd_query_agg_frame_cnt,
-			 max_tx->agg.scd_query_agg_frame_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg scd_query_no_agg:",
-			 le32_to_cpu(tx->agg.scd_query_no_agg),
-			 accum_tx->agg.scd_query_no_agg,
-			 delta_tx->agg.scd_query_no_agg,
-			 max_tx->agg.scd_query_no_agg);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg scd_query_agg:",
-			 le32_to_cpu(tx->agg.scd_query_agg),
-			 accum_tx->agg.scd_query_agg,
-			 delta_tx->agg.scd_query_agg,
-			 max_tx->agg.scd_query_agg);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg scd_query_mismatch:",
-			 le32_to_cpu(tx->agg.scd_query_mismatch),
-			 accum_tx->agg.scd_query_mismatch,
-			 delta_tx->agg.scd_query_mismatch,
-			 max_tx->agg.scd_query_mismatch);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg frame_not_ready:",
-			 le32_to_cpu(tx->agg.frame_not_ready),
-			 accum_tx->agg.frame_not_ready,
-			 delta_tx->agg.frame_not_ready,
-			 max_tx->agg.frame_not_ready);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg underrun:",
-			 le32_to_cpu(tx->agg.underrun),
-			 accum_tx->agg.underrun,
-			 delta_tx->agg.underrun, max_tx->agg.underrun);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg bt_prio_kill:",
-			 le32_to_cpu(tx->agg.bt_prio_kill),
-			 accum_tx->agg.bt_prio_kill,
-			 delta_tx->agg.bt_prio_kill,
-			 max_tx->agg.bt_prio_kill);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg rx_ba_rsp_cnt:",
-			 le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
-			 accum_tx->agg.rx_ba_rsp_cnt,
-			 delta_tx->agg.rx_ba_rsp_cnt,
-			 max_tx->agg.rx_ba_rsp_cnt);
-
-	if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
-		pos += scnprintf(buf + pos, bufsz - pos,
-			"tx power: (1/2 dB step)\n");
-		if ((priv->hw_params.valid_tx_ant & ANT_A) &&
-		    tx->tx_power.ant_a)
-			pos += scnprintf(buf + pos, bufsz - pos,
-					fmt_hex, "antenna A:",
-					tx->tx_power.ant_a);
-		if ((priv->hw_params.valid_tx_ant & ANT_B) &&
-		    tx->tx_power.ant_b)
-			pos += scnprintf(buf + pos, bufsz - pos,
-					fmt_hex, "antenna B:",
-					tx->tx_power.ant_b);
-		if ((priv->hw_params.valid_tx_ant & ANT_C) &&
-		    tx->tx_power.ant_c)
-			pos += scnprintf(buf + pos, bufsz - pos,
-					fmt_hex, "antenna C:",
-					tx->tx_power.ant_c);
-	}
-
-	spin_unlock_bh(&priv->statistics.lock);
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	char *buf;
-	int bufsz = sizeof(struct statistics_general) * 10 + 300;
-	ssize_t ret;
-	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;
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	/* the statistic information display here is based on
-	 * the last statistics notification from uCode
-	 * might not reflect the current uCode activity
-	 */
-
-	spin_lock_bh(&priv->statistics.lock);
-
-	general = &priv->statistics.common;
-	dbg = &priv->statistics.common.dbg;
-	div = &priv->statistics.common.div;
-	accum_general = &priv->accum_stats.common;
-	accum_dbg = &priv->accum_stats.common.dbg;
-	accum_div = &priv->accum_stats.common.div;
-	delta_general = &priv->delta_stats.common;
-	max_general = &priv->max_delta_stats.common;
-	delta_dbg = &priv->delta_stats.common.dbg;
-	max_dbg = &priv->max_delta_stats.common.dbg;
-	delta_div = &priv->delta_stats.common.div;
-	max_div = &priv->max_delta_stats.common.div;
-
-	pos += iwl_statistics_flag(priv, buf, bufsz);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_General:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_value, "temperature:",
-			 le32_to_cpu(general->temperature));
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_value, "temperature_m:",
-			 le32_to_cpu(general->temperature_m));
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_value, "ttl_timestamp:",
-			 le32_to_cpu(general->ttl_timestamp));
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "burst_check:",
-			 le32_to_cpu(dbg->burst_check),
-			 accum_dbg->burst_check,
-			 delta_dbg->burst_check, max_dbg->burst_check);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "burst_count:",
-			 le32_to_cpu(dbg->burst_count),
-			 accum_dbg->burst_count,
-			 delta_dbg->burst_count, max_dbg->burst_count);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "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,
-			 fmt_table, "sleep_time:",
-			 le32_to_cpu(general->sleep_time),
-			 accum_general->sleep_time,
-			 delta_general->sleep_time, max_general->sleep_time);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "slots_out:",
-			 le32_to_cpu(general->slots_out),
-			 accum_general->slots_out,
-			 delta_general->slots_out, max_general->slots_out);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "slots_idle:",
-			 le32_to_cpu(general->slots_idle),
-			 accum_general->slots_idle,
-			 delta_general->slots_idle, max_general->slots_idle);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "tx_on_a:",
-			 le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
-			 delta_div->tx_on_a, max_div->tx_on_a);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "tx_on_b:",
-			 le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
-			 delta_div->tx_on_b, max_div->tx_on_b);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "exec_time:",
-			 le32_to_cpu(div->exec_time), accum_div->exec_time,
-			 delta_div->exec_time, max_div->exec_time);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "probe_time:",
-			 le32_to_cpu(div->probe_time), accum_div->probe_time,
-			 delta_div->probe_time, max_div->probe_time);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "rx_enable_counter:",
-			 le32_to_cpu(general->rx_enable_counter),
-			 accum_general->rx_enable_counter,
-			 delta_general->rx_enable_counter,
-			 max_general->rx_enable_counter);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "num_of_sos_states:",
-			 le32_to_cpu(general->num_of_sos_states),
-			 accum_general->num_of_sos_states,
-			 delta_general->num_of_sos_states,
-			 max_general->num_of_sos_states);
-
-	spin_unlock_bh(&priv->statistics.lock);
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-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;
-	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;
-
-	if (!priv->bt_enable_flag)
-		return -EINVAL;
-
-	/* 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)
-		return -EAGAIN;
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	/*
-	 * the statistic information display here is based on
-	 * the last statistics notification from uCode
-	 * might not reflect the current uCode activity
-	 */
-
-	spin_lock_bh(&priv->statistics.lock);
-
-	bt = &priv->statistics.bt_activity;
-	accum_bt = &priv->accum_stats.bt_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_tx_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->statistics.num_bt_kills),
-			 priv->statistics.accum_num_bt_kills);
-
-	spin_unlock_bh(&priv->statistics.lock);
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_reply_tx_error_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 reply_tx_error_statistics) * 24) +
-		(sizeof(struct reply_agg_tx_error_statistics) * 24) + 200;
-	ssize_t ret;
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n");
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY),
-			 priv->reply_tx_stats.pp_delay);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES),
-			 priv->reply_tx_stats.pp_few_bytes);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO),
-			 priv->reply_tx_stats.pp_bt_prio);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD),
-			 priv->reply_tx_stats.pp_quiet_period);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK),
-			 priv->reply_tx_stats.pp_calc_ttak);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_tx_fail_reason(
-				TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY),
-			 priv->reply_tx_stats.int_crossed_retry);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT),
-			 priv->reply_tx_stats.short_limit);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT),
-			 priv->reply_tx_stats.long_limit);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN),
-			 priv->reply_tx_stats.fifo_underrun);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW),
-			 priv->reply_tx_stats.drain_flow);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH),
-			 priv->reply_tx_stats.rfkill_flush);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE),
-			 priv->reply_tx_stats.life_expire);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS),
-			 priv->reply_tx_stats.dest_ps);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED),
-			 priv->reply_tx_stats.host_abort);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY),
-			 priv->reply_tx_stats.pp_delay);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID),
-			 priv->reply_tx_stats.sta_invalid);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED),
-			 priv->reply_tx_stats.frag_drop);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE),
-			 priv->reply_tx_stats.tid_disable);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED),
-			 priv->reply_tx_stats.fifo_flush);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_tx_fail_reason(
-				TX_STATUS_FAIL_INSUFFICIENT_CF_POLL),
-			 priv->reply_tx_stats.insuff_cf_poll);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX),
-			 priv->reply_tx_stats.fail_hw_drop);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_tx_fail_reason(
-				TX_STATUS_FAIL_NO_BEACON_ON_RADAR),
-			 priv->reply_tx_stats.sta_color_mismatch);
-	pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
-			 priv->reply_tx_stats.unknown);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "\nStatistics_Agg_TX_Error:\n");
-
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK),
-			 priv->reply_agg_tx_stats.underrun);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK),
-			 priv->reply_agg_tx_stats.bt_prio);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK),
-			 priv->reply_agg_tx_stats.few_bytes);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK),
-			 priv->reply_agg_tx_stats.abort);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(
-				AGG_TX_STATE_LAST_SENT_TTL_MSK),
-			 priv->reply_agg_tx_stats.last_sent_ttl);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(
-				AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK),
-			 priv->reply_agg_tx_stats.last_sent_try);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(
-				AGG_TX_STATE_LAST_SENT_BT_KILL_MSK),
-			 priv->reply_agg_tx_stats.last_sent_bt_kill);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK),
-			 priv->reply_agg_tx_stats.scd_query);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(
-				AGG_TX_STATE_TEST_BAD_CRC32_MSK),
-			 priv->reply_agg_tx_stats.bad_crc32);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK),
-			 priv->reply_agg_tx_stats.response);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK),
-			 priv->reply_agg_tx_stats.dump_tx);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK),
-			 priv->reply_agg_tx_stats.delay_tx);
-	pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
-			 priv->reply_agg_tx_stats.unknown);
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos) {
-
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	int cnt = 0;
-	char *buf;
-	int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100;
-	ssize_t ret;
-	struct iwl_sensitivity_data *data;
-
-	data = &priv->sensitivity_data;
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
-			data->auto_corr_ofdm);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"auto_corr_ofdm_mrc:\t\t %u\n",
-			data->auto_corr_ofdm_mrc);
-	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
-			data->auto_corr_ofdm_x1);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"auto_corr_ofdm_mrc_x1:\t\t %u\n",
-			data->auto_corr_ofdm_mrc_x1);
-	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
-			data->auto_corr_cck);
-	pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
-			data->auto_corr_cck_mrc);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"last_bad_plcp_cnt_ofdm:\t\t %u\n",
-			data->last_bad_plcp_cnt_ofdm);
-	pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
-			data->last_fa_cnt_ofdm);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"last_bad_plcp_cnt_cck:\t\t %u\n",
-			data->last_bad_plcp_cnt_cck);
-	pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
-			data->last_fa_cnt_cck);
-	pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
-			data->nrg_curr_state);
-	pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
-			data->nrg_prev_state);
-	pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
-	for (cnt = 0; cnt < 10; cnt++) {
-		pos += scnprintf(buf + pos, bufsz - pos, " %u",
-				data->nrg_value[cnt]);
-	}
-	pos += scnprintf(buf + pos, bufsz - pos, "\n");
-	pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
-	for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
-		pos += scnprintf(buf + pos, bufsz - pos, " %u",
-				data->nrg_silence_rssi[cnt]);
-	}
-	pos += scnprintf(buf + pos, bufsz - pos, "\n");
-	pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
-			data->nrg_silence_ref);
-	pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
-			data->nrg_energy_idx);
-	pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
-			data->nrg_silence_idx);
-	pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
-			data->nrg_th_cck);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"nrg_auto_corr_silence_diff:\t %u\n",
-			data->nrg_auto_corr_silence_diff);
-	pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
-			data->num_in_cck_no_fa);
-	pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
-			data->nrg_th_ofdm);
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-
-static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos) {
-
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	int cnt = 0;
-	char *buf;
-	int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100;
-	ssize_t ret;
-	struct iwl_chain_noise_data *data;
-
-	data = &priv->chain_noise_data;
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
-			data->active_chains);
-	pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
-			data->chain_noise_a);
-	pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
-			data->chain_noise_b);
-	pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
-			data->chain_noise_c);
-	pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
-			data->chain_signal_a);
-	pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
-			data->chain_signal_b);
-	pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
-			data->chain_signal_c);
-	pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
-			data->beacon_count);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
-	for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
-		pos += scnprintf(buf + pos, bufsz - pos, " %u",
-				data->disconn_array[cnt]);
-	}
-	pos += scnprintf(buf + pos, bufsz - pos, "\n");
-	pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
-	for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
-		pos += scnprintf(buf + pos, bufsz - pos, " %u",
-				data->delta_gain_code[cnt]);
-	}
-	pos += scnprintf(buf + pos, bufsz - pos, "\n");
-	pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
-			data->radio_write);
-	pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
-			data->state);
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
-						    char __user *user_buf,
-						    size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	char buf[60];
-	int pos = 0;
-	const size_t bufsz = sizeof(buf);
-	u32 pwrsave_status;
-
-	pwrsave_status = iwl_read32(priv->trans, CSR_GP_CNTRL) &
-			CSR_GP_REG_POWER_SAVE_STATUS_MSK;
-
-	pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
-	pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
-		(pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
-		(pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
-		(pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
-		"error");
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_clear_ucode_statistics_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 clear;
-
-	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", &clear) != 1)
-		return -EFAULT;
-
-	/* make request to uCode to retrieve statistics information */
-	mutex_lock(&priv->mutex);
-	iwl_send_statistics_request(priv, CMD_SYNC, true);
-	mutex_unlock(&priv->mutex);
-
-	return count;
-}
-
-static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos) {
-
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	char buf[128];
-	const size_t bufsz = sizeof(buf);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
-			priv->event_log.ucode_trace ? "On" : "Off");
-	pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
-			priv->event_log.non_wraps_count);
-	pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
-			priv->event_log.wraps_once_count);
-	pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
-			priv->event_log.wraps_more_count);
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_ucode_tracing_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 trace;
-
-	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", &trace) != 1)
-		return -EFAULT;
-
-	if (trace) {
-		priv->event_log.ucode_trace = true;
-		if (iwl_is_alive(priv)) {
-			/* start collecting data now */
-			mod_timer(&priv->ucode_trace, jiffies);
-		}
-	} else {
-		priv->event_log.ucode_trace = false;
-		del_timer_sync(&priv->ucode_trace);
-	}
-
-	return count;
-}
-
-static ssize_t iwl_dbgfs_rxon_flags_read(struct file *file,
-					 char __user *user_buf,
-					 size_t count, loff_t *ppos) {
-
-	struct iwl_priv *priv = file->private_data;
-	int len = 0;
-	char buf[20];
-
-	len = sprintf(buf, "0x%04X\n",
-		le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.flags));
-	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file,
-						char __user *user_buf,
-						size_t count, loff_t *ppos) {
-
-	struct iwl_priv *priv = file->private_data;
-	int len = 0;
-	char buf[20];
-
-	len = sprintf(buf, "0x%04X\n",
-		le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags));
-	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos) {
-
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	char buf[12];
-	const size_t bufsz = sizeof(buf);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
-			priv->missed_beacon_threshold);
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_missed_beacon_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 missed;
-
-	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", &missed) != 1)
-		return -EINVAL;
-
-	if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
-	    missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
-		priv->missed_beacon_threshold =
-			IWL_MISSED_BEACON_THRESHOLD_DEF;
-	else
-		priv->missed_beacon_threshold = missed;
-
-	return count;
-}
-
-static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos) {
-
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	char buf[12];
-	const size_t bufsz = sizeof(buf);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
-			priv->plcp_delta_threshold);
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_plcp_delta_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 plcp;
-
-	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", &plcp) != 1)
-		return -EINVAL;
-	if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
-		(plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
-		priv->plcp_delta_threshold =
-			IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE;
-	else
-		priv->plcp_delta_threshold = plcp;
-	return count;
-}
-
-static ssize_t iwl_dbgfs_rf_reset_read(struct file *file,
-				       char __user *user_buf,
-				       size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	char buf[300];
-	const size_t bufsz = sizeof(buf);
-	struct iwl_rf_reset *rf_reset = &priv->rf_reset;
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"RF reset statistics\n");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"\tnumber of reset request: %d\n",
-			rf_reset->reset_request_count);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"\tnumber of reset request success: %d\n",
-			rf_reset->reset_success_count);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"\tnumber of reset request reject: %d\n",
-			rf_reset->reset_reject_count);
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_rf_reset_write(struct file *file,
-					const char __user *user_buf,
-					size_t count, loff_t *ppos) {
-
-	struct iwl_priv *priv = file->private_data;
-	int ret;
-
-	ret = iwl_force_rf_reset(priv, true);
-	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;
-
-	iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
-
-	return count;
-}
-
-static ssize_t iwl_dbgfs_bt_traffic_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[200];
-	const size_t bufsz = sizeof(buf);
-
-	if (!priv->bt_enable_flag) {
-		pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n");
-		return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	}
-	pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n",
-		priv->bt_enable_flag);
-	pos += scnprintf(buf + pos, bufsz - pos, "BT in %s mode\n",
-		priv->bt_full_concurrent ? "full concurrency" : "3-wire");
-	pos += scnprintf(buf + pos, bufsz - pos, "BT status: %s, "
-			 "last traffic notif: %d\n",
-		priv->bt_status ? "On" : "Off", priv->last_bt_traffic_load);
-	pos += scnprintf(buf + pos, bufsz - pos, "ch_announcement: %d, "
-			 "kill_ack_mask: %x, kill_cts_mask: %x\n",
-		priv->bt_ch_announce, priv->kill_ack_mask,
-		priv->kill_cts_mask);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "bluetooth traffic load: ");
-	switch (priv->bt_traffic_load) {
-	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-		pos += scnprintf(buf + pos, bufsz - pos, "Continuous\n");
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-		pos += scnprintf(buf + pos, bufsz - pos, "High\n");
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-		pos += scnprintf(buf + pos, bufsz - pos, "Low\n");
-		break;
-	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-	default:
-		pos += scnprintf(buf + pos, bufsz - pos, "None\n");
-		break;
-	}
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_protection_mode_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[40];
-	const size_t bufsz = sizeof(buf);
-
-	if (priv->cfg->ht_params)
-		pos += scnprintf(buf + pos, bufsz - pos,
-			 "use %s for aggregation\n",
-			 (priv->hw_params.use_rts_for_aggregation) ?
-				"rts/cts" : "cts-to-self");
-	else
-		pos += scnprintf(buf + pos, bufsz - pos, "N/A");
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_protection_mode_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 rts;
-
-	if (!priv->cfg->ht_params)
-		return -EINVAL;
-
-	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", &rts) != 1)
-		return -EINVAL;
-	if (rts)
-		priv->hw_params.use_rts_for_aggregation = true;
-	else
-		priv->hw_params.use_rts_for_aggregation = false;
-	return count;
-}
-
-static int iwl_cmd_echo_test(struct iwl_priv *priv)
-{
-	int ret;
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_ECHO,
-		.len = { 0 },
-		.flags = CMD_SYNC,
-	};
-
-	ret = iwl_dvm_send_cmd(priv, &cmd);
-	if (ret)
-		IWL_ERR(priv, "echo testing fail: 0X%x\n", ret);
-	else
-		IWL_DEBUG_INFO(priv, "echo testing pass\n");
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_echo_test_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;
-
-	memset(buf, 0, sizeof(buf));
-	buf_size = min(count, sizeof(buf) -  1);
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-
-	iwl_cmd_echo_test(priv);
-	return count;
-}
-
-static ssize_t iwl_dbgfs_log_event_read(struct file *file,
-					 char __user *user_buf,
-					 size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	char *buf;
-	int pos = 0;
-	ssize_t ret = -ENOMEM;
-
-	ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true);
-	if (buf) {
-		ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-		kfree(buf);
-	}
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_log_event_write(struct file *file,
-					const char __user *user_buf,
-					size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	u32 event_log_flag;
-	char buf[8];
-	int buf_size;
-
-	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", &event_log_flag) != 1)
-		return -EFAULT;
-	if (event_log_flag == 1)
-		iwl_dump_nic_event_log(priv, true, NULL, false);
-
-	return count;
-}
-
-static ssize_t iwl_dbgfs_calib_disabled_read(struct file *file,
-					 char __user *user_buf,
-					 size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	char buf[120];
-	int pos = 0;
-	const size_t bufsz = sizeof(buf);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "Sensitivity calibrations %s\n",
-			 (priv->calib_disabled &
-					IWL_SENSITIVITY_CALIB_DISABLED) ?
-			 "DISABLED" : "ENABLED");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "Chain noise calibrations %s\n",
-			 (priv->calib_disabled &
-					IWL_CHAIN_NOISE_CALIB_DISABLED) ?
-			 "DISABLED" : "ENABLED");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "Tx power calibrations %s\n",
-			 (priv->calib_disabled &
-					IWL_TX_POWER_CALIB_DISABLED) ?
-			 "DISABLED" : "ENABLED");
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_calib_disabled_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];
-	u32 calib_disabled;
-	int buf_size;
-
-	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, "%x", &calib_disabled) != 1)
-		return -EFAULT;
-
-	priv->calib_disabled = calib_disabled;
-
-	return count;
-}
-
-DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
-DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
-DEBUGFS_READ_FILE_OPS(ucode_general_stats);
-DEBUGFS_READ_FILE_OPS(sensitivity);
-DEBUGFS_READ_FILE_OPS(chain_noise);
-DEBUGFS_READ_FILE_OPS(power_save_status);
-DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
-DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
-DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
-DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
-DEBUGFS_READ_WRITE_FILE_OPS(rf_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);
-DEBUGFS_READ_FILE_OPS(bt_traffic);
-DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
-DEBUGFS_READ_FILE_OPS(reply_tx_error);
-DEBUGFS_WRITE_FILE_OPS(echo_test);
-DEBUGFS_READ_WRITE_FILE_OPS(log_event);
-DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled);
-
-/*
- * Create the debugfs files and directories
- *
- */
-int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
-{
-	struct dentry *phyd = priv->hw->wiphy->debugfsdir;
-	struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
-
-	dir_drv = debugfs_create_dir(name, phyd);
-	if (!dir_drv)
-		return -ENOMEM;
-
-	priv->debugfs_dir = dir_drv;
-
-	dir_data = debugfs_create_dir("data", dir_drv);
-	if (!dir_data)
-		goto err;
-	dir_rf = debugfs_create_dir("rf", dir_drv);
-	if (!dir_rf)
-		goto err;
-	dir_debug = debugfs_create_dir("debug", dir_drv);
-	if (!dir_debug)
-		goto err;
-
-	DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
-	DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
-	DEBUGFS_ADD_FILE(wowlan_sram, dir_data, S_IRUSR);
-	DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
-	DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
-	DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
-	DEBUGFS_ADD_FILE(rx_handlers, dir_data, S_IWUSR | S_IRUSR);
-	DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
-	DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
-	DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
-	DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
-	DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
-	DEBUGFS_ADD_FILE(temperature, dir_data, S_IRUSR);
-
-	DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
-	DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
-	DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
-	DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
-	DEBUGFS_ADD_FILE(rf_reset, dir_debug, S_IWUSR | S_IRUSR);
-	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);
-	DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
-	DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
-	DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
-	DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
-	DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
-	DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
-	DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
-	DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
-	DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
-	DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR);
-	DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR);
-
-	if (iwl_advanced_bt_coexist(priv))
-		DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
-
-	/* Calibrations disabled/enabled status*/
-	DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR);
-
-	if (iwl_trans_dbgfs_register(priv->trans, dir_debug))
-		goto err;
-	return 0;
-
-err:
-	IWL_ERR(priv, "Can't create the debugfs directory\n");
-	iwl_dbgfs_unregister(priv);
-	return -ENOMEM;
-}
-
-/**
- * Remove the debugfs files and directories
- *
- */
-void iwl_dbgfs_unregister(struct iwl_priv *priv)
-{
-	if (!priv->debugfs_dir)
-		return;
-
-	debugfs_remove_recursive(priv->debugfs_dir);
-	priv->debugfs_dir = NULL;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
deleted file mode 100644
index 7006237..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ /dev/null
@@ -1,1071 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 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.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-/*
- * Please use this file (iwl-dev.h) for driver implementation definitions.
- * Please use iwl-commands.h for uCode API definitions.
- */
-
-#ifndef __iwl_dev_h__
-#define __iwl_dev_h__
-
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/leds.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-
-#include "iwl-fw.h"
-#include "iwl-eeprom.h"
-#include "iwl-csr.h"
-#include "iwl-debug.h"
-#include "iwl-agn-hw.h"
-#include "iwl-led.h"
-#include "iwl-power.h"
-#include "iwl-agn-rs.h"
-#include "iwl-agn-tt.h"
-#include "iwl-trans.h"
-#include "iwl-op-mode.h"
-#include "iwl-notif-wait.h"
-
-/* CT-KILL constants */
-#define CT_KILL_THRESHOLD_LEGACY   110 /* in Celsius */
-#define CT_KILL_THRESHOLD	   114 /* in Celsius */
-#define CT_KILL_EXIT_THRESHOLD     95  /* in Celsius */
-
-/* Default noise level to report when noise measurement is not available.
- *   This may be because we're:
- *   1)  Not associated  no beacon statistics being sent to driver)
- *   2)  Scanning (noise measurement does not apply to associated channel)
- * Use default noise value of -127 ... this is below the range of measurable
- *   Rx dBm for all agn devices, so it can indicate "unmeasurable" to user.
- *   Also, -127 works better than 0 when averaging frames with/without
- *   noise info (e.g. averaging might be done in app); measured dBm values are
- *   always negative ... using a negative value as the default keeps all
- *   averages within an s8's (used in some apps) range of negative values. */
-#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
-
-/*
- * RTS threshold here is total size [2347] minus 4 FCS bytes
- * Per spec:
- *   a value of 0 means RTS on all data/management packets
- *   a value > max MSDU size means no RTS
- * else RTS for data/management frames where MPDU is larger
- *   than RTS value.
- */
-#define DEFAULT_RTS_THRESHOLD     2347U
-#define MIN_RTS_THRESHOLD         0U
-#define MAX_RTS_THRESHOLD         2347U
-#define MAX_MSDU_SIZE		  2304U
-#define MAX_MPDU_SIZE		  2346U
-#define DEFAULT_BEACON_INTERVAL   200U
-#define	DEFAULT_SHORT_RETRY_LIMIT 7U
-#define	DEFAULT_LONG_RETRY_LIMIT  4U
-
-#define IWL_NUM_SCAN_RATES         (2)
-
-/*
- * One for each channel, holds all channel setup data
- * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
- *     with one another!
- */
-struct iwl_channel_info {
-	struct iwl_eeprom_channel eeprom;	/* EEPROM regulatory limit */
-	struct iwl_eeprom_channel ht40_eeprom;	/* EEPROM regulatory limit for
-						 * HT40 channel */
-
-	u8 channel;	  /* channel number */
-	u8 flags;	  /* flags copied from EEPROM */
-	s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
-	s8 curr_txpow;	  /* (dBm) regulatory/spectrum/user (not h/w) limit */
-	s8 min_power;	  /* always 0 */
-	s8 scan_power;	  /* (dBm) regul. eeprom, direct scans, any rate */
-
-	u8 group_index;	  /* 0-4, maps channel to group1/2/3/4/5 */
-	u8 band_index;	  /* 0-4, maps channel to band1/2/3/4/5 */
-	enum ieee80211_band band;
-
-	/* HT40 channel info */
-	s8 ht40_max_power_avg;	/* (dBm) regul. eeprom, normal Tx, any rate */
-	u8 ht40_flags;		/* flags copied from EEPROM */
-	u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
-};
-
-/*
- * Minimum number of queues. MAX_NUM is defined in hw specific files.
- * Set the minimum to accommodate
- *  - 4 standard TX queues
- *  - the command queue
- *  - 4 PAN TX queues
- *  - the PAN multicast queue, and
- *  - the AUX (TX during scan dwell) queue.
- */
-#define IWL_MIN_NUM_QUEUES	11
-
-/*
- * Command queue depends on iPAN support.
- */
-#define IWL_DEFAULT_CMD_QUEUE_NUM	4
-#define IWL_IPAN_CMD_QUEUE_NUM		9
-
-#define IEEE80211_DATA_LEN              2304
-#define IEEE80211_4ADDR_LEN             30
-#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
-#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
-
-#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
-#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
-#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
-
-#define IWL_SUPPORTED_RATES_IE_LEN         8
-
-#define IWL_INVALID_RATE     0xFF
-#define IWL_INVALID_VALUE    -1
-
-union iwl_ht_rate_supp {
-	u16 rates;
-	struct {
-		u8 siso_rate;
-		u8 mimo_rate;
-	};
-};
-
-#define CFG_HT_RX_AMPDU_FACTOR_8K   (0x0)
-#define CFG_HT_RX_AMPDU_FACTOR_16K  (0x1)
-#define CFG_HT_RX_AMPDU_FACTOR_32K  (0x2)
-#define CFG_HT_RX_AMPDU_FACTOR_64K  (0x3)
-#define CFG_HT_RX_AMPDU_FACTOR_DEF  CFG_HT_RX_AMPDU_FACTOR_64K
-#define CFG_HT_RX_AMPDU_FACTOR_MAX  CFG_HT_RX_AMPDU_FACTOR_64K
-#define CFG_HT_RX_AMPDU_FACTOR_MIN  CFG_HT_RX_AMPDU_FACTOR_8K
-
-/*
- * Maximal MPDU density for TX aggregation
- * 4 - 2us density
- * 5 - 4us density
- * 6 - 8us density
- * 7 - 16us density
- */
-#define CFG_HT_MPDU_DENSITY_2USEC   (0x4)
-#define CFG_HT_MPDU_DENSITY_4USEC   (0x5)
-#define CFG_HT_MPDU_DENSITY_8USEC   (0x6)
-#define CFG_HT_MPDU_DENSITY_16USEC  (0x7)
-#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
-#define CFG_HT_MPDU_DENSITY_MAX CFG_HT_MPDU_DENSITY_16USEC
-#define CFG_HT_MPDU_DENSITY_MIN     (0x1)
-
-struct iwl_ht_config {
-	bool single_chain_sufficient;
-	enum ieee80211_smps_mode smps; /* current smps mode */
-};
-
-/* QoS structures */
-struct iwl_qos_info {
-	int qos_active;
-	struct iwl_qosparam_cmd def_qos_parm;
-};
-
-/**
- * enum iwl_agg_state
- *
- * The state machine of the BA agreement establishment / tear down.
- * These states relate to a specific RA / TID.
- *
- * @IWL_AGG_OFF: aggregation is not used
- * @IWL_AGG_STARTING: aggregation are starting (between start and oper)
- * @IWL_AGG_ON: aggregation session is up
- * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the
- *	HW queue to be empty from packets for this RA /TID.
- * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the
- *	HW queue to be empty from packets for this RA /TID.
- */
-enum iwl_agg_state {
-	IWL_AGG_OFF = 0,
-	IWL_AGG_STARTING,
-	IWL_AGG_ON,
-	IWL_EMPTYING_HW_QUEUE_ADDBA,
-	IWL_EMPTYING_HW_QUEUE_DELBA,
-};
-
-/**
- * struct iwl_ht_agg - aggregation state machine
-
- * This structs holds the states for the BA agreement establishment and tear
- * down. It also holds the state during the BA session itself. This struct is
- * duplicated for each RA / TID.
-
- * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the
- *	Tx response (REPLY_TX), and the block ack notification
- *	(REPLY_COMPRESSED_BA).
- * @state: state of the BA agreement establishment / tear down.
- * @txq_id: Tx queue used by the BA session
- * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or
- *	the first packet to be sent in legacy HW queue in Tx AGG stop flow.
- *	Basically when next_reclaimed reaches ssn, we can tell mac80211 that
- *	we are ready to finish the Tx AGG stop / start flow.
- * @wait_for_ba: Expect block-ack before next Tx reply
- */
-struct iwl_ht_agg {
-	u32 rate_n_flags;
-	enum iwl_agg_state state;
-	u16 txq_id;
-	u16 ssn;
-	bool wait_for_ba;
-};
-
-/**
- * struct iwl_tid_data - one for each RA / TID
-
- * This structs holds the states for each RA / TID.
-
- * @seq_number: the next WiFi sequence number to use
- * @next_reclaimed: the WiFi sequence number of the next packet to be acked.
- *	This is basically (last acked packet++).
- * @agg: aggregation state machine
- */
-struct iwl_tid_data {
-	u16 seq_number;
-	u16 next_reclaimed;
-	struct iwl_ht_agg agg;
-};
-
-/*
- * Structure should be accessed with sta_lock held. When station addition
- * is in progress (IWL_STA_UCODE_INPROGRESS) it is possible to access only
- * the commands (iwl_addsta_cmd and iwl_link_quality_cmd) without sta_lock
- * held.
- */
-struct iwl_station_entry {
-	struct iwl_addsta_cmd sta;
-	u8 used, ctxid;
-	struct iwl_link_quality_cmd *lq;
-};
-
-/*
- * iwl_station_priv: Driver's private station information
- *
- * When mac80211 creates a station it reserves some space (hw->sta_data_size)
- * in the structure for use by driver. This structure is places in that
- * space.
- */
-struct iwl_station_priv {
-	struct iwl_rxon_context *ctx;
-	struct iwl_lq_sta lq_sta;
-	atomic_t pending_frames;
-	bool client;
-	bool asleep;
-	u8 max_agg_bufsize;
-	u8 sta_id;
-};
-
-/**
- * struct iwl_vif_priv - driver's private per-interface information
- *
- * When mac80211 allocates a virtual interface, it can allocate
- * space for us to put data into.
- */
-struct iwl_vif_priv {
-	struct iwl_rxon_context *ctx;
-	u8 ibss_bssid_sta_id;
-};
-
-struct iwl_sensitivity_ranges {
-	u16 min_nrg_cck;
-
-	u16 nrg_th_cck;
-	u16 nrg_th_ofdm;
-
-	u16 auto_corr_min_ofdm;
-	u16 auto_corr_min_ofdm_mrc;
-	u16 auto_corr_min_ofdm_x1;
-	u16 auto_corr_min_ofdm_mrc_x1;
-
-	u16 auto_corr_max_ofdm;
-	u16 auto_corr_max_ofdm_mrc;
-	u16 auto_corr_max_ofdm_x1;
-	u16 auto_corr_max_ofdm_mrc_x1;
-
-	u16 auto_corr_max_cck;
-	u16 auto_corr_max_cck_mrc;
-	u16 auto_corr_min_cck;
-	u16 auto_corr_min_cck_mrc;
-
-	u16 barker_corr_th_min;
-	u16 barker_corr_th_min_mrc;
-	u16 nrg_th_cca;
-};
-
-
-#define KELVIN_TO_CELSIUS(x) ((x)-273)
-#define CELSIUS_TO_KELVIN(x) ((x)+273)
-
-
-/******************************************************************************
- *
- * Functions implemented in core module which are forward declared here
- * for use by iwl-[4-5].c
- *
- * NOTE:  The implementation of these functions are not hardware specific
- * which is why they are in the core module files.
- *
- * Naming convention --
- * iwl_         <-- Is part of iwlwifi
- * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
- *
- ****************************************************************************/
-extern void iwl_update_chain_flags(struct iwl_priv *priv);
-extern const u8 iwl_bcast_addr[ETH_ALEN];
-
-#define IWL_OPERATION_MODE_AUTO     0
-#define IWL_OPERATION_MODE_HT_ONLY  1
-#define IWL_OPERATION_MODE_MIXED    2
-#define IWL_OPERATION_MODE_20MHZ    3
-
-#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
-
-/* Sensitivity and chain noise calibration */
-#define INITIALIZATION_VALUE		0xFFFF
-#define IWL_CAL_NUM_BEACONS		16
-#define MAXIMUM_ALLOWED_PATHLOSS	15
-
-#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
-
-#define MAX_FA_OFDM  50
-#define MIN_FA_OFDM  5
-#define MAX_FA_CCK   50
-#define MIN_FA_CCK   5
-
-#define AUTO_CORR_STEP_OFDM       1
-
-#define AUTO_CORR_STEP_CCK     3
-#define AUTO_CORR_MAX_TH_CCK   160
-
-#define NRG_DIFF               2
-#define NRG_STEP_CCK           2
-#define NRG_MARGIN             8
-#define MAX_NUMBER_CCK_NO_FA 100
-
-#define AUTO_CORR_CCK_MIN_VAL_DEF    (125)
-
-#define CHAIN_A             0
-#define CHAIN_B             1
-#define CHAIN_C             2
-#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4
-#define ALL_BAND_FILTER			0xFF00
-#define IN_BAND_FILTER			0xFF
-#define MIN_AVERAGE_NOISE_MAX_VALUE	0xFFFFFFFF
-
-#define NRG_NUM_PREV_STAT_L     20
-#define NUM_RX_CHAINS           3
-
-enum iwlagn_false_alarm_state {
-	IWL_FA_TOO_MANY = 0,
-	IWL_FA_TOO_FEW = 1,
-	IWL_FA_GOOD_RANGE = 2,
-};
-
-enum iwlagn_chain_noise_state {
-	IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
-	IWL_CHAIN_NOISE_ACCUMULATE,
-	IWL_CHAIN_NOISE_CALIBRATED,
-	IWL_CHAIN_NOISE_DONE,
-};
-
-/* Sensitivity calib data */
-struct iwl_sensitivity_data {
-	u32 auto_corr_ofdm;
-	u32 auto_corr_ofdm_mrc;
-	u32 auto_corr_ofdm_x1;
-	u32 auto_corr_ofdm_mrc_x1;
-	u32 auto_corr_cck;
-	u32 auto_corr_cck_mrc;
-
-	u32 last_bad_plcp_cnt_ofdm;
-	u32 last_fa_cnt_ofdm;
-	u32 last_bad_plcp_cnt_cck;
-	u32 last_fa_cnt_cck;
-
-	u32 nrg_curr_state;
-	u32 nrg_prev_state;
-	u32 nrg_value[10];
-	u8  nrg_silence_rssi[NRG_NUM_PREV_STAT_L];
-	u32 nrg_silence_ref;
-	u32 nrg_energy_idx;
-	u32 nrg_silence_idx;
-	u32 nrg_th_cck;
-	s32 nrg_auto_corr_silence_diff;
-	u32 num_in_cck_no_fa;
-	u32 nrg_th_ofdm;
-
-	u16 barker_corr_th_min;
-	u16 barker_corr_th_min_mrc;
-	u16 nrg_th_cca;
-};
-
-/* Chain noise (differential Rx gain) calib data */
-struct iwl_chain_noise_data {
-	u32 active_chains;
-	u32 chain_noise_a;
-	u32 chain_noise_b;
-	u32 chain_noise_c;
-	u32 chain_signal_a;
-	u32 chain_signal_b;
-	u32 chain_signal_c;
-	u16 beacon_count;
-	u8 disconn_array[NUM_RX_CHAINS];
-	u8 delta_gain_code[NUM_RX_CHAINS];
-	u8 radio_write;
-	u8 state;
-};
-
-enum {
-	MEASUREMENT_READY = (1 << 0),
-	MEASUREMENT_ACTIVE = (1 << 1),
-};
-
-enum iwl_nvm_type {
-	NVM_DEVICE_TYPE_EEPROM = 0,
-	NVM_DEVICE_TYPE_OTP,
-};
-
-/*
- * Two types of OTP memory access modes
- *   IWL_OTP_ACCESS_ABSOLUTE - absolute address mode,
- * 			        based on physical memory addressing
- *   IWL_OTP_ACCESS_RELATIVE - relative address mode,
- * 			       based on logical memory addressing
- */
-enum iwl_access_mode {
-	IWL_OTP_ACCESS_ABSOLUTE,
-	IWL_OTP_ACCESS_RELATIVE,
-};
-
-/* reply_tx_statistics (for _agn devices) */
-struct reply_tx_error_statistics {
-	u32 pp_delay;
-	u32 pp_few_bytes;
-	u32 pp_bt_prio;
-	u32 pp_quiet_period;
-	u32 pp_calc_ttak;
-	u32 int_crossed_retry;
-	u32 short_limit;
-	u32 long_limit;
-	u32 fifo_underrun;
-	u32 drain_flow;
-	u32 rfkill_flush;
-	u32 life_expire;
-	u32 dest_ps;
-	u32 host_abort;
-	u32 bt_retry;
-	u32 sta_invalid;
-	u32 frag_drop;
-	u32 tid_disable;
-	u32 fifo_flush;
-	u32 insuff_cf_poll;
-	u32 fail_hw_drop;
-	u32 sta_color_mismatch;
-	u32 unknown;
-};
-
-/* reply_agg_tx_statistics (for _agn devices) */
-struct reply_agg_tx_error_statistics {
-	u32 underrun;
-	u32 bt_prio;
-	u32 few_bytes;
-	u32 abort;
-	u32 last_sent_ttl;
-	u32 last_sent_try;
-	u32 last_sent_bt_kill;
-	u32 scd_query;
-	u32 bad_crc32;
-	u32 response;
-	u32 dump_tx;
-	u32 delay_tx;
-	u32 unknown;
-};
-
-/*
- * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
- * to perform continuous uCode event logging operation if enabled
- */
-#define UCODE_TRACE_PERIOD (10)
-
-/*
- * iwl_event_log: current uCode event log position
- *
- * @ucode_trace: enable/disable ucode continuous trace timer
- * @num_wraps: how many times the event buffer wraps
- * @next_entry:  the entry just before the next one that uCode would fill
- * @non_wraps_count: counter for no wrap detected when dump ucode events
- * @wraps_once_count: counter for wrap once detected when dump ucode events
- * @wraps_more_count: counter for wrap more than once detected
- *		      when dump ucode events
- */
-struct iwl_event_log {
-	bool ucode_trace;
-	u32 num_wraps;
-	u32 next_entry;
-	int non_wraps_count;
-	int wraps_once_count;
-	int wraps_more_count;
-};
-
-#define IWL_DELAY_NEXT_FORCE_RF_RESET  (HZ*3)
-
-/* BT Antenna Coupling Threshold (dB) */
-#define IWL_BT_ANTENNA_COUPLING_THRESHOLD	(35)
-
-/* Firmware reload counter and Timestamp */
-#define IWL_MIN_RELOAD_DURATION		1000 /* 1000 ms */
-#define IWL_MAX_CONTINUE_RELOAD_CNT	4
-
-
-struct iwl_rf_reset {
-	int reset_request_count;
-	int reset_success_count;
-	int reset_reject_count;
-	unsigned long last_reset_jiffies;
-};
-
-enum iwl_rxon_context_id {
-	IWL_RXON_CTX_BSS,
-	IWL_RXON_CTX_PAN,
-
-	NUM_IWL_RXON_CTX
-};
-
-/* extend beacon time format bit shifting  */
-/*
- * for _agn devices
- * bits 31:22 - extended
- * bits 21:0  - interval
- */
-#define IWLAGN_EXT_BEACON_TIME_POS	22
-
-struct iwl_rxon_context {
-	struct ieee80211_vif *vif;
-
-	u8 mcast_queue;
-	u8 ac_to_queue[IEEE80211_NUM_ACS];
-	u8 ac_to_fifo[IEEE80211_NUM_ACS];
-
-	/*
-	 * We could use the vif to indicate active, but we
-	 * also need it to be active during disabling when
-	 * we already removed the vif for type setting.
-	 */
-	bool always_active, is_active;
-
-	bool ht_need_multiple_chains;
-
-	enum iwl_rxon_context_id ctxid;
-
-	u32 interface_modes, exclusive_interface_modes;
-	u8 unused_devtype, ap_devtype, ibss_devtype, station_devtype;
-
-	/*
-	 * We declare this const so it can only be
-	 * changed via explicit cast within the
-	 * routines that actually update the physical
-	 * hardware.
-	 */
-	const struct iwl_rxon_cmd active;
-	struct iwl_rxon_cmd staging;
-
-	struct iwl_rxon_time_cmd timing;
-
-	struct iwl_qos_info qos_data;
-
-	u8 bcast_sta_id, ap_sta_id;
-
-	u8 rxon_cmd, rxon_assoc_cmd, rxon_timing_cmd;
-	u8 qos_cmd;
-	u8 wep_key_cmd;
-
-	struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
-	u8 key_mapping_keys;
-
-	__le32 station_flags;
-
-	int beacon_int;
-
-	struct {
-		bool non_gf_sta_present;
-		u8 protection;
-		bool enabled, is_40mhz;
-		u8 extension_chan_offset;
-	} ht;
-};
-
-enum iwl_scan_type {
-	IWL_SCAN_NORMAL,
-	IWL_SCAN_RADIO_RESET,
-	IWL_SCAN_ROC,
-};
-
-/**
- * struct iwl_hw_params
- *
- * Holds the module parameters
- *
- * @tx_chains_num: Number of TX chains
- * @rx_chains_num: Number of RX chains
- * @valid_tx_ant: usable antennas for TX
- * @valid_rx_ant: usable antennas for RX
- * @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX)
- * @sku: sku read from EEPROM
- * @ct_kill_threshold: temperature threshold - in hw dependent unit
- * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
- *	relevant for 1000, 6000 and up
- * @struct iwl_sensitivity_ranges: range of sensitivity values
- * @use_rts_for_aggregation: use rts/cts protection for HT traffic
- */
-struct iwl_hw_params {
-	u8  tx_chains_num;
-	u8  rx_chains_num;
-	u8  valid_tx_ant;
-	u8  valid_rx_ant;
-	u8  ht40_channel;
-	bool use_rts_for_aggregation;
-	u16 sku;
-	u32 ct_kill_threshold;
-	u32 ct_kill_exit_threshold;
-
-	const struct iwl_sensitivity_ranges *sens;
-};
-
-struct iwl_lib_ops {
-	/* set hw dependent parameters */
-	void (*set_hw_params)(struct iwl_priv *priv);
-	int (*set_channel_switch)(struct iwl_priv *priv,
-				  struct ieee80211_channel_switch *ch_switch);
-	/* device specific configuration */
-	void (*nic_config)(struct iwl_priv *priv);
-
-	/* eeprom operations (as defined in iwl-eeprom.h) */
-	struct iwl_eeprom_ops eeprom_ops;
-
-	/* temperature */
-	void (*temperature)(struct iwl_priv *priv);
-};
-
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-struct iwl_testmode_trace {
-	u32 buff_size;
-	u32 total_size;
-	u32 num_chunks;
-	u8 *cpu_addr;
-	u8 *trace_addr;
-	dma_addr_t dma_addr;
-	bool trace_enabled;
-};
-struct iwl_testmode_mem {
-	u32 buff_size;
-	u32 num_chunks;
-	u8 *buff_addr;
-	bool read_in_progress;
-};
-#endif
-
-struct iwl_wipan_noa_data {
-	struct rcu_head rcu_head;
-	u32 length;
-	u8 data[];
-};
-
-/* Calibration disabling bit mask */
-enum {
-	IWL_CALIB_ENABLE_ALL			= 0,
-
-	IWL_SENSITIVITY_CALIB_DISABLED		= BIT(0),
-	IWL_CHAIN_NOISE_CALIB_DISABLED		= BIT(1),
-	IWL_TX_POWER_CALIB_DISABLED		= BIT(2),
-
-	IWL_CALIB_DISABLE_ALL			= 0xFFFFFFFF,
-};
-
-#define IWL_OP_MODE_GET_DVM(_iwl_op_mode) \
-	((struct iwl_priv *) ((_iwl_op_mode)->op_mode_specific))
-
-#define IWL_MAC80211_GET_DVM(_hw) \
-	((struct iwl_priv *) ((struct iwl_op_mode *) \
-	(_hw)->priv)->op_mode_specific)
-
-struct iwl_priv {
-
-	struct iwl_trans *trans;
-	struct device *dev;		/* for debug prints only */
-	const struct iwl_cfg *cfg;
-	const struct iwl_fw *fw;
-	const struct iwl_lib_ops *lib;
-	unsigned long status;
-
-	spinlock_t sta_lock;
-	struct mutex mutex;
-
-	unsigned long transport_queue_stop;
-	bool passive_no_rx;
-#define IWL_INVALID_MAC80211_QUEUE	0xff
-	u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
-	atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
-
-	unsigned long agg_q_alloc[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
-
-	/* ieee device used by generic ieee processing code */
-	struct ieee80211_hw *hw;
-	struct ieee80211_channel *ieee_channels;
-	struct ieee80211_rate *ieee_rates;
-
-	struct list_head calib_results;
-
-	struct workqueue_struct *workqueue;
-
-	struct iwl_hw_params hw_params;
-
-	enum ieee80211_band band;
-	u8 valid_contexts;
-
-	void (*pre_rx_handler)(struct iwl_priv *priv,
-			       struct iwl_rx_cmd_buffer *rxb);
-	int (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
-				       struct iwl_rx_cmd_buffer *rxb,
-				       struct iwl_device_cmd *cmd);
-
-	struct iwl_notif_wait_data notif_wait;
-
-	struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
-
-	/* spectrum measurement report caching */
-	struct iwl_spectrum_notification measure_report;
-	u8 measurement_status;
-
-#define IWL_OWNERSHIP_DRIVER	0
-#define IWL_OWNERSHIP_TM	1
-	u8 ucode_owner;
-
-	/* ucode beacon time */
-	u32 ucode_beacon_time;
-	int missed_beacon_threshold;
-
-	/* track IBSS manager (last beacon) status */
-	u32 ibss_manager;
-
-	/* jiffies when last recovery from statistics was performed */
-	unsigned long rx_statistics_jiffies;
-
-	/*counters */
-	u32 rx_handlers_stats[REPLY_MAX];
-
-	/* rf reset */
-	struct iwl_rf_reset rf_reset;
-
-	/* firmware reload counter and timestamp */
-	unsigned long reload_jiffies;
-	int reload_count;
-	bool ucode_loaded;
-	bool init_ucode_run;		/* Don't run init uCode again */
-
-	/* 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 */
-
-	u8 plcp_delta_threshold;
-
-	/* thermal calibration */
-	s32 temperature;	/* Celsius */
-	s32 last_temperature;
-
-	struct iwl_wipan_noa_data __rcu *noa_data;
-
-	/* Scan related variables */
-	unsigned long scan_start;
-	unsigned long scan_start_tsf;
-	void *scan_cmd;
-	enum ieee80211_band scan_band;
-	struct cfg80211_scan_request *scan_request;
-	struct ieee80211_vif *scan_vif;
-	enum iwl_scan_type scan_type;
-	u8 scan_tx_ant[IEEE80211_NUM_BANDS];
-	u8 mgmt_tx_ant;
-
-	/* max number of station keys */
-	u8 sta_key_max_num;
-
-	bool new_scan_threshold_behaviour;
-
-	bool wowlan;
-
-	/* EEPROM MAC addresses */
-	struct mac_address addresses[2];
-
-	struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
-
-	__le16 switch_channel;
-
-	u8 start_calib;
-	struct iwl_sensitivity_data sensitivity_data;
-	struct iwl_chain_noise_data chain_noise_data;
-	__le16 sensitivity_tbl[HD_TABLE_SIZE];
-	__le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES];
-
-	struct iwl_ht_config current_ht_config;
-
-	/* Rate scaling data */
-	u8 retry_rate;
-
-	int activity_timer_active;
-
-	struct iwl_power_mgr power_data;
-	struct iwl_tt_mgmt thermal_throttle;
-
-	/* station table variables */
-	int num_stations;
-	struct iwl_station_entry stations[IWLAGN_STATION_COUNT];
-	unsigned long ucode_key_table;
-	struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT];
-
-	u8 mac80211_registered;
-
-	/* Indication if ieee80211_ops->open has been called */
-	u8 is_open;
-
-	enum nl80211_iftype iw_mode;
-
-	/* Last Rx'd beacon timestamp */
-	u64 timestamp;
-
-	struct {
-		__le32 flag;
-		struct statistics_general_common common;
-		struct statistics_rx_non_phy rx_non_phy;
-		struct statistics_rx_phy rx_ofdm;
-		struct statistics_rx_ht_phy rx_ofdm_ht;
-		struct statistics_rx_phy rx_cck;
-		struct statistics_tx tx;
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-		struct statistics_bt_activity bt_activity;
-		__le32 num_bt_kills, accum_num_bt_kills;
-#endif
-		spinlock_t lock;
-	} statistics;
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-	struct {
-		struct statistics_general_common common;
-		struct statistics_rx_non_phy rx_non_phy;
-		struct statistics_rx_phy rx_ofdm;
-		struct statistics_rx_ht_phy rx_ofdm_ht;
-		struct statistics_rx_phy rx_cck;
-		struct statistics_tx tx;
-		struct statistics_bt_activity bt_activity;
-	} accum_stats, delta_stats, max_delta_stats;
-#endif
-
-	/*
-	 * reporting the number of tids has AGG on. 0 means
-	 * no AGGREGATION
-	 */
-	u8 agg_tids_count;
-
-	struct iwl_rx_phy_res last_phy_res;
-	bool last_phy_res_valid;
-
-	/*
-	 * 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;
-
-	/* counts reply_tx error */
-	struct reply_tx_error_statistics reply_tx_stats;
-	struct reply_agg_tx_error_statistics reply_agg_tx_stats;
-
-	/* remain-on-channel offload support */
-	struct ieee80211_channel *hw_roc_channel;
-	struct delayed_work hw_roc_disable_work;
-	enum nl80211_channel_type hw_roc_chantype;
-	int hw_roc_duration;
-	bool hw_roc_setup, hw_roc_start_notified;
-
-	/* bt coex */
-	u8 bt_enable_flag;
-	u8 bt_status;
-	u8 bt_traffic_load, last_bt_traffic_load;
-	bool bt_ch_announce;
-	bool bt_full_concurrent;
-	bool bt_ant_couple_ok;
-	__le32 kill_ack_mask;
-	__le32 kill_cts_mask;
-	__le16 bt_valid;
-	bool reduced_txpower;
-	u16 bt_on_thresh;
-	u16 bt_duration;
-	u16 dynamic_frag_thresh;
-	u8 bt_ci_compliance;
-	struct work_struct bt_traffic_change_work;
-	bool bt_enable_pspoll;
-	struct iwl_rxon_context *cur_rssi_ctx;
-	bool bt_is_sco;
-
-	struct work_struct restart;
-	struct work_struct scan_completed;
-	struct work_struct abort_scan;
-
-	struct work_struct beacon_update;
-	struct iwl_rxon_context *beacon_ctx;
-	struct sk_buff *beacon_skb;
-	void *beacon_cmd;
-
-	struct work_struct tt_work;
-	struct work_struct ct_enter;
-	struct work_struct ct_exit;
-	struct work_struct start_internal_scan;
-	struct work_struct tx_flush;
-	struct work_struct bt_full_concurrency;
-	struct work_struct bt_runtime_config;
-
-	struct delayed_work scan_check;
-
-	/* TX Power */
-	s8 tx_power_user_lmt;
-	s8 tx_power_device_lmt;
-	s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */
-	s8 tx_power_next;
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-	/* debugfs */
-	struct dentry *debugfs_dir;
-	u32 dbgfs_sram_offset, dbgfs_sram_len;
-	bool disable_ht40;
-	void *wowlan_sram;
-#endif /* CONFIG_IWLWIFI_DEBUGFS */
-
-	/* eeprom -- this is in the card's little endian byte order */
-	u8 *eeprom;
-	enum iwl_nvm_type nvm_device_type;
-
-	struct work_struct txpower_work;
-	u32 calib_disabled;
-	struct work_struct run_time_calib_work;
-	struct timer_list statistics_periodic;
-	struct timer_list ucode_trace;
-
-	struct iwl_event_log event_log;
-
-	struct led_classdev led;
-	unsigned long blink_on, blink_off;
-	bool led_registered;
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-	struct iwl_testmode_trace testmode_trace;
-	struct iwl_testmode_mem testmode_mem;
-	u32 tm_fixed_rate;
-#endif
-
-	/* WoWLAN GTK rekey data */
-	u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN];
-	__le64 replay_ctr;
-	__le16 last_seq_ctl;
-	bool have_rekey_data;
-
-	/* device_pointers: pointers to ucode event tables */
-	struct {
-		u32 error_event_table;
-		u32 log_event_table;
-	} device_pointers;
-
-	/* indicator of loaded ucode image */
-	enum iwl_ucode_type cur_ucode;
-}; /*iwl_priv */
-
-extern struct kmem_cache *iwl_tx_cmd_pool;
-
-static inline struct iwl_rxon_context *
-iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif)
-{
-	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-
-	return vif_priv->ctx;
-}
-
-#define for_each_context(priv, ctx)				\
-	for (ctx = &priv->contexts[IWL_RXON_CTX_BSS];		\
-	     ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++)	\
-		if (priv->valid_contexts & BIT(ctx->ctxid))
-
-static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
-{
-	return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
-}
-
-static inline int iwl_is_associated(struct iwl_priv *priv,
-				    enum iwl_rxon_context_id ctxid)
-{
-	return iwl_is_associated_ctx(&priv->contexts[ctxid]);
-}
-
-static inline int iwl_is_any_associated(struct iwl_priv *priv)
-{
-	struct iwl_rxon_context *ctx;
-	for_each_context(priv, ctx)
-		if (iwl_is_associated_ctx(ctx))
-			return true;
-	return false;
-}
-
-static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
-{
-	if (ch_info == NULL)
-		return 0;
-	return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
-}
-
-static inline int is_channel_radar(const struct iwl_channel_info *ch_info)
-{
-	return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
-}
-
-static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info)
-{
-	return ch_info->band == IEEE80211_BAND_5GHZ;
-}
-
-static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info)
-{
-	return ch_info->band == IEEE80211_BAND_2GHZ;
-}
-
-static inline int is_channel_passive(const struct iwl_channel_info *ch)
-{
-	return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
-}
-
-static inline int is_channel_ibss(const struct iwl_channel_info *ch)
-{
-	return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
-}
-
-#endif				/* __iwl_dev_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
index 91f45e7..70191dd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -42,4 +42,9 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_info);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_warn);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_crit);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_err);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dbg);
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index 06203d6..6536479 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -28,6 +28,7 @@
 #define __IWLWIFI_DEVICE_TRACE
 
 #include <linux/tracepoint.h>
+#include <linux/device.h>
 
 
 #if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index fac67a5..a175997 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -77,8 +77,33 @@
 /* private includes */
 #include "iwl-fw-file.h"
 
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/*
+ * module name, copyright, version, etc.
+ */
+#define DRV_DESCRIPTION	"Intel(R) Wireless WiFi driver for Linux"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#define DRV_VERSION     IWLWIFI_VERSION VD
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
+MODULE_LICENSE("GPL");
+
 /**
  * struct iwl_drv - drv common data
+ * @list: list of drv structures using this opmode
  * @fw: the iwl_fw structure
  * @op_mode: the running op_mode
  * @trans: transport layer
@@ -89,6 +114,7 @@
  * @request_firmware_complete: the firmware has been obtained from user space
  */
 struct iwl_drv {
+	struct list_head list;
 	struct iwl_fw fw;
 
 	struct iwl_op_mode *op_mode;
@@ -102,7 +128,19 @@ struct iwl_drv {
 	struct completion request_firmware_complete;
 };
 
-
+#define DVM_OP_MODE	0
+#define MVM_OP_MODE	1
+
+/* Protects the table contents, i.e. the ops pointer & drv list */
+static struct mutex iwlwifi_opmode_table_mtx;
+static struct iwlwifi_opmode_table {
+	const char *name;			/* name: iwldvm, iwlmvm, etc */
+	const struct iwl_op_mode_ops *ops;	/* pointer to op_mode ops */
+	struct list_head drv;		/* list of devices using this op_mode */
+} iwlwifi_opmode_table[] = {		/* ops set when driver is initialized */
+	{ .name = "iwldvm", .ops = NULL },
+	{ .name = "iwlmvm", .ops = NULL },
+};
 
 /*
  * struct fw_sec: Just for the image parsing proccess.
@@ -721,7 +759,6 @@ static int validate_sec_sizes(struct iwl_drv *drv,
 	return 0;
 }
 
-
 /**
  * iwl_ucode_callback - callback when firmware was loaded
  *
@@ -733,6 +770,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	struct iwl_drv *drv = context;
 	struct iwl_fw *fw = &drv->fw;
 	struct iwl_ucode_header *ucode;
+	struct iwlwifi_opmode_table *op;
 	int err;
 	struct iwl_firmware_pieces pieces;
 	const unsigned int api_max = drv->cfg->ucode_api_max;
@@ -740,6 +778,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	const unsigned int api_min = drv->cfg->ucode_api_min;
 	u32 api_ver;
 	int i;
+	bool load_module = false;
 
 	fw->ucode_capa.max_probe_length = 200;
 	fw->ucode_capa.standard_phy_calibration_size =
@@ -862,10 +901,24 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	/* We have our copies now, allow OS release its copies */
 	release_firmware(ucode_raw);
 
-	drv->op_mode = iwl_dvm_ops.start(drv->trans, drv->cfg, &drv->fw);
+	mutex_lock(&iwlwifi_opmode_table_mtx);
+	op = &iwlwifi_opmode_table[DVM_OP_MODE];
 
-	if (!drv->op_mode)
-		goto out_unbind;
+	/* add this device to the list of devices using this op_mode */
+	list_add_tail(&drv->list, &op->drv);
+
+	if (op->ops) {
+		const struct iwl_op_mode_ops *ops = op->ops;
+		drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw);
+
+		if (!drv->op_mode) {
+			mutex_unlock(&iwlwifi_opmode_table_mtx);
+			goto out_unbind;
+		}
+	} else {
+		load_module = true;
+	}
+	mutex_unlock(&iwlwifi_opmode_table_mtx);
 
 	/*
 	 * Complete the firmware request last so that
@@ -873,6 +926,14 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	 * are doing the start() above.
 	 */
 	complete(&drv->request_firmware_complete);
+
+	/*
+	 * Load the module last so we don't block anything
+	 * else from proceeding if the module fails to load
+	 * or hangs loading.
+	 */
+	if (load_module)
+		request_module("%s", op->name);
 	return;
 
  try_again:
@@ -906,6 +967,7 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans,
 	drv->cfg = cfg;
 
 	init_completion(&drv->request_firmware_complete);
+	INIT_LIST_HEAD(&drv->list);
 
 	ret = iwl_request_firmware(drv, true);
 
@@ -928,6 +990,16 @@ void iwl_drv_stop(struct iwl_drv *drv)
 
 	iwl_dealloc_ucode(drv);
 
+	mutex_lock(&iwlwifi_opmode_table_mtx);
+	/*
+	 * List is empty (this item wasn't added)
+	 * when firmware loading failed -- in that
+	 * case we can't remove it from any list.
+	 */
+	if (!list_empty(&drv->list))
+		list_del(&drv->list);
+	mutex_unlock(&iwlwifi_opmode_table_mtx);
+
 	kfree(drv);
 }
 
@@ -943,6 +1015,75 @@ struct iwl_mod_params iwlwifi_mod_params = {
 	.auto_agg = true,
 	/* the rest are 0 by default */
 };
+EXPORT_SYMBOL_GPL(iwlwifi_mod_params);
+
+int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
+{
+	int i;
+	struct iwl_drv *drv;
+
+	mutex_lock(&iwlwifi_opmode_table_mtx);
+	for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) {
+		if (strcmp(iwlwifi_opmode_table[i].name, name))
+			continue;
+		iwlwifi_opmode_table[i].ops = ops;
+		list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list)
+			drv->op_mode = ops->start(drv->trans, drv->cfg,
+						  &drv->fw);
+		mutex_unlock(&iwlwifi_opmode_table_mtx);
+		return 0;
+	}
+	mutex_unlock(&iwlwifi_opmode_table_mtx);
+	return -EIO;
+}
+EXPORT_SYMBOL_GPL(iwl_opmode_register);
+
+void iwl_opmode_deregister(const char *name)
+{
+	int i;
+	struct iwl_drv *drv;
+
+	mutex_lock(&iwlwifi_opmode_table_mtx);
+	for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) {
+		if (strcmp(iwlwifi_opmode_table[i].name, name))
+			continue;
+		iwlwifi_opmode_table[i].ops = NULL;
+
+		/* call the stop routine for all devices */
+		list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) {
+			if (drv->op_mode) {
+				iwl_op_mode_stop(drv->op_mode);
+				drv->op_mode = NULL;
+			}
+		}
+		mutex_unlock(&iwlwifi_opmode_table_mtx);
+		return;
+	}
+	mutex_unlock(&iwlwifi_opmode_table_mtx);
+}
+EXPORT_SYMBOL_GPL(iwl_opmode_deregister);
+
+static int __init iwl_drv_init(void)
+{
+	int i;
+
+	mutex_init(&iwlwifi_opmode_table_mtx);
+
+	for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++)
+		INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv);
+
+	pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+	pr_info(DRV_COPYRIGHT "\n");
+
+	return iwl_pci_register_driver();
+}
+module_init(iwl_drv_init);
+
+static void __exit iwl_drv_exit(void)
+{
+	iwl_pci_unregister_driver();
+}
+module_exit(iwl_drv_exit);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 module_param_named(debug, iwlwifi_mod_params.debug_level, uint,
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
new file mode 100644
index 0000000..f10170f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
@@ -0,0 +1,903 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include "iwl-modparams.h"
+#include "iwl-eeprom-parse.h"
+
+/* EEPROM offset definitions */
+
+/* indirect access definitions */
+#define ADDRESS_MSK                 0x0000FFFF
+#define INDIRECT_TYPE_MSK           0x000F0000
+#define INDIRECT_HOST               0x00010000
+#define INDIRECT_GENERAL            0x00020000
+#define INDIRECT_REGULATORY         0x00030000
+#define INDIRECT_CALIBRATION        0x00040000
+#define INDIRECT_PROCESS_ADJST      0x00050000
+#define INDIRECT_OTHERS             0x00060000
+#define INDIRECT_TXP_LIMIT          0x00070000
+#define INDIRECT_TXP_LIMIT_SIZE     0x00080000
+#define INDIRECT_ADDRESS            0x00100000
+
+/* corresponding link offsets in EEPROM */
+#define EEPROM_LINK_HOST             (2*0x64)
+#define EEPROM_LINK_GENERAL          (2*0x65)
+#define EEPROM_LINK_REGULATORY       (2*0x66)
+#define EEPROM_LINK_CALIBRATION      (2*0x67)
+#define EEPROM_LINK_PROCESS_ADJST    (2*0x68)
+#define EEPROM_LINK_OTHERS           (2*0x69)
+#define EEPROM_LINK_TXP_LIMIT        (2*0x6a)
+#define EEPROM_LINK_TXP_LIMIT_SIZE   (2*0x6b)
+
+/* General */
+#define EEPROM_DEVICE_ID                    (2*0x08)	/* 2 bytes */
+#define EEPROM_SUBSYSTEM_ID		    (2*0x0A)	/* 2 bytes */
+#define EEPROM_MAC_ADDRESS                  (2*0x15)	/* 6  bytes */
+#define EEPROM_BOARD_REVISION               (2*0x35)	/* 2  bytes */
+#define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1)	/* 9  bytes */
+#define EEPROM_VERSION                      (2*0x44)	/* 2  bytes */
+#define EEPROM_SKU_CAP                      (2*0x45)	/* 2  bytes */
+#define EEPROM_OEM_MODE                     (2*0x46)	/* 2  bytes */
+#define EEPROM_RADIO_CONFIG                 (2*0x48)	/* 2  bytes */
+#define EEPROM_NUM_MAC_ADDRESS              (2*0x4C)	/* 2  bytes */
+
+/* calibration */
+struct iwl_eeprom_calib_hdr {
+	u8 version;
+	u8 pa_type;
+	__le16 voltage;
+} __packed;
+
+#define EEPROM_CALIB_ALL	(INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
+#define EEPROM_XTAL		((2*0x128) | EEPROM_CALIB_ALL)
+
+/* temperature */
+#define EEPROM_KELVIN_TEMPERATURE	((2*0x12A) | EEPROM_CALIB_ALL)
+#define EEPROM_RAW_TEMPERATURE		((2*0x12B) | EEPROM_CALIB_ALL)
+
+/*
+ * EEPROM bands
+ * These are the channel numbers from each band in the order
+ * that they are stored in the EEPROM band information. Note
+ * that EEPROM bands aren't the same as mac80211 bands, and
+ * there are even special "ht40 bands" in the EEPROM.
+ */
+static const u8 iwl_eeprom_band_1[14] = { /* 2.4 GHz */
+	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+static const u8 iwl_eeprom_band_2[] = {	/* 4915-5080MHz */
+	183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
+};
+
+static const u8 iwl_eeprom_band_3[] = {	/* 5170-5320MHz */
+	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+};
+
+static const u8 iwl_eeprom_band_4[] = {	/* 5500-5700MHz */
+	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+};
+
+static const u8 iwl_eeprom_band_5[] = {	/* 5725-5825MHz */
+	145, 149, 153, 157, 161, 165
+};
+
+static const u8 iwl_eeprom_band_6[] = {	/* 2.4 ht40 channel */
+	1, 2, 3, 4, 5, 6, 7
+};
+
+static const u8 iwl_eeprom_band_7[] = {	/* 5.2 ht40 channel */
+	36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
+};
+
+#define IWL_NUM_CHANNELS	(ARRAY_SIZE(iwl_eeprom_band_1) + \
+				 ARRAY_SIZE(iwl_eeprom_band_2) + \
+				 ARRAY_SIZE(iwl_eeprom_band_3) + \
+				 ARRAY_SIZE(iwl_eeprom_band_4) + \
+				 ARRAY_SIZE(iwl_eeprom_band_5))
+
+/* rate data (static) */
+static struct ieee80211_rate iwl_cfg80211_rates[] = {
+	{ .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, },
+	{ .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+	{ .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+	{ .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+	{ .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, },
+	{ .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, },
+	{ .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, },
+	{ .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, },
+	{ .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, },
+	{ .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, },
+	{ .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, },
+	{ .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, },
+};
+#define RATES_24_OFFS	0
+#define N_RATES_24	ARRAY_SIZE(iwl_cfg80211_rates)
+#define RATES_52_OFFS	4
+#define N_RATES_52	(N_RATES_24 - RATES_52_OFFS)
+
+/* EEPROM reading functions */
+
+static u16 iwl_eeprom_query16(const u8 *eeprom, size_t eeprom_size, int offset)
+{
+	if (WARN_ON(offset + sizeof(u16) > eeprom_size))
+		return 0;
+	return le16_to_cpup((__le16 *)(eeprom + offset));
+}
+
+static u32 eeprom_indirect_address(const u8 *eeprom, size_t eeprom_size,
+				   u32 address)
+{
+	u16 offset = 0;
+
+	if ((address & INDIRECT_ADDRESS) == 0)
+		return address;
+
+	switch (address & INDIRECT_TYPE_MSK) {
+	case INDIRECT_HOST:
+		offset = iwl_eeprom_query16(eeprom, eeprom_size,
+					    EEPROM_LINK_HOST);
+		break;
+	case INDIRECT_GENERAL:
+		offset = iwl_eeprom_query16(eeprom, eeprom_size,
+					    EEPROM_LINK_GENERAL);
+		break;
+	case INDIRECT_REGULATORY:
+		offset = iwl_eeprom_query16(eeprom, eeprom_size,
+					    EEPROM_LINK_REGULATORY);
+		break;
+	case INDIRECT_TXP_LIMIT:
+		offset = iwl_eeprom_query16(eeprom, eeprom_size,
+					    EEPROM_LINK_TXP_LIMIT);
+		break;
+	case INDIRECT_TXP_LIMIT_SIZE:
+		offset = iwl_eeprom_query16(eeprom, eeprom_size,
+					    EEPROM_LINK_TXP_LIMIT_SIZE);
+		break;
+	case INDIRECT_CALIBRATION:
+		offset = iwl_eeprom_query16(eeprom, eeprom_size,
+					    EEPROM_LINK_CALIBRATION);
+		break;
+	case INDIRECT_PROCESS_ADJST:
+		offset = iwl_eeprom_query16(eeprom, eeprom_size,
+					    EEPROM_LINK_PROCESS_ADJST);
+		break;
+	case INDIRECT_OTHERS:
+		offset = iwl_eeprom_query16(eeprom, eeprom_size,
+					    EEPROM_LINK_OTHERS);
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+
+	/* translate the offset from words to byte */
+	return (address & ADDRESS_MSK) + (offset << 1);
+}
+
+static const u8 *iwl_eeprom_query_addr(const u8 *eeprom, size_t eeprom_size,
+				       u32 offset)
+{
+	u32 address = eeprom_indirect_address(eeprom, eeprom_size, offset);
+
+	if (WARN_ON(address >= eeprom_size))
+		return NULL;
+
+	return &eeprom[address];
+}
+
+static int iwl_eeprom_read_calib(const u8 *eeprom, size_t eeprom_size,
+				 struct iwl_eeprom_data *data)
+{
+	struct iwl_eeprom_calib_hdr *hdr;
+
+	hdr = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size,
+					    EEPROM_CALIB_ALL);
+	if (!hdr)
+		return -ENODATA;
+	data->calib_version = hdr->version;
+	data->calib_voltage = hdr->voltage;
+
+	return 0;
+}
+
+/**
+ * enum iwl_eeprom_channel_flags - channel flags in EEPROM
+ * @EEPROM_CHANNEL_VALID: channel is usable for this SKU/geo
+ * @EEPROM_CHANNEL_IBSS: usable as an IBSS channel
+ * @EEPROM_CHANNEL_ACTIVE: active scanning allowed
+ * @EEPROM_CHANNEL_RADAR: radar detection required
+ * @EEPROM_CHANNEL_WIDE: 20 MHz channel okay (?)
+ * @EEPROM_CHANNEL_DFS: dynamic freq selection candidate
+ */
+enum iwl_eeprom_channel_flags {
+	EEPROM_CHANNEL_VALID = BIT(0),
+	EEPROM_CHANNEL_IBSS = BIT(1),
+	EEPROM_CHANNEL_ACTIVE = BIT(3),
+	EEPROM_CHANNEL_RADAR = BIT(4),
+	EEPROM_CHANNEL_WIDE = BIT(5),
+	EEPROM_CHANNEL_DFS = BIT(7),
+};
+
+/**
+ * struct iwl_eeprom_channel - EEPROM channel data
+ * @flags: %EEPROM_CHANNEL_* flags
+ * @max_power_avg: max power (in dBm) on this channel, at most 31 dBm
+ */
+struct iwl_eeprom_channel {
+	u8 flags;
+	s8 max_power_avg;
+} __packed;
+
+
+enum iwl_eeprom_enhanced_txpwr_flags {
+	IWL_EEPROM_ENH_TXP_FL_VALID = BIT(0),
+	IWL_EEPROM_ENH_TXP_FL_BAND_52G = BIT(1),
+	IWL_EEPROM_ENH_TXP_FL_OFDM = BIT(2),
+	IWL_EEPROM_ENH_TXP_FL_40MHZ = BIT(3),
+	IWL_EEPROM_ENH_TXP_FL_HT_AP = BIT(4),
+	IWL_EEPROM_ENH_TXP_FL_RES1 = BIT(5),
+	IWL_EEPROM_ENH_TXP_FL_RES2 = BIT(6),
+	IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE = BIT(7),
+};
+
+/**
+ * iwl_eeprom_enhanced_txpwr structure
+ * @flags: entry flags
+ * @channel: channel number
+ * @chain_a_max_pwr: chain a max power in 1/2 dBm
+ * @chain_b_max_pwr: chain b max power in 1/2 dBm
+ * @chain_c_max_pwr: chain c max power in 1/2 dBm
+ * @delta_20_in_40: 20-in-40 deltas (hi/lo)
+ * @mimo2_max_pwr: mimo2 max power in 1/2 dBm
+ * @mimo3_max_pwr: mimo3 max power in 1/2 dBm
+ *
+ * This structure presents the enhanced regulatory tx power limit layout
+ * in an EEPROM image.
+ */
+struct iwl_eeprom_enhanced_txpwr {
+	u8 flags;
+	u8 channel;
+	s8 chain_a_max;
+	s8 chain_b_max;
+	s8 chain_c_max;
+	u8 delta_20_in_40;
+	s8 mimo2_max;
+	s8 mimo3_max;
+} __packed;
+
+static s8 iwl_get_max_txpwr_half_dbm(const struct iwl_eeprom_data *data,
+				     struct iwl_eeprom_enhanced_txpwr *txp)
+{
+	s8 result = 0; /* (.5 dBm) */
+
+	/* Take the highest tx power from any valid chains */
+	if (data->valid_tx_ant & ANT_A && txp->chain_a_max > result)
+		result = txp->chain_a_max;
+
+	if (data->valid_tx_ant & ANT_B && txp->chain_b_max > result)
+		result = txp->chain_b_max;
+
+	if (data->valid_tx_ant & ANT_C && txp->chain_c_max > result)
+		result = txp->chain_c_max;
+
+	if ((data->valid_tx_ant == ANT_AB ||
+	     data->valid_tx_ant == ANT_BC ||
+	     data->valid_tx_ant == ANT_AC) && txp->mimo2_max > result)
+		result = txp->mimo2_max;
+
+	if (data->valid_tx_ant == ANT_ABC && txp->mimo3_max > result)
+		result = txp->mimo3_max;
+
+	return result;
+}
+
+#define EEPROM_TXP_OFFS	(0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT)
+#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr)
+#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE)
+
+#define TXP_CHECK_AND_PRINT(x) \
+	((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) ? # x " " : "")
+
+static void
+iwl_eeprom_enh_txp_read_element(struct iwl_eeprom_data *data,
+				struct iwl_eeprom_enhanced_txpwr *txp,
+				int n_channels, s8 max_txpower_avg)
+{
+	int ch_idx;
+	enum ieee80211_band band;
+
+	band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ?
+		IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
+
+	for (ch_idx = 0; ch_idx < n_channels; ch_idx++) {
+		struct ieee80211_channel *chan = &data->channels[ch_idx];
+
+		/* update matching channel or from common data only */
+		if (txp->channel != 0 && chan->hw_value != txp->channel)
+			continue;
+
+		/* update matching band only */
+		if (band != chan->band)
+			continue;
+
+		if (chan->max_power < max_txpower_avg &&
+		    !(txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ))
+			chan->max_power = max_txpower_avg;
+	}
+}
+
+static void iwl_eeprom_enhanced_txpower(struct device *dev,
+					struct iwl_eeprom_data *data,
+					const u8 *eeprom, size_t eeprom_size,
+					int n_channels)
+{
+	struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
+	int idx, entries;
+	__le16 *txp_len;
+	s8 max_txp_avg_halfdbm;
+
+	BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
+
+	/* the length is in 16-bit words, but we want entries */
+	txp_len = (__le16 *)iwl_eeprom_query_addr(eeprom, eeprom_size,
+						  EEPROM_TXP_SZ_OFFS);
+	entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
+
+	txp_array = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size,
+						  EEPROM_TXP_OFFS);
+
+	for (idx = 0; idx < entries; idx++) {
+		txp = &txp_array[idx];
+		/* skip invalid entries */
+		if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID))
+			continue;
+
+		IWL_DEBUG_EEPROM(dev, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n",
+				 (txp->channel && (txp->flags &
+					IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ?
+					"Common " : (txp->channel) ?
+					"Channel" : "Common",
+				 (txp->channel),
+				 TXP_CHECK_AND_PRINT(VALID),
+				 TXP_CHECK_AND_PRINT(BAND_52G),
+				 TXP_CHECK_AND_PRINT(OFDM),
+				 TXP_CHECK_AND_PRINT(40MHZ),
+				 TXP_CHECK_AND_PRINT(HT_AP),
+				 TXP_CHECK_AND_PRINT(RES1),
+				 TXP_CHECK_AND_PRINT(RES2),
+				 TXP_CHECK_AND_PRINT(COMMON_TYPE),
+				 txp->flags);
+		IWL_DEBUG_EEPROM(dev,
+				 "\t\t chain_A: 0x%02x chain_B: 0X%02x chain_C: 0X%02x\n",
+				 txp->chain_a_max, txp->chain_b_max,
+				 txp->chain_c_max);
+		IWL_DEBUG_EEPROM(dev,
+				 "\t\t MIMO2: 0x%02x MIMO3: 0x%02x High 20_on_40: 0x%02x Low 20_on_40: 0x%02x\n",
+				 txp->mimo2_max, txp->mimo3_max,
+				 ((txp->delta_20_in_40 & 0xf0) >> 4),
+				 (txp->delta_20_in_40 & 0x0f));
+
+		max_txp_avg_halfdbm = iwl_get_max_txpwr_half_dbm(data, txp);
+
+		iwl_eeprom_enh_txp_read_element(data, txp, n_channels,
+				DIV_ROUND_UP(max_txp_avg_halfdbm, 2));
+
+		if (max_txp_avg_halfdbm > data->max_tx_pwr_half_dbm)
+			data->max_tx_pwr_half_dbm = max_txp_avg_halfdbm;
+	}
+}
+
+static void iwl_init_band_reference(const struct iwl_cfg *cfg,
+				    const u8 *eeprom, size_t eeprom_size,
+				    int eeprom_band, int *eeprom_ch_count,
+				    const struct iwl_eeprom_channel **ch_info,
+				    const u8 **eeprom_ch_array)
+{
+	u32 offset = cfg->eeprom_params->regulatory_bands[eeprom_band - 1];
+
+	offset |= INDIRECT_ADDRESS | INDIRECT_REGULATORY;
+
+	*ch_info = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size, offset);
+
+	switch (eeprom_band) {
+	case 1:		/* 2.4GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
+		*eeprom_ch_array = iwl_eeprom_band_1;
+		break;
+	case 2:		/* 4.9GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
+		*eeprom_ch_array = iwl_eeprom_band_2;
+		break;
+	case 3:		/* 5.2GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
+		*eeprom_ch_array = iwl_eeprom_band_3;
+		break;
+	case 4:		/* 5.5GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
+		*eeprom_ch_array = iwl_eeprom_band_4;
+		break;
+	case 5:		/* 5.7GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
+		*eeprom_ch_array = iwl_eeprom_band_5;
+		break;
+	case 6:		/* 2.4GHz ht40 channels */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
+		*eeprom_ch_array = iwl_eeprom_band_6;
+		break;
+	case 7:		/* 5 GHz ht40 channels */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
+		*eeprom_ch_array = iwl_eeprom_band_7;
+		break;
+	default:
+		*eeprom_ch_count = 0;
+		*eeprom_ch_array = NULL;
+		WARN_ON(1);
+	}
+}
+
+#define CHECK_AND_PRINT(x) \
+	((eeprom_ch->flags & EEPROM_CHANNEL_##x) ? # x " " : "")
+
+static void iwl_mod_ht40_chan_info(struct device *dev,
+				   struct iwl_eeprom_data *data, int n_channels,
+				   enum ieee80211_band band, u16 channel,
+				   const struct iwl_eeprom_channel *eeprom_ch,
+				   u8 clear_ht40_extension_channel)
+{
+	struct ieee80211_channel *chan = NULL;
+	int i;
+
+	for (i = 0; i < n_channels; i++) {
+		if (data->channels[i].band != band)
+			continue;
+		if (data->channels[i].hw_value != channel)
+			continue;
+		chan = &data->channels[i];
+		break;
+	}
+
+	if (!chan)
+		return;
+
+	IWL_DEBUG_EEPROM(dev,
+			 "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
+			 channel,
+			 band == IEEE80211_BAND_5GHZ ? "5.2" : "2.4",
+			 CHECK_AND_PRINT(IBSS),
+			 CHECK_AND_PRINT(ACTIVE),
+			 CHECK_AND_PRINT(RADAR),
+			 CHECK_AND_PRINT(WIDE),
+			 CHECK_AND_PRINT(DFS),
+			 eeprom_ch->flags,
+			 eeprom_ch->max_power_avg,
+			 ((eeprom_ch->flags & EEPROM_CHANNEL_IBSS) &&
+			  !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? ""
+								      : "not ");
+
+	if (eeprom_ch->flags & EEPROM_CHANNEL_VALID)
+		chan->flags &= ~clear_ht40_extension_channel;
+}
+
+#define CHECK_AND_PRINT_I(x)	\
+	((eeprom_ch_info[ch_idx].flags & EEPROM_CHANNEL_##x) ? # x " " : "")
+
+static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
+				struct iwl_eeprom_data *data,
+				const u8 *eeprom, size_t eeprom_size)
+{
+	int band, ch_idx;
+	const struct iwl_eeprom_channel *eeprom_ch_info;
+	const u8 *eeprom_ch_array;
+	int eeprom_ch_count;
+	int n_channels = 0;
+
+	/*
+	 * Loop through the 5 EEPROM bands and add them to the parse list
+	 */
+	for (band = 1; band <= 5; band++) {
+		struct ieee80211_channel *channel;
+
+		iwl_init_band_reference(cfg, eeprom, eeprom_size, band,
+					&eeprom_ch_count, &eeprom_ch_info,
+					&eeprom_ch_array);
+
+		/* Loop through each band adding each of the channels */
+		for (ch_idx = 0; ch_idx < eeprom_ch_count; ch_idx++) {
+			const struct iwl_eeprom_channel *eeprom_ch;
+
+			eeprom_ch = &eeprom_ch_info[ch_idx];
+
+			if (!(eeprom_ch->flags & EEPROM_CHANNEL_VALID)) {
+				IWL_DEBUG_EEPROM(dev,
+						 "Ch. %d Flags %x [%sGHz] - No traffic\n",
+						 eeprom_ch_array[ch_idx],
+						 eeprom_ch_info[ch_idx].flags,
+						 (band != 1) ? "5.2" : "2.4");
+				continue;
+			}
+
+			channel = &data->channels[n_channels];
+			n_channels++;
+
+			channel->hw_value = eeprom_ch_array[ch_idx];
+			channel->band = (band == 1) ? IEEE80211_BAND_2GHZ
+						    : IEEE80211_BAND_5GHZ;
+			channel->center_freq =
+				ieee80211_channel_to_frequency(
+					channel->hw_value, channel->band);
+
+			/* set no-HT40, will enable as appropriate later */
+			channel->flags = IEEE80211_CHAN_NO_HT40;
+
+			if (!(eeprom_ch->flags & EEPROM_CHANNEL_IBSS))
+				channel->flags |= IEEE80211_CHAN_NO_IBSS;
+
+			if (!(eeprom_ch->flags & EEPROM_CHANNEL_ACTIVE))
+				channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+			if (eeprom_ch->flags & EEPROM_CHANNEL_RADAR)
+				channel->flags |= IEEE80211_CHAN_RADAR;
+
+			/* Initialize regulatory-based run-time data */
+			channel->max_power =
+				eeprom_ch_info[ch_idx].max_power_avg;
+			IWL_DEBUG_EEPROM(dev,
+					 "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
+					 channel->hw_value,
+					 (band != 1) ? "5.2" : "2.4",
+					 CHECK_AND_PRINT_I(VALID),
+					 CHECK_AND_PRINT_I(IBSS),
+					 CHECK_AND_PRINT_I(ACTIVE),
+					 CHECK_AND_PRINT_I(RADAR),
+					 CHECK_AND_PRINT_I(WIDE),
+					 CHECK_AND_PRINT_I(DFS),
+					 eeprom_ch_info[ch_idx].flags,
+					 eeprom_ch_info[ch_idx].max_power_avg,
+					 ((eeprom_ch_info[ch_idx].flags &
+							EEPROM_CHANNEL_IBSS) &&
+					  !(eeprom_ch_info[ch_idx].flags &
+							EEPROM_CHANNEL_RADAR))
+						? "" : "not ");
+		}
+	}
+
+	if (cfg->eeprom_params->enhanced_txpower) {
+		/*
+		 * for newer device (6000 series and up)
+		 * EEPROM contain enhanced tx power information
+		 * driver need to process addition information
+		 * to determine the max channel tx power limits
+		 */
+		iwl_eeprom_enhanced_txpower(dev, data, eeprom, eeprom_size,
+					    n_channels);
+	} else {
+		/* All others use data from channel map */
+		int i;
+
+		data->max_tx_pwr_half_dbm = -128;
+
+		for (i = 0; i < n_channels; i++)
+			data->max_tx_pwr_half_dbm =
+				max_t(s8, data->max_tx_pwr_half_dbm,
+				      data->channels[i].max_power * 2);
+	}
+
+	/* Check if we do have HT40 channels */
+	if (cfg->eeprom_params->regulatory_bands[5] ==
+				EEPROM_REGULATORY_BAND_NO_HT40 &&
+	    cfg->eeprom_params->regulatory_bands[6] ==
+				EEPROM_REGULATORY_BAND_NO_HT40)
+		return n_channels;
+
+	/* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
+	for (band = 6; band <= 7; band++) {
+		enum ieee80211_band ieeeband;
+
+		iwl_init_band_reference(cfg, eeprom, eeprom_size, band,
+					&eeprom_ch_count, &eeprom_ch_info,
+					&eeprom_ch_array);
+
+		/* EEPROM band 6 is 2.4, band 7 is 5 GHz */
+		ieeeband = (band == 6) ? IEEE80211_BAND_2GHZ
+				       : IEEE80211_BAND_5GHZ;
+
+		/* Loop through each band adding each of the channels */
+		for (ch_idx = 0; ch_idx < eeprom_ch_count; ch_idx++) {
+			/* Set up driver's info for lower half */
+			iwl_mod_ht40_chan_info(dev, data, n_channels, ieeeband,
+					       eeprom_ch_array[ch_idx],
+					       &eeprom_ch_info[ch_idx],
+					       IEEE80211_CHAN_NO_HT40PLUS);
+
+			/* Set up driver's info for upper half */
+			iwl_mod_ht40_chan_info(dev, data, n_channels, ieeeband,
+					       eeprom_ch_array[ch_idx] + 4,
+					       &eeprom_ch_info[ch_idx],
+					       IEEE80211_CHAN_NO_HT40MINUS);
+		}
+	}
+
+	return n_channels;
+}
+
+static int iwl_init_sband_channels(struct iwl_eeprom_data *data,
+				   struct ieee80211_supported_band *sband,
+				   int n_channels, enum ieee80211_band band)
+{
+	struct ieee80211_channel *chan = &data->channels[0];
+	int n = 0, idx = 0;
+
+	while (chan->band != band && idx < n_channels)
+		chan = &data->channels[++idx];
+
+	sband->channels = &data->channels[idx];
+
+	while (chan->band == band && idx < n_channels) {
+		chan = &data->channels[++idx];
+		n++;
+	}
+
+	sband->n_channels = n;
+
+	return n;
+}
+
+#define MAX_BIT_RATE_40_MHZ	150 /* Mbps */
+#define MAX_BIT_RATE_20_MHZ	72 /* Mbps */
+
+static void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
+				 struct iwl_eeprom_data *data,
+				 struct ieee80211_sta_ht_cap *ht_info,
+				 enum ieee80211_band band)
+{
+	int max_bit_rate = 0;
+	u8 rx_chains;
+	u8 tx_chains;
+
+	tx_chains = hweight8(data->valid_tx_ant);
+	if (cfg->rx_with_siso_diversity)
+		rx_chains = 1;
+	else
+		rx_chains = hweight8(data->valid_rx_ant);
+
+	if (!(data->sku & EEPROM_SKU_CAP_11N_ENABLE) || !cfg->ht_params) {
+		ht_info->ht_supported = false;
+		return;
+	}
+
+	ht_info->ht_supported = true;
+	ht_info->cap = 0;
+
+	if (iwlwifi_mod_params.amsdu_size_8K)
+		ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+
+	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
+
+	ht_info->mcs.rx_mask[0] = 0xFF;
+	if (rx_chains >= 2)
+		ht_info->mcs.rx_mask[1] = 0xFF;
+	if (rx_chains >= 3)
+		ht_info->mcs.rx_mask[2] = 0xFF;
+
+	if (cfg->ht_params->ht_greenfield_support)
+		ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+	ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+
+	max_bit_rate = MAX_BIT_RATE_20_MHZ;
+
+	if (cfg->ht_params->ht40_bands & BIT(band)) {
+		ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+		ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
+		ht_info->mcs.rx_mask[4] = 0x01;
+		max_bit_rate = MAX_BIT_RATE_40_MHZ;
+	}
+
+	/* Highest supported Rx data rate */
+	max_bit_rate *= rx_chains;
+	WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK);
+	ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate);
+
+	/* Tx MCS capabilities */
+	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+	if (tx_chains != rx_chains) {
+		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+		ht_info->mcs.tx_params |= ((tx_chains - 1) <<
+				IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+	}
+}
+
+static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
+			    struct iwl_eeprom_data *data,
+			    const u8 *eeprom, size_t eeprom_size)
+{
+	int n_channels = iwl_init_channel_map(dev, cfg, data,
+					      eeprom, eeprom_size);
+	int n_used = 0;
+	struct ieee80211_supported_band *sband;
+
+	sband = &data->bands[IEEE80211_BAND_2GHZ];
+	sband->band = IEEE80211_BAND_2GHZ;
+	sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
+	sband->n_bitrates = N_RATES_24;
+	n_used += iwl_init_sband_channels(data, sband, n_channels,
+					  IEEE80211_BAND_2GHZ);
+	iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ);
+
+	sband = &data->bands[IEEE80211_BAND_5GHZ];
+	sband->band = IEEE80211_BAND_5GHZ;
+	sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
+	sband->n_bitrates = N_RATES_52;
+	n_used += iwl_init_sband_channels(data, sband, n_channels,
+					  IEEE80211_BAND_5GHZ);
+	iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ);
+
+	if (n_channels != n_used)
+		IWL_ERR_DEV(dev, "EEPROM: used only %d of %d channels\n",
+			    n_used, n_channels);
+}
+
+/* EEPROM data functions */
+
+struct iwl_eeprom_data *
+iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg,
+		      const u8 *eeprom, size_t eeprom_size)
+{
+	struct iwl_eeprom_data *data;
+	const void *tmp;
+
+	if (WARN_ON(!cfg || !cfg->eeprom_params))
+		return NULL;
+
+	data = kzalloc(sizeof(*data) +
+		       sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
+		       GFP_KERNEL);
+	if (!data)
+		return NULL;
+
+	/* get MAC address(es) */
+	tmp = iwl_eeprom_query_addr(eeprom, eeprom_size, EEPROM_MAC_ADDRESS);
+	if (!tmp)
+		goto err_free;
+	memcpy(data->hw_addr, tmp, ETH_ALEN);
+	data->n_hw_addrs = iwl_eeprom_query16(eeprom, eeprom_size,
+					      EEPROM_NUM_MAC_ADDRESS);
+
+	if (iwl_eeprom_read_calib(eeprom, eeprom_size, data))
+		goto err_free;
+
+	tmp = iwl_eeprom_query_addr(eeprom, eeprom_size, EEPROM_XTAL);
+	if (!tmp)
+		goto err_free;
+	memcpy(data->xtal_calib, tmp, sizeof(data->xtal_calib));
+
+	tmp = iwl_eeprom_query_addr(eeprom, eeprom_size,
+				    EEPROM_RAW_TEMPERATURE);
+	if (!tmp)
+		goto err_free;
+	data->raw_temperature = *(__le16 *)tmp;
+
+	tmp = iwl_eeprom_query_addr(eeprom, eeprom_size,
+				    EEPROM_KELVIN_TEMPERATURE);
+	if (!tmp)
+		goto err_free;
+	data->kelvin_temperature = *(__le16 *)tmp;
+	data->kelvin_voltage = *((__le16 *)tmp + 1);
+
+	data->radio_cfg = iwl_eeprom_query16(eeprom, eeprom_size,
+					     EEPROM_RADIO_CONFIG);
+	data->sku = iwl_eeprom_query16(eeprom, eeprom_size,
+				       EEPROM_SKU_CAP);
+	if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
+		data->sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
+
+	data->eeprom_version = iwl_eeprom_query16(eeprom, eeprom_size,
+						  EEPROM_VERSION);
+
+	data->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(data->radio_cfg);
+	data->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(data->radio_cfg);
+
+	/* check overrides (some devices have wrong EEPROM) */
+	if (cfg->valid_tx_ant)
+		data->valid_tx_ant = cfg->valid_tx_ant;
+	if (cfg->valid_rx_ant)
+		data->valid_rx_ant = cfg->valid_rx_ant;
+
+	if (!data->valid_tx_ant || !data->valid_rx_ant) {
+		IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n",
+			    data->valid_tx_ant, data->valid_rx_ant);
+		goto err_free;
+	}
+
+	iwl_init_sbands(dev, cfg, data, eeprom, eeprom_size);
+
+	return data;
+ err_free:
+	kfree(data);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(iwl_parse_eeprom_data);
+
+/* helper functions */
+int iwl_eeprom_check_version(struct iwl_eeprom_data *data,
+			     struct iwl_trans *trans)
+{
+	if (data->eeprom_version >= trans->cfg->eeprom_ver ||
+	    data->calib_version >= trans->cfg->eeprom_calib_ver) {
+		IWL_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n",
+			 data->eeprom_version, data->calib_version);
+		return 0;
+	}
+
+	IWL_ERR(trans,
+		"Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
+		data->eeprom_version, trans->cfg->eeprom_ver,
+		data->calib_version,  trans->cfg->eeprom_calib_ver);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(iwl_eeprom_check_version);
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
new file mode 100644
index 0000000..9c07c67
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
@@ -0,0 +1,138 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#ifndef __iwl_eeprom_parse_h__
+#define __iwl_eeprom_parse_h__
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#include "iwl-trans.h"
+
+/* SKU Capabilities (actual values from EEPROM definition) */
+#define EEPROM_SKU_CAP_BAND_24GHZ	(1 << 4)
+#define EEPROM_SKU_CAP_BAND_52GHZ	(1 << 5)
+#define EEPROM_SKU_CAP_11N_ENABLE	(1 << 6)
+#define EEPROM_SKU_CAP_AMT_ENABLE	(1 << 7)
+#define EEPROM_SKU_CAP_IPAN_ENABLE	(1 << 8)
+
+/* radio config bits (actual values from EEPROM definition) */
+#define EEPROM_RF_CFG_TYPE_MSK(x)   (x & 0x3)         /* bits 0-1   */
+#define EEPROM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
+#define EEPROM_RF_CFG_DASH_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
+#define EEPROM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
+#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
+#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
+
+struct iwl_eeprom_data {
+	int n_hw_addrs;
+	u8 hw_addr[ETH_ALEN];
+
+	u16 radio_config;
+
+	u8 calib_version;
+	__le16 calib_voltage;
+
+	__le16 raw_temperature;
+	__le16 kelvin_temperature;
+	__le16 kelvin_voltage;
+	__le16 xtal_calib[2];
+
+	u16 sku;
+	u16 radio_cfg;
+	u16 eeprom_version;
+	s8 max_tx_pwr_half_dbm;
+
+	u8 valid_tx_ant, valid_rx_ant;
+
+	struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
+	struct ieee80211_channel channels[];
+};
+
+/**
+ * iwl_parse_eeprom_data - parse EEPROM data and return values
+ *
+ * @dev: device pointer we're parsing for, for debug only
+ * @cfg: device configuration for parsing and overrides
+ * @eeprom: the EEPROM data
+ * @eeprom_size: length of the EEPROM data
+ *
+ * This function parses all EEPROM values we need and then
+ * returns a (newly allocated) struct containing all the
+ * relevant values for driver use. The struct must be freed
+ * later with iwl_free_eeprom_data().
+ */
+struct iwl_eeprom_data *
+iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg,
+		      const u8 *eeprom, size_t eeprom_size);
+
+/**
+ * iwl_free_eeprom_data - free EEPROM data
+ * @data: the data to free
+ */
+static inline void iwl_free_eeprom_data(struct iwl_eeprom_data *data)
+{
+	kfree(data);
+}
+
+int iwl_eeprom_check_version(struct iwl_eeprom_data *data,
+			     struct iwl_trans *trans);
+
+#endif /* __iwl_eeprom_parse_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
new file mode 100644
index 0000000..27c7da3
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
@@ -0,0 +1,463 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include "iwl-debug.h"
+#include "iwl-eeprom-read.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+#include "iwl-csr.h"
+
+/*
+ * EEPROM access time values:
+ *
+ * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG.
+ * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
+ * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
+ * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
+ */
+#define IWL_EEPROM_ACCESS_TIMEOUT	5000 /* uSec */
+
+#define IWL_EEPROM_SEM_TIMEOUT		10   /* microseconds */
+#define IWL_EEPROM_SEM_RETRY_LIMIT	1000 /* number of attempts (not time) */
+
+
+/*
+ * The device's EEPROM semaphore prevents conflicts between driver and uCode
+ * when accessing the EEPROM; each access is a series of pulses to/from the
+ * EEPROM chip, not a single event, so even reads could conflict if they
+ * weren't arbitrated by the semaphore.
+ */
+
+#define	EEPROM_SEM_TIMEOUT 10		/* milliseconds */
+#define EEPROM_SEM_RETRY_LIMIT 1000	/* number of attempts (not time) */
+
+static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans)
+{
+	u16 count;
+	int ret;
+
+	for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
+		/* Request semaphore */
+		iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
+			    CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+
+		/* See if we got it */
+		ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
+				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+				EEPROM_SEM_TIMEOUT);
+		if (ret >= 0) {
+			IWL_DEBUG_EEPROM(trans->dev,
+					 "Acquired semaphore after %d tries.\n",
+					 count+1);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static void iwl_eeprom_release_semaphore(struct iwl_trans *trans)
+{
+	iwl_clear_bit(trans, CSR_HW_IF_CONFIG_REG,
+		      CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+}
+
+static int iwl_eeprom_verify_signature(struct iwl_trans *trans, bool nvm_is_otp)
+{
+	u32 gp = iwl_read32(trans, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
+
+	IWL_DEBUG_EEPROM(trans->dev, "EEPROM signature=0x%08x\n", gp);
+
+	switch (gp) {
+	case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP:
+		if (!nvm_is_otp) {
+			IWL_ERR(trans, "EEPROM with bad signature: 0x%08x\n",
+				gp);
+			return -ENOENT;
+		}
+		return 0;
+	case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K:
+	case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K:
+		if (nvm_is_otp) {
+			IWL_ERR(trans, "OTP with bad signature: 0x%08x\n", gp);
+			return -ENOENT;
+		}
+		return 0;
+	case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP:
+	default:
+		IWL_ERR(trans,
+			"bad EEPROM/OTP signature, type=%s, EEPROM_GP=0x%08x\n",
+			nvm_is_otp ? "OTP" : "EEPROM", gp);
+		return -ENOENT;
+	}
+}
+
+/******************************************************************************
+ *
+ * OTP related functions
+ *
+******************************************************************************/
+
+static void iwl_set_otp_access_absolute(struct iwl_trans *trans)
+{
+	iwl_read32(trans, CSR_OTP_GP_REG);
+
+	iwl_clear_bit(trans, CSR_OTP_GP_REG,
+		      CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+}
+
+static int iwl_nvm_is_otp(struct iwl_trans *trans)
+{
+	u32 otpgp;
+
+	/* OTP only valid for CP/PP and after */
+	switch (trans->hw_rev & CSR_HW_REV_TYPE_MSK) {
+	case CSR_HW_REV_TYPE_NONE:
+		IWL_ERR(trans, "Unknown hardware type\n");
+		return -EIO;
+	case CSR_HW_REV_TYPE_5300:
+	case CSR_HW_REV_TYPE_5350:
+	case CSR_HW_REV_TYPE_5100:
+	case CSR_HW_REV_TYPE_5150:
+		return 0;
+	default:
+		otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
+		if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
+			return 1;
+		return 0;
+	}
+}
+
+static int iwl_init_otp_access(struct iwl_trans *trans)
+{
+	int ret;
+
+	/* Enable 40MHz radio clock */
+	iwl_write32(trans, CSR_GP_CNTRL,
+		    iwl_read32(trans, CSR_GP_CNTRL) |
+		    CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+	/* wait for clock to be ready */
+	ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
+			   CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+			   CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+			   25000);
+	if (ret < 0) {
+		IWL_ERR(trans, "Time out access OTP\n");
+	} else {
+		iwl_set_bits_prph(trans, APMG_PS_CTRL_REG,
+				  APMG_PS_CTRL_VAL_RESET_REQ);
+		udelay(5);
+		iwl_clear_bits_prph(trans, APMG_PS_CTRL_REG,
+				    APMG_PS_CTRL_VAL_RESET_REQ);
+
+		/*
+		 * CSR auto clock gate disable bit -
+		 * this is only applicable for HW with OTP shadow RAM
+		 */
+		if (trans->cfg->base_params->shadow_ram_support)
+			iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+				    CSR_RESET_LINK_PWR_MGMT_DISABLED);
+	}
+	return ret;
+}
+
+static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr,
+			     __le16 *eeprom_data)
+{
+	int ret = 0;
+	u32 r;
+	u32 otpgp;
+
+	iwl_write32(trans, CSR_EEPROM_REG,
+		    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+	ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
+				 CSR_EEPROM_REG_READ_VALID_MSK,
+				 CSR_EEPROM_REG_READ_VALID_MSK,
+				 IWL_EEPROM_ACCESS_TIMEOUT);
+	if (ret < 0) {
+		IWL_ERR(trans, "Time out reading OTP[%d]\n", addr);
+		return ret;
+	}
+	r = iwl_read32(trans, CSR_EEPROM_REG);
+	/* check for ECC errors: */
+	otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
+	if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
+		/* stop in this case */
+		/* set the uncorrectable OTP ECC bit for acknowledgement */
+		iwl_set_bit(trans, CSR_OTP_GP_REG,
+			    CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
+		IWL_ERR(trans, "Uncorrectable OTP ECC error, abort OTP read\n");
+		return -EINVAL;
+	}
+	if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
+		/* continue in this case */
+		/* set the correctable OTP ECC bit for acknowledgement */
+		iwl_set_bit(trans, CSR_OTP_GP_REG,
+			    CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
+		IWL_ERR(trans, "Correctable OTP ECC error, continue read\n");
+	}
+	*eeprom_data = cpu_to_le16(r >> 16);
+	return 0;
+}
+
+/*
+ * iwl_is_otp_empty: check for empty OTP
+ */
+static bool iwl_is_otp_empty(struct iwl_trans *trans)
+{
+	u16 next_link_addr = 0;
+	__le16 link_value;
+	bool is_empty = false;
+
+	/* locate the beginning of OTP link list */
+	if (!iwl_read_otp_word(trans, next_link_addr, &link_value)) {
+		if (!link_value) {
+			IWL_ERR(trans, "OTP is empty\n");
+			is_empty = true;
+		}
+	} else {
+		IWL_ERR(trans, "Unable to read first block of OTP list.\n");
+		is_empty = true;
+	}
+
+	return is_empty;
+}
+
+
+/*
+ * iwl_find_otp_image: find EEPROM image in OTP
+ *   finding the OTP block that contains the EEPROM image.
+ *   the last valid block on the link list (the block _before_ the last block)
+ *   is the block we should read and used to configure the device.
+ *   If all the available OTP blocks are full, the last block will be the block
+ *   we should read and used to configure the device.
+ *   only perform this operation if shadow RAM is disabled
+ */
+static int iwl_find_otp_image(struct iwl_trans *trans,
+					u16 *validblockaddr)
+{
+	u16 next_link_addr = 0, valid_addr;
+	__le16 link_value = 0;
+	int usedblocks = 0;
+
+	/* set addressing mode to absolute to traverse the link list */
+	iwl_set_otp_access_absolute(trans);
+
+	/* checking for empty OTP or error */
+	if (iwl_is_otp_empty(trans))
+		return -EINVAL;
+
+	/*
+	 * start traverse link list
+	 * until reach the max number of OTP blocks
+	 * different devices have different number of OTP blocks
+	 */
+	do {
+		/* save current valid block address
+		 * check for more block on the link list
+		 */
+		valid_addr = next_link_addr;
+		next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
+		IWL_DEBUG_EEPROM(trans->dev, "OTP blocks %d addr 0x%x\n",
+				 usedblocks, next_link_addr);
+		if (iwl_read_otp_word(trans, next_link_addr, &link_value))
+			return -EINVAL;
+		if (!link_value) {
+			/*
+			 * reach the end of link list, return success and
+			 * set address point to the starting address
+			 * of the image
+			 */
+			*validblockaddr = valid_addr;
+			/* skip first 2 bytes (link list pointer) */
+			*validblockaddr += 2;
+			return 0;
+		}
+		/* more in the link list, continue */
+		usedblocks++;
+	} while (usedblocks <= trans->cfg->base_params->max_ll_items);
+
+	/* OTP has no valid blocks */
+	IWL_DEBUG_EEPROM(trans->dev, "OTP has no valid blocks\n");
+	return -EINVAL;
+}
+
+/**
+ * iwl_read_eeprom - read EEPROM contents
+ *
+ * Load the EEPROM contents from adapter and return it
+ * and its size.
+ *
+ * NOTE:  This routine uses the non-debug IO access functions.
+ */
+int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size)
+{
+	__le16 *e;
+	u32 gp = iwl_read32(trans, CSR_EEPROM_GP);
+	int sz;
+	int ret;
+	u16 addr;
+	u16 validblockaddr = 0;
+	u16 cache_addr = 0;
+	int nvm_is_otp;
+
+	if (!eeprom || !eeprom_size)
+		return -EINVAL;
+
+	nvm_is_otp = iwl_nvm_is_otp(trans);
+	if (nvm_is_otp < 0)
+		return nvm_is_otp;
+
+	sz = trans->cfg->base_params->eeprom_size;
+	IWL_DEBUG_EEPROM(trans->dev, "NVM size = %d\n", sz);
+
+	e = kmalloc(sz, GFP_KERNEL);
+	if (!e)
+		return -ENOMEM;
+
+	ret = iwl_eeprom_verify_signature(trans, nvm_is_otp);
+	if (ret < 0) {
+		IWL_ERR(trans, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
+		goto err_free;
+	}
+
+	/* Make sure driver (instead of uCode) is allowed to read EEPROM */
+	ret = iwl_eeprom_acquire_semaphore(trans);
+	if (ret < 0) {
+		IWL_ERR(trans, "Failed to acquire EEPROM semaphore.\n");
+		goto err_free;
+	}
+
+	if (nvm_is_otp) {
+		ret = iwl_init_otp_access(trans);
+		if (ret) {
+			IWL_ERR(trans, "Failed to initialize OTP access.\n");
+			goto err_unlock;
+		}
+
+		iwl_write32(trans, CSR_EEPROM_GP,
+			    iwl_read32(trans, CSR_EEPROM_GP) &
+			    ~CSR_EEPROM_GP_IF_OWNER_MSK);
+
+		iwl_set_bit(trans, CSR_OTP_GP_REG,
+			    CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
+			    CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
+		/* traversing the linked list if no shadow ram supported */
+		if (!trans->cfg->base_params->shadow_ram_support) {
+			ret = iwl_find_otp_image(trans, &validblockaddr);
+			if (ret)
+				goto err_unlock;
+		}
+		for (addr = validblockaddr; addr < validblockaddr + sz;
+		     addr += sizeof(u16)) {
+			__le16 eeprom_data;
+
+			ret = iwl_read_otp_word(trans, addr, &eeprom_data);
+			if (ret)
+				goto err_unlock;
+			e[cache_addr / 2] = eeprom_data;
+			cache_addr += sizeof(u16);
+		}
+	} else {
+		/* eeprom is an array of 16bit values */
+		for (addr = 0; addr < sz; addr += sizeof(u16)) {
+			u32 r;
+
+			iwl_write32(trans, CSR_EEPROM_REG,
+				    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+
+			ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
+					   CSR_EEPROM_REG_READ_VALID_MSK,
+					   CSR_EEPROM_REG_READ_VALID_MSK,
+					   IWL_EEPROM_ACCESS_TIMEOUT);
+			if (ret < 0) {
+				IWL_ERR(trans,
+					"Time out reading EEPROM[%d]\n", addr);
+				goto err_unlock;
+			}
+			r = iwl_read32(trans, CSR_EEPROM_REG);
+			e[addr / 2] = cpu_to_le16(r >> 16);
+		}
+	}
+
+	IWL_DEBUG_EEPROM(trans->dev, "NVM Type: %s\n",
+			 nvm_is_otp ? "OTP" : "EEPROM");
+
+	iwl_eeprom_release_semaphore(trans);
+
+	*eeprom_size = sz;
+	*eeprom = (u8 *)e;
+	return 0;
+
+ err_unlock:
+	iwl_eeprom_release_semaphore(trans);
+ err_free:
+	kfree(e);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iwl_read_eeprom);
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
new file mode 100644
index 0000000..1337c9d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
@@ -0,0 +1,70 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_eeprom_h__
+#define __iwl_eeprom_h__
+
+#include "iwl-trans.h"
+
+int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size);
+
+#endif  /* __iwl_eeprom_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
deleted file mode 100644
index b8e2b22..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ /dev/null
@@ -1,1148 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-dev.h"
-#include "iwl-debug.h"
-#include "iwl-agn.h"
-#include "iwl-eeprom.h"
-#include "iwl-io.h"
-#include "iwl-prph.h"
-
-/************************** EEPROM BANDS ****************************
- *
- * The iwl_eeprom_band definitions below provide the mapping from the
- * EEPROM contents to the specific channel number supported for each
- * band.
- *
- * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
- * definition below maps to physical channel 42 in the 5.2GHz spectrum.
- * The specific geography and calibration information for that channel
- * is contained in the eeprom map itself.
- *
- * During init, we copy the eeprom information and channel map
- * information into priv->channel_info_24/52 and priv->channel_map_24/52
- *
- * channel_map_24/52 provides the index in the channel_info array for a
- * given channel.  We have to have two separate maps as there is channel
- * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
- * band_2
- *
- * A value of 0xff stored in the channel_map indicates that the channel
- * is not supported by the hardware at all.
- *
- * A value of 0xfe in the channel_map indicates that the channel is not
- * valid for Tx with the current hardware.  This means that
- * while the system can tune and receive on a given channel, it may not
- * be able to associate or transmit any frames on that
- * channel.  There is no corresponding channel information for that
- * entry.
- *
- *********************************************************************/
-
-/* 2.4 GHz */
-const u8 iwl_eeprom_band_1[14] = {
-	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
-};
-
-/* 5.2 GHz bands */
-static const u8 iwl_eeprom_band_2[] = {	/* 4915-5080MHz */
-	183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
-};
-
-static const u8 iwl_eeprom_band_3[] = {	/* 5170-5320MHz */
-	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
-};
-
-static const u8 iwl_eeprom_band_4[] = {	/* 5500-5700MHz */
-	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
-};
-
-static const u8 iwl_eeprom_band_5[] = {	/* 5725-5825MHz */
-	145, 149, 153, 157, 161, 165
-};
-
-static const u8 iwl_eeprom_band_6[] = {       /* 2.4 ht40 channel */
-	1, 2, 3, 4, 5, 6, 7
-};
-
-static const u8 iwl_eeprom_band_7[] = {       /* 5.2 ht40 channel */
-	36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
-};
-
-/******************************************************************************
- *
- * generic NVM functions
- *
-******************************************************************************/
-
-/*
- * The device's EEPROM semaphore prevents conflicts between driver and uCode
- * when accessing the EEPROM; each access is a series of pulses to/from the
- * EEPROM chip, not a single event, so even reads could conflict if they
- * weren't arbitrated by the semaphore.
- */
-
-#define	EEPROM_SEM_TIMEOUT 10		/* milliseconds */
-#define EEPROM_SEM_RETRY_LIMIT 1000	/* number of attempts (not time) */
-
-static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans)
-{
-	u16 count;
-	int ret;
-
-	for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
-		/* Request semaphore */
-		iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
-			    CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-
-		/* See if we got it */
-		ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
-				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
-				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
-				EEPROM_SEM_TIMEOUT);
-		if (ret >= 0) {
-			IWL_DEBUG_EEPROM(trans,
-				"Acquired semaphore after %d tries.\n",
-				count+1);
-			return ret;
-		}
-	}
-
-	return ret;
-}
-
-static void iwl_eeprom_release_semaphore(struct iwl_trans *trans)
-{
-	iwl_clear_bit(trans, CSR_HW_IF_CONFIG_REG,
-		CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-
-}
-
-static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
-{
-	u32 gp = iwl_read32(priv->trans, CSR_EEPROM_GP) &
-			   CSR_EEPROM_GP_VALID_MSK;
-	int ret = 0;
-
-	IWL_DEBUG_EEPROM(priv, "EEPROM signature=0x%08x\n", gp);
-	switch (gp) {
-	case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP:
-		if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) {
-			IWL_ERR(priv, "EEPROM with bad signature: 0x%08x\n",
-				gp);
-			ret = -ENOENT;
-		}
-		break;
-	case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K:
-	case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K:
-		if (priv->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) {
-			IWL_ERR(priv, "OTP with bad signature: 0x%08x\n", gp);
-			ret = -ENOENT;
-		}
-		break;
-	case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP:
-	default:
-		IWL_ERR(priv, "bad EEPROM/OTP signature, type=%s, "
-			"EEPROM_GP=0x%08x\n",
-			(priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
-			? "OTP" : "EEPROM", gp);
-		ret = -ENOENT;
-		break;
-	}
-	return ret;
-}
-
-u16 iwl_eeprom_query16(struct iwl_priv *priv, size_t offset)
-{
-	if (!priv->eeprom)
-		return 0;
-	return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
-}
-
-int iwl_eeprom_check_version(struct iwl_priv *priv)
-{
-	u16 eeprom_ver;
-	u16 calib_ver;
-
-	eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-	calib_ver = iwl_eeprom_calib_version(priv);
-
-	if (eeprom_ver < priv->cfg->eeprom_ver ||
-	    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",
-		  eeprom_ver, priv->cfg->eeprom_ver,
-		  calib_ver,  priv->cfg->eeprom_calib_ver);
-	return -EINVAL;
-
-}
-
-int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
-{
-	u16 radio_cfg;
-
-	priv->hw_params.sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
-	if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE &&
-	    !priv->cfg->ht_params) {
-		IWL_ERR(priv, "Invalid 11n configuration\n");
-		return -EINVAL;
-	}
-
-	if (!priv->hw_params.sku) {
-		IWL_ERR(priv, "Invalid device sku\n");
-		return -EINVAL;
-	}
-
-	IWL_INFO(priv, "Device SKU: 0x%X\n", priv->hw_params.sku);
-
-	radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
-
-	priv->hw_params.valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
-	priv->hw_params.valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg);
-
-	/* check overrides (some devices have wrong EEPROM) */
-	if (priv->cfg->valid_tx_ant)
-		priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
-	if (priv->cfg->valid_rx_ant)
-		priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
-
-	if (!priv->hw_params.valid_tx_ant || !priv->hw_params.valid_rx_ant) {
-		IWL_ERR(priv, "Invalid chain (0x%X, 0x%X)\n",
-			priv->hw_params.valid_tx_ant,
-			priv->hw_params.valid_rx_ant);
-		return -EINVAL;
-	}
-
-	IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n",
-		 priv->hw_params.valid_tx_ant, priv->hw_params.valid_rx_ant);
-
-	return 0;
-}
-
-u16 iwl_eeprom_calib_version(struct iwl_priv *priv)
-{
-	struct iwl_eeprom_calib_hdr *hdr;
-
-	hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
-							EEPROM_CALIB_ALL);
-	return hdr->version;
-}
-
-static u32 eeprom_indirect_address(struct iwl_priv *priv, u32 address)
-{
-	u16 offset = 0;
-
-	if ((address & INDIRECT_ADDRESS) == 0)
-		return address;
-
-	switch (address & INDIRECT_TYPE_MSK) {
-	case INDIRECT_HOST:
-		offset = iwl_eeprom_query16(priv, EEPROM_LINK_HOST);
-		break;
-	case INDIRECT_GENERAL:
-		offset = iwl_eeprom_query16(priv, EEPROM_LINK_GENERAL);
-		break;
-	case INDIRECT_REGULATORY:
-		offset = iwl_eeprom_query16(priv, EEPROM_LINK_REGULATORY);
-		break;
-	case INDIRECT_TXP_LIMIT:
-		offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT);
-		break;
-	case INDIRECT_TXP_LIMIT_SIZE:
-		offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT_SIZE);
-		break;
-	case INDIRECT_CALIBRATION:
-		offset = iwl_eeprom_query16(priv, EEPROM_LINK_CALIBRATION);
-		break;
-	case INDIRECT_PROCESS_ADJST:
-		offset = iwl_eeprom_query16(priv, EEPROM_LINK_PROCESS_ADJST);
-		break;
-	case INDIRECT_OTHERS:
-		offset = iwl_eeprom_query16(priv, EEPROM_LINK_OTHERS);
-		break;
-	default:
-		IWL_ERR(priv, "illegal indirect type: 0x%X\n",
-		address & INDIRECT_TYPE_MSK);
-		break;
-	}
-
-	/* translate the offset from words to byte */
-	return (address & ADDRESS_MSK) + (offset << 1);
-}
-
-const u8 *iwl_eeprom_query_addr(struct iwl_priv *priv, size_t offset)
-{
-	u32 address = eeprom_indirect_address(priv, offset);
-	BUG_ON(address >= priv->cfg->base_params->eeprom_size);
-	return &priv->eeprom[address];
-}
-
-void iwl_eeprom_get_mac(struct iwl_priv *priv, u8 *mac)
-{
-	const u8 *addr = iwl_eeprom_query_addr(priv,
-					EEPROM_MAC_ADDRESS);
-	memcpy(mac, addr, ETH_ALEN);
-}
-
-/******************************************************************************
- *
- * OTP related functions
- *
-******************************************************************************/
-
-static void iwl_set_otp_access(struct iwl_trans *trans,
-			       enum iwl_access_mode mode)
-{
-	iwl_read32(trans, CSR_OTP_GP_REG);
-
-	if (mode == IWL_OTP_ACCESS_ABSOLUTE)
-		iwl_clear_bit(trans, CSR_OTP_GP_REG,
-			      CSR_OTP_GP_REG_OTP_ACCESS_MODE);
-	else
-		iwl_set_bit(trans, CSR_OTP_GP_REG,
-			    CSR_OTP_GP_REG_OTP_ACCESS_MODE);
-}
-
-static int iwl_get_nvm_type(struct iwl_trans *trans, u32 hw_rev)
-{
-	u32 otpgp;
-	int nvm_type;
-
-	/* OTP only valid for CP/PP and after */
-	switch (hw_rev & CSR_HW_REV_TYPE_MSK) {
-	case CSR_HW_REV_TYPE_NONE:
-		IWL_ERR(trans, "Unknown hardware type\n");
-		return -ENOENT;
-	case CSR_HW_REV_TYPE_5300:
-	case CSR_HW_REV_TYPE_5350:
-	case CSR_HW_REV_TYPE_5100:
-	case CSR_HW_REV_TYPE_5150:
-		nvm_type = NVM_DEVICE_TYPE_EEPROM;
-		break;
-	default:
-		otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
-		if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
-			nvm_type = NVM_DEVICE_TYPE_OTP;
-		else
-			nvm_type = NVM_DEVICE_TYPE_EEPROM;
-		break;
-	}
-	return  nvm_type;
-}
-
-static int iwl_init_otp_access(struct iwl_trans *trans)
-{
-	int ret;
-
-	/* Enable 40MHz radio clock */
-	iwl_write32(trans, CSR_GP_CNTRL,
-		    iwl_read32(trans, CSR_GP_CNTRL) |
-		    CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
-	/* wait for clock to be ready */
-	ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
-				 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-				 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-				 25000);
-	if (ret < 0)
-		IWL_ERR(trans, "Time out access OTP\n");
-	else {
-		iwl_set_bits_prph(trans, APMG_PS_CTRL_REG,
-				  APMG_PS_CTRL_VAL_RESET_REQ);
-		udelay(5);
-		iwl_clear_bits_prph(trans, APMG_PS_CTRL_REG,
-				    APMG_PS_CTRL_VAL_RESET_REQ);
-
-		/*
-		 * CSR auto clock gate disable bit -
-		 * this is only applicable for HW with OTP shadow RAM
-		 */
-		if (trans->cfg->base_params->shadow_ram_support)
-			iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
-				CSR_RESET_LINK_PWR_MGMT_DISABLED);
-	}
-	return ret;
-}
-
-static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr,
-			     __le16 *eeprom_data)
-{
-	int ret = 0;
-	u32 r;
-	u32 otpgp;
-
-	iwl_write32(trans, CSR_EEPROM_REG,
-		    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-	ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
-				 CSR_EEPROM_REG_READ_VALID_MSK,
-				 CSR_EEPROM_REG_READ_VALID_MSK,
-				 IWL_EEPROM_ACCESS_TIMEOUT);
-	if (ret < 0) {
-		IWL_ERR(trans, "Time out reading OTP[%d]\n", addr);
-		return ret;
-	}
-	r = iwl_read32(trans, CSR_EEPROM_REG);
-	/* check for ECC errors: */
-	otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
-	if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
-		/* stop in this case */
-		/* set the uncorrectable OTP ECC bit for acknowledgement */
-		iwl_set_bit(trans, CSR_OTP_GP_REG,
-			CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-		IWL_ERR(trans, "Uncorrectable OTP ECC error, abort OTP read\n");
-		return -EINVAL;
-	}
-	if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
-		/* continue in this case */
-		/* set the correctable OTP ECC bit for acknowledgement */
-		iwl_set_bit(trans, CSR_OTP_GP_REG,
-				CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
-		IWL_ERR(trans, "Correctable OTP ECC error, continue read\n");
-	}
-	*eeprom_data = cpu_to_le16(r >> 16);
-	return 0;
-}
-
-/*
- * iwl_is_otp_empty: check for empty OTP
- */
-static bool iwl_is_otp_empty(struct iwl_trans *trans)
-{
-	u16 next_link_addr = 0;
-	__le16 link_value;
-	bool is_empty = false;
-
-	/* locate the beginning of OTP link list */
-	if (!iwl_read_otp_word(trans, next_link_addr, &link_value)) {
-		if (!link_value) {
-			IWL_ERR(trans, "OTP is empty\n");
-			is_empty = true;
-		}
-	} else {
-		IWL_ERR(trans, "Unable to read first block of OTP list.\n");
-		is_empty = true;
-	}
-
-	return is_empty;
-}
-
-
-/*
- * iwl_find_otp_image: find EEPROM image in OTP
- *   finding the OTP block that contains the EEPROM image.
- *   the last valid block on the link list (the block _before_ the last block)
- *   is the block we should read and used to configure the device.
- *   If all the available OTP blocks are full, the last block will be the block
- *   we should read and used to configure the device.
- *   only perform this operation if shadow RAM is disabled
- */
-static int iwl_find_otp_image(struct iwl_trans *trans,
-					u16 *validblockaddr)
-{
-	u16 next_link_addr = 0, valid_addr;
-	__le16 link_value = 0;
-	int usedblocks = 0;
-
-	/* set addressing mode to absolute to traverse the link list */
-	iwl_set_otp_access(trans, IWL_OTP_ACCESS_ABSOLUTE);
-
-	/* checking for empty OTP or error */
-	if (iwl_is_otp_empty(trans))
-		return -EINVAL;
-
-	/*
-	 * start traverse link list
-	 * until reach the max number of OTP blocks
-	 * different devices have different number of OTP blocks
-	 */
-	do {
-		/* save current valid block address
-		 * check for more block on the link list
-		 */
-		valid_addr = next_link_addr;
-		next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
-		IWL_DEBUG_EEPROM(trans, "OTP blocks %d addr 0x%x\n",
-			       usedblocks, next_link_addr);
-		if (iwl_read_otp_word(trans, next_link_addr, &link_value))
-			return -EINVAL;
-		if (!link_value) {
-			/*
-			 * reach the end of link list, return success and
-			 * set address point to the starting address
-			 * of the image
-			 */
-			*validblockaddr = valid_addr;
-			/* skip first 2 bytes (link list pointer) */
-			*validblockaddr += 2;
-			return 0;
-		}
-		/* more in the link list, continue */
-		usedblocks++;
-	} while (usedblocks <= trans->cfg->base_params->max_ll_items);
-
-	/* OTP has no valid blocks */
-	IWL_DEBUG_EEPROM(trans, "OTP has no valid blocks\n");
-	return -EINVAL;
-}
-
-/******************************************************************************
- *
- * Tx Power related functions
- *
-******************************************************************************/
-/**
- * iwl_get_max_txpower_avg - get the highest tx power from all chains.
- *     find the highest tx power from all chains for the channel
- */
-static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
-		struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
-		int element, s8 *max_txpower_in_half_dbm)
-{
-	s8 max_txpower_avg = 0; /* (dBm) */
-
-	/* Take the highest tx power from any valid chains */
-	if ((priv->hw_params.valid_tx_ant & ANT_A) &&
-	    (enhanced_txpower[element].chain_a_max > max_txpower_avg))
-		max_txpower_avg = enhanced_txpower[element].chain_a_max;
-	if ((priv->hw_params.valid_tx_ant & ANT_B) &&
-	    (enhanced_txpower[element].chain_b_max > max_txpower_avg))
-		max_txpower_avg = enhanced_txpower[element].chain_b_max;
-	if ((priv->hw_params.valid_tx_ant & ANT_C) &&
-	    (enhanced_txpower[element].chain_c_max > max_txpower_avg))
-		max_txpower_avg = enhanced_txpower[element].chain_c_max;
-	if (((priv->hw_params.valid_tx_ant == ANT_AB) |
-	    (priv->hw_params.valid_tx_ant == ANT_BC) |
-	    (priv->hw_params.valid_tx_ant == ANT_AC)) &&
-	    (enhanced_txpower[element].mimo2_max > max_txpower_avg))
-		max_txpower_avg =  enhanced_txpower[element].mimo2_max;
-	if ((priv->hw_params.valid_tx_ant == ANT_ABC) &&
-	    (enhanced_txpower[element].mimo3_max > max_txpower_avg))
-		max_txpower_avg = enhanced_txpower[element].mimo3_max;
-
-	/*
-	 * max. tx power in EEPROM is in 1/2 dBm format
-	 * convert from 1/2 dBm to dBm (round-up convert)
-	 * but we also do not want to loss 1/2 dBm resolution which
-	 * will impact performance
-	 */
-	*max_txpower_in_half_dbm = max_txpower_avg;
-	return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1);
-}
-
-static void
-iwl_eeprom_enh_txp_read_element(struct iwl_priv *priv,
-				    struct iwl_eeprom_enhanced_txpwr *txp,
-				    s8 max_txpower_avg)
-{
-	int ch_idx;
-	bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ;
-	enum ieee80211_band band;
-
-	band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ?
-		IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
-
-	for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) {
-		struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx];
-
-		/* update matching channel or from common data only */
-		if (txp->channel != 0 && ch_info->channel != txp->channel)
-			continue;
-
-		/* update matching band only */
-		if (band != ch_info->band)
-			continue;
-
-		if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) {
-			ch_info->max_power_avg = max_txpower_avg;
-			ch_info->curr_txpow = max_txpower_avg;
-			ch_info->scan_power = max_txpower_avg;
-		}
-
-		if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg)
-			ch_info->ht40_max_power_avg = max_txpower_avg;
-	}
-}
-
-#define EEPROM_TXP_OFFS	(0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT)
-#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr)
-#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE)
-
-#define TXP_CHECK_AND_PRINT(x) ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) \
-			    ? # x " " : "")
-
-static void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
-{
-	struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
-	int idx, entries;
-	__le16 *txp_len;
-	s8 max_txp_avg, max_txp_avg_halfdbm;
-
-	BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
-
-	/* the length is in 16-bit words, but we want entries */
-	txp_len = (__le16 *) iwl_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS);
-	entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
-
-	txp_array = (void *) iwl_eeprom_query_addr(priv, EEPROM_TXP_OFFS);
-
-	for (idx = 0; idx < entries; idx++) {
-		txp = &txp_array[idx];
-		/* skip invalid entries */
-		if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID))
-			continue;
-
-		IWL_DEBUG_EEPROM(priv, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n",
-				 (txp->channel && (txp->flags &
-					IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ?
-					"Common " : (txp->channel) ?
-					"Channel" : "Common",
-				 (txp->channel),
-				 TXP_CHECK_AND_PRINT(VALID),
-				 TXP_CHECK_AND_PRINT(BAND_52G),
-				 TXP_CHECK_AND_PRINT(OFDM),
-				 TXP_CHECK_AND_PRINT(40MHZ),
-				 TXP_CHECK_AND_PRINT(HT_AP),
-				 TXP_CHECK_AND_PRINT(RES1),
-				 TXP_CHECK_AND_PRINT(RES2),
-				 TXP_CHECK_AND_PRINT(COMMON_TYPE),
-				 txp->flags);
-		IWL_DEBUG_EEPROM(priv, "\t\t chain_A: 0x%02x "
-				 "chain_B: 0X%02x chain_C: 0X%02x\n",
-				 txp->chain_a_max, txp->chain_b_max,
-				 txp->chain_c_max);
-		IWL_DEBUG_EEPROM(priv, "\t\t MIMO2: 0x%02x "
-				 "MIMO3: 0x%02x High 20_on_40: 0x%02x "
-				 "Low 20_on_40: 0x%02x\n",
-				 txp->mimo2_max, txp->mimo3_max,
-				 ((txp->delta_20_in_40 & 0xf0) >> 4),
-				 (txp->delta_20_in_40 & 0x0f));
-
-		max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
-						      &max_txp_avg_halfdbm);
-
-		/*
-		 * Update the user limit values values to the highest
-		 * power supported by any channel
-		 */
-		if (max_txp_avg > priv->tx_power_user_lmt)
-			priv->tx_power_user_lmt = max_txp_avg;
-		if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm)
-			priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm;
-
-		iwl_eeprom_enh_txp_read_element(priv, txp, max_txp_avg);
-	}
-}
-
-/**
- * iwl_eeprom_init - read EEPROM contents
- *
- * Load the EEPROM contents from adapter into priv->eeprom
- *
- * NOTE:  This routine uses the non-debug IO access functions.
- */
-int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
-{
-	__le16 *e;
-	u32 gp = iwl_read32(priv->trans, CSR_EEPROM_GP);
-	int sz;
-	int ret;
-	u16 addr;
-	u16 validblockaddr = 0;
-	u16 cache_addr = 0;
-
-	priv->nvm_device_type = iwl_get_nvm_type(priv->trans, hw_rev);
-	if (priv->nvm_device_type == -ENOENT)
-		return -ENOENT;
-	/* allocate eeprom */
-	sz = priv->cfg->base_params->eeprom_size;
-	IWL_DEBUG_EEPROM(priv, "NVM size = %d\n", sz);
-	priv->eeprom = kzalloc(sz, GFP_KERNEL);
-	if (!priv->eeprom) {
-		ret = -ENOMEM;
-		goto alloc_err;
-	}
-	e = (__le16 *)priv->eeprom;
-
-	ret = iwl_eeprom_verify_signature(priv);
-	if (ret < 0) {
-		IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
-		ret = -ENOENT;
-		goto err;
-	}
-
-	/* Make sure driver (instead of uCode) is allowed to read EEPROM */
-	ret = iwl_eeprom_acquire_semaphore(priv->trans);
-	if (ret < 0) {
-		IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n");
-		ret = -ENOENT;
-		goto err;
-	}
-
-	if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
-
-		ret = iwl_init_otp_access(priv->trans);
-		if (ret) {
-			IWL_ERR(priv, "Failed to initialize OTP access.\n");
-			ret = -ENOENT;
-			goto done;
-		}
-		iwl_write32(priv->trans, CSR_EEPROM_GP,
-			    iwl_read32(priv->trans, CSR_EEPROM_GP) &
-			    ~CSR_EEPROM_GP_IF_OWNER_MSK);
-
-		iwl_set_bit(priv->trans, CSR_OTP_GP_REG,
-			     CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
-			     CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-		/* traversing the linked list if no shadow ram supported */
-		if (!priv->cfg->base_params->shadow_ram_support) {
-			if (iwl_find_otp_image(priv->trans, &validblockaddr)) {
-				ret = -ENOENT;
-				goto done;
-			}
-		}
-		for (addr = validblockaddr; addr < validblockaddr + sz;
-		     addr += sizeof(u16)) {
-			__le16 eeprom_data;
-
-			ret = iwl_read_otp_word(priv->trans, addr,
-						&eeprom_data);
-			if (ret)
-				goto done;
-			e[cache_addr / 2] = eeprom_data;
-			cache_addr += sizeof(u16);
-		}
-	} else {
-		/* eeprom is an array of 16bit values */
-		for (addr = 0; addr < sz; addr += sizeof(u16)) {
-			u32 r;
-
-			iwl_write32(priv->trans, CSR_EEPROM_REG,
-				    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-
-			ret = iwl_poll_bit(priv->trans, CSR_EEPROM_REG,
-						  CSR_EEPROM_REG_READ_VALID_MSK,
-						  CSR_EEPROM_REG_READ_VALID_MSK,
-						  IWL_EEPROM_ACCESS_TIMEOUT);
-			if (ret < 0) {
-				IWL_ERR(priv,
-					"Time out reading EEPROM[%d]\n", addr);
-				goto done;
-			}
-			r = iwl_read32(priv->trans, CSR_EEPROM_REG);
-			e[addr / 2] = cpu_to_le16(r >> 16);
-		}
-	}
-
-	IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n",
-		       (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
-		       ? "OTP" : "EEPROM",
-		       iwl_eeprom_query16(priv, EEPROM_VERSION));
-
-	ret = 0;
-done:
-	iwl_eeprom_release_semaphore(priv->trans);
-
-err:
-	if (ret)
-		iwl_eeprom_free(priv);
-alloc_err:
-	return ret;
-}
-
-void iwl_eeprom_free(struct iwl_priv *priv)
-{
-	kfree(priv->eeprom);
-	priv->eeprom = NULL;
-}
-
-static void iwl_init_band_reference(struct iwl_priv *priv,
-			int eep_band, int *eeprom_ch_count,
-			const struct iwl_eeprom_channel **eeprom_ch_info,
-			const u8 **eeprom_ch_index)
-{
-	u32 offset = priv->lib->
-			eeprom_ops.regulatory_bands[eep_band - 1];
-	switch (eep_band) {
-	case 1:		/* 2.4GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
-		*eeprom_ch_info = (struct iwl_eeprom_channel *)
-				iwl_eeprom_query_addr(priv, offset);
-		*eeprom_ch_index = iwl_eeprom_band_1;
-		break;
-	case 2:		/* 4.9GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
-		*eeprom_ch_info = (struct iwl_eeprom_channel *)
-				iwl_eeprom_query_addr(priv, offset);
-		*eeprom_ch_index = iwl_eeprom_band_2;
-		break;
-	case 3:		/* 5.2GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
-		*eeprom_ch_info = (struct iwl_eeprom_channel *)
-				iwl_eeprom_query_addr(priv, offset);
-		*eeprom_ch_index = iwl_eeprom_band_3;
-		break;
-	case 4:		/* 5.5GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
-		*eeprom_ch_info = (struct iwl_eeprom_channel *)
-				iwl_eeprom_query_addr(priv, offset);
-		*eeprom_ch_index = iwl_eeprom_band_4;
-		break;
-	case 5:		/* 5.7GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
-		*eeprom_ch_info = (struct iwl_eeprom_channel *)
-				iwl_eeprom_query_addr(priv, offset);
-		*eeprom_ch_index = iwl_eeprom_band_5;
-		break;
-	case 6:		/* 2.4GHz ht40 channels */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
-		*eeprom_ch_info = (struct iwl_eeprom_channel *)
-				iwl_eeprom_query_addr(priv, offset);
-		*eeprom_ch_index = iwl_eeprom_band_6;
-		break;
-	case 7:		/* 5 GHz ht40 channels */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
-		*eeprom_ch_info = (struct iwl_eeprom_channel *)
-				iwl_eeprom_query_addr(priv, offset);
-		*eeprom_ch_index = iwl_eeprom_band_7;
-		break;
-	default:
-		BUG();
-		return;
-	}
-}
-
-#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \
-			    ? # x " " : "")
-/**
- * iwl_mod_ht40_chan_info - Copy ht40 channel info into driver's priv.
- *
- * Does not set up a command, or touch hardware.
- */
-static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
-			      enum ieee80211_band band, u16 channel,
-			      const struct iwl_eeprom_channel *eeprom_ch,
-			      u8 clear_ht40_extension_channel)
-{
-	struct iwl_channel_info *ch_info;
-
-	ch_info = (struct iwl_channel_info *)
-			iwl_get_channel_info(priv, band, channel);
-
-	if (!is_channel_valid(ch_info))
-		return -1;
-
-	IWL_DEBUG_EEPROM(priv, "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):"
-			" Ad-Hoc %ssupported\n",
-			ch_info->channel,
-			is_channel_a_band(ch_info) ?
-			"5.2" : "2.4",
-			CHECK_AND_PRINT(IBSS),
-			CHECK_AND_PRINT(ACTIVE),
-			CHECK_AND_PRINT(RADAR),
-			CHECK_AND_PRINT(WIDE),
-			CHECK_AND_PRINT(DFS),
-			eeprom_ch->flags,
-			eeprom_ch->max_power_avg,
-			((eeprom_ch->flags & EEPROM_CHANNEL_IBSS)
-			 && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ?
-			"" : "not ");
-
-	ch_info->ht40_eeprom = *eeprom_ch;
-	ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg;
-	ch_info->ht40_flags = eeprom_ch->flags;
-	if (eeprom_ch->flags & EEPROM_CHANNEL_VALID)
-		ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel;
-
-	return 0;
-}
-
-#define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
-			    ? # x " " : "")
-
-/**
- * iwl_init_channel_map - Set up driver's info for all possible channels
- */
-int iwl_init_channel_map(struct iwl_priv *priv)
-{
-	int eeprom_ch_count = 0;
-	const u8 *eeprom_ch_index = NULL;
-	const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
-	int band, ch;
-	struct iwl_channel_info *ch_info;
-
-	if (priv->channel_count) {
-		IWL_DEBUG_EEPROM(priv, "Channel map already initialized.\n");
-		return 0;
-	}
-
-	IWL_DEBUG_EEPROM(priv, "Initializing regulatory info from EEPROM\n");
-
-	priv->channel_count =
-	    ARRAY_SIZE(iwl_eeprom_band_1) +
-	    ARRAY_SIZE(iwl_eeprom_band_2) +
-	    ARRAY_SIZE(iwl_eeprom_band_3) +
-	    ARRAY_SIZE(iwl_eeprom_band_4) +
-	    ARRAY_SIZE(iwl_eeprom_band_5);
-
-	IWL_DEBUG_EEPROM(priv, "Parsing data for %d channels.\n",
-			priv->channel_count);
-
-	priv->channel_info = kcalloc(priv->channel_count,
-				     sizeof(struct iwl_channel_info),
-				     GFP_KERNEL);
-	if (!priv->channel_info) {
-		IWL_ERR(priv, "Could not allocate channel_info\n");
-		priv->channel_count = 0;
-		return -ENOMEM;
-	}
-
-	ch_info = priv->channel_info;
-
-	/* Loop through the 5 EEPROM bands adding them in order to the
-	 * channel map we maintain (that contains additional information than
-	 * what just in the EEPROM) */
-	for (band = 1; band <= 5; band++) {
-
-		iwl_init_band_reference(priv, band, &eeprom_ch_count,
-					&eeprom_ch_info, &eeprom_ch_index);
-
-		/* Loop through each band adding each of the channels */
-		for (ch = 0; ch < eeprom_ch_count; ch++) {
-			ch_info->channel = eeprom_ch_index[ch];
-			ch_info->band = (band == 1) ? IEEE80211_BAND_2GHZ :
-			    IEEE80211_BAND_5GHZ;
-
-			/* permanently store EEPROM's channel regulatory flags
-			 *   and max power in channel info database. */
-			ch_info->eeprom = eeprom_ch_info[ch];
-
-			/* Copy the run-time flags so they are there even on
-			 * invalid channels */
-			ch_info->flags = eeprom_ch_info[ch].flags;
-			/* First write that ht40 is not enabled, and then enable
-			 * one by one */
-			ch_info->ht40_extension_channel =
-					IEEE80211_CHAN_NO_HT40;
-
-			if (!(is_channel_valid(ch_info))) {
-				IWL_DEBUG_EEPROM(priv,
-					       "Ch. %d Flags %x [%sGHz] - "
-					       "No traffic\n",
-					       ch_info->channel,
-					       ch_info->flags,
-					       is_channel_a_band(ch_info) ?
-					       "5.2" : "2.4");
-				ch_info++;
-				continue;
-			}
-
-			/* Initialize regulatory-based run-time data */
-			ch_info->max_power_avg = ch_info->curr_txpow =
-			    eeprom_ch_info[ch].max_power_avg;
-			ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
-			ch_info->min_power = 0;
-
-			IWL_DEBUG_EEPROM(priv, "Ch. %d [%sGHz] "
-				       "%s%s%s%s%s%s(0x%02x %ddBm):"
-				       " Ad-Hoc %ssupported\n",
-				       ch_info->channel,
-				       is_channel_a_band(ch_info) ?
-				       "5.2" : "2.4",
-				       CHECK_AND_PRINT_I(VALID),
-				       CHECK_AND_PRINT_I(IBSS),
-				       CHECK_AND_PRINT_I(ACTIVE),
-				       CHECK_AND_PRINT_I(RADAR),
-				       CHECK_AND_PRINT_I(WIDE),
-				       CHECK_AND_PRINT_I(DFS),
-				       eeprom_ch_info[ch].flags,
-				       eeprom_ch_info[ch].max_power_avg,
-				       ((eeprom_ch_info[ch].
-					 flags & EEPROM_CHANNEL_IBSS)
-					&& !(eeprom_ch_info[ch].
-					     flags & EEPROM_CHANNEL_RADAR))
-				       ? "" : "not ");
-
-			ch_info++;
-		}
-	}
-
-	/* Check if we do have HT40 channels */
-	if (priv->lib->eeprom_ops.regulatory_bands[5] ==
-	    EEPROM_REGULATORY_BAND_NO_HT40 &&
-	    priv->lib->eeprom_ops.regulatory_bands[6] ==
-	    EEPROM_REGULATORY_BAND_NO_HT40)
-		return 0;
-
-	/* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
-	for (band = 6; band <= 7; band++) {
-		enum ieee80211_band ieeeband;
-
-		iwl_init_band_reference(priv, band, &eeprom_ch_count,
-					&eeprom_ch_info, &eeprom_ch_index);
-
-		/* EEPROM band 6 is 2.4, band 7 is 5 GHz */
-		ieeeband =
-			(band == 6) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
-
-		/* Loop through each band adding each of the channels */
-		for (ch = 0; ch < eeprom_ch_count; ch++) {
-			/* Set up driver's info for lower half */
-			iwl_mod_ht40_chan_info(priv, ieeeband,
-						eeprom_ch_index[ch],
-						&eeprom_ch_info[ch],
-						IEEE80211_CHAN_NO_HT40PLUS);
-
-			/* Set up driver's info for upper half */
-			iwl_mod_ht40_chan_info(priv, ieeeband,
-						eeprom_ch_index[ch] + 4,
-						&eeprom_ch_info[ch],
-						IEEE80211_CHAN_NO_HT40MINUS);
-		}
-	}
-
-	/* for newer device (6000 series and up)
-	 * EEPROM contain enhanced tx power information
-	 * driver need to process addition information
-	 * to determine the max channel tx power limits
-	 */
-	if (priv->lib->eeprom_ops.enhanced_txpower)
-		iwl_eeprom_enhanced_txpower(priv);
-
-	return 0;
-}
-
-/*
- * iwl_free_channel_map - undo allocations in iwl_init_channel_map
- */
-void iwl_free_channel_map(struct iwl_priv *priv)
-{
-	kfree(priv->channel_info);
-	priv->channel_count = 0;
-}
-
-/**
- * iwl_get_channel_info - Find driver's private channel info
- *
- * Based on band and channel number.
- */
-const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
-					enum ieee80211_band band, u16 channel)
-{
-	int i;
-
-	switch (band) {
-	case IEEE80211_BAND_5GHZ:
-		for (i = 14; i < priv->channel_count; i++) {
-			if (priv->channel_info[i].channel == channel)
-				return &priv->channel_info[i];
-		}
-		break;
-	case IEEE80211_BAND_2GHZ:
-		if (channel >= 1 && channel <= 14)
-			return &priv->channel_info[channel - 1];
-		break;
-	default:
-		BUG();
-	}
-
-	return NULL;
-}
-
-void iwl_rf_config(struct iwl_priv *priv)
-{
-	u16 radio_cfg;
-
-	radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
-
-	/* write radio config values to register */
-	if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) {
-		iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG,
-			    EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
-			    EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
-			    EEPROM_RF_CFG_DASH_MSK(radio_cfg));
-		IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n",
-			 EEPROM_RF_CFG_TYPE_MSK(radio_cfg),
-			 EEPROM_RF_CFG_STEP_MSK(radio_cfg),
-			 EEPROM_RF_CFG_DASH_MSK(radio_cfg));
-	} else
-		WARN_ON(1);
-
-	/* set CSR_HW_CONFIG_REG for uCode use */
-	iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG,
-		    CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
-		    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
deleted file mode 100644
index 64bfd94..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ /dev/null
@@ -1,269 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-#ifndef __iwl_eeprom_h__
-#define __iwl_eeprom_h__
-
-#include <net/mac80211.h>
-
-struct iwl_priv;
-
-/*
- * EEPROM access time values:
- *
- * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG.
- * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
- * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
- * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
- */
-#define IWL_EEPROM_ACCESS_TIMEOUT	5000 /* uSec */
-
-#define IWL_EEPROM_SEM_TIMEOUT 		10   /* microseconds */
-#define IWL_EEPROM_SEM_RETRY_LIMIT	1000 /* number of attempts (not time) */
-
-
-/*
- * Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags.
- *
- * IBSS and/or AP operation is allowed *only* on those channels with
- * (VALID && IBSS && ACTIVE && !RADAR).  This restriction is in place because
- * RADAR detection is not supported by the 4965 driver, but is a
- * requirement for establishing a new network for legal operation on channels
- * requiring RADAR detection or restricting ACTIVE scanning.
- *
- * NOTE:  "WIDE" flag does not indicate anything about "HT40" 40 MHz channels.
- *        It only indicates that 20 MHz channel use is supported; HT40 channel
- *        usage is indicated by a separate set of regulatory flags for each
- *        HT40 channel pair.
- *
- * NOTE:  Using a channel inappropriately will result in a uCode error!
- */
-#define IWL_NUM_TX_CALIB_GROUPS 5
-enum {
-	EEPROM_CHANNEL_VALID = (1 << 0),	/* usable for this SKU/geo */
-	EEPROM_CHANNEL_IBSS = (1 << 1),		/* usable as an IBSS channel */
-	/* Bit 2 Reserved */
-	EEPROM_CHANNEL_ACTIVE = (1 << 3),	/* active scanning allowed */
-	EEPROM_CHANNEL_RADAR = (1 << 4),	/* radar detection required */
-	EEPROM_CHANNEL_WIDE = (1 << 5),		/* 20 MHz channel okay */
-	/* Bit 6 Reserved (was Narrow Channel) */
-	EEPROM_CHANNEL_DFS = (1 << 7),	/* dynamic freq selection candidate */
-};
-
-/* SKU Capabilities */
-#define EEPROM_SKU_CAP_BAND_24GHZ			(1 << 4)
-#define EEPROM_SKU_CAP_BAND_52GHZ			(1 << 5)
-#define EEPROM_SKU_CAP_11N_ENABLE	                (1 << 6)
-#define EEPROM_SKU_CAP_AMT_ENABLE			(1 << 7)
-#define EEPROM_SKU_CAP_IPAN_ENABLE	                (1 << 8)
-
-/* *regulatory* channel data format in eeprom, one for each channel.
- * There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */
-struct iwl_eeprom_channel {
-	u8 flags;		/* EEPROM_CHANNEL_* flags copied from EEPROM */
-	s8 max_power_avg;	/* max power (dBm) on this chnl, limit 31 */
-} __packed;
-
-enum iwl_eeprom_enhanced_txpwr_flags {
-	IWL_EEPROM_ENH_TXP_FL_VALID		= BIT(0),
-	IWL_EEPROM_ENH_TXP_FL_BAND_52G		= BIT(1),
-	IWL_EEPROM_ENH_TXP_FL_OFDM		= BIT(2),
-	IWL_EEPROM_ENH_TXP_FL_40MHZ		= BIT(3),
-	IWL_EEPROM_ENH_TXP_FL_HT_AP		= BIT(4),
-	IWL_EEPROM_ENH_TXP_FL_RES1		= BIT(5),
-	IWL_EEPROM_ENH_TXP_FL_RES2		= BIT(6),
-	IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE	= BIT(7),
-};
-
-/**
- * iwl_eeprom_enhanced_txpwr structure
- *    This structure presents the enhanced regulatory tx power limit layout
- *    in eeprom image
- *    Enhanced regulatory tx power portion of eeprom image can be broken down
- *    into individual structures; each one is 8 bytes in size and contain the
- *    following information
- * @flags: entry flags
- * @channel: channel number
- * @chain_a_max_pwr: chain a max power in 1/2 dBm
- * @chain_b_max_pwr: chain b max power in 1/2 dBm
- * @chain_c_max_pwr: chain c max power in 1/2 dBm
- * @delta_20_in_40: 20-in-40 deltas (hi/lo)
- * @mimo2_max_pwr: mimo2 max power in 1/2 dBm
- * @mimo3_max_pwr: mimo3 max power in 1/2 dBm
- *
- */
-struct iwl_eeprom_enhanced_txpwr {
-	u8 flags;
-	u8 channel;
-	s8 chain_a_max;
-	s8 chain_b_max;
-	s8 chain_c_max;
-	u8 delta_20_in_40;
-	s8 mimo2_max;
-	s8 mimo3_max;
-} __packed;
-
-/* calibration */
-struct iwl_eeprom_calib_hdr {
-	u8 version;
-	u8 pa_type;
-	__le16 voltage;
-} __packed;
-
-#define EEPROM_CALIB_ALL	(INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
-#define EEPROM_XTAL		((2*0x128) | EEPROM_CALIB_ALL)
-
-/* temperature */
-#define EEPROM_KELVIN_TEMPERATURE	((2*0x12A) | EEPROM_CALIB_ALL)
-#define EEPROM_RAW_TEMPERATURE		((2*0x12B) | EEPROM_CALIB_ALL)
-
-
-/* agn links */
-#define EEPROM_LINK_HOST             (2*0x64)
-#define EEPROM_LINK_GENERAL          (2*0x65)
-#define EEPROM_LINK_REGULATORY       (2*0x66)
-#define EEPROM_LINK_CALIBRATION      (2*0x67)
-#define EEPROM_LINK_PROCESS_ADJST    (2*0x68)
-#define EEPROM_LINK_OTHERS           (2*0x69)
-#define EEPROM_LINK_TXP_LIMIT        (2*0x6a)
-#define EEPROM_LINK_TXP_LIMIT_SIZE   (2*0x6b)
-
-/* agn regulatory - indirect access */
-#define EEPROM_REG_BAND_1_CHANNELS       ((0x08)\
-		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 28 bytes */
-#define EEPROM_REG_BAND_2_CHANNELS       ((0x26)\
-		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 26 bytes */
-#define EEPROM_REG_BAND_3_CHANNELS       ((0x42)\
-		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 24 bytes */
-#define EEPROM_REG_BAND_4_CHANNELS       ((0x5C)\
-		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22 bytes */
-#define EEPROM_REG_BAND_5_CHANNELS       ((0x74)\
-		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 12 bytes */
-#define EEPROM_REG_BAND_24_HT40_CHANNELS  ((0x82)\
-		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 14  bytes */
-#define EEPROM_REG_BAND_52_HT40_CHANNELS  ((0x92)\
-		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22  bytes */
-
-/* 6000 regulatory - indirect access */
-#define EEPROM_6000_REG_BAND_24_HT40_CHANNELS  ((0x80)\
-		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 14  bytes */
-/* 2.4 GHz */
-extern const u8 iwl_eeprom_band_1[14];
-
-#define ADDRESS_MSK                 0x0000FFFF
-#define INDIRECT_TYPE_MSK           0x000F0000
-#define INDIRECT_HOST               0x00010000
-#define INDIRECT_GENERAL            0x00020000
-#define INDIRECT_REGULATORY         0x00030000
-#define INDIRECT_CALIBRATION        0x00040000
-#define INDIRECT_PROCESS_ADJST      0x00050000
-#define INDIRECT_OTHERS             0x00060000
-#define INDIRECT_TXP_LIMIT          0x00070000
-#define INDIRECT_TXP_LIMIT_SIZE     0x00080000
-#define INDIRECT_ADDRESS            0x00100000
-
-/* General */
-#define EEPROM_DEVICE_ID                    (2*0x08)	/* 2 bytes */
-#define EEPROM_SUBSYSTEM_ID		    (2*0x0A)	/* 2 bytes */
-#define EEPROM_MAC_ADDRESS                  (2*0x15)	/* 6  bytes */
-#define EEPROM_BOARD_REVISION               (2*0x35)	/* 2  bytes */
-#define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1)	/* 9  bytes */
-#define EEPROM_VERSION                      (2*0x44)	/* 2  bytes */
-#define EEPROM_SKU_CAP                      (2*0x45)	/* 2  bytes */
-#define EEPROM_OEM_MODE                     (2*0x46)	/* 2  bytes */
-#define EEPROM_RADIO_CONFIG                 (2*0x48)	/* 2  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   */
-#define EEPROM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
-#define EEPROM_RF_CFG_DASH_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
-#define EEPROM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
-#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
-#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
-
-#define EEPROM_RF_CONFIG_TYPE_MAX	0x3
-
-#define EEPROM_REGULATORY_BAND_NO_HT40			(0)
-
-struct iwl_eeprom_ops {
-	const u32 regulatory_bands[7];
-	bool enhanced_txpower;
-};
-
-
-int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev);
-void iwl_eeprom_free(struct iwl_priv *priv);
-int iwl_eeprom_check_version(struct iwl_priv *priv);
-int iwl_eeprom_init_hw_params(struct iwl_priv *priv);
-u16 iwl_eeprom_calib_version(struct iwl_priv *priv);
-const u8 *iwl_eeprom_query_addr(struct iwl_priv *priv, size_t offset);
-u16 iwl_eeprom_query16(struct iwl_priv *priv, size_t offset);
-void iwl_eeprom_get_mac(struct iwl_priv *priv, u8 *mac);
-int iwl_init_channel_map(struct iwl_priv *priv);
-void iwl_free_channel_map(struct iwl_priv *priv);
-const struct iwl_channel_info *iwl_get_channel_info(
-		const struct iwl_priv *priv,
-		enum ieee80211_band band, u16 channel);
-void iwl_rf_config(struct iwl_priv *priv);
-
-#endif  /* __iwl_eeprom_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index 74bce97..8060466 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -421,6 +421,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
 		(FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4)
 
 #define FH_TX_CHICKEN_BITS_REG	(FH_MEM_LOWER_BOUND + 0xE98)
+#define FH_TX_TRB_REG(_chan)	(FH_MEM_LOWER_BOUND + 0x958 + (_chan) * 4)
+
 /* Instruct FH to increment the retry count of a packet when
  * it is brought from the memory to TX-FIFO
  */
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index 081dd34..66c8733 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -27,6 +27,7 @@
  *****************************************************************************/
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/export.h>
 
 #include "iwl-io.h"
 #include"iwl-csr.h"
@@ -52,6 +53,7 @@ void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
 	__iwl_set_bit(trans, reg, mask);
 	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_set_bit);
 
 void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
 {
@@ -61,6 +63,25 @@ void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
 	__iwl_clear_bit(trans, reg, mask);
 	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_clear_bit);
+
+void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value)
+{
+	unsigned long flags;
+	u32 v;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	WARN_ON_ONCE(value & ~mask);
+#endif
+
+	spin_lock_irqsave(&trans->reg_lock, flags);
+	v = iwl_read32(trans, reg);
+	v &= ~mask;
+	v |= value;
+	iwl_write32(trans, reg, v);
+	spin_unlock_irqrestore(&trans->reg_lock, flags);
+}
+EXPORT_SYMBOL_GPL(iwl_set_bits_mask);
 
 int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
 		 u32 bits, u32 mask, int timeout)
@@ -76,6 +97,7 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
 
 	return -ETIMEDOUT;
 }
+EXPORT_SYMBOL_GPL(iwl_poll_bit);
 
 int iwl_grab_nic_access_silent(struct iwl_trans *trans)
 {
@@ -117,6 +139,7 @@ int iwl_grab_nic_access_silent(struct iwl_trans *trans)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(iwl_grab_nic_access_silent);
 
 bool iwl_grab_nic_access(struct iwl_trans *trans)
 {
@@ -130,6 +153,7 @@ bool iwl_grab_nic_access(struct iwl_trans *trans)
 
 	return true;
 }
+EXPORT_SYMBOL_GPL(iwl_grab_nic_access);
 
 void iwl_release_nic_access(struct iwl_trans *trans)
 {
@@ -144,6 +168,7 @@ void iwl_release_nic_access(struct iwl_trans *trans)
 	 */
 	mmiowb();
 }
+EXPORT_SYMBOL_GPL(iwl_release_nic_access);
 
 u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
 {
@@ -158,6 +183,7 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
 
 	return value;
 }
+EXPORT_SYMBOL_GPL(iwl_read_direct32);
 
 void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
 {
@@ -170,6 +196,7 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
 	}
 	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_write_direct32);
 
 int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
 			int timeout)
@@ -185,6 +212,7 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
 
 	return -ETIMEDOUT;
 }
+EXPORT_SYMBOL_GPL(iwl_poll_direct_bit);
 
 static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 reg)
 {
@@ -211,6 +239,7 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 reg)
 	spin_unlock_irqrestore(&trans->reg_lock, flags);
 	return val;
 }
+EXPORT_SYMBOL_GPL(iwl_read_prph);
 
 void iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val)
 {
@@ -223,6 +252,7 @@ void iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val)
 	}
 	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_write_prph);
 
 void iwl_set_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
 {
@@ -236,6 +266,7 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
 	}
 	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_set_bits_prph);
 
 void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg,
 			    u32 bits, u32 mask)
@@ -250,6 +281,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg,
 	}
 	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph);
 
 void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
 {
@@ -264,9 +296,10 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
 	}
 	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
 
-void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr,
-			      void *buf, int words)
+void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
+			       void *buf, int dwords)
 {
 	unsigned long flags;
 	int offs;
@@ -275,24 +308,26 @@ void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr,
 	spin_lock_irqsave(&trans->reg_lock, flags);
 	if (likely(iwl_grab_nic_access(trans))) {
 		iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
-		for (offs = 0; offs < words; offs++)
+		for (offs = 0; offs < dwords; offs++)
 			vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
 		iwl_release_nic_access(trans);
 	}
 	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(_iwl_read_targ_mem_dwords);
 
 u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
 {
 	u32 value;
 
-	_iwl_read_targ_mem_words(trans, addr, &value, 1);
+	_iwl_read_targ_mem_dwords(trans, addr, &value, 1);
 
 	return value;
 }
+EXPORT_SYMBOL_GPL(iwl_read_targ_mem);
 
-int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
-				void *buf, int words)
+int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
+			       void *buf, int dwords)
 {
 	unsigned long flags;
 	int offs, result = 0;
@@ -301,7 +336,7 @@ int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
 	spin_lock_irqsave(&trans->reg_lock, flags);
 	if (likely(iwl_grab_nic_access(trans))) {
 		iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
-		for (offs = 0; offs < words; offs++)
+		for (offs = 0; offs < dwords; offs++)
 			iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]);
 		iwl_release_nic_access(trans);
 	} else
@@ -310,8 +345,10 @@ int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
 
 	return result;
 }
+EXPORT_SYMBOL_GPL(_iwl_write_targ_mem_dwords);
 
 int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val)
 {
-	return _iwl_write_targ_mem_words(trans, addr, &val, 1);
+	return _iwl_write_targ_mem_dwords(trans, addr, &val, 1);
 }
+EXPORT_SYMBOL_GPL(iwl_write_targ_mem);
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index abb3250..50d3819 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -54,6 +54,8 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs)
 void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask);
 void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask);
 
+void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value);
+
 int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
 		 u32 bits, u32 mask, int timeout);
 int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
@@ -74,18 +76,18 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg,
 			    u32 bits, u32 mask);
 void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask);
 
-void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr,
-			      void *buf, int words);
+void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
+			       void *buf, int dwords);
 
-#define iwl_read_targ_mem_words(trans, addr, buf, bufsize)	\
+#define iwl_read_targ_mem_bytes(trans, addr, buf, bufsize)	\
 	do {							\
 		BUILD_BUG_ON((bufsize) % sizeof(u32));		\
-		_iwl_read_targ_mem_words(trans, addr, buf,	\
-					 (bufsize) / sizeof(u32));\
+		_iwl_read_targ_mem_dwords(trans, addr, buf,	\
+					  (bufsize) / sizeof(u32));\
 	} while (0)
 
-int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
-			      void *buf, int words);
+int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
+			       void *buf, int dwords);
 
 u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr);
 int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val);
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
deleted file mode 100644
index 4700041..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 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.
- *
- * 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/delay.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <net/mac80211.h>
-#include <linux/etherdevice.h>
-#include <asm/unaligned.h>
-
-#include "iwl-dev.h"
-#include "iwl-agn.h"
-#include "iwl-io.h"
-#include "iwl-trans.h"
-#include "iwl-modparams.h"
-
-/* Throughput		OFF time(ms)	ON time (ms)
- *	>300			25		25
- *	>200 to 300		40		40
- *	>100 to 200		55		55
- *	>70 to 100		65		65
- *	>50 to 70		75		75
- *	>20 to 50		85		85
- *	>10 to 20		95		95
- *	>5 to 10		110		110
- *	>1 to 5			130		130
- *	>0 to 1			167		167
- *	<=0					SOLID ON
- */
-static const struct ieee80211_tpt_blink iwl_blink[] = {
-	{ .throughput = 0, .blink_time = 334 },
-	{ .throughput = 1 * 1024 - 1, .blink_time = 260 },
-	{ .throughput = 5 * 1024 - 1, .blink_time = 220 },
-	{ .throughput = 10 * 1024 - 1, .blink_time = 190 },
-	{ .throughput = 20 * 1024 - 1, .blink_time = 170 },
-	{ .throughput = 50 * 1024 - 1, .blink_time = 150 },
-	{ .throughput = 70 * 1024 - 1, .blink_time = 130 },
-	{ .throughput = 100 * 1024 - 1, .blink_time = 110 },
-	{ .throughput = 200 * 1024 - 1, .blink_time = 80 },
-	{ .throughput = 300 * 1024 - 1, .blink_time = 50 },
-};
-
-/* Set led register off */
-void iwlagn_led_enable(struct iwl_priv *priv)
-{
-	iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
-}
-
-/*
- * Adjust led blink rate to compensate on a MAC Clock difference on every HW
- * Led blink rate analysis showed an average deviation of 20% on 5000 series
- * and up.
- * Need to compensate on the led on/off time per HW according to the deviation
- * to achieve the desired led frequency
- * The calculation is: (100-averageDeviation)/100 * blinkTime
- * For code efficiency the calculation will be:
- *     compensation = (100 - averageDeviation) * 64 / 100
- *     NewBlinkTime = (compensation * BlinkTime) / 64
- */
-static inline u8 iwl_blink_compensation(struct iwl_priv *priv,
-				    u8 time, u16 compensation)
-{
-	if (!compensation) {
-		IWL_ERR(priv, "undefined blink compensation: "
-			"use pre-defined blinking time\n");
-		return time;
-	}
-
-	return (u8)((time * compensation) >> 6);
-}
-
-static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
-{
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_LEDS_CMD,
-		.len = { sizeof(struct iwl_led_cmd), },
-		.data = { led_cmd, },
-		.flags = CMD_ASYNC,
-	};
-	u32 reg;
-
-	reg = iwl_read32(priv->trans, CSR_LED_REG);
-	if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
-		iwl_write32(priv->trans, CSR_LED_REG,
-			    reg & CSR_LED_BSM_CTRL_MSK);
-
-	return iwl_dvm_send_cmd(priv, &cmd);
-}
-
-/* Set led pattern command */
-static int iwl_led_cmd(struct iwl_priv *priv,
-		       unsigned long on,
-		       unsigned long off)
-{
-	struct iwl_led_cmd led_cmd = {
-		.id = IWL_LED_LINK,
-		.interval = IWL_DEF_LED_INTRVL
-	};
-	int ret;
-
-	if (!test_bit(STATUS_READY, &priv->status))
-		return -EBUSY;
-
-	if (priv->blink_on == on && priv->blink_off == off)
-		return 0;
-
-	if (off == 0) {
-		/* led is SOLID_ON */
-		on = IWL_LED_SOLID;
-	}
-
-	IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n",
-			priv->cfg->base_params->led_compensation);
-	led_cmd.on = iwl_blink_compensation(priv, on,
-				priv->cfg->base_params->led_compensation);
-	led_cmd.off = iwl_blink_compensation(priv, off,
-				priv->cfg->base_params->led_compensation);
-
-	ret = iwl_send_led_cmd(priv, &led_cmd);
-	if (!ret) {
-		priv->blink_on = on;
-		priv->blink_off = off;
-	}
-	return ret;
-}
-
-static void iwl_led_brightness_set(struct led_classdev *led_cdev,
-				   enum led_brightness brightness)
-{
-	struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
-	unsigned long on = 0;
-
-	if (brightness > 0)
-		on = IWL_LED_SOLID;
-
-	iwl_led_cmd(priv, on, 0);
-}
-
-static int iwl_led_blink_set(struct led_classdev *led_cdev,
-			     unsigned long *delay_on,
-			     unsigned long *delay_off)
-{
-	struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
-
-	return iwl_led_cmd(priv, *delay_on, *delay_off);
-}
-
-void iwl_leds_init(struct iwl_priv *priv)
-{
-	int mode = iwlwifi_mod_params.led_mode;
-	int ret;
-
-	if (mode == IWL_LED_DISABLE) {
-		IWL_INFO(priv, "Led disabled\n");
-		return;
-	}
-	if (mode == IWL_LED_DEFAULT)
-		mode = priv->cfg->led_mode;
-
-	priv->led.name = kasprintf(GFP_KERNEL, "%s-led",
-				   wiphy_name(priv->hw->wiphy));
-	priv->led.brightness_set = iwl_led_brightness_set;
-	priv->led.blink_set = iwl_led_blink_set;
-	priv->led.max_brightness = 1;
-
-	switch (mode) {
-	case IWL_LED_DEFAULT:
-		WARN_ON(1);
-		break;
-	case IWL_LED_BLINK:
-		priv->led.default_trigger =
-			ieee80211_create_tpt_led_trigger(priv->hw,
-					IEEE80211_TPT_LEDTRIG_FL_CONNECTED,
-					iwl_blink, ARRAY_SIZE(iwl_blink));
-		break;
-	case IWL_LED_RF_STATE:
-		priv->led.default_trigger =
-			ieee80211_get_radio_led_name(priv->hw);
-		break;
-	}
-
-	ret = led_classdev_register(priv->trans->dev, &priv->led);
-	if (ret) {
-		kfree(priv->led.name);
-		return;
-	}
-
-	priv->led_registered = true;
-}
-
-void iwl_leds_exit(struct iwl_priv *priv)
-{
-	if (!priv->led_registered)
-		return;
-
-	led_classdev_unregister(&priv->led);
-	kfree(priv->led.name);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
deleted file mode 100644
index b02a853..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 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.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#ifndef __iwl_leds_h__
-#define __iwl_leds_h__
-
-
-struct iwl_priv;
-
-#define IWL_LED_SOLID 11
-#define IWL_DEF_LED_INTRVL cpu_to_le32(1000)
-
-#define IWL_LED_ACTIVITY       (0<<1)
-#define IWL_LED_LINK           (1<<1)
-
-void iwlagn_led_enable(struct iwl_priv *priv);
-void iwl_leds_init(struct iwl_priv *priv);
-void iwl_leds_exit(struct iwl_priv *priv);
-
-#endif /* __iwl_leds_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
deleted file mode 100644
index 3ee23134..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c
+++ /dev/null
@@ -1,1633 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-
-#include <net/mac80211.h>
-
-#include <asm/div64.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-calib.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-#include "iwl-op-mode.h"
-#include "iwl-modparams.h"
-
-/*****************************************************************************
- *
- * mac80211 entry point functions
- *
- *****************************************************************************/
-
-static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
-	{
-		.max = 1,
-		.types = BIT(NL80211_IFTYPE_STATION),
-	},
-	{
-		.max = 1,
-		.types = BIT(NL80211_IFTYPE_AP),
-	},
-};
-
-static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
-	{
-		.max = 2,
-		.types = BIT(NL80211_IFTYPE_STATION),
-	},
-};
-
-static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
-	{
-		.max = 1,
-		.types = BIT(NL80211_IFTYPE_STATION),
-	},
-	{
-		.max = 1,
-		.types = BIT(NL80211_IFTYPE_P2P_GO) |
-			 BIT(NL80211_IFTYPE_AP),
-	},
-};
-
-static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
-	{
-		.max = 2,
-		.types = BIT(NL80211_IFTYPE_STATION),
-	},
-	{
-		.max = 1,
-		.types = BIT(NL80211_IFTYPE_P2P_CLIENT),
-	},
-};
-
-static const struct ieee80211_iface_combination
-iwlagn_iface_combinations_dualmode[] = {
-	{ .num_different_channels = 1,
-	  .max_interfaces = 2,
-	  .beacon_int_infra_match = true,
-	  .limits = iwlagn_sta_ap_limits,
-	  .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
-	},
-	{ .num_different_channels = 1,
-	  .max_interfaces = 2,
-	  .limits = iwlagn_2sta_limits,
-	  .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
-	},
-};
-
-static const struct ieee80211_iface_combination
-iwlagn_iface_combinations_p2p[] = {
-	{ .num_different_channels = 1,
-	  .max_interfaces = 2,
-	  .beacon_int_infra_match = true,
-	  .limits = iwlagn_p2p_sta_go_limits,
-	  .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
-	},
-	{ .num_different_channels = 1,
-	  .max_interfaces = 2,
-	  .limits = iwlagn_p2p_2sta_limits,
-	  .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
-	},
-};
-
-/*
- * Not a mac80211 entry point function, but it fits in with all the
- * other mac80211 functions grouped here.
- */
-int iwlagn_mac_setup_register(struct iwl_priv *priv,
-			      const struct iwl_ucode_capabilities *capa)
-{
-	int ret;
-	struct ieee80211_hw *hw = priv->hw;
-	struct iwl_rxon_context *ctx;
-
-	hw->rate_control_algorithm = "iwl-agn-rs";
-
-	/* Tell mac80211 our characteristics */
-	hw->flags = IEEE80211_HW_SIGNAL_DBM |
-		    IEEE80211_HW_AMPDU_AGGREGATION |
-		    IEEE80211_HW_NEED_DTIM_PERIOD |
-		    IEEE80211_HW_SPECTRUM_MGMT |
-		    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
-		    IEEE80211_HW_QUEUE_CONTROL |
-		    IEEE80211_HW_SUPPORTS_PS |
-		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
-		    IEEE80211_HW_WANT_MONITOR_VIF |
-		    IEEE80211_HW_SCAN_WHILE_IDLE;
-
-	hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
-
-	/*
-	 * Including the following line will crash some AP's.  This
-	 * workaround removes the stimulus which causes the crash until
-	 * the AP software can be fixed.
-	hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-	 */
-
-	if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
-		hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
-			     IEEE80211_HW_SUPPORTS_STATIC_SMPS;
-
-#ifndef CONFIG_IWLWIFI_EXPERIMENTAL_MFP
-	/* enable 11w if the uCode advertise */
-	if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
-#endif /* !CONFIG_IWLWIFI_EXPERIMENTAL_MFP */
-		hw->flags |= IEEE80211_HW_MFP_CAPABLE;
-
-	hw->sta_data_size = sizeof(struct iwl_station_priv);
-	hw->vif_data_size = sizeof(struct iwl_vif_priv);
-
-	for_each_context(priv, ctx) {
-		hw->wiphy->interface_modes |= ctx->interface_modes;
-		hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
-	}
-
-	BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-
-	if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
-		hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
-		hw->wiphy->n_iface_combinations =
-			ARRAY_SIZE(iwlagn_iface_combinations_p2p);
-	} else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
-		hw->wiphy->iface_combinations =
-			iwlagn_iface_combinations_dualmode;
-		hw->wiphy->n_iface_combinations =
-			ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
-	}
-
-	hw->wiphy->max_remain_on_channel_duration = 1000;
-
-	hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
-			    WIPHY_FLAG_DISABLE_BEACON_HINTS |
-			    WIPHY_FLAG_IBSS_RSN;
-
-#ifdef CONFIG_PM_SLEEP
-	if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
-	    priv->trans->ops->wowlan_suspend &&
-	    device_can_wakeup(priv->trans->dev)) {
-		hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-					  WIPHY_WOWLAN_DISCONNECT |
-					  WIPHY_WOWLAN_EAP_IDENTITY_REQ |
-					  WIPHY_WOWLAN_RFKILL_RELEASE;
-		if (!iwlwifi_mod_params.sw_crypto)
-			hw->wiphy->wowlan.flags |=
-				WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
-				WIPHY_WOWLAN_GTK_REKEY_FAILURE;
-
-		hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
-		hw->wiphy->wowlan.pattern_min_len =
-					IWLAGN_WOWLAN_MIN_PATTERN_LEN;
-		hw->wiphy->wowlan.pattern_max_len =
-					IWLAGN_WOWLAN_MAX_PATTERN_LEN;
-	}
-#endif
-
-	if (iwlwifi_mod_params.power_save)
-		hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
-	else
-		hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-
-	hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
-	/* we create the 802.11 header and a max-length SSID element */
-	hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 34;
-
-	/*
-	 * We don't use all queues: 4 and 9 are unused and any
-	 * aggregation queue gets mapped down to the AC queue.
-	 */
-	hw->queues = IWLAGN_FIRST_AMPDU_QUEUE;
-
-	hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
-
-	if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
-		priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-			&priv->bands[IEEE80211_BAND_2GHZ];
-	if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
-		priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-			&priv->bands[IEEE80211_BAND_5GHZ];
-
-	hw->wiphy->hw_version = priv->trans->hw_id;
-
-	iwl_leds_init(priv);
-
-	ret = ieee80211_register_hw(priv->hw);
-	if (ret) {
-		IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
-		iwl_leds_exit(priv);
-		return ret;
-	}
-	priv->mac80211_registered = 1;
-
-	return 0;
-}
-
-void iwlagn_mac_unregister(struct iwl_priv *priv)
-{
-	if (!priv->mac80211_registered)
-		return;
-	iwl_leds_exit(priv);
-	ieee80211_unregister_hw(priv->hw);
-	priv->mac80211_registered = 0;
-}
-
-static int __iwl_up(struct iwl_priv *priv)
-{
-	struct iwl_rxon_context *ctx;
-	int ret;
-
-	lockdep_assert_held(&priv->mutex);
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-		IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
-		return -EIO;
-	}
-
-	for_each_context(priv, ctx) {
-		ret = iwlagn_alloc_bcast_station(priv, ctx);
-		if (ret) {
-			iwl_dealloc_bcast_stations(priv);
-			return ret;
-		}
-	}
-
-	ret = iwl_run_init_ucode(priv);
-	if (ret) {
-		IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
-		goto error;
-	}
-
-	ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
-	if (ret) {
-		IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
-		goto error;
-	}
-
-	ret = iwl_alive_start(priv);
-	if (ret)
-		goto error;
-	return 0;
-
- error:
-	set_bit(STATUS_EXIT_PENDING, &priv->status);
-	iwl_down(priv);
-	clear_bit(STATUS_EXIT_PENDING, &priv->status);
-
-	IWL_ERR(priv, "Unable to initialize device.\n");
-	return ret;
-}
-
-static int iwlagn_mac_start(struct ieee80211_hw *hw)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	int ret;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-
-	/* we should be verifying the device is ready to be opened */
-	mutex_lock(&priv->mutex);
-	ret = __iwl_up(priv);
-	mutex_unlock(&priv->mutex);
-	if (ret)
-		return ret;
-
-	IWL_DEBUG_INFO(priv, "Start UP work done.\n");
-
-	/* Now we should be done, and the READY bit should be set. */
-	if (WARN_ON(!test_bit(STATUS_READY, &priv->status)))
-		ret = -EIO;
-
-	iwlagn_led_enable(priv);
-
-	priv->is_open = 1;
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-	return 0;
-}
-
-void iwlagn_mac_stop(struct ieee80211_hw *hw)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-
-	if (!priv->is_open)
-		return;
-
-	priv->is_open = 0;
-
-	mutex_lock(&priv->mutex);
-	iwl_down(priv);
-	mutex_unlock(&priv->mutex);
-
-	iwl_cancel_deferred_work(priv);
-
-	flush_workqueue(priv->workqueue);
-
-	/* User space software may expect getting rfkill changes
-	 * even if interface is down, trans->down will leave the RF
-	 * kill interrupt enabled
-	 */
-	iwl_trans_stop_hw(priv->trans, false);
-
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
-			       struct ieee80211_vif *vif,
-			       struct cfg80211_gtk_rekey_data *data)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-	if (iwlwifi_mod_params.sw_crypto)
-		return;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-	mutex_lock(&priv->mutex);
-
-	if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
-		goto out;
-
-	memcpy(priv->kek, data->kek, NL80211_KEK_LEN);
-	memcpy(priv->kck, data->kck, NL80211_KCK_LEN);
-	priv->replay_ctr =
-		cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
-	priv->have_rekey_data = true;
-
- out:
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-#ifdef CONFIG_PM_SLEEP
-
-int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-	int ret;
-
-	if (WARN_ON(!wowlan))
-		return -EINVAL;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-	mutex_lock(&priv->mutex);
-
-	/* Don't attempt WoWLAN when not associated, tear down instead. */
-	if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
-	    !iwl_is_associated_ctx(ctx)) {
-		ret = 1;
-		goto out;
-	}
-
-	ret = iwlagn_suspend(priv, wowlan);
-	if (ret)
-		goto error;
-
-	device_set_wakeup_enable(priv->trans->dev, true);
-
-	iwl_trans_wowlan_suspend(priv->trans);
-
-	goto out;
-
- error:
-	priv->wowlan = false;
-	iwlagn_prepare_restart(priv);
-	ieee80211_restart_hw(priv->hw);
- out:
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-
-	return ret;
-}
-
-static int iwlagn_mac_resume(struct ieee80211_hw *hw)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-	struct ieee80211_vif *vif;
-	unsigned long flags;
-	u32 base, status = 0xffffffff;
-	int ret = -EIO;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-	mutex_lock(&priv->mutex);
-
-	iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
-			  CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
-
-	base = priv->device_pointers.error_event_table;
-	if (iwlagn_hw_valid_rtc_data_addr(base)) {
-		spin_lock_irqsave(&priv->trans->reg_lock, flags);
-		ret = iwl_grab_nic_access_silent(priv->trans);
-		if (likely(ret == 0)) {
-			iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
-			status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-			iwl_release_nic_access(priv->trans);
-		}
-		spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-		if (ret == 0) {
-			const struct fw_img *img;
-
-			img = &(priv->fw->img[IWL_UCODE_WOWLAN]);
-			if (!priv->wowlan_sram) {
-				priv->wowlan_sram =
-				   kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
-						GFP_KERNEL);
-			}
-
-			if (priv->wowlan_sram)
-				_iwl_read_targ_mem_words(
-				      priv->trans, 0x800000,
-				      priv->wowlan_sram,
-				      img->sec[IWL_UCODE_SECTION_DATA].len / 4);
-		}
-#endif
-	}
-
-	/* we'll clear ctx->vif during iwlagn_prepare_restart() */
-	vif = ctx->vif;
-
-	priv->wowlan = false;
-
-	device_set_wakeup_enable(priv->trans->dev, false);
-
-	iwlagn_prepare_restart(priv);
-
-	memset((void *)&ctx->active, 0, sizeof(ctx->active));
-	iwl_connection_init_rx_config(priv, ctx);
-	iwlagn_set_rxon_chain(priv, ctx);
-
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-
-	ieee80211_resume_disconnect(vif);
-
-	return 1;
-}
-
-#endif
-
-void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-	IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
-		     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
-
-	if (iwlagn_tx_skb(priv, skb))
-		dev_kfree_skb_any(skb);
-}
-
-void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
-				struct ieee80211_vif *vif,
-				struct ieee80211_key_conf *keyconf,
-				struct ieee80211_sta *sta,
-				u32 iv32, u16 *phase1key)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-	iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
-}
-
-int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
-		       struct ieee80211_vif *vif,
-		       struct ieee80211_sta *sta,
-		       struct ieee80211_key_conf *key)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-	struct iwl_rxon_context *ctx = vif_priv->ctx;
-	int ret;
-	bool is_default_wep_key = false;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-
-	if (iwlwifi_mod_params.sw_crypto) {
-		IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
-		return -EOPNOTSUPP;
-	}
-
-	switch (key->cipher) {
-	case WLAN_CIPHER_SUITE_TKIP:
-		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-		/* fall through */
-	case WLAN_CIPHER_SUITE_CCMP:
-		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-		break;
-	default:
-		break;
-	}
-
-	/*
-	 * We could program these keys into the hardware as well, but we
-	 * don't expect much multicast traffic in IBSS and having keys
-	 * for more stations is probably more useful.
-	 *
-	 * Mark key TX-only and return 0.
-	 */
-	if (vif->type == NL80211_IFTYPE_ADHOC &&
-	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
-		key->hw_key_idx = WEP_INVALID_OFFSET;
-		return 0;
-	}
-
-	/* If they key was TX-only, accept deletion */
-	if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
-		return 0;
-
-	mutex_lock(&priv->mutex);
-	iwl_scan_cancel_timeout(priv, 100);
-
-	BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
-
-	/*
-	 * If we are getting WEP group key and we didn't receive any key mapping
-	 * so far, we are in legacy wep mode (group key only), otherwise we are
-	 * in 1X mode.
-	 * In legacy wep mode, we use another host command to the uCode.
-	 */
-	if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-	     key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
-		if (cmd == SET_KEY)
-			is_default_wep_key = !ctx->key_mapping_keys;
-		else
-			is_default_wep_key =
-				key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
-	}
-
-
-	switch (cmd) {
-	case SET_KEY:
-		if (is_default_wep_key) {
-			ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
-			break;
-		}
-		ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
-		if (ret) {
-			/*
-			 * can't add key for RX, but we don't need it
-			 * in the device for TX so still return 0
-			 */
-			ret = 0;
-			key->hw_key_idx = WEP_INVALID_OFFSET;
-		}
-
-		IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
-		break;
-	case DISABLE_KEY:
-		if (is_default_wep_key)
-			ret = iwl_remove_default_wep_key(priv, ctx, key);
-		else
-			ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
-
-		IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-
-	return ret;
-}
-
-int iwlagn_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,
-			    u8 buf_size)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	int ret = -EINVAL;
-	struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
-
-	IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
-		     sta->addr, tid);
-
-	if (!(priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE))
-		return -EACCES;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-	mutex_lock(&priv->mutex);
-
-	switch (action) {
-	case IEEE80211_AMPDU_RX_START:
-		if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
-			break;
-		IWL_DEBUG_HT(priv, "start Rx\n");
-		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);
-		break;
-	case IEEE80211_AMPDU_TX_START:
-		if (!priv->trans->ops->tx_agg_setup)
-			break;
-		if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
-			break;
-		IWL_DEBUG_HT(priv, "start Tx\n");
-		ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
-		break;
-	case IEEE80211_AMPDU_TX_STOP:
-		IWL_DEBUG_HT(priv, "stop Tx\n");
-		ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
-		if ((ret == 0) && (priv->agg_tids_count > 0)) {
-			priv->agg_tids_count--;
-			IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
-				     priv->agg_tids_count);
-		}
-		if (!priv->agg_tids_count &&
-		    priv->hw_params.use_rts_for_aggregation) {
-			/*
-			 * switch off RTS/CTS if it was previously enabled
-			 */
-			sta_priv->lq_sta.lq.general_params.flags &=
-				~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-			iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
-					&sta_priv->lq_sta.lq, CMD_ASYNC, false);
-		}
-		break;
-	case IEEE80211_AMPDU_TX_OPERATIONAL:
-		ret = iwlagn_tx_agg_oper(priv, vif, sta, tid, buf_size);
-		break;
-	}
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-	return ret;
-}
-
-static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
-			      struct ieee80211_vif *vif,
-			      struct ieee80211_sta *sta)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-	bool is_ap = vif->type == NL80211_IFTYPE_STATION;
-	int ret;
-	u8 sta_id;
-
-	IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
-			sta->addr);
-	sta_priv->sta_id = IWL_INVALID_STATION;
-
-	atomic_set(&sta_priv->pending_frames, 0);
-	if (vif->type == NL80211_IFTYPE_AP)
-		sta_priv->client = true;
-
-	ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
-				     is_ap, sta, &sta_id);
-	if (ret) {
-		IWL_ERR(priv, "Unable to add station %pM (%d)\n",
-			sta->addr, ret);
-		/* Should we return success if return code is EEXIST ? */
-		return ret;
-	}
-
-	sta_priv->sta_id = sta_id;
-
-	return 0;
-}
-
-static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
-				 struct ieee80211_vif *vif,
-				 struct ieee80211_sta *sta)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-	int ret;
-
-	IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", sta->addr);
-
-	if (vif->type == NL80211_IFTYPE_STATION) {
-		/*
-		 * Station will be removed from device when the RXON
-		 * is set to unassociated -- just deactivate it here
-		 * to avoid re-programming it.
-		 */
-		ret = 0;
-		iwl_deactivate_station(priv, sta_priv->sta_id, sta->addr);
-	} else {
-		ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
-		if (ret)
-			IWL_DEBUG_QUIET_RFKILL(priv,
-				"Error removing station %pM\n", sta->addr);
-	}
-	return ret;
-}
-
-int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
-			 struct ieee80211_vif *vif,
-			 struct ieee80211_sta *sta,
-			 enum ieee80211_sta_state old_state,
-			 enum ieee80211_sta_state new_state)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-	enum {
-		NONE, ADD, REMOVE, HT_RATE_INIT, ADD_RATE_INIT,
-	} op = NONE;
-	int ret;
-
-	IWL_DEBUG_MAC80211(priv, "station %pM state change %d->%d\n",
-			   sta->addr, old_state, new_state);
-
-	mutex_lock(&priv->mutex);
-	if (vif->type == NL80211_IFTYPE_STATION) {
-		if (old_state == IEEE80211_STA_NOTEXIST &&
-		    new_state == IEEE80211_STA_NONE)
-			op = ADD;
-		else if (old_state == IEEE80211_STA_NONE &&
-			 new_state == IEEE80211_STA_NOTEXIST)
-			op = REMOVE;
-		else if (old_state == IEEE80211_STA_AUTH &&
-			 new_state == IEEE80211_STA_ASSOC)
-			op = HT_RATE_INIT;
-	} else {
-		if (old_state == IEEE80211_STA_AUTH &&
-		    new_state == IEEE80211_STA_ASSOC)
-			op = ADD_RATE_INIT;
-		else if (old_state == IEEE80211_STA_ASSOC &&
-			 new_state == IEEE80211_STA_AUTH)
-			op = REMOVE;
-	}
-
-	switch (op) {
-	case ADD:
-		ret = iwlagn_mac_sta_add(hw, vif, sta);
-		break;
-	case REMOVE:
-		ret = iwlagn_mac_sta_remove(hw, vif, sta);
-		break;
-	case ADD_RATE_INIT:
-		ret = iwlagn_mac_sta_add(hw, vif, sta);
-		if (ret)
-			break;
-		/* Initialize rate scaling */
-		IWL_DEBUG_INFO(priv,
-			       "Initializing rate scaling for station %pM\n",
-			       sta->addr);
-		iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
-		ret = 0;
-		break;
-	case HT_RATE_INIT:
-		/* Initialize rate scaling */
-		ret = iwl_sta_update_ht(priv, vif_priv->ctx, sta);
-		if (ret)
-			break;
-		IWL_DEBUG_INFO(priv,
-			       "Initializing rate scaling for station %pM\n",
-			       sta->addr);
-		iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
-		ret = 0;
-		break;
-	default:
-		ret = 0;
-		break;
-	}
-
-	/*
-	 * mac80211 might WARN if we fail, but due the way we
-	 * (badly) handle hard rfkill, we might fail here
-	 */
-	if (iwl_is_rfkill(priv))
-		ret = 0;
-
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-
-	return ret;
-}
-
-void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
-			       struct ieee80211_channel_switch *ch_switch)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	const struct iwl_channel_info *ch_info;
-	struct ieee80211_conf *conf = &hw->conf;
-	struct ieee80211_channel *channel = ch_switch->channel;
-	struct iwl_ht_config *ht_conf = &priv->current_ht_config;
-	/*
-	 * MULTI-FIXME
-	 * When we add support for multiple interfaces, we need to
-	 * revisit this. The channel switch command in the device
-	 * only affects the BSS context, but what does that really
-	 * mean? And what if we get a CSA on the second interface?
-	 * This needs a lot of work.
-	 */
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-	u16 ch;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-
-	mutex_lock(&priv->mutex);
-
-	if (iwl_is_rfkill(priv))
-		goto out;
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-	    test_bit(STATUS_SCANNING, &priv->status) ||
-	    test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
-		goto out;
-
-	if (!iwl_is_associated_ctx(ctx))
-		goto out;
-
-	if (!priv->lib->set_channel_switch)
-		goto out;
-
-	ch = channel->hw_value;
-	if (le16_to_cpu(ctx->active.channel) == ch)
-		goto out;
-
-	ch_info = iwl_get_channel_info(priv, channel->band, ch);
-	if (!is_channel_valid(ch_info)) {
-		IWL_DEBUG_MAC80211(priv, "invalid channel\n");
-		goto out;
-	}
-
-	priv->current_ht_config.smps = conf->smps_mode;
-
-	/* Configure HT40 channels */
-	ctx->ht.enabled = conf_is_ht(conf);
-	if (ctx->ht.enabled)
-		iwlagn_config_ht40(conf, ctx);
-	else
-		ctx->ht.is_40mhz = false;
-
-	if ((le16_to_cpu(ctx->staging.channel) != ch))
-		ctx->staging.flags = 0;
-
-	iwl_set_rxon_channel(priv, channel, ctx);
-	iwl_set_rxon_ht(priv, ht_conf);
-	iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
-
-	/*
-	 * at this point, staging_rxon has the
-	 * configuration for channel switch
-	 */
-	set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
-	priv->switch_channel = cpu_to_le16(ch);
-	if (priv->lib->set_channel_switch(priv, ch_switch)) {
-		clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
-		priv->switch_channel = 0;
-		ieee80211_chswitch_done(ctx->vif, false);
-	}
-
-out:
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
-{
-	/*
-	 * MULTI-FIXME
-	 * See iwlagn_mac_channel_switch.
-	 */
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
-		ieee80211_chswitch_done(ctx->vif, is_success);
-}
-
-void iwlagn_configure_filter(struct ieee80211_hw *hw,
-			     unsigned int changed_flags,
-			     unsigned int *total_flags,
-			     u64 multicast)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	__le32 filter_or = 0, filter_nand = 0;
-	struct iwl_rxon_context *ctx;
-
-#define CHK(test, flag)	do { \
-	if (*total_flags & (test))		\
-		filter_or |= (flag);		\
-	else					\
-		filter_nand |= (flag);		\
-	} while (0)
-
-	IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
-			changed_flags, *total_flags);
-
-	CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
-	/* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
-	CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
-	CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
-
-#undef CHK
-
-	mutex_lock(&priv->mutex);
-
-	for_each_context(priv, ctx) {
-		ctx->staging.filter_flags &= ~filter_nand;
-		ctx->staging.filter_flags |= filter_or;
-
-		/*
-		 * Not committing directly because hardware can perform a scan,
-		 * but we'll eventually commit the filter flags change anyway.
-		 */
-	}
-
-	mutex_unlock(&priv->mutex);
-
-	/*
-	 * Receiving all multicast frames is always enabled by the
-	 * default flags setup in iwl_connection_init_rx_config()
-	 * since we currently do not support programming multicast
-	 * filters into the device.
-	 */
-	*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
-			FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
-}
-
-void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-	mutex_lock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-
-	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 (iwlagn_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");
-	iwl_trans_wait_tx_queue_empty(priv->trans);
-done:
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
-				     struct ieee80211_channel *channel,
-				     enum nl80211_channel_type channel_type,
-				     int duration)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-	int err = 0;
-
-	if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
-		return -EOPNOTSUPP;
-
-	if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
-		return -EOPNOTSUPP;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-	mutex_lock(&priv->mutex);
-
-	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
-		err = -EBUSY;
-		goto out;
-	}
-
-	priv->hw_roc_channel = channel;
-	priv->hw_roc_chantype = channel_type;
-	/* convert from ms to TU */
-	priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024);
-	priv->hw_roc_start_notified = false;
-	cancel_delayed_work(&priv->hw_roc_disable_work);
-
-	if (!ctx->is_active) {
-		static const struct iwl_qos_info default_qos_data = {
-			.def_qos_parm = {
-				.ac[0] = {
-					.cw_min = cpu_to_le16(3),
-					.cw_max = cpu_to_le16(7),
-					.aifsn = 2,
-					.edca_txop = cpu_to_le16(1504),
-				},
-				.ac[1] = {
-					.cw_min = cpu_to_le16(7),
-					.cw_max = cpu_to_le16(15),
-					.aifsn = 2,
-					.edca_txop = cpu_to_le16(3008),
-				},
-				.ac[2] = {
-					.cw_min = cpu_to_le16(15),
-					.cw_max = cpu_to_le16(1023),
-					.aifsn = 3,
-				},
-				.ac[3] = {
-					.cw_min = cpu_to_le16(15),
-					.cw_max = cpu_to_le16(1023),
-					.aifsn = 7,
-				},
-			},
-		};
-
-		ctx->is_active = true;
-		ctx->qos_data = default_qos_data;
-		ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
-		memcpy(ctx->staging.node_addr,
-		       priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
-		       ETH_ALEN);
-		memcpy(ctx->staging.bssid_addr,
-		       priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
-		       ETH_ALEN);
-		err = iwlagn_commit_rxon(priv, ctx);
-		if (err)
-			goto out;
-		ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
-					     RXON_FILTER_PROMISC_MSK |
-					     RXON_FILTER_CTL2HOST_MSK;
-
-		err = iwlagn_commit_rxon(priv, ctx);
-		if (err) {
-			iwlagn_disable_roc(priv);
-			goto out;
-		}
-		priv->hw_roc_setup = true;
-	}
-
-	err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
-	if (err)
-		iwlagn_disable_roc(priv);
-
- out:
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-
-	return err;
-}
-
-int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-	if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
-		return -EOPNOTSUPP;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-	mutex_lock(&priv->mutex);
-	iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
-	iwlagn_disable_roc(priv);
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-
-	return 0;
-}
-
-void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
-			      enum ieee80211_rssi_event rssi_event)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-	mutex_lock(&priv->mutex);
-
-	if (priv->cfg->bt_params &&
-			priv->cfg->bt_params->advanced_bt_coexist) {
-		if (rssi_event == RSSI_EVENT_LOW)
-			priv->bt_enable_pspoll = true;
-		else if (rssi_event == RSSI_EVENT_HIGH)
-			priv->bt_enable_pspoll = false;
-
-		iwlagn_send_advance_bt_config(priv);
-	} else {
-		IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
-				"ignoring RSSI callback\n");
-	}
-
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
-		       struct ieee80211_sta *sta, bool set)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-	queue_work(priv->workqueue, &priv->beacon_update);
-
-	return 0;
-}
-
-int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
-		       struct ieee80211_vif *vif, u16 queue,
-		       const struct ieee80211_tx_queue_params *params)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-	struct iwl_rxon_context *ctx = vif_priv->ctx;
-	int q;
-
-	if (WARN_ON(!ctx))
-		return -EINVAL;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-
-	if (!iwl_is_ready_rf(priv)) {
-		IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
-		return -EIO;
-	}
-
-	if (queue >= AC_NUM) {
-		IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
-		return 0;
-	}
-
-	q = AC_NUM - 1 - queue;
-
-	mutex_lock(&priv->mutex);
-
-	ctx->qos_data.def_qos_parm.ac[q].cw_min =
-		cpu_to_le16(params->cw_min);
-	ctx->qos_data.def_qos_parm.ac[q].cw_max =
-		cpu_to_le16(params->cw_max);
-	ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
-	ctx->qos_data.def_qos_parm.ac[q].edca_txop =
-			cpu_to_le16((params->txop * 32));
-
-	ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
-
-	mutex_unlock(&priv->mutex);
-
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-	return 0;
-}
-
-int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-	return priv->ibss_manager == IWL_IBSS_MANAGER;
-}
-
-static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-	iwl_connection_init_rx_config(priv, ctx);
-
-	iwlagn_set_rxon_chain(priv, ctx);
-
-	return iwlagn_commit_rxon(priv, ctx);
-}
-
-int iwl_setup_interface(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-	struct ieee80211_vif *vif = ctx->vif;
-	int err, ac;
-
-	lockdep_assert_held(&priv->mutex);
-
-	/*
-	 * This variable will be correct only when there's just
-	 * a single context, but all code using it is for hardware
-	 * that supports only one context.
-	 */
-	priv->iw_mode = vif->type;
-
-	ctx->is_active = true;
-
-	err = iwl_set_mode(priv, ctx);
-	if (err) {
-		if (!ctx->always_active)
-			ctx->is_active = false;
-		return err;
-	}
-
-	if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
-	    vif->type == NL80211_IFTYPE_ADHOC) {
-		/*
-		 * pretend to have high BT traffic as long as we
-		 * are operating in IBSS mode, as this will cause
-		 * the rate scaling etc. to behave as intended.
-		 */
-		priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
-	}
-
-	/* set up queue mappings */
-	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-		vif->hw_queue[ac] = ctx->ac_to_queue[ac];
-
-	if (vif->type == NL80211_IFTYPE_AP)
-		vif->cab_queue = ctx->mcast_queue;
-	else
-		vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
-
-	return 0;
-}
-
-static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
-				    struct ieee80211_vif *vif)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-	struct iwl_rxon_context *tmp, *ctx = NULL;
-	int err;
-	enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
-	bool reset = false;
-
-	IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
-			   viftype, vif->addr);
-
-	cancel_delayed_work_sync(&priv->hw_roc_disable_work);
-
-	mutex_lock(&priv->mutex);
-
-	iwlagn_disable_roc(priv);
-
-	if (!iwl_is_ready_rf(priv)) {
-		IWL_WARN(priv, "Try to add interface when device not ready\n");
-		err = -EINVAL;
-		goto out;
-	}
-
-	for_each_context(priv, tmp) {
-		u32 possible_modes =
-			tmp->interface_modes | tmp->exclusive_interface_modes;
-
-		if (tmp->vif) {
-			/* On reset we need to add the same interface again */
-			if (tmp->vif == vif) {
-				reset = true;
-				ctx = tmp;
-				break;
-			}
-
-			/* check if this busy context is exclusive */
-			if (tmp->exclusive_interface_modes &
-						BIT(tmp->vif->type)) {
-				err = -EINVAL;
-				goto out;
-			}
-			continue;
-		}
-
-		if (!(possible_modes & BIT(viftype)))
-			continue;
-
-		/* have maybe usable context w/o interface */
-		ctx = tmp;
-		break;
-	}
-
-	if (!ctx) {
-		err = -EOPNOTSUPP;
-		goto out;
-	}
-
-	vif_priv->ctx = ctx;
-	ctx->vif = vif;
-
-	err = iwl_setup_interface(priv, ctx);
-	if (!err || reset)
-		goto out;
-
-	ctx->vif = NULL;
-	priv->iw_mode = NL80211_IFTYPE_STATION;
- out:
-	mutex_unlock(&priv->mutex);
-
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-	return err;
-}
-
-void iwl_teardown_interface(struct iwl_priv *priv,
-			    struct ieee80211_vif *vif,
-			    bool mode_change)
-{
-	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
-	lockdep_assert_held(&priv->mutex);
-
-	if (priv->scan_vif == vif) {
-		iwl_scan_cancel_timeout(priv, 200);
-		iwl_force_scan_end(priv);
-	}
-
-	if (!mode_change) {
-		iwl_set_mode(priv, ctx);
-		if (!ctx->always_active)
-			ctx->is_active = false;
-	}
-
-	/*
-	 * When removing the IBSS interface, overwrite the
-	 * BT traffic load with the stored one from the last
-	 * notification, if any. If this is a device that
-	 * doesn't implement this, this has no effect since
-	 * both values are the same and zero.
-	 */
-	if (vif->type == NL80211_IFTYPE_ADHOC)
-		priv->bt_traffic_load = priv->last_bt_traffic_load;
-}
-
-static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
-			      struct ieee80211_vif *vif)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-
-	mutex_lock(&priv->mutex);
-
-	if (WARN_ON(ctx->vif != vif)) {
-		struct iwl_rxon_context *tmp;
-		IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
-		for_each_context(priv, tmp)
-			IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
-				tmp->ctxid, tmp, tmp->vif);
-	}
-	ctx->vif = NULL;
-
-	iwl_teardown_interface(priv, vif, false);
-
-	mutex_unlock(&priv->mutex);
-
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-
-}
-
-static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
-				struct ieee80211_vif *vif,
-				enum nl80211_iftype newtype, bool newp2p)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-	struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-	struct iwl_rxon_context *tmp;
-	enum nl80211_iftype newviftype = newtype;
-	u32 interface_modes;
-	int err;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-
-	newtype = ieee80211_iftype_p2p(newtype, newp2p);
-
-	mutex_lock(&priv->mutex);
-
-	if (!ctx->vif || !iwl_is_ready_rf(priv)) {
-		/*
-		 * Huh? But wait ... this can maybe happen when
-		 * we're in the middle of a firmware restart!
-		 */
-		err = -EBUSY;
-		goto out;
-	}
-
-	interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
-
-	if (!(interface_modes & BIT(newtype))) {
-		err = -EBUSY;
-		goto out;
-	}
-
-	/*
-	 * Refuse a change that should be done by moving from the PAN
-	 * context to the BSS context instead, if the BSS context is
-	 * available and can support the new interface type.
-	 */
-	if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
-	    (bss_ctx->interface_modes & BIT(newtype) ||
-	     bss_ctx->exclusive_interface_modes & BIT(newtype))) {
-		BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-		err = -EBUSY;
-		goto out;
-	}
-
-	if (ctx->exclusive_interface_modes & BIT(newtype)) {
-		for_each_context(priv, tmp) {
-			if (ctx == tmp)
-				continue;
-
-			if (!tmp->vif)
-				continue;
-
-			/*
-			 * The current mode switch would be exclusive, but
-			 * another context is active ... refuse the switch.
-			 */
-			err = -EBUSY;
-			goto out;
-		}
-	}
-
-	/* success */
-	iwl_teardown_interface(priv, vif, true);
-	vif->type = newviftype;
-	vif->p2p = newp2p;
-	err = iwl_setup_interface(priv, ctx);
-	WARN_ON(err);
-	/*
-	 * We've switched internally, but submitting to the
-	 * device may have failed for some reason. Mask this
-	 * error, because otherwise mac80211 will not switch
-	 * (and set the interface type back) and we'll be
-	 * out of sync with it.
-	 */
-	err = 0;
-
- out:
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-
-	return err;
-}
-
-int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
-		       struct ieee80211_vif *vif,
-		       struct cfg80211_scan_request *req)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	int ret;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-
-	if (req->n_channels == 0)
-		return -EINVAL;
-
-	mutex_lock(&priv->mutex);
-
-	/*
-	 * If an internal scan is in progress, just set
-	 * up the scan_request as per above.
-	 */
-	if (priv->scan_type != IWL_SCAN_NORMAL) {
-		IWL_DEBUG_SCAN(priv,
-			       "SCAN request during internal scan - defer\n");
-		priv->scan_request = req;
-		priv->scan_vif = vif;
-		ret = 0;
-	} else {
-		priv->scan_request = req;
-		priv->scan_vif = vif;
-		/*
-		 * mac80211 will only ask for one band at a time
-		 * so using channels[0] here is ok
-		 */
-		ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
-					req->channels[0]->band);
-		if (ret) {
-			priv->scan_request = NULL;
-			priv->scan_vif = NULL;
-		}
-	}
-
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-
-	mutex_unlock(&priv->mutex);
-
-	return ret;
-}
-
-static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
-{
-	struct iwl_addsta_cmd cmd = {
-		.mode = STA_CONTROL_MODIFY_MSK,
-		.station_flags_msk = STA_FLG_PWR_SAVE_MSK,
-		.sta.sta_id = sta_id,
-	};
-
-	iwl_send_add_sta(priv, &cmd, CMD_ASYNC);
-}
-
-void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
-			   struct ieee80211_vif *vif,
-			   enum sta_notify_cmd cmd,
-			   struct ieee80211_sta *sta)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-	int sta_id;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-
-	switch (cmd) {
-	case STA_NOTIFY_SLEEP:
-		WARN_ON(!sta_priv->client);
-		sta_priv->asleep = true;
-		if (atomic_read(&sta_priv->pending_frames) > 0)
-			ieee80211_sta_block_awake(hw, sta, true);
-		break;
-	case STA_NOTIFY_AWAKE:
-		WARN_ON(!sta_priv->client);
-		if (!sta_priv->asleep)
-			break;
-		sta_priv->asleep = false;
-		sta_id = iwl_sta_id(sta);
-		if (sta_id != IWL_INVALID_STATION)
-			iwl_sta_modify_ps_wake(priv, sta_id);
-		break;
-	default:
-		break;
-	}
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-struct ieee80211_ops iwlagn_hw_ops = {
-	.tx = iwlagn_mac_tx,
-	.start = iwlagn_mac_start,
-	.stop = iwlagn_mac_stop,
-#ifdef CONFIG_PM_SLEEP
-	.suspend = iwlagn_mac_suspend,
-	.resume = iwlagn_mac_resume,
-#endif
-	.add_interface = iwlagn_mac_add_interface,
-	.remove_interface = iwlagn_mac_remove_interface,
-	.change_interface = iwlagn_mac_change_interface,
-	.config = iwlagn_mac_config,
-	.configure_filter = iwlagn_configure_filter,
-	.set_key = iwlagn_mac_set_key,
-	.update_tkip_key = iwlagn_mac_update_tkip_key,
-	.set_rekey_data = iwlagn_mac_set_rekey_data,
-	.conf_tx = iwlagn_mac_conf_tx,
-	.bss_info_changed = iwlagn_bss_info_changed,
-	.ampdu_action = iwlagn_mac_ampdu_action,
-	.hw_scan = iwlagn_mac_hw_scan,
-	.sta_notify = iwlagn_mac_sta_notify,
-	.sta_state = iwlagn_mac_sta_state,
-	.channel_switch = iwlagn_mac_channel_switch,
-	.flush = iwlagn_mac_flush,
-	.tx_last_beacon = iwlagn_mac_tx_last_beacon,
-	.remain_on_channel = iwlagn_mac_remain_on_channel,
-	.cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
-	.rssi_callback = iwlagn_mac_rssi_callback,
-	CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
-	CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
-	.set_tim = iwlagn_mac_set_tim,
-};
-
-/* This function both allocates and initializes hw and priv. */
-struct ieee80211_hw *iwl_alloc_all(void)
-{
-	struct iwl_priv *priv;
-	struct iwl_op_mode *op_mode;
-	/* mac80211 allocates memory for this device instance, including
-	 *   space for this driver's private structure */
-	struct ieee80211_hw *hw;
-
-	hw = ieee80211_alloc_hw(sizeof(struct iwl_priv) +
-				sizeof(struct iwl_op_mode), &iwlagn_hw_ops);
-	if (!hw)
-		goto out;
-
-	op_mode = hw->priv;
-	priv = IWL_OP_MODE_GET_DVM(op_mode);
-	priv->hw = hw;
-
-out:
-	return hw;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
index 0066b89..c61f207 100644
--- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
+++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
@@ -61,6 +61,7 @@
  *
  *****************************************************************************/
 #include <linux/sched.h>
+#include <linux/export.h>
 
 #include "iwl-notif-wait.h"
 
@@ -71,6 +72,7 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)
 	INIT_LIST_HEAD(&notif_wait->notif_waits);
 	init_waitqueue_head(&notif_wait->notif_waitq);
 }
+EXPORT_SYMBOL_GPL(iwl_notification_wait_init);
 
 void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
 				  struct iwl_rx_packet *pkt)
@@ -115,20 +117,20 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
 	if (triggered)
 		wake_up_all(&notif_wait->notif_waitq);
 }
+EXPORT_SYMBOL_GPL(iwl_notification_wait_notify);
 
 void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
 {
-	unsigned long flags;
 	struct iwl_notification_wait *wait_entry;
 
-	spin_lock_irqsave(&notif_wait->notif_wait_lock, flags);
+	spin_lock(&notif_wait->notif_wait_lock);
 	list_for_each_entry(wait_entry, &notif_wait->notif_waits, list)
 		wait_entry->aborted = true;
-	spin_unlock_irqrestore(&notif_wait->notif_wait_lock, flags);
+	spin_unlock(&notif_wait->notif_wait_lock);
 
 	wake_up_all(&notif_wait->notif_waitq);
 }
-
+EXPORT_SYMBOL_GPL(iwl_abort_notification_waits);
 
 void
 iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
@@ -152,6 +154,7 @@ iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
 	list_add(&wait_entry->list, &notif_wait->notif_waits);
 	spin_unlock_bh(&notif_wait->notif_wait_lock);
 }
+EXPORT_SYMBOL_GPL(iwl_init_notification_wait);
 
 int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
 			  struct iwl_notification_wait *wait_entry,
@@ -175,6 +178,7 @@ int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
 		return -ETIMEDOUT;
 	return 0;
 }
+EXPORT_SYMBOL_GPL(iwl_wait_notification);
 
 void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
 			     struct iwl_notification_wait *wait_entry)
@@ -183,3 +187,4 @@ void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
 	list_del(&wait_entry->list);
 	spin_unlock_bh(&notif_wait->notif_wait_lock);
 }
+EXPORT_SYMBOL_GPL(iwl_remove_notification);
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
index 4ef742b..64886f9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
@@ -111,22 +111,25 @@ struct iwl_cfg;
  *	May sleep
  * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the
  *	HCMD the this Rx responds to.
- *	Must be atomic.
+ *	Must be atomic and called with BH disabled.
  * @queue_full: notifies that a HW queue is full.
- *	Must be atomic
+ *	Must be atomic and called with BH disabled.
  * @queue_not_full: notifies that a HW queue is not full any more.
- *	Must be atomic
+ *	Must be atomic and called with BH disabled.
  * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that
  *	the radio is killed. Must be atomic.
  * @free_skb: allows the transport layer to free skbs that haven't been
  *	reclaimed by the op_mode. This can happen when the driver is freed and
  *	there are Tx packets pending in the transport layer.
  *	Must be atomic
- * @nic_error: error notification. Must be atomic
- * @cmd_queue_full: Called when the command queue gets full. Must be atomic.
+ * @nic_error: error notification. Must be atomic and must be called with BH
+ *	disabled.
+ * @cmd_queue_full: Called when the command queue gets full. Must be atomic and
+ *	called with BH disabled.
  * @nic_config: configure NIC, called before firmware is started.
  *	May sleep
- * @wimax_active: invoked when WiMax becomes active.  Must be atomic.
+ * @wimax_active: invoked when WiMax becomes active.  Must be atomic and called
+ *	with BH disabled.
  */
 struct iwl_op_mode_ops {
 	struct iwl_op_mode *(*start)(struct iwl_trans *trans,
@@ -145,6 +148,9 @@ struct iwl_op_mode_ops {
 	void (*wimax_active)(struct iwl_op_mode *op_mode);
 };
 
+int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops);
+void iwl_opmode_deregister(const char *name);
+
 /**
  * struct iwl_op_mode - operational mode
  *
@@ -162,7 +168,6 @@ struct iwl_op_mode {
 static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode)
 {
 	might_sleep();
-
 	op_mode->ops->stop(op_mode);
 }
 
@@ -218,9 +223,4 @@ static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode)
 	op_mode->ops->wimax_active(op_mode);
 }
 
-/*****************************************************
-* Op mode layers implementations
-******************************************************/
-extern const struct iwl_op_mode_ops iwl_dvm_ops;
-
 #endif /* __iwl_op_mode_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c
deleted file mode 100644
index 0c8a1c2..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-pci.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2007 - 2012 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
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pci-aspm.h>
-
-#include "iwl-trans.h"
-#include "iwl-cfg.h"
-#include "iwl-drv.h"
-#include "iwl-trans.h"
-#include "iwl-trans-pcie-int.h"
-
-#define IWL_PCI_DEVICE(dev, subdev, cfg) \
-	.vendor = PCI_VENDOR_ID_INTEL,  .device = (dev), \
-	.subvendor = PCI_ANY_ID, .subdevice = (subdev), \
-	.driver_data = (kernel_ulong_t)&(cfg)
-
-/* Hardware specific file defines the PCI IDs table for that hardware module */
-static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
-	{IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1304, iwl5100_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bgn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bgn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1221, iwl5100_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1321, iwl5100_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1224, iwl5100_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1324, iwl5100_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1225, iwl5100_bgn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1325, iwl5100_bgn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1226, iwl5100_abg_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4237, 0x1211, iwl5100_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4237, 0x1311, iwl5100_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4237, 0x1214, iwl5100_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4237, 0x1314, iwl5100_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4237, 0x1215, iwl5100_bgn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4237, 0x1315, iwl5100_bgn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4237, 0x1316, iwl5100_abg_cfg)}, /* Half Mini Card */
-
-/* 5300 Series WiFi */
-	{IWL_PCI_DEVICE(0x4235, 0x1021, iwl5300_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4235, 0x1121, iwl5300_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4235, 0x1024, iwl5300_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4235, 0x1124, iwl5300_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4235, 0x1001, iwl5300_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4235, 0x1101, iwl5300_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4235, 0x1004, iwl5300_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4235, 0x1104, iwl5300_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4236, 0x1011, iwl5300_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4236, 0x1111, iwl5300_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x4236, 0x1014, iwl5300_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x4236, 0x1114, iwl5300_agn_cfg)}, /* Half Mini Card */
-
-/* 5350 Series WiFi/WiMax */
-	{IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, /* Mini Card */
-
-/* 5150 Series Wifi/WiMax */
-	{IWL_PCI_DEVICE(0x423C, 0x1201, iwl5150_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x423C, 0x1301, iwl5150_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x423C, 0x1206, iwl5150_abg_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
-
-	{IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
-	{IWL_PCI_DEVICE(0x423D, 0x1216, iwl5150_abg_cfg)}, /* Mini Card */
-	{IWL_PCI_DEVICE(0x423D, 0x1316, iwl5150_abg_cfg)}, /* Half Mini Card */
-
-/* 6x00 Series */
-	{IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)},
-	{IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)},
-	{IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x422C, 0x1306, iwl6000i_2abg_cfg)},
-	{IWL_PCI_DEVICE(0x422C, 0x1307, iwl6000i_2bg_cfg)},
-	{IWL_PCI_DEVICE(0x422C, 0x1321, iwl6000i_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x422C, 0x1326, iwl6000i_2abg_cfg)},
-	{IWL_PCI_DEVICE(0x4238, 0x1111, iwl6000_3agn_cfg)},
-	{IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
-
-/* 6x05 Series */
-	{IWL_PCI_DEVICE(0x0082, 0x1301, iwl6005_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x0082, 0x1306, iwl6005_2abg_cfg)},
-	{IWL_PCI_DEVICE(0x0082, 0x1307, iwl6005_2bg_cfg)},
-	{IWL_PCI_DEVICE(0x0082, 0x1321, iwl6005_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x0082, 0x1326, iwl6005_2abg_cfg)},
-	{IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
-	{IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)},
-	{IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)},
-	{IWL_PCI_DEVICE(0x0082, 0x4820, iwl6005_2agn_d_cfg)},
-	{IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_mow1_cfg)},/* low 5GHz active */
-	{IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_mow2_cfg)},/* high 5GHz active */
-
-/* 6x30 Series */
-	{IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x008A, 0x5307, iwl1030_bg_cfg)},
-	{IWL_PCI_DEVICE(0x008A, 0x5325, iwl1030_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x008A, 0x5327, iwl1030_bg_cfg)},
-	{IWL_PCI_DEVICE(0x008B, 0x5315, iwl1030_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x008B, 0x5317, iwl1030_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0090, 0x5211, iwl6030_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x0090, 0x5215, iwl6030_2bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0090, 0x5216, iwl6030_2abg_cfg)},
-	{IWL_PCI_DEVICE(0x0091, 0x5201, iwl6030_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x0091, 0x5205, iwl6030_2bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0091, 0x5206, iwl6030_2abg_cfg)},
-	{IWL_PCI_DEVICE(0x0091, 0x5207, iwl6030_2bg_cfg)},
-	{IWL_PCI_DEVICE(0x0091, 0x5221, iwl6030_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x0091, 0x5225, iwl6030_2bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0091, 0x5226, iwl6030_2abg_cfg)},
-
-/* 6x50 WiFi/WiMax Series */
-	{IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
-	{IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)},
-	{IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
-
-/* 6150 WiFi/WiMax Series */
-	{IWL_PCI_DEVICE(0x0885, 0x1305, iwl6150_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0885, 0x1307, iwl6150_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0885, 0x1325, iwl6150_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0885, 0x1327, iwl6150_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0886, 0x1315, iwl6150_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0886, 0x1317, iwl6150_bg_cfg)},
-
-/* 1000 Series WiFi */
-	{IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0083, 0x1305, iwl1000_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0083, 0x1225, iwl1000_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0083, 0x1325, iwl1000_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0084, 0x1215, iwl1000_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0084, 0x1315, iwl1000_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0083, 0x1206, iwl1000_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0083, 0x1306, iwl1000_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0083, 0x1226, iwl1000_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0083, 0x1326, iwl1000_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0084, 0x1216, iwl1000_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0084, 0x1316, iwl1000_bg_cfg)},
-
-/* 100 Series WiFi */
-	{IWL_PCI_DEVICE(0x08AE, 0x1005, iwl100_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)},
-	{IWL_PCI_DEVICE(0x08AF, 0x1015, iwl100_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x08AF, 0x1017, iwl100_bg_cfg)},
-	{IWL_PCI_DEVICE(0x08AE, 0x1025, iwl100_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x08AE, 0x1027, iwl100_bg_cfg)},
-
-/* 130 Series WiFi */
-	{IWL_PCI_DEVICE(0x0896, 0x5005, iwl130_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0896, 0x5007, iwl130_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0897, 0x5015, iwl130_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0897, 0x5017, iwl130_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0896, 0x5025, iwl130_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0896, 0x5027, iwl130_bg_cfg)},
-
-/* 2x00 Series */
-	{IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0890, 0x4822, iwl2000_2bgn_d_cfg)},
-
-/* 2x30 Series */
-	{IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)},
-
-/* 6x35 Series */
-	{IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
-	{IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)},
-
-/* 105 Series */
-	{IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0894, 0x0822, iwl105_bgn_d_cfg)},
-
-/* 135 Series */
-	{IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)},
-
-	{0}
-};
-MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
-
-/* PCI registers */
-#define PCI_CFG_RETRY_TIMEOUT	0x041
-
-#ifndef CONFIG_IWLWIFI_IDI
-
-static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
-	struct iwl_trans *iwl_trans;
-	struct iwl_trans_pcie *trans_pcie;
-
-	iwl_trans = iwl_trans_pcie_alloc(pdev, ent, cfg);
-	if (iwl_trans == NULL)
-		return -ENOMEM;
-
-	pci_set_drvdata(pdev, iwl_trans);
-
-	trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
-	trans_pcie->drv = iwl_drv_start(iwl_trans, cfg);
-	if (!trans_pcie->drv)
-		goto out_free_trans;
-
-	return 0;
-
-out_free_trans:
-	iwl_trans_pcie_free(iwl_trans);
-	pci_set_drvdata(pdev, NULL);
-	return -EFAULT;
-}
-
-static void __devexit iwl_pci_remove(struct pci_dev *pdev)
-{
-	struct iwl_trans *trans = pci_get_drvdata(pdev);
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	iwl_drv_stop(trans_pcie->drv);
-	iwl_trans_pcie_free(trans);
-
-	pci_set_drvdata(pdev, NULL);
-}
-
-#endif /* CONFIG_IWLWIFI_IDI */
-
-#ifdef CONFIG_PM_SLEEP
-
-static int iwl_pci_suspend(struct device *device)
-{
-	struct pci_dev *pdev = to_pci_dev(device);
-	struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
-
-	/* Before you put code here, think about WoWLAN. You cannot check here
-	 * whether WoWLAN is enabled or not, and your code will run even if
-	 * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx.
-	 */
-
-	return iwl_trans_suspend(iwl_trans);
-}
-
-static int iwl_pci_resume(struct device *device)
-{
-	struct pci_dev *pdev = to_pci_dev(device);
-	struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
-
-	/* Before you put code here, think about WoWLAN. You cannot check here
-	 * whether WoWLAN is enabled or not, and your code will run even if
-	 * WoWLAN is enabled - the NIC may be alive.
-	 */
-
-	/*
-	 * We disable the RETRY_TIMEOUT register (0x41) to keep
-	 * PCI Tx retries from interfering with C3 CPU state.
-	 */
-	pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
-
-	return iwl_trans_resume(iwl_trans);
-}
-
-static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
-
-#define IWL_PM_OPS	(&iwl_dev_pm_ops)
-
-#else
-
-#define IWL_PM_OPS	NULL
-
-#endif
-
-#ifdef CONFIG_IWLWIFI_IDI
-/*
- * Defined externally in iwl-idi.c
- */
-int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
-void __devexit iwl_pci_remove(struct pci_dev *pdev);
-
-#endif /* CONFIG_IWLWIFI_IDI */
-
-static struct pci_driver iwl_pci_driver = {
-	.name = DRV_NAME,
-	.id_table = iwl_hw_card_ids,
-	.probe = iwl_pci_probe,
-	.remove = __devexit_p(iwl_pci_remove),
-	.driver.pm = IWL_PM_OPS,
-};
-
-int __must_check iwl_pci_register_driver(void)
-{
-	int ret;
-	ret = pci_register_driver(&iwl_pci_driver);
-	if (ret)
-		pr_err("Unable to initialize PCI module\n");
-
-	return ret;
-}
-
-void iwl_pci_unregister_driver(void)
-{
-	pci_unregister_driver(&iwl_pci_driver);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
deleted file mode 100644
index 544ddf1..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ /dev/null
@@ -1,390 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *****************************************************************************/
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-agn.h"
-#include "iwl-io.h"
-#include "iwl-commands.h"
-#include "iwl-debug.h"
-#include "iwl-power.h"
-#include "iwl-trans.h"
-#include "iwl-modparams.h"
-
-/*
- * Setting power level allows the card to go to sleep when not busy.
- *
- * We calculate a sleep command based on the required latency, which
- * we get from mac80211. In order to handle thermal throttling, we can
- * also use pre-defined power levels.
- */
-
-/*
- * This defines the old power levels. They are still used by default
- * (level 1) and for thermal throttle (levels 3 through 5)
- */
-
-struct iwl_power_vec_entry {
-	struct iwl_powertable_cmd cmd;
-	u8 no_dtim;	/* number of skip dtim */
-};
-
-#define IWL_DTIM_RANGE_0_MAX	2
-#define IWL_DTIM_RANGE_1_MAX	10
-
-#define NOSLP cpu_to_le16(0), 0, 0
-#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
-#define ASLP (IWL_POWER_POWER_SAVE_ENA_MSK |	\
-		IWL_POWER_POWER_MANAGEMENT_ENA_MSK | \
-		IWL_POWER_ADVANCE_PM_ENA_MSK)
-#define ASLP_TOUT(T) cpu_to_le32(T)
-#define TU_TO_USEC 1024
-#define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC)
-#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \
-				     cpu_to_le32(X1), \
-				     cpu_to_le32(X2), \
-				     cpu_to_le32(X3), \
-				     cpu_to_le32(X4)}
-/* default power management (not Tx power) table values */
-/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */
-/* DTIM 0 - 2 */
-static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
-	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 1, 2, 2, 0xFF)}, 0},
-	{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
-	{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0},
-	{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1},
-	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 2, 4, 6, 0xFF)}, 2}
-};
-
-
-/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
-/* DTIM 3 - 10 */
-static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
-	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
-	{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
-	{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0},
-	{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1},
-	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 6, 10, 10)}, 2}
-};
-
-/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
-/* DTIM 11 - */
-static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
-	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
-	{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
-	{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
-	{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
-	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
-};
-
-/* advance power management */
-/* DTIM 0 - 2 */
-static const struct iwl_power_vec_entry apm_range_0[IWL_POWER_NUM] = {
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
-};
-
-
-/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
-/* DTIM 3 - 10 */
-static const struct iwl_power_vec_entry apm_range_1[IWL_POWER_NUM] = {
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 6, 8, 0xFF), 0}, 2}
-};
-
-/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
-/* DTIM 11 - */
-static const struct iwl_power_vec_entry apm_range_2[IWL_POWER_NUM] = {
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-	{{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-		SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
-};
-
-static void iwl_static_sleep_cmd(struct iwl_priv *priv,
-				 struct iwl_powertable_cmd *cmd,
-				 enum iwl_power_level lvl, int period)
-{
-	const struct iwl_power_vec_entry *table;
-	int max_sleep[IWL_POWER_VEC_SIZE] = { 0 };
-	int i;
-	u8 skip;
-	u32 slp_itrvl;
-
-	if (priv->cfg->adv_pm) {
-		table = apm_range_2;
-		if (period <= IWL_DTIM_RANGE_1_MAX)
-			table = apm_range_1;
-		if (period <= IWL_DTIM_RANGE_0_MAX)
-			table = apm_range_0;
-	} else {
-		table = range_2;
-		if (period <= IWL_DTIM_RANGE_1_MAX)
-			table = range_1;
-		if (period <= IWL_DTIM_RANGE_0_MAX)
-			table = range_0;
-	}
-
-	if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM))
-		memset(cmd, 0, sizeof(*cmd));
-	else
-		*cmd = table[lvl].cmd;
-
-	if (period == 0) {
-		skip = 0;
-		period = 1;
-		for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
-			max_sleep[i] =  1;
-
-	} else {
-		skip = table[lvl].no_dtim;
-		for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
-			max_sleep[i] = le32_to_cpu(cmd->sleep_interval[i]);
-		max_sleep[IWL_POWER_VEC_SIZE - 1] = skip + 1;
-	}
-
-	slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
-	/* figure out the listen interval based on dtim period and skip */
-	if (slp_itrvl == 0xFF)
-		cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
-			cpu_to_le32(period * (skip + 1));
-
-	slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
-	if (slp_itrvl > period)
-		cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
-			cpu_to_le32((slp_itrvl / period) * period);
-
-	if (skip)
-		cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
-	else
-		cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
-
-	if (priv->cfg->base_params->shadow_reg_enable)
-		cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
-	else
-		cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
-
-	if (iwl_advanced_bt_coexist(priv)) {
-		if (!priv->cfg->bt_params->bt_sco_disable)
-			cmd->flags |= IWL_POWER_BT_SCO_ENA;
-		else
-			cmd->flags &= ~IWL_POWER_BT_SCO_ENA;
-	}
-
-
-	slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
-	if (slp_itrvl > IWL_CONN_MAX_LISTEN_INTERVAL)
-		cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
-			cpu_to_le32(IWL_CONN_MAX_LISTEN_INTERVAL);
-
-	/* enforce max sleep interval */
-	for (i = IWL_POWER_VEC_SIZE - 1; i >= 0 ; i--) {
-		if (le32_to_cpu(cmd->sleep_interval[i]) >
-		    (max_sleep[i] * period))
-			cmd->sleep_interval[i] =
-				cpu_to_le32(max_sleep[i] * period);
-		if (i != (IWL_POWER_VEC_SIZE - 1)) {
-			if (le32_to_cpu(cmd->sleep_interval[i]) >
-			    le32_to_cpu(cmd->sleep_interval[i+1]))
-				cmd->sleep_interval[i] =
-					cmd->sleep_interval[i+1];
-		}
-	}
-
-	if (priv->power_data.bus_pm)
-		cmd->flags |= IWL_POWER_PCI_PM_MSK;
-	else
-		cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
-
-	IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n",
-			skip, period);
-	/* The power level here is 0-4 (used as array index), but user expects
-	to see 1-5 (according to spec). */
-	IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
-}
-
-static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv,
-				    struct iwl_powertable_cmd *cmd)
-{
-	memset(cmd, 0, sizeof(*cmd));
-
-	if (priv->power_data.bus_pm)
-		cmd->flags |= IWL_POWER_PCI_PM_MSK;
-
-	IWL_DEBUG_POWER(priv, "Sleep command for CAM\n");
-}
-
-static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
-{
-	IWL_DEBUG_POWER(priv, "Sending power/sleep command\n");
-	IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags);
-	IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
-	IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
-	IWL_DEBUG_POWER(priv, "Sleep interval vector = { %d , %d , %d , %d , %d }\n",
-			le32_to_cpu(cmd->sleep_interval[0]),
-			le32_to_cpu(cmd->sleep_interval[1]),
-			le32_to_cpu(cmd->sleep_interval[2]),
-			le32_to_cpu(cmd->sleep_interval[3]),
-			le32_to_cpu(cmd->sleep_interval[4]));
-
-	return iwl_dvm_send_cmd_pdu(priv, POWER_TABLE_CMD, CMD_SYNC,
-				sizeof(struct iwl_powertable_cmd), cmd);
-}
-
-static void iwl_power_build_cmd(struct iwl_priv *priv,
-				struct iwl_powertable_cmd *cmd)
-{
-	bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
-	int dtimper;
-
-	dtimper = priv->hw->conf.ps_dtim_period ?: 1;
-
-	if (priv->wowlan)
-		iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper);
-	else if (!priv->cfg->base_params->no_idle_support &&
-		 priv->hw->conf.flags & IEEE80211_CONF_IDLE)
-		iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
-	else if (iwl_tt_is_low_power_state(priv)) {
-		/* in thermal throttling low power state */
-		iwl_static_sleep_cmd(priv, cmd,
-		    iwl_tt_current_power_mode(priv), dtimper);
-	} else if (!enabled)
-		iwl_power_sleep_cam_cmd(priv, cmd);
-	else if (priv->power_data.debug_sleep_level_override >= 0)
-		iwl_static_sleep_cmd(priv, cmd,
-				     priv->power_data.debug_sleep_level_override,
-				     dtimper);
-	else {
-		/* Note that the user parameter is 1-5 (according to spec),
-		but we pass 0-4 because it acts as an array index. */
-		if (iwlwifi_mod_params.power_level > IWL_POWER_INDEX_1 &&
-		    iwlwifi_mod_params.power_level <= IWL_POWER_NUM)
-			iwl_static_sleep_cmd(priv, cmd,
-				iwlwifi_mod_params.power_level - 1, dtimper);
-		else
-			iwl_static_sleep_cmd(priv, cmd,
-				IWL_POWER_INDEX_1, dtimper);
-	}
-}
-
-int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
-		       bool force)
-{
-	int ret;
-	bool update_chains;
-
-	lockdep_assert_held(&priv->mutex);
-
-	/* Don't update the RX chain when chain noise calibration is running */
-	update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
-			priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
-
-	if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force)
-		return 0;
-
-	if (!iwl_is_ready_rf(priv))
-		return -EIO;
-
-	/* scan complete use sleep_power_next, need to be updated */
-	memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd));
-	if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
-		IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
-		return 0;
-	}
-
-	if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
-		iwl_dvm_set_pmi(priv, true);
-
-	ret = iwl_set_power(priv, cmd);
-	if (!ret) {
-		if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
-			iwl_dvm_set_pmi(priv, false);
-
-		if (update_chains)
-			iwl_update_chain_flags(priv);
-		else
-			IWL_DEBUG_POWER(priv,
-					"Cannot update the power, chain noise "
-					"calibration running: %d\n",
-					priv->chain_noise_data.state);
-
-		memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd));
-	} else
-		IWL_ERR(priv, "set power fail, ret = %d", ret);
-
-	return ret;
-}
-
-int iwl_power_update_mode(struct iwl_priv *priv, bool force)
-{
-	struct iwl_powertable_cmd cmd;
-
-	iwl_power_build_cmd(priv, &cmd);
-	return iwl_power_set_mode(priv, &cmd, force);
-}
-
-/* initialize to default */
-void iwl_power_initialize(struct iwl_priv *priv)
-{
-	priv->power_data.bus_pm = priv->trans->pm_support;
-
-	priv->power_data.debug_sleep_level_override = -1;
-
-	memset(&priv->power_data.sleep_cmd, 0,
-		sizeof(priv->power_data.sleep_cmd));
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
deleted file mode 100644
index 21afc92..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *****************************************************************************/
-#ifndef __iwl_power_setting_h__
-#define __iwl_power_setting_h__
-
-#include "iwl-commands.h"
-
-struct iwl_power_mgr {
-	struct iwl_powertable_cmd sleep_cmd;
-	struct iwl_powertable_cmd sleep_cmd_next;
-	int debug_sleep_level_override;
-	bool bus_pm;
-};
-
-int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
-		       bool force);
-int iwl_power_update_mode(struct iwl_priv *priv, bool force);
-void iwl_power_initialize(struct iwl_priv *priv);
-
-extern bool no_sleep_autoadjust;
-
-#endif  /* __iwl_power_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index dfd5466..9253ef1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -187,7 +187,7 @@
 #define SCD_QUEUE_STTS_REG_POS_ACTIVE	(3)
 #define SCD_QUEUE_STTS_REG_POS_WSL	(4)
 #define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19)
-#define SCD_QUEUE_STTS_REG_MSK		(0x00FF0000)
+#define SCD_QUEUE_STTS_REG_MSK		(0x017F0000)
 
 #define SCD_QUEUE_CTX_REG1_CREDIT_POS		(8)
 #define SCD_QUEUE_CTX_REG1_CREDIT_MSK		(0x00FFFF00)
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
deleted file mode 100644
index 031d8e2..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ /dev/null
@@ -1,1160 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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/slab.h>
-#include <linux/types.h>
-#include <linux/etherdevice.h>
-#include <net/mac80211.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-
-/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
- * sending probe req.  This should be set long enough to hear probe responses
- * from more than one AP.  */
-#define IWL_ACTIVE_DWELL_TIME_24    (30)       /* all times in msec */
-#define IWL_ACTIVE_DWELL_TIME_52    (20)
-
-#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
-#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
-
-/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
- * Must be set longer than active dwell time.
- * For the most reliable scan, set > AP beacon interval (typically 100msec). */
-#define IWL_PASSIVE_DWELL_TIME_24   (20)       /* all times in msec */
-#define IWL_PASSIVE_DWELL_TIME_52   (10)
-#define IWL_PASSIVE_DWELL_BASE      (100)
-#define IWL_CHANNEL_TUNE_TIME       5
-#define MAX_SCAN_CHANNEL	    50
-
-static int iwl_send_scan_abort(struct iwl_priv *priv)
-{
-	int ret;
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_SCAN_ABORT_CMD,
-		.flags = CMD_SYNC | CMD_WANT_SKB,
-	};
-	__le32 *status;
-
-	/* Exit instantly with error when device is not ready
-	 * to receive scan abort command or it does not perform
-	 * hardware scan currently */
-	if (!test_bit(STATUS_READY, &priv->status) ||
-	    !test_bit(STATUS_GEO_CONFIGURED, &priv->status) ||
-	    !test_bit(STATUS_SCAN_HW, &priv->status) ||
-	    test_bit(STATUS_FW_ERROR, &priv->status))
-		return -EIO;
-
-	ret = iwl_dvm_send_cmd(priv, &cmd);
-	if (ret)
-		return ret;
-
-	status = (void *)cmd.resp_pkt->data;
-	if (*status != CAN_ABORT_STATUS) {
-		/* The scan abort will return 1 for success or
-		 * 2 for "failure".  A failure condition can be
-		 * due to simply not being in an active scan which
-		 * can occur if we send the scan abort before we
-		 * the microcode has notified us that a scan is
-		 * completed. */
-		IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n",
-			       le32_to_cpu(*status));
-		ret = -EIO;
-	}
-
-	iwl_free_resp(&cmd);
-	return ret;
-}
-
-static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
-{
-	/* check if scan was requested from mac80211 */
-	if (priv->scan_request) {
-		IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
-		ieee80211_scan_completed(priv->hw, aborted);
-	}
-
-	if (priv->scan_type == IWL_SCAN_ROC) {
-		ieee80211_remain_on_channel_expired(priv->hw);
-		priv->hw_roc_channel = NULL;
-		schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
-	}
-
-	priv->scan_type = IWL_SCAN_NORMAL;
-	priv->scan_vif = NULL;
-	priv->scan_request = NULL;
-}
-
-static void iwl_process_scan_complete(struct iwl_priv *priv)
-{
-	bool aborted;
-
-	lockdep_assert_held(&priv->mutex);
-
-	if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->status))
-		return;
-
-	IWL_DEBUG_SCAN(priv, "Completed scan.\n");
-
-	cancel_delayed_work(&priv->scan_check);
-
-	aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
-	if (aborted)
-		IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
-
-	if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) {
-		IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
-		goto out_settings;
-	}
-
-	if (priv->scan_type == IWL_SCAN_ROC) {
-		ieee80211_remain_on_channel_expired(priv->hw);
-		priv->hw_roc_channel = NULL;
-		schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
-	}
-
-	if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
-		int err;
-
-		/* Check if mac80211 requested scan during our internal scan */
-		if (priv->scan_request == NULL)
-			goto out_complete;
-
-		/* If so request a new scan */
-		err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
-					priv->scan_request->channels[0]->band);
-		if (err) {
-			IWL_DEBUG_SCAN(priv,
-				"failed to initiate pending scan: %d\n", err);
-			aborted = true;
-			goto out_complete;
-		}
-
-		return;
-	}
-
-out_complete:
-	iwl_complete_scan(priv, aborted);
-
-out_settings:
-	/* Can we still talk to firmware ? */
-	if (!iwl_is_ready_rf(priv))
-		return;
-
-	iwlagn_post_scan(priv);
-}
-
-void iwl_force_scan_end(struct iwl_priv *priv)
-{
-	lockdep_assert_held(&priv->mutex);
-
-	if (!test_bit(STATUS_SCANNING, &priv->status)) {
-		IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n");
-		return;
-	}
-
-	IWL_DEBUG_SCAN(priv, "Forcing scan end\n");
-	clear_bit(STATUS_SCANNING, &priv->status);
-	clear_bit(STATUS_SCAN_HW, &priv->status);
-	clear_bit(STATUS_SCAN_ABORTING, &priv->status);
-	clear_bit(STATUS_SCAN_COMPLETE, &priv->status);
-	iwl_complete_scan(priv, true);
-}
-
-static void iwl_do_scan_abort(struct iwl_priv *priv)
-{
-	int ret;
-
-	lockdep_assert_held(&priv->mutex);
-
-	if (!test_bit(STATUS_SCANNING, &priv->status)) {
-		IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n");
-		return;
-	}
-
-	if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-		IWL_DEBUG_SCAN(priv, "Scan abort in progress\n");
-		return;
-	}
-
-	ret = iwl_send_scan_abort(priv);
-	if (ret) {
-		IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret);
-		iwl_force_scan_end(priv);
-	} else
-		IWL_DEBUG_SCAN(priv, "Successfully send scan abort\n");
-}
-
-/**
- * iwl_scan_cancel - Cancel any currently executing HW scan
- */
-int iwl_scan_cancel(struct iwl_priv *priv)
-{
-	IWL_DEBUG_SCAN(priv, "Queuing abort scan\n");
-	queue_work(priv->workqueue, &priv->abort_scan);
-	return 0;
-}
-
-/**
- * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
- * @ms: amount of time to wait (in milliseconds) for scan to abort
- *
- */
-void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
-{
-	unsigned long timeout = jiffies + msecs_to_jiffies(ms);
-
-	lockdep_assert_held(&priv->mutex);
-
-	IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n");
-
-	iwl_do_scan_abort(priv);
-
-	while (time_before_eq(jiffies, timeout)) {
-		if (!test_bit(STATUS_SCAN_HW, &priv->status))
-			goto finished;
-		msleep(20);
-	}
-
-	return;
-
- finished:
-	/*
-	 * Now STATUS_SCAN_HW is clear. This means that the
-	 * device finished, but the background work is going
-	 * to execute at best as soon as we release the mutex.
-	 * Since we need to be able to issue a new scan right
-	 * after this function returns, run the complete here.
-	 * The STATUS_SCAN_COMPLETE bit will then be cleared
-	 * and prevent the background work from "completing"
-	 * a possible new scan.
-	 */
-	iwl_process_scan_complete(priv);
-}
-
-/* Service response to REPLY_SCAN_CMD (0x80) */
-static int iwl_rx_reply_scan(struct iwl_priv *priv,
-			      struct iwl_rx_cmd_buffer *rxb,
-			      struct iwl_device_cmd *cmd)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_scanreq_notification *notif = (void *)pkt->data;
-
-	IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status);
-#endif
-	return 0;
-}
-
-/* Service SCAN_START_NOTIFICATION (0x82) */
-static int iwl_rx_scan_start_notif(struct iwl_priv *priv,
-				    struct iwl_rx_cmd_buffer *rxb,
-				    struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_scanstart_notification *notif = (void *)pkt->data;
-
-	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
-	IWL_DEBUG_SCAN(priv, "Scan start: "
-		       "%d [802.11%s] "
-		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
-		       notif->channel,
-		       notif->band ? "bg" : "a",
-		       le32_to_cpu(notif->tsf_high),
-		       le32_to_cpu(notif->tsf_low),
-		       notif->status, notif->beacon_timer);
-
-	if (priv->scan_type == IWL_SCAN_ROC &&
-	    !priv->hw_roc_start_notified) {
-		ieee80211_ready_on_channel(priv->hw);
-		priv->hw_roc_start_notified = true;
-	}
-
-	return 0;
-}
-
-/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
-static int iwl_rx_scan_results_notif(struct iwl_priv *priv,
-				      struct iwl_rx_cmd_buffer *rxb,
-				      struct iwl_device_cmd *cmd)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_scanresults_notification *notif = (void *)pkt->data;
-
-	IWL_DEBUG_SCAN(priv, "Scan ch.res: "
-		       "%d [802.11%s] "
-		       "probe status: %u:%u "
-		       "(TSF: 0x%08X:%08X) - %d "
-		       "elapsed=%lu usec\n",
-		       notif->channel,
-		       notif->band ? "bg" : "a",
-		       notif->probe_status, notif->num_probe_not_sent,
-		       le32_to_cpu(notif->tsf_high),
-		       le32_to_cpu(notif->tsf_low),
-		       le32_to_cpu(notif->statistics[0]),
-		       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
-#endif
-	return 0;
-}
-
-/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
-static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,
-				       struct iwl_rx_cmd_buffer *rxb,
-				       struct iwl_device_cmd *cmd)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_scancomplete_notification *scan_notif = (void *)pkt->data;
-
-	IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
-		       scan_notif->scanned_channels,
-		       scan_notif->tsf_low,
-		       scan_notif->tsf_high, scan_notif->status);
-
-	IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
-		       (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
-		       jiffies_to_msecs(jiffies - priv->scan_start));
-
-	/*
-	 * When aborting, we run the scan completed background work inline
-	 * and the background work must then do nothing. The SCAN_COMPLETE
-	 * bit helps implement that logic and thus needs to be set before
-	 * queueing the work. Also, since the scan abort waits for SCAN_HW
-	 * to clear, we need to set SCAN_COMPLETE before clearing SCAN_HW
-	 * to avoid a race there.
-	 */
-	set_bit(STATUS_SCAN_COMPLETE, &priv->status);
-	clear_bit(STATUS_SCAN_HW, &priv->status);
-	queue_work(priv->workqueue, &priv->scan_completed);
-
-	if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
-	    iwl_advanced_bt_coexist(priv) &&
-	    priv->bt_status != scan_notif->bt_status) {
-		if (scan_notif->bt_status) {
-			/* BT on */
-			if (!priv->bt_ch_announce)
-				priv->bt_traffic_load =
-					IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
-			/*
-			 * otherwise, no traffic load information provided
-			 * no changes made
-			 */
-		} else {
-			/* BT off */
-			priv->bt_traffic_load =
-				IWL_BT_COEX_TRAFFIC_LOAD_NONE;
-		}
-		priv->bt_status = scan_notif->bt_status;
-		queue_work(priv->workqueue,
-			   &priv->bt_traffic_change_work);
-	}
-	return 0;
-}
-
-void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
-{
-	/* scan handlers */
-	priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
-	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
-	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
-					iwl_rx_scan_results_notif;
-	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
-					iwl_rx_scan_complete_notif;
-}
-
-static u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
-				     enum ieee80211_band band, u8 n_probes)
-{
-	if (band == IEEE80211_BAND_5GHZ)
-		return IWL_ACTIVE_DWELL_TIME_52 +
-			IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
-	else
-		return IWL_ACTIVE_DWELL_TIME_24 +
-			IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
-}
-
-static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time)
-{
-	struct iwl_rxon_context *ctx;
-
-	/*
-	 * If we're associated, we clamp the dwell time 98%
-	 * of the smallest beacon interval (minus 2 * channel
-	 * tune time)
-	 */
-	for_each_context(priv, ctx) {
-		u16 value;
-
-		switch (ctx->staging.dev_type) {
-		case RXON_DEV_TYPE_P2P:
-			/* no timing constraints */
-			continue;
-		case RXON_DEV_TYPE_ESS:
-		default:
-			/* timing constraints if associated */
-			if (!iwl_is_associated_ctx(ctx))
-				continue;
-			break;
-		case RXON_DEV_TYPE_CP:
-		case RXON_DEV_TYPE_2STA:
-			/*
-			 * These seem to always have timers for TBTT
-			 * active in uCode even when not associated yet.
-			 */
-			break;
-		}
-
-		value = ctx->beacon_int;
-		if (!value)
-			value = IWL_PASSIVE_DWELL_BASE;
-		value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
-		dwell_time = min(value, dwell_time);
-	}
-
-	return dwell_time;
-}
-
-static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
-				      enum ieee80211_band band)
-{
-	u16 passive = (band == IEEE80211_BAND_2GHZ) ?
-	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
-	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
-
-	return iwl_limit_dwell(priv, passive);
-}
-
-/* Return valid, unused, channel for a passive scan to reset the RF */
-static u8 iwl_get_single_channel_number(struct iwl_priv *priv,
-				 enum ieee80211_band band)
-{
-	const struct iwl_channel_info *ch_info;
-	int i;
-	u8 channel = 0;
-	u8 min, max;
-	struct iwl_rxon_context *ctx;
-
-	if (band == IEEE80211_BAND_5GHZ) {
-		min = 14;
-		max = priv->channel_count;
-	} else {
-		min = 0;
-		max = 14;
-	}
-
-	for (i = min; i < max; i++) {
-		bool busy = false;
-
-		for_each_context(priv, ctx) {
-			busy = priv->channel_info[i].channel ==
-				le16_to_cpu(ctx->staging.channel);
-			if (busy)
-				break;
-		}
-
-		if (busy)
-			continue;
-
-		channel = priv->channel_info[i].channel;
-		ch_info = iwl_get_channel_info(priv, band, channel);
-		if (is_channel_valid(ch_info))
-			break;
-	}
-
-	return channel;
-}
-
-static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
-					   struct ieee80211_vif *vif,
-					   enum ieee80211_band band,
-					   struct iwl_scan_channel *scan_ch)
-{
-	const struct ieee80211_supported_band *sband;
-	u16 passive_dwell = 0;
-	u16 active_dwell = 0;
-	int added = 0;
-	u16 channel = 0;
-
-	sband = iwl_get_hw_mode(priv, band);
-	if (!sband) {
-		IWL_ERR(priv, "invalid band\n");
-		return added;
-	}
-
-	active_dwell = iwl_get_active_dwell_time(priv, band, 0);
-	passive_dwell = iwl_get_passive_dwell_time(priv, band);
-
-	if (passive_dwell <= active_dwell)
-		passive_dwell = active_dwell + 1;
-
-	channel = iwl_get_single_channel_number(priv, band);
-	if (channel) {
-		scan_ch->channel = cpu_to_le16(channel);
-		scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
-		scan_ch->active_dwell = cpu_to_le16(active_dwell);
-		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
-		/* Set txpower levels to defaults */
-		scan_ch->dsp_atten = 110;
-		if (band == IEEE80211_BAND_5GHZ)
-			scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-		else
-			scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-		added++;
-	} else
-		IWL_ERR(priv, "no valid channel found\n");
-	return added;
-}
-
-static int iwl_get_channels_for_scan(struct iwl_priv *priv,
-				     struct ieee80211_vif *vif,
-				     enum ieee80211_band band,
-				     u8 is_active, u8 n_probes,
-				     struct iwl_scan_channel *scan_ch)
-{
-	struct ieee80211_channel *chan;
-	const struct ieee80211_supported_band *sband;
-	const struct iwl_channel_info *ch_info;
-	u16 passive_dwell = 0;
-	u16 active_dwell = 0;
-	int added, i;
-	u16 channel;
-
-	sband = iwl_get_hw_mode(priv, band);
-	if (!sband)
-		return 0;
-
-	active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
-	passive_dwell = iwl_get_passive_dwell_time(priv, band);
-
-	if (passive_dwell <= active_dwell)
-		passive_dwell = active_dwell + 1;
-
-	for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
-		chan = priv->scan_request->channels[i];
-
-		if (chan->band != band)
-			continue;
-
-		channel = chan->hw_value;
-		scan_ch->channel = cpu_to_le16(channel);
-
-		ch_info = iwl_get_channel_info(priv, band, channel);
-		if (!is_channel_valid(ch_info)) {
-			IWL_DEBUG_SCAN(priv,
-				       "Channel %d is INVALID for this band.\n",
-				       channel);
-			continue;
-		}
-
-		if (!is_active || is_channel_passive(ch_info) ||
-		    (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
-			scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
-		else
-			scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
-
-		if (n_probes)
-			scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
-
-		scan_ch->active_dwell = cpu_to_le16(active_dwell);
-		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
-
-		/* Set txpower levels to defaults */
-		scan_ch->dsp_atten = 110;
-
-		/* NOTE: if we were doing 6Mb OFDM for scans we'd use
-		 * power level:
-		 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
-		 */
-		if (band == IEEE80211_BAND_5GHZ)
-			scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-		else
-			scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-
-		IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n",
-			       channel, le32_to_cpu(scan_ch->type),
-			       (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
-				"ACTIVE" : "PASSIVE",
-			       (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
-			       active_dwell : passive_dwell);
-
-		scan_ch++;
-		added++;
-	}
-
-	IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
-	return added;
-}
-
-/**
- * iwl_fill_probe_req - fill in all required fields and IE for probe request
- */
-
-static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
-			      const u8 *ies, int ie_len, const u8 *ssid,
-			      u8 ssid_len, int left)
-{
-	int len = 0;
-	u8 *pos = NULL;
-
-	/* Make sure there is enough space for the probe request,
-	 * two mandatory IEs and the data */
-	left -= 24;
-	if (left < 0)
-		return 0;
-
-	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
-	memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
-	memcpy(frame->sa, ta, ETH_ALEN);
-	memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
-	frame->seq_ctrl = 0;
-
-	len += 24;
-
-	/* ...next IE... */
-	pos = &frame->u.probe_req.variable[0];
-
-	/* fill in our SSID IE */
-	left -= ssid_len + 2;
-	if (left < 0)
-		return 0;
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = ssid_len;
-	if (ssid && ssid_len) {
-		memcpy(pos, ssid, ssid_len);
-		pos += ssid_len;
-	}
-
-	len += ssid_len + 2;
-
-	if (WARN_ON(left < ie_len))
-		return len;
-
-	if (ies && ie_len) {
-		memcpy(pos, ies, ie_len);
-		len += ie_len;
-	}
-
-	return (u16)len;
-}
-
-static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
-{
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_SCAN_CMD,
-		.len = { sizeof(struct iwl_scan_cmd), },
-		.flags = CMD_SYNC,
-	};
-	struct iwl_scan_cmd *scan;
-	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-	u32 rate_flags = 0;
-	u16 cmd_len = 0;
-	u16 rx_chain = 0;
-	enum ieee80211_band band;
-	u8 n_probes = 0;
-	u8 rx_ant = priv->hw_params.valid_rx_ant;
-	u8 rate;
-	bool is_active = false;
-	int  chan_mod;
-	u8 active_chains;
-	u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
-	int ret;
-	int scan_cmd_size = sizeof(struct iwl_scan_cmd) +
-			    MAX_SCAN_CHANNEL * sizeof(struct iwl_scan_channel) +
-			    priv->fw->ucode_capa.max_probe_length;
-	const u8 *ssid = NULL;
-	u8 ssid_len = 0;
-
-	if (WARN_ON_ONCE(priv->scan_request &&
-			 priv->scan_request->n_channels > MAX_SCAN_CHANNEL))
-		return -EINVAL;
-
-	lockdep_assert_held(&priv->mutex);
-
-	if (vif)
-		ctx = iwl_rxon_ctx_from_vif(vif);
-
-	if (!priv->scan_cmd) {
-		priv->scan_cmd = kmalloc(scan_cmd_size, GFP_KERNEL);
-		if (!priv->scan_cmd) {
-			IWL_DEBUG_SCAN(priv,
-				       "fail to allocate memory for scan\n");
-			return -ENOMEM;
-		}
-	}
-	scan = priv->scan_cmd;
-	memset(scan, 0, scan_cmd_size);
-
-	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
-	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
-
-	if (priv->scan_type != IWL_SCAN_ROC &&
-	    iwl_is_any_associated(priv)) {
-		u16 interval = 0;
-		u32 extra;
-		u32 suspend_time = 100;
-		u32 scan_suspend_time = 100;
-
-		IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
-		switch (priv->scan_type) {
-		case IWL_SCAN_ROC:
-			WARN_ON(1);
-			break;
-		case IWL_SCAN_RADIO_RESET:
-			interval = 0;
-			break;
-		case IWL_SCAN_NORMAL:
-			interval = vif->bss_conf.beacon_int;
-			break;
-		}
-
-		scan->suspend_time = 0;
-		scan->max_out_time = cpu_to_le32(200 * 1024);
-		if (!interval)
-			interval = suspend_time;
-
-		extra = (suspend_time / interval) << 22;
-		scan_suspend_time = (extra |
-		    ((suspend_time % interval) * 1024));
-		scan->suspend_time = cpu_to_le32(scan_suspend_time);
-		IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
-			       scan_suspend_time, interval);
-	} else if (priv->scan_type == IWL_SCAN_ROC) {
-		scan->suspend_time = 0;
-		scan->max_out_time = 0;
-		scan->quiet_time = 0;
-		scan->quiet_plcp_th = 0;
-	}
-
-	switch (priv->scan_type) {
-	case IWL_SCAN_RADIO_RESET:
-		IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
-		break;
-	case IWL_SCAN_NORMAL:
-		if (priv->scan_request->n_ssids) {
-			int i, p = 0;
-			IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
-			/*
-			 * The highest priority SSID is inserted to the
-			 * probe request template.
-			 */
-			ssid_len = priv->scan_request->ssids[0].ssid_len;
-			ssid = priv->scan_request->ssids[0].ssid;
-
-			/*
-			 * Invert the order of ssids, the firmware will invert
-			 * it back.
-			 */
-			for (i = priv->scan_request->n_ssids - 1; i >= 1; i--) {
-				scan->direct_scan[p].id = WLAN_EID_SSID;
-				scan->direct_scan[p].len =
-					priv->scan_request->ssids[i].ssid_len;
-				memcpy(scan->direct_scan[p].ssid,
-				       priv->scan_request->ssids[i].ssid,
-				       priv->scan_request->ssids[i].ssid_len);
-				n_probes++;
-				p++;
-			}
-			is_active = true;
-		} else
-			IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
-		break;
-	case IWL_SCAN_ROC:
-		IWL_DEBUG_SCAN(priv, "Start ROC scan.\n");
-		break;
-	}
-
-	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-	scan->tx_cmd.sta_id = ctx->bcast_sta_id;
-	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-
-	switch (priv->scan_band) {
-	case IEEE80211_BAND_2GHZ:
-		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
-		chan_mod = le32_to_cpu(
-			priv->contexts[IWL_RXON_CTX_BSS].active.flags &
-						RXON_FLG_CHANNEL_MODE_MSK)
-				       >> RXON_FLG_CHANNEL_MODE_POS;
-		if ((priv->scan_request && priv->scan_request->no_cck) ||
-		    chan_mod == CHANNEL_MODE_PURE_40) {
-			rate = IWL_RATE_6M_PLCP;
-		} else {
-			rate = IWL_RATE_1M_PLCP;
-			rate_flags = RATE_MCS_CCK_MSK;
-		}
-		/*
-		 * Internal scans are passive, so we can indiscriminately set
-		 * the BT ignore flag on 2.4 GHz since it applies to TX only.
-		 */
-		if (priv->cfg->bt_params &&
-		    priv->cfg->bt_params->advanced_bt_coexist)
-			scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
-		break;
-	case IEEE80211_BAND_5GHZ:
-		rate = IWL_RATE_6M_PLCP;
-		break;
-	default:
-		IWL_WARN(priv, "Invalid scan band\n");
-		return -EIO;
-	}
-
-	/*
-	 * If active scanning is requested but a certain channel is
-	 * marked passive, we can do active scanning if we detect
-	 * transmissions.
-	 *
-	 * There is an issue with some firmware versions that triggers
-	 * a sysassert on a "good CRC threshold" of zero (== disabled),
-	 * on a radar channel even though this means that we should NOT
-	 * send probes.
-	 *
-	 * The "good CRC threshold" is the number of frames that we
-	 * need to receive during our dwell time on a channel before
-	 * sending out probes -- setting this to a huge value will
-	 * mean we never reach it, but at the same time work around
-	 * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
-	 * here instead of IWL_GOOD_CRC_TH_DISABLED.
-	 *
-	 * This was fixed in later versions along with some other
-	 * scan changes, and the threshold behaves as a flag in those
-	 * versions.
-	 */
-	if (priv->new_scan_threshold_behaviour)
-		scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
-						IWL_GOOD_CRC_TH_DISABLED;
-	else
-		scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
-						IWL_GOOD_CRC_TH_NEVER;
-
-	band = priv->scan_band;
-
-	if (band == IEEE80211_BAND_2GHZ &&
-	    priv->cfg->bt_params &&
-	    priv->cfg->bt_params->advanced_bt_coexist) {
-		/* transmit 2.4 GHz probes only on first antenna */
-		scan_tx_antennas = first_antenna(scan_tx_antennas);
-	}
-
-	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);
-
-	/*
-	 * In power save mode while associated use one chain,
-	 * otherwise use all chains
-	 */
-	if (test_bit(STATUS_POWER_PMI, &priv->status) &&
-	    !(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) {
-		/* rx_ant has been set to all valid chains previously */
-		active_chains = rx_ant &
-				((u8)(priv->chain_noise_data.active_chains));
-		if (!active_chains)
-			active_chains = rx_ant;
-
-		IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n",
-				priv->chain_noise_data.active_chains);
-
-		rx_ant = first_antenna(active_chains);
-	}
-	if (priv->cfg->bt_params &&
-	    priv->cfg->bt_params->advanced_bt_coexist &&
-	    priv->bt_full_concurrent) {
-		/* operated as 1x1 in full concurrency mode */
-		rx_ant = first_antenna(rx_ant);
-	}
-
-	/* MIMO is not used here, but value is required */
-	rx_chain |=
-		priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
-	rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
-	rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
-	rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
-	scan->rx_chain = cpu_to_le16(rx_chain);
-	switch (priv->scan_type) {
-	case IWL_SCAN_NORMAL:
-		cmd_len = iwl_fill_probe_req(
-					(struct ieee80211_mgmt *)scan->data,
-					vif->addr,
-					priv->scan_request->ie,
-					priv->scan_request->ie_len,
-					ssid, ssid_len,
-					scan_cmd_size - sizeof(*scan));
-		break;
-	case IWL_SCAN_RADIO_RESET:
-	case IWL_SCAN_ROC:
-		/* use bcast addr, will not be transmitted but must be valid */
-		cmd_len = iwl_fill_probe_req(
-					(struct ieee80211_mgmt *)scan->data,
-					iwl_bcast_addr, NULL, 0,
-					NULL, 0,
-					scan_cmd_size - sizeof(*scan));
-		break;
-	default:
-		BUG();
-	}
-	scan->tx_cmd.len = cpu_to_le16(cmd_len);
-
-	scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
-			       RXON_FILTER_BCON_AWARE_MSK);
-
-	switch (priv->scan_type) {
-	case IWL_SCAN_RADIO_RESET:
-		scan->channel_count =
-			iwl_get_single_channel_for_scan(priv, vif, band,
-				(void *)&scan->data[cmd_len]);
-		break;
-	case IWL_SCAN_NORMAL:
-		scan->channel_count =
-			iwl_get_channels_for_scan(priv, vif, band,
-				is_active, n_probes,
-				(void *)&scan->data[cmd_len]);
-		break;
-	case IWL_SCAN_ROC: {
-		struct iwl_scan_channel *scan_ch;
-		int n_chan, i;
-		u16 dwell;
-
-		dwell = iwl_limit_dwell(priv, priv->hw_roc_duration);
-		n_chan = DIV_ROUND_UP(priv->hw_roc_duration, dwell);
-
-		scan->channel_count = n_chan;
-
-		scan_ch = (void *)&scan->data[cmd_len];
-
-		for (i = 0; i < n_chan; i++) {
-			scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
-			scan_ch->channel =
-				cpu_to_le16(priv->hw_roc_channel->hw_value);
-
-			if (i == n_chan - 1)
-				dwell = priv->hw_roc_duration - i * dwell;
-
-			scan_ch->active_dwell =
-			scan_ch->passive_dwell = cpu_to_le16(dwell);
-
-			/* Set txpower levels to defaults */
-			scan_ch->dsp_atten = 110;
-
-			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
-			 * power level:
-			 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
-			 */
-			if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ)
-				scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-			else
-				scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-
-			scan_ch++;
-		}
-		}
-
-		break;
-	}
-
-	if (scan->channel_count == 0) {
-		IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
-		return -EIO;
-	}
-
-	cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
-	    scan->channel_count * sizeof(struct iwl_scan_channel);
-	cmd.data[0] = scan;
-	cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-	scan->len = cpu_to_le16(cmd.len[0]);
-
-	/* set scan bit here for PAN params */
-	set_bit(STATUS_SCAN_HW, &priv->status);
-
-	ret = iwlagn_set_pan_params(priv);
-	if (ret)
-		return ret;
-
-	ret = iwl_dvm_send_cmd(priv, &cmd);
-	if (ret) {
-		clear_bit(STATUS_SCAN_HW, &priv->status);
-		iwlagn_set_pan_params(priv);
-	}
-
-	return ret;
-}
-
-void iwl_init_scan_params(struct iwl_priv *priv)
-{
-	u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1;
-	if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
-		priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
-	if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
-		priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
-}
-
-int __must_check iwl_scan_initiate(struct iwl_priv *priv,
-				   struct ieee80211_vif *vif,
-				   enum iwl_scan_type scan_type,
-				   enum ieee80211_band band)
-{
-	int ret;
-
-	lockdep_assert_held(&priv->mutex);
-
-	cancel_delayed_work(&priv->scan_check);
-
-	if (!iwl_is_ready_rf(priv)) {
-		IWL_WARN(priv, "Request scan called when driver not ready.\n");
-		return -EIO;
-	}
-
-	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
-		IWL_DEBUG_SCAN(priv,
-			"Multiple concurrent scan requests in parallel.\n");
-		return -EBUSY;
-	}
-
-	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-		IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n");
-		return -EBUSY;
-	}
-
-	IWL_DEBUG_SCAN(priv, "Starting %sscan...\n",
-			scan_type == IWL_SCAN_NORMAL ? "" :
-			scan_type == IWL_SCAN_ROC ? "remain-on-channel " :
-			"internal short ");
-
-	set_bit(STATUS_SCANNING, &priv->status);
-	priv->scan_type = scan_type;
-	priv->scan_start = jiffies;
-	priv->scan_band = band;
-
-	ret = iwlagn_request_scan(priv, vif);
-	if (ret) {
-		clear_bit(STATUS_SCANNING, &priv->status);
-		priv->scan_type = IWL_SCAN_NORMAL;
-		return ret;
-	}
-
-	queue_delayed_work(priv->workqueue, &priv->scan_check,
-			   IWL_SCAN_CHECK_WATCHDOG);
-
-	return 0;
-}
-
-
-/*
- * internal short scan, this function should only been called while associated.
- * It will reset and tune the radio to prevent possible RF related problem
- */
-void iwl_internal_short_hw_scan(struct iwl_priv *priv)
-{
-	queue_work(priv->workqueue, &priv->start_internal_scan);
-}
-
-static void iwl_bg_start_internal_scan(struct work_struct *work)
-{
-	struct iwl_priv *priv =
-		container_of(work, struct iwl_priv, start_internal_scan);
-
-	IWL_DEBUG_SCAN(priv, "Start internal scan\n");
-
-	mutex_lock(&priv->mutex);
-
-	if (priv->scan_type == IWL_SCAN_RADIO_RESET) {
-		IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
-		goto unlock;
-	}
-
-	if (test_bit(STATUS_SCANNING, &priv->status)) {
-		IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
-		goto unlock;
-	}
-
-	if (iwl_scan_initiate(priv, NULL, IWL_SCAN_RADIO_RESET, priv->band))
-		IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n");
- unlock:
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_scan_check(struct work_struct *data)
-{
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, scan_check.work);
-
-	IWL_DEBUG_SCAN(priv, "Scan check work\n");
-
-	/* Since we are here firmware does not finish scan and
-	 * most likely is in bad shape, so we don't bother to
-	 * send abort command, just force scan complete to mac80211 */
-	mutex_lock(&priv->mutex);
-	iwl_force_scan_end(priv);
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_abort_scan(struct work_struct *work)
-{
-	struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
-
-	IWL_DEBUG_SCAN(priv, "Abort scan work\n");
-
-	/* We keep scan_check work queued in case when firmware will not
-	 * report back scan completed notification */
-	mutex_lock(&priv->mutex);
-	iwl_scan_cancel_timeout(priv, 200);
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_scan_completed(struct work_struct *work)
-{
-	struct iwl_priv *priv =
-		container_of(work, struct iwl_priv, scan_completed);
-
-	mutex_lock(&priv->mutex);
-	iwl_process_scan_complete(priv);
-	mutex_unlock(&priv->mutex);
-}
-
-void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
-{
-	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
-	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
-	INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
-	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
-}
-
-void iwl_cancel_scan_deferred_work(struct iwl_priv *priv)
-{
-	cancel_work_sync(&priv->start_internal_scan);
-	cancel_work_sync(&priv->abort_scan);
-	cancel_work_sync(&priv->scan_completed);
-
-	if (cancel_delayed_work_sync(&priv->scan_check)) {
-		mutex_lock(&priv->mutex);
-		iwl_force_scan_end(priv);
-		mutex_unlock(&priv->mutex);
-	}
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c
new file mode 100644
index 0000000..81e8c71
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-test.c
@@ -0,0 +1,856 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2010 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include <linux/export.h>
+#include <net/netlink.h>
+
+#include "iwl-io.h"
+#include "iwl-fh.h"
+#include "iwl-prph.h"
+#include "iwl-trans.h"
+#include "iwl-test.h"
+#include "iwl-csr.h"
+#include "iwl-testmode.h"
+
+/*
+ * Periphery registers absolute lower bound. This is used in order to
+ * differentiate registery access through HBUS_TARG_PRPH_* and
+ * HBUS_TARG_MEM_* accesses.
+ */
+#define IWL_ABS_PRPH_START (0xA00000)
+
+/*
+ * The TLVs used in the gnl message policy between the kernel module and
+ * user space application. iwl_testmode_gnl_msg_policy is to be carried
+ * through the NL80211_CMD_TESTMODE channel regulated by nl80211.
+ * See iwl-testmode.h
+ */
+static
+struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
+	[IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, },
+
+	[IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, },
+	[IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, },
+
+	[IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, },
+	[IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, },
+	[IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, },
+
+	[IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, },
+	[IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, },
+
+	[IWL_TM_ATTR_EEPROM] = { .type = NLA_UNSPEC, },
+
+	[IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, },
+	[IWL_TM_ATTR_TRACE_DUMP] = { .type = NLA_UNSPEC, },
+	[IWL_TM_ATTR_TRACE_SIZE] = { .type = NLA_U32, },
+
+	[IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
+
+	[IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, },
+
+	[IWL_TM_ATTR_MEM_ADDR] = { .type = NLA_U32, },
+	[IWL_TM_ATTR_BUFFER_SIZE] = { .type = NLA_U32, },
+	[IWL_TM_ATTR_BUFFER_DUMP] = { .type = NLA_UNSPEC, },
+
+	[IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, },
+	[IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, },
+	[IWL_TM_ATTR_FW_TYPE] = { .type = NLA_U32, },
+	[IWL_TM_ATTR_FW_INST_SIZE] = { .type = NLA_U32, },
+	[IWL_TM_ATTR_FW_DATA_SIZE] = { .type = NLA_U32, },
+
+	[IWL_TM_ATTR_ENABLE_NOTIFICATION] = {.type = NLA_FLAG, },
+};
+
+static inline void iwl_test_trace_clear(struct iwl_test *tst)
+{
+	memset(&tst->trace, 0, sizeof(struct iwl_test_trace));
+}
+
+static void iwl_test_trace_stop(struct iwl_test *tst)
+{
+	if (!tst->trace.enabled)
+		return;
+
+	if (tst->trace.cpu_addr && tst->trace.dma_addr)
+		dma_free_coherent(tst->trans->dev,
+				  tst->trace.tsize,
+				  tst->trace.cpu_addr,
+				  tst->trace.dma_addr);
+
+	iwl_test_trace_clear(tst);
+}
+
+static inline void iwl_test_mem_clear(struct iwl_test *tst)
+{
+	memset(&tst->mem, 0, sizeof(struct iwl_test_mem));
+}
+
+static inline void iwl_test_mem_stop(struct iwl_test *tst)
+{
+	if (!tst->mem.in_read)
+		return;
+
+	iwl_test_mem_clear(tst);
+}
+
+/*
+ * Initializes the test object
+ * During the lifetime of the test object it is assumed that the transport is
+ * started. The test object should be stopped before the transport is stopped.
+ */
+void iwl_test_init(struct iwl_test *tst, struct iwl_trans *trans,
+		   struct iwl_test_ops *ops)
+{
+	tst->trans = trans;
+	tst->ops = ops;
+
+	iwl_test_trace_clear(tst);
+	iwl_test_mem_clear(tst);
+}
+EXPORT_SYMBOL_GPL(iwl_test_init);
+
+/*
+ * Stop the test object
+ */
+void iwl_test_free(struct iwl_test *tst)
+{
+	iwl_test_mem_stop(tst);
+	iwl_test_trace_stop(tst);
+}
+EXPORT_SYMBOL_GPL(iwl_test_free);
+
+static inline int iwl_test_send_cmd(struct iwl_test *tst,
+				    struct iwl_host_cmd *cmd)
+{
+	return tst->ops->send_cmd(tst->trans->op_mode, cmd);
+}
+
+static inline bool iwl_test_valid_hw_addr(struct iwl_test *tst, u32 addr)
+{
+	return tst->ops->valid_hw_addr(addr);
+}
+
+static inline u32 iwl_test_fw_ver(struct iwl_test *tst)
+{
+	return tst->ops->get_fw_ver(tst->trans->op_mode);
+}
+
+static inline struct sk_buff*
+iwl_test_alloc_reply(struct iwl_test *tst, int len)
+{
+	return tst->ops->alloc_reply(tst->trans->op_mode, len);
+}
+
+static inline int iwl_test_reply(struct iwl_test *tst, struct sk_buff *skb)
+{
+	return tst->ops->reply(tst->trans->op_mode, skb);
+}
+
+static inline struct sk_buff*
+iwl_test_alloc_event(struct iwl_test *tst, int len)
+{
+	return tst->ops->alloc_event(tst->trans->op_mode, len);
+}
+
+static inline void
+iwl_test_event(struct iwl_test *tst, struct sk_buff *skb)
+{
+	return tst->ops->event(tst->trans->op_mode, skb);
+}
+
+/*
+ * This function handles the user application commands to the fw. The fw
+ * commands are sent in a synchronuous manner. In case that the user requested
+ * to get commands response, it is send to the user.
+ */
+static int iwl_test_fw_cmd(struct iwl_test *tst, struct nlattr **tb)
+{
+	struct iwl_host_cmd cmd;
+	struct iwl_rx_packet *pkt;
+	struct sk_buff *skb;
+	void *reply_buf;
+	u32 reply_len;
+	int ret;
+	bool cmd_want_skb;
+
+	memset(&cmd, 0, sizeof(struct iwl_host_cmd));
+
+	if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
+	    !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
+		IWL_ERR(tst->trans, "Missing fw command mandatory fields\n");
+		return -ENOMSG;
+	}
+
+	cmd.flags = CMD_ON_DEMAND | CMD_SYNC;
+	cmd_want_skb = nla_get_flag(tb[IWL_TM_ATTR_UCODE_CMD_SKB]);
+	if (cmd_want_skb)
+		cmd.flags |= CMD_WANT_SKB;
+
+	cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
+	cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+	cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+	cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+	IWL_DEBUG_INFO(tst->trans, "test fw cmd=0x%x, flags 0x%x, len %d\n",
+		       cmd.id, cmd.flags, cmd.len[0]);
+
+	ret = iwl_test_send_cmd(tst, &cmd);
+	if (ret) {
+		IWL_ERR(tst->trans, "Failed to send hcmd\n");
+		return ret;
+	}
+	if (!cmd_want_skb)
+		return ret;
+
+	/* Handling return of SKB to the user */
+	pkt = cmd.resp_pkt;
+	if (!pkt) {
+		IWL_ERR(tst->trans, "HCMD received a null response packet\n");
+		return ret;
+	}
+
+	reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+	skb = iwl_test_alloc_reply(tst, reply_len + 20);
+	reply_buf = kmalloc(reply_len, GFP_KERNEL);
+	if (!skb || !reply_buf) {
+		kfree_skb(skb);
+		kfree(reply_buf);
+		return -ENOMEM;
+	}
+
+	/* The reply is in a page, that we cannot send to user space. */
+	memcpy(reply_buf, &(pkt->hdr), reply_len);
+	iwl_free_resp(&cmd);
+
+	if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
+			IWL_TM_CMD_DEV2APP_UCODE_RX_PKT) ||
+	    nla_put(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf))
+		goto nla_put_failure;
+	return iwl_test_reply(tst, skb);
+
+nla_put_failure:
+	IWL_DEBUG_INFO(tst->trans, "Failed creating NL attributes\n");
+	kfree(reply_buf);
+	kfree_skb(skb);
+	return -ENOMSG;
+}
+
+/*
+ * Handles the user application commands for register access.
+ */
+static int iwl_test_reg(struct iwl_test *tst, struct nlattr **tb)
+{
+	u32 ofs, val32, cmd;
+	u8 val8;
+	struct sk_buff *skb;
+	int status = 0;
+	struct iwl_trans *trans = tst->trans;
+
+	if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
+		IWL_ERR(trans, "Missing reg offset\n");
+		return -ENOMSG;
+	}
+
+	ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
+	IWL_DEBUG_INFO(trans, "test reg access cmd offset=0x%x\n", ofs);
+
+	cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
+
+	/*
+	 * Allow access only to FH/CSR/HBUS in direct mode.
+	 * Since we don't have the upper bounds for the CSR and HBUS segments,
+	 * we will use only the upper bound of FH for sanity check.
+	 */
+	if (ofs >= FH_MEM_UPPER_BOUND) {
+		IWL_ERR(trans, "offset out of segment (0x0 - 0x%x)\n",
+			FH_MEM_UPPER_BOUND);
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
+		val32 = iwl_read_direct32(tst->trans, ofs);
+		IWL_DEBUG_INFO(trans, "32 value to read 0x%x\n", val32);
+
+		skb = iwl_test_alloc_reply(tst, 20);
+		if (!skb) {
+			IWL_ERR(trans, "Memory allocation fail\n");
+			return -ENOMEM;
+		}
+		if (nla_put_u32(skb, IWL_TM_ATTR_REG_VALUE32, val32))
+			goto nla_put_failure;
+		status = iwl_test_reply(tst, skb);
+		if (status < 0)
+			IWL_ERR(trans, "Error sending msg : %d\n", status);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
+		if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
+			IWL_ERR(trans, "Missing value to write\n");
+			return -ENOMSG;
+		} else {
+			val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
+			IWL_DEBUG_INFO(trans, "32b write val=0x%x\n", val32);
+			iwl_write_direct32(tst->trans, ofs, val32);
+		}
+		break;
+
+	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
+		if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
+			IWL_ERR(trans, "Missing value to write\n");
+			return -ENOMSG;
+		} else {
+			val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
+			IWL_DEBUG_INFO(trans, "8b write val=0x%x\n", val8);
+			iwl_write8(tst->trans, ofs, val8);
+		}
+		break;
+
+	default:
+		IWL_ERR(trans, "Unknown test register cmd ID\n");
+		return -ENOMSG;
+	}
+
+	return status;
+
+nla_put_failure:
+	kfree_skb(skb);
+	return -EMSGSIZE;
+}
+
+/*
+ * Handles the request to start FW tracing. Allocates of the trace buffer
+ * and sends a reply to user space with the address of the allocated buffer.
+ */
+static int iwl_test_trace_begin(struct iwl_test *tst, struct nlattr **tb)
+{
+	struct sk_buff *skb;
+	int status = 0;
+
+	if (tst->trace.enabled)
+		return -EBUSY;
+
+	if (!tb[IWL_TM_ATTR_TRACE_SIZE])
+		tst->trace.size = TRACE_BUFF_SIZE_DEF;
+	else
+		tst->trace.size =
+			nla_get_u32(tb[IWL_TM_ATTR_TRACE_SIZE]);
+
+	if (!tst->trace.size)
+		return -EINVAL;
+
+	if (tst->trace.size < TRACE_BUFF_SIZE_MIN ||
+	    tst->trace.size > TRACE_BUFF_SIZE_MAX)
+		return -EINVAL;
+
+	tst->trace.tsize = tst->trace.size + TRACE_BUFF_PADD;
+	tst->trace.cpu_addr = dma_alloc_coherent(tst->trans->dev,
+						 tst->trace.tsize,
+						 &tst->trace.dma_addr,
+						 GFP_KERNEL);
+	if (!tst->trace.cpu_addr)
+		return -ENOMEM;
+
+	tst->trace.enabled = true;
+	tst->trace.trace_addr = (u8 *)PTR_ALIGN(tst->trace.cpu_addr, 0x100);
+
+	memset(tst->trace.trace_addr, 0x03B, tst->trace.size);
+
+	skb = iwl_test_alloc_reply(tst, sizeof(tst->trace.dma_addr) + 20);
+	if (!skb) {
+		IWL_ERR(tst->trans, "Memory allocation fail\n");
+		iwl_test_trace_stop(tst);
+		return -ENOMEM;
+	}
+
+	if (nla_put(skb, IWL_TM_ATTR_TRACE_ADDR,
+		    sizeof(tst->trace.dma_addr),
+		    (u64 *)&tst->trace.dma_addr))
+		goto nla_put_failure;
+
+	status = iwl_test_reply(tst, skb);
+	if (status < 0)
+		IWL_ERR(tst->trans, "Error sending msg : %d\n", status);
+
+	tst->trace.nchunks = DIV_ROUND_UP(tst->trace.size,
+					  DUMP_CHUNK_SIZE);
+
+	return status;
+
+nla_put_failure:
+	kfree_skb(skb);
+	if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) ==
+	    IWL_TM_CMD_APP2DEV_BEGIN_TRACE)
+		iwl_test_trace_stop(tst);
+	return -EMSGSIZE;
+}
+
+/*
+ * Handles indirect read from the periphery or the SRAM. The read is performed
+ * to a temporary buffer. The user space application should later issue a dump
+ */
+static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size)
+{
+	struct iwl_trans *trans = tst->trans;
+	unsigned long flags;
+	int i;
+
+	if (size & 0x3)
+		return -EINVAL;
+
+	tst->mem.size = size;
+	tst->mem.addr = kmalloc(tst->mem.size, GFP_KERNEL);
+	if (tst->mem.addr == NULL)
+		return -ENOMEM;
+
+	/* Hard-coded periphery absolute address */
+	if (IWL_ABS_PRPH_START <= addr &&
+	    addr < IWL_ABS_PRPH_START + PRPH_END) {
+			spin_lock_irqsave(&trans->reg_lock, flags);
+			iwl_grab_nic_access(trans);
+			iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
+				    addr | (3 << 24));
+			for (i = 0; i < size; i += 4)
+				*(u32 *)(tst->mem.addr + i) =
+					iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
+			iwl_release_nic_access(trans);
+			spin_unlock_irqrestore(&trans->reg_lock, flags);
+	} else { /* target memory (SRAM) */
+		_iwl_read_targ_mem_dwords(trans, addr,
+					  tst->mem.addr,
+					  tst->mem.size / 4);
+	}
+
+	tst->mem.nchunks =
+		DIV_ROUND_UP(tst->mem.size, DUMP_CHUNK_SIZE);
+	tst->mem.in_read = true;
+	return 0;
+
+}
+
+/*
+ * Handles indirect write to the periphery or SRAM. The  is performed to a
+ * temporary buffer.
+ */
+static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr,
+	u32 size, unsigned char *buf)
+{
+	struct iwl_trans *trans = tst->trans;
+	u32 val, i;
+	unsigned long flags;
+
+	if (IWL_ABS_PRPH_START <= addr &&
+	    addr < IWL_ABS_PRPH_START + PRPH_END) {
+			/* Periphery writes can be 1-3 bytes long, or DWORDs */
+			if (size < 4) {
+				memcpy(&val, buf, size);
+				spin_lock_irqsave(&trans->reg_lock, flags);
+				iwl_grab_nic_access(trans);
+				iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
+					    (addr & 0x0000FFFF) |
+					    ((size - 1) << 24));
+				iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
+				iwl_release_nic_access(trans);
+				/* needed after consecutive writes w/o read */
+				mmiowb();
+				spin_unlock_irqrestore(&trans->reg_lock, flags);
+			} else {
+				if (size % 4)
+					return -EINVAL;
+				for (i = 0; i < size; i += 4)
+					iwl_write_prph(trans, addr+i,
+						       *(u32 *)(buf+i));
+			}
+	} else if (iwl_test_valid_hw_addr(tst, addr)) {
+		_iwl_write_targ_mem_dwords(trans, addr, buf, size / 4);
+	} else {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * Handles the user application commands for indirect read/write
+ * to/from the periphery or the SRAM.
+ */
+static int iwl_test_indirect_mem(struct iwl_test *tst, struct nlattr **tb)
+{
+	u32 addr, size, cmd;
+	unsigned char *buf;
+
+	/* Both read and write should be blocked, for atomicity */
+	if (tst->mem.in_read)
+		return -EBUSY;
+
+	cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
+	if (!tb[IWL_TM_ATTR_MEM_ADDR]) {
+		IWL_ERR(tst->trans, "Error finding memory offset address\n");
+		return -ENOMSG;
+	}
+	addr = nla_get_u32(tb[IWL_TM_ATTR_MEM_ADDR]);
+	if (!tb[IWL_TM_ATTR_BUFFER_SIZE]) {
+		IWL_ERR(tst->trans, "Error finding size for memory reading\n");
+		return -ENOMSG;
+	}
+	size = nla_get_u32(tb[IWL_TM_ATTR_BUFFER_SIZE]);
+
+	if (cmd == IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ) {
+		return iwl_test_indirect_read(tst, addr,  size);
+	} else {
+		if (!tb[IWL_TM_ATTR_BUFFER_DUMP])
+			return -EINVAL;
+		buf = (unsigned char *)nla_data(tb[IWL_TM_ATTR_BUFFER_DUMP]);
+		return iwl_test_indirect_write(tst, addr, size, buf);
+	}
+}
+
+/*
+ * Enable notifications to user space
+ */
+static int iwl_test_notifications(struct iwl_test *tst,
+				  struct nlattr **tb)
+{
+	tst->notify = nla_get_flag(tb[IWL_TM_ATTR_ENABLE_NOTIFICATION]);
+	return 0;
+}
+
+/*
+ * Handles the request to get the device id
+ */
+static int iwl_test_get_dev_id(struct iwl_test *tst, struct nlattr **tb)
+{
+	u32 devid = tst->trans->hw_id;
+	struct sk_buff *skb;
+	int status;
+
+	IWL_DEBUG_INFO(tst->trans, "hw version: 0x%x\n", devid);
+
+	skb = iwl_test_alloc_reply(tst, 20);
+	if (!skb) {
+		IWL_ERR(tst->trans, "Memory allocation fail\n");
+		return -ENOMEM;
+	}
+
+	if (nla_put_u32(skb, IWL_TM_ATTR_DEVICE_ID, devid))
+		goto nla_put_failure;
+	status = iwl_test_reply(tst, skb);
+	if (status < 0)
+		IWL_ERR(tst->trans, "Error sending msg : %d\n", status);
+
+	return 0;
+
+nla_put_failure:
+	kfree_skb(skb);
+	return -EMSGSIZE;
+}
+
+/*
+ * Handles the request to get the FW version
+ */
+static int iwl_test_get_fw_ver(struct iwl_test *tst, struct nlattr **tb)
+{
+	struct sk_buff *skb;
+	int status;
+	u32 ver = iwl_test_fw_ver(tst);
+
+	IWL_DEBUG_INFO(tst->trans, "uCode version raw: 0x%x\n", ver);
+
+	skb = iwl_test_alloc_reply(tst, 20);
+	if (!skb) {
+		IWL_ERR(tst->trans, "Memory allocation fail\n");
+		return -ENOMEM;
+	}
+
+	if (nla_put_u32(skb, IWL_TM_ATTR_FW_VERSION, ver))
+		goto nla_put_failure;
+
+	status = iwl_test_reply(tst, skb);
+	if (status < 0)
+		IWL_ERR(tst->trans, "Error sending msg : %d\n", status);
+
+	return 0;
+
+nla_put_failure:
+	kfree_skb(skb);
+	return -EMSGSIZE;
+}
+
+/*
+ * Parse the netlink message and validate that the IWL_TM_ATTR_CMD exists
+ */
+int iwl_test_parse(struct iwl_test *tst, struct nlattr **tb,
+		   void *data, int len)
+{
+	int result;
+
+	result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
+			iwl_testmode_gnl_msg_policy);
+	if (result) {
+		IWL_ERR(tst->trans, "Fail parse gnl msg: %d\n", result);
+		return result;
+	}
+
+	/* IWL_TM_ATTR_COMMAND is absolutely mandatory */
+	if (!tb[IWL_TM_ATTR_COMMAND]) {
+		IWL_ERR(tst->trans, "Missing testmode command type\n");
+		return -ENOMSG;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(iwl_test_parse);
+
+/*
+ * Handle test commands.
+ * Returns 1 for unknown commands (not handled by the test object); negative
+ * value in case of error.
+ */
+int iwl_test_handle_cmd(struct iwl_test *tst, struct nlattr **tb)
+{
+	int result;
+
+	switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+	case IWL_TM_CMD_APP2DEV_UCODE:
+		IWL_DEBUG_INFO(tst->trans, "test cmd to uCode\n");
+		result = iwl_test_fw_cmd(tst, tb);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
+	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
+	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
+		IWL_DEBUG_INFO(tst->trans, "test cmd to register\n");
+		result = iwl_test_reg(tst, tb);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
+		IWL_DEBUG_INFO(tst->trans, "test uCode trace cmd to driver\n");
+		result = iwl_test_trace_begin(tst, tb);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_END_TRACE:
+		iwl_test_trace_stop(tst);
+		result = 0;
+		break;
+
+	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ:
+	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE:
+		IWL_DEBUG_INFO(tst->trans, "test indirect memory cmd\n");
+		result = iwl_test_indirect_mem(tst, tb);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
+		IWL_DEBUG_INFO(tst->trans, "test notifications cmd\n");
+		result = iwl_test_notifications(tst, tb);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
+		IWL_DEBUG_INFO(tst->trans, "test get FW ver cmd\n");
+		result = iwl_test_get_fw_ver(tst, tb);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
+		IWL_DEBUG_INFO(tst->trans, "test Get device ID cmd\n");
+		result = iwl_test_get_dev_id(tst, tb);
+		break;
+
+	default:
+		IWL_DEBUG_INFO(tst->trans, "Unknown test command\n");
+		result = 1;
+		break;
+	}
+	return result;
+}
+EXPORT_SYMBOL_GPL(iwl_test_handle_cmd);
+
+static int iwl_test_trace_dump(struct iwl_test *tst, struct sk_buff *skb,
+			       struct netlink_callback *cb)
+{
+	int idx, length;
+
+	if (!tst->trace.enabled || !tst->trace.trace_addr)
+		return -EFAULT;
+
+	idx = cb->args[4];
+	if (idx >= tst->trace.nchunks)
+		return -ENOENT;
+
+	length = DUMP_CHUNK_SIZE;
+	if (((idx + 1) == tst->trace.nchunks) &&
+	    (tst->trace.size % DUMP_CHUNK_SIZE))
+		length = tst->trace.size %
+			DUMP_CHUNK_SIZE;
+
+	if (nla_put(skb, IWL_TM_ATTR_TRACE_DUMP, length,
+		    tst->trace.trace_addr + (DUMP_CHUNK_SIZE * idx)))
+		goto nla_put_failure;
+
+	cb->args[4] = ++idx;
+	return 0;
+
+ nla_put_failure:
+	return -ENOBUFS;
+}
+
+static int iwl_test_buffer_dump(struct iwl_test *tst, struct sk_buff *skb,
+				struct netlink_callback *cb)
+{
+	int idx, length;
+
+	if (!tst->mem.in_read)
+		return -EFAULT;
+
+	idx = cb->args[4];
+	if (idx >= tst->mem.nchunks) {
+		iwl_test_mem_stop(tst);
+		return -ENOENT;
+	}
+
+	length = DUMP_CHUNK_SIZE;
+	if (((idx + 1) == tst->mem.nchunks) &&
+	    (tst->mem.size % DUMP_CHUNK_SIZE))
+		length = tst->mem.size % DUMP_CHUNK_SIZE;
+
+	if (nla_put(skb, IWL_TM_ATTR_BUFFER_DUMP, length,
+		    tst->mem.addr + (DUMP_CHUNK_SIZE * idx)))
+		goto nla_put_failure;
+
+	cb->args[4] = ++idx;
+	return 0;
+
+ nla_put_failure:
+	return -ENOBUFS;
+}
+
+/*
+ * Handle dump commands.
+ * Returns 1 for unknown commands (not handled by the test object); negative
+ * value in case of error.
+ */
+int iwl_test_dump(struct iwl_test *tst, u32 cmd, struct sk_buff *skb,
+		  struct netlink_callback *cb)
+{
+	int result;
+
+	switch (cmd) {
+	case IWL_TM_CMD_APP2DEV_READ_TRACE:
+		IWL_DEBUG_INFO(tst->trans, "uCode trace cmd\n");
+		result = iwl_test_trace_dump(tst, skb, cb);
+		break;
+
+	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP:
+		IWL_DEBUG_INFO(tst->trans, "testmode sram dump cmd\n");
+		result = iwl_test_buffer_dump(tst, skb, cb);
+		break;
+
+	default:
+		result = 1;
+		break;
+	}
+	return result;
+}
+EXPORT_SYMBOL_GPL(iwl_test_dump);
+
+/*
+ * Multicast a spontaneous messages from the device to the user space.
+ */
+static void iwl_test_send_rx(struct iwl_test *tst,
+			     struct iwl_rx_cmd_buffer *rxb)
+{
+	struct sk_buff *skb;
+	struct iwl_rx_packet *data;
+	int length;
+
+	data = rxb_addr(rxb);
+	length = le32_to_cpu(data->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+
+	/* the length doesn't include len_n_flags field, so add it manually */
+	length += sizeof(__le32);
+
+	skb = iwl_test_alloc_event(tst, length + 20);
+	if (skb == NULL) {
+		IWL_ERR(tst->trans, "Out of memory for message to user\n");
+		return;
+	}
+
+	if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
+			IWL_TM_CMD_DEV2APP_UCODE_RX_PKT) ||
+	    nla_put(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data))
+		goto nla_put_failure;
+
+	iwl_test_event(tst, skb);
+	return;
+
+nla_put_failure:
+	kfree_skb(skb);
+	IWL_ERR(tst->trans, "Ouch, overran buffer, check allocation!\n");
+}
+
+/*
+ * Called whenever a Rx frames is recevied from the device. If notifications to
+ * the user space are requested, sends the frames to the user.
+ */
+void iwl_test_rx(struct iwl_test *tst, struct iwl_rx_cmd_buffer *rxb)
+{
+	if (tst->notify)
+		iwl_test_send_rx(tst, rxb);
+}
+EXPORT_SYMBOL_GPL(iwl_test_rx);
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.h b/drivers/net/wireless/iwlwifi/iwl-test.h
new file mode 100644
index 0000000..e13ffa8
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-test.h
@@ -0,0 +1,161 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2010 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __IWL_TEST_H__
+#define __IWL_TEST_H__
+
+#include <linux/types.h>
+#include "iwl-trans.h"
+
+struct iwl_test_trace {
+	u32 size;
+	u32 tsize;
+	u32 nchunks;
+	u8 *cpu_addr;
+	u8 *trace_addr;
+	dma_addr_t dma_addr;
+	bool enabled;
+};
+
+struct iwl_test_mem {
+	u32 size;
+	u32 nchunks;
+	u8 *addr;
+	bool in_read;
+};
+
+/*
+ * struct iwl_test_ops: callback to the op mode
+ *
+ * The structure defines the callbacks that the op_mode should handle,
+ * inorder to handle logic that is out of the scope of iwl_test. The
+ * op_mode must set all the callbacks.
+
+ * @send_cmd: handler that is used by the test object to request the
+ *  op_mode to send a command to the fw.
+ *
+ * @valid_hw_addr: handler that is used by the test object to request the
+ *  op_mode to check if the given address is a valid address.
+ *
+ * @get_fw_ver: handler used to get the FW version.
+ *
+ * @alloc_reply: handler used by the test object to request the op_mode
+ *  to allocate an skb for sending a reply to the user, and initialize
+ *  the skb. It is assumed that the test object only fills the required
+ *  attributes.
+ *
+ * @reply: handler used by the test object to request the op_mode to reply
+ *  to a request. The skb is an skb previously allocated by the the
+ *  alloc_reply callback.
+ I
+ * @alloc_event: handler used by the test object to request the op_mode
+ *  to allocate an skb for sending an event, and initialize
+ *  the skb. It is assumed that the test object only fills the required
+ *  attributes.
+ *
+ * @reply: handler used by the test object to request the op_mode to send
+ *  an event. The skb is an skb previously allocated by the the
+ *  alloc_event callback.
+ */
+struct iwl_test_ops {
+	int (*send_cmd)(struct iwl_op_mode *op_modes,
+			struct iwl_host_cmd *cmd);
+	bool (*valid_hw_addr)(u32 addr);
+	u32 (*get_fw_ver)(struct iwl_op_mode *op_mode);
+
+	struct sk_buff *(*alloc_reply)(struct iwl_op_mode *op_mode, int len);
+	int (*reply)(struct iwl_op_mode *op_mode, struct sk_buff *skb);
+	struct sk_buff* (*alloc_event)(struct iwl_op_mode *op_mode, int len);
+	void (*event)(struct iwl_op_mode *op_mode, struct sk_buff *skb);
+};
+
+struct iwl_test {
+	struct iwl_trans *trans;
+	struct iwl_test_ops *ops;
+	struct iwl_test_trace trace;
+	struct iwl_test_mem mem;
+	bool notify;
+};
+
+void iwl_test_init(struct iwl_test *tst, struct iwl_trans *trans,
+		   struct iwl_test_ops *ops);
+
+void iwl_test_free(struct iwl_test *tst);
+
+int iwl_test_parse(struct iwl_test *tst, struct nlattr **tb,
+		   void *data, int len);
+
+int iwl_test_handle_cmd(struct iwl_test *tst, struct nlattr **tb);
+
+int iwl_test_dump(struct iwl_test *tst, u32 cmd, struct sk_buff *skb,
+		  struct netlink_callback *cb);
+
+void iwl_test_rx(struct iwl_test *tst, struct iwl_rx_cmd_buffer *rxb);
+
+static inline void iwl_test_enable_notifications(struct iwl_test *tst,
+						 bool enable)
+{
+	tst->notify = enable;
+}
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c
deleted file mode 100644
index 060aac3..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.c
+++ /dev/null
@@ -1,1114 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2010 - 2012 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
- *
- * BSD LICENSE
- *
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <net/net_namespace.h>
-#include <linux/netdevice.h>
-#include <net/cfg80211.h>
-#include <net/mac80211.h>
-#include <net/netlink.h>
-
-#include "iwl-dev.h"
-#include "iwl-debug.h"
-#include "iwl-io.h"
-#include "iwl-agn.h"
-#include "iwl-testmode.h"
-#include "iwl-trans.h"
-#include "iwl-fh.h"
-#include "iwl-prph.h"
-
-
-/* Periphery registers absolute lower bound. This is used in order to
- * differentiate registery access through HBUS_TARG_PRPH_* and
- * HBUS_TARG_MEM_* accesses.
- */
-#define IWL_TM_ABS_PRPH_START (0xA00000)
-
-/* The TLVs used in the gnl message policy between the kernel module and
- * user space application. iwl_testmode_gnl_msg_policy is to be carried
- * through the NL80211_CMD_TESTMODE channel regulated by nl80211.
- * See iwl-testmode.h
- */
-static
-struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
-	[IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, },
-
-	[IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, },
-	[IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, },
-
-	[IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, },
-	[IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, },
-	[IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, },
-
-	[IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, },
-	[IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, },
-
-	[IWL_TM_ATTR_EEPROM] = { .type = NLA_UNSPEC, },
-
-	[IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, },
-	[IWL_TM_ATTR_TRACE_DUMP] = { .type = NLA_UNSPEC, },
-	[IWL_TM_ATTR_TRACE_SIZE] = { .type = NLA_U32, },
-
-	[IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
-
-	[IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, },
-
-	[IWL_TM_ATTR_MEM_ADDR] = { .type = NLA_U32, },
-	[IWL_TM_ATTR_BUFFER_SIZE] = { .type = NLA_U32, },
-	[IWL_TM_ATTR_BUFFER_DUMP] = { .type = NLA_UNSPEC, },
-
-	[IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, },
-	[IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, },
-	[IWL_TM_ATTR_FW_TYPE] = { .type = NLA_U32, },
-	[IWL_TM_ATTR_FW_INST_SIZE] = { .type = NLA_U32, },
-	[IWL_TM_ATTR_FW_DATA_SIZE] = { .type = NLA_U32, },
-
-	[IWL_TM_ATTR_ENABLE_NOTIFICATION] = {.type = NLA_FLAG, },
-};
-
-/*
- * See the struct iwl_rx_packet in iwl-commands.h for the format of the
- * received events from the device
- */
-static inline int get_event_length(struct iwl_rx_cmd_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	if (pkt)
-		return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-	else
-		return 0;
-}
-
-
-/*
- * This function multicasts the spontaneous messages from the device to the
- * user space. It is invoked whenever there is a received messages
- * from the device. This function is called within the ISR of the rx handlers
- * in iwlagn driver.
- *
- * The parsing of the message content is left to the user space application,
- * The message content is treated as unattacked raw data and is encapsulated
- * with IWL_TM_ATTR_UCODE_RX_PKT multicasting to the user space.
- *
- * @priv: the instance of iwlwifi device
- * @rxb: pointer to rx data content received by the ISR
- *
- * See the message policies and TLVs in iwl_testmode_gnl_msg_policy[].
- * For the messages multicasting to the user application, the mandatory
- * TLV fields are :
- *	IWL_TM_ATTR_COMMAND must be IWL_TM_CMD_DEV2APP_UCODE_RX_PKT
- *	IWL_TM_ATTR_UCODE_RX_PKT for carrying the message content
- */
-
-static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,
-				      struct iwl_rx_cmd_buffer *rxb)
-{
-	struct ieee80211_hw *hw = priv->hw;
-	struct sk_buff *skb;
-	void *data;
-	int length;
-
-	data = (void *)rxb_addr(rxb);
-	length = get_event_length(rxb);
-
-	if (!data || length == 0)
-		return;
-
-	skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length,
-								GFP_ATOMIC);
-	if (skb == NULL) {
-		IWL_ERR(priv,
-			 "Run out of memory for messages to user space ?\n");
-		return;
-	}
-	if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT) ||
-	    /* the length doesn't include len_n_flags field, so add it manually */
-	    nla_put(skb, IWL_TM_ATTR_UCODE_RX_PKT, length + sizeof(__le32), data))
-		goto nla_put_failure;
-	cfg80211_testmode_event(skb, GFP_ATOMIC);
-	return;
-
-nla_put_failure:
-	kfree_skb(skb);
-	IWL_ERR(priv, "Ouch, overran buffer, check allocation!\n");
-}
-
-void iwl_testmode_init(struct iwl_priv *priv)
-{
-	priv->pre_rx_handler = NULL;
-	priv->testmode_trace.trace_enabled = false;
-	priv->testmode_mem.read_in_progress = false;
-}
-
-static void iwl_mem_cleanup(struct iwl_priv *priv)
-{
-	if (priv->testmode_mem.read_in_progress) {
-		kfree(priv->testmode_mem.buff_addr);
-		priv->testmode_mem.buff_addr = NULL;
-		priv->testmode_mem.buff_size = 0;
-		priv->testmode_mem.num_chunks = 0;
-		priv->testmode_mem.read_in_progress = false;
-	}
-}
-
-static void iwl_trace_cleanup(struct iwl_priv *priv)
-{
-	if (priv->testmode_trace.trace_enabled) {
-		if (priv->testmode_trace.cpu_addr &&
-		    priv->testmode_trace.dma_addr)
-			dma_free_coherent(priv->trans->dev,
-					priv->testmode_trace.total_size,
-					priv->testmode_trace.cpu_addr,
-					priv->testmode_trace.dma_addr);
-		priv->testmode_trace.trace_enabled = false;
-		priv->testmode_trace.cpu_addr = NULL;
-		priv->testmode_trace.trace_addr = NULL;
-		priv->testmode_trace.dma_addr = 0;
-		priv->testmode_trace.buff_size = 0;
-		priv->testmode_trace.total_size = 0;
-	}
-}
-
-
-void iwl_testmode_cleanup(struct iwl_priv *priv)
-{
-	iwl_trace_cleanup(priv);
-	iwl_mem_cleanup(priv);
-}
-
-
-/*
- * This function handles the user application commands to the ucode.
- *
- * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_CMD_ID and
- * IWL_TM_ATTR_UCODE_CMD_DATA and calls to the handler to send the
- * host command to the ucode.
- *
- * If any mandatory field is missing, -ENOMSG is replied to the user space
- * application; otherwise, waits for the host command to be sent and checks
- * the return code. In case or error, it is returned, otherwise a reply is
- * allocated and the reply RX packet
- * is returned.
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_host_cmd cmd;
-	struct iwl_rx_packet *pkt;
-	struct sk_buff *skb;
-	void *reply_buf;
-	u32 reply_len;
-	int ret;
-	bool cmd_want_skb;
-
-	memset(&cmd, 0, sizeof(struct iwl_host_cmd));
-
-	if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
-	    !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
-		IWL_ERR(priv, "Missing ucode command mandatory fields\n");
-		return -ENOMSG;
-	}
-
-	cmd.flags = CMD_ON_DEMAND | CMD_SYNC;
-	cmd_want_skb = nla_get_flag(tb[IWL_TM_ATTR_UCODE_CMD_SKB]);
-	if (cmd_want_skb)
-		cmd.flags |= CMD_WANT_SKB;
-
-	cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
-	cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
-	cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
-	cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-	IWL_DEBUG_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
-				" len %d\n", cmd.id, cmd.flags, cmd.len[0]);
-
-	ret = iwl_dvm_send_cmd(priv, &cmd);
-	if (ret) {
-		IWL_ERR(priv, "Failed to send hcmd\n");
-		return ret;
-	}
-	if (!cmd_want_skb)
-		return ret;
-
-	/* Handling return of SKB to the user */
-	pkt = cmd.resp_pkt;
-	if (!pkt) {
-		IWL_ERR(priv, "HCMD received a null response packet\n");
-		return ret;
-	}
-
-	reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-	skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, reply_len + 20);
-	reply_buf = kmalloc(reply_len, GFP_KERNEL);
-	if (!skb || !reply_buf) {
-		kfree_skb(skb);
-		kfree(reply_buf);
-		return -ENOMEM;
-	}
-
-	/* The reply is in a page, that we cannot send to user space. */
-	memcpy(reply_buf, &(pkt->hdr), reply_len);
-	iwl_free_resp(&cmd);
-
-	if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT) ||
-	    nla_put(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf))
-		goto nla_put_failure;
-	return cfg80211_testmode_reply(skb);
-
-nla_put_failure:
-	IWL_DEBUG_INFO(priv, "Failed creating NL attributes\n");
-	return -ENOMSG;
-}
-
-
-/*
- * This function handles the user application commands for register access.
- *
- * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
- * handlers respectively.
- *
- * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the
- * mandatory fields(IWL_TM_ATTR_REG_OFFSET,IWL_TM_ATTR_REG_VALUE32,
- * IWL_TM_ATTR_REG_VALUE8) are missing; Otherwise 0 is replied indicating
- * the success of the command execution.
- *
- * If IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_READ32, the register read
- * value is returned with IWL_TM_ATTR_REG_VALUE32.
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	u32 ofs, val32, cmd;
-	u8 val8;
-	struct sk_buff *skb;
-	int status = 0;
-
-	if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
-		IWL_ERR(priv, "Missing register offset\n");
-		return -ENOMSG;
-	}
-	ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
-	IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs);
-
-	/* Allow access only to FH/CSR/HBUS in direct mode.
-	Since we don't have the upper bounds for the CSR and HBUS segments,
-	we will use only the upper bound of FH for sanity check. */
-	cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
-	if ((cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32 ||
-		cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32 ||
-		cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8) &&
-		(ofs >= FH_MEM_UPPER_BOUND)) {
-		IWL_ERR(priv, "offset out of segment (0x0 - 0x%x)\n",
-			FH_MEM_UPPER_BOUND);
-		return -EINVAL;
-	}
-
-	switch (cmd) {
-	case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
-		val32 = iwl_read_direct32(priv->trans, ofs);
-		IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
-
-		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
-		if (!skb) {
-			IWL_ERR(priv, "Memory allocation fail\n");
-			return -ENOMEM;
-		}
-		if (nla_put_u32(skb, IWL_TM_ATTR_REG_VALUE32, val32))
-			goto nla_put_failure;
-		status = cfg80211_testmode_reply(skb);
-		if (status < 0)
-			IWL_ERR(priv, "Error sending msg : %d\n", status);
-		break;
-	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
-		if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
-			IWL_ERR(priv, "Missing value to write\n");
-			return -ENOMSG;
-		} else {
-			val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
-			IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
-			iwl_write_direct32(priv->trans, ofs, val32);
-		}
-		break;
-	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
-		if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
-			IWL_ERR(priv, "Missing value to write\n");
-			return -ENOMSG;
-		} else {
-			val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
-			IWL_INFO(priv, "8bit value to write 0x%x\n", val8);
-			iwl_write8(priv->trans, ofs, val8);
-		}
-		break;
-	default:
-		IWL_ERR(priv, "Unknown testmode register command ID\n");
-		return -ENOSYS;
-	}
-
-	return status;
-
-nla_put_failure:
-	kfree_skb(skb);
-	return -EMSGSIZE;
-}
-
-
-static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
-{
-	struct iwl_notification_wait calib_wait;
-	static const u8 calib_complete[] = {
-		CALIBRATION_COMPLETE_NOTIFICATION
-	};
-	int ret;
-
-	iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
-				   calib_complete, ARRAY_SIZE(calib_complete),
-				   NULL, NULL);
-	ret = iwl_init_alive_start(priv);
-	if (ret) {
-		IWL_ERR(priv, "Fail init calibration: %d\n", ret);
-		goto cfg_init_calib_error;
-	}
-
-	ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, 2 * HZ);
-	if (ret)
-		IWL_ERR(priv, "Error detecting"
-			" CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
-	return ret;
-
-cfg_init_calib_error:
-	iwl_remove_notification(&priv->notif_wait, &calib_wait);
-	return ret;
-}
-
-/*
- * This function handles the user application commands for driver.
- *
- * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
- * handlers respectively.
- *
- * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
- * value of the actual command execution is replied to the user application.
- *
- * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
- * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
- * IWL_TM_CMD_DEV2APP_SYNC_RSP.
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct iwl_trans *trans = priv->trans;
-	struct sk_buff *skb;
-	unsigned char *rsp_data_ptr = NULL;
-	int status = 0, rsp_data_len = 0;
-	u32 devid, inst_size = 0, data_size = 0;
-	const struct fw_img *img;
-
-	switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
-	case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
-		rsp_data_ptr = (unsigned char *)priv->cfg->name;
-		rsp_data_len = strlen(priv->cfg->name);
-		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
-							rsp_data_len + 20);
-		if (!skb) {
-			IWL_ERR(priv, "Memory allocation fail\n");
-			return -ENOMEM;
-		}
-		if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
-				IWL_TM_CMD_DEV2APP_SYNC_RSP) ||
-		    nla_put(skb, IWL_TM_ATTR_SYNC_RSP,
-			    rsp_data_len, rsp_data_ptr))
-			goto nla_put_failure;
-		status = cfg80211_testmode_reply(skb);
-		if (status < 0)
-			IWL_ERR(priv, "Error sending msg : %d\n", status);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
-		status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
-		if (status)
-			IWL_ERR(priv, "Error loading init ucode: %d\n", status);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
-		iwl_testmode_cfg_init_calib(priv);
-		priv->ucode_loaded = false;
-		iwl_trans_stop_device(trans);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
-		status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
-		if (status) {
-			IWL_ERR(priv,
-				"Error loading runtime ucode: %d\n", status);
-			break;
-		}
-		status = iwl_alive_start(priv);
-		if (status)
-			IWL_ERR(priv,
-				"Error starting the device: %d\n", status);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
-		iwl_scan_cancel_timeout(priv, 200);
-		priv->ucode_loaded = false;
-		iwl_trans_stop_device(trans);
-		status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
-		if (status) {
-			IWL_ERR(priv,
-				"Error loading WOWLAN ucode: %d\n", status);
-			break;
-		}
-		status = iwl_alive_start(priv);
-		if (status)
-			IWL_ERR(priv,
-				"Error starting the device: %d\n", status);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_GET_EEPROM:
-		if (priv->eeprom) {
-			skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
-				priv->cfg->base_params->eeprom_size + 20);
-			if (!skb) {
-				IWL_ERR(priv, "Memory allocation fail\n");
-				return -ENOMEM;
-			}
-			if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
-					IWL_TM_CMD_DEV2APP_EEPROM_RSP) ||
-			    nla_put(skb, IWL_TM_ATTR_EEPROM,
-				    priv->cfg->base_params->eeprom_size,
-				    priv->eeprom))
-				goto nla_put_failure;
-			status = cfg80211_testmode_reply(skb);
-			if (status < 0)
-				IWL_ERR(priv, "Error sending msg : %d\n",
-					status);
-		} else
-			return -EFAULT;
-		break;
-
-	case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
-		if (!tb[IWL_TM_ATTR_FIXRATE]) {
-			IWL_ERR(priv, "Missing fixrate setting\n");
-			return -ENOMSG;
-		}
-		priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
-		IWL_INFO(priv, "uCode version raw: 0x%x\n",
-			 priv->fw->ucode_ver);
-
-		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
-		if (!skb) {
-			IWL_ERR(priv, "Memory allocation fail\n");
-			return -ENOMEM;
-		}
-		if (nla_put_u32(skb, IWL_TM_ATTR_FW_VERSION,
-				priv->fw->ucode_ver))
-			goto nla_put_failure;
-		status = cfg80211_testmode_reply(skb);
-		if (status < 0)
-			IWL_ERR(priv, "Error sending msg : %d\n", status);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
-		devid = priv->trans->hw_id;
-		IWL_INFO(priv, "hw version: 0x%x\n", devid);
-
-		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
-		if (!skb) {
-			IWL_ERR(priv, "Memory allocation fail\n");
-			return -ENOMEM;
-		}
-		if (nla_put_u32(skb, IWL_TM_ATTR_DEVICE_ID, devid))
-			goto nla_put_failure;
-		status = cfg80211_testmode_reply(skb);
-		if (status < 0)
-			IWL_ERR(priv, "Error sending msg : %d\n", status);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
-		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8);
-		if (!skb) {
-			IWL_ERR(priv, "Memory allocation fail\n");
-			return -ENOMEM;
-		}
-		if (!priv->ucode_loaded) {
-			IWL_ERR(priv, "No uCode has not been loaded\n");
-			return -EINVAL;
-		} else {
-			img = &priv->fw->img[priv->cur_ucode];
-			inst_size = img->sec[IWL_UCODE_SECTION_INST].len;
-			data_size = img->sec[IWL_UCODE_SECTION_DATA].len;
-		}
-		if (nla_put_u32(skb, IWL_TM_ATTR_FW_TYPE, priv->cur_ucode) ||
-		    nla_put_u32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size) ||
-		    nla_put_u32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size))
-			goto nla_put_failure;
-		status = cfg80211_testmode_reply(skb);
-		if (status < 0)
-			IWL_ERR(priv, "Error sending msg : %d\n", status);
-		break;
-
-	default:
-		IWL_ERR(priv, "Unknown testmode driver command ID\n");
-		return -ENOSYS;
-	}
-	return status;
-
-nla_put_failure:
-	kfree_skb(skb);
-	return -EMSGSIZE;
-}
-
-
-/*
- * This function handles the user application commands for uCode trace
- *
- * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
- * handlers respectively.
- *
- * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
- * value of the actual command execution is replied to the user application.
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	struct sk_buff *skb;
-	int status = 0;
-	struct device *dev = priv->trans->dev;
-
-	switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
-	case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
-		if (priv->testmode_trace.trace_enabled)
-			return -EBUSY;
-
-		if (!tb[IWL_TM_ATTR_TRACE_SIZE])
-			priv->testmode_trace.buff_size = TRACE_BUFF_SIZE_DEF;
-		else
-			priv->testmode_trace.buff_size =
-				nla_get_u32(tb[IWL_TM_ATTR_TRACE_SIZE]);
-		if (!priv->testmode_trace.buff_size)
-			return -EINVAL;
-		if (priv->testmode_trace.buff_size < TRACE_BUFF_SIZE_MIN ||
-		    priv->testmode_trace.buff_size > TRACE_BUFF_SIZE_MAX)
-			return -EINVAL;
-
-		priv->testmode_trace.total_size =
-			priv->testmode_trace.buff_size + TRACE_BUFF_PADD;
-		priv->testmode_trace.cpu_addr =
-			dma_alloc_coherent(dev,
-					   priv->testmode_trace.total_size,
-					   &priv->testmode_trace.dma_addr,
-					   GFP_KERNEL);
-		if (!priv->testmode_trace.cpu_addr)
-			return -ENOMEM;
-		priv->testmode_trace.trace_enabled = true;
-		priv->testmode_trace.trace_addr = (u8 *)PTR_ALIGN(
-			priv->testmode_trace.cpu_addr, 0x100);
-		memset(priv->testmode_trace.trace_addr, 0x03B,
-			priv->testmode_trace.buff_size);
-		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
-			sizeof(priv->testmode_trace.dma_addr) + 20);
-		if (!skb) {
-			IWL_ERR(priv, "Memory allocation fail\n");
-			iwl_trace_cleanup(priv);
-			return -ENOMEM;
-		}
-		if (nla_put(skb, IWL_TM_ATTR_TRACE_ADDR,
-			    sizeof(priv->testmode_trace.dma_addr),
-			    (u64 *)&priv->testmode_trace.dma_addr))
-			goto nla_put_failure;
-		status = cfg80211_testmode_reply(skb);
-		if (status < 0) {
-			IWL_ERR(priv, "Error sending msg : %d\n", status);
-		}
-		priv->testmode_trace.num_chunks =
-			DIV_ROUND_UP(priv->testmode_trace.buff_size,
-				     DUMP_CHUNK_SIZE);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_END_TRACE:
-		iwl_trace_cleanup(priv);
-		break;
-	default:
-		IWL_ERR(priv, "Unknown testmode mem command ID\n");
-		return -ENOSYS;
-	}
-	return status;
-
-nla_put_failure:
-	kfree_skb(skb);
-	if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) ==
-	    IWL_TM_CMD_APP2DEV_BEGIN_TRACE)
-		iwl_trace_cleanup(priv);
-	return -EMSGSIZE;
-}
-
-static int iwl_testmode_trace_dump(struct ieee80211_hw *hw,
-				   struct sk_buff *skb,
-				   struct netlink_callback *cb)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	int idx, length;
-
-	if (priv->testmode_trace.trace_enabled &&
-	    priv->testmode_trace.trace_addr) {
-		idx = cb->args[4];
-		if (idx >= priv->testmode_trace.num_chunks)
-			return -ENOENT;
-		length = DUMP_CHUNK_SIZE;
-		if (((idx + 1) == priv->testmode_trace.num_chunks) &&
-		    (priv->testmode_trace.buff_size % DUMP_CHUNK_SIZE))
-			length = priv->testmode_trace.buff_size %
-				DUMP_CHUNK_SIZE;
-
-		if (nla_put(skb, IWL_TM_ATTR_TRACE_DUMP, length,
-			    priv->testmode_trace.trace_addr +
-			    (DUMP_CHUNK_SIZE * idx)))
-			goto nla_put_failure;
-		idx++;
-		cb->args[4] = idx;
-		return 0;
-	} else
-		return -EFAULT;
-
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-/*
- * This function handles the user application switch ucode ownership.
- *
- * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_OWNER and
- * decide who the current owner of the uCode
- *
- * If the current owner is OWNERSHIP_TM, then the only host command
- * can deliver to uCode is from testmode, all the other host commands
- * will dropped.
- *
- * default driver is the owner of uCode in normal operational mode
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	u8 owner;
-
-	if (!tb[IWL_TM_ATTR_UCODE_OWNER]) {
-		IWL_ERR(priv, "Missing ucode owner\n");
-		return -ENOMSG;
-	}
-
-	owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
-	if (owner == IWL_OWNERSHIP_DRIVER) {
-		priv->ucode_owner = owner;
-		priv->pre_rx_handler = NULL;
-	} else if (owner == IWL_OWNERSHIP_TM) {
-		priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
-		priv->ucode_owner = owner;
-	} else {
-		IWL_ERR(priv, "Invalid owner\n");
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int iwl_testmode_indirect_read(struct iwl_priv *priv, u32 addr, u32 size)
-{
-	struct iwl_trans *trans = priv->trans;
-	unsigned long flags;
-	int i;
-
-	if (size & 0x3)
-		return -EINVAL;
-	priv->testmode_mem.buff_size = size;
-	priv->testmode_mem.buff_addr =
-		kmalloc(priv->testmode_mem.buff_size, GFP_KERNEL);
-	if (priv->testmode_mem.buff_addr == NULL)
-		return -ENOMEM;
-
-	/* Hard-coded periphery absolute address */
-	if (IWL_TM_ABS_PRPH_START <= addr &&
-		addr < IWL_TM_ABS_PRPH_START + PRPH_END) {
-			spin_lock_irqsave(&trans->reg_lock, flags);
-			iwl_grab_nic_access(trans);
-			iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
-				addr | (3 << 24));
-			for (i = 0; i < size; i += 4)
-				*(u32 *)(priv->testmode_mem.buff_addr + i) =
-					iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
-			iwl_release_nic_access(trans);
-			spin_unlock_irqrestore(&trans->reg_lock, flags);
-	} else { /* target memory (SRAM) */
-		_iwl_read_targ_mem_words(trans, addr,
-			priv->testmode_mem.buff_addr,
-			priv->testmode_mem.buff_size / 4);
-	}
-
-	priv->testmode_mem.num_chunks =
-		DIV_ROUND_UP(priv->testmode_mem.buff_size, DUMP_CHUNK_SIZE);
-	priv->testmode_mem.read_in_progress = true;
-	return 0;
-
-}
-
-static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr,
-	u32 size, unsigned char *buf)
-{
-	struct iwl_trans *trans = priv->trans;
-	u32 val, i;
-	unsigned long flags;
-
-	if (IWL_TM_ABS_PRPH_START <= addr &&
-		addr < IWL_TM_ABS_PRPH_START + PRPH_END) {
-			/* Periphery writes can be 1-3 bytes long, or DWORDs */
-			if (size < 4) {
-				memcpy(&val, buf, size);
-				spin_lock_irqsave(&trans->reg_lock, flags);
-				iwl_grab_nic_access(trans);
-				iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
-					    (addr & 0x0000FFFF) |
-					    ((size - 1) << 24));
-				iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
-				iwl_release_nic_access(trans);
-				/* needed after consecutive writes w/o read */
-				mmiowb();
-				spin_unlock_irqrestore(&trans->reg_lock, flags);
-			} else {
-				if (size % 4)
-					return -EINVAL;
-				for (i = 0; i < size; i += 4)
-					iwl_write_prph(trans, addr+i,
-						*(u32 *)(buf+i));
-			}
-	} else if (iwlagn_hw_valid_rtc_data_addr(addr) ||
-		(IWLAGN_RTC_INST_LOWER_BOUND <= addr &&
-		addr < IWLAGN_RTC_INST_UPPER_BOUND)) {
-			_iwl_write_targ_mem_words(trans, addr, buf, size/4);
-	} else
-		return -EINVAL;
-	return 0;
-}
-
-/*
- * This function handles the user application commands for SRAM data dump
- *
- * It retrieves the mandatory fields IWL_TM_ATTR_SRAM_ADDR and
- * IWL_TM_ATTR_SRAM_SIZE to decide the memory area for SRAM data reading
- *
- * Several error will be retured, -EBUSY if the SRAM data retrieved by
- * previous command has not been delivered to userspace, or -ENOMSG if
- * the mandatory fields (IWL_TM_ATTR_SRAM_ADDR,IWL_TM_ATTR_SRAM_SIZE)
- * are missing, or -ENOMEM if the buffer allocation fails.
- *
- * Otherwise 0 is replied indicating the success of the SRAM reading.
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_indirect_mem(struct ieee80211_hw *hw,
-	struct nlattr **tb)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	u32 addr, size, cmd;
-	unsigned char *buf;
-
-	/* Both read and write should be blocked, for atomicity */
-	if (priv->testmode_mem.read_in_progress)
-		return -EBUSY;
-
-	cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
-	if (!tb[IWL_TM_ATTR_MEM_ADDR]) {
-		IWL_ERR(priv, "Error finding memory offset address\n");
-		return -ENOMSG;
-	}
-	addr = nla_get_u32(tb[IWL_TM_ATTR_MEM_ADDR]);
-	if (!tb[IWL_TM_ATTR_BUFFER_SIZE]) {
-		IWL_ERR(priv, "Error finding size for memory reading\n");
-		return -ENOMSG;
-	}
-	size = nla_get_u32(tb[IWL_TM_ATTR_BUFFER_SIZE]);
-
-	if (cmd == IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ)
-		return iwl_testmode_indirect_read(priv, addr,  size);
-	else {
-		if (!tb[IWL_TM_ATTR_BUFFER_DUMP])
-			return -EINVAL;
-		buf = (unsigned char *) nla_data(tb[IWL_TM_ATTR_BUFFER_DUMP]);
-		return iwl_testmode_indirect_write(priv, addr, size, buf);
-	}
-}
-
-static int iwl_testmode_buffer_dump(struct ieee80211_hw *hw,
-				    struct sk_buff *skb,
-				    struct netlink_callback *cb)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	int idx, length;
-
-	if (priv->testmode_mem.read_in_progress) {
-		idx = cb->args[4];
-		if (idx >= priv->testmode_mem.num_chunks) {
-			iwl_mem_cleanup(priv);
-			return -ENOENT;
-		}
-		length = DUMP_CHUNK_SIZE;
-		if (((idx + 1) == priv->testmode_mem.num_chunks) &&
-		    (priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE))
-			length = priv->testmode_mem.buff_size %
-				DUMP_CHUNK_SIZE;
-
-		if (nla_put(skb, IWL_TM_ATTR_BUFFER_DUMP, length,
-			    priv->testmode_mem.buff_addr +
-			    (DUMP_CHUNK_SIZE * idx)))
-			goto nla_put_failure;
-		idx++;
-		cb->args[4] = idx;
-		return 0;
-	} else
-		return -EFAULT;
-
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-static int iwl_testmode_notifications(struct ieee80211_hw *hw,
-	struct nlattr **tb)
-{
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	bool enable;
-
-	enable = nla_get_flag(tb[IWL_TM_ATTR_ENABLE_NOTIFICATION]);
-	if (enable)
-		priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
-	else
-		priv->pre_rx_handler = NULL;
-	return 0;
-}
-
-
-/* The testmode gnl message handler that takes the gnl message from the
- * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
- * invoke the corresponding handlers.
- *
- * This function is invoked when there is user space application sending
- * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated
- * by nl80211.
- *
- * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before
- * dispatching it to the corresponding handler.
- *
- * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application;
- * -ENOSYS is replied to the user application if the command is unknown;
- * Otherwise, the command is dispatched to the respective handler.
- *
- * @hw: ieee80211_hw object that represents the device
- * @data: pointer to user space message
- * @len: length in byte of @data
- */
-int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
-{
-	struct nlattr *tb[IWL_TM_ATTR_MAX];
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	int result;
-
-	result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
-			iwl_testmode_gnl_msg_policy);
-	if (result != 0) {
-		IWL_ERR(priv, "Error parsing the gnl message : %d\n", result);
-		return result;
-	}
-
-	/* IWL_TM_ATTR_COMMAND is absolutely mandatory */
-	if (!tb[IWL_TM_ATTR_COMMAND]) {
-		IWL_ERR(priv, "Missing testmode command type\n");
-		return -ENOMSG;
-	}
-	/* in case multiple accesses to the device happens */
-	mutex_lock(&priv->mutex);
-
-	switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
-	case IWL_TM_CMD_APP2DEV_UCODE:
-		IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n");
-		result = iwl_testmode_ucode(hw, tb);
-		break;
-	case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
-	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
-	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
-		IWL_DEBUG_INFO(priv, "testmode cmd to register\n");
-		result = iwl_testmode_reg(hw, tb);
-		break;
-	case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
-	case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
-	case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
-	case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
-	case IWL_TM_CMD_APP2DEV_GET_EEPROM:
-	case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
-	case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
-	case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
-	case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
-	case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
-		IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
-		result = iwl_testmode_driver(hw, tb);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
-	case IWL_TM_CMD_APP2DEV_END_TRACE:
-	case IWL_TM_CMD_APP2DEV_READ_TRACE:
-		IWL_DEBUG_INFO(priv, "testmode uCode trace cmd to driver\n");
-		result = iwl_testmode_trace(hw, tb);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_OWNERSHIP:
-		IWL_DEBUG_INFO(priv, "testmode change uCode ownership\n");
-		result = iwl_testmode_ownership(hw, tb);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ:
-	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE:
-		IWL_DEBUG_INFO(priv, "testmode indirect memory cmd "
-			"to driver\n");
-		result = iwl_testmode_indirect_mem(hw, tb);
-		break;
-
-	case IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
-		IWL_DEBUG_INFO(priv, "testmode notifications cmd "
-			"to driver\n");
-		result = iwl_testmode_notifications(hw, tb);
-		break;
-
-	default:
-		IWL_ERR(priv, "Unknown testmode command\n");
-		result = -ENOSYS;
-		break;
-	}
-
-	mutex_unlock(&priv->mutex);
-	return result;
-}
-
-int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
-		      struct netlink_callback *cb,
-		      void *data, int len)
-{
-	struct nlattr *tb[IWL_TM_ATTR_MAX];
-	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-	int result;
-	u32 cmd;
-
-	if (cb->args[3]) {
-		/* offset by 1 since commands start at 0 */
-		cmd = cb->args[3] - 1;
-	} else {
-		result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
-				iwl_testmode_gnl_msg_policy);
-		if (result) {
-			IWL_ERR(priv,
-				"Error parsing the gnl message : %d\n", result);
-			return result;
-		}
-
-		/* IWL_TM_ATTR_COMMAND is absolutely mandatory */
-		if (!tb[IWL_TM_ATTR_COMMAND]) {
-			IWL_ERR(priv, "Missing testmode command type\n");
-			return -ENOMSG;
-		}
-		cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
-		cb->args[3] = cmd + 1;
-	}
-
-	/* in case multiple accesses to the device happens */
-	mutex_lock(&priv->mutex);
-	switch (cmd) {
-	case IWL_TM_CMD_APP2DEV_READ_TRACE:
-		IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n");
-		result = iwl_testmode_trace_dump(hw, skb, cb);
-		break;
-	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP:
-		IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n");
-		result = iwl_testmode_buffer_dump(hw, skb, cb);
-		break;
-	default:
-		result = -EINVAL;
-		break;
-	}
-
-	mutex_unlock(&priv->mutex);
-	return result;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
deleted file mode 100644
index e959207..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
+++ /dev/null
@@ -1,444 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-#ifndef __iwl_trans_int_pcie_h__
-#define __iwl_trans_int_pcie_h__
-
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/skbuff.h>
-#include <linux/wait.h>
-#include <linux/pci.h>
-#include <linux/timer.h>
-
-#include "iwl-fh.h"
-#include "iwl-csr.h"
-#include "iwl-trans.h"
-#include "iwl-debug.h"
-#include "iwl-io.h"
-#include "iwl-op-mode.h"
-
-struct iwl_host_cmd;
-
-/*This file includes the declaration that are internal to the
- * trans_pcie layer */
-
-struct iwl_rx_mem_buffer {
-	dma_addr_t page_dma;
-	struct page *page;
-	struct list_head list;
-};
-
-/**
- * struct isr_statistics - interrupt statistics
- *
- */
-struct isr_statistics {
-	u32 hw;
-	u32 sw;
-	u32 err_code;
-	u32 sch;
-	u32 alive;
-	u32 rfkill;
-	u32 ctkill;
-	u32 wakeup;
-	u32 rx;
-	u32 tx;
-	u32 unhandled;
-};
-
-/**
- * struct iwl_rx_queue - Rx queue
- * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
- * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
- * @pool:
- * @queue:
- * @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
- * @write_actual:
- * @rx_free: list of free SKBs for use
- * @rx_used: List of Rx buffers with no SKB
- * @need_update: flag to indicate we need to update read/write index
- * @rb_stts: driver's pointer to receive buffer status
- * @rb_stts_dma: bus address of receive buffer status
- * @lock:
- *
- * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
- */
-struct iwl_rx_queue {
-	__le32 *bd;
-	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;
-	u32 write;
-	u32 free_count;
-	u32 write_actual;
-	struct list_head rx_free;
-	struct list_head rx_used;
-	int need_update;
-	struct iwl_rb_status *rb_stts;
-	dma_addr_t rb_stts_dma;
-	spinlock_t lock;
-};
-
-struct iwl_dma_ptr {
-	dma_addr_t dma;
-	void *addr;
-	size_t size;
-};
-
-/**
- * iwl_queue_inc_wrap - increment queue index, wrap back to beginning
- * @index -- current index
- * @n_bd -- total number of entries in queue (must be power of 2)
- */
-static inline int iwl_queue_inc_wrap(int index, int n_bd)
-{
-	return ++index & (n_bd - 1);
-}
-
-/**
- * iwl_queue_dec_wrap - decrement queue index, wrap back to end
- * @index -- current index
- * @n_bd -- total number of entries in queue (must be power of 2)
- */
-static inline int iwl_queue_dec_wrap(int index, int n_bd)
-{
-	return --index & (n_bd - 1);
-}
-
-struct iwl_cmd_meta {
-	/* only for SYNC commands, iff the reply skb is wanted */
-	struct iwl_host_cmd *source;
-
-	DEFINE_DMA_UNMAP_ADDR(mapping);
-	DEFINE_DMA_UNMAP_LEN(len);
-
-	u32 flags;
-};
-
-/*
- * Generic queue structure
- *
- * Contains common data for Rx and Tx queues.
- *
- * Note the difference between n_bd and n_window: the hardware
- * always assumes 256 descriptors, so n_bd is always 256 (unless
- * there might be HW changes in the future). For the normal TX
- * queues, n_window, which is the size of the software queue data
- * is also 256; however, for the command queue, n_window is only
- * 32 since we don't need so many commands pending. Since the HW
- * still uses 256 BDs for DMA though, n_bd stays 256. As a result,
- * the software buffers (in the variables @meta, @txb in struct
- * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds
- * in the same struct) have 256.
- * This means that we end up with the following:
- *  HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
- *  SW entries:           | 0      | ... | 31          |
- * where N is a number between 0 and 7. This means that the SW
- * data is a window overlayed over the HW queue.
- */
-struct iwl_queue {
-	int n_bd;              /* number of BDs in this queue */
-	int write_ptr;       /* 1-st empty entry (index) host_w*/
-	int read_ptr;         /* last used entry (index) host_r*/
-	/* use for monitoring and recovering the stuck queue */
-	dma_addr_t dma_addr;   /* physical addr for BD's */
-	int n_window;	       /* safe queue window */
-	u32 id;
-	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 */
-};
-
-#define TFD_TX_CMD_SLOTS 256
-#define TFD_CMD_SLOTS 32
-
-struct iwl_pcie_tx_queue_entry {
-	struct iwl_device_cmd *cmd;
-	struct sk_buff *skb;
-	struct iwl_cmd_meta meta;
-};
-
-/**
- * struct iwl_tx_queue - Tx Queue for DMA
- * @q: generic Rx/Tx queue descriptor
- * @tfds: transmit frame descriptors (DMA memory)
- * @entries: transmit entries (driver state)
- * @lock: queue lock
- * @stuck_timer: timer that fires if queue gets stuck
- * @trans_pcie: pointer back to transport (for timer)
- * @need_update: indicates need to update read/write index
- * @active: stores if queue is active
- *
- * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
- * descriptors) and required locking structures.
- */
-struct iwl_tx_queue {
-	struct iwl_queue q;
-	struct iwl_tfd *tfds;
-	struct iwl_pcie_tx_queue_entry *entries;
-	spinlock_t lock;
-	struct timer_list stuck_timer;
-	struct iwl_trans_pcie *trans_pcie;
-	u8 need_update;
-	u8 active;
-};
-
-/**
- * struct iwl_trans_pcie - PCIe transport specific data
- * @rxq: all the RX queue data
- * @rx_replenish: work that will be called when buffers need to be allocated
- * @drv - pointer to iwl_drv
- * @trans: pointer to the generic transport area
- * @irq - the irq number for the device
- * @irq_requested: true when the irq has been requested
- * @scd_base_addr: scheduler sram base address in SRAM
- * @scd_bc_tbls: pointer to the byte count table of the scheduler
- * @kw: keep warm address
- * @pci_dev: basic pci-network driver stuff
- * @hw_base: pci hardware address support
- * @ucode_write_complete: indicates that the ucode has been copied.
- * @ucode_write_waitq: wait queue for uCode load
- * @status - transport specific status flags
- * @cmd_queue - command queue number
- * @rx_buf_size_8k: 8 kB RX buffer size
- * @rx_page_order: page order for receive buffer size
- * @wd_timeout: queue watchdog timeout (jiffies)
- */
-struct iwl_trans_pcie {
-	struct iwl_rx_queue rxq;
-	struct work_struct rx_replenish;
-	struct iwl_trans *trans;
-	struct iwl_drv *drv;
-
-	/* INT ICT Table */
-	__le32 *ict_tbl;
-	dma_addr_t ict_tbl_dma;
-	int ict_index;
-	u32 inta;
-	bool use_ict;
-	bool irq_requested;
-	struct tasklet_struct irq_tasklet;
-	struct isr_statistics isr_stats;
-
-	unsigned int irq;
-	spinlock_t irq_lock;
-	u32 inta_mask;
-	u32 scd_base_addr;
-	struct iwl_dma_ptr scd_bc_tbls;
-	struct iwl_dma_ptr kw;
-
-	struct iwl_tx_queue *txq;
-	unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
-	unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
-
-	/* PCI bus related data */
-	struct pci_dev *pci_dev;
-	void __iomem *hw_base;
-
-	bool ucode_write_complete;
-	wait_queue_head_t ucode_write_waitq;
-	unsigned long status;
-	u8 cmd_queue;
-	u8 n_no_reclaim_cmds;
-	u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
-	u8 setup_q_to_fifo[IWL_MAX_HW_QUEUES];
-	u8 n_q_to_fifo;
-
-	bool rx_buf_size_8k;
-	u32 rx_page_order;
-
-	const char **command_names;
-
-	/* queue watchdog */
-	unsigned long wd_timeout;
-};
-
-/*****************************************************
-* DRIVER STATUS FUNCTIONS
-******************************************************/
-#define STATUS_HCMD_ACTIVE	0
-#define STATUS_DEVICE_ENABLED	1
-#define STATUS_TPOWER_PMI	2
-#define STATUS_INT_ENABLED	3
-
-#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
-	((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))
-
-static inline struct iwl_trans *
-iwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie)
-{
-	return container_of((void *)trans_pcie, struct iwl_trans,
-			    trans_specific);
-}
-
-struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
-				       const struct pci_device_id *ent,
-				       const struct iwl_cfg *cfg);
-void iwl_trans_pcie_free(struct iwl_trans *trans);
-
-/*****************************************************
-* RX
-******************************************************/
-void iwl_bg_rx_replenish(struct work_struct *data);
-void iwl_irq_tasklet(struct iwl_trans *trans);
-void iwlagn_rx_replenish(struct iwl_trans *trans);
-void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
-			struct iwl_rx_queue *q);
-
-/*****************************************************
-* ICT
-******************************************************/
-void iwl_reset_ict(struct iwl_trans *trans);
-void iwl_disable_ict(struct iwl_trans *trans);
-int iwl_alloc_isr_ict(struct iwl_trans *trans);
-void iwl_free_isr_ict(struct iwl_trans *trans);
-irqreturn_t iwl_isr_ict(int irq, void *data);
-
-/*****************************************************
-* TX / HCMD
-******************************************************/
-void iwl_txq_update_write_ptr(struct iwl_trans *trans,
-			struct iwl_tx_queue *txq);
-int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
-				 struct iwl_tx_queue *txq,
-				 dma_addr_t addr, u16 len, u8 reset);
-int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id);
-int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
-void iwl_tx_cmd_complete(struct iwl_trans *trans,
-			 struct iwl_rx_cmd_buffer *rxb, int handler_status);
-void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
-					   struct iwl_tx_queue *txq,
-					   u16 byte_cnt);
-void iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int queue);
-void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index);
-void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
-				   struct iwl_tx_queue *txq,
-				   int tx_fifo_id, bool active);
-void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, int queue, int fifo,
-				 int sta_id, int tid, int frame_limit, u16 ssn);
-void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-			 enum dma_data_direction dma_dir);
-int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
-			 struct sk_buff_head *skbs);
-int iwl_queue_space(const struct iwl_queue *q);
-
-/*****************************************************
-* Error handling
-******************************************************/
-int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display);
-void iwl_dump_csr(struct iwl_trans *trans);
-
-/*****************************************************
-* Helpers
-******************************************************/
-static inline void iwl_disable_interrupts(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
-
-	/* disable interrupts from uCode/NIC to host */
-	iwl_write32(trans, CSR_INT_MASK, 0x00000000);
-
-	/* acknowledge/clear/reset any interrupts still pending
-	 * from uCode or flow handler (Rx/Tx DMA) */
-	iwl_write32(trans, CSR_INT, 0xffffffff);
-	iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff);
-	IWL_DEBUG_ISR(trans, "Disabled interrupts\n");
-}
-
-static inline void iwl_enable_interrupts(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
-	set_bit(STATUS_INT_ENABLED, &trans_pcie->status);
-	iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
-}
-
-static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
-{
-	IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
-	iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
-}
-
-static inline void iwl_wake_queue(struct iwl_trans *trans,
-				  struct iwl_tx_queue *txq)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	if (test_and_clear_bit(txq->q.id, trans_pcie->queue_stopped)) {
-		IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d\n", txq->q.id);
-		iwl_op_mode_queue_not_full(trans->op_mode, txq->q.id);
-	}
-}
-
-static inline void iwl_stop_queue(struct iwl_trans *trans,
-				  struct iwl_tx_queue *txq)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	if (!test_and_set_bit(txq->q.id, trans_pcie->queue_stopped)) {
-		iwl_op_mode_queue_full(trans->op_mode, txq->q.id);
-		IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d\n", txq->q.id);
-	} else
-		IWL_DEBUG_TX_QUEUES(trans, "hwq %d already stopped\n",
-				    txq->q.id);
-}
-
-static inline int iwl_queue_used(const struct iwl_queue *q, int i)
-{
-	return q->write_ptr >= q->read_ptr ?
-		(i >= q->read_ptr && i < q->write_ptr) :
-		!(i < q->read_ptr && i >= q->write_ptr);
-}
-
-static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
-{
-	return index & (q->n_window - 1);
-}
-
-static inline const char *
-trans_pcie_get_cmd_string(struct iwl_trans_pcie *trans_pcie, u8 cmd)
-{
-	if (!trans_pcie->command_names || !trans_pcie->command_names[cmd])
-		return "UNKNOWN";
-	return trans_pcie->command_names[cmd];
-}
-
-static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
-{
-	return !(iwl_read32(trans, CSR_GP_CNTRL) &
-		CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
-}
-
-#endif /* __iwl_trans_int_pcie_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
deleted file mode 100644
index 08517d3..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
+++ /dev/null
@@ -1,1069 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/gfp.h>
-
-#include "iwl-prph.h"
-#include "iwl-io.h"
-#include "iwl-trans-pcie-int.h"
-#include "iwl-op-mode.h"
-
-#ifdef CONFIG_IWLWIFI_IDI
-#include "iwl-amfh.h"
-#endif
-
-/******************************************************************************
- *
- * RX path functions
- *
- ******************************************************************************/
-
-/*
- * Rx theory of operation
- *
- * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
- * each of which point to Receive Buffers to be filled by the NIC.  These get
- * used not only for Rx frames, but for any command response or notification
- * from the NIC.  The driver and NIC manage the Rx buffers by means
- * of indexes into the circular buffer.
- *
- * Rx Queue Indexes
- * The host/firmware share two index registers for managing the Rx buffers.
- *
- * The READ index maps to the first position that the firmware may be writing
- * to -- the driver can read up to (but not including) this position and get
- * good data.
- * The READ index is managed by the firmware once the card is enabled.
- *
- * The WRITE index maps to the last position the driver has read from -- the
- * position preceding WRITE is the last slot the firmware can place a packet.
- *
- * The queue is empty (no good data) if WRITE = READ - 1, and is full if
- * WRITE = READ.
- *
- * During initialization, the host sets up the READ queue position to the first
- * INDEX position, and WRITE to the last (READ - 1 wrapped)
- *
- * When the firmware places a packet in a buffer, it will advance the READ index
- * and fire the RX interrupt.  The driver can then query the READ index and
- * process as many packets as possible, moving the WRITE index forward as it
- * resets the Rx queue buffers with new memory.
- *
- * The management in the driver is as follows:
- * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
- *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- *   to replenish the iwl->rxq->rx_free.
- * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
- *   iwl->rxq is replenished and the READ INDEX is updated (updating the
- *   'processed' and 'read' driver indexes as well)
- * + A received packet is processed and handed to the kernel network stack,
- *   detached from the iwl->rxq.  The driver 'processed' index is updated.
- * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
- *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
- *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
- *   were enough free buffers and RX_STALLED is set it is cleared.
- *
- *
- * Driver sequence:
- *
- * iwl_rx_queue_alloc()   Allocates rx_free
- * iwl_rx_replenish()     Replenishes rx_free list from rx_used, and calls
- *                            iwl_rx_queue_restock
- * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
- *                            queue, updates firmware pointers, and updates
- *                            the WRITE index.  If insufficient rx_free buffers
- *                            are available, schedules iwl_rx_replenish
- *
- * -- enable interrupts --
- * ISR - iwl_rx()         Detach iwl_rx_mem_buffers from pool up to the
- *                            READ INDEX, detaching the SKB from the pool.
- *                            Moves the packet buffer from queue to rx_used.
- *                            Calls iwl_rx_queue_restock to refill any empty
- *                            slots.
- * ...
- *
- */
-
-/**
- * iwl_rx_queue_space - Return number of free slots available in queue.
- */
-static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
-{
-	int s = q->read - q->write;
-	if (s <= 0)
-		s += RX_QUEUE_SIZE;
-	/* keep some buffer to not confuse full and empty queue */
-	s -= 2;
-	if (s < 0)
-		s = 0;
-	return s;
-}
-
-/**
- * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
- */
-void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
-			struct iwl_rx_queue *q)
-{
-	unsigned long flags;
-	u32 reg;
-
-	spin_lock_irqsave(&q->lock, flags);
-
-	if (q->need_update == 0)
-		goto exit_unlock;
-
-	if (trans->cfg->base_params->shadow_reg_enable) {
-		/* shadow register enabled */
-		/* Device expects a multiple of 8 */
-		q->write_actual = (q->write & ~0x7);
-		iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, q->write_actual);
-	} else {
-		struct iwl_trans_pcie *trans_pcie =
-			IWL_TRANS_GET_PCIE_TRANS(trans);
-
-		/* If power-saving is in use, make sure device is awake */
-		if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
-			reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
-
-			if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-				IWL_DEBUG_INFO(trans,
-					"Rx queue requesting wakeup,"
-					" GP1 = 0x%x\n", reg);
-				iwl_set_bit(trans, CSR_GP_CNTRL,
-					CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-				goto exit_unlock;
-			}
-
-			q->write_actual = (q->write & ~0x7);
-			iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
-					q->write_actual);
-
-		/* Else device is assumed to be awake */
-		} else {
-			/* Device expects a multiple of 8 */
-			q->write_actual = (q->write & ~0x7);
-			iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
-				q->write_actual);
-		}
-	}
-	q->need_update = 0;
-
- exit_unlock:
-	spin_unlock_irqrestore(&q->lock, flags);
-}
-
-/**
- * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
- */
-static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr)
-{
-	return cpu_to_le32((u32)(dma_addr >> 8));
-}
-
-/**
- * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool
- *
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can, pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
- */
-static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-	struct list_head *element;
-	struct iwl_rx_mem_buffer *rxb;
-	unsigned long flags;
-
-	spin_lock_irqsave(&rxq->lock, flags);
-	while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
-		/* The overwritten rxb must be a used one */
-		rxb = rxq->queue[rxq->write];
-		BUG_ON(rxb && rxb->page);
-
-		/* Get next free Rx buffer, remove from free list */
-		element = rxq->rx_free.next;
-		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-		list_del(element);
-
-		/* Point to Rx buffer via next RBD in circular buffer */
-		rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma);
-		rxq->queue[rxq->write] = rxb;
-		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
-		rxq->free_count--;
-	}
-	spin_unlock_irqrestore(&rxq->lock, flags);
-	/* If the pre-allocated buffer pool is dropping low, schedule to
-	 * refill it */
-	if (rxq->free_count <= RX_LOW_WATERMARK)
-		schedule_work(&trans_pcie->rx_replenish);
-
-
-	/* If we've added more space for the firmware to place data, tell it.
-	 * Increment device's write pointer in multiples of 8. */
-	if (rxq->write_actual != (rxq->write & ~0x7)) {
-		spin_lock_irqsave(&rxq->lock, flags);
-		rxq->need_update = 1;
-		spin_unlock_irqrestore(&rxq->lock, flags);
-		iwl_rx_queue_update_write_ptr(trans, rxq);
-	}
-}
-
-/**
- * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free
- *
- * When moving to rx_free an SKB is allocated for the slot.
- *
- * Also restock the Rx queue via iwl_rx_queue_restock.
- * This is called as a scheduled work item (except for during initialization)
- */
-static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-	struct list_head *element;
-	struct iwl_rx_mem_buffer *rxb;
-	struct page *page;
-	unsigned long flags;
-	gfp_t gfp_mask = priority;
-
-	while (1) {
-		spin_lock_irqsave(&rxq->lock, flags);
-		if (list_empty(&rxq->rx_used)) {
-			spin_unlock_irqrestore(&rxq->lock, flags);
-			return;
-		}
-		spin_unlock_irqrestore(&rxq->lock, flags);
-
-		if (rxq->free_count > RX_LOW_WATERMARK)
-			gfp_mask |= __GFP_NOWARN;
-
-		if (trans_pcie->rx_page_order > 0)
-			gfp_mask |= __GFP_COMP;
-
-		/* Alloc a new receive buffer */
-		page = alloc_pages(gfp_mask,
-				  trans_pcie->rx_page_order);
-		if (!page) {
-			if (net_ratelimit())
-				IWL_DEBUG_INFO(trans, "alloc_pages failed, "
-					   "order: %d\n",
-					   trans_pcie->rx_page_order);
-
-			if ((rxq->free_count <= RX_LOW_WATERMARK) &&
-			    net_ratelimit())
-				IWL_CRIT(trans, "Failed to alloc_pages with %s."
-					 "Only %u free buffers remaining.\n",
-					 priority == GFP_ATOMIC ?
-					 "GFP_ATOMIC" : "GFP_KERNEL",
-					 rxq->free_count);
-			/* We don't reschedule replenish work here -- we will
-			 * call the restock method and if it still needs
-			 * more buffers it will schedule replenish */
-			return;
-		}
-
-		spin_lock_irqsave(&rxq->lock, flags);
-
-		if (list_empty(&rxq->rx_used)) {
-			spin_unlock_irqrestore(&rxq->lock, flags);
-			__free_pages(page, trans_pcie->rx_page_order);
-			return;
-		}
-		element = rxq->rx_used.next;
-		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-		list_del(element);
-
-		spin_unlock_irqrestore(&rxq->lock, flags);
-
-		BUG_ON(rxb->page);
-		rxb->page = page;
-		/* Get physical address of the RB */
-		rxb->page_dma = dma_map_page(trans->dev, page, 0,
-				PAGE_SIZE << trans_pcie->rx_page_order,
-				DMA_FROM_DEVICE);
-		/* dma address must be no more than 36 bits */
-		BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-		/* and also 256 byte aligned! */
-		BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
-
-		spin_lock_irqsave(&rxq->lock, flags);
-
-		list_add_tail(&rxb->list, &rxq->rx_free);
-		rxq->free_count++;
-
-		spin_unlock_irqrestore(&rxq->lock, flags);
-	}
-}
-
-void iwlagn_rx_replenish(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	unsigned long flags;
-
-	iwlagn_rx_allocate(trans, GFP_KERNEL);
-
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-	iwlagn_rx_queue_restock(trans);
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-}
-
-static void iwlagn_rx_replenish_now(struct iwl_trans *trans)
-{
-	iwlagn_rx_allocate(trans, GFP_ATOMIC);
-
-	iwlagn_rx_queue_restock(trans);
-}
-
-void iwl_bg_rx_replenish(struct work_struct *data)
-{
-	struct iwl_trans_pcie *trans_pcie =
-	    container_of(data, struct iwl_trans_pcie, rx_replenish);
-
-	iwlagn_rx_replenish(trans_pcie->trans);
-}
-
-static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
-				struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-	struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
-	unsigned long flags;
-	bool page_stolen = false;
-	int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
-	u32 offset = 0;
-
-	if (WARN_ON(!rxb))
-		return;
-
-	dma_unmap_page(trans->dev, rxb->page_dma, max_len, DMA_FROM_DEVICE);
-
-	while (offset + sizeof(u32) + sizeof(struct iwl_cmd_header) < max_len) {
-		struct iwl_rx_packet *pkt;
-		struct iwl_device_cmd *cmd;
-		u16 sequence;
-		bool reclaim;
-		int index, cmd_index, err, len;
-		struct iwl_rx_cmd_buffer rxcb = {
-			._offset = offset,
-			._page = rxb->page,
-			._page_stolen = false,
-			.truesize = max_len,
-		};
-
-		pkt = rxb_addr(&rxcb);
-
-		if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID))
-			break;
-
-		IWL_DEBUG_RX(trans, "cmd at offset %d: %s (0x%.2x)\n",
-			rxcb._offset,
-			trans_pcie_get_cmd_string(trans_pcie, pkt->hdr.cmd),
-			pkt->hdr.cmd);
-
-		len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-		len += sizeof(u32); /* account for status word */
-		trace_iwlwifi_dev_rx(trans->dev, pkt, len);
-
-		/* Reclaim a command buffer only if this packet is a response
-		 *   to a (driver-originated) command.
-		 * If the packet (e.g. Rx frame) originated from uCode,
-		 *   there is no command buffer to reclaim.
-		 * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
-		 *   but apparently a few don't get set; catch them here. */
-		reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME);
-		if (reclaim) {
-			int i;
-
-			for (i = 0; i < trans_pcie->n_no_reclaim_cmds; i++) {
-				if (trans_pcie->no_reclaim_cmds[i] ==
-							pkt->hdr.cmd) {
-					reclaim = false;
-					break;
-				}
-			}
-		}
-
-		sequence = le16_to_cpu(pkt->hdr.sequence);
-		index = SEQ_TO_INDEX(sequence);
-		cmd_index = get_cmd_index(&txq->q, index);
-
-		if (reclaim)
-			cmd = txq->entries[cmd_index].cmd;
-		else
-			cmd = NULL;
-
-		err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
-
-		/*
-		 * After here, we should always check rxcb._page_stolen,
-		 * if it is true then one of the handlers took the page.
-		 */
-
-		if (reclaim) {
-			/* Invoke any callbacks, transfer the buffer to caller,
-			 * and fire off the (possibly) blocking
-			 * iwl_trans_send_cmd()
-			 * as we reclaim the driver command queue */
-			if (!rxcb._page_stolen)
-				iwl_tx_cmd_complete(trans, &rxcb, err);
-			else
-				IWL_WARN(trans, "Claim null rxb?\n");
-		}
-
-		page_stolen |= rxcb._page_stolen;
-		offset += ALIGN(len, FH_RSCSR_FRAME_ALIGN);
-	}
-
-	/* page was stolen from us -- free our reference */
-	if (page_stolen) {
-		__free_pages(rxb->page, trans_pcie->rx_page_order);
-		rxb->page = NULL;
-	}
-
-	/* Reuse the page if possible. For notification packets and
-	 * SKBs that fail to Rx correctly, add them back into the
-	 * rx_free list for reuse later. */
-	spin_lock_irqsave(&rxq->lock, flags);
-	if (rxb->page != NULL) {
-		rxb->page_dma =
-			dma_map_page(trans->dev, rxb->page, 0,
-				PAGE_SIZE << trans_pcie->rx_page_order,
-				DMA_FROM_DEVICE);
-		list_add_tail(&rxb->list, &rxq->rx_free);
-		rxq->free_count++;
-	} else
-		list_add_tail(&rxb->list, &rxq->rx_used);
-	spin_unlock_irqrestore(&rxq->lock, flags);
-}
-
-/**
- * iwl_rx_handle - Main entry function for receiving responses from uCode
- *
- * Uses the priv->rx_handlers callback function array to invoke
- * the appropriate handlers, including command responses,
- * frame-received notifications, and other notifications.
- */
-static void iwl_rx_handle(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-	u32 r, i;
-	u8 fill_rx = 0;
-	u32 count = 8;
-	int total_empty;
-
-	/* uCode's read index (stored in shared DRAM) indicates the last Rx
-	 * buffer that the driver may process (last buffer filled by ucode). */
-	r = le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF;
-	i = rxq->read;
-
-	/* Rx interrupt, but nothing sent from uCode */
-	if (i == r)
-		IWL_DEBUG_RX(trans, "r = %d, i = %d\n", r, i);
-
-	/* calculate total frames need to be restock after handling RX */
-	total_empty = r - rxq->write_actual;
-	if (total_empty < 0)
-		total_empty += RX_QUEUE_SIZE;
-
-	if (total_empty > (RX_QUEUE_SIZE / 2))
-		fill_rx = 1;
-
-	while (i != r) {
-		struct iwl_rx_mem_buffer *rxb;
-
-		rxb = rxq->queue[i];
-		rxq->queue[i] = NULL;
-
-		IWL_DEBUG_RX(trans, "rxbuf: r = %d, i = %d (%p)\n", rxb);
-
-		iwl_rx_handle_rxbuf(trans, rxb);
-
-		i = (i + 1) & RX_QUEUE_MASK;
-		/* If there are a lot of unused frames,
-		 * restock the Rx queue so ucode wont assert. */
-		if (fill_rx) {
-			count++;
-			if (count >= 8) {
-				rxq->read = i;
-				iwlagn_rx_replenish_now(trans);
-				count = 0;
-			}
-		}
-	}
-
-	/* Backtrack one entry */
-	rxq->read = i;
-	if (fill_rx)
-		iwlagn_rx_replenish_now(trans);
-	else
-		iwlagn_rx_queue_restock(trans);
-}
-
-/**
- * iwl_irq_handle_error - called for HW or SW error interrupt from card
- */
-static void iwl_irq_handle_error(struct iwl_trans *trans)
-{
-	/* W/A for WiFi/WiMAX coex and WiMAX own the RF */
-	if (trans->cfg->internal_wimax_coex &&
-	    (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
-			APMS_CLK_VAL_MRB_FUNC_MODE) ||
-	     (iwl_read_prph(trans, APMG_PS_CTRL_REG) &
-			APMG_PS_CTRL_VAL_RESET_REQ))) {
-		struct iwl_trans_pcie *trans_pcie;
-
-		trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-		clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-		iwl_op_mode_wimax_active(trans->op_mode);
-		wake_up(&trans->wait_command_queue);
-		return;
-	}
-
-	iwl_dump_csr(trans);
-	iwl_dump_fh(trans, NULL, false);
-
-	iwl_op_mode_nic_error(trans->op_mode);
-}
-
-/* tasklet for iwlagn interrupt */
-void iwl_irq_tasklet(struct iwl_trans *trans)
-{
-	u32 inta = 0;
-	u32 handled = 0;
-	unsigned long flags;
-	u32 i;
-#ifdef CONFIG_IWLWIFI_DEBUG
-	u32 inta_mask;
-#endif
-
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
-
-
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-	/* Ack/clear/reset pending uCode interrupts.
-	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
-	 */
-	/* There is a hardware bug in the interrupt mask function that some
-	 * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if
-	 * they are disabled in the CSR_INT_MASK register. Furthermore the
-	 * ICT interrupt handling mechanism has another bug that might cause
-	 * these unmasked interrupts fail to be detected. We workaround the
-	 * hardware bugs here by ACKing all the possible interrupts so that
-	 * interrupt coalescing can still be achieved.
-	 */
-	iwl_write32(trans, CSR_INT,
-		trans_pcie->inta | ~trans_pcie->inta_mask);
-
-	inta = trans_pcie->inta;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_have_debug_level(IWL_DL_ISR)) {
-		/* just for debug */
-		inta_mask = iwl_read32(trans, CSR_INT_MASK);
-		IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n",
-				inta, inta_mask);
-	}
-#endif
-
-	/* saved interrupt in inta variable now we can reset trans_pcie->inta */
-	trans_pcie->inta = 0;
-
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-	/* Now service all interrupt bits discovered above. */
-	if (inta & CSR_INT_BIT_HW_ERR) {
-		IWL_ERR(trans, "Hardware error detected.  Restarting.\n");
-
-		/* Tell the device to stop sending interrupts */
-		iwl_disable_interrupts(trans);
-
-		isr_stats->hw++;
-		iwl_irq_handle_error(trans);
-
-		handled |= CSR_INT_BIT_HW_ERR;
-
-		return;
-	}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_have_debug_level(IWL_DL_ISR)) {
-		/* NIC fires this, but we don't use it, redundant with WAKEUP */
-		if (inta & CSR_INT_BIT_SCD) {
-			IWL_DEBUG_ISR(trans, "Scheduler finished to transmit "
-				      "the frame/frames.\n");
-			isr_stats->sch++;
-		}
-
-		/* Alive notification via Rx interrupt will do the real work */
-		if (inta & CSR_INT_BIT_ALIVE) {
-			IWL_DEBUG_ISR(trans, "Alive interrupt\n");
-			isr_stats->alive++;
-		}
-	}
-#endif
-	/* Safely ignore these bits for debug checks below */
-	inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
-
-	/* HW RF KILL switch toggled */
-	if (inta & CSR_INT_BIT_RF_KILL) {
-		bool hw_rfkill;
-
-		hw_rfkill = iwl_is_rfkill_set(trans);
-		IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
-				hw_rfkill ? "disable radio" : "enable radio");
-
-		isr_stats->rfkill++;
-
-		iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-
-		handled |= CSR_INT_BIT_RF_KILL;
-	}
-
-	/* Chip got too hot and stopped itself */
-	if (inta & CSR_INT_BIT_CT_KILL) {
-		IWL_ERR(trans, "Microcode CT kill error detected.\n");
-		isr_stats->ctkill++;
-		handled |= CSR_INT_BIT_CT_KILL;
-	}
-
-	/* Error detected by uCode */
-	if (inta & CSR_INT_BIT_SW_ERR) {
-		IWL_ERR(trans, "Microcode SW error detected. "
-			" Restarting 0x%X.\n", inta);
-		isr_stats->sw++;
-		iwl_irq_handle_error(trans);
-		handled |= CSR_INT_BIT_SW_ERR;
-	}
-
-	/* uCode wakes up after power-down sleep */
-	if (inta & CSR_INT_BIT_WAKEUP) {
-		IWL_DEBUG_ISR(trans, "Wakeup interrupt\n");
-		iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq);
-		for (i = 0; i < trans->cfg->base_params->num_of_queues; i++)
-			iwl_txq_update_write_ptr(trans,
-						 &trans_pcie->txq[i]);
-
-		isr_stats->wakeup++;
-
-		handled |= CSR_INT_BIT_WAKEUP;
-	}
-
-	/* All uCode command responses, including Tx command responses,
-	 * Rx "responses" (frame-received notification), and other
-	 * notifications from uCode come through here*/
-	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX |
-			CSR_INT_BIT_RX_PERIODIC)) {
-		IWL_DEBUG_ISR(trans, "Rx interrupt\n");
-		if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
-			handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
-			iwl_write32(trans, CSR_FH_INT_STATUS,
-					CSR_FH_INT_RX_MASK);
-		}
-		if (inta & CSR_INT_BIT_RX_PERIODIC) {
-			handled |= CSR_INT_BIT_RX_PERIODIC;
-			iwl_write32(trans,
-				CSR_INT, CSR_INT_BIT_RX_PERIODIC);
-		}
-		/* Sending RX interrupt require many steps to be done in the
-		 * the device:
-		 * 1- write interrupt to current index in ICT table.
-		 * 2- dma RX frame.
-		 * 3- update RX shared data to indicate last write index.
-		 * 4- send interrupt.
-		 * This could lead to RX race, driver could receive RX interrupt
-		 * but the shared data changes does not reflect this;
-		 * periodic interrupt will detect any dangling Rx activity.
-		 */
-
-		/* Disable periodic interrupt; we use it as just a one-shot. */
-		iwl_write8(trans, CSR_INT_PERIODIC_REG,
-			    CSR_INT_PERIODIC_DIS);
-#ifdef CONFIG_IWLWIFI_IDI
-		iwl_amfh_rx_handler();
-#else
-		iwl_rx_handle(trans);
-#endif
-		/*
-		 * Enable periodic interrupt in 8 msec only if we received
-		 * real RX interrupt (instead of just periodic int), to catch
-		 * any dangling Rx interrupt.  If it was just the periodic
-		 * interrupt, there was no dangling Rx activity, and no need
-		 * to extend the periodic interrupt; one-shot is enough.
-		 */
-		if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
-			iwl_write8(trans, CSR_INT_PERIODIC_REG,
-				    CSR_INT_PERIODIC_ENA);
-
-		isr_stats->rx++;
-	}
-
-	/* This "Tx" DMA channel is used only for loading uCode */
-	if (inta & CSR_INT_BIT_FH_TX) {
-		iwl_write32(trans, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK);
-		IWL_DEBUG_ISR(trans, "uCode load interrupt\n");
-		isr_stats->tx++;
-		handled |= CSR_INT_BIT_FH_TX;
-		/* Wake up uCode load routine, now that load is complete */
-		trans_pcie->ucode_write_complete = true;
-		wake_up(&trans_pcie->ucode_write_waitq);
-	}
-
-	if (inta & ~handled) {
-		IWL_ERR(trans, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
-		isr_stats->unhandled++;
-	}
-
-	if (inta & ~(trans_pcie->inta_mask)) {
-		IWL_WARN(trans, "Disabled INTA bits 0x%08x were pending\n",
-			 inta & ~trans_pcie->inta_mask);
-	}
-
-	/* Re-enable all interrupts */
-	/* only Re-enable if disabled by irq */
-	if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status))
-		iwl_enable_interrupts(trans);
-	/* Re-enable RF_KILL if it occurred */
-	else if (handled & CSR_INT_BIT_RF_KILL)
-		iwl_enable_rfkill_int(trans);
-}
-
-/******************************************************************************
- *
- * ICT functions
- *
- ******************************************************************************/
-
-/* a device (PCI-E) page is 4096 bytes long */
-#define ICT_SHIFT	12
-#define ICT_SIZE	(1 << ICT_SHIFT)
-#define ICT_COUNT	(ICT_SIZE / sizeof(u32))
-
-/* Free dram table */
-void iwl_free_isr_ict(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	if (trans_pcie->ict_tbl) {
-		dma_free_coherent(trans->dev, ICT_SIZE,
-				  trans_pcie->ict_tbl,
-				  trans_pcie->ict_tbl_dma);
-		trans_pcie->ict_tbl = NULL;
-		trans_pcie->ict_tbl_dma = 0;
-	}
-}
-
-
-/*
- * allocate dram shared table, it is an aligned memory
- * block of ICT_SIZE.
- * also reset all data related to ICT table interrupt.
- */
-int iwl_alloc_isr_ict(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	trans_pcie->ict_tbl =
-		dma_alloc_coherent(trans->dev, ICT_SIZE,
-				   &trans_pcie->ict_tbl_dma,
-				   GFP_KERNEL);
-	if (!trans_pcie->ict_tbl)
-		return -ENOMEM;
-
-	/* just an API sanity check ... it is guaranteed to be aligned */
-	if (WARN_ON(trans_pcie->ict_tbl_dma & (ICT_SIZE - 1))) {
-		iwl_free_isr_ict(trans);
-		return -EINVAL;
-	}
-
-	IWL_DEBUG_ISR(trans, "ict dma addr %Lx\n",
-		      (unsigned long long)trans_pcie->ict_tbl_dma);
-
-	IWL_DEBUG_ISR(trans, "ict vir addr %p\n", trans_pcie->ict_tbl);
-
-	/* reset table and index to all 0 */
-	memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
-	trans_pcie->ict_index = 0;
-
-	/* add periodic RX interrupt */
-	trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
-	return 0;
-}
-
-/* Device is going up inform it about using ICT interrupt table,
- * also we need to tell the driver to start using ICT interrupt.
- */
-void iwl_reset_ict(struct iwl_trans *trans)
-{
-	u32 val;
-	unsigned long flags;
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	if (!trans_pcie->ict_tbl)
-		return;
-
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-	iwl_disable_interrupts(trans);
-
-	memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
-
-	val = trans_pcie->ict_tbl_dma >> ICT_SHIFT;
-
-	val |= CSR_DRAM_INT_TBL_ENABLE;
-	val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
-
-	IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val);
-
-	iwl_write32(trans, CSR_DRAM_INT_TBL_REG, val);
-	trans_pcie->use_ict = true;
-	trans_pcie->ict_index = 0;
-	iwl_write32(trans, CSR_INT, trans_pcie->inta_mask);
-	iwl_enable_interrupts(trans);
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-}
-
-/* Device is going down disable ict interrupt usage */
-void iwl_disable_ict(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	unsigned long flags;
-
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-	trans_pcie->use_ict = false;
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-}
-
-static irqreturn_t iwl_isr(int irq, void *data)
-{
-	struct iwl_trans *trans = data;
-	struct iwl_trans_pcie *trans_pcie;
-	u32 inta, inta_mask;
-	unsigned long flags;
-#ifdef CONFIG_IWLWIFI_DEBUG
-	u32 inta_fh;
-#endif
-	if (!trans)
-		return IRQ_NONE;
-
-	trace_iwlwifi_dev_irq(trans->dev);
-
-	trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-	/* Disable (but don't clear!) interrupts here to avoid
-	 *    back-to-back ISRs and sporadic interrupts from our NIC.
-	 * If we have something to service, the tasklet will re-enable ints.
-	 * If we *don't* have something, we'll re-enable before leaving here. */
-	inta_mask = iwl_read32(trans, CSR_INT_MASK);  /* just for debug */
-	iwl_write32(trans, CSR_INT_MASK, 0x00000000);
-
-	/* Discover which interrupts are active/pending */
-	inta = iwl_read32(trans, CSR_INT);
-
-	/* Ignore interrupt if there's nothing in NIC to service.
-	 * This may be due to IRQ shared with another device,
-	 * or due to sporadic interrupts thrown from our NIC. */
-	if (!inta) {
-		IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
-		goto none;
-	}
-
-	if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
-		/* Hardware disappeared. It might have already raised
-		 * an interrupt */
-		IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
-		goto unplugged;
-	}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_have_debug_level(IWL_DL_ISR)) {
-		inta_fh = iwl_read32(trans, CSR_FH_INT_STATUS);
-		IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x, "
-			      "fh 0x%08x\n", inta, inta_mask, inta_fh);
-	}
-#endif
-
-	trans_pcie->inta |= inta;
-	/* iwl_irq_tasklet() will service interrupts and re-enable them */
-	if (likely(inta))
-		tasklet_schedule(&trans_pcie->irq_tasklet);
-	else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
-			!trans_pcie->inta)
-		iwl_enable_interrupts(trans);
-
- unplugged:
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-	return IRQ_HANDLED;
-
- none:
-	/* re-enable interrupts here since we don't have anything to service. */
-	/* only Re-enable if disabled by irq  and no schedules tasklet. */
-	if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
-		!trans_pcie->inta)
-		iwl_enable_interrupts(trans);
-
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-	return IRQ_NONE;
-}
-
-/* interrupt handler using ict table, with this interrupt driver will
- * stop using INTA register to get device's interrupt, reading this register
- * is expensive, device will write interrupts in ICT dram table, increment
- * index then will fire interrupt to driver, driver will OR all ICT table
- * entries from current index up to table entry with 0 value. the result is
- * the interrupt we need to service, driver will set the entries back to 0 and
- * set index.
- */
-irqreturn_t iwl_isr_ict(int irq, void *data)
-{
-	struct iwl_trans *trans = data;
-	struct iwl_trans_pcie *trans_pcie;
-	u32 inta, inta_mask;
-	u32 val = 0;
-	u32 read;
-	unsigned long flags;
-
-	if (!trans)
-		return IRQ_NONE;
-
-	trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	/* dram interrupt table not set yet,
-	 * use legacy interrupt.
-	 */
-	if (!trans_pcie->use_ict)
-		return iwl_isr(irq, data);
-
-	trace_iwlwifi_dev_irq(trans->dev);
-
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-	/* Disable (but don't clear!) interrupts here to avoid
-	 * back-to-back ISRs and sporadic interrupts from our NIC.
-	 * If we have something to service, the tasklet will re-enable ints.
-	 * If we *don't* have something, we'll re-enable before leaving here.
-	 */
-	inta_mask = iwl_read32(trans, CSR_INT_MASK);  /* just for debug */
-	iwl_write32(trans, CSR_INT_MASK, 0x00000000);
-
-
-	/* Ignore interrupt if there's nothing in NIC to service.
-	 * This may be due to IRQ shared with another device,
-	 * or due to sporadic interrupts thrown from our NIC. */
-	read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
-	trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, read);
-	if (!read) {
-		IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
-		goto none;
-	}
-
-	/*
-	 * Collect all entries up to the first 0, starting from ict_index;
-	 * note we already read at ict_index.
-	 */
-	do {
-		val |= read;
-		IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n",
-				trans_pcie->ict_index, read);
-		trans_pcie->ict_tbl[trans_pcie->ict_index] = 0;
-		trans_pcie->ict_index =
-			iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT);
-
-		read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
-		trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index,
-					   read);
-	} while (read);
-
-	/* We should not get this value, just ignore it. */
-	if (val == 0xffffffff)
-		val = 0;
-
-	/*
-	 * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
-	 * (bit 15 before shifting it to 31) to clear when using interrupt
-	 * coalescing. fortunately, bits 18 and 19 stay set when this happens
-	 * so we use them to decide on the real state of the Rx bit.
-	 * In order words, bit 15 is set if bit 18 or bit 19 are set.
-	 */
-	if (val & 0xC0000)
-		val |= 0x8000;
-
-	inta = (0xff & val) | ((0xff00 & val) << 16);
-	IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
-			inta, inta_mask, val);
-
-	inta &= trans_pcie->inta_mask;
-	trans_pcie->inta |= inta;
-
-	/* iwl_irq_tasklet() will service interrupts and re-enable them */
-	if (likely(inta))
-		tasklet_schedule(&trans_pcie->irq_tasklet);
-	else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
-		 !trans_pcie->inta) {
-		/* Allow interrupt if was disabled by this handler and
-		 * no tasklet was schedules, We should not enable interrupt,
-		 * tasklet will enable it.
-		 */
-		iwl_enable_interrupts(trans);
-	}
-
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-	return IRQ_HANDLED;
-
- none:
-	/* re-enable interrupts here since we don't have anything to service.
-	 * only Re-enable if disabled by irq.
-	 */
-	if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
-	    !trans_pcie->inta)
-		iwl_enable_interrupts(trans);
-
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-	return IRQ_NONE;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
deleted file mode 100644
index a875023..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
+++ /dev/null
@@ -1,989 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-
-#include "iwl-debug.h"
-#include "iwl-csr.h"
-#include "iwl-prph.h"
-#include "iwl-io.h"
-#include "iwl-agn-hw.h"
-#include "iwl-op-mode.h"
-#include "iwl-trans-pcie-int.h"
-/* FIXME: need to abstract out TX command (once we know what it looks like) */
-#include "iwl-commands.h"
-
-#define IWL_TX_CRC_SIZE 4
-#define IWL_TX_DELIMITER_SIZE 4
-
-/**
- * iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
- */
-void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
-					   struct iwl_tx_queue *txq,
-					   u16 byte_cnt)
-{
-	struct iwlagn_scd_bc_tbl *scd_bc_tbl;
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-	int write_ptr = txq->q.write_ptr;
-	int txq_id = txq->q.id;
-	u8 sec_ctl = 0;
-	u8 sta_id = 0;
-	u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
-	__le16 bc_ent;
-	struct iwl_tx_cmd *tx_cmd =
-		(void *) txq->entries[txq->q.write_ptr].cmd->payload;
-
-	scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
-
-	WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
-
-	sta_id = tx_cmd->sta_id;
-	sec_ctl = tx_cmd->sec_ctl;
-
-	switch (sec_ctl & TX_CMD_SEC_MSK) {
-	case TX_CMD_SEC_CCM:
-		len += CCMP_MIC_LEN;
-		break;
-	case TX_CMD_SEC_TKIP:
-		len += TKIP_ICV_LEN;
-		break;
-	case TX_CMD_SEC_WEP:
-		len += WEP_IV_LEN + WEP_ICV_LEN;
-		break;
-	}
-
-	bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
-
-	scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
-
-	if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
-		scd_bc_tbl[txq_id].
-			tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
-}
-
-/**
- * iwl_txq_update_write_ptr - Send new write index to hardware
- */
-void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq)
-{
-	u32 reg = 0;
-	int txq_id = txq->q.id;
-
-	if (txq->need_update == 0)
-		return;
-
-	if (trans->cfg->base_params->shadow_reg_enable) {
-		/* shadow register enabled */
-		iwl_write32(trans, HBUS_TARG_WRPTR,
-			    txq->q.write_ptr | (txq_id << 8));
-	} else {
-		struct iwl_trans_pcie *trans_pcie =
-			IWL_TRANS_GET_PCIE_TRANS(trans);
-		/* if we're trying to save power */
-		if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
-			/* wake up nic if it's powered down ...
-			 * uCode will wake up, and interrupt us again, so next
-			 * time we'll skip this part. */
-			reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
-
-			if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-				IWL_DEBUG_INFO(trans,
-					"Tx queue %d requesting wakeup,"
-					" GP1 = 0x%x\n", txq_id, reg);
-				iwl_set_bit(trans, CSR_GP_CNTRL,
-					CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-				return;
-			}
-
-			iwl_write_direct32(trans, HBUS_TARG_WRPTR,
-				     txq->q.write_ptr | (txq_id << 8));
-
-		/*
-		 * else not in power-save mode,
-		 * uCode will never sleep when we're
-		 * trying to tx (during RFKILL, we're not trying to tx).
-		 */
-		} else
-			iwl_write32(trans, HBUS_TARG_WRPTR,
-				    txq->q.write_ptr | (txq_id << 8));
-	}
-	txq->need_update = 0;
-}
-
-static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
-{
-	struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-
-	dma_addr_t addr = get_unaligned_le32(&tb->lo);
-	if (sizeof(dma_addr_t) > sizeof(u32))
-		addr |=
-		((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
-
-	return addr;
-}
-
-static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
-{
-	struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-
-	return le16_to_cpu(tb->hi_n_len) >> 4;
-}
-
-static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
-				  dma_addr_t addr, u16 len)
-{
-	struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-	u16 hi_n_len = len << 4;
-
-	put_unaligned_le32(addr, &tb->lo);
-	if (sizeof(dma_addr_t) > sizeof(u32))
-		hi_n_len |= ((addr >> 16) >> 16) & 0xF;
-
-	tb->hi_n_len = cpu_to_le16(hi_n_len);
-
-	tfd->num_tbs = idx + 1;
-}
-
-static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
-{
-	return tfd->num_tbs & 0x1f;
-}
-
-static void iwlagn_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
-		     struct iwl_tfd *tfd, enum dma_data_direction dma_dir)
-{
-	int i;
-	int num_tbs;
-
-	/* Sanity check on number of chunks */
-	num_tbs = iwl_tfd_get_num_tbs(tfd);
-
-	if (num_tbs >= IWL_NUM_OF_TBS) {
-		IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);
-		/* @todo issue fatal error, it is quite serious situation */
-		return;
-	}
-
-	/* Unmap tx_cmd */
-	if (num_tbs)
-		dma_unmap_single(trans->dev,
-				dma_unmap_addr(meta, mapping),
-				dma_unmap_len(meta, len),
-				DMA_BIDIRECTIONAL);
-
-	/* Unmap chunks, if any. */
-	for (i = 1; i < num_tbs; i++)
-		dma_unmap_single(trans->dev, iwl_tfd_tb_get_addr(tfd, i),
-				iwl_tfd_tb_get_len(tfd, i), dma_dir);
-
-	tfd->num_tbs = 0;
-}
-
-/**
- * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
- * @trans - transport private data
- * @txq - tx queue
- * @dma_dir - the direction of the DMA mapping
- *
- * Does NOT advance any TFD circular buffer read/write indexes
- * Does NOT free the TFD itself (which is within circular buffer)
- */
-void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-			 enum dma_data_direction dma_dir)
-{
-	struct iwl_tfd *tfd_tmp = txq->tfds;
-
-	/* rd_ptr is bounded by n_bd and idx is bounded by n_window */
-	int rd_ptr = txq->q.read_ptr;
-	int idx = get_cmd_index(&txq->q, rd_ptr);
-
-	lockdep_assert_held(&txq->lock);
-
-	/* We have only q->n_window txq->entries, but we use q->n_bd tfds */
-	iwlagn_unmap_tfd(trans, &txq->entries[idx].meta,
-			 &tfd_tmp[rd_ptr], dma_dir);
-
-	/* free SKB */
-	if (txq->entries) {
-		struct sk_buff *skb;
-
-		skb = txq->entries[idx].skb;
-
-		/* Can be called from irqs-disabled context
-		 * If skb is not NULL, it means that the whole queue is being
-		 * freed and that the queue is not empty - free the skb
-		 */
-		if (skb) {
-			iwl_op_mode_free_skb(trans->op_mode, skb);
-			txq->entries[idx].skb = NULL;
-		}
-	}
-}
-
-int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
-				 struct iwl_tx_queue *txq,
-				 dma_addr_t addr, u16 len,
-				 u8 reset)
-{
-	struct iwl_queue *q;
-	struct iwl_tfd *tfd, *tfd_tmp;
-	u32 num_tbs;
-
-	q = &txq->q;
-	tfd_tmp = txq->tfds;
-	tfd = &tfd_tmp[q->write_ptr];
-
-	if (reset)
-		memset(tfd, 0, sizeof(*tfd));
-
-	num_tbs = iwl_tfd_get_num_tbs(tfd);
-
-	/* Each TFD can point to a maximum 20 Tx buffers */
-	if (num_tbs >= IWL_NUM_OF_TBS) {
-		IWL_ERR(trans, "Error can not send more than %d chunks\n",
-			  IWL_NUM_OF_TBS);
-		return -EINVAL;
-	}
-
-	if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
-		return -EINVAL;
-
-	if (unlikely(addr & ~IWL_TX_DMA_MASK))
-		IWL_ERR(trans, "Unaligned address = %llx\n",
-			  (unsigned long long)addr);
-
-	iwl_tfd_set_tb(tfd, num_tbs, addr, len);
-
-	return 0;
-}
-
-/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
- * DMA services
- *
- * Theory of operation
- *
- * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
- * of buffer descriptors, each of which points to one or more data buffers for
- * the device to read from or fill.  Driver and device exchange status of each
- * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
- * entries in each circular buffer, to protect against confusing empty and full
- * queue states.
- *
- * The device reads or writes the data in the queues via the device's several
- * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
- *
- * For Tx queue, there are low mark and high mark limits. If, after queuing
- * the packet for Tx, free space become < low mark, Tx queue stopped. When
- * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
- * Tx queue resumed.
- *
- ***************************************************/
-
-int iwl_queue_space(const struct iwl_queue *q)
-{
-	int s = q->read_ptr - q->write_ptr;
-
-	if (q->read_ptr > q->write_ptr)
-		s -= q->n_bd;
-
-	if (s <= 0)
-		s += q->n_window;
-	/* keep some reserve to not confuse empty and full situations */
-	s -= 2;
-	if (s < 0)
-		s = 0;
-	return s;
-}
-
-/**
- * iwl_queue_init - Initialize queue's high/low-water and read/write indexes
- */
-int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id)
-{
-	q->n_bd = count;
-	q->n_window = slots_num;
-	q->id = id;
-
-	/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
-	 * and iwl_queue_dec_wrap are broken. */
-	if (WARN_ON(!is_power_of_2(count)))
-		return -EINVAL;
-
-	/* slots_num must be power-of-two size, otherwise
-	 * get_cmd_index is broken. */
-	if (WARN_ON(!is_power_of_2(slots_num)))
-		return -EINVAL;
-
-	q->low_mark = q->n_window / 4;
-	if (q->low_mark < 4)
-		q->low_mark = 4;
-
-	q->high_mark = q->n_window / 8;
-	if (q->high_mark < 2)
-		q->high_mark = 2;
-
-	q->write_ptr = q->read_ptr = 0;
-
-	return 0;
-}
-
-static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
-					  struct iwl_tx_queue *txq)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwlagn_scd_bc_tbl *scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
-	int txq_id = txq->q.id;
-	int read_ptr = txq->q.read_ptr;
-	u8 sta_id = 0;
-	__le16 bc_ent;
-	struct iwl_tx_cmd *tx_cmd =
-		(void *)txq->entries[txq->q.read_ptr].cmd->payload;
-
-	WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
-
-	if (txq_id != trans_pcie->cmd_queue)
-		sta_id = tx_cmd->sta_id;
-
-	bc_ent = cpu_to_le16(1 | (sta_id << 12));
-	scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
-
-	if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
-		scd_bc_tbl[txq_id].
-			tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
-}
-
-static int iwlagn_tx_queue_set_q2ratid(struct iwl_trans *trans, u16 ra_tid,
-					u16 txq_id)
-{
-	u32 tbl_dw_addr;
-	u32 tbl_dw;
-	u16 scd_q2ratid;
-
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
-
-	tbl_dw_addr = trans_pcie->scd_base_addr +
-			SCD_TRANS_TBL_OFFSET_QUEUE(txq_id);
-
-	tbl_dw = iwl_read_targ_mem(trans, tbl_dw_addr);
-
-	if (txq_id & 0x1)
-		tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
-	else
-		tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
-
-	iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw);
-
-	return 0;
-}
-
-static void iwlagn_tx_queue_stop_scheduler(struct iwl_trans *trans, u16 txq_id)
-{
-	/* Simply stop the queue, but don't change any configuration;
-	 * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
-	iwl_write_prph(trans,
-		SCD_QUEUE_STATUS_BITS(txq_id),
-		(0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
-		(1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
-}
-
-void iwl_trans_set_wr_ptrs(struct iwl_trans *trans,
-				int txq_id, u32 index)
-{
-	IWL_DEBUG_TX_QUEUES(trans, "Q %d  WrPtr: %d\n", txq_id, index & 0xff);
-	iwl_write_direct32(trans, HBUS_TARG_WRPTR,
-			(index & 0xff) | (txq_id << 8));
-	iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), index);
-}
-
-void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
-				   struct iwl_tx_queue *txq,
-				   int tx_fifo_id, bool active)
-{
-	int txq_id = txq->q.id;
-
-	iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
-			(active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
-			(tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
-			(1 << SCD_QUEUE_STTS_REG_POS_WSL) |
-			SCD_QUEUE_STTS_REG_MSK);
-
-	if (active)
-		IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d\n",
-				    txq_id, tx_fifo_id);
-	else
-		IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id);
-}
-
-void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, int txq_id, int fifo,
-				 int sta_id, int tid, int frame_limit, u16 ssn)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	unsigned long flags;
-	u16 ra_tid = BUILD_RAxTID(sta_id, tid);
-
-	if (test_and_set_bit(txq_id, trans_pcie->queue_used))
-		WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
-
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-	/* Stop this Tx queue before configuring it */
-	iwlagn_tx_queue_stop_scheduler(trans, txq_id);
-
-	/* Map receiver-address / traffic-ID to this queue */
-	iwlagn_tx_queue_set_q2ratid(trans, ra_tid, txq_id);
-
-	/* Set this queue as a chain-building queue */
-	iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
-
-	/* enable aggregations for the queue */
-	iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
-
-	/* Place first TFD at index corresponding to start sequence number.
-	 * Assumes that ssn_idx is valid (!= 0xFFF) */
-	trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
-	trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
-	iwl_trans_set_wr_ptrs(trans, txq_id, ssn);
-
-	/* Set up Tx window size and frame limit for this queue */
-	iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
-			SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
-			((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-				SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-			((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-				SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-
-	iwl_set_bits_prph(trans, SCD_INTERRUPT_MASK, (1 << txq_id));
-
-	/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
-	iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id],
-				      fifo, true);
-
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-}
-
-void iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int txq_id)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) {
-		WARN_ONCE(1, "queue %d not used", txq_id);
-		return;
-	}
-
-	iwlagn_tx_queue_stop_scheduler(trans, txq_id);
-
-	iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
-
-	trans_pcie->txq[txq_id].q.read_ptr = 0;
-	trans_pcie->txq[txq_id].q.write_ptr = 0;
-	iwl_trans_set_wr_ptrs(trans, txq_id, 0);
-
-	iwl_clear_bits_prph(trans, SCD_INTERRUPT_MASK, BIT(txq_id));
-
-	iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id],
-				      0, false);
-}
-
-/*************** HOST COMMAND QUEUE FUNCTIONS   *****/
-
-/**
- * iwl_enqueue_hcmd - enqueue a uCode command
- * @priv: device private data point
- * @cmd: a point to the ucode command structure
- *
- * The function returns < 0 values to indicate the operation is
- * failed. On success, it turns the index (> 0) of command in the
- * command queue.
- */
-static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
-	struct iwl_queue *q = &txq->q;
-	struct iwl_device_cmd *out_cmd;
-	struct iwl_cmd_meta *out_meta;
-	dma_addr_t phys_addr;
-	u32 idx;
-	u16 copy_size, cmd_size;
-	bool had_nocopy = false;
-	int i;
-	u8 *cmd_dest;
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-	const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
-	int trace_lens[IWL_MAX_CMD_TFDS + 1] = {};
-	int trace_idx;
-#endif
-
-	copy_size = sizeof(out_cmd->hdr);
-	cmd_size = sizeof(out_cmd->hdr);
-
-	/* need one for the header if the first is NOCOPY */
-	BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);
-
-	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
-		if (!cmd->len[i])
-			continue;
-		if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
-			had_nocopy = true;
-		} else {
-			/* NOCOPY must not be followed by normal! */
-			if (WARN_ON(had_nocopy))
-				return -EINVAL;
-			copy_size += cmd->len[i];
-		}
-		cmd_size += cmd->len[i];
-	}
-
-	/*
-	 * If any of the command structures end up being larger than
-	 * the TFD_MAX_PAYLOAD_SIZE and they aren't dynamically
-	 * allocated into separate TFDs, then we will need to
-	 * increase the size of the buffers.
-	 */
-	if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE))
-		return -EINVAL;
-
-	spin_lock_bh(&txq->lock);
-
-	if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
-		spin_unlock_bh(&txq->lock);
-
-		IWL_ERR(trans, "No space in command queue\n");
-		iwl_op_mode_cmd_queue_full(trans->op_mode);
-		return -ENOSPC;
-	}
-
-	idx = get_cmd_index(q, q->write_ptr);
-	out_cmd = txq->entries[idx].cmd;
-	out_meta = &txq->entries[idx].meta;
-
-	memset(out_meta, 0, sizeof(*out_meta));	/* re-initialize to NULL */
-	if (cmd->flags & CMD_WANT_SKB)
-		out_meta->source = cmd;
-
-	/* set up the header */
-
-	out_cmd->hdr.cmd = cmd->id;
-	out_cmd->hdr.flags = 0;
-	out_cmd->hdr.sequence =
-		cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) |
-					 INDEX_TO_SEQ(q->write_ptr));
-
-	/* and copy the data that needs to be copied */
-
-	cmd_dest = out_cmd->payload;
-	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
-		if (!cmd->len[i])
-			continue;
-		if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
-			break;
-		memcpy(cmd_dest, cmd->data[i], cmd->len[i]);
-		cmd_dest += cmd->len[i];
-	}
-
-	IWL_DEBUG_HC(trans,
-		"Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n",
-		trans_pcie_get_cmd_string(trans_pcie, out_cmd->hdr.cmd),
-		out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), cmd_size,
-		q->write_ptr, idx, trans_pcie->cmd_queue);
-
-	phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size,
-				DMA_BIDIRECTIONAL);
-	if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
-		idx = -ENOMEM;
-		goto out;
-	}
-
-	dma_unmap_addr_set(out_meta, mapping, phys_addr);
-	dma_unmap_len_set(out_meta, len, copy_size);
-
-	iwlagn_txq_attach_buf_to_tfd(trans, txq,
-					phys_addr, copy_size, 1);
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-	trace_bufs[0] = &out_cmd->hdr;
-	trace_lens[0] = copy_size;
-	trace_idx = 1;
-#endif
-
-	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
-		if (!cmd->len[i])
-			continue;
-		if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
-			continue;
-		phys_addr = dma_map_single(trans->dev,
-					   (void *)cmd->data[i],
-					   cmd->len[i], DMA_BIDIRECTIONAL);
-		if (dma_mapping_error(trans->dev, phys_addr)) {
-			iwlagn_unmap_tfd(trans, out_meta,
-					 &txq->tfds[q->write_ptr],
-					 DMA_BIDIRECTIONAL);
-			idx = -ENOMEM;
-			goto out;
-		}
-
-		iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
-					     cmd->len[i], 0);
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-		trace_bufs[trace_idx] = cmd->data[i];
-		trace_lens[trace_idx] = cmd->len[i];
-		trace_idx++;
-#endif
-	}
-
-	out_meta->flags = cmd->flags;
-
-	txq->need_update = 1;
-
-	/* check that tracing gets all possible blocks */
-	BUILD_BUG_ON(IWL_MAX_CMD_TFDS + 1 != 3);
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-	trace_iwlwifi_dev_hcmd(trans->dev, cmd->flags,
-			       trace_bufs[0], trace_lens[0],
-			       trace_bufs[1], trace_lens[1],
-			       trace_bufs[2], trace_lens[2]);
-#endif
-
-	/* start timer if queue currently empty */
-	if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
-		mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
-
-	/* Increment and update queue's write index */
-	q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-	iwl_txq_update_write_ptr(trans, txq);
-
- out:
-	spin_unlock_bh(&txq->lock);
-	return idx;
-}
-
-static inline void iwl_queue_progress(struct iwl_trans_pcie *trans_pcie,
-				      struct iwl_tx_queue *txq)
-{
-	if (!trans_pcie->wd_timeout)
-		return;
-
-	/*
-	 * if empty delete timer, otherwise move timer forward
-	 * since we're making progress on this queue
-	 */
-	if (txq->q.read_ptr == txq->q.write_ptr)
-		del_timer(&txq->stuck_timer);
-	else
-		mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
-}
-
-/**
- * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd
- *
- * When FW advances 'R' index, all entries between old and new 'R' index
- * need to be reclaimed. As result, some free space forms.  If there is
- * enough free space (> low mark), wake the stack that feeds us.
- */
-static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
-				   int idx)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-	struct iwl_queue *q = &txq->q;
-	int nfreed = 0;
-
-	lockdep_assert_held(&txq->lock);
-
-	if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) {
-		IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), "
-			  "index %d is out of range [0-%d] %d %d.\n", __func__,
-			  txq_id, idx, q->n_bd, q->write_ptr, q->read_ptr);
-		return;
-	}
-
-	for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
-	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
-
-		if (nfreed++ > 0) {
-			IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", idx,
-					q->write_ptr, q->read_ptr);
-			iwl_op_mode_nic_error(trans->op_mode);
-		}
-
-	}
-
-	iwl_queue_progress(trans_pcie, txq);
-}
-
-/**
- * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
- * @rxb: Rx buffer to reclaim
- * @handler_status: return value of the handler of the command
- *	(put in setup_rx_handlers)
- *
- * If an Rx buffer has an async callback associated with it the callback
- * will be executed.  The attached skb (if present) will only be freed
- * if the callback returns 1
- */
-void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
-			 int handler_status)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
-	int txq_id = SEQ_TO_QUEUE(sequence);
-	int index = SEQ_TO_INDEX(sequence);
-	int cmd_index;
-	struct iwl_device_cmd *cmd;
-	struct iwl_cmd_meta *meta;
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
-
-	/* If a Tx command is being handled and it isn't in the actual
-	 * command queue then there a command routing bug has been introduced
-	 * in the queue management code. */
-	if (WARN(txq_id != trans_pcie->cmd_queue,
-		 "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n",
-		  txq_id, trans_pcie->cmd_queue, sequence,
-		  trans_pcie->txq[trans_pcie->cmd_queue].q.read_ptr,
-		  trans_pcie->txq[trans_pcie->cmd_queue].q.write_ptr)) {
-		iwl_print_hex_error(trans, pkt, 32);
-		return;
-	}
-
-	spin_lock(&txq->lock);
-
-	cmd_index = get_cmd_index(&txq->q, index);
-	cmd = txq->entries[cmd_index].cmd;
-	meta = &txq->entries[cmd_index].meta;
-
-	iwlagn_unmap_tfd(trans, meta, &txq->tfds[index],
-			 DMA_BIDIRECTIONAL);
-
-	/* Input error checking is done when commands are added to queue. */
-	if (meta->flags & CMD_WANT_SKB) {
-		struct page *p = rxb_steal_page(rxb);
-
-		meta->source->resp_pkt = pkt;
-		meta->source->_rx_page_addr = (unsigned long)page_address(p);
-		meta->source->_rx_page_order = trans_pcie->rx_page_order;
-		meta->source->handler_status = handler_status;
-	}
-
-	iwl_hcmd_queue_reclaim(trans, txq_id, index);
-
-	if (!(meta->flags & CMD_ASYNC)) {
-		if (!test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
-			IWL_WARN(trans,
-				 "HCMD_ACTIVE already clear for command %s\n",
-				 trans_pcie_get_cmd_string(trans_pcie,
-							   cmd->hdr.cmd));
-		}
-		clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-		IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
-			       trans_pcie_get_cmd_string(trans_pcie,
-							 cmd->hdr.cmd));
-		wake_up(&trans->wait_command_queue);
-	}
-
-	meta->flags = 0;
-
-	spin_unlock(&txq->lock);
-}
-
-#define HOST_COMPLETE_TIMEOUT (2 * HZ)
-
-static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	int ret;
-
-	/* An asynchronous command can not expect an SKB to be set. */
-	if (WARN_ON(cmd->flags & CMD_WANT_SKB))
-		return -EINVAL;
-
-
-	ret = iwl_enqueue_hcmd(trans, cmd);
-	if (ret < 0) {
-		IWL_ERR(trans,
-			"Error sending %s: enqueue_hcmd failed: %d\n",
-			trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret);
-		return ret;
-	}
-	return 0;
-}
-
-static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	int cmd_idx;
-	int ret;
-
-	IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
-		       trans_pcie_get_cmd_string(trans_pcie, cmd->id));
-
-	if (WARN_ON(test_and_set_bit(STATUS_HCMD_ACTIVE,
-				     &trans_pcie->status))) {
-		IWL_ERR(trans, "Command %s: a command is already active!\n",
-			trans_pcie_get_cmd_string(trans_pcie, cmd->id));
-		return -EIO;
-	}
-
-	IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
-		       trans_pcie_get_cmd_string(trans_pcie, cmd->id));
-
-	cmd_idx = iwl_enqueue_hcmd(trans, cmd);
-	if (cmd_idx < 0) {
-		ret = cmd_idx;
-		clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-		IWL_ERR(trans,
-			"Error sending %s: enqueue_hcmd failed: %d\n",
-			trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret);
-		return ret;
-	}
-
-	ret = wait_event_timeout(trans->wait_command_queue,
-			!test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status),
-			HOST_COMPLETE_TIMEOUT);
-	if (!ret) {
-		if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
-			struct iwl_tx_queue *txq =
-				&trans_pcie->txq[trans_pcie->cmd_queue];
-			struct iwl_queue *q = &txq->q;
-
-			IWL_ERR(trans,
-				"Error sending %s: time out after %dms.\n",
-				trans_pcie_get_cmd_string(trans_pcie, cmd->id),
-				jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
-
-			IWL_ERR(trans,
-				"Current CMD queue read_ptr %d write_ptr %d\n",
-				q->read_ptr, q->write_ptr);
-
-			clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-			IWL_DEBUG_INFO(trans,
-				       "Clearing HCMD_ACTIVE for command %s\n",
-				       trans_pcie_get_cmd_string(trans_pcie,
-								 cmd->id));
-			ret = -ETIMEDOUT;
-			goto cancel;
-		}
-	}
-
-	if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) {
-		IWL_ERR(trans, "Error: Response NULL in '%s'\n",
-			trans_pcie_get_cmd_string(trans_pcie, cmd->id));
-		ret = -EIO;
-		goto cancel;
-	}
-
-	return 0;
-
-cancel:
-	if (cmd->flags & CMD_WANT_SKB) {
-		/*
-		 * Cancel the CMD_WANT_SKB flag for the cmd in the
-		 * TX cmd queue. Otherwise in case the cmd comes
-		 * in later, it will possibly set an invalid
-		 * address (cmd->meta.source).
-		 */
-		trans_pcie->txq[trans_pcie->cmd_queue].
-			entries[cmd_idx].meta.flags &= ~CMD_WANT_SKB;
-	}
-
-	if (cmd->resp_pkt) {
-		iwl_free_resp(cmd);
-		cmd->resp_pkt = NULL;
-	}
-
-	return ret;
-}
-
-int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
-{
-	if (cmd->flags & CMD_ASYNC)
-		return iwl_send_cmd_async(trans, cmd);
-
-	return iwl_send_cmd_sync(trans, cmd);
-}
-
-/* Frees buffers until index _not_ inclusive */
-int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
-			 struct sk_buff_head *skbs)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-	struct iwl_queue *q = &txq->q;
-	int last_to_free;
-	int freed = 0;
-
-	/* This function is not meant to release cmd queue*/
-	if (WARN_ON(txq_id == trans_pcie->cmd_queue))
-		return 0;
-
-	lockdep_assert_held(&txq->lock);
-
-	/*Since we free until index _not_ inclusive, the one before index is
-	 * the last we will free. This one must be used */
-	last_to_free = iwl_queue_dec_wrap(index, q->n_bd);
-
-	if ((index >= q->n_bd) ||
-	   (iwl_queue_used(q, last_to_free) == 0)) {
-		IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), "
-			  "last_to_free %d is out of range [0-%d] %d %d.\n",
-			  __func__, txq_id, last_to_free, q->n_bd,
-			  q->write_ptr, q->read_ptr);
-		return 0;
-	}
-
-	if (WARN_ON(!skb_queue_empty(skbs)))
-		return 0;
-
-	for (;
-	     q->read_ptr != index;
-	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
-
-		if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL))
-			continue;
-
-		__skb_queue_tail(skbs, txq->entries[txq->q.read_ptr].skb);
-
-		txq->entries[txq->q.read_ptr].skb = NULL;
-
-		iwlagn_txq_inval_byte_cnt_tbl(trans, txq);
-
-		iwlagn_txq_free_tfd(trans, txq, DMA_TO_DEVICE);
-		freed++;
-	}
-
-	iwl_queue_progress(trans_pcie, txq);
-
-	return freed;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
deleted file mode 100644
index 79c6b91..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ /dev/null
@@ -1,2193 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2007 - 2012 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
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#include <linux/pci.h>
-#include <linux/pci-aspm.h>
-#include <linux/interrupt.h>
-#include <linux/debugfs.h>
-#include <linux/sched.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include "iwl-drv.h"
-#include "iwl-trans.h"
-#include "iwl-trans-pcie-int.h"
-#include "iwl-csr.h"
-#include "iwl-prph.h"
-#include "iwl-eeprom.h"
-#include "iwl-agn-hw.h"
-/* FIXME: need to abstract out TX command (once we know what it looks like) */
-#include "iwl-commands.h"
-
-#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
-
-#define SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie)	\
-	(((1<<trans->cfg->base_params->num_of_queues) - 1) &\
-	(~(1<<(trans_pcie)->cmd_queue)))
-
-static int iwl_trans_rx_alloc(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-	struct device *dev = trans->dev;
-
-	memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
-
-	spin_lock_init(&rxq->lock);
-
-	if (WARN_ON(rxq->bd || rxq->rb_stts))
-		return -EINVAL;
-
-	/* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
-	rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-				      &rxq->bd_dma, GFP_KERNEL);
-	if (!rxq->bd)
-		goto err_bd;
-
-	/*Allocate the driver's pointer to receive buffer status */
-	rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
-					   &rxq->rb_stts_dma, GFP_KERNEL);
-	if (!rxq->rb_stts)
-		goto err_rb_stts;
-
-	return 0;
-
-err_rb_stts:
-	dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-			rxq->bd, rxq->bd_dma);
-	memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
-	rxq->bd = NULL;
-err_bd:
-	return -ENOMEM;
-}
-
-static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-	int i;
-
-	/* Fill the rx_used queue with _all_ of the Rx buffers */
-	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
-		/* In the reset function, these buffers may have been allocated
-		 * to an SKB, so we need to unmap and free potential storage */
-		if (rxq->pool[i].page != NULL) {
-			dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
-				PAGE_SIZE << trans_pcie->rx_page_order,
-				DMA_FROM_DEVICE);
-			__free_pages(rxq->pool[i].page,
-				     trans_pcie->rx_page_order);
-			rxq->pool[i].page = NULL;
-		}
-		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-	}
-}
-
-static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
-				 struct iwl_rx_queue *rxq)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	u32 rb_size;
-	const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
-	u32 rb_timeout = RX_RB_TIMEOUT; /* FIXME: RX_RB_TIMEOUT for all devices? */
-
-	if (trans_pcie->rx_buf_size_8k)
-		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
-	else
-		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
-
-	/* Stop Rx DMA */
-	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-
-	/* Reset driver's Rx queue write index */
-	iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
-
-	/* Tell device where to find RBD circular buffer in DRAM */
-	iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-			   (u32)(rxq->bd_dma >> 8));
-
-	/* Tell device where in DRAM to update its Rx status */
-	iwl_write_direct32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG,
-			   rxq->rb_stts_dma >> 4);
-
-	/* Enable Rx DMA
-	 * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
-	 *      the credit mechanism in 5000 HW RX FIFO
-	 * Direct rx interrupts to hosts
-	 * Rx buffer size 4 or 8k
-	 * RB timeout 0x10
-	 * 256 RBDs
-	 */
-	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG,
-			   FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
-			   FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
-			   FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-			   rb_size|
-			   (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
-			   (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
-
-	/* Set interrupt coalescing timer to default (2048 usecs) */
-	iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
-}
-
-static int iwl_rx_init(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-
-	int i, err;
-	unsigned long flags;
-
-	if (!rxq->bd) {
-		err = iwl_trans_rx_alloc(trans);
-		if (err)
-			return err;
-	}
-
-	spin_lock_irqsave(&rxq->lock, flags);
-	INIT_LIST_HEAD(&rxq->rx_free);
-	INIT_LIST_HEAD(&rxq->rx_used);
-
-	iwl_trans_rxq_free_rx_bufs(trans);
-
-	for (i = 0; i < RX_QUEUE_SIZE; i++)
-		rxq->queue[i] = NULL;
-
-	/* Set us so that we have processed and used all buffers, but have
-	 * not restocked the Rx queue with fresh buffers */
-	rxq->read = rxq->write = 0;
-	rxq->write_actual = 0;
-	rxq->free_count = 0;
-	spin_unlock_irqrestore(&rxq->lock, flags);
-
-	iwlagn_rx_replenish(trans);
-
-	iwl_trans_rx_hw_init(trans, rxq);
-
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-	rxq->need_update = 1;
-	iwl_rx_queue_update_write_ptr(trans, rxq);
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-	return 0;
-}
-
-static void iwl_trans_pcie_rx_free(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-
-	unsigned long flags;
-
-	/*if rxq->bd is NULL, it means that nothing has been allocated,
-	 * exit now */
-	if (!rxq->bd) {
-		IWL_DEBUG_INFO(trans, "Free NULL rx context\n");
-		return;
-	}
-
-	spin_lock_irqsave(&rxq->lock, flags);
-	iwl_trans_rxq_free_rx_bufs(trans);
-	spin_unlock_irqrestore(&rxq->lock, flags);
-
-	dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
-			  rxq->bd, rxq->bd_dma);
-	memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
-	rxq->bd = NULL;
-
-	if (rxq->rb_stts)
-		dma_free_coherent(trans->dev,
-				  sizeof(struct iwl_rb_status),
-				  rxq->rb_stts, rxq->rb_stts_dma);
-	else
-		IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
-	memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
-	rxq->rb_stts = NULL;
-}
-
-static int iwl_trans_rx_stop(struct iwl_trans *trans)
-{
-
-	/* stop Rx DMA */
-	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-	return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG,
-			    FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
-}
-
-static inline int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
-				    struct iwl_dma_ptr *ptr, size_t size)
-{
-	if (WARN_ON(ptr->addr))
-		return -EINVAL;
-
-	ptr->addr = dma_alloc_coherent(trans->dev, size,
-				       &ptr->dma, GFP_KERNEL);
-	if (!ptr->addr)
-		return -ENOMEM;
-	ptr->size = size;
-	return 0;
-}
-
-static inline void iwlagn_free_dma_ptr(struct iwl_trans *trans,
-				    struct iwl_dma_ptr *ptr)
-{
-	if (unlikely(!ptr->addr))
-		return;
-
-	dma_free_coherent(trans->dev, ptr->size, ptr->addr, ptr->dma);
-	memset(ptr, 0, sizeof(*ptr));
-}
-
-static void iwl_trans_pcie_queue_stuck_timer(unsigned long data)
-{
-	struct iwl_tx_queue *txq = (void *)data;
-	struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
-	struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
-
-	spin_lock(&txq->lock);
-	/* check if triggered erroneously */
-	if (txq->q.read_ptr == txq->q.write_ptr) {
-		spin_unlock(&txq->lock);
-		return;
-	}
-	spin_unlock(&txq->lock);
-
-
-	IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id,
-		jiffies_to_msecs(trans_pcie->wd_timeout));
-	IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
-		txq->q.read_ptr, txq->q.write_ptr);
-	IWL_ERR(trans, "Current HW read_ptr %d write_ptr %d\n",
-		iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq->q.id))
-					& (TFD_QUEUE_SIZE_MAX - 1),
-		iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq->q.id)));
-
-	iwl_op_mode_nic_error(trans->op_mode);
-}
-
-static int iwl_trans_txq_alloc(struct iwl_trans *trans,
-				struct iwl_tx_queue *txq, int slots_num,
-				u32 txq_id)
-{
-	size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
-	int i;
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	if (WARN_ON(txq->entries || txq->tfds))
-		return -EINVAL;
-
-	setup_timer(&txq->stuck_timer, iwl_trans_pcie_queue_stuck_timer,
-		    (unsigned long)txq);
-	txq->trans_pcie = trans_pcie;
-
-	txq->q.n_window = slots_num;
-
-	txq->entries = kcalloc(slots_num,
-			       sizeof(struct iwl_pcie_tx_queue_entry),
-			       GFP_KERNEL);
-
-	if (!txq->entries)
-		goto error;
-
-	if (txq_id == trans_pcie->cmd_queue)
-		for (i = 0; i < slots_num; i++) {
-			txq->entries[i].cmd =
-				kmalloc(sizeof(struct iwl_device_cmd),
-					GFP_KERNEL);
-			if (!txq->entries[i].cmd)
-				goto error;
-		}
-
-	/* Circular buffer of transmit frame descriptors (TFDs),
-	 * shared with device */
-	txq->tfds = dma_alloc_coherent(trans->dev, tfd_sz,
-				       &txq->q.dma_addr, GFP_KERNEL);
-	if (!txq->tfds) {
-		IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
-		goto error;
-	}
-	txq->q.id = txq_id;
-
-	return 0;
-error:
-	if (txq->entries && txq_id == trans_pcie->cmd_queue)
-		for (i = 0; i < slots_num; i++)
-			kfree(txq->entries[i].cmd);
-	kfree(txq->entries);
-	txq->entries = NULL;
-
-	return -ENOMEM;
-
-}
-
-static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-			      int slots_num, u32 txq_id)
-{
-	int ret;
-
-	txq->need_update = 0;
-
-	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
-	 * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
-	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-
-	/* Initialize queue's high/low-water marks, and head/tail indexes */
-	ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num,
-			txq_id);
-	if (ret)
-		return ret;
-
-	spin_lock_init(&txq->lock);
-
-	/*
-	 * Tell nic where to find circular buffer of Tx Frame Descriptors for
-	 * given Tx queue, and enable the DMA channel used for that queue.
-	 * Circular buffer (TFD queue in DRAM) physical base address */
-	iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
-			     txq->q.dma_addr >> 8);
-
-	return 0;
-}
-
-/**
- * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
- */
-static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-	struct iwl_queue *q = &txq->q;
-	enum dma_data_direction dma_dir;
-
-	if (!q->n_bd)
-		return;
-
-	/* In the command queue, all the TBs are mapped as BIDI
-	 * so unmap them as such.
-	 */
-	if (txq_id == trans_pcie->cmd_queue)
-		dma_dir = DMA_BIDIRECTIONAL;
-	else
-		dma_dir = DMA_TO_DEVICE;
-
-	spin_lock_bh(&txq->lock);
-	while (q->write_ptr != q->read_ptr) {
-		iwlagn_txq_free_tfd(trans, txq, dma_dir);
-		q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
-	}
-	spin_unlock_bh(&txq->lock);
-}
-
-/**
- * iwl_tx_queue_free - Deallocate DMA queue.
- * @txq: Transmit queue to deallocate.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- * 0-fill, but do not free "txq" descriptor structure.
- */
-static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-	struct device *dev = trans->dev;
-	int i;
-	if (WARN_ON(!txq))
-		return;
-
-	iwl_tx_queue_unmap(trans, txq_id);
-
-	/* De-alloc array of command/tx buffers */
-
-	if (txq_id == trans_pcie->cmd_queue)
-		for (i = 0; i < txq->q.n_window; i++)
-			kfree(txq->entries[i].cmd);
-
-	/* De-alloc circular buffer of TFDs */
-	if (txq->q.n_bd) {
-		dma_free_coherent(dev, sizeof(struct iwl_tfd) *
-				  txq->q.n_bd, txq->tfds, txq->q.dma_addr);
-		memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
-	}
-
-	kfree(txq->entries);
-	txq->entries = NULL;
-
-	del_timer_sync(&txq->stuck_timer);
-
-	/* 0-fill queue descriptor structure */
-	memset(txq, 0, sizeof(*txq));
-}
-
-/**
- * iwl_trans_tx_free - Free TXQ Context
- *
- * Destroy all TX DMA queues and structures
- */
-static void iwl_trans_pcie_tx_free(struct iwl_trans *trans)
-{
-	int txq_id;
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	/* Tx queues */
-	if (trans_pcie->txq) {
-		for (txq_id = 0;
-		     txq_id < trans->cfg->base_params->num_of_queues; txq_id++)
-			iwl_tx_queue_free(trans, txq_id);
-	}
-
-	kfree(trans_pcie->txq);
-	trans_pcie->txq = NULL;
-
-	iwlagn_free_dma_ptr(trans, &trans_pcie->kw);
-
-	iwlagn_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls);
-}
-
-/**
- * iwl_trans_tx_alloc - allocate TX context
- * Allocate all Tx DMA structures and initialize them
- *
- * @param priv
- * @return error code
- */
-static int iwl_trans_tx_alloc(struct iwl_trans *trans)
-{
-	int ret;
-	int txq_id, slots_num;
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	u16 scd_bc_tbls_size = trans->cfg->base_params->num_of_queues *
-			sizeof(struct iwlagn_scd_bc_tbl);
-
-	/*It is not allowed to alloc twice, so warn when this happens.
-	 * We cannot rely on the previous allocation, so free and fail */
-	if (WARN_ON(trans_pcie->txq)) {
-		ret = -EINVAL;
-		goto error;
-	}
-
-	ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls,
-				   scd_bc_tbls_size);
-	if (ret) {
-		IWL_ERR(trans, "Scheduler BC Table allocation failed\n");
-		goto error;
-	}
-
-	/* Alloc keep-warm buffer */
-	ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE);
-	if (ret) {
-		IWL_ERR(trans, "Keep Warm allocation failed\n");
-		goto error;
-	}
-
-	trans_pcie->txq = kcalloc(trans->cfg->base_params->num_of_queues,
-				  sizeof(struct iwl_tx_queue), GFP_KERNEL);
-	if (!trans_pcie->txq) {
-		IWL_ERR(trans, "Not enough memory for txq\n");
-		ret = ENOMEM;
-		goto error;
-	}
-
-	/* Alloc and init all Tx queues, including the command queue (#4/#9) */
-	for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
-	     txq_id++) {
-		slots_num = (txq_id == trans_pcie->cmd_queue) ?
-					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-		ret = iwl_trans_txq_alloc(trans, &trans_pcie->txq[txq_id],
-					  slots_num, txq_id);
-		if (ret) {
-			IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);
-			goto error;
-		}
-	}
-
-	return 0;
-
-error:
-	iwl_trans_pcie_tx_free(trans);
-
-	return ret;
-}
-static int iwl_tx_init(struct iwl_trans *trans)
-{
-	int ret;
-	int txq_id, slots_num;
-	unsigned long flags;
-	bool alloc = false;
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	if (!trans_pcie->txq) {
-		ret = iwl_trans_tx_alloc(trans);
-		if (ret)
-			goto error;
-		alloc = true;
-	}
-
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-	/* Turn off all Tx DMA fifos */
-	iwl_write_prph(trans, SCD_TXFACT, 0);
-
-	/* Tell NIC where to find the "keep warm" buffer */
-	iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
-			   trans_pcie->kw.dma >> 4);
-
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-	/* Alloc and init all Tx queues, including the command queue (#4/#9) */
-	for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
-	     txq_id++) {
-		slots_num = (txq_id == trans_pcie->cmd_queue) ?
-					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-		ret = iwl_trans_txq_init(trans, &trans_pcie->txq[txq_id],
-					 slots_num, txq_id);
-		if (ret) {
-			IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);
-			goto error;
-		}
-	}
-
-	return 0;
-error:
-	/*Upon error, free only if we allocated something */
-	if (alloc)
-		iwl_trans_pcie_tx_free(trans);
-	return ret;
-}
-
-static void iwl_set_pwr_vmain(struct iwl_trans *trans)
-{
-/*
- * (for documentation purposes)
- * to set power to V_AUX, do:
-
-		if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
-			iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
-					       APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
-					       ~APMG_PS_CTRL_MSK_PWR_SRC);
- */
-
-	iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
-			       APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
-			       ~APMG_PS_CTRL_MSK_PWR_SRC);
-}
-
-/* PCI registers */
-#define PCI_CFG_RETRY_TIMEOUT	0x041
-#define PCI_CFG_LINK_CTRL_VAL_L0S_EN	0x01
-#define PCI_CFG_LINK_CTRL_VAL_L1_EN	0x02
-
-static u16 iwl_pciexp_link_ctrl(struct iwl_trans *trans)
-{
-	int pos;
-	u16 pci_lnk_ctl;
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	struct pci_dev *pci_dev = trans_pcie->pci_dev;
-
-	pos = pci_pcie_cap(pci_dev);
-	pci_read_config_word(pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
-	return pci_lnk_ctl;
-}
-
-static void iwl_apm_config(struct iwl_trans *trans)
-{
-	/*
-	 * HW bug W/A for instability in PCIe bus L0S->L1 transition.
-	 * Check if BIOS (or OS) enabled L1-ASPM on this device.
-	 * If so (likely), disable L0S, so device moves directly L0->L1;
-	 *    costs negligible amount of power savings.
-	 * If not (unlikely), enable L0S, so there is at least some
-	 *    power savings, even without L1.
-	 */
-	u16 lctl = iwl_pciexp_link_ctrl(trans);
-
-	if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
-				PCI_CFG_LINK_CTRL_VAL_L1_EN) {
-		/* L1-ASPM enabled; disable(!) L0S */
-		iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-		dev_printk(KERN_INFO, trans->dev,
-			   "L1 Enabled; Disabling L0S\n");
-	} else {
-		/* L1-ASPM disabled; enable(!) L0S */
-		iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-		dev_printk(KERN_INFO, trans->dev,
-			   "L1 Disabled; Enabling L0S\n");
-	}
-	trans->pm_support = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);
-}
-
-/*
- * Start up NIC's basic functionality after it has been reset
- * (e.g. after platform boot, or shutdown via iwl_apm_stop())
- * NOTE:  This does not load uCode nor start the embedded processor
- */
-static int iwl_apm_init(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	int ret = 0;
-	IWL_DEBUG_INFO(trans, "Init card's basic functions\n");
-
-	/*
-	 * Use "set_bit" below rather than "write", to preserve any hardware
-	 * bits already set by default after reset.
-	 */
-
-	/* Disable L0S exit timer (platform NMI Work/Around) */
-	iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
-			  CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
-	/*
-	 * Disable L0s without affecting L1;
-	 *  don't wait for ICH L0s (ICH bug W/A)
-	 */
-	iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
-			  CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
-
-	/* Set FH wait threshold to maximum (HW error during stress W/A) */
-	iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
-
-	/*
-	 * Enable HAP INTA (interrupt from management bus) to
-	 * wake device's PCI Express link L1a -> L0s
-	 */
-	iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
-				    CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
-
-	iwl_apm_config(trans);
-
-	/* Configure analog phase-lock-loop before activating to D0A */
-	if (trans->cfg->base_params->pll_cfg_val)
-		iwl_set_bit(trans, CSR_ANA_PLL_CFG,
-			    trans->cfg->base_params->pll_cfg_val);
-
-	/*
-	 * Set "initialization complete" bit to move adapter from
-	 * D0U* --> D0A* (powered-up active) state.
-	 */
-	iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
-	/*
-	 * Wait for clock stabilization; once stabilized, access to
-	 * device-internal resources is supported, e.g. iwl_write_prph()
-	 * and accesses to uCode SRAM.
-	 */
-	ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
-			CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-			CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
-	if (ret < 0) {
-		IWL_DEBUG_INFO(trans, "Failed to init the card\n");
-		goto out;
-	}
-
-	/*
-	 * Enable DMA clock and wait for it to stabilize.
-	 *
-	 * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
-	 * do not disable clocks.  This preserves any hardware bits already
-	 * set by default in "CLK_CTRL_REG" after reset.
-	 */
-	iwl_write_prph(trans, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
-	udelay(20);
-
-	/* Disable L1-Active */
-	iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
-			  APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
-	set_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
-
-out:
-	return ret;
-}
-
-static int iwl_apm_stop_master(struct iwl_trans *trans)
-{
-	int ret = 0;
-
-	/* stop device's busmaster DMA activity */
-	iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
-
-	ret = iwl_poll_bit(trans, CSR_RESET,
-			CSR_RESET_REG_FLAG_MASTER_DISABLED,
-			CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-	if (ret)
-		IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");
-
-	IWL_DEBUG_INFO(trans, "stop master\n");
-
-	return ret;
-}
-
-static void iwl_apm_stop(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
-
-	clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
-
-	/* Stop device's DMA activity */
-	iwl_apm_stop_master(trans);
-
-	/* Reset the entire device */
-	iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
-	udelay(10);
-
-	/*
-	 * Clear "initialization complete" bit to move adapter from
-	 * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
-	 */
-	iwl_clear_bit(trans, CSR_GP_CNTRL,
-		      CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-}
-
-static int iwl_nic_init(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	unsigned long flags;
-
-	/* nic_init */
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-	iwl_apm_init(trans);
-
-	/* Set interrupt coalescing calibration timer to default (512 usecs) */
-	iwl_write8(trans, CSR_INT_COALESCING,
-		IWL_HOST_INT_CALIB_TIMEOUT_DEF);
-
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-	iwl_set_pwr_vmain(trans);
-
-	iwl_op_mode_nic_config(trans->op_mode);
-
-#ifndef CONFIG_IWLWIFI_IDI
-	/* Allocate the RX queue, or reset if it is already allocated */
-	iwl_rx_init(trans);
-#endif
-
-	/* Allocate or reset and init all Tx and Command queues */
-	if (iwl_tx_init(trans))
-		return -ENOMEM;
-
-	if (trans->cfg->base_params->shadow_reg_enable) {
-		/* enable shadow regs in HW */
-		iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL,
-			0x800FFFFF);
-	}
-
-	return 0;
-}
-
-#define HW_READY_TIMEOUT (50)
-
-/* Note: returns poll_bit return value, which is >= 0 if success */
-static int iwl_set_hw_ready(struct iwl_trans *trans)
-{
-	int ret;
-
-	iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
-		CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
-
-	/* See if we got it */
-	ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
-				CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
-				CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
-				HW_READY_TIMEOUT);
-
-	IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : "");
-	return ret;
-}
-
-/* Note: returns standard 0/-ERROR code */
-static int iwl_prepare_card_hw(struct iwl_trans *trans)
-{
-	int ret;
-
-	IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
-
-	ret = iwl_set_hw_ready(trans);
-	/* If the card is ready, exit 0 */
-	if (ret >= 0)
-		return 0;
-
-	/* If HW is not ready, prepare the conditions to check again */
-	iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
-			CSR_HW_IF_CONFIG_REG_PREPARE);
-
-	ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
-			~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
-			CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
-
-	if (ret < 0)
-		return ret;
-
-	/* HW should be ready by now, check again. */
-	ret = iwl_set_hw_ready(trans);
-	if (ret >= 0)
-		return 0;
-	return ret;
-}
-
-/*
- * ucode
- */
-static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
-			    const struct fw_desc *section)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	dma_addr_t phy_addr = section->p_addr;
-	u32 byte_cnt = section->len;
-	u32 dst_addr = section->offset;
-	int ret;
-
-	trans_pcie->ucode_write_complete = false;
-
-	iwl_write_direct32(trans,
-		FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
-		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
-
-	iwl_write_direct32(trans,
-		FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
-
-	iwl_write_direct32(trans,
-		FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
-		phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
-
-	iwl_write_direct32(trans,
-		FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
-		(iwl_get_dma_hi_addr(phy_addr)
-			<< FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
-
-	iwl_write_direct32(trans,
-		FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
-		1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
-		1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
-		FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
-
-	iwl_write_direct32(trans,
-		FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
-		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE	|
-		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE	|
-		FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
-
-	IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
-		     section_num);
-	ret = wait_event_timeout(trans_pcie->ucode_write_waitq,
-				 trans_pcie->ucode_write_complete, 5 * HZ);
-	if (!ret) {
-		IWL_ERR(trans, "Could not load the [%d] uCode section\n",
-			section_num);
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
-static int iwl_load_given_ucode(struct iwl_trans *trans,
-				const struct fw_img *image)
-{
-	int ret = 0;
-		int i;
-
-		for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) {
-			if (!image->sec[i].p_addr)
-				break;
-
-			ret = iwl_load_section(trans, i, &image->sec[i]);
-			if (ret)
-				return ret;
-		}
-
-	/* Remove all resets to allow NIC to operate */
-	iwl_write32(trans, CSR_RESET, 0);
-
-	return 0;
-}
-
-static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
-				   const struct fw_img *fw)
-{
-	int ret;
-	bool hw_rfkill;
-
-	/* This may fail if AMT took ownership of the device */
-	if (iwl_prepare_card_hw(trans)) {
-		IWL_WARN(trans, "Exit HW not ready\n");
-		return -EIO;
-	}
-
-	iwl_enable_rfkill_int(trans);
-
-	/* If platform's RF_KILL switch is NOT set to KILL */
-	hw_rfkill = iwl_is_rfkill_set(trans);
-	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-	if (hw_rfkill)
-		return -ERFKILL;
-
-	iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
-
-	ret = iwl_nic_init(trans);
-	if (ret) {
-		IWL_ERR(trans, "Unable to init nic\n");
-		return ret;
-	}
-
-	/* make sure rfkill handshake bits are cleared */
-	iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
-		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
-	/* clear (again), then enable host interrupts */
-	iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
-	iwl_enable_interrupts(trans);
-
-	/* really make sure rfkill handshake bits are cleared */
-	iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-	/* Load the given image to the HW */
-	return iwl_load_given_ucode(trans, fw);
-}
-
-/*
- * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- * must be called under the irq lock and with MAC access
- */
-static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
-{
-	struct iwl_trans_pcie __maybe_unused *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	lockdep_assert_held(&trans_pcie->irq_lock);
-
-	iwl_write_prph(trans, SCD_TXFACT, mask);
-}
-
-static void iwl_tx_start(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	u32 a;
-	unsigned long flags;
-	int i, chan;
-	u32 reg_val;
-
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-	trans_pcie->scd_base_addr =
-		iwl_read_prph(trans, SCD_SRAM_BASE_ADDR);
-	a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
-	/* reset conext data memory */
-	for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
-		a += 4)
-		iwl_write_targ_mem(trans, a, 0);
-	/* reset tx status memory */
-	for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
-		a += 4)
-		iwl_write_targ_mem(trans, a, 0);
-	for (; a < trans_pcie->scd_base_addr +
-	       SCD_TRANS_TBL_OFFSET_QUEUE(
-				trans->cfg->base_params->num_of_queues);
-	       a += 4)
-		iwl_write_targ_mem(trans, a, 0);
-
-	iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
-		       trans_pcie->scd_bc_tbls.dma >> 10);
-
-	/* The chain extension of the SCD doesn't work well. This feature is
-	 * enabled by default by the HW, so we need to disable it manually.
-	 */
-	iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
-
-	/* Enable DMA channel */
-	for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
-		iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
-				FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
-				FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
-
-	/* Update FH chicken bits */
-	reg_val = iwl_read_direct32(trans, FH_TX_CHICKEN_BITS_REG);
-	iwl_write_direct32(trans, FH_TX_CHICKEN_BITS_REG,
-			   reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
-
-	iwl_write_prph(trans, SCD_QUEUECHAIN_SEL,
-		SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie));
-	iwl_write_prph(trans, SCD_AGGR_SEL, 0);
-
-	/* initiate the queues */
-	for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
-		iwl_write_prph(trans, SCD_QUEUE_RDPTR(i), 0);
-		iwl_write_direct32(trans, HBUS_TARG_WRPTR, 0 | (i << 8));
-		iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
-				SCD_CONTEXT_QUEUE_OFFSET(i), 0);
-		iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
-				SCD_CONTEXT_QUEUE_OFFSET(i) +
-				sizeof(u32),
-				((SCD_WIN_SIZE <<
-				SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-				SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-				((SCD_FRAME_LIMIT <<
-				SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-				SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-	}
-
-	iwl_write_prph(trans, SCD_INTERRUPT_MASK,
-			IWL_MASK(0, trans->cfg->base_params->num_of_queues));
-
-	/* Activate all Tx DMA/FIFO channels */
-	iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
-
-	iwl_trans_set_wr_ptrs(trans, trans_pcie->cmd_queue, 0);
-
-	/* make sure all queue are not stopped/used */
-	memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
-	memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
-
-	for (i = 0; i < trans_pcie->n_q_to_fifo; i++) {
-		int fifo = trans_pcie->setup_q_to_fifo[i];
-
-		set_bit(i, trans_pcie->queue_used);
-
-		iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[i],
-					      fifo, true);
-	}
-
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-	/* Enable L1-Active */
-	iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
-			  APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-}
-
-static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans)
-{
-	iwl_reset_ict(trans);
-	iwl_tx_start(trans);
-}
-
-/**
- * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
- */
-static int iwl_trans_tx_stop(struct iwl_trans *trans)
-{
-	int ch, txq_id, ret;
-	unsigned long flags;
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	/* Turn off all Tx DMA fifos */
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-	iwl_trans_txq_set_sched(trans, 0);
-
-	/* Stop each Tx DMA channel, and wait for it to be idle */
-	for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
-		iwl_write_direct32(trans,
-				   FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
-		ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG,
-				    FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
-				    1000);
-		if (ret < 0)
-			IWL_ERR(trans, "Failing on timeout while stopping"
-			    " DMA channel %d [0x%08x]", ch,
-			    iwl_read_direct32(trans,
-					      FH_TSSR_TX_STATUS_REG));
-	}
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-	if (!trans_pcie->txq) {
-		IWL_WARN(trans, "Stopping tx queues that aren't allocated...");
-		return 0;
-	}
-
-	/* Unmap DMA from host system and free skb's */
-	for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
-	     txq_id++)
-		iwl_tx_queue_unmap(trans, txq_id);
-
-	return 0;
-}
-
-static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
-{
-	unsigned long flags;
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	/* tell the device to stop sending interrupts */
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-	iwl_disable_interrupts(trans);
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-	/* device going down, Stop using ICT table */
-	iwl_disable_ict(trans);
-
-	/*
-	 * If a HW restart happens during firmware loading,
-	 * then the firmware loading might call this function
-	 * and later it might be called again due to the
-	 * restart. So don't process again if the device is
-	 * already dead.
-	 */
-	if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) {
-		iwl_trans_tx_stop(trans);
-#ifndef CONFIG_IWLWIFI_IDI
-		iwl_trans_rx_stop(trans);
-#endif
-		/* Power-down device's busmaster DMA clocks */
-		iwl_write_prph(trans, APMG_CLK_DIS_REG,
-			       APMG_CLK_VAL_DMA_CLK_RQT);
-		udelay(5);
-	}
-
-	/* Make sure (redundant) we've released our request to stay awake */
-	iwl_clear_bit(trans, CSR_GP_CNTRL,
-			CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-	/* Stop the device, and put it in low power state */
-	iwl_apm_stop(trans);
-
-	/* Upon stop, the APM issues an interrupt if HW RF kill is set.
-	 * Clean again the interrupt here
-	 */
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-	iwl_disable_interrupts(trans);
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-	iwl_enable_rfkill_int(trans);
-
-	/* wait to make sure we flush pending tasklet*/
-	synchronize_irq(trans_pcie->irq);
-	tasklet_kill(&trans_pcie->irq_tasklet);
-
-	cancel_work_sync(&trans_pcie->rx_replenish);
-
-	/* stop and reset the on-board processor */
-	iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
-
-	/* clear all status bits */
-	clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-	clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
-	clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
-	clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
-}
-
-static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
-{
-	/* let the ucode operate on its own */
-	iwl_write32(trans, CSR_UCODE_DRV_GP1_SET,
-		    CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
-
-	iwl_disable_interrupts(trans);
-	iwl_clear_bit(trans, CSR_GP_CNTRL,
-		      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-}
-
-static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
-			     struct iwl_device_cmd *dev_cmd, int txq_id)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
-	struct iwl_cmd_meta *out_meta;
-	struct iwl_tx_queue *txq;
-	struct iwl_queue *q;
-	dma_addr_t phys_addr = 0;
-	dma_addr_t txcmd_phys;
-	dma_addr_t scratch_phys;
-	u16 len, firstlen, secondlen;
-	u8 wait_write_ptr = 0;
-	__le16 fc = hdr->frame_control;
-	u8 hdr_len = ieee80211_hdrlen(fc);
-	u16 __maybe_unused wifi_seq;
-
-	txq = &trans_pcie->txq[txq_id];
-	q = &txq->q;
-
-	if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) {
-		WARN_ON_ONCE(1);
-		return -EINVAL;
-	}
-
-	spin_lock(&txq->lock);
-
-	/* Set up driver data for this TFD */
-	txq->entries[q->write_ptr].skb = skb;
-	txq->entries[q->write_ptr].cmd = dev_cmd;
-
-	dev_cmd->hdr.cmd = REPLY_TX;
-	dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
-				INDEX_TO_SEQ(q->write_ptr)));
-
-	/* Set up first empty entry in queue's array of Tx/cmd buffers */
-	out_meta = &txq->entries[q->write_ptr].meta;
-
-	/*
-	 * Use the first empty entry in this queue's command buffer array
-	 * to contain the Tx command and MAC header concatenated together
-	 * (payload data will be in another buffer).
-	 * Size of this varies, due to varying MAC header length.
-	 * If end is not dword aligned, we'll have 2 extra bytes at the end
-	 * of the MAC header (device reads on dword boundaries).
-	 * We'll tell device about this padding later.
-	 */
-	len = sizeof(struct iwl_tx_cmd) +
-		sizeof(struct iwl_cmd_header) + hdr_len;
-	firstlen = (len + 3) & ~3;
-
-	/* Tell NIC about any 2-byte padding after MAC header */
-	if (firstlen != len)
-		tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
-
-	/* Physical address of this Tx command's header (not MAC header!),
-	 * within command buffer array. */
-	txcmd_phys = dma_map_single(trans->dev,
-				    &dev_cmd->hdr, firstlen,
-				    DMA_BIDIRECTIONAL);
-	if (unlikely(dma_mapping_error(trans->dev, txcmd_phys)))
-		goto out_err;
-	dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
-	dma_unmap_len_set(out_meta, len, firstlen);
-
-	if (!ieee80211_has_morefrags(fc)) {
-		txq->need_update = 1;
-	} else {
-		wait_write_ptr = 1;
-		txq->need_update = 0;
-	}
-
-	/* Set up TFD's 2nd entry to point directly to remainder of skb,
-	 * if any (802.11 null frames have no payload). */
-	secondlen = skb->len - hdr_len;
-	if (secondlen > 0) {
-		phys_addr = dma_map_single(trans->dev, skb->data + hdr_len,
-					   secondlen, DMA_TO_DEVICE);
-		if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
-			dma_unmap_single(trans->dev,
-					 dma_unmap_addr(out_meta, mapping),
-					 dma_unmap_len(out_meta, len),
-					 DMA_BIDIRECTIONAL);
-			goto out_err;
-		}
-	}
-
-	/* Attach buffers to TFD */
-	iwlagn_txq_attach_buf_to_tfd(trans, txq, txcmd_phys, firstlen, 1);
-	if (secondlen > 0)
-		iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
-					     secondlen, 0);
-
-	scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
-				offsetof(struct iwl_tx_cmd, scratch);
-
-	/* take back ownership of DMA buffer to enable update */
-	dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen,
-			DMA_BIDIRECTIONAL);
-	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
-	tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
-
-	IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
-		     le16_to_cpu(dev_cmd->hdr.sequence));
-	IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
-
-	/* Set up entry for this TFD in Tx byte-count array */
-	iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
-
-	dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
-			DMA_BIDIRECTIONAL);
-
-	trace_iwlwifi_dev_tx(trans->dev,
-			     &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
-			     sizeof(struct iwl_tfd),
-			     &dev_cmd->hdr, firstlen,
-			     skb->data + hdr_len, secondlen);
-
-	/* start timer if queue currently empty */
-	if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
-		mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
-
-	/* Tell device the write index *just past* this latest filled TFD */
-	q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-	iwl_txq_update_write_ptr(trans, txq);
-
-	/*
-	 * At this point the frame is "transmitted" successfully
-	 * and we will get a TX status notification eventually,
-	 * regardless of the value of ret. "ret" only indicates
-	 * whether or not we should update the write pointer.
-	 */
-	if (iwl_queue_space(q) < q->high_mark) {
-		if (wait_write_ptr) {
-			txq->need_update = 1;
-			iwl_txq_update_write_ptr(trans, txq);
-		} else {
-			iwl_stop_queue(trans, txq);
-		}
-	}
-	spin_unlock(&txq->lock);
-	return 0;
- out_err:
-	spin_unlock(&txq->lock);
-	return -1;
-}
-
-static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-	int err;
-	bool hw_rfkill;
-
-	trans_pcie->inta_mask = CSR_INI_SET_MASK;
-
-	if (!trans_pcie->irq_requested) {
-		tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
-			iwl_irq_tasklet, (unsigned long)trans);
-
-		iwl_alloc_isr_ict(trans);
-
-		err = request_irq(trans_pcie->irq, iwl_isr_ict, IRQF_SHARED,
-			DRV_NAME, trans);
-		if (err) {
-			IWL_ERR(trans, "Error allocating IRQ %d\n",
-				trans_pcie->irq);
-			goto error;
-		}
-
-		INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish);
-		trans_pcie->irq_requested = true;
-	}
-
-	err = iwl_prepare_card_hw(trans);
-	if (err) {
-		IWL_ERR(trans, "Error while preparing HW: %d", err);
-		goto err_free_irq;
-	}
-
-	iwl_apm_init(trans);
-
-	/* From now on, the op_mode will be kept updated about RF kill state */
-	iwl_enable_rfkill_int(trans);
-
-	hw_rfkill = iwl_is_rfkill_set(trans);
-	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-
-	return err;
-
-err_free_irq:
-	free_irq(trans_pcie->irq, trans);
-error:
-	iwl_free_isr_ict(trans);
-	tasklet_kill(&trans_pcie->irq_tasklet);
-	return err;
-}
-
-static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
-				   bool op_mode_leaving)
-{
-	bool hw_rfkill;
-	unsigned long flags;
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	iwl_apm_stop(trans);
-
-	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-	iwl_disable_interrupts(trans);
-	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-	iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
-
-	if (!op_mode_leaving) {
-		/*
-		 * Even if we stop the HW, we still want the RF kill
-		 * interrupt
-		 */
-		iwl_enable_rfkill_int(trans);
-
-		/*
-		 * Check again since the RF kill state may have changed while
-		 * all the interrupts were disabled, in this case we couldn't
-		 * receive the RF kill interrupt and update the state in the
-		 * op_mode.
-		 */
-		hw_rfkill = iwl_is_rfkill_set(trans);
-		iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-	}
-}
-
-static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
-				   struct sk_buff_head *skbs)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-	/* n_bd is usually 256 => n_bd - 1 = 0xff */
-	int tfd_num = ssn & (txq->q.n_bd - 1);
-	int freed = 0;
-
-	spin_lock(&txq->lock);
-
-	if (txq->q.read_ptr != tfd_num) {
-		IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n",
-				   txq_id, txq->q.read_ptr, tfd_num, ssn);
-		freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
-		if (iwl_queue_space(&txq->q) > txq->q.low_mark)
-			iwl_wake_queue(trans, txq);
-	}
-
-	spin_unlock(&txq->lock);
-}
-
-static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
-{
-	writeb(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
-}
-
-static void iwl_trans_pcie_write32(struct iwl_trans *trans, u32 ofs, u32 val)
-{
-	writel(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
-}
-
-static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
-{
-	return readl(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
-}
-
-static void iwl_trans_pcie_configure(struct iwl_trans *trans,
-				     const struct iwl_trans_config *trans_cfg)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	trans_pcie->cmd_queue = trans_cfg->cmd_queue;
-	if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS))
-		trans_pcie->n_no_reclaim_cmds = 0;
-	else
-		trans_pcie->n_no_reclaim_cmds = trans_cfg->n_no_reclaim_cmds;
-	if (trans_pcie->n_no_reclaim_cmds)
-		memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds,
-		       trans_pcie->n_no_reclaim_cmds * sizeof(u8));
-
-	trans_pcie->n_q_to_fifo = trans_cfg->n_queue_to_fifo;
-
-	if (WARN_ON(trans_pcie->n_q_to_fifo > IWL_MAX_HW_QUEUES))
-		trans_pcie->n_q_to_fifo = IWL_MAX_HW_QUEUES;
-
-	/* at least the command queue must be mapped */
-	WARN_ON(!trans_pcie->n_q_to_fifo);
-
-	memcpy(trans_pcie->setup_q_to_fifo, trans_cfg->queue_to_fifo,
-	       trans_pcie->n_q_to_fifo * sizeof(u8));
-
-	trans_pcie->rx_buf_size_8k = trans_cfg->rx_buf_size_8k;
-	if (trans_pcie->rx_buf_size_8k)
-		trans_pcie->rx_page_order = get_order(8 * 1024);
-	else
-		trans_pcie->rx_page_order = get_order(4 * 1024);
-
-	trans_pcie->wd_timeout =
-		msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);
-
-	trans_pcie->command_names = trans_cfg->command_names;
-}
-
-void iwl_trans_pcie_free(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	iwl_trans_pcie_tx_free(trans);
-#ifndef CONFIG_IWLWIFI_IDI
-	iwl_trans_pcie_rx_free(trans);
-#endif
-	if (trans_pcie->irq_requested == true) {
-		free_irq(trans_pcie->irq, trans);
-		iwl_free_isr_ict(trans);
-	}
-
-	pci_disable_msi(trans_pcie->pci_dev);
-	iounmap(trans_pcie->hw_base);
-	pci_release_regions(trans_pcie->pci_dev);
-	pci_disable_device(trans_pcie->pci_dev);
-
-	kfree(trans);
-}
-
-static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	if (state)
-		set_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
-	else
-		clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
-{
-	return 0;
-}
-
-static int iwl_trans_pcie_resume(struct iwl_trans *trans)
-{
-	bool hw_rfkill;
-
-	iwl_enable_rfkill_int(trans);
-
-	hw_rfkill = iwl_is_rfkill_set(trans);
-	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-
-	if (!hw_rfkill)
-		iwl_enable_interrupts(trans);
-
-	return 0;
-}
-#endif /* CONFIG_PM_SLEEP */
-
-#define IWL_FLUSH_WAIT_MS	2000
-
-static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
-{
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	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 < trans->cfg->base_params->num_of_queues; cnt++) {
-		if (cnt == trans_pcie->cmd_queue)
-			continue;
-		txq = &trans_pcie->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(trans, "fail to flush all tx fifo queues\n");
-			ret = -ETIMEDOUT;
-			break;
-		}
-	}
-	return ret;
-}
-
-static const char *get_fh_string(int cmd)
-{
-#define IWL_CMD(x) case x: return #x
-	switch (cmd) {
-	IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
-	IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
-	IWL_CMD(FH_RSCSR_CHNL0_WPTR);
-	IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
-	IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
-	IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
-	IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
-	IWL_CMD(FH_TSSR_TX_STATUS_REG);
-	IWL_CMD(FH_TSSR_TX_ERROR_REG);
-	default:
-		return "UNKNOWN";
-	}
-#undef IWL_CMD
-}
-
-int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
-{
-	int i;
-#ifdef CONFIG_IWLWIFI_DEBUG
-	int pos = 0;
-	size_t bufsz = 0;
-#endif
-	static const u32 fh_tbl[] = {
-		FH_RSCSR_CHNL0_STTS_WPTR_REG,
-		FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-		FH_RSCSR_CHNL0_WPTR,
-		FH_MEM_RCSR_CHNL0_CONFIG_REG,
-		FH_MEM_RSSR_SHARED_CTRL_REG,
-		FH_MEM_RSSR_RX_STATUS_REG,
-		FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
-		FH_TSSR_TX_STATUS_REG,
-		FH_TSSR_TX_ERROR_REG
-	};
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (display) {
-		bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
-		*buf = kmalloc(bufsz, GFP_KERNEL);
-		if (!*buf)
-			return -ENOMEM;
-		pos += scnprintf(*buf + pos, bufsz - pos,
-				"FH register values:\n");
-		for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
-			pos += scnprintf(*buf + pos, bufsz - pos,
-				"  %34s: 0X%08x\n",
-				get_fh_string(fh_tbl[i]),
-				iwl_read_direct32(trans, fh_tbl[i]));
-		}
-		return pos;
-	}
-#endif
-	IWL_ERR(trans, "FH register values:\n");
-	for (i = 0; i <  ARRAY_SIZE(fh_tbl); i++) {
-		IWL_ERR(trans, "  %34s: 0X%08x\n",
-			get_fh_string(fh_tbl[i]),
-			iwl_read_direct32(trans, fh_tbl[i]));
-	}
-	return 0;
-}
-
-static const char *get_csr_string(int cmd)
-{
-#define IWL_CMD(x) case x: return #x
-	switch (cmd) {
-	IWL_CMD(CSR_HW_IF_CONFIG_REG);
-	IWL_CMD(CSR_INT_COALESCING);
-	IWL_CMD(CSR_INT);
-	IWL_CMD(CSR_INT_MASK);
-	IWL_CMD(CSR_FH_INT_STATUS);
-	IWL_CMD(CSR_GPIO_IN);
-	IWL_CMD(CSR_RESET);
-	IWL_CMD(CSR_GP_CNTRL);
-	IWL_CMD(CSR_HW_REV);
-	IWL_CMD(CSR_EEPROM_REG);
-	IWL_CMD(CSR_EEPROM_GP);
-	IWL_CMD(CSR_OTP_GP_REG);
-	IWL_CMD(CSR_GIO_REG);
-	IWL_CMD(CSR_GP_UCODE_REG);
-	IWL_CMD(CSR_GP_DRIVER_REG);
-	IWL_CMD(CSR_UCODE_DRV_GP1);
-	IWL_CMD(CSR_UCODE_DRV_GP2);
-	IWL_CMD(CSR_LED_REG);
-	IWL_CMD(CSR_DRAM_INT_TBL_REG);
-	IWL_CMD(CSR_GIO_CHICKEN_BITS);
-	IWL_CMD(CSR_ANA_PLL_CFG);
-	IWL_CMD(CSR_HW_REV_WA_REG);
-	IWL_CMD(CSR_DBG_HPET_MEM_REG);
-	default:
-		return "UNKNOWN";
-	}
-#undef IWL_CMD
-}
-
-void iwl_dump_csr(struct iwl_trans *trans)
-{
-	int i;
-	static const u32 csr_tbl[] = {
-		CSR_HW_IF_CONFIG_REG,
-		CSR_INT_COALESCING,
-		CSR_INT,
-		CSR_INT_MASK,
-		CSR_FH_INT_STATUS,
-		CSR_GPIO_IN,
-		CSR_RESET,
-		CSR_GP_CNTRL,
-		CSR_HW_REV,
-		CSR_EEPROM_REG,
-		CSR_EEPROM_GP,
-		CSR_OTP_GP_REG,
-		CSR_GIO_REG,
-		CSR_GP_UCODE_REG,
-		CSR_GP_DRIVER_REG,
-		CSR_UCODE_DRV_GP1,
-		CSR_UCODE_DRV_GP2,
-		CSR_LED_REG,
-		CSR_DRAM_INT_TBL_REG,
-		CSR_GIO_CHICKEN_BITS,
-		CSR_ANA_PLL_CFG,
-		CSR_HW_REV_WA_REG,
-		CSR_DBG_HPET_MEM_REG
-	};
-	IWL_ERR(trans, "CSR values:\n");
-	IWL_ERR(trans, "(2nd byte of CSR_INT_COALESCING is "
-		"CSR_INT_PERIODIC_REG)\n");
-	for (i = 0; i <  ARRAY_SIZE(csr_tbl); i++) {
-		IWL_ERR(trans, "  %25s: 0X%08x\n",
-			get_csr_string(csr_tbl[i]),
-			iwl_read32(trans, csr_tbl[i]));
-	}
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-/* create and remove of files */
-#define DEBUGFS_ADD_FILE(name, parent, mode) do {			\
-	if (!debugfs_create_file(#name, mode, parent, trans,		\
-				 &iwl_dbgfs_##name##_ops))		\
-		return -ENOMEM;						\
-} while (0)
-
-/* file operation */
-#define DEBUGFS_READ_FUNC(name)                                         \
-static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
-					char __user *user_buf,          \
-					size_t count, loff_t *ppos);
-
-#define DEBUGFS_WRITE_FUNC(name)                                        \
-static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
-					const char __user *user_buf,    \
-					size_t count, loff_t *ppos);
-
-
-#define DEBUGFS_READ_FILE_OPS(name)					\
-	DEBUGFS_READ_FUNC(name);					\
-static const struct file_operations iwl_dbgfs_##name##_ops = {		\
-	.read = iwl_dbgfs_##name##_read,				\
-	.open = simple_open,						\
-	.llseek = generic_file_llseek,					\
-};
-
-#define DEBUGFS_WRITE_FILE_OPS(name)                                    \
-	DEBUGFS_WRITE_FUNC(name);                                       \
-static const struct file_operations iwl_dbgfs_##name##_ops = {          \
-	.write = iwl_dbgfs_##name##_write,                              \
-	.open = simple_open,						\
-	.llseek = generic_file_llseek,					\
-};
-
-#define DEBUGFS_READ_WRITE_FILE_OPS(name)				\
-	DEBUGFS_READ_FUNC(name);					\
-	DEBUGFS_WRITE_FUNC(name);					\
-static const struct file_operations iwl_dbgfs_##name##_ops = {		\
-	.write = iwl_dbgfs_##name##_write,				\
-	.read = iwl_dbgfs_##name##_read,				\
-	.open = simple_open,						\
-	.llseek = generic_file_llseek,					\
-};
-
-static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
-						char __user *user_buf,
-						size_t count, loff_t *ppos)
-{
-	struct iwl_trans *trans = file->private_data;
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_tx_queue *txq;
-	struct iwl_queue *q;
-	char *buf;
-	int pos = 0;
-	int cnt;
-	int ret;
-	size_t bufsz;
-
-	bufsz = sizeof(char) * 64 * trans->cfg->base_params->num_of_queues;
-
-	if (!trans_pcie->txq)
-		return -EAGAIN;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
-		txq = &trans_pcie->txq[cnt];
-		q = &txq->q;
-		pos += scnprintf(buf + pos, bufsz - pos,
-				"hwq %.2d: read=%u write=%u use=%d stop=%d\n",
-				cnt, q->read_ptr, q->write_ptr,
-				!!test_bit(cnt, trans_pcie->queue_used),
-				!!test_bit(cnt, trans_pcie->queue_stopped));
-	}
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
-						char __user *user_buf,
-						size_t count, loff_t *ppos) {
-	struct iwl_trans *trans = file->private_data;
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-	char buf[256];
-	int pos = 0;
-	const size_t bufsz = sizeof(buf);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
-						rxq->read);
-	pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
-						rxq->write);
-	pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
-						rxq->free_count);
-	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);
-}
-
-static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos) {
-
-	struct iwl_trans *trans = file->private_data;
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
-
-	int pos = 0;
-	char *buf;
-	int bufsz = 24 * 64; /* 24 items * 64 char per item */
-	ssize_t ret;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"Interrupt Statistics Report:\n");
-
-	pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
-		isr_stats->hw);
-	pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
-		isr_stats->sw);
-	if (isr_stats->sw || isr_stats->hw) {
-		pos += scnprintf(buf + pos, bufsz - pos,
-			"\tLast Restarting Code:  0x%X\n",
-			isr_stats->err_code);
-	}
-#ifdef CONFIG_IWLWIFI_DEBUG
-	pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
-		isr_stats->sch);
-	pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
-		isr_stats->alive);
-#endif
-	pos += scnprintf(buf + pos, bufsz - pos,
-		"HW RF KILL switch toggled:\t %u\n", isr_stats->rfkill);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
-		isr_stats->ctkill);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
-		isr_stats->wakeup);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-		"Rx command responses:\t\t %u\n", isr_stats->rx);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
-		isr_stats->tx);
-
-	pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
-		isr_stats->unhandled);
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
-					 const char __user *user_buf,
-					 size_t count, loff_t *ppos)
-{
-	struct iwl_trans *trans = file->private_data;
-	struct iwl_trans_pcie *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-	struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
-
-	char buf[8];
-	int buf_size;
-	u32 reset_flag;
-
-	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, "%x", &reset_flag) != 1)
-		return -EFAULT;
-	if (reset_flag == 0)
-		memset(isr_stats, 0, sizeof(*isr_stats));
-
-	return count;
-}
-
-static ssize_t iwl_dbgfs_csr_write(struct file *file,
-					 const char __user *user_buf,
-					 size_t count, loff_t *ppos)
-{
-	struct iwl_trans *trans = file->private_data;
-	char buf[8];
-	int buf_size;
-	int csr;
-
-	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", &csr) != 1)
-		return -EFAULT;
-
-	iwl_dump_csr(trans);
-
-	return count;
-}
-
-static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
-					 char __user *user_buf,
-					 size_t count, loff_t *ppos)
-{
-	struct iwl_trans *trans = file->private_data;
-	char *buf;
-	int pos = 0;
-	ssize_t ret = -EFAULT;
-
-	ret = pos = iwl_dump_fh(trans, &buf, true);
-	if (buf) {
-		ret = simple_read_from_buffer(user_buf,
-					      count, ppos, buf, pos);
-		kfree(buf);
-	}
-
-	return ret;
-}
-
-static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
-					  const char __user *user_buf,
-					  size_t count, loff_t *ppos)
-{
-	struct iwl_trans *trans = file->private_data;
-
-	if (!trans->op_mode)
-		return -EAGAIN;
-
-	iwl_op_mode_nic_error(trans->op_mode);
-
-	return count;
-}
-
-DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
-DEBUGFS_READ_FILE_OPS(fh_reg);
-DEBUGFS_READ_FILE_OPS(rx_queue);
-DEBUGFS_READ_FILE_OPS(tx_queue);
-DEBUGFS_WRITE_FILE_OPS(csr);
-DEBUGFS_WRITE_FILE_OPS(fw_restart);
-
-/*
- * Create the debugfs files and directories
- *
- */
-static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
-					struct dentry *dir)
-{
-	DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
-	DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
-	DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
-	DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
-	DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
-	DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR);
-	return 0;
-}
-#else
-static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
-					struct dentry *dir)
-{ return 0; }
-
-#endif /*CONFIG_IWLWIFI_DEBUGFS */
-
-static const struct iwl_trans_ops trans_ops_pcie = {
-	.start_hw = iwl_trans_pcie_start_hw,
-	.stop_hw = iwl_trans_pcie_stop_hw,
-	.fw_alive = iwl_trans_pcie_fw_alive,
-	.start_fw = iwl_trans_pcie_start_fw,
-	.stop_device = iwl_trans_pcie_stop_device,
-
-	.wowlan_suspend = iwl_trans_pcie_wowlan_suspend,
-
-	.send_cmd = iwl_trans_pcie_send_cmd,
-
-	.tx = iwl_trans_pcie_tx,
-	.reclaim = iwl_trans_pcie_reclaim,
-
-	.tx_agg_disable = iwl_trans_pcie_tx_agg_disable,
-	.tx_agg_setup = iwl_trans_pcie_tx_agg_setup,
-
-	.dbgfs_register = iwl_trans_pcie_dbgfs_register,
-
-	.wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty,
-
-#ifdef CONFIG_PM_SLEEP
-	.suspend = iwl_trans_pcie_suspend,
-	.resume = iwl_trans_pcie_resume,
-#endif
-	.write8 = iwl_trans_pcie_write8,
-	.write32 = iwl_trans_pcie_write32,
-	.read32 = iwl_trans_pcie_read32,
-	.configure = iwl_trans_pcie_configure,
-	.set_pmi = iwl_trans_pcie_set_pmi,
-};
-
-struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
-				       const struct pci_device_id *ent,
-				       const struct iwl_cfg *cfg)
-{
-	struct iwl_trans_pcie *trans_pcie;
-	struct iwl_trans *trans;
-	u16 pci_cmd;
-	int err;
-
-	trans = kzalloc(sizeof(struct iwl_trans) +
-			     sizeof(struct iwl_trans_pcie), GFP_KERNEL);
-
-	if (WARN_ON(!trans))
-		return NULL;
-
-	trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	trans->ops = &trans_ops_pcie;
-	trans->cfg = cfg;
-	trans_pcie->trans = trans;
-	spin_lock_init(&trans_pcie->irq_lock);
-	init_waitqueue_head(&trans_pcie->ucode_write_waitq);
-
-	/* W/A - seems to solve weird behavior. We need to remove this if we
-	 * don't want to stay in L1 all the time. This wastes a lot of power */
-	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
-				PCIE_LINK_STATE_CLKPM);
-
-	if (pci_enable_device(pdev)) {
-		err = -ENODEV;
-		goto out_no_pci;
-	}
-
-	pci_set_master(pdev);
-
-	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
-	if (!err)
-		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
-	if (err) {
-		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-		if (!err)
-			err = pci_set_consistent_dma_mask(pdev,
-							DMA_BIT_MASK(32));
-		/* both attempts failed: */
-		if (err) {
-			dev_printk(KERN_ERR, &pdev->dev,
-				   "No suitable DMA available.\n");
-			goto out_pci_disable_device;
-		}
-	}
-
-	err = pci_request_regions(pdev, DRV_NAME);
-	if (err) {
-		dev_printk(KERN_ERR, &pdev->dev, "pci_request_regions failed");
-		goto out_pci_disable_device;
-	}
-
-	trans_pcie->hw_base = pci_ioremap_bar(pdev, 0);
-	if (!trans_pcie->hw_base) {
-		dev_printk(KERN_ERR, &pdev->dev, "pci_ioremap_bar failed");
-		err = -ENODEV;
-		goto out_pci_release_regions;
-	}
-
-	dev_printk(KERN_INFO, &pdev->dev,
-		"pci_resource_len = 0x%08llx\n",
-		(unsigned long long) pci_resource_len(pdev, 0));
-	dev_printk(KERN_INFO, &pdev->dev,
-		"pci_resource_base = %p\n", trans_pcie->hw_base);
-
-	dev_printk(KERN_INFO, &pdev->dev,
-		"HW Revision ID = 0x%X\n", pdev->revision);
-
-	/* We disable the RETRY_TIMEOUT register (0x41) to keep
-	 * PCI Tx retries from interfering with C3 CPU state */
-	pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
-
-	err = pci_enable_msi(pdev);
-	if (err)
-		dev_printk(KERN_ERR, &pdev->dev,
-			"pci_enable_msi failed(0X%x)", err);
-
-	trans->dev = &pdev->dev;
-	trans_pcie->irq = pdev->irq;
-	trans_pcie->pci_dev = pdev;
-	trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
-	trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
-	snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
-		 "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device);
-
-	/* TODO: Move this away, not needed if not MSI */
-	/* enable rfkill interrupt: hw bug w/a */
-	pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
-	if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
-		pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
-		pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
-	}
-
-	/* Initialize the wait queue for commands */
-	init_waitqueue_head(&trans->wait_command_queue);
-	spin_lock_init(&trans->reg_lock);
-
-	return trans;
-
-out_pci_release_regions:
-	pci_release_regions(pdev);
-out_pci_disable_device:
-	pci_disable_device(pdev);
-out_no_pci:
-	kfree(trans);
-	return NULL;
-}
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 79a1e7a..00efde8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -154,6 +154,9 @@ struct iwl_cmd_header {
 	__le16 sequence;
 } __packed;
 
+/* iwl_cmd_header flags value */
+#define IWL_CMD_FAILED_MSK 0x40
+
 
 #define FH_RSCSR_FRAME_SIZE_MSK		0x00003FFF	/* bits 0-13 */
 #define FH_RSCSR_FRAME_INVALID		0x55550000
@@ -280,6 +283,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
 
 #define MAX_NO_RECLAIM_CMDS	6
 
+#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
+
 /*
  * Maximum number of HW queues the transport layer
  * currently supports
@@ -350,10 +355,10 @@ struct iwl_trans;
  *	Must be atomic
  * @reclaim: free packet until ssn. Returns a list of freed packets.
  *	Must be atomic
- * @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is
+ * @txq_enable: setup a tx queue for AMPDU - will be called once the HW is
  *	ready and a successful ADDBA response has been received.
  *	May sleep
- * @tx_agg_disable: de-configure a Tx queue to send AMPDUs
+ * @txq_disable: de-configure a Tx queue to send AMPDUs
  *	Must be atomic
  * @wait_tx_queue_empty: wait until all tx queues are empty
  *	May sleep
@@ -386,9 +391,9 @@ struct iwl_trans_ops {
 	void (*reclaim)(struct iwl_trans *trans, int queue, int ssn,
 			struct sk_buff_head *skbs);
 
-	void (*tx_agg_setup)(struct iwl_trans *trans, int queue, int fifo,
-			     int sta_id, int tid, int frame_limit, u16 ssn);
-	void (*tx_agg_disable)(struct iwl_trans *trans, int queue);
+	void (*txq_enable)(struct iwl_trans *trans, int queue, int fifo,
+			   int sta_id, int tid, int frame_limit, u16 ssn);
+	void (*txq_disable)(struct iwl_trans *trans, int queue);
 
 	int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
 	int (*wait_tx_queue_empty)(struct iwl_trans *trans);
@@ -428,6 +433,11 @@ enum iwl_trans_state {
  * @hw_id_str: a string with info about HW ID. Set during transport allocation.
  * @pm_support: set to true in start_hw if link pm is supported
  * @wait_command_queue: the wait_queue for SYNC host commands
+ * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
+ *	The user should use iwl_trans_{alloc,free}_tx_cmd.
+ * @dev_cmd_headroom: room needed for the transport's private use before the
+ *	device_cmd for Tx - for internal use only
+ *	The user should use iwl_trans_{alloc,free}_tx_cmd.
  */
 struct iwl_trans {
 	const struct iwl_trans_ops *ops;
@@ -445,6 +455,10 @@ struct iwl_trans {
 
 	wait_queue_head_t wait_command_queue;
 
+	/* The following fields are internal only */
+	struct kmem_cache *dev_cmd_pool;
+	size_t dev_cmd_headroom;
+
 	/* pointer to trans specific struct */
 	/*Ensure that this pointer will always be aligned to sizeof pointer */
 	char trans_specific[0] __aligned(sizeof(void *));
@@ -520,6 +534,26 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
 	return trans->ops->send_cmd(trans, cmd);
 }
 
+static inline struct iwl_device_cmd *
+iwl_trans_alloc_tx_cmd(struct iwl_trans *trans)
+{
+	u8 *dev_cmd_ptr = kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC);
+
+	if (unlikely(dev_cmd_ptr == NULL))
+		return NULL;
+
+	return (struct iwl_device_cmd *)
+			(dev_cmd_ptr + trans->dev_cmd_headroom);
+}
+
+static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans,
+					 struct iwl_device_cmd *dev_cmd)
+{
+	u8 *dev_cmd_ptr = (u8 *)dev_cmd - trans->dev_cmd_headroom;
+
+	kmem_cache_free(trans->dev_cmd_pool, dev_cmd_ptr);
+}
+
 static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
 			       struct iwl_device_cmd *dev_cmd, int queue)
 {
@@ -538,24 +572,24 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
 	trans->ops->reclaim(trans, queue, ssn, skbs);
 }
 
-static inline void iwl_trans_tx_agg_disable(struct iwl_trans *trans, int queue)
+static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue)
 {
 	WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
 		  "%s bad state = %d", __func__, trans->state);
 
-	trans->ops->tx_agg_disable(trans, queue);
+	trans->ops->txq_disable(trans, queue);
 }
 
-static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, int queue,
-					  int fifo, int sta_id, int tid,
-					  int frame_limit, u16 ssn)
+static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
+					int fifo, int sta_id, int tid,
+					int frame_limit, u16 ssn)
 {
 	might_sleep();
 
 	WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
 		  "%s bad state = %d", __func__, trans->state);
 
-	trans->ops->tx_agg_setup(trans, queue, fifo, sta_id, tid,
+	trans->ops->txq_enable(trans, queue, fifo, sta_id, tid,
 				 frame_limit, ssn);
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c
deleted file mode 100644
index bc40dc6..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-ucode.c
+++ /dev/null
@@ -1,532 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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/init.h>
-
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-hw.h"
-#include "iwl-agn.h"
-#include "iwl-agn-calib.h"
-#include "iwl-trans.h"
-#include "iwl-fh.h"
-#include "iwl-op-mode.h"
-
-/******************************************************************************
- *
- * uCode download functions
- *
- ******************************************************************************/
-
-static inline const struct fw_img *
-iwl_get_ucode_image(struct iwl_priv *priv, enum iwl_ucode_type ucode_type)
-{
-	if (ucode_type >= IWL_UCODE_TYPE_MAX)
-		return NULL;
-
-	return &priv->fw->img[ucode_type];
-}
-
-/*
- *  Calibration
- */
-static int iwl_set_Xtal_calib(struct iwl_priv *priv)
-{
-	struct iwl_calib_xtal_freq_cmd cmd;
-	__le16 *xtal_calib =
-		(__le16 *)iwl_eeprom_query_addr(priv, EEPROM_XTAL);
-
-	iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD);
-	cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
-	cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
-	return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
-}
-
-static int iwl_set_temperature_offset_calib(struct iwl_priv *priv)
-{
-	struct iwl_calib_temperature_offset_cmd cmd;
-	__le16 *offset_calib =
-		(__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE);
-
-	memset(&cmd, 0, sizeof(cmd));
-	iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
-	memcpy(&cmd.radio_sensor_offset, offset_calib, sizeof(*offset_calib));
-	if (!(cmd.radio_sensor_offset))
-		cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET;
-
-	IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n",
-			le16_to_cpu(cmd.radio_sensor_offset));
-	return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
-}
-
-static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv)
-{
-	struct iwl_calib_temperature_offset_v2_cmd cmd;
-	__le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv,
-				     EEPROM_KELVIN_TEMPERATURE);
-	__le16 *offset_calib_low =
-		(__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE);
-	struct iwl_eeprom_calib_hdr *hdr;
-
-	memset(&cmd, 0, sizeof(cmd));
-	iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
-	hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
-							EEPROM_CALIB_ALL);
-	memcpy(&cmd.radio_sensor_offset_high, offset_calib_high,
-		sizeof(*offset_calib_high));
-	memcpy(&cmd.radio_sensor_offset_low, offset_calib_low,
-		sizeof(*offset_calib_low));
-	if (!(cmd.radio_sensor_offset_low)) {
-		IWL_DEBUG_CALIB(priv, "no info in EEPROM, use default\n");
-		cmd.radio_sensor_offset_low = DEFAULT_RADIO_SENSOR_OFFSET;
-		cmd.radio_sensor_offset_high = DEFAULT_RADIO_SENSOR_OFFSET;
-	}
-	memcpy(&cmd.burntVoltageRef, &hdr->voltage,
-		sizeof(hdr->voltage));
-
-	IWL_DEBUG_CALIB(priv, "Radio sensor offset high: %d\n",
-			le16_to_cpu(cmd.radio_sensor_offset_high));
-	IWL_DEBUG_CALIB(priv, "Radio sensor offset low: %d\n",
-			le16_to_cpu(cmd.radio_sensor_offset_low));
-	IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n",
-			le16_to_cpu(cmd.burntVoltageRef));
-
-	return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
-}
-
-static int iwl_send_calib_cfg(struct iwl_priv *priv)
-{
-	struct iwl_calib_cfg_cmd calib_cfg_cmd;
-	struct iwl_host_cmd cmd = {
-		.id = CALIBRATION_CFG_CMD,
-		.len = { sizeof(struct iwl_calib_cfg_cmd), },
-		.data = { &calib_cfg_cmd, },
-	};
-
-	memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
-	calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
-	calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
-	calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
-	calib_cfg_cmd.ucd_calib_cfg.flags =
-		IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK;
-
-	return iwl_dvm_send_cmd(priv, &cmd);
-}
-
-int iwl_init_alive_start(struct iwl_priv *priv)
-{
-	int ret;
-
-	if (priv->cfg->bt_params &&
-	    priv->cfg->bt_params->advanced_bt_coexist) {
-		/*
-		 * Tell uCode we are ready to perform calibration
-		 * need to perform this before any calibration
-		 * no need to close the envlope since we are going
-		 * to load the runtime uCode later.
-		 */
-		ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
-			BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
-		if (ret)
-			return ret;
-
-	}
-
-	ret = iwl_send_calib_cfg(priv);
-	if (ret)
-		return ret;
-
-	/**
-	 * temperature offset calibration is only needed for runtime ucode,
-	 * so prepare the value now.
-	 */
-	if (priv->cfg->need_temp_offset_calib) {
-		if (priv->cfg->temp_offset_v2)
-			return iwl_set_temperature_offset_calib_v2(priv);
-		else
-			return iwl_set_temperature_offset_calib(priv);
-	}
-
-	return 0;
-}
-
-int iwl_send_wimax_coex(struct iwl_priv *priv)
-{
-	struct iwl_wimax_coex_cmd coex_cmd;
-
-	/* coexistence is disabled */
-	memset(&coex_cmd, 0, sizeof(coex_cmd));
-
-	return iwl_dvm_send_cmd_pdu(priv,
-				COEX_PRIORITY_TABLE_CMD, CMD_SYNC,
-				sizeof(coex_cmd), &coex_cmd);
-}
-
-static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
-	((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-	((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-		(1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-	((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-	((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-		(1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-	((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-	((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-		(1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-	((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-	((BT_COEX_PRIO_TBL_PRIO_COEX_OFF << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-	((BT_COEX_PRIO_TBL_PRIO_COEX_ON << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-	0, 0, 0, 0, 0, 0, 0
-};
-
-void iwl_send_prio_tbl(struct iwl_priv *priv)
-{
-	struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd;
-
-	memcpy(prio_tbl_cmd.prio_tbl, iwl_bt_prio_tbl,
-		sizeof(iwl_bt_prio_tbl));
-	if (iwl_dvm_send_cmd_pdu(priv,
-				REPLY_BT_COEX_PRIO_TABLE, CMD_SYNC,
-				sizeof(prio_tbl_cmd), &prio_tbl_cmd))
-		IWL_ERR(priv, "failed to send BT prio tbl command\n");
-}
-
-int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
-{
-	struct iwl_bt_coex_prot_env_cmd env_cmd;
-	int ret;
-
-	env_cmd.action = action;
-	env_cmd.type = type;
-	ret = iwl_dvm_send_cmd_pdu(priv,
-			       REPLY_BT_COEX_PROT_ENV, CMD_SYNC,
-			       sizeof(env_cmd), &env_cmd);
-	if (ret)
-		IWL_ERR(priv, "failed to send BT env command\n");
-	return ret;
-}
-
-
-static int iwl_alive_notify(struct iwl_priv *priv)
-{
-	int ret;
-
-	iwl_trans_fw_alive(priv->trans);
-
-	priv->passive_no_rx = false;
-	priv->transport_queue_stop = 0;
-
-	ret = iwl_send_wimax_coex(priv);
-	if (ret)
-		return ret;
-
-	if (!priv->cfg->no_xtal_calib) {
-		ret = iwl_set_Xtal_calib(priv);
-		if (ret)
-			return ret;
-	}
-
-	return iwl_send_calib_results(priv);
-}
-
-
-/**
- * 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 iwl_verify_sec_sparse(struct iwl_priv *priv,
-				  const struct fw_desc *fw_desc)
-{
-	__le32 *image = (__le32 *)fw_desc->v_addr;
-	u32 len = fw_desc->len;
-	u32 val;
-	u32 i;
-
-	IWL_DEBUG_FW(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->trans, HBUS_TARG_MEM_RADDR,
-			i + fw_desc->offset);
-		val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-		if (val != le32_to_cpu(*image))
-			return -EIO;
-	}
-
-	return 0;
-}
-
-static void iwl_print_mismatch_sec(struct iwl_priv *priv,
-				    const struct fw_desc *fw_desc)
-{
-	__le32 *image = (__le32 *)fw_desc->v_addr;
-	u32 len = fw_desc->len;
-	u32 val;
-	u32 offs;
-	int errors = 0;
-
-	IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
-
-	iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
-				fw_desc->offset);
-
-	for (offs = 0;
-	     offs < len && errors < 20;
-	     offs += sizeof(u32), image++) {
-		/* read data comes through single port, auto-incr addr */
-		val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-		if (val != le32_to_cpu(*image)) {
-			IWL_ERR(priv, "uCode INST section at "
-				"offset 0x%x, is 0x%x, s/b 0x%x\n",
-				offs, val, le32_to_cpu(*image));
-			errors++;
-		}
-	}
-}
-
-/**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
- *    and verify its contents
- */
-static int iwl_verify_ucode(struct iwl_priv *priv,
-			    enum iwl_ucode_type ucode_type)
-{
-	const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type);
-
-	if (!img) {
-		IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type);
-		return -EINVAL;
-	}
-
-	if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) {
-		IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
-		return 0;
-	}
-
-	IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
-
-	iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]);
-	return -EIO;
-}
-
-struct iwl_alive_data {
-	bool valid;
-	u8 subtype;
-};
-
-static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
-			 struct iwl_rx_packet *pkt, void *data)
-{
-	struct iwl_priv *priv =
-		container_of(notif_wait, struct iwl_priv, notif_wait);
-	struct iwl_alive_data *alive_data = data;
-	struct iwl_alive_resp *palive;
-
-	palive = (void *)pkt->data;
-
-	IWL_DEBUG_FW(priv, "Alive ucode status 0x%08X revision "
-		       "0x%01X 0x%01X\n",
-		       palive->is_valid, palive->ver_type,
-		       palive->ver_subtype);
-
-	priv->device_pointers.error_event_table =
-		le32_to_cpu(palive->error_event_table_ptr);
-	priv->device_pointers.log_event_table =
-		le32_to_cpu(palive->log_event_table_ptr);
-
-	alive_data->subtype = palive->ver_subtype;
-	alive_data->valid = palive->is_valid == UCODE_VALID_OK;
-
-	return true;
-}
-
-#define UCODE_ALIVE_TIMEOUT	HZ
-#define UCODE_CALIB_TIMEOUT	(2*HZ)
-
-int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
-				 enum iwl_ucode_type ucode_type)
-{
-	struct iwl_notification_wait alive_wait;
-	struct iwl_alive_data alive_data;
-	const struct fw_img *fw;
-	int ret;
-	enum iwl_ucode_type old_type;
-	static const u8 alive_cmd[] = { REPLY_ALIVE };
-
-	old_type = priv->cur_ucode;
-	priv->cur_ucode = ucode_type;
-	fw = iwl_get_ucode_image(priv, ucode_type);
-
-	priv->ucode_loaded = false;
-
-	if (!fw)
-		return -EINVAL;
-
-	iwl_init_notification_wait(&priv->notif_wait, &alive_wait,
-				   alive_cmd, ARRAY_SIZE(alive_cmd),
-				   iwl_alive_fn, &alive_data);
-
-	ret = iwl_trans_start_fw(priv->trans, fw);
-	if (ret) {
-		priv->cur_ucode = old_type;
-		iwl_remove_notification(&priv->notif_wait, &alive_wait);
-		return ret;
-	}
-
-	/*
-	 * Some things may run in the background now, but we
-	 * just wait for the ALIVE notification here.
-	 */
-	ret = iwl_wait_notification(&priv->notif_wait, &alive_wait,
-					UCODE_ALIVE_TIMEOUT);
-	if (ret) {
-		priv->cur_ucode = old_type;
-		return ret;
-	}
-
-	if (!alive_data.valid) {
-		IWL_ERR(priv, "Loaded ucode is not valid!\n");
-		priv->cur_ucode = old_type;
-		return -EIO;
-	}
-
-	/*
-	 * This step takes a long time (60-80ms!!) and
-	 * WoWLAN image should be loaded quickly, so
-	 * skip it for WoWLAN.
-	 */
-	if (ucode_type != IWL_UCODE_WOWLAN) {
-		ret = iwl_verify_ucode(priv, ucode_type);
-		if (ret) {
-			priv->cur_ucode = old_type;
-			return ret;
-		}
-
-		/* delay a bit to give rfkill time to run */
-		msleep(5);
-	}
-
-	ret = iwl_alive_notify(priv);
-	if (ret) {
-		IWL_WARN(priv,
-			"Could not complete ALIVE transition: %d\n", ret);
-		priv->cur_ucode = old_type;
-		return ret;
-	}
-
-	priv->ucode_loaded = true;
-
-	return 0;
-}
-
-static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait,
-			      struct iwl_rx_packet *pkt, void *data)
-{
-	struct iwl_priv *priv = data;
-	struct iwl_calib_hdr *hdr;
-	int len;
-
-	if (pkt->hdr.cmd != CALIBRATION_RES_NOTIFICATION) {
-		WARN_ON(pkt->hdr.cmd != CALIBRATION_COMPLETE_NOTIFICATION);
-		return true;
-	}
-
-	hdr = (struct iwl_calib_hdr *)pkt->data;
-	len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-
-	/* reduce the size by the length field itself */
-	len -= sizeof(__le32);
-
-	if (iwl_calib_set(priv, hdr, len))
-		IWL_ERR(priv, "Failed to record calibration data %d\n",
-			hdr->op_code);
-
-	return false;
-}
-
-int iwl_run_init_ucode(struct iwl_priv *priv)
-{
-	struct iwl_notification_wait calib_wait;
-	static const u8 calib_complete[] = {
-		CALIBRATION_RES_NOTIFICATION,
-		CALIBRATION_COMPLETE_NOTIFICATION
-	};
-	int ret;
-
-	lockdep_assert_held(&priv->mutex);
-
-	/* No init ucode required? Curious, but maybe ok */
-	if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len)
-		return 0;
-
-	if (priv->init_ucode_run)
-		return 0;
-
-	iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
-				   calib_complete, ARRAY_SIZE(calib_complete),
-				   iwlagn_wait_calib, priv);
-
-	/* Will also start the device */
-	ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
-	if (ret)
-		goto error;
-
-	ret = iwl_init_alive_start(priv);
-	if (ret)
-		goto error;
-
-	/*
-	 * Some things may run in the background now, but we
-	 * just wait for the calibration complete notification.
-	 */
-	ret = iwl_wait_notification(&priv->notif_wait, &calib_wait,
-					UCODE_CALIB_TIMEOUT);
-	if (!ret)
-		priv->init_ucode_run = true;
-
-	goto out;
-
- error:
-	iwl_remove_notification(&priv->notif_wait, &calib_wait);
- out:
-	/* Whatever happened, stop the device */
-	iwl_trans_stop_device(priv->trans);
-	priv->ucode_loaded = false;
-
-	return ret;
-}
diff --git a/drivers/net/wireless/iwlwifi/pcie/1000.c b/drivers/net/wireless/iwlwifi/pcie/1000.c
new file mode 100644
index 0000000..81b83f4
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/1000.c
@@ -0,0 +1,141 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2012 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.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-csr.h"
+#include "iwl-agn-hw.h"
+#include "cfg.h"
+
+/* Highest firmware API version supported */
+#define IWL1000_UCODE_API_MAX 5
+#define IWL100_UCODE_API_MAX 5
+
+/* Oldest version we won't warn about */
+#define IWL1000_UCODE_API_OK 5
+#define IWL100_UCODE_API_OK 5
+
+/* Lowest firmware API version supported */
+#define IWL1000_UCODE_API_MIN 1
+#define IWL100_UCODE_API_MIN 5
+
+/* EEPROM version */
+#define EEPROM_1000_TX_POWER_VERSION	(4)
+#define EEPROM_1000_EEPROM_VERSION	(0x15C)
+
+#define IWL1000_FW_PRE "iwlwifi-1000-"
+#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL100_FW_PRE "iwlwifi-100-"
+#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode"
+
+
+static const struct iwl_base_params iwl1000_base_params = {
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+	.max_ll_items = OTP_MAX_LL_ITEMS_1000,
+	.shadow_ram_support = false,
+	.led_compensation = 51,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.wd_timeout = IWL_WATCHDOG_DISABLED,
+	.max_event_log_size = 128,
+};
+
+static const struct iwl_ht_params iwl1000_ht_params = {
+	.ht_greenfield_support = true,
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
+	.ht40_bands = BIT(IEEE80211_BAND_2GHZ),
+};
+
+static const struct iwl_eeprom_params iwl1000_eeprom_params = {
+	.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_REG_BAND_24_HT40_CHANNELS,
+		EEPROM_REGULATORY_BAND_NO_HT40,
+	}
+};
+
+#define IWL_DEVICE_1000						\
+	.fw_name_pre = IWL1000_FW_PRE,				\
+	.ucode_api_max = IWL1000_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL1000_UCODE_API_OK,			\
+	.ucode_api_min = IWL1000_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_1000,		\
+	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
+	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_1000_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,	\
+	.base_params = &iwl1000_base_params,			\
+	.eeprom_params = &iwl1000_eeprom_params,		\
+	.led_mode = IWL_LED_BLINK
+
+const struct iwl_cfg iwl1000_bgn_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
+	IWL_DEVICE_1000,
+	.ht_params = &iwl1000_ht_params,
+};
+
+const struct iwl_cfg iwl1000_bg_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 1000 BG",
+	IWL_DEVICE_1000,
+};
+
+#define IWL_DEVICE_100						\
+	.fw_name_pre = IWL100_FW_PRE,				\
+	.ucode_api_max = IWL100_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL100_UCODE_API_OK,			\
+	.ucode_api_min = IWL100_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_100,			\
+	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
+	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_1000_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,	\
+	.base_params = &iwl1000_base_params,			\
+	.eeprom_params = &iwl1000_eeprom_params,		\
+	.led_mode = IWL_LED_RF_STATE,				\
+	.rx_with_siso_diversity = true
+
+const struct iwl_cfg iwl100_bgn_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
+	IWL_DEVICE_100,
+	.ht_params = &iwl1000_ht_params,
+};
+
+const struct iwl_cfg iwl100_bg_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 100 BG",
+	IWL_DEVICE_100,
+};
+
+MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/2000.c b/drivers/net/wireless/iwlwifi/pcie/2000.c
new file mode 100644
index 0000000..fd4e78f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/2000.c
@@ -0,0 +1,243 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2012 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.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+#include "cfg.h"
+#include "dvm/commands.h" /* needed for BT for now */
+
+/* Highest firmware API version supported */
+#define IWL2030_UCODE_API_MAX 6
+#define IWL2000_UCODE_API_MAX 6
+#define IWL105_UCODE_API_MAX 6
+#define IWL135_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL2030_UCODE_API_OK 6
+#define IWL2000_UCODE_API_OK 6
+#define IWL105_UCODE_API_OK 6
+#define IWL135_UCODE_API_OK 6
+
+/* Lowest firmware API version supported */
+#define IWL2030_UCODE_API_MIN 5
+#define IWL2000_UCODE_API_MIN 5
+#define IWL105_UCODE_API_MIN 5
+#define IWL135_UCODE_API_MIN 5
+
+/* EEPROM version */
+#define EEPROM_2000_TX_POWER_VERSION	(6)
+#define EEPROM_2000_EEPROM_VERSION	(0x805)
+
+
+#define IWL2030_FW_PRE "iwlwifi-2030-"
+#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode"
+
+#define IWL2000_FW_PRE "iwlwifi-2000-"
+#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL105_FW_PRE "iwlwifi-105-"
+#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode"
+
+#define IWL135_FW_PRE "iwlwifi-135-"
+#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl2000_base_params = {
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.pll_cfg_val = 0,
+	.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
+	.shadow_ram_support = true,
+	.led_compensation = 51,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.wd_timeout = IWL_DEF_WD_TIMEOUT,
+	.max_event_log_size = 512,
+	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+	.hd_v2 = true,
+};
+
+
+static const struct iwl_base_params iwl2030_base_params = {
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.pll_cfg_val = 0,
+	.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
+	.shadow_ram_support = true,
+	.led_compensation = 57,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.wd_timeout = IWL_LONG_WD_TIMEOUT,
+	.max_event_log_size = 512,
+	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+	.hd_v2 = true,
+};
+
+static const struct iwl_ht_params iwl2000_ht_params = {
+	.ht_greenfield_support = true,
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
+	.ht40_bands = BIT(IEEE80211_BAND_2GHZ),
+};
+
+static const struct iwl_bt_params iwl2030_bt_params = {
+	/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+	.advanced_bt_coexist = true,
+	.agg_time_limit = BT_AGG_THRESHOLD_DEF,
+	.bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+	.bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
+	.bt_sco_disable = true,
+	.bt_session_2 = true,
+};
+
+static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
+	.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_REGULATORY_BAND_NO_HT40,
+	},
+	.enhanced_txpower = true,
+};
+
+#define IWL_DEVICE_2000						\
+	.fw_name_pre = IWL2000_FW_PRE,				\
+	.ucode_api_max = IWL2000_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL2000_UCODE_API_OK,			\
+	.ucode_api_min = IWL2000_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_2000,		\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
+	.base_params = &iwl2000_base_params,			\
+	.eeprom_params = &iwl20x0_eeprom_params,		\
+	.need_temp_offset_calib = true,				\
+	.temp_offset_v2 = true,					\
+	.led_mode = IWL_LED_RF_STATE
+
+const struct iwl_cfg iwl2000_2bgn_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
+	IWL_DEVICE_2000,
+	.ht_params = &iwl2000_ht_params,
+};
+
+const struct iwl_cfg iwl2000_2bgn_d_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 2200D BGN",
+	IWL_DEVICE_2000,
+	.ht_params = &iwl2000_ht_params,
+};
+
+#define IWL_DEVICE_2030						\
+	.fw_name_pre = IWL2030_FW_PRE,				\
+	.ucode_api_max = IWL2030_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL2030_UCODE_API_OK,			\
+	.ucode_api_min = IWL2030_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_2030,		\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
+	.base_params = &iwl2030_base_params,			\
+	.bt_params = &iwl2030_bt_params,			\
+	.eeprom_params = &iwl20x0_eeprom_params,		\
+	.need_temp_offset_calib = true,				\
+	.temp_offset_v2 = true,					\
+	.led_mode = IWL_LED_RF_STATE,				\
+	.adv_pm = true
+
+const struct iwl_cfg iwl2030_2bgn_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
+	IWL_DEVICE_2030,
+	.ht_params = &iwl2000_ht_params,
+};
+
+#define IWL_DEVICE_105						\
+	.fw_name_pre = IWL105_FW_PRE,				\
+	.ucode_api_max = IWL105_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL105_UCODE_API_OK,			\
+	.ucode_api_min = IWL105_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_105,			\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
+	.base_params = &iwl2000_base_params,			\
+	.eeprom_params = &iwl20x0_eeprom_params,		\
+	.need_temp_offset_calib = true,				\
+	.temp_offset_v2 = true,					\
+	.led_mode = IWL_LED_RF_STATE,				\
+	.adv_pm = true,						\
+	.rx_with_siso_diversity = true
+
+const struct iwl_cfg iwl105_bgn_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
+	IWL_DEVICE_105,
+	.ht_params = &iwl2000_ht_params,
+};
+
+const struct iwl_cfg iwl105_bgn_d_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 105D BGN",
+	IWL_DEVICE_105,
+	.ht_params = &iwl2000_ht_params,
+};
+
+#define IWL_DEVICE_135						\
+	.fw_name_pre = IWL135_FW_PRE,				\
+	.ucode_api_max = IWL135_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL135_UCODE_API_OK,			\
+	.ucode_api_min = IWL135_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_135,			\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
+	.base_params = &iwl2030_base_params,			\
+	.bt_params = &iwl2030_bt_params,			\
+	.eeprom_params = &iwl20x0_eeprom_params,		\
+	.need_temp_offset_calib = true,				\
+	.temp_offset_v2 = true,					\
+	.led_mode = IWL_LED_RF_STATE,				\
+	.adv_pm = true,						\
+	.rx_with_siso_diversity = true
+
+const struct iwl_cfg iwl135_bgn_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
+	IWL_DEVICE_135,
+	.ht_params = &iwl2000_ht_params,
+};
+
+MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_OK));
+MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_OK));
+MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/5000.c b/drivers/net/wireless/iwlwifi/pcie/5000.c
new file mode 100644
index 0000000..d1665fa
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/5000.c
@@ -0,0 +1,180 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 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.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+#include "iwl-csr.h"
+#include "cfg.h"
+
+/* Highest firmware API version supported */
+#define IWL5000_UCODE_API_MAX 5
+#define IWL5150_UCODE_API_MAX 2
+
+/* Oldest version we won't warn about */
+#define IWL5000_UCODE_API_OK 5
+#define IWL5150_UCODE_API_OK 2
+
+/* Lowest firmware API version supported */
+#define IWL5000_UCODE_API_MIN 1
+#define IWL5150_UCODE_API_MIN 1
+
+/* EEPROM versions */
+#define EEPROM_5000_TX_POWER_VERSION	(4)
+#define EEPROM_5000_EEPROM_VERSION	(0x11A)
+#define EEPROM_5050_TX_POWER_VERSION	(4)
+#define EEPROM_5050_EEPROM_VERSION	(0x21E)
+
+#define IWL5000_FW_PRE "iwlwifi-5000-"
+#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL5150_FW_PRE "iwlwifi-5150-"
+#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl5000_base_params = {
+	.eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+	.led_compensation = 51,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.wd_timeout = IWL_WATCHDOG_DISABLED,
+	.max_event_log_size = 512,
+	.no_idle_support = true,
+};
+
+static const struct iwl_ht_params iwl5000_ht_params = {
+	.ht_greenfield_support = true,
+	.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
+static const struct iwl_eeprom_params iwl5000_eeprom_params = {
+	.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_REG_BAND_24_HT40_CHANNELS,
+		EEPROM_REG_BAND_52_HT40_CHANNELS
+	},
+};
+
+#define IWL_DEVICE_5000						\
+	.fw_name_pre = IWL5000_FW_PRE,				\
+	.ucode_api_max = IWL5000_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL5000_UCODE_API_OK,			\
+	.ucode_api_min = IWL5000_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_5000,		\
+	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
+	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,	\
+	.base_params = &iwl5000_base_params,			\
+	.eeprom_params = &iwl5000_eeprom_params,		\
+	.led_mode = IWL_LED_BLINK
+
+const struct iwl_cfg iwl5300_agn_cfg = {
+	.name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
+	IWL_DEVICE_5000,
+	/* at least EEPROM 0x11A has wrong info */
+	.valid_tx_ant = ANT_ABC,	/* .cfg overwrite */
+	.valid_rx_ant = ANT_ABC,	/* .cfg overwrite */
+	.ht_params = &iwl5000_ht_params,
+};
+
+const struct iwl_cfg iwl5100_bgn_cfg = {
+	.name = "Intel(R) WiFi Link 5100 BGN",
+	IWL_DEVICE_5000,
+	.valid_tx_ant = ANT_B,		/* .cfg overwrite */
+	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */
+	.ht_params = &iwl5000_ht_params,
+};
+
+const struct iwl_cfg iwl5100_abg_cfg = {
+	.name = "Intel(R) WiFi Link 5100 ABG",
+	IWL_DEVICE_5000,
+	.valid_tx_ant = ANT_B,		/* .cfg overwrite */
+	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */
+};
+
+const struct iwl_cfg iwl5100_agn_cfg = {
+	.name = "Intel(R) WiFi Link 5100 AGN",
+	IWL_DEVICE_5000,
+	.valid_tx_ant = ANT_B,		/* .cfg overwrite */
+	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */
+	.ht_params = &iwl5000_ht_params,
+};
+
+const struct iwl_cfg iwl5350_agn_cfg = {
+	.name = "Intel(R) WiMAX/WiFi Link 5350 AGN",
+	.fw_name_pre = IWL5000_FW_PRE,
+	.ucode_api_max = IWL5000_UCODE_API_MAX,
+	.ucode_api_ok = IWL5000_UCODE_API_OK,
+	.ucode_api_min = IWL5000_UCODE_API_MIN,
+	.device_family = IWL_DEVICE_FAMILY_5000,
+	.max_inst_size = IWLAGN_RTC_INST_SIZE,
+	.max_data_size = IWLAGN_RTC_DATA_SIZE,
+	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+	.base_params = &iwl5000_base_params,
+	.eeprom_params = &iwl5000_eeprom_params,
+	.ht_params = &iwl5000_ht_params,
+	.led_mode = IWL_LED_BLINK,
+	.internal_wimax_coex = true,
+};
+
+#define IWL_DEVICE_5150						\
+	.fw_name_pre = IWL5150_FW_PRE,				\
+	.ucode_api_max = IWL5150_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL5150_UCODE_API_OK,			\
+	.ucode_api_min = IWL5150_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_5150,		\
+	.max_inst_size = IWLAGN_RTC_INST_SIZE,			\
+	.max_data_size = IWLAGN_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,	\
+	.base_params = &iwl5000_base_params,			\
+	.eeprom_params = &iwl5000_eeprom_params,		\
+	.no_xtal_calib = true,					\
+	.led_mode = IWL_LED_BLINK,				\
+	.internal_wimax_coex = true
+
+const struct iwl_cfg iwl5150_agn_cfg = {
+	.name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
+	IWL_DEVICE_5150,
+	.ht_params = &iwl5000_ht_params,
+
+};
+
+const struct iwl_cfg iwl5150_abg_cfg = {
+	.name = "Intel(R) WiMAX/WiFi Link 5150 ABG",
+	IWL_DEVICE_5150,
+};
+
+MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/6000.c b/drivers/net/wireless/iwlwifi/pcie/6000.c
new file mode 100644
index 0000000..4a57624
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/6000.c
@@ -0,0 +1,403 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2012 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.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+#include "cfg.h"
+#include "dvm/commands.h" /* needed for BT for now */
+
+/* Highest firmware API version supported */
+#define IWL6000_UCODE_API_MAX 6
+#define IWL6050_UCODE_API_MAX 5
+#define IWL6000G2_UCODE_API_MAX 6
+#define IWL6035_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL6000_UCODE_API_OK 4
+#define IWL6000G2_UCODE_API_OK 5
+#define IWL6050_UCODE_API_OK 5
+#define IWL6000G2B_UCODE_API_OK 6
+#define IWL6035_UCODE_API_OK 6
+
+/* Lowest firmware API version supported */
+#define IWL6000_UCODE_API_MIN 4
+#define IWL6050_UCODE_API_MIN 4
+#define IWL6000G2_UCODE_API_MIN 5
+#define IWL6035_UCODE_API_MIN 6
+
+/* EEPROM versions */
+#define EEPROM_6000_TX_POWER_VERSION	(4)
+#define EEPROM_6000_EEPROM_VERSION	(0x423)
+#define EEPROM_6050_TX_POWER_VERSION	(4)
+#define EEPROM_6050_EEPROM_VERSION	(0x532)
+#define EEPROM_6150_TX_POWER_VERSION	(6)
+#define EEPROM_6150_EEPROM_VERSION	(0x553)
+#define EEPROM_6005_TX_POWER_VERSION	(6)
+#define EEPROM_6005_EEPROM_VERSION	(0x709)
+#define EEPROM_6030_TX_POWER_VERSION	(6)
+#define EEPROM_6030_EEPROM_VERSION	(0x709)
+#define EEPROM_6035_TX_POWER_VERSION	(6)
+#define EEPROM_6035_EEPROM_VERSION	(0x753)
+
+#define IWL6000_FW_PRE "iwlwifi-6000-"
+#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL6050_FW_PRE "iwlwifi-6050-"
+#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE __stringify(api) ".ucode"
+
+#define IWL6005_FW_PRE "iwlwifi-6000g2a-"
+#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE __stringify(api) ".ucode"
+
+#define IWL6030_FW_PRE "iwlwifi-6000g2b-"
+#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl6000_base_params = {
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.pll_cfg_val = 0,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.led_compensation = 51,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.wd_timeout = IWL_DEF_WD_TIMEOUT,
+	.max_event_log_size = 512,
+	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_base_params iwl6050_base_params = {
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.pll_cfg_val = 0,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
+	.shadow_ram_support = true,
+	.led_compensation = 51,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1500,
+	.wd_timeout = IWL_DEF_WD_TIMEOUT,
+	.max_event_log_size = 1024,
+	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_base_params iwl6000_g2_base_params = {
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.pll_cfg_val = 0,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.led_compensation = 57,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.wd_timeout = IWL_LONG_WD_TIMEOUT,
+	.max_event_log_size = 512,
+	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_ht_params iwl6000_ht_params = {
+	.ht_greenfield_support = true,
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
+	.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
+static const struct iwl_bt_params iwl6000_bt_params = {
+	/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+	.advanced_bt_coexist = true,
+	.agg_time_limit = BT_AGG_THRESHOLD_DEF,
+	.bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+	.bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
+	.bt_sco_disable = true,
+};
+
+static const struct iwl_eeprom_params iwl6000_eeprom_params = {
+	.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
+	},
+	.enhanced_txpower = true,
+};
+
+#define IWL_DEVICE_6005						\
+	.fw_name_pre = IWL6005_FW_PRE,				\
+	.ucode_api_max = IWL6000G2_UCODE_API_MAX,		\
+	.ucode_api_ok = IWL6000G2_UCODE_API_OK,			\
+	.ucode_api_min = IWL6000G2_UCODE_API_MIN,		\
+	.device_family = IWL_DEVICE_FAMILY_6005,		\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_6005_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION,	\
+	.base_params = &iwl6000_g2_base_params,			\
+	.eeprom_params = &iwl6000_eeprom_params,		\
+	.need_temp_offset_calib = true,				\
+	.led_mode = IWL_LED_RF_STATE
+
+const struct iwl_cfg iwl6005_2agn_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
+	IWL_DEVICE_6005,
+	.ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2abg_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6205 ABG",
+	IWL_DEVICE_6005,
+};
+
+const struct iwl_cfg iwl6005_2bg_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6205 BG",
+	IWL_DEVICE_6005,
+};
+
+const struct iwl_cfg iwl6005_2agn_sff_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6205S AGN",
+	IWL_DEVICE_6005,
+	.ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2agn_d_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6205D AGN",
+	IWL_DEVICE_6005,
+	.ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2agn_mow1_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6206 AGN",
+	IWL_DEVICE_6005,
+	.ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6207 AGN",
+	IWL_DEVICE_6005,
+	.ht_params = &iwl6000_ht_params,
+};
+
+#define IWL_DEVICE_6030						\
+	.fw_name_pre = IWL6030_FW_PRE,				\
+	.ucode_api_max = IWL6000G2_UCODE_API_MAX,		\
+	.ucode_api_ok = IWL6000G2B_UCODE_API_OK,		\
+	.ucode_api_min = IWL6000G2_UCODE_API_MIN,		\
+	.device_family = IWL_DEVICE_FAMILY_6030,		\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_6030_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,	\
+	.base_params = &iwl6000_g2_base_params,			\
+	.bt_params = &iwl6000_bt_params,			\
+	.eeprom_params = &iwl6000_eeprom_params,		\
+	.need_temp_offset_calib = true,				\
+	.led_mode = IWL_LED_RF_STATE,				\
+	.adv_pm = true						\
+
+const struct iwl_cfg iwl6030_2agn_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
+	IWL_DEVICE_6030,
+	.ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6030_2abg_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6230 ABG",
+	IWL_DEVICE_6030,
+};
+
+const struct iwl_cfg iwl6030_2bgn_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6230 BGN",
+	IWL_DEVICE_6030,
+	.ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6030_2bg_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6230 BG",
+	IWL_DEVICE_6030,
+};
+
+#define IWL_DEVICE_6035						\
+	.fw_name_pre = IWL6030_FW_PRE,				\
+	.ucode_api_max = IWL6035_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL6035_UCODE_API_OK,			\
+	.ucode_api_min = IWL6035_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_6030,		\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_6030_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,	\
+	.base_params = &iwl6000_g2_base_params,			\
+	.bt_params = &iwl6000_bt_params,			\
+	.eeprom_params = &iwl6000_eeprom_params,		\
+	.need_temp_offset_calib = true,				\
+	.led_mode = IWL_LED_RF_STATE,				\
+	.adv_pm = true
+
+const struct iwl_cfg iwl6035_2agn_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
+	IWL_DEVICE_6035,
+	.ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl1030_bgn_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
+	IWL_DEVICE_6030,
+	.ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl1030_bg_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 1030 BG",
+	IWL_DEVICE_6030,
+};
+
+const struct iwl_cfg iwl130_bgn_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 130 BGN",
+	IWL_DEVICE_6030,
+	.ht_params = &iwl6000_ht_params,
+	.rx_with_siso_diversity = true,
+};
+
+const struct iwl_cfg iwl130_bg_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N 130 BG",
+	IWL_DEVICE_6030,
+	.rx_with_siso_diversity = true,
+};
+
+/*
+ * "i": Internal configuration, use internal Power Amplifier
+ */
+#define IWL_DEVICE_6000i					\
+	.fw_name_pre = IWL6000_FW_PRE,				\
+	.ucode_api_max = IWL6000_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL6000_UCODE_API_OK,			\
+	.ucode_api_min = IWL6000_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_6000i,		\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
+	.valid_tx_ant = ANT_BC,		/* .cfg overwrite */	\
+	.valid_rx_ant = ANT_BC,		/* .cfg overwrite */	\
+	.eeprom_ver = EEPROM_6000_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,	\
+	.base_params = &iwl6000_base_params,			\
+	.eeprom_params = &iwl6000_eeprom_params,		\
+	.led_mode = IWL_LED_BLINK
+
+const struct iwl_cfg iwl6000i_2agn_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
+	IWL_DEVICE_6000i,
+	.ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6000i_2abg_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6200 ABG",
+	IWL_DEVICE_6000i,
+};
+
+const struct iwl_cfg iwl6000i_2bg_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N 6200 BG",
+	IWL_DEVICE_6000i,
+};
+
+#define IWL_DEVICE_6050						\
+	.fw_name_pre = IWL6050_FW_PRE,				\
+	.ucode_api_max = IWL6050_UCODE_API_MAX,			\
+	.ucode_api_min = IWL6050_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_6050,		\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
+	.valid_tx_ant = ANT_AB,		/* .cfg overwrite */	\
+	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */	\
+	.eeprom_ver = EEPROM_6050_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,	\
+	.base_params = &iwl6050_base_params,			\
+	.eeprom_params = &iwl6000_eeprom_params,		\
+	.led_mode = IWL_LED_BLINK,				\
+	.internal_wimax_coex = true
+
+const struct iwl_cfg iwl6050_2agn_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
+	IWL_DEVICE_6050,
+	.ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6050_2abg_cfg = {
+	.name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG",
+	IWL_DEVICE_6050,
+};
+
+#define IWL_DEVICE_6150						\
+	.fw_name_pre = IWL6050_FW_PRE,				\
+	.ucode_api_max = IWL6050_UCODE_API_MAX,			\
+	.ucode_api_min = IWL6050_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_6150,		\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
+	.eeprom_ver = EEPROM_6150_EEPROM_VERSION,		\
+	.eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION,	\
+	.base_params = &iwl6050_base_params,			\
+	.eeprom_params = &iwl6000_eeprom_params,		\
+	.led_mode = IWL_LED_BLINK,				\
+	.internal_wimax_coex = true
+
+const struct iwl_cfg iwl6150_bgn_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
+	IWL_DEVICE_6150,
+	.ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6150_bg_cfg = {
+	.name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BG",
+	IWL_DEVICE_6150,
+};
+
+const struct iwl_cfg iwl6000_3agn_cfg = {
+	.name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN",
+	.fw_name_pre = IWL6000_FW_PRE,
+	.ucode_api_max = IWL6000_UCODE_API_MAX,
+	.ucode_api_ok = IWL6000_UCODE_API_OK,
+	.ucode_api_min = IWL6000_UCODE_API_MIN,
+	.device_family = IWL_DEVICE_FAMILY_6000,
+	.max_inst_size = IWL60_RTC_INST_SIZE,
+	.max_data_size = IWL60_RTC_DATA_SIZE,
+	.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+	.base_params = &iwl6000_base_params,
+	.eeprom_params = &iwl6000_eeprom_params,
+	.ht_params = &iwl6000_ht_params,
+	.led_mode = IWL_LED_BLINK,
+};
+
+MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_OK));
+MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_OK));
+MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2B_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/cfg.h b/drivers/net/wireless/iwlwifi/pcie/cfg.h
new file mode 100644
index 0000000..82152311
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/cfg.h
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#ifndef __iwl_pci_h__
+#define __iwl_pci_h__
+
+
+/*
+ * This file declares the config structures for all devices.
+ */
+
+extern const struct iwl_cfg iwl5300_agn_cfg;
+extern const struct iwl_cfg iwl5100_agn_cfg;
+extern const struct iwl_cfg iwl5350_agn_cfg;
+extern const struct iwl_cfg iwl5100_bgn_cfg;
+extern const struct iwl_cfg iwl5100_abg_cfg;
+extern const struct iwl_cfg iwl5150_agn_cfg;
+extern const struct iwl_cfg iwl5150_abg_cfg;
+extern const struct iwl_cfg iwl6005_2agn_cfg;
+extern const struct iwl_cfg iwl6005_2abg_cfg;
+extern const struct iwl_cfg iwl6005_2bg_cfg;
+extern const struct iwl_cfg iwl6005_2agn_sff_cfg;
+extern const struct iwl_cfg iwl6005_2agn_d_cfg;
+extern const struct iwl_cfg iwl6005_2agn_mow1_cfg;
+extern const struct iwl_cfg iwl6005_2agn_mow2_cfg;
+extern const struct iwl_cfg iwl1030_bgn_cfg;
+extern const struct iwl_cfg iwl1030_bg_cfg;
+extern const struct iwl_cfg iwl6030_2agn_cfg;
+extern const struct iwl_cfg iwl6030_2abg_cfg;
+extern const struct iwl_cfg iwl6030_2bgn_cfg;
+extern const struct iwl_cfg iwl6030_2bg_cfg;
+extern const struct iwl_cfg iwl6000i_2agn_cfg;
+extern const struct iwl_cfg iwl6000i_2abg_cfg;
+extern const struct iwl_cfg iwl6000i_2bg_cfg;
+extern const struct iwl_cfg iwl6000_3agn_cfg;
+extern const struct iwl_cfg iwl6050_2agn_cfg;
+extern const struct iwl_cfg iwl6050_2abg_cfg;
+extern const struct iwl_cfg iwl6150_bgn_cfg;
+extern const struct iwl_cfg iwl6150_bg_cfg;
+extern const struct iwl_cfg iwl1000_bgn_cfg;
+extern const struct iwl_cfg iwl1000_bg_cfg;
+extern const struct iwl_cfg iwl100_bgn_cfg;
+extern const struct iwl_cfg iwl100_bg_cfg;
+extern const struct iwl_cfg iwl130_bgn_cfg;
+extern const struct iwl_cfg iwl130_bg_cfg;
+extern const struct iwl_cfg iwl2000_2bgn_cfg;
+extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
+extern const struct iwl_cfg iwl2030_2bgn_cfg;
+extern const struct iwl_cfg iwl6035_2agn_cfg;
+extern const struct iwl_cfg iwl105_bgn_cfg;
+extern const struct iwl_cfg iwl105_bgn_d_cfg;
+extern const struct iwl_cfg iwl135_bgn_cfg;
+
+#endif /* __iwl_pci_h__ */
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
new file mode 100644
index 0000000..f4c3500
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -0,0 +1,380 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pci-aspm.h>
+
+#include "iwl-trans.h"
+#include "iwl-drv.h"
+#include "iwl-trans.h"
+
+#include "cfg.h"
+#include "internal.h"
+
+#define IWL_PCI_DEVICE(dev, subdev, cfg) \
+	.vendor = PCI_VENDOR_ID_INTEL,  .device = (dev), \
+	.subvendor = PCI_ANY_ID, .subdevice = (subdev), \
+	.driver_data = (kernel_ulong_t)&(cfg)
+
+/* Hardware specific file defines the PCI IDs table for that hardware module */
+static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
+	{IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1304, iwl5100_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bgn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bgn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1221, iwl5100_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1321, iwl5100_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1224, iwl5100_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1324, iwl5100_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1225, iwl5100_bgn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1325, iwl5100_bgn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1226, iwl5100_abg_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4237, 0x1211, iwl5100_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4237, 0x1311, iwl5100_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4237, 0x1214, iwl5100_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4237, 0x1314, iwl5100_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4237, 0x1215, iwl5100_bgn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4237, 0x1315, iwl5100_bgn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4237, 0x1316, iwl5100_abg_cfg)}, /* Half Mini Card */
+
+/* 5300 Series WiFi */
+	{IWL_PCI_DEVICE(0x4235, 0x1021, iwl5300_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4235, 0x1121, iwl5300_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4235, 0x1024, iwl5300_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4235, 0x1124, iwl5300_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4235, 0x1001, iwl5300_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4235, 0x1101, iwl5300_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4235, 0x1004, iwl5300_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4235, 0x1104, iwl5300_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4236, 0x1011, iwl5300_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4236, 0x1111, iwl5300_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x4236, 0x1014, iwl5300_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x4236, 0x1114, iwl5300_agn_cfg)}, /* Half Mini Card */
+
+/* 5350 Series WiFi/WiMax */
+	{IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, /* Mini Card */
+
+/* 5150 Series Wifi/WiMax */
+	{IWL_PCI_DEVICE(0x423C, 0x1201, iwl5150_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x423C, 0x1301, iwl5150_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x423C, 0x1206, iwl5150_abg_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
+
+	{IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
+	{IWL_PCI_DEVICE(0x423D, 0x1216, iwl5150_abg_cfg)}, /* Mini Card */
+	{IWL_PCI_DEVICE(0x423D, 0x1316, iwl5150_abg_cfg)}, /* Half Mini Card */
+
+/* 6x00 Series */
+	{IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)},
+	{IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)},
+	{IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x422C, 0x1306, iwl6000i_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x422C, 0x1307, iwl6000i_2bg_cfg)},
+	{IWL_PCI_DEVICE(0x422C, 0x1321, iwl6000i_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x422C, 0x1326, iwl6000i_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x4238, 0x1111, iwl6000_3agn_cfg)},
+	{IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
+
+/* 6x05 Series */
+	{IWL_PCI_DEVICE(0x0082, 0x1301, iwl6005_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1306, iwl6005_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1307, iwl6005_2bg_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1321, iwl6005_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1326, iwl6005_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)},
+	{IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x4820, iwl6005_2agn_d_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_mow1_cfg)},/* low 5GHz active */
+	{IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_mow2_cfg)},/* high 5GHz active */
+
+/* 6x30 Series */
+	{IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x008A, 0x5307, iwl1030_bg_cfg)},
+	{IWL_PCI_DEVICE(0x008A, 0x5325, iwl1030_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x008A, 0x5327, iwl1030_bg_cfg)},
+	{IWL_PCI_DEVICE(0x008B, 0x5315, iwl1030_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x008B, 0x5317, iwl1030_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0090, 0x5211, iwl6030_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0090, 0x5215, iwl6030_2bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0090, 0x5216, iwl6030_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5201, iwl6030_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5205, iwl6030_2bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5206, iwl6030_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5207, iwl6030_2bg_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5221, iwl6030_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5225, iwl6030_2bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5226, iwl6030_2abg_cfg)},
+
+/* 6x50 WiFi/WiMax Series */
+	{IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
+
+/* 6150 WiFi/WiMax Series */
+	{IWL_PCI_DEVICE(0x0885, 0x1305, iwl6150_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0885, 0x1307, iwl6150_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0885, 0x1325, iwl6150_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0885, 0x1327, iwl6150_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0886, 0x1315, iwl6150_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0886, 0x1317, iwl6150_bg_cfg)},
+
+/* 1000 Series WiFi */
+	{IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0083, 0x1305, iwl1000_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0083, 0x1225, iwl1000_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0083, 0x1325, iwl1000_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0084, 0x1215, iwl1000_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0084, 0x1315, iwl1000_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0083, 0x1206, iwl1000_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0083, 0x1306, iwl1000_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0083, 0x1226, iwl1000_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0083, 0x1326, iwl1000_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0084, 0x1216, iwl1000_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0084, 0x1316, iwl1000_bg_cfg)},
+
+/* 100 Series WiFi */
+	{IWL_PCI_DEVICE(0x08AE, 0x1005, iwl100_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)},
+	{IWL_PCI_DEVICE(0x08AF, 0x1015, iwl100_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x08AF, 0x1017, iwl100_bg_cfg)},
+	{IWL_PCI_DEVICE(0x08AE, 0x1025, iwl100_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x08AE, 0x1027, iwl100_bg_cfg)},
+
+/* 130 Series WiFi */
+	{IWL_PCI_DEVICE(0x0896, 0x5005, iwl130_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0896, 0x5007, iwl130_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0897, 0x5015, iwl130_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0897, 0x5017, iwl130_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0896, 0x5025, iwl130_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0896, 0x5027, iwl130_bg_cfg)},
+
+/* 2x00 Series */
+	{IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0890, 0x4822, iwl2000_2bgn_d_cfg)},
+
+/* 2x30 Series */
+	{IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)},
+
+/* 6x35 Series */
+	{IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)},
+
+/* 105 Series */
+	{IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0894, 0x0822, iwl105_bgn_d_cfg)},
+
+/* 135 Series */
+	{IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)},
+
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
+
+/* PCI registers */
+#define PCI_CFG_RETRY_TIMEOUT	0x041
+
+#ifndef CONFIG_IWLWIFI_IDI
+
+static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
+	struct iwl_trans *iwl_trans;
+	struct iwl_trans_pcie *trans_pcie;
+
+	iwl_trans = iwl_trans_pcie_alloc(pdev, ent, cfg);
+	if (iwl_trans == NULL)
+		return -ENOMEM;
+
+	pci_set_drvdata(pdev, iwl_trans);
+
+	trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
+	trans_pcie->drv = iwl_drv_start(iwl_trans, cfg);
+	if (!trans_pcie->drv)
+		goto out_free_trans;
+
+	return 0;
+
+out_free_trans:
+	iwl_trans_pcie_free(iwl_trans);
+	pci_set_drvdata(pdev, NULL);
+	return -EFAULT;
+}
+
+static void __devexit iwl_pci_remove(struct pci_dev *pdev)
+{
+	struct iwl_trans *trans = pci_get_drvdata(pdev);
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	iwl_drv_stop(trans_pcie->drv);
+	iwl_trans_pcie_free(trans);
+
+	pci_set_drvdata(pdev, NULL);
+}
+
+#endif /* CONFIG_IWLWIFI_IDI */
+
+#ifdef CONFIG_PM_SLEEP
+
+static int iwl_pci_suspend(struct device *device)
+{
+	struct pci_dev *pdev = to_pci_dev(device);
+	struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
+
+	/* Before you put code here, think about WoWLAN. You cannot check here
+	 * whether WoWLAN is enabled or not, and your code will run even if
+	 * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx.
+	 */
+
+	return iwl_trans_suspend(iwl_trans);
+}
+
+static int iwl_pci_resume(struct device *device)
+{
+	struct pci_dev *pdev = to_pci_dev(device);
+	struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
+
+	/* Before you put code here, think about WoWLAN. You cannot check here
+	 * whether WoWLAN is enabled or not, and your code will run even if
+	 * WoWLAN is enabled - the NIC may be alive.
+	 */
+
+	/*
+	 * We disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state.
+	 */
+	pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
+
+	return iwl_trans_resume(iwl_trans);
+}
+
+static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
+
+#define IWL_PM_OPS	(&iwl_dev_pm_ops)
+
+#else
+
+#define IWL_PM_OPS	NULL
+
+#endif
+
+#ifdef CONFIG_IWLWIFI_IDI
+/*
+ * Defined externally in iwl-idi.c
+ */
+int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+void __devexit iwl_pci_remove(struct pci_dev *pdev);
+
+#endif /* CONFIG_IWLWIFI_IDI */
+
+static struct pci_driver iwl_pci_driver = {
+	.name = DRV_NAME,
+	.id_table = iwl_hw_card_ids,
+	.probe = iwl_pci_probe,
+	.remove = __devexit_p(iwl_pci_remove),
+	.driver.pm = IWL_PM_OPS,
+};
+
+int __must_check iwl_pci_register_driver(void)
+{
+	int ret;
+	ret = pci_register_driver(&iwl_pci_driver);
+	if (ret)
+		pr_err("Unable to initialize PCI module\n");
+
+	return ret;
+}
+
+void iwl_pci_unregister_driver(void)
+{
+	pci_unregister_driver(&iwl_pci_driver);
+}
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
new file mode 100644
index 0000000..5024fb6
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -0,0 +1,440 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#ifndef __iwl_trans_int_pcie_h__
+#define __iwl_trans_int_pcie_h__
+
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+#include <linux/wait.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+
+#include "iwl-fh.h"
+#include "iwl-csr.h"
+#include "iwl-trans.h"
+#include "iwl-debug.h"
+#include "iwl-io.h"
+#include "iwl-op-mode.h"
+
+struct iwl_host_cmd;
+
+/*This file includes the declaration that are internal to the
+ * trans_pcie layer */
+
+struct iwl_rx_mem_buffer {
+	dma_addr_t page_dma;
+	struct page *page;
+	struct list_head list;
+};
+
+/**
+ * struct isr_statistics - interrupt statistics
+ *
+ */
+struct isr_statistics {
+	u32 hw;
+	u32 sw;
+	u32 err_code;
+	u32 sch;
+	u32 alive;
+	u32 rfkill;
+	u32 ctkill;
+	u32 wakeup;
+	u32 rx;
+	u32 tx;
+	u32 unhandled;
+};
+
+/**
+ * struct iwl_rx_queue - Rx queue
+ * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
+ * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
+ * @pool:
+ * @queue:
+ * @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
+ * @write_actual:
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
+ * @need_update: flag to indicate we need to update read/write index
+ * @rb_stts: driver's pointer to receive buffer status
+ * @rb_stts_dma: bus address of receive buffer status
+ * @lock:
+ *
+ * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
+ */
+struct iwl_rx_queue {
+	__le32 *bd;
+	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;
+	u32 write;
+	u32 free_count;
+	u32 write_actual;
+	struct list_head rx_free;
+	struct list_head rx_used;
+	int need_update;
+	struct iwl_rb_status *rb_stts;
+	dma_addr_t rb_stts_dma;
+	spinlock_t lock;
+};
+
+struct iwl_dma_ptr {
+	dma_addr_t dma;
+	void *addr;
+	size_t size;
+};
+
+/**
+ * iwl_queue_inc_wrap - increment queue index, wrap back to beginning
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl_queue_inc_wrap(int index, int n_bd)
+{
+	return ++index & (n_bd - 1);
+}
+
+/**
+ * iwl_queue_dec_wrap - decrement queue index, wrap back to end
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+	return --index & (n_bd - 1);
+}
+
+struct iwl_cmd_meta {
+	/* only for SYNC commands, iff the reply skb is wanted */
+	struct iwl_host_cmd *source;
+
+	DEFINE_DMA_UNMAP_ADDR(mapping);
+	DEFINE_DMA_UNMAP_LEN(len);
+
+	u32 flags;
+};
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues.
+ *
+ * Note the difference between n_bd and n_window: the hardware
+ * always assumes 256 descriptors, so n_bd is always 256 (unless
+ * there might be HW changes in the future). For the normal TX
+ * queues, n_window, which is the size of the software queue data
+ * is also 256; however, for the command queue, n_window is only
+ * 32 since we don't need so many commands pending. Since the HW
+ * still uses 256 BDs for DMA though, n_bd stays 256. As a result,
+ * the software buffers (in the variables @meta, @txb in struct
+ * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds
+ * in the same struct) have 256.
+ * This means that we end up with the following:
+ *  HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
+ *  SW entries:           | 0      | ... | 31          |
+ * where N is a number between 0 and 7. This means that the SW
+ * data is a window overlayed over the HW queue.
+ */
+struct iwl_queue {
+	int n_bd;              /* number of BDs in this queue */
+	int write_ptr;       /* 1-st empty entry (index) host_w*/
+	int read_ptr;         /* last used entry (index) host_r*/
+	/* use for monitoring and recovering the stuck queue */
+	dma_addr_t dma_addr;   /* physical addr for BD's */
+	int n_window;	       /* safe queue window */
+	u32 id;
+	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 */
+};
+
+#define TFD_TX_CMD_SLOTS 256
+#define TFD_CMD_SLOTS 32
+
+struct iwl_pcie_tx_queue_entry {
+	struct iwl_device_cmd *cmd;
+	struct sk_buff *skb;
+	struct iwl_cmd_meta meta;
+};
+
+/**
+ * struct iwl_tx_queue - Tx Queue for DMA
+ * @q: generic Rx/Tx queue descriptor
+ * @tfds: transmit frame descriptors (DMA memory)
+ * @entries: transmit entries (driver state)
+ * @lock: queue lock
+ * @stuck_timer: timer that fires if queue gets stuck
+ * @trans_pcie: pointer back to transport (for timer)
+ * @need_update: indicates need to update read/write index
+ * @active: stores if queue is active
+ *
+ * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
+ * descriptors) and required locking structures.
+ */
+struct iwl_tx_queue {
+	struct iwl_queue q;
+	struct iwl_tfd *tfds;
+	struct iwl_pcie_tx_queue_entry *entries;
+	spinlock_t lock;
+	struct timer_list stuck_timer;
+	struct iwl_trans_pcie *trans_pcie;
+	u8 need_update;
+	u8 active;
+};
+
+/**
+ * struct iwl_trans_pcie - PCIe transport specific data
+ * @rxq: all the RX queue data
+ * @rx_replenish: work that will be called when buffers need to be allocated
+ * @drv - pointer to iwl_drv
+ * @trans: pointer to the generic transport area
+ * @irq - the irq number for the device
+ * @irq_requested: true when the irq has been requested
+ * @scd_base_addr: scheduler sram base address in SRAM
+ * @scd_bc_tbls: pointer to the byte count table of the scheduler
+ * @kw: keep warm address
+ * @pci_dev: basic pci-network driver stuff
+ * @hw_base: pci hardware address support
+ * @ucode_write_complete: indicates that the ucode has been copied.
+ * @ucode_write_waitq: wait queue for uCode load
+ * @status - transport specific status flags
+ * @cmd_queue - command queue number
+ * @rx_buf_size_8k: 8 kB RX buffer size
+ * @rx_page_order: page order for receive buffer size
+ * @wd_timeout: queue watchdog timeout (jiffies)
+ */
+struct iwl_trans_pcie {
+	struct iwl_rx_queue rxq;
+	struct work_struct rx_replenish;
+	struct iwl_trans *trans;
+	struct iwl_drv *drv;
+
+	/* INT ICT Table */
+	__le32 *ict_tbl;
+	dma_addr_t ict_tbl_dma;
+	int ict_index;
+	u32 inta;
+	bool use_ict;
+	bool irq_requested;
+	struct tasklet_struct irq_tasklet;
+	struct isr_statistics isr_stats;
+
+	unsigned int irq;
+	spinlock_t irq_lock;
+	u32 inta_mask;
+	u32 scd_base_addr;
+	struct iwl_dma_ptr scd_bc_tbls;
+	struct iwl_dma_ptr kw;
+
+	struct iwl_tx_queue *txq;
+	unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
+	unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
+
+	/* PCI bus related data */
+	struct pci_dev *pci_dev;
+	void __iomem *hw_base;
+
+	bool ucode_write_complete;
+	wait_queue_head_t ucode_write_waitq;
+	unsigned long status;
+	u8 cmd_queue;
+	u8 n_no_reclaim_cmds;
+	u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
+	u8 setup_q_to_fifo[IWL_MAX_HW_QUEUES];
+	u8 n_q_to_fifo;
+
+	bool rx_buf_size_8k;
+	u32 rx_page_order;
+
+	const char **command_names;
+
+	/* queue watchdog */
+	unsigned long wd_timeout;
+};
+
+/*****************************************************
+* DRIVER STATUS FUNCTIONS
+******************************************************/
+#define STATUS_HCMD_ACTIVE	0
+#define STATUS_DEVICE_ENABLED	1
+#define STATUS_TPOWER_PMI	2
+#define STATUS_INT_ENABLED	3
+
+#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
+	((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))
+
+static inline struct iwl_trans *
+iwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie)
+{
+	return container_of((void *)trans_pcie, struct iwl_trans,
+			    trans_specific);
+}
+
+struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
+				       const struct pci_device_id *ent,
+				       const struct iwl_cfg *cfg);
+void iwl_trans_pcie_free(struct iwl_trans *trans);
+
+/*****************************************************
+* RX
+******************************************************/
+void iwl_bg_rx_replenish(struct work_struct *data);
+void iwl_irq_tasklet(struct iwl_trans *trans);
+void iwlagn_rx_replenish(struct iwl_trans *trans);
+void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
+				   struct iwl_rx_queue *q);
+
+/*****************************************************
+* ICT
+******************************************************/
+void iwl_reset_ict(struct iwl_trans *trans);
+void iwl_disable_ict(struct iwl_trans *trans);
+int iwl_alloc_isr_ict(struct iwl_trans *trans);
+void iwl_free_isr_ict(struct iwl_trans *trans);
+irqreturn_t iwl_isr_ict(int irq, void *data);
+
+/*****************************************************
+* TX / HCMD
+******************************************************/
+void iwl_txq_update_write_ptr(struct iwl_trans *trans,
+			      struct iwl_tx_queue *txq);
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
+				 struct iwl_tx_queue *txq,
+				 dma_addr_t addr, u16 len, u8 reset);
+int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id);
+int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
+void iwl_tx_cmd_complete(struct iwl_trans *trans,
+			 struct iwl_rx_cmd_buffer *rxb, int handler_status);
+void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
+				       struct iwl_tx_queue *txq,
+				       u16 byte_cnt);
+void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
+			       int sta_id, int tid, int frame_limit, u16 ssn);
+void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue);
+void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+		      enum dma_data_direction dma_dir);
+int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
+			 struct sk_buff_head *skbs);
+int iwl_queue_space(const struct iwl_queue *q);
+
+/*****************************************************
+* Error handling
+******************************************************/
+int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display);
+void iwl_dump_csr(struct iwl_trans *trans);
+
+/*****************************************************
+* Helpers
+******************************************************/
+static inline void iwl_disable_interrupts(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
+
+	/* disable interrupts from uCode/NIC to host */
+	iwl_write32(trans, CSR_INT_MASK, 0x00000000);
+
+	/* acknowledge/clear/reset any interrupts still pending
+	 * from uCode or flow handler (Rx/Tx DMA) */
+	iwl_write32(trans, CSR_INT, 0xffffffff);
+	iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff);
+	IWL_DEBUG_ISR(trans, "Disabled interrupts\n");
+}
+
+static inline void iwl_enable_interrupts(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
+	set_bit(STATUS_INT_ENABLED, &trans_pcie->status);
+	iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
+}
+
+static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
+{
+	IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
+	iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
+}
+
+static inline void iwl_wake_queue(struct iwl_trans *trans,
+				  struct iwl_tx_queue *txq)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	if (test_and_clear_bit(txq->q.id, trans_pcie->queue_stopped)) {
+		IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d\n", txq->q.id);
+		iwl_op_mode_queue_not_full(trans->op_mode, txq->q.id);
+	}
+}
+
+static inline void iwl_stop_queue(struct iwl_trans *trans,
+				  struct iwl_tx_queue *txq)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	if (!test_and_set_bit(txq->q.id, trans_pcie->queue_stopped)) {
+		iwl_op_mode_queue_full(trans->op_mode, txq->q.id);
+		IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d\n", txq->q.id);
+	} else
+		IWL_DEBUG_TX_QUEUES(trans, "hwq %d already stopped\n",
+				    txq->q.id);
+}
+
+static inline int iwl_queue_used(const struct iwl_queue *q, int i)
+{
+	return q->write_ptr >= q->read_ptr ?
+		(i >= q->read_ptr && i < q->write_ptr) :
+		!(i < q->read_ptr && i >= q->write_ptr);
+}
+
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
+{
+	return index & (q->n_window - 1);
+}
+
+static inline const char *
+trans_pcie_get_cmd_string(struct iwl_trans_pcie *trans_pcie, u8 cmd)
+{
+	if (!trans_pcie->command_names || !trans_pcie->command_names[cmd])
+		return "UNKNOWN";
+	return trans_pcie->command_names[cmd];
+}
+
+static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
+{
+	return !(iwl_read32(trans, CSR_GP_CNTRL) &
+		CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
+}
+
+#endif /* __iwl_trans_int_pcie_h__ */
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
new file mode 100644
index 0000000..be143eb
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -0,0 +1,1056 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/gfp.h>
+
+#include "iwl-prph.h"
+#include "iwl-io.h"
+#include "internal.h"
+#include "iwl-op-mode.h"
+
+#ifdef CONFIG_IWLWIFI_IDI
+#include "iwl-amfh.h"
+#endif
+
+/******************************************************************************
+ *
+ * RX path functions
+ *
+ ******************************************************************************/
+
+/*
+ * Rx theory of operation
+ *
+ * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
+ * each of which point to Receive Buffers to be filled by the NIC.  These get
+ * used not only for Rx frames, but for any command response or notification
+ * from the NIC.  The driver and NIC manage the Rx buffers by means
+ * of indexes into the circular buffer.
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization, the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer, it will advance the READ index
+ * and fire the RX interrupt.  The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
+ *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ *   to replenish the iwl->rxq->rx_free.
+ * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ *   iwl->rxq is replenished and the READ INDEX is updated (updating the
+ *   'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ *   detached from the iwl->rxq.  The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
+ *   were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl_rx_queue_alloc()   Allocates rx_free
+ * iwl_rx_replenish()     Replenishes rx_free list from rx_used, and calls
+ *                            iwl_rx_queue_restock
+ * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
+ *                            queue, updates firmware pointers, and updates
+ *                            the WRITE index.  If insufficient rx_free buffers
+ *                            are available, schedules iwl_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl_rx()         Detach iwl_rx_mem_buffers from pool up to the
+ *                            READ INDEX, detaching the SKB from the pool.
+ *                            Moves the packet buffer from queue to rx_used.
+ *                            Calls iwl_rx_queue_restock to refill any empty
+ *                            slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl_rx_queue_space - Return number of free slots available in queue.
+ */
+static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+{
+	int s = q->read - q->write;
+	if (s <= 0)
+		s += RX_QUEUE_SIZE;
+	/* keep some buffer to not confuse full and empty queue */
+	s -= 2;
+	if (s < 0)
+		s = 0;
+	return s;
+}
+
+/**
+ * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ */
+void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
+				   struct iwl_rx_queue *q)
+{
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&q->lock, flags);
+
+	if (q->need_update == 0)
+		goto exit_unlock;
+
+	if (trans->cfg->base_params->shadow_reg_enable) {
+		/* shadow register enabled */
+		/* Device expects a multiple of 8 */
+		q->write_actual = (q->write & ~0x7);
+		iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, q->write_actual);
+	} else {
+		struct iwl_trans_pcie *trans_pcie =
+			IWL_TRANS_GET_PCIE_TRANS(trans);
+
+		/* If power-saving is in use, make sure device is awake */
+		if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
+			reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
+
+			if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+				IWL_DEBUG_INFO(trans,
+					"Rx queue requesting wakeup,"
+					" GP1 = 0x%x\n", reg);
+				iwl_set_bit(trans, CSR_GP_CNTRL,
+					CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+				goto exit_unlock;
+			}
+
+			q->write_actual = (q->write & ~0x7);
+			iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
+					q->write_actual);
+
+		/* Else device is assumed to be awake */
+		} else {
+			/* Device expects a multiple of 8 */
+			q->write_actual = (q->write & ~0x7);
+			iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
+				q->write_actual);
+		}
+	}
+	q->need_update = 0;
+
+ exit_unlock:
+	spin_unlock_irqrestore(&q->lock, flags);
+}
+
+/**
+ * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
+ */
+static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr)
+{
+	return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+/**
+ * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can, pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+	struct list_head *element;
+	struct iwl_rx_mem_buffer *rxb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rxq->lock, flags);
+	while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+		/* The overwritten rxb must be a used one */
+		rxb = rxq->queue[rxq->write];
+		BUG_ON(rxb && rxb->page);
+
+		/* Get next free Rx buffer, remove from free list */
+		element = rxq->rx_free.next;
+		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		list_del(element);
+
+		/* Point to Rx buffer via next RBD in circular buffer */
+		rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma);
+		rxq->queue[rxq->write] = rxb;
+		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+		rxq->free_count--;
+	}
+	spin_unlock_irqrestore(&rxq->lock, flags);
+	/* If the pre-allocated buffer pool is dropping low, schedule to
+	 * refill it */
+	if (rxq->free_count <= RX_LOW_WATERMARK)
+		schedule_work(&trans_pcie->rx_replenish);
+
+
+	/* If we've added more space for the firmware to place data, tell it.
+	 * Increment device's write pointer in multiples of 8. */
+	if (rxq->write_actual != (rxq->write & ~0x7)) {
+		spin_lock_irqsave(&rxq->lock, flags);
+		rxq->need_update = 1;
+		spin_unlock_irqrestore(&rxq->lock, flags);
+		iwl_rx_queue_update_write_ptr(trans, rxq);
+	}
+}
+
+/**
+ * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during initialization)
+ */
+static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+	struct list_head *element;
+	struct iwl_rx_mem_buffer *rxb;
+	struct page *page;
+	unsigned long flags;
+	gfp_t gfp_mask = priority;
+
+	while (1) {
+		spin_lock_irqsave(&rxq->lock, flags);
+		if (list_empty(&rxq->rx_used)) {
+			spin_unlock_irqrestore(&rxq->lock, flags);
+			return;
+		}
+		spin_unlock_irqrestore(&rxq->lock, flags);
+
+		if (rxq->free_count > RX_LOW_WATERMARK)
+			gfp_mask |= __GFP_NOWARN;
+
+		if (trans_pcie->rx_page_order > 0)
+			gfp_mask |= __GFP_COMP;
+
+		/* Alloc a new receive buffer */
+		page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
+		if (!page) {
+			if (net_ratelimit())
+				IWL_DEBUG_INFO(trans, "alloc_pages failed, "
+					   "order: %d\n",
+					   trans_pcie->rx_page_order);
+
+			if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+			    net_ratelimit())
+				IWL_CRIT(trans, "Failed to alloc_pages with %s."
+					 "Only %u free buffers remaining.\n",
+					 priority == GFP_ATOMIC ?
+					 "GFP_ATOMIC" : "GFP_KERNEL",
+					 rxq->free_count);
+			/* We don't reschedule replenish work here -- we will
+			 * call the restock method and if it still needs
+			 * more buffers it will schedule replenish */
+			return;
+		}
+
+		spin_lock_irqsave(&rxq->lock, flags);
+
+		if (list_empty(&rxq->rx_used)) {
+			spin_unlock_irqrestore(&rxq->lock, flags);
+			__free_pages(page, trans_pcie->rx_page_order);
+			return;
+		}
+		element = rxq->rx_used.next;
+		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		list_del(element);
+
+		spin_unlock_irqrestore(&rxq->lock, flags);
+
+		BUG_ON(rxb->page);
+		rxb->page = page;
+		/* Get physical address of the RB */
+		rxb->page_dma =
+			dma_map_page(trans->dev, page, 0,
+				     PAGE_SIZE << trans_pcie->rx_page_order,
+				     DMA_FROM_DEVICE);
+		/* dma address must be no more than 36 bits */
+		BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
+		/* and also 256 byte aligned! */
+		BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
+
+		spin_lock_irqsave(&rxq->lock, flags);
+
+		list_add_tail(&rxb->list, &rxq->rx_free);
+		rxq->free_count++;
+
+		spin_unlock_irqrestore(&rxq->lock, flags);
+	}
+}
+
+void iwlagn_rx_replenish(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	unsigned long flags;
+
+	iwlagn_rx_allocate(trans, GFP_KERNEL);
+
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+	iwlagn_rx_queue_restock(trans);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+}
+
+static void iwlagn_rx_replenish_now(struct iwl_trans *trans)
+{
+	iwlagn_rx_allocate(trans, GFP_ATOMIC);
+
+	iwlagn_rx_queue_restock(trans);
+}
+
+void iwl_bg_rx_replenish(struct work_struct *data)
+{
+	struct iwl_trans_pcie *trans_pcie =
+	    container_of(data, struct iwl_trans_pcie, rx_replenish);
+
+	iwlagn_rx_replenish(trans_pcie->trans);
+}
+
+static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
+				struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+	struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
+	unsigned long flags;
+	bool page_stolen = false;
+	int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
+	u32 offset = 0;
+
+	if (WARN_ON(!rxb))
+		return;
+
+	dma_unmap_page(trans->dev, rxb->page_dma, max_len, DMA_FROM_DEVICE);
+
+	while (offset + sizeof(u32) + sizeof(struct iwl_cmd_header) < max_len) {
+		struct iwl_rx_packet *pkt;
+		struct iwl_device_cmd *cmd;
+		u16 sequence;
+		bool reclaim;
+		int index, cmd_index, err, len;
+		struct iwl_rx_cmd_buffer rxcb = {
+			._offset = offset,
+			._page = rxb->page,
+			._page_stolen = false,
+			.truesize = max_len,
+		};
+
+		pkt = rxb_addr(&rxcb);
+
+		if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID))
+			break;
+
+		IWL_DEBUG_RX(trans, "cmd at offset %d: %s (0x%.2x)\n",
+			rxcb._offset,
+			trans_pcie_get_cmd_string(trans_pcie, pkt->hdr.cmd),
+			pkt->hdr.cmd);
+
+		len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+		len += sizeof(u32); /* account for status word */
+		trace_iwlwifi_dev_rx(trans->dev, pkt, len);
+
+		/* Reclaim a command buffer only if this packet is a response
+		 *   to a (driver-originated) command.
+		 * If the packet (e.g. Rx frame) originated from uCode,
+		 *   there is no command buffer to reclaim.
+		 * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+		 *   but apparently a few don't get set; catch them here. */
+		reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME);
+		if (reclaim) {
+			int i;
+
+			for (i = 0; i < trans_pcie->n_no_reclaim_cmds; i++) {
+				if (trans_pcie->no_reclaim_cmds[i] ==
+							pkt->hdr.cmd) {
+					reclaim = false;
+					break;
+				}
+			}
+		}
+
+		sequence = le16_to_cpu(pkt->hdr.sequence);
+		index = SEQ_TO_INDEX(sequence);
+		cmd_index = get_cmd_index(&txq->q, index);
+
+		if (reclaim)
+			cmd = txq->entries[cmd_index].cmd;
+		else
+			cmd = NULL;
+
+		err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
+
+		/*
+		 * After here, we should always check rxcb._page_stolen,
+		 * if it is true then one of the handlers took the page.
+		 */
+
+		if (reclaim) {
+			/* Invoke any callbacks, transfer the buffer to caller,
+			 * and fire off the (possibly) blocking
+			 * iwl_trans_send_cmd()
+			 * as we reclaim the driver command queue */
+			if (!rxcb._page_stolen)
+				iwl_tx_cmd_complete(trans, &rxcb, err);
+			else
+				IWL_WARN(trans, "Claim null rxb?\n");
+		}
+
+		page_stolen |= rxcb._page_stolen;
+		offset += ALIGN(len, FH_RSCSR_FRAME_ALIGN);
+	}
+
+	/* page was stolen from us -- free our reference */
+	if (page_stolen) {
+		__free_pages(rxb->page, trans_pcie->rx_page_order);
+		rxb->page = NULL;
+	}
+
+	/* Reuse the page if possible. For notification packets and
+	 * SKBs that fail to Rx correctly, add them back into the
+	 * rx_free list for reuse later. */
+	spin_lock_irqsave(&rxq->lock, flags);
+	if (rxb->page != NULL) {
+		rxb->page_dma =
+			dma_map_page(trans->dev, rxb->page, 0,
+				     PAGE_SIZE << trans_pcie->rx_page_order,
+				     DMA_FROM_DEVICE);
+		list_add_tail(&rxb->list, &rxq->rx_free);
+		rxq->free_count++;
+	} else
+		list_add_tail(&rxb->list, &rxq->rx_used);
+	spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/**
+ * iwl_rx_handle - Main entry function for receiving responses from uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
+ */
+static void iwl_rx_handle(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+	u32 r, i;
+	u8 fill_rx = 0;
+	u32 count = 8;
+	int total_empty;
+
+	/* uCode's read index (stored in shared DRAM) indicates the last Rx
+	 * buffer that the driver may process (last buffer filled by ucode). */
+	r = le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF;
+	i = rxq->read;
+
+	/* Rx interrupt, but nothing sent from uCode */
+	if (i == r)
+		IWL_DEBUG_RX(trans, "HW = SW = %d\n", r);
+
+	/* calculate total frames need to be restock after handling RX */
+	total_empty = r - rxq->write_actual;
+	if (total_empty < 0)
+		total_empty += RX_QUEUE_SIZE;
+
+	if (total_empty > (RX_QUEUE_SIZE / 2))
+		fill_rx = 1;
+
+	while (i != r) {
+		struct iwl_rx_mem_buffer *rxb;
+
+		rxb = rxq->queue[i];
+		rxq->queue[i] = NULL;
+
+		IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d (%p)\n",
+			     r, i, rxb);
+		iwl_rx_handle_rxbuf(trans, rxb);
+
+		i = (i + 1) & RX_QUEUE_MASK;
+		/* If there are a lot of unused frames,
+		 * restock the Rx queue so ucode wont assert. */
+		if (fill_rx) {
+			count++;
+			if (count >= 8) {
+				rxq->read = i;
+				iwlagn_rx_replenish_now(trans);
+				count = 0;
+			}
+		}
+	}
+
+	/* Backtrack one entry */
+	rxq->read = i;
+	if (fill_rx)
+		iwlagn_rx_replenish_now(trans);
+	else
+		iwlagn_rx_queue_restock(trans);
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+static void iwl_irq_handle_error(struct iwl_trans *trans)
+{
+	/* W/A for WiFi/WiMAX coex and WiMAX own the RF */
+	if (trans->cfg->internal_wimax_coex &&
+	    (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
+			     APMS_CLK_VAL_MRB_FUNC_MODE) ||
+	     (iwl_read_prph(trans, APMG_PS_CTRL_REG) &
+			    APMG_PS_CTRL_VAL_RESET_REQ))) {
+		struct iwl_trans_pcie *trans_pcie =
+			IWL_TRANS_GET_PCIE_TRANS(trans);
+
+		clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+		iwl_op_mode_wimax_active(trans->op_mode);
+		wake_up(&trans->wait_command_queue);
+		return;
+	}
+
+	iwl_dump_csr(trans);
+	iwl_dump_fh(trans, NULL, false);
+
+	iwl_op_mode_nic_error(trans->op_mode);
+}
+
+/* tasklet for iwlagn interrupt */
+void iwl_irq_tasklet(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
+	u32 inta = 0;
+	u32 handled = 0;
+	unsigned long flags;
+	u32 i;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	u32 inta_mask;
+#endif
+
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+
+	/* Ack/clear/reset pending uCode interrupts.
+	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
+	 */
+	/* There is a hardware bug in the interrupt mask function that some
+	 * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if
+	 * they are disabled in the CSR_INT_MASK register. Furthermore the
+	 * ICT interrupt handling mechanism has another bug that might cause
+	 * these unmasked interrupts fail to be detected. We workaround the
+	 * hardware bugs here by ACKing all the possible interrupts so that
+	 * interrupt coalescing can still be achieved.
+	 */
+	iwl_write32(trans, CSR_INT,
+		    trans_pcie->inta | ~trans_pcie->inta_mask);
+
+	inta = trans_pcie->inta;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_have_debug_level(IWL_DL_ISR)) {
+		/* just for debug */
+		inta_mask = iwl_read32(trans, CSR_INT_MASK);
+		IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n",
+			      inta, inta_mask);
+	}
+#endif
+
+	/* saved interrupt in inta variable now we can reset trans_pcie->inta */
+	trans_pcie->inta = 0;
+
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+	/* Now service all interrupt bits discovered above. */
+	if (inta & CSR_INT_BIT_HW_ERR) {
+		IWL_ERR(trans, "Hardware error detected.  Restarting.\n");
+
+		/* Tell the device to stop sending interrupts */
+		iwl_disable_interrupts(trans);
+
+		isr_stats->hw++;
+		iwl_irq_handle_error(trans);
+
+		handled |= CSR_INT_BIT_HW_ERR;
+
+		return;
+	}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_have_debug_level(IWL_DL_ISR)) {
+		/* NIC fires this, but we don't use it, redundant with WAKEUP */
+		if (inta & CSR_INT_BIT_SCD) {
+			IWL_DEBUG_ISR(trans, "Scheduler finished to transmit "
+				      "the frame/frames.\n");
+			isr_stats->sch++;
+		}
+
+		/* Alive notification via Rx interrupt will do the real work */
+		if (inta & CSR_INT_BIT_ALIVE) {
+			IWL_DEBUG_ISR(trans, "Alive interrupt\n");
+			isr_stats->alive++;
+		}
+	}
+#endif
+	/* Safely ignore these bits for debug checks below */
+	inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
+
+	/* HW RF KILL switch toggled */
+	if (inta & CSR_INT_BIT_RF_KILL) {
+		bool hw_rfkill;
+
+		hw_rfkill = iwl_is_rfkill_set(trans);
+		IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
+			 hw_rfkill ? "disable radio" : "enable radio");
+
+		isr_stats->rfkill++;
+
+		iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+
+		handled |= CSR_INT_BIT_RF_KILL;
+	}
+
+	/* Chip got too hot and stopped itself */
+	if (inta & CSR_INT_BIT_CT_KILL) {
+		IWL_ERR(trans, "Microcode CT kill error detected.\n");
+		isr_stats->ctkill++;
+		handled |= CSR_INT_BIT_CT_KILL;
+	}
+
+	/* Error detected by uCode */
+	if (inta & CSR_INT_BIT_SW_ERR) {
+		IWL_ERR(trans, "Microcode SW error detected. "
+			" Restarting 0x%X.\n", inta);
+		isr_stats->sw++;
+		iwl_irq_handle_error(trans);
+		handled |= CSR_INT_BIT_SW_ERR;
+	}
+
+	/* uCode wakes up after power-down sleep */
+	if (inta & CSR_INT_BIT_WAKEUP) {
+		IWL_DEBUG_ISR(trans, "Wakeup interrupt\n");
+		iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq);
+		for (i = 0; i < trans->cfg->base_params->num_of_queues; i++)
+			iwl_txq_update_write_ptr(trans,
+						 &trans_pcie->txq[i]);
+
+		isr_stats->wakeup++;
+
+		handled |= CSR_INT_BIT_WAKEUP;
+	}
+
+	/* All uCode command responses, including Tx command responses,
+	 * Rx "responses" (frame-received notification), and other
+	 * notifications from uCode come through here*/
+	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX |
+		    CSR_INT_BIT_RX_PERIODIC)) {
+		IWL_DEBUG_ISR(trans, "Rx interrupt\n");
+		if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+			handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+			iwl_write32(trans, CSR_FH_INT_STATUS,
+					CSR_FH_INT_RX_MASK);
+		}
+		if (inta & CSR_INT_BIT_RX_PERIODIC) {
+			handled |= CSR_INT_BIT_RX_PERIODIC;
+			iwl_write32(trans,
+				CSR_INT, CSR_INT_BIT_RX_PERIODIC);
+		}
+		/* Sending RX interrupt require many steps to be done in the
+		 * the device:
+		 * 1- write interrupt to current index in ICT table.
+		 * 2- dma RX frame.
+		 * 3- update RX shared data to indicate last write index.
+		 * 4- send interrupt.
+		 * This could lead to RX race, driver could receive RX interrupt
+		 * but the shared data changes does not reflect this;
+		 * periodic interrupt will detect any dangling Rx activity.
+		 */
+
+		/* Disable periodic interrupt; we use it as just a one-shot. */
+		iwl_write8(trans, CSR_INT_PERIODIC_REG,
+			    CSR_INT_PERIODIC_DIS);
+#ifdef CONFIG_IWLWIFI_IDI
+		iwl_amfh_rx_handler();
+#else
+		iwl_rx_handle(trans);
+#endif
+		/*
+		 * Enable periodic interrupt in 8 msec only if we received
+		 * real RX interrupt (instead of just periodic int), to catch
+		 * any dangling Rx interrupt.  If it was just the periodic
+		 * interrupt, there was no dangling Rx activity, and no need
+		 * to extend the periodic interrupt; one-shot is enough.
+		 */
+		if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
+			iwl_write8(trans, CSR_INT_PERIODIC_REG,
+				   CSR_INT_PERIODIC_ENA);
+
+		isr_stats->rx++;
+	}
+
+	/* This "Tx" DMA channel is used only for loading uCode */
+	if (inta & CSR_INT_BIT_FH_TX) {
+		iwl_write32(trans, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK);
+		IWL_DEBUG_ISR(trans, "uCode load interrupt\n");
+		isr_stats->tx++;
+		handled |= CSR_INT_BIT_FH_TX;
+		/* Wake up uCode load routine, now that load is complete */
+		trans_pcie->ucode_write_complete = true;
+		wake_up(&trans_pcie->ucode_write_waitq);
+	}
+
+	if (inta & ~handled) {
+		IWL_ERR(trans, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
+		isr_stats->unhandled++;
+	}
+
+	if (inta & ~(trans_pcie->inta_mask)) {
+		IWL_WARN(trans, "Disabled INTA bits 0x%08x were pending\n",
+			 inta & ~trans_pcie->inta_mask);
+	}
+
+	/* Re-enable all interrupts */
+	/* only Re-enable if disabled by irq */
+	if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status))
+		iwl_enable_interrupts(trans);
+	/* Re-enable RF_KILL if it occurred */
+	else if (handled & CSR_INT_BIT_RF_KILL)
+		iwl_enable_rfkill_int(trans);
+}
+
+/******************************************************************************
+ *
+ * ICT functions
+ *
+ ******************************************************************************/
+
+/* a device (PCI-E) page is 4096 bytes long */
+#define ICT_SHIFT	12
+#define ICT_SIZE	(1 << ICT_SHIFT)
+#define ICT_COUNT	(ICT_SIZE / sizeof(u32))
+
+/* Free dram table */
+void iwl_free_isr_ict(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	if (trans_pcie->ict_tbl) {
+		dma_free_coherent(trans->dev, ICT_SIZE,
+				  trans_pcie->ict_tbl,
+				  trans_pcie->ict_tbl_dma);
+		trans_pcie->ict_tbl = NULL;
+		trans_pcie->ict_tbl_dma = 0;
+	}
+}
+
+
+/*
+ * allocate dram shared table, it is an aligned memory
+ * block of ICT_SIZE.
+ * also reset all data related to ICT table interrupt.
+ */
+int iwl_alloc_isr_ict(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	trans_pcie->ict_tbl =
+		dma_alloc_coherent(trans->dev, ICT_SIZE,
+				   &trans_pcie->ict_tbl_dma,
+				   GFP_KERNEL);
+	if (!trans_pcie->ict_tbl)
+		return -ENOMEM;
+
+	/* just an API sanity check ... it is guaranteed to be aligned */
+	if (WARN_ON(trans_pcie->ict_tbl_dma & (ICT_SIZE - 1))) {
+		iwl_free_isr_ict(trans);
+		return -EINVAL;
+	}
+
+	IWL_DEBUG_ISR(trans, "ict dma addr %Lx\n",
+		      (unsigned long long)trans_pcie->ict_tbl_dma);
+
+	IWL_DEBUG_ISR(trans, "ict vir addr %p\n", trans_pcie->ict_tbl);
+
+	/* reset table and index to all 0 */
+	memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
+	trans_pcie->ict_index = 0;
+
+	/* add periodic RX interrupt */
+	trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
+	return 0;
+}
+
+/* Device is going up inform it about using ICT interrupt table,
+ * also we need to tell the driver to start using ICT interrupt.
+ */
+void iwl_reset_ict(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	u32 val;
+	unsigned long flags;
+
+	if (!trans_pcie->ict_tbl)
+		return;
+
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+	iwl_disable_interrupts(trans);
+
+	memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
+
+	val = trans_pcie->ict_tbl_dma >> ICT_SHIFT;
+
+	val |= CSR_DRAM_INT_TBL_ENABLE;
+	val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
+
+	IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val);
+
+	iwl_write32(trans, CSR_DRAM_INT_TBL_REG, val);
+	trans_pcie->use_ict = true;
+	trans_pcie->ict_index = 0;
+	iwl_write32(trans, CSR_INT, trans_pcie->inta_mask);
+	iwl_enable_interrupts(trans);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+}
+
+/* Device is going down disable ict interrupt usage */
+void iwl_disable_ict(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	unsigned long flags;
+
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+	trans_pcie->use_ict = false;
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+}
+
+/* legacy (non-ICT) ISR. Assumes that trans_pcie->irq_lock is held */
+static irqreturn_t iwl_isr(int irq, void *data)
+{
+	struct iwl_trans *trans = data;
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	u32 inta, inta_mask;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	u32 inta_fh;
+#endif
+
+	lockdep_assert_held(&trans_pcie->irq_lock);
+
+	if (!trans)
+		return IRQ_NONE;
+
+	trace_iwlwifi_dev_irq(trans->dev);
+
+	/* Disable (but don't clear!) interrupts here to avoid
+	 *    back-to-back ISRs and sporadic interrupts from our NIC.
+	 * If we have something to service, the tasklet will re-enable ints.
+	 * If we *don't* have something, we'll re-enable before leaving here. */
+	inta_mask = iwl_read32(trans, CSR_INT_MASK);  /* just for debug */
+	iwl_write32(trans, CSR_INT_MASK, 0x00000000);
+
+	/* Discover which interrupts are active/pending */
+	inta = iwl_read32(trans, CSR_INT);
+
+	/* Ignore interrupt if there's nothing in NIC to service.
+	 * This may be due to IRQ shared with another device,
+	 * or due to sporadic interrupts thrown from our NIC. */
+	if (!inta) {
+		IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
+		goto none;
+	}
+
+	if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+		/* Hardware disappeared. It might have already raised
+		 * an interrupt */
+		IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
+		return IRQ_HANDLED;
+	}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_have_debug_level(IWL_DL_ISR)) {
+		inta_fh = iwl_read32(trans, CSR_FH_INT_STATUS);
+		IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x, "
+			      "fh 0x%08x\n", inta, inta_mask, inta_fh);
+	}
+#endif
+
+	trans_pcie->inta |= inta;
+	/* iwl_irq_tasklet() will service interrupts and re-enable them */
+	if (likely(inta))
+		tasklet_schedule(&trans_pcie->irq_tasklet);
+	else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+		 !trans_pcie->inta)
+		iwl_enable_interrupts(trans);
+
+none:
+	/* re-enable interrupts here since we don't have anything to service. */
+	/* only Re-enable if disabled by irq  and no schedules tasklet. */
+	if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+	    !trans_pcie->inta)
+		iwl_enable_interrupts(trans);
+
+	return IRQ_NONE;
+}
+
+/* interrupt handler using ict table, with this interrupt driver will
+ * stop using INTA register to get device's interrupt, reading this register
+ * is expensive, device will write interrupts in ICT dram table, increment
+ * index then will fire interrupt to driver, driver will OR all ICT table
+ * entries from current index up to table entry with 0 value. the result is
+ * the interrupt we need to service, driver will set the entries back to 0 and
+ * set index.
+ */
+irqreturn_t iwl_isr_ict(int irq, void *data)
+{
+	struct iwl_trans *trans = data;
+	struct iwl_trans_pcie *trans_pcie;
+	u32 inta, inta_mask;
+	u32 val = 0;
+	u32 read;
+	unsigned long flags;
+
+	if (!trans)
+		return IRQ_NONE;
+
+	trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+
+	/* dram interrupt table not set yet,
+	 * use legacy interrupt.
+	 */
+	if (unlikely(!trans_pcie->use_ict)) {
+		irqreturn_t ret = iwl_isr(irq, data);
+		spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+		return ret;
+	}
+
+	trace_iwlwifi_dev_irq(trans->dev);
+
+
+	/* Disable (but don't clear!) interrupts here to avoid
+	 * back-to-back ISRs and sporadic interrupts from our NIC.
+	 * If we have something to service, the tasklet will re-enable ints.
+	 * If we *don't* have something, we'll re-enable before leaving here.
+	 */
+	inta_mask = iwl_read32(trans, CSR_INT_MASK);  /* just for debug */
+	iwl_write32(trans, CSR_INT_MASK, 0x00000000);
+
+
+	/* Ignore interrupt if there's nothing in NIC to service.
+	 * This may be due to IRQ shared with another device,
+	 * or due to sporadic interrupts thrown from our NIC. */
+	read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
+	trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, read);
+	if (!read) {
+		IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
+		goto none;
+	}
+
+	/*
+	 * Collect all entries up to the first 0, starting from ict_index;
+	 * note we already read at ict_index.
+	 */
+	do {
+		val |= read;
+		IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n",
+				trans_pcie->ict_index, read);
+		trans_pcie->ict_tbl[trans_pcie->ict_index] = 0;
+		trans_pcie->ict_index =
+			iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT);
+
+		read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
+		trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index,
+					   read);
+	} while (read);
+
+	/* We should not get this value, just ignore it. */
+	if (val == 0xffffffff)
+		val = 0;
+
+	/*
+	 * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
+	 * (bit 15 before shifting it to 31) to clear when using interrupt
+	 * coalescing. fortunately, bits 18 and 19 stay set when this happens
+	 * so we use them to decide on the real state of the Rx bit.
+	 * In order words, bit 15 is set if bit 18 or bit 19 are set.
+	 */
+	if (val & 0xC0000)
+		val |= 0x8000;
+
+	inta = (0xff & val) | ((0xff00 & val) << 16);
+	IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
+		      inta, inta_mask, val);
+
+	inta &= trans_pcie->inta_mask;
+	trans_pcie->inta |= inta;
+
+	/* iwl_irq_tasklet() will service interrupts and re-enable them */
+	if (likely(inta))
+		tasklet_schedule(&trans_pcie->irq_tasklet);
+	else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+		 !trans_pcie->inta) {
+		/* Allow interrupt if was disabled by this handler and
+		 * no tasklet was schedules, We should not enable interrupt,
+		 * tasklet will enable it.
+		 */
+		iwl_enable_interrupts(trans);
+	}
+
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+	return IRQ_HANDLED;
+
+ none:
+	/* re-enable interrupts here since we don't have anything to service.
+	 * only Re-enable if disabled by irq.
+	 */
+	if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+	    !trans_pcie->inta)
+		iwl_enable_interrupts(trans);
+
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+	return IRQ_NONE;
+}
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
new file mode 100644
index 0000000..d195083
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -0,0 +1,2219 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <linux/pci.h>
+#include <linux/pci-aspm.h>
+#include <linux/interrupt.h>
+#include <linux/debugfs.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/gfp.h>
+
+#include "iwl-drv.h"
+#include "iwl-trans.h"
+#include "iwl-csr.h"
+#include "iwl-prph.h"
+#include "iwl-agn-hw.h"
+#include "internal.h"
+/* FIXME: need to abstract out TX command (once we know what it looks like) */
+#include "dvm/commands.h"
+
+#define SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie)	\
+	(((1<<trans->cfg->base_params->num_of_queues) - 1) &\
+	(~(1<<(trans_pcie)->cmd_queue)))
+
+static int iwl_trans_rx_alloc(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+	struct device *dev = trans->dev;
+
+	memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
+
+	spin_lock_init(&rxq->lock);
+
+	if (WARN_ON(rxq->bd || rxq->rb_stts))
+		return -EINVAL;
+
+	/* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
+	rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+				      &rxq->bd_dma, GFP_KERNEL);
+	if (!rxq->bd)
+		goto err_bd;
+
+	/*Allocate the driver's pointer to receive buffer status */
+	rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
+					   &rxq->rb_stts_dma, GFP_KERNEL);
+	if (!rxq->rb_stts)
+		goto err_rb_stts;
+
+	return 0;
+
+err_rb_stts:
+	dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+			  rxq->bd, rxq->bd_dma);
+	memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+	rxq->bd = NULL;
+err_bd:
+	return -ENOMEM;
+}
+
+static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+	int i;
+
+	/* Fill the rx_used queue with _all_ of the Rx buffers */
+	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+		/* In the reset function, these buffers may have been allocated
+		 * to an SKB, so we need to unmap and free potential storage */
+		if (rxq->pool[i].page != NULL) {
+			dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
+				       PAGE_SIZE << trans_pcie->rx_page_order,
+				       DMA_FROM_DEVICE);
+			__free_pages(rxq->pool[i].page,
+				     trans_pcie->rx_page_order);
+			rxq->pool[i].page = NULL;
+		}
+		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+	}
+}
+
+static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
+				 struct iwl_rx_queue *rxq)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	u32 rb_size;
+	const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
+	u32 rb_timeout = RX_RB_TIMEOUT; /* FIXME: RX_RB_TIMEOUT for all devices? */
+
+	if (trans_pcie->rx_buf_size_8k)
+		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+	else
+		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
+	/* Stop Rx DMA */
+	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+	/* Reset driver's Rx queue write index */
+	iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+
+	/* Tell device where to find RBD circular buffer in DRAM */
+	iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+			   (u32)(rxq->bd_dma >> 8));
+
+	/* Tell device where in DRAM to update its Rx status */
+	iwl_write_direct32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+			   rxq->rb_stts_dma >> 4);
+
+	/* Enable Rx DMA
+	 * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
+	 *      the credit mechanism in 5000 HW RX FIFO
+	 * Direct rx interrupts to hosts
+	 * Rx buffer size 4 or 8k
+	 * RB timeout 0x10
+	 * 256 RBDs
+	 */
+	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+			   FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+			   FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
+			   FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+			   rb_size|
+			   (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
+			   (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
+
+	/* Set interrupt coalescing timer to default (2048 usecs) */
+	iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
+}
+
+static int iwl_rx_init(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+
+	int i, err;
+	unsigned long flags;
+
+	if (!rxq->bd) {
+		err = iwl_trans_rx_alloc(trans);
+		if (err)
+			return err;
+	}
+
+	spin_lock_irqsave(&rxq->lock, flags);
+	INIT_LIST_HEAD(&rxq->rx_free);
+	INIT_LIST_HEAD(&rxq->rx_used);
+
+	iwl_trans_rxq_free_rx_bufs(trans);
+
+	for (i = 0; i < RX_QUEUE_SIZE; i++)
+		rxq->queue[i] = NULL;
+
+	/* Set us so that we have processed and used all buffers, but have
+	 * not restocked the Rx queue with fresh buffers */
+	rxq->read = rxq->write = 0;
+	rxq->write_actual = 0;
+	rxq->free_count = 0;
+	spin_unlock_irqrestore(&rxq->lock, flags);
+
+	iwlagn_rx_replenish(trans);
+
+	iwl_trans_rx_hw_init(trans, rxq);
+
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+	rxq->need_update = 1;
+	iwl_rx_queue_update_write_ptr(trans, rxq);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+	return 0;
+}
+
+static void iwl_trans_pcie_rx_free(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+	unsigned long flags;
+
+	/*if rxq->bd is NULL, it means that nothing has been allocated,
+	 * exit now */
+	if (!rxq->bd) {
+		IWL_DEBUG_INFO(trans, "Free NULL rx context\n");
+		return;
+	}
+
+	spin_lock_irqsave(&rxq->lock, flags);
+	iwl_trans_rxq_free_rx_bufs(trans);
+	spin_unlock_irqrestore(&rxq->lock, flags);
+
+	dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
+			  rxq->bd, rxq->bd_dma);
+	memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+	rxq->bd = NULL;
+
+	if (rxq->rb_stts)
+		dma_free_coherent(trans->dev,
+				  sizeof(struct iwl_rb_status),
+				  rxq->rb_stts, rxq->rb_stts_dma);
+	else
+		IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
+	memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
+	rxq->rb_stts = NULL;
+}
+
+static int iwl_trans_rx_stop(struct iwl_trans *trans)
+{
+
+	/* stop Rx DMA */
+	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+	return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG,
+				   FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+}
+
+static int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
+				struct iwl_dma_ptr *ptr, size_t size)
+{
+	if (WARN_ON(ptr->addr))
+		return -EINVAL;
+
+	ptr->addr = dma_alloc_coherent(trans->dev, size,
+				       &ptr->dma, GFP_KERNEL);
+	if (!ptr->addr)
+		return -ENOMEM;
+	ptr->size = size;
+	return 0;
+}
+
+static void iwlagn_free_dma_ptr(struct iwl_trans *trans,
+				struct iwl_dma_ptr *ptr)
+{
+	if (unlikely(!ptr->addr))
+		return;
+
+	dma_free_coherent(trans->dev, ptr->size, ptr->addr, ptr->dma);
+	memset(ptr, 0, sizeof(*ptr));
+}
+
+static void iwl_trans_pcie_queue_stuck_timer(unsigned long data)
+{
+	struct iwl_tx_queue *txq = (void *)data;
+	struct iwl_queue *q = &txq->q;
+	struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
+	struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
+	u32 scd_sram_addr = trans_pcie->scd_base_addr +
+		SCD_TX_STTS_MEM_LOWER_BOUND + (16 * txq->q.id);
+	u8 buf[16];
+	int i;
+
+	spin_lock(&txq->lock);
+	/* check if triggered erroneously */
+	if (txq->q.read_ptr == txq->q.write_ptr) {
+		spin_unlock(&txq->lock);
+		return;
+	}
+	spin_unlock(&txq->lock);
+
+	IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id,
+		jiffies_to_msecs(trans_pcie->wd_timeout));
+	IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
+		txq->q.read_ptr, txq->q.write_ptr);
+
+	iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
+
+	iwl_print_hex_error(trans, buf, sizeof(buf));
+
+	for (i = 0; i < FH_TCSR_CHNL_NUM; i++)
+		IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", i,
+			iwl_read_direct32(trans, FH_TX_TRB_REG(i)));
+
+	for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
+		u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(i));
+		u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
+		bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
+		u32 tbl_dw =
+			iwl_read_targ_mem(trans,
+					  trans_pcie->scd_base_addr +
+					  SCD_TRANS_TBL_OFFSET_QUEUE(i));
+
+		if (i & 0x1)
+			tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
+		else
+			tbl_dw = tbl_dw & 0x0000FFFF;
+
+		IWL_ERR(trans,
+			"Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
+			i, active ? "" : "in", fifo, tbl_dw,
+			iwl_read_prph(trans,
+				      SCD_QUEUE_RDPTR(i)) & (txq->q.n_bd - 1),
+			iwl_read_prph(trans, SCD_QUEUE_WRPTR(i)));
+	}
+
+	for (i = q->read_ptr; i != q->write_ptr;
+	     i = iwl_queue_inc_wrap(i, q->n_bd)) {
+		struct iwl_tx_cmd *tx_cmd =
+			(struct iwl_tx_cmd *)txq->entries[i].cmd->payload;
+		IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
+			get_unaligned_le32(&tx_cmd->scratch));
+	}
+
+	iwl_op_mode_nic_error(trans->op_mode);
+}
+
+static int iwl_trans_txq_alloc(struct iwl_trans *trans,
+			       struct iwl_tx_queue *txq, int slots_num,
+			       u32 txq_id)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
+	int i;
+
+	if (WARN_ON(txq->entries || txq->tfds))
+		return -EINVAL;
+
+	setup_timer(&txq->stuck_timer, iwl_trans_pcie_queue_stuck_timer,
+		    (unsigned long)txq);
+	txq->trans_pcie = trans_pcie;
+
+	txq->q.n_window = slots_num;
+
+	txq->entries = kcalloc(slots_num,
+			       sizeof(struct iwl_pcie_tx_queue_entry),
+			       GFP_KERNEL);
+
+	if (!txq->entries)
+		goto error;
+
+	if (txq_id == trans_pcie->cmd_queue)
+		for (i = 0; i < slots_num; i++) {
+			txq->entries[i].cmd =
+				kmalloc(sizeof(struct iwl_device_cmd),
+					GFP_KERNEL);
+			if (!txq->entries[i].cmd)
+				goto error;
+		}
+
+	/* Circular buffer of transmit frame descriptors (TFDs),
+	 * shared with device */
+	txq->tfds = dma_alloc_coherent(trans->dev, tfd_sz,
+				       &txq->q.dma_addr, GFP_KERNEL);
+	if (!txq->tfds) {
+		IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
+		goto error;
+	}
+	txq->q.id = txq_id;
+
+	return 0;
+error:
+	if (txq->entries && txq_id == trans_pcie->cmd_queue)
+		for (i = 0; i < slots_num; i++)
+			kfree(txq->entries[i].cmd);
+	kfree(txq->entries);
+	txq->entries = NULL;
+
+	return -ENOMEM;
+
+}
+
+static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+			      int slots_num, u32 txq_id)
+{
+	int ret;
+
+	txq->need_update = 0;
+
+	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+	 * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+	/* Initialize queue's high/low-water marks, and head/tail indexes */
+	ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num,
+			txq_id);
+	if (ret)
+		return ret;
+
+	spin_lock_init(&txq->lock);
+
+	/*
+	 * Tell nic where to find circular buffer of Tx Frame Descriptors for
+	 * given Tx queue, and enable the DMA channel used for that queue.
+	 * Circular buffer (TFD queue in DRAM) physical base address */
+	iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
+			     txq->q.dma_addr >> 8);
+
+	return 0;
+}
+
+/**
+ * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
+ */
+static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+	struct iwl_queue *q = &txq->q;
+	enum dma_data_direction dma_dir;
+
+	if (!q->n_bd)
+		return;
+
+	/* In the command queue, all the TBs are mapped as BIDI
+	 * so unmap them as such.
+	 */
+	if (txq_id == trans_pcie->cmd_queue)
+		dma_dir = DMA_BIDIRECTIONAL;
+	else
+		dma_dir = DMA_TO_DEVICE;
+
+	spin_lock_bh(&txq->lock);
+	while (q->write_ptr != q->read_ptr) {
+		iwl_txq_free_tfd(trans, txq, dma_dir);
+		q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
+	}
+	spin_unlock_bh(&txq->lock);
+}
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
+ */
+static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+	struct device *dev = trans->dev;
+	int i;
+
+	if (WARN_ON(!txq))
+		return;
+
+	iwl_tx_queue_unmap(trans, txq_id);
+
+	/* De-alloc array of command/tx buffers */
+
+	if (txq_id == trans_pcie->cmd_queue)
+		for (i = 0; i < txq->q.n_window; i++)
+			kfree(txq->entries[i].cmd);
+
+	/* De-alloc circular buffer of TFDs */
+	if (txq->q.n_bd) {
+		dma_free_coherent(dev, sizeof(struct iwl_tfd) *
+				  txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+		memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
+	}
+
+	kfree(txq->entries);
+	txq->entries = NULL;
+
+	del_timer_sync(&txq->stuck_timer);
+
+	/* 0-fill queue descriptor structure */
+	memset(txq, 0, sizeof(*txq));
+}
+
+/**
+ * iwl_trans_tx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+static void iwl_trans_pcie_tx_free(struct iwl_trans *trans)
+{
+	int txq_id;
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	/* Tx queues */
+	if (trans_pcie->txq) {
+		for (txq_id = 0;
+		     txq_id < trans->cfg->base_params->num_of_queues; txq_id++)
+			iwl_tx_queue_free(trans, txq_id);
+	}
+
+	kfree(trans_pcie->txq);
+	trans_pcie->txq = NULL;
+
+	iwlagn_free_dma_ptr(trans, &trans_pcie->kw);
+
+	iwlagn_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls);
+}
+
+/**
+ * iwl_trans_tx_alloc - allocate TX context
+ * Allocate all Tx DMA structures and initialize them
+ *
+ * @param priv
+ * @return error code
+ */
+static int iwl_trans_tx_alloc(struct iwl_trans *trans)
+{
+	int ret;
+	int txq_id, slots_num;
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	u16 scd_bc_tbls_size = trans->cfg->base_params->num_of_queues *
+			sizeof(struct iwlagn_scd_bc_tbl);
+
+	/*It is not allowed to alloc twice, so warn when this happens.
+	 * We cannot rely on the previous allocation, so free and fail */
+	if (WARN_ON(trans_pcie->txq)) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls,
+				   scd_bc_tbls_size);
+	if (ret) {
+		IWL_ERR(trans, "Scheduler BC Table allocation failed\n");
+		goto error;
+	}
+
+	/* Alloc keep-warm buffer */
+	ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE);
+	if (ret) {
+		IWL_ERR(trans, "Keep Warm allocation failed\n");
+		goto error;
+	}
+
+	trans_pcie->txq = kcalloc(trans->cfg->base_params->num_of_queues,
+				  sizeof(struct iwl_tx_queue), GFP_KERNEL);
+	if (!trans_pcie->txq) {
+		IWL_ERR(trans, "Not enough memory for txq\n");
+		ret = ENOMEM;
+		goto error;
+	}
+
+	/* Alloc and init all Tx queues, including the command queue (#4/#9) */
+	for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+	     txq_id++) {
+		slots_num = (txq_id == trans_pcie->cmd_queue) ?
+					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+		ret = iwl_trans_txq_alloc(trans, &trans_pcie->txq[txq_id],
+					  slots_num, txq_id);
+		if (ret) {
+			IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	iwl_trans_pcie_tx_free(trans);
+
+	return ret;
+}
+static int iwl_tx_init(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	int ret;
+	int txq_id, slots_num;
+	unsigned long flags;
+	bool alloc = false;
+
+	if (!trans_pcie->txq) {
+		ret = iwl_trans_tx_alloc(trans);
+		if (ret)
+			goto error;
+		alloc = true;
+	}
+
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+
+	/* Turn off all Tx DMA fifos */
+	iwl_write_prph(trans, SCD_TXFACT, 0);
+
+	/* Tell NIC where to find the "keep warm" buffer */
+	iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
+			   trans_pcie->kw.dma >> 4);
+
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+	/* Alloc and init all Tx queues, including the command queue (#4/#9) */
+	for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+	     txq_id++) {
+		slots_num = (txq_id == trans_pcie->cmd_queue) ?
+					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+		ret = iwl_trans_txq_init(trans, &trans_pcie->txq[txq_id],
+					 slots_num, txq_id);
+		if (ret) {
+			IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);
+			goto error;
+		}
+	}
+
+	return 0;
+error:
+	/*Upon error, free only if we allocated something */
+	if (alloc)
+		iwl_trans_pcie_tx_free(trans);
+	return ret;
+}
+
+static void iwl_set_pwr_vmain(struct iwl_trans *trans)
+{
+/*
+ * (for documentation purposes)
+ * to set power to V_AUX, do:
+
+		if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
+			iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
+					       APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+					       ~APMG_PS_CTRL_MSK_PWR_SRC);
+ */
+
+	iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
+			       APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+			       ~APMG_PS_CTRL_MSK_PWR_SRC);
+}
+
+/* PCI registers */
+#define PCI_CFG_RETRY_TIMEOUT	0x041
+#define PCI_CFG_LINK_CTRL_VAL_L0S_EN	0x01
+#define PCI_CFG_LINK_CTRL_VAL_L1_EN	0x02
+
+static u16 iwl_pciexp_link_ctrl(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	int pos;
+	u16 pci_lnk_ctl;
+
+	struct pci_dev *pci_dev = trans_pcie->pci_dev;
+
+	pos = pci_pcie_cap(pci_dev);
+	pci_read_config_word(pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
+	return pci_lnk_ctl;
+}
+
+static void iwl_apm_config(struct iwl_trans *trans)
+{
+	/*
+	 * HW bug W/A for instability in PCIe bus L0S->L1 transition.
+	 * Check if BIOS (or OS) enabled L1-ASPM on this device.
+	 * If so (likely), disable L0S, so device moves directly L0->L1;
+	 *    costs negligible amount of power savings.
+	 * If not (unlikely), enable L0S, so there is at least some
+	 *    power savings, even without L1.
+	 */
+	u16 lctl = iwl_pciexp_link_ctrl(trans);
+
+	if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
+				PCI_CFG_LINK_CTRL_VAL_L1_EN) {
+		/* L1-ASPM enabled; disable(!) L0S */
+		iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
+		dev_printk(KERN_INFO, trans->dev,
+			   "L1 Enabled; Disabling L0S\n");
+	} else {
+		/* L1-ASPM disabled; enable(!) L0S */
+		iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
+		dev_printk(KERN_INFO, trans->dev,
+			   "L1 Disabled; Enabling L0S\n");
+	}
+	trans->pm_support = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);
+}
+
+/*
+ * Start up NIC's basic functionality after it has been reset
+ * (e.g. after platform boot, or shutdown via iwl_apm_stop())
+ * NOTE:  This does not load uCode nor start the embedded processor
+ */
+static int iwl_apm_init(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	int ret = 0;
+	IWL_DEBUG_INFO(trans, "Init card's basic functions\n");
+
+	/*
+	 * Use "set_bit" below rather than "write", to preserve any hardware
+	 * bits already set by default after reset.
+	 */
+
+	/* Disable L0S exit timer (platform NMI Work/Around) */
+	iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
+		    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+	/*
+	 * Disable L0s without affecting L1;
+	 *  don't wait for ICH L0s (ICH bug W/A)
+	 */
+	iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
+		    CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
+
+	/* Set FH wait threshold to maximum (HW error during stress W/A) */
+	iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
+
+	/*
+	 * Enable HAP INTA (interrupt from management bus) to
+	 * wake device's PCI Express link L1a -> L0s
+	 */
+	iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
+		    CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
+
+	iwl_apm_config(trans);
+
+	/* Configure analog phase-lock-loop before activating to D0A */
+	if (trans->cfg->base_params->pll_cfg_val)
+		iwl_set_bit(trans, CSR_ANA_PLL_CFG,
+			    trans->cfg->base_params->pll_cfg_val);
+
+	/*
+	 * Set "initialization complete" bit to move adapter from
+	 * D0U* --> D0A* (powered-up active) state.
+	 */
+	iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+	/*
+	 * Wait for clock stabilization; once stabilized, access to
+	 * device-internal resources is supported, e.g. iwl_write_prph()
+	 * and accesses to uCode SRAM.
+	 */
+	ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
+			   CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+			   CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+	if (ret < 0) {
+		IWL_DEBUG_INFO(trans, "Failed to init the card\n");
+		goto out;
+	}
+
+	/*
+	 * Enable DMA clock and wait for it to stabilize.
+	 *
+	 * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
+	 * do not disable clocks.  This preserves any hardware bits already
+	 * set by default in "CLK_CTRL_REG" after reset.
+	 */
+	iwl_write_prph(trans, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+	udelay(20);
+
+	/* Disable L1-Active */
+	iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
+			  APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+	set_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
+
+out:
+	return ret;
+}
+
+static int iwl_apm_stop_master(struct iwl_trans *trans)
+{
+	int ret = 0;
+
+	/* stop device's busmaster DMA activity */
+	iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+	ret = iwl_poll_bit(trans, CSR_RESET,
+			   CSR_RESET_REG_FLAG_MASTER_DISABLED,
+			   CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+	if (ret)
+		IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");
+
+	IWL_DEBUG_INFO(trans, "stop master\n");
+
+	return ret;
+}
+
+static void iwl_apm_stop(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
+
+	clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
+
+	/* Stop device's DMA activity */
+	iwl_apm_stop_master(trans);
+
+	/* Reset the entire device */
+	iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+	udelay(10);
+
+	/*
+	 * Clear "initialization complete" bit to move adapter from
+	 * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
+	 */
+	iwl_clear_bit(trans, CSR_GP_CNTRL,
+		      CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+}
+
+static int iwl_nic_init(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	unsigned long flags;
+
+	/* nic_init */
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+	iwl_apm_init(trans);
+
+	/* Set interrupt coalescing calibration timer to default (512 usecs) */
+	iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
+
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+	iwl_set_pwr_vmain(trans);
+
+	iwl_op_mode_nic_config(trans->op_mode);
+
+#ifndef CONFIG_IWLWIFI_IDI
+	/* Allocate the RX queue, or reset if it is already allocated */
+	iwl_rx_init(trans);
+#endif
+
+	/* Allocate or reset and init all Tx and Command queues */
+	if (iwl_tx_init(trans))
+		return -ENOMEM;
+
+	if (trans->cfg->base_params->shadow_reg_enable) {
+		/* enable shadow regs in HW */
+		iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF);
+		IWL_DEBUG_INFO(trans, "Enabling shadow registers in device\n");
+	}
+
+	return 0;
+}
+
+#define HW_READY_TIMEOUT (50)
+
+/* Note: returns poll_bit return value, which is >= 0 if success */
+static int iwl_set_hw_ready(struct iwl_trans *trans)
+{
+	int ret;
+
+	iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
+		    CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
+
+	/* See if we got it */
+	ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
+			   CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+			   CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+			   HW_READY_TIMEOUT);
+
+	IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : "");
+	return ret;
+}
+
+/* Note: returns standard 0/-ERROR code */
+static int iwl_prepare_card_hw(struct iwl_trans *trans)
+{
+	int ret;
+
+	IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
+
+	ret = iwl_set_hw_ready(trans);
+	/* If the card is ready, exit 0 */
+	if (ret >= 0)
+		return 0;
+
+	/* If HW is not ready, prepare the conditions to check again */
+	iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
+		    CSR_HW_IF_CONFIG_REG_PREPARE);
+
+	ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
+			   ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
+			   CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
+
+	if (ret < 0)
+		return ret;
+
+	/* HW should be ready by now, check again. */
+	ret = iwl_set_hw_ready(trans);
+	if (ret >= 0)
+		return 0;
+	return ret;
+}
+
+/*
+ * ucode
+ */
+static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
+			    const struct fw_desc *section)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	dma_addr_t phy_addr = section->p_addr;
+	u32 byte_cnt = section->len;
+	u32 dst_addr = section->offset;
+	int ret;
+
+	trans_pcie->ucode_write_complete = false;
+
+	iwl_write_direct32(trans,
+			   FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+			   FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
+
+	iwl_write_direct32(trans,
+			   FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL),
+			   dst_addr);
+
+	iwl_write_direct32(trans,
+		FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
+		phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
+
+	iwl_write_direct32(trans,
+			   FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
+			   (iwl_get_dma_hi_addr(phy_addr)
+				<< FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
+
+	iwl_write_direct32(trans,
+			   FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
+			   1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
+			   1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
+			   FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
+
+	iwl_write_direct32(trans,
+			   FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+			   FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE	|
+			   FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE	|
+			   FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
+
+	IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
+		     section_num);
+	ret = wait_event_timeout(trans_pcie->ucode_write_waitq,
+				 trans_pcie->ucode_write_complete, 5 * HZ);
+	if (!ret) {
+		IWL_ERR(trans, "Could not load the [%d] uCode section\n",
+			section_num);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int iwl_load_given_ucode(struct iwl_trans *trans,
+				const struct fw_img *image)
+{
+	int ret = 0;
+		int i;
+
+		for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) {
+			if (!image->sec[i].p_addr)
+				break;
+
+			ret = iwl_load_section(trans, i, &image->sec[i]);
+			if (ret)
+				return ret;
+		}
+
+	/* Remove all resets to allow NIC to operate */
+	iwl_write32(trans, CSR_RESET, 0);
+
+	return 0;
+}
+
+static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
+				   const struct fw_img *fw)
+{
+	int ret;
+	bool hw_rfkill;
+
+	/* This may fail if AMT took ownership of the device */
+	if (iwl_prepare_card_hw(trans)) {
+		IWL_WARN(trans, "Exit HW not ready\n");
+		return -EIO;
+	}
+
+	iwl_enable_rfkill_int(trans);
+
+	/* If platform's RF_KILL switch is NOT set to KILL */
+	hw_rfkill = iwl_is_rfkill_set(trans);
+	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+	if (hw_rfkill)
+		return -ERFKILL;
+
+	iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+
+	ret = iwl_nic_init(trans);
+	if (ret) {
+		IWL_ERR(trans, "Unable to init nic\n");
+		return ret;
+	}
+
+	/* make sure rfkill handshake bits are cleared */
+	iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+	/* clear (again), then enable host interrupts */
+	iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+	iwl_enable_interrupts(trans);
+
+	/* really make sure rfkill handshake bits are cleared */
+	iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+	/* Load the given image to the HW */
+	return iwl_load_given_ucode(trans, fw);
+}
+
+/*
+ * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
+ */
+static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
+{
+	struct iwl_trans_pcie __maybe_unused *trans_pcie =
+		IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	iwl_write_prph(trans, SCD_TXFACT, mask);
+}
+
+static void iwl_tx_start(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	u32 a;
+	int i, chan;
+	u32 reg_val;
+
+	/* make sure all queue are not stopped/used */
+	memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
+	memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
+
+	trans_pcie->scd_base_addr =
+		iwl_read_prph(trans, SCD_SRAM_BASE_ADDR);
+	a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
+	/* reset conext data memory */
+	for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
+		a += 4)
+		iwl_write_targ_mem(trans, a, 0);
+	/* reset tx status memory */
+	for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
+		a += 4)
+		iwl_write_targ_mem(trans, a, 0);
+	for (; a < trans_pcie->scd_base_addr +
+	       SCD_TRANS_TBL_OFFSET_QUEUE(
+				trans->cfg->base_params->num_of_queues);
+	       a += 4)
+		iwl_write_targ_mem(trans, a, 0);
+
+	iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
+		       trans_pcie->scd_bc_tbls.dma >> 10);
+
+	/* The chain extension of the SCD doesn't work well. This feature is
+	 * enabled by default by the HW, so we need to disable it manually.
+	 */
+	iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
+
+	for (i = 0; i < trans_pcie->n_q_to_fifo; i++) {
+		int fifo = trans_pcie->setup_q_to_fifo[i];
+
+		iwl_trans_pcie_txq_enable(trans, i, fifo, IWL_INVALID_STATION,
+					  IWL_TID_NON_QOS, SCD_FRAME_LIMIT, 0);
+	}
+
+	/* Activate all Tx DMA/FIFO channels */
+	iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
+
+	/* Enable DMA channel */
+	for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
+		iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+				   FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+				   FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+	/* Update FH chicken bits */
+	reg_val = iwl_read_direct32(trans, FH_TX_CHICKEN_BITS_REG);
+	iwl_write_direct32(trans, FH_TX_CHICKEN_BITS_REG,
+			   reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
+	/* Enable L1-Active */
+	iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
+			    APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+}
+
+static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans)
+{
+	iwl_reset_ict(trans);
+	iwl_tx_start(trans);
+}
+
+/**
+ * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
+ */
+static int iwl_trans_tx_stop(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	int ch, txq_id, ret;
+	unsigned long flags;
+
+	/* Turn off all Tx DMA fifos */
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+
+	iwl_trans_txq_set_sched(trans, 0);
+
+	/* Stop each Tx DMA channel, and wait for it to be idle */
+	for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
+		iwl_write_direct32(trans,
+				   FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
+		ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG,
+			FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000);
+		if (ret < 0)
+			IWL_ERR(trans,
+				"Failing on timeout while stopping DMA channel %d [0x%08x]",
+				ch,
+				iwl_read_direct32(trans,
+						  FH_TSSR_TX_STATUS_REG));
+	}
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+	if (!trans_pcie->txq) {
+		IWL_WARN(trans, "Stopping tx queues that aren't allocated...");
+		return 0;
+	}
+
+	/* Unmap DMA from host system and free skb's */
+	for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+	     txq_id++)
+		iwl_tx_queue_unmap(trans, txq_id);
+
+	return 0;
+}
+
+static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	unsigned long flags;
+
+	/* tell the device to stop sending interrupts */
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+	iwl_disable_interrupts(trans);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+	/* device going down, Stop using ICT table */
+	iwl_disable_ict(trans);
+
+	/*
+	 * If a HW restart happens during firmware loading,
+	 * then the firmware loading might call this function
+	 * and later it might be called again due to the
+	 * restart. So don't process again if the device is
+	 * already dead.
+	 */
+	if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) {
+		iwl_trans_tx_stop(trans);
+#ifndef CONFIG_IWLWIFI_IDI
+		iwl_trans_rx_stop(trans);
+#endif
+		/* Power-down device's busmaster DMA clocks */
+		iwl_write_prph(trans, APMG_CLK_DIS_REG,
+			       APMG_CLK_VAL_DMA_CLK_RQT);
+		udelay(5);
+	}
+
+	/* Make sure (redundant) we've released our request to stay awake */
+	iwl_clear_bit(trans, CSR_GP_CNTRL,
+		      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+	/* Stop the device, and put it in low power state */
+	iwl_apm_stop(trans);
+
+	/* Upon stop, the APM issues an interrupt if HW RF kill is set.
+	 * Clean again the interrupt here
+	 */
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+	iwl_disable_interrupts(trans);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+	iwl_enable_rfkill_int(trans);
+
+	/* wait to make sure we flush pending tasklet*/
+	synchronize_irq(trans_pcie->irq);
+	tasklet_kill(&trans_pcie->irq_tasklet);
+
+	cancel_work_sync(&trans_pcie->rx_replenish);
+
+	/* stop and reset the on-board processor */
+	iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+	/* clear all status bits */
+	clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+	clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
+	clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
+	clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
+}
+
+static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
+{
+	/* let the ucode operate on its own */
+	iwl_write32(trans, CSR_UCODE_DRV_GP1_SET,
+		    CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+	iwl_disable_interrupts(trans);
+	iwl_clear_bit(trans, CSR_GP_CNTRL,
+		      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+
+static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
+			     struct iwl_device_cmd *dev_cmd, int txq_id)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
+	struct iwl_cmd_meta *out_meta;
+	struct iwl_tx_queue *txq;
+	struct iwl_queue *q;
+	dma_addr_t phys_addr = 0;
+	dma_addr_t txcmd_phys;
+	dma_addr_t scratch_phys;
+	u16 len, firstlen, secondlen;
+	u8 wait_write_ptr = 0;
+	__le16 fc = hdr->frame_control;
+	u8 hdr_len = ieee80211_hdrlen(fc);
+	u16 __maybe_unused wifi_seq;
+
+	txq = &trans_pcie->txq[txq_id];
+	q = &txq->q;
+
+	if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) {
+		WARN_ON_ONCE(1);
+		return -EINVAL;
+	}
+
+	spin_lock(&txq->lock);
+
+	/* In AGG mode, the index in the ring must correspond to the WiFi
+	 * sequence number. This is a HW requirements to help the SCD to parse
+	 * the BA.
+	 * Check here that the packets are in the right place on the ring.
+	 */
+#ifdef CONFIG_IWLWIFI_DEBUG
+	wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
+	WARN_ONCE((iwl_read_prph(trans, SCD_AGGR_SEL) & BIT(txq_id)) &&
+		  ((wifi_seq & 0xff) != q->write_ptr),
+		  "Q: %d WiFi Seq %d tfdNum %d",
+		  txq_id, wifi_seq, q->write_ptr);
+#endif
+
+	/* Set up driver data for this TFD */
+	txq->entries[q->write_ptr].skb = skb;
+	txq->entries[q->write_ptr].cmd = dev_cmd;
+
+	dev_cmd->hdr.cmd = REPLY_TX;
+	dev_cmd->hdr.sequence =
+		cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+			    INDEX_TO_SEQ(q->write_ptr)));
+
+	/* Set up first empty entry in queue's array of Tx/cmd buffers */
+	out_meta = &txq->entries[q->write_ptr].meta;
+
+	/*
+	 * Use the first empty entry in this queue's command buffer array
+	 * to contain the Tx command and MAC header concatenated together
+	 * (payload data will be in another buffer).
+	 * Size of this varies, due to varying MAC header length.
+	 * If end is not dword aligned, we'll have 2 extra bytes at the end
+	 * of the MAC header (device reads on dword boundaries).
+	 * We'll tell device about this padding later.
+	 */
+	len = sizeof(struct iwl_tx_cmd) +
+		sizeof(struct iwl_cmd_header) + hdr_len;
+	firstlen = (len + 3) & ~3;
+
+	/* Tell NIC about any 2-byte padding after MAC header */
+	if (firstlen != len)
+		tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+	/* Physical address of this Tx command's header (not MAC header!),
+	 * within command buffer array. */
+	txcmd_phys = dma_map_single(trans->dev,
+				    &dev_cmd->hdr, firstlen,
+				    DMA_BIDIRECTIONAL);
+	if (unlikely(dma_mapping_error(trans->dev, txcmd_phys)))
+		goto out_err;
+	dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+	dma_unmap_len_set(out_meta, len, firstlen);
+
+	if (!ieee80211_has_morefrags(fc)) {
+		txq->need_update = 1;
+	} else {
+		wait_write_ptr = 1;
+		txq->need_update = 0;
+	}
+
+	/* Set up TFD's 2nd entry to point directly to remainder of skb,
+	 * if any (802.11 null frames have no payload). */
+	secondlen = skb->len - hdr_len;
+	if (secondlen > 0) {
+		phys_addr = dma_map_single(trans->dev, skb->data + hdr_len,
+					   secondlen, DMA_TO_DEVICE);
+		if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
+			dma_unmap_single(trans->dev,
+					 dma_unmap_addr(out_meta, mapping),
+					 dma_unmap_len(out_meta, len),
+					 DMA_BIDIRECTIONAL);
+			goto out_err;
+		}
+	}
+
+	/* Attach buffers to TFD */
+	iwlagn_txq_attach_buf_to_tfd(trans, txq, txcmd_phys, firstlen, 1);
+	if (secondlen > 0)
+		iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
+					     secondlen, 0);
+
+	scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+				offsetof(struct iwl_tx_cmd, scratch);
+
+	/* take back ownership of DMA buffer to enable update */
+	dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen,
+				DMA_BIDIRECTIONAL);
+	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+	tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
+
+	IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
+		     le16_to_cpu(dev_cmd->hdr.sequence));
+	IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
+
+	/* Set up entry for this TFD in Tx byte-count array */
+	iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
+
+	dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
+				   DMA_BIDIRECTIONAL);
+
+	trace_iwlwifi_dev_tx(trans->dev,
+			     &txq->tfds[txq->q.write_ptr],
+			     sizeof(struct iwl_tfd),
+			     &dev_cmd->hdr, firstlen,
+			     skb->data + hdr_len, secondlen);
+
+	/* start timer if queue currently empty */
+	if (txq->need_update && q->read_ptr == q->write_ptr &&
+	    trans_pcie->wd_timeout)
+		mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+
+	/* Tell device the write index *just past* this latest filled TFD */
+	q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+	iwl_txq_update_write_ptr(trans, txq);
+
+	/*
+	 * At this point the frame is "transmitted" successfully
+	 * and we will get a TX status notification eventually,
+	 * regardless of the value of ret. "ret" only indicates
+	 * whether or not we should update the write pointer.
+	 */
+	if (iwl_queue_space(q) < q->high_mark) {
+		if (wait_write_ptr) {
+			txq->need_update = 1;
+			iwl_txq_update_write_ptr(trans, txq);
+		} else {
+			iwl_stop_queue(trans, txq);
+		}
+	}
+	spin_unlock(&txq->lock);
+	return 0;
+ out_err:
+	spin_unlock(&txq->lock);
+	return -1;
+}
+
+static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	int err;
+	bool hw_rfkill;
+
+	trans_pcie->inta_mask = CSR_INI_SET_MASK;
+
+	if (!trans_pcie->irq_requested) {
+		tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
+			iwl_irq_tasklet, (unsigned long)trans);
+
+		iwl_alloc_isr_ict(trans);
+
+		err = request_irq(trans_pcie->irq, iwl_isr_ict, IRQF_SHARED,
+				  DRV_NAME, trans);
+		if (err) {
+			IWL_ERR(trans, "Error allocating IRQ %d\n",
+				trans_pcie->irq);
+			goto error;
+		}
+
+		INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish);
+		trans_pcie->irq_requested = true;
+	}
+
+	err = iwl_prepare_card_hw(trans);
+	if (err) {
+		IWL_ERR(trans, "Error while preparing HW: %d", err);
+		goto err_free_irq;
+	}
+
+	iwl_apm_init(trans);
+
+	/* From now on, the op_mode will be kept updated about RF kill state */
+	iwl_enable_rfkill_int(trans);
+
+	hw_rfkill = iwl_is_rfkill_set(trans);
+	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+
+	return err;
+
+err_free_irq:
+	free_irq(trans_pcie->irq, trans);
+error:
+	iwl_free_isr_ict(trans);
+	tasklet_kill(&trans_pcie->irq_tasklet);
+	return err;
+}
+
+static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
+				   bool op_mode_leaving)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	bool hw_rfkill;
+	unsigned long flags;
+
+	iwl_apm_stop(trans);
+
+	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+	iwl_disable_interrupts(trans);
+	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+	iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+
+	if (!op_mode_leaving) {
+		/*
+		 * Even if we stop the HW, we still want the RF kill
+		 * interrupt
+		 */
+		iwl_enable_rfkill_int(trans);
+
+		/*
+		 * Check again since the RF kill state may have changed while
+		 * all the interrupts were disabled, in this case we couldn't
+		 * receive the RF kill interrupt and update the state in the
+		 * op_mode.
+		 */
+		hw_rfkill = iwl_is_rfkill_set(trans);
+		iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+	}
+}
+
+static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
+				   struct sk_buff_head *skbs)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+	/* n_bd is usually 256 => n_bd - 1 = 0xff */
+	int tfd_num = ssn & (txq->q.n_bd - 1);
+	int freed = 0;
+
+	spin_lock(&txq->lock);
+
+	if (txq->q.read_ptr != tfd_num) {
+		IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n",
+				   txq_id, txq->q.read_ptr, tfd_num, ssn);
+		freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
+		if (iwl_queue_space(&txq->q) > txq->q.low_mark)
+			iwl_wake_queue(trans, txq);
+	}
+
+	spin_unlock(&txq->lock);
+}
+
+static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
+{
+	writeb(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+}
+
+static void iwl_trans_pcie_write32(struct iwl_trans *trans, u32 ofs, u32 val)
+{
+	writel(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+}
+
+static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
+{
+	return readl(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+}
+
+static void iwl_trans_pcie_configure(struct iwl_trans *trans,
+				     const struct iwl_trans_config *trans_cfg)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	trans_pcie->cmd_queue = trans_cfg->cmd_queue;
+	if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS))
+		trans_pcie->n_no_reclaim_cmds = 0;
+	else
+		trans_pcie->n_no_reclaim_cmds = trans_cfg->n_no_reclaim_cmds;
+	if (trans_pcie->n_no_reclaim_cmds)
+		memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds,
+		       trans_pcie->n_no_reclaim_cmds * sizeof(u8));
+
+	trans_pcie->n_q_to_fifo = trans_cfg->n_queue_to_fifo;
+
+	if (WARN_ON(trans_pcie->n_q_to_fifo > IWL_MAX_HW_QUEUES))
+		trans_pcie->n_q_to_fifo = IWL_MAX_HW_QUEUES;
+
+	/* at least the command queue must be mapped */
+	WARN_ON(!trans_pcie->n_q_to_fifo);
+
+	memcpy(trans_pcie->setup_q_to_fifo, trans_cfg->queue_to_fifo,
+	       trans_pcie->n_q_to_fifo * sizeof(u8));
+
+	trans_pcie->rx_buf_size_8k = trans_cfg->rx_buf_size_8k;
+	if (trans_pcie->rx_buf_size_8k)
+		trans_pcie->rx_page_order = get_order(8 * 1024);
+	else
+		trans_pcie->rx_page_order = get_order(4 * 1024);
+
+	trans_pcie->wd_timeout =
+		msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);
+
+	trans_pcie->command_names = trans_cfg->command_names;
+}
+
+void iwl_trans_pcie_free(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	iwl_trans_pcie_tx_free(trans);
+#ifndef CONFIG_IWLWIFI_IDI
+	iwl_trans_pcie_rx_free(trans);
+#endif
+	if (trans_pcie->irq_requested == true) {
+		free_irq(trans_pcie->irq, trans);
+		iwl_free_isr_ict(trans);
+	}
+
+	pci_disable_msi(trans_pcie->pci_dev);
+	iounmap(trans_pcie->hw_base);
+	pci_release_regions(trans_pcie->pci_dev);
+	pci_disable_device(trans_pcie->pci_dev);
+	kmem_cache_destroy(trans->dev_cmd_pool);
+
+	kfree(trans);
+}
+
+static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	if (state)
+		set_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
+	else
+		clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
+{
+	return 0;
+}
+
+static int iwl_trans_pcie_resume(struct iwl_trans *trans)
+{
+	bool hw_rfkill;
+
+	iwl_enable_rfkill_int(trans);
+
+	hw_rfkill = iwl_is_rfkill_set(trans);
+	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+
+	if (!hw_rfkill)
+		iwl_enable_interrupts(trans);
+
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#define IWL_FLUSH_WAIT_MS	2000
+
+static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	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 < trans->cfg->base_params->num_of_queues; cnt++) {
+		if (cnt == trans_pcie->cmd_queue)
+			continue;
+		txq = &trans_pcie->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(trans, "fail to flush all tx fifo queues\n");
+			ret = -ETIMEDOUT;
+			break;
+		}
+	}
+	return ret;
+}
+
+static const char *get_fh_string(int cmd)
+{
+#define IWL_CMD(x) case x: return #x
+	switch (cmd) {
+	IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
+	IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
+	IWL_CMD(FH_RSCSR_CHNL0_WPTR);
+	IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
+	IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
+	IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
+	IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
+	IWL_CMD(FH_TSSR_TX_STATUS_REG);
+	IWL_CMD(FH_TSSR_TX_ERROR_REG);
+	default:
+		return "UNKNOWN";
+	}
+#undef IWL_CMD
+}
+
+int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
+{
+	int i;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	int pos = 0;
+	size_t bufsz = 0;
+#endif
+	static const u32 fh_tbl[] = {
+		FH_RSCSR_CHNL0_STTS_WPTR_REG,
+		FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+		FH_RSCSR_CHNL0_WPTR,
+		FH_MEM_RCSR_CHNL0_CONFIG_REG,
+		FH_MEM_RSSR_SHARED_CTRL_REG,
+		FH_MEM_RSSR_RX_STATUS_REG,
+		FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
+		FH_TSSR_TX_STATUS_REG,
+		FH_TSSR_TX_ERROR_REG
+	};
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (display) {
+		bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
+		*buf = kmalloc(bufsz, GFP_KERNEL);
+		if (!*buf)
+			return -ENOMEM;
+		pos += scnprintf(*buf + pos, bufsz - pos,
+				"FH register values:\n");
+		for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
+			pos += scnprintf(*buf + pos, bufsz - pos,
+				"  %34s: 0X%08x\n",
+				get_fh_string(fh_tbl[i]),
+				iwl_read_direct32(trans, fh_tbl[i]));
+		}
+		return pos;
+	}
+#endif
+	IWL_ERR(trans, "FH register values:\n");
+	for (i = 0; i <  ARRAY_SIZE(fh_tbl); i++) {
+		IWL_ERR(trans, "  %34s: 0X%08x\n",
+			get_fh_string(fh_tbl[i]),
+			iwl_read_direct32(trans, fh_tbl[i]));
+	}
+	return 0;
+}
+
+static const char *get_csr_string(int cmd)
+{
+#define IWL_CMD(x) case x: return #x
+	switch (cmd) {
+	IWL_CMD(CSR_HW_IF_CONFIG_REG);
+	IWL_CMD(CSR_INT_COALESCING);
+	IWL_CMD(CSR_INT);
+	IWL_CMD(CSR_INT_MASK);
+	IWL_CMD(CSR_FH_INT_STATUS);
+	IWL_CMD(CSR_GPIO_IN);
+	IWL_CMD(CSR_RESET);
+	IWL_CMD(CSR_GP_CNTRL);
+	IWL_CMD(CSR_HW_REV);
+	IWL_CMD(CSR_EEPROM_REG);
+	IWL_CMD(CSR_EEPROM_GP);
+	IWL_CMD(CSR_OTP_GP_REG);
+	IWL_CMD(CSR_GIO_REG);
+	IWL_CMD(CSR_GP_UCODE_REG);
+	IWL_CMD(CSR_GP_DRIVER_REG);
+	IWL_CMD(CSR_UCODE_DRV_GP1);
+	IWL_CMD(CSR_UCODE_DRV_GP2);
+	IWL_CMD(CSR_LED_REG);
+	IWL_CMD(CSR_DRAM_INT_TBL_REG);
+	IWL_CMD(CSR_GIO_CHICKEN_BITS);
+	IWL_CMD(CSR_ANA_PLL_CFG);
+	IWL_CMD(CSR_HW_REV_WA_REG);
+	IWL_CMD(CSR_DBG_HPET_MEM_REG);
+	default:
+		return "UNKNOWN";
+	}
+#undef IWL_CMD
+}
+
+void iwl_dump_csr(struct iwl_trans *trans)
+{
+	int i;
+	static const u32 csr_tbl[] = {
+		CSR_HW_IF_CONFIG_REG,
+		CSR_INT_COALESCING,
+		CSR_INT,
+		CSR_INT_MASK,
+		CSR_FH_INT_STATUS,
+		CSR_GPIO_IN,
+		CSR_RESET,
+		CSR_GP_CNTRL,
+		CSR_HW_REV,
+		CSR_EEPROM_REG,
+		CSR_EEPROM_GP,
+		CSR_OTP_GP_REG,
+		CSR_GIO_REG,
+		CSR_GP_UCODE_REG,
+		CSR_GP_DRIVER_REG,
+		CSR_UCODE_DRV_GP1,
+		CSR_UCODE_DRV_GP2,
+		CSR_LED_REG,
+		CSR_DRAM_INT_TBL_REG,
+		CSR_GIO_CHICKEN_BITS,
+		CSR_ANA_PLL_CFG,
+		CSR_HW_REV_WA_REG,
+		CSR_DBG_HPET_MEM_REG
+	};
+	IWL_ERR(trans, "CSR values:\n");
+	IWL_ERR(trans, "(2nd byte of CSR_INT_COALESCING is "
+		"CSR_INT_PERIODIC_REG)\n");
+	for (i = 0; i <  ARRAY_SIZE(csr_tbl); i++) {
+		IWL_ERR(trans, "  %25s: 0X%08x\n",
+			get_csr_string(csr_tbl[i]),
+			iwl_read32(trans, csr_tbl[i]));
+	}
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+/* create and remove of files */
+#define DEBUGFS_ADD_FILE(name, parent, mode) do {			\
+	if (!debugfs_create_file(#name, mode, parent, trans,		\
+				 &iwl_dbgfs_##name##_ops))		\
+		return -ENOMEM;						\
+} while (0)
+
+/* file operation */
+#define DEBUGFS_READ_FUNC(name)                                         \
+static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
+					char __user *user_buf,          \
+					size_t count, loff_t *ppos);
+
+#define DEBUGFS_WRITE_FUNC(name)                                        \
+static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
+					const char __user *user_buf,    \
+					size_t count, loff_t *ppos);
+
+
+#define DEBUGFS_READ_FILE_OPS(name)					\
+	DEBUGFS_READ_FUNC(name);					\
+static const struct file_operations iwl_dbgfs_##name##_ops = {		\
+	.read = iwl_dbgfs_##name##_read,				\
+	.open = simple_open,						\
+	.llseek = generic_file_llseek,					\
+};
+
+#define DEBUGFS_WRITE_FILE_OPS(name)                                    \
+	DEBUGFS_WRITE_FUNC(name);                                       \
+static const struct file_operations iwl_dbgfs_##name##_ops = {          \
+	.write = iwl_dbgfs_##name##_write,                              \
+	.open = simple_open,						\
+	.llseek = generic_file_llseek,					\
+};
+
+#define DEBUGFS_READ_WRITE_FILE_OPS(name)				\
+	DEBUGFS_READ_FUNC(name);					\
+	DEBUGFS_WRITE_FUNC(name);					\
+static const struct file_operations iwl_dbgfs_##name##_ops = {		\
+	.write = iwl_dbgfs_##name##_write,				\
+	.read = iwl_dbgfs_##name##_read,				\
+	.open = simple_open,						\
+	.llseek = generic_file_llseek,					\
+};
+
+static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
+				       char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct iwl_trans *trans = file->private_data;
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_tx_queue *txq;
+	struct iwl_queue *q;
+	char *buf;
+	int pos = 0;
+	int cnt;
+	int ret;
+	size_t bufsz;
+
+	bufsz = sizeof(char) * 64 * trans->cfg->base_params->num_of_queues;
+
+	if (!trans_pcie->txq)
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
+		txq = &trans_pcie->txq[cnt];
+		q = &txq->q;
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"hwq %.2d: read=%u write=%u use=%d stop=%d\n",
+				cnt, q->read_ptr, q->write_ptr,
+				!!test_bit(cnt, trans_pcie->queue_used),
+				!!test_bit(cnt, trans_pcie->queue_stopped));
+	}
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
+				       char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct iwl_trans *trans = file->private_data;
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+	char buf[256];
+	int pos = 0;
+	const size_t bufsz = sizeof(buf);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
+						rxq->read);
+	pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
+						rxq->write);
+	pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
+						rxq->free_count);
+	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);
+}
+
+static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct iwl_trans *trans = file->private_data;
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
+
+	int pos = 0;
+	char *buf;
+	int bufsz = 24 * 64; /* 24 items * 64 char per item */
+	ssize_t ret;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"Interrupt Statistics Report:\n");
+
+	pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
+		isr_stats->hw);
+	pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
+		isr_stats->sw);
+	if (isr_stats->sw || isr_stats->hw) {
+		pos += scnprintf(buf + pos, bufsz - pos,
+			"\tLast Restarting Code:  0x%X\n",
+			isr_stats->err_code);
+	}
+#ifdef CONFIG_IWLWIFI_DEBUG
+	pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
+		isr_stats->sch);
+	pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
+		isr_stats->alive);
+#endif
+	pos += scnprintf(buf + pos, bufsz - pos,
+		"HW RF KILL switch toggled:\t %u\n", isr_stats->rfkill);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
+		isr_stats->ctkill);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
+		isr_stats->wakeup);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+		"Rx command responses:\t\t %u\n", isr_stats->rx);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
+		isr_stats->tx);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
+		isr_stats->unhandled);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
+					 const char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct iwl_trans *trans = file->private_data;
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
+
+	char buf[8];
+	int buf_size;
+	u32 reset_flag;
+
+	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, "%x", &reset_flag) != 1)
+		return -EFAULT;
+	if (reset_flag == 0)
+		memset(isr_stats, 0, sizeof(*isr_stats));
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_csr_write(struct file *file,
+				   const char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	struct iwl_trans *trans = file->private_data;
+	char buf[8];
+	int buf_size;
+	int csr;
+
+	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", &csr) != 1)
+		return -EFAULT;
+
+	iwl_dump_csr(trans);
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct iwl_trans *trans = file->private_data;
+	char *buf;
+	int pos = 0;
+	ssize_t ret = -EFAULT;
+
+	ret = pos = iwl_dump_fh(trans, &buf, true);
+	if (buf) {
+		ret = simple_read_from_buffer(user_buf,
+					      count, ppos, buf, pos);
+		kfree(buf);
+	}
+
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
+					  const char __user *user_buf,
+					  size_t count, loff_t *ppos)
+{
+	struct iwl_trans *trans = file->private_data;
+
+	if (!trans->op_mode)
+		return -EAGAIN;
+
+	local_bh_disable();
+	iwl_op_mode_nic_error(trans->op_mode);
+	local_bh_enable();
+
+	return count;
+}
+
+DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
+DEBUGFS_READ_FILE_OPS(fh_reg);
+DEBUGFS_READ_FILE_OPS(rx_queue);
+DEBUGFS_READ_FILE_OPS(tx_queue);
+DEBUGFS_WRITE_FILE_OPS(csr);
+DEBUGFS_WRITE_FILE_OPS(fw_restart);
+
+/*
+ * Create the debugfs files and directories
+ *
+ */
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+					 struct dentry *dir)
+{
+	DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
+	DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
+	DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
+	DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
+	DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR);
+	return 0;
+}
+#else
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+					 struct dentry *dir)
+{
+	return 0;
+}
+#endif /*CONFIG_IWLWIFI_DEBUGFS */
+
+static const struct iwl_trans_ops trans_ops_pcie = {
+	.start_hw = iwl_trans_pcie_start_hw,
+	.stop_hw = iwl_trans_pcie_stop_hw,
+	.fw_alive = iwl_trans_pcie_fw_alive,
+	.start_fw = iwl_trans_pcie_start_fw,
+	.stop_device = iwl_trans_pcie_stop_device,
+
+	.wowlan_suspend = iwl_trans_pcie_wowlan_suspend,
+
+	.send_cmd = iwl_trans_pcie_send_cmd,
+
+	.tx = iwl_trans_pcie_tx,
+	.reclaim = iwl_trans_pcie_reclaim,
+
+	.txq_disable = iwl_trans_pcie_txq_disable,
+	.txq_enable = iwl_trans_pcie_txq_enable,
+
+	.dbgfs_register = iwl_trans_pcie_dbgfs_register,
+
+	.wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty,
+
+#ifdef CONFIG_PM_SLEEP
+	.suspend = iwl_trans_pcie_suspend,
+	.resume = iwl_trans_pcie_resume,
+#endif
+	.write8 = iwl_trans_pcie_write8,
+	.write32 = iwl_trans_pcie_write32,
+	.read32 = iwl_trans_pcie_read32,
+	.configure = iwl_trans_pcie_configure,
+	.set_pmi = iwl_trans_pcie_set_pmi,
+};
+
+struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
+				       const struct pci_device_id *ent,
+				       const struct iwl_cfg *cfg)
+{
+	struct iwl_trans_pcie *trans_pcie;
+	struct iwl_trans *trans;
+	char cmd_pool_name[100];
+	u16 pci_cmd;
+	int err;
+
+	trans = kzalloc(sizeof(struct iwl_trans) +
+			sizeof(struct iwl_trans_pcie), GFP_KERNEL);
+
+	if (WARN_ON(!trans))
+		return NULL;
+
+	trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	trans->ops = &trans_ops_pcie;
+	trans->cfg = cfg;
+	trans_pcie->trans = trans;
+	spin_lock_init(&trans_pcie->irq_lock);
+	init_waitqueue_head(&trans_pcie->ucode_write_waitq);
+
+	/* W/A - seems to solve weird behavior. We need to remove this if we
+	 * don't want to stay in L1 all the time. This wastes a lot of power */
+	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+			       PCIE_LINK_STATE_CLKPM);
+
+	if (pci_enable_device(pdev)) {
+		err = -ENODEV;
+		goto out_no_pci;
+	}
+
+	pci_set_master(pdev);
+
+	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
+	if (!err)
+		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
+	if (err) {
+		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (!err)
+			err = pci_set_consistent_dma_mask(pdev,
+							  DMA_BIT_MASK(32));
+		/* both attempts failed: */
+		if (err) {
+			dev_printk(KERN_ERR, &pdev->dev,
+				   "No suitable DMA available.\n");
+			goto out_pci_disable_device;
+		}
+	}
+
+	err = pci_request_regions(pdev, DRV_NAME);
+	if (err) {
+		dev_printk(KERN_ERR, &pdev->dev, "pci_request_regions failed");
+		goto out_pci_disable_device;
+	}
+
+	trans_pcie->hw_base = pci_ioremap_bar(pdev, 0);
+	if (!trans_pcie->hw_base) {
+		dev_printk(KERN_ERR, &pdev->dev, "pci_ioremap_bar failed");
+		err = -ENODEV;
+		goto out_pci_release_regions;
+	}
+
+	dev_printk(KERN_INFO, &pdev->dev,
+		   "pci_resource_len = 0x%08llx\n",
+		   (unsigned long long) pci_resource_len(pdev, 0));
+	dev_printk(KERN_INFO, &pdev->dev,
+		   "pci_resource_base = %p\n", trans_pcie->hw_base);
+
+	dev_printk(KERN_INFO, &pdev->dev,
+		   "HW Revision ID = 0x%X\n", pdev->revision);
+
+	/* We disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state */
+	pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
+
+	err = pci_enable_msi(pdev);
+	if (err)
+		dev_printk(KERN_ERR, &pdev->dev,
+			   "pci_enable_msi failed(0X%x)", err);
+
+	trans->dev = &pdev->dev;
+	trans_pcie->irq = pdev->irq;
+	trans_pcie->pci_dev = pdev;
+	trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
+	trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
+	snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
+		 "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device);
+
+	/* TODO: Move this away, not needed if not MSI */
+	/* enable rfkill interrupt: hw bug w/a */
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+	if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
+		pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
+	}
+
+	/* Initialize the wait queue for commands */
+	init_waitqueue_head(&trans->wait_command_queue);
+	spin_lock_init(&trans->reg_lock);
+
+	snprintf(cmd_pool_name, sizeof(cmd_pool_name), "iwl_cmd_pool:%s",
+		 dev_name(trans->dev));
+
+	trans->dev_cmd_headroom = 0;
+	trans->dev_cmd_pool =
+		kmem_cache_create(cmd_pool_name,
+				  sizeof(struct iwl_device_cmd)
+				  + trans->dev_cmd_headroom,
+				  sizeof(void *),
+				  SLAB_HWCACHE_ALIGN,
+				  NULL);
+
+	if (!trans->dev_cmd_pool)
+		goto out_pci_disable_msi;
+
+	return trans;
+
+out_pci_disable_msi:
+	pci_disable_msi(pdev);
+out_pci_release_regions:
+	pci_release_regions(pdev);
+out_pci_disable_device:
+	pci_disable_device(pdev);
+out_no_pci:
+	kfree(trans);
+	return NULL;
+}
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
new file mode 100644
index 0000000..6baf8de
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -0,0 +1,969 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/etherdevice.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include "iwl-debug.h"
+#include "iwl-csr.h"
+#include "iwl-prph.h"
+#include "iwl-io.h"
+#include "iwl-op-mode.h"
+#include "internal.h"
+/* FIXME: need to abstract out TX command (once we know what it looks like) */
+#include "dvm/commands.h"
+
+#define IWL_TX_CRC_SIZE 4
+#define IWL_TX_DELIMITER_SIZE 4
+
+/**
+ * iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
+ */
+void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
+				       struct iwl_tx_queue *txq,
+				       u16 byte_cnt)
+{
+	struct iwlagn_scd_bc_tbl *scd_bc_tbl;
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	int write_ptr = txq->q.write_ptr;
+	int txq_id = txq->q.id;
+	u8 sec_ctl = 0;
+	u8 sta_id = 0;
+	u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+	__le16 bc_ent;
+	struct iwl_tx_cmd *tx_cmd =
+		(void *) txq->entries[txq->q.write_ptr].cmd->payload;
+
+	scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
+
+	WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
+
+	sta_id = tx_cmd->sta_id;
+	sec_ctl = tx_cmd->sec_ctl;
+
+	switch (sec_ctl & TX_CMD_SEC_MSK) {
+	case TX_CMD_SEC_CCM:
+		len += CCMP_MIC_LEN;
+		break;
+	case TX_CMD_SEC_TKIP:
+		len += TKIP_ICV_LEN;
+		break;
+	case TX_CMD_SEC_WEP:
+		len += WEP_IV_LEN + WEP_ICV_LEN;
+		break;
+	}
+
+	bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
+
+	scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
+
+	if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+		scd_bc_tbl[txq_id].
+			tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
+}
+
+/**
+ * iwl_txq_update_write_ptr - Send new write index to hardware
+ */
+void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq)
+{
+	u32 reg = 0;
+	int txq_id = txq->q.id;
+
+	if (txq->need_update == 0)
+		return;
+
+	if (trans->cfg->base_params->shadow_reg_enable) {
+		/* shadow register enabled */
+		iwl_write32(trans, HBUS_TARG_WRPTR,
+			    txq->q.write_ptr | (txq_id << 8));
+	} else {
+		struct iwl_trans_pcie *trans_pcie =
+			IWL_TRANS_GET_PCIE_TRANS(trans);
+		/* if we're trying to save power */
+		if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
+			/* wake up nic if it's powered down ...
+			 * uCode will wake up, and interrupt us again, so next
+			 * time we'll skip this part. */
+			reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
+
+			if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+				IWL_DEBUG_INFO(trans,
+					"Tx queue %d requesting wakeup,"
+					" GP1 = 0x%x\n", txq_id, reg);
+				iwl_set_bit(trans, CSR_GP_CNTRL,
+					CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+				return;
+			}
+
+			iwl_write_direct32(trans, HBUS_TARG_WRPTR,
+				     txq->q.write_ptr | (txq_id << 8));
+
+		/*
+		 * else not in power-save mode,
+		 * uCode will never sleep when we're
+		 * trying to tx (during RFKILL, we're not trying to tx).
+		 */
+		} else
+			iwl_write32(trans, HBUS_TARG_WRPTR,
+				    txq->q.write_ptr | (txq_id << 8));
+	}
+	txq->need_update = 0;
+}
+
+static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
+{
+	struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+	dma_addr_t addr = get_unaligned_le32(&tb->lo);
+	if (sizeof(dma_addr_t) > sizeof(u32))
+		addr |=
+		((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
+
+	return addr;
+}
+
+static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
+{
+	struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+	return le16_to_cpu(tb->hi_n_len) >> 4;
+}
+
+static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
+				  dma_addr_t addr, u16 len)
+{
+	struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+	u16 hi_n_len = len << 4;
+
+	put_unaligned_le32(addr, &tb->lo);
+	if (sizeof(dma_addr_t) > sizeof(u32))
+		hi_n_len |= ((addr >> 16) >> 16) & 0xF;
+
+	tb->hi_n_len = cpu_to_le16(hi_n_len);
+
+	tfd->num_tbs = idx + 1;
+}
+
+static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
+{
+	return tfd->num_tbs & 0x1f;
+}
+
+static void iwl_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
+			  struct iwl_tfd *tfd, enum dma_data_direction dma_dir)
+{
+	int i;
+	int num_tbs;
+
+	/* Sanity check on number of chunks */
+	num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+	if (num_tbs >= IWL_NUM_OF_TBS) {
+		IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);
+		/* @todo issue fatal error, it is quite serious situation */
+		return;
+	}
+
+	/* Unmap tx_cmd */
+	if (num_tbs)
+		dma_unmap_single(trans->dev,
+				dma_unmap_addr(meta, mapping),
+				dma_unmap_len(meta, len),
+				DMA_BIDIRECTIONAL);
+
+	/* Unmap chunks, if any. */
+	for (i = 1; i < num_tbs; i++)
+		dma_unmap_single(trans->dev, iwl_tfd_tb_get_addr(tfd, i),
+				iwl_tfd_tb_get_len(tfd, i), dma_dir);
+
+	tfd->num_tbs = 0;
+}
+
+/**
+ * iwl_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
+ * @trans - transport private data
+ * @txq - tx queue
+ * @dma_dir - the direction of the DMA mapping
+ *
+ * Does NOT advance any TFD circular buffer read/write indexes
+ * Does NOT free the TFD itself (which is within circular buffer)
+ */
+void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+		      enum dma_data_direction dma_dir)
+{
+	struct iwl_tfd *tfd_tmp = txq->tfds;
+
+	/* rd_ptr is bounded by n_bd and idx is bounded by n_window */
+	int rd_ptr = txq->q.read_ptr;
+	int idx = get_cmd_index(&txq->q, rd_ptr);
+
+	lockdep_assert_held(&txq->lock);
+
+	/* We have only q->n_window txq->entries, but we use q->n_bd tfds */
+	iwl_unmap_tfd(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr],
+		      dma_dir);
+
+	/* free SKB */
+	if (txq->entries) {
+		struct sk_buff *skb;
+
+		skb = txq->entries[idx].skb;
+
+		/* Can be called from irqs-disabled context
+		 * If skb is not NULL, it means that the whole queue is being
+		 * freed and that the queue is not empty - free the skb
+		 */
+		if (skb) {
+			iwl_op_mode_free_skb(trans->op_mode, skb);
+			txq->entries[idx].skb = NULL;
+		}
+	}
+}
+
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
+				 struct iwl_tx_queue *txq,
+				 dma_addr_t addr, u16 len,
+				 u8 reset)
+{
+	struct iwl_queue *q;
+	struct iwl_tfd *tfd, *tfd_tmp;
+	u32 num_tbs;
+
+	q = &txq->q;
+	tfd_tmp = txq->tfds;
+	tfd = &tfd_tmp[q->write_ptr];
+
+	if (reset)
+		memset(tfd, 0, sizeof(*tfd));
+
+	num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+	/* Each TFD can point to a maximum 20 Tx buffers */
+	if (num_tbs >= IWL_NUM_OF_TBS) {
+		IWL_ERR(trans, "Error can not send more than %d chunks\n",
+			IWL_NUM_OF_TBS);
+		return -EINVAL;
+	}
+
+	if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
+		return -EINVAL;
+
+	if (unlikely(addr & ~IWL_TX_DMA_MASK))
+		IWL_ERR(trans, "Unaligned address = %llx\n",
+			(unsigned long long)addr);
+
+	iwl_tfd_set_tb(tfd, num_tbs, addr, len);
+
+	return 0;
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
+ * of buffer descriptors, each of which points to one or more data buffers for
+ * the device to read from or fill.  Driver and device exchange status of each
+ * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
+ * entries in each circular buffer, to protect against confusing empty and full
+ * queue states.
+ *
+ * The device reads or writes the data in the queues via the device's several
+ * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ ***************************************************/
+
+int iwl_queue_space(const struct iwl_queue *q)
+{
+	int s = q->read_ptr - q->write_ptr;
+
+	if (q->read_ptr > q->write_ptr)
+		s -= q->n_bd;
+
+	if (s <= 0)
+		s += q->n_window;
+	/* keep some reserve to not confuse empty and full situations */
+	s -= 2;
+	if (s < 0)
+		s = 0;
+	return s;
+}
+
+/**
+ * iwl_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
+int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id)
+{
+	q->n_bd = count;
+	q->n_window = slots_num;
+	q->id = id;
+
+	/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+	 * and iwl_queue_dec_wrap are broken. */
+	if (WARN_ON(!is_power_of_2(count)))
+		return -EINVAL;
+
+	/* slots_num must be power-of-two size, otherwise
+	 * get_cmd_index is broken. */
+	if (WARN_ON(!is_power_of_2(slots_num)))
+		return -EINVAL;
+
+	q->low_mark = q->n_window / 4;
+	if (q->low_mark < 4)
+		q->low_mark = 4;
+
+	q->high_mark = q->n_window / 8;
+	if (q->high_mark < 2)
+		q->high_mark = 2;
+
+	q->write_ptr = q->read_ptr = 0;
+
+	return 0;
+}
+
+static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
+					  struct iwl_tx_queue *txq)
+{
+	struct iwl_trans_pcie *trans_pcie =
+		IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwlagn_scd_bc_tbl *scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
+	int txq_id = txq->q.id;
+	int read_ptr = txq->q.read_ptr;
+	u8 sta_id = 0;
+	__le16 bc_ent;
+	struct iwl_tx_cmd *tx_cmd =
+		(void *)txq->entries[txq->q.read_ptr].cmd->payload;
+
+	WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
+
+	if (txq_id != trans_pcie->cmd_queue)
+		sta_id = tx_cmd->sta_id;
+
+	bc_ent = cpu_to_le16(1 | (sta_id << 12));
+	scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
+
+	if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
+		scd_bc_tbl[txq_id].
+			tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
+}
+
+static int iwl_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
+				 u16 txq_id)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	u32 tbl_dw_addr;
+	u32 tbl_dw;
+	u16 scd_q2ratid;
+
+	scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
+
+	tbl_dw_addr = trans_pcie->scd_base_addr +
+			SCD_TRANS_TBL_OFFSET_QUEUE(txq_id);
+
+	tbl_dw = iwl_read_targ_mem(trans, tbl_dw_addr);
+
+	if (txq_id & 0x1)
+		tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
+	else
+		tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
+
+	iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw);
+
+	return 0;
+}
+
+static inline void iwl_txq_set_inactive(struct iwl_trans *trans, u16 txq_id)
+{
+	/* Simply stop the queue, but don't change any configuration;
+	 * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
+	iwl_write_prph(trans,
+		SCD_QUEUE_STATUS_BITS(txq_id),
+		(0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+		(1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
+			       int sta_id, int tid, int frame_limit, u16 ssn)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	if (test_and_set_bit(txq_id, trans_pcie->queue_used))
+		WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
+
+	/* Stop this Tx queue before configuring it */
+	iwl_txq_set_inactive(trans, txq_id);
+
+	/* Set this queue as a chain-building queue unless it is CMD queue */
+	if (txq_id != trans_pcie->cmd_queue)
+		iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
+
+	/* If this queue is mapped to a certain station: it is an AGG queue */
+	if (sta_id != IWL_INVALID_STATION) {
+		u16 ra_tid = BUILD_RAxTID(sta_id, tid);
+
+		/* Map receiver-address / traffic-ID to this queue */
+		iwl_txq_set_ratid_map(trans, ra_tid, txq_id);
+
+		/* enable aggregations for the queue */
+		iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+	} else {
+		/*
+		 * disable aggregations for the queue, this will also make the
+		 * ra_tid mapping configuration irrelevant since it is now a
+		 * non-AGG queue.
+		 */
+		iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+	}
+
+	/* Place first TFD at index corresponding to start sequence number.
+	 * Assumes that ssn_idx is valid (!= 0xFFF) */
+	trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
+	trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
+
+	iwl_write_direct32(trans, HBUS_TARG_WRPTR,
+			   (ssn & 0xff) | (txq_id << 8));
+	iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
+
+	/* Set up Tx window size and frame limit for this queue */
+	iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+			SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
+	iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+			SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
+			((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+				SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+			((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+				SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+
+	/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
+	iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
+		       (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+		       (fifo << SCD_QUEUE_STTS_REG_POS_TXF) |
+		       (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
+		       SCD_QUEUE_STTS_REG_MSK);
+	IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n",
+			    txq_id, fifo, ssn & 0xff);
+}
+
+void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	u16 rd_ptr, wr_ptr;
+	int n_bd = trans_pcie->txq[txq_id].q.n_bd;
+
+	if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) {
+		WARN_ONCE(1, "queue %d not used", txq_id);
+		return;
+	}
+
+	rd_ptr = iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq_id)) & (n_bd - 1);
+	wr_ptr = iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq_id));
+
+	WARN_ONCE(rd_ptr != wr_ptr, "queue %d isn't empty: [%d,%d]",
+		  txq_id, rd_ptr, wr_ptr);
+
+	iwl_txq_set_inactive(trans, txq_id);
+	IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id);
+}
+
+/*************** HOST COMMAND QUEUE FUNCTIONS   *****/
+
+/**
+ * iwl_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
+	struct iwl_queue *q = &txq->q;
+	struct iwl_device_cmd *out_cmd;
+	struct iwl_cmd_meta *out_meta;
+	dma_addr_t phys_addr;
+	u32 idx;
+	u16 copy_size, cmd_size;
+	bool had_nocopy = false;
+	int i;
+	u8 *cmd_dest;
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+	const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
+	int trace_lens[IWL_MAX_CMD_TFDS + 1] = {};
+	int trace_idx;
+#endif
+
+	copy_size = sizeof(out_cmd->hdr);
+	cmd_size = sizeof(out_cmd->hdr);
+
+	/* need one for the header if the first is NOCOPY */
+	BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);
+
+	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+		if (!cmd->len[i])
+			continue;
+		if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
+			had_nocopy = true;
+		} else {
+			/* NOCOPY must not be followed by normal! */
+			if (WARN_ON(had_nocopy))
+				return -EINVAL;
+			copy_size += cmd->len[i];
+		}
+		cmd_size += cmd->len[i];
+	}
+
+	/*
+	 * If any of the command structures end up being larger than
+	 * the TFD_MAX_PAYLOAD_SIZE and they aren't dynamically
+	 * allocated into separate TFDs, then we will need to
+	 * increase the size of the buffers.
+	 */
+	if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE))
+		return -EINVAL;
+
+	spin_lock_bh(&txq->lock);
+
+	if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
+		spin_unlock_bh(&txq->lock);
+
+		IWL_ERR(trans, "No space in command queue\n");
+		iwl_op_mode_cmd_queue_full(trans->op_mode);
+		return -ENOSPC;
+	}
+
+	idx = get_cmd_index(q, q->write_ptr);
+	out_cmd = txq->entries[idx].cmd;
+	out_meta = &txq->entries[idx].meta;
+
+	memset(out_meta, 0, sizeof(*out_meta));	/* re-initialize to NULL */
+	if (cmd->flags & CMD_WANT_SKB)
+		out_meta->source = cmd;
+
+	/* set up the header */
+
+	out_cmd->hdr.cmd = cmd->id;
+	out_cmd->hdr.flags = 0;
+	out_cmd->hdr.sequence =
+		cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) |
+					 INDEX_TO_SEQ(q->write_ptr));
+
+	/* and copy the data that needs to be copied */
+
+	cmd_dest = out_cmd->payload;
+	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+		if (!cmd->len[i])
+			continue;
+		if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
+			break;
+		memcpy(cmd_dest, cmd->data[i], cmd->len[i]);
+		cmd_dest += cmd->len[i];
+	}
+
+	IWL_DEBUG_HC(trans,
+		     "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n",
+		     trans_pcie_get_cmd_string(trans_pcie, out_cmd->hdr.cmd),
+		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+		     cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue);
+
+	phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size,
+				   DMA_BIDIRECTIONAL);
+	if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
+		idx = -ENOMEM;
+		goto out;
+	}
+
+	dma_unmap_addr_set(out_meta, mapping, phys_addr);
+	dma_unmap_len_set(out_meta, len, copy_size);
+
+	iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr, copy_size, 1);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+	trace_bufs[0] = &out_cmd->hdr;
+	trace_lens[0] = copy_size;
+	trace_idx = 1;
+#endif
+
+	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+		if (!cmd->len[i])
+			continue;
+		if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
+			continue;
+		phys_addr = dma_map_single(trans->dev, (void *)cmd->data[i],
+					   cmd->len[i], DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(trans->dev, phys_addr)) {
+			iwl_unmap_tfd(trans, out_meta,
+				      &txq->tfds[q->write_ptr],
+				      DMA_BIDIRECTIONAL);
+			idx = -ENOMEM;
+			goto out;
+		}
+
+		iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
+					     cmd->len[i], 0);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+		trace_bufs[trace_idx] = cmd->data[i];
+		trace_lens[trace_idx] = cmd->len[i];
+		trace_idx++;
+#endif
+	}
+
+	out_meta->flags = cmd->flags;
+
+	txq->need_update = 1;
+
+	/* check that tracing gets all possible blocks */
+	BUILD_BUG_ON(IWL_MAX_CMD_TFDS + 1 != 3);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+	trace_iwlwifi_dev_hcmd(trans->dev, cmd->flags,
+			       trace_bufs[0], trace_lens[0],
+			       trace_bufs[1], trace_lens[1],
+			       trace_bufs[2], trace_lens[2]);
+#endif
+
+	/* start timer if queue currently empty */
+	if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
+		mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+
+	/* Increment and update queue's write index */
+	q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+	iwl_txq_update_write_ptr(trans, txq);
+
+ out:
+	spin_unlock_bh(&txq->lock);
+	return idx;
+}
+
+static inline void iwl_queue_progress(struct iwl_trans_pcie *trans_pcie,
+				      struct iwl_tx_queue *txq)
+{
+	if (!trans_pcie->wd_timeout)
+		return;
+
+	/*
+	 * if empty delete timer, otherwise move timer forward
+	 * since we're making progress on this queue
+	 */
+	if (txq->q.read_ptr == txq->q.write_ptr)
+		del_timer(&txq->stuck_timer);
+	else
+		mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+}
+
+/**
+ * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd
+ *
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed. As result, some free space forms.  If there is
+ * enough free space (> low mark), wake the stack that feeds us.
+ */
+static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
+				   int idx)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+	struct iwl_queue *q = &txq->q;
+	int nfreed = 0;
+
+	lockdep_assert_held(&txq->lock);
+
+	if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) {
+		IWL_ERR(trans,
+			"%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.\n",
+			__func__, txq_id, idx, q->n_bd,
+			q->write_ptr, q->read_ptr);
+		return;
+	}
+
+	for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
+	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+		if (nfreed++ > 0) {
+			IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n",
+				idx, q->write_ptr, q->read_ptr);
+			iwl_op_mode_nic_error(trans->op_mode);
+		}
+
+	}
+
+	iwl_queue_progress(trans_pcie, txq);
+}
+
+/**
+ * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ * @handler_status: return value of the handler of the command
+ *	(put in setup_rx_handlers)
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed.  The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
+			 int handler_status)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	int index = SEQ_TO_INDEX(sequence);
+	int cmd_index;
+	struct iwl_device_cmd *cmd;
+	struct iwl_cmd_meta *meta;
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
+
+	/* If a Tx command is being handled and it isn't in the actual
+	 * command queue then there a command routing bug has been introduced
+	 * in the queue management code. */
+	if (WARN(txq_id != trans_pcie->cmd_queue,
+		 "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n",
+		 txq_id, trans_pcie->cmd_queue, sequence,
+		 trans_pcie->txq[trans_pcie->cmd_queue].q.read_ptr,
+		 trans_pcie->txq[trans_pcie->cmd_queue].q.write_ptr)) {
+		iwl_print_hex_error(trans, pkt, 32);
+		return;
+	}
+
+	spin_lock(&txq->lock);
+
+	cmd_index = get_cmd_index(&txq->q, index);
+	cmd = txq->entries[cmd_index].cmd;
+	meta = &txq->entries[cmd_index].meta;
+
+	iwl_unmap_tfd(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL);
+
+	/* Input error checking is done when commands are added to queue. */
+	if (meta->flags & CMD_WANT_SKB) {
+		struct page *p = rxb_steal_page(rxb);
+
+		meta->source->resp_pkt = pkt;
+		meta->source->_rx_page_addr = (unsigned long)page_address(p);
+		meta->source->_rx_page_order = trans_pcie->rx_page_order;
+		meta->source->handler_status = handler_status;
+	}
+
+	iwl_hcmd_queue_reclaim(trans, txq_id, index);
+
+	if (!(meta->flags & CMD_ASYNC)) {
+		if (!test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
+			IWL_WARN(trans,
+				 "HCMD_ACTIVE already clear for command %s\n",
+				 trans_pcie_get_cmd_string(trans_pcie,
+							   cmd->hdr.cmd));
+		}
+		clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+		IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
+			       trans_pcie_get_cmd_string(trans_pcie,
+							 cmd->hdr.cmd));
+		wake_up(&trans->wait_command_queue);
+	}
+
+	meta->flags = 0;
+
+	spin_unlock(&txq->lock);
+}
+
+#define HOST_COMPLETE_TIMEOUT (2 * HZ)
+
+static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	int ret;
+
+	/* An asynchronous command can not expect an SKB to be set. */
+	if (WARN_ON(cmd->flags & CMD_WANT_SKB))
+		return -EINVAL;
+
+
+	ret = iwl_enqueue_hcmd(trans, cmd);
+	if (ret < 0) {
+		IWL_ERR(trans,
+			"Error sending %s: enqueue_hcmd failed: %d\n",
+			trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	int cmd_idx;
+	int ret;
+
+	IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
+		       trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+
+	if (WARN_ON(test_and_set_bit(STATUS_HCMD_ACTIVE,
+				     &trans_pcie->status))) {
+		IWL_ERR(trans, "Command %s: a command is already active!\n",
+			trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+		return -EIO;
+	}
+
+	IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
+		       trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+
+	cmd_idx = iwl_enqueue_hcmd(trans, cmd);
+	if (cmd_idx < 0) {
+		ret = cmd_idx;
+		clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+		IWL_ERR(trans,
+			"Error sending %s: enqueue_hcmd failed: %d\n",
+			trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret);
+		return ret;
+	}
+
+	ret = wait_event_timeout(trans->wait_command_queue,
+				 !test_bit(STATUS_HCMD_ACTIVE,
+					   &trans_pcie->status),
+				 HOST_COMPLETE_TIMEOUT);
+	if (!ret) {
+		if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
+			struct iwl_tx_queue *txq =
+				&trans_pcie->txq[trans_pcie->cmd_queue];
+			struct iwl_queue *q = &txq->q;
+
+			IWL_ERR(trans,
+				"Error sending %s: time out after %dms.\n",
+				trans_pcie_get_cmd_string(trans_pcie, cmd->id),
+				jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+
+			IWL_ERR(trans,
+				"Current CMD queue read_ptr %d write_ptr %d\n",
+				q->read_ptr, q->write_ptr);
+
+			clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+			IWL_DEBUG_INFO(trans,
+				       "Clearing HCMD_ACTIVE for command %s\n",
+				       trans_pcie_get_cmd_string(trans_pcie,
+								 cmd->id));
+			ret = -ETIMEDOUT;
+			goto cancel;
+		}
+	}
+
+	if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) {
+		IWL_ERR(trans, "Error: Response NULL in '%s'\n",
+			trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+		ret = -EIO;
+		goto cancel;
+	}
+
+	return 0;
+
+cancel:
+	if (cmd->flags & CMD_WANT_SKB) {
+		/*
+		 * Cancel the CMD_WANT_SKB flag for the cmd in the
+		 * TX cmd queue. Otherwise in case the cmd comes
+		 * in later, it will possibly set an invalid
+		 * address (cmd->meta.source).
+		 */
+		trans_pcie->txq[trans_pcie->cmd_queue].
+			entries[cmd_idx].meta.flags &= ~CMD_WANT_SKB;
+	}
+
+	if (cmd->resp_pkt) {
+		iwl_free_resp(cmd);
+		cmd->resp_pkt = NULL;
+	}
+
+	return ret;
+}
+
+int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+{
+	if (cmd->flags & CMD_ASYNC)
+		return iwl_send_cmd_async(trans, cmd);
+
+	return iwl_send_cmd_sync(trans, cmd);
+}
+
+/* Frees buffers until index _not_ inclusive */
+int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
+			 struct sk_buff_head *skbs)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+	struct iwl_queue *q = &txq->q;
+	int last_to_free;
+	int freed = 0;
+
+	/* This function is not meant to release cmd queue*/
+	if (WARN_ON(txq_id == trans_pcie->cmd_queue))
+		return 0;
+
+	lockdep_assert_held(&txq->lock);
+
+	/*Since we free until index _not_ inclusive, the one before index is
+	 * the last we will free. This one must be used */
+	last_to_free = iwl_queue_dec_wrap(index, q->n_bd);
+
+	if ((index >= q->n_bd) ||
+	   (iwl_queue_used(q, last_to_free) == 0)) {
+		IWL_ERR(trans,
+			"%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n",
+			__func__, txq_id, last_to_free, q->n_bd,
+			q->write_ptr, q->read_ptr);
+		return 0;
+	}
+
+	if (WARN_ON(!skb_queue_empty(skbs)))
+		return 0;
+
+	for (;
+	     q->read_ptr != index;
+	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+		if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL))
+			continue;
+
+		__skb_queue_tail(skbs, txq->entries[txq->q.read_ptr].skb);
+
+		txq->entries[txq->q.read_ptr].skb = NULL;
+
+		iwlagn_txq_inval_byte_cnt_tbl(trans, txq);
+
+		iwl_txq_free_tfd(trans, txq, DMA_TO_DEVICE);
+		freed++;
+	}
+
+	iwl_queue_progress(trans_pcie, txq);
+
+	return freed;
+}
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 2fa879b..f4a2030 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -435,24 +435,40 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
  * Set Channel
  */
 
-static int lbs_cfg_set_channel(struct wiphy *wiphy,
-	struct net_device *netdev,
-	struct ieee80211_channel *channel,
-	enum nl80211_channel_type channel_type)
+static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
+				       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, "iface %s freq %d, type %d",
-			   netdev_name(netdev), channel->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;
 
-	if (netdev == priv->mesh_dev)
-		ret = lbs_mesh_set_channel(priv, channel->hw_value);
-	else
-		ret = lbs_set_channel(priv, channel->hw_value);
+	ret = lbs_set_channel(priv, channel->hw_value);
+
+ out:
+	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+	return ret;
+}
+
+static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
+				    struct net_device *netdev,
+				    struct ieee80211_channel *channel)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	int ret = -ENOTSUPP;
+
+	lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d",
+			   netdev_name(netdev), channel->center_freq);
+
+	if (netdev != priv->mesh_dev)
+		goto out;
+
+	ret = lbs_mesh_set_channel(priv, channel->hw_value);
 
  out:
 	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -2029,7 +2045,8 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
  */
 
 static struct cfg80211_ops lbs_cfg80211_ops = {
-	.set_channel = lbs_cfg_set_channel,
+	.set_monitor_channel = lbs_cfg_set_monitor_channel,
+	.libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
 	.scan = lbs_cfg_scan,
 	.connect = lbs_cfg_connect,
 	.disconnect = lbs_cfg_disconnect,
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index a06cc28..668dd27 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -483,7 +483,7 @@ static ssize_t lbs_rdmac_write(struct file *file,
 		res = -EFAULT;
 		goto out_unlock;
 	}
-	priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
+	priv->mac_offset = simple_strtoul(buf, NULL, 16);
 	res = count;
 out_unlock:
 	free_page(addr);
@@ -565,7 +565,7 @@ static ssize_t lbs_rdbbp_write(struct file *file,
 		res = -EFAULT;
 		goto out_unlock;
 	}
-	priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
+	priv->bbp_offset = simple_strtoul(buf, NULL, 16);
 	res = count;
 out_unlock:
 	free_page(addr);
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 6720054..60996ce 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -58,6 +58,7 @@ struct lbs_private {
 	uint16_t mesh_tlv;
 	u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
 	u8 mesh_ssid_len;
+	u8 mesh_channel;
 #endif
 
 	/* Debugfs */
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index cd3b0d4..64b7dc5 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -302,7 +302,7 @@ error:
 static void if_usb_disconnect(struct usb_interface *intf)
 {
 	struct if_usb_card *cardp = usb_get_intfdata(intf);
-	struct lbs_private *priv = (struct lbs_private *) cardp->priv;
+	struct lbs_private *priv = cardp->priv;
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index e87c031..9780775 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -131,16 +131,13 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
 
 int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
 {
+	priv->mesh_channel = channel;
 	return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
 }
 
 static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
 {
-	struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
-	if (mesh_wdev->channel)
-		return mesh_wdev->channel->hw_value;
-	else
-		return 1;
+	return priv->mesh_channel ?: 1;
 }
 
 /***************************************************************************
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index 19a5a92..d576dd6 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -253,7 +253,7 @@ lbtf_deb_leave(LBTF_DEB_MAIN);
 static void if_usb_disconnect(struct usb_interface *intf)
 {
 	struct if_usb_card *cardp = usb_get_intfdata(intf);
-	struct lbtf_private *priv = (struct lbtf_private *) cardp->priv;
+	struct lbtf_private *priv = cardp->priv;
 
 	lbtf_deb_enter(LBTF_DEB_MAIN);
 
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index a0b7cfd..5bddf53 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -678,8 +678,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
 			continue;
 
 		if (data2->idle || !data2->started ||
-		    !hwsim_ps_rx_ok(data2, skb) ||
-		    !data->channel || !data2->channel ||
+		    !hwsim_ps_rx_ok(data2, skb) || !data2->channel ||
 		    data->channel->center_freq != data2->channel->center_freq ||
 		    !(data->group & data2->group))
 			continue;
@@ -1486,7 +1485,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
 	struct mac80211_hwsim_data *data2;
 	struct ieee80211_tx_info *txi;
 	struct hwsim_tx_rate *tx_attempts;
-	struct sk_buff __user *ret_skb;
+	unsigned long ret_skb_ptr;
 	struct sk_buff *skb, *tmp;
 	struct mac_address *src;
 	unsigned int hwsim_flags;
@@ -1504,8 +1503,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
 				   info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
 	hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]);
 
-	ret_skb = (struct sk_buff __user *)
-		  (unsigned long) nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
+	ret_skb_ptr = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
 
 	data2 = get_hwsim_data_ref_from_addr(src);
 
@@ -1514,7 +1512,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
 
 	/* look for the skb matching the cookie passed back from user */
 	skb_queue_walk_safe(&data2->pending, skb, tmp) {
-		if (skb == ret_skb) {
+		if ((unsigned long)skb == ret_skb_ptr) {
 			skb_unlink(skb, &data2->pending);
 			found = true;
 			break;
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index fe8ebfe..e535c93 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -101,8 +101,7 @@ int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
 {
 	int tid;
 	struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
-	struct host_cmd_ds_11n_delba *del_ba =
-		(struct host_cmd_ds_11n_delba *) &resp->params.del_ba;
+	struct host_cmd_ds_11n_delba *del_ba = &resp->params.del_ba;
 	uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set);
 
 	tid = del_ba_param_set >> DELBA_TID_POS;
@@ -147,8 +146,7 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
 			      struct host_cmd_ds_command *resp)
 {
 	int tid;
-	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
-		(struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp;
+	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp;
 	struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
 
 	add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn))
@@ -412,7 +410,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 
 		memcpy((u8 *) bss_co_2040 +
 		       sizeof(struct mwifiex_ie_types_header),
-		       (u8 *) bss_desc->bcn_bss_co_2040 +
+		       bss_desc->bcn_bss_co_2040 +
 		       sizeof(struct ieee_types_header),
 		       le16_to_cpu(bss_co_2040->header.len));
 
@@ -426,10 +424,8 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 		ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY);
 		ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap));
 
-		memcpy((u8 *) ext_cap +
-		       sizeof(struct mwifiex_ie_types_header),
-		       (u8 *) bss_desc->bcn_ext_cap +
-		       sizeof(struct ieee_types_header),
+		memcpy((u8 *)ext_cap + sizeof(struct mwifiex_ie_types_header),
+		       bss_desc->bcn_ext_cap + sizeof(struct ieee_types_header),
 		       le16_to_cpu(ext_cap->header.len));
 
 		*buffer += sizeof(struct mwifiex_ie_types_extcap);
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h
index 77646d7..28366e9 100644
--- a/drivers/net/wireless/mwifiex/11n.h
+++ b/drivers/net/wireless/mwifiex/11n.h
@@ -105,8 +105,7 @@ static inline u8 mwifiex_space_avail_for_new_ba_stream(
 		priv = adapter->priv[i];
 		if (priv)
 			ba_stream_num += mwifiex_wmm_list_len(
-						(struct list_head *)
-						&priv->tx_ba_stream_tbl_ptr);
+				&priv->tx_ba_stream_tbl_ptr);
 	}
 
 	return ((ba_stream_num <
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index 9c44088..591ccd3 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -256,7 +256,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
 	else
 		last_seq = priv->rx_seq[tid];
 
-	if (last_seq >= new_node->start_win)
+	if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
+	    last_seq >= new_node->start_win)
 		new_node->start_win = last_seq + 1;
 
 	new_node->win_size = win_size;
@@ -296,9 +297,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
  */
 int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf)
 {
-	struct host_cmd_ds_11n_addba_req *add_ba_req =
-		(struct host_cmd_ds_11n_addba_req *)
-		&cmd->params.add_ba_req;
+	struct host_cmd_ds_11n_addba_req *add_ba_req = &cmd->params.add_ba_req;
 
 	cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
 	cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
@@ -320,9 +319,7 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
 				  struct host_cmd_ds_11n_addba_req
 				  *cmd_addba_req)
 {
-	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
-		(struct host_cmd_ds_11n_addba_rsp *)
-		&cmd->params.add_ba_rsp;
+	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &cmd->params.add_ba_rsp;
 	u8 tid;
 	int win_size;
 	uint16_t block_ack_param_set;
@@ -367,8 +364,7 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
  */
 int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf)
 {
-	struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *)
-		&cmd->params.del_ba;
+	struct host_cmd_ds_11n_delba *del_ba = &cmd->params.del_ba;
 
 	cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
 	cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
@@ -398,8 +394,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
 	int start_win, end_win, win_size;
 	u16 pkt_index;
 
-	tbl = mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv,
-					     tid, ta);
+	tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
 	if (!tbl) {
 		if (pkt_type != PKT_TYPE_BAR)
 			mwifiex_process_rx_packet(priv->adapter, payload);
@@ -520,9 +515,7 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
 int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
 			       struct host_cmd_ds_command *resp)
 {
-	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
-		(struct host_cmd_ds_11n_addba_rsp *)
-		&resp->params.add_ba_rsp;
+	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp;
 	int tid, win_size;
 	struct mwifiex_rx_reorder_tbl *tbl;
 	uint16_t block_ack_param_set;
@@ -596,5 +589,5 @@ void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
 	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 
 	INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
-	memset(priv->rx_seq, 0, sizeof(priv->rx_seq));
+	mwifiex_reset_11n_rx_seq_num(priv);
 }
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h
index f1bffeb..6c9815a 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.h
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h
@@ -37,6 +37,13 @@
 
 #define ADDBA_RSP_STATUS_ACCEPT 0
 
+#define MWIFIEX_DEF_11N_RX_SEQ_NUM	0xffff
+
+static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv)
+{
+	memset(priv->rx_seq, 0xff, sizeof(priv->rx_seq));
+}
+
 int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *,
 			       u16 seqNum,
 			       u16 tid, u8 *ta,
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 015fec3..0d46b3d 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -170,7 +170,9 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
 	if (!priv->sec_info.wep_enabled)
 		return 0;
 
-	if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) {
+	if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
+		priv->wep_key_curr_index = key_index;
+	} else if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) {
 		wiphy_err(wiphy, "set default Tx key index\n");
 		return -EFAULT;
 	}
@@ -187,9 +189,25 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
 			 struct key_params *params)
 {
 	struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev);
+	struct mwifiex_wep_key *wep_key;
 	const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 	const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
 
+	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP &&
+	    (params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+	     params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
+		if (params->key && params->key_len) {
+			wep_key = &priv->wep_key[key_index];
+			memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
+			memcpy(wep_key->key_material, params->key,
+			       params->key_len);
+			wep_key->key_index = key_index;
+			wep_key->key_length = params->key_len;
+			priv->sec_info.wep_enabled = 1;
+		}
+		return 0;
+	}
+
 	if (mwifiex_set_encode(priv, params->key, params->key_len,
 			       key_index, peer_mac, 0)) {
 		wiphy_err(wiphy, "crypto keys added\n");
@@ -384,13 +402,13 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv,
 	cfp.freq = chan->center_freq;
 	cfp.channel = ieee80211_frequency_to_channel(chan->center_freq);
 
-	if (mwifiex_bss_set_channel(priv, &cfp))
-		return -EFAULT;
-
-	if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+	if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
+		if (mwifiex_bss_set_channel(priv, &cfp))
+			return -EFAULT;
 		return mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
-	else
-		return mwifiex_uap_set_channel(priv, cfp.channel);
+	}
+
+	return 0;
 }
 
 /*
@@ -961,12 +979,25 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
 		return -EINVAL;
 	}
 
+	bss_cfg->channel =
+	    (u8)ieee80211_frequency_to_channel(params->channel->center_freq);
+	bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
+
+	if (mwifiex_set_rf_channel(priv, params->channel,
+				   params->channel_type)) {
+		kfree(bss_cfg);
+		wiphy_err(wiphy, "Failed to set band config information!\n");
+		return -1;
+	}
+
 	if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
 		kfree(bss_cfg);
 		wiphy_err(wiphy, "Failed to parse secuirty parameters!\n");
 		return -1;
 	}
 
+	mwifiex_set_ht_params(priv, bss_cfg, params);
+
 	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
 				  HostCmd_ACT_GEN_SET, 0, NULL)) {
 		wiphy_err(wiphy, "Failed to stop the BSS\n");
@@ -990,6 +1021,16 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
 		return -1;
 	}
 
+	if (priv->sec_info.wep_enabled)
+		priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
+	else
+		priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+
+	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
+				  HostCmd_ACT_GEN_SET, 0,
+				  &priv->curr_pkt_filter))
+		return -1;
+
 	return 0;
 }
 
@@ -1484,7 +1525,7 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
 	struct wireless_dev *wdev;
 
 	if (!adapter)
-		return NULL;
+		return ERR_PTR(-EFAULT);
 
 	switch (type) {
 	case NL80211_IFTYPE_UNSPECIFIED:
@@ -1494,12 +1535,12 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
 		if (priv->bss_mode) {
 			wiphy_err(wiphy,
 				  "cannot create multiple sta/adhoc ifaces\n");
-			return NULL;
+			return ERR_PTR(-EINVAL);
 		}
 
 		wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
 		if (!wdev)
-			return NULL;
+			return ERR_PTR(-ENOMEM);
 
 		wdev->wiphy = wiphy;
 		priv->wdev = wdev;
@@ -1522,12 +1563,12 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
 
 		if (priv->bss_mode) {
 			wiphy_err(wiphy, "Can't create multiple AP interfaces");
-			return NULL;
+			return ERR_PTR(-EINVAL);
 		}
 
 		wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
 		if (!wdev)
-			return NULL;
+			return ERR_PTR(-ENOMEM);
 
 		priv->wdev = wdev;
 		wdev->wiphy = wiphy;
@@ -1544,14 +1585,15 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
 		break;
 	default:
 		wiphy_err(wiphy, "type not supported\n");
-		return NULL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name,
 			      ether_setup, 1);
 	if (!dev) {
 		wiphy_err(wiphy, "no memory available for netdevice\n");
-		goto error;
+		priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	mwifiex_init_priv_params(priv, dev);
@@ -1582,7 +1624,9 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
 	/* Register network device */
 	if (register_netdevice(dev)) {
 		wiphy_err(wiphy, "cannot register virtual network device\n");
-		goto error;
+		free_netdev(dev);
+		priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+		return ERR_PTR(-EFAULT);
 	}
 
 	sema_init(&priv->async_sem, 1);
@@ -1594,12 +1638,6 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
 	mwifiex_dev_debugfs_init(priv);
 #endif
 	return dev;
-error:
-	if (dev && (dev->reg_state == NETREG_UNREGISTERED))
-		free_netdev(dev);
-	priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
-
-	return NULL;
 }
 EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
 
@@ -1716,7 +1754,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
 	wdev_priv = wiphy_priv(wiphy);
 	*(unsigned long *)wdev_priv = (unsigned long)adapter;
 
-	set_wiphy_dev(wiphy, (struct device *)priv->adapter->dev);
+	set_wiphy_dev(wiphy, priv->adapter->dev);
 
 	ret = wiphy_register(wiphy);
 	if (ret < 0) {
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 51e023e..ea37b88 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -1102,7 +1102,8 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
 		&resp->params.opt_hs_cfg;
 	uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions);
 
-	if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) {
+	if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE) &&
+	    adapter->iface_type == MWIFIEX_SDIO) {
 		mwifiex_hs_activated_event(priv, true);
 		return 0;
 	} else {
@@ -1114,6 +1115,9 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
 	}
 	if (conditions != HOST_SLEEP_CFG_CANCEL) {
 		adapter->is_hs_configured = true;
+		if (adapter->iface_type == MWIFIEX_USB ||
+		    adapter->iface_type == MWIFIEX_PCIE)
+			mwifiex_hs_activated_event(priv, true);
 	} else {
 		adapter->is_hs_configured = false;
 		if (adapter->hs_activated)
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 561452a..1184141 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -124,6 +124,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_UAP_DTIM_PERIOD    (PROPRIETARY_TLV_BASE_ID + 45)
 #define TLV_TYPE_UAP_BCAST_SSID     (PROPRIETARY_TLV_BASE_ID + 48)
 #define TLV_TYPE_UAP_RTS_THRESHOLD  (PROPRIETARY_TLV_BASE_ID + 51)
+#define TLV_TYPE_UAP_WEP_KEY        (PROPRIETARY_TLV_BASE_ID + 59)
 #define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60)
 #define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64)
 #define TLV_TYPE_UAP_AKMP           (PROPRIETARY_TLV_BASE_ID + 65)
@@ -162,6 +163,12 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 
 #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11))
 
+#define MWIFIEX_DEF_HT_CAP	(IEEE80211_HT_CAP_DSSSCCK40 | \
+				 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | \
+				 IEEE80211_HT_CAP_SM_PS)
+
+#define MWIFIEX_DEF_AMPDU	IEEE80211_HT_AMPDU_PARM_FACTOR
+
 /* dev_cap bitmap
  * BIT
  * 0-16		reserved
@@ -1195,6 +1202,13 @@ struct host_cmd_tlv_passphrase {
 	u8 passphrase[0];
 } __packed;
 
+struct host_cmd_tlv_wep_key {
+	struct host_cmd_tlv tlv;
+	u8 key_index;
+	u8 is_default;
+	u8 key[1];
+};
+
 struct host_cmd_tlv_auth_type {
 	struct host_cmd_tlv tlv;
 	u8 auth_type;
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c
index ceb82cd..328fb14 100644
--- a/drivers/net/wireless/mwifiex/ie.c
+++ b/drivers/net/wireless/mwifiex/ie.c
@@ -224,29 +224,46 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
 			 struct cfg80211_ap_settings *params)
 {
 	struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
-	struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL;
-	struct ieee_types_header *ie = NULL;
+	struct mwifiex_ie *ar_ie = NULL, *gen_ie = NULL;
+	struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL;
 	u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK;
 	u16 ar_idx = MWIFIEX_AUTO_IDX_MASK, rsn_idx = MWIFIEX_AUTO_IDX_MASK;
-	u16 mask;
+	u16 mask, ie_len = 0;
+	const u8 *vendor_ie;
 	int ret = 0;
 
 	if (params->beacon.tail && params->beacon.tail_len) {
-		ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, params->beacon.tail,
-					      params->beacon.tail_len);
-		if (ie) {
-			rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
-			if (!rsn_ie)
-				return -ENOMEM;
-
-			rsn_ie->ie_index = cpu_to_le16(rsn_idx);
-			mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
-			       MGMT_MASK_ASSOC_RESP;
-			rsn_ie->mgmt_subtype_mask = cpu_to_le16(mask);
-			rsn_ie->ie_length = cpu_to_le16(ie->len + 2);
-			memcpy(rsn_ie->ie_buffer, ie, ie->len + 2);
-
-			if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &rsn_idx,
+		gen_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+		if (!gen_ie)
+			return -ENOMEM;
+		gen_ie->ie_index = cpu_to_le16(rsn_idx);
+		mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
+		       MGMT_MASK_ASSOC_RESP;
+		gen_ie->mgmt_subtype_mask = cpu_to_le16(mask);
+
+		rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN,
+						  params->beacon.tail,
+						  params->beacon.tail_len);
+		if (rsn_ie) {
+			memcpy(gen_ie->ie_buffer, rsn_ie, rsn_ie->len + 2);
+			ie_len = rsn_ie->len + 2;
+			gen_ie->ie_length = cpu_to_le16(ie_len);
+		}
+
+		vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+						    WLAN_OUI_TYPE_MICROSOFT_WPA,
+						    params->beacon.tail,
+						    params->beacon.tail_len);
+		if (vendor_ie) {
+			wpa_ie = (struct ieee_types_header *)vendor_ie;
+			memcpy(gen_ie->ie_buffer + ie_len,
+			       wpa_ie, wpa_ie->len + 2);
+			ie_len += wpa_ie->len + 2;
+			gen_ie->ie_length = cpu_to_le16(ie_len);
+		}
+
+		if (rsn_ie || wpa_ie) {
+			if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx,
 							 NULL, NULL,
 							 NULL, NULL)) {
 				ret = -1;
@@ -319,7 +336,7 @@ done:
 	kfree(beacon_ie);
 	kfree(pr_ie);
 	kfree(ar_ie);
-	kfree(rsn_ie);
+	kfree(gen_ie);
 
 	return ret;
 }
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index c1cb004..b543a4d 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -57,6 +57,69 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
 	return 0;
 }
 
+static void scan_delay_timer_fn(unsigned long data)
+{
+	struct mwifiex_private *priv = (struct mwifiex_private *)data;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *cmd_node, *tmp_node;
+	unsigned long flags;
+
+	if (!mwifiex_wmm_lists_empty(adapter)) {
+		if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
+			/*
+			 * Abort scan operation by cancelling all pending scan
+			 * command
+			 */
+			spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+			list_for_each_entry_safe(cmd_node, tmp_node,
+						 &adapter->scan_pending_q,
+						 list) {
+				list_del(&cmd_node->list);
+				cmd_node->wait_q_enabled = false;
+				mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+			}
+			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+					       flags);
+
+			spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+			adapter->scan_processing = false;
+			spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock,
+					       flags);
+
+			if (priv->user_scan_cfg) {
+				dev_dbg(priv->adapter->dev,
+					"info: %s: scan aborted\n", __func__);
+				cfg80211_scan_done(priv->scan_request, 1);
+				priv->scan_request = NULL;
+				kfree(priv->user_scan_cfg);
+				priv->user_scan_cfg = NULL;
+			}
+		} else {
+			/*
+			 * Tx data queue is still not empty, delay scan
+			 * operation further by 20msec.
+			 */
+			mod_timer(&priv->scan_delay_timer, jiffies +
+				  msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+			adapter->scan_delay_cnt++;
+		}
+		queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
+	} else {
+		/*
+		 * Tx data queue is empty. Get scan command from scan_pending_q
+		 * and put to cmd_pending_q to resume scan operation
+		 */
+		adapter->scan_delay_cnt = 0;
+		spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+		cmd_node = list_first_entry(&adapter->scan_pending_q,
+					    struct cmd_ctrl_node, list);
+		list_del(&cmd_node->list);
+		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+		mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+	}
+}
+
 /*
  * This function initializes the private structure and sets default
  * values to the members.
@@ -136,6 +199,9 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
 
 	priv->scan_block = false;
 
+	setup_timer(&priv->scan_delay_timer, scan_delay_timer_fn,
+		    (unsigned long)priv);
+
 	return mwifiex_add_bss_prio_tbl(priv);
 }
 
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index e6be6ee..9f088fb 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -21,6 +21,7 @@
 #define _MWIFIEX_IOCTL_H_
 
 #include <net/mac80211.h>
+#include <net/lib80211.h>
 
 enum {
 	MWIFIEX_SCAN_TYPE_UNCHANGED = 0,
@@ -71,6 +72,13 @@ struct wpa_param {
 	u8 passphrase[MWIFIEX_WPA_PASSHPHRASE_LEN];
 };
 
+struct wep_key {
+	u8 key_index;
+	u8 is_default;
+	u16 length;
+	u8 key[WLAN_KEY_LEN_WEP104];
+};
+
 #define KEY_MGMT_ON_HOST        0x03
 #define MWIFIEX_AUTH_MODE_AUTO  0xFF
 #define BAND_CONFIG_MANUAL      0x00
@@ -90,6 +98,8 @@ struct mwifiex_uap_bss_param {
 	u16 key_mgmt;
 	u16 key_mgmt_operation;
 	struct wpa_param wpa_cfg;
+	struct wep_key wep_cfg[NUM_WEP_KEYS];
+	struct ieee80211_ht_cap ht_cap;
 };
 
 enum {
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index d6b4fb0..82e63ce 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -1349,22 +1349,16 @@ static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
 {
 	u8 mac_address[ETH_ALEN];
 	int ret;
-	u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
 
-	if (mac) {
-		if (!memcmp(mac, zero_mac, sizeof(zero_mac)))
-			memcpy((u8 *) &mac_address,
-			       (u8 *) &priv->curr_bss_params.bss_descriptor.
-			       mac_address, ETH_ALEN);
-		else
-			memcpy((u8 *) &mac_address, (u8 *) mac, ETH_ALEN);
-	} else {
-		memcpy((u8 *) &mac_address, (u8 *) &priv->curr_bss_params.
-		       bss_descriptor.mac_address, ETH_ALEN);
-	}
+	if (!mac || is_zero_ether_addr(mac))
+		memcpy(mac_address,
+		       priv->curr_bss_params.bss_descriptor.mac_address,
+		       ETH_ALEN);
+	else
+		memcpy(mac_address, mac, ETH_ALEN);
 
 	ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
-				    HostCmd_ACT_GEN_SET, 0, &mac_address);
+				    HostCmd_ACT_GEN_SET, 0, mac_address);
 
 	return ret;
 }
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 3192855..f0219efc 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -190,7 +190,8 @@ process_start:
 			    adapter->tx_lock_flag)
 				break;
 
-			if (adapter->scan_processing || adapter->data_sent ||
+			if ((adapter->scan_processing &&
+			     !adapter->scan_delay_cnt) || adapter->data_sent ||
 			    mwifiex_wmm_lists_empty(adapter)) {
 				if (adapter->cmd_sent || adapter->curr_cmd ||
 				    (!is_command_pending(adapter)))
@@ -244,8 +245,8 @@ process_start:
 			}
 		}
 
-		if (!adapter->scan_processing && !adapter->data_sent &&
-		    !mwifiex_wmm_lists_empty(adapter)) {
+		if ((!adapter->scan_processing || adapter->scan_delay_cnt) &&
+		    !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) {
 			mwifiex_wmm_process_tx(adapter);
 			if (adapter->hs_activated) {
 				adapter->is_hs_configured = false;
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index bd3b0bf..0b3b5aa 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -79,14 +79,17 @@ enum {
 
 #define SCAN_BEACON_ENTRY_PAD			6
 
-#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME	200
-#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME	200
-#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME	110
+#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME	110
+#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME	30
+#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME	30
 
 #define SCAN_RSSI(RSSI)					(0x100 - ((u8)(RSSI)))
 
 #define MWIFIEX_MAX_TOTAL_SCAN_TIME	(MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
 
+#define MWIFIEX_MAX_SCAN_DELAY_CNT			50
+#define MWIFIEX_SCAN_DELAY_MSEC				20
+
 #define RSN_GTK_OUI_OFFSET				2
 
 #define MWIFIEX_OUI_NOT_PRESENT			0
@@ -482,6 +485,7 @@ struct mwifiex_private {
 	u16 proberesp_idx;
 	u16 assocresp_idx;
 	u16 rsn_idx;
+	struct timer_list scan_delay_timer;
 };
 
 enum mwifiex_ba_status {
@@ -686,6 +690,7 @@ struct mwifiex_adapter {
 	struct completion fw_load;
 	u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
 	u16 max_mgmt_ie_index;
+	u8 scan_delay_cnt;
 };
 
 int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -835,6 +840,9 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv,
 int mwifiex_set_secure_params(struct mwifiex_private *priv,
 			      struct mwifiex_uap_bss_param *bss_config,
 			      struct cfg80211_ap_settings *params);
+void mwifiex_set_ht_params(struct mwifiex_private *priv,
+			   struct mwifiex_uap_bss_param *bss_cfg,
+			   struct cfg80211_ap_settings *params);
 
 /*
  * This function checks if the queuing is RA based or not.
@@ -985,7 +993,6 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
 
 int mwifiex_main_process(struct mwifiex_adapter *);
 
-int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel);
 int mwifiex_bss_set_channel(struct mwifiex_private *,
 			    struct mwifiex_chan_freq_power *cfp);
 int mwifiex_get_bss_info(struct mwifiex_private *,
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 74f0457..98c6aab 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -28,7 +28,10 @@
 /* The maximum number of channels the firmware can scan per command */
 #define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN   14
 
-#define MWIFIEX_CHANNELS_PER_SCAN_CMD            4
+#define MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD	4
+#define MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD	15
+#define MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD	27
+#define MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD	35
 
 /* Memory needed to store a max sized Channel List TLV for a firmware scan */
 #define CHAN_TLV_MAX_SIZE  (sizeof(struct mwifiex_ie_types_header)         \
@@ -471,7 +474,7 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
  * This routine is used for any scan that is not provided with a
  * specific channel list to scan.
  */
-static void
+static int
 mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
 				 const struct mwifiex_user_scan_cfg
 							*user_scan_in,
@@ -528,6 +531,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
 		}
 
 	}
+	return chan_idx;
 }
 
 /*
@@ -727,6 +731,7 @@ mwifiex_config_scan(struct mwifiex_private *priv,
 	u32 num_probes;
 	u32 ssid_len;
 	u32 chan_idx;
+	u32 chan_num;
 	u32 scan_type;
 	u16 scan_dur;
 	u8 channel;
@@ -850,7 +855,7 @@ mwifiex_config_scan(struct mwifiex_private *priv,
 	if (*filtered_scan)
 		*max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
 	else
-		*max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD;
+		*max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD;
 
 	/* If the input config or adapter has the number of Probes set,
 	   add tlv */
@@ -962,13 +967,28 @@ mwifiex_config_scan(struct mwifiex_private *priv,
 			dev_dbg(adapter->dev,
 				"info: Scan: Scanning current channel only\n");
 		}
-
+		chan_num = chan_idx;
 	} else {
 		dev_dbg(adapter->dev,
 			"info: Scan: Creating full region channel list\n");
-		mwifiex_scan_create_channel_list(priv, user_scan_in,
-						 scan_chan_list,
-						 *filtered_scan);
+		chan_num = mwifiex_scan_create_channel_list(priv, user_scan_in,
+							    scan_chan_list,
+							    *filtered_scan);
+	}
+
+	/*
+	 * In associated state we will reduce the number of channels scanned per
+	 * scan command to avoid any traffic delay/loss. This number is decided
+	 * based on total number of channels to be scanned due to constraints
+	 * of command buffers.
+	 */
+	if (priv->media_connected) {
+		if (chan_num < MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD)
+			*max_chan_per_scan = 1;
+		else if (chan_num < MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD)
+			*max_chan_per_scan = 2;
+		else if (chan_num < MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD)
+			*max_chan_per_scan = 3;
 	}
 }
 
@@ -1014,14 +1034,12 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
 			case TLV_TYPE_TSFTIMESTAMP:
 				dev_dbg(adapter->dev, "info: SCAN_RESP: TSF "
 					"timestamp TLV, len = %d\n", tlv_len);
-				*tlv_data = (struct mwifiex_ie_types_data *)
-					current_tlv;
+				*tlv_data = current_tlv;
 				break;
 			case TLV_TYPE_CHANNELBANDLIST:
 				dev_dbg(adapter->dev, "info: SCAN_RESP: channel"
 					" band list TLV, len = %d\n", tlv_len);
-				*tlv_data = (struct mwifiex_ie_types_data *)
-					current_tlv;
+				*tlv_data = current_tlv;
 				break;
 			default:
 				dev_err(adapter->dev,
@@ -1226,15 +1244,15 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
 					bss_entry->beacon_buf);
 			break;
 		case WLAN_EID_BSS_COEX_2040:
-			bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr +
-					sizeof(struct ieee_types_header));
+			bss_entry->bcn_bss_co_2040 = current_ptr +
+				sizeof(struct ieee_types_header);
 			bss_entry->bss_co_2040_offset = (u16) (current_ptr +
 					sizeof(struct ieee_types_header) -
 						bss_entry->beacon_buf);
 			break;
 		case WLAN_EID_EXT_CAPABILITY:
-			bss_entry->bcn_ext_cap = (u8 *) (current_ptr +
-					sizeof(struct ieee_types_header));
+			bss_entry->bcn_ext_cap = current_ptr +
+				sizeof(struct ieee_types_header);
 			bss_entry->ext_cap_offset = (u16) (current_ptr +
 					sizeof(struct ieee_types_header) -
 					bss_entry->beacon_buf);
@@ -1683,8 +1701,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 				goto done;
 			}
 			if (element_id == WLAN_EID_DS_PARAMS) {
-				channel = *(u8 *) (current_ptr +
-					sizeof(struct ieee_types_header));
+				channel = *(current_ptr + sizeof(struct ieee_types_header));
 				break;
 			}
 
@@ -1772,14 +1789,23 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 			priv->user_scan_cfg = NULL;
 		}
 	} else {
-		/* Get scan command from scan_pending_q and put to
-		   cmd_pending_q */
-		cmd_node = list_first_entry(&adapter->scan_pending_q,
-					    struct cmd_ctrl_node, list);
-		list_del(&cmd_node->list);
-		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
-
-		mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+		if (!mwifiex_wmm_lists_empty(adapter)) {
+			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+					       flags);
+			adapter->scan_delay_cnt = 1;
+			mod_timer(&priv->scan_delay_timer, jiffies +
+				  msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+		} else {
+			/* Get scan command from scan_pending_q and put to
+			   cmd_pending_q */
+			cmd_node = list_first_entry(&adapter->scan_pending_q,
+						    struct cmd_ctrl_node, list);
+			list_del(&cmd_node->list);
+			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+					       flags);
+			mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
+							true);
+		}
 	}
 
 done:
@@ -2010,12 +2036,11 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
 
 	if (curr_bss->bcn_bss_co_2040)
 		curr_bss->bcn_bss_co_2040 =
-			(u8 *) (curr_bss->beacon_buf +
-					curr_bss->bss_co_2040_offset);
+			(curr_bss->beacon_buf + curr_bss->bss_co_2040_offset);
 
 	if (curr_bss->bcn_ext_cap)
-		curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf +
-				curr_bss->ext_cap_offset);
+		curr_bss->bcn_ext_cap = curr_bss->beacon_buf +
+			curr_bss->ext_cap_offset;
 }
 
 /*
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index e037747..fc8a9bf 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -978,10 +978,10 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
 		dev_dbg(adapter->dev, "info: --- Rx: Event ---\n");
 		adapter->event_cause = *(u32 *) skb->data;
 
-		skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN);
-
 		if ((skb->len > 0) && (skb->len  < MAX_EVENT_SIZE))
-			memcpy(adapter->event_body, skb->data, skb->len);
+			memcpy(adapter->event_body,
+			       skb->data + MWIFIEX_EVENT_HEADER_LEN,
+			       skb->len);
 
 		/* event cause has been saved to adapter->event_cause */
 		adapter->event_received = true;
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 40e025d..1ff1362 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -793,8 +793,7 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
 		struct host_cmd_ds_mac_reg_access *mac_reg;
 
 		cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN);
-		mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd->
-								params.mac_reg;
+		mac_reg = &cmd->params.mac_reg;
 		mac_reg->action = cpu_to_le16(cmd_action);
 		mac_reg->offset =
 			cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
@@ -806,8 +805,7 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
 		struct host_cmd_ds_bbp_reg_access *bbp_reg;
 
 		cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN);
-		bbp_reg = (struct host_cmd_ds_bbp_reg_access *)
-							&cmd->params.bbp_reg;
+		bbp_reg = &cmd->params.bbp_reg;
 		bbp_reg->action = cpu_to_le16(cmd_action);
 		bbp_reg->offset =
 			cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
@@ -819,8 +817,7 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
 		struct host_cmd_ds_rf_reg_access *rf_reg;
 
 		cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN);
-		rf_reg = (struct host_cmd_ds_rf_reg_access *)
-							&cmd->params.rf_reg;
+		rf_reg = &cmd->params.rf_reg;
 		rf_reg->action = cpu_to_le16(cmd_action);
 		rf_reg->offset = cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
 		rf_reg->value = (u8) le32_to_cpu(reg_rw->value);
@@ -831,8 +828,7 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
 		struct host_cmd_ds_pmic_reg_access *pmic_reg;
 
 		cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN);
-		pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd->
-				params.pmic_reg;
+		pmic_reg = &cmd->params.pmic_reg;
 		pmic_reg->action = cpu_to_le16(cmd_action);
 		pmic_reg->offset =
 				cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
@@ -844,8 +840,7 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
 		struct host_cmd_ds_rf_reg_access *cau_reg;
 
 		cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN);
-		cau_reg = (struct host_cmd_ds_rf_reg_access *)
-							&cmd->params.rf_reg;
+		cau_reg = &cmd->params.rf_reg;
 		cau_reg->action = cpu_to_le16(cmd_action);
 		cau_reg->offset =
 				cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
@@ -856,7 +851,6 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
 	{
 		struct mwifiex_ds_read_eeprom *rd_eeprom = data_buf;
 		struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom =
-			(struct host_cmd_ds_802_11_eeprom_access *)
 			&cmd->params.eeprom;
 
 		cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index a79ed9b..bd40541 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -227,7 +227,7 @@ static int mwifiex_ret_get_log(struct mwifiex_private *priv,
 			       struct mwifiex_ds_get_stats *stats)
 {
 	struct host_cmd_ds_802_11_get_log *get_log =
-		(struct host_cmd_ds_802_11_get_log *) &resp->params.get_log;
+		&resp->params.get_log;
 
 	if (stats) {
 		stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame);
@@ -282,7 +282,7 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
 	u32 i;
 	int ret = 0;
 
-	tlv_buf = (u8 *) ((u8 *) rate_cfg) +
+	tlv_buf = ((u8 *)rate_cfg) +
 			sizeof(struct host_cmd_ds_tx_rate_cfg);
 	tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16));
 
@@ -679,39 +679,33 @@ static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp,
 	eeprom = data_buf;
 	switch (type) {
 	case HostCmd_CMD_MAC_REG_ACCESS:
-		r.mac = (struct host_cmd_ds_mac_reg_access *)
-			&resp->params.mac_reg;
+		r.mac = &resp->params.mac_reg;
 		reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.mac->offset));
 		reg_rw->value = r.mac->value;
 		break;
 	case HostCmd_CMD_BBP_REG_ACCESS:
-		r.bbp = (struct host_cmd_ds_bbp_reg_access *)
-			&resp->params.bbp_reg;
+		r.bbp = &resp->params.bbp_reg;
 		reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.bbp->offset));
 		reg_rw->value = cpu_to_le32((u32) r.bbp->value);
 		break;
 
 	case HostCmd_CMD_RF_REG_ACCESS:
-		r.rf = (struct host_cmd_ds_rf_reg_access *)
-		       &resp->params.rf_reg;
+		r.rf = &resp->params.rf_reg;
 		reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.rf->offset));
 		reg_rw->value = cpu_to_le32((u32) r.bbp->value);
 		break;
 	case HostCmd_CMD_PMIC_REG_ACCESS:
-		r.pmic = (struct host_cmd_ds_pmic_reg_access *)
-			 &resp->params.pmic_reg;
+		r.pmic = &resp->params.pmic_reg;
 		reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.pmic->offset));
 		reg_rw->value = cpu_to_le32((u32) r.pmic->value);
 		break;
 	case HostCmd_CMD_CAU_REG_ACCESS:
-		r.rf = (struct host_cmd_ds_rf_reg_access *)
-		       &resp->params.rf_reg;
+		r.rf = &resp->params.rf_reg;
 		reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.rf->offset));
 		reg_rw->value = cpu_to_le32((u32) r.rf->value);
 		break;
 	case HostCmd_CMD_802_11_EEPROM_ACCESS:
-		r.eeprom = (struct host_cmd_ds_802_11_eeprom_access *)
-			   &resp->params.eeprom;
+		r.eeprom = &resp->params.eeprom;
 		pr_debug("info: EEPROM read len=%x\n", r.eeprom->byte_count);
 		if (le16_to_cpu(eeprom->byte_count) <
 		    le16_to_cpu(r.eeprom->byte_count)) {
@@ -787,7 +781,7 @@ static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv,
 				 struct mwifiex_ds_misc_subsc_evt *sub_event)
 {
 	struct host_cmd_ds_802_11_subsc_evt *cmd_sub_event =
-		(struct host_cmd_ds_802_11_subsc_evt *)&resp->params.subsc_evt;
+		&resp->params.subsc_evt;
 
 	/* For every subscribe event command (Get/Set/Clear), FW reports the
 	 * current set of subscribed events*/
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 4ace5a3..b8614a8 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -406,9 +406,9 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 		break;
 
 	case EVENT_UAP_STA_ASSOC:
-		skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
 		memset(&sinfo, 0, sizeof(sinfo));
-		event = (struct mwifiex_assoc_event *)adapter->event_skb->data;
+		event = (struct mwifiex_assoc_event *)
+			(adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
 		if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
 			len = -1;
 
@@ -422,7 +422,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
 			if (len != -1) {
 				sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
-				sinfo.assoc_req_ies = (u8 *)&event->data[len];
+				sinfo.assoc_req_ies = &event->data[len];
 				len = (u8 *)sinfo.assoc_req_ies -
 				      (u8 *)&event->frame_control;
 				sinfo.assoc_req_ies_len =
@@ -433,9 +433,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 				 GFP_KERNEL);
 		break;
 	case EVENT_UAP_STA_DEAUTH:
-		skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
-		cfg80211_del_sta(priv->netdev, adapter->event_skb->data,
-				 GFP_KERNEL);
+		cfg80211_del_sta(priv->netdev, adapter->event_body +
+				 MWIFIEX_UAP_EVENT_EXTRA_HEADER, GFP_KERNEL);
 		break;
 	case EVENT_UAP_BSS_IDLE:
 		priv->media_connected = false;
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index e2faec4..cecb272 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -161,15 +161,11 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
 		goto done;
 
 	for (i = 0; i < adapter->priv_num; i++) {
-
 		tpriv = adapter->priv[i];
 
-		if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA) &&
-		    (tpriv->media_connected)) {
-			if (netif_queue_stopped(tpriv->netdev))
-				mwifiex_wake_up_net_dev_queue(tpriv->netdev,
-							      adapter);
-		}
+		if (tpriv->media_connected &&
+		    netif_queue_stopped(tpriv->netdev))
+			mwifiex_wake_up_net_dev_queue(tpriv->netdev, adapter);
 	}
 done:
 	dev_kfree_skb_any(skb);
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index 8173ab6..f40e93f 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -26,6 +26,18 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
 			      struct mwifiex_uap_bss_param *bss_config,
 			      struct cfg80211_ap_settings *params) {
 	int i;
+	struct mwifiex_wep_key wep_key;
+
+	if (!params->privacy) {
+		bss_config->protocol = PROTOCOL_NO_SECURITY;
+		bss_config->key_mgmt = KEY_MGMT_NONE;
+		bss_config->wpa_cfg.length = 0;
+		priv->sec_info.wep_enabled = 0;
+		priv->sec_info.wpa_enabled = 0;
+		priv->sec_info.wpa2_enabled = 0;
+
+		return 0;
+	}
 
 	switch (params->auth_type) {
 	case NL80211_AUTHTYPE_OPEN_SYSTEM:
@@ -54,7 +66,7 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
 			}
 			if (params->crypto.wpa_versions &
 			    NL80211_WPA_VERSION_2) {
-				bss_config->protocol = PROTOCOL_WPA2;
+				bss_config->protocol |= PROTOCOL_WPA2;
 				bss_config->key_mgmt = KEY_MGMT_EAP;
 			}
 			break;
@@ -66,7 +78,7 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
 			}
 			if (params->crypto.wpa_versions &
 			    NL80211_WPA_VERSION_2) {
-				bss_config->protocol = PROTOCOL_WPA2;
+				bss_config->protocol |= PROTOCOL_WPA2;
 				bss_config->key_mgmt = KEY_MGMT_PSK;
 			}
 			break;
@@ -80,10 +92,19 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
 		case WLAN_CIPHER_SUITE_WEP104:
 			break;
 		case WLAN_CIPHER_SUITE_TKIP:
-			bss_config->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+				bss_config->wpa_cfg.pairwise_cipher_wpa |=
+								CIPHER_TKIP;
+			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+				bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
+								CIPHER_TKIP;
 			break;
 		case WLAN_CIPHER_SUITE_CCMP:
-			bss_config->wpa_cfg.pairwise_cipher_wpa2 =
+			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+				bss_config->wpa_cfg.pairwise_cipher_wpa |=
+								CIPHER_AES_CCMP;
+			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+				bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
 								CIPHER_AES_CCMP;
 		default:
 			break;
@@ -93,6 +114,27 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
 	switch (params->crypto.cipher_group) {
 	case WLAN_CIPHER_SUITE_WEP40:
 	case WLAN_CIPHER_SUITE_WEP104:
+		if (priv->sec_info.wep_enabled) {
+			bss_config->protocol = PROTOCOL_STATIC_WEP;
+			bss_config->key_mgmt = KEY_MGMT_NONE;
+			bss_config->wpa_cfg.length = 0;
+
+			for (i = 0; i < NUM_WEP_KEYS; i++) {
+				wep_key = priv->wep_key[i];
+				bss_config->wep_cfg[i].key_index = i;
+
+				if (priv->wep_key_curr_index == i)
+					bss_config->wep_cfg[i].is_default = 1;
+				else
+					bss_config->wep_cfg[i].is_default = 0;
+
+				bss_config->wep_cfg[i].length =
+							     wep_key.key_length;
+				memcpy(&bss_config->wep_cfg[i].key,
+				       &wep_key.key_material,
+				       wep_key.key_length);
+			}
+		}
 		break;
 	case WLAN_CIPHER_SUITE_TKIP:
 		bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
@@ -107,6 +149,33 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
 	return 0;
 }
 
+/* This function updates 11n related parameters from IE and sets them into
+ * bss_config structure.
+ */
+void
+mwifiex_set_ht_params(struct mwifiex_private *priv,
+		      struct mwifiex_uap_bss_param *bss_cfg,
+		      struct cfg80211_ap_settings *params)
+{
+	const u8 *ht_ie;
+
+	if (!ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
+		return;
+
+	ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail,
+				 params->beacon.tail_len);
+	if (ht_ie) {
+		memcpy(&bss_cfg->ht_cap, ht_ie + 2,
+		       sizeof(struct ieee80211_ht_cap));
+	} else {
+		memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap));
+		bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP);
+		bss_cfg->ht_cap.ampdu_params_info = MWIFIEX_DEF_AMPDU;
+	}
+
+	return;
+}
+
 /* This function initializes some of mwifiex_uap_bss_param variables.
  * This helps FW in ignoring invalid values. These values may or may not
  * be get updated to valid ones at later stage.
@@ -124,6 +193,120 @@ void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
 }
 
 /* This function parses BSS related parameters from structure
+ * and prepares TLVs specific to WPA/WPA2 security.
+ * These TLVs are appended to command buffer.
+ */
+static void
+mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
+{
+	struct host_cmd_tlv_pwk_cipher *pwk_cipher;
+	struct host_cmd_tlv_gwk_cipher *gwk_cipher;
+	struct host_cmd_tlv_passphrase *passphrase;
+	struct host_cmd_tlv_akmp *tlv_akmp;
+	struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
+	u16 cmd_size = *param_size;
+	u8 *tlv = *tlv_buf;
+
+	tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
+	tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
+	tlv_akmp->tlv.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
+					sizeof(struct host_cmd_tlv));
+	tlv_akmp->key_mgmt_operation = cpu_to_le16(bss_cfg->key_mgmt_operation);
+	tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
+	cmd_size += sizeof(struct host_cmd_tlv_akmp);
+	tlv += sizeof(struct host_cmd_tlv_akmp);
+
+	if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & VALID_CIPHER_BITMAP) {
+		pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
+		pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+		pwk_cipher->tlv.len =
+			cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
+				    sizeof(struct host_cmd_tlv));
+		pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
+		pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa;
+		cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
+		tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
+	}
+
+	if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) {
+		pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
+		pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+		pwk_cipher->tlv.len =
+			cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
+				    sizeof(struct host_cmd_tlv));
+		pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
+		pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
+		cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
+		tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
+	}
+
+	if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
+		gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
+		gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
+		gwk_cipher->tlv.len =
+			cpu_to_le16(sizeof(struct host_cmd_tlv_gwk_cipher) -
+				    sizeof(struct host_cmd_tlv));
+		gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
+		cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
+		tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
+	}
+
+	if (bss_cfg->wpa_cfg.length) {
+		passphrase = (struct host_cmd_tlv_passphrase *)tlv;
+		passphrase->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
+		passphrase->tlv.len = cpu_to_le16(bss_cfg->wpa_cfg.length);
+		memcpy(passphrase->passphrase, bss_cfg->wpa_cfg.passphrase,
+		       bss_cfg->wpa_cfg.length);
+		cmd_size += sizeof(struct host_cmd_tlv) +
+			    bss_cfg->wpa_cfg.length;
+		tlv += sizeof(struct host_cmd_tlv) + bss_cfg->wpa_cfg.length;
+	}
+
+	*param_size = cmd_size;
+	*tlv_buf = tlv;
+
+	return;
+}
+
+/* This function parses BSS related parameters from structure
+ * and prepares TLVs specific to WEP encryption.
+ * These TLVs are appended to command buffer.
+ */
+static void
+mwifiex_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
+{
+	struct host_cmd_tlv_wep_key *wep_key;
+	u16 cmd_size = *param_size;
+	int i;
+	u8 *tlv = *tlv_buf;
+	struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (bss_cfg->wep_cfg[i].length &&
+		    (bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP40 ||
+		     bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP104)) {
+			wep_key = (struct host_cmd_tlv_wep_key *)tlv;
+			wep_key->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+			wep_key->tlv.len =
+				cpu_to_le16(bss_cfg->wep_cfg[i].length + 2);
+			wep_key->key_index = bss_cfg->wep_cfg[i].key_index;
+			wep_key->is_default = bss_cfg->wep_cfg[i].is_default;
+			memcpy(wep_key->key, bss_cfg->wep_cfg[i].key,
+			       bss_cfg->wep_cfg[i].length);
+			cmd_size += sizeof(struct host_cmd_tlv) + 2 +
+				    bss_cfg->wep_cfg[i].length;
+			tlv += sizeof(struct host_cmd_tlv) + 2 +
+				    bss_cfg->wep_cfg[i].length;
+		}
+	}
+
+	*param_size = cmd_size;
+	*tlv_buf = tlv;
+
+	return;
+}
+
+/* This function parses BSS related parameters from structure
  * and prepares TLVs. These TLVs are appended to command buffer.
 */
 static int
@@ -137,12 +320,9 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
 	struct host_cmd_tlv_frag_threshold *frag_threshold;
 	struct host_cmd_tlv_rts_threshold *rts_threshold;
 	struct host_cmd_tlv_retry_limit *retry_limit;
-	struct host_cmd_tlv_pwk_cipher *pwk_cipher;
-	struct host_cmd_tlv_gwk_cipher *gwk_cipher;
 	struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
 	struct host_cmd_tlv_auth_type *auth_type;
-	struct host_cmd_tlv_passphrase *passphrase;
-	struct host_cmd_tlv_akmp *tlv_akmp;
+	struct mwifiex_ie_types_htcap *htcap;
 	struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
 	u16 cmd_size = *param_size;
 
@@ -232,70 +412,11 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
 	}
 	if ((bss_cfg->protocol & PROTOCOL_WPA) ||
 	    (bss_cfg->protocol & PROTOCOL_WPA2) ||
-	    (bss_cfg->protocol & PROTOCOL_EAP)) {
-		tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
-		tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
-		tlv_akmp->tlv.len =
-		    cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
-				sizeof(struct host_cmd_tlv));
-		tlv_akmp->key_mgmt_operation =
-			cpu_to_le16(bss_cfg->key_mgmt_operation);
-		tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
-		cmd_size += sizeof(struct host_cmd_tlv_akmp);
-		tlv += sizeof(struct host_cmd_tlv_akmp);
-
-		if (bss_cfg->wpa_cfg.pairwise_cipher_wpa &
-				VALID_CIPHER_BITMAP) {
-			pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
-			pwk_cipher->tlv.type =
-				cpu_to_le16(TLV_TYPE_PWK_CIPHER);
-			pwk_cipher->tlv.len = cpu_to_le16(
-				sizeof(struct host_cmd_tlv_pwk_cipher) -
-				sizeof(struct host_cmd_tlv));
-			pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
-			pwk_cipher->cipher =
-				bss_cfg->wpa_cfg.pairwise_cipher_wpa;
-			cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
-			tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
-		}
-		if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 &
-				VALID_CIPHER_BITMAP) {
-			pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
-			pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
-			pwk_cipher->tlv.len = cpu_to_le16(
-				sizeof(struct host_cmd_tlv_pwk_cipher) -
-				sizeof(struct host_cmd_tlv));
-			pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
-			pwk_cipher->cipher =
-				bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
-			cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
-			tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
-		}
-		if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
-			gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
-			gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
-			gwk_cipher->tlv.len = cpu_to_le16(
-				sizeof(struct host_cmd_tlv_gwk_cipher) -
-				sizeof(struct host_cmd_tlv));
-			gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
-			cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
-			tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
-		}
-		if (bss_cfg->wpa_cfg.length) {
-			passphrase = (struct host_cmd_tlv_passphrase *)tlv;
-			passphrase->tlv.type =
-				cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
-			passphrase->tlv.len =
-				cpu_to_le16(bss_cfg->wpa_cfg.length);
-			memcpy(passphrase->passphrase,
-			       bss_cfg->wpa_cfg.passphrase,
-			       bss_cfg->wpa_cfg.length);
-			cmd_size += sizeof(struct host_cmd_tlv) +
-				    bss_cfg->wpa_cfg.length;
-			tlv += sizeof(struct host_cmd_tlv) +
-			       bss_cfg->wpa_cfg.length;
-		}
-	}
+	    (bss_cfg->protocol & PROTOCOL_EAP))
+		mwifiex_uap_bss_wpa(&tlv, cmd_buf, &cmd_size);
+	else
+		mwifiex_uap_bss_wep(&tlv, cmd_buf, &cmd_size);
+
 	if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
 	    (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
 		auth_type = (struct host_cmd_tlv_auth_type *)tlv;
@@ -319,6 +440,25 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
 		tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
 	}
 
+	if (bss_cfg->ht_cap.cap_info) {
+		htcap = (struct mwifiex_ie_types_htcap *)tlv;
+		htcap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+		htcap->header.len =
+				cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+		htcap->ht_cap.cap_info = bss_cfg->ht_cap.cap_info;
+		htcap->ht_cap.ampdu_params_info =
+					     bss_cfg->ht_cap.ampdu_params_info;
+		memcpy(&htcap->ht_cap.mcs, &bss_cfg->ht_cap.mcs,
+		       sizeof(struct ieee80211_mcs_info));
+		htcap->ht_cap.extended_ht_cap_info =
+					bss_cfg->ht_cap.extended_ht_cap_info;
+		htcap->ht_cap.tx_BF_cap_info = bss_cfg->ht_cap.tx_BF_cap_info;
+		htcap->ht_cap.antenna_selection_info =
+					bss_cfg->ht_cap.antenna_selection_info;
+		cmd_size += sizeof(struct mwifiex_ie_types_htcap);
+		tlv += sizeof(struct mwifiex_ie_types_htcap);
+	}
+
 	*param_size = cmd_size;
 
 	return 0;
@@ -410,33 +550,3 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
 
 	return 0;
 }
-
-/* This function sets the RF channel for AP.
- *
- * This function populates channel information in AP config structure
- * and sends command to configure channel information in AP.
- */
-int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel)
-{
-	struct mwifiex_uap_bss_param *bss_cfg;
-	struct wiphy *wiphy = priv->wdev->wiphy;
-
-	bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
-	if (!bss_cfg)
-		return -ENOMEM;
-
-	mwifiex_set_sys_config_invalid_data(bss_cfg);
-	bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
-	bss_cfg->channel = channel;
-
-	if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
-				   HostCmd_ACT_GEN_SET,
-				   UAP_BSS_PARAMS_I, bss_cfg)) {
-		wiphy_err(wiphy, "Failed to set the uAP channel\n");
-		kfree(bss_cfg);
-		return -1;
-	}
-
-	kfree(bss_cfg);
-	return 0;
-}
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index 49ebf20..22a5916 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -49,6 +49,7 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
 	struct device *dev = adapter->dev;
 	u32 recv_type;
 	__le32 tmp;
+	int ret;
 
 	if (adapter->hs_activated)
 		mwifiex_process_hs_config(adapter);
@@ -69,16 +70,19 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
 		case MWIFIEX_USB_TYPE_CMD:
 			if (skb->len > MWIFIEX_SIZE_OF_CMD_BUFFER) {
 				dev_err(dev, "CMD: skb->len too large\n");
-				return -1;
+				ret = -1;
+				goto exit_restore_skb;
 			} else if (!adapter->curr_cmd) {
 				dev_dbg(dev, "CMD: no curr_cmd\n");
 				if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
 					mwifiex_process_sleep_confirm_resp(
 							adapter, skb->data,
 							skb->len);
-					return 0;
+					ret = 0;
+					goto exit_restore_skb;
 				}
-				return -1;
+				ret = -1;
+				goto exit_restore_skb;
 			}
 
 			adapter->curr_cmd->resp_skb = skb;
@@ -87,20 +91,22 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
 		case MWIFIEX_USB_TYPE_EVENT:
 			if (skb->len < sizeof(u32)) {
 				dev_err(dev, "EVENT: skb->len too small\n");
-				return -1;
+				ret = -1;
+				goto exit_restore_skb;
 			}
 			skb_copy_from_linear_data(skb, &tmp, sizeof(u32));
 			adapter->event_cause = le32_to_cpu(tmp);
-			skb_pull(skb, sizeof(u32));
 			dev_dbg(dev, "event_cause %#x\n", adapter->event_cause);
 
 			if (skb->len > MAX_EVENT_SIZE) {
 				dev_err(dev, "EVENT: event body too large\n");
-				return -1;
+				ret = -1;
+				goto exit_restore_skb;
 			}
 
-			skb_copy_from_linear_data(skb, adapter->event_body,
-						  skb->len);
+			memcpy(adapter->event_body, skb->data +
+			       MWIFIEX_EVENT_HEADER_LEN, skb->len);
+
 			adapter->event_received = true;
 			adapter->event_skb = skb;
 			break;
@@ -124,6 +130,12 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
 	}
 
 	return -EINPROGRESS;
+
+exit_restore_skb:
+	/* The buffer will be reused for further cmds/events */
+	skb_push(skb, INTF_HEADER_LEN);
+
+	return ret;
 }
 
 static void mwifiex_usb_rx_complete(struct urb *urb)
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index f3fc655..3fa4d41 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -404,6 +404,8 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
 		priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
 		priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
 
+		mwifiex_reset_11n_rx_seq_num(priv);
+
 		atomic_set(&priv->wmm.tx_pkts_queued, 0);
 		atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
 	}
@@ -1221,6 +1223,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
 
 	if (!ptr->is_11n_enabled ||
 	    mwifiex_is_ba_stream_setup(priv, ptr, tid) ||
+	    priv->wps.session_enable ||
 	    ((priv->sec_info.wpa_enabled ||
 	      priv->sec_info.wpa2_enabled) &&
 	     !priv->wpa_is_gtk_set)) {
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index f7b15b8..e156755 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -160,10 +160,9 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
 	return err;
 }
 
-static int orinoco_set_channel(struct wiphy *wiphy,
-			struct net_device *netdev,
-			struct ieee80211_channel *chan,
-			enum nl80211_channel_type channel_type)
+static int orinoco_set_monitor_channel(struct wiphy *wiphy,
+				       struct ieee80211_channel *chan,
+				       enum nl80211_channel_type channel_type)
 {
 	struct orinoco_private *priv = wiphy_priv(wiphy);
 	int err = 0;
@@ -286,7 +285,7 @@ static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 
 const struct cfg80211_ops orinoco_cfg_ops = {
 	.change_virtual_intf = orinoco_change_vif,
-	.set_channel = orinoco_set_channel,
+	.set_monitor_channel = orinoco_set_monitor_channel,
 	.scan = orinoco_scan,
 	.set_wiphy_params = orinoco_set_wiphy_params,
 };
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index fa8ce51..636daf2 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -905,7 +905,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev)
 
 	while (eeprom_size) {
 		blocksize = min(eeprom_size, maxblocksize);
-		ret = p54_download_eeprom(priv, (void *) (eeprom + offset),
+		ret = p54_download_eeprom(priv, eeprom + offset,
 					  offset, blocksize);
 		if (unlikely(ret))
 			goto free;
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index 18e82b3..9ba8510 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -478,7 +478,7 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
 
 		if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
 			memcpy(&body->longbow.curve_data,
-				(void *) entry + sizeof(__le16),
+				entry + sizeof(__le16),
 				priv->curve_data->entry_size);
 		} else {
 			struct p54_scan_body *chan = &body->normal;
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index 266d45b..799e148 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -455,7 +455,7 @@ islpci_eth_receive(islpci_private *priv)
 			      "Error mapping DMA address\n");
 
 			/* free the skbuf structure before aborting */
-			dev_kfree_skb_irq((struct sk_buff *) skb);
+			dev_kfree_skb_irq(skb);
 			skb = NULL;
 			break;
 		}
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 86a738b..598ca1c 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -1849,7 +1849,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
 	pr_debug("ray_cs: interrupt for *dev=%p\n", dev);
 
 	local = netdev_priv(dev);
-	link = (struct pcmcia_device *)local->finder;
+	link = local->finder;
 	if (!pcmcia_dev_present(link)) {
 		pr_debug(
 			"ray_cs interrupt from device not present or suspended.\n");
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 2e9e6af..dfcd02a 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2110,7 +2110,7 @@ resize_buf:
 	while (check_bssid_list_item(bssid, bssid_len, buf, len)) {
 		if (rndis_bss_info_update(usbdev, bssid) && match_bssid &&
 		    matched) {
-			if (!ether_addr_equal(bssid->mac, match_bssid))
+			if (ether_addr_equal(bssid->mac, match_bssid))
 				*matched = true;
 		}
 
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index 299c387..c7548da 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -99,6 +99,14 @@ config RT2800PCI_RT53XX
          rt2800pci driver.
          Supported chips: RT5390
 
+config RT2800PCI_RT3290
+       bool "rt2800pci - Include support for rt3290 devices (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       default y
+       ---help---
+         This adds support for rt3290 wireless chipset family to the
+         rt2800pci driver.
+         Supported chips: RT3290
 endif
 
 config RT2500USB
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 9348521..e252e9b 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -51,6 +51,7 @@
  * RF3320 2.4G 1T1R(RT3350/RT3370/RT3390)
  * RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
  * RF3053 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
+ * RF5360 2.4G 1T1R
  * RF5370 2.4G 1T1R
  * RF5390 2.4G 1T1R
  */
@@ -67,9 +68,12 @@
 #define RF3320				0x000b
 #define RF3322				0x000c
 #define RF3053				0x000d
+#define RF3290				0x3290
+#define RF5360				0x5360
 #define RF5370				0x5370
 #define RF5372				0x5372
 #define RF5390				0x5390
+#define RF5392				0x5392
 
 /*
  * Chipset revisions.
@@ -114,6 +118,12 @@
  * Registers.
  */
 
+
+/*
+ * MAC_CSR0_3290: MAC_CSR0 for RT3290 to identity MAC version number.
+ */
+#define MAC_CSR0_3290				0x0000
+
 /*
  * E2PROM_CSR: PCI EEPROM control register.
  * RELOAD: Write 1 to reload eeprom content.
@@ -130,6 +140,150 @@
 #define E2PROM_CSR_RELOAD		FIELD32(0x00000080)
 
 /*
+ * CMB_CTRL_CFG
+ */
+#define CMB_CTRL		0x0020
+#define AUX_OPT_BIT0		FIELD32(0x00000001)
+#define AUX_OPT_BIT1		FIELD32(0x00000002)
+#define AUX_OPT_BIT2		FIELD32(0x00000004)
+#define AUX_OPT_BIT3		FIELD32(0x00000008)
+#define AUX_OPT_BIT4		FIELD32(0x00000010)
+#define AUX_OPT_BIT5		FIELD32(0x00000020)
+#define AUX_OPT_BIT6		FIELD32(0x00000040)
+#define AUX_OPT_BIT7		FIELD32(0x00000080)
+#define AUX_OPT_BIT8		FIELD32(0x00000100)
+#define AUX_OPT_BIT9		FIELD32(0x00000200)
+#define AUX_OPT_BIT10		FIELD32(0x00000400)
+#define AUX_OPT_BIT11		FIELD32(0x00000800)
+#define AUX_OPT_BIT12		FIELD32(0x00001000)
+#define AUX_OPT_BIT13		FIELD32(0x00002000)
+#define AUX_OPT_BIT14		FIELD32(0x00004000)
+#define AUX_OPT_BIT15		FIELD32(0x00008000)
+#define LDO25_LEVEL		FIELD32(0x00030000)
+#define LDO25_LARGEA		FIELD32(0x00040000)
+#define LDO25_FRC_ON		FIELD32(0x00080000)
+#define CMB_RSV			FIELD32(0x00300000)
+#define XTAL_RDY		FIELD32(0x00400000)
+#define PLL_LD			FIELD32(0x00800000)
+#define LDO_CORE_LEVEL		FIELD32(0x0F000000)
+#define LDO_BGSEL		FIELD32(0x30000000)
+#define LDO3_EN			FIELD32(0x40000000)
+#define LDO0_EN			FIELD32(0x80000000)
+
+/*
+ * EFUSE_CSR_3290: RT3290 EEPROM
+ */
+#define EFUSE_CTRL_3290			0x0024
+
+/*
+ * EFUSE_DATA3 of 3290
+ */
+#define EFUSE_DATA3_3290		0x0028
+
+/*
+ * EFUSE_DATA2 of 3290
+ */
+#define EFUSE_DATA2_3290		0x002c
+
+/*
+ * EFUSE_DATA1 of 3290
+ */
+#define EFUSE_DATA1_3290		0x0030
+
+/*
+ * EFUSE_DATA0 of 3290
+ */
+#define EFUSE_DATA0_3290		0x0034
+
+/*
+ * OSC_CTRL_CFG
+ * Ring oscillator configuration
+ */
+#define OSC_CTRL		0x0038
+#define OSC_REF_CYCLE		FIELD32(0x00001fff)
+#define OSC_RSV			FIELD32(0x0000e000)
+#define OSC_CAL_CNT		FIELD32(0x0fff0000)
+#define OSC_CAL_ACK		FIELD32(0x10000000)
+#define OSC_CLK_32K_VLD		FIELD32(0x20000000)
+#define OSC_CAL_REQ		FIELD32(0x40000000)
+#define OSC_ROSC_EN		FIELD32(0x80000000)
+
+/*
+ * COEX_CFG_0
+ */
+#define COEX_CFG0			0x0040
+#define COEX_CFG_ANT		FIELD32(0xff000000)
+/*
+ * COEX_CFG_1
+ */
+#define COEX_CFG1			0x0044
+
+/*
+ * COEX_CFG_2
+ */
+#define COEX_CFG2			0x0048
+#define BT_COEX_CFG1		FIELD32(0xff000000)
+#define BT_COEX_CFG0		FIELD32(0x00ff0000)
+#define WL_COEX_CFG1		FIELD32(0x0000ff00)
+#define WL_COEX_CFG0		FIELD32(0x000000ff)
+/*
+ * PLL_CTRL_CFG
+ * PLL configuration register
+ */
+#define PLL_CTRL		0x0050
+#define PLL_RESERVED_INPUT1	FIELD32(0x000000ff)
+#define PLL_RESERVED_INPUT2	FIELD32(0x0000ff00)
+#define PLL_CONTROL		FIELD32(0x00070000)
+#define PLL_LPF_R1		FIELD32(0x00080000)
+#define PLL_LPF_C1_CTRL	FIELD32(0x00300000)
+#define PLL_LPF_C2_CTRL	FIELD32(0x00c00000)
+#define PLL_CP_CURRENT_CTRL	FIELD32(0x03000000)
+#define PLL_PFD_DELAY_CTRL	FIELD32(0x0c000000)
+#define PLL_LOCK_CTRL		FIELD32(0x70000000)
+#define PLL_VBGBK_EN		FIELD32(0x80000000)
+
+
+/*
+ * WLAN_CTRL_CFG
+ * RT3290 wlan configuration
+ */
+#define WLAN_FUN_CTRL			0x0080
+#define WLAN_EN				FIELD32(0x00000001)
+#define WLAN_CLK_EN			FIELD32(0x00000002)
+#define WLAN_RSV1			FIELD32(0x00000004)
+#define WLAN_RESET			FIELD32(0x00000008)
+#define PCIE_APP0_CLK_REQ		FIELD32(0x00000010)
+#define FRC_WL_ANT_SET			FIELD32(0x00000020)
+#define INV_TR_SW0			FIELD32(0x00000040)
+#define WLAN_GPIO_IN_BIT0		FIELD32(0x00000100)
+#define WLAN_GPIO_IN_BIT1		FIELD32(0x00000200)
+#define WLAN_GPIO_IN_BIT2		FIELD32(0x00000400)
+#define WLAN_GPIO_IN_BIT3		FIELD32(0x00000800)
+#define WLAN_GPIO_IN_BIT4		FIELD32(0x00001000)
+#define WLAN_GPIO_IN_BIT5		FIELD32(0x00002000)
+#define WLAN_GPIO_IN_BIT6		FIELD32(0x00004000)
+#define WLAN_GPIO_IN_BIT7		FIELD32(0x00008000)
+#define WLAN_GPIO_IN_BIT_ALL		FIELD32(0x0000ff00)
+#define WLAN_GPIO_OUT_BIT0		FIELD32(0x00010000)
+#define WLAN_GPIO_OUT_BIT1		FIELD32(0x00020000)
+#define WLAN_GPIO_OUT_BIT2		FIELD32(0x00040000)
+#define WLAN_GPIO_OUT_BIT3		FIELD32(0x00050000)
+#define WLAN_GPIO_OUT_BIT4		FIELD32(0x00100000)
+#define WLAN_GPIO_OUT_BIT5		FIELD32(0x00200000)
+#define WLAN_GPIO_OUT_BIT6		FIELD32(0x00400000)
+#define WLAN_GPIO_OUT_BIT7		FIELD32(0x00800000)
+#define WLAN_GPIO_OUT_BIT_ALL		FIELD32(0x00ff0000)
+#define WLAN_GPIO_OUT_OE_BIT0		FIELD32(0x01000000)
+#define WLAN_GPIO_OUT_OE_BIT1		FIELD32(0x02000000)
+#define WLAN_GPIO_OUT_OE_BIT2		FIELD32(0x04000000)
+#define WLAN_GPIO_OUT_OE_BIT3		FIELD32(0x08000000)
+#define WLAN_GPIO_OUT_OE_BIT4		FIELD32(0x10000000)
+#define WLAN_GPIO_OUT_OE_BIT5		FIELD32(0x20000000)
+#define WLAN_GPIO_OUT_OE_BIT6		FIELD32(0x40000000)
+#define WLAN_GPIO_OUT_OE_BIT7		FIELD32(0x80000000)
+#define WLAN_GPIO_OUT_OE_BIT_ALL	FIELD32(0xff000000)
+
+/*
  * AUX_CTRL: Aux/PCI-E related configuration
  */
 #define AUX_CTRL			0x10c
@@ -1760,9 +1914,11 @@ struct mac_iveiv_entry {
 /*
  * BBP 3: RX Antenna
  */
-#define BBP3_RX_ADC				FIELD8(0x03)
+#define BBP3_RX_ADC			FIELD8(0x03)
 #define BBP3_RX_ANTENNA			FIELD8(0x18)
 #define BBP3_HT40_MINUS			FIELD8(0x20)
+#define BBP3_ADC_MODE_SWITCH		FIELD8(0x40)
+#define BBP3_ADC_INIT_MODE		FIELD8(0x80)
 
 /*
  * BBP 4: Bandwidth
@@ -1772,6 +1928,14 @@ struct mac_iveiv_entry {
 #define BBP4_MAC_IF_CTRL		FIELD8(0x40)
 
 /*
+ * BBP 47: Bandwidth
+ */
+#define BBP47_TSSI_REPORT_SEL		FIELD8(0x03)
+#define BBP47_TSSI_UPDATE_REQ		FIELD8(0x04)
+#define BBP47_TSSI_TSSI_MODE		FIELD8(0x18)
+#define BBP47_TSSI_ADC6			FIELD8(0x80)
+
+/*
  * BBP 109
  */
 #define BBP109_TX0_POWER		FIELD8(0x0f)
@@ -1914,6 +2078,16 @@ struct mac_iveiv_entry {
 #define RFCSR27_R4			FIELD8(0x40)
 
 /*
+ * RFCSR 29:
+ */
+#define RFCSR29_ADC6_TEST		FIELD8(0x01)
+#define RFCSR29_ADC6_INT_TEST		FIELD8(0x02)
+#define RFCSR29_RSSI_RESET		FIELD8(0x04)
+#define RFCSR29_RSSI_ON			FIELD8(0x08)
+#define RFCSR29_RSSI_RIP_CTRL		FIELD8(0x30)
+#define RFCSR29_RSSI_GAIN		FIELD8(0xc0)
+
+/*
  * RFCSR 30:
  */
 #define RFCSR30_TX_H20M			FIELD8(0x02)
@@ -1944,6 +2118,11 @@ struct mac_iveiv_entry {
 #define RFCSR49_TX			FIELD8(0x3f)
 
 /*
+ * RFCSR 50:
+ */
+#define RFCSR50_TX			FIELD8(0x3f)
+
+/*
  * RF registers
  */
 
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index dfc90d3..068276e 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -354,16 +354,15 @@ int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
 	 * 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.
+	 * which is a multiple of 4kb. The firmware for rt3290 chip also
+	 * have a length which is a multiple of 4kb.
 	 */
-	if (rt2x00_is_usb(rt2x00dev)) {
+	if (rt2x00_is_usb(rt2x00dev) || rt2x00_rt(rt2x00dev, RT3290))
 		fw_len = 4096;
-		multiple = true;
-	} else {
+	else
 		fw_len = 8192;
-		multiple = true;
-	}
 
+	multiple = true;
 	/*
 	 * Validate the firmware length
 	 */
@@ -415,7 +414,8 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
 		return -EBUSY;
 
 	if (rt2x00_is_pci(rt2x00dev)) {
-		if (rt2x00_rt(rt2x00dev, RT3572) ||
+		if (rt2x00_rt(rt2x00dev, RT3290) ||
+		    rt2x00_rt(rt2x00dev, RT3572) ||
 		    rt2x00_rt(rt2x00dev, RT5390) ||
 		    rt2x00_rt(rt2x00dev, RT5392)) {
 			rt2800_register_read(rt2x00dev, AUX_CTRL, &reg);
@@ -851,8 +851,13 @@ int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
 
-	rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
-	return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
+	if (rt2x00_rt(rt2x00dev, RT3290)) {
+		rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+		return rt2x00_get_field32(reg, WLAN_GPIO_IN_BIT0);
+	} else {
+		rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
+		return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
+	}
 }
 EXPORT_SYMBOL_GPL(rt2800_rfkill_poll);
 
@@ -1935,9 +1940,54 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev,
 	rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
 }
 
+#define RT3290_POWER_BOUND     0x27
+#define RT3290_FREQ_OFFSET_BOUND       0x5f
 #define RT5390_POWER_BOUND     0x27
 #define RT5390_FREQ_OFFSET_BOUND       0x5f
 
+static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev,
+					 struct ieee80211_conf *conf,
+					 struct rf_channel *rf,
+					 struct channel_info *info)
+{
+	u8 rfcsr;
+
+	rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
+	rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3);
+	rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr);
+	rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf2);
+	rt2800_rfcsr_write(rt2x00dev, 11, rfcsr);
+
+	rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr);
+	if (info->default_power1 > RT3290_POWER_BOUND)
+		rt2x00_set_field8(&rfcsr, RFCSR49_TX, RT3290_POWER_BOUND);
+	else
+		rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1);
+	rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
+
+	rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
+	if (rt2x00dev->freq_offset > RT3290_FREQ_OFFSET_BOUND)
+		rt2x00_set_field8(&rfcsr, RFCSR17_CODE,
+				  RT3290_FREQ_OFFSET_BOUND);
+	else
+		rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset);
+	rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
+
+	if (rf->channel <= 14) {
+		if (rf->channel == 6)
+			rt2800_bbp_write(rt2x00dev, 68, 0x0c);
+		else
+			rt2800_bbp_write(rt2x00dev, 68, 0x0b);
+
+		if (rf->channel >= 1 && rf->channel <= 6)
+			rt2800_bbp_write(rt2x00dev, 59, 0x0f);
+		else if (rf->channel >= 7 && rf->channel <= 11)
+			rt2800_bbp_write(rt2x00dev, 59, 0x0e);
+		else if (rf->channel >= 12 && rf->channel <= 14)
+			rt2800_bbp_write(rt2x00dev, 59, 0x0d);
+	}
+}
+
 static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
 					 struct ieee80211_conf *conf,
 					 struct rf_channel *rf,
@@ -1958,7 +2008,22 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
 		rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1);
 	rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
 
+	if (rt2x00_rt(rt2x00dev, RT5392)) {
+		rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr);
+		if (info->default_power1 > RT5390_POWER_BOUND)
+			rt2x00_set_field8(&rfcsr, RFCSR50_TX,
+					  RT5390_POWER_BOUND);
+		else
+			rt2x00_set_field8(&rfcsr, RFCSR50_TX,
+					  info->default_power2);
+		rt2800_rfcsr_write(rt2x00dev, 50, rfcsr);
+	}
+
 	rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
+	if (rt2x00_rt(rt2x00dev, RT5392)) {
+		rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
+		rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
+	}
 	rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
 	rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1);
 	rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
@@ -2021,15 +2086,6 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
 			}
 		}
 	}
-
-	rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
-	rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, 0);
-	rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, 0);
-	rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
-
-	rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
-	rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
-	rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
 }
 
 static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
@@ -2039,7 +2095,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
 {
 	u32 reg;
 	unsigned int tx_pin;
-	u8 bbp;
+	u8 bbp, rfcsr;
 
 	if (rf->channel <= 14) {
 		info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1);
@@ -2060,15 +2116,36 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
 	case RF3052:
 		rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info);
 		break;
+	case RF3290:
+		rt2800_config_channel_rf3290(rt2x00dev, conf, rf, info);
+		break;
+	case RF5360:
 	case RF5370:
 	case RF5372:
 	case RF5390:
+	case RF5392:
 		rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
 		break;
 	default:
 		rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
 	}
 
+	if (rt2x00_rf(rt2x00dev, RF3290) ||
+	    rt2x00_rf(rt2x00dev, RF5360) ||
+	    rt2x00_rf(rt2x00dev, RF5370) ||
+	    rt2x00_rf(rt2x00dev, RF5372) ||
+	    rt2x00_rf(rt2x00dev, RF5390) ||
+	    rt2x00_rf(rt2x00dev, RF5392)) {
+		rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
+		rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, 0);
+		rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, 0);
+		rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
+
+		rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
+		rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
+		rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
+	}
+
 	/*
 	 * Change BBP settings
 	 */
@@ -2549,9 +2626,12 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
 		rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
 		rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
 		break;
+	case RF3290:
+	case RF5360:
 	case RF5370:
 	case RF5372:
 	case RF5390:
+	case RF5392:
 		rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
 		rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
 		rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
@@ -2682,6 +2762,7 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
 		if (rt2x00_rt(rt2x00dev, RT3070) ||
 		    rt2x00_rt(rt2x00dev, RT3071) ||
 		    rt2x00_rt(rt2x00dev, RT3090) ||
+		    rt2x00_rt(rt2x00dev, RT3290) ||
 		    rt2x00_rt(rt2x00dev, RT3390) ||
 		    rt2x00_rt(rt2x00dev, RT5390) ||
 		    rt2x00_rt(rt2x00dev, RT5392))
@@ -2778,10 +2859,54 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2);
 	rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
 
+	if (rt2x00_rt(rt2x00dev, RT3290)) {
+		rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+		if (rt2x00_get_field32(reg, WLAN_EN) == 1) {
+			rt2x00_set_field32(&reg, PCIE_APP0_CLK_REQ, 1);
+			rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+		}
+
+		rt2800_register_read(rt2x00dev, CMB_CTRL, &reg);
+		if (!(rt2x00_get_field32(reg, LDO0_EN) == 1)) {
+			rt2x00_set_field32(&reg, LDO0_EN, 1);
+			rt2x00_set_field32(&reg, LDO_BGSEL, 3);
+			rt2800_register_write(rt2x00dev, CMB_CTRL, reg);
+		}
+
+		rt2800_register_read(rt2x00dev, OSC_CTRL, &reg);
+		rt2x00_set_field32(&reg, OSC_ROSC_EN, 1);
+		rt2x00_set_field32(&reg, OSC_CAL_REQ, 1);
+		rt2x00_set_field32(&reg, OSC_REF_CYCLE, 0x27);
+		rt2800_register_write(rt2x00dev, OSC_CTRL, reg);
+
+		rt2800_register_read(rt2x00dev, COEX_CFG0, &reg);
+		rt2x00_set_field32(&reg, COEX_CFG_ANT, 0x5e);
+		rt2800_register_write(rt2x00dev, COEX_CFG0, reg);
+
+		rt2800_register_read(rt2x00dev, COEX_CFG2, &reg);
+		rt2x00_set_field32(&reg, BT_COEX_CFG1, 0x00);
+		rt2x00_set_field32(&reg, BT_COEX_CFG0, 0x17);
+		rt2x00_set_field32(&reg, WL_COEX_CFG1, 0x93);
+		rt2x00_set_field32(&reg, WL_COEX_CFG0, 0x7f);
+		rt2800_register_write(rt2x00dev, COEX_CFG2, reg);
+
+		rt2800_register_read(rt2x00dev, PLL_CTRL, &reg);
+		rt2x00_set_field32(&reg, PLL_CONTROL, 1);
+		rt2800_register_write(rt2x00dev, PLL_CTRL, reg);
+	}
+
 	if (rt2x00_rt(rt2x00dev, RT3071) ||
 	    rt2x00_rt(rt2x00dev, RT3090) ||
+	    rt2x00_rt(rt2x00dev, RT3290) ||
 	    rt2x00_rt(rt2x00dev, RT3390)) {
-		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
+
+		if (rt2x00_rt(rt2x00dev, RT3290))
+			rt2800_register_write(rt2x00dev, TX_SW_CFG0,
+					      0x00000404);
+		else
+			rt2800_register_write(rt2x00dev, TX_SW_CFG0,
+					      0x00000400);
+
 		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
 		if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
 		    rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
@@ -3190,14 +3315,16 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 		     rt2800_wait_bbp_ready(rt2x00dev)))
 		return -EACCES;
 
-	if (rt2x00_rt(rt2x00dev, RT5390) ||
-		rt2x00_rt(rt2x00dev, RT5392)) {
+	if (rt2x00_rt(rt2x00dev, RT3290) ||
+	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_bbp_read(rt2x00dev, 4, &value);
 		rt2x00_set_field8(&value, BBP4_MAC_IF_CTRL, 1);
 		rt2800_bbp_write(rt2x00dev, 4, value);
 	}
 
 	if (rt2800_is_305x_soc(rt2x00dev) ||
+	    rt2x00_rt(rt2x00dev, RT3290) ||
 	    rt2x00_rt(rt2x00dev, RT3572) ||
 	    rt2x00_rt(rt2x00dev, RT5390) ||
 	    rt2x00_rt(rt2x00dev, RT5392))
@@ -3206,20 +3333,26 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 	rt2800_bbp_write(rt2x00dev, 65, 0x2c);
 	rt2800_bbp_write(rt2x00dev, 66, 0x38);
 
-	if (rt2x00_rt(rt2x00dev, RT5390) ||
-		rt2x00_rt(rt2x00dev, RT5392))
+	if (rt2x00_rt(rt2x00dev, RT3290) ||
+	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 68, 0x0b);
 
 	if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) {
 		rt2800_bbp_write(rt2x00dev, 69, 0x16);
 		rt2800_bbp_write(rt2x00dev, 73, 0x12);
-	} else if (rt2x00_rt(rt2x00dev, RT5390) ||
-			   rt2x00_rt(rt2x00dev, RT5392)) {
+	} else if (rt2x00_rt(rt2x00dev, RT3290) ||
+		   rt2x00_rt(rt2x00dev, RT5390) ||
+		   rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_bbp_write(rt2x00dev, 69, 0x12);
 		rt2800_bbp_write(rt2x00dev, 73, 0x13);
 		rt2800_bbp_write(rt2x00dev, 75, 0x46);
 		rt2800_bbp_write(rt2x00dev, 76, 0x28);
-		rt2800_bbp_write(rt2x00dev, 77, 0x59);
+
+		if (rt2x00_rt(rt2x00dev, RT3290))
+			rt2800_bbp_write(rt2x00dev, 77, 0x58);
+		else
+			rt2800_bbp_write(rt2x00dev, 77, 0x59);
 	} else {
 		rt2800_bbp_write(rt2x00dev, 69, 0x12);
 		rt2800_bbp_write(rt2x00dev, 73, 0x10);
@@ -3244,23 +3377,33 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 		rt2800_bbp_write(rt2x00dev, 81, 0x37);
 	}
 
+	if (rt2x00_rt(rt2x00dev, RT3290)) {
+		rt2800_bbp_write(rt2x00dev, 74, 0x0b);
+		rt2800_bbp_write(rt2x00dev, 79, 0x18);
+		rt2800_bbp_write(rt2x00dev, 80, 0x09);
+		rt2800_bbp_write(rt2x00dev, 81, 0x33);
+	}
+
 	rt2800_bbp_write(rt2x00dev, 82, 0x62);
-	if (rt2x00_rt(rt2x00dev, RT5390) ||
-		rt2x00_rt(rt2x00dev, RT5392))
+	if (rt2x00_rt(rt2x00dev, RT3290) ||
+	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 83, 0x7a);
 	else
 		rt2800_bbp_write(rt2x00dev, 83, 0x6a);
 
 	if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D))
 		rt2800_bbp_write(rt2x00dev, 84, 0x19);
-	else if (rt2x00_rt(rt2x00dev, RT5390) ||
-			 rt2x00_rt(rt2x00dev, RT5392))
+	else if (rt2x00_rt(rt2x00dev, RT3290) ||
+		     rt2x00_rt(rt2x00dev, RT5390) ||
+		     rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 84, 0x9a);
 	else
 		rt2800_bbp_write(rt2x00dev, 84, 0x99);
 
-	if (rt2x00_rt(rt2x00dev, RT5390) ||
-		rt2x00_rt(rt2x00dev, RT5392))
+	if (rt2x00_rt(rt2x00dev, RT3290) ||
+	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 86, 0x38);
 	else
 		rt2800_bbp_write(rt2x00dev, 86, 0x00);
@@ -3270,8 +3413,9 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 
 	rt2800_bbp_write(rt2x00dev, 91, 0x04);
 
-	if (rt2x00_rt(rt2x00dev, RT5390) ||
-		rt2x00_rt(rt2x00dev, RT5392))
+	if (rt2x00_rt(rt2x00dev, RT3290) ||
+	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 92, 0x02);
 	else
 		rt2800_bbp_write(rt2x00dev, 92, 0x00);
@@ -3285,6 +3429,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 	    rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) ||
 	    rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) ||
 	    rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) ||
+	    rt2x00_rt(rt2x00dev, RT3290) ||
 	    rt2x00_rt(rt2x00dev, RT3572) ||
 	    rt2x00_rt(rt2x00dev, RT5390) ||
 	    rt2x00_rt(rt2x00dev, RT5392) ||
@@ -3293,27 +3438,32 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 	else
 		rt2800_bbp_write(rt2x00dev, 103, 0x00);
 
-	if (rt2x00_rt(rt2x00dev, RT5390) ||
-		rt2x00_rt(rt2x00dev, RT5392))
+	if (rt2x00_rt(rt2x00dev, RT3290) ||
+	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 104, 0x92);
 
 	if (rt2800_is_305x_soc(rt2x00dev))
 		rt2800_bbp_write(rt2x00dev, 105, 0x01);
+	else if (rt2x00_rt(rt2x00dev, RT3290))
+		rt2800_bbp_write(rt2x00dev, 105, 0x1c);
 	else if (rt2x00_rt(rt2x00dev, RT5390) ||
 			 rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 105, 0x3c);
 	else
 		rt2800_bbp_write(rt2x00dev, 105, 0x05);
 
-	if (rt2x00_rt(rt2x00dev, RT5390))
+	if (rt2x00_rt(rt2x00dev, RT3290) ||
+	    rt2x00_rt(rt2x00dev, RT5390))
 		rt2800_bbp_write(rt2x00dev, 106, 0x03);
 	else if (rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 106, 0x12);
 	else
 		rt2800_bbp_write(rt2x00dev, 106, 0x35);
 
-	if (rt2x00_rt(rt2x00dev, RT5390) ||
-		rt2x00_rt(rt2x00dev, RT5392))
+	if (rt2x00_rt(rt2x00dev, RT3290) ||
+	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392))
 		rt2800_bbp_write(rt2x00dev, 128, 0x12);
 
 	if (rt2x00_rt(rt2x00dev, RT5392)) {
@@ -3338,6 +3488,29 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 		rt2800_bbp_write(rt2x00dev, 138, value);
 	}
 
+	if (rt2x00_rt(rt2x00dev, RT3290)) {
+		rt2800_bbp_write(rt2x00dev, 67, 0x24);
+		rt2800_bbp_write(rt2x00dev, 143, 0x04);
+		rt2800_bbp_write(rt2x00dev, 142, 0x99);
+		rt2800_bbp_write(rt2x00dev, 150, 0x30);
+		rt2800_bbp_write(rt2x00dev, 151, 0x2e);
+		rt2800_bbp_write(rt2x00dev, 152, 0x20);
+		rt2800_bbp_write(rt2x00dev, 153, 0x34);
+		rt2800_bbp_write(rt2x00dev, 154, 0x40);
+		rt2800_bbp_write(rt2x00dev, 155, 0x3b);
+		rt2800_bbp_write(rt2x00dev, 253, 0x04);
+
+		rt2800_bbp_read(rt2x00dev, 47, &value);
+		rt2x00_set_field8(&value, BBP47_TSSI_ADC6, 1);
+		rt2800_bbp_write(rt2x00dev, 47, value);
+
+		/* Use 5-bit ADC for Acquisition and 8-bit ADC for data */
+		rt2800_bbp_read(rt2x00dev, 3, &value);
+		rt2x00_set_field8(&value, BBP3_ADC_MODE_SWITCH, 1);
+		rt2x00_set_field8(&value, BBP3_ADC_INIT_MODE, 1);
+		rt2800_bbp_write(rt2x00dev, 3, value);
+	}
+
 	if (rt2x00_rt(rt2x00dev, RT5390) ||
 		rt2x00_rt(rt2x00dev, RT5392)) {
 		int ant, div_mode;
@@ -3470,6 +3643,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 	if (!rt2x00_rt(rt2x00dev, RT3070) &&
 	    !rt2x00_rt(rt2x00dev, RT3071) &&
 	    !rt2x00_rt(rt2x00dev, RT3090) &&
+	    !rt2x00_rt(rt2x00dev, RT3290) &&
 	    !rt2x00_rt(rt2x00dev, RT3390) &&
 	    !rt2x00_rt(rt2x00dev, RT3572) &&
 	    !rt2x00_rt(rt2x00dev, RT5390) &&
@@ -3480,8 +3654,9 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Init RF calibration.
 	 */
-	if (rt2x00_rt(rt2x00dev, RT5390) ||
-		rt2x00_rt(rt2x00dev, RT5392)) {
+	if (rt2x00_rt(rt2x00dev, RT3290) ||
+	    rt2x00_rt(rt2x00dev, RT5390) ||
+	    rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr);
 		rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1);
 		rt2800_rfcsr_write(rt2x00dev, 2, rfcsr);
@@ -3519,6 +3694,53 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 		rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
 		rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
 		rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
+	} else if (rt2x00_rt(rt2x00dev, RT3290)) {
+		rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
+		rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+		rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
+		rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
+		rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
+		rt2800_rfcsr_write(rt2x00dev, 8, 0xf3);
+		rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
+		rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+		rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+		rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
+		rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+		rt2800_rfcsr_write(rt2x00dev, 18, 0x02);
+		rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+		rt2800_rfcsr_write(rt2x00dev, 25, 0x83);
+		rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
+		rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+		rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+		rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+		rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+		rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+		rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+		rt2800_rfcsr_write(rt2x00dev, 34, 0x05);
+		rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+		rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+		rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
+		rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+		rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
+		rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+		rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
+		rt2800_rfcsr_write(rt2x00dev, 43, 0x7b);
+		rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+		rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+		rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+		rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
+		rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+		rt2800_rfcsr_write(rt2x00dev, 49, 0x98);
+		rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
+		rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
+		rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
+		rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
+		rt2800_rfcsr_write(rt2x00dev, 56, 0x02);
+		rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
+		rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
+		rt2800_rfcsr_write(rt2x00dev, 59, 0x09);
+		rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+		rt2800_rfcsr_write(rt2x00dev, 61, 0xc1);
 	} else if (rt2x00_rt(rt2x00dev, RT3390)) {
 		rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
 		rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
@@ -3927,6 +4149,12 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 		rt2800_rfcsr_write(rt2x00dev, 27, rfcsr);
 	}
 
+	if (rt2x00_rt(rt2x00dev, RT3290)) {
+		rt2800_rfcsr_read(rt2x00dev, 29, &rfcsr);
+		rt2x00_set_field8(&rfcsr, RFCSR29_RSSI_GAIN, 3);
+		rt2800_rfcsr_write(rt2x00dev, 29, rfcsr);
+	}
+
 	if (rt2x00_rt(rt2x00dev, RT5390) ||
 		rt2x00_rt(rt2x00dev, RT5392)) {
 		rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr);
@@ -4033,9 +4261,14 @@ EXPORT_SYMBOL_GPL(rt2800_disable_radio);
 int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
+	u16 efuse_ctrl_reg;
 
-	rt2800_register_read(rt2x00dev, EFUSE_CTRL, &reg);
+	if (rt2x00_rt(rt2x00dev, RT3290))
+		efuse_ctrl_reg = EFUSE_CTRL_3290;
+	else
+		efuse_ctrl_reg = EFUSE_CTRL;
 
+	rt2800_register_read(rt2x00dev, efuse_ctrl_reg, &reg);
 	return rt2x00_get_field32(reg, EFUSE_CTRL_PRESENT);
 }
 EXPORT_SYMBOL_GPL(rt2800_efuse_detect);
@@ -4043,27 +4276,44 @@ EXPORT_SYMBOL_GPL(rt2800_efuse_detect);
 static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
 {
 	u32 reg;
-
+	u16 efuse_ctrl_reg;
+	u16 efuse_data0_reg;
+	u16 efuse_data1_reg;
+	u16 efuse_data2_reg;
+	u16 efuse_data3_reg;
+
+	if (rt2x00_rt(rt2x00dev, RT3290)) {
+		efuse_ctrl_reg = EFUSE_CTRL_3290;
+		efuse_data0_reg = EFUSE_DATA0_3290;
+		efuse_data1_reg = EFUSE_DATA1_3290;
+		efuse_data2_reg = EFUSE_DATA2_3290;
+		efuse_data3_reg = EFUSE_DATA3_3290;
+	} else {
+		efuse_ctrl_reg = EFUSE_CTRL;
+		efuse_data0_reg = EFUSE_DATA0;
+		efuse_data1_reg = EFUSE_DATA1;
+		efuse_data2_reg = EFUSE_DATA2;
+		efuse_data3_reg = EFUSE_DATA3;
+	}
 	mutex_lock(&rt2x00dev->csr_mutex);
 
-	rt2800_register_read_lock(rt2x00dev, EFUSE_CTRL, &reg);
+	rt2800_register_read_lock(rt2x00dev, efuse_ctrl_reg, &reg);
 	rt2x00_set_field32(&reg, EFUSE_CTRL_ADDRESS_IN, i);
 	rt2x00_set_field32(&reg, EFUSE_CTRL_MODE, 0);
 	rt2x00_set_field32(&reg, EFUSE_CTRL_KICK, 1);
-	rt2800_register_write_lock(rt2x00dev, EFUSE_CTRL, reg);
+	rt2800_register_write_lock(rt2x00dev, efuse_ctrl_reg, reg);
 
 	/* Wait until the EEPROM has been loaded */
-	rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, &reg);
-
+	rt2800_regbusy_read(rt2x00dev, efuse_ctrl_reg, EFUSE_CTRL_KICK, &reg);
 	/* Apparently the data is read from end to start */
-	rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, &reg);
+	rt2800_register_read_lock(rt2x00dev, efuse_data3_reg, &reg);
 	/* The returned value is in CPU order, but eeprom is le */
 	*(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg);
-	rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, &reg);
+	rt2800_register_read_lock(rt2x00dev, efuse_data2_reg, &reg);
 	*(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg);
-	rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, &reg);
+	rt2800_register_read_lock(rt2x00dev, efuse_data1_reg, &reg);
 	*(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg);
-	rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0, &reg);
+	rt2800_register_read_lock(rt2x00dev, efuse_data0_reg, &reg);
 	*(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg);
 
 	mutex_unlock(&rt2x00dev->csr_mutex);
@@ -4225,9 +4475,14 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	 * RT28xx/RT30xx: defined in "EEPROM_NIC_CONF0_RF_TYPE" field
 	 * RT53xx: defined in "EEPROM_CHIP_ID" field
 	 */
-	rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-	if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390 ||
-		rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5392)
+	if (rt2x00_rt(rt2x00dev, RT3290))
+		rt2800_register_read(rt2x00dev, MAC_CSR0_3290, &reg);
+	else
+		rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+
+	if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT3290 ||
+	    rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390 ||
+	    rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5392)
 		rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &value);
 	else
 		value = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
@@ -4242,6 +4497,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	case RT3070:
 	case RT3071:
 	case RT3090:
+	case RT3290:
 	case RT3390:
 	case RT3572:
 	case RT5390:
@@ -4262,10 +4518,13 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	case RF3021:
 	case RF3022:
 	case RF3052:
+	case RF3290:
 	case RF3320:
+	case RF5360:
 	case RF5370:
 	case RF5372:
 	case RF5390:
+	case RF5392:
 		break;
 	default:
 		ERROR(rt2x00dev, "Invalid RF chipset 0x%04x detected.\n",
@@ -4576,10 +4835,13 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 		   rt2x00_rf(rt2x00dev, RF2020) ||
 		   rt2x00_rf(rt2x00dev, RF3021) ||
 		   rt2x00_rf(rt2x00dev, RF3022) ||
+		   rt2x00_rf(rt2x00dev, RF3290) ||
 		   rt2x00_rf(rt2x00dev, RF3320) ||
+		   rt2x00_rf(rt2x00dev, RF5360) ||
 		   rt2x00_rf(rt2x00dev, RF5370) ||
 		   rt2x00_rf(rt2x00dev, RF5372) ||
-		   rt2x00_rf(rt2x00dev, RF5390)) {
+		   rt2x00_rf(rt2x00dev, RF5390) ||
+		   rt2x00_rf(rt2x00dev, RF5392)) {
 		spec->num_channels = 14;
 		spec->channels = rf_vals_3x;
 	} else if (rt2x00_rf(rt2x00dev, RF3052)) {
@@ -4662,9 +4924,12 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	case RF3022:
 	case RF3320:
 	case RF3052:
+	case RF3290:
+	case RF5360:
 	case RF5370:
 	case RF5372:
 	case RF5390:
+	case RF5392:
 		__set_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags);
 		break;
 	}
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index cad25bf..dd43612 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -280,7 +280,13 @@ static void rt2800pci_stop_queue(struct data_queue *queue)
  */
 static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
 {
-	return FIRMWARE_RT2860;
+	/*
+	 * Chip rt3290 use specific 4KB firmware named rt3290.bin.
+	 */
+	if (rt2x00_rt(rt2x00dev, RT3290))
+		return FIRMWARE_RT3290;
+	else
+		return FIRMWARE_RT2860;
 }
 
 static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
@@ -974,6 +980,66 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 	return rt2800_validate_eeprom(rt2x00dev);
 }
 
+static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	int i, count;
+
+	rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+	if ((rt2x00_get_field32(reg, WLAN_EN) == 1))
+		return 0;
+
+	rt2x00_set_field32(&reg, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff);
+	rt2x00_set_field32(&reg, FRC_WL_ANT_SET, 1);
+	rt2x00_set_field32(&reg, WLAN_CLK_EN, 0);
+	rt2x00_set_field32(&reg, WLAN_EN, 1);
+	rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+
+	udelay(REGISTER_BUSY_DELAY);
+
+	count = 0;
+	do {
+		/*
+		 * Check PLL_LD & XTAL_RDY.
+		 */
+		for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+			rt2800_register_read(rt2x00dev, CMB_CTRL, &reg);
+			if ((rt2x00_get_field32(reg, PLL_LD) == 1) &&
+				(rt2x00_get_field32(reg, XTAL_RDY) == 1))
+					break;
+			udelay(REGISTER_BUSY_DELAY);
+		}
+
+		if (i >= REGISTER_BUSY_COUNT) {
+
+			if (count >= 10)
+				return -EIO;
+
+			rt2800_register_write(rt2x00dev, 0x58, 0x018);
+			udelay(REGISTER_BUSY_DELAY);
+			rt2800_register_write(rt2x00dev, 0x58, 0x418);
+			udelay(REGISTER_BUSY_DELAY);
+			rt2800_register_write(rt2x00dev, 0x58, 0x618);
+			udelay(REGISTER_BUSY_DELAY);
+			count++;
+		} else {
+			count = 0;
+		}
+
+		rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+		rt2x00_set_field32(&reg, PCIE_APP0_CLK_REQ, 0);
+		rt2x00_set_field32(&reg, WLAN_CLK_EN, 1);
+		rt2x00_set_field32(&reg, WLAN_RESET, 1);
+		rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+		udelay(10);
+		rt2x00_set_field32(&reg, WLAN_RESET, 0);
+		rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+		udelay(10);
+		rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, 0x7fffffff);
+	} while (count != 0);
+
+	return 0;
+}
 static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 {
 	int retval;
@@ -997,6 +1063,17 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 		return retval;
 
 	/*
+	 * In probe phase call rt2800_enable_wlan_rt3290 to enable wlan
+	 * clk for rt3290. That avoid the MCU fail in start phase.
+	 */
+	if (rt2x00_rt(rt2x00dev, RT3290)) {
+		retval = rt2800_enable_wlan_rt3290(rt2x00dev);
+
+		if (retval)
+			return retval;
+	}
+
+	/*
 	 * This device has multiple filters for control frames
 	 * and has a separate filter for PS Poll frames.
 	 */
@@ -1175,6 +1252,9 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
 	{ PCI_DEVICE(0x1432, 0x7768) },
 	{ PCI_DEVICE(0x1462, 0x891a) },
 	{ PCI_DEVICE(0x1a3b, 0x1059) },
+#ifdef CONFIG_RT2800PCI_RT3290
+	{ PCI_DEVICE(0x1814, 0x3290) },
+#endif
 #ifdef CONFIG_RT2800PCI_RT33XX
 	{ PCI_DEVICE(0x1814, 0x3390) },
 #endif
@@ -1188,6 +1268,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
 	{ PCI_DEVICE(0x1814, 0x3593) },
 #endif
 #ifdef CONFIG_RT2800PCI_RT53XX
+	{ PCI_DEVICE(0x1814, 0x5360) },
 	{ PCI_DEVICE(0x1814, 0x5362) },
 	{ PCI_DEVICE(0x1814, 0x5390) },
 	{ PCI_DEVICE(0x1814, 0x5392) },
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h
index 70e050d..ab22a08 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.h
+++ b/drivers/net/wireless/rt2x00/rt2800pci.h
@@ -47,6 +47,7 @@
  * 8051 firmware image.
  */
 #define FIRMWARE_RT2860			"rt2860.bin"
+#define FIRMWARE_RT3290			"rt3290.bin"
 #define FIRMWARE_IMAGE_BASE		0x2000
 
 /*
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index bf78317..6cf3365 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -971,6 +971,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x0411, 0x015d) },
 	{ USB_DEVICE(0x0411, 0x016f) },
 	{ USB_DEVICE(0x0411, 0x01a2) },
+	{ USB_DEVICE(0x0411, 0x01ee) },
 	/* Corega */
 	{ USB_DEVICE(0x07aa, 0x002f) },
 	{ USB_DEVICE(0x07aa, 0x003c) },
@@ -1137,6 +1138,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
 #ifdef CONFIG_RT2800USB_RT33XX
 	/* Belkin */
 	{ USB_DEVICE(0x050d, 0x945b) },
+	/* D-Link */
+	{ USB_DEVICE(0x2001, 0x3c17) },
 	/* Panasonic */
 	{ USB_DEVICE(0x083a, 0xb511) },
 	/* Philips */
@@ -1237,7 +1240,6 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	/* D-Link */
 	{ USB_DEVICE(0x07d1, 0x3c0b) },
 	{ USB_DEVICE(0x07d1, 0x3c17) },
-	{ USB_DEVICE(0x2001, 0x3c17) },
 	/* Encore */
 	{ USB_DEVICE(0x203d, 0x14a1) },
 	/* Gemtek */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 8f75402..8afb546 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -187,6 +187,7 @@ struct rt2x00_chip {
 #define RT3070		0x3070
 #define RT3071		0x3071
 #define RT3090		0x3090	/* 2.4GHz PCIe */
+#define RT3290		0x3290
 #define RT3390		0x3390
 #define RT3572		0x3572
 #define RT3593		0x3593
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index e5404e5..a6b88bd 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -1161,6 +1161,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 		    BIT(NL80211_IFTYPE_MESH_POINT) |
 		    BIT(NL80211_IFTYPE_WDS);
 
+	rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
 	/*
 	 * Initialize work.
 	 */
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index dd24b26..4ff26c2 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -506,9 +506,19 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
 	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
 		return 0;
-	else if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
+
+	if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
+		return -EOPNOTSUPP;
+
+	/*
+	 * To support IBSS RSN, don't program group keys in IBSS, the
+	 * hardware will then not attempt to decrypt the frames.
+	 */
+	if (vif->type == NL80211_IFTYPE_ADHOC &&
+	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
 		return -EOPNOTSUPP;
-	else if (key->keylen > 32)
+
+	if (key->keylen > 32)
 		return -ENOSPC;
 
 	memset(&crypto, 0, sizeof(crypto));
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 0a4653a..a0c8cae 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -256,6 +256,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
 	struct ieee80211_hw *hw;
 	struct rt2x00_dev *rt2x00dev;
 	int retval;
+	u16 chip;
 
 	retval = pci_enable_device(pci_dev);
 	if (retval) {
@@ -305,6 +306,14 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
 	if (retval)
 		goto exit_free_device;
 
+	/*
+	 * Because rt3290 chip use different efuse offset to read efuse data.
+	 * So before read efuse it need to indicate it is the
+	 * rt3290 or not.
+	 */
+	pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip);
+	rt2x00dev->chip.rt = chip;
+
 	retval = rt2x00lib_probe_dev(rt2x00dev);
 	if (retval)
 		goto exit_free_reg;
diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c
index 2bebcb7..3b50539 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c
@@ -47,6 +47,8 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8180_table) = {
 	{ PCI_DEVICE(0x1799, 0x6001) },
 	{ PCI_DEVICE(0x1799, 0x6020) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x3300) },
+	{ PCI_DEVICE(0x1186, 0x3301) },
+	{ PCI_DEVICE(0x1432, 0x7106) },
 	{ }
 };
 
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index f4c852c..58e1f7b 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -907,7 +907,7 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 	struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	__le16 fc = hdr->frame_control;
-	u8 *act = (u8 *) (((u8 *) skb->data + MAC80211_3ADDR_LEN));
+	u8 *act = (u8 *)skb->data + MAC80211_3ADDR_LEN;
 	u8 category;
 
 	if (!ieee80211_is_action(fc))
diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c
index 3d8cc4a..5b4b4d4 100644
--- a/drivers/net/wireless/rtlwifi/cam.c
+++ b/drivers/net/wireless/rtlwifi/cam.c
@@ -128,7 +128,7 @@ u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
 	u32 us_config;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+	RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
 		 "EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n",
 		 ul_entry_idx, ul_key_id, ul_enc_alg,
 		 ul_default_key, mac_addr);
@@ -146,7 +146,7 @@ u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
 	}
 
 	rtl_cam_program_entry(hw, ul_entry_idx, mac_addr,
-			      (u8 *) key_content, us_config);
+			      key_content, us_config);
 
 	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "<===\n");
 
@@ -342,7 +342,8 @@ void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr)
 			/* Remove from HW Security CAM */
 			memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN);
 			rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i);
-			pr_info("&&&&&&&&&del entry %d\n", i);
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 "del CAM entry %d\n", i);
 		}
 	}
 	return;
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index 278e9f9..a18ad2a 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -680,7 +680,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 
 		mac->short_preamble = bss_conf->use_short_preamble;
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACK_PREAMBLE,
-					      (u8 *) (&mac->short_preamble));
+					      &mac->short_preamble);
 	}
 
 	if (changed & BSS_CHANGED_ERP_SLOT) {
@@ -693,7 +693,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 			mac->slot_time = RTL_SLOT_TIME_20;
 
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
-					      (u8 *) (&mac->slot_time));
+					      &mac->slot_time);
 	}
 
 	if (changed & BSS_CHANGED_HT) {
@@ -713,7 +713,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 		rcu_read_unlock();
 
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SHORTGI_DENSITY,
-					      (u8 *) (&mac->max_mss_density));
+					      &mac->max_mss_density);
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_FACTOR,
 					      &mac->current_ampdu_factor);
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_MIN_SPACE,
@@ -801,7 +801,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 				u8 mstatus = RT_MEDIA_CONNECT;
 				rtlpriv->cfg->ops->set_hw_reg(hw,
 						      HW_VAR_H2C_FW_JOINBSSRPT,
-						      (u8 *) (&mstatus));
+						      &mstatus);
 				ppsc->report_linked = true;
 			}
 		} else {
@@ -809,7 +809,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 				u8 mstatus = RT_MEDIA_DISCONNECT;
 				rtlpriv->cfg->ops->set_hw_reg(hw,
 						      HW_VAR_H2C_FW_JOINBSSRPT,
-						      (u8 *)(&mstatus));
+						      &mstatus);
 				ppsc->report_linked = false;
 			}
 		}
@@ -836,7 +836,7 @@ static void rtl_op_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
 
 	mac->tsf = tsf;
-	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&bibss));
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, &bibss);
 }
 
 static void rtl_op_reset_tsf(struct ieee80211_hw *hw,
@@ -845,7 +845,7 @@ static void rtl_op_reset_tsf(struct ieee80211_hw *hw,
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tmp = 0;
 
-	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_DUAL_TSF_RST, (u8 *) (&tmp));
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_DUAL_TSF_RST, &tmp);
 }
 
 static void rtl_op_sta_notify(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c
index 1f14380..8e2f9af 100644
--- a/drivers/net/wireless/rtlwifi/efuse.c
+++ b/drivers/net/wireless/rtlwifi/efuse.c
@@ -352,7 +352,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES,
 				      (u8 *)&efuse_utilized);
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE,
-				      (u8 *)&efuse_usage);
+				      &efuse_usage);
 done:
 	for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++)
 		kfree(efuse_word[i]);
@@ -409,7 +409,7 @@ void efuse_shadow_read(struct ieee80211_hw *hw, u8 type,
 	else if (type == 2)
 		efuse_shadow_read_2byte(hw, offset, (u16 *) value);
 	else if (type == 4)
-		efuse_shadow_read_4byte(hw, offset, (u32 *) value);
+		efuse_shadow_read_4byte(hw, offset, value);
 
 }
 
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 2062ea1..31138fd 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -756,10 +756,10 @@ done:
 		if (index == rtlpci->rxringcount - 1)
 			rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
 						    HW_DESC_RXERO,
-						    (u8 *)&tmp_one);
+						    &tmp_one);
 
 		rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN,
-					    (u8 *)&tmp_one);
+					    &tmp_one);
 
 		index = (index + 1) % rtlpci->rxringcount;
 	}
@@ -934,7 +934,7 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
 	__skb_queue_tail(&ring->queue, pskb);
 
 	rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, HW_DESC_OWN,
-				    (u8 *)&temp_one);
+				    &temp_one);
 
 	return;
 }
@@ -1126,11 +1126,11 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
 						    rxbuffersize);
 			rtlpriv->cfg->ops->set_desc((u8 *) entry, false,
 						    HW_DESC_RXOWN,
-						    (u8 *)&tmp_one);
+						    &tmp_one);
 		}
 
 		rtlpriv->cfg->ops->set_desc((u8 *) entry, false,
-					    HW_DESC_RXERO, (u8 *)&tmp_one);
+					    HW_DESC_RXERO, &tmp_one);
 	}
 	return 0;
 }
@@ -1263,7 +1263,7 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
 				rtlpriv->cfg->ops->set_desc((u8 *) entry,
 							    false,
 							    HW_DESC_RXOWN,
-							    (u8 *)&tmp_one);
+							    &tmp_one);
 			}
 			rtlpci->rx_ring[rx_queue_idx].idx = 0;
 		}
@@ -1273,17 +1273,18 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
 	 *after reset, release previous pending packet,
 	 *and force the  tx idx to the first one
 	 */
-	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) {
 		if (rtlpci->tx_ring[i].desc) {
 			struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i];
 
 			while (skb_queue_len(&ring->queue)) {
-				struct rtl_tx_desc *entry =
-				    &ring->desc[ring->idx];
-				struct sk_buff *skb =
-				    __skb_dequeue(&ring->queue);
+				struct rtl_tx_desc *entry;
+				struct sk_buff *skb;
 
+				spin_lock_irqsave(&rtlpriv->locks.irq_th_lock,
+						  flags);
+				entry = &ring->desc[ring->idx];
+				skb = __skb_dequeue(&ring->queue);
 				pci_unmap_single(rtlpci->pdev,
 						 rtlpriv->cfg->ops->
 							 get_desc((u8 *)
@@ -1291,15 +1292,15 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
 							 true,
 							 HW_DESC_TXBUFF_ADDR),
 						 skb->len, PCI_DMA_TODEVICE);
-				kfree_skb(skb);
 				ring->idx = (ring->idx + 1) % ring->entries;
+				spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+						  flags);
+				kfree_skb(skb);
 			}
 			ring->idx = 0;
 		}
 	}
 
-	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-
 	return 0;
 }
 
@@ -1422,7 +1423,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 	__skb_queue_tail(&ring->queue, skb);
 
 	rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true,
-				    HW_DESC_OWN, (u8 *)&temp_one);
+				    HW_DESC_OWN, &temp_one);
 
 
 	if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index 5ae2664..13ad33e 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -333,10 +333,10 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
 			rpwm_val = 0x0C;	/* RF on */
 			fw_pwrmode = FW_PS_ACTIVE_MODE;
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-					(u8 *) (&rpwm_val));
+					&rpwm_val);
 			rtlpriv->cfg->ops->set_hw_reg(hw,
 					HW_VAR_H2C_FW_PWRMODE,
-					(u8 *) (&fw_pwrmode));
+					&fw_pwrmode);
 			fw_current_inps = false;
 
 			rtlpriv->cfg->ops->set_hw_reg(hw,
@@ -356,11 +356,11 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
 						(u8 *) (&fw_current_inps));
 				rtlpriv->cfg->ops->set_hw_reg(hw,
 						HW_VAR_H2C_FW_PWRMODE,
-						(u8 *) (&ppsc->fwctrl_psmode));
+						&ppsc->fwctrl_psmode);
 
 				rtlpriv->cfg->ops->set_hw_reg(hw,
 						HW_VAR_SET_RPWM,
-						(u8 *) (&rpwm_val));
+						&rpwm_val);
 			} else {
 				/* Reset the power save related parameters. */
 				ppsc->dot11_psmode = EACTIVE;
@@ -446,7 +446,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	struct ieee80211_hdr *hdr = (void *) data;
+	struct ieee80211_hdr *hdr = data;
 	struct ieee80211_tim_ie *tim_ie;
 	u8 *tim;
 	u8 tim_len;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index f7f48c7..a45afda 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -656,9 +656,8 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw)
 	} else {
 		if (rtlpriv->dm.current_turbo_edca) {
 			u8 tmp = AC0_BE;
-			rtlpriv->cfg->ops->set_hw_reg(hw,
-						      HW_VAR_AC_PARAM,
-						      (u8 *) (&tmp));
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+						      &tmp);
 			rtlpriv->dm.current_turbo_edca = false;
 		}
 	}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
index 692c8ef..44febfd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -168,7 +168,7 @@ static void _rtl92c_write_fw(struct ieee80211_hw *hw,
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	u8 *bufferPtr = (u8 *) buffer;
+	u8 *bufferPtr = buffer;
 
 	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes\n", size);
 
@@ -262,7 +262,7 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
 		return 1;
 
 	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
-	pfwdata = (u8 *) rtlhal->pfirmware;
+	pfwdata = rtlhal->pfirmware;
 	fwsize = rtlhal->fwsize;
 
 	if (IS_FW_HEADER_EXIST(pfwheader)) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index 5c4d9bc..bd0da7e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -214,13 +214,13 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
 				rtlpriv->cfg->ops->set_hw_reg(hw,
 							      HW_VAR_AC_PARAM,
-							      (u8 *) (&e_aci));
+							      &e_aci);
 			}
 			break;
 		}
 	case HW_VAR_ACK_PREAMBLE:{
 			u8 reg_tmp;
-			u8 short_preamble = (bool) (*(u8 *) val);
+			u8 short_preamble = (bool)*val;
 			reg_tmp = (mac->cur_40_prime_sc) << 5;
 			if (short_preamble)
 				reg_tmp |= 0x80;
@@ -232,7 +232,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			u8 min_spacing_to_set;
 			u8 sec_min_space;
 
-			min_spacing_to_set = *((u8 *) val);
+			min_spacing_to_set = *val;
 			if (min_spacing_to_set <= 7) {
 				sec_min_space = 0;
 
@@ -257,7 +257,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 	case HW_VAR_SHORTGI_DENSITY:{
 			u8 density_to_set;
 
-			density_to_set = *((u8 *) val);
+			density_to_set = *val;
 			mac->min_space_cfg |= (density_to_set << 3);
 
 			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
@@ -284,7 +284,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			else
 				p_regtoset = regtoset_normal;
 
-			factor_toset = *((u8 *) val);
+			factor_toset = *(val);
 			if (factor_toset <= 3) {
 				factor_toset = (1 << (factor_toset + 2));
 				if (factor_toset > 0xf)
@@ -316,17 +316,17 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			break;
 		}
 	case HW_VAR_AC_PARAM:{
-			u8 e_aci = *((u8 *) val);
+			u8 e_aci = *(val);
 			rtl92c_dm_init_edca_turbo(hw);
 
 			if (rtlpci->acm_method != eAcmWay2_SW)
 				rtlpriv->cfg->ops->set_hw_reg(hw,
 							      HW_VAR_ACM_CTRL,
-							      (u8 *) (&e_aci));
+							      (&e_aci));
 			break;
 		}
 	case HW_VAR_ACM_CTRL:{
-			u8 e_aci = *((u8 *) val);
+			u8 e_aci = *(val);
 			union aci_aifsn *p_aci_aifsn =
 			    (union aci_aifsn *)(&(mac->ac[0].aifs));
 			u8 acm = p_aci_aifsn->f.acm;
@@ -382,7 +382,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			break;
 		}
 	case HW_VAR_RETRY_LIMIT:{
-			u8 retry_limit = ((u8 *) (val))[0];
+			u8 retry_limit = val[0];
 
 			rtl_write_word(rtlpriv, REG_RL,
 				       retry_limit << RETRY_LIMIT_SHORT_SHIFT |
@@ -396,13 +396,13 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		rtlefuse->efuse_usedbytes = *((u16 *) val);
 		break;
 	case HW_VAR_EFUSE_USAGE:
-		rtlefuse->efuse_usedpercentage = *((u8 *) val);
+		rtlefuse->efuse_usedpercentage = *val;
 		break;
 	case HW_VAR_IO_CMD:
 		rtl92c_phy_set_io_cmd(hw, (*(enum io_type *)val));
 		break;
 	case HW_VAR_WPA_CONFIG:
-		rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val));
+		rtl_write_byte(rtlpriv, REG_SECCFG, *val);
 		break;
 	case HW_VAR_SET_RPWM:{
 			u8 rpwm_val;
@@ -411,31 +411,30 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			udelay(1);
 
 			if (rpwm_val & BIT(7)) {
-				rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
-					       (*(u8 *) val));
+				rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val);
 			} else {
 				rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
-					       ((*(u8 *) val) | BIT(7)));
+					       *val | BIT(7));
 			}
 
 			break;
 		}
 	case HW_VAR_H2C_FW_PWRMODE:{
-			u8 psmode = (*(u8 *) val);
+			u8 psmode = *val;
 
 			if ((psmode != FW_PS_ACTIVE_MODE) &&
 			    (!IS_92C_SERIAL(rtlhal->version))) {
 				rtl92c_dm_rf_saving(hw, true);
 			}
 
-			rtl92c_set_fw_pwrmode_cmd(hw, (*(u8 *) val));
+			rtl92c_set_fw_pwrmode_cmd(hw, *val);
 			break;
 		}
 	case HW_VAR_FW_PSMODE_STATUS:
 		ppsc->fw_current_inpsmode = *((bool *) val);
 		break;
 	case HW_VAR_H2C_FW_JOINBSSRPT:{
-			u8 mstatus = (*(u8 *) val);
+			u8 mstatus = *val;
 			u8 tmp_regcr, tmp_reg422;
 			bool recover = false;
 
@@ -472,7 +471,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 				rtl_write_byte(rtlpriv, REG_CR + 1,
 					       (tmp_regcr & ~(BIT(0))));
 			}
-			rtl92c_set_fw_joinbss_report_cmd(hw, (*(u8 *) val));
+			rtl92c_set_fw_joinbss_report_cmd(hw, *val);
 
 			break;
 		}
@@ -486,7 +485,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			break;
 		}
 	case HW_VAR_CORRECT_TSF:{
-			u8 btype_ibss = ((u8 *) (val))[0];
+			u8 btype_ibss = val[0];
 
 			if (btype_ibss)
 				_rtl92ce_stop_tx_beacon(hw);
@@ -1589,10 +1588,10 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
 						 rtlefuse->autoload_failflag,
 						 hwinfo);
 
-	rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+	rtlefuse->eeprom_channelplan = *&hwinfo[EEPROM_CHANNELPLAN];
 	rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
 	rtlefuse->txpwr_fromeprom = true;
-	rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+	rtlefuse->eeprom_oemid = *&hwinfo[EEPROM_CUSTOMER_ID];
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 		 "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
@@ -1939,7 +1938,7 @@ void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw)
 	u16 sifs_timer;
 
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
-				      (u8 *)&mac->slot_time);
+				      &mac->slot_time);
 	if (!mac->ht_enable)
 		sifs_timer = 0x0a0a;
 	else
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index 3af874e..5216664 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -605,7 +605,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	bool defaultadapter = true;
 	struct ieee80211_sta *sta;
-	u8 *pdesc = (u8 *) pdesc_tx;
+	u8 *pdesc = pdesc_tx;
 	u16 seq_number;
 	__le16 fc = hdr->frame_control;
 	u8 fw_qsel = _rtl92ce_map_hwqueue_to_fwqueue(skb, hw_queue);
@@ -806,7 +806,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw,
 
 	SET_TX_DESC_OWN(pdesc, 1);
 
-	SET_TX_DESC_PKT_SIZE((u8 *) pdesc, (u16) (skb->len));
+	SET_TX_DESC_PKT_SIZE(pdesc, (u16) (skb->len));
 
 	SET_TX_DESC_FIRST_SEG(pdesc, 1);
 	SET_TX_DESC_LAST_SEG(pdesc, 1);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index 0c74d4f..4bbb711 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -381,11 +381,11 @@ static void _rtl92cu_read_adapter_info(struct ieee80211_hw *hw)
 	rtlefuse->eeprom_did = le16_to_cpu(*(__le16 *)&hwinfo[EEPROM_DID]);
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, " VID = 0x%02x PID = 0x%02x\n",
 		 rtlefuse->eeprom_vid, rtlefuse->eeprom_did);
-	rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+	rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
 	rtlefuse->eeprom_version =
 			 le16_to_cpu(*(__le16 *)&hwinfo[EEPROM_VERSION]);
 	rtlefuse->txpwr_fromeprom = true;
-	rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+	rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID];
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM Customer ID: 0x%2x\n",
 		 rtlefuse->eeprom_oemid);
 	if (rtlhal->oem_id == RT_CID_DEFAULT) {
@@ -1660,7 +1660,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 				for (e_aci = 0; e_aci < AC_MAX; e_aci++)
 					rtlpriv->cfg->ops->set_hw_reg(hw,
 								HW_VAR_AC_PARAM,
-								(u8 *)(&e_aci));
+								&e_aci);
 			} else {
 				u8 sifstime = 0;
 				u8	u1bAIFS;
@@ -1685,7 +1685,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		}
 	case HW_VAR_ACK_PREAMBLE:{
 			u8 reg_tmp;
-			u8 short_preamble = (bool) (*(u8 *) val);
+			u8 short_preamble = (bool)*val;
 			reg_tmp = 0;
 			if (short_preamble)
 				reg_tmp |= 0x80;
@@ -1696,7 +1696,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			u8 min_spacing_to_set;
 			u8 sec_min_space;
 
-			min_spacing_to_set = *((u8 *) val);
+			min_spacing_to_set = *val;
 			if (min_spacing_to_set <= 7) {
 				switch (rtlpriv->sec.pairwise_enc_algorithm) {
 				case NO_ENCRYPTION:
@@ -1729,7 +1729,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 	case HW_VAR_SHORTGI_DENSITY:{
 			u8 density_to_set;
 
-			density_to_set = *((u8 *) val);
+			density_to_set = *val;
 			density_to_set &= 0x1f;
 			mac->min_space_cfg &= 0x07;
 			mac->min_space_cfg |= (density_to_set << 3);
@@ -1747,7 +1747,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			u8 index = 0;
 
 			p_regtoset = regtoset_normal;
-			factor_toset = *((u8 *) val);
+			factor_toset = *val;
 			if (factor_toset <= 3) {
 				factor_toset = (1 << (factor_toset + 2));
 				if (factor_toset > 0xf)
@@ -1774,7 +1774,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			break;
 		}
 	case HW_VAR_AC_PARAM:{
-			u8 e_aci = *((u8 *) val);
+			u8 e_aci = *val;
 			u32 u4b_ac_param;
 			u16 cw_min = le16_to_cpu(mac->ac[e_aci].cw_min);
 			u16 cw_max = le16_to_cpu(mac->ac[e_aci].cw_max);
@@ -1814,11 +1814,11 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			}
 			if (rtlusb->acm_method != eAcmWay2_SW)
 				rtlpriv->cfg->ops->set_hw_reg(hw,
-					 HW_VAR_ACM_CTRL, (u8 *)(&e_aci));
+					 HW_VAR_ACM_CTRL, &e_aci);
 			break;
 		}
 	case HW_VAR_ACM_CTRL:{
-			u8 e_aci = *((u8 *) val);
+			u8 e_aci = *val;
 			union aci_aifsn *p_aci_aifsn = (union aci_aifsn *)
 							(&(mac->ac[0].aifs));
 			u8 acm = p_aci_aifsn->f.acm;
@@ -1874,7 +1874,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			break;
 		}
 	case HW_VAR_RETRY_LIMIT:{
-			u8 retry_limit = ((u8 *) (val))[0];
+			u8 retry_limit = val[0];
 
 			rtl_write_word(rtlpriv, REG_RL,
 				       retry_limit << RETRY_LIMIT_SHORT_SHIFT |
@@ -1891,39 +1891,38 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		rtlefuse->efuse_usedbytes = *((u16 *) val);
 		break;
 	case HW_VAR_EFUSE_USAGE:
-		rtlefuse->efuse_usedpercentage = *((u8 *) val);
+		rtlefuse->efuse_usedpercentage = *val;
 		break;
 	case HW_VAR_IO_CMD:
 		rtl92c_phy_set_io_cmd(hw, (*(enum io_type *)val));
 		break;
 	case HW_VAR_WPA_CONFIG:
-		rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val));
+		rtl_write_byte(rtlpriv, REG_SECCFG, *val);
 		break;
 	case HW_VAR_SET_RPWM:{
 			u8 rpwm_val = rtl_read_byte(rtlpriv, REG_USB_HRPWM);
 
 			if (rpwm_val & BIT(7))
-				rtl_write_byte(rtlpriv, REG_USB_HRPWM,
-					       (*(u8 *)val));
+				rtl_write_byte(rtlpriv, REG_USB_HRPWM, *val);
 			else
 				rtl_write_byte(rtlpriv, REG_USB_HRPWM,
-					       ((*(u8 *)val) | BIT(7)));
+					       *val | BIT(7));
 			break;
 		}
 	case HW_VAR_H2C_FW_PWRMODE:{
-			u8 psmode = (*(u8 *) val);
+			u8 psmode = *val;
 
 			if ((psmode != FW_PS_ACTIVE_MODE) &&
 			   (!IS_92C_SERIAL(rtlhal->version)))
 				rtl92c_dm_rf_saving(hw, true);
-			rtl92c_set_fw_pwrmode_cmd(hw, (*(u8 *) val));
+			rtl92c_set_fw_pwrmode_cmd(hw, (*val));
 			break;
 		}
 	case HW_VAR_FW_PSMODE_STATUS:
 		ppsc->fw_current_inpsmode = *((bool *) val);
 		break;
 	case HW_VAR_H2C_FW_JOINBSSRPT:{
-			u8 mstatus = (*(u8 *) val);
+			u8 mstatus = *val;
 			u8 tmp_reg422;
 			bool recover = false;
 
@@ -1948,7 +1947,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 						tmp_reg422 | BIT(6));
 				rtl_write_byte(rtlpriv, REG_CR + 1, 0x02);
 			}
-			rtl92c_set_fw_joinbss_report_cmd(hw, (*(u8 *) val));
+			rtl92c_set_fw_joinbss_report_cmd(hw, (*val));
 			break;
 		}
 	case HW_VAR_AID:{
@@ -1961,7 +1960,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			break;
 		}
 	case HW_VAR_CORRECT_TSF:{
-			u8 btype_ibss = ((u8 *) (val))[0];
+			u8 btype_ibss = val[0];
 
 			if (btype_ibss)
 				_rtl92cu_stop_tx_beacon(hw);
@@ -2184,7 +2183,7 @@ void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw)
 	u16 sifs_timer;
 
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
-				      (u8 *)&mac->slot_time);
+				      &mac->slot_time);
 	if (!mac->ht_enable)
 		sifs_timer = 0x0a0a;
 	else
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index 21bc827..2e6eb35 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -668,7 +668,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw,
 	SET_TX_DESC_RATE_ID(pdesc, 7);
 	SET_TX_DESC_MACID(pdesc, 0);
 	SET_TX_DESC_OWN(pdesc, 1);
-	SET_TX_DESC_PKT_SIZE((u8 *) pdesc, (u16) (skb->len));
+	SET_TX_DESC_PKT_SIZE(pdesc, (u16)skb->len);
 	SET_TX_DESC_FIRST_SEG(pdesc, 1);
 	SET_TX_DESC_LAST_SEG(pdesc, 1);
 	SET_TX_DESC_OFFSET(pdesc, 0x20);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
index a7d63a8..c0201ed 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
@@ -696,7 +696,7 @@ static void rtl92d_dm_check_edca_turbo(struct ieee80211_hw *hw)
 		if (rtlpriv->dm.current_turbo_edca) {
 			u8 tmp = AC0_BE;
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
-						      (u8 *) (&tmp));
+						      &tmp);
 			rtlpriv->dm.current_turbo_edca = false;
 		}
 	}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c
index f548a8d..895ae6c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c
@@ -120,7 +120,7 @@ static void _rtl92d_write_fw(struct ieee80211_hw *hw,
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	u8 *bufferPtr = (u8 *) buffer;
+	u8 *bufferPtr = buffer;
 	u32 pagenums, remainSize;
 	u32 page, offset;
 
@@ -256,8 +256,8 @@ int rtl92d_download_fw(struct ieee80211_hw *hw)
 	if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
 		return 1;
 	fwsize = rtlhal->fwsize;
-	pfwheader = (u8 *) rtlhal->pfirmware;
-	pfwdata = (u8 *) rtlhal->pfirmware;
+	pfwheader = rtlhal->pfirmware;
+	pfwdata = rtlhal->pfirmware;
 	rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader);
 	rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader);
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
index b338d52..f4051f4 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
@@ -235,12 +235,12 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		for (e_aci = 0; e_aci < AC_MAX; e_aci++)
 			rtlpriv->cfg->ops->set_hw_reg(hw,
 						      HW_VAR_AC_PARAM,
-						      (u8 *) (&e_aci));
+						      (&e_aci));
 		break;
 	}
 	case HW_VAR_ACK_PREAMBLE: {
 		u8 reg_tmp;
-		u8 short_preamble = (bool) (*(u8 *) val);
+		u8 short_preamble = (bool) (*val);
 
 		reg_tmp = (mac->cur_40_prime_sc) << 5;
 		if (short_preamble)
@@ -252,7 +252,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		u8 min_spacing_to_set;
 		u8 sec_min_space;
 
-		min_spacing_to_set = *((u8 *) val);
+		min_spacing_to_set = *val;
 		if (min_spacing_to_set <= 7) {
 			sec_min_space = 0;
 			if (min_spacing_to_set < sec_min_space)
@@ -271,7 +271,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 	case HW_VAR_SHORTGI_DENSITY: {
 		u8 density_to_set;
 
-		density_to_set = *((u8 *) val);
+		density_to_set = *val;
 		mac->min_space_cfg = rtlpriv->rtlhal.minspace_cfg;
 		mac->min_space_cfg |= (density_to_set << 3);
 		RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
@@ -293,7 +293,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			regtoSet = 0x66626641;
 		else
 			regtoSet = 0xb972a841;
-		factor_toset = *((u8 *) val);
+		factor_toset = *val;
 		if (factor_toset <= 3) {
 			factor_toset = (1 << (factor_toset + 2));
 			if (factor_toset > 0xf)
@@ -316,15 +316,15 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		break;
 	}
 	case HW_VAR_AC_PARAM: {
-		u8 e_aci = *((u8 *) val);
+		u8 e_aci = *val;
 		rtl92d_dm_init_edca_turbo(hw);
 		if (rtlpci->acm_method != eAcmWay2_SW)
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
-						      (u8 *) (&e_aci));
+						      &e_aci);
 		break;
 	}
 	case HW_VAR_ACM_CTRL: {
-		u8 e_aci = *((u8 *) val);
+		u8 e_aci = *val;
 		union aci_aifsn *p_aci_aifsn =
 		    (union aci_aifsn *)(&(mac->ac[0].aifs));
 		u8 acm = p_aci_aifsn->f.acm;
@@ -376,7 +376,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		rtlpci->receive_config = ((u32 *) (val))[0];
 		break;
 	case HW_VAR_RETRY_LIMIT: {
-		u8 retry_limit = ((u8 *) (val))[0];
+		u8 retry_limit = val[0];
 
 		rtl_write_word(rtlpriv, REG_RL,
 			       retry_limit << RETRY_LIMIT_SHORT_SHIFT |
@@ -390,16 +390,16 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		rtlefuse->efuse_usedbytes = *((u16 *) val);
 		break;
 	case HW_VAR_EFUSE_USAGE:
-		rtlefuse->efuse_usedpercentage = *((u8 *) val);
+		rtlefuse->efuse_usedpercentage = *val;
 		break;
 	case HW_VAR_IO_CMD:
 		rtl92d_phy_set_io_cmd(hw, (*(enum io_type *)val));
 		break;
 	case HW_VAR_WPA_CONFIG:
-		rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val));
+		rtl_write_byte(rtlpriv, REG_SECCFG, *val);
 		break;
 	case HW_VAR_SET_RPWM:
-		rtl92d_fill_h2c_cmd(hw, H2C_PWRM, 1, (u8 *) (val));
+		rtl92d_fill_h2c_cmd(hw, H2C_PWRM, 1, (val));
 		break;
 	case HW_VAR_H2C_FW_PWRMODE:
 		break;
@@ -407,7 +407,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		ppsc->fw_current_inpsmode = *((bool *) val);
 		break;
 	case HW_VAR_H2C_FW_JOINBSSRPT: {
-		u8 mstatus = (*(u8 *) val);
+		u8 mstatus = (*val);
 		u8 tmp_regcr, tmp_reg422;
 		bool recover = false;
 
@@ -435,7 +435,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			rtl_write_byte(rtlpriv, REG_CR + 1,
 				       (tmp_regcr & ~(BIT(0))));
 		}
-		rtl92d_set_fw_joinbss_report_cmd(hw, (*(u8 *) val));
+		rtl92d_set_fw_joinbss_report_cmd(hw, (*val));
 		break;
 	}
 	case HW_VAR_AID: {
@@ -447,7 +447,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		break;
 	}
 	case HW_VAR_CORRECT_TSF: {
-		u8 btype_ibss = ((u8 *) (val))[0];
+		u8 btype_ibss = val[0];
 
 		if (btype_ibss)
 			_rtl92de_stop_tx_beacon(hw);
@@ -1794,7 +1794,7 @@ static void _rtl92de_read_adapter_info(struct ieee80211_hw *hw)
 			 "RTL819X Not boot from eeprom, check it !!\n");
 		return;
 	}
-	rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+	rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID];
 	_rtl92de_read_macphymode_and_bandtype(hw, hwinfo);
 
 	/* VID, DID  SE     0xA-D */
@@ -2115,7 +2115,7 @@ void rtl92de_update_channel_access_setting(struct ieee80211_hw *hw)
 	u16 sifs_timer;
 
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
-				      (u8 *)&mac->slot_time);
+				      &mac->slot_time);
 	if (!mac->ht_enable)
 		sifs_timer = 0x0a0a;
 	else
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
index 1666ef7..f80690d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
@@ -560,7 +560,7 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
 	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct ieee80211_sta *sta = info->control.sta;
-	u8 *pdesc = (u8 *) pdesc_tx;
+	u8 *pdesc = pdesc_tx;
 	u16 seq_number;
 	__le16 fc = hdr->frame_control;
 	unsigned int buf_len = 0;
@@ -761,11 +761,11 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw,
 	SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
 	SET_TX_DESC_FIRST_SEG(pdesc, 1);
 	SET_TX_DESC_LAST_SEG(pdesc, 1);
-	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len));
+	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)skb->len);
 	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
 	SET_TX_DESC_RATE_ID(pdesc, 7);
 	SET_TX_DESC_MACID(pdesc, 0);
-	SET_TX_DESC_PKT_SIZE((u8 *) pdesc, (u16) (skb->len));
+	SET_TX_DESC_PKT_SIZE(pdesc, (u16) (skb->len));
 	SET_TX_DESC_FIRST_SEG(pdesc, 1);
 	SET_TX_DESC_LAST_SEG(pdesc, 1);
 	SET_TX_DESC_OFFSET(pdesc, 0x20);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
index 2e11580..465f581 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
@@ -146,7 +146,7 @@ static void _rtl92s_dm_check_edca_turbo(struct ieee80211_hw *hw)
 		if (rtlpriv->dm.current_turbo_edca) {
 			u8 tmp = AC0_BE;
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
-						      (u8 *)(&tmp));
+						      &tmp);
 			rtlpriv->dm.current_turbo_edca = false;
 		}
 	}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
index b141c35..4542e69 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
@@ -145,13 +145,13 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
 				rtlpriv->cfg->ops->set_hw_reg(hw,
 						HW_VAR_AC_PARAM,
-						(u8 *)(&e_aci));
+						(&e_aci));
 			}
 			break;
 		}
 	case HW_VAR_ACK_PREAMBLE:{
 			u8 reg_tmp;
-			u8 short_preamble = (bool) (*(u8 *) val);
+			u8 short_preamble = (bool) (*val);
 			reg_tmp = (mac->cur_40_prime_sc) << 5;
 			if (short_preamble)
 				reg_tmp |= 0x80;
@@ -163,7 +163,7 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			u8 min_spacing_to_set;
 			u8 sec_min_space;
 
-			min_spacing_to_set = *((u8 *)val);
+			min_spacing_to_set = *val;
 			if (min_spacing_to_set <= 7) {
 				if (rtlpriv->sec.pairwise_enc_algorithm ==
 				    NO_ENCRYPTION)
@@ -194,7 +194,7 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 	case HW_VAR_SHORTGI_DENSITY:{
 			u8 density_to_set;
 
-			density_to_set = *((u8 *) val);
+			density_to_set = *val;
 			mac->min_space_cfg = rtlpriv->rtlhal.minspace_cfg;
 			mac->min_space_cfg |= (density_to_set << 3);
 
@@ -216,7 +216,7 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 				15, 15, 15, 15, 0};
 			u8 index = 0;
 
-			factor_toset = *((u8 *) val);
+			factor_toset = *val;
 			if (factor_toset <= 3) {
 				factor_toset = (1 << (factor_toset + 2));
 				if (factor_toset > 0xf)
@@ -248,17 +248,17 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			break;
 		}
 	case HW_VAR_AC_PARAM:{
-			u8 e_aci = *((u8 *) val);
+			u8 e_aci = *val;
 			rtl92s_dm_init_edca_turbo(hw);
 
 			if (rtlpci->acm_method != eAcmWay2_SW)
 				rtlpriv->cfg->ops->set_hw_reg(hw,
 						 HW_VAR_ACM_CTRL,
-						 (u8 *)(&e_aci));
+						 &e_aci);
 			break;
 		}
 	case HW_VAR_ACM_CTRL:{
-			u8 e_aci = *((u8 *) val);
+			u8 e_aci = *val;
 			union aci_aifsn *p_aci_aifsn = (union aci_aifsn *)(&(
 							mac->ac[0].aifs));
 			u8 acm = p_aci_aifsn->f.acm;
@@ -313,7 +313,7 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			break;
 		}
 	case HW_VAR_RETRY_LIMIT:{
-			u8 retry_limit = ((u8 *) (val))[0];
+			u8 retry_limit = val[0];
 
 			rtl_write_word(rtlpriv, RETRY_LIMIT,
 				       retry_limit << RETRY_LIMIT_SHORT_SHIFT |
@@ -328,14 +328,14 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			break;
 		}
 	case HW_VAR_EFUSE_USAGE: {
-			rtlefuse->efuse_usedpercentage = *((u8 *) val);
+			rtlefuse->efuse_usedpercentage = *val;
 			break;
 		}
 	case HW_VAR_IO_CMD: {
 			break;
 		}
 	case HW_VAR_WPA_CONFIG: {
-			rtl_write_byte(rtlpriv, REG_SECR, *((u8 *) val));
+			rtl_write_byte(rtlpriv, REG_SECR, *val);
 			break;
 		}
 	case HW_VAR_SET_RPWM:{
@@ -1813,8 +1813,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
 		else
 			index = 2;
 
-		tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_HT20_DIFF +
-			   index]) & 0xff;
+		tempval = hwinfo[EEPROM_TX_PWR_HT20_DIFF + index] & 0xff;
 		rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF);
 		rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] =
 						 ((tempval >> 4) & 0xF);
@@ -1830,14 +1829,13 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
 		else
 			index = 1;
 
-		tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_OFDM_DIFF + index])
-				  & 0xff;
+		tempval = hwinfo[EEPROM_TX_PWR_OFDM_DIFF + index] & 0xff;
 		rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] =
 				 (tempval & 0xF);
 		rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] =
 				 ((tempval >> 4) & 0xF);
 
-		tempval = (*(u8 *)&hwinfo[TX_PWR_SAFETY_CHK]);
+		tempval = hwinfo[TX_PWR_SAFETY_CHK];
 		rtlefuse->txpwr_safetyflag = (tempval & 0x01);
 	}
 
@@ -1876,7 +1874,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
 
 	/* Read RF-indication and Tx Power gain
 	 * index diff of legacy to HT OFDM rate. */
-	tempval = (*(u8 *)&hwinfo[EEPROM_RFIND_POWERDIFF]) & 0xff;
+	tempval = hwinfo[EEPROM_RFIND_POWERDIFF] & 0xff;
 	rtlefuse->eeprom_txpowerdiff = tempval;
 	rtlefuse->legacy_httxpowerdiff =
 		rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][0];
@@ -1887,7 +1885,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
 	/* Get TSSI value for each path. */
 	usvalue = *(u16 *)&hwinfo[EEPROM_TSSI_A];
 	rtlefuse->eeprom_tssi[RF90_PATH_A] = (u8)((usvalue & 0xff00) >> 8);
-	usvalue = *(u8 *)&hwinfo[EEPROM_TSSI_B];
+	usvalue = hwinfo[EEPROM_TSSI_B];
 	rtlefuse->eeprom_tssi[RF90_PATH_B] = (u8)(usvalue & 0xff);
 
 	RTPRINT(rtlpriv, FINIT, INIT_TxPower, "TSSI_A = 0x%x, TSSI_B = 0x%x\n",
@@ -1896,7 +1894,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
 
 	/* Read antenna tx power offset of B/C/D to A  from EEPROM */
 	/* and read ThermalMeter from EEPROM */
-	tempval = *(u8 *)&hwinfo[EEPROM_THERMALMETER];
+	tempval = hwinfo[EEPROM_THERMALMETER];
 	rtlefuse->eeprom_thermalmeter = tempval;
 	RTPRINT(rtlpriv, FINIT, INIT_TxPower,
 		"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
@@ -1906,20 +1904,20 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
 	rtlefuse->tssi_13dbm = rtlefuse->eeprom_thermalmeter * 100;
 
 	/* Read CrystalCap from EEPROM */
-	tempval = (*(u8 *)&hwinfo[EEPROM_CRYSTALCAP]) >> 4;
+	tempval = hwinfo[EEPROM_CRYSTALCAP] >> 4;
 	rtlefuse->eeprom_crystalcap = tempval;
 	/* CrystalCap, BIT(12)~15 */
 	rtlefuse->crystalcap = rtlefuse->eeprom_crystalcap;
 
 	/* Read IC Version && Channel Plan */
 	/* Version ID, Channel plan */
-	rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+	rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
 	rtlefuse->txpwr_fromeprom = true;
 	RTPRINT(rtlpriv, FINIT, INIT_TxPower,
 		"EEPROM ChannelPlan = 0x%4x\n", rtlefuse->eeprom_channelplan);
 
 	/* Read Customer ID or Board Type!!! */
-	tempval = *(u8 *)&hwinfo[EEPROM_BOARDTYPE];
+	tempval = hwinfo[EEPROM_BOARDTYPE];
 	/* Change RF type definition */
 	if (tempval == 0)
 		rtlphy->rf_type = RF_2T2R;
@@ -1941,7 +1939,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
 		}
 	}
 	rtlefuse->b1ss_support = rtlefuse->b1x1_recvcombine;
-	rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMID];
+	rtlefuse->eeprom_oemid = *&hwinfo[EEPROM_CUSTOMID];
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM Customer ID: 0x%2x",
 		 rtlefuse->eeprom_oemid);
@@ -2251,7 +2249,7 @@ void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw)
 	u16 sifs_timer;
 
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
-				      (u8 *)&mac->slot_time);
+				      &mac->slot_time);
 	sifs_timer = 0x0e0e;
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
index 8d7099b..b917a2a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
@@ -1247,6 +1247,9 @@ static void _rtl92s_phy_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
 		/* Read HT 40 OFDM TX power */
 		ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_2s[0][index];
 		ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_2s[1][index];
+	} else {
+		ofdmpowerLevel[0] = 0;
+		ofdmpowerLevel[1] = 0;
 	}
 }
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
index 730bcc9..ad4b480 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
@@ -29,7 +29,6 @@
 
 #include "../wifi.h"
 #include "../core.h"
-#include "../pci.h"
 #include "../base.h"
 #include "../pci.h"
 #include "reg.h"
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
index 812b585..36d1cb3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -599,7 +599,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	struct ieee80211_sta *sta = info->control.sta;
-	u8 *pdesc = (u8 *) pdesc_tx;
+	u8 *pdesc = pdesc_tx;
 	u16 seq_number;
 	__le16 fc = hdr->frame_control;
 	u8 reserved_macid = 0;
diff --git a/drivers/net/wireless/ti/Kconfig b/drivers/net/wireless/ti/Kconfig
index 1a72932..be80011 100644
--- a/drivers/net/wireless/ti/Kconfig
+++ b/drivers/net/wireless/ti/Kconfig
@@ -8,6 +8,7 @@ menuconfig WL_TI
 if WL_TI
 source "drivers/net/wireless/ti/wl1251/Kconfig"
 source "drivers/net/wireless/ti/wl12xx/Kconfig"
+source "drivers/net/wireless/ti/wl18xx/Kconfig"
 
 # keep last for automatic dependencies
 source "drivers/net/wireless/ti/wlcore/Kconfig"
diff --git a/drivers/net/wireless/ti/Makefile b/drivers/net/wireless/ti/Makefile
index 0a56562..4d68239 100644
--- a/drivers/net/wireless/ti/Makefile
+++ b/drivers/net/wireless/ti/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_WLCORE)			+= wlcore/
 obj-$(CONFIG_WL12XX)			+= wl12xx/
 obj-$(CONFIG_WL12XX_PLATFORM_DATA)	+= wlcore/
 obj-$(CONFIG_WL1251)			+= wl1251/
+obj-$(CONFIG_WL18XX)			+= wl18xx/
diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c
index ad87a1a..db6430c 100644
--- a/drivers/net/wireless/ti/wl1251/acx.c
+++ b/drivers/net/wireless/ti/wl1251/acx.c
@@ -869,7 +869,7 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime)
 	}
 
 	*mactime = tsf_info->current_tsf_lsb |
-		(tsf_info->current_tsf_msb << 31);
+		((u64)tsf_info->current_tsf_msb << 32);
 
 out:
 	kfree(tsf_info);
diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c
index d14d69d..6822b84 100644
--- a/drivers/net/wireless/ti/wl1251/cmd.c
+++ b/drivers/net/wireless/ti/wl1251/cmd.c
@@ -277,15 +277,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel,
 	join->rx_config_options = wl->rx_config;
 	join->rx_filter_options = wl->rx_filter;
 
-	/*
-	 * FIXME: disable temporarily all filters because after commit
-	 * 9cef8737 "mac80211: fix managed mode BSSID handling" broke
-	 * association. The filter logic needs to be implemented properly
-	 * and once that is done, this hack can be removed.
-	 */
-	join->rx_config_options = 0;
-	join->rx_filter_options = WL1251_DEFAULT_RX_FILTER;
-
 	join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
 		RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
 
diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c
index 9f15cca..5ec50a4 100644
--- a/drivers/net/wireless/ti/wl1251/event.c
+++ b/drivers/net/wireless/ti/wl1251/event.c
@@ -76,8 +76,7 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
 		}
 	}
 
-	if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID &&
-	    wl->station_mode != STATION_ACTIVE_MODE) {
+	if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID) {
 		wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT");
 
 		/* indicate to the stack, that beacons have been lost */
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index d1afb8e..3118c42 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -334,6 +334,12 @@ static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel,
 	if (ret < 0)
 		goto out;
 
+	/*
+	 * Join command applies filters, and if we are not associated,
+	 * BSSID filter must be disabled for association to work.
+	 */
+	if (is_zero_ether_addr(wl->bssid))
+		wl->rx_config &= ~CFG_BSSID_FILTER_EN;
 
 	ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval,
 			      dtim_period);
@@ -348,33 +354,6 @@ out:
 	return ret;
 }
 
-static void wl1251_filter_work(struct work_struct *work)
-{
-	struct wl1251 *wl =
-		container_of(work, struct wl1251, filter_work);
-	int ret;
-
-	mutex_lock(&wl->mutex);
-
-	if (wl->state == WL1251_STATE_OFF)
-		goto out;
-
-	ret = wl1251_ps_elp_wakeup(wl);
-	if (ret < 0)
-		goto out;
-
-	ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int,
-			  wl->dtim_period);
-	if (ret < 0)
-		goto out_sleep;
-
-out_sleep:
-	wl1251_ps_elp_sleep(wl);
-
-out:
-	mutex_unlock(&wl->mutex);
-}
-
 static void wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
 	struct wl1251 *wl = hw->priv;
@@ -478,7 +457,6 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
 
 	cancel_work_sync(&wl->irq_work);
 	cancel_work_sync(&wl->tx_work);
-	cancel_work_sync(&wl->filter_work);
 	cancel_delayed_work_sync(&wl->elp_work);
 
 	mutex_lock(&wl->mutex);
@@ -681,13 +659,15 @@ out:
 				  FIF_FCSFAIL | \
 				  FIF_BCN_PRBRESP_PROMISC | \
 				  FIF_CONTROL | \
-				  FIF_OTHER_BSS)
+				  FIF_OTHER_BSS | \
+				  FIF_PROBE_REQ)
 
 static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
 				       unsigned int changed,
 				       unsigned int *total,u64 multicast)
 {
 	struct wl1251 *wl = hw->priv;
+	int ret;
 
 	wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter");
 
@@ -698,7 +678,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
 		/* no filters which we support changed */
 		return;
 
-	/* FIXME: wl->rx_config and wl->rx_filter are not protected */
+	mutex_lock(&wl->mutex);
 
 	wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
 	wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
@@ -721,15 +701,25 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
 	}
 	if (*total & FIF_CONTROL)
 		wl->rx_filter |= CFG_RX_CTL_EN;
-	if (*total & FIF_OTHER_BSS)
-		wl->rx_filter &= ~CFG_BSSID_FILTER_EN;
+	if (*total & FIF_OTHER_BSS || is_zero_ether_addr(wl->bssid))
+		wl->rx_config &= ~CFG_BSSID_FILTER_EN;
+	if (*total & FIF_PROBE_REQ)
+		wl->rx_filter |= CFG_RX_PREQ_EN;
 
-	/*
-	 * FIXME: workqueues need to be properly cancelled on stop(), for
-	 * now let's just disable changing the filter settings. They will
-	 * be updated any on config().
-	 */
-	/* schedule_work(&wl->filter_work); */
+	if (wl->state == WL1251_STATE_OFF)
+		goto out;
+
+	ret = wl1251_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	/* send filters to firmware */
+	wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
+
+	wl1251_ps_elp_sleep(wl);
+
+out:
+	mutex_unlock(&wl->mutex);
 }
 
 /* HW encryption */
@@ -1390,7 +1380,6 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
 
 	skb_queue_head_init(&wl->tx_queue);
 
-	INIT_WORK(&wl->filter_work, wl1251_filter_work);
 	INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work);
 	wl->channel = WL1251_DEFAULT_CHANNEL;
 	wl->scanning = false;
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c
index 87f6305..567660c 100644
--- a/drivers/net/wireless/ti/wl1251/spi.c
+++ b/drivers/net/wireless/ti/wl1251/spi.c
@@ -73,6 +73,8 @@ static void wl1251_spi_reset(struct wl1251 *wl)
 	spi_sync(wl_to_spi(wl), &m);
 
 	wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
+
+	kfree(cmd);
 }
 
 static void wl1251_spi_wake(struct wl1251 *wl)
@@ -127,6 +129,8 @@ static void wl1251_spi_wake(struct wl1251 *wl)
 	spi_sync(wl_to_spi(wl), &m);
 
 	wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
+
+	kfree(cmd);
 }
 
 static void wl1251_spi_reset_wake(struct wl1251 *wl)
diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h
index 9d8f581..fd02060 100644
--- a/drivers/net/wireless/ti/wl1251/wl1251.h
+++ b/drivers/net/wireless/ti/wl1251/wl1251.h
@@ -315,7 +315,6 @@ struct wl1251 {
 	bool tx_queue_stopped;
 
 	struct work_struct tx_work;
-	struct work_struct filter_work;
 
 	/* Pending TX frames */
 	struct sk_buff *tx_frames[16];
diff --git a/drivers/net/wireless/ti/wl12xx/Makefile b/drivers/net/wireless/ti/wl12xx/Makefile
index 87f64b1..da509aa 100644
--- a/drivers/net/wireless/ti/wl12xx/Makefile
+++ b/drivers/net/wireless/ti/wl12xx/Makefile
@@ -1,3 +1,3 @@
-wl12xx-objs	= main.o cmd.o acx.o
+wl12xx-objs	= main.o cmd.o acx.o debugfs.o
 
 obj-$(CONFIG_WL12XX)		+= wl12xx.o
diff --git a/drivers/net/wireless/ti/wl12xx/acx.h b/drivers/net/wireless/ti/wl12xx/acx.h
index d1f5aba..2a26868 100644
--- a/drivers/net/wireless/ti/wl12xx/acx.h
+++ b/drivers/net/wireless/ti/wl12xx/acx.h
@@ -24,6 +24,21 @@
 #define __WL12XX_ACX_H__
 
 #include "../wlcore/wlcore.h"
+#include "../wlcore/acx.h"
+
+#define WL12XX_ACX_ALL_EVENTS_VECTOR	(WL1271_ACX_INTR_WATCHDOG      | \
+					WL1271_ACX_INTR_INIT_COMPLETE | \
+					WL1271_ACX_INTR_EVENT_A       | \
+					WL1271_ACX_INTR_EVENT_B       | \
+					WL1271_ACX_INTR_CMD_COMPLETE  | \
+					WL1271_ACX_INTR_HW_AVAILABLE  | \
+					WL1271_ACX_INTR_DATA)
+
+#define WL12XX_INTR_MASK		(WL1271_ACX_INTR_WATCHDOG      | \
+					WL1271_ACX_INTR_EVENT_A       | \
+					WL1271_ACX_INTR_EVENT_B       | \
+					WL1271_ACX_INTR_HW_AVAILABLE  | \
+					WL1271_ACX_INTR_DATA)
 
 struct wl1271_acx_host_config_bitmap {
 	struct acx_header header;
@@ -31,6 +46,228 @@ struct wl1271_acx_host_config_bitmap {
 	__le32 host_cfg_bitmap;
 } __packed;
 
+struct wl12xx_acx_tx_statistics {
+	__le32 internal_desc_overflow;
+}  __packed;
+
+struct wl12xx_acx_rx_statistics {
+	__le32 out_of_mem;
+	__le32 hdr_overflow;
+	__le32 hw_stuck;
+	__le32 dropped;
+	__le32 fcs_err;
+	__le32 xfr_hint_trig;
+	__le32 path_reset;
+	__le32 reset_counter;
+} __packed;
+
+struct wl12xx_acx_dma_statistics {
+	__le32 rx_requested;
+	__le32 rx_errors;
+	__le32 tx_requested;
+	__le32 tx_errors;
+}  __packed;
+
+struct wl12xx_acx_isr_statistics {
+	/* host command complete */
+	__le32 cmd_cmplt;
+
+	/* fiqisr() */
+	__le32 fiqs;
+
+	/* (INT_STS_ND & INT_TRIG_RX_HEADER) */
+	__le32 rx_headers;
+
+	/* (INT_STS_ND & INT_TRIG_RX_CMPLT) */
+	__le32 rx_completes;
+
+	/* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */
+	__le32 rx_mem_overflow;
+
+	/* (INT_STS_ND & INT_TRIG_S_RX_RDY) */
+	__le32 rx_rdys;
+
+	/* irqisr() */
+	__le32 irqs;
+
+	/* (INT_STS_ND & INT_TRIG_TX_PROC) */
+	__le32 tx_procs;
+
+	/* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */
+	__le32 decrypt_done;
+
+	/* (INT_STS_ND & INT_TRIG_DMA0) */
+	__le32 dma0_done;
+
+	/* (INT_STS_ND & INT_TRIG_DMA1) */
+	__le32 dma1_done;
+
+	/* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */
+	__le32 tx_exch_complete;
+
+	/* (INT_STS_ND & INT_TRIG_COMMAND) */
+	__le32 commands;
+
+	/* (INT_STS_ND & INT_TRIG_RX_PROC) */
+	__le32 rx_procs;
+
+	/* (INT_STS_ND & INT_TRIG_PM_802) */
+	__le32 hw_pm_mode_changes;
+
+	/* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */
+	__le32 host_acknowledges;
+
+	/* (INT_STS_ND & INT_TRIG_PM_PCI) */
+	__le32 pci_pm;
+
+	/* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */
+	__le32 wakeups;
+
+	/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
+	__le32 low_rssi;
+} __packed;
+
+struct wl12xx_acx_wep_statistics {
+	/* WEP address keys configured */
+	__le32 addr_key_count;
+
+	/* default keys configured */
+	__le32 default_key_count;
+
+	__le32 reserved;
+
+	/* number of times that WEP key not found on lookup */
+	__le32 key_not_found;
+
+	/* number of times that WEP key decryption failed */
+	__le32 decrypt_fail;
+
+	/* WEP packets decrypted */
+	__le32 packets;
+
+	/* WEP decrypt interrupts */
+	__le32 interrupt;
+} __packed;
+
+#define ACX_MISSED_BEACONS_SPREAD 10
+
+struct wl12xx_acx_pwr_statistics {
+	/* the amount of enters into power save mode (both PD & ELP) */
+	__le32 ps_enter;
+
+	/* the amount of enters into ELP mode */
+	__le32 elp_enter;
+
+	/* the amount of missing beacon interrupts to the host */
+	__le32 missing_bcns;
+
+	/* the amount of wake on host-access times */
+	__le32 wake_on_host;
+
+	/* the amount of wake on timer-expire */
+	__le32 wake_on_timer_exp;
+
+	/* the number of packets that were transmitted with PS bit set */
+	__le32 tx_with_ps;
+
+	/* the number of packets that were transmitted with PS bit clear */
+	__le32 tx_without_ps;
+
+	/* the number of received beacons */
+	__le32 rcvd_beacons;
+
+	/* the number of entering into PowerOn (power save off) */
+	__le32 power_save_off;
+
+	/* the number of entries into power save mode */
+	__le16 enable_ps;
+
+	/*
+	 * the number of exits from power save, not including failed PS
+	 * transitions
+	 */
+	__le16 disable_ps;
+
+	/*
+	 * the number of times the TSF counter was adjusted because
+	 * of drift
+	 */
+	__le32 fix_tsf_ps;
+
+	/* Gives statistics about the spread continuous missed beacons.
+	 * The 16 LSB are dedicated for the PS mode.
+	 * The 16 MSB are dedicated for the PS mode.
+	 * cont_miss_bcns_spread[0] - single missed beacon.
+	 * cont_miss_bcns_spread[1] - two continuous missed beacons.
+	 * cont_miss_bcns_spread[2] - three continuous missed beacons.
+	 * ...
+	 * cont_miss_bcns_spread[9] - ten and more continuous missed beacons.
+	*/
+	__le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
+
+	/* the number of beacons in awake mode */
+	__le32 rcvd_awake_beacons;
+} __packed;
+
+struct wl12xx_acx_mic_statistics {
+	__le32 rx_pkts;
+	__le32 calc_failure;
+} __packed;
+
+struct wl12xx_acx_aes_statistics {
+	__le32 encrypt_fail;
+	__le32 decrypt_fail;
+	__le32 encrypt_packets;
+	__le32 decrypt_packets;
+	__le32 encrypt_interrupt;
+	__le32 decrypt_interrupt;
+} __packed;
+
+struct wl12xx_acx_event_statistics {
+	__le32 heart_beat;
+	__le32 calibration;
+	__le32 rx_mismatch;
+	__le32 rx_mem_empty;
+	__le32 rx_pool;
+	__le32 oom_late;
+	__le32 phy_transmit_error;
+	__le32 tx_stuck;
+} __packed;
+
+struct wl12xx_acx_ps_statistics {
+	__le32 pspoll_timeouts;
+	__le32 upsd_timeouts;
+	__le32 upsd_max_sptime;
+	__le32 upsd_max_apturn;
+	__le32 pspoll_max_apturn;
+	__le32 pspoll_utilization;
+	__le32 upsd_utilization;
+} __packed;
+
+struct wl12xx_acx_rxpipe_statistics {
+	__le32 rx_prep_beacon_drop;
+	__le32 descr_host_int_trig_rx_data;
+	__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;
+} __packed;
+
+struct wl12xx_acx_statistics {
+	struct acx_header header;
+
+	struct wl12xx_acx_tx_statistics tx;
+	struct wl12xx_acx_rx_statistics rx;
+	struct wl12xx_acx_dma_statistics dma;
+	struct wl12xx_acx_isr_statistics isr;
+	struct wl12xx_acx_wep_statistics wep;
+	struct wl12xx_acx_pwr_statistics pwr;
+	struct wl12xx_acx_aes_statistics aes;
+	struct wl12xx_acx_mic_statistics mic;
+	struct wl12xx_acx_event_statistics event;
+	struct wl12xx_acx_ps_statistics ps;
+	struct wl12xx_acx_rxpipe_statistics rxpipe;
+} __packed;
+
 int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
 
 #endif /* __WL12XX_ACX_H__ */
diff --git a/drivers/net/wireless/ti/wl12xx/cmd.c b/drivers/net/wireless/ti/wl12xx/cmd.c
index 8ffaeb5..30be784 100644
--- a/drivers/net/wireless/ti/wl12xx/cmd.c
+++ b/drivers/net/wireless/ti/wl12xx/cmd.c
@@ -65,6 +65,7 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
 	struct wl1271_general_parms_cmd *gen_parms;
 	struct wl1271_ini_general_params *gp =
 		&((struct wl1271_nvs_file *)wl->nvs)->general_params;
+	struct wl12xx_priv *priv = wl->priv;
 	bool answer = false;
 	int ret;
 
@@ -88,7 +89,7 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
 		answer = true;
 
 	/* Override the REF CLK from the NVS with the one from platform data */
-	gen_parms->general_params.ref_clock = wl->ref_clock;
+	gen_parms->general_params.ref_clock = priv->ref_clock;
 
 	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
 	if (ret < 0) {
@@ -118,6 +119,7 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
 	struct wl128x_general_parms_cmd *gen_parms;
 	struct wl128x_ini_general_params *gp =
 		&((struct wl128x_nvs_file *)wl->nvs)->general_params;
+	struct wl12xx_priv *priv = wl->priv;
 	bool answer = false;
 	int ret;
 
@@ -141,8 +143,8 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
 		answer = true;
 
 	/* Replace REF and TCXO CLKs with the ones from platform data */
-	gen_parms->general_params.ref_clock = wl->ref_clock;
-	gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
+	gen_parms->general_params.ref_clock = priv->ref_clock;
+	gen_parms->general_params.tcxo_ref_clock = priv->tcxo_clock;
 
 	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
 	if (ret < 0) {
@@ -172,7 +174,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
 	struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
 	struct wl1271_radio_parms_cmd *radio_parms;
 	struct wl1271_ini_general_params *gp = &nvs->general_params;
-	int ret;
+	int ret, fem_idx;
 
 	if (!wl->nvs)
 		return -ENODEV;
@@ -183,11 +185,13 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
 
 	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
 
+	fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer);
+
 	/* 2.4GHz parameters */
 	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
 	       sizeof(struct wl1271_ini_band_params_2));
 	memcpy(&radio_parms->dyn_params_2,
-	       &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
+	       &nvs->dyn_radio_params_2[fem_idx].params,
 	       sizeof(struct wl1271_ini_fem_params_2));
 
 	/* 5GHz parameters */
@@ -195,7 +199,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
 	       &nvs->stat_radio_params_5,
 	       sizeof(struct wl1271_ini_band_params_5));
 	memcpy(&radio_parms->dyn_params_5,
-	       &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
+	       &nvs->dyn_radio_params_5[fem_idx].params,
 	       sizeof(struct wl1271_ini_fem_params_5));
 
 	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
@@ -214,7 +218,7 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
 	struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
 	struct wl128x_radio_parms_cmd *radio_parms;
 	struct wl128x_ini_general_params *gp = &nvs->general_params;
-	int ret;
+	int ret, fem_idx;
 
 	if (!wl->nvs)
 		return -ENODEV;
@@ -225,11 +229,13 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
 
 	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
 
+	fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer);
+
 	/* 2.4GHz parameters */
 	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
 	       sizeof(struct wl128x_ini_band_params_2));
 	memcpy(&radio_parms->dyn_params_2,
-	       &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
+	       &nvs->dyn_radio_params_2[fem_idx].params,
 	       sizeof(struct wl128x_ini_fem_params_2));
 
 	/* 5GHz parameters */
@@ -237,7 +243,7 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
 	       &nvs->stat_radio_params_5,
 	       sizeof(struct wl128x_ini_band_params_5));
 	memcpy(&radio_parms->dyn_params_5,
-	       &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
+	       &nvs->dyn_radio_params_5[fem_idx].params,
 	       sizeof(struct wl128x_ini_fem_params_5));
 
 	radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
diff --git a/drivers/net/wireless/ti/wl12xx/debugfs.c b/drivers/net/wireless/ti/wl12xx/debugfs.c
new file mode 100644
index 0000000..0521cbf
--- /dev/null
+++ b/drivers/net/wireless/ti/wl12xx/debugfs.c
@@ -0,0 +1,243 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2011-2012 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have 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 "../wlcore/debugfs.h"
+#include "../wlcore/wlcore.h"
+
+#include "wl12xx.h"
+#include "acx.h"
+#include "debugfs.h"
+
+#define WL12XX_DEBUGFS_FWSTATS_FILE(a, b, c) \
+	DEBUGFS_FWSTATS_FILE(a, b, c, wl12xx_acx_statistics)
+
+WL12XX_DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, dropped, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, commands, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u");
+/* skipping wep.reserved */
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, packets, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u");
+/* skipping cont_miss_bcns_spread for now */
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, calibration, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, oom_late, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data,
+			    "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u");
+
+int wl12xx_debugfs_add_files(struct wl1271 *wl,
+			     struct dentry *rootdir)
+{
+	int ret = 0;
+	struct dentry *entry, *stats, *moddir;
+
+	moddir = debugfs_create_dir(KBUILD_MODNAME, rootdir);
+	if (!moddir || IS_ERR(moddir)) {
+		entry = moddir;
+		goto err;
+	}
+
+	stats = debugfs_create_dir("fw_stats", moddir);
+	if (!stats || IS_ERR(stats)) {
+		entry = stats;
+		goto err;
+	}
+
+	DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow);
+
+	DEBUGFS_FWSTATS_ADD(rx, out_of_mem);
+	DEBUGFS_FWSTATS_ADD(rx, hdr_overflow);
+	DEBUGFS_FWSTATS_ADD(rx, hw_stuck);
+	DEBUGFS_FWSTATS_ADD(rx, dropped);
+	DEBUGFS_FWSTATS_ADD(rx, fcs_err);
+	DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig);
+	DEBUGFS_FWSTATS_ADD(rx, path_reset);
+	DEBUGFS_FWSTATS_ADD(rx, reset_counter);
+
+	DEBUGFS_FWSTATS_ADD(dma, rx_requested);
+	DEBUGFS_FWSTATS_ADD(dma, rx_errors);
+	DEBUGFS_FWSTATS_ADD(dma, tx_requested);
+	DEBUGFS_FWSTATS_ADD(dma, tx_errors);
+
+	DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt);
+	DEBUGFS_FWSTATS_ADD(isr, fiqs);
+	DEBUGFS_FWSTATS_ADD(isr, rx_headers);
+	DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow);
+	DEBUGFS_FWSTATS_ADD(isr, rx_rdys);
+	DEBUGFS_FWSTATS_ADD(isr, irqs);
+	DEBUGFS_FWSTATS_ADD(isr, tx_procs);
+	DEBUGFS_FWSTATS_ADD(isr, decrypt_done);
+	DEBUGFS_FWSTATS_ADD(isr, dma0_done);
+	DEBUGFS_FWSTATS_ADD(isr, dma1_done);
+	DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete);
+	DEBUGFS_FWSTATS_ADD(isr, commands);
+	DEBUGFS_FWSTATS_ADD(isr, rx_procs);
+	DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes);
+	DEBUGFS_FWSTATS_ADD(isr, host_acknowledges);
+	DEBUGFS_FWSTATS_ADD(isr, pci_pm);
+	DEBUGFS_FWSTATS_ADD(isr, wakeups);
+	DEBUGFS_FWSTATS_ADD(isr, low_rssi);
+
+	DEBUGFS_FWSTATS_ADD(wep, addr_key_count);
+	DEBUGFS_FWSTATS_ADD(wep, default_key_count);
+	/* skipping wep.reserved */
+	DEBUGFS_FWSTATS_ADD(wep, key_not_found);
+	DEBUGFS_FWSTATS_ADD(wep, decrypt_fail);
+	DEBUGFS_FWSTATS_ADD(wep, packets);
+	DEBUGFS_FWSTATS_ADD(wep, interrupt);
+
+	DEBUGFS_FWSTATS_ADD(pwr, ps_enter);
+	DEBUGFS_FWSTATS_ADD(pwr, elp_enter);
+	DEBUGFS_FWSTATS_ADD(pwr, missing_bcns);
+	DEBUGFS_FWSTATS_ADD(pwr, wake_on_host);
+	DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp);
+	DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps);
+	DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps);
+	DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons);
+	DEBUGFS_FWSTATS_ADD(pwr, power_save_off);
+	DEBUGFS_FWSTATS_ADD(pwr, enable_ps);
+	DEBUGFS_FWSTATS_ADD(pwr, disable_ps);
+	DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps);
+	/* skipping cont_miss_bcns_spread for now */
+	DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons);
+
+	DEBUGFS_FWSTATS_ADD(mic, rx_pkts);
+	DEBUGFS_FWSTATS_ADD(mic, calc_failure);
+
+	DEBUGFS_FWSTATS_ADD(aes, encrypt_fail);
+	DEBUGFS_FWSTATS_ADD(aes, decrypt_fail);
+	DEBUGFS_FWSTATS_ADD(aes, encrypt_packets);
+	DEBUGFS_FWSTATS_ADD(aes, decrypt_packets);
+	DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt);
+	DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt);
+
+	DEBUGFS_FWSTATS_ADD(event, heart_beat);
+	DEBUGFS_FWSTATS_ADD(event, calibration);
+	DEBUGFS_FWSTATS_ADD(event, rx_mismatch);
+	DEBUGFS_FWSTATS_ADD(event, rx_mem_empty);
+	DEBUGFS_FWSTATS_ADD(event, rx_pool);
+	DEBUGFS_FWSTATS_ADD(event, oom_late);
+	DEBUGFS_FWSTATS_ADD(event, phy_transmit_error);
+	DEBUGFS_FWSTATS_ADD(event, tx_stuck);
+
+	DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts);
+	DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts);
+	DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime);
+	DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn);
+	DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn);
+	DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization);
+	DEBUGFS_FWSTATS_ADD(ps, upsd_utilization);
+
+	DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop);
+	DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data);
+	DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
+	DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
+	DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
+
+	return 0;
+
+err:
+	if (IS_ERR(entry))
+		ret = PTR_ERR(entry);
+	else
+		ret = -ENOMEM;
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ti/wl12xx/debugfs.h b/drivers/net/wireless/ti/wl12xx/debugfs.h
new file mode 100644
index 0000000..96898e2
--- /dev/null
+++ b/drivers/net/wireless/ti/wl12xx/debugfs.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have 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 __WL12XX_DEBUGFS_H__
+#define __WL12XX_DEBUGFS_H__
+
+int wl12xx_debugfs_add_files(struct wl1271 *wl,
+			     struct dentry *rootdir);
+
+#endif /* __WL12XX_DEBUGFS_H__ */
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index d7dd3de..0d2fdca 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -39,6 +39,10 @@
 #include "reg.h"
 #include "cmd.h"
 #include "acx.h"
+#include "debugfs.h"
+
+static char *fref_param;
+static char *tcxo_param;
 
 static struct wlcore_conf wl12xx_conf = {
 	.sg = {
@@ -212,7 +216,7 @@ static struct wlcore_conf wl12xx_conf = {
 		.suspend_wake_up_event       = CONF_WAKE_UP_EVENT_N_DTIM,
 		.suspend_listen_interval     = 3,
 		.bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,
-		.bcn_filt_ie_count           = 2,
+		.bcn_filt_ie_count           = 3,
 		.bcn_filt_ie = {
 			[0] = {
 				.ie          = WLAN_EID_CHANNEL_SWITCH,
@@ -222,9 +226,13 @@ static struct wlcore_conf wl12xx_conf = {
 				.ie          = WLAN_EID_HT_OPERATION,
 				.rule        = CONF_BCN_RULE_PASS_ON_CHANGE,
 			},
+			[2] = {
+				.ie	     = WLAN_EID_ERP_INFO,
+				.rule	     = CONF_BCN_RULE_PASS_ON_CHANGE,
+			},
 		},
-		.synch_fail_thold            = 10,
-		.bss_lose_timeout            = 100,
+		.synch_fail_thold            = 12,
+		.bss_lose_timeout            = 400,
 		.beacon_rx_timeout           = 10000,
 		.broadcast_timeout           = 20000,
 		.rx_broadcast_in_ps          = 1,
@@ -234,10 +242,11 @@ static struct wlcore_conf wl12xx_conf = {
 		.psm_entry_retries           = 8,
 		.psm_exit_retries            = 16,
 		.psm_entry_nullfunc_retries  = 3,
-		.dynamic_ps_timeout          = 40,
+		.dynamic_ps_timeout          = 200,
 		.forced_ps                   = false,
 		.keep_alive_interval         = 55000,
 		.max_listen_interval         = 20,
+		.sta_sleep_auth              = WL1271_PSM_ILLEGAL,
 	},
 	.itrim = {
 		.enable = false,
@@ -245,7 +254,7 @@ static struct wlcore_conf wl12xx_conf = {
 	},
 	.pm_config = {
 		.host_clk_settling_time = 5000,
-		.host_fast_wakeup_support = false
+		.host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE,
 	},
 	.roam_trigger = {
 		.trigger_pacing               = 1,
@@ -305,8 +314,8 @@ static struct wlcore_conf wl12xx_conf = {
 		.swallow_period               = 5,
 		.n_divider_fref_set_1         = 0xff,       /* default */
 		.n_divider_fref_set_2         = 12,
-		.m_divider_fref_set_1         = 148,
-		.m_divider_fref_set_2         = 0xffff,     /* default */
+		.m_divider_fref_set_1         = 0xffff,
+		.m_divider_fref_set_2         = 148,	    /* default */
 		.coex_pll_stabilization_time  = 0xffffffff, /* default */
 		.ldo_stabilization_time       = 0xffff,     /* default */
 		.fm_disturbed_band_margin     = 0xff,       /* default */
@@ -593,7 +602,7 @@ static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
 {
 	if (wl->chip.id != CHIP_ID_1283_PG20) {
 		struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
-		struct wl1271_rx_mem_pool_addr rx_mem_addr;
+		struct wl127x_rx_mem_pool_addr rx_mem_addr;
 
 		/*
 		 * Choose the block we want to read
@@ -621,10 +630,8 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
 		wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
 			       wl->chip.id);
 
-		/* clear the alignment quirk, since we don't support it */
-		wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
-
-		wl->quirks |= WLCORE_QUIRK_LEGACY_NVS;
+		wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
+			      WLCORE_QUIRK_TKIP_HEADER_SPACE;
 		wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
 		wl->mr_fw_name = WL127X_FW_NAME_MULTI;
 		memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x,
@@ -639,10 +646,8 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
 		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
 			     wl->chip.id);
 
-		/* clear the alignment quirk, since we don't support it */
-		wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
-
-		wl->quirks |= WLCORE_QUIRK_LEGACY_NVS;
+		wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
+			      WLCORE_QUIRK_TKIP_HEADER_SPACE;
 		wl->plt_fw_name = WL127X_PLT_FW_NAME;
 		wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
 		wl->mr_fw_name = WL127X_FW_NAME_MULTI;
@@ -660,6 +665,11 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
 		wl->plt_fw_name = WL128X_PLT_FW_NAME;
 		wl->sr_fw_name = WL128X_FW_NAME_SINGLE;
 		wl->mr_fw_name = WL128X_FW_NAME_MULTI;
+
+		/* wl128x requires TX blocksize alignment */
+		wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
+			      WLCORE_QUIRK_TKIP_HEADER_SPACE;
+
 		break;
 	case CHIP_ID_1283_PG10:
 	default:
@@ -773,6 +783,7 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
 	u16 spare_reg;
 	u16 pll_config;
 	u8 input_freq;
+	struct wl12xx_priv *priv = wl->priv;
 
 	/* Mask bits [3:1] in the sys_clk_cfg register */
 	spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG);
@@ -782,8 +793,8 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
 	wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
 
 	/* Handle special cases of the TCXO clock */
-	if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
-	    wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
+	if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
+	    priv->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
 		return wl128x_manually_configure_mcs_pll(wl);
 
 	/* Set the input frequency according to the selected clock source */
@@ -808,11 +819,12 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
  */
 static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
 {
+	struct wl12xx_priv *priv = wl->priv;
 	u16 sys_clk_cfg;
 
 	/* For XTAL-only modes, FREF will be used after switching from TCXO */
-	if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
-	    wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
+	if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
+	    priv->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
 		if (!wl128x_switch_tcxo_to_fref(wl))
 			return -EINVAL;
 		goto fref_clk;
@@ -826,8 +838,8 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
 		goto fref_clk;
 
 	/* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */
-	if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
-	    wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
+	if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
+	    priv->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
 		if (!wl128x_switch_tcxo_to_fref(wl))
 			return -EINVAL;
 		goto fref_clk;
@@ -836,14 +848,14 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
 	/* TCXO clock is selected */
 	if (!wl128x_is_tcxo_valid(wl))
 		return -EINVAL;
-	*selected_clock = wl->tcxo_clock;
+	*selected_clock = priv->tcxo_clock;
 	goto config_mcs_pll;
 
 fref_clk:
 	/* FREF clock is selected */
 	if (!wl128x_is_fref_valid(wl))
 		return -EINVAL;
-	*selected_clock = wl->ref_clock;
+	*selected_clock = priv->ref_clock;
 
 config_mcs_pll:
 	return wl128x_configure_mcs_pll(wl, *selected_clock);
@@ -851,25 +863,27 @@ config_mcs_pll:
 
 static int wl127x_boot_clk(struct wl1271 *wl)
 {
+	struct wl12xx_priv *priv = wl->priv;
 	u32 pause;
 	u32 clk;
 
 	if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
 		wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION;
 
-	if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
-	    wl->ref_clock == CONF_REF_CLK_38_4_E ||
-	    wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
+	if (priv->ref_clock == CONF_REF_CLK_19_2_E ||
+	    priv->ref_clock == CONF_REF_CLK_38_4_E ||
+	    priv->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
 		/* ref clk: 19.2/38.4/38.4-XTAL */
 		clk = 0x3;
-	else if (wl->ref_clock == CONF_REF_CLK_26_E ||
-		 wl->ref_clock == CONF_REF_CLK_52_E)
+	else if (priv->ref_clock == CONF_REF_CLK_26_E ||
+		 priv->ref_clock == CONF_REF_CLK_26_M_XTAL ||
+		 priv->ref_clock == CONF_REF_CLK_52_E)
 		/* ref clk: 26/52 */
 		clk = 0x5;
 	else
 		return -EINVAL;
 
-	if (wl->ref_clock != CONF_REF_CLK_19_2_E) {
+	if (priv->ref_clock != CONF_REF_CLK_19_2_E) {
 		u16 val;
 		/* Set clock type (open drain) */
 		val = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE);
@@ -939,6 +953,7 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
 
 static int wl12xx_pre_boot(struct wl1271 *wl)
 {
+	struct wl12xx_priv *priv = wl->priv;
 	int ret = 0;
 	u32 clk;
 	int selected_clock = -1;
@@ -970,7 +985,7 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
 	if (wl->chip.id == CHIP_ID_1283_PG20)
 		clk |= ((selected_clock & 0x3) << 1) << 4;
 	else
-		clk |= (wl->ref_clock << 1) << 4;
+		clk |= (priv->ref_clock << 1) << 4;
 
 	wl1271_write32(wl, WL12XX_DRPW_SCRATCH_START, clk);
 
@@ -989,7 +1004,7 @@ out:
 
 static void wl12xx_pre_upload(struct wl1271 *wl)
 {
-	u32 tmp;
+	u32 tmp, polarity;
 
 	/* write firmware's last address (ie. it's length) to
 	 * ACX_EEPROMLESS_IND_REG */
@@ -1009,23 +1024,23 @@ static void wl12xx_pre_upload(struct wl1271 *wl)
 
 	if (wl->chip.id == CHIP_ID_1283_PG20)
 		wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);
-}
-
-static void wl12xx_enable_interrupts(struct wl1271 *wl)
-{
-	u32 polarity;
 
+	/* polarity must be set before the firmware is loaded */
 	polarity = wl12xx_top_reg_read(wl, OCP_REG_POLARITY);
 
 	/* We use HIGH polarity, so unset the LOW bit */
 	polarity &= ~POLARITY_LOW;
 	wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity);
 
-	wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR);
+}
+
+static void wl12xx_enable_interrupts(struct wl1271 *wl)
+{
+	wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL12XX_ACX_ALL_EVENTS_VECTOR);
 
 	wlcore_enable_interrupts(wl);
 	wlcore_write_reg(wl, REG_INTERRUPT_MASK,
-			 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
+			 WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK));
 
 	wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL);
 }
@@ -1149,7 +1164,8 @@ static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
 
 static void wl12xx_tx_delayed_compl(struct wl1271 *wl)
 {
-	if (wl->fw_status->tx_results_counter == (wl->tx_results_count & 0xff))
+	if (wl->fw_status_1->tx_results_counter ==
+	    (wl->tx_results_count & 0xff))
 		return;
 
 	wl1271_tx_complete(wl);
@@ -1288,10 +1304,90 @@ static void wl12xx_get_mac(struct wl1271 *wl)
 		wl12xx_get_fuse_mac(wl);
 }
 
+static void wl12xx_set_tx_desc_csum(struct wl1271 *wl,
+				    struct wl1271_tx_hw_descr *desc,
+				    struct sk_buff *skb)
+{
+	desc->wl12xx_reserved = 0;
+}
+
+static int wl12xx_plt_init(struct wl1271 *wl)
+{
+	int ret;
+
+	ret = wl->ops->boot(wl);
+	if (ret < 0)
+		goto out;
+
+	ret = wl->ops->hw_init(wl);
+	if (ret < 0)
+		goto out_irq_disable;
+
+	ret = wl1271_acx_init_mem_config(wl);
+	if (ret < 0)
+		goto out_irq_disable;
+
+	ret = wl12xx_acx_mem_cfg(wl);
+	if (ret < 0)
+		goto out_free_memmap;
+
+	/* Enable data path */
+	ret = wl1271_cmd_data_path(wl, 1);
+	if (ret < 0)
+		goto out_free_memmap;
+
+	/* Configure for CAM power saving (ie. always active) */
+	ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+	if (ret < 0)
+		goto out_free_memmap;
+
+	/* configure PM */
+	ret = wl1271_acx_pm_config(wl);
+	if (ret < 0)
+		goto out_free_memmap;
+
+	goto out;
+
+out_free_memmap:
+	kfree(wl->target_mem_map);
+	wl->target_mem_map = NULL;
+
+out_irq_disable:
+	mutex_unlock(&wl->mutex);
+	/* Unlocking the mutex in the middle of handling is
+	   inherently unsafe. In this case we deem it safe to do,
+	   because we need to let any possibly pending IRQ out of
+	   the system (and while we are WL1271_STATE_OFF the IRQ
+	   work function will not do anything.) Also, any other
+	   possible concurrent operations will fail due to the
+	   current state, hence the wl1271 struct should be safe. */
+	wlcore_disable_interrupts(wl);
+	mutex_lock(&wl->mutex);
+out:
+	return ret;
+}
+
+static int wl12xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
+{
+	if (is_gem)
+		return WL12XX_TX_HW_BLOCK_GEM_SPARE;
+
+	return WL12XX_TX_HW_BLOCK_SPARE_DEFAULT;
+}
+
+static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
+			  struct ieee80211_vif *vif,
+			  struct ieee80211_sta *sta,
+			  struct ieee80211_key_conf *key_conf)
+{
+	return wlcore_set_key(wl, cmd, vif, sta, key_conf);
+}
+
 static struct wlcore_ops wl12xx_ops = {
 	.identify_chip		= wl12xx_identify_chip,
 	.identify_fw		= wl12xx_identify_fw,
 	.boot			= wl12xx_boot,
+	.plt_init		= wl12xx_plt_init,
 	.trigger_cmd		= wl12xx_trigger_cmd,
 	.ack_event		= wl12xx_ack_event,
 	.calc_tx_blocks		= wl12xx_calc_tx_blocks,
@@ -1306,6 +1402,13 @@ static struct wlcore_ops wl12xx_ops = {
 	.sta_get_ap_rate_mask	= wl12xx_sta_get_ap_rate_mask,
 	.get_pg_ver		= wl12xx_get_pg_ver,
 	.get_mac		= wl12xx_get_mac,
+	.set_tx_desc_csum	= wl12xx_set_tx_desc_csum,
+	.set_rx_csum		= NULL,
+	.ap_get_mimo_wide_rate_mask = NULL,
+	.debugfs_init		= wl12xx_debugfs_add_files,
+	.get_spare_blocks	= wl12xx_get_spare_blocks,
+	.set_key		= wl12xx_set_key,
+	.pre_pkt_send		= NULL,
 };
 
 static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
@@ -1323,6 +1426,7 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
 
 static int __devinit wl12xx_probe(struct platform_device *pdev)
 {
+	struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
 	struct wl1271 *wl;
 	struct ieee80211_hw *hw;
 	struct wl12xx_priv *priv;
@@ -1334,19 +1438,63 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
 	}
 
 	wl = hw->priv;
+	priv = wl->priv;
 	wl->ops = &wl12xx_ops;
 	wl->ptable = wl12xx_ptable;
 	wl->rtable = wl12xx_rtable;
 	wl->num_tx_desc = 16;
-	wl->normal_tx_spare = WL12XX_TX_HW_BLOCK_SPARE_DEFAULT;
-	wl->gem_tx_spare = WL12XX_TX_HW_BLOCK_GEM_SPARE;
+	wl->num_rx_desc = 8;
 	wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
 	wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
 	wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0;
 	wl->fw_status_priv_len = 0;
-	memcpy(&wl->ht_cap, &wl12xx_ht_cap, sizeof(wl12xx_ht_cap));
+	wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
+	wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl12xx_ht_cap);
+	wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl12xx_ht_cap);
 	wl12xx_conf_init(wl);
 
+	if (!fref_param) {
+		priv->ref_clock = pdata->board_ref_clock;
+	} else {
+		if (!strcmp(fref_param, "19.2"))
+			priv->ref_clock = WL12XX_REFCLOCK_19;
+		else if (!strcmp(fref_param, "26"))
+			priv->ref_clock = WL12XX_REFCLOCK_26;
+		else if (!strcmp(fref_param, "26x"))
+			priv->ref_clock = WL12XX_REFCLOCK_26_XTAL;
+		else if (!strcmp(fref_param, "38.4"))
+			priv->ref_clock = WL12XX_REFCLOCK_38;
+		else if (!strcmp(fref_param, "38.4x"))
+			priv->ref_clock = WL12XX_REFCLOCK_38_XTAL;
+		else if (!strcmp(fref_param, "52"))
+			priv->ref_clock = WL12XX_REFCLOCK_52;
+		else
+			wl1271_error("Invalid fref parameter %s", fref_param);
+	}
+
+	if (!tcxo_param) {
+		priv->tcxo_clock = pdata->board_tcxo_clock;
+	} else {
+		if (!strcmp(tcxo_param, "19.2"))
+			priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2;
+		else if (!strcmp(tcxo_param, "26"))
+			priv->tcxo_clock = WL12XX_TCXOCLOCK_26;
+		else if (!strcmp(tcxo_param, "38.4"))
+			priv->tcxo_clock = WL12XX_TCXOCLOCK_38_4;
+		else if (!strcmp(tcxo_param, "52"))
+			priv->tcxo_clock = WL12XX_TCXOCLOCK_52;
+		else if (!strcmp(tcxo_param, "16.368"))
+			priv->tcxo_clock = WL12XX_TCXOCLOCK_16_368;
+		else if (!strcmp(tcxo_param, "32.736"))
+			priv->tcxo_clock = WL12XX_TCXOCLOCK_32_736;
+		else if (!strcmp(tcxo_param, "16.8"))
+			priv->tcxo_clock = WL12XX_TCXOCLOCK_16_8;
+		else if (!strcmp(tcxo_param, "33.6"))
+			priv->tcxo_clock = WL12XX_TCXOCLOCK_33_6;
+		else
+			wl1271_error("Invalid tcxo parameter %s", tcxo_param);
+	}
+
 	return wlcore_probe(wl, pdev);
 }
 
@@ -1378,6 +1526,13 @@ static void __exit wl12xx_exit(void)
 }
 module_exit(wl12xx_exit);
 
+module_param_named(fref, fref_param, charp, 0);
+MODULE_PARM_DESC(fref, "FREF clock: 19.2, 26, 26x, 38.4, 38.4x, 52");
+
+module_param_named(tcxo, tcxo_param, charp, 0);
+MODULE_PARM_DESC(tcxo,
+		 "TCXO clock: 19.2, 26, 38.4, 52, 16.368, 32.736, 16.8, 33.6");
+
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h
index 74cd332..de11324 100644
--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
@@ -24,8 +24,16 @@
 
 #include "conf.h"
 
+struct wl127x_rx_mem_pool_addr {
+	u32 addr;
+	u32 addr_extra;
+};
+
 struct wl12xx_priv {
 	struct wl12xx_priv_conf conf;
+
+	int ref_clock;
+	int tcxo_clock;
 };
 
 #endif /* __WL12XX_PRIV_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/Kconfig b/drivers/net/wireless/ti/wl18xx/Kconfig
new file mode 100644
index 0000000..1cfdb25
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/Kconfig
@@ -0,0 +1,7 @@
+config WL18XX
+	tristate "TI wl18xx support"
+	depends on MAC80211
+	select WLCORE
+	---help---
+	  This module adds support for wireless adapters based on TI
+	  WiLink 8 chipsets.
diff --git a/drivers/net/wireless/ti/wl18xx/Makefile b/drivers/net/wireless/ti/wl18xx/Makefile
new file mode 100644
index 0000000..67c0987
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/Makefile
@@ -0,0 +1,3 @@
+wl18xx-objs	= main.o acx.o tx.o io.o debugfs.o
+
+obj-$(CONFIG_WL18XX)		+= wl18xx.o
diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
new file mode 100644
index 0000000..72840e2
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/acx.c
@@ -0,0 +1,111 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "../wlcore/cmd.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/acx.h"
+
+#include "acx.h"
+
+int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
+				  u32 sdio_blk_size, u32 extra_mem_blks,
+				  u32 len_field_size)
+{
+	struct wl18xx_acx_host_config_bitmap *bitmap_conf;
+	int ret;
+
+	wl1271_debug(DEBUG_ACX, "acx cfg bitmap %d blk %d spare %d field %d",
+		     host_cfg_bitmap, sdio_blk_size, extra_mem_blks,
+		     len_field_size);
+
+	bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
+	if (!bitmap_conf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
+	bitmap_conf->host_sdio_block_size = cpu_to_le32(sdio_blk_size);
+	bitmap_conf->extra_mem_blocks = cpu_to_le32(extra_mem_blks);
+	bitmap_conf->length_field_size = cpu_to_le32(len_field_size);
+
+	ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
+				   bitmap_conf, sizeof(*bitmap_conf));
+	if (ret < 0) {
+		wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(bitmap_conf);
+
+	return ret;
+}
+
+int wl18xx_acx_set_checksum_state(struct wl1271 *wl)
+{
+	struct wl18xx_acx_checksum_state *acx;
+	int ret;
+
+	wl1271_debug(DEBUG_ACX, "acx checksum state");
+
+	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+	if (!acx) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED;
+
+	ret = wl1271_cmd_configure(wl, ACX_CHECKSUM_CONFIG, acx, sizeof(*acx));
+	if (ret < 0) {
+		wl1271_warning("failed to set Tx checksum state: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(acx);
+	return ret;
+}
+
+int wl18xx_acx_clear_statistics(struct wl1271 *wl)
+{
+	struct wl18xx_acx_clear_statistics *acx;
+	int ret = 0;
+
+	wl1271_debug(DEBUG_ACX, "acx clear statistics");
+
+	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+	if (!acx) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = wl1271_cmd_configure(wl, ACX_CLEAR_STATISTICS, acx, sizeof(*acx));
+	if (ret < 0) {
+		wl1271_warning("failed to clear firmware statistics: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(acx);
+	return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
new file mode 100644
index 0000000..ebbaf61
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/acx.h
@@ -0,0 +1,291 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have 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 __WL18XX_ACX_H__
+#define __WL18XX_ACX_H__
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/acx.h"
+
+enum {
+	ACX_CLEAR_STATISTICS		 = 0x0047,
+};
+
+/* numbers of bits the length field takes (add 1 for the actual number) */
+#define WL18XX_HOST_IF_LEN_SIZE_FIELD 15
+
+#define WL18XX_ACX_EVENTS_VECTOR_PG1	(WL1271_ACX_INTR_WATCHDOG      | \
+					WL1271_ACX_INTR_INIT_COMPLETE | \
+					WL1271_ACX_INTR_EVENT_A       | \
+					WL1271_ACX_INTR_EVENT_B       | \
+					WL1271_ACX_INTR_CMD_COMPLETE  | \
+					WL1271_ACX_INTR_HW_AVAILABLE  | \
+					WL1271_ACX_INTR_DATA)
+
+#define WL18XX_ACX_EVENTS_VECTOR_PG2	(WL18XX_ACX_EVENTS_VECTOR_PG1 | \
+					WL1271_ACX_SW_INTR_WATCHDOG)
+
+#define WL18XX_INTR_MASK_PG1		(WL1271_ACX_INTR_WATCHDOG      | \
+					WL1271_ACX_INTR_EVENT_A       | \
+					WL1271_ACX_INTR_EVENT_B       | \
+					WL1271_ACX_INTR_HW_AVAILABLE  | \
+					WL1271_ACX_INTR_DATA)
+
+#define WL18XX_INTR_MASK_PG2		(WL18XX_INTR_MASK_PG1         | \
+					WL1271_ACX_SW_INTR_WATCHDOG)
+
+struct wl18xx_acx_host_config_bitmap {
+	struct acx_header header;
+
+	__le32 host_cfg_bitmap;
+
+	__le32 host_sdio_block_size;
+
+	/* extra mem blocks per frame in TX. */
+	__le32 extra_mem_blocks;
+
+	/*
+	 * number of bits of the length field in the first TX word
+	 * (up to 15 - for using the entire 16 bits).
+	 */
+	__le32 length_field_size;
+
+} __packed;
+
+enum {
+	CHECKSUM_OFFLOAD_DISABLED = 0,
+	CHECKSUM_OFFLOAD_ENABLED  = 1,
+	CHECKSUM_OFFLOAD_FAKE_RX  = 2,
+	CHECKSUM_OFFLOAD_INVALID  = 0xFF
+};
+
+struct wl18xx_acx_checksum_state {
+	struct acx_header header;
+
+	 /* enum acx_checksum_state */
+	u8 checksum_state;
+	u8 pad[3];
+} __packed;
+
+
+struct wl18xx_acx_error_stats {
+	u32 error_frame;
+	u32 error_null_Frame_tx_start;
+	u32 error_numll_frame_cts_start;
+	u32 error_bar_retry;
+	u32 error_frame_cts_nul_flid;
+} __packed;
+
+struct wl18xx_acx_debug_stats {
+	u32 debug1;
+	u32 debug2;
+	u32 debug3;
+	u32 debug4;
+	u32 debug5;
+	u32 debug6;
+} __packed;
+
+struct wl18xx_acx_ring_stats {
+	u32 prepared_descs;
+	u32 tx_cmplt;
+} __packed;
+
+struct wl18xx_acx_tx_stats {
+	u32 tx_prepared_descs;
+	u32 tx_cmplt;
+	u32 tx_template_prepared;
+	u32 tx_data_prepared;
+	u32 tx_template_programmed;
+	u32 tx_data_programmed;
+	u32 tx_burst_programmed;
+	u32 tx_starts;
+	u32 tx_imm_resp;
+	u32 tx_start_templates;
+	u32 tx_start_int_templates;
+	u32 tx_start_fw_gen;
+	u32 tx_start_data;
+	u32 tx_start_null_frame;
+	u32 tx_exch;
+	u32 tx_retry_template;
+	u32 tx_retry_data;
+	u32 tx_exch_pending;
+	u32 tx_exch_expiry;
+	u32 tx_done_template;
+	u32 tx_done_data;
+	u32 tx_done_int_template;
+	u32 tx_frame_checksum;
+	u32 tx_checksum_result;
+	u32 frag_called;
+	u32 frag_mpdu_alloc_failed;
+	u32 frag_init_called;
+	u32 frag_in_process_called;
+	u32 frag_tkip_called;
+	u32 frag_key_not_found;
+	u32 frag_need_fragmentation;
+	u32 frag_bad_mblk_num;
+	u32 frag_failed;
+	u32 frag_cache_hit;
+	u32 frag_cache_miss;
+} __packed;
+
+struct wl18xx_acx_rx_stats {
+	u32 rx_beacon_early_term;
+	u32 rx_out_of_mpdu_nodes;
+	u32 rx_hdr_overflow;
+	u32 rx_dropped_frame;
+	u32 rx_done_stage;
+	u32 rx_done;
+	u32 rx_defrag;
+	u32 rx_defrag_end;
+	u32 rx_cmplt;
+	u32 rx_pre_complt;
+	u32 rx_cmplt_task;
+	u32 rx_phy_hdr;
+	u32 rx_timeout;
+	u32 rx_timeout_wa;
+	u32 rx_wa_density_dropped_frame;
+	u32 rx_wa_ba_not_expected;
+	u32 rx_frame_checksum;
+	u32 rx_checksum_result;
+	u32 defrag_called;
+	u32 defrag_init_called;
+	u32 defrag_in_process_called;
+	u32 defrag_tkip_called;
+	u32 defrag_need_defrag;
+	u32 defrag_decrypt_failed;
+	u32 decrypt_key_not_found;
+	u32 defrag_need_decrypt;
+	u32 rx_tkip_replays;
+} __packed;
+
+struct wl18xx_acx_isr_stats {
+	u32 irqs;
+} __packed;
+
+#define PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD 10
+
+struct wl18xx_acx_pwr_stats {
+	u32 missing_bcns_cnt;
+	u32 rcvd_bcns_cnt;
+	u32 connection_out_of_sync;
+	u32 cont_miss_bcns_spread[PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD];
+	u32 rcvd_awake_bcns_cnt;
+} __packed;
+
+struct wl18xx_acx_event_stats {
+	u32 calibration;
+	u32 rx_mismatch;
+	u32 rx_mem_empty;
+} __packed;
+
+struct wl18xx_acx_ps_poll_stats {
+	u32 ps_poll_timeouts;
+	u32 upsd_timeouts;
+	u32 upsd_max_ap_turn;
+	u32 ps_poll_max_ap_turn;
+	u32 ps_poll_utilization;
+	u32 upsd_utilization;
+} __packed;
+
+struct wl18xx_acx_rx_filter_stats {
+	u32 beacon_filter;
+	u32 arp_filter;
+	u32 mc_filter;
+	u32 dup_filter;
+	u32 data_filter;
+	u32 ibss_filter;
+	u32 protection_filter;
+	u32 accum_arp_pend_requests;
+	u32 max_arp_queue_dep;
+} __packed;
+
+struct wl18xx_acx_rx_rate_stats {
+	u32 rx_frames_per_rates[50];
+} __packed;
+
+#define AGGR_STATS_TX_AGG	16
+#define AGGR_STATS_TX_RATE	16
+#define AGGR_STATS_RX_SIZE_LEN	16
+
+struct wl18xx_acx_aggr_stats {
+	u32 tx_agg_vs_rate[AGGR_STATS_TX_AGG * AGGR_STATS_TX_RATE];
+	u32 rx_size[AGGR_STATS_RX_SIZE_LEN];
+} __packed;
+
+#define PIPE_STATS_HW_FIFO	11
+
+struct wl18xx_acx_pipeline_stats {
+	u32 hs_tx_stat_fifo_int;
+	u32 hs_rx_stat_fifo_int;
+	u32 tcp_tx_stat_fifo_int;
+	u32 tcp_rx_stat_fifo_int;
+	u32 enc_tx_stat_fifo_int;
+	u32 enc_rx_stat_fifo_int;
+	u32 rx_complete_stat_fifo_int;
+	u32 pre_proc_swi;
+	u32 post_proc_swi;
+	u32 sec_frag_swi;
+	u32 pre_to_defrag_swi;
+	u32 defrag_to_csum_swi;
+	u32 csum_to_rx_xfer_swi;
+	u32 dec_packet_in;
+	u32 dec_packet_in_fifo_full;
+	u32 dec_packet_out;
+	u32 cs_rx_packet_in;
+	u32 cs_rx_packet_out;
+	u16 pipeline_fifo_full[PIPE_STATS_HW_FIFO];
+} __packed;
+
+struct wl18xx_acx_mem_stats {
+	u32 rx_free_mem_blks;
+	u32 tx_free_mem_blks;
+	u32 fwlog_free_mem_blks;
+	u32 fw_gen_free_mem_blks;
+} __packed;
+
+struct wl18xx_acx_statistics {
+	struct acx_header header;
+
+	struct wl18xx_acx_error_stats		error;
+	struct wl18xx_acx_debug_stats		debug;
+	struct wl18xx_acx_tx_stats		tx;
+	struct wl18xx_acx_rx_stats		rx;
+	struct wl18xx_acx_isr_stats		isr;
+	struct wl18xx_acx_pwr_stats		pwr;
+	struct wl18xx_acx_ps_poll_stats		ps_poll;
+	struct wl18xx_acx_rx_filter_stats	rx_filter;
+	struct wl18xx_acx_rx_rate_stats		rx_rate;
+	struct wl18xx_acx_aggr_stats		aggr_size;
+	struct wl18xx_acx_pipeline_stats	pipeline;
+	struct wl18xx_acx_mem_stats		mem;
+} __packed;
+
+struct wl18xx_acx_clear_statistics {
+	struct acx_header header;
+};
+
+int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
+				  u32 sdio_blk_size, u32 extra_mem_blks,
+				  u32 len_field_size);
+int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
+int wl18xx_acx_clear_statistics(struct wl1271 *wl);
+
+#endif /* __WL18XX_ACX_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h
new file mode 100644
index 0000000..fac0b7e
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/conf.h
@@ -0,0 +1,92 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL18XX_CONF_H__
+#define __WL18XX_CONF_H__
+
+#define WL18XX_CONF_MAGIC	0x10e100ca
+#define WL18XX_CONF_VERSION	(WLCORE_CONF_VERSION | 0x0002)
+#define WL18XX_CONF_MASK	0x0000ffff
+#define WL18XX_CONF_SIZE	(WLCORE_CONF_SIZE + \
+				 sizeof(struct wl18xx_priv_conf))
+
+#define NUM_OF_CHANNELS_11_ABG 150
+#define NUM_OF_CHANNELS_11_P 7
+#define WL18XX_NUM_OF_SUB_BANDS 9
+#define SRF_TABLE_LEN 16
+#define PIN_MUXING_SIZE 2
+
+struct wl18xx_mac_and_phy_params {
+	u8 phy_standalone;
+	u8 rdl;
+	u8 enable_clpc;
+	u8 enable_tx_low_pwr_on_siso_rdl;
+	u8 auto_detect;
+	u8 dedicated_fem;
+
+	u8 low_band_component;
+
+	/* Bit 0: One Hot, Bit 1: Control Enable, Bit 2: 1.8V, Bit 3: 3V */
+	u8 low_band_component_type;
+
+	u8 high_band_component;
+
+	/* Bit 0: One Hot, Bit 1: Control Enable, Bit 2: 1.8V, Bit 3: 3V */
+	u8 high_band_component_type;
+	u8 number_of_assembled_ant2_4;
+	u8 number_of_assembled_ant5;
+	u8 pin_muxing_platform_options[PIN_MUXING_SIZE];
+	u8 external_pa_dc2dc;
+	u8 tcxo_ldo_voltage;
+	u8 xtal_itrim_val;
+	u8 srf_state;
+	u8 srf1[SRF_TABLE_LEN];
+	u8 srf2[SRF_TABLE_LEN];
+	u8 srf3[SRF_TABLE_LEN];
+	u8 io_configuration;
+	u8 sdio_configuration;
+	u8 settings;
+	u8 rx_profile;
+	u8 per_chan_pwr_limit_arr_11abg[NUM_OF_CHANNELS_11_ABG];
+	u8 pwr_limit_reference_11_abg;
+	u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P];
+	u8 pwr_limit_reference_11p;
+	u8 per_sub_band_tx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
+	u8 per_sub_band_rx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
+	u8 primary_clock_setting_time;
+	u8 clock_valid_on_wake_up;
+	u8 secondary_clock_setting_time;
+	u8 board_type;
+	/* enable point saturation */
+	u8 psat;
+	/* low/medium/high Tx power in dBm */
+	s8 low_power_val;
+	s8 med_power_val;
+	s8 high_power_val;
+	u8 padding[1];
+} __packed;
+
+struct wl18xx_priv_conf {
+	/* this structure is copied wholesale to FW */
+	struct wl18xx_mac_and_phy_params phy;
+} __packed;
+
+#endif /* __WL18XX_CONF_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c
new file mode 100644
index 0000000..3ce6f10
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/debugfs.c
@@ -0,0 +1,403 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2011-2012 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have 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 "../wlcore/debugfs.h"
+#include "../wlcore/wlcore.h"
+
+#include "wl18xx.h"
+#include "acx.h"
+#include "debugfs.h"
+
+#define WL18XX_DEBUGFS_FWSTATS_FILE(a, b, c) \
+	DEBUGFS_FWSTATS_FILE(a, b, c, wl18xx_acx_statistics)
+#define WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(a, b, c) \
+	DEBUGFS_FWSTATS_FILE_ARRAY(a, b, c, wl18xx_acx_statistics)
+
+
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug1, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug2, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug3, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug4, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug5, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug6, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(error, error_null_Frame_tx_start, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(error, error_numll_frame_cts_start, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(error, error_bar_retry, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_cts_nul_flid, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_prepared_descs, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_cmplt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_template_prepared, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_data_prepared, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_template_programmed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_data_programmed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_burst_programmed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_starts, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_imm_resp, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_templates, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_int_templates, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_fw_gen, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_data, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_null_frame, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_template, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_data, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_pending, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_expiry, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_template, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_data, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_int_template, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_frame_checksum, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_checksum_result, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_mpdu_alloc_failed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_init_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_in_process_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_tkip_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_key_not_found, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_need_fragmentation, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_bad_mblk_num, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_failed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_cache_hit, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_cache_miss, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_beacon_early_term, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_out_of_mpdu_nodes, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_hdr_overflow, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_dropped_frame, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_done, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_defrag, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_defrag_end, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_cmplt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_pre_complt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_cmplt_task, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_phy_hdr, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout_wa, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_density_dropped_frame, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_ba_not_expected, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_frame_checksum, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_checksum_result, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_init_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_in_process_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_tkip_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_need_defrag, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_decrypt_failed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, decrypt_key_not_found, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_need_decrypt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_tkip_replays, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(pwr, missing_bcns_cnt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_bcns_cnt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pwr, connection_out_of_sync, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pwr, cont_miss_bcns_spread,
+				  PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD);
+WL18XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_bcns_cnt, "%u");
+
+
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_timeouts, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_timeouts, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_max_ap_turn, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_max_ap_turn, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_utilization, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_utilization, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, beacon_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, arp_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, mc_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, dup_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, data_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, ibss_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, protection_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, accum_arp_pend_requests, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, max_arp_queue_dep, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_rate, rx_frames_per_rates, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_vs_rate,
+				  AGGR_STATS_TX_AGG*AGGR_STATS_TX_RATE);
+WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, rx_size,
+				  AGGR_STATS_RX_SIZE_LEN);
+
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, hs_tx_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_tx_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_rx_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_tx_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_rx_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, rx_complete_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_proc_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, post_proc_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, sec_frag_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_to_defrag_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, defrag_to_csum_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, csum_to_rx_xfer_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in_fifo_full, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_out, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_in, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_out, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pipeline, pipeline_fifo_full,
+				  PIPE_STATS_HW_FIFO);
+
+WL18XX_DEBUGFS_FWSTATS_FILE(mem, rx_free_mem_blks, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(mem, tx_free_mem_blks, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(mem, fwlog_free_mem_blks, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(mem, fw_gen_free_mem_blks, "%u");
+
+static ssize_t conf_read(struct file *file, char __user *user_buf,
+			 size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	struct wl18xx_priv *priv = wl->priv;
+	struct wlcore_conf_header header;
+	char *buf, *pos;
+	size_t len;
+	int ret;
+
+	len = WL18XX_CONF_SIZE;
+	buf = kmalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	header.magic	= cpu_to_le32(WL18XX_CONF_MAGIC);
+	header.version	= cpu_to_le32(WL18XX_CONF_VERSION);
+	header.checksum	= 0;
+
+	mutex_lock(&wl->mutex);
+
+	pos = buf;
+	memcpy(pos, &header, sizeof(header));
+	pos += sizeof(header);
+	memcpy(pos, &wl->conf, sizeof(wl->conf));
+	pos += sizeof(wl->conf);
+	memcpy(pos, &priv->conf, sizeof(priv->conf));
+
+	mutex_unlock(&wl->mutex);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations conf_ops = {
+	.read = conf_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+static ssize_t clear_fw_stats_write(struct file *file,
+			      const char __user *user_buf,
+			      size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	int ret;
+
+	mutex_lock(&wl->mutex);
+
+	if (wl->state == WL1271_STATE_OFF)
+		goto out;
+
+	ret = wl18xx_acx_clear_statistics(wl);
+	if (ret < 0) {
+		count = ret;
+		goto out;
+	}
+out:
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+static const struct file_operations clear_fw_stats_ops = {
+	.write = clear_fw_stats_write,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+int wl18xx_debugfs_add_files(struct wl1271 *wl,
+			     struct dentry *rootdir)
+{
+	int ret = 0;
+	struct dentry *entry, *stats, *moddir;
+
+	moddir = debugfs_create_dir(KBUILD_MODNAME, rootdir);
+	if (!moddir || IS_ERR(moddir)) {
+		entry = moddir;
+		goto err;
+	}
+
+	stats = debugfs_create_dir("fw_stats", moddir);
+	if (!stats || IS_ERR(stats)) {
+		entry = stats;
+		goto err;
+	}
+
+	DEBUGFS_ADD(clear_fw_stats, stats);
+
+	DEBUGFS_FWSTATS_ADD(debug, debug1);
+	DEBUGFS_FWSTATS_ADD(debug, debug2);
+	DEBUGFS_FWSTATS_ADD(debug, debug3);
+	DEBUGFS_FWSTATS_ADD(debug, debug4);
+	DEBUGFS_FWSTATS_ADD(debug, debug5);
+	DEBUGFS_FWSTATS_ADD(debug, debug6);
+
+	DEBUGFS_FWSTATS_ADD(error, error_frame);
+	DEBUGFS_FWSTATS_ADD(error, error_null_Frame_tx_start);
+	DEBUGFS_FWSTATS_ADD(error, error_numll_frame_cts_start);
+	DEBUGFS_FWSTATS_ADD(error, error_bar_retry);
+	DEBUGFS_FWSTATS_ADD(error, error_frame_cts_nul_flid);
+
+	DEBUGFS_FWSTATS_ADD(tx, tx_prepared_descs);
+	DEBUGFS_FWSTATS_ADD(tx, tx_cmplt);
+	DEBUGFS_FWSTATS_ADD(tx, tx_template_prepared);
+	DEBUGFS_FWSTATS_ADD(tx, tx_data_prepared);
+	DEBUGFS_FWSTATS_ADD(tx, tx_template_programmed);
+	DEBUGFS_FWSTATS_ADD(tx, tx_data_programmed);
+	DEBUGFS_FWSTATS_ADD(tx, tx_burst_programmed);
+	DEBUGFS_FWSTATS_ADD(tx, tx_starts);
+	DEBUGFS_FWSTATS_ADD(tx, tx_imm_resp);
+	DEBUGFS_FWSTATS_ADD(tx, tx_start_templates);
+	DEBUGFS_FWSTATS_ADD(tx, tx_start_int_templates);
+	DEBUGFS_FWSTATS_ADD(tx, tx_start_fw_gen);
+	DEBUGFS_FWSTATS_ADD(tx, tx_start_data);
+	DEBUGFS_FWSTATS_ADD(tx, tx_start_null_frame);
+	DEBUGFS_FWSTATS_ADD(tx, tx_exch);
+	DEBUGFS_FWSTATS_ADD(tx, tx_retry_template);
+	DEBUGFS_FWSTATS_ADD(tx, tx_retry_data);
+	DEBUGFS_FWSTATS_ADD(tx, tx_exch_pending);
+	DEBUGFS_FWSTATS_ADD(tx, tx_exch_expiry);
+	DEBUGFS_FWSTATS_ADD(tx, tx_done_template);
+	DEBUGFS_FWSTATS_ADD(tx, tx_done_data);
+	DEBUGFS_FWSTATS_ADD(tx, tx_done_int_template);
+	DEBUGFS_FWSTATS_ADD(tx, tx_frame_checksum);
+	DEBUGFS_FWSTATS_ADD(tx, tx_checksum_result);
+	DEBUGFS_FWSTATS_ADD(tx, frag_called);
+	DEBUGFS_FWSTATS_ADD(tx, frag_mpdu_alloc_failed);
+	DEBUGFS_FWSTATS_ADD(tx, frag_init_called);
+	DEBUGFS_FWSTATS_ADD(tx, frag_in_process_called);
+	DEBUGFS_FWSTATS_ADD(tx, frag_tkip_called);
+	DEBUGFS_FWSTATS_ADD(tx, frag_key_not_found);
+	DEBUGFS_FWSTATS_ADD(tx, frag_need_fragmentation);
+	DEBUGFS_FWSTATS_ADD(tx, frag_bad_mblk_num);
+	DEBUGFS_FWSTATS_ADD(tx, frag_failed);
+	DEBUGFS_FWSTATS_ADD(tx, frag_cache_hit);
+	DEBUGFS_FWSTATS_ADD(tx, frag_cache_miss);
+
+	DEBUGFS_FWSTATS_ADD(rx, rx_beacon_early_term);
+	DEBUGFS_FWSTATS_ADD(rx, rx_out_of_mpdu_nodes);
+	DEBUGFS_FWSTATS_ADD(rx, rx_hdr_overflow);
+	DEBUGFS_FWSTATS_ADD(rx, rx_dropped_frame);
+	DEBUGFS_FWSTATS_ADD(rx, rx_done);
+	DEBUGFS_FWSTATS_ADD(rx, rx_defrag);
+	DEBUGFS_FWSTATS_ADD(rx, rx_defrag_end);
+	DEBUGFS_FWSTATS_ADD(rx, rx_cmplt);
+	DEBUGFS_FWSTATS_ADD(rx, rx_pre_complt);
+	DEBUGFS_FWSTATS_ADD(rx, rx_cmplt_task);
+	DEBUGFS_FWSTATS_ADD(rx, rx_phy_hdr);
+	DEBUGFS_FWSTATS_ADD(rx, rx_timeout);
+	DEBUGFS_FWSTATS_ADD(rx, rx_timeout_wa);
+	DEBUGFS_FWSTATS_ADD(rx, rx_wa_density_dropped_frame);
+	DEBUGFS_FWSTATS_ADD(rx, rx_wa_ba_not_expected);
+	DEBUGFS_FWSTATS_ADD(rx, rx_frame_checksum);
+	DEBUGFS_FWSTATS_ADD(rx, rx_checksum_result);
+	DEBUGFS_FWSTATS_ADD(rx, defrag_called);
+	DEBUGFS_FWSTATS_ADD(rx, defrag_init_called);
+	DEBUGFS_FWSTATS_ADD(rx, defrag_in_process_called);
+	DEBUGFS_FWSTATS_ADD(rx, defrag_tkip_called);
+	DEBUGFS_FWSTATS_ADD(rx, defrag_need_defrag);
+	DEBUGFS_FWSTATS_ADD(rx, defrag_decrypt_failed);
+	DEBUGFS_FWSTATS_ADD(rx, decrypt_key_not_found);
+	DEBUGFS_FWSTATS_ADD(rx, defrag_need_decrypt);
+	DEBUGFS_FWSTATS_ADD(rx, rx_tkip_replays);
+
+	DEBUGFS_FWSTATS_ADD(isr, irqs);
+
+	DEBUGFS_FWSTATS_ADD(pwr, missing_bcns_cnt);
+	DEBUGFS_FWSTATS_ADD(pwr, rcvd_bcns_cnt);
+	DEBUGFS_FWSTATS_ADD(pwr, connection_out_of_sync);
+	DEBUGFS_FWSTATS_ADD(pwr, cont_miss_bcns_spread);
+	DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_bcns_cnt);
+
+	DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_timeouts);
+	DEBUGFS_FWSTATS_ADD(ps_poll, upsd_timeouts);
+	DEBUGFS_FWSTATS_ADD(ps_poll, upsd_max_ap_turn);
+	DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_max_ap_turn);
+	DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_utilization);
+	DEBUGFS_FWSTATS_ADD(ps_poll, upsd_utilization);
+
+	DEBUGFS_FWSTATS_ADD(rx_filter, beacon_filter);
+	DEBUGFS_FWSTATS_ADD(rx_filter, arp_filter);
+	DEBUGFS_FWSTATS_ADD(rx_filter, mc_filter);
+	DEBUGFS_FWSTATS_ADD(rx_filter, dup_filter);
+	DEBUGFS_FWSTATS_ADD(rx_filter, data_filter);
+	DEBUGFS_FWSTATS_ADD(rx_filter, ibss_filter);
+	DEBUGFS_FWSTATS_ADD(rx_filter, protection_filter);
+	DEBUGFS_FWSTATS_ADD(rx_filter, accum_arp_pend_requests);
+	DEBUGFS_FWSTATS_ADD(rx_filter, max_arp_queue_dep);
+
+	DEBUGFS_FWSTATS_ADD(rx_rate, rx_frames_per_rates);
+
+	DEBUGFS_FWSTATS_ADD(aggr_size, tx_agg_vs_rate);
+	DEBUGFS_FWSTATS_ADD(aggr_size, rx_size);
+
+	DEBUGFS_FWSTATS_ADD(pipeline, hs_tx_stat_fifo_int);
+	DEBUGFS_FWSTATS_ADD(pipeline, tcp_tx_stat_fifo_int);
+	DEBUGFS_FWSTATS_ADD(pipeline, tcp_rx_stat_fifo_int);
+	DEBUGFS_FWSTATS_ADD(pipeline, enc_tx_stat_fifo_int);
+	DEBUGFS_FWSTATS_ADD(pipeline, enc_rx_stat_fifo_int);
+	DEBUGFS_FWSTATS_ADD(pipeline, rx_complete_stat_fifo_int);
+	DEBUGFS_FWSTATS_ADD(pipeline, pre_proc_swi);
+	DEBUGFS_FWSTATS_ADD(pipeline, post_proc_swi);
+	DEBUGFS_FWSTATS_ADD(pipeline, sec_frag_swi);
+	DEBUGFS_FWSTATS_ADD(pipeline, pre_to_defrag_swi);
+	DEBUGFS_FWSTATS_ADD(pipeline, defrag_to_csum_swi);
+	DEBUGFS_FWSTATS_ADD(pipeline, csum_to_rx_xfer_swi);
+	DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in);
+	DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in_fifo_full);
+	DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_out);
+	DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_in);
+	DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_out);
+	DEBUGFS_FWSTATS_ADD(pipeline, pipeline_fifo_full);
+
+	DEBUGFS_FWSTATS_ADD(mem, rx_free_mem_blks);
+	DEBUGFS_FWSTATS_ADD(mem, tx_free_mem_blks);
+	DEBUGFS_FWSTATS_ADD(mem, fwlog_free_mem_blks);
+	DEBUGFS_FWSTATS_ADD(mem, fw_gen_free_mem_blks);
+
+	DEBUGFS_ADD(conf, moddir);
+
+	return 0;
+
+err:
+	if (IS_ERR(entry))
+		ret = PTR_ERR(entry);
+	else
+		ret = -ENOMEM;
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.h b/drivers/net/wireless/ti/wl18xx/debugfs.h
new file mode 100644
index 0000000..ed679be
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/debugfs.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have 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 __WL18XX_DEBUGFS_H__
+#define __WL18XX_DEBUGFS_H__
+
+int wl18xx_debugfs_add_files(struct wl1271 *wl,
+			     struct dentry *rootdir);
+
+#endif /* __WL18XX_DEBUGFS_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/io.c b/drivers/net/wireless/ti/wl18xx/io.c
new file mode 100644
index 0000000..598c057
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/io.c
@@ -0,0 +1,60 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have 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 "../wlcore/wlcore.h"
+#include "../wlcore/io.h"
+
+#include "io.h"
+
+void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val)
+{
+	u32 tmp;
+
+	if (WARN_ON(addr % 2))
+		return;
+
+	if ((addr % 4) == 0) {
+		tmp = wl1271_read32(wl, addr);
+		tmp = (tmp & 0xffff0000) | val;
+		wl1271_write32(wl, addr, tmp);
+	} else {
+		tmp = wl1271_read32(wl, addr - 2);
+		tmp = (tmp & 0xffff) | (val << 16);
+		wl1271_write32(wl, addr - 2, tmp);
+	}
+}
+
+u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr)
+{
+	u32 val;
+
+	if (WARN_ON(addr % 2))
+		return 0;
+
+	if ((addr % 4) == 0) {
+		/* address is 4-bytes aligned */
+		val = wl1271_read32(wl, addr);
+		return val & 0xffff;
+	} else {
+		val = wl1271_read32(wl, addr - 2);
+		return (val & 0xffff0000) >> 16;
+	}
+}
diff --git a/drivers/net/wireless/ti/wl18xx/io.h b/drivers/net/wireless/ti/wl18xx/io.h
new file mode 100644
index 0000000..be4e126
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/io.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have 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 __WL18XX_IO_H__
+#define __WL18XX_IO_H__
+
+void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val);
+u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr);
+
+#endif /* __WL18XX_IO_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
new file mode 100644
index 0000000..271ff81
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -0,0 +1,1478 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ip.h>
+#include <linux/firmware.h>
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/io.h"
+#include "../wlcore/acx.h"
+#include "../wlcore/tx.h"
+#include "../wlcore/rx.h"
+#include "../wlcore/io.h"
+#include "../wlcore/boot.h"
+
+#include "reg.h"
+#include "conf.h"
+#include "acx.h"
+#include "tx.h"
+#include "wl18xx.h"
+#include "io.h"
+#include "debugfs.h"
+
+#define WL18XX_RX_CHECKSUM_MASK      0x40
+
+static char *ht_mode_param = "default";
+static char *board_type_param = "hdk";
+static bool checksum_param = false;
+static bool enable_11a_param = true;
+static int num_rx_desc_param = -1;
+
+/* phy paramters */
+static int dc2dc_param = -1;
+static int n_antennas_2_param = -1;
+static int n_antennas_5_param = -1;
+static int low_band_component_param = -1;
+static int low_band_component_type_param = -1;
+static int high_band_component_param = -1;
+static int high_band_component_type_param = -1;
+static int pwr_limit_reference_11_abg_param = -1;
+
+static const u8 wl18xx_rate_to_idx_2ghz[] = {
+	/* MCS rates are used only with 11n */
+	15,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */
+	14,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */
+	13,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */
+	12,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */
+	11,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */
+	10,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */
+	9,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */
+	8,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */
+	7,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */
+	6,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */
+	5,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */
+	4,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */
+	3,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */
+	2,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */
+	1,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */
+	0,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */
+
+	11,                            /* WL18XX_CONF_HW_RXTX_RATE_54   */
+	10,                            /* WL18XX_CONF_HW_RXTX_RATE_48   */
+	9,                             /* WL18XX_CONF_HW_RXTX_RATE_36   */
+	8,                             /* WL18XX_CONF_HW_RXTX_RATE_24   */
+
+	/* TI-specific rate */
+	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22   */
+
+	7,                             /* WL18XX_CONF_HW_RXTX_RATE_18   */
+	6,                             /* WL18XX_CONF_HW_RXTX_RATE_12   */
+	3,                             /* WL18XX_CONF_HW_RXTX_RATE_11   */
+	5,                             /* WL18XX_CONF_HW_RXTX_RATE_9    */
+	4,                             /* WL18XX_CONF_HW_RXTX_RATE_6    */
+	2,                             /* WL18XX_CONF_HW_RXTX_RATE_5_5  */
+	1,                             /* WL18XX_CONF_HW_RXTX_RATE_2    */
+	0                              /* WL18XX_CONF_HW_RXTX_RATE_1    */
+};
+
+static const u8 wl18xx_rate_to_idx_5ghz[] = {
+	/* MCS rates are used only with 11n */
+	15,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */
+	14,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */
+	13,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */
+	12,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */
+	11,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */
+	10,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */
+	9,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */
+	8,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */
+	7,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */
+	6,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */
+	5,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */
+	4,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */
+	3,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */
+	2,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */
+	1,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */
+	0,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */
+
+	7,                             /* WL18XX_CONF_HW_RXTX_RATE_54   */
+	6,                             /* WL18XX_CONF_HW_RXTX_RATE_48   */
+	5,                             /* WL18XX_CONF_HW_RXTX_RATE_36   */
+	4,                             /* WL18XX_CONF_HW_RXTX_RATE_24   */
+
+	/* TI-specific rate */
+	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22   */
+
+	3,                             /* WL18XX_CONF_HW_RXTX_RATE_18   */
+	2,                             /* WL18XX_CONF_HW_RXTX_RATE_12   */
+	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_11   */
+	1,                             /* WL18XX_CONF_HW_RXTX_RATE_9    */
+	0,                             /* WL18XX_CONF_HW_RXTX_RATE_6    */
+	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_5_5  */
+	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_2    */
+	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_1    */
+};
+
+static const u8 *wl18xx_band_rate_to_idx[] = {
+	[IEEE80211_BAND_2GHZ] = wl18xx_rate_to_idx_2ghz,
+	[IEEE80211_BAND_5GHZ] = wl18xx_rate_to_idx_5ghz
+};
+
+enum wl18xx_hw_rates {
+	WL18XX_CONF_HW_RXTX_RATE_MCS15 = 0,
+	WL18XX_CONF_HW_RXTX_RATE_MCS14,
+	WL18XX_CONF_HW_RXTX_RATE_MCS13,
+	WL18XX_CONF_HW_RXTX_RATE_MCS12,
+	WL18XX_CONF_HW_RXTX_RATE_MCS11,
+	WL18XX_CONF_HW_RXTX_RATE_MCS10,
+	WL18XX_CONF_HW_RXTX_RATE_MCS9,
+	WL18XX_CONF_HW_RXTX_RATE_MCS8,
+	WL18XX_CONF_HW_RXTX_RATE_MCS7,
+	WL18XX_CONF_HW_RXTX_RATE_MCS6,
+	WL18XX_CONF_HW_RXTX_RATE_MCS5,
+	WL18XX_CONF_HW_RXTX_RATE_MCS4,
+	WL18XX_CONF_HW_RXTX_RATE_MCS3,
+	WL18XX_CONF_HW_RXTX_RATE_MCS2,
+	WL18XX_CONF_HW_RXTX_RATE_MCS1,
+	WL18XX_CONF_HW_RXTX_RATE_MCS0,
+	WL18XX_CONF_HW_RXTX_RATE_54,
+	WL18XX_CONF_HW_RXTX_RATE_48,
+	WL18XX_CONF_HW_RXTX_RATE_36,
+	WL18XX_CONF_HW_RXTX_RATE_24,
+	WL18XX_CONF_HW_RXTX_RATE_22,
+	WL18XX_CONF_HW_RXTX_RATE_18,
+	WL18XX_CONF_HW_RXTX_RATE_12,
+	WL18XX_CONF_HW_RXTX_RATE_11,
+	WL18XX_CONF_HW_RXTX_RATE_9,
+	WL18XX_CONF_HW_RXTX_RATE_6,
+	WL18XX_CONF_HW_RXTX_RATE_5_5,
+	WL18XX_CONF_HW_RXTX_RATE_2,
+	WL18XX_CONF_HW_RXTX_RATE_1,
+	WL18XX_CONF_HW_RXTX_RATE_MAX,
+};
+
+static struct wlcore_conf wl18xx_conf = {
+	.sg = {
+		.params = {
+			[CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
+			[CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
+			[CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
+			[CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
+			[CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
+			[CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
+			[CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
+			[CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
+			[CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
+			[CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
+			[CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
+			[CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
+			[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
+			[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
+			[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
+			[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
+			[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
+			[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
+			[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
+			[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
+			[CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
+			[CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
+			[CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
+			[CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
+			[CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
+			[CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
+			/* active scan params */
+			[CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
+			[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
+			[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
+			/* passive scan params */
+			[CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
+			[CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
+			[CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
+			/* passive scan in dual antenna params */
+			[CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
+			[CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
+			[CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
+			/* general params */
+			[CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
+			[CONF_SG_ANTENNA_CONFIGURATION] = 0,
+			[CONF_SG_BEACON_MISS_PERCENT] = 60,
+			[CONF_SG_DHCP_TIME] = 5000,
+			[CONF_SG_RXT] = 1200,
+			[CONF_SG_TXT] = 1000,
+			[CONF_SG_ADAPTIVE_RXT_TXT] = 1,
+			[CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
+			[CONF_SG_HV3_MAX_SERVED] = 6,
+			[CONF_SG_PS_POLL_TIMEOUT] = 10,
+			[CONF_SG_UPSD_TIMEOUT] = 10,
+			[CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
+			[CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
+			[CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
+			/* AP params */
+			[CONF_AP_BEACON_MISS_TX] = 3,
+			[CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
+			[CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
+			[CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
+			[CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
+			[CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
+			/* CTS Diluting params */
+			[CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
+			[CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
+		},
+		.state = CONF_SG_PROTECTIVE,
+	},
+	.rx = {
+		.rx_msdu_life_time           = 512000,
+		.packet_detection_threshold  = 0,
+		.ps_poll_timeout             = 15,
+		.upsd_timeout                = 15,
+		.rts_threshold               = IEEE80211_MAX_RTS_THRESHOLD,
+		.rx_cca_threshold            = 0,
+		.irq_blk_threshold           = 0xFFFF,
+		.irq_pkt_threshold           = 0,
+		.irq_timeout                 = 600,
+		.queue_type                  = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
+	},
+	.tx = {
+		.tx_energy_detection         = 0,
+		.sta_rc_conf                 = {
+			.enabled_rates       = 0,
+			.short_retry_limit   = 10,
+			.long_retry_limit    = 10,
+			.aflags              = 0,
+		},
+		.ac_conf_count               = 4,
+		.ac_conf                     = {
+			[CONF_TX_AC_BE] = {
+				.ac          = CONF_TX_AC_BE,
+				.cw_min      = 15,
+				.cw_max      = 63,
+				.aifsn       = 3,
+				.tx_op_limit = 0,
+			},
+			[CONF_TX_AC_BK] = {
+				.ac          = CONF_TX_AC_BK,
+				.cw_min      = 15,
+				.cw_max      = 63,
+				.aifsn       = 7,
+				.tx_op_limit = 0,
+			},
+			[CONF_TX_AC_VI] = {
+				.ac          = CONF_TX_AC_VI,
+				.cw_min      = 15,
+				.cw_max      = 63,
+				.aifsn       = CONF_TX_AIFS_PIFS,
+				.tx_op_limit = 3008,
+			},
+			[CONF_TX_AC_VO] = {
+				.ac          = CONF_TX_AC_VO,
+				.cw_min      = 15,
+				.cw_max      = 63,
+				.aifsn       = CONF_TX_AIFS_PIFS,
+				.tx_op_limit = 1504,
+			},
+		},
+		.max_tx_retries = 100,
+		.ap_aging_period = 300,
+		.tid_conf_count = 4,
+		.tid_conf = {
+			[CONF_TX_AC_BE] = {
+				.queue_id    = CONF_TX_AC_BE,
+				.channel_type = CONF_CHANNEL_TYPE_EDCF,
+				.tsid        = CONF_TX_AC_BE,
+				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
+				.ack_policy  = CONF_ACK_POLICY_LEGACY,
+				.apsd_conf   = {0, 0},
+			},
+			[CONF_TX_AC_BK] = {
+				.queue_id    = CONF_TX_AC_BK,
+				.channel_type = CONF_CHANNEL_TYPE_EDCF,
+				.tsid        = CONF_TX_AC_BK,
+				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
+				.ack_policy  = CONF_ACK_POLICY_LEGACY,
+				.apsd_conf   = {0, 0},
+			},
+			[CONF_TX_AC_VI] = {
+				.queue_id    = CONF_TX_AC_VI,
+				.channel_type = CONF_CHANNEL_TYPE_EDCF,
+				.tsid        = CONF_TX_AC_VI,
+				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
+				.ack_policy  = CONF_ACK_POLICY_LEGACY,
+				.apsd_conf   = {0, 0},
+			},
+			[CONF_TX_AC_VO] = {
+				.queue_id    = CONF_TX_AC_VO,
+				.channel_type = CONF_CHANNEL_TYPE_EDCF,
+				.tsid        = CONF_TX_AC_VO,
+				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
+				.ack_policy  = CONF_ACK_POLICY_LEGACY,
+				.apsd_conf   = {0, 0},
+			},
+		},
+		.frag_threshold              = IEEE80211_MAX_FRAG_THRESHOLD,
+		.tx_compl_timeout            = 350,
+		.tx_compl_threshold          = 10,
+		.basic_rate                  = CONF_HW_BIT_RATE_1MBPS,
+		.basic_rate_5                = CONF_HW_BIT_RATE_6MBPS,
+		.tmpl_short_retry_limit      = 10,
+		.tmpl_long_retry_limit       = 10,
+		.tx_watchdog_timeout         = 5000,
+	},
+	.conn = {
+		.wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
+		.listen_interval             = 1,
+		.suspend_wake_up_event       = CONF_WAKE_UP_EVENT_N_DTIM,
+		.suspend_listen_interval     = 3,
+		.bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,
+		.bcn_filt_ie_count           = 3,
+		.bcn_filt_ie = {
+			[0] = {
+				.ie          = WLAN_EID_CHANNEL_SWITCH,
+				.rule        = CONF_BCN_RULE_PASS_ON_APPEARANCE,
+			},
+			[1] = {
+				.ie          = WLAN_EID_HT_OPERATION,
+				.rule        = CONF_BCN_RULE_PASS_ON_CHANGE,
+			},
+			[2] = {
+				.ie	     = WLAN_EID_ERP_INFO,
+				.rule	     = CONF_BCN_RULE_PASS_ON_CHANGE,
+			},
+		},
+		.synch_fail_thold            = 12,
+		.bss_lose_timeout            = 400,
+		.beacon_rx_timeout           = 10000,
+		.broadcast_timeout           = 20000,
+		.rx_broadcast_in_ps          = 1,
+		.ps_poll_threshold           = 10,
+		.bet_enable                  = CONF_BET_MODE_ENABLE,
+		.bet_max_consecutive         = 50,
+		.psm_entry_retries           = 8,
+		.psm_exit_retries            = 16,
+		.psm_entry_nullfunc_retries  = 3,
+		.dynamic_ps_timeout          = 200,
+		.forced_ps                   = false,
+		.keep_alive_interval         = 55000,
+		.max_listen_interval         = 20,
+		.sta_sleep_auth              = WL1271_PSM_ILLEGAL,
+	},
+	.itrim = {
+		.enable = false,
+		.timeout = 50000,
+	},
+	.pm_config = {
+		.host_clk_settling_time = 5000,
+		.host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE,
+	},
+	.roam_trigger = {
+		.trigger_pacing               = 1,
+		.avg_weight_rssi_beacon       = 20,
+		.avg_weight_rssi_data         = 10,
+		.avg_weight_snr_beacon        = 20,
+		.avg_weight_snr_data          = 10,
+	},
+	.scan = {
+		.min_dwell_time_active        = 7500,
+		.max_dwell_time_active        = 30000,
+		.min_dwell_time_passive       = 100000,
+		.max_dwell_time_passive       = 100000,
+		.num_probe_reqs               = 2,
+		.split_scan_timeout           = 50000,
+	},
+	.sched_scan = {
+		/*
+		 * Values are in TU/1000 but since sched scan FW command
+		 * params are in TUs rounding up may occur.
+		 */
+		.base_dwell_time		= 7500,
+		.max_dwell_time_delta		= 22500,
+		/* based on 250bits per probe @1Mbps */
+		.dwell_time_delta_per_probe	= 2000,
+		/* based on 250bits per probe @6Mbps (plus a bit more) */
+		.dwell_time_delta_per_probe_5	= 350,
+		.dwell_time_passive		= 100000,
+		.dwell_time_dfs			= 150000,
+		.num_probe_reqs			= 2,
+		.rssi_threshold			= -90,
+		.snr_threshold			= 0,
+	},
+	.ht = {
+		.rx_ba_win_size = 10,
+		.tx_ba_win_size = 64,
+		.inactivity_timeout = 10000,
+		.tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
+	},
+	.mem = {
+		.num_stations                 = 1,
+		.ssid_profiles                = 1,
+		.rx_block_num                 = 40,
+		.tx_min_block_num             = 40,
+		.dynamic_memory               = 1,
+		.min_req_tx_blocks            = 45,
+		.min_req_rx_blocks            = 22,
+		.tx_min                       = 27,
+	},
+	.fm_coex = {
+		.enable                       = true,
+		.swallow_period               = 5,
+		.n_divider_fref_set_1         = 0xff,       /* default */
+		.n_divider_fref_set_2         = 12,
+		.m_divider_fref_set_1         = 0xffff,
+		.m_divider_fref_set_2         = 148,        /* default */
+		.coex_pll_stabilization_time  = 0xffffffff, /* default */
+		.ldo_stabilization_time       = 0xffff,     /* default */
+		.fm_disturbed_band_margin     = 0xff,       /* default */
+		.swallow_clk_diff             = 0xff,       /* default */
+	},
+	.rx_streaming = {
+		.duration                      = 150,
+		.queues                        = 0x1,
+		.interval                      = 20,
+		.always                        = 0,
+	},
+	.fwlog = {
+		.mode                         = WL12XX_FWLOG_ON_DEMAND,
+		.mem_blocks                   = 2,
+		.severity                     = 0,
+		.timestamp                    = WL12XX_FWLOG_TIMESTAMP_DISABLED,
+		.output                       = WL12XX_FWLOG_OUTPUT_HOST,
+		.threshold                    = 0,
+	},
+	.rate = {
+		.rate_retry_score = 32000,
+		.per_add = 8192,
+		.per_th1 = 2048,
+		.per_th2 = 4096,
+		.max_per = 8100,
+		.inverse_curiosity_factor = 5,
+		.tx_fail_low_th = 4,
+		.tx_fail_high_th = 10,
+		.per_alpha_shift = 4,
+		.per_add_shift = 13,
+		.per_beta1_shift = 10,
+		.per_beta2_shift = 8,
+		.rate_check_up = 2,
+		.rate_check_down = 12,
+		.rate_retry_policy = {
+			0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00,
+		},
+	},
+	.hangover = {
+		.recover_time               = 0,
+		.hangover_period            = 20,
+		.dynamic_mode               = 1,
+		.early_termination_mode     = 1,
+		.max_period                 = 20,
+		.min_period                 = 1,
+		.increase_delta             = 1,
+		.decrease_delta             = 2,
+		.quiet_time                 = 4,
+		.increase_time              = 1,
+		.window_size                = 16,
+	},
+};
+
+static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
+	.phy = {
+		.phy_standalone			= 0x00,
+		.primary_clock_setting_time	= 0x05,
+		.clock_valid_on_wake_up		= 0x00,
+		.secondary_clock_setting_time	= 0x05,
+		.rdl				= 0x01,
+		.auto_detect			= 0x00,
+		.dedicated_fem			= FEM_NONE,
+		.low_band_component		= COMPONENT_2_WAY_SWITCH,
+		.low_band_component_type	= 0x05,
+		.high_band_component		= COMPONENT_2_WAY_SWITCH,
+		.high_band_component_type	= 0x09,
+		.tcxo_ldo_voltage		= 0x00,
+		.xtal_itrim_val			= 0x04,
+		.srf_state			= 0x00,
+		.io_configuration		= 0x01,
+		.sdio_configuration		= 0x00,
+		.settings			= 0x00,
+		.enable_clpc			= 0x00,
+		.enable_tx_low_pwr_on_siso_rdl	= 0x00,
+		.rx_profile			= 0x00,
+		.pwr_limit_reference_11_abg	= 0xc8,
+		.psat				= 0,
+		.low_power_val			= 0x00,
+		.med_power_val			= 0x0a,
+		.high_power_val			= 0x1e,
+		.external_pa_dc2dc		= 0,
+		.number_of_assembled_ant2_4	= 1,
+		.number_of_assembled_ant5	= 1,
+	},
+};
+
+static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
+	[PART_TOP_PRCM_ELP_SOC] = {
+		.mem  = { .start = 0x00A02000, .size  = 0x00010000 },
+		.reg  = { .start = 0x00807000, .size  = 0x00005000 },
+		.mem2 = { .start = 0x00800000, .size  = 0x0000B000 },
+		.mem3 = { .start = 0x00000000, .size  = 0x00000000 },
+	},
+	[PART_DOWN] = {
+		.mem  = { .start = 0x00000000, .size  = 0x00014000 },
+		.reg  = { .start = 0x00810000, .size  = 0x0000BFFF },
+		.mem2 = { .start = 0x00000000, .size  = 0x00000000 },
+		.mem3 = { .start = 0x00000000, .size  = 0x00000000 },
+	},
+	[PART_BOOT] = {
+		.mem  = { .start = 0x00700000, .size = 0x0000030c },
+		.reg  = { .start = 0x00802000, .size = 0x00014578 },
+		.mem2 = { .start = 0x00B00404, .size = 0x00001000 },
+		.mem3 = { .start = 0x00C00000, .size = 0x00000400 },
+	},
+	[PART_WORK] = {
+		.mem  = { .start = 0x00800000, .size  = 0x000050FC },
+		.reg  = { .start = 0x00B00404, .size  = 0x00001000 },
+		.mem2 = { .start = 0x00C00000, .size  = 0x00000400 },
+		.mem3 = { .start = 0x00000000, .size  = 0x00000000 },
+	},
+	[PART_PHY_INIT] = {
+		.mem  = { .start = 0x80926000,
+			  .size = sizeof(struct wl18xx_mac_and_phy_params) },
+		.reg  = { .start = 0x00000000, .size = 0x00000000 },
+		.mem2 = { .start = 0x00000000, .size = 0x00000000 },
+		.mem3 = { .start = 0x00000000, .size = 0x00000000 },
+	},
+};
+
+static const int wl18xx_rtable[REG_TABLE_LEN] = {
+	[REG_ECPU_CONTROL]		= WL18XX_REG_ECPU_CONTROL,
+	[REG_INTERRUPT_NO_CLEAR]	= WL18XX_REG_INTERRUPT_NO_CLEAR,
+	[REG_INTERRUPT_ACK]		= WL18XX_REG_INTERRUPT_ACK,
+	[REG_COMMAND_MAILBOX_PTR]	= WL18XX_REG_COMMAND_MAILBOX_PTR,
+	[REG_EVENT_MAILBOX_PTR]		= WL18XX_REG_EVENT_MAILBOX_PTR,
+	[REG_INTERRUPT_TRIG]		= WL18XX_REG_INTERRUPT_TRIG_H,
+	[REG_INTERRUPT_MASK]		= WL18XX_REG_INTERRUPT_MASK,
+	[REG_PC_ON_RECOVERY]		= WL18XX_SCR_PAD4,
+	[REG_CHIP_ID_B]			= WL18XX_REG_CHIP_ID_B,
+	[REG_CMD_MBOX_ADDRESS]		= WL18XX_CMD_MBOX_ADDRESS,
+
+	/* data access memory addresses, used with partition translation */
+	[REG_SLV_MEM_DATA]		= WL18XX_SLV_MEM_DATA,
+	[REG_SLV_REG_DATA]		= WL18XX_SLV_REG_DATA,
+
+	/* raw data access memory addresses */
+	[REG_RAW_FW_STATUS_ADDR]	= WL18XX_FW_STATUS_ADDR,
+};
+
+static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
+	[CLOCK_CONFIG_16_2_M]	= { 7,  104,  801, 4,  true },
+	[CLOCK_CONFIG_16_368_M]	= { 9,  132, 3751, 4,  true },
+	[CLOCK_CONFIG_16_8_M]	= { 7,  100,    0, 0, false },
+	[CLOCK_CONFIG_19_2_M]	= { 8,  100,    0, 0, false },
+	[CLOCK_CONFIG_26_M]	= { 13, 120,    0, 0, false },
+	[CLOCK_CONFIG_32_736_M]	= { 9,  132, 3751, 4,  true },
+	[CLOCK_CONFIG_33_6_M]	= { 7,  100,    0, 0, false },
+	[CLOCK_CONFIG_38_468_M]	= { 8,  100,    0, 0, false },
+	[CLOCK_CONFIG_52_M]	= { 13, 120,    0, 0, false },
+};
+
+/* TODO: maybe move to a new header file? */
+#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw.bin"
+
+static int wl18xx_identify_chip(struct wl1271 *wl)
+{
+	int ret = 0;
+
+	switch (wl->chip.id) {
+	case CHIP_ID_185x_PG20:
+		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG20)",
+				 wl->chip.id);
+		wl->sr_fw_name = WL18XX_FW_NAME;
+		/* wl18xx uses the same firmware for PLT */
+		wl->plt_fw_name = WL18XX_FW_NAME;
+		wl->quirks |= WLCORE_QUIRK_NO_ELP |
+			      WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
+			      WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
+			      WLCORE_QUIRK_TX_PAD_LAST_FRAME;
+		break;
+	case CHIP_ID_185x_PG10:
+		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG10)",
+			     wl->chip.id);
+		wl->sr_fw_name = WL18XX_FW_NAME;
+		/* wl18xx uses the same firmware for PLT */
+		wl->plt_fw_name = WL18XX_FW_NAME;
+		wl->quirks |= WLCORE_QUIRK_NO_ELP |
+			WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED |
+			WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
+			WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
+
+		/* PG 1.0 has some problems with MCS_13, so disable it */
+		wl->ht_cap[IEEE80211_BAND_2GHZ].mcs.rx_mask[1] &= ~BIT(5);
+
+		break;
+	default:
+		wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
+		ret = -ENODEV;
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+static void wl18xx_set_clk(struct wl1271 *wl)
+{
+	u32 clk_freq;
+
+	wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
+
+	/* TODO: PG2: apparently we need to read the clk type */
+
+	clk_freq = wl18xx_top_reg_read(wl, PRIMARY_CLK_DETECT);
+	wl1271_debug(DEBUG_BOOT, "clock freq %d (%d, %d, %d, %d, %s)", clk_freq,
+		     wl18xx_clk_table[clk_freq].n, wl18xx_clk_table[clk_freq].m,
+		     wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q,
+		     wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit");
+
+	wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N, wl18xx_clk_table[clk_freq].n);
+	wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M, wl18xx_clk_table[clk_freq].m);
+
+	if (wl18xx_clk_table[clk_freq].swallow) {
+		/* first the 16 lower bits */
+		wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1,
+				     wl18xx_clk_table[clk_freq].q &
+				     PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK);
+		/* then the 16 higher bits, masked out */
+		wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2,
+				     (wl18xx_clk_table[clk_freq].q >> 16) &
+				     PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK);
+
+		/* first the 16 lower bits */
+		wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1,
+				     wl18xx_clk_table[clk_freq].p &
+				     PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK);
+		/* then the 16 higher bits, masked out */
+		wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2,
+				     (wl18xx_clk_table[clk_freq].p >> 16) &
+				     PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK);
+	} else {
+		wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN,
+				     PLLSH_WCS_PLL_SWALLOW_EN_VAL2);
+	}
+}
+
+static void wl18xx_boot_soft_reset(struct wl1271 *wl)
+{
+	/* disable Rx/Tx */
+	wl1271_write32(wl, WL18XX_ENABLE, 0x0);
+
+	/* disable auto calibration on start*/
+	wl1271_write32(wl, WL18XX_SPARE_A2, 0xffff);
+}
+
+static int wl18xx_pre_boot(struct wl1271 *wl)
+{
+	wl18xx_set_clk(wl);
+
+	/* Continue the ELP wake up sequence */
+	wl1271_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
+	udelay(500);
+
+	wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+
+	/* Disable interrupts */
+	wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+
+	wl18xx_boot_soft_reset(wl);
+
+	return 0;
+}
+
+static void wl18xx_pre_upload(struct wl1271 *wl)
+{
+	u32 tmp;
+
+	wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+
+	/* TODO: check if this is all needed */
+	wl1271_write32(wl, WL18XX_EEPROMLESS_IND, WL18XX_EEPROMLESS_IND);
+
+	tmp = wlcore_read_reg(wl, REG_CHIP_ID_B);
+
+	wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
+
+	tmp = wl1271_read32(wl, WL18XX_SCR_PAD2);
+}
+
+static void wl18xx_set_mac_and_phy(struct wl1271 *wl)
+{
+	struct wl18xx_priv *priv = wl->priv;
+	size_t len;
+
+	/* the parameters struct is smaller for PG1 */
+	if (wl->chip.id == CHIP_ID_185x_PG10)
+		len = offsetof(struct wl18xx_mac_and_phy_params, psat) + 1;
+	else
+		len = sizeof(struct wl18xx_mac_and_phy_params);
+
+	wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
+	wl1271_write(wl, WL18XX_PHY_INIT_MEM_ADDR, (u8 *)&priv->conf.phy, len,
+		     false);
+}
+
+static void wl18xx_enable_interrupts(struct wl1271 *wl)
+{
+	u32 event_mask, intr_mask;
+
+	if (wl->chip.id == CHIP_ID_185x_PG10) {
+		event_mask = WL18XX_ACX_EVENTS_VECTOR_PG1;
+		intr_mask = WL18XX_INTR_MASK_PG1;
+	} else {
+		event_mask = WL18XX_ACX_EVENTS_VECTOR_PG2;
+		intr_mask = WL18XX_INTR_MASK_PG2;
+	}
+
+	wlcore_write_reg(wl, REG_INTERRUPT_MASK, event_mask);
+
+	wlcore_enable_interrupts(wl);
+	wlcore_write_reg(wl, REG_INTERRUPT_MASK,
+			 WL1271_ACX_INTR_ALL & ~intr_mask);
+}
+
+static int wl18xx_boot(struct wl1271 *wl)
+{
+	int ret;
+
+	ret = wl18xx_pre_boot(wl);
+	if (ret < 0)
+		goto out;
+
+	wl18xx_pre_upload(wl);
+
+	ret = wlcore_boot_upload_firmware(wl);
+	if (ret < 0)
+		goto out;
+
+	wl18xx_set_mac_and_phy(wl);
+
+	ret = wlcore_boot_run_firmware(wl);
+	if (ret < 0)
+		goto out;
+
+	wl18xx_enable_interrupts(wl);
+
+out:
+	return ret;
+}
+
+static void wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
+			       void *buf, size_t len)
+{
+	struct wl18xx_priv *priv = wl->priv;
+
+	memcpy(priv->cmd_buf, buf, len);
+	memset(priv->cmd_buf + len, 0, WL18XX_CMD_MAX_SIZE - len);
+
+	wl1271_write(wl, cmd_box_addr, priv->cmd_buf, WL18XX_CMD_MAX_SIZE,
+		     false);
+}
+
+static void wl18xx_ack_event(struct wl1271 *wl)
+{
+	wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL18XX_INTR_TRIG_EVENT_ACK);
+}
+
+static u32 wl18xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks)
+{
+	u32 blk_size = WL18XX_TX_HW_BLOCK_SIZE;
+	return (len + blk_size - 1) / blk_size + spare_blks;
+}
+
+static void
+wl18xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
+			  u32 blks, u32 spare_blks)
+{
+	desc->wl18xx_mem.total_mem_blocks = blks;
+}
+
+static void
+wl18xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
+			    struct sk_buff *skb)
+{
+	desc->length = cpu_to_le16(skb->len);
+
+	/* if only the last frame is to be padded, we unset this bit on Tx */
+	if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME)
+		desc->wl18xx_mem.ctrl = WL18XX_TX_CTRL_NOT_PADDED;
+	else
+		desc->wl18xx_mem.ctrl = 0;
+
+	wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d "
+		     "len: %d life: %d mem: %d", desc->hlid,
+		     le16_to_cpu(desc->length),
+		     le16_to_cpu(desc->life_time),
+		     desc->wl18xx_mem.total_mem_blocks);
+}
+
+static enum wl_rx_buf_align
+wl18xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
+{
+	if (rx_desc & RX_BUF_PADDED_PAYLOAD)
+		return WLCORE_RX_BUF_PADDED;
+
+	return WLCORE_RX_BUF_ALIGNED;
+}
+
+static u32 wl18xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
+				    u32 data_len)
+{
+	struct wl1271_rx_descriptor *desc = rx_data;
+
+	/* invalid packet */
+	if (data_len < sizeof(*desc))
+		return 0;
+
+	return data_len - sizeof(*desc);
+}
+
+static void wl18xx_tx_immediate_completion(struct wl1271 *wl)
+{
+	wl18xx_tx_immediate_complete(wl);
+}
+
+static int wl18xx_set_host_cfg_bitmap(struct wl1271 *wl, u32 extra_mem_blk)
+{
+	int ret;
+	u32 sdio_align_size = 0;
+	u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE |
+			      HOST_IF_CFG_ADD_RX_ALIGNMENT;
+
+	/* Enable Tx SDIO padding */
+	if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) {
+		host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
+		sdio_align_size = WL12XX_BUS_BLOCK_SIZE;
+	}
+
+	/* Enable Rx SDIO padding */
+	if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN) {
+		host_cfg_bitmap |= HOST_IF_CFG_RX_PAD_TO_SDIO_BLK;
+		sdio_align_size = WL12XX_BUS_BLOCK_SIZE;
+	}
+
+	ret = wl18xx_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap,
+					    sdio_align_size, extra_mem_blk,
+					    WL18XX_HOST_IF_LEN_SIZE_FIELD);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int wl18xx_hw_init(struct wl1271 *wl)
+{
+	int ret;
+	struct wl18xx_priv *priv = wl->priv;
+
+	/* (re)init private structures. Relevant on recovery as well. */
+	priv->last_fw_rls_idx = 0;
+	priv->extra_spare_vif_count = 0;
+
+	/* set the default amount of spare blocks in the bitmap */
+	ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE);
+	if (ret < 0)
+		return ret;
+
+	if (checksum_param) {
+		ret = wl18xx_acx_set_checksum_state(wl);
+		if (ret != 0)
+			return ret;
+	}
+
+	return ret;
+}
+
+static void wl18xx_set_tx_desc_csum(struct wl1271 *wl,
+				    struct wl1271_tx_hw_descr *desc,
+				    struct sk_buff *skb)
+{
+	u32 ip_hdr_offset;
+	struct iphdr *ip_hdr;
+
+	if (!checksum_param) {
+		desc->wl18xx_checksum_data = 0;
+		return;
+	}
+
+	if (skb->ip_summed != CHECKSUM_PARTIAL) {
+		desc->wl18xx_checksum_data = 0;
+		return;
+	}
+
+	ip_hdr_offset = skb_network_header(skb) - skb_mac_header(skb);
+	if (WARN_ON(ip_hdr_offset >= (1<<7))) {
+		desc->wl18xx_checksum_data = 0;
+		return;
+	}
+
+	desc->wl18xx_checksum_data = ip_hdr_offset << 1;
+
+	/* FW is interested only in the LSB of the protocol  TCP=0 UDP=1 */
+	ip_hdr = (void *)skb_network_header(skb);
+	desc->wl18xx_checksum_data |= (ip_hdr->protocol & 0x01);
+}
+
+static void wl18xx_set_rx_csum(struct wl1271 *wl,
+			       struct wl1271_rx_descriptor *desc,
+			       struct sk_buff *skb)
+{
+	if (desc->status & WL18XX_RX_CHECKSUM_MASK)
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+}
+
+/*
+ * TODO: instead of having these two functions to get the rate mask,
+ * we should modify the wlvif->rate_set instead
+ */
+static u32 wl18xx_sta_get_ap_rate_mask(struct wl1271 *wl,
+				       struct wl12xx_vif *wlvif)
+{
+	u32 hw_rate_set = wlvif->rate_set;
+
+	if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
+	    wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
+		wl1271_debug(DEBUG_ACX, "using wide channel rate mask");
+		hw_rate_set |= CONF_TX_RATE_USE_WIDE_CHAN;
+
+		/* we don't support MIMO in wide-channel mode */
+		hw_rate_set &= ~CONF_TX_MIMO_RATES;
+	}
+
+	return hw_rate_set;
+}
+
+static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
+					     struct wl12xx_vif *wlvif)
+{
+	if ((wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
+	     wlvif->channel_type == NL80211_CHAN_HT40PLUS) &&
+	    !strcmp(ht_mode_param, "wide")) {
+		wl1271_debug(DEBUG_ACX, "using wide channel rate mask");
+		return CONF_TX_RATE_USE_WIDE_CHAN;
+	} else if (!strcmp(ht_mode_param, "mimo")) {
+		wl1271_debug(DEBUG_ACX, "using MIMO rate mask");
+
+		/*
+		 * PG 1.0 has some problems with MCS_13, so disable it
+		 *
+		 * TODO: instead of hacking this in here, we should
+		 * make it more general and change a bit in the
+		 * wlvif->rate_set instead.
+		 */
+		if (wl->chip.id == CHIP_ID_185x_PG10)
+			return CONF_TX_MIMO_RATES & ~CONF_HW_BIT_RATE_MCS_13;
+
+		return CONF_TX_MIMO_RATES;
+	} else {
+		return 0;
+	}
+}
+
+static s8 wl18xx_get_pg_ver(struct wl1271 *wl)
+{
+	u32 fuse;
+
+	wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
+
+	fuse = wl1271_read32(wl, WL18XX_REG_FUSE_DATA_1_3);
+	fuse = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
+
+	wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+
+	return (s8)fuse;
+}
+
+#define WL18XX_CONF_FILE_NAME "ti-connectivity/wl18xx-conf.bin"
+static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
+{
+	struct wl18xx_priv *priv = wl->priv;
+	struct wlcore_conf_file *conf_file;
+	const struct firmware *fw;
+	int ret;
+
+	ret = request_firmware(&fw, WL18XX_CONF_FILE_NAME, dev);
+	if (ret < 0) {
+		wl1271_error("could not get configuration binary %s: %d",
+			     WL18XX_CONF_FILE_NAME, ret);
+		goto out_fallback;
+	}
+
+	if (fw->size != WL18XX_CONF_SIZE) {
+		wl1271_error("configuration binary file size is wrong, expected %zu got %zu",
+			     WL18XX_CONF_SIZE, fw->size);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	conf_file = (struct wlcore_conf_file *) fw->data;
+
+	if (conf_file->header.magic != cpu_to_le32(WL18XX_CONF_MAGIC)) {
+		wl1271_error("configuration binary file magic number mismatch, "
+			     "expected 0x%0x got 0x%0x", WL18XX_CONF_MAGIC,
+			     conf_file->header.magic);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (conf_file->header.version != cpu_to_le32(WL18XX_CONF_VERSION)) {
+		wl1271_error("configuration binary file version not supported, "
+			     "expected 0x%08x got 0x%08x",
+			     WL18XX_CONF_VERSION, conf_file->header.version);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	memcpy(&wl->conf, &conf_file->core, sizeof(wl18xx_conf));
+	memcpy(&priv->conf, &conf_file->priv, sizeof(priv->conf));
+
+	goto out;
+
+out_fallback:
+	wl1271_warning("falling back to default config");
+
+	/* apply driver default configuration */
+	memcpy(&wl->conf, &wl18xx_conf, sizeof(wl18xx_conf));
+	/* apply default private configuration */
+	memcpy(&priv->conf, &wl18xx_default_priv_conf, sizeof(priv->conf));
+
+	/* For now we just fallback */
+	return 0;
+
+out:
+	release_firmware(fw);
+	return ret;
+}
+
+static int wl18xx_plt_init(struct wl1271 *wl)
+{
+	wl1271_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT);
+
+	return wl->ops->boot(wl);
+}
+
+static void wl18xx_get_mac(struct wl1271 *wl)
+{
+	u32 mac1, mac2;
+
+	wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
+
+	mac1 = wl1271_read32(wl, WL18XX_REG_FUSE_BD_ADDR_1);
+	mac2 = wl1271_read32(wl, WL18XX_REG_FUSE_BD_ADDR_2);
+
+	/* these are the two parts of the BD_ADDR */
+	wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
+		((mac1 & 0xff000000) >> 24);
+	wl->fuse_nic_addr = (mac1 & 0xffffff);
+
+	wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
+}
+
+static int wl18xx_handle_static_data(struct wl1271 *wl,
+				     struct wl1271_static_data *static_data)
+{
+	struct wl18xx_static_data_priv *static_data_priv =
+		(struct wl18xx_static_data_priv *) static_data->priv;
+
+	wl1271_info("PHY firmware version: %s", static_data_priv->phy_version);
+
+	return 0;
+}
+
+static int wl18xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
+{
+	struct wl18xx_priv *priv = wl->priv;
+
+	/* If we have VIFs requiring extra spare, indulge them */
+	if (priv->extra_spare_vif_count)
+		return WL18XX_TX_HW_EXTRA_BLOCK_SPARE;
+
+	return WL18XX_TX_HW_BLOCK_SPARE;
+}
+
+static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
+			  struct ieee80211_vif *vif,
+			  struct ieee80211_sta *sta,
+			  struct ieee80211_key_conf *key_conf)
+{
+	struct wl18xx_priv *priv = wl->priv;
+	bool change_spare = false;
+	int ret;
+
+	/*
+	 * when adding the first or removing the last GEM/TKIP interface,
+	 * we have to adjust the number of spare blocks.
+	 */
+	change_spare = (key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
+		key_conf->cipher == WLAN_CIPHER_SUITE_TKIP) &&
+		((priv->extra_spare_vif_count == 0 && cmd == SET_KEY) ||
+		 (priv->extra_spare_vif_count == 1 && cmd == DISABLE_KEY));
+
+	/* no need to change spare - just regular set_key */
+	if (!change_spare)
+		return wlcore_set_key(wl, cmd, vif, sta, key_conf);
+
+	/*
+	 * stop the queues and flush to ensure the next packets are
+	 * in sync with FW spare block accounting
+	 */
+	wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
+	wl1271_tx_flush(wl);
+
+	ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
+	if (ret < 0)
+		goto out;
+
+	/* key is now set, change the spare blocks */
+	if (cmd == SET_KEY) {
+		ret = wl18xx_set_host_cfg_bitmap(wl,
+					WL18XX_TX_HW_EXTRA_BLOCK_SPARE);
+		if (ret < 0)
+			goto out;
+
+		priv->extra_spare_vif_count++;
+	} else {
+		ret = wl18xx_set_host_cfg_bitmap(wl,
+					WL18XX_TX_HW_BLOCK_SPARE);
+		if (ret < 0)
+			goto out;
+
+		priv->extra_spare_vif_count--;
+	}
+
+out:
+	wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
+	return ret;
+}
+
+static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
+			       u32 buf_offset, u32 last_len)
+{
+	if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) {
+		struct wl1271_tx_hw_descr *last_desc;
+
+		/* get the last TX HW descriptor written to the aggr buf */
+		last_desc = (struct wl1271_tx_hw_descr *)(wl->aggr_buf +
+							buf_offset - last_len);
+
+		/* the last frame is padded up to an SDIO block */
+		last_desc->wl18xx_mem.ctrl &= ~WL18XX_TX_CTRL_NOT_PADDED;
+		return ALIGN(buf_offset, WL12XX_BUS_BLOCK_SIZE);
+	}
+
+	/* no modifications */
+	return buf_offset;
+}
+
+static struct wlcore_ops wl18xx_ops = {
+	.identify_chip	= wl18xx_identify_chip,
+	.boot		= wl18xx_boot,
+	.plt_init	= wl18xx_plt_init,
+	.trigger_cmd	= wl18xx_trigger_cmd,
+	.ack_event	= wl18xx_ack_event,
+	.calc_tx_blocks = wl18xx_calc_tx_blocks,
+	.set_tx_desc_blocks = wl18xx_set_tx_desc_blocks,
+	.set_tx_desc_data_len = wl18xx_set_tx_desc_data_len,
+	.get_rx_buf_align = wl18xx_get_rx_buf_align,
+	.get_rx_packet_len = wl18xx_get_rx_packet_len,
+	.tx_immediate_compl = wl18xx_tx_immediate_completion,
+	.tx_delayed_compl = NULL,
+	.hw_init	= wl18xx_hw_init,
+	.set_tx_desc_csum = wl18xx_set_tx_desc_csum,
+	.get_pg_ver	= wl18xx_get_pg_ver,
+	.set_rx_csum = wl18xx_set_rx_csum,
+	.sta_get_ap_rate_mask = wl18xx_sta_get_ap_rate_mask,
+	.ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask,
+	.get_mac	= wl18xx_get_mac,
+	.debugfs_init	= wl18xx_debugfs_add_files,
+	.handle_static_data	= wl18xx_handle_static_data,
+	.get_spare_blocks = wl18xx_get_spare_blocks,
+	.set_key	= wl18xx_set_key,
+	.pre_pkt_send	= wl18xx_pre_pkt_send,
+};
+
+/* HT cap appropriate for wide channels in 2Ghz */
+static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = {
+	.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
+	       IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40,
+	.ht_supported = true,
+	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
+	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+	.mcs = {
+		.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+		.rx_highest = cpu_to_le16(150),
+		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
+		},
+};
+
+/* HT cap appropriate for wide channels in 5Ghz */
+static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = {
+	.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
+	       IEEE80211_HT_CAP_SUP_WIDTH_20_40,
+	.ht_supported = true,
+	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
+	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+	.mcs = {
+		.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+		.rx_highest = cpu_to_le16(150),
+		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
+		},
+};
+
+/* HT cap appropriate for SISO 20 */
+static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = {
+	.cap = IEEE80211_HT_CAP_SGI_20,
+	.ht_supported = true,
+	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
+	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+	.mcs = {
+		.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+		.rx_highest = cpu_to_le16(72),
+		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
+		},
+};
+
+/* HT cap appropriate for MIMO rates in 20mhz channel */
+static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = {
+	.cap = IEEE80211_HT_CAP_SGI_20,
+	.ht_supported = true,
+	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
+	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+	.mcs = {
+		.rx_mask = { 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, },
+		.rx_highest = cpu_to_le16(144),
+		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
+		},
+};
+
+static int __devinit wl18xx_probe(struct platform_device *pdev)
+{
+	struct wl1271 *wl;
+	struct ieee80211_hw *hw;
+	struct wl18xx_priv *priv;
+	int ret;
+
+	hw = wlcore_alloc_hw(sizeof(*priv));
+	if (IS_ERR(hw)) {
+		wl1271_error("can't allocate hw");
+		ret = PTR_ERR(hw);
+		goto out;
+	}
+
+	wl = hw->priv;
+	priv = wl->priv;
+	wl->ops = &wl18xx_ops;
+	wl->ptable = wl18xx_ptable;
+	wl->rtable = wl18xx_rtable;
+	wl->num_tx_desc = 32;
+	wl->num_rx_desc = 32;
+	wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
+	wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
+	wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0;
+	wl->fw_status_priv_len = sizeof(struct wl18xx_fw_status_priv);
+	wl->stats.fw_stats_len = sizeof(struct wl18xx_acx_statistics);
+	wl->static_data_priv_len = sizeof(struct wl18xx_static_data_priv);
+
+	if (num_rx_desc_param != -1)
+		wl->num_rx_desc = num_rx_desc_param;
+
+	ret = wl18xx_conf_init(wl, &pdev->dev);
+	if (ret < 0)
+		goto out_free;
+
+	if (!strcmp(board_type_param, "fpga")) {
+		priv->conf.phy.board_type = BOARD_TYPE_FPGA_18XX;
+	} else if (!strcmp(board_type_param, "hdk")) {
+		priv->conf.phy.board_type = BOARD_TYPE_HDK_18XX;
+		/* HACK! Just for now we hardcode HDK to 0x06 */
+		priv->conf.phy.low_band_component_type = 0x06;
+	} else if (!strcmp(board_type_param, "dvp")) {
+		priv->conf.phy.board_type = BOARD_TYPE_DVP_18XX;
+	} else if (!strcmp(board_type_param, "evb")) {
+		priv->conf.phy.board_type = BOARD_TYPE_EVB_18XX;
+	} else if (!strcmp(board_type_param, "com8")) {
+		priv->conf.phy.board_type = BOARD_TYPE_COM8_18XX;
+		/* HACK! Just for now we hardcode COM8 to 0x06 */
+		priv->conf.phy.low_band_component_type = 0x06;
+	} else {
+		wl1271_error("invalid board type '%s'", board_type_param);
+		ret = -EINVAL;
+		goto out_free;
+	}
+
+	/* If the module param is set, update it in conf */
+	if (low_band_component_param != -1)
+		priv->conf.phy.low_band_component = low_band_component_param;
+	if (low_band_component_type_param != -1)
+		priv->conf.phy.low_band_component_type =
+			low_band_component_type_param;
+	if (high_band_component_param != -1)
+		priv->conf.phy.high_band_component = high_band_component_param;
+	if (high_band_component_type_param != -1)
+		priv->conf.phy.high_band_component_type =
+			high_band_component_type_param;
+	if (pwr_limit_reference_11_abg_param != -1)
+		priv->conf.phy.pwr_limit_reference_11_abg =
+			pwr_limit_reference_11_abg_param;
+	if (n_antennas_2_param != -1)
+		priv->conf.phy.number_of_assembled_ant2_4 = n_antennas_2_param;
+	if (n_antennas_5_param != -1)
+		priv->conf.phy.number_of_assembled_ant5 = n_antennas_5_param;
+	if (dc2dc_param != -1)
+		priv->conf.phy.external_pa_dc2dc = dc2dc_param;
+
+	if (!strcmp(ht_mode_param, "default")) {
+		/*
+		 * Only support mimo with multiple antennas. Fall back to
+		 * siso20.
+		 */
+		if (priv->conf.phy.number_of_assembled_ant2_4 >= 2)
+			wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
+					  &wl18xx_mimo_ht_cap_2ghz);
+		else
+			wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
+					  &wl18xx_siso20_ht_cap);
+
+		/* 5Ghz is always wide */
+		wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
+				  &wl18xx_siso40_ht_cap_5ghz);
+	} else if (!strcmp(ht_mode_param, "wide")) {
+		wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
+				  &wl18xx_siso40_ht_cap_2ghz);
+		wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
+				  &wl18xx_siso40_ht_cap_5ghz);
+	} else if (!strcmp(ht_mode_param, "siso20")) {
+		wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
+				  &wl18xx_siso20_ht_cap);
+		wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
+				  &wl18xx_siso20_ht_cap);
+	} else {
+		wl1271_error("invalid ht_mode '%s'", ht_mode_param);
+		ret = -EINVAL;
+		goto out_free;
+	}
+
+	if (!checksum_param) {
+		wl18xx_ops.set_rx_csum = NULL;
+		wl18xx_ops.init_vif = NULL;
+	}
+
+	wl->enable_11a = enable_11a_param;
+
+	return wlcore_probe(wl, pdev);
+
+out_free:
+	wlcore_free_hw(wl);
+out:
+	return ret;
+}
+
+static const struct platform_device_id wl18xx_id_table[] __devinitconst = {
+	{ "wl18xx", 0 },
+	{  } /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(platform, wl18xx_id_table);
+
+static struct platform_driver wl18xx_driver = {
+	.probe		= wl18xx_probe,
+	.remove		= __devexit_p(wlcore_remove),
+	.id_table	= wl18xx_id_table,
+	.driver = {
+		.name	= "wl18xx_driver",
+		.owner	= THIS_MODULE,
+	}
+};
+
+static int __init wl18xx_init(void)
+{
+	return platform_driver_register(&wl18xx_driver);
+}
+module_init(wl18xx_init);
+
+static void __exit wl18xx_exit(void)
+{
+	platform_driver_unregister(&wl18xx_driver);
+}
+module_exit(wl18xx_exit);
+
+module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR);
+MODULE_PARM_DESC(ht_mode, "Force HT mode: wide or siso20");
+
+module_param_named(board_type, board_type_param, charp, S_IRUSR);
+MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or "
+		 "dvp");
+
+module_param_named(checksum, checksum_param, bool, S_IRUSR);
+MODULE_PARM_DESC(checksum, "Enable TCP checksum: boolean (defaults to false)");
+
+module_param_named(enable_11a, enable_11a_param, bool, S_IRUSR);
+MODULE_PARM_DESC(enable_11a, "Enable 11a (5GHz): boolean (defaults to true)");
+
+module_param_named(dc2dc, dc2dc_param, int, S_IRUSR);
+MODULE_PARM_DESC(dc2dc, "External DC2DC: u8 (defaults to 0)");
+
+module_param_named(n_antennas_2, n_antennas_2_param, int, S_IRUSR);
+MODULE_PARM_DESC(n_antennas_2,
+		 "Number of installed 2.4GHz antennas: 1 (default) or 2");
+
+module_param_named(n_antennas_5, n_antennas_5_param, int, S_IRUSR);
+MODULE_PARM_DESC(n_antennas_5,
+		 "Number of installed 5GHz antennas: 1 (default) or 2");
+
+module_param_named(low_band_component, low_band_component_param, int,
+		   S_IRUSR);
+MODULE_PARM_DESC(low_band_component, "Low band component: u8 "
+		 "(default is 0x01)");
+
+module_param_named(low_band_component_type, low_band_component_type_param,
+		   int, S_IRUSR);
+MODULE_PARM_DESC(low_band_component_type, "Low band component type: u8 "
+		 "(default is 0x05 or 0x06 depending on the board_type)");
+
+module_param_named(high_band_component, high_band_component_param, int,
+		   S_IRUSR);
+MODULE_PARM_DESC(high_band_component, "High band component: u8, "
+		 "(default is 0x01)");
+
+module_param_named(high_band_component_type, high_band_component_type_param,
+		   int, S_IRUSR);
+MODULE_PARM_DESC(high_band_component_type, "High band component type: u8 "
+		 "(default is 0x09)");
+
+module_param_named(pwr_limit_reference_11_abg,
+		   pwr_limit_reference_11_abg_param, int, S_IRUSR);
+MODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 "
+		 "(default is 0xc8)");
+
+module_param_named(num_rx_desc,
+		   num_rx_desc_param, int, S_IRUSR);
+MODULE_PARM_DESC(num_rx_desc_param,
+		 "Number of Rx descriptors: u8 (default is 32)");
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
+MODULE_FIRMWARE(WL18XX_FW_NAME);
diff --git a/drivers/net/wireless/ti/wl18xx/reg.h b/drivers/net/wireless/ti/wl18xx/reg.h
new file mode 100644
index 0000000..937b71d
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/reg.h
@@ -0,0 +1,191 @@
+/*
+ * This file is part of wlcore
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __REG_H__
+#define __REG_H__
+
+#define WL18XX_REGISTERS_BASE      0x00800000
+#define WL18XX_CODE_BASE           0x00000000
+#define WL18XX_DATA_BASE           0x00400000
+#define WL18XX_DOUBLE_BUFFER_BASE  0x00600000
+#define WL18XX_MCU_KEY_SEARCH_BASE 0x00700000
+#define WL18XX_PHY_BASE            0x00900000
+#define WL18XX_TOP_OCP_BASE        0x00A00000
+#define WL18XX_PACKET_RAM_BASE     0x00B00000
+#define WL18XX_HOST_BASE           0x00C00000
+
+#define WL18XX_REGISTERS_DOWN_SIZE 0x0000B000
+
+#define WL18XX_REG_BOOT_PART_START 0x00802000
+#define WL18XX_REG_BOOT_PART_SIZE  0x00014578
+
+#define WL18XX_PHY_INIT_MEM_ADDR   0x80926000
+
+#define WL18XX_SDIO_WSPI_BASE		(WL18XX_REGISTERS_BASE)
+#define WL18XX_REG_CONFIG_BASE		(WL18XX_REGISTERS_BASE + 0x02000)
+#define WL18XX_WGCM_REGS_BASE		(WL18XX_REGISTERS_BASE + 0x03000)
+#define WL18XX_ENC_BASE			(WL18XX_REGISTERS_BASE + 0x04000)
+#define WL18XX_INTERRUPT_BASE		(WL18XX_REGISTERS_BASE + 0x05000)
+#define WL18XX_UART_BASE		(WL18XX_REGISTERS_BASE + 0x06000)
+#define WL18XX_WELP_BASE		(WL18XX_REGISTERS_BASE + 0x07000)
+#define WL18XX_TCP_CKSM_BASE		(WL18XX_REGISTERS_BASE + 0x08000)
+#define WL18XX_FIFO_BASE		(WL18XX_REGISTERS_BASE + 0x09000)
+#define WL18XX_OCP_BRIDGE_BASE		(WL18XX_REGISTERS_BASE + 0x0A000)
+#define WL18XX_PMAC_RX_BASE		(WL18XX_REGISTERS_BASE + 0x14800)
+#define WL18XX_PMAC_ACM_BASE		(WL18XX_REGISTERS_BASE + 0x14C00)
+#define WL18XX_PMAC_TX_BASE		(WL18XX_REGISTERS_BASE + 0x15000)
+#define WL18XX_PMAC_CSR_BASE		(WL18XX_REGISTERS_BASE + 0x15400)
+
+#define WL18XX_REG_ECPU_CONTROL		(WL18XX_REGISTERS_BASE + 0x02004)
+#define WL18XX_REG_INTERRUPT_NO_CLEAR	(WL18XX_REGISTERS_BASE + 0x050E8)
+#define WL18XX_REG_INTERRUPT_ACK	(WL18XX_REGISTERS_BASE + 0x050F0)
+#define WL18XX_REG_INTERRUPT_TRIG	(WL18XX_REGISTERS_BASE + 0x5074)
+#define WL18XX_REG_INTERRUPT_TRIG_H	(WL18XX_REGISTERS_BASE + 0x5078)
+#define WL18XX_REG_INTERRUPT_MASK	(WL18XX_REGISTERS_BASE + 0x0050DC)
+
+#define WL18XX_REG_CHIP_ID_B		(WL18XX_REGISTERS_BASE + 0x01542C)
+
+#define WL18XX_SLV_MEM_DATA		(WL18XX_HOST_BASE + 0x0018)
+#define WL18XX_SLV_REG_DATA		(WL18XX_HOST_BASE + 0x0008)
+
+/* Scratch Pad registers*/
+#define WL18XX_SCR_PAD0			(WL18XX_REGISTERS_BASE + 0x0154EC)
+#define WL18XX_SCR_PAD1			(WL18XX_REGISTERS_BASE + 0x0154F0)
+#define WL18XX_SCR_PAD2			(WL18XX_REGISTERS_BASE + 0x0154F4)
+#define WL18XX_SCR_PAD3			(WL18XX_REGISTERS_BASE + 0x0154F8)
+#define WL18XX_SCR_PAD4			(WL18XX_REGISTERS_BASE + 0x0154FC)
+#define WL18XX_SCR_PAD4_SET		(WL18XX_REGISTERS_BASE + 0x015504)
+#define WL18XX_SCR_PAD4_CLR		(WL18XX_REGISTERS_BASE + 0x015500)
+#define WL18XX_SCR_PAD5			(WL18XX_REGISTERS_BASE + 0x015508)
+#define WL18XX_SCR_PAD5_SET		(WL18XX_REGISTERS_BASE + 0x015510)
+#define WL18XX_SCR_PAD5_CLR		(WL18XX_REGISTERS_BASE + 0x01550C)
+#define WL18XX_SCR_PAD6			(WL18XX_REGISTERS_BASE + 0x015514)
+#define WL18XX_SCR_PAD7			(WL18XX_REGISTERS_BASE + 0x015518)
+#define WL18XX_SCR_PAD8			(WL18XX_REGISTERS_BASE + 0x01551C)
+#define WL18XX_SCR_PAD9			(WL18XX_REGISTERS_BASE + 0x015520)
+
+/* Spare registers*/
+#define WL18XX_SPARE_A1			(WL18XX_REGISTERS_BASE + 0x002194)
+#define WL18XX_SPARE_A2			(WL18XX_REGISTERS_BASE + 0x002198)
+#define WL18XX_SPARE_A3			(WL18XX_REGISTERS_BASE + 0x00219C)
+#define WL18XX_SPARE_A4			(WL18XX_REGISTERS_BASE + 0x0021A0)
+#define WL18XX_SPARE_A5			(WL18XX_REGISTERS_BASE + 0x0021A4)
+#define WL18XX_SPARE_A6			(WL18XX_REGISTERS_BASE + 0x0021A8)
+#define WL18XX_SPARE_A7			(WL18XX_REGISTERS_BASE + 0x0021AC)
+#define WL18XX_SPARE_A8			(WL18XX_REGISTERS_BASE + 0x0021B0)
+#define WL18XX_SPARE_B1			(WL18XX_REGISTERS_BASE + 0x015524)
+#define WL18XX_SPARE_B2			(WL18XX_REGISTERS_BASE + 0x015528)
+#define WL18XX_SPARE_B3			(WL18XX_REGISTERS_BASE + 0x01552C)
+#define WL18XX_SPARE_B4			(WL18XX_REGISTERS_BASE + 0x015530)
+#define WL18XX_SPARE_B5			(WL18XX_REGISTERS_BASE + 0x015534)
+#define WL18XX_SPARE_B6			(WL18XX_REGISTERS_BASE + 0x015538)
+#define WL18XX_SPARE_B7			(WL18XX_REGISTERS_BASE + 0x01553C)
+#define WL18XX_SPARE_B8			(WL18XX_REGISTERS_BASE + 0x015540)
+
+#define WL18XX_REG_COMMAND_MAILBOX_PTR	(WL18XX_SCR_PAD0)
+#define WL18XX_REG_EVENT_MAILBOX_PTR	(WL18XX_SCR_PAD1)
+#define WL18XX_EEPROMLESS_IND		(WL18XX_SCR_PAD4)
+
+#define WL18XX_WELP_ARM_COMMAND		(WL18XX_REGISTERS_BASE + 0x7100)
+#define WL18XX_ENABLE			(WL18XX_REGISTERS_BASE + 0x01543C)
+
+/* PRCM registers */
+#define PLATFORM_DETECTION		0xA0E3E0
+#define OCS_EN				0xA02080
+#define PRIMARY_CLK_DETECT		0xA020A6
+#define PLLSH_WCS_PLL_N			0xA02362
+#define PLLSH_WCS_PLL_M			0xA02360
+#define PLLSH_WCS_PLL_Q_FACTOR_CFG_1	0xA02364
+#define PLLSH_WCS_PLL_Q_FACTOR_CFG_2	0xA02366
+#define PLLSH_WCS_PLL_P_FACTOR_CFG_1	0xA02368
+#define PLLSH_WCS_PLL_P_FACTOR_CFG_2	0xA0236A
+#define PLLSH_WCS_PLL_SWALLOW_EN	0xA0236C
+#define PLLSH_WL_PLL_EN			0xA02392
+
+#define PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK	0xFFFF
+#define PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK	0x007F
+#define PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK	0xFFFF
+#define PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK	0x000F
+
+#define PLLSH_WCS_PLL_SWALLOW_EN_VAL1	0x1
+#define PLLSH_WCS_PLL_SWALLOW_EN_VAL2	0x12
+
+#define WL18XX_REG_FUSE_DATA_1_3	0xA0260C
+#define WL18XX_PG_VER_MASK		0x70
+#define WL18XX_PG_VER_OFFSET		4
+
+#define WL18XX_REG_FUSE_BD_ADDR_1	0xA02602
+#define WL18XX_REG_FUSE_BD_ADDR_2	0xA02606
+
+#define WL18XX_CMD_MBOX_ADDRESS		0xB007B4
+
+#define WL18XX_FW_STATUS_ADDR		0x50F8
+
+#define CHIP_ID_185x_PG10              (0x06030101)
+#define CHIP_ID_185x_PG20              (0x06030111)
+
+/*
+ * Host Command Interrupt. Setting this bit masks
+ * the interrupt that the host issues to inform
+ * the FW that it has sent a command
+ * to the Wlan hardware Command Mailbox.
+ */
+#define WL18XX_INTR_TRIG_CMD       BIT(28)
+
+/*
+ * Host Event Acknowlegde Interrupt. The host
+ * sets this bit to acknowledge that it received
+ * the unsolicited information from the event
+ * mailbox.
+ */
+#define WL18XX_INTR_TRIG_EVENT_ACK BIT(29)
+
+/*
+ * To boot the firmware in PLT mode we need to write this value in
+ * SCR_PAD8 before starting.
+ */
+#define WL18XX_SCR_PAD8_PLT	0xBABABEBE
+
+enum {
+	COMPONENT_NO_SWITCH	= 0x0,
+	COMPONENT_2_WAY_SWITCH	= 0x1,
+	COMPONENT_3_WAY_SWITCH	= 0x2,
+	COMPONENT_MATCHING	= 0x3,
+};
+
+enum {
+	FEM_NONE	= 0x0,
+	FEM_VENDOR_1	= 0x1,
+	FEM_VENDOR_2	= 0x2,
+	FEM_VENDOR_3	= 0x3,
+};
+
+enum {
+	BOARD_TYPE_EVB_18XX     = 0,
+	BOARD_TYPE_DVP_18XX     = 1,
+	BOARD_TYPE_HDK_18XX     = 2,
+	BOARD_TYPE_FPGA_18XX    = 3,
+	BOARD_TYPE_COM8_18XX    = 4,
+
+	NUM_BOARD_TYPES,
+};
+
+#endif /* __REG_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/tx.c b/drivers/net/wireless/ti/wl18xx/tx.c
new file mode 100644
index 0000000..5b1fb10
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/tx.c
@@ -0,0 +1,127 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/acx.h"
+#include "../wlcore/tx.h"
+
+#include "wl18xx.h"
+#include "tx.h"
+
+static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
+{
+	struct ieee80211_tx_info *info;
+	struct sk_buff *skb;
+	int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK;
+	bool tx_success;
+
+	/* check for id legality */
+	if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) {
+		wl1271_warning("illegal id in tx completion: %d", id);
+		return;
+	}
+
+	/* a zero bit indicates Tx success */
+	tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX));
+
+
+	skb = wl->tx_frames[id];
+	info = IEEE80211_SKB_CB(skb);
+
+	if (wl12xx_is_dummy_packet(wl, skb)) {
+		wl1271_free_tx_id(wl, id);
+		return;
+	}
+
+	/* update the TX status info */
+	if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK))
+		info->flags |= IEEE80211_TX_STAT_ACK;
+
+	/* no real data about Tx completion */
+	info->status.rates[0].idx = -1;
+	info->status.rates[0].count = 0;
+	info->status.rates[0].flags = 0;
+	info->status.ack_signal = -1;
+
+	if (!tx_success)
+		wl->stats.retry_count++;
+
+	/*
+	 * TODO: update sequence number for encryption? seems to be
+	 * unsupported for now. needed for recovery with encryption.
+	 */
+
+	/* remove private header from packet */
+	skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+
+	/* remove TKIP header space if present */
+	if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
+	    info->control.hw_key &&
+	    info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+		int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+		memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, hdrlen);
+		skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
+	}
+
+	wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p success %d",
+		     id, skb, tx_success);
+
+	/* return the packet to the stack */
+	skb_queue_tail(&wl->deferred_tx_queue, skb);
+	queue_work(wl->freezable_wq, &wl->netstack_work);
+	wl1271_free_tx_id(wl, id);
+}
+
+void wl18xx_tx_immediate_complete(struct wl1271 *wl)
+{
+	struct wl18xx_fw_status_priv *status_priv =
+		(struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
+	struct wl18xx_priv *priv = wl->priv;
+	u8 i;
+
+	/* nothing to do here */
+	if (priv->last_fw_rls_idx == status_priv->fw_release_idx)
+		return;
+
+	/* freed Tx descriptors */
+	wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d",
+		     priv->last_fw_rls_idx, status_priv->fw_release_idx);
+
+	if (status_priv->fw_release_idx >= WL18XX_FW_MAX_TX_STATUS_DESC) {
+		wl1271_error("invalid desc release index %d",
+			     status_priv->fw_release_idx);
+		WARN_ON(1);
+		return;
+	}
+
+	for (i = priv->last_fw_rls_idx;
+	     i != status_priv->fw_release_idx;
+	     i = (i + 1) % WL18XX_FW_MAX_TX_STATUS_DESC) {
+		wl18xx_tx_complete_packet(wl,
+			status_priv->released_tx_desc[i]);
+
+		wl->tx_results_count++;
+	}
+
+	priv->last_fw_rls_idx = status_priv->fw_release_idx;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/tx.h b/drivers/net/wireless/ti/wl18xx/tx.h
new file mode 100644
index 0000000..ccddc54
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/tx.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have 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 __WL18XX_TX_H__
+#define __WL18XX_TX_H__
+
+#include "../wlcore/wlcore.h"
+
+#define WL18XX_TX_HW_BLOCK_SPARE        1
+/* for special cases - namely, TKIP and GEM */
+#define WL18XX_TX_HW_EXTRA_BLOCK_SPARE  2
+#define WL18XX_TX_HW_BLOCK_SIZE         268
+
+#define WL18XX_TX_STATUS_DESC_ID_MASK    0x7F
+#define WL18XX_TX_STATUS_STAT_BIT_IDX    7
+
+/* Indicates this TX HW frame is not padded to SDIO block size */
+#define WL18XX_TX_CTRL_NOT_PADDED	BIT(7)
+
+/*
+ * The FW uses a special bit to indicate a wide channel should be used in
+ * the rate policy.
+ */
+#define CONF_TX_RATE_USE_WIDE_CHAN BIT(31)
+
+void wl18xx_tx_immediate_complete(struct wl1271 *wl);
+
+#endif /* __WL12XX_TX_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
new file mode 100644
index 0000000..bc67a47
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
@@ -0,0 +1,88 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL18XX_PRIV_H__
+#define __WL18XX_PRIV_H__
+
+#include "conf.h"
+
+#define WL18XX_CMD_MAX_SIZE          740
+
+struct wl18xx_priv {
+	/* buffer for sending commands to FW */
+	u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
+
+	struct wl18xx_priv_conf conf;
+
+	/* Index of last released Tx desc in FW */
+	u8 last_fw_rls_idx;
+
+	/* number of VIFs requiring extra spare mem-blocks */
+	int extra_spare_vif_count;
+};
+
+#define WL18XX_FW_MAX_TX_STATUS_DESC 33
+
+struct wl18xx_fw_status_priv {
+	/*
+	 * Index in released_tx_desc for first byte that holds
+	 * released tx host desc
+	 */
+	u8 fw_release_idx;
+
+	/*
+	 * Array of host Tx descriptors, where fw_release_idx
+	 * indicated the first released idx.
+	 */
+	u8 released_tx_desc[WL18XX_FW_MAX_TX_STATUS_DESC];
+
+	u8 padding[2];
+};
+
+#define WL18XX_PHY_VERSION_MAX_LEN 20
+
+struct wl18xx_static_data_priv {
+	char phy_version[WL18XX_PHY_VERSION_MAX_LEN];
+};
+
+struct wl18xx_clk_cfg {
+	u32 n;
+	u32 m;
+	u32 p;
+	u32 q;
+	bool swallow;
+};
+
+enum {
+	CLOCK_CONFIG_16_2_M	= 1,
+	CLOCK_CONFIG_16_368_M,
+	CLOCK_CONFIG_16_8_M,
+	CLOCK_CONFIG_19_2_M,
+	CLOCK_CONFIG_26_M,
+	CLOCK_CONFIG_32_736_M,
+	CLOCK_CONFIG_33_6_M,
+	CLOCK_CONFIG_38_468_M,
+	CLOCK_CONFIG_52_M,
+
+	NUM_CLOCK_CONFIGS,
+};
+
+#endif /* __WL18XX_PRIV_H__ */
diff --git a/drivers/net/wireless/ti/wlcore/Kconfig b/drivers/net/wireless/ti/wlcore/Kconfig
index 54156b0..d7b907e 100644
--- a/drivers/net/wireless/ti/wlcore/Kconfig
+++ b/drivers/net/wireless/ti/wlcore/Kconfig
@@ -1,7 +1,6 @@
 config WLCORE
 	tristate "TI wlcore support"
 	depends on WL_TI && GENERIC_HARDIRQS && MAC80211
-	depends on INET
 	select FW_LOADER
 	---help---
 	  This module contains the main code for TI WLAN chips.  It abstracts
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c
index f3d6fa5..ce108a7 100644
--- a/drivers/net/wireless/ti/wlcore/acx.c
+++ b/drivers/net/wireless/ti/wlcore/acx.c
@@ -70,7 +70,7 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
 	struct acx_sleep_auth *auth;
 	int ret;
 
-	wl1271_debug(DEBUG_ACX, "acx sleep auth");
+	wl1271_debug(DEBUG_ACX, "acx sleep auth %d", sleep_auth);
 
 	auth = kzalloc(sizeof(*auth), GFP_KERNEL);
 	if (!auth) {
@@ -81,11 +81,18 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
 	auth->sleep_auth = sleep_auth;
 
 	ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
+	if (ret < 0) {
+		wl1271_error("could not configure sleep_auth to %d: %d",
+			     sleep_auth, ret);
+		goto out;
+	}
 
+	wl->sleep_auth = sleep_auth;
 out:
 	kfree(auth);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(wl1271_acx_sleep_auth);
 
 int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			int power)
@@ -708,14 +715,14 @@ out:
 	return ret;
 }
 
-int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
+int wl1271_acx_statistics(struct wl1271 *wl, void *stats)
 {
 	int ret;
 
 	wl1271_debug(DEBUG_ACX, "acx statistics");
 
 	ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats,
-				     sizeof(*stats));
+				     wl->stats.fw_stats_len);
 	if (ret < 0) {
 		wl1271_warning("acx statistics failed: %d", ret);
 		return -ENOMEM;
@@ -997,6 +1004,7 @@ out:
 	kfree(mem_conf);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(wl12xx_acx_mem_cfg);
 
 int wl1271_acx_init_mem_config(struct wl1271 *wl)
 {
@@ -1027,6 +1035,7 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(wl1271_acx_init_mem_config);
 
 int wl1271_acx_init_rx_interrupt(struct wl1271 *wl)
 {
@@ -1150,6 +1159,7 @@ out:
 	kfree(acx);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(wl1271_acx_pm_config);
 
 int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			       bool enable)
diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h
index e6a7486..d03215d 100644
--- a/drivers/net/wireless/ti/wlcore/acx.h
+++ b/drivers/net/wireless/ti/wlcore/acx.h
@@ -51,21 +51,18 @@
 #define WL1271_ACX_INTR_TRACE_A            BIT(7)
 /* Trace message on MBOX #B */
 #define WL1271_ACX_INTR_TRACE_B            BIT(8)
+/* SW FW Initiated interrupt Watchdog timer expiration */
+#define WL1271_ACX_SW_INTR_WATCHDOG        BIT(9)
 
-#define WL1271_ACX_INTR_ALL		   0xFFFFFFFF
-#define WL1271_ACX_ALL_EVENTS_VECTOR       (WL1271_ACX_INTR_WATCHDOG      | \
-					    WL1271_ACX_INTR_INIT_COMPLETE | \
-					    WL1271_ACX_INTR_EVENT_A       | \
-					    WL1271_ACX_INTR_EVENT_B       | \
-					    WL1271_ACX_INTR_CMD_COMPLETE  | \
-					    WL1271_ACX_INTR_HW_AVAILABLE  | \
-					    WL1271_ACX_INTR_DATA)
-
-#define WL1271_INTR_MASK                   (WL1271_ACX_INTR_WATCHDOG     | \
-					    WL1271_ACX_INTR_EVENT_A      | \
-					    WL1271_ACX_INTR_EVENT_B      | \
-					    WL1271_ACX_INTR_HW_AVAILABLE | \
-					    WL1271_ACX_INTR_DATA)
+#define WL1271_ACX_INTR_ALL             0xFFFFFFFF
+
+/* all possible interrupts - only appropriate ones will be masked in */
+#define WLCORE_ALL_INTR_MASK		(WL1271_ACX_INTR_WATCHDOG     | \
+					WL1271_ACX_INTR_EVENT_A       | \
+					WL1271_ACX_INTR_EVENT_B       | \
+					WL1271_ACX_INTR_HW_AVAILABLE  | \
+					WL1271_ACX_INTR_DATA          | \
+					WL1271_ACX_SW_INTR_WATCHDOG)
 
 /* Target's information element */
 struct acx_header {
@@ -121,6 +118,11 @@ enum wl1271_psm_mode {
 
 	/* Extreme low power */
 	WL1271_PSM_ELP = 2,
+
+	WL1271_PSM_MAX = WL1271_PSM_ELP,
+
+	/* illegal out of band value of PSM mode */
+	WL1271_PSM_ILLEGAL = 0xff
 };
 
 struct acx_sleep_auth {
@@ -417,228 +419,6 @@ struct acx_ctsprotect {
 	u8 padding[2];
 } __packed;
 
-struct acx_tx_statistics {
-	__le32 internal_desc_overflow;
-}  __packed;
-
-struct acx_rx_statistics {
-	__le32 out_of_mem;
-	__le32 hdr_overflow;
-	__le32 hw_stuck;
-	__le32 dropped;
-	__le32 fcs_err;
-	__le32 xfr_hint_trig;
-	__le32 path_reset;
-	__le32 reset_counter;
-} __packed;
-
-struct acx_dma_statistics {
-	__le32 rx_requested;
-	__le32 rx_errors;
-	__le32 tx_requested;
-	__le32 tx_errors;
-}  __packed;
-
-struct acx_isr_statistics {
-	/* host command complete */
-	__le32 cmd_cmplt;
-
-	/* fiqisr() */
-	__le32 fiqs;
-
-	/* (INT_STS_ND & INT_TRIG_RX_HEADER) */
-	__le32 rx_headers;
-
-	/* (INT_STS_ND & INT_TRIG_RX_CMPLT) */
-	__le32 rx_completes;
-
-	/* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */
-	__le32 rx_mem_overflow;
-
-	/* (INT_STS_ND & INT_TRIG_S_RX_RDY) */
-	__le32 rx_rdys;
-
-	/* irqisr() */
-	__le32 irqs;
-
-	/* (INT_STS_ND & INT_TRIG_TX_PROC) */
-	__le32 tx_procs;
-
-	/* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */
-	__le32 decrypt_done;
-
-	/* (INT_STS_ND & INT_TRIG_DMA0) */
-	__le32 dma0_done;
-
-	/* (INT_STS_ND & INT_TRIG_DMA1) */
-	__le32 dma1_done;
-
-	/* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */
-	__le32 tx_exch_complete;
-
-	/* (INT_STS_ND & INT_TRIG_COMMAND) */
-	__le32 commands;
-
-	/* (INT_STS_ND & INT_TRIG_RX_PROC) */
-	__le32 rx_procs;
-
-	/* (INT_STS_ND & INT_TRIG_PM_802) */
-	__le32 hw_pm_mode_changes;
-
-	/* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */
-	__le32 host_acknowledges;
-
-	/* (INT_STS_ND & INT_TRIG_PM_PCI) */
-	__le32 pci_pm;
-
-	/* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */
-	__le32 wakeups;
-
-	/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
-	__le32 low_rssi;
-} __packed;
-
-struct acx_wep_statistics {
-	/* WEP address keys configured */
-	__le32 addr_key_count;
-
-	/* default keys configured */
-	__le32 default_key_count;
-
-	__le32 reserved;
-
-	/* number of times that WEP key not found on lookup */
-	__le32 key_not_found;
-
-	/* number of times that WEP key decryption failed */
-	__le32 decrypt_fail;
-
-	/* WEP packets decrypted */
-	__le32 packets;
-
-	/* WEP decrypt interrupts */
-	__le32 interrupt;
-} __packed;
-
-#define ACX_MISSED_BEACONS_SPREAD 10
-
-struct acx_pwr_statistics {
-	/* the amount of enters into power save mode (both PD & ELP) */
-	__le32 ps_enter;
-
-	/* the amount of enters into ELP mode */
-	__le32 elp_enter;
-
-	/* the amount of missing beacon interrupts to the host */
-	__le32 missing_bcns;
-
-	/* the amount of wake on host-access times */
-	__le32 wake_on_host;
-
-	/* the amount of wake on timer-expire */
-	__le32 wake_on_timer_exp;
-
-	/* the number of packets that were transmitted with PS bit set */
-	__le32 tx_with_ps;
-
-	/* the number of packets that were transmitted with PS bit clear */
-	__le32 tx_without_ps;
-
-	/* the number of received beacons */
-	__le32 rcvd_beacons;
-
-	/* the number of entering into PowerOn (power save off) */
-	__le32 power_save_off;
-
-	/* the number of entries into power save mode */
-	__le16 enable_ps;
-
-	/*
-	 * the number of exits from power save, not including failed PS
-	 * transitions
-	 */
-	__le16 disable_ps;
-
-	/*
-	 * the number of times the TSF counter was adjusted because
-	 * of drift
-	 */
-	__le32 fix_tsf_ps;
-
-	/* Gives statistics about the spread continuous missed beacons.
-	 * The 16 LSB are dedicated for the PS mode.
-	 * The 16 MSB are dedicated for the PS mode.
-	 * cont_miss_bcns_spread[0] - single missed beacon.
-	 * cont_miss_bcns_spread[1] - two continuous missed beacons.
-	 * cont_miss_bcns_spread[2] - three continuous missed beacons.
-	 * ...
-	 * cont_miss_bcns_spread[9] - ten and more continuous missed beacons.
-	*/
-	__le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
-
-	/* the number of beacons in awake mode */
-	__le32 rcvd_awake_beacons;
-} __packed;
-
-struct acx_mic_statistics {
-	__le32 rx_pkts;
-	__le32 calc_failure;
-} __packed;
-
-struct acx_aes_statistics {
-	__le32 encrypt_fail;
-	__le32 decrypt_fail;
-	__le32 encrypt_packets;
-	__le32 decrypt_packets;
-	__le32 encrypt_interrupt;
-	__le32 decrypt_interrupt;
-} __packed;
-
-struct acx_event_statistics {
-	__le32 heart_beat;
-	__le32 calibration;
-	__le32 rx_mismatch;
-	__le32 rx_mem_empty;
-	__le32 rx_pool;
-	__le32 oom_late;
-	__le32 phy_transmit_error;
-	__le32 tx_stuck;
-} __packed;
-
-struct acx_ps_statistics {
-	__le32 pspoll_timeouts;
-	__le32 upsd_timeouts;
-	__le32 upsd_max_sptime;
-	__le32 upsd_max_apturn;
-	__le32 pspoll_max_apturn;
-	__le32 pspoll_utilization;
-	__le32 upsd_utilization;
-} __packed;
-
-struct acx_rxpipe_statistics {
-	__le32 rx_prep_beacon_drop;
-	__le32 descr_host_int_trig_rx_data;
-	__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;
-} __packed;
-
-struct acx_statistics {
-	struct acx_header header;
-
-	struct acx_tx_statistics tx;
-	struct acx_rx_statistics rx;
-	struct acx_dma_statistics dma;
-	struct acx_isr_statistics isr;
-	struct acx_wep_statistics wep;
-	struct acx_pwr_statistics pwr;
-	struct acx_aes_statistics aes;
-	struct acx_mic_statistics mic;
-	struct acx_event_statistics event;
-	struct acx_ps_statistics ps;
-	struct acx_rxpipe_statistics rxpipe;
-} __packed;
-
 struct acx_rate_class {
 	__le32 enabled_rates;
 	u8 short_retry_limit;
@@ -828,6 +608,8 @@ struct wl1271_acx_keep_alive_config {
 #define HOST_IF_CFG_RX_FIFO_ENABLE     BIT(0)
 #define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
 #define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3)
+#define HOST_IF_CFG_RX_PAD_TO_SDIO_BLK BIT(4)
+#define HOST_IF_CFG_ADD_RX_ALIGNMENT   BIT(6)
 
 enum {
 	WL1271_ACX_TRIG_TYPE_LEVEL = 0,
@@ -946,7 +728,7 @@ struct wl1271_acx_ht_information {
 	u8 padding[2];
 } __packed;
 
-#define RX_BA_MAX_SESSIONS 2
+#define RX_BA_MAX_SESSIONS 3
 
 struct wl1271_acx_ba_initiator_policy {
 	struct acx_header header;
@@ -1243,6 +1025,7 @@ enum {
 	ACX_CONFIG_HANGOVER              = 0x0042,
 	ACX_FEATURE_CFG                  = 0x0043,
 	ACX_PROTECTION_CFG               = 0x0044,
+	ACX_CHECKSUM_CONFIG              = 0x0045,
 };
 
 
@@ -1281,7 +1064,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			    enum acx_preamble_type preamble);
 int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			   enum acx_ctsprotect_type ctsprotect);
-int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
+int wl1271_acx_statistics(struct wl1271 *wl, void *stats);
 int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
 		      u8 idx);
diff --git a/drivers/net/wireless/ti/wlcore/boot.c b/drivers/net/wireless/ti/wlcore/boot.c
index 9b98230..0fda500 100644
--- a/drivers/net/wireless/ti/wlcore/boot.c
+++ b/drivers/net/wireless/ti/wlcore/boot.c
@@ -45,10 +45,17 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
 	wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
 }
 
-static int wlcore_parse_fw_ver(struct wl1271 *wl)
+static int wlcore_boot_parse_fw_ver(struct wl1271 *wl,
+				    struct wl1271_static_data *static_data)
 {
 	int ret;
 
+	strncpy(wl->chip.fw_ver_str, static_data->fw_version,
+		sizeof(wl->chip.fw_ver_str));
+
+	/* make sure the string is NULL-terminated */
+	wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
+
 	ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u",
 		     &wl->chip.fw_ver[0], &wl->chip.fw_ver[1],
 		     &wl->chip.fw_ver[2], &wl->chip.fw_ver[3],
@@ -57,43 +64,43 @@ static int wlcore_parse_fw_ver(struct wl1271 *wl)
 	if (ret != 5) {
 		wl1271_warning("fw version incorrect value");
 		memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	ret = wlcore_identify_fw(wl);
 	if (ret < 0)
-		return ret;
-
-	return 0;
+		goto out;
+out:
+	return ret;
 }
 
-static int wlcore_boot_fw_version(struct wl1271 *wl)
+static int wlcore_boot_static_data(struct wl1271 *wl)
 {
 	struct wl1271_static_data *static_data;
+	size_t len = sizeof(*static_data) + wl->static_data_priv_len;
 	int ret;
 
-	static_data = kmalloc(sizeof(*static_data), GFP_KERNEL | GFP_DMA);
+	static_data = kmalloc(len, GFP_KERNEL);
 	if (!static_data) {
-		wl1271_error("Couldn't allocate memory for static data!");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto out;
 	}
 
-	wl1271_read(wl, wl->cmd_box_addr, static_data, sizeof(*static_data),
-		    false);
-
-	strncpy(wl->chip.fw_ver_str, static_data->fw_version,
-		sizeof(wl->chip.fw_ver_str));
-
-	kfree(static_data);
+	wl1271_read(wl, wl->cmd_box_addr, static_data, len, false);
 
-	/* make sure the string is NULL-terminated */
-	wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
+	ret = wlcore_boot_parse_fw_ver(wl, static_data);
+	if (ret < 0)
+		goto out_free;
 
-	ret = wlcore_parse_fw_ver(wl);
+	ret = wlcore_handle_static_data(wl, static_data);
 	if (ret < 0)
-		return ret;
+		goto out_free;
 
-	return 0;
+out_free:
+	kfree(static_data);
+out:
+	return ret;
 }
 
 static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
@@ -204,8 +211,10 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
 	u32 dest_addr, val;
 	u8 *nvs_ptr, *nvs_aligned;
 
-	if (wl->nvs == NULL)
+	if (wl->nvs == NULL) {
+		wl1271_error("NVS file is needed during boot");
 		return -ENODEV;
+	}
 
 	if (wl->quirks & WLCORE_QUIRK_LEGACY_NVS) {
 		struct wl1271_nvs_file *nvs =
@@ -400,9 +409,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
 	wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
 		     wl->mbox_ptr[0], wl->mbox_ptr[1]);
 
-	ret = wlcore_boot_fw_version(wl);
+	ret = wlcore_boot_static_data(wl);
 	if (ret < 0) {
-		wl1271_error("couldn't boot firmware");
+		wl1271_error("error getting static data");
 		return ret;
 	}
 
diff --git a/drivers/net/wireless/ti/wlcore/boot.h b/drivers/net/wireless/ti/wlcore/boot.h
index 094981d..a525225 100644
--- a/drivers/net/wireless/ti/wlcore/boot.h
+++ b/drivers/net/wireless/ti/wlcore/boot.h
@@ -40,6 +40,7 @@ struct wl1271_static_data {
 	u8 fw_version[WL1271_FW_VERSION_MAX_LEN];
 	u32 hw_version;
 	u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS];
+	u8 priv[0];
 };
 
 /* number of times we try to read the INIT interrupt */
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 5b128a9..885364c 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -36,6 +36,7 @@
 #include "cmd.h"
 #include "event.h"
 #include "tx.h"
+#include "hw_ops.h"
 
 #define WL1271_CMD_FAST_POLL_COUNT       50
 
@@ -291,6 +292,23 @@ static int wl12xx_get_new_session_id(struct wl1271 *wl,
 	return wlvif->session_counter;
 }
 
+static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
+{
+	switch (nl_channel_type) {
+	case NL80211_CHAN_NO_HT:
+		return WLCORE_CHAN_NO_HT;
+	case NL80211_CHAN_HT20:
+		return WLCORE_CHAN_HT20;
+	case NL80211_CHAN_HT40MINUS:
+		return WLCORE_CHAN_HT40MINUS;
+	case NL80211_CHAN_HT40PLUS:
+		return WLCORE_CHAN_HT40PLUS;
+	default:
+		WARN_ON(1);
+		return WLCORE_CHAN_NO_HT;
+	}
+}
+
 static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
 				     struct wl12xx_vif *wlvif)
 {
@@ -407,6 +425,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 	memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len);
 	memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN);
 	cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
+	cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
 
 	if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
 		ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid);
@@ -482,6 +501,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 	struct wl12xx_cmd_role_start *cmd;
 	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
 	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+	u32 supported_rates;
 	int ret;
 
 	wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id);
@@ -519,6 +539,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 	/* FIXME: Change when adding DFS */
 	cmd->ap.reset_tsf = 1;  /* By default reset AP TSF */
 	cmd->channel = wlvif->channel;
+	cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
 
 	if (!bss_conf->hidden_ssid) {
 		/* take the SSID from the beacon for backward compatibility */
@@ -531,7 +552,13 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 		memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len);
 	}
 
-	cmd->ap.local_rates = cpu_to_le32(0xffffffff);
+	supported_rates = CONF_TX_AP_ENABLED_RATES | CONF_TX_MCS_RATES |
+		wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
+
+	wl1271_debug(DEBUG_CMD, "cmd role start ap with supported_rates 0x%08x",
+		     supported_rates);
+
+	cmd->ap.local_rates = cpu_to_le32(supported_rates);
 
 	switch (wlvif->band) {
 	case IEEE80211_BAND_2GHZ:
@@ -797,6 +824,7 @@ out:
 	kfree(cmd);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(wl1271_cmd_data_path);
 
 int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 		       u8 ps_mode, u16 auto_ps_timeout)
@@ -1018,7 +1046,7 @@ out:
 
 int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 {
-	int ret, extra;
+	int ret, extra = 0;
 	u16 fc;
 	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
 	struct sk_buff *skb;
@@ -1057,7 +1085,8 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 	/* encryption space */
 	switch (wlvif->encryption_type) {
 	case KEY_TKIP:
-		extra = WL1271_EXTRA_SPACE_TKIP;
+		if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE)
+			extra = WL1271_EXTRA_SPACE_TKIP;
 		break;
 	case KEY_AES:
 		extra = WL1271_EXTRA_SPACE_AES;
@@ -1346,13 +1375,18 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 
 	for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)
 		if (sta->wme && (sta->uapsd_queues & BIT(i)))
-			cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER;
+			cmd->psd_type[NUM_ACCESS_CATEGORIES_COPY-1-i] =
+					WL1271_PSD_UPSD_TRIGGER;
 		else
-			cmd->psd_type[i] = WL1271_PSD_LEGACY;
+			cmd->psd_type[NUM_ACCESS_CATEGORIES_COPY-1-i] =
+					WL1271_PSD_LEGACY;
+
 
 	sta_rates = sta->supp_rates[wlvif->band];
 	if (sta->ht_cap.ht_supported)
-		sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET;
+		sta_rates |=
+			(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
+			(sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
 
 	cmd->supported_rates =
 		cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates,
@@ -1573,19 +1607,25 @@ out:
 int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id)
 {
 	int ret = 0;
+	bool is_first_roc;
 
 	if (WARN_ON(test_bit(role_id, wl->roc_map)))
 		return 0;
 
+	is_first_roc = (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >=
+			WL12XX_MAX_ROLES);
+
 	ret = wl12xx_cmd_roc(wl, wlvif, role_id);
 	if (ret < 0)
 		goto out;
 
-	ret = wl1271_cmd_wait_for_event(wl,
-					REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
-	if (ret < 0) {
-		wl1271_error("cmd roc event completion error");
-		goto out;
+	if (is_first_roc) {
+		ret = wl1271_cmd_wait_for_event(wl,
+					   REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
+		if (ret < 0) {
+			wl1271_error("cmd roc event completion error");
+			goto out;
+		}
 	}
 
 	__set_bit(role_id, wl->roc_map);
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h
index a46ae07..c8a6510 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.h
+++ b/drivers/net/wireless/ti/wlcore/cmd.h
@@ -192,7 +192,7 @@ enum cmd_templ {
 #define WL1271_COMMAND_TIMEOUT     2000
 #define WL1271_CMD_TEMPL_DFLT_SIZE 252
 #define WL1271_CMD_TEMPL_MAX_SIZE  512
-#define WL1271_EVENT_TIMEOUT       750
+#define WL1271_EVENT_TIMEOUT       1000
 
 struct wl1271_cmd_header {
 	__le16 id;
@@ -266,13 +266,22 @@ enum wlcore_band {
 	WLCORE_BAND_MAX_RADIO		= 0x7F,
 };
 
+enum wlcore_channel_type {
+	WLCORE_CHAN_NO_HT,
+	WLCORE_CHAN_HT20,
+	WLCORE_CHAN_HT40MINUS,
+	WLCORE_CHAN_HT40PLUS
+};
+
 struct wl12xx_cmd_role_start {
 	struct wl1271_cmd_header header;
 
 	u8 role_id;
 	u8 band;
 	u8 channel;
-	u8 padding;
+
+	/* enum wlcore_channel_type */
+	u8 channel_type;
 
 	union {
 		struct {
@@ -643,4 +652,25 @@ struct wl12xx_cmd_stop_channel_switch {
 	struct wl1271_cmd_header header;
 } __packed;
 
+/* Used to check radio status after calibration */
+#define MAX_TLV_LENGTH		500
+#define TEST_CMD_P2G_CAL	2	/* TX BiP */
+
+struct wl1271_cmd_cal_p2g {
+	struct wl1271_cmd_header header;
+
+	struct wl1271_cmd_test_header test;
+
+	__le32 ver;
+	__le16 len;
+	u8 buf[MAX_TLV_LENGTH];
+	u8 type;
+	u8 padding;
+
+	__le16 radio_status;
+
+	u8 sub_band_mask;
+	u8 padding2;
+} __packed;
+
 #endif /* __WL1271_CMD_H__ */
diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h
index fef0db4..d77224f 100644
--- a/drivers/net/wireless/ti/wlcore/conf.h
+++ b/drivers/net/wireless/ti/wlcore/conf.h
@@ -45,7 +45,15 @@ enum {
 	CONF_HW_BIT_RATE_MCS_4   = BIT(17),
 	CONF_HW_BIT_RATE_MCS_5   = BIT(18),
 	CONF_HW_BIT_RATE_MCS_6   = BIT(19),
-	CONF_HW_BIT_RATE_MCS_7   = BIT(20)
+	CONF_HW_BIT_RATE_MCS_7   = BIT(20),
+	CONF_HW_BIT_RATE_MCS_8   = BIT(21),
+	CONF_HW_BIT_RATE_MCS_9   = BIT(22),
+	CONF_HW_BIT_RATE_MCS_10  = BIT(23),
+	CONF_HW_BIT_RATE_MCS_11  = BIT(24),
+	CONF_HW_BIT_RATE_MCS_12  = BIT(25),
+	CONF_HW_BIT_RATE_MCS_13  = BIT(26),
+	CONF_HW_BIT_RATE_MCS_14  = BIT(27),
+	CONF_HW_BIT_RATE_MCS_15  = BIT(28),
 };
 
 enum {
@@ -310,7 +318,7 @@ enum {
 struct conf_sg_settings {
 	u32 params[CONF_SG_PARAMS_MAX];
 	u8 state;
-};
+} __packed;
 
 enum conf_rx_queue_type {
 	CONF_RX_QUEUE_TYPE_LOW_PRIORITY,  /* All except the high priority */
@@ -394,7 +402,7 @@ struct conf_rx_settings {
 	 * Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY,
 	 */
 	u8 queue_type;
-};
+} __packed;
 
 #define CONF_TX_MAX_RATE_CLASSES       10
 
@@ -435,6 +443,12 @@ struct conf_rx_settings {
 	CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 |        \
 	CONF_HW_BIT_RATE_MCS_7)
 
+#define CONF_TX_MIMO_RATES (CONF_HW_BIT_RATE_MCS_8 |             \
+	CONF_HW_BIT_RATE_MCS_9 | CONF_HW_BIT_RATE_MCS_10 |       \
+	CONF_HW_BIT_RATE_MCS_11 | CONF_HW_BIT_RATE_MCS_12 |      \
+	CONF_HW_BIT_RATE_MCS_13 | CONF_HW_BIT_RATE_MCS_14 |      \
+	CONF_HW_BIT_RATE_MCS_15)
+
 /*
  * Default rates for management traffic when operating in AP mode. This
  * should be configured according to the basic rate set of the AP
@@ -487,7 +501,7 @@ struct conf_tx_rate_class {
 	 *               the policy (0 - long preamble, 1 - short preamble.
 	 */
 	u8 aflags;
-};
+} __packed;
 
 #define CONF_TX_MAX_AC_COUNT 4
 
@@ -504,7 +518,7 @@ enum conf_tx_ac {
 	CONF_TX_AC_VI = 2,         /* video */
 	CONF_TX_AC_VO = 3,         /* voice */
 	CONF_TX_AC_CTS2SELF = 4,   /* fictitious AC, follows AC_VO */
-	CONF_TX_AC_ANY_TID = 0x1f
+	CONF_TX_AC_ANY_TID = 0xff
 };
 
 struct conf_tx_ac_category {
@@ -544,7 +558,7 @@ struct conf_tx_ac_category {
 	 * Range: u16
 	 */
 	u16 tx_op_limit;
-};
+} __packed;
 
 #define CONF_TX_MAX_TID_COUNT 8
 
@@ -578,7 +592,7 @@ struct conf_tx_tid {
 	u8 ps_scheme;
 	u8 ack_policy;
 	u32 apsd_conf[2];
-};
+} __packed;
 
 struct conf_tx_settings {
 	/*
@@ -664,7 +678,7 @@ struct conf_tx_settings {
 
 	/* Time in ms for Tx watchdog timer to expire */
 	u32 tx_watchdog_timeout;
-};
+} __packed;
 
 enum {
 	CONF_WAKE_UP_EVENT_BEACON    = 0x01, /* Wake on every Beacon*/
@@ -711,7 +725,7 @@ struct conf_bcn_filt_rule {
 	 * Version for the vendor specifie IE (221)
 	 */
 	u8 version[CONF_BCN_IE_VER_LEN];
-};
+} __packed;
 
 #define CONF_MAX_RSSI_SNR_TRIGGERS 8
 
@@ -762,7 +776,7 @@ struct conf_sig_weights {
 	 * Range: u8
 	 */
 	u8 snr_pkt_avg_weight;
-};
+} __packed;
 
 enum conf_bcn_filt_mode {
 	CONF_BCN_FILT_MODE_DISABLED = 0,
@@ -810,7 +824,7 @@ struct conf_conn_settings {
 	 *
 	 * Range: CONF_BCN_FILT_MODE_*
 	 */
-	enum conf_bcn_filt_mode bcn_filt_mode;
+	u8 bcn_filt_mode;
 
 	/*
 	 * Configure Beacon filter pass-thru rules.
@@ -937,7 +951,13 @@ struct conf_conn_settings {
 	 * Range: u16
 	 */
 	u8 max_listen_interval;
-};
+
+	/*
+	 * Default sleep authorization for a new STA interface. This determines
+	 * whether we can go to ELP.
+	 */
+	u8 sta_sleep_auth;
+} __packed;
 
 enum {
 	CONF_REF_CLK_19_2_E,
@@ -965,6 +985,11 @@ struct conf_itrim_settings {
 
 	/* moderation timeout in microsecs from the last TX */
 	u32 timeout;
+} __packed;
+
+enum conf_fast_wakeup {
+	CONF_FAST_WAKEUP_ENABLE,
+	CONF_FAST_WAKEUP_DISABLE,
 };
 
 struct conf_pm_config_settings {
@@ -978,10 +1003,10 @@ struct conf_pm_config_settings {
 	/*
 	 * Host fast wakeup support
 	 *
-	 * Range: true, false
+	 * Range: enum conf_fast_wakeup
 	 */
-	bool host_fast_wakeup_support;
-};
+	u8 host_fast_wakeup_support;
+} __packed;
 
 struct conf_roam_trigger_settings {
 	/*
@@ -1018,7 +1043,7 @@ struct conf_roam_trigger_settings {
 	 * Range: 0 - 255
 	 */
 	u8 avg_weight_snr_data;
-};
+} __packed;
 
 struct conf_scan_settings {
 	/*
@@ -1064,7 +1089,7 @@ struct conf_scan_settings {
 	 * Range: u32 Microsecs
 	 */
 	u32 split_scan_timeout;
-};
+} __packed;
 
 struct conf_sched_scan_settings {
 	/*
@@ -1102,7 +1127,7 @@ struct conf_sched_scan_settings {
 
 	/* SNR threshold to be used for filtering */
 	s8 snr_threshold;
-};
+} __packed;
 
 struct conf_ht_setting {
 	u8 rx_ba_win_size;
@@ -1111,7 +1136,7 @@ struct conf_ht_setting {
 
 	/* bitmap of enabled TIDs for TX BA sessions */
 	u8 tx_ba_tid_bitmap;
-};
+} __packed;
 
 struct conf_memory_settings {
 	/* Number of stations supported in IBSS mode */
@@ -1151,7 +1176,7 @@ struct conf_memory_settings {
 	 * Range: 0-120
 	 */
 	u8 tx_min;
-};
+} __packed;
 
 struct conf_fm_coex {
 	u8 enable;
@@ -1164,7 +1189,7 @@ struct conf_fm_coex {
 	u16 ldo_stabilization_time;
 	u8 fm_disturbed_band_margin;
 	u8 swallow_clk_diff;
-};
+} __packed;
 
 struct conf_rx_streaming_settings {
 	/*
@@ -1193,7 +1218,7 @@ struct conf_rx_streaming_settings {
 	 * enable rx streaming also when there is no coex activity
 	 */
 	u8 always;
-};
+} __packed;
 
 struct conf_fwlog {
 	/* Continuous or on-demand */
@@ -1217,7 +1242,7 @@ struct conf_fwlog {
 
 	/* Regulates the frequency of log messages */
 	u8 threshold;
-};
+} __packed;
 
 #define ACX_RATE_MGMT_NUM_OF_RATES 13
 struct conf_rate_policy_settings {
@@ -1236,7 +1261,7 @@ struct conf_rate_policy_settings {
 	u8 rate_check_up;
 	u8 rate_check_down;
 	u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES];
-};
+} __packed;
 
 struct conf_hangover_settings {
 	u32 recover_time;
@@ -1250,7 +1275,23 @@ struct conf_hangover_settings {
 	u8 quiet_time;
 	u8 increase_time;
 	u8 window_size;
-};
+} __packed;
+
+/*
+ * The conf version consists of 4 bytes.  The two MSB are the wlcore
+ * version, the two LSB are the lower driver's private conf
+ * version.
+ */
+#define WLCORE_CONF_VERSION	(0x0002 << 16)
+#define WLCORE_CONF_MASK	0xffff0000
+#define WLCORE_CONF_SIZE	(sizeof(struct wlcore_conf_header) +	\
+				 sizeof(struct wlcore_conf))
+
+struct wlcore_conf_header {
+	__le32 magic;
+	__le32 version;
+	__le32 checksum;
+} __packed;
 
 struct wlcore_conf {
 	struct conf_sg_settings sg;
@@ -1269,6 +1310,12 @@ struct wlcore_conf {
 	struct conf_fwlog fwlog;
 	struct conf_rate_policy_settings rate;
 	struct conf_hangover_settings hangover;
-};
+} __packed;
+
+struct wlcore_conf_file {
+	struct wlcore_conf_header header;
+	struct wlcore_conf core;
+	u8 priv[0];
+} __packed;
 
 #endif
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index d5aea1f..1768f37 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -25,6 +25,7 @@
 
 #include <linux/skbuff.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 
 #include "wlcore.h"
 #include "debug.h"
@@ -32,14 +33,14 @@
 #include "ps.h"
 #include "io.h"
 #include "tx.h"
+#include "hw_ops.h"
 
 /* ms */
 #define WL1271_DEBUGFS_STATS_LIFETIME 1000
 
 /* debugfs macros idea from mac80211 */
-#define DEBUGFS_FORMAT_BUFFER_SIZE 100
-static int wl1271_format_buffer(char __user *userbuf, size_t count,
-				    loff_t *ppos, char *fmt, ...)
+int wl1271_format_buffer(char __user *userbuf, size_t count,
+			 loff_t *ppos, char *fmt, ...)
 {
 	va_list args;
 	char buf[DEBUGFS_FORMAT_BUFFER_SIZE];
@@ -51,59 +52,9 @@ static int wl1271_format_buffer(char __user *userbuf, size_t count,
 
 	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
 }
+EXPORT_SYMBOL_GPL(wl1271_format_buffer);
 
-#define DEBUGFS_READONLY_FILE(name, fmt, value...)			\
-static ssize_t name## _read(struct file *file, char __user *userbuf,	\
-			    size_t count, loff_t *ppos)			\
-{									\
-	struct wl1271 *wl = file->private_data;				\
-	return wl1271_format_buffer(userbuf, count, ppos,		\
-				    fmt "\n", ##value);			\
-}									\
-									\
-static const struct file_operations name## _ops = {			\
-	.read = name## _read,						\
-	.open = simple_open,						\
-	.llseek	= generic_file_llseek,					\
-};
-
-#define DEBUGFS_ADD(name, parent)					\
-	entry = debugfs_create_file(#name, 0400, parent,		\
-				    wl, &name## _ops);			\
-	if (!entry || IS_ERR(entry))					\
-		goto err;						\
-
-#define DEBUGFS_ADD_PREFIX(prefix, name, parent)			\
-	do {								\
-		entry = debugfs_create_file(#name, 0400, parent,	\
-				    wl, &prefix## _## name## _ops);	\
-		if (!entry || IS_ERR(entry))				\
-			goto err;					\
-	} while (0);
-
-#define DEBUGFS_FWSTATS_FILE(sub, name, fmt)				\
-static ssize_t sub## _ ##name## _read(struct file *file,		\
-				      char __user *userbuf,		\
-				      size_t count, loff_t *ppos)	\
-{									\
-	struct wl1271 *wl = file->private_data;				\
-									\
-	wl1271_debugfs_update_stats(wl);				\
-									\
-	return wl1271_format_buffer(userbuf, count, ppos, fmt "\n",	\
-				    wl->stats.fw_stats->sub.name);	\
-}									\
-									\
-static const struct file_operations sub## _ ##name## _ops = {		\
-	.read = sub## _ ##name## _read,					\
-	.open = simple_open,						\
-	.llseek	= generic_file_llseek,					\
-};
-
-#define DEBUGFS_FWSTATS_ADD(sub, name)				\
-	DEBUGFS_ADD(sub## _ ##name, stats)
-
-static void wl1271_debugfs_update_stats(struct wl1271 *wl)
+void wl1271_debugfs_update_stats(struct wl1271 *wl)
 {
 	int ret;
 
@@ -125,97 +76,7 @@ static void wl1271_debugfs_update_stats(struct wl1271 *wl)
 out:
 	mutex_unlock(&wl->mutex);
 }
-
-DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u");
-
-DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u");
-DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u");
-DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u");
-DEBUGFS_FWSTATS_FILE(rx, dropped, "%u");
-DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u");
-DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u");
-DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u");
-DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u");
-
-DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u");
-DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u");
-DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u");
-DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u");
-
-DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u");
-DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u");
-DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
-DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u");
-DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u");
-DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u");
-DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u");
-DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u");
-DEBUGFS_FWSTATS_FILE(isr, commands, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u");
-DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u");
-DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u");
-DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u");
-DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u");
-DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u");
-
-DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u");
-DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u");
-/* skipping wep.reserved */
-DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u");
-DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u");
-DEBUGFS_FWSTATS_FILE(wep, packets, "%u");
-DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u");
-
-DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u");
-/* skipping cont_miss_bcns_spread for now */
-DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u");
-
-DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u");
-DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u");
-
-DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u");
-DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u");
-DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u");
-DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u");
-DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u");
-DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u");
-
-DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u");
-DEBUGFS_FWSTATS_FILE(event, calibration, "%u");
-DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u");
-DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u");
-DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u");
-DEBUGFS_FWSTATS_FILE(event, oom_late, "%u");
-DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u");
-DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u");
-
-DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u");
-DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u");
-DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u");
-
-DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u");
+EXPORT_SYMBOL_GPL(wl1271_debugfs_update_stats);
 
 DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count);
 DEBUGFS_READONLY_FILE(excessive_retries, "%u",
@@ -241,6 +102,89 @@ static const struct file_operations tx_queue_len_ops = {
 	.llseek = default_llseek,
 };
 
+static void chip_op_handler(struct wl1271 *wl, unsigned long value,
+			    void *arg)
+{
+	int ret;
+	int (*chip_op) (struct wl1271 *wl);
+
+	if (!arg) {
+		wl1271_warning("debugfs chip_op_handler with no callback");
+		return;
+	}
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		return;
+
+	chip_op = arg;
+	chip_op(wl);
+
+	wl1271_ps_elp_sleep(wl);
+}
+
+
+static inline void no_write_handler(struct wl1271 *wl,
+				    unsigned long value,
+				    unsigned long param)
+{
+}
+
+#define WL12XX_CONF_DEBUGFS(param, conf_sub_struct,			\
+			    min_val, max_val, write_handler_locked,	\
+			    write_handler_arg)				\
+	static ssize_t param##_read(struct file *file,			\
+				      char __user *user_buf,		\
+				      size_t count, loff_t *ppos)	\
+	{								\
+	struct wl1271 *wl = file->private_data;				\
+	return wl1271_format_buffer(user_buf, count,			\
+				    ppos, "%d\n",			\
+				    wl->conf.conf_sub_struct.param);	\
+	}								\
+									\
+	static ssize_t param##_write(struct file *file,			\
+				     const char __user *user_buf,	\
+				     size_t count, loff_t *ppos)	\
+	{								\
+	struct wl1271 *wl = file->private_data;				\
+	unsigned long value;						\
+	int ret;							\
+									\
+	ret = kstrtoul_from_user(user_buf, count, 10, &value);		\
+	if (ret < 0) {							\
+		wl1271_warning("illegal value for " #param);		\
+		return -EINVAL;						\
+	}								\
+									\
+	if (value < min_val || value > max_val) {			\
+		wl1271_warning(#param " is not in valid range");	\
+		return -ERANGE;						\
+	}								\
+									\
+	mutex_lock(&wl->mutex);						\
+	wl->conf.conf_sub_struct.param = value;				\
+									\
+	write_handler_locked(wl, value, write_handler_arg);		\
+									\
+	mutex_unlock(&wl->mutex);					\
+	return count;							\
+	}								\
+									\
+	static const struct file_operations param##_ops = {		\
+		.read = param##_read,					\
+		.write = param##_write,					\
+		.open = simple_open,					\
+		.llseek = default_llseek,				\
+	};
+
+WL12XX_CONF_DEBUGFS(irq_pkt_threshold, rx, 0, 65535,
+		    chip_op_handler, wl1271_acx_init_rx_interrupt)
+WL12XX_CONF_DEBUGFS(irq_blk_threshold, rx, 0, 65535,
+		    chip_op_handler, wl1271_acx_init_rx_interrupt)
+WL12XX_CONF_DEBUGFS(irq_timeout, rx, 0, 100,
+		    chip_op_handler, wl1271_acx_init_rx_interrupt)
+
 static ssize_t gpio_power_read(struct file *file, char __user *user_buf,
 			  size_t count, loff_t *ppos)
 {
@@ -535,8 +479,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
 	DRIVER_STATE_PRINT_LHEX(ap_ps_map);
 	DRIVER_STATE_PRINT_HEX(quirks);
 	DRIVER_STATE_PRINT_HEX(irq);
-	DRIVER_STATE_PRINT_HEX(ref_clock);
-	DRIVER_STATE_PRINT_HEX(tcxo_clock);
+	/* TODO: ref_clock and tcxo_clock were moved to wl12xx priv */
 	DRIVER_STATE_PRINT_HEX(hw_pg_ver);
 	DRIVER_STATE_PRINT_HEX(platform_quirks);
 	DRIVER_STATE_PRINT_HEX(chip.id);
@@ -647,7 +590,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
 		VIF_STATE_PRINT_INT(last_rssi_event);
 		VIF_STATE_PRINT_INT(ba_support);
 		VIF_STATE_PRINT_INT(ba_allowed);
-		VIF_STATE_PRINT_INT(is_gem);
 		VIF_STATE_PRINT_LLHEX(tx_security_seq);
 		VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
 	}
@@ -1002,108 +944,92 @@ static const struct file_operations beacon_filtering_ops = {
 	.llseek = default_llseek,
 };
 
-static int wl1271_debugfs_add_files(struct wl1271 *wl,
-				     struct dentry *rootdir)
+static ssize_t fw_stats_raw_read(struct file *file,
+				 char __user *userbuf,
+				 size_t count, loff_t *ppos)
 {
-	int ret = 0;
-	struct dentry *entry, *stats, *streaming;
+	struct wl1271 *wl = file->private_data;
 
-	stats = debugfs_create_dir("fw-statistics", rootdir);
-	if (!stats || IS_ERR(stats)) {
-		entry = stats;
-		goto err;
+	wl1271_debugfs_update_stats(wl);
+
+	return simple_read_from_buffer(userbuf, count, ppos,
+				       wl->stats.fw_stats,
+				       wl->stats.fw_stats_len);
+}
+
+static const struct file_operations fw_stats_raw_ops = {
+	.read = fw_stats_raw_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+static ssize_t sleep_auth_read(struct file *file, char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+
+	return wl1271_format_buffer(user_buf, count,
+				    ppos, "%d\n",
+				    wl->sleep_auth);
+}
+
+static ssize_t sleep_auth_write(struct file *file,
+				const char __user *user_buf,
+				size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	unsigned long value;
+	int ret;
+
+	ret = kstrtoul_from_user(user_buf, count, 0, &value);
+	if (ret < 0) {
+		wl1271_warning("illegal value in sleep_auth");
+		return -EINVAL;
 	}
 
-	DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow);
-
-	DEBUGFS_FWSTATS_ADD(rx, out_of_mem);
-	DEBUGFS_FWSTATS_ADD(rx, hdr_overflow);
-	DEBUGFS_FWSTATS_ADD(rx, hw_stuck);
-	DEBUGFS_FWSTATS_ADD(rx, dropped);
-	DEBUGFS_FWSTATS_ADD(rx, fcs_err);
-	DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig);
-	DEBUGFS_FWSTATS_ADD(rx, path_reset);
-	DEBUGFS_FWSTATS_ADD(rx, reset_counter);
-
-	DEBUGFS_FWSTATS_ADD(dma, rx_requested);
-	DEBUGFS_FWSTATS_ADD(dma, rx_errors);
-	DEBUGFS_FWSTATS_ADD(dma, tx_requested);
-	DEBUGFS_FWSTATS_ADD(dma, tx_errors);
-
-	DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt);
-	DEBUGFS_FWSTATS_ADD(isr, fiqs);
-	DEBUGFS_FWSTATS_ADD(isr, rx_headers);
-	DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow);
-	DEBUGFS_FWSTATS_ADD(isr, rx_rdys);
-	DEBUGFS_FWSTATS_ADD(isr, irqs);
-	DEBUGFS_FWSTATS_ADD(isr, tx_procs);
-	DEBUGFS_FWSTATS_ADD(isr, decrypt_done);
-	DEBUGFS_FWSTATS_ADD(isr, dma0_done);
-	DEBUGFS_FWSTATS_ADD(isr, dma1_done);
-	DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete);
-	DEBUGFS_FWSTATS_ADD(isr, commands);
-	DEBUGFS_FWSTATS_ADD(isr, rx_procs);
-	DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes);
-	DEBUGFS_FWSTATS_ADD(isr, host_acknowledges);
-	DEBUGFS_FWSTATS_ADD(isr, pci_pm);
-	DEBUGFS_FWSTATS_ADD(isr, wakeups);
-	DEBUGFS_FWSTATS_ADD(isr, low_rssi);
-
-	DEBUGFS_FWSTATS_ADD(wep, addr_key_count);
-	DEBUGFS_FWSTATS_ADD(wep, default_key_count);
-	/* skipping wep.reserved */
-	DEBUGFS_FWSTATS_ADD(wep, key_not_found);
-	DEBUGFS_FWSTATS_ADD(wep, decrypt_fail);
-	DEBUGFS_FWSTATS_ADD(wep, packets);
-	DEBUGFS_FWSTATS_ADD(wep, interrupt);
-
-	DEBUGFS_FWSTATS_ADD(pwr, ps_enter);
-	DEBUGFS_FWSTATS_ADD(pwr, elp_enter);
-	DEBUGFS_FWSTATS_ADD(pwr, missing_bcns);
-	DEBUGFS_FWSTATS_ADD(pwr, wake_on_host);
-	DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp);
-	DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps);
-	DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps);
-	DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons);
-	DEBUGFS_FWSTATS_ADD(pwr, power_save_off);
-	DEBUGFS_FWSTATS_ADD(pwr, enable_ps);
-	DEBUGFS_FWSTATS_ADD(pwr, disable_ps);
-	DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps);
-	/* skipping cont_miss_bcns_spread for now */
-	DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons);
-
-	DEBUGFS_FWSTATS_ADD(mic, rx_pkts);
-	DEBUGFS_FWSTATS_ADD(mic, calc_failure);
-
-	DEBUGFS_FWSTATS_ADD(aes, encrypt_fail);
-	DEBUGFS_FWSTATS_ADD(aes, decrypt_fail);
-	DEBUGFS_FWSTATS_ADD(aes, encrypt_packets);
-	DEBUGFS_FWSTATS_ADD(aes, decrypt_packets);
-	DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt);
-	DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt);
-
-	DEBUGFS_FWSTATS_ADD(event, heart_beat);
-	DEBUGFS_FWSTATS_ADD(event, calibration);
-	DEBUGFS_FWSTATS_ADD(event, rx_mismatch);
-	DEBUGFS_FWSTATS_ADD(event, rx_mem_empty);
-	DEBUGFS_FWSTATS_ADD(event, rx_pool);
-	DEBUGFS_FWSTATS_ADD(event, oom_late);
-	DEBUGFS_FWSTATS_ADD(event, phy_transmit_error);
-	DEBUGFS_FWSTATS_ADD(event, tx_stuck);
-
-	DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts);
-	DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts);
-	DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime);
-	DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn);
-	DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn);
-	DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization);
-	DEBUGFS_FWSTATS_ADD(ps, upsd_utilization);
-
-	DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop);
-	DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data);
-	DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
-	DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
-	DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
+	if (value < 0 || value > WL1271_PSM_MAX) {
+		wl1271_warning("sleep_auth must be between 0 and %d",
+			       WL1271_PSM_MAX);
+		return -ERANGE;
+	}
+
+	mutex_lock(&wl->mutex);
+
+	wl->conf.conn.sta_sleep_auth = value;
+
+	if (wl->state == WL1271_STATE_OFF) {
+		/* this will show up on "read" in case we are off */
+		wl->sleep_auth = value;
+		goto out;
+	}
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	ret = wl1271_acx_sleep_auth(wl, value);
+	if (ret < 0)
+		goto out_sleep;
+
+out_sleep:
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+static const struct file_operations sleep_auth_ops = {
+	.read = sleep_auth_read,
+	.write = sleep_auth_write,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+static int wl1271_debugfs_add_files(struct wl1271 *wl,
+				    struct dentry *rootdir)
+{
+	int ret = 0;
+	struct dentry *entry, *streaming;
 
 	DEBUGFS_ADD(tx_queue_len, rootdir);
 	DEBUGFS_ADD(retry_count, rootdir);
@@ -1120,6 +1046,11 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
 	DEBUGFS_ADD(dynamic_ps_timeout, rootdir);
 	DEBUGFS_ADD(forced_ps, rootdir);
 	DEBUGFS_ADD(split_scan_timeout, rootdir);
+	DEBUGFS_ADD(irq_pkt_threshold, rootdir);
+	DEBUGFS_ADD(irq_blk_threshold, rootdir);
+	DEBUGFS_ADD(irq_timeout, rootdir);
+	DEBUGFS_ADD(fw_stats_raw, rootdir);
+	DEBUGFS_ADD(sleep_auth, rootdir);
 
 	streaming = debugfs_create_dir("rx_streaming", rootdir);
 	if (!streaming || IS_ERR(streaming))
@@ -1145,7 +1076,7 @@ void wl1271_debugfs_reset(struct wl1271 *wl)
 	if (!wl->stats.fw_stats)
 		return;
 
-	memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
+	memset(wl->stats.fw_stats, 0, wl->stats.fw_stats_len);
 	wl->stats.retry_count = 0;
 	wl->stats.excessive_retries = 0;
 }
@@ -1160,34 +1091,34 @@ int wl1271_debugfs_init(struct wl1271 *wl)
 
 	if (IS_ERR(rootdir)) {
 		ret = PTR_ERR(rootdir);
-		goto err;
+		goto out;
 	}
 
-	wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats),
-				      GFP_KERNEL);
-
+	wl->stats.fw_stats = kzalloc(wl->stats.fw_stats_len, GFP_KERNEL);
 	if (!wl->stats.fw_stats) {
 		ret = -ENOMEM;
-		goto err_fw;
+		goto out_remove;
 	}
 
 	wl->stats.fw_stats_update = jiffies;
 
 	ret = wl1271_debugfs_add_files(wl, rootdir);
+	if (ret < 0)
+		goto out_exit;
 
+	ret = wlcore_debugfs_init(wl, rootdir);
 	if (ret < 0)
-		goto err_file;
+		goto out_exit;
 
-	return 0;
+	goto out;
 
-err_file:
-	kfree(wl->stats.fw_stats);
-	wl->stats.fw_stats = NULL;
+out_exit:
+	wl1271_debugfs_exit(wl);
 
-err_fw:
+out_remove:
 	debugfs_remove_recursive(rootdir);
 
-err:
+out:
 	return ret;
 }
 
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.h b/drivers/net/wireless/ti/wlcore/debugfs.h
index a8d3aef..f7381dd 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.h
+++ b/drivers/net/wireless/ti/wlcore/debugfs.h
@@ -26,8 +26,95 @@
 
 #include "wlcore.h"
 
+int wl1271_format_buffer(char __user *userbuf, size_t count,
+			 loff_t *ppos, char *fmt, ...);
+
 int wl1271_debugfs_init(struct wl1271 *wl);
 void wl1271_debugfs_exit(struct wl1271 *wl);
 void wl1271_debugfs_reset(struct wl1271 *wl);
+void wl1271_debugfs_update_stats(struct wl1271 *wl);
+
+#define DEBUGFS_FORMAT_BUFFER_SIZE 256
+
+#define DEBUGFS_READONLY_FILE(name, fmt, value...)			\
+static ssize_t name## _read(struct file *file, char __user *userbuf,	\
+			    size_t count, loff_t *ppos)			\
+{									\
+	struct wl1271 *wl = file->private_data;				\
+	return wl1271_format_buffer(userbuf, count, ppos,		\
+				    fmt "\n", ##value);			\
+}									\
+									\
+static const struct file_operations name## _ops = {			\
+	.read = name## _read,						\
+	.open = simple_open,						\
+	.llseek	= generic_file_llseek,					\
+};
+
+#define DEBUGFS_ADD(name, parent)					\
+	do {								\
+		entry = debugfs_create_file(#name, 0400, parent,	\
+					    wl, &name## _ops);		\
+		if (!entry || IS_ERR(entry))				\
+			goto err;					\
+	} while (0);
+
+
+#define DEBUGFS_ADD_PREFIX(prefix, name, parent)			\
+	do {								\
+		entry = debugfs_create_file(#name, 0400, parent,	\
+				    wl, &prefix## _## name## _ops);	\
+		if (!entry || IS_ERR(entry))				\
+			goto err;					\
+	} while (0);
+
+#define DEBUGFS_FWSTATS_FILE(sub, name, fmt, struct_type)		\
+static ssize_t sub## _ ##name## _read(struct file *file,		\
+				      char __user *userbuf,		\
+				      size_t count, loff_t *ppos)	\
+{									\
+	struct wl1271 *wl = file->private_data;				\
+	struct struct_type *stats = wl->stats.fw_stats;			\
+									\
+	wl1271_debugfs_update_stats(wl);				\
+									\
+	return wl1271_format_buffer(userbuf, count, ppos, fmt "\n",	\
+				    stats->sub.name);			\
+}									\
+									\
+static const struct file_operations sub## _ ##name## _ops = {		\
+	.read = sub## _ ##name## _read,					\
+	.open = simple_open,						\
+	.llseek	= generic_file_llseek,					\
+};
+
+#define DEBUGFS_FWSTATS_FILE_ARRAY(sub, name, len, struct_type)		\
+static ssize_t sub## _ ##name## _read(struct file *file,		\
+				      char __user *userbuf,		\
+				      size_t count, loff_t *ppos)	\
+{									\
+	struct wl1271 *wl = file->private_data;				\
+	struct struct_type *stats = wl->stats.fw_stats;			\
+	char buf[DEBUGFS_FORMAT_BUFFER_SIZE] = "";			\
+	int res, i;							\
+									\
+	wl1271_debugfs_update_stats(wl);				\
+									\
+	for (i = 0; i < len; i++)					\
+		res = snprintf(buf, sizeof(buf), "%s[%d] = %d\n",	\
+			       buf, i, stats->sub.name[i]);		\
+									\
+	return wl1271_format_buffer(userbuf, count, ppos, "%s", buf);	\
+}									\
+									\
+static const struct file_operations sub## _ ##name## _ops = {		\
+	.read = sub## _ ##name## _read,					\
+	.open = simple_open,						\
+	.llseek	= generic_file_llseek,					\
+};
+
+#define DEBUGFS_FWSTATS_ADD(sub, name)					\
+	DEBUGFS_ADD(sub## _ ##name, stats)
+
 
 #endif /* WL1271_DEBUGFS_H */
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 28e2a63..c976f04 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -148,15 +148,33 @@ static int wl1271_event_process(struct wl1271 *wl)
 		int delay = wl->conf.conn.synch_fail_thold *
 					wl->conf.conn.bss_lose_timeout;
 		wl1271_info("Beacon loss detected.");
-		cancel_delayed_work_sync(&wl->connection_loss_work);
+
+		/*
+		 * if the work is already queued, it should take place. We
+		 * don't want to delay the connection loss indication
+		 * any more.
+		 */
 		ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work,
-		      msecs_to_jiffies(delay));
+					     msecs_to_jiffies(delay));
+
+		wl12xx_for_each_wlvif_sta(wl, wlvif) {
+			vif = wl12xx_wlvif_to_vif(wlvif);
+
+			ieee80211_cqm_rssi_notify(
+					vif,
+					NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
+					GFP_KERNEL);
+		}
 	}
 
 	if (vector & REGAINED_BSS_EVENT_ID) {
 		/* TODO: check for multi-role */
 		wl1271_info("Beacon regained.");
-		cancel_delayed_work_sync(&wl->connection_loss_work);
+		cancel_delayed_work(&wl->connection_loss_work);
+
+		/* sanity check - we can't lose and gain the beacon together */
+		WARN(vector & BSS_LOSE_EVENT_ID,
+		     "Concurrent beacon loss and gain from FW");
 	}
 
 	if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index 9384b4d..9e7787b 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -119,4 +119,82 @@ static inline int wlcore_identify_fw(struct wl1271 *wl)
 	return 0;
 }
 
+static inline void
+wlcore_hw_set_tx_desc_csum(struct wl1271 *wl,
+			   struct wl1271_tx_hw_descr *desc,
+			   struct sk_buff *skb)
+{
+	if (!wl->ops->set_tx_desc_csum)
+		BUG_ON(1);
+
+	wl->ops->set_tx_desc_csum(wl, desc, skb);
+}
+
+static inline void
+wlcore_hw_set_rx_csum(struct wl1271 *wl,
+		      struct wl1271_rx_descriptor *desc,
+		      struct sk_buff *skb)
+{
+	if (wl->ops->set_rx_csum)
+		wl->ops->set_rx_csum(wl, desc, skb);
+}
+
+static inline u32
+wlcore_hw_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
+				     struct wl12xx_vif *wlvif)
+{
+	if (wl->ops->ap_get_mimo_wide_rate_mask)
+		return wl->ops->ap_get_mimo_wide_rate_mask(wl, wlvif);
+
+	return 0;
+}
+
+static inline int
+wlcore_debugfs_init(struct wl1271 *wl, struct dentry *rootdir)
+{
+	if (wl->ops->debugfs_init)
+		return wl->ops->debugfs_init(wl, rootdir);
+
+	return 0;
+}
+
+static inline int
+wlcore_handle_static_data(struct wl1271 *wl, void *static_data)
+{
+	if (wl->ops->handle_static_data)
+		return wl->ops->handle_static_data(wl, static_data);
+
+	return 0;
+}
+
+static inline int
+wlcore_hw_get_spare_blocks(struct wl1271 *wl, bool is_gem)
+{
+	if (!wl->ops->get_spare_blocks)
+		BUG_ON(1);
+
+	return wl->ops->get_spare_blocks(wl, is_gem);
+}
+
+static inline int
+wlcore_hw_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
+		  struct ieee80211_vif *vif,
+		  struct ieee80211_sta *sta,
+		  struct ieee80211_key_conf *key_conf)
+{
+	if (!wl->ops->set_key)
+		BUG_ON(1);
+
+	return wl->ops->set_key(wl, cmd, vif, sta, key_conf);
+}
+
+static inline u32
+wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len)
+{
+	if (wl->ops->pre_pkt_send)
+		return wl->ops->pre_pkt_send(wl, buf_offset, last_len);
+
+	return buf_offset;
+}
+
 #endif
diff --git a/drivers/net/wireless/ti/wlcore/ini.h b/drivers/net/wireless/ti/wlcore/ini.h
index 4cf9ecc..d24fe3b 100644
--- a/drivers/net/wireless/ti/wlcore/ini.h
+++ b/drivers/net/wireless/ti/wlcore/ini.h
@@ -172,7 +172,19 @@ struct wl128x_ini_fem_params_5 {
 
 /* NVS data structure */
 #define WL1271_INI_NVS_SECTION_SIZE		     468
-#define WL1271_INI_FEM_MODULE_COUNT                  2
+
+/* We have four FEM module types: 0-RFMD, 1-TQS, 2-SKW, 3-TQS_HP */
+#define WL1271_INI_FEM_MODULE_COUNT                  4
+
+/*
+ * In NVS we only store two FEM module entries -
+ *	  FEM modules 0,2,3 are stored in entry 0
+ *	  FEM module 1 is stored in entry 1
+ */
+#define WL12XX_NVS_FEM_MODULE_COUNT                  2
+
+#define WL12XX_FEM_TO_NVS_ENTRY(ini_fem_module)      \
+	((ini_fem_module) == 1 ? 1 : 0)
 
 #define WL1271_INI_LEGACY_NVS_FILE_SIZE              800
 
@@ -188,13 +200,13 @@ struct wl1271_nvs_file {
 	struct {
 		struct wl1271_ini_fem_params_2 params;
 		u8 padding;
-	} dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
+	} dyn_radio_params_2[WL12XX_NVS_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];
+	} dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT];
 } __packed;
 
 struct wl128x_nvs_file {
@@ -209,12 +221,12 @@ struct wl128x_nvs_file {
 	struct {
 		struct wl128x_ini_fem_params_2 params;
 		u8 padding;
-	} dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
+	} dyn_radio_params_2[WL12XX_NVS_FEM_MODULE_COUNT];
 	struct wl128x_ini_band_params_5 stat_radio_params_5;
 	u8 padding3;
 	struct {
 		struct wl128x_ini_fem_params_5 params;
 		u8 padding;
-	} dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
+	} dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT];
 } __packed;
 #endif
diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c
index 9f89255..8a8a897 100644
--- a/drivers/net/wireless/ti/wlcore/init.c
+++ b/drivers/net/wireless/ti/wlcore/init.c
@@ -460,6 +460,9 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 	/* unconditionally enable HT rates */
 	supported_rates |= CONF_TX_MCS_RATES;
 
+	/* get extra MIMO or wide-chan rates where the HW supports it */
+	supported_rates |= wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
+
 	/* configure unicast TX rate classes */
 	for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
 		rc.enabled_rates = supported_rates;
@@ -551,29 +554,28 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
 	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
 	int ret, i;
 
-	/*
-	 * consider all existing roles before configuring psm.
-	 * TODO: reconfigure on interface removal.
-	 */
-	if (!wl->ap_count) {
-		if (is_ap) {
-			/* Configure for power always on */
+	/* consider all existing roles before configuring psm. */
+
+	if (wl->ap_count == 0 && is_ap) { /* first AP */
+		/* Configure for power always on */
+		ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+		if (ret < 0)
+			return ret;
+	/* first STA, no APs */
+	} else if (wl->sta_count == 0 && wl->ap_count == 0 && !is_ap) {
+		u8 sta_auth = wl->conf.conn.sta_sleep_auth;
+		/* Configure for power according to debugfs */
+		if (sta_auth != WL1271_PSM_ILLEGAL)
+			ret = wl1271_acx_sleep_auth(wl, sta_auth);
+		/* Configure for power always on */
+		else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
 			ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
-			if (ret < 0)
-				return ret;
-		} else if (!wl->sta_count) {
-			if (wl->quirks & WLCORE_QUIRK_NO_ELP) {
-				/* Configure for power always on */
-				ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
-				if (ret < 0)
-					return ret;
-			} else {
-				/* Configure for ELP power saving */
-				ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
-				if (ret < 0)
-					return ret;
-			}
-		}
+		/* Configure for ELP power saving */
+		else
+			ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
+
+		if (ret < 0)
+			return ret;
 	}
 
 	/* Mode specific init */
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index acef933..78edc58 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -320,46 +320,6 @@ static void wlcore_adjust_conf(struct wl1271 *wl)
 	}
 }
 
-static int wl1271_plt_init(struct wl1271 *wl)
-{
-	int ret;
-
-	ret = wl->ops->hw_init(wl);
-	if (ret < 0)
-		return ret;
-
-	ret = wl1271_acx_init_mem_config(wl);
-	if (ret < 0)
-		return ret;
-
-	ret = wl12xx_acx_mem_cfg(wl);
-	if (ret < 0)
-		goto out_free_memmap;
-
-	/* Enable data path */
-	ret = wl1271_cmd_data_path(wl, 1);
-	if (ret < 0)
-		goto out_free_memmap;
-
-	/* Configure for CAM power saving (ie. always active) */
-	ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
-	if (ret < 0)
-		goto out_free_memmap;
-
-	/* configure PM */
-	ret = wl1271_acx_pm_config(wl);
-	if (ret < 0)
-		goto out_free_memmap;
-
-	return 0;
-
- out_free_memmap:
-	kfree(wl->target_mem_map);
-	wl->target_mem_map = NULL;
-
-	return ret;
-}
-
 static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
 					struct wl12xx_vif *wlvif,
 					u8 hlid, u8 tx_pkts)
@@ -387,7 +347,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
 
 static void wl12xx_irq_update_links_status(struct wl1271 *wl,
 					   struct wl12xx_vif *wlvif,
-					   struct wl_fw_status *status)
+					   struct wl_fw_status_2 *status)
 {
 	struct wl1271_link *lnk;
 	u32 cur_fw_ps_map;
@@ -419,7 +379,8 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
 }
 
 static void wl12xx_fw_status(struct wl1271 *wl,
-			     struct wl_fw_status *status)
+			     struct wl_fw_status_1 *status_1,
+			     struct wl_fw_status_2 *status_2)
 {
 	struct wl12xx_vif *wlvif;
 	struct timespec ts;
@@ -428,37 +389,38 @@ static void wl12xx_fw_status(struct wl1271 *wl,
 	int i;
 	size_t status_len;
 
-	status_len = sizeof(*status) + wl->fw_status_priv_len;
+	status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
+		sizeof(*status_2) + wl->fw_status_priv_len;
 
-	wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status,
+	wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
 			     status_len, false);
 
 	wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
 		     "drv_rx_counter = %d, tx_results_counter = %d)",
-		     status->intr,
-		     status->fw_rx_counter,
-		     status->drv_rx_counter,
-		     status->tx_results_counter);
+		     status_1->intr,
+		     status_1->fw_rx_counter,
+		     status_1->drv_rx_counter,
+		     status_1->tx_results_counter);
 
 	for (i = 0; i < NUM_TX_QUEUES; i++) {
 		/* prevent wrap-around in freed-packets counter */
 		wl->tx_allocated_pkts[i] -=
-				(status->counters.tx_released_pkts[i] -
+				(status_2->counters.tx_released_pkts[i] -
 				wl->tx_pkts_freed[i]) & 0xff;
 
-		wl->tx_pkts_freed[i] = status->counters.tx_released_pkts[i];
+		wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
 	}
 
 	/* prevent wrap-around in total blocks counter */
 	if (likely(wl->tx_blocks_freed <=
-		   le32_to_cpu(status->total_released_blks)))
-		freed_blocks = le32_to_cpu(status->total_released_blks) -
+		   le32_to_cpu(status_2->total_released_blks)))
+		freed_blocks = le32_to_cpu(status_2->total_released_blks) -
 			       wl->tx_blocks_freed;
 	else
 		freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
-			       le32_to_cpu(status->total_released_blks);
+			       le32_to_cpu(status_2->total_released_blks);
 
-	wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
+	wl->tx_blocks_freed = le32_to_cpu(status_2->total_released_blks);
 
 	wl->tx_allocated_blocks -= freed_blocks;
 
@@ -474,7 +436,7 @@ static void wl12xx_fw_status(struct wl1271 *wl,
 			cancel_delayed_work(&wl->tx_watchdog_work);
 	}
 
-	avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
+	avail = le32_to_cpu(status_2->tx_total) - wl->tx_allocated_blocks;
 
 	/*
 	 * The FW might change the total number of TX memblocks before
@@ -493,13 +455,13 @@ static void wl12xx_fw_status(struct wl1271 *wl,
 
 	/* for AP update num of allocated TX blocks per link and ps status */
 	wl12xx_for_each_wlvif_ap(wl, wlvif) {
-		wl12xx_irq_update_links_status(wl, wlvif, status);
+		wl12xx_irq_update_links_status(wl, wlvif, status_2);
 	}
 
 	/* update the host-chipset time offset */
 	getnstimeofday(&ts);
 	wl->time_offset = (timespec_to_ns(&ts) >> 10) -
-		(s64)le32_to_cpu(status->fw_localtime);
+		(s64)le32_to_cpu(status_2->fw_localtime);
 }
 
 static void wl1271_flush_deferred_work(struct wl1271 *wl)
@@ -568,20 +530,30 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
 		clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
 		smp_mb__after_clear_bit();
 
-		wl12xx_fw_status(wl, wl->fw_status);
+		wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
 
 		wlcore_hw_tx_immediate_compl(wl);
 
-		intr = le32_to_cpu(wl->fw_status->intr);
-		intr &= WL1271_INTR_MASK;
+		intr = le32_to_cpu(wl->fw_status_1->intr);
+		intr &= WLCORE_ALL_INTR_MASK;
 		if (!intr) {
 			done = true;
 			continue;
 		}
 
 		if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
-			wl1271_error("watchdog interrupt received! "
+			wl1271_error("HW watchdog interrupt received! starting recovery.");
+			wl->watchdog_recovery = true;
+			wl12xx_queue_recovery_work(wl);
+
+			/* restarting the chip. ignore any other interrupt. */
+			goto out;
+		}
+
+		if (unlikely(intr & WL1271_ACX_SW_INTR_WATCHDOG)) {
+			wl1271_error("SW watchdog interrupt received! "
 				     "starting recovery.");
+			wl->watchdog_recovery = true;
 			wl12xx_queue_recovery_work(wl);
 
 			/* restarting the chip. ignore any other interrupt. */
@@ -591,7 +563,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
 		if (likely(intr & WL1271_ACX_INTR_DATA)) {
 			wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
 
-			wl12xx_rx(wl, wl->fw_status);
+			wl12xx_rx(wl, wl->fw_status_1);
 
 			/* Check if any tx blocks were freed */
 			spin_lock_irqsave(&wl->wl_lock, flags);
@@ -743,7 +715,7 @@ out:
 	return ret;
 }
 
-static int wl1271_fetch_nvs(struct wl1271 *wl)
+static void wl1271_fetch_nvs(struct wl1271 *wl)
 {
 	const struct firmware *fw;
 	int ret;
@@ -751,16 +723,15 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
 	ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
 
 	if (ret < 0) {
-		wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
-			     ret);
-		return ret;
+		wl1271_debug(DEBUG_BOOT, "could not get nvs file %s: %d",
+			     WL12XX_NVS_NAME, ret);
+		return;
 	}
 
 	wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
 
 	if (!wl->nvs) {
 		wl1271_error("could not allocate memory for the nvs file");
-		ret = -ENOMEM;
 		goto out;
 	}
 
@@ -768,8 +739,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
 
 out:
 	release_firmware(fw);
-
-	return ret;
 }
 
 void wl12xx_queue_recovery_work(struct wl1271 *wl)
@@ -801,14 +770,16 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
 	return len;
 }
 
+#define WLCORE_FW_LOG_END 0x2000000
+
 static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
 {
 	u32 addr;
-	u32 first_addr;
+	u32 offset;
+	u32 end_of_log;
 	u8 *block;
 
 	if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
-	    (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
 	    (wl->conf.fwlog.mem_blocks == 0))
 		return;
 
@@ -820,19 +791,28 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
 
 	/*
 	 * Make sure the chip is awake and the logger isn't active.
-	 * This might fail if the firmware hanged.
+	 * Do not send a stop fwlog command if the fw is hanged.
 	 */
-	if (!wl1271_ps_elp_wakeup(wl))
+	if (wl1271_ps_elp_wakeup(wl))
+		goto out;
+	if (!wl->watchdog_recovery)
 		wl12xx_cmd_stop_fwlog(wl);
 
 	/* Read the first memory block address */
-	wl12xx_fw_status(wl, wl->fw_status);
-	first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
-	if (!first_addr)
+	wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
+	addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
+	if (!addr)
 		goto out;
 
+	if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) {
+		offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor);
+		end_of_log = WLCORE_FW_LOG_END;
+	} else {
+		offset = sizeof(addr);
+		end_of_log = addr;
+	}
+
 	/* Traverse the memory blocks linked list */
-	addr = first_addr;
 	do {
 		memset(block, 0, WL12XX_HW_BLOCK_SIZE);
 		wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
@@ -841,13 +821,14 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
 		/*
 		 * Memory blocks are linked to one another. The first 4 bytes
 		 * of each memory block hold the hardware address of the next
-		 * one. The last memory block points to the first one.
+		 * one. The last memory block points to the first one in
+		 * on demand mode and is equal to 0x2000000 in continuous mode.
 		 */
 		addr = le32_to_cpup((__le32 *)block);
-		if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
-				       WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
+		if (!wl12xx_copy_fwlog(wl, block + offset,
+				       WL12XX_HW_BLOCK_SIZE - offset))
 			break;
-	} while (addr && (addr != first_addr));
+	} while (addr && (addr != end_of_log));
 
 	wake_up_interruptible(&wl->fwlog_waitq);
 
@@ -872,9 +853,14 @@ static void wl1271_recovery_work(struct work_struct *work)
 
 	wl12xx_read_fwlog_panic(wl);
 
-	wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
+	/* change partitions momentarily so we can read the FW pc */
+	wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+	wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x "
+		    "hint_sts: 0x%08x",
 		    wl->chip.fw_ver_str,
-		    wlcore_read_reg(wl, REG_PC_ON_RECOVERY));
+		    wlcore_read_reg(wl, REG_PC_ON_RECOVERY),
+		    wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR));
+	wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
 
 	BUG_ON(bug_on_recovery &&
 	       !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
@@ -885,8 +871,6 @@ static void wl1271_recovery_work(struct work_struct *work)
 		goto out_unlock;
 	}
 
-	BUG_ON(bug_on_recovery);
-
 	/*
 	 * Advance security sequence number to overcome potential progress
 	 * in the firmware during recovery. This doens't hurt if the network is
@@ -900,7 +884,7 @@ static void wl1271_recovery_work(struct work_struct *work)
 	}
 
 	/* Prevent spurious TX during FW restart */
-	ieee80211_stop_queues(wl->hw);
+	wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
 
 	if (wl->sched_scanning) {
 		ieee80211_sched_scan_stopped(wl->hw);
@@ -914,6 +898,7 @@ static void wl1271_recovery_work(struct work_struct *work)
 		vif = wl12xx_wlvif_to_vif(wlvif);
 		__wl1271_op_remove_interface(wl, vif, false);
 	}
+        wl->watchdog_recovery = false;
 	mutex_unlock(&wl->mutex);
 	wl1271_op_stop(wl->hw);
 
@@ -925,9 +910,10 @@ static void wl1271_recovery_work(struct work_struct *work)
 	 * Its safe to enable TX now - the queues are stopped after a request
 	 * to restart the HW.
 	 */
-	ieee80211_wake_queues(wl->hw);
+	wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
 	return;
 out_unlock:
+        wl->watchdog_recovery = false;
 	mutex_unlock(&wl->mutex);
 }
 
@@ -938,13 +924,19 @@ static void wl1271_fw_wakeup(struct wl1271 *wl)
 
 static int wl1271_setup(struct wl1271 *wl)
 {
-	wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
-	if (!wl->fw_status)
+	wl->fw_status_1 = kmalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
+				  sizeof(*wl->fw_status_2) +
+				  wl->fw_status_priv_len, GFP_KERNEL);
+	if (!wl->fw_status_1)
 		return -ENOMEM;
 
+	wl->fw_status_2 = (struct wl_fw_status_2 *)
+				(((u8 *) wl->fw_status_1) +
+				WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc));
+
 	wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
 	if (!wl->tx_res_if) {
-		kfree(wl->fw_status);
+		kfree(wl->fw_status_1);
 		return -ENOMEM;
 	}
 
@@ -987,13 +979,12 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
 	 * simplify the code and since the performance impact is
 	 * negligible, we use the same block size for all different
 	 * chip types.
+	 *
+	 * Check if the bus supports blocksize alignment and, if it
+	 * doesn't, make sure we don't have the quirk.
 	 */
-	if (wl1271_set_block_size(wl))
-		wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
-
-	ret = wl->ops->identify_chip(wl);
-	if (ret < 0)
-		goto out;
+	if (!wl1271_set_block_size(wl))
+		wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
 
 	/* TODO: make sure the lower driver has set things up correctly */
 
@@ -1005,13 +996,6 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
 	if (ret < 0)
 		goto out;
 
-	/* No NVS from netlink, try to get it from the filesystem */
-	if (wl->nvs == NULL) {
-		ret = wl1271_fetch_nvs(wl);
-		if (ret < 0)
-			goto out;
-	}
-
 out:
 	return ret;
 }
@@ -1039,14 +1023,10 @@ int wl1271_plt_start(struct wl1271 *wl)
 		if (ret < 0)
 			goto power_off;
 
-		ret = wl->ops->boot(wl);
+		ret = wl->ops->plt_init(wl);
 		if (ret < 0)
 			goto power_off;
 
-		ret = wl1271_plt_init(wl);
-		if (ret < 0)
-			goto irq_disable;
-
 		wl->plt = true;
 		wl->state = WL1271_STATE_ON;
 		wl1271_notice("firmware booted in PLT mode (%s)",
@@ -1059,19 +1039,6 @@ int wl1271_plt_start(struct wl1271 *wl)
 
 		goto out;
 
-irq_disable:
-		mutex_unlock(&wl->mutex);
-		/* Unlocking the mutex in the middle of handling is
-		   inherently unsafe. In this case we deem it safe to do,
-		   because we need to let any possibly pending IRQ out of
-		   the system (and while we are WL1271_STATE_OFF the IRQ
-		   work function will not do anything.) Also, any other
-		   possible concurrent operations will fail due to the
-		   current state, hence the wl1271 struct should be safe. */
-		wlcore_disable_interrupts(wl);
-		wl1271_flush_deferred_work(wl);
-		cancel_work_sync(&wl->netstack_work);
-		mutex_lock(&wl->mutex);
 power_off:
 		wl1271_power_off(wl);
 	}
@@ -1125,6 +1092,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
 	mutex_lock(&wl->mutex);
 	wl1271_power_off(wl);
 	wl->flags = 0;
+	wl->sleep_auth = WL1271_PSM_ILLEGAL;
 	wl->state = WL1271_STATE_OFF;
 	wl->plt = false;
 	wl->rx_counter = 0;
@@ -1154,9 +1122,16 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 	spin_lock_irqsave(&wl->wl_lock, flags);
 
-	/* queue the packet */
+	/*
+	 * drop the packet if the link is invalid or the queue is stopped
+	 * for any reason but watermark. Watermark is a "soft"-stop so we
+	 * allow these packets through.
+	 */
 	if (hlid == WL12XX_INVALID_LINK_ID ||
-	    (wlvif && !test_bit(hlid, wlvif->links_map))) {
+	    (wlvif && !test_bit(hlid, wlvif->links_map)) ||
+	     (wlcore_is_queue_stopped(wl, q) &&
+	      !wlcore_is_queue_stopped_by_reason(wl, q,
+			WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
 		wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
 		ieee80211_free_txskb(hw, skb);
 		goto out;
@@ -1174,8 +1149,8 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	 */
 	if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
 		wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
-		ieee80211_stop_queue(wl->hw, mapping);
-		set_bit(q, &wl->stopped_queues_map);
+		wlcore_stop_queue_locked(wl, q,
+					 WLCORE_QUEUE_STOP_REASON_WATERMARK);
 	}
 
 	/*
@@ -1758,7 +1733,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 	cancel_delayed_work_sync(&wl->connection_loss_work);
 
 	/* let's notify MAC80211 about the remaining pending TX frames */
-	wl12xx_tx_reset(wl, true);
+	wl12xx_tx_reset(wl);
 	mutex_lock(&wl->mutex);
 
 	wl1271_power_off(wl);
@@ -1767,6 +1742,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 
 	wl->rx_counter = 0;
 	wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
+	wl->channel_type = NL80211_CHAN_NO_HT;
 	wl->tx_blocks_available = 0;
 	wl->tx_allocated_blocks = 0;
 	wl->tx_results_count = 0;
@@ -1775,6 +1751,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 	wl->ap_fw_ps_map = 0;
 	wl->ap_ps_map = 0;
 	wl->sched_scanning = false;
+	wl->sleep_auth = WL1271_PSM_ILLEGAL;
 	memset(wl->roles_map, 0, sizeof(wl->roles_map));
 	memset(wl->links_map, 0, sizeof(wl->links_map));
 	memset(wl->roc_map, 0, sizeof(wl->roc_map));
@@ -1799,8 +1776,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 
 	wl1271_debugfs_reset(wl);
 
-	kfree(wl->fw_status);
-	wl->fw_status = NULL;
+	kfree(wl->fw_status_1);
+	wl->fw_status_1 = NULL;
+	wl->fw_status_2 = NULL;
 	kfree(wl->tx_res_if);
 	wl->tx_res_if = NULL;
 	kfree(wl->target_mem_map);
@@ -1894,6 +1872,9 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
 		wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
 		wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
 		wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
+		wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
+		wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
+		wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
 	} else {
 		/* init ap data */
 		wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
@@ -1903,13 +1884,19 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
 		for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
 			wl12xx_allocate_rate_policy(wl,
 						&wlvif->ap.ucast_rate_idx[i]);
+		wlvif->basic_rate_set = CONF_TX_AP_ENABLED_RATES;
+		/*
+		 * TODO: check if basic_rate shouldn't be
+		 * wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
+		 * instead (the same thing for STA above).
+		*/
+		wlvif->basic_rate = CONF_TX_AP_ENABLED_RATES;
+		/* TODO: this seems to be used only for STA, check it */
+		wlvif->rate_set = CONF_TX_AP_ENABLED_RATES;
 	}
 
 	wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
 	wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
-	wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
-	wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
-	wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
 	wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
 
 	/*
@@ -1919,6 +1906,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
 	wlvif->band = wl->band;
 	wlvif->channel = wl->channel;
 	wlvif->power_level = wl->power_level;
+	wlvif->channel_type = wl->channel_type;
 
 	INIT_WORK(&wlvif->rx_streaming_enable_work,
 		  wl1271_rx_streaming_enable_work);
@@ -2170,6 +2158,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
 {
 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 	int i, ret;
+	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
 
 	wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
 
@@ -2250,11 +2239,25 @@ deinit:
 	wlvif->role_id = WL12XX_INVALID_ROLE_ID;
 	wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
 
-	if (wlvif->bss_type == BSS_TYPE_AP_BSS)
+	if (is_ap)
 		wl->ap_count--;
 	else
 		wl->sta_count--;
 
+	/* Last AP, have more stations. Configure according to STA. */
+	if (wl->ap_count == 0 && is_ap && wl->sta_count) {
+		u8 sta_auth = wl->conf.conn.sta_sleep_auth;
+		/* Configure for power according to debugfs */
+		if (sta_auth != WL1271_PSM_ILLEGAL)
+			wl1271_acx_sleep_auth(wl, sta_auth);
+		/* Configure for power always on */
+		else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
+			wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+		/* Configure for ELP power saving */
+		else
+			wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
+	}
+
 	mutex_unlock(&wl->mutex);
 
 	del_timer_sync(&wlvif->rx_streaming_timer);
@@ -2444,7 +2447,7 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 	} else {
 		/* The current firmware only supports sched_scan in idle */
 		if (wl->sched_scanning) {
-			wl1271_scan_sched_scan_stop(wl);
+			wl1271_scan_sched_scan_stop(wl, wlvif);
 			ieee80211_sched_scan_stopped(wl->hw);
 		}
 
@@ -2469,13 +2472,21 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 	/* if the channel changes while joined, join again */
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
 	    ((wlvif->band != conf->channel->band) ||
-	     (wlvif->channel != channel))) {
+	     (wlvif->channel != channel) ||
+	     (wlvif->channel_type != conf->channel_type))) {
 		/* send all pending packets */
 		wl1271_tx_work_locked(wl);
 		wlvif->band = conf->channel->band;
 		wlvif->channel = channel;
+		wlvif->channel_type = conf->channel_type;
 
-		if (!is_ap) {
+		if (is_ap) {
+			wl1271_set_band_rate(wl, wlvif);
+			ret = wl1271_init_ap_rates(wl, wlvif);
+			if (ret < 0)
+				wl1271_error("AP rate policy change failed %d",
+					     ret);
+		} else {
 			/*
 			 * FIXME: the mac80211 should really provide a fixed
 			 * rate to use here. for now, just use the smallest
@@ -2583,8 +2594,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 	 * 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))
+	if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
+	    ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
+	     (conf->flags & IEEE80211_CONF_IDLE)))
 		wl1271_tx_flush(wl);
 
 	mutex_lock(&wl->mutex);
@@ -2593,6 +2605,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
 		wl->band = conf->channel->band;
 		wl->channel = channel;
+		wl->channel_type = conf->channel_type;
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_POWER)
@@ -2825,17 +2838,6 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 	int ret;
 	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
 
-	/*
-	 * A role set to GEM cipher requires different Tx settings (namely
-	 * spare blocks). Note when we are in this mode so the HW can adjust.
-	 */
-	if (key_type == KEY_GEM) {
-		if (action == KEY_ADD_OR_REPLACE)
-			wlvif->is_gem = true;
-		else if (action == KEY_REMOVE)
-			wlvif->is_gem = false;
-	}
-
 	if (is_ap) {
 		struct wl1271_station *wl_sta;
 		u8 hlid;
@@ -2913,12 +2915,21 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 	return 0;
 }
 
-static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 			     struct ieee80211_vif *vif,
 			     struct ieee80211_sta *sta,
 			     struct ieee80211_key_conf *key_conf)
 {
 	struct wl1271 *wl = hw->priv;
+
+	return wlcore_hw_set_key(wl, cmd, vif, sta, key_conf);
+}
+
+int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
+		   struct ieee80211_vif *vif,
+		   struct ieee80211_sta *sta,
+		   struct ieee80211_key_conf *key_conf)
+{
 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 	int ret;
 	u32 tx_seq_32 = 0;
@@ -3029,6 +3040,7 @@ out_unlock:
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(wlcore_set_key);
 
 static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
 			     struct ieee80211_vif *vif,
@@ -3167,6 +3179,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
 				      struct ieee80211_vif *vif)
 {
 	struct wl1271 *wl = hw->priv;
+	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 	int ret;
 
 	wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
@@ -3180,7 +3193,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
 	if (ret < 0)
 		goto out;
 
-	wl1271_scan_sched_scan_stop(wl);
+	wl1271_scan_sched_scan_stop(wl, wlvif);
 
 	wl1271_ps_elp_sleep(wl);
 out:
@@ -3316,8 +3329,15 @@ static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
 				      skb->data,
 				      skb->len, 0,
 				      rates);
-
 	dev_kfree_skb(skb);
+
+	if (ret < 0)
+		goto out;
+
+	wl1271_debug(DEBUG_AP, "probe response updated");
+	set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
+
+out:
 	return ret;
 }
 
@@ -3422,6 +3442,87 @@ out:
 	return ret;
 }
 
+static int wlcore_set_beacon_template(struct wl1271 *wl,
+				      struct ieee80211_vif *vif,
+				      bool is_ap)
+{
+	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+	struct ieee80211_hdr *hdr;
+	u32 min_rate;
+	int ret;
+	int ieoffset = offsetof(struct ieee80211_mgmt,
+				u.beacon.variable);
+	struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
+	u16 tmpl_id;
+
+	if (!beacon) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	wl1271_debug(DEBUG_MASTER, "beacon updated");
+
+	ret = wl1271_ssid_set(vif, beacon, ieoffset);
+	if (ret < 0) {
+		dev_kfree_skb(beacon);
+		goto out;
+	}
+	min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
+	tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
+		CMD_TEMPL_BEACON;
+	ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
+				      beacon->data,
+				      beacon->len, 0,
+				      min_rate);
+	if (ret < 0) {
+		dev_kfree_skb(beacon);
+		goto out;
+	}
+
+	/*
+	 * In case we already have a probe-resp beacon set explicitly
+	 * by usermode, don't use the beacon data.
+	 */
+	if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
+		goto end_bcn;
+
+	/* remove TIM ie from probe response */
+	wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
+
+	/*
+	 * remove p2p ie from probe response.
+	 * the fw reponds to probe requests that don't include
+	 * the p2p ie. probe requests with p2p ie will be passed,
+	 * and will be responded by the supplicant (the spec
+	 * forbids including the p2p ie when responding to probe
+	 * requests that didn't include it).
+	 */
+	wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
+				WLAN_OUI_TYPE_WFA_P2P, ieoffset);
+
+	hdr = (struct ieee80211_hdr *) beacon->data;
+	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					 IEEE80211_STYPE_PROBE_RESP);
+	if (is_ap)
+		ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
+							   beacon->data,
+							   beacon->len,
+							   min_rate);
+	else
+		ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+					      CMD_TEMPL_PROBE_RESPONSE,
+					      beacon->data,
+					      beacon->len, 0,
+					      min_rate);
+end_bcn:
+	dev_kfree_skb(beacon);
+	if (ret < 0)
+		goto out;
+
+out:
+	return ret;
+}
+
 static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
 					  struct ieee80211_vif *vif,
 					  struct ieee80211_bss_conf *bss_conf,
@@ -3440,81 +3541,12 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
 
 	if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
 		u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
-		if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
-			wl1271_debug(DEBUG_AP, "probe response updated");
-			set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
-		}
+
+		wl1271_ap_set_probe_resp_tmpl(wl, rate, vif);
 	}
 
 	if ((changed & BSS_CHANGED_BEACON)) {
-		struct ieee80211_hdr *hdr;
-		u32 min_rate;
-		int ieoffset = offsetof(struct ieee80211_mgmt,
-					u.beacon.variable);
-		struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
-		u16 tmpl_id;
-
-		if (!beacon) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		wl1271_debug(DEBUG_MASTER, "beacon updated");
-
-		ret = wl1271_ssid_set(vif, beacon, ieoffset);
-		if (ret < 0) {
-			dev_kfree_skb(beacon);
-			goto out;
-		}
-		min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
-		tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
-				  CMD_TEMPL_BEACON;
-		ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
-					      beacon->data,
-					      beacon->len, 0,
-					      min_rate);
-		if (ret < 0) {
-			dev_kfree_skb(beacon);
-			goto out;
-		}
-
-		/*
-		 * In case we already have a probe-resp beacon set explicitly
-		 * by usermode, don't use the beacon data.
-		 */
-		if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
-			goto end_bcn;
-
-		/* remove TIM ie from probe response */
-		wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
-
-		/*
-		 * remove p2p ie from probe response.
-		 * the fw reponds to probe requests that don't include
-		 * the p2p ie. probe requests with p2p ie will be passed,
-		 * and will be responded by the supplicant (the spec
-		 * forbids including the p2p ie when responding to probe
-		 * requests that didn't include it).
-		 */
-		wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
-					WLAN_OUI_TYPE_WFA_P2P, ieoffset);
-
-		hdr = (struct ieee80211_hdr *) beacon->data;
-		hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-						 IEEE80211_STYPE_PROBE_RESP);
-		if (is_ap)
-			ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
-						beacon->data,
-						beacon->len,
-						min_rate);
-		else
-			ret = wl1271_cmd_template_set(wl, wlvif->role_id,
-						CMD_TEMPL_PROBE_RESPONSE,
-						beacon->data,
-						beacon->len, 0,
-						min_rate);
-end_bcn:
-		dev_kfree_skb(beacon);
+		ret = wlcore_set_beacon_template(wl, vif, is_ap);
 		if (ret < 0)
 			goto out;
 	}
@@ -3551,6 +3583,14 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
 		ret = wl1271_ap_init_templates(wl, vif);
 		if (ret < 0)
 			goto out;
+
+		ret = wl1271_ap_set_probe_resp_tmpl(wl, wlvif->basic_rate, vif);
+		if (ret < 0)
+			goto out;
+
+		ret = wlcore_set_beacon_template(wl, vif, true);
+		if (ret < 0)
+			goto out;
 	}
 
 	ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
@@ -3691,7 +3731,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
 		sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
 		if (sta->ht_cap.ht_supported)
 			sta_rate_set |=
-			    (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
+			  (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
+			  (sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
 		sta_ht_cap = sta->ht_cap;
 		sta_exists = true;
 
@@ -3704,13 +3745,11 @@ sta_not_found:
 			u32 rates;
 			int ieoffset;
 			wlvif->aid = bss_conf->aid;
+			wlvif->channel_type = bss_conf->channel_type;
 			wlvif->beacon_int = bss_conf->beacon_int;
 			do_join = true;
 			set_assoc = true;
 
-			/* Cancel connection_loss_work */
-			cancel_delayed_work_sync(&wl->connection_loss_work);
-
 			/*
 			 * use basic rates from AP, and determine lowest rate
 			 * to use with control frames.
@@ -3960,6 +3999,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 	wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
 		     (int)changed);
 
+	/*
+	 * make sure to cancel pending disconnections if our association
+	 * state changed
+	 */
+	if (!is_ap && (changed & BSS_CHANGED_ASSOC))
+		cancel_delayed_work_sync(&wl->connection_loss_work);
+
+	if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) &&
+	    !bss_conf->enable_beacon)
+		wl1271_tx_flush(wl);
+
 	mutex_lock(&wl->mutex);
 
 	if (unlikely(wl->state == WL1271_STATE_OFF))
@@ -4068,16 +4118,13 @@ out:
 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;
-
+	survey->filled = 0;
 	return 0;
 }
 
@@ -4343,9 +4390,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
 
 	case IEEE80211_AMPDU_RX_STOP:
 		if (!(*ba_bitmap & BIT(tid))) {
-			ret = -EINVAL;
-			wl1271_error("no active RX BA session on tid: %d",
+			/*
+			 * this happens on reconfig - so only output a debug
+			 * message for now, and don't fail the function.
+			 */
+			wl1271_debug(DEBUG_MAC80211,
+				     "no active RX BA session on tid: %d",
 				     tid);
+			ret = 0;
 			break;
 		}
 
@@ -4636,7 +4688,7 @@ static const struct ieee80211_ops wl1271_ops = {
 	.prepare_multicast = wl1271_op_prepare_multicast,
 	.configure_filter = wl1271_op_configure_filter,
 	.tx = wl1271_op_tx,
-	.set_key = wl1271_op_set_key,
+	.set_key = wlcore_op_set_key,
 	.hw_scan = wl1271_op_hw_scan,
 	.cancel_hw_scan = wl1271_op_cancel_hw_scan,
 	.sched_scan_start = wl1271_op_sched_scan_start,
@@ -4905,14 +4957,8 @@ static int wl1271_register_hw(struct wl1271 *wl)
 	if (wl->mac80211_registered)
 		return 0;
 
-	ret = wl12xx_get_hw_info(wl);
-	if (ret < 0) {
-		wl1271_error("couldn't get hw info");
-		goto out;
-	}
-
-	ret = wl1271_fetch_nvs(wl);
-	if (ret == 0) {
+	wl1271_fetch_nvs(wl);
+	if (wl->nvs != NULL) {
 		/* NOTE: The wl->nvs->nvs element must be first, in
 		 * order to simplify the casting, we assume it is at
 		 * the beginning of the wl->nvs structure.
@@ -4960,6 +5006,29 @@ static void wl1271_unregister_hw(struct wl1271 *wl)
 
 }
 
+static const struct ieee80211_iface_limit wlcore_iface_limits[] = {
+	{
+		.max = 2,
+		.types = BIT(NL80211_IFTYPE_STATION),
+	},
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_AP) |
+			 BIT(NL80211_IFTYPE_P2P_GO) |
+			 BIT(NL80211_IFTYPE_P2P_CLIENT),
+	},
+};
+
+static const struct ieee80211_iface_combination
+wlcore_iface_combinations[] = {
+	{
+	  .num_different_channels = 1,
+	  .max_interfaces = 2,
+	  .limits = wlcore_iface_limits,
+	  .n_limits = ARRAY_SIZE(wlcore_iface_limits),
+	},
+};
+
 static int wl1271_init_ieee80211(struct wl1271 *wl)
 {
 	static const u32 cipher_suites[] = {
@@ -4970,9 +5039,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
 		WL1271_CIPHER_SUITE_GEM,
 	};
 
-	/* The tx descriptor buffer and the TKIP space. */
-	wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
-		sizeof(struct wl1271_tx_hw_descr);
+	/* The tx descriptor buffer */
+	wl->hw->extra_tx_headroom = sizeof(struct wl1271_tx_hw_descr);
+
+	if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE)
+		wl->hw->extra_tx_headroom += WL1271_EXTRA_SPACE_TKIP;
 
 	/* unit us */
 	/* FIXME: find a proper value */
@@ -5025,12 +5096,14 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
 	 */
 	memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
 	       sizeof(wl1271_band_2ghz));
-	memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap, &wl->ht_cap,
-	       sizeof(wl->ht_cap));
+	memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap,
+	       &wl->ht_cap[IEEE80211_BAND_2GHZ],
+	       sizeof(*wl->ht_cap));
 	memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
 	       sizeof(wl1271_band_5ghz));
-	memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap, &wl->ht_cap,
-	       sizeof(wl->ht_cap));
+	memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap,
+	       &wl->ht_cap[IEEE80211_BAND_5GHZ],
+	       sizeof(*wl->ht_cap));
 
 	wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
 		&wl->bands[IEEE80211_BAND_2GHZ];
@@ -5049,6 +5122,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
 		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
 		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
 
+	/* allowed interface combinations */
+	wl->hw->wiphy->iface_combinations = wlcore_iface_combinations;
+	wl->hw->wiphy->n_iface_combinations =
+		ARRAY_SIZE(wlcore_iface_combinations);
+
 	SET_IEEE80211_DEV(wl->hw, wl->dev);
 
 	wl->hw->sta_data_size = sizeof(struct wl1271_station);
@@ -5117,8 +5195,10 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
 	wl->rx_counter = 0;
 	wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
 	wl->band = IEEE80211_BAND_2GHZ;
+	wl->channel_type = NL80211_CHAN_NO_HT;
 	wl->flags = 0;
 	wl->sg_enabled = true;
+	wl->sleep_auth = WL1271_PSM_ILLEGAL;
 	wl->hw_pg_ver = -1;
 	wl->ap_ps_map = 0;
 	wl->ap_fw_ps_map = 0;
@@ -5142,6 +5222,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
 	wl->state = WL1271_STATE_OFF;
 	wl->fw_type = WL12XX_FW_TYPE_NONE;
 	mutex_init(&wl->mutex);
+	mutex_init(&wl->flush_mutex);
 
 	order = get_order(WL1271_AGGR_BUFFER_SIZE);
 	wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
@@ -5222,7 +5303,7 @@ int wlcore_free_hw(struct wl1271 *wl)
 	kfree(wl->nvs);
 	wl->nvs = NULL;
 
-	kfree(wl->fw_status);
+	kfree(wl->fw_status_1);
 	kfree(wl->tx_res_if);
 	destroy_workqueue(wl->freezable_wq);
 
@@ -5279,8 +5360,6 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
 	wlcore_adjust_conf(wl);
 
 	wl->irq = platform_get_irq(pdev, 0);
-	wl->ref_clock = pdata->board_ref_clock;
-	wl->tcxo_clock = pdata->board_tcxo_clock;
 	wl->platform_quirks = pdata->platform_quirks;
 	wl->set_power = pdata->set_power;
 	wl->dev = &pdev->dev;
@@ -5316,6 +5395,16 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
 	}
 	disable_irq(wl->irq);
 
+	ret = wl12xx_get_hw_info(wl);
+	if (ret < 0) {
+		wl1271_error("couldn't get hw info");
+		goto out;
+	}
+
+	ret = wl->ops->identify_chip(wl);
+	if (ret < 0)
+		goto out;
+
 	ret = wl1271_init_ieee80211(wl);
 	if (ret)
 		goto out_irq;
diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c
index 756eee2..95d8797 100644
--- a/drivers/net/wireless/ti/wlcore/ps.c
+++ b/drivers/net/wireless/ti/wlcore/ps.c
@@ -28,6 +28,8 @@
 
 #define WL1271_WAKEUP_TIMEOUT 500
 
+#define ELP_ENTRY_DELAY  5
+
 void wl1271_elp_work(struct work_struct *work)
 {
 	struct delayed_work *dwork;
@@ -72,8 +74,9 @@ out:
 void wl1271_ps_elp_sleep(struct wl1271 *wl)
 {
 	struct wl12xx_vif *wlvif;
+	u32 timeout;
 
-	if (wl->quirks & WLCORE_QUIRK_NO_ELP)
+	if (wl->sleep_auth != WL1271_PSM_ELP)
 		return;
 
 	/* we shouldn't get consecutive sleep requests */
@@ -89,8 +92,13 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
 			return;
 	}
 
+	if (wl->conf.conn.forced_ps)
+		timeout = ELP_ENTRY_DELAY;
+	else
+		timeout = wl->conf.conn.dynamic_ps_timeout;
+
 	ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
-		msecs_to_jiffies(wl->conf.conn.dynamic_ps_timeout));
+				     msecs_to_jiffies(timeout));
 }
 
 int wl1271_ps_elp_wakeup(struct wl1271 *wl)
@@ -185,8 +193,12 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 
 		set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
 
-		/* enable beacon early termination. Not relevant for 5GHz */
-		if (wlvif->band == IEEE80211_BAND_2GHZ) {
+		/*
+		 * enable beacon early termination.
+		 * Not relevant for 5GHz and for high rates.
+		 */
+		if ((wlvif->band == IEEE80211_BAND_2GHZ) &&
+		    (wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) {
 			ret = wl1271_acx_bet_enable(wl, wlvif, true);
 			if (ret < 0)
 				return ret;
@@ -196,7 +208,8 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 		wl1271_debug(DEBUG_PSM, "leaving psm");
 
 		/* disable beacon early termination */
-		if (wlvif->band == IEEE80211_BAND_2GHZ) {
+		if ((wlvif->band == IEEE80211_BAND_2GHZ) &&
+		    (wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) {
 			ret = wl1271_acx_bet_enable(wl, wlvif, false);
 			if (ret < 0)
 				return ret;
diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c
index d6a3c6b..a1db4e0 100644
--- a/drivers/net/wireless/ti/wlcore/rx.c
+++ b/drivers/net/wireless/ti/wlcore/rx.c
@@ -127,7 +127,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
 	}
 
 	if (rx_align == WLCORE_RX_BUF_UNALIGNED)
-		reserved = NET_IP_ALIGN;
+		reserved = RX_BUF_ALIGN;
 
 	/* the data read starts with the descriptor */
 	desc = (struct wl1271_rx_descriptor *) data;
@@ -175,7 +175,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
 	 */
 	memcpy(buf, data + sizeof(*desc), pkt_data_len);
 	if (rx_align == WLCORE_RX_BUF_PADDED)
-		skb_pull(skb, NET_IP_ALIGN);
+		skb_pull(skb, RX_BUF_ALIGN);
 
 	*hlid = desc->hlid;
 
@@ -186,6 +186,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
 		is_data = 1;
 
 	wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
+	wlcore_hw_set_rx_csum(wl, desc, skb);
 
 	seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 	wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb,
@@ -199,12 +200,12 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
 	return is_data;
 }
 
-void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
+void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
 {
 	unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
 	u32 buf_size;
-	u32 fw_rx_counter  = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
-	u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
+	u32 fw_rx_counter = status->fw_rx_counter % wl->num_rx_desc;
+	u32 drv_rx_counter = wl->rx_counter % wl->num_rx_desc;
 	u32 rx_counter;
 	u32 pkt_len, align_pkt_len;
 	u32 pkt_offset, des;
@@ -223,7 +224,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
 				break;
 			buf_size += align_pkt_len;
 			rx_counter++;
-			rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
+			rx_counter %= wl->num_rx_desc;
 		}
 
 		if (buf_size == 0) {
@@ -263,7 +264,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
 
 			wl->rx_counter++;
 			drv_rx_counter++;
-			drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
+			drv_rx_counter %= wl->num_rx_desc;
 			pkt_offset += wlcore_rx_get_align_buf_size(wl, pkt_len);
 		}
 	}
diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h
index e9a162a..4324a42 100644
--- a/drivers/net/wireless/ti/wlcore/rx.h
+++ b/drivers/net/wireless/ti/wlcore/rx.h
@@ -38,8 +38,6 @@
 #define RX_DESC_PACKETID_SHIFT 11
 #define RX_MAX_PACKET_ID 3
 
-#define NUM_RX_PKT_DESC_MOD_MASK   7
-
 #define RX_DESC_VALID_FCS         0x0001
 #define RX_DESC_MATCH_RXADDR1     0x0002
 #define RX_DESC_MCAST             0x0004
@@ -102,6 +100,15 @@
 /* If set, the start of IP payload is not 4 bytes aligned */
 #define RX_BUF_UNALIGNED_PAYLOAD     BIT(20)
 
+/* If set, the buffer was padded by the FW to be 4 bytes aligned */
+#define RX_BUF_PADDED_PAYLOAD        BIT(30)
+
+/*
+ * Account for the padding inserted by the FW in case of RX_ALIGNMENT
+ * or for fixing alignment in case the packet wasn't aligned.
+ */
+#define RX_BUF_ALIGN                 2
+
 /* Describes the alignment state of a Rx buffer */
 enum wl_rx_buf_align {
 	WLCORE_RX_BUF_ALIGNED,
@@ -136,7 +143,7 @@ struct wl1271_rx_descriptor {
 	u8  reserved;
 } __packed;
 
-void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status);
+void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status);
 u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
 int wl1271_rx_filter_enable(struct wl1271 *wl,
 			    int index, bool enable,
diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c
index ade21a0..d9daed5 100644
--- a/drivers/net/wireless/ti/wlcore/scan.c
+++ b/drivers/net/wireless/ti/wlcore/scan.c
@@ -411,7 +411,8 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
 				    struct cfg80211_sched_scan_request *req,
 				    struct conn_scan_ch_params *channels,
 				    u32 band, bool radar, bool passive,
-				    int start, int max_channels)
+				    int start, int max_channels,
+				    u8 *n_pactive_ch)
 {
 	struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
 	int i, j;
@@ -479,6 +480,23 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
 			channels[j].tx_power_att = req->channels[i]->max_power;
 			channels[j].channel = req->channels[i]->hw_value;
 
+			if ((band == IEEE80211_BAND_2GHZ) &&
+			    (channels[j].channel >= 12) &&
+			    (channels[j].channel <= 14) &&
+			    (flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
+			    !force_passive) {
+				/* pactive channels treated as DFS */
+				channels[j].flags = SCAN_CHANNEL_FLAGS_DFS;
+
+				/*
+				 * n_pactive_ch is counted down from the end of
+				 * the passive channel list
+				 */
+				(*n_pactive_ch)++;
+				wl1271_debug(DEBUG_SCAN, "n_pactive_ch = %d",
+					     *n_pactive_ch);
+			}
+
 			j++;
 		}
 	}
@@ -491,38 +509,47 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
 				struct cfg80211_sched_scan_request *req,
 				struct wl1271_cmd_sched_scan_config *cfg)
 {
+	u8 n_pactive_ch = 0;
+
 	cfg->passive[0] =
 		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
 						    IEEE80211_BAND_2GHZ,
 						    false, true, 0,
-						    MAX_CHANNELS_2GHZ);
+						    MAX_CHANNELS_2GHZ,
+						    &n_pactive_ch);
 	cfg->active[0] =
 		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
 						    IEEE80211_BAND_2GHZ,
 						    false, false,
 						    cfg->passive[0],
-						    MAX_CHANNELS_2GHZ);
+						    MAX_CHANNELS_2GHZ,
+						    &n_pactive_ch);
 	cfg->passive[1] =
 		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
 						    IEEE80211_BAND_5GHZ,
 						    false, true, 0,
-						    MAX_CHANNELS_5GHZ);
+						    MAX_CHANNELS_5GHZ,
+						    &n_pactive_ch);
 	cfg->dfs =
 		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
 						    IEEE80211_BAND_5GHZ,
 						    true, true,
 						    cfg->passive[1],
-						    MAX_CHANNELS_5GHZ);
+						    MAX_CHANNELS_5GHZ,
+						    &n_pactive_ch);
 	cfg->active[1] =
 		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
 						    IEEE80211_BAND_5GHZ,
 						    false, false,
 						    cfg->passive[1] + cfg->dfs,
-						    MAX_CHANNELS_5GHZ);
+						    MAX_CHANNELS_5GHZ,
+						    &n_pactive_ch);
 	/* 802.11j channels are not supported yet */
 	cfg->passive[2] = 0;
 	cfg->active[2] = 0;
 
+	cfg->n_pactive_ch = n_pactive_ch;
+
 	wl1271_debug(DEBUG_SCAN, "    2.4GHz: active %d passive %d",
 		     cfg->active[0], cfg->passive[0]);
 	wl1271_debug(DEBUG_SCAN, "    5GHz: active %d passive %d",
@@ -537,6 +564,7 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
 /* Returns the scan type to be used or a negative value on error */
 static int
 wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
+				 struct wl12xx_vif *wlvif,
 				 struct cfg80211_sched_scan_request *req)
 {
 	struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL;
@@ -565,6 +593,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
 		goto out;
 	}
 
+	cmd->role_id = wlvif->dev_role_id;
 	if (!n_match_ssids) {
 		/* No filter, with ssids */
 		type = SCAN_SSID_FILTER_DISABLED;
@@ -603,7 +632,9 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
 					continue;
 
 				for (j = 0; j < cmd->n_ssids; j++)
-					if (!memcmp(req->ssids[i].ssid,
+					if ((req->ssids[i].ssid_len ==
+					     req->ssids[j].ssid_len) &&
+					    !memcmp(req->ssids[i].ssid,
 						   cmd->ssids[j].ssid,
 						   req->ssids[i].ssid_len)) {
 						cmd->ssids[j].type =
@@ -652,6 +683,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
 	if (!cfg)
 		return -ENOMEM;
 
+	cfg->role_id = wlvif->dev_role_id;
 	cfg->rssi_threshold = c->rssi_threshold;
 	cfg->snr_threshold  = c->snr_threshold;
 	cfg->n_probe_reqs = c->num_probe_reqs;
@@ -669,7 +701,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
 		cfg->intervals[i] = cpu_to_le32(req->interval);
 
 	cfg->ssid_len = 0;
-	ret = wl12xx_scan_sched_scan_ssid_list(wl, req);
+	ret = wl12xx_scan_sched_scan_ssid_list(wl, wlvif, req);
 	if (ret < 0)
 		goto out;
 
@@ -741,6 +773,7 @@ int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 	if (!start)
 		return -ENOMEM;
 
+	start->role_id = wlvif->dev_role_id;
 	start->tag = WL1271_SCAN_DEFAULT_TAG;
 
 	ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
@@ -762,7 +795,7 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl)
 	ieee80211_sched_scan_results(wl->hw);
 }
 
-void wl1271_scan_sched_scan_stop(struct wl1271 *wl)
+void wl1271_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif)
 {
 	struct wl1271_cmd_sched_scan_stop *stop;
 	int ret = 0;
@@ -776,6 +809,7 @@ void wl1271_scan_sched_scan_stop(struct wl1271 *wl)
 		return;
 	}
 
+	stop->role_id = wlvif->dev_role_id;
 	stop->tag = WL1271_SCAN_DEFAULT_TAG;
 
 	ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
diff --git a/drivers/net/wireless/ti/wlcore/scan.h b/drivers/net/wireless/ti/wlcore/scan.h
index 81ee36a..29f3c8d6 100644
--- a/drivers/net/wireless/ti/wlcore/scan.h
+++ b/drivers/net/wireless/ti/wlcore/scan.h
@@ -40,7 +40,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
 				     struct cfg80211_sched_scan_request *req,
 				     struct ieee80211_sched_scan_ies *ies);
 int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-void wl1271_scan_sched_scan_stop(struct wl1271 *wl);
+void wl1271_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif);
 void wl1271_scan_sched_scan_results(struct wl1271 *wl);
 
 #define WL1271_SCAN_MAX_CHANNELS       24
@@ -142,7 +142,8 @@ enum {
 	SCAN_BSS_TYPE_ANY,
 };
 
-#define SCAN_CHANNEL_FLAGS_DFS		BIT(0)
+#define SCAN_CHANNEL_FLAGS_DFS		BIT(0) /* channel is passive until an
+						  activity is detected on it */
 #define SCAN_CHANNEL_FLAGS_DFS_ENABLED	BIT(1)
 
 struct conn_scan_ch_params {
@@ -185,7 +186,10 @@ struct wl1271_cmd_sched_scan_config {
 
 	u8 dfs;
 
-	u8 padding[3];
+	u8 n_pactive_ch; /* number of pactive (passive until fw detects energy)
+			    channels in BG band */
+	u8 role_id;
+	u8 padding[1];
 
 	struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
 	struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
@@ -212,21 +216,24 @@ struct wl1271_cmd_sched_scan_ssid_list {
 
 	u8 n_ssids;
 	struct wl1271_ssid ssids[SCHED_SCAN_MAX_SSIDS];
-	u8 padding[3];
+	u8 role_id;
+	u8 padding[2];
 } __packed;
 
 struct wl1271_cmd_sched_scan_start {
 	struct wl1271_cmd_header header;
 
 	u8 tag;
-	u8 padding[3];
+	u8 role_id;
+	u8 padding[2];
 } __packed;
 
 struct wl1271_cmd_sched_scan_stop {
 	struct wl1271_cmd_header header;
 
 	u8 tag;
-	u8 padding[3];
+	u8 role_id;
+	u8 padding[2];
 } __packed;
 
 
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c
index 0a72347..c67ec48 100644
--- a/drivers/net/wireless/ti/wlcore/sdio.c
+++ b/drivers/net/wireless/ti/wlcore/sdio.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/platform_device.h>
+#include <linux/mmc/sdio.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/card.h>
@@ -32,6 +33,7 @@
 #include <linux/gpio.h>
 #include <linux/wl12xx.h>
 #include <linux/pm_runtime.h>
+#include <linux/printk.h>
 
 #include "wlcore.h"
 #include "wl12xx_80211.h"
@@ -45,6 +47,8 @@
 #define SDIO_DEVICE_ID_TI_WL1271	0x4076
 #endif
 
+static bool dump = false;
+
 struct wl12xx_sdio_glue {
 	struct device *dev;
 	struct platform_device *core;
@@ -76,6 +80,13 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
 
 	sdio_claim_host(func);
 
+	if (unlikely(dump)) {
+		printk(KERN_DEBUG "wlcore_sdio: READ from 0x%04x\n", addr);
+		print_hex_dump(KERN_DEBUG, "wlcore_sdio: READ ",
+				DUMP_PREFIX_OFFSET, 16, 1,
+				buf, len, false);
+	}
+
 	if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
 		((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
 		dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
@@ -105,6 +116,13 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
 
 	sdio_claim_host(func);
 
+	if (unlikely(dump)) {
+		printk(KERN_DEBUG "wlcore_sdio: WRITE to 0x%04x\n", addr);
+		print_hex_dump(KERN_DEBUG, "wlcore_sdio: WRITE ",
+				DUMP_PREFIX_OFFSET, 16, 1,
+				buf, len, false);
+	}
+
 	if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
 		sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
 		dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
@@ -196,6 +214,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 	struct resource res[1];
 	mmc_pm_flag_t mmcflags;
 	int ret = -ENOMEM;
+	const char *chip_family;
 
 	/* We are only able to handle the wlan function */
 	if (func->num != 0x02)
@@ -236,7 +255,18 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 	/* Tell PM core that we don't need the card to be powered now */
 	pm_runtime_put_noidle(&func->dev);
 
-	glue->core = platform_device_alloc("wl12xx", -1);
+	/*
+	 * Due to a hardware bug, we can't differentiate wl18xx from
+	 * wl12xx, because both report the same device ID.  The only
+	 * way to differentiate is by checking the SDIO revision,
+	 * which is 3.00 on the wl18xx chips.
+	 */
+	if (func->card->cccr.sdio_vsn == SDIO_SDIO_REV_3_00)
+		chip_family = "wl18xx";
+	else
+		chip_family = "wl12xx";
+
+	glue->core = platform_device_alloc(chip_family, -1);
 	if (!glue->core) {
 		dev_err(glue->dev, "can't allocate platform_device");
 		ret = -ENOMEM;
@@ -367,6 +397,9 @@ static void __exit wl1271_exit(void)
 module_init(wl1271_init);
 module_exit(wl1271_exit);
 
+module_param(dump, bool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(dump, "Enable sdio read/write dumps.");
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
diff --git a/drivers/net/wireless/ti/wlcore/testmode.c b/drivers/net/wireless/ti/wlcore/testmode.c
index 0e59ea2..eeb339d 100644
--- a/drivers/net/wireless/ti/wlcore/testmode.c
+++ b/drivers/net/wireless/ti/wlcore/testmode.c
@@ -108,6 +108,20 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
 	}
 
 	if (answer) {
+		/* If we got bip calibration answer print radio status */
+		struct wl1271_cmd_cal_p2g *params =
+			(struct wl1271_cmd_cal_p2g *) buf;
+
+		s16 radio_status = (s16) le16_to_cpu(params->radio_status);
+
+		if (params->test.id == TEST_CMD_P2G_CAL &&
+		    radio_status < 0)
+			wl1271_warning("testmode cmd: radio status=%d",
+					radio_status);
+		else
+			wl1271_info("testmode cmd: radio status=%d",
+					radio_status);
+
 		len = nla_total_size(buf_len);
 		skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
 		if (!skb) {
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index 6893bc2..6b1afa6 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -72,7 +72,7 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
 	return id;
 }
 
-static void wl1271_free_tx_id(struct wl1271 *wl, int id)
+void wl1271_free_tx_id(struct wl1271 *wl, int id)
 {
 	if (__test_and_clear_bit(id, wl->tx_frames_map)) {
 		if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc))
@@ -82,6 +82,7 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
 		wl->tx_frames_cnt--;
 	}
 }
+EXPORT_SYMBOL(wl1271_free_tx_id);
 
 static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
 						 struct sk_buff *skb)
@@ -127,6 +128,7 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
 {
 	return wl->dummy_packet == skb;
 }
+EXPORT_SYMBOL(wl12xx_is_dummy_packet);
 
 u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			 struct sk_buff *skb)
@@ -146,10 +148,10 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			return wl->system_hlid;
 
 		hdr = (struct ieee80211_hdr *)skb->data;
-		if (ieee80211_is_mgmt(hdr->frame_control))
-			return wlvif->ap.global_hlid;
-		else
+		if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
 			return wlvif->ap.bcast_hlid;
+		else
+			return wlvif->ap.global_hlid;
 	}
 }
 
@@ -176,37 +178,34 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
 					  unsigned int packet_length)
 {
-	if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN)
-		return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
-	else
+	if ((wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) ||
+	    !(wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN))
 		return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
+	else
+		return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
 }
 EXPORT_SYMBOL(wlcore_calc_packet_alignment);
 
 static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			      struct sk_buff *skb, u32 extra, u32 buf_offset,
-			      u8 hlid)
+			      u8 hlid, bool is_gem)
 {
 	struct wl1271_tx_hw_descr *desc;
 	u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
 	u32 total_blocks;
 	int id, ret = -EBUSY, ac;
-	u32 spare_blocks = wl->normal_tx_spare;
-	bool is_dummy = false;
+	u32 spare_blocks;
 
 	if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
 		return -EAGAIN;
 
+	spare_blocks = wlcore_hw_get_spare_blocks(wl, is_gem);
+
 	/* allocate free identifier for the packet */
 	id = wl1271_alloc_tx_id(wl, skb);
 	if (id < 0)
 		return id;
 
-	if (unlikely(wl12xx_is_dummy_packet(wl, skb)))
-		is_dummy = true;
-	else if (wlvif->is_gem)
-		spare_blocks = wl->gem_tx_spare;
-
 	total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks);
 
 	if (total_blocks <= wl->tx_blocks_available) {
@@ -228,7 +227,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 		ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
 		wl->tx_allocated_pkts[ac]++;
 
-		if (!is_dummy && wlvif &&
+		if (!wl12xx_is_dummy_packet(wl, skb) && wlvif &&
 		    wlvif->bss_type == BSS_TYPE_AP_BSS &&
 		    test_bit(hlid, wlvif->ap.sta_hlid_map))
 			wl->links[hlid].allocated_pkts++;
@@ -268,6 +267,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 	if (extra) {
 		int hdrlen = ieee80211_hdrlen(frame_control);
 		memmove(frame_start, hdr, hdrlen);
+		skb_set_network_header(skb, skb_network_offset(skb) + extra);
 	}
 
 	/* configure packet life time */
@@ -305,11 +305,15 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 	if (is_dummy || !wlvif)
 		rate_idx = 0;
 	else if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
-		/* if the packets are destined for AP (have a STA entry)
-		   send them with AP rate policies, otherwise use default
-		   basic rates */
+		/*
+		 * if the packets are destined for AP (have a STA entry)
+		 * send them with AP rate policies (EAPOLs are an exception),
+		 * otherwise use default basic rates
+		 */
 		if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
 			rate_idx = wlvif->sta.p2p_rate_idx;
+		else if (skb->protocol == cpu_to_be16(ETH_P_PAE))
+			rate_idx = wlvif->sta.basic_rate_idx;
 		else if (control->control.sta)
 			rate_idx = wlvif->sta.ap_rate_idx;
 		else
@@ -330,9 +334,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 	    ieee80211_has_protected(frame_control))
 		tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
 
-	desc->reserved = 0;
 	desc->tx_attr = cpu_to_le16(tx_attr);
 
+	wlcore_hw_set_tx_desc_csum(wl, desc, skb);
 	wlcore_hw_set_tx_desc_data_len(wl, desc, skb);
 }
 
@@ -346,6 +350,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 	u32 total_len;
 	u8 hlid;
 	bool is_dummy;
+	bool is_gem = false;
 
 	if (!skb)
 		return -EINVAL;
@@ -355,7 +360,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 	/* TODO: handle dummy packets on multi-vifs */
 	is_dummy = wl12xx_is_dummy_packet(wl, skb);
 
-	if (info->control.hw_key &&
+	if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
+	    info->control.hw_key &&
 	    info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
 		extra = WL1271_EXTRA_SPACE_TKIP;
 
@@ -373,6 +379,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 				return ret;
 			wlvif->default_key = idx;
 		}
+
+		is_gem = (cipher == WL1271_CIPHER_SUITE_GEM);
 	}
 	hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
 	if (hlid == WL12XX_INVALID_LINK_ID) {
@@ -380,7 +388,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 		return -EINVAL;
 	}
 
-	ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid);
+	ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid,
+				 is_gem);
 	if (ret < 0)
 		return ret;
 
@@ -425,10 +434,10 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
 		rate_set >>= 1;
 	}
 
-	/* MCS rates indication are on bits 16 - 23 */
+	/* MCS rates indication are on bits 16 - 31 */
 	rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates;
 
-	for (bit = 0; bit < 8; bit++) {
+	for (bit = 0; bit < 16; bit++) {
 		if (rate_set & 0x1)
 			enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit);
 		rate_set >>= 1;
@@ -439,18 +448,15 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
 
 void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
 {
-	unsigned long flags;
 	int i;
 
 	for (i = 0; i < NUM_TX_QUEUES; i++) {
-		if (test_bit(i, &wl->stopped_queues_map) &&
+		if (wlcore_is_queue_stopped_by_reason(wl, i,
+			WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
 		    wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) {
 			/* firmware buffer has space, restart queues */
-			spin_lock_irqsave(&wl->wl_lock, flags);
-			ieee80211_wake_queue(wl->hw,
-					     wl1271_tx_get_mac80211_queue(i));
-			clear_bit(i, &wl->stopped_queues_map);
-			spin_unlock_irqrestore(&wl->wl_lock, flags);
+			wlcore_wake_queue(wl, i,
+					  WLCORE_QUEUE_STOP_REASON_WATERMARK);
 		}
 	}
 }
@@ -661,7 +667,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
 	struct wl12xx_vif *wlvif;
 	struct sk_buff *skb;
 	struct wl1271_tx_hw_descr *desc;
-	u32 buf_offset = 0;
+	u32 buf_offset = 0, last_len = 0;
 	bool sent_packets = false;
 	unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
 	int ret;
@@ -685,6 +691,9 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
 			 * Flush buffer and try again.
 			 */
 			wl1271_skb_queue_head(wl, wlvif, skb);
+
+			buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset,
+							    last_len);
 			wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
 					  buf_offset, true);
 			sent_packets = true;
@@ -710,7 +719,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
 				ieee80211_free_txskb(wl->hw, skb);
 			goto out_ack;
 		}
-		buf_offset += ret;
+		last_len = ret;
+		buf_offset += last_len;
 		wl->tx_packets_count++;
 		if (has_data) {
 			desc = (struct wl1271_tx_hw_descr *) skb->data;
@@ -720,6 +730,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
 
 out_ack:
 	if (buf_offset) {
+		buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len);
 		wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
 				  buf_offset, true);
 		sent_packets = true;
@@ -849,7 +860,8 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 	skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
 
 	/* remove TKIP header space if present */
-	if (info->control.hw_key &&
+	if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
+	    info->control.hw_key &&
 	    info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
 		int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
 		memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data,
@@ -871,8 +883,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 /* Called upon reception of a TX complete interrupt */
 void wl1271_tx_complete(struct wl1271 *wl)
 {
-	struct wl1271_acx_mem_map *memmap =
-		(struct wl1271_acx_mem_map *)wl->target_mem_map;
+	struct wl1271_acx_mem_map *memmap = wl->target_mem_map;
 	u32 count, fw_counter;
 	u32 i;
 
@@ -958,7 +969,7 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 
 }
 /* caller must hold wl->mutex and TX must be stopped */
-void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
+void wl12xx_tx_reset(struct wl1271 *wl)
 {
 	int i;
 	struct sk_buff *skb;
@@ -973,15 +984,12 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
 			wl->tx_queue_count[i] = 0;
 	}
 
-	wl->stopped_queues_map = 0;
-
 	/*
 	 * Make sure the driver is at a consistent state, in case this
 	 * function is called from a context other than interface removal.
 	 * This call will always wake the TX queues.
 	 */
-	if (reset_tx_queues)
-		wl1271_handle_tx_low_watermark(wl);
+	wl1271_handle_tx_low_watermark(wl);
 
 	for (i = 0; i < wl->num_tx_desc; i++) {
 		if (wl->tx_frames[i] == NULL)
@@ -998,7 +1006,8 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
 			 */
 			info = IEEE80211_SKB_CB(skb);
 			skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
-			if (info->control.hw_key &&
+			if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
+			    info->control.hw_key &&
 			    info->control.hw_key->cipher ==
 			    WLAN_CIPHER_SUITE_TKIP) {
 				int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -1024,6 +1033,11 @@ void wl1271_tx_flush(struct wl1271 *wl)
 	int i;
 	timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
 
+	/* only one flush should be in progress, for consistent queue state */
+	mutex_lock(&wl->flush_mutex);
+
+	wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
+
 	while (!time_after(jiffies, timeout)) {
 		mutex_lock(&wl->mutex);
 		wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d",
@@ -1032,7 +1046,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
 		if ((wl->tx_frames_cnt == 0) &&
 		    (wl1271_tx_total_queue_count(wl) == 0)) {
 			mutex_unlock(&wl->mutex);
-			return;
+			goto out;
 		}
 		mutex_unlock(&wl->mutex);
 		msleep(1);
@@ -1045,7 +1059,12 @@ void wl1271_tx_flush(struct wl1271 *wl)
 	for (i = 0; i < WL12XX_MAX_LINKS; i++)
 		wl1271_tx_reset_link_queues(wl, i);
 	mutex_unlock(&wl->mutex);
+
+out:
+	wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
+	mutex_unlock(&wl->flush_mutex);
 }
+EXPORT_SYMBOL_GPL(wl1271_tx_flush);
 
 u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
 {
@@ -1054,3 +1073,96 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
 
 	return BIT(__ffs(rate_set));
 }
+
+void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
+			      enum wlcore_queue_stop_reason reason)
+{
+	bool stopped = !!wl->queue_stop_reasons[queue];
+
+	/* queue should not be stopped for this reason */
+	WARN_ON(test_and_set_bit(reason, &wl->queue_stop_reasons[queue]));
+
+	if (stopped)
+		return;
+
+	ieee80211_stop_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
+}
+
+void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
+		       enum wlcore_queue_stop_reason reason)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->wl_lock, flags);
+	wlcore_stop_queue_locked(wl, queue, reason);
+	spin_unlock_irqrestore(&wl->wl_lock, flags);
+}
+
+void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
+		       enum wlcore_queue_stop_reason reason)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->wl_lock, flags);
+
+	/* queue should not be clear for this reason */
+	WARN_ON(!test_and_clear_bit(reason, &wl->queue_stop_reasons[queue]));
+
+	if (wl->queue_stop_reasons[queue])
+		goto out;
+
+	ieee80211_wake_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
+
+out:
+	spin_unlock_irqrestore(&wl->wl_lock, flags);
+}
+
+void wlcore_stop_queues(struct wl1271 *wl,
+			enum wlcore_queue_stop_reason reason)
+{
+	int i;
+
+	for (i = 0; i < NUM_TX_QUEUES; i++)
+		wlcore_stop_queue(wl, i, reason);
+}
+EXPORT_SYMBOL_GPL(wlcore_stop_queues);
+
+void wlcore_wake_queues(struct wl1271 *wl,
+			enum wlcore_queue_stop_reason reason)
+{
+	int i;
+
+	for (i = 0; i < NUM_TX_QUEUES; i++)
+		wlcore_wake_queue(wl, i, reason);
+}
+EXPORT_SYMBOL_GPL(wlcore_wake_queues);
+
+void wlcore_reset_stopped_queues(struct wl1271 *wl)
+{
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->wl_lock, flags);
+
+	for (i = 0; i < NUM_TX_QUEUES; i++) {
+		if (!wl->queue_stop_reasons[i])
+			continue;
+
+		wl->queue_stop_reasons[i] = 0;
+		ieee80211_wake_queue(wl->hw,
+				     wl1271_tx_get_mac80211_queue(i));
+	}
+
+	spin_unlock_irqrestore(&wl->wl_lock, flags);
+}
+
+bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
+			     enum wlcore_queue_stop_reason reason)
+{
+	return test_bit(reason, &wl->queue_stop_reasons[queue]);
+}
+
+bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue)
+{
+	return !!wl->queue_stop_reasons[queue];
+}
diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h
index 2fd6e5d..fa4be1b 100644
--- a/drivers/net/wireless/ti/wlcore/tx.h
+++ b/drivers/net/wireless/ti/wlcore/tx.h
@@ -85,6 +85,19 @@ struct wl128x_tx_mem {
 	u8 extra_bytes;
 } __packed;
 
+struct wl18xx_tx_mem {
+	/*
+	 * Total number of memory blocks allocated by the host for
+	 * this packet.
+	 */
+	u8 total_mem_blocks;
+
+	/*
+	 * control bits
+	 */
+	u8 ctrl;
+} __packed;
+
 /*
  * On wl128x based devices, when TX packets are aggregated, each packet
  * size must be aligned to the SDIO block size. The maximum block size
@@ -100,6 +113,7 @@ struct wl1271_tx_hw_descr {
 	union {
 		struct wl127x_tx_mem wl127x_mem;
 		struct wl128x_tx_mem wl128x_mem;
+		struct wl18xx_tx_mem wl18xx_mem;
 	} __packed;
 	/* Device time (in us) when the packet arrived to the driver */
 	__le32 start_time;
@@ -116,7 +130,16 @@ struct wl1271_tx_hw_descr {
 	u8 tid;
 	/* host link ID (HLID) */
 	u8 hlid;
-	u8 reserved;
+
+	union {
+		u8 wl12xx_reserved;
+
+		/*
+		 * bit 0   -> 0 = udp, 1 = tcp
+		 * bit 1:7 -> IP header offset
+		 */
+		u8 wl18xx_checksum_data;
+	} __packed;
 } __packed;
 
 enum wl1271_tx_hw_res_status {
@@ -161,6 +184,13 @@ struct wl1271_tx_hw_res_if {
 	struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
 } __packed;
 
+enum wlcore_queue_stop_reason {
+	WLCORE_QUEUE_STOP_REASON_WATERMARK,
+	WLCORE_QUEUE_STOP_REASON_FW_RESTART,
+	WLCORE_QUEUE_STOP_REASON_FLUSH,
+	WLCORE_QUEUE_STOP_REASON_SPARE_BLK, /* 18xx specific */
+};
+
 static inline int wl1271_tx_get_queue(int queue)
 {
 	switch (queue) {
@@ -207,7 +237,7 @@ void wl1271_tx_work(struct work_struct *work);
 void wl1271_tx_work_locked(struct wl1271 *wl);
 void wl1271_tx_complete(struct wl1271 *wl);
 void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
+void wl12xx_tx_reset(struct wl1271 *wl);
 void wl1271_tx_flush(struct wl1271 *wl);
 u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band);
 u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
@@ -223,6 +253,21 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
 void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
 unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
 					  unsigned int packet_length);
+void wl1271_free_tx_id(struct wl1271 *wl, int id);
+void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
+			      enum wlcore_queue_stop_reason reason);
+void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
+		       enum wlcore_queue_stop_reason reason);
+void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
+		       enum wlcore_queue_stop_reason reason);
+void wlcore_stop_queues(struct wl1271 *wl,
+			enum wlcore_queue_stop_reason reason);
+void wlcore_wake_queues(struct wl1271 *wl,
+			enum wlcore_queue_stop_reason reason);
+void wlcore_reset_stopped_queues(struct wl1271 *wl);
+bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
+				       enum wlcore_queue_stop_reason reason);
+bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue);
 
 /* from main.c */
 void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
diff --git a/drivers/net/wireless/ti/wlcore/wl12xx.h b/drivers/net/wireless/ti/wlcore/wl12xx.h
deleted file mode 100644
index f12bdf7..0000000
--- a/drivers/net/wireless/ti/wlcore/wl12xx.h
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * This file is part of wl1271
- *
- * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
- * Copyright (C) 2008-2009 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 __WL12XX_H__
-#define __WL12XX_H__
-
-#include <linux/mutex.h>
-#include <linux/completion.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <net/mac80211.h>
-
-#include "conf.h"
-#include "ini.h"
-
-#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
-#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
-
-#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
-#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
-
-#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
-#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
-
-/*
- * wl127x and wl128x are using the same NVS file name. However, the
- * ini parameters between them are different.  The driver validates
- * the correct NVS size in wl1271_boot_upload_nvs().
- */
-#define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin"
-
-#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
-#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
-#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff
-
-#define WL1271_CIPHER_SUITE_GEM 0x00147201
-
-#define WL1271_BUSY_WORD_CNT 1
-#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32))
-
-#define WL1271_ELP_HW_STATE_ASLEEP 0
-#define WL1271_ELP_HW_STATE_IRQ    1
-
-#define WL1271_DEFAULT_BEACON_INT  100
-#define WL1271_DEFAULT_DTIM_PERIOD 1
-
-#define WL12XX_MAX_ROLES           4
-#define WL12XX_MAX_LINKS           12
-#define WL12XX_INVALID_ROLE_ID     0xff
-#define WL12XX_INVALID_LINK_ID     0xff
-
-#define WL12XX_MAX_RATE_POLICIES 16
-
-/* Defined by FW as 0. Will not be freed or allocated. */
-#define WL12XX_SYSTEM_HLID         0
-
-/*
- * When in AP-mode, we allow (at least) this number of packets
- * to be transmitted to FW for a STA in PS-mode. Only when packets are
- * present in the FW buffers it will wake the sleeping STA. We want to put
- * enough packets for the driver to transmit all of its buffered data before
- * the STA goes to sleep again. But we don't want to take too much memory
- * as it might hurt the throughput of active STAs.
- */
-#define WL1271_PS_STA_MAX_PACKETS  2
-
-#define WL1271_AP_BSS_INDEX        0
-#define WL1271_AP_DEF_BEACON_EXP   20
-
-#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
-
-enum wl1271_state {
-	WL1271_STATE_OFF,
-	WL1271_STATE_ON,
-};
-
-enum wl12xx_fw_type {
-	WL12XX_FW_TYPE_NONE,
-	WL12XX_FW_TYPE_NORMAL,
-	WL12XX_FW_TYPE_MULTI,
-	WL12XX_FW_TYPE_PLT,
-};
-
-struct wl1271;
-
-enum {
-	FW_VER_CHIP,
-	FW_VER_IF_TYPE,
-	FW_VER_MAJOR,
-	FW_VER_SUBTYPE,
-	FW_VER_MINOR,
-
-	NUM_FW_VER
-};
-
-#define FW_VER_CHIP_WL127X 6
-#define FW_VER_CHIP_WL128X 7
-
-#define FW_VER_IF_TYPE_STA 1
-#define FW_VER_IF_TYPE_AP  2
-
-#define FW_VER_MINOR_1_SPARE_STA_MIN 58
-#define FW_VER_MINOR_1_SPARE_AP_MIN  47
-
-#define FW_VER_MINOR_FWLOG_STA_MIN 70
-
-struct wl1271_chip {
-	u32 id;
-	char fw_ver_str[ETHTOOL_BUSINFO_LEN];
-	unsigned int fw_ver[NUM_FW_VER];
-};
-
-struct wl1271_stats {
-	struct acx_statistics *fw_stats;
-	unsigned long fw_stats_update;
-
-	unsigned int retry_count;
-	unsigned int excessive_retries;
-};
-
-#define NUM_TX_QUEUES              4
-#define NUM_RX_PKT_DESC            8
-
-#define AP_MAX_STATIONS            8
-
-struct wl_fw_packet_counters {
-	/* Cumulative counter of released packets per AC */
-	u8 tx_released_pkts[NUM_TX_QUEUES];
-
-	/* Cumulative counter of freed packets per HLID */
-	u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
-
-	/* Cumulative counter of released Voice memory blocks */
-	u8 tx_voice_released_blks;
-
-	u8 padding[3];
-} __packed;
-
-/* FW status registers */
-struct wl_fw_status {
-	__le32 intr;
-	u8  fw_rx_counter;
-	u8  drv_rx_counter;
-	u8  reserved;
-	u8  tx_results_counter;
-	__le32 rx_pkt_descs[NUM_RX_PKT_DESC];
-	__le32 fw_localtime;
-
-	/*
-	 * A bitmap (where each bit represents a single HLID)
-	 * to indicate if the station is in PS mode.
-	 */
-	__le32 link_ps_bitmap;
-
-	/*
-	 * A bitmap (where each bit represents a single HLID) to indicate
-	 * if the station is in Fast mode
-	 */
-	__le32 link_fast_bitmap;
-
-	/* Cumulative counter of total released mem blocks since FW-reset */
-	__le32 total_released_blks;
-
-	/* Size (in Memory Blocks) of TX pool */
-	__le32 tx_total;
-
-	struct wl_fw_packet_counters counters;
-
-	__le32 log_start_addr;
-
-	/* Private status to be used by the lower drivers */
-	u8 priv[0];
-} __packed;
-
-struct wl1271_rx_mem_pool_addr {
-	u32 addr;
-	u32 addr_extra;
-};
-
-#define WL1271_MAX_CHANNELS 64
-struct wl1271_scan {
-	struct cfg80211_scan_request *req;
-	unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)];
-	bool failed;
-	u8 state;
-	u8 ssid[IEEE80211_MAX_SSID_LEN+1];
-	size_t ssid_len;
-};
-
-struct wl1271_if_operations {
-	void (*read)(struct device *child, int addr, void *buf, size_t len,
-		     bool fixed);
-	void (*write)(struct device *child, int addr, void *buf, size_t len,
-		     bool fixed);
-	void (*reset)(struct device *child);
-	void (*init)(struct device *child);
-	int (*power)(struct device *child, bool enable);
-	void (*set_block_size) (struct device *child, unsigned int blksz);
-};
-
-#define MAX_NUM_KEYS 14
-#define MAX_KEY_SIZE 32
-
-struct wl1271_ap_key {
-	u8 id;
-	u8 key_type;
-	u8 key_size;
-	u8 key[MAX_KEY_SIZE];
-	u8 hlid;
-	u32 tx_seq_32;
-	u16 tx_seq_16;
-};
-
-enum wl12xx_flags {
-	WL1271_FLAG_GPIO_POWER,
-	WL1271_FLAG_TX_QUEUE_STOPPED,
-	WL1271_FLAG_TX_PENDING,
-	WL1271_FLAG_IN_ELP,
-	WL1271_FLAG_ELP_REQUESTED,
-	WL1271_FLAG_IRQ_RUNNING,
-	WL1271_FLAG_FW_TX_BUSY,
-	WL1271_FLAG_DUMMY_PACKET_PENDING,
-	WL1271_FLAG_SUSPENDED,
-	WL1271_FLAG_PENDING_WORK,
-	WL1271_FLAG_SOFT_GEMINI,
-	WL1271_FLAG_RECOVERY_IN_PROGRESS,
-	WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
-	WL1271_FLAG_INTENDED_FW_RECOVERY,
-};
-
-enum wl12xx_vif_flags {
-	WLVIF_FLAG_INITIALIZED,
-	WLVIF_FLAG_STA_ASSOCIATED,
-	WLVIF_FLAG_STA_AUTHORIZED,
-	WLVIF_FLAG_IBSS_JOINED,
-	WLVIF_FLAG_AP_STARTED,
-	WLVIF_FLAG_IN_PS,
-	WLVIF_FLAG_STA_STATE_SENT,
-	WLVIF_FLAG_RX_STREAMING_STARTED,
-	WLVIF_FLAG_PSPOLL_FAILURE,
-	WLVIF_FLAG_CS_PROGRESS,
-	WLVIF_FLAG_AP_PROBE_RESP_SET,
-	WLVIF_FLAG_IN_USE,
-};
-
-struct wl1271_link {
-	/* AP-mode - TX queue per AC in link */
-	struct sk_buff_head tx_queue[NUM_TX_QUEUES];
-
-	/* accounting for allocated / freed packets in FW */
-	u8 allocated_pkts;
-	u8 prev_freed_pkts;
-
-	u8 addr[ETH_ALEN];
-
-	/* bitmap of TIDs where RX BA sessions are active for this link */
-	u8 ba_bitmap;
-};
-
-#define WL1271_MAX_RX_FILTERS 5
-#define WL1271_RX_FILTER_MAX_FIELDS 8
-
-#define WL1271_RX_FILTER_ETH_HEADER_SIZE 14
-#define WL1271_RX_FILTER_MAX_FIELDS_SIZE 95
-#define RX_FILTER_FIELD_OVERHEAD				\
-	(sizeof(struct wl12xx_rx_filter_field) - sizeof(u8 *))
-#define WL1271_RX_FILTER_MAX_PATTERN_SIZE			\
-	(WL1271_RX_FILTER_MAX_FIELDS_SIZE - RX_FILTER_FIELD_OVERHEAD)
-
-#define WL1271_RX_FILTER_FLAG_MASK                BIT(0)
-#define WL1271_RX_FILTER_FLAG_IP_HEADER           0
-#define WL1271_RX_FILTER_FLAG_ETHERNET_HEADER     BIT(1)
-
-enum rx_filter_action {
-	FILTER_DROP = 0,
-	FILTER_SIGNAL = 1,
-	FILTER_FW_HANDLE = 2
-};
-
-struct wl12xx_rx_filter_field {
-	__le16 offset;
-	u8 len;
-	u8 flags;
-	u8 *pattern;
-} __packed;
-
-struct wl12xx_rx_filter {
-	u8 action;
-	int num_fields;
-	struct wl12xx_rx_filter_field fields[WL1271_RX_FILTER_MAX_FIELDS];
-};
-
-struct wl1271_station {
-	u8 hlid;
-};
-
-struct wl12xx_vif {
-	struct wl1271 *wl;
-	struct list_head list;
-	unsigned long flags;
-	u8 bss_type;
-	u8 p2p; /* we are using p2p role */
-	u8 role_id;
-
-	/* sta/ibss specific */
-	u8 dev_role_id;
-	u8 dev_hlid;
-
-	union {
-		struct {
-			u8 hlid;
-			u8 ba_rx_bitmap;
-
-			u8 basic_rate_idx;
-			u8 ap_rate_idx;
-			u8 p2p_rate_idx;
-
-			bool qos;
-		} sta;
-		struct {
-			u8 global_hlid;
-			u8 bcast_hlid;
-
-			/* HLIDs bitmap of associated stations */
-			unsigned long sta_hlid_map[BITS_TO_LONGS(
-							WL12XX_MAX_LINKS)];
-
-			/* recoreded keys - set here before AP startup */
-			struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS];
-
-			u8 mgmt_rate_idx;
-			u8 bcast_rate_idx;
-			u8 ucast_rate_idx[CONF_TX_MAX_AC_COUNT];
-		} ap;
-	};
-
-	/* the hlid of the last transmitted skb */
-	int last_tx_hlid;
-
-	unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
-
-	u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
-	u8 ssid_len;
-
-	/* The current band */
-	enum ieee80211_band band;
-	int channel;
-
-	u32 bitrate_masks[IEEE80211_NUM_BANDS];
-	u32 basic_rate_set;
-
-	/*
-	 * currently configured rate set:
-	 *	bits  0-15 - 802.11abg rates
-	 *	bits 16-23 - 802.11n   MCS index mask
-	 * support only 1 stream, thus only 8 bits for the MCS rates (0-7).
-	 */
-	u32 basic_rate;
-	u32 rate_set;
-
-	/* probe-req template for the current AP */
-	struct sk_buff *probereq;
-
-	/* Beaconing interval (needed for ad-hoc) */
-	u32 beacon_int;
-
-	/* Default key (for WEP) */
-	u32 default_key;
-
-	/* Our association ID */
-	u16 aid;
-
-	/* Session counter for the chipset */
-	int session_counter;
-
-	/* retry counter for PSM entries */
-	u8 psm_entry_retry;
-
-	/* in dBm */
-	int power_level;
-
-	int rssi_thold;
-	int last_rssi_event;
-
-	/* save the current encryption type for auto-arp config */
-	u8 encryption_type;
-	__be32 ip_addr;
-
-	/* RX BA constraint value */
-	bool ba_support;
-	bool ba_allowed;
-
-	/* Rx Streaming */
-	struct work_struct rx_streaming_enable_work;
-	struct work_struct rx_streaming_disable_work;
-	struct timer_list rx_streaming_timer;
-
-	/* does the current role use GEM for encryption (AP or STA) */
-	bool is_gem;
-
-	/*
-	 * This struct must be last!
-	 * data that has to be saved acrossed reconfigs (e.g. recovery)
-	 * should be declared in this struct.
-	 */
-	struct {
-		u8 persistent[0];
-		/*
-		 * Security sequence number
-		 *     bits 0-15: lower 16 bits part of sequence number
-		 *     bits 16-47: higher 32 bits part of sequence number
-		 *     bits 48-63: not in use
-		 */
-		u64 tx_security_seq;
-
-		/* 8 bits of the last sequence number in use */
-		u8 tx_security_last_seq_lsb;
-	};
-};
-
-static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif)
-{
-	return (struct wl12xx_vif *)vif->drv_priv;
-}
-
-static inline
-struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif)
-{
-	return container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
-}
-
-#define wl12xx_for_each_wlvif(wl, wlvif) \
-		list_for_each_entry(wlvif, &wl->wlvif_list, list)
-
-#define wl12xx_for_each_wlvif_continue(wl, wlvif) \
-		list_for_each_entry_continue(wlvif, &wl->wlvif_list, list)
-
-#define wl12xx_for_each_wlvif_bss_type(wl, wlvif, _bss_type)	\
-		wl12xx_for_each_wlvif(wl, wlvif)		\
-			if (wlvif->bss_type == _bss_type)
-
-#define wl12xx_for_each_wlvif_sta(wl, wlvif)	\
-		wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_STA_BSS)
-
-#define wl12xx_for_each_wlvif_ap(wl, wlvif)	\
-		wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS)
-
-int wl1271_plt_start(struct wl1271 *wl);
-int wl1271_plt_stop(struct wl1271 *wl);
-int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-void wl12xx_queue_recovery_work(struct wl1271 *wl);
-size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
-int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
-					u16 offset, u8 flags,
-					u8 *pattern, u8 len);
-void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter);
-struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void);
-int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter);
-void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
-				     u8 *buf);
-
-#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
-
-#define SESSION_COUNTER_MAX 6 /* maximum value for the session counter */
-#define SESSION_COUNTER_INVALID 7 /* used with dummy_packet */
-
-#define WL1271_DEFAULT_POWER_LEVEL 0
-
-#define WL1271_TX_QUEUE_LOW_WATERMARK  32
-#define WL1271_TX_QUEUE_HIGH_WATERMARK 256
-
-#define WL1271_DEFERRED_QUEUE_LIMIT    64
-
-/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
-   on in case is has been shut down shortly before */
-#define WL1271_PRE_POWER_ON_SLEEP 20 /* in milliseconds */
-#define WL1271_POWER_ON_SLEEP 200 /* in milliseconds */
-
-/* Macros to handle wl1271.sta_rate_set */
-#define HW_BG_RATES_MASK	0xffff
-#define HW_HT_RATES_OFFSET	16
-
-#define WL12XX_HW_BLOCK_SIZE	256
-
-#endif
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 0b3f0b5..205d8ad 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -24,8 +24,9 @@
 
 #include <linux/platform_device.h>
 
-#include "wl12xx.h"
+#include "wlcore_i.h"
 #include "event.h"
+#include "boot.h"
 
 /* The maximum number of Tx descriptors in all chip families */
 #define WLCORE_MAX_TX_DESCRIPTORS 32
@@ -33,11 +34,13 @@
 /* forward declaration */
 struct wl1271_tx_hw_descr;
 enum wl_rx_buf_align;
+struct wl1271_rx_descriptor;
 
 struct wlcore_ops {
 	int (*identify_chip)(struct wl1271 *wl);
 	int (*identify_fw)(struct wl1271 *wl);
 	int (*boot)(struct wl1271 *wl);
+	int (*plt_init)(struct wl1271 *wl);
 	void (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr,
 			    void *buf, size_t len);
 	void (*ack_event)(struct wl1271 *wl);
@@ -61,6 +64,23 @@ struct wlcore_ops {
 				    struct wl12xx_vif *wlvif);
 	s8 (*get_pg_ver)(struct wl1271 *wl);
 	void (*get_mac)(struct wl1271 *wl);
+	void (*set_tx_desc_csum)(struct wl1271 *wl,
+				 struct wl1271_tx_hw_descr *desc,
+				 struct sk_buff *skb);
+	void (*set_rx_csum)(struct wl1271 *wl,
+			    struct wl1271_rx_descriptor *desc,
+			    struct sk_buff *skb);
+	u32 (*ap_get_mimo_wide_rate_mask)(struct wl1271 *wl,
+					  struct wl12xx_vif *wlvif);
+	int (*debugfs_init)(struct wl1271 *wl, struct dentry *rootdir);
+	int (*handle_static_data)(struct wl1271 *wl,
+				  struct wl1271_static_data *static_data);
+	int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem);
+	int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd,
+		       struct ieee80211_vif *vif,
+		       struct ieee80211_sta *sta,
+		       struct ieee80211_key_conf *key_conf);
+	u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
 };
 
 enum wlcore_partitions {
@@ -109,6 +129,15 @@ enum wlcore_registers {
 	REG_TABLE_LEN,
 };
 
+struct wl1271_stats {
+	void *fw_stats;
+	unsigned long fw_stats_update;
+	size_t fw_stats_len;
+
+	unsigned int retry_count;
+	unsigned int excessive_retries;
+};
+
 struct wl1271 {
 	struct ieee80211_hw *hw;
 	bool mac80211_registered;
@@ -121,7 +150,6 @@ struct wl1271 {
 
 	void (*set_power)(bool enable);
 	int irq;
-	int ref_clock;
 
 	spinlock_t wl_lock;
 
@@ -186,7 +214,7 @@ struct wl1271 {
 
 	/* Frames scheduled for transmission, not handled yet */
 	int tx_queue_count[NUM_TX_QUEUES];
-	long stopped_queues_map;
+	unsigned long queue_stop_reasons[NUM_TX_QUEUES];
 
 	/* Frames received, not handled yet by mac80211 */
 	struct sk_buff_head deferred_rx_queue;
@@ -205,9 +233,6 @@ struct wl1271 {
 	/* FW Rx counter */
 	u32 rx_counter;
 
-	/* Rx memory pool address */
-	struct wl1271_rx_mem_pool_addr rx_mem_pool_addr;
-
 	/* Intermediate buffer, used for packet aggregation */
 	u8 *aggr_buf;
 
@@ -228,6 +253,7 @@ struct wl1271 {
 
 	/* Hardware recovery work */
 	struct work_struct recovery_work;
+	bool watchdog_recovery;
 
 	/* Pointer that holds DMA-friendly block for the mailbox */
 	struct event_mailbox *mbox;
@@ -263,7 +289,8 @@ struct wl1271 {
 	u32 buffer_cmd;
 	u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
 
-	struct wl_fw_status *fw_status;
+	struct wl_fw_status_1 *fw_status_1;
+	struct wl_fw_status_2 *fw_status_2;
 	struct wl1271_tx_hw_res_if *tx_res_if;
 
 	/* Current chipset configuration */
@@ -279,8 +306,6 @@ struct wl1271 {
 	/* bands supported by this instance of wl12xx */
 	struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
 
-	int tcxo_clock;
-
 	/*
 	 * wowlan trigger was configured during suspend.
 	 * (currently, only "ANY" trigger is supported)
@@ -333,10 +358,8 @@ struct wl1271 {
 
 	/* number of TX descriptors the HW supports. */
 	u32 num_tx_desc;
-
-	/* spare Tx blocks for normal/GEM operating modes */
-	u32 normal_tx_spare;
-	u32 gem_tx_spare;
+	/* number of RX descriptors the HW supports. */
+	u32 num_rx_desc;
 
 	/* translate HW Tx rates to standard rate-indices */
 	const u8 **band_rate_to_idx;
@@ -348,19 +371,42 @@ struct wl1271 {
 	u8 hw_min_ht_rate;
 
 	/* HW HT (11n) capabilities */
-	struct ieee80211_sta_ht_cap ht_cap;
+	struct ieee80211_sta_ht_cap ht_cap[IEEE80211_NUM_BANDS];
 
 	/* size of the private FW status data */
 	size_t fw_status_priv_len;
 
 	/* RX Data filter rule state - enabled/disabled */
 	bool rx_filter_enabled[WL1271_MAX_RX_FILTERS];
+
+	/* size of the private static data */
+	size_t static_data_priv_len;
+
+	/* the current channel type */
+	enum nl80211_channel_type channel_type;
+
+	/* mutex for protecting the tx_flush function */
+	struct mutex flush_mutex;
+
+	/* sleep auth value currently configured to FW */
+	int sleep_auth;
 };
 
 int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
 int __devexit wlcore_remove(struct platform_device *pdev);
 struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size);
 int wlcore_free_hw(struct wl1271 *wl);
+int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
+		   struct ieee80211_vif *vif,
+		   struct ieee80211_sta *sta,
+		   struct ieee80211_key_conf *key_conf);
+
+static inline void
+wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band,
+		  struct ieee80211_sta_ht_cap *ht_cap)
+{
+	memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap));
+}
 
 /* Firmware image load chunk size */
 #define CHUNK_SIZE	16384
@@ -385,6 +431,12 @@ int wlcore_free_hw(struct wl1271 *wl);
 /* Some firmwares may not support ELP */
 #define WLCORE_QUIRK_NO_ELP			BIT(6)
 
+/* pad only the last frame in the aggregate buffer */
+#define WLCORE_QUIRK_TX_PAD_LAST_FRAME		BIT(7)
+
+/* extra header space is required for TKIP */
+#define WLCORE_QUIRK_TKIP_HEADER_SPACE		BIT(8)
+
 /* TODO: move to the lower drivers when all usages are abstracted */
 #define CHIP_ID_1271_PG10              (0x4030101)
 #define CHIP_ID_1271_PG20              (0x4030111)
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
new file mode 100644
index 0000000..8260b1e
--- /dev/null
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -0,0 +1,505 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
+ * Copyright (C) 2008-2009 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 __WLCORE_I_H__
+#define __WLCORE_I_H__
+
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/bitops.h>
+#include <net/mac80211.h>
+
+#include "conf.h"
+#include "ini.h"
+
+#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
+#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
+
+#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
+#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
+
+#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
+#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
+
+/*
+ * wl127x and wl128x are using the same NVS file name. However, the
+ * ini parameters between them are different.  The driver validates
+ * the correct NVS size in wl1271_boot_upload_nvs().
+ */
+#define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin"
+
+#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
+#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
+#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff
+
+#define WL1271_CIPHER_SUITE_GEM 0x00147201
+
+#define WL1271_BUSY_WORD_CNT 1
+#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32))
+
+#define WL1271_ELP_HW_STATE_ASLEEP 0
+#define WL1271_ELP_HW_STATE_IRQ    1
+
+#define WL1271_DEFAULT_BEACON_INT  100
+#define WL1271_DEFAULT_DTIM_PERIOD 1
+
+#define WL12XX_MAX_ROLES           4
+#define WL12XX_MAX_LINKS           12
+#define WL12XX_INVALID_ROLE_ID     0xff
+#define WL12XX_INVALID_LINK_ID     0xff
+
+#define WL12XX_MAX_RATE_POLICIES 16
+
+/* Defined by FW as 0. Will not be freed or allocated. */
+#define WL12XX_SYSTEM_HLID         0
+
+/*
+ * When in AP-mode, we allow (at least) this number of packets
+ * to be transmitted to FW for a STA in PS-mode. Only when packets are
+ * present in the FW buffers it will wake the sleeping STA. We want to put
+ * enough packets for the driver to transmit all of its buffered data before
+ * the STA goes to sleep again. But we don't want to take too much memory
+ * as it might hurt the throughput of active STAs.
+ */
+#define WL1271_PS_STA_MAX_PACKETS  2
+
+#define WL1271_AP_BSS_INDEX        0
+#define WL1271_AP_DEF_BEACON_EXP   20
+
+#define WL1271_AGGR_BUFFER_SIZE (5 * PAGE_SIZE)
+
+enum wl1271_state {
+	WL1271_STATE_OFF,
+	WL1271_STATE_ON,
+};
+
+enum wl12xx_fw_type {
+	WL12XX_FW_TYPE_NONE,
+	WL12XX_FW_TYPE_NORMAL,
+	WL12XX_FW_TYPE_MULTI,
+	WL12XX_FW_TYPE_PLT,
+};
+
+struct wl1271;
+
+enum {
+	FW_VER_CHIP,
+	FW_VER_IF_TYPE,
+	FW_VER_MAJOR,
+	FW_VER_SUBTYPE,
+	FW_VER_MINOR,
+
+	NUM_FW_VER
+};
+
+#define FW_VER_CHIP_WL127X 6
+#define FW_VER_CHIP_WL128X 7
+
+#define FW_VER_IF_TYPE_STA 1
+#define FW_VER_IF_TYPE_AP  2
+
+#define FW_VER_MINOR_1_SPARE_STA_MIN 58
+#define FW_VER_MINOR_1_SPARE_AP_MIN  47
+
+#define FW_VER_MINOR_FWLOG_STA_MIN 70
+
+struct wl1271_chip {
+	u32 id;
+	char fw_ver_str[ETHTOOL_BUSINFO_LEN];
+	unsigned int fw_ver[NUM_FW_VER];
+};
+
+#define NUM_TX_QUEUES              4
+
+#define AP_MAX_STATIONS            8
+
+struct wl_fw_packet_counters {
+	/* Cumulative counter of released packets per AC */
+	u8 tx_released_pkts[NUM_TX_QUEUES];
+
+	/* Cumulative counter of freed packets per HLID */
+	u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
+
+	/* Cumulative counter of released Voice memory blocks */
+	u8 tx_voice_released_blks;
+
+	u8 padding[3];
+} __packed;
+
+/* FW status registers */
+struct wl_fw_status_1 {
+	__le32 intr;
+	u8  fw_rx_counter;
+	u8  drv_rx_counter;
+	u8  reserved;
+	u8  tx_results_counter;
+	__le32 rx_pkt_descs[0];
+} __packed;
+
+/*
+ * Each HW arch has a different number of Rx descriptors.
+ * The length of the status depends on it, since it holds an array
+ * of descriptors.
+ */
+#define WLCORE_FW_STATUS_1_LEN(num_rx_desc) \
+		(sizeof(struct wl_fw_status_1) + \
+		(sizeof(((struct wl_fw_status_1 *)0)->rx_pkt_descs[0])) * \
+		num_rx_desc)
+
+struct wl_fw_status_2 {
+	__le32 fw_localtime;
+
+	/*
+	 * A bitmap (where each bit represents a single HLID)
+	 * to indicate if the station is in PS mode.
+	 */
+	__le32 link_ps_bitmap;
+
+	/*
+	 * A bitmap (where each bit represents a single HLID) to indicate
+	 * if the station is in Fast mode
+	 */
+	__le32 link_fast_bitmap;
+
+	/* Cumulative counter of total released mem blocks since FW-reset */
+	__le32 total_released_blks;
+
+	/* Size (in Memory Blocks) of TX pool */
+	__le32 tx_total;
+
+	struct wl_fw_packet_counters counters;
+
+	__le32 log_start_addr;
+
+	/* Private status to be used by the lower drivers */
+	u8 priv[0];
+} __packed;
+
+#define WL1271_MAX_CHANNELS 64
+struct wl1271_scan {
+	struct cfg80211_scan_request *req;
+	unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)];
+	bool failed;
+	u8 state;
+	u8 ssid[IEEE80211_MAX_SSID_LEN+1];
+	size_t ssid_len;
+};
+
+struct wl1271_if_operations {
+	void (*read)(struct device *child, int addr, void *buf, size_t len,
+		     bool fixed);
+	void (*write)(struct device *child, int addr, void *buf, size_t len,
+		     bool fixed);
+	void (*reset)(struct device *child);
+	void (*init)(struct device *child);
+	int (*power)(struct device *child, bool enable);
+	void (*set_block_size) (struct device *child, unsigned int blksz);
+};
+
+#define MAX_NUM_KEYS 14
+#define MAX_KEY_SIZE 32
+
+struct wl1271_ap_key {
+	u8 id;
+	u8 key_type;
+	u8 key_size;
+	u8 key[MAX_KEY_SIZE];
+	u8 hlid;
+	u32 tx_seq_32;
+	u16 tx_seq_16;
+};
+
+enum wl12xx_flags {
+	WL1271_FLAG_GPIO_POWER,
+	WL1271_FLAG_TX_QUEUE_STOPPED,
+	WL1271_FLAG_TX_PENDING,
+	WL1271_FLAG_IN_ELP,
+	WL1271_FLAG_ELP_REQUESTED,
+	WL1271_FLAG_IRQ_RUNNING,
+	WL1271_FLAG_FW_TX_BUSY,
+	WL1271_FLAG_DUMMY_PACKET_PENDING,
+	WL1271_FLAG_SUSPENDED,
+	WL1271_FLAG_PENDING_WORK,
+	WL1271_FLAG_SOFT_GEMINI,
+	WL1271_FLAG_RECOVERY_IN_PROGRESS,
+	WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
+	WL1271_FLAG_INTENDED_FW_RECOVERY,
+};
+
+enum wl12xx_vif_flags {
+	WLVIF_FLAG_INITIALIZED,
+	WLVIF_FLAG_STA_ASSOCIATED,
+	WLVIF_FLAG_STA_AUTHORIZED,
+	WLVIF_FLAG_IBSS_JOINED,
+	WLVIF_FLAG_AP_STARTED,
+	WLVIF_FLAG_IN_PS,
+	WLVIF_FLAG_STA_STATE_SENT,
+	WLVIF_FLAG_RX_STREAMING_STARTED,
+	WLVIF_FLAG_PSPOLL_FAILURE,
+	WLVIF_FLAG_CS_PROGRESS,
+	WLVIF_FLAG_AP_PROBE_RESP_SET,
+	WLVIF_FLAG_IN_USE,
+};
+
+struct wl1271_link {
+	/* AP-mode - TX queue per AC in link */
+	struct sk_buff_head tx_queue[NUM_TX_QUEUES];
+
+	/* accounting for allocated / freed packets in FW */
+	u8 allocated_pkts;
+	u8 prev_freed_pkts;
+
+	u8 addr[ETH_ALEN];
+
+	/* bitmap of TIDs where RX BA sessions are active for this link */
+	u8 ba_bitmap;
+};
+
+#define WL1271_MAX_RX_FILTERS 5
+#define WL1271_RX_FILTER_MAX_FIELDS 8
+
+#define WL1271_RX_FILTER_ETH_HEADER_SIZE 14
+#define WL1271_RX_FILTER_MAX_FIELDS_SIZE 95
+#define RX_FILTER_FIELD_OVERHEAD				\
+	(sizeof(struct wl12xx_rx_filter_field) - sizeof(u8 *))
+#define WL1271_RX_FILTER_MAX_PATTERN_SIZE			\
+	(WL1271_RX_FILTER_MAX_FIELDS_SIZE - RX_FILTER_FIELD_OVERHEAD)
+
+#define WL1271_RX_FILTER_FLAG_MASK                BIT(0)
+#define WL1271_RX_FILTER_FLAG_IP_HEADER           0
+#define WL1271_RX_FILTER_FLAG_ETHERNET_HEADER     BIT(1)
+
+enum rx_filter_action {
+	FILTER_DROP = 0,
+	FILTER_SIGNAL = 1,
+	FILTER_FW_HANDLE = 2
+};
+
+struct wl12xx_rx_filter_field {
+	__le16 offset;
+	u8 len;
+	u8 flags;
+	u8 *pattern;
+} __packed;
+
+struct wl12xx_rx_filter {
+	u8 action;
+	int num_fields;
+	struct wl12xx_rx_filter_field fields[WL1271_RX_FILTER_MAX_FIELDS];
+};
+
+struct wl1271_station {
+	u8 hlid;
+};
+
+struct wl12xx_vif {
+	struct wl1271 *wl;
+	struct list_head list;
+	unsigned long flags;
+	u8 bss_type;
+	u8 p2p; /* we are using p2p role */
+	u8 role_id;
+
+	/* sta/ibss specific */
+	u8 dev_role_id;
+	u8 dev_hlid;
+
+	union {
+		struct {
+			u8 hlid;
+			u8 ba_rx_bitmap;
+
+			u8 basic_rate_idx;
+			u8 ap_rate_idx;
+			u8 p2p_rate_idx;
+
+			bool qos;
+		} sta;
+		struct {
+			u8 global_hlid;
+			u8 bcast_hlid;
+
+			/* HLIDs bitmap of associated stations */
+			unsigned long sta_hlid_map[BITS_TO_LONGS(
+							WL12XX_MAX_LINKS)];
+
+			/* recoreded keys - set here before AP startup */
+			struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS];
+
+			u8 mgmt_rate_idx;
+			u8 bcast_rate_idx;
+			u8 ucast_rate_idx[CONF_TX_MAX_AC_COUNT];
+		} ap;
+	};
+
+	/* the hlid of the last transmitted skb */
+	int last_tx_hlid;
+
+	unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
+
+	u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+	u8 ssid_len;
+
+	/* The current band */
+	enum ieee80211_band band;
+	int channel;
+	enum nl80211_channel_type channel_type;
+
+	u32 bitrate_masks[IEEE80211_NUM_BANDS];
+	u32 basic_rate_set;
+
+	/*
+	 * currently configured rate set:
+	 *	bits  0-15 - 802.11abg rates
+	 *	bits 16-23 - 802.11n   MCS index mask
+	 * support only 1 stream, thus only 8 bits for the MCS rates (0-7).
+	 */
+	u32 basic_rate;
+	u32 rate_set;
+
+	/* probe-req template for the current AP */
+	struct sk_buff *probereq;
+
+	/* Beaconing interval (needed for ad-hoc) */
+	u32 beacon_int;
+
+	/* Default key (for WEP) */
+	u32 default_key;
+
+	/* Our association ID */
+	u16 aid;
+
+	/* Session counter for the chipset */
+	int session_counter;
+
+	/* retry counter for PSM entries */
+	u8 psm_entry_retry;
+
+	/* in dBm */
+	int power_level;
+
+	int rssi_thold;
+	int last_rssi_event;
+
+	/* save the current encryption type for auto-arp config */
+	u8 encryption_type;
+	__be32 ip_addr;
+
+	/* RX BA constraint value */
+	bool ba_support;
+	bool ba_allowed;
+
+	/* Rx Streaming */
+	struct work_struct rx_streaming_enable_work;
+	struct work_struct rx_streaming_disable_work;
+	struct timer_list rx_streaming_timer;
+
+	/*
+	 * This struct must be last!
+	 * data that has to be saved acrossed reconfigs (e.g. recovery)
+	 * should be declared in this struct.
+	 */
+	struct {
+		u8 persistent[0];
+		/*
+		 * Security sequence number
+		 *     bits 0-15: lower 16 bits part of sequence number
+		 *     bits 16-47: higher 32 bits part of sequence number
+		 *     bits 48-63: not in use
+		 */
+		u64 tx_security_seq;
+
+		/* 8 bits of the last sequence number in use */
+		u8 tx_security_last_seq_lsb;
+	};
+};
+
+static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif)
+{
+	return (struct wl12xx_vif *)vif->drv_priv;
+}
+
+static inline
+struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif)
+{
+	return container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
+}
+
+#define wl12xx_for_each_wlvif(wl, wlvif) \
+		list_for_each_entry(wlvif, &wl->wlvif_list, list)
+
+#define wl12xx_for_each_wlvif_continue(wl, wlvif) \
+		list_for_each_entry_continue(wlvif, &wl->wlvif_list, list)
+
+#define wl12xx_for_each_wlvif_bss_type(wl, wlvif, _bss_type)	\
+		wl12xx_for_each_wlvif(wl, wlvif)		\
+			if (wlvif->bss_type == _bss_type)
+
+#define wl12xx_for_each_wlvif_sta(wl, wlvif)	\
+		wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_STA_BSS)
+
+#define wl12xx_for_each_wlvif_ap(wl, wlvif)	\
+		wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS)
+
+int wl1271_plt_start(struct wl1271 *wl);
+int wl1271_plt_stop(struct wl1271 *wl);
+int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+void wl12xx_queue_recovery_work(struct wl1271 *wl);
+size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
+int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
+					u16 offset, u8 flags,
+					u8 *pattern, u8 len);
+void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter);
+struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void);
+int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter);
+void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
+				     u8 *buf);
+
+#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
+
+#define SESSION_COUNTER_MAX 6 /* maximum value for the session counter */
+#define SESSION_COUNTER_INVALID 7 /* used with dummy_packet */
+
+#define WL1271_DEFAULT_POWER_LEVEL 0
+
+#define WL1271_TX_QUEUE_LOW_WATERMARK  32
+#define WL1271_TX_QUEUE_HIGH_WATERMARK 256
+
+#define WL1271_DEFERRED_QUEUE_LIMIT    64
+
+/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
+   on in case is has been shut down shortly before */
+#define WL1271_PRE_POWER_ON_SLEEP 20 /* in milliseconds */
+#define WL1271_POWER_ON_SLEEP 200 /* in milliseconds */
+
+/* Macros to handle wl1271.sta_rate_set */
+#define HW_BG_RATES_MASK	0xffff
+#define HW_HT_RATES_OFFSET	16
+#define HW_MIMO_RATES_OFFSET	24
+
+#define WL12XX_HW_BLOCK_SIZE	256
+
+#endif /* __WLCORE_I_H__ */
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 117c412..7ab9222 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -827,7 +827,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values,
 static inline int zd_ioread32_locked(struct zd_chip *chip, u32 *value,
 	                             const zd_addr_t addr)
 {
-	return zd_ioread32v_locked(chip, value, (const zd_addr_t *)&addr, 1);
+	return zd_ioread32v_locked(chip, value, &addr, 1);
 }
 
 static inline int zd_iowrite16_locked(struct zd_chip *chip, u16 value,
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 99193b4..45e3bb2 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -274,7 +274,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
 static inline int zd_usb_ioread16(struct zd_usb *usb, u16 *value,
 	                      const zd_addr_t addr)
 {
-	return zd_usb_ioread16v(usb, value, (const zd_addr_t *)&addr, 1);
+	return zd_usb_ioread16v(usb, value, &addr, 1);
 }
 
 void zd_usb_iowrite16v_async_start(struct zd_usb *usb);
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 19110f0..9ac829e 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -45,6 +45,9 @@ static const struct usb_device_id pn533_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, pn533_table);
 
+/* How much time we spend listening for initiators */
+#define PN533_LISTEN_TIME 2
+
 /* frame definitions */
 #define PN533_FRAME_TAIL_SIZE 2
 #define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
@@ -74,6 +77,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 #define PN533_CMD_IN_RELEASE 0x52
 #define PN533_CMD_IN_JUMP_FOR_DEP 0x56
 
+#define PN533_CMD_TG_INIT_AS_TARGET 0x8c
+#define PN533_CMD_TG_GET_DATA 0x86
+#define PN533_CMD_TG_SET_DATA 0x8e
+
 #define PN533_CMD_RESPONSE(cmd) (cmd + 1)
 
 /* PN533 Return codes */
@@ -81,6 +88,9 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 #define PN533_CMD_MI_MASK 0x40
 #define PN533_CMD_RET_SUCCESS 0x00
 
+/* PN533 status codes */
+#define PN533_STATUS_TARGET_RELEASED 0x29
+
 struct pn533;
 
 typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg,
@@ -97,8 +107,14 @@ struct pn533_fw_version {
 };
 
 /* PN533_CMD_RF_CONFIGURATION */
+#define PN533_CFGITEM_TIMING 0x02
 #define PN533_CFGITEM_MAX_RETRIES 0x05
 
+#define PN533_CONFIG_TIMING_102 0xb
+#define PN533_CONFIG_TIMING_204 0xc
+#define PN533_CONFIG_TIMING_409 0xd
+#define PN533_CONFIG_TIMING_819 0xe
+
 #define PN533_CONFIG_MAX_RETRIES_NO_RETRY 0x00
 #define PN533_CONFIG_MAX_RETRIES_ENDLESS 0xFF
 
@@ -108,6 +124,12 @@ struct pn533_config_max_retries {
 	u8 mx_rty_passive_act;
 } __packed;
 
+struct pn533_config_timing {
+	u8 rfu;
+	u8 atr_res_timeout;
+	u8 dep_timeout;
+} __packed;
+
 /* PN533_CMD_IN_LIST_PASSIVE_TARGET */
 
 /* felica commands opcode */
@@ -144,6 +166,7 @@ enum {
 	PN533_POLL_MOD_424KBPS_FELICA,
 	PN533_POLL_MOD_106KBPS_JEWEL,
 	PN533_POLL_MOD_847KBPS_B,
+	PN533_LISTEN_MOD,
 
 	__PN533_POLL_MOD_AFTER_LAST,
 };
@@ -211,6 +234,9 @@ const struct pn533_poll_modulations poll_mod[] = {
 		},
 		.len = 3,
 	},
+	[PN533_LISTEN_MOD] = {
+		.len = 0,
+	},
 };
 
 /* PN533_CMD_IN_ATR */
@@ -237,7 +263,7 @@ struct pn533_cmd_jump_dep {
 	u8 active;
 	u8 baud;
 	u8 next;
-	u8 gt[];
+	u8 data[];
 } __packed;
 
 struct pn533_cmd_jump_dep_response {
@@ -253,6 +279,29 @@ struct pn533_cmd_jump_dep_response {
 	u8 gt[];
 } __packed;
 
+
+/* PN533_TG_INIT_AS_TARGET */
+#define PN533_INIT_TARGET_PASSIVE 0x1
+#define PN533_INIT_TARGET_DEP 0x2
+
+#define PN533_INIT_TARGET_RESP_FRAME_MASK 0x3
+#define PN533_INIT_TARGET_RESP_ACTIVE     0x1
+#define PN533_INIT_TARGET_RESP_DEP        0x4
+
+struct pn533_cmd_init_target {
+	u8 mode;
+	u8 mifare[6];
+	u8 felica[18];
+	u8 nfcid3[10];
+	u8 gb_len;
+	u8 gb[];
+} __packed;
+
+struct pn533_cmd_init_target_response {
+	u8 mode;
+	u8 cmd[];
+} __packed;
+
 struct pn533 {
 	struct usb_device *udev;
 	struct usb_interface *interface;
@@ -270,22 +319,31 @@ struct pn533 {
 
 	struct workqueue_struct	*wq;
 	struct work_struct cmd_work;
+	struct work_struct poll_work;
 	struct work_struct mi_work;
+	struct work_struct tg_work;
+	struct timer_list listen_timer;
 	struct pn533_frame *wq_in_frame;
 	int wq_in_error;
+	int cancel_listen;
 
 	pn533_cmd_complete_t cmd_complete;
 	void *cmd_complete_arg;
-	struct semaphore cmd_lock;
+	struct mutex cmd_lock;
 	u8 cmd;
 
 	struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
 	u8 poll_mod_count;
 	u8 poll_mod_curr;
 	u32 poll_protocols;
+	u32 listen_protocols;
+
+	u8 *gb;
+	size_t gb_len;
 
 	u8 tgt_available_prots;
 	u8 tgt_active_prot;
+	u8 tgt_mode;
 };
 
 struct pn533_frame {
@@ -405,7 +463,7 @@ static void pn533_wq_cmd_complete(struct work_struct *work)
 					PN533_FRAME_CMD_PARAMS_LEN(in_frame));
 
 	if (rc != -EINPROGRESS)
-		up(&dev->cmd_lock);
+		mutex_unlock(&dev->cmd_lock);
 }
 
 static void pn533_recv_response(struct urb *urb)
@@ -583,7 +641,7 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	if (down_trylock(&dev->cmd_lock))
+	if (!mutex_trylock(&dev->cmd_lock))
 		return -EBUSY;
 
 	rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
@@ -593,7 +651,7 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,
 
 	return 0;
 error:
-	up(&dev->cmd_lock);
+	mutex_unlock(&dev->cmd_lock);
 	return rc;
 }
 
@@ -963,6 +1021,11 @@ static int pn533_target_found(struct pn533 *dev,
 	return 0;
 }
 
+static inline void pn533_poll_next_mod(struct pn533 *dev)
+{
+	dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count;
+}
+
 static void pn533_poll_reset_mod_list(struct pn533 *dev)
 {
 	dev->poll_mod_count = 0;
@@ -975,102 +1038,283 @@ static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index)
 	dev->poll_mod_count++;
 }
 
-static void pn533_poll_create_mod_list(struct pn533 *dev, u32 protocols)
+static void pn533_poll_create_mod_list(struct pn533 *dev,
+				       u32 im_protocols, u32 tm_protocols)
 {
 	pn533_poll_reset_mod_list(dev);
 
-	if (protocols & NFC_PROTO_MIFARE_MASK
-					|| protocols & NFC_PROTO_ISO14443_MASK
-					|| protocols & NFC_PROTO_NFC_DEP_MASK)
+	if (im_protocols & NFC_PROTO_MIFARE_MASK
+	    || im_protocols & NFC_PROTO_ISO14443_MASK
+	    || im_protocols & NFC_PROTO_NFC_DEP_MASK)
 		pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A);
 
-	if (protocols & NFC_PROTO_FELICA_MASK
-					|| protocols & NFC_PROTO_NFC_DEP_MASK) {
+	if (im_protocols & NFC_PROTO_FELICA_MASK
+	    || im_protocols & NFC_PROTO_NFC_DEP_MASK) {
 		pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA);
 		pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA);
 	}
 
-	if (protocols & NFC_PROTO_JEWEL_MASK)
+	if (im_protocols & NFC_PROTO_JEWEL_MASK)
 		pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL);
 
-	if (protocols & NFC_PROTO_ISO14443_MASK)
+	if (im_protocols & NFC_PROTO_ISO14443_MASK)
 		pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B);
+
+	if (tm_protocols)
+		pn533_poll_add_mod(dev, PN533_LISTEN_MOD);
+}
+
+static int pn533_start_poll_complete(struct pn533 *dev, void *arg,
+				     u8 *params, int params_len)
+{
+	struct pn533_poll_response *resp;
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	resp = (struct pn533_poll_response *) params;
+	if (resp->nbtg) {
+		rc = pn533_target_found(dev, resp, params_len);
+
+		/* We must stop the poll after a valid target found */
+		if (rc == 0) {
+			pn533_poll_reset_mod_list(dev);
+			return 0;
+		}
+	}
+
+	return -EAGAIN;
 }
 
-static void pn533_start_poll_frame(struct pn533_frame *frame,
-					struct pn533_poll_modulations *mod)
+static int pn533_init_target_frame(struct pn533_frame *frame,
+				   u8 *gb, size_t gb_len)
 {
+	struct pn533_cmd_init_target *cmd;
+	size_t cmd_len;
+	u8 felica_params[18] = {0x1, 0xfe, /* DEP */
+				0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */
+				0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+				0xff, 0xff}; /* System code */
+	u8 mifare_params[6] = {0x1, 0x1, /* SENS_RES */
+			       0x0, 0x0, 0x0,
+			       0x40}; /* SEL_RES for DEP */
+
+	cmd_len = sizeof(struct pn533_cmd_init_target) + gb_len + 1;
+	cmd = kzalloc(cmd_len, GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	pn533_tx_frame_init(frame, PN533_CMD_TG_INIT_AS_TARGET);
+
+	/* DEP support only */
+	cmd->mode |= PN533_INIT_TARGET_DEP;
+
+	/* Felica params */
+	memcpy(cmd->felica, felica_params, 18);
+	get_random_bytes(cmd->felica + 2, 6);
+
+	/* NFCID3 */
+	memset(cmd->nfcid3, 0, 10);
+	memcpy(cmd->nfcid3, cmd->felica, 8);
 
-	pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
+	/* MIFARE params */
+	memcpy(cmd->mifare, mifare_params, 6);
 
-	memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
-	frame->datalen += mod->len;
+	/* General bytes */
+	cmd->gb_len = gb_len;
+	memcpy(cmd->gb, gb, gb_len);
+
+	/* Len Tk */
+	cmd->gb[gb_len] = 0;
+
+	memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), cmd, cmd_len);
+
+	frame->datalen += cmd_len;
 
 	pn533_tx_frame_finish(frame);
+
+	kfree(cmd);
+
+	return 0;
 }
 
-static int pn533_start_poll_complete(struct pn533 *dev, void *arg,
-						u8 *params, int params_len)
+#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
+#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
+static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg,
+				      u8 *params, int params_len)
 {
-	struct pn533_poll_response *resp;
-	struct pn533_poll_modulations *next_mod;
-	int rc;
+	struct sk_buff *skb_resp = arg;
+	struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	if (params_len == -ENOENT) {
-		nfc_dev_dbg(&dev->interface->dev, "Polling operation has been"
-								" stopped");
-		goto stop_poll;
+	if (params_len < 0) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Error %d when starting as a target",
+			    params_len);
+
+		return params_len;
 	}
 
+	if (params_len > 0 && params[0] != 0) {
+		nfc_tm_deactivated(dev->nfc_dev);
+
+		dev->tgt_mode = 0;
+
+		kfree_skb(skb_resp);
+		return 0;
+	}
+
+	skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
+	skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
+	skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
+
+	return nfc_tm_data_received(dev->nfc_dev, skb_resp);
+}
+
+static void pn533_wq_tg_get_data(struct work_struct *work)
+{
+	struct pn533 *dev = container_of(work, struct pn533, tg_work);
+	struct pn533_frame *in_frame;
+	struct sk_buff *skb_resp;
+	size_t skb_resp_len;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
+		PN533_CMD_DATAEXCH_DATA_MAXLEN +
+		PN533_FRAME_TAIL_SIZE;
+
+	skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL);
+	if (!skb_resp)
+		return;
+
+	in_frame = (struct pn533_frame *)skb_resp->data;
+
+	pn533_tx_frame_init(dev->out_frame, PN533_CMD_TG_GET_DATA);
+	pn533_tx_frame_finish(dev->out_frame);
+
+	pn533_send_cmd_frame_async(dev, dev->out_frame, in_frame,
+				   skb_resp_len,
+				   pn533_tm_get_data_complete,
+				   skb_resp, GFP_KERNEL);
+
+	return;
+}
+
+#define ATR_REQ_GB_OFFSET 17
+static int pn533_init_target_complete(struct pn533 *dev, void *arg,
+				      u8 *params, int params_len)
+{
+	struct pn533_cmd_init_target_response *resp;
+	u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
+	size_t gb_len;
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
 	if (params_len < 0) {
-		nfc_dev_err(&dev->interface->dev, "Error %d when running poll",
-								params_len);
-		goto stop_poll;
+		nfc_dev_err(&dev->interface->dev,
+			    "Error %d when starting as a target",
+			    params_len);
+
+		return params_len;
 	}
 
-	resp = (struct pn533_poll_response *) params;
-	if (resp->nbtg) {
-		rc = pn533_target_found(dev, resp, params_len);
+	if (params_len < ATR_REQ_GB_OFFSET + 1)
+		return -EINVAL;
 
-		/* We must stop the poll after a valid target found */
-		if (rc == 0)
-			goto stop_poll;
+	resp = (struct pn533_cmd_init_target_response *) params;
+
+	nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x param len %d\n",
+		    resp->mode, params_len);
+
+	frame = resp->mode & PN533_INIT_TARGET_RESP_FRAME_MASK;
+	if (frame == PN533_INIT_TARGET_RESP_ACTIVE)
+		comm_mode = NFC_COMM_ACTIVE;
 
-		if (rc != -EAGAIN)
-			nfc_dev_err(&dev->interface->dev, "The target found is"
-					" not valid - continuing to poll");
+	/* Again, only DEP */
+	if ((resp->mode & PN533_INIT_TARGET_RESP_DEP) == 0)
+		return -EOPNOTSUPP;
+
+	gb = resp->cmd + ATR_REQ_GB_OFFSET;
+	gb_len = params_len - (ATR_REQ_GB_OFFSET + 1);
+
+	rc = nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
+			      comm_mode, gb, gb_len);
+	if (rc < 0) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Error when signaling target activation");
+		return rc;
 	}
 
-	dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count;
+	dev->tgt_mode = 1;
 
-	next_mod = dev->poll_mod_active[dev->poll_mod_curr];
+	queue_work(dev->wq, &dev->tg_work);
 
-	nfc_dev_dbg(&dev->interface->dev, "Polling next modulation (0x%x)",
-							dev->poll_mod_curr);
+	return 0;
+}
+
+static void pn533_listen_mode_timer(unsigned long data)
+{
+	struct pn533 *dev = (struct pn533 *) data;
+
+	nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout");
+
+	/* An ack will cancel the last issued command (poll) */
+	pn533_send_ack(dev, GFP_ATOMIC);
+
+	dev->cancel_listen = 1;
+
+	mutex_unlock(&dev->cmd_lock);
+
+	pn533_poll_next_mod(dev);
+
+	queue_work(dev->wq, &dev->poll_work);
+}
 
-	pn533_start_poll_frame(dev->out_frame, next_mod);
+static int pn533_poll_complete(struct pn533 *dev, void *arg,
+			       u8 *params, int params_len)
+{
+	struct pn533_poll_modulations *cur_mod;
+	int rc;
 
-	/* Don't need to down the semaphore again */
-	rc = __pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
-				dev->in_maxlen, pn533_start_poll_complete,
-				NULL, GFP_ATOMIC);
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	if (params_len == -ENOENT) {
+		if (dev->poll_mod_count != 0)
+			return 0;
+
+		nfc_dev_err(&dev->interface->dev,
+			    "Polling operation has been stopped");
 
-	if (rc == -EPERM) {
-		nfc_dev_dbg(&dev->interface->dev, "Cannot poll next modulation"
-					" because poll has been stopped");
 		goto stop_poll;
 	}
 
-	if (rc) {
-		nfc_dev_err(&dev->interface->dev, "Error %d when trying to poll"
-							" next modulation", rc);
+	if (params_len < 0) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Error %d when running poll", params_len);
+
 		goto stop_poll;
 	}
 
-	/* Inform caller function to do not up the semaphore */
-	return -EINPROGRESS;
+	cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+	if (cur_mod->len == 0) {
+		del_timer(&dev->listen_timer);
+
+		return pn533_init_target_complete(dev, arg, params, params_len);
+	} else {
+		rc = pn533_start_poll_complete(dev, arg, params, params_len);
+		if (!rc)
+			return rc;
+	}
+
+	pn533_poll_next_mod(dev);
+
+	queue_work(dev->wq, &dev->poll_work);
+
+	return 0;
 
 stop_poll:
 	pn533_poll_reset_mod_list(dev);
@@ -1078,61 +1322,104 @@ stop_poll:
 	return 0;
 }
 
-static int pn533_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
+static void pn533_build_poll_frame(struct pn533 *dev,
+				   struct pn533_frame *frame,
+				   struct pn533_poll_modulations *mod)
 {
-	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-	struct pn533_poll_modulations *start_mod;
-	int rc;
+	nfc_dev_dbg(&dev->interface->dev, "mod len %d\n", mod->len);
 
-	nfc_dev_dbg(&dev->interface->dev, "%s - protocols=0x%x", __func__,
-								protocols);
+	if (mod->len == 0) {
+		/* Listen mode */
+		pn533_init_target_frame(frame, dev->gb, dev->gb_len);
+	} else {
+		/* Polling mode */
+		pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
 
-	if (dev->poll_mod_count) {
-		nfc_dev_err(&dev->interface->dev, "Polling operation already"
-								" active");
-		return -EBUSY;
-	}
+		memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
+		frame->datalen += mod->len;
 
-	if (dev->tgt_active_prot) {
-		nfc_dev_err(&dev->interface->dev, "Cannot poll with a target"
-							" already activated");
-		return -EBUSY;
+		pn533_tx_frame_finish(frame);
 	}
+}
 
-	pn533_poll_create_mod_list(dev, protocols);
+static int pn533_send_poll_frame(struct pn533 *dev)
+{
+	struct pn533_poll_modulations *cur_mod;
+	int rc;
 
-	if (!dev->poll_mod_count) {
-		nfc_dev_err(&dev->interface->dev, "No valid protocols"
-								" specified");
-		rc = -EINVAL;
-		goto error;
+	cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+	pn533_build_poll_frame(dev, dev->out_frame, cur_mod);
+
+	rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
+				dev->in_maxlen,	pn533_poll_complete,
+				NULL, GFP_KERNEL);
+	if (rc)
+		nfc_dev_err(&dev->interface->dev, "Polling loop error %d", rc);
+
+	return rc;
+}
+
+static void pn533_wq_poll(struct work_struct *work)
+{
+	struct pn533 *dev = container_of(work, struct pn533, poll_work);
+	struct pn533_poll_modulations *cur_mod;
+	int rc;
+
+	cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+	nfc_dev_dbg(&dev->interface->dev,
+		    "%s cancel_listen %d modulation len %d",
+		    __func__, dev->cancel_listen, cur_mod->len);
+
+	if (dev->cancel_listen == 1) {
+		dev->cancel_listen = 0;
+		usb_kill_urb(dev->in_urb);
 	}
 
-	nfc_dev_dbg(&dev->interface->dev, "It will poll %d modulations types",
-							dev->poll_mod_count);
+	rc = pn533_send_poll_frame(dev);
+	if (rc)
+		return;
 
-	dev->poll_mod_curr = 0;
-	start_mod = dev->poll_mod_active[dev->poll_mod_curr];
+	if (cur_mod->len == 0 && dev->poll_mod_count > 1)
+		mod_timer(&dev->listen_timer, jiffies + PN533_LISTEN_TIME * HZ);
 
-	pn533_start_poll_frame(dev->out_frame, start_mod);
+	return;
+}
 
-	rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
-				dev->in_maxlen,	pn533_start_poll_complete,
-				NULL, GFP_KERNEL);
+static int pn533_start_poll(struct nfc_dev *nfc_dev,
+			    u32 im_protocols, u32 tm_protocols)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
 
-	if (rc) {
-		nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
-							" start poll", rc);
-		goto error;
+	nfc_dev_dbg(&dev->interface->dev,
+		    "%s: im protocols 0x%x tm protocols 0x%x",
+		    __func__, im_protocols, tm_protocols);
+
+	if (dev->tgt_active_prot) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Cannot poll with a target already activated");
+		return -EBUSY;
 	}
 
-	dev->poll_protocols = protocols;
+	if (dev->tgt_mode) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Cannot poll while already being activated");
+		return -EBUSY;
+	}
 
-	return 0;
+	if (tm_protocols) {
+		dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len);
+		if (dev->gb == NULL)
+			tm_protocols = 0;
+	}
 
-error:
-	pn533_poll_reset_mod_list(dev);
-	return rc;
+	dev->poll_mod_curr = 0;
+	pn533_poll_create_mod_list(dev, im_protocols, tm_protocols);
+	dev->poll_protocols = im_protocols;
+	dev->listen_protocols = tm_protocols;
+
+	return pn533_send_poll_frame(dev);
 }
 
 static void pn533_stop_poll(struct nfc_dev *nfc_dev)
@@ -1141,6 +1428,8 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
+	del_timer(&dev->listen_timer);
+
 	if (!dev->poll_mod_count) {
 		nfc_dev_dbg(&dev->interface->dev, "Polling operation was not"
 								" running");
@@ -1152,6 +1441,8 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
 
 	/* prevent pn533_start_poll_complete to issue a new poll meanwhile */
 	usb_kill_urb(dev->in_urb);
+
+	pn533_poll_reset_mod_list(dev);
 }
 
 static int pn533_activate_target_nfcdep(struct pn533 *dev)
@@ -1349,13 +1640,29 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
 	return 0;
 }
 
+static int pn533_mod_to_baud(struct pn533 *dev)
+{
+	switch (dev->poll_mod_curr) {
+	case PN533_POLL_MOD_106KBPS_A:
+		return 0;
+	case PN533_POLL_MOD_212KBPS_FELICA:
+		return 1;
+	case PN533_POLL_MOD_424KBPS_FELICA:
+		return 2;
+	default:
+		return -EINVAL;
+	}
+}
+
+#define PASSIVE_DATA_LEN 5
 static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
 			     u8 comm_mode, u8* gb, size_t gb_len)
 {
 	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
 	struct pn533_cmd_jump_dep *cmd;
-	u8 cmd_len;
-	int rc;
+	u8 cmd_len, *data_ptr;
+	u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
+	int rc, baud;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
@@ -1371,7 +1678,17 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
 		return -EBUSY;
 	}
 
+	baud = pn533_mod_to_baud(dev);
+	if (baud < 0) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Invalid curr modulation %d", dev->poll_mod_curr);
+		return baud;
+	}
+
 	cmd_len = sizeof(struct pn533_cmd_jump_dep) + gb_len;
+	if (comm_mode == NFC_COMM_PASSIVE)
+		cmd_len += PASSIVE_DATA_LEN;
+
 	cmd = kzalloc(cmd_len, GFP_KERNEL);
 	if (cmd == NULL)
 		return -ENOMEM;
@@ -1379,10 +1696,18 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
 	pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_JUMP_FOR_DEP);
 
 	cmd->active = !comm_mode;
-	cmd->baud = 0;
+	cmd->next = 0;
+	cmd->baud = baud;
+	data_ptr = cmd->data;
+	if (comm_mode == NFC_COMM_PASSIVE && cmd->baud > 0) {
+		memcpy(data_ptr, passive_data, PASSIVE_DATA_LEN);
+		cmd->next |= 1;
+		data_ptr += PASSIVE_DATA_LEN;
+	}
+
 	if (gb != NULL && gb_len > 0) {
-		cmd->next = 4; /* We have some Gi */
-		memcpy(cmd->gt, gb, gb_len);
+		cmd->next |= 4; /* We have some Gi */
+		memcpy(data_ptr, gb, gb_len);
 	} else {
 		cmd->next = 0;
 	}
@@ -1407,15 +1732,25 @@ out:
 
 static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
 {
-	pn533_deactivate_target(nfc_dev, 0);
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+
+	pn533_poll_reset_mod_list(dev);
+
+	if (dev->tgt_mode || dev->tgt_active_prot) {
+		pn533_send_ack(dev, GFP_KERNEL);
+		usb_kill_urb(dev->in_urb);
+	}
+
+	dev->tgt_active_prot = 0;
+	dev->tgt_mode = 0;
+
+	skb_queue_purge(&dev->resp_q);
 
 	return 0;
 }
 
-#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
-#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
-
-static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
+static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb,
+				bool target)
 {
 	int payload_len = skb->len;
 	struct pn533_frame *out_frame;
@@ -1432,14 +1767,20 @@ static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
 		return -ENOSYS;
 	}
 
-	skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
-	out_frame = (struct pn533_frame *) skb->data;
+	if (target == true) {
+		skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
+		out_frame = (struct pn533_frame *) skb->data;
 
-	pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE);
+		pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE);
+		tg = 1;
+		memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8));
+		out_frame->datalen += sizeof(u8);
+	} else {
+		skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
+		out_frame = (struct pn533_frame *) skb->data;
+		pn533_tx_frame_init(out_frame, PN533_CMD_TG_SET_DATA);
+	}
 
-	tg = 1;
-	memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8));
-	out_frame->datalen += sizeof(u8);
 
 	/* The data is already in the out_frame, just update the datalen */
 	out_frame->datalen += payload_len;
@@ -1550,9 +1891,9 @@ error:
 	return 0;
 }
 
-static int pn533_data_exchange(struct nfc_dev *nfc_dev,
-			       struct nfc_target *target, struct sk_buff *skb,
-			       data_exchange_cb_t cb, void *cb_context)
+static int pn533_transceive(struct nfc_dev *nfc_dev,
+			    struct nfc_target *target, struct sk_buff *skb,
+			    data_exchange_cb_t cb, void *cb_context)
 {
 	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
 	struct pn533_frame *out_frame, *in_frame;
@@ -1570,7 +1911,7 @@ static int pn533_data_exchange(struct nfc_dev *nfc_dev,
 		goto error;
 	}
 
-	rc = pn533_data_exchange_tx_frame(dev, skb);
+	rc = pn533_build_tx_frame(dev, skb, true);
 	if (rc)
 		goto error;
 
@@ -1618,6 +1959,63 @@ error:
 	return rc;
 }
 
+static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
+				  u8 *params, int params_len)
+{
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	if (params_len < 0) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Error %d when sending data",
+			    params_len);
+
+		return params_len;
+	}
+
+	if (params_len > 0 && params[0] != 0) {
+		nfc_tm_deactivated(dev->nfc_dev);
+
+		dev->tgt_mode = 0;
+
+		return 0;
+	}
+
+	queue_work(dev->wq, &dev->tg_work);
+
+	return 0;
+}
+
+static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+	struct pn533_frame *out_frame;
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	rc = pn533_build_tx_frame(dev, skb, false);
+	if (rc)
+		goto error;
+
+	out_frame = (struct pn533_frame *) skb->data;
+
+	rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame,
+					dev->in_maxlen, pn533_tm_send_complete,
+					NULL, GFP_KERNEL);
+	if (rc) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Error %d when trying to send data", rc);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	kfree_skb(skb);
+
+	return rc;
+}
+
 static void pn533_wq_mi_recv(struct work_struct *work)
 {
 	struct pn533 *dev = container_of(work, struct pn533, mi_work);
@@ -1638,7 +2036,7 @@ static void pn533_wq_mi_recv(struct work_struct *work)
 
 	skb_reserve(skb_cmd, PN533_CMD_DATAEXCH_HEAD_LEN);
 
-	rc = pn533_data_exchange_tx_frame(dev, skb_cmd);
+	rc = pn533_build_tx_frame(dev, skb_cmd, true);
 	if (rc)
 		goto error_frame;
 
@@ -1677,7 +2075,7 @@ error_cmd:
 
 	kfree(arg);
 
-	up(&dev->cmd_lock);
+	mutex_unlock(&dev->cmd_lock);
 }
 
 static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
@@ -1712,7 +2110,8 @@ struct nfc_ops pn533_nfc_ops = {
 	.stop_poll = pn533_stop_poll,
 	.activate_target = pn533_activate_target,
 	.deactivate_target = pn533_deactivate_target,
-	.data_exchange = pn533_data_exchange,
+	.im_transceive = pn533_transceive,
+	.tm_send = pn533_tm_send,
 };
 
 static int pn533_probe(struct usb_interface *interface,
@@ -1723,6 +2122,7 @@ static int pn533_probe(struct usb_interface *interface,
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
 	struct pn533_config_max_retries max_retries;
+	struct pn533_config_timing timing;
 	int in_endpoint = 0;
 	int out_endpoint = 0;
 	int rc = -ENOMEM;
@@ -1735,7 +2135,7 @@ static int pn533_probe(struct usb_interface *interface,
 
 	dev->udev = usb_get_dev(interface_to_usbdev(interface));
 	dev->interface = interface;
-	sema_init(&dev->cmd_lock, 1);
+	mutex_init(&dev->cmd_lock);
 
 	iface_desc = interface->cur_altsetting;
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
@@ -1779,12 +2179,18 @@ static int pn533_probe(struct usb_interface *interface,
 
 	INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete);
 	INIT_WORK(&dev->mi_work, pn533_wq_mi_recv);
+	INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data);
+	INIT_WORK(&dev->poll_work, pn533_wq_poll);
 	dev->wq = alloc_workqueue("pn533",
 				  WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
 				  1);
 	if (dev->wq == NULL)
 		goto error;
 
+	init_timer(&dev->listen_timer);
+	dev->listen_timer.data = (unsigned long) dev;
+	dev->listen_timer.function = pn533_listen_mode_timer;
+
 	skb_queue_head_init(&dev->resp_q);
 
 	usb_set_intfdata(interface, dev);
@@ -1830,13 +2236,29 @@ static int pn533_probe(struct usb_interface *interface,
 	if (rc) {
 		nfc_dev_err(&dev->interface->dev, "Error on setting MAX_RETRIES"
 								" config");
-		goto free_nfc_dev;
+		goto unregister_nfc_dev;
+	}
+
+	timing.rfu = PN533_CONFIG_TIMING_102;
+	timing.atr_res_timeout = PN533_CONFIG_TIMING_204;
+	timing.dep_timeout = PN533_CONFIG_TIMING_409;
+
+	rc = pn533_set_configuration(dev, PN533_CFGITEM_TIMING,
+				(u8 *) &timing, sizeof(timing));
+	if (rc) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Error on setting RF timings");
+		goto unregister_nfc_dev;
 	}
 
 	return 0;
 
+unregister_nfc_dev:
+	nfc_unregister_device(dev->nfc_dev);
+
 free_nfc_dev:
 	nfc_free_device(dev->nfc_dev);
+
 destroy_wq:
 	destroy_workqueue(dev->wq);
 error:
@@ -1865,6 +2287,8 @@ static void pn533_disconnect(struct usb_interface *interface)
 
 	skb_queue_purge(&dev->resp_q);
 
+	del_timer(&dev->listen_timer);
+
 	kfree(dev->in_frame);
 	usb_free_urb(dev->in_urb);
 	kfree(dev->out_frame);
diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c
index 281f18c..457eac3 100644
--- a/drivers/nfc/pn544_hci.c
+++ b/drivers/nfc/pn544_hci.c
@@ -576,7 +576,8 @@ static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb)
 	return pn544_hci_i2c_write(client, skb->data, skb->len);
 }
 
-static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
+static int pn544_hci_start_poll(struct nfc_shdlc *shdlc,
+				u32 im_protocols, u32 tm_protocols)
 {
 	struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
 	u8 phases = 0;
@@ -584,7 +585,8 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
 	u8 duration[2];
 	u8 activated;
 
-	pr_info(DRIVER_DESC ": %s protocols = %d\n", __func__, protocols);
+	pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",
+		__func__, im_protocols, tm_protocols);
 
 	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
 			       NFC_HCI_EVT_END_OPERATION, NULL, 0);
@@ -604,10 +606,10 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
 	if (r < 0)
 		return r;
 
-	if (protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
+	if (im_protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
 			 NFC_PROTO_JEWEL_MASK))
 		phases |= 1;		/* Type A */
-	if (protocols & NFC_PROTO_FELICA_MASK) {
+	if (im_protocols & NFC_PROTO_FELICA_MASK) {
 		phases |= (1 << 2);	/* Type F 212 */
 		phases |= (1 << 3);	/* Type F 424 */
 	}
diff --git a/drivers/of/base.c b/drivers/of/base.c
index d9bfd49..7acd785 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -961,6 +961,8 @@ int of_parse_phandle_with_args(struct device_node *np, const char *list_name,
 				out_args->args_count = count;
 				for (i = 0; i < count; i++)
 					out_args->args[i] = be32_to_cpup(list++);
+			} else {
+				of_node_put(node);
 			}
 			return 0;
 		}
@@ -1173,7 +1175,7 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np,
 	ap->stem[stem_len] = 0;
 	list_add_tail(&ap->link, &aliases_lookup);
 	pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n",
-		 ap->alias, ap->stem, ap->id, np ? np->full_name : NULL);
+		 ap->alias, ap->stem, ap->id, of_node_full_name(np));
 }
 
 /**
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 9cf0060..ff8ab7b 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -255,7 +255,7 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec,
 
 	skiplevel:
 		/* Iterate again with new parent */
-		pr_debug(" -> new parent: %s\n", newpar ? newpar->full_name : "<>");
+		pr_debug(" -> new parent: %s\n", of_node_full_name(newpar));
 		of_node_put(ipar);
 		ipar = newpar;
 		newpar = NULL;
diff --git a/drivers/oprofile/oprofile_perf.c b/drivers/oprofile/oprofile_perf.c
index da14432..efc4b7f 100644
--- a/drivers/oprofile/oprofile_perf.c
+++ b/drivers/oprofile/oprofile_perf.c
@@ -25,7 +25,7 @@ static int oprofile_perf_enabled;
 static DEFINE_MUTEX(oprofile_perf_mutex);
 
 static struct op_counter_config *counter_config;
-static struct perf_event **perf_events[nr_cpumask_bits];
+static struct perf_event **perf_events[NR_CPUS];
 static int num_counters;
 
 /*
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 432d4bb..ffddc4f 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -174,7 +174,7 @@ static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where,
 		int size, u32 *val)
 {
 	struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->bridge));
-	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
+	u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start;
 	u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3);
 	void __iomem *base_addr = d->hba.base_addr;
 	unsigned long flags;
@@ -209,7 +209,7 @@ static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where,
 	int size, u32 val)
 {
 	struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->bridge));
-	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
+	u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start;
 	u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3);
 	void __iomem *base_addr = d->hba.base_addr;
 	unsigned long flags;
@@ -554,7 +554,7 @@ dino_fixup_bus(struct pci_bus *bus)
         struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge));
 
 	DBG(KERN_WARNING "%s(0x%p) bus %d platform_data 0x%p\n",
-	    __func__, bus, bus->secondary,
+	    __func__, bus, bus->busn_res.start,
 	    bus->bridge->platform_data);
 
 	/* Firmware doesn't set up card-mode dino, so we have to */
@@ -898,6 +898,7 @@ static int __init dino_probe(struct parisc_device *dev)
 	LIST_HEAD(resources);
 	struct pci_bus *bus;
 	unsigned long hpa = dev->hpa.start;
+	int max;
 
 	name = "Dino";
 	if (is_card_dino(&dev->id)) {
@@ -983,6 +984,10 @@ static int __init dino_probe(struct parisc_device *dev)
 	if (dino_dev->hba.gmmio_space.flags)
 		pci_add_resource(&resources, &dino_dev->hba.gmmio_space);
 
+	dino_dev->hba.bus_num.start = dino_current_bus;
+	dino_dev->hba.bus_num.end = 255;
+	dino_dev->hba.bus_num.flags = IORESOURCE_BUS;
+	pci_add_resource(&resources, &dino_dev->hba.bus_num);
 	/*
 	** It's not used to avoid chicken/egg problems
 	** with configuration accessor functions.
@@ -998,12 +1003,13 @@ static int __init dino_probe(struct parisc_device *dev)
 		return 0;
 	}
 
-	bus->subordinate = pci_scan_child_bus(bus);
+	max = pci_scan_child_bus(bus);
+	pci_bus_update_busn_res_end(bus, max);
 
 	/* This code *depends* on scanning being single threaded
 	 * if it isn't, this global bus number count will fail
 	 */
-	dino_current_bus = bus->subordinate + 1;
+	dino_current_bus = max + 1;
 	pci_bus_assign_resources(bus);
 	pci_bus_add_devices(bus);
 	return 0;
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 1f9e9fe..9544cdc 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -146,7 +146,7 @@
 #endif
 
 #include <asm/ropes.h>
-#include "./iosapic_private.h"
+#include "iosapic_private.h"
 
 #define MODULE_NAME "iosapic"
 
@@ -532,7 +532,7 @@ iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev)
 		intr_slot = PCI_SLOT(pcidev->devfn);
 	}
 	DBG_IRT("iosapic_xlate_pin:  bus %d slot %d pin %d\n",
-				pcidev->bus->secondary, intr_slot, intr_pin);
+			pcidev->bus->busn_res.start, intr_slot, intr_pin);
 
 	return irt_find_irqline(isi, intr_slot, intr_pin);
 }
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 052fa23..4f9cf24 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -189,8 +189,8 @@ lba_dump_res(struct resource *r, int d)
 
 static int lba_device_present(u8 bus, u8 dfn, struct lba_device *d)
 {
-	u8 first_bus = d->hba.hba_bus->secondary;
-	u8 last_sub_bus = d->hba.hba_bus->subordinate;
+	u8 first_bus = d->hba.hba_bus->busn_res.start;
+	u8 last_sub_bus = d->hba.hba_bus->busn_res.end;
 
 	if ((bus < first_bus) ||
 	    (bus > last_sub_bus) ||
@@ -364,7 +364,7 @@ lba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size)
 static int elroy_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
 {
 	struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
-	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
+	u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start;
 	u32 tok = LBA_CFG_TOK(local_bus, devfn);
 	void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;
 
@@ -380,7 +380,7 @@ static int elroy_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int
 		return 0;
 	}
 
-	if (LBA_SKIP_PROBE(d) && !lba_device_present(bus->secondary, devfn, d)) {
+	if (LBA_SKIP_PROBE(d) && !lba_device_present(bus->busn_res.start, devfn, d)) {
 		DBG_CFG("%s(%x+%2x) -> -1 (b)\n", __func__, tok, pos);
 		/* either don't want to look or know device isn't present. */
 		*data = ~0U;
@@ -431,7 +431,7 @@ lba_wr_cfg(struct lba_device *d, u32 tok, u8 reg, u32 data, u32 size)
 static int elroy_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data)
 {
 	struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
-	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
+	u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start;
 	u32 tok = LBA_CFG_TOK(local_bus,devfn);
 
 	if ((pos > 255) || (devfn > 255))
@@ -444,7 +444,7 @@ static int elroy_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int
 		return 0;
 	}
 
-	if (LBA_SKIP_PROBE(d) && (!lba_device_present(bus->secondary, devfn, d))) {
+	if (LBA_SKIP_PROBE(d) && (!lba_device_present(bus->busn_res.start, devfn, d))) {
 		DBG_CFG("%s(%x+%2x) = 0x%x (b)\n", __func__, tok, pos,data);
 		return 1; /* New Workaround */
 	}
@@ -481,7 +481,7 @@ static struct pci_ops elroy_cfg_ops = {
 static int mercury_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
 {
 	struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
-	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
+	u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start;
 	u32 tok = LBA_CFG_TOK(local_bus, devfn);
 	void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;
 
@@ -514,7 +514,7 @@ static int mercury_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, i
 {
 	struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
 	void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;
-	u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
+	u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start;
 	u32 tok = LBA_CFG_TOK(local_bus,devfn);
 
 	if ((pos > 255) || (devfn > 255))
@@ -636,7 +636,7 @@ lba_fixup_bus(struct pci_bus *bus)
 	struct lba_device *ldev = LBA_DEV(parisc_walk_tree(bus->bridge));
 
 	DBG("lba_fixup_bus(0x%p) bus %d platform_data 0x%p\n",
-		bus, bus->secondary, bus->bridge->platform_data);
+		bus, (int)bus->busn_res.start, bus->bridge->platform_data);
 
 	/*
 	** Properly Setup MMIO resources for this bus.
@@ -989,6 +989,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 		case PAT_PBNUM:
 			lba_dev->hba.bus_num.start = p->start;
 			lba_dev->hba.bus_num.end   = p->end;
+			lba_dev->hba.bus_num.flags = IORESOURCE_BUS;
 			break;
 
 		case PAT_LMMIO:
@@ -1366,6 +1367,7 @@ lba_driver_probe(struct parisc_device *dev)
 	void *tmp_obj;
 	char *version;
 	void __iomem *addr = ioremap_nocache(dev->hpa.start, 4096);
+	int max;
 
 	/* Read HW Rev First */
 	func_class = READ_REG32(addr + LBA_FCLASS);
@@ -1502,6 +1504,8 @@ lba_driver_probe(struct parisc_device *dev)
 	if (lba_dev->hba.gmmio_space.flags)
 		pci_add_resource(&resources, &lba_dev->hba.gmmio_space);
 
+	pci_add_resource(&resources, &lba_dev->hba.bus_num);
+
 	dev->dev.platform_data = lba_dev;
 	lba_bus = lba_dev->hba.hba_bus =
 		pci_create_root_bus(&dev->dev, lba_dev->hba.bus_num.start,
@@ -1511,7 +1515,7 @@ lba_driver_probe(struct parisc_device *dev)
 		return 0;
 	}
 
-	lba_bus->subordinate = pci_scan_child_bus(lba_bus);
+	max = pci_scan_child_bus(lba_bus);
 
 	/* This is in lieu of calling pci_assign_unassigned_resources() */
 	if (is_pdc_pat()) {
@@ -1541,7 +1545,7 @@ lba_driver_probe(struct parisc_device *dev)
 		lba_dev->flags |= LBA_FLAG_SKIP_PROBE;
 	}
 
-	lba_next_bus = lba_bus->subordinate + 1;
+	lba_next_bus = max + 1;
 	pci_bus_add_devices(lba_bus);
 
 	/* Whew! Finally done! Tell services we got this one covered. */
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 2a58164..ba91a7e 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -162,7 +162,8 @@ int pci_user_read_config_##size						\
 	if (ret > 0)							\
 		ret = -EINVAL;						\
 	return ret;							\
-}
+}									\
+EXPORT_SYMBOL_GPL(pci_user_read_config_##size);
 
 /* Returns 0 on success, negative values indicate error. */
 #define PCI_USER_WRITE_CONFIG(size,type)				\
@@ -181,7 +182,8 @@ int pci_user_write_config_##size					\
 	if (ret > 0)							\
 		ret = -EINVAL;						\
 	return ret;							\
-}
+}									\
+EXPORT_SYMBOL_GPL(pci_user_write_config_##size);
 
 PCI_USER_READ_CONFIG(byte, u8)
 PCI_USER_READ_CONFIG(word, u16)
diff --git a/drivers/pci/hotplug-pci.c b/drivers/pci/hotplug-pci.c
index d3509cd..6258dc2 100644
--- a/drivers/pci/hotplug-pci.c
+++ b/drivers/pci/hotplug-pci.c
@@ -4,18 +4,26 @@
 #include <linux/export.h>
 #include "pci.h"
 
-
-unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
+int __ref pci_hp_add_bridge(struct pci_dev *dev)
 {
-	unsigned int max;
-
-	max = pci_scan_child_bus(bus);
+	struct pci_bus *parent = dev->bus;
+	int pass, busnr, start = parent->busn_res.start;
+	int end = parent->busn_res.end;
 
-	/*
-	 * Make the discovered devices available.
-	 */
-	pci_bus_add_devices(bus);
+	for (busnr = start; busnr <= end; busnr++) {
+		if (!pci_find_bus(pci_domain_nr(parent), busnr))
+			break;
+	}
+	if (busnr-- > end) {
+		printk(KERN_ERR "No bus number available for hot-added bridge %s\n",
+				pci_name(dev));
+		return -1;
+	}
+	for (pass = 0; pass < 2; pass++)
+		busnr = pci_scan_bridge(parent, dev, busnr, pass);
+	if (!dev->subordinate)
+		return -1;
 
-	return max;
+	return 0;
 }
-EXPORT_SYMBOL(pci_do_scan_bus);
+EXPORT_SYMBOL_GPL(pci_hp_add_bridge);
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 806c44f..395c67d 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -100,11 +100,11 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
 			PCI_PRIMARY_BUS,
 			&buses);
 
-	if (((buses >> 8) & 0xff) != bus->secondary) {
+	if (((buses >> 8) & 0xff) != bus->busn_res.start) {
 		buses = (buses & 0xff000000)
 			| ((unsigned int)(bus->primary)     <<  0)
-			| ((unsigned int)(bus->secondary)   <<  8)
-			| ((unsigned int)(bus->subordinate) << 16);
+			| ((unsigned int)(bus->busn_res.start)   <<  8)
+			| ((unsigned int)(bus->busn_res.end) << 16);
 		pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
 	}
 	return NOTIFY_OK;
@@ -132,6 +132,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
 	if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
 		return AE_OK;
 
+	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		warn("can't evaluate _ADR (%#x)\n", status);
+		return AE_OK;
+	}
+
+	device = (adr >> 16) & 0xffff;
+	function = adr & 0xffff;
+
 	pdev = pbus->self;
 	if (pdev && pci_is_pcie(pdev)) {
 		tmp = acpi_find_root_bridge_handle(pdev);
@@ -144,10 +153,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
 		}
 	}
 
-	acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
-	device = (adr >> 16) & 0xffff;
-	function = adr & 0xffff;
-
 	newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
 	if (!newfunc)
 		return AE_NO_MEMORY;
@@ -692,7 +697,7 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
 	 * bus->subordinate value because it could have
 	 * padding in it.
 	 */
-	max = bus->secondary;
+	max = bus->busn_res.start;
 
 	list_for_each(tmp, &bus->children) {
 		n = pci_bus_max_busnr(pci_bus_b(tmp));
@@ -878,6 +883,24 @@ static void disable_bridges(struct pci_bus *bus)
 	}
 }
 
+/* return first device in slot, acquiring a reference on it */
+static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
+{
+	struct pci_bus *bus = slot->bridge->pci_bus;
+	struct pci_dev *dev;
+	struct pci_dev *ret = NULL;
+
+	down_read(&pci_bus_sem);
+	list_for_each_entry(dev, &bus->devices, bus_list)
+		if (PCI_SLOT(dev->devfn) == slot->device) {
+			ret = pci_dev_get(dev);
+			break;
+		}
+	up_read(&pci_bus_sem);
+
+	return ret;
+}
+
 /**
  * disable_device - disable a slot
  * @slot: ACPI PHP slot
@@ -893,6 +916,7 @@ static int disable_device(struct acpiphp_slot *slot)
 	pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
 	if (!pdev)
 		goto err_exit;
+	pci_dev_put(pdev);
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (func->bridge) {
@@ -901,18 +925,22 @@ static int disable_device(struct acpiphp_slot *slot)
 						(u32)1, NULL, NULL);
 			func->bridge = NULL;
 		}
+	}
 
-		pdev = pci_get_slot(slot->bridge->pci_bus,
-				    PCI_DEVFN(slot->device, func->function));
-		if (pdev) {
-			pci_stop_bus_device(pdev);
-			if (pdev->subordinate) {
-				disable_bridges(pdev->subordinate);
-				pci_disable_device(pdev);
-			}
-			__pci_remove_bus_device(pdev);
-			pci_dev_put(pdev);
+	/*
+	 * enable_device() enumerates all functions in this device via
+	 * pci_scan_slot(), whether they have associated ACPI hotplug
+	 * methods (_EJ0, etc.) or not.  Therefore, we remove all functions
+	 * here.
+	 */
+	while ((pdev = dev_in_slot(slot))) {
+		pci_stop_bus_device(pdev);
+		if (pdev->subordinate) {
+			disable_bridges(pdev->subordinate);
+			pci_disable_device(pdev);
 		}
+		__pci_remove_bus_device(pdev);
+		pci_dev_put(pdev);
 	}
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index ae853cc..dcc75c7 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -285,42 +285,19 @@ int __ref cpci_configure_slot(struct slot *slot)
 	for (fn = 0; fn < 8; fn++) {
 		struct pci_dev *dev;
 
-		dev = pci_get_slot(parent, PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
+		dev = pci_get_slot(parent,
+				   PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
 		if (!dev)
 			continue;
 		if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
-		    (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
-			/* Find an unused bus number for the new bridge */
-			struct pci_bus *child;
-			unsigned char busnr, start = parent->secondary;
-			unsigned char end = parent->subordinate;
-
-			for (busnr = start; busnr <= end; busnr++) {
-				if (!pci_find_bus(pci_domain_nr(parent),
-						  busnr))
-					break;
-			}
-			if (busnr >= end) {
-				err("No free bus for hot-added bridge\n");
-				pci_dev_put(dev);
-				continue;
-			}
-			child = pci_add_new_bus(parent, dev, busnr);
-			if (!child) {
-				err("Cannot add new bus for %s\n",
-				    pci_name(dev));
-				pci_dev_put(dev);
-				continue;
-			}
-			child->subordinate = pci_do_scan_bus(child);
-			pci_bus_size_bridges(child);
-		}
+		    (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
+			pci_hp_add_bridge(dev);
 		pci_dev_put(dev);
 	}
 
-	pci_bus_assign_resources(parent);
+	pci_assign_unassigned_bridge_resources(parent->self);
+
 	pci_bus_add_devices(parent);
-	pci_enable_bridges(parent);
 
 	dbg("%s - exit", __func__);
 	return 0;
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
index 1c84940..09801c6 100644
--- a/drivers/pci/hotplug/cpqphp_pci.c
+++ b/drivers/pci/hotplug/cpqphp_pci.c
@@ -83,7 +83,6 @@ static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iom
 
 int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
 {
-	unsigned char bus;
 	struct pci_bus *child;
 	int num;
 
@@ -106,9 +105,10 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
 	}
 
 	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
-		child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
-		pci_do_scan_bus(child);
+		pci_hp_add_bridge(func->pci_dev);
+		child = func->pci_dev->subordinate;
+		if (child)
+			pci_bus_add_devices(child);
 	}
 
 	pci_dev_put(func->pci_dev);
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index 4fda7e6..7dccad5 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -775,7 +775,6 @@ static u8 bus_structure_fixup(u8 busno)
 
 static int ibm_configure_device(struct pci_func *func)
 {
-	unsigned char bus;
 	struct pci_bus *child;
 	int num;
 	int flag = 0;	/* this is to make sure we don't double scan the bus,
@@ -805,9 +804,10 @@ static int ibm_configure_device(struct pci_func *func)
 		}
 	}
 	if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
-		pci_read_config_byte(func->dev, PCI_SECONDARY_BUS, &bus);
-		child = pci_add_new_bus(func->dev->bus, func->dev, bus);
-		pci_do_scan_bus(child);
+		pci_hp_add_bridge(func->dev);
+		child = func->dev->subordinate;
+		if (child)
+			pci_bus_add_devices(child);
 	}
 
 	return 0;
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 47d9dc0..09cecaf 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -34,29 +34,6 @@
 #include "../pci.h"
 #include "pciehp.h"
 
-static int __ref pciehp_add_bridge(struct pci_dev *dev)
-{
-	struct pci_bus *parent = dev->bus;
-	int pass, busnr, start = parent->secondary;
-	int end = parent->subordinate;
-
-	for (busnr = start; busnr <= end; busnr++) {
-		if (!pci_find_bus(pci_domain_nr(parent), busnr))
-			break;
-	}
-	if (busnr-- > end) {
-		err("No bus number available for hot-added bridge %s\n",
-				pci_name(dev));
-		return -1;
-	}
-	for (pass = 0; pass < 2; pass++)
-		busnr = pci_scan_bridge(parent, dev, busnr, pass);
-	if (!dev->subordinate)
-		return -1;
-
-	return 0;
-}
-
 int pciehp_configure_device(struct slot *p_slot)
 {
 	struct pci_dev *dev;
@@ -85,9 +62,8 @@ int pciehp_configure_device(struct slot *p_slot)
 		if (!dev)
 			continue;
 		if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
-				(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
-			pciehp_add_bridge(dev);
-		}
+				(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
+			pci_hp_add_bridge(dev);
 		pci_dev_put(dev);
 	}
 
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index de57311..f64ca92 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -397,13 +397,11 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
 			else
 				sn_io_slot_fixup(dev);
 			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-				unsigned char sec_bus;
-				pci_read_config_byte(dev, PCI_SECONDARY_BUS,
-						     &sec_bus);
-				new_bus = pci_add_new_bus(dev->bus, dev,
-							  sec_bus);
-				pci_scan_child_bus(new_bus);
-				new_ppb = 1;
+				pci_hp_add_bridge(dev);
+				if (dev->subordinate) {
+					new_bus = dev->subordinate;
+					new_ppb = 1;
+				}
 			}
 			pci_dev_put(dev);
 		}
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index b00b09b..f9b5a52 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -262,9 +262,6 @@ static int board_added(struct slot *p_slot)
 	}
 
 	if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
-		if (slots_not_empty)
-			return WRONG_BUS_FREQUENCY;
-
 		if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
 			ctrl_err(ctrl, "%s: Issue of set bus speed mode command"
 				 " failed\n", __func__);
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c
index df7e4bf..c627ed9 100644
--- a/drivers/pci/hotplug/shpchp_pci.c
+++ b/drivers/pci/hotplug/shpchp_pci.c
@@ -37,9 +37,10 @@
 int __ref shpchp_configure_device(struct slot *p_slot)
 {
 	struct pci_dev *dev;
-	struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
-	int num, fn;
 	struct controller *ctrl = p_slot->ctrl;
+	struct pci_dev *bridge = ctrl->pci_dev;
+	struct pci_bus *parent = bridge->subordinate;
+	int num, fn;
 
 	dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
 	if (dev) {
@@ -61,39 +62,23 @@ int __ref shpchp_configure_device(struct slot *p_slot)
 		if (!dev)
 			continue;
 		if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
-				(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
-			/* Find an unused bus number for the new bridge */
-			struct pci_bus *child;
-			unsigned char busnr, start = parent->secondary;
-			unsigned char end = parent->subordinate;
-			for (busnr = start; busnr <= end; busnr++) {
-				if (!pci_find_bus(pci_domain_nr(parent),
-							busnr))
-					break;
-			}
-			if (busnr > end) {
-				ctrl_err(ctrl,
-					 "No free bus for hot-added bridge\n");
-				pci_dev_put(dev);
-				continue;
-			}
-			child = pci_add_new_bus(parent, dev, busnr);
-			if (!child) {
-				ctrl_err(ctrl, "Cannot add new bus for %s\n",
-					 pci_name(dev));
-				pci_dev_put(dev);
-				continue;
-			}
-			child->subordinate = pci_do_scan_bus(child);
-			pci_bus_size_bridges(child);
-		}
+		    (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
+			pci_hp_add_bridge(dev);
+		pci_dev_put(dev);
+	}
+
+	pci_assign_unassigned_bridge_resources(bridge);
+
+	for (fn = 0; fn < 8; fn++) {
+		dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
+		if (!dev)
+			continue;
 		pci_configure_slot(dev);
 		pci_dev_put(dev);
 	}
 
-	pci_bus_assign_resources(parent);
 	pci_bus_add_devices(parent);
-	pci_enable_bridges(parent);
+
 	return 0;
 }
 
diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c
index efa30da..eeb23ce 100644
--- a/drivers/pci/hotplug/shpchp_sysfs.c
+++ b/drivers/pci/hotplug/shpchp_sysfs.c
@@ -73,13 +73,13 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
 		}
 	}
 	out += sprintf(out, "Free resources: bus numbers\n");
-	for (busnr = bus->secondary; busnr <= bus->subordinate; busnr++) {
+	for (busnr = bus->busn_res.start; busnr <= bus->busn_res.end; busnr++) {
 		if (!pci_find_bus(pci_domain_nr(bus), busnr))
 			break;
 	}
-	if (busnr < bus->subordinate)
+	if (busnr < bus->busn_res.end)
 		out += sprintf(out, "start = %8.8x, length = %8.8x\n",
-				busnr, (bus->subordinate - busnr));
+				busnr, (int)(bus->busn_res.end - busnr));
 
 	return out - buf;
 }
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 6554e1a..74bbaf8 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -47,7 +47,7 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
 	if (!child)
 		return NULL;
 
-	child->subordinate = busnr;
+	pci_bus_insert_busn_res(child, busnr, busnr);
 	child->dev.parent = bus->bridge;
 	rc = pci_bus_add_child(child);
 	if (rc) {
@@ -327,7 +327,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
 	iov->offset = offset;
 	iov->stride = stride;
 
-	if (virtfn_bus(dev, nr_virtfn - 1) > dev->bus->subordinate) {
+	if (virtfn_bus(dev, nr_virtfn - 1) > dev->bus->busn_res.end) {
 		dev_err(&dev->dev, "SR-IOV: bus number out of range\n");
 		return -ENOMEM;
 	}
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 61e2fef..fbf7b26 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -48,6 +48,12 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
 	if (event != ACPI_NOTIFY_DEVICE_WAKE || !pci_dev)
 		return;
 
+	if (pci_dev->current_state == PCI_D3cold) {
+		pci_wakeup_event(pci_dev);
+		pm_runtime_resume(&pci_dev->dev);
+		return;
+	}
+
 	if (!pci_dev->pm_cap || !pci_dev->pme_support
 	     || pci_check_pme_status(pci_dev)) {
 		if (pci_dev->pme_poll)
@@ -162,6 +168,20 @@ acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
 	return remove_pm_notifier(dev, pci_acpi_wake_dev);
 }
 
+phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
+{
+	acpi_status status = AE_NOT_EXIST;
+	unsigned long long mcfg_addr;
+
+	if (handle)
+		status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
+					       NULL, &mcfg_addr);
+	if (ACPI_FAILURE(status))
+		return 0;
+
+	return (phys_addr_t)mcfg_addr;
+}
+
 /*
  * _SxD returns the D-state with the highest power
  * (lowest D-state number) supported in the S-state "x".
@@ -187,9 +207,13 @@ acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
 
 static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
 {
-	int acpi_state;
+	int acpi_state, d_max;
 
-	acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL);
+	if (pdev->no_d3cold)
+		d_max = ACPI_STATE_D3_HOT;
+	else
+		d_max = ACPI_STATE_D3_COLD;
+	acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL, d_max);
 	if (acpi_state < 0)
 		return PCI_POWER_ERROR;
 
@@ -296,7 +320,13 @@ static void acpi_pci_propagate_run_wake(struct pci_bus *bus, bool enable)
 
 static int acpi_pci_run_wake(struct pci_dev *dev, bool enable)
 {
-	if (dev->pme_interrupt)
+	/*
+	 * Per PCI Express Base Specification Revision 2.0 section
+	 * 5.3.3.2 Link Wakeup, platform support is needed for D3cold
+	 * waking up to power on the main link even if there is PME
+	 * support for D3cold
+	 */
+	if (dev->pme_interrupt && !dev->runtime_d3cold)
 		return 0;
 
 	if (!acpi_pm_device_run_wake(&dev->dev, enable))
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index bf0cee6..ca2e4c7 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -1019,10 +1019,13 @@ static int pci_pm_runtime_suspend(struct device *dev)
 	if (!pm || !pm->runtime_suspend)
 		return -ENOSYS;
 
+	pci_dev->no_d3cold = false;
 	error = pm->runtime_suspend(dev);
 	suspend_report_result(pm->runtime_suspend, error);
 	if (error)
 		return error;
+	if (!pci_dev->d3cold_allowed)
+		pci_dev->no_d3cold = true;
 
 	pci_fixup_device(pci_fixup_suspend, pci_dev);
 
@@ -1044,6 +1047,7 @@ static int pci_pm_runtime_suspend(struct device *dev)
 
 static int pci_pm_runtime_resume(struct device *dev)
 {
+	int rc;
 	struct pci_dev *pci_dev = to_pci_dev(dev);
 	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
@@ -1054,7 +1058,11 @@ static int pci_pm_runtime_resume(struct device *dev)
 	__pci_enable_wake(pci_dev, PCI_D0, true, false);
 	pci_fixup_device(pci_fixup_resume, pci_dev);
 
-	return pm->runtime_resume(dev);
+	rc = pm->runtime_resume(dev);
+
+	pci_dev->runtime_d3cold = false;
+
+	return rc;
 }
 
 static int pci_pm_runtime_idle(struct device *dev)
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 86c63fe..6869009 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -28,6 +28,7 @@
 #include <linux/pci-aspm.h>
 #include <linux/slab.h>
 #include <linux/vgaarb.h>
+#include <linux/pm_runtime.h>
 #include "pci.h"
 
 static int sysfs_initialized;	/* = 0 */
@@ -378,6 +379,31 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
 
 #endif
 
+#if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
+static ssize_t d3cold_allowed_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	unsigned long val;
+
+	if (strict_strtoul(buf, 0, &val) < 0)
+		return -EINVAL;
+
+	pdev->d3cold_allowed = !!val;
+	pm_runtime_resume(dev);
+
+	return count;
+}
+
+static ssize_t d3cold_allowed_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	return sprintf (buf, "%u\n", pdev->d3cold_allowed);
+}
+#endif
+
 struct device_attribute pci_dev_attrs[] = {
 	__ATTR_RO(resource),
 	__ATTR_RO(vendor),
@@ -402,6 +428,9 @@ struct device_attribute pci_dev_attrs[] = {
 	__ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store),
 	__ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store),
 #endif
+#if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
+	__ATTR(d3cold_allowed, 0644, d3cold_allowed_show, d3cold_allowed_store),
+#endif
 	__ATTR_NULL,
 };
 
@@ -1112,7 +1141,7 @@ static struct bin_attribute pcie_config_attr = {
 	.write = pci_write_config,
 };
 
-int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
+int __weak pcibios_add_platform_entries(struct pci_dev *dev)
 {
 	return 0;
 }
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 77cb54a..45299e8 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -110,7 +110,7 @@ unsigned char pci_bus_max_busnr(struct pci_bus* bus)
 	struct list_head *tmp;
 	unsigned char max, n;
 
-	max = bus->subordinate;
+	max = bus->busn_res.end;
 	list_for_each(tmp, &bus->children) {
 		n = pci_bus_max_busnr(pci_bus_b(tmp));
 		if(n > max)
@@ -136,30 +136,6 @@ void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
 EXPORT_SYMBOL_GPL(pci_ioremap_bar);
 #endif
 
-#if 0
-/**
- * pci_max_busnr - returns maximum PCI bus number
- *
- * Returns the highest PCI bus number present in the system global list of
- * PCI buses.
- */
-unsigned char __devinit
-pci_max_busnr(void)
-{
-	struct pci_bus *bus = NULL;
-	unsigned char max, n;
-
-	max = 0;
-	while ((bus = pci_find_next_bus(bus)) != NULL) {
-		n = pci_bus_max_busnr(bus);
-		if(n > max)
-			max = n;
-	}
-	return max;
-}
-
-#endif  /*  0  */
-
 #define PCI_FIND_CAP_TTL	48
 
 static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
@@ -278,6 +254,38 @@ int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
 }
 
 /**
+ * pci_pcie_cap2 - query for devices' PCI_CAP_ID_EXP v2 capability structure
+ * @dev: PCI device to check
+ *
+ * Like pci_pcie_cap() but also checks that the PCIe capability version is
+ * >= 2.  Note that v1 capability structures could be sparse in that not
+ * all register fields were required.  v2 requires the entire structure to
+ * be present size wise, while still allowing for non-implemented registers
+ * to exist but they must be hardwired to 0.
+ *
+ * Due to the differences in the versions of capability structures, one
+ * must be careful not to try and access non-existant registers that may
+ * exist in early versions - v1 - of Express devices.
+ *
+ * Returns the offset of the PCIe capability structure as long as the
+ * capability version is >= 2; otherwise 0 is returned.
+ */
+static int pci_pcie_cap2(struct pci_dev *dev)
+{
+	u16 flags;
+	int pos;
+
+	pos = pci_pcie_cap(dev);
+	if (pos) {
+		pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &flags);
+		if ((flags & PCI_EXP_FLAGS_VERS) < 2)
+			pos = 0;
+	}
+
+	return pos;
+}
+
+/**
  * pci_find_ext_capability - Find an extended capability
  * @dev: PCI device to query
  * @cap: capability code
@@ -329,49 +337,6 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap)
 }
 EXPORT_SYMBOL_GPL(pci_find_ext_capability);
 
-/**
- * pci_bus_find_ext_capability - find an extended capability
- * @bus:   the PCI bus to query
- * @devfn: PCI device to query
- * @cap:   capability code
- *
- * Like pci_find_ext_capability() but works for pci devices that do not have a
- * pci_dev structure set up yet.
- *
- * Returns the address of the requested capability structure within the
- * device's PCI configuration space or 0 in case the device does not
- * support it.
- */
-int pci_bus_find_ext_capability(struct pci_bus *bus, unsigned int devfn,
-				int cap)
-{
-	u32 header;
-	int ttl;
-	int pos = PCI_CFG_SPACE_SIZE;
-
-	/* minimum 8 bytes per capability */
-	ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
-
-	if (!pci_bus_read_config_dword(bus, devfn, pos, &header))
-		return 0;
-	if (header == 0xffffffff || header == 0)
-		return 0;
-
-	while (ttl-- > 0) {
-		if (PCI_EXT_CAP_ID(header) == cap)
-			return pos;
-
-		pos = PCI_EXT_CAP_NEXT(header);
-		if (pos < PCI_CFG_SPACE_SIZE)
-			break;
-
-		if (!pci_bus_read_config_dword(bus, devfn, pos, &header))
-			break;
-	}
-
-	return 0;
-}
-
 static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
 {
 	int rc, ttl = PCI_FIND_CAP_TTL;
@@ -622,7 +587,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
 		dev_info(&dev->dev, "Refused to change power state, "
 			"currently in D%d\n", dev->current_state);
 
-	/* According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT
+	/*
+	 * According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT
 	 * INTERFACE SPECIFICATION, REV. 1.2", a device transitioning
 	 * from D3hot to D0 _may_ perform an internal reset, thereby
 	 * going to "D0 Uninitialized" rather than "D0 Initialized".
@@ -654,6 +620,16 @@ void pci_update_current_state(struct pci_dev *dev, pci_power_t state)
 	if (dev->pm_cap) {
 		u16 pmcsr;
 
+		/*
+		 * Configuration space is not accessible for device in
+		 * D3cold, so just keep or set D3cold for safety
+		 */
+		if (dev->current_state == PCI_D3cold)
+			return;
+		if (state == PCI_D3cold) {
+			dev->current_state = PCI_D3cold;
+			return;
+		}
 		pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
 		dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
 	} else {
@@ -694,8 +670,50 @@ static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
  */
 static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state)
 {
-	if (state == PCI_D0)
+	if (state == PCI_D0) {
 		pci_platform_power_transition(dev, PCI_D0);
+		/*
+		 * Mandatory power management transition delays, see
+		 * PCI Express Base Specification Revision 2.0 Section
+		 * 6.6.1: Conventional Reset.  Do not delay for
+		 * devices powered on/off by corresponding bridge,
+		 * because have already delayed for the bridge.
+		 */
+		if (dev->runtime_d3cold) {
+			msleep(dev->d3cold_delay);
+			/*
+			 * When powering on a bridge from D3cold, the
+			 * whole hierarchy may be powered on into
+			 * D0uninitialized state, resume them to give
+			 * them a chance to suspend again
+			 */
+			pci_wakeup_bus(dev->subordinate);
+		}
+	}
+}
+
+/**
+ * __pci_dev_set_current_state - Set current state of a PCI device
+ * @dev: Device to handle
+ * @data: pointer to state to be set
+ */
+static int __pci_dev_set_current_state(struct pci_dev *dev, void *data)
+{
+	pci_power_t state = *(pci_power_t *)data;
+
+	dev->current_state = state;
+	return 0;
+}
+
+/**
+ * __pci_bus_set_current_state - Walk given bus and set current state of devices
+ * @bus: Top bus of the subtree to walk.
+ * @state: state to be set
+ */
+static void __pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
+{
+	if (bus)
+		pci_walk_bus(bus, __pci_dev_set_current_state, &state);
 }
 
 /**
@@ -707,8 +725,15 @@ static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state)
  */
 int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state)
 {
-	return state >= PCI_D0 ?
-			pci_platform_power_transition(dev, state) : -EINVAL;
+	int ret;
+
+	if (state < PCI_D0)
+		return -EINVAL;
+	ret = pci_platform_power_transition(dev, state);
+	/* Power off the bridge may power off the whole hierarchy */
+	if (!ret && state == PCI_D3cold)
+		__pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(__pci_complete_power_transition);
 
@@ -732,8 +757,8 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 	int error;
 
 	/* bound the state we're entering */
-	if (state > PCI_D3hot)
-		state = PCI_D3hot;
+	if (state > PCI_D3cold)
+		state = PCI_D3cold;
 	else if (state < PCI_D0)
 		state = PCI_D0;
 	else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
@@ -748,10 +773,15 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 
 	/* This device is quirked not to be put into D3, so
 	   don't put it in D3 */
-	if (state == PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3))
+	if (state >= PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3))
 		return 0;
 
-	error = pci_raw_set_power_state(dev, state);
+	/*
+	 * To put device in D3cold, we put device into D3hot in native
+	 * way, then put device into D3cold with platform ops
+	 */
+	error = pci_raw_set_power_state(dev, state > PCI_D3hot ?
+					PCI_D3hot : state);
 
 	if (!__pci_complete_power_transition(dev, state))
 		error = 0;
@@ -822,12 +852,6 @@ EXPORT_SYMBOL(pci_choose_state);
 		((flags & PCI_EXP_FLAGS_VERS) > 1 ||	\
 		 (type == PCI_EXP_TYPE_ROOT_PORT ||	\
 		  type == PCI_EXP_TYPE_RC_EC))
-#define pcie_cap_has_devctl2(type, flags)		\
-		((flags & PCI_EXP_FLAGS_VERS) > 1)
-#define pcie_cap_has_lnkctl2(type, flags)		\
-		((flags & PCI_EXP_FLAGS_VERS) > 1)
-#define pcie_cap_has_sltctl2(type, flags)		\
-		((flags & PCI_EXP_FLAGS_VERS) > 1)
 
 static struct pci_cap_saved_state *pci_find_saved_cap(
 	struct pci_dev *pci_dev, char cap)
@@ -870,13 +894,14 @@ static int pci_save_pcie_state(struct pci_dev *dev)
 		pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
 	if (pcie_cap_has_rtctl(dev->pcie_type, flags))
 		pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
-	if (pcie_cap_has_devctl2(dev->pcie_type, flags))
-		pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]);
-	if (pcie_cap_has_lnkctl2(dev->pcie_type, flags))
-		pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]);
-	if (pcie_cap_has_sltctl2(dev->pcie_type, flags))
-		pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]);
 
+	pos = pci_pcie_cap2(dev);
+	if (!pos)
+		return 0;
+
+	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]);
+	pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]);
+	pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]);
 	return 0;
 }
 
@@ -903,12 +928,14 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
 		pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
 	if (pcie_cap_has_rtctl(dev->pcie_type, flags))
 		pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
-	if (pcie_cap_has_devctl2(dev->pcie_type, flags))
-		pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]);
-	if (pcie_cap_has_lnkctl2(dev->pcie_type, flags))
-		pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]);
-	if (pcie_cap_has_sltctl2(dev->pcie_type, flags))
-		pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]);
+
+	pos = pci_pcie_cap2(dev);
+	if (!pos)
+		return;
+
+	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]);
+	pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]);
+	pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]);
 }
 
 
@@ -1349,7 +1376,7 @@ void pcim_pin_device(struct pci_dev *pdev)
  * is the default implementation. Architecture implementations can
  * override this.
  */
-void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
+void __weak pcibios_disable_device (struct pci_dev *dev) {}
 
 static void do_pci_disable_device(struct pci_dev *dev)
 {
@@ -1413,8 +1440,8 @@ pci_disable_device(struct pci_dev *dev)
  * Sets the PCIe reset state for the device. This is the default
  * implementation. Architecture implementations can override this.
  */
-int __attribute__ ((weak)) pcibios_set_pcie_reset_state(struct pci_dev *dev,
-							enum pcie_reset_state state)
+int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev,
+					enum pcie_reset_state state)
 {
 	return -EINVAL;
 }
@@ -1498,6 +1525,28 @@ void pci_pme_wakeup_bus(struct pci_bus *bus)
 }
 
 /**
+ * pci_wakeup - Wake up a PCI device
+ * @dev: Device to handle.
+ * @ign: ignored parameter
+ */
+static int pci_wakeup(struct pci_dev *pci_dev, void *ign)
+{
+	pci_wakeup_event(pci_dev);
+	pm_request_resume(&pci_dev->dev);
+	return 0;
+}
+
+/**
+ * pci_wakeup_bus - Walk given bus and wake up devices on it
+ * @bus: Top bus of the subtree to walk.
+ */
+void pci_wakeup_bus(struct pci_bus *bus)
+{
+	if (bus)
+		pci_walk_bus(bus, pci_wakeup, NULL);
+}
+
+/**
  * pci_pme_capable - check the capability of PCI device to generate PME#
  * @dev: PCI device to handle.
  * @state: PCI state from which device will issue PME#.
@@ -1518,6 +1567,16 @@ static void pci_pme_list_scan(struct work_struct *work)
 	if (!list_empty(&pci_pme_list)) {
 		list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
 			if (pme_dev->dev->pme_poll) {
+				struct pci_dev *bridge;
+
+				bridge = pme_dev->dev->bus->self;
+				/*
+				 * If bridge is in low power state, the
+				 * configuration space of subordinate devices
+				 * may be not accessible
+				 */
+				if (bridge && bridge->current_state != PCI_D0)
+					continue;
 				pci_pme_wakeup(pme_dev->dev, NULL);
 			} else {
 				list_del(&pme_dev->list);
@@ -1744,6 +1803,10 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
 	if (target_state == PCI_POWER_ERROR)
 		return -EIO;
 
+	/* D3cold during system suspend/hibernate is not supported */
+	if (target_state > PCI_D3hot)
+		target_state = PCI_D3hot;
+
 	/* Some devices mustn't be in D3 during system sleep */
 	if (target_state == PCI_D3hot &&
 			(dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP))
@@ -1786,12 +1849,16 @@ int pci_finish_runtime_suspend(struct pci_dev *dev)
 	if (target_state == PCI_POWER_ERROR)
 		return -EIO;
 
+	dev->runtime_d3cold = target_state == PCI_D3cold;
+
 	__pci_enable_wake(dev, target_state, true, pci_dev_run_wake(dev));
 
 	error = pci_set_power_state(dev, target_state);
 
-	if (error)
+	if (error) {
 		__pci_enable_wake(dev, target_state, true, false);
+		dev->runtime_d3cold = false;
+	}
 
 	return error;
 }
@@ -1861,6 +1928,7 @@ void pci_pm_init(struct pci_dev *dev)
 
 	dev->pm_cap = pm;
 	dev->d3_delay = PCI_PM_D3_WAIT;
+	dev->d3cold_delay = PCI_PM_D3COLD_WAIT;
 
 	dev->d1_support = false;
 	dev->d2_support = false;
@@ -1988,7 +2056,7 @@ void pci_enable_ari(struct pci_dev *dev)
 {
 	int pos;
 	u32 cap;
-	u16 flags, ctrl;
+	u16 ctrl;
 	struct pci_dev *bridge;
 
 	if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
@@ -1999,18 +2067,14 @@ void pci_enable_ari(struct pci_dev *dev)
 		return;
 
 	bridge = dev->bus->self;
-	if (!bridge || !pci_is_pcie(bridge))
+	if (!bridge)
 		return;
 
-	pos = pci_pcie_cap(bridge);
+	/* ARI is a PCIe cap v2 feature */
+	pos = pci_pcie_cap2(bridge);
 	if (!pos)
 		return;
 
-	/* ARI is a PCIe v2 feature */
-	pci_read_config_word(bridge, pos + PCI_EXP_FLAGS, &flags);
-	if ((flags & PCI_EXP_FLAGS_VERS) < 2)
-		return;
-
 	pci_read_config_dword(bridge, pos + PCI_EXP_DEVCAP2, &cap);
 	if (!(cap & PCI_EXP_DEVCAP2_ARI))
 		return;
@@ -2023,7 +2087,7 @@ void pci_enable_ari(struct pci_dev *dev)
 }
 
 /**
- * pci_enable_ido - enable ID-based ordering on a device
+ * pci_enable_ido - enable ID-based Ordering on a device
  * @dev: the PCI device
  * @type: which types of IDO to enable
  *
@@ -2036,7 +2100,8 @@ void pci_enable_ido(struct pci_dev *dev, unsigned long type)
 	int pos;
 	u16 ctrl;
 
-	pos = pci_pcie_cap(dev);
+	/* ID-based Ordering is a PCIe cap v2 feature */
+	pos = pci_pcie_cap2(dev);
 	if (!pos)
 		return;
 
@@ -2059,10 +2124,8 @@ void pci_disable_ido(struct pci_dev *dev, unsigned long type)
 	int pos;
 	u16 ctrl;
 
-	if (!pci_is_pcie(dev))
-		return;
-
-	pos = pci_pcie_cap(dev);
+	/* ID-based Ordering is a PCIe cap v2 feature */
+	pos = pci_pcie_cap2(dev);
 	if (!pos)
 		return;
 
@@ -2101,10 +2164,8 @@ int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type type)
 	u16 ctrl;
 	int ret;
 
-	if (!pci_is_pcie(dev))
-		return -ENOTSUPP;
-
-	pos = pci_pcie_cap(dev);
+	/* OBFF is a PCIe cap v2 feature */
+	pos = pci_pcie_cap2(dev);
 	if (!pos)
 		return -ENOTSUPP;
 
@@ -2113,7 +2174,7 @@ int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type type)
 		return -ENOTSUPP; /* no OBFF support at all */
 
 	/* Make sure the topology supports OBFF as well */
-	if (dev->bus) {
+	if (dev->bus->self) {
 		ret = pci_enable_obff(dev->bus->self, type);
 		if (ret)
 			return ret;
@@ -2154,10 +2215,8 @@ void pci_disable_obff(struct pci_dev *dev)
 	int pos;
 	u16 ctrl;
 
-	if (!pci_is_pcie(dev))
-		return;
-
-	pos = pci_pcie_cap(dev);
+	/* OBFF is a PCIe cap v2 feature */
+	pos = pci_pcie_cap2(dev);
 	if (!pos)
 		return;
 
@@ -2174,15 +2233,13 @@ EXPORT_SYMBOL(pci_disable_obff);
  * RETURNS:
  * True if @dev supports latency tolerance reporting, false otherwise.
  */
-bool pci_ltr_supported(struct pci_dev *dev)
+static bool pci_ltr_supported(struct pci_dev *dev)
 {
 	int pos;
 	u32 cap;
 
-	if (!pci_is_pcie(dev))
-		return false;
-
-	pos = pci_pcie_cap(dev);
+	/* LTR is a PCIe cap v2 feature */
+	pos = pci_pcie_cap2(dev);
 	if (!pos)
 		return false;
 
@@ -2190,7 +2247,6 @@ bool pci_ltr_supported(struct pci_dev *dev)
 
 	return cap & PCI_EXP_DEVCAP2_LTR;
 }
-EXPORT_SYMBOL(pci_ltr_supported);
 
 /**
  * pci_enable_ltr - enable latency tolerance reporting
@@ -2211,7 +2267,8 @@ int pci_enable_ltr(struct pci_dev *dev)
 	if (!pci_ltr_supported(dev))
 		return -ENOTSUPP;
 
-	pos = pci_pcie_cap(dev);
+	/* LTR is a PCIe cap v2 feature */
+	pos = pci_pcie_cap2(dev);
 	if (!pos)
 		return -ENOTSUPP;
 
@@ -2220,7 +2277,7 @@ int pci_enable_ltr(struct pci_dev *dev)
 		return -EINVAL;
 
 	/* Enable upstream ports first */
-	if (dev->bus) {
+	if (dev->bus->self) {
 		ret = pci_enable_ltr(dev->bus->self);
 		if (ret)
 			return ret;
@@ -2246,7 +2303,8 @@ void pci_disable_ltr(struct pci_dev *dev)
 	if (!pci_ltr_supported(dev))
 		return;
 
-	pos = pci_pcie_cap(dev);
+	/* LTR is a PCIe cap v2 feature */
+	pos = pci_pcie_cap2(dev);
 	if (!pos)
 		return;
 
@@ -2365,6 +2423,75 @@ void pci_enable_acs(struct pci_dev *dev)
 }
 
 /**
+ * pci_acs_enabled - test ACS against required flags for a given device
+ * @pdev: device to test
+ * @acs_flags: required PCI ACS flags
+ *
+ * Return true if the device supports the provided flags.  Automatically
+ * filters out flags that are not implemented on multifunction devices.
+ */
+bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
+{
+	int pos, ret;
+	u16 ctrl;
+
+	ret = pci_dev_specific_acs_enabled(pdev, acs_flags);
+	if (ret >= 0)
+		return ret > 0;
+
+	if (!pci_is_pcie(pdev))
+		return false;
+
+	/* Filter out flags not applicable to multifunction */
+	if (pdev->multifunction)
+		acs_flags &= (PCI_ACS_RR | PCI_ACS_CR |
+			      PCI_ACS_EC | PCI_ACS_DT);
+
+	if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM ||
+	    pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
+	    pdev->multifunction) {
+		pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
+		if (!pos)
+			return false;
+
+		pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
+		if ((ctrl & acs_flags) != acs_flags)
+			return false;
+	}
+
+	return true;
+}
+
+/**
+ * pci_acs_path_enable - test ACS flags from start to end in a hierarchy
+ * @start: starting downstream device
+ * @end: ending upstream device or NULL to search to the root bus
+ * @acs_flags: required flags
+ *
+ * Walk up a device tree from start to end testing PCI ACS support.  If
+ * any step along the way does not support the required flags, return false.
+ */
+bool pci_acs_path_enabled(struct pci_dev *start,
+			  struct pci_dev *end, u16 acs_flags)
+{
+	struct pci_dev *pdev, *parent = start;
+
+	do {
+		pdev = parent;
+
+		if (!pci_acs_enabled(pdev, acs_flags))
+			return false;
+
+		if (pci_is_root_bus(pdev->bus))
+			return (end == NULL);
+
+		parent = pdev->bus->self;
+	} while (pdev != end);
+
+	return true;
+}
+
+/**
  * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
  * @dev: the PCI device
  * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)
@@ -2881,6 +3008,9 @@ bool pci_intx_mask_supported(struct pci_dev *dev)
 	bool mask_supported = false;
 	u16 orig, new;
 
+	if (dev->broken_intx_masking)
+		return false;
+
 	pci_cfg_access_lock(dev);
 
 	pci_read_config_word(dev, PCI_COMMAND, &orig);
@@ -3400,8 +3530,7 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc)
 
 	o = (cmd & PCI_X_CMD_MAX_READ) >> 2;
 	if (o != v) {
-		if (v > o && dev->bus &&
-		   (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MMRBC))
+		if (v > o && (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MMRBC))
 			return -EIO;
 
 		cmd &= ~PCI_X_CMD_MAX_READ;
@@ -3856,7 +3985,7 @@ static void __devinit pci_no_domains(void)
  * greater than 0xff). This is the default implementation. Architecture
  * implementations can override this.
  */
-int __attribute__ ((weak)) pci_ext_cfg_avail(struct pci_dev *dev)
+int __weak pci_ext_cfg_avail(struct pci_dev *dev)
 {
 	return 1;
 }
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index e494347..ec1512d 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -70,6 +70,7 @@ extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
 extern void pci_disable_enabled_device(struct pci_dev *dev);
 extern int pci_finish_runtime_suspend(struct pci_dev *dev);
 extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
+extern void pci_wakeup_bus(struct pci_bus *bus);
 extern void pci_pm_init(struct pci_dev *dev);
 extern void platform_pci_wakeup_init(struct pci_dev *dev);
 extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
@@ -86,13 +87,6 @@ static inline bool pci_is_bridge(struct pci_dev *pci_dev)
 	return !!(pci_dev->subordinate);
 }
 
-extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
-extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
-extern int pci_user_read_config_dword(struct pci_dev *dev, int where, u32 *val);
-extern int pci_user_write_config_byte(struct pci_dev *dev, int where, u8 val);
-extern int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val);
-extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val);
-
 struct pci_vpd_ops {
 	ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
 	ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
@@ -124,7 +118,7 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; }
 #endif
 
 /* Functions for PCI Hotplug drivers to use */
-extern unsigned int pci_do_scan_bus(struct pci_bus *bus);
+int pci_hp_add_bridge(struct pci_dev *dev);
 
 #ifdef HAVE_PCI_LEGACY
 extern void pci_create_legacy_files(struct pci_bus *bus);
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
index 275bf15..124f20f 100644
--- a/drivers/pci/pcie/aer/aerdrv_acpi.c
+++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
@@ -59,7 +59,7 @@ static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data)
 
 	p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
 	if (p->flags & ACPI_HEST_GLOBAL) {
-		if ((info->pci_dev->is_pcie &&
+		if ((pci_is_pcie(info->pci_dev) &&
 		     info->pci_dev->pcie_type == pcie_type) || bridge)
 			ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
 	} else
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index e0610bd..3a7eefc 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <linux/init.h>
 #include <linux/pcieport_if.h>
 #include <linux/aer.h>
@@ -99,6 +100,51 @@ static int pcie_port_resume_noirq(struct device *dev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+struct d3cold_info {
+	bool no_d3cold;
+	unsigned int d3cold_delay;
+};
+
+static int pci_dev_d3cold_info(struct pci_dev *pdev, void *data)
+{
+	struct d3cold_info *info = data;
+
+	info->d3cold_delay = max_t(unsigned int, pdev->d3cold_delay,
+				   info->d3cold_delay);
+	if (pdev->no_d3cold)
+		info->no_d3cold = true;
+	return 0;
+}
+
+static int pcie_port_runtime_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct d3cold_info d3cold_info = {
+		.no_d3cold	= false,
+		.d3cold_delay	= PCI_PM_D3_WAIT,
+	};
+
+	/*
+	 * If any subordinate device disable D3cold, we should not put
+	 * the port into D3cold.  The D3cold delay of port should be
+	 * the max of that of all subordinate devices.
+	 */
+	pci_walk_bus(pdev->subordinate, pci_dev_d3cold_info, &d3cold_info);
+	pdev->no_d3cold = d3cold_info.no_d3cold;
+	pdev->d3cold_delay = d3cold_info.d3cold_delay;
+	return 0;
+}
+
+static int pcie_port_runtime_resume(struct device *dev)
+{
+	return 0;
+}
+#else
+#define pcie_port_runtime_suspend	NULL
+#define pcie_port_runtime_resume	NULL
+#endif
+
 static const struct dev_pm_ops pcie_portdrv_pm_ops = {
 	.suspend	= pcie_port_device_suspend,
 	.resume		= pcie_port_device_resume,
@@ -107,6 +153,8 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
 	.poweroff	= pcie_port_device_suspend,
 	.restore	= pcie_port_device_resume,
 	.resume_noirq	= pcie_port_resume_noirq,
+	.runtime_suspend = pcie_port_runtime_suspend,
+	.runtime_resume = pcie_port_runtime_resume,
 };
 
 #define PCIE_PORTDRV_PM_OPS	(&pcie_portdrv_pm_ops)
@@ -117,6 +165,14 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
 #endif /* !PM */
 
 /*
+ * PCIe port runtime suspend is broken for some chipsets, so use a
+ * black list to disable runtime PM for these chipsets.
+ */
+static const struct pci_device_id port_runtime_pm_black_list[] = {
+	{ /* end: all zeroes */ }
+};
+
+/*
  * pcie_portdrv_probe - Probe PCI-Express port devices
  * @dev: PCI-Express port device being probed
  *
@@ -144,12 +200,16 @@ static int __devinit pcie_portdrv_probe(struct pci_dev *dev,
 		return status;
 
 	pci_save_state(dev);
+	if (!pci_match_id(port_runtime_pm_black_list, dev))
+		pm_runtime_put_noidle(&dev->dev);
 
 	return 0;
 }
 
 static void pcie_portdrv_remove(struct pci_dev *dev)
 {
+	if (!pci_match_id(port_runtime_pm_black_list, dev))
+		pm_runtime_get_noresume(&dev->dev);
 	pcie_port_device_remove(dev);
 	pci_disable_device(dev);
 }
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 658ac97..cd06c84 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -16,10 +16,47 @@
 #define CARDBUS_LATENCY_TIMER	176	/* secondary latency timer */
 #define CARDBUS_RESERVE_BUSNR	3
 
+struct resource busn_resource = {
+	.name	= "PCI busn",
+	.start	= 0,
+	.end	= 255,
+	.flags	= IORESOURCE_BUS,
+};
+
 /* Ugh.  Need to stop exporting this to modules. */
 LIST_HEAD(pci_root_buses);
 EXPORT_SYMBOL(pci_root_buses);
 
+static LIST_HEAD(pci_domain_busn_res_list);
+
+struct pci_domain_busn_res {
+	struct list_head list;
+	struct resource res;
+	int domain_nr;
+};
+
+static struct resource *get_pci_domain_busn_res(int domain_nr)
+{
+	struct pci_domain_busn_res *r;
+
+	list_for_each_entry(r, &pci_domain_busn_res_list, list)
+		if (r->domain_nr == domain_nr)
+			return &r->res;
+
+	r = kzalloc(sizeof(*r), GFP_KERNEL);
+	if (!r)
+		return NULL;
+
+	r->domain_nr = domain_nr;
+	r->res.start = 0;
+	r->res.end = 0xff;
+	r->res.flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED;
+
+	list_add_tail(&r->list, &pci_domain_busn_res_list);
+
+	return &r->res;
+}
+
 static int find_anything(struct device *dev, void *data)
 {
 	return 1;
@@ -281,10 +318,11 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
 
 	if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
 		u16 io_base_hi, io_limit_hi;
+
 		pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
 		pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
-		base |= (io_base_hi << 16);
-		limit |= (io_limit_hi << 16);
+		base |= ((unsigned long) io_base_hi << 16);
+		limit |= ((unsigned long) io_limit_hi << 16);
 	}
 
 	if (base && base <= limit) {
@@ -312,8 +350,8 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
 	res = child->resource[1];
 	pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
 	pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
-	base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
-	limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
+	base = ((unsigned long) mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
+	limit = ((unsigned long) mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
 	if (base && base <= limit) {
 		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
 		region.start = base;
@@ -334,11 +372,12 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
 	res = child->resource[2];
 	pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
 	pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
-	base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
-	limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
+	base = ((unsigned long) mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
+	limit = ((unsigned long) mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
 
 	if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
 		u32 mem_base_hi, mem_limit_hi;
+
 		pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
 		pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
 
@@ -349,8 +388,8 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
 		 */
 		if (mem_base_hi <= mem_limit_hi) {
 #if BITS_PER_LONG == 64
-			base |= ((long) mem_base_hi) << 32;
-			limit |= ((long) mem_limit_hi) << 32;
+			base |= ((unsigned long) mem_base_hi) << 32;
+			limit |= ((unsigned long) mem_limit_hi) << 32;
 #else
 			if (mem_base_hi || mem_limit_hi) {
 				dev_err(&dev->dev, "can't handle 64-bit "
@@ -381,8 +420,8 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
 	if (pci_is_root_bus(child))	/* It's a host bus, nothing to read */
 		return;
 
-	dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n",
-		 child->secondary, child->subordinate,
+	dev_info(&dev->dev, "PCI bridge to %pR%s\n",
+		 &child->busn_res,
 		 dev->transparent ? " (subtractive decode)" : "");
 
 	pci_bus_remove_resources(child);
@@ -599,9 +638,9 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
 	 * Set up the primary, secondary and subordinate
 	 * bus numbers.
 	 */
-	child->number = child->secondary = busnr;
-	child->primary = parent->secondary;
-	child->subordinate = 0xff;
+	child->number = child->busn_res.start = busnr;
+	child->primary = parent->busn_res.start;
+	child->busn_res.end = 0xff;
 
 	if (!bridge)
 		return child;
@@ -643,8 +682,8 @@ static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
 	if (!pcibios_assign_all_busses())
 		return;
 
-	while (parent->parent && parent->subordinate < max) {
-		parent->subordinate = max;
+	while (parent->parent && parent->busn_res.end < max) {
+		parent->busn_res.end = max;
 		pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max);
 		parent = parent->parent;
 	}
@@ -718,15 +757,15 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
 			if (!child)
 				goto out;
 			child->primary = primary;
-			child->subordinate = subordinate;
+			pci_bus_insert_busn_res(child, secondary, subordinate);
 			child->bridge_ctl = bctl;
 		}
 
 		cmax = pci_scan_child_bus(child);
 		if (cmax > max)
 			max = cmax;
-		if (child->subordinate > max)
-			max = child->subordinate;
+		if (child->busn_res.end > max)
+			max = child->busn_res.end;
 	} else {
 		/*
 		 * We need to assign a number to this bus which we always
@@ -756,11 +795,12 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
 			child = pci_add_new_bus(bus, dev, ++max);
 			if (!child)
 				goto out;
+			pci_bus_insert_busn_res(child, max, 0xff);
 		}
 		buses = (buses & 0xff000000)
 		      | ((unsigned int)(child->primary)     <<  0)
-		      | ((unsigned int)(child->secondary)   <<  8)
-		      | ((unsigned int)(child->subordinate) << 16);
+		      | ((unsigned int)(child->busn_res.start)   <<  8)
+		      | ((unsigned int)(child->busn_res.end) << 16);
 
 		/*
 		 * yenta.c forces a secondary latency timer of 176.
@@ -805,8 +845,8 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
 					break;
 				while (parent->parent) {
 					if ((!pcibios_assign_all_busses()) &&
-					    (parent->subordinate > max) &&
-					    (parent->subordinate <= max+i)) {
+					    (parent->busn_res.end > max) &&
+					    (parent->busn_res.end <= max+i)) {
 						j = 1;
 					}
 					parent = parent->parent;
@@ -827,7 +867,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
 		/*
 		 * Set the subordinate bus number to its real value.
 		 */
-		child->subordinate = max;
+		pci_bus_update_busn_res_end(child, max);
 		pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
 	}
 
@@ -837,19 +877,19 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
 
 	/* Has only triggered on CardBus, fixup is in yenta_socket */
 	while (bus->parent) {
-		if ((child->subordinate > bus->subordinate) ||
-		    (child->number > bus->subordinate) ||
+		if ((child->busn_res.end > bus->busn_res.end) ||
+		    (child->number > bus->busn_res.end) ||
 		    (child->number < bus->number) ||
-		    (child->subordinate < bus->number)) {
-			dev_info(&child->dev, "[bus %02x-%02x] %s "
-				"hidden behind%s bridge %s [bus %02x-%02x]\n",
-				child->number, child->subordinate,
-				(bus->number > child->subordinate &&
-				 bus->subordinate < child->number) ?
+		    (child->busn_res.end < bus->number)) {
+			dev_info(&child->dev, "%pR %s "
+				"hidden behind%s bridge %s %pR\n",
+				&child->busn_res,
+				(bus->number > child->busn_res.end &&
+				 bus->busn_res.end < child->number) ?
 					"wholly" : "partially",
 				bus->self->transparent ? " transparent" : "",
 				dev_name(&bus->dev),
-				bus->number, bus->subordinate);
+				&bus->busn_res);
 		}
 		bus = bus->parent;
 	}
@@ -1548,7 +1588,7 @@ EXPORT_SYMBOL_GPL(pcie_bus_configure_settings);
 
 unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
 {
-	unsigned int devfn, pass, max = bus->secondary;
+	unsigned int devfn, pass, max = bus->busn_res.start;
 	struct pci_dev *dev;
 
 	dev_dbg(&bus->dev, "scanning bus\n");
@@ -1642,7 +1682,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 	/* Create legacy_io and legacy_mem files for this bus */
 	pci_create_legacy_files(b);
 
-	b->number = b->secondary = bus;
+	b->number = b->busn_res.start = bus;
 
 	if (parent)
 		dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
@@ -1654,7 +1694,10 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 		list_move_tail(&window->list, &bridge->windows);
 		res = window->res;
 		offset = window->offset;
-		pci_bus_add_resource(b, res, 0);
+		if (res->flags & IORESOURCE_BUS)
+			pci_bus_insert_busn_res(b, bus, res->end);
+		else
+			pci_bus_add_resource(b, res, 0);
 		if (offset) {
 			if (resource_type(res) == IORESOURCE_IO)
 				fmt = " (bus address [%#06llx-%#06llx])";
@@ -1684,16 +1727,104 @@ err_out:
 	return NULL;
 }
 
+int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
+{
+	struct resource *res = &b->busn_res;
+	struct resource *parent_res, *conflict;
+
+	res->start = bus;
+	res->end = bus_max;
+	res->flags = IORESOURCE_BUS;
+
+	if (!pci_is_root_bus(b))
+		parent_res = &b->parent->busn_res;
+	else {
+		parent_res = get_pci_domain_busn_res(pci_domain_nr(b));
+		res->flags |= IORESOURCE_PCI_FIXED;
+	}
+
+	conflict = insert_resource_conflict(parent_res, res);
+
+	if (conflict)
+		dev_printk(KERN_DEBUG, &b->dev,
+			   "busn_res: can not insert %pR under %s%pR (conflicts with %s %pR)\n",
+			    res, pci_is_root_bus(b) ? "domain " : "",
+			    parent_res, conflict->name, conflict);
+	else
+		dev_printk(KERN_DEBUG, &b->dev,
+			   "busn_res: %pR is inserted under %s%pR\n",
+			   res, pci_is_root_bus(b) ? "domain " : "",
+			   parent_res);
+
+	return conflict == NULL;
+}
+
+int pci_bus_update_busn_res_end(struct pci_bus *b, int bus_max)
+{
+	struct resource *res = &b->busn_res;
+	struct resource old_res = *res;
+	resource_size_t size;
+	int ret;
+
+	if (res->start > bus_max)
+		return -EINVAL;
+
+	size = bus_max - res->start + 1;
+	ret = adjust_resource(res, res->start, size);
+	dev_printk(KERN_DEBUG, &b->dev,
+			"busn_res: %pR end %s updated to %02x\n",
+			&old_res, ret ? "can not be" : "is", bus_max);
+
+	if (!ret && !res->parent)
+		pci_bus_insert_busn_res(b, res->start, res->end);
+
+	return ret;
+}
+
+void pci_bus_release_busn_res(struct pci_bus *b)
+{
+	struct resource *res = &b->busn_res;
+	int ret;
+
+	if (!res->flags || !res->parent)
+		return;
+
+	ret = release_resource(res);
+	dev_printk(KERN_DEBUG, &b->dev,
+			"busn_res: %pR %s released\n",
+			res, ret ? "can not be" : "is");
+}
+
 struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
 		struct pci_ops *ops, void *sysdata, struct list_head *resources)
 {
+	struct pci_host_bridge_window *window;
+	bool found = false;
 	struct pci_bus *b;
+	int max;
+
+	list_for_each_entry(window, resources, list)
+		if (window->res->flags & IORESOURCE_BUS) {
+			found = true;
+			break;
+		}
 
 	b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
 	if (!b)
 		return NULL;
 
-	b->subordinate = pci_scan_child_bus(b);
+	if (!found) {
+		dev_info(&b->dev,
+		 "No busn resource found for root bus, will use [bus %02x-ff]\n",
+			bus);
+		pci_bus_insert_busn_res(b, bus, 255);
+	}
+
+	max = pci_scan_child_bus(b);
+
+	if (!found)
+		pci_bus_update_busn_res_end(b, max);
+
 	pci_bus_add_devices(b);
 	return b;
 }
@@ -1708,9 +1839,10 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,
 
 	pci_add_resource(&resources, &ioport_resource);
 	pci_add_resource(&resources, &iomem_resource);
+	pci_add_resource(&resources, &busn_resource);
 	b = pci_create_root_bus(parent, bus, ops, sysdata, &resources);
 	if (b)
-		b->subordinate = pci_scan_child_bus(b);
+		pci_scan_child_bus(b);
 	else
 		pci_free_resource_list(&resources);
 	return b;
@@ -1725,9 +1857,10 @@ struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,
 
 	pci_add_resource(&resources, &ioport_resource);
 	pci_add_resource(&resources, &iomem_resource);
+	pci_add_resource(&resources, &busn_resource);
 	b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
 	if (b) {
-		b->subordinate = pci_scan_child_bus(b);
+		pci_scan_child_bus(b);
 		pci_bus_add_devices(b);
 	} else {
 		pci_free_resource_list(&resources);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 194b243a..4ebc865 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -253,7 +253,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C576,	quirk_vsfx)
  *	workaround applied too
  *	[Info kindly provided by ALi]
  */	
-static void __init quirk_alimagik(struct pci_dev *dev)
+static void __devinit quirk_alimagik(struct pci_dev *dev)
 {
 	if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) {
 		dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
@@ -789,7 +789,7 @@ static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7410,	quirk_amd_ioapic);
 
-static void __init quirk_ioapic_rmw(struct pci_dev *dev)
+static void __devinit quirk_ioapic_rmw(struct pci_dev *dev)
 {
 	if (dev->devfn == 0 && dev->bus->number == 0)
 		sis_apic_bug = 1;
@@ -801,7 +801,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_ANY_ID,			quirk_ioapic_rmw);
  * Some settings of MMRBC can lead to data corruption so block changes.
  * See AMD 8131 HyperTransport PCI-X Tunnel Revision Guide
  */
-static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
+static void __devinit quirk_amd_8131_mmrbc(struct pci_dev *dev)
 {
 	if (dev->subordinate && dev->revision <= 0x12) {
 		dev_info(&dev->dev, "AMD8131 rev %x detected; "
@@ -1082,7 +1082,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB
 /*
  *	Intel 82801CAM ICH3-M datasheet says IDE modes must be the same
  */
-static void __init quirk_ide_samemode(struct pci_dev *pdev)
+static void __devinit quirk_ide_samemode(struct pci_dev *pdev)
 {
 	u8 prog;
 
@@ -1121,7 +1121,7 @@ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID,
 /* This was originally an Alpha specific thing, but it really fits here.
  * The i82375 PCI/EISA bridge appears as non-classified. Fix that.
  */
-static void __init quirk_eisa_bridge(struct pci_dev *dev)
+static void __devinit quirk_eisa_bridge(struct pci_dev *dev)
 {
 	dev->class = PCI_CLASS_BRIDGE_EISA << 8;
 }
@@ -1155,7 +1155,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82375,	quirk_e
  */
 static int asus_hides_smbus;
 
-static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
+static void __devinit asus_hides_smbus_hostbridge(struct pci_dev *dev)
 {
 	if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) {
 		if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB)
@@ -1538,7 +1538,7 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB3
 #endif
 
 #ifdef CONFIG_X86_IO_APIC
-static void __init quirk_alder_ioapic(struct pci_dev *pdev)
+static void __devinit quirk_alder_ioapic(struct pci_dev *pdev)
 {
 	int i;
 
@@ -1777,7 +1777,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD,   PCI_DEVICE_ID_AMD_8111_SMBUS, 	qui
  * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
  * Re-allocate the region if needed...
  */
-static void __init quirk_tc86c001_ide(struct pci_dev *dev)
+static void __devinit quirk_tc86c001_ide(struct pci_dev *dev)
 {
 	struct resource *r = &dev->resource[0];
 
@@ -2143,9 +2143,9 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB,
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB,
 			quirk_unhide_mch_dev6);
 
-#ifdef CONFIG_TILE
+#ifdef CONFIG_TILEPRO
 /*
- * The Tilera TILEmpower platform needs to set the link speed
+ * The Tilera TILEmpower tilepro platform needs to set the link speed
  * to 2.5GT(Giga-Transfers)/s (Gen 1). The default link speed
  * setting is 5GT/s (Gen 2). 0x98 is the Link Control2 PCIe
  * capability register of the PEX8624 PCIe switch. The switch
@@ -2160,7 +2160,7 @@ static void __devinit quirk_tile_plx_gen1(struct pci_dev *dev)
 	}
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8624, quirk_tile_plx_gen1);
-#endif /* CONFIG_TILE */
+#endif /* CONFIG_TILEPRO */
 
 #ifdef CONFIG_PCI_MSI
 /* Some chipsets do not support MSI. We cannot easily rely on setting
@@ -2169,7 +2169,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8624, quirk_tile_plx_gen1);
  * aware of it.  Instead of setting the flag on all busses in the
  * machine, simply disable MSI globally.
  */
-static void __init quirk_disable_all_msi(struct pci_dev *dev)
+static void __devinit quirk_disable_all_msi(struct pci_dev *dev)
 {
 	pci_no_msi();
 	dev_warn(&dev->dev, "MSI quirk detected; MSI disabled\n");
@@ -2955,6 +2955,20 @@ static void __devinit asus_ehci_no_d3(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3);
 
+/*
+ * Some devices may pass our check in pci_intx_mask_supported if
+ * PCI_COMMAND_INTX_DISABLE works though they actually do not properly
+ * support this feature.
+ */
+static void __devinit quirk_broken_intx_masking(struct pci_dev *dev)
+{
+	dev->broken_intx_masking = 1;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, 0x0030,
+			 quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_HEADER(0x1814, 0x0601, /* Ralink RT2800 802.11n PCI */
+			 quirk_broken_intx_masking);
+
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
 			  struct pci_fixup *end)
 {
@@ -3205,3 +3219,87 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe)
 
 	return -ENOTTY;
 }
+
+static struct pci_dev *pci_func_0_dma_source(struct pci_dev *dev)
+{
+	if (!PCI_FUNC(dev->devfn))
+		return pci_dev_get(dev);
+
+	return pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
+}
+
+static const struct pci_dev_dma_source {
+	u16 vendor;
+	u16 device;
+	struct pci_dev *(*dma_source)(struct pci_dev *dev);
+} pci_dev_dma_source[] = {
+	/*
+	 * https://bugzilla.redhat.com/show_bug.cgi?id=605888
+	 *
+	 * Some Ricoh devices use the function 0 source ID for DMA on
+	 * other functions of a multifunction device.  The DMA devices
+	 * is therefore function 0, which will have implications of the
+	 * iommu grouping of these devices.
+	 */
+	{ PCI_VENDOR_ID_RICOH, 0xe822, pci_func_0_dma_source },
+	{ PCI_VENDOR_ID_RICOH, 0xe230, pci_func_0_dma_source },
+	{ PCI_VENDOR_ID_RICOH, 0xe832, pci_func_0_dma_source },
+	{ PCI_VENDOR_ID_RICOH, 0xe476, pci_func_0_dma_source },
+	{ 0 }
+};
+
+/*
+ * IOMMUs with isolation capabilities need to be programmed with the
+ * correct source ID of a device.  In most cases, the source ID matches
+ * the device doing the DMA, but sometimes hardware is broken and will
+ * tag the DMA as being sourced from a different device.  This function
+ * allows that translation.  Note that the reference count of the
+ * returned device is incremented on all paths.
+ */
+struct pci_dev *pci_get_dma_source(struct pci_dev *dev)
+{
+	const struct pci_dev_dma_source *i;
+
+	for (i = pci_dev_dma_source; i->dma_source; i++) {
+		if ((i->vendor == dev->vendor ||
+		     i->vendor == (u16)PCI_ANY_ID) &&
+		    (i->device == dev->device ||
+		     i->device == (u16)PCI_ANY_ID))
+			return i->dma_source(dev);
+	}
+
+	return pci_dev_get(dev);
+}
+
+static const struct pci_dev_acs_enabled {
+	u16 vendor;
+	u16 device;
+	int (*acs_enabled)(struct pci_dev *dev, u16 acs_flags);
+} pci_dev_acs_enabled[] = {
+	{ 0 }
+};
+
+int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
+{
+	const struct pci_dev_acs_enabled *i;
+	int ret;
+
+	/*
+	 * Allow devices that do not expose standard PCIe ACS capabilities
+	 * or control to indicate their support here.  Multi-function express
+	 * devices which do not allow internal peer-to-peer between functions,
+	 * but do not implement PCIe ACS may wish to return true here.
+	 */
+	for (i = pci_dev_acs_enabled; i->acs_enabled; i++) {
+		if ((i->vendor == dev->vendor ||
+		     i->vendor == (u16)PCI_ANY_ID) &&
+		    (i->device == dev->device ||
+		     i->device == (u16)PCI_ANY_ID)) {
+			ret = i->acs_enabled(dev, acs_flags);
+			if (ret >= 0)
+				return ret;
+		}
+	}
+
+	return -ENOTTY;
+}
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index fd77e2b..04a4861 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -68,6 +68,7 @@ void pci_remove_bus(struct pci_bus *pci_bus)
 
 	down_write(&pci_bus_sem);
 	list_del(&pci_bus->node);
+	pci_bus_release_busn_res(pci_bus);
 	up_write(&pci_bus_sem);
 	if (!pci_bus->is_added)
 		return;
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 9d75dc8..993d4a0 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -15,6 +15,8 @@
 #include "pci.h"
 
 DECLARE_RWSEM(pci_bus_sem);
+EXPORT_SYMBOL_GPL(pci_bus_sem);
+
 /*
  * find the upstream PCIe-to-PCI bridge of a PCI device
  * if the device is PCIE, return NULL
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 8fa2d4b..561e41c 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -265,7 +265,7 @@ out:
  * assign_requested_resources_sorted() - satisfy resource requests
  *
  * @head : head of the list tracking requests for resources
- * @failed_list : head of the list tracking requests that could
+ * @fail_head : head of the list tracking requests that could
  *		not be allocated
  *
  * Satisfy resource requests of each element in the list. Add
@@ -404,8 +404,8 @@ void pci_setup_cardbus(struct pci_bus *bus)
 	struct resource *res;
 	struct pci_bus_region region;
 
-	dev_info(&bridge->dev, "CardBus bridge to [bus %02x-%02x]\n",
-		 bus->secondary, bus->subordinate);
+	dev_info(&bridge->dev, "CardBus bridge to %pR\n",
+		 &bus->busn_res);
 
 	res = bus->resource[0];
 	pcibios_resource_to_bus(bridge, &region, res);
@@ -553,8 +553,8 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type)
 {
 	struct pci_dev *bridge = bus->self;
 
-	dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
-		 bus->secondary, bus->subordinate);
+	dev_info(&bridge->dev, "PCI bridge to %pR\n",
+		 &bus->busn_res);
 
 	if (type & IORESOURCE_IO)
 		pci_setup_bridge_io(bus);
@@ -745,8 +745,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
 	if (!size0 && !size1) {
 		if (b_res->start || b_res->end)
 			dev_info(&bus->self->dev, "disabling bridge window "
-				 "%pR to [bus %02x-%02x] (unused)\n", b_res,
-				 bus->secondary, bus->subordinate);
+				 "%pR to %pR (unused)\n", b_res,
+				 &bus->busn_res);
 		b_res->flags = 0;
 		return;
 	}
@@ -757,8 +757,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
 	if (size1 > size0 && realloc_head) {
 		add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096);
 		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
-				 "%pR to [bus %02x-%02x] add_size %lx\n", b_res,
-				 bus->secondary, bus->subordinate, size1-size0);
+				 "%pR to %pR add_size %lx\n", b_res,
+				 &bus->busn_res, size1-size0);
 	}
 }
 
@@ -863,8 +863,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
 	if (!size0 && !size1) {
 		if (b_res->start || b_res->end)
 			dev_info(&bus->self->dev, "disabling bridge window "
-				 "%pR to [bus %02x-%02x] (unused)\n", b_res,
-				 bus->secondary, bus->subordinate);
+				 "%pR to %pR (unused)\n", b_res,
+				 &bus->busn_res);
 		b_res->flags = 0;
 		return 1;
 	}
@@ -874,8 +874,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
 	if (size1 > size0 && realloc_head) {
 		add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);
 		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
-				 "%pR to [bus %02x-%02x] add_size %llx\n", b_res,
-				 bus->secondary, bus->subordinate, (unsigned long long)size1-size0);
+				 "%pR to %pR add_size %llx\n", b_res,
+				 &bus->busn_res, (unsigned long long)size1-size0);
 	}
 	return 1;
 }
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 6e75153..24caeaf 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -73,7 +73,7 @@ int __ref cb_alloc(struct pcmcia_socket *s)
 	s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0));
 	pci_fixup_cardbus(bus);
 
-	max = bus->secondary;
+	max = bus->busn_res.start;
 	for (pass = 0; pass < 2; pass++)
 		list_for_each_entry(dev, &bus->devices, bus_list)
 			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index d07f9ac..667678d 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -1048,8 +1048,8 @@ static void yenta_config_init(struct yenta_socket *socket)
 	config_writeb(socket, PCI_LATENCY_TIMER, 168);
 	config_writel(socket, PCI_PRIMARY_BUS,
 		(176 << 24) |			   /* sec. latency timer */
-		(dev->subordinate->subordinate << 16) | /* subordinate bus */
-		(dev->subordinate->secondary << 8) |  /* secondary bus */
+		((unsigned int)dev->subordinate->busn_res.end << 16) | /* subordinate bus */
+		((unsigned int)dev->subordinate->busn_res.start << 8) |  /* secondary bus */
 		dev->subordinate->primary);		   /* primary bus */
 
 	/*
@@ -1086,14 +1086,14 @@ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
 	struct pci_bus *bridge_to_fix = cardbus_bridge->parent;
 
 	/* Check bus numbers are already set up correctly: */
-	if (bridge_to_fix->subordinate >= cardbus_bridge->subordinate)
+	if (bridge_to_fix->busn_res.end >= cardbus_bridge->busn_res.end)
 		return; /* The subordinate number is ok, nothing to do */
 
 	if (!bridge_to_fix->parent)
 		return; /* Root bridges are ok */
 
 	/* stay within the limits of the bus range of the parent: */
-	upper_limit = bridge_to_fix->parent->subordinate;
+	upper_limit = bridge_to_fix->parent->busn_res.end;
 
 	/* check the bus ranges of all silbling bridges to prevent overlap */
 	list_for_each(tmp, &bridge_to_fix->parent->children) {
@@ -1104,36 +1104,36 @@ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
 		 * current upper limit, set the new upper limit to
 		 * the bus number below the silbling's range:
 		 */
-		if (silbling->secondary > bridge_to_fix->subordinate
-		    && silbling->secondary <= upper_limit)
-			upper_limit = silbling->secondary - 1;
+		if (silbling->busn_res.start > bridge_to_fix->busn_res.end
+		    && silbling->busn_res.start <= upper_limit)
+			upper_limit = silbling->busn_res.start - 1;
 	}
 
 	/* Show that the wanted subordinate number is not possible: */
-	if (cardbus_bridge->subordinate > upper_limit)
+	if (cardbus_bridge->busn_res.end > upper_limit)
 		dev_printk(KERN_WARNING, &cardbus_bridge->dev,
 			   "Upper limit for fixing this "
 			   "bridge's parent bridge: #%02x\n", upper_limit);
 
 	/* If we have room to increase the bridge's subordinate number, */
-	if (bridge_to_fix->subordinate < upper_limit) {
+	if (bridge_to_fix->busn_res.end < upper_limit) {
 
 		/* use the highest number of the hidden bus, within limits */
 		unsigned char subordinate_to_assign =
-			min(cardbus_bridge->subordinate, upper_limit);
+			min_t(int, cardbus_bridge->busn_res.end, upper_limit);
 
 		dev_printk(KERN_INFO, &bridge_to_fix->dev,
 			   "Raising subordinate bus# of parent "
 			   "bus (#%02x) from #%02x to #%02x\n",
 			   bridge_to_fix->number,
-			   bridge_to_fix->subordinate, subordinate_to_assign);
+			   (int)bridge_to_fix->busn_res.end, subordinate_to_assign);
 
 		/* Save the new subordinate in the bus struct of the bridge */
-		bridge_to_fix->subordinate = subordinate_to_assign;
+		bridge_to_fix->busn_res.end = subordinate_to_assign;
 
 		/* and update the PCI config space with the new subordinate */
 		pci_write_config_byte(bridge_to_fix->self,
-			PCI_SUBORDINATE_BUS, bridge_to_fix->subordinate);
+			PCI_SUBORDINATE_BUS, bridge_to_fix->busn_res.end);
 	}
 }
 
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index c6e6ae0..4c05fe8 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -130,7 +130,7 @@ config PINCTRL_U300
 
 config PINCTRL_COH901
 	bool "ST-Ericsson U300 COH 901 335/571 GPIO"
-	depends on GPIOLIB && ARCH_U300 && PINMUX_U300
+	depends on GPIOLIB && ARCH_U300 && PINCTRL_U300
 	help
 	  Say yes here to support GPIO interface on ST-Ericsson U300.
 	  The names of the two IP block variants supported are
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 0cc053a..fb7f3be 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -332,19 +332,16 @@ void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
 }
 EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
 
-/**
- * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller
- * @pctldev: pin controller device to remove the range from
- * @range: the GPIO range to remove
- */
-void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
-			       struct pinctrl_gpio_range *range)
+void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
+			     struct pinctrl_gpio_range *ranges,
+			     unsigned nranges)
 {
-	mutex_lock(&pinctrl_mutex);
-	list_del(&range->node);
-	mutex_unlock(&pinctrl_mutex);
+	int i;
+
+	for (i = 0; i < nranges; i++)
+		pinctrl_add_gpio_range(pctldev, &ranges[i]);
 }
-EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
+EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges);
 
 /**
  * pinctrl_get_group_selector() - returns the group selector for a group
@@ -1395,9 +1392,9 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
 	struct pinctrl_dev *pctldev;
 	int ret;
 
-	if (pctldesc == NULL)
+	if (!pctldesc)
 		return NULL;
-	if (pctldesc->name == NULL)
+	if (!pctldesc->name)
 		return NULL;
 
 	pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
@@ -1415,23 +1412,20 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
 	pctldev->dev = dev;
 
 	/* check core ops for sanity */
-	ret = pinctrl_check_ops(pctldev);
-	if (ret) {
+	if (pinctrl_check_ops(pctldev)) {
 		dev_err(dev, "pinctrl ops lacks necessary functions\n");
 		goto out_err;
 	}
 
 	/* If we're implementing pinmuxing, check the ops for sanity */
 	if (pctldesc->pmxops) {
-		ret = pinmux_check_ops(pctldev);
-		if (ret)
+		if (pinmux_check_ops(pctldev))
 			goto out_err;
 	}
 
 	/* If we're implementing pinconfig, check the ops for sanity */
 	if (pctldesc->confops) {
-		ret = pinconf_check_ops(pctldev);
-		if (ret)
+		if (pinconf_check_ops(pctldev))
 			goto out_err;
 	}
 
@@ -1457,11 +1451,9 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
 		if (IS_ERR(s)) {
 			dev_dbg(dev, "failed to lookup the default state\n");
 		} else {
-			ret = pinctrl_select_state_locked(pctldev->p, s);
-			if (ret) {
+			if (pinctrl_select_state_locked(pctldev->p, s))
 				dev_err(dev,
 					"failed to select default state\n");
-			}
 		}
 	}
 
@@ -1485,6 +1477,7 @@ EXPORT_SYMBOL_GPL(pinctrl_register);
  */
 void pinctrl_unregister(struct pinctrl_dev *pctldev)
 {
+	struct pinctrl_gpio_range *range, *n;
 	if (pctldev == NULL)
 		return;
 
@@ -1500,6 +1493,10 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
 	/* Destroy descriptor tree */
 	pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
 			      pctldev->desc->npins);
+	/* remove gpio ranges map */
+	list_for_each_entry_safe(range, n, &pctldev->gpio_ranges, node)
+		list_del(&range->node);
+
 	kfree(pctldev);
 
 	mutex_unlock(&pinctrl_mutex);
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index 55697a5..cc0f00d 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -770,7 +770,7 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
 		dev_err(gpio->dev, "could not get GPIO clock\n");
 		goto err_no_clk;
 	}
-	err = clk_enable(gpio->clk);
+	err = clk_prepare_enable(gpio->clk);
 	if (err) {
 		dev_err(gpio->dev, "could not enable GPIO clock\n");
 		goto err_no_clk_enable;
@@ -912,7 +912,7 @@ err_no_ioremap:
 	release_mem_region(gpio->memres->start, resource_size(gpio->memres));
 err_no_ioregion:
 err_no_resource:
-	clk_disable(gpio->clk);
+	clk_disable_unprepare(gpio->clk);
 err_no_clk_enable:
 	clk_put(gpio->clk);
 err_no_clk:
@@ -943,7 +943,7 @@ static int __exit u300_gpio_remove(struct platform_device *pdev)
 	iounmap(gpio->base);
 	release_mem_region(gpio->memres->start,
 			   resource_size(gpio->memres));
-	clk_disable(gpio->clk);
+	clk_disable_unprepare(gpio->clk);
 	clk_put(gpio->clk);
 	platform_set_drvdata(pdev, NULL);
 	kfree(gpio);
diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c
index dd6d93a..2bafb5d 100644
--- a/drivers/pinctrl/pinctrl-imx.c
+++ b/drivers/pinctrl/pinctrl-imx.c
@@ -146,7 +146,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
 	struct pinctrl_map *new_map;
 	struct device_node *parent;
 	int map_num = 1;
-	int i;
+	int i, j;
 
 	/*
 	 * first find the group of this node and check if we need create
@@ -184,13 +184,14 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
 
 	/* create config map */
 	new_map++;
-	for (i = 0; i < grp->npins; i++) {
+	for (i = j = 0; i < grp->npins; i++) {
 		if (!(grp->configs[i] & IMX_NO_PAD_CTL)) {
-			new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
-			new_map[i].data.configs.group_or_pin =
+			new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
+			new_map[j].data.configs.group_or_pin =
 					pin_get_name(pctldev, grp->pins[i]);
-			new_map[i].data.configs.configs = &grp->configs[i];
-			new_map[i].data.configs.num_configs = 1;
+			new_map[j].data.configs.configs = &grp->configs[i];
+			new_map[j].data.configs.num_configs = 1;
+			j++;
 		}
 	}
 
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index b693486..ae52e4e 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -745,9 +745,9 @@ int __devinit tegra_pinctrl_probe(struct platform_device *pdev,
 	}
 
 	pmx->pctl = pinctrl_register(&tegra_pinctrl_desc, &pdev->dev, pmx);
-	if (IS_ERR(pmx->pctl)) {
+	if (!pmx->pctl) {
 		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
-		return PTR_ERR(pmx->pctl);
+		return -ENODEV;
 	}
 
 	pinctrl_add_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
@@ -764,7 +764,6 @@ int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
 {
 	struct tegra_pmx *pmx = platform_get_drvdata(pdev);
 
-	pinctrl_remove_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
 	pinctrl_unregister(pmx->pctl);
 
 	return 0;
diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
index 05d0299..a7ad8c1 100644
--- a/drivers/pinctrl/pinctrl-u300.c
+++ b/drivers/pinctrl/pinctrl-u300.c
@@ -1113,8 +1113,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
 	int ret;
 	int i;
 
-	pr_err("U300 PMX PROBE\n");
-
 	/* Create state holders etc for this driver */
 	upmx = devm_kzalloc(&pdev->dev, sizeof(*upmx), GFP_KERNEL);
 	if (!upmx)
@@ -1175,15 +1173,11 @@ out_no_resource:
 static int __devexit u300_pmx_remove(struct platform_device *pdev)
 {
 	struct u300_pmx *upmx = platform_get_drvdata(pdev);
-	int i;
 
-	for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++)
-		pinctrl_remove_gpio_range(upmx->pctl, &u300_gpio_ranges[i]);
 	pinctrl_unregister(upmx->pctl);
 	iounmap(upmx->virtbase);
 	release_mem_region(upmx->phybase, upmx->physize);
 	platform_set_drvdata(pdev, NULL);
-	devm_kfree(&pdev->dev, upmx);
 
 	return 0;
 }
diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c
index b3f6b28..5d4f44f 100644
--- a/drivers/pinctrl/spear/pinctrl-spear.c
+++ b/drivers/pinctrl/spear/pinctrl-spear.c
@@ -336,9 +336,9 @@ int __devinit spear_pinctrl_probe(struct platform_device *pdev,
 	spear_pinctrl_desc.npins = machdata->npins;
 
 	pmx->pctl = pinctrl_register(&spear_pinctrl_desc, &pdev->dev, pmx);
-	if (IS_ERR(pmx->pctl)) {
+	if (!pmx->pctl) {
 		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
-		return PTR_ERR(pmx->pctl);
+		return -ENODEV;
 	}
 
 	return 0;
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index ce875dc..175809d 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -95,6 +95,7 @@ MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
 
 enum acer_wmi_event_ids {
 	WMID_HOTKEY_EVENT = 0x1,
+	WMID_ACCEL_EVENT = 0x5,
 };
 
 static const struct key_entry acer_wmi_keymap[] = {
@@ -130,6 +131,7 @@ static const struct key_entry acer_wmi_keymap[] = {
 };
 
 static struct input_dev *acer_wmi_input_dev;
+static struct input_dev *acer_wmi_accel_dev;
 
 struct event_return_value {
 	u8 function;
@@ -200,6 +202,7 @@ struct hotkey_function_type_aa {
 #define ACER_CAP_BLUETOOTH		(1<<2)
 #define ACER_CAP_BRIGHTNESS		(1<<3)
 #define ACER_CAP_THREEG			(1<<4)
+#define ACER_CAP_ACCEL			(1<<5)
 #define ACER_CAP_ANY			(0xFFFFFFFF)
 
 /*
@@ -1399,6 +1402,60 @@ static void acer_backlight_exit(void)
 }
 
 /*
+ * Accelerometer device
+ */
+static acpi_handle gsensor_handle;
+
+static int acer_gsensor_init(void)
+{
+	acpi_status status;
+	struct acpi_buffer output;
+	union acpi_object out_obj;
+
+	output.length = sizeof(out_obj);
+	output.pointer = &out_obj;
+	status = acpi_evaluate_object(gsensor_handle, "_INI", NULL, &output);
+	if (ACPI_FAILURE(status))
+		return -1;
+
+	return 0;
+}
+
+static int acer_gsensor_open(struct input_dev *input)
+{
+	return acer_gsensor_init();
+}
+
+static int acer_gsensor_event(void)
+{
+	acpi_status status;
+	struct acpi_buffer output;
+	union acpi_object out_obj[5];
+
+	if (!has_cap(ACER_CAP_ACCEL))
+		return -1;
+
+	output.length = sizeof(out_obj);
+	output.pointer = out_obj;
+
+	status = acpi_evaluate_object(gsensor_handle, "RDVL", NULL, &output);
+	if (ACPI_FAILURE(status))
+		return -1;
+
+	if (out_obj->package.count != 4)
+		return -1;
+
+	input_report_abs(acer_wmi_accel_dev, ABS_X,
+		(s16)out_obj->package.elements[0].integer.value);
+	input_report_abs(acer_wmi_accel_dev, ABS_Y,
+		(s16)out_obj->package.elements[1].integer.value);
+	input_report_abs(acer_wmi_accel_dev, ABS_Z,
+		(s16)out_obj->package.elements[2].integer.value);
+	input_sync(acer_wmi_accel_dev);
+	return 0;
+}
+
+/*
  * Rfkill devices
  */
 static void acer_rfkill_update(struct work_struct *ignored);
@@ -1673,6 +1730,9 @@ static void acer_wmi_notify(u32 value, void *context)
 						   1, true);
 		}
 		break;
+	case WMID_ACCEL_EVENT:
+		acer_gsensor_event();
+		break;
 	default:
 		pr_warn("Unknown function number - %d - %d\n",
 			return_value.function, return_value.key_num);
@@ -1758,6 +1818,74 @@ static int acer_wmi_enable_lm(void)
 	return status;
 }
 
+static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level,
+						void *ctx, void **retval)
+{
+	*(acpi_handle *)retval = ah;
+	return AE_OK;
+}
+
+static int __init acer_wmi_get_handle(const char *name, const char *prop,
+					acpi_handle *ah)
+{
+	acpi_status status;
+	acpi_handle handle;
+
+	BUG_ON(!name || !ah);
+
+	handle = 0;
+	status = acpi_get_devices(prop, acer_wmi_get_handle_cb,
+					(void *)name, &handle);
+
+	if (ACPI_SUCCESS(status)) {
+		*ah = handle;
+		return 0;
+	} else {
+		return -ENODEV;
+	}
+}
+
+static int __init acer_wmi_accel_setup(void)
+{
+	int err;
+
+	err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle);
+	if (err)
+		return err;
+
+	interface->capability |= ACER_CAP_ACCEL;
+
+	acer_wmi_accel_dev = input_allocate_device();
+	if (!acer_wmi_accel_dev)
+		return -ENOMEM;
+
+	acer_wmi_accel_dev->open = acer_gsensor_open;
+
+	acer_wmi_accel_dev->name = "Acer BMA150 accelerometer";
+	acer_wmi_accel_dev->phys = "wmi/input1";
+	acer_wmi_accel_dev->id.bustype = BUS_HOST;
+	acer_wmi_accel_dev->evbit[0] = BIT_MASK(EV_ABS);
+	input_set_abs_params(acer_wmi_accel_dev, ABS_X, -16384, 16384, 0, 0);
+	input_set_abs_params(acer_wmi_accel_dev, ABS_Y, -16384, 16384, 0, 0);
+	input_set_abs_params(acer_wmi_accel_dev, ABS_Z, -16384, 16384, 0, 0);
+
+	err = input_register_device(acer_wmi_accel_dev);
+	if (err)
+		goto err_free_dev;
+
+	return 0;
+
+err_free_dev:
+	input_free_device(acer_wmi_accel_dev);
+	return err;
+}
+
+static void acer_wmi_accel_destroy(void)
+{
+	input_unregister_device(acer_wmi_accel_dev);
+	input_free_device(acer_wmi_accel_dev);
+}
+
 static int __init acer_wmi_input_setup(void)
 {
 	acpi_status status;
@@ -1877,8 +2005,7 @@ static int acer_platform_remove(struct platform_device *device)
 	return 0;
 }
 
-static int acer_platform_suspend(struct platform_device *dev,
-pm_message_t state)
+static int acer_suspend(struct device *dev)
 {
 	u32 value;
 	struct acer_data *data = &interface->data;
@@ -1900,7 +2027,7 @@ pm_message_t state)
 	return 0;
 }
 
-static int acer_platform_resume(struct platform_device *device)
+static int acer_resume(struct device *dev)
 {
 	struct acer_data *data = &interface->data;
 
@@ -1913,9 +2040,14 @@ static int acer_platform_resume(struct platform_device *device)
 	if (has_cap(ACER_CAP_BRIGHTNESS))
 		set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
 
+	if (has_cap(ACER_CAP_ACCEL))
+		acer_gsensor_init();
+
 	return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume);
+
 static void acer_platform_shutdown(struct platform_device *device)
 {
 	struct acer_data *data = &interface->data;
@@ -1931,11 +2063,10 @@ static struct platform_driver acer_platform_driver = {
 	.driver = {
 		.name = "acer-wmi",
 		.owner = THIS_MODULE,
+		.pm = &acer_pm,
 	},
 	.probe = acer_platform_probe,
 	.remove = acer_platform_remove,
-	.suspend = acer_platform_suspend,
-	.resume = acer_platform_resume,
 	.shutdown = acer_platform_shutdown,
 };
 
@@ -2090,6 +2221,8 @@ static int __init acer_wmi_init(void)
 			return err;
 	}
 
+	acer_wmi_accel_setup();
+
 	err = platform_driver_register(&acer_platform_driver);
 	if (err) {
 		pr_err("Unable to register platform driver\n");
@@ -2133,6 +2266,8 @@ error_device_alloc:
 error_platform_register:
 	if (wmi_has_guid(ACERWMID_EVENT_GUID))
 		acer_wmi_input_destroy();
+	if (has_cap(ACER_CAP_ACCEL))
+		acer_wmi_accel_destroy();
 
 	return err;
 }
@@ -2142,6 +2277,9 @@ static void __exit acer_wmi_exit(void)
 	if (wmi_has_guid(ACERWMID_EVENT_GUID))
 		acer_wmi_input_destroy();
 
+	if (has_cap(ACER_CAP_ACCEL))
+		acer_wmi_accel_destroy();
+
 	remove_sysfs(acer_platform_device);
 	remove_debugfs();
 	platform_device_unregister(acer_platform_device);
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 2fd9d36..39abb15 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -660,7 +660,7 @@ static int acerhdf_register_thermal(void)
 	if (IS_ERR(cl_dev))
 		return -EINVAL;
 
-	thz_dev = thermal_zone_device_register("acerhdf", 1, NULL,
+	thz_dev = thermal_zone_device_register("acerhdf", 1, 0, NULL,
 					      &acerhdf_dev_ops, 0, 0, 0,
 					      (kernelmode) ? interval*1000 : 0);
 	if (IS_ERR(thz_dev))
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 77aadde..556cbb4 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -1467,14 +1467,9 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
 	 */
 	if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL))
 		asus->dsts_id = ASUS_WMI_METHODID_DSTS;
-	else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL))
+	else
 		asus->dsts_id = ASUS_WMI_METHODID_DSTS2;
 
-	if (!asus->dsts_id) {
-		pr_err("Can't find DSTS");
-		return -ENODEV;
-	}
-
 	/* CWAP allow to define the behavior of the Fn+F2 key,
 	 * this method doesn't seems to be present on Eee PCs */
 	if (asus->driver->quirks->wapf >= 0)
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index c4c1a54..e2aae57 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -118,27 +118,22 @@
 #define RINGBUFFERSIZE 40
 
 /* Debugging */
-#define FUJLAPTOP_LOG	   ACPI_FUJITSU_HID ": "
-#define FUJLAPTOP_ERR	   KERN_ERR FUJLAPTOP_LOG
-#define FUJLAPTOP_NOTICE   KERN_NOTICE FUJLAPTOP_LOG
-#define FUJLAPTOP_INFO	   KERN_INFO FUJLAPTOP_LOG
-#define FUJLAPTOP_DEBUG    KERN_DEBUG FUJLAPTOP_LOG
-
 #define FUJLAPTOP_DBG_ALL	  0xffff
 #define FUJLAPTOP_DBG_ERROR	  0x0001
 #define FUJLAPTOP_DBG_WARN	  0x0002
 #define FUJLAPTOP_DBG_INFO	  0x0004
 #define FUJLAPTOP_DBG_TRACE	  0x0008
 
-#define dbg_printk(a_dbg_level, format, arg...) \
-	do { if (dbg_level & a_dbg_level) \
-		printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \
-	} while (0)
 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
-#define vdbg_printk(a_dbg_level, format, arg...) \
-	dbg_printk(a_dbg_level, format, ## arg)
+#define DEBUG
+#define fuj_dbg(a_dbg_level, format, ...)				\
+do {									\
+	if (dbg_level & a_dbg_level)					\
+		pr_debug("%s: " format, __func__ , ##__VA_ARGS__);	\
+} while (0)
 #else
-#define vdbg_printk(a_dbg_level, format, arg...)
+#define fuj_dbg(a_dbg_level, format, ...)		\
+	eliminated_printk(format, ##__VA_ARGS__)
 #endif
 
 /* Device controlling the backlight and associated keys */
@@ -225,8 +220,7 @@ static int call_fext_func(int cmd, int arg0, int arg1, int arg2)
 
 	status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle);
 	if (ACPI_FAILURE(status)) {
-		vdbg_printk(FUJLAPTOP_DBG_ERROR,
-				"FUNC interface is not present\n");
+		fuj_dbg(FUJLAPTOP_DBG_ERROR, "FUNC interface is not present\n");
 		return -ENODEV;
 	}
 
@@ -240,23 +234,22 @@ static int call_fext_func(int cmd, int arg0, int arg1, int arg2)
 
 	status = acpi_evaluate_object(handle, NULL, &arg_list, &output);
 	if (ACPI_FAILURE(status)) {
-		vdbg_printk(FUJLAPTOP_DBG_WARN,
+		fuj_dbg(FUJLAPTOP_DBG_WARN,
 			"FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n",
-				cmd, arg0, arg1, arg2);
+			cmd, arg0, arg1, arg2);
 		return -ENODEV;
 	}
 
 	if (out_obj.type != ACPI_TYPE_INTEGER) {
-		vdbg_printk(FUJLAPTOP_DBG_WARN,
-			"FUNC 0x%x (args 0x%x, 0x%x, 0x%x) did not "
-			"return an integer\n",
+		fuj_dbg(FUJLAPTOP_DBG_WARN,
+			"FUNC 0x%x (args 0x%x, 0x%x, 0x%x) did not return an integer\n",
 			cmd, arg0, arg1, arg2);
 		return -ENODEV;
 	}
 
-	vdbg_printk(FUJLAPTOP_DBG_TRACE,
+	fuj_dbg(FUJLAPTOP_DBG_TRACE,
 		"FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
-			cmd, arg0, arg1, arg2, (int)out_obj.integer.value);
+		cmd, arg0, arg1, arg2, (int)out_obj.integer.value);
 	return out_obj.integer.value;
 }
 
@@ -321,15 +314,14 @@ static int set_lcd_level(int level)
 	struct acpi_object_list arg_list = { 1, &arg0 };
 	acpi_handle handle = NULL;
 
-	vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n",
-		    level);
+	fuj_dbg(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n", level);
 
 	if (level < 0 || level >= fujitsu->max_brightness)
 		return -EINVAL;
 
 	status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle);
 	if (ACPI_FAILURE(status)) {
-		vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n");
+		fuj_dbg(FUJLAPTOP_DBG_ERROR, "SBLL not present\n");
 		return -ENODEV;
 	}
 
@@ -349,15 +341,14 @@ static int set_lcd_level_alt(int level)
 	struct acpi_object_list arg_list = { 1, &arg0 };
 	acpi_handle handle = NULL;
 
-	vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n",
-		    level);
+	fuj_dbg(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n", level);
 
 	if (level < 0 || level >= fujitsu->max_brightness)
 		return -EINVAL;
 
 	status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle);
 	if (ACPI_FAILURE(status)) {
-		vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n");
+		fuj_dbg(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n");
 		return -ENODEV;
 	}
 
@@ -375,7 +366,7 @@ static int get_lcd_level(void)
 	unsigned long long state = 0;
 	acpi_status status = AE_OK;
 
-	vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n");
+	fuj_dbg(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n");
 
 	status =
 	    acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state);
@@ -397,7 +388,7 @@ static int get_max_brightness(void)
 	unsigned long long state = 0;
 	acpi_status status = AE_OK;
 
-	vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n");
+	fuj_dbg(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n");
 
 	status =
 	    acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state);
@@ -424,7 +415,7 @@ static int bl_update_status(struct backlight_device *b)
 	else
 		ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
 	if (ret != 0)
-		vdbg_printk(FUJLAPTOP_DBG_ERROR,
+		fuj_dbg(FUJLAPTOP_DBG_ERROR,
 			"Unable to adjust backlight power, error code %i\n",
 			ret);
 
@@ -433,7 +424,7 @@ static int bl_update_status(struct backlight_device *b)
 	else
 		ret = set_lcd_level(b->props.brightness);
 	if (ret != 0)
-		vdbg_printk(FUJLAPTOP_DBG_ERROR,
+		fuj_dbg(FUJLAPTOP_DBG_ERROR,
 			"Unable to adjust LCD brightness, error code %i\n",
 			ret);
 	return ret;
@@ -594,8 +585,8 @@ static void dmi_check_cb_common(const struct dmi_system_id *id)
 			use_alt_lcd_levels = 1;
 		else
 			use_alt_lcd_levels = 0;
-		vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as "
-			"%i\n", use_alt_lcd_levels);
+		fuj_dbg(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as %i\n",
+			use_alt_lcd_levels);
 	}
 }
 
@@ -704,7 +695,7 @@ static int acpi_fujitsu_add(struct acpi_device *device)
 
 	if (ACPI_SUCCESS
 	    (acpi_get_handle(device->handle, METHOD_NAME__INI, &handle))) {
-		vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
+		fuj_dbg(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
 		if (ACPI_FAILURE
 		    (acpi_evaluate_object
 		     (device->handle, METHOD_NAME__INI, NULL, NULL)))
@@ -714,9 +705,9 @@ static int acpi_fujitsu_add(struct acpi_device *device)
 	/* do config (detect defaults) */
 	use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
 	disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
-	vdbg_printk(FUJLAPTOP_DBG_INFO,
-		    "config: [alt interface: %d], [adjust disable: %d]\n",
-		    use_alt_lcd_levels, disable_brightness_adjust);
+	fuj_dbg(FUJLAPTOP_DBG_INFO,
+		"config: [alt interface: %d], [adjust disable: %d]\n",
+		use_alt_lcd_levels, disable_brightness_adjust);
 
 	if (get_max_brightness() <= 0)
 		fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS;
@@ -762,9 +753,9 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event)
 		get_lcd_level();
 		newb = fujitsu->brightness_level;
 
-		vdbg_printk(FUJLAPTOP_DBG_TRACE,
-			    "brightness button event [%i -> %i (%i)]\n",
-			    oldb, newb, fujitsu->brightness_changed);
+		fuj_dbg(FUJLAPTOP_DBG_TRACE,
+			"brightness button event [%i -> %i (%i)]\n",
+			oldb, newb, fujitsu->brightness_changed);
 
 		if (oldb < newb) {
 			if (disable_brightness_adjust != 1) {
@@ -790,8 +781,8 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event)
 		break;
 	default:
 		keycode = KEY_UNKNOWN;
-		vdbg_printk(FUJLAPTOP_DBG_WARN,
-			    "unsupported event [0x%x]\n", event);
+		fuj_dbg(FUJLAPTOP_DBG_WARN, "unsupported event [0x%x]\n",
+			event);
 		break;
 	}
 
@@ -872,7 +863,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
 
 	if (ACPI_SUCCESS
 	    (acpi_get_handle(device->handle, METHOD_NAME__INI, &handle))) {
-		vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
+		fuj_dbg(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
 		if (ACPI_FAILURE
 		    (acpi_evaluate_object
 		     (device->handle, METHOD_NAME__INI, NULL, NULL)))
@@ -883,7 +874,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
 	while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0
 		&& (i++) < MAX_HOTKEY_RINGBUFFER_SIZE)
 		; /* No action, result is discarded */
-	vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
+	fuj_dbg(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
 
 	fujitsu_hotkey->rfkill_supported =
 		call_fext_func(FUNC_RFKILL, 0x0, 0x0, 0x0);
@@ -996,13 +987,13 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
 				keycode = 0;
 				break;
 			default:
-				vdbg_printk(FUJLAPTOP_DBG_WARN,
-					    "Unknown GIRB result [%x]\n", irb);
+				fuj_dbg(FUJLAPTOP_DBG_WARN,
+					"Unknown GIRB result [%x]\n", irb);
 				keycode = -1;
 				break;
 			}
 			if (keycode > 0) {
-				vdbg_printk(FUJLAPTOP_DBG_TRACE,
+				fuj_dbg(FUJLAPTOP_DBG_TRACE,
 					"Push keycode into ringbuffer [%d]\n",
 					keycode);
 				status = kfifo_in_locked(&fujitsu_hotkey->fifo,
@@ -1010,9 +1001,9 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
 						   sizeof(keycode),
 						   &fujitsu_hotkey->fifo_lock);
 				if (status != sizeof(keycode)) {
-					vdbg_printk(FUJLAPTOP_DBG_WARN,
-					    "Could not push keycode [0x%x]\n",
-					    keycode);
+					fuj_dbg(FUJLAPTOP_DBG_WARN,
+						"Could not push keycode [0x%x]\n",
+						keycode);
 				} else {
 					input_report_key(input, keycode, 1);
 					input_sync(input);
@@ -1027,9 +1018,9 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
 					 == sizeof(keycode_r)) {
 					input_report_key(input, keycode_r, 0);
 					input_sync(input);
-					vdbg_printk(FUJLAPTOP_DBG_TRACE,
-					  "Pop keycode from ringbuffer [%d]\n",
-					  keycode_r);
+					fuj_dbg(FUJLAPTOP_DBG_TRACE,
+						"Pop keycode from ringbuffer [%d]\n",
+						keycode_r);
 				}
 			}
 		}
@@ -1037,8 +1028,8 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
 		break;
 	default:
 		keycode = KEY_UNKNOWN;
-		vdbg_printk(FUJLAPTOP_DBG_WARN,
-			    "Unsupported event [0x%x]\n", event);
+		fuj_dbg(FUJLAPTOP_DBG_WARN, "Unsupported event [0x%x]\n",
+			event);
 		input_report_key(input, keycode, 1);
 		input_sync(input);
 		input_report_key(input, keycode, 0);
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 4f20f8d..17f6dfd 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -694,10 +694,10 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
 static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
 {
 	int ret, i;
-	unsigned long cfg;
+	int cfg;
 	struct ideapad_private *priv;
 
-	if (read_method_int(adevice->handle, "_CFG", (int *)&cfg))
+	if (read_method_int(adevice->handle, "_CFG", &cfg))
 		return -ENODEV;
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -721,7 +721,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
 		goto input_failed;
 
 	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) {
-		if (test_bit(ideapad_rfk_data[i].cfgbit, &cfg))
+		if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
 			ideapad_register_rfkill(adevice, i);
 		else
 			priv->rfk[i] = NULL;
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index 0ffdb3c..5051aa9 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -72,6 +72,7 @@
 #include <linux/string.h>
 #include <linux/tick.h>
 #include <linux/timer.h>
+#include <linux/dmi.h>
 #include <drm/i915_drm.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
@@ -1485,6 +1486,24 @@ static DEFINE_PCI_DEVICE_TABLE(ips_id_table) = {
 
 MODULE_DEVICE_TABLE(pci, ips_id_table);
 
+static int ips_blacklist_callback(const struct dmi_system_id *id)
+{
+	pr_info("Blacklisted intel_ips for %s\n", id->ident);
+	return 1;
+}
+
+static const struct dmi_system_id ips_blacklist[] = {
+	{
+		.callback = ips_blacklist_callback,
+		.ident = "HP ProBook",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook"),
+		},
+	},
+	{ }	/* terminating entry */
+};
+
 static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	u64 platform_info;
@@ -1494,6 +1513,9 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	u16 htshi, trc, trc_required_mask;
 	u8 tse;
 
+	if (dmi_check_system(ips_blacklist))
+		return -ENODEV;
+
 	ips = kzalloc(sizeof(struct ips_driver), GFP_KERNEL);
 	if (!ips)
 		return -ENOMEM;
@@ -1697,21 +1719,6 @@ static void ips_remove(struct pci_dev *dev)
 	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)
 {
 }
@@ -1721,8 +1728,6 @@ static struct pci_driver ips_pci_driver = {
 	.id_table = ips_id_table,
 	.probe = ips_probe,
 	.remove = ips_remove,
-	.suspend = ips_suspend,
-	.resume = ips_resume,
 	.shutdown = ips_shutdown,
 };
 
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
index 5ae9cd9..3a27113 100644
--- a/drivers/platform/x86/intel_mid_thermal.c
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -418,23 +418,23 @@ static struct thermal_device_info *initialize_sensor(int index)
 
 /**
  * mid_thermal_resume - resume routine
- * @pdev: platform device structure
+ * @dev: device structure
  *
  * mid thermal resume: re-initializes the adc. Can sleep.
  */
-static int mid_thermal_resume(struct platform_device *pdev)
+static int mid_thermal_resume(struct device *dev)
 {
-	return mid_initialize_adc(&pdev->dev);
+	return mid_initialize_adc(dev);
 }
 
 /**
  * mid_thermal_suspend - suspend routine
- * @pdev: platform device structure
+ * @dev: device structure
  *
  * mid thermal suspend implements the suspend functionality
  * by stopping the ADC. Can sleep.
  */
-static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg)
+static int mid_thermal_suspend(struct device *dev)
 {
 	/*
 	 * This just stops the ADC and does not disable it.
@@ -444,6 +444,9 @@ static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg)
 	return configure_adc(0);
 }
 
+static SIMPLE_DEV_PM_OPS(mid_thermal_pm,
+			 mid_thermal_suspend, mid_thermal_resume);
+
 /**
  * read_curr_temp - reads the current temperature and stores in temp
  * @temp: holds the current temperature value after reading
@@ -499,7 +502,7 @@ static int mid_thermal_probe(struct platform_device *pdev)
 			goto err;
 		}
 		pinfo->tzd[i] = thermal_zone_device_register(name[i],
-				0, td_info, &tzd_ops, 0, 0, 0, 0);
+				0, 0, td_info, &tzd_ops, 0, 0, 0, 0);
 		if (IS_ERR(pinfo->tzd[i])) {
 			kfree(td_info);
 			ret = PTR_ERR(pinfo->tzd[i]);
@@ -557,10 +560,9 @@ static struct platform_driver mid_thermal_driver = {
 	.driver = {
 		.name = DRIVER_NAME,
 		.owner = THIS_MODULE,
+		.pm = &mid_thermal_pm,
 	},
 	.probe = mid_thermal_probe,
-	.suspend = mid_thermal_suspend,
-	.resume = mid_thermal_resume,
 	.remove = __devexit_p(mid_thermal_remove),
 	.id_table = therm_id_table,
 };
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 210d4ae..d456ff0 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -973,7 +973,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 			       struct device_attribute *attr,
 			       const char *buffer, size_t count)
 {
-	unsigned long value = 0;
+	int value;
 	int ret = 0;
 	struct sony_nc_value *item =
 	    container_of(attr, struct sony_nc_value, devattr);
@@ -984,7 +984,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 	if (count > 31)
 		return -EINVAL;
 
-	if (kstrtoul(buffer, 10, &value))
+	if (kstrtoint(buffer, 10, &value))
 		return -EINVAL;
 
 	if (item->validate)
@@ -994,7 +994,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 		return value;
 
 	ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
-			(int *)&value, NULL);
+			       &value, NULL);
 	if (ret < 0)
 		return -EIO;
 
@@ -1010,6 +1010,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 struct sony_backlight_props {
 	struct backlight_device *dev;
 	int			handle;
+	int			cmd_base;
 	u8			offset;
 	u8			maxlvl;
 };
@@ -1037,7 +1038,7 @@ static int sony_nc_get_brightness_ng(struct backlight_device *bd)
 	struct sony_backlight_props *sdev =
 		(struct sony_backlight_props *)bl_get_data(bd);
 
-	sony_call_snc_handle(sdev->handle, 0x0200, &result);
+	sony_call_snc_handle(sdev->handle, sdev->cmd_base + 0x100, &result);
 
 	return (result & 0xff) - sdev->offset;
 }
@@ -1049,7 +1050,8 @@ static int sony_nc_update_status_ng(struct backlight_device *bd)
 		(struct sony_backlight_props *)bl_get_data(bd);
 
 	value = bd->props.brightness + sdev->offset;
-	if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result))
+	if (sony_call_snc_handle(sdev->handle, sdev->cmd_base | (value << 0x10),
+				&result))
 		return -EIO;
 
 	return value;
@@ -1172,6 +1174,11 @@ static int sony_nc_hotkeys_decode(u32 event, unsigned int handle)
 /*
  * ACPI callbacks
  */
+enum event_types {
+	HOTKEY = 1,
+	KILLSWITCH,
+	GFX_SWITCH
+};
 static void sony_nc_notify(struct acpi_device *device, u32 event)
 {
 	u32 real_ev = event;
@@ -1196,7 +1203,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 		/* hotkey event */
 		case 0x0100:
 		case 0x0127:
-			ev_type = 1;
+			ev_type = HOTKEY;
 			real_ev = sony_nc_hotkeys_decode(event, handle);
 
 			if (real_ev > 0)
@@ -1216,7 +1223,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 			 * update the rfkill device status when the
 			 * switch is moved.
 			 */
-			ev_type = 2;
+			ev_type = KILLSWITCH;
 			sony_call_snc_handle(handle, 0x0100, &result);
 			real_ev = result & 0x03;
 
@@ -1226,6 +1233,24 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 
 			break;
 
+		case 0x0128:
+		case 0x0146:
+			/* Hybrid GFX switching */
+			sony_call_snc_handle(handle, 0x0000, &result);
+			dprintk("GFX switch event received (reason: %s)\n",
+					(result & 0x01) ?
+					"switch change" : "unknown");
+
+			/* verify the switch state
+			 * 1: discrete GFX
+			 * 0: integrated GFX
+			 */
+			sony_call_snc_handle(handle, 0x0100, &result);
+
+			ev_type = GFX_SWITCH;
+			real_ev = result & 0xff;
+			break;
+
 		default:
 			dprintk("Unknown event 0x%x for handle 0x%x\n",
 					event, handle);
@@ -1238,7 +1263,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 
 	} else {
 		/* old style event */
-		ev_type = 1;
+		ev_type = HOTKEY;
 		sony_laptop_report_input_event(real_ev);
 	}
 
@@ -1893,32 +1918,33 @@ static ssize_t sony_nc_battery_care_limit_store(struct device *dev,
 	 *  bits 4,5: store the limit into the EC
 	 *  bits 6,7: store the limit into the battery
 	 */
+	cmd = 0;
 
-	/*
-	 * handle 0x0115 should allow storing on battery too;
-	 * handle 0x0136 same as 0x0115 + health status;
-	 * handle 0x013f, same as 0x0136 but no storing on the battery
-	 *
-	 * Store only inside the EC for now, regardless the handle number
-	 */
-	if (value == 0)
-		/* disable limits */
-		cmd = 0x0;
+	if (value > 0) {
+		if (value <= 50)
+			cmd = 0x20;
 
-	else if (value <= 50)
-		cmd = 0x21;
+		else if (value <= 80)
+			cmd = 0x10;
 
-	else if (value <= 80)
-		cmd = 0x11;
+		else if (value <= 100)
+			cmd = 0x30;
 
-	else if (value <= 100)
-		cmd = 0x31;
+		else
+			return -EINVAL;
 
-	else
-		return -EINVAL;
+		/*
+		 * handle 0x0115 should allow storing on battery too;
+		 * handle 0x0136 same as 0x0115 + health status;
+		 * handle 0x013f, same as 0x0136 but no storing on the battery
+		 */
+		if (bcare_ctl->handle != 0x013f)
+			cmd = cmd | (cmd << 2);
 
-	if (sony_call_snc_handle(bcare_ctl->handle, (cmd << 0x10) | 0x0100,
-				&result))
+		cmd = (cmd | 0x1) << 0x10;
+	}
+
+	if (sony_call_snc_handle(bcare_ctl->handle, cmd | 0x0100, &result))
 		return -EIO;
 
 	return count;
@@ -2113,7 +2139,7 @@ static ssize_t sony_nc_thermal_mode_show(struct device *dev,
 		struct device_attribute *attr, char *buffer)
 {
 	ssize_t count = 0;
-	unsigned int mode = sony_nc_thermal_mode_get();
+	int mode = sony_nc_thermal_mode_get();
 
 	if (mode < 0)
 		return mode;
@@ -2472,6 +2498,7 @@ static void sony_nc_backlight_ng_read_limits(int handle,
 {
 	u64 offset;
 	int i;
+	int lvl_table_len = 0;
 	u8 min = 0xff, max = 0x00;
 	unsigned char buffer[32] = { 0 };
 
@@ -2480,8 +2507,6 @@ static void sony_nc_backlight_ng_read_limits(int handle,
 	props->maxlvl = 0xff;
 
 	offset = sony_find_snc_handle(handle);
-	if (offset < 0)
-		return;
 
 	/* try to read the boundaries from ACPI tables, if we fail the above
 	 * defaults should be reasonable
@@ -2491,11 +2516,21 @@ static void sony_nc_backlight_ng_read_limits(int handle,
 	if (i < 0)
 		return;
 
+	switch (handle) {
+	case 0x012f:
+	case 0x0137:
+		lvl_table_len = 9;
+		break;
+	case 0x143:
+		lvl_table_len = 16;
+		break;
+	}
+
 	/* the buffer lists brightness levels available, brightness levels are
 	 * from position 0 to 8 in the array, other values are used by ALS
 	 * control.
 	 */
-	for (i = 0; i < 9 && i < ARRAY_SIZE(buffer); i++) {
+	for (i = 0; i < lvl_table_len && i < ARRAY_SIZE(buffer); i++) {
 
 		dprintk("Brightness level: %d\n", buffer[i]);
 
@@ -2520,16 +2555,24 @@ static void sony_nc_backlight_setup(void)
 	const struct backlight_ops *ops = NULL;
 	struct backlight_properties props;
 
-	if (sony_find_snc_handle(0x12f) != -1) {
+	if (sony_find_snc_handle(0x12f) >= 0) {
 		ops = &sony_backlight_ng_ops;
+		sony_bl_props.cmd_base = 0x0100;
 		sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
 		max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
 
-	} else if (sony_find_snc_handle(0x137) != -1) {
+	} else if (sony_find_snc_handle(0x137) >= 0) {
 		ops = &sony_backlight_ng_ops;
+		sony_bl_props.cmd_base = 0x0100;
 		sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
 		max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
 
+	} else if (sony_find_snc_handle(0x143) >= 0) {
+		ops = &sony_backlight_ng_ops;
+		sony_bl_props.cmd_base = 0x3000;
+		sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props);
+		max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
+
 	} else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
 						&unused))) {
 		ops = &sony_backlight_ops;
@@ -2597,6 +2640,12 @@ static int sony_nc_add(struct acpi_device *device)
 		}
 	}
 
+	result = sony_laptop_setup_input(device);
+	if (result) {
+		pr_err("Unable to create input devices\n");
+		goto outplatform;
+	}
+
 	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
 					 &handle))) {
 		int arg = 1;
@@ -2614,12 +2663,6 @@ static int sony_nc_add(struct acpi_device *device)
 	}
 
 	/* setup input devices and helper fifo */
-	result = sony_laptop_setup_input(device);
-	if (result) {
-		pr_err("Unable to create input devices\n");
-		goto outsnc;
-	}
-
 	if (acpi_video_backlight_support()) {
 		pr_info("brightness ignored, must be controlled by ACPI video driver\n");
 	} else {
@@ -2667,22 +2710,21 @@ static int sony_nc_add(struct acpi_device *device)
 
 	return 0;
 
-      out_sysfs:
+out_sysfs:
 	for (item = sony_nc_values; item->name; ++item) {
 		device_remove_file(&sony_pf_device->dev, &item->devattr);
 	}
 	sony_nc_backlight_cleanup();
-
-	sony_laptop_remove_input();
-
-      outsnc:
 	sony_nc_function_cleanup(sony_pf_device);
 	sony_nc_handles_cleanup(sony_pf_device);
 
-      outpresent:
+outplatform:
+	sony_laptop_remove_input();
+
+outpresent:
 	sony_pf_remove();
 
-      outwalk:
+outwalk:
 	sony_nc_rfkill_cleanup();
 	return result;
 }
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 8b5610d..9cb7cd8 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -277,7 +277,7 @@ struct ibm_struct {
 	int (*write) (char *);
 	void (*exit) (void);
 	void (*resume) (void);
-	void (*suspend) (pm_message_t state);
+	void (*suspend) (void);
 	void (*shutdown) (void);
 
 	struct list_head all_drivers;
@@ -392,34 +392,35 @@ static bool tpacpi_uwb_emulstate;
  *  Debugging helpers
  */
 
-#define dbg_printk(a_dbg_level, format, arg...)				\
+#define DEBUG
+
+#define tp_dbg(a_dbg_level, format, ...)				\
 do {									\
 	if (dbg_level & (a_dbg_level))					\
-		printk(KERN_DEBUG pr_fmt("%s: " format),		\
-		       __func__, ##arg);				\
+		pr_debug("%s: " format, __func__, ##__VA_ARGS__);	\
 } while (0)
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUG
-#define vdbg_printk dbg_printk
+#define tp_vdbg tp_dbg
 static const char *str_supported(int is_supported);
 #else
 static inline const char *str_supported(int is_supported) { return ""; }
-#define vdbg_printk(a_dbg_level, format, arg...)	\
-	no_printk(format, ##arg)
+#define tp_vdbg(a_dbg_level, format, ...)				\
+	eliminated_printk(format, ##__VA_ARGS__)
 #endif
 
 static void tpacpi_log_usertask(const char * const what)
 {
-	printk(KERN_DEBUG pr_fmt("%s: access by process with PID %d\n"),
-	       what, task_tgid_vnr(current));
+	pr_debug("%s: access by process with PID %d\n",
+		 what, task_tgid_vnr(current));
 }
 
-#define tpacpi_disclose_usertask(what, format, arg...)			\
+#define tpacpi_disclose_usertask(what, format, ...)			\
 do {									\
 	if (unlikely((dbg_level & TPACPI_DBG_DISCLOSETASK) &&		\
 		     (tpacpi_lifecycle == TPACPI_LIFE_RUNNING))) {	\
-		printk(KERN_DEBUG pr_fmt("%s: PID %d: " format),	\
-		       what, task_tgid_vnr(current), ## arg);		\
+		pr_debug("%s: PID %d: " format,				\
+			 what, task_tgid_vnr(current), ##__VA_ARGS__);	\
 	}								\
 } while (0)
 
@@ -680,21 +681,20 @@ static void __init drv_acpi_handle_init(const char *name,
 	int i;
 	acpi_status status;
 
-	vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n",
+	tp_vdbg(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n",
 		name);
 
 	for (i = 0; i < num_paths; i++) {
 		status = acpi_get_handle(parent, paths[i], handle);
 		if (ACPI_SUCCESS(status)) {
-			dbg_printk(TPACPI_DBG_INIT,
-				   "Found ACPI handle %s for %s\n",
-				   paths[i], name);
+			tp_dbg(TPACPI_DBG_INIT,
+			       "Found ACPI handle %s for %s\n",
+			       paths[i], name);
 			return;
 		}
 	}
 
-	vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n",
-		    name);
+	tp_vdbg(TPACPI_DBG_INIT, "ACPI handle for %s not found\n", name);
 	*handle = NULL;
 }
 
@@ -714,9 +714,9 @@ static void __init tpacpi_acpi_handle_locate(const char *name,
 	acpi_handle device_found;
 
 	BUG_ON(!name || !hid || !handle);
-	vdbg_printk(TPACPI_DBG_INIT,
-			"trying to locate ACPI handle for %s, using HID %s\n",
-			name, hid);
+	tp_vdbg(TPACPI_DBG_INIT,
+		"trying to locate ACPI handle for %s, using HID %s\n",
+		name, hid);
 
 	memset(&device_found, 0, sizeof(device_found));
 	status = acpi_get_devices(hid, tpacpi_acpi_handle_locate_callback,
@@ -726,12 +726,11 @@ static void __init tpacpi_acpi_handle_locate(const char *name,
 
 	if (ACPI_SUCCESS(status)) {
 		*handle = device_found;
-		dbg_printk(TPACPI_DBG_INIT,
-			   "Found ACPI handle for %s\n", name);
+		tp_dbg(TPACPI_DBG_INIT, "Found ACPI handle for %s\n", name);
 	} else {
-		vdbg_printk(TPACPI_DBG_INIT,
-			    "Could not locate an ACPI handle for %s: %s\n",
-			    name, acpi_format_exception(status));
+		tp_vdbg(TPACPI_DBG_INIT,
+			"Could not locate an ACPI handle for %s: %s\n",
+			name, acpi_format_exception(status));
 	}
 }
 
@@ -758,8 +757,7 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
 	if (!*ibm->acpi->handle)
 		return 0;
 
-	vdbg_printk(TPACPI_DBG_INIT,
-		"setting up ACPI notify for %s\n", ibm->name);
+	tp_vdbg(TPACPI_DBG_INIT, "setting up ACPI notify for %s\n", ibm->name);
 
 	rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
 	if (rc < 0) {
@@ -797,8 +795,8 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
 {
 	int rc;
 
-	dbg_printk(TPACPI_DBG_INIT,
-		"registering %s as an ACPI driver\n", ibm->name);
+	tp_dbg(TPACPI_DBG_INIT, "registering %s as an ACPI driver\n",
+	       ibm->name);
 
 	BUG_ON(!ibm->acpi);
 
@@ -922,8 +920,7 @@ static struct input_dev *tpacpi_inputdev;
 static struct mutex tpacpi_inputdev_send_mutex;
 static LIST_HEAD(tpacpi_all_drivers);
 
-static int tpacpi_suspend_handler(struct platform_device *pdev,
-				  pm_message_t state)
+static int tpacpi_suspend_handler(struct device *dev)
 {
 	struct ibm_struct *ibm, *itmp;
 
@@ -931,13 +928,13 @@ static int tpacpi_suspend_handler(struct platform_device *pdev,
 				 &tpacpi_all_drivers,
 				 all_drivers) {
 		if (ibm->suspend)
-			(ibm->suspend)(state);
+			(ibm->suspend)();
 	}
 
 	return 0;
 }
 
-static int tpacpi_resume_handler(struct platform_device *pdev)
+static int tpacpi_resume_handler(struct device *dev)
 {
 	struct ibm_struct *ibm, *itmp;
 
@@ -951,6 +948,9 @@ static int tpacpi_resume_handler(struct platform_device *pdev)
 	return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(tpacpi_pm,
+			 tpacpi_suspend_handler, tpacpi_resume_handler);
+
 static void tpacpi_shutdown_handler(struct platform_device *pdev)
 {
 	struct ibm_struct *ibm, *itmp;
@@ -967,9 +967,8 @@ static struct platform_driver tpacpi_pdriver = {
 	.driver = {
 		.name = TPACPI_DRVR_NAME,
 		.owner = THIS_MODULE,
+		.pm = &tpacpi_pm,
 	},
-	.suspend = tpacpi_suspend_handler,
-	.resume = tpacpi_resume_handler,
 	.shutdown = tpacpi_shutdown_handler,
 };
 
@@ -1215,9 +1214,8 @@ static int tpacpi_rfk_hook_set_block(void *data, bool blocked)
 	struct tpacpi_rfk *tp_rfk = data;
 	int res;
 
-	dbg_printk(TPACPI_DBG_RFKILL,
-		   "request to change radio state to %s\n",
-		   blocked ? "blocked" : "unblocked");
+	tp_dbg(TPACPI_DBG_RFKILL, "request to change radio state to %s\n",
+	       blocked ? "blocked" : "unblocked");
 
 	/* try to set radio state */
 	res = (tp_rfk->ops->set_status)(blocked ?
@@ -3016,8 +3014,8 @@ static void hotkey_exit(void)
 
 	kfree(hotkey_keycode_map);
 
-	dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY,
-		   "restoring original HKEY status and mask\n");
+	tp_dbg(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY,
+	       "restoring original HKEY status and mask\n");
 	/* yes, there is a bitwise or below, we want the
 	 * functions to be called even if one of them fail */
 	if (((tp_features.hotkey_mask &&
@@ -3223,8 +3221,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 	unsigned long quirks;
 	unsigned long keymap_id;
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
-			"initializing hotkey subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
+		"initializing hotkey subdriver\n");
 
 	BUG_ON(!tpacpi_inputdev);
 	BUG_ON(tpacpi_inputdev->open != NULL ||
@@ -3241,9 +3239,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 	/* hotkey not supported on 570 */
 	tp_features.hotkey = hkey_handle != NULL;
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
-		"hotkeys are %s\n",
-		str_supported(tp_features.hotkey));
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
+		"hotkeys are %s\n", str_supported(tp_features.hotkey));
 
 	if (!tp_features.hotkey)
 		return 1;
@@ -3279,7 +3276,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 			 * MHKV 0x100 in A31, R40, R40e,
 			 * T4x, X31, and later
 			 */
-			vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
+			tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
 				"firmware HKEY interface version: 0x%x\n",
 				hkeyv);
 
@@ -3297,7 +3294,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 		}
 	}
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
 		"hotkey masks are %s\n",
 		str_supported(tp_features.hotkey_mask));
 
@@ -3368,8 +3365,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 	keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable,
 					ARRAY_SIZE(tpacpi_keymap_qtable));
 	BUG_ON(keymap_id >= ARRAY_SIZE(tpacpi_keymaps));
-	dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
-		   "using keymap number %lu\n", keymap_id);
+	tp_dbg(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
+	       "using keymap number %lu\n", keymap_id);
 
 	memcpy(hotkey_keycode_map, &tpacpi_keymaps[keymap_id],
 		TPACPI_HOTKEY_MAP_SIZE);
@@ -3424,13 +3421,13 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 				& ~hotkey_all_mask
 				& ~hotkey_reserved_mask;
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
-		    "hotkey source mask 0x%08x, polling freq %u\n",
-		    hotkey_source_mask, hotkey_poll_freq);
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
+		"hotkey source mask 0x%08x, polling freq %u\n",
+		hotkey_source_mask, hotkey_poll_freq);
 #endif
 
-	dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
-			"enabling firmware HKEY event interface...\n");
+	tp_dbg(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
+	       "enabling firmware HKEY event interface...\n");
 	res = hotkey_status_set(true);
 	if (res) {
 		hotkey_exit();
@@ -3445,14 +3442,13 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 	}
 	hotkey_user_mask = (hotkey_acpi_mask | hotkey_source_mask)
 				& ~hotkey_reserved_mask;
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
 		"initial masks: user=0x%08x, fw=0x%08x, poll=0x%08x\n",
 		hotkey_user_mask, hotkey_acpi_mask, hotkey_source_mask);
 
-	dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
-			"legacy ibm/hotkey event reporting over procfs %s\n",
-			(hotkey_report_mode < 2) ?
-				"enabled" : "disabled");
+	tp_dbg(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
+	       "legacy ibm/hotkey event reporting over procfs %s\n",
+	       (hotkey_report_mode < 2) ? "enabled" : "disabled");
 
 	tpacpi_inputdev->open = &hotkey_inputdev_open;
 	tpacpi_inputdev->close = &hotkey_inputdev_close;
@@ -3758,7 +3754,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
 	}
 }
 
-static void hotkey_suspend(pm_message_t state)
+static void hotkey_suspend(void)
 {
 	/* Do these on suspend, we get the events on early resume! */
 	hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE;
@@ -3936,9 +3932,8 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state)
 {
 	int status;
 
-	vdbg_printk(TPACPI_DBG_RFKILL,
-		"will attempt to %s bluetooth\n",
-		(state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable");
+	tp_vdbg(TPACPI_DBG_RFKILL, "will attempt to %s bluetooth\n",
+		state == TPACPI_RFK_RADIO_ON ? "enable" : "disable");
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
 	if (dbg_bluetoothemul) {
@@ -4003,8 +3998,7 @@ static void bluetooth_shutdown(void)
 			TP_ACPI_BLTH_SAVE_STATE))
 		pr_notice("failed to save bluetooth state to NVRAM\n");
 	else
-		vdbg_printk(TPACPI_DBG_RFKILL,
-			"bluetooth state saved to NVRAM\n");
+		tp_vdbg(TPACPI_DBG_RFKILL, "bluetooth state saved to NVRAM\n");
 }
 
 static void bluetooth_exit(void)
@@ -4022,8 +4016,8 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
 	int res;
 	int status = 0;
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
-			"initializing bluetooth subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
+		"initializing bluetooth subdriver\n");
 
 	TPACPI_ACPIHANDLE_INIT(hkey);
 
@@ -4032,10 +4026,9 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
 	tp_features.bluetooth = hkey_handle &&
 	    acpi_evalf(hkey_handle, &status, "GBDC", "qd");
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
 		"bluetooth is %s, status 0x%02x\n",
-		str_supported(tp_features.bluetooth),
-		status);
+		str_supported(tp_features.bluetooth), status);
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
 	if (dbg_bluetoothemul) {
@@ -4047,8 +4040,8 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
 	    !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) {
 		/* no bluetooth hardware present in system */
 		tp_features.bluetooth = 0;
-		dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
-			   "bluetooth hardware not installed\n");
+		tp_dbg(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
+		       "bluetooth hardware not installed\n");
 	}
 
 	if (!tp_features.bluetooth)
@@ -4126,9 +4119,8 @@ static int wan_set_status(enum tpacpi_rfkill_state state)
 {
 	int status;
 
-	vdbg_printk(TPACPI_DBG_RFKILL,
-		"will attempt to %s wwan\n",
-		(state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable");
+	tp_vdbg(TPACPI_DBG_RFKILL, "will attempt to %s wwan\n",
+		state == TPACPI_RFK_RADIO_ON ? "enable" : "disable");
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
 	if (dbg_wwanemul) {
@@ -4193,8 +4185,7 @@ static void wan_shutdown(void)
 			TP_ACPI_WGSV_SAVE_STATE))
 		pr_notice("failed to save WWAN state to NVRAM\n");
 	else
-		vdbg_printk(TPACPI_DBG_RFKILL,
-			"WWAN state saved to NVRAM\n");
+		tp_vdbg(TPACPI_DBG_RFKILL, "WWAN state saved to NVRAM\n");
 }
 
 static void wan_exit(void)
@@ -4212,18 +4203,17 @@ static int __init wan_init(struct ibm_init_struct *iibm)
 	int res;
 	int status = 0;
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
-			"initializing wan subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
+		"initializing wan subdriver\n");
 
 	TPACPI_ACPIHANDLE_INIT(hkey);
 
 	tp_features.wan = hkey_handle &&
 	    acpi_evalf(hkey_handle, &status, "GWAN", "qd");
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
 		"wan is %s, status 0x%02x\n",
-		str_supported(tp_features.wan),
-		status);
+		str_supported(tp_features.wan), status);
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
 	if (dbg_wwanemul) {
@@ -4235,8 +4225,8 @@ static int __init wan_init(struct ibm_init_struct *iibm)
 	    !(status & TP_ACPI_WANCARD_HWPRESENT)) {
 		/* no wan hardware present in system */
 		tp_features.wan = 0;
-		dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
-			   "wan hardware not installed\n");
+		tp_dbg(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
+		       "wan hardware not installed\n");
 	}
 
 	if (!tp_features.wan)
@@ -4313,9 +4303,8 @@ static int uwb_set_status(enum tpacpi_rfkill_state state)
 {
 	int status;
 
-	vdbg_printk(TPACPI_DBG_RFKILL,
-		"will attempt to %s UWB\n",
-		(state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable");
+	tp_vdbg(TPACPI_DBG_RFKILL, "will attempt to %s UWB\n",
+		state == TPACPI_RFK_RADIO_ON ? "enable" : "disable");
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
 	if (dbg_uwbemul) {
@@ -4352,18 +4341,17 @@ static int __init uwb_init(struct ibm_init_struct *iibm)
 	int res;
 	int status = 0;
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
-			"initializing uwb subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
+		"initializing uwb subdriver\n");
 
 	TPACPI_ACPIHANDLE_INIT(hkey);
 
 	tp_features.uwb = hkey_handle &&
 	    acpi_evalf(hkey_handle, &status, "GUWB", "qd");
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
 		"uwb is %s, status 0x%02x\n",
-		str_supported(tp_features.uwb),
-		status);
+		str_supported(tp_features.uwb), status);
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
 	if (dbg_uwbemul) {
@@ -4375,8 +4363,7 @@ static int __init uwb_init(struct ibm_init_struct *iibm)
 	    !(status & TP_ACPI_UWB_HWPRESENT)) {
 		/* no uwb hardware present in system */
 		tp_features.uwb = 0;
-		dbg_printk(TPACPI_DBG_INIT,
-			   "uwb hardware not installed\n");
+		tp_dbg(TPACPI_DBG_INIT, "uwb hardware not installed\n");
 	}
 
 	if (!tp_features.uwb)
@@ -4444,7 +4431,7 @@ static int __init video_init(struct ibm_init_struct *iibm)
 {
 	int ivga;
 
-	vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT, "initializing video subdriver\n");
 
 	TPACPI_ACPIHANDLE_INIT(vid);
 	if (tpacpi_is_ibm())
@@ -4469,7 +4456,7 @@ static int __init video_init(struct ibm_init_struct *iibm)
 		/* all others */
 		video_supported = TPACPI_VIDEO_NEW;
 
-	vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n",
+	tp_vdbg(TPACPI_DBG_INIT, "video is %s, mode %d\n",
 		str_supported(video_supported != TPACPI_VIDEO_NONE),
 		video_supported);
 
@@ -4478,8 +4465,7 @@ static int __init video_init(struct ibm_init_struct *iibm)
 
 static void video_exit(void)
 {
-	dbg_printk(TPACPI_DBG_EXIT,
-		   "restoring original video autoswitch mode\n");
+	tp_dbg(TPACPI_DBG_EXIT, "restoring original video autoswitch mode\n");
 	if (video_autosw_set(video_orig_autosw))
 		pr_err("error while trying to restore original "
 			"video autoswitch mode\n");
@@ -4835,7 +4821,7 @@ static int __init light_init(struct ibm_init_struct *iibm)
 {
 	int rc;
 
-	vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT, "initializing light subdriver\n");
 
 	if (tpacpi_is_ibm()) {
 		TPACPI_ACPIHANDLE_INIT(ledb);
@@ -4853,7 +4839,7 @@ static int __init light_init(struct ibm_init_struct *iibm)
 		tp_features.light_status =
 			acpi_evalf(ec_handle, NULL, "KBLT", "qv");
 
-	vdbg_printk(TPACPI_DBG_INIT, "light is %s, light status is %s\n",
+	tp_vdbg(TPACPI_DBG_INIT, "light is %s, light status is %s\n",
 		str_supported(tp_features.light),
 		str_supported(tp_features.light_status));
 
@@ -4955,12 +4941,11 @@ static int __init cmos_init(struct ibm_init_struct *iibm)
 {
 	int res;
 
-	vdbg_printk(TPACPI_DBG_INIT,
-		"initializing cmos commands subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT, "initializing cmos commands subdriver\n");
 
 	TPACPI_ACPIHANDLE_INIT(cmos);
 
-	vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
+	tp_vdbg(TPACPI_DBG_INIT, "cmos commands are %s\n",
 		str_supported(cmos_handle != NULL));
 
 	res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
@@ -5327,11 +5312,11 @@ static int __init led_init(struct ibm_init_struct *iibm)
 	int rc;
 	unsigned long useful_leds;
 
-	vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT, "initializing LED subdriver\n");
 
 	led_supported = led_init_detect_mode();
 
-	vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
+	tp_vdbg(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
 		str_supported(led_supported), led_supported);
 
 	if (led_supported == TPACPI_LED_NONE)
@@ -5450,11 +5435,11 @@ static int __init beep_init(struct ibm_init_struct *iibm)
 {
 	unsigned long quirks;
 
-	vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT, "initializing beep subdriver\n");
 
 	TPACPI_ACPIHANDLE_INIT(beep);
 
-	vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
+	tp_vdbg(TPACPI_DBG_INIT, "beep is %s\n",
 		str_supported(beep_handle != NULL));
 
 	quirks = tpacpi_check_quirks(beep_quirk_table,
@@ -5729,7 +5714,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
 	int acpi_tmp7;
 	int res;
 
-	vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT, "initializing thermal subdriver\n");
 
 	acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
 
@@ -5787,7 +5772,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
 		thermal_read_mode = TPACPI_THERMAL_NONE;
 	}
 
-	vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n",
+	tp_vdbg(TPACPI_DBG_INIT, "thermal is %s, mode %d\n",
 		str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
 		thermal_read_mode);
 
@@ -5932,7 +5917,7 @@ static void tpacpi_brightness_checkpoint_nvram(void)
 	if (brightness_mode != TPACPI_BRGHT_MODE_ECNVRAM)
 		return;
 
-	vdbg_printk(TPACPI_DBG_BRGHT,
+	tp_vdbg(TPACPI_DBG_BRGHT,
 		"trying to checkpoint backlight level to NVRAM...\n");
 
 	if (mutex_lock_killable(&brightness_mutex) < 0)
@@ -5950,13 +5935,13 @@ static void tpacpi_brightness_checkpoint_nvram(void)
 				TP_NVRAM_POS_LEVEL_BRIGHTNESS);
 		b_nvram |= lec;
 		nvram_write_byte(b_nvram, TP_NVRAM_ADDR_BRIGHTNESS);
-		dbg_printk(TPACPI_DBG_BRGHT,
-			   "updated NVRAM backlight level to %u (0x%02x)\n",
-			   (unsigned int) lec, (unsigned int) b_nvram);
+		tp_dbg(TPACPI_DBG_BRGHT,
+		       "updated NVRAM backlight level to %u (0x%02x)\n",
+		       (unsigned int)lec, (unsigned int)b_nvram);
 	} else
-		vdbg_printk(TPACPI_DBG_BRGHT,
-			   "NVRAM backlight level already is %u (0x%02x)\n",
-			   (unsigned int) lec, (unsigned int) b_nvram);
+		tp_vdbg(TPACPI_DBG_BRGHT,
+			"NVRAM backlight level already is %u (0x%02x)\n",
+			(unsigned int)lec, (unsigned int)b_nvram);
 
 unlock:
 	mutex_unlock(&brightness_mutex);
@@ -6031,8 +6016,7 @@ static int brightness_set(unsigned int value)
 	if (value > bright_maxlvl || value < 0)
 		return -EINVAL;
 
-	vdbg_printk(TPACPI_DBG_BRGHT,
-			"set backlight level to %d\n", value);
+	tp_vdbg(TPACPI_DBG_BRGHT, "set backlight level to %d\n", value);
 
 	res = mutex_lock_killable(&brightness_mutex);
 	if (res < 0)
@@ -6063,9 +6047,8 @@ static int brightness_update_status(struct backlight_device *bd)
 		 bd->props.power == FB_BLANK_UNBLANK) ?
 				bd->props.brightness : 0;
 
-	dbg_printk(TPACPI_DBG_BRGHT,
-			"backlight: attempt to set level to %d\n",
-			level);
+	tp_dbg(TPACPI_DBG_BRGHT, "backlight: attempt to set level to %d\n",
+	       level);
 
 	/* it is the backlight class's job (caller) to handle
 	 * EINTR and other errors properly */
@@ -6187,8 +6170,8 @@ static void __init tpacpi_detect_brightness_capabilities(void)
 {
 	unsigned int b;
 
-	vdbg_printk(TPACPI_DBG_INIT,
-		    "detecting firmware brightness interface capabilities\n");
+	tp_vdbg(TPACPI_DBG_INIT,
+		"detecting firmware brightness interface capabilities\n");
 
 	/* we could run a quirks check here (same table used by
 	 * brightness_init) if needed */
@@ -6223,7 +6206,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 	int b;
 	unsigned long quirks;
 
-	vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
 
 	mutex_init(&brightness_mutex);
 
@@ -6237,9 +6220,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 		return 1;
 
 	if (!brightness_enable) {
-		dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
-			   "brightness support disabled by "
-			   "module parameter\n");
+		tp_dbg(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
+		       "brightness support disabled by module parameter\n");
 		return 1;
 	}
 
@@ -6276,9 +6258,9 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 		else
 			brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP;
 
-		dbg_printk(TPACPI_DBG_BRGHT,
-			   "driver auto-selected brightness_mode=%d\n",
-			   brightness_mode);
+		tp_dbg(TPACPI_DBG_BRGHT,
+		       "driver auto-selected brightness_mode=%d\n",
+		       brightness_mode);
 	}
 
 	/* Safety */
@@ -6304,8 +6286,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 		pr_err("Could not register backlight device\n");
 		return rc;
 	}
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
-			"brightness is supported\n");
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
+		"brightness is supported\n");
 
 	if (quirks & TPACPI_BRGHT_Q_ASK) {
 		pr_notice("brightness: will use unverified default: "
@@ -6320,16 +6302,15 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 	 * it in place just in case */
 	backlight_update_status(ibm_backlight_device);
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
-			"brightness: registering brightness hotkeys "
-			"as change notification\n");
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
+		"brightness: registering brightness hotkeys as change notification\n");
 	tpacpi_hotkey_driver_mask_set(hotkey_driver_mask
 				| TP_ACPI_HKEY_BRGHTUP_MASK
 				| TP_ACPI_HKEY_BRGHTDWN_MASK);
 	return 0;
 }
 
-static void brightness_suspend(pm_message_t state)
+static void brightness_suspend(void)
 {
 	tpacpi_brightness_checkpoint_nvram();
 }
@@ -6342,8 +6323,8 @@ static void brightness_shutdown(void)
 static void brightness_exit(void)
 {
 	if (ibm_backlight_device) {
-		vdbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_BRGHT,
-			    "calling backlight_device_unregister()\n");
+		tp_vdbg(TPACPI_DBG_EXIT | TPACPI_DBG_BRGHT,
+			"calling backlight_device_unregister()\n");
 		backlight_device_unregister(ibm_backlight_device);
 	}
 
@@ -6506,7 +6487,7 @@ static void tpacpi_volume_checkpoint_nvram(void)
 	if (!volume_control_allowed)
 		return;
 
-	vdbg_printk(TPACPI_DBG_MIXER,
+	tp_vdbg(TPACPI_DBG_MIXER,
 		"trying to checkpoint mixer state to NVRAM...\n");
 
 	if (tp_features.mixer_no_level_control)
@@ -6527,13 +6508,13 @@ static void tpacpi_volume_checkpoint_nvram(void)
 		b_nvram &= ~ec_mask;
 		b_nvram |= lec;
 		nvram_write_byte(b_nvram, TP_NVRAM_ADDR_MIXER);
-		dbg_printk(TPACPI_DBG_MIXER,
-			   "updated NVRAM mixer status to 0x%02x (0x%02x)\n",
-			   (unsigned int) lec, (unsigned int) b_nvram);
+		tp_dbg(TPACPI_DBG_MIXER,
+		       "updated NVRAM mixer status to 0x%02x (0x%02x)\n",
+		       (unsigned int)lec, (unsigned int)b_nvram);
 	} else {
-		vdbg_printk(TPACPI_DBG_MIXER,
-			   "NVRAM mixer status already is 0x%02x (0x%02x)\n",
-			   (unsigned int) lec, (unsigned int) b_nvram);
+		tp_vdbg(TPACPI_DBG_MIXER,
+			"NVRAM mixer status already is 0x%02x (0x%02x)\n",
+			(unsigned int)lec, (unsigned int)b_nvram);
 	}
 
 unlock:
@@ -6549,7 +6530,7 @@ static int volume_get_status_ec(u8 *status)
 
 	*status = s;
 
-	dbg_printk(TPACPI_DBG_MIXER, "status 0x%02x\n", s);
+	tp_dbg(TPACPI_DBG_MIXER, "status 0x%02x\n", s);
 
 	return 0;
 }
@@ -6564,7 +6545,7 @@ static int volume_set_status_ec(const u8 status)
 	if (!acpi_ec_write(TP_EC_AUDIO, status))
 		return -EIO;
 
-	dbg_printk(TPACPI_DBG_MIXER, "set EC mixer to 0x%02x\n", status);
+	tp_dbg(TPACPI_DBG_MIXER, "set EC mixer to 0x%02x\n", status);
 
 	return 0;
 }
@@ -6603,8 +6584,7 @@ unlock:
 
 static int volume_alsa_set_mute(const bool mute)
 {
-	dbg_printk(TPACPI_DBG_MIXER, "ALSA: trying to %smute\n",
-		   (mute) ? "" : "un");
+	tp_dbg(TPACPI_DBG_MIXER, "ALSA: trying to %smute\n", mute ? "" : "un");
 	return __volume_set_mute_ec(mute);
 }
 
@@ -6612,8 +6592,7 @@ static int volume_set_mute(const bool mute)
 {
 	int rc;
 
-	dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n",
-		   (mute) ? "" : "un");
+	tp_dbg(TPACPI_DBG_MIXER, "trying to %smute\n", mute ? "" : "un");
 
 	rc = __volume_set_mute_ec(mute);
 	return (rc < 0) ? rc : 0;
@@ -6650,8 +6629,8 @@ unlock:
 
 static int volume_alsa_set_volume(const u8 vol)
 {
-	dbg_printk(TPACPI_DBG_MIXER,
-		   "ALSA: trying to set volume level to %hu\n", vol);
+	tp_dbg(TPACPI_DBG_MIXER,
+	       "ALSA: trying to set volume level to %hu\n", vol);
 	return __volume_set_volume_ec(vol);
 }
 
@@ -6748,7 +6727,7 @@ static struct snd_kcontrol_new volume_alsa_control_mute __devinitdata = {
 	.get = volume_alsa_mute_get,
 };
 
-static void volume_suspend(pm_message_t state)
+static void volume_suspend(void)
 {
 	tpacpi_volume_checkpoint_nvram();
 }
@@ -6879,7 +6858,7 @@ static int __init volume_init(struct ibm_init_struct *iibm)
 	unsigned long quirks;
 	int rc;
 
-	vdbg_printk(TPACPI_DBG_INIT, "initializing volume subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT, "initializing volume subdriver\n");
 
 	mutex_init(&volume_mutex);
 
@@ -6905,9 +6884,8 @@ static int __init volume_init(struct ibm_init_struct *iibm)
 	 * When disabled, don't install the subdriver at all
 	 */
 	if (!alsa_enable) {
-		vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
-			    "ALSA mixer disabled by parameter, "
-			    "not loading volume subdriver...\n");
+		tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
+			"ALSA mixer disabled by parameter, not loading volume subdriver...\n");
 		return 1;
 	}
 
@@ -6934,26 +6912,26 @@ static int __init volume_init(struct ibm_init_struct *iibm)
 	}
 
 	if (volume_capabilities != TPACPI_VOL_CAP_AUTO)
-		dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
-				"using user-supplied volume_capabilities=%d\n",
-				volume_capabilities);
+		tp_dbg(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
+		       "using user-supplied volume_capabilities=%d\n",
+		       volume_capabilities);
 
 	if (volume_mode == TPACPI_VOL_MODE_AUTO ||
 	    volume_mode == TPACPI_VOL_MODE_MAX) {
 		volume_mode = TPACPI_VOL_MODE_ECNVRAM;
 
-		dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
-				"driver auto-selected volume_mode=%d\n",
-				volume_mode);
+		tp_dbg(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
+		       "driver auto-selected volume_mode=%d\n",
+		       volume_mode);
 	} else {
-		dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
-				"using user-supplied volume_mode=%d\n",
-				volume_mode);
+		tp_dbg(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
+		       "using user-supplied volume_mode=%d\n",
+		       volume_mode);
 	}
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
-			"mute is supported, volume control is %s\n",
-			str_supported(!tp_features.mixer_no_level_control));
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
+		"mute is supported, volume control is %s\n",
+		str_supported(!tp_features.mixer_no_level_control));
 
 	rc = volume_create_alsa_mixer();
 	if (rc) {
@@ -6966,7 +6944,7 @@ static int __init volume_init(struct ibm_init_struct *iibm)
 			"override (read/write)" :
 			"monitor (read only)");
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
 		"registering volume hotkeys as change notification\n");
 	tpacpi_hotkey_driver_mask_set(hotkey_driver_mask
 			| TP_ACPI_HKEY_VOLUP_MASK
@@ -7523,7 +7501,7 @@ static int fan_set_level(int level)
 		return -ENXIO;
 	}
 
-	vdbg_printk(TPACPI_DBG_FAN,
+	tp_vdbg(TPACPI_DBG_FAN,
 		"fan control: set fan control register to 0x%02x\n", level);
 	return 0;
 }
@@ -7604,9 +7582,8 @@ static int fan_set_enable(void)
 	mutex_unlock(&fan_mutex);
 
 	if (!rc)
-		vdbg_printk(TPACPI_DBG_FAN,
-			"fan control: set fan control register to 0x%02x\n",
-			s);
+		tp_vdbg(TPACPI_DBG_FAN,
+			"fan control: set fan control register to 0x%02x\n", s);
 	return rc;
 }
 
@@ -7644,7 +7621,7 @@ static int fan_set_disable(void)
 	}
 
 	if (!rc)
-		vdbg_printk(TPACPI_DBG_FAN,
+		tp_vdbg(TPACPI_DBG_FAN,
 			"fan control: set fan control register to 0\n");
 
 	mutex_unlock(&fan_mutex);
@@ -7980,8 +7957,8 @@ static int __init fan_init(struct ibm_init_struct *iibm)
 	int rc;
 	unsigned long quirks;
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
-			"initializing fan subdriver\n");
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
+		"initializing fan subdriver\n");
 
 	mutex_init(&fan_mutex);
 	fan_status_access_mode = TPACPI_FAN_NONE;
@@ -8014,8 +7991,8 @@ static int __init fan_init(struct ibm_init_struct *iibm)
 				fan_quirk1_setup();
 			if (quirks & TPACPI_FAN_2FAN) {
 				tp_features.second_fan = 1;
-				dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
-					"secondary fan support enabled\n");
+				tp_dbg(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
+				       "secondary fan support enabled\n");
 			}
 		} else {
 			pr_err("ThinkPad ACPI EC access misbehaving, "
@@ -8051,18 +8028,18 @@ static int __init fan_init(struct ibm_init_struct *iibm)
 		}
 	}
 
-	vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
+	tp_vdbg(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
 		"fan is %s, modes %d, %d\n",
 		str_supported(fan_status_access_mode != TPACPI_FAN_NONE ||
-		  fan_control_access_mode != TPACPI_FAN_WR_NONE),
+			      fan_control_access_mode != TPACPI_FAN_WR_NONE),
 		fan_status_access_mode, fan_control_access_mode);
 
 	/* fan control master switch */
 	if (!fan_control_allowed) {
 		fan_control_access_mode = TPACPI_FAN_WR_NONE;
 		fan_control_commands = 0;
-		dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
-			   "fan control features disabled by parameter\n");
+		tp_dbg(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
+		       "fan control features disabled by parameter\n");
 	}
 
 	/* update fan_control_desired_level */
@@ -8095,8 +8072,8 @@ static int __init fan_init(struct ibm_init_struct *iibm)
 
 static void fan_exit(void)
 {
-	vdbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_FAN,
-		    "cancelling any pending fan watchdog tasks\n");
+	tp_vdbg(TPACPI_DBG_EXIT | TPACPI_DBG_FAN,
+		"cancelling any pending fan watchdog tasks\n");
 
 	/* FIXME: can we really do this unconditionally? */
 	sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group);
@@ -8107,7 +8084,7 @@ static void fan_exit(void)
 	flush_workqueue(tpacpi_wq);
 }
 
-static void fan_suspend(pm_message_t state)
+static void fan_suspend(void)
 {
 	int rc;
 
@@ -8450,13 +8427,13 @@ static const char * __init str_supported(int is_supported)
 
 static void ibm_exit(struct ibm_struct *ibm)
 {
-	dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
+	tp_dbg(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
 
 	list_del_init(&ibm->all_drivers);
 
 	if (ibm->flags.acpi_notify_installed) {
-		dbg_printk(TPACPI_DBG_EXIT,
-			"%s: acpi_remove_notify_handler\n", ibm->name);
+		tp_dbg(TPACPI_DBG_EXIT,
+		       "%s: acpi_remove_notify_handler\n", ibm->name);
 		BUG_ON(!ibm->acpi);
 		acpi_remove_notify_handler(*ibm->acpi->handle,
 					   ibm->acpi->type,
@@ -8465,15 +8442,14 @@ static void ibm_exit(struct ibm_struct *ibm)
 	}
 
 	if (ibm->flags.proc_created) {
-		dbg_printk(TPACPI_DBG_EXIT,
-			"%s: remove_proc_entry\n", ibm->name);
+		tp_dbg(TPACPI_DBG_EXIT, "%s: remove_proc_entry\n", ibm->name);
 		remove_proc_entry(ibm->name, proc_dir);
 		ibm->flags.proc_created = 0;
 	}
 
 	if (ibm->flags.acpi_driver_registered) {
-		dbg_printk(TPACPI_DBG_EXIT,
-			"%s: acpi_bus_unregister_driver\n", ibm->name);
+		tp_dbg(TPACPI_DBG_EXIT,
+		       "%s: acpi_bus_unregister_driver\n", ibm->name);
 		BUG_ON(!ibm->acpi);
 		acpi_bus_unregister_driver(ibm->acpi->driver);
 		kfree(ibm->acpi->driver);
@@ -8486,7 +8462,7 @@ static void ibm_exit(struct ibm_struct *ibm)
 		ibm->flags.init_called = 0;
 	}
 
-	dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
+	tp_dbg(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
 }
 
 static int __init ibm_init(struct ibm_init_struct *iibm)
@@ -8502,8 +8478,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
 	if (ibm->flags.experimental && !experimental)
 		return 0;
 
-	dbg_printk(TPACPI_DBG_INIT,
-		"probing for %s\n", ibm->name);
+	tp_dbg(TPACPI_DBG_INIT, "probing for %s\n", ibm->name);
 
 	if (iibm->init) {
 		ret = iibm->init(iibm);
@@ -8535,8 +8510,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
 		}
 	}
 
-	dbg_printk(TPACPI_DBG_INIT,
-		"%s installed\n", ibm->name);
+	tp_dbg(TPACPI_DBG_INIT, "%s installed\n", ibm->name);
 
 	if (ibm->read) {
 		umode_t mode = iibm->base_procfs_mode;
@@ -8560,9 +8534,8 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
 	return 0;
 
 err_out:
-	dbg_printk(TPACPI_DBG_INIT,
-		"%s: at error exit path with result %d\n",
-		ibm->name, ret);
+	tp_dbg(TPACPI_DBG_INIT, "%s: at error exit path with result %d\n",
+	       ibm->name, ret);
 
 	ibm_exit(ibm);
 	return (ret < 0)? ret : 0;
@@ -8928,7 +8901,7 @@ static void thinkpad_acpi_module_exit(void)
 		ibm_exit(ibm);
 	}
 
-	dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
+	tp_dbg(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
 
 	if (tpacpi_inputdev) {
 		if (tp_features.input_device_registered)
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index d21e8f5..507a8e2 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -170,8 +170,8 @@ static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
 	}
 
 	if (acpi_bus_power_manageable(handle)) {
-		int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL);
-
+		int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL,
+							     ACPI_STATE_D3);
 		if (power_state < 0)
 			power_state = (state.event == PM_EVENT_ON) ?
 					ACPI_STATE_D0 : ACPI_STATE_D3;
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index f5d6d37..5657990 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -51,6 +51,7 @@
 #define BQ27x00_REG_LMD			0x12 /* Last measured discharge */
 #define BQ27x00_REG_CYCT		0x2A /* Cycle count total */
 #define BQ27x00_REG_AE			0x22 /* Available energy */
+#define BQ27x00_POWER_AVG		0x24
 
 #define BQ27000_REG_RSOC		0x0B /* Relative State-of-Charge */
 #define BQ27000_REG_ILMD		0x76 /* Initial last measured discharge */
@@ -66,8 +67,10 @@
 #define BQ27500_FLAG_SOCF		BIT(1) /* State-of-Charge threshold final */
 #define BQ27500_FLAG_SOC1		BIT(2) /* State-of-Charge threshold 1 */
 #define BQ27500_FLAG_FC			BIT(9)
+#define BQ27500_FLAG_OTC		BIT(15)
 
 #define BQ27000_RS			20 /* Resistor sense */
+#define BQ27x00_POWER_CONSTANT		(256 * 29200 / 1000)
 
 struct bq27x00_device_info;
 struct bq27x00_access_methods {
@@ -86,6 +89,8 @@ struct bq27x00_reg_cache {
 	int capacity;
 	int energy;
 	int flags;
+	int power_avg;
+	int health;
 };
 
 struct bq27x00_device_info {
@@ -123,6 +128,8 @@ static enum power_supply_property bq27x00_battery_props[] = {
 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 	POWER_SUPPLY_PROP_CYCLE_COUNT,
 	POWER_SUPPLY_PROP_ENERGY_NOW,
+	POWER_SUPPLY_PROP_POWER_AVG,
+	POWER_SUPPLY_PROP_HEALTH,
 };
 
 static unsigned int poll_interval = 360;
@@ -306,6 +313,60 @@ static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg)
 	return tval * 60;
 }
 
+/*
+ * Read a power avg register.
+ * Return < 0 if something fails.
+ */
+static int bq27x00_battery_read_pwr_avg(struct bq27x00_device_info *di, u8 reg)
+{
+	int tval;
+
+	tval = bq27x00_read(di, reg, false);
+	if (tval < 0) {
+		dev_err(di->dev, "error reading power avg rgister  %02x: %d\n",
+			reg, tval);
+		return tval;
+	}
+
+	if (di->chip == BQ27500)
+		return tval;
+	else
+		return (tval * BQ27x00_POWER_CONSTANT) / BQ27000_RS;
+}
+
+/*
+ * Read flag register.
+ * Return < 0 if something fails.
+ */
+static int bq27x00_battery_read_health(struct bq27x00_device_info *di)
+{
+	int tval;
+
+	tval = bq27x00_read(di, BQ27x00_REG_FLAGS, false);
+	if (tval < 0) {
+		dev_err(di->dev, "error reading flag register:%d\n", tval);
+		return tval;
+	}
+
+	if ((di->chip == BQ27500)) {
+		if (tval & BQ27500_FLAG_SOCF)
+			tval = POWER_SUPPLY_HEALTH_DEAD;
+		else if (tval & BQ27500_FLAG_OTC)
+			tval = POWER_SUPPLY_HEALTH_OVERHEAT;
+		else
+			tval = POWER_SUPPLY_HEALTH_GOOD;
+		return tval;
+	} else {
+		if (tval & BQ27000_FLAG_EDV1)
+			tval = POWER_SUPPLY_HEALTH_DEAD;
+		else
+			tval = POWER_SUPPLY_HEALTH_GOOD;
+		return tval;
+	}
+
+	return -1;
+}
+
 static void bq27x00_update(struct bq27x00_device_info *di)
 {
 	struct bq27x00_reg_cache cache = {0, };
@@ -321,6 +382,7 @@ static void bq27x00_update(struct bq27x00_device_info *di)
 			cache.time_to_empty_avg = -ENODATA;
 			cache.time_to_full = -ENODATA;
 			cache.charge_full = -ENODATA;
+			cache.health = -ENODATA;
 		} else {
 			cache.capacity = bq27x00_battery_read_rsoc(di);
 			cache.energy = bq27x00_battery_read_energy(di);
@@ -328,9 +390,12 @@ static void bq27x00_update(struct bq27x00_device_info *di)
 			cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);
 			cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF);
 			cache.charge_full = bq27x00_battery_read_lmd(di);
+			cache.health = bq27x00_battery_read_health(di);
 		}
 		cache.temperature = bq27x00_battery_read_temperature(di);
 		cache.cycle_count = bq27x00_battery_read_cyct(di);
+		cache.power_avg =
+			bq27x00_battery_read_pwr_avg(di, BQ27x00_POWER_AVG);
 
 		/* We only have to read charge design full once */
 		if (di->charge_design_full <= 0)
@@ -550,6 +615,12 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_ENERGY_NOW:
 		ret = bq27x00_simple_value(di->cache.energy, val);
 		break;
+	case POWER_SUPPLY_PROP_POWER_AVG:
+		ret = bq27x00_simple_value(di->cache.power_avg, val);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		ret = bq27x00_simple_value(di->cache.health, val);
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c
index de31cae..74fad94 100644
--- a/drivers/power/ds2780_battery.c
+++ b/drivers/power/ds2780_battery.c
@@ -39,7 +39,6 @@ struct ds2780_device_info {
 	struct device *dev;
 	struct power_supply bat;
 	struct device *w1_dev;
-	struct task_struct *mutex_holder;
 };
 
 enum current_types {
@@ -64,10 +63,7 @@ static inline struct power_supply *to_power_supply(struct device *dev)
 static inline int ds2780_battery_io(struct ds2780_device_info *dev_info,
 	char *buf, int addr, size_t count, int io)
 {
-	if (dev_info->mutex_holder == current)
-		return w1_ds2780_io_nolock(dev_info->w1_dev, buf, addr, count, io);
-	else
-		return w1_ds2780_io(dev_info->w1_dev, buf, addr, count, io);
+	return w1_ds2780_io(dev_info->w1_dev, buf, addr, count, io);
 }
 
 static inline int ds2780_read8(struct ds2780_device_info *dev_info, u8 *val,
@@ -779,7 +775,6 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev)
 	dev_info->bat.properties	= ds2780_battery_props;
 	dev_info->bat.num_properties	= ARRAY_SIZE(ds2780_battery_props);
 	dev_info->bat.get_property	= ds2780_battery_get_property;
-	dev_info->mutex_holder		= current;
 
 	ret = power_supply_register(&pdev->dev, &dev_info->bat);
 	if (ret) {
@@ -809,8 +804,6 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev)
 		goto fail_remove_bin_file;
 	}
 
-	dev_info->mutex_holder = NULL;
-
 	return 0;
 
 fail_remove_bin_file:
@@ -830,8 +823,6 @@ static int __devexit ds2780_battery_remove(struct platform_device *pdev)
 {
 	struct ds2780_device_info *dev_info = platform_get_drvdata(pdev);
 
-	dev_info->mutex_holder = current;
-
 	/* remove attributes */
 	sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
 
diff --git a/drivers/power/ds2781_battery.c b/drivers/power/ds2781_battery.c
index 975684a..7a1ff4e 100644
--- a/drivers/power/ds2781_battery.c
+++ b/drivers/power/ds2781_battery.c
@@ -37,7 +37,6 @@ struct ds2781_device_info {
 	struct device *dev;
 	struct power_supply bat;
 	struct device *w1_dev;
-	struct task_struct *mutex_holder;
 };
 
 enum current_types {
@@ -62,14 +61,10 @@ static inline struct power_supply *to_power_supply(struct device *dev)
 static inline int ds2781_battery_io(struct ds2781_device_info *dev_info,
 	char *buf, int addr, size_t count, int io)
 {
-	if (dev_info->mutex_holder == current)
-		return w1_ds2781_io_nolock(dev_info->w1_dev, buf, addr,
-				count, io);
-	else
-		return w1_ds2781_io(dev_info->w1_dev, buf, addr, count, io);
+	return w1_ds2781_io(dev_info->w1_dev, buf, addr, count, io);
 }
 
-int w1_ds2781_read(struct ds2781_device_info *dev_info, char *buf,
+static int w1_ds2781_read(struct ds2781_device_info *dev_info, char *buf,
 		int addr, size_t count)
 {
 	return ds2781_battery_io(dev_info, buf, addr, count, 0);
@@ -775,7 +770,6 @@ static int __devinit ds2781_battery_probe(struct platform_device *pdev)
 	dev_info->bat.properties	= ds2781_battery_props;
 	dev_info->bat.num_properties	= ARRAY_SIZE(ds2781_battery_props);
 	dev_info->bat.get_property	= ds2781_battery_get_property;
-	dev_info->mutex_holder		= current;
 
 	ret = power_supply_register(&pdev->dev, &dev_info->bat);
 	if (ret) {
@@ -805,8 +799,6 @@ static int __devinit ds2781_battery_probe(struct platform_device *pdev)
 		goto fail_remove_bin_file;
 	}
 
-	dev_info->mutex_holder = NULL;
-
 	return 0;
 
 fail_remove_bin_file:
@@ -826,8 +818,6 @@ static int __devexit ds2781_battery_remove(struct platform_device *pdev)
 {
 	struct ds2781_device_info *dev_info = platform_get_drvdata(pdev);
 
-	dev_info->mutex_holder = current;
-
 	/* remove attributes */
 	sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2781_attr_group);
 
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c
index 8672c91..cb2aa31 100644
--- a/drivers/power/gpio-charger.c
+++ b/drivers/power/gpio-charger.c
@@ -54,7 +54,7 @@ static int gpio_charger_get_property(struct power_supply *psy,
 
 	switch (psp) {
 	case POWER_SUPPLY_PROP_ONLINE:
-		val->intval = gpio_get_value(pdata->gpio);
+		val->intval = gpio_get_value_cansleep(pdata->gpio);
 		val->intval ^= pdata->gpio_active_low;
 		break;
 	default:
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
index 140788b..74abc6c 100644
--- a/drivers/power/max17042_battery.c
+++ b/drivers/power/max17042_battery.c
@@ -113,6 +113,7 @@ static enum power_supply_property max17042_battery_props[] = {
 	POWER_SUPPLY_PROP_VOLTAGE_OCV,
 	POWER_SUPPLY_PROP_CAPACITY,
 	POWER_SUPPLY_PROP_CHARGE_FULL,
+	POWER_SUPPLY_PROP_CHARGE_COUNTER,
 	POWER_SUPPLY_PROP_TEMP,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_CURRENT_AVG,
@@ -201,6 +202,13 @@ static int max17042_get_property(struct power_supply *psy,
 
 		val->intval = ret * 1000 / 2;
 		break;
+	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+		ret = max17042_read_reg(chip->client, MAX17042_QH);
+		if (ret < 0)
+			return ret;
+
+		val->intval = ret * 1000 / 2;
+		break;
 	case POWER_SUPPLY_PROP_TEMP:
 		ret = max17042_read_reg(chip->client, MAX17042_TEMP);
 		if (ret < 0)
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
index 214468f..ed54a35 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/pda_power.c
@@ -134,13 +134,13 @@ static void update_charger(void)
 			regulator_set_current_limit(ac_draw, max_uA, max_uA);
 			if (!regulator_enabled) {
 				dev_dbg(dev, "charger on (AC)\n");
-				regulator_enable(ac_draw);
+				WARN_ON(regulator_enable(ac_draw));
 				regulator_enabled = 1;
 			}
 		} else {
 			if (regulator_enabled) {
 				dev_dbg(dev, "charger off\n");
-				regulator_disable(ac_draw);
+				WARN_ON(regulator_disable(ac_draw));
 				regulator_enabled = 0;
 			}
 		}
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 6ad6127..85689fb 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -17,6 +17,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/power_supply.h>
+#include <linux/thermal.h>
 #include "power_supply.h"
 
 /* exported for the APM Power driver, APM emulation */
@@ -169,6 +170,63 @@ static void power_supply_dev_release(struct device *dev)
 	kfree(dev);
 }
 
+#ifdef CONFIG_THERMAL
+static int power_supply_read_temp(struct thermal_zone_device *tzd,
+		unsigned long *temp)
+{
+	struct power_supply *psy;
+	union power_supply_propval val;
+	int ret;
+
+	WARN_ON(tzd == NULL);
+	psy = tzd->devdata;
+	ret = psy->get_property(psy, POWER_SUPPLY_PROP_TEMP, &val);
+
+	/* Convert tenths of degree Celsius to milli degree Celsius. */
+	if (!ret)
+		*temp = val.intval * 100;
+
+	return ret;
+}
+
+static struct thermal_zone_device_ops psy_tzd_ops = {
+	.get_temp = power_supply_read_temp,
+};
+
+static int psy_register_thermal(struct power_supply *psy)
+{
+	int i;
+
+	/* Register battery zone device psy reports temperature */
+	for (i = 0; i < psy->num_properties; i++) {
+		if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) {
+			psy->tzd = thermal_zone_device_register(psy->name, 0,
+					0, psy, &psy_tzd_ops, 0, 0, 0, 0);
+			if (IS_ERR(psy->tzd))
+				return PTR_ERR(psy->tzd);
+			break;
+		}
+	}
+	return 0;
+}
+
+static void psy_unregister_thermal(struct power_supply *psy)
+{
+	if (IS_ERR_OR_NULL(psy->tzd))
+		return;
+	thermal_zone_device_unregister(psy->tzd);
+}
+#else
+static int psy_register_thermal(struct power_supply *psy)
+{
+	return 0;
+}
+
+static void psy_unregister_thermal(struct power_supply *psy)
+{
+}
+#endif
+
 int power_supply_register(struct device *parent, struct power_supply *psy)
 {
 	struct device *dev;
@@ -197,6 +255,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
 	if (rc)
 		goto device_add_failed;
 
+	rc = psy_register_thermal(psy);
+	if (rc)
+		goto register_thermal_failed;
+
 	rc = power_supply_create_triggers(psy);
 	if (rc)
 		goto create_triggers_failed;
@@ -206,6 +268,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
 	goto success;
 
 create_triggers_failed:
+	psy_unregister_thermal(psy);
+register_thermal_failed:
 	device_del(dev);
 kobject_set_name_failed:
 device_add_failed:
@@ -220,6 +284,7 @@ void power_supply_unregister(struct power_supply *psy)
 	cancel_work_sync(&psy->changed_work);
 	sysfs_remove_link(&psy->dev->kobj, "powers");
 	power_supply_remove_triggers(psy);
+	psy_unregister_thermal(psy);
 	device_unregister(psy->dev);
 }
 EXPORT_SYMBOL_GPL(power_supply_unregister);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 4150747..58846d9 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -159,6 +159,8 @@ static struct device_attribute power_supply_attrs[] = {
 	POWER_SUPPLY_ATTR(charge_now),
 	POWER_SUPPLY_ATTR(charge_avg),
 	POWER_SUPPLY_ATTR(charge_counter),
+	POWER_SUPPLY_ATTR(constant_charge_current),
+	POWER_SUPPLY_ATTR(constant_charge_voltage),
 	POWER_SUPPLY_ATTR(energy_full_design),
 	POWER_SUPPLY_ATTR(energy_empty_design),
 	POWER_SUPPLY_ATTR(energy_full),
diff --git a/drivers/power/sbs-battery.c b/drivers/power/sbs-battery.c
index a5b6849..a65e8f5 100644
--- a/drivers/power/sbs-battery.c
+++ b/drivers/power/sbs-battery.c
@@ -469,7 +469,7 @@ static int sbs_get_property(struct power_supply *psy,
 
 	case POWER_SUPPLY_PROP_TECHNOLOGY:
 		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
-		break;
+		goto done; /* don't trigger power_supply_changed()! */
 
 	case POWER_SUPPLY_PROP_ENERGY_NOW:
 	case POWER_SUPPLY_PROP_ENERGY_FULL:
diff --git a/drivers/power/smb347-charger.c b/drivers/power/smb347-charger.c
index f8eedd8..332dd01 100644
--- a/drivers/power/smb347-charger.c
+++ b/drivers/power/smb347-charger.c
@@ -196,6 +196,14 @@ static const unsigned int ccc_tbl[] = {
 	1200000,
 };
 
+/* Convert register value to current using lookup table */
+static int hw_to_current(const unsigned int *tbl, size_t size, unsigned int val)
+{
+	if (val >= size)
+		return -EINVAL;
+	return tbl[val];
+}
+
 /* Convert current to register value using lookup table */
 static int current_to_hw(const unsigned int *tbl, size_t size, unsigned int val)
 {
@@ -841,22 +849,101 @@ fail:
 	return ret;
 }
 
+/*
+ * Returns the constant charge current programmed
+ * into the charger in uA.
+ */
+static int get_const_charge_current(struct smb347_charger *smb)
+{
+	int ret, intval;
+	unsigned int v;
+
+	if (!smb347_is_ps_online(smb))
+		return -ENODATA;
+
+	ret = regmap_read(smb->regmap, STAT_B, &v);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * The current value is composition of FCC and PCC values
+	 * and we can detect which table to use from bit 5.
+	 */
+	if (v & 0x20) {
+		intval = hw_to_current(fcc_tbl, ARRAY_SIZE(fcc_tbl), v & 7);
+	} else {
+		v >>= 3;
+		intval = hw_to_current(pcc_tbl, ARRAY_SIZE(pcc_tbl), v & 7);
+	}
+
+	return intval;
+}
+
+/*
+ * Returns the constant charge voltage programmed
+ * into the charger in uV.
+ */
+static int get_const_charge_voltage(struct smb347_charger *smb)
+{
+	int ret, intval;
+	unsigned int v;
+
+	if (!smb347_is_ps_online(smb))
+		return -ENODATA;
+
+	ret = regmap_read(smb->regmap, STAT_A, &v);
+	if (ret < 0)
+		return ret;
+
+	v &= STAT_A_FLOAT_VOLTAGE_MASK;
+	if (v > 0x3d)
+		v = 0x3d;
+
+	intval = 3500000 + v * 20000;
+
+	return intval;
+}
+
 static int smb347_mains_get_property(struct power_supply *psy,
 				     enum power_supply_property prop,
 				     union power_supply_propval *val)
 {
 	struct smb347_charger *smb =
 		container_of(psy, struct smb347_charger, mains);
+	int ret;
 
-	if (prop == POWER_SUPPLY_PROP_ONLINE) {
+	switch (prop) {
+	case POWER_SUPPLY_PROP_ONLINE:
 		val->intval = smb->mains_online;
-		return 0;
+		break;
+
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		ret = get_const_charge_voltage(smb);
+		if (ret < 0)
+			return ret;
+		else
+			val->intval = ret;
+		break;
+
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		ret = get_const_charge_current(smb);
+		if (ret < 0)
+			return ret;
+		else
+			val->intval = ret;
+		break;
+
+	default:
+		return -EINVAL;
 	}
-	return -EINVAL;
+
+	return 0;
 }
 
 static enum power_supply_property smb347_mains_properties[] = {
 	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
 };
 
 static int smb347_usb_get_property(struct power_supply *psy,
@@ -865,16 +952,40 @@ static int smb347_usb_get_property(struct power_supply *psy,
 {
 	struct smb347_charger *smb =
 		container_of(psy, struct smb347_charger, usb);
+	int ret;
 
-	if (prop == POWER_SUPPLY_PROP_ONLINE) {
+	switch (prop) {
+	case POWER_SUPPLY_PROP_ONLINE:
 		val->intval = smb->usb_online;
-		return 0;
+		break;
+
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		ret = get_const_charge_voltage(smb);
+		if (ret < 0)
+			return ret;
+		else
+			val->intval = ret;
+		break;
+
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		ret = get_const_charge_current(smb);
+		if (ret < 0)
+			return ret;
+		else
+			val->intval = ret;
+		break;
+
+	default:
+		return -EINVAL;
 	}
-	return -EINVAL;
+
+	return 0;
 }
 
 static enum power_supply_property smb347_usb_properties[] = {
 	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
 };
 
 static int smb347_battery_get_property(struct power_supply *psy,
diff --git a/drivers/power/test_power.c b/drivers/power/test_power.c
index b527c93..b99a452 100644
--- a/drivers/power/test_power.c
+++ b/drivers/power/test_power.c
@@ -22,11 +22,13 @@
 #include <linux/vermagic.h>
 
 static int ac_online			= 1;
+static int usb_online			= 1;
 static int battery_status		= POWER_SUPPLY_STATUS_DISCHARGING;
 static int battery_health		= POWER_SUPPLY_HEALTH_GOOD;
 static int battery_present		= 1; /* true */
 static int battery_technology		= POWER_SUPPLY_TECHNOLOGY_LION;
 static int battery_capacity		= 50;
+static int battery_voltage		= 3300;
 
 static int test_power_get_ac_property(struct power_supply *psy,
 				      enum power_supply_property psp,
@@ -42,6 +44,20 @@ static int test_power_get_ac_property(struct power_supply *psy,
 	return 0;
 }
 
+static int test_power_get_usb_property(struct power_supply *psy,
+				      enum power_supply_property psp,
+				      union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = usb_online;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int test_power_get_battery_property(struct power_supply *psy,
 					   enum power_supply_property psp,
 					   union power_supply_propval *val)
@@ -86,6 +102,12 @@ static int test_power_get_battery_property(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
 		val->intval = 3600;
 		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = 26;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = battery_voltage;
+		break;
 	default:
 		pr_info("%s: some properties deliberately report errors.\n",
 			__func__);
@@ -114,6 +136,8 @@ static enum power_supply_property test_power_battery_props[] = {
 	POWER_SUPPLY_PROP_MODEL_NAME,
 	POWER_SUPPLY_PROP_MANUFACTURER,
 	POWER_SUPPLY_PROP_SERIAL_NUMBER,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 };
 
 static char *test_power_ac_supplied_to[] = {
@@ -135,6 +159,14 @@ static struct power_supply test_power_supplies[] = {
 		.properties = test_power_battery_props,
 		.num_properties = ARRAY_SIZE(test_power_battery_props),
 		.get_property = test_power_get_battery_property,
+	}, {
+		.name = "test_usb",
+		.type = POWER_SUPPLY_TYPE_USB,
+		.supplied_to = test_power_ac_supplied_to,
+		.num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to),
+		.properties = test_power_ac_props,
+		.num_properties = ARRAY_SIZE(test_power_ac_props),
+		.get_property = test_power_get_usb_property,
 	},
 };
 
@@ -167,6 +199,7 @@ static void __exit test_power_exit(void)
 
 	/* Let's see how we handle changes... */
 	ac_online = 0;
+	usb_online = 0;
 	battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
 	for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)
 		power_supply_changed(&test_power_supplies[i]);
@@ -275,6 +308,19 @@ static int param_get_ac_online(char *buffer, const struct kernel_param *kp)
 	return strlen(buffer);
 }
 
+static int param_set_usb_online(const char *key, const struct kernel_param *kp)
+{
+	usb_online = map_get_value(map_ac_online, key, usb_online);
+	power_supply_changed(&test_power_supplies[2]);
+	return 0;
+}
+
+static int param_get_usb_online(char *buffer, const struct kernel_param *kp)
+{
+	strcpy(buffer, map_get_key(map_ac_online, usb_online, "unknown"));
+	return strlen(buffer);
+}
+
 static int param_set_battery_status(const char *key,
 					const struct kernel_param *kp)
 {
@@ -350,13 +396,31 @@ static int param_set_battery_capacity(const char *key,
 
 #define param_get_battery_capacity param_get_int
 
+static int param_set_battery_voltage(const char *key,
+					const struct kernel_param *kp)
+{
+	int tmp;
+
+	if (1 != sscanf(key, "%d", &tmp))
+		return -EINVAL;
+
+	battery_voltage = tmp;
+	power_supply_changed(&test_power_supplies[1]);
+	return 0;
+}
 
+#define param_get_battery_voltage param_get_int
 
 static struct kernel_param_ops param_ops_ac_online = {
 	.set = param_set_ac_online,
 	.get = param_get_ac_online,
 };
 
+static struct kernel_param_ops param_ops_usb_online = {
+	.set = param_set_usb_online,
+	.get = param_get_usb_online,
+};
+
 static struct kernel_param_ops param_ops_battery_status = {
 	.set = param_set_battery_status,
 	.get = param_get_battery_status,
@@ -382,18 +446,27 @@ static struct kernel_param_ops param_ops_battery_capacity = {
 	.get = param_get_battery_capacity,
 };
 
+static struct kernel_param_ops param_ops_battery_voltage = {
+	.set = param_set_battery_voltage,
+	.get = param_get_battery_voltage,
+};
 
 #define param_check_ac_online(name, p) __param_check(name, p, void);
+#define param_check_usb_online(name, p) __param_check(name, p, void);
 #define param_check_battery_status(name, p) __param_check(name, p, void);
 #define param_check_battery_present(name, p) __param_check(name, p, void);
 #define param_check_battery_technology(name, p) __param_check(name, p, void);
 #define param_check_battery_health(name, p) __param_check(name, p, void);
 #define param_check_battery_capacity(name, p) __param_check(name, p, void);
+#define param_check_battery_voltage(name, p) __param_check(name, p, void);
 
 
 module_param(ac_online, ac_online, 0644);
 MODULE_PARM_DESC(ac_online, "AC charging state <on|off>");
 
+module_param(usb_online, usb_online, 0644);
+MODULE_PARM_DESC(usb_online, "USB charging state <on|off>");
+
 module_param(battery_status, battery_status, 0644);
 MODULE_PARM_DESC(battery_status,
 	"battery status <charging|discharging|not-charging|full>");
@@ -413,6 +486,8 @@ MODULE_PARM_DESC(battery_health,
 module_param(battery_capacity, battery_capacity, 0644);
 MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)");
 
+module_param(battery_voltage, battery_voltage, 0644);
+MODULE_PARM_DESC(battery_voltage, "battery voltage (millivolts)");
 
 MODULE_DESCRIPTION("Power supply driver for testing");
 MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index fdad850..bbda083 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -21,6 +21,7 @@
 #include <linux/power_supply.h>
 #include <linux/notifier.h>
 #include <linux/usb/otg.h>
+#include <linux/regulator/machine.h>
 
 #define TWL4030_BCIMSTATEC	0x02
 #define TWL4030_BCIICHG		0x08
@@ -28,6 +29,7 @@
 #define TWL4030_BCIVBUS		0x0c
 #define TWL4030_BCIMFSTS4	0x10
 #define TWL4030_BCICTL1		0x23
+#define TWL4030_BB_CFG		0x12
 
 #define TWL4030_BCIAUTOWEN	BIT(5)
 #define TWL4030_CONFIG_DONE	BIT(4)
@@ -37,6 +39,17 @@
 #define TWL4030_USBFASTMCHG	BIT(2)
 #define TWL4030_STS_VBUS	BIT(7)
 #define TWL4030_STS_USB_ID	BIT(2)
+#define TWL4030_BBCHEN		BIT(4)
+#define TWL4030_BBSEL_MASK	0b1100
+#define TWL4030_BBSEL_2V5	0b0000
+#define TWL4030_BBSEL_3V0	0b0100
+#define TWL4030_BBSEL_3V1	0b1000
+#define TWL4030_BBSEL_3V2	0b1100
+#define TWL4030_BBISEL_MASK	0b11
+#define TWL4030_BBISEL_25uA	0b00
+#define TWL4030_BBISEL_150uA	0b01
+#define TWL4030_BBISEL_500uA	0b10
+#define TWL4030_BBISEL_1000uA	0b11
 
 /* BCI interrupts */
 #define TWL4030_WOVF		BIT(0) /* Watchdog overflow */
@@ -74,6 +87,8 @@ struct twl4030_bci {
 	struct work_struct	work;
 	int			irq_chg;
 	int			irq_bci;
+	struct regulator	*usb_reg;
+	int			usb_enabled;
 
 	unsigned long		event;
 };
@@ -103,7 +118,7 @@ static int twl4030_bci_read(u8 reg, u8 *val)
 
 static int twl4030_clear_set_boot_bci(u8 clear, u8 set)
 {
-	return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, 0,
+	return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, clear,
 			TWL4030_CONFIG_DONE | TWL4030_BCIAUTOWEN | set,
 			TWL4030_PM_MASTER_BOOT_BCI);
 }
@@ -151,14 +166,14 @@ static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
 }
 
 /*
- * Enable/Disable USB Charge funtionality.
+ * Enable/Disable USB Charge functionality.
  */
 static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
 {
 	int ret;
 
 	if (enable) {
-		/* Check for USB charger conneted */
+		/* Check for USB charger connected */
 		if (!twl4030_bci_have_vbus(bci))
 			return -ENODEV;
 
@@ -171,6 +186,12 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
 			return -EACCES;
 		}
 
+		/* Need to keep regulator on */
+		if (!bci->usb_enabled) {
+			regulator_enable(bci->usb_reg);
+			bci->usb_enabled = 1;
+		}
+
 		/* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
 		ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
 		if (ret < 0)
@@ -181,6 +202,10 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
 			TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
 	} else {
 		ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
+		if (bci->usb_enabled) {
+			regulator_disable(bci->usb_reg);
+			bci->usb_enabled = 0;
+		}
 	}
 
 	return ret;
@@ -202,6 +227,49 @@ static int twl4030_charger_enable_ac(bool enable)
 }
 
 /*
+ * Enable/Disable charging of Backup Battery.
+ */
+static int twl4030_charger_enable_backup(int uvolt, int uamp)
+{
+	int ret;
+	u8 flags;
+
+	if (uvolt < 2500000 ||
+	    uamp < 25) {
+		/* disable charging of backup battery */
+		ret = twl4030_clear_set(TWL4030_MODULE_PM_RECEIVER,
+					TWL4030_BBCHEN, 0, TWL4030_BB_CFG);
+		return ret;
+	}
+
+	flags = TWL4030_BBCHEN;
+	if (uvolt >= 3200000)
+		flags |= TWL4030_BBSEL_3V2;
+	else if (uvolt >= 3100000)
+		flags |= TWL4030_BBSEL_3V1;
+	else if (uvolt >= 3000000)
+		flags |= TWL4030_BBSEL_3V0;
+	else
+		flags |= TWL4030_BBSEL_2V5;
+
+	if (uamp >= 1000)
+		flags |= TWL4030_BBISEL_1000uA;
+	else if (uamp >= 500)
+		flags |= TWL4030_BBISEL_500uA;
+	else if (uamp >= 150)
+		flags |= TWL4030_BBISEL_150uA;
+	else
+		flags |= TWL4030_BBISEL_25uA;
+
+	ret = twl4030_clear_set(TWL4030_MODULE_PM_RECEIVER,
+				TWL4030_BBSEL_MASK | TWL4030_BBISEL_MASK,
+				flags,
+				TWL4030_BB_CFG);
+
+	return ret;
+}
+
+/*
  * TWL4030 CHG_PRES (AC charger presence) events
  */
 static irqreturn_t twl4030_charger_interrupt(int irq, void *arg)
@@ -424,6 +492,7 @@ static enum power_supply_property twl4030_charger_props[] = {
 static int __init twl4030_bci_probe(struct platform_device *pdev)
 {
 	struct twl4030_bci *bci;
+	struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data;
 	int ret;
 	u32 reg;
 
@@ -455,6 +524,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
 	bci->usb.num_properties = ARRAY_SIZE(twl4030_charger_props);
 	bci->usb.get_property = twl4030_bci_get_property;
 
+	bci->usb_reg = regulator_get(bci->dev, "bci3v1");
+
 	ret = power_supply_register(&pdev->dev, &bci->usb);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
@@ -503,6 +574,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
 
 	twl4030_charger_enable_ac(true);
 	twl4030_charger_enable_usb(bci, true);
+	twl4030_charger_enable_backup(pdata->bb_uvolt,
+				      pdata->bb_uamp);
 
 	return 0;
 
@@ -531,6 +604,7 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
 
 	twl4030_charger_enable_ac(false);
 	twl4030_charger_enable_usb(bci, false);
+	twl4030_charger_enable_backup(0, 0);
 
 	/* mask interrupts */
 	twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index c86b886..27fe52f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -20,6 +20,7 @@ menuconfig REGULATOR
 
 	  If unsure, say no.
 
+
 if REGULATOR
 
 config REGULATOR_DEBUG
@@ -88,6 +89,13 @@ config REGULATOR_AAT2870
 	  If you have a AnalogicTech AAT2870 say Y to enable the
 	  regulator driver.
 
+config REGULATOR_ARIZONA
+	tristate "Wolfson Arizona class devices"
+	depends on MFD_ARIZONA
+	help
+	  Support for the regulators found on Wolfson Arizona class
+	  devices.
+
 config REGULATOR_DA903X
 	tristate "Dialog Semiconductor DA9030/DA9034 regulators"
 	depends on PMIC_DA903X
@@ -195,6 +203,14 @@ config REGULATOR_MAX8998
 	  via I2C bus. The provided regulator is suitable for S3C6410
 	  and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
 
+config REGULATOR_MAX77686
+	tristate "Maxim 77686 regulator"
+	depends on MFD_MAX77686
+	help
+	  This driver controls a Maxim 77686 regulator
+	  via I2C bus. The provided regulator is suitable for
+	  Exynos-4 chips to control VARM and VINT voltages.
+
 config REGULATOR_PCAP
 	tristate "Motorola PCAP2 regulator driver"
 	depends on EZX_PCAP
@@ -216,6 +232,13 @@ config REGULATOR_LP3972
 	 Say Y here to support the voltage regulators and convertors
 	 on National Semiconductors LP3972 PMIC
 
+config REGULATOR_LP872X
+	bool "TI/National Semiconductor LP8720/LP8725 voltage regulators"
+	depends on I2C=y
+	select REGMAP_I2C
+	help
+	  This driver supports LP8720/LP8725 PMIC
+
 config REGULATOR_PCF50633
 	tristate "NXP PCF50633 regulator driver"
         depends on MFD_PCF50633
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 977fd46..c746088 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
 obj-$(CONFIG_REGULATOR_AB8500)	+= ab8500.o
 obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
 obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
+obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
 obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
 obj-$(CONFIG_REGULATOR_DA9052)	+= da9052-regulator.o
 obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
@@ -23,6 +24,7 @@ obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
 obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
+obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
 obj-$(CONFIG_REGULATOR_MAX8649)	+= max8649.o
 obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
@@ -30,6 +32,7 @@ obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
 obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
 obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
+obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index 03f4d9c..16d420b 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -43,20 +43,12 @@
  * @dev: handle to the device
  * @plfdata: AB3100 platform data passed in at probe time
  * @regreg: regulator register number in the AB3100
- * @fixed_voltage: a fixed voltage for this regulator, if this
- *          0 the voltages array is used instead.
- * @typ_voltages: an array of available typical voltages for
- *          this regulator
- * @voltages_len: length of the array of available voltages
  */
 struct ab3100_regulator {
 	struct regulator_dev *rdev;
 	struct device *dev;
 	struct ab3100_platform_data *plfdata;
 	u8 regreg;
-	int fixed_voltage;
-	int const *typ_voltages;
-	u8 voltages_len;
 };
 
 /* The order in which registers are initialized */
@@ -80,7 +72,7 @@ static const u8 ab3100_reg_init_order[AB3100_NUM_REGULATORS+2] = {
 #define LDO_C_VOLTAGE 2650000
 #define LDO_D_VOLTAGE 2650000
 
-static const int ldo_e_buck_typ_voltages[] = {
+static const unsigned int ldo_e_buck_typ_voltages[] = {
 	1800000,
 	1400000,
 	1300000,
@@ -90,7 +82,7 @@ static const int ldo_e_buck_typ_voltages[] = {
 	900000,
 };
 
-static const int ldo_f_typ_voltages[] = {
+static const unsigned int ldo_f_typ_voltages[] = {
 	1800000,
 	1400000,
 	1300000,
@@ -101,21 +93,21 @@ static const int ldo_f_typ_voltages[] = {
 	2650000,
 };
 
-static const int ldo_g_typ_voltages[] = {
+static const unsigned int ldo_g_typ_voltages[] = {
 	2850000,
 	2750000,
 	1800000,
 	1500000,
 };
 
-static const int ldo_h_typ_voltages[] = {
+static const unsigned int ldo_h_typ_voltages[] = {
 	2750000,
 	1800000,
 	1500000,
 	1200000,
 };
 
-static const int ldo_k_typ_voltages[] = {
+static const unsigned int ldo_k_typ_voltages[] = {
 	2750000,
 	1800000,
 };
@@ -126,40 +118,27 @@ static struct ab3100_regulator
 ab3100_regulators[AB3100_NUM_REGULATORS] = {
 	{
 		.regreg = AB3100_LDO_A,
-		.fixed_voltage = LDO_A_VOLTAGE,
 	},
 	{
 		.regreg = AB3100_LDO_C,
-		.fixed_voltage = LDO_C_VOLTAGE,
 	},
 	{
 		.regreg = AB3100_LDO_D,
-		.fixed_voltage = LDO_D_VOLTAGE,
 	},
 	{
 		.regreg = AB3100_LDO_E,
-		.typ_voltages = ldo_e_buck_typ_voltages,
-		.voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages),
 	},
 	{
 		.regreg = AB3100_LDO_F,
-		.typ_voltages = ldo_f_typ_voltages,
-		.voltages_len = ARRAY_SIZE(ldo_f_typ_voltages),
 	},
 	{
 		.regreg = AB3100_LDO_G,
-		.typ_voltages = ldo_g_typ_voltages,
-		.voltages_len = ARRAY_SIZE(ldo_g_typ_voltages),
 	},
 	{
 		.regreg = AB3100_LDO_H,
-		.typ_voltages = ldo_h_typ_voltages,
-		.voltages_len = ARRAY_SIZE(ldo_h_typ_voltages),
 	},
 	{
 		.regreg = AB3100_LDO_K,
-		.typ_voltages = ldo_k_typ_voltages,
-		.voltages_len = ARRAY_SIZE(ldo_k_typ_voltages),
 	},
 	{
 		.regreg = AB3100_LDO_EXT,
@@ -167,8 +146,6 @@ ab3100_regulators[AB3100_NUM_REGULATORS] = {
 	},
 	{
 		.regreg = AB3100_BUCK,
-		.typ_voltages = ldo_e_buck_typ_voltages,
-		.voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages),
 	},
 };
 
@@ -257,26 +234,12 @@ static int ab3100_is_enabled_regulator(struct regulator_dev *reg)
 	return regval & AB3100_REG_ON_MASK;
 }
 
-static int ab3100_list_voltage_regulator(struct regulator_dev *reg,
-					 unsigned selector)
-{
-	struct ab3100_regulator *abreg = reg->reg_data;
-
-	if (selector >= abreg->voltages_len)
-		return -EINVAL;
-	return abreg->typ_voltages[selector];
-}
-
 static int ab3100_get_voltage_regulator(struct regulator_dev *reg)
 {
 	struct ab3100_regulator *abreg = reg->reg_data;
 	u8 regval;
 	int err;
 
-	/* Return the voltage for fixed regulators immediately */
-	if (abreg->fixed_voltage)
-		return abreg->fixed_voltage;
-
 	/*
 	 * For variable types, read out setting and index into
 	 * supplied voltage list.
@@ -294,14 +257,14 @@ static int ab3100_get_voltage_regulator(struct regulator_dev *reg)
 	regval &= 0xE0;
 	regval >>= 5;
 
-	if (regval >= abreg->voltages_len) {
+	if (regval >= reg->desc->n_voltages) {
 		dev_err(&reg->dev,
 			"regulator register %02x contains an illegal voltage setting\n",
 			abreg->regreg);
 		return -EINVAL;
 	}
 
-	return abreg->typ_voltages[regval];
+	return reg->desc->volt_table[regval];
 }
 
 static int ab3100_set_voltage_regulator_sel(struct regulator_dev *reg,
@@ -409,11 +372,17 @@ static int ab3100_enable_time_regulator(struct regulator_dev *reg)
 	return 0;
 }
 
+static int ab3100_get_fixed_voltage_regulator(struct regulator_dev *reg)
+{
+	return reg->desc->min_uV;
+}
+
 static struct regulator_ops regulator_ops_fixed = {
+	.list_voltage = regulator_list_voltage_linear,
 	.enable      = ab3100_enable_regulator,
 	.disable     = ab3100_disable_regulator,
 	.is_enabled  = ab3100_is_enabled_regulator,
-	.get_voltage = ab3100_get_voltage_regulator,
+	.get_voltage = ab3100_get_fixed_voltage_regulator,
 	.enable_time = ab3100_enable_time_regulator,
 };
 
@@ -423,7 +392,7 @@ static struct regulator_ops regulator_ops_variable = {
 	.is_enabled  = ab3100_is_enabled_regulator,
 	.get_voltage = ab3100_get_voltage_regulator,
 	.set_voltage_sel = ab3100_set_voltage_regulator_sel,
-	.list_voltage = ab3100_list_voltage_regulator,
+	.list_voltage = regulator_list_voltage_table,
 	.enable_time = ab3100_enable_time_regulator,
 };
 
@@ -434,7 +403,7 @@ static struct regulator_ops regulator_ops_variable_sleepable = {
 	.get_voltage = ab3100_get_voltage_regulator,
 	.set_voltage_sel = ab3100_set_voltage_regulator_sel,
 	.set_suspend_voltage = ab3100_set_suspend_voltage_regulator,
-	.list_voltage = ab3100_list_voltage_regulator,
+	.list_voltage = regulator_list_voltage_table,
 	.enable_time = ab3100_enable_time_regulator,
 };
 
@@ -457,28 +426,35 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
 		.name = "LDO_A",
 		.id   = AB3100_LDO_A,
 		.ops  = &regulator_ops_fixed,
+		.n_voltages = 1,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
+		.min_uV = LDO_A_VOLTAGE,
 	},
 	{
 		.name = "LDO_C",
 		.id   = AB3100_LDO_C,
 		.ops  = &regulator_ops_fixed,
+		.n_voltages = 1,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
+		.min_uV = LDO_C_VOLTAGE,
 	},
 	{
 		.name = "LDO_D",
 		.id   = AB3100_LDO_D,
 		.ops  = &regulator_ops_fixed,
+		.n_voltages = 1,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
+		.min_uV = LDO_D_VOLTAGE,
 	},
 	{
 		.name = "LDO_E",
 		.id   = AB3100_LDO_E,
 		.ops  = &regulator_ops_variable_sleepable,
 		.n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages),
+		.volt_table = ldo_e_buck_typ_voltages,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -487,6 +463,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
 		.id   = AB3100_LDO_F,
 		.ops  = &regulator_ops_variable,
 		.n_voltages = ARRAY_SIZE(ldo_f_typ_voltages),
+		.volt_table = ldo_f_typ_voltages,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -495,6 +472,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
 		.id   = AB3100_LDO_G,
 		.ops  = &regulator_ops_variable,
 		.n_voltages = ARRAY_SIZE(ldo_g_typ_voltages),
+		.volt_table = ldo_g_typ_voltages,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -503,6 +481,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
 		.id   = AB3100_LDO_H,
 		.ops  = &regulator_ops_variable,
 		.n_voltages = ARRAY_SIZE(ldo_h_typ_voltages),
+		.volt_table = ldo_h_typ_voltages,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -511,6 +490,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
 		.id   = AB3100_LDO_K,
 		.ops  = &regulator_ops_variable,
 		.n_voltages = ARRAY_SIZE(ldo_k_typ_voltages),
+		.volt_table = ldo_k_typ_voltages,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
index a739f5c..13d424f 100644
--- a/drivers/regulator/ab8500.c
+++ b/drivers/regulator/ab8500.c
@@ -30,9 +30,6 @@
  * @dev: device pointer
  * @desc: regulator description
  * @regulator_dev: regulator device
- * @max_uV: maximum voltage (for variable voltage supplies)
- * @min_uV: minimum voltage (for variable voltage supplies)
- * @fixed_uV: typical voltage (for fixed voltage supplies)
  * @update_bank: bank to control on/off
  * @update_reg: register to control on/off
  * @update_mask: mask to enable/disable regulator
@@ -40,17 +37,12 @@
  * @voltage_bank: bank to control regulator voltage
  * @voltage_reg: register to control regulator voltage
  * @voltage_mask: mask to control regulator voltage
- * @voltages: supported voltage table
- * @voltages_len: number of supported voltages for the regulator
  * @delay: startup/set voltage delay in us
  */
 struct ab8500_regulator_info {
 	struct device		*dev;
 	struct regulator_desc	desc;
 	struct regulator_dev	*regulator;
-	int max_uV;
-	int min_uV;
-	int fixed_uV;
 	u8 update_bank;
 	u8 update_reg;
 	u8 update_mask;
@@ -58,13 +50,11 @@ struct ab8500_regulator_info {
 	u8 voltage_bank;
 	u8 voltage_reg;
 	u8 voltage_mask;
-	int const *voltages;
-	int voltages_len;
 	unsigned int delay;
 };
 
 /* voltage tables for the vauxn/vintcore supplies */
-static const int ldo_vauxn_voltages[] = {
+static const unsigned int ldo_vauxn_voltages[] = {
 	1100000,
 	1200000,
 	1300000,
@@ -83,7 +73,7 @@ static const int ldo_vauxn_voltages[] = {
 	3300000,
 };
 
-static const int ldo_vaux3_voltages[] = {
+static const unsigned int ldo_vaux3_voltages[] = {
 	1200000,
 	1500000,
 	1800000,
@@ -94,7 +84,7 @@ static const int ldo_vaux3_voltages[] = {
 	2910000,
 };
 
-static const int ldo_vintcore_voltages[] = {
+static const unsigned int ldo_vintcore_voltages[] = {
 	1200000,
 	1225000,
 	1250000,
@@ -185,25 +175,6 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
 		return false;
 }
 
-static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector)
-{
-	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
-
-	if (info == NULL) {
-		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
-		return -EINVAL;
-	}
-
-	/* return the uV for the fixed regulators */
-	if (info->fixed_uV)
-		return info->fixed_uV;
-
-	if (selector >= info->voltages_len)
-		return -EINVAL;
-
-	return info->voltages[selector];
-}
-
 static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev)
 {
 	int ret, val;
@@ -279,14 +250,7 @@ static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
 					     unsigned int new_sel)
 {
 	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
-	int ret;
 
-	/* If the regulator isn't on, it won't take time here */
-	ret = ab8500_regulator_is_enabled(rdev);
-	if (ret < 0)
-		return ret;
-	if (!ret)
-		return 0;
 	return info->delay;
 }
 
@@ -296,21 +260,14 @@ static struct regulator_ops ab8500_regulator_ops = {
 	.is_enabled	= ab8500_regulator_is_enabled,
 	.get_voltage_sel = ab8500_regulator_get_voltage_sel,
 	.set_voltage_sel = ab8500_regulator_set_voltage_sel,
-	.list_voltage	= ab8500_list_voltage,
+	.list_voltage	= regulator_list_voltage_table,
 	.enable_time	= ab8500_regulator_enable_time,
 	.set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
 };
 
 static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
 {
-	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
-
-	if (info == NULL) {
-		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
-		return -EINVAL;
-	}
-
-	return info->fixed_uV;
+	return rdev->desc->min_uV;
 }
 
 static struct regulator_ops ab8500_regulator_fixed_ops = {
@@ -318,9 +275,8 @@ static struct regulator_ops ab8500_regulator_fixed_ops = {
 	.disable	= ab8500_regulator_disable,
 	.is_enabled	= ab8500_regulator_is_enabled,
 	.get_voltage	= ab8500_fixed_get_voltage,
-	.list_voltage	= ab8500_list_voltage,
+	.list_voltage	= regulator_list_voltage_linear,
 	.enable_time	= ab8500_regulator_enable_time,
-	.set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
 };
 
 static struct ab8500_regulator_info
@@ -329,7 +285,7 @@ static struct ab8500_regulator_info
 	 * Variable Voltage Regulators
 	 *   name, min mV, max mV,
 	 *   update bank, reg, mask, enable val
-	 *   volt bank, reg, mask, table, table length
+	 *   volt bank, reg, mask
 	 */
 	[AB8500_LDO_AUX1] = {
 		.desc = {
@@ -339,9 +295,8 @@ static struct ab8500_regulator_info
 			.id		= AB8500_LDO_AUX1,
 			.owner		= THIS_MODULE,
 			.n_voltages	= ARRAY_SIZE(ldo_vauxn_voltages),
+			.volt_table	= ldo_vauxn_voltages,
 		},
-		.min_uV			= 1100000,
-		.max_uV			= 3300000,
 		.update_bank		= 0x04,
 		.update_reg		= 0x09,
 		.update_mask		= 0x03,
@@ -349,8 +304,6 @@ static struct ab8500_regulator_info
 		.voltage_bank		= 0x04,
 		.voltage_reg		= 0x1f,
 		.voltage_mask		= 0x0f,
-		.voltages		= ldo_vauxn_voltages,
-		.voltages_len		= ARRAY_SIZE(ldo_vauxn_voltages),
 	},
 	[AB8500_LDO_AUX2] = {
 		.desc = {
@@ -360,9 +313,8 @@ static struct ab8500_regulator_info
 			.id		= AB8500_LDO_AUX2,
 			.owner		= THIS_MODULE,
 			.n_voltages	= ARRAY_SIZE(ldo_vauxn_voltages),
+			.volt_table	= ldo_vauxn_voltages,
 		},
-		.min_uV			= 1100000,
-		.max_uV			= 3300000,
 		.update_bank		= 0x04,
 		.update_reg		= 0x09,
 		.update_mask		= 0x0c,
@@ -370,8 +322,6 @@ static struct ab8500_regulator_info
 		.voltage_bank		= 0x04,
 		.voltage_reg		= 0x20,
 		.voltage_mask		= 0x0f,
-		.voltages		= ldo_vauxn_voltages,
-		.voltages_len		= ARRAY_SIZE(ldo_vauxn_voltages),
 	},
 	[AB8500_LDO_AUX3] = {
 		.desc = {
@@ -381,9 +331,8 @@ static struct ab8500_regulator_info
 			.id		= AB8500_LDO_AUX3,
 			.owner		= THIS_MODULE,
 			.n_voltages	= ARRAY_SIZE(ldo_vaux3_voltages),
+			.volt_table	= ldo_vaux3_voltages,
 		},
-		.min_uV			= 1100000,
-		.max_uV			= 3300000,
 		.update_bank		= 0x04,
 		.update_reg		= 0x0a,
 		.update_mask		= 0x03,
@@ -391,8 +340,6 @@ static struct ab8500_regulator_info
 		.voltage_bank		= 0x04,
 		.voltage_reg		= 0x21,
 		.voltage_mask		= 0x07,
-		.voltages		= ldo_vaux3_voltages,
-		.voltages_len		= ARRAY_SIZE(ldo_vaux3_voltages),
 	},
 	[AB8500_LDO_INTCORE] = {
 		.desc = {
@@ -402,9 +349,8 @@ static struct ab8500_regulator_info
 			.id		= AB8500_LDO_INTCORE,
 			.owner		= THIS_MODULE,
 			.n_voltages	= ARRAY_SIZE(ldo_vintcore_voltages),
+			.volt_table	= ldo_vintcore_voltages,
 		},
-		.min_uV			= 1100000,
-		.max_uV			= 3300000,
 		.update_bank		= 0x03,
 		.update_reg		= 0x80,
 		.update_mask		= 0x44,
@@ -412,8 +358,6 @@ static struct ab8500_regulator_info
 		.voltage_bank		= 0x03,
 		.voltage_reg		= 0x80,
 		.voltage_mask		= 0x38,
-		.voltages		= ldo_vintcore_voltages,
-		.voltages_len		= ARRAY_SIZE(ldo_vintcore_voltages),
 	},
 
 	/*
@@ -429,9 +373,9 @@ static struct ab8500_regulator_info
 			.id		= AB8500_LDO_TVOUT,
 			.owner		= THIS_MODULE,
 			.n_voltages	= 1,
+			.min_uV		= 2000000,
 		},
 		.delay			= 10000,
-		.fixed_uV		= 2000000,
 		.update_bank		= 0x03,
 		.update_reg		= 0x80,
 		.update_mask		= 0x82,
@@ -445,8 +389,8 @@ static struct ab8500_regulator_info
 			.id             = AB8500_LDO_USB,
 			.owner          = THIS_MODULE,
 			.n_voltages     = 1,
+			.min_uV		= 3300000,
 		},
-		.fixed_uV               = 3300000,
 		.update_bank            = 0x03,
 		.update_reg             = 0x82,
 		.update_mask            = 0x03,
@@ -460,8 +404,8 @@ static struct ab8500_regulator_info
 			.id		= AB8500_LDO_AUDIO,
 			.owner		= THIS_MODULE,
 			.n_voltages	= 1,
+			.min_uV		= 2000000,
 		},
-		.fixed_uV		= 2000000,
 		.update_bank		= 0x03,
 		.update_reg		= 0x83,
 		.update_mask		= 0x02,
@@ -475,8 +419,8 @@ static struct ab8500_regulator_info
 			.id		= AB8500_LDO_ANAMIC1,
 			.owner		= THIS_MODULE,
 			.n_voltages	= 1,
+			.min_uV		= 2050000,
 		},
-		.fixed_uV		= 2050000,
 		.update_bank		= 0x03,
 		.update_reg		= 0x83,
 		.update_mask		= 0x08,
@@ -490,8 +434,8 @@ static struct ab8500_regulator_info
 			.id		= AB8500_LDO_ANAMIC2,
 			.owner		= THIS_MODULE,
 			.n_voltages	= 1,
+			.min_uV		= 2050000,
 		},
-		.fixed_uV		= 2050000,
 		.update_bank		= 0x03,
 		.update_reg		= 0x83,
 		.update_mask		= 0x10,
@@ -505,8 +449,8 @@ static struct ab8500_regulator_info
 			.id		= AB8500_LDO_DMIC,
 			.owner		= THIS_MODULE,
 			.n_voltages	= 1,
+			.min_uV		= 1800000,
 		},
-		.fixed_uV		= 1800000,
 		.update_bank		= 0x03,
 		.update_reg		= 0x83,
 		.update_mask		= 0x04,
@@ -520,8 +464,8 @@ static struct ab8500_regulator_info
 			.id		= AB8500_LDO_ANA,
 			.owner		= THIS_MODULE,
 			.n_voltages	= 1,
+			.min_uV		= 1200000,
 		},
-		.fixed_uV		= 1200000,
 		.update_bank		= 0x04,
 		.update_reg		= 0x06,
 		.update_mask		= 0x0c,
@@ -769,9 +713,7 @@ static __devinit int ab8500_regulator_register(struct platform_device *pdev,
 		if (info->desc.id == AB8500_LDO_AUX3) {
 			info->desc.n_voltages =
 				ARRAY_SIZE(ldo_vauxn_voltages);
-			info->voltages = ldo_vauxn_voltages;
-			info->voltages_len =
-				ARRAY_SIZE(ldo_vauxn_voltages);
+			info->desc.volt_table = ldo_vauxn_voltages;
 			info->voltage_mask = 0xf;
 		}
 	}
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index e82e7ea..e9c2085 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -43,33 +43,15 @@ struct anatop_regulator {
 	struct regulator_init_data *initdata;
 };
 
-static int anatop_set_voltage(struct regulator_dev *reg, int min_uV,
-				  int max_uV, unsigned *selector)
+static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
 {
 	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
-	u32 val, sel, mask;
-	int uv;
-
-	uv = min_uV;
-	dev_dbg(&reg->dev, "%s: uv %d, min %d, max %d\n", __func__,
-		uv, anatop_reg->min_voltage,
-		anatop_reg->max_voltage);
-
-	if (uv < anatop_reg->min_voltage) {
-		if (max_uV > anatop_reg->min_voltage)
-			uv = anatop_reg->min_voltage;
-		else
-			return -EINVAL;
-	}
+	u32 val, mask;
 
 	if (!anatop_reg->control_reg)
 		return -ENOTSUPP;
 
-	sel = DIV_ROUND_UP(uv - anatop_reg->min_voltage, 25000);
-	if (sel * 25000 + anatop_reg->min_voltage > anatop_reg->max_voltage)
-		return -EINVAL;
-	val = anatop_reg->min_bit_val + sel;
-	*selector = sel;
+	val = anatop_reg->min_bit_val + selector;
 	dev_dbg(&reg->dev, "%s: calculated val %d\n", __func__, val);
 	mask = ((1 << anatop_reg->vol_bit_width) - 1) <<
 		anatop_reg->vol_bit_shift;
@@ -94,21 +76,11 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg)
 	return val - anatop_reg->min_bit_val;
 }
 
-static int anatop_list_voltage(struct regulator_dev *reg, unsigned selector)
-{
-	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
-	int uv;
-
-	uv = anatop_reg->min_voltage + selector * 25000;
-	dev_dbg(&reg->dev, "vddio = %d, selector = %u\n", uv, selector);
-
-	return uv;
-}
-
 static struct regulator_ops anatop_rops = {
-	.set_voltage     = anatop_set_voltage,
+	.set_voltage_sel = anatop_set_voltage_sel,
 	.get_voltage_sel = anatop_get_voltage_sel,
-	.list_voltage    = anatop_list_voltage,
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
 };
 
 static int __devinit anatop_regulator_probe(struct platform_device *pdev)
@@ -176,6 +148,8 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev)
 
 	rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage)
 		/ 25000 + 1;
+	rdesc->min_uV = sreg->min_voltage;
+	rdesc->uV_step = 25000;
 
 	config.dev = &pdev->dev;
 	config.init_data = initdata;
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
new file mode 100644
index 0000000..51f02ca
--- /dev/null
+++ b/drivers/regulator/arizona-ldo1.c
@@ -0,0 +1,134 @@
+/*
+ * arizona-ldo1.c  --  LDO1 supply for Arizona devices
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/pdata.h>
+#include <linux/mfd/arizona/registers.h>
+
+struct arizona_ldo1 {
+	struct regulator_dev *regulator;
+	struct arizona *arizona;
+
+	struct regulator_consumer_supply supply;
+	struct regulator_init_data init_data;
+};
+
+static struct regulator_ops arizona_ldo1_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_desc arizona_ldo1 = {
+	.name = "LDO1",
+	.supply_name = "LDOVDD",
+	.type = REGULATOR_VOLTAGE,
+	.ops = &arizona_ldo1_ops,
+
+	.vsel_reg = ARIZONA_LDO1_CONTROL_1,
+	.vsel_mask = ARIZONA_LDO1_VSEL_MASK,
+	.min_uV = 900000,
+	.uV_step = 50000,
+	.n_voltages = 7,
+
+	.owner = THIS_MODULE,
+};
+
+static const struct regulator_init_data arizona_ldo1_default = {
+	.num_consumer_supplies = 1,
+};
+
+static __devinit int arizona_ldo1_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct regulator_config config = { };
+	struct arizona_ldo1 *ldo1;
+	int ret;
+
+	ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
+	if (ldo1 == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	ldo1->arizona = arizona;
+
+	/*
+	 * Since the chip usually supplies itself we provide some
+	 * default init_data for it.  This will be overridden with
+	 * platform data if provided.
+	 */
+	ldo1->init_data = arizona_ldo1_default;
+	ldo1->init_data.consumer_supplies = &ldo1->supply;
+	ldo1->supply.supply = "DCVDD";
+	ldo1->supply.dev_name = dev_name(arizona->dev);
+
+	config.dev = arizona->dev;
+	config.driver_data = ldo1;
+	config.regmap = arizona->regmap;
+
+	if (arizona->pdata.ldo1)
+		config.init_data = arizona->pdata.ldo1;
+	else
+		config.init_data = &ldo1->init_data;
+
+	ldo1->regulator = regulator_register(&arizona_ldo1, &config);
+	if (IS_ERR(ldo1->regulator)) {
+		ret = PTR_ERR(ldo1->regulator);
+		dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n",
+			ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, ldo1);
+
+	return 0;
+}
+
+static __devexit int arizona_ldo1_remove(struct platform_device *pdev)
+{
+	struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev);
+
+	regulator_unregister(ldo1->regulator);
+
+	return 0;
+}
+
+static struct platform_driver arizona_ldo1_driver = {
+	.probe = arizona_ldo1_probe,
+	.remove = __devexit_p(arizona_ldo1_remove),
+	.driver		= {
+		.name	= "arizona-ldo1",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(arizona_ldo1_driver);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Arizona LDO1 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:arizona-ldo1");
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
new file mode 100644
index 0000000..fdd7473
--- /dev/null
+++ b/drivers/regulator/arizona-micsupp.c
@@ -0,0 +1,184 @@
+/*
+ * arizona-micsupp.c  --  Microphone supply for Arizona devices
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/pdata.h>
+#include <linux/mfd/arizona/registers.h>
+
+#define ARIZONA_MICSUPP_MAX_SELECTOR 0x1f
+
+struct arizona_micsupp {
+	struct regulator_dev *regulator;
+	struct arizona *arizona;
+
+	struct regulator_consumer_supply supply;
+	struct regulator_init_data init_data;
+};
+
+static int arizona_micsupp_list_voltage(struct regulator_dev *rdev,
+					unsigned int selector)
+{
+	if (selector > ARIZONA_MICSUPP_MAX_SELECTOR)
+		return -EINVAL;
+
+	if (selector == ARIZONA_MICSUPP_MAX_SELECTOR)
+		return 3300000;
+	else
+		return (selector * 50000) + 1700000;
+}
+
+static int arizona_micsupp_map_voltage(struct regulator_dev *rdev,
+				       int min_uV, int max_uV)
+{
+	unsigned int voltage;
+	int selector;
+
+	if (min_uV < 1700000)
+		min_uV = 1700000;
+
+	if (min_uV > 3200000)
+		selector = ARIZONA_MICSUPP_MAX_SELECTOR;
+	else
+		selector = DIV_ROUND_UP(min_uV - 1700000, 50000);
+
+	if (selector < 0)
+		return -EINVAL;
+
+	voltage = arizona_micsupp_list_voltage(rdev, selector);
+	if (voltage < min_uV || voltage > max_uV)
+		return -EINVAL;
+
+	return selector;
+}
+
+static struct regulator_ops arizona_micsupp_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+
+	.list_voltage = arizona_micsupp_list_voltage,
+	.map_voltage = arizona_micsupp_map_voltage,
+
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_desc arizona_micsupp = {
+	.name = "MICVDD",
+	.supply_name = "CPVDD",
+	.type = REGULATOR_VOLTAGE,
+	.n_voltages = ARIZONA_MICSUPP_MAX_SELECTOR + 1,
+	.ops = &arizona_micsupp_ops,
+
+	.vsel_reg = ARIZONA_LDO2_CONTROL_1,
+	.vsel_mask = ARIZONA_LDO2_VSEL_MASK,
+	.enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
+	.enable_mask = ARIZONA_CPMIC_ENA,
+
+	.owner = THIS_MODULE,
+};
+
+static const struct regulator_init_data arizona_micsupp_default = {
+	.constraints = {
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS |
+				REGULATOR_CHANGE_VOLTAGE,
+		.min_uV = 1700000,
+		.max_uV = 3300000,
+	},
+
+	.num_consumer_supplies = 1,
+};
+
+static __devinit int arizona_micsupp_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct regulator_config config = { };
+	struct arizona_micsupp *micsupp;
+	int ret;
+
+	micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
+	if (micsupp == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	micsupp->arizona = arizona;
+
+	/*
+	 * Since the chip usually supplies itself we provide some
+	 * default init_data for it.  This will be overridden with
+	 * platform data if provided.
+	 */
+	micsupp->init_data = arizona_micsupp_default;
+	micsupp->init_data.consumer_supplies = &micsupp->supply;
+	micsupp->supply.supply = "MICVDD";
+	micsupp->supply.dev_name = dev_name(arizona->dev);
+
+	config.dev = arizona->dev;
+	config.driver_data = micsupp;
+	config.regmap = arizona->regmap;
+
+	if (arizona->pdata.micvdd)
+		config.init_data = arizona->pdata.micvdd;
+	else
+		config.init_data = &micsupp->init_data;
+
+	micsupp->regulator = regulator_register(&arizona_micsupp, &config);
+	if (IS_ERR(micsupp->regulator)) {
+		ret = PTR_ERR(micsupp->regulator);
+		dev_err(arizona->dev, "Failed to register mic supply: %d\n",
+			ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, micsupp);
+
+	return 0;
+}
+
+static __devexit int arizona_micsupp_remove(struct platform_device *pdev)
+{
+	struct arizona_micsupp *micsupp = platform_get_drvdata(pdev);
+
+	regulator_unregister(micsupp->regulator);
+
+	return 0;
+}
+
+static struct platform_driver arizona_micsupp_driver = {
+	.probe = arizona_micsupp_probe,
+	.remove = __devexit_p(arizona_micsupp_remove),
+	.driver		= {
+		.name	= "arizona-micsupp",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(arizona_micsupp_driver);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Arizona microphone supply driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:arizona-micsupp");
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 09a737c..da31b8a 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -303,18 +303,6 @@ static int regulator_check_drms(struct regulator_dev *rdev)
 	return 0;
 }
 
-static ssize_t device_requested_uA_show(struct device *dev,
-			     struct device_attribute *attr, char *buf)
-{
-	struct regulator *regulator;
-
-	regulator = get_device_regulator(dev);
-	if (regulator == NULL)
-		return 0;
-
-	return sprintf(buf, "%d\n", regulator->uA_load);
-}
-
 static ssize_t regulator_uV_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
@@ -967,6 +955,14 @@ static int set_machine_constraints(struct regulator_dev *rdev,
 		}
 	}
 
+	if (rdev->constraints->ramp_delay && ops->set_ramp_delay) {
+		ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
+		if (ret < 0) {
+			rdev_err(rdev, "failed to set ramp_delay\n");
+			goto out;
+		}
+	}
+
 	print_constraints(rdev);
 	return 0;
 out:
@@ -1097,48 +1093,27 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
 	list_add(&regulator->list, &rdev->consumer_list);
 
 	if (dev) {
-		/* create a 'requested_microamps_name' sysfs entry */
-		size = scnprintf(buf, REG_STR_SIZE,
-				 "microamps_requested_%s-%s",
-				 dev_name(dev), supply_name);
-		if (size >= REG_STR_SIZE)
-			goto overflow_err;
-
-		regulator->dev = dev;
-		sysfs_attr_init(&regulator->dev_attr.attr);
-		regulator->dev_attr.attr.name = kstrdup(buf, GFP_KERNEL);
-		if (regulator->dev_attr.attr.name == NULL)
-			goto attr_name_err;
-
-		regulator->dev_attr.attr.mode = 0444;
-		regulator->dev_attr.show = device_requested_uA_show;
-		err = device_create_file(dev, &regulator->dev_attr);
-		if (err < 0) {
-			rdev_warn(rdev, "could not add regulator_dev requested microamps sysfs entry\n");
-			goto attr_name_err;
-		}
-
-		/* also add a link to the device sysfs entry */
+		/* Add a link to the device sysfs entry */
 		size = scnprintf(buf, REG_STR_SIZE, "%s-%s",
 				 dev->kobj.name, supply_name);
 		if (size >= REG_STR_SIZE)
-			goto attr_err;
+			goto overflow_err;
 
 		regulator->supply_name = kstrdup(buf, GFP_KERNEL);
 		if (regulator->supply_name == NULL)
-			goto attr_err;
+			goto overflow_err;
 
 		err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj,
 					buf);
 		if (err) {
 			rdev_warn(rdev, "could not add device link %s err %d\n",
 				  dev->kobj.name, err);
-			goto link_name_err;
+			/* non-fatal */
 		}
 	} else {
 		regulator->supply_name = kstrdup(supply_name, GFP_KERNEL);
 		if (regulator->supply_name == NULL)
-			goto attr_err;
+			goto overflow_err;
 	}
 
 	regulator->debugfs = debugfs_create_dir(regulator->supply_name,
@@ -1165,12 +1140,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
 
 	mutex_unlock(&rdev->mutex);
 	return regulator;
-link_name_err:
-	kfree(regulator->supply_name);
-attr_err:
-	device_remove_file(regulator->dev, &regulator->dev_attr);
-attr_name_err:
-	kfree(regulator->dev_attr.attr.name);
 overflow_err:
 	list_del(&regulator->list);
 	kfree(regulator);
@@ -1459,11 +1428,9 @@ void devm_regulator_put(struct regulator *regulator)
 {
 	int rc;
 
-	rc = devres_destroy(regulator->dev, devm_regulator_release,
+	rc = devres_release(regulator->dev, devm_regulator_release,
 			    devm_regulator_match, regulator);
-	if (rc == 0)
-		regulator_put(regulator);
-	else
+	if (rc != 0)
 		WARN_ON(rc);
 }
 EXPORT_SYMBOL_GPL(devm_regulator_put);
@@ -1883,6 +1850,31 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev,
 EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
 
 /**
+ * regulator_list_voltage_table - List voltages with table based mapping
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with table based mapping between voltages and
+ * selectors can set volt_table in the regulator descriptor
+ * and then use this function as their list_voltage() operation.
+ */
+int regulator_list_voltage_table(struct regulator_dev *rdev,
+				 unsigned int selector)
+{
+	if (!rdev->desc->volt_table) {
+		BUG_ON(!rdev->desc->volt_table);
+		return -EINVAL;
+	}
+
+	if (selector >= rdev->desc->n_voltages)
+		return -EINVAL;
+
+	return rdev->desc->volt_table[selector];
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_table);
+
+/**
  * regulator_list_voltage - enumerate supported voltages
  * @regulator: regulator source
  * @selector: identify voltage to list
@@ -2045,6 +2037,14 @@ int regulator_map_voltage_linear(struct regulator_dev *rdev,
 {
 	int ret, voltage;
 
+	/* Allow uV_step to be 0 for fixed voltage */
+	if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) {
+		if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV)
+			return 0;
+		else
+			return -EINVAL;
+	}
+
 	if (!rdev->desc->uV_step) {
 		BUG_ON(!rdev->desc->uV_step);
 		return -EINVAL;
@@ -2084,7 +2084,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 	 * If we can't obtain the old selector there is not enough
 	 * info to call set_voltage_time_sel().
 	 */
-	if (rdev->desc->ops->set_voltage_time_sel &&
+	if (_regulator_is_enabled(rdev) &&
+	    rdev->desc->ops->set_voltage_time_sel &&
 	    rdev->desc->ops->get_voltage_sel) {
 		old_selector = rdev->desc->ops->get_voltage_sel(rdev);
 		if (old_selector < 0)
@@ -2095,12 +2096,18 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 		ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
 						   &selector);
 	} else if (rdev->desc->ops->set_voltage_sel) {
-		if (rdev->desc->ops->map_voltage)
+		if (rdev->desc->ops->map_voltage) {
 			ret = rdev->desc->ops->map_voltage(rdev, min_uV,
 							   max_uV);
-		else
-			ret = regulator_map_voltage_iterate(rdev, min_uV,
-							    max_uV);
+		} else {
+			if (rdev->desc->ops->list_voltage ==
+			    regulator_list_voltage_linear)
+				ret = regulator_map_voltage_linear(rdev,
+								min_uV, max_uV);
+			else
+				ret = regulator_map_voltage_iterate(rdev,
+								min_uV, max_uV);
+		}
 
 		if (ret >= 0) {
 			selector = ret;
@@ -2113,10 +2120,10 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 	if (rdev->desc->ops->list_voltage)
 		best_val = rdev->desc->ops->list_voltage(rdev, selector);
 	else
-		best_val = -1;
+		best_val = _regulator_get_voltage(rdev);
 
 	/* Call set_voltage_time_sel if successfully obtained old_selector */
-	if (ret == 0 && old_selector >= 0 &&
+	if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 &&
 	    rdev->desc->ops->set_voltage_time_sel) {
 
 		delay = rdev->desc->ops->set_voltage_time_sel(rdev,
@@ -2126,19 +2133,19 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 				  delay);
 			delay = 0;
 		}
-	}
 
-	/* Insert any necessary delays */
-	if (delay >= 1000) {
-		mdelay(delay / 1000);
-		udelay(delay % 1000);
-	} else if (delay) {
-		udelay(delay);
+		/* Insert any necessary delays */
+		if (delay >= 1000) {
+			mdelay(delay / 1000);
+			udelay(delay % 1000);
+		} else if (delay) {
+			udelay(delay);
+		}
 	}
 
-	if (ret == 0)
+	if (ret == 0 && best_val >= 0)
 		_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
-				     NULL);
+				     (void *)best_val);
 
 	trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val);
 
@@ -2249,6 +2256,46 @@ int regulator_set_voltage_time(struct regulator *regulator,
 EXPORT_SYMBOL_GPL(regulator_set_voltage_time);
 
 /**
+ *regulator_set_voltage_time_sel - get raise/fall time
+ * @regulator: regulator source
+ * @old_selector: selector for starting voltage
+ * @new_selector: selector for target voltage
+ *
+ * Provided with the starting and target voltage selectors, this function
+ * returns time in microseconds required to rise or fall to this new voltage
+ *
+ * Drivers providing ramp_delay in regulation_constraints can use this as their
+ * set_voltage_time_sel() operation.
+ */
+int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+				   unsigned int old_selector,
+				   unsigned int new_selector)
+{
+	unsigned int ramp_delay = 0;
+	int old_volt, new_volt;
+
+	if (rdev->constraints->ramp_delay)
+		ramp_delay = rdev->constraints->ramp_delay;
+	else if (rdev->desc->ramp_delay)
+		ramp_delay = rdev->desc->ramp_delay;
+
+	if (ramp_delay == 0) {
+		rdev_warn(rdev, "ramp_delay not set\n");
+		return 0;
+	}
+
+	/* sanity check */
+	if (!rdev->desc->ops->list_voltage)
+		return -EINVAL;
+
+	old_volt = rdev->desc->ops->list_voltage(rdev, old_selector);
+	new_volt = rdev->desc->ops->list_voltage(rdev, new_selector);
+
+	return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
+
+/**
  * regulator_sync_voltage - re-apply last regulator output voltage
  * @regulator: regulator source
  *
@@ -2628,7 +2675,7 @@ static void _notifier_call_chain(struct regulator_dev *rdev,
 				  unsigned long event, void *data)
 {
 	/* call rdev chain first */
-	blocking_notifier_call_chain(&rdev->notifier, event, NULL);
+	blocking_notifier_call_chain(&rdev->notifier, event, data);
 }
 
 /**
@@ -3105,7 +3152,10 @@ regulator_register(const struct regulator_desc *regulator_desc,
 	rdev->reg_data = config->driver_data;
 	rdev->owner = regulator_desc->owner;
 	rdev->desc = regulator_desc;
-	rdev->regmap = config->regmap;
+	if (config->regmap)
+		rdev->regmap = config->regmap;
+	else
+		rdev->regmap = dev_get_regmap(dev, NULL);
 	INIT_LIST_HEAD(&rdev->consumer_list);
 	INIT_LIST_HEAD(&rdev->list);
 	BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index 1005f5f..36c5b92 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -107,6 +107,9 @@ static int da903x_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
 	struct device *da9034_dev = to_da903x_dev(rdev);
 	uint8_t val, mask;
 
+	if (rdev->desc->n_voltages == 1)
+		return -EINVAL;
+
 	val = selector << info->vol_shift;
 	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
 
@@ -120,6 +123,9 @@ static int da903x_get_voltage_sel(struct regulator_dev *rdev)
 	uint8_t val, mask;
 	int ret;
 
+	if (rdev->desc->n_voltages == 1)
+		return 0;
+
 	ret = da903x_read(da9034_dev, info->vol_reg, &val);
 	if (ret)
 		return ret;
diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c
index cacd33c..f9d0279 100644
--- a/drivers/regulator/fixed-helper.c
+++ b/drivers/regulator/fixed-helper.c
@@ -1,4 +1,5 @@
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
@@ -13,17 +14,20 @@ static void regulator_fixed_release(struct device *dev)
 {
 	struct fixed_regulator_data *data = container_of(dev,
 			struct fixed_regulator_data, pdev.dev);
+	kfree(data->cfg.supply_name);
 	kfree(data);
 }
 
 /**
- * regulator_register_fixed - register a no-op fixed regulator
+ * regulator_register_fixed_name - register a no-op fixed regulator
  * @id: platform device id
+ * @name: name to be used for the regulator
  * @supplies: consumers for this regulator
  * @num_supplies: number of consumers
+ * @uv: voltage in microvolts
  */
-struct platform_device *regulator_register_fixed(int id,
-		struct regulator_consumer_supply *supplies, int num_supplies)
+struct platform_device *regulator_register_always_on(int id, const char *name,
+	struct regulator_consumer_supply *supplies, int num_supplies, int uv)
 {
 	struct fixed_regulator_data *data;
 
@@ -31,8 +35,13 @@ struct platform_device *regulator_register_fixed(int id,
 	if (!data)
 		return NULL;
 
-	data->cfg.supply_name = "fixed-dummy";
-	data->cfg.microvolts = 0;
+	data->cfg.supply_name = kstrdup(name, GFP_KERNEL);
+	if (!data->cfg.supply_name) {
+		kfree(data);
+		return NULL;
+	}
+
+	data->cfg.microvolts = uv;
 	data->cfg.gpio = -EINVAL;
 	data->cfg.enabled_at_boot = 1;
 	data->cfg.init_data = &data->init_data;
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index f09fe7b..8bda365 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -296,8 +296,6 @@ static const struct of_device_id fixed_of_match[] __devinitconst = {
 	{},
 };
 MODULE_DEVICE_TABLE(of, fixed_of_match);
-#else
-#define fixed_of_match NULL
 #endif
 
 static struct platform_driver regulator_fixed_voltage_driver = {
@@ -306,7 +304,7 @@ static struct platform_driver regulator_fixed_voltage_driver = {
 	.driver		= {
 		.name		= "reg-fixed-voltage",
 		.owner		= THIS_MODULE,
-		.of_match_table = fixed_of_match,
+		.of_match_table = of_match_ptr(fixed_of_match),
 	},
 };
 
diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c
index 56d273f..1d145a0 100644
--- a/drivers/regulator/isl6271a-regulator.c
+++ b/drivers/regulator/isl6271a-regulator.c
@@ -75,19 +75,12 @@ static struct regulator_ops isl_core_ops = {
 
 static int isl6271a_get_fixed_voltage(struct regulator_dev *dev)
 {
-	int id = rdev_get_id(dev);
-	return (id == 1) ? 1100000 : 1300000;
-}
-
-static int isl6271a_list_fixed_voltage(struct regulator_dev *dev, unsigned selector)
-{
-	int id = rdev_get_id(dev);
-	return (id == 1) ? 1100000 : 1300000;
+	return dev->desc->min_uV;
 }
 
 static struct regulator_ops isl_fixed_ops = {
 	.get_voltage	= isl6271a_get_fixed_voltage,
-	.list_voltage	= isl6271a_list_fixed_voltage,
+	.list_voltage	= regulator_list_voltage_linear,
 };
 
 static const struct regulator_desc isl_rd[] = {
@@ -107,6 +100,7 @@ static const struct regulator_desc isl_rd[] = {
 		.ops		= &isl_fixed_ops,
 		.type		= REGULATOR_VOLTAGE,
 		.owner		= THIS_MODULE,
+		.min_uV		= 1100000,
 	}, {
 		.name		= "LDO2",
 		.id		= 2,
@@ -114,6 +108,7 @@ static const struct regulator_desc isl_rd[] = {
 		.ops		= &isl_fixed_ops,
 		.type		= REGULATOR_VOLTAGE,
 		.owner		= THIS_MODULE,
+		.min_uV		= 1300000,
 	},
 };
 
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 981bea9..7c6e3b8 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -65,11 +65,11 @@ static const int buck_base_addr[] = {
 #define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x])
 #define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1)
 
-static const int buck_voltage_map[] = {
-	   0,  800,  850,  900,  950, 1000, 1050, 1100,
-	1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
-	1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
-	3000, 3300,
+static const unsigned int buck_voltage_map[] = {
+	      0,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
+	1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+	1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000,
+	3000000, 3300000,
 };
 
 #define BUCK_TARGET_VOL_MASK 0x3f
@@ -98,39 +98,19 @@ static const int buck_voltage_map[] = {
 #define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2)
 #define LDO_VOL_CONTR_MASK 0x0f
 
-static const int ldo45_voltage_map[] = {
-	1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
-	1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
+static const unsigned int ldo45_voltage_map[] = {
+	1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000,
+	1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000,
 };
 
-static const int ldo123_voltage_map[] = {
-	1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
-	2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
+static const unsigned int ldo123_voltage_map[] = {
+	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+	2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
 };
 
-static const int *ldo_voltage_map[] = {
-	ldo123_voltage_map, /* LDO1 */
-	ldo123_voltage_map, /* LDO2 */
-	ldo123_voltage_map, /* LDO3 */
-	ldo45_voltage_map, /* LDO4 */
-	ldo45_voltage_map, /* LDO5 */
-};
-
-#define LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[(x - LP3971_LDO1)])
-
 #define LDO_VOL_MIN_IDX 0x00
 #define LDO_VOL_MAX_IDX 0x0f
 
-static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
-{
-	int ldo = rdev_get_id(dev) - LP3971_LDO1;
-
-	if (index > LDO_VOL_MAX_IDX)
-		return -EINVAL;
-
-	return 1000 * LDO_VOL_VALUE_MAP(ldo)[index];
-}
-
 static int lp3971_ldo_is_enabled(struct regulator_dev *dev)
 {
 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
@@ -169,7 +149,7 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
 	reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
 	val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
 
-	return 1000 * LDO_VOL_VALUE_MAP(ldo)[val];
+	return dev->desc->volt_table[val];
 }
 
 static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
@@ -184,7 +164,7 @@ static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
 }
 
 static struct regulator_ops lp3971_ldo_ops = {
-	.list_voltage = lp3971_ldo_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 	.is_enabled = lp3971_ldo_is_enabled,
 	.enable = lp3971_ldo_enable,
 	.disable = lp3971_ldo_disable,
@@ -192,14 +172,6 @@ static struct regulator_ops lp3971_ldo_ops = {
 	.set_voltage_sel = lp3971_ldo_set_voltage_sel,
 };
 
-static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
-{
-	if (index < BUCK_TARGET_VOL_MIN_IDX || index > BUCK_TARGET_VOL_MAX_IDX)
-		return -EINVAL;
-
-	return 1000 * buck_voltage_map[index];
-}
-
 static int lp3971_dcdc_is_enabled(struct regulator_dev *dev)
 {
 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
@@ -240,7 +212,7 @@ static int lp3971_dcdc_get_voltage(struct regulator_dev *dev)
 	reg &= BUCK_TARGET_VOL_MASK;
 
 	if (reg <= BUCK_TARGET_VOL_MAX_IDX)
-		val = 1000 * buck_voltage_map[reg];
+		val = buck_voltage_map[reg];
 	else {
 		val = 0;
 		dev_warn(&dev->dev, "chip reported incorrect voltage value.\n");
@@ -273,7 +245,7 @@ static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev,
 }
 
 static struct regulator_ops lp3971_dcdc_ops = {
-	.list_voltage = lp3971_dcdc_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 	.is_enabled = lp3971_dcdc_is_enabled,
 	.enable = lp3971_dcdc_enable,
 	.disable = lp3971_dcdc_disable,
@@ -287,6 +259,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3971_LDO1,
 		.ops = &lp3971_ldo_ops,
 		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+		.volt_table = ldo123_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -295,6 +268,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3971_LDO2,
 		.ops = &lp3971_ldo_ops,
 		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+		.volt_table = ldo123_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -303,6 +277,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3971_LDO3,
 		.ops = &lp3971_ldo_ops,
 		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+		.volt_table = ldo123_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -311,6 +286,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3971_LDO4,
 		.ops = &lp3971_ldo_ops,
 		.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
+		.volt_table = ldo45_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -319,6 +295,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3971_LDO5,
 		.ops = &lp3971_ldo_ops,
 		.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
+		.volt_table = ldo45_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -327,6 +304,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3971_DCDC1,
 		.ops = &lp3971_dcdc_ops,
 		.n_voltages = ARRAY_SIZE(buck_voltage_map),
+		.volt_table = buck_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -335,6 +313,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3971_DCDC2,
 		.ops = &lp3971_dcdc_ops,
 		.n_voltages = ARRAY_SIZE(buck_voltage_map),
+		.volt_table = buck_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -343,6 +322,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3971_DCDC3,
 		.ops = &lp3971_dcdc_ops,
 		.n_voltages = ARRAY_SIZE(buck_voltage_map),
+		.volt_table = buck_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c
index de073df..3cdc755 100644
--- a/drivers/regulator/lp3972.c
+++ b/drivers/regulator/lp3972.c
@@ -74,54 +74,40 @@ struct lp3972 {
 #define LP3972_OVER2_LDO4_EN	BIT(4)
 #define LP3972_OVER1_S_EN	BIT(2)
 
-static const int ldo1_voltage_map[] = {
-	1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875,
-	1900, 1925, 1950, 1975, 2000,
+static const unsigned int ldo1_voltage_map[] = {
+	1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000,
+	1900000, 1925000, 1950000, 1975000, 2000000,
 };
 
-static const int ldo23_voltage_map[] = {
-	1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
-	2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
+static const unsigned int ldo23_voltage_map[] = {
+	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+	2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
 };
 
-static const int ldo4_voltage_map[] = {
-	1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
-	1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
+static const unsigned int ldo4_voltage_map[] = {
+	1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000,
+	1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000,
 };
 
-static const int ldo5_voltage_map[] = {
-	   0,    0,    0,    0,    0,  850,  875,  900,
-	 925,  950,  975, 1000, 1025, 1050, 1075, 1100,
-	1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
-	1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+static const unsigned int ldo5_voltage_map[] = {
+	      0,       0,       0,       0,       0,  850000,  875000,  900000,
+	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
+	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
+	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
 };
 
-static const int buck1_voltage_map[] = {
-	 725,  750,  775,  800,  825,  850,  875,  900,
-	 925,  950,  975, 1000, 1025, 1050, 1075, 1100,
-	1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
-	1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+static const unsigned int buck1_voltage_map[] = {
+	 725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
+	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
+	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
+	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
 };
 
-static const int buck23_voltage_map[] = {
-	   0,  800,  850,  900,  950, 1000, 1050, 1100,
-	1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
-	1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
-	3000, 3300,
-};
-
-static const int *ldo_voltage_map[] = {
-	ldo1_voltage_map,
-	ldo23_voltage_map,
-	ldo23_voltage_map,
-	ldo4_voltage_map,
-	ldo5_voltage_map,
-};
-
-static const int *buck_voltage_map[] = {
-	buck1_voltage_map,
-	buck23_voltage_map,
-	buck23_voltage_map,
+static const unsigned int buck23_voltage_map[] = {
+	      0,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
+	1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+	1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000,
+	3000000, 3300000,
 };
 
 static const int ldo_output_enable_mask[] = {
@@ -160,7 +146,6 @@ static const int buck_base_addr[] = {
 	LP3972_B3TV_REG,
 };
 
-#define LP3972_LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[x])
 #define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x])
 #define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x])
 
@@ -177,7 +162,6 @@ static const int buck_base_addr[] = {
 #define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00)
 #define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c)
 
-#define LP3972_BUCK_VOL_VALUE_MAP(x) (buck_voltage_map[x])
 #define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x])
 #define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x])
 #define LP3972_BUCK_VOL_MASK 0x1f
@@ -242,17 +226,6 @@ static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val)
 	return ret;
 }
 
-static int lp3972_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
-{
-	int ldo = rdev_get_id(dev) - LP3972_LDO1;
-
-	if (index < LP3972_LDO_VOL_MIN_IDX(ldo) ||
-	    index > LP3972_LDO_VOL_MAX_IDX(ldo))
-		return -EINVAL;
-
-	return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[index];
-}
-
 static int lp3972_ldo_is_enabled(struct regulator_dev *dev)
 {
 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
@@ -294,7 +267,7 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
 	reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo));
 	val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask;
 
-	return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[val];
+	return dev->desc->volt_table[val];
 }
 
 static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
@@ -337,7 +310,7 @@ static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
 }
 
 static struct regulator_ops lp3972_ldo_ops = {
-	.list_voltage = lp3972_ldo_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 	.is_enabled = lp3972_ldo_is_enabled,
 	.enable = lp3972_ldo_enable,
 	.disable = lp3972_ldo_disable,
@@ -345,17 +318,6 @@ static struct regulator_ops lp3972_ldo_ops = {
 	.set_voltage_sel = lp3972_ldo_set_voltage_sel,
 };
 
-static int lp3972_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
-{
-	int buck = rdev_get_id(dev) - LP3972_DCDC1;
-
-	if (index < LP3972_BUCK_VOL_MIN_IDX(buck) ||
-	    index > LP3972_BUCK_VOL_MAX_IDX(buck))
-		return -EINVAL;
-
-	return 1000 * buck_voltage_map[buck][index];
-}
-
 static int lp3972_dcdc_is_enabled(struct regulator_dev *dev)
 {
 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
@@ -401,7 +363,7 @@ static int lp3972_dcdc_get_voltage(struct regulator_dev *dev)
 	reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck));
 	reg &= LP3972_BUCK_VOL_MASK;
 	if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck))
-		val = 1000 * buck_voltage_map[buck][reg];
+		val = dev->desc->volt_table[reg];
 	else {
 		val = 0;
 		dev_warn(&dev->dev, "chip reported incorrect voltage value."
@@ -436,7 +398,7 @@ static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev,
 }
 
 static struct regulator_ops lp3972_dcdc_ops = {
-	.list_voltage = lp3972_dcdc_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 	.is_enabled = lp3972_dcdc_is_enabled,
 	.enable = lp3972_dcdc_enable,
 	.disable = lp3972_dcdc_disable,
@@ -450,6 +412,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3972_LDO1,
 		.ops = &lp3972_ldo_ops,
 		.n_voltages = ARRAY_SIZE(ldo1_voltage_map),
+		.volt_table = ldo1_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -458,6 +421,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3972_LDO2,
 		.ops = &lp3972_ldo_ops,
 		.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
+		.volt_table = ldo23_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -466,6 +430,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3972_LDO3,
 		.ops = &lp3972_ldo_ops,
 		.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
+		.volt_table = ldo23_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -474,6 +439,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3972_LDO4,
 		.ops = &lp3972_ldo_ops,
 		.n_voltages = ARRAY_SIZE(ldo4_voltage_map),
+		.volt_table = ldo4_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -482,6 +448,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3972_LDO5,
 		.ops = &lp3972_ldo_ops,
 		.n_voltages = ARRAY_SIZE(ldo5_voltage_map),
+		.volt_table = ldo5_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -490,6 +457,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3972_DCDC1,
 		.ops = &lp3972_dcdc_ops,
 		.n_voltages = ARRAY_SIZE(buck1_voltage_map),
+		.volt_table = buck1_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -498,6 +466,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3972_DCDC2,
 		.ops = &lp3972_dcdc_ops,
 		.n_voltages = ARRAY_SIZE(buck23_voltage_map),
+		.volt_table = buck23_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
@@ -506,6 +475,7 @@ static const struct regulator_desc regulators[] = {
 		.id = LP3972_DCDC3,
 		.ops = &lp3972_dcdc_ops,
 		.n_voltages = ARRAY_SIZE(buck23_voltage_map),
+		.volt_table = buck23_voltage_map,
 		.type = REGULATOR_VOLTAGE,
 		.owner = THIS_MODULE,
 	},
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
new file mode 100644
index 0000000..471f8e8
--- /dev/null
+++ b/drivers/regulator/lp872x.c
@@ -0,0 +1,957 @@
+/*
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/regulator/lp872x.h>
+#include <linux/regulator/driver.h>
+#include <linux/platform_device.h>
+
+/* Registers : LP8720/8725 shared */
+#define LP872X_GENERAL_CFG		0x00
+#define LP872X_LDO1_VOUT		0x01
+#define LP872X_LDO2_VOUT		0x02
+#define LP872X_LDO3_VOUT		0x03
+#define LP872X_LDO4_VOUT		0x04
+#define LP872X_LDO5_VOUT		0x05
+
+/* Registers : LP8720 */
+#define LP8720_BUCK_VOUT1		0x06
+#define LP8720_BUCK_VOUT2		0x07
+#define LP8720_ENABLE			0x08
+
+/* Registers : LP8725 */
+#define LP8725_LILO1_VOUT		0x06
+#define LP8725_LILO2_VOUT		0x07
+#define LP8725_BUCK1_VOUT1		0x08
+#define LP8725_BUCK1_VOUT2		0x09
+#define LP8725_BUCK2_VOUT1		0x0A
+#define LP8725_BUCK2_VOUT2		0x0B
+#define LP8725_BUCK_CTRL		0x0C
+#define LP8725_LDO_CTRL			0x0D
+
+/* Mask/shift : LP8720/LP8725 shared */
+#define LP872X_VOUT_M			0x1F
+#define LP872X_START_DELAY_M		0xE0
+#define LP872X_START_DELAY_S		5
+#define LP872X_EN_LDO1_M		BIT(0)
+#define LP872X_EN_LDO2_M		BIT(1)
+#define LP872X_EN_LDO3_M		BIT(2)
+#define LP872X_EN_LDO4_M		BIT(3)
+#define LP872X_EN_LDO5_M		BIT(4)
+
+/* Mask/shift : LP8720 */
+#define LP8720_TIMESTEP_S		0		/* Addr 00h */
+#define LP8720_TIMESTEP_M		BIT(0)
+#define LP8720_EXT_DVS_M		BIT(2)
+#define LP8720_BUCK_FPWM_S		5		/* Addr 07h */
+#define LP8720_BUCK_FPWM_M		BIT(5)
+#define LP8720_EN_BUCK_M		BIT(5)		/* Addr 08h */
+#define LP8720_DVS_SEL_M		BIT(7)
+
+/* Mask/shift : LP8725 */
+#define LP8725_TIMESTEP_M		0xC0		/* Addr 00h */
+#define LP8725_TIMESTEP_S		6
+#define LP8725_BUCK1_EN_M		BIT(0)
+#define LP8725_DVS1_M			BIT(2)
+#define LP8725_DVS2_M			BIT(3)
+#define LP8725_BUCK2_EN_M		BIT(4)
+#define LP8725_BUCK_CL_M		0xC0		/* Addr 09h, 0Bh */
+#define LP8725_BUCK_CL_S		6
+#define LP8725_BUCK1_FPWM_S		1		/* Addr 0Ch */
+#define LP8725_BUCK1_FPWM_M		BIT(1)
+#define LP8725_BUCK2_FPWM_S		5
+#define LP8725_BUCK2_FPWM_M		BIT(5)
+#define LP8725_EN_LILO1_M		BIT(5)		/* Addr 0Dh */
+#define LP8725_EN_LILO2_M		BIT(6)
+
+/* PWM mode */
+#define LP872X_FORCE_PWM		1
+#define LP872X_AUTO_PWM			0
+
+#define LP8720_NUM_REGULATORS		6
+#define LP8725_NUM_REGULATORS		9
+#define EXTERN_DVS_USED			0
+#define MAX_DELAY			6
+
+/* dump registers in regmap-debugfs */
+#define MAX_REGISTERS			0x0F
+
+enum lp872x_id {
+	LP8720,
+	LP8725,
+};
+
+struct lp872x {
+	struct regmap *regmap;
+	struct device *dev;
+	enum lp872x_id chipid;
+	struct lp872x_platform_data *pdata;
+	struct regulator_dev **regulators;
+	int num_regulators;
+	enum lp872x_dvs_state dvs_pin;
+	int dvs_gpio;
+};
+
+/* LP8720/LP8725 shared voltage table for LDOs */
+static const unsigned int lp872x_ldo_vtbl[] = {
+	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
+	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 2000000,
+	2100000, 2200000, 2300000, 2400000, 2500000, 2600000, 2650000, 2700000,
+	2750000, 2800000, 2850000, 2900000, 2950000, 3000000, 3100000, 3300000,
+};
+
+/* LP8720 LDO4 voltage table */
+static const unsigned int lp8720_ldo4_vtbl[] = {
+	 800000,  850000,  900000, 1000000, 1100000, 1200000, 1250000, 1300000,
+	1350000, 1400000, 1450000, 1500000, 1550000, 1600000, 1650000, 1700000,
+	1750000, 1800000, 1850000, 1900000, 2000000, 2100000, 2200000, 2300000,
+	2400000, 2500000, 2600000, 2650000, 2700000, 2750000, 2800000, 2850000,
+};
+
+/* LP8725 LILO(Low Input Low Output) voltage table */
+static const unsigned int lp8725_lilo_vtbl[] = {
+	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
+	1200000, 1250000, 1300000, 1350000, 1400000, 1500000, 1600000, 1700000,
+	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+	2600000, 2700000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
+};
+
+/* LP8720 BUCK voltage table */
+#define EXT_R		0	/* external resistor divider */
+static const unsigned int lp8720_buck_vtbl[] = {
+	  EXT_R,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
+	1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+	1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000,
+	1950000, 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000,
+};
+
+/* LP8725 BUCK voltage table */
+static const unsigned int lp8725_buck_vtbl[] = {
+	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
+	1200000, 1250000, 1300000, 1350000, 1400000, 1500000, 1600000, 1700000,
+	1750000, 1800000, 1850000, 1900000, 2000000, 2100000, 2200000, 2300000,
+	2400000, 2500000, 2600000, 2700000, 2800000, 2850000, 2900000, 3000000,
+};
+
+/* LP8725 BUCK current limit */
+static const unsigned int lp8725_buck_uA[] = {
+	460000, 780000, 1050000, 1370000,
+};
+
+static int lp872x_read_byte(struct lp872x *lp, u8 addr, u8 *data)
+{
+	int ret;
+	unsigned int val;
+
+	ret = regmap_read(lp->regmap, addr, &val);
+	if (ret < 0) {
+		dev_err(lp->dev, "failed to read 0x%.2x\n", addr);
+		return ret;
+	}
+
+	*data = (u8)val;
+	return 0;
+}
+
+static inline int lp872x_write_byte(struct lp872x *lp, u8 addr, u8 data)
+{
+	return regmap_write(lp->regmap, addr, data);
+}
+
+static inline int lp872x_update_bits(struct lp872x *lp, u8 addr,
+				unsigned int mask, u8 data)
+{
+	return regmap_update_bits(lp->regmap, addr, mask, data);
+}
+
+static int _rdev_to_offset(struct regulator_dev *rdev)
+{
+	enum lp872x_regulator_id id = rdev_get_id(rdev);
+
+	switch (id) {
+	case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
+		return id;
+	case LP8725_ID_LDO1 ... LP8725_ID_BUCK2:
+		return id - LP8725_ID_BASE;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int lp872x_get_timestep_usec(struct lp872x *lp)
+{
+	enum lp872x_id chip = lp->chipid;
+	u8 val, mask, shift;
+	int *time_usec, size, ret;
+	int lp8720_time_usec[] = { 25, 50 };
+	int lp8725_time_usec[] = { 32, 64, 128, 256 };
+
+	switch (chip) {
+	case LP8720:
+		mask = LP8720_TIMESTEP_M;
+		shift = LP8720_TIMESTEP_S;
+		time_usec = &lp8720_time_usec[0];
+		size = ARRAY_SIZE(lp8720_time_usec);
+		break;
+	case LP8725:
+		mask = LP8725_TIMESTEP_M;
+		shift = LP8725_TIMESTEP_S;
+		time_usec = &lp8725_time_usec[0];
+		size = ARRAY_SIZE(lp8725_time_usec);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val);
+	if (ret)
+		return -EINVAL;
+
+	val = (val & mask) >> shift;
+	if (val >= size)
+		return -EINVAL;
+
+	return *(time_usec + val);
+}
+
+static int lp872x_regulator_enable_time(struct regulator_dev *rdev)
+{
+	struct lp872x *lp = rdev_get_drvdata(rdev);
+	enum lp872x_regulator_id regulator = rdev_get_id(rdev);
+	int time_step_us = lp872x_get_timestep_usec(lp);
+	int ret, offset;
+	u8 addr, val;
+
+	if (time_step_us < 0)
+		return -EINVAL;
+
+	switch (regulator) {
+	case LP8720_ID_LDO1 ... LP8720_ID_LDO5:
+	case LP8725_ID_LDO1 ... LP8725_ID_LILO2:
+		offset = _rdev_to_offset(rdev);
+		if (offset < 0)
+			return -EINVAL;
+
+		addr = LP872X_LDO1_VOUT + offset;
+		break;
+	case LP8720_ID_BUCK:
+		addr = LP8720_BUCK_VOUT1;
+		break;
+	case LP8725_ID_BUCK1:
+		addr = LP8725_BUCK1_VOUT1;
+		break;
+	case LP8725_ID_BUCK2:
+		addr = LP8725_BUCK2_VOUT1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = lp872x_read_byte(lp, addr, &val);
+	if (ret)
+		return ret;
+
+	val = (val & LP872X_START_DELAY_M) >> LP872X_START_DELAY_S;
+
+	return val > MAX_DELAY ? 0 : val * time_step_us;
+}
+
+static void lp872x_set_dvs(struct lp872x *lp, int gpio)
+{
+	enum lp872x_dvs_sel dvs_sel = lp->pdata->dvs->vsel;
+	enum lp872x_dvs_state state;
+
+	state = dvs_sel == SEL_V1 ? DVS_HIGH : DVS_LOW;
+	gpio_set_value(gpio, state);
+	lp->dvs_pin = state;
+}
+
+static u8 lp872x_select_buck_vout_addr(struct lp872x *lp,
+				enum lp872x_regulator_id buck)
+{
+	u8 val, addr;
+
+	if (lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val))
+		return 0;
+
+	switch (buck) {
+	case LP8720_ID_BUCK:
+		if (val & LP8720_EXT_DVS_M) {
+			addr = (lp->dvs_pin == DVS_HIGH) ?
+				LP8720_BUCK_VOUT1 : LP8720_BUCK_VOUT2;
+		} else {
+			if (lp872x_read_byte(lp, LP8720_ENABLE, &val))
+				return 0;
+
+			addr = val & LP8720_DVS_SEL_M ?
+				LP8720_BUCK_VOUT1 : LP8720_BUCK_VOUT2;
+		}
+		break;
+	case LP8725_ID_BUCK1:
+		if (val & LP8725_DVS1_M)
+			addr = LP8725_BUCK1_VOUT1;
+		else
+			addr = (lp->dvs_pin == DVS_HIGH) ?
+				LP8725_BUCK1_VOUT1 : LP8725_BUCK1_VOUT2;
+		break;
+	case LP8725_ID_BUCK2:
+		addr =  val & LP8725_DVS2_M ?
+			LP8725_BUCK2_VOUT1 : LP8725_BUCK2_VOUT2;
+		break;
+	default:
+		return 0;
+	}
+
+	return addr;
+}
+
+static bool lp872x_is_valid_buck_addr(u8 addr)
+{
+	switch (addr) {
+	case LP8720_BUCK_VOUT1:
+	case LP8720_BUCK_VOUT2:
+	case LP8725_BUCK1_VOUT1:
+	case LP8725_BUCK1_VOUT2:
+	case LP8725_BUCK2_VOUT1:
+	case LP8725_BUCK2_VOUT2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int lp872x_buck_set_voltage_sel(struct regulator_dev *rdev,
+					unsigned selector)
+{
+	struct lp872x *lp = rdev_get_drvdata(rdev);
+	enum lp872x_regulator_id buck = rdev_get_id(rdev);
+	u8 addr, mask = LP872X_VOUT_M;
+	struct lp872x_dvs *dvs = lp->pdata->dvs;
+
+	if (dvs && gpio_is_valid(dvs->gpio))
+		lp872x_set_dvs(lp, dvs->gpio);
+
+	addr = lp872x_select_buck_vout_addr(lp, buck);
+	if (!lp872x_is_valid_buck_addr(addr))
+		return -EINVAL;
+
+	return lp872x_update_bits(lp, addr, mask, selector);
+}
+
+static int lp872x_buck_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct lp872x *lp = rdev_get_drvdata(rdev);
+	enum lp872x_regulator_id buck = rdev_get_id(rdev);
+	u8 addr, val;
+	int ret;
+
+	addr = lp872x_select_buck_vout_addr(lp, buck);
+	if (!lp872x_is_valid_buck_addr(addr))
+		return -EINVAL;
+
+	ret = lp872x_read_byte(lp, addr, &val);
+	if (ret)
+		return ret;
+
+	return val & LP872X_VOUT_M;
+}
+
+static int lp8725_buck_set_current_limit(struct regulator_dev *rdev,
+					int min_uA, int max_uA)
+{
+	struct lp872x *lp = rdev_get_drvdata(rdev);
+	enum lp872x_regulator_id buck = rdev_get_id(rdev);
+	int i, max = ARRAY_SIZE(lp8725_buck_uA);
+	u8 addr, val;
+
+	switch (buck) {
+	case LP8725_ID_BUCK1:
+		addr = LP8725_BUCK1_VOUT2;
+		break;
+	case LP8725_ID_BUCK2:
+		addr = LP8725_BUCK2_VOUT2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0 ; i < max ; i++)
+		if (lp8725_buck_uA[i] >= min_uA &&
+			lp8725_buck_uA[i] <= max_uA)
+			break;
+
+	if (i == max)
+		return -EINVAL;
+
+	val = i << LP8725_BUCK_CL_S;
+
+	return lp872x_update_bits(lp, addr, LP8725_BUCK_CL_M, val);
+}
+
+static int lp8725_buck_get_current_limit(struct regulator_dev *rdev)
+{
+	struct lp872x *lp = rdev_get_drvdata(rdev);
+	enum lp872x_regulator_id buck = rdev_get_id(rdev);
+	u8 addr, val;
+	int ret;
+
+	switch (buck) {
+	case LP8725_ID_BUCK1:
+		addr = LP8725_BUCK1_VOUT2;
+		break;
+	case LP8725_ID_BUCK2:
+		addr = LP8725_BUCK2_VOUT2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = lp872x_read_byte(lp, addr, &val);
+	if (ret)
+		return ret;
+
+	val = (val & LP8725_BUCK_CL_M) >> LP8725_BUCK_CL_S;
+
+	return (val < ARRAY_SIZE(lp8725_buck_uA)) ?
+			lp8725_buck_uA[val] : -EINVAL;
+}
+
+static int lp872x_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct lp872x *lp = rdev_get_drvdata(rdev);
+	enum lp872x_regulator_id buck = rdev_get_id(rdev);
+	u8 addr, mask, shift, val;
+
+	switch (buck) {
+	case LP8720_ID_BUCK:
+		addr = LP8720_BUCK_VOUT2;
+		mask = LP8720_BUCK_FPWM_M;
+		shift = LP8720_BUCK_FPWM_S;
+		break;
+	case LP8725_ID_BUCK1:
+		addr = LP8725_BUCK_CTRL;
+		mask = LP8725_BUCK1_FPWM_M;
+		shift = LP8725_BUCK1_FPWM_S;
+		break;
+	case LP8725_ID_BUCK2:
+		addr = LP8725_BUCK_CTRL;
+		mask = LP8725_BUCK2_FPWM_M;
+		shift = LP8725_BUCK2_FPWM_S;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode == REGULATOR_MODE_FAST)
+		val = LP872X_FORCE_PWM << shift;
+	else if (mode == REGULATOR_MODE_NORMAL)
+		val = LP872X_AUTO_PWM << shift;
+	else
+		return -EINVAL;
+
+	return lp872x_update_bits(lp, addr, mask, val);
+}
+
+static unsigned int lp872x_buck_get_mode(struct regulator_dev *rdev)
+{
+	struct lp872x *lp = rdev_get_drvdata(rdev);
+	enum lp872x_regulator_id buck = rdev_get_id(rdev);
+	u8 addr, mask, val;
+	int ret;
+
+	switch (buck) {
+	case LP8720_ID_BUCK:
+		addr = LP8720_BUCK_VOUT2;
+		mask = LP8720_BUCK_FPWM_M;
+		break;
+	case LP8725_ID_BUCK1:
+		addr = LP8725_BUCK_CTRL;
+		mask = LP8725_BUCK1_FPWM_M;
+		break;
+	case LP8725_ID_BUCK2:
+		addr = LP8725_BUCK_CTRL;
+		mask = LP8725_BUCK2_FPWM_M;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = lp872x_read_byte(lp, addr, &val);
+	if (ret)
+		return ret;
+
+	return val & mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops lp872x_ldo_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.enable_time = lp872x_regulator_enable_time,
+};
+
+static struct regulator_ops lp8720_buck_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.set_voltage_sel = lp872x_buck_set_voltage_sel,
+	.get_voltage_sel = lp872x_buck_get_voltage_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.enable_time = lp872x_regulator_enable_time,
+	.set_mode = lp872x_buck_set_mode,
+	.get_mode = lp872x_buck_get_mode,
+};
+
+static struct regulator_ops lp8725_buck_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.set_voltage_sel = lp872x_buck_set_voltage_sel,
+	.get_voltage_sel = lp872x_buck_get_voltage_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.enable_time = lp872x_regulator_enable_time,
+	.set_mode = lp872x_buck_set_mode,
+	.get_mode = lp872x_buck_get_mode,
+	.set_current_limit = lp8725_buck_set_current_limit,
+	.get_current_limit = lp8725_buck_get_current_limit,
+};
+
+static struct regulator_desc lp8720_regulator_desc[] = {
+	{
+		.name = "ldo1",
+		.id = LP8720_ID_LDO1,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+		.volt_table = lp872x_ldo_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP872X_LDO1_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8720_ENABLE,
+		.enable_mask = LP872X_EN_LDO1_M,
+	},
+	{
+		.name = "ldo2",
+		.id = LP8720_ID_LDO2,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+		.volt_table = lp872x_ldo_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP872X_LDO2_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8720_ENABLE,
+		.enable_mask = LP872X_EN_LDO2_M,
+	},
+	{
+		.name = "ldo3",
+		.id = LP8720_ID_LDO3,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+		.volt_table = lp872x_ldo_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP872X_LDO3_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8720_ENABLE,
+		.enable_mask = LP872X_EN_LDO3_M,
+	},
+	{
+		.name = "ldo4",
+		.id = LP8720_ID_LDO4,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp8720_ldo4_vtbl),
+		.volt_table = lp8720_ldo4_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP872X_LDO4_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8720_ENABLE,
+		.enable_mask = LP872X_EN_LDO4_M,
+	},
+	{
+		.name = "ldo5",
+		.id = LP8720_ID_LDO5,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+		.volt_table = lp872x_ldo_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP872X_LDO5_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8720_ENABLE,
+		.enable_mask = LP872X_EN_LDO5_M,
+	},
+	{
+		.name = "buck",
+		.id = LP8720_ID_BUCK,
+		.ops = &lp8720_buck_ops,
+		.n_voltages = ARRAY_SIZE(lp8720_buck_vtbl),
+		.volt_table = lp8720_buck_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.enable_reg = LP8720_ENABLE,
+		.enable_mask = LP8720_EN_BUCK_M,
+	},
+};
+
+static struct regulator_desc lp8725_regulator_desc[] = {
+	{
+		.name = "ldo1",
+		.id = LP8725_ID_LDO1,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+		.volt_table = lp872x_ldo_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP872X_LDO1_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8725_LDO_CTRL,
+		.enable_mask = LP872X_EN_LDO1_M,
+	},
+	{
+		.name = "ldo2",
+		.id = LP8725_ID_LDO2,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+		.volt_table = lp872x_ldo_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP872X_LDO2_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8725_LDO_CTRL,
+		.enable_mask = LP872X_EN_LDO2_M,
+	},
+	{
+		.name = "ldo3",
+		.id = LP8725_ID_LDO3,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+		.volt_table = lp872x_ldo_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP872X_LDO3_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8725_LDO_CTRL,
+		.enable_mask = LP872X_EN_LDO3_M,
+	},
+	{
+		.name = "ldo4",
+		.id = LP8725_ID_LDO4,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+		.volt_table = lp872x_ldo_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP872X_LDO4_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8725_LDO_CTRL,
+		.enable_mask = LP872X_EN_LDO4_M,
+	},
+	{
+		.name = "ldo5",
+		.id = LP8725_ID_LDO5,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+		.volt_table = lp872x_ldo_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP872X_LDO5_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8725_LDO_CTRL,
+		.enable_mask = LP872X_EN_LDO5_M,
+	},
+	{
+		.name = "lilo1",
+		.id = LP8725_ID_LILO1,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl),
+		.volt_table = lp8725_lilo_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP8725_LILO1_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8725_LDO_CTRL,
+		.enable_mask = LP8725_EN_LILO1_M,
+	},
+	{
+		.name = "lilo2",
+		.id = LP8725_ID_LILO2,
+		.ops = &lp872x_ldo_ops,
+		.n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl),
+		.volt_table = lp8725_lilo_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.vsel_reg = LP8725_LILO2_VOUT,
+		.vsel_mask = LP872X_VOUT_M,
+		.enable_reg = LP8725_LDO_CTRL,
+		.enable_mask = LP8725_EN_LILO2_M,
+	},
+	{
+		.name = "buck1",
+		.id = LP8725_ID_BUCK1,
+		.ops = &lp8725_buck_ops,
+		.n_voltages = ARRAY_SIZE(lp8725_buck_vtbl),
+		.volt_table = lp8725_buck_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.enable_reg = LP872X_GENERAL_CFG,
+		.enable_mask = LP8725_BUCK1_EN_M,
+	},
+	{
+		.name = "buck2",
+		.id = LP8725_ID_BUCK2,
+		.ops = &lp8725_buck_ops,
+		.n_voltages = ARRAY_SIZE(lp8725_buck_vtbl),
+		.volt_table = lp8725_buck_vtbl,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		.enable_reg = LP872X_GENERAL_CFG,
+		.enable_mask = LP8725_BUCK2_EN_M,
+	},
+};
+
+static int lp872x_check_dvs_validity(struct lp872x *lp)
+{
+	struct lp872x_dvs *dvs = lp->pdata->dvs;
+	u8 val = 0;
+	int ret;
+
+	ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val);
+	if (ret)
+		return ret;
+
+	ret = 0;
+	if (lp->chipid == LP8720) {
+		if (val & LP8720_EXT_DVS_M)
+			ret = dvs ? 0 : -EINVAL;
+	} else {
+		if ((val & LP8725_DVS1_M) == EXTERN_DVS_USED)
+			ret = dvs ? 0 : -EINVAL;
+	}
+
+	return ret;
+}
+
+static int lp872x_init_dvs(struct lp872x *lp)
+{
+	int ret, gpio;
+	struct lp872x_dvs *dvs = lp->pdata->dvs;
+	enum lp872x_dvs_state pinstate;
+
+	ret = lp872x_check_dvs_validity(lp);
+	if (ret) {
+		dev_warn(lp->dev, "invalid dvs data: %d\n", ret);
+		return ret;
+	}
+
+	gpio = dvs->gpio;
+	if (!gpio_is_valid(gpio)) {
+		dev_err(lp->dev, "invalid gpio: %d\n", gpio);
+		return -EINVAL;
+	}
+
+	pinstate = dvs->init_state;
+	ret = devm_gpio_request_one(lp->dev, gpio, pinstate, "LP872X DVS");
+	if (ret) {
+		dev_err(lp->dev, "gpio request err: %d\n", ret);
+		return ret;
+	}
+
+	lp->dvs_pin = pinstate;
+	lp->dvs_gpio = gpio;
+
+	return 0;
+}
+
+static int lp872x_config(struct lp872x *lp)
+{
+	struct lp872x_platform_data *pdata = lp->pdata;
+	int ret;
+
+	if (!pdata->update_config)
+		return 0;
+
+	ret = lp872x_write_byte(lp, LP872X_GENERAL_CFG, pdata->general_config);
+	if (ret)
+		return ret;
+
+	return lp872x_init_dvs(lp);
+}
+
+static struct regulator_init_data
+*lp872x_find_regulator_init_data(int idx, struct lp872x *lp)
+{
+	int i, base, id, max_regulators;
+
+	switch (lp->chipid) {
+	case LP8720:
+		base = LP8720_ID_BASE;
+		max_regulators = LP8720_NUM_REGULATORS;
+		break;
+	case LP8725:
+		base = LP8725_ID_BASE;
+		max_regulators = LP8725_NUM_REGULATORS;
+		break;
+	default:
+		return NULL;
+	}
+
+	id = base + idx;
+	for (i = 0 ; i < max_regulators ; i++)
+		if (lp->pdata->regulator_data[i].id == id)
+			break;
+
+	return (i == max_regulators) ? NULL :
+			lp->pdata->regulator_data[i].init_data;
+}
+
+static int lp872x_regulator_register(struct lp872x *lp)
+{
+	struct regulator_desc *desc;
+	struct regulator_config cfg = { };
+	struct regulator_dev *rdev;
+	int i, ret;
+
+	for (i = 0 ; i < lp->num_regulators ; i++) {
+		desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] :
+						&lp8725_regulator_desc[i];
+
+		cfg.dev = lp->dev;
+		cfg.init_data = lp872x_find_regulator_init_data(i, lp);
+		cfg.driver_data = lp;
+		cfg.regmap = lp->regmap;
+
+		rdev = regulator_register(desc, &cfg);
+		if (IS_ERR(rdev)) {
+			dev_err(lp->dev, "regulator register err");
+			ret =  PTR_ERR(rdev);
+			goto err;
+		}
+
+		*(lp->regulators + i) = rdev;
+	}
+
+	return 0;
+err:
+	while (--i >= 0) {
+		rdev = *(lp->regulators + i);
+		regulator_unregister(rdev);
+	}
+	return ret;
+}
+
+static void lp872x_regulator_unregister(struct lp872x *lp)
+{
+	struct regulator_dev *rdev;
+	int i;
+
+	for (i = 0 ; i < lp->num_regulators ; i++) {
+		rdev = *(lp->regulators + i);
+		regulator_unregister(rdev);
+	}
+}
+
+static const struct regmap_config lp872x_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = MAX_REGISTERS,
+};
+
+static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
+{
+	struct lp872x *lp;
+	struct lp872x_platform_data *pdata = cl->dev.platform_data;
+	int ret, size, num_regulators;
+	const int lp872x_num_regulators[] = {
+		[LP8720] = LP8720_NUM_REGULATORS,
+		[LP8725] = LP8725_NUM_REGULATORS,
+	};
+
+	if (!pdata) {
+		dev_err(&cl->dev, "no platform data\n");
+		return -EINVAL;
+	}
+
+	lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL);
+	if (!lp)
+		goto err_mem;
+
+	num_regulators = lp872x_num_regulators[id->driver_data];
+	size = sizeof(struct regulator_dev *) * num_regulators;
+
+	lp->regulators = devm_kzalloc(&cl->dev, size, GFP_KERNEL);
+	if (!lp->regulators)
+		goto err_mem;
+
+	lp->regmap = devm_regmap_init_i2c(cl, &lp872x_regmap_config);
+	if (IS_ERR(lp->regmap)) {
+		ret = PTR_ERR(lp->regmap);
+		dev_err(&cl->dev, "regmap init i2c err: %d\n", ret);
+		goto err_dev;
+	}
+
+	lp->dev = &cl->dev;
+	lp->pdata = pdata;
+	lp->chipid = id->driver_data;
+	lp->num_regulators = num_regulators;
+	i2c_set_clientdata(cl, lp);
+
+	ret = lp872x_config(lp);
+	if (ret)
+		goto err_dev;
+
+	return lp872x_regulator_register(lp);
+
+err_mem:
+	return -ENOMEM;
+err_dev:
+	return ret;
+}
+
+static int __devexit lp872x_remove(struct i2c_client *cl)
+{
+	struct lp872x *lp = i2c_get_clientdata(cl);
+
+	lp872x_regulator_unregister(lp);
+	return 0;
+}
+
+static const struct i2c_device_id lp872x_ids[] = {
+	{"lp8720", LP8720},
+	{"lp8725", LP8725},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lp872x_ids);
+
+static struct i2c_driver lp872x_driver = {
+	.driver = {
+		.name = "lp872x",
+		.owner = THIS_MODULE,
+	},
+	.probe = lp872x_probe,
+	.remove = __devexit_p(lp872x_remove),
+	.id_table = lp872x_ids,
+};
+
+module_i2c_driver(lp872x_driver);
+
+MODULE_DESCRIPTION("TI/National Semiconductor LP872x PMU Regulator Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index b9444ee..f67af3c 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -48,6 +48,14 @@ struct max1586_data {
 };
 
 /*
+ * V6 voltage
+ * On I2C bus, sending a "x" byte to the max1586 means :
+ *   set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3)
+ * As regulator framework doesn't accept voltages to be 0V, we use 1uV.
+ */
+static int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 };
+
+/*
  * V3 voltage
  * On I2C bus, sending a "x" byte to the max1586 means :
  *   set V3 to 0.700V + (x & 0x1f) * 0.025V
@@ -55,113 +63,49 @@ struct max1586_data {
  * R24 and R25=100kOhm as described in the data sheet.
  * The gain is approximately: 1 + R24/R25 + R24/185.5kOhm
  */
-static int max1586_v3_calc_voltage(struct max1586_data *max1586,
-	unsigned selector)
-{
-	unsigned range_uV = max1586->max_uV - max1586->min_uV;
-
-	return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL);
-}
-
-static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV,
-			  unsigned *selector)
+static int max1586_v3_set_voltage_sel(struct regulator_dev *rdev,
+				      unsigned selector)
 {
 	struct max1586_data *max1586 = rdev_get_drvdata(rdev);
 	struct i2c_client *client = max1586->client;
-	unsigned range_uV = max1586->max_uV - max1586->min_uV;
 	u8 v3_prog;
 
-	if (min_uV > max1586->max_uV || max_uV < max1586->min_uV)
-		return -EINVAL;
-	if (min_uV < max1586->min_uV)
-		min_uV = max1586->min_uV;
-
-	*selector = DIV_ROUND_UP((min_uV - max1586->min_uV) *
-				 MAX1586_V3_MAX_VSEL, range_uV);
-	if (max1586_v3_calc_voltage(max1586, *selector) > max_uV)
-		return -EINVAL;
-
 	dev_dbg(&client->dev, "changing voltage v3 to %dmv\n",
-		max1586_v3_calc_voltage(max1586, *selector) / 1000);
+		regulator_list_voltage_linear(rdev, selector) / 1000);
 
-	v3_prog = I2C_V3_SELECT | (u8) *selector;
+	v3_prog = I2C_V3_SELECT | (u8) selector;
 	return i2c_smbus_write_byte(client, v3_prog);
 }
 
-static int max1586_v3_list(struct regulator_dev *rdev, unsigned selector)
-{
-	struct max1586_data *max1586 = rdev_get_drvdata(rdev);
-
-	if (selector > MAX1586_V3_MAX_VSEL)
-		return -EINVAL;
-	return max1586_v3_calc_voltage(max1586, selector);
-}
-
-/*
- * V6 voltage
- * On I2C bus, sending a "x" byte to the max1586 means :
- *   set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3)
- * As regulator framework doesn't accept voltages to be 0V, we use 1uV.
- */
-static int max1586_v6_calc_voltage(unsigned selector)
-{
-	static int voltages_uv[] = { 1, 1800000, 2500000, 3000000 };
-
-	return voltages_uv[selector];
-}
-
-static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV,
-			  unsigned int *selector)
+static int max1586_v6_set_voltage_sel(struct regulator_dev *rdev,
+				      unsigned int selector)
 {
 	struct i2c_client *client = rdev_get_drvdata(rdev);
 	u8 v6_prog;
 
-	if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV)
-		return -EINVAL;
-	if (max_uV < MAX1586_V6_MIN_UV || max_uV > MAX1586_V6_MAX_UV)
-		return -EINVAL;
-
-	if (min_uV < 1800000)
-		*selector = 0;
-	else if (min_uV < 2500000)
-		*selector = 1;
-	else if (min_uV < 3000000)
-		*selector = 2;
-	else if (min_uV >= 3000000)
-		*selector = 3;
-
-	if (max1586_v6_calc_voltage(*selector) > max_uV)
-		return -EINVAL;
-
 	dev_dbg(&client->dev, "changing voltage v6 to %dmv\n",
-		max1586_v6_calc_voltage(*selector) / 1000);
+		rdev->desc->volt_table[selector] / 1000);
 
-	v6_prog = I2C_V6_SELECT | (u8) *selector;
+	v6_prog = I2C_V6_SELECT | (u8) selector;
 	return i2c_smbus_write_byte(client, v6_prog);
 }
 
-static int max1586_v6_list(struct regulator_dev *rdev, unsigned selector)
-{
-	if (selector > MAX1586_V6_MAX_VSEL)
-		return -EINVAL;
-	return max1586_v6_calc_voltage(selector);
-}
-
 /*
  * The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back
  * the set up value.
  */
 static struct regulator_ops max1586_v3_ops = {
-	.set_voltage = max1586_v3_set,
-	.list_voltage = max1586_v3_list,
+	.set_voltage_sel = max1586_v3_set_voltage_sel,
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
 };
 
 static struct regulator_ops max1586_v6_ops = {
-	.set_voltage = max1586_v6_set,
-	.list_voltage = max1586_v6_list,
+	.set_voltage_sel = max1586_v6_set_voltage_sel,
+	.list_voltage = regulator_list_voltage_table,
 };
 
-static const struct regulator_desc max1586_reg[] = {
+static struct regulator_desc max1586_reg[] = {
 	{
 		.name = "Output_V3",
 		.id = MAX1586_V3,
@@ -176,6 +120,7 @@ static const struct regulator_desc max1586_reg[] = {
 		.ops = &max1586_v6_ops,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = MAX1586_V6_MAX_VSEL + 1,
+		.volt_table = v6_voltages_uv,
 		.owner = THIS_MODULE,
 	},
 };
@@ -213,6 +158,13 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client,
 			goto err;
 		}
 
+		if (id == MAX1586_V3) {
+			max1586_reg[id].min_uV = max1586->min_uV;
+			max1586_reg[id].uV_step =
+					(max1586->max_uV - max1586->min_uV) /
+					MAX1586_V3_MAX_VSEL;
+		}
+
 		config.dev = &client->dev;
 		config.init_data = pdata->subdevs[i].platform_data;
 		config.driver_data = max1586;
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c
new file mode 100644
index 0000000..23f956a
--- /dev/null
+++ b/drivers/regulator/max77686.c
@@ -0,0 +1,332 @@
+/*
+ * max77686.c - Regulator driver for the Maxim 77686
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Chiwoong Byun <woong.byun@smasung.com>
+ * Jonghwa Lee <jonghwa3.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8997.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/max77686.h>
+#include <linux/mfd/max77686-private.h>
+
+#define MAX77686_LDO_MINUV	800000
+#define MAX77686_LDO_UVSTEP	50000
+#define MAX77686_LDO_LOW_MINUV	800000
+#define MAX77686_LDO_LOW_UVSTEP	25000
+#define MAX77686_BUCK_MINUV	750000
+#define MAX77686_BUCK_UVSTEP	50000
+#define MAX77686_RAMP_DELAY	100000			/* uV/us */
+#define MAX77686_DVS_RAMP_DELAY	27500			/* uV/us */
+#define MAX77686_DVS_MINUV	600000
+#define MAX77686_DVS_UVSTEP	12500
+
+#define MAX77686_OPMODE_SHIFT	6
+#define MAX77686_OPMODE_BUCK234_SHIFT	4
+#define MAX77686_OPMODE_MASK	0x3
+
+#define MAX77686_VSEL_MASK	0x3F
+#define MAX77686_DVS_VSEL_MASK	0xFF
+
+#define MAX77686_RAMP_RATE_MASK	0xC0
+
+#define MAX77686_REGULATORS	MAX77686_REG_MAX
+#define MAX77686_LDOS		26
+
+enum max77686_ramp_rate {
+	RAMP_RATE_13P75MV,
+	RAMP_RATE_27P5MV,
+	RAMP_RATE_55MV,
+	RAMP_RATE_NO_CTRL,	/* 100mV/us */
+};
+
+struct max77686_data {
+	struct regulator_dev **rdev;
+};
+
+static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+	unsigned int ramp_value = RAMP_RATE_NO_CTRL;
+
+	switch (ramp_delay) {
+	case 1 ... 13750:
+		ramp_value = RAMP_RATE_13P75MV;
+		break;
+	case 13751 ... 27500:
+		ramp_value = RAMP_RATE_27P5MV;
+		break;
+	case 27501 ... 55000:
+		ramp_value = RAMP_RATE_55MV;
+		break;
+	case 55001 ... 100000:
+		break;
+	default:
+		pr_warn("%s: ramp_delay: %d not supported, setting 100000\n",
+			rdev->desc->name, ramp_delay);
+	}
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  MAX77686_RAMP_RATE_MASK, ramp_value << 6);
+}
+
+static struct regulator_ops max77686_ops = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= regulator_enable_regmap,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops max77686_buck_dvs_ops = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= regulator_enable_regmap,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+	.set_ramp_delay		= max77686_set_ramp_delay,
+};
+
+#define regulator_desc_ldo(num)		{				\
+	.name		= "LDO"#num,					\
+	.id		= MAX77686_LDO##num,				\
+	.ops		= &max77686_ops,				\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= MAX77686_LDO_MINUV,				\
+	.uV_step	= MAX77686_LDO_UVSTEP,				\
+	.ramp_delay	= MAX77686_RAMP_DELAY,				\
+	.n_voltages	= MAX77686_VSEL_MASK + 1,			\
+	.vsel_reg	= MAX77686_REG_LDO1CTRL1 + num - 1,		\
+	.vsel_mask	= MAX77686_VSEL_MASK,				\
+	.enable_reg	= MAX77686_REG_LDO1CTRL1 + num - 1,		\
+	.enable_mask	= MAX77686_OPMODE_MASK				\
+			<< MAX77686_OPMODE_SHIFT,			\
+}
+#define regulator_desc_ldo_low(num)		{			\
+	.name		= "LDO"#num,					\
+	.id		= MAX77686_LDO##num,				\
+	.ops		= &max77686_ops,				\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= MAX77686_LDO_LOW_MINUV,			\
+	.uV_step	= MAX77686_LDO_LOW_UVSTEP,			\
+	.ramp_delay	= MAX77686_RAMP_DELAY,				\
+	.n_voltages	= MAX77686_VSEL_MASK + 1,			\
+	.vsel_reg	= MAX77686_REG_LDO1CTRL1 + num - 1,		\
+	.vsel_mask	= MAX77686_VSEL_MASK,				\
+	.enable_reg	= MAX77686_REG_LDO1CTRL1 + num - 1,		\
+	.enable_mask	= MAX77686_OPMODE_MASK				\
+			<< MAX77686_OPMODE_SHIFT,			\
+}
+#define regulator_desc_buck(num)		{			\
+	.name		= "BUCK"#num,					\
+	.id		= MAX77686_BUCK##num,				\
+	.ops		= &max77686_ops,				\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= MAX77686_BUCK_MINUV,				\
+	.uV_step	= MAX77686_BUCK_UVSTEP,				\
+	.ramp_delay	= MAX77686_RAMP_DELAY,				\
+	.n_voltages	= MAX77686_VSEL_MASK + 1,			\
+	.vsel_reg	= MAX77686_REG_BUCK5OUT + (num - 5) * 2,	\
+	.vsel_mask	= MAX77686_VSEL_MASK,				\
+	.enable_reg	= MAX77686_REG_BUCK5CTRL + (num - 5) * 2,	\
+	.enable_mask	= MAX77686_OPMODE_MASK,				\
+}
+#define regulator_desc_buck1(num)		{			\
+	.name		= "BUCK"#num,					\
+	.id		= MAX77686_BUCK##num,				\
+	.ops		= &max77686_ops,				\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= MAX77686_BUCK_MINUV,				\
+	.uV_step	= MAX77686_BUCK_UVSTEP,				\
+	.ramp_delay	= MAX77686_RAMP_DELAY,				\
+	.n_voltages	= MAX77686_VSEL_MASK + 1,			\
+	.vsel_reg	= MAX77686_REG_BUCK1OUT,			\
+	.vsel_mask	= MAX77686_VSEL_MASK,				\
+	.enable_reg	= MAX77686_REG_BUCK1CTRL,			\
+	.enable_mask	= MAX77686_OPMODE_MASK,				\
+}
+#define regulator_desc_buck_dvs(num)		{			\
+	.name		= "BUCK"#num,					\
+	.id		= MAX77686_BUCK##num,				\
+	.ops		= &max77686_buck_dvs_ops,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= MAX77686_DVS_MINUV,				\
+	.uV_step	= MAX77686_DVS_UVSTEP,				\
+	.ramp_delay	= MAX77686_DVS_RAMP_DELAY,			\
+	.n_voltages	= MAX77686_DVS_VSEL_MASK + 1,			\
+	.vsel_reg	= MAX77686_REG_BUCK2DVS1 + (num - 2) * 10,	\
+	.vsel_mask	= MAX77686_DVS_VSEL_MASK,			\
+	.enable_reg	= MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10,	\
+	.enable_mask	= MAX77686_OPMODE_MASK				\
+			<< MAX77686_OPMODE_BUCK234_SHIFT,		\
+}
+
+static struct regulator_desc regulators[] = {
+	regulator_desc_ldo_low(1),
+	regulator_desc_ldo_low(2),
+	regulator_desc_ldo(3),
+	regulator_desc_ldo(4),
+	regulator_desc_ldo(5),
+	regulator_desc_ldo_low(6),
+	regulator_desc_ldo_low(7),
+	regulator_desc_ldo_low(8),
+	regulator_desc_ldo(9),
+	regulator_desc_ldo(10),
+	regulator_desc_ldo(11),
+	regulator_desc_ldo(12),
+	regulator_desc_ldo(13),
+	regulator_desc_ldo(14),
+	regulator_desc_ldo_low(15),
+	regulator_desc_ldo(16),
+	regulator_desc_ldo(17),
+	regulator_desc_ldo(18),
+	regulator_desc_ldo(19),
+	regulator_desc_ldo(20),
+	regulator_desc_ldo(21),
+	regulator_desc_ldo(22),
+	regulator_desc_ldo(23),
+	regulator_desc_ldo(24),
+	regulator_desc_ldo(25),
+	regulator_desc_ldo(26),
+	regulator_desc_buck1(1),
+	regulator_desc_buck_dvs(2),
+	regulator_desc_buck_dvs(3),
+	regulator_desc_buck_dvs(4),
+	regulator_desc_buck(5),
+	regulator_desc_buck(6),
+	regulator_desc_buck(7),
+	regulator_desc_buck(8),
+	regulator_desc_buck(9),
+};
+
+static __devinit int max77686_pmic_probe(struct platform_device *pdev)
+{
+	struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct regulator_dev **rdev;
+	struct max77686_data *max77686;
+	int i,  size;
+	int ret = 0;
+	struct regulator_config config = { };
+
+	dev_dbg(&pdev->dev, "%s\n", __func__);
+
+	if (!pdata || pdata->num_regulators != MAX77686_REGULATORS) {
+		dev_err(&pdev->dev,
+			"Invalid initial data for regulator's initialiation\n");
+		return -EINVAL;
+	}
+
+	max77686 = devm_kzalloc(&pdev->dev, sizeof(struct max77686_data),
+				GFP_KERNEL);
+	if (!max77686)
+		return -ENOMEM;
+
+	size = sizeof(struct regulator_dev *) * MAX77686_REGULATORS;
+	max77686->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+	if (!max77686->rdev)
+		return -ENOMEM;
+
+	rdev = max77686->rdev;
+	config.dev = &pdev->dev;
+	config.regmap = iodev->regmap;
+	platform_set_drvdata(pdev, max77686);
+
+	for (i = 0; i < MAX77686_REGULATORS; i++) {
+		config.init_data = pdata->regulators[i].initdata;
+
+		rdev[i] = regulator_register(&regulators[i], &config);
+		if (IS_ERR(rdev[i])) {
+			ret = PTR_ERR(rdev[i]);
+			dev_err(&pdev->dev,
+				"regulator init failed for %d\n", i);
+				rdev[i] = NULL;
+				goto err;
+		}
+	}
+
+	return 0;
+err:
+	while (--i >= 0)
+		regulator_unregister(rdev[i]);
+	return ret;
+}
+
+static int __devexit max77686_pmic_remove(struct platform_device *pdev)
+{
+	struct max77686_data *max77686 = platform_get_drvdata(pdev);
+	struct regulator_dev **rdev = max77686->rdev;
+	int i;
+
+	for (i = 0; i < MAX77686_REGULATORS; i++)
+		if (rdev[i])
+			regulator_unregister(rdev[i]);
+
+	return 0;
+}
+
+static const struct platform_device_id max77686_pmic_id[] = {
+	{"max77686-pmic", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, max77686_pmic_id);
+
+static struct platform_driver max77686_pmic_driver = {
+	.driver = {
+		.name = "max77686-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = max77686_pmic_probe,
+	.remove = __devexit_p(max77686_pmic_remove),
+	.id_table = max77686_pmic_id,
+};
+
+static int __init max77686_pmic_init(void)
+{
+	return platform_driver_register(&max77686_pmic_driver);
+}
+subsys_initcall(max77686_pmic_init);
+
+static void __exit max77686_pmic_cleanup(void)
+{
+	platform_driver_unregister(&max77686_pmic_driver);
+}
+module_exit(max77686_pmic_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 77686 Regulator Driver");
+MODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index 18bb58b..a1fa266 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -111,27 +111,6 @@ static const struct voltage_map_desc *ldo_voltage_map[] = {
 	&buck4_voltage_map_desc,	/* BUCK4 */
 };
 
-static int max8998_list_voltage(struct regulator_dev *rdev,
-				unsigned int selector)
-{
-	const struct voltage_map_desc *desc;
-	int ldo = rdev_get_id(rdev);
-	int val;
-
-	if (ldo >= ARRAY_SIZE(ldo_voltage_map))
-		return -EINVAL;
-
-	desc = ldo_voltage_map[ldo];
-	if (desc == NULL)
-		return -EINVAL;
-
-	val = desc->min + desc->step * selector;
-	if (val > desc->max)
-		return -EINVAL;
-
-	return val * 1000;
-}
-
 static int max8998_get_enable_register(struct regulator_dev *rdev,
 					int *reg, int *shift)
 {
@@ -297,41 +276,18 @@ static int max8998_get_voltage_sel(struct regulator_dev *rdev)
 	return val;
 }
 
-static int max8998_set_voltage_ldo(struct regulator_dev *rdev,
-				   int min_uV, int max_uV, unsigned *selector)
+static int max8998_set_voltage_ldo_sel(struct regulator_dev *rdev,
+				       unsigned selector)
 {
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
 	struct i2c_client *i2c = max8998->iodev->i2c;
-	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
-	const struct voltage_map_desc *desc;
-	int ldo = rdev_get_id(rdev);
-	int reg, shift = 0, mask, ret, i;
-
-	if (ldo >= ARRAY_SIZE(ldo_voltage_map))
-		return -EINVAL;
-
-	desc = ldo_voltage_map[ldo];
-	if (desc == NULL)
-		return -EINVAL;
-
-	if (max_vol < desc->min || min_vol > desc->max)
-		return -EINVAL;
-
-	if (min_vol < desc->min)
-		min_vol = desc->min;
-
-	i = DIV_ROUND_UP(min_vol - desc->min, desc->step);
-
-	if (desc->min + desc->step*i > max_vol)
-		return -EINVAL;
-
-	*selector = i;
+	int reg, shift = 0, mask, ret;
 
 	ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
 	if (ret)
 		return ret;
 
-	ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift);
+	ret = max8998_update_reg(i2c, reg, selector<<shift, mask<<shift);
 
 	return ret;
 }
@@ -347,41 +303,18 @@ static inline void buck2_gpio_set(int gpio, int v)
 	gpio_set_value(gpio, v & 0x1);
 }
 
-static int max8998_set_voltage_buck(struct regulator_dev *rdev,
-				    int min_uV, int max_uV, unsigned *selector)
+static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev,
+					unsigned selector)
 {
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
 	struct max8998_platform_data *pdata =
 		dev_get_platdata(max8998->iodev->dev);
 	struct i2c_client *i2c = max8998->iodev->i2c;
-	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
-	const struct voltage_map_desc *desc;
 	int buck = rdev_get_id(rdev);
 	int reg, shift = 0, mask, ret;
-	int i, j, previous_sel;
+	int j, previous_sel;
 	static u8 buck1_last_val;
 
-	if (buck >= ARRAY_SIZE(ldo_voltage_map))
-		return -EINVAL;
-
-	desc = ldo_voltage_map[buck];
-
-	if (desc == NULL)
-		return -EINVAL;
-
-	if (max_vol < desc->min || min_vol > desc->max)
-		return -EINVAL;
-
-	if (min_vol < desc->min)
-		min_vol = desc->min;
-
-	i = DIV_ROUND_UP(min_vol - desc->min, desc->step);
-
-	if (desc->min + desc->step*i > max_vol)
-		return -EINVAL;
-
-	*selector = i;
-
 	ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
 	if (ret)
 		return ret;
@@ -390,19 +323,19 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
 
 	/* Check if voltage needs to be changed */
 	/* if previous_voltage equal new voltage, return */
-	if (previous_sel == i) {
+	if (previous_sel == selector) {
 		dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n",
-			max8998_list_voltage(rdev, previous_sel),
-			max8998_list_voltage(rdev, i));
+			regulator_list_voltage_linear(rdev, previous_sel),
+			regulator_list_voltage_linear(rdev, selector));
 		return ret;
 	}
 
 	switch (buck) {
 	case MAX8998_BUCK1:
 		dev_dbg(max8998->dev,
-			"BUCK1, i:%d, buck1_vol1:%d, buck1_vol2:%d\n"
+			"BUCK1, selector:%d, buck1_vol1:%d, buck1_vol2:%d\n"
 			"buck1_vol3:%d, buck1_vol4:%d\n",
-			i, max8998->buck1_vol[0], max8998->buck1_vol[1],
+			selector, max8998->buck1_vol[0], max8998->buck1_vol[1],
 			max8998->buck1_vol[2], max8998->buck1_vol[3]);
 
 		if (gpio_is_valid(pdata->buck1_set1) &&
@@ -411,7 +344,7 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
 			/* check if requested voltage */
 			/* value is already defined */
 			for (j = 0; j < ARRAY_SIZE(max8998->buck1_vol); j++) {
-				if (max8998->buck1_vol[j] == i) {
+				if (max8998->buck1_vol[j] == selector) {
 					max8998->buck1_idx = j;
 					buck1_gpio_set(pdata->buck1_set1,
 						       pdata->buck1_set2, j);
@@ -426,11 +359,11 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
 			max8998->buck1_idx = (buck1_last_val % 2) + 2;
 			dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n",
 				max8998->buck1_idx);
-			max8998->buck1_vol[max8998->buck1_idx] = i;
+			max8998->buck1_vol[max8998->buck1_idx] = selector;
 			ret = max8998_get_voltage_register(rdev, &reg,
 							   &shift,
 							   &mask);
-			ret = max8998_write_reg(i2c, reg, i);
+			ret = max8998_write_reg(i2c, reg, selector);
 			buck1_gpio_set(pdata->buck1_set1,
 				       pdata->buck1_set2, max8998->buck1_idx);
 			buck1_last_val++;
@@ -440,20 +373,20 @@ buck1_exit:
 				gpio_get_value(pdata->buck1_set2));
 			break;
 		} else {
-			ret = max8998_write_reg(i2c, reg, i);
+			ret = max8998_write_reg(i2c, reg, selector);
 		}
 		break;
 
 	case MAX8998_BUCK2:
 		dev_dbg(max8998->dev,
-			"BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n"
-			, i, max8998->buck2_vol[0], max8998->buck2_vol[1]);
+			"BUCK2, selector:%d buck2_vol1:%d, buck2_vol2:%d\n",
+			selector, max8998->buck2_vol[0], max8998->buck2_vol[1]);
 		if (gpio_is_valid(pdata->buck2_set3)) {
 
 			/* check if requested voltage */
 			/* value is already defined */
 			for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) {
-				if (max8998->buck2_vol[j] == i) {
+				if (max8998->buck2_vol[j] == selector) {
 					max8998->buck2_idx = j;
 					buck2_gpio_set(pdata->buck2_set3, j);
 					goto buck2_exit;
@@ -465,20 +398,21 @@ buck1_exit:
 
 			max8998_get_voltage_register(rdev,
 					&reg, &shift, &mask);
-			ret = max8998_write_reg(i2c, reg, i);
-			max8998->buck2_vol[max8998->buck2_idx] = i;
+			ret = max8998_write_reg(i2c, reg, selector);
+			max8998->buck2_vol[max8998->buck2_idx] = selector;
 			buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx);
 buck2_exit:
 			dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name,
 				gpio_get_value(pdata->buck2_set3));
 		} else {
-			ret = max8998_write_reg(i2c, reg, i);
+			ret = max8998_write_reg(i2c, reg, selector);
 		}
 		break;
 
 	case MAX8998_BUCK3:
 	case MAX8998_BUCK4:
-		ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift);
+		ret = max8998_update_reg(i2c, reg, selector<<shift,
+					 mask<<shift);
 		break;
 	}
 
@@ -519,23 +453,25 @@ static int max8998_set_voltage_buck_time_sel(struct regulator_dev *rdev,
 }
 
 static struct regulator_ops max8998_ldo_ops = {
-	.list_voltage		= max8998_list_voltage,
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
 	.is_enabled		= max8998_ldo_is_enabled,
 	.enable			= max8998_ldo_enable,
 	.disable		= max8998_ldo_disable,
 	.get_voltage_sel	= max8998_get_voltage_sel,
-	.set_voltage		= max8998_set_voltage_ldo,
+	.set_voltage_sel	= max8998_set_voltage_ldo_sel,
 	.set_suspend_enable	= max8998_ldo_enable,
 	.set_suspend_disable	= max8998_ldo_disable,
 };
 
 static struct regulator_ops max8998_buck_ops = {
-	.list_voltage		= max8998_list_voltage,
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
 	.is_enabled		= max8998_ldo_is_enabled,
 	.enable			= max8998_ldo_enable,
 	.disable		= max8998_ldo_disable,
 	.get_voltage_sel	= max8998_get_voltage_sel,
-	.set_voltage		= max8998_set_voltage_buck,
+	.set_voltage_sel	= max8998_set_voltage_buck_sel,
 	.set_voltage_time_sel	= max8998_set_voltage_buck_time_sel,
 	.set_suspend_enable	= max8998_ldo_enable,
 	.set_suspend_disable	= max8998_ldo_disable,
@@ -860,7 +796,10 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
 		desc = ldo_voltage_map[id];
 		if (desc && regulators[index].ops != &max8998_others_ops) {
 			int count = (desc->max - desc->min) / desc->step + 1;
+
 			regulators[index].n_voltages = count;
+			regulators[index].min_uV = desc->min * 1000;
+			regulators[index].uV_step = desc->step * 1000;
 		}
 
 		config.dev = max8998->dev;
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c
index 7dcdfa2..4932e34 100644
--- a/drivers/regulator/mc13783-regulator.c
+++ b/drivers/regulator/mc13783-regulator.c
@@ -93,78 +93,78 @@
 
 
 /* Voltage Values */
-static const int mc13783_sw3_val[] = {
+static const unsigned int mc13783_sw3_val[] = {
 	5000000, 5000000, 5000000, 5500000,
 };
 
-static const int mc13783_vaudio_val[] = {
+static const unsigned int mc13783_vaudio_val[] = {
 	2775000,
 };
 
-static const int mc13783_viohi_val[] = {
+static const unsigned int mc13783_viohi_val[] = {
 	2775000,
 };
 
-static const int mc13783_violo_val[] = {
+static const unsigned int mc13783_violo_val[] = {
 	1200000, 1300000, 1500000, 1800000,
 };
 
-static const int mc13783_vdig_val[] = {
+static const unsigned int mc13783_vdig_val[] = {
 	1200000, 1300000, 1500000, 1800000,
 };
 
-static const int mc13783_vgen_val[] = {
+static const unsigned int mc13783_vgen_val[] = {
 	1200000, 1300000, 1500000, 1800000,
 	1100000, 2000000, 2775000, 2400000,
 };
 
-static const int mc13783_vrfdig_val[] = {
+static const unsigned int mc13783_vrfdig_val[] = {
 	1200000, 1500000, 1800000, 1875000,
 };
 
-static const int mc13783_vrfref_val[] = {
+static const unsigned int mc13783_vrfref_val[] = {
 	2475000, 2600000, 2700000, 2775000,
 };
 
-static const int mc13783_vrfcp_val[] = {
+static const unsigned int mc13783_vrfcp_val[] = {
 	2700000, 2775000,
 };
 
-static const int mc13783_vsim_val[] = {
+static const unsigned int mc13783_vsim_val[] = {
 	1800000, 2900000, 3000000,
 };
 
-static const int mc13783_vesim_val[] = {
+static const unsigned int mc13783_vesim_val[] = {
 	1800000, 2900000,
 };
 
-static const int mc13783_vcam_val[] = {
+static const unsigned int mc13783_vcam_val[] = {
 	1500000, 1800000, 2500000, 2550000,
 	2600000, 2750000, 2800000, 3000000,
 };
 
-static const int mc13783_vrfbg_val[] = {
+static const unsigned int mc13783_vrfbg_val[] = {
 	1250000,
 };
 
-static const int mc13783_vvib_val[] = {
+static const unsigned int mc13783_vvib_val[] = {
 	1300000, 1800000, 2000000, 3000000,
 };
 
-static const int mc13783_vmmc_val[] = {
+static const unsigned int mc13783_vmmc_val[] = {
 	1600000, 1800000, 2000000, 2600000,
 	2700000, 2800000, 2900000, 3000000,
 };
 
-static const int mc13783_vrf_val[] = {
+static const unsigned int mc13783_vrf_val[] = {
 	1500000, 1875000, 2700000, 2775000,
 };
 
-static const int mc13783_gpo_val[] = {
+static const unsigned int mc13783_gpo_val[] = {
 	3100000,
 };
 
-static const int mc13783_pwgtdrv_val[] = {
+static const unsigned int mc13783_pwgtdrv_val[] = {
 	5500000,
 };
 
@@ -328,7 +328,7 @@ static struct regulator_ops mc13783_gpo_regulator_ops = {
 	.enable = mc13783_gpo_regulator_enable,
 	.disable = mc13783_gpo_regulator_disable,
 	.is_enabled = mc13783_gpo_regulator_is_enabled,
-	.list_voltage = mc13xxx_regulator_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 	.set_voltage = mc13xxx_fixed_regulator_set_voltage,
 	.get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index 970a233..b388b74 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -150,12 +150,12 @@
 #define MC13892_USB1				50
 #define MC13892_USB1_VUSBEN			(1<<3)
 
-static const int mc13892_vcoincell[] = {
+static const unsigned int mc13892_vcoincell[] = {
 	2500000, 2700000, 2800000, 2900000, 3000000, 3100000,
 	3200000, 3300000,
 };
 
-static const int mc13892_sw1[] = {
+static const unsigned int mc13892_sw1[] = {
 	600000,   625000,  650000,  675000,  700000,  725000,
 	750000,   775000,  800000,  825000,  850000,  875000,
 	900000,   925000,  950000,  975000, 1000000, 1025000,
@@ -164,7 +164,7 @@ static const int mc13892_sw1[] = {
 	1350000, 1375000
 };
 
-static const int mc13892_sw[] = {
+static const unsigned int mc13892_sw[] = {
 	600000,   625000,  650000,  675000,  700000,  725000,
 	750000,   775000,  800000,  825000,  850000,  875000,
 	900000,   925000,  950000,  975000, 1000000, 1025000,
@@ -176,65 +176,65 @@ static const int mc13892_sw[] = {
 	1800000, 1825000, 1850000, 1875000
 };
 
-static const int mc13892_swbst[] = {
+static const unsigned int mc13892_swbst[] = {
 	5000000,
 };
 
-static const int mc13892_viohi[] = {
+static const unsigned int mc13892_viohi[] = {
 	2775000,
 };
 
-static const int mc13892_vpll[] = {
+static const unsigned int mc13892_vpll[] = {
 	1050000, 1250000, 1650000, 1800000,
 };
 
-static const int mc13892_vdig[] = {
+static const unsigned int mc13892_vdig[] = {
 	1050000, 1250000, 1650000, 1800000,
 };
 
-static const int mc13892_vsd[] = {
+static const unsigned int mc13892_vsd[] = {
 	1800000, 2000000, 2600000, 2700000,
 	2800000, 2900000, 3000000, 3150000,
 };
 
-static const int mc13892_vusb2[] = {
+static const unsigned int mc13892_vusb2[] = {
 	2400000, 2600000, 2700000, 2775000,
 };
 
-static const int mc13892_vvideo[] = {
+static const unsigned int mc13892_vvideo[] = {
 	2700000, 2775000, 2500000, 2600000,
 };
 
-static const int mc13892_vaudio[] = {
+static const unsigned int mc13892_vaudio[] = {
 	2300000, 2500000, 2775000, 3000000,
 };
 
-static const int mc13892_vcam[] = {
+static const unsigned int mc13892_vcam[] = {
 	2500000, 2600000, 2750000, 3000000,
 };
 
-static const int mc13892_vgen1[] = {
+static const unsigned int mc13892_vgen1[] = {
 	1200000, 1500000, 2775000, 3150000,
 };
 
-static const int mc13892_vgen2[] = {
+static const unsigned int mc13892_vgen2[] = {
 	1200000, 1500000, 1600000, 1800000,
 	2700000, 2800000, 3000000, 3150000,
 };
 
-static const int mc13892_vgen3[] = {
+static const unsigned int mc13892_vgen3[] = {
 	1800000, 2900000,
 };
 
-static const int mc13892_vusb[] = {
+static const unsigned int mc13892_vusb[] = {
 	3300000,
 };
 
-static const int mc13892_gpo[] = {
+static const unsigned int mc13892_gpo[] = {
 	2750000,
 };
 
-static const int mc13892_pwgtdrv[] = {
+static const unsigned int mc13892_pwgtdrv[] = {
 	5000000,
 };
 
@@ -394,7 +394,7 @@ static struct regulator_ops mc13892_gpo_regulator_ops = {
 	.enable = mc13892_gpo_regulator_enable,
 	.disable = mc13892_gpo_regulator_disable,
 	.is_enabled = mc13892_gpo_regulator_is_enabled,
-	.list_voltage = mc13xxx_regulator_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 	.set_voltage = mc13xxx_fixed_regulator_set_voltage,
 	.get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
@@ -436,7 +436,7 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
 	u32 valread;
 	int ret;
 
-	value = mc13892_regulators[id].voltages[selector];
+	value = rdev->desc->volt_table[selector];
 
 	mc13xxx_lock(priv->mc13xxx);
 	ret = mc13xxx_reg_read(priv->mc13xxx,
@@ -469,8 +469,7 @@ err:
 }
 
 static struct regulator_ops mc13892_sw_regulator_ops = {
-	.is_enabled = mc13xxx_sw_regulator_is_enabled,
-	.list_voltage = mc13xxx_regulator_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 	.set_voltage_sel = mc13892_sw_regulator_set_voltage_sel,
 	.get_voltage = mc13892_sw_regulator_get_voltage,
 };
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index 4fa9704..d6eda28 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -80,20 +80,6 @@ static int mc13xxx_regulator_is_enabled(struct regulator_dev *rdev)
 	return (val & mc13xxx_regulators[id].enable_bit) != 0;
 }
 
-int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
-						unsigned selector)
-{
-	int id = rdev_get_id(rdev);
-	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
-	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
-
-	if (selector >= mc13xxx_regulators[id].desc.n_voltages)
-		return -EINVAL;
-
-	return mc13xxx_regulators[id].voltages[selector];
-}
-EXPORT_SYMBOL_GPL(mc13xxx_regulator_list_voltage);
-
 static int mc13xxx_regulator_set_voltage_sel(struct regulator_dev *rdev,
 					     unsigned selector)
 {
@@ -135,14 +121,14 @@ static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev)
 
 	BUG_ON(val >= mc13xxx_regulators[id].desc.n_voltages);
 
-	return mc13xxx_regulators[id].voltages[val];
+	return rdev->desc->volt_table[val];
 }
 
 struct regulator_ops mc13xxx_regulator_ops = {
 	.enable = mc13xxx_regulator_enable,
 	.disable = mc13xxx_regulator_disable,
 	.is_enabled = mc13xxx_regulator_is_enabled,
-	.list_voltage = mc13xxx_regulator_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 	.set_voltage_sel = mc13xxx_regulator_set_voltage_sel,
 	.get_voltage = mc13xxx_regulator_get_voltage,
 };
@@ -151,15 +137,13 @@ EXPORT_SYMBOL_GPL(mc13xxx_regulator_ops);
 int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
 	       int max_uV, unsigned *selector)
 {
-	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
-	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
 	int id = rdev_get_id(rdev);
 
 	dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
 		__func__, id, min_uV, max_uV);
 
-	if (min_uV >= mc13xxx_regulators[id].voltages[0] &&
-	    max_uV <= mc13xxx_regulators[id].voltages[0])
+	if (min_uV <= rdev->desc->volt_table[0] &&
+	    rdev->desc->volt_table[0] <= max_uV)
 		return 0;
 	else
 		return -EINVAL;
@@ -168,13 +152,11 @@ EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage);
 
 int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev)
 {
-	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
-	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
 	int id = rdev_get_id(rdev);
 
 	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
 
-	return mc13xxx_regulators[id].voltages[0];
+	return rdev->desc->volt_table[0];
 }
 EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage);
 
@@ -182,18 +164,12 @@ struct regulator_ops mc13xxx_fixed_regulator_ops = {
 	.enable = mc13xxx_regulator_enable,
 	.disable = mc13xxx_regulator_disable,
 	.is_enabled = mc13xxx_regulator_is_enabled,
-	.list_voltage = mc13xxx_regulator_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 	.set_voltage = mc13xxx_fixed_regulator_set_voltage,
 	.get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
 EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops);
 
-int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev)
-{
-	return 1;
-}
-EXPORT_SYMBOL_GPL(mc13xxx_sw_regulator_is_enabled);
-
 #ifdef CONFIG_OF
 int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
 {
diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h
index 044aba4..8343a25 100644
--- a/drivers/regulator/mc13xxx.h
+++ b/drivers/regulator/mc13xxx.h
@@ -22,7 +22,6 @@ struct mc13xxx_regulator {
 	int vsel_shift;
 	int vsel_mask;
 	int hi_bit;
-	int const *voltages;
 };
 
 struct mc13xxx_regulator_priv {
@@ -34,9 +33,6 @@ struct mc13xxx_regulator_priv {
 };
 
 extern int mc13xxx_sw_regulator(struct regulator_dev *rdev);
-extern int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev);
-extern int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
-						unsigned selector);
 extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
 		int min_uV, int max_uV, unsigned *selector);
 extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev);
@@ -68,6 +64,7 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
 		.desc = {						\
 			.name = #_name,					\
 			.n_voltages = ARRAY_SIZE(_voltages),		\
+			.volt_table =  _voltages,			\
 			.ops = &_ops,			\
 			.type = REGULATOR_VOLTAGE,			\
 			.id = prefix ## _name,		\
@@ -78,7 +75,6 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
 		.vsel_reg = prefix ## _vsel_reg,			\
 		.vsel_shift = prefix ## _vsel_reg ## _ ## _name ## VSEL,\
 		.vsel_mask = prefix ## _vsel_reg ## _ ## _name ## VSEL_M,\
-		.voltages =  _voltages,					\
 	}
 
 #define MC13xxx_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops)	\
@@ -86,6 +82,7 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
 		.desc = {						\
 			.name = #_name,					\
 			.n_voltages = ARRAY_SIZE(_voltages),		\
+			.volt_table =  _voltages,			\
 			.ops = &_ops,		\
 			.type = REGULATOR_VOLTAGE,			\
 			.id = prefix ## _name,		\
@@ -93,7 +90,6 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
 		},							\
 		.reg = prefix ## _reg,				\
 		.enable_bit = prefix ## _reg ## _ ## _name ## EN,	\
-		.voltages =  _voltages,					\
 	}
 
 #define MC13xxx_GPO_DEFINE(prefix, _name, _reg,  _voltages, _ops)	\
@@ -101,6 +97,7 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
 		.desc = {						\
 			.name = #_name,					\
 			.n_voltages = ARRAY_SIZE(_voltages),		\
+			.volt_table =  _voltages,			\
 			.ops = &_ops,		\
 			.type = REGULATOR_VOLTAGE,			\
 			.id = prefix ## _name,		\
@@ -108,7 +105,6 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
 		},							\
 		.reg = prefix ## _reg,				\
 		.enable_bit = prefix ## _reg ## _ ## _name ## EN,	\
-		.voltages =  _voltages,					\
 	}
 
 #define MC13xxx_DEFINE_SW(_name, _reg, _vsel_reg, _voltages, ops)	\
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 56593b7..68dc3d4 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -20,7 +20,7 @@ static void of_get_regulation_constraints(struct device_node *np,
 					struct regulator_init_data **init_data)
 {
 	const __be32 *min_uV, *max_uV, *uV_offset;
-	const __be32 *min_uA, *max_uA;
+	const __be32 *min_uA, *max_uA, *ramp_delay;
 	struct regulation_constraints *constraints = &(*init_data)->constraints;
 
 	constraints->name = of_get_property(np, "regulator-name", NULL);
@@ -60,6 +60,10 @@ static void of_get_regulation_constraints(struct device_node *np,
 		constraints->always_on = true;
 	else /* status change should be possible if not always on. */
 		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
+
+	ramp_delay = of_get_property(np, "regulator-ramp-delay", NULL);
+	if (ramp_delay)
+		constraints->ramp_delay = be32_to_cpu(*ramp_delay);
 }
 
 /**
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
index 9b7ca90..7540c95 100644
--- a/drivers/regulator/palmas-regulator.c
+++ b/drivers/regulator/palmas-regulator.c
@@ -257,8 +257,7 @@ static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
 	unsigned int reg;
 
 	palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
-	reg &= ~PALMAS_SMPS12_CTRL_STATUS_MASK;
-	reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT;
+	reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
 
 	switch (mode) {
 	case REGULATOR_MODE_NORMAL:
@@ -400,19 +399,14 @@ static struct regulator_ops palmas_ops_smps = {
 	.map_voltage		= palmas_map_voltage_smps,
 };
 
-static int palmas_list_voltage_smps10(struct regulator_dev *dev,
-					unsigned selector)
-{
-	return 3750000 + (selector * 1250000);
-}
-
 static struct regulator_ops palmas_ops_smps10 = {
 	.is_enabled		= regulator_is_enabled_regmap,
 	.enable			= regulator_enable_regmap,
 	.disable		= regulator_disable_regmap,
 	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
 	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
-	.list_voltage		= palmas_list_voltage_smps10,
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
 };
 
 static int palmas_is_enabled_ldo(struct regulator_dev *dev)
@@ -522,7 +516,15 @@ static int palmas_smps_init(struct palmas *palmas, int id,
 	if (ret)
 		return ret;
 
-	if (id != PALMAS_REG_SMPS10) {
+	switch (id) {
+	case PALMAS_REG_SMPS10:
+		if (reg_init->mode_sleep) {
+			reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
+			reg |= reg_init->mode_sleep <<
+					PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT;
+		}
+		break;
+	default:
 		if (reg_init->warm_reset)
 			reg |= PALMAS_SMPS12_CTRL_WR_S;
 
@@ -534,14 +536,8 @@ static int palmas_smps_init(struct palmas *palmas, int id,
 			reg |= reg_init->mode_sleep <<
 					PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT;
 		}
-	} else {
-		if (reg_init->mode_sleep) {
-			reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
-			reg |= reg_init->mode_sleep <<
-					PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT;
-		}
-
 	}
+
 	ret = palmas_smps_write(palmas, addr, reg);
 	if (ret)
 		return ret;
@@ -665,16 +661,22 @@ static __devinit int palmas_probe(struct platform_device *pdev)
 		pmic->desc[id].name = palmas_regs_info[id].name;
 		pmic->desc[id].id = id;
 
-		if (id != PALMAS_REG_SMPS10) {
-			pmic->desc[id].ops = &palmas_ops_smps;
-			pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES;
-		} else {
+		switch (id) {
+		case PALMAS_REG_SMPS10:
 			pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES;
 			pmic->desc[id].ops = &palmas_ops_smps10;
 			pmic->desc[id].vsel_reg = PALMAS_SMPS10_CTRL;
 			pmic->desc[id].vsel_mask = SMPS10_VSEL;
-			pmic->desc[id].enable_reg = PALMAS_SMPS10_STATUS;
+			pmic->desc[id].enable_reg =
+					PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
+							PALMAS_SMPS10_STATUS);
 			pmic->desc[id].enable_mask = SMPS10_BOOST_EN;
+			pmic->desc[id].min_uV = 3750000;
+			pmic->desc[id].uV_step = 1250000;
+			break;
+		default:
+			pmic->desc[id].ops = &palmas_ops_smps;
+			pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES;
 		}
 
 		pmic->desc[id].type = REGULATOR_VOLTAGE;
@@ -739,7 +741,8 @@ static __devinit int palmas_probe(struct platform_device *pdev)
 
 		pmic->desc[id].type = REGULATOR_VOLTAGE;
 		pmic->desc[id].owner = THIS_MODULE;
-		pmic->desc[id].enable_reg = palmas_regs_info[id].ctrl_addr;
+		pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+						palmas_regs_info[id].ctrl_addr);
 		pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE;
 
 		if (pdata && pdata->reg_data)
diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c
index 8211101..68777ac 100644
--- a/drivers/regulator/pcap-regulator.c
+++ b/drivers/regulator/pcap-regulator.c
@@ -18,80 +18,80 @@
 #include <linux/regulator/machine.h>
 #include <linux/mfd/ezx-pcap.h>
 
-static const u16 V1_table[] = {
-	2775, 1275, 1600, 1725, 1825, 1925, 2075, 2275,
+static const unsigned int V1_table[] = {
+	2775000, 1275000, 1600000, 1725000, 1825000, 1925000, 2075000, 2275000,
 };
 
-static const u16 V2_table[] = {
-	2500, 2775,
+static const unsigned int V2_table[] = {
+	2500000, 2775000,
 };
 
-static const u16 V3_table[] = {
-	1075, 1275, 1550, 1725, 1876, 1950, 2075, 2275,
+static const unsigned int V3_table[] = {
+	1075000, 1275000, 1550000, 1725000, 1876000, 1950000, 2075000, 2275000,
 };
 
-static const u16 V4_table[] = {
-	1275, 1550, 1725, 1875, 1950, 2075, 2275, 2775,
+static const unsigned int V4_table[] = {
+	1275000, 1550000, 1725000, 1875000, 1950000, 2075000, 2275000, 2775000,
 };
 
-static const u16 V5_table[] = {
-	1875, 2275, 2475, 2775,
+static const unsigned int V5_table[] = {
+	1875000, 2275000, 2475000, 2775000,
 };
 
-static const u16 V6_table[] = {
-	2475, 2775,
+static const unsigned int V6_table[] = {
+	2475000, 2775000,
 };
 
-static const u16 V7_table[] = {
-	1875, 2775,
+static const unsigned int V7_table[] = {
+	1875000, 2775000,
 };
 
 #define V8_table V4_table
 
-static const u16 V9_table[] = {
-	1575, 1875, 2475, 2775,
+static const unsigned int V9_table[] = {
+	1575000, 1875000, 2475000, 2775000,
 };
 
-static const u16 V10_table[] = {
-	5000,
+static const unsigned int V10_table[] = {
+	5000000,
 };
 
-static const u16 VAUX1_table[] = {
-	1875, 2475, 2775, 3000,
+static const unsigned int VAUX1_table[] = {
+	1875000, 2475000, 2775000, 3000000,
 };
 
 #define VAUX2_table VAUX1_table
 
-static const u16 VAUX3_table[] = {
-	1200, 1200, 1200, 1200, 1400, 1600, 1800, 2000,
-	2200, 2400, 2600, 2800, 3000, 3200, 3400, 3600,
+static const unsigned int VAUX3_table[] = {
+	1200000, 1200000, 1200000, 1200000, 1400000, 1600000, 1800000, 2000000,
+	2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000, 3600000,
 };
 
-static const u16 VAUX4_table[] = {
-	1800, 1800, 3000, 5000,
+static const unsigned int VAUX4_table[] = {
+	1800000, 1800000, 3000000, 5000000,
 };
 
-static const u16 VSIM_table[] = {
-	1875, 3000,
+static const unsigned int VSIM_table[] = {
+	1875000, 3000000,
 };
 
-static const u16 VSIM2_table[] = {
-	1875,
+static const unsigned int VSIM2_table[] = {
+	1875000,
 };
 
-static const u16 VVIB_table[] = {
-	1300, 1800, 2000, 3000,
+static const unsigned int VVIB_table[] = {
+	1300000, 1800000, 2000000, 3000000,
 };
 
-static const u16 SW1_table[] = {
-	900, 950, 1000, 1050, 1100, 1150, 1200, 1250,
-	1300, 1350, 1400, 1450, 1500, 1600, 1875, 2250,
+static const unsigned int SW1_table[] = {
+	 900000,  950000, 1000000, 1050000, 1100000, 1150000, 1200000, 1250000,
+	1300000, 1350000, 1400000, 1450000, 1500000, 1600000, 1875000, 2250000,
 };
 
 #define SW2_table SW1_table
 
-static const u16 SW3_table[] = {
-	4000, 4500, 5000, 5500,
+static const unsigned int SW3_table[] = {
+	4000000, 4500000, 5000000, 5500000,
 };
 
 struct pcap_regulator {
@@ -100,8 +100,6 @@ struct pcap_regulator {
 	const u8 index;
 	const u8 stby;
 	const u8 lowpwr;
-	const u8 n_voltages;
-	const u16 *voltage_table;
 };
 
 #define NA 0xff
@@ -113,8 +111,6 @@ struct pcap_regulator {
 		.index		= _index,				\
 		.stby		= _stby,				\
 		.lowpwr		= _lowpwr,				\
-		.n_voltages	= ARRAY_SIZE(_vreg##_table),		\
-		.voltage_table	= _vreg##_table,			\
 	}
 
 static struct pcap_regulator vreg_table[] = {
@@ -157,11 +153,11 @@ static int pcap_regulator_set_voltage_sel(struct regulator_dev *rdev,
 	void *pcap = rdev_get_drvdata(rdev);
 
 	/* the regulator doesn't support voltage switching */
-	if (vreg->n_voltages == 1)
+	if (rdev->desc->n_voltages == 1)
 		return -EINVAL;
 
 	return ezx_pcap_set_bits(pcap, vreg->reg,
-				 (vreg->n_voltages - 1) << vreg->index,
+				 (rdev->desc->n_voltages - 1) << vreg->index,
 				 selector << vreg->index);
 }
 
@@ -171,11 +167,11 @@ static int pcap_regulator_get_voltage_sel(struct regulator_dev *rdev)
 	void *pcap = rdev_get_drvdata(rdev);
 	u32 tmp;
 
-	if (vreg->n_voltages == 1)
+	if (rdev->desc->n_voltages == 1)
 		return 0;
 
 	ezx_pcap_read(pcap, vreg->reg, &tmp);
-	tmp = ((tmp >> vreg->index) & (vreg->n_voltages - 1));
+	tmp = ((tmp >> vreg->index) & (rdev->desc->n_voltages - 1));
 	return tmp;
 }
 
@@ -214,16 +210,8 @@ static int pcap_regulator_is_enabled(struct regulator_dev *rdev)
 	return (tmp >> vreg->en) & 1;
 }
 
-static int pcap_regulator_list_voltage(struct regulator_dev *rdev,
-							unsigned int index)
-{
-	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
-
-	return vreg->voltage_table[index] * 1000;
-}
-
 static struct regulator_ops pcap_regulator_ops = {
-	.list_voltage	= pcap_regulator_list_voltage,
+	.list_voltage	= regulator_list_voltage_table,
 	.set_voltage_sel = pcap_regulator_set_voltage_sel,
 	.get_voltage_sel = pcap_regulator_get_voltage_sel,
 	.enable		= pcap_regulator_enable,
@@ -236,6 +224,7 @@ static struct regulator_ops pcap_regulator_ops = {
 		.name		= #_vreg,			\
 		.id		= _vreg,			\
 		.n_voltages	= ARRAY_SIZE(_vreg##_table),	\
+		.volt_table	= _vreg##_table,		\
 		.ops		= &pcap_regulator_ops,		\
 		.type		= REGULATOR_VOLTAGE,		\
 		.owner		= THIS_MODULE,			\
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
index 3c9d14c..092e5cb 100644
--- a/drivers/regulator/pcf50633-regulator.c
+++ b/drivers/regulator/pcf50633-regulator.c
@@ -100,13 +100,12 @@ static unsigned int ldo_voltage_value(u8 bits)
 	return 900 + (bits * 100);
 }
 
-static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
-					  int min_uV, int max_uV,
-					  unsigned *selector)
+static int pcf50633_regulator_map_voltage(struct regulator_dev *rdev,
+					  int min_uV, int max_uV)
 {
 	struct pcf50633 *pcf;
 	int regulator_id, millivolts;
-	u8 volt_bits, regnr;
+	u8 volt_bits;
 
 	pcf = rdev_get_drvdata(rdev);
 
@@ -116,15 +115,11 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
 
 	millivolts = min_uV / 1000;
 
-	regnr = rdev->desc->vsel_reg;
-
 	switch (regulator_id) {
 	case PCF50633_REGULATOR_AUTO:
 		volt_bits = auto_voltage_bits(millivolts);
 		break;
 	case PCF50633_REGULATOR_DOWN1:
-		volt_bits = down_voltage_bits(millivolts);
-		break;
 	case PCF50633_REGULATOR_DOWN2:
 		volt_bits = down_voltage_bits(millivolts);
 		break;
@@ -142,9 +137,7 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
 		return -EINVAL;
 	}
 
-	*selector = volt_bits;
-
-	return pcf50633_reg_write(pcf, regnr, volt_bits);
+	return volt_bits;
 }
 
 static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
@@ -159,8 +152,6 @@ static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
 		millivolts = auto_voltage_value(index);
 		break;
 	case PCF50633_REGULATOR_DOWN1:
-		millivolts = down_voltage_value(index);
-		break;
 	case PCF50633_REGULATOR_DOWN2:
 		millivolts = down_voltage_value(index);
 		break;
@@ -182,9 +173,10 @@ static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
 }
 
 static struct regulator_ops pcf50633_regulator_ops = {
-	.set_voltage = pcf50633_regulator_set_voltage,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.list_voltage = pcf50633_regulator_list_voltage,
+	.map_voltage = pcf50633_regulator_map_voltage,
 	.enable = regulator_enable_regmap,
 	.disable = regulator_disable_regmap,
 	.is_enabled = regulator_is_enabled_regmap,
diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c
index 1d34e64..8bf4e8c 100644
--- a/drivers/regulator/rc5t583-regulator.c
+++ b/drivers/regulator/rc5t583-regulator.c
@@ -42,7 +42,6 @@ struct rc5t583_regulator_info {
 
 	/* Regulator specific turn-on delay  and voltage settling time*/
 	int			enable_uv_per_us;
-	int			change_uv_per_us;
 
 	/* Used by regulator core */
 	struct regulator_desc	desc;
@@ -66,25 +65,6 @@ static int rc5t583_regulator_enable_time(struct regulator_dev *rdev)
 	return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us);
 }
 
-static int rc5t583_set_voltage_time_sel(struct regulator_dev *rdev,
-		unsigned int old_selector, unsigned int new_selector)
-{
-	struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
-	int old_uV, new_uV;
-	old_uV = regulator_list_voltage_linear(rdev, old_selector);
-
-	if (old_uV < 0)
-		return old_uV;
-
-	new_uV = regulator_list_voltage_linear(rdev, new_selector);
-	if (new_uV < 0)
-		return new_uV;
-
-	return DIV_ROUND_UP(abs(old_uV - new_uV),
-				reg->reg_info->change_uv_per_us);
-}
-
-
 static struct regulator_ops rc5t583_ops = {
 	.is_enabled		= regulator_is_enabled_regmap,
 	.enable			= regulator_enable_regmap,
@@ -94,7 +74,7 @@ static struct regulator_ops rc5t583_ops = {
 	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
 	.list_voltage		= regulator_list_voltage_linear,
 	.map_voltage		= regulator_map_voltage_linear,
-	.set_voltage_time_sel	= rc5t583_set_voltage_time_sel,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
 };
 
 #define RC5T583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, \
@@ -104,7 +84,6 @@ static struct regulator_ops rc5t583_ops = {
 	.disc_bit	= _disc_bit,				\
 	.deepsleep_reg	= RC5T583_REG_##_id##DAC_DS,		\
 	.enable_uv_per_us = _enable_mv * 1000,			\
-	.change_uv_per_us = 40 * 1000,				\
 	.deepsleep_id	= RC5T583_DS_##_id,			\
 	.desc = {						\
 		.name = "rc5t583-regulator-"#_id,		\
@@ -119,6 +98,7 @@ static struct regulator_ops rc5t583_ops = {
 		.enable_mask = BIT(_en_bit),			\
 		.min_uV	= _min_mv * 1000,			\
 		.uV_step = _step_uV,				\
+		.ramp_delay = 40 * 1000,			\
 	},							\
 }
 
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 9caadb4..1ad9c3c 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -41,6 +41,7 @@ struct s5m8767_info {
 	u8 buck3_vol[8];
 	u8 buck4_vol[8];
 	int buck_gpios[3];
+	int buck_ds[3];
 	int buck_gpioindex;
 };
 
@@ -120,27 +121,6 @@ static const struct s5m_voltage_desc *reg_voltage_map[] = {
 	[S5M8767_BUCK9] = &buck_voltage_val3,
 };
 
-static int s5m8767_list_voltage(struct regulator_dev *rdev,
-				unsigned int selector)
-{
-	const struct s5m_voltage_desc *desc;
-	int reg_id = rdev_get_id(rdev);
-	int val;
-
-	if (reg_id >= ARRAY_SIZE(reg_voltage_map) || reg_id < 0)
-		return -EINVAL;
-
-	desc = reg_voltage_map[reg_id];
-	if (desc == NULL)
-		return -EINVAL;
-
-	val = desc->min + desc->step * selector;
-	if (val > desc->max)
-		return -EINVAL;
-
-	return val;
-}
-
 static unsigned int s5m8767_opmode_reg[][4] = {
 	/* {OFF, ON, LOWPOWER, SUSPEND} */
 	/* LDO1 ... LDO28 */
@@ -283,17 +263,17 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
 		reg = S5M8767_REG_BUCK1CTRL2;
 		break;
 	case S5M8767_BUCK2:
-		reg = S5M8767_REG_BUCK2DVS1;
+		reg = S5M8767_REG_BUCK2DVS2;
 		if (s5m8767->buck2_gpiodvs)
 			reg += s5m8767->buck_gpioindex;
 		break;
 	case S5M8767_BUCK3:
-		reg = S5M8767_REG_BUCK3DVS1;
+		reg = S5M8767_REG_BUCK3DVS2;
 		if (s5m8767->buck3_gpiodvs)
 			reg += s5m8767->buck_gpioindex;
 		break;
 	case S5M8767_BUCK4:
-		reg = S5M8767_REG_BUCK4DVS1;
+		reg = S5M8767_REG_BUCK4DVS2;
 		if (s5m8767->buck4_gpiodvs)
 			reg += s5m8767->buck_gpioindex;
 		break;
@@ -357,32 +337,34 @@ static int s5m8767_convert_voltage_to_sel(
 	return selector;
 }
 
-static inline void s5m8767_set_high(struct s5m8767_info *s5m8767)
+static inline int s5m8767_set_high(struct s5m8767_info *s5m8767)
 {
 	int temp_index = s5m8767->buck_gpioindex;
 
 	gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
 	gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
 	gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
+
+	return 0;
 }
 
-static inline void s5m8767_set_low(struct s5m8767_info *s5m8767)
+static inline int s5m8767_set_low(struct s5m8767_info *s5m8767)
 {
 	int temp_index = s5m8767->buck_gpioindex;
 
 	gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
 	gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
 	gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
+
+	return 0;
 }
 
-static int s5m8767_set_voltage(struct regulator_dev *rdev,
-				int min_uV, int max_uV, unsigned *selector)
+static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
+				   unsigned selector)
 {
 	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-	const struct s5m_voltage_desc *desc;
 	int reg_id = rdev_get_id(rdev);
-	int sel, reg, mask, ret = 0, old_index, index = 0;
-	u8 val;
+	int reg, mask, ret = 0, old_index, index = 0;
 	u8 *buck234_vol = NULL;
 
 	switch (reg_id) {
@@ -407,15 +389,9 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev,
 		return -EINVAL;
 	}
 
-	desc = reg_voltage_map[reg_id];
-
-	sel = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
-	if (sel < 0)
-		return sel;
-
 	/* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */
 	if (buck234_vol) {
-		while (*buck234_vol != sel) {
+		while (*buck234_vol != selector) {
 			buck234_vol++;
 			index++;
 		}
@@ -423,22 +399,16 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev,
 		s5m8767->buck_gpioindex = index;
 
 		if (index > old_index)
-			s5m8767_set_high(s5m8767);
+			return s5m8767_set_high(s5m8767);
 		else
-			s5m8767_set_low(s5m8767);
+			return s5m8767_set_low(s5m8767);
 	} else {
 		ret = s5m8767_get_voltage_register(rdev, &reg);
 		if (ret)
 			return ret;
 
-		s5m_reg_read(s5m8767->iodev, reg, &val);
-		val = (val & ~mask) | sel;
-
-		ret = s5m_reg_write(s5m8767->iodev, reg, val);
+		return s5m_reg_update(s5m8767->iodev, reg, selector, mask);
 	}
-
-	*selector = sel;
-	return ret;
 }
 
 static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
@@ -458,15 +428,21 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
 }
 
 static struct regulator_ops s5m8767_ops = {
-	.list_voltage		= s5m8767_list_voltage,
+	.list_voltage		= regulator_list_voltage_linear,
 	.is_enabled		= s5m8767_reg_is_enabled,
 	.enable			= s5m8767_reg_enable,
 	.disable		= s5m8767_reg_disable,
 	.get_voltage_sel	= s5m8767_get_voltage_sel,
-	.set_voltage		= s5m8767_set_voltage,
+	.set_voltage_sel	= s5m8767_set_voltage_sel,
 	.set_voltage_time_sel	= s5m8767_set_voltage_time_sel,
 };
 
+static struct regulator_ops s5m8767_buck78_ops = {
+	.is_enabled		= s5m8767_reg_is_enabled,
+	.enable			= s5m8767_reg_enable,
+	.disable		= s5m8767_reg_disable,
+};
+
 #define s5m8767_regulator_desc(_name) {		\
 	.name		= #_name,		\
 	.id		= S5M8767_##_name,	\
@@ -475,6 +451,14 @@ static struct regulator_ops s5m8767_ops = {
 	.owner		= THIS_MODULE,		\
 }
 
+#define s5m8767_regulator_buck78_desc(_name) {	\
+	.name		= #_name,		\
+	.id		= S5M8767_##_name,	\
+	.ops		= &s5m8767_buck78_ops,	\
+	.type		= REGULATOR_VOLTAGE,	\
+	.owner		= THIS_MODULE,		\
+}
+
 static struct regulator_desc regulators[] = {
 	s5m8767_regulator_desc(LDO1),
 	s5m8767_regulator_desc(LDO2),
@@ -510,8 +494,8 @@ static struct regulator_desc regulators[] = {
 	s5m8767_regulator_desc(BUCK4),
 	s5m8767_regulator_desc(BUCK5),
 	s5m8767_regulator_desc(BUCK6),
-	s5m8767_regulator_desc(BUCK7),
-	s5m8767_regulator_desc(BUCK8),
+	s5m8767_regulator_buck78_desc(BUCK7),
+	s5m8767_regulator_buck78_desc(BUCK8),
 	s5m8767_regulator_desc(BUCK9),
 };
 
@@ -522,7 +506,7 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
 	struct regulator_config config = { };
 	struct regulator_dev **rdev;
 	struct s5m8767_info *s5m8767;
-	int i, ret, size;
+	int i, ret, size, buck_init;
 
 	if (!pdata) {
 		dev_err(pdev->dev.parent, "Platform data not supplied\n");
@@ -573,12 +557,37 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
 	s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
 	s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
 	s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
+	s5m8767->buck_ds[0] = pdata->buck_ds[0];
+	s5m8767->buck_ds[1] = pdata->buck_ds[1];
+	s5m8767->buck_ds[2] = pdata->buck_ds[2];
+
 	s5m8767->ramp_delay = pdata->buck_ramp_delay;
 	s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
 	s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
 	s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
 	s5m8767->opmode = pdata->opmode;
 
+	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+						pdata->buck2_init,
+						pdata->buck2_init +
+						buck_voltage_val2.step);
+
+	s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);
+
+	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+						pdata->buck3_init,
+						pdata->buck3_init +
+						buck_voltage_val2.step);
+
+	s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);
+
+	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+						pdata->buck4_init,
+						pdata->buck4_init +
+						buck_voltage_val2.step);
+
+	s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);
+
 	for (i = 0; i < 8; i++) {
 		if (s5m8767->buck2_gpiodvs) {
 			s5m8767->buck2_vol[i] =
@@ -608,48 +617,71 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
-		pdata->buck4_gpiodvs) {
-		if (gpio_is_valid(pdata->buck_gpios[0]) &&
-			gpio_is_valid(pdata->buck_gpios[1]) &&
-			gpio_is_valid(pdata->buck_gpios[2])) {
-			ret = gpio_request(pdata->buck_gpios[0],
-						"S5M8767 SET1");
-			if (ret == -EBUSY)
-				dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n");
-
-			ret = gpio_request(pdata->buck_gpios[1],
-					   "S5M8767 SET2");
-			if (ret == -EBUSY)
-				dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n");
-
-			ret = gpio_request(pdata->buck_gpios[2],
-					   "S5M8767 SET3");
-			if (ret == -EBUSY)
-				dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n");
-			/* SET1 GPIO */
-			gpio_direction_output(pdata->buck_gpios[0],
-					(s5m8767->buck_gpioindex >> 2) & 0x1);
-			/* SET2 GPIO */
-			gpio_direction_output(pdata->buck_gpios[1],
-					(s5m8767->buck_gpioindex >> 1) & 0x1);
-			/* SET3 GPIO */
-			gpio_direction_output(pdata->buck_gpios[2],
-					(s5m8767->buck_gpioindex >> 0) & 0x1);
-			ret = 0;
-		} else {
-			dev_err(&pdev->dev, "GPIO NOT VALID\n");
-			ret = -EINVAL;
-			return ret;
-		}
+	if (gpio_is_valid(pdata->buck_gpios[0]) &&
+		gpio_is_valid(pdata->buck_gpios[1]) &&
+		gpio_is_valid(pdata->buck_gpios[2])) {
+		ret = gpio_request(pdata->buck_gpios[0], "S5M8767 SET1");
+		if (ret == -EBUSY)
+			dev_warn(&pdev->dev, "Duplicated gpio request"
+				" for SET1\n");
+
+		ret = gpio_request(pdata->buck_gpios[1], "S5M8767 SET2");
+		if (ret == -EBUSY)
+			dev_warn(&pdev->dev, "Duplicated gpio request"
+				" for SET2\n");
+
+		ret = gpio_request(pdata->buck_gpios[2], "S5M8767 SET3");
+		if (ret == -EBUSY)
+			dev_warn(&pdev->dev, "Duplicated gpio request"
+					" for SET3\n");
+		/* SET1 GPIO */
+		gpio_direction_output(pdata->buck_gpios[0],
+				(s5m8767->buck_gpioindex >> 2) & 0x1);
+		/* SET2 GPIO */
+		gpio_direction_output(pdata->buck_gpios[1],
+				(s5m8767->buck_gpioindex >> 1) & 0x1);
+		/* SET3 GPIO */
+		gpio_direction_output(pdata->buck_gpios[2],
+				(s5m8767->buck_gpioindex >> 0) & 0x1);
+		ret = 0;
+
+	} else {
+		dev_err(&pdev->dev, "GPIO NOT VALID\n");
+		ret = -EINVAL;
+		return ret;
 	}
 
-	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
-			(pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
-	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
-			(pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
-	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
-			(pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
+	ret = gpio_request(pdata->buck_ds[0], "S5M8767 DS2");
+	if (ret == -EBUSY)
+		dev_warn(&pdev->dev, "Duplicated gpio request for DS2\n");
+
+	ret = gpio_request(pdata->buck_ds[1], "S5M8767 DS3");
+	if (ret == -EBUSY)
+		dev_warn(&pdev->dev, "Duplicated gpio request for DS3\n");
+
+	ret = gpio_request(pdata->buck_ds[2], "S5M8767 DS4");
+	if (ret == -EBUSY)
+		dev_warn(&pdev->dev, "Duplicated gpio request for DS4\n");
+
+	/* DS2 GPIO */
+	gpio_direction_output(pdata->buck_ds[0], 0x0);
+	/* DS3 GPIO */
+	gpio_direction_output(pdata->buck_ds[1], 0x0);
+	/* DS4 GPIO */
+	gpio_direction_output(pdata->buck_ds[2], 0x0);
+
+	if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
+	   pdata->buck4_gpiodvs) {
+		s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
+				(pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1),
+				1 << 1);
+		s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
+				(pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1),
+				1 << 1);
+		s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
+				(pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1),
+				1 << 1);
+	}
 
 	/* Initialize GPIO DVS registers */
 	for (i = 0; i < 8; i++) {
@@ -668,9 +700,6 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
 					   s5m8767->buck4_vol[i]);
 		}
 	}
-	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, 0x78, 0xff);
-	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, 0x58, 0xff);
-	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, 0x78, 0xff);
 
 	if (s5m8767->buck2_ramp)
 		s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08);
@@ -684,9 +713,13 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
 	if (s5m8767->buck2_ramp || s5m8767->buck3_ramp
 		|| s5m8767->buck4_ramp) {
 		switch (s5m8767->ramp_delay) {
-		case 15:
+		case 5:
 			s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
-					0xc0, 0xf0);
+					0x40, 0xf0);
+			break;
+		case 10:
+			s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+					0x90, 0xf0);
 			break;
 		case 25:
 			s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
@@ -711,9 +744,12 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
 		int id = pdata->regulators[i].id;
 
 		desc = reg_voltage_map[id];
-		if (desc)
+		if (desc) {
 			regulators[id].n_voltages =
 				(desc->max - desc->min) / desc->step + 1;
+			regulators[id].min_uV = desc->min;
+			regulators[id].uV_step = desc->step;
+		}
 
 		config.dev = s5m8767->dev;
 		config.init_data = pdata->regulators[i].initdata;
diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c
index d840d84..1378409 100644
--- a/drivers/regulator/tps6105x-regulator.c
+++ b/drivers/regulator/tps6105x-regulator.c
@@ -20,7 +20,7 @@
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps6105x.h>
 
-static const int tps6105x_voltages[] = {
+static const unsigned int tps6105x_voltages[] = {
 	4500000,
 	5000000,
 	5250000,
@@ -105,22 +105,13 @@ static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
 	return 0;
 }
 
-static int tps6105x_regulator_list_voltage(struct regulator_dev *rdev,
-					   unsigned selector)
-{
-	if (selector >= ARRAY_SIZE(tps6105x_voltages))
-		return -EINVAL;
-
-	return tps6105x_voltages[selector];
-}
-
 static struct regulator_ops tps6105x_regulator_ops = {
 	.enable		= tps6105x_regulator_enable,
 	.disable	= tps6105x_regulator_disable,
 	.is_enabled	= tps6105x_regulator_is_enabled,
 	.get_voltage_sel = tps6105x_regulator_get_voltage_sel,
 	.set_voltage_sel = tps6105x_regulator_set_voltage_sel,
-	.list_voltage	= tps6105x_regulator_list_voltage,
+	.list_voltage	= regulator_list_voltage_table,
 };
 
 static const struct regulator_desc tps6105x_regulator_desc = {
@@ -130,6 +121,7 @@ static const struct regulator_desc tps6105x_regulator_desc = {
 	.id		= 0,
 	.owner		= THIS_MODULE,
 	.n_voltages	= ARRAY_SIZE(tps6105x_voltages),
+	.volt_table	= tps6105x_voltages,
 };
 
 /*
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c
index e534269..bcea4e1 100644
--- a/drivers/regulator/tps62360-regulator.c
+++ b/drivers/regulator/tps62360-regulator.c
@@ -65,10 +65,8 @@ struct tps62360_chip {
 	struct regulator_desc desc;
 	struct regulator_dev *rdev;
 	struct regmap *regmap;
-	int chip_id;
 	int vsel0_gpio;
 	int vsel1_gpio;
-	int voltage_base;
 	u8 voltage_reg_mask;
 	bool en_internal_pulldn;
 	bool en_discharge;
@@ -179,17 +177,10 @@ static int tps62360_set_voltage_time_sel(struct regulator_dev *rdev,
 		unsigned int old_selector, unsigned int new_selector)
 {
 	struct tps62360_chip *tps = rdev_get_drvdata(rdev);
-	int old_uV, new_uV;
-
-	old_uV = regulator_list_voltage_linear(rdev, old_selector);
-	if (old_uV < 0)
-		return old_uV;
-
-	new_uV = regulator_list_voltage_linear(rdev, new_selector);
-	if (new_uV < 0)
-		return new_uV;
 
-	return DIV_ROUND_UP(abs(old_uV - new_uV), tps->change_uv_per_us);
+	return DIV_ROUND_UP(abs(new_selector - old_selector) *
+			    rdev->desc->uV_step,
+			    tps->change_uv_per_us);
 }
 
 static int tps62360_set_mode(struct regulator_dev *rdev, unsigned int mode)
@@ -408,13 +399,13 @@ static int __devinit tps62360_probe(struct i2c_client *client,
 	switch (chip_id) {
 	case TPS62360:
 	case TPS62362:
-		tps->voltage_base = TPS62360_BASE_VOLTAGE;
+		tps->desc.min_uV = TPS62360_BASE_VOLTAGE;
 		tps->voltage_reg_mask = 0x3F;
 		tps->desc.n_voltages = TPS62360_N_VOLTAGES;
 		break;
 	case TPS62361:
 	case TPS62363:
-		tps->voltage_base = TPS62361_BASE_VOLTAGE;
+		tps->desc.min_uV = TPS62361_BASE_VOLTAGE;
 		tps->voltage_reg_mask = 0x7F;
 		tps->desc.n_voltages = TPS62361_N_VOLTAGES;
 		break;
@@ -427,7 +418,6 @@ static int __devinit tps62360_probe(struct i2c_client *client,
 	tps->desc.ops = &tps62360_dcdc_ops;
 	tps->desc.type = REGULATOR_VOLTAGE;
 	tps->desc.owner = THIS_MODULE;
-	tps->desc.min_uV = tps->voltage_base;
 	tps->desc.uV_step = 10000;
 
 	tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config);
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index f841bd0..6998d57 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -69,10 +69,6 @@
 #define TPS65023_REG_CTRL2_DCDC1	BIT(1)
 #define TPS65023_REG_CTRL2_DCDC3	BIT(0)
 
-/* LDO_CTRL bitfields */
-#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id)	((ldo_id)*4)
-#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id)	(0x0F << ((ldo_id)*4))
-
 /* Number of step-down converters available */
 #define TPS65023_NUM_DCDC		3
 /* Number of LDO voltage regulators  available */
@@ -91,48 +87,53 @@
 #define TPS65023_MAX_REG_ID		TPS65023_LDO_2
 
 /* Supported voltage values for regulators */
-static const u16 VCORE_VSEL_table[] = {
-	800, 825, 850, 875,
-	900, 925, 950, 975,
-	1000, 1025, 1050, 1075,
-	1100, 1125, 1150, 1175,
-	1200, 1225, 1250, 1275,
-	1300, 1325, 1350, 1375,
-	1400, 1425, 1450, 1475,
-	1500, 1525, 1550, 1600,
+static const unsigned int VCORE_VSEL_table[] = {
+	800000, 825000, 850000, 875000,
+	900000, 925000, 950000, 975000,
+	1000000, 1025000, 1050000, 1075000,
+	1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000,
+	1300000, 1325000, 1350000, 1375000,
+	1400000, 1425000, 1450000, 1475000,
+	1500000, 1525000, 1550000, 1600000,
+};
+
+static const unsigned int DCDC_FIXED_3300000_VSEL_table[] = {
+	3300000,
+};
+
+static const unsigned int DCDC_FIXED_1800000_VSEL_table[] = {
+	1800000,
 };
 
 /* Supported voltage values for LDO regulators for tps65020 */
-static const u16 TPS65020_LDO1_VSEL_table[] = {
-	1000, 1050, 1100, 1300,
-	1800, 2500, 3000, 3300,
+static const unsigned int TPS65020_LDO1_VSEL_table[] = {
+	1000000, 1050000, 1100000, 1300000,
+	1800000, 2500000, 3000000, 3300000,
 };
 
-static const u16 TPS65020_LDO2_VSEL_table[] = {
-	1000, 1050, 1100, 1300,
-	1800, 2500, 3000, 3300,
+static const unsigned int TPS65020_LDO2_VSEL_table[] = {
+	1000000, 1050000, 1100000, 1300000,
+	1800000, 2500000, 3000000, 3300000,
 };
 
 /* Supported voltage values for LDO regulators
  * for tps65021 and tps65023 */
-static const u16 TPS65023_LDO1_VSEL_table[] = {
-	1000, 1100, 1300, 1800,
-	2200, 2600, 2800, 3150,
+static const unsigned int TPS65023_LDO1_VSEL_table[] = {
+	1000000, 1100000, 1300000, 1800000,
+	2200000, 2600000, 2800000, 3150000,
 };
 
-static const u16 TPS65023_LDO2_VSEL_table[] = {
-	1050, 1200, 1300, 1800,
-	2500, 2800, 3000, 3300,
+static const unsigned int TPS65023_LDO2_VSEL_table[] = {
+	1050000, 1200000, 1300000, 1800000,
+	2500000, 2800000, 3000000, 3300000,
 };
 
 /* Regulator specific details */
 struct tps_info {
 	const char *name;
-	unsigned min_uV;
-	unsigned max_uV;
-	bool fixed;
 	u8 table_len;
-	const u16 *table;
+	const unsigned int *table;
 };
 
 /* PMIC details */
@@ -150,7 +151,7 @@ struct tps_driver_data {
 	u8 core_regulator;
 };
 
-static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
+static int tps65023_dcdc_get_voltage_sel(struct regulator_dev *dev)
 {
 	struct tps_pmic *tps = rdev_get_drvdata(dev);
 	int ret;
@@ -164,9 +165,9 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
 		if (ret != 0)
 			return ret;
 		data &= (tps->info[dcdc]->table_len - 1);
-		return tps->info[dcdc]->table[data] * 1000;
+		return data;
 	} else
-		return tps->info[dcdc]->min_uV;
+		return 0;
 }
 
 static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
@@ -193,76 +194,14 @@ out:
 	return ret;
 }
 
-static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
-{
-	struct tps_pmic *tps = rdev_get_drvdata(dev);
-	int data, ldo = rdev_get_id(dev);
-	int ret;
-
-	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
-		return -EINVAL;
-
-	ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data);
-	if (ret != 0)
-		return ret;
-
-	data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1));
-	data &= (tps->info[ldo]->table_len - 1);
-	return tps->info[ldo]->table[data] * 1000;
-}
-
-static int tps65023_ldo_set_voltage_sel(struct regulator_dev *dev,
-					unsigned selector)
-{
-	struct tps_pmic *tps = rdev_get_drvdata(dev);
-	int ldo_index = rdev_get_id(dev) - TPS65023_LDO_1;
-
-	return regmap_update_bits(tps->regmap, TPS65023_REG_LDO_CTRL,
-			TPS65023_LDO_CTRL_LDOx_MASK(ldo_index),
-			selector << TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_index));
-}
-
-static int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
-					unsigned selector)
-{
-	struct tps_pmic *tps = rdev_get_drvdata(dev);
-	int dcdc = rdev_get_id(dev);
-
-	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
-		return -EINVAL;
-
-	if (dcdc == tps->core_regulator) {
-		if (selector >= tps->info[dcdc]->table_len)
-			return -EINVAL;
-		else
-			return tps->info[dcdc]->table[selector] * 1000;
-	} else
-		return tps->info[dcdc]->min_uV;
-}
-
-static int tps65023_ldo_list_voltage(struct regulator_dev *dev,
-					unsigned selector)
-{
-	struct tps_pmic *tps = rdev_get_drvdata(dev);
-	int ldo = rdev_get_id(dev);
-
-	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
-		return -EINVAL;
-
-	if (selector >= tps->info[ldo]->table_len)
-		return -EINVAL;
-	else
-		return tps->info[ldo]->table[selector] * 1000;
-}
-
 /* Operations permitted on VDCDCx */
 static struct regulator_ops tps65023_dcdc_ops = {
 	.is_enabled = regulator_is_enabled_regmap,
 	.enable = regulator_enable_regmap,
 	.disable = regulator_disable_regmap,
-	.get_voltage = tps65023_dcdc_get_voltage,
+	.get_voltage_sel = tps65023_dcdc_get_voltage_sel,
 	.set_voltage_sel = tps65023_dcdc_set_voltage_sel,
-	.list_voltage = tps65023_dcdc_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 };
 
 /* Operations permitted on LDOx */
@@ -270,9 +209,9 @@ static struct regulator_ops tps65023_ldo_ops = {
 	.is_enabled = regulator_is_enabled_regmap,
 	.enable = regulator_enable_regmap,
 	.disable = regulator_disable_regmap,
-	.get_voltage = tps65023_ldo_get_voltage,
-	.set_voltage_sel = tps65023_ldo_set_voltage_sel,
-	.list_voltage = tps65023_ldo_list_voltage,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.list_voltage = regulator_list_voltage_table,
 };
 
 static struct regmap_config tps65023_regmap_config = {
@@ -325,19 +264,28 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
 		tps->desc[i].name = info->name;
 		tps->desc[i].id = i;
 		tps->desc[i].n_voltages = info->table_len;
+		tps->desc[i].volt_table = info->table;
 		tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
 					&tps65023_ldo_ops : &tps65023_dcdc_ops);
 		tps->desc[i].type = REGULATOR_VOLTAGE;
 		tps->desc[i].owner = THIS_MODULE;
 
 		tps->desc[i].enable_reg = TPS65023_REG_REG_CTRL;
-		if (i == TPS65023_LDO_1)
+		switch (i) {
+		case TPS65023_LDO_1:
+			tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
+			tps->desc[i].vsel_mask = 0x07;
 			tps->desc[i].enable_mask = 1 << 1;
-		else if (i == TPS65023_LDO_2)
+			break;
+		case TPS65023_LDO_2:
+			tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
+			tps->desc[i].vsel_mask = 0x70;
 			tps->desc[i].enable_mask = 1 << 2;
-		else /* DCDCx */
+			break;
+		default: /* DCDCx */
 			tps->desc[i].enable_mask =
 					1 << (TPS65023_NUM_REGULATOR - i);
+		}
 
 		config.dev = &client->dev;
 		config.init_data = init_data;
@@ -384,35 +332,26 @@ static int __devexit tps_65023_remove(struct i2c_client *client)
 static const struct tps_info tps65020_regs[] = {
 	{
 		.name = "VDCDC1",
-		.min_uV = 3300000,
-		.max_uV = 3300000,
-		.fixed	= 1,
+		.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
+		.table = DCDC_FIXED_3300000_VSEL_table,
 	},
 	{
 		.name = "VDCDC2",
-		.min_uV =  1800000,
-		.max_uV = 1800000,
-		.fixed = 1,
+		.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
+		.table = DCDC_FIXED_1800000_VSEL_table,
 	},
 	{
 		.name = "VDCDC3",
-		.min_uV =  800000,
-		.max_uV = 1600000,
 		.table_len = ARRAY_SIZE(VCORE_VSEL_table),
 		.table = VCORE_VSEL_table,
 	},
-
 	{
 		.name = "LDO1",
-		.min_uV = 1000000,
-		.max_uV = 3150000,
 		.table_len = ARRAY_SIZE(TPS65020_LDO1_VSEL_table),
 		.table = TPS65020_LDO1_VSEL_table,
 	},
 	{
 		.name = "LDO2",
-		.min_uV = 1050000,
-		.max_uV = 3300000,
 		.table_len = ARRAY_SIZE(TPS65020_LDO2_VSEL_table),
 		.table = TPS65020_LDO2_VSEL_table,
 	},
@@ -421,34 +360,26 @@ static const struct tps_info tps65020_regs[] = {
 static const struct tps_info tps65021_regs[] = {
 	{
 		.name = "VDCDC1",
-		.min_uV =  3300000,
-		.max_uV = 3300000,
-		.fixed = 1,
+		.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
+		.table = DCDC_FIXED_3300000_VSEL_table,
 	},
 	{
 		.name = "VDCDC2",
-		.min_uV =  1800000,
-		.max_uV = 1800000,
-		.fixed = 1,
+		.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
+		.table = DCDC_FIXED_1800000_VSEL_table,
 	},
 	{
 		.name = "VDCDC3",
-		.min_uV =  800000,
-		.max_uV = 1600000,
 		.table_len = ARRAY_SIZE(VCORE_VSEL_table),
 		.table = VCORE_VSEL_table,
 	},
 	{
 		.name = "LDO1",
-		.min_uV = 1000000,
-		.max_uV = 3150000,
 		.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
 		.table = TPS65023_LDO1_VSEL_table,
 	},
 	{
 		.name = "LDO2",
-		.min_uV = 1050000,
-		.max_uV = 3300000,
 		.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
 		.table = TPS65023_LDO2_VSEL_table,
 	},
@@ -457,34 +388,26 @@ static const struct tps_info tps65021_regs[] = {
 static const struct tps_info tps65023_regs[] = {
 	{
 		.name = "VDCDC1",
-		.min_uV =  800000,
-		.max_uV = 1600000,
 		.table_len = ARRAY_SIZE(VCORE_VSEL_table),
 		.table = VCORE_VSEL_table,
 	},
 	{
 		.name = "VDCDC2",
-		.min_uV =  3300000,
-		.max_uV = 3300000,
-		.fixed = 1,
+		.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
+		.table = DCDC_FIXED_3300000_VSEL_table,
 	},
 	{
 		.name = "VDCDC3",
-		.min_uV =  1800000,
-		.max_uV = 1800000,
-		.fixed = 1,
+		.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
+		.table = DCDC_FIXED_1800000_VSEL_table,
 	},
 	{
 		.name = "LDO1",
-		.min_uV = 1000000,
-		.max_uV = 3150000,
 		.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
 		.table = TPS65023_LDO1_VSEL_table,
 	},
 	{
 		.name = "LDO2",
-		.min_uV = 1050000,
-		.max_uV = 3300000,
 		.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
 		.table = TPS65023_LDO2_VSEL_table,
 	},
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index da38be1..07d01cc 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -43,58 +43,40 @@
 /* Number of total regulators available */
 #define TPS6507X_NUM_REGULATOR		(TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
 
-/* Supported voltage values for regulators (in milliVolts) */
-static const u16 VDCDCx_VSEL_table[] = {
-	725, 750, 775, 800,
-	825, 850, 875, 900,
-	925, 950, 975, 1000,
-	1025, 1050, 1075, 1100,
-	1125, 1150, 1175, 1200,
-	1225, 1250, 1275, 1300,
-	1325, 1350, 1375, 1400,
-	1425, 1450, 1475, 1500,
-	1550, 1600, 1650, 1700,
-	1750, 1800, 1850, 1900,
-	1950, 2000, 2050, 2100,
-	2150, 2200, 2250, 2300,
-	2350, 2400, 2450, 2500,
-	2550, 2600, 2650, 2700,
-	2750, 2800, 2850, 2900,
-	3000, 3100, 3200, 3300,
+/* Supported voltage values for regulators (in microVolts) */
+static const unsigned int VDCDCx_VSEL_table[] = {
+	725000, 750000, 775000, 800000,
+	825000, 850000, 875000, 900000,
+	925000, 950000, 975000, 1000000,
+	1025000, 1050000, 1075000, 1100000,
+	1125000, 1150000, 1175000, 1200000,
+	1225000, 1250000, 1275000, 1300000,
+	1325000, 1350000, 1375000, 1400000,
+	1425000, 1450000, 1475000, 1500000,
+	1550000, 1600000, 1650000, 1700000,
+	1750000, 1800000, 1850000, 1900000,
+	1950000, 2000000, 2050000, 2100000,
+	2150000, 2200000, 2250000, 2300000,
+	2350000, 2400000, 2450000, 2500000,
+	2550000, 2600000, 2650000, 2700000,
+	2750000, 2800000, 2850000, 2900000,
+	3000000, 3100000, 3200000, 3300000,
 };
 
-static const u16 LDO1_VSEL_table[] = {
-	1000, 1100, 1200, 1250,
-	1300, 1350, 1400, 1500,
-	1600, 1800, 2500, 2750,
-	2800, 3000, 3100, 3300,
+static const unsigned int LDO1_VSEL_table[] = {
+	1000000, 1100000, 1200000, 1250000,
+	1300000, 1350000, 1400000, 1500000,
+	1600000, 1800000, 2500000, 2750000,
+	2800000, 3000000, 3100000, 3300000,
 };
 
-static const u16 LDO2_VSEL_table[] = {
-	725, 750, 775, 800,
-	825, 850, 875, 900,
-	925, 950, 975, 1000,
-	1025, 1050, 1075, 1100,
-	1125, 1150, 1175, 1200,
-	1225, 1250, 1275, 1300,
-	1325, 1350, 1375, 1400,
-	1425, 1450, 1475, 1500,
-	1550, 1600, 1650, 1700,
-	1750, 1800, 1850, 1900,
-	1950, 2000, 2050, 2100,
-	2150, 2200, 2250, 2300,
-	2350, 2400, 2450, 2500,
-	2550, 2600, 2650, 2700,
-	2750, 2800, 2850, 2900,
-	3000, 3100, 3200, 3300,
-};
+/* The voltage mapping table for LDO2 is the same as VDCDCx */
+#define LDO2_VSEL_table VDCDCx_VSEL_table
 
 struct tps_info {
 	const char *name;
-	unsigned min_uV;
-	unsigned max_uV;
 	u8 table_len;
-	const u16 *table;
+	const unsigned int *table;
 
 	/* Does DCDC high or the low register defines output voltage? */
 	bool defdcdc_default;
@@ -103,36 +85,26 @@ struct tps_info {
 static struct tps_info tps6507x_pmic_regs[] = {
 	{
 		.name = "VDCDC1",
-		.min_uV = 725000,
-		.max_uV = 3300000,
 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
 		.table = VDCDCx_VSEL_table,
 	},
 	{
 		.name = "VDCDC2",
-		.min_uV = 725000,
-		.max_uV = 3300000,
 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
 		.table = VDCDCx_VSEL_table,
 	},
 	{
 		.name = "VDCDC3",
-		.min_uV = 725000,
-		.max_uV = 3300000,
 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
 		.table = VDCDCx_VSEL_table,
 	},
 	{
 		.name = "LDO1",
-		.min_uV = 1000000,
-		.max_uV = 3300000,
 		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
 		.table = LDO1_VSEL_table,
 	},
 	{
 		.name = "LDO2",
-		.min_uV = 725000,
-		.max_uV = 3300000,
 		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
 		.table = LDO2_VSEL_table,
 	},
@@ -375,28 +347,13 @@ static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev,
 	return tps6507x_pmic_reg_write(tps, reg, data);
 }
 
-static int tps6507x_pmic_list_voltage(struct regulator_dev *dev,
-					unsigned selector)
-{
-	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
-	int rid = rdev_get_id(dev);
-
-	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
-		return -EINVAL;
-
-	if (selector >= tps->info[rid]->table_len)
-		return -EINVAL;
-	else
-		return tps->info[rid]->table[selector] * 1000;
-}
-
 static struct regulator_ops tps6507x_pmic_ops = {
 	.is_enabled = tps6507x_pmic_is_enabled,
 	.enable = tps6507x_pmic_enable,
 	.disable = tps6507x_pmic_disable,
 	.get_voltage_sel = tps6507x_pmic_get_voltage_sel,
 	.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
-	.list_voltage = tps6507x_pmic_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 };
 
 static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
@@ -449,6 +406,7 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
 		tps->desc[i].name = info->name;
 		tps->desc[i].id = i;
 		tps->desc[i].n_voltages = info->table_len;
+		tps->desc[i].volt_table = info->table;
 		tps->desc[i].ops = &tps6507x_pmic_ops;
 		tps->desc[i].type = REGULATOR_VOLTAGE;
 		tps->desc[i].owner = THIS_MODULE;
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c
index 9d371d2..f5fa05b 100644
--- a/drivers/regulator/tps65217-regulator.c
+++ b/drivers/regulator/tps65217-regulator.c
@@ -26,7 +26,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/mfd/tps65217.h>
 
-#define TPS65217_REGULATOR(_name, _id, _ops, _n)	\
+#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em)	\
 	{						\
 		.name		= _name,		\
 		.id		= _id,			\
@@ -34,9 +34,13 @@
 		.n_voltages	= _n,			\
 		.type		= REGULATOR_VOLTAGE,	\
 		.owner		= THIS_MODULE,		\
+		.vsel_reg	= _vr,			\
+		.vsel_mask	= _vm,			\
+		.enable_reg	= TPS65217_REG_ENABLE,	\
+		.enable_mask	= _em,			\
 	}						\
 
-#define TPS65217_INFO(_nm, _min, _max, _f1, _f2, _t, _n, _em, _vr, _vm)	\
+#define TPS65217_INFO(_nm, _min, _max, _f1, _f2, _t, _n)\
 	{						\
 		.name		= _nm,			\
 		.min_uV		= _min,			\
@@ -45,9 +49,6 @@
 		.uv_to_vsel	= _f2,			\
 		.table		= _t,			\
 		.table_len	= _n,			\
-		.enable_mask	= _em,			\
-		.set_vout_reg	= _vr,			\
-		.set_vout_mask	= _vm,			\
 	}
 
 static const int LDO1_VSEL_table[] = {
@@ -127,46 +128,21 @@ static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel)
 
 static struct tps_info tps65217_pmic_regs[] = {
 	TPS65217_INFO("DCDC1", 900000, 1800000, tps65217_vsel_to_uv1,
-			tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC1_EN,
-			TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK),
+			tps65217_uv_to_vsel1, NULL, 64),
 	TPS65217_INFO("DCDC2", 900000, 3300000, tps65217_vsel_to_uv1,
-			tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC2_EN,
-			TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK),
+			tps65217_uv_to_vsel1, NULL, 64),
 	TPS65217_INFO("DCDC3", 900000, 1500000, tps65217_vsel_to_uv1,
-			tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC3_EN,
-			TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK),
+			tps65217_uv_to_vsel1, NULL, 64),
 	TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL, LDO1_VSEL_table,
-			16, TPS65217_ENABLE_LDO1_EN, TPS65217_REG_DEFLDO1,
-			TPS65217_DEFLDO1_LDO1_MASK),
+			16),
 	TPS65217_INFO("LDO2", 900000, 3300000, tps65217_vsel_to_uv1,
-			tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_LDO2_EN,
-			TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK),
+			tps65217_uv_to_vsel1, NULL, 64),
 	TPS65217_INFO("LDO3", 1800000, 3300000, tps65217_vsel_to_uv2,
-			tps65217_uv_to_vsel2, NULL, 32,
-			TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN,
-			TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK),
+			tps65217_uv_to_vsel2, NULL, 32),
 	TPS65217_INFO("LDO4", 1800000, 3300000, tps65217_vsel_to_uv2,
-			tps65217_uv_to_vsel2, NULL, 32,
-			TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN,
-			TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK),
+			tps65217_uv_to_vsel2, NULL, 32),
 };
 
-static int tps65217_pmic_is_enabled(struct regulator_dev *dev)
-{
-	int ret;
-	struct tps65217 *tps = rdev_get_drvdata(dev);
-	unsigned int data, rid = rdev_get_id(dev);
-
-	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
-		return -EINVAL;
-
-	ret = tps65217_reg_read(tps, TPS65217_REG_ENABLE, &data);
-	if (ret)
-		return ret;
-
-	return (data & tps->info[rid]->enable_mask) ? 1 : 0;
-}
-
 static int tps65217_pmic_enable(struct regulator_dev *dev)
 {
 	struct tps65217 *tps = rdev_get_drvdata(dev);
@@ -177,9 +153,8 @@ static int tps65217_pmic_enable(struct regulator_dev *dev)
 
 	/* Enable the regulator and password protection is level 1 */
 	return tps65217_set_bits(tps, TPS65217_REG_ENABLE,
-				tps->info[rid]->enable_mask,
-				tps->info[rid]->enable_mask,
-				TPS65217_PROTECT_L1);
+				 dev->desc->enable_mask, dev->desc->enable_mask,
+				 TPS65217_PROTECT_L1);
 }
 
 static int tps65217_pmic_disable(struct regulator_dev *dev)
@@ -192,25 +167,7 @@ static int tps65217_pmic_disable(struct regulator_dev *dev)
 
 	/* Disable the regulator and password protection is level 1 */
 	return tps65217_clear_bits(tps, TPS65217_REG_ENABLE,
-			tps->info[rid]->enable_mask, TPS65217_PROTECT_L1);
-}
-
-static int tps65217_pmic_get_voltage_sel(struct regulator_dev *dev)
-{
-	int ret;
-	struct tps65217 *tps = rdev_get_drvdata(dev);
-	unsigned int selector, rid = rdev_get_id(dev);
-
-	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
-		return -EINVAL;
-
-	ret = tps65217_reg_read(tps, tps->info[rid]->set_vout_reg, &selector);
-	if (ret)
-		return ret;
-
-	selector &= tps->info[rid]->set_vout_mask;
-
-	return selector;
+				   dev->desc->enable_mask, TPS65217_PROTECT_L1);
 }
 
 static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev,
@@ -221,8 +178,7 @@ static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev,
 	unsigned int rid = rdev_get_id(dev);
 
 	/* Set the voltage based on vsel value and write protect level is 2 */
-	ret = tps65217_set_bits(tps, tps->info[rid]->set_vout_reg,
-				tps->info[rid]->set_vout_mask,
+	ret = tps65217_set_bits(tps, dev->desc->vsel_reg, dev->desc->vsel_mask,
 				selector, TPS65217_PROTECT_L2);
 
 	/* Set GO bit for DCDCx to initiate voltage transistion */
@@ -285,10 +241,10 @@ static int tps65217_pmic_list_voltage(struct regulator_dev *dev,
 
 /* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */
 static struct regulator_ops tps65217_pmic_ops = {
-	.is_enabled		= tps65217_pmic_is_enabled,
+	.is_enabled		= regulator_is_enabled_regmap,
 	.enable			= tps65217_pmic_enable,
 	.disable		= tps65217_pmic_disable,
-	.get_voltage_sel	= tps65217_pmic_get_voltage_sel,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
 	.set_voltage_sel	= tps65217_pmic_set_voltage_sel,
 	.list_voltage		= tps65217_pmic_list_voltage,
 	.map_voltage		= tps65217_pmic_map_voltage,
@@ -296,22 +252,36 @@ static struct regulator_ops tps65217_pmic_ops = {
 
 /* Operations permitted on LDO1 */
 static struct regulator_ops tps65217_pmic_ldo1_ops = {
-	.is_enabled		= tps65217_pmic_is_enabled,
+	.is_enabled		= regulator_is_enabled_regmap,
 	.enable			= tps65217_pmic_enable,
 	.disable		= tps65217_pmic_disable,
-	.get_voltage_sel	= tps65217_pmic_get_voltage_sel,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
 	.set_voltage_sel	= tps65217_pmic_set_voltage_sel,
 	.list_voltage		= tps65217_pmic_list_voltage,
 };
 
 static const struct regulator_desc regulators[] = {
-	TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64),
-	TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64),
-	TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64),
-	TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16),
-	TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64),
-	TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32),
-	TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32),
+	TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64,
+			   TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK,
+			   TPS65217_ENABLE_DC1_EN),
+	TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64,
+			   TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK,
+			   TPS65217_ENABLE_DC2_EN),
+	TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64,
+			   TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK,
+			   TPS65217_ENABLE_DC3_EN),
+	TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16,
+			   TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK,
+			   TPS65217_ENABLE_LDO1_EN),
+	TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64,
+			   TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK,
+			   TPS65217_ENABLE_LDO2_EN),
+	TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32,
+			   TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK,
+			   TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN),
+	TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32,
+			   TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK,
+			   TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN),
 };
 
 static int __devinit tps65217_regulator_probe(struct platform_device *pdev)
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index b88b3df..1b299aa 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -482,7 +482,7 @@ static int get_voltage_sel(struct regulator_dev *rdev)
 	info	= &supply_info[rdev_get_id(rdev)];
 
 	if (info->flags & FIXED_VOLTAGE)
-		return info->fixed_voltage;
+		return 0;
 
 	ret = read_field(hw, &info->voltage);
 	if (ret < 0)
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index c0a2145..c0ac241 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -63,8 +63,6 @@ struct tps6586x_regulator {
 	int enable_bit[2];
 	int enable_reg[2];
 
-	int *voltages;
-
 	/* for DVM regulators */
 	int go_reg;
 	int go_bit;
@@ -75,19 +73,6 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
 	return rdev_get_dev(rdev)->parent->parent;
 }
 
-static int tps6586x_list_voltage(struct regulator_dev *rdev, unsigned selector)
-{
-	struct tps6586x_regulator *info = rdev_get_drvdata(rdev);
-	int rid = rdev_get_id(rdev);
-
-	/* LDO0 has minimal voltage 1.2V rather than 1.25V */
-	if ((rid == TPS6586X_ID_LDO_0) && (selector == 0))
-		return (info->voltages[0] - 50) * 1000;
-
-	return info->voltages[selector] * 1000;
-}
-
-
 static int tps6586x_set_voltage_sel(struct regulator_dev *rdev,
 				    unsigned selector)
 {
@@ -168,7 +153,7 @@ static int tps6586x_regulator_is_enabled(struct regulator_dev *rdev)
 }
 
 static struct regulator_ops tps6586x_regulator_ops = {
-	.list_voltage = tps6586x_list_voltage,
+	.list_voltage = regulator_list_voltage_table,
 	.get_voltage_sel = tps6586x_get_voltage_sel,
 	.set_voltage_sel = tps6586x_set_voltage_sel,
 
@@ -177,29 +162,33 @@ static struct regulator_ops tps6586x_regulator_ops = {
 	.disable = tps6586x_regulator_disable,
 };
 
-static int tps6586x_ldo_voltages[] = {
-	1250, 1500, 1800, 2500, 2700, 2850, 3100, 3300,
+static const unsigned int tps6586x_ldo0_voltages[] = {
+	1200000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000,
+};
+
+static const unsigned int tps6586x_ldo4_voltages[] = {
+	1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000,
+	1900000, 1925000, 1950000, 1975000, 2000000, 2025000, 2050000, 2075000,
+	2100000, 2125000, 2150000, 2175000, 2200000, 2225000, 2250000, 2275000,
+	2300000, 2325000, 2350000, 2375000, 2400000, 2425000, 2450000, 2475000,
 };
 
-static int tps6586x_ldo4_voltages[] = {
-	1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875,
-	1900, 1925, 1950, 1975, 2000, 2025, 2050, 2075,
-	2100, 2125, 2150, 2175, 2200, 2225, 2250, 2275,
-	2300, 2325, 2350, 2375, 2400, 2425, 2450, 2475,
+static const unsigned int tps6586x_ldo_voltages[] = {
+	1250000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000,
 };
 
-static int tps6586x_sm2_voltages[] = {
-	3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350,
-	3400, 3450, 3500, 3550, 3600, 3650, 3700, 3750,
-	3800, 3850, 3900, 3950, 4000, 4050, 4100, 4150,
-	4200, 4250, 4300, 4350, 4400, 4450, 4500, 4550,
+static const unsigned int tps6586x_sm2_voltages[] = {
+	3000000, 3050000, 3100000, 3150000, 3200000, 3250000, 3300000, 3350000,
+	3400000, 3450000, 3500000, 3550000, 3600000, 3650000, 3700000, 3750000,
+	3800000, 3850000, 3900000, 3950000, 4000000, 4050000, 4100000, 4150000,
+	4200000, 4250000, 4300000, 4350000, 4400000, 4450000, 4500000, 4550000,
 };
 
-static int tps6586x_dvm_voltages[] = {
-	 725,  750,  775,  800,  825,  850,  875,  900,
-	 925,  950,  975, 1000, 1025, 1050, 1075, 1100,
-	1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
-	1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+static const unsigned int tps6586x_dvm_voltages[] = {
+	 725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
+	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
+	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
+	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
 };
 
 #define TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits,		\
@@ -210,6 +199,7 @@ static int tps6586x_dvm_voltages[] = {
 		.type	= REGULATOR_VOLTAGE,				\
 		.id	= TPS6586X_ID_##_id,				\
 		.n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages),	\
+		.volt_table = tps6586x_##vdata##_voltages,		\
 		.owner	= THIS_MODULE,					\
 	},								\
 	.volt_reg	= TPS6586X_##vreg,				\
@@ -218,8 +208,7 @@ static int tps6586x_dvm_voltages[] = {
 	.enable_reg[0]	= TPS6586X_SUPPLY##ereg0,			\
 	.enable_bit[0]	= (ebit0),					\
 	.enable_reg[1]	= TPS6586X_SUPPLY##ereg1,			\
-	.enable_bit[1]	= (ebit1),					\
-	.voltages	= tps6586x_##vdata##_voltages,
+	.enable_bit[1]	= (ebit1),
 
 #define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit)			\
 	.go_reg = TPS6586X_##goreg,					\
@@ -241,7 +230,7 @@ static int tps6586x_dvm_voltages[] = {
 }
 
 static struct tps6586x_regulator tps6586x_regulator[] = {
-	TPS6586X_LDO(LDO_0, ldo, SUPPLYV1, 5, 3, ENC, 0, END, 0),
+	TPS6586X_LDO(LDO_0, ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0),
 	TPS6586X_LDO(LDO_3, ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2),
 	TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
 	TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 6bf864b..66da87c 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -31,64 +31,62 @@
 			TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 |		\
 			TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
 
-/* supported VIO voltages in millivolts */
-static const u16 VIO_VSEL_table[] = {
-	1500, 1800, 2500, 3300,
+/* supported VIO voltages in microvolts */
+static const unsigned int VIO_VSEL_table[] = {
+	1500000, 1800000, 2500000, 3300000,
 };
 
 /* VSEL tables for TPS65910 specific LDOs and dcdc's */
 
-/* supported VDD3 voltages in millivolts */
-static const u16 VDD3_VSEL_table[] = {
-	5000,
+/* supported VDD3 voltages in microvolts */
+static const unsigned int VDD3_VSEL_table[] = {
+	5000000,
 };
 
-/* supported VDIG1 voltages in millivolts */
-static const u16 VDIG1_VSEL_table[] = {
-	1200, 1500, 1800, 2700,
+/* supported VDIG1 voltages in microvolts */
+static const unsigned int VDIG1_VSEL_table[] = {
+	1200000, 1500000, 1800000, 2700000,
 };
 
-/* supported VDIG2 voltages in millivolts */
-static const u16 VDIG2_VSEL_table[] = {
-	1000, 1100, 1200, 1800,
+/* supported VDIG2 voltages in microvolts */
+static const unsigned int VDIG2_VSEL_table[] = {
+	1000000, 1100000, 1200000, 1800000,
 };
 
-/* supported VPLL voltages in millivolts */
-static const u16 VPLL_VSEL_table[] = {
-	1000, 1100, 1800, 2500,
+/* supported VPLL voltages in microvolts */
+static const unsigned int VPLL_VSEL_table[] = {
+	1000000, 1100000, 1800000, 2500000,
 };
 
-/* supported VDAC voltages in millivolts */
-static const u16 VDAC_VSEL_table[] = {
-	1800, 2600, 2800, 2850,
+/* supported VDAC voltages in microvolts */
+static const unsigned int VDAC_VSEL_table[] = {
+	1800000, 2600000, 2800000, 2850000,
 };
 
-/* supported VAUX1 voltages in millivolts */
-static const u16 VAUX1_VSEL_table[] = {
-	1800, 2500, 2800, 2850,
+/* supported VAUX1 voltages in microvolts */
+static const unsigned int VAUX1_VSEL_table[] = {
+	1800000, 2500000, 2800000, 2850000,
 };
 
-/* supported VAUX2 voltages in millivolts */
-static const u16 VAUX2_VSEL_table[] = {
-	1800, 2800, 2900, 3300,
+/* supported VAUX2 voltages in microvolts */
+static const unsigned int VAUX2_VSEL_table[] = {
+	1800000, 2800000, 2900000, 3300000,
 };
 
-/* supported VAUX33 voltages in millivolts */
-static const u16 VAUX33_VSEL_table[] = {
-	1800, 2000, 2800, 3300,
+/* supported VAUX33 voltages in microvolts */
+static const unsigned int VAUX33_VSEL_table[] = {
+	1800000, 2000000, 2800000, 3300000,
 };
 
-/* supported VMMC voltages in millivolts */
-static const u16 VMMC_VSEL_table[] = {
-	1800, 2800, 3000, 3300,
+/* supported VMMC voltages in microvolts */
+static const unsigned int VMMC_VSEL_table[] = {
+	1800000, 2800000, 3000000, 3300000,
 };
 
 struct tps_info {
 	const char *name;
-	unsigned min_uV;
-	unsigned max_uV;
 	u8 n_voltages;
-	const u16 *voltage_table;
+	const unsigned int *voltage_table;
 	int enable_time_us;
 };
 
@@ -99,92 +97,68 @@ static struct tps_info tps65910_regs[] = {
 	},
 	{
 		.name = "vio",
-		.min_uV = 1500000,
-		.max_uV = 3300000,
 		.n_voltages = ARRAY_SIZE(VIO_VSEL_table),
 		.voltage_table = VIO_VSEL_table,
 		.enable_time_us = 350,
 	},
 	{
 		.name = "vdd1",
-		.min_uV = 600000,
-		.max_uV = 4500000,
 		.enable_time_us = 350,
 	},
 	{
 		.name = "vdd2",
-		.min_uV = 600000,
-		.max_uV = 4500000,
 		.enable_time_us = 350,
 	},
 	{
 		.name = "vdd3",
-		.min_uV = 5000000,
-		.max_uV = 5000000,
 		.n_voltages = ARRAY_SIZE(VDD3_VSEL_table),
 		.voltage_table = VDD3_VSEL_table,
 		.enable_time_us = 200,
 	},
 	{
 		.name = "vdig1",
-		.min_uV = 1200000,
-		.max_uV = 2700000,
 		.n_voltages = ARRAY_SIZE(VDIG1_VSEL_table),
 		.voltage_table = VDIG1_VSEL_table,
 		.enable_time_us = 100,
 	},
 	{
 		.name = "vdig2",
-		.min_uV = 1000000,
-		.max_uV = 1800000,
 		.n_voltages = ARRAY_SIZE(VDIG2_VSEL_table),
 		.voltage_table = VDIG2_VSEL_table,
 		.enable_time_us = 100,
 	},
 	{
 		.name = "vpll",
-		.min_uV = 1000000,
-		.max_uV = 2500000,
 		.n_voltages = ARRAY_SIZE(VPLL_VSEL_table),
 		.voltage_table = VPLL_VSEL_table,
 		.enable_time_us = 100,
 	},
 	{
 		.name = "vdac",
-		.min_uV = 1800000,
-		.max_uV = 2850000,
 		.n_voltages = ARRAY_SIZE(VDAC_VSEL_table),
 		.voltage_table = VDAC_VSEL_table,
 		.enable_time_us = 100,
 	},
 	{
 		.name = "vaux1",
-		.min_uV = 1800000,
-		.max_uV = 2850000,
 		.n_voltages = ARRAY_SIZE(VAUX1_VSEL_table),
 		.voltage_table = VAUX1_VSEL_table,
 		.enable_time_us = 100,
 	},
 	{
 		.name = "vaux2",
-		.min_uV = 1800000,
-		.max_uV = 3300000,
 		.n_voltages = ARRAY_SIZE(VAUX2_VSEL_table),
 		.voltage_table = VAUX2_VSEL_table,
 		.enable_time_us = 100,
 	},
 	{
 		.name = "vaux33",
-		.min_uV = 1800000,
-		.max_uV = 3300000,
 		.n_voltages = ARRAY_SIZE(VAUX33_VSEL_table),
 		.voltage_table = VAUX33_VSEL_table,
 		.enable_time_us = 100,
 	},
 	{
 		.name = "vmmc",
-		.min_uV = 1800000,
-		.max_uV = 3300000,
 		.n_voltages = ARRAY_SIZE(VMMC_VSEL_table),
 		.voltage_table = VMMC_VSEL_table,
 		.enable_time_us = 100,
@@ -198,86 +172,62 @@ static struct tps_info tps65911_regs[] = {
 	},
 	{
 		.name = "vio",
-		.min_uV = 1500000,
-		.max_uV = 3300000,
 		.n_voltages = ARRAY_SIZE(VIO_VSEL_table),
 		.voltage_table = VIO_VSEL_table,
 		.enable_time_us = 350,
 	},
 	{
 		.name = "vdd1",
-		.min_uV = 600000,
-		.max_uV = 4500000,
 		.n_voltages = 73,
 		.enable_time_us = 350,
 	},
 	{
 		.name = "vdd2",
-		.min_uV = 600000,
-		.max_uV = 4500000,
 		.n_voltages = 73,
 		.enable_time_us = 350,
 	},
 	{
 		.name = "vddctrl",
-		.min_uV = 600000,
-		.max_uV = 1400000,
 		.n_voltages = 65,
 		.enable_time_us = 900,
 	},
 	{
 		.name = "ldo1",
-		.min_uV = 1000000,
-		.max_uV = 3300000,
 		.n_voltages = 47,
 		.enable_time_us = 420,
 	},
 	{
 		.name = "ldo2",
-		.min_uV = 1000000,
-		.max_uV = 3300000,
 		.n_voltages = 47,
 		.enable_time_us = 420,
 	},
 	{
 		.name = "ldo3",
-		.min_uV = 1000000,
-		.max_uV = 3300000,
 		.n_voltages = 24,
 		.enable_time_us = 230,
 	},
 	{
 		.name = "ldo4",
-		.min_uV = 1000000,
-		.max_uV = 3300000,
 		.n_voltages = 47,
 		.enable_time_us = 230,
 	},
 	{
 		.name = "ldo5",
-		.min_uV = 1000000,
-		.max_uV = 3300000,
 		.n_voltages = 24,
 		.enable_time_us = 230,
 	},
 	{
 		.name = "ldo6",
-		.min_uV = 1000000,
-		.max_uV = 3300000,
 		.n_voltages = 24,
 		.enable_time_us = 230,
 	},
 	{
 		.name = "ldo7",
-		.min_uV = 1000000,
-		.max_uV = 3300000,
 		.n_voltages = 24,
 		.enable_time_us = 230,
 	},
 	{
 		.name = "ldo8",
-		.min_uV = 1000000,
-		.max_uV = 3300000,
 		.n_voltages = 24,
 		.enable_time_us = 230,
 	},
@@ -609,7 +559,7 @@ static int tps65910_get_voltage_sel(struct regulator_dev *dev)
 
 static int tps65910_get_voltage_vdd3(struct regulator_dev *dev)
 {
-	return 5 * 1000 * 1000;
+	return dev->desc->volt_table[0];
 }
 
 static int tps65911_get_voltage_sel(struct regulator_dev *dev)
@@ -768,23 +718,6 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,
 	return  volt * 100 * mult;
 }
 
-static int tps65910_list_voltage(struct regulator_dev *dev,
-					unsigned selector)
-{
-	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
-	int id = rdev_get_id(dev), voltage;
-
-	if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC)
-		return -EINVAL;
-
-	if (selector >= pmic->info[id]->n_voltages)
-		return -EINVAL;
-	else
-		voltage = pmic->info[id]->voltage_table[selector] * 1000;
-
-	return voltage;
-}
-
 static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
 {
 	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
@@ -816,7 +749,7 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
 		step_mv = 100;
 		break;
 	case TPS65910_REG_VIO:
-		return pmic->info[id]->voltage_table[selector] * 1000;
+		return pmic->info[id]->voltage_table[selector];
 	default:
 		return -EINVAL;
 	}
@@ -824,31 +757,6 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
 	return (LDO_MIN_VOLT + selector * step_mv) * 1000;
 }
 
-static int tps65910_set_voltage_dcdc_time_sel(struct regulator_dev *dev,
-		unsigned int old_selector, unsigned int new_selector)
-{
-	int id = rdev_get_id(dev);
-	int old_volt, new_volt;
-
-	old_volt = tps65910_list_voltage_dcdc(dev, old_selector);
-	if (old_volt < 0)
-		return old_volt;
-
-	new_volt = tps65910_list_voltage_dcdc(dev, new_selector);
-	if (new_volt < 0)
-		return new_volt;
-
-	/* VDD1 and VDD2 are 12.5mV/us, VDDCTRL is 100mV/20us */
-	switch (id) {
-	case TPS65910_REG_VDD1:
-	case TPS65910_REG_VDD2:
-		return DIV_ROUND_UP(abs(old_volt - new_volt), 12500);
-	case TPS65911_REG_VDDCTRL:
-		return DIV_ROUND_UP(abs(old_volt - new_volt), 5000);
-	}
-	return -EINVAL;
-}
-
 /* Regulator ops (except VRTC) */
 static struct regulator_ops tps65910_ops_dcdc = {
 	.is_enabled		= regulator_is_enabled_regmap,
@@ -859,7 +767,7 @@ static struct regulator_ops tps65910_ops_dcdc = {
 	.get_mode		= tps65910_get_mode,
 	.get_voltage_sel	= tps65910_get_voltage_dcdc_sel,
 	.set_voltage_sel	= tps65910_set_voltage_dcdc_sel,
-	.set_voltage_time_sel	= tps65910_set_voltage_dcdc_time_sel,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
 	.list_voltage		= tps65910_list_voltage_dcdc,
 };
 
@@ -871,7 +779,7 @@ static struct regulator_ops tps65910_ops_vdd3 = {
 	.set_mode		= tps65910_set_mode,
 	.get_mode		= tps65910_get_mode,
 	.get_voltage		= tps65910_get_voltage_vdd3,
-	.list_voltage		= tps65910_list_voltage,
+	.list_voltage		= regulator_list_voltage_table,
 };
 
 static struct regulator_ops tps65910_ops = {
@@ -883,7 +791,7 @@ static struct regulator_ops tps65910_ops = {
 	.get_mode		= tps65910_get_mode,
 	.get_voltage_sel	= tps65910_get_voltage_sel,
 	.set_voltage_sel	= tps65910_set_voltage_sel,
-	.list_voltage		= tps65910_list_voltage,
+	.list_voltage		= regulator_list_voltage_table,
 };
 
 static struct regulator_ops tps65911_ops = {
@@ -1136,7 +1044,7 @@ static inline struct tps65910_board *tps65910_parse_dt_reg_data(
 			struct of_regulator_match **tps65910_reg_matches)
 {
 	*tps65910_reg_matches = NULL;
-	return 0;
+	return NULL;
 }
 #endif
 
@@ -1236,16 +1144,22 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
 			pmic->desc[i].ops = &tps65910_ops_dcdc;
 			pmic->desc[i].n_voltages = VDD1_2_NUM_VOLT_FINE *
 							VDD1_2_NUM_VOLT_COARSE;
+			pmic->desc[i].ramp_delay = 12500;
 		} else if (i == TPS65910_REG_VDD3) {
-			if (tps65910_chip_id(tps65910) == TPS65910)
+			if (tps65910_chip_id(tps65910) == TPS65910) {
 				pmic->desc[i].ops = &tps65910_ops_vdd3;
-			else
+				pmic->desc[i].volt_table = info->voltage_table;
+			} else {
 				pmic->desc[i].ops = &tps65910_ops_dcdc;
+				pmic->desc[i].ramp_delay = 5000;
+			}
 		} else {
-			if (tps65910_chip_id(tps65910) == TPS65910)
+			if (tps65910_chip_id(tps65910) == TPS65910) {
 				pmic->desc[i].ops = &tps65910_ops;
-			else
+				pmic->desc[i].volt_table = info->voltage_table;
+			} else {
 				pmic->desc[i].ops = &tps65911_ops;
+			}
 		}
 
 		err = tps65910_set_ext_sleep_config(pmic, i,
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index c739071..ca308cb 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -577,13 +577,6 @@ static struct regulator_ops twl6030coresmps_ops = {
 	.get_voltage	= twl6030coresmps_get_voltage,
 };
 
-static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
-{
-	struct twlreg_info	*info = rdev_get_drvdata(rdev);
-
-	return ((info->min_mV + (index * 100)) * 1000);
-}
-
 static int
 twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
 		       unsigned *selector)
@@ -621,7 +614,7 @@ static int twl6030ldo_get_voltage(struct regulator_dev *rdev)
 }
 
 static struct regulator_ops twl6030ldo_ops = {
-	.list_voltage	= twl6030ldo_list_voltage,
+	.list_voltage	= regulator_list_voltage_linear,
 
 	.set_voltage	= twl6030ldo_set_voltage,
 	.get_voltage	= twl6030ldo_get_voltage,
@@ -959,6 +952,8 @@ static struct twlreg_info TWL6030_INFO_##label = { \
 		.ops = &twl6030ldo_ops, \
 		.type = REGULATOR_VOLTAGE, \
 		.owner = THIS_MODULE, \
+		.min_uV = min_mVolts * 1000, \
+		.uV_step = 100 * 1000, \
 		}, \
 	}
 
@@ -974,6 +969,8 @@ static struct twlreg_info TWL6025_INFO_##label = { \
 		.ops = &twl6030ldo_ops, \
 		.type = REGULATOR_VOLTAGE, \
 		.owner = THIS_MODULE, \
+		.min_uV = min_mVolts * 1000, \
+		.uV_step = 100 * 1000, \
 		}, \
 	}
 
@@ -1109,7 +1106,6 @@ static u8 twl_get_smps_mult(void)
 #define TWL6030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6030, label)
 #define TWL6025_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6025, label)
 #define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label)
-#define TWLRES_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLRES, label)
 #define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label)
 
 static const struct of_device_id twl_of_match[] __devinitconst = {
@@ -1157,7 +1153,6 @@ static const struct of_device_id twl_of_match[] __devinitconst = {
 	TWLFIXED_OF_MATCH("ti,twl6030-vusb", VUSB),
 	TWLFIXED_OF_MATCH("ti,twl6030-v1v8", V1V8),
 	TWLFIXED_OF_MATCH("ti,twl6030-v2v1", V2V1),
-	TWLRES_OF_MATCH("ti,twl6030-clk32kg", CLK32KG),
 	TWLSMPS_OF_MATCH("ti,twl6025-smps3", SMPS3),
 	TWLSMPS_OF_MATCH("ti,twl6025-smps4", SMPS4),
 	TWLSMPS_OF_MATCH("ti,twl6025-vio", VIO),
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 099da11..7413885 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -215,8 +215,8 @@ static int wm831x_buckv_list_voltage(struct regulator_dev *rdev,
 	return -EINVAL;
 }
 
-static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev,
-					   int min_uV, int max_uV)
+static int wm831x_buckv_map_voltage(struct regulator_dev *rdev,
+				   int min_uV, int max_uV)
 {
 	u16 vsel;
 
@@ -251,20 +251,14 @@ static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
 	return 0;
 }
 
-static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,
-				    int min_uV, int max_uV, unsigned *selector)
+static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev,
+					unsigned vsel)
 {
 	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
 	struct wm831x *wm831x = dcdc->wm831x;
 	int on_reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
 	int dvs_reg = dcdc->base + WM831X_DCDC_DVS_CONTROL;
-	int vsel, ret;
-
-	vsel = wm831x_buckv_select_min_voltage(rdev, min_uV, max_uV);
-	if (vsel < 0)
-		return vsel;
-
-	*selector = vsel;
+	int ret;
 
 	/* If this value is already set then do a GPIO update if we can */
 	if (dcdc->dvs_gpio && dcdc->on_vsel == vsel)
@@ -315,7 +309,7 @@ static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev,
 	u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
 	int vsel;
 
-	vsel = wm831x_buckv_select_min_voltage(rdev, uV, uV);
+	vsel = wm831x_buckv_map_voltage(rdev, uV, uV);
 	if (vsel < 0)
 		return vsel;
 
@@ -373,9 +367,10 @@ static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev)
 }
 
 static struct regulator_ops wm831x_buckv_ops = {
-	.set_voltage = wm831x_buckv_set_voltage,
+	.set_voltage_sel = wm831x_buckv_set_voltage_sel,
 	.get_voltage_sel = wm831x_buckv_get_voltage_sel,
 	.list_voltage = wm831x_buckv_list_voltage,
+	.map_voltage = wm831x_buckv_map_voltage,
 	.set_suspend_voltage = wm831x_buckv_set_suspend_voltage,
 	.set_current_limit = wm831x_buckv_set_current_limit,
 	.get_current_limit = wm831x_buckv_get_current_limit,
@@ -599,60 +594,25 @@ static struct platform_driver wm831x_buckv_driver = {
  * BUCKP specifics
  */
 
-static int wm831x_buckp_list_voltage(struct regulator_dev *rdev,
-				      unsigned selector)
-{
-	if (selector <= WM831X_BUCKP_MAX_SELECTOR)
-		return 850000 + (selector * 25000);
-	else
-		return -EINVAL;
-}
-
-static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg,
-					int min_uV, int max_uV, int *selector)
+static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 {
 	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
 	struct wm831x *wm831x = dcdc->wm831x;
-	u16 vsel;
-
-	if (min_uV <= 34000000)
-		vsel = (min_uV - 850000) / 25000;
-	else
-		return -EINVAL;
-
-	if (wm831x_buckp_list_voltage(rdev, vsel) > max_uV)
-		return -EINVAL;
-
-	*selector = vsel;
-
-	return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_buckp_set_voltage(struct regulator_dev *rdev,
-				    int min_uV, int max_uV,
-				    unsigned *selector)
-{
-	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
-	u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
-
-	return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV,
-					    selector);
-}
-
-static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev,
-					    int uV)
-{
-	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
 	u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
-	unsigned selector;
+	int sel;
+
+	sel = regulator_map_voltage_linear(rdev, uV, uV);
+	if (sel < 0)
+		return sel;
 
-	return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector);
+	return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, sel);
 }
 
 static struct regulator_ops wm831x_buckp_ops = {
-	.set_voltage = wm831x_buckp_set_voltage,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.list_voltage = wm831x_buckp_list_voltage,
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
 	.set_suspend_voltage = wm831x_buckp_set_suspend_voltage,
 
 	.is_enabled = regulator_is_enabled_regmap,
@@ -715,6 +675,8 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev)
 	dcdc->desc.vsel_mask = WM831X_DC3_ON_VSEL_MASK;
 	dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
 	dcdc->desc.enable_mask = 1 << id;
+	dcdc->desc.min_uV = 850000;
+	dcdc->desc.uV_step = 25000;
 
 	config.dev = pdev->dev.parent;
 	if (pdata)
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index a9a28d8..04d8a41 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -78,13 +78,10 @@ static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev,
 	return -EINVAL;
 }
 
-static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg,
-					 int min_uV, int max_uV,
-					 unsigned *selector)
+static int wm831x_gp_ldo_map_voltage(struct regulator_dev *rdev,
+				     int min_uV, int max_uV)
 {
-	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-	struct wm831x *wm831x = ldo->wm831x;
-	int vsel, ret;
+	int volt, vsel;
 
 	if (min_uV < 900000)
 		vsel = 0;
@@ -94,36 +91,25 @@ static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg,
 		vsel = ((min_uV - 1700000) / 100000)
 			+ WM831X_GP_LDO_SELECTOR_LOW + 1;
 
-	ret = wm831x_gp_ldo_list_voltage(rdev, vsel);
-	if (ret < 0)
-		return ret;
-	if (ret < min_uV || ret > max_uV)
+	volt = wm831x_gp_ldo_list_voltage(rdev, vsel);
+	if (volt < min_uV || volt > max_uV)
 		return -EINVAL;
 
-	*selector = vsel;
-
-	return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_gp_ldo_set_voltage(struct regulator_dev *rdev,
-				     int min_uV, int max_uV,
-				     unsigned *selector)
-{
-	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-	int reg = ldo->base + WM831X_LDO_ON_CONTROL;
-
-	return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV,
-					     selector);
+	return vsel;
 }
 
 static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
 					     int uV)
 {
 	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-	int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
-	unsigned int selector;
+	struct wm831x *wm831x = ldo->wm831x;
+	int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
 
-	return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+	sel = wm831x_gp_ldo_map_voltage(rdev, uV, uV);
+	if (sel < 0)
+		return sel;
+
+	return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, sel);
 }
 
 static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev)
@@ -243,8 +229,9 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
 
 static struct regulator_ops wm831x_gp_ldo_ops = {
 	.list_voltage = wm831x_gp_ldo_list_voltage,
+	.map_voltage = wm831x_gp_ldo_map_voltage,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.set_voltage = wm831x_gp_ldo_set_voltage,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
 	.get_mode = wm831x_gp_ldo_get_mode,
 	.set_mode = wm831x_gp_ldo_set_mode,
@@ -384,13 +371,10 @@ static int wm831x_aldo_list_voltage(struct regulator_dev *rdev,
 	return -EINVAL;
 }
 
-static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg,
-				       int min_uV, int max_uV,
-				       unsigned *selector)
+static int wm831x_aldo_map_voltage(struct regulator_dev *rdev,
+				   int min_uV, int max_uV)
 {
-	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-	struct wm831x *wm831x = ldo->wm831x;
-	int vsel, ret;
+	int volt, vsel;
 
 	if (min_uV < 1000000)
 		vsel = 0;
@@ -400,35 +384,26 @@ static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg,
 		vsel = ((min_uV - 1700000) / 100000)
 			+ WM831X_ALDO_SELECTOR_LOW + 1;
 
-	ret = wm831x_aldo_list_voltage(rdev, vsel);
-	if (ret < 0)
-		return ret;
-	if (ret < min_uV || ret > max_uV)
+	volt = wm831x_aldo_list_voltage(rdev, vsel);
+	if (volt < min_uV || volt > max_uV)
 		return -EINVAL;
 
-	*selector = vsel;
-
-	return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_aldo_set_voltage(struct regulator_dev *rdev,
-				   int min_uV, int max_uV, unsigned *selector)
-{
-	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-	int reg = ldo->base + WM831X_LDO_ON_CONTROL;
+	return vsel;
 
-	return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV,
-					   selector);
 }
 
 static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
 					     int uV)
 {
 	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-	int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
-	unsigned int selector;
+	struct wm831x *wm831x = ldo->wm831x;
+	int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
+
+	sel = wm831x_aldo_map_voltage(rdev, uV, uV);
+	if (sel < 0)
+		return sel;
 
-	return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+	return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, sel);
 }
 
 static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
@@ -506,8 +481,9 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev)
 
 static struct regulator_ops wm831x_aldo_ops = {
 	.list_voltage = wm831x_aldo_list_voltage,
+	.map_voltage = wm831x_aldo_map_voltage,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.set_voltage = wm831x_aldo_set_voltage,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
 	.get_mode = wm831x_aldo_get_mode,
 	.set_mode = wm831x_aldo_set_mode,
@@ -628,47 +604,18 @@ static struct platform_driver wm831x_aldo_driver = {
 
 #define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf
 
-static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev,
-					    int reg,
-					    int min_uV, int max_uV,
-					    unsigned *selector)
-{
-	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-	struct wm831x *wm831x = ldo->wm831x;
-	int vsel, ret;
-
-	vsel = (min_uV - 800000) / 50000;
-
-	ret = regulator_list_voltage_linear(rdev, vsel);
-	if (ret < 0)
-		return ret;
-	if (ret < min_uV || ret > max_uV)
-		return -EINVAL;
-
-	*selector = vsel;
-
-	return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_alive_ldo_set_voltage(struct regulator_dev *rdev,
-					int min_uV, int max_uV,
-					unsigned *selector)
-{
-	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-	int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
-
-	return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV,
-						selector);
-}
-
 static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev,
 					     int uV)
 {
 	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-	int reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
-	unsigned selector;
+	struct wm831x *wm831x = ldo->wm831x;
+	int sel, reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
+
+	sel = regulator_map_voltage_linear(rdev, uV, uV);
+	if (sel < 0)
+		return sel;
 
-	return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+	return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, sel);
 }
 
 static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
@@ -690,8 +637,9 @@ static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
 
 static struct regulator_ops wm831x_alive_ldo_ops = {
 	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.set_voltage = wm831x_alive_ldo_set_voltage,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage,
 	.get_status = wm831x_alive_ldo_get_status,
 
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 94e550d..7f0fa22 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -108,33 +108,6 @@ static int get_isink_val(int min_uA, int max_uA, u16 *setting)
 	return -EINVAL;
 }
 
-static inline int wm8350_ldo_val_to_mvolts(unsigned int val)
-{
-	if (val < 16)
-		return (val * 50) + 900;
-	else
-		return ((val - 16) * 100) + 1800;
-
-}
-
-static inline unsigned int wm8350_ldo_mvolts_to_val(int mV)
-{
-	if (mV < 1800)
-		return (mV - 900) / 50;
-	else
-		return ((mV - 1800) / 100) + 16;
-}
-
-static inline int wm8350_dcdc_val_to_mvolts(unsigned int val)
-{
-	return (val * 25) + 850;
-}
-
-static inline unsigned int wm8350_dcdc_mvolts_to_val(int mV)
-{
-	return (mV - 850) / 25;
-}
-
 static int wm8350_isink_set_current(struct regulator_dev *rdev, int min_uA,
 	int max_uA)
 {
@@ -359,104 +332,13 @@ int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
 }
 EXPORT_SYMBOL_GPL(wm8350_isink_set_flash);
 
-static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
-				   int max_uV, unsigned *selector)
-{
-	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int volt_reg, dcdc = rdev_get_id(rdev), mV,
-		min_mV = min_uV / 1000, max_mV = max_uV / 1000;
-	u16 val;
-
-	if (min_mV < 850 || min_mV > 4025)
-		return -EINVAL;
-	if (max_mV < 850 || max_mV > 4025)
-		return -EINVAL;
-
-	/* step size is 25mV */
-	mV = (min_mV - 826) / 25;
-	if (wm8350_dcdc_val_to_mvolts(mV) > max_mV)
-		return -EINVAL;
-	BUG_ON(wm8350_dcdc_val_to_mvolts(mV) < min_mV);
-
-	switch (dcdc) {
-	case WM8350_DCDC_1:
-		volt_reg = WM8350_DCDC1_CONTROL;
-		break;
-	case WM8350_DCDC_3:
-		volt_reg = WM8350_DCDC3_CONTROL;
-		break;
-	case WM8350_DCDC_4:
-		volt_reg = WM8350_DCDC4_CONTROL;
-		break;
-	case WM8350_DCDC_6:
-		volt_reg = WM8350_DCDC6_CONTROL;
-		break;
-	case WM8350_DCDC_2:
-	case WM8350_DCDC_5:
-	default:
-		return -EINVAL;
-	}
-
-	*selector = mV;
-
-	/* all DCDCs have same mV bits */
-	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
-	wm8350_reg_write(wm8350, volt_reg, val | mV);
-	return 0;
-}
-
-static int wm8350_dcdc_get_voltage_sel(struct regulator_dev *rdev)
-{
-	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int volt_reg, dcdc = rdev_get_id(rdev);
-
-	switch (dcdc) {
-	case WM8350_DCDC_1:
-		volt_reg = WM8350_DCDC1_CONTROL;
-		break;
-	case WM8350_DCDC_3:
-		volt_reg = WM8350_DCDC3_CONTROL;
-		break;
-	case WM8350_DCDC_4:
-		volt_reg = WM8350_DCDC4_CONTROL;
-		break;
-	case WM8350_DCDC_6:
-		volt_reg = WM8350_DCDC6_CONTROL;
-		break;
-	case WM8350_DCDC_2:
-	case WM8350_DCDC_5:
-	default:
-		return -EINVAL;
-	}
-
-	/* all DCDCs have same mV bits */
-	return wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK;
-}
-
-static int wm8350_dcdc_list_voltage(struct regulator_dev *rdev,
-				    unsigned selector)
-{
-	if (selector > WM8350_DCDC_MAX_VSEL)
-		return -EINVAL;
-	return wm8350_dcdc_val_to_mvolts(selector) * 1000;
-}
-
 static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 {
 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int volt_reg, mV = uV / 1000, dcdc = rdev_get_id(rdev);
+	int sel, volt_reg, dcdc = rdev_get_id(rdev);
 	u16 val;
 
-	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, mV);
-
-	if (mV && (mV < 850 || mV > 4025)) {
-		dev_err(wm8350->dev,
-			"DCDC%d suspend voltage %d mV out of range\n",
-			dcdc, mV);
-		return -EINVAL;
-	}
-	if (mV == 0)
-		mV = 850;
+	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, uV / 1000);
 
 	switch (dcdc) {
 	case WM8350_DCDC_1:
@@ -477,10 +359,13 @@ static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 		return -EINVAL;
 	}
 
+	sel = regulator_map_voltage_linear(rdev, uV, uV);
+	if (sel < 0)
+		return -EINVAL;
+
 	/* all DCDCs have same mV bits */
 	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
-	wm8350_reg_write(wm8350, volt_reg,
-			 val | wm8350_dcdc_mvolts_to_val(mV));
+	wm8350_reg_write(wm8350, volt_reg, val | sel);
 	return 0;
 }
 
@@ -657,19 +542,49 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
 	return 0;
 }
 
+static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
+				    unsigned selector)
+{
+	if (selector > WM8350_LDO1_VSEL_MASK)
+		return -EINVAL;
+
+	if (selector < 16)
+		return (selector * 50000) + 900000;
+	else
+		return ((selector - 16) * 100000) + 1800000;
+}
+
+static int wm8350_ldo_map_voltage(struct regulator_dev *rdev, int min_uV,
+				  int max_uV)
+{
+	int volt, sel;
+	int min_mV = min_uV / 1000;
+	int max_mV = max_uV / 1000;
+
+	if (min_mV < 900 || min_mV > 3300)
+		return -EINVAL;
+	if (max_mV < 900 || max_mV > 3300)
+		return -EINVAL;
+
+	if (min_mV < 1800) /* step size is 50mV < 1800mV */
+		sel = DIV_ROUND_UP(min_uV - 900, 50);
+	else /* step size is 100mV > 1800mV */
+		sel = DIV_ROUND_UP(min_uV - 1800, 100) + 16;
+
+	volt = wm8350_ldo_list_voltage(rdev, sel);
+	if (volt < min_uV || volt > max_uV)
+		return -EINVAL;
+
+	return sel;
+}
+
 static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 {
 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int volt_reg, mV = uV / 1000, ldo = rdev_get_id(rdev);
+	int sel, volt_reg, ldo = rdev_get_id(rdev);
 	u16 val;
 
-	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, mV);
-
-	if (mV < 900 || mV > 3300) {
-		dev_err(wm8350->dev, "LDO%d voltage %d mV out of range\n",
-			ldo, mV);
-		return -EINVAL;
-	}
+	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, uV / 1000);
 
 	switch (ldo) {
 	case WM8350_LDO_1:
@@ -688,10 +603,13 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 		return -EINVAL;
 	}
 
+	sel = wm8350_ldo_map_voltage(rdev, uV, uV);
+	if (sel < 0)
+		return -EINVAL;
+
 	/* all LDOs have same mV bits */
 	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
-	wm8350_reg_write(wm8350, volt_reg,
-			 val | wm8350_ldo_mvolts_to_val(mV));
+	wm8350_reg_write(wm8350, volt_reg, val | sel);
 	return 0;
 }
 
@@ -753,92 +671,6 @@ static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev)
 	return 0;
 }
 
-static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
-				  int max_uV, unsigned *selector)
-{
-	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000,
-		max_mV = max_uV / 1000;
-	u16 val;
-
-	if (min_mV < 900 || min_mV > 3300)
-		return -EINVAL;
-	if (max_mV < 900 || max_mV > 3300)
-		return -EINVAL;
-
-	if (min_mV < 1800) {
-		/* step size is 50mV < 1800mV */
-		mV = (min_mV - 851) / 50;
-		if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
-			return -EINVAL;
-		BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
-	} else {
-		/* step size is 100mV > 1800mV */
-		mV = ((min_mV - 1701) / 100) + 16;
-		if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
-			return -EINVAL;
-		BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
-	}
-
-	switch (ldo) {
-	case WM8350_LDO_1:
-		volt_reg = WM8350_LDO1_CONTROL;
-		break;
-	case WM8350_LDO_2:
-		volt_reg = WM8350_LDO2_CONTROL;
-		break;
-	case WM8350_LDO_3:
-		volt_reg = WM8350_LDO3_CONTROL;
-		break;
-	case WM8350_LDO_4:
-		volt_reg = WM8350_LDO4_CONTROL;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	*selector = mV;
-
-	/* all LDOs have same mV bits */
-	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
-	wm8350_reg_write(wm8350, volt_reg, val | mV);
-	return 0;
-}
-
-static int wm8350_ldo_get_voltage_sel(struct regulator_dev *rdev)
-{
-	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int volt_reg, ldo = rdev_get_id(rdev);
-
-	switch (ldo) {
-	case WM8350_LDO_1:
-		volt_reg = WM8350_LDO1_CONTROL;
-		break;
-	case WM8350_LDO_2:
-		volt_reg = WM8350_LDO2_CONTROL;
-		break;
-	case WM8350_LDO_3:
-		volt_reg = WM8350_LDO3_CONTROL;
-		break;
-	case WM8350_LDO_4:
-		volt_reg = WM8350_LDO4_CONTROL;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* all LDOs have same mV bits */
-	return wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK;
-}
-
-static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
-				    unsigned selector)
-{
-	if (selector > WM8350_LDO1_VSEL_MASK)
-		return -EINVAL;
-	return wm8350_ldo_val_to_mvolts(selector) * 1000;
-}
-
 int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
 			 u16 stop, u16 fault)
 {
@@ -959,63 +791,6 @@ int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
 }
 EXPORT_SYMBOL_GPL(wm8350_dcdc25_set_mode);
 
-static int wm8350_dcdc_enable(struct regulator_dev *rdev)
-{
-	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int dcdc = rdev_get_id(rdev);
-	u16 shift;
-
-	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
-		return -EINVAL;
-
-	shift = dcdc - WM8350_DCDC_1;
-	wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
-	return 0;
-}
-
-static int wm8350_dcdc_disable(struct regulator_dev *rdev)
-{
-	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int dcdc = rdev_get_id(rdev);
-	u16 shift;
-
-	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
-		return -EINVAL;
-
-	shift = dcdc - WM8350_DCDC_1;
-	wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
-
-	return 0;
-}
-
-static int wm8350_ldo_enable(struct regulator_dev *rdev)
-{
-	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int ldo = rdev_get_id(rdev);
-	u16 shift;
-
-	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
-		return -EINVAL;
-
-	shift = (ldo - WM8350_LDO_1) + 8;
-	wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
-	return 0;
-}
-
-static int wm8350_ldo_disable(struct regulator_dev *rdev)
-{
-	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int ldo = rdev_get_id(rdev);
-	u16 shift;
-
-	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
-		return -EINVAL;
-
-	shift = (ldo - WM8350_LDO_1) + 8;
-	wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
-	return 0;
-}
-
 static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable)
 {
 	int reg = 0, ret;
@@ -1197,42 +972,17 @@ static unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev,
 	return mode;
 }
 
-static int wm8350_dcdc_is_enabled(struct regulator_dev *rdev)
-{
-	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int dcdc = rdev_get_id(rdev), shift;
-
-	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
-		return -EINVAL;
-
-	shift = dcdc - WM8350_DCDC_1;
-	return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
-	    & (1 << shift);
-}
-
-static int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
-{
-	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-	int ldo = rdev_get_id(rdev), shift;
-
-	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
-		return -EINVAL;
-
-	shift = (ldo - WM8350_LDO_1) + 8;
-	return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
-	    & (1 << shift);
-}
-
 static struct regulator_ops wm8350_dcdc_ops = {
-	.set_voltage = wm8350_dcdc_set_voltage,
-	.get_voltage_sel = wm8350_dcdc_get_voltage_sel,
-	.list_voltage = wm8350_dcdc_list_voltage,
-	.enable = wm8350_dcdc_enable,
-	.disable = wm8350_dcdc_disable,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
 	.get_mode = wm8350_dcdc_get_mode,
 	.set_mode = wm8350_dcdc_set_mode,
 	.get_optimum_mode = wm8350_dcdc_get_optimum_mode,
-	.is_enabled = wm8350_dcdc_is_enabled,
 	.set_suspend_voltage = wm8350_dcdc_set_suspend_voltage,
 	.set_suspend_enable = wm8350_dcdc_set_suspend_enable,
 	.set_suspend_disable = wm8350_dcdc_set_suspend_disable,
@@ -1240,20 +990,21 @@ static struct regulator_ops wm8350_dcdc_ops = {
 };
 
 static struct regulator_ops wm8350_dcdc2_5_ops = {
-	.enable = wm8350_dcdc_enable,
-	.disable = wm8350_dcdc_disable,
-	.is_enabled = wm8350_dcdc_is_enabled,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
 	.set_suspend_enable = wm8350_dcdc25_set_suspend_enable,
 	.set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
 };
 
 static struct regulator_ops wm8350_ldo_ops = {
-	.set_voltage = wm8350_ldo_set_voltage,
-	.get_voltage_sel = wm8350_ldo_get_voltage_sel,
+	.map_voltage = wm8350_ldo_map_voltage,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.list_voltage = wm8350_ldo_list_voltage,
-	.enable = wm8350_ldo_enable,
-	.disable = wm8350_ldo_disable,
-	.is_enabled = wm8350_ldo_is_enabled,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
 	.get_mode = wm8350_ldo_get_mode,
 	.set_suspend_voltage = wm8350_ldo_set_suspend_voltage,
 	.set_suspend_enable = wm8350_ldo_set_suspend_enable,
@@ -1277,6 +1028,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
 		.irq = WM8350_IRQ_UV_DC1,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+		.min_uV = 850000,
+		.uV_step = 25000,
+		.vsel_reg = WM8350_DCDC1_CONTROL,
+		.vsel_mask = WM8350_DC1_VSEL_MASK,
+		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
+		.enable_mask = WM8350_DC1_ENA,
 		.owner = THIS_MODULE,
 	},
 	{
@@ -1285,6 +1042,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
 		.ops = &wm8350_dcdc2_5_ops,
 		.irq = WM8350_IRQ_UV_DC2,
 		.type = REGULATOR_VOLTAGE,
+		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
+		.enable_mask = WM8350_DC2_ENA,
 		.owner = THIS_MODULE,
 	},
 	{
@@ -1294,6 +1053,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
 		.irq = WM8350_IRQ_UV_DC3,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+		.min_uV = 850000,
+		.uV_step = 25000,
+		.vsel_reg = WM8350_DCDC3_CONTROL,
+		.vsel_mask = WM8350_DC3_VSEL_MASK,
+		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
+		.enable_mask = WM8350_DC3_ENA,
 		.owner = THIS_MODULE,
 	},
 	{
@@ -1303,6 +1068,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
 		.irq = WM8350_IRQ_UV_DC4,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+		.min_uV = 850000,
+		.uV_step = 25000,
+		.vsel_reg = WM8350_DCDC4_CONTROL,
+		.vsel_mask = WM8350_DC4_VSEL_MASK,
+		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
+		.enable_mask = WM8350_DC4_ENA,
 		.owner = THIS_MODULE,
 	},
 	{
@@ -1311,6 +1082,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
 		.ops = &wm8350_dcdc2_5_ops,
 		.irq = WM8350_IRQ_UV_DC5,
 		.type = REGULATOR_VOLTAGE,
+		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
+		.enable_mask = WM8350_DC5_ENA,
 		.owner = THIS_MODULE,
 	 },
 	{
@@ -1320,6 +1093,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
 		.irq = WM8350_IRQ_UV_DC6,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+		.min_uV = 850000,
+		.uV_step = 25000,
+		.vsel_reg = WM8350_DCDC6_CONTROL,
+		.vsel_mask = WM8350_DC6_VSEL_MASK,
+		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
+		.enable_mask = WM8350_DC6_ENA,
 		.owner = THIS_MODULE,
 	},
 	{
@@ -1329,6 +1108,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
 		.irq = WM8350_IRQ_UV_LDO1,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_LDO1_VSEL_MASK + 1,
+		.vsel_reg = WM8350_LDO1_CONTROL,
+		.vsel_mask = WM8350_LDO1_VSEL_MASK,
+		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
+		.enable_mask = WM8350_LDO1_ENA,
 		.owner = THIS_MODULE,
 	},
 	{
@@ -1338,6 +1121,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
 		.irq = WM8350_IRQ_UV_LDO2,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_LDO2_VSEL_MASK + 1,
+		.vsel_reg = WM8350_LDO2_CONTROL,
+		.vsel_mask = WM8350_LDO2_VSEL_MASK,
+		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
+		.enable_mask = WM8350_LDO2_ENA,
 		.owner = THIS_MODULE,
 	},
 	{
@@ -1347,6 +1134,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
 		.irq = WM8350_IRQ_UV_LDO3,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_LDO3_VSEL_MASK + 1,
+		.vsel_reg = WM8350_LDO3_CONTROL,
+		.vsel_mask = WM8350_LDO3_VSEL_MASK,
+		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
+		.enable_mask = WM8350_LDO3_ENA,
 		.owner = THIS_MODULE,
 	},
 	{
@@ -1356,6 +1147,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
 		.irq = WM8350_IRQ_UV_LDO4,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_LDO4_VSEL_MASK + 1,
+		.vsel_reg = WM8350_LDO4_CONTROL,
+		.vsel_mask = WM8350_LDO4_VSEL_MASK,
+		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
+		.enable_mask = WM8350_LDO4_ENA,
 		.owner = THIS_MODULE,
 	},
 	{
@@ -1429,6 +1224,7 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
 	config.dev = &pdev->dev;
 	config.init_data = pdev->dev.platform_data;
 	config.driver_data = dev_get_drvdata(&pdev->dev);
+	config.regmap = wm8350->regmap;
 
 	/* register regulator */
 	rdev = regulator_register(&wm8350_reg[pdev->id], &config);
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index 69a2b7c..9035dd0 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -28,34 +28,26 @@ static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
 	if (selector < 15)
 		return 900000 + (selector * 50000);
 	else
-		return 1600000 + ((selector - 14) * 100000);
+		return 1700000 + ((selector - 15) * 100000);
 }
 
 static int wm8400_ldo_map_voltage(struct regulator_dev *dev,
 				  int min_uV, int max_uV)
 {
 	u16 val;
+	int volt;
 
 	if (min_uV < 900000 || min_uV > 3300000)
 		return -EINVAL;
 
-	if (min_uV < 1700000) {
-		/* Steps of 50mV from 900mV;  */
+	if (min_uV < 1700000) /* Steps of 50mV from 900mV;  */
 		val = DIV_ROUND_UP(min_uV - 900000, 50000);
+	else /* Steps of 100mV from 1700mV */
+		val = DIV_ROUND_UP(min_uV - 1700000, 100000) + 15;
 
-		if ((val * 50000) + 900000 > max_uV)
-			return -EINVAL;
-		BUG_ON((val * 50000) + 900000 < min_uV);
-	} else {
-		/* Steps of 100mV from 1700mV */
-		val = DIV_ROUND_UP(min_uV - 1700000, 100000);
-
-		if ((val * 100000) + 1700000 > max_uV)
-			return -EINVAL;
-		BUG_ON((val * 100000) + 1700000 < min_uV);
-
-		val += 0xf;
-	}
+	volt = wm8400_ldo_list_voltage(dev, val);
+	if (volt < min_uV || volt > max_uV)
+		return -EINVAL;
 
 	return val;
 }
@@ -152,6 +144,7 @@ static struct regulator_ops wm8400_dcdc_ops = {
 	.enable = regulator_enable_regmap,
 	.disable = regulator_disable_regmap,
 	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.get_mode = wm8400_dcdc_get_mode,
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 9a99431..0e2028b 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -77,22 +77,14 @@ static int wm8994_ldo_enable_time(struct regulator_dev *rdev)
 	return 3000;
 }
 
-static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev,
-				    unsigned int selector)
-{
-	if (selector > WM8994_LDO1_MAX_SELECTOR)
-		return -EINVAL;
-
-	return (selector * 100000) + 2400000;
-}
-
 static struct regulator_ops wm8994_ldo1_ops = {
 	.enable = wm8994_ldo_enable,
 	.disable = wm8994_ldo_disable,
 	.is_enabled = wm8994_ldo_is_enabled,
 	.enable_time = wm8994_ldo_enable_time,
 
-	.list_voltage = wm8994_ldo1_list_voltage,
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 };
@@ -143,6 +135,8 @@ static const struct regulator_desc wm8994_ldo_desc[] = {
 		.vsel_reg = WM8994_LDO_1,
 		.vsel_mask = WM8994_LDO1_VSEL_MASK,
 		.ops = &wm8994_ldo1_ops,
+		.min_uV = 2400000,
+		.uV_step = 100000,
 		.owner = THIS_MODULE,
 	},
 	{
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 5445d9b..934ce6e 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -6,4 +6,5 @@ obj-$(CONFIG_REMOTEPROC)		+= remoteproc.o
 remoteproc-y				:= remoteproc_core.o
 remoteproc-y				+= remoteproc_debugfs.o
 remoteproc-y				+= remoteproc_virtio.o
+remoteproc-y				+= remoteproc_elf_loader.o
 obj-$(CONFIG_OMAP_REMOTEPROC)		+= omap_remoteproc.o
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 66324ee..8025b56 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -165,7 +165,7 @@ static void rproc_disable_iommu(struct rproc *rproc)
  * but only on kernel direct mapped RAM memory. Instead, we're just using
  * here the output of the DMA API, which should be more correct.
  */
-static void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 {
 	struct rproc_mem_entry *carveout;
 	void *ptr = NULL;
@@ -188,96 +188,7 @@ static void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 
 	return ptr;
 }
-
-/**
- * rproc_load_segments() - load firmware segments to memory
- * @rproc: remote processor which will be booted using these fw segments
- * @elf_data: the content of the ELF firmware image
- * @len: firmware size (in bytes)
- *
- * This function loads the firmware segments to memory, where the remote
- * processor expects them.
- *
- * Some remote processors will expect their code and data to be placed
- * in specific device addresses, and can't have them dynamically assigned.
- *
- * We currently support only those kind of remote processors, and expect
- * the program header's paddr member to contain those addresses. We then go
- * through the physically contiguous "carveout" memory regions which we
- * allocated (and mapped) earlier on behalf of the remote processor,
- * and "translate" device address to kernel addresses, so we can copy the
- * segments where they are expected.
- *
- * Currently we only support remote processors that required carveout
- * allocations and got them mapped onto their iommus. Some processors
- * might be different: they might not have iommus, and would prefer to
- * directly allocate memory for every segment/resource. This is not yet
- * supported, though.
- */
-static int
-rproc_load_segments(struct rproc *rproc, const u8 *elf_data, size_t len)
-{
-	struct device *dev = rproc->dev;
-	struct elf32_hdr *ehdr;
-	struct elf32_phdr *phdr;
-	int i, ret = 0;
-
-	ehdr = (struct elf32_hdr *)elf_data;
-	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
-
-	/* go through the available ELF segments */
-	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-		u32 da = phdr->p_paddr;
-		u32 memsz = phdr->p_memsz;
-		u32 filesz = phdr->p_filesz;
-		u32 offset = phdr->p_offset;
-		void *ptr;
-
-		if (phdr->p_type != PT_LOAD)
-			continue;
-
-		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-					phdr->p_type, da, memsz, filesz);
-
-		if (filesz > memsz) {
-			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
-							filesz, memsz);
-			ret = -EINVAL;
-			break;
-		}
-
-		if (offset + filesz > len) {
-			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
-					offset + filesz, len);
-			ret = -EINVAL;
-			break;
-		}
-
-		/* grab the kernel address for this device address */
-		ptr = rproc_da_to_va(rproc, da, memsz);
-		if (!ptr) {
-			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
-			ret = -EINVAL;
-			break;
-		}
-
-		/* put the segment where the remote processor expects it */
-		if (phdr->p_filesz)
-			memcpy(ptr, elf_data + phdr->p_offset, filesz);
-
-		/*
-		 * Zero out remaining memory for this segment.
-		 *
-		 * This isn't strictly required since dma_alloc_coherent already
-		 * did this for us. albeit harmless, we may consider removing
-		 * this.
-		 */
-		if (memsz > filesz)
-			memset(ptr + filesz, 0, memsz - filesz);
-	}
-
-	return ret;
-}
+EXPORT_SYMBOL(rproc_da_to_va);
 
 static int
 __rproc_handle_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
@@ -822,85 +733,6 @@ rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int l
 }
 
 /**
- * rproc_find_rsc_table() - find the resource table
- * @rproc: the rproc handle
- * @elf_data: the content of the ELF firmware image
- * @len: firmware size (in bytes)
- * @tablesz: place holder for providing back the table size
- *
- * This function finds the resource table inside the remote processor's
- * firmware. It is used both upon the registration of @rproc (in order
- * to look for and register the supported virito devices), and when the
- * @rproc is booted.
- *
- * Returns the pointer to the resource table if it is found, and write its
- * size into @tablesz. If a valid table isn't found, NULL is returned
- * (and @tablesz isn't set).
- */
-static struct resource_table *
-rproc_find_rsc_table(struct rproc *rproc, const u8 *elf_data, size_t len,
-							int *tablesz)
-{
-	struct elf32_hdr *ehdr;
-	struct elf32_shdr *shdr;
-	const char *name_table;
-	struct device *dev = rproc->dev;
-	struct resource_table *table = NULL;
-	int i;
-
-	ehdr = (struct elf32_hdr *)elf_data;
-	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
-	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
-
-	/* look for the resource table and handle it */
-	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
-		int size = shdr->sh_size;
-		int offset = shdr->sh_offset;
-
-		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
-			continue;
-
-		table = (struct resource_table *)(elf_data + offset);
-
-		/* make sure we have the entire table */
-		if (offset + size > len) {
-			dev_err(dev, "resource table truncated\n");
-			return NULL;
-		}
-
-		/* make sure table has at least the header */
-		if (sizeof(struct resource_table) > size) {
-			dev_err(dev, "header-less resource table\n");
-			return NULL;
-		}
-
-		/* we don't support any version beyond the first */
-		if (table->ver != 1) {
-			dev_err(dev, "unsupported fw ver: %d\n", table->ver);
-			return NULL;
-		}
-
-		/* make sure reserved bytes are zeroes */
-		if (table->reserved[0] || table->reserved[1]) {
-			dev_err(dev, "non zero reserved bytes\n");
-			return NULL;
-		}
-
-		/* make sure the offsets array isn't truncated */
-		if (table->num * sizeof(table->offset[0]) +
-				sizeof(struct resource_table) > size) {
-			dev_err(dev, "resource table incomplete\n");
-			return NULL;
-		}
-
-		*tablesz = shdr->sh_size;
-		break;
-	}
-
-	return table;
-}
-
-/**
  * rproc_resource_cleanup() - clean up and free all acquired resources
  * @rproc: rproc handle
  *
@@ -943,66 +775,6 @@ static void rproc_resource_cleanup(struct rproc *rproc)
 	}
 }
 
-/* make sure this fw image is sane */
-static int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
-{
-	const char *name = rproc->firmware;
-	struct device *dev = rproc->dev;
-	struct elf32_hdr *ehdr;
-	char class;
-
-	if (!fw) {
-		dev_err(dev, "failed to load %s\n", name);
-		return -EINVAL;
-	}
-
-	if (fw->size < sizeof(struct elf32_hdr)) {
-		dev_err(dev, "Image is too small\n");
-		return -EINVAL;
-	}
-
-	ehdr = (struct elf32_hdr *)fw->data;
-
-	/* We only support ELF32 at this point */
-	class = ehdr->e_ident[EI_CLASS];
-	if (class != ELFCLASS32) {
-		dev_err(dev, "Unsupported class: %d\n", class);
-		return -EINVAL;
-	}
-
-	/* We assume the firmware has the same endianess as the host */
-# ifdef __LITTLE_ENDIAN
-	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
-# else /* BIG ENDIAN */
-	if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
-# endif
-		dev_err(dev, "Unsupported firmware endianess\n");
-		return -EINVAL;
-	}
-
-	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
-		dev_err(dev, "Image is too small\n");
-		return -EINVAL;
-	}
-
-	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
-		dev_err(dev, "Image is corrupted (bad magic)\n");
-		return -EINVAL;
-	}
-
-	if (ehdr->e_phnum == 0) {
-		dev_err(dev, "No loadable segments\n");
-		return -EINVAL;
-	}
-
-	if (ehdr->e_phoff > fw->size) {
-		dev_err(dev, "Firmware size is too small\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 /*
  * take a firmware and boot a remote processor with it.
  */
@@ -1010,7 +782,6 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
 {
 	struct device *dev = rproc->dev;
 	const char *name = rproc->firmware;
-	struct elf32_hdr *ehdr;
 	struct resource_table *table;
 	int ret, tablesz;
 
@@ -1018,8 +789,6 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
 	if (ret)
 		return ret;
 
-	ehdr = (struct elf32_hdr *)fw->data;
-
 	dev_info(dev, "Booting fw image %s, size %zd\n", name, fw->size);
 
 	/*
@@ -1032,15 +801,10 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
 		return ret;
 	}
 
-	/*
-	 * The ELF entry point is the rproc's boot addr (though this is not
-	 * a configurable property of all remote processors: some will always
-	 * boot at a specific hardcoded address).
-	 */
-	rproc->bootaddr = ehdr->e_entry;
+	rproc->bootaddr = rproc_get_boot_addr(rproc, fw);
 
 	/* look for the resource table */
-	table = rproc_find_rsc_table(rproc, fw->data, fw->size, &tablesz);
+	table = rproc_find_rsc_table(rproc, fw, &tablesz);
 	if (!table) {
 		ret = -EINVAL;
 		goto clean_up;
@@ -1054,7 +818,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
 	}
 
 	/* load the ELF segments to memory */
-	ret = rproc_load_segments(rproc, fw->data, fw->size);
+	ret = rproc_load_segments(rproc, fw);
 	if (ret) {
 		dev_err(dev, "Failed to load program segments: %d\n", ret);
 		goto clean_up;
@@ -1097,7 +861,7 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
 		goto out;
 
 	/* look for the resource table */
-	table = rproc_find_rsc_table(rproc, fw->data, fw->size, &tablesz);
+	table = rproc_find_rsc_table(rproc, fw,  &tablesz);
 	if (!table)
 		goto out;
 
@@ -1490,6 +1254,9 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
 
 	atomic_set(&rproc->power, 0);
 
+	/* Set ELF as the default fw_ops handler */
+	rproc->fw_ops = &rproc_elf_fw_ops;
+
 	kref_init(&rproc->refcount);
 
 	mutex_init(&rproc->lock);
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
new file mode 100644
index 0000000..4b3ccd5
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -0,0 +1,292 @@
+/*
+ * Remote Processor Framework Elf loader
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ * Mark Grosen <mgrosen@ti.com>
+ * Fernando Guzman Lugo <fernando.lugo@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ * Robert Tivy <rtivy@ti.com>
+ * Armando Uribe De Leon <x0095078@ti.com>
+ * Sjur Brændeland <sjur.brandeland@stericsson.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)    "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/remoteproc.h>
+#include <linux/elf.h>
+
+#include "remoteproc_internal.h"
+
+/**
+ * rproc_elf_sanity_check() - ELF firmware image sanity check
+ * @rproc: the rproc handle
+ * @fw: the ELF firmware image
+ *
+ * Make sure this fw image is sane.
+ */
+static int
+rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
+{
+	const char *name = rproc->firmware;
+	struct device *dev = rproc->dev;
+	struct elf32_hdr *ehdr;
+	char class;
+
+	if (!fw) {
+		dev_err(dev, "failed to load %s\n", name);
+		return -EINVAL;
+	}
+
+	if (fw->size < sizeof(struct elf32_hdr)) {
+		dev_err(dev, "Image is too small\n");
+		return -EINVAL;
+	}
+
+	ehdr = (struct elf32_hdr *)fw->data;
+
+	/* We only support ELF32 at this point */
+	class = ehdr->e_ident[EI_CLASS];
+	if (class != ELFCLASS32) {
+		dev_err(dev, "Unsupported class: %d\n", class);
+		return -EINVAL;
+	}
+
+	/* We assume the firmware has the same endianess as the host */
+# ifdef __LITTLE_ENDIAN
+	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+# else /* BIG ENDIAN */
+	if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+# endif
+		dev_err(dev, "Unsupported firmware endianess\n");
+		return -EINVAL;
+	}
+
+	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
+		dev_err(dev, "Image is too small\n");
+		return -EINVAL;
+	}
+
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(dev, "Image is corrupted (bad magic)\n");
+		return -EINVAL;
+	}
+
+	if (ehdr->e_phnum == 0) {
+		dev_err(dev, "No loadable segments\n");
+		return -EINVAL;
+	}
+
+	if (ehdr->e_phoff > fw->size) {
+		dev_err(dev, "Firmware size is too small\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * rproc_elf_get_boot_addr() - Get rproc's boot address.
+ * @rproc: the rproc handle
+ * @fw: the ELF firmware image
+ *
+ * This function reads the ELF entry point address.
+ * Note that the boot address is not a configurable property of all remote
+ * processors. Some will always boot at a specific hard-coded address.
+ */
+static
+u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
+{
+	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
+	return ehdr->e_entry;
+}
+
+/**
+ * rproc_elf_load_segments() - load firmware segments to memory
+ * @rproc: remote processor which will be booted using these fw segments
+ * @fw: the  the ELF firmware image
+ *
+ * This function loads the firmware segments to memory, where the remote
+ * processor expects them.
+ *
+ * Some remote processors will expect their code and data to be placed
+ * in specific device addresses, and can't have them dynamically assigned.
+ *
+ * We currently support only those kind of remote processors, and expect
+ * the program header's paddr member to contain those addresses. We then go
+ * through the physically contiguous "carveout" memory regions which we
+ * allocated (and mapped) earlier on behalf of the remote processor,
+ * and "translate" device address to kernel addresses, so we can copy the
+ * segments where they are expected.
+ *
+ * Currently we only support remote processors that required carveout
+ * allocations and got them mapped onto their iommus. Some processors
+ * might be different: they might not have iommus, and would prefer to
+ * directly allocate memory for every segment/resource. This is not yet
+ * supported, though.
+ */
+static int
+rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
+{
+	struct device *dev = rproc->dev;
+	struct elf32_hdr *ehdr;
+	struct elf32_phdr *phdr;
+	int i, ret = 0;
+	const u8 *elf_data = fw->data;
+
+	ehdr = (struct elf32_hdr *)elf_data;
+	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+
+	/* go through the available ELF segments */
+	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+		u32 da = phdr->p_paddr;
+		u32 memsz = phdr->p_memsz;
+		u32 filesz = phdr->p_filesz;
+		u32 offset = phdr->p_offset;
+		void *ptr;
+
+		if (phdr->p_type != PT_LOAD)
+			continue;
+
+		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
+					phdr->p_type, da, memsz, filesz);
+
+		if (filesz > memsz) {
+			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+							filesz, memsz);
+			ret = -EINVAL;
+			break;
+		}
+
+		if (offset + filesz > fw->size) {
+			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
+					offset + filesz, fw->size);
+			ret = -EINVAL;
+			break;
+		}
+
+		/* grab the kernel address for this device address */
+		ptr = rproc_da_to_va(rproc, da, memsz);
+		if (!ptr) {
+			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+			ret = -EINVAL;
+			break;
+		}
+
+		/* put the segment where the remote processor expects it */
+		if (phdr->p_filesz)
+			memcpy(ptr, elf_data + phdr->p_offset, filesz);
+
+		/*
+		 * Zero out remaining memory for this segment.
+		 *
+		 * This isn't strictly required since dma_alloc_coherent already
+		 * did this for us. albeit harmless, we may consider removing
+		 * this.
+		 */
+		if (memsz > filesz)
+			memset(ptr + filesz, 0, memsz - filesz);
+	}
+
+	return ret;
+}
+
+/**
+ * rproc_elf_find_rsc_table() - find the resource table
+ * @rproc: the rproc handle
+ * @fw: the ELF firmware image
+ * @tablesz: place holder for providing back the table size
+ *
+ * This function finds the resource table inside the remote processor's
+ * firmware. It is used both upon the registration of @rproc (in order
+ * to look for and register the supported virito devices), and when the
+ * @rproc is booted.
+ *
+ * Returns the pointer to the resource table if it is found, and write its
+ * size into @tablesz. If a valid table isn't found, NULL is returned
+ * (and @tablesz isn't set).
+ */
+static struct resource_table *
+rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
+							int *tablesz)
+{
+	struct elf32_hdr *ehdr;
+	struct elf32_shdr *shdr;
+	const char *name_table;
+	struct device *dev = rproc->dev;
+	struct resource_table *table = NULL;
+	int i;
+	const u8 *elf_data = fw->data;
+
+	ehdr = (struct elf32_hdr *)elf_data;
+	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
+	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
+
+	/* look for the resource table and handle it */
+	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+		int size = shdr->sh_size;
+		int offset = shdr->sh_offset;
+
+		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+			continue;
+
+		table = (struct resource_table *)(elf_data + offset);
+
+		/* make sure we have the entire table */
+		if (offset + size > fw->size) {
+			dev_err(dev, "resource table truncated\n");
+			return NULL;
+		}
+
+		/* make sure table has at least the header */
+		if (sizeof(struct resource_table) > size) {
+			dev_err(dev, "header-less resource table\n");
+			return NULL;
+		}
+
+		/* we don't support any version beyond the first */
+		if (table->ver != 1) {
+			dev_err(dev, "unsupported fw ver: %d\n", table->ver);
+			return NULL;
+		}
+
+		/* make sure reserved bytes are zeroes */
+		if (table->reserved[0] || table->reserved[1]) {
+			dev_err(dev, "non zero reserved bytes\n");
+			return NULL;
+		}
+
+		/* make sure the offsets array isn't truncated */
+		if (table->num * sizeof(table->offset[0]) +
+				sizeof(struct resource_table) > size) {
+			dev_err(dev, "resource table incomplete\n");
+			return NULL;
+		}
+
+		*tablesz = shdr->sh_size;
+		break;
+	}
+
+	return table;
+}
+
+const struct rproc_fw_ops rproc_elf_fw_ops = {
+	.load = rproc_elf_load_segments,
+	.find_rsc_table = rproc_elf_find_rsc_table,
+	.sanity_check = rproc_elf_sanity_check,
+	.get_boot_addr = rproc_elf_get_boot_addr
+};
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 9f336d6..7823156 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -40,5 +40,45 @@ void rproc_delete_debug_dir(struct rproc *rproc);
 void rproc_create_debug_dir(struct rproc *rproc);
 void rproc_init_debugfs(void);
 void rproc_exit_debugfs(void);
+void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
+
+static inline
+int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
+{
+	if (rproc->fw_ops->sanity_check)
+		return rproc->fw_ops->sanity_check(rproc, fw);
+
+	return 0;
+}
+
+static inline
+u32 rproc_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
+{
+	if (rproc->fw_ops->get_boot_addr)
+		return rproc->fw_ops->get_boot_addr(rproc, fw);
+
+	return 0;
+}
+
+static inline
+int rproc_load_segments(struct rproc *rproc, const struct firmware *fw)
+{
+	if (rproc->fw_ops->load)
+		return rproc->fw_ops->load(rproc, fw);
+
+	return -EINVAL;
+}
+
+static inline
+struct resource_table *rproc_find_rsc_table(struct rproc *rproc,
+				const struct firmware *fw, int *tablesz)
+{
+	if (rproc->fw_ops->find_rsc_table)
+		return rproc->fw_ops->find_rsc_table(rproc, fw, tablesz);
+
+	return NULL;
+}
+
+extern const struct rproc_fw_ops rproc_elf_fw_ops;
 
 #endif /* REMOTEPROC_INTERNAL_H */
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 08cbdb9..668da59 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -694,6 +694,7 @@ config RTC_DRV_AB3100
 config RTC_DRV_AB8500
 	tristate "ST-Ericsson AB8500 RTC"
 	depends on AB8500_CORE
+	select RTC_INTF_DEV_UIE_EMUL
 	help
 	  Select this to enable the ST-Ericsson AB8500 power management IC RTC
 	  support. This chip contains a battery- and capacitor-backed RTC.
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
index 4bcf9ca..d4e0406 100644
--- a/drivers/rtc/rtc-ab8500.c
+++ b/drivers/rtc/rtc-ab8500.c
@@ -88,22 +88,17 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
 	if (retval < 0)
 		return retval;
 
-	/* Early AB8500 chips will not clear the rtc read request bit */
-	if (abx500_get_chip_id(dev) == 0) {
-		usleep_range(1000, 1000);
-	} else {
-		/* Wait for some cycles after enabling the rtc read in ab8500 */
-		while (time_before(jiffies, timeout)) {
-			retval = abx500_get_register_interruptible(dev,
-				AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value);
-			if (retval < 0)
-				return retval;
-
-			if (!(value & RTC_READ_REQUEST))
-				break;
-
-			usleep_range(1000, 5000);
-		}
+	/* Wait for some cycles after enabling the rtc read in ab8500 */
+	while (time_before(jiffies, timeout)) {
+		retval = abx500_get_register_interruptible(dev,
+			AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value);
+		if (retval < 0)
+			return retval;
+
+		if (!(value & RTC_READ_REQUEST))
+			break;
+
+		usleep_range(1000, 5000);
 	}
 
 	/* Read the Watchtime registers */
@@ -224,7 +219,8 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
 	int retval, i;
 	unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
-	unsigned long mins, secs = 0;
+	unsigned long mins, secs = 0, cursec = 0;
+	struct rtc_time curtm;
 
 	if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {
 		dev_dbg(dev, "year should be equal to or greater than %d\n",
@@ -236,6 +232,18 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 	rtc_tm_to_time(&alarm->time, &secs);
 
 	/*
+	 * Check whether alarm is set less than 1min.
+	 * Since our RTC doesn't support alarm resolution less than 1min,
+	 * return -EINVAL, so UIE EMUL can take it up, incase of UIE_ON
+	 */
+	ab8500_rtc_read_time(dev, &curtm); /* Read current time */
+	rtc_tm_to_time(&curtm, &cursec);
+	if ((secs - cursec) < 59) {
+		dev_dbg(dev, "Alarm less than 1 minute not supported\r\n");
+		return -EINVAL;
+	}
+
+	/*
 	 * Convert it to the number of seconds since 01-01-2000 00:00:00, since
 	 * we only have a small counter in the RTC.
 	 */
@@ -422,7 +430,7 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
 	}
 
 	err = request_threaded_irq(irq, NULL, rtc_alarm_handler,
-		IRQF_NO_SUSPEND, "ab8500-rtc", rtc);
+		IRQF_NO_SUSPEND | IRQF_ONESHOT, "ab8500-rtc", rtc);
 	if (err < 0) {
 		rtc_device_unregister(rtc);
 		return err;
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c
index a5b8a0c..76b2156 100644
--- a/drivers/rtc/rtc-coh901331.c
+++ b/drivers/rtc/rtc-coh901331.c
@@ -155,13 +155,10 @@ static int __exit coh901331_remove(struct platform_device *pdev)
 	struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
 
 	if (rtap) {
-		free_irq(rtap->irq, rtap);
 		rtc_device_unregister(rtap->rtc);
+		clk_unprepare(rtap->clk);
 		clk_put(rtap->clk);
-		iounmap(rtap->virtbase);
-		release_mem_region(rtap->phybase, rtap->physize);
 		platform_set_drvdata(pdev, NULL);
-		kfree(rtap);
 	}
 
 	return 0;
@@ -174,49 +171,43 @@ static int __init coh901331_probe(struct platform_device *pdev)
 	struct coh901331_port *rtap;
 	struct resource *res;
 
-	rtap = kzalloc(sizeof(struct coh901331_port), GFP_KERNEL);
+	rtap = devm_kzalloc(&pdev->dev,
+			    sizeof(struct coh901331_port), GFP_KERNEL);
 	if (!rtap)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -ENOENT;
-		goto out_no_resource;
-	}
+	if (!res)
+		return -ENOENT;
+
 	rtap->phybase = res->start;
 	rtap->physize = resource_size(res);
 
-	if (request_mem_region(rtap->phybase, rtap->physize,
-			       "rtc-coh901331") == NULL) {
-		ret = -EBUSY;
-		goto out_no_memregion;
-	}
+	if (devm_request_mem_region(&pdev->dev, rtap->phybase, rtap->physize,
+				    "rtc-coh901331") == NULL)
+		return -EBUSY;
 
-	rtap->virtbase = ioremap(rtap->phybase, rtap->physize);
-	if (!rtap->virtbase) {
-		ret = -ENOMEM;
-		goto out_no_remap;
-	}
+	rtap->virtbase = devm_ioremap(&pdev->dev, rtap->phybase, rtap->physize);
+	if (!rtap->virtbase)
+		return -ENOMEM;
 
 	rtap->irq = platform_get_irq(pdev, 0);
-	if (request_irq(rtap->irq, coh901331_interrupt, 0,
-			"RTC COH 901 331 Alarm", rtap)) {
-		ret = -EIO;
-		goto out_no_irq;
-	}
+	if (devm_request_irq(&pdev->dev, rtap->irq, coh901331_interrupt, 0,
+			     "RTC COH 901 331 Alarm", rtap))
+		return -EIO;
 
 	rtap->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(rtap->clk)) {
 		ret = PTR_ERR(rtap->clk);
 		dev_err(&pdev->dev, "could not get clock\n");
-		goto out_no_clk;
+		return ret;
 	}
 
 	/* We enable/disable the clock only to assure it works */
-	ret = clk_enable(rtap->clk);
+	ret = clk_prepare_enable(rtap->clk);
 	if (ret) {
 		dev_err(&pdev->dev, "could not enable clock\n");
-		goto out_no_clk_enable;
+		goto out_no_clk_prepenable;
 	}
 	clk_disable(rtap->clk);
 
@@ -232,18 +223,9 @@ static int __init coh901331_probe(struct platform_device *pdev)
 
  out_no_rtc:
 	platform_set_drvdata(pdev, NULL);
- out_no_clk_enable:
+	clk_unprepare(rtap->clk);
+ out_no_clk_prepenable:
 	clk_put(rtap->clk);
- out_no_clk:
-	free_irq(rtap->irq, rtap);
- out_no_irq:
-	iounmap(rtap->virtbase);
- out_no_remap:
-	platform_set_drvdata(pdev, NULL);
- out_no_memregion:
-	release_mem_region(rtap->phybase, SZ_4K);
- out_no_resource:
-	kfree(rtap);
 	return ret;
 }
 
@@ -265,6 +247,7 @@ static int coh901331_suspend(struct platform_device *pdev, pm_message_t state)
 		writel(0, rtap->virtbase + COH901331_IRQ_MASK);
 		clk_disable(rtap->clk);
 	}
+	clk_unprepare(rtap->clk);
 	return 0;
 }
 
@@ -272,6 +255,7 @@ static int coh901331_resume(struct platform_device *pdev)
 {
 	struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
 
+	clk_prepare(rtap->clk);
 	if (device_may_wakeup(&pdev->dev)) {
 		disable_irq_wake(rtap->irq);
 	} else {
@@ -293,6 +277,7 @@ static void coh901331_shutdown(struct platform_device *pdev)
 	clk_enable(rtap->clk);
 	writel(0, rtap->virtbase + COH901331_IRQ_MASK);
 	clk_disable(rtap->clk);
+	clk_unprepare(rtap->clk);
 }
 
 static struct platform_driver coh901331_driver = {
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index cc05339..08378e3 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -68,11 +68,26 @@
 
 #define RTC_TIMER_FREQ 32768
 
+/**
+ * struct pl031_vendor_data - per-vendor variations
+ * @ops: the vendor-specific operations used on this silicon version
+ * @clockwatch: if this is an ST Microelectronics silicon version with a
+ *	clockwatch function
+ * @st_weekday: if this is an ST Microelectronics silicon version that need
+ *	the weekday fix
+ * @irqflags: special IRQ flags per variant
+ */
+struct pl031_vendor_data {
+	struct rtc_class_ops ops;
+	bool clockwatch;
+	bool st_weekday;
+	unsigned long irqflags;
+};
+
 struct pl031_local {
+	struct pl031_vendor_data *vendor;
 	struct rtc_device *rtc;
 	void __iomem *base;
-	u8 hw_designer;
-	u8 hw_revision:4;
 };
 
 static int pl031_alarm_irq_enable(struct device *dev,
@@ -303,7 +318,8 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
 {
 	int ret;
 	struct pl031_local *ldata;
-	struct rtc_class_ops *ops = id->data;
+	struct pl031_vendor_data *vendor = id->data;
+	struct rtc_class_ops *ops = &vendor->ops;
 	unsigned long time;
 
 	ret = amba_request_regions(adev, NULL);
@@ -315,6 +331,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
 		ret = -ENOMEM;
 		goto out;
 	}
+	ldata->vendor = vendor;
 
 	ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
 
@@ -325,14 +342,11 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
 
 	amba_set_drvdata(adev, ldata);
 
-	ldata->hw_designer = amba_manf(adev);
-	ldata->hw_revision = amba_rev(adev);
-
-	dev_dbg(&adev->dev, "designer ID = 0x%02x\n", ldata->hw_designer);
-	dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision);
+	dev_dbg(&adev->dev, "designer ID = 0x%02x\n", amba_manf(adev));
+	dev_dbg(&adev->dev, "revision = 0x%01x\n", amba_rev(adev));
 
 	/* Enable the clockwatch on ST Variants */
-	if (ldata->hw_designer == AMBA_VENDOR_ST)
+	if (vendor->clockwatch)
 		writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,
 		       ldata->base + RTC_CR);
 
@@ -340,7 +354,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
 	 * On ST PL031 variants, the RTC reset value does not provide correct
 	 * weekday for 2000-01-01. Correct the erroneous sunday to saturday.
 	 */
-	if (ldata->hw_designer == AMBA_VENDOR_ST) {
+	if (vendor->st_weekday) {
 		if (readl(ldata->base + RTC_YDR) == 0x2000) {
 			time = readl(ldata->base + RTC_DR);
 			if ((time &
@@ -361,7 +375,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
 	}
 
 	if (request_irq(adev->irq[0], pl031_interrupt,
-			0, "rtc-pl031", ldata)) {
+			vendor->irqflags, "rtc-pl031", ldata)) {
 		ret = -EIO;
 		goto out_no_irq;
 	}
@@ -383,48 +397,65 @@ err_req:
 }
 
 /* Operations for the original ARM version */
-static struct rtc_class_ops arm_pl031_ops = {
-	.read_time = pl031_read_time,
-	.set_time = pl031_set_time,
-	.read_alarm = pl031_read_alarm,
-	.set_alarm = pl031_set_alarm,
-	.alarm_irq_enable = pl031_alarm_irq_enable,
+static struct pl031_vendor_data arm_pl031 = {
+	.ops = {
+		.read_time = pl031_read_time,
+		.set_time = pl031_set_time,
+		.read_alarm = pl031_read_alarm,
+		.set_alarm = pl031_set_alarm,
+		.alarm_irq_enable = pl031_alarm_irq_enable,
+	},
+	.irqflags = IRQF_NO_SUSPEND,
 };
 
 /* The First ST derivative */
-static struct rtc_class_ops stv1_pl031_ops = {
-	.read_time = pl031_read_time,
-	.set_time = pl031_set_time,
-	.read_alarm = pl031_read_alarm,
-	.set_alarm = pl031_set_alarm,
-	.alarm_irq_enable = pl031_alarm_irq_enable,
+static struct pl031_vendor_data stv1_pl031 = {
+	.ops = {
+		.read_time = pl031_read_time,
+		.set_time = pl031_set_time,
+		.read_alarm = pl031_read_alarm,
+		.set_alarm = pl031_set_alarm,
+		.alarm_irq_enable = pl031_alarm_irq_enable,
+	},
+	.clockwatch = true,
+	.st_weekday = true,
+	.irqflags = IRQF_NO_SUSPEND,
 };
 
 /* And the second ST derivative */
-static struct rtc_class_ops stv2_pl031_ops = {
-	.read_time = pl031_stv2_read_time,
-	.set_time = pl031_stv2_set_time,
-	.read_alarm = pl031_stv2_read_alarm,
-	.set_alarm = pl031_stv2_set_alarm,
-	.alarm_irq_enable = pl031_alarm_irq_enable,
+static struct pl031_vendor_data stv2_pl031 = {
+	.ops = {
+		.read_time = pl031_stv2_read_time,
+		.set_time = pl031_stv2_set_time,
+		.read_alarm = pl031_stv2_read_alarm,
+		.set_alarm = pl031_stv2_set_alarm,
+		.alarm_irq_enable = pl031_alarm_irq_enable,
+	},
+	.clockwatch = true,
+	.st_weekday = true,
+	/*
+	 * This variant shares the IRQ with another block and must not
+	 * suspend that IRQ line.
+	 */
+	.irqflags = IRQF_SHARED | IRQF_NO_SUSPEND,
 };
 
 static struct amba_id pl031_ids[] = {
 	{
 		.id = 0x00041031,
 		.mask = 0x000fffff,
-		.data = &arm_pl031_ops,
+		.data = &arm_pl031,
 	},
 	/* ST Micro variants */
 	{
 		.id = 0x00180031,
 		.mask = 0x00ffffff,
-		.data = &stv1_pl031_ops,
+		.data = &stv1_pl031,
 	},
 	{
 		.id = 0x00280031,
 		.mask = 0x00ffffff,
-		.data = &stv2_pl031_ops,
+		.data = &stv2_pl031,
 	},
 	{0, 0},
 };
diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c
index 33b6ba0..2c183eb 100644
--- a/drivers/rtc/rtc-r9701.c
+++ b/drivers/rtc/rtc-r9701.c
@@ -138,8 +138,7 @@ static int __devinit r9701_probe(struct spi_device *spi)
 	 * contain invalid values. If so, try to write a default date:
 	 * 2000/1/1 00:00:00
 	 */
-	r9701_get_datetime(&spi->dev, &dt);
-	if (rtc_valid_tm(&dt)) {
+	if (r9701_get_datetime(&spi->dev, &dt)) {
 		dev_info(&spi->dev, "trying to repair invalid date/time\n");
 		dt.tm_sec  = 0;
 		dt.tm_min  = 0;
@@ -148,7 +147,8 @@ static int __devinit r9701_probe(struct spi_device *spi)
 		dt.tm_mon  = 0;
 		dt.tm_year = 100;
 
-		if (r9701_set_datetime(&spi->dev, &dt)) {
+		if (r9701_set_datetime(&spi->dev, &dt) ||
+				r9701_get_datetime(&spi->dev, &dt)) {
 			dev_err(&spi->dev, "cannot repair RTC register\n");
 			return -ENODEV;
 		}
diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c
index 1f76320..e278547 100644
--- a/drivers/rtc/rtc-spear.c
+++ b/drivers/rtc/rtc-spear.c
@@ -458,12 +458,12 @@ static int __devexit spear_rtc_remove(struct platform_device *pdev)
 	clk_disable(config->clk);
 	clk_put(config->clk);
 	iounmap(config->ioaddr);
-	kfree(config);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res)
 		release_mem_region(res->start, resource_size(res));
 	platform_set_drvdata(pdev, NULL);
 	rtc_device_unregister(config->rtc);
+	kfree(config);
 
 	return 0;
 }
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 30f29a0..3fcc000 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -654,16 +654,6 @@ sclp_remove_processed(struct sccb_header *sccb)
 
 EXPORT_SYMBOL(sclp_remove_processed);
 
-struct init_sccb {
-	struct sccb_header header;
-	u16 _reserved;
-	u16 mask_length;
-	sccb_mask_t receive_mask;
-	sccb_mask_t send_mask;
-	sccb_mask_t sclp_receive_mask;
-	sccb_mask_t sclp_send_mask;
-} __attribute__((packed));
-
 /* Prepare init mask request. Called while sclp_lock is locked. */
 static inline void
 __sclp_make_init_req(u32 receive_mask, u32 send_mask)
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 49a1bb5..d7e97ae 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -88,6 +88,16 @@ struct sccb_header {
 	u16	response_code;
 } __attribute__((packed));
 
+struct init_sccb {
+	struct sccb_header header;
+	u16 _reserved;
+	u16 mask_length;
+	sccb_mask_t receive_mask;
+	sccb_mask_t send_mask;
+	sccb_mask_t sclp_receive_mask;
+	sccb_mask_t sclp_send_mask;
+} __attribute__((packed));
+
 extern u64 sclp_facilities;
 #define SCLP_HAS_CHP_INFO	(sclp_facilities & 0x8000000000000000ULL)
 #define SCLP_HAS_CHP_RECONFIG	(sclp_facilities & 0x2000000000000000ULL)
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 766cb7b..71ea923c 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -48,6 +48,7 @@ struct read_info_sccb {
 	u8	_reserved5[4096 - 112];	/* 112-4095 */
 } __attribute__((packed, aligned(PAGE_SIZE)));
 
+static struct init_sccb __initdata early_event_mask_sccb __aligned(PAGE_SIZE);
 static struct read_info_sccb __initdata early_read_info_sccb;
 static int __initdata early_read_info_sccb_valid;
 
@@ -104,6 +105,19 @@ static void __init sclp_read_info_early(void)
 	}
 }
 
+static void __init sclp_event_mask_early(void)
+{
+	struct init_sccb *sccb = &early_event_mask_sccb;
+	int rc;
+
+	do {
+		memset(sccb, 0, sizeof(*sccb));
+		sccb->header.length = sizeof(*sccb);
+		sccb->mask_length = sizeof(sccb_mask_t);
+		rc = sclp_cmd_sync_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb);
+	} while (rc == -EBUSY);
+}
+
 void __init sclp_facilities_detect(void)
 {
 	struct read_info_sccb *sccb;
@@ -119,6 +133,30 @@ void __init sclp_facilities_detect(void)
 	rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
 	rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
 	rzm <<= 20;
+
+	sclp_event_mask_early();
+}
+
+bool __init sclp_has_linemode(void)
+{
+	struct init_sccb *sccb = &early_event_mask_sccb;
+
+	if (sccb->header.response_code != 0x20)
+		return 0;
+	if (sccb->sclp_send_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))
+		return 1;
+	return 0;
+}
+
+bool __init sclp_has_vt220(void)
+{
+	struct init_sccb *sccb = &early_event_mask_sccb;
+
+	if (sccb->header.response_code != 0x20)
+		return 0;
+	if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK)
+		return 1;
+	return 0;
 }
 
 unsigned long long sclp_get_rnmax(void)
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 524d988..5138fc9 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -656,10 +656,19 @@ static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver,
 	len = strlen(buf);
 	return len;
 }
-
-
 static DRIVER_ATTR(recording_status, 0444, vmlogrdr_recording_status_show,
 		   NULL);
+static struct attribute *vmlogrdr_drv_attrs[] = {
+	&driver_attr_recording_status.attr,
+	NULL,
+};
+static struct attribute_group vmlogrdr_drv_attr_group = {
+	.attrs = vmlogrdr_drv_attrs,
+};
+static const struct attribute_group *vmlogrdr_drv_attr_groups[] = {
+	&vmlogrdr_drv_attr_group,
+	NULL,
+};
 
 static struct attribute *vmlogrdr_attrs[] = {
 	&dev_attr_autopurge.attr,
@@ -668,6 +677,13 @@ static struct attribute *vmlogrdr_attrs[] = {
 	&dev_attr_recording.attr,
 	NULL,
 };
+static struct attribute_group vmlogrdr_attr_group = {
+	.attrs = vmlogrdr_attrs,
+};
+static const struct attribute_group *vmlogrdr_attr_groups[] = {
+	&vmlogrdr_attr_group,
+	NULL,
+};
 
 static int vmlogrdr_pm_prepare(struct device *dev)
 {
@@ -692,18 +708,14 @@ static const struct dev_pm_ops vmlogrdr_pm_ops = {
 	.prepare = vmlogrdr_pm_prepare,
 };
 
-static struct attribute_group vmlogrdr_attr_group = {
-	.attrs = vmlogrdr_attrs,
-};
-
 static struct class *vmlogrdr_class;
 static struct device_driver vmlogrdr_driver = {
 	.name = "vmlogrdr",
 	.bus  = &iucv_bus,
 	.pm = &vmlogrdr_pm_ops,
+	.groups = vmlogrdr_drv_attr_groups,
 };
 
-
 static int vmlogrdr_register_driver(void)
 {
 	int ret;
@@ -717,21 +729,14 @@ static int vmlogrdr_register_driver(void)
 	if (ret)
 		goto out_iucv;
 
-	ret = driver_create_file(&vmlogrdr_driver,
-				 &driver_attr_recording_status);
-	if (ret)
-		goto out_driver;
-
 	vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr");
 	if (IS_ERR(vmlogrdr_class)) {
 		ret = PTR_ERR(vmlogrdr_class);
 		vmlogrdr_class = NULL;
-		goto out_attr;
+		goto out_driver;
 	}
 	return 0;
 
-out_attr:
-	driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
 out_driver:
 	driver_unregister(&vmlogrdr_driver);
 out_iucv:
@@ -745,7 +750,6 @@ static void vmlogrdr_unregister_driver(void)
 {
 	class_destroy(vmlogrdr_class);
 	vmlogrdr_class = NULL;
-	driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
 	driver_unregister(&vmlogrdr_driver);
 	iucv_unregister(&vmlogrdr_iucv_handler, 1);
 }
@@ -762,6 +766,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
 		dev->bus = &iucv_bus;
 		dev->parent = iucv_root;
 		dev->driver = &vmlogrdr_driver;
+		dev->groups = vmlogrdr_attr_groups;
 		dev_set_drvdata(dev, priv);
 		/*
 		 * The release function could be called after the
@@ -779,11 +784,6 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
 		return ret;
 	}
 
-	ret = sysfs_create_group(&dev->kobj, &vmlogrdr_attr_group);
-	if (ret) {
-		device_unregister(dev);
-		return ret;
-	}
 	priv->class_device = device_create(vmlogrdr_class, dev,
 					   MKDEV(vmlogrdr_major,
 						 priv->minor_num),
@@ -791,7 +791,6 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
 	if (IS_ERR(priv->class_device)) {
 		ret = PTR_ERR(priv->class_device);
 		priv->class_device=NULL;
-		sysfs_remove_group(&dev->kobj, &vmlogrdr_attr_group);
 		device_unregister(dev);
 		return ret;
 	}
@@ -804,7 +803,6 @@ static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv)
 {
 	device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));
 	if (priv->device != NULL) {
-		sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group);
 		device_unregister(priv->device);
 		priv->device=NULL;
 	}
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index e792436..9b05480 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -362,10 +362,13 @@ static struct attribute *chp_attrs[] = {
 	&dev_attr_shared.attr,
 	NULL,
 };
-
 static struct attribute_group chp_attr_group = {
 	.attrs = chp_attrs,
 };
+static const struct attribute_group *chp_attr_groups[] = {
+	&chp_attr_group,
+	NULL,
+};
 
 static void chp_release(struct device *dev)
 {
@@ -397,6 +400,7 @@ int chp_new(struct chp_id chpid)
 	chp->chpid = chpid;
 	chp->state = 1;
 	chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
+	chp->dev.groups = chp_attr_groups;
 	chp->dev.release = chp_release;
 	mutex_init(&chp->lock);
 
@@ -426,16 +430,10 @@ int chp_new(struct chp_id chpid)
 		put_device(&chp->dev);
 		goto out;
 	}
-	ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
-	if (ret) {
-		device_unregister(&chp->dev);
-		goto out;
-	}
 	mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
 	if (channel_subsystems[chpid.cssid]->cm_enabled) {
 		ret = chp_add_cmg_attr(chp);
 		if (ret) {
-			sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
 			device_unregister(&chp->dev);
 			mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
 			goto out;
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index d74e9ae..d3bdae4 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -25,6 +25,7 @@
 #include <asm/io.h>
 #include <asm/kvm_para.h>
 #include <asm/kvm_virtio.h>
+#include <asm/sclp.h>
 #include <asm/setup.h>
 #include <asm/irq.h>
 
@@ -468,7 +469,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count)
 
 static int __init s390_virtio_console_init(void)
 {
-	if (!MACHINE_IS_KVM)
+	if (sclp_has_vt220() || sclp_has_linemode())
 		return -ENODEV;
 	return virtio_cons_early_init(early_put_chars);
 }
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index e955978..6c810db 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -263,23 +263,6 @@ config SCSI_SCAN_ASYNC
 	  You can override this choice by specifying "scsi_mod.scan=sync"
 	  or async on the kernel's command line.
 
-config SCSI_WAIT_SCAN
-	tristate  # No prompt here, this is an invisible symbol.
-	default m
-	depends on SCSI
-	depends on MODULES
-# scsi_wait_scan is a loadable module which waits until all the async scans are
-# complete.  The idea is to use it in initrd/ initramfs scripts.  You modprobe
-# it after all the modprobes of the root SCSI drivers and it will wait until
-# they have all finished scanning their buses before allowing the boot to
-# proceed.  (This method is not applicable if targets boot independently in
-# parallel with the initiator, or with transports with non-deterministic target
-# discovery schemes, or if a transport driver does not support scsi_wait_scan.)
-#
-# This symbol is not exposed as a prompt because little is to be gained by
-# disabling it, whereas people who accidentally switch it off may wonder why
-# their mkinitrd gets into trouble.
-
 menu "SCSI Transports"
 	depends on SCSI
 
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 1a3368b..888f73a 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -159,8 +159,6 @@ obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/
 # This goes last, so that "real" scsi devices probe earlier
 obj-$(CONFIG_SCSI_DEBUG)	+= scsi_debug.o
 
-obj-$(CONFIG_SCSI_WAIT_SCAN)	+= scsi_wait_scan.o
-
 scsi_mod-y			+= scsi.o hosts.o scsi_ioctl.o constants.o \
 				   scsicam.o scsi_error.o scsi_lib.o
 scsi_mod-$(CONFIG_SCSI_DMA)	+= scsi_lib_dma.o
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index cbde1dc..def24a1 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -2821,7 +2821,7 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
 	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++) {
@@ -2839,7 +2839,7 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
 			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));
+		} while (((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);
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 68ce085..a540162 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -1173,7 +1173,16 @@ wait_io1:
 	outw(val, tmport);
 	outb(2, 0x80);
 TCM_SYNC:
-	udelay(0x800);
+	/*
+	 * The funny division into multiple delays is to accomodate
+	 * arches like ARM where udelay() multiplies its argument by
+	 * a large number to initialize a loop counter.  To avoid
+	 * overflow, the maximum supported udelay is 2000 microseconds.
+	 *
+	 * XXX it would be more polite to find a way to use msleep()
+	 */
+	mdelay(2);
+	udelay(48);
 	if ((inb(tmport) & 0x80) == 0x00) {	/* bsy ? */
 		outw(0, tmport--);
 		outb(0, tmport);
diff --git a/drivers/scsi/bnx2fc/Makefile b/drivers/scsi/bnx2fc/Makefile
index a92695a..141149e 100644
--- a/drivers/scsi/bnx2fc/Makefile
+++ b/drivers/scsi/bnx2fc/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_SCSI_BNX2X_FCOE) += bnx2fc.o
 
-bnx2fc-y := bnx2fc_els.o bnx2fc_fcoe.o bnx2fc_hwi.o bnx2fc_io.o bnx2fc_tgt.o
+bnx2fc-y := bnx2fc_els.o bnx2fc_fcoe.o bnx2fc_hwi.o bnx2fc_io.o bnx2fc_tgt.o \
+	    bnx2fc_debug.o
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 0578fa0d..5147475 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -11,6 +11,8 @@
  * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
@@ -57,12 +59,11 @@
 #include <scsi/fc/fc_fcp.h>
 
 #include "57xx_hsi_bnx2fc.h"
-#include "bnx2fc_debug.h"
 #include "../../net/ethernet/broadcom/cnic_if.h"
 #include "bnx2fc_constants.h"
 
 #define BNX2FC_NAME		"bnx2fc"
-#define BNX2FC_VERSION		"1.0.11"
+#define BNX2FC_VERSION		"1.0.12"
 
 #define PFX			"bnx2fc: "
 
@@ -274,6 +275,7 @@ struct bnx2fc_rport {
 #define BNX2FC_FLAG_CTX_ALLOC_FAILURE	0x6
 #define BNX2FC_FLAG_UPLD_REQ_COMPL	0x7
 #define BNX2FC_FLAG_EXPL_LOGO		0x8
+#define BNX2FC_FLAG_DISABLE_FAILED	0x9
 
 	u8 src_addr[ETH_ALEN];
 	u32 max_sqes;
@@ -554,4 +556,7 @@ void bnx2fc_process_seq_cleanup_compl(struct bnx2fc_cmd *seq_clnup_req,
 int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset,
 				enum fc_rctl r_ctl);
 
+
+#include "bnx2fc_debug.h"
+
 #endif
diff --git a/drivers/scsi/bnx2fc/bnx2fc_debug.c b/drivers/scsi/bnx2fc/bnx2fc_debug.c
new file mode 100644
index 0000000..0cbee1b
--- /dev/null
+++ b/drivers/scsi/bnx2fc/bnx2fc_debug.c
@@ -0,0 +1,70 @@
+#include "bnx2fc.h"
+
+void BNX2FC_IO_DBG(const struct bnx2fc_cmd *io_req, const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	if (likely(!(bnx2fc_debug_level & LOG_IO)))
+		return;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	if (io_req && io_req->port && io_req->port->lport &&
+	    io_req->port->lport->host)
+		shost_printk(KERN_INFO, io_req->port->lport->host,
+			     PFX "xid:0x%x %pV",
+			     io_req->xid, &vaf);
+	else
+		pr_info("NULL %pV", &vaf);
+
+	va_end(args);
+}
+
+void BNX2FC_TGT_DBG(const struct bnx2fc_rport *tgt, const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	if (likely(!(bnx2fc_debug_level & LOG_TGT)))
+		return;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	if (tgt && tgt->port && tgt->port->lport && tgt->port->lport->host &&
+	    tgt->rport)
+		shost_printk(KERN_INFO, tgt->port->lport->host,
+			     PFX "port:%x %pV",
+			     tgt->rport->port_id, &vaf);
+	else
+		pr_info("NULL %pV", &vaf);
+
+	va_end(args);
+}
+
+void BNX2FC_HBA_DBG(const struct fc_lport *lport, const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	if (likely(!(bnx2fc_debug_level & LOG_HBA)))
+		return;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	if (lport && lport->host)
+		shost_printk(KERN_INFO, lport->host, PFX "%pV", &vaf);
+	else
+		pr_info("NULL %pV", &vaf);
+
+	va_end(args);
+}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_debug.h b/drivers/scsi/bnx2fc/bnx2fc_debug.h
index 3416d9a..4808ff9 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_debug.h
+++ b/drivers/scsi/bnx2fc/bnx2fc_debug.h
@@ -11,60 +11,23 @@
 
 extern unsigned int bnx2fc_debug_level;
 
-#define BNX2FC_CHK_LOGGING(LEVEL, CMD)					\
-	do {								\
-		if (unlikely(bnx2fc_debug_level & LEVEL))		\
-			do {						\
-				CMD;					\
-			} while (0);					\
-	} while (0)
-
-#define BNX2FC_ELS_DBG(fmt, arg...)					\
-	BNX2FC_CHK_LOGGING(LOG_ELS,					\
-			   printk(KERN_INFO PFX fmt, ##arg))
-
-#define BNX2FC_MISC_DBG(fmt, arg...)					\
-	BNX2FC_CHK_LOGGING(LOG_MISC,					\
-			   printk(KERN_INFO PFX fmt, ##arg))
-
-#define BNX2FC_IO_DBG(io_req, fmt, arg...)				\
-	do {								\
-		if (!io_req || !io_req->port || !io_req->port->lport ||	\
-		    !io_req->port->lport->host)				\
-			BNX2FC_CHK_LOGGING(LOG_IO,			\
-			   printk(KERN_INFO PFX "NULL " fmt, ##arg));	\
-		else							\
-			BNX2FC_CHK_LOGGING(LOG_IO,			\
-			   shost_printk(KERN_INFO,			\
-				   (io_req)->port->lport->host,		\
-				   PFX "xid:0x%x " fmt,			\
-				   (io_req)->xid, ##arg));		\
-	} while (0)
-
-#define BNX2FC_TGT_DBG(tgt, fmt, arg...)				\
-	do {								\
-		if (!tgt || !tgt->port || !tgt->port->lport ||		\
-		    !tgt->port->lport->host || !tgt->rport)		\
-			BNX2FC_CHK_LOGGING(LOG_TGT,			\
-			   printk(KERN_INFO PFX "NULL " fmt, ##arg));	\
-		else							\
-			BNX2FC_CHK_LOGGING(LOG_TGT,			\
-			   shost_printk(KERN_INFO,			\
-				   (tgt)->port->lport->host,		\
-				   PFX "port:%x " fmt,			\
-				   (tgt)->rport->port_id, ##arg));	\
-	} while (0)
-
-
-#define BNX2FC_HBA_DBG(lport, fmt, arg...)				\
-	do {								\
-		if (!lport || !lport->host)				\
-			BNX2FC_CHK_LOGGING(LOG_HBA,			\
-			   printk(KERN_INFO PFX "NULL " fmt, ##arg));	\
-		else							\
-			BNX2FC_CHK_LOGGING(LOG_HBA,			\
-			   shost_printk(KERN_INFO, lport->host,	\
-				   PFX fmt, ##arg));			\
-	} while (0)
+#define BNX2FC_ELS_DBG(fmt, ...)				\
+do {								\
+	if (unlikely(bnx2fc_debug_level & LOG_ELS))		\
+		pr_info(fmt, ##__VA_ARGS__);			\
+} while (0)
+
+#define BNX2FC_MISC_DBG(fmt, ...)				\
+do {								\
+	if (unlikely(bnx2fc_debug_level & LOG_MISC))		\
+		pr_info(fmt, ##__VA_ARGS__);			\
+} while (0)
+
+__printf(2, 3)
+void BNX2FC_IO_DBG(const struct bnx2fc_cmd *io_req, const char *fmt, ...);
+__printf(2, 3)
+void BNX2FC_TGT_DBG(const struct bnx2fc_rport *tgt, const char *fmt, ...);
+__printf(2, 3)
+void BNX2FC_HBA_DBG(const struct fc_lport *lport, const char *fmt, ...);
 
 #endif
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index f52f668f..72a82c5 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -22,7 +22,7 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu);
 
 #define DRV_MODULE_NAME		"bnx2fc"
 #define DRV_MODULE_VERSION	BNX2FC_VERSION
-#define DRV_MODULE_RELDATE	"Apr 24, 2012"
+#define DRV_MODULE_RELDATE	"Jun 04, 2012"
 
 
 static char version[] __devinitdata =
@@ -286,7 +286,7 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
 	struct fcoe_port	*port;
 	struct fcoe_hdr		*hp;
 	struct bnx2fc_rport	*tgt;
-	struct fcoe_dev_stats	*stats;
+	struct fc_stats		*stats;
 	u8			sof, eof;
 	u32			crc;
 	unsigned int		hlen, tlen, elen;
@@ -412,7 +412,7 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
 	}
 
 	/*update tx stats */
-	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+	stats = per_cpu_ptr(lport->stats, get_cpu());
 	stats->TxFrames++;
 	stats->TxWords += wlen;
 	put_cpu();
@@ -522,7 +522,7 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
 	u32 fr_len;
 	struct fc_lport *lport;
 	struct fcoe_rcv_info *fr;
-	struct fcoe_dev_stats *stats;
+	struct fc_stats *stats;
 	struct fc_frame_header *fh;
 	struct fcoe_crc_eof crc_eof;
 	struct fc_frame *fp;
@@ -551,7 +551,7 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
 	skb_pull(skb, sizeof(struct fcoe_hdr));
 	fr_len = skb->len - sizeof(struct fcoe_crc_eof);
 
-	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+	stats = per_cpu_ptr(lport->stats, get_cpu());
 	stats->RxFrames++;
 	stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
 
@@ -942,7 +942,7 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
 							FC_PORTTYPE_UNKNOWN;
 			mutex_unlock(&lport->lp_mutex);
 			fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
-			per_cpu_ptr(lport->dev_stats,
+			per_cpu_ptr(lport->stats,
 				    get_cpu())->LinkFailureCount++;
 			put_cpu();
 			fcoe_clean_pending_queue(lport);
@@ -2019,11 +2019,11 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
 	struct fcoe_ctlr *ctlr;
 	struct bnx2fc_interface *interface;
 	struct bnx2fc_hba *hba;
-	struct net_device *phys_dev;
+	struct net_device *phys_dev = netdev;
 	struct fc_lport *lport;
 	struct ethtool_drvinfo drvinfo;
 	int rc = 0;
-	int vlan_id;
+	int vlan_id = 0;
 
 	BNX2FC_MISC_DBG("Entered bnx2fc_create\n");
 	if (fip_mode != FIP_MODE_FABRIC) {
@@ -2041,14 +2041,9 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
 	}
 
 	/* obtain physical netdev */
-	if (netdev->priv_flags & IFF_802_1Q_VLAN) {
+	if (netdev->priv_flags & IFF_802_1Q_VLAN)
 		phys_dev = vlan_dev_real_dev(netdev);
-		vlan_id = vlan_dev_vlan_id(netdev);
-	} else {
-		printk(KERN_ERR PFX "Not a vlan device\n");
-		rc = -EINVAL;
-		goto netdev_err;
-	}
+
 	/* verify if the physical device is a netxtreme2 device */
 	if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) {
 		memset(&drvinfo, 0, sizeof(drvinfo));
@@ -2083,9 +2078,13 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
 		goto ifput_err;
 	}
 
+	if (netdev->priv_flags & IFF_802_1Q_VLAN) {
+		vlan_id = vlan_dev_vlan_id(netdev);
+		interface->vlan_enabled = 1;
+	}
+
 	ctlr = bnx2fc_to_ctlr(interface);
 	interface->vlan_id = vlan_id;
-	interface->vlan_enabled = 1;
 
 	interface->timer_work_queue =
 			create_singlethread_workqueue("bnx2fc_timer_wq");
@@ -2152,13 +2151,10 @@ mod_err:
  **/
 static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic)
 {
-	struct list_head *list;
-	struct list_head *temp;
 	struct bnx2fc_hba *hba;
 
 	/* Called with bnx2fc_dev_lock held */
-	list_for_each_safe(list, temp, &adapter_list) {
-		hba = (struct bnx2fc_hba *)list;
+	list_for_each_entry(hba, &adapter_list, list) {
 		if (hba->cnic == cnic)
 			return hba;
 	}
@@ -2252,15 +2248,17 @@ static int bnx2fc_fcoe_reset(struct Scsi_Host *shost)
 
 static bool bnx2fc_match(struct net_device *netdev)
 {
+	struct net_device *phys_dev = netdev;
+
 	mutex_lock(&bnx2fc_dev_lock);
-	if (netdev->priv_flags & IFF_802_1Q_VLAN) {
-		struct net_device *phys_dev = vlan_dev_real_dev(netdev);
+	if (netdev->priv_flags & IFF_802_1Q_VLAN)
+		phys_dev = vlan_dev_real_dev(netdev);
 
-		if (bnx2fc_hba_lookup(phys_dev)) {
-			mutex_unlock(&bnx2fc_dev_lock);
-			return true;
-		}
+	if (bnx2fc_hba_lookup(phys_dev)) {
+		mutex_unlock(&bnx2fc_dev_lock);
+		return true;
 	}
+
 	mutex_unlock(&bnx2fc_dev_lock);
 	return false;
 }
@@ -2290,9 +2288,9 @@ static void bnx2fc_percpu_thread_create(unsigned int cpu)
 
 	p = &per_cpu(bnx2fc_percpu, cpu);
 
-	thread = kthread_create(bnx2fc_percpu_io_thread,
-				(void *)p,
-				"bnx2fc_thread/%d", cpu);
+	thread = kthread_create_on_node(bnx2fc_percpu_io_thread,
+					(void *)p, cpu_to_node(cpu),
+					"bnx2fc_thread/%d", cpu);
 	/* bind thread to the cpu */
 	if (likely(!IS_ERR(thread))) {
 		kthread_bind(thread, cpu);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index 2ca6bfe..6d6eee4 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -1244,7 +1244,9 @@ static void bnx2fc_process_conn_disable_cmpl(struct bnx2fc_hba *hba,
 	if (disable_kcqe->completion_status) {
 		printk(KERN_ERR PFX "Disable failed with cmpl status %d\n",
 			disable_kcqe->completion_status);
-		return;
+		set_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags);
+		set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags);
+		wake_up_interruptible(&tgt->upld_wait);
 	} else {
 		/* disable successful */
 		BNX2FC_TGT_DBG(tgt, "disable successful\n");
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 4f7453b..73f231c 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -405,11 +405,10 @@ free_cmd_pool:
 		goto free_cmgr;
 
 	for (i = 0; i < num_possible_cpus() + 1; i++)  {
-		struct list_head *list;
-		struct list_head *tmp;
+		struct bnx2fc_cmd *tmp, *io_req;
 
-		list_for_each_safe(list, tmp, &cmgr->free_list[i]) {
-			struct bnx2fc_cmd *io_req = (struct bnx2fc_cmd *)list;
+		list_for_each_entry_safe(io_req, tmp,
+					 &cmgr->free_list[i], link) {
 			list_del(&io_req->link);
 			kfree(io_req);
 		}
@@ -1436,9 +1435,7 @@ static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req)
 {
 	struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
 	struct bnx2fc_rport *tgt = io_req->tgt;
-	struct list_head *list;
-	struct list_head *tmp;
-	struct bnx2fc_cmd *cmd;
+	struct bnx2fc_cmd *cmd, *tmp;
 	int tm_lun = sc_cmd->device->lun;
 	int rc = 0;
 	int lun;
@@ -1449,9 +1446,8 @@ static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req)
 	 * Walk thru the active_ios queue and ABORT the IO
 	 * that matches with the LUN that was reset
 	 */
-	list_for_each_safe(list, tmp, &tgt->active_cmd_queue) {
+	list_for_each_entry_safe(cmd, tmp, &tgt->active_cmd_queue, link) {
 		BNX2FC_TGT_DBG(tgt, "LUN RST cmpl: scan for pending IOs\n");
-		cmd = (struct bnx2fc_cmd *)list;
 		lun = cmd->sc_cmd->device->lun;
 		if (lun == tm_lun) {
 			/* Initiate ABTS on this cmd */
@@ -1476,9 +1472,7 @@ static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req)
 static void bnx2fc_tgt_reset_cmpl(struct bnx2fc_cmd *io_req)
 {
 	struct bnx2fc_rport *tgt = io_req->tgt;
-	struct list_head *list;
-	struct list_head *tmp;
-	struct bnx2fc_cmd *cmd;
+	struct bnx2fc_cmd *cmd, *tmp;
 	int rc = 0;
 
 	/* called with tgt_lock held */
@@ -1487,9 +1481,8 @@ static void bnx2fc_tgt_reset_cmpl(struct bnx2fc_cmd *io_req)
 	 * Walk thru the active_ios queue and ABORT the IO
 	 * that matches with the LUN that was reset
 	 */
-	list_for_each_safe(list, tmp, &tgt->active_cmd_queue) {
+	list_for_each_entry_safe(cmd, tmp, &tgt->active_cmd_queue, link) {
 		BNX2FC_TGT_DBG(tgt, "TGT RST cmpl: scan for pending IOs\n");
-		cmd = (struct bnx2fc_cmd *)list;
 		/* Initiate ABTS */
 		if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS,
 							&cmd->req_flags)) {
@@ -1980,7 +1973,7 @@ int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
 	struct bnx2fc_interface *interface = port->priv;
 	struct bnx2fc_hba *hba = interface->hba;
 	struct fc_lport *lport = port->lport;
-	struct fcoe_dev_stats *stats;
+	struct fc_stats *stats;
 	int task_idx, index;
 	u16 xid;
 
@@ -1991,7 +1984,7 @@ int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
 	io_req->data_xfer_len = scsi_bufflen(sc_cmd);
 	sc_cmd->SCp.ptr = (char *)io_req;
 
-	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+	stats = per_cpu_ptr(lport->stats, get_cpu());
 	if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		io_req->io_req_flags = BNX2FC_READ;
 		stats->InputRequests++;
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
index 082a25c..b9d0d9c 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
@@ -150,8 +150,7 @@ tgt_init_err:
 void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
 {
 	struct bnx2fc_cmd *io_req;
-	struct list_head *list;
-	struct list_head *tmp;
+	struct bnx2fc_cmd *tmp;
 	int rc;
 	int i = 0;
 	BNX2FC_TGT_DBG(tgt, "Entered flush_active_ios - %d\n",
@@ -160,9 +159,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
 	spin_lock_bh(&tgt->tgt_lock);
 	tgt->flush_in_prog = 1;
 
-	list_for_each_safe(list, tmp, &tgt->active_cmd_queue) {
+	list_for_each_entry_safe(io_req, tmp, &tgt->active_cmd_queue, link) {
 		i++;
-		io_req = (struct bnx2fc_cmd *)list;
 		list_del_init(&io_req->link);
 		io_req->on_active_queue = 0;
 		BNX2FC_IO_DBG(io_req, "cmd_queue cleanup\n");
@@ -181,13 +179,18 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
 
 		set_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags);
 		set_bit(BNX2FC_FLAG_IO_CLEANUP, &io_req->req_flags);
-		rc = bnx2fc_initiate_cleanup(io_req);
-		BUG_ON(rc);
+
+		/* Do not issue cleanup when disable request failed */
+		if (test_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags))
+			bnx2fc_process_cleanup_compl(io_req, io_req->task, 0);
+		else {
+			rc = bnx2fc_initiate_cleanup(io_req);
+			BUG_ON(rc);
+		}
 	}
 
-	list_for_each_safe(list, tmp, &tgt->active_tm_queue) {
+	list_for_each_entry_safe(io_req, tmp, &tgt->active_tm_queue, link) {
 		i++;
-		io_req = (struct bnx2fc_cmd *)list;
 		list_del_init(&io_req->link);
 		io_req->on_tmf_queue = 0;
 		BNX2FC_IO_DBG(io_req, "tm_queue cleanup\n");
@@ -195,9 +198,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
 			complete(&io_req->tm_done);
 	}
 
-	list_for_each_safe(list, tmp, &tgt->els_queue) {
+	list_for_each_entry_safe(io_req, tmp, &tgt->els_queue, link) {
 		i++;
-		io_req = (struct bnx2fc_cmd *)list;
 		list_del_init(&io_req->link);
 		io_req->on_active_queue = 0;
 
@@ -212,13 +214,17 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
 			io_req->cb_arg = NULL;
 		}
 
-		rc = bnx2fc_initiate_cleanup(io_req);
-		BUG_ON(rc);
+		/* Do not issue cleanup when disable request failed */
+		if (test_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags))
+			bnx2fc_process_cleanup_compl(io_req, io_req->task, 0);
+		else {
+			rc = bnx2fc_initiate_cleanup(io_req);
+			BUG_ON(rc);
+		}
 	}
 
-	list_for_each_safe(list, tmp, &tgt->io_retire_queue) {
+	list_for_each_entry_safe(io_req, tmp, &tgt->io_retire_queue, link) {
 		i++;
-		io_req = (struct bnx2fc_cmd *)list;
 		list_del_init(&io_req->link);
 
 		BNX2FC_IO_DBG(io_req, "retire_queue flush\n");
@@ -321,9 +327,13 @@ static void bnx2fc_upload_session(struct fcoe_port *port,
 
 		del_timer_sync(&tgt->upld_timer);
 
-	} else
+	} else if (test_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags)) {
+		printk(KERN_ERR PFX "ERROR!! DISABLE req failed, destroy"
+				" not sent to FW\n");
+	} else {
 		printk(KERN_ERR PFX "ERROR!! DISABLE req timed out, destroy"
 				" not sent to FW\n");
+	}
 
 	/* Free session resources */
 	bnx2fc_free_session_resc(hba, tgt);
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index fda9cde..0d57382 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -46,13 +46,16 @@
 #define TPGS_SUPPORT_OFFLINE		0x40
 #define TPGS_SUPPORT_TRANSITION		0x80
 
+#define RTPG_FMT_MASK			0x70
+#define RTPG_FMT_EXT_HDR		0x10
+
 #define TPGS_MODE_UNINITIALIZED		 -1
 #define TPGS_MODE_NONE			0x0
 #define TPGS_MODE_IMPLICIT		0x1
 #define TPGS_MODE_EXPLICIT		0x2
 
 #define ALUA_INQUIRY_SIZE		36
-#define ALUA_FAILOVER_TIMEOUT		(60 * HZ)
+#define ALUA_FAILOVER_TIMEOUT		60
 #define ALUA_FAILOVER_RETRIES		5
 
 /* flags passed from user level */
@@ -68,6 +71,7 @@ struct alua_dh_data {
 	unsigned char		inq[ALUA_INQUIRY_SIZE];
 	unsigned char		*buff;
 	int			bufflen;
+	unsigned char		transition_tmo;
 	unsigned char		sense[SCSI_SENSE_BUFFERSIZE];
 	int			senselen;
 	struct scsi_device	*sdev;
@@ -128,7 +132,7 @@ static struct request *get_alua_req(struct scsi_device *sdev,
 	rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
 			 REQ_FAILFAST_DRIVER;
 	rq->retries = ALUA_FAILOVER_RETRIES;
-	rq->timeout = ALUA_FAILOVER_TIMEOUT;
+	rq->timeout = ALUA_FAILOVER_TIMEOUT * HZ;
 
 	return rq;
 }
@@ -174,7 +178,8 @@ done:
  * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
  * @sdev: sdev the command should be sent to
  */
-static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
+static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h,
+			    bool rtpg_ext_hdr_req)
 {
 	struct request *rq;
 	int err = SCSI_DH_RES_TEMP_UNAVAIL;
@@ -185,7 +190,10 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
 
 	/* Prepare the command. */
 	rq->cmd[0] = MAINTENANCE_IN;
-	rq->cmd[1] = MI_REPORT_TARGET_PGS;
+	if (rtpg_ext_hdr_req)
+		rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
+	else
+		rq->cmd[1] = MI_REPORT_TARGET_PGS;
 	rq->cmd[6] = (h->bufflen >> 24) & 0xff;
 	rq->cmd[7] = (h->bufflen >> 16) & 0xff;
 	rq->cmd[8] = (h->bufflen >>  8) & 0xff;
@@ -518,11 +526,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
 	int len, k, off, valid_states = 0;
 	unsigned char *ucp;
 	unsigned err;
-	unsigned long expiry, interval = 1000;
+	bool rtpg_ext_hdr_req = 1;
+	unsigned long expiry, interval = 0;
+	unsigned int tpg_desc_tbl_off;
+	unsigned char orig_transition_tmo;
+
+	if (!h->transition_tmo)
+		expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ);
+	else
+		expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
 
-	expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT);
  retry:
-	err = submit_rtpg(sdev, h);
+	err = submit_rtpg(sdev, h, rtpg_ext_hdr_req);
 
 	if (err == SCSI_DH_IO && h->senselen > 0) {
 		err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
@@ -530,6 +545,21 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
 		if (!err)
 			return SCSI_DH_IO;
 
+		/*
+		 * submit_rtpg() has failed on existing arrays
+		 * when requesting extended header info, and
+		 * the array doesn't support extended headers,
+		 * even though it shouldn't according to T10.
+		 * The retry without rtpg_ext_hdr_req set
+		 * handles this.
+		 */
+		if (rtpg_ext_hdr_req == 1 &&
+		    sense_hdr.sense_key == ILLEGAL_REQUEST &&
+		    sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) {
+			rtpg_ext_hdr_req = 0;
+			goto retry;
+		}
+
 		err = alua_check_sense(sdev, &sense_hdr);
 		if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry))
 			goto retry;
@@ -556,7 +586,28 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
 		goto retry;
 	}
 
-	for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) {
+	orig_transition_tmo = h->transition_tmo;
+	if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && h->buff[5] != 0)
+		h->transition_tmo = h->buff[5];
+	else
+		h->transition_tmo = ALUA_FAILOVER_TIMEOUT;
+
+	if (orig_transition_tmo != h->transition_tmo) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: transition timeout set to %d seconds\n",
+			    ALUA_DH_NAME, h->transition_tmo);
+		expiry = jiffies + h->transition_tmo * HZ;
+	}
+
+	if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
+		tpg_desc_tbl_off = 8;
+	else
+		tpg_desc_tbl_off = 4;
+
+	for (k = tpg_desc_tbl_off, ucp = h->buff + tpg_desc_tbl_off;
+	     k < len;
+	     k += off, ucp += off) {
+
 		if (h->group_id == (ucp[2] << 8) + ucp[3]) {
 			h->state = ucp[0] & 0x0f;
 			h->pref = ucp[0] >> 7;
@@ -581,7 +632,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
 	case TPGS_STATE_TRANSITIONING:
 		if (time_before(jiffies, expiry)) {
 			/* State transition, retry */
-			interval *= 2;
+			interval += 2000;
 			msleep(interval);
 			goto retry;
 		}
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index fe30b1b..2b065d2 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -1529,7 +1529,7 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
 
 	return 0;
 err:
-	per_cpu_ptr(lport->dev_stats, get_cpu())->ErrorFrames++;
+	per_cpu_ptr(lport->stats, get_cpu())->ErrorFrames++;
 	put_cpu();
 err2:
 	kfree_skb(skb);
@@ -1569,7 +1569,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
 	struct ethhdr *eh;
 	struct fcoe_crc_eof *cp;
 	struct sk_buff *skb;
-	struct fcoe_dev_stats *stats;
+	struct fc_stats *stats;
 	struct fc_frame_header *fh;
 	unsigned int hlen;		/* header length implies the version */
 	unsigned int tlen;		/* trailer length */
@@ -1680,7 +1680,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
 		skb_shinfo(skb)->gso_size = 0;
 	}
 	/* update tx stats: regardless if LLD fails */
-	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+	stats = per_cpu_ptr(lport->stats, get_cpu());
 	stats->TxFrames++;
 	stats->TxWords += wlen;
 	put_cpu();
@@ -1714,7 +1714,7 @@ static inline int fcoe_filter_frames(struct fc_lport *lport,
 	struct fcoe_interface *fcoe;
 	struct fc_frame_header *fh;
 	struct sk_buff *skb = (struct sk_buff *)fp;
-	struct fcoe_dev_stats *stats;
+	struct fc_stats *stats;
 
 	/*
 	 * We only check CRC if no offload is available and if it is
@@ -1745,7 +1745,7 @@ static inline int fcoe_filter_frames(struct fc_lport *lport,
 		return 0;
 	}
 
-	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+	stats = per_cpu_ptr(lport->stats, get_cpu());
 	stats->InvalidCRCCount++;
 	if (stats->InvalidCRCCount < 5)
 		printk(KERN_WARNING "fcoe: dropping frame with CRC error\n");
@@ -1762,7 +1762,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)
 	u32 fr_len;
 	struct fc_lport *lport;
 	struct fcoe_rcv_info *fr;
-	struct fcoe_dev_stats *stats;
+	struct fc_stats *stats;
 	struct fcoe_crc_eof crc_eof;
 	struct fc_frame *fp;
 	struct fcoe_port *port;
@@ -1793,7 +1793,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)
 	 */
 	hp = (struct fcoe_hdr *) skb_network_header(skb);
 
-	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+	stats = per_cpu_ptr(lport->stats, get_cpu());
 	if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
 		if (stats->ErrorFrames < 5)
 			printk(KERN_WARNING "fcoe: FCoE version "
@@ -1970,7 +1970,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 	struct fcoe_ctlr *ctlr;
 	struct fcoe_interface *fcoe;
 	struct fcoe_port *port;
-	struct fcoe_dev_stats *stats;
+	struct fc_stats *stats;
 	u32 link_possible = 1;
 	u32 mfs;
 	int rc = NOTIFY_OK;
@@ -2024,7 +2024,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 	if (link_possible && !fcoe_link_ok(lport))
 		fcoe_ctlr_link_up(ctlr);
 	else if (fcoe_ctlr_link_down(ctlr)) {
-		stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+		stats = per_cpu_ptr(lport->stats, get_cpu());
 		stats->LinkFailureCount++;
 		put_cpu();
 		fcoe_clean_pending_queue(lport);
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index d68d572..2ebe03a 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -788,11 +788,11 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
 	unsigned long deadline;
 	unsigned long sel_time = 0;
 	struct list_head del_list;
-	struct fcoe_dev_stats *stats;
+	struct fc_stats *stats;
 
 	INIT_LIST_HEAD(&del_list);
 
-	stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu());
+	stats = per_cpu_ptr(fip->lp->stats, get_cpu());
 
 	list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
 		deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2;
@@ -1104,8 +1104,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
 	struct fc_frame_header *fh = NULL;
 	struct fip_desc *desc;
 	struct fip_encaps *els;
-	struct fcoe_dev_stats *stats;
 	struct fcoe_fcf *sel;
+	struct fc_stats *stats;
 	enum fip_desc_type els_dtype = 0;
 	u8 els_op;
 	u8 sub;
@@ -1249,7 +1249,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
 	fr_dev(fp) = lport;
 	fr_encaps(fp) = els_dtype;
 
-	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+	stats = per_cpu_ptr(lport->stats, get_cpu());
 	stats->RxFrames++;
 	stats->RxWords += skb->len / FIP_BPW;
 	put_cpu();
@@ -1353,7 +1353,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
 						      ntoh24(vp->fd_fc_id));
 			if (vn_port && (vn_port == lport)) {
 				mutex_lock(&fip->ctlr_mutex);
-				per_cpu_ptr(lport->dev_stats,
+				per_cpu_ptr(lport->stats,
 					    get_cpu())->VLinkFailureCount++;
 				put_cpu();
 				fcoe_ctlr_reset(fip);
@@ -1383,8 +1383,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
 		 * followed by physical port
 		 */
 		mutex_lock(&fip->ctlr_mutex);
-		per_cpu_ptr(lport->dev_stats,
-			    get_cpu())->VLinkFailureCount++;
+		per_cpu_ptr(lport->stats, get_cpu())->VLinkFailureCount++;
 		put_cpu();
 		fcoe_ctlr_reset(fip);
 		mutex_unlock(&fip->ctlr_mutex);
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index b46f43d..ac76d8a 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -89,7 +89,7 @@ void __fcoe_get_lesb(struct fc_lport *lport,
 {
 	unsigned int cpu;
 	u32 lfc, vlfc, mdac;
-	struct fcoe_dev_stats *devst;
+	struct fc_stats *stats;
 	struct fcoe_fc_els_lesb *lesb;
 	struct rtnl_link_stats64 temp;
 
@@ -99,10 +99,10 @@ void __fcoe_get_lesb(struct fc_lport *lport,
 	lesb = (struct fcoe_fc_els_lesb *)fc_lesb;
 	memset(lesb, 0, sizeof(*lesb));
 	for_each_possible_cpu(cpu) {
-		devst = per_cpu_ptr(lport->dev_stats, cpu);
-		lfc += devst->LinkFailureCount;
-		vlfc += devst->VLinkFailureCount;
-		mdac += devst->MissDiscAdvCount;
+		stats = per_cpu_ptr(lport->stats, cpu);
+		lfc += stats->LinkFailureCount;
+		vlfc += stats->VLinkFailureCount;
+		mdac += stats->MissDiscAdvCount;
 	}
 	lesb->lesb_link_fail = htonl(lfc);
 	lesb->lesb_vlink_fail = htonl(vlfc);
@@ -502,7 +502,7 @@ static int __init fcoe_transport_init(void)
 	return 0;
 }
 
-static int __exit fcoe_transport_exit(void)
+static int fcoe_transport_exit(void)
 {
 	struct fcoe_transport *ft;
 
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 10b6555..192724e 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -42,7 +42,7 @@ MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");
 
 static char driver_name[] = "hptiop";
 static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
-static const char driver_ver[] = "v1.6 (090910)";
+static const char driver_ver[] = "v1.6 (091225)";
 
 static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
 static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
@@ -958,6 +958,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
 {
 	struct Scsi_Host *host = NULL;
 	struct hptiop_hba *hba;
+	struct hptiop_adapter_ops *iop_ops;
 	struct hpt_iop_request_get_config iop_config;
 	struct hpt_iop_request_set_config set_config;
 	dma_addr_t start_phy;
@@ -978,7 +979,8 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
 	pci_set_master(pcidev);
 
 	/* Enable 64bit DMA if possible */
-	if (pci_set_dma_mask(pcidev, DMA_BIT_MASK(64))) {
+	iop_ops = (struct hptiop_adapter_ops *)id->driver_data;
+	if (pci_set_dma_mask(pcidev, DMA_BIT_MASK(iop_ops->hw_dma_bit_mask))) {
 		if (pci_set_dma_mask(pcidev, DMA_BIT_MASK(32))) {
 			printk(KERN_ERR "hptiop: fail to set dma_mask\n");
 			goto disable_pci_device;
@@ -998,7 +1000,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
 
 	hba = (struct hptiop_hba *)host->hostdata;
 
-	hba->ops = (struct hptiop_adapter_ops *)id->driver_data;
+	hba->ops = iop_ops;
 	hba->pcidev = pcidev;
 	hba->host = host;
 	hba->initialized = 0;
@@ -1239,6 +1241,7 @@ static struct hptiop_adapter_ops hptiop_itl_ops = {
 	.iop_intr          = iop_intr_itl,
 	.post_msg          = hptiop_post_msg_itl,
 	.post_req          = hptiop_post_req_itl,
+	.hw_dma_bit_mask   = 64,
 };
 
 static struct hptiop_adapter_ops hptiop_mv_ops = {
@@ -1254,6 +1257,7 @@ static struct hptiop_adapter_ops hptiop_mv_ops = {
 	.iop_intr          = iop_intr_mv,
 	.post_msg          = hptiop_post_msg_mv,
 	.post_req          = hptiop_post_req_mv,
+	.hw_dma_bit_mask   = 33,
 };
 
 static struct pci_device_id hptiop_id_table[] = {
diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h
index 0b871c0..baa648d 100644
--- a/drivers/scsi/hptiop.h
+++ b/drivers/scsi/hptiop.h
@@ -297,6 +297,7 @@ struct hptiop_adapter_ops {
 	int  (*iop_intr)(struct hptiop_hba *hba);
 	void (*post_msg)(struct hptiop_hba *hba, u32 msg);
 	void (*post_req)(struct hptiop_hba *hba, struct hptiop_request *_req);
+	int  hw_dma_bit_mask;
 };
 
 #define HPT_IOCTL_RESULT_OK         0
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 45385f5..bc8981e 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -1044,7 +1044,7 @@ static enum sci_status sci_controller_start(struct isci_host *ihost,
 	return SCI_SUCCESS;
 }
 
-void isci_host_scan_start(struct Scsi_Host *shost)
+void isci_host_start(struct Scsi_Host *shost)
 {
 	struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha;
 	unsigned long tmo = sci_controller_get_suggested_start_timeout(ihost);
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 9ab58e0..4911310 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -473,7 +473,7 @@ void sci_controller_remote_device_stopped(struct isci_host *ihost,
 
 enum sci_status sci_controller_continue_io(struct isci_request *ireq);
 int isci_host_scan_finished(struct Scsi_Host *, unsigned long);
-void isci_host_scan_start(struct Scsi_Host *);
+void isci_host_start(struct Scsi_Host *);
 u16 isci_alloc_tag(struct isci_host *ihost);
 enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag);
 void isci_tci_free(struct isci_host *ihost, u16 tci);
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 47e28b5..da142a8 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -156,7 +156,7 @@ static struct scsi_host_template isci_sht = {
 	.target_alloc			= sas_target_alloc,
 	.slave_configure		= sas_slave_configure,
 	.scan_finished			= isci_host_scan_finished,
-	.scan_start			= isci_host_scan_start,
+	.scan_start			= isci_host_start,
 	.change_queue_depth		= sas_change_queue_depth,
 	.change_queue_type		= sas_change_queue_type,
 	.bios_param			= sas_bios_param,
@@ -166,6 +166,9 @@ static struct scsi_host_template isci_sht = {
 	.sg_tablesize			= SG_ALL,
 	.max_sectors			= SCSI_DEFAULT_MAX_SECTORS,
 	.use_clustering			= ENABLE_CLUSTERING,
+	.eh_abort_handler		= sas_eh_abort_handler,
+	.eh_device_reset_handler        = sas_eh_device_reset_handler,
+	.eh_bus_reset_handler           = sas_eh_bus_reset_handler,
 	.target_destroy			= sas_target_destroy,
 	.ioctl				= sas_ioctl,
 	.shost_attrs			= isci_host_attrs,
@@ -719,11 +722,67 @@ static void __devexit isci_pci_remove(struct pci_dev *pdev)
 	}
 }
 
+#ifdef CONFIG_PM
+static int isci_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct isci_host *ihost;
+	int i;
+
+	for_each_isci_host(i, ihost, pdev) {
+		sas_suspend_ha(&ihost->sas_ha);
+		isci_host_deinit(ihost);
+	}
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	return 0;
+}
+
+static int isci_resume(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct isci_host *ihost;
+	int rc, i;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	rc = pcim_enable_device(pdev);
+	if (rc) {
+		dev_err(&pdev->dev,
+			"enabling device failure after resume(%d)\n", rc);
+		return rc;
+	}
+
+	pci_set_master(pdev);
+
+	for_each_isci_host(i, ihost, pdev) {
+		sas_prep_resume_ha(&ihost->sas_ha);
+
+		isci_host_init(ihost);
+		isci_host_start(ihost->sas_ha.core.shost);
+		wait_for_start(ihost);
+
+		sas_resume_ha(&ihost->sas_ha);
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(isci_pm_ops, isci_suspend, isci_resume);
+#endif
+
 static struct pci_driver isci_pci_driver = {
 	.name		= DRV_NAME,
 	.id_table	= isci_id_table,
 	.probe		= isci_pci_probe,
 	.remove		= __devexit_p(isci_pci_remove),
+#ifdef CONFIG_PM
+	.driver.pm      = &isci_pm_ops,
+#endif
 };
 
 static __init int isci_init(void)
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index aceffad..10a6a2a 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -99,11 +99,6 @@ struct fc_exch_mgr {
 	u16		max_xid;
 	u16		pool_max_index;
 
-	/*
-	 * currently exchange mgr stats are updated but not used.
-	 * either stats can be expose via sysfs or remove them
-	 * all together if not used XXX
-	 */
 	struct {
 		atomic_t no_free_exch;
 		atomic_t no_free_exch_xid;
@@ -124,7 +119,7 @@ struct fc_exch_mgr {
  * for each anchor to determine if that EM should be used. The last
  * anchor in the list will always match to handle any exchanges not
  * handled by other EMs. The non-default EMs would be added to the
- * anchor list by HW that provides FCoE offloads.
+ * anchor list by HW that provides offloads.
  */
 struct fc_exch_mgr_anchor {
 	struct list_head ema_list;
@@ -986,7 +981,7 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport,
 				/*
 				 * Update sequence_id based on incoming last
 				 * frame of sequence exchange. This is needed
-				 * for FCoE target where DDP has been used
+				 * for FC target where DDP has been used
 				 * on target where, stack is indicated only
 				 * about last frame's (payload _header) header.
 				 * Whereas "seq_id" which is part of
@@ -2156,6 +2151,31 @@ out:
 }
 
 /**
+ * fc_exch_update_stats() - update exches stats to lport
+ * @lport: The local port to update exchange manager stats
+ */
+void fc_exch_update_stats(struct fc_lport *lport)
+{
+	struct fc_host_statistics *st;
+	struct fc_exch_mgr_anchor *ema;
+	struct fc_exch_mgr *mp;
+
+	st = &lport->host_stats;
+
+	list_for_each_entry(ema, &lport->ema_list, ema_list) {
+		mp = ema->mp;
+		st->fc_no_free_exch += atomic_read(&mp->stats.no_free_exch);
+		st->fc_no_free_exch_xid +=
+				atomic_read(&mp->stats.no_free_exch_xid);
+		st->fc_xid_not_found += atomic_read(&mp->stats.xid_not_found);
+		st->fc_xid_busy += atomic_read(&mp->stats.xid_busy);
+		st->fc_seq_not_found += atomic_read(&mp->stats.seq_not_found);
+		st->fc_non_bls_resp += atomic_read(&mp->stats.non_bls_resp);
+	}
+}
+EXPORT_SYMBOL(fc_exch_update_stats);
+
+/**
  * fc_exch_mgr_add() - Add an exchange manager to a local port's list of EMs
  * @lport: The local port to add the exchange manager to
  * @mp:	   The exchange manager to be added to the local port
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index f735730..3c96e93 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -158,6 +158,9 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp)
 		fsp->timer.data = (unsigned long)fsp;
 		INIT_LIST_HEAD(&fsp->list);
 		spin_lock_init(&fsp->scsi_pkt_lock);
+	} else {
+		per_cpu_ptr(lport->stats, get_cpu())->FcpPktAllocFails++;
+		put_cpu();
 	}
 	return fsp;
 }
@@ -264,6 +267,9 @@ static int fc_fcp_send_abort(struct fc_fcp_pkt *fsp)
 	if (!fsp->seq_ptr)
 		return -EINVAL;
 
+	per_cpu_ptr(fsp->lp->stats, get_cpu())->FcpPktAborts++;
+	put_cpu();
+
 	fsp->state |= FC_SRB_ABORT_PENDING;
 	return fsp->lp->tt.seq_exch_abort(fsp->seq_ptr, 0);
 }
@@ -420,6 +426,8 @@ static inline struct fc_frame *fc_fcp_frame_alloc(struct fc_lport *lport,
 	if (likely(fp))
 		return fp;
 
+	per_cpu_ptr(lport->stats, get_cpu())->FcpFrameAllocFails++;
+	put_cpu();
 	/* error case */
 	fc_fcp_can_queue_ramp_down(lport);
 	return NULL;
@@ -434,7 +442,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 {
 	struct scsi_cmnd *sc = fsp->cmd;
 	struct fc_lport *lport = fsp->lp;
-	struct fcoe_dev_stats *stats;
+	struct fc_stats *stats;
 	struct fc_frame_header *fh;
 	size_t start_offset;
 	size_t offset;
@@ -496,7 +504,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 
 		if (~crc != le32_to_cpu(fr_crc(fp))) {
 crc_err:
-			stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+			stats = per_cpu_ptr(lport->stats, get_cpu());
 			stats->ErrorFrames++;
 			/* per cpu count, not total count, but OK for limit */
 			if (stats->InvalidCRCCount++ < FC_MAX_ERROR_CNT)
@@ -1786,7 +1794,7 @@ int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd)
 	struct fc_rport_libfc_priv *rpriv;
 	int rval;
 	int rc = 0;
-	struct fcoe_dev_stats *stats;
+	struct fc_stats *stats;
 
 	rval = fc_remote_port_chkready(rport);
 	if (rval) {
@@ -1835,7 +1843,7 @@ int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd)
 	/*
 	 * setup the data direction
 	 */
-	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+	stats = per_cpu_ptr(lport->stats, get_cpu());
 	if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		fsp->req_flags = FC_SRB_READ;
 		stats->InputRequests++;
diff --git a/drivers/scsi/libfc/fc_frame.c b/drivers/scsi/libfc/fc_frame.c
index 981329a..0382ac0 100644
--- a/drivers/scsi/libfc/fc_frame.c
+++ b/drivers/scsi/libfc/fc_frame.c
@@ -49,7 +49,7 @@ u32 fc_frame_crc_check(struct fc_frame *fp)
 EXPORT_SYMBOL(fc_frame_crc_check);
 
 /*
- * Allocate a frame intended to be sent via fcoe_xmit.
+ * Allocate a frame intended to be sent.
  * Get an sk_buff for the frame and set the length.
  */
 struct fc_frame *_fc_frame_alloc(size_t len)
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index c1402fb..ca278d4 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -299,47 +299,54 @@ EXPORT_SYMBOL(fc_get_host_speed);
  */
 struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost)
 {
-	struct fc_host_statistics *fcoe_stats;
+	struct fc_host_statistics *fc_stats;
 	struct fc_lport *lport = shost_priv(shost);
 	struct timespec v0, v1;
 	unsigned int cpu;
 	u64 fcp_in_bytes = 0;
 	u64 fcp_out_bytes = 0;
 
-	fcoe_stats = &lport->host_stats;
-	memset(fcoe_stats, 0, sizeof(struct fc_host_statistics));
+	fc_stats = &lport->host_stats;
+	memset(fc_stats, 0, sizeof(struct fc_host_statistics));
 
 	jiffies_to_timespec(jiffies, &v0);
 	jiffies_to_timespec(lport->boot_time, &v1);
-	fcoe_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec);
+	fc_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec);
 
 	for_each_possible_cpu(cpu) {
-		struct fcoe_dev_stats *stats;
-
-		stats = per_cpu_ptr(lport->dev_stats, cpu);
-
-		fcoe_stats->tx_frames += stats->TxFrames;
-		fcoe_stats->tx_words += stats->TxWords;
-		fcoe_stats->rx_frames += stats->RxFrames;
-		fcoe_stats->rx_words += stats->RxWords;
-		fcoe_stats->error_frames += stats->ErrorFrames;
-		fcoe_stats->invalid_crc_count += stats->InvalidCRCCount;
-		fcoe_stats->fcp_input_requests += stats->InputRequests;
-		fcoe_stats->fcp_output_requests += stats->OutputRequests;
-		fcoe_stats->fcp_control_requests += stats->ControlRequests;
+		struct fc_stats *stats;
+
+		stats = per_cpu_ptr(lport->stats, cpu);
+
+		fc_stats->tx_frames += stats->TxFrames;
+		fc_stats->tx_words += stats->TxWords;
+		fc_stats->rx_frames += stats->RxFrames;
+		fc_stats->rx_words += stats->RxWords;
+		fc_stats->error_frames += stats->ErrorFrames;
+		fc_stats->invalid_crc_count += stats->InvalidCRCCount;
+		fc_stats->fcp_input_requests += stats->InputRequests;
+		fc_stats->fcp_output_requests += stats->OutputRequests;
+		fc_stats->fcp_control_requests += stats->ControlRequests;
 		fcp_in_bytes += stats->InputBytes;
 		fcp_out_bytes += stats->OutputBytes;
-		fcoe_stats->link_failure_count += stats->LinkFailureCount;
+		fc_stats->fcp_packet_alloc_failures += stats->FcpPktAllocFails;
+		fc_stats->fcp_packet_aborts += stats->FcpPktAborts;
+		fc_stats->fcp_frame_alloc_failures += stats->FcpFrameAllocFails;
+		fc_stats->link_failure_count += stats->LinkFailureCount;
 	}
-	fcoe_stats->fcp_input_megabytes = div_u64(fcp_in_bytes, 1000000);
-	fcoe_stats->fcp_output_megabytes = div_u64(fcp_out_bytes, 1000000);
-	fcoe_stats->lip_count = -1;
-	fcoe_stats->nos_count = -1;
-	fcoe_stats->loss_of_sync_count = -1;
-	fcoe_stats->loss_of_signal_count = -1;
-	fcoe_stats->prim_seq_protocol_err_count = -1;
-	fcoe_stats->dumped_frames = -1;
-	return fcoe_stats;
+	fc_stats->fcp_input_megabytes = div_u64(fcp_in_bytes, 1000000);
+	fc_stats->fcp_output_megabytes = div_u64(fcp_out_bytes, 1000000);
+	fc_stats->lip_count = -1;
+	fc_stats->nos_count = -1;
+	fc_stats->loss_of_sync_count = -1;
+	fc_stats->loss_of_signal_count = -1;
+	fc_stats->prim_seq_protocol_err_count = -1;
+	fc_stats->dumped_frames = -1;
+
+	/* update exches stats */
+	fc_exch_update_stats(lport);
+
+	return fc_stats;
 }
 EXPORT_SYMBOL(fc_get_host_stats);
 
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 441d88a..607a35b 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -523,6 +523,31 @@ static void sas_ata_set_dmamode(struct ata_port *ap, struct ata_device *ata_dev)
 		i->dft->lldd_ata_set_dmamode(dev);
 }
 
+static void sas_ata_sched_eh(struct ata_port *ap)
+{
+	struct domain_device *dev = ap->private_data;
+	struct sas_ha_struct *ha = dev->port->ha;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ha->lock, flags);
+	if (!test_and_set_bit(SAS_DEV_EH_PENDING, &dev->state))
+		ha->eh_active++;
+	ata_std_sched_eh(ap);
+	spin_unlock_irqrestore(&ha->lock, flags);
+}
+
+void sas_ata_end_eh(struct ata_port *ap)
+{
+	struct domain_device *dev = ap->private_data;
+	struct sas_ha_struct *ha = dev->port->ha;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ha->lock, flags);
+	if (test_and_clear_bit(SAS_DEV_EH_PENDING, &dev->state))
+		ha->eh_active--;
+	spin_unlock_irqrestore(&ha->lock, flags);
+}
+
 static struct ata_port_operations sas_sata_ops = {
 	.prereset		= ata_std_prereset,
 	.hardreset		= sas_ata_hard_reset,
@@ -536,6 +561,8 @@ static struct ata_port_operations sas_sata_ops = {
 	.port_start		= ata_sas_port_start,
 	.port_stop		= ata_sas_port_stop,
 	.set_dmamode		= sas_ata_set_dmamode,
+	.sched_eh		= sas_ata_sched_eh,
+	.end_eh			= sas_ata_end_eh,
 };
 
 static struct ata_port_info sata_port_info = {
@@ -591,7 +618,6 @@ void sas_ata_task_abort(struct sas_task *task)
 		spin_lock_irqsave(q->queue_lock, flags);
 		blk_abort_request(qc->scsicmd->request);
 		spin_unlock_irqrestore(q->queue_lock, flags);
-		scsi_schedule_eh(qc->scsicmd->device->host);
 		return;
 	}
 
@@ -674,6 +700,92 @@ void sas_probe_sata(struct asd_sas_port *port)
 		if (ata_dev_disabled(sas_to_ata_dev(dev)))
 			sas_fail_probe(dev, __func__, -ENODEV);
 	}
+
+}
+
+static bool sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
+{
+	struct domain_device *dev, *n;
+	bool retry = false;
+
+	list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
+		int rc;
+
+		if (!dev_is_sata(dev))
+			continue;
+
+		sas_ata_wait_eh(dev);
+		rc = dev->sata_dev.pm_result;
+		if (rc == -EAGAIN)
+			retry = true;
+		else if (rc) {
+			/* since we don't have a
+			 * ->port_{suspend|resume} routine in our
+			 *  ata_port ops, and no entanglements with
+			 *  acpi, suspend should just be mechanical trip
+			 *  through eh, catch cases where these
+			 *  assumptions are invalidated
+			 */
+			WARN_ONCE(1, "failed %s %s error: %d\n", func,
+				 dev_name(&dev->rphy->dev), rc);
+		}
+
+		/* if libata failed to power manage the device, tear it down */
+		if (ata_dev_disabled(sas_to_ata_dev(dev)))
+			sas_fail_probe(dev, func, -ENODEV);
+	}
+
+	return retry;
+}
+
+void sas_suspend_sata(struct asd_sas_port *port)
+{
+	struct domain_device *dev;
+
+ retry:
+	mutex_lock(&port->ha->disco_mutex);
+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+		struct sata_device *sata;
+
+		if (!dev_is_sata(dev))
+			continue;
+
+		sata = &dev->sata_dev;
+		if (sata->ap->pm_mesg.event == PM_EVENT_SUSPEND)
+			continue;
+
+		sata->pm_result = -EIO;
+		ata_sas_port_async_suspend(sata->ap, &sata->pm_result);
+	}
+	mutex_unlock(&port->ha->disco_mutex);
+
+	if (sas_ata_flush_pm_eh(port, __func__))
+		goto retry;
+}
+
+void sas_resume_sata(struct asd_sas_port *port)
+{
+	struct domain_device *dev;
+
+ retry:
+	mutex_lock(&port->ha->disco_mutex);
+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+		struct sata_device *sata;
+
+		if (!dev_is_sata(dev))
+			continue;
+
+		sata = &dev->sata_dev;
+		if (sata->ap->pm_mesg.event == PM_EVENT_ON)
+			continue;
+
+		sata->pm_result = -EIO;
+		ata_sas_port_async_resume(sata->ap, &sata->pm_result);
+	}
+	mutex_unlock(&port->ha->disco_mutex);
+
+	if (sas_ata_flush_pm_eh(port, __func__))
+		goto retry;
 }
 
 /**
@@ -708,10 +820,6 @@ static void async_sas_ata_eh(void *data, async_cookie_t cookie)
 	struct ata_port *ap = dev->sata_dev.ap;
 	struct sas_ha_struct *ha = dev->port->ha;
 
-	/* hold a reference over eh since we may be racing with final
-	 * remove once all commands are completed
-	 */
-	kref_get(&dev->kref);
 	sas_ata_printk(KERN_DEBUG, dev, "dev error handler\n");
 	ata_scsi_port_error_handler(ha->core.shost, ap);
 	sas_put_device(dev);
@@ -742,6 +850,13 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost)
 		list_for_each_entry(dev, &port->dev_list, dev_list_node) {
 			if (!dev_is_sata(dev))
 				continue;
+
+			/* hold a reference over eh since we may be
+			 * racing with final remove once all commands
+			 * are completed
+			 */
+			kref_get(&dev->kref);
+
 			async_schedule_domain(async_sas_ata_eh, dev, &async);
 		}
 		spin_unlock(&port->dev_list_lock);
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 629a086..a0c3003 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -24,6 +24,7 @@
 
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
+#include <linux/async.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
 #include "sas_internal.h"
@@ -39,18 +40,13 @@ void sas_init_dev(struct domain_device *dev)
 {
 	switch (dev->dev_type) {
 	case SAS_END_DEV:
+		INIT_LIST_HEAD(&dev->ssp_dev.eh_list_node);
 		break;
 	case EDGE_DEV:
 	case FANOUT_DEV:
 		INIT_LIST_HEAD(&dev->ex_dev.children);
 		mutex_init(&dev->ex_dev.cmd_mutex);
 		break;
-	case SATA_DEV:
-	case SATA_PM:
-	case SATA_PM_PORT:
-	case SATA_PENDING:
-		INIT_LIST_HEAD(&dev->sata_dev.children);
-		break;
 	default:
 		break;
 	}
@@ -185,16 +181,18 @@ int sas_notify_lldd_dev_found(struct domain_device *dev)
 	struct Scsi_Host *shost = sas_ha->core.shost;
 	struct sas_internal *i = to_sas_internal(shost->transportt);
 
-	if (i->dft->lldd_dev_found) {
-		res = i->dft->lldd_dev_found(dev);
-		if (res) {
-			printk("sas: driver on pcidev %s cannot handle "
-			       "device %llx, error:%d\n",
-			       dev_name(sas_ha->dev),
-			       SAS_ADDR(dev->sas_addr), res);
-		}
-		kref_get(&dev->kref);
+	if (!i->dft->lldd_dev_found)
+		return 0;
+
+	res = i->dft->lldd_dev_found(dev);
+	if (res) {
+		printk("sas: driver on pcidev %s cannot handle "
+		       "device %llx, error:%d\n",
+		       dev_name(sas_ha->dev),
+		       SAS_ADDR(dev->sas_addr), res);
 	}
+	set_bit(SAS_DEV_FOUND, &dev->state);
+	kref_get(&dev->kref);
 	return res;
 }
 
@@ -205,7 +203,10 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
 	struct Scsi_Host *shost = sas_ha->core.shost;
 	struct sas_internal *i = to_sas_internal(shost->transportt);
 
-	if (i->dft->lldd_dev_gone) {
+	if (!i->dft->lldd_dev_gone)
+		return;
+
+	if (test_and_clear_bit(SAS_DEV_FOUND, &dev->state)) {
 		i->dft->lldd_dev_gone(dev);
 		sas_put_device(dev);
 	}
@@ -239,6 +240,47 @@ static void sas_probe_devices(struct work_struct *work)
 	}
 }
 
+static void sas_suspend_devices(struct work_struct *work)
+{
+	struct asd_sas_phy *phy;
+	struct domain_device *dev;
+	struct sas_discovery_event *ev = to_sas_discovery_event(work);
+	struct asd_sas_port *port = ev->port;
+	struct Scsi_Host *shost = port->ha->core.shost;
+	struct sas_internal *si = to_sas_internal(shost->transportt);
+
+	clear_bit(DISCE_SUSPEND, &port->disc.pending);
+
+	sas_suspend_sata(port);
+
+	/* lldd is free to forget the domain_device across the
+	 * suspension, we force the issue here to keep the reference
+	 * counts aligned
+	 */
+	list_for_each_entry(dev, &port->dev_list, dev_list_node)
+		sas_notify_lldd_dev_gone(dev);
+
+	/* we are suspending, so we know events are disabled and
+	 * phy_list is not being mutated
+	 */
+	list_for_each_entry(phy, &port->phy_list, port_phy_el) {
+		if (si->dft->lldd_port_formed)
+			si->dft->lldd_port_deformed(phy);
+		phy->suspended = 1;
+		port->suspended = 1;
+	}
+}
+
+static void sas_resume_devices(struct work_struct *work)
+{
+	struct sas_discovery_event *ev = to_sas_discovery_event(work);
+	struct asd_sas_port *port = ev->port;
+
+	clear_bit(DISCE_RESUME, &port->disc.pending);
+
+	sas_resume_sata(port);
+}
+
 /**
  * sas_discover_end_dev -- discover an end device (SSP, etc)
  * @end: pointer to domain device of interest
@@ -286,6 +328,8 @@ void sas_free_device(struct kref *kref)
 
 static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev)
 {
+	struct sas_ha_struct *ha = port->ha;
+
 	sas_notify_lldd_dev_gone(dev);
 	if (!dev->parent)
 		dev->port->port_dev = NULL;
@@ -294,8 +338,18 @@ static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_d
 
 	spin_lock_irq(&port->dev_list_lock);
 	list_del_init(&dev->dev_list_node);
+	if (dev_is_sata(dev))
+		sas_ata_end_eh(dev->sata_dev.ap);
 	spin_unlock_irq(&port->dev_list_lock);
 
+	spin_lock_irq(&ha->lock);
+	if (dev->dev_type == SAS_END_DEV &&
+	    !list_empty(&dev->ssp_dev.eh_list_node)) {
+		list_del_init(&dev->ssp_dev.eh_list_node);
+		ha->eh_active--;
+	}
+	spin_unlock_irq(&ha->lock);
+
 	sas_put_device(dev);
 }
 
@@ -488,9 +542,9 @@ static void sas_chain_event(int event, unsigned long *pending,
 	if (!test_and_set_bit(event, pending)) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&ha->state_lock, flags);
+		spin_lock_irqsave(&ha->lock, flags);
 		sas_chain_work(ha, sw);
-		spin_unlock_irqrestore(&ha->state_lock, flags);
+		spin_unlock_irqrestore(&ha->lock, flags);
 	}
 }
 
@@ -523,6 +577,8 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
 		[DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
 		[DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
 		[DISCE_PROBE] = sas_probe_devices,
+		[DISCE_SUSPEND] = sas_suspend_devices,
+		[DISCE_RESUME] = sas_resume_devices,
 		[DISCE_DESTRUCT] = sas_destruct_devices,
 	};
 
diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c
index fc46093..cd6f99c 100644
--- a/drivers/scsi/libsas/sas_dump.c
+++ b/drivers/scsi/libsas/sas_dump.c
@@ -41,6 +41,7 @@ static const char *sas_phye_str[] = {
 	[1] = "PHYE_OOB_DONE",
 	[2] = "PHYE_OOB_ERROR",
 	[3] = "PHYE_SPINUP_HOLD",
+	[4] = "PHYE_RESUME_TIMEOUT",
 };
 
 void sas_dprint_porte(int phyid, enum port_event pe)
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index 4e4292d..aadbd53 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -47,9 +47,9 @@ static void sas_queue_event(int event, unsigned long *pending,
 	if (!test_and_set_bit(event, pending)) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&ha->state_lock, flags);
+		spin_lock_irqsave(&ha->lock, flags);
 		sas_queue_work(ha, work);
-		spin_unlock_irqrestore(&ha->state_lock, flags);
+		spin_unlock_irqrestore(&ha->lock, flags);
 	}
 }
 
@@ -61,18 +61,18 @@ void __sas_drain_work(struct sas_ha_struct *ha)
 
 	set_bit(SAS_HA_DRAINING, &ha->state);
 	/* flush submitters */
-	spin_lock_irq(&ha->state_lock);
-	spin_unlock_irq(&ha->state_lock);
+	spin_lock_irq(&ha->lock);
+	spin_unlock_irq(&ha->lock);
 
 	drain_workqueue(wq);
 
-	spin_lock_irq(&ha->state_lock);
+	spin_lock_irq(&ha->lock);
 	clear_bit(SAS_HA_DRAINING, &ha->state);
 	list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) {
 		list_del_init(&sw->drain_node);
 		sas_queue_work(ha, sw);
 	}
-	spin_unlock_irq(&ha->state_lock);
+	spin_unlock_irq(&ha->lock);
 }
 
 int sas_drain_work(struct sas_ha_struct *ha)
@@ -134,7 +134,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
 			&phy->port_events[event].work, ha);
 }
 
-static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
+void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
 {
 	struct sas_ha_struct *ha = phy->ha;
 
@@ -159,7 +159,7 @@ int sas_init_events(struct sas_ha_struct *sas_ha)
 
 	sas_ha->notify_ha_event = notify_ha_event;
 	sas_ha->notify_port_event = notify_port_event;
-	sas_ha->notify_phy_event = notify_phy_event;
+	sas_ha->notify_phy_event = sas_notify_phy_event;
 
 	return 0;
 }
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index caa0525..a4b15c1 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -51,14 +51,14 @@ static void smp_task_timedout(unsigned long _task)
 		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 static void smp_task_done(struct sas_task *task)
 {
-	if (!del_timer(&task->timer))
+	if (!del_timer(&task->slow_task->timer))
 		return;
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 /* Give it some long enough timeout. In seconds. */
@@ -79,7 +79,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
 			break;
 		}
 
-		task = sas_alloc_task(GFP_KERNEL);
+		task = sas_alloc_slow_task(GFP_KERNEL);
 		if (!task) {
 			res = -ENOMEM;
 			break;
@@ -91,20 +91,20 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
 
 		task->task_done = smp_task_done;
 
-		task->timer.data = (unsigned long) task;
-		task->timer.function = smp_task_timedout;
-		task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
-		add_timer(&task->timer);
+		task->slow_task->timer.data = (unsigned long) task;
+		task->slow_task->timer.function = smp_task_timedout;
+		task->slow_task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
+		add_timer(&task->slow_task->timer);
 
 		res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
 
 		if (res) {
-			del_timer(&task->timer);
+			del_timer(&task->slow_task->timer);
 			SAS_DPRINTK("executing SMP task failed:%d\n", res);
 			break;
 		}
 
-		wait_for_completion(&task->completion);
+		wait_for_completion(&task->slow_task->completion);
 		res = -ECOMM;
 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
 			SAS_DPRINTK("smp task timed out or aborted\n");
@@ -2005,6 +2005,7 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
 	u8 sas_addr[8];
 	int res;
 
+	memset(sas_addr, 0, 8);
 	res = sas_get_phy_attached_dev(dev, phy_id, sas_addr, &type);
 	switch (res) {
 	case SMP_RESP_NO_PHY:
@@ -2017,9 +2018,13 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
 		return res;
 	case SMP_RESP_FUNC_ACC:
 		break;
+	case -ECOMM:
+		break;
+	default:
+		return res;
 	}
 
-	if (SAS_ADDR(sas_addr) == 0) {
+	if ((SAS_ADDR(sas_addr) == 0) || (res == -ECOMM)) {
 		phy->phy_state = PHY_EMPTY;
 		sas_unregister_devs_sas_addr(dev, phy_id, last);
 		return res;
@@ -2109,9 +2114,7 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
 	struct domain_device *dev = NULL;
 
 	res = sas_find_bcast_dev(port_dev, &dev);
-	if (res)
-		goto out;
-	if (dev) {
+	while (res == 0 && dev) {
 		struct expander_device *ex = &dev->ex_dev;
 		int i = 0, phy_id;
 
@@ -2123,8 +2126,10 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
 			res = sas_rediscover(dev, phy_id);
 			i = phy_id + 1;
 		} while (i < ex->num_phys);
+
+		dev = NULL;
+		res = sas_find_bcast_dev(port_dev, &dev);
 	}
-out:
 	return res;
 }
 
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 10cb5ae..dbc8a79 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -48,18 +48,37 @@ struct sas_task *sas_alloc_task(gfp_t flags)
 		INIT_LIST_HEAD(&task->list);
 		spin_lock_init(&task->task_state_lock);
 		task->task_state_flags = SAS_TASK_STATE_PENDING;
-		init_timer(&task->timer);
-		init_completion(&task->completion);
 	}
 
 	return task;
 }
 EXPORT_SYMBOL_GPL(sas_alloc_task);
 
+struct sas_task *sas_alloc_slow_task(gfp_t flags)
+{
+	struct sas_task *task = sas_alloc_task(flags);
+	struct sas_task_slow *slow = kmalloc(sizeof(*slow), flags);
+
+	if (!task || !slow) {
+		if (task)
+			kmem_cache_free(sas_task_cache, task);
+		kfree(slow);
+		return NULL;
+	}
+
+	task->slow_task = slow;
+	init_timer(&slow->timer);
+	init_completion(&slow->completion);
+
+	return task;
+}
+EXPORT_SYMBOL_GPL(sas_alloc_slow_task);
+
 void sas_free_task(struct sas_task *task)
 {
 	if (task) {
 		BUG_ON(!list_empty(&task->list));
+		kfree(task->slow_task);
 		kmem_cache_free(sas_task_cache, task);
 	}
 }
@@ -114,9 +133,11 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
 		sas_ha->lldd_queue_size = 128; /* Sanity */
 
 	set_bit(SAS_HA_REGISTERED, &sas_ha->state);
-	spin_lock_init(&sas_ha->state_lock);
+	spin_lock_init(&sas_ha->lock);
 	mutex_init(&sas_ha->drain_mutex);
+	init_waitqueue_head(&sas_ha->eh_wait_q);
 	INIT_LIST_HEAD(&sas_ha->defer_q);
+	INIT_LIST_HEAD(&sas_ha->eh_dev_q);
 
 	error = sas_register_phys(sas_ha);
 	if (error) {
@@ -157,18 +178,22 @@ Undo_phys:
 	return error;
 }
 
-int sas_unregister_ha(struct sas_ha_struct *sas_ha)
+static void sas_disable_events(struct sas_ha_struct *sas_ha)
 {
 	/* Set the state to unregistered to avoid further unchained
 	 * events to be queued, and flush any in-progress drainers
 	 */
 	mutex_lock(&sas_ha->drain_mutex);
-	spin_lock_irq(&sas_ha->state_lock);
+	spin_lock_irq(&sas_ha->lock);
 	clear_bit(SAS_HA_REGISTERED, &sas_ha->state);
-	spin_unlock_irq(&sas_ha->state_lock);
+	spin_unlock_irq(&sas_ha->lock);
 	__sas_drain_work(sas_ha);
 	mutex_unlock(&sas_ha->drain_mutex);
+}
 
+int sas_unregister_ha(struct sas_ha_struct *sas_ha)
+{
+	sas_disable_events(sas_ha);
 	sas_unregister_ports(sas_ha);
 
 	/* flush unregistration work */
@@ -360,6 +385,90 @@ int sas_set_phy_speed(struct sas_phy *phy,
 	return ret;
 }
 
+void sas_prep_resume_ha(struct sas_ha_struct *ha)
+{
+	int i;
+
+	set_bit(SAS_HA_REGISTERED, &ha->state);
+
+	/* clear out any stale link events/data from the suspension path */
+	for (i = 0; i < ha->num_phys; i++) {
+		struct asd_sas_phy *phy = ha->sas_phy[i];
+
+		memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
+		phy->port_events_pending = 0;
+		phy->phy_events_pending = 0;
+		phy->frame_rcvd_size = 0;
+	}
+}
+EXPORT_SYMBOL(sas_prep_resume_ha);
+
+static int phys_suspended(struct sas_ha_struct *ha)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < ha->num_phys; i++) {
+		struct asd_sas_phy *phy = ha->sas_phy[i];
+
+		if (phy->suspended)
+			rc++;
+	}
+
+	return rc;
+}
+
+void sas_resume_ha(struct sas_ha_struct *ha)
+{
+	const unsigned long tmo = msecs_to_jiffies(25000);
+	int i;
+
+	/* deform ports on phys that did not resume
+	 * at this point we may be racing the phy coming back (as posted
+	 * by the lldd).  So we post the event and once we are in the
+	 * libsas context check that the phy remains suspended before
+	 * tearing it down.
+	 */
+	i = phys_suspended(ha);
+	if (i)
+		dev_info(ha->dev, "waiting up to 25 seconds for %d phy%s to resume\n",
+			 i, i > 1 ? "s" : "");
+	wait_event_timeout(ha->eh_wait_q, phys_suspended(ha) == 0, tmo);
+	for (i = 0; i < ha->num_phys; i++) {
+		struct asd_sas_phy *phy = ha->sas_phy[i];
+
+		if (phy->suspended) {
+			dev_warn(&phy->phy->dev, "resume timeout\n");
+			sas_notify_phy_event(phy, PHYE_RESUME_TIMEOUT);
+		}
+	}
+
+	/* all phys are back up or timed out, turn on i/o so we can
+	 * flush out disks that did not return
+	 */
+	scsi_unblock_requests(ha->core.shost);
+	sas_drain_work(ha);
+}
+EXPORT_SYMBOL(sas_resume_ha);
+
+void sas_suspend_ha(struct sas_ha_struct *ha)
+{
+	int i;
+
+	sas_disable_events(ha);
+	scsi_block_requests(ha->core.shost);
+	for (i = 0; i < ha->num_phys; i++) {
+		struct asd_sas_port *port = ha->sas_port[i];
+
+		sas_discover_event(port, DISCE_SUSPEND);
+	}
+
+	/* flush suspend events while unregistered */
+	mutex_lock(&ha->drain_mutex);
+	__sas_drain_work(ha);
+	mutex_unlock(&ha->drain_mutex);
+}
+EXPORT_SYMBOL(sas_suspend_ha);
+
 static void sas_phy_release(struct sas_phy *phy)
 {
 	kfree(phy->hostdata);
@@ -411,9 +520,9 @@ static int queue_phy_reset(struct sas_phy *phy, int hard_reset)
 	d->reset_result = 0;
 	d->hard_reset = hard_reset;
 
-	spin_lock_irq(&ha->state_lock);
+	spin_lock_irq(&ha->lock);
 	sas_queue_work(ha, &d->reset_work);
-	spin_unlock_irq(&ha->state_lock);
+	spin_unlock_irq(&ha->lock);
 
 	rc = sas_drain_work(ha);
 	if (rc == 0)
@@ -438,9 +547,9 @@ static int queue_phy_enable(struct sas_phy *phy, int enable)
 	d->enable_result = 0;
 	d->enable = enable;
 
-	spin_lock_irq(&ha->state_lock);
+	spin_lock_irq(&ha->lock);
 	sas_queue_work(ha, &d->enable_work);
-	spin_unlock_irq(&ha->state_lock);
+	spin_unlock_irq(&ha->lock);
 
 	rc = sas_drain_work(ha);
 	if (rc == 0)
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 507e4cf..1de6796 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -89,6 +89,7 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id,
 			enum phy_func phy_func, struct sas_phy_linkrates *);
 int sas_smp_get_phy_events(struct sas_phy *phy);
 
+void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event);
 void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
 struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
 struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
index 521422e..cdee446 100644
--- a/drivers/scsi/libsas/sas_phy.c
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -94,6 +94,25 @@ static void sas_phye_spinup_hold(struct work_struct *work)
 	i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
 }
 
+static void sas_phye_resume_timeout(struct work_struct *work)
+{
+	struct asd_sas_event *ev = to_asd_sas_event(work);
+	struct asd_sas_phy *phy = ev->phy;
+
+	clear_bit(PHYE_RESUME_TIMEOUT, &phy->phy_events_pending);
+
+	/* phew, lldd got the phy back in the nick of time */
+	if (!phy->suspended) {
+		dev_info(&phy->phy->dev, "resume timeout cancelled\n");
+		return;
+	}
+
+	phy->error = 0;
+	phy->suspended = 0;
+	sas_deform_port(phy, 1);
+}
+
+
 /* ---------- Phy class registration ---------- */
 
 int sas_register_phys(struct sas_ha_struct *sas_ha)
@@ -105,6 +124,8 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
 		[PHYE_OOB_DONE] = sas_phye_oob_done,
 		[PHYE_OOB_ERROR] = sas_phye_oob_error,
 		[PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
+		[PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
+
 	};
 
 	static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = {
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index e884a8c..1398b71 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -39,6 +39,49 @@ static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy
 	return true;
 }
 
+static void sas_resume_port(struct asd_sas_phy *phy)
+{
+	struct domain_device *dev;
+	struct asd_sas_port *port = phy->port;
+	struct sas_ha_struct *sas_ha = phy->ha;
+	struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt);
+
+	if (si->dft->lldd_port_formed)
+		si->dft->lldd_port_formed(phy);
+
+	if (port->suspended)
+		port->suspended = 0;
+	else {
+		/* we only need to handle "link returned" actions once */
+		return;
+	}
+
+	/* if the port came back:
+	 * 1/ presume every device came back
+	 * 2/ force the next revalidation to check all expander phys
+	 */
+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+		int i, rc;
+
+		rc = sas_notify_lldd_dev_found(dev);
+		if (rc) {
+			sas_unregister_dev(port, dev);
+			continue;
+		}
+
+		if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) {
+			dev->ex_dev.ex_change_count = -1;
+			for (i = 0; i < dev->ex_dev.num_phys; i++) {
+				struct ex_phy *phy = &dev->ex_dev.ex_phy[i];
+
+				phy->phy_change_count = -1;
+			}
+		}
+	}
+
+	sas_discover_event(port, DISCE_RESUME);
+}
+
 /**
  * sas_form_port -- add this phy to a port
  * @phy: the phy of interest
@@ -58,7 +101,14 @@ static void sas_form_port(struct asd_sas_phy *phy)
 	if (port) {
 		if (!phy_is_wideport_member(port, phy))
 			sas_deform_port(phy, 0);
-		else {
+		else if (phy->suspended) {
+			phy->suspended = 0;
+			sas_resume_port(phy);
+
+			/* phy came back, try to cancel the timeout */
+			wake_up(&sas_ha->eh_wait_q);
+			return;
+		} else {
 			SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
 				    __func__, phy->id, phy->port->id,
 				    phy->port->num_phys);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index f0b9b7b..6e795a1 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -460,14 +460,109 @@ struct sas_phy *sas_get_local_phy(struct domain_device *dev)
 }
 EXPORT_SYMBOL_GPL(sas_get_local_phy);
 
+static void sas_wait_eh(struct domain_device *dev)
+{
+	struct sas_ha_struct *ha = dev->port->ha;
+	DEFINE_WAIT(wait);
+
+	if (dev_is_sata(dev)) {
+		ata_port_wait_eh(dev->sata_dev.ap);
+		return;
+	}
+ retry:
+	spin_lock_irq(&ha->lock);
+
+	while (test_bit(SAS_DEV_EH_PENDING, &dev->state)) {
+		prepare_to_wait(&ha->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
+		spin_unlock_irq(&ha->lock);
+		schedule();
+		spin_lock_irq(&ha->lock);
+	}
+	finish_wait(&ha->eh_wait_q, &wait);
+
+	spin_unlock_irq(&ha->lock);
+
+	/* make sure SCSI EH is complete */
+	if (scsi_host_in_recovery(ha->core.shost)) {
+		msleep(10);
+		goto retry;
+	}
+}
+EXPORT_SYMBOL(sas_wait_eh);
+
+static int sas_queue_reset(struct domain_device *dev, int reset_type, int lun, int wait)
+{
+	struct sas_ha_struct *ha = dev->port->ha;
+	int scheduled = 0, tries = 100;
+
+	/* ata: promote lun reset to bus reset */
+	if (dev_is_sata(dev)) {
+		sas_ata_schedule_reset(dev);
+		if (wait)
+			sas_ata_wait_eh(dev);
+		return SUCCESS;
+	}
+
+	while (!scheduled && tries--) {
+		spin_lock_irq(&ha->lock);
+		if (!test_bit(SAS_DEV_EH_PENDING, &dev->state) &&
+		    !test_bit(reset_type, &dev->state)) {
+			scheduled = 1;
+			ha->eh_active++;
+			list_add_tail(&dev->ssp_dev.eh_list_node, &ha->eh_dev_q);
+			set_bit(SAS_DEV_EH_PENDING, &dev->state);
+			set_bit(reset_type, &dev->state);
+			int_to_scsilun(lun, &dev->ssp_dev.reset_lun);
+			scsi_schedule_eh(ha->core.shost);
+		}
+		spin_unlock_irq(&ha->lock);
+
+		if (wait)
+			sas_wait_eh(dev);
+
+		if (scheduled)
+			return SUCCESS;
+	}
+
+	SAS_DPRINTK("%s reset of %s failed\n",
+		    reset_type == SAS_DEV_LU_RESET ? "LUN" : "Bus",
+		    dev_name(&dev->rphy->dev));
+
+	return FAILED;
+}
+
+int sas_eh_abort_handler(struct scsi_cmnd *cmd)
+{
+	int res;
+	struct sas_task *task = TO_SAS_TASK(cmd);
+	struct Scsi_Host *host = cmd->device->host;
+	struct sas_internal *i = to_sas_internal(host->transportt);
+
+	if (current != host->ehandler)
+		return FAILED;
+
+	if (!i->dft->lldd_abort_task)
+		return FAILED;
+
+	res = i->dft->lldd_abort_task(task);
+	if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
+		return SUCCESS;
+
+	return FAILED;
+}
+EXPORT_SYMBOL_GPL(sas_eh_abort_handler);
+
 /* Attempt to send a LUN reset message to a device */
 int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
 {
-	struct domain_device *dev = cmd_to_domain_dev(cmd);
-	struct sas_internal *i =
-		to_sas_internal(dev->port->ha->core.shost->transportt);
-	struct scsi_lun lun;
 	int res;
+	struct scsi_lun lun;
+	struct Scsi_Host *host = cmd->device->host;
+	struct domain_device *dev = cmd_to_domain_dev(cmd);
+	struct sas_internal *i = to_sas_internal(host->transportt);
+
+	if (current != host->ehandler)
+		return sas_queue_reset(dev, SAS_DEV_LU_RESET, cmd->device->lun, 0);
 
 	int_to_scsilun(cmd->device->lun, &lun);
 
@@ -481,21 +576,22 @@ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
 	return FAILED;
 }
 
-/* Attempt to send a phy (bus) reset */
 int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
 {
-	struct domain_device *dev = cmd_to_domain_dev(cmd);
-	struct sas_phy *phy = sas_get_local_phy(dev);
 	int res;
+	struct Scsi_Host *host = cmd->device->host;
+	struct domain_device *dev = cmd_to_domain_dev(cmd);
+	struct sas_internal *i = to_sas_internal(host->transportt);
 
-	res = sas_phy_reset(phy, 1);
-	if (res)
-		SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
-			    kobject_name(&phy->dev.kobj),
-			    res);
-	sas_put_local_phy(phy);
+	if (current != host->ehandler)
+		return sas_queue_reset(dev, SAS_DEV_RESET, 0, 0);
 
-	if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
+	if (!i->dft->lldd_I_T_nexus_reset)
+		return FAILED;
+
+	res = i->dft->lldd_I_T_nexus_reset(dev);
+	if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE ||
+	    res == -ENODEV)
 		return SUCCESS;
 
 	return FAILED;
@@ -667,16 +763,53 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *
 	goto out;
 }
 
+static void sas_eh_handle_resets(struct Scsi_Host *shost)
+{
+	struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+	struct sas_internal *i = to_sas_internal(shost->transportt);
+
+	/* handle directed resets to sas devices */
+	spin_lock_irq(&ha->lock);
+	while (!list_empty(&ha->eh_dev_q)) {
+		struct domain_device *dev;
+		struct ssp_device *ssp;
+
+		ssp = list_entry(ha->eh_dev_q.next, typeof(*ssp), eh_list_node);
+		list_del_init(&ssp->eh_list_node);
+		dev = container_of(ssp, typeof(*dev), ssp_dev);
+		kref_get(&dev->kref);
+		WARN_ONCE(dev_is_sata(dev), "ssp reset to ata device?\n");
+
+		spin_unlock_irq(&ha->lock);
+
+		if (test_and_clear_bit(SAS_DEV_LU_RESET, &dev->state))
+			i->dft->lldd_lu_reset(dev, ssp->reset_lun.scsi_lun);
+
+		if (test_and_clear_bit(SAS_DEV_RESET, &dev->state))
+			i->dft->lldd_I_T_nexus_reset(dev);
+
+		sas_put_device(dev);
+		spin_lock_irq(&ha->lock);
+		clear_bit(SAS_DEV_EH_PENDING, &dev->state);
+		ha->eh_active--;
+	}
+	spin_unlock_irq(&ha->lock);
+}
+
+
 void sas_scsi_recover_host(struct Scsi_Host *shost)
 {
 	struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
-	unsigned long flags;
 	LIST_HEAD(eh_work_q);
+	int tries = 0;
+	bool retry;
 
-	spin_lock_irqsave(shost->host_lock, flags);
+retry:
+	tries++;
+	retry = true;
+	spin_lock_irq(shost->host_lock);
 	list_splice_init(&shost->eh_cmd_q, &eh_work_q);
-	shost->host_eh_scheduled = 0;
-	spin_unlock_irqrestore(shost->host_lock, flags);
+	spin_unlock_irq(shost->host_lock);
 
 	SAS_DPRINTK("Enter %s busy: %d failed: %d\n",
 		    __func__, shost->host_busy, shost->host_failed);
@@ -705,13 +838,26 @@ out:
 	if (ha->lldd_max_execute_num > 1)
 		wake_up_process(ha->core.queue_thread);
 
+	sas_eh_handle_resets(shost);
+
 	/* now link into libata eh --- if we have any ata devices */
 	sas_ata_strategy_handler(shost);
 
 	scsi_eh_flush_done_q(&ha->eh_done_q);
 
-	SAS_DPRINTK("--- Exit %s: busy: %d failed: %d\n",
-		    __func__, shost->host_busy, shost->host_failed);
+	/* check if any new eh work was scheduled during the last run */
+	spin_lock_irq(&ha->lock);
+	if (ha->eh_active == 0) {
+		shost->host_eh_scheduled = 0;
+		retry = false;
+	}
+	spin_unlock_irq(&ha->lock);
+
+	if (retry)
+		goto retry;
+
+	SAS_DPRINTK("--- Exit %s: busy: %d failed: %d tries: %d\n",
+		    __func__, shost->host_busy, shost->host_failed, tries);
 }
 
 enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
@@ -988,9 +1134,13 @@ void sas_task_abort(struct sas_task *task)
 
 	/* Escape for libsas internal commands */
 	if (!sc) {
-		if (!del_timer(&task->timer))
+		struct sas_task_slow *slow = task->slow_task;
+
+		if (!slow)
+			return;
+		if (!del_timer(&slow->timer))
 			return;
-		task->timer.function(task->timer.data);
+		slow->timer.function(slow->timer.data);
 		return;
 	}
 
@@ -1003,7 +1153,6 @@ void sas_task_abort(struct sas_task *task)
 		spin_lock_irqsave(q->queue_lock, flags);
 		blk_abort_request(sc->request);
 		spin_unlock_irqrestore(q->queue_lock, flags);
-		scsi_schedule_eh(sc->device->host);
 	}
 }
 
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index e5da6da..a65c05a 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -96,6 +96,10 @@ struct lpfc_sli2_slim;
 /* queue dump line buffer size */
 #define LPFC_LBUF_SZ		128
 
+/* mailbox system shutdown options */
+#define LPFC_MBX_NO_WAIT	0
+#define LPFC_MBX_WAIT		1
+
 enum lpfc_polling_flags {
 	ENABLE_FCP_RING_POLLING = 0x1,
 	DISABLE_FCP_RING_INT    = 0x2
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 5eb2bc1..adef5bb 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -3617,6 +3617,91 @@ lpfc_sriov_nr_virtfn_init(struct lpfc_hba *phba, int val)
 static DEVICE_ATTR(lpfc_sriov_nr_virtfn, S_IRUGO | S_IWUSR,
 		   lpfc_sriov_nr_virtfn_show, lpfc_sriov_nr_virtfn_store);
 
+/**
+ * lpfc_fcp_imax_store
+ *
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: string with the number of fast-path FCP interrupts per second.
+ * @count: unused variable.
+ *
+ * Description:
+ * If val is in a valid range [636,651042], then set the adapter's
+ * maximum number of fast-path FCP interrupts per second.
+ *
+ * Returns:
+ * length of the buf on success if val is in range the intended mode
+ * is supported.
+ * -EINVAL if val out of range or intended mode is not supported.
+ **/
+static ssize_t
+lpfc_fcp_imax_store(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = class_to_shost(dev);
+	struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+	struct lpfc_hba *phba = vport->phba;
+	int val = 0, i;
+
+	/* Sanity check on user data */
+	if (!isdigit(buf[0]))
+		return -EINVAL;
+	if (sscanf(buf, "%i", &val) != 1)
+		return -EINVAL;
+
+	/* Value range is [636,651042] */
+	if (val < LPFC_MIM_IMAX || val > LPFC_DMULT_CONST)
+		return -EINVAL;
+
+	phba->cfg_fcp_imax = (uint32_t)val;
+	for (i = 0; i < phba->cfg_fcp_eq_count; i += LPFC_MAX_EQ_DELAY)
+		lpfc_modify_fcp_eq_delay(phba, i);
+
+	return strlen(buf);
+}
+
+/*
+# lpfc_fcp_imax: The maximum number of fast-path FCP interrupts per second
+#
+# Value range is [636,651042]. Default value is 10000.
+*/
+static int lpfc_fcp_imax = LPFC_FP_DEF_IMAX;
+module_param(lpfc_fcp_imax, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(lpfc_fcp_imax,
+	    "Set the maximum number of fast-path FCP interrupts per second");
+lpfc_param_show(fcp_imax)
+
+/**
+ * lpfc_fcp_imax_init - Set the initial sr-iov virtual function enable
+ * @phba: lpfc_hba pointer.
+ * @val: link speed value.
+ *
+ * Description:
+ * If val is in a valid range [636,651042], then initialize the adapter's
+ * maximum number of fast-path FCP interrupts per second.
+ *
+ * Returns:
+ * zero if val saved.
+ * -EINVAL val out of range
+ **/
+static int
+lpfc_fcp_imax_init(struct lpfc_hba *phba, int val)
+{
+	if (val >= LPFC_MIM_IMAX && val <= LPFC_DMULT_CONST) {
+		phba->cfg_fcp_imax = val;
+		return 0;
+	}
+
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"3016 fcp_imax: %d out of range, using default\n", val);
+	phba->cfg_fcp_imax = LPFC_FP_DEF_IMAX;
+
+	return 0;
+}
+
+static DEVICE_ATTR(lpfc_fcp_imax, S_IRUGO | S_IWUSR,
+		   lpfc_fcp_imax_show, lpfc_fcp_imax_store);
+
 /*
 # lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
 # Value range is [2,3]. Default value is 3.
@@ -3758,14 +3843,6 @@ LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or "
 	    "MSI-X (2), if possible");
 
 /*
-# lpfc_fcp_imax: Set the maximum number of fast-path FCP interrupts per second
-#
-# Value range is [636,651042]. Default value is 10000.
-*/
-LPFC_ATTR_R(fcp_imax, LPFC_FP_DEF_IMAX, LPFC_MIM_IMAX, LPFC_DMULT_CONST,
-	    "Set the maximum number of fast-path FCP interrupts per second");
-
-/*
 # lpfc_fcp_wq_count: Set the number of fast-path FCP work queues
 #
 # Value range is [1,31]. Default value is 4.
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 9b2a16f..8a2a514 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -183,7 +183,7 @@ int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int);
 void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
 int lpfc_online(struct lpfc_hba *);
 void lpfc_unblock_mgmt_io(struct lpfc_hba *);
-void lpfc_offline_prep(struct lpfc_hba *);
+void lpfc_offline_prep(struct lpfc_hba *, int);
 void lpfc_offline(struct lpfc_hba *);
 void lpfc_reset_hba(struct lpfc_hba *);
 
@@ -273,7 +273,7 @@ int lpfc_sli_host_down(struct lpfc_vport *);
 int lpfc_sli_hba_down(struct lpfc_hba *);
 int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
 int lpfc_sli_handle_mb_event(struct lpfc_hba *);
-void lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *);
+void lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *, int);
 int lpfc_sli_check_eratt(struct lpfc_hba *);
 void lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
 				    struct lpfc_sli_ring *, uint32_t);
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h
index 616c400..afe368f 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.h
+++ b/drivers/scsi/lpfc/lpfc_debugfs.h
@@ -395,8 +395,13 @@ lpfc_debug_dump_fcp_cq(struct lpfc_hba *phba, int fcp_wqidx)
 	for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++)
 		if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid)
 			break;
-	if (fcp_cqidx >= phba->cfg_fcp_eq_count)
-		return;
+	if (phba->intr_type == MSIX) {
+		if (fcp_cqidx >= phba->cfg_fcp_eq_count)
+			return;
+	} else {
+		if (fcp_cqidx > 0)
+			return;
+	}
 
 	printk(KERN_ERR "FCP CQ: WQ[Idx:%d|Qid%d]->CQ[Idx%d|Qid%d]:\n",
 		fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id,
@@ -426,8 +431,13 @@ lpfc_debug_dump_fcp_eq(struct lpfc_hba *phba, int fcp_wqidx)
 	for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++)
 		if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid)
 			break;
-	if (fcp_cqidx >= phba->cfg_fcp_eq_count)
-		return;
+	if (phba->intr_type == MSIX) {
+		if (fcp_cqidx >= phba->cfg_fcp_eq_count)
+			return;
+	} else {
+		if (fcp_cqidx > 0)
+			return;
+	}
 
 	if (phba->cfg_fcp_eq_count == 0) {
 		fcp_eqidx = -1;
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 5bb269e..9b4f929 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -530,7 +530,7 @@ lpfc_work_list_done(struct lpfc_hba *phba)
 			break;
 		case LPFC_EVT_OFFLINE_PREP:
 			if (phba->link_state >= LPFC_LINK_DOWN)
-				lpfc_offline_prep(phba);
+				lpfc_offline_prep(phba, LPFC_MBX_WAIT);
 			*(int *)(evtp->evt_arg1) = 0;
 			complete((struct completion *)(evtp->evt_arg2));
 			break;
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index f1946df..953603a 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -874,6 +874,7 @@ struct mbox_header {
 #define LPFC_MBOX_OPCODE_MQ_CREATE			0x15
 #define LPFC_MBOX_OPCODE_GET_CNTL_ATTRIBUTES		0x20
 #define LPFC_MBOX_OPCODE_NOP				0x21
+#define LPFC_MBOX_OPCODE_MODIFY_EQ_DELAY		0x29
 #define LPFC_MBOX_OPCODE_MQ_DESTROY			0x35
 #define LPFC_MBOX_OPCODE_CQ_DESTROY			0x36
 #define LPFC_MBOX_OPCODE_EQ_DESTROY			0x37
@@ -940,6 +941,13 @@ struct eq_context {
 	uint32_t reserved3;
 };
 
+struct eq_delay_info {
+	uint32_t eq_id;
+	uint32_t phase;
+	uint32_t delay_multi;
+};
+#define	LPFC_MAX_EQ_DELAY	8
+
 struct sgl_page_pairs {
 	uint32_t sgl_pg0_addr_lo;
 	uint32_t sgl_pg0_addr_hi;
@@ -1002,6 +1010,19 @@ struct lpfc_mbx_eq_create {
 	} u;
 };
 
+struct lpfc_mbx_modify_eq_delay {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t num_eq;
+			struct eq_delay_info eq[LPFC_MAX_EQ_DELAY];
+		} request;
+		struct {
+			uint32_t word0;
+		} response;
+	} u;
+};
+
 struct lpfc_mbx_eq_destroy {
 	struct mbox_header header;
 	union {
@@ -2875,6 +2896,7 @@ struct lpfc_mqe {
 		struct lpfc_mbx_mq_create mq_create;
 		struct lpfc_mbx_mq_create_ext mq_create_ext;
 		struct lpfc_mbx_eq_create eq_create;
+		struct lpfc_mbx_modify_eq_delay eq_delay;
 		struct lpfc_mbx_cq_create cq_create;
 		struct lpfc_mbx_wq_create wq_create;
 		struct lpfc_mbx_rq_create rq_create;
@@ -3084,6 +3106,28 @@ struct lpfc_acqe_fc_la {
 #define LPFC_FC_LA_EVENT_TYPE_SHARED_LINK	0x2
 };
 
+struct lpfc_acqe_misconfigured_event {
+	struct {
+	uint32_t word0;
+#define lpfc_sli_misconfigured_port0_SHIFT	0
+#define lpfc_sli_misconfigured_port0_MASK	0x000000FF
+#define lpfc_sli_misconfigured_port0_WORD	word0
+#define lpfc_sli_misconfigured_port1_SHIFT	8
+#define lpfc_sli_misconfigured_port1_MASK	0x000000FF
+#define lpfc_sli_misconfigured_port1_WORD	word0
+#define lpfc_sli_misconfigured_port2_SHIFT	16
+#define lpfc_sli_misconfigured_port2_MASK	0x000000FF
+#define lpfc_sli_misconfigured_port2_WORD	word0
+#define lpfc_sli_misconfigured_port3_SHIFT	24
+#define lpfc_sli_misconfigured_port3_MASK	0x000000FF
+#define lpfc_sli_misconfigured_port3_WORD	word0
+	} theEvent;
+#define LPFC_SLI_EVENT_STATUS_VALID			0x00
+#define LPFC_SLI_EVENT_STATUS_NOT_PRESENT	0x01
+#define LPFC_SLI_EVENT_STATUS_WRONG_TYPE	0x02
+#define LPFC_SLI_EVENT_STATUS_UNSUPPORTED	0x03
+};
+
 struct lpfc_acqe_sli {
 	uint32_t event_data1;
 	uint32_t event_data2;
@@ -3094,6 +3138,7 @@ struct lpfc_acqe_sli {
 #define LPFC_SLI_EVENT_TYPE_NORM_TEMP		0x3
 #define LPFC_SLI_EVENT_TYPE_NVLOG_POST		0x4
 #define LPFC_SLI_EVENT_TYPE_DIAG_DUMP		0x5
+#define LPFC_SLI_EVENT_TYPE_MISCONFIGURED	0x9
 };
 
 /*
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 411ed48..45c1520 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -73,6 +73,8 @@ static int lpfc_hba_down_post_s4(struct lpfc_hba *phba);
 static int lpfc_sli4_cq_event_pool_create(struct lpfc_hba *);
 static void lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *);
 static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *);
+static void lpfc_sli4_disable_intr(struct lpfc_hba *);
+static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *, uint32_t);
 
 static struct scsi_transport_template *lpfc_transport_template = NULL;
 static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
@@ -1169,7 +1171,7 @@ lpfc_offline_eratt(struct lpfc_hba *phba)
 	spin_lock_irq(&phba->hbalock);
 	psli->sli_flag &= ~LPFC_SLI_ACTIVE;
 	spin_unlock_irq(&phba->hbalock);
-	lpfc_offline_prep(phba);
+	lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT);
 
 	lpfc_offline(phba);
 	lpfc_reset_barrier(phba);
@@ -1193,7 +1195,7 @@ lpfc_offline_eratt(struct lpfc_hba *phba)
 static void
 lpfc_sli4_offline_eratt(struct lpfc_hba *phba)
 {
-	lpfc_offline_prep(phba);
+	lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT);
 	lpfc_offline(phba);
 	lpfc_sli4_brdreset(phba);
 	lpfc_hba_down_post(phba);
@@ -1251,7 +1253,7 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba)
 	 * There was a firmware error. Take the hba offline and then
 	 * attempt to restart it.
 	 */
-	lpfc_offline_prep(phba);
+	lpfc_offline_prep(phba, LPFC_MBX_WAIT);
 	lpfc_offline(phba);
 
 	/* Wait for the ER1 bit to clear.*/
@@ -1372,7 +1374,7 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba)
 		 * There was a firmware error.  Take the hba offline and then
 		 * attempt to restart it.
 		 */
-		lpfc_offline_prep(phba);
+		lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT);
 		lpfc_offline(phba);
 		lpfc_sli_brdrestart(phba);
 		if (lpfc_online(phba) == 0) {	/* Initialize the HBA */
@@ -1428,6 +1430,54 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba)
 }
 
 /**
+ * lpfc_sli4_port_sta_fn_reset - The SLI4 function reset due to port status reg
+ * @phba: pointer to lpfc hba data structure.
+ * @mbx_action: flag for mailbox shutdown action.
+ *
+ * This routine is invoked to perform an SLI4 port PCI function reset in
+ * response to port status register polling attention. It waits for port
+ * status register (ERR, RDY, RN) bits before proceeding with function reset.
+ * During this process, interrupt vectors are freed and later requested
+ * for handling possible port resource change.
+ **/
+static int
+lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action)
+{
+	int rc;
+	uint32_t intr_mode;
+
+	/*
+	 * On error status condition, driver need to wait for port
+	 * ready before performing reset.
+	 */
+	rc = lpfc_sli4_pdev_status_reg_wait(phba);
+	if (!rc) {
+		/* need reset: attempt for port recovery */
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2887 Reset Needed: Attempting Port "
+				"Recovery...\n");
+		lpfc_offline_prep(phba, mbx_action);
+		lpfc_offline(phba);
+		/* release interrupt for possible resource change */
+		lpfc_sli4_disable_intr(phba);
+		lpfc_sli_brdrestart(phba);
+		/* request 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,
+					"3175 Failed to enable interrupt\n");
+			return -EIO;
+		} else {
+			phba->intr_mode = intr_mode;
+		}
+		rc = lpfc_online(phba);
+		if (rc == 0)
+			lpfc_unblock_mgmt_io(phba);
+	}
+	return rc;
+}
+
+/**
  * lpfc_handle_eratt_s4 - The SLI4 HBA hardware error handler
  * @phba: pointer to lpfc hba data structure.
  *
@@ -1506,30 +1556,18 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
 			 reg_err2 == SLIPORT_ERR2_REG_FUNC_PROVISON)
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 					"3145 Port Down: Provisioning\n");
-		/*
-		 * On error status condition, driver need to wait for port
-		 * ready before performing reset.
-		 */
-		rc = lpfc_sli4_pdev_status_reg_wait(phba);
-		if (!rc) {
-			/* need reset: attempt for port recovery */
-			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-					"2887 Reset Needed: Attempting Port "
-					"Recovery...\n");
-			lpfc_offline_prep(phba);
-			lpfc_offline(phba);
-			lpfc_sli_brdrestart(phba);
-			if (lpfc_online(phba) == 0) {
-				lpfc_unblock_mgmt_io(phba);
-				/* don't report event on forced debug dump */
-				if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
-				    reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP)
-					return;
-				else
-					break;
-			}
-			/* fall through for not able to recover */
+
+		/* Check port status register for function reset */
+		rc = lpfc_sli4_port_sta_fn_reset(phba, LPFC_MBX_NO_WAIT);
+		if (rc == 0) {
+			/* don't report event on forced debug dump */
+			if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
+			    reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP)
+				return;
+			else
+				break;
 		}
+		/* fall through for not able to recover */
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"3152 Unrecoverable error, bring the port "
 				"offline\n");
@@ -2494,15 +2532,19 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba)
  * driver prepares the HBA interface for online or offline.
  **/
 static void
-lpfc_block_mgmt_io(struct lpfc_hba * phba)
+lpfc_block_mgmt_io(struct lpfc_hba *phba, int mbx_action)
 {
 	unsigned long iflag;
 	uint8_t actcmd = MBX_HEARTBEAT;
 	unsigned long timeout;
 
-	timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies;
 	spin_lock_irqsave(&phba->hbalock, iflag);
 	phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
+	spin_unlock_irqrestore(&phba->hbalock, iflag);
+	if (mbx_action == LPFC_MBX_NO_WAIT)
+		return;
+	timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies;
+	spin_lock_irqsave(&phba->hbalock, iflag);
 	if (phba->sli.mbox_active) {
 		actcmd = phba->sli.mbox_active->u.mb.mbxCommand;
 		/* Determine how long we might wait for the active mailbox
@@ -2592,7 +2634,7 @@ lpfc_online(struct lpfc_hba *phba)
 	lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
 			"0458 Bring Adapter online\n");
 
-	lpfc_block_mgmt_io(phba);
+	lpfc_block_mgmt_io(phba, LPFC_MBX_WAIT);
 
 	if (!lpfc_sli_queue_setup(phba)) {
 		lpfc_unblock_mgmt_io(phba);
@@ -2660,7 +2702,7 @@ lpfc_unblock_mgmt_io(struct lpfc_hba * phba)
  * queue to make it ready to be brought offline.
  **/
 void
-lpfc_offline_prep(struct lpfc_hba * phba)
+lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
 {
 	struct lpfc_vport *vport = phba->pport;
 	struct lpfc_nodelist  *ndlp, *next_ndlp;
@@ -2671,7 +2713,7 @@ lpfc_offline_prep(struct lpfc_hba * phba)
 	if (vport->fc_flag & FC_OFFLINE_MODE)
 		return;
 
-	lpfc_block_mgmt_io(phba);
+	lpfc_block_mgmt_io(phba, mbx_action);
 
 	lpfc_linkdown(phba);
 
@@ -2718,7 +2760,7 @@ lpfc_offline_prep(struct lpfc_hba * phba)
 	}
 	lpfc_destroy_vport_work_array(phba, vports);
 
-	lpfc_sli_mbox_sys_shutdown(phba);
+	lpfc_sli_mbox_sys_shutdown(phba, mbx_action);
 }
 
 /**
@@ -3684,12 +3726,76 @@ out_free_pmb:
 static void
 lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
 {
-	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-			"2901 Async SLI event - Event Data1:x%08x Event Data2:"
-			"x%08x SLI Event Type:%d",
-			acqe_sli->event_data1, acqe_sli->event_data2,
-			bf_get(lpfc_trailer_type, acqe_sli));
-	return;
+	char port_name;
+	char message[80];
+	uint8_t status;
+	struct lpfc_acqe_misconfigured_event *misconfigured;
+
+	/* special case misconfigured event as it contains data for all ports */
+	if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+		 LPFC_SLI_INTF_IF_TYPE_2) ||
+		(bf_get(lpfc_trailer_type, acqe_sli) !=
+			LPFC_SLI_EVENT_TYPE_MISCONFIGURED)) {
+		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+				"2901 Async SLI event - Event Data1:x%08x Event Data2:"
+				"x%08x SLI Event Type:%d\n",
+				acqe_sli->event_data1, acqe_sli->event_data2,
+				bf_get(lpfc_trailer_type, acqe_sli));
+		return;
+	}
+
+	port_name = phba->Port[0];
+	if (port_name == 0x00)
+		port_name = '?'; /* get port name is empty */
+
+	misconfigured = (struct lpfc_acqe_misconfigured_event *)
+					&acqe_sli->event_data1;
+
+	/* fetch the status for this port */
+	switch (phba->sli4_hba.lnk_info.lnk_no) {
+	case LPFC_LINK_NUMBER_0:
+		status = bf_get(lpfc_sli_misconfigured_port0,
+					&misconfigured->theEvent);
+		break;
+	case LPFC_LINK_NUMBER_1:
+		status = bf_get(lpfc_sli_misconfigured_port1,
+					&misconfigured->theEvent);
+		break;
+	case LPFC_LINK_NUMBER_2:
+		status = bf_get(lpfc_sli_misconfigured_port2,
+					&misconfigured->theEvent);
+		break;
+	case LPFC_LINK_NUMBER_3:
+		status = bf_get(lpfc_sli_misconfigured_port3,
+					&misconfigured->theEvent);
+		break;
+	default:
+		status = ~LPFC_SLI_EVENT_STATUS_VALID;
+		break;
+	}
+
+	switch (status) {
+	case LPFC_SLI_EVENT_STATUS_VALID:
+		return; /* no message if the sfp is okay */
+	case LPFC_SLI_EVENT_STATUS_NOT_PRESENT:
+		sprintf(message, "Not installed");
+		break;
+	case LPFC_SLI_EVENT_STATUS_WRONG_TYPE:
+		sprintf(message,
+			"Optics of two types installed");
+		break;
+	case LPFC_SLI_EVENT_STATUS_UNSUPPORTED:
+		sprintf(message, "Incompatible optics");
+		break;
+	default:
+		/* firmware is reporting a status we don't know about */
+		sprintf(message, "Unknown event status x%02x", status);
+		break;
+	}
+
+	lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+			"3176 Misconfigured Physical Port - "
+			"Port Name %c %s\n", port_name, message);
 }
 
 /**
@@ -4312,7 +4418,7 @@ lpfc_reset_hba(struct lpfc_hba *phba)
 		phba->link_state = LPFC_HBA_ERROR;
 		return;
 	}
-	lpfc_offline_prep(phba);
+	lpfc_offline_prep(phba, LPFC_MBX_WAIT);
 	lpfc_offline(phba);
 	lpfc_sli_brdrestart(phba);
 	lpfc_online(phba);
@@ -5514,14 +5620,45 @@ lpfc_destroy_shost(struct lpfc_hba *phba)
 static void
 lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost)
 {
+	uint32_t old_mask;
+	uint32_t old_guard;
+
 	int pagecnt = 10;
 	if (lpfc_prot_mask && lpfc_prot_guard) {
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
 				"1478 Registering BlockGuard with the "
 				"SCSI layer\n");
-		scsi_host_set_prot(shost, lpfc_prot_mask);
-		scsi_host_set_guard(shost, lpfc_prot_guard);
+
+		old_mask = lpfc_prot_mask;
+		old_guard = lpfc_prot_guard;
+
+		/* Only allow supported values */
+		lpfc_prot_mask &= (SHOST_DIF_TYPE1_PROTECTION |
+			SHOST_DIX_TYPE0_PROTECTION |
+			SHOST_DIX_TYPE1_PROTECTION);
+		lpfc_prot_guard &= (SHOST_DIX_GUARD_IP | SHOST_DIX_GUARD_CRC);
+
+		/* DIF Type 1 protection for profiles AST1/C1 is end to end */
+		if (lpfc_prot_mask == SHOST_DIX_TYPE1_PROTECTION)
+			lpfc_prot_mask |= SHOST_DIF_TYPE1_PROTECTION;
+
+		if (lpfc_prot_mask && lpfc_prot_guard) {
+			if ((old_mask != lpfc_prot_mask) ||
+				(old_guard != lpfc_prot_guard))
+				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"1475 Registering BlockGuard with the "
+					"SCSI layer: mask %d  guard %d\n",
+					lpfc_prot_mask, lpfc_prot_guard);
+
+			scsi_host_set_prot(shost, lpfc_prot_mask);
+			scsi_host_set_guard(shost, lpfc_prot_guard);
+		} else
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1479 Not Registering BlockGuard with the SCSI "
+				"layer, Bad protection parameters: %d %d\n",
+				old_mask, old_guard);
 	}
+
 	if (!_dump_buf_data) {
 		while (pagecnt) {
 			spin_lock_init(&_dump_buf_lock);
@@ -8859,7 +8996,7 @@ lpfc_pci_suspend_one_s3(struct pci_dev *pdev, pm_message_t msg)
 			"0473 PCI device Power Management suspend.\n");
 
 	/* Bring down the device */
-	lpfc_offline_prep(phba);
+	lpfc_offline_prep(phba, LPFC_MBX_WAIT);
 	lpfc_offline(phba);
 	kthread_stop(phba->worker_thread);
 
@@ -8985,7 +9122,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
 			"2710 PCI channel disable preparing for reset\n");
 
 	/* Block any management I/Os to the device */
-	lpfc_block_mgmt_io(phba);
+	lpfc_block_mgmt_io(phba, LPFC_MBX_WAIT);
 
 	/* Block all SCSI devices' I/Os on the host */
 	lpfc_scsi_dev_block(phba);
@@ -9129,7 +9266,7 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev)
 		phba->intr_mode = intr_mode;
 
 	/* Take device offline, it will perform cleanup */
-	lpfc_offline_prep(phba);
+	lpfc_offline_prep(phba, LPFC_MBX_WAIT);
 	lpfc_offline(phba);
 	lpfc_sli_brdrestart(phba);
 
@@ -9603,7 +9740,7 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg)
 			"2843 PCI device Power Management suspend.\n");
 
 	/* Bring down the device */
-	lpfc_offline_prep(phba);
+	lpfc_offline_prep(phba, LPFC_MBX_WAIT);
 	lpfc_offline(phba);
 	kthread_stop(phba->worker_thread);
 
@@ -9729,7 +9866,7 @@ lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba)
 			"2826 PCI channel disable preparing for reset\n");
 
 	/* Block any management I/Os to the device */
-	lpfc_block_mgmt_io(phba);
+	lpfc_block_mgmt_io(phba, LPFC_MBX_NO_WAIT);
 
 	/* Block all SCSI devices' I/Os on the host */
 	lpfc_scsi_dev_block(phba);
@@ -9902,7 +10039,7 @@ lpfc_io_resume_s4(struct pci_dev *pdev)
 	 */
 	if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) {
 		/* Perform device reset */
-		lpfc_offline_prep(phba);
+		lpfc_offline_prep(phba, LPFC_MBX_WAIT);
 		lpfc_offline(phba);
 		lpfc_sli_brdrestart(phba);
 		/* Bring the device back online */
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 66e0906..925975d 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -4275,10 +4275,8 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
 	 * Catch race where our node has transitioned, but the
 	 * transport is still transitioning.
 	 */
-	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
-		cmnd->result = ScsiResult(DID_IMM_RETRY, 0);
-		goto out_fail_command;
-	}
+	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+		goto out_tgt_busy;
 	if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
 		goto out_tgt_busy;
 
@@ -4412,12 +4410,12 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 	struct lpfc_iocbq *abtsiocb;
 	struct lpfc_scsi_buf *lpfc_cmd;
 	IOCB_t *cmd, *icmd;
-	int ret = SUCCESS;
+	int ret = SUCCESS, status = 0;
 	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
 
-	ret = fc_block_scsi_eh(cmnd);
-	if (ret)
-		return ret;
+	status = fc_block_scsi_eh(cmnd);
+	if (status)
+		return status;
 
 	spin_lock_irq(&phba->hbalock);
 	/* driver queued commands are in process of being flushed */
@@ -4435,7 +4433,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
 			 "2873 SCSI Layer I/O Abort Request IO CMPL Status "
 			 "x%x ID %d LUN %d\n",
-			 ret, cmnd->device->id, cmnd->device->lun);
+			 SUCCESS, cmnd->device->id, cmnd->device->lun);
 		return SUCCESS;
 	}
 
@@ -4762,7 +4760,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 	unsigned tgt_id = cmnd->device->id;
 	unsigned int lun_id = cmnd->device->lun;
 	struct lpfc_scsi_event_header scsi_event;
-	int status;
+	int status, ret = SUCCESS;
 
 	if (!rdata) {
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
@@ -4803,9 +4801,9 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 	 * So, continue on.
 	 * We will report success if all the i/o aborts successfully.
 	 */
-	status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id,
+	ret = lpfc_reset_flush_io_context(vport, tgt_id, lun_id,
 						LPFC_CTX_LUN);
-	return status;
+	return ret;
 }
 
 /**
@@ -4829,7 +4827,7 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
 	unsigned tgt_id = cmnd->device->id;
 	unsigned int lun_id = cmnd->device->lun;
 	struct lpfc_scsi_event_header scsi_event;
-	int status;
+	int status, ret = SUCCESS;
 
 	if (!rdata) {
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
@@ -4870,9 +4868,9 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
 	 * So, continue on.
 	 * We will report success if all the i/o aborts successfully.
 	 */
-	status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id,
-					LPFC_CTX_TGT);
-	return status;
+	ret = lpfc_reset_flush_io_context(vport, tgt_id, lun_id,
+					  LPFC_CTX_TGT);
+	return ret;
 }
 
 /**
@@ -4982,7 +4980,7 @@ lpfc_host_reset_handler(struct scsi_cmnd *cmnd)
 	struct lpfc_hba *phba = vport->phba;
 	int rc, ret = SUCCESS;
 
-	lpfc_offline_prep(phba);
+	lpfc_offline_prep(phba, LPFC_MBX_WAIT);
 	lpfc_offline(phba);
 	rc = lpfc_sli_brdrestart(phba);
 	if (rc)
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index b4720a1..9cbd20b 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -8984,7 +8984,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
 	int i;
 
 	/* Shutdown the mailbox command sub-system */
-	lpfc_sli_mbox_sys_shutdown(phba);
+	lpfc_sli_mbox_sys_shutdown(phba, LPFC_MBX_WAIT);
 
 	lpfc_hba_down_prep(phba);
 
@@ -9996,11 +9996,17 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
  * sub-system flush routine to gracefully bring down mailbox sub-system.
  **/
 void
-lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba)
+lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action)
 {
 	struct lpfc_sli *psli = &phba->sli;
 	unsigned long timeout;
 
+	if (mbx_action == LPFC_MBX_NO_WAIT) {
+		/* delay 100ms for port state */
+		msleep(100);
+		lpfc_sli_mbox_sys_flush(phba);
+		return;
+	}
 	timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies;
 
 	spin_lock_irq(&phba->hbalock);
@@ -12042,6 +12048,83 @@ out_fail:
 }
 
 /**
+ * lpfc_modify_fcp_eq_delay - Modify Delay Multiplier on FCP EQs
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @startq: The starting FCP EQ to modify
+ *
+ * This function sends an MODIFY_EQ_DELAY mailbox command to the HBA.
+ *
+ * The @phba struct is used to send mailbox command to HBA. The @startq
+ * is used to get the starting FCP EQ to change.
+ * This function is asynchronous and will wait for the mailbox
+ * command to finish before continuing.
+ *
+ * On success this function will return a zero. If unable to allocate enough
+ * memory this function will return -ENOMEM. If the queue create mailbox command
+ * fails this function will return -ENXIO.
+ **/
+uint32_t
+lpfc_modify_fcp_eq_delay(struct lpfc_hba *phba, uint16_t startq)
+{
+	struct lpfc_mbx_modify_eq_delay *eq_delay;
+	LPFC_MBOXQ_t *mbox;
+	struct lpfc_queue *eq;
+	int cnt, rc, length, status = 0;
+	uint32_t shdr_status, shdr_add_status;
+	int fcp_eqidx;
+	union lpfc_sli4_cfg_shdr *shdr;
+	uint16_t dmult;
+
+	if (startq >= phba->cfg_fcp_eq_count)
+		return 0;
+
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	length = (sizeof(struct lpfc_mbx_modify_eq_delay) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+			 LPFC_MBOX_OPCODE_MODIFY_EQ_DELAY,
+			 length, LPFC_SLI4_MBX_EMBED);
+	eq_delay = &mbox->u.mqe.un.eq_delay;
+
+	/* Calculate delay multiper from maximum interrupt per second */
+	dmult = LPFC_DMULT_CONST/phba->cfg_fcp_imax - 1;
+
+	cnt = 0;
+	for (fcp_eqidx = startq; fcp_eqidx < phba->cfg_fcp_eq_count;
+	    fcp_eqidx++) {
+		eq = phba->sli4_hba.fp_eq[fcp_eqidx];
+		if (!eq)
+			continue;
+		eq_delay->u.request.eq[cnt].eq_id = eq->queue_id;
+		eq_delay->u.request.eq[cnt].phase = 0;
+		eq_delay->u.request.eq[cnt].delay_multi = dmult;
+		cnt++;
+		if (cnt >= LPFC_MAX_EQ_DELAY)
+			break;
+	}
+	eq_delay->u.request.num_eq = cnt;
+
+	mbox->vport = phba->pport;
+	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	mbox->context1 = NULL;
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	shdr = (union lpfc_sli4_cfg_shdr *) &eq_delay->header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2512 MODIFY_EQ_DELAY mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		status = -ENXIO;
+	}
+	mempool_free(mbox, phba->mbox_mem_pool);
+	return status;
+}
+
+/**
  * lpfc_eq_create - Create an Event Queue on the HBA
  * @phba: HBA structure that indicates port to create a queue on.
  * @eq: The queue structure to use to create the event queue.
@@ -12228,8 +12311,10 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
 		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 				"0361 Unsupported CQ count. (%d)\n",
 				cq->entry_count);
-		if (cq->entry_count < 256)
-			return -EINVAL;
+		if (cq->entry_count < 256) {
+			status = -EINVAL;
+			goto out;
+		}
 		/* otherwise default to smallest count (drop through) */
 	case 256:
 		bf_set(lpfc_cq_context_count, &cq_create->u.request.context,
@@ -12420,8 +12505,10 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
 		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 				"0362 Unsupported MQ count. (%d)\n",
 				mq->entry_count);
-		if (mq->entry_count < 16)
-			return -EINVAL;
+		if (mq->entry_count < 16) {
+			status = -EINVAL;
+			goto out;
+		}
 		/* otherwise default to smallest count (drop through) */
 	case 16:
 		bf_set(lpfc_mq_context_ring_size,
@@ -12710,8 +12797,10 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 					"2535 Unsupported RQ count. (%d)\n",
 					hrq->entry_count);
-			if (hrq->entry_count < 512)
-				return -EINVAL;
+			if (hrq->entry_count < 512) {
+				status = -EINVAL;
+				goto out;
+			}
 			/* otherwise default to smallest count (drop through) */
 		case 512:
 			bf_set(lpfc_rq_context_rqe_count,
@@ -12791,8 +12880,10 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 					"2536 Unsupported RQ count. (%d)\n",
 					drq->entry_count);
-			if (drq->entry_count < 512)
-				return -EINVAL;
+			if (drq->entry_count < 512) {
+				status = -EINVAL;
+				goto out;
+			}
 			/* otherwise default to smallest count (drop through) */
 		case 512:
 			bf_set(lpfc_rq_context_rqe_count,
@@ -15855,24 +15946,18 @@ lpfc_drain_txq(struct lpfc_hba *phba)
 		spin_lock_irqsave(&phba->hbalock, iflags);
 
 		piocbq = lpfc_sli_ringtx_get(phba, pring);
+		if (!piocbq) {
+			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;
+		}
 		sglq = __lpfc_sli_get_sglq(phba, piocbq);
 		if (!sglq) {
 			__lpfc_sli_ringtx_put(phba, pring, piocbq);
 			spin_unlock_irqrestore(&phba->hbalock, iflags);
 			break;
-		} else {
-			if (!piocbq) {
-				/* The txq_cnt out of sync. This should
-				 * never happen
-				 */
-				sglq = __lpfc_clear_active_sglq(phba,
-						 sglq->sli4_lxritag);
-				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,
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index a4a7708..ec75611 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -598,6 +598,7 @@ struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t,
 			uint32_t);
 void lpfc_sli4_queue_free(struct lpfc_queue *);
 uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t);
+uint32_t lpfc_modify_fcp_eq_delay(struct lpfc_hba *, uint16_t);
 uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *,
 			struct lpfc_queue *, uint32_t, uint32_t);
 int32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *,
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 59c57a4..4704e5b 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.31"
+#define LPFC_DRIVER_VERSION "8.3.32"
 #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/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index b6dd3a5..b3a1a30 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -1158,6 +1158,7 @@ extern struct scsi_transport_template *mpt2sas_transport_template;
 extern int scsi_internal_device_block(struct scsi_device *sdev);
 extern u8 mpt2sas_stm_zero_smid_handler(struct MPT2SAS_ADAPTER *ioc,
     u8 msix_index, u32 reply);
-extern int scsi_internal_device_unblock(struct scsi_device *sdev);
+extern int scsi_internal_device_unblock(struct scsi_device *sdev,
+					enum scsi_device_state new_state);
 
 #endif /* MPT2SAS_BASE_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 76973e8..b1ebd6f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -2904,7 +2904,7 @@ _scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc)
 		dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, "
 		    "handle(0x%04x)\n",
 		    sas_device_priv_data->sas_target->handle));
-		scsi_internal_device_unblock(sdev);
+		scsi_internal_device_unblock(sdev, SDEV_RUNNING);
 	}
 }
 /**
@@ -2933,7 +2933,7 @@ _scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
 			    "sas address(0x%016llx)\n", ioc->name,
 				(unsigned long long)sas_address));
 			sas_device_priv_data->block = 0;
-			scsi_internal_device_unblock(sdev);
+			scsi_internal_device_unblock(sdev, SDEV_RUNNING);
 		}
 	}
 }
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index fd3b283..4539d59 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -885,7 +885,6 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
 				struct completion *completion, int is_tmf,
 				struct mvs_tmf_task *tmf)
 {
-	struct domain_device *dev = task->dev;
 	struct mvs_info *mvi = NULL;
 	u32 rc = 0;
 	u32 pass = 0;
@@ -1365,9 +1364,9 @@ void mvs_dev_gone(struct domain_device *dev)
 
 static void mvs_task_done(struct sas_task *task)
 {
-	if (!del_timer(&task->timer))
+	if (!del_timer(&task->slow_task->timer))
 		return;
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 static void mvs_tmf_timedout(unsigned long data)
@@ -1375,7 +1374,7 @@ static void mvs_tmf_timedout(unsigned long data)
 	struct sas_task *task = (struct sas_task *)data;
 
 	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 #define MVS_TASK_TIMEOUT 20
@@ -1386,7 +1385,7 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev,
 	struct sas_task *task = NULL;
 
 	for (retry = 0; retry < 3; retry++) {
-		task = sas_alloc_task(GFP_KERNEL);
+		task = sas_alloc_slow_task(GFP_KERNEL);
 		if (!task)
 			return -ENOMEM;
 
@@ -1396,20 +1395,20 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev,
 		memcpy(&task->ssp_task, parameter, para_len);
 		task->task_done = mvs_task_done;
 
-		task->timer.data = (unsigned long) task;
-		task->timer.function = mvs_tmf_timedout;
-		task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ;
-		add_timer(&task->timer);
+		task->slow_task->timer.data = (unsigned long) task;
+		task->slow_task->timer.function = mvs_tmf_timedout;
+		task->slow_task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ;
+		add_timer(&task->slow_task->timer);
 
 		res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf);
 
 		if (res) {
-			del_timer(&task->timer);
+			del_timer(&task->slow_task->timer);
 			mv_printk("executing internel task failed:%d\n", res);
 			goto ex_err;
 		}
 
-		wait_for_completion(&task->completion);
+		wait_for_completion(&task->slow_task->completion);
 		res = TMF_RESP_FUNC_FAILED;
 		/* Even TMF timed out, return direct. */
 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 3b11edd..b961112 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -650,9 +650,9 @@ int pm8001_dev_found(struct domain_device *dev)
 
 static void pm8001_task_done(struct sas_task *task)
 {
-	if (!del_timer(&task->timer))
+	if (!del_timer(&task->slow_task->timer))
 		return;
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 static void pm8001_tmf_timedout(unsigned long data)
@@ -660,7 +660,7 @@ static void pm8001_tmf_timedout(unsigned long data)
 	struct sas_task *task = (struct sas_task *)data;
 
 	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
-	complete(&task->completion);
+	complete(&task->slow_task->completion);
 }
 
 #define PM8001_TASK_TIMEOUT 20
@@ -683,7 +683,7 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
 	struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev);
 
 	for (retry = 0; retry < 3; retry++) {
-		task = sas_alloc_task(GFP_KERNEL);
+		task = sas_alloc_slow_task(GFP_KERNEL);
 		if (!task)
 			return -ENOMEM;
 
@@ -691,21 +691,21 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
 		task->task_proto = dev->tproto;
 		memcpy(&task->ssp_task, parameter, para_len);
 		task->task_done = pm8001_task_done;
-		task->timer.data = (unsigned long)task;
-		task->timer.function = pm8001_tmf_timedout;
-		task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ;
-		add_timer(&task->timer);
+		task->slow_task->timer.data = (unsigned long)task;
+		task->slow_task->timer.function = pm8001_tmf_timedout;
+		task->slow_task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ;
+		add_timer(&task->slow_task->timer);
 
 		res = pm8001_task_exec(task, 1, GFP_KERNEL, 1, tmf);
 
 		if (res) {
-			del_timer(&task->timer);
+			del_timer(&task->slow_task->timer);
 			PM8001_FAIL_DBG(pm8001_ha,
 				pm8001_printk("Executing internal task "
 				"failed\n"));
 			goto ex_err;
 		}
-		wait_for_completion(&task->completion);
+		wait_for_completion(&task->slow_task->completion);
 		res = -TMF_RESP_FUNC_FAILED;
 		/* Even TMF timed out, return direct. */
 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
@@ -765,17 +765,17 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
 	struct sas_task *task = NULL;
 
 	for (retry = 0; retry < 3; retry++) {
-		task = sas_alloc_task(GFP_KERNEL);
+		task = sas_alloc_slow_task(GFP_KERNEL);
 		if (!task)
 			return -ENOMEM;
 
 		task->dev = dev;
 		task->task_proto = dev->tproto;
 		task->task_done = pm8001_task_done;
-		task->timer.data = (unsigned long)task;
-		task->timer.function = pm8001_tmf_timedout;
-		task->timer.expires = jiffies + PM8001_TASK_TIMEOUT * HZ;
-		add_timer(&task->timer);
+		task->slow_task->timer.data = (unsigned long)task;
+		task->slow_task->timer.function = pm8001_tmf_timedout;
+		task->slow_task->timer.expires = jiffies + PM8001_TASK_TIMEOUT * HZ;
+		add_timer(&task->slow_task->timer);
 
 		res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
 		if (res)
@@ -789,13 +789,13 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
 			pm8001_dev, flag, task_tag, ccb_tag);
 
 		if (res) {
-			del_timer(&task->timer);
+			del_timer(&task->slow_task->timer);
 			PM8001_FAIL_DBG(pm8001_ha,
 				pm8001_printk("Executing internal task "
 				"failed\n"));
 			goto ex_err;
 		}
-		wait_for_completion(&task->completion);
+		wait_for_completion(&task->slow_task->completion);
 		res = TMF_RESP_FUNC_FAILED;
 		/* Even TMF timed out, return direct. */
 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
@@ -962,8 +962,9 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev)
 	struct pm8001_device *pm8001_dev;
 	struct pm8001_hba_info *pm8001_ha;
 	struct sas_phy *phy;
+
 	if (!dev || !dev->lldd_dev)
-		return -1;
+		return -ENODEV;
 
 	pm8001_dev = dev->lldd_dev;
 	pm8001_ha = pm8001_find_ha_by_dev(dev);
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 96a5616..7fdba7f 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -279,6 +279,7 @@ struct qla_ddb_index {
 	struct list_head list;
 	uint16_t fw_ddb_idx;
 	struct dev_db_entry fw_ddb;
+	uint8_t flash_isid[6];
 };
 
 #define DDB_IPADDR_LEN 64
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 20b49d0..5b2525c 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -183,7 +183,8 @@ int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
 int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
 		       struct ddb_entry *ddb_entry, uint32_t state);
 void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset);
-int qla4xxx_post_aen_work(struct scsi_qla_host *ha, uint32_t aen_code,
+int qla4xxx_post_aen_work(struct scsi_qla_host *ha,
+			  enum iscsi_host_event_code aen_code,
 			  uint32_t data_size, uint8_t *data);
 int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options,
 		      uint32_t payload_size, uint32_t pid, uint8_t *ipaddr);
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index bf36723..ddd9472 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -126,7 +126,7 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha)
 
 	qla4xxx_init_response_q_entries(ha);
 
-	/* Initialize mabilbox active array */
+	/* Initialize mailbox active array */
 	for (i = 0; i < MAX_MRB; i++)
 		ha->active_mrb_array[i] = NULL;
 
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index cd15678..9da4266 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -4299,7 +4299,8 @@ static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry,
 }
 
 static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry,
-				      struct ql4_tuple_ddb *tddb)
+				      struct ql4_tuple_ddb *tddb,
+				      uint8_t *flash_isid)
 {
 	uint16_t options = 0;
 
@@ -4314,7 +4315,12 @@ static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry,
 		sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr);
 
 	tddb->port = le16_to_cpu(fw_ddb_entry->port);
-	memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0], sizeof(tddb->isid));
+
+	if (flash_isid == NULL)
+		memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0],
+		       sizeof(tddb->isid));
+	else
+		memcpy(&tddb->isid[0], &flash_isid[0], sizeof(tddb->isid));
 }
 
 static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha,
@@ -4385,7 +4391,7 @@ static int qla4xxx_is_session_exists(struct scsi_qla_host *ha,
 		goto exit_check;
 	}
 
-	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb);
+	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
 
 	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
 		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
@@ -4407,6 +4413,102 @@ exit_check:
 	return ret;
 }
 
+/**
+ * qla4xxx_check_existing_isid - check if target with same isid exist
+ *				 in target list
+ * @list_nt: list of target
+ * @isid: isid to check
+ *
+ * This routine return QLA_SUCCESS if target with same isid exist
+ **/
+static int qla4xxx_check_existing_isid(struct list_head *list_nt, uint8_t *isid)
+{
+	struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp;
+	struct dev_db_entry *fw_ddb_entry;
+
+	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
+		fw_ddb_entry = &nt_ddb_idx->fw_ddb;
+
+		if (memcmp(&fw_ddb_entry->isid[0], &isid[0],
+			   sizeof(nt_ddb_idx->fw_ddb.isid)) == 0) {
+			return QLA_SUCCESS;
+		}
+	}
+	return QLA_ERROR;
+}
+
+/**
+ * qla4xxx_update_isid - compare ddbs and updated isid
+ * @ha: Pointer to host adapter structure.
+ * @list_nt: list of nt target
+ * @fw_ddb_entry: firmware ddb entry
+ *
+ * This routine update isid if ddbs have same iqn, same isid and
+ * different IP addr.
+ * Return QLA_SUCCESS if isid is updated.
+ **/
+static int qla4xxx_update_isid(struct scsi_qla_host *ha,
+			       struct list_head *list_nt,
+			       struct dev_db_entry *fw_ddb_entry)
+{
+	uint8_t base_value, i;
+
+	base_value = fw_ddb_entry->isid[1] & 0x1f;
+	for (i = 0; i < 8; i++) {
+		fw_ddb_entry->isid[1] = (base_value | (i << 5));
+		if (qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
+			break;
+	}
+
+	if (!qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
+		return QLA_ERROR;
+
+	return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_should_update_isid - check if isid need to update
+ * @ha: Pointer to host adapter structure.
+ * @old_tddb: ddb tuple
+ * @new_tddb: ddb tuple
+ *
+ * Return QLA_SUCCESS if different IP, different PORT, same iqn,
+ * same isid
+ **/
+static int qla4xxx_should_update_isid(struct scsi_qla_host *ha,
+				      struct ql4_tuple_ddb *old_tddb,
+				      struct ql4_tuple_ddb *new_tddb)
+{
+	if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr) == 0) {
+		/* Same ip */
+		if (old_tddb->port == new_tddb->port)
+			return QLA_ERROR;
+	}
+
+	if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
+		/* different iqn */
+		return QLA_ERROR;
+
+	if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
+		   sizeof(old_tddb->isid)))
+		/* different isid */
+		return QLA_ERROR;
+
+	return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_is_flash_ddb_exists - check if fw_ddb_entry already exists in list_nt
+ * @ha: Pointer to host adapter structure.
+ * @list_nt: list of nt target.
+ * @fw_ddb_entry: firmware ddb entry.
+ *
+ * This routine check if fw_ddb_entry already exists in list_nt to avoid
+ * duplicate ddb in list_nt.
+ * Return QLA_SUCCESS if duplicate ddb exit in list_nl.
+ * Note: This function also update isid of DDB if required.
+ **/
+
 static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha,
 				       struct list_head *list_nt,
 				       struct dev_db_entry *fw_ddb_entry)
@@ -4414,7 +4516,7 @@ static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha,
 	struct qla_ddb_index  *nt_ddb_idx, *nt_ddb_idx_tmp;
 	struct ql4_tuple_ddb *fw_tddb = NULL;
 	struct ql4_tuple_ddb *tmp_tddb = NULL;
-	int ret = QLA_ERROR;
+	int rval, ret = QLA_ERROR;
 
 	fw_tddb = vzalloc(sizeof(*fw_tddb));
 	if (!fw_tddb) {
@@ -4432,12 +4534,28 @@ static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha,
 		goto exit_check;
 	}
 
-	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb);
+	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
 
 	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
-		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb);
-		if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true)) {
-			ret = QLA_SUCCESS; /* found */
+		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb,
+					  nt_ddb_idx->flash_isid);
+		ret = qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true);
+		/* found duplicate ddb */
+		if (ret == QLA_SUCCESS)
+			goto exit_check;
+	}
+
+	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
+		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb, NULL);
+
+		ret = qla4xxx_should_update_isid(ha, tmp_tddb, fw_tddb);
+		if (ret == QLA_SUCCESS) {
+			rval = qla4xxx_update_isid(ha, list_nt, fw_ddb_entry);
+			if (rval == QLA_SUCCESS)
+				ret = QLA_ERROR;
+			else
+				ret = QLA_SUCCESS;
+
 			goto exit_check;
 		}
 	}
@@ -4788,14 +4906,26 @@ static void qla4xxx_build_nt_list(struct scsi_qla_host *ha,
 
 			nt_ddb_idx->fw_ddb_idx = idx;
 
-			memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry,
-			       sizeof(struct dev_db_entry));
-
-			if (qla4xxx_is_flash_ddb_exists(ha, list_nt,
-					fw_ddb_entry) == QLA_SUCCESS) {
+			/* Copy original isid as it may get updated in function
+			 * qla4xxx_update_isid(). We need original isid in
+			 * function qla4xxx_compare_tuple_ddb to find duplicate
+			 * target */
+			memcpy(&nt_ddb_idx->flash_isid[0],
+			       &fw_ddb_entry->isid[0],
+			       sizeof(nt_ddb_idx->flash_isid));
+
+			ret = qla4xxx_is_flash_ddb_exists(ha, list_nt,
+							  fw_ddb_entry);
+			if (ret == QLA_SUCCESS) {
+				/* free nt_ddb_idx and do not add to list_nt */
 				vfree(nt_ddb_idx);
 				goto continue_next_nt;
 			}
+
+			/* Copy updated isid */
+			memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry,
+			       sizeof(struct dev_db_entry));
+
 			list_add_tail(&nt_ddb_idx->list, list_nt);
 		} else if (is_reset == RESET_ADAPTER) {
 			if (qla4xxx_is_session_exists(ha, fw_ddb_entry) ==
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index cc1cc35..725034f 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-k17"
+#define QLA4XXX_DRIVER_VERSION	"5.02.00-k18"
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index d0f71e5..63f9d22 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1687,6 +1687,20 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
 	 * requests are started.
 	 */
 	scsi_run_host_queues(shost);
+
+	/*
+	 * if eh is active and host_eh_scheduled is pending we need to re-run
+	 * recovery.  we do this check after scsi_run_host_queues() to allow
+	 * everything pent up since the last eh run a chance to make forward
+	 * progress before we sync again.  Either we'll immediately re-run
+	 * recovery or scsi_device_unbusy() will wake us again when these
+	 * pending commands complete.
+	 */
+	spin_lock_irqsave(shost->host_lock, flags);
+	if (shost->host_eh_scheduled)
+		if (scsi_host_set_state(shost, SHOST_RECOVERY))
+			WARN_ON(scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY));
+	spin_unlock_irqrestore(shost->host_lock, flags);
 }
 
 /**
@@ -1804,15 +1818,14 @@ int scsi_error_handler(void *data)
 	 * We never actually get interrupted because kthread_run
 	 * disables signal delivery for the created thread.
 	 */
-	set_current_state(TASK_INTERRUPTIBLE);
 	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
 		    shost->host_failed != shost->host_busy) {
 			SCSI_LOG_ERROR_RECOVERY(1,
 				printk("Error handler scsi_eh_%d sleeping\n",
 					shost->host_no));
 			schedule();
-			set_current_state(TASK_INTERRUPTIBLE);
 			continue;
 		}
 
@@ -1849,9 +1862,7 @@ int scsi_error_handler(void *data)
 		scsi_restart_operations(shost);
 		if (!shost->eh_noresume)
 			scsi_autopm_put_host(shost);
-		set_current_state(TASK_INTERRUPTIBLE);
 	}
-	__set_current_state(TASK_RUNNING);
 
 	SCSI_LOG_ERROR_RECOVERY(1,
 		printk("Error handler scsi_eh_%d exiting\n", shost->host_no));
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 6dfb978..9f00c12 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1173,6 +1173,7 @@ int scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
 	if (unlikely(sdev->sdev_state != SDEV_RUNNING)) {
 		switch (sdev->sdev_state) {
 		case SDEV_OFFLINE:
+		case SDEV_TRANSPORT_OFFLINE:
 			/*
 			 * If the device is offline we refuse to process any
 			 * commands.  The device must be brought online
@@ -2081,6 +2082,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 		switch (oldstate) {
 		case SDEV_CREATED:
 		case SDEV_OFFLINE:
+		case SDEV_TRANSPORT_OFFLINE:
 		case SDEV_QUIESCE:
 		case SDEV_BLOCK:
 			break;
@@ -2093,6 +2095,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 		switch (oldstate) {
 		case SDEV_RUNNING:
 		case SDEV_OFFLINE:
+		case SDEV_TRANSPORT_OFFLINE:
 			break;
 		default:
 			goto illegal;
@@ -2100,6 +2103,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 		break;
 
 	case SDEV_OFFLINE:
+	case SDEV_TRANSPORT_OFFLINE:
 		switch (oldstate) {
 		case SDEV_CREATED:
 		case SDEV_RUNNING:
@@ -2136,6 +2140,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 		case SDEV_RUNNING:
 		case SDEV_QUIESCE:
 		case SDEV_OFFLINE:
+		case SDEV_TRANSPORT_OFFLINE:
 		case SDEV_BLOCK:
 			break;
 		default:
@@ -2148,6 +2153,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 		case SDEV_CREATED:
 		case SDEV_RUNNING:
 		case SDEV_OFFLINE:
+		case SDEV_TRANSPORT_OFFLINE:
 		case SDEV_CANCEL:
 			break;
 		default:
@@ -2405,7 +2411,6 @@ EXPORT_SYMBOL(scsi_target_resume);
  *	(which must be a legal transition).  When the device is in this
  *	state, all commands are deferred until the scsi lld reenables
  *	the device with scsi_device_unblock or device_block_tmo fires.
- *	This routine assumes the host_lock is held on entry.
  */
 int
 scsi_internal_device_block(struct scsi_device *sdev)
@@ -2438,6 +2443,7 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block);
 /**
  * scsi_internal_device_unblock - resume a device after a block request
  * @sdev:	device to resume
+ * @new_state:	state to set devices to after unblocking
  *
  * Called by scsi lld's or the midlayer to restart the device queue
  * for the previously suspended scsi device.  Called from interrupt or
@@ -2447,25 +2453,29 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block);
  *
  * Notes:       
  *	This routine transitions the device to the SDEV_RUNNING state
- *	(which must be a legal transition) allowing the midlayer to
- *	goose the queue for this device.  This routine assumes the 
- *	host_lock is held upon entry.
+ *	or to one of the offline states (which must be a legal transition)
+ *	allowing the midlayer to goose the queue for this device.
  */
 int
-scsi_internal_device_unblock(struct scsi_device *sdev)
+scsi_internal_device_unblock(struct scsi_device *sdev,
+			     enum scsi_device_state new_state)
 {
 	struct request_queue *q = sdev->request_queue; 
 	unsigned long flags;
-	
-	/* 
-	 * Try to transition the scsi device to SDEV_RUNNING
-	 * and goose the device queue if successful.  
+
+	/*
+	 * Try to transition the scsi device to SDEV_RUNNING or one of the
+	 * offlined states and goose the device queue if successful.
 	 */
 	if (sdev->sdev_state == SDEV_BLOCK)
-		sdev->sdev_state = SDEV_RUNNING;
-	else if (sdev->sdev_state == SDEV_CREATED_BLOCK)
-		sdev->sdev_state = SDEV_CREATED;
-	else if (sdev->sdev_state != SDEV_CANCEL &&
+		sdev->sdev_state = new_state;
+	else if (sdev->sdev_state == SDEV_CREATED_BLOCK) {
+		if (new_state == SDEV_TRANSPORT_OFFLINE ||
+		    new_state == SDEV_OFFLINE)
+			sdev->sdev_state = new_state;
+		else
+			sdev->sdev_state = SDEV_CREATED;
+	} else if (sdev->sdev_state != SDEV_CANCEL &&
 		 sdev->sdev_state != SDEV_OFFLINE)
 		return -EINVAL;
 
@@ -2506,26 +2516,26 @@ EXPORT_SYMBOL_GPL(scsi_target_block);
 static void
 device_unblock(struct scsi_device *sdev, void *data)
 {
-	scsi_internal_device_unblock(sdev);
+	scsi_internal_device_unblock(sdev, *(enum scsi_device_state *)data);
 }
 
 static int
 target_unblock(struct device *dev, void *data)
 {
 	if (scsi_is_target_device(dev))
-		starget_for_each_device(to_scsi_target(dev), NULL,
+		starget_for_each_device(to_scsi_target(dev), data,
 					device_unblock);
 	return 0;
 }
 
 void
-scsi_target_unblock(struct device *dev)
+scsi_target_unblock(struct device *dev, enum scsi_device_state new_state)
 {
 	if (scsi_is_target_device(dev))
-		starget_for_each_device(to_scsi_target(dev), NULL,
+		starget_for_each_device(to_scsi_target(dev), &new_state,
 					device_unblock);
 	else
-		device_for_each_child(dev, NULL, target_unblock);
+		device_for_each_child(dev, &new_state, target_unblock);
 }
 EXPORT_SYMBOL_GPL(scsi_target_unblock);
 
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 07ce3f5..cbfe5df 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -2,6 +2,7 @@
 #define _SCSI_PRIV_H
 
 #include <linux/device.h>
+#include <scsi/scsi_device.h>
 
 struct request_queue;
 struct request;
@@ -172,6 +173,7 @@ extern struct list_head scsi_sd_probe_domain;
 
 #define SCSI_DEVICE_BLOCK_MAX_TIMEOUT	600	/* units in seconds */
 extern int scsi_internal_device_block(struct scsi_device *sdev);
-extern int scsi_internal_device_unblock(struct scsi_device *sdev);
+extern int scsi_internal_device_unblock(struct scsi_device *sdev,
+					enum scsi_device_state new_state);
 
 #endif /* _SCSI_PRIV_H */
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 04c2a27..5747478 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -35,6 +35,7 @@ static const struct {
 	{ SDEV_DEL, "deleted" },
 	{ SDEV_QUIESCE, "quiesce" },
 	{ SDEV_OFFLINE,	"offline" },
+	{ SDEV_TRANSPORT_OFFLINE, "transport-offline" },
 	{ SDEV_BLOCK,	"blocked" },
 	{ SDEV_CREATED_BLOCK, "created-blocked" },
 };
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 5797604..2d1e68d 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -1744,6 +1744,15 @@ fc_host_statistic(fcp_output_requests);
 fc_host_statistic(fcp_control_requests);
 fc_host_statistic(fcp_input_megabytes);
 fc_host_statistic(fcp_output_megabytes);
+fc_host_statistic(fcp_packet_alloc_failures);
+fc_host_statistic(fcp_packet_aborts);
+fc_host_statistic(fcp_frame_alloc_failures);
+fc_host_statistic(fc_no_free_exch);
+fc_host_statistic(fc_no_free_exch_xid);
+fc_host_statistic(fc_xid_not_found);
+fc_host_statistic(fc_xid_busy);
+fc_host_statistic(fc_seq_not_found);
+fc_host_statistic(fc_non_bls_resp);
 
 static ssize_t
 fc_reset_statistics(struct device *dev, struct device_attribute *attr,
@@ -1784,6 +1793,15 @@ static struct attribute *fc_statistics_attrs[] = {
 	&device_attr_host_fcp_control_requests.attr,
 	&device_attr_host_fcp_input_megabytes.attr,
 	&device_attr_host_fcp_output_megabytes.attr,
+	&device_attr_host_fcp_packet_alloc_failures.attr,
+	&device_attr_host_fcp_packet_aborts.attr,
+	&device_attr_host_fcp_frame_alloc_failures.attr,
+	&device_attr_host_fc_no_free_exch.attr,
+	&device_attr_host_fc_no_free_exch_xid.attr,
+	&device_attr_host_fc_xid_not_found.attr,
+	&device_attr_host_fc_xid_busy.attr,
+	&device_attr_host_fc_seq_not_found.attr,
+	&device_attr_host_fc_non_bls_resp.attr,
 	&device_attr_host_reset_statistics.attr,
 	NULL
 };
@@ -2477,11 +2495,9 @@ static void fc_terminate_rport_io(struct fc_rport *rport)
 		i->f->terminate_rport_io(rport);
 
 	/*
-	 * must unblock to flush queued IO. The caller will have set
-	 * the port_state or flags, so that fc_remote_port_chkready will
-	 * fail IO.
+	 * Must unblock to flush queued IO. scsi-ml will fail incoming reqs.
 	 */
-	scsi_target_unblock(&rport->dev);
+	scsi_target_unblock(&rport->dev, SDEV_TRANSPORT_OFFLINE);
 }
 
 /**
@@ -2812,8 +2828,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
 
 				/* if target, initiate a scan */
 				if (rport->scsi_target_id != -1) {
-					scsi_target_unblock(&rport->dev);
-
+					scsi_target_unblock(&rport->dev,
+							    SDEV_RUNNING);
 					spin_lock_irqsave(shost->host_lock,
 							  flags);
 					rport->flags |= FC_RPORT_SCAN_PENDING;
@@ -2882,7 +2898,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
 			spin_unlock_irqrestore(shost->host_lock, flags);
 
 			if (ids->roles & FC_PORT_ROLE_FCP_TARGET) {
-				scsi_target_unblock(&rport->dev);
+				scsi_target_unblock(&rport->dev, SDEV_RUNNING);
 
 				/* initiate a scan of the target */
 				spin_lock_irqsave(shost->host_lock, flags);
@@ -3087,7 +3103,7 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
 		/* ensure any stgt delete functions are done */
 		fc_flush_work(shost);
 
-		scsi_target_unblock(&rport->dev);
+		scsi_target_unblock(&rport->dev, SDEV_RUNNING);
 		/* initiate a scan of the target */
 		spin_lock_irqsave(shost->host_lock, flags);
 		rport->flags |= FC_RPORT_SCAN_PENDING;
@@ -3131,7 +3147,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
 			"blocked FC remote port time out: no longer"
 			" a FCP target, removing starget\n");
 		spin_unlock_irqrestore(shost->host_lock, flags);
-		scsi_target_unblock(&rport->dev);
+		scsi_target_unblock(&rport->dev, SDEV_TRANSPORT_OFFLINE);
 		fc_queue_work(shost, &rport->stgt_delete_work);
 		return;
 	}
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 1cf640e..96ec21a 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -907,7 +907,7 @@ static void session_recovery_timedout(struct work_struct *work)
 		session->transport->session_recovery_timedout(session);
 
 	ISCSI_DBG_TRANS_SESSION(session, "Unblocking SCSI target\n");
-	scsi_target_unblock(&session->dev);
+	scsi_target_unblock(&session->dev, SDEV_TRANSPORT_OFFLINE);
 	ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking SCSI target\n");
 }
 
@@ -930,7 +930,7 @@ static void __iscsi_unblock_session(struct work_struct *work)
 	session->state = ISCSI_SESSION_LOGGED_IN;
 	spin_unlock_irqrestore(&session->lock, flags);
 	/* start IO */
-	scsi_target_unblock(&session->dev);
+	scsi_target_unblock(&session->dev, SDEV_RUNNING);
 	/*
 	 * Only do kernel scanning if the driver is properly hooked into
 	 * the async scanning code (drivers like iscsi_tcp do login and
@@ -1180,7 +1180,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
 	session->state = ISCSI_SESSION_FREE;
 	spin_unlock_irqrestore(&session->lock, flags);
 
-	scsi_target_unblock(&session->dev);
+	scsi_target_unblock(&session->dev, SDEV_TRANSPORT_OFFLINE);
 	/* flush running scans then delete devices */
 	scsi_flush_work(shost);
 	__iscsi_unbind_session(&session->unbind_work);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index f7565fc..47abb90 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -33,8 +33,9 @@
 #include <linux/bsg.h>
 
 #include <scsi/scsi.h>
-#include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_scan.h>
+#include <scsi/scsi_device.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_sas.h>
 
@@ -1667,6 +1668,9 @@ sas_rphy_remove(struct sas_rphy *rphy)
 {
 	struct device *dev = &rphy->dev;
 
+	/* prevent device_del() while child device_add() may be in-flight */
+	scsi_complete_async_scans();
+
 	switch (rphy->identify.device_type) {
 	case SAS_END_DEVICE:
 		scsi_remove_target(dev);
diff --git a/drivers/scsi/scsi_wait_scan.c b/drivers/scsi/scsi_wait_scan.c
deleted file mode 100644
index ae78148..0000000
--- a/drivers/scsi/scsi_wait_scan.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * scsi_wait_scan.c
- *
- * Copyright (C) 2006 James Bottomley <James.Bottomley@SteelEye.com>
- *
- * This is a simple module to wait until all the async scans are
- * complete.  The idea is to use it in initrd/initramfs scripts.  You
- * modprobe it after all the modprobes of the root SCSI drivers and it
- * will wait until they have all finished scanning their busses before
- * allowing the boot to proceed
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include "scsi_priv.h"
-
-static int __init wait_scan_init(void)
-{
-	/*
-	 * First we need to wait for device probing to finish;
-	 * the drivers we just loaded might just still be probing
-	 * and might not yet have reached the scsi async scanning
-	 */
-	wait_for_device_probe();
-	/*
-	 * and then we wait for the actual asynchronous scsi scan
-	 * to finish.
-	 */
-	scsi_complete_async_scans();
-	return 0;
-}
-
-static void __exit wait_scan_exit(void)
-{
-}
-
-MODULE_DESCRIPTION("SCSI wait for scans");
-MODULE_AUTHOR("James Bottomley");
-MODULE_LICENSE("GPL");
-
-late_initcall(wait_scan_init);
-module_exit(wait_scan_exit);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 6f0a4c6..6f72b80 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1899,6 +1899,8 @@ static int sd_try_rc16_first(struct scsi_device *sdp)
 {
 	if (sdp->host->max_cmd_len < 16)
 		return 0;
+	if (sdp->try_rc_10_first)
+		return 0;
 	if (sdp->scsi_level > SCSI_SPC_2)
 		return 1;
 	if (scsi_device_protection(sdp))
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6a4fd00..58f4ba6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -232,11 +232,11 @@ static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
  *			      the host controller
  * @reg_hcs - host controller status register value
  *
- * Returns 0 if device present, non-zero if no device detected
+ * Returns 1 if device present, 0 if no device detected
  */
 static inline int ufshcd_is_device_present(u32 reg_hcs)
 {
-	return (DEVICE_PRESENT & reg_hcs) ? 0 : -1;
+	return (DEVICE_PRESENT & reg_hcs) ? 1 : 0;
 }
 
 /**
@@ -911,7 +911,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
 
 	/* check if device present */
 	reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
-	if (ufshcd_is_device_present(reg)) {
+	if (!ufshcd_is_device_present(reg)) {
 		dev_err(&hba->pdev->dev, "cc: Device not present\n");
 		err = -ENXIO;
 		goto out;
@@ -1163,6 +1163,8 @@ static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index)
 		if (task_result != UPIU_TASK_MANAGEMENT_FUNC_COMPL &&
 		    task_result != UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED)
 			task_result = FAILED;
+		else
+			task_result = SUCCESS;
 	} else {
 		task_result = FAILED;
 		dev_err(&hba->pdev->dev,
@@ -1556,7 +1558,7 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
 		goto out;
 	}
 	clear_bit(free_slot, &hba->tm_condition);
-	return ufshcd_task_req_compl(hba, free_slot);
+	err = ufshcd_task_req_compl(hba, free_slot);
 out:
 	return err;
 }
@@ -1580,7 +1582,7 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
 	tag = cmd->request->tag;
 
 	err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag], UFS_LOGICAL_RESET);
-	if (err)
+	if (err == FAILED)
 		goto out;
 
 	for (pos = 0; pos < hba->nutrs; pos++) {
@@ -1620,7 +1622,7 @@ static int ufshcd_host_reset(struct scsi_cmnd *cmd)
 	if (hba->ufshcd_state == UFSHCD_STATE_RESET)
 		return SUCCESS;
 
-	return (ufshcd_do_reset(hba) == SUCCESS) ? SUCCESS : FAILED;
+	return ufshcd_do_reset(hba);
 }
 
 /**
@@ -1652,7 +1654,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
 	spin_unlock_irqrestore(host->host_lock, flags);
 
 	err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag], UFS_ABORT_TASK);
-	if (err)
+	if (err == FAILED)
 		goto out;
 
 	scsi_dma_unmap(cmd);
@@ -1953,24 +1955,7 @@ static struct pci_driver ufshcd_pci_driver = {
 #endif
 };
 
-/**
- * ufshcd_init - Driver registration routine
- */
-static int __init ufshcd_init(void)
-{
-	return pci_register_driver(&ufshcd_pci_driver);
-}
-module_init(ufshcd_init);
-
-/**
- * ufshcd_exit - Driver exit clean-up routine
- */
-static void __exit ufshcd_exit(void)
-{
-	pci_unregister_driver(&ufshcd_pci_driver);
-}
-module_exit(ufshcd_exit);
-
+module_pci_driver(ufshcd_pci_driver);
 
 MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>, "
 	      "Vinayak Holikatti <h.vinayak@samsung.com>");
diff --git a/drivers/sh/Kconfig b/drivers/sh/Kconfig
index f168a61..d7dbfee 100644
--- a/drivers/sh/Kconfig
+++ b/drivers/sh/Kconfig
@@ -2,4 +2,19 @@ menu "SuperH / SH-Mobile Driver Options"
 
 source "drivers/sh/intc/Kconfig"
 
+comment "Pin function controller options"
+
+config SH_PFC
+	# XXX move off the gpio dependency
+	depends on GENERIC_GPIO
+	select GPIO_SH_PFC if ARCH_REQUIRE_GPIOLIB
+	def_bool y
+
+config GPIO_SH_PFC
+	tristate "SuperH PFC GPIO support"
+	depends on SH_PFC && GPIOLIB
+	help
+	  This enables support for GPIOs within the SoC's pin function
+	  controller.
+
 endmenu
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index 7139ad2..f5d93e8 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -6,5 +6,6 @@ obj-y	:= intc/
 obj-$(CONFIG_HAVE_CLK)		+= clk/
 obj-$(CONFIG_MAPLE)		+= maple/
 obj-$(CONFIG_SUPERHYWAY)	+= superhyway/
-obj-$(CONFIG_GENERIC_GPIO)	+= pfc.o
+obj-$(CONFIG_SH_PFC)		+= pfc.o
+obj-$(CONFIG_GPIO_SH_PFC)	+= pfc-gpio.o
 obj-y				+= pm_runtime.o
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
index f0d015d..07e9fb4 100644
--- a/drivers/sh/clk/cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -14,6 +14,8 @@
 #include <linux/io.h>
 #include <linux/sh_clk.h>
 
+#define CPG_CKSTP_BIT	BIT(8)
+
 static unsigned int sh_clk_read(struct clk *clk)
 {
 	if (clk->flags & CLK_ENABLE_REG_8BIT)
@@ -66,71 +68,43 @@ int __init sh_clk_mstp_register(struct clk *clks, int nr)
 	return ret;
 }
 
-static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
+/*
+ * Div/mult table lookup helpers
+ */
+static inline struct clk_div_table *clk_to_div_table(struct clk *clk)
 {
-	return clk_rate_table_round(clk, clk->freq_table, rate);
+	return clk->priv;
 }
 
-static int sh_clk_div6_divisors[64] = {
-	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
-	33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
-	49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
-};
+static inline struct clk_div_mult_table *clk_to_div_mult_table(struct clk *clk)
+{
+	return clk_to_div_table(clk)->div_mult_table;
+}
 
-static struct clk_div_mult_table sh_clk_div6_table = {
-	.divisors = sh_clk_div6_divisors,
-	.nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
-};
+/*
+ * Common div ops
+ */
+static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
+{
+	return clk_rate_table_round(clk, clk->freq_table, rate);
+}
 
-static unsigned long sh_clk_div6_recalc(struct clk *clk)
+static unsigned long sh_clk_div_recalc(struct clk *clk)
 {
-	struct clk_div_mult_table *table = &sh_clk_div6_table;
+	struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
 	unsigned int idx;
 
 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
-			     table, NULL);
+			     table, clk->arch_flags ? &clk->arch_flags : NULL);
 
-	idx = sh_clk_read(clk) & 0x003f;
+	idx = (sh_clk_read(clk) >> clk->enable_bit) & clk->div_mask;
 
 	return clk->freq_table[idx].frequency;
 }
 
-static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
-{
-	struct clk_div_mult_table *table = &sh_clk_div6_table;
-	u32 value;
-	int ret, i;
-
-	if (!clk->parent_table || !clk->parent_num)
-		return -EINVAL;
-
-	/* Search the parent */
-	for (i = 0; i < clk->parent_num; i++)
-		if (clk->parent_table[i] == parent)
-			break;
-
-	if (i == clk->parent_num)
-		return -ENODEV;
-
-	ret = clk_reparent(clk, parent);
-	if (ret < 0)
-		return ret;
-
-	value = sh_clk_read(clk) &
-		~(((1 << clk->src_width) - 1) << clk->src_shift);
-
-	sh_clk_write(value | (i << clk->src_shift), clk);
-
-	/* Rebuild the frequency table */
-	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
-			     table, NULL);
-
-	return 0;
-}
-
-static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
+static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate)
 {
+	struct clk_div_table *dt = clk_to_div_table(clk);
 	unsigned long value;
 	int idx;
 
@@ -139,51 +113,53 @@ static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
 		return idx;
 
 	value = sh_clk_read(clk);
-	value &= ~0x3f;
-	value |= idx;
+	value &= ~(clk->div_mask << clk->enable_bit);
+	value |= (idx << clk->enable_bit);
 	sh_clk_write(value, clk);
+
+	/* XXX: Should use a post-change notifier */
+	if (dt->kick)
+		dt->kick(clk);
+
 	return 0;
 }
 
-static int sh_clk_div6_enable(struct clk *clk)
+static int sh_clk_div_enable(struct clk *clk)
 {
-	unsigned long value;
-	int ret;
-
-	ret = sh_clk_div6_set_rate(clk, clk->rate);
-	if (ret == 0) {
-		value = sh_clk_read(clk);
-		value &= ~0x100; /* clear stop bit to enable clock */
-		sh_clk_write(value, clk);
-	}
-	return ret;
+	sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk);
+	return 0;
 }
 
-static void sh_clk_div6_disable(struct clk *clk)
+static void sh_clk_div_disable(struct clk *clk)
 {
-	unsigned long value;
+	unsigned int val;
 
-	value = sh_clk_read(clk);
-	value |= 0x100; /* stop clock */
-	value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
-	sh_clk_write(value, clk);
+	val = sh_clk_read(clk);
+	val |= CPG_CKSTP_BIT;
+
+	/*
+	 * div6 clocks require the divisor field to be non-zero or the
+	 * above CKSTP toggle silently fails. Ensure that the divisor
+	 * array is reset to its initial state on disable.
+	 */
+	if (clk->flags & CLK_MASK_DIV_ON_DISABLE)
+		val |= clk->div_mask;
+
+	sh_clk_write(val, clk);
 }
 
-static struct sh_clk_ops sh_clk_div6_clk_ops = {
-	.recalc		= sh_clk_div6_recalc,
+static struct sh_clk_ops sh_clk_div_clk_ops = {
+	.recalc		= sh_clk_div_recalc,
+	.set_rate	= sh_clk_div_set_rate,
 	.round_rate	= sh_clk_div_round_rate,
-	.set_rate	= sh_clk_div6_set_rate,
-	.enable		= sh_clk_div6_enable,
-	.disable	= sh_clk_div6_disable,
 };
 
-static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = {
-	.recalc		= sh_clk_div6_recalc,
+static struct sh_clk_ops sh_clk_div_enable_clk_ops = {
+	.recalc		= sh_clk_div_recalc,
+	.set_rate	= sh_clk_div_set_rate,
 	.round_rate	= sh_clk_div_round_rate,
-	.set_rate	= sh_clk_div6_set_rate,
-	.enable		= sh_clk_div6_enable,
-	.disable	= sh_clk_div6_disable,
-	.set_parent	= sh_clk_div6_set_parent,
+	.enable		= sh_clk_div_enable,
+	.disable	= sh_clk_div_disable,
 };
 
 static int __init sh_clk_init_parent(struct clk *clk)
@@ -218,12 +194,12 @@ static int __init sh_clk_init_parent(struct clk *clk)
 	return 0;
 }
 
-static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
-					   struct sh_clk_ops *ops)
+static int __init sh_clk_div_register_ops(struct clk *clks, int nr,
+			struct clk_div_table *table, struct sh_clk_ops *ops)
 {
 	struct clk *clkp;
 	void *freq_table;
-	int nr_divs = sh_clk_div6_table.nr_divisors;
+	int nr_divs = table->div_mult_table->nr_divisors;
 	int freq_table_size = sizeof(struct cpufreq_frequency_table);
 	int ret = 0;
 	int k;
@@ -231,7 +207,7 @@ static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
 	freq_table_size *= (nr_divs + 1);
 	freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
 	if (!freq_table) {
-		pr_err("sh_clk_div6_register: unable to alloc memory\n");
+		pr_err("%s: unable to alloc memory\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -239,47 +215,98 @@ static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
 		clkp = clks + k;
 
 		clkp->ops = ops;
+		clkp->priv = table;
+
 		clkp->freq_table = freq_table + (k * freq_table_size);
 		clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
-		ret = clk_register(clkp);
-		if (ret < 0)
-			break;
 
-		ret = sh_clk_init_parent(clkp);
+		ret = clk_register(clkp);
+		if (ret == 0)
+			ret = sh_clk_init_parent(clkp);
 	}
 
 	return ret;
 }
 
-int __init sh_clk_div6_register(struct clk *clks, int nr)
-{
-	return sh_clk_div6_register_ops(clks, nr, &sh_clk_div6_clk_ops);
-}
+/*
+ * div6 support
+ */
+static int sh_clk_div6_divisors[64] = {
+	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+	33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+	49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
+};
 
-int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
-{
-	return sh_clk_div6_register_ops(clks, nr,
-					&sh_clk_div6_reparent_clk_ops);
-}
+static struct clk_div_mult_table div6_div_mult_table = {
+	.divisors = sh_clk_div6_divisors,
+	.nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
+};
 
-static unsigned long sh_clk_div4_recalc(struct clk *clk)
+static struct clk_div_table sh_clk_div6_table = {
+	.div_mult_table	= &div6_div_mult_table,
+};
+
+static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
 {
-	struct clk_div4_table *d4t = clk->priv;
-	struct clk_div_mult_table *table = d4t->div_mult_table;
-	unsigned int idx;
+	struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
+	u32 value;
+	int ret, i;
 
+	if (!clk->parent_table || !clk->parent_num)
+		return -EINVAL;
+
+	/* Search the parent */
+	for (i = 0; i < clk->parent_num; i++)
+		if (clk->parent_table[i] == parent)
+			break;
+
+	if (i == clk->parent_num)
+		return -ENODEV;
+
+	ret = clk_reparent(clk, parent);
+	if (ret < 0)
+		return ret;
+
+	value = sh_clk_read(clk) &
+		~(((1 << clk->src_width) - 1) << clk->src_shift);
+
+	sh_clk_write(value | (i << clk->src_shift), clk);
+
+	/* Rebuild the frequency table */
 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
-			     table, &clk->arch_flags);
+			     table, NULL);
 
-	idx = (sh_clk_read(clk) >> clk->enable_bit) & 0x000f;
+	return 0;
+}
 
-	return clk->freq_table[idx].frequency;
+static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = {
+	.recalc		= sh_clk_div_recalc,
+	.round_rate	= sh_clk_div_round_rate,
+	.set_rate	= sh_clk_div_set_rate,
+	.enable		= sh_clk_div_enable,
+	.disable	= sh_clk_div_disable,
+	.set_parent	= sh_clk_div6_set_parent,
+};
+
+int __init sh_clk_div6_register(struct clk *clks, int nr)
+{
+	return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
+				       &sh_clk_div_enable_clk_ops);
+}
+
+int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
+{
+	return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
+				       &sh_clk_div6_reparent_clk_ops);
 }
 
+/*
+ * div4 support
+ */
 static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
 {
-	struct clk_div4_table *d4t = clk->priv;
-	struct clk_div_mult_table *table = d4t->div_mult_table;
+	struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
 	u32 value;
 	int ret;
 
@@ -306,107 +333,31 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
 	return 0;
 }
 
-static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
-{
-	struct clk_div4_table *d4t = clk->priv;
-	unsigned long value;
-	int idx = clk_rate_table_find(clk, clk->freq_table, rate);
-	if (idx < 0)
-		return idx;
-
-	value = sh_clk_read(clk);
-	value &= ~(0xf << clk->enable_bit);
-	value |= (idx << clk->enable_bit);
-	sh_clk_write(value, clk);
-
-	if (d4t->kick)
-		d4t->kick(clk);
-
-	return 0;
-}
-
-static int sh_clk_div4_enable(struct clk *clk)
-{
-	sh_clk_write(sh_clk_read(clk) & ~(1 << 8), clk);
-	return 0;
-}
-
-static void sh_clk_div4_disable(struct clk *clk)
-{
-	sh_clk_write(sh_clk_read(clk) | (1 << 8), clk);
-}
-
-static struct sh_clk_ops sh_clk_div4_clk_ops = {
-	.recalc		= sh_clk_div4_recalc,
-	.set_rate	= sh_clk_div4_set_rate,
-	.round_rate	= sh_clk_div_round_rate,
-};
-
-static struct sh_clk_ops sh_clk_div4_enable_clk_ops = {
-	.recalc		= sh_clk_div4_recalc,
-	.set_rate	= sh_clk_div4_set_rate,
-	.round_rate	= sh_clk_div_round_rate,
-	.enable		= sh_clk_div4_enable,
-	.disable	= sh_clk_div4_disable,
-};
-
 static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = {
-	.recalc		= sh_clk_div4_recalc,
-	.set_rate	= sh_clk_div4_set_rate,
+	.recalc		= sh_clk_div_recalc,
+	.set_rate	= sh_clk_div_set_rate,
 	.round_rate	= sh_clk_div_round_rate,
-	.enable		= sh_clk_div4_enable,
-	.disable	= sh_clk_div4_disable,
+	.enable		= sh_clk_div_enable,
+	.disable	= sh_clk_div_disable,
 	.set_parent	= sh_clk_div4_set_parent,
 };
 
-static int __init sh_clk_div4_register_ops(struct clk *clks, int nr,
-			struct clk_div4_table *table, struct sh_clk_ops *ops)
-{
-	struct clk *clkp;
-	void *freq_table;
-	int nr_divs = table->div_mult_table->nr_divisors;
-	int freq_table_size = sizeof(struct cpufreq_frequency_table);
-	int ret = 0;
-	int k;
-
-	freq_table_size *= (nr_divs + 1);
-	freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
-	if (!freq_table) {
-		pr_err("sh_clk_div4_register: unable to alloc memory\n");
-		return -ENOMEM;
-	}
-
-	for (k = 0; !ret && (k < nr); k++) {
-		clkp = clks + k;
-
-		clkp->ops = ops;
-		clkp->priv = table;
-
-		clkp->freq_table = freq_table + (k * freq_table_size);
-		clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
-
-		ret = clk_register(clkp);
-	}
-
-	return ret;
-}
-
 int __init sh_clk_div4_register(struct clk *clks, int nr,
 				struct clk_div4_table *table)
 {
-	return sh_clk_div4_register_ops(clks, nr, table, &sh_clk_div4_clk_ops);
+	return sh_clk_div_register_ops(clks, nr, table, &sh_clk_div_clk_ops);
 }
 
 int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
 				struct clk_div4_table *table)
 {
-	return sh_clk_div4_register_ops(clks, nr, table,
-					&sh_clk_div4_enable_clk_ops);
+	return sh_clk_div_register_ops(clks, nr, table,
+				       &sh_clk_div_enable_clk_ops);
 }
 
 int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
 				struct clk_div4_table *table)
 {
-	return sh_clk_div4_register_ops(clks, nr, table,
-					&sh_clk_div4_reparent_clk_ops);
+	return sh_clk_div_register_ops(clks, nr, table,
+				       &sh_clk_div4_reparent_clk_ops);
 }
diff --git a/drivers/sh/intc/Makefile b/drivers/sh/intc/Makefile
index bb5df86..44f006d 100644
--- a/drivers/sh/intc/Makefile
+++ b/drivers/sh/intc/Makefile
@@ -1,4 +1,4 @@
-obj-y 	:= access.o chip.o core.o dynamic.o handle.o virq.o
+obj-y 	:= access.o chip.o core.o handle.o virq.o
 
 obj-$(CONFIG_INTC_BALANCING)		+= balancing.o
 obj-$(CONFIG_INTC_USERIMASK)		+= userimask.o
diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c
deleted file mode 100644
index 14eb01e..0000000
--- a/drivers/sh/intc/dynamic.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Dynamic IRQ management
- *
- * Copyright (C) 2010  Paul Mundt
- *
- * Modelled after arch/x86/kernel/apic/io_apic.c
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#define pr_fmt(fmt) "intc: " fmt
-
-#include <linux/irq.h>
-#include <linux/bitmap.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include "internals.h" /* only for activate_irq() damage.. */
-
-/*
- * The IRQ bitmap provides a global map of bound IRQ vectors for a
- * given platform. Allocation of IRQs are either static through the CPU
- * vector map, or dynamic in the case of board mux vectors or MSI.
- *
- * As this is a central point for all IRQ controllers on the system,
- * each of the available sources are mapped out here. This combined with
- * sparseirq makes it quite trivial to keep the vector map tightly packed
- * when dynamically creating IRQs, as well as tying in to otherwise
- * unused irq_desc positions in the sparse array.
- */
-
-/*
- * Dynamic IRQ allocation and deallocation
- */
-unsigned int create_irq_nr(unsigned int irq_want, int node)
-{
-	int irq = irq_alloc_desc_at(irq_want, node);
-	if (irq < 0)
-		return 0;
-
-	activate_irq(irq);
-	return irq;
-}
-
-int create_irq(void)
-{
-	int irq = irq_alloc_desc(numa_node_id());
-	if (irq >= 0)
-		activate_irq(irq);
-
-	return irq;
-}
-
-void destroy_irq(unsigned int irq)
-{
-	irq_free_desc(irq);
-}
diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c
index 93cec21..f30ac93 100644
--- a/drivers/sh/intc/virq.c
+++ b/drivers/sh/intc/virq.c
@@ -219,12 +219,14 @@ restart:
 		if (radix_tree_deref_retry(entry))
 			goto restart;
 
-		irq = create_irq();
+		irq = irq_alloc_desc(numa_node_id());
 		if (unlikely(irq < 0)) {
 			pr_err("no more free IRQs, bailing..\n");
 			break;
 		}
 
+		activate_irq(irq);
+
 		pr_info("Setting up a chained VIRQ from %d -> %d\n",
 			irq, entry->pirq);
 
diff --git a/drivers/sh/pfc-gpio.c b/drivers/sh/pfc-gpio.c
new file mode 100644
index 0000000..d74e5a9
--- /dev/null
+++ b/drivers/sh/pfc-gpio.c
@@ -0,0 +1,309 @@
+/*
+ * SuperH Pin Function Controller GPIO driver.
+ *
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2009 - 2012 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+struct sh_pfc_chip {
+	struct sh_pfc		*pfc;
+	struct gpio_chip	gpio_chip;
+};
+
+static struct sh_pfc_chip *gpio_to_pfc_chip(struct gpio_chip *gc)
+{
+	return container_of(gc, struct sh_pfc_chip, gpio_chip);
+}
+
+static struct sh_pfc *gpio_to_pfc(struct gpio_chip *gc)
+{
+	return gpio_to_pfc_chip(gc)->pfc;
+}
+
+static int sh_gpio_request(struct gpio_chip *gc, unsigned offset)
+{
+	struct sh_pfc *pfc = gpio_to_pfc(gc);
+	struct pinmux_data_reg *dummy;
+	unsigned long flags;
+	int i, ret, pinmux_type;
+
+	ret = -EINVAL;
+
+	if (!pfc)
+		goto err_out;
+
+	spin_lock_irqsave(&pfc->lock, flags);
+
+	if ((pfc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE)
+		goto err_unlock;
+
+	/* setup pin function here if no data is associated with pin */
+
+	if (sh_pfc_get_data_reg(pfc, offset, &dummy, &i) != 0)
+		pinmux_type = PINMUX_TYPE_FUNCTION;
+	else
+		pinmux_type = PINMUX_TYPE_GPIO;
+
+	if (pinmux_type == PINMUX_TYPE_FUNCTION) {
+		if (sh_pfc_config_gpio(pfc, offset,
+				       pinmux_type,
+				       GPIO_CFG_DRYRUN) != 0)
+			goto err_unlock;
+
+		if (sh_pfc_config_gpio(pfc, offset,
+				       pinmux_type,
+				       GPIO_CFG_REQ) != 0)
+			BUG();
+	}
+
+	pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+	pfc->gpios[offset].flags |= pinmux_type;
+
+	ret = 0;
+ err_unlock:
+	spin_unlock_irqrestore(&pfc->lock, flags);
+ err_out:
+	return ret;
+}
+
+static void sh_gpio_free(struct gpio_chip *gc, unsigned offset)
+{
+	struct sh_pfc *pfc = gpio_to_pfc(gc);
+	unsigned long flags;
+	int pinmux_type;
+
+	if (!pfc)
+		return;
+
+	spin_lock_irqsave(&pfc->lock, flags);
+
+	pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE;
+	sh_pfc_config_gpio(pfc, offset, pinmux_type, GPIO_CFG_FREE);
+	pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+	pfc->gpios[offset].flags |= PINMUX_TYPE_NONE;
+
+	spin_unlock_irqrestore(&pfc->lock, flags);
+}
+
+static int sh_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+	struct sh_pfc *pfc = gpio_to_pfc(gc);
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&pfc->lock, flags);
+	ret = sh_pfc_set_direction(pfc, offset, PINMUX_TYPE_INPUT);
+	spin_unlock_irqrestore(&pfc->lock, flags);
+
+	return ret;
+}
+
+static void sh_gpio_set_value(struct sh_pfc *pfc, unsigned gpio, int value)
+{
+	struct pinmux_data_reg *dr = NULL;
+	int bit = 0;
+
+	if (!pfc || sh_pfc_get_data_reg(pfc, gpio, &dr, &bit) != 0)
+		BUG();
+	else
+		sh_pfc_write_bit(dr, bit, value);
+}
+
+static int sh_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
+				    int value)
+{
+	struct sh_pfc *pfc = gpio_to_pfc(gc);
+	unsigned long flags;
+	int ret;
+
+	sh_gpio_set_value(pfc, offset, value);
+
+	spin_lock_irqsave(&pfc->lock, flags);
+	ret = sh_pfc_set_direction(pfc, offset, PINMUX_TYPE_OUTPUT);
+	spin_unlock_irqrestore(&pfc->lock, flags);
+
+	return ret;
+}
+
+static int sh_gpio_get_value(struct sh_pfc *pfc, unsigned gpio)
+{
+	struct pinmux_data_reg *dr = NULL;
+	int bit = 0;
+
+	if (!pfc || sh_pfc_get_data_reg(pfc, gpio, &dr, &bit) != 0)
+		return -EINVAL;
+
+	return sh_pfc_read_bit(dr, bit);
+}
+
+static int sh_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+	return sh_gpio_get_value(gpio_to_pfc(gc), offset);
+}
+
+static void sh_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+	sh_gpio_set_value(gpio_to_pfc(gc), offset, value);
+}
+
+static int sh_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+	struct sh_pfc *pfc = gpio_to_pfc(gc);
+	pinmux_enum_t enum_id;
+	pinmux_enum_t *enum_ids;
+	int i, k, pos;
+
+	pos = 0;
+	enum_id = 0;
+	while (1) {
+		pos = sh_pfc_gpio_to_enum(pfc, offset, pos, &enum_id);
+		if (pos <= 0 || !enum_id)
+			break;
+
+		for (i = 0; i < pfc->gpio_irq_size; i++) {
+			enum_ids = pfc->gpio_irq[i].enum_ids;
+			for (k = 0; enum_ids[k]; k++) {
+				if (enum_ids[k] == enum_id)
+					return pfc->gpio_irq[i].irq;
+			}
+		}
+	}
+
+	return -ENOSYS;
+}
+
+static void sh_pfc_gpio_setup(struct sh_pfc_chip *chip)
+{
+	struct sh_pfc *pfc = chip->pfc;
+	struct gpio_chip *gc = &chip->gpio_chip;
+
+	gc->request = sh_gpio_request;
+	gc->free = sh_gpio_free;
+	gc->direction_input = sh_gpio_direction_input;
+	gc->get = sh_gpio_get;
+	gc->direction_output = sh_gpio_direction_output;
+	gc->set = sh_gpio_set;
+	gc->to_irq = sh_gpio_to_irq;
+
+	WARN_ON(pfc->first_gpio != 0); /* needs testing */
+
+	gc->label = pfc->name;
+	gc->owner = THIS_MODULE;
+	gc->base = pfc->first_gpio;
+	gc->ngpio = (pfc->last_gpio - pfc->first_gpio) + 1;
+}
+
+int sh_pfc_register_gpiochip(struct sh_pfc *pfc)
+{
+	struct sh_pfc_chip *chip;
+	int ret;
+
+	chip = kzalloc(sizeof(struct sh_pfc_chip), GFP_KERNEL);
+	if (unlikely(!chip))
+		return -ENOMEM;
+
+	chip->pfc = pfc;
+
+	sh_pfc_gpio_setup(chip);
+
+	ret = gpiochip_add(&chip->gpio_chip);
+	if (unlikely(ret < 0))
+		kfree(chip);
+
+	pr_info("%s handling gpio %d -> %d\n",
+		pfc->name, pfc->first_gpio, pfc->last_gpio);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sh_pfc_register_gpiochip);
+
+static int sh_pfc_gpio_match(struct gpio_chip *gc, void *data)
+{
+	return !!strstr(gc->label, data);
+}
+
+static int __devinit sh_pfc_gpio_probe(struct platform_device *pdev)
+{
+	struct sh_pfc_chip *chip;
+	struct gpio_chip *gc;
+
+	gc = gpiochip_find("_pfc", sh_pfc_gpio_match);
+	if (unlikely(!gc)) {
+		pr_err("Cant find gpio chip\n");
+		return -ENODEV;
+	}
+
+	chip = gpio_to_pfc_chip(gc);
+	platform_set_drvdata(pdev, chip);
+
+	pr_info("attaching to GPIO chip %s\n", chip->pfc->name);
+
+	return 0;
+}
+
+static int __devexit sh_pfc_gpio_remove(struct platform_device *pdev)
+{
+	struct sh_pfc_chip *chip = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = gpiochip_remove(&chip->gpio_chip);
+	if (unlikely(ret < 0))
+		return ret;
+
+	kfree(chip);
+	return 0;
+}
+
+static struct platform_driver sh_pfc_gpio_driver = {
+	.probe		= sh_pfc_gpio_probe,
+	.remove		= __devexit_p(sh_pfc_gpio_remove),
+	.driver		= {
+		.name	= KBUILD_MODNAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static struct platform_device sh_pfc_gpio_device = {
+	.name		= KBUILD_MODNAME,
+	.id		= -1,
+};
+
+static int __init sh_pfc_gpio_init(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&sh_pfc_gpio_driver);
+	if (likely(!rc)) {
+		rc = platform_device_register(&sh_pfc_gpio_device);
+		if (unlikely(rc))
+			platform_driver_unregister(&sh_pfc_gpio_driver);
+	}
+
+	return rc;
+}
+
+static void __exit sh_pfc_gpio_exit(void)
+{
+	platform_device_unregister(&sh_pfc_gpio_device);
+	platform_driver_unregister(&sh_pfc_gpio_driver);
+}
+
+module_init(sh_pfc_gpio_init);
+module_exit(sh_pfc_gpio_exit);
+
+MODULE_AUTHOR("Magnus Damm, Paul Mundt");
+MODULE_DESCRIPTION("GPIO driver for SuperH pin function controller");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:pfc-gpio");
diff --git a/drivers/sh/pfc.c b/drivers/sh/pfc.c
index 522c6c4..ce4579e 100644
--- a/drivers/sh/pfc.c
+++ b/drivers/sh/pfc.c
@@ -1,7 +1,8 @@
 /*
- * Pinmuxed GPIO support for SuperH.
+ * SuperH Pin Function Controller support.
  *
  * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2009 - 2012 Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -11,70 +12,74 @@
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/list.h>
+#include <linux/sh_pfc.h>
 #include <linux/module.h>
-#include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
-#include <linux/irq.h>
 #include <linux/bitops.h>
-#include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
 
-static void pfc_iounmap(struct pinmux_info *pip)
+static struct sh_pfc *sh_pfc __read_mostly;
+
+static inline bool sh_pfc_initialized(void)
+{
+	return !!sh_pfc;
+}
+
+static void pfc_iounmap(struct sh_pfc *pfc)
 {
 	int k;
 
-	for (k = 0; k < pip->num_resources; k++)
-		if (pip->window[k].virt)
-			iounmap(pip->window[k].virt);
+	for (k = 0; k < pfc->num_resources; k++)
+		if (pfc->window[k].virt)
+			iounmap(pfc->window[k].virt);
 
-	kfree(pip->window);
-	pip->window = NULL;
+	kfree(pfc->window);
+	pfc->window = NULL;
 }
 
-static int pfc_ioremap(struct pinmux_info *pip)
+static int pfc_ioremap(struct sh_pfc *pfc)
 {
 	struct resource *res;
 	int k;
 
-	if (!pip->num_resources)
+	if (!pfc->num_resources)
 		return 0;
 
-	pip->window = kzalloc(pip->num_resources * sizeof(*pip->window),
+	pfc->window = kzalloc(pfc->num_resources * sizeof(*pfc->window),
 			      GFP_NOWAIT);
-	if (!pip->window)
+	if (!pfc->window)
 		goto err1;
 
-	for (k = 0; k < pip->num_resources; k++) {
-		res = pip->resource + k;
+	for (k = 0; k < pfc->num_resources; k++) {
+		res = pfc->resource + k;
 		WARN_ON(resource_type(res) != IORESOURCE_MEM);
-		pip->window[k].phys = res->start;
-		pip->window[k].size = resource_size(res);
-		pip->window[k].virt = ioremap_nocache(res->start,
+		pfc->window[k].phys = res->start;
+		pfc->window[k].size = resource_size(res);
+		pfc->window[k].virt = ioremap_nocache(res->start,
 							 resource_size(res));
-		if (!pip->window[k].virt)
+		if (!pfc->window[k].virt)
 			goto err2;
 	}
 
 	return 0;
 
 err2:
-	pfc_iounmap(pip);
+	pfc_iounmap(pfc);
 err1:
 	return -1;
 }
 
-static void __iomem *pfc_phys_to_virt(struct pinmux_info *pip,
+static void __iomem *pfc_phys_to_virt(struct sh_pfc *pfc,
 				      unsigned long address)
 {
 	struct pfc_window *window;
 	int k;
 
 	/* scan through physical windows and convert address */
-	for (k = 0; k < pip->num_resources; k++) {
-		window = pip->window + k;
+	for (k = 0; k < pfc->num_resources; k++) {
+		window = pfc->window + k;
 
 		if (address < window->phys)
 			continue;
@@ -135,8 +140,7 @@ static void gpio_write_raw_reg(void __iomem *mapped_reg,
 	BUG();
 }
 
-static int gpio_read_bit(struct pinmux_data_reg *dr,
-			 unsigned long in_pos)
+int sh_pfc_read_bit(struct pinmux_data_reg *dr, unsigned long in_pos)
 {
 	unsigned long pos;
 
@@ -147,9 +151,10 @@ static int gpio_read_bit(struct pinmux_data_reg *dr,
 
 	return (gpio_read_raw_reg(dr->mapped_reg, dr->reg_width) >> pos) & 1;
 }
+EXPORT_SYMBOL_GPL(sh_pfc_read_bit);
 
-static void gpio_write_bit(struct pinmux_data_reg *dr,
-			   unsigned long in_pos, unsigned long value)
+void sh_pfc_write_bit(struct pinmux_data_reg *dr, unsigned long in_pos,
+		      unsigned long value)
 {
 	unsigned long pos;
 
@@ -166,8 +171,9 @@ static void gpio_write_bit(struct pinmux_data_reg *dr,
 
 	gpio_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow);
 }
+EXPORT_SYMBOL_GPL(sh_pfc_write_bit);
 
-static void config_reg_helper(struct pinmux_info *gpioc,
+static void config_reg_helper(struct sh_pfc *pfc,
 			      struct pinmux_cfg_reg *crp,
 			      unsigned long in_pos,
 			      void __iomem **mapped_regp,
@@ -176,7 +182,7 @@ static void config_reg_helper(struct pinmux_info *gpioc,
 {
 	int k;
 
-	*mapped_regp = pfc_phys_to_virt(gpioc, crp->reg);
+	*mapped_regp = pfc_phys_to_virt(pfc, crp->reg);
 
 	if (crp->field_width) {
 		*maskp = (1 << crp->field_width) - 1;
@@ -189,14 +195,14 @@ static void config_reg_helper(struct pinmux_info *gpioc,
 	}
 }
 
-static int read_config_reg(struct pinmux_info *gpioc,
+static int read_config_reg(struct sh_pfc *pfc,
 			   struct pinmux_cfg_reg *crp,
 			   unsigned long field)
 {
 	void __iomem *mapped_reg;
 	unsigned long mask, pos;
 
-	config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos);
+	config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
 
 	pr_debug("read_reg: addr = %lx, field = %ld, "
 		 "r_width = %ld, f_width = %ld\n",
@@ -205,14 +211,14 @@ static int read_config_reg(struct pinmux_info *gpioc,
 	return (gpio_read_raw_reg(mapped_reg, crp->reg_width) >> pos) & mask;
 }
 
-static void write_config_reg(struct pinmux_info *gpioc,
+static void write_config_reg(struct sh_pfc *pfc,
 			     struct pinmux_cfg_reg *crp,
 			     unsigned long field, unsigned long value)
 {
 	void __iomem *mapped_reg;
 	unsigned long mask, pos, data;
 
-	config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos);
+	config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
 
 	pr_debug("write_reg addr = %lx, value = %ld, field = %ld, "
 		 "r_width = %ld, f_width = %ld\n",
@@ -225,30 +231,30 @@ static void write_config_reg(struct pinmux_info *gpioc,
 	data &= mask;
 	data |= value;
 
-	if (gpioc->unlock_reg)
-		gpio_write_raw_reg(pfc_phys_to_virt(gpioc, gpioc->unlock_reg),
+	if (pfc->unlock_reg)
+		gpio_write_raw_reg(pfc_phys_to_virt(pfc, pfc->unlock_reg),
 				   32, ~data);
 
 	gpio_write_raw_reg(mapped_reg, crp->reg_width, data);
 }
 
-static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
+static int setup_data_reg(struct sh_pfc *pfc, unsigned gpio)
 {
-	struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
+	struct pinmux_gpio *gpiop = &pfc->gpios[gpio];
 	struct pinmux_data_reg *data_reg;
 	int k, n;
 
-	if (!enum_in_range(gpiop->enum_id, &gpioc->data))
+	if (!enum_in_range(gpiop->enum_id, &pfc->data))
 		return -1;
 
 	k = 0;
 	while (1) {
-		data_reg = gpioc->data_regs + k;
+		data_reg = pfc->data_regs + k;
 
 		if (!data_reg->reg_width)
 			break;
 
-		data_reg->mapped_reg = pfc_phys_to_virt(gpioc, data_reg->reg);
+		data_reg->mapped_reg = pfc_phys_to_virt(pfc, data_reg->reg);
 
 		for (n = 0; n < data_reg->reg_width; n++) {
 			if (data_reg->enum_ids[n] == gpiop->enum_id) {
@@ -267,17 +273,17 @@ static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
 	return -1;
 }
 
-static void setup_data_regs(struct pinmux_info *gpioc)
+static void setup_data_regs(struct sh_pfc *pfc)
 {
 	struct pinmux_data_reg *drp;
 	int k;
 
-	for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++)
-		setup_data_reg(gpioc, k);
+	for (k = pfc->first_gpio; k <= pfc->last_gpio; k++)
+		setup_data_reg(pfc, k);
 
 	k = 0;
 	while (1) {
-		drp = gpioc->data_regs + k;
+		drp = pfc->data_regs + k;
 
 		if (!drp->reg_width)
 			break;
@@ -288,23 +294,24 @@ static void setup_data_regs(struct pinmux_info *gpioc)
 	}
 }
 
-static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
+int sh_pfc_get_data_reg(struct sh_pfc *pfc, unsigned gpio,
 			struct pinmux_data_reg **drp, int *bitp)
 {
-	struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
+	struct pinmux_gpio *gpiop = &pfc->gpios[gpio];
 	int k, n;
 
-	if (!enum_in_range(gpiop->enum_id, &gpioc->data))
+	if (!enum_in_range(gpiop->enum_id, &pfc->data))
 		return -1;
 
 	k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT;
 	n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT;
-	*drp = gpioc->data_regs + k;
+	*drp = pfc->data_regs + k;
 	*bitp = n;
 	return 0;
 }
+EXPORT_SYMBOL_GPL(sh_pfc_get_data_reg);
 
-static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id,
+static int get_config_reg(struct sh_pfc *pfc, pinmux_enum_t enum_id,
 			  struct pinmux_cfg_reg **crp,
 			  int *fieldp, int *valuep,
 			  unsigned long **cntp)
@@ -315,7 +322,7 @@ static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id,
 
 	k = 0;
 	while (1) {
-		config_reg = gpioc->cfg_regs + k;
+		config_reg = pfc->cfg_regs + k;
 
 		r_width = config_reg->reg_width;
 		f_width = config_reg->field_width;
@@ -350,15 +357,15 @@ static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id,
 	return -1;
 }
 
-static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio,
-			    int pos, pinmux_enum_t *enum_idp)
+int sh_pfc_gpio_to_enum(struct sh_pfc *pfc, unsigned gpio, int pos,
+			pinmux_enum_t *enum_idp)
 {
-	pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id;
-	pinmux_enum_t *data = gpioc->gpio_data;
+	pinmux_enum_t enum_id = pfc->gpios[gpio].enum_id;
+	pinmux_enum_t *data = pfc->gpio_data;
 	int k;
 
-	if (!enum_in_range(enum_id, &gpioc->data)) {
-		if (!enum_in_range(enum_id, &gpioc->mark)) {
+	if (!enum_in_range(enum_id, &pfc->data)) {
+		if (!enum_in_range(enum_id, &pfc->mark)) {
 			pr_err("non data/mark enum_id for gpio %d\n", gpio);
 			return -1;
 		}
@@ -369,7 +376,7 @@ static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio,
 		return pos + 1;
 	}
 
-	for (k = 0; k < gpioc->gpio_data_size; k++) {
+	for (k = 0; k < pfc->gpio_data_size; k++) {
 		if (data[k] == enum_id) {
 			*enum_idp = data[k + 1];
 			return k + 1;
@@ -379,11 +386,10 @@ static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio,
 	pr_err("cannot locate data/mark enum_id for gpio %d\n", gpio);
 	return -1;
 }
+EXPORT_SYMBOL_GPL(sh_pfc_gpio_to_enum);
 
-enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE };
-
-static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
-			      int pinmux_type, int cfg_mode)
+int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
+		       int cfg_mode)
 {
 	struct pinmux_cfg_reg *cr = NULL;
 	pinmux_enum_t enum_id;
@@ -398,19 +404,19 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
 		break;
 
 	case PINMUX_TYPE_OUTPUT:
-		range = &gpioc->output;
+		range = &pfc->output;
 		break;
 
 	case PINMUX_TYPE_INPUT:
-		range = &gpioc->input;
+		range = &pfc->input;
 		break;
 
 	case PINMUX_TYPE_INPUT_PULLUP:
-		range = &gpioc->input_pu;
+		range = &pfc->input_pu;
 		break;
 
 	case PINMUX_TYPE_INPUT_PULLDOWN:
-		range = &gpioc->input_pd;
+		range = &pfc->input_pd;
 		break;
 
 	default:
@@ -422,7 +428,7 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
 	field = 0;
 	value = 0;
 	while (1) {
-		pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id);
+		pos = sh_pfc_gpio_to_enum(pfc, gpio, pos, &enum_id);
 		if (pos <= 0)
 			goto out_err;
 
@@ -430,7 +436,7 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
 			break;
 
 		/* first check if this is a function enum */
-		in_range = enum_in_range(enum_id, &gpioc->function);
+		in_range = enum_in_range(enum_id, &pfc->function);
 		if (!in_range) {
 			/* not a function enum */
 			if (range) {
@@ -467,19 +473,19 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
 		if (!in_range)
 			continue;
 
-		if (get_config_reg(gpioc, enum_id, &cr,
+		if (get_config_reg(pfc, enum_id, &cr,
 				   &field, &value, &cntp) != 0)
 			goto out_err;
 
 		switch (cfg_mode) {
 		case GPIO_CFG_DRYRUN:
 			if (!*cntp ||
-			    (read_config_reg(gpioc, cr, field) != value))
+			    (read_config_reg(pfc, cr, field) != value))
 				continue;
 			break;
 
 		case GPIO_CFG_REQ:
-			write_config_reg(gpioc, cr, field, value);
+			write_config_reg(pfc, cr, field, value);
 			*cntp = *cntp + 1;
 			break;
 
@@ -493,89 +499,18 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
  out_err:
 	return -1;
 }
+EXPORT_SYMBOL_GPL(sh_pfc_config_gpio);
 
-static DEFINE_SPINLOCK(gpio_lock);
-
-static struct pinmux_info *chip_to_pinmux(struct gpio_chip *chip)
-{
-	return container_of(chip, struct pinmux_info, chip);
-}
-
-static int sh_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
-	struct pinmux_info *gpioc = chip_to_pinmux(chip);
-	struct pinmux_data_reg *dummy;
-	unsigned long flags;
-	int i, ret, pinmux_type;
-
-	ret = -EINVAL;
-
-	if (!gpioc)
-		goto err_out;
-
-	spin_lock_irqsave(&gpio_lock, flags);
-
-	if ((gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE)
-		goto err_unlock;
-
-	/* setup pin function here if no data is associated with pin */
-
-	if (get_data_reg(gpioc, offset, &dummy, &i) != 0)
-		pinmux_type = PINMUX_TYPE_FUNCTION;
-	else
-		pinmux_type = PINMUX_TYPE_GPIO;
-
-	if (pinmux_type == PINMUX_TYPE_FUNCTION) {
-		if (pinmux_config_gpio(gpioc, offset,
-				       pinmux_type,
-				       GPIO_CFG_DRYRUN) != 0)
-			goto err_unlock;
-
-		if (pinmux_config_gpio(gpioc, offset,
-				       pinmux_type,
-				       GPIO_CFG_REQ) != 0)
-			BUG();
-	}
-
-	gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
-	gpioc->gpios[offset].flags |= pinmux_type;
-
-	ret = 0;
- err_unlock:
-	spin_unlock_irqrestore(&gpio_lock, flags);
- err_out:
-	return ret;
-}
-
-static void sh_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
-	struct pinmux_info *gpioc = chip_to_pinmux(chip);
-	unsigned long flags;
-	int pinmux_type;
-
-	if (!gpioc)
-		return;
-
-	spin_lock_irqsave(&gpio_lock, flags);
-
-	pinmux_type = gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE;
-	pinmux_config_gpio(gpioc, offset, pinmux_type, GPIO_CFG_FREE);
-	gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
-	gpioc->gpios[offset].flags |= PINMUX_TYPE_NONE;
-
-	spin_unlock_irqrestore(&gpio_lock, flags);
-}
-
-static int pinmux_direction(struct pinmux_info *gpioc,
-			    unsigned gpio, int new_pinmux_type)
+int sh_pfc_set_direction(struct sh_pfc *pfc, unsigned gpio,
+			 int new_pinmux_type)
 {
 	int pinmux_type;
 	int ret = -EINVAL;
 
-	if (!gpioc)
+	if (!pfc)
 		goto err_out;
 
-	pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE;
+	pinmux_type = pfc->gpios[gpio].flags & PINMUX_FLAG_TYPE;
 
 	switch (pinmux_type) {
 	case PINMUX_TYPE_GPIO:
@@ -584,156 +519,60 @@ static int pinmux_direction(struct pinmux_info *gpioc,
 	case PINMUX_TYPE_INPUT:
 	case PINMUX_TYPE_INPUT_PULLUP:
 	case PINMUX_TYPE_INPUT_PULLDOWN:
-		pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE);
+		sh_pfc_config_gpio(pfc, gpio, pinmux_type, GPIO_CFG_FREE);
 		break;
 	default:
 		goto err_out;
 	}
 
-	if (pinmux_config_gpio(gpioc, gpio,
+	if (sh_pfc_config_gpio(pfc, gpio,
 			       new_pinmux_type,
 			       GPIO_CFG_DRYRUN) != 0)
 		goto err_out;
 
-	if (pinmux_config_gpio(gpioc, gpio,
+	if (sh_pfc_config_gpio(pfc, gpio,
 			       new_pinmux_type,
 			       GPIO_CFG_REQ) != 0)
 		BUG();
 
-	gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE;
-	gpioc->gpios[gpio].flags |= new_pinmux_type;
+	pfc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE;
+	pfc->gpios[gpio].flags |= new_pinmux_type;
 
 	ret = 0;
  err_out:
 	return ret;
 }
+EXPORT_SYMBOL_GPL(sh_pfc_set_direction);
 
-static int sh_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-	struct pinmux_info *gpioc = chip_to_pinmux(chip);
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&gpio_lock, flags);
-	ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_INPUT);
-	spin_unlock_irqrestore(&gpio_lock, flags);
-
-	return ret;
-}
-
-static void sh_gpio_set_value(struct pinmux_info *gpioc,
-			     unsigned gpio, int value)
-{
-	struct pinmux_data_reg *dr = NULL;
-	int bit = 0;
-
-	if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
-		BUG();
-	else
-		gpio_write_bit(dr, bit, value);
-}
-
-static int sh_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
-				    int value)
+int register_sh_pfc(struct sh_pfc *pfc)
 {
-	struct pinmux_info *gpioc = chip_to_pinmux(chip);
-	unsigned long flags;
+	int (*initroutine)(struct sh_pfc *) = NULL;
 	int ret;
 
-	sh_gpio_set_value(gpioc, offset, value);
-	spin_lock_irqsave(&gpio_lock, flags);
-	ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_OUTPUT);
-	spin_unlock_irqrestore(&gpio_lock, flags);
-
-	return ret;
-}
-
-static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
-{
-	struct pinmux_data_reg *dr = NULL;
-	int bit = 0;
-
-	if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
-		return -EINVAL;
+	/*
+	 * Ensure that the type encoding fits
+	 */
+	BUILD_BUG_ON(PINMUX_FLAG_TYPE > ((1 << PINMUX_FLAG_DBIT_SHIFT) - 1));
 
-	return gpio_read_bit(dr, bit);
-}
-
-static int sh_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-	return sh_gpio_get_value(chip_to_pinmux(chip), offset);
-}
+	if (sh_pfc)
+		return -EBUSY;
 
-static void sh_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-	sh_gpio_set_value(chip_to_pinmux(chip), offset, value);
-}
-
-static int sh_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-	struct pinmux_info *gpioc = chip_to_pinmux(chip);
-	pinmux_enum_t enum_id;
-	pinmux_enum_t *enum_ids;
-	int i, k, pos;
-
-	pos = 0;
-	enum_id = 0;
-	while (1) {
-		pos = get_gpio_enum_id(gpioc, offset, pos, &enum_id);
-		if (pos <= 0 || !enum_id)
-			break;
-
-		for (i = 0; i < gpioc->gpio_irq_size; i++) {
-			enum_ids = gpioc->gpio_irq[i].enum_ids;
-			for (k = 0; enum_ids[k]; k++) {
-				if (enum_ids[k] == enum_id)
-					return gpioc->gpio_irq[i].irq;
-			}
-		}
-	}
-
-	return -ENOSYS;
-}
-
-int register_pinmux(struct pinmux_info *pip)
-{
-	struct gpio_chip *chip = &pip->chip;
-	int ret;
-
-	pr_info("%s handling gpio %d -> %d\n",
-		pip->name, pip->first_gpio, pip->last_gpio);
-
-	ret = pfc_ioremap(pip);
-	if (ret < 0)
+	ret = pfc_ioremap(pfc);
+	if (unlikely(ret < 0))
 		return ret;
 
-	setup_data_regs(pip);
-
-	chip->request = sh_gpio_request;
-	chip->free = sh_gpio_free;
-	chip->direction_input = sh_gpio_direction_input;
-	chip->get = sh_gpio_get;
-	chip->direction_output = sh_gpio_direction_output;
-	chip->set = sh_gpio_set;
-	chip->to_irq = sh_gpio_to_irq;
-
-	WARN_ON(pip->first_gpio != 0); /* needs testing */
+	spin_lock_init(&pfc->lock);
 
-	chip->label = pip->name;
-	chip->owner = THIS_MODULE;
-	chip->base = pip->first_gpio;
-	chip->ngpio = (pip->last_gpio - pip->first_gpio) + 1;
+	setup_data_regs(pfc);
 
-	ret = gpiochip_add(chip);
-	if (ret < 0)
-		pfc_iounmap(pip);
+	sh_pfc = pfc;
+	pr_info("%s support registered\n", pfc->name);
 
-	return ret;
-}
+	initroutine = symbol_request(sh_pfc_register_gpiochip);
+	if (initroutine) {
+		(*initroutine)(pfc);
+		symbol_put_addr(initroutine);
+	}
 
-int unregister_pinmux(struct pinmux_info *pip)
-{
-	pr_info("%s deregistering\n", pip->name);
-	pfc_iounmap(pip);
-	return gpiochip_remove(&pip->chip);
+	return 0;
 }
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index cd2fe35..8c8c680 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -125,7 +125,7 @@ config SPI_BUTTERFLY
 
 config SPI_COLDFIRE_QSPI
 	tristate "Freescale Coldfire QSPI controller"
-	depends on (M520x || M523x || M5249 || M527x || M528x || M532x)
+	depends on (M520x || M523x || M5249 || M525x || M527x || M528x || M532x)
 	help
 	  This enables support for the Coldfire QSPI controller in master
 	  mode.
@@ -144,6 +144,15 @@ config SPI_EP93XX
 	  This enables using the Cirrus EP93xx SPI controller in master
 	  mode.
 
+config SPI_FALCON
+	tristate "Falcon SPI controller support"
+	depends on SOC_FALCON
+	help
+	  The external bus unit (EBU) found on the FALC-ON SoC has SPI
+	  emulation that is designed for serial flash access. This driver
+	  has only been tested with m25p80 type chips. The hardware has no
+	  support for other types of SPI peripherals.
+
 config SPI_GPIO
 	tristate "GPIO-based bitbanging SPI Master"
 	depends on GENERIC_GPIO
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 9d75d21..b5cbab2 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_SPI_DW_MMIO)		+= spi-dw-mmio.o
 obj-$(CONFIG_SPI_DW_PCI)		+= spi-dw-midpci.o
 spi-dw-midpci-objs			:= spi-dw-pci.o spi-dw-mid.o
 obj-$(CONFIG_SPI_EP93XX)		+= spi-ep93xx.o
+obj-$(CONFIG_SPI_FALCON)		+= spi-falcon.o
 obj-$(CONFIG_SPI_FSL_LIB)		+= spi-fsl-lib.o
 obj-$(CONFIG_SPI_FSL_ESPI)		+= spi-fsl-espi.o
 obj-$(CONFIG_SPI_FSL_SPI)		+= spi-fsl-spi.o
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 7491971..1307833 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -36,7 +36,6 @@
 #include <bcm63xx_dev_spi.h>
 
 #define PFX		KBUILD_MODNAME
-#define DRV_VER		"0.1.2"
 
 struct bcm63xx_spi {
 	struct completion	done;
@@ -168,13 +167,6 @@ static int bcm63xx_spi_setup(struct spi_device *spi)
 		return -EINVAL;
 	}
 
-	ret = bcm63xx_spi_check_transfer(spi, NULL);
-	if (ret < 0) {
-		dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
-			spi->mode & ~MODEBITS);
-		return ret;
-	}
-
 	dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
 		__func__, spi->mode & MODEBITS, spi->bits_per_word, 0);
 
@@ -420,8 +412,8 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
 		goto out_clk_disable;
 	}
 
-	dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d) v%s\n",
-		 r->start, irq, bs->fifo_size, DRV_VER);
+	dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d)\n",
+		 r->start, irq, bs->fifo_size);
 
 	return 0;
 
@@ -462,6 +454,8 @@ static int bcm63xx_spi_suspend(struct device *dev)
 			platform_get_drvdata(to_platform_device(dev));
 	struct bcm63xx_spi *bs = spi_master_get_devdata(master);
 
+	spi_master_suspend(master);
+
 	clk_disable(bs->clk);
 
 	return 0;
@@ -475,6 +469,8 @@ static int bcm63xx_spi_resume(struct device *dev)
 
 	clk_enable(bs->clk);
 
+	spi_master_resume(master);
+
 	return 0;
 }
 
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
new file mode 100644
index 0000000..8f6aa73
--- /dev/null
+++ b/drivers/spi/spi-falcon.c
@@ -0,0 +1,469 @@
+/*
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ *  Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com>
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#include <lantiq_soc.h>
+
+#define DRV_NAME		"sflash-falcon"
+
+#define FALCON_SPI_XFER_BEGIN	(1 << 0)
+#define FALCON_SPI_XFER_END	(1 << 1)
+
+/* Bus Read Configuration Register0 */
+#define BUSRCON0		0x00000010
+/* Bus Write Configuration Register0 */
+#define BUSWCON0		0x00000018
+/* Serial Flash Configuration Register */
+#define SFCON			0x00000080
+/* Serial Flash Time Register */
+#define SFTIME			0x00000084
+/* Serial Flash Status Register */
+#define SFSTAT			0x00000088
+/* Serial Flash Command Register */
+#define SFCMD			0x0000008C
+/* Serial Flash Address Register */
+#define SFADDR			0x00000090
+/* Serial Flash Data Register */
+#define SFDATA			0x00000094
+/* Serial Flash I/O Control Register */
+#define SFIO			0x00000098
+/* EBU Clock Control Register */
+#define EBUCC			0x000000C4
+
+/* Dummy Phase Length */
+#define SFCMD_DUMLEN_OFFSET	16
+#define SFCMD_DUMLEN_MASK	0x000F0000
+/* Chip Select */
+#define SFCMD_CS_OFFSET		24
+#define SFCMD_CS_MASK		0x07000000
+/* field offset */
+#define SFCMD_ALEN_OFFSET	20
+#define SFCMD_ALEN_MASK		0x00700000
+/* SCK Rise-edge Position */
+#define SFTIME_SCKR_POS_OFFSET	8
+#define SFTIME_SCKR_POS_MASK	0x00000F00
+/* SCK Period */
+#define SFTIME_SCK_PER_OFFSET	0
+#define SFTIME_SCK_PER_MASK	0x0000000F
+/* SCK Fall-edge Position */
+#define SFTIME_SCKF_POS_OFFSET	12
+#define SFTIME_SCKF_POS_MASK	0x0000F000
+/* Device Size */
+#define SFCON_DEV_SIZE_A23_0	0x03000000
+#define SFCON_DEV_SIZE_MASK	0x0F000000
+/* Read Data Position */
+#define SFTIME_RD_POS_MASK	0x000F0000
+/* Data Output */
+#define SFIO_UNUSED_WD_MASK	0x0000000F
+/* Command Opcode mask */
+#define SFCMD_OPC_MASK		0x000000FF
+/* dlen bytes of data to write */
+#define SFCMD_DIR_WRITE		0x00000100
+/* Data Length offset */
+#define SFCMD_DLEN_OFFSET	9
+/* Command Error */
+#define SFSTAT_CMD_ERR		0x20000000
+/* Access Command Pending */
+#define SFSTAT_CMD_PEND		0x00400000
+/* Frequency set to 100MHz. */
+#define EBUCC_EBUDIV_SELF100	0x00000001
+/* Serial Flash */
+#define BUSRCON0_AGEN_SERIAL_FLASH	0xF0000000
+/* 8-bit multiplexed */
+#define BUSRCON0_PORTW_8_BIT_MUX	0x00000000
+/* Serial Flash */
+#define BUSWCON0_AGEN_SERIAL_FLASH	0xF0000000
+/* Chip Select after opcode */
+#define SFCMD_KEEP_CS_KEEP_SELECTED	0x00008000
+
+#define CLOCK_100M	100000000
+#define CLOCK_50M	50000000
+
+struct falcon_sflash {
+	u32 sfcmd; /* for caching of opcode, direction, ... */
+	struct spi_master *master;
+};
+
+int falcon_sflash_xfer(struct spi_device *spi, struct spi_transfer *t,
+		unsigned long flags)
+{
+	struct device *dev = &spi->dev;
+	struct falcon_sflash *priv = spi_master_get_devdata(spi->master);
+	const u8 *txp = t->tx_buf;
+	u8 *rxp = t->rx_buf;
+	unsigned int bytelen = ((8 * t->len + 7) / 8);
+	unsigned int len, alen, dumlen;
+	u32 val;
+	enum {
+		state_init,
+		state_command_prepare,
+		state_write,
+		state_read,
+		state_disable_cs,
+		state_end
+	} state = state_init;
+
+	do {
+		switch (state) {
+		case state_init: /* detect phase of upper layer sequence */
+		{
+			/* initial write ? */
+			if (flags & FALCON_SPI_XFER_BEGIN) {
+				if (!txp) {
+					dev_err(dev,
+						"BEGIN without tx data!\n");
+					return -ENODATA;
+				}
+				/*
+				 * Prepare the parts of the sfcmd register,
+				 * which should not change during a sequence!
+				 * Only exception are the length fields,
+				 * especially alen and dumlen.
+				 */
+
+				priv->sfcmd = ((spi->chip_select
+						<< SFCMD_CS_OFFSET)
+					       & SFCMD_CS_MASK);
+				priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED;
+				priv->sfcmd |= *txp;
+				txp++;
+				bytelen--;
+				if (bytelen) {
+					/*
+					 * more data:
+					 * maybe address and/or dummy
+					 */
+					state = state_command_prepare;
+					break;
+				} else {
+					dev_dbg(dev, "write cmd %02X\n",
+						priv->sfcmd & SFCMD_OPC_MASK);
+				}
+			}
+			/* continued write ? */
+			if (txp && bytelen) {
+				state = state_write;
+				break;
+			}
+			/* read data? */
+			if (rxp && bytelen) {
+				state = state_read;
+				break;
+			}
+			/* end of sequence? */
+			if (flags & FALCON_SPI_XFER_END)
+				state = state_disable_cs;
+			else
+				state = state_end;
+			break;
+		}
+		/* collect tx data for address and dummy phase */
+		case state_command_prepare:
+		{
+			/* txp is valid, already checked */
+			val = 0;
+			alen = 0;
+			dumlen = 0;
+			while (bytelen > 0) {
+				if (alen < 3) {
+					val = (val << 8) | (*txp++);
+					alen++;
+				} else if ((dumlen < 15) && (*txp == 0)) {
+					/*
+					 * assume dummy bytes are set to 0
+					 * from upper layer
+					 */
+					dumlen++;
+					txp++;
+				} else {
+					break;
+				}
+				bytelen--;
+			}
+			priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK);
+			priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) |
+					 (dumlen << SFCMD_DUMLEN_OFFSET);
+			if (alen > 0)
+				ltq_ebu_w32(val, SFADDR);
+
+			dev_dbg(dev, "wr %02X, alen=%d (addr=%06X) dlen=%d\n",
+				priv->sfcmd & SFCMD_OPC_MASK,
+				alen, val, dumlen);
+
+			if (bytelen > 0) {
+				/* continue with write */
+				state = state_write;
+			} else if (flags & FALCON_SPI_XFER_END) {
+				/* end of sequence? */
+				state = state_disable_cs;
+			} else {
+				/*
+				 * go to end and expect another
+				 * call (read or write)
+				 */
+				state = state_end;
+			}
+			break;
+		}
+		case state_write:
+		{
+			/* txp still valid */
+			priv->sfcmd |= SFCMD_DIR_WRITE;
+			len = 0;
+			val = 0;
+			do {
+				if (bytelen--)
+					val |= (*txp++) << (8 * len++);
+				if ((flags & FALCON_SPI_XFER_END)
+				    && (bytelen == 0)) {
+					priv->sfcmd &=
+						~SFCMD_KEEP_CS_KEEP_SELECTED;
+				}
+				if ((len == 4) || (bytelen == 0)) {
+					ltq_ebu_w32(val, SFDATA);
+					ltq_ebu_w32(priv->sfcmd
+						| (len<<SFCMD_DLEN_OFFSET),
+						SFCMD);
+					len = 0;
+					val = 0;
+					priv->sfcmd &= ~(SFCMD_ALEN_MASK
+							 | SFCMD_DUMLEN_MASK);
+				}
+			} while (bytelen);
+			state = state_end;
+			break;
+		}
+		case state_read:
+		{
+			/* read data */
+			priv->sfcmd &= ~SFCMD_DIR_WRITE;
+			do {
+				if ((flags & FALCON_SPI_XFER_END)
+				    && (bytelen <= 4)) {
+					priv->sfcmd &=
+						~SFCMD_KEEP_CS_KEEP_SELECTED;
+				}
+				len = (bytelen > 4) ? 4 : bytelen;
+				bytelen -= len;
+				ltq_ebu_w32(priv->sfcmd
+					| (len << SFCMD_DLEN_OFFSET), SFCMD);
+				priv->sfcmd &= ~(SFCMD_ALEN_MASK
+						 | SFCMD_DUMLEN_MASK);
+				do {
+					val = ltq_ebu_r32(SFSTAT);
+					if (val & SFSTAT_CMD_ERR) {
+						/* reset error status */
+						dev_err(dev, "SFSTAT: CMD_ERR");
+						dev_err(dev, " (%x)\n", val);
+						ltq_ebu_w32(SFSTAT_CMD_ERR,
+							SFSTAT);
+						return -EBADE;
+					}
+				} while (val & SFSTAT_CMD_PEND);
+				val = ltq_ebu_r32(SFDATA);
+				do {
+					*rxp = (val & 0xFF);
+					rxp++;
+					val >>= 8;
+					len--;
+				} while (len);
+			} while (bytelen);
+			state = state_end;
+			break;
+		}
+		case state_disable_cs:
+		{
+			priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED;
+			ltq_ebu_w32(priv->sfcmd | (0 << SFCMD_DLEN_OFFSET),
+				SFCMD);
+			val = ltq_ebu_r32(SFSTAT);
+			if (val & SFSTAT_CMD_ERR) {
+				/* reset error status */
+				dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val);
+				ltq_ebu_w32(SFSTAT_CMD_ERR, SFSTAT);
+				return -EBADE;
+			}
+			state = state_end;
+			break;
+		}
+		case state_end:
+			break;
+		}
+	} while (state != state_end);
+
+	return 0;
+}
+
+static int falcon_sflash_setup(struct spi_device *spi)
+{
+	unsigned int i;
+	unsigned long flags;
+
+	if (spi->chip_select > 0)
+		return -ENODEV;
+
+	spin_lock_irqsave(&ebu_lock, flags);
+
+	if (spi->max_speed_hz >= CLOCK_100M) {
+		/* set EBU clock to 100 MHz */
+		ltq_sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, EBUCC);
+		i = 1; /* divider */
+	} else {
+		/* set EBU clock to 50 MHz */
+		ltq_sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, EBUCC);
+
+		/* search for suitable divider */
+		for (i = 1; i < 7; i++) {
+			if (CLOCK_50M / i <= spi->max_speed_hz)
+				break;
+		}
+	}
+
+	/* setup period of serial clock */
+	ltq_ebu_w32_mask(SFTIME_SCKF_POS_MASK
+		     | SFTIME_SCKR_POS_MASK
+		     | SFTIME_SCK_PER_MASK,
+		     (i << SFTIME_SCKR_POS_OFFSET)
+		     | (i << (SFTIME_SCK_PER_OFFSET + 1)),
+		     SFTIME);
+
+	/*
+	 * set some bits of unused_wd, to not trigger HOLD/WP
+	 * signals on non QUAD flashes
+	 */
+	ltq_ebu_w32((SFIO_UNUSED_WD_MASK & (0x8 | 0x4)), SFIO);
+
+	ltq_ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX,
+			BUSRCON0);
+	ltq_ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, BUSWCON0);
+	/* set address wrap around to maximum for 24-bit addresses */
+	ltq_ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, SFCON);
+
+	spin_unlock_irqrestore(&ebu_lock, flags);
+
+	return 0;
+}
+
+static int falcon_sflash_prepare_xfer(struct spi_master *master)
+{
+	return 0;
+}
+
+static int falcon_sflash_unprepare_xfer(struct spi_master *master)
+{
+	return 0;
+}
+
+static int falcon_sflash_xfer_one(struct spi_master *master,
+					struct spi_message *m)
+{
+	struct falcon_sflash *priv = spi_master_get_devdata(master);
+	struct spi_transfer *t;
+	unsigned long spi_flags;
+	unsigned long flags;
+	int ret = 0;
+
+	priv->sfcmd = 0;
+	m->actual_length = 0;
+
+	spi_flags = FALCON_SPI_XFER_BEGIN;
+	list_for_each_entry(t, &m->transfers, transfer_list) {
+		if (list_is_last(&t->transfer_list, &m->transfers))
+			spi_flags |= FALCON_SPI_XFER_END;
+
+		spin_lock_irqsave(&ebu_lock, flags);
+		ret = falcon_sflash_xfer(m->spi, t, spi_flags);
+		spin_unlock_irqrestore(&ebu_lock, flags);
+
+		if (ret)
+			break;
+
+		m->actual_length += t->len;
+
+		WARN_ON(t->delay_usecs || t->cs_change);
+		spi_flags = 0;
+	}
+
+	m->status = ret;
+	m->complete(m->context);
+
+	return 0;
+}
+
+static int __devinit falcon_sflash_probe(struct platform_device *pdev)
+{
+	struct falcon_sflash *priv;
+	struct spi_master *master;
+	int ret;
+
+	if (ltq_boot_select() != BS_SPI) {
+		dev_err(&pdev->dev, "invalid bootstrap options\n");
+		return -ENODEV;
+	}
+
+	master = spi_alloc_master(&pdev->dev, sizeof(*priv));
+	if (!master)
+		return -ENOMEM;
+
+	priv = spi_master_get_devdata(master);
+	priv->master = master;
+
+	master->mode_bits = SPI_MODE_3;
+	master->num_chipselect = 1;
+	master->bus_num = -1;
+	master->setup = falcon_sflash_setup;
+	master->prepare_transfer_hardware = falcon_sflash_prepare_xfer;
+	master->transfer_one_message = falcon_sflash_xfer_one;
+	master->unprepare_transfer_hardware = falcon_sflash_unprepare_xfer;
+	master->dev.of_node = pdev->dev.of_node;
+
+	platform_set_drvdata(pdev, priv);
+
+	ret = spi_register_master(master);
+	if (ret)
+		spi_master_put(master);
+	return ret;
+}
+
+static int __devexit falcon_sflash_remove(struct platform_device *pdev)
+{
+	struct falcon_sflash *priv = platform_get_drvdata(pdev);
+
+	spi_unregister_master(priv->master);
+
+	return 0;
+}
+
+static const struct of_device_id falcon_sflash_match[] = {
+	{ .compatible = "lantiq,sflash-falcon" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, falcon_sflash_match);
+
+static struct platform_driver falcon_sflash_driver = {
+	.probe	= falcon_sflash_probe,
+	.remove	= __devexit_p(falcon_sflash_remove),
+	.driver = {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = falcon_sflash_match,
+	}
+};
+
+module_platform_driver(falcon_sflash_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Lantiq Falcon SPI/SFLASH controller driver");
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 972a94c..f4e2341 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -191,6 +191,10 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
 	writel(0, regs + S3C64XX_SPI_PACKET_CNT);
 
 	val = readl(regs + S3C64XX_SPI_CH_CFG);
+	val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
+	writel(val, regs + S3C64XX_SPI_CH_CFG);
+
+	val = readl(regs + S3C64XX_SPI_CH_CFG);
 	val |= S3C64XX_SPI_CH_SW_RST;
 	val &= ~S3C64XX_SPI_CH_HS_EN;
 	writel(val, regs + S3C64XX_SPI_CH_CFG);
@@ -224,10 +228,6 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
 	val = readl(regs + S3C64XX_SPI_MODE_CFG);
 	val &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
 	writel(val, regs + S3C64XX_SPI_MODE_CFG);
-
-	val = readl(regs + S3C64XX_SPI_CH_CFG);
-	val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
-	writel(val, regs + S3C64XX_SPI_CH_CFG);
 }
 
 static void s3c64xx_spi_dmacb(void *data)
@@ -262,14 +262,24 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
 					unsigned len, dma_addr_t buf)
 {
 	struct s3c64xx_spi_driver_data *sdd;
-	struct samsung_dma_prep_info info;
+	struct samsung_dma_prep info;
+	struct samsung_dma_config config;
 
-	if (dma->direction == DMA_DEV_TO_MEM)
+	if (dma->direction == DMA_DEV_TO_MEM) {
 		sdd = container_of((void *)dma,
 			struct s3c64xx_spi_driver_data, rx_dma);
-	else
+		config.direction = sdd->rx_dma.direction;
+		config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
+		config.width = sdd->cur_bpw / 8;
+		sdd->ops->config(sdd->rx_dma.ch, &config);
+	} else {
 		sdd = container_of((void *)dma,
 			struct s3c64xx_spi_driver_data, tx_dma);
+		config.direction =  sdd->tx_dma.direction;
+		config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
+		config.width = sdd->cur_bpw / 8;
+		sdd->ops->config(sdd->tx_dma.ch, &config);
+	}
 
 	info.cap = DMA_SLAVE;
 	info.len = len;
@@ -284,20 +294,15 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
 
 static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
 {
-	struct samsung_dma_info info;
+	struct samsung_dma_req req;
 
 	sdd->ops = samsung_dma_get_ops();
 
-	info.cap = DMA_SLAVE;
-	info.client = &s3c64xx_spi_dma_client;
-	info.width = sdd->cur_bpw / 8;
+	req.cap = DMA_SLAVE;
+	req.client = &s3c64xx_spi_dma_client;
 
-	info.direction = sdd->rx_dma.direction;
-	info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
-	sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &info);
-	info.direction =  sdd->tx_dma.direction;
-	info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
-	sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &info);
+	sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req);
+	sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req);
 
 	return 1;
 }
@@ -745,8 +750,6 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
 			if (list_is_last(&xfer->transfer_list,
 						&msg->transfers))
 				cs_toggle = 1;
-			else
-				disable_cs(sdd, spi);
 		}
 
 		msg->actual_length += xfer->len;
diff --git a/drivers/spi/spi-tegra.c b/drivers/spi/spi-tegra.c
index ae6d78a..7f99ff3 100644
--- a/drivers/spi/spi-tegra.c
+++ b/drivers/spi/spi-tegra.c
@@ -261,7 +261,7 @@ static void spi_tegra_start_transfer(struct spi_device *spi,
 		clk_set_rate(tspi->clk, speed);
 
 	if (tspi->cur_speed == 0)
-		clk_enable(tspi->clk);
+		clk_prepare_enable(tspi->clk);
 
 	tspi->cur_speed = speed;
 
@@ -373,7 +373,7 @@ static void tegra_spi_rx_dma_complete(struct tegra_dma_req *req)
 			spi = m->state;
 			spi_tegra_start_message(spi, m);
 		} else {
-			clk_disable(tspi->clk);
+			clk_disable_unprepare(tspi->clk);
 			tspi->cur_speed = 0;
 		}
 	}
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 1041cb8..fc0da39 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -53,7 +53,7 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf)
 {
 	const struct spi_device	*spi = to_spi_device(dev);
 
-	return sprintf(buf, "%s\n", spi->modalias);
+	return sprintf(buf, "%s%s\n", SPI_MODULE_PREFIX, spi->modalias);
 }
 
 static struct device_attribute spi_dev_attrs[] = {
@@ -813,6 +813,7 @@ static void of_register_spi_devices(struct spi_master *master)
 	struct spi_device *spi;
 	struct device_node *nc;
 	const __be32 *prop;
+	char modalias[SPI_NAME_SIZE + 4];
 	int rc;
 	int len;
 
@@ -874,7 +875,9 @@ static void of_register_spi_devices(struct spi_master *master)
 		spi->dev.of_node = nc;
 
 		/* Register the new device */
-		request_module(spi->modalias);
+		snprintf(modalias, sizeof(modalias), "%s%s", SPI_MODULE_PREFIX,
+			 spi->modalias);
+		request_module(modalias);
 		rc = spi_add_device(spi);
 		if (rc) {
 			dev_err(&master->dev, "spi_device register error %s\n",
diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c
index f551e53..266aa16 100644
--- a/drivers/ssb/b43_pci_bridge.c
+++ b/drivers/ssb/b43_pci_bridge.c
@@ -36,6 +36,7 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4328) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4329) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432b) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432c) },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index 266c7c5..ab4627c 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -90,6 +90,8 @@ const char *ssb_core_name(u16 coreid)
 		return "ARM 1176";
 	case SSB_DEV_ARM_7TDMI:
 		return "ARM 7TDMI";
+	case SSB_DEV_ARM_CM3:
+		return "ARM Cortex M3";
 	}
 	return "UNKNOWN";
 }
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 05e33c7..d3934d7 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -84,7 +84,7 @@ source "drivers/staging/wlags49_h2/Kconfig"
 
 source "drivers/staging/wlags49_h25/Kconfig"
 
-source "drivers/staging/sm7xx/Kconfig"
+source "drivers/staging/sm7xxfb/Kconfig"
 
 source "drivers/staging/crystalhd/Kconfig"
 
@@ -132,4 +132,6 @@ source "drivers/staging/ipack/Kconfig"
 
 source "drivers/staging/gdm72xx/Kconfig"
 
+source "drivers/staging/csr/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index a987b3a..5b2219a 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -37,7 +37,7 @@ obj-$(CONFIG_ZCACHE)		+= zcache/
 obj-$(CONFIG_ZSMALLOC)		+= zsmalloc/
 obj-$(CONFIG_WLAGS49_H2)	+= wlags49_h2/
 obj-$(CONFIG_WLAGS49_H25)	+= wlags49_h25/
-obj-$(CONFIG_FB_SM7XX)		+= sm7xx/
+obj-$(CONFIG_FB_SM7XX)		+= sm7xxfb/
 obj-$(CONFIG_CRYSTALHD)		+= crystalhd/
 obj-$(CONFIG_CXT1E1)		+= cxt1e1/
 obj-$(CONFIG_FB_XGI)		+= xgifb/
@@ -58,3 +58,4 @@ obj-$(CONFIG_RAMSTER)		+= ramster/
 obj-$(CONFIG_USB_WPAN_HCD)	+= ozwpan/
 obj-$(CONFIG_USB_G_CCG)		+= ccg/
 obj-$(CONFIG_WIMAX_GDM72XX)	+= gdm72xx/
+obj-$(CONFIG_CSR_WIFI)		+= csr/
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 0e16b59..0ce50d1 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -25,11 +25,6 @@ config ANDROID_LOGGER
 	tristate "Android log driver"
 	default n
 
-config ANDROID_RAM_CONSOLE
-	bool "Android RAM buffer console"
-	depends on !S390 && !UML && HAVE_MEMBLOCK && PSTORE_RAM=y
-	default n
-
 config ANDROID_TIMED_OUTPUT
 	bool "Timed output class driver"
 	default y
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index 98711e2..e16fcd5 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -1,7 +1,6 @@
 obj-$(CONFIG_ANDROID_BINDER_IPC)	+= binder.o
 obj-$(CONFIG_ASHMEM)			+= ashmem.o
 obj-$(CONFIG_ANDROID_LOGGER)		+= logger.o
-obj-$(CONFIG_ANDROID_RAM_CONSOLE)	+= ram_console.o
 obj-$(CONFIG_ANDROID_TIMED_OUTPUT)	+= timed_output.o
 obj-$(CONFIG_ANDROID_TIMED_GPIO)	+= timed_gpio.o
 obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER)	+= lowmemorykiller.o
diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c
index 53ce6ec..5b70640 100644
--- a/drivers/staging/android/alarm-dev.c
+++ b/drivers/staging/android/alarm-dev.c
@@ -29,16 +29,14 @@
 #define ANDROID_ALARM_PRINT_IO (1U << 1)
 #define ANDROID_ALARM_PRINT_INT (1U << 2)
 
-
 static int debug_mask = ANDROID_ALARM_PRINT_INFO;
 module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
-#define pr_alarm(debug_level_mask, args...) \
-	do { \
-		if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
-			pr_info(args); \
-		} \
-	} while (0)
+#define alarm_dbg(debug_level_mask, fmt, ...)				\
+do {									\
+	if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask)	\
+		pr_info(fmt, ##__VA_ARGS__);				\
+} while (0)
 
 #define ANDROID_ALARM_WAKEUP_MASK ( \
 	ANDROID_ALARM_RTC_WAKEUP_MASK | \
@@ -138,7 +136,7 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
 	case ANDROID_ALARM_CLEAR(0):
 		spin_lock_irqsave(&alarm_slock, flags);
-		pr_alarm(IO, "alarm %d clear\n", alarm_type);
+		alarm_dbg(IO, "alarm %d clear\n", alarm_type);
 		devalarm_try_to_cancel(&alarms[alarm_type]);
 		if (alarm_pending) {
 			alarm_pending &= ~alarm_type_mask;
@@ -167,8 +165,9 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		}
 from_old_alarm_set:
 		spin_lock_irqsave(&alarm_slock, flags);
-		pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type,
-			new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
+		alarm_dbg(IO, "alarm %d set %ld.%09ld\n",
+			  alarm_type,
+			  new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
 		alarm_enabled |= alarm_type_mask;
 		devalarm_start(&alarms[alarm_type],
 			timespec_to_ktime(new_alarm_time));
@@ -179,7 +178,7 @@ from_old_alarm_set:
 		/* fall though */
 	case ANDROID_ALARM_WAIT:
 		spin_lock_irqsave(&alarm_slock, flags);
-		pr_alarm(IO, "alarm wait\n");
+		alarm_dbg(IO, "alarm wait\n");
 		if (!alarm_pending && wait_pending) {
 			__pm_relax(&alarm_wake_lock);
 			wait_pending = 0;
@@ -238,7 +237,6 @@ from_old_alarm_set:
 
 	default:
 		rv = -EINVAL;
-		goto err1;
 	}
 err1:
 	return rv;
@@ -256,13 +254,14 @@ static int alarm_release(struct inode *inode, struct file *file)
 	unsigned long flags;
 
 	spin_lock_irqsave(&alarm_slock, flags);
-	if (file->private_data != 0) {
+	if (file->private_data) {
 		for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
 			uint32_t alarm_type_mask = 1U << i;
 			if (alarm_enabled & alarm_type_mask) {
-				pr_alarm(INFO, "alarm_release: clear alarm, "
-					"pending %d\n",
-					!!(alarm_pending & alarm_type_mask));
+				alarm_dbg(INFO,
+					  "%s: clear alarm, pending %d\n",
+					  __func__,
+					  !!(alarm_pending & alarm_type_mask));
 				alarm_enabled &= ~alarm_type_mask;
 			}
 			spin_unlock_irqrestore(&alarm_slock, flags);
@@ -271,8 +270,8 @@ static int alarm_release(struct inode *inode, struct file *file)
 		}
 		if (alarm_pending | wait_pending) {
 			if (alarm_pending)
-				pr_alarm(INFO, "alarm_release: clear "
-					"pending alarms %x\n", alarm_pending);
+				alarm_dbg(INFO, "%s: clear pending alarms %x\n",
+					  __func__, alarm_pending);
 			__pm_relax(&alarm_wake_lock);
 			wait_pending = 0;
 			alarm_pending = 0;
@@ -288,7 +287,7 @@ static void devalarm_triggered(struct devalarm *alarm)
 	unsigned long flags;
 	uint32_t alarm_type_mask = 1U << alarm->type;
 
-	pr_alarm(INT, "devalarm_triggered type %d\n", alarm->type);
+	alarm_dbg(INT, "%s: type %d\n", __func__, alarm->type);
 	spin_lock_irqsave(&alarm_slock, flags);
 	if (alarm_enabled & alarm_type_mask) {
 		__pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index e84dbec..69cf2db 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -16,6 +16,8 @@
 ** GNU General Public License for more details.
 */
 
+#define pr_fmt(fmt) "ashmem: " fmt
+
 #include <linux/module.h>
 #include <linux/file.h>
 #include <linux/fs.h>
@@ -707,7 +709,7 @@ static int __init ashmem_init(void)
 					  sizeof(struct ashmem_area),
 					  0, 0, NULL);
 	if (unlikely(!ashmem_area_cachep)) {
-		printk(KERN_ERR "ashmem: failed to create slab cache\n");
+		pr_err("failed to create slab cache\n");
 		return -ENOMEM;
 	}
 
@@ -715,19 +717,19 @@ static int __init ashmem_init(void)
 					  sizeof(struct ashmem_range),
 					  0, 0, NULL);
 	if (unlikely(!ashmem_range_cachep)) {
-		printk(KERN_ERR "ashmem: failed to create slab cache\n");
+		pr_err("failed to create slab cache\n");
 		return -ENOMEM;
 	}
 
 	ret = misc_register(&ashmem_misc);
 	if (unlikely(ret)) {
-		printk(KERN_ERR "ashmem: failed to register misc device!\n");
+		pr_err("failed to register misc device!\n");
 		return ret;
 	}
 
 	register_shrinker(&ashmem_shrinker);
 
-	printk(KERN_INFO "ashmem: initialized\n");
+	pr_info("initialized\n");
 
 	return 0;
 }
@@ -740,12 +742,12 @@ static void __exit ashmem_exit(void)
 
 	ret = misc_deregister(&ashmem_misc);
 	if (unlikely(ret))
-		printk(KERN_ERR "ashmem: failed to unregister misc device!\n");
+		pr_err("failed to unregister misc device!\n");
 
 	kmem_cache_destroy(ashmem_range_cachep);
 	kmem_cache_destroy(ashmem_area_cachep);
 
-	printk(KERN_INFO "ashmem: unloaded\n");
+	pr_info("unloaded\n");
 }
 
 module_init(ashmem_init);
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index c283212..574e992 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -124,13 +124,13 @@ module_param_call(stop_on_user_error, binder_set_stop_on_user_error,
 #define binder_debug(mask, x...) \
 	do { \
 		if (binder_debug_mask & mask) \
-			printk(KERN_INFO x); \
+			pr_info(x); \
 	} while (0)
 
 #define binder_user_error(x...) \
 	do { \
 		if (binder_debug_mask & BINDER_DEBUG_USER_ERROR) \
-			printk(KERN_INFO x); \
+			pr_info(x); \
 		if (binder_stop_on_user_error) \
 			binder_stop_on_user_error = 2; \
 	} while (0)
@@ -418,7 +418,7 @@ repeat:
 #if 1
 	/* Sanity check */
 	if (fdt->fd[fd] != NULL) {
-		printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);
+		pr_warn("get_unused_fd: slot %d not NULL!\n", fd);
 		fdt->fd[fd] = NULL;
 	}
 #endif
@@ -644,7 +644,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
 		goto free_range;
 
 	if (vma == NULL) {
-		printk(KERN_ERR "binder: %d: binder_alloc_buf failed to "
+		pr_err("binder: %d: binder_alloc_buf failed to "
 		       "map pages in userspace, no vma\n", proc->pid);
 		goto err_no_vma;
 	}
@@ -657,7 +657,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
 		BUG_ON(*page);
 		*page = alloc_page(GFP_KERNEL | __GFP_ZERO);
 		if (*page == NULL) {
-			printk(KERN_ERR "binder: %d: binder_alloc_buf failed "
+			pr_err("binder: %d: binder_alloc_buf failed "
 			       "for page at %p\n", proc->pid, page_addr);
 			goto err_alloc_page_failed;
 		}
@@ -666,7 +666,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
 		page_array_ptr = page;
 		ret = map_vm_area(&tmp_area, PAGE_KERNEL, &page_array_ptr);
 		if (ret) {
-			printk(KERN_ERR "binder: %d: binder_alloc_buf failed "
+			pr_err("binder: %d: binder_alloc_buf failed "
 			       "to map page at %p in kernel\n",
 			       proc->pid, page_addr);
 			goto err_map_kernel_failed;
@@ -675,7 +675,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
 			(uintptr_t)page_addr + proc->user_buffer_offset;
 		ret = vm_insert_page(vma, user_page_addr, page[0]);
 		if (ret) {
-			printk(KERN_ERR "binder: %d: binder_alloc_buf failed "
+			pr_err("binder: %d: binder_alloc_buf failed "
 			       "to map page at %lx in userspace\n",
 			       proc->pid, user_page_addr);
 			goto err_vm_insert_page_failed;
@@ -724,7 +724,7 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
 	size_t size;
 
 	if (proc->vma == NULL) {
-		printk(KERN_ERR "binder: %d: binder_alloc_buf, no vma\n",
+		pr_err("binder: %d: binder_alloc_buf, no vma\n",
 		       proc->pid);
 		return NULL;
 	}
@@ -762,7 +762,7 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
 		}
 	}
 	if (best_fit == NULL) {
-		printk(KERN_ERR "binder: %d: binder_alloc_buf size %zd failed, "
+		pr_err("binder: %d: binder_alloc_buf size %zd failed, "
 		       "no address space\n", proc->pid, size);
 		return NULL;
 	}
@@ -997,7 +997,7 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal,
 			    node->internal_strong_refs == 0 &&
 			    !(node == binder_context_mgr_node &&
 			    node->has_strong_ref)) {
-				printk(KERN_ERR "binder: invalid inc strong "
+				pr_err("binder: invalid inc strong "
 					"node for %d\n", node->debug_id);
 				return -EINVAL;
 			}
@@ -1013,7 +1013,7 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal,
 			node->local_weak_refs++;
 		if (!node->has_weak_ref && list_empty(&node->work.entry)) {
 			if (target_list == NULL) {
-				printk(KERN_ERR "binder: invalid inc weak node "
+				pr_err("binder: invalid inc weak node "
 					"for %d\n", node->debug_id);
 				return -EINVAL;
 			}
@@ -1276,7 +1276,7 @@ static void binder_send_failed_reply(struct binder_transaction *t,
 				target_thread->return_error = error_code;
 				wake_up_interruptible(&target_thread->wait);
 			} else {
-				printk(KERN_ERR "binder: reply failed, target "
+				pr_err("binder: reply failed, target "
 					"thread, %d:%d, has error code %d "
 					"already\n", target_thread->proc->pid,
 					target_thread->pid,
@@ -1331,7 +1331,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
 		if (*offp > buffer->data_size - sizeof(*fp) ||
 		    buffer->data_size < sizeof(*fp) ||
 		    !IS_ALIGNED(*offp, sizeof(void *))) {
-			printk(KERN_ERR "binder: transaction release %d bad"
+			pr_err("binder: transaction release %d bad"
 					"offset %zd, size %zd\n", debug_id,
 					*offp, buffer->data_size);
 			continue;
@@ -1342,7 +1342,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
 		case BINDER_TYPE_WEAK_BINDER: {
 			struct binder_node *node = binder_get_node(proc, fp->binder);
 			if (node == NULL) {
-				printk(KERN_ERR "binder: transaction release %d"
+				pr_err("binder: transaction release %d"
 				       " bad node %p\n", debug_id, fp->binder);
 				break;
 			}
@@ -1355,7 +1355,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
 		case BINDER_TYPE_WEAK_HANDLE: {
 			struct binder_ref *ref = binder_get_ref(proc, fp->handle);
 			if (ref == NULL) {
-				printk(KERN_ERR "binder: transaction release %d"
+				pr_err("binder: transaction release %d"
 				       " bad handle %ld\n", debug_id,
 				       fp->handle);
 				break;
@@ -1374,7 +1374,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
 			break;
 
 		default:
-			printk(KERN_ERR "binder: transaction release %d bad "
+			pr_err("binder: transaction release %d bad "
 			       "object type %lx\n", debug_id, fp->type);
 			break;
 		}
@@ -1925,10 +1925,10 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
 			break;
 		}
 		case BC_ATTEMPT_ACQUIRE:
-			printk(KERN_ERR "binder: BC_ATTEMPT_ACQUIRE not supported\n");
+			pr_err("binder: BC_ATTEMPT_ACQUIRE not supported\n");
 			return -EINVAL;
 		case BC_ACQUIRE_RESULT:
-			printk(KERN_ERR "binder: BC_ACQUIRE_RESULT not supported\n");
+			pr_err("binder: BC_ACQUIRE_RESULT not supported\n");
 			return -EINVAL;
 
 		case BC_FREE_BUFFER: {
@@ -2165,7 +2165,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
 		} break;
 
 		default:
-			printk(KERN_ERR "binder: %d:%d unknown command %d\n",
+			pr_err("binder: %d:%d unknown command %d\n",
 			       proc->pid, thread->pid, cmd);
 			return -EINVAL;
 		}
@@ -2635,7 +2635,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 	unsigned int size = _IOC_SIZE(cmd);
 	void __user *ubuf = (void __user *)arg;
 
-	/*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/
+	/*pr_info("binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/
 
 	ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
 	if (ret)
@@ -2701,13 +2701,13 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		break;
 	case BINDER_SET_CONTEXT_MGR:
 		if (binder_context_mgr_node != NULL) {
-			printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n");
+			pr_err("binder: BINDER_SET_CONTEXT_MGR already set\n");
 			ret = -EBUSY;
 			goto err;
 		}
 		if (binder_context_mgr_uid != -1) {
 			if (binder_context_mgr_uid != current->cred->euid) {
-				printk(KERN_ERR "binder: BINDER_SET_"
+				pr_err("binder: BINDER_SET_"
 				       "CONTEXT_MGR bad uid %d != %d\n",
 				       current->cred->euid,
 				       binder_context_mgr_uid);
@@ -2753,7 +2753,7 @@ err:
 	mutex_unlock(&binder_lock);
 	wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
 	if (ret && ret != -ERESTARTSYS)
-		printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
+		pr_info("binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
 	return ret;
 }
 
@@ -2829,7 +2829,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
 #ifdef CONFIG_CPU_CACHE_VIPT
 	if (cache_is_vipt_aliasing()) {
 		while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) {
-			printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);
+			pr_info("binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);
 			vma->vm_start += PAGE_SIZE;
 		}
 	}
@@ -2861,7 +2861,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
 	proc->vma = vma;
 	proc->vma_vm_mm = vma->vm_mm;
 
-	/*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n",
+	/*pr_info("binder_mmap: %d %lx-%lx maps %p\n",
 		 proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/
 	return 0;
 
@@ -2876,7 +2876,7 @@ err_get_vm_area_failed:
 err_already_mapped:
 	mutex_unlock(&binder_mmap_lock);
 err_bad_arg:
-	printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n",
+	pr_err("binder_mmap: %d %lx-%lx %s failed %d\n",
 	       proc->pid, vma->vm_start, vma->vm_end, failure_string, ret);
 	return ret;
 }
@@ -3031,7 +3031,7 @@ static void binder_deferred_release(struct binder_proc *proc)
 		if (t) {
 			t->buffer = NULL;
 			buffer->transaction = NULL;
-			printk(KERN_ERR "binder: release proc %d, "
+			pr_err("binder: release proc %d, "
 			       "transaction %d, not freed\n",
 			       proc->pid, t->debug_id);
 			/*BUG();*/
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index b2e71c6..f7b8237 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -17,6 +17,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "logger: " fmt
+
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/fs.h>
@@ -621,13 +623,13 @@ static int __init create_log(char *log_name, int size)
 	/* finally, initialize the misc device for this log */
 	ret = misc_register(&log->misc);
 	if (unlikely(ret)) {
-		printk(KERN_ERR "logger: failed to register misc "
-		       "device for log '%s'!\n", log->misc.name);
+		pr_err("failed to register misc device for log '%s'!\n",
+				log->misc.name);
 		goto out_free_log;
 	}
 
-	printk(KERN_INFO "logger: created %luK log '%s'\n",
-	       (unsigned long) log->size >> 10, log->misc.name);
+	pr_info("created %luK log '%s'\n",
+		(unsigned long) log->size >> 10, log->misc.name);
 
 	return 0;
 
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
deleted file mode 100644
index 82323bb..0000000
--- a/drivers/staging/android/ram_console.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/* drivers/android/ram_console.c
- *
- * Copyright (C) 2007-2008 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/proc_fs.h>
-#include <linux/string.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/pstore_ram.h>
-#include "ram_console.h"
-
-static struct persistent_ram_zone *ram_console_zone;
-static const char *bootinfo;
-static size_t bootinfo_size;
-
-static void
-ram_console_write(struct console *console, const char *s, unsigned int count)
-{
-	struct persistent_ram_zone *prz = console->data;
-	persistent_ram_write(prz, s, count);
-}
-
-static struct console ram_console = {
-	.name	= "ram",
-	.write	= ram_console_write,
-	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
-	.index	= -1,
-};
-
-void ram_console_enable_console(int enabled)
-{
-	if (enabled)
-		ram_console.flags |= CON_ENABLED;
-	else
-		ram_console.flags &= ~CON_ENABLED;
-}
-
-static int __init ram_console_probe(struct platform_device *pdev)
-{
-	struct ram_console_platform_data *pdata = pdev->dev.platform_data;
-	struct persistent_ram_zone *prz;
-
-	prz = persistent_ram_init_ringbuffer(&pdev->dev, true);
-	if (IS_ERR(prz))
-		return PTR_ERR(prz);
-
-
-	if (pdata) {
-		bootinfo = kstrdup(pdata->bootinfo, GFP_KERNEL);
-		if (bootinfo)
-			bootinfo_size = strlen(bootinfo);
-	}
-
-	ram_console_zone = prz;
-	ram_console.data = prz;
-
-	register_console(&ram_console);
-
-	return 0;
-}
-
-static struct platform_driver ram_console_driver = {
-	.driver		= {
-		.name	= "ram_console",
-	},
-};
-
-static int __init ram_console_module_init(void)
-{
-	return platform_driver_probe(&ram_console_driver, ram_console_probe);
-}
-
-#ifndef CONFIG_PRINTK
-#define dmesg_restrict	0
-#endif
-
-static ssize_t ram_console_read_old(struct file *file, char __user *buf,
-				    size_t len, loff_t *offset)
-{
-	loff_t pos = *offset;
-	ssize_t count;
-	struct persistent_ram_zone *prz = ram_console_zone;
-	size_t old_log_size = persistent_ram_old_size(prz);
-	const char *old_log = persistent_ram_old(prz);
-	char *str;
-	int ret;
-
-	if (dmesg_restrict && !capable(CAP_SYSLOG))
-		return -EPERM;
-
-	/* Main last_kmsg log */
-	if (pos < old_log_size) {
-		count = min(len, (size_t)(old_log_size - pos));
-		if (copy_to_user(buf, old_log + pos, count))
-			return -EFAULT;
-		goto out;
-	}
-
-	/* ECC correction notice */
-	pos -= old_log_size;
-	count = persistent_ram_ecc_string(prz, NULL, 0);
-	if (pos < count) {
-		str = kmalloc(count, GFP_KERNEL);
-		if (!str)
-			return -ENOMEM;
-		persistent_ram_ecc_string(prz, str, count + 1);
-		count = min(len, (size_t)(count - pos));
-		ret = copy_to_user(buf, str + pos, count);
-		kfree(str);
-		if (ret)
-			return -EFAULT;
-		goto out;
-	}
-
-	/* Boot info passed through pdata */
-	pos -= count;
-	if (pos < bootinfo_size) {
-		count = min(len, (size_t)(bootinfo_size - pos));
-		if (copy_to_user(buf, bootinfo + pos, count))
-			return -EFAULT;
-		goto out;
-	}
-
-	/* EOF */
-	return 0;
-
-out:
-	*offset += count;
-	return count;
-}
-
-static const struct file_operations ram_console_file_ops = {
-	.owner = THIS_MODULE,
-	.read = ram_console_read_old,
-};
-
-static int __init ram_console_late_init(void)
-{
-	struct proc_dir_entry *entry;
-	struct persistent_ram_zone *prz = ram_console_zone;
-
-	if (!prz)
-		return 0;
-
-	if (persistent_ram_old_size(prz) == 0)
-		return 0;
-
-	entry = create_proc_entry("last_kmsg", S_IFREG | S_IRUGO, NULL);
-	if (!entry) {
-		printk(KERN_ERR "ram_console: failed to create proc entry\n");
-		persistent_ram_free_old(prz);
-		return 0;
-	}
-
-	entry->proc_fops = &ram_console_file_ops;
-	entry->size = persistent_ram_old_size(prz) +
-		persistent_ram_ecc_string(prz, NULL, 0) +
-		bootinfo_size;
-
-	return 0;
-}
-
-late_initcall(ram_console_late_init);
-postcore_initcall(ram_console_module_init);
diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c
index 38d930c..ec9e2ae 100644
--- a/drivers/staging/android/timed_output.c
+++ b/drivers/staging/android/timed_output.c
@@ -14,6 +14,8 @@
  *
  */
 
+#define pr_fmt(fmt) "timed_output: " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/device.h>
@@ -90,7 +92,7 @@ int timed_output_dev_register(struct timed_output_dev *tdev)
 
 err_create_file:
 	device_destroy(timed_output_class, MKDEV(0, tdev->index));
-	printk(KERN_ERR "timed_output: Failed to register driver %s\n",
+	pr_err("failed to register driver %s\n",
 			tdev->name);
 
 	return ret;
diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h
index aa51d17..4d490a9 100644
--- a/drivers/staging/bcm/Adapter.h
+++ b/drivers/staging/bcm/Adapter.h
@@ -7,74 +7,28 @@
 #define MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES 256
 #include "Debug.h"
 
-struct _LEADER {
+struct bcm_leader {
 	USHORT	Vcid;
 	USHORT	PLength;
 	UCHAR	Status;
 	UCHAR	Unused[3];
 } __packed;
-typedef struct _LEADER LEADER, *PLEADER;
 
-struct _PACKETTOSEND {
-	LEADER	Leader;
+struct bcm_packettosend {
+	struct bcm_leader Leader;
 	UCHAR	ucPayload;
 } __packed;
-typedef struct _PACKETTOSEND PACKETTOSEND, *PPACKETTOSEND;
 
-struct _CONTROL_PACKET {
+struct bcm_control_packet {
 	PVOID	ControlBuff;
 	UINT	ControlBuffLen;
-	struct _CONTROL_PACKET *next;
+	struct bcm_control_packet *next;
 } __packed;
-typedef struct _CONTROL_PACKET CONTROL_PACKET, *PCONTROL_PACKET;
 
-struct link_request {
-	LEADER	Leader;
+struct bcm_link_request {
+	struct bcm_leader Leader;
 	UCHAR	szData[4];
 } __packed;
-typedef struct link_request LINK_REQUEST, *PLINK_REQUEST;
-
-/* classification extension is added */
-typedef struct _ADD_CONNECTION {
-	ULONG	SrcIpAddressCount;
-	ULONG	SrcIpAddress[MAX_CONNECTIONS];
-	ULONG	SrcIpMask[MAX_CONNECTIONS];
-
-	ULONG	DestIpAddressCount;
-	ULONG	DestIpAddress[MAX_CONNECTIONS];
-	ULONG	DestIpMask[MAX_CONNECTIONS];
-
-	USHORT	SrcPortBegin;
-	USHORT	SrcPortEnd;
-
-	USHORT	DestPortBegin;
-	USHORT	DestPortEnd;
-
-	UCHAR	SrcTOS;
-	UCHAR	SrcProtocol;
-} ADD_CONNECTION, *PADD_CONNECTION;
-
-typedef struct _CLASSIFICATION_RULE {
-	UCHAR	ucIPSrcAddrLen;
-	UCHAR	ucIPSrcAddr[32];
-	UCHAR	ucIPDestAddrLen;
-	UCHAR	ucIPDestAddr[32];
-	UCHAR	ucSrcPortRangeLen;
-	UCHAR	ucSrcPortRange[4];
-	UCHAR	ucDestPortRangeLen;
-	UCHAR	ucDestPortRange[4];
-	USHORT	usVcid;
-} CLASSIFICATION_RULE, *PCLASSIFICATION_RULE;
-
-typedef struct _CLASSIFICATION_ONLY {
-	USHORT	usVcid;
-	ULONG	DestIpAddress;
-	ULONG	DestIpMask;
-	USHORT	usPortLo;
-	USHORT	usPortHi;
-	BOOLEAN	bIpVersion;
-	UCHAR	ucDestinationAddress[16];
-} CLASSIFICATION_ONLY, *PCLASSIFICATION_ONLY;
 
 #define MAX_IP_RANGE_LENGTH 4
 #define MAX_PORT_RANGE 4
@@ -99,14 +53,13 @@ typedef union _U_IP_ADDRESS {
 		UCHAR ucIpv6Mask[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
 	};
 } U_IP_ADDRESS;
-struct _packet_info;
 
-typedef struct _S_HDR_SUPRESSION_CONTEXTINFO {
-	UCHAR ucaHdrSupressionInBuf[MAX_PHS_LENGTHS]; /* Intermediate buffer to accumulate pkt Header for PHS */
-	UCHAR ucaHdrSupressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN]; /* Intermediate buffer containing pkt Header after PHS */
-} S_HDR_SUPRESSION_CONTEXTINFO;
+struct bcm_hdr_suppression_contextinfo {
+	UCHAR ucaHdrSuppressionInBuf[MAX_PHS_LENGTHS]; /* Intermediate buffer to accumulate pkt Header for PHS */
+	UCHAR ucaHdrSuppressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN]; /* Intermediate buffer containing pkt Header after PHS */
+};
 
-typedef struct _S_CLASSIFIER_RULE {
+struct bcm_classifier_rule {
 	ULONG		ulSFID;
 	UCHAR		ucReserved[2];
 	B_UINT16	uiClassifierRuleIndex;
@@ -157,18 +110,17 @@ typedef struct _S_CLASSIFIER_RULE {
 	UCHAR		usUserPriority[2];
 	USHORT		usVLANID;
 	USHORT		usValidityBitMap;
-} S_CLASSIFIER_RULE;
-/* typedef struct _S_CLASSIFIER_RULE S_CLASSIFIER_RULE; */
+};
 
-typedef struct _S_FRAGMENTED_PACKET_INFO {
+struct bcm_fragmented_packet_info {
 	BOOLEAN			bUsed;
 	ULONG			ulSrcIpAddress;
 	USHORT			usIpIdentification;
-	S_CLASSIFIER_RULE	*pstMatchedClassifierEntry;
+	struct bcm_classifier_rule *pstMatchedClassifierEntry;
 	BOOLEAN			bOutOfOrderFragment;
-} S_FRAGMENTED_PACKET_INFO, *PS_FRAGMENTED_PACKET_INFO;
+};
 
-struct _packet_info {
+struct bcm_packet_info {
 	/* classification extension Rule */
 	ULONG		ulSFID;
 	USHORT		usVCID_Value;
@@ -237,11 +189,10 @@ struct _packet_info {
 	UCHAR		bIPCSSupport;
 	UCHAR		bEthCSSupport;
 };
-typedef struct _packet_info PacketInfo;
 
-typedef struct _PER_TARANG_DATA {
-	struct _PER_TARANG_DATA	*next;
-	struct _MINI_ADAPTER	*Adapter;
+struct bcm_tarang_data {
+	struct bcm_tarang_data	*next;
+	struct bcm_mini_adapter	*Adapter;
 	struct sk_buff		*RxAppControlHead;
 	struct sk_buff		*RxAppControlTail;
 	int			AppCtrlQueueLen;
@@ -249,104 +200,23 @@ typedef struct _PER_TARANG_DATA {
 	BOOLEAN			bApplicationToExit;
 	S_MIBS_DROPPED_APP_CNTRL_MESSAGES	stDroppedAppCntrlMsgs;
 	ULONG			RxCntrlMsgBitMask;
-} PER_TARANG_DATA, *PPER_TARANG_DATA;
-
-#ifdef REL_4_1
-typedef struct _TARGET_PARAMS {
-	B_UINT32 m_u32CfgVersion;
-
-	/* Scanning Related Params */
-	B_UINT32 m_u32CenterFrequency;
-	B_UINT32 m_u32BandAScan;
-	B_UINT32 m_u32BandBScan;
-	B_UINT32 m_u32BandCScan;
-
-	/* QoS Params */
-	B_UINT32 m_u32minGrantsize;	/* size of minimum grant is 0 or 6 */
-	B_UINT32 m_u32PHSEnable;
-
-	/* HO Params */
-	B_UINT32 m_u32HoEnable;
-	B_UINT32 m_u32HoReserved1;
-	B_UINT32 m_u32HoReserved2;
-
-	/* Power Control Params */
-	B_UINT32 m_u32MimoEnable;
-	B_UINT32 m_u32SecurityEnable;
-	/*
-	 * bit 1: 1 Idlemode enable;
-	 * bit 2: 1 Sleepmode Enable
-	 */
-	B_UINT32 m_u32PowerSavingModesEnable;
-	/* PowerSaving Mode Options:
-	 * bit 0 = 1: CPE mode - to keep pcmcia if alive;
-	 * bit 1 = 1: CINR reporing in Idlemode Msg
-	 * bit 2 = 1: Default PSC Enable in sleepmode
-	 */
-	B_UINT32 m_u32PowerSavingModeOptions;
-
-	B_UINT32 m_u32ArqEnable;
-
-	/* From Version #3, the HARQ section renamed as general */
-	B_UINT32 m_u32HarqEnable;
-	/* EEPROM Param Location */
-	B_UINT32 m_u32EEPROMFlag;
-	/* BINARY TYPE - 4th MSByte:
-	 * Interface Type -  3rd MSByte:
-	 * Vendor Type - 2nd MSByte
-	 */
-	/* Unused - LSByte */
-	B_UINT32 m_u32Customize;
-	B_UINT32 m_u32ConfigBW;  /* In Hz */
-	B_UINT32 m_u32ShutDownTimer;
-	B_UINT32 m_u32RadioParameter;
-	B_UINT32 m_u32PhyParameter1;
-	B_UINT32 m_u32PhyParameter2;
-	B_UINT32 m_u32PhyParameter3;
-
-	/* in eval mode only;
-	 * lower 16bits = basic cid for testing;
-	 * then bit 16 is test cqich,
-	 * bit 17  test init rang;
-	 * bit 18 test periodic rang
-	 * bit 19 is test harq ack/nack
-	 */
-	B_UINT32 m_u32TestOptions;
-	B_UINT32 m_u32MaxMACDataperDLFrame;
-	B_UINT32 m_u32MaxMACDataperULFrame;
-	B_UINT32 m_u32Corr2MacFlags;
-
-	/* adding driver params. */
-	B_UINT32 HostDrvrConfig1;
-	B_UINT32 HostDrvrConfig2;
-	B_UINT32 HostDrvrConfig3;
-	B_UINT32 HostDrvrConfig4;
-	B_UINT32 HostDrvrConfig5;
-	B_UINT32 HostDrvrConfig6;
-	B_UINT32 m_u32SegmentedPUSCenable;
-
-	/* BAMC enable - but 4.x does not support this feature
-	 * This is added just to sync 4.x and 5.x CFGs
-	 */
-	B_UINT32 m_u32BandAMCEnable;
-} STARGETPARAMS, *PSTARGETPARAMS;
-#endif
+};
 
-typedef struct _STTARGETDSXBUFFER {
+struct bcm_targetdsx_buffer {
 	ULONG		ulTargetDsxBuffer;
 	B_UINT16	tid;
 	BOOLEAN		valid;
-} STTARGETDSXBUFFER, *PSTTARGETDSXBUFFER;
+};
 
-typedef int (*FP_FLASH_WRITE)(struct _MINI_ADAPTER *, UINT, PVOID);
+typedef int (*FP_FLASH_WRITE)(struct bcm_mini_adapter *, UINT, PVOID);
 
-typedef int (*FP_FLASH_WRITE_STATUS)(struct _MINI_ADAPTER *, UINT, PVOID);
+typedef int (*FP_FLASH_WRITE_STATUS)(struct bcm_mini_adapter *, UINT, PVOID);
 
 /*
  * Driver adapter data structure
  */
-struct _MINI_ADAPTER {
-	struct _MINI_ADAPTER	*next;
+struct bcm_mini_adapter {
+	struct bcm_mini_adapter	*next;
 	struct net_device	*dev;
 	u32			msg_enable;
 	CHAR			*caDsxReqResp;
@@ -361,7 +231,7 @@ struct _MINI_ADAPTER {
 	struct sk_buff		*RxControlTail;
 	struct semaphore	RxAppControlQueuelock;
 	struct semaphore	fw_download_sema;
-	PPER_TARANG_DATA	pTarangs;
+	struct bcm_tarang_data	*pTarangs;
 	spinlock_t		control_queue_lock;
 	wait_queue_head_t	process_read_wait_queue;
 
@@ -377,8 +247,8 @@ struct _MINI_ADAPTER {
 	USHORT			PrevNumRecvDescs;
 	USHORT			CurrNumRecvDescs;
 	UINT			u32TotalDSD;
-	PacketInfo		PackInfo[NO_OF_QUEUES];
-	S_CLASSIFIER_RULE	astClassifierTable[MAX_CLASSIFIERS];
+	struct bcm_packet_info	PackInfo[NO_OF_QUEUES];
+	struct bcm_classifier_rule astClassifierTable[MAX_CLASSIFIERS];
 	BOOLEAN			TransferMode;
 
 	/*************** qos ******************/
@@ -404,7 +274,7 @@ struct _MINI_ADAPTER {
 	UINT			index_datpkt;
 	struct semaphore	rdmwrmsync;
 
-	STTARGETDSXBUFFER	astTargetDsxBuffer[MAX_TARGET_DSX_BUFFERS];
+	struct bcm_targetdsx_buffer	astTargetDsxBuffer[MAX_TARGET_DSX_BUFFERS];
 	ULONG			ulFreeTargetBufferCnt;
 	ULONG			ulCurrentTargetBuffer;
 	ULONG			ulTotalTargetBuffersAvailable;
@@ -464,7 +334,7 @@ struct _MINI_ADAPTER {
 	BOOLEAN			bLinkDownRequested;
 	int			downloadDDR;
 	PHS_DEVICE_EXTENSION	stBCMPhsContext;
-	S_HDR_SUPRESSION_CONTEXTINFO stPhsTxContextInfo;
+	struct bcm_hdr_suppression_contextinfo stPhsTxContextInfo;
 	uint8_t			ucaPHSPktRestoreBuf[2048];
 	uint8_t			bPHSEnabled;
 	BOOLEAN			AutoFirmDld;
@@ -472,7 +342,7 @@ struct _MINI_ADAPTER {
 	BOOLEAN			bDPLLConfig;
 	UINT32			aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
 	UINT32			aRxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
-	S_FRAGMENTED_PACKET_INFO astFragmentedPktClassifierTable[MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES];
+	struct bcm_fragmented_packet_info astFragmentedPktClassifierTable[MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES];
 	atomic_t		uiMBupdate;
 	UINT32			PmuMode;
 	NVM_TYPE		eNVMType;
@@ -524,37 +394,29 @@ struct _MINI_ADAPTER {
 	UINT			gpioBitMap;
 	S_BCM_DEBUG_STATE	stDebugState;
 };
-typedef struct _MINI_ADAPTER MINI_ADAPTER, *PMINI_ADAPTER;
 
 #define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev)
 
-struct _ETH_HEADER_STRUC {
+struct bcm_eth_header {
 	UCHAR	au8DestinationAddress[6];
 	UCHAR	au8SourceAddress[6];
 	USHORT	u16Etype;
 } __packed;
-typedef struct _ETH_HEADER_STRUC ETH_HEADER_STRUC, *PETH_HEADER_STRUC;
 
-typedef struct FirmwareInfo {
+struct bcm_firmware_info {
 	void	__user *pvMappedFirmwareAddress;
 	ULONG	u32FirmwareLength;
 	ULONG	u32StartingAddress;
-} __packed FIRMWARE_INFO, *PFIRMWARE_INFO;
+} __packed;
 
 /* holds the value of net_device structure.. */
 extern struct net_device *gblpnetdev;
-typedef struct _cntl_pkt {
-	PMINI_ADAPTER	Adapter;
-	PLEADER		PLeader;
-} cntl_pkt;
-typedef LINK_REQUEST CONTROL_MESSAGE;
 
-typedef struct _DDR_SETTING {
+struct bcm_ddr_setting {
 	UINT ulRegAddress;
 	UINT ulRegValue;
-} DDR_SETTING, *PDDR_SETTING;
-typedef DDR_SETTING DDR_SET_NODE, *PDDR_SET_NODE;
-int InitAdapter(PMINI_ADAPTER psAdapter);
+};
+int InitAdapter(struct bcm_mini_adapter *psAdapter);
 
 /* =====================================================================
  * Beceem vendor request codes for EP0
@@ -585,9 +447,9 @@ int InitAdapter(PMINI_ADAPTER psAdapter);
 #define EP5 4
 #define EP6 5
 
-typedef enum eInterface_setting {
+enum bcm_einterface_setting {
 	DEFAULT_SETTING_0  = 0,
 	ALTERNATE_SETTING_1 = 1,
-} INTERFACE_SETTING;
+};
 
 #endif	/* __ADAPTER_H__ */
diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c
index cf30592..cf411d1 100644
--- a/drivers/staging/bcm/Bcmchar.c
+++ b/drivers/staging/bcm/Bcmchar.c
@@ -15,11 +15,11 @@
 
 static int bcm_char_open(struct inode *inode, struct file * filp)
 {
-	PMINI_ADAPTER       Adapter = NULL;
-	PPER_TARANG_DATA    pTarang = NULL;
+	struct bcm_mini_adapter *Adapter = NULL;
+	struct bcm_tarang_data *pTarang = NULL;
 
 	Adapter = GET_BCM_ADAPTER(gblpnetdev);
-	pTarang = kzalloc(sizeof(PER_TARANG_DATA), GFP_KERNEL);
+	pTarang = kzalloc(sizeof(struct bcm_tarang_data), GFP_KERNEL);
 	if (!pTarang)
 		return -ENOMEM;
 
@@ -43,11 +43,11 @@ static int bcm_char_open(struct inode *inode, struct file * filp)
 
 static int bcm_char_release(struct inode *inode, struct file *filp)
 {
-	PPER_TARANG_DATA pTarang, tmp, ptmp;
-	PMINI_ADAPTER Adapter = NULL;
+	struct bcm_tarang_data *pTarang, *tmp, *ptmp;
+	struct bcm_mini_adapter *Adapter = NULL;
 	struct sk_buff *pkt, *npkt;
 
-	pTarang = (PPER_TARANG_DATA)filp->private_data;
+	pTarang = (struct bcm_tarang_data *)filp->private_data;
 
 	if (pTarang == NULL) {
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
@@ -97,8 +97,8 @@ static int bcm_char_release(struct inode *inode, struct file *filp)
 static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size,
 			     loff_t *f_pos)
 {
-	PPER_TARANG_DATA pTarang = filp->private_data;
-	PMINI_ADAPTER	Adapter = pTarang->Adapter;
+	struct bcm_tarang_data *pTarang = filp->private_data;
+	struct bcm_mini_adapter *Adapter = pTarang->Adapter;
 	struct sk_buff *Packet = NULL;
 	ssize_t PktLen = 0;
 	int wait_ret_val = 0;
@@ -155,9 +155,9 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size,
 
 static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
 {
-	PPER_TARANG_DATA  pTarang = filp->private_data;
+	struct bcm_tarang_data *pTarang = filp->private_data;
 	void __user *argp = (void __user *)arg;
-	PMINI_ADAPTER Adapter = pTarang->Adapter;
+	struct bcm_mini_adapter *Adapter = pTarang->Adapter;
 	INT Status = STATUS_FAILURE;
 	int timeout = 0;
 	IOCTL_BUFFER IoBuffer;
@@ -722,7 +722,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
 		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
 			return -EFAULT;
 
-		if (IoBuffer.InputLength < sizeof(struct link_request))
+		if (IoBuffer.InputLength < sizeof(struct bcm_link_request))
 			return -EINVAL;
 
 		if (IoBuffer.InputLength > MAX_CNTL_PKT_SIZE)
@@ -787,7 +787,7 @@ cntrlEnd:
 	}
 
 	case IOCTL_BCM_BUFFER_DOWNLOAD: {
-		FIRMWARE_INFO *psFwInfo = NULL;
+		struct bcm_firmware_info *psFwInfo = NULL;
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Starting the firmware download PID =0x%x!!!!\n", current->pid);
 
 		if (!down_trylock(&Adapter->fw_download_sema)) {
@@ -807,7 +807,7 @@ cntrlEnd:
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
 				"Length for FW DLD is : %lx\n", IoBuffer.InputLength);
 
-		if (IoBuffer.InputLength > sizeof(FIRMWARE_INFO)) {
+		if (IoBuffer.InputLength > sizeof(struct bcm_firmware_info)) {
 			up(&Adapter->fw_download_sema);
 			return -EINVAL;
 		}
@@ -971,7 +971,7 @@ cntrlEnd:
 		break;
 
 	case IOCTL_GET_PACK_INFO:
-		if (copy_to_user(argp, &Adapter->PackInfo, sizeof(PacketInfo)*NO_OF_QUEUES))
+		if (copy_to_user(argp, &Adapter->PackInfo, sizeof(struct bcm_packet_info)*NO_OF_QUEUES))
 			return -EFAULT;
 		Status = STATUS_SUCCESS;
 		break;
@@ -2014,7 +2014,7 @@ static const struct file_operations bcm_fops = {
 	.llseek = no_llseek,
 };
 
-int register_control_device_interface(PMINI_ADAPTER Adapter)
+int register_control_device_interface(struct bcm_mini_adapter *Adapter)
 {
 
 	if (Adapter->major > 0)
@@ -2039,7 +2039,7 @@ int register_control_device_interface(PMINI_ADAPTER Adapter)
 	return 0;
 }
 
-void unregister_control_device_interface(PMINI_ADAPTER Adapter)
+void unregister_control_device_interface(struct bcm_mini_adapter *Adapter)
 {
 	if (Adapter->major > 0) {
 		device_destroy(bcm_class, MKDEV(Adapter->major, 0));
diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c
index 133e146..6e8c7f5 100644
--- a/drivers/staging/bcm/Bcmnet.c
+++ b/drivers/staging/bcm/Bcmnet.c
@@ -4,7 +4,7 @@ struct net_device *gblpnetdev;
 
 static INT bcm_open(struct net_device *dev)
 {
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev);
 
 	if (Adapter->fw_download_done == FALSE) {
 		pr_notice(PFX "%s: link up failed (download in progress)\n",
@@ -28,7 +28,7 @@ static INT bcm_open(struct net_device *dev)
 
 static INT bcm_close(struct net_device *dev)
 {
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev);
 
 	if (netif_msg_ifdown(Adapter))
 		pr_info(PFX "%s: disabling interface\n", dev->name);
@@ -59,7 +59,7 @@ static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb)
 
 static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev)
 {
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev);
 	u16 qindex = skb_get_queue_mapping(skb);
 
 
@@ -141,7 +141,7 @@ static int bcm_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void bcm_get_drvinfo(struct net_device *dev,
 			    struct ethtool_drvinfo *info)
 {
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev);
 	PS_INTERFACE_ADAPTER psIntfAdapter = Adapter->pvInterfaceAdapter;
 	struct usb_device *udev = interface_to_usbdev(psIntfAdapter->interface);
 
@@ -156,21 +156,21 @@ static void bcm_get_drvinfo(struct net_device *dev,
 
 static u32 bcm_get_link(struct net_device *dev)
 {
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev);
 
 	return Adapter->LinkUpStatus;
 }
 
 static u32 bcm_get_msglevel(struct net_device *dev)
 {
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev);
 
 	return Adapter->msg_enable;
 }
 
 static void bcm_set_msglevel(struct net_device *dev, u32 level)
 {
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev);
 
 	Adapter->msg_enable = level;
 }
@@ -183,7 +183,7 @@ static const struct ethtool_ops bcm_ethtool_ops = {
 	.set_msglevel	= bcm_set_msglevel,
 };
 
-int register_networkdev(PMINI_ADAPTER Adapter)
+int register_networkdev(struct bcm_mini_adapter *Adapter)
 {
 	struct net_device *net = Adapter->dev;
 	PS_INTERFACE_ADAPTER IntfAdapter = Adapter->pvInterfaceAdapter;
@@ -224,7 +224,7 @@ int register_networkdev(PMINI_ADAPTER Adapter)
 	return 0;
 }
 
-void unregister_networkdev(PMINI_ADAPTER Adapter)
+void unregister_networkdev(struct bcm_mini_adapter *Adapter)
 {
 	struct net_device *net = Adapter->dev;
 	PS_INTERFACE_ADAPTER IntfAdapter = Adapter->pvInterfaceAdapter;
diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c
index 7e38af5..189d243 100644
--- a/drivers/staging/bcm/CmHost.c
+++ b/drivers/staging/bcm/CmHost.c
@@ -14,7 +14,7 @@ enum E_CLASSIFIER_ACTION {
 	eDeleteClassifier
 };
 
-static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter, B_UINT16 tid);
+static ULONG GetNextTargetBufferLocation(struct bcm_mini_adapter *Adapter, B_UINT16 tid);
 
 /************************************************************
  * Function - SearchSfid
@@ -28,7 +28,7 @@ static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter, B_UINT16 tid);
  * Returns - Queue index for this SFID(If matched)
  *  Else Invalid Queue Index(If Not matched)
  ************************************************************/
-int SearchSfid(PMINI_ADAPTER Adapter, UINT uiSfid)
+int SearchSfid(struct bcm_mini_adapter *Adapter, UINT uiSfid)
 {
 	int i;
 
@@ -49,7 +49,7 @@ int SearchSfid(PMINI_ADAPTER Adapter, UINT uiSfid)
  * Returns - Queue index for the free SFID
  *  Else returns Invalid Index.
  ****************************************************************/
-static int SearchFreeSfid(PMINI_ADAPTER Adapter)
+static int SearchFreeSfid(struct bcm_mini_adapter *Adapter)
 {
 	int i;
 
@@ -63,12 +63,12 @@ static int SearchFreeSfid(PMINI_ADAPTER Adapter)
 /*
  * Function: SearchClsid
  * Description:	This routinue would search Classifier  having specified ClassifierID as input parameter
- * Input parameters: PMINI_ADAPTER Adapter - Adapter Context
+ * Input parameters: struct bcm_mini_adapter *Adapter - Adapter Context
  *  unsigned int uiSfid   - The SF in which the classifier is to searched
  *  B_UINT16  uiClassifierID - The classifier ID to be searched
  * Return: int :Classifier table index of matching entry
  */
-static int SearchClsid(PMINI_ADAPTER Adapter, ULONG ulSFID, B_UINT16  uiClassifierID)
+static int SearchClsid(struct bcm_mini_adapter *Adapter, ULONG ulSFID, B_UINT16  uiClassifierID)
 {
 	int i;
 
@@ -87,7 +87,7 @@ static int SearchClsid(PMINI_ADAPTER Adapter, ULONG ulSFID, B_UINT16  uiClassifi
  * This routinue would search Free available Classifier entry in classifier table.
  * @return free Classifier Entry index in classifier table for specified SF
  */
-static int SearchFreeClsid(PMINI_ADAPTER Adapter /**Adapter Context*/)
+static int SearchFreeClsid(struct bcm_mini_adapter *Adapter /**Adapter Context*/)
 {
 	int i;
 
@@ -99,7 +99,7 @@ static int SearchFreeClsid(PMINI_ADAPTER Adapter /**Adapter Context*/)
 	return MAX_CLASSIFIERS+1;
 }
 
-static VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex)
+static VOID deleteSFBySfid(struct bcm_mini_adapter *Adapter, UINT uiSearchRuleIndex)
 {
 	/* deleting all the packet held in the SF */
 	flush_queue(Adapter, uiSearchRuleIndex);
@@ -112,7 +112,7 @@ static VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex)
 }
 
 static inline VOID
-CopyIpAddrToClassifier(S_CLASSIFIER_RULE *pstClassifierEntry,
+CopyIpAddrToClassifier(struct bcm_classifier_rule *pstClassifierEntry,
 		B_UINT8 u8IpAddressLen, B_UINT8 *pu8IpAddressMaskSrc,
 		BOOLEAN bIpVersion6, E_IPADDR_CONTEXT eIpAddrContext)
 {
@@ -120,7 +120,7 @@ CopyIpAddrToClassifier(S_CLASSIFIER_RULE *pstClassifierEntry,
 	UINT nSizeOfIPAddressInBytes = IP_LENGTH_OF_ADDRESS;
 	UCHAR *ptrClassifierIpAddress = NULL;
 	UCHAR *ptrClassifierIpMask = NULL;
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 	if (bIpVersion6)
 		nSizeOfIPAddressInBytes = IPV6_ADDRESS_SIZEINBYTES;
@@ -214,7 +214,7 @@ CopyIpAddrToClassifier(S_CLASSIFIER_RULE *pstClassifierEntry,
 	}
 }
 
-void ClearTargetDSXBuffer(PMINI_ADAPTER Adapter, B_UINT16 TID, BOOLEAN bFreeAll)
+void ClearTargetDSXBuffer(struct bcm_mini_adapter *Adapter, B_UINT16 TID, BOOLEAN bFreeAll)
 {
 	int i;
 
@@ -236,9 +236,9 @@ void ClearTargetDSXBuffer(PMINI_ADAPTER Adapter, B_UINT16 TID, BOOLEAN bFreeAll)
  * @ingroup ctrl_pkt_functions
  * copy classifier rule into the specified SF index
  */
-static inline VOID CopyClassifierRuleToSF(PMINI_ADAPTER Adapter, stConvergenceSLTypes  *psfCSType, UINT uiSearchRuleIndex, UINT nClassifierIndex)
+static inline VOID CopyClassifierRuleToSF(struct bcm_mini_adapter *Adapter, stConvergenceSLTypes  *psfCSType, UINT uiSearchRuleIndex, UINT nClassifierIndex)
 {
-	S_CLASSIFIER_RULE *pstClassifierEntry = NULL;
+	struct bcm_classifier_rule *pstClassifierEntry = NULL;
 	/* VOID *pvPhsContext = NULL; */
 	int i;
 	/* UCHAR ucProtocolLength=0; */
@@ -365,9 +365,9 @@ static inline VOID CopyClassifierRuleToSF(PMINI_ADAPTER Adapter, stConvergenceSL
 /*
  * @ingroup ctrl_pkt_functions
  */
-static inline VOID DeleteClassifierRuleFromSF(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex, UINT nClassifierIndex)
+static inline VOID DeleteClassifierRuleFromSF(struct bcm_mini_adapter *Adapter, UINT uiSearchRuleIndex, UINT nClassifierIndex)
 {
-	S_CLASSIFIER_RULE *pstClassifierEntry = NULL;
+	struct bcm_classifier_rule *pstClassifierEntry = NULL;
 	B_UINT16 u16PacketClassificationRuleIndex;
 	USHORT usVCID;
 	/* VOID *pvPhsContext = NULL; */
@@ -386,7 +386,7 @@ static inline VOID DeleteClassifierRuleFromSF(PMINI_ADAPTER Adapter, UINT uiSear
 	if (pstClassifierEntry) {
 		pstClassifierEntry->bUsed = FALSE;
 		pstClassifierEntry->uiClassifierRuleIndex = 0;
-		memset(pstClassifierEntry, 0, sizeof(S_CLASSIFIER_RULE));
+		memset(pstClassifierEntry, 0, sizeof(struct bcm_classifier_rule));
 
 		/* Delete the PHS Rule for this classifier */
 		PhsDeleteClassifierRule(&Adapter->stBCMPhsContext, usVCID, u16PacketClassificationRuleIndex);
@@ -396,9 +396,9 @@ static inline VOID DeleteClassifierRuleFromSF(PMINI_ADAPTER Adapter, UINT uiSear
 /*
  * @ingroup ctrl_pkt_functions
  */
-VOID DeleteAllClassifiersForSF(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex)
+VOID DeleteAllClassifiersForSF(struct bcm_mini_adapter *Adapter, UINT uiSearchRuleIndex)
 {
-	S_CLASSIFIER_RULE *pstClassifierEntry = NULL;
+	struct bcm_classifier_rule *pstClassifierEntry = NULL;
 	int i;
 	/* B_UINT16  u16PacketClassificationRuleIndex; */
 	USHORT ulVCID;
@@ -428,7 +428,7 @@ VOID DeleteAllClassifiersForSF(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex)
  * related data into the Adapter structure.
  * @ingroup ctrl_pkt_functions
  */
-static VOID CopyToAdapter(register PMINI_ADAPTER Adapter, /* <Pointer to the Adapter structure */
+static VOID CopyToAdapter(register struct bcm_mini_adapter *Adapter, /* <Pointer to the Adapter structure */
 			register pstServiceFlowParamSI psfLocalSet, /* <Pointer to the ServiceFlowParamSI structure */
 			register UINT uiSearchRuleIndex, /* <Index of Queue, to which this data belongs */
 			register UCHAR ucDsxType,
@@ -836,7 +836,7 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
 	int nIndex;
 	stLocalSFAddIndicationAlt *pstAddIndication;
 	UINT nCurClassifierCnt;
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 	pstAddIndication = (stLocalSFAddIndicationAlt *)pvBuffer;
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "======>");
@@ -1325,7 +1325,7 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " bValid: 0x%X", pstAddIndication->sfActiveSet.bValid);
 }
 
-static inline ULONG RestoreSFParam(PMINI_ADAPTER Adapter, ULONG ulAddrSFParamSet, PUCHAR pucDestBuffer)
+static inline ULONG RestoreSFParam(struct bcm_mini_adapter *Adapter, ULONG ulAddrSFParamSet, PUCHAR pucDestBuffer)
 {
 	UINT  nBytesToRead = sizeof(stServiceFlowParamSI);
 
@@ -1342,7 +1342,7 @@ static inline ULONG RestoreSFParam(PMINI_ADAPTER Adapter, ULONG ulAddrSFParamSet
 	return 1;
 }
 
-static ULONG StoreSFParam(PMINI_ADAPTER Adapter, PUCHAR pucSrcBuffer, ULONG ulAddrSFParamSet)
+static ULONG StoreSFParam(struct bcm_mini_adapter *Adapter, PUCHAR pucSrcBuffer, ULONG ulAddrSFParamSet)
 {
 	UINT nBytesToWrite = sizeof(stServiceFlowParamSI);
 	int ret = 0;
@@ -1358,7 +1358,7 @@ static ULONG StoreSFParam(PMINI_ADAPTER Adapter, PUCHAR pucSrcBuffer, ULONG ulAd
 	return 1;
 }
 
-ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter, PVOID pvBuffer, UINT *puBufferLength)
+ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBuffer, UINT *puBufferLength)
 {
 	stLocalSFAddIndicationAlt *pstAddIndicationAlt = NULL;
 	stLocalSFAddIndication *pstAddIndication = NULL;
@@ -1473,7 +1473,7 @@ ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter, PVOID pvBuffer, UINT
 }
 
 static inline stLocalSFAddIndicationAlt
-*RestoreCmControlResponseMessage(register PMINI_ADAPTER Adapter, register PVOID pvBuffer)
+*RestoreCmControlResponseMessage(register struct bcm_mini_adapter *Adapter, register PVOID pvBuffer)
 {
 	ULONG ulStatus = 0;
 	stLocalSFAddIndication *pstAddIndication = NULL;
@@ -1551,7 +1551,7 @@ failed_restore_sf_param:
 	return NULL;
 }
 
-ULONG SetUpTargetDsxBuffers(PMINI_ADAPTER Adapter)
+ULONG SetUpTargetDsxBuffers(struct bcm_mini_adapter *Adapter)
 {
 	ULONG ulTargetDsxBuffersBase = 0;
 	ULONG ulCntTargetBuffers;
@@ -1598,7 +1598,7 @@ ULONG SetUpTargetDsxBuffers(PMINI_ADAPTER Adapter)
 	return 1;
 }
 
-static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter, B_UINT16 tid)
+static ULONG GetNextTargetBufferLocation(struct bcm_mini_adapter *Adapter, B_UINT16 tid)
 {
 	ULONG ulTargetDSXBufferAddress;
 	ULONG ulTargetDsxBufferIndexToUse, ulMaxTry;
@@ -1632,7 +1632,7 @@ static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter, B_UINT16 tid)
 	return ulTargetDSXBufferAddress;
 }
 
-int AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter)
+int AllocAdapterDsxBuffer(struct bcm_mini_adapter *Adapter)
 {
 	/*
 	 * Need to Allocate memory to contain the SUPER Large structures
@@ -1645,7 +1645,7 @@ int AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter)
 	return 0;
 }
 
-int FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter)
+int FreeAdapterDsxBuffer(struct bcm_mini_adapter *Adapter)
 {
 	kfree(Adapter->caDsxReqResp);
 	return 0;
@@ -1657,13 +1657,13 @@ int FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter)
  * for the Connection Management.
  * @return - Queue index for the free SFID else returns Invalid Index.
  */
-BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /* <Pointer to the Adapter structure */
+BOOLEAN CmControlResponseMessage(struct bcm_mini_adapter *Adapter,  /* <Pointer to the Adapter structure */
 				PVOID pvBuffer /* Starting Address of the Buffer, that contains the AddIndication Data */)
 {
 	stServiceFlowParamSI *psfLocalSet = NULL;
 	stLocalSFAddIndicationAlt *pstAddIndication = NULL;
 	stLocalSFChangeIndicationAlt *pstChangeIndication = NULL;
-	PLEADER pLeader = NULL;
+	struct bcm_leader *pLeader = NULL;
 
 	/*
 	 * Otherwise the message contains a target address from where we need to
@@ -1678,7 +1678,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /* <Pointer to the Adap
 
 	DumpCmControlPacket(pstAddIndication);
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "====>");
-	pLeader = (PLEADER)Adapter->caDsxReqResp;
+	pLeader = (struct bcm_leader *)Adapter->caDsxReqResp;
 
 	pLeader->Status = CM_CONTROL_NEWDSX_MULTICLASSIFIER_REQ;
 	pLeader->Vcid = 0;
@@ -1915,10 +1915,10 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /* <Pointer to the Adap
 	return TRUE;
 }
 
-int get_dsx_sf_data_to_application(PMINI_ADAPTER Adapter, UINT uiSFId, void __user *user_buffer)
+int get_dsx_sf_data_to_application(struct bcm_mini_adapter *Adapter, UINT uiSFId, void __user *user_buffer)
 {
 	int status = 0;
-	struct _packet_info *psSfInfo = NULL;
+	struct bcm_packet_info *psSfInfo = NULL;
 
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "status =%d", status);
 	status = SearchSfid(Adapter, uiSFId);
@@ -1937,7 +1937,7 @@ int get_dsx_sf_data_to_application(PMINI_ADAPTER Adapter, UINT uiSFId, void __us
 	return STATUS_SUCCESS;
 }
 
-VOID OverrideServiceFlowParams(PMINI_ADAPTER Adapter, PUINT puiBuffer)
+VOID OverrideServiceFlowParams(struct bcm_mini_adapter *Adapter, PUINT puiBuffer)
 {
 	B_UINT32 u32NumofSFsinMsg = ntohl(*(puiBuffer + 1));
 	stIM_SFHostNotify *pHostInfo = NULL;
diff --git a/drivers/staging/bcm/CmHost.h b/drivers/staging/bcm/CmHost.h
index 8f68976..4cc6f93 100644
--- a/drivers/staging/bcm/CmHost.h
+++ b/drivers/staging/bcm/CmHost.h
@@ -148,14 +148,14 @@ typedef struct stLocalSFChangeIndicationAlt{
 
 }stLocalSFChangeIndicationAlt;
 
-ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT *puBufferLength);
+ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBuffer,UINT *puBufferLength);
 
-INT AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter);
+INT AllocAdapterDsxBuffer(struct bcm_mini_adapter *Adapter);
 
-INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter);
-ULONG SetUpTargetDsxBuffers(PMINI_ADAPTER Adapter);
+INT FreeAdapterDsxBuffer(struct bcm_mini_adapter *Adapter);
+ULONG SetUpTargetDsxBuffers(struct bcm_mini_adapter *Adapter);
 
-BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer);
+BOOLEAN CmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBuffer);
 
 
 #pragma pack (pop)
diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c
index 2b46f4d..8c696b6 100644
--- a/drivers/staging/bcm/DDRInit.c
+++ b/drivers/staging/bcm/DDRInit.c
@@ -7,7 +7,7 @@
 
     //DDR INIT-133Mhz
 #define T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 12  //index for 0x0F007000
-static DDR_SET_NODE asT3_DDRSetting133MHz[]= {//      # DPLL Clock Setting
+static struct bcm_ddr_setting asT3_DDRSetting133MHz[]= {//      # DPLL Clock Setting
                                         {0x0F000800,0x00007212},
                                         {0x0f000820,0x07F13FFF},
                                         {0x0f000810,0x00000F95},
@@ -65,7 +65,7 @@ static DDR_SET_NODE asT3_DDRSetting133MHz[]= {//      # DPLL Clock Setting
                                         };
 //80Mhz
 #define T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 10  //index for 0x0F007000
-static DDR_SET_NODE asT3_DDRSetting80MHz[]= {//   # DPLL Clock Setting
+static struct bcm_ddr_setting asT3_DDRSetting80MHz[]= {//   # DPLL Clock Setting
                                         {0x0f000810,0x00000F95},
                                         {0x0f000820,0x07f1ffff},
                                         {0x0f000860,0x00000000},
@@ -117,7 +117,7 @@ static DDR_SET_NODE asT3_DDRSetting80MHz[]= {//   # DPLL Clock Setting
                                 };
 //100Mhz
 #define T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 13  //index for 0x0F007000
-static DDR_SET_NODE asT3_DDRSetting100MHz[]= {//  # DPLL Clock Setting
+static struct bcm_ddr_setting asT3_DDRSetting100MHz[]= {//  # DPLL Clock Setting
                                         {0x0F000800,0x00007008},
                                         {0x0f000810,0x00000F95},
                                         {0x0f000820,0x07F13E3F},
@@ -177,7 +177,7 @@ static DDR_SET_NODE asT3_DDRSetting100MHz[]= {//  # DPLL Clock Setting
 
 //Net T3B DDR Settings
 //DDR INIT-133Mhz
-static DDR_SET_NODE asDPLL_266MHZ[] = {
+static struct bcm_ddr_setting asDPLL_266MHZ[] = {
                                         {0x0F000800,0x00007212},
                                         {0x0f000820,0x07F13FFF},
                                         {0x0f000810,0x00000F95},
@@ -189,7 +189,7 @@ static DDR_SET_NODE asDPLL_266MHZ[] = {
 									  };
 
 #define T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 11  //index for 0x0F007000
-static DDR_SET_NODE asT3B_DDRSetting133MHz[] = {//      # DPLL Clock Setting
+static struct bcm_ddr_setting asT3B_DDRSetting133MHz[] = {//      # DPLL Clock Setting
                                         {0x0f000810,0x00000F95},
                                         {0x0f000810,0x00000F95},
                                         {0x0f000810,0x00000F95},
@@ -247,7 +247,7 @@ static DDR_SET_NODE asT3B_DDRSetting133MHz[] = {//      # DPLL Clock Setting
                                         };
 
 #define T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 9  //index for 0x0F007000
-static DDR_SET_NODE asT3B_DDRSetting80MHz[] = {//       # DPLL Clock Setting
+static struct bcm_ddr_setting asT3B_DDRSetting80MHz[] = {//       # DPLL Clock Setting
 										{0x0f000810,0x00000F95},
 										{0x0f000820,0x07F13FFF},
 										{0x0f000840,0x0FFF1F00},
@@ -301,7 +301,7 @@ static DDR_SET_NODE asT3B_DDRSetting80MHz[] = {//       # DPLL Clock Setting
 
 //100Mhz
 #define T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 9  //index for 0x0F007000
-static DDR_SET_NODE asT3B_DDRSetting100MHz[] = {//      # DPLL Clock Setting
+static struct bcm_ddr_setting asT3B_DDRSetting100MHz[] = {//      # DPLL Clock Setting
 										{0x0f000810,0x00000F95},
 										{0x0f000820,0x07F1369B},
 										{0x0f000840,0x0FFF0800},
@@ -356,7 +356,7 @@ static DDR_SET_NODE asT3B_DDRSetting100MHz[] = {//      # DPLL Clock Setting
 
 
 #define T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 9  //index for 0x0F007000
-static DDR_SET_NODE asT3LP_DDRSetting133MHz[]= {//	# DPLL Clock Setting
+static struct bcm_ddr_setting asT3LP_DDRSetting133MHz[]= {//	# DPLL Clock Setting
 								{0x0f000820,0x03F1365B},
 								{0x0f000810,0x00002F95},
 								{0x0f000880,0x000003DD},
@@ -416,7 +416,7 @@ static DDR_SET_NODE asT3LP_DDRSetting133MHz[]= {//	# DPLL Clock Setting
 };
 
 #define T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 11  //index for 0x0F007000
-static DDR_SET_NODE asT3LP_DDRSetting100MHz[]= {//	# DPLL Clock Setting
+static struct bcm_ddr_setting asT3LP_DDRSetting100MHz[]= {//	# DPLL Clock Setting
 								{0x0f000810,0x00002F95},
 								{0x0f000820,0x03F1369B},
 								{0x0f000840,0x0fff0000},
@@ -476,7 +476,7 @@ static DDR_SET_NODE asT3LP_DDRSetting100MHz[]= {//	# DPLL Clock Setting
 };
 
 #define T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 9  //index for 0x0F007000
-static DDR_SET_NODE asT3LP_DDRSetting80MHz[]= {//	# DPLL Clock Setting
+static struct bcm_ddr_setting asT3LP_DDRSetting80MHz[]= {//	# DPLL Clock Setting
 								{0x0f000820,0x07F13FFF},
 								{0x0f000810,0x00002F95},
 								{0x0f000860,0x00000000},
@@ -536,7 +536,7 @@ static DDR_SET_NODE asT3LP_DDRSetting80MHz[]= {//	# DPLL Clock Setting
 ///T3 LP-B (UMA-B)
 
 #define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ 7  //index for 0x0F007000
-static DDR_SET_NODE asT3LPB_DDRSetting160MHz[]= {//	# DPLL Clock Setting
+static struct bcm_ddr_setting asT3LPB_DDRSetting160MHz[]= {//	# DPLL Clock Setting
 
 								{0x0f000820,0x03F137DB},
 								{0x0f000810,0x01842795},
@@ -594,7 +594,7 @@ static DDR_SET_NODE asT3LPB_DDRSetting160MHz[]= {//	# DPLL Clock Setting
 
 
 #define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 7  //index for 0x0F007000
-static DDR_SET_NODE asT3LPB_DDRSetting133MHz[]= {//	# DPLL Clock Setting
+static struct bcm_ddr_setting asT3LPB_DDRSetting133MHz[]= {//	# DPLL Clock Setting
 								{0x0f000820,0x03F1365B},
 								{0x0f000810,0x00002F95},
 								{0x0f000880,0x000003DD},
@@ -655,7 +655,7 @@ static DDR_SET_NODE asT3LPB_DDRSetting133MHz[]= {//	# DPLL Clock Setting
 };
 
 #define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 8  //index for 0x0F007000
-static DDR_SET_NODE asT3LPB_DDRSetting100MHz[]= {//	# DPLL Clock Setting
+static struct bcm_ddr_setting asT3LPB_DDRSetting100MHz[]= {//	# DPLL Clock Setting
 								{0x0f000810,0x00002F95},
 								{0x0f000820,0x03F1369B},
 								{0x0f000840,0x0fff0000},
@@ -716,7 +716,7 @@ static DDR_SET_NODE asT3LPB_DDRSetting100MHz[]= {//	# DPLL Clock Setting
 };
 
 #define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 7  //index for 0x0F007000
-static DDR_SET_NODE asT3LPB_DDRSetting80MHz[]= {//	# DPLL Clock Setting
+static struct bcm_ddr_setting asT3LPB_DDRSetting80MHz[]= {//	# DPLL Clock Setting
 								{0x0f000820,0x07F13FFF},
 								{0x0f000810,0x00002F95},
 								{0x0f000860,0x00000000},
@@ -772,9 +772,9 @@ static DDR_SET_NODE asT3LPB_DDRSetting80MHz[]= {//	# DPLL Clock Setting
 };
 
 
-int ddr_init(MINI_ADAPTER *Adapter)
+int ddr_init(struct bcm_mini_adapter *Adapter)
 {
-	PDDR_SETTING psDDRSetting=NULL;
+	struct bcm_ddr_setting *psDDRSetting=NULL;
 	ULONG RegCount=0;
 	UINT value = 0;
 	UINT  uiResetValue = 0;
@@ -789,17 +789,17 @@ int ddr_init(MINI_ADAPTER *Adapter)
 	        case DDR_80_MHZ:
 				psDDRSetting=asT3LP_DDRSetting80MHz;
 			    RegCount=(sizeof(asT3LP_DDRSetting80MHz)/
-			  	sizeof(DDR_SETTING));
+			  	sizeof(struct bcm_ddr_setting));
 			    break;
 		    case DDR_100_MHZ:
 				psDDRSetting=asT3LP_DDRSetting100MHz;
 			    RegCount=(sizeof(asT3LP_DDRSetting100MHz)/
-			  	sizeof(DDR_SETTING));
+			  	sizeof(struct bcm_ddr_setting));
 			    break;
 		    case DDR_133_MHZ:
 				psDDRSetting=asT3LP_DDRSetting133MHz;
 			    RegCount=(sizeof(asT3LP_DDRSetting133MHz)/
-		 	  		sizeof(DDR_SETTING));
+		 	  		sizeof(struct bcm_ddr_setting));
 				if(Adapter->bMipsConfig == MIPS_200_MHZ)
 				{
 					uiClockSetting = 0x03F13652;
@@ -846,17 +846,17 @@ int ddr_init(MINI_ADAPTER *Adapter)
 			case DDR_80_MHZ:
 				psDDRSetting = asT3LPB_DDRSetting80MHz;
 		        RegCount=(sizeof(asT3B_DDRSetting80MHz)/
-		                  sizeof(DDR_SETTING));
+		                  sizeof(struct bcm_ddr_setting));
 			break;
             case DDR_100_MHZ:
 				psDDRSetting=asT3LPB_DDRSetting100MHz;
 		        RegCount=(sizeof(asT3B_DDRSetting100MHz)/
-		                 sizeof(DDR_SETTING));
+		                 sizeof(struct bcm_ddr_setting));
 			break;
             case DDR_133_MHZ:
 				psDDRSetting = asT3LPB_DDRSetting133MHz;
 				RegCount=(sizeof(asT3B_DDRSetting133MHz)/
-						 sizeof(DDR_SETTING));
+						 sizeof(struct bcm_ddr_setting));
 
 				if(Adapter->bMipsConfig == MIPS_200_MHZ)
 				{
@@ -870,7 +870,7 @@ int ddr_init(MINI_ADAPTER *Adapter)
 
 			case DDR_160_MHZ:
 				psDDRSetting = asT3LPB_DDRSetting160MHz;
-				RegCount = sizeof(asT3LPB_DDRSetting160MHz)/sizeof(DDR_SETTING);
+				RegCount = sizeof(asT3LPB_DDRSetting160MHz)/sizeof(struct bcm_ddr_setting);
 
 				if(Adapter->bMipsConfig == MIPS_200_MHZ)
 				{
@@ -894,17 +894,17 @@ int ddr_init(MINI_ADAPTER *Adapter)
 	        case DDR_80_MHZ:
 				psDDRSetting = asT3_DDRSetting80MHz;
 			    RegCount = (sizeof(asT3_DDRSetting80MHz)/
-			  	sizeof(DDR_SETTING));
+			  	sizeof(struct bcm_ddr_setting));
 			    break;
 		    case DDR_100_MHZ:
 				psDDRSetting = asT3_DDRSetting100MHz;
 			    RegCount = (sizeof(asT3_DDRSetting100MHz)/
-			  	sizeof(DDR_SETTING));
+			  	sizeof(struct bcm_ddr_setting));
 			    break;
 		    case DDR_133_MHZ:
 				psDDRSetting = asT3_DDRSetting133MHz;
 			    RegCount = (sizeof(asT3_DDRSetting133MHz)/
-		 	  	sizeof(DDR_SETTING));
+		 	  	sizeof(struct bcm_ddr_setting));
 				break;
 		    default:
 			    return -EINVAL;
@@ -916,12 +916,12 @@ int ddr_init(MINI_ADAPTER *Adapter)
 	        case DDR_80_MHZ:
 				psDDRSetting = asT3B_DDRSetting80MHz;
 		        RegCount=(sizeof(asT3B_DDRSetting80MHz)/
-		                  sizeof(DDR_SETTING));
+		                  sizeof(struct bcm_ddr_setting));
 		    break;
             case DDR_100_MHZ:
 				psDDRSetting=asT3B_DDRSetting100MHz;
 		        RegCount=(sizeof(asT3B_DDRSetting100MHz)/
-		                 sizeof(DDR_SETTING));
+		                 sizeof(struct bcm_ddr_setting));
 			break;
             case DDR_133_MHZ:
 
@@ -931,13 +931,13 @@ int ddr_init(MINI_ADAPTER *Adapter)
 									 sizeof(asDPLL_266MHZ));
 					psDDRSetting = asT3B_DDRSetting133MHz;
 					RegCount=(sizeof(asT3B_DDRSetting133MHz)/
-									sizeof(DDR_SETTING));
+									sizeof(struct bcm_ddr_setting));
 				}
 				else
 				{
 					psDDRSetting = asT3B_DDRSetting133MHz;
 					RegCount=(sizeof(asT3B_DDRSetting133MHz)/
-									sizeof(DDR_SETTING));
+									sizeof(struct bcm_ddr_setting));
 					if(Adapter->bMipsConfig == MIPS_200_MHZ)
 					{
 						uiClockSetting = 0x07F13652;
@@ -1099,9 +1099,9 @@ int ddr_init(MINI_ADAPTER *Adapter)
 	return retval;
 }
 
-int download_ddr_settings(PMINI_ADAPTER Adapter)
+int download_ddr_settings(struct bcm_mini_adapter *Adapter)
 {
-	PDDR_SET_NODE psDDRSetting=NULL;
+	struct bcm_ddr_setting *psDDRSetting=NULL;
 	ULONG RegCount=0;
 	unsigned long ul_ddr_setting_load_addr = DDR_DUMP_INTERNAL_DEVICE_MEMORY;
 	UINT  value = 0;
@@ -1250,7 +1250,7 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
 	}
 
 	ul_ddr_setting_load_addr+=sizeof(ULONG);
-	RegCount*=(sizeof(DDR_SETTING)/sizeof(ULONG));
+	RegCount*=(sizeof(struct bcm_ddr_setting)/sizeof(ULONG));
 
 	while(RegCount && !retval)
 	{
diff --git a/drivers/staging/bcm/DDRInit.h b/drivers/staging/bcm/DDRInit.h
index 550e260..b0196fc 100644
--- a/drivers/staging/bcm/DDRInit.h
+++ b/drivers/staging/bcm/DDRInit.h
@@ -3,7 +3,7 @@
 
 
 
-int ddr_init(PMINI_ADAPTER	psAdapter);
-int download_ddr_settings(PMINI_ADAPTER	psAdapter);
+int ddr_init(struct bcm_mini_adapter *psAdapter);
+int download_ddr_settings(struct bcm_mini_adapter *psAdapter);
 
 #endif
diff --git a/drivers/staging/bcm/HandleControlPacket.c b/drivers/staging/bcm/HandleControlPacket.c
index b058e30..25e5c68 100644
--- a/drivers/staging/bcm/HandleControlPacket.c
+++ b/drivers/staging/bcm/HandleControlPacket.c
@@ -11,9 +11,9 @@
  * Enqueue the control packet for Application.
  * @return None
  */
-static VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, struct sk_buff *skb)
+static VOID handle_rx_control_packet(struct bcm_mini_adapter *Adapter, struct sk_buff *skb)
 {
-	PPER_TARANG_DATA pTarang = NULL;
+	struct bcm_tarang_data *pTarang = NULL;
 	BOOLEAN HighPriorityMessage = FALSE;
 	struct sk_buff *newPacket = NULL;
 	CHAR cntrl_msg_mask_bit = 0;
@@ -154,7 +154,7 @@ static VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, struct sk_buff *skb)
  * @ingroup ctrl_pkt_functions
  * Thread to handle control pkt reception
  */
-int control_packet_handler(PMINI_ADAPTER Adapter /* pointer to adapter object*/)
+int control_packet_handler(struct bcm_mini_adapter *Adapter /* pointer to adapter object*/)
 {
 	struct sk_buff *ctrl_packet = NULL;
 	unsigned long flags = 0;
@@ -213,8 +213,8 @@ int control_packet_handler(PMINI_ADAPTER Adapter /* pointer to adapter object*/)
 
 INT flushAllAppQ(void)
 {
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
-	PPER_TARANG_DATA pTarang = NULL;
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_tarang_data *pTarang = NULL;
 	struct sk_buff *PacketToDrop = NULL;
 	for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) {
 		while (pTarang->RxAppControlHead != NULL) {
diff --git a/drivers/staging/bcm/IPv6Protocol.c b/drivers/staging/bcm/IPv6Protocol.c
index 1da2164..4745ddd 100644
--- a/drivers/staging/bcm/IPv6Protocol.c
+++ b/drivers/staging/bcm/IPv6Protocol.c
@@ -1,8 +1,8 @@
 #include "headers.h"
 
-static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+static BOOLEAN MatchSrcIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
 	IPV6Header *pstIpv6Header);
-static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+static BOOLEAN MatchDestIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
 	IPV6Header *pstIpv6Header);
 static VOID DumpIpv6Header(IPV6Header *pstIpv6Header);
 
@@ -12,7 +12,7 @@ static UCHAR *GetNextIPV6ChainedHeader(UCHAR **ppucPayload,
 	UCHAR *pucRetHeaderPtr = NULL;
 	UCHAR *pucPayloadPtr = NULL;
 	USHORT  usNextHeaderOffset = 0 ;
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 	if ((ppucPayload == NULL) || (*pusPayloadLength == 0) ||
 		(*bParseDone)) {
@@ -147,7 +147,7 @@ static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload, USHORT *pusSrcPort,
 	BOOLEAN bDone = FALSE;
 	UCHAR ucHeaderType = 0;
 	UCHAR *pucNextHeader = NULL;
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 	if (!pucPayload || (usPayloadLength == 0))
 		return 0;
@@ -177,11 +177,11 @@ static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload, USHORT *pusSrcPort,
 
 
 /*
- * Arg 1 PMINI_ADAPTER Adapter is a pointer ot the driver contorl structure
+ * Arg 1 struct bcm_mini_adapter *Adapter is a pointer ot the driver contorl structure
  * Arg 2 PVOID pcIpHeader is a pointer to the IP header of the packet
  */
-USHORT	IpVersion6(PMINI_ADAPTER Adapter, PVOID pcIpHeader,
-					S_CLASSIFIER_RULE *pstClassifierRule)
+USHORT	IpVersion6(struct bcm_mini_adapter *Adapter, PVOID pcIpHeader,
+					struct bcm_classifier_rule *pstClassifierRule)
 {
 	USHORT	ushDestPort = 0;
 	USHORT	ushSrcPort = 0;
@@ -288,14 +288,14 @@ USHORT	IpVersion6(PMINI_ADAPTER Adapter, PVOID pcIpHeader,
 }
 
 
-static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+static BOOLEAN MatchSrcIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
 	IPV6Header *pstIpv6Header)
 {
 	UINT uiLoopIndex = 0;
 	UINT uiIpv6AddIndex = 0;
 	UINT uiIpv6AddrNoLongWords = 4;
 	ULONG aulSrcIP[4];
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	/*
 	 * This is the no. of Src Addresses ie Range of IP Addresses contained
 	 * in the classifier rule for which we need to match
@@ -344,14 +344,14 @@ static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
 	return FALSE;
 }
 
-static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+static BOOLEAN MatchDestIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
 	IPV6Header *pstIpv6Header)
 {
 	UINT uiLoopIndex = 0;
 	UINT uiIpv6AddIndex = 0;
 	UINT uiIpv6AddrNoLongWords = 4;
 	ULONG aulDestIP[4];
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	/*
 	 * This is the no. of Destination Addresses
 	 * ie Range of IP Addresses contained in the classifier rule
@@ -406,7 +406,7 @@ VOID DumpIpv6Address(ULONG *puIpv6Address)
 {
 	UINT uiIpv6AddrNoLongWords = 4;
 	UINT uiIpv6AddIndex = 0;
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
 				":%lx", puIpv6Address[uiIpv6AddIndex]);
@@ -418,7 +418,7 @@ static VOID DumpIpv6Header(IPV6Header *pstIpv6Header)
 {
 	UCHAR ucVersion;
 	UCHAR ucPrio;
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
 			"----Ipv6 Header---");
 	ucVersion = pstIpv6Header->ucVersionPrio & 0xf0;
diff --git a/drivers/staging/bcm/IPv6ProtocolHdr.h b/drivers/staging/bcm/IPv6ProtocolHdr.h
index a0db5a1..8ba88a5 100644
--- a/drivers/staging/bcm/IPv6ProtocolHdr.h
+++ b/drivers/staging/bcm/IPv6ProtocolHdr.h
@@ -102,15 +102,15 @@ typedef enum _E_IPADDR_CONTEXT
 
 //Function Prototypes
 
-USHORT	IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */
+USHORT	IpVersion6(struct bcm_mini_adapter *Adapter, /**< Pointer to the driver control structure */
 					PVOID pcIpHeader, /**<Pointer to the IP Hdr of the packet*/
-					S_CLASSIFIER_RULE *pstClassifierRule );
+					struct bcm_classifier_rule *pstClassifierRule );
 
 VOID DumpIpv6Address(ULONG *puIpv6Address);
 
-extern BOOLEAN MatchSrcPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
-extern BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
-extern BOOLEAN MatchProtocol(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucProtocol);
+extern BOOLEAN MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushSrcPort);
+extern BOOLEAN MatchDestPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushSrcPort);
+extern BOOLEAN MatchProtocol(struct bcm_classifier_rule *pstClassifierRule,UCHAR ucProtocol);
 
 
 #endif
diff --git a/drivers/staging/bcm/InterfaceAdapter.h b/drivers/staging/bcm/InterfaceAdapter.h
index 6397c20..4607c26 100644
--- a/drivers/staging/bcm/InterfaceAdapter.h
+++ b/drivers/staging/bcm/InterfaceAdapter.h
@@ -85,7 +85,7 @@ typedef struct _S_INTERFACE_ADAPTER
 	atomic_t		uNumRcbUsed;
 	atomic_t		uCurrRcb;
 
-	PMINI_ADAPTER	psAdapter;
+	struct bcm_mini_adapter *psAdapter;
 	BOOLEAN                 bFlashBoot;
 	BOOLEAN 		bHighSpeedDevice ;
 
diff --git a/drivers/staging/bcm/InterfaceDld.c b/drivers/staging/bcm/InterfaceDld.c
index 65c352f..3a89e33 100644
--- a/drivers/staging/bcm/InterfaceDld.c
+++ b/drivers/staging/bcm/InterfaceDld.c
@@ -7,7 +7,7 @@ int InterfaceFileDownload(PVOID arg, struct file *flp, unsigned int on_chip_loc)
 	int errno = 0, len = 0; /* ,is_config_file = 0 */
 	loff_t pos = 0;
 	PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)arg;
-	/* PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter; */
+	/* struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter; */
 	char *buff = kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL);
 
 	if (!buff)
@@ -132,7 +132,7 @@ exit:
 	return Status;
 }
 
-static int bcm_download_config_file(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo)
+static int bcm_download_config_file(struct bcm_mini_adapter *Adapter, struct bcm_firmware_info *psFwInfo)
 {
 	int retval = STATUS_SUCCESS;
 	B_UINT32 value = 0;
@@ -208,7 +208,7 @@ static int bcm_download_config_file(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwIn
 static int bcm_compare_buff_contents(unsigned char *readbackbuff, unsigned char *buff, unsigned int len)
 {
 	int retval = STATUS_SUCCESS;
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	if ((len-sizeof(unsigned int)) < 4) {
 		if (memcmp(readbackbuff , buff, len))
 			retval = -EINVAL;
@@ -229,7 +229,7 @@ static int bcm_compare_buff_contents(unsigned char *readbackbuff, unsigned char
 	return retval;
 }
 
-int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo)
+int bcm_ioctl_fw_download(struct bcm_mini_adapter *Adapter, struct bcm_firmware_info *psFwInfo)
 {
 	int retval = STATUS_SUCCESS;
 	PUCHAR buff = NULL;
@@ -278,7 +278,7 @@ error:
 	return retval;
 }
 
-static INT buffDnld(PMINI_ADAPTER Adapter, PUCHAR mappedbuffer, UINT u32FirmwareLength, ULONG u32StartingAddress)
+static INT buffDnld(struct bcm_mini_adapter *Adapter, PUCHAR mappedbuffer, UINT u32FirmwareLength, ULONG u32StartingAddress)
 {
 	unsigned int len = 0;
 	int retval = STATUS_SUCCESS;
@@ -299,7 +299,7 @@ static INT buffDnld(PMINI_ADAPTER Adapter, PUCHAR mappedbuffer, UINT u32Firmware
 	return retval;
 }
 
-static INT buffRdbkVerify(PMINI_ADAPTER Adapter, PUCHAR mappedbuffer, UINT u32FirmwareLength, ULONG u32StartingAddress)
+static INT buffRdbkVerify(struct bcm_mini_adapter *Adapter, PUCHAR mappedbuffer, UINT u32FirmwareLength, ULONG u32StartingAddress)
 {
 	UINT len = u32FirmwareLength;
 	INT retval = STATUS_SUCCESS;
@@ -334,7 +334,7 @@ static INT buffRdbkVerify(PMINI_ADAPTER Adapter, PUCHAR mappedbuffer, UINT u32Fi
 	return retval;
 }
 
-INT buffDnldVerify(PMINI_ADAPTER Adapter, unsigned char *mappedbuffer, unsigned int u32FirmwareLength, unsigned long u32StartingAddress)
+INT buffDnldVerify(struct bcm_mini_adapter *Adapter, unsigned char *mappedbuffer, unsigned int u32FirmwareLength, unsigned long u32StartingAddress)
 {
 	INT status = STATUS_SUCCESS;
 
diff --git a/drivers/staging/bcm/InterfaceIdleMode.c b/drivers/staging/bcm/InterfaceIdleMode.c
index faeb03e..4f2f490 100644
--- a/drivers/staging/bcm/InterfaceIdleMode.c
+++ b/drivers/staging/bcm/InterfaceIdleMode.c
@@ -7,7 +7,7 @@ Description:			This is the hardware specific Function for waking up HW device fr
 						A software abort pattern is written to the device to wake it and necessary power state
 						transitions from host are performed here.
 
-Input parameters:		IN PMINI_ADAPTER Adapter   - Miniport Adapter Context
+Input parameters:		IN struct bcm_mini_adapter *Adapter   - Miniport Adapter Context
 
 
 Return:				BCM_STATUS_SUCCESS - If Wakeup of the HW Interface was successful.
@@ -22,7 +22,7 @@ Description:			This is the hardware specific Function for responding to Idle mod
 						Necessary power state transitions from host for idle mode or other device specific
 						initializations are performed here.
 
-Input parameters:		IN PMINI_ADAPTER Adapter   - Miniport Adapter Context
+Input parameters:		IN struct bcm_mini_adapter * Adapter   - Miniport Adapter Context
 
 
 Return:				BCM_STATUS_SUCCESS - If Idle mode response related HW configuration was successful.
@@ -42,7 +42,7 @@ send to f/w with in 200 ms after the Idle/Shutdown req issued
 */
 
 
-int InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int* puiBuffer)
+int InterfaceIdleModeRespond(struct bcm_mini_adapter *Adapter, unsigned int* puiBuffer)
 {
 	int	status = STATUS_SUCCESS;
 	unsigned int	uiRegRead = 0;
@@ -147,7 +147,7 @@ int InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int* puiBuffer)
 	return status;
 }
 
-static int InterfaceAbortIdlemode(PMINI_ADAPTER Adapter, unsigned int Pattern)
+static int InterfaceAbortIdlemode(struct bcm_mini_adapter *Adapter, unsigned int Pattern)
 {
 	int 	status = STATUS_SUCCESS;
 	unsigned int value;
@@ -246,7 +246,7 @@ static int InterfaceAbortIdlemode(PMINI_ADAPTER Adapter, unsigned int Pattern)
 	}
 	return status;
 }
-int InterfaceIdleModeWakeup(PMINI_ADAPTER Adapter)
+int InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter)
 {
 	ULONG	Status = 0;
 	if(Adapter->bTriedToWakeUpFromlowPowerMode)
@@ -263,7 +263,7 @@ int InterfaceIdleModeWakeup(PMINI_ADAPTER Adapter)
 	return Status;
 }
 
-void InterfaceHandleShutdownModeWakeup(PMINI_ADAPTER Adapter)
+void InterfaceHandleShutdownModeWakeup(struct bcm_mini_adapter *Adapter)
 {
 	unsigned int uiRegVal = 0;
 	INT Status = 0;
diff --git a/drivers/staging/bcm/InterfaceIdleMode.h b/drivers/staging/bcm/InterfaceIdleMode.h
index 859a2ff..c3338c8 100644
--- a/drivers/staging/bcm/InterfaceIdleMode.h
+++ b/drivers/staging/bcm/InterfaceIdleMode.h
@@ -1,14 +1,14 @@
 #ifndef _INTERFACE_IDLEMODE_H
 #define _INTERFACE_IDLEMODE_H
 
-INT InterfaceIdleModeWakeup(PMINI_ADAPTER Adapter);
+INT InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter);
 
-INT InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int *puiBuffer);
+INT InterfaceIdleModeRespond(struct bcm_mini_adapter *Adapter, unsigned int *puiBuffer);
 
-VOID InterfaceWriteIdleModeWakePattern(PMINI_ADAPTER Adapter);
+VOID InterfaceWriteIdleModeWakePattern(struct bcm_mini_adapter *Adapter);
 
-INT InterfaceWakeUp(PMINI_ADAPTER Adapter);
+INT InterfaceWakeUp(struct bcm_mini_adapter * Adapter);
 
-VOID InterfaceHandleShutdownModeWakeup(PMINI_ADAPTER Adapter);
+VOID InterfaceHandleShutdownModeWakeup(struct bcm_mini_adapter *Adapter);
 #endif
 
diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c
index 8e3c586..8f85de6 100644
--- a/drivers/staging/bcm/InterfaceInit.c
+++ b/drivers/staging/bcm/InterfaceInit.c
@@ -65,7 +65,7 @@ static void InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter)
 	AdapterFree(psIntfAdapter->psAdapter);
 }
 
-static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter)
+static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter)
 {
 	unsigned long ulReg = 0;
 	int bytes;
@@ -143,12 +143,12 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 	int retval;
-	PMINI_ADAPTER psAdapter;
+	struct bcm_mini_adapter *psAdapter;
 	PS_INTERFACE_ADAPTER psIntfAdapter;
 	struct net_device *ndev;
 
 	/* Reserve one extra queue for the bit-bucket */
-	ndev = alloc_etherdev_mq(sizeof(MINI_ADAPTER), NO_OF_QUEUES+1);
+	ndev = alloc_etherdev_mq(sizeof(struct bcm_mini_adapter), NO_OF_QUEUES+1);
 	if (ndev == NULL) {
 		dev_err(&udev->dev, DRV_NAME ": no memory for device\n");
 		return -ENOMEM;
@@ -257,7 +257,7 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi
 static void usbbcm_disconnect(struct usb_interface *intf)
 {
 	PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
-	PMINI_ADAPTER psAdapter;
+	struct bcm_mini_adapter *psAdapter;
 	struct usb_device  *udev = interface_to_usbdev(intf);
 
 	if (psIntfAdapter == NULL)
diff --git a/drivers/staging/bcm/InterfaceIsr.c b/drivers/staging/bcm/InterfaceIsr.c
index 67719d5..6ee3428 100644
--- a/drivers/staging/bcm/InterfaceIsr.c
+++ b/drivers/staging/bcm/InterfaceIsr.c
@@ -5,7 +5,7 @@ static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/)
 {
 	int		status = urb->status;
 	PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)urb->context;
-	PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter ;
+	struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter ;
 
 	if (netif_msg_intr(Adapter))
 		pr_info(PFX "%s: interrupt status %d\n",
diff --git a/drivers/staging/bcm/InterfaceIsr.h b/drivers/staging/bcm/InterfaceIsr.h
index 6065a71..4039978 100644
--- a/drivers/staging/bcm/InterfaceIsr.h
+++ b/drivers/staging/bcm/InterfaceIsr.h
@@ -7,9 +7,9 @@ int CreateInterruptUrb(PS_INTERFACE_ADAPTER psIntfAdapter);
 INT StartInterruptUrb(PS_INTERFACE_ADAPTER psIntfAdapter);
 
 
-VOID InterfaceEnableInterrupt(PMINI_ADAPTER Adapter);
+VOID InterfaceEnableInterrupt(struct bcm_mini_adapter *Adapter);
 
-VOID InterfaceDisableInterrupt(PMINI_ADAPTER Adapter);
+VOID InterfaceDisableInterrupt(struct bcm_mini_adapter *Adapter);
 
 #endif
 
diff --git a/drivers/staging/bcm/InterfaceMisc.c b/drivers/staging/bcm/InterfaceMisc.c
index 2218fae..bbe9099 100644
--- a/drivers/staging/bcm/InterfaceMisc.c
+++ b/drivers/staging/bcm/InterfaceMisc.c
@@ -133,7 +133,7 @@ INT BcmWRM(PVOID arg,
 	return InterfaceWRM((PS_INTERFACE_ADAPTER)arg, addr, buff, len);
 }
 
-INT Bcm_clear_halt_of_endpoints(PMINI_ADAPTER Adapter)
+INT Bcm_clear_halt_of_endpoints(struct bcm_mini_adapter *Adapter)
 {
 	PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter);
 	INT status = STATUS_SUCCESS;
diff --git a/drivers/staging/bcm/InterfaceMisc.h b/drivers/staging/bcm/InterfaceMisc.h
index 6c9e39b..1dfabdc 100644
--- a/drivers/staging/bcm/InterfaceMisc.h
+++ b/drivers/staging/bcm/InterfaceMisc.h
@@ -33,7 +33,7 @@ int BcmWRM(PVOID arg,
 			PVOID buff,
 			INT len);
 
-INT Bcm_clear_halt_of_endpoints(PMINI_ADAPTER Adapter);
+INT Bcm_clear_halt_of_endpoints(struct bcm_mini_adapter *Adapter);
 
 VOID Bcm_kill_all_URBs(PS_INTERFACE_ADAPTER psIntfAdapter);
 
diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c
index d495828..8a9f90f 100644
--- a/drivers/staging/bcm/InterfaceRx.c
+++ b/drivers/staging/bcm/InterfaceRx.c
@@ -1,6 +1,6 @@
 #include "headers.h"
 
-static int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid)
+static int SearchVcid(struct bcm_mini_adapter *Adapter,unsigned short usVcid)
 {
 	int iIndex=0;
 
@@ -45,8 +45,8 @@ static void read_bulk_callback(struct urb *urb)
 	//int idleflag = 0 ;
 	PUSB_RCB pRcb = (PUSB_RCB)urb->context;
 	PS_INTERFACE_ADAPTER psIntfAdapter = pRcb->psIntfAdapter;
-	PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter;
-	PLEADER pLeader = urb->transfer_buffer;
+	struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter;
+	struct bcm_leader *pLeader = urb->transfer_buffer;
 
 	if (unlikely(netif_msg_rx_status(Adapter)))
 		pr_info(PFX "%s: rx urb status %d length %d\n",
@@ -126,7 +126,7 @@ static void read_bulk_callback(struct urb *urb)
 	    BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_CTRL, DBG_LVL_ALL, "Received control pkt...");
 		*(PUSHORT)skb->data = pLeader->Status;
        	memcpy(skb->data+sizeof(USHORT), urb->transfer_buffer +
-			(sizeof(LEADER)), pLeader->PLength);
+			(sizeof(struct bcm_leader)), pLeader->PLength);
 		skb->len = pLeader->PLength + sizeof(USHORT);
 
 		spin_lock(&Adapter->control_queue_lock);
@@ -144,7 +144,7 @@ static void read_bulk_callback(struct urb *urb)
 		  */
         BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Received Data pkt...");
 		skb_reserve(skb, 2 + SKB_RESERVE_PHS_BYTES);
-		memcpy(skb->data+ETH_HLEN, (PUCHAR)urb->transfer_buffer + sizeof(LEADER), pLeader->PLength);
+		memcpy(skb->data+ETH_HLEN, (PUCHAR)urb->transfer_buffer + sizeof(struct bcm_leader), pLeader->PLength);
 		skb->dev = Adapter->dev;
 
 		/* currently skb->len has extra ETH_HLEN bytes in the beginning */
@@ -232,7 +232,7 @@ Function:				InterfaceRx
 Description:			This is the hardware specific Function for Receiving
 						data packet/control packets from the device.
 
-Input parameters:		IN PMINI_ADAPTER Adapter   - Miniport Adapter Context
+Input parameters:		IN struct bcm_mini_adapter *Adapter   - Miniport Adapter Context
 
 
 
diff --git a/drivers/staging/bcm/InterfaceTx.c b/drivers/staging/bcm/InterfaceTx.c
index a842de9..7e2b53b 100644
--- a/drivers/staging/bcm/InterfaceTx.c
+++ b/drivers/staging/bcm/InterfaceTx.c
@@ -5,10 +5,10 @@ static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/)
 {
 	PUSB_TCB pTcb= (PUSB_TCB)urb->context;
 	PS_INTERFACE_ADAPTER psIntfAdapter = pTcb->psIntfAdapter;
-	CONTROL_MESSAGE *pControlMsg = (CONTROL_MESSAGE *)urb->transfer_buffer;
-	PMINI_ADAPTER psAdapter = psIntfAdapter->psAdapter ;
+	struct bcm_link_request *pControlMsg = (struct bcm_link_request *)urb->transfer_buffer;
+	struct bcm_mini_adapter *psAdapter = psIntfAdapter->psAdapter ;
 	BOOLEAN bpowerDownMsg = FALSE ;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
     if (unlikely(netif_msg_tx_done(Adapter)))
 	    pr_info(PFX "%s: transmit status %d\n", Adapter->dev->name, urb->status);
diff --git a/drivers/staging/bcm/LeakyBucket.c b/drivers/staging/bcm/LeakyBucket.c
index a55d422..6e8a327 100644
--- a/drivers/staging/bcm/LeakyBucket.c
+++ b/drivers/staging/bcm/LeakyBucket.c
@@ -15,7 +15,7 @@
 * Returns     - None
 **********************************************************************/
 
-static VOID UpdateTokenCount(register PMINI_ADAPTER Adapter)
+static VOID UpdateTokenCount(register struct bcm_mini_adapter *Adapter)
 {
 	ULONG 	liCurrentTime;
 	INT 	i = 0;
@@ -75,7 +75,7 @@ static VOID UpdateTokenCount(register PMINI_ADAPTER Adapter)
 * Returns     - The number of bytes allowed for transmission.
 *
 ***********************************************************************/
-static ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF)
+static ULONG GetSFTokenCount(struct bcm_mini_adapter *Adapter, struct bcm_packet_info *psSF)
 {
 	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow ===>");
 	/* Validate the parameters */
@@ -112,8 +112,8 @@ static ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF)
 This function despatches packet from the specified queue.
 @return Zero(success) or Negative value(failure)
 */
-static INT SendPacketFromQueue(PMINI_ADAPTER Adapter,/**<Logical Adapter*/
-			       PacketInfo *psSF,		/**<Queue identifier*/
+static INT SendPacketFromQueue(struct bcm_mini_adapter *Adapter,/**<Logical Adapter*/
+			struct bcm_packet_info *psSF, /**<Queue identifier*/
 			       struct sk_buff*  Packet)	/**<Pointer to the packet to be sent*/
 {
 	INT  	Status=STATUS_FAILURE;
@@ -156,7 +156,7 @@ static INT SendPacketFromQueue(PMINI_ADAPTER Adapter,/**<Logical Adapter*/
 * Returns     - None.
 *
 ****************************************************************************/
-static VOID CheckAndSendPacketFromIndex(PMINI_ADAPTER Adapter, PacketInfo *psSF)
+static VOID CheckAndSendPacketFromIndex(struct bcm_mini_adapter *Adapter, struct bcm_packet_info *psSF)
 {
 	struct sk_buff	*QueuePacket=NULL;
 	char 			*pControlPacket = NULL;
@@ -243,10 +243,10 @@ static VOID CheckAndSendPacketFromIndex(PMINI_ADAPTER Adapter, PacketInfo *psSF)
 				{
 					spin_lock_bh(&psSF->SFQueueLock);
 					psSF->NumOfPacketsSent++;
-					psSF->uiSentBytes+=((PLEADER)pControlPacket)->PLength;
+					psSF->uiSentBytes+=((struct bcm_leader *)pControlPacket)->PLength;
 					psSF->uiSentPackets++;
 					atomic_dec(&Adapter->TotalPacketCount);
-					psSF->uiCurrentBytesOnHost -= ((PLEADER)pControlPacket)->PLength;
+					psSF->uiCurrentBytesOnHost -= ((struct bcm_leader *)pControlPacket)->PLength;
 					psSF->uiCurrentPacketsOnHost--;
 					atomic_inc(&Adapter->index_rd_txcntrlpkt);
 					spin_unlock_bh(&psSF->SFQueueLock);
@@ -273,7 +273,7 @@ static VOID CheckAndSendPacketFromIndex(PMINI_ADAPTER Adapter, PacketInfo *psSF)
 *
 * Returns     - None.
 ********************************************************************/
-VOID transmit_packets(PMINI_ADAPTER Adapter)
+VOID transmit_packets(struct bcm_mini_adapter *Adapter)
 {
 	UINT 	uiPrevTotalCount = 0;
 	int iIndex = 0;
diff --git a/drivers/staging/bcm/Macros.h b/drivers/staging/bcm/Macros.h
index 46ed99c..b5ca6f6 100644
--- a/drivers/staging/bcm/Macros.h
+++ b/drivers/staging/bcm/Macros.h
@@ -108,11 +108,11 @@
 /*Leader related terms */
 #define LEADER_STATUS         0x00
 #define LEADER_STATUS_TCP_ACK 0x1
-#define LEADER_SIZE           sizeof(LEADER)
-#define MAC_ADDR_REQ_SIZE     sizeof(PACKETTOSEND)
-#define SS_INFO_REQ_SIZE      sizeof(PACKETTOSEND)
+#define LEADER_SIZE           sizeof(struct bcm_leader)
+#define MAC_ADDR_REQ_SIZE     sizeof(struct bcm_packettosend)
+#define SS_INFO_REQ_SIZE      sizeof(struct bcm_packettosend)
 #define CM_REQUEST_SIZE       (LEADER_SIZE + sizeof(stLocalSFChangeRequest))
-#define IDLE_REQ_SIZE         sizeof(PACKETTOSEND)
+#define IDLE_REQ_SIZE         sizeof(struct bcm_packettosend)
 
 
 #define MAX_TRANSFER_CTRL_BYTE_USB (2*1024)
@@ -252,11 +252,7 @@ typedef enum _E_PHS_DSC_ACTION {
 #define IDLE_MODE_WAKEUP_NOTIFIER_ADDRESS 0x1FC02FA8
 #define IDLE_MODE_MAX_RETRY_COUNT 1000
 
-#ifdef REL_4_1
-#define CONFIG_BEGIN_ADDR 0xBF60B004
-#else
 #define CONFIG_BEGIN_ADDR 0xBF60B000
-#endif
 
 #define FIRMWARE_BEGIN_ADDR 0xBFC00000
 
diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c
index 8223a69..c36fd76 100644
--- a/drivers/staging/bcm/Misc.c
+++ b/drivers/staging/bcm/Misc.c
@@ -1,12 +1,12 @@
 #include "headers.h"
 
-static int BcmFileDownload(PMINI_ADAPTER Adapter, const char *path, unsigned int loc);
-static VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter);
-static void HandleShutDownModeRequest(PMINI_ADAPTER Adapter, PUCHAR pucBuffer);
-static int bcm_parse_target_params(PMINI_ADAPTER Adapter);
-static void beceem_protocol_reset(PMINI_ADAPTER Adapter);
+static int BcmFileDownload(struct bcm_mini_adapter *Adapter, const char *path, unsigned int loc);
+static VOID doPowerAutoCorrection(struct bcm_mini_adapter *psAdapter);
+static void HandleShutDownModeRequest(struct bcm_mini_adapter *Adapter, PUCHAR pucBuffer);
+static int bcm_parse_target_params(struct bcm_mini_adapter *Adapter);
+static void beceem_protocol_reset(struct bcm_mini_adapter *Adapter);
 
-static VOID default_wimax_protocol_initialize(PMINI_ADAPTER Adapter)
+static VOID default_wimax_protocol_initialize(struct bcm_mini_adapter *Adapter)
 {
 	UINT uiLoopIndex;
 
@@ -24,7 +24,7 @@ static VOID default_wimax_protocol_initialize(PMINI_ADAPTER Adapter)
 	return;
 }
 
-INT InitAdapter(PMINI_ADAPTER psAdapter)
+INT InitAdapter(struct bcm_mini_adapter *psAdapter)
 {
 	int i = 0;
 	INT Status = STATUS_SUCCESS;
@@ -93,7 +93,7 @@ INT InitAdapter(PMINI_ADAPTER psAdapter)
 	return STATUS_SUCCESS;
 }
 
-VOID AdapterFree(PMINI_ADAPTER Adapter)
+VOID AdapterFree(struct bcm_mini_adapter *Adapter)
 {
 	int count;
 	beceem_protocol_reset(Adapter);
@@ -134,7 +134,7 @@ VOID AdapterFree(PMINI_ADAPTER Adapter)
 	free_netdev(Adapter->dev);
 }
 
-static int create_worker_threads(PMINI_ADAPTER psAdapter)
+static int create_worker_threads(struct bcm_mini_adapter *psAdapter)
 {
 	/* Rx Control Packets Processing */
 	psAdapter->control_packet_handler = kthread_run((int (*)(void *))
@@ -155,7 +155,7 @@ static int create_worker_threads(PMINI_ADAPTER psAdapter)
 	return 0;
 }
 
-static struct file *open_firmware_file(PMINI_ADAPTER Adapter, const char *path)
+static struct file *open_firmware_file(struct bcm_mini_adapter *Adapter, const char *path)
 {
 	struct file *flp = NULL;
 	mm_segment_t oldfs;
@@ -179,7 +179,7 @@ static struct file *open_firmware_file(PMINI_ADAPTER Adapter, const char *path)
  * Path to image file
  * Download Address on the chip
  */
-static int BcmFileDownload(PMINI_ADAPTER Adapter, const char *path, unsigned int loc)
+static int BcmFileDownload(struct bcm_mini_adapter *Adapter, const char *path, unsigned int loc)
 {
 	int errorno = 0;
 	struct file *flp = NULL;
@@ -231,13 +231,13 @@ exit_download:
  * Logical Adapter
  * Control Packet Buffer
  */
-INT CopyBufferToControlPacket(PMINI_ADAPTER Adapter, PVOID ioBuffer)
+INT CopyBufferToControlPacket(struct bcm_mini_adapter *Adapter, PVOID ioBuffer)
 {
-	PLEADER	pLeader = NULL;
+	struct bcm_leader *pLeader = NULL;
 	INT Status = 0;
 	unsigned char *ctrl_buff = NULL;
 	UINT pktlen = 0;
-	PLINK_REQUEST pLinkReq = NULL;
+	struct bcm_link_request *pLinkReq = NULL;
 	PUCHAR pucAddIndication = NULL;
 
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "======>");
@@ -246,8 +246,8 @@ INT CopyBufferToControlPacket(PMINI_ADAPTER Adapter, PVOID ioBuffer)
 		return -EINVAL;
 	}
 
-	pLinkReq = (PLINK_REQUEST)ioBuffer;
-	pLeader = (PLEADER)ioBuffer; /* ioBuffer Contains sw_Status and Payload */
+	pLinkReq = (struct bcm_link_request *)ioBuffer;
+	pLeader = (struct bcm_leader *)ioBuffer; /* ioBuffer Contains sw_Status and Payload */
 
 	if (Adapter->bShutStatus == TRUE &&
 		pLinkReq->szData[0] == LINK_DOWN_REQ_PAYLOAD &&
@@ -373,7 +373,7 @@ INT CopyBufferToControlPacket(PMINI_ADAPTER Adapter, PVOID ioBuffer)
 
 		memset(ctrl_buff, 0, pktlen+LEADER_SIZE);
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Copying the Control Packet Buffer with length=%d\n", pLeader->PLength);
-		*(PLEADER)ctrl_buff = *pLeader;
+		*(struct bcm_leader *)ctrl_buff = *pLeader;
 		memcpy(ctrl_buff + LEADER_SIZE, ((PUCHAR)ioBuffer + LEADER_SIZE), pLeader->PLength);
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Enqueuing the Control Packet");
 
@@ -414,7 +414,7 @@ INT CopyBufferToControlPacket(PMINI_ADAPTER Adapter, PVOID ioBuffer)
 *
 * Returns     - None.
 *****************************************************************/
-static VOID SendStatisticsPointerRequest(PMINI_ADAPTER Adapter, PLINK_REQUEST pstStatisticsPtrRequest)
+static VOID SendStatisticsPointerRequest(struct bcm_mini_adapter *Adapter, struct bcm_link_request *pstStatisticsPtrRequest)
 {
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "======>");
 	pstStatisticsPtrRequest->Leader.Status = STATS_POINTER_REQ_STATUS;
@@ -436,12 +436,12 @@ static VOID SendStatisticsPointerRequest(PMINI_ADAPTER Adapter, PLINK_REQUEST ps
 *
 * Returns     - None.
 *******************************************************************/
-VOID LinkMessage(PMINI_ADAPTER Adapter)
+VOID LinkMessage(struct bcm_mini_adapter *Adapter)
 {
-	PLINK_REQUEST pstLinkRequest = NULL;
+	struct bcm_link_request *pstLinkRequest = NULL;
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "=====>");
 	if (Adapter->LinkStatus == SYNC_UP_REQUEST && Adapter->AutoSyncup) {
-		pstLinkRequest = kzalloc(sizeof(LINK_REQUEST), GFP_ATOMIC);
+		pstLinkRequest = kzalloc(sizeof(struct bcm_link_request), GFP_ATOMIC);
 		if (!pstLinkRequest) {
 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "Can not allocate memory for Link request!");
 			return;
@@ -456,7 +456,7 @@ VOID LinkMessage(PMINI_ADAPTER Adapter)
 		Adapter->bSyncUpRequestSent = TRUE;
 
 	} else if (Adapter->LinkStatus == PHY_SYNC_ACHIVED && Adapter->AutoLinkUp) {
-		pstLinkRequest = kzalloc(sizeof(LINK_REQUEST), GFP_ATOMIC);
+		pstLinkRequest = kzalloc(sizeof(struct bcm_link_request), GFP_ATOMIC);
 		if (!pstLinkRequest) {
 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "Can not allocate memory for Link request!");
 			return;
@@ -487,7 +487,7 @@ VOID LinkMessage(PMINI_ADAPTER Adapter)
 *
 * Returns     - None.
 ************************************************************************/
-VOID StatisticsResponse(PMINI_ADAPTER Adapter, PVOID pvBuffer)
+VOID StatisticsResponse(struct bcm_mini_adapter *Adapter, PVOID pvBuffer)
 {
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "%s====>", __func__);
 	Adapter->StatisticsPointer = ntohl(*(__be32 *)pvBuffer);
@@ -506,7 +506,7 @@ VOID StatisticsResponse(PMINI_ADAPTER Adapter, PVOID pvBuffer)
 *
 * Returns     - None.
 ***********************************************************************/
-VOID LinkControlResponseMessage(PMINI_ADAPTER Adapter, PUCHAR pucBuffer)
+VOID LinkControlResponseMessage(struct bcm_mini_adapter *Adapter, PUCHAR pucBuffer)
 {
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "=====>");
 
@@ -580,11 +580,11 @@ VOID LinkControlResponseMessage(PMINI_ADAPTER Adapter, PUCHAR pucBuffer)
 	return;
 }
 
-void SendIdleModeResponse(PMINI_ADAPTER Adapter)
+void SendIdleModeResponse(struct bcm_mini_adapter *Adapter)
 {
 	INT status = 0, NVMAccess = 0, lowPwrAbortMsg = 0;
 	struct timeval tv;
-	CONTROL_MESSAGE stIdleResponse = {{0} };
+	struct bcm_link_request stIdleResponse = {{0} };
 	memset(&tv, 0, sizeof(tv));
 	stIdleResponse.Leader.Status = IDLE_MESSAGE;
 	stIdleResponse.Leader.PLength = IDLE_MODE_PAYLOAD_LENGTH;
@@ -679,12 +679,12 @@ void SendIdleModeResponse(PMINI_ADAPTER Adapter)
 *
 * Returns     - None.
 *******************************************************************/
-VOID DumpPackInfo(PMINI_ADAPTER Adapter)
+VOID DumpPackInfo(struct bcm_mini_adapter *Adapter)
 {
 	UINT uiLoopIndex = 0;
 	UINT uiIndex = 0;
 	UINT uiClsfrIndex = 0;
-	S_CLASSIFIER_RULE *pstClassifierEntry = NULL;
+	struct bcm_classifier_rule *pstClassifierEntry = NULL;
 
 	for (uiLoopIndex = 0; uiLoopIndex < NO_OF_QUEUES; uiLoopIndex++) {
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "*********** Showing Details Of Queue %d***** ******", uiLoopIndex);
@@ -808,10 +808,10 @@ VOID DumpPackInfo(PMINI_ADAPTER Adapter)
 	return;
 }
 
-int reset_card_proc(PMINI_ADAPTER ps_adapter)
+int reset_card_proc(struct bcm_mini_adapter *ps_adapter)
 {
 	int retval = STATUS_SUCCESS;
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	PS_INTERFACE_ADAPTER psIntfAdapter = NULL;
 	unsigned int value = 0, uiResetValue = 0;
 	int bytes;
@@ -926,7 +926,7 @@ err_exit:
 	return retval;
 }
 
-int run_card_proc(PMINI_ADAPTER ps_adapter)
+int run_card_proc(struct bcm_mini_adapter *ps_adapter)
 {
 	int status = STATUS_SUCCESS;
 	int bytes;
@@ -953,7 +953,7 @@ int run_card_proc(PMINI_ADAPTER ps_adapter)
 	return status;
 }
 
-int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
+int InitCardAndDownloadFirmware(struct bcm_mini_adapter *ps_adapter)
 {
 	int status;
 	UINT value = 0;
@@ -1077,7 +1077,7 @@ OUT:
 	return status;
 }
 
-static int bcm_parse_target_params(PMINI_ADAPTER Adapter)
+static int bcm_parse_target_params(struct bcm_mini_adapter *Adapter)
 {
 	struct file *flp = NULL;
 	mm_segment_t oldfs = {0};
@@ -1128,7 +1128,7 @@ static int bcm_parse_target_params(PMINI_ADAPTER Adapter)
 	return STATUS_SUCCESS;
 }
 
-void beceem_parse_target_struct(PMINI_ADAPTER Adapter)
+void beceem_parse_target_struct(struct bcm_mini_adapter *Adapter)
 {
 	UINT uiHostDrvrCfg6 = 0, uiEEPROMFlag = 0;
 
@@ -1186,7 +1186,7 @@ void beceem_parse_target_struct(PMINI_ADAPTER Adapter)
 		doPowerAutoCorrection(Adapter);
 }
 
-static VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter)
+static VOID doPowerAutoCorrection(struct bcm_mini_adapter *psAdapter)
 {
 	UINT reporting_mode;
 
@@ -1218,7 +1218,7 @@ static VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter)
 }
 
 #if 0
-static unsigned char *ReadMacAddrEEPROM(PMINI_ADAPTER Adapter, ulong dwAddress)
+static unsigned char *ReadMacAddrEEPROM(struct bcm_mini_adapter *Adapter, ulong dwAddress)
 {
 	int status = 0, i = 0;
 	unsigned int temp = 0;
@@ -1272,13 +1272,13 @@ static void convertEndian(B_UINT8 rwFlag, PUINT puiBuffer, UINT uiByteCount)
 #define CACHE_ADDRESS_MASK 0x80000000
 #define UNCACHE_ADDRESS_MASK 0xa0000000
 
-int rdm(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
+int rdm(struct bcm_mini_adapter *Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
 {
 	return Adapter->interface_rdm(Adapter->pvInterfaceAdapter,
 				uiAddress, pucBuff, sSize);
 }
 
-int wrm(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
+int wrm(struct bcm_mini_adapter *Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
 {
 	int iRetVal;
 
@@ -1287,13 +1287,13 @@ int wrm(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
 	return iRetVal;
 }
 
-int wrmalt(PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t size)
+int wrmalt(struct bcm_mini_adapter *Adapter, UINT uiAddress, PUINT pucBuff, size_t size)
 {
 	convertEndian(RWM_WRITE, pucBuff, size);
 	return wrm(Adapter, uiAddress, (PUCHAR)pucBuff, size);
 }
 
-int rdmalt(PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t size)
+int rdmalt(struct bcm_mini_adapter *Adapter, UINT uiAddress, PUINT pucBuff, size_t size)
 {
 	INT uiRetVal = 0;
 
@@ -1303,7 +1303,7 @@ int rdmalt(PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t size)
 	return uiRetVal;
 }
 
-int wrmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
+int wrmWithLock(struct bcm_mini_adapter *Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
 {
 	INT status = STATUS_SUCCESS;
 	down(&Adapter->rdmwrmsync);
@@ -1322,7 +1322,7 @@ exit:
 	return status;
 }
 
-int wrmaltWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t size)
+int wrmaltWithLock(struct bcm_mini_adapter *Adapter, UINT uiAddress, PUINT pucBuff, size_t size)
 {
 	int iRetVal = STATUS_SUCCESS;
 
@@ -1342,7 +1342,7 @@ exit:
 	return iRetVal;
 }
 
-int rdmaltWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t size)
+int rdmaltWithLock(struct bcm_mini_adapter *Adapter, UINT uiAddress, PUINT pucBuff, size_t size)
 {
 	INT uiRetVal = STATUS_SUCCESS;
 
@@ -1361,7 +1361,7 @@ exit:
 	return uiRetVal;
 }
 
-static VOID HandleShutDownModeWakeup(PMINI_ADAPTER Adapter)
+static VOID HandleShutDownModeWakeup(struct bcm_mini_adapter *Adapter)
 {
 	int clear_abort_pattern = 0, Status = 0;
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "====>\n");
@@ -1390,13 +1390,13 @@ static VOID HandleShutDownModeWakeup(PMINI_ADAPTER Adapter)
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "<====\n");
 }
 
-static VOID SendShutModeResponse(PMINI_ADAPTER Adapter)
+static VOID SendShutModeResponse(struct bcm_mini_adapter *Adapter)
 {
-	CONTROL_MESSAGE stShutdownResponse;
+	struct bcm_link_request stShutdownResponse;
 	UINT NVMAccess = 0, lowPwrAbortMsg = 0;
 	UINT Status = 0;
 
-	memset(&stShutdownResponse, 0, sizeof(CONTROL_MESSAGE));
+	memset(&stShutdownResponse, 0, sizeof(struct bcm_link_request));
 	stShutdownResponse.Leader.Status  = LINK_UP_CONTROL_REQ;
 	stShutdownResponse.Leader.PLength = 8; /* 8 bytes; */
 	stShutdownResponse.szData[0] = LINK_UP_ACK;
@@ -1474,7 +1474,7 @@ static VOID SendShutModeResponse(PMINI_ADAPTER Adapter)
 	}
 }
 
-static void HandleShutDownModeRequest(PMINI_ADAPTER Adapter, PUCHAR pucBuffer)
+static void HandleShutDownModeRequest(struct bcm_mini_adapter *Adapter, PUCHAR pucBuffer)
 {
 	B_UINT32 uiResetValue = 0;
 
@@ -1503,7 +1503,7 @@ static void HandleShutDownModeRequest(PMINI_ADAPTER Adapter, PUCHAR pucBuffer)
 	return;
 }
 
-VOID ResetCounters(PMINI_ADAPTER Adapter)
+VOID ResetCounters(struct bcm_mini_adapter *Adapter)
 {
 	beceem_protocol_reset(Adapter);
 	Adapter->CurrNumRecvDescs = 0;
@@ -1519,7 +1519,7 @@ VOID ResetCounters(PMINI_ADAPTER Adapter)
 	Adapter->bShutStatus = FALSE;
 }
 
-S_CLASSIFIER_RULE *GetFragIPClsEntry(PMINI_ADAPTER Adapter, USHORT usIpIdentification, ULONG SrcIP)
+struct bcm_classifier_rule *GetFragIPClsEntry(struct bcm_mini_adapter *Adapter, USHORT usIpIdentification, ULONG SrcIP)
 {
 	UINT uiIndex = 0;
 	for (uiIndex = 0; uiIndex < MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES; uiIndex++) {
@@ -1533,18 +1533,18 @@ S_CLASSIFIER_RULE *GetFragIPClsEntry(PMINI_ADAPTER Adapter, USHORT usIpIdentific
 	return NULL;
 }
 
-void AddFragIPClsEntry(PMINI_ADAPTER Adapter, PS_FRAGMENTED_PACKET_INFO psFragPktInfo)
+void AddFragIPClsEntry(struct bcm_mini_adapter *Adapter, struct bcm_fragmented_packet_info *psFragPktInfo)
 {
 	UINT uiIndex = 0;
 	for (uiIndex = 0; uiIndex < MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES; uiIndex++) {
 		if (!Adapter->astFragmentedPktClassifierTable[uiIndex].bUsed) {
-			memcpy(&Adapter->astFragmentedPktClassifierTable[uiIndex], psFragPktInfo, sizeof(S_FRAGMENTED_PACKET_INFO));
+			memcpy(&Adapter->astFragmentedPktClassifierTable[uiIndex], psFragPktInfo, sizeof(struct bcm_fragmented_packet_info));
 			break;
 		}
 	}
 }
 
-void DelFragIPClsEntry(PMINI_ADAPTER Adapter, USHORT usIpIdentification, ULONG SrcIp)
+void DelFragIPClsEntry(struct bcm_mini_adapter *Adapter, USHORT usIpIdentification, ULONG SrcIp)
 {
 	UINT uiIndex = 0;
 	for (uiIndex = 0; uiIndex < MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES; uiIndex++) {
@@ -1552,11 +1552,11 @@ void DelFragIPClsEntry(PMINI_ADAPTER Adapter, USHORT usIpIdentification, ULONG S
 			(Adapter->astFragmentedPktClassifierTable[uiIndex].usIpIdentification == usIpIdentification) &&
 			(Adapter->astFragmentedPktClassifierTable[uiIndex].ulSrcIpAddress == SrcIp))
 
-			memset(&Adapter->astFragmentedPktClassifierTable[uiIndex], 0, sizeof(S_FRAGMENTED_PACKET_INFO));
+			memset(&Adapter->astFragmentedPktClassifierTable[uiIndex], 0, sizeof(struct bcm_fragmented_packet_info));
 	}
 }
 
-void update_per_cid_rx(PMINI_ADAPTER Adapter)
+void update_per_cid_rx(struct bcm_mini_adapter *Adapter)
 {
 	UINT qindex = 0;
 
@@ -1580,7 +1580,7 @@ void update_per_cid_rx(PMINI_ADAPTER Adapter)
 	Adapter->liDrainCalculated = jiffies;
 }
 
-void update_per_sf_desc_cnts(PMINI_ADAPTER Adapter)
+void update_per_sf_desc_cnts(struct bcm_mini_adapter *Adapter)
 {
 	INT iIndex = 0;
 	u32 uibuff[MAX_TARGET_DSX_BUFFERS];
@@ -1606,7 +1606,7 @@ void update_per_sf_desc_cnts(PMINI_ADAPTER Adapter)
 	atomic_set(&Adapter->uiMBupdate, FALSE);
 }
 
-void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex)
+void flush_queue(struct bcm_mini_adapter *Adapter, UINT iQIndex)
 {
 	struct sk_buff *PacketToDrop = NULL;
 	struct net_device_stats *netstats = &Adapter->dev->stats;
@@ -1630,7 +1630,7 @@ void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex)
 	spin_unlock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
 }
 
-static void beceem_protocol_reset(PMINI_ADAPTER Adapter)
+static void beceem_protocol_reset(struct bcm_mini_adapter *Adapter)
 {
 	int i;
 	if (netif_msg_link(Adapter))
@@ -1652,7 +1652,7 @@ static void beceem_protocol_reset(PMINI_ADAPTER Adapter)
 	if (Adapter->TimerActive == TRUE)
 		Adapter->TimerActive = FALSE;
 
-	memset(Adapter->astFragmentedPktClassifierTable, 0, sizeof(S_FRAGMENTED_PACKET_INFO) * MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES);
+	memset(Adapter->astFragmentedPktClassifierTable, 0, sizeof(struct bcm_fragmented_packet_info) * MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES);
 
 	for (i = 0; i < HiPriority; i++) {
 		/* resetting only the first size (S_MIBS_SERVICEFLOW_TABLE) for the SF. */
diff --git a/drivers/staging/bcm/PHSModule.c b/drivers/staging/bcm/PHSModule.c
index 4aa2b71..4795742 100644
--- a/drivers/staging/bcm/PHSModule.c
+++ b/drivers/staging/bcm/PHSModule.c
@@ -54,11 +54,11 @@ Function:				PHSTransmit
 
 Description:			This routine handle PHS(Payload Header Suppression for Tx path.
 					It extracts a fragment of the NDIS_PACKET containing the header
-					to be suppressed.It then supresses the header by invoking PHS exported compress routine.
-					The header data after supression is copied back to the NDIS_PACKET.
+					to be suppressed. It then suppresses the header by invoking PHS exported compress routine.
+					The header data after suppression is copied back to the NDIS_PACKET.
 
 
-Input parameters:		IN PMINI_ADAPTER Adapter         - Miniport Adapter Context
+Input parameters:		IN struct bcm_mini_adapter *Adapter         - Miniport Adapter Context
 						IN Packet 				- NDIS packet containing data to be transmitted
 						IN USHORT Vcid        - vcid pertaining to connection on which the packet is being sent.Used to
 										        identify PHS rule to be applied.
@@ -69,7 +69,7 @@ Return:					STATUS_SUCCESS - If the send was successful.
 						Other          - If an error occured.
 */
 
-int PHSTransmit(PMINI_ADAPTER Adapter,
+int PHSTransmit(struct bcm_mini_adapter *Adapter,
 					 struct sk_buff	**pPacket,
 					 USHORT Vcid,
 					 B_UINT16 uiClassifierRuleID,
@@ -84,10 +84,10 @@ int PHSTransmit(PMINI_ADAPTER Adapter,
 	UINT	unPHSNewPktHeaderLen = 0;
 	/* Pointer to PHS IN Hdr Buffer */
 	PUCHAR pucPHSPktHdrInBuf =
-				Adapter->stPhsTxContextInfo.ucaHdrSupressionInBuf;
+				Adapter->stPhsTxContextInfo.ucaHdrSuppressionInBuf;
 	/* Pointer to PHS OUT Hdr Buffer */
 	PUCHAR  pucPHSPktHdrOutBuf =
-					Adapter->stPhsTxContextInfo.ucaHdrSupressionOutBuf;
+					Adapter->stPhsTxContextInfo.ucaHdrSuppressionOutBuf;
 	UINT       usPacketType;
 	UINT       BytesToRemove=0;
 	BOOLEAN  bPHSI = 0;
@@ -101,7 +101,7 @@ int PHSTransmit(PMINI_ADAPTER Adapter,
 	if(!bEthCSSupport)
 		BytesToRemove=ETH_HLEN;
 	/*
-		Accumulate the header upto the size we support supression
+		Accumulate the header upto the size we support suppression
 		from NDIS packet
 	*/
 
@@ -125,7 +125,7 @@ int PHSTransmit(PMINI_ADAPTER Adapter,
 	{
 
 
-		// Step 2 Supress Header using PHS and fill into intermediate ucaPHSPktHdrOutBuf.
+		// Step 2 Suppress Header using PHS and fill into intermediate ucaPHSPktHdrOutBuf.
 	// Suppress only if IP Header and PHS Enabled For the Service Flow
 		if(((usPacketType == ETHERNET_FRAMETYPE_IPV4) ||
 			(usPacketType == ETHERNET_FRAMETYPE_IPV6)) &&
@@ -209,7 +209,7 @@ int PHSTransmit(PMINI_ADAPTER Adapter,
 	return STATUS_SUCCESS;
 }
 
-int PHSReceive(PMINI_ADAPTER Adapter,
+int PHSReceive(struct bcm_mini_adapter *Adapter,
 					USHORT usVcid,
 					struct sk_buff *packet,
 					UINT *punPacketLen,
@@ -217,7 +217,7 @@ int PHSReceive(PMINI_ADAPTER Adapter,
 					UINT	bHeaderSuppressionEnabled)
 {
 	u32   nStandardPktHdrLen            		= 0;
-	u32   nTotalsupressedPktHdrBytes  = 0;
+	u32   nTotalsuppressedPktHdrBytes  = 0;
 	int     ulPhsStatus 		= 0;
 	PUCHAR pucInBuff = NULL ;
 	UINT TotalBytesAdded = 0;
@@ -235,11 +235,11 @@ int PHSReceive(PMINI_ADAPTER Adapter,
 		usVcid,
 		pucInBuff,
 		Adapter->ucaPHSPktRestoreBuf,
-		&nTotalsupressedPktHdrBytes,
+		&nTotalsuppressedPktHdrBytes,
 		&nStandardPktHdrLen);
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nSupressed PktHdrLen : 0x%x Restored PktHdrLen : 0x%x",
-					nTotalsupressedPktHdrBytes,nStandardPktHdrLen);
+	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nSuppressed PktHdrLen : 0x%x Restored PktHdrLen : 0x%x",
+					nTotalsuppressedPktHdrBytes,nStandardPktHdrLen);
 
 	if(ulPhsStatus != STATUS_PHS_COMPRESSED)
 	{
@@ -248,7 +248,7 @@ int PHSReceive(PMINI_ADAPTER Adapter,
 	}
 	else
 	{
-		TotalBytesAdded = nStandardPktHdrLen - nTotalsupressedPktHdrBytes - PHSI_LEN;
+		TotalBytesAdded = nStandardPktHdrLen - nTotalsuppressedPktHdrBytes - PHSI_LEN;
 		if(TotalBytesAdded)
 		{
 			if(skb_headroom(packet) >= (SKB_RESERVE_ETHERNET_HEADER + TotalBytesAdded))
@@ -273,7 +273,7 @@ int PHSReceive(PMINI_ADAPTER Adapter,
 
 void DumpFullPacket(UCHAR *pBuf,UINT nPktLen)
 {
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
     BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,"Dumping Data Packet");
     BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,pBuf,nPktLen);
 }
@@ -291,7 +291,7 @@ void DumpFullPacket(UCHAR *pBuf,UINT nPktLen)
 // TRUE(1)	-If allocation of memory was success full.
 // FALSE	-If allocation of memory fails.
 //-----------------------------------------------------------------------------
-int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter)
+int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension, struct bcm_mini_adapter *Adapter)
 {
 	int i;
 	S_SERVICEFLOW_TABLE *pstServiceFlowTable;
@@ -398,7 +398,7 @@ ULONG PhsUpdateClassifierRule(IN void* pvContext,
 	ULONG lStatus =0;
 	UINT nSFIndex =0 ;
 	S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 
 
@@ -462,7 +462,7 @@ ULONG PhsDeletePHSRule(IN void* pvContext,IN B_UINT16 uiVcid,IN B_UINT8 u8PHSI)
 	UINT nSFIndex =0, nClsidIndex =0 ;
 	S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
 	S_CLASSIFIER_TABLE *pstClassifierRulesTable = NULL;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 
 	PPHS_DEVICE_EXTENSION pDeviceExtension= (PPHS_DEVICE_EXTENSION)pvContext;
@@ -528,7 +528,7 @@ ULONG PhsDeleteClassifierRule(IN void* pvContext,IN B_UINT16 uiVcid ,IN B_UINT16
 	UINT nSFIndex =0, nClsidIndex =0 ;
 	S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
 	S_CLASSIFIER_ENTRY *pstClassifierEntry = NULL;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	PPHS_DEVICE_EXTENSION pDeviceExtension= (PPHS_DEVICE_EXTENSION)pvContext;
 
 	if(pDeviceExtension)
@@ -592,7 +592,7 @@ ULONG PhsDeleteSFRules(IN void* pvContext,IN B_UINT16 uiVcid)
 	UINT nSFIndex =0, nClsidIndex =0  ;
 	S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
 	S_CLASSIFIER_TABLE *pstClassifierRulesTable = NULL;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	PPHS_DEVICE_EXTENSION pDeviceExtension= (PPHS_DEVICE_EXTENSION)pvContext;
     BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"====> \n");
 
@@ -684,7 +684,7 @@ ULONG PhsCompress(IN void* pvContext,
 	S_CLASSIFIER_ENTRY *pstClassifierEntry = NULL;
 	S_PHS_RULE *pstPhsRule = NULL;
 	ULONG lStatus =0;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 
 
@@ -778,7 +778,7 @@ ULONG PhsDeCompress(IN void* pvContext,
 	S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
 	S_PHS_RULE *pstPhsRule = NULL;
 	UINT phsi;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	PPHS_DEVICE_EXTENSION pDeviceExtension=
         (PPHS_DEVICE_EXTENSION)pvContext;
 
@@ -847,7 +847,7 @@ ULONG PhsDeCompress(IN void* pvContext,
 static void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable)
 {
 	int i,j;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "=======>\n");
     if(psServiceFlowRulesTable)
@@ -1057,7 +1057,7 @@ UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid,
 	UINT uiStatus =PHS_SUCCESS;
 	UINT nClassifierIndex = 0;
 	S_CLASSIFIER_TABLE *psaClassifiertable = NULL;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
     psaClassifiertable = pstServiceFlowEntry->pstClassifierTable;
 
 	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "==>");
@@ -1148,7 +1148,7 @@ static UINT CreateClassifierPHSRule(IN B_UINT16  uiClsId,
 	BOOLEAN bFreeEntryFound = FALSE;
 	S_CLASSIFIER_ENTRY *psClassifierRules = NULL;
 	UINT nStatus = PHS_SUCCESS;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"Inside CreateClassifierPHSRule");
     if(psaClassifiertable == NULL)
 	{
@@ -1259,7 +1259,7 @@ static UINT UpdateClassifierPHSRule(IN B_UINT16  uiClsId,
 	S_PHS_RULE *pstAddPhsRule = NULL;
 	UINT              nPhsRuleIndex = 0;
 	BOOLEAN       bPHSRuleOrphaned = FALSE;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	psPhsRule->u8RefCnt =0;
 
 	/* Step 1 Deref Any Exisiting PHS Rule in this classifier Entry*/
@@ -1334,7 +1334,7 @@ static BOOLEAN DerefPhsRule(IN B_UINT16  uiClsId,S_CLASSIFIER_TABLE *psaClassifi
 void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension)
 {
 	int i,j,k,l;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
     BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n Dumping PHS Rules : \n");
 	for(i=0;i<MAX_SERVICEFLOWS;i++)
 	{
@@ -1415,7 +1415,7 @@ int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,
 	int bit,i=0;
 	unsigned char *phsf,*phsm;
 	int in_buf_len = *header_size-1;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	in_buf++;
     BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"====>\n");
 	*header_size = 0;
@@ -1494,8 +1494,8 @@ static int phs_compress(S_PHS_RULE  *phs_rule,unsigned char *in_buf
 			,unsigned char *out_buf,UINT *header_size,UINT *new_header_size)
 {
 	unsigned char *old_addr = out_buf;
-	int supress = 0;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	int suppress = 0;
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
     if(phs_rule == NULL)
 	{
 		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nphs_compress(): phs_rule null!");
@@ -1514,10 +1514,10 @@ static int phs_compress(S_PHS_RULE  *phs_rule,unsigned char *in_buf
 	}
 	//To copy PHSI
 	out_buf++;
-	supress = verify_suppress_phsf(in_buf,out_buf,phs_rule->u8PHSF,
+	suppress = verify_suppress_phsf(in_buf,out_buf,phs_rule->u8PHSF,
         phs_rule->u8PHSM, phs_rule->u8PHSS, phs_rule->u8PHSV,new_header_size);
 
-	if(supress == STATUS_PHS_COMPRESSED)
+	if(suppress == STATUS_PHS_COMPRESSED)
 	{
 		*old_addr = (unsigned char)phs_rule->u8PHSI;
 		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In phs_compress phsi %d",phs_rule->u8PHSI);
@@ -1527,7 +1527,7 @@ static int phs_compress(S_PHS_RULE  *phs_rule,unsigned char *in_buf
 		*old_addr = ZERO_PHSI;
 		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In phs_compress PHSV Verification failed");
 	}
-	return supress;
+	return suppress;
 }
 
 
@@ -1557,7 +1557,7 @@ static int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buff
 {
 	unsigned int size=0;
 	int bit,i=0;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
     BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In verify_phsf PHSM - 0x%X",*phsm);
 
 
diff --git a/drivers/staging/bcm/PHSModule.h b/drivers/staging/bcm/PHSModule.h
index c629585..b5f2115 100644
--- a/drivers/staging/bcm/PHSModule.h
+++ b/drivers/staging/bcm/PHSModule.h
@@ -1,7 +1,7 @@
 #ifndef BCM_MINIPORT_PHSMODULE_H
 #define BCM_MINIPORT_PHSMODULE_H
 
-int PHSTransmit(PMINI_ADAPTER Adapter,
+int PHSTransmit(struct bcm_mini_adapter *Adapter,
 					struct sk_buff **pPacket,
 					 USHORT Vcid,
 					 B_UINT16 uiClassifierRuleID,
@@ -9,7 +9,7 @@ int PHSTransmit(PMINI_ADAPTER Adapter,
 					 PUINT PacketLen,
 					 UCHAR bEthCSSupport);
 
-int PHSReceive(PMINI_ADAPTER Adapter,
+int PHSReceive(struct bcm_mini_adapter *Adapter,
 					USHORT usVcid,
 					struct sk_buff *packet,
 					UINT *punPacketLen,
@@ -25,7 +25,7 @@ void DumpFullPacket(UCHAR *pBuf,UINT nPktLen);
 void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension);
 
 
-int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter);
+int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,struct bcm_mini_adapter *Adapter);
 
 int PhsCleanup(PPHS_DEVICE_EXTENSION pPHSDeviceExt);
 
diff --git a/drivers/staging/bcm/Protocol.h b/drivers/staging/bcm/Protocol.h
index b8a4009..562d4dd 100644
--- a/drivers/staging/bcm/Protocol.h
+++ b/drivers/staging/bcm/Protocol.h
@@ -55,7 +55,7 @@ typedef struct _S_ETHCS_PKT_INFO
 
 typedef struct _ETH_CS_802_Q_FRAME
 {
-	ETH_HEADER_STRUC EThHdr;
+	struct bcm_eth_header EThHdr;
 	USHORT UserPriority:3;
 	USHORT CFI:1;
 	USHORT VLANID:12;
@@ -64,7 +64,7 @@ typedef struct _ETH_CS_802_Q_FRAME
 
 typedef struct _ETH_CS_802_LLC_FRAME
 {
-	ETH_HEADER_STRUC EThHdr;
+	struct bcm_eth_header EThHdr;
 	unsigned char DSAP;
 	unsigned char SSAP;
 	unsigned char Control;
@@ -72,7 +72,7 @@ typedef struct _ETH_CS_802_LLC_FRAME
 
 typedef struct _ETH_CS_802_LLC_SNAP_FRAME
 {
-	ETH_HEADER_STRUC EThHdr;
+	struct bcm_eth_header EThHdr;
 	unsigned char DSAP;
 	unsigned char SSAP;
 	unsigned char Control;
@@ -82,7 +82,7 @@ typedef struct _ETH_CS_802_LLC_SNAP_FRAME
 
 typedef struct _ETH_CS_ETH2_FRAME
 {
-	ETH_HEADER_STRUC EThHdr;
+	struct bcm_eth_header EThHdr;
 } __attribute__((packed)) ETH_CS_ETH2_FRAME;
 
 #define ETHERNET_FRAMETYPE_IPV4		ntohs(0x0800)
diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h
index b80b806..3c8cc5b 100644
--- a/drivers/staging/bcm/Prototypes.h
+++ b/drivers/staging/bcm/Prototypes.h
@@ -1,172 +1,172 @@
 #ifndef _PROTOTYPES_H_
 #define _PROTOTYPES_H_
 
-VOID LinkControlResponseMessage(PMINI_ADAPTER Adapter, PUCHAR pucBuffer);
+VOID LinkControlResponseMessage(struct bcm_mini_adapter *Adapter, PUCHAR pucBuffer);
 
-VOID StatisticsResponse(PMINI_ADAPTER Adapter,PVOID pvBuffer);
+VOID StatisticsResponse(struct bcm_mini_adapter *Adapter,PVOID pvBuffer);
 
-VOID IdleModeResponse(PMINI_ADAPTER Adapter,PUINT puiBuffer);
+VOID IdleModeResponse(struct bcm_mini_adapter *Adapter,PUINT puiBuffer);
 
-int control_packet_handler	(PMINI_ADAPTER Adapter);
+int control_packet_handler	(struct bcm_mini_adapter *Adapter);
 
-VOID DeleteAllClassifiersForSF(PMINI_ADAPTER Adapter,UINT uiSearchRuleIndex);
+VOID DeleteAllClassifiersForSF(struct bcm_mini_adapter *Adapter,UINT uiSearchRuleIndex);
 
-VOID flush_all_queues(PMINI_ADAPTER Adapter);
+VOID flush_all_queues(struct bcm_mini_adapter *Adapter);
 
-int register_control_device_interface(PMINI_ADAPTER ps_adapter);
+int register_control_device_interface(struct bcm_mini_adapter *ps_adapter);
 
-void unregister_control_device_interface(PMINI_ADAPTER Adapter);
+void unregister_control_device_interface(struct bcm_mini_adapter *Adapter);
 
-INT CopyBufferToControlPacket(PMINI_ADAPTER Adapter,/**<Logical Adapter*/
+INT CopyBufferToControlPacket(struct bcm_mini_adapter *Adapter,/**<Logical Adapter*/
 									  PVOID ioBuffer/**<Control Packet Buffer*/
 									  );
 
-VOID SortPackInfo(PMINI_ADAPTER Adapter);
+VOID SortPackInfo(struct bcm_mini_adapter *Adapter);
 
-VOID SortClassifiers(PMINI_ADAPTER Adapter);
+VOID SortClassifiers(struct bcm_mini_adapter *Adapter);
 
-VOID flush_all_queues(PMINI_ADAPTER Adapter);
+VOID flush_all_queues(struct bcm_mini_adapter *Adapter);
 
-VOID PruneQueueAllSF(PMINI_ADAPTER Adapter);
+VOID PruneQueueAllSF(struct bcm_mini_adapter *Adapter);
 
-INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid);
+INT SearchSfid(struct bcm_mini_adapter *Adapter,UINT uiSfid);
 
-USHORT ClassifyPacket(PMINI_ADAPTER Adapter,struct sk_buff* skb);
+USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter,struct sk_buff* skb);
 
-BOOLEAN MatchSrcPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
-BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
-BOOLEAN MatchProtocol(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucProtocol);
+BOOLEAN MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushSrcPort);
+BOOLEAN MatchDestPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushSrcPort);
+BOOLEAN MatchProtocol(struct bcm_classifier_rule *pstClassifierRule,UCHAR ucProtocol);
 
 
-INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
+INT SetupNextSend(struct bcm_mini_adapter *Adapter, /**<Logical Adapter*/
 					struct sk_buff *Packet, /**<data buffer*/
 					USHORT Vcid)	;
 
-VOID LinkMessage(PMINI_ADAPTER Adapter);
+VOID LinkMessage(struct bcm_mini_adapter *Adapter);
 
-VOID transmit_packets(PMINI_ADAPTER Adapter);
+VOID transmit_packets(struct bcm_mini_adapter *Adapter);
 
-INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
+INT SendControlPacket(struct bcm_mini_adapter *Adapter, /**<Logical Adapter*/
 							char *pControlPacket/**<Control Packet*/
 							);
 
 
-int register_networkdev(PMINI_ADAPTER Adapter);
-void unregister_networkdev(PMINI_ADAPTER Adapter);
+int register_networkdev(struct bcm_mini_adapter *Adapter);
+void unregister_networkdev(struct bcm_mini_adapter *Adapter);
 
-INT AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter);
+INT AllocAdapterDsxBuffer(struct bcm_mini_adapter *Adapter);
 
-VOID AdapterFree(PMINI_ADAPTER Adapter);
+VOID AdapterFree(struct bcm_mini_adapter *Adapter);
 
-INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter);
+INT FreeAdapterDsxBuffer(struct bcm_mini_adapter *Adapter);
 
-int tx_pkt_handler(PMINI_ADAPTER Adapter);
+int tx_pkt_handler(struct bcm_mini_adapter *Adapter);
 
-int  reset_card_proc(PMINI_ADAPTER Adapter );
+int  reset_card_proc(struct bcm_mini_adapter *Adapter );
 
-int run_card_proc(PMINI_ADAPTER Adapter );
+int run_card_proc(struct bcm_mini_adapter *Adapter );
 
-int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter);
+int InitCardAndDownloadFirmware(struct bcm_mini_adapter *ps_adapter);
 
 
-INT ReadMacAddressFromNVM(PMINI_ADAPTER Adapter);
+INT ReadMacAddressFromNVM(struct bcm_mini_adapter *Adapter);
 
-int register_control_device_interface(PMINI_ADAPTER ps_adapter);
+int register_control_device_interface(struct bcm_mini_adapter *ps_adapter);
 
-void DumpPackInfo(PMINI_ADAPTER Adapter);
+void DumpPackInfo(struct bcm_mini_adapter *Adapter);
 
-int rdm(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t size);
+int rdm(struct bcm_mini_adapter *Adapter, UINT uiAddress, PCHAR pucBuff, size_t size);
 
-int wrm(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t size);
+int wrm(struct bcm_mini_adapter *Adapter, UINT uiAddress, PCHAR pucBuff, size_t size);
 
-int wrmalt (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
+int wrmalt (struct bcm_mini_adapter *Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
 
-int rdmalt (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
+int rdmalt (struct bcm_mini_adapter *Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
 
-int get_dsx_sf_data_to_application(PMINI_ADAPTER Adapter, UINT uiSFId, void __user * user_buffer);
+int get_dsx_sf_data_to_application(struct bcm_mini_adapter *Adapter, UINT uiSFId, void __user * user_buffer);
 
-void SendIdleModeResponse(PMINI_ADAPTER Adapter);
+void SendIdleModeResponse(struct bcm_mini_adapter *Adapter);
 
 
-int  ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *buf);
-void GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *ioBuffer, PPER_TARANG_DATA pTarang);
-void beceem_parse_target_struct(PMINI_ADAPTER Adapter);
+int  ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, S_MIBS_HOST_STATS_MIBS *buf);
+void GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *ioBuffer, struct bcm_tarang_data *pTarang);
+void beceem_parse_target_struct(struct bcm_mini_adapter *Adapter);
 
-int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo);
+int bcm_ioctl_fw_download(struct bcm_mini_adapter *Adapter, struct bcm_firmware_info *psFwInfo);
 
-void CopyMIBSExtendedSFParameters(PMINI_ADAPTER Adapter,
+void CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter,
 		CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex);
 
-VOID ResetCounters(PMINI_ADAPTER Adapter);
+VOID ResetCounters(struct bcm_mini_adapter *Adapter);
 
-int InitLedSettings(PMINI_ADAPTER Adapter);
+int InitLedSettings(struct bcm_mini_adapter *Adapter);
 
-S_CLASSIFIER_RULE *GetFragIPClsEntry(PMINI_ADAPTER Adapter,USHORT usIpIdentification,ULONG SrcIP);
+struct bcm_classifier_rule *GetFragIPClsEntry(struct bcm_mini_adapter *Adapter,USHORT usIpIdentification,ULONG SrcIP);
 
-void AddFragIPClsEntry(PMINI_ADAPTER Adapter,PS_FRAGMENTED_PACKET_INFO psFragPktInfo);
+void AddFragIPClsEntry(struct bcm_mini_adapter *Adapter, struct bcm_fragmented_packet_info *psFragPktInfo);
 
-void DelFragIPClsEntry(PMINI_ADAPTER Adapter,USHORT usIpIdentification,ULONG SrcIp);
+void DelFragIPClsEntry(struct bcm_mini_adapter *Adapter,USHORT usIpIdentification,ULONG SrcIp);
 
-void update_per_cid_rx (PMINI_ADAPTER Adapter);
+void update_per_cid_rx (struct bcm_mini_adapter *Adapter);
 
-void update_per_sf_desc_cnts( PMINI_ADAPTER Adapter);
+void update_per_sf_desc_cnts( struct bcm_mini_adapter *Adapter);
 
-void ClearTargetDSXBuffer(PMINI_ADAPTER Adapter,B_UINT16 TID,BOOLEAN bFreeAll);
+void ClearTargetDSXBuffer(struct bcm_mini_adapter *Adapter,B_UINT16 TID,BOOLEAN bFreeAll);
 
 
-void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex);
+void flush_queue(struct bcm_mini_adapter *Adapter, UINT iQIndex);
 
 
 INT flushAllAppQ(VOID);
 
 
 INT BeceemEEPROMBulkRead(
-	PMINI_ADAPTER Adapter,
+	struct bcm_mini_adapter *Adapter,
 	PUINT pBuffer,
 	UINT uiOffset,
 	UINT uiNumBytes);
 
 
 
-INT WriteBeceemEEPROM(PMINI_ADAPTER Adapter,UINT uiEEPROMOffset, UINT uiData);
+INT WriteBeceemEEPROM(struct bcm_mini_adapter *Adapter,UINT uiEEPROMOffset, UINT uiData);
 
-INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter);
+INT PropagateCalParamsFromFlashToMemory(struct bcm_mini_adapter *Adapter);
 
 
 INT BeceemEEPROMBulkWrite(
-	PMINI_ADAPTER Adapter,
+	struct bcm_mini_adapter *Adapter,
 	PUCHAR pBuffer,
 	UINT uiOffset,
 	UINT uiNumBytes,
 	BOOLEAN bVerify);
 
 
-INT ReadBeceemEEPROM(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData);
+INT ReadBeceemEEPROM(struct bcm_mini_adapter *Adapter,UINT dwAddress, UINT *pdwData);
 
 
 INT BeceemNVMRead(
-	PMINI_ADAPTER Adapter,
+	struct bcm_mini_adapter *Adapter,
 	PUINT pBuffer,
 	UINT uiOffset,
 	UINT uiNumBytes);
 
 INT BeceemNVMWrite(
-	PMINI_ADAPTER Adapter,
+	struct bcm_mini_adapter *Adapter,
 	PUINT pBuffer,
 	UINT uiOffset,
 	UINT uiNumBytes,
 	BOOLEAN bVerify);
 
 
-INT BcmInitNVM(PMINI_ADAPTER Adapter);
+INT BcmInitNVM(struct bcm_mini_adapter *Adapter);
 
-INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize);
-BOOLEAN IsSectionExistInFlash(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section);
+INT BcmUpdateSectorSize(struct bcm_mini_adapter *Adapter,UINT uiSectorSize);
+BOOLEAN IsSectionExistInFlash(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL section);
 
-INT BcmGetFlash2xSectionalBitMap(PMINI_ADAPTER Adapter, PFLASH2X_BITMAP psFlash2xBitMap);
+INT BcmGetFlash2xSectionalBitMap(struct bcm_mini_adapter *Adapter, PFLASH2X_BITMAP psFlash2xBitMap);
 
 INT BcmFlash2xBulkWrite(
-	PMINI_ADAPTER Adapter,
+	struct bcm_mini_adapter *Adapter,
 	PUINT pBuffer,
 	FLASH2X_SECTION_VAL eFlashSectionVal,
 	UINT uiOffset,
@@ -174,45 +174,45 @@ INT BcmFlash2xBulkWrite(
 	UINT bVerify);
 
 INT BcmFlash2xBulkRead(
-	PMINI_ADAPTER Adapter,
+	struct bcm_mini_adapter *Adapter,
 	PUINT pBuffer,
 	FLASH2X_SECTION_VAL eFlashSectionVal,
 	UINT uiOffsetWithinSectionVal,
 	UINT uiNumBytes);
 
-INT BcmGetSectionValStartOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlashSectionVal);
+INT BcmGetSectionValStartOffset(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlashSectionVal);
 
-INT BcmSetActiveSection(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectVal);
-INT BcmAllocFlashCSStructure(PMINI_ADAPTER psAdapter);
-INT BcmDeAllocFlashCSStructure(PMINI_ADAPTER psAdapter);
+INT BcmSetActiveSection(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlash2xSectVal);
+INT BcmAllocFlashCSStructure(struct bcm_mini_adapter *psAdapter);
+INT BcmDeAllocFlashCSStructure(struct bcm_mini_adapter *psAdapter);
 
-INT BcmCopyISO(PMINI_ADAPTER Adapter, FLASH2X_COPY_SECTION sCopySectStrut);
-INT BcmFlash2xCorruptSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
-INT BcmFlash2xWriteSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlashSectionVal);
-INT	validateFlash2xReadWrite(PMINI_ADAPTER Adapter, PFLASH2X_READWRITE psFlash2xReadWrite);
-INT IsFlash2x(PMINI_ADAPTER Adapter);
-INT	BcmCopySection(PMINI_ADAPTER Adapter,
+INT BcmCopyISO(struct bcm_mini_adapter *Adapter, FLASH2X_COPY_SECTION sCopySectStrut);
+INT BcmFlash2xCorruptSig(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+INT BcmFlash2xWriteSig(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlashSectionVal);
+INT	validateFlash2xReadWrite(struct bcm_mini_adapter *Adapter, PFLASH2X_READWRITE psFlash2xReadWrite);
+INT IsFlash2x(struct bcm_mini_adapter *Adapter);
+INT	BcmCopySection(struct bcm_mini_adapter *Adapter,
 						FLASH2X_SECTION_VAL SrcSection,
 						FLASH2X_SECTION_VAL DstSection,
 						UINT offset,
 						UINT numOfBytes);
 
 
-BOOLEAN IsNonCDLessDevice(PMINI_ADAPTER Adapter);
+BOOLEAN IsNonCDLessDevice(struct bcm_mini_adapter *Adapter);
 
 
-VOID OverrideServiceFlowParams(PMINI_ADAPTER Adapter,PUINT puiBuffer);
+VOID OverrideServiceFlowParams(struct bcm_mini_adapter *Adapter,PUINT puiBuffer);
 
-int wrmaltWithLock (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
-int rdmaltWithLock (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
+int wrmaltWithLock (struct bcm_mini_adapter *Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
+int rdmaltWithLock (struct bcm_mini_adapter *Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
 
-int wrmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t size);
-INT buffDnldVerify(PMINI_ADAPTER Adapter, unsigned char *mappedbuffer, unsigned int u32FirmwareLength,
+int wrmWithLock(struct bcm_mini_adapter *Adapter, UINT uiAddress, PCHAR pucBuff, size_t size);
+INT buffDnldVerify(struct bcm_mini_adapter *Adapter, unsigned char *mappedbuffer, unsigned int u32FirmwareLength,
 		unsigned long u32StartingAddress);
 
 
 VOID putUsbSuspend(struct work_struct *work);
-BOOLEAN IsReqGpioIsLedInNVM(PMINI_ADAPTER Adapter, UINT gpios);
+BOOLEAN IsReqGpioIsLedInNVM(struct bcm_mini_adapter *Adapter, UINT gpios);
 
 
 #endif
diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c
index c97020f..1b857bd 100644
--- a/drivers/staging/bcm/Qos.c
+++ b/drivers/staging/bcm/Qos.c
@@ -4,13 +4,13 @@ This file contains the routines related to Quality of Service.
 */
 #include "headers.h"
 
-static void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,PS_ETHCS_PKT_INFO pstEthCsPktInfo);
-static BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo,S_CLASSIFIER_RULE *pstClassifierRule, B_UINT8 EthCSCupport);
+static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter,PVOID pvEthPayload,PS_ETHCS_PKT_INFO pstEthCsPktInfo);
+static BOOLEAN EThCSClassifyPkt(struct bcm_mini_adapter *Adapter,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo,struct bcm_classifier_rule *pstClassifierRule, B_UINT8 EthCSCupport);
 
-static USHORT	IpVersion4(PMINI_ADAPTER Adapter, struct iphdr *iphd,
-			   S_CLASSIFIER_RULE *pstClassifierRule );
+static USHORT	IpVersion4(struct bcm_mini_adapter *Adapter, struct iphdr *iphd,
+			   struct bcm_classifier_rule *pstClassifierRule );
 
-static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex);
+static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex);
 
 
 /*******************************************************************
@@ -24,11 +24,11 @@ static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex);
 *
 * Returns     - TRUE(If address matches) else FAIL .
 *********************************************************************/
-BOOLEAN MatchSrcIpAddress(S_CLASSIFIER_RULE *pstClassifierRule,ULONG ulSrcIP)
+BOOLEAN MatchSrcIpAddress(struct bcm_classifier_rule *pstClassifierRule,ULONG ulSrcIP)
 {
     UCHAR 	ucLoopIndex=0;
 
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+    struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
     ulSrcIP=ntohl(ulSrcIP);
     if(0 == pstClassifierRule->ucIPSourceAddressLength)
@@ -58,10 +58,10 @@ BOOLEAN MatchSrcIpAddress(S_CLASSIFIER_RULE *pstClassifierRule,ULONG ulSrcIP)
 *
 * Returns     - TRUE(If address matches) else FAIL .
 *********************************************************************/
-BOOLEAN MatchDestIpAddress(S_CLASSIFIER_RULE *pstClassifierRule,ULONG ulDestIP)
+BOOLEAN MatchDestIpAddress(struct bcm_classifier_rule *pstClassifierRule,ULONG ulDestIP)
 {
 	UCHAR 	ucLoopIndex=0;
-    PMINI_ADAPTER	Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 	ulDestIP=ntohl(ulDestIP);
     if(0 == pstClassifierRule->ucIPDestinationAddressLength)
@@ -91,10 +91,10 @@ BOOLEAN MatchDestIpAddress(S_CLASSIFIER_RULE *pstClassifierRule,ULONG ulDestIP)
 *
 * Returns     - TRUE(If address matches) else FAIL.
 **************************************************************************/
-BOOLEAN MatchTos(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucTypeOfService)
+BOOLEAN MatchTos(struct bcm_classifier_rule *pstClassifierRule,UCHAR ucTypeOfService)
 {
 
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
     if( 3 != pstClassifierRule->ucIPTypeOfServiceLength )
        	return TRUE;
 
@@ -117,10 +117,10 @@ BOOLEAN MatchTos(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucTypeOfService)
 *
 * Returns     - TRUE(If address matches) else FAIL.
 ****************************************************************************/
-BOOLEAN MatchProtocol(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucProtocol)
+BOOLEAN MatchProtocol(struct bcm_classifier_rule *pstClassifierRule,UCHAR ucProtocol)
 {
    	UCHAR 	ucLoopIndex=0;
-	PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	if(0 == pstClassifierRule->ucProtocolLength)
       	return TRUE;
 	for(ucLoopIndex=0;ucLoopIndex<pstClassifierRule->ucProtocolLength;ucLoopIndex++)
@@ -146,11 +146,11 @@ BOOLEAN MatchProtocol(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucProtocol)
 *
 * Returns     - TRUE(If address matches) else FAIL.
 ***************************************************************************/
-BOOLEAN MatchSrcPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort)
+BOOLEAN MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushSrcPort)
 {
     	UCHAR 	ucLoopIndex=0;
 
-		PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 
     	if(0 == pstClassifierRule->ucSrcPortRangeLength)
@@ -178,10 +178,10 @@ BOOLEAN MatchSrcPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort)
 *
 * Returns     - TRUE(If address matches) else FAIL.
 ***************************************************************************/
-BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushDestPort)
+BOOLEAN MatchDestPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushDestPort)
 {
     	UCHAR 	ucLoopIndex=0;
-		PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
     	if(0 == pstClassifierRule->ucDestPortRangeLength)
         	return TRUE;
@@ -204,9 +204,9 @@ BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushDestPort)
 Compares IPV4 Ip address and port number
 @return Queue Index.
 */
-static USHORT	IpVersion4(PMINI_ADAPTER Adapter,
+static USHORT	IpVersion4(struct bcm_mini_adapter *Adapter,
 			   struct iphdr *iphd,
-			   S_CLASSIFIER_RULE *pstClassifierRule )
+			   struct bcm_classifier_rule *pstClassifierRule)
 {
 	xporthdr     		*xprt_hdr=NULL;
 	BOOLEAN	bClassificationSucceed=FALSE;
@@ -302,7 +302,7 @@ static USHORT	IpVersion4(PMINI_ADAPTER Adapter,
 	return bClassificationSucceed;
 }
 
-VOID PruneQueueAllSF(PMINI_ADAPTER Adapter)
+VOID PruneQueueAllSF(struct bcm_mini_adapter *Adapter)
 {
 	UINT iIndex = 0;
 
@@ -323,7 +323,7 @@ is less than number of bytes in the queue. If so -
 drops packets from the Head till the number of bytes is
 less than or equal to max queue size for the queue.
 */
-static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex)
+static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex)
 {
 	struct sk_buff* PacketToDrop=NULL;
 	struct net_device_stats *netstats;
@@ -392,7 +392,7 @@ static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex)
 	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "<=====");
 }
 
-VOID flush_all_queues(PMINI_ADAPTER Adapter)
+VOID flush_all_queues(struct bcm_mini_adapter *Adapter)
 {
 	INT		iQIndex;
 	UINT	uiTotalPacketLength;
@@ -442,10 +442,10 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter)
 	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "<=====");
 }
 
-USHORT ClassifyPacket(PMINI_ADAPTER Adapter,struct sk_buff* skb)
+USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter,struct sk_buff* skb)
 {
 	INT			uiLoopIndex=0;
-	S_CLASSIFIER_RULE *pstClassifierRule = NULL;
+	struct bcm_classifier_rule *pstClassifierRule = NULL;
 	S_ETHCS_PKT_INFO stEthCsPktInfo;
 	PVOID pvEThPayload = NULL;
 	struct iphdr 		*pIpHeader = NULL;
@@ -631,7 +631,7 @@ USHORT ClassifyPacket(PMINI_ADAPTER Adapter,struct sk_buff* skb)
 		if(bFragmentedPkt && (usCurrFragment == 0))
 		{
 			//First Fragment of Fragmented Packet. Create Frag CLS Entry
-			S_FRAGMENTED_PACKET_INFO stFragPktInfo;
+			struct bcm_fragmented_packet_info stFragPktInfo;
 			stFragPktInfo.bUsed = TRUE;
 			stFragPktInfo.ulSrcIpAddress = pIpHeader->saddr;
 			stFragPktInfo.usIpIdentification = pIpHeader->id;
@@ -649,10 +649,10 @@ USHORT ClassifyPacket(PMINI_ADAPTER Adapter,struct sk_buff* skb)
 		return INVALID_QUEUE_INDEX;
 }
 
-static BOOLEAN EthCSMatchSrcMACAddress(S_CLASSIFIER_RULE *pstClassifierRule,PUCHAR Mac)
+static BOOLEAN EthCSMatchSrcMACAddress(struct bcm_classifier_rule *pstClassifierRule,PUCHAR Mac)
 {
 	UINT i=0;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	if(pstClassifierRule->ucEthCSSrcMACLen==0)
 		return TRUE;
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s \n",__FUNCTION__);
@@ -666,10 +666,10 @@ static BOOLEAN EthCSMatchSrcMACAddress(S_CLASSIFIER_RULE *pstClassifierRule,PUCH
 	return TRUE;
 }
 
-static BOOLEAN EthCSMatchDestMACAddress(S_CLASSIFIER_RULE *pstClassifierRule,PUCHAR Mac)
+static BOOLEAN EthCSMatchDestMACAddress(struct bcm_classifier_rule *pstClassifierRule,PUCHAR Mac)
 {
 	UINT i=0;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	if(pstClassifierRule->ucEthCSDestMACLen==0)
 		return TRUE;
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s \n",__FUNCTION__);
@@ -683,9 +683,9 @@ static BOOLEAN EthCSMatchDestMACAddress(S_CLASSIFIER_RULE *pstClassifierRule,PUC
 	return TRUE;
 }
 
-static BOOLEAN EthCSMatchEThTypeSAP(S_CLASSIFIER_RULE *pstClassifierRule,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo)
+static BOOLEAN EthCSMatchEThTypeSAP(struct bcm_classifier_rule *pstClassifierRule,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo)
 {
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 	if((pstClassifierRule->ucEtherTypeLen==0)||
 		(pstClassifierRule->au8EthCSEtherType[0] == 0))
 		return TRUE;
@@ -718,12 +718,12 @@ static BOOLEAN EthCSMatchEThTypeSAP(S_CLASSIFIER_RULE *pstClassifierRule,struct
 
 }
 
-static BOOLEAN EthCSMatchVLANRules(S_CLASSIFIER_RULE *pstClassifierRule,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo)
+static BOOLEAN EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo)
 {
 	BOOLEAN bClassificationSucceed = FALSE;
 	USHORT usVLANID;
 	B_UINT8 uPriority = 0;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s  CLS UserPrio:%x CLS VLANID:%x\n",__FUNCTION__,ntohs(*((USHORT *)pstClassifierRule->usUserPriority)),pstClassifierRule->usVLANID);
 
@@ -733,7 +733,7 @@ static BOOLEAN EthCSMatchVLANRules(S_CLASSIFIER_RULE *pstClassifierRule,struct s
 		if(pstEthCsPktInfo->eNwpktEthFrameType!=eEth802QVLANFrame)
 				return FALSE;
 
-		uPriority = (ntohs(*(USHORT *)(skb->data + sizeof(ETH_HEADER_STRUC))) & 0xF000) >> 13;
+		uPriority = (ntohs(*(USHORT *)(skb->data + sizeof(struct bcm_eth_header))) & 0xF000) >> 13;
 
 		if((uPriority >= pstClassifierRule->usUserPriority[0]) && (uPriority <= pstClassifierRule->usUserPriority[1]))
 				bClassificationSucceed = TRUE;
@@ -751,7 +751,7 @@ static BOOLEAN EthCSMatchVLANRules(S_CLASSIFIER_RULE *pstClassifierRule,struct s
 		if(pstEthCsPktInfo->eNwpktEthFrameType!=eEth802QVLANFrame)
 				return FALSE;
 
-		usVLANID = ntohs(*(USHORT *)(skb->data + sizeof(ETH_HEADER_STRUC))) & 0xFFF;
+		usVLANID = ntohs(*(USHORT *)(skb->data + sizeof(struct bcm_eth_header))) & 0xFFF;
 
 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s  Pkt VLANID %x Priority: %d\n",__FUNCTION__,usVLANID, uPriority);
 
@@ -768,18 +768,18 @@ static BOOLEAN EthCSMatchVLANRules(S_CLASSIFIER_RULE *pstClassifierRule,struct s
 }
 
 
-static BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,
+static BOOLEAN EThCSClassifyPkt(struct bcm_mini_adapter *Adapter,struct sk_buff* skb,
 				PS_ETHCS_PKT_INFO pstEthCsPktInfo,
-				S_CLASSIFIER_RULE *pstClassifierRule,
+				struct bcm_classifier_rule *pstClassifierRule,
 				B_UINT8 EthCSCupport)
 {
 	BOOLEAN bClassificationSucceed = FALSE;
-	bClassificationSucceed = EthCSMatchSrcMACAddress(pstClassifierRule,((ETH_HEADER_STRUC *)(skb->data))->au8SourceAddress);
+	bClassificationSucceed = EthCSMatchSrcMACAddress(pstClassifierRule,((struct bcm_eth_header *)(skb->data))->au8SourceAddress);
 	if(!bClassificationSucceed)
 		return FALSE;
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "ETH CS SrcMAC Matched\n");
 
-	bClassificationSucceed = EthCSMatchDestMACAddress(pstClassifierRule,((ETH_HEADER_STRUC*)(skb->data))->au8DestinationAddress);
+	bClassificationSucceed = EthCSMatchDestMACAddress(pstClassifierRule,((struct bcm_eth_header *)(skb->data))->au8DestinationAddress);
 	if(!bClassificationSucceed)
 		return FALSE;
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "ETH CS DestMAC Matched\n");
@@ -801,10 +801,10 @@ static BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,
 	return bClassificationSucceed;
 }
 
-static void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,
+static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter,PVOID pvEthPayload,
 			    PS_ETHCS_PKT_INFO pstEthCsPktInfo)
 {
-	USHORT u16Etype = ntohs(((ETH_HEADER_STRUC*)pvEthPayload)->u16Etype);
+	USHORT u16Etype = ntohs(((struct bcm_eth_header *)pvEthPayload)->u16Etype);
 
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCSGetPktInfo : Eth Hdr Type : %X\n",u16Etype);
 	if(u16Etype > 0x5dc)
@@ -845,7 +845,7 @@ static void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,
 	else
 		pstEthCsPktInfo->eNwpktIPFrameType = eNonIPPacket;
 
-	pstEthCsPktInfo->usEtherType = ((ETH_HEADER_STRUC*)pvEthPayload)->u16Etype;
+	pstEthCsPktInfo->usEtherType = ((struct bcm_eth_header *)pvEthPayload)->u16Etype;
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCsPktInfo->eNwpktIPFrameType : %x\n",pstEthCsPktInfo->eNwpktIPFrameType);
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCsPktInfo->eNwpktEthFrameType : %x\n",pstEthCsPktInfo->eNwpktEthFrameType);
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCsPktInfo->usEtherType : %x\n",pstEthCsPktInfo->usEtherType);
diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c
index d5e4a74..5e603ce 100644
--- a/drivers/staging/bcm/Transmit.c
+++ b/drivers/staging/bcm/Transmit.c
@@ -41,9 +41,9 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53
 This function dispatches control packet to the h/w interface
 @return zero(success) or -ve value(failure)
 */
-INT SendControlPacket(PMINI_ADAPTER Adapter, char *pControlPacket)
+INT SendControlPacket(struct bcm_mini_adapter *Adapter, char *pControlPacket)
 {
-	PLEADER PLeader = (PLEADER)pControlPacket;
+	struct bcm_leader *PLeader = (struct bcm_leader *)pControlPacket;
 
 	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
 	if(!pControlPacket || !Adapter)
@@ -84,13 +84,13 @@ This function despatches the IP packets with the given vcid
 to the target via the host h/w interface.
 @return  zero(success) or -ve value(failure)
 */
-INT SetupNextSend(PMINI_ADAPTER Adapter,  struct sk_buff *Packet, USHORT Vcid)
+INT SetupNextSend(struct bcm_mini_adapter *Adapter,  struct sk_buff *Packet, USHORT Vcid)
 {
 	int		status=0;
 	BOOLEAN bHeaderSupressionEnabled = FALSE;
 	B_UINT16            uiClassifierRuleID;
 	u16	QueueIndex = skb_get_queue_mapping(Packet);
-	LEADER Leader={0};
+	struct bcm_leader Leader={0};
 
 	if(Packet->len > MAX_DEVICE_DESC_SIZE)
 	{
@@ -143,7 +143,7 @@ INT SetupNextSend(PMINI_ADAPTER Adapter,  struct sk_buff *Packet, USHORT Vcid)
 	else
 	{
 		Leader.PLength = Packet->len - ETH_HLEN;
-		memcpy((LEADER*)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
+		memcpy((struct bcm_leader *)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
 	}
 
 	status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
@@ -180,7 +180,7 @@ errExit:
 	return status;
 }
 
-static int tx_pending(PMINI_ADAPTER Adapter)
+static int tx_pending(struct bcm_mini_adapter *Adapter)
 {
 	return (atomic_read(&Adapter->TxPktAvail)
 		&& MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc))
@@ -191,7 +191,7 @@ static int tx_pending(PMINI_ADAPTER Adapter)
 @ingroup tx_functions
 Transmit thread
 */
-int tx_pkt_handler(PMINI_ADAPTER Adapter  /**< pointer to adapter object*/
+int tx_pkt_handler(struct bcm_mini_adapter *Adapter  /**< pointer to adapter object*/
 				)
 {
 	int status = 0;
diff --git a/drivers/staging/bcm/cntrl_SignalingInterface.h b/drivers/staging/bcm/cntrl_SignalingInterface.h
index ab13180..7619e4b 100644
--- a/drivers/staging/bcm/cntrl_SignalingInterface.h
+++ b/drivers/staging/bcm/cntrl_SignalingInterface.h
@@ -117,7 +117,7 @@ typedef struct _stPhsRuleSI {
     B_UINT8                         u8PHSM[MAX_PHS_LENGTHS];
 	/**  8bit Total number of bytes to be suppressed for the Service Flow*/
     B_UINT8                         u8PHSS;
-	/**  8bit Indicates whether or not Packet Header contents need to be verified prior to supression */
+	/**  8bit Indicates whether or not Packet Header contents need to be verified prior to suppression */
     B_UINT8                         u8PHSV;
 	/**  Vendor Specific PHS param Length Of The Service Flow*/
     B_UINT8                         u8VendorSpecificPHSParamsLength;
diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c
index 101c4e3..08d13a4 100644
--- a/drivers/staging/bcm/hostmibs.c
+++ b/drivers/staging/bcm/hostmibs.c
@@ -9,7 +9,7 @@
 
 #include "headers.h"
 
-INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *pstHostMibs)
+INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, S_MIBS_HOST_STATS_MIBS *pstHostMibs)
 {
 	S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
 	S_PHS_RULE *pstPhsRule = NULL;
@@ -94,14 +94,14 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *pstHostMib
 	return STATUS_SUCCESS;
 }
 
-VOID GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *pstHostMibs, const PPER_TARANG_DATA pTarang)
+VOID GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *pstHostMibs, struct bcm_tarang_data *pTarang)
 {
 	memcpy(&(pstHostMibs->stDroppedAppCntrlMsgs),
 	       &(pTarang->stDroppedAppCntrlMsgs),
 	       sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES));
 }
 
-VOID CopyMIBSExtendedSFParameters(PMINI_ADAPTER Adapter, CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex)
+VOID CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter, CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex)
 {
 	S_MIBS_EXTSERVICEFLOW_PARAMETERS *t = &Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable;
 
diff --git a/drivers/staging/bcm/led_control.c b/drivers/staging/bcm/led_control.c
index c7f4886..252a1b3 100644
--- a/drivers/staging/bcm/led_control.c
+++ b/drivers/staging/bcm/led_control.c
@@ -13,7 +13,7 @@ static B_UINT16 CFG_CalculateChecksum(B_UINT8 *pu8Buffer, B_UINT32 u32Size)
 	return u16CheckSum;
 }
 
-BOOLEAN IsReqGpioIsLedInNVM(PMINI_ADAPTER Adapter, UINT gpios)
+BOOLEAN IsReqGpioIsLedInNVM(struct bcm_mini_adapter *Adapter, UINT gpios)
 {
 	INT Status;
 	Status = (Adapter->gpioBitMap & gpios) ^ gpios;
@@ -23,7 +23,7 @@ BOOLEAN IsReqGpioIsLedInNVM(PMINI_ADAPTER Adapter, UINT gpios)
 		return TRUE;
 }
 
-static INT LED_Blink(PMINI_ADAPTER Adapter, UINT GPIO_Num, UCHAR uiLedIndex,
+static INT LED_Blink(struct bcm_mini_adapter *Adapter, UINT GPIO_Num, UCHAR uiLedIndex,
 		ULONG timeout, INT num_of_time, LedEventInfo_t currdriverstate)
 {
 	int Status = STATUS_SUCCESS;
@@ -95,7 +95,7 @@ static INT ScaleRateofTransfer(ULONG rate)
 
 
 
-static INT LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx,
+static INT LED_Proportional_Blink(struct bcm_mini_adapter *Adapter, UCHAR GPIO_Num_tx,
 		UCHAR uiTxLedIndex, UCHAR GPIO_Num_rx, UCHAR uiRxLedIndex,
 		LedEventInfo_t currdriverstate)
 {
@@ -261,7 +261,7 @@ static INT LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx,
  *  <OSAL_STATUS_CODE>
  * -----------------------------------------------------------------------------
  */
-static INT ValidateDSDParamsChecksum(PMINI_ADAPTER Adapter, ULONG ulParamOffset,
+static INT ValidateDSDParamsChecksum(struct bcm_mini_adapter *Adapter, ULONG ulParamOffset,
 					USHORT usParamLen)
 {
 	INT Status = STATUS_SUCCESS;
@@ -347,7 +347,7 @@ exit:
  *  <OSAL_STATUS_CODE>
  * -----------------------------------------------------------------------------
  */
-static INT ValidateHWParmStructure(PMINI_ADAPTER Adapter, ULONG ulHwParamOffset)
+static INT ValidateHWParmStructure(struct bcm_mini_adapter *Adapter, ULONG ulHwParamOffset)
 {
 
 	INT Status = STATUS_SUCCESS;
@@ -371,7 +371,7 @@ static INT ValidateHWParmStructure(PMINI_ADAPTER Adapter, ULONG ulHwParamOffset)
 	return Status;
 } /* ValidateHWParmStructure() */
 
-static int ReadLEDInformationFromEEPROM(PMINI_ADAPTER Adapter,
+static int ReadLEDInformationFromEEPROM(struct bcm_mini_adapter *Adapter,
 					UCHAR GPIO_Array[])
 {
 	int Status = STATUS_SUCCESS;
@@ -477,7 +477,7 @@ static int ReadLEDInformationFromEEPROM(PMINI_ADAPTER Adapter,
 }
 
 
-static int ReadConfigFileStructure(PMINI_ADAPTER Adapter,
+static int ReadConfigFileStructure(struct bcm_mini_adapter *Adapter,
 					BOOLEAN *bEnableThread)
 {
 	int Status = STATUS_SUCCESS;
@@ -580,7 +580,7 @@ static int ReadConfigFileStructure(PMINI_ADAPTER Adapter,
  *
  * -----------------------------------------------------------------------------
  */
-static VOID LedGpioInit(PMINI_ADAPTER Adapter)
+static VOID LedGpioInit(struct bcm_mini_adapter *Adapter)
 {
 	UINT uiResetValue = 0;
 	UINT uiIndex      = 0;
@@ -605,7 +605,7 @@ static VOID LedGpioInit(PMINI_ADAPTER Adapter)
 	Adapter->LEDInfo.bIdle_led_off = FALSE;
 }
 
-static INT BcmGetGPIOPinInfo(PMINI_ADAPTER Adapter, UCHAR *GPIO_num_tx,
+static INT BcmGetGPIOPinInfo(struct bcm_mini_adapter *Adapter, UCHAR *GPIO_num_tx,
 		UCHAR *GPIO_num_rx, UCHAR *uiLedTxIndex, UCHAR *uiLedRxIndex,
 		LedEventInfo_t currdriverstate)
 {
@@ -645,7 +645,7 @@ static INT BcmGetGPIOPinInfo(PMINI_ADAPTER Adapter, UCHAR *GPIO_num_tx,
 	}
 	return STATUS_SUCCESS;
 }
-static VOID LEDControlThread(PMINI_ADAPTER Adapter)
+static VOID LEDControlThread(struct bcm_mini_adapter *Adapter)
 {
 	UINT uiIndex = 0;
 	UCHAR GPIO_num = 0;
@@ -857,7 +857,7 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter)
 	Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_DISABLED;
 }
 
-int InitLedSettings(PMINI_ADAPTER Adapter)
+int InitLedSettings(struct bcm_mini_adapter *Adapter)
 {
 	int Status = STATUS_SUCCESS;
 	BOOLEAN bEnableThread = TRUE;
diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c
index 7d703cb..b179dba 100644
--- a/drivers/staging/bcm/nvm.c
+++ b/drivers/staging/bcm/nvm.c
@@ -2,195 +2,181 @@
 
 #define DWORD unsigned int
 
-static INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset);
-static INT BcmGetActiveDSD(PMINI_ADAPTER Adapter);
-static INT BcmGetActiveISO(PMINI_ADAPTER Adapter);
-static UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter);
-static INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter);
-static UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize);
-
-static VOID BcmValidateNvmType(PMINI_ADAPTER Adapter);
-static INT BcmGetNvmSize(PMINI_ADAPTER Adapter);
-static UINT BcmGetFlashSize(PMINI_ADAPTER Adapter);
-static NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter);
-
-static INT BcmGetSectionValEndOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
-
-static B_UINT8 IsOffsetWritable(PMINI_ADAPTER Adapter, UINT uiOffset);
-static INT IsSectionWritable(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL Section);
-static INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section);
-
-static INT ReadDSDPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd);
-static INT ReadDSDSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd);
-static INT ReadISOPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso);
-static INT ReadISOSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso);
-
-static INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
-static INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
-static INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiSectAlignAddr);
-static INT WriteToFlashWithoutSectorErase(PMINI_ADAPTER Adapter, PUINT pBuff,
-					  FLASH2X_SECTION_VAL eFlash2xSectionVal,
-					  UINT uiOffset, UINT uiNumBytes);
-static FLASH2X_SECTION_VAL getHighestPriDSD(PMINI_ADAPTER Adapter);
-static FLASH2X_SECTION_VAL getHighestPriISO(PMINI_ADAPTER Adapter);
-
-static INT BeceemFlashBulkRead(
-	PMINI_ADAPTER Adapter,
+static int BcmDoChipSelect(struct bcm_mini_adapter *Adapter, unsigned int offset);
+static int BcmGetActiveDSD(struct bcm_mini_adapter *Adapter);
+static int BcmGetActiveISO(struct bcm_mini_adapter *Adapter);
+static unsigned int BcmGetEEPROMSize(struct bcm_mini_adapter *Adapter);
+static int BcmGetFlashCSInfo(struct bcm_mini_adapter *Adapter);
+static unsigned int BcmGetFlashSectorSize(struct bcm_mini_adapter *Adapter, unsigned int FlashSectorSizeSig, unsigned int FlashSectorSize);
+
+static VOID BcmValidateNvmType(struct bcm_mini_adapter *Adapter);
+static int BcmGetNvmSize(struct bcm_mini_adapter *Adapter);
+static unsigned int BcmGetFlashSize(struct bcm_mini_adapter *Adapter);
+static NVM_TYPE BcmGetNvmType(struct bcm_mini_adapter *Adapter);
+
+static int BcmGetSectionValEndOffset(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+
+static B_UINT8 IsOffsetWritable(struct bcm_mini_adapter *Adapter, unsigned int uiOffset);
+static int IsSectionWritable(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL Section);
+static int IsSectionExistInVendorInfo(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL section);
+
+static int ReadDSDPriority(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL dsd);
+static int ReadDSDSignature(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL dsd);
+static int ReadISOPriority(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL iso);
+static int ReadISOSignature(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL iso);
+
+static int CorruptDSDSig(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+static int CorruptISOSig(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+static int SaveHeaderIfPresent(struct bcm_mini_adapter *Adapter, PUCHAR pBuff, unsigned int uiSectAlignAddr);
+static int WriteToFlashWithoutSectorErase(struct bcm_mini_adapter *Adapter, PUINT pBuff,
+					FLASH2X_SECTION_VAL eFlash2xSectionVal,
+					unsigned int uiOffset, unsigned int uiNumBytes);
+static FLASH2X_SECTION_VAL getHighestPriDSD(struct bcm_mini_adapter *Adapter);
+static FLASH2X_SECTION_VAL getHighestPriISO(struct bcm_mini_adapter *Adapter);
+
+static int BeceemFlashBulkRead(
+	struct bcm_mini_adapter *Adapter,
 	PUINT pBuffer,
-	UINT uiOffset,
-	UINT uiNumBytes);
+	unsigned int uiOffset,
+	unsigned int uiNumBytes);
 
-static INT BeceemFlashBulkWrite(
-	PMINI_ADAPTER Adapter,
+static int BeceemFlashBulkWrite(
+	struct bcm_mini_adapter *Adapter,
 	PUINT pBuffer,
-	UINT uiOffset,
-	UINT uiNumBytes,
+	unsigned int uiOffset,
+	unsigned int uiNumBytes,
 	BOOLEAN bVerify);
 
-static INT GetFlashBaseAddr(PMINI_ADAPTER Adapter);
+static int GetFlashBaseAddr(struct bcm_mini_adapter *Adapter);
 
-static INT ReadBeceemEEPROMBulk(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData, UINT dwNumData);
+static int ReadBeceemEEPROMBulk(struct bcm_mini_adapter *Adapter, unsigned int dwAddress, unsigned int *pdwData, unsigned int dwNumData);
 
-// Procedure:	ReadEEPROMStatusRegister
-//
-// Description: Reads the standard EEPROM Status Register.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-
-static UCHAR ReadEEPROMStatusRegister( PMINI_ADAPTER Adapter )
+/* Procedure:	ReadEEPROMStatusRegister
+ *
+ * Description: Reads the standard EEPROM Status Register.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ * Returns:
+ *		OSAL_STATUS_CODE
+ */
+static UCHAR ReadEEPROMStatusRegister(struct bcm_mini_adapter *Adapter)
 {
 	UCHAR uiData = 0;
-	DWORD dwRetries = MAX_EEPROM_RETRIES*RETRIES_PER_DELAY;
-	UINT uiStatus = 0;
-	UINT value = 0;
-	UINT value1 = 0;
+	DWORD dwRetries = MAX_EEPROM_RETRIES * RETRIES_PER_DELAY;
+	unsigned int uiStatus = 0;
+	unsigned int value = 0;
+	unsigned int value1 = 0;
 
 	/* Read the EEPROM status register */
-	value = EEPROM_READ_STATUS_REGISTER ;
-	wrmalt( Adapter, EEPROM_CMDQ_SPI_REG, &value, sizeof(value));
+	value = EEPROM_READ_STATUS_REGISTER;
+	wrmalt(Adapter, EEPROM_CMDQ_SPI_REG, &value, sizeof(value));
 
-	while ( dwRetries != 0 )
-	{
-		value=0;
-		uiStatus = 0 ;
+	while (dwRetries != 0) {
+		value = 0;
+		uiStatus = 0;
 		rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus));
-		if(Adapter->device_removed == TRUE)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Modem has got removed hence exiting....");
+		if (Adapter->device_removed == TRUE) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Modem has got removed hence exiting....");
 			break;
 		}
 
 		/* Wait for Avail bit to be set. */
-		if ( ( uiStatus & EEPROM_READ_DATA_AVAIL) != 0 )
-		{
+		if ((uiStatus & EEPROM_READ_DATA_AVAIL) != 0) {
 			/* Clear the Avail/Full bits - which ever is set. */
 			value = uiStatus & (EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL);
-			wrmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
+			wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
 
-			value =0;
+			value = 0;
 			rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value));
 			uiData = (UCHAR)value;
 
 			break;
 		}
 
-		dwRetries-- ;
-		if ( dwRetries == 0 )
-		{
-			 rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
-			 rdmalt(Adapter, EEPROM_SPI_Q_STATUS_REG, &value1, sizeof(value1));
-			 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"0x3004 = %x 0x3008 = %x, retries = %d failed.\n",value,value1,  MAX_EEPROM_RETRIES*RETRIES_PER_DELAY);
+		dwRetries--;
+		if (dwRetries == 0) {
+			rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
+			rdmalt(Adapter, EEPROM_SPI_Q_STATUS_REG, &value1, sizeof(value1));
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "0x3004 = %x 0x3008 = %x, retries = %d failed.\n", value, value1, MAX_EEPROM_RETRIES * RETRIES_PER_DELAY);
 			return uiData;
 		}
-		if( !(dwRetries%RETRIES_PER_DELAY) )
-			msleep(1);
+		if (!(dwRetries%RETRIES_PER_DELAY))
+			udelay(1000);
 		uiStatus = 0 ;
 	}
 	return uiData;
 } /* ReadEEPROMStatusRegister */
 
-//-----------------------------------------------------------------------------
-// Procedure:	ReadBeceemEEPROMBulk
-//
-// Description: This routine reads 16Byte data from EEPROM
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//      dwAddress   - EEPROM Offset to read the data from.
-//      pdwData     - Pointer to double word where data needs to be stored in.  //		dwNumWords  - Number of words.  Valid values are 4 ONLY.
-//
-// Returns:
-//		OSAL_STATUS_CODE:
-//-----------------------------------------------------------------------------
-
-INT ReadBeceemEEPROMBulk( PMINI_ADAPTER Adapter,
-									   DWORD dwAddress,
-									   DWORD *pdwData,
-									   DWORD dwNumWords
-									 )
+/*
+ * Procedure:	ReadBeceemEEPROMBulk
+ *
+ * Description: This routine reads 16Byte data from EEPROM
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *      dwAddress   - EEPROM Offset to read the data from.
+ *      pdwData     - Pointer to double word where data needs to be stored in.  //		dwNumWords  - Number of words.  Valid values are 4 ONLY.
+ *
+ * Returns:
+ *		OSAL_STATUS_CODE:
+ */
+
+int ReadBeceemEEPROMBulk(struct bcm_mini_adapter *Adapter,
+			DWORD dwAddress,
+			DWORD *pdwData,
+			DWORD dwNumWords)
 {
 	DWORD dwIndex = 0;
-	DWORD dwRetries = MAX_EEPROM_RETRIES*RETRIES_PER_DELAY;
-	UINT uiStatus  = 0;
-	UINT value= 0;
-	UINT value1 = 0;
+	DWORD dwRetries = MAX_EEPROM_RETRIES * RETRIES_PER_DELAY;
+	unsigned int uiStatus  = 0;
+	unsigned int value = 0;
+	unsigned int value1 = 0;
 	UCHAR *pvalue;
 
 	/* Flush the read and cmd queue. */
-	value=( EEPROM_READ_QUEUE_FLUSH | EEPROM_CMD_QUEUE_FLUSH );
-	wrmalt( Adapter, SPI_FLUSH_REG, &value, sizeof(value) );
-	value=0;
-	wrmalt( Adapter, SPI_FLUSH_REG, &value, sizeof(value));
+	value = (EEPROM_READ_QUEUE_FLUSH | EEPROM_CMD_QUEUE_FLUSH);
+	wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value));
+	value = 0;
+	wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value));
 
 	/* Clear the Avail/Full bits. */
-	value=( EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL );
-	wrmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG,&value, sizeof(value));
-
-	value= dwAddress | ( (dwNumWords == 4) ? EEPROM_16_BYTE_PAGE_READ : EEPROM_4_BYTE_PAGE_READ );
-	wrmalt( Adapter, EEPROM_CMDQ_SPI_REG, &value, sizeof(value));
+	value = (EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL);
+	wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
 
-	while ( dwRetries != 0 )
-		{
+	value = dwAddress | ((dwNumWords == 4) ? EEPROM_16_BYTE_PAGE_READ : EEPROM_4_BYTE_PAGE_READ);
+	wrmalt(Adapter, EEPROM_CMDQ_SPI_REG, &value, sizeof(value));
 
+	while (dwRetries != 0) {
 		uiStatus = 0;
 		rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus));
-		if(Adapter->device_removed == TRUE)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Modem has got Removed.hence exiting from loop...");
+		if (Adapter->device_removed == TRUE) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Modem has got Removed.hence exiting from loop...");
 			return -ENODEV;
 		}
 
 		/* If we are reading 16 bytes we want to be sure that the queue
 		 * is full before we read.  In the other cases we are ok if the
-		 * queue has data available */
-		if ( dwNumWords == 4 )
-		{
-			if ( ( uiStatus & EEPROM_READ_DATA_FULL ) != 0 )
-			{
+		 * queue has data available
+		 */
+		if (dwNumWords == 4) {
+			if ((uiStatus & EEPROM_READ_DATA_FULL) != 0) {
 				/* Clear the Avail/Full bits - which ever is set. */
-				value = ( uiStatus & (EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL) ) ;
-				wrmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG,&value, sizeof(value));
+				value = (uiStatus & (EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL));
+				wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
 				break;
 			}
-		}
-		else if ( dwNumWords == 1 )
-		{
-
-			if ( ( uiStatus & EEPROM_READ_DATA_AVAIL ) != 0 )
-			{
+		} else if (dwNumWords == 1) {
+			if ((uiStatus & EEPROM_READ_DATA_AVAIL) != 0) {
 				/* We just got Avail and we have to read 32bits so we
-				 * need this sleep for Cardbus kind of devices. */
-				if (Adapter->chip_id == 0xBECE0210 )
-	  					udelay(800);
+				 * need this sleep for Cardbus kind of devices.
+				 */
+				if (Adapter->chip_id == 0xBECE0210)
+					udelay(800);
 
 				/* Clear the Avail/Full bits - which ever is set. */
-				value=( uiStatus & (EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL) );
-				wrmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG,&value, sizeof(value));
+				value = (uiStatus & (EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL));
+				wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
 				break;
 			}
 		}
@@ -198,25 +184,25 @@ INT ReadBeceemEEPROMBulk( PMINI_ADAPTER Adapter,
 		uiStatus = 0;
 
 		dwRetries--;
-		if(dwRetries == 0)
-		{
-			value=0;
-			value1=0;
+		if (dwRetries == 0) {
+			value = 0;
+			value1 = 0;
 			rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
 			rdmalt(Adapter, EEPROM_SPI_Q_STATUS_REG, &value1, sizeof(value1));
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "dwNumWords %d 0x3004 = %x 0x3008 = %x  retries = %d failed.\n", dwNumWords, value,  value1,  MAX_EEPROM_RETRIES*RETRIES_PER_DELAY);
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "dwNumWords %d 0x3004 = %x 0x3008 = %x  retries = %d failed.\n",
+					dwNumWords, value,  value1,  MAX_EEPROM_RETRIES * RETRIES_PER_DELAY);
 			return STATUS_FAILURE;
 		}
-		if( !(dwRetries%RETRIES_PER_DELAY) )
-			msleep(1);
+
+		if (!(dwRetries%RETRIES_PER_DELAY))
+			udelay(1000);
 	}
 
-	for ( dwIndex = 0; dwIndex < dwNumWords ; dwIndex++ )
-	{
+	for (dwIndex = 0; dwIndex < dwNumWords; dwIndex++) {
 		/* We get only a byte at a time - from LSB to MSB. We shift it into an integer. */
 		pvalue = (PUCHAR)(pdwData + dwIndex);
 
-		value =0;
+		value = 0;
 		rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value));
 
 		pvalue[0] = value;
@@ -226,7 +212,7 @@ INT ReadBeceemEEPROMBulk( PMINI_ADAPTER Adapter,
 
 		pvalue[1] = value;
 
-		value =0;
+		value = 0;
 		rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value));
 
 		pvalue[2] = value;
@@ -240,31 +226,30 @@ INT ReadBeceemEEPROMBulk( PMINI_ADAPTER Adapter,
 	return STATUS_SUCCESS;
 } /* ReadBeceemEEPROMBulk() */
 
-//-----------------------------------------------------------------------------
-// Procedure:	ReadBeceemEEPROM
-//
-// Description: This routine reads 4 data from EEPROM.  It uses 1 or 2 page
-//				reads to do this operation.
-//
-// Arguments:
-//		Adapter     - ptr to Adapter object instance
-//      uiOffset	- EEPROM Offset to read the data from.
-//      pBuffer		- Pointer to word where data needs to be stored in.
-//
-// Returns:
-//		OSAL_STATUS_CODE:
-//-----------------------------------------------------------------------------
-
-INT ReadBeceemEEPROM( PMINI_ADAPTER Adapter,
-								   DWORD uiOffset,
-								   DWORD *pBuffer
-								 )
+/*
+ * Procedure:	ReadBeceemEEPROM
+ *
+ * Description: This routine reads 4 data from EEPROM.  It uses 1 or 2 page
+ *				reads to do this operation.
+ *
+ * Arguments:
+ *		Adapter     - ptr to Adapter object instance
+ *      uiOffset	- EEPROM Offset to read the data from.
+ *      pBuffer		- Pointer to word where data needs to be stored in.
+ *
+ * Returns:
+ *		OSAL_STATUS_CODE:
+ */
+
+int ReadBeceemEEPROM(struct bcm_mini_adapter *Adapter,
+		DWORD uiOffset,
+		DWORD *pBuffer)
 {
-	UINT uiData[8]	 	= {0};
-	UINT uiByteOffset	= 0;
-	UINT uiTempOffset	= 0;
+	unsigned int uiData[8]		= {0};
+	unsigned int uiByteOffset	= 0;
+	unsigned int uiTempOffset	= 0;
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL," ====> ");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, " ====> ");
 
 	uiTempOffset = uiOffset - (uiOffset % MAX_RW_SIZE);
 	uiByteOffset = uiOffset - uiTempOffset;
@@ -272,22 +257,19 @@ INT ReadBeceemEEPROM( PMINI_ADAPTER Adapter,
 	ReadBeceemEEPROMBulk(Adapter, uiTempOffset, (PUINT)&uiData[0], 4);
 
 	/* A word can overlap at most over 2 pages. In that case we read the
-	 * next page too. */
-	if ( uiByteOffset > 12 )
-	{
+	 * next page too.
+	 */
+	if (uiByteOffset > 12)
 		ReadBeceemEEPROMBulk(Adapter, uiTempOffset + MAX_RW_SIZE, (PUINT)&uiData[4], 4);
-	}
 
-	memcpy( (PUCHAR) pBuffer, ( ((PUCHAR)&uiData[0]) + uiByteOffset ), 4);
+	memcpy((PUCHAR)pBuffer, (((PUCHAR)&uiData[0]) + uiByteOffset), 4);
 
 	return STATUS_SUCCESS;
 } /* ReadBeceemEEPROM() */
 
-
-
-INT ReadMacAddressFromNVM(PMINI_ADAPTER Adapter)
+int ReadMacAddressFromNVM(struct bcm_mini_adapter *Adapter)
 {
-	INT Status;
+	int Status;
 	unsigned char puMacAddr[6];
 
 	Status = BeceemNVMRead(Adapter,
@@ -295,182 +277,154 @@ INT ReadMacAddressFromNVM(PMINI_ADAPTER Adapter)
 			INIT_PARAMS_1_MACADDRESS_ADDRESS,
 			MAC_ADDRESS_SIZE);
 
-	if(Status == STATUS_SUCCESS)
+	if (Status == STATUS_SUCCESS)
 		memcpy(Adapter->dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE);
 
 	return Status;
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BeceemEEPROMBulkRead
-//
-// Description: Reads the EEPROM and returns the Data.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//		pBuffer    - Buffer to store the data read from EEPROM
-//		uiOffset   - Offset of EEPROM from where data should be read
-//		uiNumBytes - Number of bytes to be read from the EEPROM.
-//
-// Returns:
-//		OSAL_STATUS_SUCCESS - if EEPROM read is successful.
-//		<FAILURE>			- if failed.
-//-----------------------------------------------------------------------------
-
-INT BeceemEEPROMBulkRead(
-	PMINI_ADAPTER Adapter,
-	PUINT pBuffer,
-	UINT uiOffset,
-	UINT uiNumBytes)
+/*
+ * Procedure:	BeceemEEPROMBulkRead
+ *
+ * Description: Reads the EEPROM and returns the Data.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *		pBuffer    - Buffer to store the data read from EEPROM
+ *		uiOffset   - Offset of EEPROM from where data should be read
+ *		uiNumBytes - Number of bytes to be read from the EEPROM.
+ *
+ * Returns:
+ *		OSAL_STATUS_SUCCESS - if EEPROM read is successful.
+ *		<FAILURE>			- if failed.
+ */
+
+int BeceemEEPROMBulkRead(struct bcm_mini_adapter *Adapter,
+			PUINT pBuffer,
+			unsigned int uiOffset,
+			unsigned int uiNumBytes)
 {
-	UINT uiData[4]		  = {0};
-	//UINT uiAddress 		  = 0;
-	UINT uiBytesRemaining = uiNumBytes;
-	UINT uiIndex 		  = 0;
-	UINT uiTempOffset  	  = 0;
-	UINT uiExtraBytes     = 0;
-	UINT uiFailureRetries = 0;
+	unsigned int uiData[4]		= {0};
+	/* unsigned int uiAddress	= 0; */
+	unsigned int uiBytesRemaining	= uiNumBytes;
+	unsigned int uiIndex		= 0;
+	unsigned int uiTempOffset	= 0;
+	unsigned int uiExtraBytes	= 0;
+	unsigned int uiFailureRetries	= 0;
 	PUCHAR pcBuff = (PUCHAR)pBuffer;
 
-
-	if(uiOffset%MAX_RW_SIZE&& uiBytesRemaining)
-	{
-		uiTempOffset = uiOffset - (uiOffset%MAX_RW_SIZE);
-		uiExtraBytes = uiOffset-uiTempOffset;
-		ReadBeceemEEPROMBulk(Adapter,uiTempOffset,(PUINT)&uiData[0],4);
-		if(uiBytesRemaining >= (MAX_RW_SIZE - uiExtraBytes))
-		{
-			memcpy(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),MAX_RW_SIZE - uiExtraBytes);
-
+	if (uiOffset % MAX_RW_SIZE && uiBytesRemaining) {
+		uiTempOffset = uiOffset - (uiOffset % MAX_RW_SIZE);
+		uiExtraBytes = uiOffset - uiTempOffset;
+		ReadBeceemEEPROMBulk(Adapter, uiTempOffset, (PUINT)&uiData[0], 4);
+		if (uiBytesRemaining >= (MAX_RW_SIZE - uiExtraBytes)) {
+			memcpy(pBuffer, (((PUCHAR)&uiData[0]) + uiExtraBytes), MAX_RW_SIZE - uiExtraBytes);
 			uiBytesRemaining -= (MAX_RW_SIZE - uiExtraBytes);
 			uiIndex += (MAX_RW_SIZE - uiExtraBytes);
 			uiOffset += (MAX_RW_SIZE - uiExtraBytes);
-		}
-		else
-		{
-			memcpy(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),uiBytesRemaining);
+		} else {
+			memcpy(pBuffer, (((PUCHAR)&uiData[0]) + uiExtraBytes), uiBytesRemaining);
 			uiIndex += uiBytesRemaining;
 			uiOffset += uiBytesRemaining;
 			uiBytesRemaining = 0;
 		}
-
-
 	}
 
-
-	while(uiBytesRemaining && uiFailureRetries != 128)
-	{
-		if(Adapter->device_removed )
-		{
+	while (uiBytesRemaining && uiFailureRetries != 128) {
+		if (Adapter->device_removed)
 			return -1;
-		}
 
-		if(uiBytesRemaining >= MAX_RW_SIZE)
-		{
+		if (uiBytesRemaining >= MAX_RW_SIZE) {
 			/* For the requests more than or equal to 16 bytes, use bulk
 			 * read function to make the access faster.
-			 * We read 4 Dwords of data */
-			if(0 == ReadBeceemEEPROMBulk(Adapter,uiOffset,&uiData[0],4))
-			{
-				memcpy(pcBuff+uiIndex,&uiData[0],MAX_RW_SIZE);
+			 * We read 4 Dwords of data
+			 */
+			if (ReadBeceemEEPROMBulk(Adapter, uiOffset, &uiData[0], 4) == 0) {
+				memcpy(pcBuff + uiIndex, &uiData[0], MAX_RW_SIZE);
 				uiOffset += MAX_RW_SIZE;
 				uiBytesRemaining -= MAX_RW_SIZE;
 				uiIndex += MAX_RW_SIZE;
-			}
-			else
-			{
+			} else {
 				uiFailureRetries++;
-				mdelay(3);//sleep for a while before retry...
+				mdelay(3); /* sleep for a while before retry... */
 			}
-		}
-		else if(uiBytesRemaining >= 4)
-		{
-			if(0 == ReadBeceemEEPROM(Adapter,uiOffset,&uiData[0]))
-			{
-				memcpy(pcBuff+uiIndex,&uiData[0],4);
+		} else if (uiBytesRemaining >= 4) {
+			if (ReadBeceemEEPROM(Adapter, uiOffset, &uiData[0]) == 0) {
+				memcpy(pcBuff + uiIndex, &uiData[0], 4);
 				uiOffset += 4;
 				uiBytesRemaining -= 4;
-				uiIndex +=4;
-			}
-			else
-			{
+				uiIndex += 4;
+			} else {
 				uiFailureRetries++;
-				mdelay(3);//sleep for a while before retry...
+				mdelay(3); /* sleep for a while before retry... */
 			}
-		}
-		else
-		{ // Handle the reads less than 4 bytes...
+		} else {
+			/* Handle the reads less than 4 bytes... */
 			PUCHAR pCharBuff = (PUCHAR)pBuffer;
 			pCharBuff += uiIndex;
-			if(0 == ReadBeceemEEPROM(Adapter,uiOffset,&uiData[0]))
-			{
-				memcpy(pCharBuff,&uiData[0],uiBytesRemaining);//copy only bytes requested.
+			if (ReadBeceemEEPROM(Adapter, uiOffset, &uiData[0]) == 0) {
+				memcpy(pCharBuff, &uiData[0], uiBytesRemaining); /* copy only bytes requested. */
 				uiBytesRemaining = 0;
-			}
-			else
-			{
+			} else {
 				uiFailureRetries++;
-				mdelay(3);//sleep for a while before retry...
+				mdelay(3); /* sleep for a while before retry... */
 			}
 		}
-
 	}
 
 	return 0;
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BeceemFlashBulkRead
-//
-// Description: Reads the FLASH and returns the Data.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//		pBuffer    - Buffer to store the data read from FLASH
-//		uiOffset   - Offset of FLASH from where data should be read
-//		uiNumBytes - Number of bytes to be read from the FLASH.
-//
-// Returns:
-//		OSAL_STATUS_SUCCESS - if FLASH read is successful.
-//		<FAILURE>			- if failed.
-//-----------------------------------------------------------------------------
-
-static INT BeceemFlashBulkRead(
-	PMINI_ADAPTER Adapter,
-	PUINT pBuffer,
-	UINT uiOffset,
-	UINT uiNumBytes)
+/*
+ * Procedure:	BeceemFlashBulkRead
+ *
+ * Description: Reads the FLASH and returns the Data.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *		pBuffer    - Buffer to store the data read from FLASH
+ *		uiOffset   - Offset of FLASH from where data should be read
+ *		uiNumBytes - Number of bytes to be read from the FLASH.
+ *
+ * Returns:
+ *		OSAL_STATUS_SUCCESS - if FLASH read is successful.
+ *		<FAILURE>			- if failed.
+ */
+
+static int BeceemFlashBulkRead(struct bcm_mini_adapter *Adapter,
+			PUINT pBuffer,
+			unsigned int uiOffset,
+			unsigned int uiNumBytes)
 {
-	UINT uiIndex = 0;
-	UINT uiBytesToRead = uiNumBytes;
-	INT Status = 0;
-	UINT uiPartOffset = 0;
+	unsigned int uiIndex = 0;
+	unsigned int uiBytesToRead = uiNumBytes;
+	int Status = 0;
+	unsigned int uiPartOffset = 0;
 	int bytes;
 
-	if(Adapter->device_removed )
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Device Got Removed ");
+	if (Adapter->device_removed) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device Got Removed");
 		return -ENODEV;
 	}
 
-	//Adding flash Base address
-//	uiOffset = uiOffset + GetFlashBaseAddr(Adapter);
-#if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
-  Status = bcmflash_raw_read((uiOffset/FLASH_PART_SIZE),(uiOffset % FLASH_PART_SIZE),( unsigned char *)pBuffer,uiNumBytes);
-  return Status;
-#endif
+	/* Adding flash Base address
+	 * uiOffset = uiOffset + GetFlashBaseAddr(Adapter);
+	 */
+	#if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
+		Status = bcmflash_raw_read((uiOffset/FLASH_PART_SIZE), (uiOffset % FLASH_PART_SIZE), (unsigned char *)pBuffer, uiNumBytes);
+		return Status;
+	#endif
 
 	Adapter->SelectedChip = RESET_CHIP_SELECT;
 
-	if(uiOffset % MAX_RW_SIZE)
-	{
-		BcmDoChipSelect(Adapter,uiOffset);
+	if (uiOffset % MAX_RW_SIZE) {
+		BcmDoChipSelect(Adapter, uiOffset);
 		uiPartOffset = (uiOffset & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter);
 
-		uiBytesToRead = MAX_RW_SIZE - (uiOffset%MAX_RW_SIZE);
-		uiBytesToRead = MIN(uiNumBytes,uiBytesToRead);
+		uiBytesToRead = MAX_RW_SIZE - (uiOffset % MAX_RW_SIZE);
+		uiBytesToRead = MIN(uiNumBytes, uiBytesToRead);
 
-		bytes = rdm(Adapter, uiPartOffset, (PCHAR)pBuffer+uiIndex, uiBytesToRead);
+		bytes = rdm(Adapter, uiPartOffset, (PCHAR)pBuffer + uiIndex, uiBytesToRead);
 		if (bytes < 0) {
 			Status = bytes;
 			Adapter->SelectedChip = RESET_CHIP_SELECT;
@@ -482,142 +436,122 @@ static INT BeceemFlashBulkRead(
 		uiNumBytes -= uiBytesToRead;
 	}
 
-	while(uiNumBytes)
-	{
-		BcmDoChipSelect(Adapter,uiOffset);
+	while (uiNumBytes) {
+		BcmDoChipSelect(Adapter, uiOffset);
 		uiPartOffset = (uiOffset & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter);
 
-		uiBytesToRead = MIN(uiNumBytes,MAX_RW_SIZE);
+		uiBytesToRead = MIN(uiNumBytes, MAX_RW_SIZE);
 
-		bytes = rdm(Adapter, uiPartOffset, (PCHAR)pBuffer+uiIndex, uiBytesToRead);
+		bytes = rdm(Adapter, uiPartOffset, (PCHAR)pBuffer + uiIndex, uiBytesToRead);
 		if (bytes < 0) {
 			Status = bytes;
 			break;
 		}
 
-
 		uiIndex += uiBytesToRead;
 		uiOffset += uiBytesToRead;
 		uiNumBytes -= uiBytesToRead;
-
 	}
 	Adapter->SelectedChip = RESET_CHIP_SELECT;
 	return Status;
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BcmGetFlashSize
-//
-// Description: Finds the size of FLASH.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//
-// Returns:
-//		UINT - size of the FLASH Storage.
-//
-//-----------------------------------------------------------------------------
-
-static UINT BcmGetFlashSize(PMINI_ADAPTER Adapter)
+/*
+ * Procedure:	BcmGetFlashSize
+ *
+ * Description: Finds the size of FLASH.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *
+ * Returns:
+ *		unsigned int - size of the FLASH Storage.
+ *
+ */
+
+static unsigned int BcmGetFlashSize(struct bcm_mini_adapter *Adapter)
 {
-	if(IsFlash2x(Adapter))
-		return 	(Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER));
+	if (IsFlash2x(Adapter))
+		return Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER);
 	else
-		return 32*1024;
-
-
+		return 32 * 1024;
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BcmGetEEPROMSize
-//
-// Description: Finds the size of EEPROM.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//
-// Returns:
-//		UINT - size of the EEPROM Storage.
-//
-//-----------------------------------------------------------------------------
-
-static UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter)
+/*
+ * Procedure:	BcmGetEEPROMSize
+ *
+ * Description: Finds the size of EEPROM.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *
+ * Returns:
+ *		unsigned int - size of the EEPROM Storage.
+ *
+ */
+
+static unsigned int BcmGetEEPROMSize(struct bcm_mini_adapter *Adapter)
 {
-	UINT uiData = 0;
-	UINT uiIndex = 0;
-
-//
-// if EEPROM is present and already Calibrated,it will have
-// 'BECM' string at 0th offset.
-//	To find the EEPROM size read the possible boundaries of the
-// EEPROM like 4K,8K etc..accessing the EEPROM beyond its size will
-// result in wrap around. So when we get the End of the EEPROM we will
-// get 'BECM' string which is indeed at offset 0.
-//
-	BeceemEEPROMBulkRead(Adapter,&uiData,0x0,4);
-	if(uiData == BECM)
-	{
-		for(uiIndex = 2;uiIndex <=256; uiIndex*=2)
-		{
-			BeceemEEPROMBulkRead(Adapter,&uiData,uiIndex*1024,4);
-			if(uiData == BECM)
-			{
-				return uiIndex*1024;
-			}
-		}
-	}
-	else
-	{
-//
-// EEPROM may not be present or not programmed
-//
+	unsigned int uiData = 0;
+	unsigned int uiIndex = 0;
 
-        uiData = 0xBABEFACE;
-		if(0 == BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&uiData,0,4,TRUE))
-		{
+	/*
+	 * if EEPROM is present and already Calibrated,it will have
+	 * 'BECM' string at 0th offset.
+	 * To find the EEPROM size read the possible boundaries of the
+	 * EEPROM like 4K,8K etc..accessing the EEPROM beyond its size will
+	 * result in wrap around. So when we get the End of the EEPROM we will
+	 * get 'BECM' string which is indeed at offset 0.
+	 */
+	BeceemEEPROMBulkRead(Adapter, &uiData, 0x0, 4);
+	if (uiData == BECM) {
+		for (uiIndex = 2; uiIndex <= 256; uiIndex *= 2)	{
+			BeceemEEPROMBulkRead(Adapter, &uiData, uiIndex * 1024, 4);
+			if (uiData == BECM)
+				return uiIndex * 1024;
+		}
+	} else {
+		/*
+		 * EEPROM may not be present or not programmed
+		 */
+		uiData = 0xBABEFACE;
+		if (BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&uiData, 0, 4, TRUE) == 0) {
 			uiData = 0;
-			for(uiIndex = 2;uiIndex <=256; uiIndex*=2)
-			{
-				BeceemEEPROMBulkRead(Adapter,&uiData,uiIndex*1024,4);
-				if(uiData == 0xBABEFACE)
-				{
-					return uiIndex*1024;
-				}
+			for (uiIndex = 2; uiIndex <= 256; uiIndex *= 2) {
+				BeceemEEPROMBulkRead(Adapter, &uiData, uiIndex * 1024, 4);
+				if (uiData == 0xBABEFACE)
+					return uiIndex * 1024;
 			}
 		}
-
 	}
 	return 0;
 }
 
-
-//-----------------------------------------------------------------------------
-// Procedure:	FlashSectorErase
-//
-// Description: Finds the sector size of the FLASH.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//		addr	   - sector start address
-//		numOfSectors - number of sectors to  be erased.
-//
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-
-
-static INT FlashSectorErase(PMINI_ADAPTER Adapter,
-	UINT addr,
-	UINT numOfSectors)
+/*
+ * Procedure:	FlashSectorErase
+ *
+ * Description: Finds the sector size of the FLASH.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *		addr	   - sector start address
+ *		numOfSectors - number of sectors to  be erased.
+ *
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+
+static int FlashSectorErase(struct bcm_mini_adapter *Adapter,
+			unsigned int addr,
+			unsigned int numOfSectors)
 {
-	UINT iIndex = 0, iRetries = 0;
-	UINT uiStatus = 0;
-	UINT value;
+	unsigned int iIndex = 0, iRetries = 0;
+	unsigned int uiStatus = 0;
+	unsigned int value;
 	int bytes;
 
-	for(iIndex=0;iIndex<numOfSectors;iIndex++)
-	{
+	for (iIndex = 0; iIndex < numOfSectors; iIndex++) {
 		value = 0x06000000;
 		wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value));
 
@@ -625,12 +559,10 @@ static INT FlashSectorErase(PMINI_ADAPTER Adapter,
 		wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value));
 		iRetries = 0;
 
-		do
-		{
+		do {
 			value = (FLASH_CMD_STATUS_REG_READ << 24);
-			if(wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0)
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Programing of FLASH_SPI_CMDQ_REG fails");
+			if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programing of FLASH_SPI_CMDQ_REG fails");
 				return STATUS_FAILURE;
 			}
 
@@ -641,15 +573,15 @@ static INT FlashSectorErase(PMINI_ADAPTER Adapter,
 				return uiStatus;
 			}
 			iRetries++;
-			//After every try lets make the CPU free for 10 ms. generally time taken by the
-			//the sector erase cycle is 500 ms to 40000 msec. hence sleeping 10 ms
-			//won't hamper performance in any case.
-			msleep(10);
-		}while((uiStatus & 0x1) && (iRetries < 400));
-
-		if(uiStatus & 0x1)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"iRetries crossing the limit of 80000\n");
+			/* After every try lets make the CPU free for 10 ms. generally time taken by the
+			 * the sector erase cycle is 500 ms to 40000 msec. hence sleeping 10 ms
+			 * won't hamper performance in any case.
+			 */
+			udelay(10000);
+		} while ((uiStatus & 0x1) && (iRetries < 400));
+
+		if (uiStatus & 0x1) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "iRetries crossing the limit of 80000\n");
 			return STATUS_FAILURE;
 		}
 
@@ -657,158 +589,137 @@ static INT FlashSectorErase(PMINI_ADAPTER Adapter,
 	}
 	return 0;
 }
-//-----------------------------------------------------------------------------
-// Procedure:	flashByteWrite
-//
-// Description: Performs Byte by Byte write to flash
-//
-// Arguments:
-//		Adapter   - ptr to Adapter object instance
-//		uiOffset   - Offset of the flash where data needs to be written to.
-//		pData	- Address of Data to be written.
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-
-static INT flashByteWrite(
-	PMINI_ADAPTER Adapter,
-	UINT uiOffset,
-	PVOID pData)
+/*
+ * Procedure:	flashByteWrite
+ *
+ * Description: Performs Byte by Byte write to flash
+ *
+ * Arguments:
+ *		Adapter   - ptr to Adapter object instance
+ *		uiOffset   - Offset of the flash where data needs to be written to.
+ *		pData	- Address of Data to be written.
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+
+static int flashByteWrite(struct bcm_mini_adapter *Adapter,
+			unsigned int uiOffset,
+			PVOID pData)
 {
-
-	UINT uiStatus = 0;
-	INT  iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; //3
-
-	UINT value;
+	unsigned int uiStatus = 0;
+	int  iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; /* 3 */
+	unsigned int value;
 	ULONG ulData = *(PUCHAR)pData;
 	int bytes;
+	/*
+	 * need not write 0xFF because write requires an erase and erase will
+	 * make whole sector 0xFF.
+	 */
 
-//
-// need not write 0xFF because write requires an erase and erase will
-// make whole sector 0xFF.
-//
-
-	if(0xFF == ulData)
-	{
+	if (0xFF == ulData)
 		return STATUS_SUCCESS;
-	}
 
-//	DumpDebug(NVM_RW,("flashWrite ====>\n"));
+	/* DumpDebug(NVM_RW,("flashWrite ====>\n")); */
 	value = (FLASH_CMD_WRITE_ENABLE << 24);
-	if(wrmalt(Adapter, FLASH_SPI_CMDQ_REG,&value, sizeof(value)) < 0)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Write enable in FLASH_SPI_CMDQ_REG register fails");
+	if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write enable in FLASH_SPI_CMDQ_REG register fails");
 		return STATUS_FAILURE;
 	}
-	if(wrm(Adapter,FLASH_SPI_WRITEQ_REG, (PCHAR)&ulData, 4) < 0 )
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"DATA Write on FLASH_SPI_WRITEQ_REG fails");
+
+	if (wrm(Adapter, FLASH_SPI_WRITEQ_REG, (PCHAR)&ulData, 4) < 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "DATA Write on FLASH_SPI_WRITEQ_REG fails");
 		return STATUS_FAILURE;
 	}
 	value = (0x02000000 | (uiOffset & 0xFFFFFF));
-	if(wrmalt(Adapter, FLASH_SPI_CMDQ_REG,&value, sizeof(value)) < 0 )
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Programming of FLASH_SPI_CMDQ_REG fails");
+	if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programming of FLASH_SPI_CMDQ_REG fails");
 		return STATUS_FAILURE;
 	}
 
-	//__udelay(950);
+	/* __udelay(950); */
 
-	do
-	{
+	do {
 		value = (FLASH_CMD_STATUS_REG_READ << 24);
-	  	if(wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0)
-	  	{
-	  		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Programing of FLASH_SPI_CMDQ_REG fails");
+		if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programing of FLASH_SPI_CMDQ_REG fails");
 			return STATUS_FAILURE;
-	  	}
-	  	//__udelay(1);
+		}
+		/* __udelay(1); */
 		bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus));
 		if (bytes < 0) {
 			uiStatus = bytes;
 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails");
 			return uiStatus;
 		}
-	  	iRetries--;
-		if( iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0))
-			 msleep(1);
+		iRetries--;
+		if (iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0))
+			udelay(1000);
 
-	}while((uiStatus & 0x1) && (iRetries  >0) );
+	} while ((uiStatus & 0x1) && (iRetries  > 0));
 
-	if(uiStatus & 0x1)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Flash Write fails even after checking status for 200 times.");
-		return STATUS_FAILURE ;
+	if (uiStatus & 0x1) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Write fails even after checking status for 200 times.");
+		return STATUS_FAILURE;
 	}
 
 	return STATUS_SUCCESS;
 }
 
-
-
-//-----------------------------------------------------------------------------
-// Procedure:	flashWrite
-//
-// Description: Performs write to flash
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//		uiOffset   - Offset of the flash where data needs to be written to.
-//		pData	- Address of Data to be written.
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-
-static INT flashWrite(
-	PMINI_ADAPTER Adapter,
-	UINT uiOffset,
-	PVOID pData)
-
+/*
+ * Procedure:	flashWrite
+ *
+ * Description: Performs write to flash
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *		uiOffset   - Offset of the flash where data needs to be written to.
+ *		pData	- Address of Data to be written.
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+
+static int flashWrite(struct bcm_mini_adapter *Adapter,
+		unsigned int uiOffset,
+		PVOID pData)
 {
-	//UINT uiStatus = 0;
-	//INT  iRetries = 0;
-	//UINT uiReadBack = 0;
-
-	UINT uiStatus = 0;
-	INT  iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; //3
-
-	UINT value;
-	UINT uiErasePattern[4] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
+	/* unsigned int uiStatus = 0;
+	 * int  iRetries = 0;
+	 * unsigned int uiReadBack = 0;
+	 */
+	unsigned int uiStatus = 0;
+	int  iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; /* 3 */
+	unsigned int value;
+	unsigned int uiErasePattern[4] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
 	int bytes;
-//
-// need not write 0xFFFFFFFF because write requires an erase and erase will
-// make whole sector 0xFFFFFFFF.
-//
+	/*
+	 * need not write 0xFFFFFFFF because write requires an erase and erase will
+	 * make whole sector 0xFFFFFFFF.
+	 */
 	if (!memcmp(pData, uiErasePattern, MAX_RW_SIZE))
-	{
 		return 0;
-	}
 
 	value = (FLASH_CMD_WRITE_ENABLE << 24);
 
-	if(wrmalt(Adapter, FLASH_SPI_CMDQ_REG,&value, sizeof(value)) < 0 )
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Write Enable of FLASH_SPI_CMDQ_REG fails");
+	if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write Enable of FLASH_SPI_CMDQ_REG fails");
 		return STATUS_FAILURE;
 	}
-	if(wrm(Adapter, uiOffset, (PCHAR)pData, MAX_RW_SIZE) < 0)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Data write fails...");
+
+	if (wrm(Adapter, uiOffset, (PCHAR)pData, MAX_RW_SIZE) < 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Data write fails...");
 		return STATUS_FAILURE;
 	}
 
-	//__udelay(950);
-	do
-	{
+	/* __udelay(950); */
+	do {
 		value = (FLASH_CMD_STATUS_REG_READ << 24);
-	  	if(wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0)
-	  	{
-	  		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Programing of FLASH_SPI_CMDQ_REG fails");
+		if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programing of FLASH_SPI_CMDQ_REG fails");
 			return STATUS_FAILURE;
-	  	}
-	  	//__udelay(1);
+		}
+		/* __udelay(1); */
 		bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus));
 		if (bytes < 0) {
 			uiStatus = bytes;
@@ -817,88 +728,80 @@ static INT flashWrite(
 		}
 
 		iRetries--;
-		//this will ensure that in there will be no changes in the current path.
-		//currently one rdm/wrm takes 125 us.
-		//Hence  125 *2 * FLASH_PER_RETRIES_DELAY > 3 ms(worst case delay)
-		//Hence current implementation cycle will intoduce no delay in current path
-		if(iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0))
-				msleep(1);
-	}while((uiStatus & 0x1) && (iRetries > 0));
-
-	if(uiStatus & 0x1)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Flash Write fails even after checking status for 200 times.");
-		return STATUS_FAILURE ;
+		/* this will ensure that in there will be no changes in the current path.
+		 * currently one rdm/wrm takes 125 us.
+		 * Hence  125 *2 * FLASH_PER_RETRIES_DELAY > 3 ms(worst case delay)
+		 * Hence current implementation cycle will intoduce no delay in current path
+		 */
+		if (iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0))
+			udelay(1000);
+	} while ((uiStatus & 0x1) && (iRetries > 0));
+
+	if (uiStatus & 0x1) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Write fails even after checking status for 200 times.");
+		return STATUS_FAILURE;
 	}
 
 	return STATUS_SUCCESS;
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	flashByteWriteStatus
-//
-// Description: Performs byte by byte write to flash with write done status check
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//		uiOffset    - Offset of the flash where data needs to be written to.
-//		pData	 - Address of the Data to be written.
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-static INT flashByteWriteStatus(
-	PMINI_ADAPTER Adapter,
-	UINT uiOffset,
-	PVOID pData)
+/*-----------------------------------------------------------------------------
+ * Procedure:	flashByteWriteStatus
+ *
+ * Description: Performs byte by byte write to flash with write done status check
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *		uiOffset    - Offset of the flash where data needs to be written to.
+ *		pData	 - Address of the Data to be written.
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+static int flashByteWriteStatus(struct bcm_mini_adapter *Adapter,
+				unsigned int uiOffset,
+				PVOID pData)
 {
-	UINT uiStatus = 0;
-	INT  iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; //3
+	unsigned int uiStatus = 0;
+	int  iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; /* 3 */
 	ULONG ulData  = *(PUCHAR)pData;
-	UINT value;
+	unsigned int value;
 	int bytes;
 
-//
-// need not write 0xFFFFFFFF because write requires an erase and erase will
-// make whole sector 0xFFFFFFFF.
-//
+	/*
+	 * need not write 0xFFFFFFFF because write requires an erase and erase will
+	 * make whole sector 0xFFFFFFFF.
+	 */
 
-	if(0xFF == ulData)
-	{
+	if (0xFF == ulData)
 		return STATUS_SUCCESS;
-	}
 
-	//	DumpDebug(NVM_RW,("flashWrite ====>\n"));
+	/* DumpDebug(NVM_RW,("flashWrite ====>\n")); */
 
 	value = (FLASH_CMD_WRITE_ENABLE << 24);
-	if(wrmalt(Adapter, FLASH_SPI_CMDQ_REG,&value, sizeof(value)) < 0)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Write enable in FLASH_SPI_CMDQ_REG register fails");
+	if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write enable in FLASH_SPI_CMDQ_REG register fails");
 		return STATUS_SUCCESS;
 	}
-	if(wrm(Adapter,FLASH_SPI_WRITEQ_REG, (PCHAR)&ulData, 4) < 0)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"DATA Write on FLASH_SPI_WRITEQ_REG fails");
+	if (wrm(Adapter, FLASH_SPI_WRITEQ_REG, (PCHAR)&ulData, 4) < 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "DATA Write on FLASH_SPI_WRITEQ_REG fails");
 		return STATUS_FAILURE;
 	}
 	value = (0x02000000 | (uiOffset & 0xFFFFFF));
-	if(wrmalt(Adapter, FLASH_SPI_CMDQ_REG,&value, sizeof(value)) < 0)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Programming of FLASH_SPI_CMDQ_REG fails");
+	if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programming of FLASH_SPI_CMDQ_REG fails");
 		return STATUS_FAILURE;
 	}
 
-    //msleep(1);
+	/* msleep(1); */
 
-	do
-	{
+	do {
 		value = (FLASH_CMD_STATUS_REG_READ << 24);
-		if(wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Programing of FLASH_SPI_CMDQ_REG fails");
+		if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programing of FLASH_SPI_CMDQ_REG fails");
 			return STATUS_FAILURE;
 		}
-		//__udelay(1);
+		/* __udelay(1); */
 		bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus));
 		if (bytes < 0) {
 			uiStatus = bytes;
@@ -907,405 +810,361 @@ static INT flashByteWriteStatus(
 		}
 
 		iRetries--;
-		if( iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0))
-				msleep(1);
-	}while((uiStatus & 0x1) && (iRetries > 0));
+		if (iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0))
+			udelay(1000);
 
-	if(uiStatus & 0x1)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Flash Write fails even after checking status for 200 times.");
-		return STATUS_FAILURE ;
+	} while ((uiStatus & 0x1) && (iRetries > 0));
+
+	if (uiStatus & 0x1) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Write fails even after checking status for 200 times.");
+		return STATUS_FAILURE;
 	}
 
 	return STATUS_SUCCESS;
-
 }
-//-----------------------------------------------------------------------------
-// Procedure:	flashWriteStatus
-//
-// Description: Performs write to flash with write done status check
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//		uiOffset    - Offset of the flash where data needs to be written to.
-//		pData	 - Address of the Data to be written.
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-
-static INT flashWriteStatus(
-	PMINI_ADAPTER Adapter,
-	UINT uiOffset,
-	PVOID pData)
+/*
+ * Procedure:	flashWriteStatus
+ *
+ * Description: Performs write to flash with write done status check
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *		uiOffset    - Offset of the flash where data needs to be written to.
+ *		pData	 - Address of the Data to be written.
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+
+static int flashWriteStatus(struct bcm_mini_adapter *Adapter,
+			unsigned int uiOffset,
+			PVOID pData)
 {
-	UINT uiStatus = 0;
-	INT  iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; //3
-	//UINT uiReadBack = 0;
-	UINT value;
-	UINT uiErasePattern[4] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
+	unsigned int uiStatus = 0;
+	int  iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; /* 3 */
+	/* unsigned int uiReadBack = 0; */
+	unsigned int value;
+	unsigned int uiErasePattern[4] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
 	int bytes;
 
-//
-// need not write 0xFFFFFFFF because write requires an erase and erase will
-// make whole sector 0xFFFFFFFF.
-//
-	if (!memcmp(pData,uiErasePattern,MAX_RW_SIZE))
-	{
+	/*
+	 * need not write 0xFFFFFFFF because write requires an erase and erase will
+	 * make whole sector 0xFFFFFFFF.
+	 */
+	if (!memcmp(pData, uiErasePattern, MAX_RW_SIZE))
 		return 0;
-	}
 
 	value = (FLASH_CMD_WRITE_ENABLE << 24);
-	if(wrmalt(Adapter, FLASH_SPI_CMDQ_REG,&value, sizeof(value)) < 0)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Write Enable of FLASH_SPI_CMDQ_REG fails");
+	if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write Enable of FLASH_SPI_CMDQ_REG fails");
 		return STATUS_FAILURE;
 	}
-	if(wrm(Adapter, uiOffset, (PCHAR)pData, MAX_RW_SIZE) < 0)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Data write fails...");
+
+	if (wrm(Adapter, uiOffset, (PCHAR)pData, MAX_RW_SIZE) < 0) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Data write fails...");
 		return STATUS_FAILURE;
 	}
-   // __udelay(1);
+	/* __udelay(1); */
 
-	do
-	{
+	do {
 		value = (FLASH_CMD_STATUS_REG_READ << 24);
-	  	if(wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0)
-	  	{
-	  		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Programing of FLASH_SPI_CMDQ_REG fails");
+		if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programing of FLASH_SPI_CMDQ_REG fails");
 			return STATUS_FAILURE;
-	  	}
-	  	//__udelay(1);
+		}
+		/* __udelay(1); */
 		bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus));
 		if (bytes < 0) {
 			uiStatus = bytes;
 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails");
 			return uiStatus;
 		}
-	  	iRetries--;
-		//this will ensure that in there will be no changes in the current path.
-		//currently one rdm/wrm takes 125 us.
-		//Hence  125 *2  * FLASH_PER_RETRIES_DELAY  >3 ms(worst case delay)
-		//Hence current implementation cycle will intoduce no delay in current path
-		if(iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0))
-				msleep(1);
-	}while((uiStatus & 0x1) && (iRetries >0));
-
-	if(uiStatus & 0x1)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Flash Write fails even after checking status for 200 times.");
-		return STATUS_FAILURE ;
+		iRetries--;
+		/* this will ensure that in there will be no changes in the current path.
+		 * currently one rdm/wrm takes 125 us.
+		 * Hence  125 *2  * FLASH_PER_RETRIES_DELAY  >3 ms(worst case delay)
+		 * Hence current implementation cycle will intoduce no delay in current path
+		 */
+		if (iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0))
+			udelay(1000);
+
+	} while ((uiStatus & 0x1) && (iRetries > 0));
+
+	if (uiStatus & 0x1) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Write fails even after checking status for 200 times.");
+		return STATUS_FAILURE;
 	}
 
 	return STATUS_SUCCESS;
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BcmRestoreBlockProtectStatus
-//
-// Description: Restores the original block protection status.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//		ulWriteStatus   -Original status
-// Returns:
-//		<VOID>
-//
-//-----------------------------------------------------------------------------
-
-static VOID BcmRestoreBlockProtectStatus(PMINI_ADAPTER Adapter,ULONG ulWriteStatus)
+/*
+ * Procedure:	BcmRestoreBlockProtectStatus
+ *
+ * Description: Restores the original block protection status.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *		ulWriteStatus   -Original status
+ * Returns:
+ *		<VOID>
+ *
+ */
+
+static VOID BcmRestoreBlockProtectStatus(struct bcm_mini_adapter *Adapter, ULONG ulWriteStatus)
 {
-	UINT value;
-	value = (FLASH_CMD_WRITE_ENABLE<< 24);
+	unsigned int value;
+	value = (FLASH_CMD_WRITE_ENABLE << 24);
 	wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value));
 
 	udelay(20);
-	value = (FLASH_CMD_STATUS_REG_WRITE<<24)|(ulWriteStatus << 16);
+	value = (FLASH_CMD_STATUS_REG_WRITE << 24) | (ulWriteStatus << 16);
 	wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value));
 	udelay(20);
 }
-//-----------------------------------------------------------------------------
-// Procedure:	BcmFlashUnProtectBlock
-//
-// Description: UnProtects appropriate blocks for writing.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//		uiOffset   - Offset of the flash where data needs to be written to. This should be Sector aligned.
-// Returns:
-//		ULONG   - Status value before UnProtect.
-//
-//-----------------------------------------------------------------------------
-static ULONG BcmFlashUnProtectBlock(PMINI_ADAPTER Adapter,UINT uiOffset, UINT uiLength)
+
+/*
+ * Procedure:	BcmFlashUnProtectBlock
+ *
+ * Description: UnProtects appropriate blocks for writing.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *		uiOffset   - Offset of the flash where data needs to be written to. This should be Sector aligned.
+ * Returns:
+ *		ULONG   - Status value before UnProtect.
+ *
+ */
+
+static ULONG BcmFlashUnProtectBlock(struct bcm_mini_adapter *Adapter, unsigned int uiOffset, unsigned int uiLength)
 {
-	ULONG ulStatus      = 0;
-	ULONG ulWriteStatus = 0;
-	UINT value;
-	uiOffset = uiOffset&0x000FFFFF;
+	ULONG ulStatus		= 0;
+	ULONG ulWriteStatus	= 0;
+	unsigned int value;
 
-//
-// Implemented only for 1MB Flash parts.
-//
-	if(FLASH_PART_SST25VF080B == Adapter->ulFlashID)
-	{
-	//
-	// Get Current BP status.
-	//
+	uiOffset = uiOffset&0x000FFFFF;
+	/*
+	 * Implemented only for 1MB Flash parts.
+	 */
+	if (FLASH_PART_SST25VF080B == Adapter->ulFlashID) {
+		/*
+		 * Get Current BP status.
+		 */
 		value = (FLASH_CMD_STATUS_REG_READ << 24);
 		wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value));
 		udelay(10);
-	//
-	// Read status will be WWXXYYZZ. We have to take only WW.
-	//
+		/*
+		 * Read status will be WWXXYYZZ. We have to take only WW.
+		 */
 		rdmalt(Adapter, FLASH_SPI_READQ_REG, (PUINT)&ulStatus, sizeof(ulStatus));
 		ulStatus >>= 24;
 		ulWriteStatus = ulStatus;
-
-	//
-	// Bits [5-2] give current block level protection status.
-	// Bit5: BP3 - DONT CARE
-	// BP2-BP0: 0 - NO PROTECTION, 1 - UPPER 1/16, 2 - UPPER 1/8, 3 - UPPER 1/4
-	//                4 - UPPER 1/2. 5 to 7 - ALL BLOCKS
-	//
-
-		if(ulStatus)
-		{
-			if((uiOffset+uiLength) <= 0x80000)
-			{
-			//
-			// Offset comes in lower half of 1MB. Protect the upper half.
-			// Clear BP1 and BP0 and set BP2.
-			//
+		/*
+		 * Bits [5-2] give current block level protection status.
+		 * Bit5: BP3 - DONT CARE
+		 * BP2-BP0: 0 - NO PROTECTION, 1 - UPPER 1/16, 2 - UPPER 1/8, 3 - UPPER 1/4
+		 *                4 - UPPER 1/2. 5 to 7 - ALL BLOCKS
+		 */
+
+		if (ulStatus) {
+			if ((uiOffset+uiLength) <= 0x80000) {
+				/*
+				 * Offset comes in lower half of 1MB. Protect the upper half.
+				 * Clear BP1 and BP0 and set BP2.
+				 */
 				ulWriteStatus |= (0x4<<2);
 				ulWriteStatus &= ~(0x3<<2);
-			}
-			else if((uiOffset+uiLength) <= 0xC0000)
-			{
-			//
-			// Offset comes below Upper 1/4. Upper 1/4 can be protected.
-			//  Clear BP2 and set BP1 and BP0.
-			//
+			} else if ((uiOffset + uiLength) <= 0xC0000) {
+				/*
+				 * Offset comes below Upper 1/4. Upper 1/4 can be protected.
+				 *  Clear BP2 and set BP1 and BP0.
+				 */
 				ulWriteStatus |= (0x3<<2);
 				ulWriteStatus &= ~(0x1<<4);
+			} else if ((uiOffset + uiLength) <= 0xE0000) {
+				/*
+				 * Offset comes below Upper 1/8. Upper 1/8 can be protected.
+				 * Clear BP2 and BP0  and set BP1
+				 */
+				ulWriteStatus |= (0x1<<3);
+				ulWriteStatus &= ~(0x5<<2);
+			} else if ((uiOffset + uiLength) <= 0xF0000) {
+				/*
+				 * Offset comes below Upper 1/16. Only upper 1/16 can be protected.
+				 * Set BP0 and Clear BP2,BP1.
+				 */
+				ulWriteStatus |= (0x1<<2);
+				ulWriteStatus &= ~(0x3<<3);
+			} else {
+				/*
+				 * Unblock all.
+				 * Clear BP2,BP1 and BP0.
+				 */
+				ulWriteStatus &= ~(0x7<<2);
 			}
-			else if((uiOffset+uiLength) <= 0xE0000)
-		    {
-		    //
-		    // Offset comes below Upper 1/8. Upper 1/8 can be protected.
-		    // Clear BP2 and BP0  and set BP1
-		    //
-		    	ulWriteStatus |= (0x1<<3);
-		    	ulWriteStatus &= ~(0x5<<2);
-
-		    }
-		    else if((uiOffset+uiLength) <= 0xF0000)
-		    {
-		    //
-		    // Offset comes below Upper 1/16. Only upper 1/16 can be protected.
-		    // Set BP0 and Clear BP2,BP1.
-		    //
-		    	ulWriteStatus |= (0x1<<2);
-		    	ulWriteStatus &= ~(0x3<<3);
-		    }
-		    else
-		    {
-		    //
-		    // Unblock all.
-		    // Clear BP2,BP1 and BP0.
-		    //
-		    	ulWriteStatus &= ~(0x7<<2);
-		    }
-
-			value = (FLASH_CMD_WRITE_ENABLE<< 24);
+
+			value = (FLASH_CMD_WRITE_ENABLE << 24);
 			wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value));
 			udelay(20);
-			value = (FLASH_CMD_STATUS_REG_WRITE<<24)|(ulWriteStatus << 16);
+			value = (FLASH_CMD_STATUS_REG_WRITE << 24) | (ulWriteStatus << 16);
 			wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value));
 			udelay(20);
-
 		}
-
 	}
 	return ulStatus;
 }
-//-----------------------------------------------------------------------------
-// Procedure:	BeceemFlashBulkWrite
-//
-// Description: Performs write to the flash
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//		pBuffer 	- Data to be written.
-//		uiOffset   - Offset of the flash where data needs to be written to.
-//		uiNumBytes - Number of bytes to be written.
-//		bVerify    - read verify flag.
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-
-static INT BeceemFlashBulkWrite(
-	PMINI_ADAPTER Adapter,
-	PUINT pBuffer,
-	UINT uiOffset,
-	UINT uiNumBytes,
-	BOOLEAN bVerify)
+
+/*
+ * Procedure:	BeceemFlashBulkWrite
+ *
+ * Description: Performs write to the flash
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ * pBuffer - Data to be written.
+ *		uiOffset   - Offset of the flash where data needs to be written to.
+ *		uiNumBytes - Number of bytes to be written.
+ *		bVerify    - read verify flag.
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+
+static int BeceemFlashBulkWrite(struct bcm_mini_adapter *Adapter,
+				PUINT pBuffer,
+				unsigned int uiOffset,
+				unsigned int uiNumBytes,
+				BOOLEAN bVerify)
 {
-	PCHAR  pTempBuff 			= NULL;
-	PUCHAR pcBuffer             = (PUCHAR)pBuffer;
-	UINT  uiIndex				= 0;
-	UINT  uiOffsetFromSectStart = 0;
-	UINT  uiSectAlignAddr		= 0;
-	UINT  uiCurrSectOffsetAddr	= 0;
-	UINT  uiSectBoundary		= 0;
-	UINT  uiNumSectTobeRead 	= 0;
-	UCHAR ucReadBk[16]       	= {0};
-	ULONG ulStatus              = 0;
-	INT Status 					= STATUS_SUCCESS;
-	UINT uiTemp 				= 0;
-	UINT index 					= 0;
-	UINT uiPartOffset 			= 0;
-
-#if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
-  Status = bcmflash_raw_write((uiOffset/FLASH_PART_SIZE),(uiOffset % FLASH_PART_SIZE),( unsigned char *)pBuffer,uiNumBytes);
-  return Status;
-#endif
-
-	uiOffsetFromSectStart 	= uiOffset & ~(Adapter->uiSectorSize - 1);
-
-	//Adding flash Base address
-//	uiOffset = uiOffset + GetFlashBaseAddr(Adapter);
-
-	uiSectAlignAddr   		= uiOffset & ~(Adapter->uiSectorSize - 1);
-	uiCurrSectOffsetAddr	= uiOffset & (Adapter->uiSectorSize - 1);
-	uiSectBoundary	  		= uiSectAlignAddr + Adapter->uiSectorSize;
+	PCHAR pTempBuff			= NULL;
+	PUCHAR pcBuffer			= (PUCHAR)pBuffer;
+	unsigned int uiIndex			= 0;
+	unsigned int uiOffsetFromSectStart	= 0;
+	unsigned int uiSectAlignAddr		= 0;
+	unsigned int uiCurrSectOffsetAddr	= 0;
+	unsigned int uiSectBoundary		= 0;
+	unsigned int uiNumSectTobeRead		= 0;
+	UCHAR ucReadBk[16]		= {0};
+	ULONG ulStatus			= 0;
+	int Status			= STATUS_SUCCESS;
+	unsigned int uiTemp			= 0;
+	unsigned int index			= 0;
+	unsigned int uiPartOffset		= 0;
+
+	#if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
+		Status = bcmflash_raw_write((uiOffset / FLASH_PART_SIZE), (uiOffset % FLASH_PART_SIZE), (unsigned char *)pBuffer, uiNumBytes);
+		return Status;
+	#endif
+
+	uiOffsetFromSectStart = uiOffset & ~(Adapter->uiSectorSize - 1);
+
+	/* Adding flash Base address
+	 * uiOffset = uiOffset + GetFlashBaseAddr(Adapter);
+	 */
+
+	uiSectAlignAddr	= uiOffset & ~(Adapter->uiSectorSize - 1);
+	uiCurrSectOffsetAddr = uiOffset & (Adapter->uiSectorSize - 1);
+	uiSectBoundary = uiSectAlignAddr + Adapter->uiSectorSize;
 
 	pTempBuff = kmalloc(Adapter->uiSectorSize, GFP_KERNEL);
-	if(NULL == pTempBuff)
+	if (!pTempBuff)
 		goto BeceemFlashBulkWrite_EXIT;
-//
-// check if the data to be written is overlapped across sectors
-//
-	if(uiOffset+uiNumBytes < uiSectBoundary)
-	{
+	/*
+	 * check if the data to be written is overlapped across sectors
+	 */
+	if (uiOffset+uiNumBytes < uiSectBoundary) {
 		uiNumSectTobeRead = 1;
-	}
-	else
-	{
-		//      Number of sectors  = Last sector start address/First sector start address
-		uiNumSectTobeRead =  (uiCurrSectOffsetAddr+uiNumBytes)/Adapter->uiSectorSize;
-		if((uiCurrSectOffsetAddr+uiNumBytes)%Adapter->uiSectorSize)
-		{
+	} else {
+		/* Number of sectors  = Last sector start address/First sector start address */
+		uiNumSectTobeRead =  (uiCurrSectOffsetAddr + uiNumBytes) / Adapter->uiSectorSize;
+		if ((uiCurrSectOffsetAddr + uiNumBytes)%Adapter->uiSectorSize)
 			uiNumSectTobeRead++;
-		}
 	}
-	//Check whether Requested sector is writable or not in case of flash2x write. But if  write call is
-	// for DSD calibration, allow it without checking of sector permission
+	/* Check whether Requested sector is writable or not in case of flash2x write. But if  write call is
+	 * for DSD calibration, allow it without checking of sector permission
+	 */
 
-	if(IsFlash2x(Adapter) && (Adapter->bAllDSDWriteAllow == FALSE))
-	{
+	if (IsFlash2x(Adapter) && (Adapter->bAllDSDWriteAllow == FALSE)) {
 		index = 0;
-		uiTemp = uiNumSectTobeRead ;
-		while(uiTemp)
-		{
-			 if(IsOffsetWritable(Adapter, uiOffsetFromSectStart + index * Adapter->uiSectorSize ) == FALSE)
-			 {
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Sector Starting at offset <0X%X> is not writable",
-											(uiOffsetFromSectStart + index * Adapter->uiSectorSize));
+		uiTemp = uiNumSectTobeRead;
+		while (uiTemp) {
+			if (IsOffsetWritable(Adapter, uiOffsetFromSectStart + index * Adapter->uiSectorSize) == FALSE) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Sector Starting at offset <0X%X> is not writable",
+						(uiOffsetFromSectStart + index * Adapter->uiSectorSize));
 				Status = SECTOR_IS_NOT_WRITABLE;
 				goto BeceemFlashBulkWrite_EXIT;
-			 }
-			 uiTemp = uiTemp - 1;
-			 index = index + 1 ;
+			}
+			uiTemp = uiTemp - 1;
+			index = index + 1 ;
 		}
 	}
 	Adapter->SelectedChip = RESET_CHIP_SELECT;
-	while(uiNumSectTobeRead)
-	{
-		//do_gettimeofday(&tv1);
-		//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "\nTime In start of write :%ld ms\n",(tv1.tv_sec *1000 + tv1.tv_usec /1000));
+	while (uiNumSectTobeRead) {
+		/* do_gettimeofday(&tv1);
+		 * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "\nTime In start of write :%ld ms\n",(tv1.tv_sec *1000 + tv1.tv_usec /1000));
+		 */
 		uiPartOffset = (uiSectAlignAddr & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter);
 
-		BcmDoChipSelect(Adapter,uiSectAlignAddr);
+		BcmDoChipSelect(Adapter, uiSectAlignAddr);
 
-		if(0 != BeceemFlashBulkRead(Adapter,
+		if (0 != BeceemFlashBulkRead(Adapter,
 						(PUINT)pTempBuff,
 						uiOffsetFromSectStart,
-						Adapter->uiSectorSize))
-		{
+						Adapter->uiSectorSize)) {
 			Status = -1;
 			goto BeceemFlashBulkWrite_EXIT;
 		}
 
-		//do_gettimeofday(&tr);
-		//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken by Read :%ld ms\n", (tr.tv_sec *1000 + tr.tv_usec/1000) - (tv1.tv_sec *1000 + tv1.tv_usec/1000));
-
-		ulStatus = BcmFlashUnProtectBlock(Adapter,uiSectAlignAddr,Adapter->uiSectorSize);
-
-
-		if(uiNumSectTobeRead > 1)
-		{
-
-			memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
-			pcBuffer += ((uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)));
-			uiNumBytes -= (uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
-		}
-		else
-		{
-				memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes);
-		}
-
-		if(IsFlash2x(Adapter))
-		{
-			SaveHeaderIfPresent(Adapter,(PUCHAR)pTempBuff,uiOffsetFromSectStart);
+		/* do_gettimeofday(&tr);
+		 * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken by Read :%ld ms\n", (tr.tv_sec *1000 + tr.tv_usec/1000) - (tv1.tv_sec *1000 + tv1.tv_usec/1000));
+		 */
+		ulStatus = BcmFlashUnProtectBlock(Adapter, uiSectAlignAddr, Adapter->uiSectorSize);
+
+		if (uiNumSectTobeRead > 1) {
+			memcpy(&pTempBuff[uiCurrSectOffsetAddr], pcBuffer, uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr));
+			pcBuffer += ((uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr)));
+			uiNumBytes -= (uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr));
+		} else {
+			memcpy(&pTempBuff[uiCurrSectOffsetAddr], pcBuffer, uiNumBytes);
 		}
 
-		FlashSectorErase(Adapter,uiPartOffset,1);
-		//do_gettimeofday(&te);
-		//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken by Erase :%ld ms\n", (te.tv_sec *1000 + te.tv_usec/1000) - (tr.tv_sec *1000 + tr.tv_usec/1000));
+		if (IsFlash2x(Adapter))
+			SaveHeaderIfPresent(Adapter, (PUCHAR)pTempBuff, uiOffsetFromSectStart);
 
-		for(uiIndex = 0; uiIndex < Adapter->uiSectorSize; uiIndex +=Adapter->ulFlashWriteSize)
-		{
-			if(Adapter->device_removed)
-			{
+		FlashSectorErase(Adapter, uiPartOffset, 1);
+		/* do_gettimeofday(&te);
+		 * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken by Erase :%ld ms\n", (te.tv_sec *1000 + te.tv_usec/1000) - (tr.tv_sec *1000 + tr.tv_usec/1000));
+		 */
+		for (uiIndex = 0; uiIndex < Adapter->uiSectorSize; uiIndex += Adapter->ulFlashWriteSize) {
+			if (Adapter->device_removed) {
 				Status = -1;
 				goto BeceemFlashBulkWrite_EXIT;
 			}
-			if(STATUS_SUCCESS != (*Adapter->fpFlashWrite)(Adapter,uiPartOffset+uiIndex,(&pTempBuff[uiIndex])))
-			{
+
+			if (STATUS_SUCCESS != (*Adapter->fpFlashWrite)(Adapter, uiPartOffset + uiIndex, (&pTempBuff[uiIndex]))) {
 				Status = -1;
 				goto BeceemFlashBulkWrite_EXIT;
 			}
 		}
 
-		//do_gettimeofday(&tw);
-		//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken in Write  to Flash :%ld ms\n", (tw.tv_sec *1000 + tw.tv_usec/1000) - (te.tv_sec *1000 + te.tv_usec/1000));
-		for(uiIndex = 0;uiIndex < Adapter->uiSectorSize;uiIndex += MAX_RW_SIZE)
-		{
-			if(STATUS_SUCCESS == BeceemFlashBulkRead(Adapter,(PUINT)ucReadBk,uiOffsetFromSectStart+uiIndex,MAX_RW_SIZE))
-			{
-				if(Adapter->ulFlashWriteSize == 1)
-				{
-					UINT uiReadIndex = 0;
-					for(uiReadIndex = 0; uiReadIndex < 16; uiReadIndex++)
-					{
-						if(ucReadBk[uiReadIndex] != pTempBuff[uiIndex+uiReadIndex])
-						{
-							if(STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter,uiPartOffset+uiIndex+uiReadIndex,&pTempBuff[uiIndex+uiReadIndex]))
-							{
+		/* do_gettimeofday(&tw);
+		 * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken in Write  to Flash :%ld ms\n", (tw.tv_sec *1000 + tw.tv_usec/1000) - (te.tv_sec *1000 + te.tv_usec/1000));
+		 */
+		for (uiIndex = 0; uiIndex < Adapter->uiSectorSize; uiIndex += MAX_RW_SIZE) {
+			if (STATUS_SUCCESS == BeceemFlashBulkRead(Adapter, (PUINT)ucReadBk, uiOffsetFromSectStart + uiIndex, MAX_RW_SIZE)) {
+				if (Adapter->ulFlashWriteSize == 1) {
+					unsigned int uiReadIndex = 0;
+					for (uiReadIndex = 0; uiReadIndex < 16; uiReadIndex++) {
+						if (ucReadBk[uiReadIndex] != pTempBuff[uiIndex + uiReadIndex]) {
+							if (STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter, uiPartOffset + uiIndex + uiReadIndex, &pTempBuff[uiIndex+uiReadIndex])) {
 								Status = STATUS_FAILURE;
 								goto BeceemFlashBulkWrite_EXIT;
 							}
 						}
 					}
-				}
-				else
-				{
-					if(memcmp(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE))
-					{
-						if(STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter,uiPartOffset+uiIndex,&pTempBuff[uiIndex]))
-						{
+				} else {
+					if (memcmp(ucReadBk, &pTempBuff[uiIndex], MAX_RW_SIZE)) {
+						if (STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter, uiPartOffset + uiIndex, &pTempBuff[uiIndex])) {
 							Status = STATUS_FAILURE;
 							goto BeceemFlashBulkWrite_EXIT;
 						}
@@ -1313,13 +1172,11 @@ static INT BeceemFlashBulkWrite(
 				}
 			}
 		}
-		//do_gettimeofday(&twv);
-		//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken in Write  to Flash verification :%ld ms\n", (twv.tv_sec *1000 + twv.tv_usec/1000) - (tw.tv_sec *1000 + tw.tv_usec/1000));
-
-
-		if(ulStatus)
-		{
-			BcmRestoreBlockProtectStatus(Adapter,ulStatus);
+		/* do_gettimeofday(&twv);
+		 * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken in Write  to Flash verification :%ld ms\n", (twv.tv_sec *1000 + twv.tv_usec/1000) - (tw.tv_sec *1000 + tw.tv_usec/1000));
+		 */
+		if (ulStatus) {
+			BcmRestoreBlockProtectStatus(Adapter, ulStatus);
 			ulStatus = 0;
 		}
 
@@ -1329,185 +1186,153 @@ static INT BeceemFlashBulkWrite(
 		uiOffsetFromSectStart += Adapter->uiSectorSize;
 		uiNumSectTobeRead--;
 	}
-	//do_gettimeofday(&tv2);
-	//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Time after Write :%ld ms\n",(tv2.tv_sec *1000 + tv2.tv_usec/1000));
-	//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken by in Write is :%ld ms\n", (tv2.tv_sec *1000 + tv2.tv_usec/1000) - (tv1.tv_sec *1000 + tv1.tv_usec/1000));
-//
-// Cleanup.
-//
+	/* do_gettimeofday(&tv2);
+	 * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Time after Write :%ld ms\n",(tv2.tv_sec *1000 + tv2.tv_usec/1000));
+	 * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken by in Write is :%ld ms\n", (tv2.tv_sec *1000 + tv2.tv_usec/1000) - (tv1.tv_sec *1000 + tv1.tv_usec/1000));
+	 *
+	 * Cleanup.
+	 */
 BeceemFlashBulkWrite_EXIT:
-	if(ulStatus)
-	{
-		BcmRestoreBlockProtectStatus(Adapter,ulStatus);
-	}
-	
+	if (ulStatus)
+		BcmRestoreBlockProtectStatus(Adapter, ulStatus);
+
 	kfree(pTempBuff);
 
 	Adapter->SelectedChip = RESET_CHIP_SELECT;
 	return Status;
 }
 
-
-//-----------------------------------------------------------------------------
-// Procedure:	BeceemFlashBulkWriteStatus
-//
-// Description: Writes to Flash. Checks the SPI status after each write.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//		pBuffer 	- Data to be written.
-//		uiOffset   - Offset of the flash where data needs to be written to.
-//		uiNumBytes - Number of bytes to be written.
-//		bVerify    - read verify flag.
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-
-static INT BeceemFlashBulkWriteStatus(
-	PMINI_ADAPTER Adapter,
-	PUINT pBuffer,
-	UINT uiOffset,
-	UINT uiNumBytes,
-	BOOLEAN bVerify)
+/*
+ * Procedure:	BeceemFlashBulkWriteStatus
+ *
+ * Description: Writes to Flash. Checks the SPI status after each write.
+ *
+ * Arguments:
+ *		Adapter		- ptr to Adapter object instance
+ *		pBuffer		- Data to be written.
+ *		uiOffset	- Offset of the flash where data needs to be written to.
+ *		uiNumBytes	- Number of bytes to be written.
+ *		bVerify		- read verify flag.
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+
+static int BeceemFlashBulkWriteStatus(struct bcm_mini_adapter *Adapter,
+				PUINT pBuffer,
+				unsigned int uiOffset,
+				unsigned int uiNumBytes,
+				BOOLEAN bVerify)
 {
-	PCHAR  pTempBuff 			= NULL;
-	PUCHAR pcBuffer             = (PUCHAR)pBuffer;
-	UINT  uiIndex				= 0;
-	UINT  uiOffsetFromSectStart = 0;
-	UINT  uiSectAlignAddr		= 0;
-	UINT  uiCurrSectOffsetAddr	= 0;
-	UINT  uiSectBoundary		= 0;
-	UINT  uiNumSectTobeRead 	= 0;
-	UCHAR ucReadBk[16]			= {0};
-	ULONG ulStatus              = 0;
-	UINT  Status				= STATUS_SUCCESS;
-	UINT uiTemp 				= 0;
-	UINT index 					= 0;
-	UINT uiPartOffset			= 0;
-
-	uiOffsetFromSectStart 	= uiOffset & ~(Adapter->uiSectorSize - 1);
-
-	//uiOffset += Adapter->ulFlashCalStart;
-	//Adding flash Base address
-//	uiOffset = uiOffset + GetFlashBaseAddr(Adapter);
-
-	uiSectAlignAddr 		= uiOffset & ~(Adapter->uiSectorSize - 1);
-	uiCurrSectOffsetAddr	= uiOffset & (Adapter->uiSectorSize - 1);
-	uiSectBoundary			= uiSectAlignAddr + Adapter->uiSectorSize;
+	PCHAR pTempBuff			= NULL;
+	PUCHAR pcBuffer			= (PUCHAR)pBuffer;
+	unsigned int uiIndex			= 0;
+	unsigned int uiOffsetFromSectStart	= 0;
+	unsigned int uiSectAlignAddr		= 0;
+	unsigned int uiCurrSectOffsetAddr	= 0;
+	unsigned int uiSectBoundary		= 0;
+	unsigned int uiNumSectTobeRead		= 0;
+	UCHAR ucReadBk[16]		= {0};
+	ULONG ulStatus			= 0;
+	unsigned int Status			= STATUS_SUCCESS;
+	unsigned int uiTemp			= 0;
+	unsigned int index			= 0;
+	unsigned int uiPartOffset		= 0;
+
+	uiOffsetFromSectStart = uiOffset & ~(Adapter->uiSectorSize - 1);
+
+	/* uiOffset += Adapter->ulFlashCalStart;
+	 * Adding flash Base address
+	 * uiOffset = uiOffset + GetFlashBaseAddr(Adapter);
+	 */
+	uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize - 1);
+	uiCurrSectOffsetAddr = uiOffset & (Adapter->uiSectorSize - 1);
+	uiSectBoundary = uiSectAlignAddr + Adapter->uiSectorSize;
 
 	pTempBuff = kmalloc(Adapter->uiSectorSize, GFP_KERNEL);
-	if(NULL == pTempBuff)
+	if (!pTempBuff)
 		goto BeceemFlashBulkWriteStatus_EXIT;
 
-//
-// check if the data to be written is overlapped across sectors
-//
-	if(uiOffset+uiNumBytes < uiSectBoundary)
-	{
+	/*
+	 * check if the data to be written is overlapped across sectors
+	 */
+	if (uiOffset+uiNumBytes < uiSectBoundary) {
 		uiNumSectTobeRead = 1;
-	}
-	else
-	{
-//      Number of sectors  = Last sector start address/First sector start address
-		uiNumSectTobeRead =  (uiCurrSectOffsetAddr+uiNumBytes)/Adapter->uiSectorSize;
-		if((uiCurrSectOffsetAddr+uiNumBytes)%Adapter->uiSectorSize)
-		{
+	} else {
+		/* Number of sectors  = Last sector start address/First sector start address */
+		uiNumSectTobeRead =  (uiCurrSectOffsetAddr + uiNumBytes) / Adapter->uiSectorSize;
+		if ((uiCurrSectOffsetAddr + uiNumBytes)%Adapter->uiSectorSize)
 			uiNumSectTobeRead++;
-		}
 	}
 
-	if(IsFlash2x(Adapter) && (Adapter->bAllDSDWriteAllow == FALSE))
-	{
+	if (IsFlash2x(Adapter) && (Adapter->bAllDSDWriteAllow == FALSE)) {
 		index = 0;
-		uiTemp = uiNumSectTobeRead ;
-		while(uiTemp)
-		{
-			 if(IsOffsetWritable(Adapter,uiOffsetFromSectStart + index * Adapter->uiSectorSize ) == FALSE)
-			 {
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Sector Starting at offset <0X%x> is not writable",
-											(uiOffsetFromSectStart + index * Adapter->uiSectorSize));
+		uiTemp = uiNumSectTobeRead;
+		while (uiTemp) {
+			if (IsOffsetWritable(Adapter, uiOffsetFromSectStart + index * Adapter->uiSectorSize) == FALSE) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Sector Starting at offset <0X%x> is not writable",
+						(uiOffsetFromSectStart + index * Adapter->uiSectorSize));
 				Status = SECTOR_IS_NOT_WRITABLE;
 				goto BeceemFlashBulkWriteStatus_EXIT;
-			 }
-			 uiTemp = uiTemp - 1;
-			 index = index + 1 ;
+			}
+			uiTemp = uiTemp - 1;
+			index = index + 1 ;
 		}
 	}
 
 	Adapter->SelectedChip = RESET_CHIP_SELECT;
-	while(uiNumSectTobeRead)
-	{
+	while (uiNumSectTobeRead) {
 		uiPartOffset = (uiSectAlignAddr & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter);
 
-		BcmDoChipSelect(Adapter,uiSectAlignAddr);
-		if(0 != BeceemFlashBulkRead(Adapter,
+		BcmDoChipSelect(Adapter, uiSectAlignAddr);
+		if (0 != BeceemFlashBulkRead(Adapter,
 						(PUINT)pTempBuff,
 						uiOffsetFromSectStart,
-						Adapter->uiSectorSize))
-		{
+						Adapter->uiSectorSize))	{
 			Status = -1;
 			goto BeceemFlashBulkWriteStatus_EXIT;
 		}
 
-		ulStatus = BcmFlashUnProtectBlock(Adapter,uiOffsetFromSectStart,Adapter->uiSectorSize);
-
-		if(uiNumSectTobeRead > 1)
-		{
-
-			memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
-			pcBuffer += ((uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)));
-			uiNumBytes -= (uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
-		}
-		else
-		{
-			memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes);
-		}
+		ulStatus = BcmFlashUnProtectBlock(Adapter, uiOffsetFromSectStart, Adapter->uiSectorSize);
 
-		if(IsFlash2x(Adapter))
-		{
-			SaveHeaderIfPresent(Adapter,(PUCHAR)pTempBuff,uiOffsetFromSectStart);
+		if (uiNumSectTobeRead > 1) {
+			memcpy(&pTempBuff[uiCurrSectOffsetAddr], pcBuffer, uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr));
+			pcBuffer += ((uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr)));
+			uiNumBytes -= (uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr));
+		} else {
+			memcpy(&pTempBuff[uiCurrSectOffsetAddr], pcBuffer, uiNumBytes);
 		}
 
-		FlashSectorErase(Adapter,uiPartOffset,1);
+		if (IsFlash2x(Adapter))
+			SaveHeaderIfPresent(Adapter, (PUCHAR)pTempBuff, uiOffsetFromSectStart);
 
-		for(uiIndex = 0; uiIndex < Adapter->uiSectorSize; uiIndex +=Adapter->ulFlashWriteSize)
+		FlashSectorErase(Adapter, uiPartOffset, 1);
 
-		{
-			if(Adapter->device_removed)
-			{
+		for (uiIndex = 0; uiIndex < Adapter->uiSectorSize; uiIndex += Adapter->ulFlashWriteSize) {
+			if (Adapter->device_removed) {
 				Status = -1;
 				goto BeceemFlashBulkWriteStatus_EXIT;
 			}
 
-			if(STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter,uiPartOffset+uiIndex,&pTempBuff[uiIndex]))
-			{
+			if (STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter, uiPartOffset+uiIndex, &pTempBuff[uiIndex])) {
 				Status = -1;
 				goto BeceemFlashBulkWriteStatus_EXIT;
 			}
 		}
 
-		if(bVerify)
-		{
-			for(uiIndex = 0;uiIndex < Adapter->uiSectorSize;uiIndex += MAX_RW_SIZE)
-			{
-
-				if(STATUS_SUCCESS == BeceemFlashBulkRead(Adapter,(PUINT)ucReadBk,uiOffsetFromSectStart+uiIndex,MAX_RW_SIZE))
-				{
-					if(memcmp(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE))
-					{
+		if (bVerify) {
+			for (uiIndex = 0; uiIndex < Adapter->uiSectorSize; uiIndex += MAX_RW_SIZE) {
+				if (STATUS_SUCCESS == BeceemFlashBulkRead(Adapter, (PUINT)ucReadBk, uiOffsetFromSectStart + uiIndex, MAX_RW_SIZE)) {
+					if (memcmp(ucReadBk, &pTempBuff[uiIndex], MAX_RW_SIZE)) {
 						Status = STATUS_FAILURE;
 						goto BeceemFlashBulkWriteStatus_EXIT;
 					}
-
 				}
-
 			}
 		}
 
-		if(ulStatus)
-		{
-			BcmRestoreBlockProtectStatus(Adapter,ulStatus);
+		if (ulStatus) {
+			BcmRestoreBlockProtectStatus(Adapter, ulStatus);
 			ulStatus = 0;
 		}
 
@@ -1517,265 +1342,231 @@ static INT BeceemFlashBulkWriteStatus(
 		uiOffsetFromSectStart += Adapter->uiSectorSize;
 		uiNumSectTobeRead--;
 	}
-//
-// Cleanup.
-//
+/*
+ * Cleanup.
+ */
 BeceemFlashBulkWriteStatus_EXIT:
-	if(ulStatus)
-	{
-		BcmRestoreBlockProtectStatus(Adapter,ulStatus);
-	}
+	if (ulStatus)
+		BcmRestoreBlockProtectStatus(Adapter, ulStatus);
 
 	kfree(pTempBuff);
 	Adapter->SelectedChip = RESET_CHIP_SELECT;
 	return Status;
-
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	PropagateCalParamsFromEEPROMToMemory
-//
-// Description: Dumps the calibration section of EEPROM to DDR.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-
-
-INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter)
+/*
+ * Procedure:	PropagateCalParamsFromEEPROMToMemory
+ *
+ * Description: Dumps the calibration section of EEPROM to DDR.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+
+int PropagateCalParamsFromEEPROMToMemory(struct bcm_mini_adapter *Adapter)
 {
 	PCHAR pBuff = kmalloc(BUFFER_4K, GFP_KERNEL);
-	UINT uiEepromSize = 0;
-	UINT uiIndex = 0;
-	UINT uiBytesToCopy = 0;
-	UINT uiCalStartAddr = EEPROM_CALPARAM_START;
-	UINT uiMemoryLoc = EEPROM_CAL_DATA_INTERNAL_LOC;
-	UINT value;
-	INT Status = 0;
-	if(pBuff == NULL)
-	{
-		return -1;
-	}
-
-	if(0 != BeceemEEPROMBulkRead(Adapter,&uiEepromSize,EEPROM_SIZE_OFFSET,4))
-	{
+	unsigned int uiEepromSize = 0;
+	unsigned int uiIndex = 0;
+	unsigned int uiBytesToCopy = 0;
+	unsigned int uiCalStartAddr = EEPROM_CALPARAM_START;
+	unsigned int uiMemoryLoc = EEPROM_CAL_DATA_INTERNAL_LOC;
+	unsigned int value;
+	int Status = 0;
+
+	if (!pBuff)
+		return -ENOMEM;
 
+	if (0 != BeceemEEPROMBulkRead(Adapter, &uiEepromSize, EEPROM_SIZE_OFFSET, 4)) {
 		kfree(pBuff);
 		return -1;
 	}
 
 	uiEepromSize >>= 16;
-	if(uiEepromSize > 1024*1024)
-	{
+	if (uiEepromSize > 1024 * 1024) {
 		kfree(pBuff);
 		return -1;
 	}
 
+	uiBytesToCopy = MIN(BUFFER_4K, uiEepromSize);
 
-	uiBytesToCopy = MIN(BUFFER_4K,uiEepromSize);
-
-	while(uiBytesToCopy)
-	{
-		if(0 != BeceemEEPROMBulkRead(Adapter,(PUINT)pBuff,uiCalStartAddr,uiBytesToCopy))
-		{
+	while (uiBytesToCopy) {
+		if (0 != BeceemEEPROMBulkRead(Adapter, (PUINT)pBuff, uiCalStartAddr, uiBytesToCopy)) {
 			Status = -1;
 			break;
 		}
-		wrm(Adapter,uiMemoryLoc,(PCHAR)(((PULONG)pBuff)+uiIndex),uiBytesToCopy);
+		wrm(Adapter, uiMemoryLoc, (PCHAR)(((PULONG)pBuff) + uiIndex), uiBytesToCopy);
 		uiMemoryLoc += uiBytesToCopy;
 		uiEepromSize -= uiBytesToCopy;
 		uiCalStartAddr += uiBytesToCopy;
-		uiIndex += uiBytesToCopy/4;
-		uiBytesToCopy = MIN(BUFFER_4K,uiEepromSize);
+		uiIndex += uiBytesToCopy / 4;
+		uiBytesToCopy = MIN(BUFFER_4K, uiEepromSize);
 
 	}
 	value = 0xbeadbead;
-	wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC-4,&value, sizeof(value));
+	wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 4, &value, sizeof(value));
 	value = 0xbeadbead;
-	wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC-8,&value, sizeof(value));
+	wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 8, &value, sizeof(value));
 	kfree(pBuff);
 
 	return Status;
-
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	PropagateCalParamsFromFlashToMemory
-//
-// Description: Dumps the calibration section of EEPROM to DDR.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-
-INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter)
+/*
+ * Procedure:	PropagateCalParamsFromFlashToMemory
+ *
+ * Description: Dumps the calibration section of EEPROM to DDR.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+
+int PropagateCalParamsFromFlashToMemory(struct bcm_mini_adapter *Adapter)
 {
 	PCHAR pBuff, pPtr;
-	UINT uiEepromSize = 0;
-	UINT uiBytesToCopy = 0;
-	//UINT uiIndex = 0;
-	UINT uiCalStartAddr = EEPROM_CALPARAM_START;
-	UINT uiMemoryLoc = EEPROM_CAL_DATA_INTERNAL_LOC;
-	UINT value;
-	INT Status = 0;
-//
-// Write the signature first. This will ensure firmware does not access EEPROM.
-//
+	unsigned int uiEepromSize = 0;
+	unsigned int uiBytesToCopy = 0;
+	/* unsigned int uiIndex = 0; */
+	unsigned int uiCalStartAddr = EEPROM_CALPARAM_START;
+	unsigned int uiMemoryLoc = EEPROM_CAL_DATA_INTERNAL_LOC;
+	unsigned int value;
+	int Status = 0;
+
+	/*
+	 * Write the signature first. This will ensure firmware does not access EEPROM.
+	 */
 	value = 0xbeadbead;
 	wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 4, &value, sizeof(value));
 	value = 0xbeadbead;
 	wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 8, &value, sizeof(value));
 
-	if(0 != BeceemNVMRead(Adapter,&uiEepromSize,EEPROM_SIZE_OFFSET, 4))
-	{
+	if (0 != BeceemNVMRead(Adapter, &uiEepromSize, EEPROM_SIZE_OFFSET, 4))
 		return -1;
-	}
+
 	uiEepromSize = ntohl(uiEepromSize);
 	uiEepromSize >>= 16;
 
-//
-//	subtract the auto init section size
-//
+	/*
+	 * subtract the auto init section size
+	 */
 	uiEepromSize -= EEPROM_CALPARAM_START;
 
-	if(uiEepromSize > 1024*1024)
-	{
+	if (uiEepromSize > 1024 * 1024)
 		return -1;
-	}
 
 	pBuff = kmalloc(uiEepromSize, GFP_KERNEL);
-	if ( pBuff == NULL )
-		return -1;
+	if (pBuff == NULL)
+		return -ENOMEM;
 
-	if(0 != BeceemNVMRead(Adapter,(PUINT)pBuff,uiCalStartAddr, uiEepromSize))
-	{
+	if (0 != BeceemNVMRead(Adapter, (PUINT)pBuff, uiCalStartAddr, uiEepromSize)) {
 		kfree(pBuff);
 		return -1;
 	}
 
 	pPtr = pBuff;
 
-	uiBytesToCopy = MIN(BUFFER_4K,uiEepromSize);
+	uiBytesToCopy = MIN(BUFFER_4K, uiEepromSize);
 
-	while(uiBytesToCopy)
-	{
-		Status = wrm(Adapter,uiMemoryLoc,(PCHAR)pPtr,uiBytesToCopy);
-		if(Status)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"wrm failed with status :%d",Status);
+	while (uiBytesToCopy) {
+		Status = wrm(Adapter, uiMemoryLoc, (PCHAR)pPtr, uiBytesToCopy);
+		if (Status) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "wrm failed with status :%d", Status);
 			break;
 		}
 
 		pPtr += uiBytesToCopy;
 		uiEepromSize -= uiBytesToCopy;
 		uiMemoryLoc += uiBytesToCopy;
-		uiBytesToCopy = MIN(BUFFER_4K,uiEepromSize);
+		uiBytesToCopy = MIN(BUFFER_4K, uiEepromSize);
 	}
 
 	kfree(pBuff);
 	return Status;
-
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BeceemEEPROMReadBackandVerify
-//
-// Description: Read back the data written and verifies.
-//
-// Arguments:
-//		Adapter       - ptr to Adapter object instance
-//		pBuffer 	    - Data to be written.
-//		uiOffset       - Offset of the flash where data needs to be written to.
-//		uiNumBytes - Number of bytes to be written.
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-
-static INT BeceemEEPROMReadBackandVerify(
-	PMINI_ADAPTER Adapter,
-	PUINT pBuffer,
-	UINT uiOffset,
-	UINT uiNumBytes)
+/*
+ * Procedure:	BeceemEEPROMReadBackandVerify
+ *
+ * Description: Read back the data written and verifies.
+ *
+ * Arguments:
+ *		Adapter		- ptr to Adapter object instance
+ *		pBuffer		- Data to be written.
+ *		uiOffset	- Offset of the flash where data needs to be written to.
+ *		uiNumBytes	- Number of bytes to be written.
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+
+static int BeceemEEPROMReadBackandVerify(struct bcm_mini_adapter *Adapter,
+					PUINT pBuffer,
+					unsigned int uiOffset,
+					unsigned int uiNumBytes)
 {
-	UINT uiRdbk  	= 0;
-	UINT uiIndex 	= 0;
-	UINT uiData  	= 0;
-	UINT auiData[4] = {0};
+	unsigned int uiRdbk	= 0;
+	unsigned int uiIndex	= 0;
+	unsigned int uiData	= 0;
+	unsigned int auiData[4]	= {0};
 
-	while(uiNumBytes)
-	{
-		if(Adapter->device_removed )
-		{
+	while (uiNumBytes) {
+		if (Adapter->device_removed)
 			return -1;
-		}
 
-		if(uiNumBytes >= MAX_RW_SIZE)
-		{// for the requests more than or equal to MAX_RW_SIZE bytes, use bulk read function to make the access faster.
-			BeceemEEPROMBulkRead(Adapter,&auiData[0],uiOffset,MAX_RW_SIZE);
+		if (uiNumBytes >= MAX_RW_SIZE) {
+			/* for the requests more than or equal to MAX_RW_SIZE bytes, use bulk read function to make the access faster. */
+			BeceemEEPROMBulkRead(Adapter, &auiData[0], uiOffset, MAX_RW_SIZE);
 
-			if(memcmp(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE))
-			{
-				// re-write
-				BeceemEEPROMBulkWrite(Adapter,(PUCHAR)(pBuffer+uiIndex),uiOffset,MAX_RW_SIZE,FALSE);
+			if (memcmp(&pBuffer[uiIndex], &auiData[0], MAX_RW_SIZE)) {
+				/* re-write */
+				BeceemEEPROMBulkWrite(Adapter, (PUCHAR)(pBuffer + uiIndex), uiOffset, MAX_RW_SIZE, FALSE);
 				mdelay(3);
-				BeceemEEPROMBulkRead(Adapter,&auiData[0],uiOffset,MAX_RW_SIZE);
+				BeceemEEPROMBulkRead(Adapter, &auiData[0], uiOffset, MAX_RW_SIZE);
 
-				if(memcmp(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE))
-				{
+				if (memcmp(&pBuffer[uiIndex], &auiData[0], MAX_RW_SIZE))
 					return -1;
-				}
 			}
 			uiOffset += MAX_RW_SIZE;
 			uiNumBytes -= MAX_RW_SIZE;
 			uiIndex += 4;
-
-		}
-		else if(uiNumBytes >= 4)
-		{
-			BeceemEEPROMBulkRead(Adapter,&uiData,uiOffset,4);
-			if(uiData != pBuffer[uiIndex])
-			{
-				//re-write
-				BeceemEEPROMBulkWrite(Adapter,(PUCHAR)(pBuffer+uiIndex),uiOffset,4,FALSE);
+		} else if (uiNumBytes >= 4) {
+			BeceemEEPROMBulkRead(Adapter, &uiData, uiOffset, 4);
+			if (uiData != pBuffer[uiIndex]) {
+				/* re-write */
+				BeceemEEPROMBulkWrite(Adapter, (PUCHAR)(pBuffer + uiIndex), uiOffset, 4, FALSE);
 				mdelay(3);
-				BeceemEEPROMBulkRead(Adapter,&uiData,uiOffset,4);
-				if(uiData != pBuffer[uiIndex])
-				{
+				BeceemEEPROMBulkRead(Adapter, &uiData, uiOffset, 4);
+				if (uiData != pBuffer[uiIndex])
 					return -1;
-				}
 			}
 			uiOffset += 4;
 			uiNumBytes -= 4;
 			uiIndex++;
-
-		}
-		else
-		{ // Handle the reads less than 4 bytes...
+		} else {
+			/* Handle the reads less than 4 bytes... */
 			uiData = 0;
-			memcpy(&uiData,((PUCHAR)pBuffer)+(uiIndex*sizeof(UINT)),uiNumBytes);
-			BeceemEEPROMBulkRead(Adapter,&uiRdbk,uiOffset,4);
+			memcpy(&uiData, ((PUCHAR)pBuffer) + (uiIndex * sizeof(unsigned int)), uiNumBytes);
+			BeceemEEPROMBulkRead(Adapter, &uiRdbk, uiOffset, 4);
 
-			if(memcmp(&uiData, &uiRdbk, uiNumBytes))
+			if (memcmp(&uiData, &uiRdbk, uiNumBytes))
 				return -1;
 
 			uiNumBytes = 0;
 		}
-
 	}
 
 	return 0;
 }
 
-static VOID BcmSwapWord(UINT *ptr1) {
-
-	UINT  tempval = (UINT)*ptr1;
+static VOID BcmSwapWord(unsigned int *ptr1)
+{
+	unsigned int tempval = (unsigned int)*ptr1;
 	char *ptr2 = (char *)&tempval;
 	char *ptr = (char *)ptr1;
 
@@ -1785,495 +1576,436 @@ static VOID BcmSwapWord(UINT *ptr1) {
 	ptr[3] = ptr2[0];
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BeceemEEPROMWritePage
-//
-// Description: Performs page write (16bytes) to the EEPROM
-//
-// Arguments:
-//		Adapter       - ptr to Adapter object instance
-//		uiData 	  	  - Data to be written.
-//		uiOffset      - Offset of the EEPROM where data needs to be written to.
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-static INT BeceemEEPROMWritePage( PMINI_ADAPTER Adapter, UINT uiData[], UINT uiOffset )
+/*
+ * Procedure:	BeceemEEPROMWritePage
+ *
+ * Description: Performs page write (16bytes) to the EEPROM
+ *
+ * Arguments:
+ *		Adapter		- ptr to Adapter object instance
+ *		uiData		- Data to be written.
+ *		uiOffset	- Offset of the EEPROM where data needs to be written to.
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+
+static int BeceemEEPROMWritePage(struct bcm_mini_adapter *Adapter, unsigned int uiData[], unsigned int uiOffset)
 {
-	UINT uiRetries = MAX_EEPROM_RETRIES*RETRIES_PER_DELAY;
-	UINT uiStatus = 0;
+	unsigned int uiRetries = MAX_EEPROM_RETRIES * RETRIES_PER_DELAY;
+	unsigned int uiStatus = 0;
 	UCHAR uiEpromStatus = 0;
-	UINT value =0 ;
+	unsigned int value = 0;
 
 	/* Flush the Write/Read/Cmd queues. */
-	value = ( EEPROM_WRITE_QUEUE_FLUSH | EEPROM_CMD_QUEUE_FLUSH | EEPROM_READ_QUEUE_FLUSH );
-	wrmalt( Adapter, SPI_FLUSH_REG, &value, sizeof(value));
-	value = 0 ;
-	wrmalt( Adapter, SPI_FLUSH_REG, &value, sizeof(value) );
+	value = (EEPROM_WRITE_QUEUE_FLUSH | EEPROM_CMD_QUEUE_FLUSH | EEPROM_READ_QUEUE_FLUSH);
+	wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value));
+	value = 0;
+	wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value));
 
 	/* Clear the Empty/Avail/Full bits.  After this it has been confirmed
 	 * that the bit was cleared by reading back the register. See NOTE below.
 	 * We also clear the Read queues as we do a EEPROM status register read
-	 * later. */
-	value = ( EEPROM_WRITE_QUEUE_EMPTY | EEPROM_WRITE_QUEUE_AVAIL | EEPROM_WRITE_QUEUE_FULL | EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL ) ;
-	wrmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG,&value, sizeof(value));
+	 * later.
+	 */
+	value = (EEPROM_WRITE_QUEUE_EMPTY | EEPROM_WRITE_QUEUE_AVAIL | EEPROM_WRITE_QUEUE_FULL | EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL);
+	wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
 
 	/* Enable write */
-	value = EEPROM_WRITE_ENABLE ;
-	wrmalt( Adapter, EEPROM_CMDQ_SPI_REG,&value, sizeof(value) );
+	value = EEPROM_WRITE_ENABLE;
+	wrmalt(Adapter, EEPROM_CMDQ_SPI_REG, &value, sizeof(value));
 
 	/* We can write back to back 8bits * 16 into the queue and as we have
-	 * checked for the queue to be empty we can write in a burst. */
+	 * checked for the queue to be empty we can write in a burst.
+	 */
 
 	value = uiData[0];
 	BcmSwapWord(&value);
-	wrm( Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4);
+	wrm(Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4);
 
 	value = uiData[1];
 	BcmSwapWord(&value);
-	wrm( Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4);
+	wrm(Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4);
 
 	value = uiData[2];
 	BcmSwapWord(&value);
-	wrm( Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4);
+	wrm(Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4);
 
 	value = uiData[3];
 	BcmSwapWord(&value);
-	wrm( Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4);
+	wrm(Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4);
 
 	/* NOTE : After this write, on readback of EEPROM_SPI_Q_STATUS1_REG
 	 * shows that we see 7 for the EEPROM data write.  Which means that
 	 * queue got full, also space is available as well as the queue is empty.
-	 * This may happen in sequence. */
-	value =  EEPROM_16_BYTE_PAGE_WRITE | uiOffset ;
-	wrmalt( Adapter, EEPROM_CMDQ_SPI_REG, &value, sizeof(value) );
+	 * This may happen in sequence.
+	 */
+	value =  EEPROM_16_BYTE_PAGE_WRITE | uiOffset;
+	wrmalt(Adapter, EEPROM_CMDQ_SPI_REG, &value, sizeof(value));
 
 	/* Ideally we should loop here without tries and eventually succeed.
 	 * What we are checking if the previous write has completed, and this
-	 * may take time. We should wait till the Empty bit is set. */
+	 * may take time. We should wait till the Empty bit is set.
+	 */
 	uiStatus = 0;
 	rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus));
-	while ( ( uiStatus & EEPROM_WRITE_QUEUE_EMPTY ) == 0 )
-	{
+	while ((uiStatus & EEPROM_WRITE_QUEUE_EMPTY) == 0) {
 		uiRetries--;
-		if ( uiRetries == 0 )
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "0x0f003004 = %x, %d retries failed.\n", uiStatus, MAX_EEPROM_RETRIES *RETRIES_PER_DELAY);
-			return STATUS_FAILURE ;
+		if (uiRetries == 0) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "0x0f003004 = %x, %d retries failed.\n", uiStatus, MAX_EEPROM_RETRIES * RETRIES_PER_DELAY);
+			return STATUS_FAILURE;
 		}
 
-		if( !(uiRetries%RETRIES_PER_DELAY) )
-					msleep(1);
+		if (!(uiRetries%RETRIES_PER_DELAY))
+			udelay(1000);
 
 		uiStatus = 0;
 		rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus));
-		if(Adapter->device_removed == TRUE)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Modem got removed hence exiting from loop....");
+		if (Adapter->device_removed == TRUE) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Modem got removed hence exiting from loop....");
 			return -ENODEV;
 		}
-
 	}
 
-	if ( uiRetries != 0 )
-	{
+	if (uiRetries != 0) {
 		/* Clear the ones that are set - either, Empty/Full/Avail bits */
-		value = ( uiStatus & ( EEPROM_WRITE_QUEUE_EMPTY | EEPROM_WRITE_QUEUE_AVAIL | EEPROM_WRITE_QUEUE_FULL ) );
-		wrmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
+		value = (uiStatus & (EEPROM_WRITE_QUEUE_EMPTY | EEPROM_WRITE_QUEUE_AVAIL | EEPROM_WRITE_QUEUE_FULL));
+		wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
 	}
 
 	/* Here we should check if the EEPROM status register is correct before
 	 * proceeding. Bit 0 in the EEPROM Status register should be 0 before
 	 * we proceed further.  A 1 at Bit 0 indicates that the EEPROM is busy
 	 * with the previous write. Note also that issuing this read finally
-	 * means the previous write to the EEPROM has completed. */
-	uiRetries = MAX_EEPROM_RETRIES*RETRIES_PER_DELAY;
+	 * means the previous write to the EEPROM has completed.
+	 */
+	uiRetries = MAX_EEPROM_RETRIES * RETRIES_PER_DELAY;
 	uiEpromStatus = 0;
-	while ( uiRetries != 0 )
-	{
-		uiEpromStatus = ReadEEPROMStatusRegister( Adapter) ;
-		if(Adapter->device_removed == TRUE)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Modem has got removed hence exiting from loop...");
+	while (uiRetries != 0) {
+		uiEpromStatus = ReadEEPROMStatusRegister(Adapter);
+		if (Adapter->device_removed == TRUE) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Modem has got removed hence exiting from loop...");
 			return -ENODEV;
 		}
-		if ( ( EEPROM_STATUS_REG_WRITE_BUSY & uiEpromStatus ) == 0 )
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "EEPROM status register = %x tries = %d\n", uiEpromStatus, (MAX_EEPROM_RETRIES * RETRIES_PER_DELAY- uiRetries) );
-			return STATUS_SUCCESS ;
+		if ((EEPROM_STATUS_REG_WRITE_BUSY & uiEpromStatus) == 0) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "EEPROM status register = %x tries = %d\n", uiEpromStatus, (MAX_EEPROM_RETRIES * RETRIES_PER_DELAY - uiRetries));
+			return STATUS_SUCCESS;
 		}
 		uiRetries--;
-		if ( uiRetries == 0 )
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "0x0f003004 = %x, for EEPROM status read %d retries failed.\n", uiEpromStatus, MAX_EEPROM_RETRIES *RETRIES_PER_DELAY);
-			return STATUS_FAILURE ;
+		if (uiRetries == 0) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "0x0f003004 = %x, for EEPROM status read %d retries failed.\n", uiEpromStatus, MAX_EEPROM_RETRIES * RETRIES_PER_DELAY);
+			return STATUS_FAILURE;
 		}
 		uiEpromStatus = 0;
-		if( !(uiRetries%RETRIES_PER_DELAY) )
-				msleep(1);
+		if (!(uiRetries%RETRIES_PER_DELAY))
+			udelay(1000);
 	}
 
-	return STATUS_SUCCESS ;
+	return STATUS_SUCCESS;
 } /* BeceemEEPROMWritePage */
 
-
-//-----------------------------------------------------------------------------
-// Procedure:	BeceemEEPROMBulkWrite
-//
-// Description: Performs write to the EEPROM
-//
-// Arguments:
-//		Adapter       - ptr to Adapter object instance
-//		pBuffer 	    - Data to be written.
-//		uiOffset       - Offset of the EEPROM where data needs to be written to.
-//		uiNumBytes - Number of bytes to be written.
-//		bVerify        - read verify flag.
-// Returns:
-//		OSAL_STATUS_CODE
-//
-//-----------------------------------------------------------------------------
-
-INT BeceemEEPROMBulkWrite(
-	PMINI_ADAPTER Adapter,
-	PUCHAR pBuffer,
-	UINT uiOffset,
-	UINT uiNumBytes,
-	BOOLEAN bVerify)
+/*
+ * Procedure:	BeceemEEPROMBulkWrite
+ *
+ * Description: Performs write to the EEPROM
+ *
+ * Arguments:
+ *		Adapter		- ptr to Adapter object instance
+ *		pBuffer		- Data to be written.
+ *		uiOffset	- Offset of the EEPROM where data needs to be written to.
+ *		uiNumBytes	- Number of bytes to be written.
+ *		bVerify		- read verify flag.
+ * Returns:
+ *		OSAL_STATUS_CODE
+ *
+ */
+
+int BeceemEEPROMBulkWrite(struct bcm_mini_adapter *Adapter,
+			PUCHAR pBuffer,
+			unsigned int uiOffset,
+			unsigned int uiNumBytes,
+			BOOLEAN bVerify)
 {
-	UINT  uiBytesToCopy = uiNumBytes;
-	//UINT  uiRdbk 		= 0;
-	UINT  uiData[4] 	= {0};
-	UINT  uiIndex 		= 0;
-	UINT  uiTempOffset  = 0;
-	UINT  uiExtraBytes  = 0;
-	//PUINT puiBuffer 	= (PUINT)pBuffer;
-	//INT value;
-
-	if(uiOffset%MAX_RW_SIZE && uiBytesToCopy)
-	{
-		uiTempOffset = uiOffset - (uiOffset%MAX_RW_SIZE);
-		uiExtraBytes = uiOffset-uiTempOffset;
-
-
-		BeceemEEPROMBulkRead(Adapter,&uiData[0],uiTempOffset,MAX_RW_SIZE);
-
-		if(uiBytesToCopy >= (16 -uiExtraBytes))
-		{
-			memcpy((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,MAX_RW_SIZE- uiExtraBytes);
-
-			if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiTempOffset ) )
-					return STATUS_FAILURE;
+	unsigned int uiBytesToCopy	= uiNumBytes;
+	/* unsigned int uiRdbk		= 0; */
+	unsigned int uiData[4]		= {0};
+	unsigned int uiIndex		= 0;
+	unsigned int uiTempOffset	= 0;
+	unsigned int uiExtraBytes	= 0;
+	/* PUINT puiBuffer	= (PUINT)pBuffer;
+	 * int value;
+	 */
+
+	if (uiOffset % MAX_RW_SIZE && uiBytesToCopy) {
+		uiTempOffset = uiOffset - (uiOffset % MAX_RW_SIZE);
+		uiExtraBytes = uiOffset - uiTempOffset;
+
+		BeceemEEPROMBulkRead(Adapter, &uiData[0], uiTempOffset, MAX_RW_SIZE);
+
+		if (uiBytesToCopy >= (16 - uiExtraBytes)) {
+			memcpy((((PUCHAR)&uiData[0]) + uiExtraBytes), pBuffer, MAX_RW_SIZE - uiExtraBytes);
+
+			if (STATUS_FAILURE == BeceemEEPROMWritePage(Adapter, uiData, uiTempOffset))
+				return STATUS_FAILURE;
 
 			uiBytesToCopy -= (MAX_RW_SIZE - uiExtraBytes);
 			uiIndex += (MAX_RW_SIZE - uiExtraBytes);
 			uiOffset += (MAX_RW_SIZE - uiExtraBytes);
-		}
-		else
-		{
-			memcpy((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,uiBytesToCopy);
+		} else {
+			memcpy((((PUCHAR)&uiData[0]) + uiExtraBytes), pBuffer, uiBytesToCopy);
 
-			if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiTempOffset ) )
-					return STATUS_FAILURE;
+			if (STATUS_FAILURE == BeceemEEPROMWritePage(Adapter, uiData, uiTempOffset))
+				return STATUS_FAILURE;
 
 			uiIndex += uiBytesToCopy;
 			uiOffset += uiBytesToCopy;
 			uiBytesToCopy = 0;
 		}
-
-
 	}
 
-	while(uiBytesToCopy)
-	{
-		if(Adapter->device_removed)
-		{
+	while (uiBytesToCopy) {
+		if (Adapter->device_removed)
 			return -1;
-		}
 
-		if(uiBytesToCopy >= MAX_RW_SIZE)
-		{
-
-			if (STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, (PUINT) &pBuffer[uiIndex], uiOffset ) )
-						return STATUS_FAILURE;
+		if (uiBytesToCopy >= MAX_RW_SIZE) {
+			if (STATUS_FAILURE == BeceemEEPROMWritePage(Adapter, (PUINT) &pBuffer[uiIndex], uiOffset))
+				return STATUS_FAILURE;
 
 			uiIndex += MAX_RW_SIZE;
 			uiOffset += MAX_RW_SIZE;
-			uiBytesToCopy	-= MAX_RW_SIZE;
-		}
-		else
-		{
-	//
-	// To program non 16byte aligned data, read 16byte and then update.
-	//
-			BeceemEEPROMBulkRead(Adapter,&uiData[0],uiOffset,16);
-			memcpy(&uiData[0],pBuffer+uiIndex,uiBytesToCopy);
-
+			uiBytesToCopy -= MAX_RW_SIZE;
+		} else {
+			/*
+			 * To program non 16byte aligned data, read 16byte and then update.
+			 */
+			BeceemEEPROMBulkRead(Adapter, &uiData[0], uiOffset, 16);
+			memcpy(&uiData[0], pBuffer + uiIndex, uiBytesToCopy);
+
+			if (STATUS_FAILURE == BeceemEEPROMWritePage(Adapter, uiData, uiOffset))
+				return STATUS_FAILURE;
 
-			if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiOffset ) )
-					return STATUS_FAILURE;
 			uiBytesToCopy = 0;
 		}
-
 	}
 
 	return 0;
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BeceemNVMRead
-//
-// Description: Reads n number of bytes from NVM.
-//
-// Arguments:
-//		Adapter      - ptr to Adapter object instance
-//		pBuffer       - Buffer to store the data read from NVM
-//		uiOffset       - Offset of NVM from where data should be read
-//		uiNumBytes - Number of bytes to be read from the NVM.
-//
-// Returns:
-//		OSAL_STATUS_SUCCESS - if NVM read is successful.
-//		<FAILURE>			- if failed.
-//-----------------------------------------------------------------------------
-
-INT BeceemNVMRead(
-	PMINI_ADAPTER Adapter,
-	PUINT pBuffer,
-	UINT uiOffset,
-	UINT uiNumBytes)
+/*
+ * Procedure:	BeceemNVMRead
+ *
+ * Description: Reads n number of bytes from NVM.
+ *
+ * Arguments:
+ *		Adapter      - ptr to Adapter object instance
+ *		pBuffer       - Buffer to store the data read from NVM
+ *		uiOffset       - Offset of NVM from where data should be read
+ *		uiNumBytes - Number of bytes to be read from the NVM.
+ *
+ * Returns:
+ *		OSAL_STATUS_SUCCESS - if NVM read is successful.
+ *		<FAILURE>			- if failed.
+ */
+
+int BeceemNVMRead(struct bcm_mini_adapter *Adapter,
+		PUINT pBuffer,
+		unsigned int uiOffset,
+		unsigned int uiNumBytes)
 {
-	INT Status = 0;
-#if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS)
-	UINT uiTemp = 0, value;
-#endif
+	int Status = 0;
 
-	if(Adapter->eNVMType == NVM_FLASH)
-	{
-		if(Adapter->bFlashRawRead == FALSE)
-		{
-			if (IsSectionExistInVendorInfo(Adapter,Adapter->eActiveDSD))
-				return vendorextnReadSection(Adapter,(PUCHAR)pBuffer,Adapter->eActiveDSD,uiOffset,uiNumBytes);
-			uiOffset = uiOffset+ Adapter->ulFlashCalStart ;
+	#if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS)
+		unsigned int uiTemp = 0, value;
+	#endif
+
+	if (Adapter->eNVMType == NVM_FLASH) {
+		if (Adapter->bFlashRawRead == FALSE) {
+			if (IsSectionExistInVendorInfo(Adapter, Adapter->eActiveDSD))
+				return vendorextnReadSection(Adapter, (PUCHAR)pBuffer, Adapter->eActiveDSD, uiOffset, uiNumBytes);
+
+			uiOffset = uiOffset + Adapter->ulFlashCalStart;
 		}
-#if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
-		Status = bcmflash_raw_read((uiOffset/FLASH_PART_SIZE),(uiOffset % FLASH_PART_SIZE),( unsigned char *)pBuffer,uiNumBytes);
-#else
 
-		rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
-		value = 0;
-		wrmalt(Adapter, 0x0f000C80,&value, sizeof(value));
-		Status = BeceemFlashBulkRead(Adapter,
+		#if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
+			Status = bcmflash_raw_read((uiOffset / FLASH_PART_SIZE), (uiOffset % FLASH_PART_SIZE), (unsigned char *)pBuffer, uiNumBytes);
+		#else
+			rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
+			value = 0;
+			wrmalt(Adapter, 0x0f000C80, &value, sizeof(value));
+			Status = BeceemFlashBulkRead(Adapter,
 						pBuffer,
 						uiOffset,
 						uiNumBytes);
-		wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
-#endif
-	}
-	else if(Adapter->eNVMType == NVM_EEPROM)
-	{
+			wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
+		#endif
+	} else if (Adapter->eNVMType == NVM_EEPROM) {
 		Status = BeceemEEPROMBulkRead(Adapter,
 					pBuffer,
 					uiOffset,
 					uiNumBytes);
-	}
-	else
-	{
+	} else {
 		Status = -1;
 	}
+
 	return Status;
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BeceemNVMWrite
-//
-// Description: Writes n number of bytes to NVM.
-//
-// Arguments:
-//		Adapter      - ptr to Adapter object instance
-//		pBuffer       - Buffer contains the data to be written.
-//		uiOffset       - Offset of NVM where data to be written to.
-//		uiNumBytes - Number of bytes to be written..
-//
-// Returns:
-//		OSAL_STATUS_SUCCESS - if NVM write is successful.
-//		<FAILURE>			- if failed.
-//-----------------------------------------------------------------------------
-
-INT BeceemNVMWrite(
-	PMINI_ADAPTER Adapter,
-	PUINT pBuffer,
-	UINT uiOffset,
-	UINT uiNumBytes,
-	BOOLEAN bVerify)
+/*
+ * Procedure:	BeceemNVMWrite
+ *
+ * Description: Writes n number of bytes to NVM.
+ *
+ * Arguments:
+ *		Adapter      - ptr to Adapter object instance
+ *		pBuffer       - Buffer contains the data to be written.
+ *		uiOffset       - Offset of NVM where data to be written to.
+ *		uiNumBytes - Number of bytes to be written..
+ *
+ * Returns:
+ *		OSAL_STATUS_SUCCESS - if NVM write is successful.
+ *		<FAILURE>			- if failed.
+ */
+
+int BeceemNVMWrite(struct bcm_mini_adapter *Adapter,
+		PUINT pBuffer,
+		unsigned int uiOffset,
+		unsigned int uiNumBytes,
+		BOOLEAN bVerify)
 {
-	INT Status = 0;
-	UINT uiTemp = 0;
-	UINT uiMemoryLoc = EEPROM_CAL_DATA_INTERNAL_LOC;
-	UINT uiIndex = 0;
-#if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS)
-	UINT value;
-#endif
-	UINT uiFlashOffset = 0;
-
-	if(Adapter->eNVMType == NVM_FLASH)
-	{
-		if (IsSectionExistInVendorInfo(Adapter,Adapter->eActiveDSD))
-			Status = vendorextnWriteSection(Adapter,(PUCHAR)pBuffer,Adapter->eActiveDSD,uiOffset,uiNumBytes,bVerify);
-		else
-		{
-			uiFlashOffset = uiOffset + Adapter->ulFlashCalStart;
+	int Status = 0;
+	unsigned int uiTemp = 0;
+	unsigned int uiMemoryLoc = EEPROM_CAL_DATA_INTERNAL_LOC;
+	unsigned int uiIndex = 0;
 
-#if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
-			Status = bcmflash_raw_write((uiFlashOffset/FLASH_PART_SIZE), (uiFlashOffset % FLASH_PART_SIZE), (unsigned char *)pBuffer,uiNumBytes);
-#else
-			rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
-			value = 0;
-			wrmalt(Adapter, 0x0f000C80, &value, sizeof(value));
+	#if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS)
+		unsigned int value;
+	#endif
 
-			if(Adapter->bStatusWrite == TRUE)
-			{
-				Status = BeceemFlashBulkWriteStatus(Adapter,
-							pBuffer,
-							uiFlashOffset,
-							uiNumBytes ,
-							bVerify);
-			}
-			else
-			{
+	unsigned int uiFlashOffset = 0;
 
-				Status = BeceemFlashBulkWrite(Adapter,
-							pBuffer,
-							uiFlashOffset,
-							uiNumBytes,
-							bVerify);
-			}
-#endif
-		}
+	if (Adapter->eNVMType == NVM_FLASH) {
+		if (IsSectionExistInVendorInfo(Adapter, Adapter->eActiveDSD))
+			Status = vendorextnWriteSection(Adapter, (PUCHAR)pBuffer, Adapter->eActiveDSD, uiOffset, uiNumBytes, bVerify);
+		else {
+			uiFlashOffset = uiOffset + Adapter->ulFlashCalStart;
+
+			#if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
+				Status = bcmflash_raw_write((uiFlashOffset / FLASH_PART_SIZE), (uiFlashOffset % FLASH_PART_SIZE), (unsigned char *)pBuffer, uiNumBytes);
+			#else
+				rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
+				value = 0;
+				wrmalt(Adapter, 0x0f000C80, &value, sizeof(value));
+
+				if (Adapter->bStatusWrite == TRUE)
+					Status = BeceemFlashBulkWriteStatus(Adapter,
+									pBuffer,
+									uiFlashOffset,
+									uiNumBytes ,
+									bVerify);
+				else
 
+					Status = BeceemFlashBulkWrite(Adapter,
+								pBuffer,
+								uiFlashOffset,
+								uiNumBytes,
+								bVerify);
+			#endif
+		}
 
-		if(uiOffset >= EEPROM_CALPARAM_START)
-		{
+		if (uiOffset >= EEPROM_CALPARAM_START) {
 			uiMemoryLoc += (uiOffset - EEPROM_CALPARAM_START);
-			while(uiNumBytes)
-			{
-				if(uiNumBytes > BUFFER_4K)
-				{
-					wrm(Adapter,(uiMemoryLoc+uiIndex),(PCHAR)(pBuffer+(uiIndex/4)),BUFFER_4K);
+			while (uiNumBytes) {
+				if (uiNumBytes > BUFFER_4K) {
+					wrm(Adapter, (uiMemoryLoc+uiIndex), (PCHAR)(pBuffer + (uiIndex / 4)), BUFFER_4K);
 					uiNumBytes -= BUFFER_4K;
 					uiIndex += BUFFER_4K;
-				}
-				else
-				{
-					wrm(Adapter,uiMemoryLoc+uiIndex,(PCHAR)(pBuffer+(uiIndex/4)),uiNumBytes);
+				} else {
+					wrm(Adapter, uiMemoryLoc+uiIndex, (PCHAR)(pBuffer + (uiIndex / 4)), uiNumBytes);
 					uiNumBytes = 0;
 					break;
 				}
 			}
-		}
-		else
-		{
-			if((uiOffset+uiNumBytes) > EEPROM_CALPARAM_START)
-			{
+		} else {
+			if ((uiOffset + uiNumBytes) > EEPROM_CALPARAM_START) {
 				ULONG ulBytesTobeSkipped = 0;
-				PUCHAR pcBuffer = (PUCHAR)pBuffer;// char pointer to take care of odd byte cases.
+				PUCHAR pcBuffer = (PUCHAR)pBuffer; /* char pointer to take care of odd byte cases. */
 				uiNumBytes -= (EEPROM_CALPARAM_START - uiOffset);
 				ulBytesTobeSkipped += (EEPROM_CALPARAM_START - uiOffset);
 				uiOffset += (EEPROM_CALPARAM_START - uiOffset);
-				while(uiNumBytes)
-				{
-					if(uiNumBytes > BUFFER_4K)
-					{
-						wrm(Adapter,uiMemoryLoc+uiIndex,(PCHAR )&pcBuffer[ulBytesTobeSkipped+uiIndex],BUFFER_4K);
+				while (uiNumBytes) {
+					if (uiNumBytes > BUFFER_4K) {
+						wrm(Adapter, uiMemoryLoc + uiIndex, (PCHAR)&pcBuffer[ulBytesTobeSkipped + uiIndex], BUFFER_4K);
 						uiNumBytes -= BUFFER_4K;
 						uiIndex += BUFFER_4K;
-					}
-					else
-					{
-						wrm(Adapter,uiMemoryLoc+uiIndex,(PCHAR)&pcBuffer[ulBytesTobeSkipped+uiIndex],uiNumBytes);
+					} else {
+						wrm(Adapter, uiMemoryLoc + uiIndex, (PCHAR)&pcBuffer[ulBytesTobeSkipped + uiIndex], uiNumBytes);
 						uiNumBytes = 0;
 						break;
 					}
 				}
-
 			}
 		}
-
-	// restore the values.
-		wrmalt(Adapter,0x0f000C80,&uiTemp, sizeof(uiTemp));
-	}
-	else if(Adapter->eNVMType == NVM_EEPROM)
-	{
+		/* restore the values. */
+		wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
+	} else if (Adapter->eNVMType == NVM_EEPROM) {
 		Status = BeceemEEPROMBulkWrite(Adapter,
 					(PUCHAR)pBuffer,
 					uiOffset,
 					uiNumBytes,
 					bVerify);
-		if(bVerify)
-		{
-			Status = BeceemEEPROMReadBackandVerify(Adapter,(PUINT)pBuffer,uiOffset,uiNumBytes);
-		}
-	}
-	else
-	{
+		if (bVerify)
+			Status = BeceemEEPROMReadBackandVerify(Adapter, (PUINT)pBuffer, uiOffset, uiNumBytes);
+	} else {
 		Status = -1;
 	}
 	return Status;
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BcmUpdateSectorSize
-//
-// Description: Updates the sector size to FLASH.
-//
-// Arguments:
-//		Adapter       - ptr to Adapter object instance
-//          uiSectorSize - sector size
-//
-// Returns:
-//		OSAL_STATUS_SUCCESS - if NVM write is successful.
-//		<FAILURE>			- if failed.
-//-----------------------------------------------------------------------------
-
-INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize)
+/*
+ * Procedure:	BcmUpdateSectorSize
+ *
+ * Description: Updates the sector size to FLASH.
+ *
+ * Arguments:
+ *		Adapter       - ptr to Adapter object instance
+ *          uiSectorSize - sector size
+ *
+ * Returns:
+ *		OSAL_STATUS_SUCCESS - if NVM write is successful.
+ *		<FAILURE>			- if failed.
+ */
+
+int BcmUpdateSectorSize(struct bcm_mini_adapter *Adapter, unsigned int uiSectorSize)
 {
-	INT Status = -1;
+	int Status = -1;
 	FLASH_CS_INFO sFlashCsInfo = {0};
-	UINT uiTemp = 0;
-
-	UINT uiSectorSig = 0;
-	UINT uiCurrentSectorSize = 0;
-
-	UINT value;
-
-
+	unsigned int uiTemp = 0;
+	unsigned int uiSectorSig = 0;
+	unsigned int uiCurrentSectorSize = 0;
+	unsigned int value;
 
 	rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
 	value = 0;
-	wrmalt(Adapter, 0x0f000C80,&value, sizeof(value));
+	wrmalt(Adapter, 0x0f000C80, &value, sizeof(value));
 
-//
-// Before updating the sector size in the reserved area, check if already present.
-//
-	BeceemFlashBulkRead(Adapter,(PUINT)&sFlashCsInfo,Adapter->ulFlashControlSectionStart,sizeof(sFlashCsInfo));
+	/*
+	 * Before updating the sector size in the reserved area, check if already present.
+	 */
+	BeceemFlashBulkRead(Adapter, (PUINT)&sFlashCsInfo, Adapter->ulFlashControlSectionStart, sizeof(sFlashCsInfo));
 	uiSectorSig = ntohl(sFlashCsInfo.FlashSectorSizeSig);
 	uiCurrentSectorSize = ntohl(sFlashCsInfo.FlashSectorSize);
 
-	if(uiSectorSig == FLASH_SECTOR_SIZE_SIG)
-	{
-
-		if((uiCurrentSectorSize <= MAX_SECTOR_SIZE) && (uiCurrentSectorSize >= MIN_SECTOR_SIZE))
-		{
-			if(uiSectorSize == uiCurrentSectorSize)
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Provided sector size is same as programmed in Flash");
+	if (uiSectorSig == FLASH_SECTOR_SIZE_SIG) {
+		if ((uiCurrentSectorSize <= MAX_SECTOR_SIZE) && (uiCurrentSectorSize >= MIN_SECTOR_SIZE)) {
+			if (uiSectorSize == uiCurrentSectorSize) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Provided sector size is same as programmed in Flash");
 				Status = STATUS_SUCCESS;
-				goto Restore ;
+				goto Restore;
 			}
 		}
 	}
 
-	if((uiSectorSize <= MAX_SECTOR_SIZE) && (uiSectorSize >= MIN_SECTOR_SIZE))
-	{
-
+	if ((uiSectorSize <= MAX_SECTOR_SIZE) && (uiSectorSize >= MIN_SECTOR_SIZE)) {
 		sFlashCsInfo.FlashSectorSize = htonl(uiSectorSize);
 		sFlashCsInfo.FlashSectorSizeSig = htonl(FLASH_SECTOR_SIZE_SIG);
 
@@ -2282,152 +2014,128 @@ INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize)
 					Adapter->ulFlashControlSectionStart,
 					sizeof(sFlashCsInfo),
 					TRUE);
-
-
 	}
 
-	Restore :
-	// restore the values.
-	wrmalt(Adapter, 0x0f000C80,&uiTemp, sizeof(uiTemp));
-
+Restore:
+	/* restore the values. */
+	wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
 
 	return Status;
-
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BcmGetFlashSectorSize
-//
-// Description: Finds the sector size of the FLASH.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//
-// Returns:
-//		UINT - sector size.
-//
-//-----------------------------------------------------------------------------
-
-static UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize)
+/*
+ * Procedure:	BcmGetFlashSectorSize
+ *
+ * Description: Finds the sector size of the FLASH.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *
+ * Returns:
+ *		unsigned int - sector size.
+ *
+ */
+
+static unsigned int BcmGetFlashSectorSize(struct bcm_mini_adapter *Adapter, unsigned int FlashSectorSizeSig, unsigned int FlashSectorSize)
 {
-	UINT uiSectorSize = 0;
-	UINT uiSectorSig = 0;
+	unsigned int uiSectorSize = 0;
+	unsigned int uiSectorSig = 0;
 
-	if(Adapter->bSectorSizeOverride &&
+	if (Adapter->bSectorSizeOverride &&
 		(Adapter->uiSectorSizeInCFG <= MAX_SECTOR_SIZE &&
-		Adapter->uiSectorSizeInCFG >= MIN_SECTOR_SIZE))
-	{
+			Adapter->uiSectorSizeInCFG >= MIN_SECTOR_SIZE)) {
 		Adapter->uiSectorSize = Adapter->uiSectorSizeInCFG;
-	}
-	else
-	{
-
+	} else {
 		uiSectorSig = FlashSectorSizeSig;
 
-		if(uiSectorSig == FLASH_SECTOR_SIZE_SIG)
-		{
+		if (uiSectorSig == FLASH_SECTOR_SIZE_SIG) {
 			uiSectorSize = FlashSectorSize;
-	//
-	// If the sector size stored in the FLASH makes sense then use it.
-	//
-			if(uiSectorSize <= MAX_SECTOR_SIZE && uiSectorSize >= MIN_SECTOR_SIZE)
-			{
+			/*
+			 * If the sector size stored in the FLASH makes sense then use it.
+			 */
+			if (uiSectorSize <= MAX_SECTOR_SIZE && uiSectorSize >= MIN_SECTOR_SIZE) {
 				Adapter->uiSectorSize = uiSectorSize;
-			}
-	//No valid size in FLASH, check if Config file has it.
-			else if(Adapter->uiSectorSizeInCFG <= MAX_SECTOR_SIZE &&
-					Adapter->uiSectorSizeInCFG >= MIN_SECTOR_SIZE)
-			{
+			} else if (Adapter->uiSectorSizeInCFG <= MAX_SECTOR_SIZE &&
+				Adapter->uiSectorSizeInCFG >= MIN_SECTOR_SIZE) {
+				/* No valid size in FLASH, check if Config file has it. */
 				Adapter->uiSectorSize = Adapter->uiSectorSizeInCFG;
-			}
-	// Init to Default, if none of the above works.
-			else
-			{
+			} else {
+				/* Init to Default, if none of the above works. */
 				Adapter->uiSectorSize = DEFAULT_SECTOR_SIZE;
 			}
-
-		}
-		else
-		{
-			if(Adapter->uiSectorSizeInCFG <= MAX_SECTOR_SIZE &&
-					Adapter->uiSectorSizeInCFG >= MIN_SECTOR_SIZE)
-			{
+		} else {
+			if (Adapter->uiSectorSizeInCFG <= MAX_SECTOR_SIZE &&
+				Adapter->uiSectorSizeInCFG >= MIN_SECTOR_SIZE)
 				Adapter->uiSectorSize = Adapter->uiSectorSizeInCFG;
-			}
 			else
-			{
 				Adapter->uiSectorSize = DEFAULT_SECTOR_SIZE;
-			}
 		}
 	}
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Sector size  :%x \n", Adapter->uiSectorSize);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Sector size  :%x\n", Adapter->uiSectorSize);
+
 	return Adapter->uiSectorSize;
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BcmInitEEPROMQueues
-//
-// Description: Initialization of EEPROM queues.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//
-// Returns:
-//		<OSAL_STATUS_CODE>
-//-----------------------------------------------------------------------------
-
-static INT BcmInitEEPROMQueues(PMINI_ADAPTER Adapter)
+/*
+ * Procedure:	BcmInitEEPROMQueues
+ *
+ * Description: Initialization of EEPROM queues.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *
+ * Returns:
+ *		<OSAL_STATUS_CODE>
+ */
+
+static int BcmInitEEPROMQueues(struct bcm_mini_adapter *Adapter)
 {
-	UINT value = 0;
+	unsigned int value = 0;
 	/* CHIP Bug : Clear the Avail bits on the Read queue. The default
 	 * value on this register is supposed to be 0x00001102.
-	 * But we get 0x00001122. */
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Fixing reset value on 0x0f003004 register\n" );
+	 * But we get 0x00001122.
+	 */
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Fixing reset value on 0x0f003004 register\n");
 	value = EEPROM_READ_DATA_AVAIL;
-	wrmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
+	wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
 
 	/* Flush the all the EEPROM queues. */
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, " Flushing the queues\n");
-	value =EEPROM_ALL_QUEUE_FLUSH ;
-	wrmalt( Adapter, SPI_FLUSH_REG, &value, sizeof(value));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, " Flushing the queues\n");
+	value = EEPROM_ALL_QUEUE_FLUSH;
+	wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value));
 
 	value = 0;
-	wrmalt( Adapter, SPI_FLUSH_REG, &value, sizeof(value) );
+	wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value));
 
 	/* Read the EEPROM Status Register. Just to see, no real purpose. */
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "EEPROM Status register value = %x\n", ReadEEPROMStatusRegister(Adapter) );
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "EEPROM Status register value = %x\n", ReadEEPROMStatusRegister(Adapter));
 
 	return STATUS_SUCCESS;
 } /* BcmInitEEPROMQueues() */
 
-//-----------------------------------------------------------------------------
-// Procedure:	BcmInitNVM
-//
-// Description: Initialization of NVM, EEPROM size,FLASH size, sector size etc.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//
-// Returns:
-//		<OSAL_STATUS_CODE>
-//-----------------------------------------------------------------------------
-
-INT BcmInitNVM(PMINI_ADAPTER ps_adapter)
+/*
+ * Procedure:	BcmInitNVM
+ *
+ * Description: Initialization of NVM, EEPROM size,FLASH size, sector size etc.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *
+ * Returns:
+ *		<OSAL_STATUS_CODE>
+ */
+
+int BcmInitNVM(struct bcm_mini_adapter *ps_adapter)
 {
 	BcmValidateNvmType(ps_adapter);
 	BcmInitEEPROMQueues(ps_adapter);
 
-	if(ps_adapter->eNVMType == NVM_AUTODETECT)
-	{
+	if (ps_adapter->eNVMType == NVM_AUTODETECT) {
 		ps_adapter->eNVMType = BcmGetNvmType(ps_adapter);
-		if(ps_adapter->eNVMType == NVM_UNKNOWN)
-		{
-			BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_PRINTK, 0, 0, "NVM Type is unknown!!\n");
-		}
-	}
-	else if(ps_adapter->eNVMType == NVM_FLASH)
-	{
+		if (ps_adapter->eNVMType == NVM_UNKNOWN)
+			BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_PRINTK, 0, 0, "NVM Type is unknown!!\n");
+	} else if (ps_adapter->eNVMType == NVM_FLASH) {
 		BcmGetFlashCSInfo(ps_adapter);
 	}
 
@@ -2435,115 +2143,107 @@ INT BcmInitNVM(PMINI_ADAPTER ps_adapter)
 
 	return STATUS_SUCCESS;
 }
-/***************************************************************************/
-/*BcmGetNvmSize : set the EEPROM or flash size in Adapter.
-*
-*Input Parameter:
-*		Adapter data structure
-*Return Value :
-*		0. means success;
-*/
-/***************************************************************************/
-
-static INT BcmGetNvmSize(PMINI_ADAPTER Adapter)
+
+/* BcmGetNvmSize : set the EEPROM or flash size in Adapter.
+ *
+ * Input Parameter:
+ *		Adapter data structure
+ * Return Value :
+ *		0. means success;
+ */
+
+static int BcmGetNvmSize(struct bcm_mini_adapter *Adapter)
 {
-	if(Adapter->eNVMType == NVM_EEPROM)
-	{
+	if (Adapter->eNVMType == NVM_EEPROM)
 		Adapter->uiNVMDSDSize = BcmGetEEPROMSize(Adapter);
-	}
-	else if(Adapter->eNVMType == NVM_FLASH)
-	{
+	else if (Adapter->eNVMType == NVM_FLASH)
 		Adapter->uiNVMDSDSize = BcmGetFlashSize(Adapter);
-	}
+
 	return 0;
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BcmValidateNvm
-//
-// Description: Validates the NVM Type option selected against the device
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//
-// Returns:
-//		<VOID>
-//-----------------------------------------------------------------------------
-static VOID BcmValidateNvmType(PMINI_ADAPTER Adapter)
+/*
+ * Procedure:	BcmValidateNvm
+ *
+ * Description: Validates the NVM Type option selected against the device
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *
+ * Returns:
+ *		<VOID>
+ */
+
+static VOID BcmValidateNvmType(struct bcm_mini_adapter *Adapter)
 {
+	/*
+	 * if forcing the FLASH through CFG file, we should ensure device really has a FLASH.
+	 * Accessing the FLASH address without the FLASH being present can cause hang/freeze etc.
+	 * So if NVM_FLASH is selected for older chipsets, change it to AUTODETECT where EEPROM is 1st choice.
+	 */
 
-	//
-	// if forcing the FLASH through CFG file, we should ensure device really has a FLASH.
-	// Accessing the FLASH address without the FLASH being present can cause hang/freeze etc.
-	// So if NVM_FLASH is selected for older chipsets, change it to AUTODETECT where EEPROM is 1st choice.
-	//
-
-	if(Adapter->eNVMType == NVM_FLASH &&
+	if (Adapter->eNVMType == NVM_FLASH &&
 		Adapter->chip_id < 0xBECE3300)
-	{
 		Adapter->eNVMType = NVM_AUTODETECT;
-	}
 }
-//-----------------------------------------------------------------------------
-// Procedure:	BcmReadFlashRDID
-//
-// Description: Reads ID from Serial Flash
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//
-// Returns:
-//		Flash ID
-//-----------------------------------------------------------------------------
-static ULONG BcmReadFlashRDID(PMINI_ADAPTER Adapter)
+
+/*
+ * Procedure:	BcmReadFlashRDID
+ *
+ * Description: Reads ID from Serial Flash
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *
+ * Returns:
+ *		Flash ID
+ */
+
+static ULONG BcmReadFlashRDID(struct bcm_mini_adapter *Adapter)
 {
 	ULONG ulRDID = 0;
-	UINT value;
-//
-// Read ID Instruction.
-//
-	value = (FLASH_CMD_READ_ID<<24);
-	wrmalt(Adapter, FLASH_SPI_CMDQ_REG,&value, sizeof(value));
-
-//Delay
-	udelay(10);
-//
-// Read SPI READQ REG. The output will be WWXXYYZZ.
-// The ID is 3Bytes long and is WWXXYY. ZZ needs to be Ignored.
-//
-	rdmalt(Adapter, FLASH_SPI_READQ_REG, (PUINT)&ulRDID, sizeof(ulRDID));
+	unsigned int value;
 
-	return (ulRDID >>8);
+	/*
+	 * Read ID Instruction.
+	 */
+	value = (FLASH_CMD_READ_ID << 24);
+	wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value));
+
+	/* Delay */
+	udelay(10);
 
+	/*
+	 * Read SPI READQ REG. The output will be WWXXYYZZ.
+	 * The ID is 3Bytes long and is WWXXYY. ZZ needs to be Ignored.
+	 */
+	rdmalt(Adapter, FLASH_SPI_READQ_REG, (PUINT)&ulRDID, sizeof(ulRDID));
 
+	return ulRDID >> 8;
 }
 
-INT BcmAllocFlashCSStructure(PMINI_ADAPTER psAdapter)
+int BcmAllocFlashCSStructure(struct bcm_mini_adapter *psAdapter)
 {
-	if(psAdapter == NULL)
-	{
-		BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0, "Adapter structure point is NULL");
+	if (!psAdapter) {
+		BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Adapter structure point is NULL");
 		return -EINVAL;
 	}
 	psAdapter->psFlashCSInfo = (PFLASH_CS_INFO)kzalloc(sizeof(FLASH_CS_INFO), GFP_KERNEL);
-	if(psAdapter->psFlashCSInfo == NULL)
-	{
-		BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0,"Can't Allocate memory for Flash 1.x");
+	if (psAdapter->psFlashCSInfo == NULL) {
+		BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate memory for Flash 1.x");
 		return -ENOMEM;
 	}
 
 	psAdapter->psFlash2xCSInfo = (PFLASH2X_CS_INFO)kzalloc(sizeof(FLASH2X_CS_INFO), GFP_KERNEL);
-	if(psAdapter->psFlash2xCSInfo == NULL)
-	{
-		BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0,"Can't Allocate memory for Flash 2.x");
+	if (!psAdapter->psFlash2xCSInfo) {
+		BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate memory for Flash 2.x");
 		kfree(psAdapter->psFlashCSInfo);
 		return -ENOMEM;
 	}
 
 	psAdapter->psFlash2xVendorInfo = (PFLASH2X_VENDORSPECIFIC_INFO)kzalloc(sizeof(FLASH2X_VENDORSPECIFIC_INFO), GFP_KERNEL);
-	if(psAdapter->psFlash2xVendorInfo == NULL)
-	{
-		BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0,"Can't Allocate Vendor Info Memory for Flash 2.x");
+	if (!psAdapter->psFlash2xVendorInfo) {
+		BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate Vendor Info Memory for Flash 2.x");
 		kfree(psAdapter->psFlashCSInfo);
 		kfree(psAdapter->psFlash2xCSInfo);
 		return -ENOMEM;
@@ -2552,91 +2252,90 @@ INT BcmAllocFlashCSStructure(PMINI_ADAPTER psAdapter)
 	return STATUS_SUCCESS;
 }
 
-INT BcmDeAllocFlashCSStructure(PMINI_ADAPTER psAdapter)
+int BcmDeAllocFlashCSStructure(struct bcm_mini_adapter *psAdapter)
 {
-	if(psAdapter == NULL)
-	{
-		BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0," Adapter structure point is NULL");
+	if (!psAdapter) {
+		BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Adapter structure point is NULL");
 		return -EINVAL;
 	}
 	kfree(psAdapter->psFlashCSInfo);
 	kfree(psAdapter->psFlash2xCSInfo);
 	kfree(psAdapter->psFlash2xVendorInfo);
-	return STATUS_SUCCESS ;
+	return STATUS_SUCCESS;
 }
 
-static INT	BcmDumpFlash2XCSStructure(PFLASH2X_CS_INFO psFlash2xCSInfo,PMINI_ADAPTER Adapter)
+static int BcmDumpFlash2XCSStructure(PFLASH2X_CS_INFO psFlash2xCSInfo, struct bcm_mini_adapter *Adapter)
 {
-	UINT Index = 0;
-    BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "**********************FLASH2X CS Structure *******************");
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Signature is  :%x", (psFlash2xCSInfo->MagicNumber));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Major Version :%d", MAJOR_VERSION(psFlash2xCSInfo->FlashLayoutVersion));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Minor Version :%d", MINOR_VERSION(psFlash2xCSInfo->FlashLayoutVersion));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, " ISOImageMajorVersion:0x%x", (psFlash2xCSInfo->ISOImageVersion));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SCSIFirmwareMajorVersion :0x%x", (psFlash2xCSInfo->SCSIFirmwareVersion));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForPart1ISOImage :0x%x", (psFlash2xCSInfo->OffsetFromZeroForPart1ISOImage));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForScsiFirmware :0x%x", (psFlash2xCSInfo->OffsetFromZeroForScsiFirmware));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SizeOfScsiFirmware  :0x%x", (psFlash2xCSInfo->SizeOfScsiFirmware ));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForPart2ISOImage :0x%x", (psFlash2xCSInfo->OffsetFromZeroForPart2ISOImage));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSDStart :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSDStart));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSDEnd :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSDEnd));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSAStart :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSAStart));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSAEnd :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSAEnd));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForControlSectionStart :0x%x", (psFlash2xCSInfo->OffsetFromZeroForControlSectionStart));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForControlSectionData :0x%x", (psFlash2xCSInfo->OffsetFromZeroForControlSectionData));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "CDLessInactivityTimeout :0x%x", (psFlash2xCSInfo->CDLessInactivityTimeout));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "NewImageSignature :0x%x", (psFlash2xCSInfo->NewImageSignature));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashSectorSizeSig :0x%x", (psFlash2xCSInfo->FlashSectorSizeSig));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashSectorSize :0x%x", (psFlash2xCSInfo->FlashSectorSize));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashWriteSupportSize :0x%x", (psFlash2xCSInfo->FlashWriteSupportSize));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "TotalFlashSize :0x%X", (psFlash2xCSInfo->TotalFlashSize));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashBaseAddr :0x%x", (psFlash2xCSInfo->FlashBaseAddr));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashPartMaxSize :0x%x", (psFlash2xCSInfo->FlashPartMaxSize));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "IsCDLessDeviceBootSig :0x%x", (psFlash2xCSInfo->IsCDLessDeviceBootSig));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "MassStorageTimeout :0x%x", (psFlash2xCSInfo->MassStorageTimeout));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part1Start :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part1Start));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part1End :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part1End));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part2Start :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part2Start));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part2End :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part2End));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part3Start :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part3Start));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part3End :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part3End));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part1Start :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part1Start));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part1End	:0x%x", (psFlash2xCSInfo->OffsetISOImage2Part1End));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part2Start :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part2Start));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part2End :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part2End));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part3Start :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part3Start));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part3End :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part3End));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromDSDStartForDSDHeader :0x%x", (psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD1Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD1Start));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD1End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD1End));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD2Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD2Start));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD2End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD2End));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA1Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA1Start));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA1End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA1End));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA2Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA2Start));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA2End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA2End));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Sector Access Bit Map is Defined as :");
-	for(Index =0; Index <(FLASH2X_TOTAL_SIZE/(DEFAULT_SECTOR_SIZE *16)); Index++)
-	{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SectorAccessBitMap[%d] :0x%x", Index,
+	unsigned int Index = 0;
+
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "**********************FLASH2X CS Structure *******************");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Signature is  :%x", (psFlash2xCSInfo->MagicNumber));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Major Version :%d", MAJOR_VERSION(psFlash2xCSInfo->FlashLayoutVersion));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Minor Version :%d", MINOR_VERSION(psFlash2xCSInfo->FlashLayoutVersion));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, " ISOImageMajorVersion:0x%x", (psFlash2xCSInfo->ISOImageVersion));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SCSIFirmwareMajorVersion :0x%x", (psFlash2xCSInfo->SCSIFirmwareVersion));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForPart1ISOImage :0x%x", (psFlash2xCSInfo->OffsetFromZeroForPart1ISOImage));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForScsiFirmware :0x%x", (psFlash2xCSInfo->OffsetFromZeroForScsiFirmware));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SizeOfScsiFirmware  :0x%x", (psFlash2xCSInfo->SizeOfScsiFirmware));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForPart2ISOImage :0x%x", (psFlash2xCSInfo->OffsetFromZeroForPart2ISOImage));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSDStart :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSDStart));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSDEnd :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSDEnd));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSAStart :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSAStart));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSAEnd :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSAEnd));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForControlSectionStart :0x%x", (psFlash2xCSInfo->OffsetFromZeroForControlSectionStart));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForControlSectionData :0x%x", (psFlash2xCSInfo->OffsetFromZeroForControlSectionData));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "CDLessInactivityTimeout :0x%x", (psFlash2xCSInfo->CDLessInactivityTimeout));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "NewImageSignature :0x%x", (psFlash2xCSInfo->NewImageSignature));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashSectorSizeSig :0x%x", (psFlash2xCSInfo->FlashSectorSizeSig));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashSectorSize :0x%x", (psFlash2xCSInfo->FlashSectorSize));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashWriteSupportSize :0x%x", (psFlash2xCSInfo->FlashWriteSupportSize));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "TotalFlashSize :0x%X", (psFlash2xCSInfo->TotalFlashSize));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashBaseAddr :0x%x", (psFlash2xCSInfo->FlashBaseAddr));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashPartMaxSize :0x%x", (psFlash2xCSInfo->FlashPartMaxSize));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "IsCDLessDeviceBootSig :0x%x", (psFlash2xCSInfo->IsCDLessDeviceBootSig));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "MassStorageTimeout :0x%x", (psFlash2xCSInfo->MassStorageTimeout));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part1Start :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part1Start));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part1End :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part1End));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part2Start :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part2Start));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part2End :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part2End));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part3Start :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part3Start));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part3End :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part3End));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part1Start :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part1Start));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part1End	:0x%x", (psFlash2xCSInfo->OffsetISOImage2Part1End));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part2Start :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part2Start));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part2End :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part2End));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part3Start :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part3Start));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part3End :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part3End));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromDSDStartForDSDHeader :0x%x", (psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD1Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD1Start));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD1End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD1End));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD2Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD2Start));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD2End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD2End));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA1Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA1Start));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA1End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA1End));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA2Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA2Start));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA2End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA2End));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Sector Access Bit Map is Defined as :");
+
+	for (Index = 0; Index < (FLASH2X_TOTAL_SIZE / (DEFAULT_SECTOR_SIZE * 16)); Index++)
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SectorAccessBitMap[%d] :0x%x", Index,
 				(psFlash2xCSInfo->SectorAccessBitMap[Index]));
-	}
 
 	return STATUS_SUCCESS;
 }
 
-
-static INT	ConvertEndianOf2XCSStructure(PFLASH2X_CS_INFO psFlash2xCSInfo)
+static int ConvertEndianOf2XCSStructure(PFLASH2X_CS_INFO psFlash2xCSInfo)
 {
-	UINT Index = 0;
+	unsigned int Index = 0;
+
 	psFlash2xCSInfo->MagicNumber = ntohl(psFlash2xCSInfo->MagicNumber);
-	psFlash2xCSInfo->FlashLayoutVersion= ntohl(psFlash2xCSInfo->FlashLayoutVersion);
-	//psFlash2xCSInfo->FlashLayoutMinorVersion = ntohs(psFlash2xCSInfo->FlashLayoutMinorVersion);
+	psFlash2xCSInfo->FlashLayoutVersion = ntohl(psFlash2xCSInfo->FlashLayoutVersion);
+	/* psFlash2xCSInfo->FlashLayoutMinorVersion = ntohs(psFlash2xCSInfo->FlashLayoutMinorVersion); */
 	psFlash2xCSInfo->ISOImageVersion = ntohl(psFlash2xCSInfo->ISOImageVersion);
-	psFlash2xCSInfo->SCSIFirmwareVersion =ntohl(psFlash2xCSInfo->SCSIFirmwareVersion);
+	psFlash2xCSInfo->SCSIFirmwareVersion = ntohl(psFlash2xCSInfo->SCSIFirmwareVersion);
 	psFlash2xCSInfo->OffsetFromZeroForPart1ISOImage = ntohl(psFlash2xCSInfo->OffsetFromZeroForPart1ISOImage);
 	psFlash2xCSInfo->OffsetFromZeroForScsiFirmware = ntohl(psFlash2xCSInfo->OffsetFromZeroForScsiFirmware);
-	psFlash2xCSInfo->SizeOfScsiFirmware = ntohl(psFlash2xCSInfo->SizeOfScsiFirmware );
+	psFlash2xCSInfo->SizeOfScsiFirmware = ntohl(psFlash2xCSInfo->SizeOfScsiFirmware);
 	psFlash2xCSInfo->OffsetFromZeroForPart2ISOImage = ntohl(psFlash2xCSInfo->OffsetFromZeroForPart2ISOImage);
 	psFlash2xCSInfo->OffsetFromZeroForDSDStart = ntohl(psFlash2xCSInfo->OffsetFromZeroForDSDStart);
 	psFlash2xCSInfo->OffsetFromZeroForDSDEnd = ntohl(psFlash2xCSInfo->OffsetFromZeroForDSDEnd);
@@ -2675,119 +2374,115 @@ static INT	ConvertEndianOf2XCSStructure(PFLASH2X_CS_INFO psFlash2xCSInfo)
 	psFlash2xCSInfo->OffsetFromZeroForVSA1End = ntohl(psFlash2xCSInfo->OffsetFromZeroForVSA1End);
 	psFlash2xCSInfo->OffsetFromZeroForVSA2Start = ntohl(psFlash2xCSInfo->OffsetFromZeroForVSA2Start);
 	psFlash2xCSInfo->OffsetFromZeroForVSA2End = ntohl(psFlash2xCSInfo->OffsetFromZeroForVSA2End);
-	for(Index =0; Index <(FLASH2X_TOTAL_SIZE/(DEFAULT_SECTOR_SIZE *16)); Index++)
-	{
-			psFlash2xCSInfo->SectorAccessBitMap[Index] = ntohl(psFlash2xCSInfo->SectorAccessBitMap[Index]);
-	}
+
+	for (Index = 0; Index < (FLASH2X_TOTAL_SIZE / (DEFAULT_SECTOR_SIZE * 16)); Index++)
+		psFlash2xCSInfo->SectorAccessBitMap[Index] = ntohl(psFlash2xCSInfo->SectorAccessBitMap[Index]);
+
 	return STATUS_SUCCESS;
 }
 
-static INT	ConvertEndianOfCSStructure(PFLASH_CS_INFO psFlashCSInfo)
+static int ConvertEndianOfCSStructure(PFLASH_CS_INFO psFlashCSInfo)
 {
-	//UINT Index = 0;
-	psFlashCSInfo->MagicNumber					 		=ntohl(psFlashCSInfo->MagicNumber);
-	psFlashCSInfo->FlashLayoutVersion					=ntohl(psFlashCSInfo->FlashLayoutVersion);
-	psFlashCSInfo->ISOImageVersion 						= ntohl(psFlashCSInfo->ISOImageVersion);
-	//won't convert according to old assumption
-	psFlashCSInfo->SCSIFirmwareVersion =(psFlashCSInfo->SCSIFirmwareVersion);
-
-	psFlashCSInfo->OffsetFromZeroForPart1ISOImage  		= ntohl(psFlashCSInfo->OffsetFromZeroForPart1ISOImage);
-	psFlashCSInfo->OffsetFromZeroForScsiFirmware        = ntohl(psFlashCSInfo->OffsetFromZeroForScsiFirmware);
-	psFlashCSInfo->SizeOfScsiFirmware                   = ntohl(psFlashCSInfo->SizeOfScsiFirmware );
-	psFlashCSInfo->OffsetFromZeroForPart2ISOImage       = ntohl(psFlashCSInfo->OffsetFromZeroForPart2ISOImage);
-	psFlashCSInfo->OffsetFromZeroForCalibrationStart    = ntohl(psFlashCSInfo->OffsetFromZeroForCalibrationStart);
-	psFlashCSInfo->OffsetFromZeroForCalibrationEnd      = ntohl(psFlashCSInfo->OffsetFromZeroForCalibrationEnd);
-	psFlashCSInfo->OffsetFromZeroForVSAStart            = ntohl(psFlashCSInfo->OffsetFromZeroForVSAStart);
-	psFlashCSInfo->OffsetFromZeroForVSAEnd              = ntohl(psFlashCSInfo->OffsetFromZeroForVSAEnd);
-	psFlashCSInfo->OffsetFromZeroForControlSectionStart = ntohl(psFlashCSInfo->OffsetFromZeroForControlSectionStart);
-	psFlashCSInfo->OffsetFromZeroForControlSectionData  = ntohl(psFlashCSInfo->OffsetFromZeroForControlSectionData);
-	psFlashCSInfo->CDLessInactivityTimeout 				= ntohl(psFlashCSInfo->CDLessInactivityTimeout);
-	psFlashCSInfo->NewImageSignature                    = ntohl(psFlashCSInfo->NewImageSignature);
-	psFlashCSInfo->FlashSectorSizeSig                   = ntohl(psFlashCSInfo->FlashSectorSizeSig);
-	psFlashCSInfo->FlashSectorSize                      = ntohl(psFlashCSInfo->FlashSectorSize);
-	psFlashCSInfo->FlashWriteSupportSize                = ntohl(psFlashCSInfo->FlashWriteSupportSize);
-	psFlashCSInfo->TotalFlashSize        				= ntohl(psFlashCSInfo->TotalFlashSize);
- 	psFlashCSInfo->FlashBaseAddr         				= ntohl(psFlashCSInfo->FlashBaseAddr);
-	psFlashCSInfo->FlashPartMaxSize      				= ntohl(psFlashCSInfo->FlashPartMaxSize);
- 	psFlashCSInfo->IsCDLessDeviceBootSig 				= ntohl(psFlashCSInfo->IsCDLessDeviceBootSig);
-	psFlashCSInfo->MassStorageTimeout    				= ntohl(psFlashCSInfo->MassStorageTimeout);
+	/* unsigned int Index = 0; */
+	psFlashCSInfo->MagicNumber				= ntohl(psFlashCSInfo->MagicNumber);
+	psFlashCSInfo->FlashLayoutVersion			= ntohl(psFlashCSInfo->FlashLayoutVersion);
+	psFlashCSInfo->ISOImageVersion				= ntohl(psFlashCSInfo->ISOImageVersion);
+	/* won't convert according to old assumption */
+	psFlashCSInfo->SCSIFirmwareVersion			= (psFlashCSInfo->SCSIFirmwareVersion);
+	psFlashCSInfo->OffsetFromZeroForPart1ISOImage		= ntohl(psFlashCSInfo->OffsetFromZeroForPart1ISOImage);
+	psFlashCSInfo->OffsetFromZeroForScsiFirmware		= ntohl(psFlashCSInfo->OffsetFromZeroForScsiFirmware);
+	psFlashCSInfo->SizeOfScsiFirmware			= ntohl(psFlashCSInfo->SizeOfScsiFirmware);
+	psFlashCSInfo->OffsetFromZeroForPart2ISOImage		= ntohl(psFlashCSInfo->OffsetFromZeroForPart2ISOImage);
+	psFlashCSInfo->OffsetFromZeroForCalibrationStart	= ntohl(psFlashCSInfo->OffsetFromZeroForCalibrationStart);
+	psFlashCSInfo->OffsetFromZeroForCalibrationEnd		= ntohl(psFlashCSInfo->OffsetFromZeroForCalibrationEnd);
+	psFlashCSInfo->OffsetFromZeroForVSAStart		= ntohl(psFlashCSInfo->OffsetFromZeroForVSAStart);
+	psFlashCSInfo->OffsetFromZeroForVSAEnd			= ntohl(psFlashCSInfo->OffsetFromZeroForVSAEnd);
+	psFlashCSInfo->OffsetFromZeroForControlSectionStart	= ntohl(psFlashCSInfo->OffsetFromZeroForControlSectionStart);
+	psFlashCSInfo->OffsetFromZeroForControlSectionData	= ntohl(psFlashCSInfo->OffsetFromZeroForControlSectionData);
+	psFlashCSInfo->CDLessInactivityTimeout			= ntohl(psFlashCSInfo->CDLessInactivityTimeout);
+	psFlashCSInfo->NewImageSignature			= ntohl(psFlashCSInfo->NewImageSignature);
+	psFlashCSInfo->FlashSectorSizeSig			= ntohl(psFlashCSInfo->FlashSectorSizeSig);
+	psFlashCSInfo->FlashSectorSize				= ntohl(psFlashCSInfo->FlashSectorSize);
+	psFlashCSInfo->FlashWriteSupportSize			= ntohl(psFlashCSInfo->FlashWriteSupportSize);
+	psFlashCSInfo->TotalFlashSize				= ntohl(psFlashCSInfo->TotalFlashSize);
+	psFlashCSInfo->FlashBaseAddr				= ntohl(psFlashCSInfo->FlashBaseAddr);
+	psFlashCSInfo->FlashPartMaxSize				= ntohl(psFlashCSInfo->FlashPartMaxSize);
+	psFlashCSInfo->IsCDLessDeviceBootSig			= ntohl(psFlashCSInfo->IsCDLessDeviceBootSig);
+	psFlashCSInfo->MassStorageTimeout			= ntohl(psFlashCSInfo->MassStorageTimeout);
 
 	return STATUS_SUCCESS;
 }
 
-static INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section)
+static int IsSectionExistInVendorInfo(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL section)
 {
- 	return ( Adapter->uiVendorExtnFlag &&
- 		(Adapter->psFlash2xVendorInfo->VendorSection[section].AccessFlags & FLASH2X_SECTION_PRESENT) &&
- 		(Adapter->psFlash2xVendorInfo->VendorSection[section].OffsetFromZeroForSectionStart != UNINIT_PTR_IN_CS) );
+	return (Adapter->uiVendorExtnFlag &&
+		(Adapter->psFlash2xVendorInfo->VendorSection[section].AccessFlags & FLASH2X_SECTION_PRESENT) &&
+		(Adapter->psFlash2xVendorInfo->VendorSection[section].OffsetFromZeroForSectionStart != UNINIT_PTR_IN_CS));
 }
 
-static VOID UpdateVendorInfo(PMINI_ADAPTER Adapter)
+static VOID UpdateVendorInfo(struct bcm_mini_adapter *Adapter)
 {
 	B_UINT32 i = 0;
-	UINT uiSizeSection = 0;
+	unsigned int uiSizeSection = 0;
 
 	Adapter->uiVendorExtnFlag = FALSE;
 
-	for(i = 0;i < TOTAL_SECTIONS;i++)
+	for (i = 0; i < TOTAL_SECTIONS; i++)
 		Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart = UNINIT_PTR_IN_CS;
 
-	if(STATUS_SUCCESS != vendorextnGetSectionInfo(Adapter, Adapter->psFlash2xVendorInfo))
+	if (STATUS_SUCCESS != vendorextnGetSectionInfo(Adapter, Adapter->psFlash2xVendorInfo))
 		return;
 
 	i = 0;
-	while(i < TOTAL_SECTIONS)
-	{
-		if(!(Adapter->psFlash2xVendorInfo->VendorSection[i].AccessFlags & FLASH2X_SECTION_PRESENT))
-		{
+	while (i < TOTAL_SECTIONS) {
+		if (!(Adapter->psFlash2xVendorInfo->VendorSection[i].AccessFlags & FLASH2X_SECTION_PRESENT)) {
 			i++;
 			continue;
 		}
 
 		Adapter->uiVendorExtnFlag = TRUE;
 		uiSizeSection = (Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionEnd -
-						Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart);
+				Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart);
 
-		switch(i)
-		{
+		switch (i) {
 		case DSD0:
-			if(( uiSizeSection >= (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER))) &&
-			(UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart))
+			if ((uiSizeSection >= (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER))) &&
+				(UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart))
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDEnd = VENDOR_PTR_IN_CS;
 			else
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDEnd = UNINIT_PTR_IN_CS;
 			break;
 
 		case DSD1:
-			if(( uiSizeSection >= (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER))) &&
-			(UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart))
+			if ((uiSizeSection >= (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER))) &&
+				(UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart))
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1End = VENDOR_PTR_IN_CS;
 			else
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1End = UNINIT_PTR_IN_CS;
 			break;
 
 		case DSD2:
-			if(( uiSizeSection >= (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER))) &&
-			(UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart))
+			if ((uiSizeSection >= (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER))) &&
+				(UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart))
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2End = VENDOR_PTR_IN_CS;
 			else
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2End = UNINIT_PTR_IN_CS;
 			break;
 		case VSA0:
-			if(UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart)
+			if (UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart)
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAEnd = VENDOR_PTR_IN_CS;
 			else
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAEnd = UNINIT_PTR_IN_CS;
 			break;
 
 		case VSA1:
-			if(UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart)
+			if (UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart)
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1End = VENDOR_PTR_IN_CS;
 			else
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1End = UNINIT_PTR_IN_CS;
 			break;
 		case VSA2:
-			if(UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart)
+			if (UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart)
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2End = VENDOR_PTR_IN_CS;
 			else
 				Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2End = UNINIT_PTR_IN_CS;
@@ -2798,133 +2493,111 @@ static VOID UpdateVendorInfo(PMINI_ADAPTER Adapter)
 		}
 		i++;
 	}
-
 }
 
-//-----------------------------------------------------------------------------
-// Procedure:	BcmGetFlashCSInfo
-//
-// Description: Reads control structure and gets Cal section addresses.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//
-// Returns:
-//		<VOID>
-//-----------------------------------------------------------------------------
-
-static INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
+/*
+ * Procedure:	BcmGetFlashCSInfo
+ *
+ * Description: Reads control structure and gets Cal section addresses.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *
+ * Returns:
+ *		<VOID>
+ */
+
+static int BcmGetFlashCSInfo(struct bcm_mini_adapter *Adapter)
 {
-	//FLASH_CS_INFO sFlashCsInfo = {0};
+	/* FLASH_CS_INFO sFlashCsInfo = {0}; */
+
+	#if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS)
+		unsigned int value;
+	#endif
 
-#if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS)
-	UINT value;
-#endif
-	UINT uiFlashLayoutMajorVersion;
+	unsigned int uiFlashLayoutMajorVersion;
 	Adapter->uiFlashLayoutMinorVersion = 0;
 	Adapter->uiFlashLayoutMajorVersion = 0;
 	Adapter->ulFlashControlSectionStart = FLASH_CS_INFO_START_ADDR;
 
-
 	Adapter->uiFlashBaseAdd = 0;
 	Adapter->ulFlashCalStart = 0;
-	memset(Adapter->psFlashCSInfo, 0 ,sizeof(FLASH_CS_INFO));
-	memset(Adapter->psFlash2xCSInfo, 0 ,sizeof(FLASH2X_CS_INFO));
+	memset(Adapter->psFlashCSInfo, 0 , sizeof(FLASH_CS_INFO));
+	memset(Adapter->psFlash2xCSInfo, 0 , sizeof(FLASH2X_CS_INFO));
 
-	if(!Adapter->bDDRInitDone)
-	{
-		{
-			value = FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT;
-			wrmalt(Adapter, 0xAF00A080, &value, sizeof(value));
-		}
+	if (!Adapter->bDDRInitDone) {
+		value = FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT;
+		wrmalt(Adapter, 0xAF00A080, &value, sizeof(value));
 	}
 
-
-	// Reading first 8 Bytes to get the Flash Layout
-	// MagicNumber(4 bytes) +FlashLayoutMinorVersion(2 Bytes) +FlashLayoutMajorVersion(2 Bytes)
-	BeceemFlashBulkRead(Adapter,(PUINT)Adapter->psFlashCSInfo,Adapter->ulFlashControlSectionStart,8);
+	/* Reading first 8 Bytes to get the Flash Layout
+	 * MagicNumber(4 bytes) +FlashLayoutMinorVersion(2 Bytes) +FlashLayoutMajorVersion(2 Bytes)
+	 */
+	BeceemFlashBulkRead(Adapter, (PUINT)Adapter->psFlashCSInfo, Adapter->ulFlashControlSectionStart, 8);
 
 	Adapter->psFlashCSInfo->FlashLayoutVersion =  ntohl(Adapter->psFlashCSInfo->FlashLayoutVersion);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Layout Version :%X", (Adapter->psFlashCSInfo->FlashLayoutVersion));
-	//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Layout Minor Version :%d\n", ntohs(sFlashCsInfo.FlashLayoutMinorVersion));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Signature is  :%x\n", ntohl(Adapter->psFlashCSInfo->MagicNumber));
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Layout Version :%X", (Adapter->psFlashCSInfo->FlashLayoutVersion));
+	/* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Layout Minor Version :%d\n", ntohs(sFlashCsInfo.FlashLayoutMinorVersion)); */
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Signature is  :%x\n", ntohl(Adapter->psFlashCSInfo->MagicNumber));
 
-	if(FLASH_CONTROL_STRUCT_SIGNATURE == ntohl(Adapter->psFlashCSInfo->MagicNumber))
-	{
+	if (FLASH_CONTROL_STRUCT_SIGNATURE == ntohl(Adapter->psFlashCSInfo->MagicNumber)) {
 		uiFlashLayoutMajorVersion = MAJOR_VERSION((Adapter->psFlashCSInfo->FlashLayoutVersion));
 		Adapter->uiFlashLayoutMinorVersion = MINOR_VERSION((Adapter->psFlashCSInfo->FlashLayoutVersion));
-	}
-	else
-	{
+	} else {
 		Adapter->uiFlashLayoutMinorVersion = 0;
 		uiFlashLayoutMajorVersion = 0;
 	}
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"FLASH LAYOUT MAJOR VERSION :%X", uiFlashLayoutMajorVersion);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FLASH LAYOUT MAJOR VERSION :%X", uiFlashLayoutMajorVersion);
 
-	if(uiFlashLayoutMajorVersion < FLASH_2X_MAJOR_NUMBER)
-	{
-		BeceemFlashBulkRead(Adapter,(PUINT)Adapter->psFlashCSInfo,Adapter->ulFlashControlSectionStart,sizeof(FLASH_CS_INFO));
+	if (uiFlashLayoutMajorVersion < FLASH_2X_MAJOR_NUMBER) {
+		BeceemFlashBulkRead(Adapter, (PUINT)Adapter->psFlashCSInfo, Adapter->ulFlashControlSectionStart, sizeof(FLASH_CS_INFO));
 		ConvertEndianOfCSStructure(Adapter->psFlashCSInfo);
 		Adapter->ulFlashCalStart = (Adapter->psFlashCSInfo->OffsetFromZeroForCalibrationStart);
 
-		if(!((Adapter->uiFlashLayoutMajorVersion == 1) && (Adapter->uiFlashLayoutMinorVersion == 1)))
-		{
+		if (!((Adapter->uiFlashLayoutMajorVersion == 1) && (Adapter->uiFlashLayoutMinorVersion == 1)))
 			Adapter->ulFlashControlSectionStart = Adapter->psFlashCSInfo->OffsetFromZeroForControlSectionStart;
-		}
 
-		if((FLASH_CONTROL_STRUCT_SIGNATURE == (Adapter->psFlashCSInfo->MagicNumber)) &&
-		   (SCSI_FIRMWARE_MINOR_VERSION <= MINOR_VERSION(Adapter->psFlashCSInfo->SCSIFirmwareVersion)) &&
-		   (FLASH_SECTOR_SIZE_SIG == (Adapter->psFlashCSInfo->FlashSectorSizeSig)) &&
-		   (BYTE_WRITE_SUPPORT == (Adapter->psFlashCSInfo->FlashWriteSupportSize)))
-		{
+		if ((FLASH_CONTROL_STRUCT_SIGNATURE == (Adapter->psFlashCSInfo->MagicNumber)) &&
+			(SCSI_FIRMWARE_MINOR_VERSION <= MINOR_VERSION(Adapter->psFlashCSInfo->SCSIFirmwareVersion)) &&
+			(FLASH_SECTOR_SIZE_SIG == (Adapter->psFlashCSInfo->FlashSectorSizeSig)) &&
+			(BYTE_WRITE_SUPPORT == (Adapter->psFlashCSInfo->FlashWriteSupportSize))) {
 			Adapter->ulFlashWriteSize = (Adapter->psFlashCSInfo->FlashWriteSupportSize);
-		   	Adapter->fpFlashWrite = flashByteWrite;
-		   	Adapter->fpFlashWriteWithStatusCheck = flashByteWriteStatus;
-		}
-		else
-		{
+			Adapter->fpFlashWrite = flashByteWrite;
+			Adapter->fpFlashWriteWithStatusCheck = flashByteWriteStatus;
+		} else {
 			Adapter->ulFlashWriteSize = MAX_RW_SIZE;
 			Adapter->fpFlashWrite = flashWrite;
-		   	Adapter->fpFlashWriteWithStatusCheck = flashWriteStatus;
+			Adapter->fpFlashWriteWithStatusCheck = flashWriteStatus;
 		}
 
 		BcmGetFlashSectorSize(Adapter, (Adapter->psFlashCSInfo->FlashSectorSizeSig),
-					 (Adapter->psFlashCSInfo->FlashSectorSize));
-
-
+				(Adapter->psFlashCSInfo->FlashSectorSize));
 		Adapter->uiFlashBaseAdd = Adapter->psFlashCSInfo->FlashBaseAddr & 0xFCFFFFFF;
-
-
-	}
-	else
-	{
-		if(BcmFlash2xBulkRead(Adapter,(PUINT)Adapter->psFlash2xCSInfo,NO_SECTION_VAL,
-				Adapter->ulFlashControlSectionStart,sizeof(FLASH2X_CS_INFO)))
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Unable to read CS structure \n");
+	} else {
+		if (BcmFlash2xBulkRead(Adapter, (PUINT)Adapter->psFlash2xCSInfo, NO_SECTION_VAL,
+					Adapter->ulFlashControlSectionStart, sizeof(FLASH2X_CS_INFO))) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Unable to read CS structure\n");
 			return STATUS_FAILURE;
 		}
+
 		ConvertEndianOf2XCSStructure(Adapter->psFlash2xCSInfo);
-		BcmDumpFlash2XCSStructure(Adapter->psFlash2xCSInfo,Adapter);
-		if((FLASH_CONTROL_STRUCT_SIGNATURE == Adapter->psFlash2xCSInfo->MagicNumber) &&
-		   (SCSI_FIRMWARE_MINOR_VERSION <= MINOR_VERSION(Adapter->psFlash2xCSInfo->SCSIFirmwareVersion)) &&
-		   (FLASH_SECTOR_SIZE_SIG == Adapter->psFlash2xCSInfo->FlashSectorSizeSig) &&
-		   (BYTE_WRITE_SUPPORT == Adapter->psFlash2xCSInfo->FlashWriteSupportSize))
-		{
+		BcmDumpFlash2XCSStructure(Adapter->psFlash2xCSInfo, Adapter);
+		if ((FLASH_CONTROL_STRUCT_SIGNATURE == Adapter->psFlash2xCSInfo->MagicNumber) &&
+			(SCSI_FIRMWARE_MINOR_VERSION <= MINOR_VERSION(Adapter->psFlash2xCSInfo->SCSIFirmwareVersion)) &&
+			(FLASH_SECTOR_SIZE_SIG == Adapter->psFlash2xCSInfo->FlashSectorSizeSig) &&
+			(BYTE_WRITE_SUPPORT == Adapter->psFlash2xCSInfo->FlashWriteSupportSize)) {
 			Adapter->ulFlashWriteSize = Adapter->psFlash2xCSInfo->FlashWriteSupportSize;
-		   	Adapter->fpFlashWrite = flashByteWrite;
-		   	Adapter->fpFlashWriteWithStatusCheck = flashByteWriteStatus;
-		}
-		else
-		{
+			Adapter->fpFlashWrite = flashByteWrite;
+			Adapter->fpFlashWriteWithStatusCheck = flashByteWriteStatus;
+		} else {
 			Adapter->ulFlashWriteSize = MAX_RW_SIZE;
 			Adapter->fpFlashWrite = flashWrite;
-		   	Adapter->fpFlashWriteWithStatusCheck = flashWriteStatus;
+			Adapter->fpFlashWriteWithStatusCheck = flashWriteStatus;
 		}
 
 		BcmGetFlashSectorSize(Adapter, Adapter->psFlash2xCSInfo->FlashSectorSizeSig,
-					Adapter->psFlash2xCSInfo->FlashSectorSize);
+				Adapter->psFlash2xCSInfo->FlashSectorSize);
 
 		UpdateVendorInfo(Adapter);
 
@@ -2932,426 +2605,394 @@ static INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
 		BcmGetActiveISO(Adapter);
 		Adapter->uiFlashBaseAdd = Adapter->psFlash2xCSInfo->FlashBaseAddr & 0xFCFFFFFF;
 		Adapter->ulFlashControlSectionStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForControlSectionStart;
-
 	}
 	/*
-	Concerns: what if CS sector size does not match with this sector size ???
-	what is the indication of AccessBitMap  in CS in flash 2.x ????
-	*/
+	 * Concerns: what if CS sector size does not match with this sector size ???
+	 * what is the indication of AccessBitMap  in CS in flash 2.x ????
+	 */
 	Adapter->ulFlashID = BcmReadFlashRDID(Adapter);
-
 	Adapter->uiFlashLayoutMajorVersion = uiFlashLayoutMajorVersion;
 
-
-	return STATUS_SUCCESS ;
+	return STATUS_SUCCESS;
 }
 
-
-//-----------------------------------------------------------------------------
-// Procedure:	BcmGetNvmType
-//
-// Description: Finds the type of NVM used.
-//
-// Arguments:
-//		Adapter    - ptr to Adapter object instance
-//
-// Returns:
-//		NVM_TYPE
-//
-//-----------------------------------------------------------------------------
-
-static NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter)
+/*
+ * Procedure:	BcmGetNvmType
+ *
+ * Description: Finds the type of NVM used.
+ *
+ * Arguments:
+ *		Adapter    - ptr to Adapter object instance
+ *
+ * Returns:
+ *		NVM_TYPE
+ *
+ */
+
+static NVM_TYPE BcmGetNvmType(struct bcm_mini_adapter *Adapter)
 {
-	UINT uiData = 0;
+	unsigned int uiData = 0;
 
-	BeceemEEPROMBulkRead(Adapter,&uiData,0x0,4);
-	if(uiData == BECM)
-	{
+	BeceemEEPROMBulkRead(Adapter, &uiData, 0x0, 4);
+	if (uiData == BECM)
 		return NVM_EEPROM;
-	}
-	//
-	// Read control struct and get cal addresses before accessing the flash
-	//
+
+	/*
+	 * Read control struct and get cal addresses before accessing the flash
+	 */
 	BcmGetFlashCSInfo(Adapter);
 
-	BeceemFlashBulkRead(Adapter,&uiData,0x0 + Adapter->ulFlashCalStart,4);
-	if(uiData == BECM)
-	{
+	BeceemFlashBulkRead(Adapter, &uiData, 0x0 + Adapter->ulFlashCalStart, 4);
+	if (uiData == BECM)
 		return NVM_FLASH;
-	}
-//
-// even if there is no valid signature on EEPROM/FLASH find out if they really exist.
-// if exist select it.
-//
-	if(BcmGetEEPROMSize(Adapter))
-	{
-		return NVM_EEPROM;
-	}
-
-//TBD for Flash.
 
+	/*
+	 * even if there is no valid signature on EEPROM/FLASH find out if they really exist.
+	 * if exist select it.
+	 */
+	if (BcmGetEEPROMSize(Adapter))
+		return NVM_EEPROM;
 
+	/* TBD for Flash. */
 	return NVM_UNKNOWN;
 }
 
-/**
-*	BcmGetSectionValStartOffset - this will calculate the section's starting offset if section val is given
-*	@Adapter : Drivers Private Data structure
-*	@eFlashSectionVal : Flash secion value defined in enum FLASH2X_SECTION_VAL
-*
-*	Return value:-
-*	On success it return the start offset of the provided section val
-*	On Failure -returns STATUS_FAILURE
-**/
-
-INT BcmGetSectionValStartOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlashSectionVal)
+/*
+ * BcmGetSectionValStartOffset - this will calculate the section's starting offset if section val is given
+ * @Adapter : Drivers Private Data structure
+ * @eFlashSectionVal : Flash secion value defined in enum FLASH2X_SECTION_VAL
+ *
+ * Return value:-
+ * On success it return the start offset of the provided section val
+ * On Failure -returns STATUS_FAILURE
+ */
+
+int BcmGetSectionValStartOffset(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlashSectionVal)
 {
 	/*
-	*	Considering all the section for which end offset can be calculated or directly given
-	*	in CS Structure. if matching case does not exist, return STATUS_FAILURE indicating section
-	*	endoffset can't be calculated or given in CS Structure.
-	*/
+	 * Considering all the section for which end offset can be calculated or directly given
+	 * in CS Structure. if matching case does not exist, return STATUS_FAILURE indicating section
+	 * endoffset can't be calculated or given in CS Structure.
+	 */
 
-	INT SectStartOffset = 0 ;
+	int SectStartOffset = 0;
 
-	SectStartOffset = INVALID_OFFSET ;
+	SectStartOffset = INVALID_OFFSET;
 
-	if(IsSectionExistInVendorInfo(Adapter,eFlashSectionVal))
-	{
+	if (IsSectionExistInVendorInfo(Adapter, eFlashSectionVal))
 		return Adapter->psFlash2xVendorInfo->VendorSection[eFlashSectionVal].OffsetFromZeroForSectionStart;
-	}
 
-	switch(eFlashSectionVal)
-	{
-		case ISO_IMAGE1 :
-			  if((Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start != UNINIT_PTR_IN_CS) &&
-			  	(IsNonCDLessDevice(Adapter) == FALSE))
-				  SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start);
-			   break;
-		case ISO_IMAGE2 :
-				if((Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start != UNINIT_PTR_IN_CS) &&
-					(IsNonCDLessDevice(Adapter) == FALSE))
-			  		SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start);
-			  break;
-		case DSD0 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart != UNINIT_PTR_IN_CS)
-					SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart);
-				break;
-		case DSD1 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start != UNINIT_PTR_IN_CS)
-					SectStartOffset =  (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start);
-				break;
-		case DSD2 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start != UNINIT_PTR_IN_CS)
-					SectStartOffset =  (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start);
-				break;
-		case VSA0 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart != UNINIT_PTR_IN_CS)
-					SectStartOffset =  (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart);
-				break;
-		case VSA1 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start != UNINIT_PTR_IN_CS)
-					SectStartOffset =  (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start);
-				break;
-		case VSA2 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start != UNINIT_PTR_IN_CS)
-					SectStartOffset =  (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start);
-				break;
-		case SCSI :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware != UNINIT_PTR_IN_CS)
-					SectStartOffset =  (Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware);
-				break;
-		case CONTROL_SECTION :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForControlSectionStart != UNINIT_PTR_IN_CS)
-					SectStartOffset =  (Adapter->psFlash2xCSInfo->OffsetFromZeroForControlSectionStart);
-				break;
-		case ISO_IMAGE1_PART2 :
-				if(Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start != UNINIT_PTR_IN_CS)
-				 	 SectStartOffset =  (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start);
-				 break;
-		case ISO_IMAGE1_PART3 :
-				if(Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start != UNINIT_PTR_IN_CS)
-				  SectStartOffset =  (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start);
-			  	break;
-		case ISO_IMAGE2_PART2 :
-				if(Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start != UNINIT_PTR_IN_CS)
-			 		 SectStartOffset =  (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start);
-			    break;
-		case ISO_IMAGE2_PART3 :
-  			  if(Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start != UNINIT_PTR_IN_CS)
-  				  SectStartOffset =  (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start);
-  			  break;
-		default :
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section Does not exist in Flash 2.x");
-			SectStartOffset =  INVALID_OFFSET;
+	switch (eFlashSectionVal) {
+	case ISO_IMAGE1:
+		if ((Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start != UNINIT_PTR_IN_CS) &&
+			(IsNonCDLessDevice(Adapter) == FALSE))
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start);
+		break;
+	case ISO_IMAGE2:
+		if ((Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start != UNINIT_PTR_IN_CS) &&
+			(IsNonCDLessDevice(Adapter) == FALSE))
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start);
+		break;
+	case DSD0:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart);
+		break;
+	case DSD1:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start);
+		break;
+	case DSD2:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start);
+		break;
+	case VSA0:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart);
+		break;
+	case VSA1:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start);
+		break;
+	case VSA2:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start);
+		break;
+	case SCSI:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware);
+		break;
+	case CONTROL_SECTION:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForControlSectionStart != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForControlSectionStart);
+		break;
+	case ISO_IMAGE1_PART2:
+		if (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start);
+		break;
+	case ISO_IMAGE1_PART3:
+		if (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start);
+		break;
+	case ISO_IMAGE2_PART2:
+		if (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start);
+		break;
+	case ISO_IMAGE2_PART3:
+		if (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start != UNINIT_PTR_IN_CS)
+			SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start);
+		break;
+	default:
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section Does not exist in Flash 2.x");
+		SectStartOffset = INVALID_OFFSET;
 	}
+
 	return SectStartOffset;
 }
 
-/**
-*	BcmGetSectionValEndOffset - this will calculate the section's Ending offset if section val is given
-*	@Adapter : Drivers Private Data structure
-*	@eFlashSectionVal : Flash secion value defined in enum FLASH2X_SECTION_VAL
-*
-*	Return value:-
-*	On success it return the end offset of the provided section val
-*	On Failure -returns STATUS_FAILURE
-**/
-
-INT BcmGetSectionValEndOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
+/*
+ * BcmGetSectionValEndOffset - this will calculate the section's Ending offset if section val is given
+ * @Adapter : Drivers Private Data structure
+ * @eFlashSectionVal : Flash secion value defined in enum FLASH2X_SECTION_VAL
+ *
+ * Return value:-
+ * On success it return the end offset of the provided section val
+ * On Failure -returns STATUS_FAILURE
+ */
+
+int BcmGetSectionValEndOffset(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
 {
-	INT SectEndOffset = 0 ;
-	SectEndOffset = INVALID_OFFSET;
+	int SectEndOffset = 0;
 
-	if(IsSectionExistInVendorInfo(Adapter,eFlash2xSectionVal))
-	{
+	SectEndOffset = INVALID_OFFSET;
+	if (IsSectionExistInVendorInfo(Adapter, eFlash2xSectionVal))
 		return Adapter->psFlash2xVendorInfo->VendorSection[eFlash2xSectionVal].OffsetFromZeroForSectionEnd;
-	}
 
-	switch(eFlash2xSectionVal)
-	{
-		case ISO_IMAGE1 :
-			 if((Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End!= UNINIT_PTR_IN_CS) &&
-			 	 (IsNonCDLessDevice(Adapter) == FALSE))
-				  SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End);
-			   break;
-		case ISO_IMAGE2 :
-			if((Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End!= UNINIT_PTR_IN_CS) &&
-				(IsNonCDLessDevice(Adapter) == FALSE))
-					SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End);
-			 break;
-		case DSD0 :
-			if(Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDEnd != UNINIT_PTR_IN_CS)
-				SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDEnd);
-			break;
-		case DSD1 :
-			if(Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1End != UNINIT_PTR_IN_CS)
-				SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1End);
-			break;
-		case DSD2 :
-			if(Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2End != UNINIT_PTR_IN_CS)
-				SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2End);
-			break;
-		case VSA0 :
-			if(Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAEnd != UNINIT_PTR_IN_CS)
-				SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAEnd);
-			break;
-		case VSA1 :
-			if(Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1End != UNINIT_PTR_IN_CS)
-				SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1End);
-			break;
-		case VSA2 :
-			if(Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2End != UNINIT_PTR_IN_CS)
-				SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2End);
-			break;
-		case SCSI :
-			if(Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware != UNINIT_PTR_IN_CS)
-				SectEndOffset = ((Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware) +
+	switch (eFlash2xSectionVal) {
+	case ISO_IMAGE1:
+		if ((Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End != UNINIT_PTR_IN_CS) &&
+			(IsNonCDLessDevice(Adapter) == FALSE))
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End);
+		break;
+	case ISO_IMAGE2:
+		if ((Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End != UNINIT_PTR_IN_CS) &&
+			(IsNonCDLessDevice(Adapter) == FALSE))
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End);
+		break;
+	case DSD0:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDEnd != UNINIT_PTR_IN_CS)
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDEnd);
+		break;
+	case DSD1:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1End != UNINIT_PTR_IN_CS)
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1End);
+		break;
+	case DSD2:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2End != UNINIT_PTR_IN_CS)
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2End);
+		break;
+	case VSA0:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAEnd != UNINIT_PTR_IN_CS)
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAEnd);
+		break;
+	case VSA1:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1End != UNINIT_PTR_IN_CS)
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1End);
+		break;
+	case VSA2:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2End != UNINIT_PTR_IN_CS)
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2End);
+		break;
+	case SCSI:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware != UNINIT_PTR_IN_CS)
+			SectEndOffset = ((Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware) +
 					(Adapter->psFlash2xCSInfo->SizeOfScsiFirmware));
-			break;
-		case CONTROL_SECTION :
-				//Not Clear So Putting failure. confirm and fix it.
-				SectEndOffset = STATUS_FAILURE;
-		case ISO_IMAGE1_PART2 :
-				if(Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End!= UNINIT_PTR_IN_CS)
-				 	 SectEndOffset =  (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End);
-				 break;
-		case ISO_IMAGE1_PART3 :
-				if(Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End!= UNINIT_PTR_IN_CS)
-				  SectEndOffset =  (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End);
-			  	break;
-		case ISO_IMAGE2_PART2 :
-				if(Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End != UNINIT_PTR_IN_CS)
-			 		 SectEndOffset =  (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End);
-			    break;
-		case ISO_IMAGE2_PART3 :
-  			  if(Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End!= UNINIT_PTR_IN_CS)
-  				  SectEndOffset =  (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End);
-  			  break;
-
-		default :
-			SectEndOffset = INVALID_OFFSET;
+		break;
+	case CONTROL_SECTION:
+		/* Not Clear So Putting failure. confirm and fix it. */
+		SectEndOffset = STATUS_FAILURE;
+	case ISO_IMAGE1_PART2:
+		if (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End != UNINIT_PTR_IN_CS)
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End);
+		break;
+	case ISO_IMAGE1_PART3:
+		if (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End != UNINIT_PTR_IN_CS)
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End);
+		break;
+	case ISO_IMAGE2_PART2:
+		if (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End != UNINIT_PTR_IN_CS)
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End);
+		break;
+	case ISO_IMAGE2_PART3:
+		if (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End != UNINIT_PTR_IN_CS)
+			SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End);
+		break;
+	default:
+		SectEndOffset = INVALID_OFFSET;
 	}
+
 	return SectEndOffset ;
 }
 
 /*
-*	BcmFlash2xBulkRead:- Read API for Flash Map 2.x .
-*	@Adapter :Driver Private Data Structure
-*	@pBuffer : Buffer where data has to be put after reading
-*	@eFlashSectionVal :Flash Section Val defined in FLASH2X_SECTION_VAL
-*	@uiOffsetWithinSectionVal :- Offset with in provided section
-*	@uiNumBytes : Number of Bytes for Read
-*
-*	Return value:-
-*		return true on success and STATUS_FAILURE on fail.
-*/
-
-INT BcmFlash2xBulkRead(
-	PMINI_ADAPTER Adapter,
-	PUINT pBuffer,
-	FLASH2X_SECTION_VAL eFlash2xSectionVal,
-	UINT uiOffsetWithinSectionVal,
-	UINT uiNumBytes)
+ * BcmFlash2xBulkRead:- Read API for Flash Map 2.x .
+ * @Adapter :Driver Private Data Structure
+ * @pBuffer : Buffer where data has to be put after reading
+ * @eFlashSectionVal :Flash Section Val defined in FLASH2X_SECTION_VAL
+ * @uiOffsetWithinSectionVal :- Offset with in provided section
+ * @uiNumBytes : Number of Bytes for Read
+ *
+ * Return value:-
+ * return true on success and STATUS_FAILURE on fail.
+ */
+
+int BcmFlash2xBulkRead(struct bcm_mini_adapter *Adapter,
+		PUINT pBuffer,
+		FLASH2X_SECTION_VAL eFlash2xSectionVal,
+		unsigned int uiOffsetWithinSectionVal,
+		unsigned int uiNumBytes)
 {
+	int Status = STATUS_SUCCESS;
+	int SectionStartOffset = 0;
+	unsigned int uiAbsoluteOffset = 0;
+	unsigned int uiTemp = 0, value = 0;
 
-	INT Status = STATUS_SUCCESS;
-	INT SectionStartOffset = 0;
-	UINT uiAbsoluteOffset = 0 ;
-	UINT uiTemp =0, value =0 ;
-	if(Adapter == NULL)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Adapter structure is NULL");
+	if (!Adapter) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Adapter structure is NULL");
 		return -EINVAL;
 	}
-	if(Adapter->device_removed )
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Device has been removed");
+	if (Adapter->device_removed) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device has been removed");
 		return -ENODEV;
 	}
 
-	//NO_SECTION_VAL means absolute offset is given.
-	if(eFlash2xSectionVal == NO_SECTION_VAL)
+	/* NO_SECTION_VAL means absolute offset is given. */
+	if (eFlash2xSectionVal == NO_SECTION_VAL)
 		SectionStartOffset = 0;
 	else
-		SectionStartOffset = BcmGetSectionValStartOffset(Adapter,eFlash2xSectionVal);
+		SectionStartOffset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectionVal);
 
-	if(SectionStartOffset == STATUS_FAILURE )
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"This Section<%d> does not exixt in Flash 2.x Map ",eFlash2xSectionVal);
+	if (SectionStartOffset == STATUS_FAILURE) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "This Section<%d> does not exixt in Flash 2.x Map ", eFlash2xSectionVal);
 		return -EINVAL;
 	}
 
-	if(IsSectionExistInVendorInfo(Adapter,eFlash2xSectionVal))
-		return vendorextnReadSection(Adapter,(PUCHAR)pBuffer, eFlash2xSectionVal, uiOffsetWithinSectionVal, uiNumBytes);
+	if (IsSectionExistInVendorInfo(Adapter, eFlash2xSectionVal))
+		return vendorextnReadSection(Adapter, (PUCHAR)pBuffer, eFlash2xSectionVal, uiOffsetWithinSectionVal, uiNumBytes);
 
-	//calculating  the absolute offset from FLASH;
+	/* calculating  the absolute offset from FLASH; */
 	uiAbsoluteOffset = uiOffsetWithinSectionVal + SectionStartOffset;
 	rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
 	value = 0;
-	wrmalt(Adapter, 0x0f000C80,&value, sizeof(value));
-
-	Status= BeceemFlashBulkRead(Adapter, pBuffer,uiAbsoluteOffset,uiNumBytes) ;
-
+	wrmalt(Adapter, 0x0f000C80, &value, sizeof(value));
+	Status = BeceemFlashBulkRead(Adapter, pBuffer, uiAbsoluteOffset, uiNumBytes);
 	wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
-	if(Status)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Flash Read Failed with Status :%d", Status);
-		return Status ;
+	if (Status) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Read Failed with Status :%d", Status);
+		return Status;
 	}
 
 	return Status;
 }
 
 /*
-*	BcmFlash2xBulkWrite :-API for Writing on the Flash Map 2.x.
-*	@Adapter :Driver Private Data Structure
-*	@pBuffer : Buffer From where data has to taken for writing
-*	@eFlashSectionVal :Flash Section Val defined in FLASH2X_SECTION_VAL
-*	@uiOffsetWithinSectionVal :- Offset with in provided section
-*	@uiNumBytes : Number of Bytes for Write
-*
-*	Return value:-
-*		return true on success and STATUS_FAILURE on fail.
-*
-*/
-
-INT BcmFlash2xBulkWrite(
-	PMINI_ADAPTER Adapter,
-	PUINT pBuffer,
-	FLASH2X_SECTION_VAL eFlash2xSectVal,
-	UINT uiOffset,
-	UINT uiNumBytes,
-	UINT bVerify)
+ * BcmFlash2xBulkWrite :-API for Writing on the Flash Map 2.x.
+ * @Adapter :Driver Private Data Structure
+ * @pBuffer : Buffer From where data has to taken for writing
+ * @eFlashSectionVal :Flash Section Val defined in FLASH2X_SECTION_VAL
+ * @uiOffsetWithinSectionVal :- Offset with in provided section
+ * @uiNumBytes : Number of Bytes for Write
+ *
+ * Return value:-
+ * return true on success and STATUS_FAILURE on fail.
+ *
+ */
+
+int BcmFlash2xBulkWrite(struct bcm_mini_adapter *Adapter,
+			PUINT pBuffer,
+			FLASH2X_SECTION_VAL eFlash2xSectVal,
+			unsigned int uiOffset,
+			unsigned int uiNumBytes,
+			unsigned int bVerify)
 {
+	int Status = STATUS_SUCCESS;
+	unsigned int FlashSectValStartOffset = 0;
+	unsigned int uiTemp = 0, value = 0;
 
-	INT Status 	= STATUS_SUCCESS;
-	UINT FlashSectValStartOffset = 0;
-	UINT uiTemp = 0, value = 0;
-	if(Adapter == NULL)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Adapter structure is NULL");
+	if (!Adapter) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Adapter structure is NULL");
 		return -EINVAL;
 	}
-	if(Adapter->device_removed )
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Device has been removed");
+
+	if (Adapter->device_removed) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device has been removed");
 		return -ENODEV;
 	}
 
-	//NO_SECTION_VAL means absolute offset is given.
-	if(eFlash2xSectVal == NO_SECTION_VAL)
+	/* NO_SECTION_VAL means absolute offset is given. */
+	if (eFlash2xSectVal == NO_SECTION_VAL)
 		FlashSectValStartOffset = 0;
 	else
-		FlashSectValStartOffset = BcmGetSectionValStartOffset(Adapter,eFlash2xSectVal);
+		FlashSectValStartOffset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectVal);
 
-	if(FlashSectValStartOffset == STATUS_FAILURE )
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"This Section<%d> does not exixt in Flash Map 2.x",eFlash2xSectVal);
+	if (FlashSectValStartOffset == STATUS_FAILURE) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "This Section<%d> does not exixt in Flash Map 2.x", eFlash2xSectVal);
 		return -EINVAL;
 	}
 
-	if(IsSectionExistInVendorInfo(Adapter,eFlash2xSectVal))
+	if (IsSectionExistInVendorInfo(Adapter, eFlash2xSectVal))
 		return vendorextnWriteSection(Adapter, (PUCHAR)pBuffer, eFlash2xSectVal, uiOffset, uiNumBytes, bVerify);
 
-	//calculating  the absolute offset from FLASH;
+	/* calculating  the absolute offset from FLASH; */
 	uiOffset = uiOffset + FlashSectValStartOffset;
 
 	rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
 	value = 0;
-	wrmalt(Adapter, 0x0f000C80,&value, sizeof(value));
+	wrmalt(Adapter, 0x0f000C80, &value, sizeof(value));
 
-	Status = BeceemFlashBulkWrite(Adapter, pBuffer,uiOffset,uiNumBytes,bVerify);
+	Status = BeceemFlashBulkWrite(Adapter, pBuffer, uiOffset, uiNumBytes, bVerify);
 
 	wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
-	if(Status)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Flash Write failed with Status :%d", Status);
-		return Status ;
+	if (Status) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Write failed with Status :%d", Status);
+		return Status;
 	}
 
 	return Status;
-
 }
 
-/**
-*	BcmGetActiveDSD : Set the Active DSD in Adapter Structure which has to be dumped in DDR
-*	@Adapter :-Drivers private Data Structure
-*
-*	Return Value:-
-*		Return STATUS_SUCESS if get success in setting the right DSD else negaive error code
-*
-**/
-static INT BcmGetActiveDSD(PMINI_ADAPTER Adapter)
+/*
+ * BcmGetActiveDSD : Set the Active DSD in Adapter Structure which has to be dumped in DDR
+ * @Adapter :-Drivers private Data Structure
+ *
+ * Return Value:-
+ * Return STATUS_SUCESS if get success in setting the right DSD else negaive error code
+ *
+ */
+
+static int BcmGetActiveDSD(struct bcm_mini_adapter *Adapter)
 {
-	FLASH2X_SECTION_VAL uiHighestPriDSD = 0 ;
+	FLASH2X_SECTION_VAL uiHighestPriDSD = 0;
 
 	uiHighestPriDSD = getHighestPriDSD(Adapter);
 	Adapter->eActiveDSD = uiHighestPriDSD;
 
-	if(DSD0  == uiHighestPriDSD)
+	if (DSD0  == uiHighestPriDSD)
 		Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart;
-	if(DSD1 == uiHighestPriDSD)
+	if (DSD1 == uiHighestPriDSD)
 		Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start;
-	if(DSD2 == uiHighestPriDSD)
+	if (DSD2 == uiHighestPriDSD)
 		Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start;
-	if(Adapter->eActiveDSD)
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Active DSD :%d", Adapter->eActiveDSD);
-	if(Adapter->eActiveDSD == 0)
-	{
-		//if No DSD gets Active, Make Active the DSD with WR  permission
-		if(IsSectionWritable(Adapter,DSD2))
-		{
+	if (Adapter->eActiveDSD)
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Active DSD :%d", Adapter->eActiveDSD);
+	if (Adapter->eActiveDSD == 0) {
+		/* if No DSD gets Active, Make Active the DSD with WR  permission */
+		if (IsSectionWritable(Adapter, DSD2)) {
 			Adapter->eActiveDSD = DSD2;
 			Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start;
-		}
-		else if(IsSectionWritable(Adapter,DSD1))
-		{
+		} else if (IsSectionWritable(Adapter, DSD1)) {
 			Adapter->eActiveDSD = DSD1;
 			Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start;
-		}
-		else if(IsSectionWritable(Adapter,DSD0))
-		{
+		} else if (IsSectionWritable(Adapter, DSD0)) {
 			Adapter->eActiveDSD = DSD0;
 			Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart;
 		}
@@ -3360,1398 +3001,1230 @@ static INT BcmGetActiveDSD(PMINI_ADAPTER Adapter)
 	return STATUS_SUCCESS;
 }
 
-
-/**
-*	BcmGetActiveISO :- Set the Active ISO in Adapter Data Structue
-*	@Adapter : Driver private Data Structure
-*
-*	Return Value:-
-*		Sucsess:- STATUS_SUCESS
-*		Failure- : negative erro code
-*
-**/
-
-static INT BcmGetActiveISO(PMINI_ADAPTER Adapter)
+/*
+ * BcmGetActiveISO :- Set the Active ISO in Adapter Data Structue
+ * @Adapter : Driver private Data Structure
+ *
+ * Return Value:-
+ * Sucsess:- STATUS_SUCESS
+ * Failure- : negative erro code
+ *
+ */
+
+static int BcmGetActiveISO(struct bcm_mini_adapter *Adapter)
 {
+	int HighestPriISO = 0;
 
-	INT HighestPriISO = 0 ;
 	HighestPriISO = getHighestPriISO(Adapter);
 
-	Adapter->eActiveISO = HighestPriISO ;
-	if(Adapter->eActiveISO == ISO_IMAGE2)
+	Adapter->eActiveISO = HighestPriISO;
+	if (Adapter->eActiveISO == ISO_IMAGE2)
 		Adapter->uiActiveISOOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start);
-	else if(Adapter->eActiveISO == ISO_IMAGE1)
+	else if (Adapter->eActiveISO == ISO_IMAGE1)
 		Adapter->uiActiveISOOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start);
 
-	if(Adapter->eActiveISO)
-	 	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Active ISO :%x", Adapter->eActiveISO);
+	if (Adapter->eActiveISO)
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Active ISO :%x", Adapter->eActiveISO);
 
 	return STATUS_SUCCESS;
 }
 
-/**
-*	IsOffsetWritable :- it will tell the access permission of the sector having passed offset
-*	@Adapter : Drivers Private Data Structure
-*	@uiOffset : Offset provided in the Flash
-*
-*	Return Value:-
-*	Success:-TRUE ,  offset is writable
-*	Failure:-FALSE, offset is RO
-*
-**/
-B_UINT8 IsOffsetWritable(PMINI_ADAPTER Adapter, UINT uiOffset)
+/*
+ * IsOffsetWritable :- it will tell the access permission of the sector having passed offset
+ * @Adapter : Drivers Private Data Structure
+ * @uiOffset : Offset provided in the Flash
+ *
+ * Return Value:-
+ * Success:-TRUE ,  offset is writable
+ * Failure:-FALSE, offset is RO
+ *
+ */
+
+B_UINT8 IsOffsetWritable(struct bcm_mini_adapter *Adapter, unsigned int uiOffset)
 {
-	UINT uiSectorNum = 0;
-	UINT uiWordOfSectorPermission =0;
-	UINT uiBitofSectorePermission = 0;
+	unsigned int uiSectorNum = 0;
+	unsigned int uiWordOfSectorPermission = 0;
+	unsigned int uiBitofSectorePermission = 0;
 	B_UINT32 permissionBits = 0;
+
 	uiSectorNum = uiOffset/Adapter->uiSectorSize;
 
-	//calculating the word having this Sector Access permission from SectorAccessBitMap Array
-	uiWordOfSectorPermission = Adapter->psFlash2xCSInfo->SectorAccessBitMap[uiSectorNum /16];
+	/* calculating the word having this Sector Access permission from SectorAccessBitMap Array */
+	uiWordOfSectorPermission = Adapter->psFlash2xCSInfo->SectorAccessBitMap[uiSectorNum / 16];
 
-	//calculating the bit index inside the word for  this sector
-	uiBitofSectorePermission = 2*(15 - uiSectorNum %16);
+	/* calculating the bit index inside the word for  this sector */
+	uiBitofSectorePermission = 2 * (15 - uiSectorNum % 16);
 
-	//Setting Access permission
-	permissionBits = uiWordOfSectorPermission & (0x3 << uiBitofSectorePermission) ;
+	/* Setting Access permission */
+	permissionBits = uiWordOfSectorPermission & (0x3 << uiBitofSectorePermission);
 	permissionBits = (permissionBits >> uiBitofSectorePermission) & 0x3;
-	if(permissionBits == SECTOR_READWRITE_PERMISSION)
-		return 	TRUE;
+	if (permissionBits == SECTOR_READWRITE_PERMISSION)
+		return TRUE;
 	else
 		return FALSE;
 }
 
-static INT BcmDumpFlash2xSectionBitMap(PFLASH2X_BITMAP psFlash2xBitMap)
+static int BcmDumpFlash2xSectionBitMap(PFLASH2X_BITMAP psFlash2xBitMap)
 {
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "***************Flash 2.x Section Bitmap***************");
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"ISO_IMAGE1  :0X%x", psFlash2xBitMap->ISO_IMAGE1);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"ISO_IMAGE2  :0X%x", psFlash2xBitMap->ISO_IMAGE2);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"DSD0  :0X%x", psFlash2xBitMap->DSD0);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"DSD1  :0X%x", psFlash2xBitMap->DSD1);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"DSD2  :0X%x", psFlash2xBitMap->DSD2);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"VSA0  :0X%x", psFlash2xBitMap->VSA0);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"VSA1  :0X%x", psFlash2xBitMap->VSA1);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"VSA2  :0X%x", psFlash2xBitMap->VSA2);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"SCSI  :0X%x", psFlash2xBitMap->SCSI);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"CONTROL_SECTION  :0X%x", psFlash2xBitMap->CONTROL_SECTION);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
+
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "***************Flash 2.x Section Bitmap***************");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISO_IMAGE1  :0X%x", psFlash2xBitMap->ISO_IMAGE1);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISO_IMAGE2  :0X%x", psFlash2xBitMap->ISO_IMAGE2);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSD0  :0X%x", psFlash2xBitMap->DSD0);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSD1  :0X%x", psFlash2xBitMap->DSD1);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSD2  :0X%x", psFlash2xBitMap->DSD2);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "VSA0  :0X%x", psFlash2xBitMap->VSA0);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "VSA1  :0X%x", psFlash2xBitMap->VSA1);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "VSA2  :0X%x", psFlash2xBitMap->VSA2);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SCSI  :0X%x", psFlash2xBitMap->SCSI);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "CONTROL_SECTION  :0X%x", psFlash2xBitMap->CONTROL_SECTION);
 
 	return STATUS_SUCCESS;
 }
 
-/**
-*	BcmGetFlash2xSectionalBitMap :- It will provide the bit map of all the section present in Flash
-*	8bit has been assigned to every section.
-	bit[0] :Section present or not
-	bit[1] :section is valid or not
-	bit[2] : Secton is read only or has write permission too.
-	bit[3] : Active Section -
-	bit[7...4] = Reserved .
-
-	@Adapter:-Driver private Data Structure
-*
-*	Return value:-
-*	Success:- STATUS_SUCESS
-*	Failure:- negative error code
-**/
-
-INT BcmGetFlash2xSectionalBitMap(PMINI_ADAPTER Adapter, PFLASH2X_BITMAP psFlash2xBitMap)
+/*
+ * BcmGetFlash2xSectionalBitMap :- It will provide the bit map of all the section present in Flash
+ * 8bit has been assigned to every section.
+ * bit[0] :Section present or not
+ * bit[1] :section is valid or not
+ * bit[2] : Secton is read only or has write permission too.
+ * bit[3] : Active Section -
+ * bit[7...4] = Reserved .
+ *
+ * @Adapter:-Driver private Data Structure
+ *
+ * Return value:-
+ * Success:- STATUS_SUCESS
+ * Failure:- negative error code
+ */
+
+int BcmGetFlash2xSectionalBitMap(struct bcm_mini_adapter *Adapter, PFLASH2X_BITMAP psFlash2xBitMap)
 {
-
-
 	PFLASH2X_CS_INFO psFlash2xCSInfo = Adapter->psFlash2xCSInfo;
-	FLASH2X_SECTION_VAL uiHighestPriDSD = 0 ;
-	FLASH2X_SECTION_VAL uiHighestPriISO= 0 ;
-	BOOLEAN SetActiveDSDDone = FALSE ;
-	BOOLEAN SetActiveISODone = FALSE ;
-
-	//For 1.x map all the section except DSD0 will be shown as not present
-	//This part will be used by calibration tool to detect the number of DSD present in Flash.
-	if(IsFlash2x(Adapter) == FALSE)
-	{
+	FLASH2X_SECTION_VAL uiHighestPriDSD = 0;
+	FLASH2X_SECTION_VAL uiHighestPriISO = 0;
+	BOOLEAN SetActiveDSDDone = FALSE;
+	BOOLEAN SetActiveISODone = FALSE;
+
+	/* For 1.x map all the section except DSD0 will be shown as not present
+	 * This part will be used by calibration tool to detect the number of DSD present in Flash.
+	 */
+	if (IsFlash2x(Adapter) == FALSE) {
 		psFlash2xBitMap->ISO_IMAGE2 = 0;
 		psFlash2xBitMap->ISO_IMAGE1 = 0;
-		psFlash2xBitMap->DSD0 = FLASH2X_SECTION_VALID | FLASH2X_SECTION_ACT | FLASH2X_SECTION_PRESENT; //0xF;   //0000(Reseved)1(Active)0(RW)1(valid)1(present)
-		psFlash2xBitMap->DSD1  = 0 ;
-		psFlash2xBitMap->DSD2 = 0 ;
-		psFlash2xBitMap->VSA0 = 0 ;
-		psFlash2xBitMap->VSA1 = 0 ;
-		psFlash2xBitMap->VSA2 = 0 ;
-		psFlash2xBitMap->CONTROL_SECTION = 0 ;
-		psFlash2xBitMap->SCSI= 0 ;
-		psFlash2xBitMap->Reserved0 = 0 ;
-		psFlash2xBitMap->Reserved1 = 0 ;
-		psFlash2xBitMap->Reserved2 = 0 ;
-		return STATUS_SUCCESS ;
+		psFlash2xBitMap->DSD0 = FLASH2X_SECTION_VALID | FLASH2X_SECTION_ACT | FLASH2X_SECTION_PRESENT; /* 0xF; 0000(Reseved)1(Active)0(RW)1(valid)1(present) */
+		psFlash2xBitMap->DSD1  = 0;
+		psFlash2xBitMap->DSD2 = 0;
+		psFlash2xBitMap->VSA0 = 0;
+		psFlash2xBitMap->VSA1 = 0;
+		psFlash2xBitMap->VSA2 = 0;
+		psFlash2xBitMap->CONTROL_SECTION = 0;
+		psFlash2xBitMap->SCSI = 0;
+		psFlash2xBitMap->Reserved0 = 0;
+		psFlash2xBitMap->Reserved1 = 0;
+		psFlash2xBitMap->Reserved2 = 0;
 
+		return STATUS_SUCCESS;
 	}
 
 	uiHighestPriDSD = getHighestPriDSD(Adapter);
 	uiHighestPriISO = getHighestPriISO(Adapter);
 
-	///
-	//	IS0 IMAGE 2
-	///
-	if((psFlash2xCSInfo->OffsetISOImage2Part1Start) != UNINIT_PTR_IN_CS)
-	{
-		//Setting the 0th Bit representing the Section is present or not.
-		psFlash2xBitMap->ISO_IMAGE2= psFlash2xBitMap->ISO_IMAGE2 | FLASH2X_SECTION_PRESENT;
-
+	/*
+	 * IS0 IMAGE 2
+	 */
+	if ((psFlash2xCSInfo->OffsetISOImage2Part1Start) != UNINIT_PTR_IN_CS) {
+		/* Setting the 0th Bit representing the Section is present or not. */
+		psFlash2xBitMap->ISO_IMAGE2 = psFlash2xBitMap->ISO_IMAGE2 | FLASH2X_SECTION_PRESENT;
 
-		if(ReadISOSignature(Adapter,ISO_IMAGE2)== ISO_IMAGE_MAGIC_NUMBER)
+		if (ReadISOSignature(Adapter, ISO_IMAGE2) == ISO_IMAGE_MAGIC_NUMBER)
 			psFlash2xBitMap->ISO_IMAGE2 |= FLASH2X_SECTION_VALID;
 
-
-		//Calculation for extrating the Access permission
-		if(IsSectionWritable(Adapter, ISO_IMAGE2) == FALSE)
+		/* Calculation for extrating the Access permission */
+		if (IsSectionWritable(Adapter, ISO_IMAGE2) == FALSE)
 			psFlash2xBitMap->ISO_IMAGE2 |= FLASH2X_SECTION_RO;
 
-		if(SetActiveISODone == FALSE && uiHighestPriISO == ISO_IMAGE2)
-		{
-			psFlash2xBitMap->ISO_IMAGE2 |= FLASH2X_SECTION_ACT ;
+		if (SetActiveISODone == FALSE && uiHighestPriISO == ISO_IMAGE2) {
+			psFlash2xBitMap->ISO_IMAGE2 |= FLASH2X_SECTION_ACT;
 			SetActiveISODone = TRUE;
 		}
-
 	}
 
-	///
-	//	IS0 IMAGE 1
-	///
-	if((psFlash2xCSInfo->OffsetISOImage1Part1Start) != UNINIT_PTR_IN_CS)
-	{
-		//Setting the 0th Bit representing the Section is present or not.
+	/*
+	 * IS0 IMAGE 1
+	 */
+	if ((psFlash2xCSInfo->OffsetISOImage1Part1Start) != UNINIT_PTR_IN_CS) {
+		/* Setting the 0th Bit representing the Section is present or not. */
 		psFlash2xBitMap->ISO_IMAGE1 = psFlash2xBitMap->ISO_IMAGE1 | FLASH2X_SECTION_PRESENT;
 
-		if(ReadISOSignature(Adapter,ISO_IMAGE1) == ISO_IMAGE_MAGIC_NUMBER)
+		if (ReadISOSignature(Adapter, ISO_IMAGE1) == ISO_IMAGE_MAGIC_NUMBER)
 			psFlash2xBitMap->ISO_IMAGE1 |= FLASH2X_SECTION_VALID;
 
-		//	Calculation for extrating the Access permission
-		if(IsSectionWritable(Adapter, ISO_IMAGE1) == FALSE)
+		/* Calculation for extrating the Access permission */
+		if (IsSectionWritable(Adapter, ISO_IMAGE1) == FALSE)
 			psFlash2xBitMap->ISO_IMAGE1 |= FLASH2X_SECTION_RO;
 
-		if(SetActiveISODone == FALSE && uiHighestPriISO == ISO_IMAGE1)
-		{
-			psFlash2xBitMap->ISO_IMAGE1 |= FLASH2X_SECTION_ACT ;
+		if (SetActiveISODone == FALSE && uiHighestPriISO == ISO_IMAGE1) {
+			psFlash2xBitMap->ISO_IMAGE1 |= FLASH2X_SECTION_ACT;
 			SetActiveISODone = TRUE;
 		}
 	}
 
+	/*
+	 * DSD2
+	 */
+	if ((psFlash2xCSInfo->OffsetFromZeroForDSD2Start) != UNINIT_PTR_IN_CS) {
+		/* Setting the 0th Bit representing the Section is present or not. */
+		psFlash2xBitMap->DSD2 = psFlash2xBitMap->DSD2 | FLASH2X_SECTION_PRESENT;
 
-
-	///
-	// DSD2
-	///
-	if((psFlash2xCSInfo->OffsetFromZeroForDSD2Start) != UNINIT_PTR_IN_CS)
-	{
-		//Setting the 0th Bit representing the Section is present or not.
-		psFlash2xBitMap->DSD2= psFlash2xBitMap->DSD2 | FLASH2X_SECTION_PRESENT;
-
-		if(ReadDSDSignature(Adapter,DSD2)== DSD_IMAGE_MAGIC_NUMBER)
+		if (ReadDSDSignature(Adapter, DSD2) == DSD_IMAGE_MAGIC_NUMBER)
 			psFlash2xBitMap->DSD2 |= FLASH2X_SECTION_VALID;
 
-		//Calculation for extrating the Access permission
-		if(IsSectionWritable(Adapter, DSD2) == FALSE)
-		{
+		/* Calculation for extrating the Access permission */
+		if (IsSectionWritable(Adapter, DSD2) == FALSE) {
 			psFlash2xBitMap->DSD2 |= FLASH2X_SECTION_RO;
-
-		}
-		else
-		{
-			//Means section is writable
-			if((SetActiveDSDDone == FALSE) && (uiHighestPriDSD == DSD2))
-			{
-				psFlash2xBitMap->DSD2 |= FLASH2X_SECTION_ACT ;
-				SetActiveDSDDone =TRUE ;
+		} else {
+			/* Means section is writable */
+			if ((SetActiveDSDDone == FALSE) && (uiHighestPriDSD == DSD2)) {
+				psFlash2xBitMap->DSD2 |= FLASH2X_SECTION_ACT;
+				SetActiveDSDDone = TRUE;
 			}
 		}
 	}
 
-	///
-	//	DSD 1
-	///
-	if((psFlash2xCSInfo->OffsetFromZeroForDSD1Start) != UNINIT_PTR_IN_CS)
-	{
-		//Setting the 0th Bit representing the Section is present or not.
-		psFlash2xBitMap->DSD1= psFlash2xBitMap->DSD1 | FLASH2X_SECTION_PRESENT;
-
+	/*
+	 * DSD 1
+	 */
+	if ((psFlash2xCSInfo->OffsetFromZeroForDSD1Start) != UNINIT_PTR_IN_CS) {
+		/* Setting the 0th Bit representing the Section is present or not. */
+		psFlash2xBitMap->DSD1 = psFlash2xBitMap->DSD1 | FLASH2X_SECTION_PRESENT;
 
-		if(ReadDSDSignature(Adapter,DSD1)== DSD_IMAGE_MAGIC_NUMBER)
+		if (ReadDSDSignature(Adapter, DSD1) == DSD_IMAGE_MAGIC_NUMBER)
 			psFlash2xBitMap->DSD1 |= FLASH2X_SECTION_VALID;
 
-		//Calculation for extrating the Access permission
-		if(IsSectionWritable(Adapter, DSD1) == FALSE)
-		{
+		/* Calculation for extrating the Access permission */
+		if (IsSectionWritable(Adapter, DSD1) == FALSE) {
 			psFlash2xBitMap->DSD1 |= FLASH2X_SECTION_RO;
-		}
-		else
-		{
-			//Means section is writable
-			if((SetActiveDSDDone == FALSE) && (uiHighestPriDSD == DSD1))
-			{
-					psFlash2xBitMap->DSD1 |= FLASH2X_SECTION_ACT ;
-					SetActiveDSDDone =TRUE ;
+		} else {
+			/* Means section is writable */
+			if ((SetActiveDSDDone == FALSE) && (uiHighestPriDSD == DSD1)) {
+				psFlash2xBitMap->DSD1 |= FLASH2X_SECTION_ACT;
+				SetActiveDSDDone = TRUE;
 			}
 		}
-
 	}
 
-	///
-	//For DSD 0
-	//
-	if((psFlash2xCSInfo->OffsetFromZeroForDSDStart) != UNINIT_PTR_IN_CS)
-	{
-		//Setting the 0th Bit representing the Section is present or not.
+	/*
+	 * For DSD 0
+	 */
+	if ((psFlash2xCSInfo->OffsetFromZeroForDSDStart) != UNINIT_PTR_IN_CS) {
+		/* Setting the 0th Bit representing the Section is present or not. */
 		psFlash2xBitMap->DSD0 = psFlash2xBitMap->DSD0 | FLASH2X_SECTION_PRESENT;
 
-		if(ReadDSDSignature(Adapter,DSD0) == DSD_IMAGE_MAGIC_NUMBER)
+		if (ReadDSDSignature(Adapter, DSD0) == DSD_IMAGE_MAGIC_NUMBER)
 			psFlash2xBitMap->DSD0 |= FLASH2X_SECTION_VALID;
 
-		//Setting Access permission
-		if(IsSectionWritable(Adapter, DSD0) == FALSE)
-		{
+		/* Setting Access permission */
+		if (IsSectionWritable(Adapter, DSD0) == FALSE) {
 			psFlash2xBitMap->DSD0 |= FLASH2X_SECTION_RO;
-		}
-		else
-		{
-			//Means section is writable
-			if((SetActiveDSDDone == FALSE) &&(uiHighestPriDSD == DSD0))
-			{
-					psFlash2xBitMap->DSD0 |= FLASH2X_SECTION_ACT ;
-					SetActiveDSDDone =TRUE ;
+		} else {
+			/* Means section is writable */
+			if ((SetActiveDSDDone == FALSE) && (uiHighestPriDSD == DSD0)) {
+				psFlash2xBitMap->DSD0 |= FLASH2X_SECTION_ACT;
+				SetActiveDSDDone = TRUE;
 			}
 		}
 	}
 
-	///
-	// 	VSA 0
-	///
-	if((psFlash2xCSInfo->OffsetFromZeroForVSAStart) != UNINIT_PTR_IN_CS)
-	{
-		//Setting the 0th Bit representing the Section is present or not.
-		psFlash2xBitMap->VSA0= psFlash2xBitMap->VSA0 | FLASH2X_SECTION_PRESENT;
+	/*
+	 * VSA 0
+	 */
+	if ((psFlash2xCSInfo->OffsetFromZeroForVSAStart) != UNINIT_PTR_IN_CS) {
+		/* Setting the 0th Bit representing the Section is present or not. */
+		psFlash2xBitMap->VSA0 = psFlash2xBitMap->VSA0 | FLASH2X_SECTION_PRESENT;
 
-		//Setting the Access Bit. Map is not defined hece setting it always valid
+		/* Setting the Access Bit. Map is not defined hece setting it always valid */
 		psFlash2xBitMap->VSA0 |= FLASH2X_SECTION_VALID;
 
-		//Calculation for extrating the Access permission
-		if(IsSectionWritable(Adapter, VSA0) == FALSE)
+		/* Calculation for extrating the Access permission */
+		if (IsSectionWritable(Adapter, VSA0) == FALSE)
 			psFlash2xBitMap->VSA0 |=  FLASH2X_SECTION_RO;
 
-		//By Default section is Active
-		psFlash2xBitMap->VSA0 |= FLASH2X_SECTION_ACT ;
-
+		/* By Default section is Active */
+		psFlash2xBitMap->VSA0 |= FLASH2X_SECTION_ACT;
 	}
 
+	/*
+	 * VSA 1
+	 */
+	if ((psFlash2xCSInfo->OffsetFromZeroForVSA1Start) != UNINIT_PTR_IN_CS) {
+		/* Setting the 0th Bit representing the Section is present or not. */
+		psFlash2xBitMap->VSA1 = psFlash2xBitMap->VSA1 | FLASH2X_SECTION_PRESENT;
 
-	///
-	//	 VSA 1
-	///
-
-	if((psFlash2xCSInfo->OffsetFromZeroForVSA1Start) != UNINIT_PTR_IN_CS)
-	{
-		//Setting the 0th Bit representing the Section is present or not.
-		psFlash2xBitMap->VSA1= psFlash2xBitMap->VSA1 | FLASH2X_SECTION_PRESENT;
-
-		//Setting the Access Bit. Map is not defined hece setting it always valid
-		psFlash2xBitMap->VSA1|= FLASH2X_SECTION_VALID;
+		/* Setting the Access Bit. Map is not defined hece setting it always valid */
+		psFlash2xBitMap->VSA1 |= FLASH2X_SECTION_VALID;
 
-		//Checking For Access permission
-		if(IsSectionWritable(Adapter, VSA1) == FALSE)
+		/* Checking For Access permission */
+		if (IsSectionWritable(Adapter, VSA1) == FALSE)
 			psFlash2xBitMap->VSA1 |= FLASH2X_SECTION_RO;
 
-		//By Default section is Active
-		psFlash2xBitMap->VSA1 |= FLASH2X_SECTION_ACT ;
-
+		/* By Default section is Active */
+		psFlash2xBitMap->VSA1 |= FLASH2X_SECTION_ACT;
 	}
 
+	/*
+	 * VSA 2
+	 */
+	if ((psFlash2xCSInfo->OffsetFromZeroForVSA2Start) != UNINIT_PTR_IN_CS) {
+		/* Setting the 0th Bit representing the Section is present or not. */
+		psFlash2xBitMap->VSA2 = psFlash2xBitMap->VSA2 | FLASH2X_SECTION_PRESENT;
 
-	///
-	//	VSA 2
-	///
-
-	if((psFlash2xCSInfo->OffsetFromZeroForVSA2Start) != UNINIT_PTR_IN_CS)
-	{
-		//Setting the 0th Bit representing the Section is present or not.
-		psFlash2xBitMap->VSA2= psFlash2xBitMap->VSA2 | FLASH2X_SECTION_PRESENT;
-
-
-		//Setting the Access Bit. Map is not defined hece setting it always valid
+		/* Setting the Access Bit. Map is not defined hece setting it always valid */
 		psFlash2xBitMap->VSA2 |= FLASH2X_SECTION_VALID;
 
-		//Checking For Access permission
-		if(IsSectionWritable(Adapter, VSA2) == FALSE)
+		/* Checking For Access permission */
+		if (IsSectionWritable(Adapter, VSA2) == FALSE)
 			psFlash2xBitMap->VSA2 |= FLASH2X_SECTION_RO;
 
-		//By Default section is Active
-		psFlash2xBitMap->VSA2 |= FLASH2X_SECTION_ACT ;
+		/* By Default section is Active */
+		psFlash2xBitMap->VSA2 |= FLASH2X_SECTION_ACT;
 	}
 
-	///
-	// SCSI Section
-	///
-	if((psFlash2xCSInfo->OffsetFromZeroForScsiFirmware) != UNINIT_PTR_IN_CS)
-	{
-		//Setting the 0th Bit representing the Section is present or not.
-		psFlash2xBitMap->SCSI= psFlash2xBitMap->SCSI | FLASH2X_SECTION_PRESENT;
-
+	/*
+	 * SCSI Section
+	 */
+	if ((psFlash2xCSInfo->OffsetFromZeroForScsiFirmware) != UNINIT_PTR_IN_CS) {
+		/* Setting the 0th Bit representing the Section is present or not. */
+		psFlash2xBitMap->SCSI = psFlash2xBitMap->SCSI | FLASH2X_SECTION_PRESENT;
 
-		//Setting the Access Bit. Map is not defined hece setting it always valid
-		psFlash2xBitMap->SCSI|= FLASH2X_SECTION_VALID;
+		/* Setting the Access Bit. Map is not defined hece setting it always valid */
+		psFlash2xBitMap->SCSI |= FLASH2X_SECTION_VALID;
 
-		//Checking For Access permission
-		if(IsSectionWritable(Adapter, SCSI) == FALSE)
+		/* Checking For Access permission */
+		if (IsSectionWritable(Adapter, SCSI) == FALSE)
 			psFlash2xBitMap->SCSI |= FLASH2X_SECTION_RO;
 
-		//By Default section is Active
-		psFlash2xBitMap->SCSI |= FLASH2X_SECTION_ACT ;
-
+		/* By Default section is Active */
+		psFlash2xBitMap->SCSI |= FLASH2X_SECTION_ACT;
 	}
 
-
-	///
-	//	Control Section
-	///
-	if((psFlash2xCSInfo->OffsetFromZeroForControlSectionStart) != UNINIT_PTR_IN_CS)
-	{
-		//Setting the 0th Bit representing the Section is present or not.
+	/*
+	 * Control Section
+	 */
+	if ((psFlash2xCSInfo->OffsetFromZeroForControlSectionStart) != UNINIT_PTR_IN_CS) {
+		/* Setting the 0th Bit representing the Section is present or not. */
 		psFlash2xBitMap->CONTROL_SECTION = psFlash2xBitMap->CONTROL_SECTION | (FLASH2X_SECTION_PRESENT);
 
-
-		//Setting the Access Bit. Map is not defined hece setting it always valid
+		/* Setting the Access Bit. Map is not defined hece setting it always valid */
 		psFlash2xBitMap->CONTROL_SECTION |= FLASH2X_SECTION_VALID;
 
-		//Checking For Access permission
-		if(IsSectionWritable(Adapter, CONTROL_SECTION) == FALSE)
+		/* Checking For Access permission */
+		if (IsSectionWritable(Adapter, CONTROL_SECTION) == FALSE)
 			psFlash2xBitMap->CONTROL_SECTION |= FLASH2X_SECTION_RO;
 
-		//By Default section is Active
-		psFlash2xBitMap->CONTROL_SECTION |= FLASH2X_SECTION_ACT ;
-
+		/* By Default section is Active */
+		psFlash2xBitMap->CONTROL_SECTION |= FLASH2X_SECTION_ACT;
 	}
 
-	///
-	//	For Reserved Sections
-	///
+	/*
+	 * For Reserved Sections
+	 */
 	psFlash2xBitMap->Reserved0 = 0;
 	psFlash2xBitMap->Reserved0 = 0;
 	psFlash2xBitMap->Reserved0 = 0;
-
 	BcmDumpFlash2xSectionBitMap(psFlash2xBitMap);
 
-	return STATUS_SUCCESS ;
-
+	return STATUS_SUCCESS;
 }
-/**
-BcmSetActiveSection :- Set Active section is used to make priority field highest over other
-					section of same type.
-
-@Adapater :- Bcm Driver Private Data Structure
-@eFlash2xSectionVal :- Flash section val whose priority has to be made highest.
-
-Return Value:- Make the priorit highest else return erorr code
 
-**/
-INT BcmSetActiveSection(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectVal)
+/*
+ * BcmSetActiveSection :- Set Active section is used to make priority field highest over other
+ * section of same type.
+ *
+ * @Adapater :- Bcm Driver Private Data Structure
+ * @eFlash2xSectionVal :- Flash section val whose priority has to be made highest.
+ *
+ * Return Value:- Make the priorit highest else return erorr code
+ *
+ */
+
+int BcmSetActiveSection(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlash2xSectVal)
 {
 	unsigned int SectImagePriority = 0;
-	INT Status =STATUS_SUCCESS;
-
-	//DSD_HEADER sDSD = {0};
-	//ISO_HEADER sISO = {0};
-	INT HighestPriDSD = 0 ;
-	INT HighestPriISO = 0;
-
+	int Status = STATUS_SUCCESS;
 
+	/* DSD_HEADER sDSD = {0};
+	 * ISO_HEADER sISO = {0};
+	 */
+	int HighestPriDSD = 0 ;
+	int HighestPriISO = 0;
 
-	Status = IsSectionWritable(Adapter,eFlash2xSectVal) ;
-	if(Status != TRUE )
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Provided Section <%d> is not writable",eFlash2xSectVal);
+	Status = IsSectionWritable(Adapter, eFlash2xSectVal);
+	if (Status != TRUE) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Provided Section <%d> is not writable", eFlash2xSectVal);
 		return STATUS_FAILURE;
 	}
 
-	Adapter->bHeaderChangeAllowed = TRUE ;
-	switch(eFlash2xSectVal)
-	{
-		case ISO_IMAGE1 :
-		case ISO_IMAGE2	:
-			if(ReadISOSignature(Adapter,eFlash2xSectVal)== ISO_IMAGE_MAGIC_NUMBER )
-			{
-				HighestPriISO = getHighestPriISO(Adapter);
+	Adapter->bHeaderChangeAllowed = TRUE;
+	switch (eFlash2xSectVal) {
+	case ISO_IMAGE1:
+	case ISO_IMAGE2:
+		if (ReadISOSignature(Adapter, eFlash2xSectVal) == ISO_IMAGE_MAGIC_NUMBER) {
+			HighestPriISO = getHighestPriISO(Adapter);
+
+			if (HighestPriISO == eFlash2xSectVal) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Given ISO<%x> already has highest priority", eFlash2xSectVal);
+				Status = STATUS_SUCCESS;
+				break;
+			}
+
+			SectImagePriority = ReadISOPriority(Adapter, HighestPriISO) + 1;
 
-				if(HighestPriISO == eFlash2xSectVal	)
-				{
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Given ISO<%x> already  has highest priority",eFlash2xSectVal );
-					Status = STATUS_SUCCESS ;
+			if ((SectImagePriority <= 0) && IsSectionWritable(Adapter, HighestPriISO)) {
+				/* This is a SPECIAL Case which will only happen if the current highest priority ISO has priority value = 0x7FFFFFFF.
+				 * We will write 1 to the current Highest priority ISO And then shall increase the priority of the requested ISO
+				 * by user
+				 */
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SectImagePriority wraparound happened, eFlash2xSectVal: 0x%x\n", eFlash2xSectVal);
+				SectImagePriority = htonl(0x1);
+				Status = BcmFlash2xBulkWrite(Adapter,
+							&SectImagePriority,
+							HighestPriISO,
+							0 + FIELD_OFFSET_IN_HEADER(PISO_HEADER, ISOImagePriority),
+							SIGNATURE_SIZE,
+							TRUE);
+				if (Status) {
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly");
+					Status = STATUS_FAILURE;
 					break;
 				}
 
-				SectImagePriority = ReadISOPriority(Adapter, HighestPriISO) + 1;
-
-				if((SectImagePriority <= 0) && IsSectionWritable(Adapter,HighestPriISO))
-				{
-					// This is a SPECIAL Case which will only happen if the current highest priority ISO has priority value = 0x7FFFFFFF.
-					// We will write 1 to the current Highest priority ISO And then shall increase the priority of the requested ISO
-					// by user
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SectImagePriority wraparound happened, eFlash2xSectVal: 0x%x\n",eFlash2xSectVal);
-					SectImagePriority = htonl(0x1);
-					Status = BcmFlash2xBulkWrite(Adapter,
-								&SectImagePriority,
-								HighestPriISO,
-								0 + FIELD_OFFSET_IN_HEADER(PISO_HEADER, ISOImagePriority),
-								SIGNATURE_SIZE,
-								TRUE);
-
-					if(Status)
-					{
-						BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Priority has not been written properly");
-						Status = STATUS_FAILURE;
-						break ;
-					}
-
-					HighestPriISO = getHighestPriISO(Adapter);
-
-					if(HighestPriISO == eFlash2xSectVal	)
-					{
-						BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Given ISO<%x> already  has highest priority",eFlash2xSectVal );
-						Status = STATUS_SUCCESS ;
-						break;
-					}
+				HighestPriISO = getHighestPriISO(Adapter);
 
-					SectImagePriority = 2;
-				 }
+				if (HighestPriISO == eFlash2xSectVal) {
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Given ISO<%x> already has highest priority", eFlash2xSectVal);
+					Status = STATUS_SUCCESS;
+					break;
+				}
 
+				SectImagePriority = 2;
+			}
 
-				SectImagePriority = htonl(SectImagePriority);
+			SectImagePriority = htonl(SectImagePriority);
 
-				Status = BcmFlash2xBulkWrite(Adapter,
-								&SectImagePriority,
-								eFlash2xSectVal,
-								0 + FIELD_OFFSET_IN_HEADER(PISO_HEADER, ISOImagePriority),
-								SIGNATURE_SIZE,
-								TRUE);
-				if(Status)
-				{
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Priority has not been written properly");
-					break ;
-				}
-			}
-			else
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Signature is currupted. Hence can't increase the priority");
-				Status = STATUS_FAILURE ;
+			Status = BcmFlash2xBulkWrite(Adapter,
+						&SectImagePriority,
+						eFlash2xSectVal,
+						0 + FIELD_OFFSET_IN_HEADER(PISO_HEADER, ISOImagePriority),
+						SIGNATURE_SIZE,
+						TRUE);
+			if (Status) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly");
 				break;
 			}
+		} else {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Signature is currupted. Hence can't increase the priority");
+			Status = STATUS_FAILURE;
 			break;
-		case DSD0 :
-		case DSD1 :
-		case DSD2 :
-			if(ReadDSDSignature(Adapter,eFlash2xSectVal)== DSD_IMAGE_MAGIC_NUMBER)
-			{
-				HighestPriDSD = getHighestPriDSD(Adapter);
+		}
+		break;
+	case DSD0:
+	case DSD1:
+	case DSD2:
+		if (ReadDSDSignature(Adapter, eFlash2xSectVal) == DSD_IMAGE_MAGIC_NUMBER) {
+			HighestPriDSD = getHighestPriDSD(Adapter);
+			if ((HighestPriDSD == eFlash2xSectVal)) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Given DSD<%x> already has highest priority", eFlash2xSectVal);
+				Status = STATUS_SUCCESS;
+				break;
+			}
+
+			SectImagePriority = ReadDSDPriority(Adapter, HighestPriDSD) + 1;
+			if (SectImagePriority <= 0) {
+				/* This is a SPECIAL Case which will only happen if the current highest priority DSD has priority value = 0x7FFFFFFF.
+				 * We will write 1 to the current Highest priority DSD And then shall increase the priority of the requested DSD
+				 * by user
+				 */
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, NVM_RW, DBG_LVL_ALL, "SectImagePriority wraparound happened, eFlash2xSectVal: 0x%x\n", eFlash2xSectVal);
+				SectImagePriority = htonl(0x1);
 
-				if((HighestPriDSD == eFlash2xSectVal))
-				{
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Given DSD<%x> already  has highest priority", eFlash2xSectVal);
-					Status = STATUS_SUCCESS ;
+				Status = BcmFlash2xBulkWrite(Adapter,
+							&SectImagePriority,
+							HighestPriDSD,
+							Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImagePriority),
+							SIGNATURE_SIZE,
+							TRUE);
+				if (Status) {
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly");
 					break;
 				}
 
-				SectImagePriority = ReadDSDPriority(Adapter, HighestPriDSD) + 1 ;
-				if(SectImagePriority <= 0)
-				{
-					// This is a SPECIAL Case which will only happen if the current highest priority DSD has priority value = 0x7FFFFFFF.
-					// We will write 1 to the current Highest priority DSD And then shall increase the priority of the requested DSD
-					// by user
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, NVM_RW, DBG_LVL_ALL, "SectImagePriority wraparound happened, eFlash2xSectVal: 0x%x\n",eFlash2xSectVal);
-					SectImagePriority = htonl(0x1);
-
-					Status = BcmFlash2xBulkWrite(Adapter,
-									&SectImagePriority,
-									HighestPriDSD,
-									Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImagePriority),
-									SIGNATURE_SIZE,
-									TRUE);
-
-					if(Status)
-					{
-						BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly");
-						break ;
-					}
-
-					HighestPriDSD = getHighestPriDSD(Adapter);
-
-					if((HighestPriDSD == eFlash2xSectVal))
-					{
-						BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Made the DSD: %x highest by reducing priority of other\n", eFlash2xSectVal);
-						Status = STATUS_SUCCESS ;
-						break;
-					}
-
-					SectImagePriority = htonl(0x2);
-					Status = BcmFlash2xBulkWrite(Adapter,
-									&SectImagePriority,
-									HighestPriDSD,
-									Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImagePriority),
-									SIGNATURE_SIZE,
-									TRUE);
-
-					if(Status)
-					{
-						BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly");
-						break ;
-					}
-
-					HighestPriDSD = getHighestPriDSD(Adapter);
-
-					if((HighestPriDSD == eFlash2xSectVal))
-					{
-						Status = STATUS_SUCCESS ;
-						break;
-					}
-					SectImagePriority = 3 ;
+				HighestPriDSD = getHighestPriDSD(Adapter);
 
+				if ((HighestPriDSD == eFlash2xSectVal)) {
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Made the DSD: %x highest by reducing priority of other\n", eFlash2xSectVal);
+					Status = STATUS_SUCCESS;
+					break;
 				}
-				SectImagePriority = htonl(SectImagePriority);
+
+				SectImagePriority = htonl(0x2);
 				Status = BcmFlash2xBulkWrite(Adapter,
-								&SectImagePriority,
-								eFlash2xSectVal,
-								Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImagePriority),
-								SIGNATURE_SIZE ,
-								TRUE);
-				if(Status)
-				{
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Priority has not been written properly");
-					Status = STATUS_FAILURE ;
-					break ;
+							&SectImagePriority,
+							HighestPriDSD,
+							Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImagePriority),
+							SIGNATURE_SIZE,
+							TRUE);
+				if (Status) {
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly");
+					break;
 				}
+
+				HighestPriDSD = getHighestPriDSD(Adapter);
+				if ((HighestPriDSD == eFlash2xSectVal)) {
+					Status = STATUS_SUCCESS;
+					break;
+				}
+
+				SectImagePriority = 3;
 			}
-			else
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Signature is currupted. Hence can't increase the priority");
-				Status = STATUS_FAILURE ;
+			SectImagePriority = htonl(SectImagePriority);
+			Status = BcmFlash2xBulkWrite(Adapter,
+						&SectImagePriority,
+						eFlash2xSectVal,
+						Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImagePriority),
+						SIGNATURE_SIZE,
+						TRUE);
+			if (Status) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly");
+				Status = STATUS_FAILURE;
 				break;
 			}
+		} else {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Signature is currupted. Hence can't increase the priority");
+			Status = STATUS_FAILURE;
 			break;
-		case VSA0 :
-		case VSA1 :
-		case VSA2 :
-			//Has to be decided
-			break ;
-		default :
-				Status = STATUS_FAILURE ;
-				break;
-
+		}
+		break;
+	case VSA0:
+	case VSA1:
+	case VSA2:
+		/* Has to be decided */
+		break;
+	default:
+		Status = STATUS_FAILURE;
+		break;
 	}
 
-	Adapter->bHeaderChangeAllowed = FALSE ;
+	Adapter->bHeaderChangeAllowed = FALSE;
 	return Status;
-
 }
 
-/**
-BcmCopyISO - Used only for copying the ISO section
-@Adapater :- Bcm Driver Private Data Structure
-@sCopySectStrut :- Section copy structure
-
-Return value:- SUCCESS if copies successfully else negative error code
-
-**/
-INT BcmCopyISO(PMINI_ADAPTER Adapter, FLASH2X_COPY_SECTION sCopySectStrut)
+/*
+ * BcmCopyISO - Used only for copying the ISO section
+ * @Adapater :- Bcm Driver Private Data Structure
+ * @sCopySectStrut :- Section copy structure
+ *
+ * Return value:- SUCCESS if copies successfully else negative error code
+ *
+ */
+
+int BcmCopyISO(struct bcm_mini_adapter *Adapter, FLASH2X_COPY_SECTION sCopySectStrut)
 {
-
 	PCHAR Buff = NULL;
-	FLASH2X_SECTION_VAL eISOReadPart = 0,eISOWritePart = 0;
-	UINT uiReadOffsetWithinPart = 0, uiWriteOffsetWithinPart = 0;
-	UINT uiTotalDataToCopy = 0;
-	BOOLEAN IsThisHeaderSector = FALSE ;
-	UINT sigOffset = 0;
-	UINT ISOLength = 0;
-	UINT Status = STATUS_SUCCESS;
-	UINT SigBuff[MAX_RW_SIZE];
-	UINT i = 0;
-
-	if(ReadISOSignature(Adapter,sCopySectStrut.SrcSection) != ISO_IMAGE_MAGIC_NUMBER)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "error as Source ISO Section does not have valid signature");
+	FLASH2X_SECTION_VAL eISOReadPart = 0, eISOWritePart = 0;
+	unsigned int uiReadOffsetWithinPart = 0, uiWriteOffsetWithinPart = 0;
+	unsigned int uiTotalDataToCopy = 0;
+	BOOLEAN IsThisHeaderSector = FALSE;
+	unsigned int sigOffset = 0;
+	unsigned int ISOLength = 0;
+	unsigned int Status = STATUS_SUCCESS;
+	unsigned int SigBuff[MAX_RW_SIZE];
+	unsigned int i = 0;
+
+	if (ReadISOSignature(Adapter, sCopySectStrut.SrcSection) != ISO_IMAGE_MAGIC_NUMBER) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "error as Source ISO Section does not have valid signature");
 		return STATUS_FAILURE;
 	}
 
 	Status = BcmFlash2xBulkRead(Adapter,
-					   &ISOLength,
-					   sCopySectStrut.SrcSection,
-					   0 + FIELD_OFFSET_IN_HEADER(PISO_HEADER,ISOImageSize),
-					   4);
-
-	if(Status)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Read failed while copying ISO\n");
+				&ISOLength,
+				sCopySectStrut.SrcSection,
+				0 + FIELD_OFFSET_IN_HEADER(PISO_HEADER, ISOImageSize),
+				4);
+	if (Status) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read failed while copying ISO\n");
 		return Status;
 	}
 
 	ISOLength = htonl(ISOLength);
-
-	if(ISOLength % Adapter->uiSectorSize)
-	{
-		ISOLength = Adapter->uiSectorSize*(1 + ISOLength/Adapter->uiSectorSize);
-	}
+	if (ISOLength % Adapter->uiSectorSize)
+		ISOLength = Adapter->uiSectorSize * (1 + ISOLength/Adapter->uiSectorSize);
 
 	sigOffset = FIELD_OFFSET_IN_HEADER(PISO_HEADER, ISOImageMagicNumber);
 
 	Buff = kzalloc(Adapter->uiSectorSize, GFP_KERNEL);
 
-	if(Buff == NULL)
-	{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory allocation failed for section size");
-			return -ENOMEM;
+	if (!Buff) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed for section size");
+		return -ENOMEM;
 	}
 
-	if(sCopySectStrut.SrcSection ==ISO_IMAGE1 && sCopySectStrut.DstSection ==ISO_IMAGE2)
-	{
-		eISOReadPart = ISO_IMAGE1 ;
-		eISOWritePart = ISO_IMAGE2 ;
+	if (sCopySectStrut.SrcSection == ISO_IMAGE1 && sCopySectStrut.DstSection == ISO_IMAGE2) {
+		eISOReadPart = ISO_IMAGE1;
+		eISOWritePart = ISO_IMAGE2;
 		uiReadOffsetWithinPart =  0;
-		uiWriteOffsetWithinPart = 0 ;
-
-		uiTotalDataToCopy =(Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start)+
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start)+
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start);
-
-		if(uiTotalDataToCopy < ISOLength)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"error as Source ISO Section does not have valid signature");
+		uiWriteOffsetWithinPart = 0;
+
+		uiTotalDataToCopy = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start) +
+			(Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start) +
+			(Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start);
+
+		if (uiTotalDataToCopy < ISOLength) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "error as Source ISO Section does not have valid signature");
 			Status = STATUS_FAILURE;
 			goto out;
 		}
 
-		uiTotalDataToCopy =(Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start)+
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start)+
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start);
+		uiTotalDataToCopy = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start) +
+			(Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start) +
+			(Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start);
 
-		if(uiTotalDataToCopy < ISOLength)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"error as Dest ISO Section does not have enough section size");
+		if (uiTotalDataToCopy < ISOLength) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "error as Dest ISO Section does not have enough section size");
 			Status = STATUS_FAILURE;
 			goto out;
 		}
 
 		uiTotalDataToCopy = ISOLength;
 
-		CorruptISOSig(Adapter,ISO_IMAGE2);
-
-		while(uiTotalDataToCopy)
-		{
-			if(uiTotalDataToCopy == Adapter->uiSectorSize)
-			{
-				//Setting for write of first sector. First sector is assumed to be written in last
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Writing the signature sector");
-				eISOReadPart = ISO_IMAGE1 ;
+		CorruptISOSig(Adapter, ISO_IMAGE2);
+		while (uiTotalDataToCopy) {
+			if (uiTotalDataToCopy == Adapter->uiSectorSize) {
+				/* Setting for write of first sector. First sector is assumed to be written in last */
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Writing the signature sector");
+				eISOReadPart = ISO_IMAGE1;
 				uiReadOffsetWithinPart = 0;
 				eISOWritePart = ISO_IMAGE2;
-				uiWriteOffsetWithinPart = 0 ;
-				IsThisHeaderSector = TRUE ;
-
-			}
-			else
-			{
-				uiReadOffsetWithinPart = uiReadOffsetWithinPart + Adapter->uiSectorSize ;
-				uiWriteOffsetWithinPart = uiWriteOffsetWithinPart + Adapter->uiSectorSize ;
+				uiWriteOffsetWithinPart = 0;
+				IsThisHeaderSector = TRUE;
+			} else {
+				uiReadOffsetWithinPart = uiReadOffsetWithinPart + Adapter->uiSectorSize;
+				uiWriteOffsetWithinPart = uiWriteOffsetWithinPart + Adapter->uiSectorSize;
 
-				if((eISOReadPart == ISO_IMAGE1) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start) ))
-				{
-					eISOReadPart = ISO_IMAGE1_PART2 ;
+				if ((eISOReadPart == ISO_IMAGE1) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start))) {
+					eISOReadPart = ISO_IMAGE1_PART2;
 					uiReadOffsetWithinPart = 0;
 				}
-				if((eISOReadPart == ISO_IMAGE1_PART2) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start)))
-				{
-					eISOReadPart = ISO_IMAGE1_PART3 ;
+
+				if ((eISOReadPart == ISO_IMAGE1_PART2) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start))) {
+					eISOReadPart = ISO_IMAGE1_PART3;
 					uiReadOffsetWithinPart = 0;
 				}
-				if((eISOWritePart == ISO_IMAGE2) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start)))
-				{
-					eISOWritePart = ISO_IMAGE2_PART2 ;
+
+				if ((eISOWritePart == ISO_IMAGE2) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start))) {
+					eISOWritePart = ISO_IMAGE2_PART2;
 					uiWriteOffsetWithinPart = 0;
 				}
-				if((eISOWritePart == ISO_IMAGE2_PART2) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start)))
-				{
-					eISOWritePart = ISO_IMAGE2_PART3 ;
+
+				if ((eISOWritePart == ISO_IMAGE2_PART2) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start))) {
+					eISOWritePart = ISO_IMAGE2_PART3;
 					uiWriteOffsetWithinPart = 0;
 				}
 			}
 
 			Status = BcmFlash2xBulkRead(Adapter,
-								   (PUINT)Buff,
-								   eISOReadPart,
-								   uiReadOffsetWithinPart,
-								   Adapter->uiSectorSize
-								);
-
-			if(Status)
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Read failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOReadPart, uiReadOffsetWithinPart);
+						(PUINT)Buff,
+						eISOReadPart,
+						uiReadOffsetWithinPart,
+						Adapter->uiSectorSize);
+			if (Status) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOReadPart, uiReadOffsetWithinPart);
 				break;
 			}
 
-			if(IsThisHeaderSector == TRUE)
-			{
-				//If this is header sector write 0xFFFFFFFF at the sig time and in last write sig
+			if (IsThisHeaderSector == TRUE) {
+				/* If this is header sector write 0xFFFFFFFF at the sig time and in last write sig */
 				memcpy(SigBuff, Buff + sigOffset, MAX_RW_SIZE);
 
-				for(i = 0; i < MAX_RW_SIZE;i++)
+				for (i = 0; i < MAX_RW_SIZE; i++)
 					*(Buff + sigOffset + i) = 0xFF;
 			}
-			Adapter->bHeaderChangeAllowed = TRUE ;
-
+			Adapter->bHeaderChangeAllowed = TRUE;
 			Status = BcmFlash2xBulkWrite(Adapter,
-								 (PUINT)Buff,
-								 eISOWritePart,
-								 uiWriteOffsetWithinPart,
-								 Adapter->uiSectorSize,
-								 TRUE);
-			if(Status)
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Write failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOWritePart, uiWriteOffsetWithinPart);
+						(PUINT)Buff,
+						eISOWritePart,
+						uiWriteOffsetWithinPart,
+						Adapter->uiSectorSize,
+						TRUE);
+			if (Status) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOWritePart, uiWriteOffsetWithinPart);
 				break;
 			}
 
 			Adapter->bHeaderChangeAllowed = FALSE;
-
-			if(IsThisHeaderSector == TRUE)
-			{
+			if (IsThisHeaderSector == TRUE) {
 				WriteToFlashWithoutSectorErase(Adapter,
-												SigBuff,
-												eISOWritePart,
-												sigOffset,
-												MAX_RW_SIZE);
-				IsThisHeaderSector = FALSE ;
+							SigBuff,
+							eISOWritePart,
+							sigOffset,
+							MAX_RW_SIZE);
+				IsThisHeaderSector = FALSE;
 			}
-			//subtracting the written Data
-			uiTotalDataToCopy = uiTotalDataToCopy - Adapter->uiSectorSize ;
+			/* subtracting the written Data */
+			uiTotalDataToCopy = uiTotalDataToCopy - Adapter->uiSectorSize;
 		}
+	}
 
+	if (sCopySectStrut.SrcSection == ISO_IMAGE2 && sCopySectStrut.DstSection == ISO_IMAGE1) {
+		eISOReadPart = ISO_IMAGE2;
+		eISOWritePart = ISO_IMAGE1;
+		uiReadOffsetWithinPart = 0;
+		uiWriteOffsetWithinPart = 0;
 
-	}
+		uiTotalDataToCopy = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start) +
+			(Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start) +
+			(Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start);
 
-	if(sCopySectStrut.SrcSection ==ISO_IMAGE2 && sCopySectStrut.DstSection ==ISO_IMAGE1)
-	{
-		eISOReadPart = ISO_IMAGE2 ;
-		eISOWritePart = ISO_IMAGE1 ;
-		uiReadOffsetWithinPart =	0;
-		uiWriteOffsetWithinPart = 0 ;
-
-		uiTotalDataToCopy =(Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start)+
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start)+
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start);
-
-		if(uiTotalDataToCopy < ISOLength)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"error as Source ISO Section does not have valid signature");
+		if (uiTotalDataToCopy < ISOLength) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "error as Source ISO Section does not have valid signature");
 			Status = STATUS_FAILURE;
 			goto out;
 		}
 
-		uiTotalDataToCopy =(Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start)+
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start)+
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End) -
-						   (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start);
+		uiTotalDataToCopy = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start) +
+			(Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start) +
+			(Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End) -
+			(Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start);
 
-		if(uiTotalDataToCopy < ISOLength)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"error as Dest ISO Section does not have enough section size");
+		if (uiTotalDataToCopy < ISOLength) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "error as Dest ISO Section does not have enough section size");
 			Status = STATUS_FAILURE;
 			goto out;
 		}
 
 		uiTotalDataToCopy = ISOLength;
 
-		CorruptISOSig(Adapter,ISO_IMAGE1);
+		CorruptISOSig(Adapter, ISO_IMAGE1);
 
-		while(uiTotalDataToCopy)
-		{
-			if(uiTotalDataToCopy == Adapter->uiSectorSize)
-			{
-				//Setting for write of first sector. First sector is assumed to be written in last
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Writing the signature sector");
-				eISOReadPart = ISO_IMAGE2 ;
+		while (uiTotalDataToCopy) {
+			if (uiTotalDataToCopy == Adapter->uiSectorSize) {
+				/* Setting for write of first sector. First sector is assumed to be written in last */
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Writing the signature sector");
+				eISOReadPart = ISO_IMAGE2;
 				uiReadOffsetWithinPart = 0;
 				eISOWritePart = ISO_IMAGE1;
-				uiWriteOffsetWithinPart = 0 ;
+				uiWriteOffsetWithinPart = 0;
 				IsThisHeaderSector = TRUE;
+			} else {
+				uiReadOffsetWithinPart = uiReadOffsetWithinPart + Adapter->uiSectorSize;
+				uiWriteOffsetWithinPart = uiWriteOffsetWithinPart + Adapter->uiSectorSize;
 
-			}
-			else
-			{
-				uiReadOffsetWithinPart = uiReadOffsetWithinPart + Adapter->uiSectorSize ;
-				uiWriteOffsetWithinPart = uiWriteOffsetWithinPart + Adapter->uiSectorSize ;
-
-				if((eISOReadPart == ISO_IMAGE2) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start) ))
-				{
-					eISOReadPart = ISO_IMAGE2_PART2 ;
+				if ((eISOReadPart == ISO_IMAGE2) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start))) {
+					eISOReadPart = ISO_IMAGE2_PART2;
 					uiReadOffsetWithinPart = 0;
 				}
-				if((eISOReadPart == ISO_IMAGE2_PART2) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start)))
-				{
-					eISOReadPart = ISO_IMAGE2_PART3 ;
+
+				if ((eISOReadPart == ISO_IMAGE2_PART2) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start))) {
+					eISOReadPart = ISO_IMAGE2_PART3;
 					uiReadOffsetWithinPart = 0;
 				}
-				if((eISOWritePart == ISO_IMAGE1) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start)))
-				{
-					eISOWritePart = ISO_IMAGE1_PART2 ;
+
+				if ((eISOWritePart == ISO_IMAGE1) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start))) {
+					eISOWritePart = ISO_IMAGE1_PART2;
 					uiWriteOffsetWithinPart = 0;
 				}
-				if((eISOWritePart == ISO_IMAGE1_PART2) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start)))
-				{
-					eISOWritePart = ISO_IMAGE1_PART3 ;
+
+				if ((eISOWritePart == ISO_IMAGE1_PART2) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start))) {
+					eISOWritePart = ISO_IMAGE1_PART3;
 					uiWriteOffsetWithinPart = 0;
 				}
 			}
 
 			Status = BcmFlash2xBulkRead(Adapter,
-								   (PUINT)Buff,
-								   eISOReadPart,
-								   uiReadOffsetWithinPart,
-								   Adapter->uiSectorSize
-								);
-			if(Status)
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Read failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOReadPart, uiReadOffsetWithinPart);
+						(PUINT)Buff,
+						eISOReadPart,
+						uiReadOffsetWithinPart,
+						Adapter->uiSectorSize);
+			if (Status) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOReadPart, uiReadOffsetWithinPart);
 				break;
 			}
 
-			if(IsThisHeaderSector == TRUE)
-			{
-				//If this is header sector write 0xFFFFFFFF at the sig time and in last write sig
+			if (IsThisHeaderSector == TRUE) {
+				/* If this is header sector write 0xFFFFFFFF at the sig time and in last write sig */
 				memcpy(SigBuff, Buff + sigOffset, MAX_RW_SIZE);
 
-				for(i = 0; i < MAX_RW_SIZE;i++)
+				for (i = 0; i < MAX_RW_SIZE; i++)
 					*(Buff + sigOffset + i) = 0xFF;
-
 			}
-			Adapter->bHeaderChangeAllowed = TRUE ;
+			Adapter->bHeaderChangeAllowed = TRUE;
 			Status = BcmFlash2xBulkWrite(Adapter,
-								 (PUINT)Buff,
-								 eISOWritePart,
-								 uiWriteOffsetWithinPart,
-								 Adapter->uiSectorSize,
-								 TRUE);
-
-			if(Status)
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Write failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOWritePart, uiWriteOffsetWithinPart);
+						(PUINT)Buff,
+						eISOWritePart,
+						uiWriteOffsetWithinPart,
+						Adapter->uiSectorSize,
+						TRUE);
+			if (Status) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOWritePart, uiWriteOffsetWithinPart);
 				break;
 			}
 
-			Adapter->bHeaderChangeAllowed = FALSE ;
-
-			if(IsThisHeaderSector == TRUE)
-			{
+			Adapter->bHeaderChangeAllowed = FALSE;
+			if (IsThisHeaderSector == TRUE) {
 				WriteToFlashWithoutSectorErase(Adapter,
-												SigBuff,
-												eISOWritePart,
-												sigOffset,
-												MAX_RW_SIZE);
-				IsThisHeaderSector = FALSE ;
+							SigBuff,
+							eISOWritePart,
+							sigOffset,
+							MAX_RW_SIZE);
+
+				IsThisHeaderSector = FALSE;
 			}
 
-			//subtracting the written Data
-			uiTotalDataToCopy = uiTotalDataToCopy - Adapter->uiSectorSize ;
+			/* subtracting the written Data */
+			uiTotalDataToCopy = uiTotalDataToCopy - Adapter->uiSectorSize;
 		}
-
-
 	}
-
 out:
 	kfree(Buff);
 
 	return Status;
 }
-/**
-BcmFlash2xCorruptSig : this API is used to corrupt the written sig in Bcm Header present in flash section.
-					     It will corrupt the sig, if Section is writable, by making first bytes as zero.
-@Adapater :- Bcm Driver Private Data Structure
-@eFlash2xSectionVal :- Flash section val which has header
 
-Return Value :-
-	Success :- If Section is present and writable, corrupt the sig and return STATUS_SUCCESS
-	Failure :-Return negative error code
-
-
-**/
-INT BcmFlash2xCorruptSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
+/*
+ * BcmFlash2xCorruptSig : this API is used to corrupt the written sig in Bcm Header present in flash section.
+ * It will corrupt the sig, if Section is writable, by making first bytes as zero.
+ * @Adapater :- Bcm Driver Private Data Structure
+ * @eFlash2xSectionVal :- Flash section val which has header
+ *
+ * Return Value :-
+ *	Success :- If Section is present and writable, corrupt the sig and return STATUS_SUCCESS
+ *	Failure :-Return negative error code
+ */
+
+int BcmFlash2xCorruptSig(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
 {
+	int Status = STATUS_SUCCESS;
 
-	INT Status = STATUS_SUCCESS ;
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Section Value :%x \n", eFlash2xSectionVal);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section Value :%x\n", eFlash2xSectionVal);
 
-	if((eFlash2xSectionVal == DSD0) || (eFlash2xSectionVal == DSD1) || (eFlash2xSectionVal == DSD2))
-	{
+	if ((eFlash2xSectionVal == DSD0) || (eFlash2xSectionVal == DSD1) || (eFlash2xSectionVal == DSD2)) {
 		Status = CorruptDSDSig(Adapter, eFlash2xSectionVal);
-	}
-	else if(eFlash2xSectionVal == ISO_IMAGE1 || eFlash2xSectionVal == ISO_IMAGE2)
-	{
+	} else if (eFlash2xSectionVal == ISO_IMAGE1 || eFlash2xSectionVal == ISO_IMAGE2) {
 		Status = CorruptISOSig(Adapter, eFlash2xSectionVal);
-	}
-	else
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Given Section <%d>does not have Header",eFlash2xSectionVal);
+	} else {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Given Section <%d>does not have Header", eFlash2xSectionVal);
 		return STATUS_SUCCESS;
 	}
 	return Status;
 }
-/**
-BcmFlash2xWriteSig :-this API is used to Write the sig if requested Section has
-					  header and  Write Permission.
-@Adapater :- Bcm Driver Private Data Structure
-@eFlashSectionVal :- Flash section val which has header
-
-Return Value :-
-	Success :- If Section is present and writable write the sig and return STATUS_SUCCESS
-	Failure :-Return negative error code
-
-**/
-INT BcmFlash2xWriteSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlashSectionVal)
-{
 
-	UINT uiSignature = 0 ;
-	UINT uiOffset = 0;
-	//DSD_HEADER dsdHeader = {0};
+/*
+ *BcmFlash2xWriteSig :-this API is used to Write the sig if requested Section has
+ *					  header and  Write Permission.
+ * @Adapater :- Bcm Driver Private Data Structure
+ * @eFlashSectionVal :- Flash section val which has header
+ *
+ * Return Value :-
+ *	Success :- If Section is present and writable write the sig and return STATUS_SUCCESS
+ *	Failure :-Return negative error code
+ */
+
+int BcmFlash2xWriteSig(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlashSectionVal)
+{
+	unsigned int uiSignature = 0;
+	unsigned int uiOffset = 0;
 
-	if(Adapter->bSigCorrupted == FALSE)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Signature is not corrupted by driver, hence not restoring\n");
+	/* DSD_HEADER dsdHeader = {0}; */
+	if (Adapter->bSigCorrupted == FALSE) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Signature is not corrupted by driver, hence not restoring\n");
 		return STATUS_SUCCESS;
 	}
-	if(Adapter->bAllDSDWriteAllow == FALSE)
-	{
-		if(IsSectionWritable(Adapter,eFlashSectionVal) == FALSE)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section is not Writable...Hence can't Write signature");
+
+	if (Adapter->bAllDSDWriteAllow == FALSE) {
+		if (IsSectionWritable(Adapter, eFlashSectionVal) == FALSE) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section is not Writable...Hence can't Write signature");
 			return SECTOR_IS_NOT_WRITABLE;
 		}
 	}
-	if((eFlashSectionVal == DSD0) ||(eFlashSectionVal == DSD1) || (eFlashSectionVal == DSD2))
-	{
-		uiSignature = htonl(DSD_IMAGE_MAGIC_NUMBER) ;
-		uiOffset = Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader ;
 
-		uiOffset += FIELD_OFFSET_IN_HEADER(PDSD_HEADER,DSDImageMagicNumber);
+	if ((eFlashSectionVal == DSD0) || (eFlashSectionVal == DSD1) || (eFlashSectionVal == DSD2)) {
+		uiSignature = htonl(DSD_IMAGE_MAGIC_NUMBER);
+		uiOffset = Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader;
 
-		if((ReadDSDSignature(Adapter,eFlashSectionVal) & 0xFF000000) != CORRUPTED_PATTERN)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Corrupted Pattern is not there. Hence won't write sig");
+		uiOffset += FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImageMagicNumber);
+
+		if ((ReadDSDSignature(Adapter, eFlashSectionVal) & 0xFF000000) != CORRUPTED_PATTERN) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Corrupted Pattern is not there. Hence won't write sig");
 			return STATUS_FAILURE;
 		}
-
-	}
-	else if((eFlashSectionVal == ISO_IMAGE1) || (eFlashSectionVal == ISO_IMAGE2))
-	{
+	} else if ((eFlashSectionVal == ISO_IMAGE1) || (eFlashSectionVal == ISO_IMAGE2)) {
 		uiSignature = htonl(ISO_IMAGE_MAGIC_NUMBER);
-		//uiOffset = 0;
-		uiOffset = FIELD_OFFSET_IN_HEADER(PISO_HEADER,ISOImageMagicNumber);
-		if((ReadISOSignature(Adapter,eFlashSectionVal) & 0xFF000000) != CORRUPTED_PATTERN)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Currupted Pattern is not there. Hence won't write sig");
+		/* uiOffset = 0; */
+		uiOffset = FIELD_OFFSET_IN_HEADER(PISO_HEADER, ISOImageMagicNumber);
+		if ((ReadISOSignature(Adapter, eFlashSectionVal) & 0xFF000000) != CORRUPTED_PATTERN) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Currupted Pattern is not there. Hence won't write sig");
 			return STATUS_FAILURE;
 		}
-	}
-	else
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"GIVEN SECTION< %d > IS NOT VALID FOR SIG WRITE...", eFlashSectionVal);
+	} else {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "GIVEN SECTION< %d > IS NOT VALID FOR SIG WRITE...", eFlashSectionVal);
 		return STATUS_FAILURE;
 	}
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Restoring the signature");
-
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Restoring the signature");
 
 	Adapter->bHeaderChangeAllowed = TRUE;
 	Adapter->bSigCorrupted = FALSE;
-	BcmFlash2xBulkWrite(Adapter, &uiSignature,eFlashSectionVal,uiOffset,SIGNATURE_SIZE,TRUE);
+	BcmFlash2xBulkWrite(Adapter, &uiSignature, eFlashSectionVal, uiOffset, SIGNATURE_SIZE, TRUE);
 	Adapter->bHeaderChangeAllowed = FALSE;
 
-
-
 	return STATUS_SUCCESS;
 }
-/**
-validateFlash2xReadWrite :- This API is used to validate the user request for Read/Write.
-						      if requested Bytes goes beyond the Requested section, it reports error.
-@Adapater :- Bcm Driver Private Data Structure
-@psFlash2xReadWrite :-Flash2x Read/write structure pointer
 
-Return values:-Return TRUE is request is valid else FALSE.
-
-
-**/
-INT	validateFlash2xReadWrite(PMINI_ADAPTER Adapter, PFLASH2X_READWRITE psFlash2xReadWrite)
+/*
+ * validateFlash2xReadWrite :- This API is used to validate the user request for Read/Write.
+ *						      if requested Bytes goes beyond the Requested section, it reports error.
+ * @Adapater :- Bcm Driver Private Data Structure
+ * @psFlash2xReadWrite :-Flash2x Read/write structure pointer
+ *
+ * Return values:-Return TRUE is request is valid else FALSE.
+ */
+
+int validateFlash2xReadWrite(struct bcm_mini_adapter *Adapter, PFLASH2X_READWRITE psFlash2xReadWrite)
 {
-	UINT uiNumOfBytes = 0 ;
-	UINT uiSectStartOffset = 0 ;
-	UINT uiSectEndOffset = 0;
+	unsigned int uiNumOfBytes = 0;
+	unsigned int uiSectStartOffset = 0;
+	unsigned int uiSectEndOffset = 0;
+
 	uiNumOfBytes = psFlash2xReadWrite->numOfBytes;
 
-	if(IsSectionExistInFlash(Adapter,psFlash2xReadWrite->Section) != TRUE)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section<%x> does not exixt in Flash",psFlash2xReadWrite->Section);
+	if (IsSectionExistInFlash(Adapter, psFlash2xReadWrite->Section) != TRUE) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section<%x> does not exixt in Flash", psFlash2xReadWrite->Section);
 		return FALSE;
 	}
-	uiSectStartOffset = BcmGetSectionValStartOffset(Adapter,psFlash2xReadWrite->Section);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Start offset :%x ,section :%d\n",uiSectStartOffset,psFlash2xReadWrite->Section);
-	if((psFlash2xReadWrite->Section == ISO_IMAGE1) ||(psFlash2xReadWrite->Section == ISO_IMAGE2))
-	{
-		if(psFlash2xReadWrite->Section == ISO_IMAGE1)
-		{
-			uiSectEndOffset = BcmGetSectionValEndOffset(Adapter,ISO_IMAGE1) -
-							  BcmGetSectionValStartOffset(Adapter,ISO_IMAGE1)+
-							  BcmGetSectionValEndOffset(Adapter,ISO_IMAGE1_PART2) -
-							  BcmGetSectionValStartOffset(Adapter,ISO_IMAGE1_PART2)+
-							  BcmGetSectionValEndOffset(Adapter,ISO_IMAGE1_PART3) -
-							  BcmGetSectionValStartOffset(Adapter,ISO_IMAGE1_PART3);
+	uiSectStartOffset = BcmGetSectionValStartOffset(Adapter, psFlash2xReadWrite->Section);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Start offset :%x ,section :%d\n", uiSectStartOffset, psFlash2xReadWrite->Section);
+	if ((psFlash2xReadWrite->Section == ISO_IMAGE1) || (psFlash2xReadWrite->Section == ISO_IMAGE2)) {
+		if (psFlash2xReadWrite->Section == ISO_IMAGE1) {
+			uiSectEndOffset = BcmGetSectionValEndOffset(Adapter, ISO_IMAGE1) -
+				BcmGetSectionValStartOffset(Adapter, ISO_IMAGE1) +
+				BcmGetSectionValEndOffset(Adapter, ISO_IMAGE1_PART2) -
+				BcmGetSectionValStartOffset(Adapter, ISO_IMAGE1_PART2) +
+				BcmGetSectionValEndOffset(Adapter, ISO_IMAGE1_PART3) -
+				BcmGetSectionValStartOffset(Adapter, ISO_IMAGE1_PART3);
+		} else if (psFlash2xReadWrite->Section == ISO_IMAGE2) {
+			uiSectEndOffset = BcmGetSectionValEndOffset(Adapter, ISO_IMAGE2) -
+				BcmGetSectionValStartOffset(Adapter, ISO_IMAGE2) +
+				BcmGetSectionValEndOffset(Adapter, ISO_IMAGE2_PART2) -
+				BcmGetSectionValStartOffset(Adapter, ISO_IMAGE2_PART2) +
+				BcmGetSectionValEndOffset(Adapter, ISO_IMAGE2_PART3) -
+				BcmGetSectionValStartOffset(Adapter, ISO_IMAGE2_PART3);
 		}
-		else if(psFlash2xReadWrite->Section == ISO_IMAGE2)
-		{
-			uiSectEndOffset = BcmGetSectionValEndOffset(Adapter,ISO_IMAGE2) -
-							  BcmGetSectionValStartOffset(Adapter,ISO_IMAGE2)+
-							  BcmGetSectionValEndOffset(Adapter,ISO_IMAGE2_PART2) -
-							  BcmGetSectionValStartOffset(Adapter,ISO_IMAGE2_PART2)+
-							  BcmGetSectionValEndOffset(Adapter,ISO_IMAGE2_PART3) -
-							  BcmGetSectionValStartOffset(Adapter,ISO_IMAGE2_PART3);
 
-		}
+		/* since this uiSectEndoffset is the size of iso Image. hence for calculating the vitual endoffset
+		 * it should be added in startoffset. so that check done in last of this function can be valued.
+		 */
+		uiSectEndOffset = uiSectStartOffset + uiSectEndOffset;
 
-		//since this uiSectEndoffset is the size of iso Image. hence for calculating the vitual endoffset
-		//it should be added in startoffset. so that check done in last of this function can be valued.
-		uiSectEndOffset = uiSectStartOffset + uiSectEndOffset ;
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Total size of the ISO Image :%x", uiSectEndOffset);
+	} else
+		uiSectEndOffset = BcmGetSectionValEndOffset(Adapter, psFlash2xReadWrite->Section);
 
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Total size of the ISO Image :%x",uiSectEndOffset);
-	}
-	else
-		uiSectEndOffset   = BcmGetSectionValEndOffset(Adapter,psFlash2xReadWrite->Section);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "End offset :%x \n",uiSectEndOffset);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "End offset :%x\n", uiSectEndOffset);
 
-	//Checking the boundary condition
-	if((uiSectStartOffset + psFlash2xReadWrite->offset + uiNumOfBytes) <= uiSectEndOffset)
+	/* Checking the boundary condition */
+	if ((uiSectStartOffset + psFlash2xReadWrite->offset + uiNumOfBytes) <= uiSectEndOffset)
 		return TRUE;
-	else
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Invalid Request....");
+	else {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Invalid Request....");
 		return FALSE;
 	}
-
 }
 
-/**
-IsFlash2x :- check for Flash 2.x
-@Adapater :- Bcm Driver Private Data Structure
-
-Return value:-
-	return TRUE if flah2.x of hgher version else return false.
-**/
-
-INT IsFlash2x(PMINI_ADAPTER Adapter)
+/*
+ * IsFlash2x :- check for Flash 2.x
+ * Adapater :- Bcm Driver Private Data Structure
+ *
+ * Return value:-
+ *	return TRUE if flah2.x of hgher version else return false.
+ */
+
+int IsFlash2x(struct bcm_mini_adapter *Adapter)
 {
-	if(Adapter->uiFlashLayoutMajorVersion >= FLASH_2X_MAJOR_NUMBER)
-		return TRUE ;
+	if (Adapter->uiFlashLayoutMajorVersion >= FLASH_2X_MAJOR_NUMBER)
+		return TRUE;
 	else
 		return FALSE;
 }
-/**
-GetFlashBaseAddr :- Calculate the Flash Base address
-@Adapater :- Bcm Driver Private Data Structure
-
-Return Value:-
-	Success :- Base Address of the Flash
-**/
 
-static INT GetFlashBaseAddr(PMINI_ADAPTER Adapter)
+/*
+ * GetFlashBaseAddr :- Calculate the Flash Base address
+ * @Adapater :- Bcm Driver Private Data Structure
+ *
+ * Return Value:-
+ *	Success :- Base Address of the Flash
+ */
+
+static int GetFlashBaseAddr(struct bcm_mini_adapter *Adapter)
 {
+	unsigned int uiBaseAddr = 0;
 
-	UINT uiBaseAddr = 0;
-
-	if(Adapter->bDDRInitDone)
-	{
+	if (Adapter->bDDRInitDone) {
 		/*
-		For All Valid Flash Versions... except 1.1, take the value from FlashBaseAddr
-		In case of Raw Read... use the default value
-		*/
-		if(Adapter->uiFlashLayoutMajorVersion && (Adapter->bFlashRawRead == FALSE) &&
-			!((Adapter->uiFlashLayoutMajorVersion == 1) && (Adapter->uiFlashLayoutMinorVersion == 1))
-			)
-			uiBaseAddr = Adapter->uiFlashBaseAdd ;
+		 * For All Valid Flash Versions... except 1.1, take the value from FlashBaseAddr
+		 * In case of Raw Read... use the default value
+		 */
+		if (Adapter->uiFlashLayoutMajorVersion && (Adapter->bFlashRawRead == FALSE) &&
+			!((Adapter->uiFlashLayoutMajorVersion == 1) && (Adapter->uiFlashLayoutMinorVersion == 1)))
+			uiBaseAddr = Adapter->uiFlashBaseAdd;
 		else
 			uiBaseAddr = FLASH_CONTIGIOUS_START_ADDR_AFTER_INIT;
-	}
-	else
-	{
+	} else {
 		/*
-		For All Valid Flash Versions... except 1.1, take the value from FlashBaseAddr
-		In case of Raw Read... use the default value
-		*/
-		if(Adapter->uiFlashLayoutMajorVersion && (Adapter->bFlashRawRead == FALSE) &&
-			!((Adapter->uiFlashLayoutMajorVersion == 1) && (Adapter->uiFlashLayoutMinorVersion == 1))
-			)
+		 * For All Valid Flash Versions... except 1.1, take the value from FlashBaseAddr
+		 * In case of Raw Read... use the default value
+		 */
+		if (Adapter->uiFlashLayoutMajorVersion && (Adapter->bFlashRawRead == FALSE) &&
+			!((Adapter->uiFlashLayoutMajorVersion == 1) && (Adapter->uiFlashLayoutMinorVersion == 1)))
 			uiBaseAddr = Adapter->uiFlashBaseAdd | FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT;
 		else
 			uiBaseAddr = FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT;
 	}
 
-	return uiBaseAddr ;
+	return uiBaseAddr;
 }
-/**
-BcmCopySection :- This API is used to copy the One section in another. Both section should
-				    be contiuous and of same size. Hence this Will not be applicabe to copy ISO.
-
-@Adapater :- Bcm Driver Private Data Structure
-@SrcSection :- Source section From where data has to be copied
-@DstSection :- Destination section to which data has to be copied
-@offset :- Offset from/to  where data has to be copied from one section to another.
-@numOfBytes :- number of byes that has to be copyed from one section to another at given offset.
-			     in case of numofBytes  equal zero complete section will be copied.
-
-Return Values-
-	Success : Return STATUS_SUCCESS
-	Faillure :- return negative error code
-
-**/
-
-INT	BcmCopySection(PMINI_ADAPTER Adapter,
-						FLASH2X_SECTION_VAL SrcSection,
-						FLASH2X_SECTION_VAL DstSection,
-						UINT offset,
-						UINT numOfBytes)
+
+/*
+ * BcmCopySection :- This API is used to copy the One section in another. Both section should
+ *				    be contiuous and of same size. Hence this Will not be applicabe to copy ISO.
+ *
+ * @Adapater :- Bcm Driver Private Data Structure
+ * @SrcSection :- Source section From where data has to be copied
+ * @DstSection :- Destination section to which data has to be copied
+ * @offset :- Offset from/to  where data has to be copied from one section to another.
+ * @numOfBytes :- number of byes that has to be copyed from one section to another at given offset.
+ *			     in case of numofBytes  equal zero complete section will be copied.
+ * Return Values-
+ *	Success : Return STATUS_SUCCESS
+ *	Faillure :- return negative error code
+ */
+
+int BcmCopySection(struct bcm_mini_adapter *Adapter,
+		FLASH2X_SECTION_VAL SrcSection,
+		FLASH2X_SECTION_VAL DstSection,
+		unsigned int offset,
+		unsigned int numOfBytes)
 {
-	UINT BuffSize = 0 ;
-	UINT BytesToBeCopied = 0;
-	PUCHAR pBuff = NULL ;
-	INT Status = STATUS_SUCCESS ;
-	if(SrcSection == DstSection)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Source and Destination should be different ...try again");
+	unsigned int BuffSize = 0;
+	unsigned int BytesToBeCopied = 0;
+	PUCHAR pBuff = NULL;
+	int Status = STATUS_SUCCESS;
+
+	if (SrcSection == DstSection) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Source and Destination should be different ...try again");
 		return -EINVAL;
 	}
-	if((SrcSection != DSD0) && (SrcSection != DSD1) && (SrcSection != DSD2))
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Source should be DSD subsection");
-		return  -EINVAL;
-	}
-	if((DstSection != DSD0) && (DstSection != DSD1) && (DstSection != DSD2))
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Destination should be DSD subsection");
-		return  -EINVAL;
+
+	if ((SrcSection != DSD0) && (SrcSection != DSD1) && (SrcSection != DSD2)) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Source should be DSD subsection");
+		return -EINVAL;
 	}
 
-	//if offset zero means have to copy complete secton
+	if ((DstSection != DSD0) && (DstSection != DSD1) && (DstSection != DSD2)) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Destination should be DSD subsection");
+		return -EINVAL;
+	}
 
-	if(numOfBytes == 0)
-	{
-		numOfBytes = BcmGetSectionValEndOffset(Adapter,SrcSection)
-				  - BcmGetSectionValStartOffset(Adapter,SrcSection);
+	/* if offset zero means have to copy complete secton */
+	if (numOfBytes == 0) {
+		numOfBytes = BcmGetSectionValEndOffset(Adapter, SrcSection)
+			- BcmGetSectionValStartOffset(Adapter, SrcSection);
 
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL," Section Size :0x%x",numOfBytes);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Section Size :0x%x", numOfBytes);
 	}
 
-	if((offset + numOfBytes) > BcmGetSectionValEndOffset(Adapter,SrcSection)
-				  - BcmGetSectionValStartOffset(Adapter,SrcSection))
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0," Input parameters going beyond the section offS: %x numB: %x of Source Section\n",
-						offset, numOfBytes);
+	if ((offset + numOfBytes) > BcmGetSectionValEndOffset(Adapter, SrcSection)
+		- BcmGetSectionValStartOffset(Adapter, SrcSection)) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, " Input parameters going beyond the section offS: %x numB: %x of Source Section\n",
+				offset, numOfBytes);
 		return -EINVAL;
 	}
 
-	if((offset + numOfBytes) > BcmGetSectionValEndOffset(Adapter,DstSection)
-				  - BcmGetSectionValStartOffset(Adapter,DstSection))
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0," Input parameters going beyond the section offS: %x numB: %x of Destination Section\n",
-						offset, numOfBytes);
+	if ((offset + numOfBytes) > BcmGetSectionValEndOffset(Adapter, DstSection)
+		- BcmGetSectionValStartOffset(Adapter, DstSection)) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Input parameters going beyond the section offS: %x numB: %x of Destination Section\n",
+				offset, numOfBytes);
 		return -EINVAL;
 	}
 
-
-	if(numOfBytes > Adapter->uiSectorSize )
+	if (numOfBytes > Adapter->uiSectorSize)
 		BuffSize = Adapter->uiSectorSize;
 	else
-		BuffSize = numOfBytes ;
+		BuffSize = numOfBytes;
 
 	pBuff = (PCHAR)kzalloc(BuffSize, GFP_KERNEL);
-	if(pBuff == NULL)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory allocation failed.. ");
+	if (!pBuff) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed.. ");
 		return -ENOMEM;
 	}
 
-
-	BytesToBeCopied = Adapter->uiSectorSize ;
-	if(offset % Adapter->uiSectorSize)
+	BytesToBeCopied = Adapter->uiSectorSize;
+	if (offset % Adapter->uiSectorSize)
 		BytesToBeCopied = Adapter->uiSectorSize - (offset % Adapter->uiSectorSize);
-	if(BytesToBeCopied > numOfBytes)
-		BytesToBeCopied = numOfBytes ;
-
-
+	if (BytesToBeCopied > numOfBytes)
+		BytesToBeCopied = numOfBytes;
 
 	Adapter->bHeaderChangeAllowed = TRUE;
 
-	do
-	{
-		Status = BcmFlash2xBulkRead(Adapter, (PUINT)pBuff, SrcSection , offset,BytesToBeCopied);
-		if(Status)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Read failed at offset :%d for NOB :%d", SrcSection,BytesToBeCopied);
+	do {
+		Status = BcmFlash2xBulkRead(Adapter, (PUINT)pBuff, SrcSection , offset, BytesToBeCopied);
+		if (Status) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read failed at offset :%d for NOB :%d", SrcSection, BytesToBeCopied);
 			break;
 		}
-		Status = BcmFlash2xBulkWrite(Adapter,(PUINT)pBuff,DstSection,offset,BytesToBeCopied,FALSE);
-		if(Status)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Write failed at offset :%d for NOB :%d", DstSection,BytesToBeCopied);
+		Status = BcmFlash2xBulkWrite(Adapter, (PUINT)pBuff, DstSection, offset, BytesToBeCopied, FALSE);
+		if (Status) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write failed at offset :%d for NOB :%d", DstSection, BytesToBeCopied);
 			break;
 		}
 		offset = offset + BytesToBeCopied;
-		numOfBytes = numOfBytes - BytesToBeCopied ;
-		if(numOfBytes)
-		{
-			if(numOfBytes > Adapter->uiSectorSize )
+		numOfBytes = numOfBytes - BytesToBeCopied;
+		if (numOfBytes) {
+			if (numOfBytes > Adapter->uiSectorSize)
 				BytesToBeCopied = Adapter->uiSectorSize;
 			else
 				BytesToBeCopied = numOfBytes;
 		}
-	}while(numOfBytes > 0) ;
+	} while (numOfBytes > 0);
+
 	kfree(pBuff);
-	Adapter->bHeaderChangeAllowed = FALSE ;
+	Adapter->bHeaderChangeAllowed = FALSE;
+
 	return Status;
 }
 
-/**
-SaveHeaderIfPresent :- This API is use to Protect the Header in case of Header Sector write
-@Adapater :- Bcm Driver Private Data Structure
-@pBuff :- Data buffer that has to be written in sector having the header map.
-@uiOffset :- Flash offset that has to be written.
-
-Return value :-
-	Success :- On success return STATUS_SUCCESS
-	Faillure :- Return negative error code
-
-**/
-
-INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset)
+/*
+ * SaveHeaderIfPresent :- This API is use to Protect the Header in case of Header Sector write
+ * @Adapater :- Bcm Driver Private Data Structure
+ * @pBuff :- Data buffer that has to be written in sector having the header map.
+ * @uiOffset :- Flash offset that has to be written.
+ *
+ * Return value :-
+ *	Success :- On success return STATUS_SUCCESS
+ *	Faillure :- Return negative error code
+ */
+
+int SaveHeaderIfPresent(struct bcm_mini_adapter *Adapter, PUCHAR pBuff, unsigned int uiOffset)
 {
-	UINT offsetToProtect = 0,HeaderSizeToProtect =0;
-	BOOLEAN bHasHeader = FALSE ;
-	PUCHAR pTempBuff =NULL;
-	UINT uiSectAlignAddr = 0;
-	UINT sig = 0;
+	unsigned int offsetToProtect = 0, HeaderSizeToProtect = 0;
+	BOOLEAN bHasHeader = FALSE;
+	PUCHAR pTempBuff = NULL;
+	unsigned int uiSectAlignAddr = 0;
+	unsigned int sig = 0;
 
-	//making the offset sector aligned
+	/* making the offset sector aligned */
 	uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize - 1);
 
-
-	if((uiSectAlignAddr == BcmGetSectionValEndOffset(Adapter,DSD2)- Adapter->uiSectorSize)||
-	(uiSectAlignAddr == BcmGetSectionValEndOffset(Adapter,DSD1)- Adapter->uiSectorSize)||
-	(uiSectAlignAddr == BcmGetSectionValEndOffset(Adapter,DSD0)- Adapter->uiSectorSize))
-	{
-
-		//offset from the sector boundary having the header map
+	if ((uiSectAlignAddr == BcmGetSectionValEndOffset(Adapter, DSD2) - Adapter->uiSectorSize) ||
+		(uiSectAlignAddr == BcmGetSectionValEndOffset(Adapter, DSD1) - Adapter->uiSectorSize) ||
+		(uiSectAlignAddr == BcmGetSectionValEndOffset(Adapter, DSD0) - Adapter->uiSectorSize)) {
+		/* offset from the sector boundary having the header map */
 		offsetToProtect = Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader % Adapter->uiSectorSize;
 		HeaderSizeToProtect = sizeof(DSD_HEADER);
-		bHasHeader = TRUE ;
+		bHasHeader = TRUE;
 	}
 
-	if(uiSectAlignAddr == BcmGetSectionValStartOffset(Adapter,ISO_IMAGE1) ||
-		uiSectAlignAddr == BcmGetSectionValStartOffset(Adapter,ISO_IMAGE2))
-	{
+	if (uiSectAlignAddr == BcmGetSectionValStartOffset(Adapter, ISO_IMAGE1) ||
+		uiSectAlignAddr == BcmGetSectionValStartOffset(Adapter, ISO_IMAGE2)) {
 		offsetToProtect = 0;
 		HeaderSizeToProtect = sizeof(ISO_HEADER);
 		bHasHeader = TRUE;
 	}
-	//If Header is present overwrite passed buffer with this
-	if(bHasHeader && (Adapter->bHeaderChangeAllowed == FALSE))
-	{
+	/* If Header is present overwrite passed buffer with this */
+	if (bHasHeader && (Adapter->bHeaderChangeAllowed == FALSE)) {
 		pTempBuff = (PUCHAR)kzalloc(HeaderSizeToProtect, GFP_KERNEL);
-		if(pTempBuff == NULL)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory allocation failed ");
+		if (!pTempBuff) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed");
 			return -ENOMEM;
 		}
-		//Read header
-		BeceemFlashBulkRead(Adapter,(PUINT)pTempBuff,(uiSectAlignAddr + offsetToProtect),HeaderSizeToProtect);
-		BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,pTempBuff ,HeaderSizeToProtect);
-		//Replace Buffer content with Header
-		memcpy(pBuff +offsetToProtect,pTempBuff,HeaderSizeToProtect);
+		/* Read header */
+		BeceemFlashBulkRead(Adapter, (PUINT)pTempBuff, (uiSectAlignAddr + offsetToProtect), HeaderSizeToProtect);
+		BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, pTempBuff, HeaderSizeToProtect);
+		/* Replace Buffer content with Header */
+		memcpy(pBuff + offsetToProtect, pTempBuff, HeaderSizeToProtect);
 
 		kfree(pTempBuff);
 	}
-	if(bHasHeader && Adapter->bSigCorrupted)
-	{
-		sig = *((PUINT)(pBuff + offsetToProtect + FIELD_OFFSET_IN_HEADER(PDSD_HEADER,DSDImageMagicNumber)));
+	if (bHasHeader && Adapter->bSigCorrupted) {
+		sig = *((PUINT)(pBuff + offsetToProtect + FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImageMagicNumber)));
 		sig = ntohl(sig);
-		if((sig & 0xFF000000) != CORRUPTED_PATTERN)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Desired pattern is not at sig offset. Hence won't restore");
+		if ((sig & 0xFF000000) != CORRUPTED_PATTERN) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Desired pattern is not at sig offset. Hence won't restore");
 			Adapter->bSigCorrupted = FALSE;
 			return STATUS_SUCCESS;
 		}
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL," Corrupted sig is :%X", sig);
-		*((PUINT)(pBuff + offsetToProtect + FIELD_OFFSET_IN_HEADER(PDSD_HEADER,DSDImageMagicNumber)))= htonl(DSD_IMAGE_MAGIC_NUMBER);
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Restoring the signature in Header Write only");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, " Corrupted sig is :%X", sig);
+		*((PUINT)(pBuff + offsetToProtect + FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImageMagicNumber))) = htonl(DSD_IMAGE_MAGIC_NUMBER);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Restoring the signature in Header Write only");
 		Adapter->bSigCorrupted = FALSE;
 	}
 
-	return STATUS_SUCCESS ;
+	return STATUS_SUCCESS;
 }
 
-/**
-BcmDoChipSelect : This will selcet the appropriate chip for writing.
-@Adapater :- Bcm Driver Private Data Structure
-
-OutPut:-
-	Select the Appropriate chip and retrn status Success
-**/
-static INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset)
+/*
+ * BcmDoChipSelect : This will selcet the appropriate chip for writing.
+ * @Adapater :- Bcm Driver Private Data Structure
+ *
+ * OutPut:-
+ *	Select the Appropriate chip and retrn status Success
+ */
+static int BcmDoChipSelect(struct bcm_mini_adapter *Adapter, unsigned int offset)
 {
-	UINT FlashConfig = 0;
-	INT ChipNum = 0;
-	UINT GPIOConfig = 0;
-	UINT PartNum = 0;
+	unsigned int FlashConfig = 0;
+	int ChipNum = 0;
+	unsigned int GPIOConfig = 0;
+	unsigned int PartNum = 0;
 
-	ChipNum = offset / FLASH_PART_SIZE ;
+	ChipNum = offset / FLASH_PART_SIZE;
 
-	//
-	// Chip Select mapping to enable flash0.
-	// To select flash 0, we have to OR with (0<<12).
-	// ORing 0 will have no impact so not doing that part.
-	// In future if Chip select value changes from 0 to non zero,
-	// That needs be taken care with backward comaptibility. No worries for now.
-	//
+	/*
+	 * Chip Select mapping to enable flash0.
+	 * To select flash 0, we have to OR with (0<<12).
+	 * ORing 0 will have no impact so not doing that part.
+	 * In future if Chip select value changes from 0 to non zero,
+	 * That needs be taken care with backward comaptibility. No worries for now.
+	 */
 
 	/*
-	SelectedChip Variable is the selection that the host is 100% Sure the same as what the register will hold. This can be ONLY ensured
-	if the Chip doesn't goes to low power mode while the flash operation is in progress (NVMRdmWrmLock is taken)
-	Before every new Flash Write operation, we reset the variable. This is to ensure that after any wake-up from
-	power down modes (Idle mode/shutdown mode), the values in the register will be different.
-	*/
+	 * SelectedChip Variable is the selection that the host is 100% Sure the same as what the register will hold. This can be ONLY ensured
+	 * if the Chip doesn't goes to low power mode while the flash operation is in progress (NVMRdmWrmLock is taken)
+	 * Before every new Flash Write operation, we reset the variable. This is to ensure that after any wake-up from
+	 * power down modes (Idle mode/shutdown mode), the values in the register will be different.
+	 */
 
-	if(Adapter->SelectedChip == ChipNum)
-    		return STATUS_SUCCESS;
+	if (Adapter->SelectedChip == ChipNum)
+		return STATUS_SUCCESS;
 
-	//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Selected Chip :%x", ChipNum);
-	Adapter->SelectedChip = ChipNum ;
+	/* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Selected Chip :%x", ChipNum); */
+	Adapter->SelectedChip = ChipNum;
 
-	//bit[13..12]  will select the appropriate chip
+	/* bit[13..12]  will select the appropriate chip */
 	rdmalt(Adapter, FLASH_CONFIG_REG, &FlashConfig, 4);
 	rdmalt(Adapter, FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4);
-
 	{
-		switch(ChipNum)
-		{
+		switch (ChipNum) {
 		case 0:
 			PartNum = 0;
 			break;
@@ -4770,453 +4243,422 @@ static INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset)
 		}
 	}
 	/* In case the bits already written in the FLASH_CONFIG_REG is same as what the user desired,
-	    nothing to do... can return immediately.
-	    ASSUMPTION: FLASH_GPIO_CONFIG_REG will be in sync with FLASH_CONFIG_REG.
-	    Even if the chip goes to low power mode, it should wake with values in each register in sync with each other.
-	    These values are not written by host other than during CHIP_SELECT.
-	*/
-	if(PartNum == ((FlashConfig >> CHIP_SELECT_BIT12) & 0x3))
+	 * nothing to do... can return immediately.
+	 * ASSUMPTION: FLASH_GPIO_CONFIG_REG will be in sync with FLASH_CONFIG_REG.
+	 * Even if the chip goes to low power mode, it should wake with values in each register in sync with each other.
+	 * These values are not written by host other than during CHIP_SELECT.
+	 */
+	if (PartNum == ((FlashConfig >> CHIP_SELECT_BIT12) & 0x3))
 		return STATUS_SUCCESS;
 
-	//clearing the bit[13..12]
+	/* clearing the bit[13..12] */
 	FlashConfig &= 0xFFFFCFFF;
-	FlashConfig = (FlashConfig | (PartNum<<CHIP_SELECT_BIT12)); //00
+	FlashConfig = (FlashConfig | (PartNum<<CHIP_SELECT_BIT12)); /* 00 */
 
-	wrmalt(Adapter,FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4);
+	wrmalt(Adapter, FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4);
 	udelay(100);
 
-	wrmalt(Adapter,FLASH_CONFIG_REG, &FlashConfig, 4);
+	wrmalt(Adapter, FLASH_CONFIG_REG, &FlashConfig, 4);
 	udelay(100);
 
 	return STATUS_SUCCESS;
-
 }
-INT ReadDSDSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd)
-{
-		UINT uiDSDsig = 0;
-		//UINT sigoffsetInMap = 0;
-		//DSD_HEADER dsdHeader = {0};
 
+int ReadDSDSignature(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL dsd)
+{
+	unsigned int uiDSDsig = 0;
+	/* unsigned int sigoffsetInMap = 0;
+	 * DSD_HEADER dsdHeader = {0};
+	 */
 
-		//sigoffsetInMap =(PUCHAR)&(dsdHeader.DSDImageMagicNumber) -(PUCHAR)&dsdHeader;
+	/* sigoffsetInMap =(PUCHAR)&(dsdHeader.DSDImageMagicNumber) -(PUCHAR)&dsdHeader; */
 
-		if(dsd != DSD0 && dsd != DSD1 && dsd != DSD2)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"passed section value is not for DSDs");
-			return STATUS_FAILURE;
-		}
-		BcmFlash2xBulkRead(Adapter,
-						   &uiDSDsig,
-						   dsd,
-						   Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(PDSD_HEADER,DSDImageMagicNumber),
-						   SIGNATURE_SIZE);
+	if (dsd != DSD0 && dsd != DSD1 && dsd != DSD2) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "passed section value is not for DSDs");
+		return STATUS_FAILURE;
+	}
+	BcmFlash2xBulkRead(Adapter,
+			&uiDSDsig,
+			dsd,
+			Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImageMagicNumber),
+			SIGNATURE_SIZE);
 
-		uiDSDsig = ntohl(uiDSDsig);
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"DSD SIG :%x", uiDSDsig);
+	uiDSDsig = ntohl(uiDSDsig);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSD SIG :%x", uiDSDsig);
 
-		return uiDSDsig ;
+	return uiDSDsig;
 }
-INT ReadDSDPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd)
+
+int ReadDSDPriority(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL dsd)
 {
-	//UINT priOffsetInMap = 0 ;
+	/* unsigned int priOffsetInMap = 0 ; */
 	unsigned int uiDSDPri = STATUS_FAILURE;
-	//DSD_HEADER dsdHeader = {0};
-	//priOffsetInMap = (PUCHAR)&(dsdHeader.DSDImagePriority) -(PUCHAR)&dsdHeader;
-	if(IsSectionWritable(Adapter,dsd))
-	{
-		if(ReadDSDSignature(Adapter,dsd)== DSD_IMAGE_MAGIC_NUMBER)
-		{
+	/* DSD_HEADER dsdHeader = {0};
+	 * priOffsetInMap = (PUCHAR)&(dsdHeader.DSDImagePriority) -(PUCHAR)&dsdHeader;
+	 */
+	if (IsSectionWritable(Adapter, dsd)) {
+		if (ReadDSDSignature(Adapter, dsd) == DSD_IMAGE_MAGIC_NUMBER) {
 			BcmFlash2xBulkRead(Adapter,
-							   &uiDSDPri,
-							   dsd,
-							   Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader +FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImagePriority),
-							   4);
+					&uiDSDPri,
+					dsd,
+					Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(PDSD_HEADER, DSDImagePriority),
+					4);
 
 			uiDSDPri = ntohl(uiDSDPri);
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"DSD<%x> Priority :%x", dsd, uiDSDPri);
-
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSD<%x> Priority :%x", dsd, uiDSDPri);
 		}
 	}
+
 	return uiDSDPri;
 }
-FLASH2X_SECTION_VAL getHighestPriDSD(PMINI_ADAPTER Adapter)
+
+FLASH2X_SECTION_VAL getHighestPriDSD(struct bcm_mini_adapter *Adapter)
 {
-	INT DSDHighestPri = STATUS_FAILURE;
-	INT  DsdPri= 0 ;
-	FLASH2X_SECTION_VAL HighestPriDSD = 0 ;
+	int DSDHighestPri = STATUS_FAILURE;
+	int DsdPri = 0;
+	FLASH2X_SECTION_VAL HighestPriDSD = 0;
 
-	if(IsSectionWritable(Adapter,DSD2))
-	{
-		DSDHighestPri = ReadDSDPriority(Adapter,DSD2);
-		HighestPriDSD = DSD2 ;
+	if (IsSectionWritable(Adapter, DSD2)) {
+		DSDHighestPri = ReadDSDPriority(Adapter, DSD2);
+		HighestPriDSD = DSD2;
 	}
-	if(IsSectionWritable(Adapter,DSD1))
-	{
-		 DsdPri = ReadDSDPriority(Adapter,DSD1);
-		 if(DSDHighestPri  < DsdPri)
-		 {
-		 	DSDHighestPri = DsdPri ;
+
+	if (IsSectionWritable(Adapter, DSD1)) {
+		DsdPri = ReadDSDPriority(Adapter, DSD1);
+		if (DSDHighestPri  < DsdPri) {
+			DSDHighestPri = DsdPri;
 			HighestPriDSD = DSD1;
-		 }
+		}
 	}
-	if(IsSectionWritable(Adapter,DSD0))
-	{
-		 DsdPri = ReadDSDPriority(Adapter,DSD0);
-		 if(DSDHighestPri  < DsdPri)
-		 {
-		 	DSDHighestPri = DsdPri ;
+
+	if (IsSectionWritable(Adapter, DSD0)) {
+		DsdPri = ReadDSDPriority(Adapter, DSD0);
+		if (DSDHighestPri  < DsdPri) {
+			DSDHighestPri = DsdPri;
 			HighestPriDSD = DSD0;
-		 }
+		}
 	}
-	if(HighestPriDSD)
-	 	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Highest DSD :%x , and its  Pri :%x", HighestPriDSD, DSDHighestPri);
-	return  HighestPriDSD ;
+	if (HighestPriDSD)
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Highest DSD :%x , and its  Pri :%x", HighestPriDSD, DSDHighestPri);
+
+	return  HighestPriDSD;
 }
 
-INT ReadISOSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso)
+int ReadISOSignature(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL iso)
 {
-		UINT uiISOsig = 0;
-		//UINT sigoffsetInMap = 0;
-		//ISO_HEADER ISOHeader = {0};
-
-
-		//sigoffsetInMap =(PUCHAR)&(ISOHeader.ISOImageMagicNumber) -(PUCHAR)&ISOHeader;
-
-		if(iso != ISO_IMAGE1 && iso != ISO_IMAGE2)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"passed section value is not for ISOs");
-			return STATUS_FAILURE;
-		}
-		BcmFlash2xBulkRead(Adapter,
-						   &uiISOsig,
-						   iso,
-						   0 + FIELD_OFFSET_IN_HEADER(PISO_HEADER,ISOImageMagicNumber),
-						   SIGNATURE_SIZE);
+	unsigned int uiISOsig = 0;
+	/* unsigned int sigoffsetInMap = 0;
+	 * ISO_HEADER ISOHeader = {0};
+	 * sigoffsetInMap =(PUCHAR)&(ISOHeader.ISOImageMagicNumber) -(PUCHAR)&ISOHeader;
+	 */
+	if (iso != ISO_IMAGE1 && iso != ISO_IMAGE2) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "passed section value is not for ISOs");
+		return STATUS_FAILURE;
+	}
+	BcmFlash2xBulkRead(Adapter,
+			&uiISOsig,
+			iso,
+			0 + FIELD_OFFSET_IN_HEADER(PISO_HEADER, ISOImageMagicNumber),
+			SIGNATURE_SIZE);
 
-		uiISOsig = ntohl(uiISOsig);
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"ISO SIG :%x", uiISOsig);
+	uiISOsig = ntohl(uiISOsig);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISO SIG :%x", uiISOsig);
 
-		return uiISOsig ;
+	return uiISOsig;
 }
-INT ReadISOPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso)
-{
 
+int ReadISOPriority(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL iso)
+{
 	unsigned int ISOPri = STATUS_FAILURE;
-	if(IsSectionWritable(Adapter,iso))
-	{
-		if(ReadISOSignature(Adapter,iso)== ISO_IMAGE_MAGIC_NUMBER)
-		{
+	if (IsSectionWritable(Adapter, iso)) {
+		if (ReadISOSignature(Adapter, iso) == ISO_IMAGE_MAGIC_NUMBER) {
 			BcmFlash2xBulkRead(Adapter,
-							   &ISOPri,
-							   iso,
-							   0 + FIELD_OFFSET_IN_HEADER(PISO_HEADER, ISOImagePriority),
-							   4);
+					&ISOPri,
+					iso,
+					0 + FIELD_OFFSET_IN_HEADER(PISO_HEADER, ISOImagePriority),
+					4);
 
 			ISOPri = ntohl(ISOPri);
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"ISO<%x> Priority :%x", iso, ISOPri);
-
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISO<%x> Priority :%x", iso, ISOPri);
 		}
 	}
+
 	return ISOPri;
 }
-FLASH2X_SECTION_VAL getHighestPriISO(PMINI_ADAPTER Adapter)
+
+FLASH2X_SECTION_VAL getHighestPriISO(struct bcm_mini_adapter *Adapter)
 {
-	INT ISOHighestPri = STATUS_FAILURE;
-	INT  ISOPri= 0 ;
-	FLASH2X_SECTION_VAL HighestPriISO = NO_SECTION_VAL ;
+	int ISOHighestPri = STATUS_FAILURE;
+	int ISOPri = 0;
+	FLASH2X_SECTION_VAL HighestPriISO = NO_SECTION_VAL;
 
-	if(IsSectionWritable(Adapter,ISO_IMAGE2))
-	{
-		ISOHighestPri = ReadISOPriority(Adapter,ISO_IMAGE2);
-		HighestPriISO = ISO_IMAGE2 ;
+	if (IsSectionWritable(Adapter, ISO_IMAGE2)) {
+		ISOHighestPri = ReadISOPriority(Adapter, ISO_IMAGE2);
+		HighestPriISO = ISO_IMAGE2;
 	}
-	if(IsSectionWritable(Adapter,ISO_IMAGE1))
-	{
-		 ISOPri = ReadISOPriority(Adapter,ISO_IMAGE1);
-		 if(ISOHighestPri  < ISOPri)
-		 {
-			ISOHighestPri = ISOPri ;
+
+	if (IsSectionWritable(Adapter, ISO_IMAGE1)) {
+		ISOPri = ReadISOPriority(Adapter, ISO_IMAGE1);
+		if (ISOHighestPri  < ISOPri) {
+			ISOHighestPri = ISOPri;
 			HighestPriISO = ISO_IMAGE1;
-		 }
+		}
 	}
-	if(HighestPriISO)
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Highest ISO :%x and its Pri :%x",HighestPriISO,ISOHighestPri);
-	return	HighestPriISO ;
+	if (HighestPriISO)
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Highest ISO :%x and its Pri :%x", HighestPriISO, ISOHighestPri);
+
+	return HighestPriISO;
 }
-INT WriteToFlashWithoutSectorErase(PMINI_ADAPTER Adapter,
-										PUINT pBuff,
-										FLASH2X_SECTION_VAL eFlash2xSectionVal,
-										UINT uiOffset,
-										UINT uiNumBytes
-										)
+
+int WriteToFlashWithoutSectorErase(struct bcm_mini_adapter *Adapter,
+				PUINT pBuff,
+				FLASH2X_SECTION_VAL eFlash2xSectionVal,
+				unsigned int uiOffset,
+				unsigned int uiNumBytes)
 {
-#if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS)
-	UINT uiTemp = 0, value = 0 ;
-	UINT i = 0;
-	UINT uiPartOffset = 0;
-#endif
-	UINT uiStartOffset = 0;
-	//Adding section start address
-	INT Status = STATUS_SUCCESS;
+	#if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS)
+		unsigned int uiTemp = 0, value = 0;
+		unsigned int i = 0;
+		unsigned int uiPartOffset = 0;
+	#endif
+	unsigned int uiStartOffset = 0;
+	/* Adding section start address */
+	int Status = STATUS_SUCCESS;
 	PUCHAR pcBuff = (PUCHAR)pBuff;
 
-	if(uiNumBytes % Adapter->ulFlashWriteSize)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Writing without Sector Erase for non-FlashWriteSize number of bytes 0x%x\n", uiNumBytes);
+	if (uiNumBytes % Adapter->ulFlashWriteSize) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Writing without Sector Erase for non-FlashWriteSize number of bytes 0x%x\n", uiNumBytes);
 		return STATUS_FAILURE;
 	}
 
-	uiStartOffset = BcmGetSectionValStartOffset(Adapter,eFlash2xSectionVal);
+	uiStartOffset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectionVal);
 
-	if(IsSectionExistInVendorInfo(Adapter,eFlash2xSectionVal))
-	{
+	if (IsSectionExistInVendorInfo(Adapter, eFlash2xSectionVal))
 		return vendorextnWriteSectionWithoutErase(Adapter, pcBuff, eFlash2xSectionVal, uiOffset, uiNumBytes);
-	}
 
 	uiOffset = uiOffset + uiStartOffset;
 
-#if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
-  Status = bcmflash_raw_writenoerase((uiOffset/FLASH_PART_SIZE),(uiOffset % FLASH_PART_SIZE), pcBuff,uiNumBytes);
-#else
-	rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
-	value = 0;
-	wrmalt(Adapter, 0x0f000C80,&value, sizeof(value));
+	#if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
+		Status = bcmflash_raw_writenoerase((uiOffset / FLASH_PART_SIZE), (uiOffset % FLASH_PART_SIZE), pcBuff, uiNumBytes);
+	#else
+		rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
+		value = 0;
+		wrmalt(Adapter, 0x0f000C80, &value, sizeof(value));
 
-	Adapter->SelectedChip = RESET_CHIP_SELECT;
-	BcmDoChipSelect(Adapter,uiOffset);
-	uiPartOffset = (uiOffset & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter);
+		Adapter->SelectedChip = RESET_CHIP_SELECT;
+		BcmDoChipSelect(Adapter, uiOffset);
+		uiPartOffset = (uiOffset & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter);
 
-	for(i = 0 ; i< uiNumBytes; i += Adapter->ulFlashWriteSize)
-	{
-		if(Adapter->ulFlashWriteSize == BYTE_WRITE_SUPPORT)
-			Status = flashByteWrite(Adapter,uiPartOffset, pcBuff);
-		else
-			Status = flashWrite(Adapter,uiPartOffset, pcBuff);
+		for (i = 0 ; i < uiNumBytes; i += Adapter->ulFlashWriteSize) {
+			if (Adapter->ulFlashWriteSize == BYTE_WRITE_SUPPORT)
+				Status = flashByteWrite(Adapter, uiPartOffset, pcBuff);
+			else
+				Status = flashWrite(Adapter, uiPartOffset, pcBuff);
 
-		if(Status != STATUS_SUCCESS)
-			break;
+			if (Status != STATUS_SUCCESS)
+				break;
 
-		pcBuff = pcBuff + Adapter->ulFlashWriteSize;
-		uiPartOffset = uiPartOffset +  Adapter->ulFlashWriteSize;
-	}
-	wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
-	Adapter->SelectedChip = RESET_CHIP_SELECT;
-#endif
+			pcBuff = pcBuff + Adapter->ulFlashWriteSize;
+			uiPartOffset = uiPartOffset +  Adapter->ulFlashWriteSize;
+		}
+		wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp));
+		Adapter->SelectedChip = RESET_CHIP_SELECT;
+	#endif
 
 	return Status;
 }
 
-BOOLEAN IsSectionExistInFlash(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section)
+BOOLEAN IsSectionExistInFlash(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL section)
 {
+	BOOLEAN SectionPresent = FALSE;
+
+	switch (section) {
+	case ISO_IMAGE1:
+		if ((Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start != UNINIT_PTR_IN_CS) &&
+			(IsNonCDLessDevice(Adapter) == FALSE))
+			SectionPresent = TRUE;
+		break;
+	case ISO_IMAGE2:
+		if ((Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start != UNINIT_PTR_IN_CS) &&
+			(IsNonCDLessDevice(Adapter) == FALSE))
+			SectionPresent = TRUE;
+		break;
+	case DSD0:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart != UNINIT_PTR_IN_CS)
+			SectionPresent = TRUE;
+		break;
+	case DSD1:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start != UNINIT_PTR_IN_CS)
+			SectionPresent = TRUE;
+		break;
+	case DSD2:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start != UNINIT_PTR_IN_CS)
+			SectionPresent = TRUE;
+		break;
+	case VSA0:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart != UNINIT_PTR_IN_CS)
+			SectionPresent = TRUE;
+		break;
+	case VSA1:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start != UNINIT_PTR_IN_CS)
+			SectionPresent = TRUE;
+		break;
+	case VSA2:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start != UNINIT_PTR_IN_CS)
+			SectionPresent = TRUE;
+		break;
+	case SCSI:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware != UNINIT_PTR_IN_CS)
+			SectionPresent = TRUE;
+		break;
+	case CONTROL_SECTION:
+		if (Adapter->psFlash2xCSInfo->OffsetFromZeroForControlSectionStart != UNINIT_PTR_IN_CS)
+			SectionPresent = TRUE;
+		break;
+	default:
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section Does not exist in Flash 2.x");
+		SectionPresent =  FALSE;
+	}
+
+	return SectionPresent;
+}
 
-	BOOLEAN SectionPresent = FALSE ;
+int IsSectionWritable(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL Section)
+{
+	int offset = STATUS_FAILURE;
+	int Status = FALSE;
 
-	switch(section)
-	{
+	if (IsSectionExistInFlash(Adapter, Section) == FALSE) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section <%d> does not exixt", Section);
+		return FALSE;
+	}
 
-		case ISO_IMAGE1 :
-			  if((Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start != UNINIT_PTR_IN_CS) &&
-			  		(IsNonCDLessDevice(Adapter) == FALSE))
-				  SectionPresent = TRUE ;
-			   break;
-		case ISO_IMAGE2 :
-				if((Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start != UNINIT_PTR_IN_CS) &&
-					(IsNonCDLessDevice(Adapter) == FALSE))
-					 SectionPresent = TRUE ;
-			  break;
-		case DSD0 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart != UNINIT_PTR_IN_CS)
-					 SectionPresent = TRUE ;
-				break;
-		case DSD1 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start != UNINIT_PTR_IN_CS)
-					 SectionPresent = TRUE ;
-				break;
-		case DSD2 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start != UNINIT_PTR_IN_CS)
-					 SectionPresent = TRUE ;
-				break;
-		case VSA0 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart != UNINIT_PTR_IN_CS)
-					 SectionPresent = TRUE ;
-				break;
-		case VSA1 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start != UNINIT_PTR_IN_CS)
-					 SectionPresent = TRUE ;
-				break;
-		case VSA2 :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start != UNINIT_PTR_IN_CS)
-					 SectionPresent = TRUE ;
-				break;
-		case SCSI :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware != UNINIT_PTR_IN_CS)
-					 SectionPresent = TRUE ;
-				break;
-		case CONTROL_SECTION :
-				if(Adapter->psFlash2xCSInfo->OffsetFromZeroForControlSectionStart != UNINIT_PTR_IN_CS)
-					 SectionPresent = TRUE ;
-				break;
-		default :
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section Does not exist in Flash 2.x");
-			SectionPresent =  FALSE;
+	offset = BcmGetSectionValStartOffset(Adapter, Section);
+	if (offset == INVALID_OFFSET) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section<%d> does not exixt", Section);
+		return FALSE;
 	}
-	return SectionPresent ;
-}
-INT IsSectionWritable(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL Section)
-{
-		INT offset = STATUS_FAILURE;
-		INT Status = FALSE;
-		if(IsSectionExistInFlash(Adapter,Section) == FALSE)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section <%d> does not exixt", Section);
-			return FALSE;
-		}
-		offset = BcmGetSectionValStartOffset(Adapter,Section);
-		if(offset == INVALID_OFFSET)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section<%d> does not exixt", Section);
-			return FALSE;
-		}
 
-		if(IsSectionExistInVendorInfo(Adapter,Section))
-		{
-			return !(Adapter->psFlash2xVendorInfo->VendorSection[Section].AccessFlags & FLASH2X_SECTION_RO);
-		}
+	if (IsSectionExistInVendorInfo(Adapter, Section))
+		return !(Adapter->psFlash2xVendorInfo->VendorSection[Section].AccessFlags & FLASH2X_SECTION_RO);
 
-		Status = IsOffsetWritable(Adapter,offset);
-		return Status ;
+	Status = IsOffsetWritable(Adapter, offset);
+	return Status;
 }
 
-static INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
+static int CorruptDSDSig(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
 {
-
 	PUCHAR pBuff = NULL;
-	UINT sig = 0;
-	UINT uiOffset = 0;
-	UINT BlockStatus = 0;
-	UINT uiSectAlignAddr = 0;
+	unsigned int sig = 0;
+	unsigned int uiOffset = 0;
+	unsigned int BlockStatus = 0;
+	unsigned int uiSectAlignAddr = 0;
 
 	Adapter->bSigCorrupted = FALSE;
-
-	if(Adapter->bAllDSDWriteAllow == FALSE)
-	{
-		if(IsSectionWritable(Adapter,eFlash2xSectionVal) != TRUE)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section is not Writable...Hence can't Corrupt signature");
+	if (Adapter->bAllDSDWriteAllow == FALSE) {
+		if (IsSectionWritable(Adapter, eFlash2xSectionVal) != TRUE) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section is not Writable...Hence can't Corrupt signature");
 			return SECTOR_IS_NOT_WRITABLE;
 		}
 	}
 
 	pBuff = (PUCHAR)kzalloc(MAX_RW_SIZE, GFP_KERNEL);
-	if(pBuff == NULL)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Can't allocate memorey");
-		return -ENOMEM ;
+	if (!pBuff) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Can't allocate memorey");
+		return -ENOMEM;
 	}
 
 	uiOffset = Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER);
-	uiOffset -= MAX_RW_SIZE ;
-
-	BcmFlash2xBulkRead(Adapter, (PUINT)pBuff,eFlash2xSectionVal,uiOffset,MAX_RW_SIZE);
+	uiOffset -= MAX_RW_SIZE;
 
+	BcmFlash2xBulkRead(Adapter, (PUINT)pBuff, eFlash2xSectionVal, uiOffset, MAX_RW_SIZE);
 
-	sig = *((PUINT)(pBuff +12));
-	sig =ntohl(sig);
-	BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,pBuff,MAX_RW_SIZE);
-	//Now corrupting the sig by corrupting 4th last Byte.
+	sig = *((PUINT)(pBuff + 12));
+	sig = ntohl(sig);
+	BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, pBuff, MAX_RW_SIZE);
+	/* Now corrupting the sig by corrupting 4th last Byte. */
 	*(pBuff + 12) = 0;
 
-	if(sig == DSD_IMAGE_MAGIC_NUMBER)
-	{
+	if (sig == DSD_IMAGE_MAGIC_NUMBER) {
 		Adapter->bSigCorrupted = TRUE;
-		if(Adapter->ulFlashWriteSize == BYTE_WRITE_SUPPORT)
-		{
-			uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize -1);
-			BlockStatus = BcmFlashUnProtectBlock(Adapter,uiSectAlignAddr,Adapter->uiSectorSize);
-
-			WriteToFlashWithoutSectorErase(Adapter,(PUINT)(pBuff + 12),eFlash2xSectionVal,
-												(uiOffset + 12),BYTE_WRITE_SUPPORT);
-			if(BlockStatus)
-			{
-				BcmRestoreBlockProtectStatus(Adapter,BlockStatus);
+		if (Adapter->ulFlashWriteSize == BYTE_WRITE_SUPPORT) {
+			uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize - 1);
+			BlockStatus = BcmFlashUnProtectBlock(Adapter, uiSectAlignAddr, Adapter->uiSectorSize);
+
+			WriteToFlashWithoutSectorErase(Adapter, (PUINT)(pBuff + 12), eFlash2xSectionVal,
+						(uiOffset + 12), BYTE_WRITE_SUPPORT);
+			if (BlockStatus) {
+				BcmRestoreBlockProtectStatus(Adapter, BlockStatus);
 				BlockStatus = 0;
 			}
+		} else {
+			WriteToFlashWithoutSectorErase(Adapter, (PUINT)pBuff, eFlash2xSectionVal,
+						uiOffset, MAX_RW_SIZE);
 		}
-		else
-		{
-			WriteToFlashWithoutSectorErase(Adapter,(PUINT)pBuff,eFlash2xSectionVal,
-												uiOffset ,MAX_RW_SIZE);
-		}
-	}
-	else
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"BCM Signature is not present in header");
+	} else {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "BCM Signature is not present in header");
 		kfree(pBuff);
+
 		return STATUS_FAILURE;
 	}
 
 	kfree(pBuff);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Corrupted the signature");
-	return STATUS_SUCCESS ;
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Corrupted the signature");
+
+	return STATUS_SUCCESS;
 }
 
-static INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
+static int CorruptISOSig(struct bcm_mini_adapter *Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
 {
-
 	PUCHAR pBuff = NULL;
-	UINT sig = 0;
-	UINT uiOffset = 0;
+	unsigned int sig = 0;
+	unsigned int uiOffset = 0;
 
 	Adapter->bSigCorrupted = FALSE;
 
-	if(IsSectionWritable(Adapter,eFlash2xSectionVal) != TRUE)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section is not Writable...Hence can't Corrupt signature");
+	if (IsSectionWritable(Adapter, eFlash2xSectionVal) != TRUE) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section is not Writable...Hence can't Corrupt signature");
 		return SECTOR_IS_NOT_WRITABLE;
 	}
 
 	pBuff = (PUCHAR)kzalloc(MAX_RW_SIZE, GFP_KERNEL);
-	if(pBuff == NULL)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Can't allocate memorey");
-		return -ENOMEM ;
+	if (!pBuff) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Can't allocate memorey");
+		return -ENOMEM;
 	}
 
 	uiOffset = 0;
 
-	BcmFlash2xBulkRead(Adapter, (PUINT)pBuff,eFlash2xSectionVal,uiOffset, MAX_RW_SIZE);
+	BcmFlash2xBulkRead(Adapter, (PUINT)pBuff, eFlash2xSectionVal, uiOffset, MAX_RW_SIZE);
 
 	sig = *((PUINT)pBuff);
-	sig =ntohl(sig);
+	sig = ntohl(sig);
 
-	//corrupt signature
+	/* corrupt signature */
 	*pBuff = 0;
 
-	if(sig == ISO_IMAGE_MAGIC_NUMBER)
-	{
+	if (sig == ISO_IMAGE_MAGIC_NUMBER) {
 		Adapter->bSigCorrupted = TRUE;
-		WriteToFlashWithoutSectorErase(Adapter,(PUINT)pBuff,eFlash2xSectionVal,
-											uiOffset ,Adapter->ulFlashWriteSize);
-	}
-	else
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"BCM Signature is not present in header");
+		WriteToFlashWithoutSectorErase(Adapter, (PUINT)pBuff, eFlash2xSectionVal,
+					uiOffset, Adapter->ulFlashWriteSize);
+	} else {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "BCM Signature is not present in header");
 		kfree(pBuff);
+
 		return STATUS_FAILURE;
 	}
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Corrupted the signature");
-	BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,pBuff,MAX_RW_SIZE);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Corrupted the signature");
+	BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, pBuff, MAX_RW_SIZE);
 
 	kfree(pBuff);
-	return STATUS_SUCCESS ;
+	return STATUS_SUCCESS;
 }
 
-BOOLEAN IsNonCDLessDevice(PMINI_ADAPTER Adapter)
+BOOLEAN IsNonCDLessDevice(struct bcm_mini_adapter *Adapter)
 {
-	if(Adapter->psFlash2xCSInfo->IsCDLessDeviceBootSig == NON_CDLESS_DEVICE_BOOT_SIG)
+	if (Adapter->psFlash2xCSInfo->IsCDLessDeviceBootSig == NON_CDLESS_DEVICE_BOOT_SIG)
 		return TRUE;
 	else
-		return FALSE ;
+		return FALSE;
 }
-
diff --git a/drivers/staging/bcm/sort.c b/drivers/staging/bcm/sort.c
index 63c966a..d518c42 100644
--- a/drivers/staging/bcm/sort.c
+++ b/drivers/staging/bcm/sort.c
@@ -13,8 +13,8 @@
 
 static int compare_packet_info(void const *a, void const *b)
 {
-	PacketInfo const *pa = a;
-	PacketInfo const *pb = b;
+	struct bcm_packet_info const *pa = a;
+	struct bcm_packet_info const *pb = b;
 
 	if (!pa->bValid || !pb->bValid)
 		return 0;
@@ -22,19 +22,19 @@ static int compare_packet_info(void const *a, void const *b)
 	return pa->u8TrafficPriority - pb->u8TrafficPriority;
 }
 
-VOID SortPackInfo(PMINI_ADAPTER Adapter)
+VOID SortPackInfo(struct bcm_mini_adapter *Adapter)
 {
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG,
 			DBG_LVL_ALL, "<=======");
 
-	sort(Adapter->PackInfo, NO_OF_QUEUES, sizeof(PacketInfo),
+	sort(Adapter->PackInfo, NO_OF_QUEUES, sizeof(struct bcm_packet_info),
 		compare_packet_info, NULL);
 }
 
 static int compare_classifiers(void const *a, void const *b)
 {
-	S_CLASSIFIER_RULE const *pa = a;
-	S_CLASSIFIER_RULE const *pb = b;
+	struct bcm_classifier_rule const *pa = a;
+	struct bcm_classifier_rule const *pb = b;
 
 	if (!pa->bUsed || !pb->bUsed)
 		return 0;
@@ -42,11 +42,11 @@ static int compare_classifiers(void const *a, void const *b)
 	return pa->u8ClassifierRulePriority - pb->u8ClassifierRulePriority;
 }
 
-VOID SortClassifiers(PMINI_ADAPTER Adapter)
+VOID SortClassifiers(struct bcm_mini_adapter *Adapter)
 {
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG,
 			DBG_LVL_ALL, "<=======");
 
 	sort(Adapter->astClassifierTable, MAX_CLASSIFIERS,
-		sizeof(S_CLASSIFIER_RULE), compare_classifiers, NULL);
+		sizeof(struct bcm_classifier_rule), compare_classifiers, NULL);
 }
diff --git a/drivers/staging/bcm/vendorspecificextn.c b/drivers/staging/bcm/vendorspecificextn.c
index 4178cd1..833883c 100644
--- a/drivers/staging/bcm/vendorspecificextn.c
+++ b/drivers/staging/bcm/vendorspecificextn.c
@@ -28,7 +28,7 @@ INT vendorextnGetSectionInfo(PVOID  pContext,PFLASH2X_VENDORSPECIFIC_INFO pVendo
 //              STATUS_SUCCESS/STATUS_FAILURE
 //
 //-----------------------------------------------------------------------------
-INT vendorextnInit(PMINI_ADAPTER Adapter)
+INT vendorextnInit(struct bcm_mini_adapter *Adapter)
 {
 	return STATUS_SUCCESS;
 }
@@ -45,7 +45,7 @@ INT vendorextnInit(PMINI_ADAPTER Adapter)
 //              STATUS_SUCCESS/STATUS_FAILURE
 //
 //-----------------------------------------------------------------------------
-INT vendorextnExit(PMINI_ADAPTER Adapter)
+INT vendorextnExit(struct bcm_mini_adapter *Adapter)
 {
 	return STATUS_SUCCESS;
 }
@@ -65,7 +65,7 @@ INT vendorextnExit(PMINI_ADAPTER Adapter)
 //		STATUS_SUCCESS/STATUS_FAILURE as per the IOCTL return value
 //
 //--------------------------------------------------------------------------
-INT vendorextnIoctl(PMINI_ADAPTER Adapter, UINT cmd, ULONG arg)
+INT vendorextnIoctl(struct bcm_mini_adapter *Adapter, UINT cmd, ULONG arg)
 {
 	return CONTINUE_COMMON_PATH;
 }
diff --git a/drivers/staging/bcm/vendorspecificextn.h b/drivers/staging/bcm/vendorspecificextn.h
index 7ff1495..f237891b 100644
--- a/drivers/staging/bcm/vendorspecificextn.h
+++ b/drivers/staging/bcm/vendorspecificextn.h
@@ -5,9 +5,9 @@
 #define CONTINUE_COMMON_PATH 0xFFFF
 
 INT vendorextnGetSectionInfo(PVOID  pContext,PFLASH2X_VENDORSPECIFIC_INFO pVendorInfo);
-INT vendorextnExit(PMINI_ADAPTER Adapter);
-INT vendorextnInit(PMINI_ADAPTER Adapter);
-INT vendorextnIoctl(PMINI_ADAPTER Adapter, UINT cmd, ULONG arg);
+INT vendorextnExit(struct bcm_mini_adapter *Adapter);
+INT vendorextnInit(struct bcm_mini_adapter *Adapter);
+INT vendorextnIoctl(struct bcm_mini_adapter *Adapter, UINT cmd, ULONG arg);
 INT vendorextnReadSection(PVOID  pContext, PUCHAR pBuffer, FLASH2X_SECTION_VAL SectionVal,
 			UINT offset, UINT numOfBytes);
 INT vendorextnWriteSection(PVOID  pContext, PUCHAR pBuffer, FLASH2X_SECTION_VAL SectionVal,
diff --git a/drivers/staging/ccg/Kconfig b/drivers/staging/ccg/Kconfig
index ff05e52..1f00d70 100644
--- a/drivers/staging/ccg/Kconfig
+++ b/drivers/staging/ccg/Kconfig
@@ -2,7 +2,7 @@ if USB_GADGET
 
 config USB_G_CCG
 	tristate "Configurable Composite Gadget (STAGING)"
-	depends on STAGING && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM
+	depends on STAGING && BLOCK && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM
 	help
 	  The Configurable Composite Gadget supports multiple USB
 	  functions: acm, mass storage, rndis and FunctionFS.
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 3bbe3fd..6cee785 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -6,9 +6,10 @@ config COMEDI
 	  Enable support a wide range of data acquisition devices
 	  for Linux.
 
+if COMEDI
+
 config COMEDI_DEBUG
 	bool "Comedi debugging"
-	depends on COMEDI != n
 	---help---
 	  This is an option for use by developers; most people should
 	  say N here. This enables comedi core and driver debugging.
@@ -16,7 +17,6 @@ config COMEDI_DEBUG
 config COMEDI_DEFAULT_BUF_SIZE_KB
 	int "Comedi default initial asynchronous buffer size in KiB"
 	default "2048"
-	depends on COMEDI != n
 	---help---
 	  This is the default asynchronous buffer size which is used for
 	  commands running in the background in kernel space.  This
@@ -26,7 +26,6 @@ config COMEDI_DEFAULT_BUF_SIZE_KB
 config COMEDI_DEFAULT_BUF_MAXSIZE_KB
 	int "Comedi default maximum asynchronous buffer size in KiB"
 	default "20480"
-	depends on COMEDI != n
 	---help---
 	  This is the default maximum asynchronous buffer size which can
 	  be requested by a userspace program without root privileges.
@@ -34,8 +33,7 @@ config COMEDI_DEFAULT_BUF_MAXSIZE_KB
 	  channels running at 100 kHz has 2-4 seconds of buffer.
 
 menuconfig COMEDI_MISC_DRIVERS
-	tristate "Comedi misc drivers"
-	depends on COMEDI
+	bool "Comedi misc drivers"
 	---help---
 	  Enable comedi misc drivers to be built
 
@@ -102,8 +100,8 @@ config COMEDI_SKEL
 endif # COMEDI_MISC_DRIVERS
 
 menuconfig COMEDI_ISA_DRIVERS
-	tristate "Comedi ISA and PC/104 drivers"
-	depends on COMEDI && ISA
+	bool "Comedi ISA and PC/104 drivers"
+	depends on ISA
 	---help---
 	  Enable comedi ISA and PC/104 drivers to be built
 
@@ -111,7 +109,7 @@ menuconfig COMEDI_ISA_DRIVERS
 	  kernel: saying N will just cause the configurator to skip all
 	  the questions about ISA and PC/104 comedi drivers.
 
-if COMEDI_ISA_DRIVERS && ISA
+if COMEDI_ISA_DRIVERS
 
 config COMEDI_ACL7225B
 	tristate "ADlink NuDAQ ACL-7225b and compatibles support"
@@ -215,7 +213,6 @@ config COMEDI_PCM3730
 config COMEDI_AMPLC_DIO200_ISA
 	tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E"
 	select COMEDI_AMPLC_DIO200
-	depends on COMEDI_ISA_DRIVERS
 	---help---
 	  Enable support for Amplicon PC212E, PC214E, PC215E, PC218E and
 	  PC272E ISA DIO boards
@@ -447,7 +444,6 @@ config COMEDI_ADQ12B
 
 config COMEDI_NI_AT_A2150
 	tristate "NI AT-A2150 ISA card support"
-	depends on COMEDI_NI_COMMON
 	depends on VIRT_TO_BUS
 	---help---
 	  Enable support for National Instruments AT-A2150 cards
@@ -457,7 +453,6 @@ config COMEDI_NI_AT_A2150
 
 config COMEDI_NI_AT_AO
 	tristate "NI AT-AO-6/10 EISA card support"
-	depends on COMEDI_NI_COMMON
 	---help---
 	  Enable support for National Instruments AT-AO-6/10 cards
 
@@ -466,8 +461,9 @@ config COMEDI_NI_AT_AO
 
 config COMEDI_NI_ATMIO
 	tristate "NI AT-MIO E series ISA-PNP card support"
-	depends on ISAPNP && COMEDI_NI_TIO && COMEDI_NI_COMMON
+	depends on ISAPNP
 	select COMEDI_8255
+	select COMEDI_NI_TIO
 	---help---
 	  Enable support for National Instruments AT-MIO E series cards
 	  National Instruments AT-MIO-16E-1 (ni_atmio),
@@ -479,7 +475,7 @@ config COMEDI_NI_ATMIO
 
 config COMEDI_NI_ATMIO16D
 	tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support"
-	depends on ISAPNP && COMEDI_NI_COMMON
+	depends on ISAPNP
 	select COMEDI_8255
 	---help---
 	  Enable support for National Instruments AT-MIO16/AT-MIO16D cards.
@@ -542,8 +538,8 @@ config COMEDI_POC
 endif # COMEDI_ISA_DRIVERS
 
 menuconfig COMEDI_PCI_DRIVERS
-	tristate "Comedi PCI drivers"
-	depends on COMEDI && PCI
+	bool "Comedi PCI drivers"
+	depends on PCI
 	---help---
 	  Enable comedi PCI drivers to be built
 
@@ -551,7 +547,7 @@ menuconfig COMEDI_PCI_DRIVERS
 	  kernel: saying N will just cause the configurator to skip all
 	  the questions about PCI comedi drivers.
 
-if COMEDI_PCI_DRIVERS && PCI
+if COMEDI_PCI_DRIVERS
 
 config COMEDI_ADDI_APCI_035
 	tristate "ADDI-DATA APCI_035 support"
@@ -674,7 +670,6 @@ config COMEDI_ADDI_APCI_3XXX
 
 config COMEDI_ADL_PCI6208
 	tristate "ADLink PCI-6208A support"
-	select COMEDI_8255
 	---help---
 	  Enable support for ADLink PCI-6208A cards
 
@@ -691,6 +686,7 @@ config COMEDI_ADL_PCI7230
 
 config COMEDI_ADL_PCI7296
 	tristate "ADLink PCI-7296 96 ch. digital io board support"
+	select COMEDI_8255
 	---help---
 	  Enable support for ADlink PCI-7296 96 ch. digital io board support
 
@@ -988,7 +984,7 @@ config COMEDI_ME_DAQ
 
 config COMEDI_NI_6527
 	tristate "NI 6527 support"
-	depends on COMEDI_MITE
+	select COMEDI_MITE
 	---help---
 	  Enable support for the National Instruments 6527 PCI card
 
@@ -997,7 +993,7 @@ config COMEDI_NI_6527
 
 config COMEDI_NI_65XX
 	tristate "NI 65xx static dio PCI card support"
-	depends on COMEDI_MITE
+	select COMEDI_MITE
 	---help---
 	  Enable support for National Instruments 65xx static dio boards.
 	  Supported devices: National Instruments PCI-6509 (ni_65xx),
@@ -1010,7 +1006,7 @@ config COMEDI_NI_65XX
 
 config COMEDI_NI_660X
 	tristate "NI 660x counter/timer PCI card support"
-	depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
+	select COMEDI_NI_TIOCMD
 	---help---
 	  Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602,
 	  PXI-6602 and PXI-6608.
@@ -1020,16 +1016,31 @@ config COMEDI_NI_660X
 
 config COMEDI_NI_670X
 	tristate "NI 670x PCI card support"
-	depends on COMEDI_MITE
+	select COMEDI_MITE
 	---help---
 	  Enable support for National Instruments PCI-6703 and PCI-6704
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called ni_670x.
 
+config COMEDI_NI_LABPC
+	tristate "NI Lab-PC and compatibles ISA and PCI support"
+	select COMEDI_MITE
+	select COMEDI_8255
+	select COMEDI_FC
+	depends on VIRT_TO_BUS
+	---help---
+	  Enable support for National Instruments Lab-PC and compatibles
+	  Lab-PC-1200, Lab-PC-1200AI, Lab-PC+ and PCI-1200.
+	  Kernel-level ISA plug-and-play support for the lab-pc-1200 boards has
+	  not yet been added to the driver.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called ni_labpc.
+
 config COMEDI_NI_PCIDIO
 	tristate "NI PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 support"
-	depends on COMEDI_MITE
+	select COMEDI_MITE
 	select COMEDI_8255
 	---help---
 	  Enable support for National Instruments PCI-DIO-32HS, PXI-6533,
@@ -1043,7 +1054,7 @@ config COMEDI_NI_PCIDIO
 
 config COMEDI_NI_PCIMIO
 	tristate "NI PCI-MIO-E series and M series support"
-	depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
+	select COMEDI_NI_TIOCMD
 	select COMEDI_8255
 	select COMEDI_FC
 	---help---
@@ -1063,7 +1074,6 @@ config COMEDI_NI_PCIMIO
 
 config COMEDI_RTD520
 	tristate "Real Time Devices PCI4520/DM7520 support"
-	select COMEDI_8255
 	---help---
 	  Enable support for Real Time Devices PCI4520/DM7520
 
@@ -1095,11 +1105,19 @@ config COMEDI_SSV_DNP
 	  To compile this driver as a module, choose M here: the module will be
 	  called ssv_dnp.
 
+config COMEDI_MITE
+	tristate
+
+config COMEDI_NI_TIOCMD
+	tristate
+	select COMEDI_NI_TIO
+	select COMEDI_MITE
+
 endif # COMEDI_PCI_DRIVERS
 
 menuconfig COMEDI_PCMCIA_DRIVERS
-	tristate "Comedi PCMCIA drivers"
-	depends on COMEDI && (PCMCIA || PCCARD)
+	bool "Comedi PCMCIA drivers"
+	depends on PCMCIA
 	---help---
 	  Enable comedi PCMCIA and PCCARD drivers to be built
 
@@ -1107,7 +1125,7 @@ menuconfig COMEDI_PCMCIA_DRIVERS
 	  kernel: saying N will just cause the configurator to skip all
 	  the questions about PCMCIA comedi drivers.
 
-if COMEDI_PCMCIA_DRIVERS && PCMCIA
+if COMEDI_PCMCIA_DRIVERS
 
 config COMEDI_CB_DAS16_CS
 	tristate "CB DAS16 series PCMCIA support"
@@ -1130,7 +1148,6 @@ config COMEDI_DAS08_CS
 
 config COMEDI_NI_DAQ_700_CS
 	tristate "NI DAQCard-700 PCMCIA support"
-	depends on COMEDI_NI_COMMON
 	---help---
 	  Enable support for the National Instruments PCMCIA DAQCard-700 DIO
 
@@ -1139,7 +1156,6 @@ config COMEDI_NI_DAQ_700_CS
 
 config COMEDI_NI_DAQ_DIO24_CS
 	tristate "NI DAQ-Card DIO-24 PCMCIA support"
-	depends on COMEDI_NI_COMMON
 	select COMEDI_8255
 	---help---
 	  Enable support for the National Instruments PCMCIA DAQ-Card DIO-24
@@ -1158,7 +1174,7 @@ config COMEDI_NI_LABPC_CS
 
 config COMEDI_NI_MIO_CS
 	tristate "NI DAQCard E series PCMCIA support"
-	depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
+	select COMEDI_NI_TIO
 	select COMEDI_8255
 	select COMEDI_FC
 	---help---
@@ -1181,8 +1197,8 @@ config COMEDI_QUATECH_DAQP_CS
 endif # COMEDI_PCMCIA_DRIVERS
 
 menuconfig COMEDI_USB_DRIVERS
-	tristate "Comedi USB drivers"
-	depends on COMEDI && USB
+	bool "Comedi USB drivers"
+	depends on USB
 	---help---
 	  Enable comedi USB drivers to be built
 
@@ -1190,7 +1206,7 @@ menuconfig COMEDI_USB_DRIVERS
 	  kernel: saying N will just cause the configurator to skip all
 	  the questions about USB comedi drivers.
 
-if COMEDI_USB_DRIVERS && USB
+if COMEDI_USB_DRIVERS
 
 config COMEDI_DT9812
 	tristate "DataTranslation DT9812 USB module support"
@@ -1237,60 +1253,8 @@ config COMEDI_VMK80XX
 
 endif # COMEDI_USB_DRIVERS
 
-menuconfig COMEDI_NI_COMMON
-	tristate "Comedi National Instruments card support"
-	depends on COMEDI
-	---help---
-	  Enable comedi support for National Instruments cards.
-	  Modules in this section are used by many comedi NI drivers.
-
-	  Note that the answer to this question won't directly affect the
-	  kernel: saying N will just cause the configurator to skip all
-	  the questions about National Instruments cards.
-
-if COMEDI_NI_COMMON
-
-config COMEDI_MITE
-	tristate "NI Mite PCI interface chip support"
-	depends on PCI
-	---help---
-	  Enable support for National Instruments Mite PCI interface chip
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called mite.
-
-config COMEDI_NI_TIO
-	tristate "NI general purpose counter support"
-	depends on COMEDI_MITE
-	---help---
-	  Enable support for National Instruments general purpose counters.
-	  This module is not used directly by end-users. Rather, it
-	  is used by other drivers (for example ni_660x and ni_pcimio)
-	  to provide support for NI's general purpose counters.
-
-	  To compile this driver as a modules, choose M here: two modules will
-	  be build: ni_tio and ni_tiocmd.
-
-config COMEDI_NI_LABPC
-	tristate "NI Lab-PC and compatibles ISA and PCI support"
-	depends on COMEDI_MITE
-	select COMEDI_8255
-	select COMEDI_FC
-	depends on VIRT_TO_BUS
-	---help---
-	  Enable support for National Instruments Lab-PC and compatibles
-	  Lab-PC-1200, Lab-PC-1200AI, Lab-PC+ and PCI-1200.
-	  Kernel-level ISA plug-and-play support for the lab-pc-1200 boards has
-	  not yet been added to the driver.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called ni_labpc.
-
-endif # COMEDI_NI_COMMON
-
 config COMEDI_8255
 	tristate "Generic 8255 support"
-	depends on COMEDI
 	---help---
 	  Enable generic 8255 support.
 
@@ -1305,31 +1269,24 @@ config COMEDI_8255
 	  called 8255.
 
 config COMEDI_FC
-	tristate "Comedi shared functions for low-level driver support"
-	depends on COMEDI
-	---help---
-	  Enable support for shared functions for low-level drivers.
-	  This module is not used directly by end-users. Rather, it
-	  is used by many other comedi drivers.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called comedi_fc.
+	tristate
 
 config COMEDI_AMPLC_DIO200
 	tristate
-	depends on COMEDI
 	select COMEDI_8255
 
 config COMEDI_AMPLC_PC236
 	tristate
-	depends on COMEDI
 	select COMEDI_8255
 
 config COMEDI_AMPLC_PC263
 	tristate
-	depends on COMEDI
 
 config COMEDI_DAS08
 	tristate
-	depends on COMEDI
 	select COMEDI_8255
+
+config COMEDI_NI_TIO
+	tristate
+
+endif # COMEDI
diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c
index 41a7a62..0a5057f 100644
--- a/drivers/staging/comedi/comedi_compat32.c
+++ b/drivers/staging/comedi/comedi_compat32.c
@@ -26,6 +26,8 @@
 
 #define __NO_VERSION__
 #include <linux/uaccess.h>
+#include <linux/compat.h>
+#include <linux/fs.h>
 #include "comedi.h"
 #include "comedi_compat32.h"
 
diff --git a/drivers/staging/comedi/comedi_compat32.h b/drivers/staging/comedi/comedi_compat32.h
index 0340a89..60cf51c 100644
--- a/drivers/staging/comedi/comedi_compat32.h
+++ b/drivers/staging/comedi/comedi_compat32.h
@@ -27,17 +27,15 @@
 #ifndef _COMEDI_COMPAT32_H
 #define _COMEDI_COMPAT32_H
 
-#include <linux/compat.h>
-#include <linux/fs.h>
-
 #ifdef CONFIG_COMPAT
 
+struct file;
 extern long comedi_compat_ioctl(struct file *file, unsigned int cmd,
 				unsigned long arg);
 
 #else /* CONFIG_COMPAT */
 
-#define comedi_compat_ioctl 0	/* NULL */
+#define comedi_compat_ioctl	NULL
 
 #endif /* CONFIG_COMPAT */
 
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 7677657..e821264 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -24,7 +24,6 @@
 #undef DEBUG
 
 #define __NO_VERSION__
-#include "comedi_fops.h"
 #include "comedi_compat32.h"
 
 #include <linux/module.h>
@@ -49,7 +48,7 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include "internal.h"
+#include "comedi_internal.h"
 
 MODULE_AUTHOR("http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi core module");
@@ -92,36 +91,6 @@ static DEFINE_SPINLOCK(comedi_file_info_table_lock);
 static struct comedi_device_file_info
 *comedi_file_info_table[COMEDI_NUM_MINORS];
 
-static int do_devconfig_ioctl(struct comedi_device *dev,
-			      struct comedi_devconfig __user *arg);
-static int do_bufconfig_ioctl(struct comedi_device *dev,
-			      struct comedi_bufconfig __user *arg);
-static int do_devinfo_ioctl(struct comedi_device *dev,
-			    struct comedi_devinfo __user *arg,
-			    struct file *file);
-static int do_subdinfo_ioctl(struct comedi_device *dev,
-			     struct comedi_subdinfo __user *arg, void *file);
-static int do_chaninfo_ioctl(struct comedi_device *dev,
-			     struct comedi_chaninfo __user *arg);
-static int do_bufinfo_ioctl(struct comedi_device *dev,
-			    struct comedi_bufinfo __user *arg, void *file);
-static int do_cmd_ioctl(struct comedi_device *dev,
-			struct comedi_cmd __user *arg, void *file);
-static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
-			 void *file);
-static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
-			   void *file);
-static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
-			   void *file);
-static int do_cmdtest_ioctl(struct comedi_device *dev,
-			    struct comedi_cmd __user *arg, void *file);
-static int do_insnlist_ioctl(struct comedi_device *dev,
-			     struct comedi_insnlist __user *arg, void *file);
-static int do_insn_ioctl(struct comedi_device *dev,
-			 struct comedi_insn __user *arg, void *file);
-static int do_poll_ioctl(struct comedi_device *dev, unsigned int subd,
-			 void *file);
-
 static void do_become_nonbusy(struct comedi_device *dev,
 			      struct comedi_subdevice *s);
 static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
@@ -172,28 +141,19 @@ static int resize_async_buffer(struct comedi_device *dev,
 
 /* sysfs attribute files */
 
-static const unsigned bytes_per_kibi = 1024;
-
 static ssize_t show_max_read_buffer_kb(struct device *dev,
 				       struct device_attribute *attr, char *buf)
 {
-	ssize_t retval;
 	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned max_buffer_size_kb = 0;
-	struct comedi_subdevice *const read_subdevice =
-	    comedi_get_read_subdevice(info);
+	struct comedi_subdevice *s = comedi_get_read_subdevice(info);
+	unsigned int size = 0;
 
 	mutex_lock(&info->device->mutex);
-	if (read_subdevice &&
-	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
-	    read_subdevice->async) {
-		max_buffer_size_kb = read_subdevice->async->max_bufsize /
-		    bytes_per_kibi;
-	}
-	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
+	if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
+		size = s->async->max_bufsize / 1024;
 	mutex_unlock(&info->device->mutex);
 
-	return retval;
+	return snprintf(buf, PAGE_SIZE, "%i\n", size);
 }
 
 static ssize_t store_max_read_buffer_kb(struct device *dev,
@@ -201,52 +161,40 @@ static ssize_t store_max_read_buffer_kb(struct device *dev,
 					const char *buf, size_t count)
 {
 	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned int new_max_size_kb;
-	unsigned int new_max_size;
-	int ret;
-	struct comedi_subdevice *const read_subdevice =
-	    comedi_get_read_subdevice(info);
-
-	ret = kstrtouint(buf, 10, &new_max_size_kb);
-	if (ret)
-		return ret;
-	if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
+	struct comedi_subdevice *s = comedi_get_read_subdevice(info);
+	unsigned int size;
+	int err;
+
+	err = kstrtouint(buf, 10, &size);
+	if (err)
+		return err;
+	if (size > (UINT_MAX / 1024))
 		return -EINVAL;
-	new_max_size = new_max_size_kb * bytes_per_kibi;
+	size *= 1024;
 
 	mutex_lock(&info->device->mutex);
-	if (read_subdevice == NULL ||
-	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
-	    read_subdevice->async == NULL) {
-		mutex_unlock(&info->device->mutex);
-		return -EINVAL;
-	}
-	read_subdevice->async->max_bufsize = new_max_size;
+	if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
+		s->async->max_bufsize = size;
+	else
+		err = -EINVAL;
 	mutex_unlock(&info->device->mutex);
 
-	return count;
+	return err ? err : count;
 }
 
 static ssize_t show_read_buffer_kb(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
-	ssize_t retval;
 	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned buffer_size_kb = 0;
-	struct comedi_subdevice *const read_subdevice =
-	    comedi_get_read_subdevice(info);
+	struct comedi_subdevice *s = comedi_get_read_subdevice(info);
+	unsigned int size = 0;
 
 	mutex_lock(&info->device->mutex);
-	if (read_subdevice &&
-	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
-	    read_subdevice->async) {
-		buffer_size_kb = read_subdevice->async->prealloc_bufsz /
-		    bytes_per_kibi;
-	}
-	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
+	if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
+		size = s->async->prealloc_bufsz / 1024;
 	mutex_unlock(&info->device->mutex);
 
-	return retval;
+	return snprintf(buf, PAGE_SIZE, "%i\n", size);
 }
 
 static ssize_t store_read_buffer_kb(struct device *dev,
@@ -254,57 +202,41 @@ static ssize_t store_read_buffer_kb(struct device *dev,
 				    const char *buf, size_t count)
 {
 	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned int new_size_kb;
-	unsigned int new_size;
-	int retval;
-	int ret;
-	struct comedi_subdevice *const read_subdevice =
-	    comedi_get_read_subdevice(info);
-
-	ret = kstrtouint(buf, 10, &new_size_kb);
-	if (ret)
-		return ret;
-	if (new_size_kb > (UINT_MAX / bytes_per_kibi))
+	struct comedi_subdevice *s = comedi_get_read_subdevice(info);
+	unsigned int size;
+	int err;
+
+	err = kstrtouint(buf, 10, &size);
+	if (err)
+		return err;
+	if (size > (UINT_MAX / 1024))
 		return -EINVAL;
-	new_size = new_size_kb * bytes_per_kibi;
+	size *= 1024;
 
 	mutex_lock(&info->device->mutex);
-	if (read_subdevice == NULL ||
-	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
-	    read_subdevice->async == NULL) {
-		mutex_unlock(&info->device->mutex);
-		return -EINVAL;
-	}
-	retval = resize_async_buffer(info->device, read_subdevice,
-				     read_subdevice->async, new_size);
+	if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
+		err = resize_async_buffer(info->device, s, s->async, size);
+	else
+		err = -EINVAL;
 	mutex_unlock(&info->device->mutex);
 
-	if (retval < 0)
-		return retval;
-	return count;
+	return err ? err : count;
 }
 
 static ssize_t show_max_write_buffer_kb(struct device *dev,
 					struct device_attribute *attr,
 					char *buf)
 {
-	ssize_t retval;
 	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned max_buffer_size_kb = 0;
-	struct comedi_subdevice *const write_subdevice =
-	    comedi_get_write_subdevice(info);
+	struct comedi_subdevice *s = comedi_get_write_subdevice(info);
+	unsigned int size = 0;
 
 	mutex_lock(&info->device->mutex);
-	if (write_subdevice &&
-	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
-	    write_subdevice->async) {
-		max_buffer_size_kb = write_subdevice->async->max_bufsize /
-		    bytes_per_kibi;
-	}
-	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
+	if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
+		size = s->async->max_bufsize / 1024;
 	mutex_unlock(&info->device->mutex);
 
-	return retval;
+	return snprintf(buf, PAGE_SIZE, "%i\n", size);
 }
 
 static ssize_t store_max_write_buffer_kb(struct device *dev,
@@ -312,52 +244,40 @@ static ssize_t store_max_write_buffer_kb(struct device *dev,
 					 const char *buf, size_t count)
 {
 	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned int new_max_size_kb;
-	unsigned int new_max_size;
-	int ret;
-	struct comedi_subdevice *const write_subdevice =
-	    comedi_get_write_subdevice(info);
-
-	ret = kstrtouint(buf, 10, &new_max_size_kb);
-	if (ret)
-		return ret;
-	if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
+	struct comedi_subdevice *s = comedi_get_write_subdevice(info);
+	unsigned int size;
+	int err;
+
+	err = kstrtouint(buf, 10, &size);
+	if (err)
+		return err;
+	if (size > (UINT_MAX / 1024))
 		return -EINVAL;
-	new_max_size = new_max_size_kb * bytes_per_kibi;
+	size *= 1024;
 
 	mutex_lock(&info->device->mutex);
-	if (write_subdevice == NULL ||
-	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
-	    write_subdevice->async == NULL) {
-		mutex_unlock(&info->device->mutex);
-		return -EINVAL;
-	}
-	write_subdevice->async->max_bufsize = new_max_size;
+	if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
+		s->async->max_bufsize = size;
+	else
+		err = -EINVAL;
 	mutex_unlock(&info->device->mutex);
 
-	return count;
+	return err ? err : count;
 }
 
 static ssize_t show_write_buffer_kb(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 {
-	ssize_t retval;
 	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned buffer_size_kb = 0;
-	struct comedi_subdevice *const write_subdevice =
-	    comedi_get_write_subdevice(info);
+	struct comedi_subdevice *s = comedi_get_write_subdevice(info);
+	unsigned int size = 0;
 
 	mutex_lock(&info->device->mutex);
-	if (write_subdevice &&
-	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
-	    write_subdevice->async) {
-		buffer_size_kb = write_subdevice->async->prealloc_bufsz /
-		    bytes_per_kibi;
-	}
-	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
+	if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
+		size = s->async->prealloc_bufsz / 1024;
 	mutex_unlock(&info->device->mutex);
 
-	return retval;
+	return snprintf(buf, PAGE_SIZE, "%i\n", size);
 }
 
 static ssize_t store_write_buffer_kb(struct device *dev,
@@ -365,34 +285,25 @@ static ssize_t store_write_buffer_kb(struct device *dev,
 				     const char *buf, size_t count)
 {
 	struct comedi_device_file_info *info = dev_get_drvdata(dev);
-	unsigned int new_size_kb;
-	unsigned int new_size;
-	int retval;
-	int ret;
-	struct comedi_subdevice *const write_subdevice =
-	    comedi_get_write_subdevice(info);
-
-	ret = kstrtouint(buf, 10, &new_size_kb);
-	if (ret)
-		return ret;
-	if (new_size_kb > (UINT_MAX / bytes_per_kibi))
+	struct comedi_subdevice *s = comedi_get_write_subdevice(info);
+	unsigned int size;
+	int err;
+
+	err = kstrtouint(buf, 10, &size);
+	if (err)
+		return err;
+	if (size > (UINT_MAX / 1024))
 		return -EINVAL;
-	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
+	size *= 1024;
 
 	mutex_lock(&info->device->mutex);
-	if (write_subdevice == NULL ||
-	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
-	    write_subdevice->async == NULL) {
-		mutex_unlock(&info->device->mutex);
-		return -EINVAL;
-	}
-	retval = resize_async_buffer(info->device, write_subdevice,
-				     write_subdevice->async, new_size);
+	if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
+		err = resize_async_buffer(info->device, s, s->async, size);
+	else
+		err = -EINVAL;
 	mutex_unlock(&info->device->mutex);
 
-	if (retval < 0)
-		return retval;
-	return count;
+	return err ? err : count;
 }
 
 static struct device_attribute comedi_dev_attrs[] = {
@@ -407,98 +318,6 @@ static struct device_attribute comedi_dev_attrs[] = {
 	__ATTR_NULL
 };
 
-static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
-				  unsigned long arg)
-{
-	const unsigned minor = iminor(file->f_dentry->d_inode);
-	struct comedi_device_file_info *dev_file_info =
-	    comedi_get_device_file_info(minor);
-	struct comedi_device *dev;
-	int rc;
-
-	if (dev_file_info == NULL || dev_file_info->device == NULL)
-		return -ENODEV;
-	dev = dev_file_info->device;
-
-	mutex_lock(&dev->mutex);
-
-	/* Device config is special, because it must work on
-	 * an unconfigured device. */
-	if (cmd == COMEDI_DEVCONFIG) {
-		rc = do_devconfig_ioctl(dev,
-					(struct comedi_devconfig __user *)arg);
-		goto done;
-	}
-
-	if (!dev->attached) {
-		DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
-		rc = -ENODEV;
-		goto done;
-	}
-
-	switch (cmd) {
-	case COMEDI_BUFCONFIG:
-		rc = do_bufconfig_ioctl(dev,
-					(struct comedi_bufconfig __user *)arg);
-		break;
-	case COMEDI_DEVINFO:
-		rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
-				      file);
-		break;
-	case COMEDI_SUBDINFO:
-		rc = do_subdinfo_ioctl(dev,
-				       (struct comedi_subdinfo __user *)arg,
-				       file);
-		break;
-	case COMEDI_CHANINFO:
-		rc = do_chaninfo_ioctl(dev, (void __user *)arg);
-		break;
-	case COMEDI_RANGEINFO:
-		rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
-		break;
-	case COMEDI_BUFINFO:
-		rc = do_bufinfo_ioctl(dev,
-				      (struct comedi_bufinfo __user *)arg,
-				      file);
-		break;
-	case COMEDI_LOCK:
-		rc = do_lock_ioctl(dev, arg, file);
-		break;
-	case COMEDI_UNLOCK:
-		rc = do_unlock_ioctl(dev, arg, file);
-		break;
-	case COMEDI_CANCEL:
-		rc = do_cancel_ioctl(dev, arg, file);
-		break;
-	case COMEDI_CMD:
-		rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
-		break;
-	case COMEDI_CMDTEST:
-		rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
-				      file);
-		break;
-	case COMEDI_INSNLIST:
-		rc = do_insnlist_ioctl(dev,
-				       (struct comedi_insnlist __user *)arg,
-				       file);
-		break;
-	case COMEDI_INSN:
-		rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
-				   file);
-		break;
-	case COMEDI_POLL:
-		rc = do_poll_ioctl(dev, arg, file);
-		break;
-	default:
-		rc = -ENOTTY;
-		break;
-	}
-
-done:
-	mutex_unlock(&dev->mutex);
-	return rc;
-}
-
 /*
 	COMEDI_DEVCONFIG
 	device config ioctl
@@ -1709,6 +1528,98 @@ static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
 	return -EINVAL;
 }
 
+static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
+				  unsigned long arg)
+{
+	const unsigned minor = iminor(file->f_dentry->d_inode);
+	struct comedi_device_file_info *dev_file_info =
+	    comedi_get_device_file_info(minor);
+	struct comedi_device *dev;
+	int rc;
+
+	if (dev_file_info == NULL || dev_file_info->device == NULL)
+		return -ENODEV;
+	dev = dev_file_info->device;
+
+	mutex_lock(&dev->mutex);
+
+	/* Device config is special, because it must work on
+	 * an unconfigured device. */
+	if (cmd == COMEDI_DEVCONFIG) {
+		rc = do_devconfig_ioctl(dev,
+					(struct comedi_devconfig __user *)arg);
+		goto done;
+	}
+
+	if (!dev->attached) {
+		DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
+		rc = -ENODEV;
+		goto done;
+	}
+
+	switch (cmd) {
+	case COMEDI_BUFCONFIG:
+		rc = do_bufconfig_ioctl(dev,
+					(struct comedi_bufconfig __user *)arg);
+		break;
+	case COMEDI_DEVINFO:
+		rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
+				      file);
+		break;
+	case COMEDI_SUBDINFO:
+		rc = do_subdinfo_ioctl(dev,
+				       (struct comedi_subdinfo __user *)arg,
+				       file);
+		break;
+	case COMEDI_CHANINFO:
+		rc = do_chaninfo_ioctl(dev, (void __user *)arg);
+		break;
+	case COMEDI_RANGEINFO:
+		rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
+		break;
+	case COMEDI_BUFINFO:
+		rc = do_bufinfo_ioctl(dev,
+				      (struct comedi_bufinfo __user *)arg,
+				      file);
+		break;
+	case COMEDI_LOCK:
+		rc = do_lock_ioctl(dev, arg, file);
+		break;
+	case COMEDI_UNLOCK:
+		rc = do_unlock_ioctl(dev, arg, file);
+		break;
+	case COMEDI_CANCEL:
+		rc = do_cancel_ioctl(dev, arg, file);
+		break;
+	case COMEDI_CMD:
+		rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
+		break;
+	case COMEDI_CMDTEST:
+		rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
+				      file);
+		break;
+	case COMEDI_INSNLIST:
+		rc = do_insnlist_ioctl(dev,
+				       (struct comedi_insnlist __user *)arg,
+				       file);
+		break;
+	case COMEDI_INSN:
+		rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
+				   file);
+		break;
+	case COMEDI_POLL:
+		rc = do_poll_ioctl(dev, arg, file);
+		break;
+	default:
+		rc = -ENOTTY;
+		break;
+	}
+
+done:
+	mutex_unlock(&dev->mutex);
+	return rc;
+}
+
 static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	int ret = 0;
@@ -2270,7 +2181,7 @@ static int comedi_fasync(int fd, struct file *file, int on)
 	return fasync_helper(fd, file, on, &dev->async_queue);
 }
 
-const struct file_operations comedi_fops = {
+static const struct file_operations comedi_fops = {
 	.owner = THIS_MODULE,
 	.unlocked_ioctl = comedi_unlocked_ioctl,
 	.compat_ioctl = comedi_compat_ioctl,
@@ -2284,7 +2195,7 @@ const struct file_operations comedi_fops = {
 	.llseek = noop_llseek,
 };
 
-struct class *comedi_class;
+static struct class *comedi_class;
 static struct cdev comedi_cdev;
 
 static void comedi_cleanup_legacy_minors(void)
diff --git a/drivers/staging/comedi/comedi_fops.h b/drivers/staging/comedi/comedi_fops.h
deleted file mode 100644
index 006cf14..0000000
--- a/drivers/staging/comedi/comedi_fops.h
+++ /dev/null
@@ -1,11 +0,0 @@
-
-#ifndef _COMEDI_FOPS_H
-#define _COMEDI_FOPS_H
-#include <linux/types.h>
-
-extern struct class *comedi_class;
-extern const struct file_operations comedi_fops;
-extern bool comedi_autoconfig;
-extern struct comedi_driver *comedi_drivers;
-
-#endif /* _COMEDI_FOPS_H */
diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/staging/comedi/comedi_internal.h
new file mode 100644
index 0000000..e70ef051
--- /dev/null
+++ b/drivers/staging/comedi/comedi_internal.h
@@ -0,0 +1,25 @@
+#ifndef _COMEDI_INTERNAL_H
+#define _COMEDI_INTERNAL_H
+
+#include <linux/types.h>
+
+/*
+ * various internal comedi stuff
+ */
+int do_rangeinfo_ioctl(struct comedi_device *dev,
+		       struct comedi_rangeinfo __user *arg);
+int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
+	       struct comedi_insn *insn, unsigned int *data);
+int comedi_alloc_board_minor(struct device *hardware_device);
+void comedi_free_board_minor(unsigned minor);
+int comedi_find_board_minor(struct device *hardware_device);
+void comedi_reset_async_buf(struct comedi_async *async);
+int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
+		     unsigned long new_size);
+
+extern unsigned int comedi_default_buf_size_kb;
+extern unsigned int comedi_default_buf_maxsize_kb;
+extern bool comedi_autoconfig;
+extern struct comedi_driver *comedi_drivers;
+
+#endif /* _COMEDI_INTERNAL_H */
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index 134be93..de8c99c 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -40,6 +40,7 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/timer.h>
+#include <linux/pci.h>
 
 #include "comedi.h"
 
@@ -77,7 +78,7 @@ struct comedi_subdevice {
 	unsigned runflags;
 	spinlock_t spin_lock;
 
-	int io_bits;
+	unsigned int io_bits;
 
 	unsigned int maxdata;	/* if maxdata==0, use list */
 	const unsigned int *maxdata_list;	/* list is channel specific */
@@ -180,7 +181,6 @@ struct comedi_async {
 			unsigned int x);
 };
 
-struct pci_dev;
 struct usb_interface;
 
 struct comedi_driver {
@@ -292,6 +292,8 @@ static inline struct comedi_subdevice *comedi_get_write_subdevice(
 	return info->device->write_subdev;
 }
 
+int comedi_alloc_subdevices(struct comedi_device *, int);
+
 void comedi_device_detach(struct comedi_device *dev);
 int comedi_device_attach(struct comedi_device *dev,
 			 struct comedi_devconfig *it);
@@ -310,7 +312,8 @@ int comedi_driver_unregister(struct comedi_driver *);
 	module_driver(__comedi_driver, comedi_driver_register, \
 			comedi_driver_unregister)
 
-struct pci_driver;
+int comedi_pci_enable(struct pci_dev *, const char *);
+void comedi_pci_disable(struct pci_dev *);
 
 int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *);
 void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *);
@@ -412,26 +415,6 @@ struct comedi_lrange {
 
 /* some silly little inline functions */
 
-static inline int alloc_subdevices(struct comedi_device *dev,
-				   unsigned int num_subdevices)
-{
-	unsigned i;
-
-	dev->n_subdevices = num_subdevices;
-	dev->subdevices =
-	    kcalloc(num_subdevices, sizeof(struct comedi_subdevice),
-		    GFP_KERNEL);
-	if (!dev->subdevices)
-		return -ENOMEM;
-	for (i = 0; i < num_subdevices; ++i) {
-		dev->subdevices[i].device = dev;
-		dev->subdevices[i].async_dma_dir = DMA_NONE;
-		spin_lock_init(&dev->subdevices[i].spin_lock);
-		dev->subdevices[i].minor = -1;
-	}
-	return 0;
-}
-
 static inline int alloc_private(struct comedi_device *dev, int size)
 {
 	dev->private = kzalloc(size, GFP_KERNEL);
@@ -524,17 +507,4 @@ int comedi_usb_auto_config(struct usb_interface *intf,
 			   struct comedi_driver *driver);
 void comedi_usb_auto_unconfig(struct usb_interface *intf);
 
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
-#define CONFIG_COMEDI_PCI
-#endif
-#ifdef CONFIG_COMEDI_PCI_DRIVERS_MODULE
-#define CONFIG_COMEDI_PCI
-#endif
-#ifdef CONFIG_COMEDI_PCMCIA_DRIVERS
-#define CONFIG_COMEDI_PCMCIA
-#endif
-#ifdef CONFIG_COMEDI_PCMCIA_DRIVERS_MODULE
-#define CONFIG_COMEDI_PCMCIA
-#endif
-
 #endif /* _COMEDIDEV_H */
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index aeac1ca..c0fdb00 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -24,7 +24,6 @@
 #define _GNU_SOURCE
 
 #define __NO_VERSION__
-#include "comedi_fops.h"
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -45,7 +44,7 @@
 #include <linux/io.h>
 
 #include "comedidev.h"
-#include "internal.h"
+#include "comedi_internal.h"
 
 static int postconfig(struct comedi_device *dev);
 static int insn_rw_emulate_bits(struct comedi_device *dev,
@@ -57,6 +56,31 @@ static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s);
 
 struct comedi_driver *comedi_drivers;
 
+int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices)
+{
+	struct comedi_subdevice *s;
+	int i;
+
+	if (num_subdevices < 1)
+		return -EINVAL;
+
+	s = kcalloc(num_subdevices, sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
+	dev->subdevices = s;
+	dev->n_subdevices = num_subdevices;
+
+	for (i = 0; i < num_subdevices; ++i) {
+		s = dev->subdevices + i;
+		s->device = dev;
+		s->async_dma_dir = DMA_NONE;
+		spin_lock_init(&s->spin_lock);
+		s->minor = -1;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(comedi_alloc_subdevices);
+
 static void cleanup_device(struct comedi_device *dev)
 {
 	int i;
@@ -301,18 +325,41 @@ static int postconfig(struct comedi_device *dev)
 	return 0;
 }
 
-/* generic recognize function for drivers
- * that register their supported board names */
+/*
+ * Generic recognize function for drivers that register their supported
+ * board names.
+ *
+ * 'driv->board_name' points to a 'const char *' member within the
+ * zeroth element of an array of some private board information
+ * structure, say 'struct foo_board' containing a member 'const char
+ * *board_name' that is initialized to point to a board name string that
+ * is one of the candidates matched against this function's 'name'
+ * parameter.
+ *
+ * 'driv->offset' is the size of the private board information
+ * structure, say 'sizeof(struct foo_board)', and 'driv->num_names' is
+ * the length of the array of private board information structures.
+ *
+ * If one of the board names in the array of private board information
+ * structures matches the name supplied to this function, the function
+ * returns a pointer to the pointer to the board name, otherwise it
+ * returns NULL.  The return value ends up in the 'board_ptr' member of
+ * a 'struct comedi_device' that the low-level comedi driver's
+ * 'attach()' hook can convert to a point to a particular element of its
+ * array of private board information structures by subtracting the
+ * offset of the member that points to the board name.  (No subtraction
+ * is required if the board name pointer is the first member of the
+ * private board information structure, which is generally the case.)
+ */
 static void *comedi_recognize(struct comedi_driver *driv, const char *name)
 {
-	unsigned i;
-	const char *const *name_ptr = driv->board_name;
+	char **name_ptr = (char **)driv->board_name;
+	int i;
+
 	for (i = 0; i < driv->num_names; i++) {
 		if (strcmp(*name_ptr, name) == 0)
-			return (void *)name_ptr;
-		name_ptr =
-		    (const char *const *)((const char *)name_ptr +
-					  driv->offset);
+			return name_ptr;
+		name_ptr = (void *)name_ptr + driv->offset;
 	}
 
 	return NULL;
@@ -385,39 +432,6 @@ static int insn_rw_emulate_bits(struct comedi_device *dev,
 	return 1;
 }
 
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-	unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-	pud_t *pud;
-
-	if (!pgd_none(*pgd)) {
-		pud = pud_offset(pgd, adr);
-		pmd = pmd_offset(pud, adr);
-		if (!pmd_none(*pmd)) {
-			ptep = pte_offset_kernel(pmd, adr);
-			pte = *ptep;
-			if (pte_present(pte)) {
-				ret = (unsigned long)
-				    page_address(pte_page(pte));
-				ret |= (adr & (PAGE_SIZE - 1));
-			}
-		}
-	}
-	return ret;
-}
-
-static inline unsigned long kvirt_to_kva(unsigned long adr)
-{
-	unsigned long va, kva;
-
-	va = adr;
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
-
-	return kva;
-}
-
 int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
 		     unsigned long new_size)
 {
@@ -909,6 +923,40 @@ static void comedi_auto_unconfig(struct device *hardware_device)
 	comedi_free_board_minor(minor);
 }
 
+/**
+ * comedi_pci_enable() - Enable the PCI device and request the regions.
+ * @pdev: pci_dev struct
+ * @res_name: name for the requested reqource
+ */
+int comedi_pci_enable(struct pci_dev *pdev, const char *res_name)
+{
+	int rc;
+
+	rc = pci_enable_device(pdev);
+	if (rc < 0)
+		return rc;
+
+	rc = pci_request_regions(pdev, res_name);
+	if (rc < 0)
+		pci_disable_device(pdev);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(comedi_pci_enable);
+
+/**
+ * comedi_pci_disable() - Release the regions and disable the PCI device.
+ * @pdev: pci_dev struct
+ *
+ * This must be matched with a previous successful call to comedi_pci_enable().
+ */
+void comedi_pci_disable(struct pci_dev *pdev)
+{
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+EXPORT_SYMBOL_GPL(comedi_pci_disable);
+
 static int comedi_old_pci_auto_config(struct pci_dev *pcidev,
 				      struct comedi_driver *driver)
 {
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index 27e39e4..4c9977b 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -60,15 +60,15 @@ I/O port base address can be found in the output of 'lspci -v'.
    set up the subdevice in the attach function of the driver by
    calling:
 
-     subdev_8255_init(device, subdevice, callback_function, arg)
+     subdev_8255_init(device, subdevice, io_function, iobase)
 
    device and subdevice are pointers to the device and subdevice
-   structures.  callback_function will be called to provide the
+   structures.  io_function will be called to provide the
    low-level input/output to the device, i.e., actual register
-   access.  callback_function will be called with the value of arg
+   access.  io_function will be called with the value of iobase
    as the last parameter.  If the 8255 device is mapped as 4
-   consecutive I/O ports, you can use NULL for callback_function
-   and the I/O port base for arg, and an internal function will
+   consecutive I/O ports, you can use NULL for io_function
+   and the I/O port base for iobase, and an internal function will
    handle the register access.
 
    In addition, if the main driver handles interrupts, you can
@@ -84,10 +84,10 @@ I/O port base address can be found in the output of 'lspci -v'.
 #include <linux/slab.h>
 #include "8255.h"
 
-#define _8255_SIZE 4
+#define _8255_SIZE	4
 
-#define _8255_DATA 0
-#define _8255_CR 3
+#define _8255_DATA	0
+#define _8255_CR	3
 
 #define CR_C_LO_IO	0x01
 #define CR_B_IO		0x02
@@ -97,23 +97,30 @@ I/O port base address can be found in the output of 'lspci -v'.
 #define CR_A_MODE(a)	((a)<<5)
 #define CR_CW		0x80
 
-struct subdev_8255_struct {
-	unsigned long cb_arg;
-	int (*cb_func) (int, int, int, unsigned long);
-	int have_irq;
+struct subdev_8255_private {
+	unsigned long iobase;
+	int (*io) (int, int, int, unsigned long);
 };
 
-#define CALLBACK_ARG	(((struct subdev_8255_struct *)s->private)->cb_arg)
-#define CALLBACK_FUNC	(((struct subdev_8255_struct *)s->private)->cb_func)
-#define subdevpriv	((struct subdev_8255_struct *)s->private)
+static int subdev_8255_io(int dir, int port, int data, unsigned long iobase)
+{
+	if (dir) {
+		outb(data, iobase + port);
+		return 0;
+	} else {
+		return inb(iobase + port);
+	}
+}
 
 void subdev_8255_interrupt(struct comedi_device *dev,
 			   struct comedi_subdevice *s)
 {
+	struct subdev_8255_private *spriv = s->private;
+	unsigned long iobase = spriv->iobase;
 	short d;
 
-	d = CALLBACK_FUNC(0, _8255_DATA, 0, CALLBACK_ARG);
-	d |= (CALLBACK_FUNC(0, _8255_DATA + 1, 0, CALLBACK_ARG) << 8);
+	d = spriv->io(0, _8255_DATA, 0, iobase);
+	d |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8);
 
 	comedi_buf_put(s->async, d);
 	s->async->events |= COMEDI_CB_EOS;
@@ -122,46 +129,48 @@ void subdev_8255_interrupt(struct comedi_device *dev,
 }
 EXPORT_SYMBOL(subdev_8255_interrupt);
 
-static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
-{
-	unsigned long iobase = arg;
-
-	if (dir) {
-		outb(data, iobase + port);
-		return 0;
-	} else {
-		return inb(iobase + port);
-	}
-}
-
 static int subdev_8255_insn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
 {
-	if (data[0]) {
-		s->state &= ~data[0];
-		s->state |= (data[0] & data[1]);
-
-		if (data[0] & 0xff)
-			CALLBACK_FUNC(1, _8255_DATA, s->state & 0xff,
-				      CALLBACK_ARG);
-		if (data[0] & 0xff00)
-			CALLBACK_FUNC(1, _8255_DATA + 1, (s->state >> 8) & 0xff,
-				      CALLBACK_ARG);
-		if (data[0] & 0xff0000)
-			CALLBACK_FUNC(1, _8255_DATA + 2,
-				      (s->state >> 16) & 0xff, CALLBACK_ARG);
+	struct subdev_8255_private *spriv = s->private;
+	unsigned long iobase = spriv->iobase;
+	unsigned int mask;
+	unsigned int bits;
+	unsigned int v;
+
+	mask = data[0];
+	bits = data[1];
+
+	if (mask) {
+		v = s->state;
+		v &= ~mask;
+		v |= (bits & mask);
+
+		if (mask & 0xff)
+			spriv->io(1, _8255_DATA, v & 0xff, iobase);
+		if (mask & 0xff00)
+			spriv->io(1, _8255_DATA + 1, (v >> 8) & 0xff, iobase);
+		if (mask & 0xff0000)
+			spriv->io(1, _8255_DATA + 2, (v >> 16) & 0xff, iobase);
+
+		s->state = v;
 	}
 
-	data[1] = CALLBACK_FUNC(0, _8255_DATA, 0, CALLBACK_ARG);
-	data[1] |= (CALLBACK_FUNC(0, _8255_DATA + 1, 0, CALLBACK_ARG) << 8);
-	data[1] |= (CALLBACK_FUNC(0, _8255_DATA + 2, 0, CALLBACK_ARG) << 16);
+	v = spriv->io(0, _8255_DATA, 0, iobase);
+	v |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8);
+	v |= (spriv->io(0, _8255_DATA + 2, 0, iobase) << 16);
+
+	data[1] = v;
 
-	return 2;
+	return insn->n;
 }
 
-static void do_config(struct comedi_device *dev, struct comedi_subdevice *s)
+static void subdev_8255_do_config(struct comedi_device *dev,
+				  struct comedi_subdevice *s)
 {
+	struct subdev_8255_private *spriv = s->private;
+	unsigned long iobase = spriv->iobase;
 	int config;
 
 	config = CR_CW;
@@ -174,7 +183,8 @@ static void do_config(struct comedi_device *dev, struct comedi_subdevice *s)
 		config |= CR_C_LO_IO;
 	if (!(s->io_bits & 0xf00000))
 		config |= CR_C_HI_IO;
-	CALLBACK_FUNC(1, _8255_CR, config, CALLBACK_ARG);
+
+	spriv->io(1, _8255_CR, config, iobase);
 }
 
 static int subdev_8255_insn_config(struct comedi_device *dev,
@@ -209,7 +219,7 @@ static int subdev_8255_insn_config(struct comedi_device *dev,
 		return -EINVAL;
 	}
 
-	do_config(dev, s);
+	subdev_8255_do_config(dev, s);
 
 	return 1;
 }
@@ -307,50 +317,50 @@ static int subdev_8255_cancel(struct comedi_device *dev,
 }
 
 int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
-		     int (*cb) (int, int, int, unsigned long),
-		     unsigned long arg)
+		     int (*io) (int, int, int, unsigned long),
+		     unsigned long iobase)
 {
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 24;
-	s->range_table = &range_digital;
-	s->maxdata = 1;
-
-	s->private = kmalloc(sizeof(struct subdev_8255_struct), GFP_KERNEL);
-	if (!s->private)
+	struct subdev_8255_private *spriv;
+
+	spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
+	if (!spriv)
 		return -ENOMEM;
 
-	CALLBACK_ARG = arg;
-	if (cb == NULL)
-		CALLBACK_FUNC = subdev_8255_cb;
-	else
-		CALLBACK_FUNC = cb;
-	s->insn_bits = subdev_8255_insn;
-	s->insn_config = subdev_8255_insn_config;
+	spriv->iobase	= iobase;
+	spriv->io	= io ? io : subdev_8255_io;
+
+	s->private	= spriv;
+
+	s->type		= COMEDI_SUBD_DIO;
+	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
+	s->n_chan	= 24;
+	s->range_table	= &range_digital;
+	s->maxdata	= 1;
+	s->insn_bits	= subdev_8255_insn;
+	s->insn_config	= subdev_8255_insn_config;
 
-	s->state = 0;
-	s->io_bits = 0;
-	do_config(dev, s);
+	s->state	= 0;
+	s->io_bits	= 0;
+
+	subdev_8255_do_config(dev, s);
 
 	return 0;
 }
 EXPORT_SYMBOL(subdev_8255_init);
 
 int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
-			 int (*cb) (int, int, int, unsigned long),
-			 unsigned long arg)
+			 int (*io) (int, int, int, unsigned long),
+			 unsigned long iobase)
 {
 	int ret;
 
-	ret = subdev_8255_init(dev, s, cb, arg);
-	if (ret < 0)
+	ret = subdev_8255_init(dev, s, io, iobase);
+	if (ret)
 		return ret;
 
-	s->do_cmdtest = subdev_8255_cmdtest;
-	s->do_cmd = subdev_8255_cmd;
-	s->cancel = subdev_8255_cancel;
-
-	subdevpriv->have_irq = 1;
+	s->do_cmdtest	= subdev_8255_cmdtest;
+	s->do_cmd	= subdev_8255_cmd;
+	s->cancel	= subdev_8255_cancel;
 
 	return 0;
 }
@@ -371,6 +381,7 @@ EXPORT_SYMBOL(subdev_8255_cleanup);
 static int dev_8255_attach(struct comedi_device *dev,
 			   struct comedi_devconfig *it)
 {
+	struct comedi_subdevice *s;
 	int ret;
 	unsigned long iobase;
 	int i;
@@ -383,51 +394,45 @@ static int dev_8255_attach(struct comedi_device *dev,
 			break;
 	}
 	if (i == 0) {
-		printk(KERN_WARNING
-		       "comedi%d: 8255: no devices specified\n", dev->minor);
+		dev_warn(dev->class_dev, "no devices specified\n");
 		return -EINVAL;
 	}
 
-	ret = alloc_subdevices(dev, i);
-	if (ret < 0) {
-		/* FIXME this printk call should give a proper message, the
-		 * below line just maintains previous functionality */
-		printk("comedi%d: 8255:", dev->minor);
+	ret = comedi_alloc_subdevices(dev, i);
+	if (ret)
 		return ret;
-	}
-
-	printk(KERN_INFO "comedi%d: 8255:", dev->minor);
 
 	for (i = 0; i < dev->n_subdevices; i++) {
+		s = dev->subdevices + i;
 		iobase = it->options[i];
 
-		printk(" 0x%04lx", iobase);
 		if (!request_region(iobase, _8255_SIZE, "8255")) {
-			printk(" (I/O port conflict)");
+			dev_warn(dev->class_dev,
+				"0x%04lx (I/O port conflict)\n", iobase);
 
-			dev->subdevices[i].type = COMEDI_SUBD_UNUSED;
+			s->type = COMEDI_SUBD_UNUSED;
 		} else {
-			subdev_8255_init(dev, dev->subdevices + i, NULL,
-					 iobase);
+			ret = subdev_8255_init(dev, s, NULL, iobase);
+			if (ret)
+				return ret;
+			dev_info(dev->class_dev, "0x%04lx\n", iobase);
 		}
 	}
 
-	printk("\n");
-
 	return 0;
 }
 
 static void dev_8255_detach(struct comedi_device *dev)
 {
-	int i;
-	unsigned long iobase;
 	struct comedi_subdevice *s;
+	struct subdev_8255_private *spriv;
+	int i;
 
 	for (i = 0; i < dev->n_subdevices; i++) {
 		s = dev->subdevices + i;
 		if (s->type != COMEDI_SUBD_UNUSED) {
-			iobase = CALLBACK_ARG;
-			release_region(iobase, _8255_SIZE);
+			spriv = s->private;
+			release_region(spriv->iobase, _8255_SIZE);
 		}
 		subdev_8255_cleanup(dev, s);
 	}
diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h
index b6314c9..1e589b4 100644
--- a/drivers/staging/comedi/drivers/8255.h
+++ b/drivers/staging/comedi/drivers/8255.h
@@ -27,11 +27,11 @@
 #include "../comedidev.h"
 
 int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
-		     int (*cb) (int, int, int, unsigned long),
-		     unsigned long arg);
+		     int (*io) (int, int, int, unsigned long),
+		     unsigned long iobase);
 int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
-			 int (*cb) (int, int, int, unsigned long),
-			 unsigned long arg);
+			 int (*io) (int, int, int, unsigned long),
+			 unsigned long iobase);
 void subdev_8255_cleanup(struct comedi_device *dev, struct comedi_subdevice *s);
 void subdev_8255_interrupt(struct comedi_device *dev,
 			   struct comedi_subdevice *s);
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index 170da60..57b19e4 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -55,7 +55,6 @@ obj-$(CONFIG_COMEDI_MULTIQ3)		+= multiq3.o
 obj-$(CONFIG_COMEDI_POC)		+= poc.o
 
 # Comedi PCI drivers
-obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= 8255.o
 obj-$(CONFIG_COMEDI_ADDI_APCI_035)	+= addi_apci_035.o
 obj-$(CONFIG_COMEDI_ADDI_APCI_1032)	+= addi_apci_1032.o
 obj-$(CONFIG_COMEDI_ADDI_APCI_1500)	+= addi_apci_1500.o
@@ -132,7 +131,7 @@ obj-$(CONFIG_COMEDI_VMK80XX)		+= vmk80xx.o
 # Comedi NI drivers
 obj-$(CONFIG_COMEDI_MITE)		+= mite.o
 obj-$(CONFIG_COMEDI_NI_TIO)		+= ni_tio.o
-obj-$(CONFIG_COMEDI_NI_TIO)		+= ni_tiocmd.o
+obj-$(CONFIG_COMEDI_NI_TIOCMD)		+= ni_tiocmd.o
 obj-$(CONFIG_COMEDI_NI_LABPC)		+= ni_labpc.o
 
 obj-$(CONFIG_COMEDI_8255)		+= 8255.o
diff --git a/drivers/staging/comedi/drivers/acl7225b.c b/drivers/staging/comedi/drivers/acl7225b.c
index 4e4fc41..ddba5db 100644
--- a/drivers/staging/comedi/drivers/acl7225b.c
+++ b/drivers/staging/comedi/drivers/acl7225b.c
@@ -27,15 +27,10 @@ struct boardtype {
 	int io_range;		/*  len of I/O space */
 };
 
-#define this_board ((const struct boardtype *)dev->board_ptr)
-
 static int acl7225b_do_insn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] & data[1]);
@@ -48,43 +43,43 @@ static int acl7225b_do_insn(struct comedi_device *dev,
 
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 static int acl7225b_di_insn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = inb(dev->iobase + (unsigned long)s->private) |
 	    (inb(dev->iobase + (unsigned long)s->private + 1) << 8);
 
-	return 2;
+	return insn->n;
 }
 
 static int acl7225b_attach(struct comedi_device *dev,
 			   struct comedi_devconfig *it)
 {
+	const struct boardtype *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	int iobase, iorange;
+	int ret;
 
 	iobase = it->options[0];
-	iorange = this_board->io_range;
+	iorange = board->io_range;
 	printk(KERN_INFO "comedi%d: acl7225b: board=%s 0x%04x\n", dev->minor,
-	       this_board->name, iobase);
+	       board->name, iobase);
 	if (!request_region(iobase, iorange, "acl7225b")) {
 		printk(KERN_ERR "comedi%d: request_region failed - I/O port conflict\n",
 			dev->minor);
 		return -EIO;
 	}
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 	dev->iobase = iobase;
 	dev->irq = 0;
 
-	if (alloc_subdevices(dev, 3) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* Relays outputs */
@@ -121,8 +116,10 @@ static int acl7225b_attach(struct comedi_device *dev,
 
 static void acl7225b_detach(struct comedi_device *dev)
 {
+	const struct boardtype *board = comedi_board(dev);
+
 	if (dev->iobase)
-		release_region(dev->iobase, this_board->io_range);
+		release_region(dev->iobase, board->io_range);
 }
 
 static const struct boardtype boardtypes[] = {
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h b/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h
index 35a3ea1..95f7dc6 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h
+++ b/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h
@@ -22,12 +22,6 @@
 
 #include "../../comedidev.h"
 
-#include "../comedi_pci.h"
-
-#ifdef PCI_SUPPORT_VER1
-#error     No support for 2.1.55 and older
-#endif
-
 /* written on base0 */
 #define FIFO_ADVANCE_ON_BYTE_2	0x20000000
 
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index 44aaf83..a5aa673 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -1686,10 +1686,9 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		devpriv->s_BoardInfos.ui_Address = io_addr[2];
 #endif
 	} else {
-		/* Update-0.7.57->0.7.68dev->n_subdevices = 7; */
 		n_subdevices = 7;
-		ret = alloc_subdevices(dev, n_subdevices);
-		if (ret < 0)
+		ret = comedi_alloc_subdevices(dev, n_subdevices);
+		if (ret)
 			return ret;
 
 		/*  Allocate and Initialise AI Subdevice Structures */
diff --git a/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h b/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h
index 349e93c..c26c28c 100644
--- a/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h
+++ b/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h
@@ -23,10 +23,6 @@
 #include <linux/pci.h>
 #include "../../comedidev.h"
 
-#ifdef PCI_SUPPORT_VER1
-#error    Sorry, no support for 2.1.55 and older! :-((((
-#endif
-
 /***********Added by sarath for compatibility with APCI3120
 
 *************************/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
index a76ed25..595238f 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
@@ -62,9 +62,8 @@ void i_ADDI_AttachPCI1710(struct comedi_device *dev)
 	int ret = 0;
 	int n_subdevices = 9;
 
-	/* Update-0.7.57->0.7.68dev->n_subdevices = 9; */
-	ret = alloc_subdevices(dev, n_subdevices);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	if (ret)
 		return;
 
 	/*  Allocate and Initialise Timer Subdevice Structures */
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index de8c68a..79f6765 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -52,7 +52,6 @@ References:
  * options that are used with comedi_config.
  */
 #include "../comedidev.h"
-#include "comedi_pci.h"
 
 /* Board descriptions */
 struct pci6208_board {
@@ -142,8 +141,6 @@ static int pci6208_ao_rinsn(struct comedi_device *dev,
  *					struct comedi_subdevice *s, */
 /* struct comedi_insn *insn,unsigned int *data) */
 /* { */
-/* if(insn->n!=2)return -EINVAL; */
-
 	/* The insn data is a mask in data[0] and the new data
 	 * in data[1], each channel cooresponding to a bit. */
 /* if(data[0]){ */
@@ -160,7 +157,7 @@ static int pci6208_ao_rinsn(struct comedi_device *dev,
 	 * it was a purely digital output subdevice */
 	/* data[1]=s->state; */
 
-/* return 2; */
+/* return insn->n; */
 /* } */
 
 /* static int pci6208_dio_insn_config(struct comedi_device *dev,
@@ -302,8 +299,9 @@ static int pci6208_attach(struct comedi_device *dev,
 	dev->iobase = io_base;
 	dev->board_name = thisboard->name;
 
-	if (alloc_subdevices(dev, 2) < 0)
-		return -ENOMEM;
+	retval = comedi_alloc_subdevices(dev, 2);
+	if (retval)
+		return retval;
 
 	s = dev->subdevices + 0;
 	/* analog output subdevice */
diff --git a/drivers/staging/comedi/drivers/adl_pci7230.c b/drivers/staging/comedi/drivers/adl_pci7230.c
index e8053bc..cfb8bb0 100644
--- a/drivers/staging/comedi/drivers/adl_pci7230.c
+++ b/drivers/staging/comedi/drivers/adl_pci7230.c
@@ -36,7 +36,6 @@ Configuration Options:
 
 #include "../comedidev.h"
 #include <linux/kernel.h>
-#include "comedi_pci.h"
 
 #define PCI7230_DI      0x00
 #define PCI7230_DO	    0x00
@@ -55,9 +54,6 @@ static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
 	struct comedi_insn *insn,
 	unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] & data[1]);
@@ -65,7 +61,7 @@ static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
 		outl((s->state  << 16) & 0xffffffff, dev->iobase + PCI7230_DO);
 	}
 
-	return 2;
+	return insn->n;
 }
 
 static int adl_pci7230_di_insn_bits(struct comedi_device *dev,
@@ -73,58 +69,62 @@ static int adl_pci7230_di_insn_bits(struct comedi_device *dev,
 	struct comedi_insn *insn,
 	unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff;
 
-	return 2;
+	return insn->n;
 }
 
-static int adl_pci7230_attach(struct comedi_device *dev,
+static struct pci_dev *adl_pci7230_find_pci(struct comedi_device *dev,
 	struct comedi_devconfig *it)
 {
 	struct pci_dev *pcidev = NULL;
+	int bus = it->options[0];
+	int slot = it->options[1];
+
+	for_each_pci_dev(pcidev) {
+		if (pcidev->vendor != PCI_VENDOR_ID_ADLINK ||
+		    pcidev->device != PCI_DEVICE_ID_PCI7230)
+			continue;
+		if (bus || slot) {
+			/* requested particular bus/slot */
+			if (pcidev->bus->number != bus ||
+			    PCI_SLOT(pcidev->devfn) != slot)
+				continue;
+		}
+		return pcidev;
+	}
+	printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
+		dev->minor, bus, slot);
+	return NULL;
+}
+
+static int adl_pci7230_attach(struct comedi_device *dev,
+	struct comedi_devconfig *it)
+{
 	struct comedi_subdevice *s;
-	int bus, slot;
+	int ret;
 
 	printk(KERN_INFO "comedi%d: adl_pci7230\n", dev->minor);
 
 	dev->board_name = "pci7230";
-	bus = it->options[0];
-	slot = it->options[1];
 
 	if (alloc_private(dev, sizeof(struct adl_pci7230_private)) < 0)
 		return -ENOMEM;
 
-	if (alloc_subdevices(dev, 2) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 2);
+	if (ret)
+		return ret;
 
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
-			pcidev->device == PCI_DEVICE_ID_PCI7230) {
-			if (bus || slot) {
-				/* requested particular bus/slot */
-				if (pcidev->bus->number != bus ||
-					PCI_SLOT(pcidev->devfn) != slot) {
-					continue;
-				}
-			}
-			devpriv->pci_dev = pcidev;
-			break;
-		}
-	}
-	if (pcidev == NULL) {
-		printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-			dev->minor, bus, slot);
+	devpriv->pci_dev = adl_pci7230_find_pci(dev, it);
+	if (!devpriv->pci_dev)
 		return -EIO;
-	}
-	if (comedi_pci_enable(pcidev, "adl_pci7230") < 0) {
+
+	if (comedi_pci_enable(devpriv->pci_dev, "adl_pci7230") < 0) {
 		printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n",
 			dev->minor);
 		return -EIO;
 	}
-	dev->iobase = pci_resource_start(pcidev, 2);
+	dev->iobase = pci_resource_start(devpriv->pci_dev, 2);
 	printk(KERN_DEBUG "comedi: base addr %4lx\n", dev->iobase);
 
 	s = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/adl_pci7296.c b/drivers/staging/comedi/drivers/adl_pci7296.c
index b4dae3b..58deb60 100644
--- a/drivers/staging/comedi/drivers/adl_pci7296.c
+++ b/drivers/staging/comedi/drivers/adl_pci7296.c
@@ -37,7 +37,6 @@ Configuration Options:
 #include "../comedidev.h"
 #include <linux/kernel.h>
 
-#include "comedi_pci.h"
 #include "8255.h"
 /* #include "8253.h" */
 
@@ -55,83 +54,87 @@ struct adl_pci7296_private {
 
 #define devpriv ((struct adl_pci7296_private *)dev->private)
 
+static struct pci_dev *adl_pci7296_find_pci(struct comedi_device *dev,
+					    struct comedi_devconfig *it)
+{
+	struct pci_dev *pcidev = NULL;
+	int bus = it->options[0];
+	int slot = it->options[1];
+
+	for_each_pci_dev(pcidev) {
+		if (pcidev->vendor != PCI_VENDOR_ID_ADLINK ||
+		    pcidev->device != PCI_DEVICE_ID_PCI7296)
+			continue;
+		if (bus || slot) {
+			/* requested particular bus/slot */
+			if (pcidev->bus->number != bus ||
+			    PCI_SLOT(pcidev->devfn) != slot)
+				continue;
+		}
+		return pcidev;
+	}
+	printk(KERN_ERR
+		"comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
+	       dev->minor, bus, slot);
+	return NULL;
+}
+
 static int adl_pci7296_attach(struct comedi_device *dev,
 			      struct comedi_devconfig *it)
 {
-	struct pci_dev *pcidev = NULL;
 	struct comedi_subdevice *s;
-	int bus, slot;
 	int ret;
 
 	printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor);
 
 	dev->board_name = "pci7432";
-	bus = it->options[0];
-	slot = it->options[1];
 
 	if (alloc_private(dev, sizeof(struct adl_pci7296_private)) < 0)
 		return -ENOMEM;
 
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
+		return ret;
 
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
-		    pcidev->device == PCI_DEVICE_ID_PCI7296) {
-			if (bus || slot) {
-				/* requested particular bus/slot */
-				if (pcidev->bus->number != bus
-				    || PCI_SLOT(pcidev->devfn) != slot) {
-					continue;
-				}
-			}
-			devpriv->pci_dev = pcidev;
-			if (comedi_pci_enable(pcidev, "adl_pci7296") < 0) {
-				printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n",
-				     dev->minor);
-				return -EIO;
-			}
-
-			dev->iobase = pci_resource_start(pcidev, 2);
-			printk(KERN_INFO "comedi: base addr %4lx\n",
-				dev->iobase);
-
-			/*  four 8255 digital io subdevices */
-			s = dev->subdevices + 0;
-			subdev_8255_init(dev, s, NULL,
-					 (unsigned long)(dev->iobase));
-
-			s = dev->subdevices + 1;
-			ret = subdev_8255_init(dev, s, NULL,
-					       (unsigned long)(dev->iobase +
-							       PORT2A));
-			if (ret < 0)
-				return ret;
-
-			s = dev->subdevices + 2;
-			ret = subdev_8255_init(dev, s, NULL,
-					       (unsigned long)(dev->iobase +
-							       PORT3A));
-			if (ret < 0)
-				return ret;
-
-			s = dev->subdevices + 3;
-			ret = subdev_8255_init(dev, s, NULL,
-					       (unsigned long)(dev->iobase +
-							       PORT4A));
-			if (ret < 0)
-				return ret;
-
-			printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n",
-				dev->minor);
-
-			return 1;
-		}
+	devpriv->pci_dev = adl_pci7296_find_pci(dev, it);
+	if (!devpriv->pci_dev)
+		return -EIO;
+
+	if (comedi_pci_enable(devpriv->pci_dev, "adl_pci7296") < 0) {
+		printk(KERN_ERR
+			"comedi%d: Failed to enable PCI device and request regions\n",
+			dev->minor);
+		return -EIO;
 	}
 
-	printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-	       dev->minor, bus, slot);
-	return -EIO;
+	dev->iobase = pci_resource_start(devpriv->pci_dev, 2);
+	printk(KERN_INFO "comedi: base addr %4lx\n", dev->iobase);
+
+	/*  four 8255 digital io subdevices */
+	s = dev->subdevices + 0;
+	subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase));
+
+	s = dev->subdevices + 1;
+	ret = subdev_8255_init(dev, s, NULL,
+				(unsigned long)(dev->iobase + PORT2A));
+	if (ret < 0)
+		return ret;
+
+	s = dev->subdevices + 2;
+	ret = subdev_8255_init(dev, s, NULL,
+				(unsigned long)(dev->iobase + PORT3A));
+	if (ret < 0)
+		return ret;
+
+	s = dev->subdevices + 3;
+	ret = subdev_8255_init(dev, s, NULL,
+				(unsigned long)(dev->iobase + PORT4A));
+	if (ret < 0)
+		return ret;
+
+	printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", dev->minor);
+
+	return 0;
 }
 
 static void adl_pci7296_detach(struct comedi_device *dev)
diff --git a/drivers/staging/comedi/drivers/adl_pci7432.c b/drivers/staging/comedi/drivers/adl_pci7432.c
index 9cbfb61..10683c2 100644
--- a/drivers/staging/comedi/drivers/adl_pci7432.c
+++ b/drivers/staging/comedi/drivers/adl_pci7432.c
@@ -36,7 +36,6 @@ Configuration Options:
 
 #include "../comedidev.h"
 #include <linux/kernel.h>
-#include "comedi_pci.h"
 
 #define PCI7432_DI      0x00
 #define PCI7432_DO	    0x00
@@ -58,9 +57,6 @@ static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
 	printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n");
 	printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
 
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] & data[1]);
@@ -69,7 +65,7 @@ static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
 		       dev->iobase + PCI7432_DO);
 		outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO);
 	}
-	return 2;
+	return insn->n;
 }
 
 static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
@@ -80,85 +76,88 @@ static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
 	printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n");
 	printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
 
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff;
 	printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]);
 
-	return 2;
+	return insn->n;
+}
+
+static struct pci_dev *adl_pci7432_find_pci(struct comedi_device *dev,
+					    struct comedi_devconfig *it)
+{
+	struct pci_dev *pcidev = NULL;
+	int bus = it->options[0];
+	int slot = it->options[1];
+
+	for_each_pci_dev(pcidev) {
+		if (pcidev->vendor != PCI_VENDOR_ID_ADLINK ||
+		    pcidev->device != PCI_DEVICE_ID_PCI7432)
+			continue;
+		if (bus || slot) {
+			/* requested particular bus/slot */
+			if (pcidev->bus->number != bus ||
+			    PCI_SLOT(pcidev->devfn) != slot)
+				continue;
+		}
+		return pcidev;
+	}
+	printk(KERN_ERR
+		"comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
+	       dev->minor, bus, slot);
+	return NULL;
 }
 
 static int adl_pci7432_attach(struct comedi_device *dev,
 			      struct comedi_devconfig *it)
 {
-	struct pci_dev *pcidev = NULL;
 	struct comedi_subdevice *s;
-	int bus, slot;
+	int ret;
 
 	printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor);
 
 	dev->board_name = "pci7432";
-	bus = it->options[0];
-	slot = it->options[1];
 
 	if (alloc_private(dev, sizeof(struct adl_pci7432_private)) < 0)
 		return -ENOMEM;
 
-	if (alloc_subdevices(dev, 2) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 2);
+	if (ret)
+		return ret;
 
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
-		    pcidev->device == PCI_DEVICE_ID_PCI7432) {
-			if (bus || slot) {
-				/* requested particular bus/slot */
-				if (pcidev->bus->number != bus
-				    || PCI_SLOT(pcidev->devfn) != slot) {
-					continue;
-				}
-			}
-			devpriv->pci_dev = pcidev;
-			if (comedi_pci_enable(pcidev, "adl_pci7432") < 0) {
-				printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n",
-				     dev->minor);
-				return -EIO;
-			}
-			dev->iobase = pci_resource_start(pcidev, 2);
-			printk(KERN_INFO "comedi: base addr %4lx\n",
-				dev->iobase);
-
-			s = dev->subdevices + 0;
-			s->type = COMEDI_SUBD_DI;
-			s->subdev_flags =
-			    SDF_READABLE | SDF_GROUND | SDF_COMMON;
-			s->n_chan = 32;
-			s->maxdata = 1;
-			s->len_chanlist = 32;
-			s->io_bits = 0x00000000;
-			s->range_table = &range_digital;
-			s->insn_bits = adl_pci7432_di_insn_bits;
-
-			s = dev->subdevices + 1;
-			s->type = COMEDI_SUBD_DO;
-			s->subdev_flags =
-			    SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
-			s->n_chan = 32;
-			s->maxdata = 1;
-			s->len_chanlist = 32;
-			s->io_bits = 0xffffffff;
-			s->range_table = &range_digital;
-			s->insn_bits = adl_pci7432_do_insn_bits;
-
-			printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n",
-				dev->minor);
-			return 1;
-		}
-	}
+	devpriv->pci_dev = adl_pci7432_find_pci(dev, it);
+	if (!devpriv->pci_dev)
+		return -EIO;
 
-	printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-	       dev->minor, bus, slot);
-	return -EIO;
+	if (comedi_pci_enable(devpriv->pci_dev, "adl_pci7432") < 0) {
+		printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n",
+			dev->minor);
+		return -EIO;
+	}
+	dev->iobase = pci_resource_start(devpriv->pci_dev, 2);
+	printk(KERN_INFO "comedi: base addr %4lx\n", dev->iobase);
+
+	s = dev->subdevices + 0;
+	s->type = COMEDI_SUBD_DI;
+	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 32;
+	s->maxdata = 1;
+	s->len_chanlist = 32;
+	s->io_bits = 0x00000000;
+	s->range_table = &range_digital;
+	s->insn_bits = adl_pci7432_di_insn_bits;
+
+	s = dev->subdevices + 1;
+	s->type = COMEDI_SUBD_DO;
+	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 32;
+	s->maxdata = 1;
+	s->len_chanlist = 32;
+	s->io_bits = 0xffffffff;
+	s->range_table = &range_digital;
+	s->insn_bits = adl_pci7432_do_insn_bits;
+
+	printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", dev->minor);
+	return 0;
 }
 
 static void adl_pci7432_detach(struct comedi_device *dev)
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index 409ef13..1811375 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -38,7 +38,6 @@ Configuration Options:
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include "comedi_fc.h"
-#include "comedi_pci.h"
 #include "8253.h"
 
 #define PCI8164_AXIS_X  0x00
@@ -224,94 +223,103 @@ static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
 	return 2;
 }
 
+static struct pci_dev *adl_pci8164_find_pci(struct comedi_device *dev,
+					    struct comedi_devconfig *it)
+{
+	struct pci_dev *pcidev = NULL;
+	int bus = it->options[0];
+	int slot = it->options[1];
+
+	for_each_pci_dev(pcidev) {
+		if (pcidev->vendor != PCI_VENDOR_ID_ADLINK ||
+		    pcidev->device != PCI_DEVICE_ID_PCI8164)
+			continue;
+		if (bus || slot) {
+			/* requested particular bus/slot */
+			if (pcidev->bus->number != bus ||
+			    PCI_SLOT(pcidev->devfn) != slot)
+				continue;
+		}
+		return pcidev;
+	}
+	printk(KERN_ERR
+		"comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
+		dev->minor, bus, slot);
+	return NULL;
+}
+
 static int adl_pci8164_attach(struct comedi_device *dev,
 			      struct comedi_devconfig *it)
 {
-	struct pci_dev *pcidev = NULL;
 	struct comedi_subdevice *s;
-	int bus, slot;
+	int ret;
 
 	printk(KERN_INFO "comedi: attempt to attach...\n");
 	printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor);
 
 	dev->board_name = "pci8164";
-	bus = it->options[0];
-	slot = it->options[1];
 
 	if (alloc_private(dev, sizeof(struct adl_pci8164_private)) < 0)
 		return -ENOMEM;
 
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
+		return ret;
 
-	for_each_pci_dev(pcidev) {
-		if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
-		    pcidev->device == PCI_DEVICE_ID_PCI8164) {
-			if (bus || slot) {
-				/* requested particular bus/slot */
-				if (pcidev->bus->number != bus
-					|| PCI_SLOT(pcidev->devfn) != slot)
-					continue;
-			}
-			devpriv->pci_dev = pcidev;
-			if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) {
-				printk(KERN_ERR "comedi%d: Failed to enable "
-				"PCI device and request regions\n", dev->minor);
-				return -EIO;
-			}
-			dev->iobase = pci_resource_start(pcidev, 2);
-			printk(KERN_DEBUG "comedi: base addr %4lx\n",
-				   dev->iobase);
-
-			s = dev->subdevices + 0;
-			s->type = COMEDI_SUBD_PROC;
-			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-			s->n_chan = 4;
-			s->maxdata = 0xffff;
-			s->len_chanlist = 4;
-			/* s->range_table = &range_axis; */
-			s->insn_read = adl_pci8164_insn_read_msts;
-			s->insn_write = adl_pci8164_insn_write_cmd;
-
-			s = dev->subdevices + 1;
-			s->type = COMEDI_SUBD_PROC;
-			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-			s->n_chan = 4;
-			s->maxdata = 0xffff;
-			s->len_chanlist = 4;
-			/* s->range_table = &range_axis; */
-			s->insn_read = adl_pci8164_insn_read_ssts;
-			s->insn_write = adl_pci8164_insn_write_otp;
-
-			s = dev->subdevices + 2;
-			s->type = COMEDI_SUBD_PROC;
-			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-			s->n_chan = 4;
-			s->maxdata = 0xffff;
-			s->len_chanlist = 4;
-			/* s->range_table = &range_axis; */
-			s->insn_read = adl_pci8164_insn_read_buf0;
-			s->insn_write = adl_pci8164_insn_write_buf0;
-
-			s = dev->subdevices + 3;
-			s->type = COMEDI_SUBD_PROC;
-			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-			s->n_chan = 4;
-			s->maxdata = 0xffff;
-			s->len_chanlist = 4;
-			/* s->range_table = &range_axis; */
-			s->insn_read = adl_pci8164_insn_read_buf1;
-			s->insn_write = adl_pci8164_insn_write_buf1;
-
-			printk(KERN_INFO "comedi: attached\n");
-
-			return 1;
-		}
-	}
+	devpriv->pci_dev = adl_pci8164_find_pci(dev, it);
+	if (!devpriv->pci_dev)
+		return -EIO;
 
-	printk(KERN_ERR "comedi%d: no supported board found!"
-		   "(req. bus/slot : %d/%d)\n", dev->minor, bus, slot);
-	return -EIO;
+	if (comedi_pci_enable(devpriv->pci_dev, "adl_pci8164") < 0) {
+		printk(KERN_ERR "comedi%d: Failed to enable "
+		"PCI device and request regions\n", dev->minor);
+		return -EIO;
+	}
+	dev->iobase = pci_resource_start(devpriv->pci_dev, 2);
+	printk(KERN_DEBUG "comedi: base addr %4lx\n", dev->iobase);
+
+	s = dev->subdevices + 0;
+	s->type = COMEDI_SUBD_PROC;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 4;
+	s->maxdata = 0xffff;
+	s->len_chanlist = 4;
+	/* s->range_table = &range_axis; */
+	s->insn_read = adl_pci8164_insn_read_msts;
+	s->insn_write = adl_pci8164_insn_write_cmd;
+
+	s = dev->subdevices + 1;
+	s->type = COMEDI_SUBD_PROC;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 4;
+	s->maxdata = 0xffff;
+	s->len_chanlist = 4;
+	/* s->range_table = &range_axis; */
+	s->insn_read = adl_pci8164_insn_read_ssts;
+	s->insn_write = adl_pci8164_insn_write_otp;
+
+	s = dev->subdevices + 2;
+	s->type = COMEDI_SUBD_PROC;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 4;
+	s->maxdata = 0xffff;
+	s->len_chanlist = 4;
+	/* s->range_table = &range_axis; */
+	s->insn_read = adl_pci8164_insn_read_buf0;
+	s->insn_write = adl_pci8164_insn_write_buf0;
+
+	s = dev->subdevices + 3;
+	s->type = COMEDI_SUBD_PROC;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 4;
+	s->maxdata = 0xffff;
+	s->len_chanlist = 4;
+	/* s->range_table = &range_axis; */
+	s->insn_read = adl_pci8164_insn_read_buf1;
+	s->insn_write = adl_pci8164_insn_write_buf1;
+
+	printk(KERN_INFO "comedi: attached\n");
+	return 0;
 }
 
 static void adl_pci8164_detach(struct comedi_device *dev)
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index ccfb1a5..c41cfc5 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -81,7 +81,6 @@ TODO:
 #include <linux/interrupt.h>
 
 #include "8253.h"
-#include "comedi_pci.h"
 #include "comedi_fc.h"
 
 #define PCI9111_DRIVER_NAME	"adl_pci9111"
@@ -1154,7 +1153,7 @@ static int pci9111_di_insn_bits(struct comedi_device *dev,
 	bits = pci9111_di_get_bits();
 	data[1] = bits;
 
-	return 2;
+	return insn->n;
 }
 
 /*  Digital outputs */
@@ -1180,7 +1179,7 @@ static int pci9111_do_insn_bits(struct comedi_device *dev,
 
 	data[1] = bits;
 
-	return 2;
+	return insn->n;
 }
 
 /*  ------------------------------------------------------------------ */
@@ -1210,17 +1209,47 @@ static int pci9111_reset(struct comedi_device *dev)
 	return 0;
 }
 
-/*  Attach */
-/*       - Register PCI device */
-/*       - Declare device driver capability */
+static struct pci_dev *pci9111_find_pci(struct comedi_device *dev,
+					struct comedi_devconfig *it)
+{
+	struct pci_dev *pcidev = NULL;
+	int bus = it->options[0];
+	int slot = it->options[1];
+	int i;
+
+	for_each_pci_dev(pcidev) {
+		if (pcidev->vendor != PCI_VENDOR_ID_ADLINK)
+			continue;
+		for (i = 0; i < pci9111_board_nbr; i++) {
+			if (pcidev->device != pci9111_boards[i].device_id)
+				continue;
+			if (bus || slot) {
+				/* requested particular bus/slot */
+				if (pcidev->bus->number != bus ||
+				    PCI_SLOT(pcidev->devfn) != slot)
+					continue;
+			}
+			dev->board_ptr = pci9111_boards + i;
+			printk(KERN_ERR
+				"comedi%d: found %s (b:s:f=%d:%d:%d), irq=%d\n",
+				dev->minor, pci9111_boards[i].name,
+				pcidev->bus->number, PCI_SLOT(pcidev->devfn),
+				PCI_FUNC(pcidev->devfn), pcidev->irq);
+			return pcidev;
+		}
+	}
+	printk(KERN_ERR
+		"comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
+		dev->minor, bus, slot);
+	return NULL;
+}
 
 static int pci9111_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
 	struct comedi_subdevice *subdevice;
 	unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
-	struct pci_dev *pci_device = NULL;
-	int error, i;
+	int error;
 	const struct pci9111_board *board;
 
 	if (alloc_private(dev, sizeof(struct pci9111_private_data)) < 0)
@@ -1230,65 +1259,25 @@ static int pci9111_attach(struct comedi_device *dev,
 	printk(KERN_ERR "comedi%d: " PCI9111_DRIVER_NAME " driver\n",
 								dev->minor);
 
-	for_each_pci_dev(pci_device) {
-		if (pci_device->vendor == PCI_VENDOR_ID_ADLINK) {
-			for (i = 0; i < pci9111_board_nbr; i++) {
-				if (pci9111_boards[i].device_id ==
-				    pci_device->device) {
-					/* was a particular bus/slot
-					 * requested? */
-					if ((it->options[0] != 0)
-					    || (it->options[1] != 0)) {
-						/* are we on the wrong
-						 * bus/slot? */
-						if (pci_device->bus->number !=
-						    it->options[0]
-						    ||
-						    PCI_SLOT(pci_device->devfn)
-						    != it->options[1]) {
-							continue;
-						}
-					}
-
-					dev->board_ptr = pci9111_boards + i;
-					board =
-					    (struct pci9111_board *)
-					    dev->board_ptr;
-					dev_private->pci_device = pci_device;
-					goto found;
-				}
-			}
-		}
-	}
-
-	printk(KERN_ERR
-		"comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-			dev->minor, it->options[0], it->options[1]);
-	return -EIO;
-
-found:
-
-	printk(KERN_ERR "comedi%d: found %s (b:s:f=%d:%d:%d) , irq=%d\n",
-	       dev->minor,
-	       pci9111_boards[i].name,
-	       pci_device->bus->number,
-	       PCI_SLOT(pci_device->devfn),
-	       PCI_FUNC(pci_device->devfn), pci_device->irq);
+	dev_private->pci_device = pci9111_find_pci(dev, it);
+	if (!dev_private->pci_device)
+		return -EIO;
+	board = (struct pci9111_board *)dev->board_ptr;
 
 	/*  TODO: Warn about non-tested boards. */
 
 	/*  Read local configuration register base address
 	 *  [PCI_BASE_ADDRESS #1]. */
 
-	lcr_io_base = pci_resource_start(pci_device, 1);
-	lcr_io_range = pci_resource_len(pci_device, 1);
+	lcr_io_base = pci_resource_start(dev_private->pci_device, 1);
+	lcr_io_range = pci_resource_len(dev_private->pci_device, 1);
 
 	printk
 	    ("comedi%d: local configuration registers at address 0x%4lx [0x%4lx]\n",
 	     dev->minor, lcr_io_base, lcr_io_range);
 
 	/*  Enable PCI device and request regions */
-	if (comedi_pci_enable(pci_device, PCI9111_DRIVER_NAME) < 0) {
+	if (comedi_pci_enable(dev_private->pci_device, PCI9111_DRIVER_NAME) < 0) {
 		printk
 		    ("comedi%d: Failed to enable PCI device and request regions\n",
 		     dev->minor);
@@ -1296,8 +1285,8 @@ found:
 	}
 	/*  Read PCI6308 register base address [PCI_BASE_ADDRESS #2]. */
 
-	io_base = pci_resource_start(pci_device, 2);
-	io_range = pci_resource_len(pci_device, 2);
+	io_base = pci_resource_start(dev_private->pci_device, 2);
+	io_range = pci_resource_len(dev_private->pci_device, 2);
 
 	printk(KERN_ERR "comedi%d: 6503 registers at address 0x%4lx [0x%4lx]\n",
 	       dev->minor, io_base, io_range);
@@ -1314,21 +1303,22 @@ found:
 	/*  Irq setup */
 
 	dev->irq = 0;
-	if (pci_device->irq > 0) {
-		if (request_irq(pci_device->irq, pci9111_interrupt,
+	if (dev_private->pci_device->irq > 0) {
+		dev->irq = dev_private->pci_device->irq;
+
+		if (request_irq(dev->irq, pci9111_interrupt,
 				IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) {
 			printk(KERN_ERR
 				"comedi%d: unable to allocate irq  %u\n",
-					dev->minor, pci_device->irq);
+					dev->minor, dev->irq);
 			return -EINVAL;
 		}
 	}
-	dev->irq = pci_device->irq;
 
 	/*  TODO: Add external multiplexer setup (according to option[2]). */
 
-	error = alloc_subdevices(dev, 4);
-	if (error < 0)
+	error = comedi_alloc_subdevices(dev, 4);
+	if (error)
 		return error;
 
 	subdevice = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index 7864586..4482aab 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -71,7 +71,6 @@ Configuration options:
 
 #include "amcc_s5933.h"
 #include "8253.h"
-#include "comedi_pci.h"
 #include "comedi_fc.h"
 
 #define PCI_VENDOR_ID_AMCC	0x10e8
@@ -300,7 +299,7 @@ struct pci9118_private {
 	short *ai_data;
 	short ao_data[2];			/* data output buffer */
 	unsigned int ai_scans;			/* number of scans to do */
-	char dma_doublebuf;			/* we can use double buffring */
+	char dma_doublebuf;			/* we can use double buffering */
 	unsigned int dma_actbuf;		/* which buffer is used now */
 	short *dmabuf_virt[2];			/*
 						 * pointers to begin of
@@ -493,7 +492,7 @@ static int pci9118_insn_bits_di(struct comedi_device *dev,
 {
 	data[1] = inl(dev->iobase + PCI9118_DI) & 0xf;
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -510,7 +509,7 @@ static int pci9118_insn_bits_do(struct comedi_device *dev,
 	}
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -1736,7 +1735,7 @@ static int check_channel_list(struct comedi_device *dev,
 							"can't be mixtured!");
 				return 0;
 			}
-			if ((!devpriv->usemux) & (differencial) &
+			if (!devpriv->usemux && differencial &&
 			    (CR_CHAN(chanlist[i]) >= this_board->n_aichand)) {
 				comedi_error(dev,
 					     "If AREF_DIFF is used then is "
@@ -2111,6 +2110,44 @@ static int pci9118_reset(struct comedi_device *dev)
 	return 0;
 }
 
+static struct pci_dev *pci9118_find_pci(struct comedi_device *dev,
+					struct comedi_devconfig *it)
+{
+	struct pci_dev *pcidev = NULL;
+	int bus = it->options[0];
+	int slot = it->options[1];
+
+	for_each_pci_dev(pcidev) {
+		if (pcidev->vendor != PCI_VENDOR_ID_AMCC)
+			continue;
+		if (pcidev->device != this_board->device_id)
+			continue;
+		if (bus || slot) {
+			/* requested particular bus/slot */
+			if (pcidev->bus->number != bus ||
+			    PCI_SLOT(pcidev->devfn) != slot)
+				continue;
+		}
+		/*
+		 * Look for device that isn't in use.
+		 * Enable PCI device and request regions.
+		 */
+		if (comedi_pci_enable(pcidev, "adl_pci9118"))
+			continue;
+		printk(KERN_ERR ", b:s:f=%d:%d:%d, io=0x%4lx, 0x%4lx",
+			pcidev->bus->number,
+			PCI_SLOT(pcidev->devfn),
+			PCI_FUNC(pcidev->devfn),
+			(unsigned long)pci_resource_start(pcidev, 2),
+			(unsigned long)pci_resource_start(pcidev, 0));
+		return pcidev;
+	}
+	printk(KERN_ERR
+		"comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
+		dev->minor, bus, slot);
+	return NULL;
+}
+
 static int pci9118_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
@@ -2118,17 +2155,10 @@ static int pci9118_attach(struct comedi_device *dev,
 	int ret, pages, i;
 	unsigned short master;
 	unsigned int irq;
-	unsigned long iobase_a, iobase_9;
-	struct pci_dev *pcidev;
-	int opt_bus, opt_slot;
-	const char *errstr;
-	unsigned char pci_bus, pci_slot, pci_func;
 	u16 u16w;
 
 	printk("comedi%d: adl_pci9118: board=%s", dev->minor, this_board->name);
 
-	opt_bus = it->options[0];
-	opt_slot = it->options[1];
 	if (it->options[3] & 1)
 		master = 0;	/* user don't want use bus master */
 	else
@@ -2140,61 +2170,19 @@ static int pci9118_attach(struct comedi_device *dev,
 		return -ENOMEM;
 	}
 
-	/* Look for matching PCI device */
-	errstr = "not found!";
-	pcidev = NULL;
-	while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_AMCC,
-						this_board->device_id,
-						pcidev))) {
-		/* Found matching vendor/device. */
-		if (opt_bus || opt_slot) {
-			/* Check bus/slot. */
-			if (opt_bus != pcidev->bus->number
-			    || opt_slot != PCI_SLOT(pcidev->devfn))
-				continue;	/* no match */
-		}
-		/*
-		 * Look for device that isn't in use.
-		 * Enable PCI device and request regions.
-		 */
-		if (comedi_pci_enable(pcidev, "adl_pci9118")) {
-			errstr =
-			    "failed to enable PCI device and request regions!";
-			continue;
-		}
-		break;
-	}
-
-	if (!pcidev) {
-		if (opt_bus || opt_slot) {
-			printk(KERN_ERR " - Card at b:s %d:%d %s\n",
-			       opt_bus, opt_slot, errstr);
-		} else {
-			printk(KERN_ERR " - Card %s\n", errstr);
-		}
+	devpriv->pcidev = pci9118_find_pci(dev, it);
+	if (!devpriv->pcidev)
 		return -EIO;
-	}
 
 	if (master)
-		pci_set_master(pcidev);
+		pci_set_master(devpriv->pcidev);
 
+	irq = devpriv->pcidev->irq;
+	devpriv->iobase_a = pci_resource_start(devpriv->pcidev, 0);
+	dev->iobase = pci_resource_start(devpriv->pcidev, 2);
 
-	pci_bus = pcidev->bus->number;
-	pci_slot = PCI_SLOT(pcidev->devfn);
-	pci_func = PCI_FUNC(pcidev->devfn);
-	irq = pcidev->irq;
-	iobase_a = pci_resource_start(pcidev, 0);
-	iobase_9 = pci_resource_start(pcidev, 2);
-
-	printk(KERN_ERR ", b:s:f=%d:%d:%d, io=0x%4lx, 0x%4lx", pci_bus,
-				pci_slot, pci_func, iobase_9, iobase_a);
-
-	dev->iobase = iobase_9;
 	dev->board_name = this_board->name;
 
-	devpriv->pcidev = pcidev;
-	devpriv->iobase_a = iobase_a;
-
 	pci9118_reset(dev);
 
 	if (it->options[3] & 2)
@@ -2280,8 +2268,8 @@ static int pci9118_attach(struct comedi_device *dev,
 	pci_write_config_word(devpriv->pcidev, PCI_COMMAND, u16w | 64);
 				/* Enable parity check for parity error */
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index 7d585a1..6df51c8 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -125,8 +125,6 @@ struct adq12b_board {
 	int do_chans;
 };
 
-#define thisboard ((const struct adq12b_board *)dev->board_ptr)
-
 struct adq12b_private {
 	int unipolar;		/* option 2 of comedi_config (1 is iobase) */
 	int differential;	/* option 3 of comedi_config */
@@ -195,7 +193,7 @@ static int adq12b_di_insn_bits(struct comedi_device *dev,
 	/* only bits 0-4 have information about digital inputs */
 	data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f));
 
-	return 2;
+	return insn->n;
 }
 
 static int adq12b_do_insn_bits(struct comedi_device *dev,
@@ -217,14 +215,16 @@ static int adq12b_do_insn_bits(struct comedi_device *dev,
 
 	data[1] = devpriv->digital_state;
 
-	return 2;
+	return insn->n;
 }
 
 static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct adq12b_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	unsigned long iobase;
 	int unipolar, differential;
+	int ret;
 
 	iobase = it->options[0];
 	unipolar = it->options[1];
@@ -250,11 +250,7 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	}
 	dev->iobase = iobase;
 
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 /*
  * Allocate the private structure area.  alloc_private() is a
@@ -272,22 +268,19 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	devpriv->last_channel = -1;
 	devpriv->last_range = -1;
 
-/*
- * Allocate the subdevice structures.  alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_subdevices(dev, 3) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* analog input subdevice */
 	s->type = COMEDI_SUBD_AI;
 	if (differential) {
 		s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
-		s->n_chan = thisboard->ai_diff_chans;
+		s->n_chan = board->ai_diff_chans;
 	} else {
 		s->subdev_flags = SDF_READABLE | SDF_GROUND;
-		s->n_chan = thisboard->ai_se_chans;
+		s->n_chan = board->ai_se_chans;
 	}
 
 	if (unipolar)
@@ -295,7 +288,7 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	else
 		s->range_table = &range_adq12b_ai_bipolar;
 
-	s->maxdata = (1 << thisboard->ai_bits) - 1;
+	s->maxdata = (1 << board->ai_bits) - 1;
 
 	s->len_chanlist = 4;	/* This is the maximum chanlist length that
 				   the board can handle */
@@ -305,7 +298,7 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	/* digital input subdevice */
 	s->type = COMEDI_SUBD_DI;
 	s->subdev_flags = SDF_READABLE;
-	s->n_chan = thisboard->di_chans;
+	s->n_chan = board->di_chans;
 	s->maxdata = 1;
 	s->range_table = &range_digital;
 	s->insn_bits = adq12b_di_insn_bits;
@@ -314,7 +307,7 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	/* digital output subdevice */
 	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = thisboard->do_chans;
+	s->n_chan = board->do_chans;
 	s->maxdata = 1;
 	s->range_table = &range_digital;
 	s->insn_bits = adq12b_do_insn_bits;
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index de8c98c..0ed1ff9 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -45,8 +45,6 @@ Configuration options:
 
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
-
 #include "8253.h"
 #include "amcc_s5933.h"
 
@@ -437,7 +435,7 @@ static int pci171x_insn_bits_di(struct comedi_device *dev,
 {
 	data[1] = inw(dev->iobase + PCI171x_DI);
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -454,7 +452,7 @@ static int pci171x_insn_bits_do(struct comedi_device *dev,
 	}
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -1349,7 +1347,7 @@ static int pci1710_attach(struct comedi_device *dev,
 	int i;
 	int board_index;
 
-	dev_info(dev->hw_dev, "comedi%d: adv_pci1710:\n", dev->minor);
+	dev_info(dev->class_dev, DRV_NAME ": attach\n");
 
 	opt_bus = it->options[0];
 	opt_slot = it->options[1];
@@ -1401,10 +1399,10 @@ static int pci1710_attach(struct comedi_device *dev,
 
 	if (!pcidev) {
 		if (opt_bus || opt_slot) {
-			dev_err(dev->hw_dev, "- Card at b:s %d:%d %s\n",
+			dev_err(dev->class_dev, "- Card at b:s %d:%d %s\n",
 				opt_bus, opt_slot, errstr);
 		} else {
-			dev_err(dev->hw_dev, "- Card %s\n", errstr);
+			dev_err(dev->class_dev, "- Card %s\n", errstr);
 		}
 		return -EIO;
 	}
@@ -1415,8 +1413,8 @@ static int pci1710_attach(struct comedi_device *dev,
 	irq = pcidev->irq;
 	iobase = pci_resource_start(pcidev, 2);
 
-	dev_dbg(dev->hw_dev, "b:s:f=%d:%d:%d, io=0x%4lx\n", pci_bus, pci_slot,
-		pci_func, iobase);
+	dev_dbg(dev->class_dev, "b:s:f=%d:%d:%d, io=0x%4lx\n",
+		pci_bus, pci_slot, pci_func, iobase);
 
 	dev->iobase = iobase;
 
@@ -1435,8 +1433,8 @@ static int pci1710_attach(struct comedi_device *dev,
 	if (this_board->n_counter)
 		n_subdevices++;
 
-	ret = alloc_subdevices(dev, n_subdevices);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	if (ret)
 		return ret;
 
 	pci1710_reset(dev);
@@ -1446,14 +1444,15 @@ static int pci1710_attach(struct comedi_device *dev,
 			if (request_irq(irq, interrupt_service_pci1710,
 					IRQF_SHARED, "Advantech PCI-1710",
 					dev)) {
-				dev_dbg(dev->hw_dev, "unable to allocate IRQ %d, DISABLING IT",
+				dev_dbg(dev->class_dev,
+					"unable to allocate IRQ %d, DISABLING IT",
 					irq);
 				irq = 0;	/* Can't use IRQ */
 			} else {
-				dev_dbg(dev->hw_dev, "irq=%u", irq);
+				dev_dbg(dev->class_dev, "irq=%u", irq);
 			}
 		} else {
-			dev_dbg(dev->hw_dev, "IRQ disabled");
+			dev_dbg(dev->class_dev, "IRQ disabled");
 		}
 	} else {
 		irq = 0;
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 336addc..5c99c74 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -50,8 +50,6 @@ TODO:
 
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
-
 #define PCI_VENDOR_ID_ADVANTECH		0x13fe	/* Advantech PCI vendor ID */
 
 /* hardware types of the cards */
@@ -286,7 +284,7 @@ static int pci1723_dio_insn_bits(struct comedi_device *dev,
 		outw(s->state, dev->iobase + PCI1723_WRITE_DIGITAL_OUTPUT_CMD);
 	}
 	data[1] = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA);
-	return 2;
+	return insn->n;
 }
 
 static int pci1723_attach(struct comedi_device *dev,
@@ -367,11 +365,9 @@ static int pci1723_attach(struct comedi_device *dev,
 	if (this_board->n_diochan)
 		n_subdevices++;
 
-	ret = alloc_subdevices(dev, n_subdevices);
-	if (ret < 0) {
-		printk(" - Allocation failed!\n");
+	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	if (ret)
 		return ret;
-	}
 
 	pci1723_reset(dev);
 	subdev = 0;
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index 43a32dc..ad653a5 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -33,7 +33,6 @@ Configuration options:
 
 #include <linux/delay.h>
 
-#include "comedi_pci.h"
 #include "8255.h"
 #include "8253.h"
 
@@ -425,7 +424,7 @@ static int pci_dio_insn_bits_di_b(struct comedi_device *dev,
 		data[1] |= inb(dev->iobase + d->addr + i) << (8 * i);
 
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -442,7 +441,7 @@ static int pci_dio_insn_bits_di_w(struct comedi_device *dev,
 	for (i = 0; i < d->regs; i++)
 		data[1] |= inw(dev->iobase + d->addr + 2 * i) << (16 * i);
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -464,7 +463,7 @@ static int pci_dio_insn_bits_do_b(struct comedi_device *dev,
 	}
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -486,7 +485,7 @@ static int pci_dio_insn_bits_do_w(struct comedi_device *dev,
 	}
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -635,7 +634,7 @@ static int pci1760_insn_bits_di(struct comedi_device *dev,
 {
 	data[1] = inb(dev->iobase + IMB3);
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -664,7 +663,7 @@ static int pci1760_insn_bits_do(struct comedi_device *dev,
 	}
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -1122,16 +1121,18 @@ static int pci_dio_attach(struct comedi_device *dev,
 	}
 
 	if (!dev->board_ptr) {
-		dev_err(dev->hw_dev, "Error: Requested type of the card was not found!\n");
+		dev_err(dev->class_dev,
+			"Error: Requested type of the card was not found!\n");
 		return -EIO;
 	}
 
 	if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
-		dev_err(dev->hw_dev, "Error: Can't enable PCI device and request regions!\n");
+		dev_err(dev->class_dev,
+			"Error: Can't enable PCI device and request regions!\n");
 		return -EIO;
 	}
 	iobase = pci_resource_start(pcidev, this_board->main_pci_region);
-	dev_dbg(dev->hw_dev, "b:s:f=%d:%d:%d, io=0x%4lx\n",
+	dev_dbg(dev->class_dev, "b:s:f=%d:%d:%d, io=0x%4lx\n",
 		pcidev->bus->number, PCI_SLOT(pcidev->devfn),
 		PCI_FUNC(pcidev->devfn), iobase);
 
@@ -1157,8 +1158,8 @@ static int pci_dio_attach(struct comedi_device *dev,
 				n_subdevices++;
 	}
 
-	ret = alloc_subdevices(dev, n_subdevices);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	if (ret)
 		return ret;
 
 	subdev = 0;
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index 64d82bc..f7d453f 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -80,8 +80,6 @@ static const struct aio12_8_boardtype board_types[] = {
 	 .name = "aio_aio12_8"},
 };
 
-#define	thisboard	((const struct aio12_8_boardtype  *) dev->board_ptr)
-
 struct aio12_8_private {
 	unsigned int ao_readback[4];
 };
@@ -167,8 +165,10 @@ static const struct comedi_lrange range_aio_aio12_8 = {
 static int aio_aio12_8_attach(struct comedi_device *dev,
 			      struct comedi_devconfig *it)
 {
+	const struct aio12_8_boardtype *board = comedi_board(dev);
 	int iobase;
 	struct comedi_subdevice *s;
+	int ret;
 
 	iobase = it->options[0];
 	if (!request_region(iobase, 24, "aio_aio12_8")) {
@@ -176,15 +176,16 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
 		return -EIO;
 	}
 
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 	dev->iobase = iobase;
 
 	if (alloc_private(dev, sizeof(struct aio12_8_private)) < 0)
 		return -ENOMEM;
 
-	if (alloc_subdevices(dev, 3) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
+		return ret;
 
 	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_AI;
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 04f6f94..16f28f6 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -57,8 +57,6 @@ static const struct aio_iiro_16_board aio_iiro_16_boards[] = {
 	 .do_ = 16},
 };
 
-#define	thisboard	((const struct aio_iiro_16_board *) dev->board_ptr)
-
 struct aio_iiro_16_private {
 	int data;
 	struct pci_dev *pci_dev;
@@ -72,9 +70,6 @@ static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
 					   struct comedi_insn *insn,
 					   unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= data[0] & data[1];
@@ -85,7 +80,7 @@ static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
 
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
@@ -93,25 +88,24 @@ static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
 					  struct comedi_insn *insn,
 					  unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = 0;
 	data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
 	data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
 
-	return 2;
+	return insn->n;
 }
 
 static int aio_iiro_16_attach(struct comedi_device *dev,
 			      struct comedi_devconfig *it)
 {
+	const struct aio_iiro_16_board *board = comedi_board(dev);
 	int iobase;
 	struct comedi_subdevice *s;
+	int ret;
 
 	printk(KERN_INFO "comedi%d: aio_iiro_16: ", dev->minor);
 
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 	iobase = it->options[0];
 
@@ -125,8 +119,9 @@ static int aio_iiro_16_attach(struct comedi_device *dev,
 	if (alloc_private(dev, sizeof(struct aio_iiro_16_private)) < 0)
 		return -ENOMEM;
 
-	if (alloc_subdevices(dev, 2) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 2);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	s->type = COMEDI_SUBD_DIO;
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index c9c5d97..55f3050 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -210,21 +210,11 @@ order they appear in the channel list.
 
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
-
 #include "8255.h"
 #include "8253.h"
 
 #define DIO200_DRIVER_NAME	"amplc_dio200"
 
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA_MODULE
-#define CONFIG_COMEDI_AMPLC_DIO200_ISA
-#endif
-
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI_MODULE
-#define CONFIG_COMEDI_AMPLC_DIO200_PCI
-#endif
-
 /* PCI IDs */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
@@ -282,12 +272,12 @@ enum dio200_model {
 };
 
 enum dio200_layout {
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
 	pc212_layout,
 	pc214_layout,
 #endif
 	pc215_layout,
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
 	pc218_layout,
 #endif
 	pc272_layout
@@ -302,7 +292,7 @@ struct dio200_board {
 };
 
 static const struct dio200_board dio200_boards[] = {
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
 	{
 	 .name = "pc212e",
 	 .bustype = isa_bustype,
@@ -334,7 +324,7 @@ static const struct dio200_board dio200_boards[] = {
 	 .layout = pc272_layout,
 	 },
 #endif
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)
 	{
 	 .name = "pci215",
 	 .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
@@ -377,7 +367,7 @@ struct dio200_layout_struct {
 };
 
 static const struct dio200_layout_struct dio200_layouts[] = {
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
 	[pc212_layout] = {
 			  .n_subdevs = 6,
 			  .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254,
@@ -406,7 +396,7 @@ static const struct dio200_layout_struct dio200_layouts[] = {
 			  .has_int_sce = 1,
 			  .has_clk_gat_sce = 1,
 			  },
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
 	[pc218_layout] = {
 			  .n_subdevs = 7,
 			  .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254,
@@ -429,40 +419,15 @@ static const struct dio200_layout_struct dio200_layouts[] = {
 			  },
 };
 
-/*
- * PCI driver table.
- */
-
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
-static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, dio200_pci_table);
-#endif /* CONFIG_COMEDI_AMPLC_DIO200_PCI */
-
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct dio200_board *)dev->board_ptr)
-#define thislayout (&dio200_layouts[((struct dio200_board *) \
-		    dev->board_ptr)->layout])
-
 /* this structure is for data unique to this hardware driver.  If
    several hardware drivers keep similar information in this structure,
    feel free to suggest moving the variable to the struct comedi_device struct.
  */
 struct dio200_private {
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
 	struct pci_dev *pci_dev;	/* PCI device */
-#endif
 	int intr_sd;
 };
 
-#define devpriv ((struct dio200_private *)dev->private)
-
 struct dio200_subdev_8254 {
 	unsigned long iobase;	/* Counter base address */
 	unsigned long clk_sce_iobase;	/* CLK_SCE base address */
@@ -486,92 +451,30 @@ struct dio200_subdev_intr {
 };
 
 /*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
+ * This function looks for a board matching the supplied PCI device.
  */
-static int dio200_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static void dio200_detach(struct comedi_device *dev);
-static struct comedi_driver driver_amplc_dio200 = {
-	.driver_name = DIO200_DRIVER_NAME,
-	.module = THIS_MODULE,
-	.attach = dio200_attach,
-	.detach = dio200_detach,
-	.board_name = &dio200_boards[0].name,
-	.offset = sizeof(struct dio200_board),
-	.num_names = ARRAY_SIZE(dio200_boards),
-};
-
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
-static int __devinit driver_amplc_dio200_pci_probe(struct pci_dev *dev,
-						   const struct pci_device_id
-						   *ent)
-{
-	return comedi_pci_auto_config(dev, &driver_amplc_dio200);
-}
-
-static void __devexit driver_amplc_dio200_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_amplc_dio200_pci_driver = {
-	.id_table = dio200_pci_table,
-	.probe = &driver_amplc_dio200_pci_probe,
-	.remove = __devexit_p(&driver_amplc_dio200_pci_remove)
-};
-
-static int __init driver_amplc_dio200_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_amplc_dio200);
-	if (retval < 0)
-		return retval;
-
-	driver_amplc_dio200_pci_driver.name =
-	    (char *)driver_amplc_dio200.driver_name;
-	return pci_register_driver(&driver_amplc_dio200_pci_driver);
-}
-
-static void __exit driver_amplc_dio200_cleanup_module(void)
+static const struct dio200_board *
+dio200_find_pci_board(struct pci_dev *pci_dev)
 {
-	pci_unregister_driver(&driver_amplc_dio200_pci_driver);
-	comedi_driver_unregister(&driver_amplc_dio200);
-}
+	unsigned int i;
 
-module_init(driver_amplc_dio200_init_module);
-module_exit(driver_amplc_dio200_cleanup_module);
-#else
-static int __init driver_amplc_dio200_init_module(void)
-{
-	return comedi_driver_register(&driver_amplc_dio200);
-}
-
-static void __exit driver_amplc_dio200_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_amplc_dio200);
+	for (i = 0; i < ARRAY_SIZE(dio200_boards); i++)
+		if (dio200_boards[i].bustype == pci_bustype &&
+		    pci_dev->device == dio200_boards[i].devid)
+			return &dio200_boards[i];
+	return NULL;
 }
 
-module_init(driver_amplc_dio200_init_module);
-module_exit(driver_amplc_dio200_cleanup_module);
-#endif
-
 /*
  * This function looks for a PCI device matching the requested board name,
  * bus and slot.
  */
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
-static int
-dio200_find_pci(struct comedi_device *dev, int bus, int slot,
-		struct pci_dev **pci_dev_p)
+static struct pci_dev *
+dio200_find_pci(struct comedi_device *dev, int bus, int slot)
 {
+	const struct dio200_board *thisboard = comedi_board(dev);
 	struct pci_dev *pci_dev = NULL;
 
-	*pci_dev_p = NULL;
-
 	/* Look for matching PCI device. */
 	for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
 	     pci_dev != NULL;
@@ -584,20 +487,15 @@ dio200_find_pci(struct comedi_device *dev, int bus, int slot,
 				continue;
 		}
 		if (thisboard->model == anypci_model) {
-			/* Match any supported model. */
-			int i;
-
-			for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) {
-				if (dio200_boards[i].bustype != pci_bustype)
-					continue;
-				if (pci_dev->device == dio200_boards[i].devid) {
-					/* Change board_ptr to matched board. */
-					dev->board_ptr = &dio200_boards[i];
-					break;
-				}
-			}
-			if (i == ARRAY_SIZE(dio200_boards))
+			/* Wildcard board matches any supported PCI board. */
+			const struct dio200_board *foundboard;
+
+			foundboard = dio200_find_pci_board(pci_dev);
+			if (foundboard == NULL)
 				continue;
+			/* Replace wildcard board_ptr. */
+			dev->board_ptr = foundboard;
+			thisboard = comedi_board(dev);
 		} else {
 			/* Match specific model name. */
 			if (pci_dev->device != thisboard->devid)
@@ -605,38 +503,35 @@ dio200_find_pci(struct comedi_device *dev, int bus, int slot,
 		}
 
 		/* Found a match. */
-		*pci_dev_p = pci_dev;
-		return 0;
+		return pci_dev;
 	}
 	/* No match found. */
 	if (bus || slot) {
-		printk(KERN_ERR
-		       "comedi%d: error! no %s found at pci %02x:%02x!\n",
-		       dev->minor, thisboard->name, bus, slot);
+		dev_err(dev->class_dev,
+			"error! no %s found at pci %02x:%02x!\n",
+			thisboard->name, bus, slot);
 	} else {
-		printk(KERN_ERR "comedi%d: error! no %s found!\n",
-		       dev->minor, thisboard->name);
+		dev_err(dev->class_dev, "error! no %s found!\n",
+			thisboard->name);
 	}
-	return -EIO;
+	return NULL;
 }
-#endif
 
 /*
  * This function checks and requests an I/O region, reporting an error
  * if there is a conflict.
  */
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
 static int
-dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
+dio200_request_region(struct comedi_device *dev,
+		      unsigned long from, unsigned long extent)
 {
 	if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) {
-		printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
-		       minor, from, extent);
+		dev_err(dev->class_dev, "I/O port conflict (%#lx,%lu)!\n",
+			from, extent);
 		return -EIO;
 	}
 	return 0;
 }
-#endif
 
 /*
  * 'insn_bits' function for an 'INTERRUPT' subdevice.
@@ -656,7 +551,7 @@ dio200_subdev_intr_insn_bits(struct comedi_device *dev,
 		data[0] = 0;
 	}
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -1030,8 +925,7 @@ dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
 	if (!subpriv) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
+		dev_err(dev->class_dev, "error! out of memory!\n");
 		return -ENOMEM;
 	}
 	subpriv->iobase = iobase;
@@ -1080,6 +974,7 @@ dio200_subdev_intr_cleanup(struct comedi_device *dev,
 static irqreturn_t dio200_interrupt(int irq, void *d)
 {
 	struct comedi_device *dev = d;
+	struct dio200_private *devpriv = dev->private;
 	int handled;
 
 	if (!dev->attached)
@@ -1284,8 +1179,7 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
 	if (!subpriv) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
+		dev_err(dev->class_dev, "error! out of memory!\n");
 		return -ENOMEM;
 	}
 
@@ -1337,99 +1231,52 @@ dio200_subdev_8254_cleanup(struct comedi_device *dev,
 	kfree(subpriv);
 }
 
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static void dio200_report_attach(struct comedi_device *dev, unsigned int irq)
+{
+	const struct dio200_board *thisboard = comedi_board(dev);
+	struct dio200_private *devpriv = dev->private;
+	char tmpbuf[60];
+	int tmplen;
+
+	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) &&
+	    thisboard->bustype == isa_bustype)
+		tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
+				   "(base %#lx) ", dev->iobase);
+	else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) &&
+		 thisboard->bustype == pci_bustype)
+		tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
+				   "(pci %s) ", pci_name(devpriv->pci_dev));
+	else
+		tmplen = 0;
+	if (irq)
+		tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
+				    "(irq %u%s) ", irq,
+				    (dev->irq ? "" : " UNAVAILABLE"));
+	else
+		tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
+				    "(no irq) ");
+	dev_info(dev->class_dev, "%s %sattached\n", dev->board_name, tmpbuf);
+}
+
+static int dio200_common_attach(struct comedi_device *dev, unsigned long iobase,
+				unsigned int irq, unsigned long req_irq_flags)
 {
+	const struct dio200_board *thisboard = comedi_board(dev);
+	struct dio200_private *devpriv = dev->private;
+	const struct dio200_layout_struct *layout =
+		&dio200_layouts[thisboard->layout];
 	struct comedi_subdevice *s;
-	unsigned long iobase = 0;
-	unsigned int irq = 0;
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
-	struct pci_dev *pci_dev = NULL;
-	int bus = 0, slot = 0;
-#endif
-	const struct dio200_layout_struct *layout;
-	int share_irq = 0;
 	int sdx;
-	unsigned n;
+	unsigned int n;
 	int ret;
 
-	printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
-	       DIO200_DRIVER_NAME);
-
-	ret = alloc_private(dev, sizeof(struct dio200_private));
-	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
-		return ret;
-	}
-
-	/* Process options. */
-	switch (thisboard->bustype) {
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
-	case isa_bustype:
-		iobase = it->options[0];
-		irq = it->options[1];
-		share_irq = 0;
-		break;
-#endif
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
-	case pci_bustype:
-		bus = it->options[0];
-		slot = it->options[1];
-		share_irq = 1;
-
-		ret = dio200_find_pci(dev, bus, slot, &pci_dev);
-		if (ret < 0)
-			return ret;
-		devpriv->pci_dev = pci_dev;
-		break;
-#endif
-	default:
-		printk(KERN_ERR
-		       "comedi%d: %s: BUG! cannot determine board type!\n",
-		       dev->minor, DIO200_DRIVER_NAME);
-		return -EINVAL;
-		break;
-	}
-
 	devpriv->intr_sd = -1;
-
-	/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
-	if (pci_dev) {
-		ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
-		if (ret < 0) {
-			printk(KERN_ERR
-			       "comedi%d: error! cannot enable PCI device and request regions!\n",
-			       dev->minor);
-			return ret;
-		}
-		iobase = pci_resource_start(pci_dev, 2);
-		irq = pci_dev->irq;
-	} else
-#endif
-	{
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
-		ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
-		if (ret < 0)
-			return ret;
-#endif
-	}
 	dev->iobase = iobase;
+	dev->board_name = thisboard->name;
 
-	layout = thislayout;
-
-	ret = alloc_subdevices(dev, layout->n_subdevs);
-	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
+	ret = comedi_alloc_subdevices(dev, layout->n_subdevs);
+	if (ret)
 		return ret;
-	}
 
 	for (n = 0; n < dev->n_subdevices; n++) {
 		s = &dev->subdevices[n];
@@ -1441,7 +1288,6 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 						      layout->has_clk_gat_sce);
 			if (ret < 0)
 				return ret;
-
 			break;
 		case sd_8255:
 			/* digital i/o subdevice (8255) */
@@ -1449,7 +1295,6 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 					       iobase + layout->sdinfo[n]);
 			if (ret < 0)
 				return ret;
-
 			break;
 		case sd_intr:
 			/* 'INTERRUPT' subdevice */
@@ -1462,7 +1307,6 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 							      has_int_sce);
 				if (ret < 0)
 					return ret;
-
 				devpriv->intr_sd = n;
 			} else {
 				s->type = COMEDI_SUBD_UNUSED;
@@ -1473,60 +1317,128 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 			break;
 		}
 	}
-
 	sdx = devpriv->intr_sd;
 	if (sdx >= 0 && sdx < dev->n_subdevices)
 		dev->read_subdev = &dev->subdevices[sdx];
-
-	dev->board_name = thisboard->name;
-
 	if (irq) {
-		unsigned long flags = share_irq ? IRQF_SHARED : 0;
-
-		if (request_irq(irq, dio200_interrupt, flags,
+		if (request_irq(irq, dio200_interrupt, req_irq_flags,
 				DIO200_DRIVER_NAME, dev) >= 0) {
 			dev->irq = irq;
 		} else {
-			printk(KERN_WARNING
-			       "comedi%d: warning! irq %u unavailable!\n",
-			       dev->minor, irq);
+			dev_warn(dev->class_dev,
+				 "warning! irq %u unavailable!\n", irq);
 		}
 	}
+	dio200_report_attach(dev, irq);
+	return 1;
+}
 
-	printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
-	switch (thisboard->bustype) {
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
-	case isa_bustype:
-		printk("(base %#lx) ", iobase);
-		break;
-#endif
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
-	case pci_bustype:
-		printk("(pci %s) ", pci_name(pci_dev));
-		break;
-#endif
-	default:
-		break;
+static int dio200_pci_common_attach(struct comedi_device *dev,
+				    struct pci_dev *pci_dev)
+{
+	struct dio200_private *devpriv = dev->private;
+	unsigned long iobase;
+	int ret;
+
+	devpriv->pci_dev = pci_dev;
+	ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
+	if (ret < 0) {
+		dev_err(dev->class_dev,
+			"error! cannot enable PCI device and request regions!\n");
+		return ret;
 	}
-	if (irq)
-		printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
-	else
-		printk("(no irq) ");
+	iobase = pci_resource_start(pci_dev, 2);
+	return dio200_common_attach(dev, iobase, pci_dev->irq, IRQF_SHARED);
+}
+
+/*
+ * Attach is called by the Comedi core to configure the driver
+ * for a particular board.  If you specified a board_name array
+ * in the driver structure, dev->board_ptr contains that
+ * address.
+ */
+static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	const struct dio200_board *thisboard = comedi_board(dev);
+	int ret;
 
-	printk("attached\n");
+	dev_info(dev->class_dev, DIO200_DRIVER_NAME ": attach\n");
 
-	return 1;
+	ret = alloc_private(dev, sizeof(struct dio200_private));
+	if (ret < 0) {
+		dev_err(dev->class_dev, "error! out of memory!\n");
+		return ret;
+	}
+
+	/* Process options and reserve resources according to bus type. */
+	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) &&
+	    thisboard->bustype == isa_bustype) {
+		unsigned long iobase;
+		unsigned int irq;
+
+		iobase = it->options[0];
+		irq = it->options[1];
+		ret = dio200_request_region(dev, iobase, DIO200_IO_SIZE);
+		if (ret < 0)
+			return ret;
+		return dio200_common_attach(dev, iobase, irq, 0);
+	} else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) &&
+		   thisboard->bustype == pci_bustype) {
+		struct pci_dev *pci_dev;
+		int bus, slot;
+
+		bus = it->options[0];
+		slot = it->options[1];
+		pci_dev = dio200_find_pci(dev, bus, slot);
+		if (pci_dev == NULL)
+			return -EIO;
+		return dio200_pci_common_attach(dev, pci_dev);
+	} else {
+		dev_err(dev->class_dev, DIO200_DRIVER_NAME
+			": BUG! cannot determine board type!\n");
+		return -EINVAL;
+	}
+}
+
+/*
+ * The attach_pci hook (if non-NULL) is called at PCI probe time in preference
+ * to the "manual" attach hook.  dev->board_ptr is NULL on entry.  There should
+ * be a board entry matching the supplied PCI device.
+ */
+static int __devinit dio200_attach_pci(struct comedi_device *dev,
+				       struct pci_dev *pci_dev)
+{
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI))
+		return -EINVAL;
+
+	dev_info(dev->class_dev, DIO200_DRIVER_NAME ": attach pci %s\n",
+		 pci_name(pci_dev));
+	ret = alloc_private(dev, sizeof(struct dio200_private));
+	if (ret < 0) {
+		dev_err(dev->class_dev, "error! out of memory!\n");
+		return ret;
+	}
+	dev->board_ptr = dio200_find_pci_board(pci_dev);
+	if (dev->board_ptr == NULL) {
+		dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
+		return -EINVAL;
+	}
+	return dio200_pci_common_attach(dev, pci_dev);
 }
 
 static void dio200_detach(struct comedi_device *dev)
 {
+	const struct dio200_board *thisboard = comedi_board(dev);
+	struct dio200_private *devpriv = dev->private;
 	const struct dio200_layout_struct *layout;
 	unsigned n;
 
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->subdevices) {
-		layout = thislayout;
+		layout = &dio200_layouts[thisboard->layout];
 		for (n = 0; n < dev->n_subdevices; n++) {
 			struct comedi_subdevice *s = &dev->subdevices[n];
 			switch (layout->sdtype[n]) {
@@ -1545,22 +1457,70 @@ static void dio200_detach(struct comedi_device *dev)
 		}
 	}
 	if (devpriv) {
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
-		if (devpriv->pci_dev) {
-			if (dev->iobase)
-				comedi_pci_disable(devpriv->pci_dev);
-			pci_dev_put(devpriv->pci_dev);
-		} else
-#endif
-		{
-#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
+		if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) &&
+		    thisboard->bustype == pci_bustype) {
+			if (devpriv->pci_dev) {
+				if (dev->iobase)
+					comedi_pci_disable(devpriv->pci_dev);
+				pci_dev_put(devpriv->pci_dev);
+			}
+		} else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) &&
+			   thisboard->bustype == isa_bustype) {
 			if (dev->iobase)
 				release_region(dev->iobase, DIO200_IO_SIZE);
-#endif
 		}
 	}
 }
 
+/*
+ * The struct comedi_driver structure tells the Comedi core module
+ * which functions to call to configure/deconfigure (attach/detach)
+ * the board, and also about the kernel module that contains
+ * the device code.
+ */
+static struct comedi_driver amplc_dio200_driver = {
+	.driver_name = DIO200_DRIVER_NAME,
+	.module = THIS_MODULE,
+	.attach = dio200_attach,
+	.attach_pci = dio200_attach_pci,
+	.detach = dio200_detach,
+	.board_name = &dio200_boards[0].name,
+	.offset = sizeof(struct dio200_board),
+	.num_names = ARRAY_SIZE(dio200_boards),
+};
+
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)
+static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) },
+	{0}
+};
+
+MODULE_DEVICE_TABLE(pci, dio200_pci_table);
+
+static int __devinit amplc_dio200_pci_probe(struct pci_dev *dev,
+						   const struct pci_device_id
+						   *ent)
+{
+	return comedi_pci_auto_config(dev, &amplc_dio200_driver);
+}
+
+static void __devexit amplc_dio200_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver amplc_dio200_pci_driver = {
+	.name = DIO200_DRIVER_NAME,
+	.id_table = dio200_pci_table,
+	.probe = &amplc_dio200_pci_probe,
+	.remove = __devexit_p(&amplc_dio200_pci_remove)
+};
+module_comedi_pci_driver(amplc_dio200_driver, amplc_dio200_pci_driver);
+#else
+module_comedi_driver(amplc_dio200_driver);
+#endif
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index 57ba322..77dae8e 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -56,21 +56,11 @@ unused.
 
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
-
 #include "8255.h"
 #include "plx9052.h"
 
 #define PC236_DRIVER_NAME	"amplc_pc236"
 
-#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA_MODULE
-#define CONFIG_COMEDI_AMPLC_PC236_ISA
-#endif
-
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI_MODULE
-#define CONFIG_COMEDI_AMPLC_PC236_PCI
-#endif
-
 /* PCI236 PCI configuration register information */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI236 0x0009
@@ -108,172 +98,69 @@ enum pc236_model { pc36at_model, pci236_model, anypci_model };
 
 struct pc236_board {
 	const char *name;
-	const char *fancy_name;
 	unsigned short devid;
 	enum pc236_bustype bustype;
 	enum pc236_model model;
 };
 static const struct pc236_board pc236_boards[] = {
-#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA)
 	{
-	 .name = "pc36at",
-	 .fancy_name = "PC36AT",
-	 .bustype = isa_bustype,
-	 .model = pc36at_model,
-	 },
+		.name = "pc36at",
+		.bustype = isa_bustype,
+		.model = pc36at_model,
+	},
 #endif
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI)
 	{
-	 .name = "pci236",
-	 .fancy_name = "PCI236",
-	 .devid = PCI_DEVICE_ID_AMPLICON_PCI236,
-	 .bustype = pci_bustype,
-	 .model = pci236_model,
-	 },
+		.name = "pci236",
+		.devid = PCI_DEVICE_ID_AMPLICON_PCI236,
+		.bustype = pci_bustype,
+		.model = pci236_model,
+	},
 	{
-	 .name = PC236_DRIVER_NAME,
-	 .fancy_name = PC236_DRIVER_NAME,
-	 .devid = PCI_DEVICE_ID_INVALID,
-	 .bustype = pci_bustype,
-	 .model = anypci_model,	/* wildcard */
-	 },
+		.name = PC236_DRIVER_NAME,
+		.devid = PCI_DEVICE_ID_INVALID,
+		.bustype = pci_bustype,
+		.model = anypci_model,	/* wildcard */
+	},
 #endif
 };
 
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
-static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, pc236_pci_table);
-#endif /* CONFIG_COMEDI_AMPLC_PC236_PCI */
-
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct pc236_board *)dev->board_ptr)
-
 /* this structure is for data unique to this hardware driver.  If
    several hardware drivers keep similar information in this structure,
    feel free to suggest moving the variable to the struct comedi_device struct.
  */
 struct pc236_private {
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
 	/* PCI device */
 	struct pci_dev *pci_dev;
 	unsigned long lcr_iobase; /* PLX PCI9052 config registers in PCIBAR1 */
-#endif
 	int enable_irq;
 };
 
-#define devpriv ((struct pc236_private *)dev->private)
-
 /*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
+ * This function looks for a board matching the supplied PCI device.
  */
-static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static void pc236_detach(struct comedi_device *dev);
-static struct comedi_driver driver_amplc_pc236 = {
-	.driver_name = PC236_DRIVER_NAME,
-	.module = THIS_MODULE,
-	.attach = pc236_attach,
-	.detach = pc236_detach,
-	.board_name = &pc236_boards[0].name,
-	.offset = sizeof(struct pc236_board),
-	.num_names = ARRAY_SIZE(pc236_boards),
-};
-
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
-static int __devinit driver_amplc_pc236_pci_probe(struct pci_dev *dev,
-						  const struct pci_device_id
-						  *ent)
-{
-	return comedi_pci_auto_config(dev, &driver_amplc_pc236);
-}
-
-static void __devexit driver_amplc_pc236_pci_remove(struct pci_dev *dev)
-{
-	comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_amplc_pc236_pci_driver = {
-	.id_table = pc236_pci_table,
-	.probe = &driver_amplc_pc236_pci_probe,
-	.remove = __devexit_p(&driver_amplc_pc236_pci_remove)
-};
-
-static int __init driver_amplc_pc236_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_amplc_pc236);
-	if (retval < 0)
-		return retval;
-
-	driver_amplc_pc236_pci_driver.name =
-	    (char *)driver_amplc_pc236.driver_name;
-	return pci_register_driver(&driver_amplc_pc236_pci_driver);
-}
-
-static void __exit driver_amplc_pc236_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_amplc_pc236_pci_driver);
-	comedi_driver_unregister(&driver_amplc_pc236);
-}
-
-module_init(driver_amplc_pc236_init_module);
-module_exit(driver_amplc_pc236_cleanup_module);
-#else
-static int __init driver_amplc_pc236_init_module(void)
+static const struct pc236_board *pc236_find_pci_board(struct pci_dev *pci_dev)
 {
-	return comedi_driver_register(&driver_amplc_pc236);
-}
+	unsigned int i;
 
-static void __exit driver_amplc_pc236_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_amplc_pc236);
+	for (i = 0; i < ARRAY_SIZE(pc236_boards); i++)
+		if (pc236_boards[i].bustype == pci_bustype &&
+		    pci_dev->device == pc236_boards[i].devid)
+			return &pc236_boards[i];
+	return NULL;
 }
 
-module_init(driver_amplc_pc236_init_module);
-module_exit(driver_amplc_pc236_cleanup_module);
-#endif
-
-#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
-static int pc236_request_region(unsigned minor, unsigned long from,
-				unsigned long extent);
-#endif
-static void pc236_intr_disable(struct comedi_device *dev);
-static void pc236_intr_enable(struct comedi_device *dev);
-static int pc236_intr_check(struct comedi_device *dev);
-static int pc236_intr_insn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
-			   unsigned int *data);
-static int pc236_intr_cmdtest(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_cmd *cmd);
-static int pc236_intr_cmd(struct comedi_device *dev,
-			  struct comedi_subdevice *s);
-static int pc236_intr_cancel(struct comedi_device *dev,
-			     struct comedi_subdevice *s);
-static irqreturn_t pc236_interrupt(int irq, void *d);
-
 /*
  * This function looks for a PCI device matching the requested board name,
  * bus and slot.
  */
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
-static int
-pc236_find_pci(struct comedi_device *dev, int bus, int slot,
-	       struct pci_dev **pci_dev_p)
+static struct pci_dev *
+pc236_find_pci(struct comedi_device *dev, int bus, int slot)
 {
+	const struct pc236_board *thisboard = comedi_board(dev);
 	struct pci_dev *pci_dev = NULL;
 
-	*pci_dev_p = NULL;
-
 	/* Look for matching PCI device. */
 	for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
 	     pci_dev != NULL;
@@ -286,20 +173,13 @@ pc236_find_pci(struct comedi_device *dev, int bus, int slot,
 				continue;
 		}
 		if (thisboard->model == anypci_model) {
-			/* Match any supported model. */
-			int i;
-
-			for (i = 0; i < ARRAY_SIZE(pc236_boards); i++) {
-				if (pc236_boards[i].bustype != pci_bustype)
-					continue;
-				if (pci_dev->device == pc236_boards[i].devid) {
-					/* Change board_ptr to matched board. */
-					dev->board_ptr = &pc236_boards[i];
-					break;
-				}
-			}
-			if (i == ARRAY_SIZE(pc236_boards))
+			/* Wildcard board matches any supported PCI board. */
+			const struct pc236_board *foundboard;
+			foundboard = pc236_find_pci_board(pci_dev);
+			if (foundboard == NULL)
 				continue;
+			/* Replace wildcard board_ptr. */
+			dev->board_ptr = thisboard = foundboard;
 		} else {
 			/* Match specific model name. */
 			if (pci_dev->device != thisboard->devid)
@@ -307,217 +187,34 @@ pc236_find_pci(struct comedi_device *dev, int bus, int slot,
 		}
 
 		/* Found a match. */
-		*pci_dev_p = pci_dev;
-		return 0;
+		return pci_dev;
 	}
 	/* No match found. */
 	if (bus || slot) {
-		printk(KERN_ERR
-		       "comedi%d: error! no %s found at pci %02x:%02x!\n",
-		       dev->minor, thisboard->name, bus, slot);
+		dev_err(dev->class_dev,
+			"error! no %s found at pci %02x:%02x!\n",
+			thisboard->name, bus, slot);
 	} else {
-		printk(KERN_ERR "comedi%d: error! no %s found!\n",
-		       dev->minor, thisboard->name);
-	}
-	return -EIO;
-}
-#endif
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	unsigned long iobase = 0;
-	unsigned int irq = 0;
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
-	struct pci_dev *pci_dev = NULL;
-	int bus = 0, slot = 0;
-#endif
-	int share_irq = 0;
-	int ret;
-
-	printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
-	       PC236_DRIVER_NAME);
-/*
- * Allocate the private structure area.  alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
-	ret = alloc_private(dev, sizeof(struct pc236_private));
-	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
-		return ret;
-	}
-	/* Process options. */
-	switch (thisboard->bustype) {
-#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
-	case isa_bustype:
-		iobase = it->options[0];
-		irq = it->options[1];
-		share_irq = 0;
-		break;
-#endif
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
-	case pci_bustype:
-		bus = it->options[0];
-		slot = it->options[1];
-		share_irq = 1;
-
-		ret = pc236_find_pci(dev, bus, slot, &pci_dev);
-		if (ret < 0)
-			return ret;
-		devpriv->pci_dev = pci_dev;
-		break;
-#endif
-	default:
-		printk(KERN_ERR
-		       "comedi%d: %s: BUG! cannot determine board type!\n",
-		       dev->minor, PC236_DRIVER_NAME);
-		return -EINVAL;
-		break;
-	}
-
-/*
- * Initialize dev->board_name.
- */
-	dev->board_name = thisboard->name;
-
-	/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
-	if (pci_dev) {
-
-		ret = comedi_pci_enable(pci_dev, PC236_DRIVER_NAME);
-		if (ret < 0) {
-			printk(KERN_ERR
-			       "comedi%d: error! cannot enable PCI device and request regions!\n",
-			       dev->minor);
-			return ret;
-		}
-		devpriv->lcr_iobase = pci_resource_start(pci_dev, 1);
-		iobase = pci_resource_start(pci_dev, 2);
-		irq = pci_dev->irq;
-	} else
-#endif
-	{
-#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
-		ret = pc236_request_region(dev->minor, iobase, PC236_IO_SIZE);
-		if (ret < 0)
-			return ret;
-#endif
-	}
-	dev->iobase = iobase;
-
-/*
- * Allocate the subdevice structures.  alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
-	ret = alloc_subdevices(dev, 2);
-	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
-		return ret;
-	}
-
-	s = dev->subdevices + 0;
-	/* digital i/o subdevice (8255) */
-	ret = subdev_8255_init(dev, s, NULL, iobase);
-	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
-		return ret;
-	}
-	s = dev->subdevices + 1;
-	dev->read_subdev = s;
-	s->type = COMEDI_SUBD_UNUSED;
-	pc236_intr_disable(dev);
-	if (irq) {
-		unsigned long flags = share_irq ? IRQF_SHARED : 0;
-
-		if (request_irq(irq, pc236_interrupt, flags,
-				PC236_DRIVER_NAME, dev) >= 0) {
-			dev->irq = irq;
-			s->type = COMEDI_SUBD_DI;
-			s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
-			s->n_chan = 1;
-			s->maxdata = 1;
-			s->range_table = &range_digital;
-			s->insn_bits = pc236_intr_insn;
-			s->do_cmdtest = pc236_intr_cmdtest;
-			s->do_cmd = pc236_intr_cmd;
-			s->cancel = pc236_intr_cancel;
-		}
-	}
-	printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
-	switch (thisboard->bustype) {
-#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
-	case isa_bustype:
-		printk("(base %#lx) ", iobase);
-		break;
-#endif
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
-	case pci_bustype:
-		printk("(pci %s) ", pci_name(pci_dev));
-		break;
-#endif
-	default:
-		break;
-	}
-	if (irq)
-		printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
-	else
-		printk("(no irq) ");
-
-	printk("attached\n");
-
-	return 1;
-}
-
-static void pc236_detach(struct comedi_device *dev)
-{
-	if (devpriv)
-		pc236_intr_disable(dev);
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-	if (dev->subdevices)
-		subdev_8255_cleanup(dev, dev->subdevices + 0);
-	if (devpriv) {
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
-		if (devpriv->pci_dev) {
-			if (dev->iobase)
-				comedi_pci_disable(devpriv->pci_dev);
-			pci_dev_put(devpriv->pci_dev);
-		} else
-#endif
-		{
-#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
-			if (dev->iobase)
-				release_region(dev->iobase, PC236_IO_SIZE);
-#endif
-		}
+		dev_err(dev->class_dev, "error! no %s found!\n",
+			thisboard->name);
 	}
+	return NULL;
 }
 
 /*
  * This function checks and requests an I/O region, reporting an error
  * if there is a conflict.
  */
-#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
-static int pc236_request_region(unsigned minor, unsigned long from,
+static int pc236_request_region(struct comedi_device *dev, unsigned long from,
 				unsigned long extent)
 {
 	if (!from || !request_region(from, extent, PC236_DRIVER_NAME)) {
-		printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
-		       minor, from, extent);
+		dev_err(dev->class_dev, "I/O port conflict (%#lx,%lu)!\n",
+		       from, extent);
 		return -EIO;
 	}
 	return 0;
 }
-#endif
 
 /*
  * This function is called to mark the interrupt as disabled (no command
@@ -526,14 +223,13 @@ static int pc236_request_region(unsigned minor, unsigned long from,
  */
 static void pc236_intr_disable(struct comedi_device *dev)
 {
+	struct pc236_private *devpriv = dev->private;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->spinlock, flags);
 	devpriv->enable_irq = 0;
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
-	if (devpriv->lcr_iobase)
+	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) && devpriv->lcr_iobase)
 		outl(PCI236_INTR_DISABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
-#endif
 	spin_unlock_irqrestore(&dev->spinlock, flags);
 }
 
@@ -544,14 +240,13 @@ static void pc236_intr_disable(struct comedi_device *dev)
  */
 static void pc236_intr_enable(struct comedi_device *dev)
 {
+	struct pc236_private *devpriv = dev->private;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->spinlock, flags);
 	devpriv->enable_irq = 1;
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
-	if (devpriv->lcr_iobase)
+	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) && devpriv->lcr_iobase)
 		outl(PCI236_INTR_ENABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
-#endif
 	spin_unlock_irqrestore(&dev->spinlock, flags);
 }
 
@@ -564,14 +259,15 @@ static void pc236_intr_enable(struct comedi_device *dev)
  */
 static int pc236_intr_check(struct comedi_device *dev)
 {
+	struct pc236_private *devpriv = dev->private;
 	int retval = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->spinlock, flags);
 	if (devpriv->enable_irq) {
 		retval = 1;
-#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
-		if (devpriv->lcr_iobase) {
+		if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) &&
+		    devpriv->lcr_iobase) {
 			if ((inl(devpriv->lcr_iobase + PLX9052_INTCSR)
 			     & PLX9052_INTCSR_LI1STAT_MASK)
 			    == PLX9052_INTCSR_LI1STAT_INACTIVE) {
@@ -582,7 +278,6 @@ static int pc236_intr_check(struct comedi_device *dev)
 				     devpriv->lcr_iobase + PLX9052_INTCSR);
 			}
 		}
-#endif
 	}
 	spin_unlock_irqrestore(&dev->spinlock, flags);
 
@@ -598,7 +293,7 @@ static int pc236_intr_insn(struct comedi_device *dev,
 			   unsigned int *data)
 {
 	data[1] = 0;
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -721,6 +416,240 @@ static irqreturn_t pc236_interrupt(int irq, void *d)
 	return IRQ_RETVAL(handled);
 }
 
+static void pc236_report_attach(struct comedi_device *dev, unsigned int irq)
+{
+	const struct pc236_board *thisboard = comedi_board(dev);
+	char tmpbuf[60];
+	int tmplen;
+
+	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA) &&
+	    thisboard->bustype == isa_bustype)
+		tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
+				   "(base %#lx) ", dev->iobase);
+	else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) &&
+		 thisboard->bustype == pci_bustype) {
+		struct pc236_private *devpriv = dev->private;
+		struct pci_dev *pci_dev = devpriv->pci_dev;
+		tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
+				   "(pci %s) ", pci_name(pci_dev));
+	} else
+		tmplen = 0;
+	if (irq)
+		tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
+				    "(irq %u%s) ", irq,
+				    (dev->irq ? "" : " UNAVAILABLE"));
+	else
+		tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
+				    "(no irq) ");
+	dev_info(dev->class_dev, "%s %sattached\n",
+		 dev->board_name, tmpbuf);
+}
+
+static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase,
+			       unsigned int irq, unsigned long req_irq_flags)
+{
+	const struct pc236_board *thisboard = comedi_board(dev);
+	struct comedi_subdevice *s;
+	int ret;
+
+	dev->board_name = thisboard->name;
+	dev->iobase = iobase;
+
+	ret = comedi_alloc_subdevices(dev, 2);
+	if (ret)
+		return ret;
+
+	s = dev->subdevices + 0;
+	/* digital i/o subdevice (8255) */
+	ret = subdev_8255_init(dev, s, NULL, iobase);
+	if (ret < 0) {
+		dev_err(dev->class_dev, "error! out of memory!\n");
+		return ret;
+	}
+	s = dev->subdevices + 1;
+	dev->read_subdev = s;
+	s->type = COMEDI_SUBD_UNUSED;
+	pc236_intr_disable(dev);
+	if (irq) {
+		if (request_irq(irq, pc236_interrupt, req_irq_flags,
+				PC236_DRIVER_NAME, dev) >= 0) {
+			dev->irq = irq;
+			s->type = COMEDI_SUBD_DI;
+			s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
+			s->n_chan = 1;
+			s->maxdata = 1;
+			s->range_table = &range_digital;
+			s->insn_bits = pc236_intr_insn;
+			s->do_cmdtest = pc236_intr_cmdtest;
+			s->do_cmd = pc236_intr_cmd;
+			s->cancel = pc236_intr_cancel;
+		}
+	}
+	pc236_report_attach(dev, irq);
+	return 1;
+}
+
+static int pc236_pci_common_attach(struct comedi_device *dev,
+				   struct pci_dev *pci_dev)
+{
+	struct pc236_private *devpriv = dev->private;
+	unsigned long iobase;
+	int ret;
+
+	devpriv->pci_dev = pci_dev;
+	ret = comedi_pci_enable(pci_dev, PC236_DRIVER_NAME);
+	if (ret < 0) {
+		dev_err(dev->class_dev,
+			"error! cannot enable PCI device and request regions!\n");
+		return ret;
+	}
+	devpriv->lcr_iobase = pci_resource_start(pci_dev, 1);
+	iobase = pci_resource_start(pci_dev, 2);
+	return pc236_common_attach(dev, iobase, pci_dev->irq, IRQF_SHARED);
+}
+
+/*
+ * Attach is called by the Comedi core to configure the driver
+ * for a particular board.  If you specified a board_name array
+ * in the driver structure, dev->board_ptr contains that
+ * address.
+ */
+static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	const struct pc236_board *thisboard = comedi_board(dev);
+	int ret;
+
+	dev_info(dev->class_dev, PC236_DRIVER_NAME ": attach\n");
+	ret = alloc_private(dev, sizeof(struct pc236_private));
+	if (ret < 0) {
+		dev_err(dev->class_dev, "error! out of memory!\n");
+		return ret;
+	}
+	/* Process options according to bus type. */
+	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA) &&
+	    thisboard->bustype == isa_bustype) {
+		unsigned long iobase = it->options[0];
+		unsigned int irq = it->options[1];
+		ret = pc236_request_region(dev, iobase, PC236_IO_SIZE);
+		if (ret < 0)
+			return ret;
+		return pc236_common_attach(dev, iobase, irq, 0);
+	} else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) &&
+		   thisboard->bustype == pci_bustype) {
+		int bus = it->options[0];
+		int slot = it->options[1];
+		struct pci_dev *pci_dev;
+
+		pci_dev = pc236_find_pci(dev, bus, slot);
+		if (pci_dev == NULL)
+			return -EIO;
+		return pc236_pci_common_attach(dev, pci_dev);
+	} else {
+		dev_err(dev->class_dev, PC236_DRIVER_NAME
+			": BUG! cannot determine board type!\n");
+		return -EINVAL;
+	}
+}
+
+/*
+ * The attach_pci hook (if non-NULL) is called at PCI probe time in preference
+ * to the "manual" attach hook.  dev->board_ptr is NULL on entry.  There should
+ * be a board entry matching the supplied PCI device.
+ */
+static int __devinit pc236_attach_pci(struct comedi_device *dev,
+				      struct pci_dev *pci_dev)
+{
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI))
+		return -EINVAL;
+
+	dev_info(dev->class_dev, PC236_DRIVER_NAME ": attach pci %s\n",
+		 pci_name(pci_dev));
+	ret = alloc_private(dev, sizeof(struct pc236_private));
+	if (ret < 0) {
+		dev_err(dev->class_dev, "error! out of memory!\n");
+		return ret;
+	}
+	dev->board_ptr = pc236_find_pci_board(pci_dev);
+	if (dev->board_ptr == NULL) {
+		dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
+		return -EINVAL;
+	}
+	return pc236_pci_common_attach(dev, pci_dev);
+}
+
+static void pc236_detach(struct comedi_device *dev)
+{
+	struct pc236_private *devpriv = dev->private;
+
+	if (devpriv)
+		pc236_intr_disable(dev);
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (dev->subdevices)
+		subdev_8255_cleanup(dev, dev->subdevices + 0);
+	if (devpriv) {
+		if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) &&
+		    devpriv->pci_dev) {
+			if (dev->iobase)
+				comedi_pci_disable(devpriv->pci_dev);
+			pci_dev_put(devpriv->pci_dev);
+		} else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA)) {
+			if (dev->iobase)
+				release_region(dev->iobase, PC236_IO_SIZE);
+		}
+	}
+}
+
+/*
+ * The struct comedi_driver structure tells the Comedi core module
+ * which functions to call to configure/deconfigure (attach/detach)
+ * the board, and also about the kernel module that contains
+ * the device code.
+ */
+static struct comedi_driver amplc_pc236_driver = {
+	.driver_name = PC236_DRIVER_NAME,
+	.module = THIS_MODULE,
+	.attach = pc236_attach,
+	.attach_pci = pc236_attach_pci,
+	.detach = pc236_detach,
+	.board_name = &pc236_boards[0].name,
+	.offset = sizeof(struct pc236_board),
+	.num_names = ARRAY_SIZE(pc236_boards),
+};
+
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI)
+static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) },
+	{0}
+};
+
+MODULE_DEVICE_TABLE(pci, pc236_pci_table);
+
+static int __devinit amplc_pc236_pci_probe(struct pci_dev *dev,
+					   const struct pci_device_id *ent)
+{
+	return comedi_pci_auto_config(dev, &amplc_pc236_driver);
+}
+
+static void __devexit amplc_pc236_pci_remove(struct pci_dev *dev)
+{
+	comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver amplc_pc236_pci_driver = {
+	.name = PC236_DRIVER_NAME,
+	.id_table = pc236_pci_table,
+	.probe = &amplc_pc236_pci_probe,
+	.remove = __devexit_p(&amplc_pc236_pci_remove)
+};
+
+module_comedi_pci_driver(amplc_pc236_driver, amplc_pc236_pci_driver);
+#else
+module_comedi_driver(amplc_pc236_driver);
+#endif
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 974d745..e90178d 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -46,18 +46,8 @@ The state of the outputs can be read.
 
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
-
 #define PC263_DRIVER_NAME	"amplc_pc263"
 
-#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA_MODULE
-#define CONFIG_COMEDI_AMPLC_PC263_ISA
-#endif
-
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI_MODULE
-#define CONFIG_COMEDI_AMPLC_PC263_PCI
-#endif
-
 /* PCI263 PCI configuration register information */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c
@@ -75,107 +65,68 @@ enum pc263_model { pc263_model, pci263_model, anypci_model };
 
 struct pc263_board {
 	const char *name;
-	const char *fancy_name;
 	unsigned short devid;
 	enum pc263_bustype bustype;
 	enum pc263_model model;
 };
 static const struct pc263_board pc263_boards[] = {
-#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA)
 	{
-	 .name = "pc263",
-	 .fancy_name = "PC263",
-	 .bustype = isa_bustype,
-	 .model = pc263_model,
-	 },
+		.name = "pc263",
+		.bustype = isa_bustype,
+		.model = pc263_model,
+	},
 #endif
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)
 	{
-	 .name = "pci263",
-	 .fancy_name = "PCI263",
-	 .devid = PCI_DEVICE_ID_AMPLICON_PCI263,
-	 .bustype = pci_bustype,
-	 .model = pci263_model,
-	 },
+		.name = "pci263",
+		.devid = PCI_DEVICE_ID_AMPLICON_PCI263,
+		.bustype = pci_bustype,
+		.model = pci263_model,
+	},
 	{
-	 .name = PC263_DRIVER_NAME,
-	 .fancy_name = PC263_DRIVER_NAME,
-	 .devid = PCI_DEVICE_ID_INVALID,
-	 .bustype = pci_bustype,
-	 .model = anypci_model,	/* wildcard */
-	 },
+		.name = PC263_DRIVER_NAME,
+		.devid = PCI_DEVICE_ID_INVALID,
+		.bustype = pci_bustype,
+		.model = anypci_model,	/* wildcard */
+	},
 #endif
 };
 
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
-static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, pc263_pci_table);
-#endif /* CONFIG_COMEDI_AMPLC_PC263_PCI */
-
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct pc263_board *)dev->board_ptr)
-
 /* this structure is for data unique to this hardware driver.  If
    several hardware drivers keep similar information in this structure,
    feel free to suggest moving the variable to the struct comedi_device struct.
 */
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
 struct pc263_private {
 	/* PCI device. */
 	struct pci_dev *pci_dev;
 };
 
-#define devpriv ((struct pc263_private *)dev->private)
-#endif /* CONFIG_COMEDI_AMPLC_PC263_PCI */
-
 /*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
+ * This function looks for a board matching the supplied PCI device.
  */
-static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static void pc263_detach(struct comedi_device *dev);
-static struct comedi_driver driver_amplc_pc263 = {
-	.driver_name = PC263_DRIVER_NAME,
-	.module = THIS_MODULE,
-	.attach = pc263_attach,
-	.detach = pc263_detach,
-	.board_name = &pc263_boards[0].name,
-	.offset = sizeof(struct pc263_board),
-	.num_names = ARRAY_SIZE(pc263_boards),
-};
+static const struct pc263_board *pc263_find_pci_board(struct pci_dev *pci_dev)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(pc263_boards); i++)
+		if (pc263_boards[i].bustype == pci_bustype &&
+		    pci_dev->device == pc263_boards[i].devid)
+			return &pc263_boards[i];
+	return NULL;
+}
 
-#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
-static int pc263_request_region(unsigned minor, unsigned long from,
-				unsigned long extent);
-#endif
-static int pc263_dio_insn_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int pc263_dio_insn_config(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data);
 
 /*
  * This function looks for a PCI device matching the requested board name,
  * bus and slot.
  */
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
-static int
-pc263_find_pci(struct comedi_device *dev, int bus, int slot,
-	       struct pci_dev **pci_dev_p)
+static struct pci_dev *
+pc263_find_pci(struct comedi_device *dev, int bus, int slot)
 {
+	const struct pc263_board *thisboard = comedi_board(dev);
 	struct pci_dev *pci_dev = NULL;
 
-	*pci_dev_p = NULL;
-
 	/* Look for matching PCI device. */
 	for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
 	     pci_dev != NULL;
@@ -188,20 +139,13 @@ pc263_find_pci(struct comedi_device *dev, int bus, int slot,
 				continue;
 		}
 		if (thisboard->model == anypci_model) {
-			/* Match any supported model. */
-			int i;
-
-			for (i = 0; i < ARRAY_SIZE(pc263_boards); i++) {
-				if (pc263_boards[i].bustype != pci_bustype)
-					continue;
-				if (pci_dev->device == pc263_boards[i].devid) {
-					/* Change board_ptr to matched board. */
-					dev->board_ptr = &pc263_boards[i];
-					break;
-				}
-			}
-			if (i == ARRAY_SIZE(pc263_boards))
+			/* Wildcard board matches any supported PCI board. */
+			const struct pc263_board *foundboard;
+			foundboard = pc263_find_pci_board(pci_dev);
+			if (foundboard == NULL)
 				continue;
+			/* Replace wildcard board_ptr. */
+			dev->board_ptr = thisboard = foundboard;
 		} else {
 			/* Match specific model name. */
 			if (pci_dev->device != thisboard->devid)
@@ -209,288 +153,245 @@ pc263_find_pci(struct comedi_device *dev, int bus, int slot,
 		}
 
 		/* Found a match. */
-		*pci_dev_p = pci_dev;
-		return 0;
+		return pci_dev;
 	}
 	/* No match found. */
 	if (bus || slot) {
-		printk(KERN_ERR
-		       "comedi%d: error! no %s found at pci %02x:%02x!\n",
-		       dev->minor, thisboard->name, bus, slot);
+		dev_err(dev->class_dev,
+			"error! no %s found at pci %02x:%02x!\n",
+			thisboard->name, bus, slot);
 	} else {
-		printk(KERN_ERR "comedi%d: error! no %s found!\n",
-		       dev->minor, thisboard->name);
+		dev_err(dev->class_dev, "error! no %s found!\n",
+			thisboard->name);
 	}
-	return -EIO;
+	return NULL;
 }
-#endif
-
 /*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
+ * This function checks and requests an I/O region, reporting an error
+ * if there is a conflict.
  */
-static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static int pc263_request_region(struct comedi_device *dev, unsigned long from,
+				unsigned long extent)
 {
-	struct comedi_subdevice *s;
-	unsigned long iobase = 0;
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
-	struct pci_dev *pci_dev = NULL;
-	int bus = 0, slot = 0;
-#endif
-	int ret;
-
-	printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
-	       PC263_DRIVER_NAME);
-/*
- * Allocate the private structure area.  alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
-	ret = alloc_private(dev, sizeof(struct pc263_private));
-	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
-		return ret;
+	if (!from || !request_region(from, extent, PC263_DRIVER_NAME)) {
+		dev_err(dev->class_dev, "I/O port conflict (%#lx,%lu)!\n",
+			from, extent);
+		return -EIO;
 	}
-#endif
-	/* Process options. */
-	switch (thisboard->bustype) {
-#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
-	case isa_bustype:
-		iobase = it->options[0];
-		break;
-#endif
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
-	case pci_bustype:
-		bus = it->options[0];
-		slot = it->options[1];
+	return 0;
+}
 
-		ret = pc263_find_pci(dev, bus, slot, &pci_dev);
-		if (ret < 0)
-			return ret;
-		devpriv->pci_dev = pci_dev;
-		break;
-#endif
-	default:
-		printk(KERN_ERR
-		       "comedi%d: %s: BUG! cannot determine board type!\n",
-		       dev->minor, PC263_DRIVER_NAME);
-		return -EINVAL;
-		break;
+static int pc263_do_insn_bits(struct comedi_device *dev,
+			      struct comedi_subdevice *s,
+			      struct comedi_insn *insn, unsigned int *data)
+{
+	/* The insn data is a mask in data[0] and the new data
+	 * in data[1], each channel cooresponding to a bit. */
+	if (data[0]) {
+		s->state &= ~data[0];
+		s->state |= data[0] & data[1];
+		/* Write out the new digital output lines */
+		outb(s->state & 0xFF, dev->iobase);
+		outb(s->state >> 8, dev->iobase + 1);
 	}
+	return insn->n;
+}
 
-/*
- * Initialize dev->board_name.
- */
-	dev->board_name = thisboard->name;
+static void pc263_report_attach(struct comedi_device *dev)
+{
+	const struct pc263_board *thisboard = comedi_board(dev);
+	struct pc263_private *devpriv = dev->private;
+	char tmpbuf[40];
+
+	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) &&
+	    thisboard->bustype == isa_bustype)
+		snprintf(tmpbuf, sizeof(tmpbuf), "(base %#lx) ", dev->iobase);
+	else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) &&
+		 thisboard->bustype == pci_bustype)
+		snprintf(tmpbuf, sizeof(tmpbuf), "(pci %s) ",
+			 pci_name(devpriv->pci_dev));
+	else
+		tmpbuf[0] = '\0';
+	dev_info(dev->class_dev, "%s %sattached\n", dev->board_name, tmpbuf);
+}
 
-	/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
-	if (pci_dev) {
-		ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME);
-		if (ret < 0) {
-			printk(KERN_ERR
-			       "comedi%d: error! cannot enable PCI device and "
-				"request regions!\n",
-			       dev->minor);
-			return ret;
-		}
-		iobase = pci_resource_start(pci_dev, 2);
-	} else
-#endif
-	{
-#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
-		ret = pc263_request_region(dev->minor, iobase, PC263_IO_SIZE);
-		if (ret < 0)
-			return ret;
-#endif
-	}
+static int pc263_common_attach(struct comedi_device *dev, unsigned long iobase)
+{
+	const struct pc263_board *thisboard = comedi_board(dev);
+	struct comedi_subdevice *s;
+	int ret;
+
+	dev->board_name = thisboard->name;
 	dev->iobase = iobase;
 
-/*
- * Allocate the subdevice structures.  alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
-	ret = alloc_subdevices(dev, 1);
-	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
 		return ret;
-	}
 
 	s = dev->subdevices + 0;
-	/* digital i/o subdevice */
-	s->type = COMEDI_SUBD_DIO;
+	/* digital output subdevice */
+	s->type = COMEDI_SUBD_DO;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 	s->n_chan = 16;
 	s->maxdata = 1;
 	s->range_table = &range_digital;
-	s->insn_bits = pc263_dio_insn_bits;
-	s->insn_config = pc263_dio_insn_config;
-	/* all outputs */
-	s->io_bits = 0xffff;
+	s->insn_bits = pc263_do_insn_bits;
 	/* read initial relay state */
-	s->state = inb(dev->iobase);
-	s->state = s->state | (inb(dev->iobase) << 8);
-
-	printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
-	switch (thisboard->bustype) {
-#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
-	case isa_bustype:
-		printk("(base %#lx) ", iobase);
-		break;
-#endif
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
-		printk("(pci %s) ", pci_name(pci_dev));
-		break;
-#endif
-	default:
-		break;
-	}
-
-	printk("attached\n");
+	s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8);
 
+	pc263_report_attach(dev);
 	return 1;
 }
 
-static void pc263_detach(struct comedi_device *dev)
+static int pc263_pci_common_attach(struct comedi_device *dev,
+				   struct pci_dev *pci_dev)
 {
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
-	if (devpriv)
-#endif
-	{
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
-		if (devpriv->pci_dev) {
-			if (dev->iobase)
-				comedi_pci_disable(devpriv->pci_dev);
-			pci_dev_put(devpriv->pci_dev);
-		} else
-#endif
-		{
-#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
-			if (dev->iobase)
-				release_region(dev->iobase, PC263_IO_SIZE);
-#endif
-		}
+	struct pc263_private *devpriv = dev->private;
+	unsigned long iobase;
+	int ret;
+
+	devpriv->pci_dev = pci_dev;
+	ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME);
+	if (ret < 0) {
+		dev_err(dev->class_dev,
+			"error! cannot enable PCI device and request regions!\n");
+		return ret;
 	}
+	iobase = pci_resource_start(pci_dev, 2);
+	return pc263_common_attach(dev, iobase);
 }
 
 /*
- * This function checks and requests an I/O region, reporting an error
- * if there is a conflict.
+ * Attach is called by the Comedi core to configure the driver
+ * for a particular board.  If you specified a board_name array
+ * in the driver structure, dev->board_ptr contains that
+ * address.
  */
-#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
-static int pc263_request_region(unsigned minor, unsigned long from,
-				unsigned long extent)
+static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
-	if (!from || !request_region(from, extent, PC263_DRIVER_NAME)) {
-		printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
-		       minor, from, extent);
-		return -EIO;
+	const struct pc263_board *thisboard = comedi_board(dev);
+	int ret;
+
+	dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach\n");
+
+	/* Process options and reserve resources according to bus type. */
+	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) &&
+	    thisboard->bustype == isa_bustype) {
+		unsigned long iobase = it->options[0];
+		ret = pc263_request_region(dev, iobase, PC263_IO_SIZE);
+		if (ret < 0)
+			return ret;
+		return pc263_common_attach(dev, iobase);
+	} else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) &&
+		   thisboard->bustype == pci_bustype) {
+		struct pci_dev *pci_dev;
+		int bus, slot;
+
+		ret = alloc_private(dev, sizeof(struct pc263_private));
+		if (ret < 0) {
+			dev_err(dev->class_dev, "error! out of memory!\n");
+			return ret;
+		}
+		bus = it->options[0];
+		slot = it->options[1];
+		pci_dev = pc263_find_pci(dev, bus, slot);
+		if (pci_dev == NULL)
+			return -EIO;
+		return pc263_pci_common_attach(dev, pci_dev);
+	} else {
+		dev_err(dev->class_dev, PC263_DRIVER_NAME
+			": BUG! cannot determine board type!\n");
+		return -EINVAL;
 	}
-	return 0;
 }
-#endif
-
-/* DIO devices are slightly special.  Although it is possible to
- * implement the insn_read/insn_write interface, it is much more
- * useful to applications if you implement the insn_bits interface.
- * This allows packed reading/writing of the DIO channels.  The
- * comedi core can convert between insn_bits and insn_read/write */
-static int pc263_dio_insn_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
+/*
+ * The attach_pci hook (if non-NULL) is called at PCI probe time in preference
+ * to the "manual" attach hook.  dev->board_ptr is NULL on entry.  There should
+ * be a board entry matching the supplied PCI device.
+ */
+static int __devinit pc263_attach_pci(struct comedi_device *dev,
+				      struct pci_dev *pci_dev)
 {
-	if (insn->n != 2)
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI))
 		return -EINVAL;
 
-	/* The insn data is a mask in data[0] and the new data
-	 * in data[1], each channel cooresponding to a bit. */
-	if (data[0]) {
-		s->state &= ~data[0];
-		s->state |= data[0] & data[1];
-		/* Write out the new digital output lines */
-		outb(s->state & 0xFF, dev->iobase);
-		outb(s->state >> 8, dev->iobase + 1);
+	dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach pci %s\n",
+		 pci_name(pci_dev));
+	ret = alloc_private(dev, sizeof(struct pc263_private));
+	if (ret < 0) {
+		dev_err(dev->class_dev, "error! out of memory!\n");
+		return ret;
 	}
-
-	/* on return, data[1] contains the value of the digital
-	 * input and output lines. */
-	/* or we could just return the software copy of the output values if
-	 * it was a purely digital output subdevice */
-	data[1] = s->state;
-
-	return 2;
+	dev->board_ptr = pc263_find_pci_board(pci_dev);
+	if (dev->board_ptr == NULL) {
+		dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
+		return -EINVAL;
+	}
+	return pc263_pci_common_attach(dev, pci_dev);
 }
 
-static int pc263_dio_insn_config(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data)
+static void pc263_detach(struct comedi_device *dev)
 {
-	if (insn->n != 1)
-		return -EINVAL;
-	return 1;
+	struct pc263_private *devpriv = dev->private;
+
+	if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) && devpriv &&
+	    devpriv->pci_dev) {
+		if (dev->iobase)
+			comedi_pci_disable(devpriv->pci_dev);
+		pci_dev_put(devpriv->pci_dev);
+	} else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA)) {
+		if (dev->iobase)
+			release_region(dev->iobase, PC263_IO_SIZE);
+	}
 }
 
 /*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * The struct comedi_driver structure tells the Comedi core module
+ * which functions to call to configure/deconfigure (attach/detach)
+ * the board, and also about the kernel module that contains
+ * the device code.
  */
-#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
-static int __devinit driver_amplc_pc263_pci_probe(struct pci_dev *dev,
+static struct comedi_driver amplc_pc263_driver = {
+	.driver_name = PC263_DRIVER_NAME,
+	.module = THIS_MODULE,
+	.attach = pc263_attach,
+	.attach_pci = pc263_attach_pci,
+	.detach = pc263_detach,
+	.board_name = &pc263_boards[0].name,
+	.offset = sizeof(struct pc263_board),
+	.num_names = ARRAY_SIZE(pc263_boards),
+};
+
+#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)
+static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) },
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, pc263_pci_table);
+
+static int __devinit amplc_pc263_pci_probe(struct pci_dev *dev,
 						  const struct pci_device_id
 						  *ent)
 {
-	return comedi_pci_auto_config(dev, &driver_amplc_pc263);
+	return comedi_pci_auto_config(dev, &amplc_pc263_driver);
 }
 
-static void __devexit driver_amplc_pc263_pci_remove(struct pci_dev *dev)
+static void __devexit amplc_pc263_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_amplc_pc263_pci_driver = {
+static struct pci_driver amplc_pc263_pci_driver = {
+	.name = PC263_DRIVER_NAME,
 	.id_table = pc263_pci_table,
-	.probe = &driver_amplc_pc263_pci_probe,
-	.remove = __devexit_p(&driver_amplc_pc263_pci_remove)
+	.probe = &amplc_pc263_pci_probe,
+	.remove = __devexit_p(&amplc_pc263_pci_remove)
 };
-
-static int __init driver_amplc_pc263_init_module(void)
-{
-	int retval;
-
-	retval = comedi_driver_register(&driver_amplc_pc263);
-	if (retval < 0)
-		return retval;
-
-	driver_amplc_pc263_pci_driver.name =
-	    (char *)driver_amplc_pc263.driver_name;
-	return pci_register_driver(&driver_amplc_pc263_pci_driver);
-}
-
-static void __exit driver_amplc_pc263_cleanup_module(void)
-{
-	pci_unregister_driver(&driver_amplc_pc263_pci_driver);
-	comedi_driver_unregister(&driver_amplc_pc263);
-}
-
-module_init(driver_amplc_pc263_init_module);
-module_exit(driver_amplc_pc263_cleanup_module);
+module_comedi_pci_driver(amplc_pc263_driver, amplc_pc263_pci_driver);
 #else
-static int __init driver_amplc_pc263_init_module(void)
-{
-	return comedi_driver_register(&driver_amplc_pc263);
-}
-
-static void __exit driver_amplc_pc263_cleanup_module(void)
-{
-	comedi_driver_unregister(&driver_amplc_pc263);
-}
-
-module_init(driver_amplc_pc263_init_module);
-module_exit(driver_amplc_pc263_cleanup_module);
+module_comedi_driver(amplc_pc263_driver);
 #endif
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index fbf19ca..b87e10d 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -108,8 +108,6 @@ Caveats:
 
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
-
 #include "comedi_fc.h"
 #include "8253.h"
 
@@ -267,9 +265,6 @@ Caveats:
 /* Combine old and new bits. */
 #define COMBINE(old, new, mask)	(((old) & ~(mask)) | ((new) & (mask)))
 
-/* A generic null function pointer value.  */
-#define NULLFUNC	0
-
 /* Current CPU.  XXX should this be hard_smp_processor_id()? */
 #define THISCPU		smp_processor_id()
 
@@ -379,11 +374,6 @@ static const struct pci224_board pci224_boards[] = {
 	 },
 };
 
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((struct pci224_board *)dev->board_ptr)
-
 /* this structure is for data unique to this hardware driver.  If
    several hardware drivers keep similar information in this structure,
    feel free to suggest moving the variable to the struct comedi_device struct.  */
@@ -407,8 +397,6 @@ struct pci224_private {
 	unsigned char intsce;
 };
 
-#define devpriv ((struct pci224_private *)dev->private)
-
 /*
  * Called from the 'insn_write' function to perform a single write.
  */
@@ -416,6 +404,8 @@ static void
 pci224_ao_set_data(struct comedi_device *dev, int chan, int range,
 		   unsigned int data)
 {
+	const struct pci224_board *thisboard = comedi_board(dev);
+	struct pci224_private *devpriv = dev->private;
 	unsigned short mangled;
 
 	/* Store unmangled data for readback. */
@@ -478,6 +468,7 @@ static int
 pci224_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
 		    struct comedi_insn *insn, unsigned int *data)
 {
+	struct pci224_private *devpriv = dev->private;
 	int i;
 	int chan;
 
@@ -506,6 +497,7 @@ pci224_cascade_ns_to_timer(int osc_base, unsigned int *d1, unsigned int *d2,
 static void pci224_ao_stop(struct comedi_device *dev,
 			   struct comedi_subdevice *s)
 {
+	struct pci224_private *devpriv = dev->private;
 	unsigned long flags;
 
 	if (!test_and_clear_bit(AO_CMD_STARTED, &devpriv->state))
@@ -549,6 +541,7 @@ static void pci224_ao_stop(struct comedi_device *dev,
 static void pci224_ao_start(struct comedi_device *dev,
 			    struct comedi_subdevice *s)
 {
+	struct pci224_private *devpriv = dev->private;
 	struct comedi_cmd *cmd = &s->async->cmd;
 	unsigned long flags;
 
@@ -577,6 +570,7 @@ static void pci224_ao_start(struct comedi_device *dev,
 static void pci224_ao_handle_fifo(struct comedi_device *dev,
 				  struct comedi_subdevice *s)
 {
+	struct pci224_private *devpriv = dev->private;
 	struct comedi_cmd *cmd = &s->async->cmd;
 	unsigned int num_scans;
 	unsigned int room;
@@ -628,8 +622,7 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev,
 			/* Nothing left to put in the FIFO. */
 			pci224_ao_stop(dev, s);
 			s->async->events |= COMEDI_CB_OVERFLOW;
-			printk(KERN_ERR "comedi%d: "
-			       "AO buffer underrun\n", dev->minor);
+			dev_err(dev->class_dev, "AO buffer underrun\n");
 		}
 	}
 	/* Determine how many new scans can be put in the FIFO. */
@@ -707,7 +700,7 @@ pci224_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s,
 	if (trignum != 0)
 		return -EINVAL;
 
-	s->async->inttrig = NULLFUNC;
+	s->async->inttrig = NULL;
 	pci224_ao_start(dev, s);
 
 	return 1;
@@ -724,6 +717,7 @@ static int
 pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
 		  struct comedi_cmd *cmd)
 {
+	struct pci224_private *devpriv = dev->private;
 	int err = 0;
 	unsigned int tmp;
 
@@ -994,6 +988,7 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
  */
 static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	struct pci224_private *devpriv = dev->private;
 	struct comedi_cmd *cmd = &s->async->cmd;
 	int range;
 	unsigned int i, j;
@@ -1166,6 +1161,8 @@ static void
 pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
 		void *data, unsigned int num_bytes, unsigned int chan_index)
 {
+	const struct pci224_board *thisboard = comedi_board(dev);
+	struct pci224_private *devpriv = dev->private;
 	struct comedi_async *async = s->async;
 	short *array = data;
 	unsigned int length = num_bytes / sizeof(*array);
@@ -1196,6 +1193,7 @@ pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
 static irqreturn_t pci224_interrupt(int irq, void *d)
 {
 	struct comedi_device *dev = d;
+	struct pci224_private *devpriv = dev->private;
 	struct comedi_subdevice *s = &dev->subdevices[0];
 	struct comedi_cmd *cmd;
 	unsigned char intstat, valid_intstat;
@@ -1258,14 +1256,12 @@ static const struct pci224_board
  * This function looks for a PCI device matching the requested board name,
  * bus and slot.
  */
-static int
-pci224_find_pci(struct comedi_device *dev, int bus, int slot,
-		struct pci_dev **pci_dev_p)
+static struct pci_dev *
+pci224_find_pci(struct comedi_device *dev, int bus, int slot)
 {
+	const struct pci224_board *thisboard = comedi_board(dev);
 	struct pci_dev *pci_dev = NULL;
 
-	*pci_dev_p = NULL;
-
 	/* Look for matching PCI device. */
 	for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
 	     pci_dev != NULL;
@@ -1285,6 +1281,7 @@ pci224_find_pci(struct comedi_device *dev, int bus, int slot,
 				continue;
 			/* Change board_ptr to matched board. */
 			dev->board_ptr = board_ptr;
+			thisboard = comedi_board(dev);
 		} else {
 			/* Match specific model name. */
 			if (thisboard->devid != pci_dev->device)
@@ -1292,19 +1289,32 @@ pci224_find_pci(struct comedi_device *dev, int bus, int slot,
 		}
 
 		/* Found a match. */
-		*pci_dev_p = pci_dev;
-		return 0;
+		return pci_dev;
 	}
 	/* No match found. */
 	if (bus || slot) {
-		printk(KERN_ERR "comedi%d: error! "
-		       "no %s found at pci %02x:%02x!\n",
-		       dev->minor, thisboard->name, bus, slot);
+		dev_err(dev->class_dev,
+			"error! no %s found at pci %02x:%02x!\n",
+			thisboard->name, bus, slot);
 	} else {
-		printk(KERN_ERR "comedi%d: error! no %s found!\n",
-		       dev->minor, thisboard->name);
+		dev_err(dev->class_dev, "error! no %s found!\n",
+			thisboard->name);
 	}
-	return -EIO;
+	return NULL;
+}
+
+static void pci224_report_attach(struct comedi_device *dev, unsigned int irq)
+{
+	struct pci224_private *devpriv = dev->private;
+	char tmpbuf[30];
+
+	if (irq)
+		snprintf(tmpbuf, sizeof(tmpbuf), "irq %u%s", irq,
+			 (dev->irq ? "" : " UNAVAILABLE"));
+	else
+		snprintf(tmpbuf, sizeof(tmpbuf), "no irq");
+	dev_info(dev->class_dev, "%s (pci %s) (%s) attached\n",
+		 dev->board_name, pci_name(devpriv->pci_dev), tmpbuf);
 }
 
 /*
@@ -1313,6 +1323,8 @@ pci224_find_pci(struct comedi_device *dev, int bus, int slot,
 static int pci224_attach_common(struct comedi_device *dev,
 				struct pci_dev *pci_dev, int *options)
 {
+	const struct pci224_board *thisboard = comedi_board(dev);
+	struct pci224_private *devpriv = dev->private;
 	struct comedi_subdevice *s;
 	unsigned int irq;
 	unsigned n;
@@ -1321,9 +1333,9 @@ static int pci224_attach_common(struct comedi_device *dev,
 	devpriv->pci_dev = pci_dev;
 	ret = comedi_pci_enable(pci_dev, DRIVER_NAME);
 	if (ret < 0) {
-		printk(KERN_ERR
-		       "comedi%d: error! cannot enable PCI device "
-		       "and request regions!\n", dev->minor);
+		dev_err(dev->class_dev,
+			"error! cannot enable PCI device and request regions!\n"
+			);
 		return ret;
 	}
 	spin_lock_init(&devpriv->ao_spinlock);
@@ -1367,13 +1379,9 @@ static int pci224_attach_common(struct comedi_device *dev,
 	outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
 	     dev->iobase + PCI224_DACCON);
 
-	/* Allocate subdevices.  There is only one!  */
-	ret = alloc_subdevices(dev, 1);
-	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
 		return ret;
-	}
 
 	s = dev->subdevices + 0;
 	/* Analog output subdevice. */
@@ -1405,10 +1413,9 @@ static int pci224_attach_common(struct comedi_device *dev,
 		if (options) {
 			for (n = 2; n < 3 + s->n_chan; n++) {
 				if (options[n] < 0 || options[n] > 1) {
-					printk(KERN_WARNING
-					       "comedi%d: %s: warning! bad options[%u]=%d\n",
-					       dev->minor, DRIVER_NAME, n,
-					       options[n]);
+					dev_warn(dev->class_dev, DRIVER_NAME
+						 ": warning! bad options[%u]=%d\n",
+						 n, options[n]);
 				}
 			}
 		}
@@ -1437,9 +1444,9 @@ static int pci224_attach_common(struct comedi_device *dev,
 			devpriv->hwrange = hwrange_pci224_external;
 		} else {
 			if (options && options[2] != 0) {
-				printk(KERN_WARNING "comedi%d: %s: warning! "
-				       "bad options[2]=%d\n",
-				       dev->minor, DRIVER_NAME, options[2]);
+				dev_warn(dev->class_dev, DRIVER_NAME
+					 ": warning! bad options[2]=%d\n",
+					 options[2]);
 			}
 			s->range_table = &range_pci224_internal;
 			devpriv->hwrange = hwrange_pci224_internal;
@@ -1452,24 +1459,15 @@ static int pci224_attach_common(struct comedi_device *dev,
 		ret = request_irq(irq, pci224_interrupt, IRQF_SHARED,
 				  DRIVER_NAME, dev);
 		if (ret < 0) {
-			printk(KERN_ERR "comedi%d: error! "
-			       "unable to allocate irq %u\n", dev->minor, irq);
+			dev_err(dev->class_dev,
+				"error! unable to allocate irq %u\n", irq);
 			return ret;
 		} else {
 			dev->irq = irq;
 		}
 	}
 
-	printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
-	printk("(pci %s) ", pci_name(pci_dev));
-	if (irq)
-		printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
-	else
-		printk("(no irq) ");
-
-
-	printk("attached\n");
-
+	pci224_report_attach(dev, irq);
 	return 1;
 }
 
@@ -1479,44 +1477,41 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	int bus, slot;
 	int ret;
 
-	printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DRIVER_NAME);
+	dev_info(dev->class_dev, DRIVER_NAME ": attach\n");
 
 	bus = it->options[0];
 	slot = it->options[1];
 	ret = alloc_private(dev, sizeof(struct pci224_private));
 	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
+		dev_err(dev->class_dev, "error! out of memory!\n");
 		return ret;
 	}
 
-	ret = pci224_find_pci(dev, bus, slot, &pci_dev);
-	if (ret < 0)
-		return ret;
+	pci_dev = pci224_find_pci(dev, bus, slot);
+	if (pci_dev == NULL)
+		return -EIO;
 
 	return pci224_attach_common(dev, pci_dev, it->options);
 }
 
-static int
+static int __devinit
 pci224_attach_pci(struct comedi_device *dev, struct pci_dev *pci_dev)
 {
 	int ret;
 
-	printk(KERN_DEBUG "comedi%d: %s: attach_pci %s\n", dev->minor,
-	       DRIVER_NAME, pci_name(pci_dev));
+	dev_info(dev->class_dev, DRIVER_NAME ": attach_pci %s\n",
+		 pci_name(pci_dev));
 
 	ret = alloc_private(dev, sizeof(struct pci224_private));
 	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: error! out of memory!\n",
-		       dev->minor);
+		dev_err(dev->class_dev, "error! out of memory!\n");
 		return ret;
 	}
 
 	dev->board_ptr = pci224_find_pci_board(pci_dev);
 	if (dev->board_ptr == NULL) {
-		printk(KERN_ERR
-		       "comedi%d: %s: BUG! cannot determine board type!\n",
-		       dev->minor, DRIVER_NAME);
+		dev_err(dev->class_dev,
+			DRIVER_NAME ": BUG! cannot determine board type!\n");
 		return -EINVAL;
 	}
 	return pci224_attach_common(dev, pci_dev, NULL);
@@ -1524,6 +1519,8 @@ pci224_attach_pci(struct comedi_device *dev, struct pci_dev *pci_dev)
 
 static void pci224_detach(struct comedi_device *dev)
 {
+	struct pci224_private *devpriv = dev->private;
+
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->subdevices) {
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index d4c80b1..3d7f2cd 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -193,7 +193,6 @@ for (or detection of) various hardware problems added by Ian Abbott.
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 
-#include "comedi_pci.h"
 #include "8253.h"
 #include "8255.h"
 
@@ -431,9 +430,6 @@ enum {
 /* Combine old and new bits. */
 #define COMBINE(old, new, mask)	(((old) & ~(mask)) | ((new) & (mask)))
 
-/* A generic null function pointer value.  */
-#define NULLFUNC	0
-
 /* Current CPU.  XXX should this be hard_smp_processor_id()? */
 #define THISCPU		smp_processor_id()
 
@@ -500,12 +496,6 @@ static const struct pci230_board pci230_boards[] = {
 	 },
 };
 
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define n_pci230_boards ARRAY_SIZE(pci230_boards)
-#define thisboard ((const struct pci230_board *)dev->board_ptr)
-
 /* this structure is for data unique to this hardware driver.  If
    several hardware drivers keep similar information in this structure,
    feel free to suggest moving the variable to the struct comedi_device struct.  */
@@ -549,8 +539,6 @@ struct pci230_private {
 	unsigned char res_owner[NUM_RESOURCES];	/* Shared resource owners. */
 };
 
-#define devpriv ((struct pci230_private *)dev->private)
-
 /* PCI230 clock source periods in ns */
 static const unsigned int pci230_timebase[8] = {
 	[CLK_10MHZ] = TIMEBASE_10MHZ,
@@ -588,49 +576,14 @@ static const struct comedi_lrange pci230_ao_range = { 2, {
 /* PCI230 daccon bipolar flag for each analogue output range. */
 static const unsigned char pci230_ao_bipolar[2] = { 0, 1 };
 
-static int pci230_ai_rinsn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
-			   unsigned int *data);
-static int pci230_ao_winsn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
-			   unsigned int *data);
-static int pci230_ao_rinsn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
-			   unsigned int *data);
-static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct,
-				    unsigned int mode, uint64_t ns,
-				    unsigned int round);
-static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round);
-static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct);
-static irqreturn_t pci230_interrupt(int irq, void *d);
-static int pci230_ao_cmdtest(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_cmd *cmd);
-static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pci230_ao_cancel(struct comedi_device *dev,
-			    struct comedi_subdevice *s);
-static void pci230_ao_stop(struct comedi_device *dev,
-			   struct comedi_subdevice *s);
-static void pci230_handle_ao_nofifo(struct comedi_device *dev,
-				    struct comedi_subdevice *s);
-static int pci230_handle_ao_fifo(struct comedi_device *dev,
-				 struct comedi_subdevice *s);
-static int pci230_ai_cmdtest(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_cmd *cmd);
-static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pci230_ai_cancel(struct comedi_device *dev,
-			    struct comedi_subdevice *s);
-static void pci230_ai_stop(struct comedi_device *dev,
-			   struct comedi_subdevice *s);
-static void pci230_handle_ai(struct comedi_device *dev,
-			     struct comedi_subdevice *s);
-
 static short pci230_ai_read(struct comedi_device *dev)
 {
-	/* Read sample. */
-	short data = (short)inw(dev->iobase + PCI230_ADCDATA);
+	const struct pci230_board *thisboard = comedi_board(dev);
+	struct pci230_private *devpriv = dev->private;
+	short data;
 
+	/* Read sample. */
+	data = (short)inw(dev->iobase + PCI230_ADCDATA);
 	/* PCI230 is 12 bit - stored in upper bits of 16 bit register (lower
 	 * four bits reserved for expansion). */
 	/* PCI230+ is 16 bit AI. */
@@ -647,12 +600,14 @@ static short pci230_ai_read(struct comedi_device *dev)
 static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev,
 						    short datum)
 {
+	const struct pci230_board *thisboard = comedi_board(dev);
+	struct pci230_private *devpriv = dev->private;
+
 	/* If a bipolar range was specified, mangle it (straight binary->twos
 	 * complement). */
 	if (devpriv->ao_bipolar)
 		datum ^= 1 << (thisboard->ao_bits - 1);
 
-
 	/* PCI230 is 12 bit - stored in upper bits of 16 bit register (lower
 	 * four bits reserved for expansion). */
 	/* PCI230+ is also 12 bit AO. */
@@ -663,6 +618,8 @@ static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev,
 static inline void pci230_ao_write_nofifo(struct comedi_device *dev,
 					  short datum, unsigned int chan)
 {
+	struct pci230_private *devpriv = dev->private;
+
 	/* Store unmangled datum to be read back later. */
 	devpriv->ao_readback[chan] = datum;
 
@@ -676,6 +633,8 @@ static inline void pci230_ao_write_nofifo(struct comedi_device *dev,
 static inline void pci230_ao_write_fifo(struct comedi_device *dev, short datum,
 					unsigned int chan)
 {
+	struct pci230_private *devpriv = dev->private;
+
 	/* Store unmangled datum to be read back later. */
 	devpriv->ao_readback[chan] = datum;
 
@@ -684,277 +643,10 @@ static inline void pci230_ao_write_fifo(struct comedi_device *dev, short datum,
 	     dev->iobase + PCI230P2_DACDATA);
 }
 
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	struct comedi_subdevice *s;
-	unsigned long iobase1, iobase2;
-	/* PCI230's I/O spaces 1 and 2 respectively. */
-	struct pci_dev *pci_dev = NULL;
-	int i = 0, irq_hdl, rc;
-
-	printk("comedi%d: amplc_pci230: attach %s %d,%d\n", dev->minor,
-	       thisboard->name, it->options[0], it->options[1]);
-
-	/* Allocate the private structure area using alloc_private().
-	 * Macro defined in comedidev.h - memsets struct fields to 0. */
-	if ((alloc_private(dev, sizeof(struct pci230_private))) < 0)
-		return -ENOMEM;
-
-	spin_lock_init(&devpriv->isr_spinlock);
-	spin_lock_init(&devpriv->res_spinlock);
-	spin_lock_init(&devpriv->ai_stop_spinlock);
-	spin_lock_init(&devpriv->ao_stop_spinlock);
-	/* Find card */
-	for_each_pci_dev(pci_dev) {
-		if (it->options[0] || it->options[1]) {
-			/* Match against bus/slot options. */
-			if (it->options[0] != pci_dev->bus->number ||
-			    it->options[1] != PCI_SLOT(pci_dev->devfn))
-				continue;
-		}
-		if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON)
-			continue;
-		if (thisboard->id == PCI_DEVICE_ID_INVALID) {
-			/* The name was specified as "amplc_pci230" which is
-			 * used to match any supported device.  Replace the
-			 * current dev->board_ptr with one that matches the
-			 * PCI device ID. */
-			for (i = 0; i < n_pci230_boards; i++) {
-				if (pci_dev->device == pci230_boards[i].id) {
-					if (pci230_boards[i].min_hwver > 0) {
-						/* Check for a '+' model.
-						 * First check length of
-						 * registers. */
-						if (pci_resource_len(pci_dev, 3)
-						    < 32) {
-							/* Not a '+' model. */
-							continue;
-						}
-						/* TODO: temporarily enable the
-						 * PCI device and read the
-						 * hardware version register.
-						 * For now assume it's okay. */
-					}
-					/* Change board_ptr to matched board */
-					dev->board_ptr = &pci230_boards[i];
-					break;
-				}
-			}
-			if (i < n_pci230_boards)
-				break;
-		} else {
-			/* The name was specified as a specific device name.
-			 * The current dev->board_ptr is correct.  Check
-			 * whether it matches the PCI device ID. */
-			if (thisboard->id == pci_dev->device) {
-				/* Check minimum hardware version. */
-				if (thisboard->min_hwver > 0) {
-					/* Looking for a '+' model.  First
-					 * check length of registers. */
-					if (pci_resource_len(pci_dev, 3) < 32) {
-						/* Not a '+' model. */
-						continue;
-					}
-					/* TODO: temporarily enable the PCI
-					 * device and read the hardware version
-					 * register.  For now, assume it's
-					 * okay. */
-					break;
-				} else {
-					break;
-				}
-			}
-		}
-	}
-	if (!pci_dev) {
-		printk("comedi%d: No %s card found\n", dev->minor,
-		       thisboard->name);
-		return -EIO;
-	}
-	devpriv->pci_dev = pci_dev;
-
-	/*
-	 * Initialize dev->board_name.
-	 */
-	dev->board_name = thisboard->name;
-
-	/* Enable PCI device and reserve I/O spaces. */
-	if (comedi_pci_enable(pci_dev, "amplc_pci230") < 0) {
-		printk("comedi%d: failed to enable PCI device "
-		       "and request regions\n", dev->minor);
-		return -EIO;
-	}
-
-	/* Read base addresses of the PCI230's two I/O regions from PCI
-	 * configuration register. */
-	iobase1 = pci_resource_start(pci_dev, 2);
-	iobase2 = pci_resource_start(pci_dev, 3);
-
-	printk("comedi%d: %s I/O region 1 0x%04lx I/O region 2 0x%04lx\n",
-	       dev->minor, dev->board_name, iobase1, iobase2);
-
-	devpriv->iobase1 = iobase1;
-	dev->iobase = iobase2;
-
-	/* Read bits of DACCON register - only the output range. */
-	devpriv->daccon = inw(dev->iobase + PCI230_DACCON) & PCI230_DAC_OR_MASK;
-
-	/* Read hardware version register and set extended function register
-	 * if they exist. */
-	if (pci_resource_len(pci_dev, 3) >= 32) {
-		unsigned short extfunc = 0;
-
-		devpriv->hwver = inw(dev->iobase + PCI230P_HWVER);
-		if (devpriv->hwver < thisboard->min_hwver) {
-			printk("comedi%d: %s - bad hardware version "
-			       "- got %u, need %u\n", dev->minor,
-			       dev->board_name, devpriv->hwver,
-			       thisboard->min_hwver);
-			return -EIO;
-		}
-		if (devpriv->hwver > 0) {
-			if (!thisboard->have_dio) {
-				/* No DIO ports.  Route counters' external gates
-				 * to the EXTTRIG signal (PCI260+ pin 17).
-				 * (Otherwise, they would be routed to DIO
-				 * inputs PC0, PC1 and PC2 which don't exist
-				 * on PCI260[+].) */
-				extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG;
-			}
-			if ((thisboard->ao_chans > 0)
-			    && (devpriv->hwver >= 2)) {
-				/* Enable DAC FIFO functionality. */
-				extfunc |= PCI230P2_EXTFUNC_DACFIFO;
-			}
-		}
-		outw(extfunc, dev->iobase + PCI230P_EXTFUNC);
-		if ((extfunc & PCI230P2_EXTFUNC_DACFIFO) != 0) {
-			/* Temporarily enable DAC FIFO, reset it and disable
-			 * FIFO wraparound. */
-			outw(devpriv->daccon | PCI230P2_DAC_FIFO_EN
-			     | PCI230P2_DAC_FIFO_RESET,
-			     dev->iobase + PCI230_DACCON);
-			/* Clear DAC FIFO channel enable register. */
-			outw(0, dev->iobase + PCI230P2_DACEN);
-			/* Disable DAC FIFO. */
-			outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
-		}
-	}
-
-	/* Disable board's interrupts. */
-	outb(0, devpriv->iobase1 + PCI230_INT_SCE);
-
-	/* Set ADC to a reasonable state. */
-	devpriv->adcg = 0;
-	devpriv->adccon = PCI230_ADC_TRIG_NONE | PCI230_ADC_IM_SE
-	    | PCI230_ADC_IR_BIP;
-	outw(1 << 0, dev->iobase + PCI230_ADCEN);
-	outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
-	outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
-	     dev->iobase + PCI230_ADCCON);
-
-	/* Register the interrupt handler. */
-	irq_hdl = request_irq(devpriv->pci_dev->irq, pci230_interrupt,
-			      IRQF_SHARED, "amplc_pci230", dev);
-	if (irq_hdl < 0) {
-		printk("comedi%d: unable to register irq, "
-		       "commands will not be available %d\n", dev->minor,
-		       devpriv->pci_dev->irq);
-	} else {
-		dev->irq = devpriv->pci_dev->irq;
-		printk("comedi%d: registered irq %u\n", dev->minor,
-		       devpriv->pci_dev->irq);
-	}
-
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.
-	 */
-	if (alloc_subdevices(dev, 3) < 0)
-		return -ENOMEM;
-
-	s = dev->subdevices + 0;
-	/* analog input subdevice */
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
-	s->n_chan = thisboard->ai_chans;
-	s->maxdata = (1 << thisboard->ai_bits) - 1;
-	s->range_table = &pci230_ai_range;
-	s->insn_read = &pci230_ai_rinsn;
-	s->len_chanlist = 256;	/* but there are restrictions. */
-	/* Only register commands if the interrupt handler is installed. */
-	if (irq_hdl == 0) {
-		dev->read_subdev = s;
-		s->subdev_flags |= SDF_CMD_READ;
-		s->do_cmd = &pci230_ai_cmd;
-		s->do_cmdtest = &pci230_ai_cmdtest;
-		s->cancel = pci230_ai_cancel;
-	}
-
-	s = dev->subdevices + 1;
-	/* analog output subdevice */
-	if (thisboard->ao_chans > 0) {
-		s->type = COMEDI_SUBD_AO;
-		s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
-		s->n_chan = thisboard->ao_chans;
-		s->maxdata = (1 << thisboard->ao_bits) - 1;
-		s->range_table = &pci230_ao_range;
-		s->insn_write = &pci230_ao_winsn;
-		s->insn_read = &pci230_ao_rinsn;
-		s->len_chanlist = thisboard->ao_chans;
-		/* Only register commands if the interrupt handler is
-		 * installed. */
-		if (irq_hdl == 0) {
-			dev->write_subdev = s;
-			s->subdev_flags |= SDF_CMD_WRITE;
-			s->do_cmd = &pci230_ao_cmd;
-			s->do_cmdtest = &pci230_ao_cmdtest;
-			s->cancel = pci230_ao_cancel;
-		}
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
-
-	s = dev->subdevices + 2;
-	/* digital i/o subdevice */
-	if (thisboard->have_dio) {
-		rc = subdev_8255_init(dev, s, NULL,
-				      (devpriv->iobase1 + PCI230_PPI_X_BASE));
-		if (rc < 0)
-			return rc;
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
-
-	printk("comedi%d: attached\n", dev->minor);
-
-	return 1;
-}
-
-static void pci230_detach(struct comedi_device *dev)
-{
-	if (dev->subdevices && thisboard->have_dio)
-		subdev_8255_cleanup(dev, dev->subdevices + 2);
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-	if (devpriv) {
-		if (devpriv->pci_dev) {
-			if (dev->iobase)
-				comedi_pci_disable(devpriv->pci_dev);
-			pci_dev_put(devpriv->pci_dev);
-		}
-	}
-}
-
 static int get_resources(struct comedi_device *dev, unsigned int res_mask,
 			 unsigned char owner)
 {
+	struct pci230_private *devpriv = dev->private;
 	int ok;
 	unsigned int i;
 	unsigned int b;
@@ -997,6 +689,7 @@ static inline int get_one_resource(struct comedi_device *dev,
 static void put_resources(struct comedi_device *dev, unsigned int res_mask,
 			  unsigned char owner)
 {
+	struct pci230_private *devpriv = dev->private;
 	unsigned int i;
 	unsigned int b;
 	unsigned long irqflags;
@@ -1026,37 +719,118 @@ static inline void put_all_resources(struct comedi_device *dev,
 	put_resources(dev, (1U << NUM_RESOURCES) - 1, owner);
 }
 
-/*
- *  COMEDI_SUBD_AI instruction;
- */
-static int pci230_ai_rinsn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
-			   unsigned int *data)
+static unsigned int divide_ns(uint64_t ns, unsigned int timebase,
+			      unsigned int round_mode)
 {
-	unsigned int n, i;
-	unsigned int chan, range, aref;
-	unsigned int gainshift;
-	unsigned int status;
-	unsigned short adccon, adcen;
-
-	/* Unpack channel and range. */
-	chan = CR_CHAN(insn->chanspec);
-	range = CR_RANGE(insn->chanspec);
-	aref = CR_AREF(insn->chanspec);
-	if (aref == AREF_DIFF) {
-		/* Differential. */
-		if (chan >= s->n_chan / 2) {
-			DPRINTK("comedi%d: amplc_pci230: ai_rinsn: "
-				"differential channel number out of range "
-				"0 to %u\n", dev->minor, (s->n_chan / 2) - 1);
-			return -EINVAL;
-		}
-	}
+	uint64_t div;
+	unsigned int rem;
 
-	/* Use Z2-CT2 as a conversion trigger instead of the built-in
-	 * software trigger, as otherwise triggering of differential channels
-	 * doesn't work properly for some versions of PCI230/260.  Also set
-	 * FIFO mode because the ADC busy bit only works for software triggers.
+	div = ns;
+	rem = do_div(div, timebase);
+	round_mode &= TRIG_ROUND_MASK;
+	switch (round_mode) {
+	default:
+	case TRIG_ROUND_NEAREST:
+		div += (rem + (timebase / 2)) / timebase;
+		break;
+	case TRIG_ROUND_DOWN:
+		break;
+	case TRIG_ROUND_UP:
+		div += (rem + timebase - 1) / timebase;
+		break;
+	}
+	return div > UINT_MAX ? UINT_MAX : (unsigned int)div;
+}
+
+/* Given desired period in ns, returns the required internal clock source
+ * and gets the initial count. */
+static unsigned int pci230_choose_clk_count(uint64_t ns, unsigned int *count,
+					    unsigned int round_mode)
+{
+	unsigned int clk_src, cnt;
+
+	for (clk_src = CLK_10MHZ;; clk_src++) {
+		cnt = divide_ns(ns, pci230_timebase[clk_src], round_mode);
+		if ((cnt <= 65536) || (clk_src == CLK_1KHZ))
+			break;
+
+	}
+	*count = cnt;
+	return clk_src;
+}
+
+static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round)
+{
+	unsigned int count;
+	unsigned int clk_src;
+
+	clk_src = pci230_choose_clk_count(*ns, &count, round);
+	*ns = count * pci230_timebase[clk_src];
+	return;
+}
+
+static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct,
+				    unsigned int mode, uint64_t ns,
+				    unsigned int round)
+{
+	struct pci230_private *devpriv = dev->private;
+	unsigned int clk_src;
+	unsigned int count;
+
+	/* Set mode. */
+	i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, mode);
+	/* Determine clock source and count. */
+	clk_src = pci230_choose_clk_count(ns, &count, round);
+	/* Program clock source. */
+	outb(CLK_CONFIG(ct, clk_src), devpriv->iobase1 + PCI230_ZCLK_SCE);
+	/* Set initial count. */
+	if (count >= 65536)
+		count = 0;
+
+	i8254_write(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, count);
+}
+
+static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct)
+{
+	struct pci230_private *devpriv = dev->private;
+
+	i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct,
+		       I8254_MODE1);
+	/* Counter ct, 8254 mode 1, initial count not written. */
+}
+
+/*
+ *  COMEDI_SUBD_AI instruction;
+ */
+static int pci230_ai_rinsn(struct comedi_device *dev,
+			   struct comedi_subdevice *s, struct comedi_insn *insn,
+			   unsigned int *data)
+{
+	struct pci230_private *devpriv = dev->private;
+	unsigned int n, i;
+	unsigned int chan, range, aref;
+	unsigned int gainshift;
+	unsigned int status;
+	unsigned short adccon, adcen;
+
+	/* Unpack channel and range. */
+	chan = CR_CHAN(insn->chanspec);
+	range = CR_RANGE(insn->chanspec);
+	aref = CR_AREF(insn->chanspec);
+	if (aref == AREF_DIFF) {
+		/* Differential. */
+		if (chan >= s->n_chan / 2) {
+			DPRINTK("comedi%d: amplc_pci230: ai_rinsn: "
+				"differential channel number out of range "
+				"0 to %u\n", dev->minor, (s->n_chan / 2) - 1);
+			return -EINVAL;
+		}
+	}
+
+	/* Use Z2-CT2 as a conversion trigger instead of the built-in
+	 * software trigger, as otherwise triggering of differential channels
+	 * doesn't work properly for some versions of PCI230/260.  Also set
+	 * FIFO mode because the ADC busy bit only works for software triggers.
 	 */
 	adccon = PCI230_ADC_TRIG_Z2CT2 | PCI230_ADC_FIFO_EN;
 	/* Set Z2-CT2 output low to avoid any false triggers. */
@@ -1118,9 +892,7 @@ static int pci230_ai_rinsn(struct comedi_device *dev,
 			udelay(1);
 		}
 		if (i == TIMEOUT) {
-			/* printk() should be used instead of printk()
-			 * whenever the code can be called from real-time. */
-			printk("timeout\n");
+			dev_err(dev->class_dev, "timeout\n");
 			return -ETIMEDOUT;
 		}
 
@@ -1139,6 +911,7 @@ static int pci230_ao_winsn(struct comedi_device *dev,
 			   struct comedi_subdevice *s, struct comedi_insn *insn,
 			   unsigned int *data)
 {
+	struct pci230_private *devpriv = dev->private;
 	int i;
 	int chan, range;
 
@@ -1168,6 +941,7 @@ static int pci230_ao_rinsn(struct comedi_device *dev,
 			   struct comedi_subdevice *s, struct comedi_insn *insn,
 			   unsigned int *data)
 {
+	struct pci230_private *devpriv = dev->private;
 	int i;
 	int chan = CR_CHAN(insn->chanspec);
 
@@ -1180,6 +954,8 @@ static int pci230_ao_rinsn(struct comedi_device *dev,
 static int pci230_ao_cmdtest(struct comedi_device *dev,
 			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
+	const struct pci230_board *thisboard = comedi_board(dev);
+	struct pci230_private *devpriv = dev->private;
 	int err = 0;
 	unsigned int tmp;
 
@@ -1389,113 +1165,307 @@ static int pci230_ao_cmdtest(struct comedi_device *dev,
 	return 0;
 }
 
-static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev,
-					struct comedi_subdevice *s,
-					unsigned int trig_num)
+static void pci230_ao_stop(struct comedi_device *dev,
+			   struct comedi_subdevice *s)
 {
+	struct pci230_private *devpriv = dev->private;
 	unsigned long irqflags;
-
-	if (trig_num != 0)
-		return -EINVAL;
+	unsigned char intsrc;
+	int started;
+	struct comedi_cmd *cmd;
 
 	spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
-	if (test_bit(AO_CMD_STARTED, &devpriv->state)) {
-		/* Perform scan. */
-		if (devpriv->hwver < 2) {
-			/* Not using DAC FIFO. */
-			spin_unlock_irqrestore(&devpriv->ao_stop_spinlock,
-					       irqflags);
-			pci230_handle_ao_nofifo(dev, s);
-			comedi_event(dev, s);
-		} else {
-			/* Using DAC FIFO. */
-			/* Read DACSWTRIG register to trigger conversion. */
-			inw(dev->iobase + PCI230P2_DACSWTRIG);
-			spin_unlock_irqrestore(&devpriv->ao_stop_spinlock,
-					       irqflags);
-		}
-		/* Delay.  Should driver be responsible for this? */
-		/* XXX TODO: See if DAC busy bit can be used. */
-		udelay(8);
+	started = test_and_clear_bit(AO_CMD_STARTED, &devpriv->state);
+	spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags);
+	if (!started)
+		return;
+	cmd = &s->async->cmd;
+	if (cmd->scan_begin_src == TRIG_TIMER) {
+		/* Stop scan rate generator. */
+		pci230_cancel_ct(dev, 1);
 	}
-
-	return 1;
+	/* Determine interrupt source. */
+	if (devpriv->hwver < 2) {
+		/* Not using DAC FIFO.  Using CT1 interrupt. */
+		intsrc = PCI230_INT_ZCLK_CT1;
+	} else {
+		/* Using DAC FIFO interrupt. */
+		intsrc = PCI230P2_INT_DAC;
+	}
+	/* Disable interrupt and wait for interrupt routine to finish running
+	 * unless we are called from the interrupt routine. */
+	spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
+	devpriv->int_en &= ~intsrc;
+	while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
+		spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
+		spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
+	}
+	if (devpriv->ier != devpriv->int_en) {
+		devpriv->ier = devpriv->int_en;
+		outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
+	}
+	spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
+	if (devpriv->hwver >= 2) {
+		/* Using DAC FIFO.  Reset FIFO, clear underrun error,
+		 * disable FIFO. */
+		devpriv->daccon &= PCI230_DAC_OR_MASK;
+		outw(devpriv->daccon | PCI230P2_DAC_FIFO_RESET
+		     | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR,
+		     dev->iobase + PCI230_DACCON);
+	}
+	/* Release resources. */
+	put_all_resources(dev, OWNER_AOCMD);
 }
 
-static void pci230_ao_start(struct comedi_device *dev,
-			    struct comedi_subdevice *s)
+static void pci230_handle_ao_nofifo(struct comedi_device *dev,
+				    struct comedi_subdevice *s)
 {
+	struct pci230_private *devpriv = dev->private;
+	short data;
+	int i, ret;
 	struct comedi_async *async = s->async;
 	struct comedi_cmd *cmd = &async->cmd;
-	unsigned long irqflags;
-
-	set_bit(AO_CMD_STARTED, &devpriv->state);
-	if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) {
-		/* An empty acquisition! */
-		async->events |= COMEDI_CB_EOA;
-		pci230_ao_stop(dev, s);
-		comedi_event(dev, s);
-	} else {
-		if (devpriv->hwver >= 2) {
-			/* Using DAC FIFO. */
-			unsigned short scantrig;
-			int run;
-
-			/* Preload FIFO data. */
-			run = pci230_handle_ao_fifo(dev, s);
-			comedi_event(dev, s);
-			if (!run) {
-				/* Stopped. */
-				return;
-			}
-			/* Set scan trigger source. */
-			switch (cmd->scan_begin_src) {
-			case TRIG_TIMER:
-				scantrig = PCI230P2_DAC_TRIG_Z2CT1;
-				break;
-			case TRIG_EXT:
-				/* Trigger on EXTTRIG/EXTCONVCLK pin. */
-				if ((cmd->scan_begin_arg & CR_INVERT) == 0) {
-					/* +ve edge */
-					scantrig = PCI230P2_DAC_TRIG_EXTP;
-				} else {
-					/* -ve edge */
-					scantrig = PCI230P2_DAC_TRIG_EXTN;
-				}
-				break;
-			case TRIG_INT:
-				scantrig = PCI230P2_DAC_TRIG_SW;
-				break;
-			default:
-				/* Shouldn't get here. */
-				scantrig = PCI230P2_DAC_TRIG_NONE;
-				break;
-			}
-			devpriv->daccon = (devpriv->daccon
-					   & ~PCI230P2_DAC_TRIG_MASK) |
-			    scantrig;
-			outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
 
+	if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0))
+		return;
+	for (i = 0; i < cmd->chanlist_len; i++) {
+		/* Read sample from Comedi's circular buffer. */
+		ret = comedi_buf_get(s->async, &data);
+		if (ret == 0) {
+			s->async->events |= COMEDI_CB_OVERFLOW;
+			pci230_ao_stop(dev, s);
+			comedi_error(dev, "AO buffer underrun");
+			return;
 		}
-		switch (cmd->scan_begin_src) {
-		case TRIG_TIMER:
-			if (devpriv->hwver < 2) {
-				/* Not using DAC FIFO. */
-				/* Enable CT1 timer interrupt. */
-				spin_lock_irqsave(&devpriv->isr_spinlock,
-						  irqflags);
-				devpriv->int_en |= PCI230_INT_ZCLK_CT1;
-				devpriv->ier |= PCI230_INT_ZCLK_CT1;
-				outb(devpriv->ier,
-				     devpriv->iobase1 + PCI230_INT_SCE);
-				spin_unlock_irqrestore(&devpriv->isr_spinlock,
-						       irqflags);
-			}
-			/* Set CT1 gate high to start counting. */
-			outb(GAT_CONFIG(1, GAT_VCC),
-			     devpriv->iobase1 + PCI230_ZGAT_SCE);
-			break;
-		case TRIG_INT:
+		/* Write value to DAC. */
+		pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i]));
+	}
+	async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
+	if (!devpriv->ao_continuous) {
+		devpriv->ao_scan_count--;
+		if (devpriv->ao_scan_count == 0) {
+			/* End of acquisition. */
+			async->events |= COMEDI_CB_EOA;
+			pci230_ao_stop(dev, s);
+		}
+	}
+}
+
+/* Loads DAC FIFO (if using it) from buffer. */
+/* Returns 0 if AO finished due to completion or error, 1 if still going. */
+static int pci230_handle_ao_fifo(struct comedi_device *dev,
+				 struct comedi_subdevice *s)
+{
+	struct pci230_private *devpriv = dev->private;
+	struct comedi_async *async = s->async;
+	struct comedi_cmd *cmd = &async->cmd;
+	unsigned int num_scans;
+	unsigned int room;
+	unsigned short dacstat;
+	unsigned int i, n;
+	unsigned int bytes_per_scan;
+	unsigned int events = 0;
+	int running;
+
+	/* Get DAC FIFO status. */
+	dacstat = inw(dev->iobase + PCI230_DACCON);
+	/* Determine number of scans available in buffer. */
+	bytes_per_scan = cmd->chanlist_len * sizeof(short);
+	num_scans = comedi_buf_read_n_available(async) / bytes_per_scan;
+	if (!devpriv->ao_continuous) {
+		/* Fixed number of scans. */
+		if (num_scans > devpriv->ao_scan_count)
+			num_scans = devpriv->ao_scan_count;
+		if (devpriv->ao_scan_count == 0) {
+			/* End of acquisition. */
+			events |= COMEDI_CB_EOA;
+		}
+	}
+	if (events == 0) {
+		/* Check for FIFO underrun. */
+		if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) {
+			comedi_error(dev, "AO FIFO underrun");
+			events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
+		}
+		/* Check for buffer underrun if FIFO less than half full
+		 * (otherwise there will be loads of "DAC FIFO not half full"
+		 * interrupts). */
+		if ((num_scans == 0)
+		    && ((dacstat & PCI230P2_DAC_FIFO_HALF) == 0)) {
+			comedi_error(dev, "AO buffer underrun");
+			events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
+		}
+	}
+	if (events == 0) {
+		/* Determine how much room is in the FIFO (in samples). */
+		if ((dacstat & PCI230P2_DAC_FIFO_FULL) != 0)
+			room = PCI230P2_DAC_FIFOROOM_FULL;
+		else if ((dacstat & PCI230P2_DAC_FIFO_HALF) != 0)
+			room = PCI230P2_DAC_FIFOROOM_HALFTOFULL;
+		else if ((dacstat & PCI230P2_DAC_FIFO_EMPTY) != 0)
+			room = PCI230P2_DAC_FIFOROOM_EMPTY;
+		else
+			room = PCI230P2_DAC_FIFOROOM_ONETOHALF;
+		/* Convert room to number of scans that can be added. */
+		room /= cmd->chanlist_len;
+		/* Determine number of scans to process. */
+		if (num_scans > room)
+			num_scans = room;
+		/* Process scans. */
+		for (n = 0; n < num_scans; n++) {
+			for (i = 0; i < cmd->chanlist_len; i++) {
+				short datum;
+
+				comedi_buf_get(async, &datum);
+				pci230_ao_write_fifo(dev, datum,
+						     CR_CHAN(cmd->chanlist[i]));
+			}
+		}
+		events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK;
+		if (!devpriv->ao_continuous) {
+			devpriv->ao_scan_count -= num_scans;
+			if (devpriv->ao_scan_count == 0) {
+				/* All data for the command has been written
+				 * to FIFO.  Set FIFO interrupt trigger level
+				 * to 'empty'. */
+				devpriv->daccon = (devpriv->daccon
+						   &
+						   ~PCI230P2_DAC_INT_FIFO_MASK)
+				    | PCI230P2_DAC_INT_FIFO_EMPTY;
+				outw(devpriv->daccon,
+				     dev->iobase + PCI230_DACCON);
+			}
+		}
+		/* Check if FIFO underrun occurred while writing to FIFO. */
+		dacstat = inw(dev->iobase + PCI230_DACCON);
+		if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) {
+			comedi_error(dev, "AO FIFO underrun");
+			events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
+		}
+	}
+	if ((events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW))
+	    != 0) {
+		/* Stopping AO due to completion or error. */
+		pci230_ao_stop(dev, s);
+		running = 0;
+	} else {
+		running = 1;
+	}
+	async->events |= events;
+	return running;
+}
+
+static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev,
+					struct comedi_subdevice *s,
+					unsigned int trig_num)
+{
+	struct pci230_private *devpriv = dev->private;
+	unsigned long irqflags;
+
+	if (trig_num != 0)
+		return -EINVAL;
+
+	spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
+	if (test_bit(AO_CMD_STARTED, &devpriv->state)) {
+		/* Perform scan. */
+		if (devpriv->hwver < 2) {
+			/* Not using DAC FIFO. */
+			spin_unlock_irqrestore(&devpriv->ao_stop_spinlock,
+					       irqflags);
+			pci230_handle_ao_nofifo(dev, s);
+			comedi_event(dev, s);
+		} else {
+			/* Using DAC FIFO. */
+			/* Read DACSWTRIG register to trigger conversion. */
+			inw(dev->iobase + PCI230P2_DACSWTRIG);
+			spin_unlock_irqrestore(&devpriv->ao_stop_spinlock,
+					       irqflags);
+		}
+		/* Delay.  Should driver be responsible for this? */
+		/* XXX TODO: See if DAC busy bit can be used. */
+		udelay(8);
+	} else {
+		spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags);
+	}
+
+	return 1;
+}
+
+static void pci230_ao_start(struct comedi_device *dev,
+			    struct comedi_subdevice *s)
+{
+	struct pci230_private *devpriv = dev->private;
+	struct comedi_async *async = s->async;
+	struct comedi_cmd *cmd = &async->cmd;
+	unsigned long irqflags;
+
+	set_bit(AO_CMD_STARTED, &devpriv->state);
+	if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) {
+		/* An empty acquisition! */
+		async->events |= COMEDI_CB_EOA;
+		pci230_ao_stop(dev, s);
+		comedi_event(dev, s);
+	} else {
+		if (devpriv->hwver >= 2) {
+			/* Using DAC FIFO. */
+			unsigned short scantrig;
+			int run;
+
+			/* Preload FIFO data. */
+			run = pci230_handle_ao_fifo(dev, s);
+			comedi_event(dev, s);
+			if (!run) {
+				/* Stopped. */
+				return;
+			}
+			/* Set scan trigger source. */
+			switch (cmd->scan_begin_src) {
+			case TRIG_TIMER:
+				scantrig = PCI230P2_DAC_TRIG_Z2CT1;
+				break;
+			case TRIG_EXT:
+				/* Trigger on EXTTRIG/EXTCONVCLK pin. */
+				if ((cmd->scan_begin_arg & CR_INVERT) == 0) {
+					/* +ve edge */
+					scantrig = PCI230P2_DAC_TRIG_EXTP;
+				} else {
+					/* -ve edge */
+					scantrig = PCI230P2_DAC_TRIG_EXTN;
+				}
+				break;
+			case TRIG_INT:
+				scantrig = PCI230P2_DAC_TRIG_SW;
+				break;
+			default:
+				/* Shouldn't get here. */
+				scantrig = PCI230P2_DAC_TRIG_NONE;
+				break;
+			}
+			devpriv->daccon = (devpriv->daccon
+					   & ~PCI230P2_DAC_TRIG_MASK) |
+			    scantrig;
+			outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
+
+		}
+		switch (cmd->scan_begin_src) {
+		case TRIG_TIMER:
+			if (devpriv->hwver < 2) {
+				/* Not using DAC FIFO. */
+				/* Enable CT1 timer interrupt. */
+				spin_lock_irqsave(&devpriv->isr_spinlock,
+						  irqflags);
+				devpriv->int_en |= PCI230_INT_ZCLK_CT1;
+				devpriv->ier |= PCI230_INT_ZCLK_CT1;
+				outb(devpriv->ier,
+				     devpriv->iobase1 + PCI230_INT_SCE);
+				spin_unlock_irqrestore(&devpriv->isr_spinlock,
+						       irqflags);
+			}
+			/* Set CT1 gate high to start counting. */
+			outb(GAT_CONFIG(1, GAT_VCC),
+			     devpriv->iobase1 + PCI230_ZGAT_SCE);
+			break;
+		case TRIG_INT:
 			async->inttrig = pci230_ao_inttrig_scan_begin;
 			break;
 		}
@@ -1518,7 +1488,7 @@ static int pci230_ao_inttrig_start(struct comedi_device *dev,
 	if (trig_num != 0)
 		return -EINVAL;
 
-	s->async->inttrig = NULLFUNC;
+	s->async->inttrig = NULL;
 	pci230_ao_start(dev, s);
 
 	return 1;
@@ -1526,6 +1496,7 @@ static int pci230_ao_inttrig_start(struct comedi_device *dev,
 
 static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	struct pci230_private *devpriv = dev->private;
 	unsigned short daccon;
 	unsigned int range;
 
@@ -1601,6 +1572,13 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 	return 0;
 }
 
+static int pci230_ao_cancel(struct comedi_device *dev,
+			    struct comedi_subdevice *s)
+{
+	pci230_ao_stop(dev, s);
+	return 0;
+}
+
 static int pci230_ai_check_scan_period(struct comedi_cmd *cmd)
 {
 	unsigned int min_scan_period, chanlist_len;
@@ -1628,6 +1606,8 @@ static int pci230_ai_check_scan_period(struct comedi_cmd *cmd)
 static int pci230_ai_cmdtest(struct comedi_device *dev,
 			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
+	const struct pci230_board *thisboard = comedi_board(dev);
+	struct pci230_private *devpriv = dev->private;
 	int err = 0;
 	unsigned int tmp;
 
@@ -1993,13 +1973,9 @@ static int pci230_ai_cmdtest(struct comedi_device *dev,
 					(s->n_chan / 2) - 1);
 			}
 			if ((errors & buggy_chan0_err) != 0) {
-				/* Use printk instead of DPRINTK here. */
-				printk("comedi: comedi%d: amplc_pci230: "
-				       "ai_cmdtest: Buggy PCI230+/260+ "
-				       "h/w version %u requires first channel "
-				       "of multi-channel sequence to be 0 "
-				       "(corrected in h/w version 4)\n",
-				       dev->minor, devpriv->hwver);
+				dev_info(dev->class_dev,
+					 "amplc_pci230: ai_cmdtest: Buggy PCI230+/260+ h/w version %u requires first channel of multi-channel sequence to be 0 (corrected in h/w version 4)\n",
+					 devpriv->hwver);
 			}
 		}
 	}
@@ -2013,6 +1989,7 @@ static int pci230_ai_cmdtest(struct comedi_device *dev,
 static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev,
 						struct comedi_subdevice *s)
 {
+	struct pci230_private *devpriv = dev->private;
 	struct comedi_cmd *cmd = &s->async->cmd;
 	unsigned int scanlen = cmd->scan_end_arg;
 	unsigned int wake;
@@ -2057,6 +2034,7 @@ static int pci230_ai_inttrig_convert(struct comedi_device *dev,
 				     struct comedi_subdevice *s,
 				     unsigned int trig_num)
 {
+	struct pci230_private *devpriv = dev->private;
 	unsigned long irqflags;
 
 	if (trig_num != 0)
@@ -2099,6 +2077,7 @@ static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev,
 					struct comedi_subdevice *s,
 					unsigned int trig_num)
 {
+	struct pci230_private *devpriv = dev->private;
 	unsigned long irqflags;
 	unsigned char zgat;
 
@@ -2118,29 +2097,76 @@ static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev,
 	return 1;
 }
 
-static void pci230_ai_start(struct comedi_device *dev,
-			    struct comedi_subdevice *s)
+static void pci230_ai_stop(struct comedi_device *dev,
+			   struct comedi_subdevice *s)
 {
+	struct pci230_private *devpriv = dev->private;
 	unsigned long irqflags;
-	unsigned short conv;
-	struct comedi_async *async = s->async;
-	struct comedi_cmd *cmd = &async->cmd;
-
-	set_bit(AI_CMD_STARTED, &devpriv->state);
-	if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
-		/* An empty acquisition! */
-		async->events |= COMEDI_CB_EOA;
-		pci230_ai_stop(dev, s);
-		comedi_event(dev, s);
-	} else {
-		/* Enable ADC FIFO trigger level interrupt. */
-		spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
-		devpriv->int_en |= PCI230_INT_ADC;
-		devpriv->ier |= PCI230_INT_ADC;
-		outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
-		spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
+	struct comedi_cmd *cmd;
+	int started;
 
-		/* Update conversion trigger source which is currently set
+	spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
+	started = test_and_clear_bit(AI_CMD_STARTED, &devpriv->state);
+	spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
+	if (!started)
+		return;
+	cmd = &s->async->cmd;
+	if (cmd->convert_src == TRIG_TIMER) {
+		/* Stop conversion rate generator. */
+		pci230_cancel_ct(dev, 2);
+	}
+	if (cmd->scan_begin_src != TRIG_FOLLOW) {
+		/* Stop scan period monostable. */
+		pci230_cancel_ct(dev, 0);
+	}
+	spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
+	/* Disable ADC interrupt and wait for interrupt routine to finish
+	 * running unless we are called from the interrupt routine. */
+	devpriv->int_en &= ~PCI230_INT_ADC;
+	while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
+		spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
+		spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
+	}
+	if (devpriv->ier != devpriv->int_en) {
+		devpriv->ier = devpriv->int_en;
+		outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
+	}
+	spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
+	/* Reset FIFO, disable FIFO and set start conversion source to none.
+	 * Keep se/diff and bip/uni settings */
+	devpriv->adccon = (devpriv->adccon & (PCI230_ADC_IR_MASK
+					      | PCI230_ADC_IM_MASK)) |
+	    PCI230_ADC_TRIG_NONE;
+	outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
+	     dev->iobase + PCI230_ADCCON);
+	/* Release resources. */
+	put_all_resources(dev, OWNER_AICMD);
+}
+
+static void pci230_ai_start(struct comedi_device *dev,
+			    struct comedi_subdevice *s)
+{
+	struct pci230_private *devpriv = dev->private;
+	unsigned long irqflags;
+	unsigned short conv;
+	struct comedi_async *async = s->async;
+	struct comedi_cmd *cmd = &async->cmd;
+
+	set_bit(AI_CMD_STARTED, &devpriv->state);
+	if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
+		/* An empty acquisition! */
+		async->events |= COMEDI_CB_EOA;
+		pci230_ai_stop(dev, s);
+		comedi_event(dev, s);
+	} else {
+		/* Enable ADC FIFO trigger level interrupt. */
+		spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
+		devpriv->int_en |= PCI230_INT_ADC;
+		devpriv->ier |= PCI230_INT_ADC;
+		outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
+		spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
+
+		/* Update conversion trigger source which is currently set
 		 * to CT2 output, which is currently stuck high. */
 		switch (cmd->convert_src) {
 		default:
@@ -2263,14 +2289,108 @@ static int pci230_ai_inttrig_start(struct comedi_device *dev,
 	if (trig_num != 0)
 		return -EINVAL;
 
-	s->async->inttrig = NULLFUNC;
+	s->async->inttrig = NULL;
 	pci230_ai_start(dev, s);
 
 	return 1;
 }
 
+static void pci230_handle_ai(struct comedi_device *dev,
+			     struct comedi_subdevice *s)
+{
+	struct pci230_private *devpriv = dev->private;
+	unsigned int events = 0;
+	unsigned int status_fifo;
+	unsigned int i;
+	unsigned int todo;
+	unsigned int fifoamount;
+	struct comedi_async *async = s->async;
+	unsigned int scanlen = async->cmd.scan_end_arg;
+
+	/* Determine number of samples to read. */
+	if (devpriv->ai_continuous) {
+		todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
+	} else if (devpriv->ai_scan_count == 0) {
+		todo = 0;
+	} else if ((devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL)
+		   || (scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL)) {
+		todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
+	} else {
+		todo = (devpriv->ai_scan_count * scanlen)
+		    - devpriv->ai_scan_pos;
+		if (todo > PCI230_ADC_FIFOLEVEL_HALFFULL)
+			todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
+	}
+	if (todo == 0)
+		return;
+	fifoamount = 0;
+	for (i = 0; i < todo; i++) {
+		if (fifoamount == 0) {
+			/* Read FIFO state. */
+			status_fifo = inw(dev->iobase + PCI230_ADCCON);
+			if ((status_fifo & PCI230_ADC_FIFO_FULL_LATCHED) != 0) {
+				/* Report error otherwise FIFO overruns will go
+				 * unnoticed by the caller. */
+				comedi_error(dev, "AI FIFO overrun");
+				events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
+				break;
+			} else if ((status_fifo & PCI230_ADC_FIFO_EMPTY) != 0) {
+				/* FIFO empty. */
+				break;
+			} else if ((status_fifo & PCI230_ADC_FIFO_HALF) != 0) {
+				/* FIFO half full. */
+				fifoamount = PCI230_ADC_FIFOLEVEL_HALFFULL;
+			} else {
+				/* FIFO not empty. */
+				if (devpriv->hwver > 0) {
+					/* Read PCI230+/260+ ADC FIFO level. */
+					fifoamount = inw(dev->iobase
+							 + PCI230P_ADCFFLEV);
+					if (fifoamount == 0) {
+						/* Shouldn't happen. */
+						break;
+					}
+				} else {
+					fifoamount = 1;
+				}
+			}
+		}
+		/* Read sample and store in Comedi's circular buffer. */
+		if (comedi_buf_put(async, pci230_ai_read(dev)) == 0) {
+			events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
+			comedi_error(dev, "AI buffer overflow");
+			break;
+		}
+		fifoamount--;
+		devpriv->ai_scan_pos++;
+		if (devpriv->ai_scan_pos == scanlen) {
+			/* End of scan. */
+			devpriv->ai_scan_pos = 0;
+			devpriv->ai_scan_count--;
+			async->events |= COMEDI_CB_EOS;
+		}
+	}
+	if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
+		/* End of acquisition. */
+		events |= COMEDI_CB_EOA;
+	} else {
+		/* More samples required, tell Comedi to block. */
+		events |= COMEDI_CB_BLOCK;
+	}
+	async->events |= events;
+	if ((async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
+			      COMEDI_CB_OVERFLOW)) != 0) {
+		/* disable hardware conversions */
+		pci230_ai_stop(dev, s);
+	} else {
+		/* update FIFO interrupt trigger level */
+		pci230_ai_update_fifo_trigger_level(dev, s);
+	}
+}
+
 static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	struct pci230_private *devpriv = dev->private;
 	unsigned int i, chan, range, diff;
 	unsigned int res_mask;
 	unsigned short adccon, adcen;
@@ -2462,81 +2582,11 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 	return 0;
 }
 
-static unsigned int divide_ns(uint64_t ns, unsigned int timebase,
-			      unsigned int round_mode)
-{
-	uint64_t div;
-	unsigned int rem;
-
-	div = ns;
-	rem = do_div(div, timebase);
-	round_mode &= TRIG_ROUND_MASK;
-	switch (round_mode) {
-	default:
-	case TRIG_ROUND_NEAREST:
-		div += (rem + (timebase / 2)) / timebase;
-		break;
-	case TRIG_ROUND_DOWN:
-		break;
-	case TRIG_ROUND_UP:
-		div += (rem + timebase - 1) / timebase;
-		break;
-	}
-	return div > UINT_MAX ? UINT_MAX : (unsigned int)div;
-}
-
-/* Given desired period in ns, returns the required internal clock source
- * and gets the initial count. */
-static unsigned int pci230_choose_clk_count(uint64_t ns, unsigned int *count,
-					    unsigned int round_mode)
-{
-	unsigned int clk_src, cnt;
-
-	for (clk_src = CLK_10MHZ;; clk_src++) {
-		cnt = divide_ns(ns, pci230_timebase[clk_src], round_mode);
-		if ((cnt <= 65536) || (clk_src == CLK_1KHZ))
-			break;
-
-	}
-	*count = cnt;
-	return clk_src;
-}
-
-static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round)
-{
-	unsigned int count;
-	unsigned int clk_src;
-
-	clk_src = pci230_choose_clk_count(*ns, &count, round);
-	*ns = count * pci230_timebase[clk_src];
-	return;
-}
-
-static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct,
-				    unsigned int mode, uint64_t ns,
-				    unsigned int round)
-{
-	unsigned int clk_src;
-	unsigned int count;
-
-	/* Set mode. */
-	i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, mode);
-	/* Determine clock source and count. */
-	clk_src = pci230_choose_clk_count(ns, &count, round);
-	/* Program clock source. */
-	outb(CLK_CONFIG(ct, clk_src), devpriv->iobase1 + PCI230_ZCLK_SCE);
-	/* Set initial count. */
-	if (count >= 65536)
-		count = 0;
-
-	i8254_write(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, count);
-}
-
-static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct)
+static int pci230_ai_cancel(struct comedi_device *dev,
+			    struct comedi_subdevice *s)
 {
-	i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct,
-		       I8254_MODE1);
-	/* Counter ct, 8254 mode 1, initial count not written. */
+	pci230_ai_stop(dev, s);
+	return 0;
 }
 
 /* Interrupt handler */
@@ -2544,6 +2594,7 @@ static irqreturn_t pci230_interrupt(int irq, void *d)
 {
 	unsigned char status_int, valid_status_int;
 	struct comedi_device *dev = (struct comedi_device *)d;
+	struct pci230_private *devpriv = dev->private;
 	struct comedi_subdevice *s;
 	unsigned long irqflags;
 
@@ -2603,373 +2654,310 @@ static irqreturn_t pci230_interrupt(int irq, void *d)
 	return IRQ_HANDLED;
 }
 
-static void pci230_handle_ao_nofifo(struct comedi_device *dev,
-				    struct comedi_subdevice *s)
+/* Check if PCI device matches a specific board. */
+static bool pci230_match_pci_board(const struct pci230_board *board,
+				   struct pci_dev *pci_dev)
 {
-	short data;
-	int i, ret;
-	struct comedi_async *async = s->async;
-	struct comedi_cmd *cmd = &async->cmd;
-
-	if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0))
-		return;
+	/* assume pci_dev->device != PCI_DEVICE_ID_INVALID */
+	if (board->id != pci_dev->device)
+		return false;
+	if (board->min_hwver == 0)
+		return true;
+	/* Looking for a '+' model.  First check length of registers. */
+	if (pci_resource_len(pci_dev, 3) < 32)
+		return false;	/* Not a '+' model. */
+	/* TODO: temporarily enable PCI device and read the hardware version
+	 * register.  For now, assume it's okay. */
+	return true;
+}
 
+/* Look for board matching PCI device. */
+static const struct pci230_board *pci230_find_pci_board(struct pci_dev *pci_dev)
+{
+	unsigned int i;
 
-	for (i = 0; i < cmd->chanlist_len; i++) {
-		/* Read sample from Comedi's circular buffer. */
-		ret = comedi_buf_get(s->async, &data);
-		if (ret == 0) {
-			s->async->events |= COMEDI_CB_OVERFLOW;
-			pci230_ao_stop(dev, s);
-			comedi_error(dev, "AO buffer underrun");
-			return;
-		}
-		/* Write value to DAC. */
-		pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i]));
-	}
+	for (i = 0; i < ARRAY_SIZE(pci230_boards); i++)
+		if (pci230_match_pci_board(&pci230_boards[i], pci_dev))
+			return &pci230_boards[i];
+	return NULL;
+}
 
-	async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
-	if (!devpriv->ao_continuous) {
-		devpriv->ao_scan_count--;
-		if (devpriv->ao_scan_count == 0) {
-			/* End of acquisition. */
-			async->events |= COMEDI_CB_EOA;
-			pci230_ao_stop(dev, s);
-		}
-	}
-}
-
-/* Loads DAC FIFO (if using it) from buffer. */
-/* Returns 0 if AO finished due to completion or error, 1 if still going. */
-static int pci230_handle_ao_fifo(struct comedi_device *dev,
-				 struct comedi_subdevice *s)
+/* Look for PCI device matching requested board name, bus and slot. */
+static struct pci_dev *pci230_find_pci(struct comedi_device *dev,
+				       int bus, int slot)
 {
-	struct comedi_async *async = s->async;
-	struct comedi_cmd *cmd = &async->cmd;
-	unsigned int num_scans;
-	unsigned int room;
-	unsigned short dacstat;
-	unsigned int i, n;
-	unsigned int bytes_per_scan;
-	unsigned int events = 0;
-	int running;
-
-	/* Get DAC FIFO status. */
-	dacstat = inw(dev->iobase + PCI230_DACCON);
+	const struct pci230_board *thisboard = comedi_board(dev);
+	struct pci_dev *pci_dev = NULL;
 
-	/* Determine number of scans available in buffer. */
-	bytes_per_scan = cmd->chanlist_len * sizeof(short);
-	num_scans = comedi_buf_read_n_available(async) / bytes_per_scan;
-	if (!devpriv->ao_continuous) {
-		/* Fixed number of scans. */
-		if (num_scans > devpriv->ao_scan_count)
-			num_scans = devpriv->ao_scan_count;
+	for_each_pci_dev(pci_dev) {
+		/* Check vendor ID (same for all supported PCI boards). */
+		if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON)
+			continue;
+		/* If bus/slot specified, check them. */
+		if ((bus || slot) &&
+		    (bus != pci_dev->bus->number ||
+		     slot != PCI_SLOT(pci_dev->devfn)))
+			continue;
+		if (thisboard->id == PCI_DEVICE_ID_INVALID) {
+			/* Wildcard board matches any supported PCI board. */
+			const struct pci230_board *foundboard;
 
-		if (devpriv->ao_scan_count == 0) {
-			/* End of acquisition. */
-			events |= COMEDI_CB_EOA;
-		}
-	}
-	if (events == 0) {
-		/* Check for FIFO underrun. */
-		if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) {
-			comedi_error(dev, "AO FIFO underrun");
-			events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
-		}
-		/* Check for buffer underrun if FIFO less than half full
-		 * (otherwise there will be loads of "DAC FIFO not half full"
-		 * interrupts). */
-		if ((num_scans == 0)
-		    && ((dacstat & PCI230P2_DAC_FIFO_HALF) == 0)) {
-			comedi_error(dev, "AO buffer underrun");
-			events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
+			foundboard = pci230_find_pci_board(pci_dev);
+			if (foundboard == NULL)
+				continue;
+			/* Replace wildcard board_ptr. */
+			dev->board_ptr = foundboard;
+			thisboard = comedi_board(dev);
+		} else {
+			/* Need to match a specific board. */
+			if (!pci230_match_pci_board(thisboard, pci_dev))
+				continue;
 		}
-	}
-	if (events == 0) {
-		/* Determine how much room is in the FIFO (in samples). */
-		if ((dacstat & PCI230P2_DAC_FIFO_FULL) != 0)
-			room = PCI230P2_DAC_FIFOROOM_FULL;
-		else if ((dacstat & PCI230P2_DAC_FIFO_HALF) != 0)
-			room = PCI230P2_DAC_FIFOROOM_HALFTOFULL;
-		else if ((dacstat & PCI230P2_DAC_FIFO_EMPTY) != 0)
-			room = PCI230P2_DAC_FIFOROOM_EMPTY;
-		else
-			room = PCI230P2_DAC_FIFOROOM_ONETOHALF;
-
-		/* Convert room to number of scans that can be added. */
-		room /= cmd->chanlist_len;
-		/* Determine number of scans to process. */
-		if (num_scans > room)
-			num_scans = room;
+		/* Found a matching PCI device. */
+		return pci_dev;
+	}
+	/* No matching PCI device found. */
+	if (bus || slot)
+		dev_err(dev->class_dev,
+			"error! no %s found at pci %02x:%02x\n",
+			thisboard->name, bus, slot);
+	else
+		dev_err(dev->class_dev,
+			"error! no %s found\n", thisboard->name);
+	return NULL;
+}
 
-		/* Process scans. */
-		for (n = 0; n < num_scans; n++) {
-			for (i = 0; i < cmd->chanlist_len; i++) {
-				short datum;
+static int pci230_alloc_private(struct comedi_device *dev)
+{
+	struct pci230_private *devpriv;
+	int err;
 
-				comedi_buf_get(async, &datum);
-				pci230_ao_write_fifo(dev, datum,
-						     CR_CHAN(cmd->chanlist[i]));
-			}
-		}
-		events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK;
-		if (!devpriv->ao_continuous) {
-			devpriv->ao_scan_count -= num_scans;
-			if (devpriv->ao_scan_count == 0) {
-				/* All data for the command has been written
-				 * to FIFO.  Set FIFO interrupt trigger level
-				 * to 'empty'. */
-				devpriv->daccon = (devpriv->daccon
-						   &
-						   ~PCI230P2_DAC_INT_FIFO_MASK)
-				    | PCI230P2_DAC_INT_FIFO_EMPTY;
-				outw(devpriv->daccon,
-				     dev->iobase + PCI230_DACCON);
-			}
-		}
-		/* Check if FIFO underrun occurred while writing to FIFO. */
-		dacstat = inw(dev->iobase + PCI230_DACCON);
-		if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) {
-			comedi_error(dev, "AO FIFO underrun");
-			events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
-		}
+	/* sets dev->private to allocated memory */
+	err = alloc_private(dev, sizeof(struct pci230_private));
+	if (err) {
+		dev_err(dev->class_dev, "error! out of memory!\n");
+		return err;
 	}
-	if ((events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW))
-	    != 0) {
-		/* Stopping AO due to completion or error. */
-		pci230_ao_stop(dev, s);
-		running = 0;
-	} else {
-		running = 1;
-	}
-	async->events |= events;
-	return running;
+	devpriv = dev->private;
+	spin_lock_init(&devpriv->isr_spinlock);
+	spin_lock_init(&devpriv->res_spinlock);
+	spin_lock_init(&devpriv->ai_stop_spinlock);
+	spin_lock_init(&devpriv->ao_stop_spinlock);
+	return 0;
 }
 
-static void pci230_handle_ai(struct comedi_device *dev,
-			     struct comedi_subdevice *s)
+/* Common part of attach and attach_pci. */
+static int pci230_attach_common(struct comedi_device *dev,
+				struct pci_dev *pci_dev)
 {
-	unsigned int events = 0;
-	unsigned int status_fifo;
-	unsigned int i;
-	unsigned int todo;
-	unsigned int fifoamount;
-	struct comedi_async *async = s->async;
-	unsigned int scanlen = async->cmd.scan_end_arg;
-
-	/* Determine number of samples to read. */
-	if (devpriv->ai_continuous) {
-		todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
-	} else if (devpriv->ai_scan_count == 0) {
-		todo = 0;
-	} else if ((devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL)
-		   || (scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL)) {
-		todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
-	} else {
-		todo = (devpriv->ai_scan_count * scanlen)
-		    - devpriv->ai_scan_pos;
-		if (todo > PCI230_ADC_FIFOLEVEL_HALFFULL)
-			todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
+	const struct pci230_board *thisboard = comedi_board(dev);
+	struct pci230_private *devpriv = dev->private;
+	struct comedi_subdevice *s;
+	unsigned long iobase1, iobase2;
+	/* PCI230's I/O spaces 1 and 2 respectively. */
+	int irq_hdl, rc;
 
+	devpriv->pci_dev = pci_dev;
+	dev->board_name = thisboard->name;
+	/* Enable PCI device and reserve I/O spaces. */
+	if (comedi_pci_enable(pci_dev, "amplc_pci230") < 0) {
+		dev_err(dev->class_dev,
+			"failed to enable PCI device and request regions\n");
+		return -EIO;
 	}
+	/* Read base addresses of the PCI230's two I/O regions from PCI
+	 * configuration register. */
+	iobase1 = pci_resource_start(pci_dev, 2);
+	iobase2 = pci_resource_start(pci_dev, 3);
+	dev_dbg(dev->class_dev,
+		"%s I/O region 1 0x%04lx I/O region 2 0x%04lx\n",
+		dev->board_name, iobase1, iobase2);
+	devpriv->iobase1 = iobase1;
+	dev->iobase = iobase2;
+	/* Read bits of DACCON register - only the output range. */
+	devpriv->daccon = inw(dev->iobase + PCI230_DACCON) & PCI230_DAC_OR_MASK;
+	/* Read hardware version register and set extended function register
+	 * if they exist. */
+	if (pci_resource_len(pci_dev, 3) >= 32) {
+		unsigned short extfunc = 0;
 
-	if (todo == 0)
-		return;
-
-
-	fifoamount = 0;
-	for (i = 0; i < todo; i++) {
-		if (fifoamount == 0) {
-			/* Read FIFO state. */
-			status_fifo = inw(dev->iobase + PCI230_ADCCON);
-
-			if ((status_fifo & PCI230_ADC_FIFO_FULL_LATCHED) != 0) {
-				/* Report error otherwise FIFO overruns will go
-				 * unnoticed by the caller. */
-				comedi_error(dev, "AI FIFO overrun");
-				events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
-				break;
-			} else if ((status_fifo & PCI230_ADC_FIFO_EMPTY) != 0) {
-				/* FIFO empty. */
-				break;
-			} else if ((status_fifo & PCI230_ADC_FIFO_HALF) != 0) {
-				/* FIFO half full. */
-				fifoamount = PCI230_ADC_FIFOLEVEL_HALFFULL;
-			} else {
-				/* FIFO not empty. */
-				if (devpriv->hwver > 0) {
-					/* Read PCI230+/260+ ADC FIFO level. */
-					fifoamount = inw(dev->iobase
-							 + PCI230P_ADCFFLEV);
-					if (fifoamount == 0) {
-						/* Shouldn't happen. */
-						break;
-					}
-				} else {
-					fifoamount = 1;
-				}
-			}
+		devpriv->hwver = inw(dev->iobase + PCI230P_HWVER);
+		if (devpriv->hwver < thisboard->min_hwver) {
+			dev_err(dev->class_dev,
+				"%s - bad hardware version - got %u, need %u\n",
+				dev->board_name, devpriv->hwver,
+				thisboard->min_hwver);
+			return -EIO;
 		}
-
-		/* Read sample and store in Comedi's circular buffer. */
-		if (comedi_buf_put(async, pci230_ai_read(dev)) == 0) {
-			events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
-			comedi_error(dev, "AI buffer overflow");
-			break;
+		if (devpriv->hwver > 0) {
+			if (!thisboard->have_dio) {
+				/* No DIO ports.  Route counters' external gates
+				 * to the EXTTRIG signal (PCI260+ pin 17).
+				 * (Otherwise, they would be routed to DIO
+				 * inputs PC0, PC1 and PC2 which don't exist
+				 * on PCI260[+].) */
+				extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG;
+			}
+			if ((thisboard->ao_chans > 0)
+			    && (devpriv->hwver >= 2)) {
+				/* Enable DAC FIFO functionality. */
+				extfunc |= PCI230P2_EXTFUNC_DACFIFO;
+			}
 		}
-		fifoamount--;
-		devpriv->ai_scan_pos++;
-		if (devpriv->ai_scan_pos == scanlen) {
-			/* End of scan. */
-			devpriv->ai_scan_pos = 0;
-			devpriv->ai_scan_count--;
-			async->events |= COMEDI_CB_EOS;
+		outw(extfunc, dev->iobase + PCI230P_EXTFUNC);
+		if ((extfunc & PCI230P2_EXTFUNC_DACFIFO) != 0) {
+			/* Temporarily enable DAC FIFO, reset it and disable
+			 * FIFO wraparound. */
+			outw(devpriv->daccon | PCI230P2_DAC_FIFO_EN
+			     | PCI230P2_DAC_FIFO_RESET,
+			     dev->iobase + PCI230_DACCON);
+			/* Clear DAC FIFO channel enable register. */
+			outw(0, dev->iobase + PCI230P2_DACEN);
+			/* Disable DAC FIFO. */
+			outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
 		}
 	}
-
-	if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
-		/* End of acquisition. */
-		events |= COMEDI_CB_EOA;
+	/* Disable board's interrupts. */
+	outb(0, devpriv->iobase1 + PCI230_INT_SCE);
+	/* Set ADC to a reasonable state. */
+	devpriv->adcg = 0;
+	devpriv->adccon = PCI230_ADC_TRIG_NONE | PCI230_ADC_IM_SE
+	    | PCI230_ADC_IR_BIP;
+	outw(1 << 0, dev->iobase + PCI230_ADCEN);
+	outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
+	outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
+	     dev->iobase + PCI230_ADCCON);
+	/* Register the interrupt handler. */
+	irq_hdl = request_irq(devpriv->pci_dev->irq, pci230_interrupt,
+			      IRQF_SHARED, "amplc_pci230", dev);
+	if (irq_hdl < 0) {
+		dev_warn(dev->class_dev,
+			 "unable to register irq %u, commands will not be available\n",
+			 devpriv->pci_dev->irq);
 	} else {
-		/* More samples required, tell Comedi to block. */
-		events |= COMEDI_CB_BLOCK;
+		dev->irq = devpriv->pci_dev->irq;
+		dev_dbg(dev->class_dev, "registered irq %u\n",
+			devpriv->pci_dev->irq);
 	}
-	async->events |= events;
 
-	if ((async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
-			      COMEDI_CB_OVERFLOW)) != 0) {
-		/* disable hardware conversions */
-		pci230_ai_stop(dev, s);
-	} else {
-		/* update FIFO interrupt trigger level */
-		pci230_ai_update_fifo_trigger_level(dev, s);
-	}
-}
+	rc = comedi_alloc_subdevices(dev, 3);
+	if (rc)
+		return rc;
 
-static void pci230_ao_stop(struct comedi_device *dev,
-			   struct comedi_subdevice *s)
-{
-	unsigned long irqflags;
-	unsigned char intsrc;
-	int started;
-	struct comedi_cmd *cmd;
-
-	spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
-	started = test_and_clear_bit(AO_CMD_STARTED, &devpriv->state);
-	spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags);
-	if (!started)
-		return;
-
-
-	cmd = &s->async->cmd;
-	if (cmd->scan_begin_src == TRIG_TIMER) {
-		/* Stop scan rate generator. */
-		pci230_cancel_ct(dev, 1);
+	s = dev->subdevices + 0;
+	/* analog input subdevice */
+	s->type = COMEDI_SUBD_AI;
+	s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
+	s->n_chan = thisboard->ai_chans;
+	s->maxdata = (1 << thisboard->ai_bits) - 1;
+	s->range_table = &pci230_ai_range;
+	s->insn_read = &pci230_ai_rinsn;
+	s->len_chanlist = 256;	/* but there are restrictions. */
+	/* Only register commands if the interrupt handler is installed. */
+	if (irq_hdl == 0) {
+		dev->read_subdev = s;
+		s->subdev_flags |= SDF_CMD_READ;
+		s->do_cmd = &pci230_ai_cmd;
+		s->do_cmdtest = &pci230_ai_cmdtest;
+		s->cancel = pci230_ai_cancel;
 	}
-
-	/* Determine interrupt source. */
-	if (devpriv->hwver < 2) {
-		/* Not using DAC FIFO.  Using CT1 interrupt. */
-		intsrc = PCI230_INT_ZCLK_CT1;
+	s = dev->subdevices + 1;
+	/* analog output subdevice */
+	if (thisboard->ao_chans > 0) {
+		s->type = COMEDI_SUBD_AO;
+		s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
+		s->n_chan = thisboard->ao_chans;
+		s->maxdata = (1 << thisboard->ao_bits) - 1;
+		s->range_table = &pci230_ao_range;
+		s->insn_write = &pci230_ao_winsn;
+		s->insn_read = &pci230_ao_rinsn;
+		s->len_chanlist = thisboard->ao_chans;
+		/* Only register commands if the interrupt handler is
+		 * installed. */
+		if (irq_hdl == 0) {
+			dev->write_subdev = s;
+			s->subdev_flags |= SDF_CMD_WRITE;
+			s->do_cmd = &pci230_ao_cmd;
+			s->do_cmdtest = &pci230_ao_cmdtest;
+			s->cancel = pci230_ao_cancel;
+		}
 	} else {
-		/* Using DAC FIFO interrupt. */
-		intsrc = PCI230P2_INT_DAC;
-	}
-	/* Disable interrupt and wait for interrupt routine to finish running
-	 * unless we are called from the interrupt routine. */
-	spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
-	devpriv->int_en &= ~intsrc;
-	while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
-		spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
-		spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
-	}
-	if (devpriv->ier != devpriv->int_en) {
-		devpriv->ier = devpriv->int_en;
-		outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
+		s->type = COMEDI_SUBD_UNUSED;
 	}
-	spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
-
-	if (devpriv->hwver >= 2) {
-		/* Using DAC FIFO.  Reset FIFO, clear underrun error,
-		 * disable FIFO. */
-		devpriv->daccon &= PCI230_DAC_OR_MASK;
-		outw(devpriv->daccon | PCI230P2_DAC_FIFO_RESET
-		     | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR,
-		     dev->iobase + PCI230_DACCON);
+	s = dev->subdevices + 2;
+	/* digital i/o subdevice */
+	if (thisboard->have_dio) {
+		rc = subdev_8255_init(dev, s, NULL,
+				      (devpriv->iobase1 + PCI230_PPI_X_BASE));
+		if (rc < 0)
+			return rc;
+	} else {
+		s->type = COMEDI_SUBD_UNUSED;
 	}
-
-	/* Release resources. */
-	put_all_resources(dev, OWNER_AOCMD);
+	dev_info(dev->class_dev, "attached\n");
+	return 1;
 }
 
-static int pci230_ao_cancel(struct comedi_device *dev,
-			    struct comedi_subdevice *s)
+static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
-	pci230_ao_stop(dev, s);
-	return 0;
+	const struct pci230_board *thisboard = comedi_board(dev);
+	struct pci_dev *pci_dev;
+	int rc;
+
+	dev_info(dev->class_dev, "amplc_pci230: attach %s %d,%d\n",
+		 thisboard->name, it->options[0], it->options[1]);
+	rc = pci230_alloc_private(dev); /* sets dev->private */
+	if (rc)
+		return rc;
+	/* Find card. */
+	pci_dev = pci230_find_pci(dev, it->options[0], it->options[1]);
+	if (!pci_dev)
+		return -EIO;
+	return pci230_attach_common(dev, pci_dev);
 }
 
-static void pci230_ai_stop(struct comedi_device *dev,
-			   struct comedi_subdevice *s)
+static int __devinit pci230_attach_pci(struct comedi_device *dev,
+				       struct pci_dev *pci_dev)
 {
-	unsigned long irqflags;
-	struct comedi_cmd *cmd;
-	int started;
-
-	spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
-	started = test_and_clear_bit(AI_CMD_STARTED, &devpriv->state);
-	spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
-	if (!started)
-		return;
-
-
-	cmd = &s->async->cmd;
-	if (cmd->convert_src == TRIG_TIMER) {
-		/* Stop conversion rate generator. */
-		pci230_cancel_ct(dev, 2);
-	}
-	if (cmd->scan_begin_src != TRIG_FOLLOW) {
-		/* Stop scan period monostable. */
-		pci230_cancel_ct(dev, 0);
-	}
-
-	spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
-	/* Disable ADC interrupt and wait for interrupt routine to finish
-	 * running unless we are called from the interrupt routine. */
-	devpriv->int_en &= ~PCI230_INT_ADC;
-	while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
-		spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
-		spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
-	}
-	if (devpriv->ier != devpriv->int_en) {
-		devpriv->ier = devpriv->int_en;
-		outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
+	int rc;
+
+	dev_info(dev->class_dev, "amplc_pci230: attach pci %s\n",
+		 pci_name(pci_dev));
+	rc = pci230_alloc_private(dev); /* sets dev->private */
+	if (rc)
+		return rc;
+	dev->board_ptr = pci230_find_pci_board(pci_dev);
+	if (dev->board_ptr == NULL) {
+		dev_err(dev->class_dev,
+			"amplc_pci230: BUG! cannot determine board type!\n");
+		return -EINVAL;
 	}
-	spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
-
-	/* Reset FIFO, disable FIFO and set start conversion source to none.
-	 * Keep se/diff and bip/uni settings */
-	devpriv->adccon = (devpriv->adccon & (PCI230_ADC_IR_MASK
-					      | PCI230_ADC_IM_MASK)) |
-	    PCI230_ADC_TRIG_NONE;
-	outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
-	     dev->iobase + PCI230_ADCCON);
-
-	/* Release resources. */
-	put_all_resources(dev, OWNER_AICMD);
+	return pci230_attach_common(dev, pci_dev);
 }
 
-static int pci230_ai_cancel(struct comedi_device *dev,
-			    struct comedi_subdevice *s)
+static void pci230_detach(struct comedi_device *dev)
 {
-	pci230_ai_stop(dev, s);
-	return 0;
+	const struct pci230_board *thisboard = comedi_board(dev);
+	struct pci230_private *devpriv = dev->private;
+
+	if (dev->subdevices && thisboard->have_dio)
+		subdev_8255_cleanup(dev, dev->subdevices + 2);
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (devpriv) {
+		if (devpriv->pci_dev) {
+			if (dev->iobase)
+				comedi_pci_disable(devpriv->pci_dev);
+			pci_dev_put(devpriv->pci_dev);
+		}
+	}
 }
 
 static struct comedi_driver amplc_pci230_driver = {
 	.driver_name	= "amplc_pci230",
 	.module		= THIS_MODULE,
 	.attach		= pci230_attach,
+	.attach_pci	= pci230_attach_pci,
 	.detach		= pci230_detach,
 	.board_name	= &pci230_boards[0].name,
 	.offset		= sizeof(pci230_boards[0]),
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index fb9951a..41ed857 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -433,8 +433,8 @@ static int c6xdigio_attach(struct comedi_device *dev,
 	dev->iobase = iobase;
 	dev->board_name = "c6xdigio";
 
-	result = alloc_subdevices(dev, 2);	/*  3 with encoder_init write */
-	if (result < 0)
+	result = comedi_alloc_subdevices(dev, 2);
+	if (result)
 		return result;
 
 	/*  Make sure that PnP ports get activated */
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 3515923..58d4529 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -19,6 +19,13 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
+    PCMCIA support code for this driver is adapted from the dummy_cs.c
+    driver of the Linux PCMCIA Card Services package.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
 */
 /*
 Driver: cb_das16_cs
@@ -35,7 +42,6 @@ Status: experimental
 #include <linux/slab.h>
 #include "../comedidev.h"
 #include <linux/delay.h>
-#include <linux/pci.h>
 
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
@@ -59,207 +65,39 @@ struct das16cs_board {
 	int device_id;
 	int n_ao_chans;
 };
+
 static const struct das16cs_board das16cs_boards[] = {
 	{
-	 .device_id = 0x0000,	/* unknown */
-	 .name = "PC-CARD DAS16/16",
-	 .n_ao_chans = 0,
-	 },
-	{
-	 .device_id = 0x0039,
-	 .name = "PC-CARD DAS16/16-AO",
-	 .n_ao_chans = 2,
-	 },
-	{
-	 .device_id = 0x4009,
-	 .name = "PCM-DAS16s/16",
-	 .n_ao_chans = 0,
-	 },
+		.name		= "PC-CARD DAS16/16-AO",
+		.device_id	= 0x0039,
+		.n_ao_chans	= 2,
+	}, {
+		.name		= "PCM-DAS16s/16",
+		.device_id	= 0x4009,
+		.n_ao_chans	= 0,
+	}, {
+		.name		= "PC-CARD DAS16/16",
+		.device_id	= 0x0000,	/* unknown */
+		.n_ao_chans	= 0,
+	},
 };
 
-#define n_boards ARRAY_SIZE(das16cs_boards)
-#define thisboard ((const struct das16cs_board *)dev->board_ptr)
-
 struct das16cs_private {
-	struct pcmcia_device *link;
-
 	unsigned int ao_readback[2];
 	unsigned short status1;
 	unsigned short status2;
 };
-#define devpriv ((struct das16cs_private *)dev->private)
-
-static int das16cs_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it);
-static void das16cs_detach(struct comedi_device *dev);
-static struct comedi_driver driver_das16cs = {
-	.driver_name = "cb_das16_cs",
-	.module = THIS_MODULE,
-	.attach = das16cs_attach,
-	.detach = das16cs_detach,
-};
 
 static struct pcmcia_device *cur_dev;
 
-static const struct comedi_lrange das16cs_ai_range = { 4, {
-							   RANGE(-10, 10),
-							   RANGE(-5, 5),
-							   RANGE(-2.5, 2.5),
-							   RANGE(-1.25, 1.25),
-							   }
-};
-
-static irqreturn_t das16cs_interrupt(int irq, void *d);
-static int das16cs_ai_rinsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int das16cs_ai_cmd(struct comedi_device *dev,
-			  struct comedi_subdevice *s);
-static int das16cs_ai_cmdtest(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_cmd *cmd);
-static int das16cs_ao_winsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int das16cs_ao_rinsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int das16cs_dio_insn_bits(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data);
-static int das16cs_dio_insn_config(struct comedi_device *dev,
-				   struct comedi_subdevice *s,
-				   struct comedi_insn *insn,
-				   unsigned int *data);
-static int das16cs_timer_insn_read(struct comedi_device *dev,
-				   struct comedi_subdevice *s,
-				   struct comedi_insn *insn,
-				   unsigned int *data);
-static int das16cs_timer_insn_config(struct comedi_device *dev,
-				     struct comedi_subdevice *s,
-				     struct comedi_insn *insn,
-				     unsigned int *data);
-
-static const struct das16cs_board *das16cs_probe(struct comedi_device *dev,
-						 struct pcmcia_device *link)
-{
-	int i;
-
-	for (i = 0; i < n_boards; i++) {
-		if (das16cs_boards[i].device_id == link->card_id)
-			return das16cs_boards + i;
-	}
-
-	dev_dbg(dev->hw_dev, "unknown board!\n");
-
-	return NULL;
-}
-
-static int das16cs_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
-{
-	struct pcmcia_device *link;
-	struct comedi_subdevice *s;
-	int ret;
-	int i;
-
-	dev_dbg(dev->hw_dev, "comedi%d: cb_das16_cs: attached\n", dev->minor);
-
-	link = cur_dev;		/* XXX hack */
-	if (!link)
-		return -EIO;
-
-	dev->iobase = link->resource[0]->start;
-	dev_dbg(dev->hw_dev, "I/O base=0x%04lx\n", dev->iobase);
-
-	dev_dbg(dev->hw_dev, "fingerprint:\n");
-	for (i = 0; i < 48; i += 2)
-		dev_dbg(dev->hw_dev, "%04x\n", inw(dev->iobase + i));
-
-
-	ret = request_irq(link->irq, das16cs_interrupt,
-			  IRQF_SHARED, "cb_das16_cs", dev);
-	if (ret < 0)
-		return ret;
-
-	dev->irq = link->irq;
-
-	dev_dbg(dev->hw_dev, "irq=%u\n", dev->irq);
-
-	dev->board_ptr = das16cs_probe(dev, link);
-	if (!dev->board_ptr)
-		return -EIO;
-
-	dev->board_name = thisboard->name;
-
-	if (alloc_private(dev, sizeof(struct das16cs_private)) < 0)
-		return -ENOMEM;
-
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
-
-	s = dev->subdevices + 0;
-	dev->read_subdev = s;
-	/* analog input subdevice */
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
-	s->n_chan = 16;
-	s->maxdata = 0xffff;
-	s->range_table = &das16cs_ai_range;
-	s->len_chanlist = 16;
-	s->insn_read = das16cs_ai_rinsn;
-	s->do_cmd = das16cs_ai_cmd;
-	s->do_cmdtest = das16cs_ai_cmdtest;
-
-	s = dev->subdevices + 1;
-	/* analog output subdevice */
-	if (thisboard->n_ao_chans) {
-		s->type = COMEDI_SUBD_AO;
-		s->subdev_flags = SDF_WRITABLE;
-		s->n_chan = thisboard->n_ao_chans;
-		s->maxdata = 0xffff;
-		s->range_table = &range_bipolar10;
-		s->insn_write = &das16cs_ao_winsn;
-		s->insn_read = &das16cs_ao_rinsn;
-	}
-
-	s = dev->subdevices + 2;
-	/* digital i/o subdevice */
-	if (1) {
-		s->type = COMEDI_SUBD_DIO;
-		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->n_chan = 8;
-		s->maxdata = 1;
-		s->range_table = &range_digital;
-		s->insn_bits = das16cs_dio_insn_bits;
-		s->insn_config = das16cs_dio_insn_config;
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
-
-	s = dev->subdevices + 3;
-	/* timer subdevice */
-	if (0) {
-		s->type = COMEDI_SUBD_TIMER;
-		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->n_chan = 1;
-		s->maxdata = 0xff;
-		s->range_table = &range_unknown;
-		s->insn_read = das16cs_timer_insn_read;
-		s->insn_config = das16cs_timer_insn_config;
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
+static const struct comedi_lrange das16cs_ai_range = {
+	4, {
+		BIP_RANGE(10),
+		BIP_RANGE(5),
+		BIP_RANGE(2.5),
+		BIP_RANGE(1.25),
 	}
-
-
-	return 1;
-}
-
-static void das16cs_detach(struct comedi_device *dev)
-{
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-}
+};
 
 static irqreturn_t das16cs_interrupt(int irq, void *d)
 {
@@ -267,48 +105,53 @@ static irqreturn_t das16cs_interrupt(int irq, void *d)
 	return IRQ_HANDLED;
 }
 
-/*
- * "instructions" read/write data in "one-shot" or "software-triggered"
- * mode.
- */
 static int das16cs_ai_rinsn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
 {
+	struct das16cs_private *devpriv = dev->private;
+	int chan = CR_CHAN(insn->chanspec);
+	int range = CR_RANGE(insn->chanspec);
+	int aref = CR_AREF(insn->chanspec);
 	int i;
 	int to;
-	int aref;
-	int range;
-	int chan;
-	static int range_bits[] = { 0x800, 0x000, 0x100, 0x200 };
 
-	chan = CR_CHAN(insn->chanspec);
-	aref = CR_AREF(insn->chanspec);
-	range = CR_RANGE(insn->chanspec);
-
-	outw(chan, dev->iobase + 2);
+	outw(chan, dev->iobase + DAS16CS_DIO_MUX);
 
 	devpriv->status1 &= ~0xf320;
 	devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020;
-	outw(devpriv->status1, dev->iobase + 4);
+	outw(devpriv->status1, dev->iobase + DAS16CS_MISC1);
 
 	devpriv->status2 &= ~0xff00;
-	devpriv->status2 |= range_bits[range];
-	outw(devpriv->status2, dev->iobase + 6);
+	switch (range) {
+	case 0:
+		devpriv->status2 |= 0x800;
+		break;
+	case 1:
+		devpriv->status2 |= 0x000;
+		break;
+	case 2:
+		devpriv->status2 |= 0x100;
+		break;
+	case 3:
+		devpriv->status2 |= 0x200;
+		break;
+	}
+	outw(devpriv->status2, dev->iobase + DAS16CS_MISC2);
 
 	for (i = 0; i < insn->n; i++) {
-		outw(0, dev->iobase);
+		outw(0, dev->iobase + DAS16CS_ADC_DATA);
 
 #define TIMEOUT 1000
 		for (to = 0; to < TIMEOUT; to++) {
-			if (inw(dev->iobase + 4) & 0x0080)
+			if (inw(dev->iobase + DAS16CS_MISC1) & 0x0080)
 				break;
 		}
 		if (to == TIMEOUT) {
-			dev_dbg(dev->hw_dev, "cb_das16_cs: ai timeout\n");
+			dev_dbg(dev->class_dev, "cb_das16_cs: ai timeout\n");
 			return -ETIME;
 		}
-		data[i] = (unsigned short)inw(dev->iobase + 0);
+		data[i] = inw(dev->iobase + DAS16CS_ADC_DATA);
 	}
 
 	return i;
@@ -326,13 +169,6 @@ static int das16cs_ai_cmdtest(struct comedi_device *dev,
 	int err = 0;
 	int tmp;
 
-	/* cmdtest tests a particular command to see if it is valid.
-	 * Using the cmdtest ioctl, a user can create a valid cmd
-	 * and then have it executes by the cmd ioctl.
-	 *
-	 * cmdtest returns 1,2,3,4 or 0, depending on which tests
-	 * the command passes. */
-
 	/* step 1: make sure trigger sources are trivially valid */
 
 	tmp = cmd->start_src;
@@ -483,6 +319,7 @@ static int das16cs_ao_winsn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
 {
+	struct das16cs_private *devpriv = dev->private;
 	int i;
 	int chan = CR_CHAN(insn->chanspec);
 	unsigned short status1;
@@ -493,7 +330,7 @@ static int das16cs_ao_winsn(struct comedi_device *dev,
 		devpriv->ao_readback[chan] = data[i];
 		d = data[i];
 
-		outw(devpriv->status1, dev->iobase + 4);
+		outw(devpriv->status1, dev->iobase + DAS16CS_MISC1);
 		udelay(1);
 
 		status1 = devpriv->status1 & ~0xf;
@@ -502,34 +339,32 @@ static int das16cs_ao_winsn(struct comedi_device *dev,
 		else
 			status1 |= 0x0008;
 
-/*		printk("0x%04x\n",status1);*/
-		outw(status1, dev->iobase + 4);
+		outw(status1, dev->iobase + DAS16CS_MISC1);
 		udelay(1);
 
 		for (bit = 15; bit >= 0; bit--) {
 			int b = (d >> bit) & 0x1;
 			b <<= 1;
-/*			printk("0x%04x\n",status1 | b | 0x0000);*/
-			outw(status1 | b | 0x0000, dev->iobase + 4);
+			outw(status1 | b | 0x0000, dev->iobase + DAS16CS_MISC1);
 			udelay(1);
-/*			printk("0x%04x\n",status1 | b | 0x0004);*/
-			outw(status1 | b | 0x0004, dev->iobase + 4);
+			outw(status1 | b | 0x0004, dev->iobase + DAS16CS_MISC1);
 			udelay(1);
 		}
-/*		make high both DAC0CS and DAC1CS to load
-		new data and update analog output*/
-		outw(status1 | 0x9, dev->iobase + 4);
+		/*
+		 * Make both DAC0CS and DAC1CS high to load
+		 * the new data and update analog the output
+		 */
+		outw(status1 | 0x9, dev->iobase + DAS16CS_MISC1);
 	}
 
 	return i;
 }
 
-/* AO subdevices should have a read insn as well as a write insn.
- * Usually this means copying a value stored in devpriv. */
 static int das16cs_ao_rinsn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
 {
+	struct das16cs_private *devpriv = dev->private;
 	int i;
 	int chan = CR_CHAN(insn->chanspec);
 
@@ -539,36 +374,27 @@ static int das16cs_ao_rinsn(struct comedi_device *dev,
 	return i;
 }
 
-/* DIO devices are slightly special.  Although it is possible to
- * implement the insn_read/insn_write interface, it is much more
- * useful to applications if you implement the insn_bits interface.
- * This allows packed reading/writing of the DIO channels.  The
- * comedi core can convert between insn_bits and insn_read/write */
 static int das16cs_dio_insn_bits(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= data[0] & data[1];
 
-		outw(s->state, dev->iobase + 16);
+		outw(s->state, dev->iobase + DAS16CS_DIO);
 	}
 
-	/* on return, data[1] contains the value of the digital
-	 * input and output lines. */
-	data[1] = inw(dev->iobase + 16);
+	data[1] = inw(dev->iobase + DAS16CS_DIO);
 
-	return 2;
+	return insn->n;
 }
 
 static int das16cs_dio_insn_config(struct comedi_device *dev,
 				   struct comedi_subdevice *s,
 				   struct comedi_insn *insn, unsigned int *data)
 {
+	struct das16cs_private *devpriv = dev->private;
 	int chan = CR_CHAN(insn->chanspec);
 	int bits;
 
@@ -598,110 +424,116 @@ static int das16cs_dio_insn_config(struct comedi_device *dev,
 	devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0;
 	devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0;
 
-	outw(devpriv->status2, dev->iobase + 6);
+	outw(devpriv->status2, dev->iobase + DAS16CS_MISC2);
 
 	return insn->n;
 }
 
-static int das16cs_timer_insn_read(struct comedi_device *dev,
-				   struct comedi_subdevice *s,
-				   struct comedi_insn *insn, unsigned int *data)
-{
-	return -EINVAL;
-}
-
-static int das16cs_timer_insn_config(struct comedi_device *dev,
-				     struct comedi_subdevice *s,
-				     struct comedi_insn *insn,
-				     unsigned int *data)
+static const struct das16cs_board *das16cs_probe(struct comedi_device *dev,
+						 struct pcmcia_device *link)
 {
-	return -EINVAL;
-}
-
-/* PCMCIA stuff */
-
-/*======================================================================
-
-    The following pcmcia code for the pcm-das08 is adapted from the
-    dummy_cs.c driver of the Linux PCMCIA Card Services package.
-
-    The initial developer of the original code is David A. Hinds
-    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-
-======================================================================*/
-
-#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
-
-static void das16cs_pcmcia_config(struct pcmcia_device *link);
-static void das16cs_pcmcia_release(struct pcmcia_device *link);
-static int das16cs_pcmcia_suspend(struct pcmcia_device *p_dev);
-static int das16cs_pcmcia_resume(struct pcmcia_device *p_dev);
+	int i;
 
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
+	for (i = 0; i < ARRAY_SIZE(das16cs_boards); i++) {
+		if (das16cs_boards[i].device_id == link->card_id)
+			return das16cs_boards + i;
+	}
 
-static int das16cs_pcmcia_attach(struct pcmcia_device *);
-static void das16cs_pcmcia_detach(struct pcmcia_device *);
+	dev_dbg(dev->class_dev, "unknown board!\n");
 
-/*
-   You'll also need to prototype all the functions that will actually
-   be used to talk to your device.  See 'memory_cs' for a good example
-   of a fully self-sufficient driver; the other drivers rely more or
-   less on other parts of the kernel.
-*/
+	return NULL;
+}
 
-struct local_info_t {
+static int das16cs_attach(struct comedi_device *dev,
+			  struct comedi_devconfig *it)
+{
+	const struct das16cs_board *thisboard;
 	struct pcmcia_device *link;
-	int stop;
-	struct bus_operations *bus;
-};
-
-/*======================================================================
+	struct comedi_subdevice *s;
+	int ret;
 
-    das16cs_pcmcia_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
+	link = cur_dev;		/* XXX hack */
+	if (!link)
+		return -EIO;
 
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
+	dev->board_ptr = das16cs_probe(dev, link);
+	if (!dev->board_ptr)
+		return -EIO;
+	thisboard = comedi_board(dev);
 
-======================================================================*/
+	dev->board_name = thisboard->name;
 
-static int das16cs_pcmcia_attach(struct pcmcia_device *link)
-{
-	struct local_info_t *local;
+	dev->iobase = link->resource[0]->start;
 
-	dev_dbg(&link->dev, "das16cs_pcmcia_attach()\n");
+	ret = request_irq(link->irq, das16cs_interrupt,
+			  IRQF_SHARED, "cb_das16_cs", dev);
+	if (ret < 0)
+		return ret;
+	dev->irq = link->irq;
 
-	/* Allocate space for private device-specific data */
-	local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
-	if (!local)
+	if (alloc_private(dev, sizeof(struct das16cs_private)) < 0)
 		return -ENOMEM;
-	local->link = link;
-	link->priv = local;
 
-	cur_dev = link;
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
+		return ret;
 
-	das16cs_pcmcia_config(link);
+	s = dev->subdevices + 0;
+	dev->read_subdev = s;
+	/* analog input subdevice */
+	s->type		= COMEDI_SUBD_AI;
+	s->subdev_flags	= SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
+	s->n_chan	= 16;
+	s->maxdata	= 0xffff;
+	s->range_table	= &das16cs_ai_range;
+	s->len_chanlist	= 16;
+	s->insn_read	= das16cs_ai_rinsn;
+	s->do_cmd	= das16cs_ai_cmd;
+	s->do_cmdtest	= das16cs_ai_cmdtest;
+
+	s = dev->subdevices + 1;
+	/* analog output subdevice */
+	if (thisboard->n_ao_chans) {
+		s->type		= COMEDI_SUBD_AO;
+		s->subdev_flags	= SDF_WRITABLE;
+		s->n_chan	= thisboard->n_ao_chans;
+		s->maxdata	= 0xffff;
+		s->range_table	= &range_bipolar10;
+		s->insn_write	= &das16cs_ao_winsn;
+		s->insn_read	= &das16cs_ao_rinsn;
+	} else {
+		s->type		= COMEDI_SUBD_UNUSED;
+	}
+
+	s = dev->subdevices + 2;
+	/* digital i/o subdevice */
+	s->type		= COMEDI_SUBD_DIO;
+	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
+	s->n_chan	= 8;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= das16cs_dio_insn_bits;
+	s->insn_config	= das16cs_dio_insn_config;
+
+	dev_info(dev->class_dev, "%s: %s, I/O base=0x%04lx, irq=%u\n",
+		dev->driver->driver_name, dev->board_name,
+		dev->iobase, dev->irq);
 
 	return 0;
-}				/* das16cs_pcmcia_attach */
+}
 
-static void das16cs_pcmcia_detach(struct pcmcia_device *link)
+static void das16cs_detach(struct comedi_device *dev)
 {
-	dev_dbg(&link->dev, "das16cs_pcmcia_detach\n");
-
-	((struct local_info_t *)link->priv)->stop = 1;
-	das16cs_pcmcia_release(link);
-	/* This points to the parent struct local_info_t struct */
-	kfree(link->priv);
-}				/* das16cs_pcmcia_detach */
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+}
 
+static struct comedi_driver driver_das16cs = {
+	.driver_name	= "cb_das16_cs",
+	.module		= THIS_MODULE,
+	.attach		= das16cs_attach,
+	.detach		= das16cs_detach,
+};
 
 static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev,
 				void *priv_data)
@@ -712,20 +544,16 @@ static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev,
 	return pcmcia_request_io(p_dev);
 }
 
-static void das16cs_pcmcia_config(struct pcmcia_device *link)
+static int das16cs_pcmcia_attach(struct pcmcia_device *link)
 {
 	int ret;
 
-	dev_dbg(&link->dev, "das16cs_pcmcia_config\n");
-
 	/* Do we need to allocate an interrupt? */
 	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
 
 	ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL);
-	if (ret) {
-		dev_warn(&link->dev, "no configuration found\n");
+	if (ret)
 		goto failed;
-	}
 
 	if (!link->irq)
 		goto failed;
@@ -734,99 +562,60 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link)
 	if (ret)
 		goto failed;
 
-	return;
+	cur_dev = link;
+	return 0;
 
 failed:
-	das16cs_pcmcia_release(link);
-}				/* das16cs_pcmcia_config */
-
-static void das16cs_pcmcia_release(struct pcmcia_device *link)
-{
-	dev_dbg(&link->dev, "das16cs_pcmcia_release\n");
 	pcmcia_disable_device(link);
-}				/* das16cs_pcmcia_release */
-
-static int das16cs_pcmcia_suspend(struct pcmcia_device *link)
-{
-	struct local_info_t *local = link->priv;
-
-	/* Mark the device as stopped, to block IO until later */
-	local->stop = 1;
-
-	return 0;
-}				/* das16cs_pcmcia_suspend */
+	return ret;
+}
 
-static int das16cs_pcmcia_resume(struct pcmcia_device *link)
+static void das16cs_pcmcia_detach(struct pcmcia_device *link)
 {
-	struct local_info_t *local = link->priv;
-
-	local->stop = 0;
-	return 0;
-}				/* das16cs_pcmcia_resume */
-
-/*====================================================================*/
+	pcmcia_disable_device(link);
+	cur_dev = NULL;
+}
 
 static const struct pcmcia_device_id das16cs_id_table[] = {
 	PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
 	PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
 	PCMCIA_DEVICE_NULL
 };
-
 MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table);
-MODULE_AUTHOR("David A. Schleef <ds@schleef.org>");
-MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16");
-MODULE_LICENSE("GPL");
 
-struct pcmcia_driver das16cs_driver = {
-	.probe = das16cs_pcmcia_attach,
-	.remove = das16cs_pcmcia_detach,
-	.suspend = das16cs_pcmcia_suspend,
-	.resume = das16cs_pcmcia_resume,
-	.id_table = das16cs_id_table,
-	.owner = THIS_MODULE,
-	.name = "cb_das16_cs",
+static struct pcmcia_driver das16cs_driver = {
+	.name		= "cb_das16_cs",
+	.owner		= THIS_MODULE,
+	.probe		= das16cs_pcmcia_attach,
+	.remove		= das16cs_pcmcia_detach,
+	.id_table	= das16cs_id_table,
 };
 
-static int __init init_das16cs_pcmcia_cs(void)
-{
-	pcmcia_register_driver(&das16cs_driver);
-	return 0;
-}
-
-static void __exit exit_das16cs_pcmcia_cs(void)
-{
-	pr_debug("das16cs_pcmcia_cs: unloading\n");
-	pcmcia_unregister_driver(&das16cs_driver);
-}
-
-int __init init_module(void)
+static int __init das16cs_init(void)
 {
 	int ret;
 
-	ret = init_das16cs_pcmcia_cs();
+	ret = comedi_driver_register(&driver_das16cs);
 	if (ret < 0)
 		return ret;
 
-	return comedi_driver_register(&driver_das16cs);
-}
-
-void __exit cleanup_module(void)
-{
-	exit_das16cs_pcmcia_cs();
-	comedi_driver_unregister(&driver_das16cs);
-}
+	ret = pcmcia_register_driver(&das16cs_driver);
+	if (ret < 0) {
+		comedi_driver_unregister(&driver_das16cs);
+		return ret;
+	}
 
-#else
-static int __init driver_das16cs_init_module(void)
-{
-	return comedi_driver_register(&driver_das16cs);
+	return 0;
 }
+module_init(das16cs_init);
 
-static void __exit driver_das16cs_cleanup_module(void)
+static void __exit das16cs_exit(void)
 {
+	pcmcia_unregister_driver(&das16cs_driver);
 	comedi_driver_unregister(&driver_das16cs);
 }
+module_exit(das16cs_exit);
 
-module_init(driver_das16cs_init_module);
-module_exit(driver_das16cs_cleanup_module);
-#endif /* CONFIG_PCMCIA */
+MODULE_AUTHOR("David A. Schleef <ds@schleef.org>");
+MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index ee9e084..e2bf222 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -57,8 +57,8 @@ range and aref.
 AI Triggering:
    For start_src == TRIG_EXT, the A/D EXTERNAL TRIGGER IN (pin 45) is used.
    For 1602 series, the start_arg is interpreted as follows:
-     start_arg == 0                   => gated triger (level high)
-     start_arg == CR_INVERT           => gated triger (level low)
+     start_arg == 0                   => gated trigger (level high)
+     start_arg == CR_INVERT           => gated trigger (level low)
      start_arg == CR_EDGE             => Rising edge
      start_arg == CR_EDGE | CR_INVERT => Falling edge
    For the other boards the trigger will be done on rising edge
@@ -77,7 +77,6 @@ analog triggering on 1602 series
 #include "8253.h"
 #include "8255.h"
 #include "amcc_s5933.h"
-#include "comedi_pci.h"
 #include "comedi_fc.h"
 
 #undef CB_PCIDAS_DEBUG		/*  disable debugging code */
@@ -534,6 +533,7 @@ static int cb_pcidas_attach(struct comedi_device *dev,
 	struct pci_dev *pcidev = NULL;
 	int index;
 	int i;
+	int ret;
 
 /*
  * Allocate the private structure area.
@@ -567,12 +567,13 @@ static int cb_pcidas_attach(struct comedi_device *dev,
 		}
 	}
 
-	dev_err(dev->hw_dev, "No supported ComputerBoards/MeasurementComputing card found on requested position\n");
+	dev_err(dev->class_dev,
+		"No supported ComputerBoards/MeasurementComputing card found on requested position\n");
 	return -EIO;
 
 found:
 
-	dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n",
+	dev_dbg(dev->class_dev, "Found %s on bus %i, slot %i\n",
 		cb_pcidas_boards[index].name, pcidev->bus->number,
 		PCI_SLOT(pcidev->devfn));
 
@@ -580,7 +581,8 @@ found:
 	 * Enable PCI device and reserve I/O ports.
 	 */
 	if (comedi_pci_enable(pcidev, "cb_pcidas")) {
-		dev_err(dev->hw_dev, "Failed to enable PCI device and request regions\n");
+		dev_err(dev->class_dev,
+			"Failed to enable PCI device and request regions\n");
 		return -EIO;
 	}
 	/*
@@ -606,7 +608,7 @@ found:
 	/*  get irq */
 	if (request_irq(devpriv->pci_dev->irq, cb_pcidas_interrupt,
 			IRQF_SHARED, "cb_pcidas", dev)) {
-		dev_dbg(dev->hw_dev, "unable to allocate irq %d\n",
+		dev_dbg(dev->class_dev, "unable to allocate irq %d\n",
 			devpriv->pci_dev->irq);
 		return -EINVAL;
 	}
@@ -615,11 +617,9 @@ found:
 	/* Initialize dev->board_name */
 	dev->board_name = thisboard->name;
 
-/*
- * Allocate the subdevice structures.
- */
-	if (alloc_subdevices(dev, 7) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 7);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* analog input subdevice */
@@ -809,7 +809,7 @@ static int ai_config_calibration_source(struct comedi_device *dev,
 	unsigned int source = data[1];
 
 	if (source >= num_calibration_sources) {
-		dev_err(dev->hw_dev, "invalid calibration source: %i\n",
+		dev_err(dev->class_dev, "invalid calibration source: %i\n",
 			source);
 		return -EINVAL;
 	}
@@ -1231,7 +1231,7 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
 	outw(bits, devpriv->control_status + ADCMUX_CONT);
 
 #ifdef CB_PCIDAS_DEBUG
-	dev_dbg(dev->hw_dev, "comedi: sent 0x%x to adcmux control\n", bits);
+	dev_dbg(dev->class_dev, "sent 0x%x to adcmux control\n", bits);
 #endif
 
 	/*  load counters */
@@ -1258,7 +1258,7 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
 		devpriv->adc_fifo_bits |= INT_FHF;	/* interrupt fifo half full */
 	}
 #ifdef CB_PCIDAS_DEBUG
-	dev_dbg(dev->hw_dev, "comedi: adc_fifo_bits are 0x%x\n",
+	dev_dbg(dev->class_dev, "adc_fifo_bits are 0x%x\n",
 		devpriv->adc_fifo_bits);
 #endif
 	/*  enable (and clear) interrupts */
@@ -1285,7 +1285,7 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
 		bits |= BURSTE;
 	outw(bits, devpriv->control_status + TRIG_CONTSTAT);
 #ifdef CB_PCIDAS_DEBUG
-	dev_dbg(dev->hw_dev, "comedi: sent 0x%x to trig control\n", bits);
+	dev_dbg(dev->class_dev, "sent 0x%x to trig control\n", bits);
 #endif
 
 	return 0;
@@ -1502,7 +1502,7 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
 	spin_lock_irqsave(&dev->spinlock, flags);
 	devpriv->adc_fifo_bits |= DAEMIE | DAHFIE;
 #ifdef CB_PCIDAS_DEBUG
-	dev_dbg(dev->hw_dev, "comedi: adc_fifo_bits are 0x%x\n",
+	dev_dbg(dev->class_dev, "adc_fifo_bits are 0x%x\n",
 		devpriv->adc_fifo_bits);
 #endif
 	/*  enable and clear interrupts */
@@ -1513,7 +1513,7 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
 	devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY;
 	outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
 #ifdef CB_PCIDAS_DEBUG
-	dev_dbg(dev->hw_dev, "comedi: sent 0x%x to dac control\n",
+	dev_dbg(dev->class_dev, "sent 0x%x to dac control\n",
 		devpriv->ao_control_bits);
 #endif
 	spin_unlock_irqrestore(&dev->spinlock, flags);
@@ -1542,8 +1542,8 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
 
 	s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);
 #ifdef CB_PCIDAS_DEBUG
-	dev_dbg(dev->hw_dev, "intcsr 0x%x\n", s5933_status);
-	dev_dbg(dev->hw_dev, "mbef 0x%x\n",
+	dev_dbg(dev->class_dev, "intcsr 0x%x\n", s5933_status);
+	dev_dbg(dev->class_dev, "mbef 0x%x\n",
 		inl(devpriv->s5933_config + AMCC_OP_REG_MBEF));
 #endif
 
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 9d0b875..11ce3fd 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -87,7 +87,6 @@ TODO:
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 
-#include "comedi_pci.h"
 #include "8253.h"
 #include "8255.h"
 #include "plx9080.h"
@@ -1153,7 +1152,7 @@ static int eeprom_read_insn(struct comedi_device *dev,
 static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd);
 static unsigned int get_divisor(unsigned int ns, unsigned int flags);
 static void i2c_write(struct comedi_device *dev, unsigned int address,
-		      const uint8_t * data, unsigned int length);
+		      const uint8_t *data, unsigned int length);
 static void caldac_write(struct comedi_device *dev, unsigned int channel,
 			 unsigned int value);
 static int caldac_8800_write(struct comedi_device *dev, unsigned int address,
@@ -1230,7 +1229,7 @@ static unsigned int hw_revision(const struct comedi_device *dev,
 }
 
 static void set_dac_range_bits(struct comedi_device *dev,
-			       volatile uint16_t * bits, unsigned int channel,
+			       volatile uint16_t *bits, unsigned int channel,
 			       unsigned int range)
 {
 	unsigned int code = board(dev)->ao_range_code[range];
@@ -1345,9 +1344,11 @@ static int setup_subdevices(struct comedi_device *dev)
 	struct comedi_subdevice *s;
 	void __iomem *dio_8255_iobase;
 	int i;
+	int ret;
 
-	if (alloc_subdevices(dev, 10) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 10);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* analog input subdevice */
@@ -1700,11 +1701,12 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		return -EIO;
 	}
 
-	dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n", board(dev)->name,
-		pcidev->bus->number, PCI_SLOT(pcidev->devfn));
+	dev_dbg(dev->class_dev, "Found %s on bus %i, slot %i\n",
+		board(dev)->name, pcidev->bus->number, PCI_SLOT(pcidev->devfn));
 
 	if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
-		dev_warn(dev->hw_dev, "failed to enable PCI device and request regions\n");
+		dev_warn(dev->class_dev,
+			 "failed to enable PCI device and request regions\n");
 		return -EIO;
 	}
 	pci_set_master(pcidev);
@@ -1732,7 +1734,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	if (!priv(dev)->plx9080_iobase || !priv(dev)->main_iobase
 	    || !priv(dev)->dio_counter_iobase) {
-		dev_warn(dev->hw_dev, "failed to remap io memory\n");
+		dev_warn(dev->class_dev, "failed to remap io memory\n");
 		return -ENOMEM;
 	}
 
@@ -1768,19 +1770,19 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	priv(dev)->hw_revision =
 	    hw_revision(dev, readw(priv(dev)->main_iobase + HW_STATUS_REG));
-	dev_dbg(dev->hw_dev, "stc hardware revision %i\n",
+	dev_dbg(dev->class_dev, "stc hardware revision %i\n",
 		priv(dev)->hw_revision);
 	init_plx9080(dev);
 	init_stc_registers(dev);
 	/*  get irq */
 	if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
 			"cb_pcidas64", dev)) {
-		dev_dbg(dev->hw_dev, "unable to allocate irq %u\n",
+		dev_dbg(dev->class_dev, "unable to allocate irq %u\n",
 			pcidev->irq);
 		return -EINVAL;
 	}
 	dev->irq = pcidev->irq;
-	dev_dbg(dev->hw_dev, "irq %u\n", dev->irq);
+	dev_dbg(dev->class_dev, "irq %u\n", dev->irq);
 
 	retval = setup_subdevices(dev);
 	if (retval < 0)
@@ -2001,7 +2003,7 @@ static int ai_config_calibration_source(struct comedi_device *dev,
 	else
 		num_calibration_sources = 8;
 	if (source >= num_calibration_sources) {
-		dev_dbg(dev->hw_dev, "invalid calibration source: %i\n",
+		dev_dbg(dev->class_dev, "invalid calibration source: %i\n",
 			source);
 		return -EINVAL;
 	}
@@ -2833,7 +2835,8 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev)
 		}
 
 		if (num_samples < 0) {
-			dev_err(dev->hw_dev, "cb_pcidas64: bug! num_samples < 0\n");
+			dev_err(dev->class_dev,
+				"cb_pcidas64: bug! num_samples < 0\n");
 			break;
 		}
 
@@ -3614,7 +3617,7 @@ static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
 	data[1] = bits;
 	data[0] = 0;
 
-	return 2;
+	return insn->n;
 }
 
 static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -3630,7 +3633,7 @@ static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 static int dio_60xx_config_insn(struct comedi_device *dev,
@@ -3673,7 +3676,7 @@ static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	data[1] = readb(priv(dev)->dio_counter_iobase + DIO_DATA_60XX_REG);
 
-	return 2;
+	return insn->n;
 }
 
 static void caldac_write(struct comedi_device *dev, unsigned int channel,
@@ -4191,7 +4194,7 @@ static void i2c_stop(struct comedi_device *dev)
 }
 
 static void i2c_write(struct comedi_device *dev, unsigned int address,
-		      const uint8_t * data, unsigned int length)
+		      const uint8_t *data, unsigned int length)
 {
 	unsigned int i;
 	uint8_t bitstream;
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index 25ebca1..f5a7957 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -48,10 +48,8 @@ Please report success/failure with other different cards to
 
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
 #include "8255.h"
 
-
 /* PCI vendor number of ComputerBoards */
 #define PCI_VENDOR_ID_CB        0x1307
 #define EEPROM_SIZE	128	/*  number of entries in eeprom */
@@ -267,7 +265,7 @@ static int cb_pcidda_attach(struct comedi_device *dev,
 	struct comedi_subdevice *s;
 	struct pci_dev *pcidev = NULL;
 	int index;
-
+	int ret;
 
 /*
  * Allocate the private structure area.
@@ -296,21 +294,23 @@ static int cb_pcidda_attach(struct comedi_device *dev,
 		}
 	}
 	if (!pcidev) {
-		dev_err(dev->hw_dev, "Not a ComputerBoards/MeasurementComputing card on requested position\n");
+		dev_err(dev->class_dev,
+			"Not a ComputerBoards/MeasurementComputing card on requested position\n");
 		return -EIO;
 	}
 found:
 	devpriv->pci_dev = pcidev;
 	dev->board_ptr = cb_pcidda_boards + index;
 	/*  "thisboard" macro can be used from here. */
-	dev_dbg(dev->hw_dev, "Found %s at requested position\n",
+	dev_dbg(dev->class_dev, "Found %s at requested position\n",
 		thisboard->name);
 
 	/*
 	 * Enable PCI device and request regions.
 	 */
 	if (comedi_pci_enable(pcidev, thisboard->name)) {
-		dev_err(dev->hw_dev, "cb_pcidda: failed to enable PCI device and request regions\n");
+		dev_err(dev->class_dev,
+			"cb_pcidda: failed to enable PCI device and request regions\n");
 		return -EIO;
 	}
 
@@ -335,11 +335,9 @@ found:
  */
 	dev->board_name = thisboard->name;
 
-/*
- * Allocate the subdevice structures.
- */
-	if (alloc_subdevices(dev, 3) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* analog output subdevice */
@@ -360,10 +358,10 @@ found:
 	s = dev->subdevices + 2;
 	subdev_8255_init(dev, s, NULL, devpriv->digitalio + PORT2A);
 
-	dev_dbg(dev->hw_dev, "eeprom:\n");
+	dev_dbg(dev->class_dev, "eeprom:\n");
 	for (index = 0; index < EEPROM_SIZE; index++) {
 		devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index);
-		dev_dbg(dev->hw_dev, "%i:0x%x\n", index,
+		dev_dbg(dev->class_dev, "%i:0x%x\n", index,
 			devpriv->eeprom_data[index]);
 	}
 
diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c
index 713132c..9160859 100644
--- a/drivers/staging/comedi/drivers/cb_pcidio.c
+++ b/drivers/staging/comedi/drivers/cb_pcidio.c
@@ -41,7 +41,6 @@ Passing a zero for an option is the same as leaving it unspecified.
 
 /*------------------------------ HEADER FILES ---------------------------------*/
 #include "../comedidev.h"
-#include "comedi_pci.h"
 #include "8255.h"
 
 /*-------------------------- MACROS and DATATYPES -----------------------------*/
@@ -117,6 +116,7 @@ static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	struct pci_dev *pcidev = NULL;
 	int index;
 	int i;
+	int ret;
 
 /*
  * Allocate the private structure area.  alloc_private() is a
@@ -155,7 +155,8 @@ static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		}
 	}
 
-	dev_err(dev->hw_dev, "No supported ComputerBoards/MeasurementComputing card found on requested position\n");
+	dev_err(dev->class_dev,
+		"No supported ComputerBoards/MeasurementComputing card found on requested position\n");
 	return -EIO;
 
 found:
@@ -167,8 +168,8 @@ found:
 	dev->board_name = thisboard->name;
 
 	devpriv->pci_dev = pcidev;
-	dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n", thisboard->name,
-		devpriv->pci_dev->bus->number,
+	dev_dbg(dev->class_dev, "Found %s on bus %i, slot %i\n",
+		thisboard->name, devpriv->pci_dev->bus->number,
 		PCI_SLOT(devpriv->pci_dev->devfn));
 	if (comedi_pci_enable(pcidev, thisboard->name))
 		return -EIO;
@@ -178,17 +179,14 @@ found:
 	    pci_resource_start(devpriv->pci_dev,
 			       pcidio_boards[index].dioregs_badrindex);
 
-/*
- * Allocate the subdevice structures.  alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_subdevices(dev, thisboard->n_8255) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, thisboard->n_8255);
+	if (ret)
+		return ret;
 
 	for (i = 0; i < thisboard->n_8255; i++) {
 		subdev_8255_init(dev, dev->subdevices + i,
 				 NULL, devpriv->dio_reg_base + i * 4);
-		dev_dbg(dev->hw_dev, "subdev %d: base = 0x%lx\n", i,
+		dev_dbg(dev->class_dev, "subdev %d: base = 0x%lx\n", i,
 			devpriv->dio_reg_base + i * 4);
 	}
 
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index 5f834d0..2977f2d 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -45,7 +45,6 @@ See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details.
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 
-#include "comedi_pci.h"
 #include "plx9052.h"
 #include "8255.h"
 
@@ -188,6 +187,7 @@ static int cb_pcimdas_attach(struct comedi_device *dev,
 	struct comedi_subdevice *s;
 	struct pci_dev *pcidev = NULL;
 	int index;
+	int ret;
 	/* int i; */
 
 /*
@@ -223,12 +223,13 @@ static int cb_pcimdas_attach(struct comedi_device *dev,
 		}
 	}
 
-	dev_err(dev->hw_dev, "No supported ComputerBoards/MeasurementComputing card found on requested position\n");
+	dev_err(dev->class_dev,
+		"No supported ComputerBoards/MeasurementComputing card found on requested position\n");
 	return -EIO;
 
 found:
 
-	dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n",
+	dev_dbg(dev->class_dev, "Found %s on bus %i, slot %i\n",
 		cb_pcimdas_boards[index].name, pcidev->bus->number,
 		PCI_SLOT(pcidev->devfn));
 
@@ -237,12 +238,14 @@ found:
 	case 0x56:
 		break;
 	default:
-		dev_dbg(dev->hw_dev, "THIS CARD IS UNSUPPORTED.\n"
+		dev_dbg(dev->class_dev, "THIS CARD IS UNSUPPORTED.\n");
+		dev_dbg(dev->class_dev,
 			"PLEASE REPORT USAGE TO <mocelet@sucs.org>\n");
 	}
 
 	if (comedi_pci_enable(pcidev, "cb_pcimdas")) {
-		dev_err(dev->hw_dev, "Failed to enable PCI device and request regions\n");
+		dev_err(dev->class_dev,
+			"Failed to enable PCI device and request regions\n");
 		return -EIO;
 	}
 
@@ -252,11 +255,11 @@ found:
 	devpriv->BADR3 = pci_resource_start(devpriv->pci_dev, 3);
 	devpriv->BADR4 = pci_resource_start(devpriv->pci_dev, 4);
 
-	dev_dbg(dev->hw_dev, "devpriv->BADR0 = 0x%lx\n", devpriv->BADR0);
-	dev_dbg(dev->hw_dev, "devpriv->BADR1 = 0x%lx\n", devpriv->BADR1);
-	dev_dbg(dev->hw_dev, "devpriv->BADR2 = 0x%lx\n", devpriv->BADR2);
-	dev_dbg(dev->hw_dev, "devpriv->BADR3 = 0x%lx\n", devpriv->BADR3);
-	dev_dbg(dev->hw_dev, "devpriv->BADR4 = 0x%lx\n", devpriv->BADR4);
+	dev_dbg(dev->class_dev, "devpriv->BADR0 = 0x%lx\n", devpriv->BADR0);
+	dev_dbg(dev->class_dev, "devpriv->BADR1 = 0x%lx\n", devpriv->BADR1);
+	dev_dbg(dev->class_dev, "devpriv->BADR2 = 0x%lx\n", devpriv->BADR2);
+	dev_dbg(dev->class_dev, "devpriv->BADR3 = 0x%lx\n", devpriv->BADR3);
+	dev_dbg(dev->class_dev, "devpriv->BADR4 = 0x%lx\n", devpriv->BADR4);
 
 /* Dont support IRQ yet */
 /*  get irq */
@@ -270,12 +273,9 @@ found:
 	/* Initialize dev->board_name */
 	dev->board_name = thisboard->name;
 
-/*
- * Allocate the subdevice structures.  alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_subdevices(dev, 3) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* dev->read_subdev=s; */
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index b339685..a801461 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -86,8 +86,6 @@ Configuration Options:
 
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
-
 #include "8255.h"
 
 /* device ids of the cards we support -- currently only 1 card supported */
@@ -238,12 +236,9 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
  */
 	dev->board_name = thisboard->name;
 
-/*
- * Allocate the subdevice structures.  alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_subdevices(dev, 2) < 0)
-		return -ENOMEM;
+	err = comedi_alloc_subdevices(dev, 2);
+	if (err)
+		return err;
 
 	s = dev->subdevices + 0;
 
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index 29412de..5ed324c 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -133,8 +133,6 @@ static int bonding_dio_insn_bits(struct comedi_device *dev,
 {
 #define LSAMPL_BITS (sizeof(unsigned int)*8)
 	unsigned nchans = LSAMPL_BITS, num_done = 0, i;
-	if (insn->n != 2)
-		return -EINVAL;
 
 	if (devpriv->nchans < nchans)
 		nchans = devpriv->nchans;
@@ -336,6 +334,7 @@ static int bonding_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
 	struct comedi_subdevice *s;
+	int ret;
 
 	LOG_MSG("comedi%d\n", dev->minor);
 
@@ -358,12 +357,9 @@ static int bonding_attach(struct comedi_device *dev,
 	 */
 	dev->board_name = devpriv->name;
 
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.
-	 */
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	s->type = COMEDI_SUBD_DIO;
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index bff5dcd..9a63cac 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -110,7 +110,7 @@ static int parport_insn_a(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	data[1] = inb(dev->iobase + PARPORT_A);
 
-	return 2;
+	return insn->n;
 }
 
 static int parport_insn_config_a(struct comedi_device *dev,
@@ -139,7 +139,7 @@ static int parport_insn_b(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	data[1] = (inb(dev->iobase + PARPORT_B) >> 3);
 
-	return 2;
+	return insn->n;
 }
 
 static int parport_insn_c(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -155,18 +155,15 @@ static int parport_insn_c(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	data[1] = devpriv->c_data & 0xf;
 
-	return 2;
+	return insn->n;
 }
 
 static int parport_intr_insn(struct comedi_device *dev,
 			     struct comedi_subdevice *s,
 			     struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n < 1)
-		return -EINVAL;
-
 	data[1] = 0;
-	return 2;
+	return insn->n;
 }
 
 static int parport_intr_cmdtest(struct comedi_device *dev,
@@ -315,9 +312,10 @@ static int parport_attach(struct comedi_device *dev,
 	}
 	dev->board_name = "parport";
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		return ret;
+
 	ret = alloc_private(dev, sizeof(struct parport_private));
 	if (ret < 0)
 		return ret;
diff --git a/drivers/staging/comedi/drivers/comedi_pci.h b/drivers/staging/comedi/drivers/comedi_pci.h
deleted file mode 100644
index c14a036..0000000
--- a/drivers/staging/comedi/drivers/comedi_pci.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-    comedi/drivers/comedi_pci.h
-    Various PCI functions for drivers.
-
-    Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
-
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 2000 David A. Schleef <ds@schleef.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.
-
-*/
-
-#ifndef _COMEDI_PCI_H_
-#define _COMEDI_PCI_H_
-
-#include <linux/pci.h>
-
-/*
- * Enable the PCI device and request the regions.
- */
-static inline int comedi_pci_enable(struct pci_dev *pdev, const char *res_name)
-{
-	int rc;
-
-	rc = pci_enable_device(pdev);
-	if (rc < 0)
-		return rc;
-
-	rc = pci_request_regions(pdev, res_name);
-	if (rc < 0)
-		pci_disable_device(pdev);
-
-	return rc;
-}
-
-/*
- * Release the regions and disable the PCI device.
- *
- * This must be matched with a previous successful call to comedi_pci_enable().
- */
-static inline void comedi_pci_disable(struct pci_dev *pdev)
-{
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-}
-
-#endif
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index 873e374..523a809 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -67,8 +67,6 @@ struct waveform_board {
 
 #define N_CHANS 8
 
-#define thisboard ((const struct waveform_board *)dev->board_ptr)
-
 /* Data unique to this driver */
 struct waveform_private {
 	struct timer_list timer;
@@ -429,12 +427,14 @@ static int waveform_ao_insn_write(struct comedi_device *dev,
 static int waveform_attach(struct comedi_device *dev,
 			   struct comedi_devconfig *it)
 {
+	const struct waveform_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	int amplitude = it->options[0];
 	int period = it->options[1];
 	int i;
+	int ret;
 
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 	if (alloc_private(dev, sizeof(struct waveform_private)) < 0)
 		return -ENOMEM;
@@ -448,17 +448,17 @@ static int waveform_attach(struct comedi_device *dev,
 	devpriv->uvolt_amplitude = amplitude;
 	devpriv->usec_period = period;
 
-	dev->n_subdevices = 2;
-	if (alloc_subdevices(dev, dev->n_subdevices) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 2);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	dev->read_subdev = s;
 	/* analog input subdevice */
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
-	s->n_chan = thisboard->ai_chans;
-	s->maxdata = (1 << thisboard->ai_bits) - 1;
+	s->n_chan = board->ai_chans;
+	s->maxdata = (1 << board->ai_bits) - 1;
 	s->range_table = &waveform_ai_ranges;
 	s->len_chanlist = s->n_chan * 2;
 	s->insn_read = waveform_ai_insn_read;
@@ -471,8 +471,8 @@ static int waveform_attach(struct comedi_device *dev,
 	/* analog output subdevice (loopback) */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
-	s->n_chan = thisboard->ai_chans;
-	s->maxdata = (1 << thisboard->ai_bits) - 1;
+	s->n_chan = board->ai_chans;
+	s->maxdata = (1 << board->ai_bits) - 1;
 	s->range_table = &waveform_ai_ranges;
 	s->len_chanlist = s->n_chan * 2;
 	s->insn_write = waveform_ao_insn_write;
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index b8bac80..ee769e0 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -36,8 +36,6 @@ Configuration Options:
 
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
-
 enum contec_model {
 	PIO1616L = 0,
 };
@@ -73,20 +71,17 @@ static int contec_do_insn_bits(struct comedi_device *dev,
 			       struct comedi_insn *insn, unsigned int *data)
 {
 
-	dev_dbg(dev->hw_dev, "contec_do_insn_bits called\n");
-	dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
-
-	if (insn->n != 2)
-		return -EINVAL;
+	dev_dbg(dev->class_dev, "contec_do_insn_bits called\n");
+	dev_dbg(dev->class_dev, "data: %d %d\n", data[0], data[1]);
 
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= data[0] & data[1];
-		dev_dbg(dev->hw_dev, "out: %d on %lx\n", s->state,
+		dev_dbg(dev->class_dev, "out: %d on %lx\n", s->state,
 			dev->iobase + thisboard->out_offs);
 		outw(s->state, dev->iobase + thisboard->out_offs);
 	}
-	return 2;
+	return insn->n;
 }
 
 static int contec_di_insn_bits(struct comedi_device *dev,
@@ -94,21 +89,19 @@ static int contec_di_insn_bits(struct comedi_device *dev,
 			       struct comedi_insn *insn, unsigned int *data)
 {
 
-	dev_dbg(dev->hw_dev, "contec_di_insn_bits called\n");
-	dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
-
-	if (insn->n != 2)
-		return -EINVAL;
+	dev_dbg(dev->class_dev, "contec_di_insn_bits called\n");
+	dev_dbg(dev->class_dev, "data: %d %d\n", data[0], data[1]);
 
 	data[1] = inw(dev->iobase + thisboard->in_offs);
 
-	return 2;
+	return insn->n;
 }
 
 static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct pci_dev *pcidev = NULL;
 	struct comedi_subdevice *s;
+	int ret;
 
 	printk("comedi%d: contec: ", dev->minor);
 
@@ -117,8 +110,9 @@ static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	if (alloc_private(dev, sizeof(struct contec_private)) < 0)
 		return -ENOMEM;
 
-	if (alloc_subdevices(dev, 2) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 2);
+	if (ret)
+		return ret;
 
 	for_each_pci_dev(pcidev) {
 		if (pcidev->vendor == PCI_VENDOR_ID_CONTEC &&
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index 696b58c..8455cb9 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -118,7 +118,6 @@ Configuration options:
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 
-#include "comedi_pci.h"
 #include "8255.h"
 
 #define DAQBOARD2000_SUBSYSTEM_IDS2 	0x00021616	/* Daqboard/2000 - 2 Dacs */
@@ -486,7 +485,7 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev,
 
 static void daqboard2000_resetLocalBus(struct comedi_device *dev)
 {
-	dev_dbg(dev->hw_dev, "daqboard2000_resetLocalBus\n");
+	dev_dbg(dev->class_dev, "daqboard2000_resetLocalBus\n");
 	writel(DAQBOARD2000_SECRLocalBusHi, devpriv->plx + 0x6c);
 	udelay(10000);
 	writel(DAQBOARD2000_SECRLocalBusLo, devpriv->plx + 0x6c);
@@ -495,7 +494,7 @@ static void daqboard2000_resetLocalBus(struct comedi_device *dev)
 
 static void daqboard2000_reloadPLX(struct comedi_device *dev)
 {
-	dev_dbg(dev->hw_dev, "daqboard2000_reloadPLX\n");
+	dev_dbg(dev->class_dev, "daqboard2000_reloadPLX\n");
 	writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c);
 	udelay(10000);
 	writel(DAQBOARD2000_SECRReloadHi, devpriv->plx + 0x6c);
@@ -506,7 +505,7 @@ static void daqboard2000_reloadPLX(struct comedi_device *dev)
 
 static void daqboard2000_pulseProgPin(struct comedi_device *dev)
 {
-	dev_dbg(dev->hw_dev, "daqboard2000_pulseProgPin 1\n");
+	dev_dbg(dev->class_dev, "daqboard2000_pulseProgPin 1\n");
 	writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c);
 	udelay(10000);
 	writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c);
@@ -558,14 +557,14 @@ static int initialize_daqboard2000(struct comedi_device *dev,
 	secr = readl(devpriv->plx + 0x6c);
 	if (!(secr & DAQBOARD2000_EEPROM_PRESENT)) {
 #ifdef DEBUG_EEPROM
-		dev_dbg(dev->hw_dev, "no serial eeprom\n");
+		dev_dbg(dev->class_dev, "no serial eeprom\n");
 #endif
 		return -EIO;
 	}
 
 	for (retry = 0; retry < 3; retry++) {
 #ifdef DEBUG_EEPROM
-		dev_dbg(dev->hw_dev, "Programming EEPROM try %x\n", retry);
+		dev_dbg(dev->class_dev, "Programming EEPROM try %x\n", retry);
 #endif
 
 		daqboard2000_resetLocalBus(dev);
@@ -576,8 +575,8 @@ static int initialize_daqboard2000(struct comedi_device *dev,
 				if (cpld_array[i] == 0xff
 				    && cpld_array[i + 1] == 0x20) {
 #ifdef DEBUG_EEPROM
-					dev_dbg(dev->hw_dev, "Preamble found at %d\n",
-						i);
+					dev_dbg(dev->class_dev,
+						"Preamble found at %d\n", i);
 #endif
 					break;
 				}
@@ -590,7 +589,7 @@ static int initialize_daqboard2000(struct comedi_device *dev,
 			}
 			if (i >= len) {
 #ifdef DEBUG_EEPROM
-				dev_dbg(dev->hw_dev, "Programmed\n");
+				dev_dbg(dev->class_dev, "Programmed\n");
 #endif
 				daqboard2000_resetLocalBus(dev);
 				daqboard2000_reloadPLX(dev);
@@ -734,10 +733,11 @@ static int daqboard2000_attach(struct comedi_device *dev,
 	}
 	if (!card) {
 		if (bus || slot)
-			dev_err(dev->hw_dev, "no daqboard2000 found at bus/slot: %d/%d\n",
+			dev_err(dev->class_dev,
+				"no daqboard2000 found at bus/slot: %d/%d\n",
 				bus, slot);
 		else
-			dev_err(dev->hw_dev, "no daqboard2000 found\n");
+			dev_err(dev->class_dev, "no daqboard2000 found\n");
 		return -EIO;
 	} else {
 		u32 id;
@@ -747,7 +747,7 @@ static int daqboard2000_attach(struct comedi_device *dev,
 		      subsystem_device << 16) | card->subsystem_vendor;
 		for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
 			if (boardtypes[i].id == id) {
-				dev_dbg(dev->hw_dev, "%s\n",
+				dev_dbg(dev->class_dev, "%s\n",
 					boardtypes[i].name);
 				dev->board_ptr = boardtypes + i;
 			}
@@ -762,7 +762,8 @@ static int daqboard2000_attach(struct comedi_device *dev,
 
 	result = comedi_pci_enable(card, "daqboard2000");
 	if (result < 0) {
-		dev_err(dev->hw_dev, "failed to enable PCI device and request regions\n");
+		dev_err(dev->class_dev,
+			"failed to enable PCI device and request regions\n");
 		return -EIO;
 	}
 	devpriv->got_regions = 1;
@@ -773,9 +774,9 @@ static int daqboard2000_attach(struct comedi_device *dev,
 	if (!devpriv->plx || !devpriv->daq)
 		return -ENOMEM;
 
-	result = alloc_subdevices(dev, 3);
-	if (result < 0)
-		goto out;
+	result = comedi_alloc_subdevices(dev, 3);
+	if (result)
+		return result;
 
 	readl(devpriv->plx + 0x6c);
 
@@ -792,7 +793,8 @@ static int daqboard2000_attach(struct comedi_device *dev,
 	if (aux_data && aux_len) {
 		result = initialize_daqboard2000(dev, aux_data, aux_len);
 	} else {
-		dev_dbg(dev->hw_dev, "no FPGA initialization code, aborting\n");
+		dev_dbg(dev->class_dev,
+			"no FPGA initialization code, aborting\n");
 		result = -EIO;
 	}
 	if (result < 0)
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index 1f31943..d0128e0 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -32,7 +32,7 @@
  *   [ComputerBoards] DAS08 (isa-das08), DAS08-PGM (das08-pgm),
  *   DAS08-PGH (das08-pgh), DAS08-PGL (das08-pgl), DAS08-AOH (das08-aoh),
  *   DAS08-AOL (das08-aol), DAS08-AOM (das08-aom), DAS08/JR-AO (das08/jr-ao),
- *   DAS08/JR-16-AO (das08jr-16-ao), PCI-DAS08 (das08),
+ *   DAS08/JR-16-AO (das08jr-16-ao), PCI-DAS08 (pci-das08 or das08),
  *   PC104-DAS08 (pc104-das08), DAS08/JR/16 (das08jr/16)
  * Status: works
  *
@@ -55,25 +55,14 @@
 
 #include <linux/delay.h>
 
-#include "comedi_pci.h"
 #include "8255.h"
 #include "das08.h"
 
 #define DRV_NAME "das08"
 
-#ifdef CONFIG_COMEDI_DAS08_ISA_MODULE
-#define CONFIG_COMEDI_DAS08_ISA
-#endif
-#ifdef CONFIG_COMEDI_DAS08_PCI_MODULE
-#define CONFIG_COMEDI_DAS08_PCI
-#endif
-#ifdef CONFIG_COMEDI_DAS08_CS_MODULE
-#define CONFIG_COMEDI_DAS08_CS
-#endif
-
-#if defined(CONFIG_COMEDI_DAS08_ISA) || defined(CONFIG_COMEDI_DAS08_PCI)
-#define DO_COMEDI_DRIVER_REGISTER
-#endif
+#define DO_COMEDI_DRIVER_REGISTER \
+	(IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) || \
+	 IS_ENABLED(CONFIG_COMEDI_DAS08_PCI))
 
 #define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307
 #define PCI_DEVICE_ID_PCIDAS08 0x29
@@ -168,29 +157,6 @@
 
 /* gainlist same as _pgx_ below */
 
-static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data);
-static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data);
-static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data);
-#ifdef CONFIG_COMEDI_DAS08_ISA
-static int das08jr_di_rbits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int das08jr_do_wbits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int das08jr_ao_winsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int das08ao_ao_winsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-#endif
-static void i8254_set_mode_low(unsigned int base, int channel,
-			       unsigned int mode);
-
 static const struct comedi_lrange range_das08_pgl = { 9, {
 							  BIP_RANGE(10),
 							  BIP_RANGE(5),
@@ -269,278 +235,13 @@ static const int *const das08_gainlists[] = {
 	das08_pgm_gainlist,
 };
 
-#ifdef DO_COMEDI_DRIVER_REGISTER
-static const struct das08_board_struct das08_boards[] = {
-#ifdef CONFIG_COMEDI_DAS08_ISA
-	{
-	 .name = "isa-das08",	/*  cio-das08.pdf */
-	 .bustype = isa,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_pg_none,
-	 .ai_encoding = das08_encode12,
-	 .ao = NULL,
-	 .ao_nbits = 12,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 4,
-	 .i8255_offset = 8,
-	 .i8254_offset = 4,
-	 .iosize = 16,		/*  unchecked */
-	 },
-	{
-	 .name = "das08-pgm",	/*  cio-das08pgx.pdf */
-	 .bustype = isa,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_pgm,
-	 .ai_encoding = das08_encode12,
-	 .ao = NULL,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 4,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x04,
-	 .iosize = 16,		/*  unchecked */
-	 },
-	{
-	 .name = "das08-pgh",	/*  cio-das08pgx.pdf */
-	 .bustype = isa,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_pgh,
-	 .ai_encoding = das08_encode12,
-	 .ao = NULL,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 4,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x04,
-	 .iosize = 16,		/*  unchecked */
-	 },
-	{
-	 .name = "das08-pgl",	/*  cio-das08pgx.pdf */
-	 .bustype = isa,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_pgl,
-	 .ai_encoding = das08_encode12,
-	 .ao = NULL,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 4,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x04,
-	 .iosize = 16,		/*  unchecked */
-	 },
-	{
-	 .name = "das08-aoh",	/*  cio-das08_aox.pdf */
-	 .bustype = isa,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_pgh,
-	 .ai_encoding = das08_encode12,
-	 .ao = das08ao_ao_winsn,	/*  8 */
-	 .ao_nbits = 12,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 4,
-	 .i8255_offset = 0x0c,
-	 .i8254_offset = 0x04,
-	 .iosize = 16,		/*  unchecked */
-	 },
-	{
-	 .name = "das08-aol",	/*  cio-das08_aox.pdf */
-	 .bustype = isa,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_pgl,
-	 .ai_encoding = das08_encode12,
-	 .ao = das08ao_ao_winsn,	/*  8 */
-	 .ao_nbits = 12,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 4,
-	 .i8255_offset = 0x0c,
-	 .i8254_offset = 0x04,
-	 .iosize = 16,		/*  unchecked */
-	 },
-	{
-	 .name = "das08-aom",	/*  cio-das08_aox.pdf */
-	 .bustype = isa,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_pgm,
-	 .ai_encoding = das08_encode12,
-	 .ao = das08ao_ao_winsn,	/*  8 */
-	 .ao_nbits = 12,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 4,
-	 .i8255_offset = 0x0c,
-	 .i8254_offset = 0x04,
-	 .iosize = 16,		/*  unchecked */
-	 },
-	{
-	 .name = "das08/jr-ao",	/*  cio-das08-jr-ao.pdf */
-	 .bustype = isa,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_pg_none,
-	 .ai_encoding = das08_encode12,
-	 .ao = das08jr_ao_winsn,
-	 .ao_nbits = 12,
-	 .di = das08jr_di_rbits,
-	 .do_ = das08jr_do_wbits,
-	 .do_nchan = 8,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0,
-	 .iosize = 16,		/*  unchecked */
-	 },
-	{
-	 .name = "das08jr-16-ao",	/*  cio-das08jr-16-ao.pdf */
-	 .bustype = isa,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 16,
-	 .ai_pg = das08_pg_none,
-	 .ai_encoding = das08_encode12,
-	 .ao = das08jr_ao_winsn,
-	 .ao_nbits = 16,
-	 .di = das08jr_di_rbits,
-	 .do_ = das08jr_do_wbits,
-	 .do_nchan = 8,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0x04,
-	 .iosize = 16,		/*  unchecked */
-	 },
-	{
-	 .name = "pc104-das08",
-	 .bustype = pc104,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_pg_none,
-	 .ai_encoding = das08_encode12,
-	 .ao = NULL,
-	 .ao_nbits = 0,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 4,
-	 .i8255_offset = 0,
-	 .i8254_offset = 4,
-	 .iosize = 16,		/*  unchecked */
-	 },
-#if 0
-	{
-	 .name = "das08/f",
-	 },
-	{
-	 .name = "das08jr",
-	 },
-#endif
-	{
-	 .name = "das08jr/16",
-	 .bustype = isa,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 16,
-	 .ai_pg = das08_pg_none,
-	 .ai_encoding = das08_encode16,
-	 .ao = NULL,
-	 .ao_nbits = 0,
-	 .di = das08jr_di_rbits,
-	 .do_ = das08jr_do_wbits,
-	 .do_nchan = 8,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0,
-	 .iosize = 16,		/*  unchecked */
-	 },
-#if 0
-	{
-	 .name = "das48-pga",	/*  cio-das48-pga.pdf */
-	 },
-	{
-	 .name = "das08-pga-g2",	/*  a KM board */
-	 },
-#endif
-#endif /* CONFIG_COMEDI_DAS08_ISA */
-#ifdef CONFIG_COMEDI_DAS08_PCI
-	{
-	 .name = "das08",	/*  pci-das08 */
-	 .id = PCI_DEVICE_ID_PCIDAS08,
-	 .bustype = pci,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_bipolar5,
-	 .ai_encoding = das08_encode12,
-	 .ao = NULL,
-	 .ao_nbits = 0,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 4,
-	 .i8255_offset = 0,
-	 .i8254_offset = 4,
-	 .iosize = 8,
-	 },
-#endif /* CONFIG_COMEDI_DAS08_PCI */
-};
-#endif /* DO_COMEDI_DRIVER_REGISTER */
-
-#ifdef CONFIG_COMEDI_DAS08_CS
-struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = {
-	{
-	 .name = "pcm-das08",
-	 .id = 0x0,		/*  XXX */
-	 .bustype = pcmcia,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_bipolar5,
-	 .ai_encoding = das08_pcm_encode12,
-	 .ao = NULL,
-	 .ao_nbits = 0,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 3,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0,
-	 .iosize = 16,
-	 },
-	/*  duplicate so driver name can be used also */
-	{
-	 .name = "das08_cs",
-	 .id = 0x0,		/*  XXX */
-	 .bustype = pcmcia,
-	 .ai = das08_ai_rinsn,
-	 .ai_nbits = 12,
-	 .ai_pg = das08_bipolar5,
-	 .ai_encoding = das08_pcm_encode12,
-	 .ao = NULL,
-	 .ao_nbits = 0,
-	 .di = das08_di_rbits,
-	 .do_ = das08_do_wbits,
-	 .do_nchan = 3,
-	 .i8255_offset = 0,
-	 .i8254_offset = 0,
-	 .iosize = 16,
-	 },
-};
-#endif
-
-#ifdef CONFIG_COMEDI_DAS08_PCI
-static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_DEVICE_ID_PCIDAS08) },
-	{0}
-};
-
-MODULE_DEVICE_TABLE(pci, das08_pci_table);
-#endif
-
-#define devpriv ((struct das08_private_struct *)dev->private)
-#define thisboard ((const struct das08_board_struct *)dev->board_ptr)
-
 #define TIMEOUT 100000
 
 static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
+	const struct das08_board_struct *thisboard = comedi_board(dev);
+	struct das08_private_struct *devpriv = dev->private;
 	int i, n;
 	int chan;
 	int range;
@@ -572,7 +273,7 @@ static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 		/* clear over-range bits for 16-bit boards */
 		if (thisboard->ai_nbits == 16)
 			if (inb(dev->iobase + DAS08_MSB) & 0x80)
-				printk(KERN_INFO "das08: over-range\n");
+				dev_info(dev->class_dev, "over-range\n");
 
 		/* trigger conversion */
 		outb_p(0, dev->iobase + DAS08_TRIG_12BIT);
@@ -582,7 +283,7 @@ static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 				break;
 		}
 		if (i == TIMEOUT) {
-			printk(KERN_ERR "das08: timeout\n");
+			dev_err(dev->class_dev, "timeout\n");
 			return -ETIME;
 		}
 		msb = inb(dev->iobase + DAS08_MSB);
@@ -612,12 +313,13 @@ static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
 	data[0] = 0;
 	data[1] = DAS08_IP(inb(dev->iobase + DAS08_STATUS));
 
-	return 2;
+	return insn->n;
 }
 
 static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
+	struct das08_private_struct *devpriv = dev->private;
 	int wbits;
 
 	/*  get current settings of digital output lines */
@@ -636,26 +338,25 @@ static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	data[1] = wbits;
 
-	return 2;
+	return insn->n;
 }
 
-#ifdef CONFIG_COMEDI_DAS08_ISA
-static int das08jr_di_rbits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data)
+static int __maybe_unused
+das08jr_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
+		 struct comedi_insn *insn, unsigned int *data)
 {
 	data[0] = 0;
 	data[1] = inb(dev->iobase + DAS08JR_DIO);
 
-	return 2;
+	return insn->n;
 }
-#endif
 
-#ifdef CONFIG_COMEDI_DAS08_ISA
-static int das08jr_do_wbits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data)
+static int __maybe_unused
+das08jr_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
+		 struct comedi_insn *insn, unsigned int *data)
 {
+	struct das08_private_struct *devpriv = dev->private;
+
 	/*  null bits we are going to set */
 	devpriv->do_bits &= ~data[0];
 	/*  set new bit values */
@@ -664,14 +365,12 @@ static int das08jr_do_wbits(struct comedi_device *dev,
 
 	data[1] = devpriv->do_bits;
 
-	return 2;
+	return insn->n;
 }
-#endif
 
-#ifdef CONFIG_COMEDI_DAS08_ISA
-static int das08jr_ao_winsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data)
+static int __maybe_unused
+das08jr_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
+		 struct comedi_insn *insn, unsigned int *data)
 {
 	int n;
 	int lsb, msb;
@@ -697,7 +396,6 @@ static int das08jr_ao_winsn(struct comedi_device *dev,
 
 	return n;
 }
-#endif
 
 /*
  *
@@ -705,10 +403,9 @@ static int das08jr_ao_winsn(struct comedi_device *dev,
  * a different method to force an update.
  *
  */
-#ifdef CONFIG_COMEDI_DAS08_ISA
-static int das08ao_ao_winsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data)
+static int __maybe_unused
+das08ao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
+		 struct comedi_insn *insn, unsigned int *data)
 {
 	int n;
 	int lsb, msb;
@@ -734,7 +431,6 @@ static int das08ao_ao_winsn(struct comedi_device *dev,
 
 	return n;
 }
-#endif
 
 static unsigned int i8254_read_channel_low(unsigned int base, int chan)
 {
@@ -787,13 +483,6 @@ static void i8254_write_channel(struct i8254_struct *st, int channel,
 	i8254_write_channel_low(st->iobase, chan, value);
 }
 
-static void i8254_initialize(struct i8254_struct *st)
-{
-	int i;
-	for (i = 0; i < 3; ++i)
-		i8254_set_mode_low(st->iobase, i, st->mode[i]);
-}
-
 static void i8254_set_mode_low(unsigned int base, int channel,
 			       unsigned int mode)
 {
@@ -822,16 +511,20 @@ static unsigned int i8254_read_status(struct i8254_struct *st, int channel)
 	return i8254_read_status_low(st->iobase, chan);
 }
 
+static void i8254_initialize(struct i8254_struct *st)
+{
+	int i;
+	for (i = 0; i < 3; ++i)
+		i8254_set_mode_low(st->iobase, i, st->mode[i]);
+}
+
 static int das08_counter_read(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
+	struct das08_private_struct *devpriv = dev->private;
 	int chan = insn->chanspec;
-
-	/* printk("Reading counter channel %d ",chan); */
 	data[0] = i8254_read_channel(&devpriv->i8254, chan);
-	/* printk("=> 0x%08X\n",data[0]); */
-
 	return 1;
 }
 
@@ -839,11 +532,9 @@ static int das08_counter_write(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
+	struct das08_private_struct *devpriv = dev->private;
 	int chan = insn->chanspec;
-
-	/* printk("Writing counter channel %d with 0x%04X\n",chan,data[0]); */
 	i8254_write_channel(&devpriv->i8254, chan, data[0]);
-
 	return 1;
 }
 
@@ -851,6 +542,7 @@ static int das08_counter_config(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
+	struct das08_private_struct *devpriv = dev->private;
 	int chan = insn->chanspec;
 
 	if (insn->n != 2)
@@ -870,39 +562,280 @@ static int das08_counter_config(struct comedi_device *dev,
 	return 2;
 }
 
-#ifdef DO_COMEDI_DRIVER_REGISTER
-static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it);
+#if DO_COMEDI_DRIVER_REGISTER
+static const struct das08_board_struct das08_boards[] = {
+#if IS_ENABLED(CONFIG_COMEDI_DAS08_ISA)
+	{
+		.name = "isa-das08",	/*  cio-das08.pdf */
+		.bustype = isa,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_pg_none,
+		.ai_encoding = das08_encode12,
+		.ao = NULL,
+		.ao_nbits = 12,
+		.di = das08_di_rbits,
+		.do_ = das08_do_wbits,
+		.do_nchan = 4,
+		.i8255_offset = 8,
+		.i8254_offset = 4,
+		.iosize = 16,		/*  unchecked */
+	},
+	{
+		.name = "das08-pgm",	/*  cio-das08pgx.pdf */
+		.bustype = isa,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_pgm,
+		.ai_encoding = das08_encode12,
+		.ao = NULL,
+		.di = das08_di_rbits,
+		.do_ = das08_do_wbits,
+		.do_nchan = 4,
+		.i8255_offset = 0,
+		.i8254_offset = 0x04,
+		.iosize = 16,		/*  unchecked */
+	},
+	{
+		.name = "das08-pgh",	/*  cio-das08pgx.pdf */
+		.bustype = isa,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_pgh,
+		.ai_encoding = das08_encode12,
+		.ao = NULL,
+		.di = das08_di_rbits,
+		.do_ = das08_do_wbits,
+		.do_nchan = 4,
+		.i8255_offset = 0,
+		.i8254_offset = 0x04,
+		.iosize = 16,		/*  unchecked */
+	},
+	{
+		.name = "das08-pgl",	/*  cio-das08pgx.pdf */
+		.bustype = isa,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_pgl,
+		.ai_encoding = das08_encode12,
+		.ao = NULL,
+		.di = das08_di_rbits,
+		.do_ = das08_do_wbits,
+		.do_nchan = 4,
+		.i8255_offset = 0,
+		.i8254_offset = 0x04,
+		.iosize = 16,		/*  unchecked */
+	},
+	{
+		.name = "das08-aoh",	/*  cio-das08_aox.pdf */
+		.bustype = isa,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_pgh,
+		.ai_encoding = das08_encode12,
+		.ao = das08ao_ao_winsn,	/*  8 */
+		.ao_nbits = 12,
+		.di = das08_di_rbits,
+		.do_ = das08_do_wbits,
+		.do_nchan = 4,
+		.i8255_offset = 0x0c,
+		.i8254_offset = 0x04,
+		.iosize = 16,		/*  unchecked */
+	},
+	{
+		.name = "das08-aol",	/*  cio-das08_aox.pdf */
+		.bustype = isa,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_pgl,
+		.ai_encoding = das08_encode12,
+		.ao = das08ao_ao_winsn,	/*  8 */
+		.ao_nbits = 12,
+		.di = das08_di_rbits,
+		.do_ = das08_do_wbits,
+		.do_nchan = 4,
+		.i8255_offset = 0x0c,
+		.i8254_offset = 0x04,
+		.iosize = 16,		/*  unchecked */
+	},
+	{
+		.name = "das08-aom",	/*  cio-das08_aox.pdf */
+		.bustype = isa,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_pgm,
+		.ai_encoding = das08_encode12,
+		.ao = das08ao_ao_winsn,	/*  8 */
+		.ao_nbits = 12,
+		.di = das08_di_rbits,
+		.do_ = das08_do_wbits,
+		.do_nchan = 4,
+		.i8255_offset = 0x0c,
+		.i8254_offset = 0x04,
+		.iosize = 16,		/*  unchecked */
+	},
+	{
+		.name = "das08/jr-ao",	/*  cio-das08-jr-ao.pdf */
+		.bustype = isa,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_pg_none,
+		.ai_encoding = das08_encode12,
+		.ao = das08jr_ao_winsn,
+		.ao_nbits = 12,
+		.di = das08jr_di_rbits,
+		.do_ = das08jr_do_wbits,
+		.do_nchan = 8,
+		.i8255_offset = 0,
+		.i8254_offset = 0,
+		.iosize = 16,		/*  unchecked */
+	},
+	{
+		.name = "das08jr-16-ao",	/*  cio-das08jr-16-ao.pdf */
+		.bustype = isa,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 16,
+		.ai_pg = das08_pg_none,
+		.ai_encoding = das08_encode12,
+		.ao = das08jr_ao_winsn,
+		.ao_nbits = 16,
+		.di = das08jr_di_rbits,
+		.do_ = das08jr_do_wbits,
+		.do_nchan = 8,
+		.i8255_offset = 0,
+		.i8254_offset = 0x04,
+		.iosize = 16,		/*  unchecked */
+	},
+	{
+		.name = "pc104-das08",
+		.bustype = pc104,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_pg_none,
+		.ai_encoding = das08_encode12,
+		.ao = NULL,
+		.ao_nbits = 0,
+		.di = das08_di_rbits,
+		.do_ = das08_do_wbits,
+		.do_nchan = 4,
+		.i8255_offset = 0,
+		.i8254_offset = 4,
+		.iosize = 16,		/*  unchecked */
+	},
+#if 0
+	{
+		.name = "das08/f",
+	},
+	{
+		.name = "das08jr",
+	},
+#endif
+	{
+		.name = "das08jr/16",
+		.bustype = isa,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 16,
+		.ai_pg = das08_pg_none,
+		.ai_encoding = das08_encode16,
+		.ao = NULL,
+		.ao_nbits = 0,
+		.di = das08jr_di_rbits,
+		.do_ = das08jr_do_wbits,
+		.do_nchan = 8,
+		.i8255_offset = 0,
+		.i8254_offset = 0,
+		.iosize = 16,		/*  unchecked */
+	},
+#if 0
+	{
+		.name = "das48-pga",	/*  cio-das48-pga.pdf */
+	},
+	{
+		.name = "das08-pga-g2",	/*  a KM board */
+	},
+#endif
+#endif /* IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) */
+#if IS_ENABLED(CONFIG_COMEDI_DAS08_PCI)
+	{
+		.name = "pci-das08",	/*  pci-das08 */
+		.id = PCI_DEVICE_ID_PCIDAS08,
+		.bustype = pci,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_bipolar5,
+		.ai_encoding = das08_encode12,
+		.ao = NULL,
+		.ao_nbits = 0,
+		.di = das08_di_rbits,
+		.do_ = das08_do_wbits,
+		.do_nchan = 4,
+		.i8255_offset = 0,
+		.i8254_offset = 4,
+		.iosize = 8,
+	},
+	{ /* wildcard entry matches any supported PCI device */
+		.name = DRV_NAME,
+		.id = PCI_ANY_ID,
+		.bustype = pci,
+	},
+#endif /* IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) */
+};
+#endif /* DO_COMEDI_DRIVER_REGISTER */
 
-static struct comedi_driver driver_das08 = {
-	.driver_name = DRV_NAME,
-	.module = THIS_MODULE,
-	.attach = das08_attach,
-	.detach = das08_common_detach,
-	.board_name = &das08_boards[0].name,
-	.num_names = sizeof(das08_boards) / sizeof(struct das08_board_struct),
-	.offset = sizeof(struct das08_board_struct),
+#if IS_ENABLED(CONFIG_COMEDI_DAS08_CS)
+struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = {
+	{
+		.name = "pcm-das08",
+		.id = 0x0,		/*  XXX */
+		.bustype = pcmcia,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_bipolar5,
+		.ai_encoding = das08_pcm_encode12,
+		.ao = NULL,
+		.ao_nbits = 0,
+		.di = das08_di_rbits,
+		.do_ = das08_do_wbits,
+		.do_nchan = 3,
+		.i8255_offset = 0,
+		.i8254_offset = 0,
+		.iosize = 16,
+	},
+	/*  duplicate so driver name can be used also */
+	{
+		.name = "das08_cs",
+		.id = 0x0,		/*  XXX */
+		.bustype = pcmcia,
+		.ai = das08_ai_rinsn,
+		.ai_nbits = 12,
+		.ai_pg = das08_bipolar5,
+		.ai_encoding = das08_pcm_encode12,
+		.ao = NULL,
+		.ao_nbits = 0,
+		.di = das08_di_rbits,
+		.do_ = das08_do_wbits,
+		.do_nchan = 3,
+		.i8255_offset = 0,
+		.i8254_offset = 0,
+		.iosize = 16,
+	},
 };
+EXPORT_SYMBOL_GPL(das08_cs_boards);
 #endif
 
 int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
 {
+	const struct das08_board_struct *thisboard = comedi_board(dev);
+	struct das08_private_struct *devpriv = dev->private;
 	struct comedi_subdevice *s;
 	int ret;
 
-	/*  allocate ioports for non-pcmcia, non-pci boards */
-	if ((thisboard->bustype != pcmcia) && (thisboard->bustype != pci)) {
-		printk(KERN_INFO " iobase 0x%lx\n", iobase);
-		if (!request_region(iobase, thisboard->iosize, DRV_NAME)) {
-			printk(KERN_ERR " I/O port conflict\n");
-			return -EIO;
-		}
-	}
 	dev->iobase = iobase;
 
 	dev->board_name = thisboard->name;
 
-	ret = alloc_subdevices(dev, 6);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 6);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices + 0;
@@ -1002,155 +935,246 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
 }
 EXPORT_SYMBOL_GPL(das08_common_attach);
 
-#ifdef DO_COMEDI_DRIVER_REGISTER
-static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static int das08_pci_attach_common(struct comedi_device *dev,
+				   struct pci_dev *pdev)
 {
-	int ret;
 	unsigned long iobase;
-#ifdef CONFIG_COMEDI_DAS08_PCI
-	unsigned long pci_iobase = 0;
-	struct pci_dev *pdev = NULL;
+	unsigned long pci_iobase;
+	struct das08_private_struct *devpriv = dev->private;
+
+	if (!IS_ENABLED(CONFIG_COMEDI_DAS08_PCI))
+		return -EINVAL;
+
+	devpriv->pdev = pdev;
+	/*  enable PCI device and reserve I/O spaces */
+	if (comedi_pci_enable(pdev, dev->driver->driver_name)) {
+		dev_err(dev->class_dev,
+			"Error enabling PCI device and requesting regions\n");
+		return -EIO;
+	}
+	/*  read base addresses */
+	pci_iobase = pci_resource_start(pdev, 1);
+	iobase = pci_resource_start(pdev, 2);
+	dev_info(dev->class_dev, "pcibase 0x%lx  iobase 0x%lx\n",
+		 pci_iobase, iobase);
+	devpriv->pci_iobase = pci_iobase;
+#if 0
+	/* We could enable pci-das08's interrupt here to make it possible
+	* to do timed input in this driver, but there is little point since
+	* conversions would have to be started by the interrupt handler
+	* so you might as well use comedi_rt_timer to emulate commands
+	*/
+	/* set source of interrupt trigger to counter2 output */
+	outb(CNTRL_INTR | CNTRL_DIR, pci_iobase + CNTRL);
+	/* Enable local interrupt 1 and pci interrupt */
+	outw(INTR1_ENABLE | PCI_INTR_ENABLE, pci_iobase + INTCSR);
+#endif
+	return das08_common_attach(dev, iobase);
+}
+
+static const struct das08_board_struct *
+das08_find_pci_board(struct pci_dev *pdev)
+{
+#if DO_COMEDI_DRIVER_REGISTER
+	unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(das08_boards); i++)
+		if (das08_boards[i].bustype == pci &&
+		    pdev->device == das08_boards[i].id)
+			return &das08_boards[i];
 #endif
+	return NULL;
+}
+
+/* only called in the PCI probe path, via comedi_pci_auto_config() */
+static int __devinit __maybe_unused
+das08_attach_pci(struct comedi_device *dev, struct pci_dev *pdev)
+{
+	int ret;
 
+	if (!IS_ENABLED(CONFIG_COMEDI_DAS08_PCI))
+		return -EINVAL;
 	ret = alloc_private(dev, sizeof(struct das08_private_struct));
 	if (ret < 0)
 		return ret;
+	dev_info(dev->class_dev, "attach pci %s\n", pci_name(pdev));
+	dev->board_ptr = das08_find_pci_board(pdev);
+	if (dev->board_ptr == NULL) {
+		dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
+		return -EINVAL;
+	}
+	return das08_pci_attach_common(dev, pdev);
+}
 
-	printk(KERN_INFO "comedi%d: das08: ", dev->minor);
-#ifdef CONFIG_COMEDI_DAS08_PCI
-	/*  deal with a pci board */
-	if (thisboard->bustype == pci) {
-		if (it->options[0] || it->options[1]) {
-			printk("bus %i slot %i ",
-			       it->options[0], it->options[1]);
-		}
-		printk("\n");
-		/*  find card */
-		for_each_pci_dev(pdev) {
-			if (pdev->vendor == PCI_VENDOR_ID_COMPUTERBOARDS
-			    && pdev->device == PCI_DEVICE_ID_PCIDAS08) {
-				if (it->options[0] || it->options[1]) {
-					if (pdev->bus->number == it->options[0]
-					    && PCI_SLOT(pdev->devfn) ==
-					    it->options[1]) {
-						break;
-					}
-				} else {
-					break;
-				}
-			}
+static struct pci_dev *das08_find_pci(struct comedi_device *dev,
+				      int bus, int slot)
+{
+	const struct das08_board_struct *thisboard = comedi_board(dev);
+	struct pci_dev *pdev;
+	unsigned int matchid;
+
+	if (bus || slot)
+		dev_dbg(dev->class_dev, "Looking for %s at PCI %02X:%02X\n",
+			thisboard->name, bus, slot);
+	else
+		dev_dbg(dev->class_dev, "Looking for %s on PCI buses\n",
+			thisboard->name);
+
+	matchid = thisboard->id;
+	pdev = NULL;
+	for_each_pci_dev(pdev) {
+		if ((bus || slot) &&
+		    (bus != pdev->bus->number || slot != PCI_SLOT(pdev->devfn)))
+			continue;
+		if (pdev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
+			continue;
+		if (matchid == PCI_ANY_ID) {
+			/* wildcard board matches any supported PCI board */
+			const struct das08_board_struct *foundboard;
+			foundboard = das08_find_pci_board(pdev);
+			if (foundboard == NULL)
+				continue;
+			/* replace wildcard board_ptr */
+			dev->board_ptr = thisboard = foundboard;
+		} else {
+			/* match specific PCI board */
+			if (pdev->device != matchid)
+				continue;
 		}
-		if (!pdev) {
-			printk(KERN_ERR "No pci das08 cards found\n");
+		/* found a match */
+		dev_info(dev->class_dev, "Found %s at PCI %s\n",
+			 thisboard->name, pci_name(pdev));
+		return pdev;
+	}
+	/* no match found */
+	if (bus || slot)
+		dev_err(dev->class_dev,
+			"No %s cards found at PCI %02X:%02X\n",
+			thisboard->name, bus, slot);
+	else
+		dev_err(dev->class_dev, "No %s cards found on PCI buses\n",
+			thisboard->name);
+	return NULL;
+}
+
+static int __maybe_unused
+das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	const struct das08_board_struct *thisboard = comedi_board(dev);
+	struct das08_private_struct *devpriv;
+	int ret;
+	unsigned long iobase;
+
+	ret = alloc_private(dev, sizeof(struct das08_private_struct));
+	if (ret < 0)
+		return ret;
+	devpriv = dev->private;
+
+	dev_info(dev->class_dev, "attach\n");
+	if (IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) && thisboard->bustype == pci) {
+		struct pci_dev *pdev;
+		pdev = das08_find_pci(dev, it->options[0], it->options[1]);
+		if (pdev == NULL)
 			return -EIO;
-		}
-		devpriv->pdev = pdev;
-		/*  enable PCI device and reserve I/O spaces */
-		if (comedi_pci_enable(pdev, DRV_NAME)) {
-			printk(KERN_ERR " Error enabling PCI device and "
-						"requesting regions\n");
+		return das08_pci_attach_common(dev, pdev);
+	} else if (IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) &&
+		   (thisboard->bustype == isa || thisboard->bustype == pc104)) {
+		iobase = it->options[0];
+		dev_info(dev->class_dev, "iobase 0x%lx\n", iobase);
+		if (!request_region(iobase, thisboard->iosize, DRV_NAME)) {
+			dev_err(dev->class_dev, "I/O port conflict\n");
 			return -EIO;
 		}
-		/*  read base addresses */
-		pci_iobase = pci_resource_start(pdev, 1);
-		iobase = pci_resource_start(pdev, 2);
-		printk(KERN_INFO "pcibase 0x%lx  iobase 0x%lx\n",
-							pci_iobase, iobase);
-		devpriv->pci_iobase = pci_iobase;
-#if 0
-/* We could enable to pci-das08's interrupt here to make it possible
- * to do timed input in this driver, but there is little point since
- * conversions would have to be started by the interrupt handler
- * so you might as well use comedi_rt_timer to emulate commands
- */
-		/* set source of interrupt trigger to counter2 output */
-		outb(CNTRL_INTR | CNTRL_DIR, pci_iobase + CNTRL);
-		/* Enable local interrupt 1 and pci interrupt */
-		outw(INTR1_ENABLE | PCI_INTR_ENABLE, pci_iobase + INTCSR);
-#endif
+		return das08_common_attach(dev, iobase);
 	} else
-#endif /* CONFIG_COMEDI_DAS08_PCI */
-	{
-		iobase = it->options[0];
-	}
-	printk(KERN_INFO "\n");
-
-	return das08_common_attach(dev, iobase);
+		return -EIO;
 }
-#endif /* DO_COMEDI_DRIVER_REGISTER */
 
 void das08_common_detach(struct comedi_device *dev)
 {
 	if (dev->subdevices)
 		subdev_8255_cleanup(dev, dev->subdevices + 4);
-	if ((thisboard->bustype != pcmcia) && (thisboard->bustype != pci)) {
+}
+EXPORT_SYMBOL_GPL(das08_common_detach);
+
+static void __maybe_unused das08_detach(struct comedi_device *dev)
+{
+	const struct das08_board_struct *thisboard = comedi_board(dev);
+	struct das08_private_struct *devpriv = dev->private;
+
+	das08_common_detach(dev);
+	if (IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) &&
+	    (thisboard->bustype == isa || thisboard->bustype == pc104)) {
 		if (dev->iobase)
 			release_region(dev->iobase, thisboard->iosize);
-	}
-#ifdef CONFIG_COMEDI_DAS08_PCI
-	if (devpriv) {
-		if (devpriv->pdev) {
+	} else if (IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) &&
+		   thisboard->bustype == pci) {
+		if (devpriv && devpriv->pdev) {
 			if (devpriv->pci_iobase)
 				comedi_pci_disable(devpriv->pdev);
-
 			pci_dev_put(devpriv->pdev);
 		}
 	}
-#endif
 }
-EXPORT_SYMBOL_GPL(das08_common_detach);
 
-#ifdef CONFIG_COMEDI_DAS08_PCI
-static int __devinit driver_das08_pci_probe(struct pci_dev *dev,
+#if DO_COMEDI_DRIVER_REGISTER
+static struct comedi_driver das08_driver = {
+	.driver_name = DRV_NAME,
+	.module = THIS_MODULE,
+	.attach = das08_attach,
+	.attach_pci = das08_attach_pci,
+	.detach = das08_detach,
+	.board_name = &das08_boards[0].name,
+	.num_names = sizeof(das08_boards) / sizeof(struct das08_board_struct),
+	.offset = sizeof(struct das08_board_struct),
+};
+#endif
+
+#if IS_ENABLED(CONFIG_COMEDI_DAS08_PCI)
+static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_DEVICE_ID_PCIDAS08) },
+	{0}
+};
+
+MODULE_DEVICE_TABLE(pci, das08_pci_table);
+
+static int __devinit das08_pci_probe(struct pci_dev *dev,
 					    const struct pci_device_id *ent)
 {
-	return comedi_pci_auto_config(dev, &driver_das08);
+	return comedi_pci_auto_config(dev, &das08_driver);
 }
 
-static void __devexit driver_das08_pci_remove(struct pci_dev *dev)
+static void __devexit das08_pci_remove(struct pci_dev *dev)
 {
 	comedi_pci_auto_unconfig(dev);
 }
 
-static struct pci_driver driver_das08_pci_driver = {
+static struct pci_driver das08_pci_driver = {
 	.id_table = das08_pci_table,
-	.probe = &driver_das08_pci_probe,
-	.remove = __devexit_p(&driver_das08_pci_remove)
+	.name =  DRV_NAME,
+	.probe = &das08_pci_probe,
+	.remove = __devexit_p(&das08_pci_remove)
 };
 #endif /* CONFIG_COMEDI_DAS08_PCI */
 
-static int __init driver_das08_init_module(void)
-{
-	int retval = 0;
-
-#ifdef DO_COMEDI_DRIVER_REGISTER
-	retval = comedi_driver_register(&driver_das08);
-	if (retval < 0)
-		return retval;
-#endif
-#ifdef CONFIG_COMEDI_DAS08_PCI
-	driver_das08_pci_driver.name = (char *)driver_das08.driver_name;
-	retval = pci_register_driver(&driver_das08_pci_driver);
+#if DO_COMEDI_DRIVER_REGISTER
+#if IS_ENABLED(CONFIG_COMEDI_DAS08_PCI)
+module_comedi_pci_driver(das08_driver, das08_pci_driver);
+#else
+module_comedi_driver(das08_driver);
 #endif
-	return retval;
+#else /* DO_COMEDI_DRIVER_REGISTER */
+static int __init das08_init(void)
+{
+	return 0;
 }
 
-static void __exit driver_das08_cleanup_module(void)
+static void __exit das08_exit(void)
 {
-#ifdef CONFIG_COMEDI_DAS08_PCI
-	pci_unregister_driver(&driver_das08_pci_driver);
-#endif
-#ifdef DO_COMEDI_DRIVER_REGISTER
-	comedi_driver_unregister(&driver_das08);
-#endif
 }
 
-module_init(driver_das08_init_module);
-module_exit(driver_das08_cleanup_module);
-
-#ifdef CONFIG_COMEDI_DAS08_CS
-EXPORT_SYMBOL_GPL(das08_cs_boards);
-#endif
+module_init(das08_init);
+module_exit(das08_exit);
+#endif /* DO_COMEDI_DRIVER_REGISTER */
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index 4ad398a..8bf6ec2 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -79,17 +79,18 @@ static int das08_cs_attach(struct comedi_device *dev,
 	if (ret < 0)
 		return ret;
 
-	dev_info(dev->hw_dev, "comedi%d: das08_cs:\n", dev->minor);
+	dev_info(dev->class_dev, "das08_cs: attach\n");
 	/*  deal with a pci board */
 
 	if (thisboard->bustype == pcmcia) {
 		if (link == NULL) {
-			dev_err(dev->hw_dev, "no pcmcia cards found\n");
+			dev_err(dev->class_dev, "no pcmcia cards found\n");
 			return -EIO;
 		}
 		iobase = link->resource[0]->start;
 	} else {
-		dev_err(dev->hw_dev, "bug! board does not have PCMCIA bustype\n");
+		dev_err(dev->class_dev,
+			"bug! board does not have PCMCIA bustype\n");
 		return -EINVAL;
 	}
 
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index 998444c..895cc77 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -393,11 +393,11 @@ struct das16_private_struct {
 	volatile short timer_mode;	/*  true if using timer mode */
 };
 #define devpriv ((struct das16_private_struct *)(dev->private))
-#define thisboard ((struct das16_board *)(dev->board_ptr))
 
 static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_cmd *cmd)
 {
+	const struct das16_board *board = comedi_board(dev);
 	int err = 0, tmp;
 	int gain, start_chan, i;
 	int mask;
@@ -411,7 +411,7 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
 	tmp = cmd->scan_begin_src;
 	mask = TRIG_FOLLOW;
 	/*  if board supports burst mode */
-	if (thisboard->size > 0x400)
+	if (board->size > 0x400)
 		mask |= TRIG_TIMER | TRIG_EXT;
 	cmd->scan_begin_src &= mask;
 	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
@@ -420,7 +420,7 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
 	tmp = cmd->convert_src;
 	mask = TRIG_TIMER | TRIG_EXT;
 	/*  if board supports burst mode */
-	if (thisboard->size > 0x400)
+	if (board->size > 0x400)
 		mask |= TRIG_NOW;
 	cmd->convert_src &= mask;
 	if (!cmd->convert_src || tmp != cmd->convert_src)
@@ -483,15 +483,15 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
 	/*  check against maximum frequency */
 	if (cmd->scan_begin_src == TRIG_TIMER) {
 		if (cmd->scan_begin_arg <
-		    thisboard->ai_speed * cmd->chanlist_len) {
+		    board->ai_speed * cmd->chanlist_len) {
 			cmd->scan_begin_arg =
-			    thisboard->ai_speed * cmd->chanlist_len;
+			    board->ai_speed * cmd->chanlist_len;
 			err++;
 		}
 	}
 	if (cmd->convert_src == TRIG_TIMER) {
-		if (cmd->convert_arg < thisboard->ai_speed) {
-			cmd->convert_arg = thisboard->ai_speed;
+		if (cmd->convert_arg < board->ai_speed) {
+			cmd->convert_arg = board->ai_speed;
 			err++;
 		}
 	}
@@ -614,6 +614,7 @@ static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
 
 static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	const struct das16_board *board = comedi_board(dev);
 	struct comedi_async *async = s->async;
 	struct comedi_cmd *cmd = &async->cmd;
 	unsigned int byte;
@@ -637,7 +638,7 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
 	    cmd->stop_arg * cmd->chanlist_len * sizeof(uint16_t);
 
 	/*  disable conversions for das1600 mode */
-	if (thisboard->size > 0x400)
+	if (board->size > 0x400)
 		outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV);
 
 	/*  set scan limits */
@@ -648,9 +649,9 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
 	/* set gain (this is also burst rate register but according to
 	 * computer boards manual, burst rate does nothing, even on
 	 * keithley cards) */
-	if (thisboard->ai_pg != das16_pg_none) {
+	if (board->ai_pg != das16_pg_none) {
 		range = CR_RANGE(cmd->chanlist[0]);
-		outb((das16_gainlists[thisboard->ai_pg])[range],
+		outb((das16_gainlists[board->ai_pg])[range],
 		     dev->iobase + DAS16_GAIN);
 	}
 
@@ -663,7 +664,7 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
 	/* enable counters */
 	byte = 0;
 	/* Enable burst mode if appropriate. */
-	if (thisboard->size > 0x400) {
+	if (board->size > 0x400) {
 		if (cmd->convert_src == TRIG_NOW) {
 			outb(DAS1600_BURST_VAL, dev->iobase + DAS1600_BURST);
 			/*  set burst length */
@@ -710,7 +711,7 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
 	outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
 
 	/* Enable conversions if using das1600 mode */
-	if (thisboard->size > 0x400)
+	if (board->size > 0x400)
 		outb(0, dev->iobase + DAS1600_CONV);
 
 
@@ -719,6 +720,7 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
 
 static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	const struct das16_board *board = comedi_board(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->spinlock, flags);
@@ -735,7 +737,7 @@ static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 	}
 
 	/* disable burst mode */
-	if (thisboard->size > 0x400)
+	if (board->size > 0x400)
 		outb(0, dev->iobase + DAS1600_BURST);
 
 
@@ -755,6 +757,7 @@ static void das16_reset(struct comedi_device *dev)
 static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
+	const struct das16_board *board = comedi_board(dev);
 	int i, n;
 	int range;
 	int chan;
@@ -770,9 +773,9 @@ static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 	outb(chan, dev->iobase + DAS16_MUX);
 
 	/* set gain */
-	if (thisboard->ai_pg != das16_pg_none) {
+	if (board->ai_pg != das16_pg_none) {
 		range = CR_RANGE(insn->chanspec);
-		outb((das16_gainlists[thisboard->ai_pg])[range],
+		outb((das16_gainlists[board->ai_pg])[range],
 		     dev->iobase + DAS16_GAIN);
 	}
 
@@ -790,7 +793,7 @@ static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 		}
 		msb = inb(dev->iobase + DAS16_AI_MSB);
 		lsb = inb(dev->iobase + DAS16_AI_LSB);
-		if (thisboard->ai_nbits == 12)
+		if (board->ai_nbits == 12)
 			data[n] = ((lsb >> 4) & 0xf) | (msb << 4);
 		else
 			data[n] = lsb | (msb << 8);
@@ -809,7 +812,7 @@ static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
 	data[1] = bits;
 	data[0] = 0;
 
-	return 2;
+	return insn->n;
 }
 
 static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -829,12 +832,13 @@ static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	outb(s->state, dev->iobase + DAS16_DIO);
 
-	return 2;
+	return insn->n;
 }
 
 static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
+	const struct das16_board *board = comedi_board(dev);
 	int i;
 	int lsb, msb;
 	int chan;
@@ -842,7 +846,7 @@ static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
 	chan = CR_CHAN(insn->chanspec);
 
 	for (i = 0; i < insn->n; i++) {
-		if (thisboard->ao_nbits == 12) {
+		if (board->ao_nbits == 12) {
 			lsb = (data[i] << 4) & 0xff;
 			msb = (data[i] >> 4) & 0xff;
 		} else {
@@ -892,6 +896,7 @@ static int disable_dma_on_even(struct comedi_device *dev)
 
 static void das16_interrupt(struct comedi_device *dev)
 {
+	const struct das16_board *board = comedi_board(dev);
 	unsigned long dma_flags, spin_flags;
 	struct comedi_subdevice *s = dev->read_subdev;
 	struct comedi_async *async;
@@ -953,7 +958,7 @@ static void das16_interrupt(struct comedi_device *dev)
 		set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
 		enable_dma(devpriv->dma_chan);
 		/* reenable conversions for das1600 mode, (stupid hardware) */
-		if (thisboard->size > 0x400 && devpriv->timer_mode == 0)
+		if (board->size > 0x400 && devpriv->timer_mode == 0)
 			outb(0x00, dev->iobase + DAS1600_CONV);
 
 	}
@@ -1015,6 +1020,7 @@ static void reg_dump(struct comedi_device *dev)
 
 static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct das16_board *board = comedi_board(dev);
 	int status;
 	int diobits;
 
@@ -1039,9 +1045,9 @@ static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it)
 	diobits = inb(dev->iobase + DAS16_DIO) & 0xf0;
 
 	printk(KERN_INFO " id bits are 0x%02x\n", diobits);
-	if (thisboard->id != diobits) {
+	if (board->id != diobits) {
 		printk(KERN_INFO " requested board's id bits are 0x%x (ignore)\n",
-		       thisboard->id);
+		       board->id);
 	}
 
 	return 0;
@@ -1071,12 +1077,13 @@ static void das16_ai_munge(struct comedi_device *dev,
 			   unsigned int num_bytes,
 			   unsigned int start_chan_index)
 {
+	const struct das16_board *board = comedi_board(dev);
 	unsigned int i, num_samples = num_bytes / sizeof(short);
 	short *data = array;
 
 	for (i = 0; i < num_samples; i++) {
 		data[i] = le16_to_cpu(data[i]);
-		if (thisboard->ai_nbits == 12)
+		if (board->ai_nbits == 12)
 			data[i] = (data[i] >> 4) & 0xfff;
 
 	}
@@ -1092,6 +1099,7 @@ static void das16_ai_munge(struct comedi_device *dev,
  */
 static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct das16_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	int ret;
 	unsigned int irq;
@@ -1130,9 +1138,9 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	if (ret < 0)
 		return ret;
 
-	if (thisboard->size < 0x400) {
-		printk(" 0x%04lx-0x%04lx\n", iobase, iobase + thisboard->size);
-		if (!request_region(iobase, thisboard->size, "das16")) {
+	if (board->size < 0x400) {
+		printk(" 0x%04lx-0x%04lx\n", iobase, iobase + board->size);
+		if (!request_region(iobase, board->size, "das16")) {
 			printk(KERN_ERR " I/O port conflict\n");
 			return -EIO;
 		}
@@ -1140,18 +1148,18 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		printk(KERN_INFO " 0x%04lx-0x%04lx 0x%04lx-0x%04lx\n",
 		       iobase, iobase + 0x0f,
 		       iobase + 0x400,
-		       iobase + 0x400 + (thisboard->size & 0x3ff));
+		       iobase + 0x400 + (board->size & 0x3ff));
 		if (!request_region(iobase, 0x10, "das16")) {
 			printk(KERN_ERR " I/O port conflict:  0x%04lx-0x%04lx\n",
 			       iobase, iobase + 0x0f);
 			return -EIO;
 		}
-		if (!request_region(iobase + 0x400, thisboard->size & 0x3ff,
+		if (!request_region(iobase + 0x400, board->size & 0x3ff,
 				    "das16")) {
 			release_region(iobase, 0x10);
 			printk(KERN_ERR " I/O port conflict:  0x%04lx-0x%04lx\n",
 			       iobase + 0x400,
-			       iobase + 0x400 + (thisboard->size & 0x3ff));
+			       iobase + 0x400 + (board->size & 0x3ff));
 			return -EIO;
 		}
 	}
@@ -1163,10 +1171,10 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		printk(KERN_ERR " id bits do not match selected board, aborting\n");
 		return -EINVAL;
 	}
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 	/*  get master clock speed */
-	if (thisboard->size < 0x400) {
+	if (board->size < 0x400) {
 		if (it->options[3])
 			devpriv->clockbase = 1000 / it->options[3];
 		else
@@ -1222,7 +1230,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	}
 
 	/*  get any user-defined input range */
-	if (thisboard->ai_pg == das16_pg_none &&
+	if (board->ai_pg == das16_pg_none &&
 	    (it->options[4] || it->options[5])) {
 		/*  allocate single-range range table */
 		devpriv->user_ai_range_table =
@@ -1256,14 +1264,14 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	}
 	devpriv->timer_mode = timer_mode ? 1 : 0;
 
-	ret = alloc_subdevices(dev, 5);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 5);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices + 0;
 	dev->read_subdev = s;
 	/* ai */
-	if (thisboard->ai) {
+	if (board->ai) {
 		s->type = COMEDI_SUBD_AI;
 		s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
 		if (devpriv->ai_singleended) {
@@ -1275,15 +1283,15 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 			s->len_chanlist = 8;
 			s->subdev_flags |= SDF_DIFF;
 		}
-		s->maxdata = (1 << thisboard->ai_nbits) - 1;
+		s->maxdata = (1 << board->ai_nbits) - 1;
 		if (devpriv->user_ai_range_table) { /*  user defined ai range */
 			s->range_table = devpriv->user_ai_range_table;
 		} else if (devpriv->ai_unipolar) {
-			s->range_table = das16_ai_uni_lranges[thisboard->ai_pg];
+			s->range_table = das16_ai_uni_lranges[board->ai_pg];
 		} else {
-			s->range_table = das16_ai_bip_lranges[thisboard->ai_pg];
+			s->range_table = das16_ai_bip_lranges[board->ai_pg];
 		}
-		s->insn_read = thisboard->ai;
+		s->insn_read = board->ai;
 		s->do_cmdtest = das16_cmd_test;
 		s->do_cmd = das16_cmd_exec;
 		s->cancel = das16_cancel;
@@ -1294,44 +1302,44 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	s = dev->subdevices + 1;
 	/* ao */
-	if (thisboard->ao) {
+	if (board->ao) {
 		s->type = COMEDI_SUBD_AO;
 		s->subdev_flags = SDF_WRITABLE;
 		s->n_chan = 2;
-		s->maxdata = (1 << thisboard->ao_nbits) - 1;
+		s->maxdata = (1 << board->ao_nbits) - 1;
 		/*  user defined ao range */
 		if (devpriv->user_ao_range_table)
 			s->range_table = devpriv->user_ao_range_table;
 		else
 			s->range_table = &range_unknown;
 
-		s->insn_write = thisboard->ao;
+		s->insn_write = board->ao;
 	} else {
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
 	s = dev->subdevices + 2;
 	/* di */
-	if (thisboard->di) {
+	if (board->di) {
 		s->type = COMEDI_SUBD_DI;
 		s->subdev_flags = SDF_READABLE;
 		s->n_chan = 4;
 		s->maxdata = 1;
 		s->range_table = &range_digital;
-		s->insn_bits = thisboard->di;
+		s->insn_bits = board->di;
 	} else {
 		s->type = COMEDI_SUBD_UNUSED;
 	}
 
 	s = dev->subdevices + 3;
 	/* do */
-	if (thisboard->do_) {
+	if (board->do_) {
 		s->type = COMEDI_SUBD_DO;
 		s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
 		s->n_chan = 4;
 		s->maxdata = 1;
 		s->range_table = &range_digital;
-		s->insn_bits = thisboard->do_;
+		s->insn_bits = board->do_;
 		/*  initialize digital output lines */
 		outb(s->state, dev->iobase + DAS16_DIO);
 	} else {
@@ -1340,9 +1348,9 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	s = dev->subdevices + 4;
 	/* 8255 */
-	if (thisboard->i8255_offset != 0) {
+	if (board->i8255_offset != 0) {
 		subdev_8255_init(dev, s, NULL, (dev->iobase +
-						thisboard->i8255_offset));
+						board->i8255_offset));
 	} else {
 		s->type = COMEDI_SUBD_UNUSED;
 	}
@@ -1353,7 +1361,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
 
 	/*  turn on das1600 mode if available */
-	if (thisboard->size > 0x400) {
+	if (board->size > 0x400) {
 		outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE);
 		outb(0, dev->iobase + DAS1600_CONV);
 		outb(0, dev->iobase + DAS1600_BURST);
@@ -1364,6 +1372,8 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 static void das16_detach(struct comedi_device *dev)
 {
+	const struct das16_board *board = comedi_board(dev);
+
 	das16_reset(dev);
 	if (dev->subdevices)
 		subdev_8255_cleanup(dev, dev->subdevices + 4);
@@ -1384,12 +1394,12 @@ static void das16_detach(struct comedi_device *dev)
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->iobase) {
-		if (thisboard->size < 0x400) {
-			release_region(dev->iobase, thisboard->size);
+		if (board->size < 0x400) {
+			release_region(dev->iobase, board->size);
 		} else {
 			release_region(dev->iobase, 0x10);
 			release_region(dev->iobase + 0x400,
-				       thisboard->size & 0x3ff);
+				       board->size & 0x3ff);
 		}
 	}
 }
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index d2e1490..2009263 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -150,7 +150,6 @@ struct das16m1_private_struct {
 	unsigned int divisor2;	/*  divides master clock to obtain conversion speed */
 };
 #define devpriv ((struct das16m1_private_struct *)(dev->private))
-#define thisboard ((const struct das16m1_board *)(dev->board_ptr))
 
 static inline short munge_sample(short data)
 {
@@ -168,6 +167,7 @@ static void munge_sample_array(short *array, unsigned int num_elements)
 static int das16m1_cmd_test(struct comedi_device *dev,
 			    struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
+	const struct das16m1_board *board = comedi_board(dev);
 	unsigned int err = 0, tmp, i;
 
 	/* make sure triggers are valid */
@@ -225,8 +225,8 @@ static int das16m1_cmd_test(struct comedi_device *dev,
 	}
 
 	if (cmd->convert_src == TRIG_TIMER) {
-		if (cmd->convert_arg < thisboard->ai_speed) {
-			cmd->convert_arg = thisboard->ai_speed;
+		if (cmd->convert_arg < board->ai_speed) {
+			cmd->convert_arg = board->ai_speed;
 			err++;
 		}
 	}
@@ -428,7 +428,7 @@ static int das16m1_di_rbits(struct comedi_device *dev,
 	data[1] = bits;
 	data[0] = 0;
 
-	return 2;
+	return insn->n;
 }
 
 static int das16m1_do_wbits(struct comedi_device *dev,
@@ -449,7 +449,7 @@ static int das16m1_do_wbits(struct comedi_device *dev,
 
 	outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO);
 
-	return 2;
+	return insn->n;
 }
 
 static void das16m1_handler(struct comedi_device *dev, unsigned int status)
@@ -600,6 +600,7 @@ static int das16m1_irq_bits(unsigned int irq)
 static int das16m1_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
+	const struct das16m1_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	int ret;
 	unsigned int irq;
@@ -611,7 +612,7 @@ static int das16m1_attach(struct comedi_device *dev,
 	if (ret < 0)
 		return ret;
 
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 	if (!request_region(iobase, DAS16M1_SIZE, dev->driver->driver_name)) {
 		comedi_error(dev, "I/O port conflict\n");
@@ -645,8 +646,8 @@ static int das16m1_attach(struct comedi_device *dev,
 		return -EINVAL;
 	}
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 2ac3443..25e7e56 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -183,46 +183,6 @@ enum {
 	das1802hr, das1802hr_da, das1801hc, das1802hc, das1801ao, das1802ao
 };
 
-static int das1800_probe(struct comedi_device *dev);
-static int das1800_cancel(struct comedi_device *dev,
-			  struct comedi_subdevice *s);
-static irqreturn_t das1800_interrupt(int irq, void *d);
-static int das1800_ai_poll(struct comedi_device *dev,
-			   struct comedi_subdevice *s);
-static void das1800_ai_handler(struct comedi_device *dev);
-static void das1800_handle_dma(struct comedi_device *dev,
-			       struct comedi_subdevice *s, unsigned int status);
-static void das1800_flush_dma(struct comedi_device *dev,
-			      struct comedi_subdevice *s);
-static void das1800_flush_dma_channel(struct comedi_device *dev,
-				      struct comedi_subdevice *s,
-				      unsigned int channel, uint16_t *buffer);
-static void das1800_handle_fifo_half_full(struct comedi_device *dev,
-					  struct comedi_subdevice *s);
-static void das1800_handle_fifo_not_empty(struct comedi_device *dev,
-					  struct comedi_subdevice *s);
-static int das1800_ai_do_cmdtest(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_cmd *cmd);
-static int das1800_ai_do_cmd(struct comedi_device *dev,
-			     struct comedi_subdevice *s);
-static int das1800_ai_rinsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int das1800_ao_winsn(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int das1800_di_rbits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-static int das1800_do_wbits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data);
-
-static int das1800_set_frequency(struct comedi_device *dev);
-static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode);
-static unsigned int suggest_transfer_size(struct comedi_cmd *cmd);
-
 /* analog input ranges */
 static const struct comedi_lrange range_ai_das1801 = {
 	8,
@@ -515,400 +475,182 @@ static const struct comedi_lrange range_ao_2 = {
 };
 */
 
-static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
-			    unsigned int dma1)
+static inline uint16_t munge_bipolar_sample(const struct comedi_device *dev,
+					    uint16_t sample)
 {
-	unsigned long flags;
+	sample += 1 << (thisboard->resolution - 1);
+	return sample;
+}
 
-	/*  need an irq to do dma */
-	if (dev->irq && dma0) {
-		/* encode dma0 and dma1 into 2 digit hexadecimal for switch */
-		switch ((dma0 & 0x7) | (dma1 << 4)) {
-		case 0x5:	/*  dma0 == 5 */
-			devpriv->dma_bits |= DMA_CH5;
-			break;
-		case 0x6:	/*  dma0 == 6 */
-			devpriv->dma_bits |= DMA_CH6;
-			break;
-		case 0x7:	/*  dma0 == 7 */
-			devpriv->dma_bits |= DMA_CH7;
-			break;
-		case 0x65:	/*  dma0 == 5, dma1 == 6 */
-			devpriv->dma_bits |= DMA_CH5_CH6;
-			break;
-		case 0x76:	/*  dma0 == 6, dma1 == 7 */
-			devpriv->dma_bits |= DMA_CH6_CH7;
-			break;
-		case 0x57:	/*  dma0 == 7, dma1 == 5 */
-			devpriv->dma_bits |= DMA_CH7_CH5;
-			break;
-		default:
-			dev_err(dev->hw_dev, " only supports dma channels 5 through 7\n"
-				" Dual dma only allows the following combinations:\n"
-				" dma 5,6 / 6,7 / or 7,5\n");
-			return -EINVAL;
-			break;
-		}
-		if (request_dma(dma0, dev->driver->driver_name)) {
-			dev_err(dev->hw_dev, "failed to allocate dma channel %i\n",
-				dma0);
-			return -EINVAL;
-		}
-		devpriv->dma0 = dma0;
-		devpriv->dma_current = dma0;
-		if (dma1) {
-			if (request_dma(dma1, dev->driver->driver_name)) {
-				dev_err(dev->hw_dev, "failed to allocate dma channel %i\n",
-					dma1);
-				return -EINVAL;
-			}
-			devpriv->dma1 = dma1;
-		}
-		devpriv->ai_buf0 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
-		if (devpriv->ai_buf0 == NULL)
-			return -ENOMEM;
-		devpriv->dma_current_buf = devpriv->ai_buf0;
-		if (dma1) {
-			devpriv->ai_buf1 =
-			    kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
-			if (devpriv->ai_buf1 == NULL)
-				return -ENOMEM;
-		}
-		flags = claim_dma_lock();
-		disable_dma(devpriv->dma0);
-		set_dma_mode(devpriv->dma0, DMA_MODE_READ);
-		if (dma1) {
-			disable_dma(devpriv->dma1);
-			set_dma_mode(devpriv->dma1, DMA_MODE_READ);
-		}
-		release_dma_lock(flags);
+static void munge_data(struct comedi_device *dev, uint16_t * array,
+		       unsigned int num_elements)
+{
+	unsigned int i;
+	int unipolar;
+
+	/* see if card is using a unipolar or bipolar range so we can munge data correctly */
+	unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
+
+	/* convert to unsigned type if we are in a bipolar mode */
+	if (!unipolar) {
+		for (i = 0; i < num_elements; i++)
+			array[i] = munge_bipolar_sample(dev, array[i]);
 	}
-	return 0;
 }
 
-static int das1800_attach(struct comedi_device *dev,
-			  struct comedi_devconfig *it)
+static void das1800_handle_fifo_half_full(struct comedi_device *dev,
+					  struct comedi_subdevice *s)
 {
-	struct comedi_subdevice *s;
-	unsigned long iobase = it->options[0];
-	unsigned int irq = it->options[1];
-	unsigned int dma0 = it->options[2];
-	unsigned int dma1 = it->options[3];
-	unsigned long iobase2;
-	int board;
-	int retval;
+	int numPoints = 0;	/* number of points to read */
+	struct comedi_cmd *cmd = &s->async->cmd;
 
-	/* allocate and initialize dev->private */
-	if (alloc_private(dev, sizeof(struct das1800_private)) < 0)
-		return -ENOMEM;
+	numPoints = FIFO_SIZE / 2;
+	/* if we only need some of the points */
+	if (cmd->stop_src == TRIG_COUNT && devpriv->count < numPoints)
+		numPoints = devpriv->count;
+	insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, numPoints);
+	munge_data(dev, devpriv->ai_buf0, numPoints);
+	cfc_write_array_to_buffer(s, devpriv->ai_buf0,
+				  numPoints * sizeof(devpriv->ai_buf0[0]));
+	if (cmd->stop_src == TRIG_COUNT)
+		devpriv->count -= numPoints;
+	return;
+}
 
-	printk(KERN_DEBUG "comedi%d: %s: io 0x%lx", dev->minor,
-	       dev->driver->driver_name, iobase);
-	if (irq) {
-		printk(KERN_CONT ", irq %u", irq);
-		if (dma0) {
-			printk(KERN_CONT ", dma %u", dma0);
-			if (dma1)
-				printk(KERN_CONT " and %u", dma1);
-		}
-	}
-	printk(KERN_CONT "\n");
+static void das1800_handle_fifo_not_empty(struct comedi_device *dev,
+					  struct comedi_subdevice *s)
+{
+	short dpnt;
+	int unipolar;
+	struct comedi_cmd *cmd = &s->async->cmd;
 
-	if (iobase == 0) {
-		dev_err(dev->hw_dev, "io base address required\n");
-		return -EINVAL;
-	}
+	unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
 
-	/* check if io addresses are available */
-	if (!request_region(iobase, DAS1800_SIZE, dev->driver->driver_name)) {
-		printk
-		    (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
-		     iobase, iobase + DAS1800_SIZE - 1);
-		return -EIO;
+	while (inb(dev->iobase + DAS1800_STATUS) & FNE) {
+		if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0)
+			break;
+		dpnt = inw(dev->iobase + DAS1800_FIFO);
+		/* convert to unsigned type if we are in a bipolar mode */
+		if (!unipolar)
+			;
+		dpnt = munge_bipolar_sample(dev, dpnt);
+		cfc_write_to_buffer(s, dpnt);
+		if (cmd->stop_src == TRIG_COUNT)
+			devpriv->count--;
 	}
-	dev->iobase = iobase;
 
-	board = das1800_probe(dev);
-	if (board < 0) {
-		dev_err(dev->hw_dev, "unable to determine board type\n");
-		return -ENODEV;
-	}
+	return;
+}
 
-	dev->board_ptr = das1800_boards + board;
-	dev->board_name = thisboard->name;
+/* Utility function used by das1800_flush_dma() and das1800_handle_dma().
+ * Assumes dma lock is held */
+static void das1800_flush_dma_channel(struct comedi_device *dev,
+				      struct comedi_subdevice *s,
+				      unsigned int channel, uint16_t *buffer)
+{
+	unsigned int num_bytes, num_samples;
+	struct comedi_cmd *cmd = &s->async->cmd;
 
-	/*  if it is an 'ao' board with fancy analog out then we need extra io ports */
-	if (thisboard->ao_ability == 2) {
-		iobase2 = iobase + IOBASE2;
-		if (!request_region(iobase2, DAS1800_SIZE,
-				    dev->driver->driver_name)) {
-			printk
-			    (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
-			     iobase2, iobase2 + DAS1800_SIZE - 1);
-			return -EIO;
-		}
-		devpriv->iobase2 = iobase2;
-	}
+	disable_dma(channel);
 
-	/* grab our IRQ */
-	if (irq) {
-		if (request_irq(irq, das1800_interrupt, 0,
-				dev->driver->driver_name, dev)) {
-			dev_dbg(dev->hw_dev, "unable to allocate irq %u\n",
-				irq);
-			return -EINVAL;
-		}
-	}
-	dev->irq = irq;
+	/* clear flip-flop to make sure 2-byte registers
+	 * get set correctly */
+	clear_dma_ff(channel);
 
-	/*  set bits that tell card which irq to use */
-	switch (irq) {
-	case 0:
-		break;
-	case 3:
-		devpriv->irq_dma_bits |= 0x8;
-		break;
-	case 5:
-		devpriv->irq_dma_bits |= 0x10;
-		break;
-	case 7:
-		devpriv->irq_dma_bits |= 0x18;
-		break;
-	case 10:
-		devpriv->irq_dma_bits |= 0x28;
-		break;
-	case 11:
-		devpriv->irq_dma_bits |= 0x30;
-		break;
-	case 15:
-		devpriv->irq_dma_bits |= 0x38;
-		break;
-	default:
-		dev_err(dev->hw_dev, "irq out of range\n");
-		return -EINVAL;
-		break;
-	}
+	/*  figure out how many points to read */
+	num_bytes = devpriv->dma_transfer_size - get_dma_residue(channel);
+	num_samples = num_bytes / sizeof(short);
 
-	retval = das1800_init_dma(dev, dma0, dma1);
-	if (retval < 0)
-		return retval;
+	/* if we only need some of the points */
+	if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_samples)
+		num_samples = devpriv->count;
 
-	if (devpriv->ai_buf0 == NULL) {
-		devpriv->ai_buf0 =
-		    kmalloc(FIFO_SIZE * sizeof(uint16_t), GFP_KERNEL);
-		if (devpriv->ai_buf0 == NULL)
-			return -ENOMEM;
-	}
+	munge_data(dev, buffer, num_samples);
+	cfc_write_array_to_buffer(s, buffer, num_bytes);
+	if (s->async->cmd.stop_src == TRIG_COUNT)
+		devpriv->count -= num_samples;
 
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
+	return;
+}
 
-	/* analog input subdevice */
-	s = dev->subdevices + 0;
-	dev->read_subdev = s;
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND | SDF_CMD_READ;
-	if (thisboard->common)
-		s->subdev_flags |= SDF_COMMON;
-	s->n_chan = thisboard->qram_len;
-	s->len_chanlist = thisboard->qram_len;
-	s->maxdata = (1 << thisboard->resolution) - 1;
-	s->range_table = thisboard->range_ai;
-	s->do_cmd = das1800_ai_do_cmd;
-	s->do_cmdtest = das1800_ai_do_cmdtest;
-	s->insn_read = das1800_ai_rinsn;
-	s->poll = das1800_ai_poll;
-	s->cancel = das1800_cancel;
-
-	/* analog out */
-	s = dev->subdevices + 1;
-	if (thisboard->ao_ability == 1) {
-		s->type = COMEDI_SUBD_AO;
-		s->subdev_flags = SDF_WRITABLE;
-		s->n_chan = thisboard->ao_n_chan;
-		s->maxdata = (1 << thisboard->resolution) - 1;
-		s->range_table = &range_ao_1;
-		s->insn_write = das1800_ao_winsn;
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
-
-	/* di */
-	s = dev->subdevices + 2;
-	s->type = COMEDI_SUBD_DI;
-	s->subdev_flags = SDF_READABLE;
-	s->n_chan = 4;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = das1800_di_rbits;
-
-	/* do */
-	s = dev->subdevices + 3;
-	s->type = COMEDI_SUBD_DO;
-	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-	s->n_chan = thisboard->do_n_chan;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = das1800_do_wbits;
-
-	das1800_cancel(dev, dev->read_subdev);
-
-	/*  initialize digital out channels */
-	outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL);
-
-	/*  initialize analog out channels */
-	if (thisboard->ao_ability == 1) {
-		/*  select 'update' dac channel for baseAddress + 0x0 */
-		outb(DAC(thisboard->ao_n_chan - 1),
-		     dev->iobase + DAS1800_SELECT);
-		outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC);
-	}
-
-	return 0;
-};
-
-static void das1800_detach(struct comedi_device *dev)
-{
-	if (dev->iobase)
-		release_region(dev->iobase, DAS1800_SIZE);
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-	if (dev->private) {
-		if (devpriv->iobase2)
-			release_region(devpriv->iobase2, DAS1800_SIZE);
-		if (devpriv->dma0)
-			free_dma(devpriv->dma0);
-		if (devpriv->dma1)
-			free_dma(devpriv->dma1);
-		kfree(devpriv->ai_buf0);
-		kfree(devpriv->ai_buf1);
-	}
-};
-
-/* probes and checks das-1800 series board type
- */
-static int das1800_probe(struct comedi_device *dev)
+/* flushes remaining data from board when external trigger has stopped acquisition
+ * and we are using dma transfers */
+static void das1800_flush_dma(struct comedi_device *dev,
+			      struct comedi_subdevice *s)
 {
-	int id;
-	int board;
+	unsigned long flags;
+	const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
 
-	id = (inb(dev->iobase + DAS1800_DIGITAL) >> 4) & 0xf;	/* get id bits */
-	board = ((struct das1800_board *)dev->board_ptr) - das1800_boards;
+	flags = claim_dma_lock();
+	das1800_flush_dma_channel(dev, s, devpriv->dma_current,
+				  devpriv->dma_current_buf);
 
-	switch (id) {
-	case 0x3:
-		if (board == das1801st_da || board == das1802st_da ||
-		    board == das1701st_da || board == das1702st_da) {
-			dev_dbg(dev->hw_dev, "Board model: %s\n",
-				das1800_boards[board].name);
-			return board;
-		}
-		printk
-		    (" Board model (probed, not recommended): das-1800st-da series\n");
-		return das1801st;
-		break;
-	case 0x4:
-		if (board == das1802hr_da || board == das1702hr_da) {
-			dev_dbg(dev->hw_dev, "Board model: %s\n",
-				das1800_boards[board].name);
-			return board;
-		}
-		printk
-		    (" Board model (probed, not recommended): das-1802hr-da\n");
-		return das1802hr;
-		break;
-	case 0x5:
-		if (board == das1801ao || board == das1802ao ||
-		    board == das1701ao || board == das1702ao) {
-			dev_dbg(dev->hw_dev, "Board model: %s\n",
-				das1800_boards[board].name);
-			return board;
-		}
-		printk
-		    (" Board model (probed, not recommended): das-1800ao series\n");
-		return das1801ao;
-		break;
-	case 0x6:
-		if (board == das1802hr || board == das1702hr) {
-			dev_dbg(dev->hw_dev, "Board model: %s\n",
-				das1800_boards[board].name);
-			return board;
-		}
-		printk
-		    (" Board model (probed, not recommended): das-1802hr\n");
-		return das1802hr;
-		break;
-	case 0x7:
-		if (board == das1801st || board == das1802st ||
-		    board == das1701st || board == das1702st) {
-			dev_dbg(dev->hw_dev, "Board model: %s\n",
-				das1800_boards[board].name);
-			return board;
-		}
-		printk
-		    (" Board model (probed, not recommended): das-1800st series\n");
-		return das1801st;
-		break;
-	case 0x8:
-		if (board == das1801hc || board == das1802hc) {
-			dev_dbg(dev->hw_dev, "Board model: %s\n",
-				das1800_boards[board].name);
-			return board;
+	if (dual_dma) {
+		/*  switch to other channel and flush it */
+		if (devpriv->dma_current == devpriv->dma0) {
+			devpriv->dma_current = devpriv->dma1;
+			devpriv->dma_current_buf = devpriv->ai_buf1;
+		} else {
+			devpriv->dma_current = devpriv->dma0;
+			devpriv->dma_current_buf = devpriv->ai_buf0;
 		}
-		printk
-		    (" Board model (probed, not recommended): das-1800hc series\n");
-		return das1801hc;
-		break;
-	default:
-		printk
-		    (" Board model: probe returned 0x%x (unknown, please report)\n",
-		     id);
-		return board;
-		break;
+		das1800_flush_dma_channel(dev, s, devpriv->dma_current,
+					  devpriv->dma_current_buf);
 	}
-	return -1;
-}
 
-static int das1800_ai_poll(struct comedi_device *dev,
-			   struct comedi_subdevice *s)
-{
-	unsigned long flags;
+	release_dma_lock(flags);
 
-	/*  prevent race with interrupt handler */
-	spin_lock_irqsave(&dev->spinlock, flags);
-	das1800_ai_handler(dev);
-	spin_unlock_irqrestore(&dev->spinlock, flags);
+	/*  get any remaining samples in fifo */
+	das1800_handle_fifo_not_empty(dev, s);
 
-	return s->async->buf_write_count - s->async->buf_read_count;
+	return;
 }
 
-static irqreturn_t das1800_interrupt(int irq, void *d)
+static void das1800_handle_dma(struct comedi_device *dev,
+			       struct comedi_subdevice *s, unsigned int status)
 {
-	struct comedi_device *dev = d;
-	unsigned int status;
-
-	if (dev->attached == 0) {
-		comedi_error(dev, "premature interrupt");
-		return IRQ_HANDLED;
-	}
+	unsigned long flags;
+	const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
 
-	/* Prevent race with das1800_ai_poll() on multi processor systems.
-	 * Also protects indirect addressing in das1800_ai_handler */
-	spin_lock(&dev->spinlock);
-	status = inb(dev->iobase + DAS1800_STATUS);
+	flags = claim_dma_lock();
+	das1800_flush_dma_channel(dev, s, devpriv->dma_current,
+				  devpriv->dma_current_buf);
+	/*  re-enable  dma channel */
+	set_dma_addr(devpriv->dma_current,
+		     virt_to_bus(devpriv->dma_current_buf));
+	set_dma_count(devpriv->dma_current, devpriv->dma_transfer_size);
+	enable_dma(devpriv->dma_current);
+	release_dma_lock(flags);
 
-	/* if interrupt was not caused by das-1800 */
-	if (!(status & INT)) {
-		spin_unlock(&dev->spinlock);
-		return IRQ_NONE;
+	if (status & DMATC) {
+		/*  clear DMATC interrupt bit */
+		outb(CLEAR_INTR_MASK & ~DMATC, dev->iobase + DAS1800_STATUS);
+		/*  switch dma channels for next time, if appropriate */
+		if (dual_dma) {
+			/*  read data from the other channel next time */
+			if (devpriv->dma_current == devpriv->dma0) {
+				devpriv->dma_current = devpriv->dma1;
+				devpriv->dma_current_buf = devpriv->ai_buf1;
+			} else {
+				devpriv->dma_current = devpriv->dma0;
+				devpriv->dma_current_buf = devpriv->ai_buf0;
+			}
+		}
 	}
-	/* clear the interrupt status bit INT */
-	outb(CLEAR_INTR_MASK & ~INT, dev->iobase + DAS1800_STATUS);
-	/*  handle interrupt */
-	das1800_ai_handler(dev);
 
-	spin_unlock(&dev->spinlock);
-	return IRQ_HANDLED;
+	return;
+}
+
+static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+	outb(0x0, dev->iobase + DAS1800_STATUS);	/* disable conversions */
+	outb(0x0, dev->iobase + DAS1800_CONTROL_B);	/* disable interrupts and dma */
+	outb(0x0, dev->iobase + DAS1800_CONTROL_A);	/* disable and clear fifo and stop triggering */
+	if (devpriv->dma0)
+		disable_dma(devpriv->dma0);
+	if (devpriv->dma1)
+		disable_dma(devpriv->dma1);
+	return 0;
 }
 
 /* the guts of the interrupt handler, that is shared with das1800_ai_poll */
@@ -965,182 +707,75 @@ static void das1800_ai_handler(struct comedi_device *dev)
 	return;
 }
 
-static void das1800_handle_dma(struct comedi_device *dev,
-			       struct comedi_subdevice *s, unsigned int status)
+static int das1800_ai_poll(struct comedi_device *dev,
+			   struct comedi_subdevice *s)
 {
 	unsigned long flags;
-	const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
 
-	flags = claim_dma_lock();
-	das1800_flush_dma_channel(dev, s, devpriv->dma_current,
-				  devpriv->dma_current_buf);
-	/*  re-enable  dma channel */
-	set_dma_addr(devpriv->dma_current,
-		     virt_to_bus(devpriv->dma_current_buf));
-	set_dma_count(devpriv->dma_current, devpriv->dma_transfer_size);
-	enable_dma(devpriv->dma_current);
-	release_dma_lock(flags);
-
-	if (status & DMATC) {
-		/*  clear DMATC interrupt bit */
-		outb(CLEAR_INTR_MASK & ~DMATC, dev->iobase + DAS1800_STATUS);
-		/*  switch dma channels for next time, if appropriate */
-		if (dual_dma) {
-			/*  read data from the other channel next time */
-			if (devpriv->dma_current == devpriv->dma0) {
-				devpriv->dma_current = devpriv->dma1;
-				devpriv->dma_current_buf = devpriv->ai_buf1;
-			} else {
-				devpriv->dma_current = devpriv->dma0;
-				devpriv->dma_current_buf = devpriv->ai_buf0;
-			}
-		}
-	}
-
-	return;
-}
+	/*  prevent race with interrupt handler */
+	spin_lock_irqsave(&dev->spinlock, flags);
+	das1800_ai_handler(dev);
+	spin_unlock_irqrestore(&dev->spinlock, flags);
 
-static inline uint16_t munge_bipolar_sample(const struct comedi_device *dev,
-					    uint16_t sample)
-{
-	sample += 1 << (thisboard->resolution - 1);
-	return sample;
+	return s->async->buf_write_count - s->async->buf_read_count;
 }
 
-static void munge_data(struct comedi_device *dev, uint16_t * array,
-		       unsigned int num_elements)
+static irqreturn_t das1800_interrupt(int irq, void *d)
 {
-	unsigned int i;
-	int unipolar;
-
-	/* see if card is using a unipolar or bipolar range so we can munge data correctly */
-	unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
+	struct comedi_device *dev = d;
+	unsigned int status;
 
-	/* convert to unsigned type if we are in a bipolar mode */
-	if (!unipolar) {
-		for (i = 0; i < num_elements; i++)
-			array[i] = munge_bipolar_sample(dev, array[i]);
+	if (dev->attached == 0) {
+		comedi_error(dev, "premature interrupt");
+		return IRQ_HANDLED;
 	}
-}
-
-/* Utility function used by das1800_flush_dma() and das1800_handle_dma().
- * Assumes dma lock is held */
-static void das1800_flush_dma_channel(struct comedi_device *dev,
-				      struct comedi_subdevice *s,
-				      unsigned int channel, uint16_t *buffer)
-{
-	unsigned int num_bytes, num_samples;
-	struct comedi_cmd *cmd = &s->async->cmd;
-
-	disable_dma(channel);
-
-	/* clear flip-flop to make sure 2-byte registers
-	 * get set correctly */
-	clear_dma_ff(channel);
-
-	/*  figure out how many points to read */
-	num_bytes = devpriv->dma_transfer_size - get_dma_residue(channel);
-	num_samples = num_bytes / sizeof(short);
-
-	/* if we only need some of the points */
-	if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_samples)
-		num_samples = devpriv->count;
-
-	munge_data(dev, buffer, num_samples);
-	cfc_write_array_to_buffer(s, buffer, num_bytes);
-	if (s->async->cmd.stop_src == TRIG_COUNT)
-		devpriv->count -= num_samples;
-
-	return;
-}
-
-/* flushes remaining data from board when external trigger has stopped acquisition
- * and we are using dma transfers */
-static void das1800_flush_dma(struct comedi_device *dev,
-			      struct comedi_subdevice *s)
-{
-	unsigned long flags;
-	const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
 
-	flags = claim_dma_lock();
-	das1800_flush_dma_channel(dev, s, devpriv->dma_current,
-				  devpriv->dma_current_buf);
+	/* Prevent race with das1800_ai_poll() on multi processor systems.
+	 * Also protects indirect addressing in das1800_ai_handler */
+	spin_lock(&dev->spinlock);
+	status = inb(dev->iobase + DAS1800_STATUS);
 
-	if (dual_dma) {
-		/*  switch to other channel and flush it */
-		if (devpriv->dma_current == devpriv->dma0) {
-			devpriv->dma_current = devpriv->dma1;
-			devpriv->dma_current_buf = devpriv->ai_buf1;
-		} else {
-			devpriv->dma_current = devpriv->dma0;
-			devpriv->dma_current_buf = devpriv->ai_buf0;
-		}
-		das1800_flush_dma_channel(dev, s, devpriv->dma_current,
-					  devpriv->dma_current_buf);
+	/* if interrupt was not caused by das-1800 */
+	if (!(status & INT)) {
+		spin_unlock(&dev->spinlock);
+		return IRQ_NONE;
 	}
+	/* clear the interrupt status bit INT */
+	outb(CLEAR_INTR_MASK & ~INT, dev->iobase + DAS1800_STATUS);
+	/*  handle interrupt */
+	das1800_ai_handler(dev);
 
-	release_dma_lock(flags);
-
-	/*  get any remaining samples in fifo */
-	das1800_handle_fifo_not_empty(dev, s);
-
-	return;
-}
-
-static void das1800_handle_fifo_half_full(struct comedi_device *dev,
-					  struct comedi_subdevice *s)
-{
-	int numPoints = 0;	/* number of points to read */
-	struct comedi_cmd *cmd = &s->async->cmd;
-
-	numPoints = FIFO_SIZE / 2;
-	/* if we only need some of the points */
-	if (cmd->stop_src == TRIG_COUNT && devpriv->count < numPoints)
-		numPoints = devpriv->count;
-	insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, numPoints);
-	munge_data(dev, devpriv->ai_buf0, numPoints);
-	cfc_write_array_to_buffer(s, devpriv->ai_buf0,
-				  numPoints * sizeof(devpriv->ai_buf0[0]));
-	if (cmd->stop_src == TRIG_COUNT)
-		devpriv->count -= numPoints;
-	return;
+	spin_unlock(&dev->spinlock);
+	return IRQ_HANDLED;
 }
 
-static void das1800_handle_fifo_not_empty(struct comedi_device *dev,
-					  struct comedi_subdevice *s)
+/* converts requested conversion timing to timing compatible with
+ * hardware, used only when card is in 'burst mode'
+ */
+static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode)
 {
-	short dpnt;
-	int unipolar;
-	struct comedi_cmd *cmd = &s->async->cmd;
+	unsigned int micro_sec;
 
-	unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
+	/*  in burst mode, the maximum conversion time is 64 microseconds */
+	if (convert_arg > 64000)
+		convert_arg = 64000;
 
-	while (inb(dev->iobase + DAS1800_STATUS) & FNE) {
-		if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0)
-			break;
-		dpnt = inw(dev->iobase + DAS1800_FIFO);
-		/* convert to unsigned type if we are in a bipolar mode */
-		if (!unipolar)
-			;
-		dpnt = munge_bipolar_sample(dev, dpnt);
-		cfc_write_to_buffer(s, dpnt);
-		if (cmd->stop_src == TRIG_COUNT)
-			devpriv->count--;
+	/*  the conversion time must be an integral number of microseconds */
+	switch (round_mode) {
+	case TRIG_ROUND_NEAREST:
+	default:
+		micro_sec = (convert_arg + 500) / 1000;
+		break;
+	case TRIG_ROUND_DOWN:
+		micro_sec = convert_arg / 1000;
+		break;
+	case TRIG_ROUND_UP:
+		micro_sec = (convert_arg - 1) / 1000 + 1;
+		break;
 	}
 
-	return;
-}
-
-static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
-{
-	outb(0x0, dev->iobase + DAS1800_STATUS);	/* disable conversions */
-	outb(0x0, dev->iobase + DAS1800_CONTROL_B);	/* disable interrupts and dma */
-	outb(0x0, dev->iobase + DAS1800_CONTROL_A);	/* disable and clear fifo and stop triggering */
-	if (devpriv->dma0)
-		disable_dma(devpriv->dma0);
-	if (devpriv->dma1)
-		disable_dma(devpriv->dma1);
-	return 0;
+	/*  return number of nanoseconds */
+	return micro_sec * 1000;
 }
 
 /* test analog input cmd */
@@ -1322,10 +957,6 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev,
 	return 0;
 }
 
-/* analog input cmd interface */
-
-/* first, some utility functions used in the main ai_do_cmd() */
-
 /* returns appropriate bits for control register a, depending on command */
 static int control_a_bits(struct comedi_cmd cmd)
 {
@@ -1396,6 +1027,25 @@ static int control_c_bits(struct comedi_cmd cmd)
 	return control_c;
 }
 
+/* loads counters with divisor1, divisor2 from private structure */
+static int das1800_set_frequency(struct comedi_device *dev)
+{
+	int err = 0;
+
+	/*  counter 1, mode 2 */
+	if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 1, devpriv->divisor1,
+		       2))
+		err++;
+	/*  counter 2, mode 2 */
+	if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 2, devpriv->divisor2,
+		       2))
+		err++;
+	if (err)
+		return -1;
+
+	return 0;
+}
+
 /* sets up counters */
 static int setup_counters(struct comedi_device *dev, struct comedi_cmd cmd)
 {
@@ -1436,6 +1086,44 @@ static int setup_counters(struct comedi_device *dev, struct comedi_cmd cmd)
 	return 0;
 }
 
+/* utility function that suggests a dma transfer size based on the conversion period 'ns' */
+static unsigned int suggest_transfer_size(struct comedi_cmd *cmd)
+{
+	unsigned int size = DMA_BUF_SIZE;
+	static const int sample_size = 2;	/*  size in bytes of one sample from board */
+	unsigned int fill_time = 300000000;	/*  target time in nanoseconds for filling dma buffer */
+	unsigned int max_size;	/*  maximum size we will allow for a transfer */
+
+	/*  make dma buffer fill in 0.3 seconds for timed modes */
+	switch (cmd->scan_begin_src) {
+	case TRIG_FOLLOW:	/*  not in burst mode */
+		if (cmd->convert_src == TRIG_TIMER)
+			size = (fill_time / cmd->convert_arg) * sample_size;
+		break;
+	case TRIG_TIMER:
+		size = (fill_time / (cmd->scan_begin_arg * cmd->chanlist_len)) *
+		    sample_size;
+		break;
+	default:
+		size = DMA_BUF_SIZE;
+		break;
+	}
+
+	/*  set a minimum and maximum size allowed */
+	max_size = DMA_BUF_SIZE;
+	/*  if we are taking limited number of conversions, limit transfer size to that */
+	if (cmd->stop_src == TRIG_COUNT &&
+	    cmd->stop_arg * cmd->chanlist_len * sample_size < max_size)
+		max_size = cmd->stop_arg * cmd->chanlist_len * sample_size;
+
+	if (size > max_size)
+		size = max_size;
+	if (size < sample_size)
+		size = sample_size;
+
+	return size;
+}
+
 /* sets up dma */
 static void setup_dma(struct comedi_device *dev, struct comedi_cmd cmd)
 {
@@ -1665,7 +1353,7 @@ static int das1800_di_rbits(struct comedi_device *dev,
 	data[1] = inb(dev->iobase + DAS1800_DIGITAL) & 0xf;
 	data[0] = 0;
 
-	return 2;
+	return insn->n;
 }
 
 /* writes to digital output channels */
@@ -1686,94 +1374,365 @@ static int das1800_do_wbits(struct comedi_device *dev,
 
 	data[1] = devpriv->do_bits;
 
-	return 2;
+	return insn->n;
 }
 
-/* loads counters with divisor1, divisor2 from private structure */
-static int das1800_set_frequency(struct comedi_device *dev)
+static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
+			    unsigned int dma1)
 {
-	int err = 0;
-
-	/*  counter 1, mode 2 */
-	if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 1, devpriv->divisor1,
-		       2))
-		err++;
-	/*  counter 2, mode 2 */
-	if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 2, devpriv->divisor2,
-		       2))
-		err++;
-	if (err)
-		return -1;
+	unsigned long flags;
 
+	/*  need an irq to do dma */
+	if (dev->irq && dma0) {
+		/* encode dma0 and dma1 into 2 digit hexadecimal for switch */
+		switch ((dma0 & 0x7) | (dma1 << 4)) {
+		case 0x5:	/*  dma0 == 5 */
+			devpriv->dma_bits |= DMA_CH5;
+			break;
+		case 0x6:	/*  dma0 == 6 */
+			devpriv->dma_bits |= DMA_CH6;
+			break;
+		case 0x7:	/*  dma0 == 7 */
+			devpriv->dma_bits |= DMA_CH7;
+			break;
+		case 0x65:	/*  dma0 == 5, dma1 == 6 */
+			devpriv->dma_bits |= DMA_CH5_CH6;
+			break;
+		case 0x76:	/*  dma0 == 6, dma1 == 7 */
+			devpriv->dma_bits |= DMA_CH6_CH7;
+			break;
+		case 0x57:	/*  dma0 == 7, dma1 == 5 */
+			devpriv->dma_bits |= DMA_CH7_CH5;
+			break;
+		default:
+			dev_err(dev->class_dev,
+				"only supports dma channels 5 through 7\n");
+			dev_err(dev->class_dev,
+				"Dual dma only allows the following combinations:\n");
+			dev_err(dev->class_dev,
+				"dma 5,6 / 6,7 / or 7,5\n");
+			return -EINVAL;
+			break;
+		}
+		if (request_dma(dma0, dev->driver->driver_name)) {
+			dev_err(dev->class_dev,
+				"failed to allocate dma channel %i\n", dma0);
+			return -EINVAL;
+		}
+		devpriv->dma0 = dma0;
+		devpriv->dma_current = dma0;
+		if (dma1) {
+			if (request_dma(dma1, dev->driver->driver_name)) {
+				dev_err(dev->class_dev,
+					"failed to allocate dma channel %i\n",
+					dma1);
+				return -EINVAL;
+			}
+			devpriv->dma1 = dma1;
+		}
+		devpriv->ai_buf0 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
+		if (devpriv->ai_buf0 == NULL)
+			return -ENOMEM;
+		devpriv->dma_current_buf = devpriv->ai_buf0;
+		if (dma1) {
+			devpriv->ai_buf1 =
+			    kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
+			if (devpriv->ai_buf1 == NULL)
+				return -ENOMEM;
+		}
+		flags = claim_dma_lock();
+		disable_dma(devpriv->dma0);
+		set_dma_mode(devpriv->dma0, DMA_MODE_READ);
+		if (dma1) {
+			disable_dma(devpriv->dma1);
+			set_dma_mode(devpriv->dma1, DMA_MODE_READ);
+		}
+		release_dma_lock(flags);
+	}
 	return 0;
 }
 
-/* converts requested conversion timing to timing compatible with
- * hardware, used only when card is in 'burst mode'
- */
-static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode)
+static int das1800_probe(struct comedi_device *dev)
 {
-	unsigned int micro_sec;
+	int id;
+	int board;
 
-	/*  in burst mode, the maximum conversion time is 64 microseconds */
-	if (convert_arg > 64000)
-		convert_arg = 64000;
+	id = (inb(dev->iobase + DAS1800_DIGITAL) >> 4) & 0xf;	/* get id bits */
+	board = ((struct das1800_board *)dev->board_ptr) - das1800_boards;
 
-	/*  the conversion time must be an integral number of microseconds */
-	switch (round_mode) {
-	case TRIG_ROUND_NEAREST:
-	default:
-		micro_sec = (convert_arg + 500) / 1000;
+	switch (id) {
+	case 0x3:
+		if (board == das1801st_da || board == das1802st_da ||
+		    board == das1701st_da || board == das1702st_da) {
+			dev_dbg(dev->class_dev, "Board model: %s\n",
+				das1800_boards[board].name);
+			return board;
+		}
+		printk
+		    (" Board model (probed, not recommended): das-1800st-da series\n");
+		return das1801st;
 		break;
-	case TRIG_ROUND_DOWN:
-		micro_sec = convert_arg / 1000;
+	case 0x4:
+		if (board == das1802hr_da || board == das1702hr_da) {
+			dev_dbg(dev->class_dev, "Board model: %s\n",
+				das1800_boards[board].name);
+			return board;
+		}
+		printk
+		    (" Board model (probed, not recommended): das-1802hr-da\n");
+		return das1802hr;
 		break;
-	case TRIG_ROUND_UP:
-		micro_sec = (convert_arg - 1) / 1000 + 1;
+	case 0x5:
+		if (board == das1801ao || board == das1802ao ||
+		    board == das1701ao || board == das1702ao) {
+			dev_dbg(dev->class_dev, "Board model: %s\n",
+				das1800_boards[board].name);
+			return board;
+		}
+		printk
+		    (" Board model (probed, not recommended): das-1800ao series\n");
+		return das1801ao;
+		break;
+	case 0x6:
+		if (board == das1802hr || board == das1702hr) {
+			dev_dbg(dev->class_dev, "Board model: %s\n",
+				das1800_boards[board].name);
+			return board;
+		}
+		printk
+		    (" Board model (probed, not recommended): das-1802hr\n");
+		return das1802hr;
+		break;
+	case 0x7:
+		if (board == das1801st || board == das1802st ||
+		    board == das1701st || board == das1702st) {
+			dev_dbg(dev->class_dev, "Board model: %s\n",
+				das1800_boards[board].name);
+			return board;
+		}
+		printk
+		    (" Board model (probed, not recommended): das-1800st series\n");
+		return das1801st;
+		break;
+	case 0x8:
+		if (board == das1801hc || board == das1802hc) {
+			dev_dbg(dev->class_dev, "Board model: %s\n",
+				das1800_boards[board].name);
+			return board;
+		}
+		printk
+		    (" Board model (probed, not recommended): das-1800hc series\n");
+		return das1801hc;
+		break;
+	default:
+		printk
+		    (" Board model: probe returned 0x%x (unknown, please report)\n",
+		     id);
+		return board;
 		break;
 	}
-
-	/*  return number of nanoseconds */
-	return micro_sec * 1000;
+	return -1;
 }
 
-/* utility function that suggests a dma transfer size based on the conversion period 'ns' */
-static unsigned int suggest_transfer_size(struct comedi_cmd *cmd)
+static int das1800_attach(struct comedi_device *dev,
+			  struct comedi_devconfig *it)
 {
-	unsigned int size = DMA_BUF_SIZE;
-	static const int sample_size = 2;	/*  size in bytes of one sample from board */
-	unsigned int fill_time = 300000000;	/*  target time in nanoseconds for filling dma buffer */
-	unsigned int max_size;	/*  maximum size we will allow for a transfer */
+	struct comedi_subdevice *s;
+	unsigned long iobase = it->options[0];
+	unsigned int irq = it->options[1];
+	unsigned int dma0 = it->options[2];
+	unsigned int dma1 = it->options[3];
+	unsigned long iobase2;
+	int board;
+	int retval;
 
-	/*  make dma buffer fill in 0.3 seconds for timed modes */
-	switch (cmd->scan_begin_src) {
-	case TRIG_FOLLOW:	/*  not in burst mode */
-		if (cmd->convert_src == TRIG_TIMER)
-			size = (fill_time / cmd->convert_arg) * sample_size;
+	/* allocate and initialize dev->private */
+	if (alloc_private(dev, sizeof(struct das1800_private)) < 0)
+		return -ENOMEM;
+
+	printk(KERN_DEBUG "comedi%d: %s: io 0x%lx", dev->minor,
+	       dev->driver->driver_name, iobase);
+	if (irq) {
+		printk(KERN_CONT ", irq %u", irq);
+		if (dma0) {
+			printk(KERN_CONT ", dma %u", dma0);
+			if (dma1)
+				printk(KERN_CONT " and %u", dma1);
+		}
+	}
+	printk(KERN_CONT "\n");
+
+	if (iobase == 0) {
+		dev_err(dev->class_dev, "io base address required\n");
+		return -EINVAL;
+	}
+
+	/* check if io addresses are available */
+	if (!request_region(iobase, DAS1800_SIZE, dev->driver->driver_name)) {
+		printk
+		    (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
+		     iobase, iobase + DAS1800_SIZE - 1);
+		return -EIO;
+	}
+	dev->iobase = iobase;
+
+	board = das1800_probe(dev);
+	if (board < 0) {
+		dev_err(dev->class_dev, "unable to determine board type\n");
+		return -ENODEV;
+	}
+
+	dev->board_ptr = das1800_boards + board;
+	dev->board_name = thisboard->name;
+
+	/*  if it is an 'ao' board with fancy analog out then we need extra io ports */
+	if (thisboard->ao_ability == 2) {
+		iobase2 = iobase + IOBASE2;
+		if (!request_region(iobase2, DAS1800_SIZE,
+				    dev->driver->driver_name)) {
+			printk
+			    (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
+			     iobase2, iobase2 + DAS1800_SIZE - 1);
+			return -EIO;
+		}
+		devpriv->iobase2 = iobase2;
+	}
+
+	/* grab our IRQ */
+	if (irq) {
+		if (request_irq(irq, das1800_interrupt, 0,
+				dev->driver->driver_name, dev)) {
+			dev_dbg(dev->class_dev, "unable to allocate irq %u\n",
+				irq);
+			return -EINVAL;
+		}
+	}
+	dev->irq = irq;
+
+	/*  set bits that tell card which irq to use */
+	switch (irq) {
+	case 0:
 		break;
-	case TRIG_TIMER:
-		size = (fill_time / (cmd->scan_begin_arg * cmd->chanlist_len)) *
-		    sample_size;
+	case 3:
+		devpriv->irq_dma_bits |= 0x8;
+		break;
+	case 5:
+		devpriv->irq_dma_bits |= 0x10;
+		break;
+	case 7:
+		devpriv->irq_dma_bits |= 0x18;
+		break;
+	case 10:
+		devpriv->irq_dma_bits |= 0x28;
+		break;
+	case 11:
+		devpriv->irq_dma_bits |= 0x30;
+		break;
+	case 15:
+		devpriv->irq_dma_bits |= 0x38;
 		break;
 	default:
-		size = DMA_BUF_SIZE;
+		dev_err(dev->class_dev, "irq out of range\n");
+		return -EINVAL;
 		break;
 	}
 
-	/*  set a minimum and maximum size allowed */
-	max_size = DMA_BUF_SIZE;
-	/*  if we are taking limited number of conversions, limit transfer size to that */
-	if (cmd->stop_src == TRIG_COUNT &&
-	    cmd->stop_arg * cmd->chanlist_len * sample_size < max_size)
-		max_size = cmd->stop_arg * cmd->chanlist_len * sample_size;
+	retval = das1800_init_dma(dev, dma0, dma1);
+	if (retval < 0)
+		return retval;
 
-	if (size > max_size)
-		size = max_size;
-	if (size < sample_size)
-		size = sample_size;
+	if (devpriv->ai_buf0 == NULL) {
+		devpriv->ai_buf0 =
+		    kmalloc(FIFO_SIZE * sizeof(uint16_t), GFP_KERNEL);
+		if (devpriv->ai_buf0 == NULL)
+			return -ENOMEM;
+	}
 
-	return size;
-}
+	retval = comedi_alloc_subdevices(dev, 4);
+	if (retval)
+		return retval;
+
+	/* analog input subdevice */
+	s = dev->subdevices + 0;
+	dev->read_subdev = s;
+	s->type = COMEDI_SUBD_AI;
+	s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND | SDF_CMD_READ;
+	if (thisboard->common)
+		s->subdev_flags |= SDF_COMMON;
+	s->n_chan = thisboard->qram_len;
+	s->len_chanlist = thisboard->qram_len;
+	s->maxdata = (1 << thisboard->resolution) - 1;
+	s->range_table = thisboard->range_ai;
+	s->do_cmd = das1800_ai_do_cmd;
+	s->do_cmdtest = das1800_ai_do_cmdtest;
+	s->insn_read = das1800_ai_rinsn;
+	s->poll = das1800_ai_poll;
+	s->cancel = das1800_cancel;
+
+	/* analog out */
+	s = dev->subdevices + 1;
+	if (thisboard->ao_ability == 1) {
+		s->type = COMEDI_SUBD_AO;
+		s->subdev_flags = SDF_WRITABLE;
+		s->n_chan = thisboard->ao_n_chan;
+		s->maxdata = (1 << thisboard->resolution) - 1;
+		s->range_table = &range_ao_1;
+		s->insn_write = das1800_ao_winsn;
+	} else {
+		s->type = COMEDI_SUBD_UNUSED;
+	}
+
+	/* di */
+	s = dev->subdevices + 2;
+	s->type = COMEDI_SUBD_DI;
+	s->subdev_flags = SDF_READABLE;
+	s->n_chan = 4;
+	s->maxdata = 1;
+	s->range_table = &range_digital;
+	s->insn_bits = das1800_di_rbits;
+
+	/* do */
+	s = dev->subdevices + 3;
+	s->type = COMEDI_SUBD_DO;
+	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+	s->n_chan = thisboard->do_n_chan;
+	s->maxdata = 1;
+	s->range_table = &range_digital;
+	s->insn_bits = das1800_do_wbits;
+
+	das1800_cancel(dev, dev->read_subdev);
+
+	/*  initialize digital out channels */
+	outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL);
+
+	/*  initialize analog out channels */
+	if (thisboard->ao_ability == 1) {
+		/*  select 'update' dac channel for baseAddress + 0x0 */
+		outb(DAC(thisboard->ao_n_chan - 1),
+		     dev->iobase + DAS1800_SELECT);
+		outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC);
+	}
+
+	return 0;
+};
+
+static void das1800_detach(struct comedi_device *dev)
+{
+	if (dev->iobase)
+		release_region(dev->iobase, DAS1800_SIZE);
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (dev->private) {
+		if (devpriv->iobase2)
+			release_region(devpriv->iobase2, DAS1800_SIZE);
+		if (devpriv->dma0)
+			free_dma(devpriv->dma0);
+		if (devpriv->dma1)
+			free_dma(devpriv->dma1);
+		kfree(devpriv->ai_buf0);
+		kfree(devpriv->ai_buf1);
+	}
+};
 
 static struct comedi_driver das1800_driver = {
 	.driver_name	= "das1800",
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index 881f392..e3afcfa 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -155,7 +155,7 @@ static irqreturn_t intr_handler(int irq, void *d)
 	struct comedi_subdevice *s = dev->subdevices;
 
 	if (!dev->attached || devpriv->das6402_ignoreirq) {
-		dev_warn(dev->hw_dev, "BUG: spurious interrupt\n");
+		dev_warn(dev->class_dev, "BUG: spurious interrupt\n");
 		return IRQ_HANDLED;
 	}
 #ifdef DEBUG
@@ -202,7 +202,7 @@ static int das6402_ai_cancel(struct comedi_device *dev,
 	 */
 
 	devpriv->das6402_ignoreirq = 1;
-	dev_dbg(dev->hw_dev, "Stopping acquisition\n");
+	dev_dbg(dev->class_dev, "Stopping acquisition\n");
 	devpriv->das6402_ignoreirq = 1;
 	outb_p(0x02, dev->iobase + 10);	/* disable external trigging */
 	outw_p(SCANL, dev->iobase + 2);	/* resets the card fifo */
@@ -218,7 +218,7 @@ static int das6402_ai_mode2(struct comedi_device *dev,
 			    struct comedi_subdevice *s, comedi_trig * it)
 {
 	devpriv->das6402_ignoreirq = 1;
-	dev_dbg(dev->hw_dev, "Starting acquisition\n");
+	dev_dbg(dev->class_dev, "Starting acquisition\n");
 	outb_p(0x03, dev->iobase + 10);	/* enable external trigging */
 	outw_p(SCANL, dev->iobase + 2);	/* resets the card fifo */
 	outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
@@ -289,7 +289,7 @@ static int das6402_attach(struct comedi_device *dev,
 		iobase = 0x300;
 
 	if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
-		dev_err(dev->hw_dev, "I/O port conflict\n");
+		dev_err(dev->class_dev, "I/O port conflict\n");
 		return -EIO;
 	}
 	dev->iobase = iobase;
@@ -297,7 +297,7 @@ static int das6402_attach(struct comedi_device *dev,
 	/* should do a probe here */
 
 	irq = it->options[0];
-	dev_dbg(dev->hw_dev, "( irq = %u )\n", irq);
+	dev_dbg(dev->class_dev, "( irq = %u )\n", irq);
 	ret = request_irq(irq, intr_handler, 0, "das6402", dev);
 	if (ret < 0)
 		return ret;
@@ -307,8 +307,8 @@ static int das6402_attach(struct comedi_device *dev,
 	if (ret < 0)
 		return ret;
 
-	ret = alloc_subdevices(dev, 1);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
 		return ret;
 
 	/* ai subdevice */
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index a3a54e1..a0959a5 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -296,46 +296,47 @@ static int das800_probe(struct comedi_device *dev)
 	switch (id_bits) {
 	case 0x0:
 		if (board == das800) {
-			dev_dbg(dev->hw_dev, "Board model: DAS-800\n");
+			dev_dbg(dev->class_dev, "Board model: DAS-800\n");
 			return board;
 		}
 		if (board == ciodas800) {
-			dev_dbg(dev->hw_dev, "Board model: CIO-DAS800\n");
+			dev_dbg(dev->class_dev, "Board model: CIO-DAS800\n");
 			return board;
 		}
-		dev_dbg(dev->hw_dev, "Board model (probed): DAS-800\n");
+		dev_dbg(dev->class_dev, "Board model (probed): DAS-800\n");
 		return das800;
 		break;
 	case 0x2:
 		if (board == das801) {
-			dev_dbg(dev->hw_dev, "Board model: DAS-801\n");
+			dev_dbg(dev->class_dev, "Board model: DAS-801\n");
 			return board;
 		}
 		if (board == ciodas801) {
-			dev_dbg(dev->hw_dev, "Board model: CIO-DAS801\n");
+			dev_dbg(dev->class_dev, "Board model: CIO-DAS801\n");
 			return board;
 		}
-		dev_dbg(dev->hw_dev, "Board model (probed): DAS-801\n");
+		dev_dbg(dev->class_dev, "Board model (probed): DAS-801\n");
 		return das801;
 		break;
 	case 0x3:
 		if (board == das802) {
-			dev_dbg(dev->hw_dev, "Board model: DAS-802\n");
+			dev_dbg(dev->class_dev, "Board model: DAS-802\n");
 			return board;
 		}
 		if (board == ciodas802) {
-			dev_dbg(dev->hw_dev, "Board model: CIO-DAS802\n");
+			dev_dbg(dev->class_dev, "Board model: CIO-DAS802\n");
 			return board;
 		}
 		if (board == ciodas80216) {
-			dev_dbg(dev->hw_dev, "Board model: CIO-DAS802/16\n");
+			dev_dbg(dev->class_dev, "Board model: CIO-DAS802/16\n");
 			return board;
 		}
-		dev_dbg(dev->hw_dev, "Board model (probed): DAS-802\n");
+		dev_dbg(dev->class_dev, "Board model (probed): DAS-802\n");
 		return das802;
 		break;
 	default:
-		dev_dbg(dev->hw_dev, "Board model: probe returned 0x%x (unknown)\n",
+		dev_dbg(dev->class_dev,
+			"Board model: probe returned 0x%x (unknown)\n",
 			id_bits);
 		return board;
 		break;
@@ -450,7 +451,7 @@ static irqreturn_t das800_interrupt(int irq, void *d)
 		/* otherwise, stop taking data */
 	} else {
 		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
-		disable_das800(dev);	/* diable hardware triggered conversions */
+		disable_das800(dev);	/* disable hardware triggered conversions */
 		async->events |= COMEDI_CB_EOA;
 	}
 	comedi_event(dev, s);
@@ -465,43 +466,44 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	unsigned int irq = it->options[1];
 	unsigned long irq_flags;
 	int board;
+	int ret;
 
-	dev_info(dev->hw_dev, "comedi%d: das800: io 0x%lx\n", dev->minor,
-		 iobase);
+	dev_info(dev->class_dev, "das800: io 0x%lx\n", iobase);
 	if (irq)
-		dev_dbg(dev->hw_dev, "irq %u\n", irq);
+		dev_dbg(dev->class_dev, "irq %u\n", irq);
 
 	/* allocate and initialize dev->private */
 	if (alloc_private(dev, sizeof(struct das800_private)) < 0)
 		return -ENOMEM;
 
 	if (iobase == 0) {
-		dev_err(dev->hw_dev, "io base address required for das800\n");
+		dev_err(dev->class_dev,
+			"io base address required for das800\n");
 		return -EINVAL;
 	}
 
 	/* check if io addresses are available */
 	if (!request_region(iobase, DAS800_SIZE, "das800")) {
-		dev_err(dev->hw_dev, "I/O port conflict\n");
+		dev_err(dev->class_dev, "I/O port conflict\n");
 		return -EIO;
 	}
 	dev->iobase = iobase;
 
 	board = das800_probe(dev);
 	if (board < 0) {
-		dev_dbg(dev->hw_dev, "unable to determine board type\n");
+		dev_dbg(dev->class_dev, "unable to determine board type\n");
 		return -ENODEV;
 	}
 	dev->board_ptr = das800_boards + board;
 
 	/* grab our IRQ */
 	if (irq == 1 || irq > 7) {
-		dev_err(dev->hw_dev, "irq out of range\n");
+		dev_err(dev->class_dev, "irq out of range\n");
 		return -EINVAL;
 	}
 	if (irq) {
 		if (request_irq(irq, das800_interrupt, 0, "das800", dev)) {
-			dev_err(dev->hw_dev, "unable to allocate irq %u\n",
+			dev_err(dev->class_dev, "unable to allocate irq %u\n",
 				irq);
 			return -EINVAL;
 		}
@@ -510,8 +512,9 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	dev->board_name = thisboard->name;
 
-	if (alloc_subdevices(dev, 3) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
+		return ret;
 
 	/* analog input subdevice */
 	s = dev->subdevices + 0;
@@ -872,7 +875,7 @@ static int das800_di_rbits(struct comedi_device *dev,
 	data[1] = bits;
 	data[0] = 0;
 
-	return 2;
+	return insn->n;
 }
 
 static int das800_do_wbits(struct comedi_device *dev,
@@ -896,7 +899,7 @@ static int das800_do_wbits(struct comedi_device *dev,
 
 	data[1] = wbits;
 
-	return 2;
+	return insn->n;
 }
 
 /* loads counters with divisor1, divisor2 from private structure */
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index 8382890..af353167 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -189,11 +189,6 @@ static const struct dmm32at_board dmm32at_boards[] = {
 	 },
 };
 
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct dmm32at_board *)dev->board_ptr)
-
 /* this structure is for data unique to this hardware driver.  If
  * several hardware drivers keep similar information in this structure,
  * feel free to suggest moving the variable to the struct comedi_device struct.
@@ -290,6 +285,7 @@ void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec);
 static int dmm32at_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
+	const struct dmm32at_board *board = comedi_board(dev);
 	int ret;
 	struct comedi_subdevice *s;
 	unsigned char aihi, ailo, fifostat, aistat, intstat, airback;
@@ -304,7 +300,7 @@ static int dmm32at_attach(struct comedi_device *dev,
 	       iobase, irq);
 
 	/* register address space */
-	if (!request_region(iobase, DMM32AT_MEMSIZE, thisboard->name)) {
+	if (!request_region(iobase, DMM32AT_MEMSIZE, board->name)) {
 		printk(KERN_ERR "comedi%d: dmm32at: I/O port conflict\n",
 		       dev->minor);
 		return -EIO;
@@ -358,7 +354,7 @@ static int dmm32at_attach(struct comedi_device *dev,
 
 	/* board is there, register interrupt */
 	if (irq) {
-		ret = request_irq(irq, dmm32at_isr, 0, thisboard->name, dev);
+		ret = request_irq(irq, dmm32at_isr, 0, board->name, dev);
 		if (ret < 0) {
 			printk(KERN_ERR "dmm32at: irq conflict\n");
 			return ret;
@@ -366,18 +362,7 @@ static int dmm32at_attach(struct comedi_device *dev,
 		dev->irq = irq;
 	}
 
-/*
- * If you can probe the device to determine what device in a series
- * it is, this is the place to do it.  Otherwise, dev->board_ptr
- * should already be initialized.
- */
-	/* dev->board_ptr = dmm32at_probe(dev); */
-
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 /*
  * Allocate the private structure area.  alloc_private() is a
@@ -386,12 +371,9 @@ static int dmm32at_attach(struct comedi_device *dev,
 	if (alloc_private(dev, sizeof(struct dmm32at_private)) < 0)
 		return -ENOMEM;
 
-/*
- * Allocate the subdevice structures.  alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_subdevices(dev, 3) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	dev->read_subdev = s;
@@ -399,9 +381,9 @@ static int dmm32at_attach(struct comedi_device *dev,
 	s->type = COMEDI_SUBD_AI;
 	/* we support single-ended (ground) and differential */
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
-	s->n_chan = thisboard->ai_chans;
-	s->maxdata = (1 << thisboard->ai_bits) - 1;
-	s->range_table = thisboard->ai_ranges;
+	s->n_chan = board->ai_chans;
+	s->maxdata = (1 << board->ai_bits) - 1;
+	s->range_table = board->ai_ranges;
 	s->len_chanlist = 32;	/* This is the maximum chanlist length that
 				   the board can handle */
 	s->insn_read = dmm32at_ai_rinsn;
@@ -413,15 +395,15 @@ static int dmm32at_attach(struct comedi_device *dev,
 	/* analog output subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = thisboard->ao_chans;
-	s->maxdata = (1 << thisboard->ao_bits) - 1;
-	s->range_table = thisboard->ao_ranges;
+	s->n_chan = board->ao_chans;
+	s->maxdata = (1 << board->ao_bits) - 1;
+	s->range_table = board->ao_ranges;
 	s->insn_write = dmm32at_ao_winsn;
 	s->insn_read = dmm32at_ao_rinsn;
 
 	s = dev->subdevices + 2;
 	/* digital i/o subdevice */
-	if (thisboard->have_dio) {
+	if (board->have_dio) {
 
 		/* get access to the DIO regs */
 		dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC);
@@ -433,7 +415,7 @@ static int dmm32at_attach(struct comedi_device *dev,
 		/* set up the subdevice */
 		s->type = COMEDI_SUBD_DIO;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->n_chan = thisboard->dio_chans;
+		s->n_chan = board->dio_chans;
 		s->maxdata = 1;
 		s->state = 0;
 		s->range_table = &range_digital;
@@ -932,9 +914,6 @@ static int dmm32at_dio_insn_bits(struct comedi_device *dev,
 {
 	unsigned char diobits;
 
-	if (insn->n != 2)
-		return -EINVAL;
-
 	/* The insn data is a mask in data[0] and the new data
 	 * in data[1], each channel cooresponding to a bit. */
 	if (data[0]) {
@@ -977,7 +956,7 @@ static int dmm32at_dio_insn_bits(struct comedi_device *dev,
 	 * it was a purely digital output subdevice */
 	/* data[1]=s->state; */
 
-	return 2;
+	return insn->n;
 }
 
 static int dmm32at_dio_insn_config(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index 625bd61..d332269 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -535,8 +535,6 @@ static int dt2801_dio_insn_bits(struct comedi_device *dev,
 	if (s == dev->subdevices + 4)
 		which = 1;
 
-	if (insn->n != 2)
-		return -EINVAL;
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] & data[1]);
@@ -548,7 +546,7 @@ static int dt2801_dio_insn_bits(struct comedi_device *dev,
 	dt2801_writedata(dev, which);
 	dt2801_readdata(dev, data + 1);
 
-	return 2;
+	return insn->n;
 }
 
 static int dt2801_dio_insn_config(struct comedi_device *dev,
@@ -626,15 +624,15 @@ havetype:
 	printk("dt2801: %s at port 0x%lx", boardtype.name, iobase);
 
 	n_ai_chans = probe_number_of_ai_chans(dev);
-	printk(" (ai channels = %d)", n_ai_chans);
+	printk(" (ai channels = %d)\n", n_ai_chans);
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		goto out;
 
 	ret = alloc_private(dev, sizeof(struct dt2801_private));
 	if (ret < 0)
-		goto out;
+		return ret;
 
 	dev->board_name = boardtype.name;
 
@@ -688,8 +686,6 @@ havetype:
 
 	ret = 0;
 out:
-	printk("\n");
-
 	return ret;
 }
 
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index 106ffea..290b933 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -211,8 +211,6 @@ struct dt2811_board {
 	const struct comedi_lrange *unip_5;
 };
 
-#define this_board ((const struct dt2811_board *)dev->board_ptr)
-
 enum { card_2811_pgh, card_2811_pgl };
 
 struct dt2811_private {
@@ -354,28 +352,22 @@ static int dt2811_di_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = inb(dev->iobase + DT2811_DIO);
 
-	return 2;
+	return insn->n;
 }
 
 static int dt2811_do_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	s->state &= ~data[0];
 	s->state |= data[0] & data[1];
 	outb(s->state, dev->iobase + DT2811_DIO);
 
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -404,6 +396,7 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	/* unsigned long irqs; */
 	/* long flags; */
 
+	const struct dt2811_board *board = comedi_board(dev);
 	int ret;
 	struct comedi_subdevice *s;
 	unsigned long iobase;
@@ -418,7 +411,7 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	}
 
 	dev->iobase = iobase;
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 
 #if 0
 	outb(0, dev->iobase + DT2811_ADCSR);
@@ -466,8 +459,8 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	}
 #endif
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		return ret;
 
 	ret = alloc_private(dev, sizeof(struct dt2811_private));
@@ -527,13 +520,13 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	switch (it->options[3]) {
 	case 0:
 	default:
-		s->range_table = this_board->bip_5;
+		s->range_table = board->bip_5;
 		break;
 	case 1:
-		s->range_table = this_board->bip_2_5;
+		s->range_table = board->bip_2_5;
 		break;
 	case 2:
-		s->range_table = this_board->unip_5;
+		s->range_table = board->unip_5;
 		break;
 	}
 
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index fa4ade6..2e39ebe 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -338,8 +338,8 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 #endif
 	}
 
-	ret = alloc_subdevices(dev, 1);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
 		return ret;
 
 	ret = alloc_private(dev, sizeof(struct dt2814_private));
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index bbab712..45b20be 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -166,6 +166,7 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	int i;
 	const struct comedi_lrange *current_range_type, *voltage_range_type;
 	unsigned long iobase;
+	int ret;
 
 	iobase = it->options[0];
 	printk(KERN_INFO "comedi%d: dt2815: 0x%04lx ", dev->minor, iobase);
@@ -177,8 +178,10 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	dev->iobase = iobase;
 	dev->board_name = "dt2815";
 
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
+
 	if (alloc_private(dev, sizeof(struct dt2815_private)) < 0)
 		return -ENOMEM;
 
diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c
index 1ee10e7b..beba044 100644
--- a/drivers/staging/comedi/drivers/dt2817.c
+++ b/drivers/staging/comedi/drivers/dt2817.c
@@ -119,7 +119,7 @@ static int dt2817_dio_insn_bits(struct comedi_device *dev,
 	data[1] |= (inb(dev->iobase + DT2817_DATA + 2) << 16);
 	data[1] |= (inb(dev->iobase + DT2817_DATA + 3) << 24);
 
-	return 2;
+	return insn->n;
 }
 
 static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -137,8 +137,8 @@ static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	dev->iobase = iobase;
 	dev->board_name = "dt2817";
 
-	ret = alloc_subdevices(dev, 1);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 736d8fa..4af3343 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -221,8 +221,6 @@ struct dt282x_board {
 	int dabits;
 };
 
-#define this_board ((const struct dt282x_board *)dev->board_ptr)
-
 struct dt282x_private {
 	int ad_2scomp;		/* we have 2's comp jumper set  */
 	int da0_2scomp;		/* same, for DAC0               */
@@ -580,6 +578,7 @@ static int dt282x_ai_insn_read(struct comedi_device *dev,
 static int dt282x_ai_cmdtest(struct comedi_device *dev,
 			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
+	const struct dt282x_board *board = comedi_board(dev);
 	int err = 0;
 	int tmp;
 
@@ -658,8 +657,8 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev,
 		cmd->convert_arg = SLOWEST_TIMER;
 		err++;
 	}
-	if (cmd->convert_arg < this_board->ai_speed) {
-		cmd->convert_arg = this_board->ai_speed;
+	if (cmd->convert_arg < board->ai_speed) {
+		cmd->convert_arg = board->ai_speed;
 		err++;
 	}
 	if (cmd->scan_end_arg != cmd->chanlist_len) {
@@ -694,6 +693,7 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev,
 
 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	const struct dt282x_board *board = comedi_board(dev);
 	struct comedi_cmd *cmd = &s->async->cmd;
 	int timer;
 
@@ -706,8 +706,8 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 
 	dt282x_disable_dma(dev);
 
-	if (cmd->convert_arg < this_board->ai_speed)
-		cmd->convert_arg = this_board->ai_speed;
+	if (cmd->convert_arg < board->ai_speed)
+		cmd->convert_arg = board->ai_speed;
 	timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
 	outw(timer, dev->iobase + DT2821_TMRCTR);
 
@@ -1038,7 +1038,7 @@ static int dt282x_dio_insn_bits(struct comedi_device *dev,
 	}
 	data[1] = inw(dev->iobase + DT2821_DIODAT);
 
-	return 2;
+	return insn->n;
 }
 
 static int dt282x_dio_insn_config(struct comedi_device *dev,
@@ -1176,12 +1176,13 @@ static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
  */
 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct dt282x_board *board = comedi_board(dev);
 	int i, irq;
 	int ret;
 	struct comedi_subdevice *s;
 	unsigned long iobase;
 
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 
 	iobase = it->options[opt_iobase];
 	if (!iobase)
@@ -1267,8 +1268,8 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	if (ret < 0)
 		return ret;
 
-	ret = alloc_subdevices(dev, 3);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 0d27326..d1d99a3 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -63,8 +63,6 @@ AO commands are not supported.
 #include "../comedidev.h"
 #include <linux/delay.h>
 
-#include "comedi_pci.h"
-
 #define PCI_VENDOR_ID_DT	0x1116
 
 static const struct comedi_lrange range_dt3000_ai = { 4, {
@@ -254,7 +252,7 @@ struct dt3k_private {
 
 	struct pci_dev *pci_dev;
 	resource_size_t phys_addr;
-	void *io_addr;
+	void __iomem *io_addr;
 	unsigned int lock;
 	unsigned int ao_readback[2];
 	unsigned int ai_front;
@@ -291,7 +289,7 @@ static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
 	if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR)
 		return 0;
 
-	dev_dbg(dev->hw_dev, "dt3k_send_cmd() timeout/error status=0x%04x\n",
+	dev_dbg(dev->class_dev, "dt3k_send_cmd() timeout/error status=0x%04x\n",
 		status);
 
 	return -ETIME;
@@ -392,7 +390,7 @@ static void dt3k_ai_empty_fifo(struct comedi_device *dev,
 	if (count < 0)
 		count += AI_FIFO_DEPTH;
 
-	dev_dbg(dev->hw_dev, "reading %d samples\n", count);
+	dev_dbg(dev->class_dev, "reading %d samples\n", count);
 
 	rear = devpriv->ai_rear;
 
@@ -580,7 +578,7 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 	int ret;
 	unsigned int mode;
 
-	dev_dbg(dev->hw_dev, "dt3k_ai_cmd:\n");
+	dev_dbg(dev->class_dev, "dt3k_ai_cmd:\n");
 	for (i = 0; i < cmd->chanlist_len; i++) {
 		chan = CR_CHAN(cmd->chanlist[i]);
 		range = CR_RANGE(cmd->chanlist[i]);
@@ -591,15 +589,15 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 	aref = CR_AREF(cmd->chanlist[0]);
 
 	writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
-	dev_dbg(dev->hw_dev, "param[0]=0x%04x\n", cmd->scan_end_arg);
+	dev_dbg(dev->class_dev, "param[0]=0x%04x\n", cmd->scan_end_arg);
 
 	if (cmd->convert_src == TRIG_TIMER) {
 		divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
 					   cmd->flags & TRIG_ROUND_MASK);
 		writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
-		dev_dbg(dev->hw_dev, "param[1]=0x%04x\n", divider >> 16);
+		dev_dbg(dev->class_dev, "param[1]=0x%04x\n", divider >> 16);
 		writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
-		dev_dbg(dev->hw_dev, "param[2]=0x%04x\n", divider & 0xffff);
+		dev_dbg(dev->class_dev, "param[2]=0x%04x\n", divider & 0xffff);
 	} else {
 		/* not supported */
 	}
@@ -608,21 +606,21 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 		tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
 					    cmd->flags & TRIG_ROUND_MASK);
 		writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
-		dev_dbg(dev->hw_dev, "param[3]=0x%04x\n", tscandiv >> 16);
+		dev_dbg(dev->class_dev, "param[3]=0x%04x\n", tscandiv >> 16);
 		writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
-		dev_dbg(dev->hw_dev, "param[4]=0x%04x\n", tscandiv & 0xffff);
+		dev_dbg(dev->class_dev, "param[4]=0x%04x\n", tscandiv & 0xffff);
 	} else {
 		/* not supported */
 	}
 
 	mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
 	writew(mode, devpriv->io_addr + DPR_Params(5));
-	dev_dbg(dev->hw_dev, "param[5]=0x%04x\n", mode);
+	dev_dbg(dev->class_dev, "param[5]=0x%04x\n", mode);
 	writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
-	dev_dbg(dev->hw_dev, "param[6]=0x%04x\n", aref == AREF_DIFF);
+	dev_dbg(dev->class_dev, "param[6]=0x%04x\n", aref == AREF_DIFF);
 
 	writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
-	dev_dbg(dev->hw_dev, "param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
+	dev_dbg(dev->class_dev, "param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
 
 	writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
 	ret = dt3k_send_cmd(dev, CMD_CONFIG);
@@ -747,9 +745,6 @@ static int dt3k_dio_insn_bits(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= data[1] & data[0];
@@ -757,7 +752,7 @@ static int dt3k_dio_insn_bits(struct comedi_device *dev,
 	}
 	data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
 
-	return 2;
+	return insn->n;
 }
 
 static int dt3k_mem_insn_read(struct comedi_device *dev,
@@ -858,7 +853,7 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	int bus, slot;
 	int ret = 0;
 
-	dev_dbg(dev->hw_dev, "dt3000:\n");
+	dev_dbg(dev->class_dev, "dt3000:\n");
 	bus = it->options[0];
 	slot = it->options[1];
 
@@ -870,7 +865,7 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	if (ret < 0)
 		return ret;
 	if (ret == 0) {
-		dev_warn(dev->hw_dev, "no DT board found\n");
+		dev_warn(dev->class_dev, "no DT board found\n");
 		return -ENODEV;
 	}
 
@@ -878,14 +873,14 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
 			"dt3000", dev)) {
-		dev_err(dev->hw_dev, "unable to allocate IRQ %u\n",
+		dev_err(dev->class_dev, "unable to allocate IRQ %u\n",
 			devpriv->pci_dev->irq);
 		return -EINVAL;
 	}
 	dev->irq = devpriv->pci_dev->irq;
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices;
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 22cda5c..40821c7 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -1021,6 +1021,7 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	int i;
 	struct comedi_subdevice *s;
+	int ret;
 
 	dev->board_name = "dt9812";
 
@@ -1035,9 +1036,9 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	devpriv->serial = it->options[0];
 
-	/* Allocate subdevices */
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
+		return ret;
 
 	/* digital input subdevice */
 	s = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index b0cec7b..d0e3679 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -38,7 +38,6 @@
 */
 
 #include "../comedidev.h"
-#include "comedi_pci.h"
 #include <linux/mutex.h>
 
 #define PCI_VENDOR_ID_DYNALOG		0x10b5
@@ -142,7 +141,7 @@ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev,
 		for (counter = 0; counter < READ_TIMEOUT; counter++) {
 			d = inw_p(devpriv->BADR2);
 
-			/* check if read is successfull if the EOC bit is set */
+			/* check if read is successful if the EOC bit is set */
 			if (d & (1 << 15))
 				goto conv_finish;
 		}
@@ -190,9 +189,6 @@ static int dyna_pci10xx_di_insn_bits(struct comedi_device *dev,
 {
 	u16 d = 0;
 
-	if (insn->n != 2)
-		return -EINVAL;
-
 	mutex_lock(&devpriv->mutex);
 	smp_mb();
 	d = inw_p(devpriv->BADR3);
@@ -202,7 +198,7 @@ static int dyna_pci10xx_di_insn_bits(struct comedi_device *dev,
 	data[1] = d;
 	data[0] = s->state;
 	mutex_unlock(&devpriv->mutex);
-	return 2;
+	return insn->n;
 }
 
 /* digital output bit interface */
@@ -210,9 +206,6 @@ static int dyna_pci10xx_do_insn_bits(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	/* The insn data is a mask in data[0] and the new data
 	 * in data[1], each channel cooresponding to a bit.
 	 * s->state contains the previous write data
@@ -233,7 +226,7 @@ static int dyna_pci10xx_do_insn_bits(struct comedi_device *dev,
 	 */
 	data[1] = s->state;
 	mutex_unlock(&devpriv->mutex);
-	return 2;
+	return insn->n;
 }
 
 /******************************************************************************/
@@ -247,6 +240,7 @@ static int dyna_pci10xx_attach(struct comedi_device *dev,
 	struct pci_dev *pcidev;
 	unsigned int opt_bus, opt_slot;
 	int board_index, i;
+	int ret;
 
 	mutex_lock(&start_stop_sem);
 
@@ -330,11 +324,10 @@ found:
 	devpriv->BADR4 = pci_resource_start(pcidev, 4);
 	devpriv->BADR5 = pci_resource_start(pcidev, 5);
 
-	if (alloc_subdevices(dev, 4) < 0) {
-		printk(KERN_ERR "comedi: dyna_pci10xx: "
-			"failed allocating subdevices\n");
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret) {
 		mutex_unlock(&start_stop_sem);
-		return -ENOMEM;
+		return ret;
 	}
 
 	/* analog input */
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index d2381445..d1da809 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -111,6 +111,7 @@ static int fl512_ao_insn_readback(struct comedi_device *dev,
 static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	unsigned long iobase;
+	int ret;
 
 	/* pointer to the subdevice: Analog in, Analog out,
 	   (not made ->and Digital IO) */
@@ -131,8 +132,9 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	printk(KERN_DEBUG "malloc ok\n");
 #endif
 
-	if (alloc_subdevices(dev, 2) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 2);
+	if (ret)
+		return ret;
 
 	/*
 	 * this if the definitions of the supdevices, 2 have been defined
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index 8aece08..79f5808 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -49,7 +49,6 @@ support could be added to this driver.
 #include "../comedidev.h"
 #include <linux/delay.h>
 
-#include "comedi_pci.h"
 #include "plx9080.h"
 #include "comedi_fc.h"
 
@@ -297,8 +296,8 @@ struct hpdi_private {
 	resource_size_t plx9080_phys_iobase;
 	resource_size_t hpdi_phys_iobase;
 	/*  base addresses (ioremapped) */
-	void *plx9080_iobase;
-	void *hpdi_iobase;
+	void __iomem *plx9080_iobase;
+	void __iomem *hpdi_iobase;
 	uint32_t *dio_buffer[NUM_DMA_BUFFERS];	/*  dma buffers */
 	/* physical addresses of dma buffers */
 	dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS];
@@ -364,7 +363,7 @@ static void disable_plx_interrupts(struct comedi_device *dev)
 static void init_plx9080(struct comedi_device *dev)
 {
 	uint32_t bits;
-	void *plx_iobase = priv(dev)->plx9080_iobase;
+	void __iomem *plx_iobase = priv(dev)->plx9080_iobase;
 
 	/*  plx9080 dump */
 	DEBUG_PRINT(" plx interrupt status 0x%x\n",
@@ -431,9 +430,11 @@ static void init_plx9080(struct comedi_device *dev)
 static int setup_subdevices(struct comedi_device *dev)
 {
 	struct comedi_subdevice *s;
+	int ret;
 
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* analog input subdevice */
@@ -632,7 +633,7 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	printk(KERN_WARNING " irq %u\n", dev->irq);
 
-	/*  alocate pci dma buffers */
+	/*  allocate pci dma buffers */
 	for (i = 0; i < NUM_DMA_BUFFERS; i++) {
 		priv(dev)->dio_buffer[i] =
 		    pci_alloc_consistent(priv(dev)->hw_dev, DMA_BUFFER_SIZE,
@@ -673,10 +674,10 @@ static void hpdi_detach(struct comedi_device *dev)
 	if ((priv(dev)) && (priv(dev)->hw_dev)) {
 		if (priv(dev)->plx9080_iobase) {
 			disable_plx_interrupts(dev);
-			iounmap((void *)priv(dev)->plx9080_iobase);
+			iounmap(priv(dev)->plx9080_iobase);
 		}
 		if (priv(dev)->hpdi_iobase)
-			iounmap((void *)priv(dev)->hpdi_iobase);
+			iounmap(priv(dev)->hpdi_iobase);
 		/*  free pci dma buffers */
 		for (i = 0; i < NUM_DMA_BUFFERS; i++) {
 			if (priv(dev)->dio_buffer[i])
@@ -903,7 +904,7 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel)
 	uint32_t next_transfer_addr;
 	int j;
 	int num_samples = 0;
-	void *pci_addr_reg;
+	void __iomem *pci_addr_reg;
 
 	if (channel)
 		pci_addr_reg =
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index fdc596f..b10ebdb 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -148,7 +148,7 @@ struct boardtype {
 struct icp_multi_private {
 	struct pcilst_struct *card;	/*  pointer to card */
 	char valid;		/*  card is usable */
-	void *io_addr;		/*  Pointer to mapped io address */
+	void __iomem *io_addr;		/*  Pointer to mapped io address */
 	resource_size_t phys_iobase;	/*  Physical io address */
 	unsigned int AdcCmdStatus;	/*  ADC Command/Status register */
 	unsigned int DacCmdStatus;	/*  DAC Command/Status register */
@@ -542,7 +542,7 @@ static int icp_multi_insn_bits_di(struct comedi_device *dev,
 {
 	data[1] = readw(devpriv->io_addr + ICP_MULTI_DI);
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -585,7 +585,7 @@ static int icp_multi_insn_bits_do(struct comedi_device *dev,
 #ifdef ICP_MULTI_EXTDEBUG
 	printk(KERN_DEBUG "icp multi EDBG: END: icp_multi_insn_bits_do(...)\n");
 #endif
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -835,7 +835,7 @@ static int icp_multi_attach(struct comedi_device *dev,
 	printk(KERN_WARNING
 	       "icp_multi EDBG: BGN: icp_multi_attach(...)\n");
 
-	/*  Alocate private data storage space */
+	/*  Allocate private data storage space */
 	ret = alloc_private(dev, sizeof(struct icp_multi_private));
 	if (ret < 0)
 		return ret;
@@ -903,8 +903,8 @@ static int icp_multi_attach(struct comedi_device *dev,
 	if (this_board->n_ctrs)
 		n_subdevices++;
 
-	ret = alloc_subdevices(dev, n_subdevices);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	if (ret)
 		return ret;
 
 	icp_multi_reset(dev);
diff --git a/drivers/staging/comedi/drivers/icp_multi.h b/drivers/staging/comedi/drivers/icp_multi.h
index 68acefe..dbf9908 100644
--- a/drivers/staging/comedi/drivers/icp_multi.h
+++ b/drivers/staging/comedi/drivers/icp_multi.h
@@ -11,7 +11,6 @@
 #define _ICP_MULTI_H_
 
 #include "../comedidev.h"
-#include "comedi_pci.h"
 
 /****************************************************************************/
 
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index f0a579a..0f9cfe6 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -135,15 +135,15 @@ options for PCI-20341M:
 #define PCI20341_SCANLIST		0x80	/* Channel/Gain Scan List */
 
 union pci20xxx_subdev_private {
-	void *iobase;
+	void __iomem *iobase;
 	struct {
-		void *iobase;
+		void __iomem *iobase;
 		const struct comedi_lrange *ao_range_list[2];
 					/* range of channels of ao module */
 		unsigned int last_data[2];
 	} pci20006;
 	struct {
-		void *iobase;
+		void __iomem *iobase;
 		int timebase;
 		int settling_time;
 		int ai_gain;
@@ -152,7 +152,7 @@ union pci20xxx_subdev_private {
 
 struct pci20xxx_private {
 
-	void *ioaddr;
+	void __iomem *ioaddr;
 	union pci20xxx_subdev_private subdev_private[PCI20000_MODULES];
 };
 
@@ -202,15 +202,15 @@ static int pci20xxx_attach(struct comedi_device *dev,
 	struct comedi_subdevice *s;
 	union pci20xxx_subdev_private *sdp;
 
-	ret = alloc_subdevices(dev, 1 + PCI20000_MODULES);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 1 + PCI20000_MODULES);
+	if (ret)
 		return ret;
 
 	ret = alloc_private(dev, sizeof(struct pci20xxx_private));
 	if (ret < 0)
 		return ret;
 
-	devpriv->ioaddr = (void *)(unsigned long)it->options[0];
+	devpriv->ioaddr = (void __iomem *)(unsigned long)it->options[0];
 	dev->board_name = "pci20kc";
 
 	/* Check PCI-20001 C-2A Carrier Board ID */
@@ -565,7 +565,7 @@ static int pci20xxx_dio_insn_bits(struct comedi_device *dev,
 	data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16;
 	data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24;
 
-	return 2;
+	return insn->n;
 }
 
 static void pci20xxx_dio_config(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index d536a11..93f94cd 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -49,7 +49,6 @@ Devices: [JR3] PCI force sensor board (jr3_pci)
 #include <linux/slab.h>
 #include <linux/timer.h>
 #include <linux/kernel.h>
-#include "comedi_pci.h"
 #include "jr3_pci.h"
 
 #define PCI_VENDOR_ID_JR3 0x1762
@@ -350,13 +349,13 @@ static int jr3_pci_open(struct comedi_device *dev)
 	int i;
 	struct jr3_pci_dev_private *devpriv = dev->private;
 
-	dev_dbg(dev->hw_dev, "jr3_pci_open\n");
+	dev_dbg(dev->class_dev, "jr3_pci_open\n");
 	for (i = 0; i < devpriv->n_channels; i++) {
 		struct jr3_pci_subdev_private *p;
 
 		p = dev->subdevices[i].private;
 		if (p) {
-			dev_dbg(dev->hw_dev, "serial: %p %d (%d)\n", p,
+			dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", p,
 				p->serial_no, p->channel_no);
 		}
 	}
@@ -435,7 +434,8 @@ static int jr3_download_firmware(struct comedi_device *dev, const u8 * data,
 					break;
 				more = more
 				    && read_idm_word(data, size, &pos, &addr);
-				dev_dbg(dev->hw_dev, "Loading#%d %4.4x bytes at %4.4x\n",
+				dev_dbg(dev->class_dev,
+					"Loading#%d %4.4x bytes at %4.4x\n",
 					i, count, addr);
 				while (more && count > 0) {
 					if (addr & 0x4000) {
@@ -755,7 +755,8 @@ static int jr3_pci_attach(struct comedi_device *dev,
 	opt_slot = it->options[1];
 
 	if (sizeof(struct jr3_channel) != 0xc00) {
-		dev_err(dev->hw_dev, "sizeof(struct jr3_channel) = %x [expected %x]\n",
+		dev_err(dev->class_dev,
+			"sizeof(struct jr3_channel) = %x [expected %x]\n",
 			(unsigned)sizeof(struct jr3_channel), 0xc00);
 		return -EINVAL;
 	}
@@ -810,7 +811,7 @@ static int jr3_pci_attach(struct comedi_device *dev,
 		}
 	}
 	if (!card) {
-		dev_err(dev->hw_dev, "no jr3_pci found\n");
+		dev_err(dev->class_dev, "no jr3_pci found\n");
 		return -EIO;
 	} else {
 		devpriv->pci_dev = card;
@@ -827,9 +828,9 @@ static int jr3_pci_attach(struct comedi_device *dev,
 	if (!devpriv->iobase)
 		return -ENOMEM;
 
-	result = alloc_subdevices(dev, devpriv->n_channels);
-	if (result < 0)
-		goto out;
+	result = comedi_alloc_subdevices(dev, devpriv->n_channels);
+	if (result)
+		return result;
 
 	dev->open = jr3_pci_open;
 	for (i = 0; i < devpriv->n_channels; i++) {
@@ -845,7 +846,7 @@ static int jr3_pci_attach(struct comedi_device *dev,
 
 			p = dev->subdevices[i].private;
 			p->channel = &devpriv->iobase->channel[i].data;
-			dev_dbg(dev->hw_dev, "p->channel %p %p (%tx)\n",
+			dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n",
 				p->channel, devpriv->iobase,
 				((char *)(p->channel) -
 				 (char *)(devpriv->iobase)));
@@ -886,7 +887,7 @@ static int jr3_pci_attach(struct comedi_device *dev,
 	devpriv->iobase->channel[0].reset = 0;
 
 	result = comedi_load_firmware(dev, "jr3pci.idm", jr3_download_firmware);
-	dev_dbg(dev->hw_dev, "Firmare load %d\n", result);
+	dev_dbg(dev->class_dev, "Firmare load %d\n", result);
 
 	if (result < 0)
 		goto out;
@@ -904,7 +905,7 @@ static int jr3_pci_attach(struct comedi_device *dev,
  */
 	msleep_interruptible(25);
 	for (i = 0; i < 0x18; i++) {
-		dev_dbg(dev->hw_dev, "%c\n",
+		dev_dbg(dev->class_dev, "%c\n",
 			get_u16(&devpriv->iobase->channel[0].
 				data.copyright[i]) >> 8);
 	}
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index 09d1918..019e91a 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -40,8 +40,6 @@ Kolter Electronic PCI Counter Card.
 
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
-
 #define CNT_DRIVER_NAME         "ke_counter"
 #define PCI_VENDOR_ID_KOLTER    0x1001
 #define CNT_CARD_DEVICE_ID      0x0014
@@ -191,9 +189,8 @@ found:
 	io_base = pci_resource_start(pci_device, 0);
 	dev->iobase = io_base;
 
-	/* allocate the subdevice structures */
-	error = alloc_subdevices(dev, 1);
-	if (error < 0)
+	error = comedi_alloc_subdevices(dev, 1);
+	if (error)
 		return error;
 
 	subdevice = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index 8ca1b54..9a8258e 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -58,7 +58,6 @@ broken.
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
-#include "comedi_pci.h"
 #include "me4000.h"
 #if 0
 /* file removed due to GPL incompatibility */
@@ -105,42 +104,6 @@ static int ai_write_chanlist(struct comedi_device *dev,
 			     struct comedi_subdevice *s,
 			     struct comedi_cmd *cmd);
 
-/*-----------------------------------------------------------------------------
-  Meilhaus inline functions
-  ---------------------------------------------------------------------------*/
-
-static inline void me4000_outb(struct comedi_device *dev, unsigned char value,
-			       unsigned long port)
-{
-	PORT_PDEBUG("--> 0x%02X port 0x%04lX\n", value, port);
-	outb(value, port);
-}
-
-static inline void me4000_outl(struct comedi_device *dev, unsigned long value,
-			       unsigned long port)
-{
-	PORT_PDEBUG("--> 0x%08lX port 0x%04lX\n", value, port);
-	outl(value, port);
-}
-
-static inline unsigned long me4000_inl(struct comedi_device *dev,
-				       unsigned long port)
-{
-	unsigned long value;
-	value = inl(port);
-	PORT_PDEBUG("<-- 0x%08lX port 0x%04lX\n", value, port);
-	return value;
-}
-
-static inline unsigned char me4000_inb(struct comedi_device *dev,
-				       unsigned long port)
-{
-	unsigned char value;
-	value = inb(port);
-	PORT_PDEBUG("<-- 0x%08X port 0x%04lX\n", value, port);
-	return value;
-}
-
 static const struct comedi_lrange me4000_ai_range = {
 	4,
 	{
@@ -164,8 +127,6 @@ static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it)
 	int result, i;
 	struct me4000_board *board;
 
-	CALL_PDEBUG("In me4000_probe()\n");
-
 	/* Allocate private memory */
 	if (alloc_private(dev, sizeof(struct me4000_info)) < 0)
 		return -ENOMEM;
@@ -309,9 +270,6 @@ found:
 
 static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p)
 {
-
-	CALL_PDEBUG("In get_registers()\n");
-
     /*--------------------------- plx regbase -------------------------------*/
 
 	info->plx_regbase = pci_resource_start(pci_dev_p, 1);
@@ -363,8 +321,6 @@ static int init_board_info(struct comedi_device *dev, struct pci_dev *pci_dev_p)
 {
 	int result;
 
-	CALL_PDEBUG("In init_board_info()\n");
-
 	/* Init spin locks */
 	/* spin_lock_init(&info->preload_lock); */
 	/* spin_lock_init(&info->ai_ctrl_lock); */
@@ -395,8 +351,6 @@ static int init_ao_context(struct comedi_device *dev)
 {
 	int i;
 
-	CALL_PDEBUG("In init_ao_context()\n");
-
 	for (i = 0; i < thisboard->ao.count; i++) {
 		/* spin_lock_init(&info->ao_context[i].use_lock); */
 		info->ao_context[i].irq = info->irq;
@@ -476,9 +430,6 @@ static int init_ao_context(struct comedi_device *dev)
 
 static int init_ai_context(struct comedi_device *dev)
 {
-
-	CALL_PDEBUG("In init_ai_context()\n");
-
 	info->ai_context.irq = info->irq;
 
 	info->ai_context.ctrl_reg = info->me4000_regbase + ME4000_AI_CTRL_REG;
@@ -510,9 +461,6 @@ static int init_ai_context(struct comedi_device *dev)
 
 static int init_dio_context(struct comedi_device *dev)
 {
-
-	CALL_PDEBUG("In init_dio_context()\n");
-
 	info->dio_context.dir_reg = info->me4000_regbase + ME4000_DIO_DIR_REG;
 	info->dio_context.ctrl_reg = info->me4000_regbase + ME4000_DIO_CTRL_REG;
 	info->dio_context.port_0_reg =
@@ -529,9 +477,6 @@ static int init_dio_context(struct comedi_device *dev)
 
 static int init_cnt_context(struct comedi_device *dev)
 {
-
-	CALL_PDEBUG("In init_cnt_context()\n");
-
 	info->cnt_context.ctrl_reg = info->timer_regbase + ME4000_CNT_CTRL_REG;
 	info->cnt_context.counter_0_reg =
 	    info->timer_regbase + ME4000_CNT_COUNTER_0_REG;
@@ -555,8 +500,6 @@ static int xilinx_download(struct comedi_device *dev)
 	int idx = 0;
 	int size = 0;
 
-	CALL_PDEBUG("In xilinx_download()\n");
-
 	init_waitqueue_head(&queue);
 
 	/*
@@ -635,59 +578,46 @@ static int reset_board(struct comedi_device *dev)
 {
 	unsigned long icr;
 
-	CALL_PDEBUG("In reset_board()\n");
-
 	/* Make a hardware reset */
-	icr = me4000_inl(dev, info->plx_regbase + PLX_ICR);
+	icr = inl(info->plx_regbase + PLX_ICR);
 	icr |= 0x40000000;
-	me4000_outl(dev, icr, info->plx_regbase + PLX_ICR);
+	outl(icr, info->plx_regbase + PLX_ICR);
 	icr &= ~0x40000000;
-	me4000_outl(dev, icr, info->plx_regbase + PLX_ICR);
+	outl(icr, info->plx_regbase + PLX_ICR);
 
 	/* 0x8000 to the DACs means an output voltage of 0V */
-	me4000_outl(dev, 0x8000,
-		    info->me4000_regbase + ME4000_AO_00_SINGLE_REG);
-	me4000_outl(dev, 0x8000,
-		    info->me4000_regbase + ME4000_AO_01_SINGLE_REG);
-	me4000_outl(dev, 0x8000,
-		    info->me4000_regbase + ME4000_AO_02_SINGLE_REG);
-	me4000_outl(dev, 0x8000,
-		    info->me4000_regbase + ME4000_AO_03_SINGLE_REG);
+	outl(0x8000, info->me4000_regbase + ME4000_AO_00_SINGLE_REG);
+	outl(0x8000, info->me4000_regbase + ME4000_AO_01_SINGLE_REG);
+	outl(0x8000, info->me4000_regbase + ME4000_AO_02_SINGLE_REG);
+	outl(0x8000, info->me4000_regbase + ME4000_AO_03_SINGLE_REG);
 
 	/* Set both stop bits in the analog input control register */
-	me4000_outl(dev,
-		    ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP,
-		    info->me4000_regbase + ME4000_AI_CTRL_REG);
+	outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP,
+		info->me4000_regbase + ME4000_AI_CTRL_REG);
 
 	/* Set both stop bits in the analog output control register */
-	me4000_outl(dev,
-		    ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
-		    info->me4000_regbase + ME4000_AO_00_CTRL_REG);
-	me4000_outl(dev,
-		    ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
-		    info->me4000_regbase + ME4000_AO_01_CTRL_REG);
-	me4000_outl(dev,
-		    ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
-		    info->me4000_regbase + ME4000_AO_02_CTRL_REG);
-	me4000_outl(dev,
-		    ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
-		    info->me4000_regbase + ME4000_AO_03_CTRL_REG);
+	outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
+		info->me4000_regbase + ME4000_AO_00_CTRL_REG);
+	outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
+		info->me4000_regbase + ME4000_AO_01_CTRL_REG);
+	outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
+		info->me4000_regbase + ME4000_AO_02_CTRL_REG);
+	outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
+		info->me4000_regbase + ME4000_AO_03_CTRL_REG);
 
 	/* Enable interrupts on the PLX */
-	me4000_outl(dev, 0x43, info->plx_regbase + PLX_INTCSR);
+	outl(0x43, info->plx_regbase + PLX_INTCSR);
 
 	/* Set the adustment register for AO demux */
-	me4000_outl(dev, ME4000_AO_DEMUX_ADJUST_VALUE,
+	outl(ME4000_AO_DEMUX_ADJUST_VALUE,
 		    info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG);
 
 	/*
 	 * Set digital I/O direction for port 0
 	 * to output on isolated versions
 	 */
-	if (!(me4000_inl(dev, info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1)) {
-		me4000_outl(dev, 0x1,
-			    info->me4000_regbase + ME4000_DIO_CTRL_REG);
-	}
+	if (!(inl(info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1))
+		outl(0x1, info->me4000_regbase + ME4000_DIO_CTRL_REG);
 
 	return 0;
 }
@@ -709,8 +639,6 @@ static int me4000_ai_insn_read(struct comedi_device *dev,
 	unsigned long tmp;
 	long lval;
 
-	CALL_PDEBUG("In me4000_ai_insn_read()\n");
-
 	if (insn->n == 0) {
 		return 0;
 	} else if (insn->n > 1) {
@@ -779,36 +707,34 @@ static int me4000_ai_insn_read(struct comedi_device *dev,
 	entry |= ME4000_AI_LIST_LAST_ENTRY;
 
 	/* Clear channel list, data fifo and both stop bits */
-	tmp = me4000_inl(dev, info->ai_context.ctrl_reg);
+	tmp = inl(info->ai_context.ctrl_reg);
 	tmp &= ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
 		 ME4000_AI_CTRL_BIT_DATA_FIFO |
 		 ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
-	me4000_outl(dev, tmp, info->ai_context.ctrl_reg);
+	outl(tmp, info->ai_context.ctrl_reg);
 
 	/* Set the acquisition mode to single */
 	tmp &= ~(ME4000_AI_CTRL_BIT_MODE_0 | ME4000_AI_CTRL_BIT_MODE_1 |
 		 ME4000_AI_CTRL_BIT_MODE_2);
-	me4000_outl(dev, tmp, info->ai_context.ctrl_reg);
+	outl(tmp, info->ai_context.ctrl_reg);
 
 	/* Enable channel list and data fifo */
 	tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO;
-	me4000_outl(dev, tmp, info->ai_context.ctrl_reg);
+	outl(tmp, info->ai_context.ctrl_reg);
 
 	/* Generate channel list entry */
-	me4000_outl(dev, entry, info->ai_context.channel_list_reg);
+	outl(entry, info->ai_context.channel_list_reg);
 
 	/* Set the timer to maximum sample rate */
-	me4000_outl(dev, ME4000_AI_MIN_TICKS, info->ai_context.chan_timer_reg);
-	me4000_outl(dev, ME4000_AI_MIN_TICKS,
-		    info->ai_context.chan_pre_timer_reg);
+	outl(ME4000_AI_MIN_TICKS, info->ai_context.chan_timer_reg);
+	outl(ME4000_AI_MIN_TICKS, info->ai_context.chan_pre_timer_reg);
 
 	/* Start conversion by dummy read */
-	me4000_inl(dev, info->ai_context.start_reg);
+	inl(info->ai_context.start_reg);
 
 	/* Wait until ready */
 	udelay(10);
-	if (!
-	    (me4000_inl(dev, info->ai_context.status_reg) &
+	if (!(inl(info->ai_context.status_reg) &
 	     ME4000_AI_STATUS_BIT_EF_DATA)) {
 		printk(KERN_ERR
 		       "comedi%d: me4000: me4000_ai_insn_read(): "
@@ -817,7 +743,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev,
 	}
 
 	/* Read value from data fifo */
-	lval = me4000_inl(dev, info->ai_context.data_reg) & 0xFFFF;
+	lval = inl(info->ai_context.data_reg) & 0xFFFF;
 	data[0] = lval ^ 0x8000;
 
 	return 1;
@@ -828,15 +754,13 @@ static int me4000_ai_cancel(struct comedi_device *dev,
 {
 	unsigned long tmp;
 
-	CALL_PDEBUG("In me4000_ai_cancel()\n");
-
 	/* Stop any running conversion */
-	tmp = me4000_inl(dev, info->ai_context.ctrl_reg);
+	tmp = inl(info->ai_context.ctrl_reg);
 	tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
-	me4000_outl(dev, tmp, info->ai_context.ctrl_reg);
+	outl(tmp, info->ai_context.ctrl_reg);
 
 	/* Clear the control register */
-	me4000_outl(dev, 0x0, info->ai_context.ctrl_reg);
+	outl(0x0, info->ai_context.ctrl_reg);
 
 	return 0;
 }
@@ -847,8 +771,6 @@ static int ai_check_chanlist(struct comedi_device *dev,
 	int aref;
 	int i;
 
-	CALL_PDEBUG("In ai_check_chanlist()\n");
-
 	/* Check whether a channel list is available */
 	if (!cmd->chanlist_len) {
 		printk(KERN_ERR
@@ -934,25 +856,18 @@ static int ai_round_cmd_args(struct comedi_device *dev,
 
 	int rest;
 
-	CALL_PDEBUG("In ai_round_cmd_args()\n");
-
 	*init_ticks = 0;
 	*scan_ticks = 0;
 	*chan_ticks = 0;
 
-	PDEBUG("ai_round_cmd_arg(): start_arg = %d\n", cmd->start_arg);
-	PDEBUG("ai_round_cmd_arg(): scan_begin_arg = %d\n",
-	       cmd->scan_begin_arg);
-	PDEBUG("ai_round_cmd_arg(): convert_arg = %d\n", cmd->convert_arg);
-
 	if (cmd->start_arg) {
 		*init_ticks = (cmd->start_arg * 33) / 1000;
 		rest = (cmd->start_arg * 33) % 1000;
 
-		if (cmd->flags & TRIG_ROUND_NEAREST) {
+		if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
 			if (rest > 33)
 				(*init_ticks)++;
-		} else if (cmd->flags & TRIG_ROUND_UP) {
+		} else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
 			if (rest)
 				(*init_ticks)++;
 		}
@@ -962,10 +877,10 @@ static int ai_round_cmd_args(struct comedi_device *dev,
 		*scan_ticks = (cmd->scan_begin_arg * 33) / 1000;
 		rest = (cmd->scan_begin_arg * 33) % 1000;
 
-		if (cmd->flags & TRIG_ROUND_NEAREST) {
+		if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
 			if (rest > 33)
 				(*scan_ticks)++;
-		} else if (cmd->flags & TRIG_ROUND_UP) {
+		} else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
 			if (rest)
 				(*scan_ticks)++;
 		}
@@ -975,19 +890,15 @@ static int ai_round_cmd_args(struct comedi_device *dev,
 		*chan_ticks = (cmd->convert_arg * 33) / 1000;
 		rest = (cmd->convert_arg * 33) % 1000;
 
-		if (cmd->flags & TRIG_ROUND_NEAREST) {
+		if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
 			if (rest > 33)
 				(*chan_ticks)++;
-		} else if (cmd->flags & TRIG_ROUND_UP) {
+		} else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
 			if (rest)
 				(*chan_ticks)++;
 		}
 	}
 
-	PDEBUG("ai_round_cmd_args(): init_ticks = %d\n", *init_ticks);
-	PDEBUG("ai_round_cmd_args(): scan_ticks = %d\n", *scan_ticks);
-	PDEBUG("ai_round_cmd_args(): chan_ticks = %d\n", *chan_ticks);
-
 	return 0;
 }
 
@@ -995,21 +906,16 @@ static void ai_write_timer(struct comedi_device *dev,
 			   unsigned int init_ticks,
 			   unsigned int scan_ticks, unsigned int chan_ticks)
 {
-
-	CALL_PDEBUG("In ai_write_timer()\n");
-
-	me4000_outl(dev, init_ticks - 1,
-		    info->ai_context.scan_pre_timer_low_reg);
-	me4000_outl(dev, 0x0, info->ai_context.scan_pre_timer_high_reg);
+	outl(init_ticks - 1, info->ai_context.scan_pre_timer_low_reg);
+	outl(0x0, info->ai_context.scan_pre_timer_high_reg);
 
 	if (scan_ticks) {
-		me4000_outl(dev, scan_ticks - 1,
-			    info->ai_context.scan_timer_low_reg);
-		me4000_outl(dev, 0x0, info->ai_context.scan_timer_high_reg);
+		outl(scan_ticks - 1, info->ai_context.scan_timer_low_reg);
+		outl(0x0, info->ai_context.scan_timer_high_reg);
 	}
 
-	me4000_outl(dev, chan_ticks - 1, info->ai_context.chan_pre_timer_reg);
-	me4000_outl(dev, chan_ticks - 1, info->ai_context.chan_timer_reg);
+	outl(chan_ticks - 1, info->ai_context.chan_pre_timer_reg);
+	outl(chan_ticks - 1, info->ai_context.chan_timer_reg);
 }
 
 static int ai_prepare(struct comedi_device *dev,
@@ -1021,13 +927,11 @@ static int ai_prepare(struct comedi_device *dev,
 
 	unsigned long tmp = 0;
 
-	CALL_PDEBUG("In ai_prepare()\n");
-
 	/* Write timer arguments */
 	ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks);
 
 	/* Reset control register */
-	me4000_outl(dev, tmp, info->ai_context.ctrl_reg);
+	outl(tmp, info->ai_context.ctrl_reg);
 
 	/* Start sources */
 	if ((cmd->start_src == TRIG_EXT &&
@@ -1060,12 +964,12 @@ static int ai_prepare(struct comedi_device *dev,
 
 	/* Stop triggers */
 	if (cmd->stop_src == TRIG_COUNT) {
-		me4000_outl(dev, cmd->chanlist_len * cmd->stop_arg,
+		outl(cmd->chanlist_len * cmd->stop_arg,
 			    info->ai_context.sample_counter_reg);
 		tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ;
 	} else if (cmd->stop_src == TRIG_NONE &&
 		   cmd->scan_end_src == TRIG_COUNT) {
-		me4000_outl(dev, cmd->scan_end_arg,
+		outl(cmd->scan_end_arg,
 			    info->ai_context.sample_counter_reg);
 		tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ;
 	} else {
@@ -1073,7 +977,7 @@ static int ai_prepare(struct comedi_device *dev,
 	}
 
 	/* Write the setup to the control register */
-	me4000_outl(dev, tmp, info->ai_context.ctrl_reg);
+	outl(tmp, info->ai_context.ctrl_reg);
 
 	/* Write the channel list */
 	ai_write_chanlist(dev, s, cmd);
@@ -1090,8 +994,6 @@ static int ai_write_chanlist(struct comedi_device *dev,
 	unsigned int aref;
 	int i;
 
-	CALL_PDEBUG("In ai_write_chanlist()\n");
-
 	for (i = 0; i < cmd->chanlist_len; i++) {
 		chan = CR_CHAN(cmd->chanlist[i]);
 		rang = CR_RANGE(cmd->chanlist[i]);
@@ -1113,7 +1015,7 @@ static int ai_write_chanlist(struct comedi_device *dev,
 		else
 			entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED;
 
-		me4000_outl(dev, entry, info->ai_context.channel_list_reg);
+		outl(entry, info->ai_context.channel_list_reg);
 	}
 
 	return 0;
@@ -1128,8 +1030,6 @@ static int me4000_ai_do_cmd(struct comedi_device *dev,
 	unsigned int chan_ticks = 0;
 	struct comedi_cmd *cmd = &s->async->cmd;
 
-	CALL_PDEBUG("In me4000_ai_do_cmd()\n");
-
 	/* Reset the analog input */
 	err = me4000_ai_cancel(dev, s);
 	if (err)
@@ -1147,7 +1047,7 @@ static int me4000_ai_do_cmd(struct comedi_device *dev,
 		return err;
 
 	/* Start acquistion by dummy read */
-	me4000_inl(dev, info->ai_context.start_reg);
+	inl(info->ai_context.start_reg);
 
 	return 0;
 }
@@ -1174,34 +1074,6 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
 	unsigned int scan_ticks;
 	int err = 0;
 
-	CALL_PDEBUG("In me4000_ai_do_cmd_test()\n");
-
-	PDEBUG("me4000_ai_do_cmd_test(): subdev         = %d\n", cmd->subdev);
-	PDEBUG("me4000_ai_do_cmd_test(): flags          = %08X\n", cmd->flags);
-	PDEBUG("me4000_ai_do_cmd_test(): start_src      = %08X\n",
-	       cmd->start_src);
-	PDEBUG("me4000_ai_do_cmd_test(): start_arg      = %d\n",
-	       cmd->start_arg);
-	PDEBUG("me4000_ai_do_cmd_test(): scan_begin_src = %08X\n",
-	       cmd->scan_begin_src);
-	PDEBUG("me4000_ai_do_cmd_test(): scan_begin_arg = %d\n",
-	       cmd->scan_begin_arg);
-	PDEBUG("me4000_ai_do_cmd_test(): convert_src    = %08X\n",
-	       cmd->convert_src);
-	PDEBUG("me4000_ai_do_cmd_test(): convert_arg    = %d\n",
-	       cmd->convert_arg);
-	PDEBUG("me4000_ai_do_cmd_test(): scan_end_src   = %08X\n",
-	       cmd->scan_end_src);
-	PDEBUG("me4000_ai_do_cmd_test(): scan_end_arg   = %d\n",
-	       cmd->scan_end_arg);
-	PDEBUG("me4000_ai_do_cmd_test(): stop_src       = %08X\n",
-	       cmd->stop_src);
-	PDEBUG("me4000_ai_do_cmd_test(): stop_arg       = %d\n", cmd->stop_arg);
-	PDEBUG("me4000_ai_do_cmd_test(): chanlist       = %d\n",
-	       (unsigned int)cmd->chanlist);
-	PDEBUG("me4000_ai_do_cmd_test(): chanlist_len   = %d\n",
-	       cmd->chanlist_len);
-
 	/* Only rounding flags are implemented */
 	cmd->flags &= TRIG_ROUND_NEAREST | TRIG_ROUND_UP | TRIG_ROUND_DOWN;
 
@@ -1544,12 +1416,8 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
 	int c = 0;
 	long lval;
 
-	ISR_PDEBUG("me4000_ai_isr() is executed\n");
-
-	if (!dev->attached) {
-		ISR_PDEBUG("me4000_ai_isr() premature interrupt\n");
+	if (!dev->attached)
 		return IRQ_NONE;
-	}
 
 	/* Reset all events */
 	s->async->events = 0;
@@ -1562,19 +1430,14 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
 		return IRQ_HANDLED;
 	}
 
-	if (me4000_inl(dev,
-		       ai_context->irq_status_reg) &
+	if (inl(ai_context->irq_status_reg) &
 	    ME4000_IRQ_STATUS_BIT_AI_HF) {
-		ISR_PDEBUG
-		    ("me4000_ai_isr(): Fifo half full interrupt occurred\n");
-
 		/* Read status register to find out what happened */
-		tmp = me4000_inl(dev, ai_context->ctrl_reg);
+		tmp = inl(ai_context->ctrl_reg);
 
 		if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
 		    !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) &&
 		    (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
-			ISR_PDEBUG("me4000_ai_isr(): Fifo full\n");
 			c = ME4000_AI_FIFO_COUNT;
 
 			/*
@@ -1584,7 +1447,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
 			tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
 			tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
 				 ME4000_AI_CTRL_BIT_SC_IRQ);
-			me4000_outl(dev, tmp, ai_context->ctrl_reg);
+			outl(tmp, ai_context->ctrl_reg);
 
 			s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 
@@ -1594,8 +1457,6 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
 		} else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
 			   && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
 			   && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
-			ISR_PDEBUG("me4000_ai_isr(): Fifo half full\n");
-
 			s->async->events |= COMEDI_CB_BLOCK;
 
 			c = ME4000_AI_FIFO_COUNT / 2;
@@ -1612,7 +1473,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
 			tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
 			tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
 				 ME4000_AI_CTRL_BIT_SC_IRQ);
-			me4000_outl(dev, tmp, ai_context->ctrl_reg);
+			outl(tmp, ai_context->ctrl_reg);
 
 			s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 
@@ -1621,8 +1482,6 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
 			       "Undefined FIFO state\n", dev->minor);
 		}
 
-		ISR_PDEBUG("me4000_ai_isr(): Try to read %d values\n", c);
-
 		for (i = 0; i < c; i++) {
 			/* Read value from data fifo */
 			lval = inl(ai_context->data_reg) & 0xFFFF;
@@ -1636,7 +1495,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
 				tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
 				tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
 					 ME4000_AI_CTRL_BIT_SC_IRQ);
-				me4000_outl(dev, tmp, ai_context->ctrl_reg);
+				outl(tmp, ai_context->ctrl_reg);
 
 				s->async->events |= COMEDI_CB_OVERFLOW;
 
@@ -1649,28 +1508,23 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
 		}
 
 		/* Work is done, so reset the interrupt */
-		ISR_PDEBUG("me4000_ai_isr(): Reset fifo half full interrupt\n");
 		tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
-		me4000_outl(dev, tmp, ai_context->ctrl_reg);
+		outl(tmp, ai_context->ctrl_reg);
 		tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
-		me4000_outl(dev, tmp, ai_context->ctrl_reg);
+		outl(tmp, ai_context->ctrl_reg);
 	}
 
-	if (me4000_inl(dev,
-		       ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) {
-		ISR_PDEBUG
-		    ("me4000_ai_isr(): Sample counter interrupt occurred\n");
-
+	if (inl(ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) {
 		s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOA;
 
 		/*
 		 * Acquisition is complete, so stop
 		 * conversion and disable all interrupts
 		 */
-		tmp = me4000_inl(dev, ai_context->ctrl_reg);
+		tmp = inl(ai_context->ctrl_reg);
 		tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
 		tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ);
-		me4000_outl(dev, tmp, ai_context->ctrl_reg);
+		outl(tmp, ai_context->ctrl_reg);
 
 		/* Poll data until fifo empty */
 		while (inl(ai_context->ctrl_reg) & ME4000_AI_STATUS_BIT_EF_DATA) {
@@ -1688,16 +1542,12 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
 		}
 
 		/* Work is done, so reset the interrupt */
-		ISR_PDEBUG
-		    ("me4000_ai_isr(): Reset interrupt from sample counter\n");
 		tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
-		me4000_outl(dev, tmp, ai_context->ctrl_reg);
+		outl(tmp, ai_context->ctrl_reg);
 		tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
-		me4000_outl(dev, tmp, ai_context->ctrl_reg);
+		outl(tmp, ai_context->ctrl_reg);
 	}
 
-	ISR_PDEBUG("me4000_ai_isr(): Events = 0x%X\n", s->async->events);
-
 	if (s->async->events)
 		comedi_event(dev, s);
 
@@ -1718,8 +1568,6 @@ static int me4000_ao_insn_write(struct comedi_device *dev,
 	int aref = CR_AREF(insn->chanspec);
 	unsigned long tmp;
 
-	CALL_PDEBUG("In me4000_ao_insn_write()\n");
-
 	if (insn->n == 0) {
 		return 0;
 	} else if (insn->n > 1) {
@@ -1751,15 +1599,15 @@ static int me4000_ao_insn_write(struct comedi_device *dev,
 	}
 
 	/* Stop any running conversion */
-	tmp = me4000_inl(dev, info->ao_context[chan].ctrl_reg);
+	tmp = inl(info->ao_context[chan].ctrl_reg);
 	tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
-	me4000_outl(dev, tmp, info->ao_context[chan].ctrl_reg);
+	outl(tmp, info->ao_context[chan].ctrl_reg);
 
 	/* Clear control register and set to single mode */
-	me4000_outl(dev, 0x0, info->ao_context[chan].ctrl_reg);
+	outl(0x0, info->ao_context[chan].ctrl_reg);
 
 	/* Write data value */
-	me4000_outl(dev, data[0], info->ao_context[chan].single_reg);
+	outl(data[0], info->ao_context[chan].single_reg);
 
 	/* Store in the mirror */
 	info->ao_context[chan].mirror = data[0];
@@ -1795,20 +1643,6 @@ static int me4000_dio_insn_bits(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
-
-	CALL_PDEBUG("In me4000_dio_insn_bits()\n");
-
-	/* Length of data must be 2 (mask and new data, see below) */
-	if (insn->n == 0)
-		return 0;
-
-	if (insn->n != 2) {
-		printk
-		    ("comedi%d: me4000: me4000_dio_insn_bits(): "
-		     "Invalid instruction length\n", dev->minor);
-		return -EINVAL;
-	}
-
 	/*
 	 * The insn data consists of a mask in data[0] and the new data
 	 * in data[1]. The mask defines which bits we are concerning about.
@@ -1824,25 +1658,24 @@ static int me4000_dio_insn_bits(struct comedi_device *dev,
 		s->state |= data[0] & data[1];
 
 		/* Write out the new digital output lines */
-		me4000_outl(dev, (s->state >> 0) & 0xFF,
+		outl((s->state >> 0) & 0xFF,
 			    info->dio_context.port_0_reg);
-		me4000_outl(dev, (s->state >> 8) & 0xFF,
+		outl((s->state >> 8) & 0xFF,
 			    info->dio_context.port_1_reg);
-		me4000_outl(dev, (s->state >> 16) & 0xFF,
+		outl((s->state >> 16) & 0xFF,
 			    info->dio_context.port_2_reg);
-		me4000_outl(dev, (s->state >> 24) & 0xFF,
+		outl((s->state >> 24) & 0xFF,
 			    info->dio_context.port_3_reg);
 	}
 
 	/* On return, data[1] contains the value of
 	   the digital input and output lines. */
-	data[1] =
-	    ((me4000_inl(dev, info->dio_context.port_0_reg) & 0xFF) << 0) |
-	    ((me4000_inl(dev, info->dio_context.port_1_reg) & 0xFF) << 8) |
-	    ((me4000_inl(dev, info->dio_context.port_2_reg) & 0xFF) << 16) |
-	    ((me4000_inl(dev, info->dio_context.port_3_reg) & 0xFF) << 24);
+	data[1] = ((inl(info->dio_context.port_0_reg) & 0xFF) << 0) |
+		  ((inl(info->dio_context.port_1_reg) & 0xFF) << 8) |
+		  ((inl(info->dio_context.port_2_reg) & 0xFF) << 16) |
+		  ((inl(info->dio_context.port_3_reg) & 0xFF) << 24);
 
-	return 2;
+	return insn->n;
 }
 
 static int me4000_dio_insn_config(struct comedi_device *dev,
@@ -1852,8 +1685,6 @@ static int me4000_dio_insn_config(struct comedi_device *dev,
 	unsigned long tmp;
 	int chan = CR_CHAN(insn->chanspec);
 
-	CALL_PDEBUG("In me4000_dio_insn_config()\n");
-
 	switch (data[0]) {
 	default:
 		return -EINVAL;
@@ -1874,7 +1705,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev,
 	 * On the ME-4000 it is only possible to switch port wise (8 bit)
 	 */
 
-	tmp = me4000_inl(dev, info->dio_context.ctrl_reg);
+	tmp = inl(info->dio_context.ctrl_reg);
 
 	if (data[0] == INSN_CONFIG_DIO_OUTPUT) {
 		if (chan < 8) {
@@ -1888,7 +1719,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev,
 			 * If one the first port is a fixed output
 			 * port and the second is a fixed input port.
 			 */
-			if (!me4000_inl(dev, info->dio_context.dir_reg))
+			if (!inl(info->dio_context.dir_reg))
 				return -ENODEV;
 
 			s->io_bits |= 0xFF00;
@@ -1915,7 +1746,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev,
 			 * If one the first port is a fixed output
 			 * port and the second is a fixed input port.
 			 */
-			if (!me4000_inl(dev, info->dio_context.dir_reg))
+			if (!inl(info->dio_context.dir_reg))
 				return -ENODEV;
 
 			s->io_bits &= ~0xFF;
@@ -1938,7 +1769,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev,
 		}
 	}
 
-	me4000_outl(dev, tmp, info->dio_context.ctrl_reg);
+	outl(tmp, info->dio_context.ctrl_reg);
 
 	return 1;
 }
@@ -1949,24 +1780,21 @@ static int me4000_dio_insn_config(struct comedi_device *dev,
 
 static int cnt_reset(struct comedi_device *dev, unsigned int channel)
 {
-
-	CALL_PDEBUG("In cnt_reset()\n");
-
 	switch (channel) {
 	case 0:
-		me4000_outb(dev, 0x30, info->cnt_context.ctrl_reg);
-		me4000_outb(dev, 0x00, info->cnt_context.counter_0_reg);
-		me4000_outb(dev, 0x00, info->cnt_context.counter_0_reg);
+		outb(0x30, info->cnt_context.ctrl_reg);
+		outb(0x00, info->cnt_context.counter_0_reg);
+		outb(0x00, info->cnt_context.counter_0_reg);
 		break;
 	case 1:
-		me4000_outb(dev, 0x70, info->cnt_context.ctrl_reg);
-		me4000_outb(dev, 0x00, info->cnt_context.counter_1_reg);
-		me4000_outb(dev, 0x00, info->cnt_context.counter_1_reg);
+		outb(0x70, info->cnt_context.ctrl_reg);
+		outb(0x00, info->cnt_context.counter_1_reg);
+		outb(0x00, info->cnt_context.counter_1_reg);
 		break;
 	case 2:
-		me4000_outb(dev, 0xB0, info->cnt_context.ctrl_reg);
-		me4000_outb(dev, 0x00, info->cnt_context.counter_2_reg);
-		me4000_outb(dev, 0x00, info->cnt_context.counter_2_reg);
+		outb(0xB0, info->cnt_context.ctrl_reg);
+		outb(0x00, info->cnt_context.counter_2_reg);
+		outb(0x00, info->cnt_context.counter_2_reg);
 		break;
 	default:
 		printk(KERN_ERR
@@ -1983,8 +1811,6 @@ static int cnt_config(struct comedi_device *dev, unsigned int channel,
 {
 	int tmp = 0;
 
-	CALL_PDEBUG("In cnt_config()\n");
-
 	switch (channel) {
 	case 0:
 		tmp |= ME4000_CNT_COUNTER_0;
@@ -2030,7 +1856,7 @@ static int cnt_config(struct comedi_device *dev, unsigned int channel,
 
 	/* Write the control word */
 	tmp |= 0x30;
-	me4000_outb(dev, tmp, info->cnt_context.ctrl_reg);
+	outb(tmp, info->cnt_context.ctrl_reg);
 
 	return 0;
 }
@@ -2042,8 +1868,6 @@ static int me4000_cnt_insn_config(struct comedi_device *dev,
 
 	int err;
 
-	CALL_PDEBUG("In me4000_cnt_insn_config()\n");
-
 	switch (data[0]) {
 	case GPCT_RESET:
 		if (insn->n != 1) {
@@ -2088,8 +1912,6 @@ static int me4000_cnt_insn_read(struct comedi_device *dev,
 
 	unsigned short tmp;
 
-	CALL_PDEBUG("In me4000_cnt_insn_read()\n");
-
 	if (insn->n == 0)
 		return 0;
 
@@ -2103,21 +1925,21 @@ static int me4000_cnt_insn_read(struct comedi_device *dev,
 
 	switch (insn->chanspec) {
 	case 0:
-		tmp = me4000_inb(dev, info->cnt_context.counter_0_reg);
+		tmp = inb(info->cnt_context.counter_0_reg);
 		data[0] = tmp;
-		tmp = me4000_inb(dev, info->cnt_context.counter_0_reg);
+		tmp = inb(info->cnt_context.counter_0_reg);
 		data[0] |= tmp << 8;
 		break;
 	case 1:
-		tmp = me4000_inb(dev, info->cnt_context.counter_1_reg);
+		tmp = inb(info->cnt_context.counter_1_reg);
 		data[0] = tmp;
-		tmp = me4000_inb(dev, info->cnt_context.counter_1_reg);
+		tmp = inb(info->cnt_context.counter_1_reg);
 		data[0] |= tmp << 8;
 		break;
 	case 2:
-		tmp = me4000_inb(dev, info->cnt_context.counter_2_reg);
+		tmp = inb(info->cnt_context.counter_2_reg);
 		data[0] = tmp;
-		tmp = me4000_inb(dev, info->cnt_context.counter_2_reg);
+		tmp = inb(info->cnt_context.counter_2_reg);
 		data[0] |= tmp << 8;
 		break;
 	default:
@@ -2138,8 +1960,6 @@ static int me4000_cnt_insn_write(struct comedi_device *dev,
 
 	unsigned short tmp;
 
-	CALL_PDEBUG("In me4000_cnt_insn_write()\n");
-
 	if (insn->n == 0) {
 		return 0;
 	} else if (insn->n > 1) {
@@ -2153,21 +1973,21 @@ static int me4000_cnt_insn_write(struct comedi_device *dev,
 	switch (insn->chanspec) {
 	case 0:
 		tmp = data[0] & 0xFF;
-		me4000_outb(dev, tmp, info->cnt_context.counter_0_reg);
+		outb(tmp, info->cnt_context.counter_0_reg);
 		tmp = (data[0] >> 8) & 0xFF;
-		me4000_outb(dev, tmp, info->cnt_context.counter_0_reg);
+		outb(tmp, info->cnt_context.counter_0_reg);
 		break;
 	case 1:
 		tmp = data[0] & 0xFF;
-		me4000_outb(dev, tmp, info->cnt_context.counter_1_reg);
+		outb(tmp, info->cnt_context.counter_1_reg);
 		tmp = (data[0] >> 8) & 0xFF;
-		me4000_outb(dev, tmp, info->cnt_context.counter_1_reg);
+		outb(tmp, info->cnt_context.counter_1_reg);
 		break;
 	case 2:
 		tmp = data[0] & 0xFF;
-		me4000_outb(dev, tmp, info->cnt_context.counter_2_reg);
+		outb(tmp, info->cnt_context.counter_2_reg);
 		tmp = (data[0] >> 8) & 0xFF;
-		me4000_outb(dev, tmp, info->cnt_context.counter_2_reg);
+		outb(tmp, info->cnt_context.counter_2_reg);
 		break;
 	default:
 		printk(KERN_ERR
@@ -2185,19 +2005,13 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	struct comedi_subdevice *s;
 	int result;
 
-	CALL_PDEBUG("In me4000_attach()\n");
-
 	result = me4000_probe(dev, it);
 	if (result)
 		return result;
 
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.  It relies on
-	 * n_subdevices being set correctly.
-	 */
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
+	result = comedi_alloc_subdevices(dev, 4);
+	if (result)
+		return result;
 
     /*=========================================================================
       Analog input subdevice
@@ -2277,10 +2091,9 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	 * Check for optoisolated ME-4000 version. If one the first
 	 * port is a fixed output port and the second is a fixed input port.
 	 */
-	if (!me4000_inl(dev, info->dio_context.dir_reg)) {
+	if (!inl(info->dio_context.dir_reg)) {
 		s->io_bits |= 0xFF;
-		me4000_outl(dev, ME4000_DIO_CTRL_BIT_MODE_0,
-			    info->dio_context.dir_reg);
+		outl(ME4000_DIO_CTRL_BIT_MODE_0, info->dio_context.dir_reg);
 	}
 
     /*=========================================================================
diff --git a/drivers/staging/comedi/drivers/me4000.h b/drivers/staging/comedi/drivers/me4000.h
index 733b192..5a4df4e 100644
--- a/drivers/staging/comedi/drivers/me4000.h
+++ b/drivers/staging/comedi/drivers/me4000.h
@@ -25,43 +25,6 @@
 #define _ME4000_H_
 
 /*=============================================================================
-  Debug section
-  ===========================================================================*/
-
-#undef ME4000_CALL_DEBUG	/*  Debug function entry and exit */
-#undef ME4000_PORT_DEBUG	/*  Debug port access */
-#undef ME4000_ISR_DEBUG		/*  Debug the interrupt service routine */
-#undef ME4000_DEBUG		/*  General purpose debug masseges */
-
-#ifdef ME4000_CALL_DEBUG
-#undef CALL_PDEBUG
-#define CALL_PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor, ##args)
-#else
-# define CALL_PDEBUG(fmt, args...)	/*  no debugging, do nothing */
-#endif
-
-#ifdef ME4000_PORT_DEBUG
-#undef PORT_PDEBUG
-#define PORT_PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor,  ##args)
-#else
-#define PORT_PDEBUG(fmt, args...)	/*  no debugging, do nothing */
-#endif
-
-#ifdef ME4000_ISR_DEBUG
-#undef ISR_PDEBUG
-#define ISR_PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor,  ##args)
-#else
-#define ISR_PDEBUG(fmt, args...)	/*  no debugging, do nothing */
-#endif
-
-#ifdef ME4000_DEBUG
-#undef PDEBUG
-#define PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor,  ##args)
-#else
-#define PDEBUG(fmt, args...)	/*  no debugging, do nothing */
-#endif
-
-/*=============================================================================
   PCI vendor and device IDs
   ===========================================================================*/
 
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index ffe2512..1803d66 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -54,8 +54,6 @@ from http://www.comedi.org
 #include <linux/sched.h>
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
-
 /*#include "me2600_fw.h" */
 
 #define ME_DRIVER_NAME		"me_daq"
@@ -333,7 +331,7 @@ static int me_dio_insn_bits(struct comedi_device *dev,
 		data[1] |= readw(dev_private->me_regbase + ME_DIO_PORT_B) << 16;
 	}
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -763,9 +761,8 @@ found:
 
 	me_reset(dev);
 
-	/* device driver capabilities */
-	error = alloc_subdevices(dev, 3);
-	if (error < 0)
+	error = comedi_alloc_subdevices(dev, 3);
+	if (error)
 		return error;
 
 	subdevice = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index 13e9c80..a93166d 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -52,7 +52,6 @@
 #include "mite.h"
 
 #include "comedi_fc.h"
-#include "comedi_pci.h"
 #include "../comedidev.h"
 
 
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index 4304e86..b928b67 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -285,6 +285,7 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct comedi_subdevice *s;
 	unsigned long iobase;
+	int ret;
 
 	iobase = it->options[0];
 	printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase);
@@ -348,9 +349,9 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
 	}
 
-	/*  Subdevices structures */
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	s->type = COMEDI_SUBD_AI;
diff --git a/drivers/staging/comedi/drivers/mpc8260cpm.c b/drivers/staging/comedi/drivers/mpc8260cpm.c
index 364470e..a7fda8f 100644
--- a/drivers/staging/comedi/drivers/mpc8260cpm.c
+++ b/drivers/staging/comedi/drivers/mpc8260cpm.c
@@ -113,7 +113,7 @@ static int mpc8260cpm_dio_bits(struct comedi_device *dev,
 
 	p = cpm_pdat((int)s->private);
 
-	return 2;
+	return insn->n;
 }
 
 static int mpc8260cpm_attach(struct comedi_device *dev,
@@ -121,6 +121,7 @@ static int mpc8260cpm_attach(struct comedi_device *dev,
 {
 	struct comedi_subdevice *s;
 	int i;
+	int ret;
 
 	printk("comedi%d: mpc8260cpm: ", dev->minor);
 
@@ -131,8 +132,9 @@ static int mpc8260cpm_attach(struct comedi_device *dev,
 	if (alloc_private(dev, sizeof(struct mpc8260cpm_private)) < 0)
 		return -ENOMEM;
 
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
+	ret =comedi_alloc_subdevices(dev, 4);
+	if (ret)
+		return ret;
 
 	for (i = 0; i < 4; i++) {
 		s = dev->subdevices + i;
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index e951e73..eccbe1f 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -161,28 +161,22 @@ static int multiq3_di_insn_bits(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = inw(dev->iobase + MULTIQ3_DIGIN_PORT);
 
-	return 2;
+	return insn->n;
 }
 
 static int multiq3_do_insn_bits(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	s->state &= ~data[0];
 	s->state |= (data[0] & data[1]);
 	outw(s->state, dev->iobase + MULTIQ3_DIGOUT_PORT);
 
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 static int multiq3_encoder_insn_read(struct comedi_device *dev,
@@ -255,8 +249,9 @@ static int multiq3_attach(struct comedi_device *dev,
 	else
 		printk(KERN_WARNING "comedi%d: no irq\n", dev->minor);
 	dev->board_name = "multiq3";
-	result = alloc_subdevices(dev, 5);
-	if (result < 0)
+
+	result = comedi_alloc_subdevices(dev, 5);
+	if (result)
 		return result;
 
 	result = alloc_private(dev, sizeof(struct multiq3_private));
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index b02aa0e..a80c52f 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -174,22 +174,17 @@ static int ni6527_di_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = readb(devpriv->mite->daq_io_addr + Port_Register(0));
 	data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(1)) << 8;
 	data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(2)) << 16;
 
-	return 2;
+	return insn->n;
 }
 
 static int ni6527_do_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] & data[1]);
@@ -211,7 +206,7 @@ static int ni6527_do_insn_bits(struct comedi_device *dev,
 	}
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 static irqreturn_t ni6527_interrupt(int irq, void *d)
@@ -339,11 +334,8 @@ static int ni6527_intr_insn_bits(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n < 1)
-		return -EINVAL;
-
 	data[1] = 0;
-	return 2;
+	return insn->n;
 }
 
 static int ni6527_intr_insn_config(struct comedi_device *dev,
@@ -397,8 +389,8 @@ static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	printk(KERN_INFO "comedi board: %s, ID=0x%02x\n", dev->board_name,
 		readb(devpriv->mite->daq_io_addr + ID_Register));
 
-	ret = alloc_subdevices(dev, 3);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index 0d27a93..bce39f1 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -415,8 +415,7 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
 	const unsigned max_ports_per_bitfield = 5;
 	unsigned read_bits = 0;
 	unsigned j;
-	if (insn->n != 2)
-		return -EINVAL;
+
 	base_bitfield_channel = CR_CHAN(insn->chanspec);
 	for (j = 0; j < max_ports_per_bitfield; ++j) {
 		const unsigned port_offset =
@@ -602,11 +601,8 @@ static int ni_65xx_intr_insn_bits(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n < 1)
-		return -EINVAL;
-
 	data[1] = 0;
-	return 2;
+	return insn->n;
 }
 
 static int ni_65xx_intr_insn_config(struct comedi_device *dev,
@@ -678,8 +674,8 @@ static int ni_65xx_attach(struct comedi_device *dev,
 	printk(KERN_INFO " ID=0x%02x",
 	       readb(private(dev)->mite->daq_io_addr + ID_Register));
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index 8c40730..5e863ff 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -1093,10 +1093,9 @@ static int ni_660x_attach(struct comedi_device *dev,
 
 	printk(KERN_INFO " %s ", dev->board_name);
 
-	dev->n_subdevices = 2 + NI_660X_MAX_NUM_COUNTERS;
-
-	if (alloc_subdevices(dev, dev->n_subdevices) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 2 + NI_660X_MAX_NUM_COUNTERS);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* Old GENERAL-PURPOSE COUNTER/TIME (GPCT) subdevice, no longer used */
@@ -1286,7 +1285,7 @@ static int ni_660x_dio_insn_bits(struct comedi_device *dev,
 	data[1] =
 	    (ni_660x_read_register(dev, 0,
 				   DIO32Input) >> base_bitfield_channel);
-	return 2;
+	return insn->n;
 }
 
 static void ni_660x_select_pfi_output(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index a9cf94f..9032bac 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -202,8 +202,9 @@ static int ni_670x_attach(struct comedi_device *dev,
 	dev->irq = mite_irq(devpriv->mite);
 	printk(KERN_INFO " %s", dev->board_name);
 
-	if (alloc_subdevices(dev, 2) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 2);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* analog output subdevice */
@@ -305,9 +306,6 @@ static int ni_670x_dio_insn_bits(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	/* The insn data is a mask in data[0] and the new data
 	 * in data[1], each channel cooresponding to a bit. */
 	if (data[0]) {
@@ -321,7 +319,7 @@ static int ni_670x_dio_insn_bits(struct comedi_device *dev,
 	 * input lines. */
 	data[1] = readl(devpriv->mite->daq_io_addr + DIO_PORT0_DATA_OFFSET);
 
-	return 2;
+	return insn->n;
 }
 
 static int ni_670x_dio_insn_config(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index ae896a0..b53a428 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -755,6 +755,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	unsigned int dma = it->options[2];
 	static const int timeout = 2000;
 	int i;
+	int ret;
 
 	printk("comedi%d: %s: io 0x%lx", dev->minor, dev->driver->driver_name,
 	       iobase);
@@ -826,8 +827,9 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	dev->board_ptr = a2150_boards + a2150_probe(dev);
 	dev->board_name = thisboard->name;
 
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
 
 	/* analog input subdevice */
 	s = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index c43dd8a..62c8c44 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -157,8 +157,6 @@ struct atao_board {
 	int n_ao_chans;
 };
 
-#define thisboard ((struct atao_board *)dev->board_ptr)
-
 struct atao_private {
 
 	unsigned short cfg1;
@@ -241,9 +239,6 @@ static int atao_dio_insn_bits(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= data[0] & data[1];
@@ -252,7 +247,7 @@ static int atao_dio_insn_bits(struct comedi_device *dev,
 
 	data[1] = inw(dev->iobase + ATAO_DIN);
 
-	return 2;
+	return insn->n;
 }
 
 static int atao_dio_insn_config(struct comedi_device *dev,
@@ -335,9 +330,11 @@ static int atao_calib_insn_write(struct comedi_device *dev,
 
 static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct atao_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	unsigned long iobase;
 	int ao_unipolar;
+	int ret;
 
 	iobase = it->options[0];
 	if (iobase == 0)
@@ -352,21 +349,20 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	}
 	dev->iobase = iobase;
 
-	/* dev->board_ptr = atao_probe(dev); */
-
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 	if (alloc_private(dev, sizeof(struct atao_private)) < 0)
 		return -ENOMEM;
 
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* analog output subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = thisboard->n_ao_chans;
+	s->n_chan = board->n_ao_chans;
 	s->maxdata = (1 << 12) - 1;
 	if (ao_unipolar)
 		s->range_table = &range_unipolar10;
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index 4f61453..2c78d3d 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -110,8 +110,6 @@ struct atmio16_board_t {
 	int has_8255;
 };
 
-#define boardtype ((const struct atmio16_board_t *)dev->board_ptr)
-
 /* range structs */
 static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 4, {
 								       BIP_RANGE
@@ -238,10 +236,6 @@ static irqreturn_t atmio16d_interrupt(int irq, void *d)
 	struct comedi_device *dev = d;
 	struct comedi_subdevice *s = dev->subdevices + 0;
 
-#ifdef DEBUG1
-	printk(KERN_DEBUG "atmio16d_interrupt!\n");
-#endif
-
 	comedi_buf_put(s->async, inw(dev->iobase + AD_FIFO_REG));
 
 	comedi_event(dev, s);
@@ -253,9 +247,7 @@ static int atmio16d_ai_cmdtest(struct comedi_device *dev,
 			       struct comedi_cmd *cmd)
 {
 	int err = 0, tmp;
-#ifdef DEBUG1
-	printk(KERN_DEBUG "atmio16d_ai_cmdtest\n");
-#endif
+
 	/* make sure triggers are valid */
 	tmp = cmd->start_src;
 	cmd->start_src &= TRIG_NOW;
@@ -357,9 +349,7 @@ static int atmio16d_ai_cmd(struct comedi_device *dev,
 	unsigned int timer, base_clock;
 	unsigned int sample_count, tmp, chan, gain;
 	int i;
-#ifdef DEBUG1
-	printk(KERN_DEBUG "atmio16d_ai_cmd\n");
-#endif
+
 	/* This is slowly becoming a working command interface. *
 	 * It is still uber-experimental */
 
@@ -519,9 +509,6 @@ static int atmio16d_ai_insn_read(struct comedi_device *dev,
 	int gain;
 	int status;
 
-#ifdef DEBUG1
-	printk(KERN_DEBUG "atmio16d_ai_insn_read\n");
-#endif
 	chan = CR_CHAN(insn->chanspec);
 	gain = CR_RANGE(insn->chanspec);
 
@@ -540,9 +527,6 @@ static int atmio16d_ai_insn_read(struct comedi_device *dev,
 		for (t = 0; t < ATMIO16D_TIMEOUT; t++) {
 			/* check conversion status */
 			status = inw(dev->iobase + STAT_REG);
-#ifdef DEBUG1
-			printk(KERN_DEBUG "status=%x\n", status);
-#endif
 			if (status & STAT_AD_CONVAVAIL) {
 				/* read the data now */
 				data[i] = inw(dev->iobase + AD_FIFO_REG);
@@ -574,9 +558,6 @@ static int atmio16d_ao_insn_read(struct comedi_device *dev,
 				 struct comedi_insn *insn, unsigned int *data)
 {
 	int i;
-#ifdef DEBUG1
-	printk(KERN_DEBUG "atmio16d_ao_insn_read\n");
-#endif
 
 	for (i = 0; i < insn->n; i++)
 		data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
@@ -590,9 +571,6 @@ static int atmio16d_ao_insn_write(struct comedi_device *dev,
 	int i;
 	int chan;
 	int d;
-#ifdef DEBUG1
-	printk(KERN_DEBUG "atmio16d_ao_insn_write\n");
-#endif
 
 	chan = CR_CHAN(insn->chanspec);
 
@@ -621,9 +599,6 @@ static int atmio16d_dio_insn_bits(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] | data[1]);
@@ -631,7 +606,7 @@ static int atmio16d_dio_insn_bits(struct comedi_device *dev,
 	}
 	data[1] = inw(dev->iobase + MIO_16_DIG_IN_REG);
 
-	return 2;
+	return insn->n;
 }
 
 static int atmio16d_dio_insn_config(struct comedi_device *dev,
@@ -693,6 +668,7 @@ static int atmio16d_dio_insn_config(struct comedi_device *dev,
 static int atmio16d_attach(struct comedi_device *dev,
 			   struct comedi_devconfig *it)
 {
+	const struct atmio16_board_t *board = comedi_board(dev);
 	unsigned int irq;
 	unsigned long iobase;
 	int ret;
@@ -708,11 +684,10 @@ static int atmio16d_attach(struct comedi_device *dev,
 	}
 	dev->iobase = iobase;
 
-	/* board name */
-	dev->board_name = boardtype->name;
+	dev->board_name = board->name;
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		return ret;
 
 	ret = alloc_private(dev, sizeof(struct atmio16d_private));
@@ -811,7 +786,7 @@ static int atmio16d_attach(struct comedi_device *dev,
 
 	/* 8255 subdevice */
 	s++;
-	if (boardtype->has_8255)
+	if (board->has_8255)
 		subdev_8255_init(dev, s, NULL, dev->iobase);
 	else
 		s->type = COMEDI_SUBD_UNUSED;
@@ -831,7 +806,9 @@ static int atmio16d_attach(struct comedi_device *dev,
 
 static void atmio16d_detach(struct comedi_device *dev)
 {
-	if (dev->subdevices && boardtype->has_8255)
+	const struct atmio16_board_t *board = comedi_board(dev);
+
+	if (dev->subdevices && board->has_8255)
 		subdev_8255_cleanup(dev, dev->subdevices + 3);
 	if (dev->irq)
 		free_irq(dev->irq, dev);
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index 75764e8..83016b4 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -37,8 +37,6 @@ port, bit 0; channel 8 corresponds to the input port, bit 0.
 
 Direction configuration: channels 0-7 output, 8-15 input (8225 device
 emu as port A output, port B input, port C N/A).
-
-IRQ is assigned but not used.
 */
 
 #include <linux/interrupt.h>
@@ -53,111 +51,13 @@ IRQ is assigned but not used.
 
 static struct pcmcia_device *pcmcia_cur_dev;
 
-#define DIO700_SIZE 8		/*  size of io region used by board */
-
-static int dio700_attach(struct comedi_device *dev,
-			 struct comedi_devconfig *it);
-static void dio700_detach(struct comedi_device *dev);
-
-enum dio700_bustype { pcmcia_bustype };
-
 struct dio700_board {
 	const char *name;
-	int device_id;		/*  device id for pcmcia board */
-	enum dio700_bustype bustype;	/*  PCMCIA */
-	int have_dio;		/*  have daqcard-700 dio */
-	/*  function pointers so we can use inb/outb or readb/writeb */
-	/*  as appropriate */
-	unsigned int (*read_byte) (unsigned int address);
-	void (*write_byte) (unsigned int byte, unsigned int address);
-};
-
-static const struct dio700_board dio700_boards[] = {
-	{
-	 .name = "daqcard-700",
-	  /*  0x10b is manufacturer id, 0x4743 is device id */
-	 .device_id = 0x4743,
-	 .bustype = pcmcia_bustype,
-	 .have_dio = 1,
-	 },
-	{
-	 .name = "ni_daq_700",
-	  /*  0x10b is manufacturer id, 0x4743 is device id */
-	 .device_id = 0x4743,
-	 .bustype = pcmcia_bustype,
-	 .have_dio = 1,
-	 },
-};
-
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct dio700_board *)dev->board_ptr)
-
-struct dio700_private {
-
-	int data;		/* number of data points left to be taken */
 };
 
-#define devpriv ((struct dio700_private *)dev->private)
-
-static struct comedi_driver driver_dio700 = {
-	.driver_name = "ni_daq_700",
-	.module = THIS_MODULE,
-	.attach = dio700_attach,
-	.detach = dio700_detach,
-	.num_names = ARRAY_SIZE(dio700_boards),
-	.board_name = &dio700_boards[0].name,
-	.offset = sizeof(struct dio700_board),
-};
-
-/*	the real driver routines	*/
-
-#define _700_SIZE 8
-
-#define _700_DATA 0
-
 #define DIO_W		0x04
 #define DIO_R		0x05
 
-struct subdev_700_struct {
-	unsigned long cb_arg;
-	int (*cb_func) (int, int, int, unsigned long);
-	int have_irq;
-};
-
-#define CALLBACK_ARG	(((struct subdev_700_struct *)s->private)->cb_arg)
-#define CALLBACK_FUNC	(((struct subdev_700_struct *)s->private)->cb_func)
-#define subdevpriv	((struct subdev_700_struct *)s->private)
-
-static void do_config(struct comedi_device *dev, struct comedi_subdevice *s);
-
-void subdev_700_interrupt(struct comedi_device *dev, struct comedi_subdevice *s)
-{
-	short d;
-
-	d = CALLBACK_FUNC(0, _700_DATA, 0, CALLBACK_ARG);
-
-	comedi_buf_put(s->async, d);
-	s->async->events |= COMEDI_CB_EOS;
-
-	comedi_event(dev, s);
-}
-EXPORT_SYMBOL(subdev_700_interrupt);
-
-static int subdev_700_cb(int dir, int port, int data, unsigned long arg)
-{
-	/* port is always A for output and B for input (8255 emu) */
-	unsigned long iobase = arg;
-
-	if (dir) {
-		outb(data, iobase + DIO_W);
-		return 0;
-	} else {
-		return inb(iobase + DIO_R);
-	}
-}
-
 static int subdev_700_insn(struct comedi_device *dev,
 			   struct comedi_subdevice *s, struct comedi_insn *insn,
 			   unsigned int *data)
@@ -167,20 +67,20 @@ static int subdev_700_insn(struct comedi_device *dev,
 		s->state |= (data[0] & data[1]);
 
 		if (data[0] & 0xff)
-			CALLBACK_FUNC(1, _700_DATA, s->state & 0xff,
-				      CALLBACK_ARG);
+			outb(s->state & 0xff, dev->iobase + DIO_W);
 	}
 
 	data[1] = s->state & 0xff;
-	data[1] |= CALLBACK_FUNC(0, _700_DATA, 0, CALLBACK_ARG) << 8;
+	data[1] |= inb(dev->iobase + DIO_R);
 
-	return 2;
+	return insn->n;
 }
 
 static int subdev_700_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
 				  struct comedi_insn *insn, unsigned int *data)
 {
+	unsigned int chan = 1 << CR_CHAN(insn->chanspec);
 
 	switch (data[0]) {
 	case INSN_CONFIG_DIO_INPUT:
@@ -188,291 +88,81 @@ static int subdev_700_insn_config(struct comedi_device *dev,
 	case INSN_CONFIG_DIO_OUTPUT:
 		break;
 	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->
-		     io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
-		    COMEDI_INPUT;
-		return insn->n;
+		data[1] = (s->io_bits & chan) ? COMEDI_OUTPUT : COMEDI_INPUT;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	return 1;
-}
-
-static void do_config(struct comedi_device *dev, struct comedi_subdevice *s)
-{				/* use powerup defaults */
-	return;
-}
-
-static int subdev_700_cmdtest(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_cmd *cmd)
-{
-	int err = 0;
-	unsigned int tmp;
-
-	/* step 1 */
-
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_FOLLOW;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
-
-	if (err)
-		return 1;
-
-	/* step 2 */
-
-	if (err)
-		return 2;
-
-	/* step 3 */
-
-	if (cmd->start_arg != 0) {
-		cmd->start_arg = 0;
-		err++;
-	}
-	if (cmd->scan_begin_arg != 0) {
-		cmd->scan_begin_arg = 0;
-		err++;
-	}
-	if (cmd->convert_arg != 0) {
-		cmd->convert_arg = 0;
-		err++;
-	}
-	if (cmd->scan_end_arg != 1) {
-		cmd->scan_end_arg = 1;
-		err++;
-	}
-	if (cmd->stop_arg != 0) {
-		cmd->stop_arg = 0;
-		err++;
-	}
-
-	if (err)
-		return 3;
-
-	/* step 4 */
-
-	if (err)
-		return 4;
-
-	return 0;
-}
-
-static int subdev_700_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
-{
-	/* FIXME */
-
-	return 0;
-}
-
-static int subdev_700_cancel(struct comedi_device *dev,
-			     struct comedi_subdevice *s)
-{
-	/* FIXME */
-
-	return 0;
-}
-
-int subdev_700_init(struct comedi_device *dev, struct comedi_subdevice *s,
-		    int (*cb) (int, int, int, unsigned long), unsigned long arg)
-{
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 16;
-	s->range_table = &range_digital;
-	s->maxdata = 1;
-
-	s->private = kmalloc(sizeof(struct subdev_700_struct), GFP_KERNEL);
-	if (!s->private)
-		return -ENOMEM;
-
-	CALLBACK_ARG = arg;
-	if (cb == NULL)
-		CALLBACK_FUNC = subdev_700_cb;
-	 else
-		CALLBACK_FUNC = cb;
-
-	s->insn_bits = subdev_700_insn;
-	s->insn_config = subdev_700_insn_config;
-
-	s->state = 0;
-	s->io_bits = 0x00ff;
-	do_config(dev, s);
-
-	return 0;
-}
-EXPORT_SYMBOL(subdev_700_init);
-
-int subdev_700_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
-			int (*cb) (int, int, int, unsigned long),
-			unsigned long arg)
-{
-	int ret;
-
-	ret = subdev_700_init(dev, s, cb, arg);
-	if (ret < 0)
-		return ret;
-
-	s->do_cmdtest = subdev_700_cmdtest;
-	s->do_cmd = subdev_700_cmd;
-	s->cancel = subdev_700_cancel;
-
-	subdevpriv->have_irq = 1;
-
-	return 0;
+	return insn->n;
 }
-EXPORT_SYMBOL(subdev_700_init_irq);
-
-void subdev_700_cleanup(struct comedi_device *dev, struct comedi_subdevice *s)
-{
-	if (s->private)
-		if (subdevpriv->have_irq)
-
-			kfree(s->private);
-}
-EXPORT_SYMBOL(subdev_700_cleanup);
 
 static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct dio700_board *thisboard = comedi_board(dev);
 	struct comedi_subdevice *s;
-	unsigned long iobase = 0;
-#ifdef incomplete
-	unsigned int irq = 0;
-#endif
 	struct pcmcia_device *link;
+	int ret;
 
-	/* allocate and initialize dev->private */
-	if (alloc_private(dev, sizeof(struct dio700_private)) < 0)
-		return -ENOMEM;
-
-	/*  get base address, irq etc. based on bustype */
-	switch (thisboard->bustype) {
-	case pcmcia_bustype:
-		link = pcmcia_cur_dev;	/* XXX hack */
-		if (!link)
-			return -EIO;
-		iobase = link->resource[0]->start;
-#ifdef incomplete
-		irq = link->irq;
-#endif
-		break;
-	default:
-		printk(KERN_ERR "bug! couldn't determine board type\n");
-		return -EINVAL;
-		break;
-	}
-	printk(KERN_ERR "comedi%d: ni_daq_700: %s, io 0x%lx", dev->minor,
-	       thisboard->name, iobase);
-#ifdef incomplete
-	if (irq)
-		printk(", irq %u", irq);
-
-#endif
-
-	printk("\n");
+	link = pcmcia_cur_dev;	/* XXX hack */
+	if (!link)
+		return -EIO;
 
-	if (iobase == 0) {
-		printk(KERN_ERR "io base address is zero!\n");
+	dev->iobase = link->resource[0]->start;
+	if (!dev->iobase) {
+		dev_err(dev->class_dev, "io base address is zero!\n");
 		return -EINVAL;
 	}
 
-	dev->iobase = iobase;
-
-#ifdef incomplete
-	/* grab our IRQ */
-	dev->irq = irq;
-#endif
-
 	dev->board_name = thisboard->name;
 
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
 
 	/* DAQCard-700 dio */
 	s = dev->subdevices + 0;
-	subdev_700_init(dev, s, NULL, dev->iobase);
+	s->type		= COMEDI_SUBD_DIO;
+	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
+	s->n_chan	= 16;
+	s->range_table	= &range_digital;
+	s->maxdata	= 1;
+	s->insn_bits	= subdev_700_insn;
+	s->insn_config	= subdev_700_insn_config;
+
+	s->state	= 0;
+	s->io_bits	= 0x00ff;
+
+	dev_info(dev->class_dev, "%s: %s, io 0x%lx\n",
+		dev->driver->driver_name,
+		dev->board_name,
+		dev->iobase);
 
 	return 0;
-};
+}
 
 static void dio700_detach(struct comedi_device *dev)
 {
-	if (dev->subdevices)
-		subdev_700_cleanup(dev, dev->subdevices + 0);
-	if (thisboard->bustype != pcmcia_bustype && dev->iobase)
-		release_region(dev->iobase, DIO700_SIZE);
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-};
-
-static void dio700_config(struct pcmcia_device *link);
-static void dio700_release(struct pcmcia_device *link);
-static int dio700_cs_suspend(struct pcmcia_device *p_dev);
-static int dio700_cs_resume(struct pcmcia_device *p_dev);
-
-static int dio700_cs_attach(struct pcmcia_device *);
-static void dio700_cs_detach(struct pcmcia_device *);
+	/* nothing to cleanup */
+}
 
-struct local_info_t {
-	struct pcmcia_device *link;
-	int stop;
-	struct bus_operations *bus;
+static const struct dio700_board dio700_boards[] = {
+	{
+		.name		= "daqcard-700",
+	}, {
+		.name		= "ni_daq_700",
+	},
 };
 
-static int dio700_cs_attach(struct pcmcia_device *link)
-{
-	struct local_info_t *local;
-
-	printk(KERN_INFO "ni_daq_700:  cs-attach\n");
-
-	dev_dbg(&link->dev, "dio700_cs_attach()\n");
-
-	/* Allocate space for private device-specific data */
-	local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
-	if (!local)
-		return -ENOMEM;
-	local->link = link;
-	link->priv = local;
-
-	pcmcia_cur_dev = link;
-
-	dio700_config(link);
-
-	return 0;
-}				/* dio700_cs_attach */
-
-static void dio700_cs_detach(struct pcmcia_device *link)
-{
-	((struct local_info_t *)link->priv)->stop = 1;
-	dio700_release(link);
-
-	/* This points to the parent struct local_info_t struct */
-	kfree(link->priv);
-}
+static struct comedi_driver driver_dio700 = {
+	.driver_name	= "ni_daq_700",
+	.module		= THIS_MODULE,
+	.attach		= dio700_attach,
+	.detach		= dio700_detach,
+	.board_name	= &dio700_boards[0].name,
+	.num_names	= ARRAY_SIZE(dio700_boards),
+	.offset		= sizeof(struct dio700_board),
+};
 
 static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev,
 				void *priv_data)
@@ -483,112 +173,78 @@ static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev,
 	return pcmcia_request_io(p_dev);
 }
 
-static void dio700_config(struct pcmcia_device *link)
+static int dio700_cs_attach(struct pcmcia_device *link)
 {
 	int ret;
 
-	printk(KERN_INFO "ni_daq_700:  cs-config\n");
-
-	dev_dbg(&link->dev, "dio700_config\n");
-
 	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO |
 		CONF_AUTO_SET_IO;
 
 	ret = pcmcia_loop_config(link, dio700_pcmcia_config_loop, NULL);
-	if (ret) {
-		dev_warn(&link->dev, "no configuration found\n");
+	if (ret)
 		goto failed;
-	}
 
 	if (!link->irq)
 		goto failed;
 
 	ret = pcmcia_enable_device(link);
-	if (ret != 0)
+	if (ret)
 		goto failed;
 
-	return;
+	pcmcia_cur_dev = link;
+	return 0;
 
 failed:
-	printk(KERN_INFO "ni_daq_700 cs failed");
-	dio700_release(link);
-
-}				/* dio700_config */
-
-static void dio700_release(struct pcmcia_device *link)
-{
-	dev_dbg(&link->dev, "dio700_release\n");
-
 	pcmcia_disable_device(link);
-}				/* dio700_release */
-
-static int dio700_cs_suspend(struct pcmcia_device *link)
-{
-	struct local_info_t *local = link->priv;
-
-	/* Mark the device as stopped, to block IO until later */
-	local->stop = 1;
-	return 0;
-}				/* dio700_cs_suspend */
+	return ret;
+}
 
-static int dio700_cs_resume(struct pcmcia_device *link)
+static void dio700_cs_detach(struct pcmcia_device *link)
 {
-	struct local_info_t *local = link->priv;
-
-	local->stop = 0;
-	return 0;
-}				/* dio700_cs_resume */
-
-/*====================================================================*/
+	pcmcia_disable_device(link);
+	pcmcia_cur_dev = NULL;
+}
 
 static const struct pcmcia_device_id dio700_cs_ids[] = {
-	/* N.B. These IDs should match those in dio700_boards */
-	PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),	/* daqcard-700 */
+	PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),
 	PCMCIA_DEVICE_NULL
 };
-
-
 MODULE_DEVICE_TABLE(pcmcia, dio700_cs_ids);
-MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>");
-MODULE_DESCRIPTION("Comedi driver for National Instruments "
-		   "PCMCIA DAQCard-700 DIO");
-MODULE_LICENSE("GPL");
 
-struct pcmcia_driver dio700_cs_driver = {
-	.probe = dio700_cs_attach,
-	.remove = dio700_cs_detach,
-	.suspend = dio700_cs_suspend,
-	.resume = dio700_cs_resume,
-	.id_table = dio700_cs_ids,
-	.owner = THIS_MODULE,
-	.name = "ni_daq_700",
+static struct pcmcia_driver dio700_cs_driver = {
+	.name		= "ni_daq_700",
+	.owner		= THIS_MODULE,
+	.probe		= dio700_cs_attach,
+	.remove		= dio700_cs_detach,
+	.id_table	= dio700_cs_ids,
 };
 
-static int __init init_dio700_cs(void)
-{
-	pcmcia_register_driver(&dio700_cs_driver);
-	return 0;
-}
-
-static void __exit exit_dio700_cs(void)
-{
-	pr_debug("ni_daq_700: unloading\n");
-	pcmcia_unregister_driver(&dio700_cs_driver);
-}
-
-int __init init_module(void)
+static int __init dio700_cs_init(void)
 {
 	int ret;
 
-	ret = init_dio700_cs();
+	ret = comedi_driver_register(&driver_dio700);
 	if (ret < 0)
 		return ret;
 
-	return comedi_driver_register(&driver_dio700);
+	ret = pcmcia_register_driver(&dio700_cs_driver);
+	if (ret < 0) {
+		comedi_driver_unregister(&driver_dio700);
+		return ret;
+	}
+
+	return 0;
 }
+module_init(dio700_cs_init);
 
-void __exit cleanup_module(void)
+static void __exit dio700_cs_exit(void)
 {
-	exit_dio700_cs();
+	pcmcia_unregister_driver(&dio700_cs_driver);
 	comedi_driver_unregister(&driver_dio700);
 }
+module_exit(dio700_cs_exit);
+
+MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>");
+MODULE_DESCRIPTION(
+	"Comedi driver for National Instruments PCMCIA DAQCard-700 DIO");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index 493a227..e27cae0 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -116,6 +116,7 @@ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	unsigned int irq = 0;
 #endif
 	struct pcmcia_device *link;
+	int ret;
 
 	/* allocate and initialize dev->private */
 	if (alloc_private(dev, sizeof(struct dio24_private)) < 0)
@@ -158,8 +159,9 @@ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	dev->board_name = thisboard->name;
 
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
 
 	/* 8255 dio */
 	s = dev->subdevices + 0;
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 5334977..ab8b787 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -536,6 +536,7 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
 	unsigned long dma_flags;
 #endif
 	short lsb, msb;
+	int ret;
 
 	printk(KERN_ERR "comedi%d: ni_labpc: %s, io 0x%lx", dev->minor,
 								thisboard->name,
@@ -622,8 +623,9 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
 
 	dev->board_name = thisboard->name;
 
-	if (alloc_subdevices(dev, 5) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 5);
+	if (ret)
+		return ret;
 
 	/* analog input subdevice */
 	s = dev->subdevices + 0;
@@ -1386,6 +1388,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 		break;
 	default:
 		comedi_error(dev, "bug with start_src");
+		spin_unlock_irqrestore(&dev->spinlock, flags);
 		return -1;
 		break;
 	}
@@ -1398,6 +1401,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 		break;
 	default:
 		comedi_error(dev, "bug with stop_src");
+		spin_unlock_irqrestore(&dev->spinlock, flags);
 		return -1;
 	}
 	devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index fd232bc..cf0e0d14 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -3567,8 +3567,7 @@ static int ni_dio_insn_bits(struct comedi_device *dev,
 #ifdef DEBUG_DIO
 	printk("ni_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0], data[1]);
 #endif
-	if (insn->n != 2)
-		return -EINVAL;
+
 	if (data[0]) {
 		/* Perform check to make sure we're not using the
 		   serial part of the dio */
@@ -3585,7 +3584,7 @@ static int ni_dio_insn_bits(struct comedi_device *dev,
 	}
 	data[1] = devpriv->stc_readw(dev, DIO_Parallel_Input_Register);
 
-	return 2;
+	return insn->n;
 }
 
 static int ni_m_series_dio_insn_config(struct comedi_device *dev,
@@ -3629,8 +3628,7 @@ static int ni_m_series_dio_insn_bits(struct comedi_device *dev,
 	printk("ni_m_series_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0],
 	       data[1]);
 #endif
-	if (insn->n != 2)
-		return -EINVAL;
+
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] & data[1]);
@@ -3638,7 +3636,7 @@ static int ni_m_series_dio_insn_bits(struct comedi_device *dev,
 	}
 	data[1] = ni_readl(M_Offset_Static_Digital_Input);
 
-	return 2;
+	return insn->n;
 }
 
 static int ni_cdio_cmdtest(struct comedi_device *dev,
@@ -4406,14 +4404,16 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it)
 	struct comedi_subdevice *s;
 	unsigned j;
 	enum ni_gpct_variant counter_variant;
+	int ret;
 
 	if (boardtype.n_aochan > MAX_N_AO_CHAN) {
 		printk("bug! boardtype.n_aochan > MAX_N_AO_CHAN\n");
 		return -EINVAL;
 	}
 
-	if (alloc_subdevices(dev, NI_NUM_SUBDEVICES) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, NI_NUM_SUBDEVICES);
+	if (ret)
+		return ret;
 
 	/* analog input subdevice */
 
@@ -5394,7 +5394,7 @@ static int ni_pfi_insn_bits(struct comedi_device *dev,
 		ni_writew(s->state, M_Offset_PFI_DO);
 	}
 	data[1] = ni_readw(M_Offset_PFI_DI);
-	return 2;
+	return insn->n;
 }
 
 static int ni_pfi_insn_config(struct comedi_device *dev,
@@ -5483,12 +5483,9 @@ static int ni_rtsi_insn_bits(struct comedi_device *dev,
 			     struct comedi_subdevice *s,
 			     struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = 0;
 
-	return 2;
+	return insn->n;
 }
 
 /* Find best multiplier/divider to try and get the PLL running at 80 MHz
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 37b7008..0a55de9 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -745,8 +745,6 @@ static int ni_pcidio_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] & data[1]);
@@ -754,7 +752,7 @@ static int ni_pcidio_insn_bits(struct comedi_device *dev,
 	}
 	data[1] = readl(devpriv->mite->daq_io_addr + Port_IO(0));
 
-	return 2;
+	return insn->n;
 }
 
 static int ni_pcidio_cmdtest(struct comedi_device *dev,
@@ -1248,8 +1246,8 @@ static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	else
 		n_subdevices = 1;
 
-	ret = alloc_subdevices(dev, n_subdevices);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	if (ret)
 		return ret;
 
 	if (!this_board->is_diodaq) {
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 3974c0d..89f4d43 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -1593,7 +1593,7 @@ static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	int ret;
 
-	dev_info(dev->hw_dev, "comedi%d: ni_pcimio:\n", dev->minor);
+	dev_info(dev->class_dev, "ni_pcimio: attach\n");
 
 	ret = ni_alloc_private(dev);
 	if (ret < 0)
@@ -1603,7 +1603,7 @@ static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	if (ret < 0)
 		return ret;
 
-	dev_dbg(dev->hw_dev, "%s\n", boardtype.name);
+	dev_dbg(dev->class_dev, "%s\n", boardtype.name);
 	dev->board_name = boardtype.name;
 
 	if (boardtype.reg_type & ni_reg_m_series_mask) {
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index 2e7753f..bb72d0b 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -148,8 +148,6 @@ struct pcl711_board {
 	const struct comedi_lrange *ai_range_type;
 };
 
-#define this_board ((const struct pcl711_board *)dev->board_ptr)
-
 struct pcl711_private {
 
 	int board;
@@ -169,6 +167,7 @@ static irqreturn_t pcl711_interrupt(int irq, void *d)
 	int lo, hi;
 	int data;
 	struct comedi_device *dev = d;
+	const struct pcl711_board *board = comedi_board(dev);
 	struct comedi_subdevice *s = dev->subdevices + 0;
 
 	if (!dev->attached) {
@@ -184,7 +183,7 @@ static irqreturn_t pcl711_interrupt(int irq, void *d)
 
 	/* FIXME! Nothing else sets ntrig! */
 	if (!(--devpriv->ntrig)) {
-		if (this_board->is_8112)
+		if (board->is_8112)
 			outb(1, dev->iobase + PCL711_MODE);
 		else
 			outb(0, dev->iobase + PCL711_MODE);
@@ -197,13 +196,14 @@ static irqreturn_t pcl711_interrupt(int irq, void *d)
 
 static void pcl711_set_changain(struct comedi_device *dev, int chan)
 {
+	const struct pcl711_board *board = comedi_board(dev);
 	int chan_register;
 
 	outb(CR_RANGE(chan), dev->iobase + PCL711_GAIN);
 
 	chan_register = CR_CHAN(chan);
 
-	if (this_board->is_8112) {
+	if (board->is_8112) {
 
 		/*
 		 *  Set the correct channel.  The two channel banks are switched
@@ -225,6 +225,7 @@ static void pcl711_set_changain(struct comedi_device *dev, int chan)
 static int pcl711_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
+	const struct pcl711_board *board = comedi_board(dev);
 	int i, n;
 	int hi, lo;
 
@@ -237,7 +238,7 @@ static int pcl711_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 		 */
 		outb(1, dev->iobase + PCL711_MODE);
 
-		if (!this_board->is_8112)
+		if (!board->is_8112)
 			outb(0, dev->iobase + PCL711_SOFTTRIG);
 
 		i = PCL711_TIMEOUT;
@@ -448,13 +449,10 @@ static int pcl711_di_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = inb(dev->iobase + PCL711_DI_LO) |
 	    (inb(dev->iobase + PCL711_DI_HI) << 8);
 
-	return 2;
+	return insn->n;
 }
 
 /* Digital port write - Untested on 8112 */
@@ -462,9 +460,6 @@ static int pcl711_do_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= data[0] & data[1];
@@ -476,11 +471,12 @@ static int pcl711_do_insn_bits(struct comedi_device *dev,
 
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct pcl711_board *board = comedi_board(dev);
 	int ret;
 	unsigned long iobase;
 	unsigned int irq;
@@ -498,12 +494,11 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	/* there should be a sanity check here */
 
-	/* set up some name stuff */
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 
 	/* grab our IRQ */
 	irq = it->options[1];
-	if (irq > this_board->maxirq) {
+	if (irq > board->maxirq) {
 		printk(KERN_ERR "irq out of range\n");
 		return -EINVAL;
 	}
@@ -517,8 +512,8 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	}
 	dev->irq = irq;
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		return ret;
 
 	ret = alloc_private(dev, sizeof(struct pcl711_private));
@@ -529,10 +524,10 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	/* AI subdevice */
 	s->type = COMEDI_SUBD_AI;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
-	s->n_chan = this_board->n_aichan;
+	s->n_chan = board->n_aichan;
 	s->maxdata = 0xfff;
 	s->len_chanlist = 1;
-	s->range_table = this_board->ai_range_type;
+	s->range_table = board->ai_range_type;
 	s->insn_read = pcl711_ai_insn;
 	if (irq) {
 		dev->read_subdev = s;
@@ -545,7 +540,7 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	/* AO subdevice */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = this_board->n_aochan;
+	s->n_chan = board->n_aochan;
 	s->maxdata = 0xfff;
 	s->len_chanlist = 1;
 	s->range_table = &range_bipolar5;
@@ -577,7 +572,7 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	   this is the "base value" for the mode register, which is
 	   used for the irq on the PCL711
 	 */
-	if (this_board->is_pcl711b)
+	if (board->is_pcl711b)
 		devpriv->mode = (dev->irq << 4);
 
 	/* clear DAC */
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index 1f66fe1..c8fe23c 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -67,8 +67,6 @@ struct pcl724_board {
 	char is_pet48;
 };
 
-#define this_board ((const struct pcl724_board *)dev->board_ptr)
-
 static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
 {
 	unsigned long iobase = arg;
@@ -100,6 +98,7 @@ static int subdev_8255mapped_cb(int dir, int port, int data,
 
 static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct pcl724_board *board = comedi_board(dev);
 	unsigned long iobase;
 	unsigned int iorange;
 	int ret, i, n_subdevices;
@@ -108,12 +107,12 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 #endif
 
 	iobase = it->options[0];
-	iorange = this_board->io_range;
-	if ((this_board->can_have96) && ((it->options[1] == 1)
+	iorange = board->io_range;
+	if ((board->can_have96) && ((it->options[1] == 1)
 					 || (it->options[1] == 96)))
 		iorange = PCL722_96_SIZE; /* PCL-724 in 96 DIO configuration */
 	printk(KERN_INFO "comedi%d: pcl724: board=%s, 0x%03lx ", dev->minor,
-	       this_board->name, iobase);
+	       board->name, iobase);
 	if (!request_region(iobase, iorange, "pcl724")) {
 		printk("I/O port conflict\n");
 		return -EIO;
@@ -121,14 +120,14 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	dev->iobase = iobase;
 
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 
 #ifdef PCL724_IRQ
 	irq = 0;
-	if (this_board->IRQbits != 0) {	/* board support IRQ */
+	if (board->IRQbits != 0) {	/* board support IRQ */
 		irq = it->options[1];
 		if (irq) {	/* we want to use IRQ */
-			if (((1 << irq) & this_board->IRQbits) == 0) {
+			if (((1 << irq) & board->IRQbits) == 0) {
 				printk(KERN_WARNING
 				       ", IRQ %u is out of allowed range, "
 				       "DISABLING IT", irq);
@@ -152,17 +151,17 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	printk("\n");
 
-	n_subdevices = this_board->numofports;
-	if ((this_board->can_have96) && ((it->options[1] == 1)
+	n_subdevices = board->numofports;
+	if ((board->can_have96) && ((it->options[1] == 1)
 					 || (it->options[1] == 96)))
 		n_subdevices = 4;	/*  PCL-724 in 96 DIO configuration */
 
-	ret = alloc_subdevices(dev, n_subdevices);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	if (ret)
 		return ret;
 
 	for (i = 0; i < dev->n_subdevices; i++) {
-		if (this_board->is_pet48) {
+		if (board->is_pet48) {
 			subdev_8255_init(dev, dev->subdevices + i,
 					 subdev_8255mapped_cb,
 					 (unsigned long)(dev->iobase +
@@ -179,6 +178,7 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 static void pcl724_detach(struct comedi_device *dev)
 {
+	const struct pcl724_board *board = comedi_board(dev);
 	int i;
 
 	for (i = 0; i < dev->n_subdevices; i++)
@@ -187,7 +187,7 @@ static void pcl724_detach(struct comedi_device *dev)
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 #endif
-	release_region(dev->iobase, this_board->io_range);
+	release_region(dev->iobase, board->io_range);
 }
 
 static const struct pcl724_board boardtypes[] = {
diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c
index 83a6fa5..d5b60cf 100644
--- a/drivers/staging/comedi/drivers/pcl725.c
+++ b/drivers/staging/comedi/drivers/pcl725.c
@@ -23,9 +23,6 @@ Devices: [Advantech] PCL-725 (pcl725)
 static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] & data[1]);
@@ -34,24 +31,22 @@ static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 static int pcl725_di_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = inb(dev->iobase + PCL725_DI);
 
-	return 2;
+	return insn->n;
 }
 
 static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct comedi_subdevice *s;
 	unsigned long iobase;
+	int ret;
 
 	iobase = it->options[0];
 	printk(KERN_INFO "comedi%d: pcl725: 0x%04lx ", dev->minor, iobase);
@@ -63,8 +58,9 @@ static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	dev->iobase = iobase;
 	dev->irq = 0;
 
-	if (alloc_subdevices(dev, 2) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 2);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* do */
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index d25c30c..2b10f1d 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -145,8 +145,6 @@ static const struct pcl726_board boardtypes[] = {
 	 &rangelist_728[0],},
 };
 
-#define this_board ((const struct pcl726_board *)dev->board_ptr)
-
 struct pcl726_private {
 
 	int bipolar[12];
@@ -197,38 +195,37 @@ static int pcl726_di_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
+	const struct pcl726_board *board = comedi_board(dev);
 
-	data[1] = inb(dev->iobase + this_board->di_lo) |
-	    (inb(dev->iobase + this_board->di_hi) << 8);
+	data[1] = inb(dev->iobase + board->di_lo) |
+	    (inb(dev->iobase + board->di_hi) << 8);
 
-	return 2;
+	return insn->n;
 }
 
 static int pcl726_do_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
+	const struct pcl726_board *board = comedi_board(dev);
 
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= data[0] & data[1];
 	}
 	if (data[1] & 0x00ff)
-		outb(s->state & 0xff, dev->iobase + this_board->do_lo);
+		outb(s->state & 0xff, dev->iobase + board->do_lo);
 	if (data[1] & 0xff00)
-		outb((s->state >> 8), dev->iobase + this_board->do_hi);
+		outb((s->state >> 8), dev->iobase + board->do_hi);
 
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct pcl726_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	unsigned long iobase;
 	unsigned int iorange;
@@ -238,9 +235,9 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 #endif
 
 	iobase = it->options[0];
-	iorange = this_board->io_range;
+	iorange = board->io_range;
 	printk(KERN_WARNING "comedi%d: pcl726: board=%s, 0x%03lx ", dev->minor,
-	       this_board->name, iobase);
+	       board->name, iobase);
 	if (!request_region(iobase, iorange, "pcl726")) {
 		printk(KERN_WARNING "I/O port conflict\n");
 		return -EIO;
@@ -248,7 +245,7 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	dev->iobase = iobase;
 
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 
 	ret = alloc_private(dev, sizeof(struct pcl726_private));
 	if (ret < 0)
@@ -289,31 +286,31 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	printk("\n");
 
-	ret = alloc_subdevices(dev, 3);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices + 0;
 	/* ao */
 	s->type = COMEDI_SUBD_AO;
 	s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
-	s->n_chan = this_board->n_aochan;
+	s->n_chan = board->n_aochan;
 	s->maxdata = 0xfff;
 	s->len_chanlist = 1;
 	s->insn_write = pcl726_ao_insn;
 	s->insn_read = pcl726_ao_insn_read;
 	s->range_table_list = devpriv->rangelist;
-	for (i = 0; i < this_board->n_aochan; i++) {
+	for (i = 0; i < board->n_aochan; i++) {
 		int j;
 
 		j = it->options[2 + 1];
-		if ((j < 0) || (j >= this_board->num_of_ranges)) {
+		if ((j < 0) || (j >= board->num_of_ranges)) {
 			printk
 			    ("Invalid range for channel %d! Must be 0<=%d<%d\n",
-			     i, j, this_board->num_of_ranges - 1);
+			     i, j, board->num_of_ranges - 1);
 			j = 0;
 		}
-		devpriv->rangelist[i] = this_board->range_type_list[j];
+		devpriv->rangelist[i] = board->range_type_list[j];
 		if (devpriv->rangelist[i]->range[0].min ==
 		    -devpriv->rangelist[i]->range[0].max)
 			devpriv->bipolar[i] = 1;	/* bipolar range */
@@ -321,7 +318,7 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	s = dev->subdevices + 1;
 	/* di */
-	if (!this_board->have_dio) {
+	if (!board->have_dio) {
 		s->type = COMEDI_SUBD_UNUSED;
 	} else {
 		s->type = COMEDI_SUBD_DI;
@@ -335,7 +332,7 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	s = dev->subdevices + 2;
 	/* do */
-	if (!this_board->have_dio) {
+	if (!board->have_dio) {
 		s->type = COMEDI_SUBD_UNUSED;
 	} else {
 		s->type = COMEDI_SUBD_DO;
@@ -352,12 +349,14 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 static void pcl726_detach(struct comedi_device *dev)
 {
+	const struct pcl726_board *board = comedi_board(dev);
+
 #ifdef ACL6126_IRQ
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 #endif
 	if (dev->iobase)
-		release_region(dev->iobase, this_board->io_range);
+		release_region(dev->iobase, board->io_range);
 }
 
 static struct comedi_driver pcl726_driver = {
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index e11704a..4675ec5 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -32,14 +32,9 @@ struct pcl730_board {
 	unsigned int io_range;	/*  len of I/O space */
 };
 
-#define this_board ((const struct pcl730_board *)dev->board_ptr)
-
 static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] & data[1]);
@@ -53,41 +48,41 @@ static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 static int pcl730_di_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = inb(dev->iobase + ((unsigned long)s->private)) |
 	    (inb(dev->iobase + ((unsigned long)s->private) + 1) << 8);
 
-	return 2;
+	return insn->n;
 }
 
 static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct pcl730_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	unsigned long iobase;
 	unsigned int iorange;
+	int ret;
 
 	iobase = it->options[0];
-	iorange = this_board->io_range;
+	iorange = board->io_range;
 	printk(KERN_INFO "comedi%d: pcl730: board=%s 0x%04lx ", dev->minor,
-	       this_board->name, iobase);
+	       board->name, iobase);
 	if (!request_region(iobase, iorange, "pcl730")) {
 		printk("I/O port conflict\n");
 		return -EIO;
 	}
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 	dev->iobase = iobase;
 	dev->irq = 0;
 
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* Isolated do */
@@ -136,8 +131,10 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 static void pcl730_detach(struct comedi_device *dev)
 {
+	const struct pcl730_board *board = comedi_board(dev);
+
 	if (dev->iobase)
-		release_region(dev->iobase, this_board->io_range);
+		release_region(dev->iobase, board->io_range);
 }
 
 static const struct pcl730_board boardtypes[] = {
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index 51f4ca9..578fd89 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -119,9 +119,6 @@
 
 #include "8253.h"
 
-/* if this is defined then a lot of messages is printed */
-#undef PCL812_EXTDEBUG
-
 /* hardware types of the cards */
 #define boardPCL812PG	      0	/* and ACL-8112PG */
 #define boardPCL813B	      1
@@ -336,8 +333,6 @@ struct pcl812_board {
 	unsigned char haveMPC508;	/*  1=board use MPC508A multiplexor */
 };
 
-#define this_board ((const struct pcl812_board *)dev->board_ptr)
-
 struct pcl812_private {
 
 	unsigned char valid;	/*  =1 device is OK */
@@ -506,13 +501,10 @@ static int pcl812_di_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = inb(dev->iobase + PCL812_DI_LO);
 	data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8;
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -522,9 +514,6 @@ static int pcl812_do_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= data[0] & data[1];
@@ -533,26 +522,8 @@ static int pcl812_do_insn_bits(struct comedi_device *dev,
 	}
 	data[1] = s->state;
 
-	return 2;
-}
-
-#ifdef PCL812_EXTDEBUG
-/*
-==============================================================================
-*/
-static void pcl812_cmdtest_out(int e, struct comedi_cmd *cmd)
-{
-	printk(KERN_INFO "pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
-	       cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
-	printk(KERN_INFO "pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
-	       cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
-	printk(KERN_INFO "pcl812 e=%d stopsrc=%x scanend=%x\n", e,
-	       cmd->stop_src, cmd->scan_end_src);
-	printk(KERN_INFO "pcl812 e=%d stoparg=%d scanendarg=%d "
-	       "chanlistlen=%d\n", e, cmd->stop_arg, cmd->scan_end_arg,
-	       cmd->chanlist_len);
+	return insn->n;
 }
-#endif
 
 /*
 ==============================================================================
@@ -560,13 +531,10 @@ static void pcl812_cmdtest_out(int e, struct comedi_cmd *cmd)
 static int pcl812_ai_cmdtest(struct comedi_device *dev,
 			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
+	const struct pcl812_board *board = comedi_board(dev);
 	int err = 0;
 	int tmp, divisor1, divisor2;
 
-#ifdef PCL812_EXTDEBUG
-	printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...)\n");
-	pcl812_cmdtest_out(-1, cmd);
-#endif
 	/* step 1: make sure trigger sources are trivially valid */
 
 	tmp = cmd->start_src;
@@ -598,60 +566,19 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
 	if (!cmd->stop_src || tmp != cmd->stop_src)
 		err++;
 
-	if (err) {
-#ifdef PCL812_EXTDEBUG
-		pcl812_cmdtest_out(1, cmd);
-		printk
-		    ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=1\n",
-		     err);
-#endif
+	if (err)
 		return 1;
-	}
 
 	/*
 	 * step 2: make sure trigger sources are
 	 * unique and mutually compatible
 	 */
 
-	if (cmd->start_src != TRIG_NOW) {
-		cmd->start_src = TRIG_NOW;
-		err++;
-	}
-
-	if (cmd->scan_begin_src != TRIG_FOLLOW) {
-		cmd->scan_begin_src = TRIG_FOLLOW;
-		err++;
-	}
-
-	if (devpriv->use_ext_trg) {
-		if (cmd->convert_src != TRIG_EXT) {
-			cmd->convert_src = TRIG_EXT;
-			err++;
-		}
-	} else {
-		if (cmd->convert_src != TRIG_TIMER) {
-			cmd->convert_src = TRIG_TIMER;
-			err++;
-		}
-	}
-
-	if (cmd->scan_end_src != TRIG_COUNT) {
-		cmd->scan_end_src = TRIG_COUNT;
-		err++;
-	}
-
 	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
 		err++;
 
-	if (err) {
-#ifdef PCL812_EXTDEBUG
-		pcl812_cmdtest_out(2, cmd);
-		printk
-		    ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=2\n",
-		     err);
-#endif
+	if (err)
 		return 2;
-	}
 
 	/* step 3: make sure arguments are trivially compatible */
 
@@ -666,8 +593,8 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
 	}
 
 	if (cmd->convert_src == TRIG_TIMER) {
-		if (cmd->convert_arg < this_board->ai_ns_min) {
-			cmd->convert_arg = this_board->ai_ns_min;
+		if (cmd->convert_arg < board->ai_ns_min) {
+			cmd->convert_arg = board->ai_ns_min;
 			err++;
 		}
 	} else {		/* TRIG_EXT */
@@ -682,7 +609,7 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
 		err++;
 	}
 	if (cmd->chanlist_len > MAX_CHANLIST_LEN) {
-		cmd->chanlist_len = this_board->n_aichan;
+		cmd->chanlist_len = board->n_aichan;
 		err++;
 	}
 	if (cmd->scan_end_arg != cmd->chanlist_len) {
@@ -701,37 +628,24 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
 		}
 	}
 
-	if (err) {
-#ifdef PCL812_EXTDEBUG
-		pcl812_cmdtest_out(3, cmd);
-		printk
-		    ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=3\n",
-		     err);
-#endif
+	if (err)
 		return 3;
-	}
 
 	/* step 4: fix up any arguments */
 
 	if (cmd->convert_src == TRIG_TIMER) {
 		tmp = cmd->convert_arg;
-		i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1,
+		i8253_cascade_ns_to_timer(board->i8254_osc_base, &divisor1,
 					  &divisor2, &cmd->convert_arg,
 					  cmd->flags & TRIG_ROUND_MASK);
-		if (cmd->convert_arg < this_board->ai_ns_min)
-			cmd->convert_arg = this_board->ai_ns_min;
+		if (cmd->convert_arg < board->ai_ns_min)
+			cmd->convert_arg = board->ai_ns_min;
 		if (tmp != cmd->convert_arg)
 			err++;
 	}
 
-	if (err) {
-#ifdef PCL812_EXTDEBUG
-		printk
-		    ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=4\n",
-		     err);
-#endif
+	if (err)
 		return 4;
-	}
 
 	return 0;
 }
@@ -741,13 +655,10 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
 */
 static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	const struct pcl812_board *board = comedi_board(dev);
 	unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes;
 	struct comedi_cmd *cmd = &s->async->cmd;
 
-#ifdef PCL812_EXTDEBUG
-	printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n");
-#endif
-
 	if (cmd->start_src != TRIG_NOW)
 		return -EINVAL;
 	if (cmd->scan_begin_src != TRIG_FOLLOW)
@@ -767,9 +678,9 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 		return -EINVAL;
 
 	if (cmd->convert_src == TRIG_TIMER) {
-		if (cmd->convert_arg < this_board->ai_ns_min)
-			cmd->convert_arg = this_board->ai_ns_min;
-		i8253_cascade_ns_to_timer(this_board->i8254_osc_base,
+		if (cmd->convert_arg < board->ai_ns_min)
+			cmd->convert_arg = board->ai_ns_min;
+		i8253_cascade_ns_to_timer(board->i8254_osc_base,
 					  &divisor1, &divisor2,
 					  &cmd->convert_arg,
 					  cmd->flags & TRIG_ROUND_MASK);
@@ -871,13 +782,6 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 		set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
 		release_dma_lock(dma_flags);
 		enable_dma(devpriv->dma);
-#ifdef PCL812_EXTDEBUG
-		printk
-		    ("pcl812 EDBG:   DMA %d PTR 0x%0x/0x%0x LEN %u/%u EOS %d\n",
-		     devpriv->dma, devpriv->hwdmaptr[0],
-		     devpriv->hwdmaptr[1], devpriv->dmabytestomove[0],
-		     devpriv->dmabytestomove[1], devpriv->ai_eos);
-#endif
 	}
 
 	switch (cmd->convert_src) {
@@ -891,10 +795,6 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 	else							/*  let's go! */
 		outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE);
 
-#ifdef PCL812_EXTDEBUG
-	printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_ai_cmd(...)\n");
-#endif
-
 	return 0;
 }
 
@@ -1014,9 +914,6 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
 	int len, bufptr;
 	short *ptr;
 
-#ifdef PCL812_EXTDEBUG
-	printk(KERN_DEBUG "pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n");
-#endif
 	ptr = (short *)devpriv->dmabuf[devpriv->next_dma_buf];
 	len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) -
 	    devpriv->ai_poll_ptr;
@@ -1049,9 +946,6 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
 
 	transfer_from_dma_buf(dev, s, ptr, bufptr, len);
 
-#ifdef PCL812_EXTDEBUG
-	printk(KERN_DEBUG "pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n");
-#endif
 	return IRQ_HANDLED;
 }
 
@@ -1168,10 +1062,6 @@ static void setup_range_channel(struct comedi_device *dev,
 static void start_pacer(struct comedi_device *dev, int mode,
 			unsigned int divisor1, unsigned int divisor2)
 {
-#ifdef PCL812_EXTDEBUG
-	printk(KERN_DEBUG "pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
-	       divisor1, divisor2);
-#endif
 	outb(0xb4, dev->iobase + PCL812_CTRCTL);
 	outb(0x74, dev->iobase + PCL812_CTRCTL);
 	udelay(1);
@@ -1182,9 +1072,6 @@ static void start_pacer(struct comedi_device *dev, int mode,
 		outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1);
 		outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1);
 	}
-#ifdef PCL812_EXTDEBUG
-	printk(KERN_DEBUG "pcl812 EDBG: END: start_pacer(...)\n");
-#endif
 }
 
 /*
@@ -1192,6 +1079,7 @@ static void start_pacer(struct comedi_device *dev, int mode,
 */
 static void free_resources(struct comedi_device *dev)
 {
+	const struct pcl812_board *board = comedi_board(dev);
 
 	if (dev->private) {
 		if (devpriv->dmabuf[0])
@@ -1204,7 +1092,7 @@ static void free_resources(struct comedi_device *dev)
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->iobase)
-		release_region(dev->iobase, this_board->io_range);
+		release_region(dev->iobase, board->io_range);
 }
 
 /*
@@ -1213,9 +1101,6 @@ static void free_resources(struct comedi_device *dev)
 static int pcl812_ai_cancel(struct comedi_device *dev,
 			    struct comedi_subdevice *s)
 {
-#ifdef PCL812_EXTDEBUG
-	printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n");
-#endif
 	if (devpriv->ai_dma)
 		disable_dma(devpriv->dma);
 	outb(0, dev->iobase + PCL812_CLRINT);	/* clear INT request */
@@ -1223,9 +1108,6 @@ static int pcl812_ai_cancel(struct comedi_device *dev,
 	outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
 	start_pacer(dev, -1, 0, 0);	/*  stop 8254 */
 	outb(0, dev->iobase + PCL812_CLRINT);	/* clear INT request */
-#ifdef PCL812_EXTDEBUG
-	printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_ai_cancel(...)\n");
-#endif
 	return 0;
 }
 
@@ -1234,15 +1116,14 @@ static int pcl812_ai_cancel(struct comedi_device *dev,
 */
 static void pcl812_reset(struct comedi_device *dev)
 {
-#ifdef PCL812_EXTDEBUG
-	printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_reset(...)\n");
-#endif
+	const struct pcl812_board *board = comedi_board(dev);
+
 	outb(0, dev->iobase + PCL812_MUX);
 	outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN);
 	devpriv->old_chan_reg = -1;	/*  invalidate chain/gain memory */
 	devpriv->old_gain_reg = -1;
 
-	switch (this_board->board_type) {
+	switch (board->board_type) {
 	case boardPCL812PG:
 	case boardPCL812:
 	case boardACL8112:
@@ -1266,13 +1147,11 @@ static void pcl812_reset(struct comedi_device *dev)
 		break;
 	}
 	udelay(5);
-#ifdef PCL812_EXTDEBUG
-	printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_reset(...)\n");
-#endif
 }
 
 static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct pcl812_board *board = comedi_board(dev);
 	int ret, subdev;
 	unsigned long iobase;
 	unsigned int irq;
@@ -1283,9 +1162,9 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	iobase = it->options[0];
 	printk(KERN_INFO "comedi%d: pcl812:  board=%s, ioport=0x%03lx",
-	       dev->minor, this_board->name, iobase);
+	       dev->minor, board->name, iobase);
 
-	if (!request_region(iobase, this_board->io_range, "pcl812")) {
+	if (!request_region(iobase, board->io_range, "pcl812")) {
 		printk("I/O port conflict\n");
 		return -EIO;
 	}
@@ -1297,13 +1176,13 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		return ret;	/* Can't alloc mem */
 	}
 
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 
 	irq = 0;
-	if (this_board->IRQbits != 0) {	/* board support IRQ */
+	if (board->IRQbits != 0) {	/* board support IRQ */
 		irq = it->options[1];
 		if (irq) {	/* we want to use IRQ */
-			if (((1 << irq) & this_board->IRQbits) == 0) {
+			if (((1 << irq) & board->IRQbits) == 0) {
 				printk
 				    (", IRQ %u is out of allowed range, "
 				     "DISABLING IT", irq);
@@ -1328,9 +1207,9 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	devpriv->dma = dma;
 	if (!dev->irq)
 		goto no_dma;	/* if we haven't IRQ, we can't use DMA */
-	if (this_board->DMAbits != 0) {	/* board support DMA */
+	if (board->DMAbits != 0) {	/* board support DMA */
 		dma = it->options[2];
-		if (((1 << dma) & this_board->DMAbits) == 0) {
+		if (((1 << dma) & board->DMAbits) == 0) {
 			printk(", DMA is out of allowed range, FAIL!\n");
 			return -EINVAL;	/* Bad DMA */
 		}
@@ -1369,17 +1248,17 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 no_dma:
 
 	n_subdevices = 0;
-	if (this_board->n_aichan > 0)
+	if (board->n_aichan > 0)
 		n_subdevices++;
-	if (this_board->n_aochan > 0)
+	if (board->n_aochan > 0)
 		n_subdevices++;
-	if (this_board->n_dichan > 0)
+	if (board->n_dichan > 0)
 		n_subdevices++;
-	if (this_board->n_dochan > 0)
+	if (board->n_dochan > 0)
 		n_subdevices++;
 
-	ret = alloc_subdevices(dev, n_subdevices);
-	if (ret < 0) {
+	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	if (ret) {
 		free_resources(dev);
 		return ret;
 	}
@@ -1387,46 +1266,46 @@ no_dma:
 	subdev = 0;
 
 	/* analog input */
-	if (this_board->n_aichan > 0) {
+	if (board->n_aichan > 0) {
 		s = dev->subdevices + subdev;
 		s->type = COMEDI_SUBD_AI;
 		s->subdev_flags = SDF_READABLE;
-		switch (this_board->board_type) {
+		switch (board->board_type) {
 		case boardA821:
 			if (it->options[2] == 1) {
-				s->n_chan = this_board->n_aichan_diff;
+				s->n_chan = board->n_aichan_diff;
 				s->subdev_flags |= SDF_DIFF;
 				devpriv->use_diff = 1;
 			} else {
-				s->n_chan = this_board->n_aichan;
+				s->n_chan = board->n_aichan;
 				s->subdev_flags |= SDF_GROUND;
 			}
 			break;
 		case boardACL8112:
 		case boardACL8216:
 			if (it->options[4] == 1) {
-				s->n_chan = this_board->n_aichan_diff;
+				s->n_chan = board->n_aichan_diff;
 				s->subdev_flags |= SDF_DIFF;
 				devpriv->use_diff = 1;
 			} else {
-				s->n_chan = this_board->n_aichan;
+				s->n_chan = board->n_aichan;
 				s->subdev_flags |= SDF_GROUND;
 			}
 			break;
 		default:
-			s->n_chan = this_board->n_aichan;
+			s->n_chan = board->n_aichan;
 			s->subdev_flags |= SDF_GROUND;
 			break;
 		}
-		s->maxdata = this_board->ai_maxdata;
+		s->maxdata = board->ai_maxdata;
 		s->len_chanlist = MAX_CHANLIST_LEN;
-		s->range_table = this_board->rangelist_ai;
-		if (this_board->board_type == boardACL8216)
+		s->range_table = board->rangelist_ai;
+		if (board->board_type == boardACL8216)
 			s->insn_read = acl8216_ai_insn_read;
 		else
 			s->insn_read = pcl812_ai_insn_read;
 
-		devpriv->use_MPC = this_board->haveMPC508;
+		devpriv->use_MPC = board->haveMPC508;
 		s->cancel = pcl812_ai_cancel;
 		if (dev->irq) {
 			dev->read_subdev = s;
@@ -1435,7 +1314,7 @@ no_dma:
 			s->do_cmd = pcl812_ai_cmd;
 			s->poll = pcl812_ai_poll;
 		}
-		switch (this_board->board_type) {
+		switch (board->board_type) {
 		case boardPCL812PG:
 			if (it->options[4] == 1)
 				s->range_table = &range_pcl812pg2_ai;
@@ -1529,17 +1408,17 @@ no_dma:
 	}
 
 	/* analog output */
-	if (this_board->n_aochan > 0) {
+	if (board->n_aochan > 0) {
 		s = dev->subdevices + subdev;
 		s->type = COMEDI_SUBD_AO;
 		s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
-		s->n_chan = this_board->n_aochan;
+		s->n_chan = board->n_aochan;
 		s->maxdata = 0xfff;
 		s->len_chanlist = 1;
-		s->range_table = this_board->rangelist_ao;
+		s->range_table = board->rangelist_ao;
 		s->insn_read = pcl812_ao_insn_read;
 		s->insn_write = pcl812_ao_insn_write;
-		switch (this_board->board_type) {
+		switch (board->board_type) {
 		case boardA821:
 			if (it->options[3] == 1)
 				s->range_table = &range_unipolar10;
@@ -1558,32 +1437,32 @@ no_dma:
 	}
 
 	/* digital input */
-	if (this_board->n_dichan > 0) {
+	if (board->n_dichan > 0) {
 		s = dev->subdevices + subdev;
 		s->type = COMEDI_SUBD_DI;
 		s->subdev_flags = SDF_READABLE;
-		s->n_chan = this_board->n_dichan;
+		s->n_chan = board->n_dichan;
 		s->maxdata = 1;
-		s->len_chanlist = this_board->n_dichan;
+		s->len_chanlist = board->n_dichan;
 		s->range_table = &range_digital;
 		s->insn_bits = pcl812_di_insn_bits;
 		subdev++;
 	}
 
 	/* digital output */
-	if (this_board->n_dochan > 0) {
+	if (board->n_dochan > 0) {
 		s = dev->subdevices + subdev;
 		s->type = COMEDI_SUBD_DO;
 		s->subdev_flags = SDF_WRITABLE;
-		s->n_chan = this_board->n_dochan;
+		s->n_chan = board->n_dochan;
 		s->maxdata = 1;
-		s->len_chanlist = this_board->n_dochan;
+		s->len_chanlist = board->n_dochan;
 		s->range_table = &range_digital;
 		s->insn_bits = pcl812_do_insn_bits;
 		subdev++;
 	}
 
-	switch (this_board->board_type) {
+	switch (board->board_type) {
 	case boardACL8216:
 		devpriv->ai_is16b = 1;
 	case boardPCL812PG:
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index cc67b6d..ba6911f 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -126,7 +126,6 @@ struct pcl816_board {
 };
 
 #define devpriv ((struct pcl816_private *)dev->private)
-#define this_board ((const struct pcl816_board *)dev->board_ptr)
 
 #ifdef unused
 static int RTC_lock;	/* RTC lock */
@@ -415,8 +414,8 @@ static irqreturn_t interrupt_pcl816(int irq, void *d)
 	}
 
 	outb(0, dev->iobase + PCL816_CLRINT);	/* clear INT request */
-	if ((!dev->irq) | (!devpriv->irq_free) | (!devpriv->irq_blocked) |
-	    (!devpriv->int816_mode)) {
+	if (!dev->irq || !devpriv->irq_free || !devpriv->irq_blocked ||
+	    !devpriv->int816_mode) {
 		if (devpriv->irq_was_now_closed) {
 			devpriv->irq_was_now_closed = 0;
 			/*  comedi_error(dev,"last IRQ.."); */
@@ -451,6 +450,7 @@ static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
 static int pcl816_ai_cmdtest(struct comedi_device *dev,
 			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
+	const struct pcl816_board *board = comedi_board(dev);
 	int err = 0;
 	int tmp, divisor1 = 0, divisor2 = 0;
 
@@ -493,26 +493,11 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
 	 * are unique and mutually compatible
 	 */
 
-	if (cmd->start_src != TRIG_NOW) {
-		cmd->start_src = TRIG_NOW;
-		err++;
-	}
-
-	if (cmd->scan_begin_src != TRIG_FOLLOW) {
-		cmd->scan_begin_src = TRIG_FOLLOW;
-		err++;
-	}
-
 	if (cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_TIMER) {
 		cmd->convert_src = TRIG_TIMER;
 		err++;
 	}
 
-	if (cmd->scan_end_src != TRIG_COUNT) {
-		cmd->scan_end_src = TRIG_COUNT;
-		err++;
-	}
-
 	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
 		err++;
 
@@ -531,8 +516,8 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
 		err++;
 	}
 	if (cmd->convert_src == TRIG_TIMER) {
-		if (cmd->convert_arg < this_board->ai_ns_min) {
-			cmd->convert_arg = this_board->ai_ns_min;
+		if (cmd->convert_arg < board->ai_ns_min) {
+			cmd->convert_arg = board->ai_ns_min;
 			err++;
 		}
 	} else {		/* TRIG_EXT */
@@ -565,12 +550,12 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
 	/* step 4: fix up any arguments */
 	if (cmd->convert_src == TRIG_TIMER) {
 		tmp = cmd->convert_arg;
-		i8253_cascade_ns_to_timer(this_board->i8254_osc_base,
+		i8253_cascade_ns_to_timer(board->i8254_osc_base,
 					  &divisor1, &divisor2,
 					  &cmd->convert_arg,
 					  cmd->flags & TRIG_ROUND_MASK);
-		if (cmd->convert_arg < this_board->ai_ns_min)
-			cmd->convert_arg = this_board->ai_ns_min;
+		if (cmd->convert_arg < board->ai_ns_min)
+			cmd->convert_arg = board->ai_ns_min;
 		if (tmp != cmd->convert_arg)
 			err++;
 	}
@@ -592,6 +577,7 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
 
 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	const struct pcl816_board *board = comedi_board(dev);
 	unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
 	struct comedi_cmd *cmd = &s->async->cmd;
 	unsigned int seglen;
@@ -609,10 +595,10 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 		return -EBUSY;
 
 	if (cmd->convert_src == TRIG_TIMER) {
-		if (cmd->convert_arg < this_board->ai_ns_min)
-			cmd->convert_arg = this_board->ai_ns_min;
+		if (cmd->convert_arg < board->ai_ns_min)
+			cmd->convert_arg = board->ai_ns_min;
 
-		i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1,
+		i8253_cascade_ns_to_timer(board->i8254_osc_base, &divisor1,
 					  &divisor2, &cmd->convert_arg,
 					  cmd->flags & TRIG_ROUND_MASK);
 
@@ -1028,6 +1014,7 @@ static int set_rtc_irq_bit(unsigned char bit)
 
 static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct pcl816_board *board = comedi_board(dev);
 	int ret;
 	unsigned long iobase;
 	unsigned int irq, dma;
@@ -1038,9 +1025,9 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	/* claim our I/O space */
 	iobase = it->options[0];
 	printk("comedi%d: pcl816:  board=%s, ioport=0x%03lx", dev->minor,
-	       this_board->name, iobase);
+	       board->name, iobase);
 
-	if (!request_region(iobase, this_board->io_range, "pcl816")) {
+	if (!request_region(iobase, board->io_range, "pcl816")) {
 		printk("I/O port conflict\n");
 		return -EIO;
 	}
@@ -1056,15 +1043,14 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	if (ret < 0)
 		return ret;	/* Can't alloc mem */
 
-	/* set up some name stuff */
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 
 	/* grab our IRQ */
 	irq = 0;
-	if (this_board->IRQbits != 0) {	/* board support IRQ */
+	if (board->IRQbits != 0) {	/* board support IRQ */
 		irq = it->options[1];
 		if (irq) {	/* we want to use IRQ */
-			if (((1 << irq) & this_board->IRQbits) == 0) {
+			if (((1 << irq) & board->IRQbits) == 0) {
 				printk
 				    (", IRQ %u is out of allowed range, "
 				     "DISABLING IT", irq);
@@ -1134,12 +1120,12 @@ no_rtc:
 	if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
 		goto no_dma;	/* if we haven't IRQ, we can't use DMA */
 
-	if (this_board->DMAbits != 0) {	/* board support DMA */
+	if (board->DMAbits != 0) {	/* board support DMA */
 		dma = it->options[2];
 		if (dma < 1)
 			goto no_dma;	/* DMA disabled */
 
-		if (((1 << dma) & this_board->DMAbits) == 0) {
+		if (((1 << dma) & board->DMAbits) == 0) {
 			printk(", DMA is out of allowed range, FAIL!\n");
 			return -EINVAL;	/* Bad DMA */
 		}
@@ -1185,30 +1171,30 @@ no_rtc:
 
 no_dma:
 
-/*  if (this_board->n_aochan > 0)
+/*  if (board->n_aochan > 0)
     subdevs[1] = COMEDI_SUBD_AO;
-  if (this_board->n_dichan > 0)
+  if (board->n_dichan > 0)
     subdevs[2] = COMEDI_SUBD_DI;
-  if (this_board->n_dochan > 0)
+  if (board->n_dochan > 0)
     subdevs[3] = COMEDI_SUBD_DO;
 */
 
-	ret = alloc_subdevices(dev, 1);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices + 0;
-	if (this_board->n_aichan > 0) {
+	if (board->n_aichan > 0) {
 		s->type = COMEDI_SUBD_AI;
 		devpriv->sub_ai = s;
 		dev->read_subdev = s;
 		s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
-		s->n_chan = this_board->n_aichan;
+		s->n_chan = board->n_aichan;
 		s->subdev_flags |= SDF_DIFF;
 		/* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */
-		s->maxdata = this_board->ai_maxdata;
-		s->len_chanlist = this_board->ai_chanlist;
-		s->range_table = this_board->ai_range_type;
+		s->maxdata = board->ai_maxdata;
+		s->len_chanlist = board->ai_chanlist;
+		s->range_table = board->ai_range_type;
 		s->cancel = pcl816_ai_cancel;
 		s->do_cmdtest = pcl816_ai_cmdtest;
 		s->do_cmd = pcl816_ai_cmd;
@@ -1221,25 +1207,25 @@ no_dma:
 #if 0
 case COMEDI_SUBD_AO:
 	s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
-	s->n_chan = this_board->n_aochan;
-	s->maxdata = this_board->ao_maxdata;
-	s->len_chanlist = this_board->ao_chanlist;
-	s->range_table = this_board->ao_range_type;
+	s->n_chan = board->n_aochan;
+	s->maxdata = board->ao_maxdata;
+	s->len_chanlist = board->ao_chanlist;
+	s->range_table = board->ao_range_type;
 	break;
 
 case COMEDI_SUBD_DI:
 	s->subdev_flags = SDF_READABLE;
-	s->n_chan = this_board->n_dichan;
+	s->n_chan = board->n_dichan;
 	s->maxdata = 1;
-	s->len_chanlist = this_board->n_dichan;
+	s->len_chanlist = board->n_dichan;
 	s->range_table = &range_digital;
 	break;
 
 case COMEDI_SUBD_DO:
 	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = this_board->n_dochan;
+	s->n_chan = board->n_dochan;
 	s->maxdata = 1;
-	s->len_chanlist = this_board->n_dochan;
+	s->len_chanlist = board->n_dochan;
 	s->range_table = &range_digital;
 	break;
 #endif
@@ -1253,6 +1239,8 @@ case COMEDI_SUBD_DO:
 
 static void pcl816_detach(struct comedi_device *dev)
 {
+	const struct pcl816_board *board = comedi_board(dev);
+
 	if (dev->private) {
 		pcl816_ai_cancel(dev, devpriv->sub_ai);
 		pcl816_reset(dev);
@@ -1275,7 +1263,7 @@ static void pcl816_detach(struct comedi_device *dev)
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 	if (dev->iobase)
-		release_region(dev->iobase, this_board->io_range);
+		release_region(dev->iobase, board->io_range);
 #ifdef unused
 	if (devpriv->dma_rtc)
 		RTC_lock--;
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 1406c97..34169c1 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -326,7 +326,6 @@ static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0
 };
 
 #define devpriv ((struct pcl818_private *)dev->private)
-#define this_board ((const struct pcl818_board *)dev->board_ptr)
 
 /*
 ==============================================================================
@@ -443,13 +442,10 @@ static int pcl818_di_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = inb(dev->iobase + PCL818_DI_LO) |
 	    (inb(dev->iobase + PCL818_DI_HI) << 8);
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -462,9 +458,6 @@ static int pcl818_do_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	s->state &= ~data[0];
 	s->state |= (data[0] & data[1]);
 
@@ -473,7 +466,7 @@ static int pcl818_do_insn_bits(struct comedi_device *dev,
 
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -953,7 +946,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
 	int divisor1 = 0, divisor2 = 0;
 	unsigned int seglen;
 
-	dev_dbg(dev->hw_dev, "pcl818_ai_cmd_mode()\n");
+	dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode()\n");
 	if ((!dev->irq) && (!devpriv->dma_rtc)) {
 		comedi_error(dev, "IRQ not defined!");
 		return -EINVAL;
@@ -1056,7 +1049,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
 		break;
 	}
 #endif
-	dev_dbg(dev->hw_dev, "pcl818_ai_cmd_mode() end\n");
+	dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode() end\n");
 	return 0;
 }
 
@@ -1264,6 +1257,7 @@ static int check_single_ended(unsigned int port)
 static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
 		      struct comedi_cmd *cmd)
 {
+	const struct pcl818_board *board = comedi_board(dev);
 	int err = 0;
 	int tmp, divisor1 = 0, divisor2 = 0;
 
@@ -1299,22 +1293,9 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
 
 	/* step 2: make sure trigger sources are unique and mutually compatible */
 
-	if (cmd->start_src != TRIG_NOW) {
-		cmd->start_src = TRIG_NOW;
-		err++;
-	}
-	if (cmd->scan_begin_src != TRIG_FOLLOW) {
-		cmd->scan_begin_src = TRIG_FOLLOW;
-		err++;
-	}
 	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
 		err++;
 
-	if (cmd->scan_end_src != TRIG_COUNT) {
-		cmd->scan_end_src = TRIG_COUNT;
-		err++;
-	}
-
 	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
 		err++;
 
@@ -1334,8 +1315,8 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
 	}
 
 	if (cmd->convert_src == TRIG_TIMER) {
-		if (cmd->convert_arg < this_board->ns_min) {
-			cmd->convert_arg = this_board->ns_min;
+		if (cmd->convert_arg < board->ns_min) {
+			cmd->convert_arg = board->ns_min;
 			err++;
 		}
 	} else {		/* TRIG_EXT */
@@ -1371,8 +1352,8 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
 		i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
 					  &divisor2, &cmd->convert_arg,
 					  cmd->flags & TRIG_ROUND_MASK);
-		if (cmd->convert_arg < this_board->ns_min)
-			cmd->convert_arg = this_board->ns_min;
+		if (cmd->convert_arg < board->ns_min)
+			cmd->convert_arg = board->ns_min;
 		if (tmp != cmd->convert_arg)
 			err++;
 	}
@@ -1399,7 +1380,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 	struct comedi_cmd *cmd = &s->async->cmd;
 	int retval;
 
-	dev_dbg(dev->hw_dev, "pcl818_ai_cmd()\n");
+	dev_dbg(dev->class_dev, "pcl818_ai_cmd()\n");
 	devpriv->ai_n_chan = cmd->chanlist_len;
 	devpriv->ai_chanlist = cmd->chanlist;
 	devpriv->ai_flags = cmd->flags;
@@ -1417,7 +1398,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 		if (cmd->convert_src == TRIG_TIMER) {	/*  mode 1 */
 			devpriv->ai_timer1 = cmd->convert_arg;
 			retval = pcl818_ai_cmd_mode(1, dev, s);
-			dev_dbg(dev->hw_dev, "pcl818_ai_cmd() end\n");
+			dev_dbg(dev->class_dev, "pcl818_ai_cmd() end\n");
 			return retval;
 		}
 		if (cmd->convert_src == TRIG_EXT) {	/*  mode 3 */
@@ -1436,7 +1417,7 @@ static int pcl818_ai_cancel(struct comedi_device *dev,
 			    struct comedi_subdevice *s)
 {
 	if (devpriv->irq_blocked > 0) {
-		dev_dbg(dev->hw_dev, "pcl818_ai_cancel()\n");
+		dev_dbg(dev->class_dev, "pcl818_ai_cancel()\n");
 		devpriv->irq_was_now_closed = 1;
 
 		switch (devpriv->ai_mode) {
@@ -1486,7 +1467,7 @@ static int pcl818_ai_cancel(struct comedi_device *dev,
 	}
 
 end:
-	dev_dbg(dev->hw_dev, "pcl818_ai_cancel() end\n");
+	dev_dbg(dev->class_dev, "pcl818_ai_cancel() end\n");
 	return 0;
 }
 
@@ -1519,6 +1500,8 @@ static int pcl818_check(unsigned long iobase)
 */
 static void pcl818_reset(struct comedi_device *dev)
 {
+	const struct pcl818_board *board = comedi_board(dev);
+
 	if (devpriv->usefifo) {	/*  FIFO shutdown */
 		outb(0, dev->iobase + PCL818_FI_INTCLR);
 		outb(0, dev->iobase + PCL818_FI_FLUSH);
@@ -1537,7 +1520,7 @@ static void pcl818_reset(struct comedi_device *dev)
 	outb(0xb0, dev->iobase + PCL818_CTRCTL);	/* Stop pacer */
 	outb(0x70, dev->iobase + PCL818_CTRCTL);
 	outb(0x30, dev->iobase + PCL818_CTRCTL);
-	if (this_board->is_818) {
+	if (board->is_818) {
 		outb(0, dev->iobase + PCL818_RANGE);
 	} else {
 		outb(0, dev->iobase + PCL718_DA2_LO);
@@ -1636,6 +1619,7 @@ static int rtc_setfreq_irq(int freq)
 
 static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct pcl818_board *board = comedi_board(dev);
 	int ret;
 	unsigned long iobase;
 	unsigned int irq;
@@ -1651,9 +1635,10 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	iobase = it->options[0];
 	printk
 	    ("comedi%d: pcl818:  board=%s, ioport=0x%03lx",
-	     dev->minor, this_board->name, iobase);
-	devpriv->io_range = this_board->io_range;
-	if ((this_board->fifo) && (it->options[2] == -1)) {	/*  we've board with FIFO and we want to use FIFO */
+	     dev->minor, board->name, iobase);
+	devpriv->io_range = board->io_range;
+	if ((board->fifo) && (it->options[2] == -1)) {
+		/*  we've board with FIFO and we want to use FIFO */
 		devpriv->io_range = PCLx1xFIFO_RANGE;
 		devpriv->usefifo = 1;
 	}
@@ -1669,14 +1654,14 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		return -EIO;
 	}
 
-	/* set up some name stuff */
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
+
 	/* grab our IRQ */
 	irq = 0;
-	if (this_board->IRQbits != 0) {	/* board support IRQ */
+	if (board->IRQbits != 0) {	/* board support IRQ */
 		irq = it->options[1];
 		if (irq) {	/* we want to use IRQ */
-			if (((1 << irq) & this_board->IRQbits) == 0) {
+			if (((1 << irq) & board->IRQbits) == 0) {
 				printk
 				    (", IRQ %u is out of allowed range, DISABLING IT",
 				     irq);
@@ -1740,11 +1725,11 @@ no_rtc:
 	devpriv->dma = dma;
 	if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
 		goto no_dma;	/* if we haven't IRQ, we can't use DMA */
-	if (this_board->DMAbits != 0) {	/* board support DMA */
+	if (board->DMAbits != 0) {	/* board support DMA */
 		dma = it->options[2];
 		if (dma < 1)
 			goto no_dma;	/* DMA disabled */
-		if (((1 << dma) & this_board->DMAbits) == 0) {
+		if (((1 << dma) & board->DMAbits) == 0) {
 			printk(KERN_ERR "DMA is out of allowed range, FAIL!\n");
 			return -EINVAL;	/* Bad DMA */
 		}
@@ -1774,29 +1759,29 @@ no_rtc:
 
 no_dma:
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		return ret;
 
 	s = dev->subdevices + 0;
-	if (!this_board->n_aichan_se) {
+	if (!board->n_aichan_se) {
 		s->type = COMEDI_SUBD_UNUSED;
 	} else {
 		s->type = COMEDI_SUBD_AI;
 		devpriv->sub_ai = s;
 		s->subdev_flags = SDF_READABLE;
 		if (check_single_ended(dev->iobase)) {
-			s->n_chan = this_board->n_aichan_se;
+			s->n_chan = board->n_aichan_se;
 			s->subdev_flags |= SDF_COMMON | SDF_GROUND;
 			printk(", %dchans S.E. DAC", s->n_chan);
 		} else {
-			s->n_chan = this_board->n_aichan_diff;
+			s->n_chan = board->n_aichan_diff;
 			s->subdev_flags |= SDF_DIFF;
 			printk(", %dchans DIFF DAC", s->n_chan);
 		}
-		s->maxdata = this_board->ai_maxdata;
+		s->maxdata = board->ai_maxdata;
 		s->len_chanlist = s->n_chan;
-		s->range_table = this_board->ai_range_type;
+		s->range_table = board->ai_range_type;
 		s->cancel = pcl818_ai_cancel;
 		s->insn_read = pcl818_ai_insn_read;
 		if ((irq) || (devpriv->dma_rtc)) {
@@ -1805,7 +1790,7 @@ no_dma:
 			s->do_cmdtest = ai_cmdtest;
 			s->do_cmd = ai_cmd;
 		}
-		if (this_board->is_818) {
+		if (board->is_818) {
 			if ((it->options[4] == 1) || (it->options[4] == 10))
 				s->range_table = &range_pcl818l_h_ai;	/*  secondary range list jumper selectable */
 		} else {
@@ -1845,15 +1830,15 @@ no_dma:
 	}
 
 	s = dev->subdevices + 1;
-	if (!this_board->n_aochan) {
+	if (!board->n_aochan) {
 		s->type = COMEDI_SUBD_UNUSED;
 	} else {
 		s->type = COMEDI_SUBD_AO;
 		s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
-		s->n_chan = this_board->n_aochan;
-		s->maxdata = this_board->ao_maxdata;
-		s->len_chanlist = this_board->n_aochan;
-		s->range_table = this_board->ao_range_type;
+		s->n_chan = board->n_aochan;
+		s->maxdata = board->ao_maxdata;
+		s->len_chanlist = board->n_aochan;
+		s->range_table = board->ao_range_type;
 		s->insn_read = pcl818_ao_insn_read;
 		s->insn_write = pcl818_ao_insn_write;
 #ifdef unused
@@ -1864,7 +1849,7 @@ no_dma:
 		}
 #endif
 #endif
-		if (this_board->is_818) {
+		if (board->is_818) {
 			if ((it->options[4] == 1) || (it->options[4] == 10))
 				s->range_table = &range_unipolar10;
 			if (it->options[4] == 2)
@@ -1878,27 +1863,27 @@ no_dma:
 	}
 
 	s = dev->subdevices + 2;
-	if (!this_board->n_dichan) {
+	if (!board->n_dichan) {
 		s->type = COMEDI_SUBD_UNUSED;
 	} else {
 		s->type = COMEDI_SUBD_DI;
 		s->subdev_flags = SDF_READABLE;
-		s->n_chan = this_board->n_dichan;
+		s->n_chan = board->n_dichan;
 		s->maxdata = 1;
-		s->len_chanlist = this_board->n_dichan;
+		s->len_chanlist = board->n_dichan;
 		s->range_table = &range_digital;
 		s->insn_bits = pcl818_di_insn_bits;
 	}
 
 	s = dev->subdevices + 3;
-	if (!this_board->n_dochan) {
+	if (!board->n_dochan) {
 		s->type = COMEDI_SUBD_UNUSED;
 	} else {
 		s->type = COMEDI_SUBD_DO;
 		s->subdev_flags = SDF_WRITABLE;
-		s->n_chan = this_board->n_dochan;
+		s->n_chan = board->n_dochan;
 		s->maxdata = 1;
-		s->len_chanlist = this_board->n_dochan;
+		s->len_chanlist = board->n_dochan;
 		s->range_table = &range_digital;
 		s->insn_bits = pcl818_do_insn_bits;
 	}
@@ -1910,9 +1895,9 @@ no_dma:
 		devpriv->i8253_osc_base = 1000;
 
 	/* max sampling speed */
-	devpriv->ns_min = this_board->ns_min;
+	devpriv->ns_min = board->ns_min;
 
-	if (!this_board->is_818) {
+	if (!board->is_818) {
 		if ((it->options[6] == 1) || (it->options[6] == 100))
 			devpriv->ns_min = 10000;	/* extended PCL718 to 100kHz DAC */
 	}
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index 7492b8f..62c22cc 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -76,10 +76,6 @@ struct priv_pcm3724 {
 	int dio_2;
 };
 
-#define this_board ((const struct pcm3724_board *)dev->board_ptr)
-
-/* (setq c-basic-offset 8) */
-
 static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
 {
 	unsigned long iobase = arg;
@@ -234,12 +230,13 @@ static int subdev_3724_insn_config(struct comedi_device *dev,
 static int pcm3724_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
+	const struct pcm3724_board *board = comedi_board(dev);
 	unsigned long iobase;
 	unsigned int iorange;
 	int ret, i, n_subdevices;
 
 	iobase = it->options[0];
-	iorange = this_board->io_range;
+	iorange = board->io_range;
 
 	ret = alloc_private(dev, sizeof(struct priv_pcm3724));
 	if (ret < 0)
@@ -249,20 +246,20 @@ static int pcm3724_attach(struct comedi_device *dev,
 	((struct priv_pcm3724 *)(dev->private))->dio_2 = 0;
 
 	printk(KERN_INFO "comedi%d: pcm3724: board=%s, 0x%03lx ", dev->minor,
-	       this_board->name, iobase);
+	       board->name, iobase);
 	if (!iobase || !request_region(iobase, iorange, "pcm3724")) {
 		printk("I/O port conflict\n");
 		return -EIO;
 	}
 
 	dev->iobase = iobase;
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 	printk(KERN_INFO "\n");
 
-	n_subdevices = this_board->numofports;
+	n_subdevices = board->numofports;
 
-	ret = alloc_subdevices(dev, n_subdevices);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, n_subdevices);
+	if (ret)
 		return ret;
 
 	for (i = 0; i < dev->n_subdevices; i++) {
@@ -275,6 +272,7 @@ static int pcm3724_attach(struct comedi_device *dev,
 
 static void pcm3724_detach(struct comedi_device *dev)
 {
+	const struct pcm3724_board *board = comedi_board(dev);
 	int i;
 
 	if (dev->subdevices) {
@@ -282,7 +280,7 @@ static void pcm3724_detach(struct comedi_device *dev)
 			subdev_8255_cleanup(dev, dev->subdevices + i);
 	}
 	if (dev->iobase)
-		release_region(dev->iobase, this_board->io_range);
+		release_region(dev->iobase, board->io_range);
 }
 
 static const struct pcm3724_board boardtypes[] = {
diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c
index f8d1c64..d65e0bd 100644
--- a/drivers/staging/comedi/drivers/pcm3730.c
+++ b/drivers/staging/comedi/drivers/pcm3730.c
@@ -32,8 +32,6 @@ static int pcm3730_do_insn_bits(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] & data[1]);
@@ -41,17 +39,15 @@ static int pcm3730_do_insn_bits(struct comedi_device *dev,
 	}
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 static int pcm3730_di_insn_bits(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
 	data[1] = inb(dev->iobase + (unsigned long)(s->private));
-	return 2;
+	return insn->n;
 }
 
 static int pcm3730_attach(struct comedi_device *dev,
@@ -59,6 +55,7 @@ static int pcm3730_attach(struct comedi_device *dev,
 {
 	struct comedi_subdevice *s;
 	unsigned long iobase;
+	int ret;
 
 	iobase = it->options[0];
 	printk(KERN_INFO "comedi%d: pcm3730: 0x%04lx ", dev->minor, iobase);
@@ -71,8 +68,9 @@ static int pcm3730_attach(struct comedi_device *dev,
 	dev->iobase = dev->iobase;
 	dev->irq = 0;
 
-	if (alloc_subdevices(dev, 6) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 6);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	s->type = COMEDI_SUBD_DO;
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index 1ec7d5c..54d19c9 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -58,8 +58,6 @@ struct pcmad_board_struct {
 	int n_ai_bits;
 };
 
-#define this_board ((const struct pcmad_board_struct *)(dev->board_ptr))
-
 struct pcmad_priv_struct {
 	int differential;
 	int twos_comp;
@@ -72,6 +70,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
+	const struct pcmad_board_struct *board = comedi_board(dev);
 	int i;
 	int chan;
 	int n;
@@ -89,7 +88,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev,
 		data[n] |= (inb(dev->iobase + PCMAD_MSB) << 8);
 
 		if (devpriv->twos_comp)
-			data[n] ^= (1 << (this_board->n_ai_bits - 1));
+			data[n] ^= (1 << (board->n_ai_bits - 1));
 	}
 
 	return n;
@@ -104,6 +103,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev,
  */
 static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct pcmad_board_struct *board = comedi_board(dev);
 	int ret;
 	struct comedi_subdevice *s;
 	unsigned long iobase;
@@ -117,15 +117,15 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	printk(KERN_CONT "\n");
 	dev->iobase = iobase;
 
-	ret = alloc_subdevices(dev, 1);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
 		return ret;
 
 	ret = alloc_private(dev, sizeof(struct pcmad_priv_struct));
 	if (ret < 0)
 		return ret;
 
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 
 	s = dev->subdevices + 0;
 	s->type = COMEDI_SUBD_AI;
@@ -133,7 +133,7 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	s->n_chan = 16;		/* XXX */
 	s->len_chanlist = 1;
 	s->insn_read = pcmad_ai_insn_read;
-	s->maxdata = (1 << this_board->n_ai_bits) - 1;
+	s->maxdata = (1 << board->n_ai_bits) - 1;
 	s->range_table = &range_unknown;
 
 	return 0;
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 4786148..291ce7c 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -80,11 +80,6 @@ static const struct comedi_lrange pcmda12_ranges = {
 	 }
 };
 
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct pcmda12_board *)dev->board_ptr)
-
 struct pcmda12_private {
 
 	unsigned int ao_readback[CHANS];
@@ -167,8 +162,10 @@ static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 static int pcmda12_attach(struct comedi_device *dev,
 			  struct comedi_devconfig *it)
 {
+	const struct pcmda12_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	unsigned long iobase;
+	int ret;
 
 	iobase = it->options[0];
 	printk(KERN_INFO
@@ -181,11 +178,7 @@ static int pcmda12_attach(struct comedi_device *dev,
 	}
 	dev->iobase = iobase;
 
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 /*
  * Allocate the private structure area.  alloc_private() is a
@@ -198,17 +191,9 @@ static int pcmda12_attach(struct comedi_device *dev,
 
 	devpriv->simultaneous_xfer_mode = it->options[1];
 
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.
-	 *
-	 * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
-	 * 96-channel version of the board.
-	 */
-	if (alloc_subdevices(dev, 1) < 0) {
-		printk(KERN_ERR "cannot allocate subdevice data structures\n");
-		return -ENOMEM;
-	}
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices;
 	s->private = NULL;
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index efed168..3d2e6f0 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -183,11 +183,6 @@ static const struct comedi_lrange ranges_ao = {
 	  RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
 };
 
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct pcmmio_board *)dev->board_ptr)
-
 /* this structure is for data unique to this subdevice.  */
 struct pcmmio_subdev_private {
 
@@ -280,8 +275,6 @@ static int pcmmio_dio_insn_bits(struct comedi_device *dev,
 				struct comedi_insn *insn, unsigned int *data)
 {
 	int byte_no;
-	if (insn->n != 2)
-		return -EINVAL;
 
 	/* NOTE:
 	   reading a 0 means this channel was high
@@ -351,7 +344,7 @@ static int pcmmio_dio_insn_bits(struct comedi_device *dev,
 	printk(KERN_DEBUG "s->state %08x data_out %08x\n", s->state, data[1]);
 #endif
 
-	return 2;
+	return insn->n;
 }
 
 /* The input or output configuration of each digital line is
@@ -423,7 +416,9 @@ static int pcmmio_dio_insn_config(struct comedi_device *dev,
 
 static void switch_page(struct comedi_device *dev, int asic, int page)
 {
-	if (asic < 0 || asic >= thisboard->dio_num_asics)
+	const struct pcmmio_board *board = comedi_board(dev);
+
+	if (asic < 0 || asic >= board->dio_num_asics)
 		return;		/* paranoia */
 	if (page < 0 || page >= NUM_PAGES)
 		return;		/* more paranoia */
@@ -439,9 +434,10 @@ static void switch_page(struct comedi_device *dev, int asic, int page)
 static void init_asics(struct comedi_device *dev)
 {				/* sets up an
 				   ASIC chip to defaults */
+	const struct pcmmio_board *board = comedi_board(dev);
 	int asic;
 
-	for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
+	for (asic = 0; asic < board->dio_num_asics; ++asic) {
 		int port, page;
 		unsigned long baseaddr = devpriv->asics[asic].iobase;
 
@@ -476,7 +472,9 @@ static void init_asics(struct comedi_device *dev)
 #ifdef notused
 static void lock_port(struct comedi_device *dev, int asic, int port)
 {
-	if (asic < 0 || asic >= thisboard->dio_num_asics)
+	const struct pcmmio_board *board = comedi_board(dev);
+
+	if (asic < 0 || asic >= board->dio_num_asics)
 		return;		/* paranoia */
 	if (port < 0 || port >= PORTS_PER_ASIC)
 		return;		/* more paranoia */
@@ -490,7 +488,9 @@ static void lock_port(struct comedi_device *dev, int asic, int port)
 
 static void unlock_port(struct comedi_device *dev, int asic, int port)
 {
-	if (asic < 0 || asic >= thisboard->dio_num_asics)
+	const struct pcmmio_board *board = comedi_board(dev);
+
+	if (asic < 0 || asic >= board->dio_num_asics)
 		return;		/* paranoia */
 	if (port < 0 || port >= PORTS_PER_ASIC)
 		return;		/* more paranoia */
@@ -512,7 +512,7 @@ static void pcmmio_stop_intr(struct comedi_device *dev,
 
 	subpriv->dio.intr.enabled_mask = 0;
 	subpriv->dio.intr.active = 0;
-	s->async->inttrig = 0;
+	s->async->inttrig = NULL;
 	nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
 	firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
 	switch_page(dev, asic, PAGE_ENAB);
@@ -778,7 +778,7 @@ pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
 		return -EINVAL;
 
 	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
-	s->async->inttrig = 0;
+	s->async->inttrig = NULL;
 	if (subpriv->dio.intr.active)
 		event = pcmmio_start_intr(dev, s);
 	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
@@ -1012,11 +1012,13 @@ static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
 
 static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct pcmmio_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
 	    thisasic_chanct = 0;
 	unsigned long iobase;
 	unsigned int irq[MAX_ASICS];
+	int ret;
 
 	iobase = it->options[0];
 	irq[0] = it->options[1];
@@ -1027,17 +1029,13 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	dev->iobase = iobase;
 
 	if (!iobase || !request_region(iobase,
-				       thisboard->total_iosize,
+				       board->total_iosize,
 				       dev->driver->driver_name)) {
 		printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
 		return -EIO;
 	}
 
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 /*
  * Allocate the private structure area.  alloc_private() is a
@@ -1061,7 +1059,7 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		spin_lock_init(&devpriv->asics[asic].spinlock);
 	}
 
-	chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
+	chans_left = CHANS_PER_ASIC * board->dio_num_asics;
 	n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
 	n_subdevs = n_dio_subdevs + 2;
 	devpriv->sprivs =
@@ -1072,29 +1070,22 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 				dev->minor);
 		return -ENOMEM;
 	}
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.
-	 *
-	 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
-	 */
-	if (alloc_subdevices(dev, n_subdevs) < 0) {
-		printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n",
-				dev->minor);
-		return -ENOMEM;
-	}
+
+	ret = comedi_alloc_subdevices(dev, n_subdevs);
+	if (ret)
+		return ret;
 
 	/* First, AI */
 	sdev_no = 0;
 	s = dev->subdevices + sdev_no;
 	s->private = devpriv->sprivs + sdev_no;
-	s->maxdata = (1 << thisboard->ai_bits) - 1;
-	s->range_table = thisboard->ai_range_table;
+	s->maxdata = (1 << board->ai_bits) - 1;
+	s->range_table = board->ai_range_table;
 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
 	s->type = COMEDI_SUBD_AI;
-	s->n_chan = thisboard->n_ai_chans;
+	s->n_chan = board->n_ai_chans;
 	s->len_chanlist = s->n_chan;
-	s->insn_read = thisboard->ai_rinsn;
+	s->insn_read = board->ai_rinsn;
 	subpriv->iobase = dev->iobase + 0;
 	/* initialize the resource enable register by clearing it */
 	outb(0, subpriv->iobase + 3);
@@ -1104,14 +1095,14 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	++sdev_no;
 	s = dev->subdevices + sdev_no;
 	s->private = devpriv->sprivs + sdev_no;
-	s->maxdata = (1 << thisboard->ao_bits) - 1;
-	s->range_table = thisboard->ao_range_table;
+	s->maxdata = (1 << board->ao_bits) - 1;
+	s->range_table = board->ao_range_table;
 	s->subdev_flags = SDF_READABLE;
 	s->type = COMEDI_SUBD_AO;
-	s->n_chan = thisboard->n_ao_chans;
+	s->n_chan = board->n_ao_chans;
 	s->len_chanlist = s->n_chan;
-	s->insn_read = thisboard->ao_rinsn;
-	s->insn_write = thisboard->ao_winsn;
+	s->insn_read = board->ao_rinsn;
+	s->insn_write = board->ao_winsn;
 	subpriv->iobase = dev->iobase + 8;
 	/* initialize the resource enable register by clearing it */
 	outb(0, subpriv->iobase + 3);
@@ -1192,7 +1183,7 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
 		if (irq[asic]
 		    && request_irq(irq[asic], interrupt_pcmmio,
-				   IRQF_SHARED, thisboard->name, dev)) {
+				   IRQF_SHARED, board->name, dev)) {
 			int i;
 			/* unroll the allocated irqs.. */
 			for (i = asic - 1; i >= 0; --i) {
@@ -1211,7 +1202,7 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	if (irq[0]) {
 		printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
-		if (thisboard->dio_num_asics == 2 && irq[1])
+		if (board->dio_num_asics == 2 && irq[1])
 			printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
 					dev->minor, irq[1]);
 	} else {
@@ -1225,10 +1216,11 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 static void pcmmio_detach(struct comedi_device *dev)
 {
+	const struct pcmmio_board *board = comedi_board(dev);
 	int i;
 
 	if (dev->iobase)
-		release_region(dev->iobase, thisboard->total_iosize);
+		release_region(dev->iobase, board->total_iosize);
 	for (i = 0; i < MAX_ASICS; ++i) {
 		if (devpriv && devpriv->asics[i].irq)
 			free_irq(devpriv->asics[i].irq, dev);
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index 623381d..feef3d0 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -155,11 +155,6 @@ struct pcmuio_board {
 	const int num_ports;
 };
 
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct pcmuio_board *)dev->board_ptr)
-
 /* this structure is for data unique to this subdevice.  */
 struct pcmuio_subdev_private {
 	/* mapping of halfwords (bytes) in port/chanarray to iobase */
@@ -216,8 +211,6 @@ static int pcmuio_dio_insn_bits(struct comedi_device *dev,
 				struct comedi_insn *insn, unsigned int *data)
 {
 	int byte_no;
-	if (insn->n != 2)
-		return -EINVAL;
 
 	/* NOTE:
 	   reading a 0 means this channel was high
@@ -232,7 +225,7 @@ static int pcmuio_dio_insn_bits(struct comedi_device *dev,
 
 #ifdef DAMMIT_ITS_BROKEN
 	/* DEBUG */
-	dev_dbg(dev->hw_dev, "write mask: %08x  data: %08x\n", data[0],
+	dev_dbg(dev->class_dev, "write mask: %08x  data: %08x\n", data[0],
 		data[1]);
 #endif
 
@@ -269,7 +262,7 @@ static int pcmuio_dio_insn_bits(struct comedi_device *dev,
 		}
 #ifdef DAMMIT_ITS_BROKEN
 		/* DEBUG */
-		dev_dbg(dev->hw_dev, "data_out_byte %02x\n", (unsigned)byte);
+		dev_dbg(dev->class_dev, "data_out_byte %02x\n", (unsigned)byte);
 #endif
 		/* save the digital input lines for this byte.. */
 		s->state |= ((unsigned int)byte) << offset;
@@ -280,11 +273,11 @@ static int pcmuio_dio_insn_bits(struct comedi_device *dev,
 
 #ifdef DAMMIT_ITS_BROKEN
 	/* DEBUG */
-	dev_dbg(dev->hw_dev, "s->state %08x data_out %08x\n", s->state,
+	dev_dbg(dev->class_dev, "s->state %08x data_out %08x\n", s->state,
 		data[1]);
 #endif
 
-	return 2;
+	return insn->n;
 }
 
 /* The input or output configuration of each digital line is
@@ -354,7 +347,9 @@ static int pcmuio_dio_insn_config(struct comedi_device *dev,
 
 static void switch_page(struct comedi_device *dev, int asic, int page)
 {
-	if (asic < 0 || asic >= thisboard->num_asics)
+	const struct pcmuio_board *board = comedi_board(dev);
+
+	if (asic < 0 || asic >= board->num_asics)
 		return;		/* paranoia */
 	if (page < 0 || page >= NUM_PAGES)
 		return;		/* more paranoia */
@@ -370,9 +365,10 @@ static void switch_page(struct comedi_device *dev, int asic, int page)
 static void init_asics(struct comedi_device *dev)
 {				/* sets up an
 				   ASIC chip to defaults */
+	const struct pcmuio_board *board = comedi_board(dev);
 	int asic;
 
-	for (asic = 0; asic < thisboard->num_asics; ++asic) {
+	for (asic = 0; asic < board->num_asics; ++asic) {
 		int port, page;
 		unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE;
 
@@ -407,7 +403,9 @@ static void init_asics(struct comedi_device *dev)
 #ifdef notused
 static void lock_port(struct comedi_device *dev, int asic, int port)
 {
-	if (asic < 0 || asic >= thisboard->num_asics)
+	const struct pcmuio_board *board = comedi_board(dev);
+
+	if (asic < 0 || asic >= board->num_asics)
 		return;		/* paranoia */
 	if (port < 0 || port >= PORTS_PER_ASIC)
 		return;		/* more paranoia */
@@ -420,7 +418,9 @@ static void lock_port(struct comedi_device *dev, int asic, int port)
 
 static void unlock_port(struct comedi_device *dev, int asic, int port)
 {
-	if (asic < 0 || asic >= thisboard->num_asics)
+	const struct pcmuio_board *board = comedi_board(dev);
+
+	if (asic < 0 || asic >= board->num_asics)
 		return;		/* paranoia */
 	if (port < 0 || port >= PORTS_PER_ASIC)
 		return;		/* more paranoia */
@@ -747,39 +747,38 @@ pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
 
 static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct pcmuio_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
 	unsigned long iobase;
 	unsigned int irq[MAX_ASICS];
+	int ret;
 
 	iobase = it->options[0];
 	irq[0] = it->options[1];
 	irq[1] = it->options[2];
 
-	dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
+	dev_dbg(dev->class_dev, "%s: io: %lx attach\n",
 		dev->driver->driver_name, iobase);
 
 	dev->iobase = iobase;
 
 	if (!iobase || !request_region(iobase,
-				       thisboard->num_asics * ASIC_IOSIZE,
+				       board->num_asics * ASIC_IOSIZE,
 				       dev->driver->driver_name)) {
-		dev_err(dev->hw_dev, "I/O port conflict\n");
+		dev_err(dev->class_dev, "I/O port conflict\n");
 		return -EIO;
 	}
 
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 /*
  * Allocate the private structure area.  alloc_private() is a
  * convenient macro defined in comedidev.h.
  */
 	if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
-		dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
+		dev_warn(dev->class_dev,
+			 "cannot allocate private data structure\n");
 		return -ENOMEM;
 	}
 
@@ -792,27 +791,21 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		spin_lock_init(&devpriv->asics[asic].spinlock);
 	}
 
-	chans_left = CHANS_PER_ASIC * thisboard->num_asics;
+	chans_left = CHANS_PER_ASIC * board->num_asics;
 	n_subdevs = CALC_N_SUBDEVS(chans_left);
 	devpriv->sprivs =
 	    kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
 		    GFP_KERNEL);
 	if (!devpriv->sprivs) {
-		dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
-		return -ENOMEM;
-	}
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.
-	 *
-	 * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
-	 * 96-channel version of the board.
-	 */
-	if (alloc_subdevices(dev, n_subdevs) < 0) {
-		dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
+		dev_warn(dev->class_dev,
+			 "cannot allocate subdevice private data structures\n");
 		return -ENOMEM;
 	}
 
+	ret = comedi_alloc_subdevices(dev, n_subdevs);
+	if (ret)
+		return ret;
+
 	port = 0;
 	asic = 0;
 	for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
@@ -881,7 +874,7 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
 		if (irq[asic]
 		    && request_irq(irq[asic], interrupt_pcmuio,
-				   IRQF_SHARED, thisboard->name, dev)) {
+				   IRQF_SHARED, board->name, dev)) {
 			int i;
 			/* unroll the allocated irqs.. */
 			for (i = asic - 1; i >= 0; --i) {
@@ -897,11 +890,12 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 				   irqs.. */
 
 	if (irq[0]) {
-		dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
-		if (irq[1] && thisboard->num_asics == 2)
-			dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
+		dev_dbg(dev->class_dev, "irq: %u\n", irq[0]);
+		if (irq[1] && board->num_asics == 2)
+			dev_dbg(dev->class_dev, "second ASIC irq: %u\n",
+				irq[1]);
 	} else {
-		dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
+		dev_dbg(dev->class_dev, "(IRQ mode disabled)\n");
 	}
 
 
@@ -910,10 +904,11 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 static void pcmuio_detach(struct comedi_device *dev)
 {
+	const struct pcmuio_board *board = comedi_board(dev);
 	int i;
 
 	if (dev->iobase)
-		release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
+		release_region(dev->iobase, ASIC_IOSIZE * board->num_asics);
 	for (i = 0; i < MAX_ASICS; ++i) {
 		if (devpriv->asics[i].irq)
 			free_irq(devpriv->asics[i].irq, dev);
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
index e712048..c253bb9 100644
--- a/drivers/staging/comedi/drivers/poc.c
+++ b/drivers/staging/comedi/drivers/poc.c
@@ -57,8 +57,6 @@ struct boarddef_struct {
 	const struct comedi_lrange *range;
 };
 
-#define this_board ((const struct boarddef_struct *)dev->board_ptr)
-
 static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 			 struct comedi_insn *insn, unsigned int *data)
 {
@@ -101,23 +99,18 @@ static int pcl733_insn_bits(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	data[1] = inb(dev->iobase + 0);
 	data[1] |= (inb(dev->iobase + 1) << 8);
 	data[1] |= (inb(dev->iobase + 2) << 16);
 	data[1] |= (inb(dev->iobase + 3) << 24);
 
-	return 2;
+	return insn->n;
 }
 
 static int pcl734_insn_bits(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= (data[0] & data[1]);
@@ -132,27 +125,29 @@ static int pcl734_insn_bits(struct comedi_device *dev,
 	}
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct boarddef_struct *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	unsigned long iobase;
 	unsigned int iosize;
+	int ret;
 
 	iobase = it->options[0];
 	printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
-	       this_board->name, iobase);
+	       board->name, iobase);
 
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 
 	if (iobase == 0) {
 		printk(KERN_ERR "io base address required\n");
 		return -EINVAL;
 	}
 
-	iosize = this_board->iosize;
+	iosize = board->iosize;
 	/* check if io addresses are available */
 	if (!request_region(iobase, iosize, "dac02")) {
 		printk(KERN_ERR "I/O port conflict: failed to allocate ports "
@@ -161,20 +156,22 @@ static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	}
 	dev->iobase = iobase;
 
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
-	if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0)
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
+
+	if (alloc_private(dev, sizeof(unsigned int) * board->n_chan) < 0)
 		return -ENOMEM;
 
 	/* analog output subdevice */
 	s = dev->subdevices + 0;
-	s->type = this_board->type;
-	s->n_chan = this_board->n_chan;
-	s->maxdata = (1 << this_board->n_bits) - 1;
-	s->range_table = this_board->range;
-	s->insn_write = this_board->winsn;
-	s->insn_read = this_board->rinsn;
-	s->insn_bits = this_board->insnbits;
+	s->type = board->type;
+	s->n_chan = board->n_chan;
+	s->maxdata = (1 << board->n_bits) - 1;
+	s->range_table = board->range;
+	s->insn_write = board->winsn;
+	s->insn_read = board->rinsn;
+	s->insn_bits = board->insnbits;
 	if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO)
 		s->subdev_flags = SDF_WRITABLE;
 
@@ -183,8 +180,10 @@ static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 static void poc_detach(struct comedi_device *dev)
 {
+	const struct boarddef_struct *board = comedi_board(dev);
+
 	if (dev->iobase)
-		release_region(dev->iobase, this_board->iosize);
+		release_region(dev->iobase, board->iosize);
 }
 
 static const struct boarddef_struct boards[] = {
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index 2f130b3..a029147 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -871,8 +871,8 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	dev->iobase = local->link->resource[0]->start;
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		return ret;
 
 	printk(KERN_INFO "comedi%d: attaching daqp%d (io 0x%04lx)\n",
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 1678a0c..cc1371d 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -105,7 +105,6 @@ Configuration options:
 #include <linux/delay.h>
 
 #include "../comedidev.h"
-#include "comedi_pci.h"
 
 #define DRV_NAME "rtd520"
 
@@ -703,580 +702,183 @@ struct rtdPrivate {
 #define RtdDma1Status(dev) \
 	readb(devpriv->lcfg+LCFG_DMACSR1)
 
-static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			struct comedi_insn *insn, unsigned int *data);
-static int rtd_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			struct comedi_insn *insn, unsigned int *data);
-static int rtd_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			struct comedi_insn *insn, unsigned int *data);
-static int rtd_dio_insn_bits(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_insn *insn, unsigned int *data);
-static int rtd_dio_insn_config(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int rtd_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_cmd *cmd);
-static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
 /*
- * static int rtd_ai_poll(struct comedi_device *dev,
- *			  struct comedi_subdevice *s);
- */
-static int rtd_ns_to_timer(unsigned int *ns, int roundMode);
-static irqreturn_t rtd_interrupt(int irq, void *d);
-static int rtd520_probe_fifo_depth(struct comedi_device *dev);
+  Given a desired period and the clock period (both in ns),
+  return the proper counter value (divider-1).
+  Sets the original period to be the true value.
+  Note: you have to check if the value is larger than the counter range!
+*/
+static int rtd_ns_to_timer_base(unsigned int *nanosec,	/* desired period (in ns) */
+				int round_mode, int base)
+{				/* clock period (in ns) */
+	int divider;
+
+	switch (round_mode) {
+	case TRIG_ROUND_NEAREST:
+	default:
+		divider = (*nanosec + base / 2) / base;
+		break;
+	case TRIG_ROUND_DOWN:
+		divider = (*nanosec) / base;
+		break;
+	case TRIG_ROUND_UP:
+		divider = (*nanosec + base - 1) / base;
+		break;
+	}
+	if (divider < 2)
+		divider = 2;	/* min is divide by 2 */
+
+	/* Note: we don't check for max, because different timers
+	   have different ranges */
+
+	*nanosec = base * divider;
+	return divider - 1;	/* countdown is divisor+1 */
+}
 
 /*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.  If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{				/* board name and options flags */
-	struct comedi_subdevice *s;
-	struct pci_dev *pcidev;
-	int ret;
-	resource_size_t physLas0;	/* configuration */
-	resource_size_t physLas1;	/* data area */
-	resource_size_t physLcfg;	/* PLX9080 */
-#ifdef USE_DMA
-	int index;
-#endif
+  Given a desired period (in ns),
+  return the proper counter value (divider-1) for the internal clock.
+  Sets the original period to be the true value.
+*/
+static int rtd_ns_to_timer(unsigned int *ns, int round_mode)
+{
+	return rtd_ns_to_timer_base(ns, round_mode, RTD_CLOCK_BASE);
+}
 
-	printk(KERN_INFO "comedi%d: rtd520 attaching.\n", dev->minor);
+/*
+  Convert a single comedi channel-gain entry to a RTD520 table entry
+*/
+static unsigned short rtdConvertChanGain(struct comedi_device *dev,
+					 unsigned int comediChan, int chanIndex)
+{				/* index in channel list */
+	unsigned int chan, range, aref;
+	unsigned short r = 0;
 
-#if defined(CONFIG_COMEDI_DEBUG) && defined(USE_DMA)
-	/* You can set this a load time: modprobe comedi comedi_debug=1 */
-	if (0 == comedi_debug)	/* force DMA debug printks */
-		comedi_debug = 1;
-#endif
+	chan = CR_CHAN(comediChan);
+	range = CR_RANGE(comediChan);
+	aref = CR_AREF(comediChan);
 
-	/*
-	 * Allocate the private structure area.  alloc_private() is a
-	 * convenient macro defined in comedidev.h.
-	 */
-	if (alloc_private(dev, sizeof(struct rtdPrivate)) < 0)
-		return -ENOMEM;
+	r |= chan & 0xf;
 
-	/*
-	 * Probe the device to determine what device in the series it is.
-	 */
-	for (pcidev = pci_get_device(PCI_VENDOR_ID_RTD, PCI_ANY_ID, NULL);
-	     pcidev != NULL;
-	     pcidev = pci_get_device(PCI_VENDOR_ID_RTD, PCI_ANY_ID, pcidev)) {
-		int i;
+	/* Note: we also setup the channel list bipolar flag array */
+	if (range < thisboard->range10Start) {	/* first batch are +-5 */
+		r |= 0x000;	/* +-5 range */
+		r |= (range & 0x7) << 4;	/* gain */
+		CHAN_ARRAY_SET(devpriv->chanBipolar, chanIndex);
+	} else if (range < thisboard->rangeUniStart) {	/* second batch are +-10 */
+		r |= 0x100;	/* +-10 range */
+		/* gain */
+		r |= ((range - thisboard->range10Start) & 0x7) << 4;
+		CHAN_ARRAY_SET(devpriv->chanBipolar, chanIndex);
+	} else {		/* last batch is +10 */
+		r |= 0x200;	/* +10 range */
+		/* gain */
+		r |= ((range - thisboard->rangeUniStart) & 0x7) << 4;
+		CHAN_ARRAY_CLEAR(devpriv->chanBipolar, chanIndex);
+	}
 
-		if (it->options[0] || it->options[1]) {
-			if (pcidev->bus->number != it->options[0]
-			    || PCI_SLOT(pcidev->devfn) != it->options[1]) {
-				continue;
-			}
-		}
-		for (i = 0; i < ARRAY_SIZE(rtd520Boards); ++i) {
-			if (pcidev->device == rtd520Boards[i].device_id) {
-				dev->board_ptr = &rtd520Boards[i];
-				break;
-			}
+	switch (aref) {
+	case AREF_GROUND:	/* on-board ground */
+		break;
+
+	case AREF_COMMON:
+		r |= 0x80;	/* ref external analog common */
+		break;
+
+	case AREF_DIFF:
+		r |= 0x400;	/* differential inputs */
+		break;
+
+	case AREF_OTHER:	/* ??? */
+		break;
+	}
+	/*printk ("chan=%d r=%d a=%d -> 0x%x\n",
+	   chan, range, aref, r); */
+	return r;
+}
+
+/*
+  Setup the channel-gain table from a comedi list
+*/
+static void rtd_load_channelgain_list(struct comedi_device *dev,
+				      unsigned int n_chan, unsigned int *list)
+{
+	if (n_chan > 1) {	/* setup channel gain table */
+		int ii;
+		RtdClearCGT(dev);
+		RtdEnableCGT(dev, 1);	/* enable table */
+		for (ii = 0; ii < n_chan; ii++) {
+			RtdWriteCGTable(dev, rtdConvertChanGain(dev, list[ii],
+								ii));
 		}
-		if (dev->board_ptr)
-			break;	/* found one */
+	} else {		/* just use the channel gain latch */
+		RtdEnableCGT(dev, 0);	/* disable table, enable latch */
+		RtdWriteCGLatch(dev, rtdConvertChanGain(dev, list[0], 0));
 	}
-	if (!pcidev) {
-		if (it->options[0] && it->options[1]) {
-			printk(KERN_INFO "No RTD card at bus=%d slot=%d.\n",
-			       it->options[0], it->options[1]);
-		} else {
-			printk(KERN_INFO "No RTD card found.\n");
+}
+
+/* determine fifo size by doing adc conversions until the fifo half
+empty status flag clears */
+static int rtd520_probe_fifo_depth(struct comedi_device *dev)
+{
+	unsigned int chanspec = CR_PACK(0, 0, AREF_GROUND);
+	unsigned i;
+	static const unsigned limit = 0x2000;
+	unsigned fifo_size = 0;
+
+	RtdAdcClearFifo(dev);
+	rtd_load_channelgain_list(dev, 1, &chanspec);
+	RtdAdcConversionSource(dev, 0);	/* software */
+	/* convert  samples */
+	for (i = 0; i < limit; ++i) {
+		unsigned fifo_status;
+		/* trigger conversion */
+		RtdAdcStart(dev);
+		udelay(1);
+		fifo_status = RtdFifoStatus(dev);
+		if ((fifo_status & FS_ADC_HEMPTY) == 0) {
+			fifo_size = 2 * i;
+			break;
 		}
+	}
+	if (i == limit) {
+		printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n",
+		       DRV_NAME);
 		return -EIO;
 	}
-	devpriv->pci_dev = pcidev;
-	dev->board_name = thisboard->name;
-
-	ret = comedi_pci_enable(pcidev, DRV_NAME);
-	if (ret < 0) {
-		printk(KERN_INFO "Failed to enable PCI device and request regions.\n");
-		return ret;
+	RtdAdcClearFifo(dev);
+	if (fifo_size != 0x400 && fifo_size != 0x2000) {
+		printk
+		    (KERN_INFO "\ncomedi: %s: unexpected fifo size of %i, expected 1024 or 8192.\n",
+		     DRV_NAME, fifo_size);
+		return -EIO;
 	}
-	devpriv->got_regions = 1;
-
-	/*
-	 * Initialize base addresses
-	 */
-	/* Get the physical address from PCI config */
-	physLas0 = pci_resource_start(devpriv->pci_dev, LAS0_PCIINDEX);
-	physLas1 = pci_resource_start(devpriv->pci_dev, LAS1_PCIINDEX);
-	physLcfg = pci_resource_start(devpriv->pci_dev, LCFG_PCIINDEX);
-	/* Now have the kernel map this into memory */
-	/* ASSUME page aligned */
-	devpriv->las0 = ioremap_nocache(physLas0, LAS0_PCISIZE);
-	devpriv->las1 = ioremap_nocache(physLas1, LAS1_PCISIZE);
-	devpriv->lcfg = ioremap_nocache(physLcfg, LCFG_PCISIZE);
+	return fifo_size;
+}
 
-	if (!devpriv->las0 || !devpriv->las1 || !devpriv->lcfg)
-		return -ENOMEM;
+/*
+  "instructions" read/write data in "one-shot" or "software-triggered"
+  mode (simplest case).
+  This doesn't use interrupts.
 
+  Note, we don't do any settling delays.  Use a instruction list to
+  select, delay, then read.
+ */
+static int rtd_ai_rinsn(struct comedi_device *dev,
+			struct comedi_subdevice *s, struct comedi_insn *insn,
+			unsigned int *data)
+{
+	int n, ii;
+	int stat;
 
-	DPRINTK("%s: LAS0=%llx, LAS1=%llx, CFG=%llx.\n", dev->board_name,
-		(unsigned long long)physLas0, (unsigned long long)physLas1,
-		(unsigned long long)physLcfg);
-	{			/* The RTD driver does this */
-		unsigned char pci_latency;
-		u16 revision;
-		/*uint32_t epld_version; */
+	/* clear any old fifo data */
+	RtdAdcClearFifo(dev);
 
-		pci_read_config_word(devpriv->pci_dev, PCI_REVISION_ID,
-				     &revision);
-		DPRINTK("%s: PCI revision %d.\n", dev->board_name, revision);
+	/* write channel to multiplexer and clear channel gain table */
+	rtd_load_channelgain_list(dev, 1, &insn->chanspec);
 
-		pci_read_config_byte(devpriv->pci_dev,
-				     PCI_LATENCY_TIMER, &pci_latency);
-		if (pci_latency < 32) {
-			printk(KERN_INFO "%s: PCI latency changed from %d to %d\n",
-			       dev->board_name, pci_latency, 32);
-			pci_write_config_byte(devpriv->pci_dev,
-					      PCI_LATENCY_TIMER, 32);
-		} else {
-			DPRINTK("rtd520: PCI latency = %d\n", pci_latency);
-		}
-
-		/*
-		 * Undocumented EPLD version (doesn't match RTD driver results)
-		 */
-		/*DPRINTK ("rtd520: Reading epld from %p\n",
-		   devpriv->las0+0);
-		   epld_version = readl (devpriv->las0+0);
-		   if ((epld_version & 0xF0) >> 4 == 0x0F) {
-		   DPRINTK("rtd520: pre-v8 EPLD. (%x)\n", epld_version);
-		   } else {
-		   DPRINTK("rtd520: EPLD version %x.\n", epld_version >> 4);
-		   } */
-	}
-
-	/* Show board configuration */
-	printk(KERN_INFO "%s:", dev->board_name);
-
-	/*
-	 * Allocate the subdevice structures.  alloc_subdevice() is a
-	 * convenient macro defined in comedidev.h.
-	 */
-	if (alloc_subdevices(dev, 4) < 0)
-		return -ENOMEM;
-
-
-	s = dev->subdevices + 0;
-	dev->read_subdev = s;
-	/* analog input subdevice */
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags =
-	    SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ;
-	s->n_chan = thisboard->aiChans;
-	s->maxdata = (1 << thisboard->aiBits) - 1;
-	if (thisboard->aiMaxGain <= 32)
-		s->range_table = &rtd_ai_7520_range;
-	else
-		s->range_table = &rtd_ai_4520_range;
-
-	s->len_chanlist = RTD_MAX_CHANLIST;	/* devpriv->fifoLen */
-	s->insn_read = rtd_ai_rinsn;
-	s->do_cmd = rtd_ai_cmd;
-	s->do_cmdtest = rtd_ai_cmdtest;
-	s->cancel = rtd_ai_cancel;
-	/* s->poll = rtd_ai_poll; *//* not ready yet */
-
-	s = dev->subdevices + 1;
-	/* analog output subdevice */
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = 2;
-	s->maxdata = (1 << thisboard->aiBits) - 1;
-	s->range_table = &rtd_ao_range;
-	s->insn_write = rtd_ao_winsn;
-	s->insn_read = rtd_ao_rinsn;
-
-	s = dev->subdevices + 2;
-	/* digital i/o subdevice */
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	/* we only support port 0 right now.  Ignoring port 1 and user IO */
-	s->n_chan = 8;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = rtd_dio_insn_bits;
-	s->insn_config = rtd_dio_insn_config;
-
-	/* timer/counter subdevices (not currently supported) */
-	s = dev->subdevices + 3;
-	s->type = COMEDI_SUBD_COUNTER;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 3;
-	s->maxdata = 0xffff;
-
-	/* initialize board, per RTD spec */
-	/* also, initialize shadow registers */
-	RtdResetBoard(dev);
-	udelay(100);		/* needed? */
-	RtdPlxInterruptWrite(dev, 0);
-	RtdInterruptMask(dev, 0);	/* and sets shadow */
-	RtdInterruptClearMask(dev, ~0);	/* and sets shadow */
-	RtdInterruptClear(dev);	/* clears bits set by mask */
-	RtdInterruptOverrunClear(dev);
-	RtdClearCGT(dev);
-	RtdAdcClearFifo(dev);
-	RtdDacClearFifo(dev, 0);
-	RtdDacClearFifo(dev, 1);
-	/* clear digital IO fifo */
-	RtdDioStatusWrite(dev, 0);	/* safe state, set shadow */
-	RtdUtcCtrlPut(dev, 0, 0x30);	/* safe state, set shadow */
-	RtdUtcCtrlPut(dev, 1, 0x30);	/* safe state, set shadow */
-	RtdUtcCtrlPut(dev, 2, 0x30);	/* safe state, set shadow */
-	RtdUtcCtrlPut(dev, 3, 0);	/* safe state, set shadow */
-	/* TODO: set user out source ??? */
-
-	/* check if our interrupt is available and get it */
-	ret = request_irq(devpriv->pci_dev->irq, rtd_interrupt,
-			  IRQF_SHARED, DRV_NAME, dev);
-
-	if (ret < 0) {
-		printk("Could not get interrupt! (%u)\n",
-		       devpriv->pci_dev->irq);
-		return ret;
-	}
-	dev->irq = devpriv->pci_dev->irq;
-	printk(KERN_INFO "( irq=%u )", dev->irq);
-
-	ret = rtd520_probe_fifo_depth(dev);
-	if (ret < 0)
-		return ret;
-
-	devpriv->fifoLen = ret;
-	printk("( fifoLen=%d )", devpriv->fifoLen);
-
-#ifdef USE_DMA
-	if (dev->irq > 0) {
-		printk("( DMA buff=%d )\n", DMA_CHAIN_COUNT);
-		/*
-		 * The PLX9080 has 2 DMA controllers, but there could be
-		 * 4 sources: ADC, digital, DAC1, and DAC2.  Since only the
-		 * ADC supports cmd mode right now, this isn't an issue (yet)
-		 */
-		devpriv->dma0Offset = 0;
-
-		for (index = 0; index < DMA_CHAIN_COUNT; index++) {
-			devpriv->dma0Buff[index] =
-			    pci_alloc_consistent(devpriv->pci_dev,
-						 sizeof(u16) *
-						 devpriv->fifoLen / 2,
-						 &devpriv->
-						 dma0BuffPhysAddr[index]);
-			if (devpriv->dma0Buff[index] == NULL) {
-				ret = -ENOMEM;
-				goto rtd_attach_die_error;
-			}
-			/*DPRINTK ("buff[%d] @ %p virtual, %x PCI\n",
-			   index,
-			   devpriv->dma0Buff[index],
-			   devpriv->dma0BuffPhysAddr[index]); */
-		}
-
-		/*
-		 * setup DMA descriptor ring (use cpu_to_le32 for byte
-		 * ordering?)
-		 */
-		devpriv->dma0Chain =
-		    pci_alloc_consistent(devpriv->pci_dev,
-					 sizeof(struct plx_dma_desc) *
-					 DMA_CHAIN_COUNT,
-					 &devpriv->dma0ChainPhysAddr);
-		for (index = 0; index < DMA_CHAIN_COUNT; index++) {
-			devpriv->dma0Chain[index].pci_start_addr =
-			    devpriv->dma0BuffPhysAddr[index];
-			devpriv->dma0Chain[index].local_start_addr =
-			    DMALADDR_ADC;
-			devpriv->dma0Chain[index].transfer_size =
-			    sizeof(u16) * devpriv->fifoLen / 2;
-			devpriv->dma0Chain[index].next =
-			    (devpriv->dma0ChainPhysAddr + ((index +
-							    1) %
-							   (DMA_CHAIN_COUNT))
-			     * sizeof(devpriv->dma0Chain[0]))
-			    | DMA_TRANSFER_BITS;
-			/*DPRINTK ("ring[%d] @%lx PCI: %x, local: %x, N: 0x%x, next: %x\n",
-			   index,
-			   ((long)devpriv->dma0ChainPhysAddr
-			   + (index * sizeof(devpriv->dma0Chain[0]))),
-			   devpriv->dma0Chain[index].pci_start_addr,
-			   devpriv->dma0Chain[index].local_start_addr,
-			   devpriv->dma0Chain[index].transfer_size,
-			   devpriv->dma0Chain[index].next); */
-		}
-
-		if (devpriv->dma0Chain == NULL) {
-			ret = -ENOMEM;
-			goto rtd_attach_die_error;
-		}
-
-		RtdDma0Mode(dev, DMA_MODE_BITS);
-		/* set DMA trigger source */
-		RtdDma0Source(dev, DMAS_ADFIFO_HALF_FULL);
-	} else {
-		printk(KERN_INFO "( no IRQ->no DMA )");
-	}
-#endif /* USE_DMA */
-
-	if (dev->irq) {		/* enable plx9080 interrupts */
-		RtdPlxInterruptWrite(dev, ICS_PIE | ICS_PLIE);
-	}
-
-	printk("\ncomedi%d: rtd520 driver attached.\n", dev->minor);
-
-	return 1;
-
-#if 0
-	/* hit an error, clean up memory and return ret */
-/* rtd_attach_die_error: */
-#ifdef USE_DMA
-	for (index = 0; index < DMA_CHAIN_COUNT; index++) {
-		if (NULL != devpriv->dma0Buff[index]) {	/* free buffer memory */
-			pci_free_consistent(devpriv->pci_dev,
-					    sizeof(u16) * devpriv->fifoLen / 2,
-					    devpriv->dma0Buff[index],
-					    devpriv->dma0BuffPhysAddr[index]);
-			devpriv->dma0Buff[index] = NULL;
-		}
-	}
-	if (NULL != devpriv->dma0Chain) {
-		pci_free_consistent(devpriv->pci_dev,
-				    sizeof(struct plx_dma_desc)
-				    * DMA_CHAIN_COUNT,
-				    devpriv->dma0Chain,
-				    devpriv->dma0ChainPhysAddr);
-		devpriv->dma0Chain = NULL;
-	}
-#endif /* USE_DMA */
-	/* subdevices and priv are freed by the core */
-	if (dev->irq) {
-		/* disable interrupt controller */
-		RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev)
-				     & ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E));
-		free_irq(dev->irq, dev);
-	}
-
-	/* release all regions that were allocated */
-	if (devpriv->las0)
-		iounmap(devpriv->las0);
-
-	if (devpriv->las1)
-		iounmap(devpriv->las1);
-
-	if (devpriv->lcfg)
-		iounmap(devpriv->lcfg);
-
-	if (devpriv->pci_dev)
-		pci_dev_put(devpriv->pci_dev);
-
-	return ret;
-#endif
-}
-
-static void rtd_detach(struct comedi_device *dev)
-{
-#ifdef USE_DMA
-	int index;
-#endif
-
-	if (devpriv) {
-		/* Shut down any board ops by resetting it */
-#ifdef USE_DMA
-		if (devpriv->lcfg) {
-			RtdDma0Control(dev, 0);	/* disable DMA */
-			RtdDma1Control(dev, 0);	/* disable DMA */
-			RtdPlxInterruptWrite(dev, ICS_PIE | ICS_PLIE);
-		}
-#endif /* USE_DMA */
-		if (devpriv->las0) {
-			RtdResetBoard(dev);
-			RtdInterruptMask(dev, 0);
-			RtdInterruptClearMask(dev, ~0);
-			RtdInterruptClear(dev);	/* clears bits set by mask */
-		}
-#ifdef USE_DMA
-		/* release DMA */
-		for (index = 0; index < DMA_CHAIN_COUNT; index++) {
-			if (NULL != devpriv->dma0Buff[index]) {
-				pci_free_consistent(devpriv->pci_dev,
-						    sizeof(u16) *
-						    devpriv->fifoLen / 2,
-						    devpriv->dma0Buff[index],
-						    devpriv->
-						    dma0BuffPhysAddr[index]);
-				devpriv->dma0Buff[index] = NULL;
-			}
-		}
-		if (NULL != devpriv->dma0Chain) {
-			pci_free_consistent(devpriv->pci_dev,
-					    sizeof(struct plx_dma_desc) *
-					    DMA_CHAIN_COUNT, devpriv->dma0Chain,
-					    devpriv->dma0ChainPhysAddr);
-			devpriv->dma0Chain = NULL;
-		}
-#endif /* USE_DMA */
-		if (dev->irq) {
-			RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev)
-					     & ~(ICS_PLIE | ICS_DMA0_E |
-						 ICS_DMA1_E));
-			free_irq(dev->irq, dev);
-		}
-		if (devpriv->las0)
-			iounmap(devpriv->las0);
-		if (devpriv->las1)
-			iounmap(devpriv->las1);
-		if (devpriv->lcfg)
-			iounmap(devpriv->lcfg);
-		if (devpriv->pci_dev) {
-			if (devpriv->got_regions)
-				comedi_pci_disable(devpriv->pci_dev);
-			pci_dev_put(devpriv->pci_dev);
-		}
-	}
-}
-
-/*
-  Convert a single comedi channel-gain entry to a RTD520 table entry
-*/
-static unsigned short rtdConvertChanGain(struct comedi_device *dev,
-					 unsigned int comediChan, int chanIndex)
-{				/* index in channel list */
-	unsigned int chan, range, aref;
-	unsigned short r = 0;
-
-	chan = CR_CHAN(comediChan);
-	range = CR_RANGE(comediChan);
-	aref = CR_AREF(comediChan);
-
-	r |= chan & 0xf;
-
-	/* Note: we also setup the channel list bipolar flag array */
-	if (range < thisboard->range10Start) {	/* first batch are +-5 */
-		r |= 0x000;	/* +-5 range */
-		r |= (range & 0x7) << 4;	/* gain */
-		CHAN_ARRAY_SET(devpriv->chanBipolar, chanIndex);
-	} else if (range < thisboard->rangeUniStart) {	/* second batch are +-10 */
-		r |= 0x100;	/* +-10 range */
-		/* gain */
-		r |= ((range - thisboard->range10Start) & 0x7) << 4;
-		CHAN_ARRAY_SET(devpriv->chanBipolar, chanIndex);
-	} else {		/* last batch is +10 */
-		r |= 0x200;	/* +10 range */
-		/* gain */
-		r |= ((range - thisboard->rangeUniStart) & 0x7) << 4;
-		CHAN_ARRAY_CLEAR(devpriv->chanBipolar, chanIndex);
-	}
-
-	switch (aref) {
-	case AREF_GROUND:	/* on-board ground */
-		break;
-
-	case AREF_COMMON:
-		r |= 0x80;	/* ref external analog common */
-		break;
-
-	case AREF_DIFF:
-		r |= 0x400;	/* differential inputs */
-		break;
-
-	case AREF_OTHER:	/* ??? */
-		break;
-	}
-	/*printk ("chan=%d r=%d a=%d -> 0x%x\n",
-	   chan, range, aref, r); */
-	return r;
-}
-
-/*
-  Setup the channel-gain table from a comedi list
-*/
-static void rtd_load_channelgain_list(struct comedi_device *dev,
-				      unsigned int n_chan, unsigned int *list)
-{
-	if (n_chan > 1) {	/* setup channel gain table */
-		int ii;
-		RtdClearCGT(dev);
-		RtdEnableCGT(dev, 1);	/* enable table */
-		for (ii = 0; ii < n_chan; ii++) {
-			RtdWriteCGTable(dev, rtdConvertChanGain(dev, list[ii],
-								ii));
-		}
-	} else {		/* just use the channel gain latch */
-		RtdEnableCGT(dev, 0);	/* disable table, enable latch */
-		RtdWriteCGLatch(dev, rtdConvertChanGain(dev, list[0], 0));
-	}
-}
-
-/* determine fifo size by doing adc conversions until the fifo half
-empty status flag clears */
-static int rtd520_probe_fifo_depth(struct comedi_device *dev)
-{
-	unsigned int chanspec = CR_PACK(0, 0, AREF_GROUND);
-	unsigned i;
-	static const unsigned limit = 0x2000;
-	unsigned fifo_size = 0;
-
-	RtdAdcClearFifo(dev);
-	rtd_load_channelgain_list(dev, 1, &chanspec);
-	RtdAdcConversionSource(dev, 0);	/* software */
-	/* convert  samples */
-	for (i = 0; i < limit; ++i) {
-		unsigned fifo_status;
-		/* trigger conversion */
-		RtdAdcStart(dev);
-		udelay(1);
-		fifo_status = RtdFifoStatus(dev);
-		if ((fifo_status & FS_ADC_HEMPTY) == 0) {
-			fifo_size = 2 * i;
-			break;
-		}
-	}
-	if (i == limit) {
-		printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n",
-		       DRV_NAME);
-		return -EIO;
-	}
-	RtdAdcClearFifo(dev);
-	if (fifo_size != 0x400 && fifo_size != 0x2000) {
-		printk
-		    (KERN_INFO "\ncomedi: %s: unexpected fifo size of %i, expected 1024 or 8192.\n",
-		     DRV_NAME, fifo_size);
-		return -EIO;
-	}
-	return fifo_size;
-}
-
-/*
-  "instructions" read/write data in "one-shot" or "software-triggered"
-  mode (simplest case).
-  This doesn't use interrupts.
-
-  Note, we don't do any settling delays.  Use a instruction list to
-  select, delay, then read.
- */
-static int rtd_ai_rinsn(struct comedi_device *dev,
-			struct comedi_subdevice *s, struct comedi_insn *insn,
-			unsigned int *data)
-{
-	int n, ii;
-	int stat;
-
-	/* clear any old fifo data */
-	RtdAdcClearFifo(dev);
-
-	/* write channel to multiplexer and clear channel gain table */
-	rtd_load_channelgain_list(dev, 1, &insn->chanspec);
-
-	/* set conversion source */
-	RtdAdcConversionSource(dev, 0);	/* software */
+	/* set conversion source */
+	RtdAdcConversionSource(dev, 0);	/* software */
 
 	/* convert n samples */
 	for (n = 0; n < insn->n; n++) {
@@ -1611,708 +1213,1068 @@ static irqreturn_t rtd_interrupt(int irq,	/* interrupt number (ignored) */
 		DPRINTK("rtd520: unknown interrupt source!\n");
 	}
 
-	if (0xffff & RtdInterruptOverrunStatus(dev)) {	/* interrupt overrun */
-		DPRINTK
-		    ("rtd520: Interrupt overrun with %ld to go! over_status=0x%x\n",
-		     devpriv->aiCount, 0xffff & RtdInterruptOverrunStatus(dev));
-		goto abortTransfer;
+	if (0xffff & RtdInterruptOverrunStatus(dev)) {	/* interrupt overrun */
+		DPRINTK
+		    ("rtd520: Interrupt overrun with %ld to go! over_status=0x%x\n",
+		     devpriv->aiCount, 0xffff & RtdInterruptOverrunStatus(dev));
+		goto abortTransfer;
+	}
+
+	/* clear the interrupt */
+	RtdInterruptClearMask(dev, status);
+	RtdInterruptClear(dev);
+	return IRQ_HANDLED;
+
+abortTransfer:
+	RtdAdcClearFifo(dev);	/* clears full flag */
+	s->async->events |= COMEDI_CB_ERROR;
+	devpriv->aiCount = 0;	/* stop and don't transfer any more */
+	/* fall into transferDone */
+
+transferDone:
+	RtdPacerStopSource(dev, 0);	/* stop on SOFTWARE stop */
+	RtdPacerStop(dev);	/* Stop PACER */
+	RtdAdcConversionSource(dev, 0);	/* software trigger only */
+	RtdInterruptMask(dev, 0);	/* mask out SAMPLE */
+#ifdef USE_DMA
+	if (devpriv->flags & DMA0_ACTIVE) {
+		RtdPlxInterruptWrite(dev,	/* disable any more interrupts */
+				     RtdPlxInterruptRead(dev) & ~ICS_DMA0_E);
+		abort_dma(dev, 0);
+		devpriv->flags &= ~DMA0_ACTIVE;
+		/* if Using DMA, then we should have read everything by now */
+		if (devpriv->aiCount > 0) {
+			DPRINTK("rtd520: Lost DMA data! %ld remain\n",
+				devpriv->aiCount);
+		}
+	}
+#endif /* USE_DMA */
+
+	if (devpriv->aiCount > 0) {	/* there shouldn't be anything left */
+		fifoStatus = RtdFifoStatus(dev);
+		DPRINTK("rtd520: Finishing up. %ld remain, fifoStat=%x\n", devpriv->aiCount, (fifoStatus ^ 0x6666) & 0x7777);	/* should read all 0s */
+		ai_read_dregs(dev, s);	/* read anything left in FIFO */
+	}
+
+	s->async->events |= COMEDI_CB_EOA;	/* signal end to comedi */
+	comedi_event(dev, s);
+
+	/* clear the interrupt */
+	status = RtdInterruptStatus(dev);
+	RtdInterruptClearMask(dev, status);
+	RtdInterruptClear(dev);
+
+	fifoStatus = RtdFifoStatus(dev);	/* DEBUG */
+	DPRINTK
+	    ("rtd520: Acquisition complete. %ld ints, intStat=%x, overStat=%x\n",
+	     devpriv->intCount, status,
+	     0xffff & RtdInterruptOverrunStatus(dev));
+
+	return IRQ_HANDLED;
+}
+
+#if 0
+/*
+  return the number of samples available
+*/
+static int rtd_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+	/* TODO: This needs to mask interrupts, read_dregs, and then re-enable */
+	/* Not sure what to do if DMA is active */
+	return s->async->buf_write_count - s->async->buf_read_count;
+}
+#endif
+
+/*
+  cmdtest tests a particular command to see if it is valid.
+  Using the cmdtest ioctl, a user can create a valid cmd
+  and then have it executed by the cmd ioctl (asyncronously).
+
+  cmdtest returns 1,2,3,4 or 0, depending on which tests
+  the command passes.
+*/
+
+static int rtd_ai_cmdtest(struct comedi_device *dev,
+			  struct comedi_subdevice *s, struct comedi_cmd *cmd)
+{
+	int err = 0;
+	int tmp;
+
+	/* step 1: make sure trigger sources are trivially valid */
+
+	tmp = cmd->start_src;
+	cmd->start_src &= TRIG_NOW;
+	if (!cmd->start_src || tmp != cmd->start_src)
+		err++;
+
+	tmp = cmd->scan_begin_src;
+	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
+	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
+		err++;
+
+
+	tmp = cmd->convert_src;
+	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
+	if (!cmd->convert_src || tmp != cmd->convert_src)
+		err++;
+
+
+	tmp = cmd->scan_end_src;
+	cmd->scan_end_src &= TRIG_COUNT;
+	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
+		err++;
+
+
+	tmp = cmd->stop_src;
+	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
+	if (!cmd->stop_src || tmp != cmd->stop_src)
+		err++;
+
+
+	if (err)
+		return 1;
+
+	/* step 2: make sure trigger sources are unique
+	   and mutually compatible */
+	/* note that mutual compatibility is not an issue here */
+	if (cmd->scan_begin_src != TRIG_TIMER &&
+	    cmd->scan_begin_src != TRIG_EXT) {
+		err++;
+	}
+	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
+		err++;
+
+	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
+		err++;
+
+	if (err)
+		return 2;
+
+	/* step 3: make sure arguments are trivially compatible */
+
+	if (cmd->start_arg != 0) {
+		cmd->start_arg = 0;
+		err++;
+	}
+
+	if (cmd->scan_begin_src == TRIG_TIMER) {
+		/* Note: these are time periods, not actual rates */
+		if (1 == cmd->chanlist_len) {	/* no scanning */
+			if (cmd->scan_begin_arg < RTD_MAX_SPEED_1) {
+				cmd->scan_begin_arg = RTD_MAX_SPEED_1;
+				rtd_ns_to_timer(&cmd->scan_begin_arg,
+						TRIG_ROUND_UP);
+				err++;
+			}
+			if (cmd->scan_begin_arg > RTD_MIN_SPEED_1) {
+				cmd->scan_begin_arg = RTD_MIN_SPEED_1;
+				rtd_ns_to_timer(&cmd->scan_begin_arg,
+						TRIG_ROUND_DOWN);
+				err++;
+			}
+		} else {
+			if (cmd->scan_begin_arg < RTD_MAX_SPEED) {
+				cmd->scan_begin_arg = RTD_MAX_SPEED;
+				rtd_ns_to_timer(&cmd->scan_begin_arg,
+						TRIG_ROUND_UP);
+				err++;
+			}
+			if (cmd->scan_begin_arg > RTD_MIN_SPEED) {
+				cmd->scan_begin_arg = RTD_MIN_SPEED;
+				rtd_ns_to_timer(&cmd->scan_begin_arg,
+						TRIG_ROUND_DOWN);
+				err++;
+			}
+		}
+	} else {
+		/* external trigger */
+		/* should be level/edge, hi/lo specification here */
+		/* should specify multiple external triggers */
+		if (cmd->scan_begin_arg > 9) {
+			cmd->scan_begin_arg = 9;
+			err++;
+		}
+	}
+	if (cmd->convert_src == TRIG_TIMER) {
+		if (1 == cmd->chanlist_len) {	/* no scanning */
+			if (cmd->convert_arg < RTD_MAX_SPEED_1) {
+				cmd->convert_arg = RTD_MAX_SPEED_1;
+				rtd_ns_to_timer(&cmd->convert_arg,
+						TRIG_ROUND_UP);
+				err++;
+			}
+			if (cmd->convert_arg > RTD_MIN_SPEED_1) {
+				cmd->convert_arg = RTD_MIN_SPEED_1;
+				rtd_ns_to_timer(&cmd->convert_arg,
+						TRIG_ROUND_DOWN);
+				err++;
+			}
+		} else {
+			if (cmd->convert_arg < RTD_MAX_SPEED) {
+				cmd->convert_arg = RTD_MAX_SPEED;
+				rtd_ns_to_timer(&cmd->convert_arg,
+						TRIG_ROUND_UP);
+				err++;
+			}
+			if (cmd->convert_arg > RTD_MIN_SPEED) {
+				cmd->convert_arg = RTD_MIN_SPEED;
+				rtd_ns_to_timer(&cmd->convert_arg,
+						TRIG_ROUND_DOWN);
+				err++;
+			}
+		}
+	} else {
+		/* external trigger */
+		/* see above */
+		if (cmd->convert_arg > 9) {
+			cmd->convert_arg = 9;
+			err++;
+		}
+	}
+
+#if 0
+	if (cmd->scan_end_arg != cmd->chanlist_len) {
+		cmd->scan_end_arg = cmd->chanlist_len;
+		err++;
+	}
+#endif
+	if (cmd->stop_src == TRIG_COUNT) {
+		/* TODO check for rounding error due to counter wrap */
+
+	} else {
+		/* TRIG_NONE */
+		if (cmd->stop_arg != 0) {
+			cmd->stop_arg = 0;
+			err++;
+		}
+	}
+
+	if (err)
+		return 3;
+
+
+	/* step 4: fix up any arguments */
+
+	if (cmd->chanlist_len > RTD_MAX_CHANLIST) {
+		cmd->chanlist_len = RTD_MAX_CHANLIST;
+		err++;
+	}
+	if (cmd->scan_begin_src == TRIG_TIMER) {
+		tmp = cmd->scan_begin_arg;
+		rtd_ns_to_timer(&cmd->scan_begin_arg,
+				cmd->flags & TRIG_ROUND_MASK);
+		if (tmp != cmd->scan_begin_arg)
+			err++;
+
+	}
+	if (cmd->convert_src == TRIG_TIMER) {
+		tmp = cmd->convert_arg;
+		rtd_ns_to_timer(&cmd->convert_arg,
+				cmd->flags & TRIG_ROUND_MASK);
+		if (tmp != cmd->convert_arg)
+			err++;
+
+		if (cmd->scan_begin_src == TRIG_TIMER
+		    && (cmd->scan_begin_arg
+			< (cmd->convert_arg * cmd->scan_end_arg))) {
+			cmd->scan_begin_arg =
+			    cmd->convert_arg * cmd->scan_end_arg;
+			err++;
+		}
 	}
 
-	/* clear the interrupt */
-	RtdInterruptClearMask(dev, status);
-	RtdInterruptClear(dev);
-	return IRQ_HANDLED;
+	if (err)
+		return 4;
 
-abortTransfer:
-	RtdAdcClearFifo(dev);	/* clears full flag */
-	s->async->events |= COMEDI_CB_ERROR;
-	devpriv->aiCount = 0;	/* stop and don't transfer any more */
-	/* fall into transferDone */
+	return 0;
+}
 
-transferDone:
+/*
+  Execute a analog in command with many possible triggering options.
+  The data get stored in the async structure of the subdevice.
+  This is usually done by an interrupt handler.
+  Userland gets to the data using read calls.
+*/
+static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+	struct comedi_cmd *cmd = &s->async->cmd;
+	int timer;
+
+	/* stop anything currently running */
 	RtdPacerStopSource(dev, 0);	/* stop on SOFTWARE stop */
-	RtdPacerStop(dev);	/* Stop PACER */
+	RtdPacerStop(dev);	/* make sure PACER is stopped */
 	RtdAdcConversionSource(dev, 0);	/* software trigger only */
-	RtdInterruptMask(dev, 0);	/* mask out SAMPLE */
+	RtdInterruptMask(dev, 0);
 #ifdef USE_DMA
-	if (devpriv->flags & DMA0_ACTIVE) {
+	if (devpriv->flags & DMA0_ACTIVE) {	/* cancel anything running */
 		RtdPlxInterruptWrite(dev,	/* disable any more interrupts */
 				     RtdPlxInterruptRead(dev) & ~ICS_DMA0_E);
 		abort_dma(dev, 0);
 		devpriv->flags &= ~DMA0_ACTIVE;
-		/* if Using DMA, then we should have read everything by now */
-		if (devpriv->aiCount > 0) {
-			DPRINTK("rtd520: Lost DMA data! %ld remain\n",
-				devpriv->aiCount);
+		if (RtdPlxInterruptRead(dev) & ICS_DMA0_A) {	/*clear pending int */
+			RtdDma0Control(dev, PLX_CLEAR_DMA_INTR_BIT);
 		}
 	}
+	RtdDma0Reset(dev);	/* reset onboard state */
 #endif /* USE_DMA */
+	RtdAdcClearFifo(dev);	/* clear any old data */
+	RtdInterruptOverrunClear(dev);
+	devpriv->intCount = 0;
 
-	if (devpriv->aiCount > 0) {	/* there shouldn't be anything left */
-		fifoStatus = RtdFifoStatus(dev);
-		DPRINTK("rtd520: Finishing up. %ld remain, fifoStat=%x\n", devpriv->aiCount, (fifoStatus ^ 0x6666) & 0x7777);	/* should read all 0s */
-		ai_read_dregs(dev, s);	/* read anything left in FIFO */
+	if (!dev->irq) {	/* we need interrupts for this */
+		DPRINTK("rtd520: ERROR! No interrupt available!\n");
+		return -ENXIO;
 	}
 
-	s->async->events |= COMEDI_CB_EOA;	/* signal end to comedi */
-	comedi_event(dev, s);
+	/* start configuration */
+	/* load channel list and reset CGT */
+	rtd_load_channelgain_list(dev, cmd->chanlist_len, cmd->chanlist);
 
-	/* clear the interrupt */
-	status = RtdInterruptStatus(dev);
-	RtdInterruptClearMask(dev, status);
+	/* setup the common case and override if needed */
+	if (cmd->chanlist_len > 1) {
+		/*DPRINTK ("rtd520: Multi channel setup\n"); */
+		RtdPacerStartSource(dev, 0);	/* software triggers pacer */
+		RtdBurstStartSource(dev, 1);	/* PACER triggers burst */
+		RtdAdcConversionSource(dev, 2);	/* BURST triggers ADC */
+	} else {		/* single channel */
+		/*DPRINTK ("rtd520: single channel setup\n"); */
+		RtdPacerStartSource(dev, 0);	/* software triggers pacer */
+		RtdAdcConversionSource(dev, 1);	/* PACER triggers ADC */
+	}
+	RtdAboutCounter(dev, devpriv->fifoLen / 2 - 1);	/* 1/2 FIFO */
+
+	if (TRIG_TIMER == cmd->scan_begin_src) {
+		/* scan_begin_arg is in nanoseconds */
+		/* find out how many samples to wait before transferring */
+		if (cmd->flags & TRIG_WAKE_EOS) {
+			/* this may generate un-sustainable interrupt rates */
+			/* the application is responsible for doing the right thing */
+			devpriv->transCount = cmd->chanlist_len;
+			devpriv->flags |= SEND_EOS;
+		} else {
+			/* arrange to transfer data periodically */
+			devpriv->transCount
+			    =
+			    (TRANS_TARGET_PERIOD * cmd->chanlist_len) /
+			    cmd->scan_begin_arg;
+			if (devpriv->transCount < cmd->chanlist_len) {
+				/* transfer after each scan (and avoid 0) */
+				devpriv->transCount = cmd->chanlist_len;
+			} else {	/* make a multiple of scan length */
+				devpriv->transCount =
+				    (devpriv->transCount +
+				     cmd->chanlist_len - 1)
+				    / cmd->chanlist_len;
+				devpriv->transCount *= cmd->chanlist_len;
+			}
+			devpriv->flags |= SEND_EOS;
+		}
+		if (devpriv->transCount >= (devpriv->fifoLen / 2)) {
+			/* out of counter range, use 1/2 fifo instead */
+			devpriv->transCount = 0;
+			devpriv->flags &= ~SEND_EOS;
+		} else {
+			/* interrupt for each transfer */
+			RtdAboutCounter(dev, devpriv->transCount - 1);
+		}
+
+		DPRINTK
+		    ("rtd520: scanLen=%d transferCount=%d fifoLen=%d\n  scanTime(ns)=%d flags=0x%x\n",
+		     cmd->chanlist_len, devpriv->transCount, devpriv->fifoLen,
+		     cmd->scan_begin_arg, devpriv->flags);
+	} else {		/* unknown timing, just use 1/2 FIFO */
+		devpriv->transCount = 0;
+		devpriv->flags &= ~SEND_EOS;
+	}
+	RtdPacerClockSource(dev, 1);	/* use INTERNAL 8Mhz clock source */
+	RtdAboutStopEnable(dev, 1);	/* just interrupt, dont stop */
+
+	/* BUG??? these look like enumerated values, but they are bit fields */
+
+	/* First, setup when to stop */
+	switch (cmd->stop_src) {
+	case TRIG_COUNT:	/* stop after N scans */
+		devpriv->aiCount = cmd->stop_arg * cmd->chanlist_len;
+		if ((devpriv->transCount > 0)
+		    && (devpriv->transCount > devpriv->aiCount)) {
+			devpriv->transCount = devpriv->aiCount;
+		}
+		break;
+
+	case TRIG_NONE:	/* stop when cancel is called */
+		devpriv->aiCount = -1;	/* read forever */
+		break;
+
+	default:
+		DPRINTK("rtd520: Warning! ignoring stop_src mode %d\n",
+			cmd->stop_src);
+	}
+
+	/* Scan timing */
+	switch (cmd->scan_begin_src) {
+	case TRIG_TIMER:	/* periodic scanning */
+		timer = rtd_ns_to_timer(&cmd->scan_begin_arg,
+					TRIG_ROUND_NEAREST);
+		/* set PACER clock */
+		/*DPRINTK ("rtd520: loading %d into pacer\n", timer); */
+		RtdPacerCounter(dev, timer);
+
+		break;
+
+	case TRIG_EXT:
+		RtdPacerStartSource(dev, 1);	/* EXTERNALy trigger pacer */
+		break;
+
+	default:
+		DPRINTK("rtd520: Warning! ignoring scan_begin_src mode %d\n",
+			cmd->scan_begin_src);
+	}
+
+	/* Sample timing within a scan */
+	switch (cmd->convert_src) {
+	case TRIG_TIMER:	/* periodic */
+		if (cmd->chanlist_len > 1) {	/* only needed for multi-channel */
+			timer = rtd_ns_to_timer(&cmd->convert_arg,
+						TRIG_ROUND_NEAREST);
+			/* setup BURST clock */
+			/*DPRINTK ("rtd520: loading %d into burst\n", timer); */
+			RtdBurstCounter(dev, timer);
+		}
+
+		break;
+
+	case TRIG_EXT:		/* external */
+		RtdBurstStartSource(dev, 2);	/* EXTERNALy trigger burst */
+		break;
+
+	default:
+		DPRINTK("rtd520: Warning! ignoring convert_src mode %d\n",
+			cmd->convert_src);
+	}
+	/* end configuration */
+
+	/* This doesn't seem to work.  There is no way to clear an interrupt
+	   that the priority controller has queued! */
+	RtdInterruptClearMask(dev, ~0);	/* clear any existing flags */
 	RtdInterruptClear(dev);
 
-	fifoStatus = RtdFifoStatus(dev);	/* DEBUG */
-	DPRINTK
-	    ("rtd520: Acquisition complete. %ld ints, intStat=%x, overStat=%x\n",
-	     devpriv->intCount, status,
-	     0xffff & RtdInterruptOverrunStatus(dev));
+	/* TODO: allow multiple interrupt sources */
+	if (devpriv->transCount > 0) {	/* transfer every N samples */
+		RtdInterruptMask(dev, IRQM_ADC_ABOUT_CNT);
+		DPRINTK("rtd520: Transferring every %d\n", devpriv->transCount);
+	} else {		/* 1/2 FIFO transfers */
+#ifdef USE_DMA
+		devpriv->flags |= DMA0_ACTIVE;
 
-	return IRQ_HANDLED;
+		/* point to first transfer in ring */
+		devpriv->dma0Offset = 0;
+		RtdDma0Mode(dev, DMA_MODE_BITS);
+		RtdDma0Next(dev,	/* point to first block */
+			    devpriv->dma0Chain[DMA_CHAIN_COUNT - 1].next);
+		RtdDma0Source(dev, DMAS_ADFIFO_HALF_FULL);	/* set DMA trigger source */
+
+		RtdPlxInterruptWrite(dev,	/* enable interrupt */
+				     RtdPlxInterruptRead(dev) | ICS_DMA0_E);
+		/* Must be 2 steps.  See PLX app note about "Starting a DMA transfer" */
+		RtdDma0Control(dev, PLX_DMA_EN_BIT);	/* enable DMA (clear INTR?) */
+		RtdDma0Control(dev, PLX_DMA_EN_BIT | PLX_DMA_START_BIT);	/*start DMA */
+		DPRINTK("rtd520: Using DMA0 transfers. plxInt %x RtdInt %x\n",
+			RtdPlxInterruptRead(dev), devpriv->intMask);
+#else /* USE_DMA */
+		RtdInterruptMask(dev, IRQM_ADC_ABOUT_CNT);
+		DPRINTK("rtd520: Transferring every 1/2 FIFO\n");
+#endif /* USE_DMA */
+	}
+
+	/* BUG: start_src is ASSUMED to be TRIG_NOW */
+	/* BUG? it seems like things are running before the "start" */
+	RtdPacerStart(dev);	/* Start PACER */
+	return 0;
 }
 
-#if 0
 /*
-  return the number of samples available
+  Stop a running data acquisition.
 */
-static int rtd_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
+static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 {
-	/* TODO: This needs to mask interrupts, read_dregs, and then re-enable */
-	/* Not sure what to do if DMA is active */
-	return s->async->buf_write_count - s->async->buf_read_count;
+	u16 status;
+
+	RtdPacerStopSource(dev, 0);	/* stop on SOFTWARE stop */
+	RtdPacerStop(dev);	/* Stop PACER */
+	RtdAdcConversionSource(dev, 0);	/* software trigger only */
+	RtdInterruptMask(dev, 0);
+	devpriv->aiCount = 0;	/* stop and don't transfer any more */
+#ifdef USE_DMA
+	if (devpriv->flags & DMA0_ACTIVE) {
+		RtdPlxInterruptWrite(dev,	/* disable any more interrupts */
+				     RtdPlxInterruptRead(dev) & ~ICS_DMA0_E);
+		abort_dma(dev, 0);
+		devpriv->flags &= ~DMA0_ACTIVE;
+	}
+#endif /* USE_DMA */
+	status = RtdInterruptStatus(dev);
+	DPRINTK
+	    ("rtd520: Acquisition canceled. %ld ints, intStat=%x, overStat=%x\n",
+	     devpriv->intCount, status,
+	     0xffff & RtdInterruptOverrunStatus(dev));
+	return 0;
 }
-#endif
 
 /*
-  cmdtest tests a particular command to see if it is valid.
-  Using the cmdtest ioctl, a user can create a valid cmd
-  and then have it executed by the cmd ioctl (asyncronously).
-
-  cmdtest returns 1,2,3,4 or 0, depending on which tests
-  the command passes.
+  Output one (or more) analog values to a single port as fast as possible.
 */
-
-static int rtd_ai_cmdtest(struct comedi_device *dev,
-			  struct comedi_subdevice *s, struct comedi_cmd *cmd)
+static int rtd_ao_winsn(struct comedi_device *dev,
+			struct comedi_subdevice *s, struct comedi_insn *insn,
+			unsigned int *data)
 {
-	int err = 0;
-	int tmp;
-
-	/* step 1: make sure trigger sources are trivially valid */
-
-	tmp = cmd->start_src;
-	cmd->start_src &= TRIG_NOW;
-	if (!cmd->start_src || tmp != cmd->start_src)
-		err++;
-
-	tmp = cmd->scan_begin_src;
-	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
-		err++;
-
-
-	tmp = cmd->convert_src;
-	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
-	if (!cmd->convert_src || tmp != cmd->convert_src)
-		err++;
-
-
-	tmp = cmd->scan_end_src;
-	cmd->scan_end_src &= TRIG_COUNT;
-	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
-		err++;
-
-
-	tmp = cmd->stop_src;
-	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-	if (!cmd->stop_src || tmp != cmd->stop_src)
-		err++;
+	int i;
+	int chan = CR_CHAN(insn->chanspec);
+	int range = CR_RANGE(insn->chanspec);
 
+	/* Configure the output range (table index matches the range values) */
+	RtdDacRange(dev, chan, range);
 
-	if (err)
-		return 1;
+	/* Writing a list of values to an AO channel is probably not
+	 * very useful, but that's how the interface is defined. */
+	for (i = 0; i < insn->n; ++i) {
+		int val = data[i] << 3;
+		int stat = 0;	/* initialize to avoid bogus warning */
+		int ii;
 
-	/* step 2: make sure trigger sources are unique
-	   and mutually compatible */
-	/* note that mutual compatibility is not an issue here */
-	if (cmd->scan_begin_src != TRIG_TIMER &&
-	    cmd->scan_begin_src != TRIG_EXT) {
-		err++;
-	}
-	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
-		err++;
+		/* VERIFY: comedi range and offset conversions */
 
-	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
-		err++;
+		if ((range > 1)	/* bipolar */
+		    && (data[i] < 2048)) {
+			/* offset and sign extend */
+			val = (((int)data[i]) - 2048) << 3;
+		} else {	/* unipolor */
+			val = data[i] << 3;
+		}
 
-	if (err)
-		return 2;
+		DPRINTK
+		    ("comedi: rtd520 DAC chan=%d range=%d writing %d as 0x%x\n",
+		     chan, range, data[i], val);
 
-	/* step 3: make sure arguments are trivially compatible */
+		/* a typical programming sequence */
+		RtdDacFifoPut(dev, chan, val);	/* put the value in */
+		RtdDacUpdate(dev, chan);	/* trigger the conversion */
 
-	if (cmd->start_arg != 0) {
-		cmd->start_arg = 0;
-		err++;
-	}
+		devpriv->aoValue[chan] = data[i];	/* save for read back */
 
-	if (cmd->scan_begin_src == TRIG_TIMER) {
-		/* Note: these are time periods, not actual rates */
-		if (1 == cmd->chanlist_len) {	/* no scanning */
-			if (cmd->scan_begin_arg < RTD_MAX_SPEED_1) {
-				cmd->scan_begin_arg = RTD_MAX_SPEED_1;
-				rtd_ns_to_timer(&cmd->scan_begin_arg,
-						TRIG_ROUND_UP);
-				err++;
-			}
-			if (cmd->scan_begin_arg > RTD_MIN_SPEED_1) {
-				cmd->scan_begin_arg = RTD_MIN_SPEED_1;
-				rtd_ns_to_timer(&cmd->scan_begin_arg,
-						TRIG_ROUND_DOWN);
-				err++;
-			}
-		} else {
-			if (cmd->scan_begin_arg < RTD_MAX_SPEED) {
-				cmd->scan_begin_arg = RTD_MAX_SPEED;
-				rtd_ns_to_timer(&cmd->scan_begin_arg,
-						TRIG_ROUND_UP);
-				err++;
-			}
-			if (cmd->scan_begin_arg > RTD_MIN_SPEED) {
-				cmd->scan_begin_arg = RTD_MIN_SPEED;
-				rtd_ns_to_timer(&cmd->scan_begin_arg,
-						TRIG_ROUND_DOWN);
-				err++;
-			}
-		}
-	} else {
-		/* external trigger */
-		/* should be level/edge, hi/lo specification here */
-		/* should specify multiple external triggers */
-		if (cmd->scan_begin_arg > 9) {
-			cmd->scan_begin_arg = 9;
-			err++;
-		}
-	}
-	if (cmd->convert_src == TRIG_TIMER) {
-		if (1 == cmd->chanlist_len) {	/* no scanning */
-			if (cmd->convert_arg < RTD_MAX_SPEED_1) {
-				cmd->convert_arg = RTD_MAX_SPEED_1;
-				rtd_ns_to_timer(&cmd->convert_arg,
-						TRIG_ROUND_UP);
-				err++;
-			}
-			if (cmd->convert_arg > RTD_MIN_SPEED_1) {
-				cmd->convert_arg = RTD_MIN_SPEED_1;
-				rtd_ns_to_timer(&cmd->convert_arg,
-						TRIG_ROUND_DOWN);
-				err++;
-			}
-		} else {
-			if (cmd->convert_arg < RTD_MAX_SPEED) {
-				cmd->convert_arg = RTD_MAX_SPEED;
-				rtd_ns_to_timer(&cmd->convert_arg,
-						TRIG_ROUND_UP);
-				err++;
-			}
-			if (cmd->convert_arg > RTD_MIN_SPEED) {
-				cmd->convert_arg = RTD_MIN_SPEED;
-				rtd_ns_to_timer(&cmd->convert_arg,
-						TRIG_ROUND_DOWN);
-				err++;
-			}
+		for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) {
+			stat = RtdFifoStatus(dev);
+			/* 1 -> not empty */
+			if (stat & ((0 == chan) ? FS_DAC1_NOT_EMPTY :
+				    FS_DAC2_NOT_EMPTY))
+				break;
+			WAIT_QUIETLY;
 		}
-	} else {
-		/* external trigger */
-		/* see above */
-		if (cmd->convert_arg > 9) {
-			cmd->convert_arg = 9;
-			err++;
+		if (ii >= RTD_DAC_TIMEOUT) {
+			DPRINTK
+			    ("rtd520: Error: DAC never finished! FifoStatus=0x%x\n",
+			     stat ^ 0x6666);
+			return -ETIMEDOUT;
 		}
 	}
 
-#if 0
-	if (cmd->scan_end_arg != cmd->chanlist_len) {
-		cmd->scan_end_arg = cmd->chanlist_len;
-		err++;
-	}
-#endif
-	if (cmd->stop_src == TRIG_COUNT) {
-		/* TODO check for rounding error due to counter wrap */
+	/* return the number of samples read/written */
+	return i;
+}
 
-	} else {
-		/* TRIG_NONE */
-		if (cmd->stop_arg != 0) {
-			cmd->stop_arg = 0;
-			err++;
-		}
-	}
+/* AO subdevices should have a read insn as well as a write insn.
+ * Usually this means copying a value stored in devpriv. */
+static int rtd_ao_rinsn(struct comedi_device *dev,
+			struct comedi_subdevice *s, struct comedi_insn *insn,
+			unsigned int *data)
+{
+	int i;
+	int chan = CR_CHAN(insn->chanspec);
 
-	if (err)
-		return 3;
+	for (i = 0; i < insn->n; i++)
+		data[i] = devpriv->aoValue[chan];
 
 
-	/* step 4: fix up any arguments */
+	return i;
+}
 
-	if (cmd->chanlist_len > RTD_MAX_CHANLIST) {
-		cmd->chanlist_len = RTD_MAX_CHANLIST;
-		err++;
-	}
-	if (cmd->scan_begin_src == TRIG_TIMER) {
-		tmp = cmd->scan_begin_arg;
-		rtd_ns_to_timer(&cmd->scan_begin_arg,
-				cmd->flags & TRIG_ROUND_MASK);
-		if (tmp != cmd->scan_begin_arg)
-			err++;
+/*
+   Write a masked set of bits and the read back the port.
+   We track what the bits should be (i.e. we don't read the port first).
 
-	}
-	if (cmd->convert_src == TRIG_TIMER) {
-		tmp = cmd->convert_arg;
-		rtd_ns_to_timer(&cmd->convert_arg,
-				cmd->flags & TRIG_ROUND_MASK);
-		if (tmp != cmd->convert_arg)
-			err++;
+   DIO devices are slightly special.  Although it is possible to
+ * implement the insn_read/insn_write interface, it is much more
+ * useful to applications if you implement the insn_bits interface.
+ * This allows packed reading/writing of the DIO channels.  The
+ * comedi core can convert between insn_bits and insn_read/write
+ */
+static int rtd_dio_insn_bits(struct comedi_device *dev,
+			     struct comedi_subdevice *s,
+			     struct comedi_insn *insn, unsigned int *data)
+{
+	/* The insn data is a mask in data[0] and the new data
+	 * in data[1], each channel cooresponding to a bit. */
+	if (data[0]) {
+		s->state &= ~data[0];
+		s->state |= data[0] & data[1];
 
-		if (cmd->scan_begin_src == TRIG_TIMER
-		    && (cmd->scan_begin_arg
-			< (cmd->convert_arg * cmd->scan_end_arg))) {
-			cmd->scan_begin_arg =
-			    cmd->convert_arg * cmd->scan_end_arg;
-			err++;
-		}
+		/* Write out the new digital output lines */
+		RtdDio0Write(dev, s->state);
 	}
+	/* on return, data[1] contains the value of the digital
+	 * input lines. */
+	data[1] = RtdDio0Read(dev);
 
-	if (err)
-		return 4;
+	/*DPRINTK("rtd520:port_0 wrote: 0x%x read: 0x%x\n", s->state, data[1]); */
 
-	return 0;
+	return insn->n;
 }
 
 /*
-  Execute a analog in command with many possible triggering options.
-  The data get stored in the async structure of the subdevice.
-  This is usually done by an interrupt handler.
-  Userland gets to the data using read calls.
+  Configure one bit on a IO port as Input or Output (hence the name :-).
 */
-static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
+static int rtd_dio_insn_config(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_insn *insn, unsigned int *data)
 {
-	struct comedi_cmd *cmd = &s->async->cmd;
-	int timer;
-
-	/* stop anything currently running */
-	RtdPacerStopSource(dev, 0);	/* stop on SOFTWARE stop */
-	RtdPacerStop(dev);	/* make sure PACER is stopped */
-	RtdAdcConversionSource(dev, 0);	/* software trigger only */
-	RtdInterruptMask(dev, 0);
-#ifdef USE_DMA
-	if (devpriv->flags & DMA0_ACTIVE) {	/* cancel anything running */
-		RtdPlxInterruptWrite(dev,	/* disable any more interrupts */
-				     RtdPlxInterruptRead(dev) & ~ICS_DMA0_E);
-		abort_dma(dev, 0);
-		devpriv->flags &= ~DMA0_ACTIVE;
-		if (RtdPlxInterruptRead(dev) & ICS_DMA0_A) {	/*clear pending int */
-			RtdDma0Control(dev, PLX_CLEAR_DMA_INTR_BIT);
-		}
-	}
-	RtdDma0Reset(dev);	/* reset onboard state */
-#endif /* USE_DMA */
-	RtdAdcClearFifo(dev);	/* clear any old data */
-	RtdInterruptOverrunClear(dev);
-	devpriv->intCount = 0;
-
-	if (!dev->irq) {	/* we need interrupts for this */
-		DPRINTK("rtd520: ERROR! No interrupt available!\n");
-		return -ENXIO;
-	}
-
-	/* start configuration */
-	/* load channel list and reset CGT */
-	rtd_load_channelgain_list(dev, cmd->chanlist_len, cmd->chanlist);
+	int chan = CR_CHAN(insn->chanspec);
 
-	/* setup the common case and override if needed */
-	if (cmd->chanlist_len > 1) {
-		/*DPRINTK ("rtd520: Multi channel setup\n"); */
-		RtdPacerStartSource(dev, 0);	/* software triggers pacer */
-		RtdBurstStartSource(dev, 1);	/* PACER triggers burst */
-		RtdAdcConversionSource(dev, 2);	/* BURST triggers ADC */
-	} else {		/* single channel */
-		/*DPRINTK ("rtd520: single channel setup\n"); */
-		RtdPacerStartSource(dev, 0);	/* software triggers pacer */
-		RtdAdcConversionSource(dev, 1);	/* PACER triggers ADC */
+	/* The input or output configuration of each digital line is
+	 * configured by a special insn_config instruction.  chanspec
+	 * contains the channel to be changed, and data[0] contains the
+	 * value COMEDI_INPUT or COMEDI_OUTPUT. */
+	switch (data[0]) {
+	case INSN_CONFIG_DIO_OUTPUT:
+		s->io_bits |= 1 << chan;	/* 1 means Out */
+		break;
+	case INSN_CONFIG_DIO_INPUT:
+		s->io_bits &= ~(1 << chan);
+		break;
+	case INSN_CONFIG_DIO_QUERY:
+		data[1] =
+		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
+		return insn->n;
+		break;
+	default:
+		return -EINVAL;
 	}
-	RtdAboutCounter(dev, devpriv->fifoLen / 2 - 1);	/* 1/2 FIFO */
 
-	if (TRIG_TIMER == cmd->scan_begin_src) {
-		/* scan_begin_arg is in nanoseconds */
-		/* find out how many samples to wait before transferring */
-		if (cmd->flags & TRIG_WAKE_EOS) {
-			/* this may generate un-sustainable interrupt rates */
-			/* the application is responsible for doing the right thing */
-			devpriv->transCount = cmd->chanlist_len;
-			devpriv->flags |= SEND_EOS;
-		} else {
-			/* arrange to transfer data periodically */
-			devpriv->transCount
-			    =
-			    (TRANS_TARGET_PERIOD * cmd->chanlist_len) /
-			    cmd->scan_begin_arg;
-			if (devpriv->transCount < cmd->chanlist_len) {
-				/* transfer after each scan (and avoid 0) */
-				devpriv->transCount = cmd->chanlist_len;
-			} else {	/* make a multiple of scan length */
-				devpriv->transCount =
-				    (devpriv->transCount +
-				     cmd->chanlist_len - 1)
-				    / cmd->chanlist_len;
-				devpriv->transCount *= cmd->chanlist_len;
-			}
-			devpriv->flags |= SEND_EOS;
-		}
-		if (devpriv->transCount >= (devpriv->fifoLen / 2)) {
-			/* out of counter range, use 1/2 fifo instead */
-			devpriv->transCount = 0;
-			devpriv->flags &= ~SEND_EOS;
-		} else {
-			/* interrupt for each transfer */
-			RtdAboutCounter(dev, devpriv->transCount - 1);
-		}
+	DPRINTK("rtd520: port_0_direction=0x%x (1 means out)\n", s->io_bits);
+	/* TODO support digital match interrupts and strobes */
+	RtdDioStatusWrite(dev, 0x01);	/* make Dio0Ctrl point to direction */
+	RtdDio0CtrlWrite(dev, s->io_bits);	/* set direction 1 means Out */
+	RtdDioStatusWrite(dev, 0);	/* make Dio0Ctrl clear interrupts */
 
-		DPRINTK
-		    ("rtd520: scanLen=%d transferCount=%d fifoLen=%d\n  scanTime(ns)=%d flags=0x%x\n",
-		     cmd->chanlist_len, devpriv->transCount, devpriv->fifoLen,
-		     cmd->scan_begin_arg, devpriv->flags);
-	} else {		/* unknown timing, just use 1/2 FIFO */
-		devpriv->transCount = 0;
-		devpriv->flags &= ~SEND_EOS;
-	}
-	RtdPacerClockSource(dev, 1);	/* use INTERNAL 8Mhz clock source */
-	RtdAboutStopEnable(dev, 1);	/* just interrupt, dont stop */
+	/* port1 can only be all input or all output */
 
-	/* BUG??? these look like enumerated values, but they are bit fields */
+	/* there are also 2 user input lines and 2 user output lines */
 
-	/* First, setup when to stop */
-	switch (cmd->stop_src) {
-	case TRIG_COUNT:	/* stop after N scans */
-		devpriv->aiCount = cmd->stop_arg * cmd->chanlist_len;
-		if ((devpriv->transCount > 0)
-		    && (devpriv->transCount > devpriv->aiCount)) {
-			devpriv->transCount = devpriv->aiCount;
-		}
-		break;
+	return 1;
+}
 
-	case TRIG_NONE:	/* stop when cancel is called */
-		devpriv->aiCount = -1;	/* read forever */
-		break;
+static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{				/* board name and options flags */
+	struct comedi_subdevice *s;
+	struct pci_dev *pcidev;
+	int ret;
+	resource_size_t physLas0;	/* configuration */
+	resource_size_t physLas1;	/* data area */
+	resource_size_t physLcfg;	/* PLX9080 */
+#ifdef USE_DMA
+	int index;
+#endif
 
-	default:
-		DPRINTK("rtd520: Warning! ignoring stop_src mode %d\n",
-			cmd->stop_src);
-	}
+	printk(KERN_INFO "comedi%d: rtd520 attaching.\n", dev->minor);
 
-	/* Scan timing */
-	switch (cmd->scan_begin_src) {
-	case TRIG_TIMER:	/* periodic scanning */
-		timer = rtd_ns_to_timer(&cmd->scan_begin_arg,
-					TRIG_ROUND_NEAREST);
-		/* set PACER clock */
-		/*DPRINTK ("rtd520: loading %d into pacer\n", timer); */
-		RtdPacerCounter(dev, timer);
+#if defined(CONFIG_COMEDI_DEBUG) && defined(USE_DMA)
+	/* You can set this a load time: modprobe comedi comedi_debug=1 */
+	if (0 == comedi_debug)	/* force DMA debug printks */
+		comedi_debug = 1;
+#endif
 
-		break;
+	/*
+	 * Allocate the private structure area.  alloc_private() is a
+	 * convenient macro defined in comedidev.h.
+	 */
+	if (alloc_private(dev, sizeof(struct rtdPrivate)) < 0)
+		return -ENOMEM;
 
-	case TRIG_EXT:
-		RtdPacerStartSource(dev, 1);	/* EXTERNALy trigger pacer */
-		break;
+	/*
+	 * Probe the device to determine what device in the series it is.
+	 */
+	for (pcidev = pci_get_device(PCI_VENDOR_ID_RTD, PCI_ANY_ID, NULL);
+	     pcidev != NULL;
+	     pcidev = pci_get_device(PCI_VENDOR_ID_RTD, PCI_ANY_ID, pcidev)) {
+		int i;
 
-	default:
-		DPRINTK("rtd520: Warning! ignoring scan_begin_src mode %d\n",
-			cmd->scan_begin_src);
+		if (it->options[0] || it->options[1]) {
+			if (pcidev->bus->number != it->options[0]
+			    || PCI_SLOT(pcidev->devfn) != it->options[1]) {
+				continue;
+			}
+		}
+		for (i = 0; i < ARRAY_SIZE(rtd520Boards); ++i) {
+			if (pcidev->device == rtd520Boards[i].device_id) {
+				dev->board_ptr = &rtd520Boards[i];
+				break;
+			}
+		}
+		if (dev->board_ptr)
+			break;	/* found one */
 	}
-
-	/* Sample timing within a scan */
-	switch (cmd->convert_src) {
-	case TRIG_TIMER:	/* periodic */
-		if (cmd->chanlist_len > 1) {	/* only needed for multi-channel */
-			timer = rtd_ns_to_timer(&cmd->convert_arg,
-						TRIG_ROUND_NEAREST);
-			/* setup BURST clock */
-			/*DPRINTK ("rtd520: loading %d into burst\n", timer); */
-			RtdBurstCounter(dev, timer);
+	if (!pcidev) {
+		if (it->options[0] && it->options[1]) {
+			printk(KERN_INFO "No RTD card at bus=%d slot=%d.\n",
+			       it->options[0], it->options[1]);
+		} else {
+			printk(KERN_INFO "No RTD card found.\n");
 		}
-
-		break;
-
-	case TRIG_EXT:		/* external */
-		RtdBurstStartSource(dev, 2);	/* EXTERNALy trigger burst */
-		break;
-
-	default:
-		DPRINTK("rtd520: Warning! ignoring convert_src mode %d\n",
-			cmd->convert_src);
+		return -EIO;
 	}
-	/* end configuration */
+	devpriv->pci_dev = pcidev;
+	dev->board_name = thisboard->name;
 
-	/* This doesn't seem to work.  There is no way to clear an interrupt
-	   that the priority controller has queued! */
-	RtdInterruptClearMask(dev, ~0);	/* clear any existing flags */
-	RtdInterruptClear(dev);
+	ret = comedi_pci_enable(pcidev, DRV_NAME);
+	if (ret < 0) {
+		printk(KERN_INFO "Failed to enable PCI device and request regions.\n");
+		return ret;
+	}
+	devpriv->got_regions = 1;
 
-	/* TODO: allow multiple interrupt sources */
-	if (devpriv->transCount > 0) {	/* transfer every N samples */
-		RtdInterruptMask(dev, IRQM_ADC_ABOUT_CNT);
-		DPRINTK("rtd520: Transferring every %d\n", devpriv->transCount);
-	} else {		/* 1/2 FIFO transfers */
-#ifdef USE_DMA
-		devpriv->flags |= DMA0_ACTIVE;
+	/*
+	 * Initialize base addresses
+	 */
+	/* Get the physical address from PCI config */
+	physLas0 = pci_resource_start(devpriv->pci_dev, LAS0_PCIINDEX);
+	physLas1 = pci_resource_start(devpriv->pci_dev, LAS1_PCIINDEX);
+	physLcfg = pci_resource_start(devpriv->pci_dev, LCFG_PCIINDEX);
+	/* Now have the kernel map this into memory */
+	/* ASSUME page aligned */
+	devpriv->las0 = ioremap_nocache(physLas0, LAS0_PCISIZE);
+	devpriv->las1 = ioremap_nocache(physLas1, LAS1_PCISIZE);
+	devpriv->lcfg = ioremap_nocache(physLcfg, LCFG_PCISIZE);
 
-		/* point to first transfer in ring */
-		devpriv->dma0Offset = 0;
-		RtdDma0Mode(dev, DMA_MODE_BITS);
-		RtdDma0Next(dev,	/* point to first block */
-			    devpriv->dma0Chain[DMA_CHAIN_COUNT - 1].next);
-		RtdDma0Source(dev, DMAS_ADFIFO_HALF_FULL);	/* set DMA trigger source */
+	if (!devpriv->las0 || !devpriv->las1 || !devpriv->lcfg)
+		return -ENOMEM;
 
-		RtdPlxInterruptWrite(dev,	/* enable interrupt */
-				     RtdPlxInterruptRead(dev) | ICS_DMA0_E);
-		/* Must be 2 steps.  See PLX app note about "Starting a DMA transfer" */
-		RtdDma0Control(dev, PLX_DMA_EN_BIT);	/* enable DMA (clear INTR?) */
-		RtdDma0Control(dev, PLX_DMA_EN_BIT | PLX_DMA_START_BIT);	/*start DMA */
-		DPRINTK("rtd520: Using DMA0 transfers. plxInt %x RtdInt %x\n",
-			RtdPlxInterruptRead(dev), devpriv->intMask);
-#else /* USE_DMA */
-		RtdInterruptMask(dev, IRQM_ADC_ABOUT_CNT);
-		DPRINTK("rtd520: Transferring every 1/2 FIFO\n");
-#endif /* USE_DMA */
-	}
 
-	/* BUG: start_src is ASSUMED to be TRIG_NOW */
-	/* BUG? it seems like things are running before the "start" */
-	RtdPacerStart(dev);	/* Start PACER */
-	return 0;
-}
+	DPRINTK("%s: LAS0=%llx, LAS1=%llx, CFG=%llx.\n", dev->board_name,
+		(unsigned long long)physLas0, (unsigned long long)physLas1,
+		(unsigned long long)physLcfg);
+	{			/* The RTD driver does this */
+		unsigned char pci_latency;
+		u16 revision;
+		/*uint32_t epld_version; */
 
-/*
-  Stop a running data acquisition.
-*/
-static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
-{
-	u16 status;
+		pci_read_config_word(devpriv->pci_dev, PCI_REVISION_ID,
+				     &revision);
+		DPRINTK("%s: PCI revision %d.\n", dev->board_name, revision);
 
-	RtdPacerStopSource(dev, 0);	/* stop on SOFTWARE stop */
-	RtdPacerStop(dev);	/* Stop PACER */
-	RtdAdcConversionSource(dev, 0);	/* software trigger only */
-	RtdInterruptMask(dev, 0);
-	devpriv->aiCount = 0;	/* stop and don't transfer any more */
-#ifdef USE_DMA
-	if (devpriv->flags & DMA0_ACTIVE) {
-		RtdPlxInterruptWrite(dev,	/* disable any more interrupts */
-				     RtdPlxInterruptRead(dev) & ~ICS_DMA0_E);
-		abort_dma(dev, 0);
-		devpriv->flags &= ~DMA0_ACTIVE;
+		pci_read_config_byte(devpriv->pci_dev,
+				     PCI_LATENCY_TIMER, &pci_latency);
+		if (pci_latency < 32) {
+			printk(KERN_INFO "%s: PCI latency changed from %d to %d\n",
+			       dev->board_name, pci_latency, 32);
+			pci_write_config_byte(devpriv->pci_dev,
+					      PCI_LATENCY_TIMER, 32);
+		} else {
+			DPRINTK("rtd520: PCI latency = %d\n", pci_latency);
+		}
+
+		/*
+		 * Undocumented EPLD version (doesn't match RTD driver results)
+		 */
+		/*DPRINTK ("rtd520: Reading epld from %p\n",
+		   devpriv->las0+0);
+		   epld_version = readl (devpriv->las0+0);
+		   if ((epld_version & 0xF0) >> 4 == 0x0F) {
+		   DPRINTK("rtd520: pre-v8 EPLD. (%x)\n", epld_version);
+		   } else {
+		   DPRINTK("rtd520: EPLD version %x.\n", epld_version >> 4);
+		   } */
 	}
-#endif /* USE_DMA */
-	status = RtdInterruptStatus(dev);
-	DPRINTK
-	    ("rtd520: Acquisition canceled. %ld ints, intStat=%x, overStat=%x\n",
-	     devpriv->intCount, status,
-	     0xffff & RtdInterruptOverrunStatus(dev));
-	return 0;
-}
 
-/*
-  Given a desired period and the clock period (both in ns),
-  return the proper counter value (divider-1).
-  Sets the original period to be the true value.
-  Note: you have to check if the value is larger than the counter range!
-*/
-static int rtd_ns_to_timer_base(unsigned int *nanosec,	/* desired period (in ns) */
-				int round_mode, int base)
-{				/* clock period (in ns) */
-	int divider;
+	/* Show board configuration */
+	printk(KERN_INFO "%s:", dev->board_name);
 
-	switch (round_mode) {
-	case TRIG_ROUND_NEAREST:
-	default:
-		divider = (*nanosec + base / 2) / base;
-		break;
-	case TRIG_ROUND_DOWN:
-		divider = (*nanosec) / base;
-		break;
-	case TRIG_ROUND_UP:
-		divider = (*nanosec + base - 1) / base;
-		break;
-	}
-	if (divider < 2)
-		divider = 2;	/* min is divide by 2 */
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
+		return ret;
 
-	/* Note: we don't check for max, because different timers
-	   have different ranges */
+	s = dev->subdevices + 0;
+	dev->read_subdev = s;
+	/* analog input subdevice */
+	s->type = COMEDI_SUBD_AI;
+	s->subdev_flags =
+	    SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ;
+	s->n_chan = thisboard->aiChans;
+	s->maxdata = (1 << thisboard->aiBits) - 1;
+	if (thisboard->aiMaxGain <= 32)
+		s->range_table = &rtd_ai_7520_range;
+	else
+		s->range_table = &rtd_ai_4520_range;
 
-	*nanosec = base * divider;
-	return divider - 1;	/* countdown is divisor+1 */
-}
+	s->len_chanlist = RTD_MAX_CHANLIST;	/* devpriv->fifoLen */
+	s->insn_read = rtd_ai_rinsn;
+	s->do_cmd = rtd_ai_cmd;
+	s->do_cmdtest = rtd_ai_cmdtest;
+	s->cancel = rtd_ai_cancel;
+	/* s->poll = rtd_ai_poll; *//* not ready yet */
 
-/*
-  Given a desired period (in ns),
-  return the proper counter value (divider-1) for the internal clock.
-  Sets the original period to be the true value.
-*/
-static int rtd_ns_to_timer(unsigned int *ns, int round_mode)
-{
-	return rtd_ns_to_timer_base(ns, round_mode, RTD_CLOCK_BASE);
-}
+	s = dev->subdevices + 1;
+	/* analog output subdevice */
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_WRITABLE;
+	s->n_chan = 2;
+	s->maxdata = (1 << thisboard->aiBits) - 1;
+	s->range_table = &rtd_ao_range;
+	s->insn_write = rtd_ao_winsn;
+	s->insn_read = rtd_ao_rinsn;
 
-/*
-  Output one (or more) analog values to a single port as fast as possible.
-*/
-static int rtd_ao_winsn(struct comedi_device *dev,
-			struct comedi_subdevice *s, struct comedi_insn *insn,
-			unsigned int *data)
-{
-	int i;
-	int chan = CR_CHAN(insn->chanspec);
-	int range = CR_RANGE(insn->chanspec);
+	s = dev->subdevices + 2;
+	/* digital i/o subdevice */
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	/* we only support port 0 right now.  Ignoring port 1 and user IO */
+	s->n_chan = 8;
+	s->maxdata = 1;
+	s->range_table = &range_digital;
+	s->insn_bits = rtd_dio_insn_bits;
+	s->insn_config = rtd_dio_insn_config;
 
-	/* Configure the output range (table index matches the range values) */
-	RtdDacRange(dev, chan, range);
+	/* timer/counter subdevices (not currently supported) */
+	s = dev->subdevices + 3;
+	s->type = COMEDI_SUBD_COUNTER;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 3;
+	s->maxdata = 0xffff;
 
-	/* Writing a list of values to an AO channel is probably not
-	 * very useful, but that's how the interface is defined. */
-	for (i = 0; i < insn->n; ++i) {
-		int val = data[i] << 3;
-		int stat = 0;	/* initialize to avoid bogus warning */
-		int ii;
+	/* initialize board, per RTD spec */
+	/* also, initialize shadow registers */
+	RtdResetBoard(dev);
+	udelay(100);		/* needed? */
+	RtdPlxInterruptWrite(dev, 0);
+	RtdInterruptMask(dev, 0);	/* and sets shadow */
+	RtdInterruptClearMask(dev, ~0);	/* and sets shadow */
+	RtdInterruptClear(dev);	/* clears bits set by mask */
+	RtdInterruptOverrunClear(dev);
+	RtdClearCGT(dev);
+	RtdAdcClearFifo(dev);
+	RtdDacClearFifo(dev, 0);
+	RtdDacClearFifo(dev, 1);
+	/* clear digital IO fifo */
+	RtdDioStatusWrite(dev, 0);	/* safe state, set shadow */
+	RtdUtcCtrlPut(dev, 0, 0x30);	/* safe state, set shadow */
+	RtdUtcCtrlPut(dev, 1, 0x30);	/* safe state, set shadow */
+	RtdUtcCtrlPut(dev, 2, 0x30);	/* safe state, set shadow */
+	RtdUtcCtrlPut(dev, 3, 0);	/* safe state, set shadow */
+	/* TODO: set user out source ??? */
 
-		/* VERIFY: comedi range and offset conversions */
+	/* check if our interrupt is available and get it */
+	ret = request_irq(devpriv->pci_dev->irq, rtd_interrupt,
+			  IRQF_SHARED, DRV_NAME, dev);
 
-		if ((range > 1)	/* bipolar */
-		    && (data[i] < 2048)) {
-			/* offset and sign extend */
-			val = (((int)data[i]) - 2048) << 3;
-		} else {	/* unipolor */
-			val = data[i] << 3;
-		}
+	if (ret < 0) {
+		printk("Could not get interrupt! (%u)\n",
+		       devpriv->pci_dev->irq);
+		return ret;
+	}
+	dev->irq = devpriv->pci_dev->irq;
+	printk(KERN_INFO "( irq=%u )", dev->irq);
 
-		DPRINTK
-		    ("comedi: rtd520 DAC chan=%d range=%d writing %d as 0x%x\n",
-		     chan, range, data[i], val);
+	ret = rtd520_probe_fifo_depth(dev);
+	if (ret < 0)
+		return ret;
 
-		/* a typical programming sequence */
-		RtdDacFifoPut(dev, chan, val);	/* put the value in */
-		RtdDacUpdate(dev, chan);	/* trigger the conversion */
+	devpriv->fifoLen = ret;
+	printk("( fifoLen=%d )", devpriv->fifoLen);
 
-		devpriv->aoValue[chan] = data[i];	/* save for read back */
+#ifdef USE_DMA
+	if (dev->irq > 0) {
+		printk("( DMA buff=%d )\n", DMA_CHAIN_COUNT);
+		/*
+		 * The PLX9080 has 2 DMA controllers, but there could be
+		 * 4 sources: ADC, digital, DAC1, and DAC2.  Since only the
+		 * ADC supports cmd mode right now, this isn't an issue (yet)
+		 */
+		devpriv->dma0Offset = 0;
 
-		for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) {
-			stat = RtdFifoStatus(dev);
-			/* 1 -> not empty */
-			if (stat & ((0 == chan) ? FS_DAC1_NOT_EMPTY :
-				    FS_DAC2_NOT_EMPTY))
-				break;
-			WAIT_QUIETLY;
+		for (index = 0; index < DMA_CHAIN_COUNT; index++) {
+			devpriv->dma0Buff[index] =
+			    pci_alloc_consistent(devpriv->pci_dev,
+						 sizeof(u16) *
+						 devpriv->fifoLen / 2,
+						 &devpriv->
+						 dma0BuffPhysAddr[index]);
+			if (devpriv->dma0Buff[index] == NULL) {
+				ret = -ENOMEM;
+				goto rtd_attach_die_error;
+			}
+			/*DPRINTK ("buff[%d] @ %p virtual, %x PCI\n",
+			   index,
+			   devpriv->dma0Buff[index],
+			   devpriv->dma0BuffPhysAddr[index]); */
 		}
-		if (ii >= RTD_DAC_TIMEOUT) {
-			DPRINTK
-			    ("rtd520: Error: DAC never finished! FifoStatus=0x%x\n",
-			     stat ^ 0x6666);
-			return -ETIMEDOUT;
+
+		/*
+		 * setup DMA descriptor ring (use cpu_to_le32 for byte
+		 * ordering?)
+		 */
+		devpriv->dma0Chain =
+		    pci_alloc_consistent(devpriv->pci_dev,
+					 sizeof(struct plx_dma_desc) *
+					 DMA_CHAIN_COUNT,
+					 &devpriv->dma0ChainPhysAddr);
+		for (index = 0; index < DMA_CHAIN_COUNT; index++) {
+			devpriv->dma0Chain[index].pci_start_addr =
+			    devpriv->dma0BuffPhysAddr[index];
+			devpriv->dma0Chain[index].local_start_addr =
+			    DMALADDR_ADC;
+			devpriv->dma0Chain[index].transfer_size =
+			    sizeof(u16) * devpriv->fifoLen / 2;
+			devpriv->dma0Chain[index].next =
+			    (devpriv->dma0ChainPhysAddr + ((index +
+							    1) %
+							   (DMA_CHAIN_COUNT))
+			     * sizeof(devpriv->dma0Chain[0]))
+			    | DMA_TRANSFER_BITS;
+			/*DPRINTK ("ring[%d] @%lx PCI: %x, local: %x, N: 0x%x, next: %x\n",
+			   index,
+			   ((long)devpriv->dma0ChainPhysAddr
+			   + (index * sizeof(devpriv->dma0Chain[0]))),
+			   devpriv->dma0Chain[index].pci_start_addr,
+			   devpriv->dma0Chain[index].local_start_addr,
+			   devpriv->dma0Chain[index].transfer_size,
+			   devpriv->dma0Chain[index].next); */
 		}
-	}
 
-	/* return the number of samples read/written */
-	return i;
-}
+		if (devpriv->dma0Chain == NULL) {
+			ret = -ENOMEM;
+			goto rtd_attach_die_error;
+		}
 
-/* AO subdevices should have a read insn as well as a write insn.
- * Usually this means copying a value stored in devpriv. */
-static int rtd_ao_rinsn(struct comedi_device *dev,
-			struct comedi_subdevice *s, struct comedi_insn *insn,
-			unsigned int *data)
-{
-	int i;
-	int chan = CR_CHAN(insn->chanspec);
+		RtdDma0Mode(dev, DMA_MODE_BITS);
+		/* set DMA trigger source */
+		RtdDma0Source(dev, DMAS_ADFIFO_HALF_FULL);
+	} else {
+		printk(KERN_INFO "( no IRQ->no DMA )");
+	}
+#endif /* USE_DMA */
 
-	for (i = 0; i < insn->n; i++)
-		data[i] = devpriv->aoValue[chan];
+	if (dev->irq) {		/* enable plx9080 interrupts */
+		RtdPlxInterruptWrite(dev, ICS_PIE | ICS_PLIE);
+	}
 
+	printk("\ncomedi%d: rtd520 driver attached.\n", dev->minor);
 
-	return i;
-}
+	return 1;
 
-/*
-   Write a masked set of bits and the read back the port.
-   We track what the bits should be (i.e. we don't read the port first).
+#if 0
+	/* hit an error, clean up memory and return ret */
+/* rtd_attach_die_error: */
+#ifdef USE_DMA
+	for (index = 0; index < DMA_CHAIN_COUNT; index++) {
+		if (NULL != devpriv->dma0Buff[index]) {	/* free buffer memory */
+			pci_free_consistent(devpriv->pci_dev,
+					    sizeof(u16) * devpriv->fifoLen / 2,
+					    devpriv->dma0Buff[index],
+					    devpriv->dma0BuffPhysAddr[index]);
+			devpriv->dma0Buff[index] = NULL;
+		}
+	}
+	if (NULL != devpriv->dma0Chain) {
+		pci_free_consistent(devpriv->pci_dev,
+				    sizeof(struct plx_dma_desc)
+				    * DMA_CHAIN_COUNT,
+				    devpriv->dma0Chain,
+				    devpriv->dma0ChainPhysAddr);
+		devpriv->dma0Chain = NULL;
+	}
+#endif /* USE_DMA */
+	/* subdevices and priv are freed by the core */
+	if (dev->irq) {
+		/* disable interrupt controller */
+		RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev)
+				     & ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E));
+		free_irq(dev->irq, dev);
+	}
 
-   DIO devices are slightly special.  Although it is possible to
- * implement the insn_read/insn_write interface, it is much more
- * useful to applications if you implement the insn_bits interface.
- * This allows packed reading/writing of the DIO channels.  The
- * comedi core can convert between insn_bits and insn_read/write
- */
-static int rtd_dio_insn_bits(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_insn *insn, unsigned int *data)
-{
-	if (insn->n != 2)
-		return -EINVAL;
+	/* release all regions that were allocated */
+	if (devpriv->las0)
+		iounmap(devpriv->las0);
 
-	/* The insn data is a mask in data[0] and the new data
-	 * in data[1], each channel cooresponding to a bit. */
-	if (data[0]) {
-		s->state &= ~data[0];
-		s->state |= data[0] & data[1];
+	if (devpriv->las1)
+		iounmap(devpriv->las1);
 
-		/* Write out the new digital output lines */
-		RtdDio0Write(dev, s->state);
-	}
-	/* on return, data[1] contains the value of the digital
-	 * input lines. */
-	data[1] = RtdDio0Read(dev);
+	if (devpriv->lcfg)
+		iounmap(devpriv->lcfg);
 
-	/*DPRINTK("rtd520:port_0 wrote: 0x%x read: 0x%x\n", s->state, data[1]); */
+	if (devpriv->pci_dev)
+		pci_dev_put(devpriv->pci_dev);
 
-	return 2;
+	return ret;
+#endif
 }
 
-/*
-  Configure one bit on a IO port as Input or Output (hence the name :-).
-*/
-static int rtd_dio_insn_config(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
+static void rtd_detach(struct comedi_device *dev)
 {
-	int chan = CR_CHAN(insn->chanspec);
+#ifdef USE_DMA
+	int index;
+#endif
 
-	/* The input or output configuration of each digital line is
-	 * configured by a special insn_config instruction.  chanspec
-	 * contains the channel to be changed, and data[0] contains the
-	 * value COMEDI_INPUT or COMEDI_OUTPUT. */
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= 1 << chan;	/* 1 means Out */
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~(1 << chan);
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
+	if (devpriv) {
+		/* Shut down any board ops by resetting it */
+#ifdef USE_DMA
+		if (devpriv->lcfg) {
+			RtdDma0Control(dev, 0);	/* disable DMA */
+			RtdDma1Control(dev, 0);	/* disable DMA */
+			RtdPlxInterruptWrite(dev, ICS_PIE | ICS_PLIE);
+		}
+#endif /* USE_DMA */
+		if (devpriv->las0) {
+			RtdResetBoard(dev);
+			RtdInterruptMask(dev, 0);
+			RtdInterruptClearMask(dev, ~0);
+			RtdInterruptClear(dev);	/* clears bits set by mask */
+		}
+#ifdef USE_DMA
+		/* release DMA */
+		for (index = 0; index < DMA_CHAIN_COUNT; index++) {
+			if (NULL != devpriv->dma0Buff[index]) {
+				pci_free_consistent(devpriv->pci_dev,
+						    sizeof(u16) *
+						    devpriv->fifoLen / 2,
+						    devpriv->dma0Buff[index],
+						    devpriv->
+						    dma0BuffPhysAddr[index]);
+				devpriv->dma0Buff[index] = NULL;
+			}
+		}
+		if (NULL != devpriv->dma0Chain) {
+			pci_free_consistent(devpriv->pci_dev,
+					    sizeof(struct plx_dma_desc) *
+					    DMA_CHAIN_COUNT, devpriv->dma0Chain,
+					    devpriv->dma0ChainPhysAddr);
+			devpriv->dma0Chain = NULL;
+		}
+#endif /* USE_DMA */
+		if (dev->irq) {
+			RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev)
+					     & ~(ICS_PLIE | ICS_DMA0_E |
+						 ICS_DMA1_E));
+			free_irq(dev->irq, dev);
+		}
+		if (devpriv->las0)
+			iounmap(devpriv->las0);
+		if (devpriv->las1)
+			iounmap(devpriv->las1);
+		if (devpriv->lcfg)
+			iounmap(devpriv->lcfg);
+		if (devpriv->pci_dev) {
+			if (devpriv->got_regions)
+				comedi_pci_disable(devpriv->pci_dev);
+			pci_dev_put(devpriv->pci_dev);
+		}
 	}
-
-	DPRINTK("rtd520: port_0_direction=0x%x (1 means out)\n", s->io_bits);
-	/* TODO support digital match interrupts and strobes */
-	RtdDioStatusWrite(dev, 0x01);	/* make Dio0Ctrl point to direction */
-	RtdDio0CtrlWrite(dev, s->io_bits);	/* set direction 1 means Out */
-	RtdDioStatusWrite(dev, 0);	/* make Dio0Ctrl clear interrupts */
-
-	/* port1 can only be all input or all output */
-
-	/* there are also 2 user input lines and 2 user output lines */
-
-	return 1;
 }
 
 static struct comedi_driver rtd520_driver = {
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index f0eb52a..f7fa940 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -138,8 +138,6 @@ struct rti800_board {
 	int has_ao;
 };
 
-#define this_board ((const struct rti800_board *)dev->board_ptr)
-
 static irqreturn_t rti800_interrupt(int irq, void *dev);
 
 struct rti800_private {
@@ -265,19 +263,14 @@ static int rti800_di_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
 	data[1] = inb(dev->iobase + RTI800_DI);
-	return 2;
+	return insn->n;
 }
 
 static int rti800_do_insn_bits(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
 			       struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	if (data[0]) {
 		s->state &= ~data[0];
 		s->state |= data[0] & data[1];
@@ -287,7 +280,7 @@ static int rti800_do_insn_bits(struct comedi_device *dev,
 
 	data[1] = s->state;
 
-	return 2;
+	return insn->n;
 }
 
 /*
@@ -309,6 +302,7 @@ static int rti800_do_insn_bits(struct comedi_device *dev,
 
 static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct rti800_board *board = comedi_board(dev);
 	unsigned int irq;
 	unsigned long iobase;
 	int ret;
@@ -347,10 +341,10 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		printk(KERN_INFO "( no irq )\n");
 	}
 
-	dev->board_name = this_board->name;
+	dev->board_name = board->name;
 
-	ret = alloc_subdevices(dev, 4);
-	if (ret < 0)
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
 		return ret;
 
 	ret = alloc_private(dev, sizeof(struct rti800_private));
@@ -386,7 +380,7 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	}
 
 	s++;
-	if (this_board->has_ao) {
+	if (board->has_ao) {
 		/* ao subdevice (only on rti815) */
 		s->type = COMEDI_SUBD_AO;
 		s->subdev_flags = SDF_WRITABLE;
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index 09da5c2..fc16508 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -92,6 +92,7 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	struct comedi_subdevice *s;
 	int i;
 	unsigned long iobase;
+	int ret;
 
 	iobase = it->options[0];
 	printk(KERN_INFO "comedi%d: rti802: 0x%04lx ", dev->minor, iobase);
@@ -103,10 +104,12 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	dev->board_name = "rti802";
 
-	if (alloc_subdevices(dev, 1) < 0
-	    || alloc_private(dev, sizeof(struct rti802_private))) {
+	if (alloc_private(dev, sizeof(struct rti802_private)))
 		return -ENOMEM;
-	}
+
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices;
 	/* ao subdevice */
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index 7a56434..358380f 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -200,11 +200,6 @@ static const struct s526_board s526_boards[] = {
 #define ADDR_REG(reg) (dev->iobase + (reg))
 #define ADDR_CHAN_REG(reg, chan) (dev->iobase + (reg) + (chan) * 8)
 
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct s526_board *)dev->board_ptr)
-
 /* this structure is for data unique to this hardware driver.  If
    several hardware drivers keep similar information in this structure,
    feel free to suggest moving the variable to the struct comedi_device
@@ -683,9 +678,6 @@ static int s526_dio_insn_bits(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	/* The insn data is a mask in data[0] and the new data
 	 * in data[1], each channel cooresponding to a bit. */
 	if (data[0]) {
@@ -702,7 +694,7 @@ static int s526_dio_insn_bits(struct comedi_device *dev,
 	 * it was a purely digital output subdevice */
 	/* data[1]=s->state & 0xFF; */
 
-	return 2;
+	return insn->n;
 }
 
 static int s526_dio_insn_config(struct comedi_device *dev,
@@ -744,9 +736,11 @@ static int s526_dio_insn_config(struct comedi_device *dev,
 
 static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct s526_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
 	int iobase;
 	int i, n;
+	int ret;
 /* short value; */
 /* int subdev_channel = 0; */
 	union cmReg cmReg;
@@ -754,7 +748,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	printk(KERN_INFO "comedi%d: s526: ", dev->minor);
 
 	iobase = it->options[0];
-	if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
+	if (!iobase || !request_region(iobase, S526_IOSIZE, board->name)) {
 		comedi_error(dev, "I/O port conflict");
 		return -EIO;
 	}
@@ -769,13 +763,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	}
 	***/
 
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-	dev->board_ptr = &s526_boards[0];
-
-	dev->board_name = thisboard->name;
+	dev->board_name = board->name;
 
 /*
  * Allocate the private structure area.  alloc_private() is a
@@ -784,20 +772,16 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	if (alloc_private(dev, sizeof(struct s526_private)) < 0)
 		return -ENOMEM;
 
-/*
- * Allocate the subdevice structures.  alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
-	dev->n_subdevices = 4;
-	if (alloc_subdevices(dev, dev->n_subdevices) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
 	s->type = COMEDI_SUBD_COUNTER;
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
 	/* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
-	s->n_chan = thisboard->gpct_chans;
+	s->n_chan = board->gpct_chans;
 	s->maxdata = 0x00ffffff;	/* 24 bit counter */
 	s->insn_read = s526_gpct_rinsn;
 	s->insn_config = s526_gpct_insn_config;
@@ -838,7 +822,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
 	s = dev->subdevices + 3;
 	/* digital i/o subdevice */
-	if (thisboard->have_dio) {
+	if (board->have_dio) {
 		s->type = COMEDI_SUBD_DIO;
 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 		s->n_chan = 8;
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 7beb8f6..bef9649 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -74,8 +74,6 @@ INSN_CONFIG instructions:
 
 #include "../comedidev.h"
 
-#include "comedi_pci.h"
-
 #include "comedi_fc.h"
 #include "s626.h"
 
@@ -120,7 +118,7 @@ static const struct s626_board s626_boards[] = {
 
 struct s626_private {
 	struct pci_dev *pdev;
-	void *base_addr;
+	void __iomem *base_addr;
 	int got_regions;
 	short allocatedBuf;
 	uint8_t ai_cmd_running;	/*  ai_cmd is running */
@@ -209,71 +207,6 @@ static struct dio_private *dio_private_word[]={
 #define devpriv ((struct s626_private *)dev->private)
 #define diopriv ((struct dio_private *)s->private)
 
-/* ioctl routines */
-static int s626_ai_insn_config(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-/* static int s626_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */
-static int s626_ai_insn_read(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_insn *insn, unsigned int *data);
-static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int s626_ai_cmdtest(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_cmd *cmd);
-static int s626_ai_cancel(struct comedi_device *dev,
-			  struct comedi_subdevice *s);
-static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			 struct comedi_insn *insn, unsigned int *data);
-static int s626_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			 struct comedi_insn *insn, unsigned int *data);
-static int s626_dio_insn_bits(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn, unsigned int *data);
-static int s626_dio_insn_config(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-static int s626_dio_set_irq(struct comedi_device *dev, unsigned int chan);
-static int s626_dio_reset_irq(struct comedi_device *dev, unsigned int gruop,
-			      unsigned int mask);
-static int s626_dio_clear_irq(struct comedi_device *dev);
-static int s626_enc_insn_config(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data);
-static int s626_enc_insn_read(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn, unsigned int *data);
-static int s626_enc_insn_write(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-static int s626_ns_to_timer(int *nanosec, int round_mode);
-static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd);
-static int s626_ai_inttrig(struct comedi_device *dev,
-			   struct comedi_subdevice *s, unsigned int trignum);
-static irqreturn_t s626_irq_handler(int irq, void *d);
-static unsigned int s626_ai_reg_to_uint(int data);
-/* static unsigned int s626_uint_to_reg(struct comedi_subdevice *s, int data); */
-
-/* end ioctl routines */
-
-/* internal routines */
-static void s626_dio_init(struct comedi_device *dev);
-static void ResetADC(struct comedi_device *dev, uint8_t * ppl);
-static void LoadTrimDACs(struct comedi_device *dev);
-static void WriteTrimDAC(struct comedi_device *dev, uint8_t LogicalChan,
-			 uint8_t DacData);
-static uint8_t I2Cread(struct comedi_device *dev, uint8_t addr);
-static uint32_t I2Chandshake(struct comedi_device *dev, uint32_t val);
-static void SetDAC(struct comedi_device *dev, uint16_t chan, short dacdata);
-static void SendDAC(struct comedi_device *dev, uint32_t val);
-static void WriteMISC2(struct comedi_device *dev, uint16_t NewImage);
-static void DEBItransfer(struct comedi_device *dev);
-static uint16_t DEBIread(struct comedi_device *dev, uint16_t addr);
-static void DEBIwrite(struct comedi_device *dev, uint16_t addr, uint16_t wdata);
-static void DEBIreplace(struct comedi_device *dev, uint16_t addr, uint16_t mask,
-			uint16_t wdata);
-static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma,
-		      size_t bsize);
-
 /*  COUNTER OBJECT ------------------------------------------------ */
 struct enc_private {
 	/*  Pointers to functions that differ for A and B counters: */
@@ -297,56 +230,6 @@ struct enc_private {
 
 #define encpriv ((struct enc_private *)(dev->subdevices+5)->private)
 
-/* counters routines */
-static void s626_timer_load(struct comedi_device *dev, struct enc_private *k,
-			    int tick);
-static uint32_t ReadLatch(struct comedi_device *dev, struct enc_private *k);
-static void ResetCapFlags_A(struct comedi_device *dev, struct enc_private *k);
-static void ResetCapFlags_B(struct comedi_device *dev, struct enc_private *k);
-static uint16_t GetMode_A(struct comedi_device *dev, struct enc_private *k);
-static uint16_t GetMode_B(struct comedi_device *dev, struct enc_private *k);
-static void SetMode_A(struct comedi_device *dev, struct enc_private *k,
-		      uint16_t Setup, uint16_t DisableIntSrc);
-static void SetMode_B(struct comedi_device *dev, struct enc_private *k,
-		      uint16_t Setup, uint16_t DisableIntSrc);
-static void SetEnable_A(struct comedi_device *dev, struct enc_private *k,
-			uint16_t enab);
-static void SetEnable_B(struct comedi_device *dev, struct enc_private *k,
-			uint16_t enab);
-static uint16_t GetEnable_A(struct comedi_device *dev, struct enc_private *k);
-static uint16_t GetEnable_B(struct comedi_device *dev, struct enc_private *k);
-static void SetLatchSource(struct comedi_device *dev, struct enc_private *k,
-			   uint16_t value);
-/* static uint16_t GetLatchSource(struct comedi_device *dev, struct enc_private *k ); */
-static void SetLoadTrig_A(struct comedi_device *dev, struct enc_private *k,
-			  uint16_t Trig);
-static void SetLoadTrig_B(struct comedi_device *dev, struct enc_private *k,
-			  uint16_t Trig);
-static uint16_t GetLoadTrig_A(struct comedi_device *dev, struct enc_private *k);
-static uint16_t GetLoadTrig_B(struct comedi_device *dev, struct enc_private *k);
-static void SetIntSrc_B(struct comedi_device *dev, struct enc_private *k,
-			uint16_t IntSource);
-static void SetIntSrc_A(struct comedi_device *dev, struct enc_private *k,
-			uint16_t IntSource);
-static uint16_t GetIntSrc_A(struct comedi_device *dev, struct enc_private *k);
-static uint16_t GetIntSrc_B(struct comedi_device *dev, struct enc_private *k);
-/* static void SetClkMult(struct comedi_device *dev, struct enc_private *k, uint16_t value ) ; */
-/* static uint16_t GetClkMult(struct comedi_device *dev, struct enc_private *k ) ; */
-/* static void SetIndexPol(struct comedi_device *dev, struct enc_private *k, uint16_t value ); */
-/* static uint16_t GetClkPol(struct comedi_device *dev, struct enc_private *k ) ; */
-/* static void SetIndexSrc( struct comedi_device *dev,struct enc_private *k, uint16_t value );  */
-/* static uint16_t GetClkSrc( struct comedi_device *dev,struct enc_private *k );  */
-/* static void SetIndexSrc( struct comedi_device *dev,struct enc_private *k, uint16_t value );  */
-/* static uint16_t GetIndexSrc( struct comedi_device *dev,struct enc_private *k );  */
-static void PulseIndex_A(struct comedi_device *dev, struct enc_private *k);
-static void PulseIndex_B(struct comedi_device *dev, struct enc_private *k);
-static void Preload(struct comedi_device *dev, struct enc_private *k,
-		    uint32_t value);
-static void CountersInit(struct comedi_device *dev);
-/* end internal routines */
-
-/*  Counter objects constructor. */
-
 /*  Counter overflow/index event flag masks for RDMISC2. */
 #define INDXMASK(C)		(1 << (((C) > 2) ? ((C) * 2 - 1) : ((C) * 2 +  4)))
 #define OVERMASK(C)		(1 << (((C) > 2) ? ((C) * 2 + 5) : ((C) * 2 + 10)))
@@ -355,106 +238,6 @@ static void CountersInit(struct comedi_device *dev);
 /*  Translation table to map IntSrc into equivalent RDMISC2 event flag  bits. */
 /* static const uint16_t EventBits[][4] = { EVBITS(0), EVBITS(1), EVBITS(2), EVBITS(3), EVBITS(4), EVBITS(5) }; */
 
-/* struct enc_private; */
-static struct enc_private enc_private_data[] = {
-	{
-	 .GetEnable = GetEnable_A,
-	 .GetIntSrc = GetIntSrc_A,
-	 .GetLoadTrig = GetLoadTrig_A,
-	 .GetMode = GetMode_A,
-	 .PulseIndex = PulseIndex_A,
-	 .SetEnable = SetEnable_A,
-	 .SetIntSrc = SetIntSrc_A,
-	 .SetLoadTrig = SetLoadTrig_A,
-	 .SetMode = SetMode_A,
-	 .ResetCapFlags = ResetCapFlags_A,
-	 .MyCRA = LP_CR0A,
-	 .MyCRB = LP_CR0B,
-	 .MyLatchLsw = LP_CNTR0ALSW,
-	 .MyEventBits = EVBITS(0),
-	 },
-	{
-	 .GetEnable = GetEnable_A,
-	 .GetIntSrc = GetIntSrc_A,
-	 .GetLoadTrig = GetLoadTrig_A,
-	 .GetMode = GetMode_A,
-	 .PulseIndex = PulseIndex_A,
-	 .SetEnable = SetEnable_A,
-	 .SetIntSrc = SetIntSrc_A,
-	 .SetLoadTrig = SetLoadTrig_A,
-	 .SetMode = SetMode_A,
-	 .ResetCapFlags = ResetCapFlags_A,
-	 .MyCRA = LP_CR1A,
-	 .MyCRB = LP_CR1B,
-	 .MyLatchLsw = LP_CNTR1ALSW,
-	 .MyEventBits = EVBITS(1),
-	 },
-	{
-	 .GetEnable = GetEnable_A,
-	 .GetIntSrc = GetIntSrc_A,
-	 .GetLoadTrig = GetLoadTrig_A,
-	 .GetMode = GetMode_A,
-	 .PulseIndex = PulseIndex_A,
-	 .SetEnable = SetEnable_A,
-	 .SetIntSrc = SetIntSrc_A,
-	 .SetLoadTrig = SetLoadTrig_A,
-	 .SetMode = SetMode_A,
-	 .ResetCapFlags = ResetCapFlags_A,
-	 .MyCRA = LP_CR2A,
-	 .MyCRB = LP_CR2B,
-	 .MyLatchLsw = LP_CNTR2ALSW,
-	 .MyEventBits = EVBITS(2),
-	 },
-	{
-	 .GetEnable = GetEnable_B,
-	 .GetIntSrc = GetIntSrc_B,
-	 .GetLoadTrig = GetLoadTrig_B,
-	 .GetMode = GetMode_B,
-	 .PulseIndex = PulseIndex_B,
-	 .SetEnable = SetEnable_B,
-	 .SetIntSrc = SetIntSrc_B,
-	 .SetLoadTrig = SetLoadTrig_B,
-	 .SetMode = SetMode_B,
-	 .ResetCapFlags = ResetCapFlags_B,
-	 .MyCRA = LP_CR0A,
-	 .MyCRB = LP_CR0B,
-	 .MyLatchLsw = LP_CNTR0BLSW,
-	 .MyEventBits = EVBITS(3),
-	 },
-	{
-	 .GetEnable = GetEnable_B,
-	 .GetIntSrc = GetIntSrc_B,
-	 .GetLoadTrig = GetLoadTrig_B,
-	 .GetMode = GetMode_B,
-	 .PulseIndex = PulseIndex_B,
-	 .SetEnable = SetEnable_B,
-	 .SetIntSrc = SetIntSrc_B,
-	 .SetLoadTrig = SetLoadTrig_B,
-	 .SetMode = SetMode_B,
-	 .ResetCapFlags = ResetCapFlags_B,
-	 .MyCRA = LP_CR1A,
-	 .MyCRB = LP_CR1B,
-	 .MyLatchLsw = LP_CNTR1BLSW,
-	 .MyEventBits = EVBITS(4),
-	 },
-	{
-	 .GetEnable = GetEnable_B,
-	 .GetIntSrc = GetIntSrc_B,
-	 .GetLoadTrig = GetLoadTrig_B,
-	 .GetMode = GetMode_B,
-	 .PulseIndex = PulseIndex_B,
-	 .SetEnable = SetEnable_B,
-	 .SetIntSrc = SetIntSrc_B,
-	 .SetLoadTrig = SetLoadTrig_B,
-	 .SetMode = SetMode_B,
-	 .ResetCapFlags = ResetCapFlags_B,
-	 .MyCRA = LP_CR2A,
-	 .MyCRB = LP_CR2B,
-	 .MyLatchLsw = LP_CNTR2BLSW,
-	 .MyEventBits = EVBITS(5),
-	 },
-};
-
 /*  enab/disable a function or test status bit(s) that are accessed */
 /*  through Main Control Registers 1 or 2. */
 #define MC_ENABLE(REGADRS, CTRLWORD)	writel(((uint32_t)(CTRLWORD) << 16) | (uint32_t)(CTRLWORD), devpriv->base_addr+(REGADRS))
@@ -488,480 +271,416 @@ static const struct comedi_lrange s626_range_table = { 2, {
 							   }
 };
 
-static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+/*  Execute a DEBI transfer.  This must be called from within a */
+/*  critical section. */
+static void DEBItransfer(struct comedi_device *dev)
 {
-/*   uint8_t	PollList; */
-/*   uint16_t	AdcData; */
-/*   uint16_t	StartVal; */
-/*   uint16_t	index; */
-/*   unsigned int data[16]; */
-	int result;
-	int i;
-	int ret;
-	resource_size_t resourceStart;
-	dma_addr_t appdma;
-	struct comedi_subdevice *s;
-	struct pci_dev *pdev = NULL;
+	/*  Initiate upload of shadow RAM to DEBI control register. */
+	MC_ENABLE(P_MC2, MC2_UPLD_DEBI);
 
-	if (alloc_private(dev, sizeof(struct s626_private)) < 0)
-		return -ENOMEM;
+	/*  Wait for completion of upload from shadow RAM to DEBI control */
+	/*  register. */
+	while (!MC_TEST(P_MC2, MC2_UPLD_DEBI))
+		;
 
-	for (i = 0; i < ARRAY_SIZE(s626_boards) && !pdev; i++) {
-		do {
-			pdev = pci_get_subsys(s626_boards[i].vendor_id,
-					      s626_boards[i].device_id,
-					      s626_boards[i].subvendor_id,
-					      s626_boards[i].subdevice_id,
-					      pdev);
+	/*  Wait until DEBI transfer is done. */
+	while (RR7146(P_PSR) & PSR_DEBI_S)
+		;
+}
 
-			if ((it->options[0] || it->options[1]) && pdev) {
-				/* matches requested bus/slot */
-				if (pdev->bus->number == it->options[0] &&
-				    PCI_SLOT(pdev->devfn) == it->options[1])
-					break;
-			} else
-				break;
-		} while (1);
-	}
-	devpriv->pdev = pdev;
+/*  Initialize the DEBI interface for all transfers. */
 
-	if (pdev == NULL) {
-		printk(KERN_ERR "s626_attach: Board not present!!!\n");
-		return -ENODEV;
-	}
+static uint16_t DEBIread(struct comedi_device *dev, uint16_t addr)
+{
+	uint16_t retval;
 
-	result = comedi_pci_enable(pdev, "s626");
-	if (result < 0) {
-		printk(KERN_ERR "s626_attach: comedi_pci_enable fails\n");
-		return -ENODEV;
-	}
-	devpriv->got_regions = 1;
+	/*  Set up DEBI control register value in shadow RAM. */
+	WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr);
 
-	resourceStart = pci_resource_start(devpriv->pdev, 0);
+	/*  Execute the DEBI transfer. */
+	DEBItransfer(dev);
 
-	devpriv->base_addr = ioremap(resourceStart, SIZEOF_ADDRESS_SPACE);
-	if (devpriv->base_addr == NULL) {
-		printk(KERN_ERR "s626_attach: IOREMAP failed\n");
-		return -ENODEV;
-	}
+	/*  Fetch target register value. */
+	retval = (uint16_t) RR7146(P_DEBIAD);
 
-	if (devpriv->base_addr) {
-		/* disable master interrupt */
-		writel(0, devpriv->base_addr + P_IER);
+	/*  Return register value. */
+	return retval;
+}
 
-		/* soft reset */
-		writel(MC1_SOFT_RESET, devpriv->base_addr + P_MC1);
+/*  Write a value to a gate array register. */
+static void DEBIwrite(struct comedi_device *dev, uint16_t addr, uint16_t wdata)
+{
 
-		/* DMA FIXME DMA// */
-		DEBUG("s626_attach: DMA ALLOCATION\n");
+	/*  Set up DEBI control register value in shadow RAM. */
+	WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr);
+	WR7146(P_DEBIAD, wdata);
 
-		/* adc buffer allocation */
-		devpriv->allocatedBuf = 0;
+	/*  Execute the DEBI transfer. */
+	DEBItransfer(dev);
+}
 
-		devpriv->ANABuf.LogicalBase =
-		    pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma);
+/* Replace the specified bits in a gate array register.  Imports: mask
+ * specifies bits that are to be preserved, wdata is new value to be
+ * or'd with the masked original.
+ */
+static void DEBIreplace(struct comedi_device *dev, uint16_t addr, uint16_t mask,
+			uint16_t wdata)
+{
 
-		if (devpriv->ANABuf.LogicalBase == NULL) {
-			printk(KERN_ERR "s626_attach: DMA Memory mapping error\n");
-			return -ENOMEM;
-		}
+	/*  Copy target gate array register into P_DEBIAD register. */
+	WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr);
+	/* Set up DEBI control reg value in shadow RAM. */
+	DEBItransfer(dev);	/*  Execute the DEBI Read transfer. */
 
-		devpriv->ANABuf.PhysicalBase = appdma;
+	/*  Write back the modified image. */
+	WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr);
+	/* Set up DEBI control reg value in shadow  RAM. */
 
-		DEBUG
-		    ("s626_attach: AllocDMAB ADC Logical=%p, bsize=%d, Physical=0x%x\n",
-		     devpriv->ANABuf.LogicalBase, DMABUF_SIZE,
-		     (uint32_t) devpriv->ANABuf.PhysicalBase);
+	WR7146(P_DEBIAD, wdata | ((uint16_t) RR7146(P_DEBIAD) & mask));
+	/* Modify the register image. */
+	DEBItransfer(dev);	/*  Execute the DEBI Write transfer. */
+}
 
-		devpriv->allocatedBuf++;
+/* **************  EEPROM ACCESS FUNCTIONS  ************** */
 
-		devpriv->RPSBuf.LogicalBase =
-		    pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma);
+static uint32_t I2Chandshake(struct comedi_device *dev, uint32_t val)
+{
+	/*  Write I2C command to I2C Transfer Control shadow register. */
+	WR7146(P_I2CCTRL, val);
 
-		if (devpriv->RPSBuf.LogicalBase == NULL) {
-			printk(KERN_ERR "s626_attach: DMA Memory mapping error\n");
-			return -ENOMEM;
-		}
+	/*  Upload I2C shadow registers into working registers and wait for */
+	/*  upload confirmation. */
 
-		devpriv->RPSBuf.PhysicalBase = appdma;
+	MC_ENABLE(P_MC2, MC2_UPLD_IIC);
+	while (!MC_TEST(P_MC2, MC2_UPLD_IIC))
+		;
 
-		DEBUG
-		    ("s626_attach: AllocDMAB RPS Logical=%p, bsize=%d, Physical=0x%x\n",
-		     devpriv->RPSBuf.LogicalBase, DMABUF_SIZE,
-		     (uint32_t) devpriv->RPSBuf.PhysicalBase);
+	/*  Wait until I2C bus transfer is finished or an error occurs. */
+	while ((RR7146(P_I2CCTRL) & (I2C_BUSY | I2C_ERR)) == I2C_BUSY)
+		;
 
-		devpriv->allocatedBuf++;
+	/*  Return non-zero if I2C error occurred. */
+	return RR7146(P_I2CCTRL) & I2C_ERR;
 
-	}
+}
 
-	dev->board_ptr = s626_boards;
-	dev->board_name = thisboard->name;
+/*  Read uint8_t from EEPROM. */
+static uint8_t I2Cread(struct comedi_device *dev, uint8_t addr)
+{
+	uint8_t rtnval;
 
-	if (alloc_subdevices(dev, 6) < 0)
-		return -ENOMEM;
+	/*  Send EEPROM target address. */
+	if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CW)
+			 /* Byte2 = I2C command: write to I2C EEPROM  device. */
+			 | I2C_B1(I2C_ATTRSTOP, addr)
+			 /* Byte1 = EEPROM internal target address. */
+			 | I2C_B0(I2C_ATTRNOP, 0))) {	/*  Byte0 = Not sent. */
+		/*  Abort function and declare error if handshake failed. */
+		return 0;
+	}
+	/*  Execute EEPROM read. */
+	if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CR)
 
-	dev->iobase = (unsigned long)devpriv->base_addr;
-	dev->irq = devpriv->pdev->irq;
+			 /*  Byte2 = I2C */
+			 /*  command: read */
+			 /*  from I2C EEPROM */
+			 /*  device. */
+			 |I2C_B1(I2C_ATTRSTOP, 0)
 
-	/* set up interrupt handler */
-	if (dev->irq == 0) {
-		printk(KERN_ERR " unknown irq (bad)\n");
-	} else {
-		ret = request_irq(dev->irq, s626_irq_handler, IRQF_SHARED,
-				  "s626", dev);
+			 /*  Byte1 receives */
+			 /*  uint8_t from */
+			 /*  EEPROM. */
+			 |I2C_B0(I2C_ATTRNOP, 0))) {	/*  Byte0 = Not  sent. */
 
-		if (ret < 0) {
-			printk(KERN_ERR " irq not available\n");
-			dev->irq = 0;
-		}
+		/*  Abort function and declare error if handshake failed. */
+		return 0;
 	}
+	/*  Return copy of EEPROM value. */
+	rtnval = (uint8_t) (RR7146(P_I2CCTRL) >> 16);
+	return rtnval;
+}
 
-	DEBUG("s626_attach: -- it opts  %d,%d --\n",
-	      it->options[0], it->options[1]);
+/* ***********  DAC FUNCTIONS *********** */
 
-	s = dev->subdevices + 0;
-	/* analog input subdevice */
-	dev->read_subdev = s;
-	/* we support single-ended (ground) and differential */
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_CMD_READ;
-	s->n_chan = thisboard->ai_chans;
-	s->maxdata = (0xffff >> 2);
-	s->range_table = &s626_range_table;
-	s->len_chanlist = thisboard->ai_chans;	/* This is the maximum chanlist
-						   length that the board can
-						   handle */
-	s->insn_config = s626_ai_insn_config;
-	s->insn_read = s626_ai_insn_read;
-	s->do_cmd = s626_ai_cmd;
-	s->do_cmdtest = s626_ai_cmdtest;
-	s->cancel = s626_ai_cancel;
+/*  Slot 0 base settings. */
+#define VECT0	(XSD2 | RSD3 | SIB_A2)
+/*  Slot 0 always shifts in  0xFF and store it to  FB_BUFFER2. */
 
-	s = dev->subdevices + 1;
-	/* analog output subdevice */
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-	s->n_chan = thisboard->ao_chans;
-	s->maxdata = (0x3fff);
-	s->range_table = &range_bipolar10;
-	s->insn_write = s626_ao_winsn;
-	s->insn_read = s626_ao_rinsn;
+/*  TrimDac LogicalChan-to-PhysicalChan mapping table. */
+static uint8_t trimchan[] = { 10, 9, 8, 3, 2, 7, 6, 1, 0, 5, 4 };
 
-	s = dev->subdevices + 2;
-	/* digital I/O subdevice */
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-	s->n_chan = S626_DIO_CHANNELS;
-	s->maxdata = 1;
-	s->io_bits = 0xffff;
-	s->private = &dio_private_A;
-	s->range_table = &range_digital;
-	s->insn_config = s626_dio_insn_config;
-	s->insn_bits = s626_dio_insn_bits;
-
-	s = dev->subdevices + 3;
-	/* digital I/O subdevice */
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->io_bits = 0xffff;
-	s->private = &dio_private_B;
-	s->range_table = &range_digital;
-	s->insn_config = s626_dio_insn_config;
-	s->insn_bits = s626_dio_insn_bits;
-
-	s = dev->subdevices + 4;
-	/* digital I/O subdevice */
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->io_bits = 0xffff;
-	s->private = &dio_private_C;
-	s->range_table = &range_digital;
-	s->insn_config = s626_dio_insn_config;
-	s->insn_bits = s626_dio_insn_bits;
-
-	s = dev->subdevices + 5;
-	/* encoder (counter) subdevice */
-	s->type = COMEDI_SUBD_COUNTER;
-	s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL;
-	s->n_chan = thisboard->enc_chans;
-	s->private = enc_private_data;
-	s->insn_config = s626_enc_insn_config;
-	s->insn_read = s626_enc_insn_read;
-	s->insn_write = s626_enc_insn_write;
-	s->maxdata = 0xffffff;
-	s->range_table = &range_unknown;
-
-	/* stop ai_command */
-	devpriv->ai_cmd_running = 0;
-
-	if (devpriv->base_addr && (devpriv->allocatedBuf == 2)) {
-		dma_addr_t pPhysBuf;
-		uint16_t chan;
-
-		/*  enab DEBI and audio pins, enable I2C interface. */
-		MC_ENABLE(P_MC1, MC1_DEBI | MC1_AUDIO | MC1_I2C);
-		/*  Configure DEBI operating mode. */
-		WR7146(P_DEBICFG, DEBI_CFG_SLAVE16	/*  Local bus is 16 */
-		       /*  bits wide. */
-		       | (DEBI_TOUT << DEBI_CFG_TOUT_BIT)
-
-		       /*  Declare DEBI */
-		       /*  transfer timeout */
-		       /*  interval. */
-		       |DEBI_SWAP	/*  Set up byte lane */
-		       /*  steering. */
-		       | DEBI_CFG_INTEL);	/*  Intel-compatible */
-		/*  local bus (DEBI */
-		/*  never times out). */
-		DEBUG("s626_attach: %d debi init -- %d\n",
-		      DEBI_CFG_SLAVE16 | (DEBI_TOUT << DEBI_CFG_TOUT_BIT) |
-		      DEBI_SWAP | DEBI_CFG_INTEL,
-		      DEBI_CFG_INTEL | DEBI_CFG_TOQ | DEBI_CFG_INCQ |
-		      DEBI_CFG_16Q);
-
-		/* DEBI INIT S626 WR7146( P_DEBICFG, DEBI_CFG_INTEL | DEBI_CFG_TOQ */
-		/* | DEBI_CFG_INCQ| DEBI_CFG_16Q); //end */
-
-		/*  Paging is disabled. */
-		WR7146(P_DEBIPAGE, DEBI_PAGE_DISABLE);	/*  Disable MMU paging. */
-
-		/*  Init GPIO so that ADC Start* is negated. */
-		WR7146(P_GPIO, GPIO_BASE | GPIO1_HI);
-
-		/* IsBoardRevA is a boolean that indicates whether the board is RevA.
-		 *
-		 * VERSION 2.01 CHANGE: REV A & B BOARDS NOW SUPPORTED BY DYNAMIC
-		 * EEPROM ADDRESS SELECTION.  Initialize the I2C interface, which
-		 * is used to access the onboard serial EEPROM.  The EEPROM's I2C
-		 * DeviceAddress is hardwired to a value that is dependent on the
-		 * 626 board revision.  On all board revisions, the EEPROM stores
-		 * TrimDAC calibration constants for analog I/O.  On RevB and
-		 * higher boards, the DeviceAddress is hardwired to 0 to enable
-		 * the EEPROM to also store the PCI SubVendorID and SubDeviceID;
-		 * this is the address at which the SAA7146 expects a
-		 * configuration EEPROM to reside.  On RevA boards, the EEPROM
-		 * device address, which is hardwired to 4, prevents the SAA7146
-		 * from retrieving PCI sub-IDs, so the SAA7146 uses its built-in
-		 * default values, instead.
-		 */
-
-		/*     devpriv->I2Cards= IsBoardRevA ? 0xA8 : 0xA0; // Set I2C EEPROM */
-		/*  DeviceType (0xA0) */
-		/*  and DeviceAddress<<1. */
-
-		devpriv->I2CAdrs = 0xA0;	/*  I2C device address for onboard */
-		/*  eeprom(revb) */
-
-		/*  Issue an I2C ABORT command to halt any I2C operation in */
-		/* progress and reset BUSY flag. */
-		WR7146(P_I2CSTAT, I2C_CLKSEL | I2C_ABORT);
-		/*  Write I2C control: abort any I2C activity. */
-		MC_ENABLE(P_MC2, MC2_UPLD_IIC);
-		/*  Invoke command  upload */
-		while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0)
-			;
-		/*  and wait for upload to complete. */
-
-		/* Per SAA7146 data sheet, write to STATUS reg twice to
-		 * reset all  I2C error flags. */
-		for (i = 0; i < 2; i++) {
-			WR7146(P_I2CSTAT, I2C_CLKSEL);
-			/*  Write I2C control: reset  error flags. */
-			MC_ENABLE(P_MC2, MC2_UPLD_IIC);	/*  Invoke command upload */
-			while (!MC_TEST(P_MC2, MC2_UPLD_IIC))
-				;
-			/* and wait for upload to complete. */
-		}
+/*  TrimDac LogicalChan-to-EepromAdrs mapping table. */
+static uint8_t trimadrs[] = { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 };
 
-		/* Init audio interface functional attributes: set DAC/ADC
-		 * serial clock rates, invert DAC serial clock so that
-		 * DAC data setup times are satisfied, enable DAC serial
-		 * clock out.
-		 */
+/* Private helper function: Transmit serial data to DAC via Audio
+ * channel 2.  Assumes: (1) TSL2 slot records initialized, and (2)
+ * Dacpol contains valid target image.
+ */
+static void SendDAC(struct comedi_device *dev, uint32_t val)
+{
 
-		WR7146(P_ACON2, ACON2_INIT);
+	/* START THE SERIAL CLOCK RUNNING ------------- */
 
-		/* Set up TSL1 slot list, which is used to control the
-		 * accumulation of ADC data: RSD1 = shift data in on SD1.
-		 * SIB_A1  = store data uint8_t at next available location in
-		 * FB BUFFER1  register. */
-		WR7146(P_TSL1, RSD1 | SIB_A1);
-		/*  Fetch ADC high data uint8_t. */
-		WR7146(P_TSL1 + 4, RSD1 | SIB_A1 | EOS);
-		/*  Fetch ADC low data uint8_t; end of TSL1. */
+	/* Assert DAC polarity control and enable gating of DAC serial clock
+	 * and audio bit stream signals.  At this point in time we must be
+	 * assured of being in time slot 0.  If we are not in slot 0, the
+	 * serial clock and audio stream signals will be disabled; this is
+	 * because the following DEBIwrite statement (which enables signals
+	 * to be passed through the gate array) would execute before the
+	 * trailing edge of WS1/WS3 (which turns off the signals), thus
+	 * causing the signals to be inactive during the DAC write.
+	 */
+	DEBIwrite(dev, LP_DACPOL, devpriv->Dacpol);
 
-		/*  enab TSL1 slot list so that it executes all the time. */
-		WR7146(P_ACON1, ACON1_ADCSTART);
+	/* TRANSFER OUTPUT DWORD VALUE INTO A2'S OUTPUT FIFO ---------------- */
 
-		/*  Initialize RPS registers used for ADC. */
+	/* Copy DAC setpoint value to DAC's output DMA buffer. */
 
-		/* Physical start of RPS program. */
-		WR7146(P_RPSADDR1, (uint32_t) devpriv->RPSBuf.PhysicalBase);
+	/* WR7146( (uint32_t)devpriv->pDacWBuf, val ); */
+	*devpriv->pDacWBuf = val;
 
-		WR7146(P_RPSPAGE1, 0);
-		/*  RPS program performs no explicit mem writes. */
-		WR7146(P_RPS1_TOUT, 0);	/*  Disable RPS timeouts. */
+	/* enab the output DMA transfer.  This will cause the DMAC to copy
+	 * the DAC's data value to A2's output FIFO.  The DMA transfer will
+	 * then immediately terminate because the protection address is
+	 * reached upon transfer of the first DWORD value.
+	 */
+	MC_ENABLE(P_MC1, MC1_A2OUT);
 
-		/* SAA7146 BUG WORKAROUND.  Initialize SAA7146 ADC interface
-		 * to a known state by invoking ADCs until FB BUFFER 1
-		 * register shows that it is correctly receiving ADC data.
-		 * This is necessary because the SAA7146 ADC interface does
-		 * not start up in a defined state after a PCI reset.
-		 */
+	/*  While the DMA transfer is executing ... */
 
-/*     PollList = EOPL;		// Create a simple polling */
-/*				// list for analog input */
-/*				// channel 0. */
-/*     ResetADC( dev, &PollList ); */
+	/* Reset Audio2 output FIFO's underflow flag (along with any other
+	 * FIFO underflow/overflow flags).  When set, this flag will
+	 * indicate that we have emerged from slot 0.
+	 */
+	WR7146(P_ISR, ISR_AFOU);
 
-/*     s626_ai_rinsn(dev,dev->subdevices,NULL,data); //( &AdcData ); // */
-/*							//Get initial ADC */
-/*							//value. */
+	/* Wait for the DMA transfer to finish so that there will be data
+	 * available in the FIFO when time slot 1 tries to transfer a DWORD
+	 * from the FIFO to the output buffer register.  We test for DMA
+	 * Done by polling the DMAC enable flag; this flag is automatically
+	 * cleared when the transfer has finished.
+	 */
+	while ((RR7146(P_MC1) & MC1_A2OUT) != 0)
+		;
 
-/*     StartVal = data[0]; */
+	/* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */
 
-/*     // VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION. */
-/*     // Invoke ADCs until the new ADC value differs from the initial */
-/*     // value or a timeout occurs.  The timeout protects against the */
-/*     // possibility that the driver is restarting and the ADC data is a */
-/*     // fixed value resulting from the applied ADC analog input being */
-/*     // unusually quiet or at the rail. */
+	/* FIFO data is now available, so we enable execution of time slots
+	 * 1 and higher by clearing the EOS flag in slot 0.  Note that SD3
+	 * will be shifted in and stored in FB_BUFFER2 for end-of-slot-list
+	 * detection.
+	 */
+	SETVECT(0, XSD2 | RSD3 | SIB_A2);
 
-/*     for ( index = 0; index < 500; index++ ) */
-/*       { */
-/*	s626_ai_rinsn(dev,dev->subdevices,NULL,data); */
-/*	AdcData = data[0];	//ReadADC(  &AdcData ); */
-/*	if ( AdcData != StartVal ) */
-/*		break; */
-/*       } */
+	/* Wait for slot 1 to execute to ensure that the Packet will be
+	 * transmitted.  This is detected by polling the Audio2 output FIFO
+	 * underflow flag, which will be set when slot 1 execution has
+	 * finished transferring the DAC's data DWORD from the output FIFO
+	 * to the output buffer register.
+	 */
+	while ((RR7146(P_SSR) & SSR_AF2_OUT) == 0)
+		;
 
-		/*  end initADC */
+	/* Set up to trap execution at slot 0 when the TSL sequencer cycles
+	 * back to slot 0 after executing the EOS in slot 5.  Also,
+	 * simultaneously shift out and in the 0x00 that is ALWAYS the value
+	 * stored in the last byte to be shifted out of the FIFO's DWORD
+	 * buffer register.
+	 */
+	SETVECT(0, XSD2 | XFIFO_2 | RSD2 | SIB_A2 | EOS);
 
-		/*  init the DAC interface */
+	/* WAIT FOR THE TRANSACTION TO FINISH ----------------------- */
 
-		/* Init Audio2's output DMAC attributes: burst length = 1
-		 * DWORD,  threshold = 1 DWORD.
+	/* Wait for the TSL to finish executing all time slots before
+	 * exiting this function.  We must do this so that the next DAC
+	 * write doesn't start, thereby enabling clock/chip select signals:
+	 *
+	 * 1. Before the TSL sequence cycles back to slot 0, which disables
+	 *    the clock/cs signal gating and traps slot // list execution.
+	 *    we have not yet finished slot 5 then the clock/cs signals are
+	 *    still gated and we have not finished transmitting the stream.
+	 *
+	 * 2. While slots 2-5 are executing due to a late slot 0 trap.  In
+	 *    this case, the slot sequence is currently repeating, but with
+	 *    clock/cs signals disabled.  We must wait for slot 0 to trap
+	 *    execution before setting up the next DAC setpoint DMA transfer
+	 *    and enabling the clock/cs signals.  To detect the end of slot 5,
+	 *    we test for the FB_BUFFER2 MSB contents to be equal to 0xFF.  If
+	 *    the TSL has not yet finished executing slot 5 ...
+	 */
+	if ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0) {
+		/* The trap was set on time and we are still executing somewhere
+		 * in slots 2-5, so we now wait for slot 0 to execute and trap
+		 * TSL execution.  This is detected when FB_BUFFER2 MSB changes
+		 * from 0xFF to 0x00, which slot 0 causes to happen by shifting
+		 * out/in on SD2 the 0x00 that is always referenced by slot 5.
 		 */
-		WR7146(P_PCI_BT_A, 0);
+		while ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0)
+			;
+	}
+	/* Either (1) we were too late setting the slot 0 trap; the TSL
+	 * sequencer restarted slot 0 before we could set the EOS trap flag,
+	 * or (2) we were not late and execution is now trapped at slot 0.
+	 * In either case, we must now change slot 0 so that it will store
+	 * value 0xFF (instead of 0x00) to FB_BUFFER2 next time it executes.
+	 * In order to do this, we reprogram slot 0 so that it will shift in
+	 * SD3, which is driven only by a pull-up resistor.
+	 */
+	SETVECT(0, RSD3 | SIB_A2 | EOS);
 
-		/* Init Audio2's output DMA physical addresses.  The protection
-		 * address is set to 1 DWORD past the base address so that a
-		 * single DWORD will be transferred each time a DMA transfer is
-		 * enabled. */
+	/* Wait for slot 0 to execute, at which time the TSL is setup for
+	 * the next DAC write.  This is detected when FB_BUFFER2 MSB changes
+	 * from 0x00 to 0xFF.
+	 */
+	while ((RR7146(P_FB_BUFFER2) & 0xFF000000) == 0)
+		;
+}
 
-		pPhysBuf =
-		    devpriv->ANABuf.PhysicalBase +
-		    (DAC_WDMABUF_OS * sizeof(uint32_t));
+/*  Private helper function: Write setpoint to an application DAC channel. */
+static void SetDAC(struct comedi_device *dev, uint16_t chan, short dacdata)
+{
+	register uint16_t signmask;
+	register uint32_t WSImage;
 
-		WR7146(P_BASEA2_OUT, (uint32_t) pPhysBuf);	/*  Buffer base adrs. */
-		WR7146(P_PROTA2_OUT, (uint32_t) (pPhysBuf + sizeof(uint32_t)));	/*  Protection address. */
+	/*  Adjust DAC data polarity and set up Polarity Control Register */
+	/*  image. */
+	signmask = 1 << chan;
+	if (dacdata < 0) {
+		dacdata = -dacdata;
+		devpriv->Dacpol |= signmask;
+	} else
+		devpriv->Dacpol &= ~signmask;
 
-		/* Cache Audio2's output DMA buffer logical address.  This is
-		 * where DAC data is buffered for A2 output DMA transfers. */
-		devpriv->pDacWBuf =
-		    (uint32_t *) devpriv->ANABuf.LogicalBase + DAC_WDMABUF_OS;
+	/*  Limit DAC setpoint value to valid range. */
+	if ((uint16_t) dacdata > 0x1FFF)
+		dacdata = 0x1FFF;
 
-		/* Audio2's output channels does not use paging.  The protection
-		 * violation handling bit is set so that the DMAC will
-		 * automatically halt and its PCI address pointer will be reset
-		 * when the protection address is reached. */
+	/* Set up TSL2 records (aka "vectors") for DAC update.  Vectors V2
+	 * and V3 transmit the setpoint to the target DAC.  V4 and V5 send
+	 * data to a non-existent TrimDac channel just to keep the clock
+	 * running after sending data to the target DAC.  This is necessary
+	 * to eliminate the clock glitch that would otherwise occur at the
+	 * end of the target DAC's serial data stream.  When the sequence
+	 * restarts at V0 (after executing V5), the gate array automatically
+	 * disables gating for the DAC clock and all DAC chip selects.
+	 */
 
-		WR7146(P_PAGEA2_OUT, 8);
+	WSImage = (chan & 2) ? WS1 : WS2;
+	/* Choose DAC chip select to be asserted. */
+	SETVECT(2, XSD2 | XFIFO_1 | WSImage);
+	/* Slot 2: Transmit high data byte to target DAC. */
+	SETVECT(3, XSD2 | XFIFO_0 | WSImage);
+	/* Slot 3: Transmit low data byte to target DAC. */
+	SETVECT(4, XSD2 | XFIFO_3 | WS3);
+	/* Slot 4: Transmit to non-existent TrimDac channel to keep clock */
+	SETVECT(5, XSD2 | XFIFO_2 | WS3 | EOS);
+	/* Slot 5: running after writing target DAC's low data byte. */
 
-		/* Initialize time slot list 2 (TSL2), which is used to control
-		 * the clock generation for and serialization of data to be sent
-		 * to the DAC devices.  Slot 0 is a NOP that is used to trap TSL
-		 * execution; this permits other slots to be safely modified
-		 * without first turning off the TSL sequencer (which is
-		 * apparently impossible to do).  Also, SD3 (which is driven by a
-		 * pull-up resistor) is shifted in and stored to the MSB of
-		 * FB_BUFFER2 to be used as evidence that the slot sequence has
-		 * not yet finished executing.
-		 */
+	/*  Construct and transmit target DAC's serial packet:
+	 * ( A10D DDDD ),( DDDD DDDD ),( 0x0F ),( 0x00 ) where A is chan<0>,
+	 * and D<12:0> is the DAC setpoint.  Append a WORD value (that writes
+	 * to a  non-existent TrimDac channel) that serves to keep the clock
+	 * running after the packet has been sent to the target DAC.
+	 */
+	SendDAC(dev, 0x0F000000
+		/* Continue clock after target DAC data (write to non-existent trimdac). */
+		| 0x00004000
+		/* Address the two main dual-DAC devices (TSL's chip select enables
+		 * target device). */
+		| ((uint32_t) (chan & 1) << 15)
+		/*  Address the DAC channel within the  device. */
+		| (uint32_t) dacdata);	/*  Include DAC setpoint data. */
 
-		SETVECT(0, XSD2 | RSD3 | SIB_A2 | EOS);
-		/*  Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2. */
+}
 
-		/* Initialize slot 1, which is constant.  Slot 1 causes a
-		 * DWORD to be transferred from audio channel 2's output FIFO
-		 * to the FIFO's output buffer so that it can be serialized
-		 * and sent to the DAC during subsequent slots.  All remaining
-		 * slots are dynamically populated as required by the target
-		 * DAC device.
-		 */
-		SETVECT(1, LF_A2);
-		/*  Slot 1: Fetch DWORD from Audio2's output FIFO. */
+static void WriteTrimDAC(struct comedi_device *dev, uint8_t LogicalChan,
+			 uint8_t DacData)
+{
+	uint32_t chan;
 
-		/*  Start DAC's audio interface (TSL2) running. */
-		WR7146(P_ACON1, ACON1_DACSTART);
+	/*  Save the new setpoint in case the application needs to read it back later. */
+	devpriv->TrimSetpoint[LogicalChan] = (uint8_t) DacData;
 
-		/* end init DAC interface */
+	/*  Map logical channel number to physical channel number. */
+	chan = (uint32_t) trimchan[LogicalChan];
 
-		/* Init Trim DACs to calibrated values.  Do it twice because the
-		 * SAA7146 audio channel does not always reset properly and
-		 * sometimes causes the first few TrimDAC writes to malfunction.
-		 */
+	/* Set up TSL2 records for TrimDac write operation.  All slots shift
+	 * 0xFF in from pulled-up SD3 so that the end of the slot sequence
+	 * can be detected.
+	 */
 
-		LoadTrimDACs(dev);
-		LoadTrimDACs(dev);	/*  Insurance. */
+	SETVECT(2, XSD2 | XFIFO_1 | WS3);
+	/* Slot 2: Send high uint8_t to target TrimDac. */
+	SETVECT(3, XSD2 | XFIFO_0 | WS3);
+	/* Slot 3: Send low uint8_t to target TrimDac. */
+	SETVECT(4, XSD2 | XFIFO_3 | WS1);
+	/* Slot 4: Send NOP high uint8_t to DAC0 to keep clock running. */
+	SETVECT(5, XSD2 | XFIFO_2 | WS1 | EOS);
+	/* Slot 5: Send NOP low  uint8_t to DAC0. */
 
-		/* Manually init all gate array hardware in case this is a soft
-		 * reset (we have no way of determining whether this is a warm
-		 * or cold start).  This is necessary because the gate array will
-		 * reset only in response to a PCI hard reset; there is no soft
-		 * reset function. */
+	/* Construct and transmit target DAC's serial packet:
+	 * ( 0000 AAAA ), ( DDDD DDDD ),( 0x00 ),( 0x00 ) where A<3:0> is the
+	 * DAC channel's address, and D<7:0> is the DAC setpoint.  Append a
+	 * WORD value (that writes a channel 0 NOP command to a non-existent
+	 * main DAC channel) that serves to keep the clock running after the
+	 * packet has been sent to the target DAC.
+	 */
 
-		/* Init all DAC outputs to 0V and init all DAC setpoint and
-		 * polarity images.
-		 */
-		for (chan = 0; chan < S626_DAC_CHANNELS; chan++)
-			SetDAC(dev, chan, 0);
+	/*  Address the DAC channel within the trimdac device. */
+	SendDAC(dev, ((uint32_t) chan << 8)
+		| (uint32_t) DacData);	/*  Include DAC setpoint data. */
+}
 
-		/* Init image of WRMISC2 Battery Charger Enabled control bit.
-		 * This image is used when the state of the charger control bit,
-		 * which has no direct hardware readback mechanism, is queried.
-		 */
-		devpriv->ChargeEnabled = 0;
+static void LoadTrimDACs(struct comedi_device *dev)
+{
+	register uint8_t i;
 
-		/* Init image of watchdog timer interval in WRMISC2.  This image
-		 * maintains the value of the control bits of MISC2 are
-		 * continuously reset to zero as long as the WD timer is disabled.
-		 */
-		devpriv->WDInterval = 0;
+	/*  Copy TrimDac setpoint values from EEPROM to TrimDacs. */
+	for (i = 0; i < ARRAY_SIZE(trimchan); i++)
+		WriteTrimDAC(dev, i, I2Cread(dev, trimadrs[i]));
+}
 
-		/* Init Counter Interrupt enab mask for RDMISC2.  This mask is
-		 * applied against MISC2 when testing to determine which timer
-		 * events are requesting interrupt service.
-		 */
-		devpriv->CounterIntEnabs = 0;
+/* ******  COUNTER FUNCTIONS  ******* */
+/* All counter functions address a specific counter by means of the
+ * "Counter" argument, which is a logical counter number.  The Counter
+ * argument may have any of the following legal values: 0=0A, 1=1A,
+ * 2=2A, 3=0B, 4=1B, 5=2B.
+ */
 
-		/*  Init counters. */
-		CountersInit(dev);
+/*  Read a counter's output latch. */
+static uint32_t ReadLatch(struct comedi_device *dev, struct enc_private *k)
+{
+	register uint32_t value;
 
-		/* Without modifying the state of the Battery Backup enab, disable
-		 * the watchdog timer, set DIO channels 0-5 to operate in the
-		 * standard DIO (vs. counter overflow) mode, disable the battery
-		 * charger, and reset the watchdog interval selector to zero.
-		 */
-		WriteMISC2(dev, (uint16_t) (DEBIread(dev,
-						     LP_RDMISC2) &
-					    MISC2_BATT_ENABLE));
+	/*  Latch counts and fetch LSW of latched counts value. */
+	value = (uint32_t) DEBIread(dev, k->MyLatchLsw);
 
-		/*  Initialize the digital I/O subsystem. */
-		s626_dio_init(dev);
+	/*  Fetch MSW of latched counts and combine with LSW. */
+	value |= ((uint32_t) DEBIread(dev, k->MyLatchLsw + 2) << 16);
 
-		/* enable interrupt test */
-		/*  writel(IRQ_GPIO3 | IRQ_RPS1,devpriv->base_addr+P_IER); */
-	}
+	/*  Return latched counts. */
+	return value;
+}
 
-	DEBUG("s626_attach: comedi%d s626 attached %04x\n", dev->minor,
-	      (uint32_t) devpriv->base_addr);
+/* Return/set a counter pair's latch trigger source.  0: On read
+ * access, 1: A index latches A, 2: B index latches B, 3: A overflow
+ * latches B.
+ */
+static void SetLatchSource(struct comedi_device *dev, struct enc_private *k,
+			   uint16_t value)
+{
+	DEBIreplace(dev, k->MyCRB,
+		    (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_LATCHSRC)),
+		    (uint16_t) (value << CRBBIT_LATCHSRC));
+}
 
-	return 1;
+/*  Write value into counter preload register. */
+static void Preload(struct comedi_device *dev, struct enc_private *k,
+		    uint32_t value)
+{
+	DEBIwrite(dev, (uint16_t) (k->MyLatchLsw), (uint16_t) value);
+	DEBIwrite(dev, (uint16_t) (k->MyLatchLsw + 2),
+		  (uint16_t) (value >> 16));
 }
 
 static unsigned int s626_ai_reg_to_uint(int data)
@@ -981,6 +700,81 @@ static unsigned int s626_ai_reg_to_uint(int data)
 /*   return 0; */
 /* } */
 
+static int s626_dio_set_irq(struct comedi_device *dev, unsigned int chan)
+{
+	unsigned int group;
+	unsigned int bitmask;
+	unsigned int status;
+
+	/* select dio bank */
+	group = chan / 16;
+	bitmask = 1 << (chan - (16 * group));
+
+	/* set channel to capture positive edge */
+	status = DEBIread(dev,
+			  ((struct dio_private *)(dev->subdevices + 2 +
+						  group)->private)->RDEdgSel);
+	DEBIwrite(dev,
+		  ((struct dio_private *)(dev->subdevices + 2 +
+					  group)->private)->WREdgSel,
+		  bitmask | status);
+
+	/* enable interrupt on selected channel */
+	status = DEBIread(dev,
+			  ((struct dio_private *)(dev->subdevices + 2 +
+						  group)->private)->RDIntSel);
+	DEBIwrite(dev,
+		  ((struct dio_private *)(dev->subdevices + 2 +
+					  group)->private)->WRIntSel,
+		  bitmask | status);
+
+	/* enable edge capture write command */
+	DEBIwrite(dev, LP_MISC1, MISC1_EDCAP);
+
+	/* enable edge capture on selected channel */
+	status = DEBIread(dev,
+			  ((struct dio_private *)(dev->subdevices + 2 +
+						  group)->private)->RDCapSel);
+	DEBIwrite(dev,
+		  ((struct dio_private *)(dev->subdevices + 2 +
+					  group)->private)->WRCapSel,
+		  bitmask | status);
+
+	return 0;
+}
+
+static int s626_dio_reset_irq(struct comedi_device *dev, unsigned int group,
+			      unsigned int mask)
+{
+	/* disable edge capture write command */
+	DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP);
+
+	/* enable edge capture on selected channel */
+	DEBIwrite(dev,
+		  ((struct dio_private *)(dev->subdevices + 2 +
+					  group)->private)->WRCapSel, mask);
+
+	return 0;
+}
+
+static int s626_dio_clear_irq(struct comedi_device *dev)
+{
+	unsigned int group;
+
+	/* disable edge capture write command */
+	DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP);
+
+	for (group = 0; group < S626_DIO_BANKS; group++) {
+		/* clear pending events and interrupt */
+		DEBIwrite(dev,
+			  ((struct dio_private *)(dev->subdevices + 2 +
+						  group)->private)->WRCapSel,
+			  0xffff);
+	}
+
+	return 0;
+}
+
 static irqreturn_t s626_irq_handler(int irq, void *d)
 {
 	struct comedi_device *dev = d;
@@ -995,8 +789,6 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
 	uint8_t group;
 	uint16_t irqbit;
 
-	DEBUG("s626_irq_handler: interrupt request received!!!\n");
-
 	if (dev->attached == 0)
 		return IRQ_NONE;
 	/*  lock to avoid race with comedi_poll */
@@ -1014,14 +806,8 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
 	/* clear interrupt */
 	writel(irqtype, devpriv->base_addr + P_ISR);
 
-	/* do somethings */
-	DEBUG("s626_irq_handler: interrupt type %d\n", irqtype);
-
 	switch (irqtype) {
 	case IRQ_RPS1:		/*  end_of_scan occurs */
-
-		DEBUG("s626_irq_handler: RPS1 irq detected\n");
-
 		/*  manage ai subdevice */
 		s = dev->subdevices;
 		cmd = &(s->async->cmd);
@@ -1044,9 +830,6 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
 			if (cfc_write_to_buffer(s, tempdata) == 0)
 				printk
 				    ("s626_irq_handler: cfc_write_to_buffer error!\n");
-
-			DEBUG("s626_irq_handler: ai channel %d acquired: %d\n",
-			      i, tempdata);
 		}
 
 		/* end of scan occurs */
@@ -1067,23 +850,12 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
 			irqstatus = 0;
 		}
 
-		if (devpriv->ai_cmd_running && cmd->scan_begin_src == TRIG_EXT) {
-			DEBUG
-			    ("s626_irq_handler: enable interrupt on dio channel %d\n",
-			     cmd->scan_begin_arg);
-
+		if (devpriv->ai_cmd_running && cmd->scan_begin_src == TRIG_EXT)
 			s626_dio_set_irq(dev, cmd->scan_begin_arg);
-
-			DEBUG("s626_irq_handler: External trigger is set!!!\n");
-		}
 		/*  tell comedi that data is there */
-		DEBUG("s626_irq_handler: events %d\n", s->async->events);
 		comedi_event(dev, s);
 		break;
 	case IRQ_GPIO3:	/* check dio and conter interrupt */
-
-		DEBUG("s626_irq_handler: GPIO3 irq detected\n");
-
 		/*  manage ai subdevice */
 		s = dev->subdevices;
 		cmd = &(s->async->cmd);
@@ -1103,36 +875,18 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
 			/* check if interrupt is generated from dio channels */
 			if (irqbit) {
 				s626_dio_reset_irq(dev, group, irqbit);
-				DEBUG
-				    ("s626_irq_handler: check interrupt on dio group %d %d\n",
-				     group, i);
 				if (devpriv->ai_cmd_running) {
 					/* check if interrupt is an ai acquisition start trigger */
 					if ((irqbit >> (cmd->start_arg -
 							(16 * group)))
 					    == 1 && cmd->start_src == TRIG_EXT) {
-						DEBUG
-						    ("s626_irq_handler: Edge capture interrupt received from channel %d\n",
-						     cmd->start_arg);
-
 						/*  Start executing the RPS program. */
 						MC_ENABLE(P_MC1, MC1_ERPS1);
 
-						DEBUG
-						    ("s626_irq_handler: acquisition start triggered!!!\n");
-
 						if (cmd->scan_begin_src ==
 						    TRIG_EXT) {
-							DEBUG
-							    ("s626_ai_cmd: enable interrupt on dio channel %d\n",
-							     cmd->
-							     scan_begin_arg);
-
 							s626_dio_set_irq(dev,
 									 cmd->scan_begin_arg);
-
-							DEBUG
-							    ("s626_irq_handler: External scan trigger is set!!!\n");
 						}
 					}
 					if ((irqbit >> (cmd->scan_begin_arg -
@@ -1140,33 +894,16 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
 					    == 1
 					    && cmd->scan_begin_src ==
 					    TRIG_EXT) {
-						DEBUG
-						    ("s626_irq_handler: Edge capture interrupt received from channel %d\n",
-						     cmd->scan_begin_arg);
-
 						/*  Trigger ADC scan loop start by setting RPS Signal 0. */
 						MC_ENABLE(P_MC2, MC2_ADC_RPS);
 
-						DEBUG
-						    ("s626_irq_handler: scan triggered!!! %d\n",
-						     devpriv->ai_sample_count);
 						if (cmd->convert_src ==
 						    TRIG_EXT) {
-
-							DEBUG
-							    ("s626_ai_cmd: enable interrupt on dio channel %d group %d\n",
-							     cmd->convert_arg -
-							     (16 * group),
-							     group);
-
 							devpriv->ai_convert_count
 							    = cmd->chanlist_len;
 
 							s626_dio_set_irq(dev,
 									 cmd->convert_arg);
-
-							DEBUG
-							    ("s626_irq_handler: External convert trigger is set!!!\n");
 						}
 
 						if (cmd->convert_src ==
@@ -1182,32 +919,15 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
 							(16 * group)))
 					    == 1
 					    && cmd->convert_src == TRIG_EXT) {
-						DEBUG
-						    ("s626_irq_handler: Edge capture interrupt received from channel %d\n",
-						     cmd->convert_arg);
-
 						/*  Trigger ADC scan loop start by setting RPS Signal 0. */
 						MC_ENABLE(P_MC2, MC2_ADC_RPS);
 
-						DEBUG
-						    ("s626_irq_handler: adc convert triggered!!!\n");
-
 						devpriv->ai_convert_count--;
 
 						if (devpriv->ai_convert_count >
 						    0) {
-
-							DEBUG
-							    ("s626_ai_cmd: enable interrupt on dio channel %d group %d\n",
-							     cmd->convert_arg -
-							     (16 * group),
-							     group);
-
 							s626_dio_set_irq(dev,
 									 cmd->convert_arg);
-
-							DEBUG
-							    ("s626_irq_handler: External trigger is set!!!\n");
 						}
 					}
 				}
@@ -1219,44 +939,31 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
 		irqbit = DEBIread(dev, LP_RDMISC2);
 
 		/* check interrupt on counters */
-		DEBUG("s626_irq_handler: check counters interrupt %d\n",
-		      irqbit);
-
 		if (irqbit & IRQ_COINT1A) {
-			DEBUG
-			    ("s626_irq_handler: interrupt on counter 1A overflow\n");
 			k = &encpriv[0];
 
 			/* clear interrupt capture flag */
 			k->ResetCapFlags(dev, k);
 		}
 		if (irqbit & IRQ_COINT2A) {
-			DEBUG
-			    ("s626_irq_handler: interrupt on counter 2A overflow\n");
 			k = &encpriv[1];
 
 			/* clear interrupt capture flag */
 			k->ResetCapFlags(dev, k);
 		}
 		if (irqbit & IRQ_COINT3A) {
-			DEBUG
-			    ("s626_irq_handler: interrupt on counter 3A overflow\n");
 			k = &encpriv[2];
 
 			/* clear interrupt capture flag */
 			k->ResetCapFlags(dev, k);
 		}
 		if (irqbit & IRQ_COINT1B) {
-			DEBUG
-			    ("s626_irq_handler: interrupt on counter 1B overflow\n");
 			k = &encpriv[3];
 
 			/* clear interrupt capture flag */
 			k->ResetCapFlags(dev, k);
 		}
 		if (irqbit & IRQ_COINT2B) {
-			DEBUG
-			    ("s626_irq_handler: interrupt on counter 2B overflow\n");
 			k = &encpriv[4];
 
 			/* clear interrupt capture flag */
@@ -1268,34 +975,23 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
 					k->SetEnable(dev, k, CLKENAB_INDEX);
 
 				if (cmd->convert_src == TRIG_TIMER) {
-					DEBUG
-					    ("s626_irq_handler: conver timer trigger!!! %d\n",
-					     devpriv->ai_convert_count);
-
 					/*  Trigger ADC scan loop start by setting RPS Signal 0. */
 					MC_ENABLE(P_MC2, MC2_ADC_RPS);
 				}
 			}
 		}
 		if (irqbit & IRQ_COINT3B) {
-			DEBUG
-			    ("s626_irq_handler: interrupt on counter 3B overflow\n");
 			k = &encpriv[5];
 
 			/* clear interrupt capture flag */
 			k->ResetCapFlags(dev, k);
 
 			if (cmd->scan_begin_src == TRIG_TIMER) {
-				DEBUG
-				    ("s626_irq_handler: scan timer trigger!!!\n");
-
 				/*  Trigger ADC scan loop start by setting RPS Signal 0. */
 				MC_ENABLE(P_MC2, MC2_ADC_RPS);
 			}
 
 			if (cmd->convert_src == TRIG_TIMER) {
-				DEBUG
-				    ("s626_irq_handler: convert timer trigger is set\n");
 				k = &encpriv[4];
 				devpriv->ai_convert_count = cmd->chanlist_len;
 				k->SetEnable(dev, k, CLKENAB_ALWAYS);
@@ -1306,50 +1002,14 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
 	/* enable interrupt */
 	writel(irqstatus, devpriv->base_addr + P_IER);
 
-	DEBUG("s626_irq_handler: exit interrupt service routine.\n");
-
 	spin_unlock_irqrestore(&dev->spinlock, flags);
 	return IRQ_HANDLED;
 }
 
-static void s626_detach(struct comedi_device *dev)
-{
-	if (devpriv) {
-		/* stop ai_command */
-		devpriv->ai_cmd_running = 0;
-
-		if (devpriv->base_addr) {
-			/* interrupt mask */
-			WR7146(P_IER, 0);	/*  Disable master interrupt. */
-			WR7146(P_ISR, IRQ_GPIO3 | IRQ_RPS1);	/*  Clear board's IRQ status flag. */
-
-			/*  Disable the watchdog timer and battery charger. */
-			WriteMISC2(dev, 0);
-
-			/*  Close all interfaces on 7146 device. */
-			WR7146(P_MC1, MC1_SHUTDOWN);
-			WR7146(P_ACON1, ACON1_BASE);
-
-			CloseDMAB(dev, &devpriv->RPSBuf, DMABUF_SIZE);
-			CloseDMAB(dev, &devpriv->ANABuf, DMABUF_SIZE);
-		}
-
-		if (dev->irq)
-			free_irq(dev->irq, dev);
-		if (devpriv->base_addr)
-			iounmap(devpriv->base_addr);
-		if (devpriv->pdev) {
-			if (devpriv->got_regions)
-				comedi_pci_disable(devpriv->pdev);
-			pci_dev_put(devpriv->pdev);
-		}
-	}
-}
-
 /*
  * this functions build the RPS program for hardware driven acquistion
  */
-void ResetADC(struct comedi_device *dev, uint8_t * ppl)
+static void ResetADC(struct comedi_device *dev, uint8_t *ppl)
 {
 	register uint32_t *pRPS;
 	uint32_t JmpAdrs;
@@ -1370,7 +1030,6 @@ void ResetADC(struct comedi_device *dev, uint8_t * ppl)
 	/*  Construct RPS program in RPSBuf DMA buffer */
 
 	if (cmd != NULL && cmd->scan_begin_src != TRIG_FOLLOW) {
-		DEBUG("ResetADC: scan_begin pause inserted\n");
 		/*  Wait for Start trigger. */
 		*pRPS++ = RPS_PAUSE | RPS_SIGADC;
 		*pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC;
@@ -1460,7 +1119,6 @@ void ResetADC(struct comedi_device *dev, uint8_t * ppl)
 		}
 
 		if (cmd != NULL && cmd->convert_src != TRIG_NOW) {
-			DEBUG("ResetADC: convert pause inserted\n");
 			/*  Wait for Start trigger. */
 			*pRPS++ = RPS_PAUSE | RPS_SIGADC;
 			*pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC;
@@ -1492,7 +1150,6 @@ void ResetADC(struct comedi_device *dev, uint8_t * ppl)
 			break;	/*  Exit poll list processing loop. */
 		}
 	}
-	DEBUG("ResetADC: ADC items %d\n", devpriv->AdcItems);
 
 	/* VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US.  Allow the
 	 * ADC to stabilize for 2 microseconds before starting the final
@@ -1529,7 +1186,6 @@ void ResetADC(struct comedi_device *dev, uint8_t * ppl)
 
 	/* invoke interrupt */
 	if (devpriv->ai_cmd_running == 1) {
-		DEBUG("ResetADC: insert irq in ADC RPS task\n");
 		*pRPS++ = RPS_IRQ;
 	}
 	/*  Restart RPS program at its beginning. */
@@ -1553,8 +1209,6 @@ static int s626_ai_insn_config(struct comedi_device *dev,
 /*   register uint8_t	i; */
 /*   register int32_t	*readaddr; */
 
-/*   DEBUG("as626_ai_rinsn: ai_rinsn enter\n");  */
-
 /*   Trigger ADC scan loop start by setting RPS Signal 0. */
 /*   MC_ENABLE( P_MC2, MC2_ADC_RPS ); */
 
@@ -1570,11 +1224,9 @@ static int s626_ai_insn_config(struct comedi_device *dev,
 /*  Convert ADC data to 16-bit integer values and copy to application buffer. */
 /*   for ( i = 0; i < devpriv->AdcItems; i++ ) { */
 /*     *data = s626_ai_reg_to_uint( *readaddr++ ); */
-/*     DEBUG("s626_ai_rinsn: data %d\n",*data); */
 /*     data++; */
 /*   } */
 
-/*   DEBUG("s626_ai_rinsn: ai_rinsn escape\n"); */
 /*   return i; */
 /* } */
 
@@ -1594,8 +1246,6 @@ static int s626_ai_insn_read(struct comedi_device *dev,
 	 * corresponding interrupt to be generated if enabled
 	 */
 
-	DEBUG("s626_ai_insn_read: entering\n");
-
 	/* Convert application's ADC specification into form
 	 *  appropriate for register programming.
 	 */
@@ -1672,8 +1322,6 @@ static int s626_ai_insn_read(struct comedi_device *dev,
 	if (n != 0)
 		data[n - 1] = s626_ai_reg_to_uint(RR7146(P_FB_BUFFER1));
 
-	DEBUG("s626_ai_insn_read: samples %d, data %d\n", n, data[n - 1]);
-
 	return n;
 }
 
@@ -1700,18 +1348,76 @@ static int s626_ai_inttrig(struct comedi_device *dev,
 	if (trignum != 0)
 		return -EINVAL;
 
-	DEBUG("s626_ai_inttrig: trigger adc start...");
-
 	/*  Start executing the RPS program. */
 	MC_ENABLE(P_MC1, MC1_ERPS1);
 
 	s->async->inttrig = NULL;
 
-	DEBUG(" done\n");
-
 	return 1;
 }
 
+/* This function doesn't require a particular form, this is just what
+ * happens to be used in some of the drivers.  It should convert ns
+ * nanoseconds to a counter value suitable for programming the device.
+ * Also, it should adjust ns so that it cooresponds to the actual time
+ * that the device will use. */
+static int s626_ns_to_timer(int *nanosec, int round_mode)
+{
+	int divider, base;
+
+	base = 500;		/* 2MHz internal clock */
+
+	switch (round_mode) {
+	case TRIG_ROUND_NEAREST:
+	default:
+		divider = (*nanosec + base / 2) / base;
+		break;
+	case TRIG_ROUND_DOWN:
+		divider = (*nanosec) / base;
+		break;
+	case TRIG_ROUND_UP:
+		divider = (*nanosec + base - 1) / base;
+		break;
+	}
+
+	*nanosec = base * divider;
+	return divider - 1;
+}
+
+static void s626_timer_load(struct comedi_device *dev, struct enc_private *k,
+			    int tick)
+{
+	uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) |	/*  Preload upon */
+	    /*  index. */
+	    (INDXSRC_SOFT << BF_INDXSRC) |	/*  Disable hardware index. */
+	    (CLKSRC_TIMER << BF_CLKSRC) |	/*  Operating mode is Timer. */
+	    (CLKPOL_POS << BF_CLKPOL) |	/*  Active high clock. */
+	    (CNTDIR_DOWN << BF_CLKPOL) |	/*  Count direction is Down. */
+	    (CLKMULT_1X << BF_CLKMULT) |	/*  Clock multiplier is 1x. */
+	    (CLKENAB_INDEX << BF_CLKENAB);
+	uint16_t valueSrclatch = LATCHSRC_A_INDXA;
+	/*   uint16_t enab=CLKENAB_ALWAYS; */
+
+	k->SetMode(dev, k, Setup, FALSE);
+
+	/*  Set the preload register */
+	Preload(dev, k, tick);
+
+	/*  Software index pulse forces the preload register to load */
+	/*  into the counter */
+	k->SetLoadTrig(dev, k, 0);
+	k->PulseIndex(dev, k);
+
+	/* set reload on counter overflow */
+	k->SetLoadTrig(dev, k, 1);
+
+	/* set interrupt on overflow */
+	k->SetIntSrc(dev, k, INTSRC_OVER);
+
+	SetLatchSource(dev, k, valueSrclatch);
+	/*   k->SetEnable(dev,k,(uint16_t)(enab != 0)); */
+}
+
 /*  TO COMPLETE  */
 static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
@@ -1721,8 +1427,6 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 	struct enc_private *k;
 	int tick;
 
-	DEBUG("s626_ai_cmd: entering command function\n");
-
 	if (devpriv->ai_cmd_running) {
 		printk(KERN_ERR "s626_ai_cmd: Another ai_cmd is running %d\n",
 		       dev->minor);
@@ -1742,12 +1446,8 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 	devpriv->ai_cmd_running = 0;
 
 	/*  test if cmd is valid */
-	if (cmd == NULL) {
-		DEBUG("s626_ai_cmd: NULL command\n");
+	if (cmd == NULL)
 		return -EINVAL;
-	} else {
-		DEBUG("s626_ai_cmd: command received!!!\n");
-	}
 
 	if (dev->irq == 0) {
 		comedi_error(dev,
@@ -1771,18 +1471,11 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 		/* load timer value and enable interrupt */
 		s626_timer_load(dev, k, tick);
 		k->SetEnable(dev, k, CLKENAB_ALWAYS);
-
-		DEBUG("s626_ai_cmd: scan trigger timer is set with value %d\n",
-		      tick);
-
 		break;
 	case TRIG_EXT:
 		/*  set the digital line and interrupt for scan trigger */
 		if (cmd->start_src != TRIG_EXT)
 			s626_dio_set_irq(dev, cmd->scan_begin_arg);
-
-		DEBUG("s626_ai_cmd: External scan trigger is set!!!\n");
-
 		break;
 	}
 
@@ -1798,19 +1491,12 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 		/* load timer value and enable interrupt */
 		s626_timer_load(dev, k, tick);
 		k->SetEnable(dev, k, CLKENAB_INDEX);
-
-		DEBUG
-		    ("s626_ai_cmd: convert trigger timer is set with value %d\n",
-		     tick);
 		break;
 	case TRIG_EXT:
 		/*  set the digital line and interrupt for convert trigger */
 		if (cmd->scan_begin_src != TRIG_EXT
 		    && cmd->start_src == TRIG_EXT)
 			s626_dio_set_irq(dev, cmd->convert_arg);
-
-		DEBUG("s626_ai_cmd: External convert trigger is set!!!\n");
-
 		break;
 	}
 
@@ -1837,15 +1523,12 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 		/*  Start executing the RPS program. */
 		MC_ENABLE(P_MC1, MC1_ERPS1);
 
-		DEBUG("s626_ai_cmd: ADC triggered\n");
 		s->async->inttrig = NULL;
 		break;
 	case TRIG_EXT:
 		/* configure DIO channel for acquisition trigger */
 		s626_dio_set_irq(dev, cmd->start_arg);
 
-		DEBUG("s626_ai_cmd: External start trigger is set!!!\n");
-
 		s->async->inttrig = NULL;
 		break;
 	case TRIG_INT:
@@ -1856,8 +1539,6 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 	/* enable interrupt */
 	writel(IRQ_GPIO3 | IRQ_RPS1, devpriv->base_addr + P_IER);
 
-	DEBUG("s626_ai_cmd: command function terminated\n");
-
 	return 0;
 }
 
@@ -2044,34 +1725,6 @@ static int s626_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 	return 0;
 }
 
-/* This function doesn't require a particular form, this is just what
- * happens to be used in some of the drivers.  It should convert ns
- * nanoseconds to a counter value suitable for programming the device.
- * Also, it should adjust ns so that it cooresponds to the actual time
- * that the device will use. */
-static int s626_ns_to_timer(int *nanosec, int round_mode)
-{
-	int divider, base;
-
-	base = 500;		/* 2MHz internal clock */
-
-	switch (round_mode) {
-	case TRIG_ROUND_NEAREST:
-	default:
-		divider = (*nanosec + base / 2) / base;
-		break;
-	case TRIG_ROUND_DOWN:
-		divider = (*nanosec) / base;
-		break;
-	case TRIG_ROUND_UP:
-		divider = (*nanosec + base - 1) / base;
-		break;
-	}
-
-	*nanosec = base * divider;
-	return divider - 1;
-}
-
 static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
 			 struct comedi_insn *insn, unsigned int *data)
 {
@@ -2128,7 +1781,6 @@ static void s626_dio_init(struct comedi_device *dev)
 		DEBIwrite(dev, diopriv->WRDOut, 0);	/*  Program all outputs */
 		/*  to inactive state. */
 	}
-	DEBUG("s626_dio_init: DIO initialized\n");
 }
 
 /* DIO devices are slightly special.  Although it is possible to
@@ -2141,18 +1793,6 @@ static int s626_dio_insn_bits(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
-
-	/* Length of data must be 2 (mask and new data, see below) */
-	if (insn->n == 0)
-		return 0;
-
-	if (insn->n != 2) {
-		printk
-		    ("comedi%d: s626: s626_dio_insn_bits(): Invalid instruction length\n",
-		     dev->minor);
-		return -EINVAL;
-	}
-
 	/*
 	 * The insn data consists of a mask in data[0] and the new data in
 	 * data[1]. The mask defines which bits we are concerning about.
@@ -2173,116 +1813,35 @@ static int s626_dio_insn_bits(struct comedi_device *dev,
 	}
 	data[1] = DEBIread(dev, diopriv->RDDIn);
 
-	return 2;
+	return insn->n;
 }
 
 static int s626_dio_insn_config(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
-{
-
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->
-		     io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
-		    COMEDI_INPUT;
-		return insn->n;
-		break;
-	case COMEDI_INPUT:
-		s->io_bits &= ~(1 << CR_CHAN(insn->chanspec));
-		break;
-	case COMEDI_OUTPUT:
-		s->io_bits |= 1 << CR_CHAN(insn->chanspec);
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
-	DEBIwrite(dev, diopriv->WRDOut, s->io_bits);
-
-	return 1;
-}
-
-static int s626_dio_set_irq(struct comedi_device *dev, unsigned int chan)
-{
-	unsigned int group;
-	unsigned int bitmask;
-	unsigned int status;
-
-	/* select dio bank */
-	group = chan / 16;
-	bitmask = 1 << (chan - (16 * group));
-	DEBUG("s626_dio_set_irq: enable interrupt on dio channel %d group %d\n",
-	      chan - (16 * group), group);
-
-	/* set channel to capture positive edge */
-	status = DEBIread(dev,
-			  ((struct dio_private *)(dev->subdevices + 2 +
-						  group)->private)->RDEdgSel);
-	DEBIwrite(dev,
-		  ((struct dio_private *)(dev->subdevices + 2 +
-					  group)->private)->WREdgSel,
-		  bitmask | status);
-
-	/* enable interrupt on selected channel */
-	status = DEBIread(dev,
-			  ((struct dio_private *)(dev->subdevices + 2 +
-						  group)->private)->RDIntSel);
-	DEBIwrite(dev,
-		  ((struct dio_private *)(dev->subdevices + 2 +
-					  group)->private)->WRIntSel,
-		  bitmask | status);
-
-	/* enable edge capture write command */
-	DEBIwrite(dev, LP_MISC1, MISC1_EDCAP);
-
-	/* enable edge capture on selected channel */
-	status = DEBIread(dev,
-			  ((struct dio_private *)(dev->subdevices + 2 +
-						  group)->private)->RDCapSel);
-	DEBIwrite(dev,
-		  ((struct dio_private *)(dev->subdevices + 2 +
-					  group)->private)->WRCapSel,
-		  bitmask | status);
-
-	return 0;
-}
-
-static int s626_dio_reset_irq(struct comedi_device *dev, unsigned int group,
-			      unsigned int mask)
-{
-	DEBUG
-	    ("s626_dio_reset_irq: disable  interrupt on dio channel %d group %d\n",
-	     mask, group);
-
-	/* disable edge capture write command */
-	DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP);
-
-	/* enable edge capture on selected channel */
-	DEBIwrite(dev,
-		  ((struct dio_private *)(dev->subdevices + 2 +
-					  group)->private)->WRCapSel, mask);
-
-	return 0;
-}
-
-static int s626_dio_clear_irq(struct comedi_device *dev)
-{
-	unsigned int group;
-
-	/* disable edge capture write command */
-	DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP);
-
-	for (group = 0; group < S626_DIO_BANKS; group++) {
-		/* clear pending events and interrupt */
-		DEBIwrite(dev,
-			  ((struct dio_private *)(dev->subdevices + 2 +
-						  group)->private)->WRCapSel,
-			  0xffff);
+{
+
+	switch (data[0]) {
+	case INSN_CONFIG_DIO_QUERY:
+		data[1] =
+		    (s->
+		     io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
+		    COMEDI_INPUT;
+		return insn->n;
+		break;
+	case COMEDI_INPUT:
+		s->io_bits &= ~(1 << CR_CHAN(insn->chanspec));
+		break;
+	case COMEDI_OUTPUT:
+		s->io_bits |= 1 << CR_CHAN(insn->chanspec);
+		break;
+	default:
+		return -EINVAL;
+		break;
 	}
+	DEBIwrite(dev, diopriv->WRDOut, s->io_bits);
 
-	return 0;
+	return 1;
 }
 
 /* Now this function initializes the value of the counter (data[0])
@@ -2306,8 +1865,6 @@ static int s626_enc_insn_config(struct comedi_device *dev,
 	uint16_t enab = CLKENAB_ALWAYS;
 	struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)];
 
-	DEBUG("s626_enc_insn_config: encoder config\n");
-
 	/*   (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */
 
 	k->SetMode(dev, k, Setup, TRUE);
@@ -2327,14 +1884,9 @@ static int s626_enc_insn_read(struct comedi_device *dev,
 	int n;
 	struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)];
 
-	DEBUG("s626_enc_insn_read: encoder read channel %d\n",
-	      CR_CHAN(insn->chanspec));
-
 	for (n = 0; n < insn->n; n++)
 		data[n] = ReadLatch(dev, k);
 
-	DEBUG("s626_enc_insn_read: encoder sample %d\n", data[n]);
-
 	return n;
 }
 
@@ -2345,9 +1897,6 @@ static int s626_enc_insn_write(struct comedi_device *dev,
 
 	struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)];
 
-	DEBUG("s626_enc_insn_write: encoder write channel %d\n",
-	      CR_CHAN(insn->chanspec));
-
 	/*  Set the preload register */
 	Preload(dev, k, data[0]);
 
@@ -2357,956 +1906,1073 @@ static int s626_enc_insn_write(struct comedi_device *dev,
 	k->PulseIndex(dev, k);
 	k->SetLoadTrig(dev, k, 2);
 
-	DEBUG("s626_enc_insn_write: End encoder write\n");
-
 	return 1;
 }
 
-static void s626_timer_load(struct comedi_device *dev, struct enc_private *k,
-			    int tick)
+static void WriteMISC2(struct comedi_device *dev, uint16_t NewImage)
 {
-	uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) |	/*  Preload upon */
-	    /*  index. */
-	    (INDXSRC_SOFT << BF_INDXSRC) |	/*  Disable hardware index. */
-	    (CLKSRC_TIMER << BF_CLKSRC) |	/*  Operating mode is Timer. */
-	    (CLKPOL_POS << BF_CLKPOL) |	/*  Active high clock. */
-	    (CNTDIR_DOWN << BF_CLKPOL) |	/*  Count direction is Down. */
-	    (CLKMULT_1X << BF_CLKMULT) |	/*  Clock multiplier is 1x. */
-	    (CLKENAB_INDEX << BF_CLKENAB);
-	uint16_t valueSrclatch = LATCHSRC_A_INDXA;
-	/*   uint16_t enab=CLKENAB_ALWAYS; */
-
-	k->SetMode(dev, k, Setup, FALSE);
-
-	/*  Set the preload register */
-	Preload(dev, k, tick);
-
-	/*  Software index pulse forces the preload register to load */
-	/*  into the counter */
-	k->SetLoadTrig(dev, k, 0);
-	k->PulseIndex(dev, k);
+	DEBIwrite(dev, LP_MISC1, MISC1_WENABLE);	/*  enab writes to */
+	/*  MISC2 register. */
+	DEBIwrite(dev, LP_WRMISC2, NewImage);	/*  Write new image to MISC2. */
+	DEBIwrite(dev, LP_MISC1, MISC1_WDISABLE);	/*  Disable writes to MISC2. */
+}
 
-	/* set reload on counter overflow */
-	k->SetLoadTrig(dev, k, 1);
+static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma,
+		      size_t bsize)
+{
+	void *vbptr;
+	dma_addr_t vpptr;
 
-	/* set interrupt on overflow */
-	k->SetIntSrc(dev, k, INTSRC_OVER);
+	if (pdma == NULL)
+		return;
+	/* find the matching allocation from the board struct */
 
-	SetLatchSource(dev, k, valueSrclatch);
-	/*   k->SetEnable(dev,k,(uint16_t)(enab != 0)); */
+	vbptr = pdma->LogicalBase;
+	vpptr = pdma->PhysicalBase;
+	if (vbptr) {
+		pci_free_consistent(devpriv->pdev, bsize, vbptr, vpptr);
+		pdma->LogicalBase = NULL;
+		pdma->PhysicalBase = 0;
+	}
 }
 
-/* ***********  DAC FUNCTIONS *********** */
-
-/*  Slot 0 base settings. */
-#define VECT0	(XSD2 | RSD3 | SIB_A2)
-/*  Slot 0 always shifts in  0xFF and store it to  FB_BUFFER2. */
-
-/*  TrimDac LogicalChan-to-PhysicalChan mapping table. */
-static uint8_t trimchan[] = { 10, 9, 8, 3, 2, 7, 6, 1, 0, 5, 4 };
+/* ******  PRIVATE COUNTER FUNCTIONS ****** */
 
-/*  TrimDac LogicalChan-to-EepromAdrs mapping table. */
-static uint8_t trimadrs[] = { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 };
+/*  Reset a counter's index and overflow event capture flags. */
 
-static void LoadTrimDACs(struct comedi_device *dev)
+static void ResetCapFlags_A(struct comedi_device *dev, struct enc_private *k)
 {
-	register uint8_t i;
-
-	/*  Copy TrimDac setpoint values from EEPROM to TrimDacs. */
-	for (i = 0; i < ARRAY_SIZE(trimchan); i++)
-		WriteTrimDAC(dev, i, I2Cread(dev, trimadrs[i]));
+	DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
+		    CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A);
 }
 
-static void WriteTrimDAC(struct comedi_device *dev, uint8_t LogicalChan,
-			 uint8_t DacData)
+static void ResetCapFlags_B(struct comedi_device *dev, struct enc_private *k)
 {
-	uint32_t chan;
-
-	/*  Save the new setpoint in case the application needs to read it back later. */
-	devpriv->TrimSetpoint[LogicalChan] = (uint8_t) DacData;
-
-	/*  Map logical channel number to physical channel number. */
-	chan = (uint32_t) trimchan[LogicalChan];
-
-	/* Set up TSL2 records for TrimDac write operation.  All slots shift
-	 * 0xFF in from pulled-up SD3 so that the end of the slot sequence
-	 * can be detected.
-	 */
-
-	SETVECT(2, XSD2 | XFIFO_1 | WS3);
-	/* Slot 2: Send high uint8_t to target TrimDac. */
-	SETVECT(3, XSD2 | XFIFO_0 | WS3);
-	/* Slot 3: Send low uint8_t to target TrimDac. */
-	SETVECT(4, XSD2 | XFIFO_3 | WS1);
-	/* Slot 4: Send NOP high uint8_t to DAC0 to keep clock running. */
-	SETVECT(5, XSD2 | XFIFO_2 | WS1 | EOS);
-	/* Slot 5: Send NOP low  uint8_t to DAC0. */
-
-	/* Construct and transmit target DAC's serial packet:
-	 * ( 0000 AAAA ), ( DDDD DDDD ),( 0x00 ),( 0x00 ) where A<3:0> is the
-	 * DAC channel's address, and D<7:0> is the DAC setpoint.  Append a
-	 * WORD value (that writes a channel 0 NOP command to a non-existent
-	 * main DAC channel) that serves to keep the clock running after the
-	 * packet has been sent to the target DAC.
-	 */
-
-	/*  Address the DAC channel within the trimdac device. */
-	SendDAC(dev, ((uint32_t) chan << 8)
-		| (uint32_t) DacData);	/*  Include DAC setpoint data. */
+	DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
+		    CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B);
 }
 
-/* **************  EEPROM ACCESS FUNCTIONS  ************** */
-/*  Read uint8_t from EEPROM. */
-
-static uint8_t I2Cread(struct comedi_device *dev, uint8_t addr)
-{
-	uint8_t rtnval;
-
-	/*  Send EEPROM target address. */
-	if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CW)
-			 /* Byte2 = I2C command: write to I2C EEPROM  device. */
-			 | I2C_B1(I2C_ATTRSTOP, addr)
-			 /* Byte1 = EEPROM internal target address. */
-			 | I2C_B0(I2C_ATTRNOP, 0))) {	/*  Byte0 = Not sent. */
-		/*  Abort function and declare error if handshake failed. */
-		DEBUG("I2Cread: error handshake I2Cread  a\n");
-		return 0;
-	}
-	/*  Execute EEPROM read. */
-	if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CR)
-
-			 /*  Byte2 = I2C */
-			 /*  command: read */
-			 /*  from I2C EEPROM */
-			 /*  device. */
-			 |I2C_B1(I2C_ATTRSTOP, 0)
-
-			 /*  Byte1 receives */
-			 /*  uint8_t from */
-			 /*  EEPROM. */
-			 |I2C_B0(I2C_ATTRNOP, 0))) {	/*  Byte0 = Not  sent. */
-
-		/*  Abort function and declare error if handshake failed. */
-		DEBUG("I2Cread: error handshake I2Cread b\n");
-		return 0;
-	}
-	/*  Return copy of EEPROM value. */
-	rtnval = (uint8_t) (RR7146(P_I2CCTRL) >> 16);
-	return rtnval;
-}
+/*  Return counter setup in a format (COUNTER_SETUP) that is consistent */
+/*  for both A and B counters. */
 
-static uint32_t I2Chandshake(struct comedi_device *dev, uint32_t val)
+static uint16_t GetMode_A(struct comedi_device *dev, struct enc_private *k)
 {
-	/*  Write I2C command to I2C Transfer Control shadow register. */
-	WR7146(P_I2CCTRL, val);
+	register uint16_t cra;
+	register uint16_t crb;
+	register uint16_t setup;
 
-	/*  Upload I2C shadow registers into working registers and wait for */
-	/*  upload confirmation. */
+	/*  Fetch CRA and CRB register images. */
+	cra = DEBIread(dev, k->MyCRA);
+	crb = DEBIread(dev, k->MyCRB);
 
-	MC_ENABLE(P_MC2, MC2_UPLD_IIC);
-	while (!MC_TEST(P_MC2, MC2_UPLD_IIC))
-		;
+	/*  Populate the standardized counter setup bit fields.  Note: */
+	/*  IndexSrc is restricted to ENC_X or IndxPol. */
+	setup = ((cra & STDMSK_LOADSRC)	/*  LoadSrc  = LoadSrcA. */
+		 |((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC)	/*  LatchSrc = LatchSrcA. */
+		 |((cra << (STDBIT_INTSRC - CRABIT_INTSRC_A)) & STDMSK_INTSRC)	/*  IntSrc   = IntSrcA. */
+		 |((cra << (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1))) & STDMSK_INDXSRC)	/*  IndxSrc  = IndxSrcA<1>. */
+		 |((cra >> (CRABIT_INDXPOL_A - STDBIT_INDXPOL)) & STDMSK_INDXPOL)	/*  IndxPol  = IndxPolA. */
+		 |((crb >> (CRBBIT_CLKENAB_A - STDBIT_CLKENAB)) & STDMSK_CLKENAB));	/*  ClkEnab  = ClkEnabA. */
 
-	/*  Wait until I2C bus transfer is finished or an error occurs. */
-	while ((RR7146(P_I2CCTRL) & (I2C_BUSY | I2C_ERR)) == I2C_BUSY)
-		;
+	/*  Adjust mode-dependent parameters. */
+	if (cra & (2 << CRABIT_CLKSRC_A))	/*  If Timer mode (ClkSrcA<1> == 1): */
+		setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC)	/*    Indicate Timer mode. */
+			  |((cra << (STDBIT_CLKPOL - CRABIT_CLKSRC_A)) & STDMSK_CLKPOL)	/*    Set ClkPol to indicate count direction (ClkSrcA<0>). */
+			  |(MULT_X1 << STDBIT_CLKMULT));	/*    ClkMult must be 1x in Timer mode. */
 
-	/*  Return non-zero if I2C error occurred. */
-	return RR7146(P_I2CCTRL) & I2C_ERR;
+	else			/*  If Counter mode (ClkSrcA<1> == 0): */
+		setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC)	/*    Indicate Counter mode. */
+			  |((cra >> (CRABIT_CLKPOL_A - STDBIT_CLKPOL)) & STDMSK_CLKPOL)	/*    Pass through ClkPol. */
+			  |(((cra & CRAMSK_CLKMULT_A) == (MULT_X0 << CRABIT_CLKMULT_A)) ?	/*    Force ClkMult to 1x if not legal, else pass through. */
+			    (MULT_X1 << STDBIT_CLKMULT) :
+			    ((cra >> (CRABIT_CLKMULT_A -
+				      STDBIT_CLKMULT)) & STDMSK_CLKMULT)));
 
+	/*  Return adjusted counter setup. */
+	return setup;
 }
 
-/*  Private helper function: Write setpoint to an application DAC channel. */
-
-static void SetDAC(struct comedi_device *dev, uint16_t chan, short dacdata)
+static uint16_t GetMode_B(struct comedi_device *dev, struct enc_private *k)
 {
-	register uint16_t signmask;
-	register uint32_t WSImage;
-
-	/*  Adjust DAC data polarity and set up Polarity Control Register */
-	/*  image. */
-	signmask = 1 << chan;
-	if (dacdata < 0) {
-		dacdata = -dacdata;
-		devpriv->Dacpol |= signmask;
-	} else
-		devpriv->Dacpol &= ~signmask;
+	register uint16_t cra;
+	register uint16_t crb;
+	register uint16_t setup;
 
-	/*  Limit DAC setpoint value to valid range. */
-	if ((uint16_t) dacdata > 0x1FFF)
-		dacdata = 0x1FFF;
+	/*  Fetch CRA and CRB register images. */
+	cra = DEBIread(dev, k->MyCRA);
+	crb = DEBIread(dev, k->MyCRB);
 
-	/* Set up TSL2 records (aka "vectors") for DAC update.  Vectors V2
-	 * and V3 transmit the setpoint to the target DAC.  V4 and V5 send
-	 * data to a non-existent TrimDac channel just to keep the clock
-	 * running after sending data to the target DAC.  This is necessary
-	 * to eliminate the clock glitch that would otherwise occur at the
-	 * end of the target DAC's serial data stream.  When the sequence
-	 * restarts at V0 (after executing V5), the gate array automatically
-	 * disables gating for the DAC clock and all DAC chip selects.
-	 */
+	/*  Populate the standardized counter setup bit fields.  Note: */
+	/*  IndexSrc is restricted to ENC_X or IndxPol. */
+	setup = (((crb << (STDBIT_INTSRC - CRBBIT_INTSRC_B)) & STDMSK_INTSRC)	/*  IntSrc   = IntSrcB. */
+		 |((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC)	/*  LatchSrc = LatchSrcB. */
+		 |((crb << (STDBIT_LOADSRC - CRBBIT_LOADSRC_B)) & STDMSK_LOADSRC)	/*  LoadSrc  = LoadSrcB. */
+		 |((crb << (STDBIT_INDXPOL - CRBBIT_INDXPOL_B)) & STDMSK_INDXPOL)	/*  IndxPol  = IndxPolB. */
+		 |((crb >> (CRBBIT_CLKENAB_B - STDBIT_CLKENAB)) & STDMSK_CLKENAB)	/*  ClkEnab  = ClkEnabB. */
+		 |((cra >> ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC)) & STDMSK_INDXSRC));	/*  IndxSrc  = IndxSrcB<1>. */
 
-	WSImage = (chan & 2) ? WS1 : WS2;
-	/* Choose DAC chip select to be asserted. */
-	SETVECT(2, XSD2 | XFIFO_1 | WSImage);
-	/* Slot 2: Transmit high data byte to target DAC. */
-	SETVECT(3, XSD2 | XFIFO_0 | WSImage);
-	/* Slot 3: Transmit low data byte to target DAC. */
-	SETVECT(4, XSD2 | XFIFO_3 | WS3);
-	/* Slot 4: Transmit to non-existent TrimDac channel to keep clock */
-	SETVECT(5, XSD2 | XFIFO_2 | WS3 | EOS);
-	/* Slot 5: running after writing target DAC's low data byte. */
+	/*  Adjust mode-dependent parameters. */
+	if ((crb & CRBMSK_CLKMULT_B) == (MULT_X0 << CRBBIT_CLKMULT_B))	/*  If Extender mode (ClkMultB == MULT_X0): */
+		setup |= ((CLKSRC_EXTENDER << STDBIT_CLKSRC)	/*    Indicate Extender mode. */
+			  |(MULT_X1 << STDBIT_CLKMULT)	/*    Indicate multiplier is 1x. */
+			  |((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL));	/*    Set ClkPol equal to Timer count direction (ClkSrcB<0>). */
 
-	/*  Construct and transmit target DAC's serial packet:
-	 * ( A10D DDDD ),( DDDD DDDD ),( 0x0F ),( 0x00 ) where A is chan<0>,
-	 * and D<12:0> is the DAC setpoint.  Append a WORD value (that writes
-	 * to a  non-existent TrimDac channel) that serves to keep the clock
-	 * running after the packet has been sent to the target DAC.
-	 */
-	SendDAC(dev, 0x0F000000
-		/* Continue clock after target DAC data (write to non-existent trimdac). */
-		| 0x00004000
-		/* Address the two main dual-DAC devices (TSL's chip select enables
-		 * target device). */
-		| ((uint32_t) (chan & 1) << 15)
-		/*  Address the DAC channel within the  device. */
-		| (uint32_t) dacdata);	/*  Include DAC setpoint data. */
+	else if (cra & (2 << CRABIT_CLKSRC_B))	/*  If Timer mode (ClkSrcB<1> == 1): */
+		setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC)	/*    Indicate Timer mode. */
+			  |(MULT_X1 << STDBIT_CLKMULT)	/*    Indicate multiplier is 1x. */
+			  |((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL));	/*    Set ClkPol equal to Timer count direction (ClkSrcB<0>). */
+
+	else			/*  If Counter mode (ClkSrcB<1> == 0): */
+		setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC)	/*    Indicate Timer mode. */
+			  |((crb >> (CRBBIT_CLKMULT_B - STDBIT_CLKMULT)) & STDMSK_CLKMULT)	/*    Clock multiplier is passed through. */
+			  |((crb << (STDBIT_CLKPOL - CRBBIT_CLKPOL_B)) & STDMSK_CLKPOL));	/*    Clock polarity is passed through. */
 
+	/*  Return adjusted counter setup. */
+	return setup;
 }
 
-/* Private helper function: Transmit serial data to DAC via Audio
- * channel 2.  Assumes: (1) TSL2 slot records initialized, and (2)
- * Dacpol contains valid target image.
+/*
+ * Set the operating mode for the specified counter.  The setup
+ * parameter is treated as a COUNTER_SETUP data type.  The following
+ * parameters are programmable (all other parms are ignored): ClkMult,
+ * ClkPol, ClkEnab, IndexSrc, IndexPol, LoadSrc.
  */
 
-static void SendDAC(struct comedi_device *dev, uint32_t val)
+static void SetMode_A(struct comedi_device *dev, struct enc_private *k,
+		      uint16_t Setup, uint16_t DisableIntSrc)
 {
+	register uint16_t cra;
+	register uint16_t crb;
+	register uint16_t setup = Setup;	/*  Cache the Standard Setup. */
 
-	/* START THE SERIAL CLOCK RUNNING ------------- */
+	/*  Initialize CRA and CRB images. */
+	cra = ((setup & CRAMSK_LOADSRC_A)	/*  Preload trigger is passed through. */
+	       |((setup & STDMSK_INDXSRC) >> (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1))));	/*  IndexSrc is restricted to ENC_X or IndxPol. */
 
-	/* Assert DAC polarity control and enable gating of DAC serial clock
-	 * and audio bit stream signals.  At this point in time we must be
-	 * assured of being in time slot 0.  If we are not in slot 0, the
-	 * serial clock and audio stream signals will be disabled; this is
-	 * because the following DEBIwrite statement (which enables signals
-	 * to be passed through the gate array) would execute before the
-	 * trailing edge of WS1/WS3 (which turns off the signals), thus
-	 * causing the signals to be inactive during the DAC write.
-	 */
-	DEBIwrite(dev, LP_DACPOL, devpriv->Dacpol);
+	crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A	/*  Reset any pending CounterA event captures. */
+	       | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_A - STDBIT_CLKENAB)));	/*  Clock enable is passed through. */
 
-	/* TRANSFER OUTPUT DWORD VALUE INTO A2'S OUTPUT FIFO ---------------- */
+	/*  Force IntSrc to Disabled if DisableIntSrc is asserted. */
+	if (!DisableIntSrc)
+		cra |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC -
+						    CRABIT_INTSRC_A));
 
-	/* Copy DAC setpoint value to DAC's output DMA buffer. */
+	/*  Populate all mode-dependent attributes of CRA & CRB images. */
+	switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) {
+	case CLKSRC_EXTENDER:	/*  Extender Mode: Force to Timer mode */
+		/*  (Extender valid only for B counters). */
 
-	/* WR7146( (uint32_t)devpriv->pDacWBuf, val ); */
-	*devpriv->pDacWBuf = val;
+	case CLKSRC_TIMER:	/*  Timer Mode: */
+		cra |= ((2 << CRABIT_CLKSRC_A)	/*    ClkSrcA<1> selects system clock */
+			|((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRABIT_CLKSRC_A))	/*      with count direction (ClkSrcA<0>) obtained from ClkPol. */
+			|(1 << CRABIT_CLKPOL_A)	/*    ClkPolA behaves as always-on clock enable. */
+			|(MULT_X1 << CRABIT_CLKMULT_A));	/*    ClkMult must be 1x. */
+		break;
 
-	/* enab the output DMA transfer.  This will cause the DMAC to copy
-	 * the DAC's data value to A2's output FIFO.  The DMA transfer will
-	 * then immediately terminate because the protection address is
-	 * reached upon transfer of the first DWORD value.
-	 */
-	MC_ENABLE(P_MC1, MC1_A2OUT);
+	default:		/*  Counter Mode: */
+		cra |= (CLKSRC_COUNTER	/*    Select ENC_C and ENC_D as clock/direction inputs. */
+			| ((setup & STDMSK_CLKPOL) << (CRABIT_CLKPOL_A - STDBIT_CLKPOL))	/*    Clock polarity is passed through. */
+			|(((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ?	/*    Force multiplier to x1 if not legal, otherwise pass through. */
+			  (MULT_X1 << CRABIT_CLKMULT_A) :
+			  ((setup & STDMSK_CLKMULT) << (CRABIT_CLKMULT_A -
+							STDBIT_CLKMULT))));
+	}
 
-	/*  While the DMA transfer is executing ... */
+	/*  Force positive index polarity if IndxSrc is software-driven only, */
+	/*  otherwise pass it through. */
+	if (~setup & STDMSK_INDXSRC)
+		cra |= ((setup & STDMSK_INDXPOL) << (CRABIT_INDXPOL_A -
+						     STDBIT_INDXPOL));
 
-	/* Reset Audio2 output FIFO's underflow flag (along with any other
-	 * FIFO underflow/overflow flags).  When set, this flag will
-	 * indicate that we have emerged from slot 0.
-	 */
-	WR7146(P_ISR, ISR_AFOU);
+	/*  If IntSrc has been forced to Disabled, update the MISC2 interrupt */
+	/*  enable mask to indicate the counter interrupt is disabled. */
+	if (DisableIntSrc)
+		devpriv->CounterIntEnabs &= ~k->MyEventBits[3];
 
-	/* Wait for the DMA transfer to finish so that there will be data
-	 * available in the FIFO when time slot 1 tries to transfer a DWORD
-	 * from the FIFO to the output buffer register.  We test for DMA
-	 * Done by polling the DMAC enable flag; this flag is automatically
-	 * cleared when the transfer has finished.
-	 */
-	while ((RR7146(P_MC1) & MC1_A2OUT) != 0)
-		;
+	/*  While retaining CounterB and LatchSrc configurations, program the */
+	/*  new counter operating mode. */
+	DEBIreplace(dev, k->MyCRA, CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B, cra);
+	DEBIreplace(dev, k->MyCRB,
+		    (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)), crb);
+}
 
-	/* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */
+static void SetMode_B(struct comedi_device *dev, struct enc_private *k,
+		      uint16_t Setup, uint16_t DisableIntSrc)
+{
+	register uint16_t cra;
+	register uint16_t crb;
+	register uint16_t setup = Setup;	/*  Cache the Standard Setup. */
 
-	/* FIFO data is now available, so we enable execution of time slots
-	 * 1 and higher by clearing the EOS flag in slot 0.  Note that SD3
-	 * will be shifted in and stored in FB_BUFFER2 for end-of-slot-list
-	 * detection.
-	 */
-	SETVECT(0, XSD2 | RSD3 | SIB_A2);
+	/*  Initialize CRA and CRB images. */
+	cra = ((setup & STDMSK_INDXSRC) << ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC));	/*  IndexSrc field is restricted to ENC_X or IndxPol. */
 
-	/* Wait for slot 1 to execute to ensure that the Packet will be
-	 * transmitted.  This is detected by polling the Audio2 output FIFO
-	 * underflow flag, which will be set when slot 1 execution has
-	 * finished transferring the DAC's data DWORD from the output FIFO
-	 * to the output buffer register.
-	 */
-	while ((RR7146(P_SSR) & SSR_AF2_OUT) == 0)
-		;
+	crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B	/*  Reset event captures and disable interrupts. */
+	       | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_B - STDBIT_CLKENAB))	/*  Clock enable is passed through. */
+	       |((setup & STDMSK_LOADSRC) >> (STDBIT_LOADSRC - CRBBIT_LOADSRC_B)));	/*  Preload trigger source is passed through. */
 
-	/* Set up to trap execution at slot 0 when the TSL sequencer cycles
-	 * back to slot 0 after executing the EOS in slot 5.  Also,
-	 * simultaneously shift out and in the 0x00 that is ALWAYS the value
-	 * stored in the last byte to be shifted out of the FIFO's DWORD
-	 * buffer register.
-	 */
-	SETVECT(0, XSD2 | XFIFO_2 | RSD2 | SIB_A2 | EOS);
+	/*  Force IntSrc to Disabled if DisableIntSrc is asserted. */
+	if (!DisableIntSrc)
+		crb |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC -
+						    CRBBIT_INTSRC_B));
 
-	/* WAIT FOR THE TRANSACTION TO FINISH ----------------------- */
+	/*  Populate all mode-dependent attributes of CRA & CRB images. */
+	switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) {
+	case CLKSRC_TIMER:	/*  Timer Mode: */
+		cra |= ((2 << CRABIT_CLKSRC_B)	/*    ClkSrcB<1> selects system clock */
+			|((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL)));	/*      with direction (ClkSrcB<0>) obtained from ClkPol. */
+		crb |= ((1 << CRBBIT_CLKPOL_B)	/*    ClkPolB behaves as always-on clock enable. */
+			|(MULT_X1 << CRBBIT_CLKMULT_B));	/*    ClkMultB must be 1x. */
+		break;
 
-	/* Wait for the TSL to finish executing all time slots before
-	 * exiting this function.  We must do this so that the next DAC
-	 * write doesn't start, thereby enabling clock/chip select signals:
-	 *
-	 * 1. Before the TSL sequence cycles back to slot 0, which disables
-	 *    the clock/cs signal gating and traps slot // list execution.
-	 *    we have not yet finished slot 5 then the clock/cs signals are
-	 *    still gated and we have not finished transmitting the stream.
-	 *
-	 * 2. While slots 2-5 are executing due to a late slot 0 trap.  In
-	 *    this case, the slot sequence is currently repeating, but with
-	 *    clock/cs signals disabled.  We must wait for slot 0 to trap
-	 *    execution before setting up the next DAC setpoint DMA transfer
-	 *    and enabling the clock/cs signals.  To detect the end of slot 5,
-	 *    we test for the FB_BUFFER2 MSB contents to be equal to 0xFF.  If
-	 *    the TSL has not yet finished executing slot 5 ...
-	 */
-	if ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0) {
-		/* The trap was set on time and we are still executing somewhere
-		 * in slots 2-5, so we now wait for slot 0 to execute and trap
-		 * TSL execution.  This is detected when FB_BUFFER2 MSB changes
-		 * from 0xFF to 0x00, which slot 0 causes to happen by shifting
-		 * out/in on SD2 the 0x00 that is always referenced by slot 5.
-		 */
-		while ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0)
-			;
+	case CLKSRC_EXTENDER:	/*  Extender Mode: */
+		cra |= ((2 << CRABIT_CLKSRC_B)	/*    ClkSrcB source is OverflowA (same as "timer") */
+			|((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL)));	/*      with direction obtained from ClkPol. */
+		crb |= ((1 << CRBBIT_CLKPOL_B)	/*    ClkPolB controls IndexB -- always set to active. */
+			|(MULT_X0 << CRBBIT_CLKMULT_B));	/*    ClkMultB selects OverflowA as the clock source. */
+		break;
+
+	default:		/*  Counter Mode: */
+		cra |= (CLKSRC_COUNTER << CRABIT_CLKSRC_B);	/*    Select ENC_C and ENC_D as clock/direction inputs. */
+		crb |= (((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRBBIT_CLKPOL_B))	/*    ClkPol is passed through. */
+			|(((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ?	/*    Force ClkMult to x1 if not legal, otherwise pass through. */
+			  (MULT_X1 << CRBBIT_CLKMULT_B) :
+			  ((setup & STDMSK_CLKMULT) << (CRBBIT_CLKMULT_B -
+							STDBIT_CLKMULT))));
 	}
-	/* Either (1) we were too late setting the slot 0 trap; the TSL
-	 * sequencer restarted slot 0 before we could set the EOS trap flag,
-	 * or (2) we were not late and execution is now trapped at slot 0.
-	 * In either case, we must now change slot 0 so that it will store
-	 * value 0xFF (instead of 0x00) to FB_BUFFER2 next time it executes.
-	 * In order to do this, we reprogram slot 0 so that it will shift in
-	 * SD3, which is driven only by a pull-up resistor.
-	 */
-	SETVECT(0, RSD3 | SIB_A2 | EOS);
 
-	/* Wait for slot 0 to execute, at which time the TSL is setup for
-	 * the next DAC write.  This is detected when FB_BUFFER2 MSB changes
-	 * from 0x00 to 0xFF.
-	 */
-	while ((RR7146(P_FB_BUFFER2) & 0xFF000000) == 0)
-		;
+	/*  Force positive index polarity if IndxSrc is software-driven only, */
+	/*  otherwise pass it through. */
+	if (~setup & STDMSK_INDXSRC)
+		crb |= ((setup & STDMSK_INDXPOL) >> (STDBIT_INDXPOL -
+						     CRBBIT_INDXPOL_B));
+
+	/*  If IntSrc has been forced to Disabled, update the MISC2 interrupt */
+	/*  enable mask to indicate the counter interrupt is disabled. */
+	if (DisableIntSrc)
+		devpriv->CounterIntEnabs &= ~k->MyEventBits[3];
+
+	/*  While retaining CounterA and LatchSrc configurations, program the */
+	/*  new counter operating mode. */
+	DEBIreplace(dev, k->MyCRA,
+		    (uint16_t) (~(CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B)), cra);
+	DEBIreplace(dev, k->MyCRB, CRBMSK_CLKENAB_A | CRBMSK_LATCHSRC, crb);
+}
+
+/*  Return/set a counter's enable.  enab: 0=always enabled, 1=enabled by index. */
+
+static void SetEnable_A(struct comedi_device *dev, struct enc_private *k,
+			uint16_t enab)
+{
+	DEBIreplace(dev, k->MyCRB,
+		    (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)),
+		    (uint16_t) (enab << CRBBIT_CLKENAB_A));
 }
 
-static void WriteMISC2(struct comedi_device *dev, uint16_t NewImage)
+static void SetEnable_B(struct comedi_device *dev, struct enc_private *k,
+			uint16_t enab)
 {
-	DEBIwrite(dev, LP_MISC1, MISC1_WENABLE);	/*  enab writes to */
-	/*  MISC2 register. */
-	DEBIwrite(dev, LP_WRMISC2, NewImage);	/*  Write new image to MISC2. */
-	DEBIwrite(dev, LP_MISC1, MISC1_WDISABLE);	/*  Disable writes to MISC2. */
+	DEBIreplace(dev, k->MyCRB,
+		    (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_B)),
+		    (uint16_t) (enab << CRBBIT_CLKENAB_B));
 }
 
-/*  Initialize the DEBI interface for all transfers. */
-
-static uint16_t DEBIread(struct comedi_device *dev, uint16_t addr)
+static uint16_t GetEnable_A(struct comedi_device *dev, struct enc_private *k)
 {
-	uint16_t retval;
+	return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_A) & 1;
+}
 
-	/*  Set up DEBI control register value in shadow RAM. */
-	WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr);
+static uint16_t GetEnable_B(struct comedi_device *dev, struct enc_private *k)
+{
+	return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_B) & 1;
+}
 
-	/*  Execute the DEBI transfer. */
-	DEBItransfer(dev);
+/*
+ * static uint16_t GetLatchSource(struct comedi_device *dev, struct enc_private *k )
+ * {
+ *	return ( DEBIread( dev, k->MyCRB) >> CRBBIT_LATCHSRC ) & 3;
+ * }
+ */
 
-	/*  Fetch target register value. */
-	retval = (uint16_t) RR7146(P_DEBIAD);
+/*
+ * Return/set the event that will trigger transfer of the preload
+ * register into the counter.  0=ThisCntr_Index, 1=ThisCntr_Overflow,
+ * 2=OverflowA (B counters only), 3=disabled.
+ */
 
-	/*  Return register value. */
-	return retval;
+static void SetLoadTrig_A(struct comedi_device *dev, struct enc_private *k,
+			  uint16_t Trig)
+{
+	DEBIreplace(dev, k->MyCRA, (uint16_t) (~CRAMSK_LOADSRC_A),
+		    (uint16_t) (Trig << CRABIT_LOADSRC_A));
 }
 
-/*  Execute a DEBI transfer.  This must be called from within a */
-/*  critical section. */
-static void DEBItransfer(struct comedi_device *dev)
+static void SetLoadTrig_B(struct comedi_device *dev, struct enc_private *k,
+			  uint16_t Trig)
 {
-	/*  Initiate upload of shadow RAM to DEBI control register. */
-	MC_ENABLE(P_MC2, MC2_UPLD_DEBI);
+	DEBIreplace(dev, k->MyCRB,
+		    (uint16_t) (~(CRBMSK_LOADSRC_B | CRBMSK_INTCTRL)),
+		    (uint16_t) (Trig << CRBBIT_LOADSRC_B));
+}
 
-	/*  Wait for completion of upload from shadow RAM to DEBI control */
-	/*  register. */
-	while (!MC_TEST(P_MC2, MC2_UPLD_DEBI))
-		;
+static uint16_t GetLoadTrig_A(struct comedi_device *dev, struct enc_private *k)
+{
+	return (DEBIread(dev, k->MyCRA) >> CRABIT_LOADSRC_A) & 3;
+}
 
-	/*  Wait until DEBI transfer is done. */
-	while (RR7146(P_PSR) & PSR_DEBI_S)
-		;
+static uint16_t GetLoadTrig_B(struct comedi_device *dev, struct enc_private *k)
+{
+	return (DEBIread(dev, k->MyCRB) >> CRBBIT_LOADSRC_B) & 3;
 }
 
-/*  Write a value to a gate array register. */
-static void DEBIwrite(struct comedi_device *dev, uint16_t addr, uint16_t wdata)
+/* Return/set counter interrupt source and clear any captured
+ * index/overflow events.  IntSource: 0=Disabled, 1=OverflowOnly,
+ * 2=IndexOnly, 3=IndexAndOverflow.
+ */
+
+static void SetIntSrc_A(struct comedi_device *dev, struct enc_private *k,
+			uint16_t IntSource)
 {
+	/*  Reset any pending counter overflow or index captures. */
+	DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
+		    CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A);
 
-	/*  Set up DEBI control register value in shadow RAM. */
-	WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr);
-	WR7146(P_DEBIAD, wdata);
+	/*  Program counter interrupt source. */
+	DEBIreplace(dev, k->MyCRA, ~CRAMSK_INTSRC_A,
+		    (uint16_t) (IntSource << CRABIT_INTSRC_A));
 
-	/*  Execute the DEBI transfer. */
-	DEBItransfer(dev);
+	/*  Update MISC2 interrupt enable mask. */
+	devpriv->CounterIntEnabs =
+	    (devpriv->CounterIntEnabs & ~k->
+	     MyEventBits[3]) | k->MyEventBits[IntSource];
 }
 
-/* Replace the specified bits in a gate array register.  Imports: mask
- * specifies bits that are to be preserved, wdata is new value to be
- * or'd with the masked original.
- */
-static void DEBIreplace(struct comedi_device *dev, uint16_t addr, uint16_t mask,
-			uint16_t wdata)
+static void SetIntSrc_B(struct comedi_device *dev, struct enc_private *k,
+			uint16_t IntSource)
 {
+	uint16_t crb;
 
-	/*  Copy target gate array register into P_DEBIAD register. */
-	WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr);
-	/* Set up DEBI control reg value in shadow RAM. */
-	DEBItransfer(dev);	/*  Execute the DEBI Read transfer. */
+	/*  Cache writeable CRB register image. */
+	crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL;
 
-	/*  Write back the modified image. */
-	WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr);
-	/* Set up DEBI control reg value in shadow  RAM. */
+	/*  Reset any pending counter overflow or index captures. */
+	DEBIwrite(dev, k->MyCRB,
+		  (uint16_t) (crb | CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B));
 
-	WR7146(P_DEBIAD, wdata | ((uint16_t) RR7146(P_DEBIAD) & mask));
-	/* Modify the register image. */
-	DEBItransfer(dev);	/*  Execute the DEBI Write transfer. */
+	/*  Program counter interrupt source. */
+	DEBIwrite(dev, k->MyCRB,
+		  (uint16_t) ((crb & ~CRBMSK_INTSRC_B) | (IntSource <<
+							  CRBBIT_INTSRC_B)));
+
+	/*  Update MISC2 interrupt enable mask. */
+	devpriv->CounterIntEnabs =
+	    (devpriv->CounterIntEnabs & ~k->
+	     MyEventBits[3]) | k->MyEventBits[IntSource];
 }
 
-static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma,
-		      size_t bsize)
+static uint16_t GetIntSrc_A(struct comedi_device *dev, struct enc_private *k)
 {
-	void *vbptr;
-	dma_addr_t vpptr;
+	return (DEBIread(dev, k->MyCRA) >> CRABIT_INTSRC_A) & 3;
+}
 
-	DEBUG("CloseDMAB: Entering S626DRV_CloseDMAB():\n");
-	if (pdma == NULL)
-		return;
-	/* find the matching allocation from the board struct */
+static uint16_t GetIntSrc_B(struct comedi_device *dev, struct enc_private *k)
+{
+	return (DEBIread(dev, k->MyCRB) >> CRBBIT_INTSRC_B) & 3;
+}
 
-	vbptr = pdma->LogicalBase;
-	vpptr = pdma->PhysicalBase;
-	if (vbptr) {
-		pci_free_consistent(devpriv->pdev, bsize, vbptr, vpptr);
-		pdma->LogicalBase = 0;
-		pdma->PhysicalBase = 0;
+/*  Return/set the clock multiplier. */
 
-		DEBUG("CloseDMAB(): Logical=%p, bsize=%d, Physical=0x%x\n",
-		      vbptr, bsize, (uint32_t) vpptr);
-	}
+/* static void SetClkMult(struct comedi_device *dev, struct enc_private *k, uint16_t value )  */
+/* { */
+/*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKMULT ) | ( value << STDBIT_CLKMULT ) ), FALSE ); */
+/* } */
+
+/* static uint16_t GetClkMult(struct comedi_device *dev, struct enc_private *k )  */
+/* { */
+/*   return ( k->GetMode(dev, k ) >> STDBIT_CLKMULT ) & 3; */
+/* } */
+
+/* Return/set the clock polarity. */
+
+/* static void SetClkPol( struct comedi_device *dev,struct enc_private *k, uint16_t value )  */
+/* { */
+/*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKPOL ) | ( value << STDBIT_CLKPOL ) ), FALSE ); */
+/* } */
+
+/* static uint16_t GetClkPol(struct comedi_device *dev, struct enc_private *k )  */
+/* { */
+/*   return ( k->GetMode(dev, k ) >> STDBIT_CLKPOL ) & 1; */
+/* } */
+
+/* Return/set the clock source.  */
+
+/* static void SetClkSrc( struct comedi_device *dev,struct enc_private *k, uint16_t value )  */
+/* { */
+/*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKSRC ) | ( value << STDBIT_CLKSRC ) ), FALSE ); */
+/* } */
+
+/* static uint16_t GetClkSrc( struct comedi_device *dev,struct enc_private *k )  */
+/* { */
+/*   return ( k->GetMode(dev, k ) >> STDBIT_CLKSRC ) & 3; */
+/* } */
+
+/* Return/set the index polarity. */
+
+/* static void SetIndexPol(struct comedi_device *dev, struct enc_private *k, uint16_t value )  */
+/* { */
+/*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXPOL ) | ( (value != 0) << STDBIT_INDXPOL ) ), FALSE ); */
+/* } */
+
+/* static uint16_t GetIndexPol(struct comedi_device *dev, struct enc_private *k )  */
+/* { */
+/*   return ( k->GetMode(dev, k ) >> STDBIT_INDXPOL ) & 1; */
+/* } */
+
+/*  Return/set the index source. */
+
+/* static void SetIndexSrc(struct comedi_device *dev, struct enc_private *k, uint16_t value )  */
+/* { */
+/*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXSRC ) | ( (value != 0) << STDBIT_INDXSRC ) ), FALSE ); */
+/* } */
+
+/* static uint16_t GetIndexSrc(struct comedi_device *dev, struct enc_private *k )  */
+/* { */
+/*   return ( k->GetMode(dev, k ) >> STDBIT_INDXSRC ) & 1; */
+/* } */
+
+/*  Generate an index pulse. */
+
+static void PulseIndex_A(struct comedi_device *dev, struct enc_private *k)
+{
+	register uint16_t cra;
+
+	cra = DEBIread(dev, k->MyCRA);	/*  Pulse index. */
+	DEBIwrite(dev, k->MyCRA, (uint16_t) (cra ^ CRAMSK_INDXPOL_A));
+	DEBIwrite(dev, k->MyCRA, cra);
 }
 
-/* ******  COUNTER FUNCTIONS  ******* */
-/* All counter functions address a specific counter by means of the
- * "Counter" argument, which is a logical counter number.  The Counter
- * argument may have any of the following legal values: 0=0A, 1=1A,
- * 2=2A, 3=0B, 4=1B, 5=2B.
- */
+static void PulseIndex_B(struct comedi_device *dev, struct enc_private *k)
+{
+	register uint16_t crb;
 
-/* Forward declarations for functions that are common to both A and B counters: */
+	crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL;	/*  Pulse index. */
+	DEBIwrite(dev, k->MyCRB, (uint16_t) (crb ^ CRBMSK_INDXPOL_B));
+	DEBIwrite(dev, k->MyCRB, crb);
+}
 
-/* ******  PRIVATE COUNTER FUNCTIONS ****** */
+static struct enc_private enc_private_data[] = {
+	{
+		.GetEnable	= GetEnable_A,
+		.GetIntSrc	= GetIntSrc_A,
+		.GetLoadTrig	= GetLoadTrig_A,
+		.GetMode	= GetMode_A,
+		.PulseIndex	= PulseIndex_A,
+		.SetEnable	= SetEnable_A,
+		.SetIntSrc	= SetIntSrc_A,
+		.SetLoadTrig	= SetLoadTrig_A,
+		.SetMode	= SetMode_A,
+		.ResetCapFlags	= ResetCapFlags_A,
+		.MyCRA		= LP_CR0A,
+		.MyCRB		= LP_CR0B,
+		.MyLatchLsw	= LP_CNTR0ALSW,
+		.MyEventBits	= EVBITS(0),
+	}, {
+		.GetEnable	= GetEnable_A,
+		.GetIntSrc	= GetIntSrc_A,
+		.GetLoadTrig	= GetLoadTrig_A,
+		.GetMode	= GetMode_A,
+		.PulseIndex	= PulseIndex_A,
+		.SetEnable	= SetEnable_A,
+		.SetIntSrc	= SetIntSrc_A,
+		.SetLoadTrig	= SetLoadTrig_A,
+		.SetMode	= SetMode_A,
+		.ResetCapFlags	= ResetCapFlags_A,
+		.MyCRA		= LP_CR1A,
+		.MyCRB		= LP_CR1B,
+		.MyLatchLsw	= LP_CNTR1ALSW,
+		.MyEventBits	= EVBITS(1),
+	}, {
+		.GetEnable	= GetEnable_A,
+		.GetIntSrc	= GetIntSrc_A,
+		.GetLoadTrig	= GetLoadTrig_A,
+		.GetMode	= GetMode_A,
+		.PulseIndex	= PulseIndex_A,
+		.SetEnable	= SetEnable_A,
+		.SetIntSrc	= SetIntSrc_A,
+		.SetLoadTrig	= SetLoadTrig_A,
+		.SetMode	= SetMode_A,
+		.ResetCapFlags	= ResetCapFlags_A,
+		.MyCRA		= LP_CR2A,
+		.MyCRB		= LP_CR2B,
+		.MyLatchLsw	= LP_CNTR2ALSW,
+		.MyEventBits	= EVBITS(2),
+	}, {
+		.GetEnable	= GetEnable_B,
+		.GetIntSrc	= GetIntSrc_B,
+		.GetLoadTrig	= GetLoadTrig_B,
+		.GetMode	= GetMode_B,
+		.PulseIndex	= PulseIndex_B,
+		.SetEnable	= SetEnable_B,
+		.SetIntSrc	= SetIntSrc_B,
+		.SetLoadTrig	= SetLoadTrig_B,
+		.SetMode	= SetMode_B,
+		.ResetCapFlags	= ResetCapFlags_B,
+		.MyCRA		= LP_CR0A,
+		.MyCRB		= LP_CR0B,
+		.MyLatchLsw	= LP_CNTR0BLSW,
+		.MyEventBits	= EVBITS(3),
+	}, {
+		.GetEnable	= GetEnable_B,
+		.GetIntSrc	= GetIntSrc_B,
+		.GetLoadTrig	= GetLoadTrig_B,
+		.GetMode	= GetMode_B,
+		.PulseIndex	= PulseIndex_B,
+		.SetEnable	= SetEnable_B,
+		.SetIntSrc	= SetIntSrc_B,
+		.SetLoadTrig	= SetLoadTrig_B,
+		.SetMode	= SetMode_B,
+		.ResetCapFlags	= ResetCapFlags_B,
+		.MyCRA		= LP_CR1A,
+		.MyCRB		= LP_CR1B,
+		.MyLatchLsw	= LP_CNTR1BLSW,
+		.MyEventBits	= EVBITS(4),
+	}, {
+		.GetEnable	= GetEnable_B,
+		.GetIntSrc	= GetIntSrc_B,
+		.GetLoadTrig	= GetLoadTrig_B,
+		.GetMode	= GetMode_B,
+		.PulseIndex	= PulseIndex_B,
+		.SetEnable	= SetEnable_B,
+		.SetIntSrc	= SetIntSrc_B,
+		.SetLoadTrig	= SetLoadTrig_B,
+		.SetMode	= SetMode_B,
+		.ResetCapFlags	= ResetCapFlags_B,
+		.MyCRA		= LP_CR2A,
+		.MyCRB		= LP_CR2B,
+		.MyLatchLsw	= LP_CNTR2BLSW,
+		.MyEventBits	= EVBITS(5),
+	},
+};
 
-/*  Read a counter's output latch. */
+static void CountersInit(struct comedi_device *dev)
+{
+	int chan;
+	struct enc_private *k;
+	uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) |	/*  Preload upon */
+	    /*  index. */
+	    (INDXSRC_SOFT << BF_INDXSRC) |	/*  Disable hardware index. */
+	    (CLKSRC_COUNTER << BF_CLKSRC) |	/*  Operating mode is counter. */
+	    (CLKPOL_POS << BF_CLKPOL) |	/*  Active high clock. */
+	    (CNTDIR_UP << BF_CLKPOL) |	/*  Count direction is up. */
+	    (CLKMULT_1X << BF_CLKMULT) |	/*  Clock multiplier is 1x. */
+	    (CLKENAB_INDEX << BF_CLKENAB);	/*  Enabled by index */
+
+	/*  Disable all counter interrupts and clear any captured counter events. */
+	for (chan = 0; chan < S626_ENCODER_CHANNELS; chan++) {
+		k = &encpriv[chan];
+		k->SetMode(dev, k, Setup, TRUE);
+		k->SetIntSrc(dev, k, 0);
+		k->ResetCapFlags(dev, k);
+		k->SetEnable(dev, k, CLKENAB_ALWAYS);
+	}
+}
 
-static uint32_t ReadLatch(struct comedi_device *dev, struct enc_private *k)
+static struct pci_dev *s626_find_pci(struct comedi_device *dev,
+				     struct comedi_devconfig *it)
 {
-	register uint32_t value;
-	/* DEBUG FIXME DEBUG("ReadLatch: Read Latch enter\n"); */
-
-	/*  Latch counts and fetch LSW of latched counts value. */
-	value = (uint32_t) DEBIread(dev, k->MyLatchLsw);
-
-	/*  Fetch MSW of latched counts and combine with LSW. */
-	value |= ((uint32_t) DEBIread(dev, k->MyLatchLsw + 2) << 16);
+	struct pci_dev *pcidev = NULL;
+	int bus = it->options[0];
+	int slot = it->options[1];
+	int i;
 
-	/*  DEBUG FIXME DEBUG("ReadLatch: Read Latch exit\n"); */
+	for (i = 0; i < ARRAY_SIZE(s626_boards) && !pcidev; i++) {
+		do {
+			pcidev = pci_get_subsys(s626_boards[i].vendor_id,
+						s626_boards[i].device_id,
+						s626_boards[i].subvendor_id,
+						s626_boards[i].subdevice_id,
+						pcidev);
 
-	/*  Return latched counts. */
-	return value;
+			if ((bus || slot) && pcidev) {
+				/* matches requested bus/slot */
+				if (pcidev->bus->number == bus &&
+				    PCI_SLOT(pcidev->devfn) == slot)
+					break;
+			} else {
+				break;
+			}
+		} while (1);
+	}
+	return pcidev;
 }
 
-/*  Reset a counter's index and overflow event capture flags. */
-
-static void ResetCapFlags_A(struct comedi_device *dev, struct enc_private *k)
+static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
-	DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
-		    CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A);
-}
+/*   uint8_t	PollList; */
+/*   uint16_t	AdcData; */
+/*   uint16_t	StartVal; */
+/*   uint16_t	index; */
+/*   unsigned int data[16]; */
+	int result;
+	int i;
+	int ret;
+	resource_size_t resourceStart;
+	dma_addr_t appdma;
+	struct comedi_subdevice *s;
 
-static void ResetCapFlags_B(struct comedi_device *dev, struct enc_private *k)
-{
-	DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
-		    CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B);
-}
+	if (alloc_private(dev, sizeof(struct s626_private)) < 0)
+		return -ENOMEM;
 
-/*  Return counter setup in a format (COUNTER_SETUP) that is consistent */
-/*  for both A and B counters. */
+	devpriv->pdev = s626_find_pci(dev, it);
+	if (!devpriv->pdev) {
+		printk(KERN_ERR "s626_attach: Board not present!!!\n");
+		return -ENODEV;
+	}
 
-static uint16_t GetMode_A(struct comedi_device *dev, struct enc_private *k)
-{
-	register uint16_t cra;
-	register uint16_t crb;
-	register uint16_t setup;
+	result = comedi_pci_enable(devpriv->pdev, "s626");
+	if (result < 0) {
+		printk(KERN_ERR "s626_attach: comedi_pci_enable fails\n");
+		return -ENODEV;
+	}
+	devpriv->got_regions = 1;
 
-	/*  Fetch CRA and CRB register images. */
-	cra = DEBIread(dev, k->MyCRA);
-	crb = DEBIread(dev, k->MyCRB);
+	resourceStart = pci_resource_start(devpriv->pdev, 0);
 
-	/*  Populate the standardized counter setup bit fields.  Note: */
-	/*  IndexSrc is restricted to ENC_X or IndxPol. */
-	setup = ((cra & STDMSK_LOADSRC)	/*  LoadSrc  = LoadSrcA. */
-		 |((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC)	/*  LatchSrc = LatchSrcA. */
-		 |((cra << (STDBIT_INTSRC - CRABIT_INTSRC_A)) & STDMSK_INTSRC)	/*  IntSrc   = IntSrcA. */
-		 |((cra << (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1))) & STDMSK_INDXSRC)	/*  IndxSrc  = IndxSrcA<1>. */
-		 |((cra >> (CRABIT_INDXPOL_A - STDBIT_INDXPOL)) & STDMSK_INDXPOL)	/*  IndxPol  = IndxPolA. */
-		 |((crb >> (CRBBIT_CLKENAB_A - STDBIT_CLKENAB)) & STDMSK_CLKENAB));	/*  ClkEnab  = ClkEnabA. */
+	devpriv->base_addr = ioremap(resourceStart, SIZEOF_ADDRESS_SPACE);
+	if (devpriv->base_addr == NULL) {
+		printk(KERN_ERR "s626_attach: IOREMAP failed\n");
+		return -ENODEV;
+	}
 
-	/*  Adjust mode-dependent parameters. */
-	if (cra & (2 << CRABIT_CLKSRC_A))	/*  If Timer mode (ClkSrcA<1> == 1): */
-		setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC)	/*    Indicate Timer mode. */
-			  |((cra << (STDBIT_CLKPOL - CRABIT_CLKSRC_A)) & STDMSK_CLKPOL)	/*    Set ClkPol to indicate count direction (ClkSrcA<0>). */
-			  |(MULT_X1 << STDBIT_CLKMULT));	/*    ClkMult must be 1x in Timer mode. */
+	if (devpriv->base_addr) {
+		/* disable master interrupt */
+		writel(0, devpriv->base_addr + P_IER);
 
-	else			/*  If Counter mode (ClkSrcA<1> == 0): */
-		setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC)	/*    Indicate Counter mode. */
-			  |((cra >> (CRABIT_CLKPOL_A - STDBIT_CLKPOL)) & STDMSK_CLKPOL)	/*    Pass through ClkPol. */
-			  |(((cra & CRAMSK_CLKMULT_A) == (MULT_X0 << CRABIT_CLKMULT_A)) ?	/*    Force ClkMult to 1x if not legal, else pass through. */
-			    (MULT_X1 << STDBIT_CLKMULT) :
-			    ((cra >> (CRABIT_CLKMULT_A -
-				      STDBIT_CLKMULT)) & STDMSK_CLKMULT)));
+		/* soft reset */
+		writel(MC1_SOFT_RESET, devpriv->base_addr + P_MC1);
 
-	/*  Return adjusted counter setup. */
-	return setup;
-}
+		/* DMA FIXME DMA// */
 
-static uint16_t GetMode_B(struct comedi_device *dev, struct enc_private *k)
-{
-	register uint16_t cra;
-	register uint16_t crb;
-	register uint16_t setup;
+		/* adc buffer allocation */
+		devpriv->allocatedBuf = 0;
 
-	/*  Fetch CRA and CRB register images. */
-	cra = DEBIread(dev, k->MyCRA);
-	crb = DEBIread(dev, k->MyCRB);
+		devpriv->ANABuf.LogicalBase =
+		    pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma);
 
-	/*  Populate the standardized counter setup bit fields.  Note: */
-	/*  IndexSrc is restricted to ENC_X or IndxPol. */
-	setup = (((crb << (STDBIT_INTSRC - CRBBIT_INTSRC_B)) & STDMSK_INTSRC)	/*  IntSrc   = IntSrcB. */
-		 |((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC)	/*  LatchSrc = LatchSrcB. */
-		 |((crb << (STDBIT_LOADSRC - CRBBIT_LOADSRC_B)) & STDMSK_LOADSRC)	/*  LoadSrc  = LoadSrcB. */
-		 |((crb << (STDBIT_INDXPOL - CRBBIT_INDXPOL_B)) & STDMSK_INDXPOL)	/*  IndxPol  = IndxPolB. */
-		 |((crb >> (CRBBIT_CLKENAB_B - STDBIT_CLKENAB)) & STDMSK_CLKENAB)	/*  ClkEnab  = ClkEnabB. */
-		 |((cra >> ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC)) & STDMSK_INDXSRC));	/*  IndxSrc  = IndxSrcB<1>. */
+		if (devpriv->ANABuf.LogicalBase == NULL) {
+			printk(KERN_ERR "s626_attach: DMA Memory mapping error\n");
+			return -ENOMEM;
+		}
 
-	/*  Adjust mode-dependent parameters. */
-	if ((crb & CRBMSK_CLKMULT_B) == (MULT_X0 << CRBBIT_CLKMULT_B))	/*  If Extender mode (ClkMultB == MULT_X0): */
-		setup |= ((CLKSRC_EXTENDER << STDBIT_CLKSRC)	/*    Indicate Extender mode. */
-			  |(MULT_X1 << STDBIT_CLKMULT)	/*    Indicate multiplier is 1x. */
-			  |((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL));	/*    Set ClkPol equal to Timer count direction (ClkSrcB<0>). */
+		devpriv->ANABuf.PhysicalBase = appdma;
 
-	else if (cra & (2 << CRABIT_CLKSRC_B))	/*  If Timer mode (ClkSrcB<1> == 1): */
-		setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC)	/*    Indicate Timer mode. */
-			  |(MULT_X1 << STDBIT_CLKMULT)	/*    Indicate multiplier is 1x. */
-			  |((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL));	/*    Set ClkPol equal to Timer count direction (ClkSrcB<0>). */
+		devpriv->allocatedBuf++;
 
-	else			/*  If Counter mode (ClkSrcB<1> == 0): */
-		setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC)	/*    Indicate Timer mode. */
-			  |((crb >> (CRBBIT_CLKMULT_B - STDBIT_CLKMULT)) & STDMSK_CLKMULT)	/*    Clock multiplier is passed through. */
-			  |((crb << (STDBIT_CLKPOL - CRBBIT_CLKPOL_B)) & STDMSK_CLKPOL));	/*    Clock polarity is passed through. */
+		devpriv->RPSBuf.LogicalBase =
+		    pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma);
 
-	/*  Return adjusted counter setup. */
-	return setup;
-}
+		if (devpriv->RPSBuf.LogicalBase == NULL) {
+			printk(KERN_ERR "s626_attach: DMA Memory mapping error\n");
+			return -ENOMEM;
+		}
 
-/*
- * Set the operating mode for the specified counter.  The setup
- * parameter is treated as a COUNTER_SETUP data type.  The following
- * parameters are programmable (all other parms are ignored): ClkMult,
- * ClkPol, ClkEnab, IndexSrc, IndexPol, LoadSrc.
- */
+		devpriv->RPSBuf.PhysicalBase = appdma;
 
-static void SetMode_A(struct comedi_device *dev, struct enc_private *k,
-		      uint16_t Setup, uint16_t DisableIntSrc)
-{
-	register uint16_t cra;
-	register uint16_t crb;
-	register uint16_t setup = Setup;	/*  Cache the Standard Setup. */
+		devpriv->allocatedBuf++;
 
-	/*  Initialize CRA and CRB images. */
-	cra = ((setup & CRAMSK_LOADSRC_A)	/*  Preload trigger is passed through. */
-	       |((setup & STDMSK_INDXSRC) >> (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1))));	/*  IndexSrc is restricted to ENC_X or IndxPol. */
+	}
 
-	crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A	/*  Reset any pending CounterA event captures. */
-	       | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_A - STDBIT_CLKENAB)));	/*  Clock enable is passed through. */
+	dev->board_ptr = s626_boards;
+	dev->board_name = thisboard->name;
 
-	/*  Force IntSrc to Disabled if DisableIntSrc is asserted. */
-	if (!DisableIntSrc)
-		cra |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC -
-						    CRABIT_INTSRC_A));
+	ret = comedi_alloc_subdevices(dev, 6);
+	if (ret)
+		return ret;
 
-	/*  Populate all mode-dependent attributes of CRA & CRB images. */
-	switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) {
-	case CLKSRC_EXTENDER:	/*  Extender Mode: Force to Timer mode */
-		/*  (Extender valid only for B counters). */
+	dev->iobase = (unsigned long)devpriv->base_addr;
+	dev->irq = devpriv->pdev->irq;
 
-	case CLKSRC_TIMER:	/*  Timer Mode: */
-		cra |= ((2 << CRABIT_CLKSRC_A)	/*    ClkSrcA<1> selects system clock */
-			|((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRABIT_CLKSRC_A))	/*      with count direction (ClkSrcA<0>) obtained from ClkPol. */
-			|(1 << CRABIT_CLKPOL_A)	/*    ClkPolA behaves as always-on clock enable. */
-			|(MULT_X1 << CRABIT_CLKMULT_A));	/*    ClkMult must be 1x. */
-		break;
+	/* set up interrupt handler */
+	if (dev->irq == 0) {
+		printk(KERN_ERR " unknown irq (bad)\n");
+	} else {
+		ret = request_irq(dev->irq, s626_irq_handler, IRQF_SHARED,
+				  "s626", dev);
 
-	default:		/*  Counter Mode: */
-		cra |= (CLKSRC_COUNTER	/*    Select ENC_C and ENC_D as clock/direction inputs. */
-			| ((setup & STDMSK_CLKPOL) << (CRABIT_CLKPOL_A - STDBIT_CLKPOL))	/*    Clock polarity is passed through. */
-			|(((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ?	/*    Force multiplier to x1 if not legal, otherwise pass through. */
-			  (MULT_X1 << CRABIT_CLKMULT_A) :
-			  ((setup & STDMSK_CLKMULT) << (CRABIT_CLKMULT_A -
-							STDBIT_CLKMULT))));
+		if (ret < 0) {
+			printk(KERN_ERR " irq not available\n");
+			dev->irq = 0;
+		}
 	}
 
-	/*  Force positive index polarity if IndxSrc is software-driven only, */
-	/*  otherwise pass it through. */
-	if (~setup & STDMSK_INDXSRC)
-		cra |= ((setup & STDMSK_INDXPOL) << (CRABIT_INDXPOL_A -
-						     STDBIT_INDXPOL));
-
-	/*  If IntSrc has been forced to Disabled, update the MISC2 interrupt */
-	/*  enable mask to indicate the counter interrupt is disabled. */
-	if (DisableIntSrc)
-		devpriv->CounterIntEnabs &= ~k->MyEventBits[3];
+	s = dev->subdevices + 0;
+	/* analog input subdevice */
+	dev->read_subdev = s;
+	/* we support single-ended (ground) and differential */
+	s->type = COMEDI_SUBD_AI;
+	s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_CMD_READ;
+	s->n_chan = thisboard->ai_chans;
+	s->maxdata = (0xffff >> 2);
+	s->range_table = &s626_range_table;
+	s->len_chanlist = thisboard->ai_chans;	/* This is the maximum chanlist
+						   length that the board can
+						   handle */
+	s->insn_config = s626_ai_insn_config;
+	s->insn_read = s626_ai_insn_read;
+	s->do_cmd = s626_ai_cmd;
+	s->do_cmdtest = s626_ai_cmdtest;
+	s->cancel = s626_ai_cancel;
 
-	/*  While retaining CounterB and LatchSrc configurations, program the */
-	/*  new counter operating mode. */
-	DEBIreplace(dev, k->MyCRA, CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B, cra);
-	DEBIreplace(dev, k->MyCRB,
-		    (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)), crb);
-}
+	s = dev->subdevices + 1;
+	/* analog output subdevice */
+	s->type = COMEDI_SUBD_AO;
+	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+	s->n_chan = thisboard->ao_chans;
+	s->maxdata = (0x3fff);
+	s->range_table = &range_bipolar10;
+	s->insn_write = s626_ao_winsn;
+	s->insn_read = s626_ao_rinsn;
 
-static void SetMode_B(struct comedi_device *dev, struct enc_private *k,
-		      uint16_t Setup, uint16_t DisableIntSrc)
-{
-	register uint16_t cra;
-	register uint16_t crb;
-	register uint16_t setup = Setup;	/*  Cache the Standard Setup. */
+	s = dev->subdevices + 2;
+	/* digital I/O subdevice */
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+	s->n_chan = S626_DIO_CHANNELS;
+	s->maxdata = 1;
+	s->io_bits = 0xffff;
+	s->private = &dio_private_A;
+	s->range_table = &range_digital;
+	s->insn_config = s626_dio_insn_config;
+	s->insn_bits = s626_dio_insn_bits;
 
-	/*  Initialize CRA and CRB images. */
-	cra = ((setup & STDMSK_INDXSRC) << ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC));	/*  IndexSrc field is restricted to ENC_X or IndxPol. */
+	s = dev->subdevices + 3;
+	/* digital I/O subdevice */
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+	s->n_chan = 16;
+	s->maxdata = 1;
+	s->io_bits = 0xffff;
+	s->private = &dio_private_B;
+	s->range_table = &range_digital;
+	s->insn_config = s626_dio_insn_config;
+	s->insn_bits = s626_dio_insn_bits;
 
-	crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B	/*  Reset event captures and disable interrupts. */
-	       | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_B - STDBIT_CLKENAB))	/*  Clock enable is passed through. */
-	       |((setup & STDMSK_LOADSRC) >> (STDBIT_LOADSRC - CRBBIT_LOADSRC_B)));	/*  Preload trigger source is passed through. */
+	s = dev->subdevices + 4;
+	/* digital I/O subdevice */
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+	s->n_chan = 16;
+	s->maxdata = 1;
+	s->io_bits = 0xffff;
+	s->private = &dio_private_C;
+	s->range_table = &range_digital;
+	s->insn_config = s626_dio_insn_config;
+	s->insn_bits = s626_dio_insn_bits;
 
-	/*  Force IntSrc to Disabled if DisableIntSrc is asserted. */
-	if (!DisableIntSrc)
-		crb |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC -
-						    CRBBIT_INTSRC_B));
+	s = dev->subdevices + 5;
+	/* encoder (counter) subdevice */
+	s->type = COMEDI_SUBD_COUNTER;
+	s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL;
+	s->n_chan = thisboard->enc_chans;
+	s->private = enc_private_data;
+	s->insn_config = s626_enc_insn_config;
+	s->insn_read = s626_enc_insn_read;
+	s->insn_write = s626_enc_insn_write;
+	s->maxdata = 0xffffff;
+	s->range_table = &range_unknown;
 
-	/*  Populate all mode-dependent attributes of CRA & CRB images. */
-	switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) {
-	case CLKSRC_TIMER:	/*  Timer Mode: */
-		cra |= ((2 << CRABIT_CLKSRC_B)	/*    ClkSrcB<1> selects system clock */
-			|((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL)));	/*      with direction (ClkSrcB<0>) obtained from ClkPol. */
-		crb |= ((1 << CRBBIT_CLKPOL_B)	/*    ClkPolB behaves as always-on clock enable. */
-			|(MULT_X1 << CRBBIT_CLKMULT_B));	/*    ClkMultB must be 1x. */
-		break;
+	/* stop ai_command */
+	devpriv->ai_cmd_running = 0;
 
-	case CLKSRC_EXTENDER:	/*  Extender Mode: */
-		cra |= ((2 << CRABIT_CLKSRC_B)	/*    ClkSrcB source is OverflowA (same as "timer") */
-			|((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL)));	/*      with direction obtained from ClkPol. */
-		crb |= ((1 << CRBBIT_CLKPOL_B)	/*    ClkPolB controls IndexB -- always set to active. */
-			|(MULT_X0 << CRBBIT_CLKMULT_B));	/*    ClkMultB selects OverflowA as the clock source. */
-		break;
+	if (devpriv->base_addr && (devpriv->allocatedBuf == 2)) {
+		dma_addr_t pPhysBuf;
+		uint16_t chan;
 
-	default:		/*  Counter Mode: */
-		cra |= (CLKSRC_COUNTER << CRABIT_CLKSRC_B);	/*    Select ENC_C and ENC_D as clock/direction inputs. */
-		crb |= (((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRBBIT_CLKPOL_B))	/*    ClkPol is passed through. */
-			|(((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ?	/*    Force ClkMult to x1 if not legal, otherwise pass through. */
-			  (MULT_X1 << CRBBIT_CLKMULT_B) :
-			  ((setup & STDMSK_CLKMULT) << (CRBBIT_CLKMULT_B -
-							STDBIT_CLKMULT))));
-	}
+		/*  enab DEBI and audio pins, enable I2C interface. */
+		MC_ENABLE(P_MC1, MC1_DEBI | MC1_AUDIO | MC1_I2C);
+		/*  Configure DEBI operating mode. */
+		WR7146(P_DEBICFG, DEBI_CFG_SLAVE16	/*  Local bus is 16 */
+		       /*  bits wide. */
+		       | (DEBI_TOUT << DEBI_CFG_TOUT_BIT)
 
-	/*  Force positive index polarity if IndxSrc is software-driven only, */
-	/*  otherwise pass it through. */
-	if (~setup & STDMSK_INDXSRC)
-		crb |= ((setup & STDMSK_INDXPOL) >> (STDBIT_INDXPOL -
-						     CRBBIT_INDXPOL_B));
+		       /*  Declare DEBI */
+		       /*  transfer timeout */
+		       /*  interval. */
+		       |DEBI_SWAP	/*  Set up byte lane */
+		       /*  steering. */
+		       | DEBI_CFG_INTEL);	/*  Intel-compatible */
+		/*  local bus (DEBI */
+		/*  never times out). */
 
-	/*  If IntSrc has been forced to Disabled, update the MISC2 interrupt */
-	/*  enable mask to indicate the counter interrupt is disabled. */
-	if (DisableIntSrc)
-		devpriv->CounterIntEnabs &= ~k->MyEventBits[3];
+		/* DEBI INIT S626 WR7146( P_DEBICFG, DEBI_CFG_INTEL | DEBI_CFG_TOQ */
+		/* | DEBI_CFG_INCQ| DEBI_CFG_16Q); //end */
 
-	/*  While retaining CounterA and LatchSrc configurations, program the */
-	/*  new counter operating mode. */
-	DEBIreplace(dev, k->MyCRA,
-		    (uint16_t) (~(CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B)), cra);
-	DEBIreplace(dev, k->MyCRB, CRBMSK_CLKENAB_A | CRBMSK_LATCHSRC, crb);
-}
+		/*  Paging is disabled. */
+		WR7146(P_DEBIPAGE, DEBI_PAGE_DISABLE);	/*  Disable MMU paging. */
 
-/*  Return/set a counter's enable.  enab: 0=always enabled, 1=enabled by index. */
+		/*  Init GPIO so that ADC Start* is negated. */
+		WR7146(P_GPIO, GPIO_BASE | GPIO1_HI);
 
-static void SetEnable_A(struct comedi_device *dev, struct enc_private *k,
-			uint16_t enab)
-{
-	DEBUG("SetEnable_A: SetEnable_A enter 3541\n");
-	DEBIreplace(dev, k->MyCRB,
-		    (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)),
-		    (uint16_t) (enab << CRBBIT_CLKENAB_A));
-}
+		/* IsBoardRevA is a boolean that indicates whether the board is RevA.
+		 *
+		 * VERSION 2.01 CHANGE: REV A & B BOARDS NOW SUPPORTED BY DYNAMIC
+		 * EEPROM ADDRESS SELECTION.  Initialize the I2C interface, which
+		 * is used to access the onboard serial EEPROM.  The EEPROM's I2C
+		 * DeviceAddress is hardwired to a value that is dependent on the
+		 * 626 board revision.  On all board revisions, the EEPROM stores
+		 * TrimDAC calibration constants for analog I/O.  On RevB and
+		 * higher boards, the DeviceAddress is hardwired to 0 to enable
+		 * the EEPROM to also store the PCI SubVendorID and SubDeviceID;
+		 * this is the address at which the SAA7146 expects a
+		 * configuration EEPROM to reside.  On RevA boards, the EEPROM
+		 * device address, which is hardwired to 4, prevents the SAA7146
+		 * from retrieving PCI sub-IDs, so the SAA7146 uses its built-in
+		 * default values, instead.
+		 */
 
-static void SetEnable_B(struct comedi_device *dev, struct enc_private *k,
-			uint16_t enab)
-{
-	DEBIreplace(dev, k->MyCRB,
-		    (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_B)),
-		    (uint16_t) (enab << CRBBIT_CLKENAB_B));
-}
+		/*     devpriv->I2Cards= IsBoardRevA ? 0xA8 : 0xA0; // Set I2C EEPROM */
+		/*  DeviceType (0xA0) */
+		/*  and DeviceAddress<<1. */
 
-static uint16_t GetEnable_A(struct comedi_device *dev, struct enc_private *k)
-{
-	return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_A) & 1;
-}
+		devpriv->I2CAdrs = 0xA0;	/*  I2C device address for onboard */
+		/*  eeprom(revb) */
 
-static uint16_t GetEnable_B(struct comedi_device *dev, struct enc_private *k)
-{
-	return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_B) & 1;
-}
+		/*  Issue an I2C ABORT command to halt any I2C operation in */
+		/* progress and reset BUSY flag. */
+		WR7146(P_I2CSTAT, I2C_CLKSEL | I2C_ABORT);
+		/*  Write I2C control: abort any I2C activity. */
+		MC_ENABLE(P_MC2, MC2_UPLD_IIC);
+		/*  Invoke command  upload */
+		while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0)
+			;
+		/*  and wait for upload to complete. */
 
-/* Return/set a counter pair's latch trigger source.  0: On read
- * access, 1: A index latches A, 2: B index latches B, 3: A overflow
- * latches B.
- */
+		/* Per SAA7146 data sheet, write to STATUS reg twice to
+		 * reset all  I2C error flags. */
+		for (i = 0; i < 2; i++) {
+			WR7146(P_I2CSTAT, I2C_CLKSEL);
+			/*  Write I2C control: reset  error flags. */
+			MC_ENABLE(P_MC2, MC2_UPLD_IIC);	/*  Invoke command upload */
+			while (!MC_TEST(P_MC2, MC2_UPLD_IIC))
+				;
+			/* and wait for upload to complete. */
+		}
 
-static void SetLatchSource(struct comedi_device *dev, struct enc_private *k,
-			   uint16_t value)
-{
-	DEBUG("SetLatchSource: SetLatchSource enter 3550\n");
-	DEBIreplace(dev, k->MyCRB,
-		    (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_LATCHSRC)),
-		    (uint16_t) (value << CRBBIT_LATCHSRC));
+		/* Init audio interface functional attributes: set DAC/ADC
+		 * serial clock rates, invert DAC serial clock so that
+		 * DAC data setup times are satisfied, enable DAC serial
+		 * clock out.
+		 */
 
-	DEBUG("SetLatchSource: SetLatchSource exit\n");
-}
+		WR7146(P_ACON2, ACON2_INIT);
 
-/*
- * static uint16_t GetLatchSource(struct comedi_device *dev, struct enc_private *k )
- * {
- *	return ( DEBIread( dev, k->MyCRB) >> CRBBIT_LATCHSRC ) & 3;
- * }
- */
+		/* Set up TSL1 slot list, which is used to control the
+		 * accumulation of ADC data: RSD1 = shift data in on SD1.
+		 * SIB_A1  = store data uint8_t at next available location in
+		 * FB BUFFER1  register. */
+		WR7146(P_TSL1, RSD1 | SIB_A1);
+		/*  Fetch ADC high data uint8_t. */
+		WR7146(P_TSL1 + 4, RSD1 | SIB_A1 | EOS);
+		/*  Fetch ADC low data uint8_t; end of TSL1. */
 
-/*
- * Return/set the event that will trigger transfer of the preload
- * register into the counter.  0=ThisCntr_Index, 1=ThisCntr_Overflow,
- * 2=OverflowA (B counters only), 3=disabled.
- */
+		/*  enab TSL1 slot list so that it executes all the time. */
+		WR7146(P_ACON1, ACON1_ADCSTART);
 
-static void SetLoadTrig_A(struct comedi_device *dev, struct enc_private *k,
-			  uint16_t Trig)
-{
-	DEBIreplace(dev, k->MyCRA, (uint16_t) (~CRAMSK_LOADSRC_A),
-		    (uint16_t) (Trig << CRABIT_LOADSRC_A));
-}
+		/*  Initialize RPS registers used for ADC. */
 
-static void SetLoadTrig_B(struct comedi_device *dev, struct enc_private *k,
-			  uint16_t Trig)
-{
-	DEBIreplace(dev, k->MyCRB,
-		    (uint16_t) (~(CRBMSK_LOADSRC_B | CRBMSK_INTCTRL)),
-		    (uint16_t) (Trig << CRBBIT_LOADSRC_B));
-}
+		/* Physical start of RPS program. */
+		WR7146(P_RPSADDR1, (uint32_t) devpriv->RPSBuf.PhysicalBase);
 
-static uint16_t GetLoadTrig_A(struct comedi_device *dev, struct enc_private *k)
-{
-	return (DEBIread(dev, k->MyCRA) >> CRABIT_LOADSRC_A) & 3;
-}
+		WR7146(P_RPSPAGE1, 0);
+		/*  RPS program performs no explicit mem writes. */
+		WR7146(P_RPS1_TOUT, 0);	/*  Disable RPS timeouts. */
 
-static uint16_t GetLoadTrig_B(struct comedi_device *dev, struct enc_private *k)
-{
-	return (DEBIread(dev, k->MyCRB) >> CRBBIT_LOADSRC_B) & 3;
-}
+		/* SAA7146 BUG WORKAROUND.  Initialize SAA7146 ADC interface
+		 * to a known state by invoking ADCs until FB BUFFER 1
+		 * register shows that it is correctly receiving ADC data.
+		 * This is necessary because the SAA7146 ADC interface does
+		 * not start up in a defined state after a PCI reset.
+		 */
 
-/* Return/set counter interrupt source and clear any captured
- * index/overflow events.  IntSource: 0=Disabled, 1=OverflowOnly,
- * 2=IndexOnly, 3=IndexAndOverflow.
- */
+/*     PollList = EOPL;		// Create a simple polling */
+/*				// list for analog input */
+/*				// channel 0. */
+/*     ResetADC( dev, &PollList ); */
 
-static void SetIntSrc_A(struct comedi_device *dev, struct enc_private *k,
-			uint16_t IntSource)
-{
-	/*  Reset any pending counter overflow or index captures. */
-	DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
-		    CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A);
+/*     s626_ai_rinsn(dev,dev->subdevices,NULL,data); //( &AdcData ); // */
+/*							//Get initial ADC */
+/*							//value. */
 
-	/*  Program counter interrupt source. */
-	DEBIreplace(dev, k->MyCRA, ~CRAMSK_INTSRC_A,
-		    (uint16_t) (IntSource << CRABIT_INTSRC_A));
+/*     StartVal = data[0]; */
 
-	/*  Update MISC2 interrupt enable mask. */
-	devpriv->CounterIntEnabs =
-	    (devpriv->CounterIntEnabs & ~k->
-	     MyEventBits[3]) | k->MyEventBits[IntSource];
-}
+/*     // VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION. */
+/*     // Invoke ADCs until the new ADC value differs from the initial */
+/*     // value or a timeout occurs.  The timeout protects against the */
+/*     // possibility that the driver is restarting and the ADC data is a */
+/*     // fixed value resulting from the applied ADC analog input being */
+/*     // unusually quiet or at the rail. */
 
-static void SetIntSrc_B(struct comedi_device *dev, struct enc_private *k,
-			uint16_t IntSource)
-{
-	uint16_t crb;
+/*     for ( index = 0; index < 500; index++ ) */
+/*       { */
+/*	s626_ai_rinsn(dev,dev->subdevices,NULL,data); */
+/*	AdcData = data[0];	//ReadADC(  &AdcData ); */
+/*	if ( AdcData != StartVal ) */
+/*		break; */
+/*       } */
 
-	/*  Cache writeable CRB register image. */
-	crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL;
+		/*  end initADC */
 
-	/*  Reset any pending counter overflow or index captures. */
-	DEBIwrite(dev, k->MyCRB,
-		  (uint16_t) (crb | CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B));
+		/*  init the DAC interface */
 
-	/*  Program counter interrupt source. */
-	DEBIwrite(dev, k->MyCRB,
-		  (uint16_t) ((crb & ~CRBMSK_INTSRC_B) | (IntSource <<
-							  CRBBIT_INTSRC_B)));
+		/* Init Audio2's output DMAC attributes: burst length = 1
+		 * DWORD,  threshold = 1 DWORD.
+		 */
+		WR7146(P_PCI_BT_A, 0);
 
-	/*  Update MISC2 interrupt enable mask. */
-	devpriv->CounterIntEnabs =
-	    (devpriv->CounterIntEnabs & ~k->
-	     MyEventBits[3]) | k->MyEventBits[IntSource];
-}
+		/* Init Audio2's output DMA physical addresses.  The protection
+		 * address is set to 1 DWORD past the base address so that a
+		 * single DWORD will be transferred each time a DMA transfer is
+		 * enabled. */
 
-static uint16_t GetIntSrc_A(struct comedi_device *dev, struct enc_private *k)
-{
-	return (DEBIread(dev, k->MyCRA) >> CRABIT_INTSRC_A) & 3;
-}
+		pPhysBuf =
+		    devpriv->ANABuf.PhysicalBase +
+		    (DAC_WDMABUF_OS * sizeof(uint32_t));
 
-static uint16_t GetIntSrc_B(struct comedi_device *dev, struct enc_private *k)
-{
-	return (DEBIread(dev, k->MyCRB) >> CRBBIT_INTSRC_B) & 3;
-}
+		WR7146(P_BASEA2_OUT, (uint32_t) pPhysBuf);	/*  Buffer base adrs. */
+		WR7146(P_PROTA2_OUT, (uint32_t) (pPhysBuf + sizeof(uint32_t)));	/*  Protection address. */
 
-/*  Return/set the clock multiplier. */
+		/* Cache Audio2's output DMA buffer logical address.  This is
+		 * where DAC data is buffered for A2 output DMA transfers. */
+		devpriv->pDacWBuf =
+		    (uint32_t *) devpriv->ANABuf.LogicalBase + DAC_WDMABUF_OS;
 
-/* static void SetClkMult(struct comedi_device *dev, struct enc_private *k, uint16_t value )  */
-/* { */
-/*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKMULT ) | ( value << STDBIT_CLKMULT ) ), FALSE ); */
-/* } */
+		/* Audio2's output channels does not use paging.  The protection
+		 * violation handling bit is set so that the DMAC will
+		 * automatically halt and its PCI address pointer will be reset
+		 * when the protection address is reached. */
 
-/* static uint16_t GetClkMult(struct comedi_device *dev, struct enc_private *k )  */
-/* { */
-/*   return ( k->GetMode(dev, k ) >> STDBIT_CLKMULT ) & 3; */
-/* } */
+		WR7146(P_PAGEA2_OUT, 8);
 
-/* Return/set the clock polarity. */
+		/* Initialize time slot list 2 (TSL2), which is used to control
+		 * the clock generation for and serialization of data to be sent
+		 * to the DAC devices.  Slot 0 is a NOP that is used to trap TSL
+		 * execution; this permits other slots to be safely modified
+		 * without first turning off the TSL sequencer (which is
+		 * apparently impossible to do).  Also, SD3 (which is driven by a
+		 * pull-up resistor) is shifted in and stored to the MSB of
+		 * FB_BUFFER2 to be used as evidence that the slot sequence has
+		 * not yet finished executing.
+		 */
 
-/* static void SetClkPol( struct comedi_device *dev,struct enc_private *k, uint16_t value )  */
-/* { */
-/*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKPOL ) | ( value << STDBIT_CLKPOL ) ), FALSE ); */
-/* } */
+		SETVECT(0, XSD2 | RSD3 | SIB_A2 | EOS);
+		/*  Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2. */
 
-/* static uint16_t GetClkPol(struct comedi_device *dev, struct enc_private *k )  */
-/* { */
-/*   return ( k->GetMode(dev, k ) >> STDBIT_CLKPOL ) & 1; */
-/* } */
+		/* Initialize slot 1, which is constant.  Slot 1 causes a
+		 * DWORD to be transferred from audio channel 2's output FIFO
+		 * to the FIFO's output buffer so that it can be serialized
+		 * and sent to the DAC during subsequent slots.  All remaining
+		 * slots are dynamically populated as required by the target
+		 * DAC device.
+		 */
+		SETVECT(1, LF_A2);
+		/*  Slot 1: Fetch DWORD from Audio2's output FIFO. */
 
-/* Return/set the clock source.  */
+		/*  Start DAC's audio interface (TSL2) running. */
+		WR7146(P_ACON1, ACON1_DACSTART);
 
-/* static void SetClkSrc( struct comedi_device *dev,struct enc_private *k, uint16_t value )  */
-/* { */
-/*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKSRC ) | ( value << STDBIT_CLKSRC ) ), FALSE ); */
-/* } */
+		/* end init DAC interface */
 
-/* static uint16_t GetClkSrc( struct comedi_device *dev,struct enc_private *k )  */
-/* { */
-/*   return ( k->GetMode(dev, k ) >> STDBIT_CLKSRC ) & 3; */
-/* } */
+		/* Init Trim DACs to calibrated values.  Do it twice because the
+		 * SAA7146 audio channel does not always reset properly and
+		 * sometimes causes the first few TrimDAC writes to malfunction.
+		 */
 
-/* Return/set the index polarity. */
+		LoadTrimDACs(dev);
+		LoadTrimDACs(dev);	/*  Insurance. */
 
-/* static void SetIndexPol(struct comedi_device *dev, struct enc_private *k, uint16_t value )  */
-/* { */
-/*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXPOL ) | ( (value != 0) << STDBIT_INDXPOL ) ), FALSE ); */
-/* } */
+		/* Manually init all gate array hardware in case this is a soft
+		 * reset (we have no way of determining whether this is a warm
+		 * or cold start).  This is necessary because the gate array will
+		 * reset only in response to a PCI hard reset; there is no soft
+		 * reset function. */
 
-/* static uint16_t GetIndexPol(struct comedi_device *dev, struct enc_private *k )  */
-/* { */
-/*   return ( k->GetMode(dev, k ) >> STDBIT_INDXPOL ) & 1; */
-/* } */
+		/* Init all DAC outputs to 0V and init all DAC setpoint and
+		 * polarity images.
+		 */
+		for (chan = 0; chan < S626_DAC_CHANNELS; chan++)
+			SetDAC(dev, chan, 0);
 
-/*  Return/set the index source. */
+		/* Init image of WRMISC2 Battery Charger Enabled control bit.
+		 * This image is used when the state of the charger control bit,
+		 * which has no direct hardware readback mechanism, is queried.
+		 */
+		devpriv->ChargeEnabled = 0;
 
-/* static void SetIndexSrc(struct comedi_device *dev, struct enc_private *k, uint16_t value )  */
-/* { */
-/*   DEBUG("SetIndexSrc: set index src enter 3700\n"); */
-/*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXSRC ) | ( (value != 0) << STDBIT_INDXSRC ) ), FALSE ); */
-/* } */
+		/* Init image of watchdog timer interval in WRMISC2.  This image
+		 * maintains the value of the control bits of MISC2 are
+		 * continuously reset to zero as long as the WD timer is disabled.
+		 */
+		devpriv->WDInterval = 0;
 
-/* static uint16_t GetIndexSrc(struct comedi_device *dev, struct enc_private *k )  */
-/* { */
-/*   return ( k->GetMode(dev, k ) >> STDBIT_INDXSRC ) & 1; */
-/* } */
+		/* Init Counter Interrupt enab mask for RDMISC2.  This mask is
+		 * applied against MISC2 when testing to determine which timer
+		 * events are requesting interrupt service.
+		 */
+		devpriv->CounterIntEnabs = 0;
 
-/*  Generate an index pulse. */
+		/*  Init counters. */
+		CountersInit(dev);
 
-static void PulseIndex_A(struct comedi_device *dev, struct enc_private *k)
-{
-	register uint16_t cra;
+		/* Without modifying the state of the Battery Backup enab, disable
+		 * the watchdog timer, set DIO channels 0-5 to operate in the
+		 * standard DIO (vs. counter overflow) mode, disable the battery
+		 * charger, and reset the watchdog interval selector to zero.
+		 */
+		WriteMISC2(dev, (uint16_t) (DEBIread(dev,
+						     LP_RDMISC2) &
+					    MISC2_BATT_ENABLE));
 
-	DEBUG("PulseIndex_A: pulse index enter\n");
+		/*  Initialize the digital I/O subsystem. */
+		s626_dio_init(dev);
 
-	cra = DEBIread(dev, k->MyCRA);	/*  Pulse index. */
-	DEBIwrite(dev, k->MyCRA, (uint16_t) (cra ^ CRAMSK_INDXPOL_A));
-	DEBUG("PulseIndex_A: pulse index step1\n");
-	DEBIwrite(dev, k->MyCRA, cra);
+		/* enable interrupt test */
+		/*  writel(IRQ_GPIO3 | IRQ_RPS1,devpriv->base_addr+P_IER); */
+	}
+
+	return 1;
 }
 
-static void PulseIndex_B(struct comedi_device *dev, struct enc_private *k)
+static void s626_detach(struct comedi_device *dev)
 {
-	register uint16_t crb;
+	if (devpriv) {
+		/* stop ai_command */
+		devpriv->ai_cmd_running = 0;
 
-	crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL;	/*  Pulse index. */
-	DEBIwrite(dev, k->MyCRB, (uint16_t) (crb ^ CRBMSK_INDXPOL_B));
-	DEBIwrite(dev, k->MyCRB, crb);
-}
+		if (devpriv->base_addr) {
+			/* interrupt mask */
+			WR7146(P_IER, 0);	/*  Disable master interrupt. */
+			WR7146(P_ISR, IRQ_GPIO3 | IRQ_RPS1);	/*  Clear board's IRQ status flag. */
 
-/*  Write value into counter preload register. */
+			/*  Disable the watchdog timer and battery charger. */
+			WriteMISC2(dev, 0);
 
-static void Preload(struct comedi_device *dev, struct enc_private *k,
-		    uint32_t value)
-{
-	DEBUG("Preload: preload enter\n");
-	DEBIwrite(dev, (uint16_t) (k->MyLatchLsw), (uint16_t) value);	/*  Write value to preload register. */
-	DEBUG("Preload: preload step 1\n");
-	DEBIwrite(dev, (uint16_t) (k->MyLatchLsw + 2),
-		  (uint16_t) (value >> 16));
-}
+			/*  Close all interfaces on 7146 device. */
+			WR7146(P_MC1, MC1_SHUTDOWN);
+			WR7146(P_ACON1, ACON1_BASE);
 
-static void CountersInit(struct comedi_device *dev)
-{
-	int chan;
-	struct enc_private *k;
-	uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) |	/*  Preload upon */
-	    /*  index. */
-	    (INDXSRC_SOFT << BF_INDXSRC) |	/*  Disable hardware index. */
-	    (CLKSRC_COUNTER << BF_CLKSRC) |	/*  Operating mode is counter. */
-	    (CLKPOL_POS << BF_CLKPOL) |	/*  Active high clock. */
-	    (CNTDIR_UP << BF_CLKPOL) |	/*  Count direction is up. */
-	    (CLKMULT_1X << BF_CLKMULT) |	/*  Clock multiplier is 1x. */
-	    (CLKENAB_INDEX << BF_CLKENAB);	/*  Enabled by index */
+			CloseDMAB(dev, &devpriv->RPSBuf, DMABUF_SIZE);
+			CloseDMAB(dev, &devpriv->ANABuf, DMABUF_SIZE);
+		}
 
-	/*  Disable all counter interrupts and clear any captured counter events. */
-	for (chan = 0; chan < S626_ENCODER_CHANNELS; chan++) {
-		k = &encpriv[chan];
-		k->SetMode(dev, k, Setup, TRUE);
-		k->SetIntSrc(dev, k, 0);
-		k->ResetCapFlags(dev, k);
-		k->SetEnable(dev, k, CLKENAB_ALWAYS);
+		if (dev->irq)
+			free_irq(dev->irq, dev);
+		if (devpriv->base_addr)
+			iounmap(devpriv->base_addr);
+		if (devpriv->pdev) {
+			if (devpriv->got_regions)
+				comedi_pci_disable(devpriv->pdev);
+			pci_dev_put(devpriv->pdev);
+		}
 	}
-	DEBUG("CountersInit: counters initialized\n");
-
 }
 
 static struct comedi_driver s626_driver = {
diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h
index 2d1afec..1796236 100644
--- a/drivers/staging/comedi/drivers/s626.h
+++ b/drivers/staging/comedi/drivers/s626.h
@@ -62,12 +62,6 @@
    comedi_do_insn(cf,&insn); // executing configuration
 */
 
-#ifdef _DEBUG_
-#define DEBUG(...);        printk(__VA_ARGS__);
-#else
-#define DEBUG(...)
-#endif
-
 #if !defined(TRUE)
 #define TRUE    (1)
 #endif
@@ -76,10 +70,6 @@
 #define FALSE   (0)
 #endif
 
-#if !defined(INLINE)
-#define INLINE static __inline
-#endif
-
 #include<linux/slab.h>
 
 #define S626_SIZE 0x0200
diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c
index 6342bc5..c18314b 100644
--- a/drivers/staging/comedi/drivers/serial2002.c
+++ b/drivers/staging/comedi/drivers/serial2002.c
@@ -47,11 +47,6 @@ struct serial2002_board {
 	const char *name;
 };
 
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct serial2002_board *)dev->board_ptr)
-
 struct serial2002_range_table_t {
 
 	/*  HACK... */
@@ -648,7 +643,7 @@ err_alloc_configs:
 
 		if (result) {
 			if (devpriv->tty) {
-				filp_close(devpriv->tty, 0);
+				filp_close(devpriv->tty, NULL);
 				devpriv->tty = NULL;
 			}
 		}
@@ -658,8 +653,8 @@ err_alloc_configs:
 
 static void serial_2002_close(struct comedi_device *dev)
 {
-	if (!IS_ERR(devpriv->tty) && (devpriv->tty != 0))
-		filp_close(devpriv->tty, 0);
+	if (!IS_ERR(devpriv->tty) && devpriv->tty)
+		filp_close(devpriv->tty, NULL);
 }
 
 static int serial2002_di_rinsn(struct comedi_device *dev,
@@ -783,21 +778,24 @@ static int serial2002_ei_rinsn(struct comedi_device *dev,
 static int serial2002_attach(struct comedi_device *dev,
 			     struct comedi_devconfig *it)
 {
+	const struct serial2002_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
+	int ret;
 
-	dev_dbg(dev->hw_dev, "comedi%d: attached\n", dev->minor);
-	dev->board_name = thisboard->name;
+	dev_dbg(dev->class_dev, "serial2002: attach\n");
+	dev->board_name = board->name;
 	if (alloc_private(dev, sizeof(struct serial2002_private)) < 0)
 		return -ENOMEM;
 	dev->open = serial_2002_open;
 	dev->close = serial_2002_close;
 	devpriv->port = it->options[0];
 	devpriv->speed = it->options[1];
-	dev_dbg(dev->hw_dev, "/dev/ttyS%d @ %d\n", devpriv->port,
+	dev_dbg(dev->class_dev, "/dev/ttyS%d @ %d\n", devpriv->port,
 		devpriv->speed);
 
-	if (alloc_subdevices(dev, 5) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 5);
+	if (ret)
+		return ret;
 
 	/* digital input subdevice */
 	s = dev->subdevices + 0;
@@ -823,7 +821,7 @@ static int serial2002_attach(struct comedi_device *dev,
 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
 	s->n_chan = 0;
 	s->maxdata = 1;
-	s->range_table = 0;
+	s->range_table = NULL;
 	s->insn_read = &serial2002_ai_rinsn;
 
 	/* analog output subdevice */
@@ -832,7 +830,7 @@ static int serial2002_attach(struct comedi_device *dev,
 	s->subdev_flags = SDF_WRITEABLE;
 	s->n_chan = 0;
 	s->maxdata = 1;
-	s->range_table = 0;
+	s->range_table = NULL;
 	s->insn_write = &serial2002_ao_winsn;
 	s->insn_read = &serial2002_ao_rinsn;
 
@@ -842,7 +840,7 @@ static int serial2002_attach(struct comedi_device *dev,
 	s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
 	s->n_chan = 0;
 	s->maxdata = 1;
-	s->range_table = 0;
+	s->range_table = NULL;
 	s->insn_read = &serial2002_ei_rinsn;
 
 	return 1;
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index 7d13ffa..9a68eeb 100644
--- a/drivers/staging/comedi/drivers/skel.c
+++ b/drivers/staging/comedi/drivers/skel.c
@@ -210,6 +210,7 @@ static int skel_ns_to_timer(unsigned int *ns, int round);
 static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct comedi_subdevice *s;
+	int ret;
 
 	pr_info("comedi%d: skel: ", dev->minor);
 
@@ -233,12 +234,9 @@ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	if (alloc_private(dev, sizeof(struct skel_private)) < 0)
 		return -ENOMEM;
 
-/*
- * Allocate the subdevice structures.  alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
-	if (alloc_subdevices(dev, 3) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 3);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* dev->read_subdev=s; */
@@ -563,9 +561,6 @@ static int skel_dio_insn_bits(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_insn *insn, unsigned int *data)
 {
-	if (insn->n != 2)
-		return -EINVAL;
-
 	/* The insn data is a mask in data[0] and the new data
 	 * in data[1], each channel cooresponding to a bit. */
 	if (data[0]) {
@@ -582,7 +577,7 @@ static int skel_dio_insn_bits(struct comedi_device *dev,
 	 * it was a purely digital output subdevice */
 	/* data[1]=s->state; */
 
-	return 2;
+	return insn->n;
 }
 
 static int skel_dio_insn_config(struct comedi_device *dev,
@@ -616,7 +611,7 @@ static int skel_dio_insn_config(struct comedi_device *dev,
 	return insn->n;
 }
 
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_PCI_DRIVERS
 static int __devinit driver_skel_pci_probe(struct pci_dev *dev,
 					   const struct pci_device_id *ent)
 {
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index 16c4f5a..84b9f2a 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -59,17 +59,6 @@ struct dnp_board {
 	int have_dio;
 };
 
-/* Useful for shorthand access to the particular board structure ----------- */
-#define thisboard ((const struct dnp_board *)dev->board_ptr)
-
-/* This structure is for data unique to the DNP driver --------------------- */
-struct dnp_private_data {
-
-};
-
-/* Shorthand macro for faster access to the private data ------------------- */
-#define devpriv ((dnp_private *)dev->private)
-
 /* ------------------------------------------------------------------------- */
 /* The insn_bits interface allows packed reading/writing of DIO channels.    */
 /* The comedi core can convert between insn_bits and insn_read/write, so you */
@@ -80,10 +69,6 @@ static int dnp_dio_insn_bits(struct comedi_device *dev,
 			     struct comedi_subdevice *s,
 			     struct comedi_insn *insn, unsigned int *data)
 {
-
-	if (insn->n != 2)
-		return -EINVAL;	/* insn uses data[0] and data[1]     */
-
 	/* The insn data is a mask in data[0] and the new data in data[1],   */
 	/* each channel cooresponding to a bit.                              */
 
@@ -117,7 +102,7 @@ static int dnp_dio_insn_bits(struct comedi_device *dev,
 	outb(PCDR, CSCIR);
 	data[0] += ((inb(CSCDR) & 0xF0) << 12);
 
-	return 2;
+	return insn->n;
 
 }
 
@@ -188,29 +173,17 @@ static int dnp_dio_insn_config(struct comedi_device *dev,
 
 static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
+	const struct dnp_board *board = comedi_board(dev);
 	struct comedi_subdevice *s;
+	int ret;
 
 	printk(KERN_INFO "comedi%d: dnp: ", dev->minor);
 
-	/* Autoprobing: this should find out which board we have. Currently  */
-	/* only the 1486 board is supported and autoprobing is not           */
-	/* implemented :-)                                                   */
-	/* dev->board_ptr = dnp_probe(dev); */
-
-	/* Initialize the name of the board.                                 */
-	/* We can use the "thisboard" macro now.                             */
-	dev->board_name = thisboard->name;
-
-	/* Allocate the private structure area. alloc_private() is a         */
-	/* convenient macro defined in comedidev.h.                          */
-	if (alloc_private(dev, sizeof(struct dnp_private_data)) < 0)
-		return -ENOMEM;
-
-	/* Allocate the subdevice structures. alloc_subdevice() is a         */
-	/* convenient macro defined in comedidev.h.                          */
+	dev->board_name = board->name;
 
-	if (alloc_subdevices(dev, 1) < 0)
-		return -ENOMEM;
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret)
+		return ret;
 
 	s = dev->subdevices + 0;
 	/* digital i/o subdevice                                             */
diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c
index d5f1f22..9f1fdec 100644
--- a/drivers/staging/comedi/drivers/unioxx5.c
+++ b/drivers/staging/comedi/drivers/unioxx5.c
@@ -443,6 +443,7 @@ static int unioxx5_attach(struct comedi_device *dev,
 {
 	int iobase, i, n_subd;
 	int id, num, ba;
+	int ret;
 
 	iobase = it->options[0];
 
@@ -468,10 +469,9 @@ static int unioxx5_attach(struct comedi_device *dev,
 		return -1;
 	}
 
-	if (alloc_subdevices(dev, n_subd) < 0) {
-		printk(KERN_ERR "out of memory\n");
-		return -ENOMEM;
-	}
+	ret = comedi_alloc_subdevices(dev, n_subd);
+	if (ret)
+		return ret;
 
 	/* initializing each of for same subdevices */
 	for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) {
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 13d9fd3..848c7ec 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -1,6 +1,3 @@
-#define DRIVER_VERSION "v2.4"
-#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
-#define DRIVER_DESC "Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com"
 /*
    comedi/drivers/usbdux.c
    Copyright (C) 2003-2007 Bernd Porr, Bernd.Porr@f2s.com
@@ -101,8 +98,6 @@ sampling rate. If you sample two channels you get 4kHz and so on.
 
 #include "../comedidev.h"
 
-#define BOARDNAME "usbdux"
-
 /* timeout for the USB-transfer in ms*/
 #define BULK_TIMEOUT 1000
 
@@ -317,8 +312,6 @@ static struct usbduxsub usbduxsub[NUMUSBDUX];
 
 static DEFINE_SEMAPHORE(start_stop_sem);
 
-static struct comedi_driver driver_usbdux;	/* see below for initializer */
-
 /*
  * Stops the data acquision
  * It should be safe to call this function from any context
@@ -1780,9 +1773,6 @@ static int usbdux_dio_insn_bits(struct comedi_device *dev,
 	if (!this_usbduxsub)
 		return -EFAULT;
 
-	if (insn->n != 2)
-		return -EINVAL;
-
 	down(&this_usbduxsub->sem);
 
 	if (!(this_usbduxsub->probed)) {
@@ -1812,7 +1802,7 @@ static int usbdux_dio_insn_bits(struct comedi_device *dev,
 
 	data[1] = le16_to_cpu(this_usbduxsub->insnBuffer[1]);
 	up(&this_usbduxsub->sem);
-	return 2;
+	return insn->n;
 }
 
 /* reads the 4 counters, only two are used just now */
@@ -2302,6 +2292,231 @@ static void tidy_up(struct usbduxsub *usbduxsub_tmp)
 	usbduxsub_tmp->pwm_cmd_running = 0;
 }
 
+/* common part of attach and attach_usb */
+static int usbdux_attach_common(struct comedi_device *dev,
+				struct usbduxsub *udev,
+				void *aux_data, int aux_len)
+{
+	int ret;
+	struct comedi_subdevice *s = NULL;
+	int n_subdevs;
+
+	down(&udev->sem);
+	/* pointer back to the corresponding comedi device */
+	udev->comedidev = dev;
+
+	/* trying to upload the firmware into the chip */
+	if (aux_data)
+		firmwareUpload(udev, aux_data, aux_len);
+
+	dev->board_name = "usbdux";
+
+	/* set number of subdevices */
+	if (udev->high_speed) {
+		/* with pwm */
+		n_subdevs = 5;
+	} else {
+		/* without pwm */
+		n_subdevs = 4;
+	}
+
+	ret = comedi_alloc_subdevices(dev, n_subdevs);
+	if (ret) {
+		up(&udev->sem);
+		return ret;
+	}
+
+	/* private structure is also simply the usb-structure */
+	dev->private = udev;
+
+	/* the first subdevice is the A/D converter */
+	s = dev->subdevices + SUBDEV_AD;
+	/* the URBs get the comedi subdevice */
+	/* which is responsible for reading */
+	/* this is the subdevice which reads data */
+	dev->read_subdev = s;
+	/* the subdevice receives as private structure the */
+	/* usb-structure */
+	s->private = NULL;
+	/* analog input */
+	s->type = COMEDI_SUBD_AI;
+	/* readable and ref is to ground */
+	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
+	/* 8 channels */
+	s->n_chan = 8;
+	/* length of the channellist */
+	s->len_chanlist = 8;
+	/* callback functions */
+	s->insn_read = usbdux_ai_insn_read;
+	s->do_cmdtest = usbdux_ai_cmdtest;
+	s->do_cmd = usbdux_ai_cmd;
+	s->cancel = usbdux_ai_cancel;
+	/* max value from the A/D converter (12bit) */
+	s->maxdata = 0xfff;
+	/* range table to convert to physical units */
+	s->range_table = (&range_usbdux_ai_range);
+
+	/* analog out */
+	s = dev->subdevices + SUBDEV_DA;
+	/* analog out */
+	s->type = COMEDI_SUBD_AO;
+	/* backward pointer */
+	dev->write_subdev = s;
+	/* the subdevice receives as private structure the */
+	/* usb-structure */
+	s->private = NULL;
+	/* are writable */
+	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
+	/* 4 channels */
+	s->n_chan = 4;
+	/* length of the channellist */
+	s->len_chanlist = 4;
+	/* 12 bit resolution */
+	s->maxdata = 0x0fff;
+	/* bipolar range */
+	s->range_table = (&range_usbdux_ao_range);
+	/* callback */
+	s->do_cmdtest = usbdux_ao_cmdtest;
+	s->do_cmd = usbdux_ao_cmd;
+	s->cancel = usbdux_ao_cancel;
+	s->insn_read = usbdux_ao_insn_read;
+	s->insn_write = usbdux_ao_insn_write;
+
+	/* digital I/O */
+	s = dev->subdevices + SUBDEV_DIO;
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 8;
+	s->maxdata = 1;
+	s->range_table = (&range_digital);
+	s->insn_bits = usbdux_dio_insn_bits;
+	s->insn_config = usbdux_dio_insn_config;
+	/* we don't use it */
+	s->private = NULL;
+
+	/* counter */
+	s = dev->subdevices + SUBDEV_COUNTER;
+	s->type = COMEDI_SUBD_COUNTER;
+	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+	s->n_chan = 4;
+	s->maxdata = 0xFFFF;
+	s->insn_read = usbdux_counter_read;
+	s->insn_write = usbdux_counter_write;
+	s->insn_config = usbdux_counter_config;
+
+	if (udev->high_speed) {
+		/* timer / pwm */
+		s = dev->subdevices + SUBDEV_PWM;
+		s->type = COMEDI_SUBD_PWM;
+		s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
+		s->n_chan = 8;
+		/* this defines the max duty cycle resolution */
+		s->maxdata = udev->sizePwmBuf;
+		s->insn_write = usbdux_pwm_write;
+		s->insn_read = usbdux_pwm_read;
+		s->insn_config = usbdux_pwm_config;
+		usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
+	}
+	/* finally decide that it's attached */
+	udev->attached = 1;
+
+	up(&udev->sem);
+
+	dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n",
+		 dev->minor);
+
+	return 0;
+}
+
+/* is called when comedi-config is called */
+static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	int ret;
+	int index;
+	int i;
+	void *aux_data;
+	int aux_len;
+
+	dev->private = NULL;
+
+	aux_data = comedi_aux_data(it->options, 0);
+	aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
+	if (aux_data == NULL)
+		aux_len = 0;
+	else if (aux_len == 0)
+		aux_data = NULL;
+
+	down(&start_stop_sem);
+	/* find a valid device which has been detected by the probe function of
+	 * the usb */
+	index = -1;
+	for (i = 0; i < NUMUSBDUX; i++) {
+		if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
+			index = i;
+			break;
+		}
+	}
+
+	if (index < 0) {
+		printk(KERN_ERR
+		       "comedi%d: usbdux: error: attach failed, no usbdux devs connected to the usb bus.\n",
+		       dev->minor);
+		ret = -ENODEV;
+	} else
+		ret = usbdux_attach_common(dev, &usbduxsub[index],
+					   aux_data, aux_len);
+	up(&start_stop_sem);
+	return ret;
+}
+
+/* is called from comedi_usb_auto_config() */
+static int usbdux_attach_usb(struct comedi_device *dev,
+			     struct usb_interface *uinterf)
+{
+	int ret;
+	struct usbduxsub *this_usbduxsub;
+
+	dev->private = NULL;
+
+	down(&start_stop_sem);
+	this_usbduxsub = usb_get_intfdata(uinterf);
+	if (!this_usbduxsub || !this_usbduxsub->probed) {
+		printk(KERN_ERR
+		       "comedi%d: usbdux: error: attach_usb failed, not connected\n",
+		       dev->minor);
+		ret = -ENODEV;
+	} else if (this_usbduxsub->attached) {
+		printk(KERN_ERR
+		       "comedi%d: usbdux: error: attach_usb failed, already attached\n",
+		       dev->minor);
+		ret = -ENODEV;
+	} else
+		ret = usbdux_attach_common(dev, this_usbduxsub, NULL, 0);
+	up(&start_stop_sem);
+	return ret;
+}
+
+static void usbdux_detach(struct comedi_device *dev)
+{
+	struct usbduxsub *usb = dev->private;
+
+	if (usb) {
+		down(&usb->sem);
+		dev->private = NULL;
+		usb->attached = 0;
+		usb->comedidev = NULL;
+		up(&usb->sem);
+	}
+}
+
+static struct comedi_driver usbdux_driver = {
+	.driver_name	= "usbdux",
+	.module		= THIS_MODULE,
+	.attach		= usbdux_attach,
+	.detach		= usbdux_detach,
+	.attach_usb	= usbdux_attach_usb,
+};
+
 static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
 						     void *context)
 {
@@ -2326,14 +2541,13 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
 			"Could not upload firmware (err=%d)\n", ret);
 		goto out;
 	}
-	comedi_usb_auto_config(uinterf, &driver_usbdux);
+	comedi_usb_auto_config(uinterf, &usbdux_driver);
  out:
 	release_firmware(fw);
 }
 
-/* allocate memory for the urbs and initialise them */
-static int usbduxsub_probe(struct usb_interface *uinterf,
-			   const struct usb_device_id *id)
+static int usbdux_usb_probe(struct usb_interface *uinterf,
+			    const struct usb_device_id *id)
 {
 	struct usb_device *udev = interface_to_usbdev(uinterf);
 	struct device *dev = &uinterf->dev;
@@ -2594,7 +2808,7 @@ static int usbduxsub_probe(struct usb_interface *uinterf,
 	return 0;
 }
 
-static void usbduxsub_disconnect(struct usb_interface *intf)
+static void usbdux_usb_disconnect(struct usb_interface *intf)
 {
 	struct usbduxsub *usbduxsub_tmp = usb_get_intfdata(intf);
 	struct usb_device *udev = interface_to_usbdev(intf);
@@ -2617,273 +2831,22 @@ static void usbduxsub_disconnect(struct usb_interface *intf)
 	dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n");
 }
 
-/* common part of attach and attach_usb */
-static int usbdux_attach_common(struct comedi_device *dev,
-				struct usbduxsub *udev,
-				void *aux_data, int aux_len)
-{
-	int ret;
-	struct comedi_subdevice *s = NULL;
-
-	down(&udev->sem);
-	/* pointer back to the corresponding comedi device */
-	udev->comedidev = dev;
-
-	/* trying to upload the firmware into the chip */
-	if (aux_data)
-		firmwareUpload(udev, aux_data, aux_len);
-
-	dev->board_name = BOARDNAME;
-
-	/* set number of subdevices */
-	if (udev->high_speed) {
-		/* with pwm */
-		dev->n_subdevices = 5;
-	} else {
-		/* without pwm */
-		dev->n_subdevices = 4;
-	}
-
-	/* allocate space for the subdevices */
-	ret = alloc_subdevices(dev, dev->n_subdevices);
-	if (ret < 0) {
-		dev_err(&udev->interface->dev,
-			"comedi%d: error alloc space for subdev\n", dev->minor);
-		up(&udev->sem);
-		return ret;
-	}
-
-	/* private structure is also simply the usb-structure */
-	dev->private = udev;
-
-	/* the first subdevice is the A/D converter */
-	s = dev->subdevices + SUBDEV_AD;
-	/* the URBs get the comedi subdevice */
-	/* which is responsible for reading */
-	/* this is the subdevice which reads data */
-	dev->read_subdev = s;
-	/* the subdevice receives as private structure the */
-	/* usb-structure */
-	s->private = NULL;
-	/* analog input */
-	s->type = COMEDI_SUBD_AI;
-	/* readable and ref is to ground */
-	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
-	/* 8 channels */
-	s->n_chan = 8;
-	/* length of the channellist */
-	s->len_chanlist = 8;
-	/* callback functions */
-	s->insn_read = usbdux_ai_insn_read;
-	s->do_cmdtest = usbdux_ai_cmdtest;
-	s->do_cmd = usbdux_ai_cmd;
-	s->cancel = usbdux_ai_cancel;
-	/* max value from the A/D converter (12bit) */
-	s->maxdata = 0xfff;
-	/* range table to convert to physical units */
-	s->range_table = (&range_usbdux_ai_range);
-
-	/* analog out */
-	s = dev->subdevices + SUBDEV_DA;
-	/* analog out */
-	s->type = COMEDI_SUBD_AO;
-	/* backward pointer */
-	dev->write_subdev = s;
-	/* the subdevice receives as private structure the */
-	/* usb-structure */
-	s->private = NULL;
-	/* are writable */
-	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
-	/* 4 channels */
-	s->n_chan = 4;
-	/* length of the channellist */
-	s->len_chanlist = 4;
-	/* 12 bit resolution */
-	s->maxdata = 0x0fff;
-	/* bipolar range */
-	s->range_table = (&range_usbdux_ao_range);
-	/* callback */
-	s->do_cmdtest = usbdux_ao_cmdtest;
-	s->do_cmd = usbdux_ao_cmd;
-	s->cancel = usbdux_ao_cancel;
-	s->insn_read = usbdux_ao_insn_read;
-	s->insn_write = usbdux_ao_insn_write;
-
-	/* digital I/O */
-	s = dev->subdevices + SUBDEV_DIO;
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 8;
-	s->maxdata = 1;
-	s->range_table = (&range_digital);
-	s->insn_bits = usbdux_dio_insn_bits;
-	s->insn_config = usbdux_dio_insn_config;
-	/* we don't use it */
-	s->private = NULL;
-
-	/* counter */
-	s = dev->subdevices + SUBDEV_COUNTER;
-	s->type = COMEDI_SUBD_COUNTER;
-	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-	s->n_chan = 4;
-	s->maxdata = 0xFFFF;
-	s->insn_read = usbdux_counter_read;
-	s->insn_write = usbdux_counter_write;
-	s->insn_config = usbdux_counter_config;
-
-	if (udev->high_speed) {
-		/* timer / pwm */
-		s = dev->subdevices + SUBDEV_PWM;
-		s->type = COMEDI_SUBD_PWM;
-		s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
-		s->n_chan = 8;
-		/* this defines the max duty cycle resolution */
-		s->maxdata = udev->sizePwmBuf;
-		s->insn_write = usbdux_pwm_write;
-		s->insn_read = usbdux_pwm_read;
-		s->insn_config = usbdux_pwm_config;
-		usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
-	}
-	/* finally decide that it's attached */
-	udev->attached = 1;
-
-	up(&udev->sem);
-
-	dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n",
-		 dev->minor);
-
-	return 0;
-}
-
-/* is called when comedi-config is called */
-static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	int ret;
-	int index;
-	int i;
-	void *aux_data;
-	int aux_len;
-
-	dev->private = NULL;
-
-	aux_data = comedi_aux_data(it->options, 0);
-	aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
-	if (aux_data == NULL)
-		aux_len = 0;
-	else if (aux_len == 0)
-		aux_data = NULL;
-
-	down(&start_stop_sem);
-	/* find a valid device which has been detected by the probe function of
-	 * the usb */
-	index = -1;
-	for (i = 0; i < NUMUSBDUX; i++) {
-		if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
-			index = i;
-			break;
-		}
-	}
-
-	if (index < 0) {
-		printk(KERN_ERR
-		       "comedi%d: usbdux: error: attach failed, no usbdux devs connected to the usb bus.\n",
-		       dev->minor);
-		ret = -ENODEV;
-	} else
-		ret = usbdux_attach_common(dev, &usbduxsub[index],
-					   aux_data, aux_len);
-	up(&start_stop_sem);
-	return ret;
-}
-
-/* is called from comedi_usb_auto_config() */
-static int usbdux_attach_usb(struct comedi_device *dev,
-			     struct usb_interface *uinterf)
-{
-	int ret;
-	struct usbduxsub *this_usbduxsub;
-
-	dev->private = NULL;
-
-	down(&start_stop_sem);
-	this_usbduxsub = usb_get_intfdata(uinterf);
-	if (!this_usbduxsub || !this_usbduxsub->probed) {
-		printk(KERN_ERR
-		       "comedi%d: usbdux: error: attach_usb failed, not connected\n",
-		       dev->minor);
-		ret = -ENODEV;
-	} else if (this_usbduxsub->attached) {
-		printk(KERN_ERR
-		       "comedi%d: usbdux: error: attach_usb failed, already attached\n",
-		       dev->minor);
-		ret = -ENODEV;
-	} else
-		ret = usbdux_attach_common(dev, this_usbduxsub, NULL, 0);
-	up(&start_stop_sem);
-	return ret;
-}
-
-static void usbdux_detach(struct comedi_device *dev)
-{
-	struct usbduxsub *usb = dev->private;
-
-	if (usb) {
-		down(&usb->sem);
-		dev->private = NULL;
-		usb->attached = 0;
-		usb->comedidev = NULL;
-		up(&usb->sem);
-	}
-}
-
-/* main driver struct */
-static struct comedi_driver driver_usbdux = {
-	.driver_name = "usbdux",
-	.module = THIS_MODULE,
-	.attach = usbdux_attach,
-	.detach = usbdux_detach,
-	.attach_usb = usbdux_attach_usb,
+static const struct usb_device_id usbdux_usb_table[] = {
+	{ USB_DEVICE(0x13d8, 0x0001) },
+	{ USB_DEVICE(0x13d8, 0x0002) },
+	{ }
 };
 
-/* Table with the USB-devices: just now only testing IDs */
-static const struct usb_device_id usbduxsub_table[] = {
-	{USB_DEVICE(0x13d8, 0x0001)},
-	{USB_DEVICE(0x13d8, 0x0002)},
-	{}			/* Terminating entry */
-};
+MODULE_DEVICE_TABLE(usb, usbdux_usb_table);
 
-MODULE_DEVICE_TABLE(usb, usbduxsub_table);
-
-/* The usbduxsub-driver */
-static struct usb_driver usbduxsub_driver = {
-	.name = BOARDNAME,
-	.probe = usbduxsub_probe,
-	.disconnect = usbduxsub_disconnect,
-	.id_table = usbduxsub_table,
+static struct usb_driver usbdux_usb_driver = {
+	.name		= "usbdux",
+	.probe		= usbdux_usb_probe,
+	.disconnect	= usbdux_usb_disconnect,
+	.id_table	= usbdux_usb_table,
 };
+module_comedi_usb_driver(usbdux_driver, usbdux_usb_driver);
 
-/* Can't use the nice macro as I have also to initialise the USB */
-/* subsystem: */
-/* registering the usb-system _and_ the comedi-driver */
-static int __init init_usbdux(void)
-{
-	printk(KERN_INFO KBUILD_MODNAME ": "
-	       DRIVER_VERSION ":" DRIVER_DESC "\n");
-	usb_register(&usbduxsub_driver);
-	comedi_driver_register(&driver_usbdux);
-	return 0;
-}
-
-/* deregistering the comedi driver and the usb-subsystem */
-static void __exit exit_usbdux(void)
-{
-	comedi_driver_unregister(&driver_usbdux);
-	usb_deregister(&usbduxsub_driver);
-}
-
-module_init(init_usbdux);
-module_exit(exit_usbdux);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
+MODULE_DESCRIPTION("Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 7b1d21a..d991158 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -49,11 +49,6 @@
 #include "comedi_fc.h"
 #include "../comedidev.h"
 
-#define DRIVER_VERSION "v1.0"
-#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
-#define DRIVER_DESC "USB-DUXfast, BerndPorr@f2s.com"
-#define BOARDNAME "usbduxfast"
-
 /*
  * timeout for the USB-transfer
  */
@@ -127,11 +122,6 @@
 #define NUMUSBDUXFAST	16
 
 /*
- * number of subdevices
- */
-#define N_SUBDEVICES	1
-
-/*
  * analogue in subdevice
  */
 #define SUBDEV_AD	0
@@ -201,8 +191,6 @@ static struct usbduxfastsub_s usbduxfastsub[NUMUSBDUXFAST];
 
 static DEFINE_SEMAPHORE(start_stop_sem);
 
-static struct comedi_driver driver_usbduxfast;	/* see below for initializer */
-
 /*
  * bulk transfers to usbduxfast
  */
@@ -1441,6 +1429,149 @@ static void tidy_up(struct usbduxfastsub_s *udfs)
 	udfs->ai_cmd_running = 0;
 }
 
+/* common part of attach and attach_usb */
+static int usbduxfast_attach_common(struct comedi_device *dev,
+				    struct usbduxfastsub_s *udfs,
+				    void *aux_data, int aux_len)
+{
+	int ret;
+	struct comedi_subdevice *s;
+
+	down(&udfs->sem);
+	/* pointer back to the corresponding comedi device */
+	udfs->comedidev = dev;
+	/* trying to upload the firmware into the chip */
+	if (aux_data)
+		firmwareUpload(udfs, aux_data, aux_len);
+	dev->board_name = "usbduxfast";
+	ret = comedi_alloc_subdevices(dev, 1);
+	if (ret) {
+		up(&udfs->sem);
+		return ret;
+	}
+	/* private structure is also simply the usb-structure */
+	dev->private = udfs;
+	/* the first subdevice is the A/D converter */
+	s = dev->subdevices + SUBDEV_AD;
+	/*
+	 * the URBs get the comedi subdevice which is responsible for reading
+	 * this is the subdevice which reads data
+	 */
+	dev->read_subdev = s;
+	/* the subdevice receives as private structure the usb-structure */
+	s->private = NULL;
+	/* analog input */
+	s->type = COMEDI_SUBD_AI;
+	/* readable and ref is to ground */
+	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
+	/* 16 channels */
+	s->n_chan = 16;
+	/* length of the channellist */
+	s->len_chanlist = 16;
+	/* callback functions */
+	s->insn_read = usbduxfast_ai_insn_read;
+	s->do_cmdtest = usbduxfast_ai_cmdtest;
+	s->do_cmd = usbduxfast_ai_cmd;
+	s->cancel = usbduxfast_ai_cancel;
+	/* max value from the A/D converter (12bit+1 bit for overflow) */
+	s->maxdata = 0x1000;
+	/* range table to convert to physical units */
+	s->range_table = &range_usbduxfast_ai_range;
+	/* finally decide that it's attached */
+	udfs->attached = 1;
+	up(&udfs->sem);
+	dev_info(dev->class_dev, "successfully attached to usbduxfast.\n");
+	return 0;
+}
+
+/* is called for COMEDI_DEVCONFIG ioctl (when comedi_config is run) */
+static int usbduxfast_attach(struct comedi_device *dev,
+			     struct comedi_devconfig *it)
+{
+	int ret;
+	int index;
+	int i;
+	void *aux_data;
+	int aux_len;
+
+	dev->private = NULL;
+
+	aux_data = comedi_aux_data(it->options, 0);
+	aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
+	if (aux_data == NULL)
+		aux_len = 0;
+	else if (aux_len == 0)
+		aux_data = NULL;
+	down(&start_stop_sem);
+	/*
+	 * find a valid device which has been detected by the
+	 * probe function of the usb
+	 */
+	index = -1;
+	for (i = 0; i < NUMUSBDUXFAST; i++) {
+		if (usbduxfastsub[i].probed && !usbduxfastsub[i].attached) {
+			index = i;
+			break;
+		}
+	}
+	if (index < 0) {
+		dev_err(dev->class_dev,
+			"usbduxfast: error: attach failed, no usbduxfast devs connected to the usb bus.\n");
+		ret = -ENODEV;
+	} else
+		ret = usbduxfast_attach_common(dev, &usbduxfastsub[index],
+					       aux_data, aux_len);
+	up(&start_stop_sem);
+	return ret;
+}
+
+/* is called from comedi_usb_auto_config() */
+static int usbduxfast_attach_usb(struct comedi_device *dev,
+				 struct usb_interface *uinterf)
+{
+	int ret;
+	struct usbduxfastsub_s *udfs;
+
+	dev->private = NULL;
+	down(&start_stop_sem);
+	udfs = usb_get_intfdata(uinterf);
+	if (!udfs || !udfs->probed) {
+		dev_err(dev->class_dev,
+			"usbduxfast: error: attach_usb failed, not connected\n");
+		ret = -ENODEV;
+	} else if (udfs->attached) {
+		dev_err(dev->class_dev,
+		       "usbduxfast: error: attach_usb failed, already attached\n");
+		ret = -ENODEV;
+	} else
+		ret = usbduxfast_attach_common(dev, udfs, NULL, 0);
+	up(&start_stop_sem);
+	return ret;
+}
+
+static void usbduxfast_detach(struct comedi_device *dev)
+{
+	struct usbduxfastsub_s *usb = dev->private;
+
+	if (usb) {
+		down(&usb->sem);
+		down(&start_stop_sem);
+		dev->private = NULL;
+		usb->attached = 0;
+		usb->comedidev = NULL;
+		up(&start_stop_sem);
+		up(&usb->sem);
+	}
+}
+
+static struct comedi_driver usbduxfast_driver = {
+	.driver_name	= "usbduxfast",
+	.module		= THIS_MODULE,
+	.attach		= usbduxfast_attach,
+	.detach		= usbduxfast_detach,
+	.attach_usb	= usbduxfast_attach_usb,
+};
+
 static void usbduxfast_firmware_request_complete_handler(const struct firmware
 							 *fw, void *context)
 {
@@ -1463,16 +1594,13 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware
 		goto out;
 	}
 
-	comedi_usb_auto_config(uinterf, &driver_usbduxfast);
+	comedi_usb_auto_config(uinterf, &usbduxfast_driver);
  out:
 	release_firmware(fw);
 }
 
-/*
- * allocate memory for the urbs and initialise them
- */
-static int usbduxfastsub_probe(struct usb_interface *uinterf,
-			       const struct usb_device_id *id)
+static int usbduxfast_usb_probe(struct usb_interface *uinterf,
+				const struct usb_device_id *id)
 {
 	struct usb_device *udev = interface_to_usbdev(uinterf);
 	int i;
@@ -1595,7 +1723,7 @@ static int usbduxfastsub_probe(struct usb_interface *uinterf,
 	return 0;
 }
 
-static void usbduxfastsub_disconnect(struct usb_interface *intf)
+static void usbduxfast_usb_disconnect(struct usb_interface *intf)
 {
 	struct usbduxfastsub_s *udfs = usb_get_intfdata(intf);
 	struct usb_device *udev = interface_to_usbdev(intf);
@@ -1624,183 +1752,25 @@ static void usbduxfastsub_disconnect(struct usb_interface *intf)
 #endif
 }
 
-/*
- * is called when comedi-config is called
- */
-static int usbduxfast_attach(struct comedi_device *dev,
-			     struct comedi_devconfig *it)
-{
-	int ret;
-	int index;
-	int i;
-	struct comedi_subdevice *s = NULL;
-	dev->private = NULL;
-
-	down(&start_stop_sem);
-	/*
-	 * find a valid device which has been detected by the
-	 * probe function of the usb
-	 */
-	index = -1;
-	for (i = 0; i < NUMUSBDUXFAST; i++) {
-		if (usbduxfastsub[i].probed && !usbduxfastsub[i].attached) {
-			index = i;
-			break;
-		}
-	}
-
-	if (index < 0) {
-		printk(KERN_ERR "comedi%d: usbduxfast: error: attach failed, "
-		       "no usbduxfast devs connected to the usb bus.\n",
-		       dev->minor);
-		up(&start_stop_sem);
-		return -ENODEV;
-	}
-
-	down(&(usbduxfastsub[index].sem));
-	/* pointer back to the corresponding comedi device */
-	usbduxfastsub[index].comedidev = dev;
-
-	/* trying to upload the firmware into the chip */
-	if (comedi_aux_data(it->options, 0) &&
-	    it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
-		firmwareUpload(&usbduxfastsub[index],
-			       comedi_aux_data(it->options, 0),
-			       it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
-	}
-
-	dev->board_name = BOARDNAME;
-
-	/* set number of subdevices */
-	dev->n_subdevices = N_SUBDEVICES;
-
-	/* allocate space for the subdevices */
-	ret = alloc_subdevices(dev, N_SUBDEVICES);
-	if (ret < 0) {
-		printk(KERN_ERR "comedi%d: usbduxfast: error alloc space for "
-		       "subdev\n", dev->minor);
-		up(&(usbduxfastsub[index].sem));
-		up(&start_stop_sem);
-		return ret;
-	}
-
-	printk(KERN_INFO "comedi%d: usbduxfast: usb-device %d is attached to "
-	       "comedi.\n", dev->minor, index);
-	/* private structure is also simply the usb-structure */
-	dev->private = usbduxfastsub + index;
-	/* the first subdevice is the A/D converter */
-	s = dev->subdevices + SUBDEV_AD;
-	/*
-	 * the URBs get the comedi subdevice which is responsible for reading
-	 * this is the subdevice which reads data
-	 */
-	dev->read_subdev = s;
-	/* the subdevice receives as private structure the usb-structure */
-	s->private = NULL;
-	/* analog input */
-	s->type = COMEDI_SUBD_AI;
-	/* readable and ref is to ground */
-	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
-	/* 16 channels */
-	s->n_chan = 16;
-	/* length of the channellist */
-	s->len_chanlist = 16;
-	/* callback functions */
-	s->insn_read = usbduxfast_ai_insn_read;
-	s->do_cmdtest = usbduxfast_ai_cmdtest;
-	s->do_cmd = usbduxfast_ai_cmd;
-	s->cancel = usbduxfast_ai_cancel;
-	/* max value from the A/D converter (12bit+1 bit for overflow) */
-	s->maxdata = 0x1000;
-	/* range table to convert to physical units */
-	s->range_table = &range_usbduxfast_ai_range;
-
-	/* finally decide that it's attached */
-	usbduxfastsub[index].attached = 1;
-
-	up(&(usbduxfastsub[index].sem));
-	up(&start_stop_sem);
-	printk(KERN_INFO "comedi%d: successfully attached to usbduxfast.\n",
-	       dev->minor);
-
-	return 0;
-}
-
-static void usbduxfast_detach(struct comedi_device *dev)
-{
-	struct usbduxfastsub_s *usb = dev->private;
-
-	if (usb) {
-		down(&usb->sem);
-		down(&start_stop_sem);
-		dev->private = NULL;
-		usb->attached = 0;
-		usb->comedidev = NULL;
-		up(&start_stop_sem);
-		up(&usb->sem);
-	}
-}
-
-/*
- * main driver struct
- */
-static struct comedi_driver driver_usbduxfast = {
-	.driver_name = "usbduxfast",
-	.module = THIS_MODULE,
-	.attach = usbduxfast_attach,
-	.detach = usbduxfast_detach
-};
-
-/*
- * Table with the USB-devices: just now only testing IDs
- */
-static const struct usb_device_id usbduxfastsub_table[] = {
+static const struct usb_device_id usbduxfast_usb_table[] = {
 	/* { USB_DEVICE(0x4b4, 0x8613) }, testing */
-	{USB_DEVICE(0x13d8, 0x0010)},	/* real ID */
-	{USB_DEVICE(0x13d8, 0x0011)},	/* real ID */
-	{}			/* Terminating entry */
+	{ USB_DEVICE(0x13d8, 0x0010) },	/* real ID */
+	{ USB_DEVICE(0x13d8, 0x0011) },	/* real ID */
+	{ }
 };
+MODULE_DEVICE_TABLE(usb, usbduxfast_usb_table);
 
-MODULE_DEVICE_TABLE(usb, usbduxfastsub_table);
-
-/*
- * The usbduxfastsub-driver
- */
-static struct usb_driver usbduxfastsub_driver = {
+static struct usb_driver usbduxfast_usb_driver = {
 #ifdef COMEDI_HAVE_USB_DRIVER_OWNER
-	.owner = THIS_MODULE,
+	.owner		= THIS_MODULE,
 #endif
-	.name = BOARDNAME,
-	.probe = usbduxfastsub_probe,
-	.disconnect = usbduxfastsub_disconnect,
-	.id_table = usbduxfastsub_table
+	.name		= "usbduxfast",
+	.probe		= usbduxfast_usb_probe,
+	.disconnect	= usbduxfast_usb_disconnect,
+	.id_table	= usbduxfast_usb_table,
 };
+module_comedi_usb_driver(usbduxfast_driver, usbduxfast_usb_driver);
 
-/*
- * Can't use the nice macro as I have also to initialise the USB subsystem:
- * registering the usb-system _and_ the comedi-driver
- */
-static int __init init_usbduxfast(void)
-{
-	printk(KERN_INFO
-	       KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n");
-	usb_register(&usbduxfastsub_driver);
-	comedi_driver_register(&driver_usbduxfast);
-	return 0;
-}
-
-/*
- * deregistering the comedi driver and the usb-subsystem
- */
-static void __exit exit_usbduxfast(void)
-{
-	comedi_driver_unregister(&driver_usbduxfast);
-	usb_deregister(&usbduxfastsub_driver);
-}
-
-module_init(init_usbduxfast);
-module_exit(exit_usbduxfast);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
+MODULE_DESCRIPTION("USB-DUXfast, BerndPorr@f2s.com");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index 465afbd..543e604 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -1,6 +1,3 @@
-#define DRIVER_VERSION "v0.6"
-#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
-#define DRIVER_DESC "Stirling/ITL USB-DUX SIGMA -- Bernd.Porr@f2s.com"
 /*
    comedi/drivers/usbdux.c
    Copyright (C) 2011 Bernd Porr, Bernd.Porr@f2s.com
@@ -62,8 +59,6 @@ Status: testing
 #include "comedi_fc.h"
 #include "../comedidev.h"
 
-#define BOARDNAME "usbduxsigma"
-
 /* timeout for the USB-transfer in ms*/
 #define BULK_TIMEOUT 1000
 
@@ -267,8 +262,6 @@ static struct usbduxsub usbduxsub[NUMUSBDUX];
 
 static DEFINE_SEMAPHORE(start_stop_sem);
 
-static struct comedi_driver driver_usbduxsigma;	/* see below for initializer */
-
 /*
  * Stops the data acquision
  * It should be safe to call this function from any context
@@ -1358,7 +1351,7 @@ static int usbdux_ai_insn_read(struct comedi_device *dev,
 		/* 32 bits big endian from the A/D converter */
 		one = be32_to_cpu(*((int32_t *)
 				    ((this_usbduxsub->insnBuffer)+1)));
-		/* mask out the staus byte */
+		/* mask out the status byte */
 		one = one & 0x00ffffff;
 		/* turn it into an unsigned integer */
 		one = one ^ 0x00800000;
@@ -1845,9 +1838,6 @@ static int usbdux_dio_insn_bits(struct comedi_device *dev,
 	if (!this_usbduxsub)
 		return -EFAULT;
 
-	if (insn->n != 2)
-		return -EINVAL;
-
 	down(&this_usbduxsub->sem);
 
 	if (!(this_usbduxsub->probed)) {
@@ -1887,7 +1877,7 @@ static int usbdux_dio_insn_bits(struct comedi_device *dev,
 	s->state = data[1];
 
 	up(&this_usbduxsub->sem);
-	return 2;
+	return insn->n;
 }
 
 /***********************************/
@@ -2310,6 +2300,209 @@ static void tidy_up(struct usbduxsub *usbduxsub_tmp)
 	usbduxsub_tmp->pwm_cmd_running = 0;
 }
 
+/* common part of attach and attach_usb */
+static int usbduxsigma_attach_common(struct comedi_device *dev,
+				     struct usbduxsub *uds,
+				     void *aux_data, int aux_len)
+{
+	int ret;
+	struct comedi_subdevice *s;
+	int n_subdevs;
+	int offset;
+
+	down(&uds->sem);
+	/* pointer back to the corresponding comedi device */
+	uds->comedidev = dev;
+	/* trying to upload the firmware into the FX2 */
+	if (aux_data)
+		firmwareUpload(uds, aux_data, aux_len);
+	dev->board_name = "usbduxsigma";
+	/* set number of subdevices */
+	if (uds->high_speed)
+		n_subdevs = 4;	/* with pwm */
+	else
+		n_subdevs = 3;	/* without pwm */
+	ret = comedi_alloc_subdevices(dev, n_subdevs);
+	if (ret) {
+		up(&uds->sem);
+		return ret;
+	}
+	/* private structure is also simply the usb-structure */
+	dev->private = uds;
+	/* the first subdevice is the A/D converter */
+	s = dev->subdevices + SUBDEV_AD;
+	/* the URBs get the comedi subdevice */
+	/* which is responsible for reading */
+	/* this is the subdevice which reads data */
+	dev->read_subdev = s;
+	/* the subdevice receives as private structure the */
+	/* usb-structure */
+	s->private = NULL;
+	/* analog input */
+	s->type = COMEDI_SUBD_AI;
+	/* readable and ref is to ground, 32 bit wide data! */
+	s->subdev_flags = SDF_READABLE | SDF_GROUND |
+		SDF_CMD_READ | SDF_LSAMPL;
+	/* 16 A/D channels */
+	s->n_chan = NUMCHANNELS;
+	/* length of the channellist */
+	s->len_chanlist = NUMCHANNELS;
+	/* callback functions */
+	s->insn_read = usbdux_ai_insn_read;
+	s->do_cmdtest = usbdux_ai_cmdtest;
+	s->do_cmd = usbdux_ai_cmd;
+	s->cancel = usbdux_ai_cancel;
+	/* max value from the A/D converter (24bit) */
+	s->maxdata = 0x00FFFFFF;
+	/* range table to convert to physical units */
+	s->range_table = (&range_usbdux_ai_range);
+	/* analog output subdevice */
+	s = dev->subdevices + SUBDEV_DA;
+	/* analog out */
+	s->type = COMEDI_SUBD_AO;
+	/* backward pointer */
+	dev->write_subdev = s;
+	/* the subdevice receives as private structure the */
+	/* usb-structure */
+	s->private = NULL;
+	/* are writable */
+	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
+	/* 4 channels */
+	s->n_chan = 4;
+	/* length of the channellist */
+	s->len_chanlist = 4;
+	/* 8 bit resolution */
+	s->maxdata = 0x00ff;
+	/* unipolar range */
+	s->range_table = (&range_usbdux_ao_range);
+	/* callback */
+	s->do_cmdtest = usbdux_ao_cmdtest;
+	s->do_cmd = usbdux_ao_cmd;
+	s->cancel = usbdux_ao_cancel;
+	s->insn_read = usbdux_ao_insn_read;
+	s->insn_write = usbdux_ao_insn_write;
+	/* digital I/O subdevice */
+	s = dev->subdevices + SUBDEV_DIO;
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	/* 8 external and 16 internal channels */
+	s->n_chan = 24;
+	s->maxdata = 1;
+	s->range_table = (&range_digital);
+	s->insn_bits = usbdux_dio_insn_bits;
+	s->insn_config = usbdux_dio_insn_config;
+	/* we don't use it */
+	s->private = NULL;
+	if (uds->high_speed) {
+		/* timer / pwm subdevice */
+		s = dev->subdevices + SUBDEV_PWM;
+		s->type = COMEDI_SUBD_PWM;
+		s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
+		s->n_chan = 8;
+		/* this defines the max duty cycle resolution */
+		s->maxdata = uds->sizePwmBuf;
+		s->insn_write = usbdux_pwm_write;
+		s->insn_read = usbdux_pwm_read;
+		s->insn_config = usbdux_pwm_config;
+		usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
+	}
+	/* finally decide that it's attached */
+	uds->attached = 1;
+	up(&uds->sem);
+	offset = usbdux_getstatusinfo(dev, 0);
+	if (offset < 0)
+		dev_err(&uds->interface->dev,
+			"Communication to USBDUXSIGMA failed! Check firmware and cabling.");
+	dev_info(&uds->interface->dev,
+		 "comedi%d: attached, ADC_zero = %x\n", dev->minor, offset);
+	return 0;
+}
+
+/* is called for COMEDI_DEVCONFIG ioctl (when comedi_config is run) */
+static int usbduxsigma_attach(struct comedi_device *dev,
+			      struct comedi_devconfig *it)
+{
+	int ret;
+	int index;
+	int i;
+	void *aux_data;
+	int aux_len;
+
+	dev->private = NULL;
+
+	aux_data = comedi_aux_data(it->options, 0);
+	aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
+	if (aux_data == NULL)
+		aux_len = 0;
+	else if (aux_len == 0)
+		aux_data = NULL;
+
+	down(&start_stop_sem);
+	/* find a valid device which has been detected by the probe function of
+	 * the usb */
+	index = -1;
+	for (i = 0; i < NUMUSBDUX; i++) {
+		if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
+			index = i;
+			break;
+		}
+	}
+	if (index < 0) {
+		dev_err(dev->class_dev,
+			"usbduxsigma: error: attach failed, dev not connected to the usb bus.\n");
+		ret = -ENODEV;
+	} else
+		ret = usbduxsigma_attach_common(dev, &usbduxsub[index],
+						aux_data, aux_len);
+	up(&start_stop_sem);
+	return ret;
+}
+
+/* is called from comedi_usb_auto_config() */
+static int usbduxsigma_attach_usb(struct comedi_device *dev,
+				  struct usb_interface *uinterf)
+{
+	int ret;
+	struct usbduxsub *uds;
+
+	dev->private = NULL;
+	down(&start_stop_sem);
+	uds = usb_get_intfdata(uinterf);
+	if (!uds || !uds->probed) {
+		dev_err(dev->class_dev,
+			"usbduxsigma: error: attach_usb failed, not connected\n");
+		ret = -ENODEV;
+	} else if (uds->attached) {
+		dev_err(dev->class_dev,
+		       "usbduxsigma: error: attach_usb failed, already attached\n");
+		ret = -ENODEV;
+	} else
+		ret = usbduxsigma_attach_common(dev, uds, NULL, 0);
+	up(&start_stop_sem);
+	return ret;
+}
+
+static void usbduxsigma_detach(struct comedi_device *dev)
+{
+	struct usbduxsub *usb = dev->private;
+
+	if (usb) {
+		down(&usb->sem);
+		dev->private = NULL;
+		usb->attached = 0;
+		usb->comedidev = NULL;
+		up(&usb->sem);
+	}
+}
+
+static struct comedi_driver usbduxsigma_driver = {
+	.driver_name	= "usbduxsigma",
+	.module		= THIS_MODULE,
+	.attach		= usbduxsigma_attach,
+	.detach		= usbduxsigma_detach,
+	.attach_usb	= usbduxsigma_attach_usb,
+};
+
 static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
 						     void *context)
 {
@@ -2334,14 +2527,13 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
 			"Could not upload firmware (err=%d)\n", ret);
 		goto out;
 	}
-	comedi_usb_auto_config(uinterf, &driver_usbduxsigma);
+	comedi_usb_auto_config(uinterf, &usbduxsigma_driver);
 out:
 	release_firmware(fw);
 }
 
-/* allocate memory for the urbs and initialise them */
-static int usbduxsigma_probe(struct usb_interface *uinterf,
-			   const struct usb_device_id *id)
+static int usbduxsigma_usb_probe(struct usb_interface *uinterf,
+				 const struct usb_device_id *id)
 {
 	struct usb_device *udev = interface_to_usbdev(uinterf);
 	struct device *dev = &uinterf->dev;
@@ -2605,7 +2797,7 @@ static int usbduxsigma_probe(struct usb_interface *uinterf,
 	return 0;
 }
 
-static void usbduxsigma_disconnect(struct usb_interface *intf)
+static void usbduxsigma_usb_disconnect(struct usb_interface *intf)
 {
 	struct usbduxsub *usbduxsub_tmp = usb_get_intfdata(intf);
 	struct usb_device *udev = interface_to_usbdev(intf);
@@ -2634,234 +2826,22 @@ static void usbduxsigma_disconnect(struct usb_interface *intf)
 	dev_info(&intf->dev, "comedi_: disconnected from the usb\n");
 }
 
-/* is called when comedi-config is called */
-static int usbduxsigma_attach(struct comedi_device *dev,
-			      struct comedi_devconfig *it)
-{
-	int ret;
-	int index;
-	int i;
-	struct usbduxsub *udev;
-
-	int offset;
-
-	struct comedi_subdevice *s = NULL;
-	dev->private = NULL;
-
-	down(&start_stop_sem);
-	/* find a valid device which has been detected by the probe function of
-	 * the usb */
-	index = -1;
-	for (i = 0; i < NUMUSBDUX; i++) {
-		if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
-			index = i;
-			break;
-		}
-	}
-
-	if (index < 0) {
-		printk(KERN_ERR "comedi%d: usbduxsigma: error: attach failed,"
-		       "dev not connected to the usb bus.\n", dev->minor);
-		up(&start_stop_sem);
-		return -ENODEV;
-	}
-
-	udev = &usbduxsub[index];
-	down(&udev->sem);
-	/* pointer back to the corresponding comedi device */
-	udev->comedidev = dev;
-
-	/* trying to upload the firmware into the FX2 */
-	if (comedi_aux_data(it->options, 0) &&
-	    it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
-		firmwareUpload(udev, comedi_aux_data(it->options, 0),
-			       it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
-	}
-
-	dev->board_name = BOARDNAME;
-
-	/* set number of subdevices */
-	if (udev->high_speed) {
-		/* with pwm */
-		dev->n_subdevices = 4;
-	} else {
-		/* without pwm */
-		dev->n_subdevices = 3;
-	}
-
-	/* allocate space for the subdevices */
-	ret = alloc_subdevices(dev, dev->n_subdevices);
-	if (ret < 0) {
-		dev_err(&udev->interface->dev,
-			"comedi%d: no space for subdev\n", dev->minor);
-		up(&udev->sem);
-		up(&start_stop_sem);
-		return ret;
-	}
-
-	/* private structure is also simply the usb-structure */
-	dev->private = udev;
-
-	/* the first subdevice is the A/D converter */
-	s = dev->subdevices + SUBDEV_AD;
-	/* the URBs get the comedi subdevice */
-	/* which is responsible for reading */
-	/* this is the subdevice which reads data */
-	dev->read_subdev = s;
-	/* the subdevice receives as private structure the */
-	/* usb-structure */
-	s->private = NULL;
-	/* analog input */
-	s->type = COMEDI_SUBD_AI;
-	/* readable and ref is to ground, 32 bit wide data! */
-	s->subdev_flags = SDF_READABLE | SDF_GROUND |
-		SDF_CMD_READ | SDF_LSAMPL;
-	/* 16 A/D channels */
-	s->n_chan = NUMCHANNELS;
-	/* length of the channellist */
-	s->len_chanlist = NUMCHANNELS;
-	/* callback functions */
-	s->insn_read = usbdux_ai_insn_read;
-	s->do_cmdtest = usbdux_ai_cmdtest;
-	s->do_cmd = usbdux_ai_cmd;
-	s->cancel = usbdux_ai_cancel;
-	/* max value from the A/D converter (24bit) */
-	s->maxdata = 0x00FFFFFF;
-	/* range table to convert to physical units */
-	s->range_table = (&range_usbdux_ai_range);
-
-	/* analog out */
-	s = dev->subdevices + SUBDEV_DA;
-	/* analog out */
-	s->type = COMEDI_SUBD_AO;
-	/* backward pointer */
-	dev->write_subdev = s;
-	/* the subdevice receives as private structure the */
-	/* usb-structure */
-	s->private = NULL;
-	/* are writable */
-	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
-	/* 4 channels */
-	s->n_chan = 4;
-	/* length of the channellist */
-	s->len_chanlist = 4;
-	/* 8 bit resolution */
-	s->maxdata = 0x00ff;
-	/* unipolar range */
-	s->range_table = (&range_usbdux_ao_range);
-	/* callback */
-	s->do_cmdtest = usbdux_ao_cmdtest;
-	s->do_cmd = usbdux_ao_cmd;
-	s->cancel = usbdux_ao_cancel;
-	s->insn_read = usbdux_ao_insn_read;
-	s->insn_write = usbdux_ao_insn_write;
-
-	/* digital I/O */
-	s = dev->subdevices + SUBDEV_DIO;
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	/* 8 external and 16 internal channels */
-	s->n_chan = 24;
-	s->maxdata = 1;
-	s->range_table = (&range_digital);
-	s->insn_bits = usbdux_dio_insn_bits;
-	s->insn_config = usbdux_dio_insn_config;
-	/* we don't use it */
-	s->private = NULL;
-
-	if (udev->high_speed) {
-		/* timer / pwm */
-		s = dev->subdevices + SUBDEV_PWM;
-		s->type = COMEDI_SUBD_PWM;
-		s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
-		s->n_chan = 8;
-		/* this defines the max duty cycle resolution */
-		s->maxdata = udev->sizePwmBuf;
-		s->insn_write = usbdux_pwm_write;
-		s->insn_read = usbdux_pwm_read;
-		s->insn_config = usbdux_pwm_config;
-		usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
-	}
-	/* finally decide that it's attached */
-	udev->attached = 1;
-
-	up(&udev->sem);
-
-	up(&start_stop_sem);
-
-	offset = usbdux_getstatusinfo(dev, 0);
-	if (offset < 0)
-		dev_err(&udev->interface->dev,
-			"Communication to USBDUXSIGMA failed!"
-			"Check firmware and cabling.");
-
-	dev_info(&udev->interface->dev,
-		 "comedi%d: attached, ADC_zero = %x", dev->minor, offset);
-
-	return 0;
-}
-
-static void usbduxsigma_detach(struct comedi_device *dev)
-{
-	struct usbduxsub *usb = dev->private;
-
-	if (usb) {
-		down(&usb->sem);
-		dev->private = NULL;
-		usb->attached = 0;
-		usb->comedidev = NULL;
-		up(&usb->sem);
-	}
-}
-
-/* main driver struct */
-static struct comedi_driver driver_usbduxsigma = {
-	.driver_name = "usbduxsigma",
-	.module = THIS_MODULE,
-	.attach = usbduxsigma_attach,
-	.detach = usbduxsigma_detach,
+static const struct usb_device_id usbduxsigma_usb_table[] = {
+	{ USB_DEVICE(0x13d8, 0x0020) },
+	{ USB_DEVICE(0x13d8, 0x0021) },
+	{ USB_DEVICE(0x13d8, 0x0022) },
+	{ }
 };
+MODULE_DEVICE_TABLE(usb, usbduxsigma_usb_table);
 
-/* Table with the USB-devices */
-static const struct usb_device_id usbduxsigma_table[] = {
-	{USB_DEVICE(0x13d8, 0x0020)},
-	{USB_DEVICE(0x13d8, 0x0021)},
-	{USB_DEVICE(0x13d8, 0x0022)},
-	{}			/* Terminating entry */
+static struct usb_driver usbduxsigma_usb_driver = {
+	.name		= "usbduxsigma",
+	.probe		= usbduxsigma_usb_probe,
+	.disconnect	= usbduxsigma_usb_disconnect,
+	.id_table	= usbduxsigma_usb_table,
 };
+module_comedi_usb_driver(usbduxsigma_driver, usbduxsigma_usb_driver);
 
-MODULE_DEVICE_TABLE(usb, usbduxsigma_table);
-
-/* The usbduxsub-driver */
-static struct usb_driver usbduxsigma_driver = {
-	.name = BOARDNAME,
-	.probe = usbduxsigma_probe,
-	.disconnect = usbduxsigma_disconnect,
-	.id_table = usbduxsigma_table,
-};
-
-/* Can't use the nice macro as I have also to initialise the USB */
-/* subsystem: */
-/* registering the usb-system _and_ the comedi-driver */
-static int __init init_usbduxsigma(void)
-{
-	printk(KERN_INFO KBUILD_MODNAME ": "
-	       DRIVER_VERSION ":" DRIVER_DESC "\n");
-	usb_register(&usbduxsigma_driver);
-	comedi_driver_register(&driver_usbduxsigma);
-	return 0;
-}
-
-/* deregistering the comedi driver and the usb-subsystem */
-static void __exit exit_usbduxsigma(void)
-{
-	comedi_driver_unregister(&driver_usbduxsigma);
-	usb_deregister(&usbduxsigma_driver);
-}
-
-module_init(init_usbduxsigma);
-module_exit(exit_usbduxsigma);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
+MODULE_DESCRIPTION("Stirling/ITL USB-DUX SIGMA -- Bernd.Porr@f2s.com");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c
index baee8d7..94010fc 100644
--- a/drivers/staging/comedi/drivers/vmk80xx.c
+++ b/drivers/staging/comedi/drivers/vmk80xx.c
@@ -64,37 +64,11 @@ Changelog:
 
 #include "../comedidev.h"
 
-#define BOARDNAME "vmk80xx"
-
-MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
-MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
-MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
-MODULE_VERSION("0.8.01");
-MODULE_LICENSE("GPL");
-
 enum {
 	DEVICE_VMK8055,
 	DEVICE_VMK8061
 };
 
-static const struct usb_device_id vmk80xx_id_table[] = {
-	{USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055},
-	{USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055},
-	{USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055},
-	{USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055},
-	{USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061},
-	{USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061},
-	{USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061},
-	{USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061},
-	{USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061},
-	{USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061},
-	{USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061},
-	{USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061},
-	{}			/* terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, vmk80xx_id_table);
-
 #define VMK8055_DI_REG          0x00
 #define VMK8055_DO_REG          0x01
 #define VMK8055_AO1_REG         0x02
@@ -232,8 +206,6 @@ static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS];
 
 static DEFINE_MUTEX(glb_mutex);
 
-static struct comedi_driver driver_vmk80xx;	/* see below for initializer */
-
 static void vmk80xx_tx_callback(struct urb *urb)
 {
 	struct vmk80xx_usb *dev = urb->context;
@@ -1127,44 +1099,25 @@ static int vmk80xx_pwm_winsn(struct comedi_device *cdev,
 	return n;
 }
 
-static int vmk80xx_attach(struct comedi_device *cdev,
-			  struct comedi_devconfig *it)
+static int vmk80xx_attach_common(struct comedi_device *cdev,
+				 struct vmk80xx_usb *dev)
 {
-	int i;
-	struct vmk80xx_usb *dev;
 	int n_subd;
 	struct comedi_subdevice *s;
-	int minor;
-
-	mutex_lock(&glb_mutex);
-
-	for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
-		if (vmb[i].probed && !vmb[i].attached)
-			break;
-
-	if (i == VMK80XX_MAX_BOARDS) {
-		mutex_unlock(&glb_mutex);
-		return -ENODEV;
-	}
-
-	dev = &vmb[i];
+	int ret;
 
 	down(&dev->limit_sem);
-
 	cdev->board_name = dev->board.name;
 	cdev->private = dev;
-
 	if (dev->board.model == VMK8055_MODEL)
 		n_subd = 5;
 	else
 		n_subd = 6;
-
-	if (alloc_subdevices(cdev, n_subd) < 0) {
+	ret = comedi_alloc_subdevices(cdev, n_subd);
+	if (ret) {
 		up(&dev->limit_sem);
-		mutex_unlock(&glb_mutex);
-		return -ENOMEM;
+		return ret;
 	}
-
 	/* Analog input subdevice */
 	s = cdev->subdevices + VMK80XX_SUBD_AI;
 	s->type = COMEDI_SUBD_AI;
@@ -1173,7 +1126,6 @@ static int vmk80xx_attach(struct comedi_device *cdev,
 	s->maxdata = (1 << dev->board.ai_bits) - 1;
 	s->range_table = dev->board.range;
 	s->insn_read = vmk80xx_ai_rinsn;
-
 	/* Analog output subdevice */
 	s = cdev->subdevices + VMK80XX_SUBD_AO;
 	s->type = COMEDI_SUBD_AO;
@@ -1182,12 +1134,10 @@ static int vmk80xx_attach(struct comedi_device *cdev,
 	s->maxdata = (1 << dev->board.ao_bits) - 1;
 	s->range_table = dev->board.range;
 	s->insn_write = vmk80xx_ao_winsn;
-
 	if (dev->board.model == VMK8061_MODEL) {
 		s->subdev_flags |= SDF_READABLE;
 		s->insn_read = vmk80xx_ao_rinsn;
 	}
-
 	/* Digital input subdevice */
 	s = cdev->subdevices + VMK80XX_SUBD_DI;
 	s->type = COMEDI_SUBD_DI;
@@ -1196,7 +1146,6 @@ static int vmk80xx_attach(struct comedi_device *cdev,
 	s->maxdata = 1;
 	s->insn_read = vmk80xx_di_rinsn;
 	s->insn_bits = vmk80xx_di_bits;
-
 	/* Digital output subdevice */
 	s = cdev->subdevices + VMK80XX_SUBD_DO;
 	s->type = COMEDI_SUBD_DO;
@@ -1205,12 +1154,10 @@ static int vmk80xx_attach(struct comedi_device *cdev,
 	s->maxdata = 1;
 	s->insn_write = vmk80xx_do_winsn;
 	s->insn_bits = vmk80xx_do_bits;
-
 	if (dev->board.model == VMK8061_MODEL) {
 		s->subdev_flags |= SDF_READABLE;
 		s->insn_read = vmk80xx_do_rinsn;
 	}
-
 	/* Counter subdevice */
 	s = cdev->subdevices + VMK80XX_SUBD_CNT;
 	s->type = COMEDI_SUBD_COUNTER;
@@ -1218,13 +1165,11 @@ static int vmk80xx_attach(struct comedi_device *cdev,
 	s->n_chan = dev->board.cnt_chans;
 	s->insn_read = vmk80xx_cnt_rinsn;
 	s->insn_config = vmk80xx_cnt_cinsn;
-
 	if (dev->board.model == VMK8055_MODEL) {
 		s->subdev_flags |= SDF_WRITEABLE;
 		s->maxdata = (1 << dev->board.cnt_bits) - 1;
 		s->insn_write = vmk80xx_cnt_winsn;
 	}
-
 	/* PWM subdevice */
 	if (dev->board.model == VMK8061_MODEL) {
 		s = cdev->subdevices + VMK80XX_SUBD_PWM;
@@ -1235,19 +1180,51 @@ static int vmk80xx_attach(struct comedi_device *cdev,
 		s->insn_read = vmk80xx_pwm_rinsn;
 		s->insn_write = vmk80xx_pwm_winsn;
 	}
-
 	dev->attached = 1;
+	dev_info(cdev->class_dev, "vmk80xx: board #%d [%s] attached\n",
+		 dev->count, dev->board.name);
+	up(&dev->limit_sem);
+	return 0;
+}
 
-	minor = cdev->minor;
-
-	printk(KERN_INFO
-	       "comedi%d: vmk80xx: board #%d [%s] attached to comedi\n",
-	       minor, dev->count, dev->board.name);
+/* called for COMEDI_DEVCONFIG ioctl for board_name "vmk80xx" */
+static int vmk80xx_attach(struct comedi_device *cdev,
+			  struct comedi_devconfig *it)
+{
+	int i;
+	int ret;
 
-	up(&dev->limit_sem);
+	mutex_lock(&glb_mutex);
+	for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
+		if (vmb[i].probed && !vmb[i].attached)
+			break;
+	if (i == VMK80XX_MAX_BOARDS)
+		ret = -ENODEV;
+	else
+		ret = vmk80xx_attach_common(cdev, &vmb[i]);
 	mutex_unlock(&glb_mutex);
+	return ret;
+}
 
-	return 0;
+/* called via comedi_usb_auto_config() */
+static int vmk80xx_attach_usb(struct comedi_device *cdev,
+			      struct usb_interface *intf)
+{
+	int i;
+	int ret;
+
+	mutex_lock(&glb_mutex);
+	for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
+		if (vmb[i].probed && vmb[i].intf == intf)
+			break;
+	if (i == VMK80XX_MAX_BOARDS)
+		ret = -ENODEV;
+	else if (vmb[i].attached)
+		ret = -EBUSY;
+	else
+		ret = vmk80xx_attach_common(cdev, &vmb[i]);
+	mutex_unlock(&glb_mutex);
+	return ret;
 }
 
 static void vmk80xx_detach(struct comedi_device *dev)
@@ -1262,8 +1239,16 @@ static void vmk80xx_detach(struct comedi_device *dev)
 	}
 }
 
-static int vmk80xx_probe(struct usb_interface *intf,
-			 const struct usb_device_id *id)
+static struct comedi_driver vmk80xx_driver = {
+	.module		= THIS_MODULE,
+	.driver_name	= "vmk80xx",
+	.attach		= vmk80xx_attach,
+	.detach		= vmk80xx_detach,
+	.attach_usb	= vmk80xx_attach_usb,
+};
+
+static int vmk80xx_usb_probe(struct usb_interface *intf,
+			     const struct usb_device_id *id)
 {
 	int i;
 	struct vmk80xx_usb *dev;
@@ -1405,7 +1390,7 @@ static int vmk80xx_probe(struct usb_interface *intf,
 
 	mutex_unlock(&glb_mutex);
 
-	comedi_usb_auto_config(intf, &driver_vmk80xx);
+	comedi_usb_auto_config(intf, &vmk80xx_driver);
 
 	return 0;
 error:
@@ -1414,7 +1399,7 @@ error:
 	return -ENODEV;
 }
 
-static void vmk80xx_disconnect(struct usb_interface *intf)
+static void vmk80xx_usb_disconnect(struct usb_interface *intf)
 {
 	struct vmk80xx_usb *dev = usb_get_intfdata(intf);
 
@@ -1442,41 +1427,35 @@ static void vmk80xx_disconnect(struct usb_interface *intf)
 	mutex_unlock(&glb_mutex);
 }
 
-/* TODO: Add support for suspend, resume, pre_reset,
- * post_reset and flush */
-static struct usb_driver vmk80xx_driver = {
-	.name = "vmk80xx",
-	.probe = vmk80xx_probe,
-	.disconnect = vmk80xx_disconnect,
-	.id_table = vmk80xx_id_table
+static const struct usb_device_id vmk80xx_usb_id_table[] = {
+	{ USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
+	{ USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
+	{ USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
+	{ USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
+	{ USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
+	{ USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
+	{ USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
+	{ USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
+	{ USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
+	{ USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
+	{ USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
+	{ USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
+	{ }
 };
+MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
 
-static struct comedi_driver driver_vmk80xx = {
-	.module = THIS_MODULE,
-	.driver_name = "vmk80xx",
-	.attach = vmk80xx_attach,
-	.detach = vmk80xx_detach
+/* TODO: Add support for suspend, resume, pre_reset,
+ * post_reset and flush */
+static struct usb_driver vmk80xx_usb_driver = {
+	.name		= "vmk80xx",
+	.probe		= vmk80xx_usb_probe,
+	.disconnect	= vmk80xx_usb_disconnect,
+	.id_table	= vmk80xx_usb_id_table,
 };
+module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
 
-static int __init vmk80xx_init(void)
-{
-	int retval;
-
-	printk(KERN_INFO "vmk80xx: version 0.8.01 "
-	       "Manuel Gebele <forensixs@gmx.de>\n");
-
-	retval = comedi_driver_register(&driver_vmk80xx);
-	if (retval < 0)
-		return retval;
-
-	return usb_register(&vmk80xx_driver);
-}
-
-static void __exit vmk80xx_exit(void)
-{
-	comedi_driver_unregister(&driver_vmk80xx);
-	usb_deregister(&vmk80xx_driver);
-}
-
-module_init(vmk80xx_init);
-module_exit(vmk80xx_exit);
+MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
+MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
+MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
+MODULE_VERSION("0.8.01");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/internal.h b/drivers/staging/comedi/internal.h
deleted file mode 100644
index 7ed20a0..0000000
--- a/drivers/staging/comedi/internal.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * various internal comedi stuff
- */
-int do_rangeinfo_ioctl(struct comedi_device *dev,
-		       struct comedi_rangeinfo __user *arg);
-int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
-	       struct comedi_insn *insn, unsigned int *data);
-int comedi_alloc_board_minor(struct device *hardware_device);
-void comedi_free_board_minor(unsigned minor);
-int comedi_find_board_minor(struct device *hardware_device);
-void comedi_reset_async_buf(struct comedi_async *async);
-int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
-		     unsigned long new_size);
-
-extern unsigned int comedi_default_buf_size_kb;
-extern unsigned int comedi_default_buf_maxsize_kb;
diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c
index 2aa487b..bb7e70e 100644
--- a/drivers/staging/comedi/proc.c
+++ b/drivers/staging/comedi/proc.c
@@ -30,7 +30,7 @@
 
 #define __NO_VERSION__
 #include "comedidev.h"
-#include "comedi_fops.h"
+#include "comedi_internal.h"
 #include <linux/proc_fs.h>
 #include <linux/string.h>
 
diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c
index 148ec6f..41f9523 100644
--- a/drivers/staging/comedi/range.c
+++ b/drivers/staging/comedi/range.c
@@ -23,7 +23,7 @@
 
 #include <linux/uaccess.h>
 #include "comedidev.h"
-#include "internal.h"
+#include "comedi_internal.h"
 
 const struct comedi_lrange range_bipolar10 = { 1, {BIP_RANGE(10)} };
 EXPORT_SYMBOL(range_bipolar10);
diff --git a/drivers/staging/cptm1217/clearpad_tm1217.c b/drivers/staging/cptm1217/clearpad_tm1217.c
index 5456f82..0d924d3 100644
--- a/drivers/staging/cptm1217/clearpad_tm1217.c
+++ b/drivers/staging/cptm1217/clearpad_tm1217.c
@@ -396,8 +396,8 @@ static int cp_tm1217_setup_gpio_irq(struct cp_tm1217_device *ts)
 
 	retval = gpio_to_irq(ts->gpio);
 	if (retval < 0) {
-		dev_err(ts->dev, "cp_tm1217: GPIO to IRQ failedi,"
-		" error %d\n", retval);
+		dev_err(ts->dev,
+			"cp_tm1217: GPIO to IRQ failed, error %d\n", retval);
 		gpio_free(ts->gpio);
 	}
 	dev_dbg(ts->dev,
diff --git a/drivers/staging/csr/Kconfig b/drivers/staging/csr/Kconfig
new file mode 100644
index 0000000..bd86fb9
--- /dev/null
+++ b/drivers/staging/csr/Kconfig
@@ -0,0 +1,9 @@
+config CSR_WIFI
+	tristate "CSR wireless driver"
+	depends on PCI && MMC && CFG80211_WEXT
+	select WIRELESS_EXT
+	select WEXT_PRIV
+	help
+	  Driver for the CSR wireless SDIO device.
+
+	  If unsure, select N.
diff --git a/drivers/staging/csr/LICENSE.txt b/drivers/staging/csr/LICENSE.txt
new file mode 100644
index 0000000..364853e
--- /dev/null
+++ b/drivers/staging/csr/LICENSE.txt
@@ -0,0 +1,39 @@
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+Except as contained in this notice, the names of above-listed
+copyright holders and the names of any contributors shall not be used
+in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+CONTRIBUTORS 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.
+
+Alternatively, this software may be distributed under the terms of the
+GNU General Public License ("GPL") version 2 as published
+by the Free Software Foundation.
+
+As a special exception, if other files instantiate templates or use
+macros or inline functions from this file, or you compile this file
+and link it with other works to produce a work based on this file,
+this file does not by itself cause the resulting work to be covered by
+the GNU General Public License. However the source code for this file
+must still be made available in accordance with section (3) of the GNU
+General Public License.
+
+This exception does not invalidate any other reasons why a work based
+on this file might be covered by the GNU General Public License.
diff --git a/drivers/staging/csr/Makefile b/drivers/staging/csr/Makefile
new file mode 100644
index 0000000..e0e7bab
--- /dev/null
+++ b/drivers/staging/csr/Makefile
@@ -0,0 +1,80 @@
+obj-$(CONFIG_CSR_WIFI)	+= oska/
+
+ccflags-y	:= -DCSR_SME_USERSPACE -DCSR_SUPPORT_SME -DREMOTE_SYS_SAP -DCSR_WIFI_SECURITY_WAPI_ENABLE -DENABLE_SHUTDOWN -DUNIFI_DEBUG
+ccflags-y	+= -DSDIO_EXPORTS_STRUCT_DEVICE -DCSR_WIFI_SUPPORT_MMC_DRIVER -DCSR_WIFI_SINGLE_FUNCTION -DCSR_WIFI_SPLIT_PATCH
+ccflags-y	+= -DCSR_SUPPORT_WEXT -DREMOTE_SYS_SAP  -DREMOTE_MGT_SAP -DCSR_WIFI_SECURITY_WAPI_ENABLE -DCSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND -DENABLE_SHUTDOWN -DCSR_WIFI_NME_ENABLE -DCSR_WIFI_AP_ENABLE -DCSR_SUPPORT_WEXT_AP -DCSR_WIFI_REQUEUE_PACKET_TO_HAL
+
+obj-$(CONFIG_CSR_WIFI)	+= csr_wifi.o
+obj-$(CONFIG_CSR_WIFI)	+= csr_helper.o
+
+csr_wifi-y :=	bh.o				\
+		data_tx.o			\
+		drv.o				\
+		firmware.o			\
+		indications.o			\
+		inet.o				\
+		init_hw.o			\
+		io.o				\
+		monitor.o			\
+		netdev.o			\
+		os.o				\
+		putest.o			\
+		sdio_events.o			\
+		sdio_mmc.o			\
+		sdio_stubs.o			\
+		sme_blocking.o			\
+		ul_int.o			\
+		unifi_dbg.o			\
+		unifi_event.o			\
+		unifi_pdu_processing.o		\
+		unifi_sme.o			\
+		csr_formatted_io.o		\
+		csr_wifi_hip_card_sdio.o	\
+		csr_wifi_hip_card_sdio_intr.o	\
+		csr_wifi_hip_card_sdio_mem.o	\
+		csr_wifi_hip_chiphelper.o	\
+		csr_wifi_hip_download.o		\
+		csr_wifi_hip_dump.o		\
+		csr_wifi_hip_packing.o		\
+		csr_wifi_hip_send.o		\
+		csr_wifi_hip_signals.o		\
+		csr_wifi_hip_ta_sampling.o	\
+		csr_wifi_hip_udi.o		\
+		csr_wifi_hip_unifi_signal_names.o	\
+		csr_wifi_hip_xbv.o		\
+		csr_wifi_nme_ap_converter_init.o		\
+		csr_wifi_nme_ap_free_downstream_contents.o	\
+		csr_wifi_nme_ap_free_upstream_contents.o	\
+		csr_wifi_nme_ap_serialize.o	\
+		csr_wifi_nme_ap_sef.o		\
+		csr_wifi_router_ctrl_sef.o	\
+		csr_wifi_router_sef.o		\
+		csr_wifi_router_transport.o	\
+		csr_wifi_sme_sef.o		\
+		csr_wifi_sme_converter_init.o	\
+		csr_wifi_sme_free_downstream_contents.o		\
+		csr_wifi_sme_free_upstream_contents.o		\
+		csr_wifi_sme_serialize.o			\
+		csr_wifi_router_ctrl_converter_init.o		\
+		csr_wifi_router_ctrl_free_downstream_contents.o	\
+		csr_wifi_router_ctrl_free_upstream_contents.o	\
+		csr_wifi_router_ctrl_serialize.o		\
+		csr_wifi_router_converter_init.o		\
+		csr_wifi_router_free_downstream_contents.o	\
+		csr_wifi_router_free_upstream_contents.o	\
+		csr_wifi_router_serialize.o			\
+		sme_mgt.o			\
+		sme_sys.o			\
+		sme_userspace.o 		\
+		sme_wext.o			\
+		wext_events.o
+
+csr_helper-y :=	csr_time.o			\
+		csr_util.o			\
+		csr_framework_ext.o		\
+		csr_pmem.o			\
+		csr_wifi_serialize_primitive_types.o	\
+		csr_serialize_primitive_types.o	\
+		csr_utf16.o			\
+		csr_msgconv.o			\
+		csr_panic.o
diff --git a/drivers/staging/csr/bh.c b/drivers/staging/csr/bh.c
new file mode 100644
index 0000000..6af9d29
--- /dev/null
+++ b/drivers/staging/csr/bh.c
@@ -0,0 +1,391 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     bh.c
+ *
+ * PURPOSE:
+ *      Provides an implementation for the driver bottom-half.
+ *      It is part of the porting exercise in Linux.
+ *
+ * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "unifi_priv.h"
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_start_thread
+ *
+ *      Helper function to start a new thread.
+ *
+ *  Arguments:
+ *      priv            Pointer to OS driver structure for the device.
+ *      thread          Pointer to the thread object
+ *      func            The thread function
+ *
+ *  Returns:
+ *      0 on success or else a Linux error code.
+ * ---------------------------------------------------------------------------
+ */
+int
+uf_start_thread(unifi_priv_t *priv, struct uf_thread *thread, int (*func)(void *))
+{
+    if (thread->thread_task != NULL) {
+        unifi_error(priv, "%s thread already started\n", thread->name);
+        return 0;
+    }
+
+    /* Start the kernel thread that handles all h/w accesses. */
+    thread->thread_task = kthread_run(func, priv, "%s", thread->name);
+    if (IS_ERR(thread->thread_task)) {
+        return PTR_ERR(thread->thread_task);
+    }
+
+    /* Module parameter overides the thread priority */
+    if (bh_priority != -1) {
+        if (bh_priority >= 0 && bh_priority <= MAX_RT_PRIO) {
+            struct sched_param param;
+            priv->bh_thread.prio = bh_priority;
+            unifi_trace(priv, UDBG1, "%s thread (RT) priority = %d\n",
+                        thread->name, bh_priority);
+            param.sched_priority = bh_priority;
+            sched_setscheduler(thread->thread_task, SCHED_FIFO, &param);
+        } else if (bh_priority > MAX_RT_PRIO && bh_priority <= MAX_PRIO) {
+            priv->bh_thread.prio = bh_priority;
+            unifi_trace(priv, UDBG1, "%s thread priority = %d\n",
+                        thread->name, PRIO_TO_NICE(bh_priority));
+            set_user_nice(thread->thread_task, PRIO_TO_NICE(bh_priority));
+        } else {
+            priv->bh_thread.prio = DEFAULT_PRIO;
+            unifi_warning(priv, "%s thread unsupported (%d) priority\n",
+                          thread->name, bh_priority);
+        }
+    } else {
+        priv->bh_thread.prio = DEFAULT_PRIO;
+    }
+    unifi_trace(priv, UDBG2, "Started %s thread\n", thread->name);
+
+    return 0;
+} /* uf_start_thread() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_stop_thread
+ *
+ *      Helper function to stop a thread.
+ *
+ *  Arguments:
+ *      priv            Pointer to OS driver structure for the device.
+ *      thread          Pointer to the thread object
+ *
+ *  Returns:
+ *
+ * ---------------------------------------------------------------------------
+ */
+    void
+uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread)
+{
+    if (!thread->thread_task) {
+        unifi_notice(priv, "%s thread is already stopped\n", thread->name);
+        return;
+    }
+
+    unifi_trace(priv, UDBG2, "Stopping %s thread\n", thread->name);
+
+    kthread_stop(thread->thread_task);
+    thread->thread_task = NULL;
+
+} /* uf_stop_thread() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_wait_for_thread_to_stop
+ *
+ *      Helper function to wait until a thread is stopped.
+ *
+ *  Arguments:
+ *      priv    Pointer to OS driver structure for the device.
+ *
+ *  Returns:
+ *
+ * ---------------------------------------------------------------------------
+ */
+    void
+uf_wait_for_thread_to_stop(unifi_priv_t *priv, struct uf_thread *thread)
+{
+    /*
+     * kthread_stop() cannot handle the thread exiting while
+     * kthread_should_stop() is false, so sleep until kthread_stop()
+     * wakes us up.
+     */
+    unifi_trace(priv, UDBG2, "%s waiting for the stop signal.\n", thread->name);
+    set_current_state(TASK_INTERRUPTIBLE);
+    if (!kthread_should_stop()) {
+        unifi_trace(priv, UDBG2, "%s schedule....\n", thread->name);
+        schedule();
+    }
+
+    thread->thread_task = NULL;
+    unifi_trace(priv, UDBG2, "%s exiting....\n", thread->name);
+} /* uf_wait_for_thread_to_stop() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  handle_bh_error
+ *
+ *      This function reports an error returned from the HIP core bottom-half.
+ *      Normally, implemented during the porting exercise, passing the error
+ *      to the SME using unifi_sys_wifi_off_ind().
+ *      The SME will try to reset the device and go through
+ *      the initialisation of the UniFi.
+ *
+ *  Arguments:
+ *      priv            Pointer to OS driver structure for the device.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+    static void
+handle_bh_error(unifi_priv_t *priv)
+{
+    u8 conf_param = CONFIG_IND_ERROR;
+    CsrUint8 interfaceTag = 0; /* used as a loop counter */
+
+
+    /* Block unifi_run_bh() until the error has been handled. */
+    priv->bh_thread.block_thread = 1;
+
+    /* Consider UniFi to be uninitialised */
+    priv->init_progress = UNIFI_INIT_NONE;
+
+    /* Stop the network traffic */
+    for( interfaceTag =0; interfaceTag <CSR_WIFI_NUM_INTERFACES;interfaceTag ++) {
+        netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+        if (interfacePriv->netdev_registered == 1) {
+            netif_carrier_off(priv->netdev[interfaceTag]);
+        }
+    }
+
+#ifdef CSR_NATIVE_LINUX
+    /* Force any client waiting on an mlme_wait_for_reply() to abort. */
+    uf_abort_mlme(priv);
+
+    /* Cancel any pending workqueue tasks */
+    flush_workqueue(priv->unifi_workqueue);
+
+#endif /* CSR_NATIVE_LINUX */
+
+    unifi_error(priv, "handle_bh_error: fatal error is reported to the SME.\n");
+    /* Notify the clients (SME or unifi_manager) for the error. */
+    ul_log_config_ind(priv, &conf_param, sizeof(u8));
+
+} /* handle_bh_error() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  bh_thread_function
+ *
+ *      All hardware access happens in this thread.
+ *      This means there is no need for locks on the hardware and we don't need
+ *      to worry about reentrancy with the SDIO library.
+ *      Provides and example implementation on how to call unifi_bh(), which
+ *      is part of the HIP core API.
+ *
+ *      It processes the events generated by unifi_run_bh() to serialise calls
+ *      to unifi_bh(). It also demonstrates how the timeout parameter passed in
+ *      and returned from unifi_bh() needs to be handled.
+ *
+ *  Arguments:
+ *      arg             Pointer to OS driver structure for the device.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *      When the bottom half of the driver needs to process signals, events,
+ *      or simply the host status (i.e sleep mode), it invokes unifi_run_bh().
+ *      Since we need all SDIO transaction to be in a single thread, the
+ *      unifi_run_bh() will wake up this thread to process it.
+ *
+ * ---------------------------------------------------------------------------
+ */
+static int
+bh_thread_function(void *arg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)arg;
+    CsrResult csrResult;
+    long ret;
+    CsrUint32 timeout, t;
+    struct uf_thread *this_thread;
+
+    unifi_trace(priv, UDBG2, "bh_thread_function starting\n");
+
+    this_thread = &priv->bh_thread;
+
+    t = timeout = 0;
+    while (!kthread_should_stop()) {
+        /* wait until an error occurs, or we need to process something. */
+        unifi_trace(priv, UDBG3, "bh_thread goes to sleep.\n");
+
+        if (timeout > 0) {
+            /* Convert t in ms to jiffies */
+            t = msecs_to_jiffies(timeout);
+            ret = wait_event_interruptible_timeout(this_thread->wakeup_q,
+                    (this_thread->wakeup_flag && !this_thread->block_thread) ||
+                    kthread_should_stop(),
+                    t);
+            timeout = (ret > 0) ? jiffies_to_msecs(ret) : 0;
+        } else {
+            ret = wait_event_interruptible(this_thread->wakeup_q,
+                    (this_thread->wakeup_flag && !this_thread->block_thread) ||
+                    kthread_should_stop());
+        }
+
+        if (kthread_should_stop()) {
+            unifi_trace(priv, UDBG2, "bh_thread: signalled to exit\n");
+            break;
+        }
+
+        if (ret < 0) {
+            unifi_notice(priv,
+                    "bh_thread: wait_event returned %d, thread will exit\n",
+                    ret);
+            uf_wait_for_thread_to_stop(priv, this_thread);
+            break;
+        }
+
+        this_thread->wakeup_flag = 0;
+
+        unifi_trace(priv, UDBG3, "bh_thread calls unifi_bh().\n");
+
+        CsrSdioClaim(priv->sdio);
+        csrResult = unifi_bh(priv->card, &timeout);
+        if(csrResult != CSR_RESULT_SUCCESS) {
+            if (csrResult == CSR_WIFI_HIP_RESULT_NO_DEVICE) {
+                CsrSdioRelease(priv->sdio);
+                uf_wait_for_thread_to_stop(priv, this_thread);
+                break;
+            }
+            /* Errors must be delivered to the error task */
+            handle_bh_error(priv);
+        }
+        CsrSdioRelease(priv->sdio);
+    }
+
+    /*
+     * I would normally try to call csr_sdio_remove_irq() here to make sure
+     * that we do not get any interrupts while this thread is not running.
+     * However, the MMC/SDIO driver tries to kill its' interrupt thread.
+     * The kernel threads implementation does not allow to kill threads
+     * from a signalled to stop thread.
+     * So, instead call csr_sdio_linux_remove_irq() always after calling
+     * uf_stop_thread() to kill this thread.
+     */
+
+    unifi_trace(priv, UDBG2, "bh_thread exiting....\n");
+    return 0;
+} /* bh_thread_function() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_init_bh
+ *
+ *      Helper function to start the bottom half of the driver.
+ *      All we need to do here is start the I/O bh thread.
+ *
+ *  Arguments:
+ *      priv            Pointer to OS driver structure for the device.
+ *
+ *  Returns:
+ *      0 on success or else a Linux error code.
+ * ---------------------------------------------------------------------------
+ */
+    int
+uf_init_bh(unifi_priv_t *priv)
+{
+    int r;
+
+    /* Enable mlme interface. */
+    priv->io_aborted = 0;
+
+
+    /* Start the BH thread */
+    r = uf_start_thread(priv, &priv->bh_thread, bh_thread_function);
+    if (r) {
+        unifi_error(priv,
+                "uf_init_bh: failed to start the BH thread.\n");
+        return r;
+    }
+
+    /* Allow interrupts */
+    r = csr_sdio_linux_install_irq(priv->sdio);
+    if (r) {
+        unifi_error(priv,
+                "uf_init_bh: failed to install the IRQ.\n");
+
+        uf_stop_thread(priv, &priv->bh_thread);
+    }
+
+    return r;
+} /* uf_init_bh() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_run_bh
+ *
+ *      Part of the HIP core lib API, implemented in the porting exercise.
+ *      The bottom half of the driver calls this function when
+ *      it wants to process anything that requires access to unifi.
+ *      We need to call unifi_bh() which in this implementation is done
+ *      by waking up the I/O thread.
+ *
+ *  Arguments:
+ *      ospriv          Pointer to OS driver structure for the device.
+ *
+ *  Returns:
+ *      0 on success or else a Linux error code.
+ *
+ *  Notes:
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_run_bh(void *ospriv)
+{
+    unifi_priv_t *priv = ospriv;
+
+    /*
+     * If an error has occured, we discard silently all messages from the bh
+     * until the error has been processed and the unifi has been reinitialised.
+     */
+    if (priv->bh_thread.block_thread == 1) {
+        unifi_trace(priv, UDBG3, "unifi_run_bh: discard message.\n");
+        /*
+         * Do not try to acknowledge a pending interrupt here.
+         * This function is called by unifi_send_signal() which in turn can be
+         * running in an atomic or 'disabled irq' level if a signal is sent
+         * from a workqueue task (i.e multicass addresses set).
+         * We can not hold the SDIO lock because it might sleep.
+         */
+        return CSR_RESULT_FAILURE;
+    }
+
+    priv->bh_thread.wakeup_flag = 1;
+    /* wake up I/O thread */
+    wake_up_interruptible(&priv->bh_thread.wakeup_q);
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_run_bh() */
+
diff --git a/drivers/staging/csr/csr_formatted_io.c b/drivers/staging/csr/csr_formatted_io.c
new file mode 100644
index 0000000..bd6456b
--- /dev/null
+++ b/drivers/staging/csr/csr_formatted_io.c
@@ -0,0 +1,29 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+#include "csr_formatted_io.h"
+#include "csr_util.h"
+
+CsrInt32 CsrSnprintf(CsrCharString *dest, CsrSize n, const CsrCharString *fmt, ...)
+{
+    CsrInt32 r;
+    va_list args;
+    va_start(args, fmt);
+    r = CsrVsnprintf(dest, n, fmt, args);
+    va_end(args);
+
+    if (dest && (n > 0))
+    {
+        dest[n - 1] = '\0';
+    }
+
+    return r;
+}
diff --git a/drivers/staging/csr/csr_formatted_io.h b/drivers/staging/csr/csr_formatted_io.h
new file mode 100644
index 0000000..b458eb5
--- /dev/null
+++ b/drivers/staging/csr/csr_formatted_io.h
@@ -0,0 +1,25 @@
+#ifndef CSR_FORMATTED_IO_H__
+#define CSR_FORMATTED_IO_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "csr_types.h"
+
+CsrInt32 CsrSnprintf(CsrCharString *dest, CsrSize n, const CsrCharString *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_framework_ext.c b/drivers/staging/csr/csr_framework_ext.c
new file mode 100644
index 0000000..1586b23
--- /dev/null
+++ b/drivers/staging/csr/csr_framework_ext.c
@@ -0,0 +1,248 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+#include <linux/slab.h>
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19)
+#include <linux/freezer.h>
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
+#include <asm/semaphore.h>
+#else
+#include <linux/semaphore.h>
+#endif
+
+#include <linux/bitops.h>
+
+#include "csr_types.h"
+#include "csr_framework_ext.h"
+#include "csr_panic.h"
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMutexCreate
+ *
+ *  DESCRIPTION
+ *      Create a mutex and return a handle to the created mutex.
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS           in case of success
+ *          CSR_FE_RESULT_NO_MORE_MUTEXES   in case of out of mutex resources
+ *          CSR_FE_RESULT_INVALID_POINTER   in case the mutexHandle pointer is invalid
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrMutexCreate(CsrMutexHandle *mutexHandle)
+{
+    if (mutexHandle == NULL)
+    {
+        return CSR_FE_RESULT_INVALID_POINTER;
+    }
+
+    sema_init(mutexHandle, 1);
+
+    return CSR_RESULT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMutexDestroy
+ *
+ *  DESCRIPTION
+ *      Destroy the previously created mutex.
+ *
+ *  RETURNS
+ *      void
+ *
+ *----------------------------------------------------------------------------*/
+void CsrMutexDestroy(CsrMutexHandle *mutexHandle)
+{
+}
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMutexLock
+ *
+ *  DESCRIPTION
+ *      Lock the mutex refered to by the provided handle.
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS           in case of success
+ *          CSR_FE_RESULT_INVALID_HANDLE    in case the mutexHandle is invalid
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrMutexLock(CsrMutexHandle *mutexHandle)
+{
+    if (mutexHandle == NULL)
+    {
+        return CSR_FE_RESULT_INVALID_POINTER;
+    }
+
+    if (down_interruptible(mutexHandle))
+    {
+        CsrPanic(CSR_TECH_FW, CSR_PANIC_FW_UNEXPECTED_VALUE, "CsrMutexLock Failed");
+        return CSR_FE_RESULT_INVALID_POINTER;
+    }
+
+    return CSR_RESULT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMutexUnlock
+ *
+ *  DESCRIPTION
+ *      Unlock the mutex refered to by the provided handle.
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS           in case of success
+ *          CSR_FE_RESULT_INVALID_HANDLE    in case the mutexHandle is invalid
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrMutexUnlock(CsrMutexHandle *mutexHandle)
+{
+    if (mutexHandle == NULL)
+    {
+        return CSR_FE_RESULT_INVALID_POINTER;
+    }
+
+    up(mutexHandle);
+
+    return CSR_RESULT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrThreadSleep
+ *
+ *  DESCRIPTION
+ *      Sleep for a given period.
+ *
+ *  RETURNS
+ *      void
+ *
+ *----------------------------------------------------------------------------*/
+void CsrThreadSleep(CsrUint16 sleepTimeInMs)
+{
+    unsigned long t;
+
+    /* Convert t in ms to jiffies and round up */
+    t = ((sleepTimeInMs * HZ) + 999) / 1000;
+    schedule_timeout_uninterruptible(t);
+}
+EXPORT_SYMBOL_GPL(CsrThreadSleep);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMemCalloc
+ *
+ *  DESCRIPTION
+ *      Allocate dynamic memory of a given size calculated as the
+ *      numberOfElements times the elementSize.
+ *
+ *  RETURNS
+ *      Pointer to allocated memory, or NULL in case of failure.
+ *      Allocated memory is zero initialised.
+ *
+ *----------------------------------------------------------------------------*/
+void *CsrMemCalloc(CsrSize numberOfElements, CsrSize elementSize)
+{
+    void *buf;
+    size_t size;
+
+    size = numberOfElements * elementSize;
+
+    buf = kmalloc(size, GFP_KERNEL);
+    if (buf != NULL)
+    {
+        memset(buf, 0, size);
+    }
+
+    return buf;
+}
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMemAlloc
+ *
+ *  DESCRIPTION
+ *      Allocate dynamic memory of a given size.
+ *
+ *  RETURNS
+ *      Pointer to allocated memory, or NULL in case of failure.
+ *      Allocated memory is not initialised.
+ *
+ *----------------------------------------------------------------------------*/
+void *CsrMemAlloc(CsrSize size)
+{
+    return kmalloc(size, GFP_KERNEL);
+}
+EXPORT_SYMBOL_GPL(CsrMemAlloc);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMemFree
+ *
+ *  DESCRIPTION
+ *      Free dynamic allocated memory.
+ *
+ *  RETURNS
+ *      void
+ *
+ *----------------------------------------------------------------------------*/
+void CsrMemFree(void *pointer)
+{
+    kfree(pointer);
+}
+EXPORT_SYMBOL_GPL(CsrMemFree);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMemAllocDma
+ *
+ *  DESCRIPTION
+ *      Allocate DMA capable dynamic memory of a given size.
+ *
+ *  RETURNS
+ *      Pointer to allocated memory, or NULL in case of failure.
+ *      Allocated memory is not initialised.
+ *
+ *----------------------------------------------------------------------------*/
+void *CsrMemAllocDma(CsrSize size)
+{
+    return kmalloc(size, GFP_KERNEL | GFP_DMA);
+}
+EXPORT_SYMBOL_GPL(CsrMemAllocDma);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMemFreeDma
+ *
+ *  DESCRIPTION
+ *      Free DMA capable dynamic allocated memory.
+ *
+ *  RETURNS
+ *      void
+ *
+ *----------------------------------------------------------------------------*/
+void CsrMemFreeDma(void *pointer)
+{
+    kfree(pointer);
+}
+EXPORT_SYMBOL_GPL(CsrMemFreeDma);
diff --git a/drivers/staging/csr/csr_framework_ext.h b/drivers/staging/csr/csr_framework_ext.h
new file mode 100644
index 0000000..401bf2d
--- /dev/null
+++ b/drivers/staging/csr/csr_framework_ext.h
@@ -0,0 +1,354 @@
+#ifndef CSR_FRAMEWORK_EXT_H__
+#define CSR_FRAMEWORK_EXT_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+#include "csr_result.h"
+#include "csr_framework_ext_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Result codes */
+#define CSR_FE_RESULT_NO_MORE_EVENTS    ((CsrResult) 0x0001)
+#define CSR_FE_RESULT_INVALID_POINTER   ((CsrResult) 0x0002)
+#define CSR_FE_RESULT_INVALID_HANDLE    ((CsrResult) 0x0003)
+#define CSR_FE_RESULT_NO_MORE_MUTEXES   ((CsrResult) 0x0004)
+#define CSR_FE_RESULT_TIMEOUT           ((CsrResult) 0x0005)
+#define CSR_FE_RESULT_NO_MORE_THREADS   ((CsrResult) 0x0006)
+
+/* Thread priorities */
+#define CSR_THREAD_PRIORITY_HIGHEST     ((CsrUint16) 0)
+#define CSR_THREAD_PRIORITY_HIGH        ((CsrUint16) 1)
+#define CSR_THREAD_PRIORITY_NORMAL      ((CsrUint16) 2)
+#define CSR_THREAD_PRIORITY_LOW         ((CsrUint16) 3)
+#define CSR_THREAD_PRIORITY_LOWEST      ((CsrUint16) 4)
+
+#define CSR_EVENT_WAIT_INFINITE         ((CsrUint16) 0xFFFF)
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrEventCreate
+ *
+ *  DESCRIPTION
+ *      Creates an event and returns a handle to the created event.
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS          in case of success
+ *          CSR_FE_RESULT_NO_MORE_EVENTS   in case of out of event resources
+ *          CSR_FE_RESULT_INVALID_POINTER  in case the eventHandle pointer is invalid
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrEventCreate(CsrEventHandle *eventHandle);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrEventWait
+ *
+ *  DESCRIPTION
+ *      Wait fore one or more of the event bits to be set.
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS              in case of success
+ *          CSR_FE_RESULT_TIMEOUT              in case of timeout
+ *          CSR_FE_RESULT_INVALID_HANDLE       in case the eventHandle is invalid
+ *          CSR_FE_RESULT_INVALID_POINTER      in case the eventBits pointer is invalid
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrEventWait(CsrEventHandle *eventHandle, CsrUint16 timeoutInMs, CsrUint32 *eventBits);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrEventSet
+ *
+ *  DESCRIPTION
+ *      Set an event.
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS              in case of success
+ *          CSR_FE_RESULT_INVALID_HANDLE       in case the eventHandle is invalid
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrEventSet(CsrEventHandle *eventHandle, CsrUint32 eventBits);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrEventDestroy
+ *
+ *  DESCRIPTION
+ *      Destroy the event associated.
+ *
+ *  RETURNS
+ *      void
+ *
+ *----------------------------------------------------------------------------*/
+void CsrEventDestroy(CsrEventHandle *eventHandle);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMutexCreate
+ *
+ *  DESCRIPTION
+ *      Create a mutex and return a handle to the created mutex.
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS           in case of success
+ *          CSR_FE_RESULT_NO_MORE_MUTEXES   in case of out of mutex resources
+ *          CSR_FE_RESULT_INVALID_POINTER   in case the mutexHandle pointer is invalid
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrMutexCreate(CsrMutexHandle *mutexHandle);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMutexLock
+ *
+ *  DESCRIPTION
+ *      Lock the mutex refered to by the provided handle.
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS           in case of success
+ *          CSR_FE_RESULT_INVALID_HANDLE    in case the mutexHandle is invalid
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrMutexLock(CsrMutexHandle *mutexHandle);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMutexUnlock
+ *
+ *  DESCRIPTION
+ *      Unlock the mutex refered to by the provided handle.
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS           in case of success
+ *          CSR_FE_RESULT_INVALID_HANDLE    in case the mutexHandle is invalid
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrMutexUnlock(CsrMutexHandle *mutexHandle);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMutexDestroy
+ *
+ *  DESCRIPTION
+ *      Destroy the previously created mutex.
+ *
+ *  RETURNS
+ *      void
+ *
+ *----------------------------------------------------------------------------*/
+void CsrMutexDestroy(CsrMutexHandle *mutexHandle);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrGlobalMutexLock
+ *
+ *  DESCRIPTION
+ *      Lock the global mutex. The global mutex is a single pre-initialised
+ *      shared mutex, spinlock or similar that does not need to be created prior
+ *      to use. The limitation is that there is only one single lock shared
+ *      between all code. Consequently, it must only be used very briefly to
+ *      either protect simple one-time initialisation or to protect the creation
+ *      of a dedicated mutex by calling CsrMutexCreate.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrGlobalMutexLock(void);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrGlobalMutexUnlock
+ *
+ *  DESCRIPTION
+ *      Unlock the global mutex.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrGlobalMutexUnlock(void);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrThreadCreate
+ *
+ *  DESCRIPTION
+ *      Create thread function and return a handle to the created thread.
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS           in case of success
+ *          CSR_FE_RESULT_NO_MORE_THREADS   in case of out of thread resources
+ *          CSR_FE_RESULT_INVALID_POINTER   in case one of the supplied pointers is invalid
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrThreadCreate(void (*threadFunction)(void *pointer), void *pointer,
+    CsrUint32 stackSize, CsrUint16 priority,
+    const CsrCharString *threadName, CsrThreadHandle *threadHandle);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrThreadGetHandle
+ *
+ *  DESCRIPTION
+ *      Return thread handle of calling thread.
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS             in case of success
+ *          CSR_FE_RESULT_INVALID_POINTER  in case the threadHandle pointer is invalid
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrThreadGetHandle(CsrThreadHandle *threadHandle);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrThreadEqual
+ *
+ *  DESCRIPTION
+ *      Compare thread handles
+ *
+ *  RETURNS
+ *      Possible values:
+ *          CSR_RESULT_SUCCESS             in case thread handles are identical
+ *          CSR_FE_RESULT_INVALID_POINTER  in case either threadHandle pointer is invalid
+ *          CSR_RESULT_FAILURE             otherwise
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrThreadEqual(CsrThreadHandle *threadHandle1, CsrThreadHandle *threadHandle2);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrThreadSleep
+ *
+ *  DESCRIPTION
+ *      Sleep for a given period.
+ *
+ *  RETURNS
+ *      void
+ *
+ *----------------------------------------------------------------------------*/
+void CsrThreadSleep(CsrUint16 sleepTimeInMs);
+
+#ifndef CSR_PMEM_DEBUG_ENABLE
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMemAlloc
+ *
+ *  DESCRIPTION
+ *      Allocate dynamic memory of a given size.
+ *
+ *  RETURNS
+ *      Pointer to allocated memory, or NULL in case of failure.
+ *      Allocated memory is not initialised.
+ *
+ *----------------------------------------------------------------------------*/
+#ifdef CSR_MEM_DEBUG
+void *CsrMemAllocDebug(CsrSize size,
+    const CsrCharString *file, CsrUint32 line);
+#define CsrMemAlloc(sz) CsrMemAllocDebug((sz), __FILE__, __LINE__)
+#else
+void *CsrMemAlloc(CsrSize size);
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMemCalloc
+ *
+ *  DESCRIPTION
+ *      Allocate dynamic memory of a given size calculated as the
+ *      numberOfElements times the elementSize.
+ *
+ *  RETURNS
+ *      Pointer to allocated memory, or NULL in case of failure.
+ *      Allocated memory is zero initialised.
+ *
+ *----------------------------------------------------------------------------*/
+#ifdef CSR_MEM_DEBUG
+void *CsrMemCallocDebug(CsrSize numberOfElements, CsrSize elementSize,
+    const CsrCharString *file, CsrUint32 line);
+#define CsrMemCalloc(cnt, sz) CsrMemAllocDebug((cnt), (sz), __FILE__, __LINE__)
+#else
+void *CsrMemCalloc(CsrSize numberOfElements, CsrSize elementSize);
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMemFree
+ *
+ *  DESCRIPTION
+ *      Free dynamic allocated memory.
+ *
+ *  RETURNS
+ *      void
+ *
+ *----------------------------------------------------------------------------*/
+void CsrMemFree(void *pointer);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMemAllocDma
+ *
+ *  DESCRIPTION
+ *      Allocate dynamic memory suitable for DMA transfers.
+ *
+ *  RETURNS
+ *      Pointer to allocated memory, or NULL in case of failure.
+ *      Allocated memory is not initialised.
+ *
+ *----------------------------------------------------------------------------*/
+#ifdef CSR_MEM_DEBUG
+void *CsrMemAllocDmaDebug(CsrSize size,
+    const CsrCharString *file, CsrUint32 line);
+#define CsrMemAllocDma(sz) CsrMemAllocDmaDebug((sz), __FILE__, __LINE__)
+#else
+void *CsrMemAllocDma(CsrSize size);
+#endif
+
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrMemFreeDma
+ *
+ *  DESCRIPTION
+ *      Free dynamic memory allocated by CsrMemAllocDma.
+ *
+ *  RETURNS
+ *      void
+ *
+ *----------------------------------------------------------------------------*/
+void CsrMemFreeDma(void *pointer);
+#else
+
+#include "csr_pmem.h"
+
+#define CsrMemAlloc(size) CsrPmemDebugAlloc(size, CSR_PMEM_DEBUG_TYPE_MEM_ALLOC, __FILE__, __LINE__)
+
+#define CsrMemCalloc(numberOfElements, elementSize) CsrPmemDebugAlloc((numberOfElements * elementSize), CSR_PMEM_DEBUG_TYPE_MEM_CALLOC, __FILE__, __LINE__)
+
+#define CsrMemFree(ptr) CsrPmemDebugFree(ptr,CSR_PMEM_DEBUG_TYPE_MEM_ALLOC,  __FILE__, __LINE__)
+
+#define CsrMemAllocDma(size) CsrPmemDebugAlloc(size, CSR_PMEM_DEBUG_TYPE_MEM_ALLOC_DMA, __FILE__, __LINE__)
+
+#define CsrMemFreeDma(ptr) CsrPmemDebugFree(ptr, CSR_PMEM_DEBUG_TYPE_MEM_ALLOC_DMA, __FILE__, __LINE__)
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_framework_ext_types.h b/drivers/staging/csr/csr_framework_ext_types.h
new file mode 100644
index 0000000..d155a2b
--- /dev/null
+++ b/drivers/staging/csr/csr_framework_ext_types.h
@@ -0,0 +1,65 @@
+#ifndef CSR_FRAMEWORK_EXT_TYPES_H__
+#define CSR_FRAMEWORK_EXT_TYPES_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+
+#ifdef __KERNEL__
+#include <linux/kthread.h>
+#include <linux/semaphore.h>
+#else
+#include <pthread.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __KERNEL__
+
+struct CsrThread
+{
+    struct task_struct *thread_task;
+    char                name[16];
+};
+
+struct CsrEvent
+{
+    /* wait_queue for waking the kernel thread */
+    wait_queue_head_t wakeup_q;
+    unsigned int      wakeup_flag;
+};
+
+typedef struct CsrEvent CsrEventHandle;
+typedef struct semaphore CsrMutexHandle;
+typedef struct CsrThread CsrThreadHandle;
+
+#else /* __KERNEL __ */
+
+struct CsrEvent
+{
+    pthread_cond_t  event;
+    pthread_mutex_t mutex;
+    CsrUint32       eventBits;
+};
+
+typedef struct CsrEvent CsrEventHandle;
+typedef pthread_mutex_t CsrMutexHandle;
+typedef pthread_t CsrThreadHandle;
+
+#endif /* __KERNEL__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_lib.h b/drivers/staging/csr/csr_lib.h
new file mode 100644
index 0000000..171f5fe
--- /dev/null
+++ b/drivers/staging/csr/csr_lib.h
@@ -0,0 +1,189 @@
+#ifndef CSR_LIB_H__
+#define CSR_LIB_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+#include "csr_prim_defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+    CsrPrim type;
+} CsrEvent;
+
+/*----------------------------------------------------------------------------*
+ *  CsrEvent_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrEvent
+ *
+ *----------------------------------------------------------------------------*/
+CsrEvent *CsrEvent_struct(CsrUint16 primtype, CsrUint16 msgtype);
+
+typedef struct
+{
+    CsrPrim  type;
+    CsrUint8 value;
+} CsrEventCsrUint8;
+
+/*----------------------------------------------------------------------------*
+ *  CsrEventCsrUint8_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrEventCsrUint8
+ *
+ *----------------------------------------------------------------------------*/
+CsrEventCsrUint8 *CsrEventCsrUint8_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrUint8 value);
+
+typedef struct
+{
+    CsrPrim   type;
+    CsrUint16 value;
+} CsrEventCsrUint16;
+
+/*----------------------------------------------------------------------------*
+ *  CsrEventCsrUint16_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrEventCsrUint16
+ *
+ *----------------------------------------------------------------------------*/
+CsrEventCsrUint16 *CsrEventCsrUint16_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrUint16 value);
+
+typedef struct
+{
+    CsrPrim   type;
+    CsrUint16 value1;
+    CsrUint8  value2;
+} CsrEventCsrUint16CsrUint8;
+
+/*----------------------------------------------------------------------------*
+ *  CsrEventCsrUint16CsrUint8_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrEventCsrUint16CsrUint8
+ *
+ *----------------------------------------------------------------------------*/
+CsrEventCsrUint16CsrUint8 *CsrEventCsrUint16CsrUint8_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrUint16 value1, CsrUint8 value2);
+
+typedef struct
+{
+    CsrPrim   type;
+    CsrUint16 value1;
+    CsrUint16 value2;
+} CsrEventCsrUint16CsrUint16;
+
+/*----------------------------------------------------------------------------*
+ *  CsrEventCsrUint16CsrUint16_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrEventCsrUint16CsrUint16
+ *
+ *----------------------------------------------------------------------------*/
+CsrEventCsrUint16CsrUint16 *CsrEventCsrUint16CsrUint16_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrUint16 value1, CsrUint16 value2);
+
+typedef struct
+{
+    CsrPrim   type;
+    CsrUint16 value1;
+    CsrUint32 value2;
+} CsrEventCsrUint16CsrUint32;
+
+/*----------------------------------------------------------------------------*
+ *  CsrEventCsrUint16_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrEventCsrUint16
+ *
+ *----------------------------------------------------------------------------*/
+CsrEventCsrUint16CsrUint32 *CsrEventCsrUint16CsrUint32_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrUint16 value1, CsrUint32 value2);
+
+typedef struct
+{
+    CsrPrim        type;
+    CsrUint16      value1;
+    CsrCharString *value2;
+} CsrEventCsrUint16CsrCharString;
+
+/*----------------------------------------------------------------------------*
+ *  CsrEventCsrUint16CsrCharString_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrEventCsrUint16CsrCharString
+ *
+ *----------------------------------------------------------------------------*/
+CsrEventCsrUint16CsrCharString *CsrEventCsrUint16CsrCharString_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrUint16 value1, CsrCharString *value2);
+
+typedef struct
+{
+    CsrPrim   type;
+    CsrUint32 value;
+} CsrEventCsrUint32;
+
+/*----------------------------------------------------------------------------*
+ *  CsrEventCsrUint32_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrEventCsrUint32
+ *
+ *----------------------------------------------------------------------------*/
+CsrEventCsrUint32 *CsrEventCsrUint32_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrUint32 value);
+
+typedef struct
+{
+    CsrPrim   type;
+    CsrUint32 value1;
+    CsrUint16 value2;
+} CsrEventCsrUint32CsrUint16;
+
+/*----------------------------------------------------------------------------*
+ *  CsrEventCsrUint32CsrUint16_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrEventCsrUint32CsrUint16
+ *
+ *----------------------------------------------------------------------------*/
+CsrEventCsrUint32CsrUint16 *CsrEventCsrUint32CsrUint16_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrUint32 value1, CsrUint32 value2);
+
+typedef struct
+{
+    CsrPrim        type;
+    CsrUint32      value1;
+    CsrCharString *value2;
+} CsrEventCsrUint32CsrCharString;
+
+/*----------------------------------------------------------------------------*
+ *  CsrEventCsrUint32CsrCharString_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrEventCsrUint32CsrCharString
+ *
+ *----------------------------------------------------------------------------*/
+CsrEventCsrUint32CsrCharString *CsrEventCsrUint32CsrCharString_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrUint32 value1, CsrCharString *value2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_LIB_H__ */
diff --git a/drivers/staging/csr/csr_log.h b/drivers/staging/csr/csr_log.h
new file mode 100644
index 0000000..db2653c
--- /dev/null
+++ b/drivers/staging/csr/csr_log.h
@@ -0,0 +1,250 @@
+#ifndef CSR_LOG_H__
+#define CSR_LOG_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+#include "csr_sched.h"
+#include "csr_panic.h"
+#include "csr_prim_defs.h"
+#include "csr_msgconv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Log filtering
+ */
+
+/*----------------------------------------------------*/
+/*  Filtering on environment specific log levels      */
+/*----------------------------------------------------*/
+typedef CsrUint32 CsrLogLevelEnvironment;
+#define CSR_LOG_LEVEL_ENVIRONMENT_OFF          ((CsrLogLevelEnvironment) 0x00000000) /* No environment data/events are logged */
+#define CSR_LOG_LEVEL_ENVIRONMENT_BCI_ACL      ((CsrLogLevelEnvironment) 0x00000001) /* BlueCore Channel Interface HCI Acl data are logged */
+#define CSR_LOG_LEVEL_ENVIRONMENT_BCI_HCI      ((CsrLogLevelEnvironment) 0x00000002) /* BlueCore Channel Interface HCI Cmd/Evt data are logged */
+#define CSR_LOG_LEVEL_ENVIRONMENT_BCI_SCO      ((CsrLogLevelEnvironment) 0x00000004) /* BlueCore Channel Interface HCI Sco data are logged */
+#define CSR_LOG_LEVEL_ENVIRONMENT_BCI_VENDOR   ((CsrLogLevelEnvironment) 0x00000008) /* BlueCore Channel Interface HCI Vendor specific data are logged (This includes BCCMD, HQ, VM etc) */
+#define CSR_LOG_LEVEL_ENVIRONMENT_TRANSPORTS   ((CsrLogLevelEnvironment) 0x00000010) /* Transport protocol data is logged (This includes transport protocols like BCSP, H4 etc.) */
+#define CSR_LOG_LEVEL_ENVIRONMENT_BGINT_REG    ((CsrLogLevelEnvironment) 0x00000020) /* Background Interrupt registration events are logged */
+#define CSR_LOG_LEVEL_ENVIRONMENT_BGINT_UNREG  ((CsrLogLevelEnvironment) 0x00000040) /* Background Interrupt unregistration events are logged */
+#define CSR_LOG_LEVEL_ENVIRONMENT_BGINT_SET    ((CsrLogLevelEnvironment) 0x00000080) /* Background Interrupt set events are logged */
+#define CSR_LOG_LEVEL_ENVIRONMENT_BGINT_START  ((CsrLogLevelEnvironment) 0x00000100) /* Background Interrupt start events are logged */
+#define CSR_LOG_LEVEL_ENVIRONMENT_BGINT_DONE   ((CsrLogLevelEnvironment) 0x00000200) /* Background Interrupt done events are logged */
+#define CSR_LOG_LEVEL_ENVIRONMENT_PROTO        ((CsrLogLevelEnvironment) 0x00000400) /* Transport protocol events are logged */
+#define CSR_LOG_LEVEL_ENVIRONMENT_PROTO_LOC    ((CsrLogLevelEnvironment) 0x00000800) /* The Location where the transport protocol event occured are logged NB: This is a supplement to CSR_LOG_LEVEL_ENVIRONMENT_PROTO, it has no effect without it */
+/* The bit masks between here are reserved for future usage */
+#define CSR_LOG_LEVEL_ENVIRONMENT_ALL          ((CsrLogLevelEnvironment) 0xFFFFFFFF) /* All possible environment data/events are logged WARNING: By using this define the application also accepts future possible environment data/events in the logs */
+
+/*----------------------------------------------------*/
+/*  Filtering on task specific log levels             */
+/*----------------------------------------------------*/
+typedef CsrUint32 CsrLogLevelTask;
+#define CSR_LOG_LEVEL_TASK_OFF                 ((CsrLogLevelTask) 0x00000000) /* No events are logged for this task */
+#define CSR_LOG_LEVEL_TASK_TEXT                ((CsrLogLevelTask) 0x00000001) /* Text strings printed by a task are logged NB: This bit does not affect the CSR_LOG_TEXT_LEVEL interface. This has to be configured separately */
+#define CSR_LOG_LEVEL_TASK_TEXT_LOC            ((CsrLogLevelTask) 0x00000002) /* The locaction where the text string call occured are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_TEXT, it has no effect without it */
+#define CSR_LOG_LEVEL_TASK_STATE               ((CsrLogLevelTask) 0x00000004) /* FSM state transitions in a task are logged */
+#define CSR_LOG_LEVEL_TASK_STATE_NAME          ((CsrLogLevelTask) 0x00000008) /* The name of each state in a FSM state transition are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_STATE, it has no effect without it */
+#define CSR_LOG_LEVEL_TASK_STATE_LOC           ((CsrLogLevelTask) 0x00000010) /* The location where the FSM state transition occured are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_STATE, it has no effect without it */
+#define CSR_LOG_LEVEL_TASK_TASK_SWITCH         ((CsrLogLevelTask) 0x00000020) /* Activation and deactiation of a task are logged */
+#define CSR_LOG_LEVEL_TASK_MESSAGE_PUT         ((CsrLogLevelTask) 0x00000080) /* Message put operations are logged */
+#define CSR_LOG_LEVEL_TASK_MESSAGE_PUT_LOC     ((CsrLogLevelTask) 0x00000100) /* The location where a message was sent are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_MESSAGE_PUT, it has no effect without it */
+#define CSR_LOG_LEVEL_TASK_MESSAGE_GET         ((CsrLogLevelTask) 0x00000200) /* Message get operations are logged */
+#define CSR_LOG_LEVEL_TASK_MESSAGE_QUEUE_PUSH  ((CsrLogLevelTask) 0x00000400) /* Message push operations are logged */
+#define CSR_LOG_LEVEL_TASK_MESSAGE_QUEUE_POP   ((CsrLogLevelTask) 0x00000800) /* Message pop operations are logged */
+#define CSR_LOG_LEVEL_TASK_PRIM_ONLY_TYPE      ((CsrLogLevelTask) 0x00001000) /* Only the type of primitives in messages are logged. By default the entire primitive is serialized and logged */
+#define CSR_LOG_LEVEL_TASK_PRIM_APPLY_LIMIT    ((CsrLogLevelTask) 0x00002000) /* An upper limit (defined by CSR_LOG_PRIM_SIZE_UPPER_LIMIT) is applied to how much of a primitive in a message are logged. NB: This limit is only applied if CSR_LOG_LEVEL_TASK_PRIM_ONLY_TYPE is _not_ defined */
+#define CSR_LOG_LEVEL_TASK_TIMER_IN            ((CsrLogLevelTask) 0x00004000) /* TimedEventIn events are logged */
+#define CSR_LOG_LEVEL_TASK_TIMER_IN_LOC        ((CsrLogLevelTask) 0x00008000) /* The location where a timer was started are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_TIMER_IN, it has no effect without it */
+#define CSR_LOG_LEVEL_TASK_TIMER_CANCEL        ((CsrLogLevelTask) 0x00010000) /* TimedEventCancel events are logged */
+#define CSR_LOG_LEVEL_TASK_TIMER_CANCEL_LOC    ((CsrLogLevelTask) 0x00020000) /* The location where a timer was cancelled are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_TIMER_CANCEL, it has no effect without it */
+#define CSR_LOG_LEVEL_TASK_TIMER_FIRE          ((CsrLogLevelTask) 0x00040000) /* TimedEventFire events are logged */
+#define CSR_LOG_LEVEL_TASK_TIMER_DONE          ((CsrLogLevelTask) 0x00080000) /* TimedEventDone events are logged */
+/* The bit masks between here are reserved for future usage */
+#define CSR_LOG_LEVEL_TASK_ALL                 ((CsrLogLevelTask) 0xFFFFFFFF & ~(CSR_LOG_LEVEL_TASK_PRIM_ONLY_TYPE | CSR_LOG_LEVEL_TASK_PRIM_APPLY_LIMIT)) /* All info possible to log for a task are logged. WARNING: By using this define the application also accepts future possible task data/events in the logs */
+
+CsrBool CsrLogEnvironmentIsFiltered(CsrLogLevelEnvironment level);
+CsrLogLevelTask CsrLogTaskFilterGet(CsrSchedQid taskId);
+CsrBool CsrLogTaskIsFiltered(CsrSchedQid taskId, CsrLogLevelTask level);
+
+/*
+ * Logging stuff
+ */
+#define CSR_LOG_STRINGIFY_REAL(a) #a
+#define CSR_LOG_STRINGIFY(a) CSR_LOG_STRINGIFY_REAL(a)
+
+#ifdef CSR_LOG_ASSERT_ENABLE
+#define CSR_LOG_ASSERT(cond)                        \
+    do {                                                \
+        if (!(cond))                                    \
+        {                                               \
+            CsrCharString *panic_arg = "[" __FILE__ ":" CSR_LOG_STRINGIFY(__LINE__) "] - " CSR_LOG_STRINGIFY(cond); \
+            CsrPanic(CSR_TECH_FW, CSR_PANIC_FW_ASSERTION_FAIL, panic_arg); \
+        }                                               \
+    } while (0)
+#else
+#define CSR_LOG_ASSERT(cond)
+#endif
+
+typedef struct
+{
+    CsrUint16            primitiveType;
+    const CsrCharString *primitiveName;
+    CsrMsgConvMsgEntry  *messageConv; /* Private - do not use */
+} CsrLogPrimitiveInformation;
+
+typedef struct
+{
+    const CsrCharString        *techVer;
+    CsrUint32                   primitiveInfoCount;
+    CsrLogPrimitiveInformation *primitiveInfo;
+} CsrLogTechInformation;
+
+/*---------------------------------*/
+/*  Tech logging */
+/*---------------------------------*/
+typedef CsrUint8 bitmask8_t;
+typedef CsrUint16 bitmask16_t;
+typedef CsrUint32 bitmask32_t;
+
+#ifdef CSR_LOG_ENABLE
+#ifdef CSR_LOG_INCLUDE_FILE_NAME_AND_LINE_NUMBER
+/* DEPRECATED - replaced by csr_log_text.h */
+#define CSR_LOG_TEXT(text) \
+    do { \
+        if (!CsrLogTaskIsFiltered(CsrSchedTaskQueueGet(), CSR_LOG_LEVEL_TASK_TEXT)) \
+        { \
+            CsrLogTaskText(text, __LINE__, __FILE__); \
+        } \
+    } while (0)
+#else
+/* DEPRECATED - replaced by csr_log_text.h */
+#define CSR_LOG_TEXT(text) \
+    do { \
+        if (!CsrLogTaskIsFiltered(CsrSchedTaskQueueGet(), CSR_LOG_LEVEL_TASK_TEXT)) \
+        { \
+            CsrLogTaskText(text, 0, NULL); \
+        } \
+    } while (0)
+#endif
+#else
+#define CSR_LOG_TEXT(text)
+#endif
+
+/* DEPRECATED - replaced by csr_log_text.h */
+void CsrLogTaskText(const CsrCharString *text,
+    CsrUint32 line,
+    const CsrCharString *file);
+
+#define CSR_LOG_STATE_TRANSITION_MASK_FSM_NAME          (0x001)
+#define CSR_LOG_STATE_TRANSITION_MASK_NEXT_STATE        (0x002)
+#define CSR_LOG_STATE_TRANSITION_MASK_NEXT_STATE_STR    (0x004)
+#define CSR_LOG_STATE_TRANSITION_MASK_PREV_STATE        (0x008)
+#define CSR_LOG_STATE_TRANSITION_MASK_PREV_STATE_STR    (0x010)
+#define CSR_LOG_STATE_TRANSITION_MASK_EVENT             (0x020)
+#define CSR_LOG_STATE_TRANSITION_MASK_EVENT_STR         (0x040)
+
+/* DEPRECATED - replaced by csr_log_text.h */
+void CsrLogStateTransition(bitmask16_t mask,
+    CsrUint32 identifier,
+    const CsrCharString *fsm_name,
+    CsrUint32 prev_state,
+    const CsrCharString *prev_state_str,
+    CsrUint32 in_event,
+    const CsrCharString *in_event_str,
+    CsrUint32 next_state,
+    const CsrCharString *next_state_str,
+    CsrUint32 line,
+    const CsrCharString *file);
+
+/*---------------------------------*/
+/*  BSP logging */
+/*---------------------------------*/
+void CsrLogSchedInit(CsrUint8 thread_id);
+void CsrLogSchedDeinit(CsrUint8 thread_id);
+
+void CsrLogSchedStart(CsrUint8 thread_id);
+void CsrLogSchedStop(CsrUint8 thread_id);
+
+void CsrLogInitTask(CsrUint8 thread_id, CsrSchedQid tskid, const CsrCharString *tskName);
+void CsrLogDeinitTask(CsrUint16 task_id);
+
+void CsrLogActivate(CsrSchedQid tskid);
+void CsrLogDeactivate(CsrSchedQid tskid);
+
+#define SYNERGY_SERIALIZER_TYPE_DUMP    (0x000)
+#define SYNERGY_SERIALIZER_TYPE_SER     (0x001)
+
+void CsrLogMessagePut(CsrUint32 line,
+    const CsrCharString *file,
+    CsrSchedQid src_task_id,
+    CsrSchedQid dst_taskid,
+    CsrSchedMsgId msg_id,
+    CsrUint16 prim_type,
+    const void *msg);
+
+void CsrLogMessageGet(CsrSchedQid src_task_id,
+    CsrSchedQid dst_taskid,
+    CsrBool get_res,
+    CsrSchedMsgId msg_id,
+    CsrUint16 prim_type,
+    const void *msg);
+
+void CsrLogTimedEventIn(CsrUint32 line,
+    const CsrCharString *file,
+    CsrSchedQid task_id,
+    CsrSchedTid tid,
+    CsrTime requested_delay,
+    CsrUint16 fniarg,
+    const void *fnvarg);
+
+void CsrLogTimedEventFire(CsrSchedQid task_id,
+    CsrSchedTid tid);
+
+void CsrLogTimedEventDone(CsrSchedQid task_id,
+    CsrSchedTid tid);
+
+void CsrLogTimedEventCancel(CsrUint32 line,
+    const CsrCharString *file,
+    CsrSchedQid task_id,
+    CsrSchedTid tid,
+    CsrBool cancel_res);
+
+void CsrLogBgintRegister(CsrUint8 thread_id,
+    CsrSchedBgint irq,
+    const CsrCharString *callback,
+    const void *ptr);
+void CsrLogBgintUnregister(CsrSchedBgint irq);
+void CsrLogBgintSet(CsrSchedBgint irq);
+void CsrLogBgintServiceStart(CsrSchedBgint irq);
+void CsrLogBgintServiceDone(CsrSchedBgint irq);
+
+void CsrLogExceptionStateEvent(CsrUint16 prim_type,
+    CsrPrim msg_type,
+    CsrUint16 state,
+    CsrUint32 line,
+    const CsrCharString *file);
+void CsrLogExceptionGeneral(CsrUint16 prim_type,
+    CsrUint16 state,
+    const CsrCharString *text,
+    CsrUint32 line,
+    const CsrCharString *file);
+void CsrLogExceptionWarning(CsrUint16 prim_type,
+    CsrUint16 state,
+    const CsrCharString *text,
+    CsrUint32 line,
+    const CsrCharString *file);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_log_configure.h b/drivers/staging/csr/csr_log_configure.h
new file mode 100644
index 0000000..3d48bf9
--- /dev/null
+++ b/drivers/staging/csr/csr_log_configure.h
@@ -0,0 +1,135 @@
+#ifndef CSR_LOG_CONFIGURE_H__
+#define CSR_LOG_CONFIGURE_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+#include "csr_log.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*---------------------------------*/
+/* Log init/deinit                 */
+/*---------------------------------*/
+void CsrLogInit(CsrUint8 size);
+void CsrLogDeinit(void);
+
+/*---------------------------------*/
+/* Log Framework Tech info         */
+/*---------------------------------*/
+void CsrLogTechInfoRegister(void);
+
+/* Set the logging level for the environment outside the scheduler context */
+void CsrLogLevelEnvironmentSet(CsrLogLevelEnvironment environmentLogLevel);
+
+
+/* Set the logging level for all scheduler tasks */
+/* This function call takes precedence over all previous calls to CsrLogLevelTaskSetSpecific() */
+void CsrLogLevelTaskSetAll(CsrLogLevelTask tasksLogLevelMask);
+
+/* Set the logging level for a given Task */
+/* This function can be used as a complement to CsrLogLevelTaskSetAll() to add more _or_ less log from a given task than what is set
+generally with CsrLogLevelTaskSetAll(). */
+void CsrLogLevelTaskSetSpecific(CsrSchedQid taskId, CsrLogLevelTask taskLogLevelMask);
+
+
+/*--------------------------------------------*/
+/*  Filtering on log text warning levels      */
+/*--------------------------------------------*/
+typedef CsrUint32 CsrLogLevelText;
+#define CSR_LOG_LEVEL_TEXT_OFF       ((CsrLogLevelText) 0x0000)
+
+#define CSR_LOG_LEVEL_TEXT_CRITICAL  ((CsrLogLevelText) 0x0001)
+#define CSR_LOG_LEVEL_TEXT_ERROR     ((CsrLogLevelText) 0x0002)
+#define CSR_LOG_LEVEL_TEXT_WARNING   ((CsrLogLevelText) 0x0004)
+#define CSR_LOG_LEVEL_TEXT_INFO      ((CsrLogLevelText) 0x0008)
+#define CSR_LOG_LEVEL_TEXT_DEBUG     ((CsrLogLevelText) 0x0010)
+
+#define CSR_LOG_LEVEL_TEXT_ALL       ((CsrLogLevelText) 0xFFFF)
+
+/* The log text interface is used by both scheduler tasks and components outside the scheduler context.
+ * Therefore a CsrLogTextTaskId is introduced. It is effectively considered as two CsrUint16's. The lower
+ * 16 bits corresponds one2one with the scheduler queueId's (CsrSchedQid) and as such these bits can not be used
+ * by components outside scheduler tasks. The upper 16 bits are allocated for use of components outside the
+ * scheduler like drivers etc. Components in this range is defined independently by each technology. To avoid
+ * clashes the technologies are only allowed to assign values within the same restrictive range as allies to
+ * primitive identifiers. eg. for the framework components outside the scheduler is only allowed to assign
+ * taskId's in the range 0x0600xxxx to 0x06FFxxxx. And so on for other technologies. */
+typedef CsrUint32 CsrLogTextTaskId;
+
+/* Set the text logging level for all Tasks */
+/* This function call takes precedence over all previous calls to CsrLogLevelTextSetTask() and CsrLogLevelTextSetTaskSubOrigin() */
+void CsrLogLevelTextSetAll(CsrLogLevelText warningLevelMask);
+
+/* Set the text logging level for a given Task */
+/* This function call takes precedence over all previous calls to CsrLogLevelTextSetTaskSubOrigin(), but it can be used as a complement to
+ * CsrLogLevelTextSetAll() to add more _or_ less log from a given task than what is set generally with CsrLogLevelTextSetAll(). */
+void CsrLogLevelTextSetTask(CsrLogTextTaskId taskId, CsrLogLevelText warningLevelMask);
+
+/* Set the text logging level for a given tasks subOrigin */
+/* This function can be used as a complement to CsrLogLevelTextSetAll() and CsrLogLevelTextSetTask() to add more _or_ less log from a given
+ * subOrigin within a task than what is set generally with CsrLogLevelTextSetAll() _or_ CsrLogLevelTextSetTask(). */
+void CsrLogLevelTextSetTaskSubOrigin(CsrLogTextTaskId taskId, CsrUint16 subOrigin, CsrLogLevelText warningLevelMask);
+
+/*******************************************************************************
+
+    NAME
+        CsrLogLevelTextSet
+
+    DESCRIPTION
+        Set the text logging level for a given origin and optionally sub origin
+        by name. If either string is NULL or zero length, it is interpreted as
+        all origins and/or all sub origins respectively. If originName is NULL
+        or zero length, subOriginName is ignored.
+
+        Passing NULL or zero length strings in both originName and subOriginName
+        is equivalent to calling CsrLogLevelTextSetAll, and overrides all
+        previous filter configurations for all origins and sub origins.
+
+        Passing NULL or a zero length string in subOriginName overrides all
+        previous filter configurations for all sub origins of the specified
+        origin.
+
+        Note: the supplied strings may be accessed after the function returns
+        and must remain valid and constant until CsrLogDeinit is called.
+
+        Note: when specifying an origin (originName is not NULL and not zero
+        length), this function can only be used for origins that use the
+        csr_log_text_2.h interface for registration and logging. Filtering for
+        origins that use the legacy csr_log_text.h interface must be be
+        configured using the legacy filter configuration functions that accept
+        a CsrLogTextTaskId as origin specifier. However, when not specifying an
+        origin this function also affects origins that have been registered with
+        the legacy csr_log_text.h interface. Furthermore, using this function
+        and the legacy filter configuration functions on the same origin is not
+        allowed.
+
+    PARAMETERS
+        originName - a string containing the name of the origin. Can be NULL or
+            zero length to set the log level for all origins. In this case, the
+            subOriginName parameter will be ignored.
+        subOriginName - a string containing the name of the sub origin. Can be
+            NULL or zero length to set the log level for all sub origins of the
+            specified origin.
+        warningLevelMask - The desired log level for the specified origin(s) and
+            sub origin(s).
+
+*******************************************************************************/
+void CsrLogLevelTextSet(const CsrCharString *originName,
+    const CsrCharString *subOriginName,
+    CsrLogLevelText warningLevelMask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_log_text.h b/drivers/staging/csr/csr_log_text.h
new file mode 100644
index 0000000..6e0df43
--- /dev/null
+++ b/drivers/staging/csr/csr_log_text.h
@@ -0,0 +1,133 @@
+#ifndef CSR_LOG_TEXT_H__
+#define CSR_LOG_TEXT_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+#include "csr_log_configure.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct CsrLogSubOrigin
+{
+    CsrUint16            subOriginNumber;  /* Id of the given SubOrigin */
+    const CsrCharString *subOriginName;    /* Prefix Text for this SubOrigin */
+} CsrLogSubOrigin;
+
+/* Register a task which is going to use the CSR_LOG_TEXT_XXX interface */
+#ifdef CSR_LOG_ENABLE
+void CsrLogTextRegister(CsrLogTextTaskId taskId, const CsrCharString *taskName, CsrUint16 subOriginsLength, const CsrLogSubOrigin *subOrigins);
+#else
+#define CsrLogTextRegister(taskId, taskName, subOriginsLength, subOrigins)
+#endif
+
+/* CRITICAL: Conditions that are threatening to the integrity/stability of the
+   system as a whole. */
+#if defined(CSR_LOG_ENABLE) && !defined(CSR_LOG_LEVEL_TEXT_CRITICAL_DISABLE)
+void CsrLogTextCritical(CsrLogTextTaskId taskId, CsrUint16 subOrigin, const CsrCharString *formatString, ...);
+void CsrLogTextBufferCritical(CsrLogTextTaskId taskId, CsrUint16 subOrigin, CsrSize bufferLength, const void *buffer, const CsrCharString *formatString, ...);
+#define CSR_LOG_TEXT_CRITICAL(taskId_subOrigin_formatString_varargs) CsrLogTextCritical taskId_subOrigin_formatString_varargs
+#define CSR_LOG_TEXT_CONDITIONAL_CRITICAL(condition, logtextargs) {if (condition) {CSR_LOG_TEXT_CRITICAL(logtextargs);}}
+#define CSR_LOG_TEXT_BUFFER_CRITICAL(taskId_subOrigin_length_buffer_formatString_varargs) CsrLogTextBufferCritical taskId_subOrigin_length_buffer_formatString_varargs
+#define CSR_LOG_TEXT_BUFFER_CONDITIONAL_CRITICAL(condition, logtextbufferargs) {if (condition) {CSR_LOG_TEXT_BUFFER_CRITICAL(logtextbufferargs);}}
+#else
+#define CSR_LOG_TEXT_CRITICAL(taskId_subOrigin_formatString_varargs)
+#define CSR_LOG_TEXT_CONDITIONAL_CRITICAL(condition, logtextargs)
+#define CSR_LOG_TEXT_BUFFER_CRITICAL(taskId_subOrigin_length_buffer_formatString_varargs)
+#define CSR_LOG_TEXT_BUFFER_CONDITIONAL_CRITICAL(condition, logtextbufferargs)
+#endif
+
+/* ERROR: Malfunction of a component rendering it unable to operate correctly,
+   causing lack of functionality but not loss of system integrity/stability. */
+#if defined(CSR_LOG_ENABLE) && !defined(CSR_LOG_LEVEL_TEXT_ERROR_DISABLE)
+void CsrLogTextError(CsrLogTextTaskId taskId, CsrUint16 subOrigin, const CsrCharString *formatString, ...);
+void CsrLogTextBufferError(CsrLogTextTaskId taskId, CsrUint16 subOrigin, CsrSize bufferLength, const void *buffer, const CsrCharString *formatString, ...);
+#define CSR_LOG_TEXT_ERROR(taskId_subOrigin_formatString_varargs) CsrLogTextError taskId_subOrigin_formatString_varargs
+#define CSR_LOG_TEXT_CONDITIONAL_ERROR(condition, logtextargs) {if (condition) {CSR_LOG_TEXT_ERROR(logtextargs);}}
+#define CSR_LOG_TEXT_BUFFER_ERROR(taskId_subOrigin_length_buffer_formatString_varargs) CsrLogTextBufferError taskId_subOrigin_length_buffer_formatString_varargs
+#define CSR_LOG_TEXT_BUFFER_CONDITIONAL_ERROR(condition, logtextbufferargs) {if (condition) {CSR_LOG_TEXT_BUFFER_ERROR(logtextbufferargs);}}
+#else
+#define CSR_LOG_TEXT_ERROR(taskId_subOrigin_formatString_varargs)
+#define CSR_LOG_TEXT_CONDITIONAL_ERROR(condition, logtextargs)
+#define CSR_LOG_TEXT_BUFFER_ERROR(taskId_subOrigin_length_buffer_formatString_varargs)
+#define CSR_LOG_TEXT_BUFFER_CONDITIONAL_ERROR(condition, logtextbufferargs)
+#endif
+
+/* WARNING: Conditions that are unexpected and indicative of possible problems
+   or violations of specifications, where the result of such deviations does not
+   lead to malfunction of the component. */
+#if defined(CSR_LOG_ENABLE) && !defined(CSR_LOG_LEVEL_TEXT_WARNING_DISABLE)
+void CsrLogTextWarning(CsrLogTextTaskId taskId, CsrUint16 subOrigin, const CsrCharString *formatString, ...);
+void CsrLogTextBufferWarning(CsrLogTextTaskId taskId, CsrUint16 subOrigin, CsrSize bufferLength, const void *buffer, const CsrCharString *formatString, ...);
+#define CSR_LOG_TEXT_WARNING(taskId_subOrigin_formatString_varargs) CsrLogTextWarning taskId_subOrigin_formatString_varargs
+#define CSR_LOG_TEXT_CONDITIONAL_WARNING(condition, logtextargs) {if (condition) {CSR_LOG_TEXT_WARNING(logtextargs);}}
+#define CSR_LOG_TEXT_BUFFER_WARNING(taskId_subOrigin_length_buffer_formatString_varargs) CsrLogTextBufferWarning taskId_subOrigin_length_buffer_formatString_varargs
+#define CSR_LOG_TEXT_BUFFER_CONDITIONAL_WARNING(condition, logtextbufferargs) {if (condition) {CSR_LOG_TEXT_BUFFER_WARNING(logtextbufferargs);}}
+#else
+#define CSR_LOG_TEXT_WARNING(taskId_subOrigin_formatString_varargs)
+#define CSR_LOG_TEXT_CONDITIONAL_WARNING(condition, logtextargs)
+#define CSR_LOG_TEXT_BUFFER_WARNING(taskId_subOrigin_length_buffer_formatString_varargs)
+#define CSR_LOG_TEXT_BUFFER_CONDITIONAL_WARNING(condition, logtextbufferargs)
+#endif
+
+/* INFO: Important events that may aid in determining the conditions under which
+   the more severe conditions are encountered. */
+#if defined(CSR_LOG_ENABLE) && !defined(CSR_LOG_LEVEL_TEXT_INFO_DISABLE)
+void CsrLogTextInfo(CsrLogTextTaskId taskId, CsrUint16 subOrigin, const CsrCharString *formatString, ...);
+void CsrLogTextBufferInfo(CsrLogTextTaskId taskId, CsrUint16 subOrigin, CsrSize bufferLength, const void *buffer, const CsrCharString *formatString, ...);
+#define CSR_LOG_TEXT_INFO(taskId_subOrigin_formatString_varargs) CsrLogTextInfo taskId_subOrigin_formatString_varargs
+#define CSR_LOG_TEXT_CONDITIONAL_INFO(condition, logtextargs) {if (condition) {CSR_LOG_TEXT_INFO(logtextargs);}}
+#define CSR_LOG_TEXT_BUFFER_INFO(taskId_subOrigin_length_buffer_formatString_varargs) CsrLogTextBufferInfo taskId_subOrigin_length_buffer_formatString_varargs
+#define CSR_LOG_TEXT_BUFFER_CONDITIONAL_INFO(condition, logtextbufferargs) {if (condition) {CSR_LOG_TEXT_BUFFER_INFO(logtextbufferargs);}}
+#else
+#define CSR_LOG_TEXT_INFO(taskId_subOrigin_formatString_varargs)
+#define CSR_LOG_TEXT_CONDITIONAL_INFO(condition, logtextargs)
+#define CSR_LOG_TEXT_BUFFER_INFO(taskId_subOrigin_length_buffer_formatString_varargs)
+#define CSR_LOG_TEXT_BUFFER_CONDITIONAL_INFO(condition, logtextbufferargs)
+#endif
+
+/* DEBUG: Similar to INFO, but dedicated to events that occur more frequently. */
+#if defined(CSR_LOG_ENABLE) && !defined(CSR_LOG_LEVEL_TEXT_DEBUG_DISABLE)
+void CsrLogTextDebug(CsrLogTextTaskId taskId, CsrUint16 subOrigin, const CsrCharString *formatString, ...);
+void CsrLogTextBufferDebug(CsrLogTextTaskId taskId, CsrUint16 subOrigin, CsrSize bufferLength, const void *buffer, const CsrCharString *formatString, ...);
+#define CSR_LOG_TEXT_DEBUG(taskId_subOrigin_formatString_varargs) CsrLogTextDebug taskId_subOrigin_formatString_varargs
+#define CSR_LOG_TEXT_CONDITIONAL_DEBUG(condition, logtextargs) {if (condition) {CSR_LOG_TEXT_DEBUG(logtextargs);}}
+#define CSR_LOG_TEXT_BUFFER_DEBUG(taskId_subOrigin_length_buffer_formatString_varargs) CsrLogTextBufferDebug taskId_subOrigin_length_buffer_formatString_varargs
+#define CSR_LOG_TEXT_BUFFER_CONDITIONAL_DEBUG(condition, logtextbufferargs) {if (condition) {CSR_LOG_TEXT_BUFFER_DEBUG(logtextbufferargs);}}
+#else
+#define CSR_LOG_TEXT_DEBUG(taskId_subOrigin_formatString_varargs)
+#define CSR_LOG_TEXT_CONDITIONAL_DEBUG(condition, logtextargs)
+#define CSR_LOG_TEXT_BUFFER_DEBUG(taskId_subOrigin_length_buffer_formatString_varargs)
+#define CSR_LOG_TEXT_BUFFER_CONDITIONAL_DEBUG(condition, logtextbufferargs)
+#endif
+
+/* CSR_LOG_TEXT_ASSERT (CRITICAL) */
+#ifdef CSR_LOG_ENABLE
+#define CSR_LOG_TEXT_ASSERT(origin, suborigin, condition) \
+    {if (!(condition)) {CSR_LOG_TEXT_CRITICAL((origin, suborigin, "Assertion \"%s\" failed at %s:%u", #condition, __FILE__, __LINE__));}}
+#else
+#define CSR_LOG_TEXT_ASSERT(origin, suborigin, condition)
+#endif
+
+/* CSR_LOG_TEXT_UNHANDLED_PRIM (CRITICAL) */
+#ifdef CSR_LOG_ENABLE
+#define CSR_LOG_TEXT_UNHANDLED_PRIMITIVE(origin, suborigin, primClass, primType) \
+    CSR_LOG_TEXT_CRITICAL((origin, suborigin, "Unhandled primitive 0x%04X:0x%04X at %s:%u", primClass, primType, __FILE__, __LINE__))
+#else
+#define CSR_LOG_TEXT_UNHANDLED_PRIMITIVE(origin, suborigin, primClass, primType)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_macro.h b/drivers/staging/csr/csr_macro.h
new file mode 100644
index 0000000..2e3dcac
--- /dev/null
+++ b/drivers/staging/csr/csr_macro.h
@@ -0,0 +1,111 @@
+#ifndef CSR_MACRO_H__
+#define CSR_MACRO_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*------------------------------------------------------------------*/
+/* Bits - intended to operate on CsrUint32 values */
+/*------------------------------------------------------------------*/
+#define CSR_MASK_IS_SET(val, mask) (((val) & (mask)) == (mask))
+#define CSR_MASK_IS_UNSET(val, mask) ((((val) & (mask)) ^ mask) == (mask))
+#define CSR_MASK_SET(val, mask)    ((val) |= (mask))
+#define CSR_MASK_UNSET(val, mask)  ((val) = ((val) ^ (mask)) & (val)) /* Unsets the bits in val that are set in mask */
+#define CSR_BIT_IS_SET(val, bit)   ((CsrBool) ((((val) & (1UL << (bit))) != 0)))
+#define CSR_BIT_SET(val, bit)      ((val) |= (1UL << (bit)))
+#define CSR_BIT_UNSET(val, bit)    ((val) &= ~(1UL << (bit)))
+#define CSR_BIT_TOGGLE(val, bit)   ((val) ^= (1UL << (bit)))
+
+/*------------------------------------------------------------------*/
+/* Endian conversion */
+/*------------------------------------------------------------------*/
+#define CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr)        (((CsrUint16) ((CsrUint8 *) (ptr))[0]) | ((CsrUint16) ((CsrUint8 *) (ptr))[1]) << 8)
+#define CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr)        (((CsrUint32) ((CsrUint8 *) (ptr))[0]) | ((CsrUint32) ((CsrUint8 *) (ptr))[1]) << 8 | \
+                                                       ((CsrUint32) ((CsrUint8 *) (ptr))[2]) << 16 | ((CsrUint32) ((CsrUint8 *) (ptr))[3]) << 24)
+#define CSR_COPY_UINT16_TO_LITTLE_ENDIAN(uint, ptr)    ((CsrUint8 *) (ptr))[0] = ((CsrUint8) ((uint) & 0x00FF)); \
+    ((CsrUint8 *) (ptr))[1] = ((CsrUint8) ((uint) >> 8))
+#define CSR_COPY_UINT32_TO_LITTLE_ENDIAN(uint, ptr)    ((CsrUint8 *) (ptr))[0] = ((CsrUint8) ((uint) & 0x000000FF)); \
+    ((CsrUint8 *) (ptr))[1] = ((CsrUint8) (((uint) >> 8) & 0x000000FF)); \
+    ((CsrUint8 *) (ptr))[2] = ((CsrUint8) (((uint) >> 16) & 0x000000FF)); \
+    ((CsrUint8 *) (ptr))[3] = ((CsrUint8) (((uint) >> 24) & 0x000000FF))
+#define CSR_GET_UINT16_FROM_BIG_ENDIAN(ptr) (((CsrUint16) ((CsrUint8 *) (ptr))[1]) | ((CsrUint16) ((CsrUint8 *) (ptr))[0]) << 8)
+#define CSR_GET_UINT24_FROM_BIG_ENDIAN(ptr) (((CsrUint24) ((CsrUint8 *) (ptr))[2]) | \
+                                             ((CsrUint24) ((CsrUint8 *) (ptr))[1]) << 8 | ((CsrUint24) ((CsrUint8 *) (ptr))[0]) << 16)
+#define CSR_GET_UINT32_FROM_BIG_ENDIAN(ptr) (((CsrUint32) ((CsrUint8 *) (ptr))[3]) | ((CsrUint32) ((CsrUint8 *) (ptr))[2]) << 8 | \
+                                             ((CsrUint32) ((CsrUint8 *) (ptr))[1]) << 16 | ((CsrUint32) ((CsrUint8 *) (ptr))[0]) << 24)
+#define CSR_COPY_UINT16_TO_BIG_ENDIAN(uint, ptr)    ((CsrUint8 *) (ptr))[1] = ((CsrUint8) ((uint) & 0x00FF)); \
+    ((CsrUint8 *) (ptr))[0] = ((CsrUint8) ((uint) >> 8))
+#define CSR_COPY_UINT24_TO_BIG_ENDIAN(uint, ptr)    ((CsrUint8 *) (ptr))[2] = ((CsrUint8) ((uint) & 0x000000FF)); \
+    ((CsrUint8 *) (ptr))[1] = ((CsrUint8) (((uint) >> 8) & 0x000000FF)); \
+    ((CsrUint8 *) (ptr))[0] = ((CsrUint8) (((uint) >> 16) & 0x000000FF))
+#define CSR_COPY_UINT32_TO_BIG_ENDIAN(uint, ptr)    ((CsrUint8 *) (ptr))[3] = ((CsrUint8) ((uint) & 0x000000FF)); \
+    ((CsrUint8 *) (ptr))[2] = ((CsrUint8) (((uint) >> 8) & 0x000000FF)); \
+    ((CsrUint8 *) (ptr))[1] = ((CsrUint8) (((uint) >> 16) & 0x000000FF)); \
+    ((CsrUint8 *) (ptr))[0] = ((CsrUint8) (((uint) >> 24) & 0x000000FF))
+
+/*------------------------------------------------------------------*/
+/* XAP conversion macros */
+/*------------------------------------------------------------------*/
+
+#define CSR_LSB16(a) ((CsrUint8) ((a) & 0x00ff))
+#define CSR_MSB16(b) ((CsrUint8) ((b) >> 8))
+
+#define CSR_CONVERT_8_FROM_XAP(output, input) \
+    (output) = ((CsrUint8) (input));(input) += 2
+
+#define CSR_CONVERT_16_FROM_XAP(output, input) \
+    (output) = (CsrUint16) ((((CsrUint16) (input)[1]) << 8) | \
+                            ((CsrUint16) (input)[0]));(input) += 2
+
+#define CSR_CONVERT_32_FROM_XAP(output, input) \
+    (output) = (((CsrUint32) (input)[1]) << 24) | \
+               (((CsrUint32) (input)[0]) << 16) | \
+               (((CsrUint32) (input)[3]) << 8) | \
+               ((CsrUint32) (input)[2]);input += 4
+
+#define CSR_ADD_UINT8_TO_XAP(output, input) \
+    (output)[0] = (input);  \
+    (output)[1] = 0;(output) += 2
+
+#define CSR_ADD_UINT16_TO_XAP(output, input) \
+    (output)[0] = ((CsrUint8) ((input) & 0x00FF));  \
+    (output)[1] = ((CsrUint8) ((input) >> 8));(output) += 2
+
+#define CSR_ADD_UINT32_TO_XAP(output, input) \
+    (output)[0] = ((CsrUint8) (((input) >> 16) & 0x00FF)); \
+    (output)[1] = ((CsrUint8) ((input) >> 24)); \
+    (output)[2] = ((CsrUint8) ((input) & 0x00FF)); \
+    (output)[3] = ((CsrUint8) (((input) >> 8) & 0x00FF));(output) += 4
+
+/*------------------------------------------------------------------*/
+/* Misc */
+/*------------------------------------------------------------------*/
+#define CSRMAX(a, b)    (((a) > (b)) ? (a) : (b))
+#define CSRMIN(a, b)    (((a) < (b)) ? (a) : (b))
+
+/* Use this macro on unused local variables that cannot be removed (such as
+   unused function parameters). This will quell warnings from certain compilers
+   and static code analysis tools like Lint and Valgrind. */
+#define CSR_UNUSED(x) ((void) (x))
+
+#define CSR_TOUPPER(character)  (((character) >= 'a') && ((character) <= 'z') ? ((character) - 0x20) : (character))
+#define CSR_TOLOWER(character)  (((character) >= 'A') && ((character) <= 'Z') ? ((character) + 0x20) : (character))
+#define CSR_ARRAY_SIZE(x)       (sizeof(x) / sizeof(*(x)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_msg_transport.h b/drivers/staging/csr/csr_msg_transport.h
new file mode 100644
index 0000000..b0095b0
--- /dev/null
+++ b/drivers/staging/csr/csr_msg_transport.h
@@ -0,0 +1,25 @@
+#ifndef CSR_MSG_TRANSPORT_H__
+#define CSR_MSG_TRANSPORT_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CsrMsgTransport
+#define CsrMsgTransport CsrSchedMessagePut
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_MSG_TRANSPORT */
diff --git a/drivers/staging/csr/csr_msgconv.c b/drivers/staging/csr/csr_msgconv.c
new file mode 100644
index 0000000..9f1c946
--- /dev/null
+++ b/drivers/staging/csr/csr_msgconv.c
@@ -0,0 +1,324 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include <linux/module.h>
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_panic.h"
+#include "csr_sched.h"
+#include "csr_msgconv.h"
+#include "csr_util.h"
+
+static CsrMsgConvEntry *converter;
+
+CsrMsgConvPrimEntry *CsrMsgConvFind(CsrUint16 primType)
+{
+    CsrMsgConvPrimEntry *ptr = NULL;
+
+    if (converter)
+    {
+        ptr = converter->profile_converters;
+        while (ptr)
+        {
+            if (ptr->primType == primType)
+            {
+                break;
+            }
+            else
+            {
+                ptr = ptr->next;
+            }
+        }
+    }
+
+    return ptr;
+}
+
+static const CsrMsgConvMsgEntry *find_msg_converter(CsrMsgConvPrimEntry *ptr, CsrUint16 msgType)
+{
+    const CsrMsgConvMsgEntry *cv = ptr->conv;
+    if (ptr->lookupFunc)
+    {
+        return (const CsrMsgConvMsgEntry *) ptr->lookupFunc((CsrMsgConvMsgEntry *) cv, msgType);
+    }
+
+    while (cv)
+    {
+        if (cv->serFunc == NULL)
+        {
+            /* We've reached the end of the chain */
+            cv = NULL;
+            break;
+        }
+
+        if (cv->msgType == msgType)
+        {
+            break;
+        }
+        else
+        {
+            cv++;
+        }
+    }
+
+    return cv;
+}
+
+static void *deserialize_data(CsrUint16 primType,
+    CsrSize length,
+    CsrUint8 *data)
+{
+    CsrMsgConvPrimEntry *ptr;
+    CsrUint8 *ret;
+
+    ptr = CsrMsgConvFind(primType);
+
+    if (ptr)
+    {
+        const CsrMsgConvMsgEntry *cv;
+        CsrUint16 msgId = 0;
+        CsrSize offset = 0;
+        CsrUint16Des(&msgId, data, &offset);
+
+        cv = find_msg_converter(ptr, msgId);
+        if (cv)
+        {
+            ret = cv->deserFunc(data, length);
+        }
+        else
+        {
+            ret = NULL;
+        }
+    }
+    else
+    {
+        ret = NULL;
+    }
+
+    return ret;
+}
+
+static CsrSize sizeof_message(CsrUint16 primType, void *msg)
+{
+    CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType);
+    CsrSize ret;
+
+    if (ptr)
+    {
+        const CsrMsgConvMsgEntry *cv;
+        CsrUint16 msgId = *(CsrUint16 *) msg;
+
+        cv = find_msg_converter(ptr, msgId);
+        if (cv)
+        {
+            ret = cv->sizeofFunc(msg);
+        }
+        else
+        {
+            ret = 0;
+        }
+    }
+    else
+    {
+        ret = 0;
+    }
+
+    return ret;
+}
+
+static CsrBool free_message(CsrUint16 primType, CsrUint8 *data)
+{
+    CsrMsgConvPrimEntry *ptr;
+    CsrBool ret;
+
+    ptr = CsrMsgConvFind(primType);
+
+    if (ptr)
+    {
+        const CsrMsgConvMsgEntry *cv;
+        CsrUint16 msgId = *(CsrUint16 *) data;
+
+        cv = find_msg_converter(ptr, msgId);
+        if (cv)
+        {
+            cv->freeFunc(data);
+            ret = TRUE;
+        }
+        else
+        {
+            ret = FALSE;
+        }
+    }
+    else
+    {
+        ret = FALSE;
+    }
+
+    return ret;
+}
+
+static CsrUint8 *serialize_message(CsrUint16 primType,
+    void *msg,
+    CsrSize *length,
+    CsrUint8 *buffer)
+{
+    CsrMsgConvPrimEntry *ptr;
+    CsrUint8 *ret;
+
+    ptr = CsrMsgConvFind(primType);
+
+    *length = 0;
+
+    if (ptr)
+    {
+        const CsrMsgConvMsgEntry *cv;
+
+        cv = find_msg_converter(ptr, *(CsrUint16 *) msg);
+        if (cv)
+        {
+            ret = cv->serFunc(buffer, length, msg);
+        }
+        else
+        {
+            ret = NULL;
+        }
+    }
+    else
+    {
+        ret = NULL;
+    }
+
+    return ret;
+}
+
+CsrSize CsrMsgConvSizeof(CsrUint16 primType, void *msg)
+{
+    return sizeof_message(primType, msg);
+}
+
+CsrUint8 *CsrMsgConvSerialize(CsrUint8 *buffer, CsrSize maxBufferOffset, CsrSize *offset, CsrUint16 primType, void *msg)
+{
+    if (converter)
+    {
+        CsrSize serializedLength;
+        CsrUint8 *bufSerialized;
+        CsrUint8 *bufOffset = &buffer[*offset];
+        bufSerialized = converter->serialize_message(primType, msg, &serializedLength, bufOffset);
+        *offset += serializedLength;
+        return bufSerialized;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+/* Insert profile converter at head of converter list. */
+void CsrMsgConvInsert(CsrUint16 primType, const CsrMsgConvMsgEntry *ce)
+{
+    CsrMsgConvPrimEntry *pc;
+    pc = CsrMsgConvFind(primType);
+
+    if (pc)
+    {
+        /* Already registered. Do nothing */
+    }
+    else
+    {
+        pc = CsrPmemAlloc(sizeof(*pc));
+        pc->primType = primType;
+        pc->conv = ce;
+        pc->lookupFunc = NULL;
+        pc->next = converter->profile_converters;
+        converter->profile_converters = pc;
+    }
+}
+EXPORT_SYMBOL_GPL(CsrMsgConvInsert);
+
+CsrMsgConvMsgEntry *CsrMsgConvFindEntry(CsrUint16 primType, CsrUint16 msgType)
+{
+    CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType);
+    if (ptr)
+    {
+        return (CsrMsgConvMsgEntry *) find_msg_converter(ptr, msgType);
+    }
+    return NULL;
+}
+EXPORT_SYMBOL_GPL(CsrMsgConvFindEntry);
+
+CsrMsgConvMsgEntry *CsrMsgConvFindEntryByMsg(CsrUint16 primType, const void *msg)
+{
+    CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType);
+    if (ptr && msg)
+    {
+        CsrUint16 msgType = *((CsrUint16 *) msg);
+        return (CsrMsgConvMsgEntry *) find_msg_converter(ptr, msgType);
+    }
+    return NULL;
+}
+
+void CsrMsgConvCustomLookupRegister(CsrUint16 primType, CsrMsgCustomLookupFunc *lookupFunc)
+{
+    CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType);
+    if (ptr)
+    {
+        ptr->lookupFunc = lookupFunc;
+    }
+}
+EXPORT_SYMBOL_GPL(CsrMsgConvCustomLookupRegister);
+
+CsrMsgConvEntry *CsrMsgConvInit(void)
+{
+    if (!converter)
+    {
+        converter = (CsrMsgConvEntry *) CsrPmemAlloc(sizeof(CsrMsgConvEntry));
+
+        converter->profile_converters = NULL;
+        converter->free_message = free_message;
+        converter->sizeof_message = sizeof_message;
+        converter->serialize_message = serialize_message;
+        converter->deserialize_data = deserialize_data;
+    }
+
+    return converter;
+}
+EXPORT_SYMBOL_GPL(CsrMsgConvInit);
+
+CsrMsgConvEntry *CsrMsgConvGet(void)
+{
+    return converter;
+}
+
+#ifdef ENABLE_SHUTDOWN
+void CsrMsgConvDeinit(void)
+{
+    CsrMsgConvPrimEntry *s;
+
+    if (converter == NULL)
+    {
+        return;
+    }
+
+    /* Walk converter list and free elements. */
+    s = converter->profile_converters;
+    while (s)
+    {
+        CsrMsgConvPrimEntry *s_next;
+        s_next = s->next;
+        CsrPmemFree(s);
+        s = s_next;
+    }
+
+    CsrPmemFree(converter);
+    converter = NULL;
+}
+EXPORT_SYMBOL_GPL(CsrMsgConvDeinit);
+
+#endif /* ENABLE_SHUTDOWN */
diff --git a/drivers/staging/csr/csr_msgconv.h b/drivers/staging/csr/csr_msgconv.h
new file mode 100644
index 0000000..2875c8c
--- /dev/null
+++ b/drivers/staging/csr/csr_msgconv.h
@@ -0,0 +1,145 @@
+#ifndef CSR_MSGCONV_H__
+#define CSR_MSGCONV_H__
+
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+#include "csr_prim_defs.h"
+#include "csr_sched.h"
+#include "csr_unicode.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef CsrSize (CsrMsgSizeofFunc)(void *msg);
+typedef CsrUint8 *(CsrMsgSerializeFunc)(CsrUint8 *buffer, CsrSize *length, void *msg);
+typedef void (CsrMsgFreeFunc)(void *msg);
+typedef void *(CsrMsgDeserializeFunc)(CsrUint8 *buffer, CsrSize length);
+
+/* Converter entry for one message type */
+typedef struct CsrMsgConvMsgEntry
+{
+    CsrUint16              msgType;
+    CsrMsgSizeofFunc      *sizeofFunc;
+    CsrMsgSerializeFunc   *serFunc;
+    CsrMsgDeserializeFunc *deserFunc;
+    CsrMsgFreeFunc        *freeFunc;
+} CsrMsgConvMsgEntry;
+
+/* Optional lookup function */
+typedef CsrMsgConvMsgEntry *(CsrMsgCustomLookupFunc)(CsrMsgConvMsgEntry *ce, CsrUint16 msgType);
+
+/* All converter entries for one specific primitive */
+typedef struct CsrMsgConvPrimEntry
+{
+    CsrUint16                   primType;
+    const CsrMsgConvMsgEntry   *conv;
+    CsrMsgCustomLookupFunc     *lookupFunc;
+    struct CsrMsgConvPrimEntry *next;
+} CsrMsgConvPrimEntry;
+
+typedef struct
+{
+    CsrMsgConvPrimEntry *profile_converters;
+    void *(*deserialize_data)(CsrUint16 primType, CsrSize length, CsrUint8 * data);
+    CsrBool (*free_message)(CsrUint16 primType, CsrUint8 *data);
+    CsrSize (*sizeof_message)(CsrUint16 primType, void *msg);
+    CsrUint8 *(*serialize_message)(CsrUint16 primType, void *msg,
+                                   CsrSize * length,
+                                   CsrUint8 * buffer);
+} CsrMsgConvEntry;
+
+CsrSize CsrMsgConvSizeof(CsrUint16 primType, void *msg);
+CsrUint8 *CsrMsgConvSerialize(CsrUint8 *buffer, CsrSize maxBufferOffset, CsrSize *offset, CsrUint16 primType, void *msg);
+void CsrMsgConvCustomLookupRegister(CsrUint16 primType, CsrMsgCustomLookupFunc *lookupFunc);
+void CsrMsgConvInsert(CsrUint16 primType, const CsrMsgConvMsgEntry *ce);
+CsrMsgConvPrimEntry *CsrMsgConvFind(CsrUint16 primType);
+CsrMsgConvMsgEntry *CsrMsgConvFindEntry(CsrUint16 primType, CsrUint16 msgType);
+CsrMsgConvMsgEntry *CsrMsgConvFindEntryByMsg(CsrUint16 primType, const void *msg);
+CsrMsgConvEntry *CsrMsgConvGet(void);
+CsrMsgConvEntry *CsrMsgConvInit(void);
+#ifdef ENABLE_SHUTDOWN
+void CsrMsgConvDeinit(void);
+#endif /* ENABLE_SHUTDOWN */
+
+/* SHOULD BE INTERNAL TO FRAMEWORK AKA DEPRECATED */
+
+CsrUint32 CsrCharStringSerLen(const CsrCharString *str);
+CsrUint32 CsrUtf8StringSerLen(const CsrUtf8String *str);
+CsrUint32 CsrUtf16StringSerLen(const CsrUtf16String *str);
+
+/* Prototypes for primitive type serializers */
+void CsrUint8Ser(CsrUint8 *buffer, CsrSize *offset, CsrUint8 value);
+void CsrUint16Ser(CsrUint8 *buffer, CsrSize *offset, CsrUint16 value);
+void CsrUint32Ser(CsrUint8 *buffer, CsrSize *offset, CsrUint32 value);
+void CsrMemCpySer(CsrUint8 *buffer, CsrSize *offset, const void *value, CsrSize length);
+void CsrCharStringSer(CsrUint8 *buffer, CsrSize *offset, const CsrCharString *value);
+void CsrUtf8StringSer(CsrUint8 *buffer, CsrSize *offset, const CsrUtf8String *value);
+void CsrUtf16StringSer(CsrUint8 *buffer, CsrSize *offset, const CsrUtf16String *value);
+void CsrVoidPtrSer(CsrUint8 *buffer, CsrSize *offset, void *ptr);
+void CsrSizeSer(CsrUint8 *buffer, CsrSize *offset, CsrSize value);
+
+void CsrUint8Des(CsrUint8 *value, CsrUint8 *buffer, CsrSize *offset);
+void CsrUint16Des(CsrUint16 *value, CsrUint8 *buffer, CsrSize *offset);
+void CsrUint32Des(CsrUint32 *value, CsrUint8 *buffer, CsrSize *offset);
+void CsrMemCpyDes(void *value, CsrUint8 *buffer, CsrSize *offset, CsrSize length);
+void CsrCharStringDes(CsrCharString **value, CsrUint8 *buffer, CsrSize *offset);
+void CsrUtf8StringDes(CsrUtf8String **value, CsrUint8 *buffer, CsrSize *offset);
+void CsrUtf16StringDes(CsrUtf16String **value, CsrUint8 *buffer, CsrSize *offset);
+void CsrVoidPtrDes(void **value, CsrUint8 *buffer, CsrSize *offset);
+void CsrSizeDes(CsrSize *value, CsrUint8 *buffer, CsrSize *offset);
+
+CsrSize CsrEventSizeof(void *msg);
+CsrUint8 *CsrEventSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+void *CsrEventDes(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrEventCsrUint8Sizeof(void *msg);
+CsrUint8 *CsrEventCsrUint8Ser(CsrUint8 *ptr, CsrSize *len, void *msg);
+void *CsrEventCsrUint8Des(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrEventCsrUint16Sizeof(void *msg);
+CsrUint8 *CsrEventCsrUint16Ser(CsrUint8 *ptr, CsrSize *len, void *msg);
+void *CsrEventCsrUint16Des(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrEventCsrUint32Sizeof(void *msg);
+CsrUint8 *CsrEventCsrUint32Ser(CsrUint8 *ptr, CsrSize *len, void *msg);
+void *CsrEventCsrUint32Des(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrEventCsrUint16CsrUint8Sizeof(void *msg);
+CsrUint8 *CsrEventCsrUint16CsrUint8Ser(CsrUint8 *ptr, CsrSize *len, void *msg);
+void *CsrEventCsrUint16CsrUint8Des(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrEventCsrUint16CsrUint16Sizeof(void *msg);
+CsrUint8 *CsrEventCsrUint16CsrUint16Ser(CsrUint8 *ptr, CsrSize *len, void *msg);
+void *CsrEventCsrUint16CsrUint16Des(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrEventCsrUint16CsrUint32Sizeof(void *msg);
+CsrUint8 *CsrEventCsrUint16CsrUint32Ser(CsrUint8 *ptr, CsrSize *len, void *msg);
+void *CsrEventCsrUint16CsrUint32Des(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrEventCsrUint16CsrCharStringSizeof(void *msg);
+CsrUint8 *CsrEventCsrUint16CsrCharStringSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+void *CsrEventCsrUint16CsrCharStringDes(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrEventCsrUint32CsrUint16Sizeof(void *msg);
+CsrUint8 *CsrEventCsrUint32CsrUint16Ser(CsrUint8 *ptr, CsrSize *len, void *msg);
+void *CsrEventCsrUint32CsrUint16Des(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrEventCsrUint32CsrCharStringSizeof(void *msg);
+CsrUint8 *CsrEventCsrUint32CsrCharStringSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+void *CsrEventCsrUint32CsrCharStringDes(CsrUint8 *buffer, CsrSize length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_panic.c b/drivers/staging/csr/csr_panic.c
new file mode 100644
index 0000000..2564e80
--- /dev/null
+++ b/drivers/staging/csr/csr_panic.c
@@ -0,0 +1,22 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include "csr_types.h"
+#include "csr_panic.h"
+
+void CsrPanic(CsrUint8 tech, CsrUint16 reason, const char *p)
+{
+    BUG_ON(1);
+}
+EXPORT_SYMBOL_GPL(CsrPanic);
diff --git a/drivers/staging/csr/csr_panic.h b/drivers/staging/csr/csr_panic.h
new file mode 100644
index 0000000..6e33f93
--- /dev/null
+++ b/drivers/staging/csr/csr_panic.h
@@ -0,0 +1,55 @@
+#ifndef CSR_PANIC_H__
+#define CSR_PANIC_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+#include "csr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Synergy techonology ID definitions */
+#define CSR_TECH_FW     0
+#define CSR_TECH_BT     1
+#define CSR_TECH_WIFI   2
+#define CSR_TECH_GPS    3
+#define CSR_TECH_NFC    4
+
+/* Panic type ID definitions for technology type CSR_TECH_FW */
+#define CSR_PANIC_FW_UNEXPECTED_VALUE        0
+#define CSR_PANIC_FW_HEAP_EXHAUSTION         1
+#define CSR_PANIC_FW_INVALID_PFREE_POINTER   2
+#define CSR_PANIC_FW_EXCEPTION               3
+#define CSR_PANIC_FW_ASSERTION_FAIL          4
+#define CSR_PANIC_FW_NULL_TASK_HANDLER       5
+#define CSR_PANIC_FW_UNKNOWN_TASK            6
+#define CSR_PANIC_FW_QUEUE_ACCESS_VIOLATION  7
+#define CSR_PANIC_FW_TOO_MANY_MESSAGES       8
+#define CSR_PANIC_FW_TOO_MANY_TIMED_EVENTS   9
+#define CSR_PANIC_FW_ABCSP_SYNC_LOST        10
+#define CSR_PANIC_FW_OVERSIZE_ABCSP_PRIM    11
+#define CSR_PANIC_FW_H4_CORRUPTION          12
+#define CSR_PANIC_FW_H4_SYNC_LOST           13
+#define CSR_PANIC_FW_H4_RX_OVERRUN          14
+#define CSR_PANIC_FW_H4_TX_OVERRUN          15
+#define CSR_PANIC_FW_TM_BC_RESTART_FAIL     16
+#define CSR_PANIC_FW_TM_BC_START_FAIL       17
+#define CSR_PANIC_FW_TM_BC_BAD_STATE        18
+#define CSR_PANIC_FW_TM_BC_TRANSPORT_LOST   19
+
+/* Panic interface used by technologies */
+/* DEPRECATED - replaced by csr_log_text.h */
+void CsrPanic(CsrUint8 tech, CsrUint16 reason, const char *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_PANIC_H__ */
diff --git a/drivers/staging/csr/csr_pmem.c b/drivers/staging/csr/csr_pmem.c
new file mode 100644
index 0000000..a07c449
--- /dev/null
+++ b/drivers/staging/csr/csr_pmem.c
@@ -0,0 +1,51 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
+#include <linux/autoconf.h>
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
+#include <linux/config.h>
+#endif
+
+#include <linux/slab.h>
+
+#include "csr_panic.h"
+#include "csr_pmem.h"
+
+void *CsrPmemAlloc(CsrSize size)
+{
+    void *ret;
+
+    ret = kmalloc(size, GFP_KERNEL);
+    if (!ret)
+    {
+        CsrPanic(CSR_TECH_FW, CSR_PANIC_FW_HEAP_EXHAUSTION,
+            "out of memory");
+    }
+
+    return ret;
+}
+EXPORT_SYMBOL_GPL(CsrPmemAlloc);
+
+void CsrPmemFree(void *ptr)
+{
+    if (ptr == NULL)
+    {
+        return;
+    }
+
+    kfree(ptr);
+}
+EXPORT_SYMBOL_GPL(CsrPmemFree);
diff --git a/drivers/staging/csr/csr_pmem.h b/drivers/staging/csr/csr_pmem.h
new file mode 100644
index 0000000..f1e59ef
--- /dev/null
+++ b/drivers/staging/csr/csr_pmem.h
@@ -0,0 +1,143 @@
+#ifndef CSR_PMEM_H__
+#define CSR_PMEM_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+#include "csr_util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_PMEM_DEBUG_ENABLE
+/*****************************************************************************
+
+    NAME
+        CsrPmemAlloc
+
+    DESCRIPTION
+        This function will allocate a contiguous block of memory of at least
+        the specified size in bytes and return a pointer to the allocated
+        memory. This function is not allowed to return NULL. A size of 0 is a
+        valid request, and a unique and valid (not NULL) pointer must be
+        returned in this case.
+
+    PARAMETERS
+        size - Size of memory requested. Note that a size of 0 is valid.
+
+    RETURNS
+        Pointer to allocated memory.
+
+*****************************************************************************/
+#ifdef CSR_PMEM_DEBUG
+void *CsrPmemAllocDebug(CsrSize size,
+    const CsrCharString *file, CsrUint32 line);
+#define CsrPmemAlloc(sz) CsrPmemAllocDebug((sz), __FILE__, __LINE__)
+#else
+void *CsrPmemAlloc(CsrSize size);
+#endif
+
+
+/*****************************************************************************
+
+    NAME
+        CsrPmemFree
+
+    DESCRIPTION
+        This function will deallocate a previously allocated block of memory.
+
+    PARAMETERS
+        ptr - Pointer to allocated memory.
+
+*****************************************************************************/
+void CsrPmemFree(void *ptr);
+#endif
+
+/*****************************************************************************
+
+    NAME
+        CsrPmemZalloc
+
+    DESCRIPTION
+        This function is equivalent to CsrPmemAlloc, but the allocated memory
+        is initialised to zero.
+
+    PARAMETERS
+        size - Size of memory requested. Note that a size of 0 is valid.
+
+    RETURNS
+        Pointer to allocated memory.
+
+*****************************************************************************/
+#define CsrPmemZalloc(s) (CsrMemSet(CsrPmemAlloc(s), 0x00, (s)))
+
+
+/*****************************************************************************
+
+    NAME
+        pnew and zpnew
+
+    DESCRIPTIOM
+        Type-safe wrappers for CsrPmemAlloc and CsrPmemZalloc, for allocating
+        single instances of a specified and named type.
+
+    PARAMETERS
+        t - type to allocate.
+
+*****************************************************************************/
+#define pnew(t) ((t *) (CsrPmemAlloc(sizeof(t))))
+#define zpnew(t) ((t *) (CsrPmemZalloc(sizeof(t))))
+
+
+/*----------------------------------------------------------------------------*
+ * Csr Pmem Debug code. Allows custom callbacks on CsrPmemAlloc and CsrPmemFree
+ *----------------------------------------------------------------------------*/
+#ifdef CSR_PMEM_DEBUG_ENABLE
+
+typedef CsrUint8 CsrPmemDebugAllocType;
+#define CSR_PMEM_DEBUG_TYPE_PMEM_ALLOC    1
+#define CSR_PMEM_DEBUG_TYPE_MEM_ALLOC     2
+#define CSR_PMEM_DEBUG_TYPE_MEM_CALLOC    3
+#define CSR_PMEM_DEBUG_TYPE_MEM_ALLOC_DMA 4
+
+typedef void (CsrPmemDebugOnAlloc)(void *ptr, void *userptr, CsrSize size, CsrPmemDebugAllocType type, const CsrCharString* file, CsrUint32 line);
+typedef void (CsrPmemDebugOnFree)(void *ptr, void *userptr, CsrPmemDebugAllocType type, const CsrCharString* file, CsrUint32 line);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrPmemInstallHooks
+ *
+ *  DESCRIPTION
+ *      Install debug hooks for memory allocation
+ *      Use NULL values to uninstall the hooks
+ *      headSize = The number of extra bytes to allocate in the head of the Allocated buffer
+ *      footSize = The number of extra bytes to allocate in the end of the Allocated buffer
+ *
+ *  RETURNS
+ *      void
+ *
+ *----------------------------------------------------------------------------*/
+void CsrPmemDebugInstallHooks(CsrUint8 headSize, CsrUint8 endSize, CsrPmemDebugOnAlloc *onAllocCallback, CsrPmemDebugOnFree *onFreeCallback);
+
+void *CsrPmemDebugAlloc(CsrSize size, CsrPmemDebugAllocType type, const CsrCharString* file, CsrUint32 line);
+#define CsrPmemAlloc(size) CsrPmemDebugAlloc(size, CSR_PMEM_DEBUG_TYPE_PMEM_ALLOC, __FILE__, __LINE__)
+
+void CsrPmemDebugFree(void *ptr, CsrPmemDebugAllocType type, const CsrCharString* file, CsrUint32 line);
+#define CsrPmemFree(ptr) CsrPmemDebugFree(ptr, CSR_PMEM_DEBUG_TYPE_PMEM_ALLOC, __FILE__, __LINE__)
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_prim_defs.h b/drivers/staging/csr/csr_prim_defs.h
new file mode 100644
index 0000000..02ab913
--- /dev/null
+++ b/drivers/staging/csr/csr_prim_defs.h
@@ -0,0 +1,64 @@
+#ifndef CSR_PRIM_DEFS_H__
+#define CSR_PRIM_DEFS_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+#include "csr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/************************************************************************************
+ * Segmentation of primitives in upstream and downstream segment
+ ************************************************************************************/
+typedef CsrUint16 CsrPrim;
+#define CSR_PRIM_UPSTREAM                   ((CsrPrim) (0x8000))
+
+/************************************************************************************
+ * Primitive definitions for Synergy framework
+ ************************************************************************************/
+#define CSR_SYNERGY_EVENT_CLASS_BASE        ((CsrUint16) (0x0600))
+
+#define CSR_HCI_PRIM                        ((CsrUint16) (0x0000 | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_BCCMD_PRIM                      ((CsrUint16) (0x0001 | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_HQ_PRIM                         ((CsrUint16) (0x0002 | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_VM_PRIM                         ((CsrUint16) (0x0003 | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_TM_BLUECORE_PRIM                ((CsrUint16) (0x0004 | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_FP_PRIM                         ((CsrUint16) (0x0005 | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_IP_SOCKET_PRIM                  ((CsrUint16) (0x0006 | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_IP_ETHER_PRIM                   ((CsrUint16) (0x0007 | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_IP_IFCONFIG_PRIM                ((CsrUint16) (0x0008 | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_IP_INTERNAL_PRIM                ((CsrUint16) (0x0009 | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_FSAL_PRIM                       ((CsrUint16) (0x000A | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_DATA_STORE_PRIM                 ((CsrUint16) (0x000B | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_AM_PRIM                         ((CsrUint16) (0x000C | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_TLS_PRIM                        ((CsrUint16) (0x000D | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_DHCP_SERVER_PRIM                ((CsrUint16) (0x000E | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_TFTP_PRIM                       ((CsrUint16) (0x000F | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_DSPM_PRIM                       ((CsrUint16) (0x0010 | CSR_SYNERGY_EVENT_CLASS_BASE))
+#define CSR_TLS_INTERNAL_PRIM               ((CsrUint16) (0x0011 | CSR_SYNERGY_EVENT_CLASS_BASE))
+
+#define NUMBER_OF_CSR_FW_EVENTS             (CSR_DSPM_PRIM - CSR_SYNERGY_EVENT_CLASS_BASE + 1)
+
+#define CSR_SYNERGY_EVENT_CLASS_MISC_BASE   ((CsrUint16) (0x06A0))
+
+#define CSR_UI_PRIM                         ((CsrUint16) (0x0000 | CSR_SYNERGY_EVENT_CLASS_MISC_BASE))
+#define CSR_APP_PRIM                        ((CsrUint16) (0x0001 | CSR_SYNERGY_EVENT_CLASS_MISC_BASE))
+#define CSR_SDIO_PROBE_PRIM                 ((CsrUint16) (0x0002 | CSR_SYNERGY_EVENT_CLASS_MISC_BASE))
+
+#define NUMBER_OF_CSR_FW_MISC_EVENTS        (CSR_SDIO_PROBE_PRIM - CSR_SYNERGY_EVENT_CLASS_MISC_BASE + 1)
+
+#define CSR_ENV_PRIM                        ((CsrUint16) (0x00FF | CSR_SYNERGY_EVENT_CLASS_MISC_BASE))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_PRIM_DEFS_H__ */
diff --git a/drivers/staging/csr/csr_result.h b/drivers/staging/csr/csr_result.h
new file mode 100644
index 0000000..249b499
--- /dev/null
+++ b/drivers/staging/csr/csr_result.h
@@ -0,0 +1,27 @@
+#ifndef CSR_RESULT_H__
+#define CSR_RESULT_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef CsrUint16 CsrResult;
+#define CSR_RESULT_SUCCESS  ((CsrResult) 0x0000)
+#define CSR_RESULT_FAILURE  ((CsrResult) 0xFFFF)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_sched.h b/drivers/staging/csr/csr_sched.h
new file mode 100644
index 0000000..2f982bb
--- /dev/null
+++ b/drivers/staging/csr/csr_sched.h
@@ -0,0 +1,292 @@
+#ifndef CSR_SCHED_H__
+#define CSR_SCHED_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+#include "csr_types.h"
+#include "csr_time.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* An identifier issued by the scheduler. */
+typedef CsrUint32 CsrSchedIdentifier;
+
+/* A task identifier */
+typedef CsrUint16 CsrSchedTaskId;
+
+/* A queue identifier */
+typedef CsrUint16 CsrSchedQid;
+#define CSR_SCHED_QID_INVALID     ((CsrSchedQid) 0xFFFF)
+
+/* A message identifier */
+typedef CsrSchedIdentifier CsrSchedMsgId;
+
+/* A timer event identifier */
+typedef CsrSchedIdentifier CsrSchedTid;
+#define CSR_SCHED_TID_INVALID     ((CsrSchedTid) 0)
+
+/* Scheduler entry functions share this structure */
+typedef void (*schedEntryFunction_t)(void **inst);
+
+/* Time constants. */
+#define CSR_SCHED_TIME_MAX                ((CsrTime) 0xFFFFFFFF)
+#define CSR_SCHED_MILLISECOND             ((CsrTime) (1000))
+#define CSR_SCHED_SECOND                  ((CsrTime) (1000 * CSR_SCHED_MILLISECOND))
+#define CSR_SCHED_MINUTE                  ((CsrTime) (60 * CSR_SCHED_SECOND))
+
+/* Queue and primitive that identifies the environment */
+#define CSR_SCHED_TASK_ID        0xFFFF
+#define CSR_SCHED_PRIM                   (CSR_SCHED_TASK_ID)
+#define CSR_SCHED_EXCLUDED_MODULE_QUEUE      0xFFFF
+
+/*
+ * Background interrupt definitions
+ */
+typedef CsrUint16 CsrSchedBgint;
+#define CSR_SCHED_BGINT_INVALID ((CsrSchedBgint) 0xFFFF)
+
+typedef void (*CsrSchedBgintHandler)(void *);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSchedBgintReg
+ *
+ *  DESCRIPTION
+ *      Register a background interrupt handler function with the scheduler.
+ *        When CsrSchedBgint() is called from the foreground (e.g. an interrupt
+ *        routine) the registered function is called.
+ *
+ *        If "cb" is null then the interrupt is effectively disabled. If a
+ *        no bgints are available, CSR_SCHED_BGINT_INVALID is returned, otherwise
+ *        a CsrSchedBgint value is returned to be used in subsequent calls to
+ *        CsrSchedBgint().  id is a possibly NULL identifier used for logging
+ *        purposes only.
+ *
+ *  RETURNS
+ *      CsrSchedBgint -- CSR_SCHED_BGINT_INVALID denotes failure to obtain a CsrSchedBgintSet.
+ *
+ *----------------------------------------------------------------------------*/
+CsrSchedBgint CsrSchedBgintReg(CsrSchedBgintHandler cb,
+    void *context,
+    const CsrCharString *id);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSchedBgintUnreg
+ *
+ *  DESCRIPTION
+ *      Unregister a background interrupt handler function.
+ *
+ *      ``irq'' is a background interrupt handle previously obtained
+ *      from a call to CsrSchedBgintReg().
+ *
+ *  RETURNS
+ *      void.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSchedBgintUnreg(CsrSchedBgint bgint);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSchedBgintSet
+ *
+ *  DESCRIPTION
+ *      Set background interrupt.
+ *
+ *  RETURNS
+ *      void.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSchedBgintSet(CsrSchedBgint bgint);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSchedMessagePut
+ *
+ *  DESCRIPTION
+ *      Sends a message consisting of the integer "mi" and the void * pointer
+ *      "mv" to the message queue "q".
+ *
+ *      "mi" and "mv" are neither inspected nor changed by the scheduler - the
+ *      task that owns "q" is expected to make sense of the values. "mv" may
+ *      be null.
+ *
+ *  NOTE
+ *      If "mv" is not null then it will typically be a chunk of CsrPmemAlloc()ed
+ *      memory, though there is no need for it to be so. Tasks should normally
+ *      obey the convention that when a message built with CsrPmemAlloc()ed memory
+ *      is given to CsrSchedMessagePut() then ownership of the memory is ceded to the
+ *      scheduler - and eventually to the recipient task. I.e., the receiver of
+ *      the message will be expected to CsrPmemFree() the message storage.
+ *
+ *  RETURNS
+ *      void.
+ *
+ *----------------------------------------------------------------------------*/
+#if defined(CSR_LOG_ENABLE) && defined(CSR_LOG_INCLUDE_FILE_NAME_AND_LINE_NUMBER)
+void CsrSchedMessagePutStringLog(CsrSchedQid q,
+    CsrUint16 mi,
+    void *mv,
+    CsrUint32 line,
+    const CsrCharString *file);
+#define CsrSchedMessagePut(q, mi, mv) CsrSchedMessagePutStringLog((q), (mi), (mv), __LINE__, __FILE__)
+#else
+void CsrSchedMessagePut(CsrSchedQid q,
+    CsrUint16 mi,
+    void *mv);
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSchedMessageBroadcast
+ *
+ *  DESCRIPTION
+ *      Sends a message to all tasks.
+ *
+ *      The user must supply a "factory function" that is called once
+ *      for every task that exists. The "factory function", msg_build_func,
+ *      must allocate and initialise the message and set the msg_build_ptr
+ *      to point to the message when done.
+ *
+ *  NOTE
+ *      N/A
+ *
+ *  RETURNS
+ *      void
+ *
+ *----------------------------------------------------------------------------*/
+#if defined(CSR_LOG_ENABLE) && defined(CSR_LOG_INCLUDE_FILE_NAME_AND_LINE_NUMBER)
+void CsrSchedMessageBroadcastStringLog(CsrUint16 mi,
+    void *(*msg_build_func)(void *),
+    void *msg_build_ptr,
+    CsrUint32 line,
+    const CsrCharString *file);
+#define CsrSchedMessageBroadcast(mi, fn, ptr) CsrSchedMessageBroadcastStringLog((mi), (fn), (ptr), __LINE__, __FILE__)
+#else
+void CsrSchedMessageBroadcast(CsrUint16 mi,
+    void *(*msg_build_func)(void *),
+    void *msg_build_ptr);
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSchedMessageGet
+ *
+ *  DESCRIPTION
+ *      Obtains a message from the message queue belonging to the calling task.
+ *      The message consists of one or both of a CsrUint16 and a void *.
+ *
+ *  RETURNS
+ *      CsrBool - TRUE if a message has been obtained from the queue, else FALSE.
+ *      If a message is taken from the queue, then "*pmi" and "*pmv" are set to
+ *      the "mi" and "mv" passed to CsrSchedMessagePut() respectively.
+ *
+ *      "pmi" and "pmv" can be null, in which case the corresponding value from
+ *      them message is discarded.
+ *
+ *----------------------------------------------------------------------------*/
+CsrBool CsrSchedMessageGet(CsrUint16 *pmi, void **pmv);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSchedTimerSet
+ *
+ *  DESCRIPTION
+ *      Causes the void function "fn" to be called with the arguments
+ *      "fniarg" and "fnvarg" after "delay" has elapsed.
+ *
+ *      "delay" must be less than half the range of a CsrTime.
+ *
+ *      CsrSchedTimerSet() does nothing with "fniarg" and "fnvarg" except
+ *      deliver them via a call to "fn()".   (Unless CsrSchedTimerCancel()
+ *      is used to prevent delivery.)
+ *
+ *  NOTE
+ *      The function will be called at or after "delay"; the actual delay will
+ *      depend on the timing behaviour of the scheduler's tasks.
+ *
+ *  RETURNS
+ *      CsrSchedTid - A timed event identifier, can be used in CsrSchedTimerCancel().
+ *
+ *----------------------------------------------------------------------------*/
+#if defined(CSR_LOG_ENABLE) && defined(CSR_LOG_INCLUDE_FILE_NAME_AND_LINE_NUMBER)
+CsrSchedTid CsrSchedTimerSetStringLog(CsrTime delay,
+    void (*fn)(CsrUint16 mi, void *mv),
+    CsrUint16 fniarg,
+    void *fnvarg,
+    CsrUint32 line,
+    const CsrCharString *file);
+#define CsrSchedTimerSet(d, fn, fni, fnv) CsrSchedTimerSetStringLog((d), (fn), (fni), (fnv), __LINE__, __FILE__)
+#else
+CsrSchedTid CsrSchedTimerSet(CsrTime delay,
+    void (*fn)(CsrUint16 mi, void *mv),
+    CsrUint16 fniarg,
+    void *fnvarg);
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSchedTimerCancel
+ *
+ *  DESCRIPTION
+ *      Attempts to prevent the timed event with identifier "eventid" from
+ *      occurring.
+ *
+ *  RETURNS
+ *      CsrBool - TRUE if cancelled, FALSE if the event has already occurred.
+ *
+ *----------------------------------------------------------------------------*/
+#if defined(CSR_LOG_ENABLE) && defined(CSR_LOG_INCLUDE_FILE_NAME_AND_LINE_NUMBER)
+CsrBool CsrSchedTimerCancelStringLog(CsrSchedTid eventid,
+    CsrUint16 *pmi,
+    void **pmv,
+    CsrUint32 line,
+    const CsrCharString *file);
+#define CsrSchedTimerCancel(e, pmi, pmv) CsrSchedTimerCancelStringLog((e), (pmi), (pmv), __LINE__, __FILE__)
+#else
+CsrBool CsrSchedTimerCancel(CsrSchedTid eventid,
+    CsrUint16 *pmi,
+    void **pmv);
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSchedTaskQueueGet
+ *
+ *  DESCRIPTION
+ *      Return the queue identifier for the currently running queue
+ *
+ *  RETURNS
+ *      CsrSchedQid - The current task queue identifier, or 0xFFFF if not available.
+ *
+ *----------------------------------------------------------------------------*/
+CsrSchedQid CsrSchedTaskQueueGet(void);
+
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSchedTaskQueueGet
+ *
+ *  DESCRIPTION
+ *      Return the queue identifier for the currently running queue
+ *
+ *  RETURNS
+ *      CsrCharString - The current task queue identifier, or 0xFFFF if not available.
+ *
+ *----------------------------------------------------------------------------*/
+CsrCharString* CsrSchedTaskNameGet(CsrSchedQid );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_sdio.h b/drivers/staging/csr/csr_sdio.h
new file mode 100644
index 0000000..d60ef45
--- /dev/null
+++ b/drivers/staging/csr/csr_sdio.h
@@ -0,0 +1,732 @@
+#ifndef CSR_SDIO_H__
+#define CSR_SDIO_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+#include "csr_result.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Result Codes */
+#define CSR_SDIO_RESULT_INVALID_VALUE   ((CsrResult) 1) /* Invalid argument value */
+#define CSR_SDIO_RESULT_NO_DEVICE       ((CsrResult) 2) /* The specified device is no longer present */
+#define CSR_SDIO_RESULT_CRC_ERROR       ((CsrResult) 3) /* The transmitted/received data or command response contained a CRC error */
+#define CSR_SDIO_RESULT_TIMEOUT         ((CsrResult) 4) /* No command response or data received from device, or function enable/disable did not succeed within timeout period */
+#define CSR_SDIO_RESULT_NOT_RESET       ((CsrResult) 5) /* The device was not reset */
+
+/* Features (for use in features member of CsrSdioFunction) */
+#define CSR_SDIO_FEATURE_BYTE_MODE                   0x00000001 /* Transfer sizes do not have to be a multiple of block size */
+#define CSR_SDIO_FEATURE_DMA_CAPABLE_MEM_REQUIRED    0x00000002 /* Bulk operations require DMA friendly memory */
+
+/* CsrSdioFunctionId wildcards (for use in CsrSdioFunctionId members) */
+#define CSR_SDIO_ANY_MANF_ID        0xFFFF
+#define CSR_SDIO_ANY_CARD_ID        0xFFFF
+#define CSR_SDIO_ANY_SDIO_FUNCTION  0xFF
+#define CSR_SDIO_ANY_SDIO_INTERFACE 0xFF
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunctionId
+ *
+ *  DESCRIPTION
+ *      This structure describes one or more functions of a device, based on
+ *      four qualitative measures. The CsrSdioFunctionId wildcard defines can be
+ *      used for making the CsrSdioFunctionId match more than one function.
+ *
+ *  MEMBERS
+ *      manfId - Vendor ID (or CSR_SDIO_ANY_MANF_ID).
+ *      cardId - Device ID (or CSR_SDIO_ANY_CARD_ID).
+ *      sdioFunction - SDIO Function number (or CSR_SDIO_ANY_SDIO_FUNCTION).
+ *      sdioInterface - SDIO Standard Interface Code (or CSR_SDIO_ANY_SDIO_INTERFACE)
+ *
+ *----------------------------------------------------------------------------*/
+typedef struct
+{
+    CsrUint16 manfId;       /* Vendor ID to match or CSR_SDIO_ANY_MANF_ID */
+    CsrUint16 cardId;       /* Device ID to match or CSR_SDIO_ANY_CARD_ID */
+    CsrUint8  sdioFunction; /* SDIO Function number to match or CSR_SDIO_ANY_SDIO_FUNCTION */
+    CsrUint8  sdioInterface; /* SDIO Standard Interface Code to match or CSR_SDIO_ANY_SDIO_INTERFACE */
+} CsrSdioFunctionId;
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunction
+ *
+ *  DESCRIPTION
+ *      This structure represents a single function on a device.
+ *
+ *  MEMBERS
+ *      sdioId - A CsrSdioFunctionId describing this particular function. The
+ *               subfield shall not contain any CsrSdioFunctionId wildcards. The
+ *               subfields shall describe the specific single function
+ *               represented by this structure.
+ *      blockSize - Actual configured block size, or 0 if unconfigured.
+ *      features - Bit mask with any of CSR_SDIO_FEATURE_* set.
+ *      device - Handle of device containing the function. If two functions have
+ *               the same device handle, they reside on the same device.
+ *      driverData - For use by the Function Driver. The SDIO Driver shall not
+ *                   attempt to dereference the pointer.
+ *      priv - For use by the SDIO Driver. The Function Driver shall not attempt
+ *             to dereference the pointer.
+ *
+ *
+ *----------------------------------------------------------------------------*/
+typedef struct
+{
+    CsrSdioFunctionId sdioId;
+    CsrUint16         blockSize; /* Actual configured block size, or 0 if unconfigured */
+    CsrUint32         features; /* Bit mask with any of CSR_SDIO_FEATURE_* set */
+    void             *device; /* Handle of device containing the function */
+    void             *driverData; /* For use by the Function Driver */
+    void             *priv; /* For use by the SDIO Driver */
+} CsrSdioFunction;
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioInsertedCallback, CsrSdioRemovedCallback
+ *
+ *  DESCRIPTION
+ *      CsrSdioInsertedCallback is called when a function becomes available to
+ *      a registered Function Driver that supports the function.
+ *      CsrSdioRemovedCallback is called when a function is no longer available
+ *      to a Function Driver, either because the device has been removed, or the
+ *      Function Driver has been unregistered.
+ *
+ *      NOTE: These functions are implemented by the Function Driver, and are
+ *            passed as function pointers in the CsrSdioFunctionDriver struct.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *----------------------------------------------------------------------------*/
+typedef void (*CsrSdioInsertedCallback)(CsrSdioFunction *function);
+typedef void (*CsrSdioRemovedCallback)(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioInterruptDsrCallback, CsrSdioInterruptCallback
+ *
+ *  DESCRIPTION
+ *      CsrSdioInterruptCallback is called when an interrupt occurs on the
+ *      the device associated with the specified function.
+ *
+ *      NOTE: These functions are implemented by the Function Driver, and are
+ *            passed as function pointers in the CsrSdioFunctionDriver struct.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *  RETURNS (only CsrSdioInterruptCallback)
+ *      A pointer to a CsrSdioInterruptDsrCallback function.
+ *
+ *----------------------------------------------------------------------------*/
+typedef void (*CsrSdioInterruptDsrCallback)(CsrSdioFunction *function);
+typedef CsrSdioInterruptDsrCallback (*CsrSdioInterruptCallback)(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioSuspendCallback, CsrSdioResumeCallback
+ *
+ *  DESCRIPTION
+ *      CsrSdioSuspendCallback is called when the system is preparing to go
+ *      into a suspended state. CsrSdioResumeCallback is called when the system
+ *      has entered an active state again.
+ *
+ *      NOTE: These functions are implemented by the Function Driver, and are
+ *            passed as function pointers in the CsrSdioFunctionDriver struct.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *----------------------------------------------------------------------------*/
+typedef void (*CsrSdioSuspendCallback)(CsrSdioFunction *function);
+typedef void (*CsrSdioResumeCallback)(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioAsyncCallback, CsrSdioAsyncDsrCallback
+ *
+ *  DESCRIPTION
+ *      CsrSdioAsyncCallback is called when an asynchronous operation completes.
+ *
+ *      NOTE: These functions are implemented by the Function Driver, and are
+ *            passed as function pointers in the function calls that initiate
+ *            the operation.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      result - The result of the operation that completed. See the description
+ *               of the initiating function for possible result values.
+ *
+ *  RETURNS (only CsrSdioAsyncCallback)
+ *      A pointer to a CsrSdioAsyncDsrCallback function.
+ *
+ *----------------------------------------------------------------------------*/
+typedef void (*CsrSdioAsyncDsrCallback)(CsrSdioFunction *function, CsrResult result);
+typedef CsrSdioAsyncDsrCallback (*CsrSdioAsyncCallback)(CsrSdioFunction *function, CsrResult result);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunctionDriver
+ *
+ *  DESCRIPTION
+ *      Structure representing a Function Driver.
+ *
+ *  MEMBERS
+ *      inserted - Callback, see description of CsrSdioInsertedCallback.
+ *      removed - Callback, see description of CsrSdioRemovedCallback.
+ *      intr - Callback, see description of CsrSdioInterruptCallback.
+ *      suspend - Callback, see description of CsrSdioSuspendCallback.
+ *      resume - Callback, see description of CsrSdioResumeCallback.
+ *      ids - Array of CsrSdioFunctionId describing one or more functions that
+ *            are supported by the Function Driver.
+ *      idsCount - Length of the ids array.
+ *      priv - For use by the SDIO Driver. The Function Driver may initialise
+ *             it to NULL, but shall otherwise not access the pointer or attempt
+ *             to dereference it.
+ *
+ *----------------------------------------------------------------------------*/
+typedef struct
+{
+    CsrSdioInsertedCallback  inserted;
+    CsrSdioRemovedCallback   removed;
+    CsrSdioInterruptCallback intr;
+    CsrSdioSuspendCallback   suspend;
+    CsrSdioResumeCallback    resume;
+    CsrSdioFunctionId       *ids;
+    CsrUint8                 idsCount;
+    void                    *priv;          /* For use by the SDIO Driver */
+} CsrSdioFunctionDriver;
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunctionDriverRegister
+ *
+ *  DESCRIPTION
+ *      Register a Function Driver.
+ *
+ *  PARAMETERS
+ *      functionDriver - Pointer to struct describing the Function Driver.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The Function Driver was successfully
+ *                           registered.
+ *      CSR_RESULT_FAILURE - Unable to register the function driver,
+ *                                because of an unspecified/unknown error. The
+ *                                Function Driver has not been registered.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - The specified Function Driver pointer
+ *                                      does not point at a valid Function
+ *                                      Driver structure, or some of the members
+ *                                      contain invalid entries.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioFunctionDriverRegister(CsrSdioFunctionDriver *functionDriver);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunctionDriverUnregister
+ *
+ *  DESCRIPTION
+ *      Unregister a previously registered Function Driver.
+ *
+ *  PARAMETERS
+ *      functionDriver - pointer to struct describing the Function Driver.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSdioFunctionDriverUnregister(CsrSdioFunctionDriver *functionDriver);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunctionEnable, CsrSdioFunctionDisable
+ *
+ *  DESCRIPTION
+ *      Enable/disable the specified function by setting/clearing the
+ *      corresponding bit in the I/O Enable register in function 0, and then
+ *      periodically reading the related bit in the I/O Ready register until it
+ *      is set/clear, limited by an implementation defined timeout.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The specified function was enabled/disabled.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. The state of the
+ *                                  related bit in the I/O Enable register is
+ *                                  undefined.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device, or the related
+ *                                bit in the I/O ready register was not
+ *                                set/cleared within the timeout period.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioFunctionEnable(CsrSdioFunction *function);
+CsrResult CsrSdioFunctionDisable(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioInterruptEnable, CsrSdioInterruptDisable
+ *
+ *  DESCRIPTION
+ *      Enable/disable the interrupt for the specified function by
+ *      setting/clearing the corresponding bit in the INT Enable register in
+ *      function 0.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The specified function was enabled/disabled.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. The state of the
+ *                                  related bit in the INT Enable register is
+ *                                  unchanged.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - The specified function cannot be
+ *                                      enabled/disabled, because it either
+ *                                      does not exist or it is not possible to
+ *                                      individually enable/disable functions.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioInterruptEnable(CsrSdioFunction *function);
+CsrResult CsrSdioInterruptDisable(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioInterruptAcknowledge
+ *
+ *  DESCRIPTION
+ *      Acknowledge that a signalled interrupt has been handled. Shall only
+ *      be called once, and exactly once for each signalled interrupt to the
+ *      corresponding function.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function to which the
+ *                 event was signalled.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSdioInterruptAcknowledge(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioInsertedAcknowledge, CsrSdioRemovedAcknowledge
+ *
+ *  DESCRIPTION
+ *      Acknowledge that a signalled inserted/removed event has been handled.
+ *      Shall only be called once, and exactly once for each signalled event to
+ *      the corresponding function.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function to which the
+ *                 inserted was signalled.
+ *      result (CsrSdioInsertedAcknowledge only)
+ *          CSR_RESULT_SUCCESS - The Function Driver has accepted the
+ *                                    function, and the function is attached to
+ *                                    the Function Driver until the
+ *                                    CsrSdioRemovedCallback is called and
+ *                                    acknowledged.
+ *          CSR_RESULT_FAILURE - Unable to accept the function. The
+ *                                    function is not attached to the Function
+ *                                    Driver, and it may be passed to another
+ *                                    Function Driver which supports the
+ *                                    function.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSdioInsertedAcknowledge(CsrSdioFunction *function, CsrResult result);
+void CsrSdioRemovedAcknowledge(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioSuspendAcknowledge, CsrSdioResumeAcknowledge
+ *
+ *  DESCRIPTION
+ *      Acknowledge that a signalled suspend event has been handled. Shall only
+ *      be called once, and exactly once for each signalled event to the
+ *      corresponding function.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function to which the
+ *                 event was signalled.
+ *      result
+ *          CSR_RESULT_SUCCESS - Successfully suspended/resumed.
+ *          CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSdioSuspendAcknowledge(CsrSdioFunction *function, CsrResult result);
+void CsrSdioResumeAcknowledge(CsrSdioFunction *function, CsrResult result);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioBlockSizeSet
+ *
+ *  DESCRIPTION
+ *      Set the block size to use for the function. The actual configured block
+ *      size shall be the minimum of:
+ *          1) Maximum block size supported by the function.
+ *          2) Maximum block size supported by the host controller.
+ *          3) The block size specified by the blockSize argument.
+ *
+ *      When this function returns, the actual configured block size is
+ *      available in the blockSize member of the function struct.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      blockSize - Block size to use for the function. Valid range is 1 to
+ *                  2048.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The block size register on the chip
+ *                                was updated.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. The configured block
+ *                                  size is undefined.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and the FUNCTION_NUMBER
+ *            bits is set, CSR_SDIO_RESULT_INVALID_VALUE shall be returned.
+ *            If the ERROR bit is set (but not FUNCTION_NUMBER),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *      NOTE: Setting the block size requires two individual operations. The
+ *            implementation shall ignore the OUT_OF_RANGE bit of the SDIO R5
+ *            response for the first operation, as the partially configured
+ *            block size may be out of range, even if the final block size
+ *            (after the second operation) is in the valid range.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioBlockSizeSet(CsrSdioFunction *function, CsrUint16 blockSize);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioMaxBusClockFrequencySet
+ *
+ *  DESCRIPTION
+ *      Set the maximum clock frequency to use for the device associated with
+ *      the specified function. The actual configured clock frequency for the
+ *      device shall be the minimum of:
+ *          1) Maximum clock frequency supported by the device.
+ *          2) Maximum clock frequency supported by the host controller.
+ *          3) Maximum clock frequency specified for any function on the same
+ *             device.
+ *
+ *      If the clock frequency exceeds 25MHz, it is the responsibility of the
+ *      SDIO driver to enable high speed mode on the device, using the standard
+ *      defined procedure, before increasing the frequency beyond the limit.
+ *
+ *      Note that the clock frequency configured affects all functions on the
+ *      same device.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      maxFrequency - The maximum clock frequency for the function in Hertz.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The maximum clock frequency was succesfully
+ *                                set for the function.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *
+ *      NOTE: If the SDIO R5 response is available, and the FUNCTION_NUMBER
+ *            bits is set, CSR_SDIO_RESULT_INVALID_VALUE shall be returned.
+ *            If the ERROR bit is set (but not FUNCTION_NUMBER),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioMaxBusClockFrequencySet(CsrSdioFunction *function, CsrUint32 maxFrequency);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioRead8, CsrSdioWrite8, CsrSdioRead8Async, CsrSdioWrite8Async
+ *
+ *  DESCRIPTION
+ *      Read/write an 8bit value from/to the specified register address.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      address - Register address within the function.
+ *      data - The data to read/write.
+ *      callback - The function to call on operation completion.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The data was successfully read/written.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. No data read/written.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *      NOTE: The CsrSdioRead8Async and CsrSdioWrite8Async functions return
+ *            immediately, and the supplied callback function is called when the
+ *            operation is complete. The result value is given as an argument to
+ *            the callback function.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioRead8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data);
+CsrResult CsrSdioWrite8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data);
+void CsrSdioRead8Async(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data, CsrSdioAsyncCallback callback);
+void CsrSdioWrite8Async(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data, CsrSdioAsyncCallback callback);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioRead16, CsrSdioWrite16, CsrSdioRead16Async, CsrSdioWrite16Async
+ *
+ *  DESCRIPTION
+ *      Read/write a 16bit value from/to the specified register address.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      address - Register address within the function.
+ *      data - The data to read/write.
+ *      callback - The function to call on operation completion.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The data was successfully read/written.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. Data may have been
+ *                                  partially read/written.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *      NOTE: The CsrSdioRead16Async and CsrSdioWrite16Async functions return
+ *            immediately, and the supplied callback function is called when the
+ *            operation is complete. The result value is given as an argument to
+ *            the callback function.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioRead16(CsrSdioFunction *function, CsrUint32 address, CsrUint16 *data);
+CsrResult CsrSdioWrite16(CsrSdioFunction *function, CsrUint32 address, CsrUint16 data);
+void CsrSdioRead16Async(CsrSdioFunction *function, CsrUint32 address, CsrUint16 *data, CsrSdioAsyncCallback callback);
+void CsrSdioWrite16Async(CsrSdioFunction *function, CsrUint32 address, CsrUint16 data, CsrSdioAsyncCallback callback);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioF0Read8, CsrSdioF0Write8, CsrSdioF0Read8Async,
+ *      CsrSdioF0Write8Async
+ *
+ *  DESCRIPTION
+ *      Read/write an 8bit value from/to the specified register address in
+ *      function 0.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      address - Register address within the function.
+ *      data - The data to read/write.
+ *      callback - The function to call on operation completion.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The data was successfully read/written.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. No data read/written.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *      NOTE: The CsrSdioF0Read8Async and CsrSdioF0Write8Async functions return
+ *            immediately, and the supplied callback function is called when the
+ *            operation is complete. The result value is given as an argument to
+ *            the callback function.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioF0Read8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data);
+CsrResult CsrSdioF0Write8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data);
+void CsrSdioF0Read8Async(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data, CsrSdioAsyncCallback callback);
+void CsrSdioF0Write8Async(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data, CsrSdioAsyncCallback callback);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioRead, CsrSdioWrite, CsrSdioReadAsync, CsrSdioWriteAsync
+ *
+ *  DESCRIPTION
+ *      Read/write a specified number of bytes from/to the specified register
+ *      address.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      address - Register address within the function.
+ *      data - The data to read/write.
+ *      length - Number of byte to read/write.
+ *      callback - The function to call on operation completion.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The data was successfully read/written.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. Data may have been
+ *                                  partially read/written.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *      NOTE: The CsrSdioF0Read8Async and CsrSdioF0Write8Async functions return
+ *            immediately, and the supplied callback function is called when the
+ *            operation is complete. The result value is given as an argument to
+ *            the callback function.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioRead(CsrSdioFunction *function, CsrUint32 address, void *data, CsrUint32 length);
+CsrResult CsrSdioWrite(CsrSdioFunction *function, CsrUint32 address, const void *data, CsrUint32 length);
+void CsrSdioReadAsync(CsrSdioFunction *function, CsrUint32 address, void *data, CsrUint32 length, CsrSdioAsyncCallback callback);
+void CsrSdioWriteAsync(CsrSdioFunction *function, CsrUint32 address, const void *data, CsrUint32 length, CsrSdioAsyncCallback callback);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioPowerOn, CsrSdioPowerOff
+ *
+ *  DESCRIPTION
+ *      Power on/off the device.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function that resides on
+ *                 the device to power on/off.
+ *
+ *  RETURNS (only CsrSdioPowerOn)
+ *      CSR_RESULT_SUCCESS - Power was succesfully reapplied and the device
+ *                                has been reinitialised.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured during reinitialisation.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device during
+ *                                reinitialisation.
+ *      CSR_SDIO_RESULT_NOT_RESET - The power was not removed by the
+ *                                  CsrSdioPowerOff call. The state of the
+ *                                  device is unchanged.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioPowerOn(CsrSdioFunction *function);
+void CsrSdioPowerOff(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioHardReset
+ *
+ *  DESCRIPTION
+ *      Perform a hardware reset of the device.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function that resides on
+ *                 the device to hard reset.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - Reset was succesfully performed and the device
+ *                                has been reinitialised.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured during reinitialisation.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device during
+ *                                reinitialisation.
+ *      CSR_SDIO_RESULT_NOT_RESET - The reset was not applied because it is not
+ *                                  supported. The state of the device is
+ *                                  unchanged.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioHardReset(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunctionActive, CsrSdioFunctionIdle
+ *
+ *  DESCRIPTION
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSdioFunctionActive(CsrSdioFunction *function);
+void CsrSdioFunctionIdle(CsrSdioFunction *function);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_serialize_primitive_types.c b/drivers/staging/csr/csr_serialize_primitive_types.c
new file mode 100644
index 0000000..5ea06fc
--- /dev/null
+++ b/drivers/staging/csr/csr_serialize_primitive_types.c
@@ -0,0 +1,472 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include <linux/module.h>
+#include "csr_types.h"
+#include "csr_prim_defs.h"
+#include "csr_msgconv.h"
+#include "csr_util.h"
+#include "csr_pmem.h"
+#include "csr_lib.h"
+
+void CsrUint8Des(CsrUint8 *value, CsrUint8 *buffer, CsrSize *offset)
+{
+    *value = buffer[*offset];
+    *offset += sizeof(*value);
+}
+EXPORT_SYMBOL_GPL(CsrUint8Des);
+
+void CsrUint16Des(CsrUint16 *value, CsrUint8 *buffer, CsrSize *offset)
+{
+    *value = (buffer[*offset + 0] << 0) |
+             (buffer[*offset + 1] << 8);
+    *offset += sizeof(*value);
+}
+EXPORT_SYMBOL_GPL(CsrUint16Des);
+
+void CsrUint32Des(CsrUint32 *value, CsrUint8 *buffer, CsrSize *offset)
+{
+    *value = (buffer[*offset + 0] << 0) |
+             (buffer[*offset + 1] << 8) |
+             (buffer[*offset + 2] << 16) |
+             (buffer[*offset + 3] << 24);
+    *offset += sizeof(*value);
+}
+EXPORT_SYMBOL_GPL(CsrUint32Des);
+
+void CsrMemCpyDes(void *value, CsrUint8 *buffer, CsrSize *offset, CsrSize length)
+{
+    CsrMemCpy(value, &buffer[*offset], length);
+    *offset += length;
+}
+EXPORT_SYMBOL_GPL(CsrMemCpyDes);
+
+void CsrCharStringDes(CsrCharString **value, CsrUint8 *buffer, CsrSize *offset)
+{
+    *value = CsrStrDup((CsrCharString *) &buffer[*offset]);
+    *offset += CsrStrLen(*value) + 1;
+}
+EXPORT_SYMBOL_GPL(CsrCharStringDes);
+
+void CsrUtf8StringDes(CsrUtf8String **value, CsrUint8 *buffer, CsrSize *offset)
+{
+    *value = (CsrUtf8String *) CsrStrDup((CsrCharString *) &buffer[*offset]);
+    *offset += CsrStrLen((CsrCharString *) *value) + 1;
+}
+
+void CsrUtf16StringDes(CsrUtf16String **value, CsrUint8 *buffer, CsrSize *offset)
+{
+    CsrUint32 length, i;
+
+    CsrUint32Des(&length, buffer, offset);
+
+    *value = CsrPmemAlloc(length * sizeof(**value));
+    for (i = 0; i < length; i++)
+    {
+        CsrUint16Des(&(*value)[i], buffer, offset);
+    }
+}
+
+void CsrSizeDes(CsrSize *value, CsrUint8 *buffer, CsrSize *offset)
+{
+    *value = (buffer[*offset + 0] << 0) |
+             (buffer[*offset + 1] << 8) |
+             (buffer[*offset + 2] << 16) |
+             (buffer[*offset + 3] << 24);
+    *offset += sizeof(*value);
+}
+
+void CsrVoidPtrDes(void **value, CsrUint8 *buffer, CsrSize *offset)
+{
+    CsrSizeDes((CsrSize *) value, buffer, offset);
+}
+
+void CsrUint8Ser(CsrUint8 *buffer, CsrSize *offset, CsrUint8 value)
+{
+    buffer[*offset] = value;
+    *offset += sizeof(value);
+}
+EXPORT_SYMBOL_GPL(CsrUint8Ser);
+
+void CsrUint16Ser(CsrUint8 *buffer, CsrSize *offset, CsrUint16 value)
+{
+    buffer[*offset + 0] = (CsrUint8) ((value >> 0) & 0xFF);
+    buffer[*offset + 1] = (CsrUint8) ((value >> 8) & 0xFF);
+    *offset += sizeof(value);
+}
+EXPORT_SYMBOL_GPL(CsrUint16Ser);
+
+void CsrUint32Ser(CsrUint8 *buffer, CsrSize *offset, CsrUint32 value)
+{
+    buffer[*offset + 0] = (CsrUint8) ((value >> 0) & 0xFF);
+    buffer[*offset + 1] = (CsrUint8) ((value >> 8) & 0xFF);
+    buffer[*offset + 2] = (CsrUint8) ((value >> 16) & 0xFF);
+    buffer[*offset + 3] = (CsrUint8) ((value >> 24) & 0xFF);
+    *offset += sizeof(value);
+}
+EXPORT_SYMBOL_GPL(CsrUint32Ser);
+
+void CsrMemCpySer(CsrUint8 *buffer, CsrSize *offset, const void *value, CsrSize length)
+{
+    CsrMemCpy(&buffer[*offset], value, length);
+    *offset += length;
+}
+EXPORT_SYMBOL_GPL(CsrMemCpySer);
+
+void CsrCharStringSer(CsrUint8 *buffer, CsrSize *offset, const CsrCharString *value)
+{
+    if (value)
+    {
+        CsrStrCpy(((CsrCharString *) &buffer[*offset]), value);
+        *offset += CsrStrLen(value) + 1;
+    }
+    else
+    {
+        CsrUint8Ser(buffer, offset, 0);
+    }
+}
+EXPORT_SYMBOL_GPL(CsrCharStringSer);
+
+void CsrUtf8StringSer(CsrUint8 *buffer, CsrSize *offset, const CsrUtf8String *value)
+{
+    CsrCharStringSer(buffer, offset, (CsrCharString *) value);
+}
+
+void CsrUtf16StringSer(CsrUint8 *buffer, CsrSize *offset, const CsrUtf16String *value)
+{
+    if (value)
+    {
+        CsrUint32 length = CsrUtf16StrLen(value) + 1;
+        CsrUint32 i;
+
+        CsrUint32Ser(buffer, offset, length);
+
+        for (i = 0; i < length; i++)
+        {
+            CsrUint16Ser(buffer, offset, (CsrUint16) value[i]);
+        }
+    }
+    else
+    {
+        CsrUint32Ser(buffer, offset, 0);
+    }
+}
+
+void CsrSizeSer(CsrUint8 *buffer, CsrSize *offset, CsrSize value)
+{
+    buffer[*offset + 0] = (CsrUint8) ((value >> 0) & 0xFF);
+    buffer[*offset + 1] = (CsrUint8) ((value >> 8) & 0xFF);
+    buffer[*offset + 2] = (CsrUint8) ((value >> 16) & 0xFF);
+    buffer[*offset + 3] = (CsrUint8) ((value >> 24) & 0xFF);
+    *offset += sizeof(value);
+}
+
+void CsrVoidPtrSer(CsrUint8 *buffer, CsrSize *offset, void *ptr)
+{
+    CsrSizeSer(buffer, offset, (CsrSize) ptr);
+}
+
+CsrUint32 CsrCharStringSerLen(const CsrCharString *str)
+{
+    if (str)
+    {
+        return (CsrUint32) (CsrStrLen(str) + sizeof(*str));
+    }
+    else
+    {
+        return sizeof(*str);
+    }
+}
+
+CsrUint32 CsrUtf8StringSerLen(const CsrUtf8String *str)
+{
+    if (str)
+    {
+        return (CsrUint32) (CsrStrLen((CsrCharString *) str) + sizeof(*str));
+    }
+    else
+    {
+        return sizeof(*str);
+    }
+}
+
+CsrUint32 CsrUtf16StringSerLen(const CsrUtf16String *str)
+{
+    if (str)
+    {
+        /* We always write down the length of the string */
+        return sizeof(CsrUint32) + (CsrUtf16StrLen(str) + 1) * sizeof(*str);
+    }
+    else
+    {
+        return sizeof(CsrUint32);
+    }
+}
+
+CsrSize CsrEventSizeof(void *msg)
+{
+    return 2;
+}
+
+CsrUint8 *CsrEventSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrEvent *primitive = (CsrEvent *) msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->type);
+    return ptr;
+}
+
+void *CsrEventDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrEvent *primitive = (CsrEvent *) CsrPmemAlloc(sizeof(CsrEvent));
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->type, buffer, &offset);
+
+    return primitive;
+}
+
+CsrSize CsrEventCsrUint8Sizeof(void *msg)
+{
+    return 3;
+}
+
+CsrUint8 *CsrEventCsrUint8Ser(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrEventCsrUint8 *primitive = (CsrEventCsrUint8 *) msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->type);
+    CsrUint8Ser(ptr, len, primitive->value);
+    return ptr;
+}
+
+void *CsrEventCsrUint8Des(CsrUint8 *buffer, CsrSize length)
+{
+    CsrEventCsrUint8 *primitive = (CsrEventCsrUint8 *) CsrPmemAlloc(sizeof(CsrEventCsrUint8));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->type, buffer, &offset);
+    CsrUint8Des(&primitive->value, buffer, &offset);
+
+    return primitive;
+}
+
+CsrSize CsrEventCsrUint16Sizeof(void *msg)
+{
+    return 4;
+}
+
+CsrUint8 *CsrEventCsrUint16Ser(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrEventCsrUint16 *primitive = (CsrEventCsrUint16 *) msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->type);
+    CsrUint16Ser(ptr, len, primitive->value);
+    return ptr;
+}
+
+void *CsrEventCsrUint16Des(CsrUint8 *buffer, CsrSize length)
+{
+    CsrEventCsrUint16 *primitive = (CsrEventCsrUint16 *) CsrPmemAlloc(sizeof(CsrEventCsrUint16));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->type, buffer, &offset);
+    CsrUint16Des(&primitive->value, buffer, &offset);
+
+    return primitive;
+}
+
+CsrSize CsrEventCsrUint32Sizeof(void *msg)
+{
+    return 6;
+}
+
+CsrUint8 *CsrEventCsrUint32Ser(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrEventCsrUint32 *primitive = (CsrEventCsrUint32 *) msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->type);
+    CsrUint32Ser(ptr, len, primitive->value);
+    return ptr;
+}
+
+void *CsrEventCsrUint32Des(CsrUint8 *buffer, CsrSize length)
+{
+    CsrEventCsrUint32 *primitive = (CsrEventCsrUint32 *) CsrPmemAlloc(sizeof(CsrEventCsrUint32));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->type, buffer, &offset);
+    CsrUint32Des(&primitive->value, buffer, &offset);
+
+    return primitive;
+}
+
+CsrSize CsrEventCsrUint16CsrUint8Sizeof(void *msg)
+{
+    return 5;
+}
+
+CsrUint8 *CsrEventCsrUint16CsrUint8Ser(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrEventCsrUint16CsrUint8 *primitive = (CsrEventCsrUint16CsrUint8 *) msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->type);
+    CsrUint16Ser(ptr, len, primitive->value1);
+    CsrUint8Ser(ptr, len, primitive->value2);
+    return ptr;
+}
+
+void *CsrEventCsrUint16CsrUint8Des(CsrUint8 *buffer, CsrSize length)
+{
+    CsrEventCsrUint16CsrUint8 *primitive = (CsrEventCsrUint16CsrUint8 *) CsrPmemAlloc(sizeof(CsrEventCsrUint16CsrUint8));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->type, buffer, &offset);
+    CsrUint16Des(&primitive->value1, buffer, &offset);
+    CsrUint8Des(&primitive->value2, buffer, &offset);
+
+    return primitive;
+}
+
+CsrSize CsrEventCsrUint16CsrUint16Sizeof(void *msg)
+{
+    return 6;
+}
+
+CsrUint8 *CsrEventCsrUint16CsrUint16Ser(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrEventCsrUint16CsrUint16 *primitive = (CsrEventCsrUint16CsrUint16 *) msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->type);
+    CsrUint16Ser(ptr, len, primitive->value1);
+    CsrUint16Ser(ptr, len, primitive->value2);
+    return ptr;
+}
+
+void *CsrEventCsrUint16CsrUint16Des(CsrUint8 *buffer, CsrSize length)
+{
+    CsrEventCsrUint16CsrUint16 *primitive = (CsrEventCsrUint16CsrUint16 *) CsrPmemAlloc(sizeof(CsrEventCsrUint16CsrUint16));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->type, buffer, &offset);
+    CsrUint16Des(&primitive->value1, buffer, &offset);
+    CsrUint16Des(&primitive->value2, buffer, &offset);
+
+    return primitive;
+}
+
+CsrSize CsrEventCsrUint16CsrUint32Sizeof(void *msg)
+{
+    return 8;
+}
+
+CsrUint8 *CsrEventCsrUint16CsrUint32Ser(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrEventCsrUint16CsrUint32 *primitive = (CsrEventCsrUint16CsrUint32 *) msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->type);
+    CsrUint16Ser(ptr, len, primitive->value1);
+    CsrUint32Ser(ptr, len, primitive->value2);
+    return ptr;
+}
+
+void *CsrEventCsrUint16CsrUint32Des(CsrUint8 *buffer, CsrSize length)
+{
+    CsrEventCsrUint16CsrUint32 *primitive = (CsrEventCsrUint16CsrUint32 *) CsrPmemAlloc(sizeof(CsrEventCsrUint16CsrUint32));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->type, buffer, &offset);
+    CsrUint16Des(&primitive->value1, buffer, &offset);
+    CsrUint32Des(&primitive->value2, buffer, &offset);
+
+    return primitive;
+}
+
+CsrSize CsrEventCsrUint16CsrCharStringSizeof(void *msg)
+{
+    CsrEventCsrUint16CsrCharString *primitive = (CsrEventCsrUint16CsrCharString *) msg;
+    return 4 + CsrStrLen(primitive->value2) + 1;
+}
+
+CsrUint8 *CsrEventCsrUint16CsrCharStringSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrEventCsrUint16CsrCharString *primitive = (CsrEventCsrUint16CsrCharString *) msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->type);
+    CsrUint16Ser(ptr, len, primitive->value1);
+    CsrCharStringSer(ptr, len, primitive->value2);
+    return ptr;
+}
+
+void *CsrEventCsrUint16CsrCharStringDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrEventCsrUint16CsrCharString *primitive = (CsrEventCsrUint16CsrCharString *) CsrPmemAlloc(sizeof(CsrEventCsrUint16CsrCharString));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->type, buffer, &offset);
+    CsrUint16Des(&primitive->value1, buffer, &offset);
+    CsrCharStringDes(&primitive->value2, buffer, &offset);
+
+    return primitive;
+}
+
+CsrSize CsrEventCsrUint32CsrUint16Sizeof(void *msg)
+{
+    return 8;
+}
+
+CsrUint8 *CsrEventCsrUint32CsrUint16Ser(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrEventCsrUint32CsrUint16 *primitive = (CsrEventCsrUint32CsrUint16 *) msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->type);
+    CsrUint32Ser(ptr, len, primitive->value1);
+    CsrUint16Ser(ptr, len, primitive->value2);
+    return ptr;
+}
+
+void *CsrEventCsrUint32CsrUint16Des(CsrUint8 *buffer, CsrSize length)
+{
+    CsrEventCsrUint32CsrUint16 *primitive = (CsrEventCsrUint32CsrUint16 *) CsrPmemAlloc(sizeof(CsrEventCsrUint32CsrUint16));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->type, buffer, &offset);
+    CsrUint32Des(&primitive->value1, buffer, &offset);
+    CsrUint16Des(&primitive->value2, buffer, &offset);
+
+    return primitive;
+}
+
+CsrSize CsrEventCsrUint32CsrCharStringSizeof(void *msg)
+{
+    CsrEventCsrUint32CsrCharString *primitive = (CsrEventCsrUint32CsrCharString *) msg;
+    return 6 + CsrStrLen(primitive->value2) + 1;
+}
+
+CsrUint8 *CsrEventCsrUint32CsrCharStringSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrEventCsrUint32CsrCharString *primitive = (CsrEventCsrUint32CsrCharString *) msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->type);
+    CsrUint32Ser(ptr, len, primitive->value1);
+    CsrCharStringSer(ptr, len, primitive->value2);
+    return ptr;
+}
+
+void *CsrEventCsrUint32CsrCharStringDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrEventCsrUint32CsrCharString *primitive = (CsrEventCsrUint32CsrCharString *) CsrPmemAlloc(sizeof(CsrEventCsrUint32CsrCharString));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->type, buffer, &offset);
+    CsrUint32Des(&primitive->value1, buffer, &offset);
+    CsrCharStringDes(&primitive->value2, buffer, &offset);
+
+    return primitive;
+}
diff --git a/drivers/staging/csr/csr_time.c b/drivers/staging/csr/csr_time.c
new file mode 100644
index 0000000..1ef61e3
--- /dev/null
+++ b/drivers/staging/csr/csr_time.c
@@ -0,0 +1,71 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
+#include <linux/autoconf.h>
+#include <linux/config.h>
+#endif
+
+#include <linux/time.h>
+#include <linux/module.h>
+
+#include "csr_types.h"
+#include "csr_time.h"
+
+CsrTime CsrTimeGet(CsrTime *high)
+{
+    struct timespec ts;
+    CsrUint64 time;
+    CsrTime low;
+
+    ts = current_kernel_time();
+    time = (CsrUint64) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+
+    if (high != NULL)
+    {
+        *high = (CsrTime) ((time >> 32) & 0xFFFFFFFF);
+    }
+
+    low = (CsrTime) (time & 0xFFFFFFFF);
+
+    return low;
+}
+EXPORT_SYMBOL_GPL(CsrTimeGet);
+
+void CsrTimeUtcGet(CsrTimeUtc *tod, CsrTime *low, CsrTime *high)
+{
+    struct timespec ts;
+    CsrUint64 time;
+
+    ts = current_kernel_time();
+    time = (CsrUint64) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+
+    if (high != NULL)
+    {
+        *high = (CsrTime) ((time >> 32) & 0xFFFFFFFF);
+    }
+
+    if (low != NULL)
+    {
+        *low = (CsrTime) (time & 0xFFFFFFFF);
+    }
+
+    if (tod != NULL)
+    {
+        struct timeval tv;
+        do_gettimeofday(&tv);
+        tod->sec = tv.tv_sec;
+        tod->msec = tv.tv_usec / 1000;
+    }
+}
diff --git a/drivers/staging/csr/csr_time.h b/drivers/staging/csr/csr_time.h
new file mode 100644
index 0000000..0ede47e
--- /dev/null
+++ b/drivers/staging/csr/csr_time.h
@@ -0,0 +1,205 @@
+#ifndef CSR_TIME_H__
+#define CSR_TIME_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+
+    NAME
+        CsrTime
+
+    DESCRIPTION
+        Type to hold a value describing the current system time, which is a
+        measure of time elapsed since some arbitrarily defined fixed time
+        reference, usually associated with system startup.
+
+*******************************************************************************/
+typedef CsrUint32 CsrTime;
+
+
+/*******************************************************************************
+
+    NAME
+        CsrTimeUtc
+
+    DESCRIPTION
+        Type to hold a value describing a UTC wallclock time expressed in
+        seconds and milliseconds elapsed since midnight January 1st 1970.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint32 sec;
+    CsrUint16 msec;
+} CsrTimeUtc;
+
+
+/*******************************************************************************
+
+    NAME
+        CsrTimeGet
+
+    DESCRIPTION
+        Returns the current system time in a low and a high part. The low part
+        is expressed in microseconds. The high part is incremented when the low
+        part wraps to provide an extended range.
+
+        The caller may provide a NULL pointer as the high parameter. In this case
+        the function just returns the low part and ignores the high parameter.
+
+        Although the time is expressed in microseconds the actual resolution is
+        platform dependent and can be less. It is recommended that the
+        resolution is at least 10 milliseconds.
+
+    PARAMETERS
+        high - Pointer to variable that will receive the high part of the
+               current system time. Passing NULL is valid.
+
+    RETURNS
+        Low part of current system time in microseconds.
+
+*******************************************************************************/
+CsrTime CsrTimeGet(CsrTime *high);
+
+
+/*******************************************************************************
+
+    NAME
+        CsrTimeUtcGet
+
+    DESCRIPTION
+        Get the current system wallclock time, and optionally the current system
+        time in a low and a high part as would have been returned by
+        CsrTimeGet.
+
+        Although CsrTimeUtc is expressed in seconds and milliseconds, the actual
+        resolution is platform dependent, and can be less. It is recommended
+        that the resolution is at least 1 second.
+
+    PARAMETERS
+        tod - Pointer to variable that will receive the current system
+              wallclock time.
+        low - The low part of the current system time in microseconds. Passing
+              NULL is valid.
+        high - The high part of the current system time in microseconds. Passing
+               NULL is valid.
+
+*******************************************************************************/
+void CsrTimeUtcGet(CsrTimeUtc *tod, CsrTime *low, CsrTime *high);
+
+
+/*------------------------------------------------------------------*/
+/* CsrTime Macros */
+/*------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrTimeAdd
+ *
+ *  DESCRIPTION
+ *      Add two time values. Adding the numbers can overflow the range of a
+ *      CsrTime, so the user must be cautious.
+ *
+ *  RETURNS
+ *      CsrTime - the sum of "t1" and "t2".
+ *
+ *----------------------------------------------------------------------------*/
+#define CsrTimeAdd(t1, t2) ((t1) + (t2))
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrTimeSub
+ *
+ *  DESCRIPTION
+ *      Subtract two time values. Subtracting the numbers can provoke an
+ *      underflow, so the user must be cautious.
+ *
+ *  RETURNS
+ *      CsrTime - "t1" - "t2".
+ *
+ *----------------------------------------------------------------------------*/
+#define CsrTimeSub(t1, t2)    ((CsrInt32) (t1) - (CsrInt32) (t2))
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrTimeEq
+ *
+ *  DESCRIPTION
+ *      Compare two time values.
+ *
+ *  RETURNS
+ *      !0 if "t1" equal "t2", else 0.
+ *
+ *----------------------------------------------------------------------------*/
+#define CsrTimeEq(t1, t2) ((t1) == (t2))
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrTimeGt
+ *
+ *  DESCRIPTION
+ *      Compare two time values.
+ *
+ *  RETURNS
+ *      !0 if "t1" is greater than "t2", else 0.
+ *
+ *----------------------------------------------------------------------------*/
+#define CsrTimeGt(t1, t2) (CsrTimeSub((t1), (t2)) > 0)
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrTimeGe
+ *
+ *  DESCRIPTION
+ *      Compare two time values.
+ *
+ *  RETURNS
+ *      !0 if "t1" is greater than, or equal to "t2", else 0.
+ *
+ *----------------------------------------------------------------------------*/
+#define CsrTimeGe(t1, t2) (CsrTimeSub((t1), (t2)) >= 0)
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrTimeLt
+ *
+ *  DESCRIPTION
+ *      Compare two time values.
+ *
+ *  RETURNS
+ *      !0 if "t1" is less than "t2", else 0.
+ *
+ *----------------------------------------------------------------------------*/
+#define CsrTimeLt(t1, t2) (CsrTimeSub((t1), (t2)) < 0)
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrTimeLe
+ *
+ *  DESCRIPTION
+ *      Compare two time values.
+ *
+ *  RETURNS
+ *      !0 if "t1" is less than, or equal to "t2", else 0.
+ *
+ *----------------------------------------------------------------------------*/
+#define CsrTimeLe(t1, t2) (CsrTimeSub((t1), (t2)) <= 0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_types.h b/drivers/staging/csr/csr_types.h
new file mode 100644
index 0000000..23193ea
--- /dev/null
+++ b/drivers/staging/csr/csr_types.h
@@ -0,0 +1,94 @@
+#ifndef CSR_TYPES_H__
+#define CSR_TYPES_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifdef __KERNEL__
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <linux/string.h>
+#else
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#undef  FALSE
+#define FALSE (0)
+
+#undef  TRUE
+#define TRUE (1)
+
+/* Basic types */
+typedef size_t CsrSize;         /* Return type of sizeof (ISO/IEC 9899:1990 7.1.6) */
+typedef ptrdiff_t CsrPtrdiff;   /* Type of the result of subtracting two pointers (ISO/IEC 9899:1990 7.1.6) */
+typedef uintptr_t CsrUintptr;   /* Unsigned integer large enough to hold any pointer (ISO/IEC 9899:1999 7.18.1.4) */
+#ifdef __KERNEL__
+typedef ptrdiff_t CsrIntptr;    /* intptr_t is not defined in kernel. Use the equivalent ptrdiff_t. */
+#else
+typedef intptr_t CsrIntptr;     /* Signed integer large enough to hold any pointer (ISO/IEC 9899:1999 7.18.1.4) */
+#endif
+
+/* Unsigned fixed width types */
+typedef uint8_t CsrUint8;
+typedef uint16_t CsrUint16;
+typedef uint32_t CsrUint32;
+
+/* Signed fixed width types */
+typedef int8_t CsrInt8;
+typedef int16_t CsrInt16;
+typedef int32_t CsrInt32;
+
+/* Boolean */
+typedef CsrUint8 CsrBool;
+
+/* String types */
+typedef char CsrCharString;
+typedef CsrUint8 CsrUtf8String;
+typedef CsrUint16 CsrUtf16String;   /* 16-bit UTF16 strings */
+typedef CsrUint32 CsrUint24;
+
+/*
+ * 64-bit integers
+ *
+ * Note: If a given compiler does not support 64-bit types, it is
+ * OK to omit these definitions;  32-bit versions of the code using
+ * these types may be available.  Consult the relevant documentation
+ * or the customer support group for information on this.
+ */
+#define CSR_HAVE_64_BIT_INTEGERS
+typedef uint64_t CsrUint64;
+typedef int64_t CsrInt64;
+
+/*
+ * Floating point
+ *
+ * Note: If a given compiler does not support floating point, it is
+ * OK to omit these definitions;  alternative versions of the code using
+ * these types may be available.  Consult the relevant documentation
+ * or the customer support group for information on this.
+ */
+#define CSR_HAVE_FLOATING_POINT
+typedef float CsrFloat;
+typedef double CsrDouble;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_unicode.h b/drivers/staging/csr/csr_unicode.h
new file mode 100644
index 0000000..9faf856
--- /dev/null
+++ b/drivers/staging/csr/csr_unicode.h
@@ -0,0 +1,190 @@
+#ifndef CSR_UNICODE_H__
+#define CSR_UNICODE_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CsrUtf16String *CsrUint32ToUtf16String(CsrUint32 number);
+
+CsrUint32 CsrUtf16StringToUint32(const CsrUtf16String *unicodeString);
+CsrUint32 CsrUtf16StrLen(const CsrUtf16String *unicodeString);
+
+CsrUtf8String *CsrUtf16String2Utf8(const CsrUtf16String *source);
+
+CsrUtf16String *CsrUtf82Utf16String(const CsrUtf8String *utf8String);
+
+CsrUtf16String *CsrUtf16StrCpy(CsrUtf16String *target, const CsrUtf16String *source);
+CsrUtf16String *CsrUtf16StringDuplicate(const CsrUtf16String *source);
+
+CsrUint16 CsrUtf16StrICmp(const CsrUtf16String *string1, const CsrUtf16String *string2);
+CsrUint16 CsrUtf16StrNICmp(const CsrUtf16String *string1, const CsrUtf16String *string2, CsrUint32 count);
+
+CsrUtf16String *CsrUtf16MemCpy(CsrUtf16String *dest, const CsrUtf16String *src, CsrUint32 count);
+CsrUtf16String *CsrUtf16ConcatenateTexts(const CsrUtf16String *inputText1, const CsrUtf16String *inputText2,
+    const CsrUtf16String *inputText3, const CsrUtf16String *inputText4);
+
+CsrUtf16String *CsrUtf16String2XML(CsrUtf16String *str);
+CsrUtf16String *CsrXML2Utf16String(CsrUtf16String *str);
+
+CsrInt32 CsrUtf8StrCmp(const CsrUtf8String *string1, const CsrUtf8String *string2);
+CsrInt32 CsrUtf8StrNCmp(const CsrUtf8String *string1, const CsrUtf8String *string2, CsrSize count);
+CsrUint32 CsrUtf8StringLengthInBytes(const CsrUtf8String *string);
+
+/*******************************************************************************
+
+    NAME
+        CsrUtf8StrTruncate
+
+    DESCRIPTION
+        In-place truncate a string on a UTF-8 character boundary by writing a
+        null character somewhere in the range target[count - 3]:target[count].
+
+        Please note that memory passed must be at least of length count + 1, to
+        ensure space for a full length string that is terminated at
+        target[count], in the event that target[count - 1] is the final byte of
+        a UTF-8 character.
+
+    PARAMETERS
+        target - Target string to truncate.
+        count - The desired length, in bytes, of the resulting string. Depending
+                on the contents, the resulting string length will be between
+                count - 3 and count.
+
+    RETURNS
+        Returns target
+
+*******************************************************************************/
+CsrUtf8String *CsrUtf8StrTruncate(CsrUtf8String *target, CsrSize count);
+
+/*******************************************************************************
+
+    NAME
+        CsrUtf8StrCpy
+
+    DESCRIPTION
+        Copies the null terminated UTF-8 string pointed at by source into the
+        memory pointed at by target, including the terminating null character.
+
+        To avoid overflows, the size of the memory pointed at by target shall be
+        long enough to contain the same UTF-8 string as source (including the
+        terminating null character), and should not overlap in memory with
+        source.
+
+    PARAMETERS
+        target - Pointer to the target memory where the content is to be copied.
+        source - UTF-8 string to be copied.
+
+    RETURNS
+        Returns target
+
+*******************************************************************************/
+CsrUtf8String *CsrUtf8StrCpy(CsrUtf8String *target, const CsrUtf8String *source);
+
+/*******************************************************************************
+
+    NAME
+        CsrUtf8StrNCpy
+
+    DESCRIPTION
+        Copies the first count bytes of source to target. If the end of the
+        source UTF-8 string (which is signaled by a null-character) is found
+        before count bytes have been copied, target is padded with null
+        characters until a total of count bytes have been written to it.
+
+        No null-character is implicitly appended to the end of target, so target
+        will only be null-terminated if the length of the UTF-8 string in source
+        is less than count.
+
+    PARAMETERS
+        target - Pointer to the target memory where the content is to be copied.
+        source - UTF-8 string to be copied.
+        count - Maximum number of bytes to be written to target.
+
+    RETURNS
+        Returns target
+
+*******************************************************************************/
+CsrUtf8String *CsrUtf8StrNCpy(CsrUtf8String *target, const CsrUtf8String *source, CsrSize count);
+
+/*******************************************************************************
+
+    NAME
+        CsrUtf8StrNCpyZero
+
+    DESCRIPTION
+        Equivalent to CsrUtf8StrNCpy, but if the length of source is equal to or
+        greater than count the target string is truncated on a UTF-8 character
+        boundary by writing a null character somewhere in the range
+        target[count - 4]:target[count - 1], leaving the target string
+        unconditionally null terminated in all cases.
+
+        Please note that if the length of source is shorter than count, no
+        truncation will be applied, and the target string will be a one to one
+        copy of source.
+
+    PARAMETERS
+        target - Pointer to the target memory where the content is to be copied.
+        source - UTF-8 string to be copied.
+        count - Maximum number of bytes to be written to target.
+
+    RETURNS
+        Returns target
+
+*******************************************************************************/
+CsrUtf8String *CsrUtf8StrNCpyZero(CsrUtf8String *target, const CsrUtf8String *source, CsrSize count);
+
+/*******************************************************************************
+
+    NAME
+        CsrUtf8StrDup
+
+    DESCRIPTION
+        This function will allocate memory and copy the source string into the
+        allocated memory, which is then returned as a duplicate of the original
+        string. The memory returned must be freed by calling CsrPmemFree when
+        the duplicate is no longer needed.
+
+    PARAMETERS
+        source - UTF-8 string to be duplicated.
+
+    RETURNS
+        Returns a duplicate of source.
+
+*******************************************************************************/
+CsrUtf8String *CsrUtf8StrDup(const CsrUtf8String *source);
+
+CsrUtf8String *CsrUtf8StringConcatenateTexts(const CsrUtf8String *inputText1, const CsrUtf8String *inputText2, const CsrUtf8String *inputText3, const CsrUtf8String *inputText4);
+
+/*
+ * UCS2
+ *
+ * D-13157
+ */
+typedef CsrUint8 CsrUcs2String;
+
+CsrSize CsrUcs2ByteStrLen(const CsrUcs2String *ucs2String);
+CsrSize CsrConverterUcs2ByteStrLen(const CsrUcs2String *str);
+
+CsrUint8 *CsrUcs2ByteString2Utf8(const CsrUcs2String *ucs2String);
+CsrUcs2String *CsrUtf82Ucs2ByteString(const CsrUint8 *utf8String);
+
+CsrUint8 *CsrUtf16String2Ucs2ByteString(const CsrUtf16String *source);
+CsrUtf16String *CsrUcs2ByteString2Utf16String(const CsrUint8 *source);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_utf16.c b/drivers/staging/csr/csr_utf16.c
new file mode 100644
index 0000000..9259635
--- /dev/null
+++ b/drivers/staging/csr/csr_utf16.c
@@ -0,0 +1,1136 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+#include <linux/module.h>
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_unicode.h"
+#include "csr_util.h"
+
+#define UNI_SUR_HIGH_START   ((CsrUint32) 0xD800)
+#define UNI_SUR_HIGH_END     ((CsrUint32) 0xDBFF)
+#define UNI_SUR_LOW_START    ((CsrUint32) 0xDC00)
+#define UNI_SUR_LOW_END      ((CsrUint32) 0xDFFF)
+#define UNI_REPLACEMENT_CHAR ((CsrUint32) 0xFFFD)
+#define UNI_HALF_SHIFT       ((CsrUint8) 10)  /* used for shifting by 10 bits */
+#define UNI_HALF_BASE        ((CsrUint32) 0x00010000)
+#define UNI_BYTEMASK         ((CsrUint32) 0xBF)
+#define UNI_BYTEMARK         ((CsrUint32) 0x80)
+
+#define CAPITAL(x)    ((x >= 'a') && (x <= 'z') ? ((x) & 0x00DF) : (x))
+
+/*
+*  Index into the table with the first byte to get the number of trailing bytes in a utf-8 character.
+*  -1 if the byte has an invalid value.
+*
+*  Legal sequences are:
+*
+*  byte  1st      2nd      3rd      4th
+*
+*       00-7F
+*       C2-DF    80-BF
+*       E0       A0-BF    80-BF
+*       E1-EC    80-BF    80-BF
+*       ED       80-9F    80-BF
+*       EE-EF    80-BF    80-BF
+*       F0       90-BF    80-BF    80-BF
+*       F1-F3    80-BF    80-BF    80-BF
+*       F4       80-8F    80-BF    80-BF
+*/
+static const CsrInt8 trailingBytesForUtf8[256] =
+{
+    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,                                 /* 0x00 - 0x1F */
+    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,                                 /* 0x20 - 0x3F */
+    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,                                 /* 0x40 - 0x5F */
+    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,                                 /* 0x60 - 0x7F */
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 - 0x9F */
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xA0 - 0xBF */
+    -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,                               /* 0xC0 - 0xDF */
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,                      /* 0xE0 - 0xFF */
+};
+
+/* Values to be substracted from a CsrUint32 when converting from UTF8 to UTF16 */
+static const CsrUint32 offsetsFromUtf8[4] =
+{
+    0x00000000, 0x00003080, 0x000E2080, 0x03C82080
+};
+
+/********************************************************************************
+*
+*   Name:           CsrUint32ToUtf16String
+*
+*   Description:    The function converts an 32 bit number to an UTF-16 string
+*                   that is allocated and 0-terminated.
+*
+*   Input:          32 bit number.
+*
+*   Output:         A string of UTF-16 characters.
+*
+*********************************************************************************/
+CsrUtf16String *CsrUint32ToUtf16String(CsrUint32 number)
+{
+    CsrUint16 count, noOfDigits;
+    CsrUtf16String *output;
+    CsrUint32 tempNumber;
+
+    /* calculate the number of digits in the output */
+    tempNumber = number;
+    noOfDigits = 1;
+    while (tempNumber >= 10)
+    {
+        tempNumber = tempNumber / 10;
+        noOfDigits++;
+    }
+
+    output = (CsrUtf16String *) CsrPmemAlloc(sizeof(CsrUtf16String) * (noOfDigits + 1)); /*add space for 0-termination*/
+
+    tempNumber = number;
+    for (count = noOfDigits; count > 0; count--)
+    {
+        output[count - 1] = (CsrUtf16String) ((tempNumber % 10) + '0');
+        tempNumber = tempNumber / 10;
+    }
+    output[noOfDigits] = '\0';
+
+    return output;
+}
+
+/********************************************************************************
+*
+*   Name:           CsrUtf16StringToUint32
+*
+*   Description:    The function converts an UTF-16 string that is
+*                   0-terminated into a 32 bit number.
+*
+*   Input:          A string of UTF-16 characters containig a number.
+*
+*   Output:         32 bit number.
+*
+*********************************************************************************/
+CsrUint32 CsrUtf16StringToUint32(const CsrUtf16String *unicodeString)
+{
+    CsrUint16 numLen, count;
+    CsrUint32 newNumber = 0;
+
+    numLen = (CsrUint16) CsrUtf16StrLen(unicodeString);
+
+    if ((numLen > 10) || (numLen == 0) || (unicodeString == NULL)) /*CSRMAX number is 4.294.967.295 */
+    {
+        return 0;
+    }
+
+    for (count = 0; count < numLen; count++)
+    {
+        CsrUtf16String input = unicodeString[count];
+        if ((input < 0x30) || (input > 0x39) || ((newNumber == 0x19999999) && (input > 0x35)) || (newNumber > 0x19999999)) /* chars are present or number is too large now causing number to get to large when *10 */
+        {
+            return 0;
+        }
+
+        newNumber = (newNumber * 10) + (input - 0x30);
+    }
+    return newNumber;
+}
+
+/********************************************************************************
+*
+*   Name:           CsrUtf16MemCpy
+*
+*   Description:    The function copies count number of 16 bit data elements
+*                   from srv to dest.
+*
+*   Input:          A pointer to an unicoded string.
+*
+*   Output:         A pointer to an unicoded string.
+*
+*********************************************************************************/
+CsrUtf16String *CsrUtf16MemCpy(CsrUtf16String *dest, const CsrUtf16String *src, CsrUint32 count)
+{
+    return CsrMemCpy((CsrUint8 *) dest, (CsrUint8 *) src, count * sizeof(CsrUtf16String));
+}
+
+/********************************************************************************
+*
+*   Name:           CsrUtf16ConcatenateTexts
+*
+*   Description:    The function merge the contents of 4 unicoded input pointers
+*                   into a new string.
+*
+*   Input:          4 unicoded input strings (UTF-16).
+*
+*   Output:         A new unicoded string (UTF-16) containing the combined strings.
+*
+*********************************************************************************/
+CsrUtf16String *CsrUtf16ConcatenateTexts(const CsrUtf16String *inputText1, const CsrUtf16String *inputText2,
+    const CsrUtf16String *inputText3, const CsrUtf16String *inputText4)
+{
+    CsrUtf16String *outputText;
+    CsrUint32 textLen, textLen1, textLen2, textLen3, textLen4;
+
+    textLen1 = CsrUtf16StrLen(inputText1);
+    textLen2 = CsrUtf16StrLen(inputText2);
+    textLen3 = CsrUtf16StrLen(inputText3);
+    textLen4 = CsrUtf16StrLen(inputText4);
+
+    textLen = textLen1 + textLen2 + textLen3 + textLen4;
+
+    if (textLen == 0) /*stop here is all lengths are 0*/
+    {
+        return NULL;
+    }
+
+    outputText = (CsrUtf16String *) CsrPmemAlloc((textLen + 1) * sizeof(CsrUtf16String)); /* add space for 0-termination*/
+
+
+    if (inputText1 != NULL)
+    {
+        CsrUtf16MemCpy(outputText, inputText1, textLen1);
+    }
+
+    if (inputText2 != NULL)
+    {
+        CsrUtf16MemCpy(&(outputText[textLen1]), inputText2, textLen2);
+    }
+
+    if (inputText3 != NULL)
+    {
+        CsrUtf16MemCpy(&(outputText[textLen1 + textLen2]), inputText3, textLen3);
+    }
+
+    if (inputText4 != NULL)
+    {
+        CsrUtf16MemCpy(&(outputText[textLen1 + textLen2 + textLen3]), inputText4, textLen4);
+    }
+
+    outputText[textLen] = '\0';
+
+    return outputText;
+}
+
+/********************************************************************************
+*
+*   Name:           CsrUtf16StrLen
+*
+*   Description:    The function returns the number of 16 bit elements present
+*                   in the 0-terminated string.
+*
+*   Input:          0-terminated string of 16 bit unicoded characters.
+*
+*   Output:         The number of 16 bit elements in the string.
+*
+*********************************************************************************/
+CsrUint32 CsrUtf16StrLen(const CsrUtf16String *unicodeString)
+{
+    CsrUint32 length;
+
+    length = 0;
+    if (unicodeString != NULL)
+    {
+        while (*unicodeString)
+        {
+            length++;
+            unicodeString++;
+        }
+    }
+    return length;
+}
+
+/********************************************************************************
+*
+*   Name:           CsrUtf16String2Utf8
+*
+*   Description:    The function decodes an UTF-16 string into an UTF8 byte
+*                   oriented string.
+*
+*   Input:          0-terminated UTF-16 string characters.
+*
+*   Output:         0-terminated string of byte oriented UTF8 coded characters.
+*
+*********************************************************************************/
+CsrUtf8String *CsrUtf16String2Utf8(const CsrUtf16String *source)
+{
+    CsrUtf8String *dest, *destStart = NULL;
+    CsrUint32 i;
+    CsrUint32 ch;
+    CsrUint32 length;
+    CsrUint32 sourceLength;
+    CsrUint8 bytes;
+    CsrBool appendNull = FALSE;
+
+    CsrUint8 firstByteMark[5] = {0x00, 0x00, 0xC0, 0xE0, 0xF0};
+
+    if (!source)
+    {
+        return NULL;
+    }
+
+    length = 0;
+    sourceLength = CsrUtf16StrLen(source) + 1;
+
+    for (i = 0; i < sourceLength; i++)
+    {
+        ch = source[i];
+        if ((ch >= UNI_SUR_HIGH_START) && (ch <= UNI_SUR_HIGH_END)) /* This is a high surrogate */
+        {
+            if (i + 1 < sourceLength) /* The low surrogate is in the source */
+            {
+                CsrUint32 ch2 = source[++i];
+                if ((ch2 >= UNI_SUR_LOW_START) && (ch2 <= UNI_SUR_LOW_END)) /* And it is a legal low surrogate */
+                {
+                    length += 4;
+                }
+                else /* It is not a low surrogate, instead put a Unicode
+                     'REPLACEMENT CHARACTER' (U+FFFD) */
+                {
+                    length += 3;
+                    i--; /* Substract 1 again as the conversion must continue after the ill-formed code unit */
+                }
+            }
+            else /* The low surrogate does not exist, instead put a Unicode
+                 'REPLACEMENT CHARACTER' (U+FFFD), and the null terminated character */
+            {
+                length += 4;
+            }
+        }
+        else if ((ch >= UNI_SUR_LOW_START) && (ch <= UNI_SUR_LOW_END)) /* The value of UTF-16 is not allowed to be in this range, instead put
+             a Unicode 'REPLACEMENT CHARACTER' (U+FFFD) */
+        {
+            length += 3;
+        }
+        else /* Figure out how many bytes that are required */
+        {
+            if (ch < 0x0080)
+            {
+                length++;
+            }
+            else if (ch < 0x0800)
+            {
+                length += 2;
+            }
+            else
+            {
+                length += 3;
+            }
+        }
+    }
+
+    dest = CsrPmemAlloc(length);
+    destStart = dest;
+
+    for (i = 0; i < sourceLength; i++)
+    {
+        ch = source[i];
+        if ((ch >= UNI_SUR_HIGH_START) && (ch <= UNI_SUR_HIGH_END)) /* This is a high surrogate */
+        {
+            if (i + 1 < sourceLength) /* The low surrogate is in the source */
+            {
+                CsrUint32 ch2 = source[++i];
+                if ((ch2 >= UNI_SUR_LOW_START) && (ch2 <= UNI_SUR_LOW_END)) /* And it is a legal low surrogate, convert to UTF-32 */
+                {
+                    ch = ((ch - UNI_SUR_HIGH_START) << UNI_HALF_SHIFT) + (ch2 - UNI_SUR_LOW_START) + UNI_HALF_BASE;
+                }
+                else /* It is not a low surrogate, instead put a Unicode
+                     'REPLACEMENT CHARACTER' (U+FFFD) */
+                {
+                    ch = UNI_REPLACEMENT_CHAR;
+                    i--; /* Substract 1 again as the conversion must continue after the ill-formed code unit */
+                }
+            }
+            else /* The low surrogate does not exist, instead put a Unicode
+                 'REPLACEMENT CHARACTER' (U+FFFD), and the null terminated character */
+            {
+                ch = UNI_REPLACEMENT_CHAR;
+                appendNull = TRUE;
+            }
+        }
+        else if ((ch >= UNI_SUR_LOW_START) && (ch <= UNI_SUR_LOW_END)) /* The value of UTF-16 is not allowed to be in this range, instead put
+             a Unicode 'REPLACEMENT CHARACTER' (U+FFFD) */
+        {
+            ch = UNI_REPLACEMENT_CHAR;
+        }
+
+        /* Figure out how many bytes that are required */
+        if (ch < (CsrUint32) 0x80)
+        {
+            bytes = 1;
+        }
+        else if (ch < (CsrUint32) 0x800)
+        {
+            bytes = 2;
+        }
+        else if (ch < (CsrUint32) 0x10000)
+        {
+            bytes = 3;
+        }
+        else if (ch < (CsrUint32) 0x110000)
+        {
+            bytes = 4;
+        }
+        else
+        {
+            bytes = 3;
+            ch = UNI_REPLACEMENT_CHAR;
+        }
+
+        dest += bytes;
+
+        switch (bytes) /* Convert character to UTF-8. Note: everything falls through. */
+        {
+            case 4:
+            {
+                *--dest = (CsrUint8) ((ch | UNI_BYTEMARK) & UNI_BYTEMASK);
+                ch >>= 6;
+            }
+            /* FALLTHROUGH */
+            case 3:
+            {
+                *--dest = (CsrUint8) ((ch | UNI_BYTEMARK) & UNI_BYTEMASK);
+                ch >>= 6;
+            }
+            /* FALLTHROUGH */
+            case 2:
+            {
+                *--dest = (CsrUint8) ((ch | UNI_BYTEMARK) & UNI_BYTEMASK);
+                ch >>= 6;
+            }
+            /* FALLTHROUGH */
+            case 1:
+            {
+                *--dest = (CsrUint8) (ch | firstByteMark[bytes]);
+            }
+            /* FALLTHROUGH */
+            default:
+            {
+                break;
+            }
+        }
+
+        dest += bytes;
+    }
+
+    if (appendNull) /* Append the \0 character */
+    {
+        *dest = '\0';
+    }
+
+    return destStart;
+}
+
+/*****************************************************************************
+
+    NAME
+        isLegalUtf8
+
+    DESCRIPTION
+        Returns TRUE if the given UFT-8 code unit is legal as defined by the
+        Unicode standard (see Chapter 3: Conformance, Section 3.9: Unicode
+        Encoding Forms, UTF-8).
+
+        This function assumes that the length parameter is unconditionally
+        correct and that the first byte is already validated by looking it up
+        in the trailingBytesForUtf8 array, which also reveals the number of
+        trailing bytes.
+
+        Legal code units are composed of one of the following byte sequences:
+
+        1st      2nd      3rd      4th
+        --------------------------------
+        00-7F
+        C2-DF    80-BF
+        E0       A0-BF    80-BF
+        E1-EC    80-BF    80-BF
+        ED       80-9F    80-BF
+        EE-EF    80-BF    80-BF
+        F0       90-BF    80-BF    80-BF
+        F1-F3    80-BF    80-BF    80-BF
+        F4       80-8F    80-BF    80-BF
+
+        Please note that this function only checks whether the 2nd, 3rd and
+        4th bytes fall into the valid ranges.
+
+    PARAMETERS
+        codeUnit - pointer to the first byte of the byte sequence composing
+            the code unit to test.
+        length - the number of bytes in the code unit. Valid range is 1 to 4.
+
+    RETURNS
+        TRUE if the given code unit is legal.
+
+*****************************************************************************/
+static CsrBool isLegalUtf8(const CsrUtf8String *codeUnit, CsrUint32 length)
+{
+    const CsrUtf8String *srcPtr = codeUnit + length;
+    CsrUint8 byte;
+
+    switch (length) /* Everything falls through except case 1 */
+    {
+        case 4:
+        {
+            byte = *--srcPtr;
+            if ((byte < 0x80) || (byte > 0xBF))
+            {
+                return FALSE;
+            }
+        }
+        /* Fallthrough */
+        case 3:
+        {
+            byte = *--srcPtr;
+            if ((byte < 0x80) || (byte > 0xBF))
+            {
+                return FALSE;
+            }
+        }
+        /* Fallthrough */
+        case 2:
+        {
+            byte = *--srcPtr;
+            if (byte > 0xBF)
+            {
+                return FALSE;
+            }
+
+            switch (*codeUnit) /* No fallthrough */
+            {
+                case 0xE0:
+                {
+                    if (byte < 0xA0)
+                    {
+                        return FALSE;
+                    }
+                    break;
+                }
+                case 0xED:
+                {
+                    if ((byte < 0x80) || (byte > 0x9F))
+                    {
+                        return FALSE;
+                    }
+                    break;
+                }
+                case 0xF0:
+                {
+                    if (byte < 0x90)
+                    {
+                        return FALSE;
+                    }
+                    break;
+                }
+                case 0xF4:
+                {
+                    if ((byte < 0x80) || (byte > 0x8F))
+                    {
+                        return FALSE;
+                    }
+                    break;
+                }
+                default:
+                {
+                    if (byte < 0x80)
+                    {
+                        return FALSE;
+                    }
+                    break;
+                }
+            }
+        }
+        /* Fallthrough */
+        case 1:
+        default:
+            /* The 1st byte and length are assumed correct */
+            break;
+    }
+
+    return TRUE;
+}
+
+/********************************************************************************
+*
+*   Name:           CsrUtf82Utf16String
+*
+*   Description:    The function decodes an UTF8 byte oriented string into a
+*                   UTF-16string.
+*
+*   Input:          0-terminated string of byte oriented UTF8 coded characters.
+*
+*   Output:         0-terminated string of UTF-16 characters.
+*
+*********************************************************************************/
+CsrUtf16String *CsrUtf82Utf16String(const CsrUtf8String *utf8String)
+{
+    CsrSize i, length = 0;
+    CsrSize sourceLength;
+    CsrUtf16String *dest = NULL;
+    CsrUtf16String *destStart = NULL;
+    CsrInt8 extraBytes2Read;
+
+    if (!utf8String)
+    {
+        return NULL;
+    }
+    sourceLength = CsrStrLen((CsrCharString *) utf8String);
+
+    for (i = 0; i < sourceLength; i++)
+    {
+        extraBytes2Read = trailingBytesForUtf8[utf8String[i]];
+
+        if (extraBytes2Read == -1) /* Illegal byte value, instead put a Unicode 'REPLACEMENT CHARACTER' (U+FFFD) */
+        {
+            length += 1;
+        }
+        else if (i + extraBytes2Read > sourceLength) /* The extra bytes does not exist, instead put a Unicode 'REPLACEMENT
+             CHARACTER' (U+FFFD), and the null terminated character */
+        {
+            length += 2;
+            break;
+        }
+        else if (isLegalUtf8(&utf8String[i], extraBytes2Read + 1) == FALSE) /* It is not a legal utf-8 character, instead put a Unicode 'REPLACEMENT
+             CHARACTER' (U+FFFD) */
+        {
+            length += 1;
+        }
+        else
+        {
+            if (utf8String[i] > 0xEF) /* Needs a high and a low surrogate */
+            {
+                length += 2;
+            }
+            else
+            {
+                length += 1;
+            }
+            i += extraBytes2Read;
+        }
+    }
+
+    /* Create space for the null terminated character */
+    dest = (CsrUtf16String *) CsrPmemAlloc((1 + length) * sizeof(CsrUtf16String));
+    destStart = dest;
+
+    for (i = 0; i < sourceLength; i++)
+    {
+        extraBytes2Read = trailingBytesForUtf8[utf8String[i]];
+
+        if (extraBytes2Read == -1) /* Illegal byte value, instead put a Unicode 'REPLACEMENT CHARACTER' (U+FFFD) */
+        {
+            *dest++ = UNI_REPLACEMENT_CHAR;
+        }
+        else if (i + extraBytes2Read > sourceLength) /* The extra bytes does not exist, instead put a Unicode 'REPLACEMENT
+             CHARACTER' (U+FFFD), and the null terminated character */
+        {
+            *dest++ = UNI_REPLACEMENT_CHAR;
+            *dest++ = '\0';
+            break;
+        }
+        else if (isLegalUtf8(&utf8String[i], extraBytes2Read + 1) == FALSE) /* It is not a legal utf-8 character, instead put a Unicode 'REPLACEMENT
+             CHARACTER' (U+FFFD) */
+        {
+            *dest++ = UNI_REPLACEMENT_CHAR;
+        }
+        else /* It is legal, convert the character to an CsrUint32 */
+        {
+            CsrUint32 ch = 0;
+
+            switch (extraBytes2Read) /* Everything falls through */
+            {
+                case 3:
+                {
+                    ch += utf8String[i];
+                    ch <<= 6;
+                    i++;
+                }
+                /* FALLTHROUGH */
+                case 2:
+                {
+                    ch += utf8String[i];
+                    ch <<= 6;
+                    i++;
+                }
+                /* FALLTHROUGH */
+                case 1:
+                {
+                    ch += utf8String[i];
+                    ch <<= 6;
+                    i++;
+                }
+                /* FALLTHROUGH */
+                case 0:
+                {
+                    ch += utf8String[i];
+                }
+                /* FALLTHROUGH */
+                default:
+                {
+                    break;
+                }
+            }
+
+            ch -= offsetsFromUtf8[extraBytes2Read];
+
+            if (ch <= 0xFFFF) /* Character can be encoded in one CsrUint16 */
+            {
+                *dest++ = (CsrUint16) ch;
+            }
+            else /* The character needs two CsrUint16 */
+            {
+                ch -= UNI_HALF_BASE;
+                *dest++ = (CsrUint16) ((ch >> UNI_HALF_SHIFT) | UNI_SUR_HIGH_START);
+                *dest++ = (CsrUint16) ((ch & 0x03FF) | UNI_SUR_LOW_START);
+            }
+        }
+    }
+
+    destStart[length] = 0x00;
+
+    return destStart;
+}
+
+/********************************************************************************
+*
+*   Name:           CsrUtf16StrCpy
+*
+*   Description:    The function copies the contents from one UTF-16 string
+*                   to another UTF-16 string.
+*
+*   Input:          0-terminated UTF-16 string.
+*
+*   Output:         0-terminated UTF-16 string.
+*
+*********************************************************************************/
+CsrUtf16String *CsrUtf16StrCpy(CsrUtf16String *target, const CsrUtf16String *source)
+{
+    if (source) /* if source is not NULL*/
+    {
+        CsrMemCpy(target, source, (CsrUtf16StrLen(source) + 1) * sizeof(CsrUtf16String));
+        return target;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+/********************************************************************************
+*
+*   Name:           CsrUtf16StringDuplicate
+*
+*   Description:    The function allocates a new pointer and copies the input to
+*                   the new pointer.
+*
+*   Input:          0-terminated UTF-16 string.
+*
+*   Output:         Allocated variable0-terminated UTF-16 string.
+*
+*********************************************************************************/
+CsrUtf16String *CsrUtf16StringDuplicate(const CsrUtf16String *source)
+{
+    CsrUtf16String *target = NULL;
+    CsrUint32 length;
+
+    if (source) /* if source is not NULL*/
+    {
+        length = (CsrUtf16StrLen(source) + 1) * sizeof(CsrUtf16String);
+        target = (CsrUtf16String *) CsrPmemAlloc(length);
+        CsrMemCpy(target, source, length);
+    }
+    return target;
+}
+
+/********************************************************************************
+*
+*   Name:           CsrUtf16StrICmp
+*
+*   Description:    The function compares two UTF-16 strings.
+*
+*   Input:          Two 0-terminated UTF-16 string.
+*
+*   Output:         0: if the strings are identical.
+*
+*********************************************************************************/
+CsrUint16 CsrUtf16StrICmp(const CsrUtf16String *string1, const CsrUtf16String *string2)
+{
+    while (*string1 || *string2)
+    {
+        if (CAPITAL(*string1) != CAPITAL(*string2))
+        {
+            return *string1 - *string2;
+        }
+        string1++;
+        string2++;
+    }
+
+    return 0;
+}
+
+/********************************************************************************
+*
+*   Name:           CsrUtf16StrNICmp
+*
+*   Description:    The function compares upto count number of elements in the
+*                   two UTF-16 string.
+*
+*   Input:          Two 0-terminated UTF-16 string and a maximum
+*                   number of elements to check.
+*
+*   Output:         0: if the strings are identical.
+*
+*********************************************************************************/
+CsrUint16 CsrUtf16StrNICmp(const CsrUtf16String *string1, const CsrUtf16String *string2, CsrUint32 count)
+{
+    while ((*string1 || *string2) && count--)
+    {
+        if (CAPITAL(*string1) != CAPITAL(*string2))
+        {
+            return *string1 - *string2;
+        }
+        string1++;
+        string2++;
+    }
+
+    return 0;
+}
+
+/********************************************************************************
+*
+*   Name:           CsrUtf16String2XML
+*
+*   Description:    The function converts an unicoded string (UTF-16) into an unicoded XML
+*                   string where some special characters are encoded according to
+*                   the XML spec.
+*
+*   Input:          A unicoded string (UTF-16) which is freed.
+*
+*   Output:         A new unicoded string (UTF-16) containing the converted output.
+*
+*********************************************************************************/
+CsrUtf16String *CsrUtf16String2XML(CsrUtf16String *str)
+{
+    CsrUtf16String *scanString;
+    CsrUtf16String *outputString = NULL;
+    CsrUtf16String *resultString = str;
+    CsrUint32 stringLength = 0;
+    CsrBool encodeChars = FALSE;
+
+    scanString = str;
+    if (scanString)
+    {
+        while (*scanString)
+        {
+            if (*scanString == L'&')
+            {
+                stringLength += 5;
+                encodeChars = TRUE;
+            }
+            else if ((*scanString == L'<') || (*scanString == L'>'))
+            {
+                stringLength += 4;
+                encodeChars = TRUE;
+            }
+            else
+            {
+                stringLength++;
+            }
+
+            scanString++;
+        }
+
+        stringLength++;
+
+        if (encodeChars)
+        {
+            resultString = outputString = CsrPmemAlloc(stringLength * sizeof(CsrUtf16String));
+
+            scanString = str;
+
+            while (*scanString)
+            {
+                if (*scanString == L'&')
+                {
+                    *outputString++ = '&';
+                    *outputString++ = 'a';
+                    *outputString++ = 'm';
+                    *outputString++ = 'p';
+                    *outputString++ = ';';
+                }
+                else if (*scanString == L'<')
+                {
+                    *outputString++ = '&';
+                    *outputString++ = 'l';
+                    *outputString++ = 't';
+                    *outputString++ = ';';
+                }
+                else if (*scanString == L'>')
+                {
+                    *outputString++ = '&';
+                    *outputString++ = 'g';
+                    *outputString++ = 't';
+                    *outputString++ = ';';
+                }
+                else
+                {
+                    *outputString++ = *scanString;
+                }
+
+                scanString++;
+            }
+
+            *outputString++ = 0;
+
+            CsrPmemFree(str);
+        }
+    }
+
+    return resultString;
+}
+
+/********************************************************************************
+*
+*   Name:           CsrXML2Utf16String
+*
+*   Description:    The function converts an unicoded XML string into an unicoded
+*                   string (UTF-16) where some special XML characters are decoded according to
+*                   the XML spec.
+*
+*   Input:          A unicoded XML string which is freed.
+*
+*   Output:         A new unicoded pointer containing the decoded output.
+*
+*********************************************************************************/
+CsrUtf16String *CsrXML2Utf16String(CsrUtf16String *str)
+{
+    CsrUtf16String *scanString;
+    CsrUtf16String *outputString = NULL;
+    CsrUtf16String *resultString = str;
+    CsrUint32 stringLength = 0;
+    CsrBool encodeChars = FALSE;
+
+    scanString = str;
+    if (scanString)
+    {
+        while (*scanString)
+        {
+            if (*scanString == (CsrUtf16String) L'&')
+            {
+                scanString++;
+
+                if (!CsrUtf16StrNICmp(scanString, (CsrUtf16String *) L"AMP;", 4))
+                {
+                    scanString += 3;
+                    encodeChars = TRUE;
+                }
+                else if (!CsrUtf16StrNICmp(scanString, (CsrUtf16String *) L"LT;", 3))
+                {
+                    scanString += 2;
+                    encodeChars = TRUE;
+                }
+                else if (!CsrUtf16StrNICmp(scanString, (CsrUtf16String *) L"GT;", 3))
+                {
+                    scanString += 2;
+                    encodeChars = TRUE;
+                }
+                if (!CsrUtf16StrNICmp(scanString, (CsrUtf16String *) L"APOS;", 5))
+                {
+                    scanString += 4;
+                    encodeChars = TRUE;
+                }
+                if (!CsrUtf16StrNICmp(scanString, (CsrUtf16String *) L"QUOT;", 5))
+                {
+                    scanString += 4;
+                    encodeChars = TRUE;
+                }
+                else
+                {
+                    scanString--;
+                }
+            }
+
+            stringLength++;
+            scanString++;
+        }
+
+        stringLength++;
+
+        if (encodeChars)
+        {
+            resultString = outputString = CsrPmemAlloc(stringLength * sizeof(CsrUtf16String));
+
+            scanString = str;
+
+            while (*scanString)
+            {
+                if (*scanString == L'&')
+                {
+                    scanString++;
+
+                    if (!CsrUtf16StrNICmp(scanString, (CsrUtf16String *) L"AMP;", 4))
+                    {
+                        *outputString++ = L'&';
+                        scanString += 3;
+                    }
+                    else if (!CsrUtf16StrNICmp(scanString, (CsrUtf16String *) L"LT;", 3))
+                    {
+                        *outputString++ = L'<';
+                        scanString += 2;
+                    }
+                    else if (!CsrUtf16StrNICmp(scanString, (CsrUtf16String *) L"GT;", 3))
+                    {
+                        *outputString++ = L'>';
+                        scanString += 2;
+                    }
+                    else if (!CsrUtf16StrNICmp(scanString, (CsrUtf16String *) L"APOS;", 5))
+                    {
+                        *outputString++ = L'\'';
+                        scanString += 4;
+                    }
+                    else if (!CsrUtf16StrNICmp(scanString, (CsrUtf16String *) L"QUOT;", 5))
+                    {
+                        *outputString++ = L'\"';
+                        scanString += 4;
+                    }
+                    else
+                    {
+                        *outputString++ = L'&';
+                        scanString--;
+                    }
+                }
+                else
+                {
+                    *outputString++ = *scanString;
+                }
+
+                scanString++;
+            }
+
+            *outputString++ = 0;
+
+            CsrPmemFree(str);
+        }
+    }
+
+    return resultString;
+}
+
+CsrInt32 CsrUtf8StrCmp(const CsrUtf8String *string1, const CsrUtf8String *string2)
+{
+    return CsrStrCmp((const CsrCharString *) string1, (const CsrCharString *) string2);
+}
+
+CsrInt32 CsrUtf8StrNCmp(const CsrUtf8String *string1, const CsrUtf8String *string2, CsrSize count)
+{
+    return CsrStrNCmp((const CsrCharString *) string1, (const CsrCharString *) string2, count);
+}
+
+CsrUint32 CsrUtf8StringLengthInBytes(const CsrUtf8String *string)
+{
+    CsrSize length = 0;
+    if (string)
+    {
+        length = CsrStrLen((const CsrCharString *) string);
+    }
+    return (CsrUint32) length;
+}
+
+CsrUtf8String *CsrUtf8StrCpy(CsrUtf8String *target, const CsrUtf8String *source)
+{
+    return (CsrUtf8String *) CsrStrCpy((CsrCharString *) target, (const CsrCharString *) source);
+}
+
+CsrUtf8String *CsrUtf8StrTruncate(CsrUtf8String *target, CsrSize count)
+{
+    CsrSize lastByte = count - 1;
+
+    target[count] = '\0';
+
+    if (count && (target[lastByte] & 0x80))
+    {
+        /* the last byte contains non-ascii char */
+        if (target[lastByte] & 0x40)
+        {
+            /* multi-byte char starting just before truncation */
+            target[lastByte] = '\0';
+        }
+        else if ((target[lastByte - 1] & 0xE0) == 0xE0)
+        {
+            /* 3-byte char starting 2 bytes before truncation */
+            target[lastByte - 1] = '\0';
+        }
+        else if ((target[lastByte - 2] & 0xF0) == 0xF0)
+        {
+            /* 4-byte char starting 3 bytes before truncation */
+            target[lastByte - 2] = '\0';
+        }
+    }
+
+    return target;
+}
+
+CsrUtf8String *CsrUtf8StrNCpy(CsrUtf8String *target, const CsrUtf8String *source, CsrSize count)
+{
+    return (CsrUtf8String *) CsrStrNCpy((CsrCharString *) target, (const CsrCharString *) source, count);
+}
+
+CsrUtf8String *CsrUtf8StrNCpyZero(CsrUtf8String *target, const CsrUtf8String *source, CsrSize count)
+{
+    CsrStrNCpy((CsrCharString *) target, (const CsrCharString *) source, count);
+    if (target[count - 1] != '\0')
+    {
+        CsrUtf8StrTruncate(target, count - 1);
+    }
+    return target;
+}
+
+CsrUtf8String *CsrUtf8StrDup(const CsrUtf8String *source)
+{
+    return (CsrUtf8String *) CsrStrDup((const CsrCharString *) source);
+}
+
+CsrUtf8String *CsrUtf8StringConcatenateTexts(const CsrUtf8String *inputText1, const CsrUtf8String *inputText2, const CsrUtf8String *inputText3, const CsrUtf8String *inputText4)
+{
+    CsrUtf8String *outputText;
+    CsrUint32 textLen, textLen1, textLen2, textLen3, textLen4;
+
+    textLen1 = CsrUtf8StringLengthInBytes(inputText1);
+    textLen2 = CsrUtf8StringLengthInBytes(inputText2);
+    textLen3 = CsrUtf8StringLengthInBytes(inputText3);
+    textLen4 = CsrUtf8StringLengthInBytes(inputText4);
+
+    textLen = textLen1 + textLen2 + textLen3 + textLen4;
+
+    if (textLen == 0) /*stop here is all lengths are 0*/
+    {
+        return NULL;
+    }
+
+    outputText = (CsrUtf8String *) CsrPmemAlloc((textLen + 1) * sizeof(CsrUtf8String)); /* add space for 0-termination*/
+
+
+    if (inputText1 != NULL)
+    {
+        CsrUtf8StrNCpy(outputText, inputText1, textLen1);
+    }
+
+    if (inputText2 != NULL)
+    {
+        CsrUtf8StrNCpy(&(outputText[textLen1]), inputText2, textLen2);
+    }
+
+    if (inputText3 != NULL)
+    {
+        CsrUtf8StrNCpy(&(outputText[textLen1 + textLen2]), inputText3, textLen3);
+    }
+
+    if (inputText4 != NULL)
+    {
+        CsrUtf8StrNCpy(&(outputText[textLen1 + textLen2 + textLen3]), inputText4, textLen4);
+    }
+
+    outputText[textLen] = '\0';
+
+    return outputText;
+}
diff --git a/drivers/staging/csr/csr_util.c b/drivers/staging/csr/csr_util.c
new file mode 100644
index 0000000..ee2d047
--- /dev/null
+++ b/drivers/staging/csr/csr_util.c
@@ -0,0 +1,443 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <stdarg.h>
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_util.h"
+
+/*------------------------------------------------------------------*/
+/* Bits */
+/*------------------------------------------------------------------*/
+
+/* Time proportional with the number of 1's */
+CsrUint8 CsrBitCountSparse(CsrUint32 n)
+{
+    CsrUint8 count = 0;
+
+    while (n)
+    {
+        count++;
+        n &= (n - 1);
+    }
+
+    return count;
+}
+
+/* Time proportional with the number of 0's */
+CsrUint8 CsrBitCountDense(CsrUint32 n)
+{
+    CsrUint8 count = 8 * sizeof(CsrUint32);
+
+    n ^= (CsrUint32) (-1);
+
+    while (n)
+    {
+        count--;
+        n &= (n - 1);
+    }
+
+    return count;
+}
+
+/*------------------------------------------------------------------*/
+/* Base conversion */
+/*------------------------------------------------------------------*/
+CsrBool CsrHexStrToUint8(const CsrCharString *string, CsrUint8 *returnValue)
+{
+    CsrUint16 currentIndex = 0;
+    *returnValue = 0;
+    if ((string[currentIndex] == '0') && (CSR_TOUPPER(string[currentIndex + 1]) == 'X'))
+    {
+        string += 2;
+    }
+    if (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F')))
+    {
+        while (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F')))
+        {
+            *returnValue = (CsrUint8) (*returnValue * 16 + (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) ? string[currentIndex] - '0' : CSR_TOUPPER(string[currentIndex]) - 'A' + 10));
+            currentIndex++;
+            if (currentIndex >= 2)
+            {
+                break;
+            }
+        }
+        return TRUE;
+    }
+    return FALSE;
+}
+
+CsrBool CsrHexStrToUint16(const CsrCharString *string, CsrUint16 *returnValue)
+{
+    CsrUint16 currentIndex = 0;
+    *returnValue = 0;
+    if ((string[currentIndex] == '0') && (CSR_TOUPPER(string[currentIndex + 1]) == 'X'))
+    {
+        string += 2;
+    }
+    if (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F')))
+    {
+        while (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F')))
+        {
+            *returnValue = (CsrUint16) (*returnValue * 16 + (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) ? string[currentIndex] - '0' : CSR_TOUPPER(string[currentIndex]) - 'A' + 10));
+            currentIndex++;
+            if (currentIndex >= 4)
+            {
+                break;
+            }
+        }
+        return TRUE;
+    }
+    return FALSE;
+}
+
+CsrBool CsrHexStrToUint32(const CsrCharString *string, CsrUint32 *returnValue)
+{
+    CsrUint16 currentIndex = 0;
+    *returnValue = 0;
+    if ((string[currentIndex] == '0') && (CSR_TOUPPER(string[currentIndex + 1]) == 'X'))
+    {
+        string += 2;
+    }
+    if (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F')))
+    {
+        while (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F')))
+        {
+            *returnValue = *returnValue * 16 + (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) ? string[currentIndex] - '0' : CSR_TOUPPER(string[currentIndex]) - 'A' + 10);
+            currentIndex++;
+            if (currentIndex >= 8)
+            {
+                break;
+            }
+        }
+        return TRUE;
+    }
+    return FALSE;
+}
+
+CsrUint32 CsrPow(CsrUint32 base, CsrUint32 exponent)
+{
+    if (exponent == 0)
+    {
+        return 1;
+    }
+    else
+    {
+        CsrUint32 i, t = base;
+
+        for (i = 1; i < exponent; i++)
+        {
+            t = t * base;
+        }
+        return t;
+    }
+}
+
+/* Convert signed 32 bit (or less) integer to string */
+#define I2B10_MAX 12
+void CsrIntToBase10(CsrInt32 number, CsrCharString *str)
+{
+    CsrInt32 digit;
+    CsrUint8 index;
+    CsrCharString res[I2B10_MAX];
+    CsrBool foundDigit = FALSE;
+
+    for (digit = 0; digit < I2B10_MAX; digit++)
+    {
+        res[digit] = '\0';
+    }
+
+    /* Catch sign - and deal with positive numbers only afterwards */
+    index = 0;
+    if (number < 0)
+    {
+        res[index++] = '-';
+        number = -1 * number;
+    }
+
+    digit = 1000000000;
+    if (number > 0)
+    {
+        while ((index < I2B10_MAX - 1) && (digit > 0))
+        {
+            /* If the foundDigit flag is TRUE, this routine should be proceeded.
+            Otherwise the number which has '0' digit cannot be converted correctly */
+            if (((number / digit) > 0) || foundDigit)
+            {
+                foundDigit = TRUE; /* set foundDigit flag to TRUE*/
+                res[index++] = (char) ('0' + (number / digit));
+                number = number % digit;
+            }
+
+            digit = digit / 10;
+        }
+    }
+    else
+    {
+        res[index] = (char) '0';
+    }
+
+    CsrStrCpy(str, res);
+}
+
+void CsrUInt16ToHex(CsrUint16 number, CsrCharString *str)
+{
+    CsrUint16 index;
+    CsrUint16 currentValue;
+
+    for (index = 0; index < 4; index++)
+    {
+        currentValue = (CsrUint16) (number & 0x000F);
+        number >>= 4;
+        str[3 - index] = (char) (currentValue > 9 ? currentValue + 55 : currentValue + '0');
+    }
+    str[4] = '\0';
+}
+
+void CsrUInt32ToHex(CsrUint32 number, CsrCharString *str)
+{
+    CsrUint16 index;
+    CsrUint32 currentValue;
+
+    for (index = 0; index < 8; index++)
+    {
+        currentValue = (CsrUint32) (number & 0x0000000F);
+        number >>= 4;
+        str[7 - index] = (char) (currentValue > 9 ? currentValue + 55 : currentValue + '0');
+    }
+    str[8] = '\0';
+}
+
+/*------------------------------------------------------------------*/
+/*  String */
+/*------------------------------------------------------------------*/
+#ifndef CSR_USE_STDC_LIB
+void *CsrMemCpy(void *dest, const void *src, CsrSize count)
+{
+    return memcpy(dest, src, count);
+}
+EXPORT_SYMBOL_GPL(CsrMemCpy);
+
+void *CsrMemSet(void *dest, CsrUint8 c, CsrSize count)
+{
+    return memset(dest, c, count);
+}
+EXPORT_SYMBOL_GPL(CsrMemSet);
+
+void *CsrMemMove(void *dest, const void *src, CsrSize count)
+{
+    return memmove(dest, src, count);
+}
+EXPORT_SYMBOL_GPL(CsrMemMove);
+
+CsrInt32 CsrMemCmp(const void *buf1, const void *buf2, CsrSize count)
+{
+    return memcmp(buf1, buf2, count);
+}
+EXPORT_SYMBOL_GPL(CsrMemCmp);
+
+void *CsrMemDup(const void *buf1, CsrSize count)
+{
+    void *buf2 = NULL;
+
+    if (buf1)
+    {
+        buf2 = CsrPmemAlloc(count);
+        CsrMemCpy(buf2, buf1, count);
+    }
+
+    return buf2;
+}
+#endif
+
+#ifndef CSR_USE_STDC_LIB
+CsrCharString *CsrStrCpy(CsrCharString *dest, const CsrCharString *src)
+{
+    return strcpy(dest, src);
+}
+
+CsrCharString *CsrStrNCpy(CsrCharString *dest, const CsrCharString *src, CsrSize count)
+{
+    return strncpy(dest, src, count);
+}
+
+CsrCharString *CsrStrCat(CsrCharString *dest, const CsrCharString *src)
+{
+    return strcat(dest, src);
+}
+
+CsrCharString *CsrStrNCat(CsrCharString *dest, const CsrCharString *src, CsrSize count)
+{
+    return strncat(dest, src, count);
+}
+
+CsrCharString *CsrStrStr(const CsrCharString *string1, const CsrCharString *string2)
+{
+    return strstr(string1, string2);
+}
+
+CsrSize CsrStrLen(const CsrCharString *string)
+{
+    return strlen(string);
+}
+EXPORT_SYMBOL_GPL(CsrStrLen);
+
+CsrInt32 CsrStrCmp(const CsrCharString *string1, const CsrCharString *string2)
+{
+    return strcmp(string1, string2);
+}
+
+CsrInt32 CsrStrNCmp(const CsrCharString *string1, const CsrCharString *string2, CsrSize count)
+{
+    return strncmp(string1, string2, count);
+}
+
+CsrCharString *CsrStrChr(const CsrCharString *string, CsrCharString c)
+{
+    return strchr(string, c);
+}
+#endif
+
+CsrInt32 CsrVsnprintf(CsrCharString *string, CsrSize count, const CsrCharString *format, va_list args)
+{
+    return vsnprintf(string, count, format, args);
+}
+EXPORT_SYMBOL_GPL(CsrVsnprintf);
+
+CsrCharString *CsrStrNCpyZero(CsrCharString *dest,
+    const CsrCharString *src,
+    CsrSize count)
+{
+    CsrStrNCpy(dest, src, count - 1);
+    dest[count - 1] = '\0';
+    return dest;
+}
+
+/* Convert string with base 10 to integer */
+CsrUint32 CsrStrToInt(const CsrCharString *str)
+{
+    CsrInt16 i;
+    CsrUint32 res;
+    CsrUint32 digit;
+
+    res = 0;
+    digit = 1;
+
+    /* Start from the string end */
+    for (i = (CsrUint16) (CsrStrLen(str) - 1); i >= 0; i--)
+    {
+        /* Only convert numbers */
+        if ((str[i] >= '0') && (str[i] <= '9'))
+        {
+            res += digit * (str[i] - '0');
+            digit = digit * 10;
+        }
+    }
+
+    return res;
+}
+
+CsrCharString *CsrStrDup(const CsrCharString *string)
+{
+    CsrCharString *copy;
+    CsrUint32 len;
+
+    copy = NULL;
+    if (string != NULL)
+    {
+        len = CsrStrLen(string) + 1;
+        copy = CsrPmemAlloc(len);
+        CsrMemCpy(copy, string, len);
+    }
+    return copy;
+}
+
+int CsrStrNICmp(const CsrCharString *string1,
+    const CsrCharString *string2,
+    CsrSize count)
+{
+    CsrUint32 index;
+    int returnValue = 0;
+
+    for (index = 0; index < count; index++)
+    {
+        if (CSR_TOUPPER(string1[index]) != CSR_TOUPPER(string2[index]))
+        {
+            if (CSR_TOUPPER(string1[index]) > CSR_TOUPPER(string2[index]))
+            {
+                returnValue = 1;
+            }
+            else
+            {
+                returnValue = -1;
+            }
+            break;
+        }
+        if (string1[index] == '\0')
+        {
+            break;
+        }
+    }
+    return returnValue;
+}
+
+const CsrCharString *CsrGetBaseName(const CsrCharString *file)
+{
+    const CsrCharString *pch;
+    static const CsrCharString dotDir[] = ".";
+
+    if (!file)
+    {
+        return NULL;
+    }
+
+    if (file[0] == '\0')
+    {
+        return dotDir;
+    }
+
+    pch = file + CsrStrLen(file) - 1;
+
+    while (*pch != '\\' && *pch != '/' && *pch != ':')
+    {
+        if (pch == file)
+        {
+            return pch;
+        }
+        --pch;
+    }
+
+    return ++pch;
+}
+
+/*------------------------------------------------------------------*/
+/* Misc */
+/*------------------------------------------------------------------*/
+CsrBool CsrIsSpace(CsrUint8 c)
+{
+    switch (c)
+    {
+        case '\t':
+        case '\n':
+        case '\f':
+        case '\r':
+        case ' ':
+            return TRUE;
+        default:
+            return FALSE;
+    }
+}
+
+MODULE_DESCRIPTION("CSR Operating System Kernel Abstraction");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/staging/csr/csr_util.h b/drivers/staging/csr/csr_util.h
new file mode 100644
index 0000000..ce39c7e
--- /dev/null
+++ b/drivers/staging/csr/csr_util.h
@@ -0,0 +1,102 @@
+#ifndef CSR_UTIL_H__
+#define CSR_UTIL_H__
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "csr_types.h"
+#include "csr_macro.h"
+
+/*------------------------------------------------------------------*/
+/* Bits - intended to operate on CsrUint32 values */
+/*------------------------------------------------------------------*/
+CsrUint8 CsrBitCountSparse(CsrUint32 n);
+CsrUint8 CsrBitCountDense(CsrUint32 n);
+
+/*------------------------------------------------------------------*/
+/* Base conversion */
+/*------------------------------------------------------------------*/
+CsrBool CsrHexStrToUint8(const CsrCharString *string, CsrUint8 *returnValue);
+CsrBool CsrHexStrToUint16(const CsrCharString *string, CsrUint16 *returnValue);
+CsrBool CsrHexStrToUint32(const CsrCharString *string, CsrUint32 *returnValue);
+CsrUint32 CsrPow(CsrUint32 base, CsrUint32 exponent);
+void CsrIntToBase10(CsrInt32 number, CsrCharString *str);
+void CsrUInt16ToHex(CsrUint16 number, CsrCharString *str);
+void CsrUInt32ToHex(CsrUint32 number, CsrCharString *str);
+
+/*------------------------------------------------------------------*/
+/* Standard C Library functions */
+/*------------------------------------------------------------------*/
+#ifdef CSR_USE_STDC_LIB
+#define CsrMemCpy memcpy
+#define CsrMemMove memmove
+#define CsrStrCpy strcpy
+#define CsrStrNCpy strncpy
+#define CsrStrCat strcat
+#define CsrStrNCat strncat
+#define CsrMemCmp(s1, s2, n) ((CsrInt32) memcmp((s1), (s2), (n)))
+#define CsrStrCmp(s1, s2) ((CsrInt32) strcmp((s1), (s2)))
+#define CsrStrNCmp(s1, s2, n) ((CsrInt32) strncmp((s1), (s2), (n)))
+/*#define CsrMemChr memchr*/
+#define CsrStrChr strchr
+/*#define CsrStrCSpn strcspn*/
+/*#define CsrStrPBrk strpbrk*/
+/*#define CsrStrRChr strrchr*/
+/*#define CsrStrSpn strspn*/
+#define CsrStrStr strstr
+/*#define CsrStrTok strtok*/
+#define CsrMemSet memset
+#define CsrStrLen strlen
+/*#define CsrVsnprintf(s, n, format, arg) ((CsrInt32) vsnprintf((s), (n), (format), (arg)))*/
+#else /* !CSR_USE_STDC_LIB */
+void *CsrMemCpy(void *dest, const void *src, CsrSize count);
+void *CsrMemMove(void *dest, const void *src, CsrSize count);
+CsrCharString *CsrStrCpy(CsrCharString *dest, const CsrCharString *src);
+CsrCharString *CsrStrNCpy(CsrCharString *dest, const CsrCharString *src, CsrSize count);
+CsrCharString *CsrStrCat(CsrCharString *dest, const CsrCharString *src);
+CsrCharString *CsrStrNCat(CsrCharString *dest, const CsrCharString *src, CsrSize count);
+CsrInt32 CsrMemCmp(const void *buf1, const void *buf2, CsrSize count);
+CsrInt32 CsrStrCmp(const CsrCharString *string1, const CsrCharString *string2);
+CsrInt32 CsrStrNCmp(const CsrCharString *string1, const CsrCharString *string2, CsrSize count);
+CsrCharString *CsrStrChr(const CsrCharString *string, CsrCharString c);
+CsrCharString *CsrStrStr(const CsrCharString *string1, const CsrCharString *string2);
+void *CsrMemSet(void *dest, CsrUint8 c, CsrSize count);
+CsrSize CsrStrLen(const CsrCharString *string);
+#endif /* !CSR_USE_STDC_LIB */
+CsrInt32 CsrVsnprintf(CsrCharString *string, CsrSize count, const CsrCharString *format, va_list args);
+
+/*------------------------------------------------------------------*/
+/* Non-standard utility functions */
+/*------------------------------------------------------------------*/
+void *CsrMemDup(const void *buf1, CsrSize count);
+int CsrStrNICmp(const CsrCharString *string1, const CsrCharString *string2, CsrSize count);
+CsrCharString *CsrStrDup(const CsrCharString *string);
+CsrUint32 CsrStrToInt(const CsrCharString *string);
+CsrCharString *CsrStrNCpyZero(CsrCharString *dest, const CsrCharString *src, CsrSize count);
+
+/*------------------------------------------------------------------*/
+/* Filename */
+/*------------------------------------------------------------------*/
+const CsrCharString *CsrGetBaseName(const CsrCharString *file);
+
+/*------------------------------------------------------------------*/
+/* Misc */
+/*------------------------------------------------------------------*/
+CsrBool CsrIsSpace(CsrUint8 c);
+#define CsrOffsetOf(st, m)  ((CsrSize) & ((st *) 0)->m)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_wifi_common.h b/drivers/staging/csr/csr_wifi_common.h
new file mode 100644
index 0000000..442dcc6
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_common.h
@@ -0,0 +1,109 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifndef CSR_WIFI_COMMON_H__
+#define CSR_WIFI_COMMON_H__
+
+#include "csr_types.h"
+#include "csr_result.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* MAC address */
+typedef struct
+{
+    CsrUint8 a[6];
+} CsrWifiMacAddress;
+
+/* IPv4 address */
+typedef struct
+{
+    CsrUint8 a[4];
+} CsrWifiIp4Address;
+
+/* IPv6 address */
+typedef struct
+{
+    CsrUint8 a[16];
+} CsrWifiIp6Address;
+
+typedef struct
+{
+    CsrUint8 ssid[32];
+    CsrUint8 length;
+} CsrWifiSsid;
+
+/*******************************************************************************
+
+  DESCRIPTION
+    Result values used on the Wifi Interfaces
+
+ VALUES
+    CSR_RESULT_SUCCESS
+                   - The request/procedure succeeded
+    CSR_RESULT_FAILURE
+                   - The request/procedure did not succeed because of an error
+    CSR_WIFI_RESULT_NOT_FOUND
+                   - The request did not succeed because some resource was not
+                     found.
+    CSR_WIFI_RESULT_TIMED_OUT
+                   - The request/procedure did not succeed because of a time out
+    CSR_WIFI_RESULT_CANCELLED
+                   - The request was canceled due to another conflicting
+                     request that was issued before this one was completed
+    CSR_WIFI_RESULT_INVALID_PARAMETER
+                   - The request/procedure did not succeed because it had an
+                     invalid parameter
+    CSR_WIFI_RESULT_NO_ROOM
+                   - The request did not succeed due to a lack of resources,
+                     e.g. out of memory problem.
+    CSR_WIFI_RESULT_UNSUPPORTED
+                   - The request/procedure did not succeed because the feature
+                     is not supported yet
+    CSR_WIFI_RESULT_UNAVAILABLE
+                   - The request cannot be processed at this time
+    CSR_WIFI_RESULT_WIFI_OFF
+                   - The requested action is not available because Wi-Fi is
+                     currently off
+    CSR_WIFI_RESULT_SECURITY_ERROR
+                   - The request/procedure did not succeed because of a security
+                     error
+    CSR_WIFI_RESULT_MIB_SET_FAILURE
+                   - MIB Set Failure: either the MIB OID to be written to does
+                     not exist or the MIB Value is invalid.
+    CSR_WIFI_RESULT_INVALID_INTERFACE_TAG
+                   - The supplied Interface Tag is not valid.
+    CSR_WIFI_RESULT_P2P_NOA_CONFIG_CONFLICT
+                   - The new NOA configuration conflicts with the existing NOA configuration
+                     hence not accepted"
+*******************************************************************************/
+#define CSR_WIFI_RESULT_NOT_FOUND                 ((CsrResult) 0x0001)
+#define CSR_WIFI_RESULT_TIMED_OUT                 ((CsrResult) 0x0002)
+#define CSR_WIFI_RESULT_CANCELLED                 ((CsrResult) 0x0003)
+#define CSR_WIFI_RESULT_INVALID_PARAMETER         ((CsrResult) 0x0004)
+#define CSR_WIFI_RESULT_NO_ROOM                   ((CsrResult) 0x0005)
+#define CSR_WIFI_RESULT_UNSUPPORTED               ((CsrResult) 0x0006)
+#define CSR_WIFI_RESULT_UNAVAILABLE               ((CsrResult) 0x0007)
+#define CSR_WIFI_RESULT_WIFI_OFF                  ((CsrResult) 0x0008)
+#define CSR_WIFI_RESULT_SECURITY_ERROR            ((CsrResult) 0x0009)
+#define CSR_WIFI_RESULT_MIB_SET_FAILURE           ((CsrResult) 0x000A)
+#define CSR_WIFI_RESULT_INVALID_INTERFACE_TAG     ((CsrResult) 0x000B)
+#define CSR_WIFI_RESULT_P2P_NOA_CONFIG_CONFLICT   ((CsrResult) 0x000C)
+
+#define CSR_WIFI_VERSION	"5.1.0.0"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/drivers/staging/csr/csr_wifi_fsm.h b/drivers/staging/csr/csr_wifi_fsm.h
new file mode 100644
index 0000000..cfdf082
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_fsm.h
@@ -0,0 +1,250 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifndef CSR_WIFI_FSM_H
+#define CSR_WIFI_FSM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_prim_defs.h"
+#include "csr_log_text.h"
+#include "csr_wifi_fsm_event.h"
+
+/* including this file for CsrWifiInterfaceMode*/
+#include "csr_wifi_common.h"
+
+#define CSR_WIFI_FSM_ENV       (0xFFFF)
+
+/**
+ * @brief
+ *   Toplevel FSM context data
+ *
+ * @par Description
+ *   Holds ALL FSM static and dynamic data for a FSM
+ */
+typedef struct CsrWifiFsmContext CsrWifiFsmContext;
+
+/**
+ * @brief
+ *   FSM External Wakeup CallbackFunction Pointer
+ *
+ * @par Description
+ *   Defines the external wakeup function for the FSM
+ *   to call when an external event is injected into the systen
+ *
+ * @param[in]    context : External context
+ *
+ * @return
+ *   void
+ */
+typedef void (*CsrWifiFsmExternalWakupCallbackPtr)(void *context);
+
+/**
+ * @brief
+ *   Initialises a top level FSM context
+ *
+ * @par Description
+ *   Initialises the FSM Context to an initial state and allocates
+ *   space for "maxProcesses" number of instances
+ *
+ * @param[in]    osaContext         : OSA context
+ * @param[in]    applicationContext : Internal fsm application context
+ * @param[in]    externalContext    : External context
+ * @param[in]    maxProcesses       : Max processes to allocate room for
+ *
+ * @return
+ *   CsrWifiFsmContext* fsm context
+ */
+extern CsrWifiFsmContext* CsrWifiFsmInit(void *applicationContext, void *externalContext, CsrUint16 maxProcesses, CsrLogTextTaskId loggingTaskId);
+
+/**
+ * @brief
+ *   Resets the FSM's back to first conditions
+ *
+ * @par Description
+ *   This function is used to free any dynamic resources allocated for the
+ *   given context by CsrWifiFsmInit().
+ *   The FSM's reset function is called to cleanup any fsm specific memory
+ *   The reset funtion does NOT need to free the fsm data pointer as
+ *   CsrWifiFsmShutdown() will do it.
+ *   the FSM's init function is call again to reinitialise the FSM context.
+ *   CsrWifiFsmReset() should NEVER be called when CsrWifiFsmExecute() is running.
+ *
+ * @param[in]    context    : FSM context
+ *
+ * @return
+ *   void
+ */
+extern void CsrWifiFsmReset(CsrWifiFsmContext *context);
+
+/**
+ * @brief
+ *   Frees resources allocated by CsrWifiFsmInit
+ *
+ * @par Description
+ *   This function is used to free any dynamic resources allocated for the
+ *   given context by CsrWifiFsmInit(), prior to complete termination of
+ *   the program.
+ *   The FSM's reset function is called to cleanup any fsm specific memory.
+ *   The reset funtion does NOT need to free the fsm data pointer as
+ *   CsrWifiFsmShutdown() will do it.
+ *   CsrWifiFsmShutdown() should NEVER be called when CsrWifiFsmExecute() is running.
+ *
+ * @param[in]    context       : FSM context
+ *
+ * @return
+ *   void
+ */
+extern void CsrWifiFsmShutdown(CsrWifiFsmContext *context);
+
+/**
+ * @brief
+ *   Executes the fsm context
+ *
+ * @par Description
+ *   Executes the FSM context and runs until ALL events in the context are processed.
+ *   When no more events are left to process then CsrWifiFsmExecute() returns to a time
+ *   specifying when to next call the CsrWifiFsmExecute()
+ *   Scheduling, threading, blocking and external event notification are outside
+ *   the scope of the FSM and CsrWifiFsmExecute().
+ *
+ * @param[in]    context  : FSM context
+ *
+ * @return
+ *   CsrUint32    Time in ms until next timeout or 0xFFFFFFFF for no timer set
+ */
+extern CsrUint32 CsrWifiFsmExecute(CsrWifiFsmContext *context);
+
+/**
+ * @brief
+ *   Adds an event to the FSM context's external event queue for processing
+ *
+ * @par Description
+ *   Adds an event to the contexts external queue
+ *   This is thread safe and adds an event to the fsm's external event queue.
+ *
+ * @param[in]    context      : FSM context
+ * @param[in]    event        : event to add to the event queue
+ * @param[in]    source       : source of the event (this can be a synergy task queue or an fsm instance id)
+ * @param[in]    destination  : destination of the event (This can be a fsm instance id or CSR_WIFI_FSM_ENV)
+ * @param[in]    id           : event id
+ *
+ * @return
+ *   void
+ */
+extern void CsrWifiFsmSendEventExternal(CsrWifiFsmContext *context, CsrWifiFsmEvent *event, CsrUint16 source, CsrUint16 destination, CsrPrim primtype, CsrUint16 id);
+
+/**
+ * @brief
+ *   Adds an Alien event to the FSM context's external event queue for processing
+ *
+ * @par Description
+ *   Adds an event to the contexts external queue
+ *   This is thread safe and adds an event to the fsm's external event queue.
+ *
+ * @param[in]    context      : FSM context
+ * @param[in]    event        : event to add to the event queue
+ * @param[in]    source       : source of the event (this can be a synergy task queue or an fsm instance id)
+ * @param[in]    destination  : destination of the event (This can be a fsm instance id or CSR_WIFI_FSM_ENV)
+ * @param[in]    id           : event id
+ */
+#define CsrWifiFsmSendAlienEventExternal(_context, _alienEvent, _source, _destination, _primtype, _id) \
+    { \
+        CsrWifiFsmAlienEvent *_evt = (CsrWifiFsmAlienEvent *)CsrPmemAlloc(sizeof(CsrWifiFsmAlienEvent)); \
+        _evt->alienEvent = _alienEvent; \
+        CsrWifiFsmSendEventExternal(_context, (CsrWifiFsmEvent *)_evt, _source, _destination, _primtype, _id); \
+    }
+
+
+/**
+ * @brief
+ *   Current time of day in ms
+ *
+ * @param[in]    context   : FSM context
+ *
+ * @return
+ *   CsrUint32 32 bit ms tick
+ */
+extern CsrUint32 CsrWifiFsmGetTimeOfDayMs(CsrWifiFsmContext *context);
+
+/**
+ * @brief
+ *   Gets the time until the next FSM timer expiry
+ *
+ * @par Description
+ *   Returns the next timeout time or 0 if no timers are set.
+ *
+ * @param[in]    context    : FSM context
+ *
+ * @return
+ *   CsrUint32    Time in ms until next timeout or 0xFFFFFFFF for no timer set
+ */
+extern CsrUint32 CsrWifiFsmGetNextTimeout(CsrWifiFsmContext *context);
+
+/**
+ * @brief
+ *   Fast forwards the fsm timers by ms Milliseconds
+ *
+ * @param[in]  context : FSM context
+ * @param[in]  ms      : Milliseconds to fast forward by
+ *
+ * @return
+ *   void
+ */
+extern void CsrWifiFsmFastForward(CsrWifiFsmContext *context, CsrUint16 ms);
+
+/**
+ * @brief
+ *   shift the current time of day by ms amount
+ *
+ * @par Description
+ *   usefull to speed up tests where time needs to pass
+ *
+ * @param[in]    context  : FSM context
+ * @param[in]    ms       : ms to adjust time by
+ *
+ * @return
+ *   void
+ */
+extern void CsrWifiFsmTestAdvanceTime(CsrWifiFsmContext *context, CsrUint32 ms);
+
+/**
+ * @brief
+ *    Check if the fsm has events to process
+ *
+ * @param[in]    context    : FSM context
+ *
+ * @return
+ *   CsrBool returns TRUE if there are events for the FSM to process
+ */
+extern CsrBool CsrWifiFsmHasEvents(CsrWifiFsmContext *context);
+
+/**
+ * @brief
+ *   function that installs the contexts wakeup function
+ *
+ * @param[in]    context    : FSM context
+ * @param[in]    callback   : Callback function pointer
+ *
+ * @return
+ *   void
+ */
+extern void CsrWifiFsmInstallWakeupCallback(CsrWifiFsmContext *context, CsrWifiFsmExternalWakupCallbackPtr callback);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_FSM_H */
+
diff --git a/drivers/staging/csr/csr_wifi_fsm_event.h b/drivers/staging/csr/csr_wifi_fsm_event.h
new file mode 100644
index 0000000..ef07d8a
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_fsm_event.h
@@ -0,0 +1,51 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifndef CSR_WIFI_FSM_EVENT_H
+#define CSR_WIFI_FSM_EVENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "csr_types.h"
+#include "csr_prim_defs.h"
+#include "csr_sched.h"
+
+/**
+ * @brief
+ *   FSM event header.
+ *
+ * @par Description
+ *   All events MUST have this struct as the FIRST member.
+ *   The next member is used internally for linked lists
+ */
+typedef struct CsrWifiFsmEvent
+{
+    CsrPrim     type;
+    CsrUint16   primtype;
+    CsrSchedQid destination;
+    CsrSchedQid source;
+
+    /* Private pointer to allow an optimal Event list */
+    /* NOTE: Ignore this pointer.
+     *       Do not waste code initializing OR freeing it.
+     *       The pointer is used internally in the CsrWifiFsm code
+     *       to avoid a second malloc when queuing events.
+     */
+    struct CsrWifiFsmEvent *next;
+} CsrWifiFsmEvent;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_FSM_EVENT_H */
+
diff --git a/drivers/staging/csr/csr_wifi_fsm_types.h b/drivers/staging/csr/csr_wifi_fsm_types.h
new file mode 100644
index 0000000..7c611e3
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_fsm_types.h
@@ -0,0 +1,441 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifndef CSR_WIFI_FSM_TYPES_H
+#define CSR_WIFI_FSM_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "csr_types.h"
+#include "csr_util.h"
+#include "csr_pmem.h"
+#include "csr_panic.h"
+#include "csr_sched.h"
+
+#ifdef CSR_WIFI_FSM_MUTEX_ENABLE
+#include "csr_framework_ext.h"
+#endif
+
+#include "csr_wifi_fsm.h"
+
+#define CSR_WIFI_FSM_MAX_TRANSITION_HISTORY 10
+
+/**
+ * @brief
+ *   FSM event list header.
+ *
+ * @par Description
+ *   Singly linked list of events.
+ */
+typedef struct CsrWifiFsmEventList
+{
+    CsrWifiFsmEvent *first;
+    CsrWifiFsmEvent *last;
+} CsrWifiFsmEventList;
+
+
+/**
+ * @brief
+ *   FSM timer id.
+ *
+ * @par Description
+ *   Composite Id made up of the type, dest and a unique id so
+ *   CsrWifiFsmRemoveTimer knows where to look when removing the timer
+ */
+typedef struct CsrWifiFsmTimerId
+{
+    CsrPrim     type;
+    CsrUint16   primtype;
+    CsrSchedQid destination;
+    CsrUint16   uniqueid;
+} CsrWifiFsmTimerId;
+
+/**
+ * @brief
+ *   FSM timer header.
+ *
+ * @par Description
+ *   All timer MUST have this struct as the FIRST member.
+ *   The first members of the structure MUST remain compatable
+ *   with the CsrWifiFsmEvent so that timers are just specialised events
+ */
+typedef struct CsrWifiFsmTimer
+{
+    CsrPrim     type;
+    CsrUint16   primtype;
+    CsrSchedQid destination;
+    CsrSchedQid source;
+
+    /* Private pointer to allow an optimal Event list */
+    struct CsrWifiFsmTimer *next;
+
+    CsrWifiFsmTimerId timerid;
+    CsrUint32         timeoutTimeMs;
+} CsrWifiFsmTimer;
+
+
+/**
+ * @brief
+ *   Fsm Alien Event
+ *
+ * @par Description
+ *   Allows the wrapping of alien events that do not use CsrWifiFsmEvent
+ *   as the first member of the Event struct
+ */
+typedef struct
+{
+    CsrWifiFsmEvent event;
+    void           *alienEvent;
+} CsrWifiFsmAlienEvent;
+
+
+/**
+ * @brief
+ *   FSM timer list header.
+ *
+ * @par Description
+ *   Singly linked list of timers.
+ */
+typedef struct CsrWifiFsmTimerList
+{
+    CsrWifiFsmTimer *first;
+    CsrWifiFsmTimer *last;
+    CsrUint16        nexttimerid;
+} CsrWifiFsmTimerList;
+
+/**
+ * @brief
+ *   Process Entry Function Pointer
+ *
+ * @par Description
+ *   Defines the entry function for a processes.
+ *   Called at process initialisation.
+ *
+ * @param[in]    context : FSM context
+ *
+ * @return
+ *   void
+ */
+typedef void (*CsrWifiFsmProcEntryFnPtr)(CsrWifiFsmContext *context);
+
+/**
+ * @brief
+ *   Process Transition Function Pointer
+ *
+ * @par Description
+ *   Defines a transition function for a processes.
+ *   Called when an event causes a transition on a process
+ *
+ * @param[in]    CsrWifiFsmContext* : FSM context
+ * @param[in]    void* : FSM data (can be NULL)
+ * @param[in]    const CsrWifiFsmEvent*  : event to process
+ *
+ * @return
+ *   void
+ */
+typedef void (*CsrWifiFsmTransitionFnPtr)(CsrWifiFsmContext *context, void *fsmData, const CsrWifiFsmEvent *event);
+
+/**
+ * @brief
+ *   Process reset/shutdown Function Pointer
+ *
+ * @par Description
+ *   Defines the reset/shutdown function for a processes.
+ *   Called to reset or shutdown an fsm.
+ *
+ * @param[in]    context      : FSM context
+ *
+ * @return
+ *   void
+ */
+typedef void (*CsrWifiFsmProcResetFnPtr)(CsrWifiFsmContext *context);
+
+/**
+ * @brief
+ *   FSM Default Destination CallbackFunction Pointer
+ *
+ * @par Description
+ *   Defines the default destination function for the FSM
+ *   to call when an event does not have a valid destination.
+ *   This
+ *
+ * @param[in]    context : External context
+ *
+ * @return
+ *   CsrUint16 a valid destination OR CSR_WIFI_FSM_ENV
+ */
+typedef CsrUint16 (*CsrWifiFsmDestLookupCallbackPtr)(void *context, const CsrWifiFsmEvent *event);
+
+
+#ifdef CSR_WIFI_FSM_DUMP_ENABLE
+/**
+ * @brief
+ *   Trace Dump Function Pointer
+ *
+ * @par Description
+ *   Called when we want to trace the FSM
+ *
+ * @param[in]    context : FSM context
+ * @param[in]    id      : fsm id
+ *
+ * @return
+ *   void
+ */
+typedef void (*CsrWifiFsmDumpFnPtr)(CsrWifiFsmContext *context, void *fsmData);
+#endif
+
+/**
+ * @brief
+ *   Event ID to transition function entry
+ *
+ * @par Description
+ *   Event ID to Transition Entry in a state table.
+ */
+typedef struct
+{
+    CsrUint32                 eventid;
+    CsrWifiFsmTransitionFnPtr transition;
+#ifdef CSR_LOG_ENABLE
+    const CsrCharString *transitionName;
+#endif
+} CsrWifiFsmEventEntry;
+
+/**
+ * @brief
+ *   Single State's Transition Table
+ *
+ * @par Description
+ *   Stores Data for a single State's event to
+ *   transition functions mapping
+ */
+typedef struct
+{
+    const CsrUint8              numEntries;
+    const CsrBool               saveAll;
+    const CsrWifiFsmEventEntry *eventEntryArray; /* array of transition function pointers for state */
+#ifdef CSR_LOG_ENABLE
+    CsrUint16            stateNumber;
+    const CsrCharString *stateName;
+#endif
+} CsrWifiFsmTableEntry;
+
+/**
+ * @brief
+ *   Process State Transtion table
+ *
+ * @par Description
+ *   Stores Data for a processes State to transition table
+ */
+typedef struct
+{
+    CsrUint16                   numStates;         /* number of states    */
+    const CsrWifiFsmTableEntry *aStateEventMatrix; /* state event matrix  */
+} CsrWifiFsmTransitionFunctionTable;
+
+/**
+ * @brief
+ *   Const Process definition
+ *
+ * @par Description
+ *   Constant process specification.
+ *   This is ALL the non dynamic data that defines
+ *   a process.
+ */
+typedef struct
+{
+    const CsrCharString                    *processName;
+    const CsrUint32                         processId;
+    const CsrWifiFsmTransitionFunctionTable transitionTable;
+    const CsrWifiFsmTableEntry              unhandledTransitions;
+    const CsrWifiFsmTableEntry              ignoreFunctions;
+    const CsrWifiFsmProcEntryFnPtr          entryFn;
+    const CsrWifiFsmProcResetFnPtr          resetFn;
+#ifdef CSR_WIFI_FSM_DUMP_ENABLE
+    const CsrWifiFsmDumpFnPtr dumpFn;               /* Called to dump fsm specific trace if not NULL */
+#endif
+} CsrWifiFsmProcessStateMachine;
+
+#ifdef CSR_WIFI_FSM_DUMP_ENABLE
+/**
+ * @brief
+ *   Storage for state transition info
+ */
+typedef struct
+{
+    CsrUint16                 transitionNumber;
+    CsrWifiFsmEvent           event;
+    CsrUint16                 fromState;
+    CsrUint16                 toState;
+    CsrWifiFsmTransitionFnPtr transitionFn;
+    CsrUint16                 transitionCount; /* number consecutive of times this transition was seen */
+#ifdef CSR_LOG_ENABLE
+    const CsrCharString *transitionName;
+#endif
+} CsrWifiFsmTransitionRecord;
+
+/**
+ * @brief
+ *   Storage for the last state X transitions
+ */
+typedef struct
+{
+    CsrUint16                  numTransitions;
+    CsrWifiFsmTransitionRecord records[CSR_WIFI_FSM_MAX_TRANSITION_HISTORY];
+} CsrWifiFsmTransitionRecords;
+#endif
+
+/**
+ * @brief
+ *   Dynamic Process data
+ *
+ * @par Description
+ *   Dynamic process data that is used to keep track of the
+ *   state and data for a process instance
+ */
+typedef struct
+{
+    const CsrWifiFsmProcessStateMachine *fsmInfo;         /* state machine info that is constant regardless of context */
+    CsrUint16                            instanceId;      /* Runtime process id */
+    CsrUint16                            state;           /* Current state */
+    void                                *params;          /* Instance user data */
+    CsrWifiFsmEventList                  savedEventQueue; /* The saved event queue */
+    struct CsrWifiFsmInstanceEntry      *subFsm;          /* Sub Fsm instance data */
+    struct CsrWifiFsmInstanceEntry      *subFsmCaller;    /* The Fsm instance that created the SubFsm and should be used for callbacks*/
+#ifdef CSR_WIFI_FSM_DUMP_ENABLE
+    CsrWifiFsmTransitionRecords transitionRecords;        /* Last X transitions in the FSM */
+#endif
+} CsrWifiFsmInstanceEntry;
+
+/**
+ * @brief
+ *   OnCreate Callback Function Pointer
+ *
+ * @par Description
+ *   Called when an fsm is created.
+ *
+ * @param[in]    extContext : External context
+ * @param[in]    instance : FSM instance
+ *
+ * @return
+ *   void
+ */
+typedef void (*CsrWifiFsmOnCreateFnPtr)(void *extContext, const CsrWifiFsmInstanceEntry *instance);
+
+/**
+ * @brief
+ *   OnTransition Callback Function Pointer
+ *
+ * @par Description
+ *   Called when an event is processed by a fsm
+ *
+ * @param[in]    extContext : External context
+ * @param[in]    eventEntryArray : Entry data
+ * @param[in]    event : Event
+ *
+ * @return
+ *   void
+ */
+typedef void (*CsrWifiFsmOnTransitionFnPtr)(void *extContext, const CsrWifiFsmEventEntry *eventEntryArray, const CsrWifiFsmEvent *event);
+
+/**
+ * @brief
+ *   OnStateChange Callback Function Pointer
+ *
+ * @par Description
+ *   Called when CsrWifiFsmNextState is called
+ *
+ * @param[in]    extContext : External context
+ *
+ * @return
+ *   void
+ */
+typedef void (*CsrWifiFsmOnStateChangeFnPtr)(void *extContext, CsrUint16 nextstate);
+
+/**
+ * @brief
+ *   OnIgnore,OnError or OnInvalid Callback Function Pointer
+ *
+ * @par Description
+ *   Called when an event is processed by a fsm
+ *
+ * @param[in]    extContext : External context
+ * @param[in]    event : Event
+ *
+ * @return
+ *   void
+ */
+typedef void (*CsrWifiFsmOnEventFnPtr)(void *extContext, const CsrWifiFsmEvent *event);
+
+/**
+ * @brief
+ *   Toplevel FSM context data
+ *
+ * @par Description
+ *   Holds ALL FSM static and dynamic data for a FSM
+ */
+struct CsrWifiFsmContext
+{
+    CsrWifiFsmEventList eventQueue;                           /* The internal event queue                     */
+    CsrWifiFsmEventList externalEventQueue;                   /* The external event queue                     */
+#ifdef CSR_WIFI_FSM_MUTEX_ENABLE
+    CsrMutexHandle externalEventQueueLock;                    /* The external event queue mutex               */
+#endif
+    CsrUint32                          timeOffset;            /* Amount to adjust the TimeOfDayMs by          */
+    CsrWifiFsmTimerList                timerQueue;            /* The internal timer queue                     */
+    CsrBool                            useTempSaveList;       /* Should the temp save list be used            */
+    CsrWifiFsmEventList                tempSaveList;          /* The temp save event queue                    */
+    CsrWifiFsmEvent                   *eventForwardedOrSaved; /* The event that was forwarded or Saved        */
+    CsrUint16                          maxProcesses;          /* Size of instanceArray                        */
+    CsrUint16                          numProcesses;          /* Current number allocated in instanceArray    */
+    CsrWifiFsmInstanceEntry           *instanceArray;         /* Array of processes for this component        */
+    CsrWifiFsmInstanceEntry           *ownerInstance;         /* The Process that owns currentInstance (SubFsm support) */
+    CsrWifiFsmInstanceEntry           *currentInstance;       /* Current Process that is executing            */
+    CsrWifiFsmExternalWakupCallbackPtr externalEventFn;       /* External event Callback                      */
+    CsrWifiFsmOnEventFnPtr             appIgnoreCallback;     /* Application Ignore event Callback            */
+    CsrWifiFsmDestLookupCallbackPtr    appEvtDstCallback;     /* Application Lookup event Destination Function*/
+
+    void            *applicationContext;                      /* Internal fsm application context             */
+    void            *externalContext;                         /* External context (set by the user of the fsm)*/
+    CsrLogTextTaskId loggingTaskId;                           /* Task Id to use in any logging output         */
+
+#ifndef CSR_WIFI_FSM_SCHEDULER_DISABLED
+    CsrSchedTid schedTimerId;                                 /* Scheduler TimerId for use in Scheduler Tasks */
+    CsrUint32   schedTimerNexttimeoutMs;                      /* Next timeout time for the current timer      */
+#endif
+
+#ifdef CSR_WIFI_FSM_MUTEX_ENABLE
+#ifdef CSR_WIFI_FSM_TRANSITION_LOCK
+    CsrMutexHandle transitionLock;                     /* Lock when calling transition functions        */
+#endif
+#endif
+
+#ifdef CSR_LOG_ENABLE
+    CsrWifiFsmOnCreateFnPtr      onCreate;             /* Debug Transition Callback                    */
+    CsrWifiFsmOnTransitionFnPtr  onTransition;         /* Debug Transition Callback                    */
+    CsrWifiFsmOnTransitionFnPtr  onUnhandedCallback;   /* Unhanded event Callback                      */
+    CsrWifiFsmOnStateChangeFnPtr onStateChange;        /* Debug State Change Callback                  */
+    CsrWifiFsmOnEventFnPtr       onIgnoreCallback;     /* Ignore event Callback                        */
+    CsrWifiFsmOnEventFnPtr       onSaveCallback;       /* Save event Callback                          */
+    CsrWifiFsmOnEventFnPtr       onErrorCallback;      /* Error event Callback                         */
+    CsrWifiFsmOnEventFnPtr       onInvalidCallback;    /* Invalid event Callback                       */
+#endif
+#ifdef CSR_WIFI_FSM_DUMP_ENABLE
+    CsrUint16 masterTransitionNumber;                  /* Increments on every transition              */
+#endif
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_FSM_TYPES_H */
diff --git a/drivers/staging/csr/csr_wifi_hip_card.h b/drivers/staging/csr/csr_wifi_hip_card.h
new file mode 100644
index 0000000..2ab4784
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_card.h
@@ -0,0 +1,123 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ ******************************************************************************
+ * FILE : csr_wifi_hip_card.h
+ *
+ * PURPOSE : Defines abstract interface for hardware specific functions.
+ *           Note, this is a different file from one of the same name in the
+ *           Windows driver.
+ *
+ *****************************************************************************
+ */
+#ifndef __CARD_H__
+#define __CARD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "csr_wifi_hip_card_sdio.h"
+#include "csr_wifi_hip_signals.h"
+#include "csr_wifi_hip_unifi_udi.h"
+
+
+/*****************************************************************************
+ * CardEnableInt -
+ */
+CsrResult CardEnableInt(card_t *card);
+
+/*****************************************************************************
+ * CardGenInt -
+ */
+CsrResult CardGenInt(card_t *card);
+
+/*****************************************************************************
+ * CardPendingInt -
+ */
+CsrResult CardPendingInt(card_t *card, CsrBool *pintr);
+
+/*****************************************************************************
+ * CardDisableInt -
+ */
+CsrResult CardDisableInt(card_t *card);
+
+/*****************************************************************************
+ * CardClearInt -
+ */
+CsrResult CardClearInt(card_t *card);
+
+/*****************************************************************************
+ * CardDisable -
+ */
+void CardDisable(card_t *card);
+
+/*****************************************************************************
+ * CardIntEnabled -
+ */
+CsrResult CardIntEnabled(card_t *card, CsrBool *enabled);
+
+/*****************************************************************************
+ * CardGetDataSlotSize
+ */
+CsrUint16 CardGetDataSlotSize(card_t *card);
+
+/*****************************************************************************
+ * CardWriteBulkData -
+ */
+CsrResult CardWriteBulkData(card_t *card, card_signal_t *csptr, unifi_TrafficQueue queue);
+
+
+/*****************************************************************************
+ * CardClearFromHostDataSlot -
+ */
+void CardClearFromHostDataSlot(card_t *card, const CsrInt16 aSlotNum);
+
+#ifdef CSR_WIFI_REQUEUE_PACKET_TO_HAL
+/*****************************************************************************
+ * CardClearFromHostDataSlotWithoutFreeingBulkData - Clear the data stot
+ * without freeing the bulk data
+ */
+
+void CardClearFromHostDataSlotWithoutFreeingBulkData(card_t *card, const CsrInt16 aSlotNum);
+#endif
+
+/*****************************************************************************
+ * CardGetFreeFromHostDataSlots -
+ */
+CsrUint16 CardGetFreeFromHostDataSlots(card_t *card);
+
+CsrUint16 CardAreAllFromHostDataSlotsEmpty(card_t *card);
+
+CsrResult card_start_processor(card_t *card, enum unifi_dbg_processors_select which);
+
+CsrResult card_wait_for_firmware_to_start(card_t *card, CsrUint32 *paddr);
+
+CsrResult unifi_dl_firmware(card_t *card, void *arg);
+CsrResult unifi_dl_patch(card_t *card, void *arg, CsrUint32 boot_ctrl);
+CsrResult unifi_do_loader_op(card_t *card, CsrUint32 op_addr, CsrUint8 opcode);
+void* unifi_dl_fw_read_start(card_t *card, CsrInt8 is_fw);
+
+CsrResult unifi_coredump_handle_request(card_t *card);
+
+CsrResult ConvertCsrSdioToCsrHipResult(card_t *card, CsrResult csrResult);
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+void unifi_debug_log_to_buf(const CsrCharString *fmt, ...);
+void unifi_debug_string_to_buf(const CsrCharString *str);
+void unifi_debug_hex_to_buf(const CsrCharString *buff, CsrUint16 length);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CARD_H__ */
diff --git a/drivers/staging/csr/csr_wifi_hip_card_sdio.c b/drivers/staging/csr/csr_wifi_hip_card_sdio.c
new file mode 100644
index 0000000..91976b8
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_card_sdio.c
@@ -0,0 +1,4185 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ * FILE: csr_wifi_hip_card_sdio.c
+ *
+ * PURPOSE: Implementation of the Card API for SDIO.
+ *
+ * NOTES:
+ *      CardInit() is called from the SDIO probe callback when a card is
+ *      inserted. This performs the basic SDIO initialisation, enabling i/o
+ *      etc.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_conversions.h"
+#include "csr_wifi_hip_unifiversion.h"
+#include "csr_wifi_hip_card.h"
+#include "csr_wifi_hip_card_sdio.h"
+#include "csr_wifi_hip_chiphelper.h"
+
+
+/* Time to wait between attempts to read MAILBOX0 */
+#define MAILBOX1_TIMEOUT                10  /* in millisecs */
+#define MAILBOX1_ATTEMPTS               200 /* 2 seconds */
+
+#define MAILBOX2_TIMEOUT                5   /* in millisecs */
+#define MAILBOX2_ATTEMPTS               10  /* 50ms */
+
+#define MAILBOX2_RESET_ATTEMPTS         10
+#define MAILBOX2_RESET_TIMEOUT          5   /* in millisecs */
+
+#define RESET_SETTLE_DELAY              25  /* in millisecs */
+
+static CsrResult card_init_slots(card_t *card);
+static CsrResult card_hw_init(card_t *card);
+static CsrResult firmware_present_in_flash(card_t *card);
+static void bootstrap_chip_hw(card_t *card);
+static CsrResult unifi_reset_hardware(card_t *card);
+static CsrResult unifi_hip_init(card_t *card);
+static CsrResult card_access_panic(card_t *card);
+static CsrResult unifi_read_chip_version(card_t *card);
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_alloc_card
+ *
+ *      Allocate and initialise the card context structure.
+ *
+ *  Arguments:
+ *      sdio            Pointer to SDIO context pointer to pass to low
+ *                      level i/o functions.
+ *      ospriv          Pointer to O/S private struct to pass when calling
+ *                      callbacks to the higher level system.
+ *
+ *  Returns:
+ *      Pointer to card struct, which represents the driver context or
+ *      NULL if the allocation failed.
+ * ---------------------------------------------------------------------------
+ */
+card_t* unifi_alloc_card(CsrSdioFunction *sdio, void *ospriv)
+{
+    card_t *card;
+    CsrUint32 i;
+
+    func_enter();
+
+
+    card = (card_t *)CsrMemAlloc(sizeof(card_t));
+    if (card == NULL)
+    {
+        return NULL;
+    }
+    CsrMemSet(card, 0, sizeof(card_t));
+
+
+    card->sdio_if = sdio;
+    card->ospriv  = ospriv;
+
+    card->unifi_interrupt_seq = 1;
+
+    /* Make these invalid. */
+    card->proc_select = (CsrUint32)(-1);
+    card->dmem_page = (CsrUint32)(-1);
+    card->pmem_page = (CsrUint32)(-1);
+
+    card->bh_reason_host = 0;
+    card->bh_reason_unifi = 0;
+
+    for (i = 0; i < sizeof(card->tx_q_paused_flag) / sizeof(card->tx_q_paused_flag[0]); i++)
+    {
+        card->tx_q_paused_flag[i] = 0;
+    }
+    card->memory_resources_allocated = 0;
+
+    card->low_power_mode = UNIFI_LOW_POWER_DISABLED;
+    card->periodic_wake_mode = UNIFI_PERIODIC_WAKE_HOST_DISABLED;
+
+    card->host_state = UNIFI_HOST_STATE_AWAKE;
+    card->intmode = CSR_WIFI_INTMODE_DEFAULT;
+
+    /*
+     * Memory resources for buffers are allocated when the chip is initialised
+     * because we need configuration information from the firmware.
+     */
+
+    /*
+     * Initialise wait queues and lists
+     */
+    card->fh_command_queue.q_body = card->fh_command_q_body;
+    card->fh_command_queue.q_length = UNIFI_SOFT_COMMAND_Q_LENGTH;
+
+    for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
+    {
+        card->fh_traffic_queue[i].q_body = card->fh_traffic_q_body[i];
+        card->fh_traffic_queue[i].q_length = UNIFI_SOFT_TRAFFIC_Q_LENGTH;
+    }
+
+
+    /* Initialise mini-coredump pointers in case no coredump buffers
+     * are requested by the OS layer.
+     */
+    card->request_coredump_on_reset = 0;
+    card->dump_next_write = NULL;
+    card->dump_cur_read = NULL;
+    card->dump_buf = NULL;
+
+#ifdef UNIFI_DEBUG
+    /* Determine offset of LSB in pointer for later alignment sanity check.
+     * Synergy integer types have specific widths, which cause compiler
+     * warnings when casting pointer types, e.g. on 64-bit systems.
+     */
+    {
+        CsrUint32 val = 0x01234567;
+
+        if (*((CsrUint8 *)&val) == 0x01)
+        {
+            card->lsb = sizeof(void *) - 1;     /* BE */
+        }
+        else
+        {
+            card->lsb = 0;                      /* LE */
+        }
+    }
+#endif
+    func_exit();
+    return card;
+} /* unifi_alloc_card() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_init_card
+ *
+ *      Reset the hardware and perform HIP initialization
+ *
+ *  Arguments:
+ *      card        Pointer to card struct
+ *
+ *  Returns:
+ *      CsrResult code
+ *      CSR_RESULT_SUCCESS if successful
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_init_card(card_t *card, CsrInt32 led_mask)
+{
+    CsrResult r;
+
+    func_enter();
+
+    if (card == NULL)
+    {
+        func_exit_r(CSR_WIFI_HIP_RESULT_INVALID_VALUE);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    r = unifi_init(card);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        func_exit_r(r);
+        return r;
+    }
+
+    r = unifi_hip_init(card);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        func_exit_r(r);
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to start host protocol.\n");
+        func_exit_r(r);
+        return r;
+    }
+
+    func_exit();
+    return CSR_RESULT_SUCCESS;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_init
+ *
+ *      Init the hardware.
+ *
+ *  Arguments:
+ *      card        Pointer to card struct
+ *
+ *  Returns:
+ *      CsrResult code
+ *      CSR_RESULT_SUCCESS if successful
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_init(card_t *card)
+{
+    CsrResult r;
+    CsrResult csrResult;
+
+    func_enter();
+
+    if (card == NULL)
+    {
+        func_exit_r(CSR_WIFI_HIP_RESULT_INVALID_VALUE);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    /*
+     * Disable the SDIO interrupts while initialising UniFi.
+     * Re-enable them when f/w is running.
+     */
+    csrResult = CsrSdioInterruptDisable(card->sdio_if);
+    if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+    {
+        return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+    }
+
+    /*
+     * UniFi's PLL may start with a slow clock (~ 1 MHz) so initially
+     * set the SDIO bus clock to a similar value or SDIO accesses may
+     * fail.
+     */
+    csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_SAFE_HZ);
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+        func_exit_r(r);
+        return r;
+    }
+    card->sdio_clock_speed = UNIFI_SDIO_CLOCK_SAFE_HZ;
+
+    /*
+     * Reset UniFi. Note, this only resets the WLAN function part of the chip,
+     * the SDIO interface is not reset.
+     */
+    unifi_trace(card->ospriv, UDBG1, "Resetting UniFi\n");
+    r = unifi_reset_hardware(card);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to reset UniFi\n");
+        func_exit_r(r);
+        return r;
+    }
+
+    /* Reset the power save mode, to be active until the MLME-reset is complete */
+    r = unifi_configure_low_power_mode(card,
+                                       UNIFI_LOW_POWER_DISABLED, UNIFI_PERIODIC_WAKE_HOST_DISABLED);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to set power save mode\n");
+        func_exit_r(r);
+        return r;
+    }
+
+    /*
+     * Set initial value of page registers.
+     * The page registers will be maintained by unifi_read...() and
+     * unifi_write...().
+     */
+    card->proc_select = (CsrUint32)(-1);
+    card->dmem_page = (CsrUint32)(-1);
+    card->pmem_page = (CsrUint32)(-1);
+    r = unifi_write_direct16(card, ChipHelper_HOST_WINDOW3_PAGE(card->helper) * 2, 0);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to write SHARED_DMEM_PAGE\n");
+        func_exit_r(r);
+        return r;
+    }
+    r = unifi_write_direct16(card, ChipHelper_HOST_WINDOW2_PAGE(card->helper) * 2, 0);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to write PROG_MEM2_PAGE\n");
+        func_exit_r(r);
+        return r;
+    }
+
+    /*
+     * If the driver has reset UniFi due to previous SDIO failure, this may
+     * have been due to a chip watchdog reset. In this case, the driver may
+     * have requested a mini-coredump which needs to be captured now the
+     * SDIO interface is alive.
+     */
+    (void)unifi_coredump_handle_request(card);
+
+    /*
+     * Probe to see if the UniFi has ROM/flash to boot from. CSR6xxx should do.
+     */
+    r = firmware_present_in_flash(card);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r == CSR_WIFI_HIP_RESULT_NOT_FOUND)
+    {
+        unifi_error(card->ospriv, "No firmware found\n");
+    }
+    else if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Probe for Flash failed\n");
+    }
+
+    func_exit_r(r);
+    return r;
+} /* unifi_init() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_download
+ *
+ *      Load the firmware.
+ *
+ *  Arguments:
+ *      card        Pointer to card struct
+ *      led_mask    Loader LED mask
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success
+ *      CsrResult error code on failure.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_download(card_t *card, CsrInt32 led_mask)
+{
+    CsrResult r;
+    void *dlpriv;
+
+    func_enter();
+
+    if (card == NULL)
+    {
+        func_exit_r(CSR_WIFI_HIP_RESULT_INVALID_VALUE);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    /* Set the loader led mask */
+    card->loader_led_mask = led_mask;
+
+    /* Get the firmware file information */
+    unifi_trace(card->ospriv, UDBG1, "downloading firmware...\n");
+
+    dlpriv = unifi_dl_fw_read_start(card, UNIFI_FW_STA);
+    if (dlpriv == NULL)
+    {
+        func_exit_r(CSR_WIFI_HIP_RESULT_NOT_FOUND);
+        return CSR_WIFI_HIP_RESULT_NOT_FOUND;
+    }
+
+    /* Download the firmware. */
+    r = unifi_dl_firmware(card, dlpriv);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to download firmware\n");
+        func_exit_r(r);
+        return r;
+    }
+
+    /* Free the firmware file information. */
+    unifi_fw_read_stop(card->ospriv, dlpriv);
+
+    func_exit();
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_download() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_hip_init
+ *
+ *      This function performs the f/w initialisation sequence as described
+ *      in the Unifi Host Interface Protocol Specification.
+ *      It allocates memory for host-side slot data and signal queues.
+ *
+ *  Arguments:
+ *      card        Pointer to card struct
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success or else a CSR error code
+ *
+ *  Notes:
+ *      The firmware must have been downloaded.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult unifi_hip_init(card_t *card)
+{
+    CsrResult r;
+    CsrResult csrResult;
+
+    func_enter();
+
+    r = card_hw_init(card);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to establish communication with UniFi\n");
+        func_exit_r(r);
+        return r;
+    }
+#ifdef CSR_PRE_ALLOC_NET_DATA
+    /* if there is any preallocated netdata left from the prev session free it now */
+    prealloc_netdata_free(card);
+#endif
+    /*
+     * Allocate memory for host-side slot data and signal queues.
+     * We need the config info read from the firmware to know how much
+     * memory to allocate.
+     */
+    r = card_init_slots(card);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Init slots failed: %d\n", r);
+        func_exit_r(r);
+        return r;
+    }
+
+    unifi_trace(card->ospriv, UDBG2, "Sending first UniFi interrupt\n");
+
+    r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        func_exit_r(r);
+        return r;
+    }
+
+    /* Enable the SDIO interrupts now that the f/w is running. */
+    csrResult = CsrSdioInterruptEnable(card->sdio_if);
+    if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+    {
+        return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+    }
+
+    /* Signal the UniFi to start handling messages */
+    r = CardGenInt(card);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        func_exit_r(r);
+        return r;
+    }
+
+    func_exit();
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_hip_init() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  _build_sdio_config_data
+ *
+ *      Unpack the SDIO configuration information from a buffer read from
+ *      UniFi into a host structure.
+ *      The data is byte-swapped for a big-endian host if necessary by the
+ *      UNPACK... macros.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      cfg_data        Destination structure to unpack into.
+ *      cfg_data_buf    Source buffer to read from. This should be the raw
+ *                      data read from UniFi.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void _build_sdio_config_data(sdio_config_data_t *cfg_data,
+                                    const CsrUint8     *cfg_data_buf)
+{
+    CsrInt16 offset = 0;
+
+    cfg_data->version = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->sdio_ctrl_offset = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->fromhost_sigbuf_handle = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->tohost_sigbuf_handle = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->num_fromhost_sig_frags = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->num_tohost_sig_frags = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->num_fromhost_data_slots = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->num_tohost_data_slots = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->data_slot_size = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->initialised = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->overlay_size = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT32;
+
+    cfg_data->data_slot_round = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->sig_frag_size = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+    offset += SIZEOF_UINT16;
+
+    cfg_data->tohost_signal_padding = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset);
+} /* _build_sdio_config_data() */
+
+
+/*
+ * - Function ----------------------------------------------------------------
+ * card_hw_init()
+ *
+ *      Perform the initialisation procedure described in the UniFi Host
+ *      Interface Protocol document (section 3.3.8) and read the run-time
+ *      configuration information from the UniFi. This is stuff like number
+ *      of bulk data slots etc.
+ *
+ *      The card enumeration and SD initialisation has already been done by
+ *      the SDIO library, see card_sdio_init().
+ *
+ *      The initialisation is done when firmware is ready, i.e. this may need
+ *      to be called after a f/w download operation.
+ *
+ *      The initialisation procedure goes like this:
+ *       - Wait for UniFi to start-up by polling SHARED_MAILBOX1
+ *       - Find the symbol table and look up SLT_SDIO_SLOT_CONFIG
+ *       - Read the config structure
+ *       - Check the "SDIO initialised" flag, if not zero do a h/w reset and
+ *         start again
+ *       - Decide the number of bulk data slots to allocate, allocate them and
+ *         set "SDIO initialised" flag (and generate an interrupt) to say so.
+ *
+ * Arguments:
+ *      card        Pointer to card struct
+ *
+ * Returns:
+ *      CSR_RESULT_SUCEESS on success,
+ *      a CSR error code on failure
+ *
+ * Notes:
+ *      All data in the f/w is stored in a little endian format, without any
+ *      padding bytes. Every read from this memory has to be transformed in
+ *      host (cpu specific) format, before it is stored in driver's parameters
+ *      or/and structures. Athough unifi_card_read16() and unifi_read32() do perform
+ *      the convertion internally, unifi_readn() does not.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult card_hw_init(card_t *card)
+{
+    CsrUint32 slut_address;
+    CsrUint16 initialised;
+    CsrUint16 finger_print;
+    symbol_t slut;
+    sdio_config_data_t *cfg_data;
+    CsrUint8 cfg_data_buf[SDIO_CONFIG_DATA_SIZE];
+    CsrResult r;
+    void *dlpriv;
+    CsrInt16 major, minor;
+    CsrInt16 search_4slut_again;
+    CsrResult csrResult;
+
+    func_enter();
+
+    /*
+     * The device revision from the TPLMID_MANF and TPLMID_CARD fields
+     * of the CIS are available as
+     *   card->sdio_if->pDevice->ManfID
+     *   card->sdio_if->pDevice->AppID
+     */
+
+    /*
+     * Run in a loop so we can patch.
+     */
+    do
+    {
+        /* Reset these each time around the loop. */
+        search_4slut_again = 0;
+        cfg_data = NULL;
+
+        r = card_wait_for_firmware_to_start(card, &slut_address);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Firmware hasn't started\n");
+            func_exit_r(r);
+            return r;
+        }
+        unifi_trace(card->ospriv, UDBG4, "SLUT addr 0x%lX\n", slut_address);
+
+        /*
+         * Firmware has started, but doesn't know full clock configuration yet
+         * as some of the information may be in the MIB. Therefore we set an
+         * initial SDIO clock speed, faster than UNIFI_SDIO_CLOCK_SAFE_HZ, for
+         * the patch download and subsequent firmware initialisation, and
+         * full speed UNIFI_SDIO_CLOCK_MAX_HZ will be set once the f/w tells us
+         * that it is ready.
+         */
+        csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_INIT_HZ);
+        if (csrResult != CSR_RESULT_SUCCESS)
+        {
+            r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+            func_exit_r(r);
+            return r;
+        }
+        card->sdio_clock_speed = UNIFI_SDIO_CLOCK_INIT_HZ;
+
+        /*
+         * Check the SLUT fingerprint.
+         * The slut_address is a generic pointer so we must use unifi_card_read16().
+         */
+        unifi_trace(card->ospriv, UDBG4, "Looking for SLUT finger print\n");
+        finger_print = 0;
+        r = unifi_card_read16(card, slut_address, &finger_print);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to read SLUT finger print\n");
+            func_exit_r(r);
+            return r;
+        }
+
+        if (finger_print != SLUT_FINGERPRINT)
+        {
+            unifi_error(card->ospriv, "Failed to find Symbol lookup table fingerprint\n");
+            func_exit_r(CSR_RESULT_FAILURE);
+            return CSR_RESULT_FAILURE;
+        }
+
+        /* Symbol table starts imedately after the fingerprint */
+        slut_address += 2;
+
+        /* Search the table until either the end marker is found, or the
+         * loading of patch firmware invalidates the current table.
+         */
+        while (!search_4slut_again)
+        {
+            CsrUint16 s;
+            CsrUint32 l;
+
+            r = unifi_card_read16(card, slut_address, &s);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                func_exit_r(r);
+                return r;
+            }
+            slut_address += 2;
+
+            if (s == CSR_SLT_END)
+            {
+                unifi_trace(card->ospriv, UDBG3, "  found CSR_SLT_END\n");
+                break;
+            }
+
+            r = unifi_read32(card, slut_address, &l);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                func_exit_r(r);
+                return r;
+            }
+            slut_address += 4;
+
+            slut.id = s;
+            slut.obj = l;
+
+            unifi_trace(card->ospriv, UDBG3, "  found SLUT id %02d.%08lx\n", slut.id, slut.obj);
+            switch (slut.id)
+            {
+                case CSR_SLT_SDIO_SLOT_CONFIG:
+                    cfg_data = &card->config_data;
+                    /*
+                     * unifi_card_readn reads n bytes from the card, where data is stored
+                     * in a little endian format, without any padding bytes. So, we
+                     * can not just pass the cfg_data pointer or use the
+                     * sizeof(sdio_config_data_t) since the structure in the host can
+                     * be big endian formatted or have padding bytes for alignment.
+                     * We use a char buffer to read the data from the card.
+                     */
+                    r = unifi_card_readn(card, slut.obj, cfg_data_buf, SDIO_CONFIG_DATA_SIZE);
+                    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+                    {
+                        return r;
+                    }
+                    if (r != CSR_RESULT_SUCCESS)
+                    {
+                        unifi_error(card->ospriv, "Failed to read config data\n");
+                        func_exit_r(r);
+                        return r;
+                    }
+                    /* .. and then we copy the data to the host structure */
+                    _build_sdio_config_data(cfg_data, cfg_data_buf);
+
+                    /* Make sure the from host data slots are what we expect
+                        we reserve 2 for commands and there should be at least
+                        1 left for each access category */
+                    if ((cfg_data->num_fromhost_data_slots < UNIFI_RESERVED_COMMAND_SLOTS)
+                        || (cfg_data->num_fromhost_data_slots - UNIFI_RESERVED_COMMAND_SLOTS) / UNIFI_NO_OF_TX_QS == 0)
+                    {
+                        unifi_error(card->ospriv, "From host data slots %d\n", cfg_data->num_fromhost_data_slots);
+                        unifi_error(card->ospriv, "need to be (queues * x + 2) (UNIFI_RESERVED_COMMAND_SLOTS for commands)\n");
+                        func_exit_r(CSR_RESULT_FAILURE);
+                        return CSR_RESULT_FAILURE;
+                    }
+
+                    /* Configure SDIO to-block-size padding */
+                    if (card->sdio_io_block_pad)
+                    {
+                    /*
+                     * Firmware limits the maximum padding size via data_slot_round.
+                     * Therefore when padding to whole block sizes, the block size
+                     * must be configured correctly by adjusting CSR_WIFI_HIP_SDIO_BLOCK_SIZE.
+                     */
+                        if (cfg_data->data_slot_round < card->sdio_io_block_size)
+                        {
+                            unifi_error(card->ospriv,
+                                        "Configuration error: Block size of %d exceeds f/w data_slot_round of %d\n",
+                                        card->sdio_io_block_size, cfg_data->data_slot_round);
+                            return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+                        }
+
+                        /*
+                         * To force the To-Host signals to be rounded up to the SDIO block
+                         * size, we need to write the To-Host Signal Padding Fragments
+                         * field of the SDIO configuration in UniFi.
+                         */
+                        if ((card->sdio_io_block_size % cfg_data->sig_frag_size) != 0)
+                        {
+                            unifi_error(card->ospriv, "Configuration error: Can not pad to-host signals.\n");
+                            func_exit_r(CSR_WIFI_HIP_RESULT_INVALID_VALUE);
+                            return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+                        }
+                        cfg_data->tohost_signal_padding = (CsrUint16) (card->sdio_io_block_size / cfg_data->sig_frag_size);
+                        unifi_info(card->ospriv, "SDIO block size %d requires %d padding chunks\n",
+                                   card->sdio_io_block_size, cfg_data->tohost_signal_padding);
+                        r = unifi_card_write16(card, slut.obj + SDIO_TO_HOST_SIG_PADDING_OFFSET, cfg_data->tohost_signal_padding);
+                        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+                        {
+                            return r;
+                        }
+                        if (r != CSR_RESULT_SUCCESS)
+                        {
+                            unifi_error(card->ospriv, "Failed to write To-Host Signal Padding Fragments\n");
+                            func_exit_r(r);
+                            return r;
+                        }
+                    }
+
+                    /* Reconstruct the Generic Pointer address of the
+                     * SDIO Control Data Struct.
+                     */
+                    card->sdio_ctrl_addr = cfg_data->sdio_ctrl_offset | (UNIFI_SH_DMEM << 24);
+                    card->init_flag_addr = slut.obj + SDIO_INIT_FLAG_OFFSET;
+                    break;
+
+                case CSR_SLT_BUILD_ID_NUMBER:
+                {
+                    CsrUint32 n;
+                    r = unifi_read32(card, slut.obj, &n);
+                    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+                    {
+                        return r;
+                    }
+                    if (r != CSR_RESULT_SUCCESS)
+                    {
+                        unifi_error(card->ospriv, "Failed to read build id\n");
+                        func_exit_r(r);
+                        return r;
+                    }
+                    card->build_id = n;
+                }
+                break;
+
+                case CSR_SLT_BUILD_ID_STRING:
+                    r = unifi_readnz(card, slut.obj, card->build_id_string,
+                                     sizeof(card->build_id_string));
+                    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+                    {
+                        return r;
+                    }
+                    if (r != CSR_RESULT_SUCCESS)
+                    {
+                        unifi_error(card->ospriv, "Failed to read build string\n");
+                        func_exit_r(r);
+                        return r;
+                    }
+                    break;
+
+                case CSR_SLT_PERSISTENT_STORE_DB:
+                    break;
+
+                case CSR_SLT_BOOT_LOADER_CONTROL:
+
+                    /* This command copies most of the station firmware
+                     * image from ROM into program RAM.  It also clears
+                     * out the zerod data and sets up the initialised
+                     * data. */
+                    r = unifi_do_loader_op(card, slut.obj + 6, UNIFI_BOOT_LOADER_LOAD_STA);
+                    if (r != CSR_RESULT_SUCCESS)
+                    {
+                        unifi_error(card->ospriv, "Failed to write loader load image command\n");
+                        func_exit_r(r);
+                        return r;
+                    }
+
+                    dlpriv = unifi_dl_fw_read_start(card, UNIFI_FW_STA);
+
+                    /* dlpriv might be NULL, we still need to do the do_loader_op step. */
+                    if (dlpriv != NULL)
+                    {
+                    /* Download the firmware. */
+                        r = unifi_dl_patch(card, dlpriv, slut.obj);
+
+                    /* Free the firmware file information. */
+                        unifi_fw_read_stop(card->ospriv, dlpriv);
+
+                        if (r != CSR_RESULT_SUCCESS)
+                        {
+                            unifi_error(card->ospriv, "Failed to patch firmware\n");
+                            func_exit_r(r);
+                            return r;
+                        }
+                    }
+
+                    /* This command starts the firmware image that we want (the
+                    * station by default) with any patches required applied. */
+                    r = unifi_do_loader_op(card, slut.obj + 6, UNIFI_BOOT_LOADER_RESTART);
+                    if (r != CSR_RESULT_SUCCESS)
+                    {
+                        unifi_error(card->ospriv, "Failed to write loader restart command\n");
+                        func_exit_r(r);
+                        return r;
+                    }
+
+                    /* The now running patch f/w defines a new SLUT data structure -
+                     * the current one is no longer valid. We must drop out of the
+                     * processing loop and enumerate the new SLUT (which may appear
+                     * at a different offset).
+                     */
+                    search_4slut_again = 1;
+                    break;
+
+                case CSR_SLT_PANIC_DATA_PHY:
+                    card->panic_data_phy_addr = slut.obj;
+                    break;
+
+                case CSR_SLT_PANIC_DATA_MAC:
+                    card->panic_data_mac_addr = slut.obj;
+                    break;
+
+                default:
+                    /* do nothing */
+                    break;
+            }
+        } /* while */
+    } while (search_4slut_again);
+
+    /* Did we find the Config Data ? */
+    if (cfg_data == NULL)
+    {
+        unifi_error(card->ospriv, "Failed to find SDIO_SLOT_CONFIG Symbol\n");
+        func_exit_r(CSR_RESULT_FAILURE);
+        return CSR_RESULT_FAILURE;
+    }
+
+    /*
+     * Has ths card already been initialised?
+     * If so, return an error so we do a h/w reset and start again.
+     */
+    r = unifi_card_read16(card, card->init_flag_addr, &initialised);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to read init flag at %08lx\n",
+                    card->init_flag_addr);
+        func_exit_r(r);
+        return r;
+    }
+    if (initialised != 0)
+    {
+        func_exit_r(CSR_RESULT_FAILURE);
+        return CSR_RESULT_FAILURE;
+    }
+
+
+    /*
+     * Now check the UniFi firmware version
+     */
+    major = (cfg_data->version >> 8) & 0xFF;
+    minor = cfg_data->version & 0xFF;
+    unifi_info(card->ospriv, "UniFi f/w protocol version %d.%d (driver %d.%d)\n",
+               major, minor,
+               UNIFI_HIP_MAJOR_VERSION, UNIFI_HIP_MINOR_VERSION);
+
+    unifi_info(card->ospriv, "Firmware build %u: %s\n",
+               card->build_id, card->build_id_string);
+
+    if (major != UNIFI_HIP_MAJOR_VERSION)
+    {
+        unifi_error(card->ospriv, "UniFi f/w protocol major version (%d) is different from driver (v%d.%d)\n",
+                    major, UNIFI_HIP_MAJOR_VERSION, UNIFI_HIP_MINOR_VERSION);
+#ifndef CSR_WIFI_DISABLE_HIP_VERSION_CHECK
+        func_exit_r(CSR_RESULT_FAILURE);
+        return CSR_RESULT_FAILURE;
+#endif
+    }
+    if (minor < UNIFI_HIP_MINOR_VERSION)
+    {
+        unifi_error(card->ospriv, "UniFi f/w protocol version (v%d.%d) is older than minimum required by driver (v%d.%d).\n",
+                    major, minor,
+                    UNIFI_HIP_MAJOR_VERSION, UNIFI_HIP_MINOR_VERSION);
+#ifndef CSR_WIFI_DISABLE_HIP_VERSION_CHECK
+        func_exit_r(CSR_RESULT_FAILURE);
+        return CSR_RESULT_FAILURE;
+#endif
+    }
+
+    /* Read panic codes from a previous firmware panic. If the firmware has
+     * not panicked since power was applied (e.g. power-off hard reset)
+     * the stored panic codes will not be updated.
+     */
+    unifi_read_panic(card);
+
+    func_exit();
+    return CSR_RESULT_SUCCESS;
+} /* card_hw_init() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  card_wait_for_unifi_to_reset
+ *
+ *      Waits for a reset to complete by polling the WLAN function enable
+ *      bit (which is cleared on reset).
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR error code on failure.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult card_wait_for_unifi_to_reset(card_t *card)
+{
+    CsrInt16 i;
+    CsrResult r;
+    CsrUint8 io_enable;
+    CsrResult csrResult;
+
+    func_enter();
+
+    r = CSR_RESULT_SUCCESS;
+    for (i = 0; i < MAILBOX2_ATTEMPTS; i++)
+    {
+        unifi_trace(card->ospriv, UDBG1, "waiting for reset to complete, attempt %d\n", i);
+        if (card->chip_id > SDIO_CARD_ID_UNIFI_2)
+        {
+            /* It's quite likely that this read will timeout for the
+             * first few tries - especially if we have reset via
+             * DBG_RESET.
+             */
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+            unifi_debug_log_to_buf("m0@%02X=", SDIO_IO_READY);
+#endif
+            csrResult = CsrSdioF0Read8(card->sdio_if, SDIO_IO_READY, &io_enable);
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+            if (csrResult != CSR_RESULT_SUCCESS)
+            {
+                unifi_debug_log_to_buf("error=%X\n", csrResult);
+            }
+            else
+            {
+                unifi_debug_log_to_buf("%X\n", io_enable);
+            }
+#endif
+            if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+            {
+                return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+            }
+            r = CSR_RESULT_SUCCESS;
+            if (csrResult != CSR_RESULT_SUCCESS)
+            {
+                r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+            }
+        }
+        else
+        {
+            r = sdio_read_f0(card, SDIO_IO_ENABLE, &io_enable);
+        }
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r == CSR_RESULT_SUCCESS)
+        {
+            CsrUint16 mbox2;
+            CsrInt16 enabled = io_enable & (1 << card->function);
+
+            if (!enabled)
+            {
+                unifi_trace(card->ospriv, UDBG1,
+                            "Reset complete (function %d is disabled) in ~ %u msecs\n",
+                            card->function, i * MAILBOX2_TIMEOUT);
+
+                /* Enable WLAN function and verify MAILBOX2 is zero'd */
+                csrResult = CsrSdioFunctionEnable(card->sdio_if);
+                if (csrResult != CSR_RESULT_SUCCESS)
+                {
+                    r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+                    unifi_error(card->ospriv, "CsrSdioFunctionEnable failed %d\n", r);
+                    break;
+                }
+            }
+
+            r = unifi_read_direct16(card, ChipHelper_SDIO_HIP_HANDSHAKE(card->helper) * 2, &mbox2);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                unifi_error(card->ospriv, "read HIP_HANDSHAKE failed %d\n", r);
+                break;
+            }
+            if (mbox2 != 0)
+            {
+                unifi_error(card->ospriv, "MAILBOX2 non-zero after reset (mbox2 = %04x)\n", mbox2);
+                r = CSR_RESULT_FAILURE;
+            }
+            break;
+        }
+        else
+        {
+            if (card->chip_id > SDIO_CARD_ID_UNIFI_2)
+            {
+                /* We ignore read failures for the first few reads,
+                 * they are probably benign. */
+                if (i > MAILBOX2_ATTEMPTS / 4)
+                {
+                    unifi_trace(card->ospriv, UDBG1, "Failed to read CCCR IO Ready register while polling for reset\n");
+                }
+            }
+            else
+            {
+                unifi_trace(card->ospriv, UDBG1, "Failed to read CCCR IO Enable register while polling for reset\n");
+            }
+        }
+        CsrThreadSleep(MAILBOX2_TIMEOUT);
+    }
+
+    if (r == CSR_RESULT_SUCCESS && i == MAILBOX2_ATTEMPTS)
+    {
+        unifi_trace(card->ospriv, UDBG1, "Timeout waiting for UniFi to complete reset\n");
+        r = CSR_RESULT_FAILURE;
+    }
+
+    func_exit();
+    return r;
+} /* card_wait_for_unifi_to_reset() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  card_wait_for_unifi_to_disable
+ *
+ *      Waits for the function to become disabled by polling the
+ *      IO_READY bit.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR error code on failure.
+ *
+ *  Notes: This function can only be used with
+ *         card->chip_id > SDIO_CARD_ID_UNIFI_2
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult card_wait_for_unifi_to_disable(card_t *card)
+{
+    CsrInt16 i;
+    CsrResult r;
+    CsrUint8 io_enable;
+    CsrResult csrResult;
+
+    func_enter();
+
+    if (card->chip_id <= SDIO_CARD_ID_UNIFI_2)
+    {
+        unifi_error(card->ospriv,
+                    "Function reset method not supported for chip_id=%d\n",
+                    card->chip_id);
+        func_exit();
+        return CSR_RESULT_FAILURE;
+    }
+
+    r = CSR_RESULT_SUCCESS;
+    for (i = 0; i < MAILBOX2_ATTEMPTS; i++)
+    {
+        unifi_trace(card->ospriv, UDBG1, "waiting for disable to complete, attempt %d\n", i);
+
+        /*
+         * It's quite likely that this read will timeout for the
+         * first few tries - especially if we have reset via
+         * DBG_RESET.
+         */
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+        unifi_debug_log_to_buf("r0@%02X=", SDIO_IO_READY);
+#endif
+        csrResult = CsrSdioF0Read8(card->sdio_if, SDIO_IO_READY, &io_enable);
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+        if (csrResult != CSR_RESULT_SUCCESS)
+        {
+            unifi_debug_log_to_buf("error=%X\n", csrResult);
+        }
+        else
+        {
+            unifi_debug_log_to_buf("%X\n", io_enable);
+        }
+#endif
+        if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+        {
+            return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+        }
+        if (csrResult == CSR_RESULT_SUCCESS)
+        {
+            CsrInt16 enabled = io_enable & (1 << card->function);
+            r = CSR_RESULT_SUCCESS;
+            if (!enabled)
+            {
+                unifi_trace(card->ospriv, UDBG1,
+                            "Disable complete (function %d is disabled) in ~ %u msecs\n",
+                            card->function, i * MAILBOX2_TIMEOUT);
+
+                break;
+            }
+        }
+        else
+        {
+            /*
+             * We ignore read failures for the first few reads,
+             * they are probably benign.
+             */
+            r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+            if (i > (MAILBOX2_ATTEMPTS / 4))
+            {
+                unifi_trace(card->ospriv, UDBG1,
+                            "Failed to read CCCR IO Ready register while polling for disable\n");
+            }
+        }
+        CsrThreadSleep(MAILBOX2_TIMEOUT);
+    }
+
+    if ((r == CSR_RESULT_SUCCESS) && (i == MAILBOX2_ATTEMPTS))
+    {
+        unifi_trace(card->ospriv, UDBG1, "Timeout waiting for UniFi to complete disable\n");
+        r = CSR_RESULT_FAILURE;
+    }
+
+    func_exit();
+    return r;
+} /* card_wait_for_unifi_to_reset() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  card_wait_for_firmware_to_start
+ *
+ *      Polls the MAILBOX1 register for a non-zero value.
+ *      Then reads MAILBOX0 and forms the two values into a 32-bit address
+ *      which is returned to the caller.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      paddr           Pointer to receive the UniFi address formed
+ *                      by concatenating MAILBOX1 and MAILBOX0.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR error code on failure.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult card_wait_for_firmware_to_start(card_t *card, CsrUint32 *paddr)
+{
+    CsrInt32 i;
+    CsrUint16 mbox0, mbox1;
+    CsrResult r;
+
+    func_enter();
+
+    /*
+     * Wait for UniFi to initialise its data structures by polling
+     * the SHARED_MAILBOX1 register.
+     * Experience shows this is typically 120ms.
+     */
+    CsrThreadSleep(MAILBOX1_TIMEOUT);
+
+    mbox1 = 0;
+    unifi_trace(card->ospriv, UDBG1, "waiting for MAILBOX1 to be non-zero...\n");
+    for (i = 0; i < MAILBOX1_ATTEMPTS; i++)
+    {
+        r = unifi_read_direct16(card, ChipHelper_MAILBOX1(card->helper) * 2, &mbox1);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            /* These reads can fail if UniFi isn't up yet, so try again */
+            unifi_warning(card->ospriv, "Failed to read UniFi Mailbox1 register\n");
+        }
+
+        if ((r == CSR_RESULT_SUCCESS) && (mbox1 != 0))
+        {
+            unifi_trace(card->ospriv, UDBG1, "MAILBOX1 ready (0x%04X) in %u millisecs\n",
+                        mbox1, i * MAILBOX1_TIMEOUT);
+
+            /* Read the MAILBOX1 again in case we caught the value as it
+             * changed. */
+            r = unifi_read_direct16(card, ChipHelper_MAILBOX1(card->helper) * 2, &mbox1);
+            if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+            {
+                return r;
+            }
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                unifi_error(card->ospriv, "Failed to read UniFi Mailbox1 register for second time\n");
+                func_exit_r(r);
+                return r;
+            }
+            unifi_trace(card->ospriv, UDBG1, "MAILBOX1 value=0x%04X\n", mbox1);
+
+            break;
+        }
+
+        CsrThreadSleep(MAILBOX1_TIMEOUT);
+        if ((i % 100) == 99)
+        {
+            unifi_trace(card->ospriv, UDBG2, "MAILBOX1 not ready (0x%X), still trying...\n", mbox1);
+        }
+    }
+
+    if ((r == CSR_RESULT_SUCCESS) && (mbox1 == 0))
+    {
+        unifi_trace(card->ospriv, UDBG1, "Timeout waiting for firmware to start, Mailbox1 still 0 after %d ms\n",
+                    MAILBOX1_ATTEMPTS * MAILBOX1_TIMEOUT);
+        func_exit_r(CSR_RESULT_FAILURE);
+        return CSR_RESULT_FAILURE;
+    }
+
+
+    /*
+     * Complete the reset handshake by setting MAILBOX2 to 0xFFFF
+     */
+    r = unifi_write_direct16(card, ChipHelper_SDIO_HIP_HANDSHAKE(card->helper) * 2, 0xFFFF);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to write f/w startup handshake to MAILBOX2\n");
+        func_exit_r(r);
+        return r;
+    }
+
+
+    /*
+     * Read the Symbol Look Up Table (SLUT) offset.
+     * Top 16 bits are in mbox1, read the lower 16 bits from mbox0.
+     */
+    mbox0 = 0;
+    r = unifi_read_direct16(card, ChipHelper_MAILBOX0(card->helper) * 2, &mbox0);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to read UniFi Mailbox0 register\n");
+        func_exit_r(r);
+        return r;
+    }
+
+    *paddr = (((CsrUint32)mbox1 << 16) | mbox0);
+
+    func_exit();
+    return CSR_RESULT_SUCCESS;
+} /* card_wait_for_firmware_to_start() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_capture_panic
+ *
+ *      Attempt to capture panic codes from the firmware. This may involve
+ *      warm reset of the chip to regain access following a watchdog reset.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS if panic codes were captured, or none available
+ *      CSR_RESULT_FAILURE if the driver could not access function 1
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_capture_panic(card_t *card)
+{
+    func_enter();
+
+    /* The firmware must have previously initialised to read the panic addresses
+     * from the SLUT
+     */
+    if (!card->panic_data_phy_addr || !card->panic_data_mac_addr)
+    {
+        func_exit();
+        return CSR_RESULT_SUCCESS;
+    }
+
+    /* Ensure we can access function 1 following a panic/watchdog reset */
+    if (card_access_panic(card) == CSR_RESULT_SUCCESS)
+    {
+        /* Read the panic codes */
+        unifi_read_panic(card);
+    }
+    else
+    {
+        unifi_info(card->ospriv, "Unable to read panic codes");
+    }
+
+    func_exit();
+    return CSR_RESULT_SUCCESS;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  card_access_panic
+ *      Attempt to read the WLAN SDIO function in order to read panic codes
+ *      and perform various reset steps to regain access if the read fails.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS if panic codes can be read
+ *      CSR error code if panic codes can not be read
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult card_access_panic(card_t *card)
+{
+    CsrUint16 data_u16 = 0;
+    CsrInt32 i;
+    CsrResult r, sr;
+
+    func_enter();
+
+    /* A chip version of zero means that the version never got succesfully read
+     * during reset. In this case give up because it will not be possible to
+     * verify the chip version.
+     */
+    if (!card->chip_version)
+    {
+        unifi_info(card->ospriv, "Unknown chip version\n");
+        return CSR_RESULT_FAILURE;
+    }
+
+    /* Ensure chip is awake or access to function 1 will fail */
+    r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "unifi_set_host_state() failed %d\n", r);
+        return CSR_RESULT_FAILURE; /* Card is probably unpowered */
+    }
+    CsrThreadSleep(20);
+
+    for (i = 0; i < 3; i++)
+    {
+        sr = CsrSdioRead16(card->sdio_if, CHIP_HELPER_UNIFI_GBL_CHIP_VERSION * 2, &data_u16);
+        if (sr != CSR_RESULT_SUCCESS || data_u16 != card->chip_version)
+        {
+            unifi_info(card->ospriv, "Failed to read valid chip version sr=%d (0x%04x want 0x%04x) try %d\n",
+                       sr, data_u16, card->chip_version, i);
+
+            /* Set clock speed low */
+            sr = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_SAFE_HZ);
+            if (sr != CSR_RESULT_SUCCESS)
+            {
+                unifi_error(card->ospriv, "CsrSdioMaxBusClockFrequencySet() failed1 %d\n", sr);
+                r = ConvertCsrSdioToCsrHipResult(card, sr);
+            }
+            card->sdio_clock_speed = UNIFI_SDIO_CLOCK_SAFE_HZ;
+
+            /* First try re-enabling function in case a f/w watchdog reset disabled it */
+            if (i == 0)
+            {
+                unifi_info(card->ospriv, "Try function enable\n");
+                sr = CsrSdioFunctionEnable(card->sdio_if);
+                if (sr != CSR_RESULT_SUCCESS)
+                {
+                    r = ConvertCsrSdioToCsrHipResult(card, sr);
+                    unifi_error(card->ospriv, "CsrSdioFunctionEnable failed %d (HIP %d)\n", sr, r);
+                }
+                continue;
+            }
+
+            /* Second try, set awake */
+            unifi_info(card->ospriv, "Try set awake\n");
+
+            /* Ensure chip is awake */
+            r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE);
+            if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+            {
+                return r;
+            }
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                unifi_error(card->ospriv, "unifi_set_host_state() failed2 %d\n", r);
+            }
+
+            /* Set clock speed low in case setting the host state raised it, which
+             * would only happen if host state was previously TORPID
+             */
+            sr = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_SAFE_HZ);
+            if (sr != CSR_RESULT_SUCCESS)
+            {
+                unifi_error(card->ospriv, "CsrSdioMaxBusClockFrequencySet() failed2 %d\n", sr);
+            }
+            card->sdio_clock_speed = UNIFI_SDIO_CLOCK_SAFE_HZ;
+
+            if (i == 1)
+            {
+                continue;
+            }
+
+            /* Perform a s/w reset to preserve as much as the card state as possible,
+             * (mainly the preserve RAM). The context will be lost for coredump - but as we
+             * were unable to access the WLAN function for panic, the coredump would have
+             * also failed without a reset.
+             */
+            unifi_info(card->ospriv, "Try s/w reset\n");
+
+            r = unifi_card_hard_reset(card);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                unifi_error(card->ospriv, "unifi_card_hard_reset() failed %d\n", r);
+            }
+        }
+        else
+        {
+            if (i > 0)
+            {
+                unifi_info(card->ospriv, "Read chip version 0x%x after %d retries\n", data_u16, i);
+            }
+            break;
+        }
+    }
+
+    r = ConvertCsrSdioToCsrHipResult(card, sr);
+    func_exit_r(r);
+    return r;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_read_panic
+ *      Reads, saves and prints panic codes stored by the firmware in UniFi's
+ *      preserve RAM by the last panic that occurred since chip was powered.
+ *      Nothing is saved if the panic codes are read as zero.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ * ---------------------------------------------------------------------------
+ */
+void unifi_read_panic(card_t *card)
+{
+    CsrResult r;
+    CsrUint16 p_code, p_arg;
+
+    func_enter();
+
+    /* The firmware must have previously initialised to read the panic addresses
+     * from the SLUT
+     */
+    if (!card->panic_data_phy_addr || !card->panic_data_mac_addr)
+    {
+        return;
+    }
+
+    /* Get the panic data from PHY */
+    r = unifi_card_read16(card, card->panic_data_phy_addr, &p_code);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "capture_panic: unifi_read16 %08x failed %d\n", card->panic_data_phy_addr, r);
+        p_code = 0;
+    }
+    if (p_code)
+    {
+        r = unifi_card_read16(card, card->panic_data_phy_addr + 2, &p_arg);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "capture_panic: unifi_read16 %08x failed %d\n", card->panic_data_phy_addr + 2, r);
+        }
+        unifi_error(card->ospriv, "Last UniFi PHY PANIC %04x arg %04x\n", p_code, p_arg);
+        card->last_phy_panic_code = p_code;
+        card->last_phy_panic_arg = p_arg;
+    }
+
+    /* Get the panic data from MAC */
+    r = unifi_card_read16(card, card->panic_data_mac_addr, &p_code);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "capture_panic: unifi_read16 %08x failed %d\n", card->panic_data_mac_addr, r);
+        p_code = 0;
+    }
+    if (p_code)
+    {
+        r = unifi_card_read16(card, card->panic_data_mac_addr + 2, &p_arg);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "capture_panic: unifi_read16 %08x failed %d\n", card->panic_data_mac_addr + 2, r);
+        }
+        unifi_error(card->ospriv, "Last UniFi MAC PANIC %04x arg %04x\n", p_code, p_arg);
+        card->last_mac_panic_code = p_code;
+        card->last_mac_panic_arg = p_arg;
+    }
+
+    func_exit();
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  card_allocate_memory_resources
+ *
+ *      Allocates memory for the from-host, to-host bulk data slots,
+ *      soft queue buffers and bulk data buffers.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR error code on failure.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult card_allocate_memory_resources(card_t *card)
+{
+    CsrInt16 n, i, k, r;
+    sdio_config_data_t *cfg_data;
+
+    func_enter();
+
+    /* Reset any state carried forward from a previous life */
+    card->fh_command_queue.q_rd_ptr = 0;
+    card->fh_command_queue.q_wr_ptr = 0;
+    (void)CsrSnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH,
+                      "fh_cmd_q");
+    for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
+    {
+        card->fh_traffic_queue[i].q_rd_ptr = 0;
+        card->fh_traffic_queue[i].q_wr_ptr = 0;
+        (void)CsrSnprintf(card->fh_traffic_queue[i].name,
+                          UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_data_q%d", i);
+    }
+#ifndef CSR_WIFI_HIP_TA_DISABLE
+    unifi_ta_sampling_init(card);
+#endif
+    /* Convenience short-cut */
+    cfg_data = &card->config_data;
+
+    /*
+     * Allocate memory for the from-host and to-host signal buffers.
+     */
+    card->fh_buffer.buf = CsrMemAllocDma(UNIFI_FH_BUF_SIZE);
+    if (card->fh_buffer.buf == NULL)
+    {
+        unifi_error(card->ospriv, "Failed to allocate memory for F-H signals\n");
+        func_exit_r(CSR_WIFI_HIP_RESULT_NO_MEMORY);
+        return CSR_WIFI_HIP_RESULT_NO_MEMORY;
+    }
+    card->fh_buffer.bufsize = UNIFI_FH_BUF_SIZE;
+    card->fh_buffer.ptr = card->fh_buffer.buf;
+    card->fh_buffer.count = 0;
+
+    card->th_buffer.buf = CsrMemAllocDma(UNIFI_FH_BUF_SIZE);
+    if (card->th_buffer.buf == NULL)
+    {
+        unifi_error(card->ospriv, "Failed to allocate memory for T-H signals\n");
+        func_exit_r(CSR_WIFI_HIP_RESULT_NO_MEMORY);
+        return CSR_WIFI_HIP_RESULT_NO_MEMORY;
+    }
+    card->th_buffer.bufsize = UNIFI_FH_BUF_SIZE;
+    card->th_buffer.ptr = card->th_buffer.buf;
+    card->th_buffer.count = 0;
+
+
+    /*
+     * Allocate memory for the from-host and to-host bulk data slots.
+     * This is done as separate CsrPmemAllocs because lots of smaller
+     * allocations are more likely to succeed than one huge one.
+     */
+
+    /* Allocate memory for the array of pointers */
+    n = cfg_data->num_fromhost_data_slots;
+
+    unifi_trace(card->ospriv, UDBG3, "Alloc from-host resources, %d slots.\n", n);
+    card->from_host_data =
+        (slot_desc_t *)CsrMemAlloc(n * sizeof(slot_desc_t));
+    if (card->from_host_data == NULL)
+    {
+        unifi_error(card->ospriv, "Failed to allocate memory for F-H bulk data array\n");
+        func_exit_r(CSR_WIFI_HIP_RESULT_NO_MEMORY);
+        return CSR_WIFI_HIP_RESULT_NO_MEMORY;
+    }
+
+    /* Initialise from-host bulk data slots */
+    for (i = 0; i < n; i++)
+    {
+        UNIFI_INIT_BULK_DATA(&card->from_host_data[i].bd);
+    }
+
+    /* Allocate memory for the array used for slot host tag mapping */
+    card->fh_slot_host_tag_record =
+        (CsrUint32 *)CsrMemAlloc(n * sizeof(CsrUint32));
+
+    if (card->fh_slot_host_tag_record == NULL)
+    {
+        unifi_error(card->ospriv, "Failed to allocate memory for F-H slot host tag mapping array\n");
+        func_exit_r(CSR_WIFI_HIP_RESULT_NO_MEMORY);
+        return CSR_WIFI_HIP_RESULT_NO_MEMORY;
+    }
+
+    /* Initialise host tag entries for from-host bulk data slots */
+    for (i = 0; i < n; i++)
+    {
+        card->fh_slot_host_tag_record[i] = CSR_WIFI_HIP_RESERVED_HOST_TAG;
+    }
+
+
+    /* Allocate memory for the array of pointers */
+    n = cfg_data->num_tohost_data_slots;
+
+    unifi_trace(card->ospriv, UDBG3, "Alloc to-host resources, %d slots.\n", n);
+    card->to_host_data =
+        (bulk_data_desc_t *)CsrMemAlloc(n * sizeof(bulk_data_desc_t));
+    if (card->to_host_data == NULL)
+    {
+        unifi_error(card->ospriv, "Failed to allocate memory for T-H bulk data array\n");
+        func_exit_r(CSR_WIFI_HIP_RESULT_NO_MEMORY);
+        return CSR_WIFI_HIP_RESULT_NO_MEMORY;
+    }
+
+    /* Initialise to-host bulk data slots */
+    for (i = 0; i < n; i++)
+    {
+        UNIFI_INIT_BULK_DATA(&card->to_host_data[i]);
+    }
+
+    /*
+     * Initialise buffers for soft Q
+     */
+    for (i = 0; i < UNIFI_SOFT_COMMAND_Q_LENGTH; i++)
+    {
+        for (r = 0; r < UNIFI_MAX_DATA_REFERENCES; r++)
+        {
+            UNIFI_INIT_BULK_DATA(&card->fh_command_q_body[i].bulkdata[r]);
+        }
+    }
+
+    for (k = 0; k < UNIFI_NO_OF_TX_QS; k++)
+    {
+        for (i = 0; i < UNIFI_SOFT_TRAFFIC_Q_LENGTH; i++)
+        {
+            for (r = 0; r < UNIFI_MAX_DATA_REFERENCES; r++)
+            {
+                UNIFI_INIT_BULK_DATA(&card->fh_traffic_q_body[k][i].bulkdata[r]);
+            }
+        }
+    }
+
+    card->memory_resources_allocated = 1;
+
+    func_exit();
+    return CSR_RESULT_SUCCESS;
+} /* card_allocate_memory_resources() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_free_bulk_data
+ *
+ *      Free the data associated to a bulk data structure.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      bulk_data_slot  Pointer to bulk data structure
+ *
+ *  Returns:
+ *      None.
+ *
+ * ---------------------------------------------------------------------------
+ */
+static void unifi_free_bulk_data(card_t *card, bulk_data_desc_t *bulk_data_slot)
+{
+    if (bulk_data_slot->data_length != 0)
+    {
+        unifi_net_data_free(card->ospriv, bulk_data_slot);
+    }
+} /* unifi_free_bulk_data() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  card_free_memory_resources
+ *
+ *      Frees memory allocated for the from-host, to-host bulk data slots,
+ *      soft queue buffers and bulk data buffers.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void card_free_memory_resources(card_t *card)
+{
+    func_enter();
+
+    unifi_trace(card->ospriv, UDBG1, "Freeing card memory resources.\n");
+
+    /* Clear our internal queues */
+    unifi_cancel_pending_signals(card);
+
+
+    if (card->to_host_data)
+    {
+        CsrMemFree(card->to_host_data);
+        card->to_host_data = NULL;
+    }
+
+    if (card->from_host_data)
+    {
+        CsrMemFree(card->from_host_data);
+        card->from_host_data = NULL;
+    }
+
+    /* free the memory for slot host tag mapping array */
+    if (card->fh_slot_host_tag_record)
+    {
+        CsrMemFree(card->fh_slot_host_tag_record);
+        card->fh_slot_host_tag_record = NULL;
+    }
+
+    if (card->fh_buffer.buf)
+    {
+        CsrMemFreeDma(card->fh_buffer.buf);
+    }
+    card->fh_buffer.ptr = card->fh_buffer.buf = NULL;
+    card->fh_buffer.bufsize = 0;
+    card->fh_buffer.count = 0;
+
+    if (card->th_buffer.buf)
+    {
+        CsrMemFreeDma(card->th_buffer.buf);
+    }
+    card->th_buffer.ptr = card->th_buffer.buf = NULL;
+    card->th_buffer.bufsize = 0;
+    card->th_buffer.count = 0;
+
+
+    card->memory_resources_allocated = 0;
+
+    func_exit();
+} /* card_free_memory_resources() */
+
+
+static void card_init_soft_queues(card_t *card)
+{
+    CsrInt16 i;
+
+    func_enter();
+
+    unifi_trace(card->ospriv, UDBG1, "Initialising internal signal queues.\n");
+    /* Reset any state carried forward from a previous life */
+    card->fh_command_queue.q_rd_ptr = 0;
+    card->fh_command_queue.q_wr_ptr = 0;
+    (void)CsrSnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH,
+                      "fh_cmd_q");
+    for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
+    {
+        card->fh_traffic_queue[i].q_rd_ptr = 0;
+        card->fh_traffic_queue[i].q_wr_ptr = 0;
+        (void)CsrSnprintf(card->fh_traffic_queue[i].name,
+                          UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_data_q%d", i);
+    }
+#ifndef CSR_WIFI_HIP_TA_DISABLE
+    unifi_ta_sampling_init(card);
+#endif
+    func_exit();
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_cancel_pending_signals
+ *
+ *      Free the signals and associated bulk data, pending in the core.
+ *
+ *  Arguments:
+ *      card        Pointer to card struct
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void unifi_cancel_pending_signals(card_t *card)
+{
+    CsrInt16 i, n, r;
+    func_enter();
+
+    unifi_trace(card->ospriv, UDBG1, "Canceling pending signals.\n");
+
+    if (card->to_host_data)
+    {
+        /*
+         * Free any bulk data buffers allocated for the t-h slots
+         * This will clear all buffers that did not make it to
+         * unifi_receive_event() before cancel was request.
+         */
+        n = card->config_data.num_tohost_data_slots;
+        unifi_trace(card->ospriv, UDBG3, "Freeing to-host resources, %d slots.\n", n);
+        for (i = 0; i < n; i++)
+        {
+            unifi_free_bulk_data(card, &card->to_host_data[i]);
+        }
+    }
+
+    /*
+     * If any of the from-host bulk data has reached the card->from_host_data
+     * but not UniFi, we need to free the buffers here.
+     */
+    if (card->from_host_data)
+    {
+        /* Free any bulk data buffers allocated for the f-h slots */
+        n = card->config_data.num_fromhost_data_slots;
+        unifi_trace(card->ospriv, UDBG3, "Freeing from-host resources, %d slots.\n", n);
+        for (i = 0; i < n; i++)
+        {
+            unifi_free_bulk_data(card, &card->from_host_data[i].bd);
+        }
+
+        for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
+        {
+            card->dynamic_slot_data.from_host_used_slots[i] = 0;
+            card->dynamic_slot_data.from_host_max_slots[i] = 0;
+            card->dynamic_slot_data.from_host_reserved_slots[i] = 0;
+        }
+    }
+
+    /*
+     * Free any bulk data buffers allocated in the soft queues.
+     * This covers the case where a bulk data pointer has reached the soft queue
+     * but not the card->from_host_data.
+     */
+    unifi_trace(card->ospriv, UDBG3, "Freeing cmd q resources.\n");
+    for (i = 0; i < UNIFI_SOFT_COMMAND_Q_LENGTH; i++)
+    {
+        for (r = 0; r < UNIFI_MAX_DATA_REFERENCES; r++)
+        {
+            unifi_free_bulk_data(card, &card->fh_command_q_body[i].bulkdata[r]);
+        }
+    }
+
+    unifi_trace(card->ospriv, UDBG3, "Freeing traffic q resources.\n");
+    for (n = 0; n < UNIFI_NO_OF_TX_QS; n++)
+    {
+        for (i = 0; i < UNIFI_SOFT_TRAFFIC_Q_LENGTH; i++)
+        {
+            for (r = 0; r < UNIFI_MAX_DATA_REFERENCES; r++)
+            {
+                unifi_free_bulk_data(card, &card->fh_traffic_q_body[n][i].bulkdata[r]);
+            }
+        }
+    }
+
+    card_init_soft_queues(card);
+
+    func_exit();
+} /* unifi_cancel_pending_signals() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_free_card
+ *
+ *      Free the memory allocated for the card structure and buffers.
+ *
+ *  Notes:
+ *      The porting layer is responsible for freeing any mini-coredump buffers
+ *      allocated when it called unifi_coredump_init(), by calling
+ *      unifi_coredump_free() before calling this function.
+ *
+ *  Arguments:
+ *      card        Pointer to card struct
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void unifi_free_card(card_t *card)
+{
+    func_enter();
+#ifdef CSR_PRE_ALLOC_NET_DATA
+    prealloc_netdata_free(card);
+#endif
+    /* Free any memory allocated. */
+    card_free_memory_resources(card);
+
+    /* Warn if caller didn't free coredump buffers */
+    if (card->dump_buf)
+    {
+        unifi_error(card->ospriv, "Caller should call unifi_coredump_free()\n");
+        unifi_coredump_free(card); /* free anyway to prevent memory leak */
+    }
+
+    CsrMemFree(card);
+
+    func_exit();
+} /* unifi_free_card() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  card_init_slots
+ *
+ *      Allocate memory for host-side slot data and signal queues.
+ *
+ * Arguments:
+ *      card            Pointer to card object
+ *
+ * Returns:
+ *      CSR error code.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult card_init_slots(card_t *card)
+{
+    CsrResult r;
+    CsrUint8 i;
+
+    func_enter();
+
+    /* Allocate the buffers we need, only once. */
+    if (card->memory_resources_allocated == 1)
+    {
+        card_free_memory_resources(card);
+    }
+    else
+    {
+        /* Initialise our internal command and traffic queues */
+        card_init_soft_queues(card);
+    }
+
+    r = card_allocate_memory_resources(card);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to allocate card memory resources.\n");
+        card_free_memory_resources(card);
+        func_exit_r(r);
+        return r;
+    }
+
+    if (card->sdio_ctrl_addr == 0)
+    {
+        unifi_error(card->ospriv, "Failed to find config struct!\n");
+        func_exit_r(CSR_WIFI_HIP_RESULT_INVALID_VALUE);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    /*
+     * Set initial counts.
+     */
+
+    card->from_host_data_head = 0;
+
+    /* Get initial signal counts from UniFi, in case it has not been reset. */
+    {
+        CsrUint16 s;
+
+        /* Get the from-host-signals-written count */
+        r = unifi_card_read16(card, card->sdio_ctrl_addr + 0, &s);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to read from-host sig written count\n");
+            func_exit_r(r);
+            return r;
+        }
+        card->from_host_signals_w = (CsrInt16)s;
+
+        /* Get the to-host-signals-written count */
+        r = unifi_card_read16(card, card->sdio_ctrl_addr + 6, &s);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to read to-host sig read count\n");
+            func_exit_r(r);
+            return r;
+        }
+        card->to_host_signals_r = (CsrInt16)s;
+    }
+
+    /* Set Initialised flag. */
+    r = unifi_card_write16(card, card->init_flag_addr, 0x0001);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to write initialised flag\n");
+        func_exit_r(r);
+        return r;
+    }
+
+    /* Dynamic queue reservation */
+    CsrMemSet(&card->dynamic_slot_data, 0, sizeof(card_dynamic_slot_t));
+
+    for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
+    {
+        card->dynamic_slot_data.from_host_max_slots[i] = card->config_data.num_fromhost_data_slots -
+                                                         UNIFI_RESERVED_COMMAND_SLOTS;
+        card->dynamic_slot_data.queue_stable[i] = FALSE;
+    }
+
+    card->dynamic_slot_data.packets_interval = UNIFI_PACKETS_INTERVAL;
+
+    func_exit();
+    return CSR_RESULT_SUCCESS;
+} /* card_init_slots() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_set_udi_hook
+ *
+ *      Registers the udi hook that reports the sent signals to the core.
+ *
+ *  Arguments:
+ *      card            Pointer to the card context struct
+ *      udi_fn          Pointer to the callback function.
+ *
+ *  Returns:
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE if the card pointer is invalid,
+ *      CSR_RESULT_SUCCESS on success.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_set_udi_hook(card_t *card, udi_func_t udi_fn)
+{
+    if (card == NULL)
+    {
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    if (card->udi_hook == NULL)
+    {
+        card->udi_hook = udi_fn;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_set_udi_hook() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_remove_udi_hook
+ *
+ *      Removes the udi hook that reports the sent signals from the core.
+ *
+ *  Arguments:
+ *      card            Pointer to the card context struct
+ *      udi_fn          Pointer to the callback function.
+ *
+ *  Returns:
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE if the card pointer is invalid,
+ *      CSR_RESULT_SUCCESS on success.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_remove_udi_hook(card_t *card, udi_func_t udi_fn)
+{
+    if (card == NULL)
+    {
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    if (card->udi_hook == udi_fn)
+    {
+        card->udi_hook = NULL;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_remove_udi_hook() */
+
+
+static void CardReassignDynamicReservation(card_t *card)
+{
+    CsrUint8 i;
+
+    func_enter();
+
+    unifi_trace(card->ospriv, UDBG5, "Packets Txed %d %d %d %d\n",
+                card->dynamic_slot_data.packets_txed[0],
+                card->dynamic_slot_data.packets_txed[1],
+                card->dynamic_slot_data.packets_txed[2],
+                card->dynamic_slot_data.packets_txed[3]);
+
+    /* Clear reservation and recalculate max slots */
+    for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
+    {
+        card->dynamic_slot_data.queue_stable[i] = FALSE;
+        card->dynamic_slot_data.from_host_reserved_slots[i] = 0;
+        card->dynamic_slot_data.from_host_max_slots[i] = card->config_data.num_fromhost_data_slots -
+                                                         UNIFI_RESERVED_COMMAND_SLOTS;
+        card->dynamic_slot_data.packets_txed[i] = 0;
+
+        unifi_trace(card->ospriv, UDBG5, "CardReassignDynamicReservation: queue %d reserved %d Max %d\n", i,
+                    card->dynamic_slot_data.from_host_reserved_slots[i],
+                    card->dynamic_slot_data.from_host_max_slots[i]);
+    }
+
+    card->dynamic_slot_data.total_packets_txed = 0;
+    func_exit();
+}
+
+
+/* Algorithm to dynamically reserve slots. The logic is based mainly on the outstanding queue
+ * length. Slots are reserved for particular queues during an interval and cleared after the interval.
+ * Each queue has three associated variables.. a) used slots - the number of slots currently occupied
+ * by the queue b) reserved slots - number of slots reserved specifically for the queue c) max slots - total
+ * slots that this queue can actually use (may be higher than reserved slots and is dependent on reserved slots
+ * for other queues).
+ * This function is called when there are no slots available for a queue. It checks to see if there are enough
+ * unreserved slots sufficient for this request. If available these slots are reserved for the queue.
+ * If there are not enough unreserved slots, a fair share for each queue is calculated based on the total slots
+ * and the number of active queues (any queue with existing reservation is considered active). Queues needing
+ * less than their fair share are allowed to have the previously reserved slots. The remaining slots are
+ * distributed evenly among queues that need more than the fair share
+ *
+ * A better scheme would take current bandwidth per AC into consideration when reserving slots. An
+ * implementation scheme could consider the relative time/service period for slots in an AC. If the firmware
+ * services other ACs faster than a particular AC (packets wait in the slots longer) then it is fair to reserve
+ * less slots for the AC
+ */
+static void CardCheckDynamicReservation(card_t *card, unifi_TrafficQueue queue)
+{
+    CsrUint16 q_len, active_queues = 0, excess_queue_slots, div_extra_slots,
+              queue_fair_share, reserved_slots = 0, q, excess_need_queues = 0, unmovable_slots = 0;
+    CsrInt32 i;
+    q_t *sigq;
+    CsrUint16 num_data_slots = card->config_data.num_fromhost_data_slots - UNIFI_RESERVED_COMMAND_SLOTS;
+
+    func_enter();
+
+    /* Calculate the pending queue length */
+    sigq = &card->fh_traffic_queue[queue];
+    q_len = CSR_WIFI_HIP_Q_SLOTS_USED(sigq);
+
+    if (q_len <= card->dynamic_slot_data.from_host_reserved_slots[queue])
+    {
+        unifi_trace(card->ospriv, UDBG5, "queue %d q_len %d already has that many reserved slots, exiting\n", queue, q_len);
+        func_exit();
+        return;
+    }
+
+    /* Upper limit */
+    if (q_len > num_data_slots)
+    {
+        q_len = num_data_slots;
+    }
+
+    for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
+    {
+        if (i != (CsrInt32)queue)
+        {
+            reserved_slots += card->dynamic_slot_data.from_host_reserved_slots[i];
+        }
+        if ((i == (CsrInt32)queue) || (card->dynamic_slot_data.from_host_reserved_slots[i] > 0))
+        {
+            active_queues++;
+        }
+    }
+
+    unifi_trace(card->ospriv, UDBG5, "CardCheckDynamicReservation: queue %d q_len %d\n", queue, q_len);
+    unifi_trace(card->ospriv, UDBG5, "Active queues %d reserved slots on other queues %d\n",
+                active_queues, reserved_slots);
+
+    if (reserved_slots + q_len <= num_data_slots)
+    {
+        card->dynamic_slot_data.from_host_reserved_slots[queue] = q_len;
+        if (q_len == num_data_slots)
+        {
+            /* This is the common case when just 1 stream is going */
+            card->dynamic_slot_data.queue_stable[queue] = TRUE;
+        }
+    }
+    else
+    {
+        queue_fair_share = num_data_slots / active_queues;
+        unifi_trace(card->ospriv, UDBG5, "queue fair share %d\n", queue_fair_share);
+
+        /* Evenly distribute slots among active queues */
+        /* Find out the queues that need excess of fair share. Also find slots allocated
+         * to queues less than their fair share, these slots cannot be reallocated (unmovable slots) */
+
+        card->dynamic_slot_data.from_host_reserved_slots[queue] = q_len;
+
+        for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
+        {
+            if (card->dynamic_slot_data.from_host_reserved_slots[i] > queue_fair_share)
+            {
+                excess_need_queues++;
+            }
+            else
+            {
+                unmovable_slots += card->dynamic_slot_data.from_host_reserved_slots[i];
+            }
+        }
+
+        unifi_trace(card->ospriv, UDBG5, "Excess need queues %d\n", excess_need_queues);
+
+        /* Now find the slots per excess demand queue */
+        excess_queue_slots = (num_data_slots - unmovable_slots) / excess_need_queues;
+        div_extra_slots = (num_data_slots - unmovable_slots) - excess_queue_slots * excess_need_queues;
+        for (i = UNIFI_NO_OF_TX_QS - 1; i >= 0; i--)
+        {
+            if (card->dynamic_slot_data.from_host_reserved_slots[i] > excess_queue_slots)
+            {
+                card->dynamic_slot_data.from_host_reserved_slots[i] = excess_queue_slots;
+                if (div_extra_slots > 0)
+                {
+                    card->dynamic_slot_data.from_host_reserved_slots[i]++;
+                    div_extra_slots--;
+                }
+                /* No more slots will be allocated to this queue during the current interval */
+                card->dynamic_slot_data.queue_stable[i] = TRUE;
+                unifi_trace(card->ospriv, UDBG5, "queue stable %d\n", i);
+            }
+        }
+    }
+
+    /* Redistribute max slots */
+    for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
+    {
+        reserved_slots = 0;
+        for (q = 0; q < UNIFI_NO_OF_TX_QS; q++)
+        {
+            if (i != q)
+            {
+                reserved_slots += card->dynamic_slot_data.from_host_reserved_slots[q];
+            }
+        }
+
+        card->dynamic_slot_data.from_host_max_slots[i] = num_data_slots - reserved_slots;
+        unifi_trace(card->ospriv, UDBG5, "queue %d reserved %d Max %d\n", i,
+                    card->dynamic_slot_data.from_host_reserved_slots[i],
+                    card->dynamic_slot_data.from_host_max_slots[i]);
+    }
+
+    func_exit();
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CardClearFromHostDataSlot
+ *
+ *      Clear a the given data slot, making it available again.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *      slot            Index of the signal slot to clear.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void CardClearFromHostDataSlot(card_t *card, const CsrInt16 slot)
+{
+    CsrUint8 queue = card->from_host_data[slot].queue;
+    const void *os_data_ptr = card->from_host_data[slot].bd.os_data_ptr;
+
+    func_enter();
+
+    if (card->from_host_data[slot].bd.data_length == 0)
+    {
+        unifi_warning(card->ospriv,
+                      "Surprise: request to clear an already free FH data slot: %d\n",
+                      slot);
+        func_exit();
+        return;
+    }
+
+    if (os_data_ptr == NULL)
+    {
+        unifi_warning(card->ospriv,
+                      "Clearing FH data slot %d: has null payload, len=%d\n",
+                      slot, card->from_host_data[slot].bd.data_length);
+    }
+
+    /* Free card->from_host_data[slot].bd.os_net_ptr here. */
+    /* Mark slot as free by setting length to 0. */
+    unifi_free_bulk_data(card, &card->from_host_data[slot].bd);
+    if (queue < UNIFI_NO_OF_TX_QS)
+    {
+        if (card->dynamic_slot_data.from_host_used_slots[queue] == 0)
+        {
+            unifi_error(card->ospriv, "Goofed up used slots q = %d used slots = %d\n",
+                        queue,
+                        card->dynamic_slot_data.from_host_used_slots[queue]);
+        }
+        else
+        {
+            card->dynamic_slot_data.from_host_used_slots[queue]--;
+        }
+        card->dynamic_slot_data.packets_txed[queue]++;
+        card->dynamic_slot_data.total_packets_txed++;
+        if (card->dynamic_slot_data.total_packets_txed >= card->dynamic_slot_data.packets_interval)
+        {
+            CardReassignDynamicReservation(card);
+        }
+    }
+
+    unifi_trace(card->ospriv, UDBG4, "CardClearFromHostDataSlot: slot %d recycled %p\n", slot, os_data_ptr);
+
+    func_exit();
+} /* CardClearFromHostDataSlot() */
+
+
+#ifdef CSR_WIFI_REQUEUE_PACKET_TO_HAL
+/*
+ * ---------------------------------------------------------------------------
+ *  CardClearFromHostDataSlotWithoutFreeingBulkData
+ *
+ *      Clear the given data slot with out freeing the bulk data.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *      slot            Index of the signal slot to clear.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void CardClearFromHostDataSlotWithoutFreeingBulkData(card_t *card, const CsrInt16 slot)
+{
+    CsrUint8 queue = card->from_host_data[slot].queue;
+
+    /* Initialise the from_host data slot so it can be re-used,
+     * Set length field in from_host_data array to 0.
+     */
+    UNIFI_INIT_BULK_DATA(&card->from_host_data[slot].bd);
+
+    queue = card->from_host_data[slot].queue;
+
+    if (queue < UNIFI_NO_OF_TX_QS)
+    {
+        if (card->dynamic_slot_data.from_host_used_slots[queue] == 0)
+        {
+            unifi_error(card->ospriv, "Goofed up used slots q = %d used slots = %d\n",
+                        queue,
+                        card->dynamic_slot_data.from_host_used_slots[queue]);
+        }
+        else
+        {
+            card->dynamic_slot_data.from_host_used_slots[queue]--;
+        }
+        card->dynamic_slot_data.packets_txed[queue]++;
+        card->dynamic_slot_data.total_packets_txed++;
+        if (card->dynamic_slot_data.total_packets_txed >=
+            card->dynamic_slot_data.packets_interval)
+        {
+            CardReassignDynamicReservation(card);
+        }
+    }
+} /* CardClearFromHostDataSlotWithoutFreeingBulkData() */
+
+
+#endif
+
+CsrUint16 CardGetDataSlotSize(card_t *card)
+{
+    return card->config_data.data_slot_size;
+} /* CardGetDataSlotSize() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CardGetFreeFromHostDataSlots
+ *
+ *      Retrieve the number of from-host bulk data slots available.
+ *
+ *  Arguments:
+ *      card            Pointer to the card context struct
+ *
+ *  Returns:
+ *      Number of free from-host bulk data slots.
+ * ---------------------------------------------------------------------------
+ */
+CsrUint16 CardGetFreeFromHostDataSlots(card_t *card)
+{
+    CsrUint16 i, n = 0;
+
+    func_enter();
+
+    /* First two slots reserved for MLME */
+    for (i = 0; i < card->config_data.num_fromhost_data_slots; i++)
+    {
+        if (card->from_host_data[i].bd.data_length == 0)
+        {
+            /* Free slot */
+            n++;
+        }
+    }
+
+    func_exit();
+    return n;
+} /* CardGetFreeFromHostDataSlots() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CardAreAllFromHostDataSlotsEmpty
+ *
+ *      Returns the state of from-host bulk data slots.
+ *
+ *  Arguments:
+ *      card            Pointer to the card context struct
+ *
+ *  Returns:
+ *      1       The from-host bulk data slots are all empty (available).
+ *      0       Some or all the from-host bulk data slots are in use.
+ * ---------------------------------------------------------------------------
+ */
+CsrUint16 CardAreAllFromHostDataSlotsEmpty(card_t *card)
+{
+    CsrUint16 i;
+
+    for (i = 0; i < card->config_data.num_fromhost_data_slots; i++)
+    {
+        if (card->from_host_data[i].bd.data_length != 0)
+        {
+            return 0;
+        }
+    }
+
+    return 1;
+} /* CardGetFreeFromHostDataSlots() */
+
+
+static CsrResult unifi_identify_hw(card_t *card)
+{
+    func_enter();
+
+    card->chip_id = card->sdio_if->sdioId.cardId;
+    card->function = card->sdio_if->sdioId.sdioFunction;
+    card->sdio_io_block_size = card->sdio_if->blockSize;
+
+    /* If SDIO controller doesn't support byte mode CMD53, pad transfers to block sizes */
+    card->sdio_io_block_pad = (card->sdio_if->features & CSR_SDIO_FEATURE_BYTE_MODE)?FALSE : TRUE;
+
+    /*
+     * Setup the chip helper so that we can access the registers (and
+     * also tell what sub-type of HIP we should use).
+     */
+    card->helper = ChipHelper_GetVersionSdio((CsrUint8)card->chip_id);
+    if (!card->helper)
+    {
+        unifi_error(card->ospriv, "Null ChipHelper\n");
+    }
+
+    unifi_info(card->ospriv, "Chip ID 0x%02X  Function %u  Block Size %u  Name %s(%s)\n",
+               card->chip_id, card->function, card->sdio_io_block_size,
+               ChipHelper_MarketingName(card->helper),
+               ChipHelper_FriendlyName(card->helper));
+
+    func_exit();
+    return CSR_RESULT_SUCCESS;
+} /* unifi_identify_hw() */
+
+
+static CsrResult unifi_prepare_hw(card_t *card)
+{
+    CsrResult r;
+    CsrResult csrResult;
+    enum unifi_host_state old_state = card->host_state;
+
+    func_enter();
+
+    r = unifi_identify_hw(card);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to identify hw\n");
+        func_exit_r(r);
+        return r;
+    }
+
+    unifi_trace(card->ospriv, UDBG1,
+                "%s mode SDIO\n", card->sdio_io_block_pad?"Block" : "Byte");
+    /*
+     * Chip must be a awake or blocks that are asleep may not get
+     * reset.  We can only do this after we have read the chip_id.
+     */
+    r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+
+    if (old_state == UNIFI_HOST_STATE_TORPID)
+    {
+        /* Ensure the initial clock rate is set; if a reset occured when the chip was
+         * TORPID, unifi_set_host_state() may have raised it to MAX.
+         */
+        csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_INIT_HZ);
+        if (csrResult != CSR_RESULT_SUCCESS)
+        {
+            r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+            func_exit_r(r);
+            return r;
+        }
+        card->sdio_clock_speed = UNIFI_SDIO_CLOCK_INIT_HZ;
+    }
+
+    /*
+     * The WLAN function must be enabled to access MAILBOX2 and DEBUG_RST
+     * registers.
+     */
+    csrResult = CsrSdioFunctionEnable(card->sdio_if);
+    if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+    {
+        return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+    }
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+        /* Can't enable WLAN function. Try resetting the SDIO block. */
+        unifi_error(card->ospriv, "Failed to re-enable function %d.\n", card->function);
+        func_exit_r(r);
+        return r;
+    }
+
+    /*
+     * Poke some registers to make sure the PLL has started,
+     * otherwise memory accesses are likely to fail.
+     */
+    bootstrap_chip_hw(card);
+
+    /* Try to read the chip version from register. */
+    r = unifi_read_chip_version(card);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        func_exit_r(r);
+        return r;
+    }
+
+    func_exit();
+    return CSR_RESULT_SUCCESS;
+} /* unifi_prepare_hw() */
+
+
+static CsrResult unifi_read_chip_version(card_t *card)
+{
+    CsrUint32 gbl_chip_version;
+    CsrResult r;
+    CsrUint16 ver;
+
+    func_enter();
+
+    gbl_chip_version = ChipHelper_GBL_CHIP_VERSION(card->helper);
+
+    /* Try to read the chip version from register. */
+    if (gbl_chip_version != 0)
+    {
+        r = unifi_read_direct16(card, gbl_chip_version * 2, &ver);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to read GBL_CHIP_VERSION\n");
+            func_exit_r(r);
+            return r;
+        }
+        card->chip_version = ver;
+    }
+    else
+    {
+        unifi_info(card->ospriv, "Unknown Chip ID, cannot locate GBL_CHIP_VERSION\n");
+        r = CSR_RESULT_FAILURE;
+    }
+
+    unifi_info(card->ospriv, "Chip Version 0x%04X\n", card->chip_version);
+
+    func_exit_r(r);
+    return r;
+} /* unifi_read_chip_version() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_reset_hardware
+ *
+ *      Execute the UniFi reset sequence.
+ *
+ *      Note: This may fail if the chip is going TORPID so retry at
+ *      least once.
+ *
+ *  Arguments:
+ *      card - pointer to card context structure
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR error otherwise.
+ *
+ *  Notes:
+ *      Some platforms (e.g. Windows Vista) do not allow access to registers
+ *      that are necessary for a software soft reset.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult unifi_reset_hardware(card_t *card)
+{
+    CsrResult r;
+    CsrUint16 new_block_size = UNIFI_IO_BLOCK_SIZE;
+    CsrResult csrResult;
+
+    func_enter();
+
+    /* Errors returned by unifi_prepare_hw() are not critical at this point */
+    r = unifi_prepare_hw(card);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+
+    /* First try SDIO controller reset, which may power cycle the UniFi, assert
+     * its reset line, or not be implemented depending on the platform.
+     */
+    unifi_info(card->ospriv, "Calling CsrSdioHardReset\n");
+    csrResult = CsrSdioHardReset(card->sdio_if);
+    if (csrResult == CSR_RESULT_SUCCESS)
+    {
+        unifi_info(card->ospriv, "CsrSdioHardReset succeeded on reseting UniFi\n");
+        r = unifi_prepare_hw(card);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "unifi_prepare_hw failed after hard reset\n");
+            func_exit_r(r);
+            return r;
+        }
+    }
+    else if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+    {
+        return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+    }
+    else
+    {
+        /* Falling back to software hard reset methods */
+        unifi_info(card->ospriv, "Falling back to software hard reset\n");
+        r = unifi_card_hard_reset(card);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "software hard reset failed\n");
+            func_exit_r(r);
+            return r;
+        }
+
+        /* If we fell back to unifi_card_hard_reset() methods, chip version may
+         * not have been read. (Note in the unlikely event that it is zero,
+         * it will be harmlessly read again)
+         */
+        if (card->chip_version == 0)
+        {
+            r = unifi_read_chip_version(card);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                func_exit_r(r);
+                return r;
+            }
+        }
+    }
+
+#ifdef CSR_WIFI_HIP_SDIO_BLOCK_SIZE
+    new_block_size = CSR_WIFI_HIP_SDIO_BLOCK_SIZE;
+#endif
+
+    /* After hard reset, we need to restore the SDIO block size */
+    csrResult = CsrSdioBlockSizeSet(card->sdio_if, new_block_size);
+    r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+
+    /* Warn if a different block size was achieved by the transport */
+    if (card->sdio_if->blockSize != new_block_size)
+    {
+        unifi_info(card->ospriv,
+                   "Actually got block size %d\n", card->sdio_if->blockSize);
+    }
+
+    /* sdio_io_block_size always needs be updated from the achieved block size,
+     * as it is used by the OS layer to allocate memory in unifi_net_malloc().
+     * Controllers which don't support block mode (e.g. CSPI) will report a
+     * block size of zero.
+     */
+    if (card->sdio_if->blockSize == 0)
+    {
+        unifi_info(card->ospriv, "Block size 0, block mode not available\n");
+
+        /* Set sdio_io_block_size to 1 so that unifi_net_data_malloc() has a
+         * sensible rounding value. Elsewhere padding will already be
+         * disabled because the controller supports byte mode.
+         */
+        card->sdio_io_block_size = 1;
+
+        /* Controller features must declare support for byte mode */
+        if (!(card->sdio_if->features & CSR_SDIO_FEATURE_BYTE_MODE))
+        {
+            unifi_error(card->ospriv, "Requires byte mode\n");
+            r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+        }
+    }
+    else
+    {
+        /* Padding will be enabled if CSR_SDIO_FEATURE_BYTE_MODE isn't set */
+        card->sdio_io_block_size = card->sdio_if->blockSize;
+    }
+
+
+    func_exit_r(r);
+    return r;
+} /* unifi_reset_hardware() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  card_reset_method_io_enable
+ *
+ *      Issue a hard reset to the hw writing the IO_ENABLE.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *
+ *  Returns:
+ *      0 on success,
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE   if the card was ejected
+ *      CSR_RESULT_FAILURE         if an SDIO error occurred or if a response
+ *                                 was not seen in the expected time
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult card_reset_method_io_enable(card_t *card)
+{
+    CsrResult r;
+    CsrResult csrResult;
+
+    func_enter();
+
+    /*
+     * This resets only function 1, so should be used in
+     * preference to the method below (CSR_FUNC_EN)
+     */
+    unifi_trace(card->ospriv, UDBG1, "Hard reset (IO_ENABLE)\n");
+
+    csrResult = CsrSdioFunctionDisable(card->sdio_if);
+    if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+    {
+        return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+    }
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+        unifi_warning(card->ospriv, "SDIO error writing IO_ENABLE: %d\n", r);
+    }
+    else
+    {
+        /* Delay here to let the reset take affect. */
+        CsrThreadSleep(RESET_SETTLE_DELAY);
+
+        r = card_wait_for_unifi_to_disable(card);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+
+        if (r == CSR_RESULT_SUCCESS)
+        {
+            r = card_wait_for_unifi_to_reset(card);
+            if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+            {
+                return r;
+            }
+        }
+    }
+
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_trace(card->ospriv, UDBG1, "Hard reset (CSR_FUNC_EN)\n");
+
+        r = sdio_write_f0(card, SDIO_CSR_FUNC_EN, 0);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_warning(card->ospriv, "SDIO error writing SDIO_CSR_FUNC_EN: %d\n", r);
+            func_exit_r(r);
+            return r;
+        }
+        else
+        {
+            /* Delay here to let the reset take affect. */
+            CsrThreadSleep(RESET_SETTLE_DELAY);
+
+            r = card_wait_for_unifi_to_reset(card);
+            if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+            {
+                return r;
+            }
+        }
+    }
+
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_warning(card->ospriv, "card_reset_method_io_enable failed to reset UniFi\n");
+    }
+
+    func_exit();
+    return r;
+} /* card_reset_method_io_enable() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  card_reset_method_dbg_reset
+ *
+ *      Issue a hard reset to the hw writing the DBG_RESET.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS         on success,
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE   if the card was ejected
+ *      CSR_RESULT_FAILURE         if an SDIO error occurred or if a response
+ *                                 was not seen in the expected time
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult card_reset_method_dbg_reset(card_t *card)
+{
+    CsrResult r;
+
+    func_enter();
+
+    /*
+     * Prepare UniFi for h/w reset
+     */
+    if (card->host_state == UNIFI_HOST_STATE_TORPID)
+    {
+        r = unifi_set_host_state(card, UNIFI_HOST_STATE_DROWSY);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to set UNIFI_HOST_STATE_DROWSY\n");
+            func_exit_r(r);
+            return r;
+        }
+        CsrThreadSleep(5);
+    }
+
+    r = unifi_card_stop_processor(card, UNIFI_PROC_BOTH);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Can't stop processors\n");
+        func_exit();
+        return r;
+    }
+
+    unifi_trace(card->ospriv, UDBG1, "Hard reset (DBG_RESET)\n");
+
+    /*
+     * This register write may fail. The debug reset resets
+     * parts of the Function 0 sections of the chip, and
+     * therefore the response cannot be sent back to the host.
+     */
+    r = unifi_write_direct_8_or_16(card, ChipHelper_DBG_RESET(card->helper) * 2, 1);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_warning(card->ospriv, "SDIO error writing DBG_RESET: %d\n", r);
+        func_exit_r(r);
+        return r;
+    }
+
+    /* Delay here to let the reset take affect. */
+    CsrThreadSleep(RESET_SETTLE_DELAY);
+
+    r = card_wait_for_unifi_to_reset(card);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_warning(card->ospriv, "card_reset_method_dbg_reset failed to reset UniFi\n");
+    }
+
+    func_exit();
+    return r;
+} /* card_reset_method_dbg_reset() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_card_hard_reset
+ *
+ *      Issue reset to hardware, by writing to registers on the card.
+ *      Power to the card is preserved.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS         on success,
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE   if the card was ejected
+ *      CSR_RESULT_FAILURE         if an SDIO error occurred or if a response
+ *                                 was not seen in the expected time
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_card_hard_reset(card_t *card)
+{
+    CsrResult r;
+    const struct chip_helper_reset_values *init_data;
+    CsrUint32 chunks;
+
+    func_enter();
+
+    /* Clear cache of page registers */
+    card->proc_select = (CsrUint32)(-1);
+    card->dmem_page = (CsrUint32)(-1);
+    card->pmem_page = (CsrUint32)(-1);
+
+    /*
+     * We need to have a valid card->helper before we use software hard reset.
+     * If unifi_identify_hw() fails to get the card ID, it probably means
+     * that there is no way to talk to the h/w.
+     */
+    r = unifi_identify_hw(card);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "unifi_card_hard_reset failed to identify h/w\n");
+        func_exit();
+        return r;
+    }
+
+    /* Search for some reset code. */
+    chunks = ChipHelper_HostResetSequence(card->helper, &init_data);
+    if (chunks != 0)
+    {
+        unifi_error(card->ospriv,
+                    "Hard reset (Code download) is unsupported\n");
+
+        func_exit_r(CSR_RESULT_FAILURE);
+        return CSR_RESULT_FAILURE;
+    }
+
+    if (card->chip_id > SDIO_CARD_ID_UNIFI_2)
+    {
+        /* The HIP spec considers this a bus-specific reset.
+         * This resets only function 1, so should be used in
+         * preference to the method below (CSR_FUNC_EN)
+         * If this method fails, it means that the f/w is probably
+         * not running. In this case, try the DBG_RESET method.
+         */
+        r = card_reset_method_io_enable(card);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r == CSR_RESULT_SUCCESS)
+        {
+            func_exit();
+            return r;
+        }
+    }
+
+    /* Software hard reset */
+    r = card_reset_method_dbg_reset(card);
+
+    func_exit_r(r);
+    return r;
+} /* unifi_card_hard_reset() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ *  CardGenInt
+ *
+ *      Prod the card.
+ *      This function causes an internal interrupt to be raised in the
+ *      UniFi chip. It is used to signal the firmware that some action has
+ *      been completed.
+ *      The UniFi Host Interface asks that the value used increments for
+ *      debugging purposes.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS         on success,
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE   if the card was ejected
+ *      CSR_RESULT_FAILURE         if an SDIO error occurred or if a response
+ *                                 was not seen in the expected time
+ * ---------------------------------------------------------------------------
+ */
+CsrResult CardGenInt(card_t *card)
+{
+    CsrResult r;
+
+    func_enter();
+
+    if (card->chip_id > SDIO_CARD_ID_UNIFI_2)
+    {
+        r = sdio_write_f0(card, SDIO_CSR_FROM_HOST_SCRATCH0,
+                          (CsrUint8)card->unifi_interrupt_seq);
+    }
+    else
+    {
+        r = unifi_write_direct_8_or_16(card,
+                                       ChipHelper_SHARED_IO_INTERRUPT(card->helper) * 2,
+                                       (CsrUint8)card->unifi_interrupt_seq);
+    }
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "SDIO error writing UNIFI_SHARED_IO_INTERRUPT: %d\n", r);
+        func_exit_r(r);
+        return r;
+    }
+
+    card->unifi_interrupt_seq++;
+
+    func_exit();
+    return CSR_RESULT_SUCCESS;
+} /* CardGenInt() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CardEnableInt
+ *
+ *      Enable the outgoing SDIO interrupt from UniFi to the host.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS            on success,
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE      if the card was ejected
+ *      CSR_RESULT_FAILURE            if an SDIO error occurred,
+ * ---------------------------------------------------------------------------
+ */
+CsrResult CardEnableInt(card_t *card)
+{
+    CsrResult r;
+    CsrUint8 int_enable;
+
+    r = sdio_read_f0(card, SDIO_INT_ENABLE, &int_enable);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "SDIO error reading SDIO_INT_ENABLE\n");
+        return r;
+    }
+
+    int_enable |= (1 << card->function) | UNIFI_SD_INT_ENABLE_IENM;
+
+    r = sdio_write_f0(card, SDIO_INT_ENABLE, int_enable);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "SDIO error writing SDIO_INT_ENABLE\n");
+        return r;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CardEnableInt() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CardDisableInt
+ *
+ *      Disable the outgoing SDIO interrupt from UniFi to the host.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS            on success,
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE      if the card was ejected
+ *      CSR_RESULT_FAILURE            if an SDIO error occurred,
+ * ---------------------------------------------------------------------------
+ */
+CsrResult CardDisableInt(card_t *card)
+{
+    CsrResult r;
+    CsrUint8 int_enable;
+
+    r = sdio_read_f0(card, SDIO_INT_ENABLE, &int_enable);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "SDIO error reading SDIO_INT_ENABLE\n");
+        return r;
+    }
+
+    int_enable &= ~(1 << card->function);
+
+    r = sdio_write_f0(card, SDIO_INT_ENABLE, int_enable);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "SDIO error writing SDIO_INT_ENABLE\n");
+        return r;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CardDisableInt() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CardPendingInt
+ *
+ *      Determine whether UniFi is currently asserting the SDIO interrupt
+ *      request.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *      pintr           Pointer to location to write interrupt status,
+ *                          TRUE if interrupt pending,
+ *                          FALSE if no interrupt pending.
+ *  Returns:
+ *      CSR_RESULT_SUCCESS            interrupt status read successfully
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE      if the card was ejected
+ *      CSR_RESULT_FAILURE            if an SDIO error occurred,
+ * ---------------------------------------------------------------------------
+ */
+CsrResult CardPendingInt(card_t *card, CsrBool *pintr)
+{
+    CsrResult r;
+    CsrUint8 pending;
+
+    *pintr = FALSE;
+
+    r = sdio_read_f0(card, SDIO_INT_PENDING, &pending);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "SDIO error reading SDIO_INT_PENDING\n");
+        return r;
+    }
+
+    *pintr = (pending & (1 << card->function))?TRUE : FALSE;
+
+    return CSR_RESULT_SUCCESS;
+} /* CardPendingInt() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CardClearInt
+ *
+ *      Clear the UniFi SDIO interrupt request.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS          if pending interrupt was cleared, or no pending interrupt.
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE    if the card was ejected
+ *      CSR_RESULT_FAILURE          if an SDIO error occurred,
+ * ---------------------------------------------------------------------------
+ */
+CsrResult CardClearInt(card_t *card)
+{
+    CsrResult r;
+    CsrBool intr;
+
+    if (card->chip_id > SDIO_CARD_ID_UNIFI_2)
+    {
+        /* CardPendingInt() sets intr, if there is a pending interrupt */
+        r = CardPendingInt(card, &intr);
+        if (intr == FALSE)
+        {
+            return r;
+        }
+
+        r = sdio_write_f0(card, SDIO_CSR_HOST_INT_CLEAR, 1);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "SDIO error writing SDIO_CSR_HOST_INT_CLEAR\n");
+        }
+    }
+    else
+    {
+        r = unifi_write_direct_8_or_16(card,
+                                       ChipHelper_SDIO_HOST_INT(card->helper) * 2,
+                                       0);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "SDIO error writing UNIFI_SDIO_HOST_INT\n");
+        }
+    }
+
+    return r;
+} /* CardClearInt() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CardIntEnabled
+ *
+ *      Determine whether UniFi is currently asserting the SDIO interrupt
+ *      request.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *      enabled         Pointer to location to write interrupt enable status,
+ *                          TRUE if interrupts enabled,
+ *                          FALSE if interupts disabled.
+ *
+ *  Returns:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE      if the card was ejected
+ *      CSR_RESULT_FAILURE            if an SDIO error occurred,
+ * ---------------------------------------------------------------------------
+ */
+CsrResult CardIntEnabled(card_t *card, CsrBool *enabled)
+{
+    CsrResult r;
+    CsrUint8 int_enable;
+
+    r = sdio_read_f0(card, SDIO_INT_ENABLE, &int_enable);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "SDIO error reading SDIO_INT_ENABLE\n");
+        return r;
+    }
+
+    *enabled = (int_enable & (1 << card->function))?TRUE : FALSE;
+
+    return CSR_RESULT_SUCCESS;
+} /* CardIntEnabled() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CardWriteBulkData
+ *      Allocate slot in the pending bulkdata arrays and assign it to a signal's
+ *      bulkdata reference. The slot is then ready for UniFi's bulkdata commands
+ *      to transfer the data to/from the host.
+ *
+ *  Arguments:
+ *      card            Pointer to Card object
+ *      csptr           Pending signal pointer, including bulkdata ref
+ *      queue           Traffic queue that this signal is using
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS if a free slot was assigned
+ *      CSR_RESULT_FAILURE if no slot was available
+ * ---------------------------------------------------------------------------
+ */
+CsrResult CardWriteBulkData(card_t *card, card_signal_t *csptr, unifi_TrafficQueue queue)
+{
+    CsrUint16 i, slots[UNIFI_MAX_DATA_REFERENCES], j = 0;
+    CsrUint8 *packed_sigptr, num_slots_required = 0;
+    bulk_data_desc_t *bulkdata = csptr->bulkdata;
+    CsrInt16 h, nslots;
+
+    func_enter();
+
+    /* Count the number of slots required */
+    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++)
+    {
+        if (bulkdata[i].data_length != 0)
+        {
+            num_slots_required++;
+        }
+    }
+
+    /* Get the slot numbers */
+    if (num_slots_required != 0)
+    {
+        /* Last 2 slots for MLME */
+        if (queue == UNIFI_TRAFFIC_Q_MLME)
+        {
+            h = card->config_data.num_fromhost_data_slots - UNIFI_RESERVED_COMMAND_SLOTS;
+            for (i = 0; i < card->config_data.num_fromhost_data_slots; i++)
+            {
+                if (card->from_host_data[h].bd.data_length == 0)
+                {
+                    /* Free data slot, claim it */
+                    slots[j++] = h;
+                    if (j == num_slots_required)
+                    {
+                        break;
+                    }
+                }
+
+                if (++h >= card->config_data.num_fromhost_data_slots)
+                {
+                    h = 0;
+                }
+            }
+        }
+        else
+        {
+            if (card->dynamic_slot_data.from_host_used_slots[queue]
+                < card->dynamic_slot_data.from_host_max_slots[queue])
+            {
+                /* Data commands get a free slot only after a few checks */
+                nslots = card->config_data.num_fromhost_data_slots - UNIFI_RESERVED_COMMAND_SLOTS;
+
+                h = card->from_host_data_head;
+
+                for (i = 0; i < nslots; i++)
+                {
+                    if (card->from_host_data[h].bd.data_length == 0)
+                    {
+                        /* Free data slot, claim it */
+                        slots[j++] = h;
+                        if (j == num_slots_required)
+                        {
+                            break;
+                        }
+                    }
+
+                    if (++h >= nslots)
+                    {
+                        h = 0;
+                    }
+                }
+                card->from_host_data_head = h;
+            }
+        }
+
+        /* Required number of slots are not available, bail out */
+        if (j != num_slots_required)
+        {
+            unifi_trace(card->ospriv, UDBG5, "CardWriteBulkData: didn't find free slot/s\n");
+
+            /* If we haven't already reached the stable state we can ask for reservation */
+            if ((queue != UNIFI_TRAFFIC_Q_MLME) && (card->dynamic_slot_data.queue_stable[queue] == FALSE))
+            {
+                CardCheckDynamicReservation(card, queue);
+            }
+
+            for (i = 0; i < card->config_data.num_fromhost_data_slots; i++)
+            {
+                unifi_trace(card->ospriv, UDBG5, "fh data slot %d: %d\n", i, card->from_host_data[i].bd.data_length);
+            }
+            func_exit();
+            return CSR_RESULT_FAILURE;
+        }
+    }
+
+    packed_sigptr = csptr->sigbuf;
+
+    /* Fill in the slots with data */
+    j = 0;
+    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++)
+    {
+        if (bulkdata[i].data_length == 0)
+        {
+            /* Zero-out the DATAREF in the signal */
+            SET_PACKED_DATAREF_SLOT(packed_sigptr, i, 0);
+            SET_PACKED_DATAREF_LEN(packed_sigptr, i, 0);
+        }
+        else
+        {
+            /*
+             * Fill in the slot number in the SIGNAL structure but
+             * preserve the offset already in there
+             */
+            SET_PACKED_DATAREF_SLOT(packed_sigptr, i, slots[j] | (((CsrUint16)packed_sigptr[SIZEOF_SIGNAL_HEADER + (i * SIZEOF_DATAREF) + 1]) << 8));
+            SET_PACKED_DATAREF_LEN(packed_sigptr, i, bulkdata[i].data_length);
+
+            /* Do not copy the data, just store the information to them */
+            card->from_host_data[slots[j]].bd.os_data_ptr = bulkdata[i].os_data_ptr;
+            card->from_host_data[slots[j]].bd.os_net_buf_ptr = bulkdata[i].os_net_buf_ptr;
+            card->from_host_data[slots[j]].bd.data_length = bulkdata[i].data_length;
+            card->from_host_data[slots[j]].bd.net_buf_length = bulkdata[i].net_buf_length;
+            card->from_host_data[slots[j]].queue = queue;
+
+            unifi_trace(card->ospriv, UDBG4, "CardWriteBulkData sig=0x%x, fh slot %d = %p\n",
+                        GET_SIGNAL_ID(packed_sigptr), i, bulkdata[i].os_data_ptr);
+
+            /* Sanity-check that the bulk data desc being assigned to the slot
+             * actually has a payload.
+             */
+            if (!bulkdata[i].os_data_ptr)
+            {
+                unifi_error(card->ospriv, "Assign null os_data_ptr (len=%d) fh slot %d, i=%d, q=%d, sig=0x%x",
+                            bulkdata[i].data_length, slots[j], i, queue, GET_SIGNAL_ID(packed_sigptr));
+            }
+
+            j++;
+            if (queue < UNIFI_NO_OF_TX_QS)
+            {
+                card->dynamic_slot_data.from_host_used_slots[queue]++;
+            }
+        }
+    }
+
+    func_exit();
+
+    return CSR_RESULT_SUCCESS;
+} /*  CardWriteBulkData() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  card_find_data_slot
+ *
+ *      Dereference references to bulk data slots into pointers to real data.
+ *
+ *  Arguments:
+ *      card            Pointer to the card struct.
+ *      slot            Slot number from a signal structure
+ *
+ *  Returns:
+ *      Pointer to entry in bulk_data_slot array.
+ * ---------------------------------------------------------------------------
+ */
+bulk_data_desc_t* card_find_data_slot(card_t *card, CsrInt16 slot)
+{
+    CsrInt16 sn;
+    bulk_data_desc_t *bd;
+
+    sn = slot & 0x7FFF;
+
+    /* ?? check sanity of slot number ?? */
+
+    if (slot & SLOT_DIR_TO_HOST)
+    {
+        bd = &card->to_host_data[sn];
+    }
+    else
+    {
+        bd = &card->from_host_data[sn].bd;
+    }
+
+    return bd;
+} /* card_find_data_slot() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  firmware_present_in_flash
+ *
+ *      Probe for external Flash that looks like it might contain firmware.
+ *
+ *      If Flash is not present, reads always return 0x0008.
+ *      If Flash is present, but empty, reads return 0xFFFF.
+ *      Anything else is considered to be firmware.
+ *
+ *  Arguments:
+ *      card        Pointer to card struct
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS                 firmware is present in ROM or flash
+ *      CSR_WIFI_HIP_RESULT_NOT_FOUND      firmware is not present in ROM or flash
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE      if the card was ejected
+ *      CSR_RESULT_FAILURE                 if an SDIO error occurred
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult firmware_present_in_flash(card_t *card)
+{
+    CsrResult r;
+    CsrUint16 m1, m5;
+
+    if (ChipHelper_HasRom(card->helper))
+    {
+        return CSR_RESULT_SUCCESS;
+    }
+    if (!ChipHelper_HasFlash(card->helper))
+    {
+        return CSR_WIFI_HIP_RESULT_NOT_FOUND;
+    }
+
+    /*
+     * Examine the Flash locations that are the power-on default reset
+     * vectors of the XAP processors.
+     * These are words 1 and 5 in Flash.
+     */
+    r = unifi_card_read16(card, UNIFI_MAKE_GP(EXT_FLASH, 2), &m1);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+    r = unifi_card_read16(card, UNIFI_MAKE_GP(EXT_FLASH, 10), &m5);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+    /* Check for uninitialised/missing flash */
+    if ((m1 == 0x0008) || (m1 == 0xFFFF) ||
+        (m1 == 0x0004) || (m5 == 0x0004) ||
+        (m5 == 0x0008) || (m5 == 0xFFFF))
+    {
+        return CSR_WIFI_HIP_RESULT_NOT_FOUND;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* firmware_present_in_flash() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  bootstrap_chip_hw
+ *
+ *      Perform chip specific magic to "Get It Working" TM.  This will
+ *      increase speed of PLLs in analogue and maybe enable some
+ *      on-chip regulators.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void bootstrap_chip_hw(card_t *card)
+{
+    const struct chip_helper_init_values *vals;
+    CsrUint32 i, len;
+    void *sdio = card->sdio_if;
+    CsrResult csrResult;
+
+    len = ChipHelper_ClockStartupSequence(card->helper, &vals);
+    if (len != 0)
+    {
+        for (i = 0; i < len; i++)
+        {
+            csrResult = CsrSdioWrite16(sdio, vals[i].addr * 2, vals[i].value);
+            if (csrResult != CSR_RESULT_SUCCESS)
+            {
+                unifi_warning(card->ospriv, "Failed to write bootstrap value %d\n", i);
+                /* Might not be fatal */
+            }
+
+            CsrThreadSleep(1);
+        }
+    }
+} /* bootstrap_chip_hw() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_card_stop_processor
+ *
+ *      Stop the UniFi XAP processors.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      which           One of UNIFI_PROC_MAC, UNIFI_PROC_PHY, UNIFI_PROC_BOTH
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS if successful, or CSR error code
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_card_stop_processor(card_t *card, enum unifi_dbg_processors_select which)
+{
+    CsrResult r = CSR_RESULT_SUCCESS;
+    CsrUint8 status;
+    CsrInt16 retry = 100;
+
+    while (retry--)
+    {
+        /* Select both XAPs */
+        r = unifi_set_proc_select(card, which);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            break;
+        }
+
+        /* Stop processors */
+        r = unifi_write_direct16(card, ChipHelper_DBG_EMU_CMD(card->helper) * 2, 2);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            break;
+        }
+
+        /* Read status */
+        r = unifi_read_direct_8_or_16(card,
+                                      ChipHelper_DBG_HOST_STOP_STATUS(card->helper) * 2,
+                                      &status);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            break;
+        }
+
+        if ((status & 1) == 1)
+        {
+            /* Success! */
+            return CSR_RESULT_SUCCESS;
+        }
+
+        /* Processors didn't stop, try again */
+    }
+
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        /* An SDIO error occurred */
+        unifi_error(card->ospriv, "Failed to stop processors: SDIO error\n");
+    }
+    else
+    {
+        /* If we reach here, we didn't the status in time. */
+        unifi_error(card->ospriv, "Failed to stop processors: timeout waiting for stopped status\n");
+        r = CSR_RESULT_FAILURE;
+    }
+
+    return r;
+} /* unifi_card_stop_processor() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  card_start_processor
+ *
+ *      Start the UniFi XAP processors.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      which           One of UNIFI_PROC_MAC, UNIFI_PROC_PHY, UNIFI_PROC_BOTH
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS or CSR error code
+ * ---------------------------------------------------------------------------
+ */
+CsrResult card_start_processor(card_t *card, enum unifi_dbg_processors_select which)
+{
+    CsrResult r;
+
+    /* Select both XAPs */
+    r = unifi_set_proc_select(card, which);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "unifi_set_proc_select failed: %d.\n", r);
+        return r;
+    }
+
+
+    r = unifi_write_direct_8_or_16(card,
+                                   ChipHelper_DBG_EMU_CMD(card->helper) * 2, 8);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+    r = unifi_write_direct_8_or_16(card,
+                                   ChipHelper_DBG_EMU_CMD(card->helper) * 2, 0);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* card_start_processor() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_set_interrupt_mode
+ *
+ *      Configure the interrupt processing mode used by the HIP
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      mode            Interrupt mode to apply
+ *
+ *  Returns:
+ *      None
+ * ---------------------------------------------------------------------------
+ */
+void unifi_set_interrupt_mode(card_t *card, CsrUint32 mode)
+{
+    if (mode == CSR_WIFI_INTMODE_RUN_BH_ONCE)
+    {
+        unifi_info(card->ospriv, "Scheduled interrupt mode");
+    }
+    card->intmode = mode;
+} /* unifi_set_interrupt_mode() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_start_processors
+ *
+ *      Start all UniFi XAP processors.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR error code on error
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_start_processors(card_t *card)
+{
+    return card_start_processor(card, UNIFI_PROC_BOTH);
+} /* unifi_start_processors() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_request_max_sdio_clock
+ *
+ *      Requests that the maximum SDIO clock rate is set at the next suitable
+ *      opportunity (e.g. when the BH next runs, so as not to interfere with
+ *      any current operation).
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ *      None
+ * ---------------------------------------------------------------------------
+ */
+void unifi_request_max_sdio_clock(card_t *card)
+{
+    card->request_max_clock = 1;
+} /* unifi_request_max_sdio_clock() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_set_host_state
+ *
+ *      Set the host deep-sleep state.
+ *
+ *      If transitioning to TORPID, the SDIO driver will be notified
+ *      that the SD bus will be unused (idle) and conversely, when
+ *      transitioning from TORPID that the bus will be used (active).
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      state           New deep-sleep state.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS            on success
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE      if the card was ejected
+ *      CSR_RESULT_FAILURE            if an SDIO error occurred
+ *
+ *  Notes:
+ *      We need to reduce the SDIO clock speed before trying to wake up the
+ *      chip. Actually, in the implementation below we reduce the clock speed
+ *      not just before we try to wake up the chip, but when we put the chip to
+ *      deep sleep. This means that if the f/w wakes up on its' own, we waste
+ *      a reduce/increace cycle. However, trying to eliminate this overhead is
+ *      proved difficult, as the current state machine in the HIP lib does at
+ *      least a CMD52 to disable the interrupts before we configure the host
+ *      state.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_set_host_state(card_t *card, enum unifi_host_state state)
+{
+    CsrResult r = CSR_RESULT_SUCCESS;
+    CsrResult csrResult;
+    static const CsrCharString *const states[] = {
+        "AWAKE", "DROWSY", "TORPID"
+    };
+    static const CsrUint8 state_csr_host_wakeup[] = {
+        1, 3, 0
+    };
+    static const CsrUint8 state_io_abort[] = {
+        0, 2, 3
+    };
+
+    unifi_trace(card->ospriv, UDBG4, "State %s to %s\n",
+                states[card->host_state], states[state]);
+
+    if (card->host_state == UNIFI_HOST_STATE_TORPID)
+    {
+        CsrSdioFunctionActive(card->sdio_if);
+    }
+
+    /* Write the new state to UniFi. */
+    if (card->chip_id > SDIO_CARD_ID_UNIFI_2)
+    {
+        r = sdio_write_f0(card, SDIO_CSR_HOST_WAKEUP,
+                          (CsrUint8)((card->function << 4) | state_csr_host_wakeup[state]));
+    }
+    else
+    {
+        r = sdio_write_f0(card, SDIO_IO_ABORT, state_io_abort[state]);
+    }
+
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to write UniFi deep sleep state\n");
+    }
+    else
+    {
+        /*
+         * If the chip was in state TORPID then we can now increase
+         * the maximum bus clock speed.
+         */
+        if (card->host_state == UNIFI_HOST_STATE_TORPID)
+        {
+            csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if,
+                                                       UNIFI_SDIO_CLOCK_MAX_HZ);
+            r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+            /* Non-fatal error */
+            if (r != CSR_RESULT_SUCCESS && r != CSR_WIFI_HIP_RESULT_NO_DEVICE)
+            {
+                unifi_warning(card->ospriv,
+                              "Failed to increase the SDIO clock speed\n");
+            }
+            else
+            {
+                card->sdio_clock_speed = UNIFI_SDIO_CLOCK_MAX_HZ;
+            }
+        }
+
+        /*
+         * Cache the current state in the card structure to avoid
+         * unnecessary SDIO reads.
+         */
+        card->host_state = state;
+
+        if (state == UNIFI_HOST_STATE_TORPID)
+        {
+            /*
+             * If the chip is now in state TORPID then we must now decrease
+             * the maximum bus clock speed.
+             */
+            csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if,
+                                                       UNIFI_SDIO_CLOCK_SAFE_HZ);
+            r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+            if (r != CSR_RESULT_SUCCESS && r != CSR_WIFI_HIP_RESULT_NO_DEVICE)
+            {
+                unifi_warning(card->ospriv,
+                              "Failed to decrease the SDIO clock speed\n");
+            }
+            else
+            {
+                card->sdio_clock_speed = UNIFI_SDIO_CLOCK_SAFE_HZ;
+            }
+            CsrSdioFunctionIdle(card->sdio_if);
+        }
+    }
+
+    return r;
+} /* unifi_set_host_state() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_card_info
+ *
+ *      Update the card information data structure
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      card_info       Pointer to info structure to update
+ *
+ *  Returns:
+ *      None
+ * ---------------------------------------------------------------------------
+ */
+void unifi_card_info(card_t *card, card_info_t *card_info)
+{
+    card_info->chip_id = card->chip_id;
+    card_info->chip_version = card->chip_version;
+    card_info->fw_build = card->build_id;
+    card_info->fw_hip_version = card->config_data.version;
+    card_info->sdio_block_size = card->sdio_io_block_size;
+} /* unifi_card_info() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_check_io_status
+ *
+ *      Check UniFi for spontaneous reset and pending interrupt.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      status          Pointer to location to write chip status:
+ *                        0 if UniFi is running, and no interrupt pending
+ *                        1 if UniFi has spontaneously reset
+ *                        2 if there is a pending interrupt
+ *  Returns:
+ *      CSR_RESULT_SUCCESS if OK, or CSR error
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_check_io_status(card_t *card, CsrInt32 *status)
+{
+    CsrUint8 io_en;
+    CsrResult r;
+    CsrBool pending;
+
+    *status = 0;
+
+    r = sdio_read_f0(card, SDIO_IO_ENABLE, &io_en);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to read SDIO_IO_ENABLE to check for spontaneous reset\n");
+        return r;
+    }
+
+    if ((io_en & (1 << card->function)) == 0)
+    {
+        CsrInt32 fw_count;
+        *status = 1;
+        unifi_error(card->ospriv, "UniFi has spontaneously reset.\n");
+
+        /*
+         * These reads are very likely to fail. We want to know if the function is really
+         * disabled or the SDIO driver just returns rubbish.
+         */
+        fw_count = unifi_read_shared_count(card, card->sdio_ctrl_addr + 4);
+        if (fw_count < 0)
+        {
+            unifi_error(card->ospriv, "Failed to read to-host sig written count\n");
+        }
+        else
+        {
+            unifi_error(card->ospriv, "thsw: %u (driver thinks is %u)\n",
+                        fw_count, card->to_host_signals_w);
+        }
+        fw_count = unifi_read_shared_count(card, card->sdio_ctrl_addr + 2);
+        if (fw_count < 0)
+        {
+            unifi_error(card->ospriv, "Failed to read from-host sig read count\n");
+        }
+        else
+        {
+            unifi_error(card->ospriv, "fhsr: %u (driver thinks is %u)\n",
+                        fw_count, card->from_host_signals_r);
+        }
+
+        return r;
+    }
+
+    unifi_info(card->ospriv, "UniFi function %d is enabled.\n", card->function);
+
+    /* See if we missed an SDIO interrupt */
+    r = CardPendingInt(card, &pending);
+    if (pending)
+    {
+        unifi_error(card->ospriv, "There is an unhandled pending interrupt.\n");
+        *status = 2;
+        return r;
+    }
+
+    return r;
+} /* unifi_check_io_status() */
+
+
+void unifi_get_hip_qos_info(card_t *card, unifi_HipQosInfo *hipqosinfo)
+{
+    CsrInt32 count_fhr;
+    CsrInt16 t;
+    CsrUint32 occupied_fh;
+
+    q_t *sigq;
+    CsrUint16 nslots, i;
+
+    CsrMemSet(hipqosinfo, 0, sizeof(unifi_HipQosInfo));
+
+    nslots = card->config_data.num_fromhost_data_slots;
+
+    for (i = 0; i < nslots; i++)
+    {
+        if (card->from_host_data[i].bd.data_length == 0)
+        {
+            hipqosinfo->free_fh_bulkdata_slots++;
+        }
+    }
+
+    for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
+    {
+        sigq = &card->fh_traffic_queue[i];
+        t = sigq->q_wr_ptr - sigq->q_rd_ptr;
+        if (t < 0)
+        {
+            t += sigq->q_length;
+        }
+        hipqosinfo->free_fh_sig_queue_slots[i] = (sigq->q_length - t) - 1;
+    }
+
+    count_fhr = unifi_read_shared_count(card, card->sdio_ctrl_addr + 2);
+    if (count_fhr < 0)
+    {
+        unifi_error(card->ospriv, "Failed to read from-host sig read count - %d\n", count_fhr);
+        hipqosinfo->free_fh_fw_slots = 0xfa;
+        return;
+    }
+
+    occupied_fh = (card->from_host_signals_w - count_fhr) % 128;
+
+    hipqosinfo->free_fh_fw_slots = (CsrUint16)(card->config_data.num_fromhost_sig_frags - occupied_fh);
+}
+
+
+
+CsrResult ConvertCsrSdioToCsrHipResult(card_t *card, CsrResult csrResult)
+{
+    CsrResult r = CSR_RESULT_FAILURE;
+
+    switch (csrResult)
+    {
+        case CSR_RESULT_SUCCESS:
+            r = CSR_RESULT_SUCCESS;
+            break;
+        /* Timeout errors */
+        case CSR_SDIO_RESULT_TIMEOUT:
+        /* Integrity errors */
+        case CSR_SDIO_RESULT_CRC_ERROR:
+            r = CSR_RESULT_FAILURE;
+            break;
+        case CSR_SDIO_RESULT_NO_DEVICE:
+            r = CSR_WIFI_HIP_RESULT_NO_DEVICE;
+            break;
+        case CSR_SDIO_RESULT_INVALID_VALUE:
+            r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            break;
+        case CSR_RESULT_FAILURE:
+            r = CSR_RESULT_FAILURE;
+            break;
+        default:
+            unifi_warning(card->ospriv, "Unrecognised csrResult error code: %d\n", csrResult);
+            break;
+    }
+
+    return r;
+} /* ConvertCsrSdioToCsrHipResult() */
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_card_sdio.h b/drivers/staging/csr/csr_wifi_hip_card_sdio.h
new file mode 100644
index 0000000..4481d81
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_card_sdio.h
@@ -0,0 +1,702 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ *  FILE:     csr_wifi_hip_card_sdio.h
+ *
+ *  PURPOSE:
+ *      Internal header for Card API for SDIO.
+ * ---------------------------------------------------------------------------
+ */
+#ifndef __CARD_SDIO_H__
+#define __CARD_SDIO_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_unifi_udi.h"
+#include "csr_wifi_hip_unifihw.h"
+#include "csr_wifi_hip_unifiversion.h"
+#ifndef CSR_WIFI_HIP_TA_DISABLE
+#include "csr_wifi_hip_ta_sampling.h"
+#endif
+#include "csr_wifi_hip_xbv.h"
+#include "csr_wifi_hip_chiphelper.h"
+
+
+/*
+ *
+ * Configuration items.
+ * Which of these should go in a platform unifi_config.h file?
+ *
+ */
+
+/*
+ * When the traffic queues contain more signals than there is space for on
+ * UniFi, a limiting algorithm comes into play.
+ * If a traffic queue has enough slots free to buffer more traffic from the
+ * network stack, then the following check is applied. The number of free
+ * slots is RESUME_XMIT_THRESHOLD.
+ */
+#define RESUME_XMIT_THRESHOLD           4
+
+
+/*
+ * When reading signals from UniFi, the host processes pending all signals
+ * and then acknowledges them together in a single write to update the
+ * to-host-chunks-read location.
+ * When there is more than one bulk data transfer (e.g. one received data
+ * packet and a request for the payload data of a transmitted packet), the
+ * update can be delayed significantly. This ties up resources on chip.
+ *
+ * To remedy this problem, to-host-chunks-read is updated after processing
+ * a signal if TO_HOST_FLUSH_THRESHOLD bytes of bulk data have been
+ * transferred since the last update.
+ */
+#define TO_HOST_FLUSH_THRESHOLD (500 * 5)
+
+
+/* SDIO Card Common Control Registers */
+#define SDIO_CCCR_SDIO_REVISION     (0x00)
+#define SDIO_SD_SPEC_REVISION       (0x01)
+#define SDIO_IO_ENABLE              (0x02)
+#define SDIO_IO_READY               (0x03)
+#define SDIO_INT_ENABLE             (0x04)
+#define SDIO_INT_PENDING            (0x05)
+#define SDIO_IO_ABORT               (0x06)
+#define SDIO_BUS_IFACE_CONTROL      (0x07)
+#define SDIO_CARD_CAPABILOTY        (0x08)
+#define SDIO_COMMON_CIS_POINTER     (0x09)
+#define SDIO_BUS_SUSPEND            (0x0C)
+#define SDIO_FUNCTION_SELECT        (0x0D)
+#define SDIO_EXEC_FLAGS             (0x0E)
+#define SDIO_READY_FLAGS            (0x0F)
+#define SDIO_FN0_BLOCK_SIZE         (0x10)
+#define SDIO_POWER_CONTROL          (0x12)
+#define SDIO_VENDOR_START           (0xF0)
+
+#define SDIO_CSR_HOST_WAKEUP        (0xf0)
+#define SDIO_CSR_HOST_INT_CLEAR     (0xf1)
+#define SDIO_CSR_FROM_HOST_SCRATCH0 (0xf2)
+#define SDIO_CSR_FROM_HOST_SCRATCH1 (0xf3)
+#define SDIO_CSR_TO_HOST_SCRATCH0   (0xf4)
+#define SDIO_CSR_TO_HOST_SCRATCH1   (0xf5)
+#define SDIO_CSR_FUNC_EN            (0xf6)
+#define SDIO_CSR_CSPI_MODE          (0xf7)
+#define SDIO_CSR_CSPI_STATUS        (0xf8)
+#define SDIO_CSR_CSPI_PADDING       (0xf9)
+
+
+#define UNIFI_SD_INT_ENABLE_IENM 0x0001    /* Master INT Enable */
+
+#ifdef CSR_PRE_ALLOC_NET_DATA
+#define BULK_DATA_PRE_ALLOC_NUM 16
+#endif
+
+/*
+ * Structure to hold configuration information read from UniFi.
+ */
+typedef struct
+{
+    /*
+     * The version of the SDIO signal queues and bulk data pools
+     * configuration structure. The MSB is the major version number, used to
+     * indicate incompatible changes. The LSB gives the minor revision number,
+     * used to indicate changes that maintain backwards compatibility.
+     */
+    CsrUint16 version;
+
+    /*
+     * offset from the start of the shared data memory to the SD IO
+     * control structure.
+     */
+    CsrUint16 sdio_ctrl_offset;
+
+    /* Buffer handle of the from-host signal queue */
+    CsrUint16 fromhost_sigbuf_handle;
+
+    /* Buffer handle of the to-host signal queue */
+    CsrUint16 tohost_sigbuf_handle;
+
+    /*
+     * Maximum number of signal primitive or bulk data command fragments that may be
+     * pending in the to-hw signal queue.
+     */
+    CsrUint16 num_fromhost_sig_frags;
+
+    /*
+     * Number of signal primitive or bulk data command fragments that must be pending
+     * in the to-host signal queue before the host will generate an interrupt
+     * to indicate that it has read a signal. This will usually be the total
+     * capacity of the to-host signal buffer less the size of the largest signal
+     * primitive divided by the signal primitive fragment size, but may be set
+     * to 1 to request interrupts every time that the host read a signal.
+     * Note that the hw may place more signals in the to-host signal queue
+     * than indicated by this field.
+     */
+    CsrUint16 num_tohost_sig_frags;
+
+    /*
+     * Number of to-hw bulk data slots. Slots are numbered from 0 (zero) to
+     * one less than the value in this field
+     */
+    CsrUint16 num_fromhost_data_slots;
+
+    /*
+     * Number of frm-hw bulk data slots. Slots are numbered from 0 (zero) to
+     * one less than the value in this field
+     */
+    CsrUint16 num_tohost_data_slots;
+
+    /*
+     * Size of the bulk data slots (2 octets)
+     * The size of the bulk data slots in octets. This will usually be
+     * the size of the largest MSDU. The value should always be even.
+     */
+    CsrUint16 data_slot_size;
+
+    /*
+     * Indicates that the host has finished the initialisation sequence.
+     * Initialised to 0x0000 by the firmware, and set to 0x0001 by us.
+     */
+    CsrUint16 initialised;
+
+    /* Added by protocol version 0x0001 */
+    CsrUint32 overlay_size;
+
+    /* Added by protocol version 0x0300 */
+    CsrUint16 data_slot_round;
+    CsrUint16 sig_frag_size;
+
+    /* Added by protocol version 0x0500 */
+    CsrUint16 tohost_signal_padding;
+} sdio_config_data_t;
+
+/*
+ * These values may change with versions of the Host Interface Protocol.
+ */
+/*
+ * Size of config info block pointed to by the CSR_SLT_SDIO_SLOT_CONFIG
+ * entry in the f/w symbol table
+ */
+#define SDIO_CONFIG_DATA_SIZE 30
+
+/* Offset of the INIT flag in the config info block. */
+#define SDIO_INIT_FLAG_OFFSET 0x12
+#define SDIO_TO_HOST_SIG_PADDING_OFFSET 0x1C
+
+
+/* Structure for a bulk data transfer command */
+typedef struct
+{
+    CsrUint16 cmd_and_len;   /* bits 12-15 cmd, bits 0-11 len */
+    CsrUint16 data_slot;     /* slot number, perhaps OR'd with SLOT_DIR_TO_HOST */
+    CsrUint16 offset;
+    CsrUint16 buffer_handle;
+} bulk_data_cmd_t;
+
+
+/* Bulk Data signal command values */
+#define SDIO_CMD_SIGNAL                 0x00
+#define SDIO_CMD_TO_HOST_TRANSFER       0x01
+#define SDIO_CMD_TO_HOST_TRANSFER_ACK   0x02 /*deprecated*/
+#define SDIO_CMD_FROM_HOST_TRANSFER     0x03
+#define SDIO_CMD_FROM_HOST_TRANSFER_ACK 0x04 /*deprecated*/
+#define SDIO_CMD_CLEAR_SLOT             0x05
+#define SDIO_CMD_OVERLAY_TRANSFER       0x06
+#define SDIO_CMD_OVERLAY_TRANSFER_ACK   0x07 /*deprecated*/
+#define SDIO_CMD_FROM_HOST_AND_CLEAR    0x08
+#define SDIO_CMD_PADDING                0x0f
+
+#define SLOT_DIR_TO_HOST 0x8000
+
+
+/* Initialise bulkdata slot
+ *  params:
+ *      bulk_data_desc_t *bulk_data_slot
+ */
+#define UNIFI_INIT_BULK_DATA(bulk_data_slot)        \
+    {                                               \
+        (bulk_data_slot)->os_data_ptr = NULL;       \
+        (bulk_data_slot)->data_length = 0;          \
+        (bulk_data_slot)->os_net_buf_ptr = NULL;    \
+        (bulk_data_slot)->net_buf_length = 0;       \
+    }
+
+/*
+ * Structure to contain a SIGNAL datagram.
+ * This is used to build signal queues between the main driver and the
+ * i/o thread.
+ * The fields are:
+ *      sigbuf          Contains the HIP signal is wire-format (i.e. packed,
+ *                      little-endian)
+ *      bulkdata        Contains a copy of any associated bulk data
+ *      signal_length   The size of the signal in the sigbuf
+ */
+typedef struct card_signal
+{
+    CsrUint8 sigbuf[UNIFI_PACKED_SIGBUF_SIZE];
+
+    /* Length of the SIGNAL inside sigbuf */
+    CsrUint16 signal_length;
+
+    bulk_data_desc_t bulkdata[UNIFI_MAX_DATA_REFERENCES];
+} card_signal_t;
+
+
+/*
+ * Control structure for a generic ring buffer.
+ */
+#define UNIFI_QUEUE_NAME_MAX_LENGTH     16
+typedef struct
+{
+    card_signal_t *q_body;
+
+    /* Num elements in queue (capacity is one less than this!) */
+    CsrUint16 q_length;
+
+    CsrUint16 q_wr_ptr;
+    CsrUint16 q_rd_ptr;
+
+    CsrCharString name[UNIFI_QUEUE_NAME_MAX_LENGTH];
+} q_t;
+
+
+#define UNIFI_RESERVED_COMMAND_SLOTS   2
+
+/* Considering approx 500 us per packet giving 0.5 secs */
+#define UNIFI_PACKETS_INTERVAL         1000
+
+/*
+ * Dynamic slot reservation for QoS
+ */
+typedef struct
+{
+    CsrUint16 from_host_used_slots[UNIFI_NO_OF_TX_QS];
+    CsrUint16 from_host_max_slots[UNIFI_NO_OF_TX_QS];
+    CsrUint16 from_host_reserved_slots[UNIFI_NO_OF_TX_QS];
+
+    /* Parameters to determine if a queue was active.
+       If number of packets sent is greater than the threshold
+       for the queue, the queue is considered active and no
+       re reservation is done, it is important not to keep this
+       value too low */
+    /* Packets sent during this interval */
+    CsrUint16 packets_txed[UNIFI_NO_OF_TX_QS];
+    CsrUint16 total_packets_txed;
+
+    /* Number of packets to see if slots need to be reassigned */
+    CsrUint16 packets_interval;
+
+    /* Once a queue reaches a stable state, avoid processing */
+    CsrBool queue_stable[UNIFI_NO_OF_TX_QS];
+} card_dynamic_slot_t;
+
+
+/* These are type-safe and don't write incorrect values to the
+ * structure. */
+
+/* Return queue slots used count
+ *  params:
+ *      const q_t *q
+ *  returns:
+ *      CsrUint16
+ */
+#define CSR_WIFI_HIP_Q_SLOTS_USED(q)     \
+    (((q)->q_wr_ptr - (q)->q_rd_ptr < 0)? \
+     ((q)->q_wr_ptr - (q)->q_rd_ptr + (q)->q_length) : ((q)->q_wr_ptr - (q)->q_rd_ptr))
+
+/* Return queue slots free count
+ *  params:
+ *      const q_t *q
+ *  returns:
+ *      CsrUint16
+ */
+#define CSR_WIFI_HIP_Q_SLOTS_FREE(q)     \
+    ((q)->q_length - CSR_WIFI_HIP_Q_SLOTS_USED((q)) - 1)
+
+/* Return slot signal data pointer
+ *  params:
+ *      const q_t *q
+ *      CsrUint16 slot
+ *  returns:
+ *      card_signal_t *
+ */
+#define CSR_WIFI_HIP_Q_SLOT_DATA(q, slot)    \
+    ((q)->q_body + slot)
+
+/* Return queue next read slot
+ *  params:
+ *      const q_t *q
+ *  returns:
+ *      CsrUint16 slot offset
+ */
+#define CSR_WIFI_HIP_Q_NEXT_R_SLOT(q)    \
+    ((q)->q_rd_ptr)
+
+/* Return queue next write slot
+ *  params:
+ *      const q_t *q
+ *  returns:
+ *      CsrUint16 slot offset
+ */
+#define CSR_WIFI_HIP_Q_NEXT_W_SLOT(q)    \
+    ((q)->q_wr_ptr)
+
+/* Return updated queue pointer wrapped around its length
+ *  params:
+ *      const q_t *q
+ *      CsrUint16 x     amount to add to queue pointer
+ *  returns:
+ *      CsrUint16 wrapped queue pointer
+ */
+#define CSR_WIFI_HIP_Q_WRAP(q, x)    \
+    ((((x) >= (q)->q_length)?((x) % (q)->q_length) : (x)))
+
+/* Advance queue read pointer
+ *  params:
+ *      const q_t *q
+ */
+#define CSR_WIFI_HIP_Q_INC_R(q)  \
+    ((q)->q_rd_ptr = CSR_WIFI_HIP_Q_WRAP((q), (q)->q_rd_ptr + 1))
+
+/* Advance queue write pointer
+ *  params:
+ *      const q_t *q
+ */
+#define CSR_WIFI_HIP_Q_INC_W(q)  \
+    ((q)->q_wr_ptr = CSR_WIFI_HIP_Q_WRAP((q), (q)->q_wr_ptr + 1))
+
+enum unifi_host_state
+{
+    UNIFI_HOST_STATE_AWAKE   = 0,
+    UNIFI_HOST_STATE_DROWSY  = 1,
+    UNIFI_HOST_STATE_TORPID  = 2
+};
+
+typedef struct
+{
+    bulk_data_desc_t   bd;
+    unifi_TrafficQueue queue; /* Used for dynamic slot reservation */
+} slot_desc_t;
+
+/*
+ * Structure describing a UniFi SDIO card.
+ */
+struct card
+{
+    /*
+     * Back pointer for the higher level OS code. This is passed as
+     * an argument to callbacks (e.g. for received data and indications).
+     */
+    void *ospriv;
+
+    /*
+     * mapping of HIP slot to MA-PACKET.req host tag, the
+     * array is indexed by slot numbers and each index stores
+     * information of the last host tag it was used for
+     */
+    CsrUint32 *fh_slot_host_tag_record;
+
+
+    /* Info read from Symbol Table during probe */
+    CsrUint32     build_id;
+    CsrCharString build_id_string[128];
+
+    /* Retrieve from SDIO driver. */
+    CsrUint16 chip_id;
+
+    /* Read from GBL_CHIP_VERSION. */
+    CsrUint16 chip_version;
+
+    /* From the SDIO driver (probably 1) */
+    CsrUint8 function;
+
+    /* This is sused to get the register addresses and things. */
+    ChipDescript *helper;
+
+    /*
+     * Bit mask of PIOs for the loader to waggle during download.
+     * We assume these are connected to LEDs. The main firmware gets
+     * the mask from a MIB entry.
+     */
+    CsrInt32 loader_led_mask;
+
+    /*
+     * Support for flow control. When the from-host queue of signals
+     * is full, we ask the host upper layer to stop sending packets. When
+     * the queue drains we tell it that it can send packets again.
+     * We use this flag to remember the current state.
+     */
+#define card_is_tx_q_paused(card, q)   (card->tx_q_paused_flag[q])
+#define card_tx_q_unpause(card, q)   (card->tx_q_paused_flag[q] = 0)
+#define card_tx_q_pause(card, q)   (card->tx_q_paused_flag[q] = 1)
+
+    CsrUint16 tx_q_paused_flag[UNIFI_TRAFFIC_Q_MAX + 1 + UNIFI_NO_OF_TX_QS]; /* defensive more than big enough */
+
+    /* UDI callback for logging UniFi interactions */
+    udi_func_t udi_hook;
+
+    CsrUint8 bh_reason_host;
+    CsrUint8 bh_reason_unifi;
+
+    /* SDIO clock speed request from OS layer */
+    CsrUint8 request_max_clock;
+
+    /* Last SDIO clock frequency set */
+    CsrUint32 sdio_clock_speed;
+
+    /*
+     * Current host state (copy of value in IOABORT register and
+     * spinlock to protect it.
+     */
+    enum unifi_host_state host_state;
+
+    enum unifi_low_power_mode     low_power_mode;
+    enum unifi_periodic_wake_mode periodic_wake_mode;
+
+    /*
+     * Ring buffer of signal structs for a queue of data packets from
+     * the host.
+     * The queue is empty when fh_data_q_num_rd == fh_data_q_num_wr.
+     * To add a packet to the queue, copy it to index given by
+     * (fh_data_q_num_wr%UNIFI_SOFT_Q_LENGTH) and advance fh_data_q_num_wr.
+     * To take a packet from the queue, copy data from index given by
+     * (fh_data_q_num_rd%UNIFI_SOFT_Q_LENGTH) and advance fh_data_q_num_rd.
+     * fh_data_q_num_rd and fh_data_q_num_rd are both modulo 256.
+     */
+    card_signal_t fh_command_q_body[UNIFI_SOFT_COMMAND_Q_LENGTH];
+    q_t           fh_command_queue;
+
+    card_signal_t fh_traffic_q_body[UNIFI_NO_OF_TX_QS][UNIFI_SOFT_TRAFFIC_Q_LENGTH];
+    q_t           fh_traffic_queue[UNIFI_NO_OF_TX_QS];
+
+    /*
+     * Signal counts from UniFi SDIO Control Data Structure.
+     * These are cached and synchronised with the UniFi before and after
+     * a batch of operations.
+     *
+     * These are the modulo-256 count of signals written to or read from UniFi
+     * The value is incremented for every signal.
+     */
+    CsrInt32 from_host_signals_w;
+    CsrInt32 from_host_signals_r;
+    CsrInt32 to_host_signals_r;
+    CsrInt32 to_host_signals_w;
+
+
+    /* Should specify buffer size as a number of signals */
+    /*
+     * Enough for 10 th and 10 fh data slots:
+     *   1 * 10 * 8 =  80
+     *   2 * 10 * 8 = 160
+     */
+#define UNIFI_FH_BUF_SIZE 1024
+    struct sigbuf
+    {
+        CsrUint8 *buf;     /* buffer area */
+        CsrUint8 *ptr;     /* current pos */
+        CsrUint16 count;   /* signal count */
+        CsrUint16 bufsize;
+    } fh_buffer;
+    struct sigbuf th_buffer;
+
+
+    /*
+     * Field to use for the incrementing value to write to the UniFi
+     * SHARED_IO_INTERRUPT register.
+     * Flag to say we need to generate an interrupt at end of processing.
+     */
+    CsrUint32 unifi_interrupt_seq;
+    CsrUint8  generate_interrupt;
+
+
+    /* Pointers to the bulk data slots */
+    slot_desc_t      *from_host_data;
+    bulk_data_desc_t *to_host_data;
+
+
+    /*
+     * Index of the next (hopefully) free data slot.
+     * This is an optimisation that starts searching at a more likely point
+     * than the beginning.
+     */
+    CsrInt16 from_host_data_head;
+
+    /* Dynamic slot allocation for queues */
+    card_dynamic_slot_t dynamic_slot_data;
+
+    /*
+     * SDIO specific fields
+     */
+
+    /* Interface pointer for the SDIO library */
+    CsrSdioFunction *sdio_if;
+
+    /* Copy of config_data struct from the card */
+    sdio_config_data_t config_data;
+
+    /* SDIO address of the Initialised flag and Control Data struct */
+    CsrUint32 init_flag_addr;
+    CsrUint32 sdio_ctrl_addr;
+
+    /* The last value written to the Shared Data Memory Page register */
+    CsrUint32 proc_select;
+    CsrUint32 dmem_page;
+    CsrUint32 pmem_page;
+
+    /* SDIO traffic counters limited to 32 bits for Synergy compatibility */
+    CsrUint32 sdio_bytes_read;
+    CsrUint32 sdio_bytes_written;
+
+    CsrUint8 memory_resources_allocated;
+
+    /* UniFi SDIO I/O Block size. */
+    CsrUint16 sdio_io_block_size;
+
+    /* Pad transfer sizes to SDIO block boundaries */
+    CsrBool sdio_io_block_pad;
+
+    /* Read from the XBV */
+    struct FWOV fwov;
+
+#ifndef CSR_WIFI_HIP_TA_DISABLE
+    /* TA sampling */
+    ta_data_t ta_sampling;
+#endif
+
+    /* Auto-coredump */
+    CsrInt16             request_coredump_on_reset; /* request coredump on next reset */
+    struct coredump_buf *dump_buf;                  /* root node */
+    struct coredump_buf *dump_next_write;           /* node to fill at next dump */
+    struct coredump_buf *dump_cur_read;             /* valid node to read, or NULL */
+
+#ifdef CSR_WIFI_HIP_DATA_PLANE_PROFILE
+    struct cmd_profile
+    {
+        CsrUint32 cmd52_count;
+        CsrUint32 cmd53_count;
+        CsrUint32 tx_count;
+        CsrUint32 tx_cfm_count;
+        CsrUint32 rx_count;
+        CsrUint32 bh_count;
+        CsrUint32 process_count;
+        CsrUint32 protocol_count;
+
+        CsrUint32 cmd52_f0_r_count;
+        CsrUint32 cmd52_f0_w_count;
+        CsrUint32 cmd52_r8or16_count;
+        CsrUint32 cmd52_w8or16_count;
+        CsrUint32 cmd52_r16_count;
+        CsrUint32 cmd52_w16_count;
+        CsrUint32 cmd52_r32_count;
+
+        CsrUint32 sdio_cmd_signal;
+        CsrUint32 sdio_cmd_clear_slot;
+        CsrUint32 sdio_cmd_to_host;
+        CsrUint32 sdio_cmd_from_host;
+        CsrUint32 sdio_cmd_from_host_and_clear;
+    } hip_prof;
+    struct cmd_profile cmd_prof;
+#endif
+
+    /* Interrupt processing mode flags */
+    CsrUint32 intmode;
+
+#ifdef UNIFI_DEBUG
+    CsrUint8 lsb;
+#endif
+
+    /* Historic firmware panic codes */
+    CsrUint32 panic_data_phy_addr;
+    CsrUint32 panic_data_mac_addr;
+    CsrUint16 last_phy_panic_code;
+    CsrUint16 last_phy_panic_arg;
+    CsrUint16 last_mac_panic_code;
+    CsrUint16 last_mac_panic_arg;
+#ifdef CSR_PRE_ALLOC_NET_DATA
+    bulk_data_desc_t bulk_data_desc_list[BULK_DATA_PRE_ALLOC_NUM];
+    CsrUint16        prealloc_netdata_r;
+    CsrUint16        prealloc_netdata_w;
+#endif
+}; /* struct card */
+
+
+/* Reset types */
+enum unifi_reset_type
+{
+    UNIFI_COLD_RESET = 1,
+    UNIFI_WARM_RESET = 2
+};
+
+/*
+ * unifi_set_host_state() implements signalling for waking UniFi from
+ * deep sleep. The host indicates to UniFi that it is in one of three states:
+ *   Torpid - host has nothing to send, UniFi can go to sleep.
+ *   Drowsy - host has data to send to UniFi. UniFi will respond with an
+ *            SDIO interrupt. When hosts responds it moves to Awake.
+ *   Awake  - host has data to transfer, UniFi must stay awake.
+ *            When host has finished, it moves to Torpid.
+ */
+CsrResult unifi_set_host_state(card_t *card, enum unifi_host_state state);
+
+
+CsrResult unifi_set_proc_select(card_t *card, enum unifi_dbg_processors_select select);
+CsrInt32 card_read_signal_counts(card_t *card);
+bulk_data_desc_t* card_find_data_slot(card_t *card, CsrInt16 slot);
+
+
+CsrResult unifi_read32(card_t *card, CsrUint32 unifi_addr, CsrUint32 *pdata);
+CsrResult unifi_readnz(card_t *card, CsrUint32 unifi_addr,
+                       void *pdata, CsrUint16 len);
+CsrInt32 unifi_read_shared_count(card_t *card, CsrUint32 addr);
+
+CsrResult unifi_writen(card_t *card, CsrUint32 unifi_addr, void *pdata, CsrUint16 len);
+
+CsrResult unifi_bulk_rw(card_t *card, CsrUint32 handle,
+                        void *pdata, CsrUint32 len, CsrInt16 direction);
+CsrResult unifi_bulk_rw_noretry(card_t *card, CsrUint32 handle,
+                                void *pdata, CsrUint32 len, CsrInt16 direction);
+#define UNIFI_SDIO_READ       0
+#define UNIFI_SDIO_WRITE      1
+
+CsrResult unifi_read_8_or_16(card_t *card, CsrUint32 unifi_addr, CsrUint8 *pdata);
+CsrResult unifi_write_8_or_16(card_t *card, CsrUint32 unifi_addr, CsrUint8 data);
+CsrResult unifi_read_direct_8_or_16(card_t *card, CsrUint32 addr, CsrUint8 *pdata);
+CsrResult unifi_write_direct_8_or_16(card_t *card, CsrUint32 addr, CsrUint8 data);
+
+CsrResult unifi_read_direct16(card_t *card, CsrUint32 addr, CsrUint16 *pdata);
+CsrResult unifi_read_direct32(card_t *card, CsrUint32 addr, CsrUint32 *pdata);
+CsrResult unifi_read_directn(card_t *card, CsrUint32 addr, void *pdata, CsrUint16 len);
+
+CsrResult unifi_write_direct16(card_t *card, CsrUint32 addr, CsrUint16 data);
+CsrResult unifi_write_directn(card_t *card, CsrUint32 addr, void *pdata, CsrUint16 len);
+
+CsrResult sdio_read_f0(card_t *card, CsrUint32 addr, CsrUint8 *pdata);
+CsrResult sdio_write_f0(card_t *card, CsrUint32 addr, CsrUint8 data);
+
+void unifi_read_panic(card_t *card);
+#ifdef CSR_PRE_ALLOC_NET_DATA
+void prealloc_netdata_free(card_t *card);
+CsrResult prealloc_netdata_alloc(card_t *card);
+#endif
+/* For diagnostic use */
+void dump(void *mem, CsrUint16 len);
+void dump16(void *mem, CsrUint16 len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CARD_SDIO_H__ */
diff --git a/drivers/staging/csr/csr_wifi_hip_card_sdio_intr.c b/drivers/staging/csr/csr_wifi_hip_card_sdio_intr.c
new file mode 100644
index 0000000..8fefbdf
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_card_sdio_intr.c
@@ -0,0 +1,2579 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     csr_wifi_hip_card_sdio_intr.c
+ *
+ *  PURPOSE:
+ *      Interrupt processing for the UniFi SDIO driver.
+ *
+ *      We may need another signal queue of responses to UniFi to hold
+ *      bulk data commands generated by read_to_host_signals().
+ *
+ * ---------------------------------------------------------------------------
+ */
+#undef CSR_WIFI_HIP_NOISY
+
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_conversions.h"
+#include "csr_wifi_hip_card.h"
+#include "csr_wifi_hip_xbv.h"
+
+
+/*
+ * If the SDIO link is idle for this time (in milliseconds),
+ * signal UniFi to go into Deep Sleep.
+ * Valid return value of unifi_bh().
+ */
+#define UNIFI_DEFAULT_HOST_IDLE_TIMEOUT 5
+/*
+ * If the UniFi has not woken up for this time (in milliseconds),
+ * signal the bottom half to take action.
+ * Valid return value of unifi_bh().
+ */
+#define UNIFI_DEFAULT_WAKE_TIMEOUT      1000
+
+
+static CsrResult process_bh(card_t *card);
+static CsrResult handle_host_protocol(card_t *card, CsrBool *processed_something);
+
+static CsrResult flush_fh_buffer(card_t *card);
+
+static CsrResult check_fh_sig_slots(card_t *card, CsrUint16 needed, CsrInt32 *space);
+
+static CsrResult read_to_host_signals(card_t *card, CsrInt32 *processed);
+static CsrResult process_to_host_signals(card_t *card, CsrInt32 *processed);
+
+static CsrResult process_bulk_data_command(card_t *card,
+                                           const CsrUint8 *cmdptr,
+                                           CsrInt16 cmd, CsrUint16 len);
+static CsrResult process_clear_slot_command(card_t         *card,
+                                            const CsrUint8 *cmdptr);
+static CsrResult process_fh_cmd_queue(card_t *card, CsrInt32 *processed);
+static CsrResult process_fh_traffic_queue(card_t *card, CsrInt32 *processed);
+static void restart_packet_flow(card_t *card);
+static CsrResult process_clock_request(card_t *card);
+
+#ifdef CSR_WIFI_HIP_NOISY
+CsrInt16 dump_fh_buf = 0;
+#endif /* CSR_WIFI_HIP_NOISY */
+
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+
+/*
+ * The unifi_debug_output buffer can be used to debug the HIP behaviour offline
+ * i.e. without using the tracing functions that change the timing.
+ *
+ * Call unifi_debug_log_to_buf() with printf arguments to store a string into
+ * unifi_debug_output. When unifi_debug_buf_dump() is called, the contents of the
+ * buffer are dumped with dump_str() which has to be implemented in the
+ * OS layer, during the porting exercise. The offset printed, holds the
+ * offset where the last character is (always a zero).
+ *
+ */
+
+#define UNIFI_DEBUG_GBUFFER_SIZE       8192
+static CsrCharString unifi_debug_output[UNIFI_DEBUG_GBUFFER_SIZE];
+static CsrCharString *unifi_dbgbuf_ptr = unifi_debug_output;
+static CsrCharString *unifi_dbgbuf_start = unifi_debug_output;
+
+static void append_char(CsrCharString c)
+{
+    /* write char and advance pointer */
+    *unifi_dbgbuf_ptr++ = c;
+    /* wrap pointer at end of buffer */
+    if ((unifi_dbgbuf_ptr - unifi_debug_output) >= UNIFI_DEBUG_GBUFFER_SIZE)
+    {
+        unifi_dbgbuf_ptr = unifi_debug_output;
+    }
+} /* append_char() */
+
+
+void unifi_debug_string_to_buf(const CsrCharString *str)
+{
+    const CsrCharString *p = str;
+    while (*p)
+    {
+        append_char(*p);
+        p++;
+    }
+    /* Update start-of-buffer pointer */
+    unifi_dbgbuf_start = unifi_dbgbuf_ptr + 1;
+    if ((unifi_dbgbuf_start - unifi_debug_output) >= UNIFI_DEBUG_GBUFFER_SIZE)
+    {
+        unifi_dbgbuf_start = unifi_debug_output;
+    }
+}
+
+
+void unifi_debug_log_to_buf(const CsrCharString *fmt, ...)
+{
+#define DEBUG_BUFFER_SIZE       80
+    static CsrCharString s[DEBUG_BUFFER_SIZE];
+    va_list args;
+
+    va_start(args, fmt);
+    CsrVsnprintf(s, DEBUG_BUFFER_SIZE, fmt, args);
+    va_end(args);
+
+    unifi_debug_string_to_buf(s);
+} /* unifi_debug_log_to_buf() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_debug_hex_to_buf
+ *
+ *  puts the contents of the passed buffer into the debug buffer as a hex string
+ *
+ *  Arguments:
+ *      buff         buffer to print as hex
+ *      length       number of chars to print
+ *
+ *  Returns:
+ *      None.
+ *
+ * ---------------------------------------------------------------------------
+ */
+void unifi_debug_hex_to_buf(const CsrCharString *buff, CsrUint16 length)
+{
+    CsrCharString s[5];
+    CsrUint16 i;
+
+    for (i = 0; i < length; i = i + 2)
+    {
+        CsrUInt16ToHex(*((CsrUint16 *)(buff + i)), s);
+        unifi_debug_string_to_buf(s);
+    }
+}
+
+
+void unifi_debug_buf_dump(void)
+{
+    CsrInt32 offset = unifi_dbgbuf_ptr - unifi_debug_output;
+
+    unifi_error(NULL, "HIP debug buffer offset=%d\n", offset);
+    dump_str(unifi_debug_output + offset, UNIFI_DEBUG_GBUFFER_SIZE - offset);
+    dump_str(unifi_debug_output, offset);
+} /* unifi_debug_buf_dump() */
+
+
+#endif /* CSR_WIFI_HIP_DEBUG_OFFLINE */
+
+#ifdef CSR_PRE_ALLOC_NET_DATA
+#define NETDATA_PRE_ALLOC_BUF_SIZE 8000
+
+void prealloc_netdata_free(card_t *card)
+{
+    unifi_warning(card->ospriv, "prealloc_netdata_free: IN: w=%d r=%d\n", card->prealloc_netdata_w, card->prealloc_netdata_r);
+
+    while (card->bulk_data_desc_list[card->prealloc_netdata_r].data_length != 0)
+    {
+        unifi_warning(card->ospriv, "prealloc_netdata_free: r=%d\n", card->prealloc_netdata_r);
+
+        unifi_net_data_free(card->ospriv, &card->bulk_data_desc_list[card->prealloc_netdata_r]);
+        card->prealloc_netdata_r++;
+        card->prealloc_netdata_r %= BULK_DATA_PRE_ALLOC_NUM;
+    }
+    card->prealloc_netdata_r = card->prealloc_netdata_w = 0;
+
+    unifi_warning(card->ospriv, "prealloc_netdata_free: OUT: w=%d r=%d\n", card->prealloc_netdata_w, card->prealloc_netdata_r);
+}
+
+
+CsrResult prealloc_netdata_alloc(card_t *card)
+{
+    CsrResult r;
+
+    unifi_trace(card->ospriv, UDBG5, "prealloc_netdata_alloc: IN: w=%d r=%d\n", card->prealloc_netdata_w, card->prealloc_netdata_r);
+
+    while (card->bulk_data_desc_list[card->prealloc_netdata_w].data_length == 0)
+    {
+        r = unifi_net_data_malloc(card->ospriv, &card->bulk_data_desc_list[card->prealloc_netdata_w], NETDATA_PRE_ALLOC_BUF_SIZE);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "prealloc_netdata_alloc: Failed to allocate t-h bulk data\n");
+            return CSR_RESULT_FAILURE;
+        }
+        card->prealloc_netdata_w++;
+        card->prealloc_netdata_w %= BULK_DATA_PRE_ALLOC_NUM;
+    }
+    unifi_trace(card->ospriv, UDBG5, "prealloc_netdata_alloc: OUT: w=%d r=%d\n", card->prealloc_netdata_w, card->prealloc_netdata_r);
+
+    return CSR_RESULT_SUCCESS;
+}
+
+
+static CsrResult prealloc_netdata_get(card_t *card, bulk_data_desc_t *bulk_data_slot, CsrUint32 size)
+{
+    CsrResult r;
+
+    unifi_trace(card->ospriv, UDBG5, "prealloc_netdata_get: IN: w=%d r=%d\n", card->prealloc_netdata_w, card->prealloc_netdata_r);
+
+    if (card->bulk_data_desc_list[card->prealloc_netdata_r].data_length == 0)
+    {
+        unifi_error(card->ospriv, "prealloc_netdata_get: data_length = 0\n");
+    }
+
+    if ((size > NETDATA_PRE_ALLOC_BUF_SIZE) || (card->bulk_data_desc_list[card->prealloc_netdata_r].data_length == 0))
+    {
+        unifi_warning(card->ospriv, "prealloc_netdata_get: Calling net_data_malloc\n");
+
+        r = unifi_net_data_malloc(card->ospriv, bulk_data_slot, size);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "prealloc_netdata_get: Failed to allocate t-h bulk data\n");
+            return CSR_RESULT_FAILURE;
+        }
+        return CSR_RESULT_SUCCESS;
+    }
+
+    *bulk_data_slot = card->bulk_data_desc_list[card->prealloc_netdata_r];
+    card->bulk_data_desc_list[card->prealloc_netdata_r].os_data_ptr = NULL;
+    card->bulk_data_desc_list[card->prealloc_netdata_r].os_net_buf_ptr = NULL;
+    card->bulk_data_desc_list[card->prealloc_netdata_r].net_buf_length = 0;
+    card->bulk_data_desc_list[card->prealloc_netdata_r].data_length = 0;
+
+    card->prealloc_netdata_r++;
+    card->prealloc_netdata_r %= BULK_DATA_PRE_ALLOC_NUM;
+
+    unifi_trace(card->ospriv, UDBG5, "prealloc_netdata_get: OUT: w=%d r=%d\n", card->prealloc_netdata_w, card->prealloc_netdata_r);
+
+    return CSR_RESULT_SUCCESS;
+}
+
+
+#endif
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_sdio_interrupt_handler
+ *
+ *      This function should be called by the OS-dependent code to handle
+ *      an SDIO interrupt from the UniFi.
+ *
+ *  Arguments:
+ *      card            Pointer to card context structure.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes: This function may be called in DRS context. In this case,
+ *         tracing with the unifi_trace(), etc, is not allowed.
+ * ---------------------------------------------------------------------------
+ */
+void unifi_sdio_interrupt_handler(card_t *card)
+{
+    /*
+     * Set the flag to say reason for waking was SDIO interrupt.
+     * Then ask the OS layer to run the unifi_bh to give attention to the UniFi.
+     */
+    card->bh_reason_unifi = 1;
+    (void)unifi_run_bh(card->ospriv);
+} /*  sdio_interrupt_handler() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_configure_low_power_mode
+ *
+ *      This function should be called by the OS-dependent when
+ *      the deep sleep signaling needs to be enabled or disabled.
+ *
+ *  Arguments:
+ *      card            Pointer to card context structure.
+ *      low_power_mode  Disable/Enable the deep sleep signaling
+ *      periodic_wake_mode UniFi wakes host periodically.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success or a CSR error code.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_configure_low_power_mode(card_t                       *card,
+                                         enum unifi_low_power_mode     low_power_mode,
+                                         enum unifi_periodic_wake_mode periodic_wake_mode)
+{
+    card->low_power_mode = low_power_mode;
+    card->periodic_wake_mode = periodic_wake_mode;
+
+    unifi_trace(card->ospriv, UDBG1,
+                "unifi_configure_low_power_mode: new mode = %s, wake_host = %s\n",
+                (low_power_mode == UNIFI_LOW_POWER_DISABLED)?"disabled" : "enabled",
+                (periodic_wake_mode == UNIFI_PERIODIC_WAKE_HOST_DISABLED)?"FALSE" : "TRUE");
+
+    (void)unifi_run_bh(card->ospriv);
+    return CSR_RESULT_SUCCESS;
+} /* unifi_configure_low_power_mode() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_force_low_power_mode
+ *
+ *      This function should be called by the OS-dependent when
+ *      UniFi needs to be set to the low power mode (e.g. on suspend)
+ *
+ *  Arguments:
+ *      card            Pointer to card context structure.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success or a CSR error code.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_force_low_power_mode(card_t *card)
+{
+    if (card->low_power_mode == UNIFI_LOW_POWER_DISABLED)
+    {
+        unifi_error(card->ospriv, "Attempt to set mode to TORPID when lower power mode is disabled\n");
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    return unifi_set_host_state(card, UNIFI_HOST_STATE_TORPID);
+} /* unifi_force_low_power_mode() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_bh
+ *
+ *      This function should be called by the OS-dependent code when
+ *      host and/or UniFi has requested an exchange of messages.
+ *
+ *  Arguments:
+ *      card            Pointer to card context structure.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success or a CSR error code.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_bh(card_t *card, CsrUint32 *remaining)
+{
+    CsrResult r;
+    CsrResult csrResult;
+    CsrBool pending;
+    CsrInt32 iostate, j;
+    const enum unifi_low_power_mode low_power_mode = card->low_power_mode;
+    CsrUint16 data_slots_used = 0;
+
+
+    /* Process request to raise the maximum SDIO clock */
+    r = process_clock_request(card);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Error setting maximum SDIO clock\n");
+        goto exit;
+    }
+
+    /*
+     * Why was the BH thread woken?
+     * If it was an SDIO interrupt, UniFi is awake and we need to process it.
+     * If it was a host process queueing data, then we need to awaken UniFi.
+     *
+     * Priority of flags is top down.
+     *
+     * ----------------------------------------------------------+
+     *    \state|   AWAKE      |    DROWSY      |    TORPID      |
+     * flag\    |              |                |                |
+     * ---------+--------------+----------------+----------------|
+     *          | do the host  | go to AWAKE and| go to AWAKE and|
+     *   unifi  | protocol     | do the host    | do the host    |
+     *          |              | protocol       | protocol       |
+     * ---------+--------------+----------------+----------------|
+     *          | do the host  |                |                |
+     *   host   | protocol     |  do nothing    | go to DROWSY   |
+     *          |              |                |                |
+     * ---------+--------------+----------------+----------------|
+     *          |              |                | should not     |
+     *  timeout | go to TORPID | error, unifi   | occur          |
+     *          |              | didn't wake up | do nothing     |
+     * ----------------------------------------------------------+
+     *
+     * Note that if we end up in the AWAKE state we always do the host protocol.
+     */
+
+    do
+    {
+        /*
+         * When the host state is set to DROWSY, then we can not disable the
+         * interrupts as UniFi can generate an interrupt even when the INT_ENABLE
+         * register has the interrupts disabled. This interrupt will be lost.
+         */
+        if (card->host_state == UNIFI_HOST_STATE_DROWSY || card->host_state == UNIFI_HOST_STATE_TORPID)
+        {
+            CsrUint8 reason_unifi;
+
+            /*
+             * An interrupt may occur while or after we cache the reason.
+             * This interrupt will cause the unifi_bh() to be scheduled again.
+             * Any interrupt that has happened before the register is read
+             * and is considered spurious has to acknowledged.
+             */
+            reason_unifi = card->bh_reason_unifi;
+
+            /*
+             * If an interrupt is received, check if it was a real one,
+             * set the host state to AWAKE and run the BH.
+             */
+            r = CardPendingInt(card, &pending);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                goto exit;
+            }
+
+            if (pending)
+            {
+                unifi_trace(card->ospriv, UDBG5,
+                            "UNIFI_HOST_STATE_%s: Set state to AWAKE.\n",
+                            (card->host_state == UNIFI_HOST_STATE_TORPID)?"TORPID" : "DROWSY");
+
+                r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE);
+                if (r == CSR_RESULT_SUCCESS)
+                {
+                    (*remaining) = 0;
+                    break;
+                }
+            }
+            else if (reason_unifi)
+            {
+                CsrSdioInterruptAcknowledge(card->sdio_if);
+            }
+
+            /*
+             * If an chip is in TORPID, and the host wants to wake it up,
+             * set the host state to DROWSY and wait for the wake-up interrupt.
+             */
+            if ((card->host_state == UNIFI_HOST_STATE_TORPID) && card->bh_reason_host)
+            {
+                r = unifi_set_host_state(card, UNIFI_HOST_STATE_DROWSY);
+                if (r == CSR_RESULT_SUCCESS)
+                {
+                    /*
+                     * set the timeout value to UNIFI_DEFAULT_WAKE_TIMEOUT
+                     * to capture a wake error.
+                     */
+                    card->bh_reason_host = 0;
+                    (*remaining) = UNIFI_DEFAULT_WAKE_TIMEOUT;
+                    return CSR_RESULT_SUCCESS;
+                }
+
+                goto exit;
+            }
+
+            /*
+             * If the chip is in DROWSY, and the timeout expires,
+             * we need to reset the chip. This should never occur.
+             * (If it does, check that the calling thread set "remaining"
+             * according to the time remaining when unifi_bh() was called).
+             */
+            if ((card->host_state == UNIFI_HOST_STATE_DROWSY) && ((*remaining) == 0))
+            {
+                unifi_error(card->ospriv, "UniFi did not wake up on time...\n");
+
+                /*
+                 * Check if Function1 has gone away or
+                 * if we missed an SDIO interrupt.
+                 */
+                r = unifi_check_io_status(card, &iostate);
+                if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+                {
+                    goto exit;
+                }
+                /* Need to reset and reboot */
+                return CSR_RESULT_FAILURE;
+            }
+        }
+        else
+        {
+            if (card->bh_reason_unifi || card->bh_reason_host)
+            {
+                break;
+            }
+
+            if (((*remaining) == 0) && (low_power_mode == UNIFI_LOW_POWER_ENABLED))
+            {
+                r = unifi_set_host_state(card, UNIFI_HOST_STATE_TORPID);
+                if (r == CSR_RESULT_SUCCESS)
+                {
+                    (*remaining) = 0;
+                    return CSR_RESULT_SUCCESS;
+                }
+
+                goto exit;
+            }
+        }
+
+        /* No need to run the host protocol */
+        return CSR_RESULT_SUCCESS;
+    } while (0);
+
+
+    /* Disable the SDIO interrupts while doing SDIO ops */
+    csrResult = CsrSdioInterruptDisable(card->sdio_if);
+    if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+    {
+        r = CSR_WIFI_HIP_RESULT_NO_DEVICE;
+        goto exit;
+    }
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+        unifi_error(card->ospriv, "Failed to disable SDIO interrupts. unifi_bh queues error.\n");
+        goto exit;
+    }
+
+    /* Now that the interrupts are disabled, ack the interrupt */
+    CsrSdioInterruptAcknowledge(card->sdio_if);
+
+    /* Run the HIP */
+    r = process_bh(card);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        goto exit;
+    }
+
+    /*
+     * If host is now idle, schedule a timer for the delay before we
+     * let UniFi go into deep sleep.
+     * If the timer goes off, we will move to TORPID state.
+     * If UniFi raises an interrupt in the meantime, we will cancel
+     * the timer and start a new one when we become idle.
+     */
+    for (j = 0; j < UNIFI_NO_OF_TX_QS; j++)
+    {
+        data_slots_used += CSR_WIFI_HIP_Q_SLOTS_USED(&card->fh_traffic_queue[j]);
+    }
+
+    if ((low_power_mode == UNIFI_LOW_POWER_ENABLED) && (data_slots_used == 0))
+    {
+#ifndef CSR_WIFI_HIP_TA_DISABLE
+        if (card->ta_sampling.traffic_type != CSR_WIFI_ROUTER_CTRL_TRAFFIC_TYPE_PERIODIC)
+        {
+#endif
+        /* return the UNIFI_DEFAULT_HOST_IDLE_TIMEOUT, so we can go to sleep. */
+        unifi_trace(card->ospriv, UDBG5,
+                    "Traffic is not periodic, set timer for TORPID.\n");
+        (*remaining) = UNIFI_DEFAULT_HOST_IDLE_TIMEOUT;
+#ifndef CSR_WIFI_HIP_TA_DISABLE
+    }
+    else
+    {
+        unifi_trace(card->ospriv, UDBG5,
+                    "Traffic is periodic, set unifi to TORPID immediately.\n");
+        if (CardAreAllFromHostDataSlotsEmpty(card) == 1)
+        {
+            r = unifi_set_host_state(card, UNIFI_HOST_STATE_TORPID);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                goto exit;
+            }
+        }
+    }
+#endif
+    }
+
+    csrResult = CsrSdioInterruptEnable(card->sdio_if);
+    if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+    {
+        r = CSR_WIFI_HIP_RESULT_NO_DEVICE;
+    }
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+        unifi_error(card->ospriv, "Failed to enable SDIO interrupt\n");
+    }
+
+exit:
+
+    unifi_trace(card->ospriv, UDBG4, "New state=%d\n", card->host_state);
+
+    if (r != CSR_RESULT_SUCCESS)
+    {
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+        unifi_debug_buf_dump();
+#endif
+        /* If an interrupt has been raised, ack it here */
+        if (card->bh_reason_unifi)
+        {
+            CsrSdioInterruptAcknowledge(card->sdio_if);
+        }
+
+        unifi_error(card->ospriv,
+                    "unifi_bh: state=%d %c, clock=%dkHz, interrupt=%d host=%d, power_save=%s\n",
+                    card->host_state,
+                    (card->host_state == UNIFI_HOST_STATE_AWAKE)?'A' : (card->host_state == UNIFI_HOST_STATE_DROWSY)?'D' : 'T',
+                    card->sdio_clock_speed / 1000,
+                    card->bh_reason_unifi, card->bh_reason_host,
+                    (low_power_mode == UNIFI_LOW_POWER_DISABLED)?"disabled" : "enabled");
+
+        /* Try to capture firmware panic codes */
+        (void)unifi_capture_panic(card);
+
+        /* Ask for a mini-coredump when the driver has reset UniFi */
+        (void)unifi_coredump_request_at_next_reset(card, 1);
+    }
+
+    return r;
+} /* unifi_bh() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  process_clock_request
+ *
+ *      Handle request from the OS layer to increase the SDIO clock speed.
+ *      The fast clock is limited until the firmware has indicated that it has
+ *      completed initialisation to the OS layer.
+ *
+ *  Arguments:
+ *      card            Pointer to card context structure.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success or CSR error code.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult process_clock_request(card_t *card)
+{
+    CsrResult r = CSR_RESULT_SUCCESS;
+    CsrResult csrResult;
+
+    if (!card->request_max_clock)
+    {
+        return CSR_RESULT_SUCCESS;   /* No pending request */
+    }
+
+    /*
+     * The SDIO clock speed request from the OS layer is only acted upon if
+     * the UniFi is awake. If it was in any other state, the clock speed will
+     * transition through SAFE to MAX while the host wakes it up, and the
+     * final speed reached will be UNIFI_SDIO_CLOCK_MAX_HZ.
+     * This assumes that the SME never requests low power mode while the f/w
+     * initialisation takes place.
+     */
+    if (card->host_state == UNIFI_HOST_STATE_AWAKE)
+    {
+        unifi_trace(card->ospriv, UDBG1, "Set SDIO max clock\n");
+        csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_MAX_HZ);
+        if (csrResult != CSR_RESULT_SUCCESS)
+        {
+            r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+        }
+        else
+        {
+            card->sdio_clock_speed = UNIFI_SDIO_CLOCK_MAX_HZ;  /* log the new freq */
+        }
+    }
+    else
+    {
+        unifi_trace(card->ospriv, UDBG1, "Will set SDIO max clock after wakeup\n");
+    }
+
+    /* Cancel the request now that it has been acted upon, or is about to be
+     * by the wakeup mechanism
+     */
+    card->request_max_clock = 0;
+
+    return r;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  process_bh
+ *
+ *      Exchange messages with UniFi
+ *
+ *  Arguments:
+ *      card            Pointer to card context structure.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success or CSR error code.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult process_bh(card_t *card)
+{
+    CsrResult r;
+    CsrBool more;
+    more = FALSE;
+
+    /* Process the reasons (interrupt, signals) */
+    do
+    {
+        /*
+         * Run in a while loop, to save clearing the interrupts
+         * every time around the outside loop.
+         */
+        do
+        {
+            /* If configured to run the HIP just once, skip first loop */
+            if (card->intmode & CSR_WIFI_INTMODE_RUN_BH_ONCE)
+            {
+                break;
+            }
+
+            r = handle_host_protocol(card, &more);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+            unifi_debug_log_to_buf("c52=%d c53=%d tx=%d txc=%d rx=%d s=%d t=%d fc=%d\n",
+                                   card->cmd_prof.cmd52_count,
+                                   card->cmd_prof.cmd53_count,
+                                   card->cmd_prof.tx_count,
+                                   card->cmd_prof.tx_cfm_count,
+                                   card->cmd_prof.rx_count,
+                                   card->cmd_prof.sdio_cmd_signal,
+                                   card->cmd_prof.sdio_cmd_to_host,
+                                   card->cmd_prof.sdio_cmd_from_host_and_clear
+                                   );
+
+            card->cmd_prof.cmd52_count = card->cmd_prof.cmd53_count = 0;
+            card->cmd_prof.tx_count = card->cmd_prof.tx_cfm_count = card->cmd_prof.rx_count = 0;
+
+            card->cmd_prof.cmd52_f0_r_count = 0;
+            card->cmd_prof.cmd52_f0_w_count = 0;
+            card->cmd_prof.cmd52_r8or16_count = 0;
+            card->cmd_prof.cmd52_w8or16_count = 0;
+            card->cmd_prof.cmd52_r16_count = 0;
+            card->cmd_prof.cmd52_w16_count = 0;
+            card->cmd_prof.cmd52_r32_count = 0;
+
+            card->cmd_prof.sdio_cmd_signal = 0;
+            card->cmd_prof.sdio_cmd_clear_slot = 0;
+            card->cmd_prof.sdio_cmd_to_host = 0;
+            card->cmd_prof.sdio_cmd_from_host = 0;
+            card->cmd_prof.sdio_cmd_from_host_and_clear = 0;
+#endif
+
+
+        } while (more || card->bh_reason_unifi || card->bh_reason_host);
+
+        /* Acknowledge the h/w interrupt */
+        r = CardClearInt(card);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to acknowledge interrupt.\n");
+            return r;
+        }
+
+        /*
+         * UniFi may have tried to generate an interrupt during the
+         * CardClearInt() was running. So, we need to run the host
+         * protocol again, to check if there are any pending requests.
+         */
+        r = handle_host_protocol(card, &more);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            return r;
+        }
+
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+        unifi_debug_log_to_buf("c52=%d c53=%d tx=%d txc=%d rx=%d s=%d t=%d fc=%d\n",
+                               card->cmd_prof.cmd52_count,
+                               card->cmd_prof.cmd53_count,
+                               card->cmd_prof.tx_count,
+                               card->cmd_prof.tx_cfm_count,
+                               card->cmd_prof.rx_count,
+                               card->cmd_prof.sdio_cmd_signal,
+                               card->cmd_prof.sdio_cmd_to_host,
+                               card->cmd_prof.sdio_cmd_from_host_and_clear
+                               );
+
+        card->cmd_prof.cmd52_count = card->cmd_prof.cmd53_count = 0;
+        card->cmd_prof.tx_count = card->cmd_prof.tx_cfm_count = card->cmd_prof.rx_count = 0;
+
+        card->cmd_prof.cmd52_f0_r_count = 0;
+        card->cmd_prof.cmd52_f0_w_count = 0;
+        card->cmd_prof.cmd52_r8or16_count = 0;
+        card->cmd_prof.cmd52_w8or16_count = 0;
+        card->cmd_prof.cmd52_r16_count = 0;
+        card->cmd_prof.cmd52_w16_count = 0;
+        card->cmd_prof.cmd52_r32_count = 0;
+
+        card->cmd_prof.sdio_cmd_signal = 0;
+        card->cmd_prof.sdio_cmd_clear_slot = 0;
+        card->cmd_prof.sdio_cmd_to_host = 0;
+        card->cmd_prof.sdio_cmd_from_host = 0;
+        card->cmd_prof.sdio_cmd_from_host_and_clear = 0;
+#endif
+        /* If configured to run the HIP just once, work is now done */
+        if (card->intmode & CSR_WIFI_INTMODE_RUN_BH_ONCE)
+        {
+            break;
+        }
+
+    } while (more || card->bh_reason_unifi || card->bh_reason_host);
+
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+    if ((card->intmode & CSR_WIFI_INTMODE_RUN_BH_ONCE) == 0)
+    {
+        unifi_debug_log_to_buf("proc=%d\n",
+                               card->cmd_prof.process_count);
+    }
+#endif
+
+    return CSR_RESULT_SUCCESS;
+} /* process_bh() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  handle_host_protocol
+ *
+ *      This function implements the Host Interface Protocol (HIP) as
+ *      described in the Host Interface Protocol Specification.
+ *
+ *  Arguments:
+ *      card                 Pointer to card context structure.
+ *      processed_something  Pointer to location to update processing status:
+ *                              TRUE when data was transferred
+ *                              FALSE when no data was transferred (queues empty)
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success or CSR error code.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult handle_host_protocol(card_t *card, CsrBool *processed_something)
+{
+    CsrResult r;
+    CsrInt32 done;
+
+    *processed_something = FALSE;
+
+#ifdef CSR_WIFI_HIP_NOISY
+    unifi_error(card->ospriv, "   ========================     \n");
+#endif /* CSR_WIFI_HIP_NOISY */
+
+#ifdef CSR_WIFI_HIP_DATA_PLANE_PROFILE
+    card->cmd_prof.process_count++;
+#endif
+
+    card->bh_reason_unifi = card->bh_reason_host = 0;
+    card->generate_interrupt = 0;
+
+
+    /*
+     * (Re)fill the T-H signal buffer
+     */
+    r = read_to_host_signals(card, &done);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Error occured reading to-host signals\n");
+        return r;
+    }
+    if (done > 0)
+    {
+        *processed_something = TRUE;
+    }
+
+    /*
+     * Process any to-host signals.
+     * Perform any requested CMD53 transfers here, but just queue any
+     * bulk data command responses.
+     */
+    r = process_to_host_signals(card, &done);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Error occured processing to-host signals\n");
+        return r;
+    }
+
+    /* Now send any signals in the F-H queues */
+    /* Give precedence to the command queue */
+    r = process_fh_cmd_queue(card, &done);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Error occured processing from-host signals\n");
+        return r;
+    }
+    if (done > 0)
+    {
+        *processed_something = TRUE;
+    }
+
+    r = process_fh_traffic_queue(card, &done);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Error occured processing from-host data signals\n");
+        return r;
+    }
+    if (done > 0)
+    {
+        *processed_something = TRUE;
+    }
+
+    /* Flush out the batch of signals to the UniFi. */
+    r = flush_fh_buffer(card);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to copy from-host signals to UniFi\n");
+        return r;
+    }
+
+
+    /*
+     * Send the host interrupt to say the queues have been modified.
+     */
+    if (card->generate_interrupt)
+    {
+        r = CardGenInt(card);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to notify UniFi that queues have been modified.\n");
+            return r;
+        }
+    }
+
+#ifdef CSR_WIFI_RX_PATH_SPLIT
+#ifdef CSR_WIFI_RX_PATH_SPLIT_DONT_USE_WQ
+    unifi_rx_queue_flush(card->ospriv);
+#endif
+#endif
+
+    /* See if we can re-enable transmission now */
+    restart_packet_flow(card);
+
+#ifdef CSR_PRE_ALLOC_NET_DATA
+    r = prealloc_netdata_alloc(card);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "prealloc_netdata failed\n");
+        return r;
+    }
+#endif
+
+    /*
+     * Don't put the thread sleep if we just interacted with the chip,
+     * there might be more to do if we look again.
+     */
+    return r;
+} /* handle_host_protocol() */
+
+
+/*
+ *      Rounds the given signal length in bytes to a whole number
+ *      of sig_frag_size.
+ */
+#define GET_CHUNKS_FOR(SIG_FRAG_SIZE, LENGTH) (((LENGTH) + ((SIG_FRAG_SIZE)-1)) / (SIG_FRAG_SIZE))
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  read_to_host_signals
+ *
+ *      Read everything pending in the UniFi TH signal buffer.
+ *      Only do it if the local buffer is empty.
+ *
+ *  Arguments:
+ *      card        Pointer to card context struct
+ *      processed   Number of signals read:
+ *                      0 if there were no signals pending,
+ *                      1 if we read at least one signal
+ *  Returns:
+ *      CSR error code if an error occurred.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult read_to_host_signals(card_t *card, CsrInt32 *processed)
+{
+    CsrInt32 count_thw, count_thr;
+    CsrInt32 unread_chunks, unread_bytes;
+    CsrResult r;
+
+    *processed = 0;
+
+    /* Read any pending signals or bulk data commands */
+    count_thw = unifi_read_shared_count(card, card->sdio_ctrl_addr + 4);
+    if (count_thw < 0)
+    {
+        unifi_error(card->ospriv, "Failed to read to-host sig written count\n");
+        return CSR_RESULT_FAILURE;
+    }
+    card->to_host_signals_w = count_thw; /* diag */
+
+    count_thr = card->to_host_signals_r;
+
+    if (count_thw == count_thr)
+    {
+        return CSR_RESULT_SUCCESS;
+    }
+
+    unread_chunks =
+        (((count_thw - count_thr) + 128) % 128) - card->th_buffer.count;
+
+    if (unread_chunks == 0)
+    {
+        return CSR_RESULT_SUCCESS;
+    }
+
+    unread_bytes = card->config_data.sig_frag_size * unread_chunks;
+
+
+    r = unifi_bulk_rw(card,
+                      card->config_data.tohost_sigbuf_handle,
+                      card->th_buffer.ptr,
+                      unread_bytes,
+                      UNIFI_SDIO_READ);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to read ToHost signal\n");
+        return r;
+    }
+
+    card->th_buffer.ptr += unread_bytes;
+    card->th_buffer.count += (CsrUint16)unread_chunks;
+
+    *processed = 1;
+
+    return CSR_RESULT_SUCCESS;
+} /* read_to_host_signals() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  update_to_host_signals_r
+ *
+ *      Advance the shared-memory count of chunks read from the to-host
+ *      signal buffer.
+ *      Raise a UniFi internal interrupt to tell the firmware that the
+ *      count has changed.
+ *
+ *  Arguments:
+ *      card            Pointer to card context struct
+ *      pending         Number of chunks remaining
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success or CSR error code
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult update_to_host_signals_r(card_t *card, CsrInt16 pending)
+{
+    CsrResult r;
+
+    card->to_host_signals_r =
+        (card->to_host_signals_r + (card->th_buffer.count - pending)) % 128;
+    card->th_buffer.count = pending;
+
+    /* Update the count of signals read */
+    r = unifi_write_8_or_16(card, card->sdio_ctrl_addr + 6,
+                            (CsrUint8)card->to_host_signals_r);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to update to-host signals read\n");
+        return r;
+    }
+
+    r = CardGenInt(card);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to notify UniFi that we processed to-host signals.\n");
+        return r;
+    }
+
+    card->generate_interrupt = 0;
+
+    return CSR_RESULT_SUCCESS;
+} /* update_to_host_signals_r() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  read_unpack_cmd
+ *
+ *      Converts a wire-formatted command to the host bulk_data_cmd_t structure.
+ *
+ *  Arguments:
+ *      ptr             Pointer to the command
+ *      bulk_data_cmd   Pointer to the host structure
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void read_unpack_cmd(const CsrUint8 *ptr, bulk_data_cmd_t *bulk_data_cmd)
+{
+    CsrInt16 index = 0;
+    bulk_data_cmd->cmd_and_len = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+    index += SIZEOF_UINT16;
+    bulk_data_cmd->data_slot = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+    index += SIZEOF_UINT16;
+    bulk_data_cmd->offset = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+    index += SIZEOF_UINT16;
+    bulk_data_cmd->buffer_handle = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+    index += SIZEOF_UINT16;
+} /* read_unpack_cmd */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  process_to_host_signals
+ *
+ *      Read and dispatch signals from the UniFi
+ *
+ *  Arguments:
+ *      card        Pointer to card context struct
+ *      processed   Pointer to location to write processing result:
+ *                      0 if there were no signals pending,
+ *                      1 if we read at least one signal
+ *
+ *  Returns:
+ *      CSR error code if there was an error
+ *
+ *  Notes:
+ *      Since bulk data transfers can take a long time, if we wait until
+ *      all are done before we acknowledge the signals, the UniFi runs out
+ *      of buffer space. Therefore we keep a count of the bytes transferred
+ *      in bulk data commands, and update the to-host-signals-read count
+ *      if we've done a large transfer.
+ *
+ *      All data in the f/w is stored in a little endian format, without any
+ *      padding bytes. Every read from the memory has to be transformed in
+ *      host (cpu specific) format, before we can process it. Therefore we
+ *      use read_unpack_cmd() and read_unpack_signal() to convert the raw data
+ *      contained in the card->th_buffer.buf to host structures.
+ *      Important: UDI clients use wire-formatted structures, so we need to
+ *      indicate all data, as we have read it from the device.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult process_to_host_signals(card_t *card, CsrInt32 *processed)
+{
+    CsrInt16 pending;
+    CsrInt16 remaining;
+    CsrUint8 *bufptr;
+    bulk_data_param_t data_ptrs;
+    CsrInt16 cmd;
+    CsrUint16 sig_len;
+    CsrInt16 i;
+    CsrUint16 chunks_in_buf;
+    CsrUint16 bytes_transferred = 0;
+    CsrResult r = CSR_RESULT_SUCCESS;
+
+    *processed = 0;
+
+    pending = card->th_buffer.count;
+
+    /* Are there new to-host signals? */
+    unifi_trace(card->ospriv, UDBG4, "handling %d to-host chunks\n", pending);
+
+    if (!pending)
+    {
+        return CSR_RESULT_SUCCESS;
+    }
+
+    /*
+     * This is a pointer to the raw data we have read from the f/w.
+     * Can be a signal or a command. Note that we need to convert
+     * it to a host structure before we process it.
+     */
+    bufptr = card->th_buffer.buf;
+
+    while (pending > 0)
+    {
+        CsrInt16 f_flush_count = 0;
+
+        /*
+         * Command and length are common to signal and bulk data msgs.
+         * If command == 0 (i.e. a signal), len is number of bytes
+         * *following* the 2-byte header.
+         */
+        cmd = bufptr[1] >> 4;
+        sig_len = bufptr[0] + ((bufptr[1] & 0x0F) << 8);
+
+#ifdef CSR_WIFI_HIP_NOISY
+        unifi_error(card->ospriv, "Received UniFi msg cmd=%d, len=%d\n",
+                    cmd, sig_len);
+#endif  /* CSR_WIFI_HIP_NOISY */
+
+        if ((sig_len == 0) &&
+            ((cmd != SDIO_CMD_CLEAR_SLOT) && (cmd != SDIO_CMD_PADDING)))
+        {
+            unifi_error(card->ospriv, "incomplete signal or command: has size zero\n");
+            return CSR_RESULT_FAILURE;
+        }
+        /*
+         * Make sure the buffer contains a complete message.
+         * Signals may occupy multiple chunks, bulk-data commands occupy
+         * one chunk.
+         */
+        if (cmd == SDIO_CMD_SIGNAL)
+        {
+            chunks_in_buf = GET_CHUNKS_FOR(card->config_data.sig_frag_size, (CsrUint16)(sig_len + 2));
+        }
+        else
+        {
+            chunks_in_buf = 1;
+        }
+
+        if (chunks_in_buf > (CsrUint16)pending)
+        {
+            unifi_error(card->ospriv, "incomplete signal (0x%x?): need %d chunks, got %d\n",
+                        GET_SIGNAL_ID(bufptr + 2),
+                        chunks_in_buf, pending);
+            unifi_error(card->ospriv, " thsw=%d, thsr=%d\n",
+                        card->to_host_signals_w,
+                        card->to_host_signals_r);
+            return CSR_RESULT_FAILURE;
+        }
+
+
+        switch (cmd)
+        {
+            case SDIO_CMD_SIGNAL:
+                /* This is a signal. Read the rest of it and then handle it. */
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+                card->cmd_prof.sdio_cmd_signal++;
+#endif
+
+                for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++)
+                {
+                    /* Retrieve dataRefs[i].DataLength */
+                    CsrUint16 data_len = GET_PACKED_DATAREF_LEN(bufptr + 2, i);
+
+                    /*
+                     * The bulk data length in the signal can not be greater than
+                     * the maximun length allowed by the SDIO config structure.
+                     */
+                    if (data_len > card->config_data.data_slot_size)
+                    {
+                        unifi_error(card->ospriv,
+                                    "Bulk Data length (%d) exceeds Maximum Bulk Data length (%d)\n",
+                                    data_len, card->config_data.data_slot_size);
+                        return CSR_RESULT_FAILURE;
+                    }
+
+                    /*
+                     * Len here might not be the same as the length in the
+                     * bulk data slot.  The slot length will always be even,
+                     * but len could be odd.
+                     */
+                    if (data_len != 0)
+                    {
+                    /* Retrieve dataRefs[i].SlotNumber */
+                        CsrInt16 slot = GET_PACKED_DATAREF_SLOT(bufptr + 2, i);
+
+                        if (slot >= card->config_data.num_tohost_data_slots)
+                        {
+                            unifi_error(card->ospriv, "!!!bad slot number in to-host signal: %d, sig 0x%X\n",
+                                        slot, cmd);
+                            return CSR_RESULT_FAILURE;
+                        }
+
+                        data_ptrs.d[i].os_data_ptr = card->to_host_data[slot].os_data_ptr;
+                        data_ptrs.d[i].os_net_buf_ptr = card->to_host_data[slot].os_net_buf_ptr;
+                        data_ptrs.d[i].net_buf_length = card->to_host_data[slot].net_buf_length;
+                        data_ptrs.d[i].data_length = data_len;
+                    }
+                    else
+                    {
+                        UNIFI_INIT_BULK_DATA(&data_ptrs.d[i]);
+                    }
+                }
+
+            /*
+             * Log the signal to the UDI, before call unifi_receive_event() as
+             * it can modify the bulk data.
+             */
+                if (card->udi_hook)
+                {
+                    (*card->udi_hook)(card->ospriv, bufptr + 2, sig_len,
+                                      &data_ptrs, UDI_LOG_TO_HOST);
+                }
+
+#ifdef CSR_WIFI_HIP_DATA_PLANE_PROFILE
+                if (GET_SIGNAL_ID(bufptr + 2) == CSR_MA_PACKET_CONFIRM_ID)
+                {
+                    card->cmd_prof.tx_cfm_count++;
+                }
+                else if (GET_SIGNAL_ID(bufptr + 2) == CSR_MA_PACKET_INDICATION_ID)
+                {
+                    if (data_ptrs.d[0].os_data_ptr)
+                    {
+                        if ((*data_ptrs.d[0].os_data_ptr) & 0x08)
+                        {
+                            card->cmd_prof.rx_count++;
+                        }
+                    }
+                }
+#endif
+                /*
+                 * Check if the signal is MA-PACKET.cfm and if so check the status.
+                 * If the status is failure, search through the slot records to find
+                 * if any slots are occupied for this host tag. This can happen if
+                 * f/w has not downloaded the bulkdata and before that itself it has
+                 * signalled the confirm with failure. If it finds a slot with that
+                 * host tag then, it clears the corresponding slot
+                 */
+
+                if (GET_SIGNAL_ID(bufptr + 2) == CSR_MA_PACKET_CONFIRM_ID)
+                {
+                    /* Get host tag and transmission status */
+                    CsrUint32 host_tag = GET_PACKED_MA_PACKET_CONFIRM_HOST_TAG(bufptr + 2);
+                    CsrUint16 status = GET_PACKED_MA_PACKET_CONFIRM_TRANSMISSION_STATUS(bufptr + 2);
+
+                    unifi_trace(card->ospriv, UDBG4, "process_to_host_signals signal ID=%x host Tag=%x status=%x\n",
+                                GET_SIGNAL_ID(bufptr + 2), host_tag, status);
+
+                    /* If transmission status is failure then search through the slot records
+                     * and if for any slot records the clear slot is not done then do it now
+                     */
+
+                    if (status && (card->fh_slot_host_tag_record))
+                    {
+                        CsrUint16 num_fh_slots = card->config_data.num_fromhost_data_slots;
+
+                        /* search through the list of slot records and match with host tag
+                         * If a slot is not yet cleared then clear the slot from here
+                         */
+                        for (i = 0; i < num_fh_slots; i++)
+                        {
+                            if (card->fh_slot_host_tag_record[i] == host_tag)
+                            {
+#ifdef CSR_WIFI_REQUEUE_PACKET_TO_HAL
+                                /* Invoke the HAL module function to requeue it back to HAL Queues */
+                                r = unifi_reque_ma_packet_request(card->ospriv, host_tag, status, &card->from_host_data[i].bd);
+                                card->fh_slot_host_tag_record[i] = CSR_WIFI_HIP_RESERVED_HOST_TAG;
+                                if (CSR_RESULT_SUCCESS != r)
+                                {
+                                    unifi_trace(card->ospriv, UDBG5, "process_to_host_signals: Failed to requeue Packet(hTag:%x) back to HAL \n", host_tag);
+                                    CardClearFromHostDataSlot(card, i);
+                                }
+                                else
+                                {
+                                    CardClearFromHostDataSlotWithoutFreeingBulkData(card, i);
+                                }
+
+#else
+                                unifi_trace(card->ospriv, UDBG4, "process_to_host_signals Clear slot=%x host tag=%x\n", i, host_tag);
+                                card->fh_slot_host_tag_record[i] = CSR_WIFI_HIP_RESERVED_HOST_TAG;
+
+                                /* Set length field in from_host_data array to 0 */
+                                CardClearFromHostDataSlot(card, i);
+#endif
+                                break;
+                            }
+                        }
+                    }
+                }
+
+                /* Pass event to OS layer */
+                unifi_receive_event(card->ospriv, bufptr + 2, sig_len, &data_ptrs);
+
+                /* Initialise the to_host data, so it can be re-used. */
+                for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++)
+                {
+                /* The slot is only valid if the length is non-zero. */
+                    if (GET_PACKED_DATAREF_LEN(bufptr + 2, i) != 0)
+                    {
+                        CsrInt16 slot = GET_PACKED_DATAREF_SLOT(bufptr + 2, i);
+                        if (slot < card->config_data.num_tohost_data_slots)
+                        {
+                            UNIFI_INIT_BULK_DATA(&card->to_host_data[slot]);
+                        }
+                    }
+                }
+
+#ifndef CSR_WIFI_DEFER_TH_FLUSH
+                /*
+                 * If we have previously transferred a lot of data, ack
+                 * the signals read so far, so f/w can reclaim the buffer
+                 * memory sooner.
+                 */
+                if (bytes_transferred >= TO_HOST_FLUSH_THRESHOLD)
+                {
+                    f_flush_count = 1;
+                }
+#endif
+                break;
+
+
+            case SDIO_CMD_CLEAR_SLOT:
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+                card->cmd_prof.sdio_cmd_clear_slot++;
+#endif
+                /* This is a clear slot command. */
+                if (sig_len != 0)
+                {
+                    unifi_error(card->ospriv, "process_to_host_signals: clear slot, bad data len: 0x%X at offset %d\n",
+                                sig_len, bufptr - card->th_buffer.buf);
+                    return CSR_RESULT_FAILURE;
+                }
+
+                r = process_clear_slot_command(card, bufptr);
+                if (r != CSR_RESULT_SUCCESS)
+                {
+                    unifi_error(card->ospriv, "Failed to process clear slot\n");
+                    return r;
+                }
+                break;
+
+            case SDIO_CMD_TO_HOST_TRANSFER:
+            case SDIO_CMD_FROM_HOST_TRANSFER:
+            case SDIO_CMD_FROM_HOST_AND_CLEAR:
+            case SDIO_CMD_OVERLAY_TRANSFER:
+                /* This is a bulk data command. */
+                if (sig_len & 1)
+                {
+                    unifi_error(card->ospriv, "process_to_host_signals: bulk data, bad data len: 0x%X at offset %d\n",
+                                sig_len, bufptr - card->th_buffer.buf);
+                    return CSR_RESULT_FAILURE;
+                }
+
+                r = process_bulk_data_command(card, bufptr, cmd, sig_len);
+                if (r != CSR_RESULT_SUCCESS)
+                {
+                    unifi_error(card->ospriv, "Failed to process bulk cmd\n");
+                    return r;
+                }
+                /* Count the bytes transferred */
+                bytes_transferred += sig_len;
+
+                if (cmd == SDIO_CMD_FROM_HOST_AND_CLEAR)
+                {
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+                    card->cmd_prof.sdio_cmd_from_host_and_clear++;
+#endif
+#ifndef CSR_WIFI_DEFER_TH_FLUSH
+                    f_flush_count = 1;
+#endif
+                }
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+                else if (cmd == SDIO_CMD_FROM_HOST_TRANSFER)
+                {
+                    card->cmd_prof.sdio_cmd_from_host++;
+                }
+                else if (cmd == SDIO_CMD_TO_HOST_TRANSFER)
+                {
+                    card->cmd_prof.sdio_cmd_to_host++;
+                }
+#endif
+                break;
+
+            case SDIO_CMD_PADDING:
+                break;
+
+            default:
+                unifi_error(card->ospriv, "Unrecognised to-host command: %d\n", cmd);
+                break;
+        }
+
+        bufptr += chunks_in_buf * card->config_data.sig_frag_size;
+        pending -= chunks_in_buf;
+
+        /*
+         * Write out the host signal count when a significant
+         * number of bytes of bulk data have been transferred or
+         * when we have performed a CopyFromHostAndClear.
+         */
+        if (f_flush_count)
+        {
+            r = update_to_host_signals_r(card, pending);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+            bytes_transferred = 0;
+        }
+    }
+
+    if (pending)
+    {
+        unifi_warning(card->ospriv, "proc_th_sigs: %d unprocessed\n", pending);
+    }
+
+    /* If we processed any signals, write the updated count to UniFi */
+    if (card->th_buffer.count != pending)
+    {
+        r = update_to_host_signals_r(card, pending);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            return r;
+        }
+    }
+
+    /*
+     * Reset the buffer pointer, copying down any un-processed signals.
+     * This can happen if we enable the optimisation in read_to_host_signals()
+     * that limits the length to whole blocks.
+     */
+    remaining = card->th_buffer.ptr - bufptr;
+    if (remaining < 0)
+    {
+        unifi_error(card->ospriv, "Processing TH signals overran the buffer\n");
+        return CSR_RESULT_FAILURE;
+    }
+    if (remaining > 0)
+    {
+        /* Use a safe copy because source and destination may overlap */
+        CsrUint8 *d = card->th_buffer.buf;
+        CsrUint8 *s = bufptr;
+        CsrInt32 n = remaining;
+        while (n--)
+        {
+            *d++ = *s++;
+        }
+    }
+    card->th_buffer.ptr = card->th_buffer.buf + remaining;
+
+
+    /* If we reach here then we processed something */
+    *processed = 1;
+    return CSR_RESULT_SUCCESS;
+} /* process_to_host_signals() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  process_clear_slot_command
+ *
+ *      Process a clear slot command fom the UniFi.
+ *
+ *  Arguments:
+ *   card       Pointer to card context struct
+ *   bdcmd      Pointer to bulk-data command msg from UniFi
+ *
+ *  Returns:
+ *      0 on success, CSR error code on error
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult process_clear_slot_command(card_t *card, const CsrUint8 *cmdptr)
+{
+    CsrUint16 data_slot;
+    CsrInt16 slot;
+
+    data_slot = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cmdptr + SIZEOF_UINT16);
+
+    unifi_trace(card->ospriv, UDBG4, "Processing clear slot cmd, slot=0x%X\n",
+                data_slot);
+
+    slot = data_slot & 0x7FFF;
+
+#ifdef CSR_WIFI_HIP_NOISY
+    unifi_error(card->ospriv, "CMD clear data slot 0x%04x\n", data_slot);
+#endif /* CSR_WIFI_HIP_NOISY */
+
+    if (data_slot & SLOT_DIR_TO_HOST)
+    {
+        if (slot >= card->config_data.num_tohost_data_slots)
+        {
+            unifi_error(card->ospriv,
+                        "Invalid to-host data slot in SDIO_CMD_CLEAR_SLOT: %d\n",
+                        slot);
+            return CSR_RESULT_FAILURE;
+        }
+        /* clear to-host data slot */
+        unifi_warning(card->ospriv, "Unexpected clear to-host data slot cmd: 0x%04x\n",
+                      data_slot);
+    }
+    else
+    {
+        if (slot >= card->config_data.num_fromhost_data_slots)
+        {
+            unifi_error(card->ospriv,
+                        "Invalid from-host data slot in SDIO_CMD_CLEAR_SLOT: %d\n",
+                        slot);
+            return CSR_RESULT_FAILURE;
+        }
+
+        /*
+         * The driver is the owner to clear all slots now
+         * Ref - comment in process_fh_traffic_queue
+         * so it will just ignore the clear slot command from firmware
+         * and return success
+         */
+        return CSR_RESULT_SUCCESS;
+
+        /* Set length field in from_host_data array to 0 */
+        /* CardClearFromHostDataSlot(card, slot); */
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* process_clear_slot_command() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  process_bulk_data_command
+ *
+ *      Process a bulk data request from the UniFi.
+ *
+ *  Arguments:
+ *   card       Pointer to card context struct
+ *   bdcmd      Pointer to bulk-data command msg from UniFi
+ *   cmd, len   Decoded values of command and length from the msg header
+ *              Cmd will only be one of:
+ *                      SDIO_CMD_TO_HOST_TRANSFER
+ *                      SDIO_CMD_FROM_HOST_TRANSFER
+ *                      SDIO_CMD_FROM_HOST_AND_CLEAR
+ *                      SDIO_CMD_OVERLAY_TRANSFER
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR error code on error
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult process_bulk_data_command(card_t *card, const CsrUint8 *cmdptr,
+                                           CsrInt16 cmd, CsrUint16 len)
+{
+    bulk_data_desc_t *bdslot;
+#ifdef CSR_WIFI_ALIGNMENT_WORKAROUND
+    CsrUint8 *host_bulk_data_slot;
+#endif
+    bulk_data_cmd_t bdcmd;
+    CsrInt16 offset;
+    CsrInt16 slot;
+    CsrInt16 dir;
+    CsrResult r;
+
+    read_unpack_cmd(cmdptr, &bdcmd);
+
+    unifi_trace(card->ospriv, UDBG4, "Processing bulk data cmd %d %s, len=%d, slot=0x%X\n",
+                cmd, lookup_bulkcmd_name(cmd), len, bdcmd.data_slot);
+
+    /*
+     * Round up the transfer length if required.
+     * This is useful to force all transfers to be a multiple of the SDIO block
+     * size, so the SDIO driver won't try to use a byte-mode CMD53. These are
+     * broken on some hardware platforms.
+     */
+    if (card->sdio_io_block_pad)
+    {
+        len = (len + card->sdio_io_block_size - 1) & ~(card->sdio_io_block_size - 1);
+        unifi_trace(card->ospriv, UDBG4, "Rounded bulk data length up to %d\n", len);
+    }
+
+    slot = bdcmd.data_slot & 0x7FFF;
+
+    if (cmd == SDIO_CMD_OVERLAY_TRANSFER)
+    {
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;     /* Not used on CSR6xxx */
+    }
+    else
+    {
+        if (bdcmd.data_slot & SLOT_DIR_TO_HOST)
+        {
+            /* Request is for to-host bulk data */
+
+            /* Check sanity of slot number */
+            if (slot >= card->config_data.num_tohost_data_slots)
+            {
+                unifi_error(card->ospriv,
+                            "Invalid to-host data slot in SDIO bulk xfr req: %d\n",
+                            slot);
+                return CSR_RESULT_FAILURE;
+            }
+
+            /* Allocate memory for card->to_host_data[slot] bulk data here. */
+#ifdef CSR_PRE_ALLOC_NET_DATA
+            r = prealloc_netdata_get(card, &card->to_host_data[slot], len);
+#else
+            r = unifi_net_data_malloc(card->ospriv, &card->to_host_data[slot], len);
+#endif
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                unifi_error(card->ospriv, "Failed to allocate t-h bulk data\n");
+                return CSR_RESULT_FAILURE;
+            }
+
+            bdslot = &card->to_host_data[slot];
+
+            /* Make sure that the buffer is 4-bytes aligned */
+            r = unifi_net_dma_align(card->ospriv, bdslot);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                unifi_error(card->ospriv, "Failed to align t-h bulk data buffer for DMA\n");
+                return CSR_RESULT_FAILURE;
+            }
+        }
+        else
+        {
+            /* Request is for from-host bulk data */
+
+            if (slot >= card->config_data.num_fromhost_data_slots)
+            {
+                unifi_error(card->ospriv,
+                            "Invalid from-host data slot in SDIO bulk xfr req: %d\n",
+                            slot);
+                return CSR_RESULT_FAILURE;
+            }
+            bdslot = &card->from_host_data[slot].bd;
+        }
+        offset = bdcmd.offset;
+    }
+    /* Do the transfer */
+    dir = (cmd == SDIO_CMD_TO_HOST_TRANSFER)?
+          UNIFI_SDIO_READ : UNIFI_SDIO_WRITE;
+
+    unifi_trace(card->ospriv, UDBG4,
+                "Bulk %c %s len=%d, handle %d - slot=%d %p+(%d)\n",
+                (dir == UNIFI_SDIO_READ)?'R' : 'W',
+                lookup_bulkcmd_name(cmd),
+                len,
+                bdcmd.buffer_handle,
+                slot, bdslot->os_data_ptr, offset);
+#ifdef CSR_WIFI_HIP_NOISY
+    unifi_error(card->ospriv, "Bulk %s len=%d, handle %d - slot=%d %p+(%d)\n",
+                lookup_bulkcmd_name(cmd),
+                len,
+                bdcmd.buffer_handle,
+                slot, bdslot->os_data_ptr, offset);
+#endif /* CSR_WIFI_HIP_NOISY */
+
+
+    if (bdslot->os_data_ptr == NULL)
+    {
+        unifi_error(card->ospriv, "Null os_data_ptr - Bulk %s handle %d - slot=%d o=(%d)\n",
+                    lookup_bulkcmd_name(cmd),
+                    bdcmd.buffer_handle,
+                    slot,
+                    offset);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+#ifdef CSR_WIFI_ALIGNMENT_WORKAROUND
+    /* if os_data_ptr is not 4-byte aligned, then allocate a new buffer and copy data
+    to new buffer to ensure the address passed to unifi_bulk_rw is 4-byte aligned */
+
+    if (len != 0 && (dir == UNIFI_SDIO_WRITE) && (((CsrIntptr)bdslot->os_data_ptr + offset) & 3))
+    {
+        host_bulk_data_slot = CsrMemAllocDma(len);
+
+        if (!host_bulk_data_slot)
+        {
+            unifi_error(card->ospriv, " failed to allocate request_data before unifi_bulk_rw\n");
+            return -1;
+        }
+
+        CsrMemCpy((void *)host_bulk_data_slot,
+                  (void *)(bdslot->os_data_ptr + offset), len);
+
+        r = unifi_bulk_rw(card,
+                          bdcmd.buffer_handle,
+                          (void *)host_bulk_data_slot,
+                          len,
+                          dir);
+    }
+    else
+#endif
+    {
+        r = unifi_bulk_rw(card,
+                          bdcmd.buffer_handle,
+                          (void *)(bdslot->os_data_ptr + offset),
+                          len,
+                          dir);
+    }
+
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv,
+                    "Failed: %s hlen=%d, slen=%d, handle %d - slot=%d %p+0x%X\n",
+                    lookup_bulkcmd_name(cmd),
+                    len,                    /* Header length */
+                    bdslot->data_length,    /* Length stored in slot */
+                    bdcmd.buffer_handle,
+                    slot, bdslot->os_data_ptr, offset);
+        return r;
+    }
+
+    bdslot->data_length = len;
+
+    if (cmd == SDIO_CMD_FROM_HOST_AND_CLEAR)
+    {
+        if (slot >= card->config_data.num_fromhost_data_slots)
+        {
+            unifi_error(card->ospriv,
+                        "Invalid from-host data slot in SDIO_CMD_FROM_HOST_AND_CLEAR: %d\n",
+                        slot);
+            return CSR_RESULT_FAILURE;
+        }
+
+#ifdef CSR_WIFI_ALIGNMENT_WORKAROUND
+        /* moving this check before we clear host data slot */
+        if ((len != 0) && (dir == UNIFI_SDIO_WRITE) && (((CsrIntptr)bdslot->os_data_ptr + offset) & 3))
+        {
+            CsrMemFreeDma(host_bulk_data_slot);
+        }
+#endif
+
+        if (card->fh_slot_host_tag_record)
+        {
+            unifi_trace(card->ospriv, UDBG5, "CopyFromHostAndClearSlot Reset entry for slot=%d\n", slot);
+
+            /* reset the host tag entry for the corresponding slot */
+            card->fh_slot_host_tag_record[slot] = CSR_WIFI_HIP_RESERVED_HOST_TAG;
+        }
+
+
+        /* Set length field in from_host_data array to 0 */
+        CardClearFromHostDataSlot(card, slot);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* process_bulk_data_command() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  check_fh_sig_slots
+ *
+ *      Check whether there are <n> free signal slots available on UniFi.
+ *      This takes into account the signals already batched since the
+ *      from_host_signal counts were last read.
+ *      If the from_host_signal counts indicate not enough space, we read
+ *      the latest count from UniFi to see if some more have been freed.
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS, otherwise CSR error code on error.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult check_fh_sig_slots(card_t *card, CsrUint16 needed, CsrInt32 *space_fh)
+{
+    CsrUint32 count_fhw;
+    CsrUint32 occupied_fh, slots_fh;
+    CsrInt32 count_fhr;
+
+    count_fhw = card->from_host_signals_w;
+    count_fhr = card->from_host_signals_r;
+    slots_fh = card->config_data.num_fromhost_sig_frags;
+
+    /* Only read the space in from-host queue if necessary */
+    occupied_fh = (count_fhw - count_fhr) % 128;
+
+    if (slots_fh < occupied_fh)
+    {
+        *space_fh = 0;
+    }
+    else
+    {
+        *space_fh = slots_fh - occupied_fh;
+    }
+
+    if ((occupied_fh != 0) && (*space_fh < needed))
+    {
+        count_fhr = unifi_read_shared_count(card, card->sdio_ctrl_addr + 2);
+        if (count_fhr < 0)
+        {
+            unifi_error(card->ospriv, "Failed to read from-host sig read count\n");
+            return CSR_RESULT_FAILURE;
+        }
+        card->from_host_signals_r = count_fhr; /* diag */
+
+        occupied_fh = (count_fhw - count_fhr) % 128;
+        *space_fh = slots_fh - occupied_fh;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* check_fh_sig_slots() */
+
+
+/*
+* If we are padding the From-Host signals to the SDIO block size,
+* we need to round up the needed_chunks to the SDIO block size.
+*/
+#define ROUND_UP_NEEDED_CHUNKS(_card, _needed_chunks) \
+    { \
+        CsrUint16 _chunks_per_block; \
+        CsrUint16 _chunks_in_last_block; \
+ \
+        if (_card->sdio_io_block_pad) \
+        { \
+            _chunks_per_block = _card->sdio_io_block_size / _card->config_data.sig_frag_size; \
+            _chunks_in_last_block = _needed_chunks % _chunks_per_block; \
+            if (_chunks_in_last_block != 0) \
+            { \
+                _needed_chunks = _needed_chunks + (_chunks_per_block - _chunks_in_last_block); \
+            } \
+        } \
+    }
+
+
+#define ROUND_UP_SPACE_CHUNKS(_card, _space_chunks) \
+    { \
+        CsrUint16 _chunks_per_block; \
+ \
+        if (_card->sdio_io_block_pad) \
+        { \
+            _chunks_per_block = _card->sdio_io_block_size / _card->config_data.sig_frag_size; \
+            _space_chunks = ((_space_chunks / _chunks_per_block) * _chunks_per_block); \
+        } \
+    }
+
+
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  process_fh_cmd_queue
+ *
+ *      Take one signal off the from-host queue and copy it to the UniFi.
+ *      Does nothing if the UniFi has no slots free.
+ *
+ *  Arguments:
+ *      card       Pointer to card context struct
+ *      processed  Location to write:
+ *                      0 if there is nothing on the queue to process
+ *                      1 if a signal was successfully processed
+ *
+ *  Returns:
+ *      CSR error code if an error occurred.
+ *
+ *  Notes:
+ *      The from-host queue contains signal requests from the network driver
+ *      and any UDI clients interspersed. UDI clients' requests have been stored
+ *      in the from-host queue using the wire-format structures, as they arrive.
+ *      All other requests are stored in the from-host queue using the host
+ *      (cpu specific) structures. We use the is_packed member of the card_signal_t
+ *      structure that describes the queue to make the distiction.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult process_fh_cmd_queue(card_t *card, CsrInt32 *processed)
+{
+    q_t *sigq = &card->fh_command_queue;
+
+    CsrResult r;
+    CsrUint16 pending_sigs;
+    CsrUint16 pending_chunks;
+    CsrUint16 needed_chunks;
+    CsrInt32 space_chunks;
+    CsrUint16 q_index;
+
+    *processed = 0;
+
+    /* Get the number of pending signals. */
+    pending_sigs = CSR_WIFI_HIP_Q_SLOTS_USED(sigq);
+    unifi_trace(card->ospriv, UDBG5, "proc_fh: %d pending\n", pending_sigs);
+    if (pending_sigs == 0)
+    {
+        /* Nothing to do */
+        return CSR_RESULT_SUCCESS;
+    }
+
+    /* Work out how many chunks we have waiting to send */
+    for (pending_chunks = 0, q_index = CSR_WIFI_HIP_Q_NEXT_R_SLOT(sigq);
+         q_index != CSR_WIFI_HIP_Q_NEXT_W_SLOT(sigq);
+         q_index = CSR_WIFI_HIP_Q_WRAP(sigq, q_index + 1))
+    {
+        card_signal_t *csptr = CSR_WIFI_HIP_Q_SLOT_DATA(sigq, q_index);
+
+        /*
+         * Note that GET_CHUNKS_FOR() needs the size of the packed
+         * (wire-formatted) structure
+         */
+        pending_chunks += GET_CHUNKS_FOR(card->config_data.sig_frag_size, (CsrUint16)(csptr->signal_length + 2));
+    }
+
+    /*
+     * Check whether UniFi has space for all the buffered bulk-data
+     * commands and signals as well.
+     */
+    needed_chunks = pending_chunks + card->fh_buffer.count;
+
+    /* Round up to the block size if necessary */
+    ROUND_UP_NEEDED_CHUNKS(card, needed_chunks);
+
+    r = check_fh_sig_slots(card, needed_chunks, &space_chunks);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        /* Error */
+        unifi_error(card->ospriv, "Failed to read fh sig count\n");
+        return r;
+    }
+
+#ifdef CSR_WIFI_HIP_NOISY
+    unifi_error(card->ospriv, "proc_fh: %d chunks free, need %d\n",
+                space_chunks, needed_chunks);
+#endif /* CSR_WIFI_HIP_NOISY */
+
+
+    /*
+     * Coalesce as many from-host signals as possible
+     * into a single block and write using a single CMD53
+     */
+    if (needed_chunks > (CsrUint16)space_chunks)
+    {
+        /* Round up to the block size if necessary */
+        ROUND_UP_SPACE_CHUNKS(card, space_chunks);
+
+        /*
+         * If the f/w has less free chunks than those already pending
+         * return immediately.
+         */
+        if ((CsrUint16)space_chunks <= card->fh_buffer.count)
+        {
+            /*
+             * No room in UniFi for any signals after the buffered bulk
+             * data commands have been sent.
+             */
+            unifi_error(card->ospriv, "not enough room to send signals, need %d chunks, %d free\n",
+                        card->fh_buffer.count, space_chunks);
+            card->generate_interrupt = 1;
+            return CSR_RESULT_SUCCESS;
+        }
+        pending_chunks = (CsrUint16)(space_chunks - card->fh_buffer.count);
+    }
+
+    while (pending_sigs-- && pending_chunks > 0)
+    {
+        card_signal_t *csptr;
+        CsrInt16 i;
+        CsrUint16 sig_chunks, total_length, free_chunks_in_fh_buffer;
+        bulk_data_param_t bulkdata;
+        CsrUint8 *packed_sigptr;
+        CsrUint16 signal_length = 0;
+
+        /* Retrieve the entry at the head of the queue */
+        q_index = CSR_WIFI_HIP_Q_NEXT_R_SLOT(sigq);
+
+        /* Get a pointer to the containing card_signal_t struct */
+        csptr = CSR_WIFI_HIP_Q_SLOT_DATA(sigq, q_index);
+
+        /* Get the new length of the packed signal */
+        signal_length = csptr->signal_length;
+
+        if ((signal_length & 1) || (signal_length > UNIFI_PACKED_SIGBUF_SIZE))
+        {
+            unifi_error(card->ospriv, "process_fh_queue: Bad len: %d\n", signal_length);
+            return CSR_RESULT_FAILURE;
+        }
+
+        /* Need space for 2-byte SDIO protocol header + signal */
+        sig_chunks = GET_CHUNKS_FOR(card->config_data.sig_frag_size, (CsrUint16)(signal_length + 2));
+
+        free_chunks_in_fh_buffer = GET_CHUNKS_FOR(card->config_data.sig_frag_size,
+                                                  (CsrUint16)((card->fh_buffer.buf + UNIFI_FH_BUF_SIZE) - card->fh_buffer.ptr));
+        if (free_chunks_in_fh_buffer < sig_chunks)
+        {
+            /* No more room */
+            unifi_notice(card->ospriv, "proc_fh_cmd_q: no room in fh buffer for 0x%.4X, deferring\n",
+                         (CsrUint16)(GET_SIGNAL_ID(csptr->sigbuf)));
+            break;
+        }
+
+        packed_sigptr = csptr->sigbuf;
+
+        /* Claim and set up a from-host data slot */
+        if (CSR_RESULT_FAILURE == CardWriteBulkData(card, csptr, UNIFI_TRAFFIC_Q_MLME))
+        {
+            unifi_notice(card->ospriv, "proc_fh_cmd_q: no fh data slots for 0x%.4X, deferring\n",
+                         (CsrUint16)(GET_SIGNAL_ID(csptr->sigbuf)));
+            break;
+        }
+
+        for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++)
+        {
+            if (csptr->bulkdata[i].data_length == 0)
+            {
+                UNIFI_INIT_BULK_DATA(&bulkdata.d[i]);
+            }
+            else
+            {
+                bulkdata.d[i].os_data_ptr = csptr->bulkdata[i].os_data_ptr;
+                bulkdata.d[i].data_length = csptr->bulkdata[i].data_length;
+            }
+
+            /* Pass the free responsibility to the lower layer. */
+            UNIFI_INIT_BULK_DATA(&csptr->bulkdata[i]);
+        }
+
+        unifi_trace(card->ospriv, UDBG2, "Sending signal 0x%.4X\n",
+                    GET_SIGNAL_ID(packed_sigptr));
+#ifdef CSR_WIFI_HIP_NOISY
+        unifi_error(card->ospriv, "Sending signal 0x%.4X\n",
+                    GET_SIGNAL_ID(packed_sigptr));
+#endif  /* CSR_WIFI_HIP_NOISY */
+
+
+        /* Append packed signal to F-H buffer */
+        total_length = sig_chunks * card->config_data.sig_frag_size;
+
+        card->fh_buffer.ptr[0] = (CsrUint8)(signal_length & 0xff);
+        card->fh_buffer.ptr[1] =
+            (CsrUint8)(((signal_length >> 8) & 0xf) | (SDIO_CMD_SIGNAL << 4));
+
+        CsrMemCpy(card->fh_buffer.ptr + 2, packed_sigptr, signal_length);
+        CsrMemSet(card->fh_buffer.ptr + 2 + signal_length, 0,
+                  total_length - (2 + signal_length));
+
+#ifdef CSR_WIFI_HIP_NOISY
+        unifi_error(card->ospriv, "proc_fh: fh_buffer %d bytes \n",
+                    signal_length + 2);
+        dump(card->fh_buffer.ptr, signal_length + 2);
+        unifi_trace(card->ospriv, UDBG1, " \n");
+#endif  /* CSR_WIFI_HIP_NOISY */
+
+        card->fh_buffer.ptr += total_length;
+        card->fh_buffer.count += sig_chunks;
+
+#ifdef CSR_WIFI_HIP_NOISY
+        unifi_error(card->ospriv, "Added %d to fh buf, len now %d, count %d\n",
+                    signal_length,
+                    card->fh_buffer.ptr - card->fh_buffer.buf,
+                    card->fh_buffer.count);
+#endif  /* CSR_WIFI_HIP_NOISY */
+
+        (*processed)++;
+        pending_chunks -= sig_chunks;
+
+        /* Log the signal to the UDI. */
+        /* UDI will get the packed structure */
+        /* Can not log the unpacked signal, unless we reconstruct it! */
+        if (card->udi_hook)
+        {
+            (*card->udi_hook)(card->ospriv, packed_sigptr, signal_length,
+                              &bulkdata, UDI_LOG_FROM_HOST);
+        }
+
+        /* Remove entry from q */
+        csptr->signal_length = 0;
+        CSR_WIFI_HIP_Q_INC_R(sigq);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* process_fh_cmd_queue() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  process_fh_traffic_queue
+ *
+ *      Take signals off the from-host queue and copy them to the UniFi.
+ *      Does nothing if the UniFi has no slots free.
+ *
+ *  Arguments:
+ *      card       Pointer to card context struct
+ *      sigq       Pointer to the traffic queue
+ *      processed  Pointer to location to write:
+ *                      0 if there is nothing on the queue to process
+ *                      1 if a signal was successfully processed
+ *
+ *  Returns:
+ *      CSR error code if an error occurred.
+ *
+ *  Notes:
+ *      The from-host queue contains signal requests from the network driver
+ *      and any UDI clients interspersed.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult process_fh_traffic_queue(card_t *card, CsrInt32 *processed)
+{
+    q_t *sigq = card->fh_traffic_queue;
+
+    CsrResult r;
+    CsrInt16 n = 0;
+    CsrInt32 q_no;
+    CsrUint16 pending_sigs = 0;
+    CsrUint16 pending_chunks = 0;
+    CsrUint16 needed_chunks;
+    CsrInt32 space_chunks;
+    CsrUint16 q_index;
+    CsrUint32 host_tag = 0;
+    CsrUint16 slot_num = 0;
+
+    *processed = 0;
+
+    /* calculate how many signals are in queues and how many chunks are needed. */
+    for (n = UNIFI_NO_OF_TX_QS - 1; n >= 0; n--)
+    {
+        /* Get the number of pending signals. */
+        pending_sigs += CSR_WIFI_HIP_Q_SLOTS_USED(&sigq[n]);
+        unifi_trace(card->ospriv, UDBG5, "proc_fh%d: %d pending\n", n, pending_sigs);
+
+        /* Work out how many chunks we have waiting to send */
+        for (q_index = CSR_WIFI_HIP_Q_NEXT_R_SLOT(&sigq[n]);
+             q_index != CSR_WIFI_HIP_Q_NEXT_W_SLOT(&sigq[n]);
+             q_index = CSR_WIFI_HIP_Q_WRAP(&sigq[n], q_index + 1))
+        {
+            card_signal_t *csptr = CSR_WIFI_HIP_Q_SLOT_DATA(&sigq[n], q_index);
+
+            /*
+             * Note that GET_CHUNKS_FOR() needs the size of the packed
+             * (wire-formatted) structure
+             */
+            pending_chunks += GET_CHUNKS_FOR(card->config_data.sig_frag_size, (CsrUint16)(csptr->signal_length + 2));
+        }
+    }
+
+    /* If there are no pending signals, just return */
+    if (pending_sigs == 0)
+    {
+        /* Nothing to do */
+        return CSR_RESULT_SUCCESS;
+    }
+
+    /*
+     * Check whether UniFi has space for all the buffered bulk-data
+     * commands and signals as well.
+     */
+    needed_chunks = pending_chunks + card->fh_buffer.count;
+
+    /* Round up to the block size if necessary */
+    ROUND_UP_NEEDED_CHUNKS(card, needed_chunks);
+
+    r = check_fh_sig_slots(card, needed_chunks, &space_chunks);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        /* Error */
+        unifi_error(card->ospriv, "Failed to read fh sig count\n");
+        return r;
+    }
+
+#ifdef CSR_WIFI_HIP_NOISY
+    unifi_error(card->ospriv,
+                "process_fh_traffic_queue: %d chunks free, need %d\n",
+                space_chunks, needed_chunks);
+    read_fhsr(card);            /* debugging only */
+#endif /* CSR_WIFI_HIP_NOISY */
+
+    /* Coalesce as many from-host signals as possible
+       into a single block and write using a single CMD53 */
+    if (needed_chunks > (CsrUint16)space_chunks)
+    {
+        /* Round up to the block size if necessary */
+        ROUND_UP_SPACE_CHUNKS(card, space_chunks);
+
+        if ((CsrUint16)space_chunks <= card->fh_buffer.count)
+        {
+            /*
+             * No room in UniFi for any signals after the buffered bulk
+             * data commands have been sent.
+             */
+            unifi_error(card->ospriv, "not enough room to send signals, need %d chunks, %d free\n",
+                        card->fh_buffer.count, space_chunks);
+            card->generate_interrupt = 1;
+            return 0;
+        }
+
+        pending_chunks = (CsrUint16)space_chunks - card->fh_buffer.count;
+    }
+
+    q_no = UNIFI_NO_OF_TX_QS - 1;
+
+    /*
+     * pending_sigs will be exhausted if there are is no restriction to the pending
+     * signals per queue. pending_chunks may be exhausted if there is a restriction.
+     * q_no check will be exhausted if there is a restriction and our round-robin
+     * algorith fails to fill all chunks.
+     */
+    do
+    {
+        card_signal_t *csptr;
+        CsrUint16 sig_chunks, total_length, free_chunks_in_fh_buffer;
+        bulk_data_param_t bulkdata;
+        CsrUint8 *packed_sigptr;
+        CsrUint16 signal_length = 0;
+
+        /* if this queue is empty go to next one. */
+        if (CSR_WIFI_HIP_Q_SLOTS_USED(&sigq[q_no]) == 0)
+        {
+            q_no--;
+            continue;
+        }
+
+        /* Retrieve the entry at the head of the queue */
+        q_index = CSR_WIFI_HIP_Q_NEXT_R_SLOT(&sigq[q_no]);
+
+        /* Get a pointer to the containing card_signal_t struct */
+        csptr = CSR_WIFI_HIP_Q_SLOT_DATA(&sigq[q_no], q_index);
+
+        /* Get the new length of the packed signal */
+        signal_length = csptr->signal_length;
+
+        if ((signal_length & 1) || (signal_length > UNIFI_PACKED_SIGBUF_SIZE))
+        {
+            unifi_error(card->ospriv, "process_fh_traffic_queue: Bad len: %d\n", signal_length);
+            return CSR_RESULT_FAILURE;
+        }
+
+        /* Need space for 2-byte SDIO protocol header + signal */
+        sig_chunks = GET_CHUNKS_FOR(card->config_data.sig_frag_size, (CsrUint16)(signal_length + 2));
+        free_chunks_in_fh_buffer = GET_CHUNKS_FOR(card->config_data.sig_frag_size,
+                                                  (CsrUint16)((card->fh_buffer.buf + UNIFI_FH_BUF_SIZE) - card->fh_buffer.ptr));
+        if (free_chunks_in_fh_buffer < sig_chunks)
+        {
+            /* No more room */
+            unifi_notice(card->ospriv, "process_fh_traffic_queue: no more chunks.\n");
+            break;
+        }
+
+        packed_sigptr = csptr->sigbuf;
+        /* Claim and set up a from-host data slot */
+        if (CSR_RESULT_FAILURE == CardWriteBulkData(card, csptr, (unifi_TrafficQueue)q_no))
+        {
+            q_no--;
+            continue;
+        }
+
+        /* Sanity check: MA-PACKET.req must have a valid bulk data */
+        if ((csptr->bulkdata[0].data_length == 0) || (csptr->bulkdata[0].os_data_ptr == NULL))
+        {
+            unifi_error(card->ospriv, "MA-PACKET.req with empty bulk data (%d bytes in %p)\n",
+                        csptr->bulkdata[0].data_length, csptr->bulkdata[0].os_data_ptr);
+            dump(packed_sigptr, signal_length);
+            return CSR_RESULT_FAILURE;
+        }
+
+        bulkdata.d[0].os_data_ptr = csptr->bulkdata[0].os_data_ptr;
+        bulkdata.d[0].data_length = csptr->bulkdata[0].data_length;
+        bulkdata.d[0].os_net_buf_ptr = csptr->bulkdata[0].os_net_buf_ptr;
+        bulkdata.d[0].net_buf_length = csptr->bulkdata[0].net_buf_length;
+
+        /* The driver owns clearing of HIP slots for following scenario
+         * - driver has requested a MA-PACKET.req signal
+         * - The f/w after receiving the signal decides it can't send it out due to various reasons
+         * - So the f/w without downloading the bulk data decides to just send a confirmation with fail
+         * - and then sends a clear slot signal to HIP
+         *
+         * But in some cases the clear slot signal never comes and the slot remains --NOT-- freed for ever
+         *
+         * To handle this, HIP will keep the record of host tag for each occupied slot
+         * and then based on status of that Host tag and slot the driver will decide if the slot is
+         * cleared by f/w signal or the slot has to be freed by driver
+         */
+
+        if (card->fh_slot_host_tag_record)
+        {
+            /* Update the f-h slot record for the corresponding host tag */
+            host_tag = GET_PACKED_MA_PACKET_REQUEST_HOST_TAG(packed_sigptr);
+            slot_num = GET_PACKED_DATAREF_SLOT(packed_sigptr, 0) & 0x00FF;
+
+            unifi_trace(card->ospriv, UDBG5,
+                        "process_fh_traffic_queue signal ID =%x fh slot=%x Host tag =%x\n",
+                        GET_SIGNAL_ID(packed_sigptr), slot_num, host_tag);
+            card->fh_slot_host_tag_record[slot_num] = host_tag;
+        }
+        UNIFI_INIT_BULK_DATA(&bulkdata.d[1]);
+        UNIFI_INIT_BULK_DATA(&csptr->bulkdata[0]);
+        UNIFI_INIT_BULK_DATA(&csptr->bulkdata[1]);
+
+#ifdef CSR_WIFI_HIP_DATA_PLANE_PROFILE
+        if (bulkdata.d[0].os_data_ptr)
+        {
+            if ((*bulkdata.d[0].os_data_ptr) & 0x08)
+            {
+                card->cmd_prof.tx_count++;
+            }
+        }
+#endif
+        unifi_trace(card->ospriv, UDBG3, "Sending signal 0x%.4X\n",
+                    GET_SIGNAL_ID(packed_sigptr));
+#ifdef CSR_WIFI_HIP_NOISY
+        unifi_error(card->ospriv, "Sending signal 0x%.4X\n",
+                    GET_SIGNAL_ID(packed_sigptr));
+#endif  /* CSR_WIFI_HIP_NOISY */
+
+        /* Append packed signal to F-H buffer */
+        total_length = sig_chunks * card->config_data.sig_frag_size;
+
+        card->fh_buffer.ptr[0] = (CsrUint8)(signal_length & 0xff);
+        card->fh_buffer.ptr[1] =
+            (CsrUint8)(((signal_length >> 8) & 0xf) | (SDIO_CMD_SIGNAL << 4));
+
+        CsrMemCpy(card->fh_buffer.ptr + 2, packed_sigptr, signal_length);
+        CsrMemSet(card->fh_buffer.ptr + 2 + signal_length, 0,
+                  total_length - (2 + signal_length));
+
+#ifdef CSR_WIFI_HIP_NOISY
+        unifi_error(card->ospriv, "proc_fh: fh_buffer %d bytes \n",
+                    signal_length + 2);
+        dump(card->fh_buffer.ptr, signal_length + 2);
+        unifi_trace(card->ospriv, UDBG1, " \n");
+#endif  /* CSR_WIFI_HIP_NOISY */
+
+        card->fh_buffer.ptr += total_length;
+        card->fh_buffer.count += sig_chunks;
+
+#ifdef CSR_WIFI_HIP_NOISY
+        unifi_error(card->ospriv, "Added %d to fh buf, len now %d, count %d\n",
+                    signal_length,
+                    card->fh_buffer.ptr - card->fh_buffer.buf,
+                    card->fh_buffer.count);
+#endif  /* CSR_WIFI_HIP_NOISY */
+
+        (*processed)++;
+        pending_sigs--;
+        pending_chunks -= sig_chunks;
+
+        /* Log the signal to the UDI. */
+        /* UDI will get the packed structure */
+        /* Can not log the unpacked signal, unless we reconstruct it! */
+        if (card->udi_hook)
+        {
+            (*card->udi_hook)(card->ospriv, packed_sigptr, signal_length,
+                              &bulkdata, UDI_LOG_FROM_HOST);
+        }
+
+        /* Remove entry from q */
+        csptr->signal_length = 0;
+        /* Note that the traffic queue has only one valid bulk data buffer. */
+        csptr->bulkdata[0].data_length = 0;
+
+        CSR_WIFI_HIP_Q_INC_R(&sigq[q_no]);
+    } while ((pending_sigs > 0) && (pending_chunks > 0) && (q_no >= 0));
+
+    return CSR_RESULT_SUCCESS;
+} /* process_fh_traffic_queue() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  flush_fh_buffer
+ *
+ *      Write out the cache from-hosts signals to the UniFi.
+ *
+ *  Arguments:
+ *      card       Pointer to card context struct
+ *
+ *  Returns:
+ *      CSR error code if an SDIO error occurred.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult flush_fh_buffer(card_t *card)
+{
+    CsrResult r;
+    CsrUint16 len;
+    CsrUint16 sig_units;
+    CsrUint16 data_round;
+    CsrUint16 chunks_in_last_block;
+    CsrUint16 padding_chunks;
+    CsrUint16 i;
+
+    len = card->fh_buffer.ptr - card->fh_buffer.buf;
+
+#ifdef CSR_WIFI_HIP_NOISY
+    unifi_error(card->ospriv, "fh_buffer is at %p, ptr= %p\n",
+                card->fh_buffer.buf, card->fh_buffer.ptr);
+#endif /* CSR_WIFI_HIP_NOISY */
+
+    if (len == 0)
+    {
+        return CSR_RESULT_SUCCESS;
+    }
+
+#ifdef CSR_WIFI_HIP_NOISY
+    if (dump_fh_buf)
+    {
+        dump(card->fh_buffer.buf, len);
+        dump_fh_buf = 0;
+    }
+#endif /* CSR_WIFI_HIP_NOISY */
+
+    if (card->sdio_io_block_pad)
+    {
+        /* Both of these are powers of 2 */
+        sig_units = card->config_data.sig_frag_size;
+        data_round = card->sdio_io_block_size;
+
+        if (data_round > sig_units)
+        {
+            chunks_in_last_block = (len % data_round) / sig_units;
+
+            if (chunks_in_last_block != 0)
+            {
+                padding_chunks = (data_round / sig_units) - chunks_in_last_block;
+
+                CsrMemSet(card->fh_buffer.ptr, 0, padding_chunks * sig_units);
+                for (i = 0; i < padding_chunks; i++)
+                {
+                    card->fh_buffer.ptr[1] = SDIO_CMD_PADDING << 4;
+                    card->fh_buffer.ptr += sig_units;
+                }
+
+                card->fh_buffer.count += padding_chunks;
+                len += padding_chunks * sig_units;
+            }
+        }
+    }
+
+    r = unifi_bulk_rw(card,
+                      card->config_data.fromhost_sigbuf_handle,
+                      card->fh_buffer.buf,
+                      len, UNIFI_SDIO_WRITE);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to write fh signals: %u bytes, error %d\n", len, r);
+        return r;
+    }
+
+    /* Update from-host-signals-written signal count */
+    card->from_host_signals_w =
+        (card->from_host_signals_w + card->fh_buffer.count) % 128u;
+    r = unifi_write_8_or_16(card, card->sdio_ctrl_addr + 0,
+                            (CsrUint8)card->from_host_signals_w);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to write fh signal count %u with error %d\n",
+                    card->from_host_signals_w, r);
+        return r;
+    }
+    card->generate_interrupt = 1;
+
+    /* Reset the fh buffer pointer */
+    card->fh_buffer.ptr = card->fh_buffer.buf;
+    card->fh_buffer.count = 0;
+
+#ifdef CSR_WIFI_HIP_NOISY
+    unifi_error(card->ospriv, "END flush: fh len %d, count %d\n",
+                card->fh_buffer.ptr - card->fh_buffer.buf,
+                card->fh_buffer.count);
+#endif /* CSR_WIFI_HIP_NOISY */
+
+    return CSR_RESULT_SUCCESS;
+} /* flush_fh_buffer() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  restart_packet_flow
+ *
+ *      This function is called before the bottom-half thread sleeps.
+ *      It checks whether both data and signal resources are available and
+ *      then calls the OS-layer function to re-enable packet transmission.
+ *
+ *  Arguments:
+ *      card       Pointer to card context struct
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void restart_packet_flow(card_t *card)
+{
+    CsrUint8 q;
+
+    /*
+     * We only look at the fh_traffic_queue, because that is where packets from
+     * the network stack are placed.
+     */
+    for (q = 0; q <= UNIFI_TRAFFIC_Q_VO; q++)
+    {
+        if (card_is_tx_q_paused(card, q) &&
+            CSR_WIFI_HIP_Q_SLOTS_FREE(&card->fh_traffic_queue[q]) >= RESUME_XMIT_THRESHOLD)
+        {
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+            unifi_debug_log_to_buf("U");
+#endif
+            card_tx_q_unpause(card, q);
+            unifi_restart_xmit(card->ospriv, (unifi_TrafficQueue)q);
+        }
+    }
+} /* restart_packet_flow() */
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_card_sdio_mem.c b/drivers/staging/csr/csr_wifi_hip_card_sdio_mem.c
new file mode 100644
index 0000000..8bc2d74
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_card_sdio_mem.c
@@ -0,0 +1,1713 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ * FILE: csr_wifi_hip_card_sdio_mem.c
+ *
+ * PURPOSE: Implementation of the Card API for SDIO.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_card.h"
+
+#define SDIO_RETRIES    3
+#define CSR_WIFI_HIP_SDIO_TRACE_DATA_LENGTH 16
+
+
+#define retryable_sdio_error(_csrResult) (((_csrResult) == CSR_SDIO_RESULT_CRC_ERROR) || ((_csrResult) == CSR_SDIO_RESULT_TIMEOUT))
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  retrying_read8
+ *  retrying_write8
+ *
+ *      These functions provide the first level of retry for SDIO operations.
+ *      If an SDIO command fails for reason of a response timeout or CRC
+ *      error, it is retried immediately. If three attempts fail we report a
+ *      failure.
+ *      If the command failed for any other reason, the failure is reported
+ *      immediately.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      funcnum         The SDIO function to access.
+ *                      Function 0 is the Card Configuration Register space,
+ *                      function 1/2 is the UniFi register space.
+ *      addr            Address to access
+ *      pdata           Pointer in which to return the value read.
+ *      data            Value to write.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS  on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult retrying_read8(card_t *card, CsrInt16 funcnum, CsrUint32 addr, CsrUint8 *pdata)
+{
+    CsrSdioFunction *sdio = card->sdio_if;
+    CsrResult r = CSR_RESULT_SUCCESS;
+    CsrInt16 retries;
+    CsrResult csrResult = CSR_RESULT_SUCCESS;
+
+    retries = 0;
+    while (retries++ < SDIO_RETRIES)
+    {
+        if (funcnum == 0)
+        {
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+            unifi_debug_log_to_buf("r0@%02X", addr);
+#endif
+            csrResult = CsrSdioF0Read8(sdio, addr, pdata);
+        }
+        else
+        {
+#ifdef CSR_WIFI_TRANSPORT_CSPI
+            unifi_error(card->ospriv,
+                        "retrying_read_f0_8: F1 8-bit reads are not allowed.\n");
+            return CSR_RESULT_FAILURE;
+#else
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+            unifi_debug_log_to_buf("r@%02X", addr);
+#endif
+            csrResult = CsrSdioRead8(sdio, addr, pdata);
+#endif
+        }
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+        if (csrResult != CSR_RESULT_SUCCESS)
+        {
+            unifi_debug_log_to_buf("error=%X\n", csrResult);
+        }
+        else
+        {
+            unifi_debug_log_to_buf("=%X\n", *pdata);
+        }
+#endif
+        if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+        {
+            return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+        }
+        /*
+         * Try again for retryable (CRC or TIMEOUT) errors,
+         * break on success or fatal error
+         */
+        if (!retryable_sdio_error(csrResult))
+        {
+#ifdef CSR_WIFI_HIP_DATA_PLANE_PROFILE
+            card->cmd_prof.cmd52_count++;
+#endif
+            break;
+        }
+        unifi_trace(card->ospriv, UDBG2, "retryable SDIO error reading F%d 0x%lX\n", funcnum, addr);
+    }
+
+    if ((csrResult == CSR_RESULT_SUCCESS) && (retries > 1))
+    {
+        unifi_warning(card->ospriv, "Read succeeded after %d attempts\n", retries);
+    }
+
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to read from UniFi (addr 0x%lX) after %d tries\n",
+                    addr, retries - 1);
+        /* Report any SDIO error as a general i/o error */
+        r = CSR_RESULT_FAILURE;
+    }
+
+    return r;
+} /* retrying_read8() */
+
+
+static CsrResult retrying_write8(card_t *card, CsrInt16 funcnum, CsrUint32 addr, CsrUint8 data)
+{
+    CsrSdioFunction *sdio = card->sdio_if;
+    CsrResult r = CSR_RESULT_SUCCESS;
+    CsrInt16 retries;
+    CsrResult csrResult = CSR_RESULT_SUCCESS;
+
+    retries = 0;
+    while (retries++ < SDIO_RETRIES)
+    {
+        if (funcnum == 0)
+        {
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+            unifi_debug_log_to_buf("w0@%02X=%X", addr, data);
+#endif
+            csrResult = CsrSdioF0Write8(sdio, addr, data);
+        }
+        else
+        {
+#ifdef CSR_WIFI_TRANSPORT_CSPI
+            unifi_error(card->ospriv,
+                        "retrying_write_f0_8: F1 8-bit writes are not allowed.\n");
+            return CSR_RESULT_FAILURE;
+#else
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+            unifi_debug_log_to_buf("w@%02X=%X", addr, data);
+#endif
+            csrResult = CsrSdioWrite8(sdio, addr, data);
+#endif
+        }
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+        if (csrResult != CSR_RESULT_SUCCESS)
+        {
+            unifi_debug_log_to_buf(",error=%X", csrResult);
+        }
+        unifi_debug_string_to_buf("\n");
+#endif
+        if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+        {
+            return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+        }
+        /*
+         * Try again for retryable (CRC or TIMEOUT) errors,
+         * break on success or fatal error
+         */
+        if (!retryable_sdio_error(csrResult))
+        {
+#ifdef CSR_WIFI_HIP_DATA_PLANE_PROFILE
+            card->cmd_prof.cmd52_count++;
+#endif
+            break;
+        }
+        unifi_trace(card->ospriv, UDBG2, "retryable SDIO error writing %02X to F%d 0x%lX\n",
+                    data, funcnum, addr);
+    }
+
+    if ((csrResult == CSR_RESULT_SUCCESS) && (retries > 1))
+    {
+        unifi_warning(card->ospriv, "Write succeeded after %d attempts\n", retries);
+    }
+
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to write to UniFi (addr 0x%lX) after %d tries\n",
+                    addr, retries - 1);
+        /* Report any SDIO error as a general i/o error */
+        r = CSR_RESULT_FAILURE;
+    }
+
+    return r;
+} /* retrying_write8() */
+
+
+static CsrResult retrying_read16(card_t *card, CsrInt16 funcnum,
+                                 CsrUint32 addr, CsrUint16 *pdata)
+{
+    CsrSdioFunction *sdio = card->sdio_if;
+    CsrResult r = CSR_RESULT_SUCCESS;
+    CsrInt16 retries;
+    CsrResult csrResult = CSR_RESULT_SUCCESS;
+
+    retries = 0;
+    while (retries++ < SDIO_RETRIES)
+    {
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+        unifi_debug_log_to_buf("r@%02X", addr);
+#endif
+        csrResult = CsrSdioRead16(sdio, addr, pdata);
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+        if (csrResult != CSR_RESULT_SUCCESS)
+        {
+            unifi_debug_log_to_buf("error=%X\n", csrResult);
+        }
+        else
+        {
+            unifi_debug_log_to_buf("=%X\n", *pdata);
+        }
+#endif
+        if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+        {
+            return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+        }
+
+        /*
+         * Try again for retryable (CRC or TIMEOUT) errors,
+         * break on success or fatal error
+         */
+        if (!retryable_sdio_error(csrResult))
+        {
+#ifdef CSR_WIFI_HIP_DATA_PLANE_PROFILE
+            card->cmd_prof.cmd52_count++;
+#endif
+            break;
+        }
+        unifi_trace(card->ospriv, UDBG2, "retryable SDIO error reading F%d 0x%lX\n", funcnum, addr);
+    }
+
+    if ((csrResult == CSR_RESULT_SUCCESS) && (retries > 1))
+    {
+        unifi_warning(card->ospriv, "Read succeeded after %d attempts\n", retries);
+    }
+
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to read from UniFi (addr 0x%lX) after %d tries\n",
+                    addr, retries - 1);
+        /* Report any SDIO error as a general i/o error */
+        r = CSR_RESULT_FAILURE;
+    }
+
+    return r;
+} /* retrying_read16() */
+
+
+static CsrResult retrying_write16(card_t *card, CsrInt16 funcnum,
+                                  CsrUint32 addr, CsrUint16 data)
+{
+    CsrSdioFunction *sdio = card->sdio_if;
+    CsrResult r = CSR_RESULT_SUCCESS;
+    CsrInt16 retries;
+    CsrResult csrResult = CSR_RESULT_SUCCESS;
+
+    retries = 0;
+    while (retries++ < SDIO_RETRIES)
+    {
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+        unifi_debug_log_to_buf("w@%02X=%X", addr, data);
+#endif
+        csrResult = CsrSdioWrite16(sdio, addr, data);
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+        if (csrResult != CSR_RESULT_SUCCESS)
+        {
+            unifi_debug_log_to_buf(",error=%X", csrResult);
+        }
+        unifi_debug_string_to_buf("\n");
+#endif
+        if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+        {
+            return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+        }
+
+        /*
+         * Try again for retryable (CRC or TIMEOUT) errors,
+         * break on success or fatal error
+         */
+        if (!retryable_sdio_error(csrResult))
+        {
+#ifdef CSR_WIFI_HIP_DATA_PLANE_PROFILE
+            card->cmd_prof.cmd52_count++;
+#endif
+            break;
+        }
+        unifi_trace(card->ospriv, UDBG2, "retryable SDIO error writing %02X to F%d 0x%lX\n",
+                    data, funcnum, addr);
+    }
+
+    if ((csrResult == CSR_RESULT_SUCCESS) && (retries > 1))
+    {
+        unifi_warning(card->ospriv, "Write succeeded after %d attempts\n", retries);
+    }
+
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to write to UniFi (addr 0x%lX) after %d tries\n",
+                    addr, retries - 1);
+        /* Report any SDIO error as a general i/o error */
+        r = CSR_RESULT_FAILURE;
+    }
+
+    return r;
+} /* retrying_write16() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  sdio_read_f0
+ *
+ *      Reads a byte value from the CCCR (func 0) area of UniFi.
+ *
+ *  Arguments:
+ *      card    Pointer to card structure.
+ *      addr    Address to read from
+ *      pdata   Pointer in which to store the read value.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ * ---------------------------------------------------------------------------
+ */
+CsrResult sdio_read_f0(card_t *card, CsrUint32 addr, CsrUint8 *pdata)
+{
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+    card->cmd_prof.cmd52_f0_r_count++;
+#endif
+    return retrying_read8(card, 0, addr, pdata);
+} /* sdio_read_f0() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  sdio_write_f0
+ *
+ *      Writes a byte value to the CCCR (func 0) area of UniFi.
+ *
+ *  Arguments:
+ *      card    Pointer to card structure.
+ *      addr    Address to read from
+ *      data    Data value to write.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ * ---------------------------------------------------------------------------
+ */
+CsrResult sdio_write_f0(card_t *card, CsrUint32 addr, CsrUint8 data)
+{
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+    card->cmd_prof.cmd52_f0_w_count++;
+#endif
+    return retrying_write8(card, 0, addr, data);
+} /* sdio_write_f0() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * unifi_read_direct_8_or_16
+ *
+ *      Read a 8-bit value from the UniFi SDIO interface.
+ *
+ *  Arguments:
+ *      card    Pointer to card structure.
+ *      addr    Address to read from
+ *      pdata   Pointer in which to return data.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_read_direct_8_or_16(card_t *card, CsrUint32 addr, CsrUint8 *pdata)
+{
+#ifdef CSR_WIFI_TRANSPORT_CSPI
+    CsrUint16 w;
+    CsrResult r;
+
+    r = retrying_read16(card, card->function, addr, &w);
+    *pdata = (CsrUint8)(w & 0xFF);
+    return r;
+#else
+    return retrying_read8(card, card->function, addr, pdata);
+#endif
+} /* unifi_read_direct_8_or_16() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_write_direct_8_or_16
+ *
+ *      Write a byte value to the UniFi SDIO interface.
+ *
+ *  Arguments:
+ *      card    Pointer to card structure.
+ *      addr    Address to write to
+ *      data    Value to write.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error
+ *
+ *  Notes:
+ *      If 8-bit write is used, the even address *must* be written second.
+ *      This is because writes to odd bytes are cached and not committed
+ *      to memory until the preceding even address is written.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_write_direct_8_or_16(card_t *card, CsrUint32 addr, CsrUint8 data)
+{
+    if (addr & 1)
+    {
+        unifi_warning(card->ospriv,
+                      "Warning: Byte write to an odd address (0x%lX) is dangerous\n",
+                      addr);
+    }
+
+#ifdef CSR_WIFI_TRANSPORT_CSPI
+    return retrying_write16(card, card->function, addr, (CsrUint16)data);
+#else
+    return retrying_write8(card, card->function, addr, data);
+#endif
+} /* unifi_write_direct_8_or_16() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_read_direct16
+ *
+ *      Read a 16-bit value from the UniFi SDIO interface.
+ *
+ *  Arguments:
+ *      card    Pointer to card structure.
+ *      addr    Address to read from
+ *      pdata   Pointer in which to return data.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *
+ *  Notes:
+ *      The even address *must* be read first. This is because reads from
+ *      odd bytes are cached and read from memory when the preceding
+ *      even address is read.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_read_direct16(card_t *card, CsrUint32 addr, CsrUint16 *pdata)
+{
+    return retrying_read16(card, card->function, addr, pdata);
+} /* unifi_read_direct16() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_write_direct16
+ *
+ *      Write a 16-bit value to the UniFi SDIO interface.
+ *
+ *  Arguments:
+ *      card    Pointer to card structure.
+ *      addr    Address to write to
+ *      data    Value to write.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *
+ *  Notes:
+ *      The even address *must* be written second. This is because writes to
+ *      odd bytes are cached and not committed to memory until the preceding
+ *      even address is written.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_write_direct16(card_t *card, CsrUint32 addr, CsrUint16 data)
+{
+    return retrying_write16(card, card->function, addr, data);
+} /* unifi_write_direct16() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_read_direct32
+ *
+ *      Read a 32-bit value from the UniFi SDIO interface.
+ *
+ *  Arguments:
+ *      card    Pointer to card structure.
+ *      addr    Address to read from
+ *      pdata   Pointer in which to return data.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_read_direct32(card_t *card, CsrUint32 addr, CsrUint32 *pdata)
+{
+    CsrResult r;
+    CsrUint16 w0, w1;
+
+    r = retrying_read16(card, card->function, addr, &w0);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+    r = retrying_read16(card, card->function, addr + 2, &w1);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+    *pdata = ((CsrUint32)w1 << 16) | (CsrUint32)w0;
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_read_direct32() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_read_directn_match
+ *
+ *      Read multiple 8-bit values from the UniFi SDIO interface,
+ *      stopping when either we have read 'len' bytes or we have read
+ *      a octet equal to 'match'.  If 'match' is not a valid octet
+ *      then this function is the same as 'unifi_read_directn'.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      addr            Start address to read from.
+ *      pdata           Pointer to which to write data.
+ *      len             Maximum umber of bytes to read
+ *      match           The value to stop reading at.
+ *      num             Pointer to buffer to write number of bytes read
+ *
+ *  Returns:
+ *      number of octets read on success, negative error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *
+ *  Notes:
+ *      The even address *must* be read first. This is because reads from
+ *      odd bytes are cached and read from memory when the preceding
+ *      even address is read.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult unifi_read_directn_match(card_t *card, CsrUint32 addr, void *pdata, CsrUint16 len, CsrInt8 m, CsrUint32 *num)
+{
+    CsrResult r;
+    CsrUint32 i;
+    CsrUint8 *cptr;
+    CsrUint16 w;
+
+    *num = 0;
+
+    cptr = (CsrUint8 *)pdata;
+    for (i = 0; i < len; i += 2)
+    {
+        r = retrying_read16(card, card->function, addr, &w);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            return r;
+        }
+
+        *cptr++ = ((CsrUint8)w & 0xFF);
+        if ((m >= 0) && (((CsrInt8)w & 0xFF) == m))
+        {
+            break;
+        }
+
+        if (i + 1 == len)
+        {
+            /* The len is odd. Ignore the last high byte */
+            break;
+        }
+
+        *cptr++ = ((CsrUint8)(w >> 8) & 0xFF);
+        if ((m >= 0) && (((CsrInt8)(w >> 8) & 0xFF) == m))
+        {
+            break;
+        }
+
+        addr += 2;
+    }
+
+    *num = (CsrInt32)(cptr - (CsrUint8 *)pdata);
+    return CSR_RESULT_SUCCESS;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_read_directn
+ *
+ *      Read multiple 8-bit values from the UniFi SDIO interface.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      addr            Start address to read from.
+ *      pdata           Pointer to which to write data.
+ *      len             Number of bytes to read
+ *
+ *  Returns:
+ *      0 on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *
+ *  Notes:
+ *      The even address *must* be read first. This is because reads from
+ *      odd bytes are cached and read from memory when the preceding
+ *      even address is read.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_read_directn(card_t *card, CsrUint32 addr, void *pdata, CsrUint16 len)
+{
+    CsrUint32 num;
+
+    return unifi_read_directn_match(card, addr, pdata, len, -1, &num);
+} /* unifi_read_directn() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_write_directn
+ *
+ *      Write multiple 8-bit values to the UniFi SDIO interface.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      addr            Start address to write to.
+ *      pdata           Source data pointer.
+ *      len             Number of bytes to write, must be even.
+ *
+ *  Returns:
+ *      0 on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *
+ *  Notes:
+ *      The UniFi has a peculiar 16-bit bus architecture. Writes are only
+ *      committed to memory when an even address is accessed. Writes to
+ *      odd addresses are cached and only committed if the next write is
+ *      to the preceding address.
+ *      This means we must write data as pairs of bytes in reverse order.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_write_directn(card_t *card, CsrUint32 addr, void *pdata, CsrUint16 len)
+{
+    CsrResult r;
+    CsrUint8 *cptr;
+    CsrInt16 signed_len;
+
+    cptr = (CsrUint8 *)pdata;
+    signed_len = (CsrInt16)len;
+    while (signed_len > 0)
+    {
+        /* This is UniFi-1 specific code. CSPI not supported so 8-bit write allowed */
+        r = retrying_write16(card, card->function, addr, *cptr);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            return r;
+        }
+
+        cptr += 2;
+        addr += 2;
+        signed_len -= 2;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_write_directn() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  set_dmem_page
+ *  set_pmem_page
+ *
+ *      Set up the page register for the shared data memory window or program
+ *      memory window.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      dmem_addr       UniFi shared-data-memory address to access.
+ *      pmem_addr       UniFi program memory address to access. This includes
+ *                        External FLASH memory at    0x000000
+ *                        Processor program memory at 0x200000
+ *                        External SRAM at memory     0x400000
+ *      paddr           Location to write an SDIO address (24-bit) for
+ *                       use in a unifi_read_direct or unifi_write_direct call.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE card was ejected
+ *      CSR_RESULT_FAILURE an SDIO error occurred
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult set_dmem_page(card_t *card, CsrUint32 dmem_addr, CsrUint32 *paddr)
+{
+    CsrUint16 page, addr;
+    CsrUint32 len;
+    CsrResult r;
+
+    *paddr = 0;
+
+    if (!ChipHelper_DecodeWindow(card->helper,
+                                 CHIP_HELPER_WINDOW_3,
+                                 CHIP_HELPER_WT_SHARED,
+                                 dmem_addr / 2,
+                                 &page, &addr, &len))
+    {
+        unifi_error(card->ospriv, "Failed to decode SHARED_DMEM_PAGE %08lx\n", dmem_addr);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    if (page != card->dmem_page)
+    {
+        unifi_trace(card->ospriv, UDBG6, "setting dmem page=0x%X, addr=0x%lX\n", page, addr);
+
+        /* change page register */
+        r = unifi_write_direct16(card, ChipHelper_HOST_WINDOW3_PAGE(card->helper) * 2, page);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to write SHARED_DMEM_PAGE\n");
+            return r;
+        }
+
+        card->dmem_page = page;
+    }
+
+    *paddr = ((CsrInt32)addr * 2) + (dmem_addr & 1);
+
+    return CSR_RESULT_SUCCESS;
+} /* set_dmem_page() */
+
+
+static CsrResult set_pmem_page(card_t *card, CsrUint32 pmem_addr,
+                               enum chip_helper_window_type mem_type, CsrUint32 *paddr)
+{
+    CsrUint16 page, addr;
+    CsrUint32 len;
+    CsrResult r;
+
+    *paddr = 0;
+
+    if (!ChipHelper_DecodeWindow(card->helper,
+                                 CHIP_HELPER_WINDOW_2,
+                                 mem_type,
+                                 pmem_addr / 2,
+                                 &page, &addr, &len))
+    {
+        unifi_error(card->ospriv, "Failed to decode PROG MEM PAGE %08lx %d\n", pmem_addr, mem_type);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    if (page != card->pmem_page)
+    {
+        unifi_trace(card->ospriv, UDBG6, "setting pmem page=0x%X, addr=0x%lX\n", page, addr);
+
+        /* change page register */
+        r = unifi_write_direct16(card, ChipHelper_HOST_WINDOW2_PAGE(card->helper) * 2, page);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to write PROG MEM PAGE\n");
+            return r;
+        }
+
+        card->pmem_page = page;
+    }
+
+    *paddr = ((CsrInt32)addr * 2) + (pmem_addr & 1);
+
+    return CSR_RESULT_SUCCESS;
+} /* set_pmem_page() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  set_page
+ *
+ *      Sets up the appropriate page register to access the given address.
+ *      Returns the sdio address at which the unifi address can be accessed.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      generic_addr    UniFi internal address to access, in Generic Pointer
+ *                      format, i.e. top byte is space indicator.
+ *      paddr           Location to write page address
+ *                          SDIO address (24-bit) for use in a unifi_read_direct or
+ *                          unifi_write_direct call
+ *
+ *  Returns:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE  the address is invalid
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult set_page(card_t *card, CsrUint32 generic_addr, CsrUint32 *paddr)
+{
+    CsrInt32 space;
+    CsrUint32 addr;
+    CsrResult r = CSR_RESULT_SUCCESS;
+
+    if (!paddr)
+    {
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+    *paddr = 0;
+    space = UNIFI_GP_SPACE(generic_addr);
+    addr = UNIFI_GP_OFFSET(generic_addr);
+    switch (space)
+    {
+        case UNIFI_SH_DMEM:
+            /* Shared Data Memory is accessed via the Shared Data Memory window */
+            r = set_dmem_page(card, addr, paddr);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+            break;
+
+        case UNIFI_EXT_FLASH:
+            if (!ChipHelper_HasFlash(card->helper))
+            {
+                unifi_error(card->ospriv, "Bad address space for chip in generic pointer 0x%08lX (helper=0x%x)\n",
+                            generic_addr, card->helper);
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+            /* External FLASH is accessed via the Program Memory window */
+            r = set_pmem_page(card, addr, CHIP_HELPER_WT_FLASH, paddr);
+            break;
+
+        case UNIFI_EXT_SRAM:
+            if (!ChipHelper_HasExtSram(card->helper))
+            {
+                unifi_error(card->ospriv, "Bad address space for chip in generic pointer 0x%08l (helper=0x%x)\n",
+                            generic_addr, card->helper);
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+            /* External SRAM is accessed via the Program Memory window */
+            r = set_pmem_page(card, addr, CHIP_HELPER_WT_EXT_SRAM, paddr);
+            break;
+
+        case UNIFI_REGISTERS:
+            /* Registers are accessed directly */
+            *paddr = addr;
+            break;
+
+        case UNIFI_PHY_DMEM:
+            r = unifi_set_proc_select(card, UNIFI_PROC_PHY);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+            *paddr = ChipHelper_DATA_MEMORY_RAM_OFFSET(card->helper) * 2 + addr;
+            break;
+
+        case UNIFI_MAC_DMEM:
+            r = unifi_set_proc_select(card, UNIFI_PROC_MAC);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+            *paddr = ChipHelper_DATA_MEMORY_RAM_OFFSET(card->helper) * 2 + addr;
+            break;
+
+        case UNIFI_BT_DMEM:
+            if (!ChipHelper_HasBt(card->helper))
+            {
+                unifi_error(card->ospriv, "Bad address space for chip in generic pointer 0x%08lX (helper=0x%x)\n",
+                            generic_addr, card->helper);
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+            r = unifi_set_proc_select(card, UNIFI_PROC_BT);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+            *paddr = ChipHelper_DATA_MEMORY_RAM_OFFSET(card->helper) * 2 + addr;
+            break;
+
+        case UNIFI_PHY_PMEM:
+            r = unifi_set_proc_select(card, UNIFI_PROC_PHY);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+            r = set_pmem_page(card, addr, CHIP_HELPER_WT_CODE_RAM, paddr);
+            break;
+
+        case UNIFI_MAC_PMEM:
+            r = unifi_set_proc_select(card, UNIFI_PROC_MAC);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+            r = set_pmem_page(card, addr, CHIP_HELPER_WT_CODE_RAM, paddr);
+            break;
+
+        case UNIFI_BT_PMEM:
+            if (!ChipHelper_HasBt(card->helper))
+            {
+                unifi_error(card->ospriv, "Bad address space for chip in generic pointer 0x%08lX (helper=0x%x)\n",
+                            generic_addr, card->helper);
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+            r = unifi_set_proc_select(card, UNIFI_PROC_BT);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+            r = set_pmem_page(card, addr, CHIP_HELPER_WT_CODE_RAM, paddr);
+            break;
+
+        case UNIFI_PHY_ROM:
+            if (!ChipHelper_HasRom(card->helper))
+            {
+                unifi_error(card->ospriv, "Bad address space for chip in generic pointer 0x%08lX (helper=0x%x)\n",
+                            generic_addr, card->helper);
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+            r = unifi_set_proc_select(card, UNIFI_PROC_PHY);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+            r = set_pmem_page(card, addr, CHIP_HELPER_WT_ROM, paddr);
+            break;
+
+        case UNIFI_MAC_ROM:
+            if (!ChipHelper_HasRom(card->helper))
+            {
+                unifi_error(card->ospriv, "Bad address space for chip in generic pointer 0x%08lX (helper=0x%x)\n",
+                            generic_addr, card->helper);
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+            r = unifi_set_proc_select(card, UNIFI_PROC_MAC);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+            r = set_pmem_page(card, addr, CHIP_HELPER_WT_ROM, paddr);
+            break;
+
+        case UNIFI_BT_ROM:
+            if (!ChipHelper_HasRom(card->helper) || !ChipHelper_HasBt(card->helper))
+            {
+                unifi_error(card->ospriv, "Bad address space for chip in generic pointer 0x%08lX (helper=0x%x)\n",
+                            generic_addr, card->helper);
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+            r = unifi_set_proc_select(card, UNIFI_PROC_BT);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                return r;
+            }
+            r = set_pmem_page(card, addr, CHIP_HELPER_WT_ROM, paddr);
+            break;
+
+        default:
+            unifi_error(card->ospriv, "Bad address space %d in generic pointer 0x%08lX (helper=0x%x)\n",
+                        space, generic_addr, card->helper);
+            return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    return r;
+} /* set_page() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_set_proc_select
+ *
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      select          Which XAP core to select
+ *
+ *  Returns:
+ *      0 on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_set_proc_select(card_t *card, enum unifi_dbg_processors_select select)
+{
+    CsrResult r;
+
+    /* Verify the the select value is allowed. */
+    switch (select)
+    {
+        case UNIFI_PROC_MAC:
+        case UNIFI_PROC_PHY:
+        case UNIFI_PROC_BOTH:
+            break;
+
+
+        default:
+            return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    if (card->proc_select != (CsrUint32)select)
+    {
+        r = unifi_write_direct16(card,
+                                 ChipHelper_DBG_HOST_PROC_SELECT(card->helper) * 2,
+                                 (CsrUint8)select);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to write to Proc Select register\n");
+            return r;
+        }
+
+        card->proc_select = (CsrUint32)select;
+    }
+
+    return CSR_RESULT_SUCCESS;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * unifi_read_8_or_16
+ *
+ * Performs a byte read of the given address in shared data memory.
+ * Set up the shared data memory page register as required.
+ *
+ * Arguments:
+ * card Pointer to card structure.
+ * unifi_addr UniFi shared-data-memory address to access.
+ * pdata Pointer to a byte variable for the value read.
+ *
+ * Returns:
+ * CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ * CSR_WIFI_HIP_RESULT_NO_DEVICE card was ejected
+ * CSR_RESULT_FAILURE an SDIO error occurred
+ * CSR_WIFI_HIP_RESULT_INVALID_VALUE a bad generic pointer was specified
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_read_8_or_16(card_t *card, CsrUint32 unifi_addr, CsrUint8 *pdata)
+{
+    CsrUint32 sdio_addr;
+    CsrResult r;
+#ifdef CSR_WIFI_TRANSPORT_CSPI
+    CsrUint16 w;
+#endif
+
+    r = set_page(card, unifi_addr, &sdio_addr);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+    card->cmd_prof.cmd52_r8or16_count++;
+#endif
+#ifdef CSR_WIFI_TRANSPORT_CSPI
+    r = retrying_read16(card, card->function, sdio_addr, &w);
+    *pdata = (CsrUint8)(w & 0xFF);
+    return r;
+#else
+    return retrying_read8(card, card->function, sdio_addr, pdata);
+#endif
+} /* unifi_read_8_or_16() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * unifi_write_8_or_16
+ *
+ * Performs a byte write of the given address in shared data memory.
+ * Set up the shared data memory page register as required.
+ *
+ * Arguments:
+ * card Pointer to card context struct.
+ * unifi_addr UniFi shared-data-memory address to access.
+ * data Value to write.
+ *
+ * Returns:
+ * CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ * CSR_WIFI_HIP_RESULT_NO_DEVICE card was ejected
+ * CSR_RESULT_FAILURE an SDIO error occurred
+ * CSR_WIFI_HIP_RESULT_INVALID_VALUE a bad generic pointer was specified
+ *
+ * Notes:
+ * Beware using unifi_write8() because byte writes are not safe on UniFi.
+ * Writes to odd bytes are cached, writes to even bytes perform a 16-bit
+ * write with the previously cached odd byte.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_write_8_or_16(card_t *card, CsrUint32 unifi_addr, CsrUint8 data)
+{
+    CsrUint32 sdio_addr;
+    CsrResult r;
+#ifdef CSR_WIFI_TRANSPORT_CSPI
+    CsrUint16 w;
+#endif
+
+    r = set_page(card, unifi_addr, &sdio_addr);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+    if (sdio_addr & 1)
+    {
+        unifi_warning(card->ospriv,
+                      "Warning: Byte write to an odd address (0x%lX) is dangerous\n",
+                      sdio_addr);
+    }
+
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+    card->cmd_prof.cmd52_w8or16_count++;
+#endif
+#ifdef CSR_WIFI_TRANSPORT_CSPI
+    w = data;
+    return retrying_write16(card, card->function, sdio_addr, w);
+#else
+    return retrying_write8(card, card->function, sdio_addr, data);
+#endif
+} /* unifi_write_8_or_16() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_card_read16
+ *
+ *      Performs a 16-bit read of the given address in shared data memory.
+ *      Set up the shared data memory page register as required.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      unifi_addr      UniFi shared-data-memory address to access.
+ *      pdata           Pointer to a 16-bit int variable for the value read.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE  a bad generic pointer was specified
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_card_read16(card_t *card, CsrUint32 unifi_addr, CsrUint16 *pdata)
+{
+    CsrUint32 sdio_addr;
+    CsrResult r;
+
+    r = set_page(card, unifi_addr, &sdio_addr);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+    card->cmd_prof.cmd52_r16_count++;
+#endif
+    return unifi_read_direct16(card, sdio_addr, pdata);
+} /* unifi_card_read16() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_card_write16
+ *
+ *      Performs a 16-bit write of the given address in shared data memory.
+ *      Set up the shared data memory page register as required.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      unifi_addr      UniFi shared-data-memory address to access.
+ *      pdata           Pointer to a byte variable for the value write.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE  a bad generic pointer was specified
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_card_write16(card_t *card, CsrUint32 unifi_addr, CsrUint16 data)
+{
+    CsrUint32 sdio_addr;
+    CsrResult r;
+
+    r = set_page(card, unifi_addr, &sdio_addr);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+    card->cmd_prof.cmd52_w16_count++;
+#endif
+    return unifi_write_direct16(card, sdio_addr, data);
+} /* unifi_card_write16() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_read32
+ *
+ *      Performs a 32-bit read of the given address in shared data memory.
+ *      Set up the shared data memory page register as required.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      unifi_addr      UniFi shared-data-memory address to access.
+ *      pdata           Pointer to a int variable for the value read.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE  a bad generic pointer was specified
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_read32(card_t *card, CsrUint32 unifi_addr, CsrUint32 *pdata)
+{
+    CsrUint32 sdio_addr;
+    CsrResult r;
+
+    r = set_page(card, unifi_addr, &sdio_addr);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+    card->cmd_prof.cmd52_r32_count++;
+#endif
+    return unifi_read_direct32(card, sdio_addr, pdata);
+} /* unifi_read32() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_card_readn
+ *  unifi_readnz
+ *
+ *      Read multiple 8-bit values from the UniFi SDIO interface.
+ *      This function interprets the address as a GenericPointer as
+ *      defined in the UniFi Host Interface Protocol Specification.
+ *      The readnz version of this function will stop when it reads a
+ *      zero octet.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      unifi_addr      UniFi shared-data-memory address to access.
+ *      pdata           Pointer to which to write data.
+ *      len             Number of bytes to read
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE  a bad generic pointer was specified
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_readn_match(card_t *card, CsrUint32 unifi_addr, void *pdata, CsrUint16 len, CsrInt8 match)
+{
+    CsrUint32 sdio_addr;
+    CsrResult r;
+    CsrUint32 num;
+
+    r = set_page(card, unifi_addr, &sdio_addr);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+    r = unifi_read_directn_match(card, sdio_addr, pdata, len, match, &num);
+    return r;
+} /* unifi_readn_match() */
+
+
+CsrResult unifi_card_readn(card_t *card, CsrUint32 unifi_addr, void *pdata, CsrUint16 len)
+{
+    return unifi_readn_match(card, unifi_addr, pdata, len, -1);
+} /* unifi_card_readn() */
+
+
+CsrResult unifi_readnz(card_t *card, CsrUint32 unifi_addr, void *pdata, CsrUint16 len)
+{
+    return unifi_readn_match(card, unifi_addr, pdata, len, 0);
+} /* unifi_readnz() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_read_shared_count
+ *
+ *      Read signal count locations, checking for an SDIO error.  The
+ *      signal count locations only contain a valid number if the
+ *      highest bit isn't set.
+ *
+ *  Arguments:
+ *      card            Pointer to card context structure.
+ *      addr            Shared-memory address to read.
+ *
+ *  Returns:
+ *      Value read from memory (0-127) or -1 on error
+ * ---------------------------------------------------------------------------
+ */
+CsrInt32 unifi_read_shared_count(card_t *card, CsrUint32 addr)
+{
+    CsrUint8 b;
+    /* I've increased this count, because I have seen cases where
+     * there were three reads in a row with the top bit set.  I'm not
+     * sure why this might have happened, but I can't see a problem
+     * with increasing this limit.  It's better to take a while to
+     * recover than to fail. */
+#define SHARED_READ_RETRY_LIMIT 10
+    CsrInt32 i;
+
+    /*
+     * Get the to-host-signals-written count.
+     * The top-bit will be set if the firmware was in the process of
+     * changing the value, in which case we read again.
+     */
+    /* Limit the number of repeats so we don't freeze */
+    for (i = 0; i < SHARED_READ_RETRY_LIMIT; i++)
+    {
+        CsrResult r;
+        r = unifi_read_8_or_16(card, addr, &b);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            return -1;
+        }
+        if (!(b & 0x80))
+        {
+            /* There is a chance that the MSB may have contained invalid data
+             * (overflow) at the time it was read. Therefore mask off the MSB.
+             * This avoids a race between driver read and firmware write of the
+             * word, the value we need is in the lower 8 bits anway.
+             */
+            return (CsrInt32)(b & 0xff);
+        }
+    }
+
+    return -1;                  /* this function has changed in WMM mods */
+} /* unifi_read_shared_count() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_writen
+ *
+ *      Write multiple 8-bit values to the UniFi SDIO interface using CMD52
+ *      This function interprets the address as a GenericPointer as
+ *      defined in the UniFi Host Interface Protocol Specification.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      unifi_addr      UniFi shared-data-memory address to access.
+ *      pdata           Pointer to which to write data.
+ *      len             Number of bytes to write
+ *
+ *  Returns:
+ *      0 on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE    an odd length or length too big.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_writen(card_t *card, CsrUint32 unifi_addr, void *pdata, CsrUint16 len)
+{
+    CsrUint32 sdio_addr;
+    CsrResult r;
+
+    r = set_page(card, unifi_addr, &sdio_addr);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+    return unifi_write_directn(card, sdio_addr, pdata, len);
+} /* unifi_writen() */
+
+
+static CsrResult csr_sdio_block_rw(card_t *card, CsrInt16 funcnum,
+                                   CsrUint32 addr, CsrUint8 *pdata,
+                                   CsrUint16 count, CsrInt16 dir_is_write)
+{
+    CsrResult csrResult;
+
+    if (dir_is_write == UNIFI_SDIO_READ)
+    {
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+        unifi_debug_log_to_buf("r@%02X#%X=", addr, count);
+#endif
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+        unifi_debug_log_to_buf("R");
+#endif
+        csrResult = CsrSdioRead(card->sdio_if, addr, pdata, count);
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+        unifi_debug_log_to_buf("<");
+#endif
+    }
+    else
+    {
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+        unifi_debug_log_to_buf("w@%02X#%X=", addr, count);
+        unifi_debug_hex_to_buf(pdata, count > CSR_WIFI_HIP_SDIO_TRACE_DATA_LENGTH?CSR_WIFI_HIP_SDIO_TRACE_DATA_LENGTH : count);
+#endif
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+        unifi_debug_log_to_buf("W");
+#endif
+        csrResult = CsrSdioWrite(card->sdio_if, addr, pdata, count);
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+        unifi_debug_log_to_buf(">");
+#endif
+    }
+#ifdef CSR_WIFI_HIP_DATA_PLANE_PROFILE
+    card->cmd_prof.cmd53_count++;
+#endif
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE)
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        unifi_debug_log_to_buf("error=%X", csrResult);
+    }
+    else if (dir_is_write == UNIFI_SDIO_READ)
+    {
+        unifi_debug_hex_to_buf(pdata, count > CSR_WIFI_HIP_SDIO_TRACE_DATA_LENGTH?CSR_WIFI_HIP_SDIO_TRACE_DATA_LENGTH : count);
+    }
+    unifi_debug_string_to_buf("\n");
+#endif
+    return csrResult;  /* CSR SDIO (not HIP) error code */
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_bulk_rw
+ *
+ *      Transfer bulk data to or from the UniFi SDIO interface.
+ *      This function is used to read or write signals and bulk data.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      handle          Value to put in the Register Address field of the CMD53 req.
+ *      data            Pointer to data to write.
+ *      direction       One of UNIFI_SDIO_READ or UNIFI_SDIO_WRITE
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *
+ *  Notes:
+ *      This function uses SDIO CMD53, which is the block transfer mode.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_bulk_rw(card_t *card, CsrUint32 handle, void *pdata,
+                        CsrUint32 len, CsrInt16 direction)
+{
+#define CMD53_RETRIES 3
+    /*
+     * Ideally instead of sleeping, we want to busy wait.
+     * Currently there is no framework API to do this. When it becomes available,
+     * we can use it to busy wait using usecs
+     */
+#define REWIND_RETRIES          15    /* when REWIND_DELAY==1msec, or 250 when REWIND_DELAY==50usecs */
+#define REWIND_POLLING_RETRIES  5
+#define REWIND_DELAY            1     /* msec or 50usecs */
+    CsrResult csrResult;              /* SDIO error code */
+    CsrResult r = CSR_RESULT_SUCCESS; /* HIP error code */
+    CsrInt16 retries = CMD53_RETRIES;
+    CsrInt16 stat_retries;
+    CsrUint8 stat;
+    CsrInt16 dump_read;
+#ifdef UNIFI_DEBUG
+    CsrUint8 *pdata_lsb = ((CsrUint8 *)&pdata) + card->lsb;
+#endif
+#ifdef CSR_WIFI_MAKE_FAKE_CMD53_ERRORS
+    static CsrInt16 fake_error;
+#endif
+
+    dump_read = 0;
+#ifdef UNIFI_DEBUG
+    if (*pdata_lsb & 1)
+    {
+        unifi_notice(card->ospriv, "CD53 request on a unaligned buffer (addr: 0x%X) dir %s-Host\n",
+                     pdata, (direction == UNIFI_SDIO_READ)?"To" : "From");
+        if (direction == UNIFI_SDIO_WRITE)
+        {
+            dump(pdata, (CsrUint16)len);
+        }
+        else
+        {
+            dump_read = 1;
+        }
+    }
+#endif
+
+    /* Defensive checks */
+    if (!pdata)
+    {
+        unifi_error(card->ospriv, "Null pdata for unifi_bulk_rw() len: %d\n", len);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+    if ((len & 1) || (len > 0xffff))
+    {
+        unifi_error(card->ospriv, "Impossible CMD53 length requested: %d\n", len);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    while (1)
+    {
+        csrResult = csr_sdio_block_rw(card, card->function, handle,
+                                      (CsrUint8 *)pdata, (CsrUint16)len,
+                                      direction);
+        if (csrResult == CSR_SDIO_RESULT_NO_DEVICE)
+        {
+            return CSR_WIFI_HIP_RESULT_NO_DEVICE;
+        }
+#ifdef CSR_WIFI_MAKE_FAKE_CMD53_ERRORS
+        if (++fake_error > 100)
+        {
+            fake_error = 90;
+            unifi_warning(card->ospriv, "Faking a CMD53 error,\n");
+            if (csrResult == CSR_RESULT_SUCCESS)
+            {
+                csrResult = CSR_RESULT_FAILURE;
+            }
+        }
+#endif
+        if (csrResult == CSR_RESULT_SUCCESS)
+        {
+            if (dump_read)
+            {
+                dump(pdata, (CsrUint16)len);
+            }
+            break;
+        }
+
+        /*
+         * At this point the SDIO driver should have written the I/O Abort
+         * register to notify UniFi that the command has failed.
+         * UniFi-1 and UniFi-2 (not UF6xxx) use the same register to store the
+         * Deep Sleep State. This means we have to restore the Deep Sleep
+         * State (AWAKE in any case since we can not perform a CD53 in any other
+         * state) by rewriting the I/O Abort register to its previous value.
+         */
+        if (card->chip_id <= SDIO_CARD_ID_UNIFI_2)
+        {
+            (void)unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE);
+        }
+
+        /* If csr_sdio_block_rw() failed in a non-retryable way, or retries exhausted
+         * then stop retrying
+         */
+        if (!retryable_sdio_error(csrResult))
+        {
+            unifi_error(card->ospriv, "Fatal error in a CMD53 transfer\n");
+            break;
+        }
+
+        /*
+         * These happen from time to time, try again
+         */
+        if (--retries == 0)
+        {
+            break;
+        }
+
+        unifi_trace(card->ospriv, UDBG4,
+                    "Error in a CMD53 transfer, retrying (h:%d,l:%u)...\n",
+                    (CsrInt16)handle & 0xff, len);
+
+        /* The transfer failed, rewind and try again */
+        r = unifi_write_8_or_16(card, card->sdio_ctrl_addr + 8,
+                                (CsrUint8)(handle & 0xff));
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            /*
+             * If we can't even do CMD52 (register read/write) then
+             * stop here.
+             */
+            unifi_error(card->ospriv, "Failed to write REWIND cmd\n");
+            return r;
+        }
+
+        /* Signal the UniFi to look for the rewind request. */
+        r = CardGenInt(card);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            return r;
+        }
+
+        /* Wait for UniFi to acknowledge the rewind */
+        stat_retries = REWIND_RETRIES;
+        while (1)
+        {
+            r = unifi_read_8_or_16(card, card->sdio_ctrl_addr + 8, &stat);
+            if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+            {
+                return r;
+            }
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                unifi_error(card->ospriv, "Failed to read REWIND status\n");
+                return CSR_RESULT_FAILURE;
+            }
+
+            if (stat == 0)
+            {
+                break;
+            }
+            if (--stat_retries == 0)
+            {
+                unifi_error(card->ospriv, "Timeout waiting for REWIND ready\n");
+                return CSR_RESULT_FAILURE;
+            }
+
+            /* Poll for the ack a few times */
+            if (stat_retries < REWIND_RETRIES - REWIND_POLLING_RETRIES)
+            {
+                CsrThreadSleep(REWIND_DELAY);
+            }
+        }
+    }
+
+    /* The call to csr_sdio_block_rw() still failed after retrying */
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Block %s failed after %d retries\n",
+                    (direction == UNIFI_SDIO_READ)?"read" : "write",
+                    CMD53_RETRIES - retries);
+        /* Report any SDIO error as a general i/o error */
+        return CSR_RESULT_FAILURE;
+    }
+
+    /* Collect some stats */
+    if (direction == UNIFI_SDIO_READ)
+    {
+        card->sdio_bytes_read += len;
+    }
+    else
+    {
+        card->sdio_bytes_written += len;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_bulk_rw() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_bulk_rw_noretry
+ *
+ *      Transfer bulk data to or from the UniFi SDIO interface.
+ *      This function is used to read or write signals and bulk data.
+ *
+ *  Arguments:
+ *      card            Pointer to card structure.
+ *      handle          Value to put in the Register Address field of
+ *                      the CMD53 req.
+ *      data            Pointer to data to write.
+ *      direction       One of UNIFI_SDIO_READ or UNIFI_SDIO_WRITE
+ *
+ *  Returns:
+ *      0 on success, non-zero error code on error:
+ *      CSR_WIFI_HIP_RESULT_NO_DEVICE  card was ejected
+ *      CSR_RESULT_FAILURE     an SDIO error occurred
+ *
+ *  Notes:
+ *      This function uses SDIO CMD53, which is the block transfer mode.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_bulk_rw_noretry(card_t *card, CsrUint32 handle, void *pdata,
+                                CsrUint32 len, CsrInt16 direction)
+{
+    CsrResult csrResult;
+
+    csrResult = csr_sdio_block_rw(card, card->function, handle,
+                                  (CsrUint8 *)pdata, (CsrUint16)len, direction);
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Block %s failed\n",
+                    (direction == UNIFI_SDIO_READ)?"read" : "write");
+        return csrResult;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_bulk_rw_noretry() */
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_chiphelper.c b/drivers/staging/csr/csr_wifi_hip_chiphelper.c
new file mode 100644
index 0000000..0e2477f
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_chiphelper.c
@@ -0,0 +1,793 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+
+#include "csr_wifi_hip_chiphelper_private.h"
+
+#ifndef nelem
+#define nelem(a) (sizeof(a) / sizeof(a[0]))
+#endif
+
+#define counted(foo) { nelem(foo), foo }
+#define null_counted()  { 0, NULL }
+
+/* The init values are a set of register writes that we must
+   perform when we first connect to the chip to get it working.
+   They swicth on the correct clocks and possibly set the host
+   interface as a wkaeup source.  They should not be used if
+   proper HIP opperation is required, but are useful before we
+   do a code download. */
+static const struct chip_helper_init_values init_vals_v1[] = {
+    { 0xFDBB, 0xFFFF },
+    { 0xFDB6, 0x03FF },
+    { 0xFDB1, 0x01E3 },
+    { 0xFDB3, 0x0FFF },
+    { 0xFEE3, 0x08F0 },
+    { 0xFEE7, 0x3C3F },
+    { 0xFEE6, 0x0050 },
+    { 0xFDBA, 0x0000 }
+};
+
+static const struct chip_helper_init_values init_vals_v2[] = {
+    { 0xFDB6, 0x0FFF },
+    { 0xF023, 0x3F3F },
+    { 0xFDB1, 0x01E3 },
+    { 0xFDB3, 0x0FFF },
+    { 0xF003, 0x08F0 },
+    { 0xF007, 0x3C3F },
+    { 0xF006, 0x0050 }
+};
+
+
+static const struct chip_helper_init_values init_vals_v22_v23[] = {
+    { 0xF81C, 0x00FF },
+    /*{ 0x????, 0x???? }, */
+    { 0xF80C, 0x1FFF },
+    { 0xFA25, 0x001F },
+    { 0xF804, 0x00FF },
+    { 0xF802, 0x0FFF },
+    /*{ 0x????, 0x???? },
+      { 0x????, 0x???? },
+      { 0x????, 0x???? }*/
+};
+
+static const CsrUint16 reset_program_a_v1_or_v2[] = {
+    0x0000
+};
+static const CsrUint16 reset_program_b_v1_or_v2[] = {
+    0x0010, 0xFE00, 0xA021, 0xFF00, 0x8111, 0x0009, 0x0CA4, 0x0114,
+    0x0280, 0x04F8, 0xFE00, 0x6F25, 0x06E0, 0x0010, 0xFC00, 0x0121,
+    0xFC00, 0x0225, 0xFE00, 0x7125, 0xFE00, 0x6D11, 0x03F0, 0xFE00,
+    0x6E25, 0x0008, 0x00E0
+};
+
+static const struct chip_helper_reset_values reset_program_v1_or_v2[] =
+{
+    {
+        MAKE_GP(REGISTERS, 0x000C),
+        nelem(reset_program_a_v1_or_v2),
+        reset_program_a_v1_or_v2
+    },
+    {
+        MAKE_GP(MAC_PMEM, 0x000000),
+        nelem(reset_program_b_v1_or_v2),
+        reset_program_b_v1_or_v2
+    }
+};
+
+static const struct chip_map_address_t unifi_map_address_v1_v2[] =
+{
+    { 0xFE9F, 0xFE7B },     /* PM1_BANK_SELECT */
+    { 0xFE9E, 0xFE78 },     /* PM2_BANK_SELECT */
+    { 0xFE9D, 0xFE7E },     /* SHARED_DMEM_PAGE */
+    { 0xFE91, 0xFE90 },     /* PROC_SELECT */
+    { 0xFE8D, 0xFE8C },     /* STOP_STATUS */
+};
+
+static const struct chip_map_address_t unifi_map_address_v22_v23[] =
+{
+    { 0xF8F9, 0xF8AC },     /* GW1_CONFIG */
+    { 0xF8FA, 0xF8AD },     /* GW2_CONFIG */
+    { 0xF8FB, 0xF8AE },     /* GW3_CONFIG */
+    { 0xF830, 0xF81E },     /* PROC_SELECT */
+    { 0xF831, 0xF81F },     /* STOP_STATUS */
+    { 0xF8FC, 0xF8AF },     /* IO_LOG_ADDRESS */
+};
+
+static const struct chip_device_regs_t unifi_device_regs_null =
+{
+    0xFE81,                     /* GBL_CHIP_VERSION */
+    0x0000,                     /* GBL_MISC_ENABLES */
+    0x0000,                     /* DBG_EMU_CMD */
+    {
+        0x0000,                 /* HOST.DBG_PROC_SELECT */
+        0x0000,                 /* HOST.DBG_STOP_STATUS */
+        0x0000,                 /* HOST.WINDOW1_PAGE */
+        0x0000,                 /* HOST.WINDOW2_PAGE */
+        0x0000,                 /* HOST.WINDOW3_PAGE */
+        0x0000                  /* HOST.IO_LOG_ADDR */
+    },
+    {
+        0x0000,                 /* SPI.DBG_PROC_SELECT */
+        0x0000,                 /* SPI.DBG_STOP_STATUS */
+        0x0000,                 /* SPI.WINDOW1_PAGE */
+        0x0000,                 /* SPI.WINDOW2_PAGE */
+        0x0000,                 /* SPI.WINDOW3_PAGE */
+        0x0000                  /* SPI.IO_LOG_ADDR */
+    },
+    0x0000,                     /* DBG_RESET */
+    0x0000,                     /* > DBG_RESET_VALUE */
+    0x0000,                     /* DBG_RESET_WARN */
+    0x0000,                     /* DBG_RESET_WARN_VALUE */
+    0x0000,                     /* DBG_RESET_RESULT */
+    0xFFE9,                     /* XAP_PCH */
+    0xFFEA,                     /* XAP_PCL */
+    0x0000,                     /* PROC_PC_SNOOP */
+    0x0000,                     /* WATCHDOG_DISABLE */
+    0x0000,                     /* MAILBOX0 */
+    0x0000,                     /* MAILBOX1 */
+    0x0000,                     /* MAILBOX2 */
+    0x0000,                     /* MAILBOX3 */
+    0x0000,                     /* SDIO_HOST_INT */
+    0x0000,                     /* SHARED_IO_INTERRUPT */
+    0x0000,                     /* SDIO HIP HANDSHAKE */
+    0x0000                      /* COEX_STATUS */
+};
+
+/* UF105x */
+static const struct chip_device_regs_t unifi_device_regs_v1 =
+{
+    0xFE81,                     /* GBL_CHIP_VERSION */
+    0xFE87,                     /* GBL_MISC_ENABLES */
+    0xFE9C,                     /* DBG_EMU_CMD */
+    {
+        0xFE90,                 /* HOST.DBG_PROC_SELECT */
+        0xFE8C,                 /* HOST.DBG_STOP_STATUS */
+        0xFE7B,                 /* HOST.WINDOW1_PAGE */
+        0xFE78,                 /* HOST.WINDOW2_PAGE */
+        0xFE7E,                 /* HOST.WINDOW3_PAGE */
+        0x0000                  /* HOST.IO_LOG_ADDR */
+    },
+    {
+        0xFE91,                 /* SPI.DBG_PROC_SELECT */
+        0xFE8D,                 /* SPI.DBG_STOP_STATUS */
+        0xFE9F,                 /* SPI.WINDOW1_PAGE */
+        0xFE9E,                 /* SPI.WINDOW2_PAGE */
+        0xFE9D,                 /* SPI.WINDOW3_PAGE */
+        0x0000                  /* SPI.IO_LOG_ADDR */
+    },
+    0xFE92,                     /* DBG_RESET */
+    0x0001,                     /* > DBG_RESET_VALUE */
+    0xFDA0,                     /* DBG_RESET_WARN (HOST_SELECT) */
+    0x0000,                     /* DBG_RESET_WARN_VALUE */
+    0xFE92,                     /* DBG_RESET_RESULT */
+    0xFFE9,                     /* XAP_PCH */
+    0xFFEA,                     /* XAP_PCL */
+    0x0051,                     /* PROC_PC_SNOOP */
+    0xFE70,                     /* WATCHDOG_DISABLE */
+    0xFE6B,                     /* MAILBOX0 */
+    0xFE6A,                     /* MAILBOX1 */
+    0xFE69,                     /* MAILBOX2 */
+    0xFE68,                     /* MAILBOX3 */
+    0xFE67,                     /* SDIO_HOST_INT */
+    0xFE65,                     /* SHARED_IO_INTERRUPT */
+    0xFDE9,                     /* SDIO HIP HANDSHAKE */
+    0x0000                      /* COEX_STATUS */
+};
+
+/* UF2... */
+static const struct chip_device_regs_t unifi_device_regs_v2 =
+{
+    0xFE81,                     /* GBL_CHIP_VERSION */
+    0xFE87,                     /* GBL_MISC_ENABLES */
+    0xFE9C,                     /* DBG_EMU_CMD */
+    {
+        0xFE90,                 /* HOST.DBG_PROC_SELECT */
+        0xFE8C,                 /* HOST.DBG_STOP_STATUS */
+        0xFE7B,                 /* HOST.WINDOW1_PAGE */
+        0xFE78,                 /* HOST.WINDOW2_PAGE */
+        0xFE7E,                 /* HOST.WINDOW3_PAGE */
+        0x0000                  /* HOST.IO_LOG_ADDR */
+    },
+    {
+        0xFE91,                 /* SPI.DBG_PROC_SELECT */
+        0xFE8D,                 /* SPI.DBG_STOP_STATUS */
+        0xFE9F,                 /* SPI.WINDOW1_PAGE */
+        0xFE9E,                 /* SPI.WINDOW2_PAGE */
+        0xFE9D,                 /* SPI.WINDOW3_PAGE */
+        0x0000                  /* SPI.IO_LOG_ADDR */
+    },
+    0xFE92,                     /* DBG_RESET */
+    0x0000,                     /* > DBG_RESET_VALUE */
+    0xFDE9,                     /* DBG_RESET_WARN (TEST_FLASH_DATA - SHARED_MAILBOX2B) */
+    0xFFFF,                     /* DBG_RESET_WARN_VALUE */
+    0xFDE9,                     /* DBG_RESET_RESULT (TEST_FLASH_DATA) */
+    0xFFE9,                     /* XAP_PCH */
+    0xFFEA,                     /* XAP_PCL */
+    0x0051,                     /* PROC_PC_SNOOP */
+    0xFE70,                     /* WATCHDOG_DISABLE */
+    0xFE6B,                     /* MAILBOX0 */
+    0xFE6A,                     /* MAILBOX1 */
+    0xFE69,                     /* MAILBOX2 */
+    0xFE68,                     /* MAILBOX3 */
+    0xFE67,                     /* SDIO_HOST_INT */
+    0xFE65,                     /* SHARED_IO_INTERRUPT */
+    0xFE69,                     /* SDIO HIP HANDSHAKE */
+    0x0000                      /* COEX_STATUS */
+};
+
+/* UF60xx */
+static const struct chip_device_regs_t unifi_device_regs_v22_v23 =
+{
+    0xFE81,                     /* GBL_CHIP_VERSION */
+    0xF84F,                     /* GBL_MISC_ENABLES */
+    0xF81D,                     /* DBG_EMU_CMD */
+    {
+        0xF81E,                 /* HOST.DBG_PROC_SELECT */
+        0xF81F,                 /* HOST.DBG_STOP_STATUS */
+        0xF8AC,                 /* HOST.WINDOW1_PAGE */
+        0xF8AD,                 /* HOST.WINDOW2_PAGE */
+        0xF8AE,                 /* HOST.WINDOW3_PAGE */
+        0xF8AF                  /* HOST.IO_LOG_ADDR */
+    },
+    {
+        0xF830,                 /* SPI.DBG_PROC_SELECT */
+        0xF831,                 /* SPI.DBG_STOP_STATUS */
+        0xF8F9,                 /* SPI.WINDOW1_PAGE */
+        0xF8FA,                 /* SPI.WINDOW2_PAGE */
+        0xF8FB,                 /* SPI.WINDOW3_PAGE */
+        0xF8FC                  /* SPI.IO_LOG_ADDR */
+    },
+    0xF82F,                     /* DBG_RESET */
+    0x0001,                     /* > DBG_RESET_VALUE */
+    0x0000,                     /* DBG_RESET_WARN */
+    0x0000,                     /* DBG_RESET_WARN_VALUE */
+    0xF82F,                     /* DBG_RESET_RESULT */
+    0xFFE9,                     /* XAP_PCH */
+    0xFFEA,                     /* XAP_PCL */
+    0x001B,                     /* PROC_PC_SNOOP */
+    0x0055,                     /* WATCHDOG_DISABLE */
+    0xF84B,                     /* MAILBOX0 */
+    0xF84C,                     /* MAILBOX1 */
+    0xF84D,                     /* MAILBOX2 */
+    0xF84E,                     /* MAILBOX3 */
+    0xF92F,                     /* SDIO_HOST_INT */
+    0xF92B,                     /* SDIO_FROMHOST_SCRTACH0 / SHARED_IO_INTERRUPT */
+    0xF84D,                     /* SDIO HIP HANDSHAKE (MAILBOX2) */
+    0xF9FB                      /* COEX_STATUS */
+};
+
+/* Program memory window on UF105x. */
+static const struct window_shift_info_t prog_window_array_unifi_v1_v2[CHIP_HELPER_WT_COUNT] =
+{
+    { TRUE, 11, 0x0200 }, /* CODE RAM */
+    { TRUE, 11, 0x0000 }, /* FLASH */
+    { TRUE, 11, 0x0400 }, /* External SRAM */
+    { FALSE, 0, 0 },      /* ROM */
+    { FALSE, 0, 0 }       /* SHARED */
+};
+
+/* Shared memory window on UF105x. */
+static const struct window_shift_info_t shared_window_array_unifi_v1_v2[CHIP_HELPER_WT_COUNT] =
+{
+    { FALSE, 0, 0 },      /* CODE RAM */
+    { FALSE, 0, 0 },      /* FLASH */
+    { FALSE, 0, 0 },      /* External SRAM */
+    { FALSE, 0, 0 },      /* ROM */
+    { TRUE, 11, 0x0000 }  /* SHARED */
+};
+
+/* One of the Generic Windows on UF60xx and later. */
+static const struct window_shift_info_t generic_window_array_unifi_v22_v23[CHIP_HELPER_WT_COUNT] =
+{
+    { TRUE, 11, 0x3800 }, /* CODE RAM */
+    { FALSE, 0, 0 },      /* FLASH */
+    { FALSE, 0, 0 },      /* External SRAM */
+    { TRUE, 11, 0x2000 }, /* ROM */
+    { TRUE, 11, 0x0000 }  /* SHARED */
+};
+
+/* The three windows on UF105x. */
+static const struct window_info_t prog1_window_unifi_v1_v2  = { 0x0000, 0x2000, 0x0080, prog_window_array_unifi_v1_v2 };
+static const struct window_info_t prog2_window_unifi_v1_v2  = { 0x2000, 0x2000, 0x0000, prog_window_array_unifi_v1_v2 };
+static const struct window_info_t shared_window_unifi_v1_v2 = { 0x4000, 0x2000, 0x0000, shared_window_array_unifi_v1_v2 };
+
+/* The three windows on UF60xx and later. */
+static const struct window_info_t generic1_window_unifi_v22_v23 = { 0x0000, 0x2000, 0x0080, generic_window_array_unifi_v22_v23 };
+static const struct window_info_t generic2_window_unifi_v22_v23 = { 0x2000, 0x2000, 0x0000, generic_window_array_unifi_v22_v23 };
+static const struct window_info_t generic3_window_unifi_v22_v23 = { 0x4000, 0x2000, 0x0000, generic_window_array_unifi_v22_v23 };
+
+static const struct chip_device_desc_t chip_device_desc_null =
+{
+    { FALSE, 0x0000, 0x0000, 0x00 },
+    "",
+    "",
+    null_counted(),                         /* init */
+    null_counted(),                         /* reset_prog */
+    &unifi_device_regs_null,                /* regs */
+    {
+        FALSE,                              /* has_flash */
+        FALSE,                              /* has_ext_sram */
+        FALSE,                              /* has_rom */
+        FALSE,                              /* has_bt */
+        FALSE,                              /* has_wlan */
+    },
+    null_counted(),
+    /* prog_offset */
+    {
+        0x00000000,
+        0x00000000,
+        0x00000000,
+        0x00000000
+    },
+    /* data_offset */
+    {
+        0x0000                              /* ram */
+    },
+    /* windows */
+    {
+        NULL,
+        NULL,
+        NULL
+    }
+};
+
+static const struct chip_device_desc_t unifi_device_desc_v1 =
+{
+    { FALSE, 0xf0ff, 0x1001, 0x01 },        /* UF105x R01 */
+    "UF105x",
+    "UniFi-1",
+    counted(init_vals_v1),                  /* init */
+    counted(reset_program_v1_or_v2),        /* reset_prog */
+    &unifi_device_regs_v1,                  /* regs */
+    {
+        TRUE,                               /* has_flash    */
+        TRUE,                               /* has_ext_sram */
+        FALSE,                              /* has_rom      */
+        FALSE,                              /* has_bt       */
+        TRUE,                               /* has_wlan */
+    },
+    counted(unifi_map_address_v1_v2),       /* map */
+    /* prog_offset */
+    {
+        0x00100000,                         /* ram */
+        0x00000000,                         /* rom (invalid) */
+        0x00000000,                         /* flash */
+        0x00200000,                         /* ext_ram */
+    },
+    /* data_offset */
+    {
+        0x8000                              /* ram */
+    },
+    /* windows */
+    {
+        &prog1_window_unifi_v1_v2,
+        &prog2_window_unifi_v1_v2,
+        &shared_window_unifi_v1_v2
+    }
+};
+
+static const struct chip_device_desc_t unifi_device_desc_v2 =
+{
+    { FALSE, 0xf0ff, 0x2001, 0x02 },        /* UF2... R02 */
+    "UF2...",
+    "UniFi-2",
+    counted(init_vals_v2),                  /* init */
+    counted(reset_program_v1_or_v2),        /* reset_prog */
+    &unifi_device_regs_v2,                  /* regs */
+    {
+        TRUE,                               /* has_flash    */
+        TRUE,                               /* has_ext_sram */
+        FALSE,                              /* has_rom      */
+        FALSE,                              /* has_bt      */
+        TRUE,                               /* has_wlan */
+    },
+    counted(unifi_map_address_v1_v2),       /* map */
+    /* prog_offset */
+    {
+        0x00100000,                         /* ram */
+        0x00000000,                         /* rom (invalid) */
+        0x00000000,                         /* flash */
+        0x00200000,                         /* ext_ram */
+    },
+    /* data_offset */
+    {
+        0x8000                              /* ram */
+    },
+    /* windows */
+    {
+        &prog1_window_unifi_v1_v2,
+        &prog2_window_unifi_v1_v2,
+        &shared_window_unifi_v1_v2
+    }
+};
+
+static const struct chip_device_desc_t unifi_device_desc_v3 =
+{
+    { FALSE, 0xf0ff, 0x3001, 0x02 },        /* UF2... R03 */
+    "UF2...",
+    "UniFi-3",
+    counted(init_vals_v2),                  /* init */
+    counted(reset_program_v1_or_v2),        /* reset_prog */
+    &unifi_device_regs_v2,                  /* regs */
+    {
+        TRUE,                               /* has_flash    */
+        TRUE,                               /* has_ext_sram */
+        FALSE,                              /* has_rom      */
+        FALSE,                              /* has_bt      */
+        TRUE,                               /* has_wlan */
+    },
+    counted(unifi_map_address_v1_v2),       /* map */
+    /* prog_offset */
+    {
+        0x00100000,                         /* ram */
+        0x00000000,                         /* rom (invalid) */
+        0x00000000,                         /* flash */
+        0x00200000,                         /* ext_ram */
+    },
+    /* data_offset */
+    {
+        0x8000                              /* ram */
+    },
+    /* windows */
+    {
+        &prog1_window_unifi_v1_v2,
+        &prog2_window_unifi_v1_v2,
+        &shared_window_unifi_v1_v2
+    }
+};
+
+static const struct chip_device_desc_t unifi_device_desc_v22 =
+{
+    { FALSE, 0x00ff, 0x0022, 0x07 },        /* UF60xx */
+    "UF60xx",
+    "UniFi-4",
+    counted(init_vals_v22_v23),             /* init */
+    null_counted(),                         /* reset_prog */
+    &unifi_device_regs_v22_v23,             /* regs */
+    {
+        FALSE,                              /* has_flash    */
+        FALSE,                              /* has_ext_sram */
+        TRUE,                               /* has_rom      */
+        FALSE,                              /* has_bt       */
+        TRUE,                               /* has_wlan */
+    },
+    counted(unifi_map_address_v22_v23),     /* map */
+    /* prog_offset */
+    {
+        0x00C00000,                         /* ram */
+        0x00000000,                         /* rom */
+        0x00000000,                         /* flash (invalid) */
+        0x00000000,                         /* ext_ram (invalid) */
+    },
+    /* data_offset */
+    {
+        0x8000                              /* ram */
+    },
+    /* windows */
+    {
+        &generic1_window_unifi_v22_v23,
+        &generic2_window_unifi_v22_v23,
+        &generic3_window_unifi_v22_v23
+    }
+};
+
+static const struct chip_device_desc_t unifi_device_desc_v23 =
+{
+    { FALSE, 0x00ff, 0x0023, 0x08 },        /* UF.... */
+    "UF....",
+    "UF.... (5)",
+    counted(init_vals_v22_v23),             /* init */
+    null_counted(),                         /* reset_prog */
+    &unifi_device_regs_v22_v23,             /* regs */
+    {
+        FALSE,                              /* has_flash    */
+        FALSE,                              /* has_ext_sram */
+        TRUE,                               /* has_rom      */
+        TRUE,                               /* has_bt       */
+        TRUE,                               /* has_wlan */
+    },
+    counted(unifi_map_address_v22_v23),
+    /* prog_offset */
+    {
+        0x00C00000,                         /* ram */
+        0x00000000,                         /* rom */
+        0x00000000,                         /* flash (invalid) */
+        0x00000000,                         /* ext_sram (invalid) */
+    },
+    /* data_offset */
+    {
+        0x8000                              /* ram */
+    },
+    /* windows */
+    {
+        &generic1_window_unifi_v22_v23,
+        &generic2_window_unifi_v22_v23,
+        &generic3_window_unifi_v22_v23
+    }
+};
+
+static const struct chip_device_desc_t hyd_wlan_subsys_desc_v1 =
+{
+    { FALSE, 0x00ff, 0x0044, 0x00 },        /* UF.... */
+    "HYD...",
+    "HYD...    ",
+    counted(init_vals_v22_v23),             /* init */
+    null_counted(),                         /* reset_prog */
+    &unifi_device_regs_v22_v23,             /* regs */
+    {
+        FALSE,                              /* has_flash    */
+        FALSE,                              /* has_ext_sram */
+        TRUE,                               /* has_rom      */
+        FALSE,                              /* has_bt       */
+        TRUE,                               /* has_wlan */
+    },
+    counted(unifi_map_address_v22_v23),
+    /* prog_offset */
+    {
+        0x00C00000,                         /* ram */
+        0x00000000,                         /* rom */
+        0x00000000,                         /* flash (invalid) */
+        0x00000000,                         /* ext_sram (invalid) */
+    },
+    /* data_offset */
+    {
+        0x8000                              /* ram */
+    },
+    /* windows */
+    {
+        &generic1_window_unifi_v22_v23,
+        &generic2_window_unifi_v22_v23,
+        &generic3_window_unifi_v22_v23
+    }
+};
+
+
+/* This is the list of all chips that we know about.  I'm
+   assuming that the order here will be important - we
+   might have multiple entries witrh the same SDIO id for
+   instance.  The first one in this list will be the one
+   that is returned if a search is done on only that id.
+   The client will then have to call GetVersionXXX again
+   but with more detailed info.
+
+   I don't know if we need to signal this up to the client
+   in some way?
+
+   (We get the SDIO id before we know anything else about
+   the chip.  We might not be able to read any of the other
+   registers at first, but we still need to know about the
+   chip). */
+static const struct chip_device_desc_t *chip_ver_to_desc[] =
+{
+    &unifi_device_desc_v1,      /* UF105x R01 */
+    &unifi_device_desc_v2,      /* UF2... R02 */
+    &unifi_device_desc_v3,      /* UF2... R03 */
+    &unifi_device_desc_v22,     /* UF60xx */
+    &unifi_device_desc_v23,     /* UF.... */
+    &hyd_wlan_subsys_desc_v1
+};
+
+ChipDescript* ChipHelper_GetVersionSdio(CsrUint8 sdio_ver)
+{
+    CsrUint32 i;
+
+    for (i = 0; i < nelem(chip_ver_to_desc); i++)
+    {
+        if (chip_ver_to_desc[i]->chip_version.sdio == sdio_ver)
+        {
+            return chip_ver_to_desc[i];
+        }
+    }
+
+    return &chip_device_desc_null;
+}
+
+
+ChipDescript* ChipHelper_GetVersionAny(CsrUint16 from_FF9A, CsrUint16 from_FE81)
+{
+    CsrUint32 i;
+
+    if ((from_FF9A & 0xFF00) != 0)
+    {
+        for (i = 0; i < nelem(chip_ver_to_desc); i++)
+        {
+            if (chip_ver_to_desc[i]->chip_version.pre_bc7 &&
+                ((from_FF9A & chip_ver_to_desc[i]->chip_version.mask) ==
+                 chip_ver_to_desc[i]->chip_version.result))
+            {
+                return chip_ver_to_desc[i];
+            }
+        }
+    }
+    else
+    {
+        for (i = 0; i < nelem(chip_ver_to_desc); i++)
+        {
+            if (!chip_ver_to_desc[i]->chip_version.pre_bc7 &&
+                ((from_FE81 & chip_ver_to_desc[i]->chip_version.mask) ==
+                 chip_ver_to_desc[i]->chip_version.result))
+            {
+                return chip_ver_to_desc[i];
+            }
+        }
+    }
+
+    return &chip_device_desc_null;
+}
+
+
+ChipDescript* ChipHelper_GetVersionUniFi(CsrUint16 ver)
+{
+    return ChipHelper_GetVersionAny(0x0000, ver);
+}
+
+
+ChipDescript* ChipHelper_Null()
+{
+    return &chip_device_desc_null;
+}
+
+
+ChipDescript* ChipHelper_GetVersionBlueCore(enum chip_helper_bluecore_age bc_age, CsrUint16 version)
+{
+    if (bc_age == chip_helper_bluecore_pre_bc7)
+    {
+        return ChipHelper_GetVersionAny(version, 0x0000);
+    }
+    else
+    {
+        return ChipHelper_GetVersionAny(0x0000, version);
+    }
+}
+
+
+/* Expand the DEF0 functions into simple code to return the
+   correct thing.  The DEF1 functions expand to nothing in
+   this X macro expansion. */
+#define CHIP_HELPER_DEF0_C_DEF(ret_type, name, info)            \
+    ret_type ChipHelper_ ## name(ChipDescript * chip_help)           \
+    {                                                               \
+        return chip_help->info;                                     \
+    }
+#define CHIP_HELPER_DEF1_C_DEF(ret_type, name, type1, name1)
+
+CHIP_HELPER_LIST(C_DEF)
+
+/*
+ * Map register addresses between HOST and SPI access.
+ */
+CsrUint16 ChipHelper_MapAddress_SPI2HOST(ChipDescript *chip_help, CsrUint16 addr)
+{
+    CsrUint32 i;
+    for (i = 0; i < chip_help->map.len; i++)
+    {
+        if (chip_help->map.vals[i].spi == addr)
+        {
+            return chip_help->map.vals[i].host;
+        }
+    }
+    return addr;
+}
+
+
+CsrUint16 ChipHelper_MapAddress_HOST2SPI(ChipDescript *chip_help, CsrUint16 addr)
+{
+    CsrUint32 i;
+    for (i = 0; i < chip_help->map.len; i++)
+    {
+        if (chip_help->map.vals[i].host == addr)
+        {
+            return chip_help->map.vals[i].spi;
+        }
+    }
+    return addr;
+}
+
+
+/* The address returned by this function is the start of the
+   window in the address space, that is where we can start
+   accessing data from.  If a section of the window at the
+   start is unusable because something else is cluttering up
+   the address map then that is taken into account and this
+   function returns that address justt past that. */
+CsrUint16 ChipHelper_WINDOW_ADDRESS(ChipDescript                 *chip_help,
+                                    enum chip_helper_window_index window)
+{
+    if (window < CHIP_HELPER_WINDOW_COUNT &&
+        chip_help->windows[window] != NULL)
+    {
+        return chip_help->windows[window]->address + chip_help->windows[window]->blocked;
+    }
+    return 0;
+}
+
+
+/* This returns the size of the window minus any blocked section */
+CsrUint16 ChipHelper_WINDOW_SIZE(ChipDescript                 *chip_help,
+                                 enum chip_helper_window_index window)
+{
+    if (window < CHIP_HELPER_WINDOW_COUNT &&
+        chip_help->windows[window] != NULL)
+    {
+        return chip_help->windows[window]->size - chip_help->windows[window]->blocked;
+    }
+    return 0;
+}
+
+
+/* Get the register writes we should do to make sure that
+   the chip is running with most clocks on. */
+CsrUint32 ChipHelper_ClockStartupSequence(ChipDescript                          *chip_help,
+                                          const struct chip_helper_init_values **val)
+{
+    *val = chip_help->init.vals;
+    return chip_help->init.len;
+}
+
+
+/* Get the set of values tat we should write to the chip to perform a reset. */
+CsrUint32 ChipHelper_HostResetSequence(ChipDescript                           *chip_help,
+                                       const struct chip_helper_reset_values **val)
+{
+    *val = chip_help->reset_prog.vals;
+    return chip_help->reset_prog.len;
+}
+
+
+/* Decode a windowed access to the chip. */
+CsrInt32 ChipHelper_DecodeWindow(ChipDescript *chip_help,
+                                 enum chip_helper_window_index window,
+                                 enum chip_helper_window_type type,
+                                 CsrUint32 offset,
+                                 CsrUint16 *page, CsrUint16 *addr, CsrUint32 *len)
+{
+    const struct window_info_t *win;
+    const struct window_shift_info_t *mode;
+    CsrUint16 of, pg;
+
+    if (window >= CHIP_HELPER_WINDOW_COUNT)
+    {
+        return FALSE;
+    }
+    if ((win = chip_help->windows[window]) == NULL)
+    {
+        return FALSE;
+    }
+    if (type >= CHIP_HELPER_WT_COUNT)
+    {
+        return FALSE;
+    }
+    if ((mode = &win->mode[type]) == NULL)
+    {
+        return FALSE;
+    }
+    if (!mode->allowed)
+    {
+        return FALSE;
+    }
+
+    pg = (CsrUint16)(offset >> mode->page_shift) + mode->page_offset;
+    of = (CsrUint16)(offset & ((1 << mode->page_shift) - 1));
+    /* If 'blocked' is zero this does nothing, else decrease
+       the page register and increase the offset until we aren't
+       in the blocked region of the window. */
+    while (of < win->blocked)
+    {
+        of += 1 << mode->page_shift;
+        pg--;
+    }
+    *page = pg;
+    *addr = win->address + of;
+    *len = win->size - of;
+    return TRUE;
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_chiphelper.h b/drivers/staging/csr/csr_wifi_hip_chiphelper.h
new file mode 100644
index 0000000..6166d55
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_chiphelper.h
@@ -0,0 +1,471 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifndef CSR_WIFI_HIP_CHIPHELPER_H__
+#define CSR_WIFI_HIP_CHIPHELPER_H__
+
+
+#include "csr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The age of the BlueCore chip.  This is probably not useful, if
+   you know the age then you can probably work out the version directly. */
+enum chip_helper_bluecore_age
+{
+    chip_helper_bluecore_pre_bc7,
+    chip_helper_bluecore_bc7_or_later
+};
+
+/* We support up to three windowed regions at the moment.
+   Don't reorder these - they're used to index into an array. */
+enum chip_helper_window_index
+{
+    CHIP_HELPER_WINDOW_1        = 0,
+    CHIP_HELPER_WINDOW_2        = 1,
+    CHIP_HELPER_WINDOW_3        = 2,
+    CHIP_HELPER_WINDOW_COUNT    = 3
+};
+
+/* These are the things that we can access through a window.
+   Don't reorder these - they're used to index into an array. */
+enum chip_helper_window_type
+{
+    CHIP_HELPER_WT_CODE_RAM = 0,
+    CHIP_HELPER_WT_FLASH    = 1,
+    CHIP_HELPER_WT_EXT_SRAM = 2,
+    CHIP_HELPER_WT_ROM      = 3,
+    CHIP_HELPER_WT_SHARED   = 4,
+    CHIP_HELPER_WT_COUNT    = 5
+};
+
+/* Commands to stop and start the XAP */
+enum chip_helper_dbg_emu_cmd_enum
+{
+    CHIP_HELPER_DBG_EMU_CMD_XAP_STEP_MASK   = 0x0001,
+    CHIP_HELPER_DBG_EMU_CMD_XAP_RUN_B_MASK  = 0x0002,
+    CHIP_HELPER_DBG_EMU_CMD_XAP_BRK_MASK    = 0x0004,
+    CHIP_HELPER_DBG_EMU_CMD_XAP_WAKEUP_MASK = 0x0008
+};
+
+/* Bitmasks for Stop and sleep status: DBG_SPI_STOP_STATUS & DBG_HOST_STOP_STATUS */
+enum chip_helper_dbg_stop_status_enum
+{
+    CHIP_HELPER_DBG_STOP_STATUS_NONE_MASK               = 0x0000,
+    CHIP_HELPER_DBG_STOP_STATUS_P0_MASK                 = 0x0001,
+    CHIP_HELPER_DBG_STOP_STATUS_P1_MASK                 = 0x0002,
+    CHIP_HELPER_DBG_STOP_STATUS_P2_MASK                 = 0x0004,
+    CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_P0_MASK    = 0x0008,
+    CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_P1_MASK    = 0x0010,
+    CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_P2_MASK    = 0x0020,
+    /* Legacy names/alias */
+    CHIP_HELPER_DBG_STOP_STATUS_MAC_MASK                = 0x0001,
+    CHIP_HELPER_DBG_STOP_STATUS_PHY_MASK                = 0x0002,
+    CHIP_HELPER_DBG_STOP_STATUS_BT_MASK                 = 0x0004,
+    CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_MAC_MASK   = 0x0008,
+    CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_PHY_MASK   = 0x0010,
+    CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_BT_MASK    = 0x0020
+};
+
+/* Codes to disable the watchdog */
+enum chip_helper_watchdog_disable_enum
+{
+    CHIP_HELPER_WATCHDOG_DISABLE_CODE1 = 0x6734,
+    CHIP_HELPER_WATCHDOG_DISABLE_CODE2 = 0xD6BF,
+    CHIP_HELPER_WATCHDOG_DISABLE_CODE3 = 0xC31E
+};
+
+/* Other bits have changed between versions */
+enum chip_helper_gbl_misc_enum
+{
+    CHIP_HELPER_GBL_MISC_SPI_STOP_OUT_EN_MASK  = 0x0001,
+    CHIP_HELPER_GBL_MISC_MMU_INIT_DONE_MASK    = 0x0004
+};
+
+/* Coex status register, contains interrupt status and reset pullup status.
+ * CHIP_HELPER_COEX_STATUS_RST_PULLS_MSB_MASK can be used to check
+ * for WAPI on R03 chips and later. */
+enum chip_helper_coex_status_mask_enum
+{
+    CHIP_HELPER_COEX_STATUS_RST_PULLS_LSB_MASK   = 0x0001,
+    CHIP_HELPER_COEX_STATUS_RST_PULLS_MSB_MASK   = 0x0008,
+    CHIP_HELPER_COEX_STATUS_WL_FEC_PINS_LSB_MASK = 0x0010,
+    CHIP_HELPER_COEX_STATUS_WL_FEC_PINS_MSB_MASK = 0x0080,
+    CHIP_HELPER_COEX_STATUS_INT_UART_MASK        = 0x0100,
+    CHIP_HELPER_COEX_STATUS_INT_BT_LEG_MASK      = 0x0200
+};
+
+/* How to select the different CPUs */
+enum chip_helper_dbg_proc_sel_enum
+{
+    CHIP_HELPER_DBG_PROC_SEL_MAC  = 0,
+    CHIP_HELPER_DBG_PROC_SEL_PHY  = 1,
+    CHIP_HELPER_DBG_PROC_SEL_BT   = 2,
+    CHIP_HELPER_DBG_PROC_SEL_NONE = 2,
+    CHIP_HELPER_DBG_PROC_SEL_BOTH = 3
+};
+
+/* These are the only registers that we have to know the
+   address of before we know the chip version. */
+enum chip_helper_fixed_registers
+{
+    /* This is the address of GBL_CHIP_VERISON on BC7,
+       UF105x, UF60xx and
+       anything later than that. */
+    CHIP_HELPER_UNIFI_GBL_CHIP_VERSION  = 0xFE81,
+
+    CHIP_HELPER_OLD_BLUECORE_GBL_CHIP_VERSION = 0xFF9A
+
+                                                /* This isn't used at the moment (but might be needed
+                                                to distinguish the BlueCore sub version?) */
+                                                /* CHIP_HELPER_OLD_BLUECORE_ANA_VERSION_ID = 0xFF7D */
+};
+
+/* Address-value pairs for defining initialisation values */
+struct chip_helper_init_values
+{
+    CsrUint16 addr;
+    CsrUint16 value;
+};
+
+/* A block of data that should be written to the device */
+struct chip_helper_reset_values
+{
+    CsrUint32        gp_address;
+    CsrUint32        len;
+    const CsrUint16 *data;
+};
+
+/*
+ * This is the C API.
+ */
+
+/* opaque type */
+typedef const struct chip_device_desc_t ChipDescript;
+
+/* Return a NULL descriptor */
+ChipDescript* ChipHelper_Null(void);
+
+/* This should get the correct version for any CSR chip.
+   The two parameters are what is read from addresses
+   0xFF9A and 0xFE81 (OLD_BLUECORE_GBL_CHIP_VERSION and
+   UNIFI_GBL_CHIP_VERSION).  These should give a unique identity
+   for most (all?) chips.
+
+   FF9A is the old GBL_CHIP_VERSION register.  If the high
+   eight bits are zero then the chip is a new (BC7 +) one
+   and FE81 is the _new_ GBL_CHIP_VERSION register. */
+ChipDescript* ChipHelper_GetVersionAny(CsrUint16 from_FF9A, CsrUint16 from_FE81);
+
+/* The chip is a UniFi, but we don't know which type
+   The parameter is the value of UNIFI_GBL_CHIP_VERSION (0xFE81) */
+ChipDescript* ChipHelper_GetVersionUniFi(CsrUint16 version);
+
+/* This gets the version from the SDIO device id.  This only
+   gives quite a coarse grained version, so we should update once
+   we hav access to the function N registers. */
+ChipDescript* ChipHelper_GetVersionSdio(CsrUint8 sdio_version);
+
+/* The chip is some sort of BlueCore.  If "age" is "pre_bc7" then
+   "version" is what was read from FF9A.  If "age" is bc7_or_later
+   then "version" is read from FE81.  If we don't know if we're pre
+   or post BC7 then we should use "GetVersionAny". */
+ChipDescript* ChipHelper_GetVersionBlueCore(enum chip_helper_bluecore_age age,
+                                            CsrUint16                     version);
+
+/* The main functions of this class are built with an X macro.  This
+   means we can generate the C and C++ versions from the same source
+   without the two diverging.
+
+   The DEF0 functions are simple and take no parameters.  The first
+   parameter to the macro is the return type.  The second parameter
+   is the function name and the third parameter is where to get the
+   info from (this is hidden from the user).
+
+   The DEF1 functions take one parameter. This time the third macro
+   parameter is the type of this parameter, and the fourth macro
+   parameter is the name of the parameter. The bodies of these
+   functions are hand written. */
+#define CHIP_HELPER_LIST(m)                                             \
+    CHIP_HELPER_DEF0(m, (const CsrCharString *, FriendlyName, friendly_name))     \
+    CHIP_HELPER_DEF0(m, (const CsrCharString *, MarketingName, marketing_name))  \
+    CHIP_HELPER_DEF0(m, (CsrUint16, DBG_EMU_CMD, regs->dbg_emu_cmd))       \
+    CHIP_HELPER_DEF0(m, (CsrUint16, DBG_HOST_PROC_SELECT, regs->host.dbg_proc_select)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, DBG_HOST_STOP_STATUS, regs->host.dbg_stop_status)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, HOST_WINDOW1_PAGE, regs->host.window1_page)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, HOST_WINDOW2_PAGE, regs->host.window2_page)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, HOST_WINDOW3_PAGE, regs->host.window3_page)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, HOST_IO_LOG_ADDR, regs->host.io_log_addr)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, DBG_SPI_PROC_SELECT, regs->spi.dbg_proc_select)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, DBG_SPI_STOP_STATUS, regs->spi.dbg_stop_status)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, SPI_WINDOW1_PAGE, regs->spi.window1_page)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, SPI_WINDOW2_PAGE, regs->spi.window2_page)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, SPI_WINDOW3_PAGE, regs->spi.window3_page)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, SPI_IO_LOG_ADDR, regs->spi.io_log_addr)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, DBG_RESET, regs->dbg_reset))           \
+    CHIP_HELPER_DEF0(m, (CsrUint16, DBG_RESET_VALUE, regs->dbg_reset_value)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, DBG_RESET_WARN, regs->dbg_reset_warn)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, DBG_RESET_WARN_VALUE, regs->dbg_reset_warn_value)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, DBG_RESET_RESULT, regs->dbg_reset_result)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, WATCHDOG_DISABLE, regs->watchdog_disable)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, PROC_PC_SNOOP, regs->proc_pc_snoop))   \
+    CHIP_HELPER_DEF0(m, (CsrUint16, GBL_CHIP_VERSION, regs->gbl_chip_version)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, GBL_MISC_ENABLES, regs->gbl_misc_enables)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, XAP_PCH, regs->xap_pch))               \
+    CHIP_HELPER_DEF0(m, (CsrUint16, XAP_PCL, regs->xap_pcl))               \
+    CHIP_HELPER_DEF0(m, (CsrUint16, MAILBOX0, regs->mailbox0))             \
+    CHIP_HELPER_DEF0(m, (CsrUint16, MAILBOX1, regs->mailbox1))             \
+    CHIP_HELPER_DEF0(m, (CsrUint16, MAILBOX2, regs->mailbox2))             \
+    CHIP_HELPER_DEF0(m, (CsrUint16, MAILBOX3, regs->mailbox3))             \
+    CHIP_HELPER_DEF0(m, (CsrUint16, SDIO_HIP_HANDSHAKE, regs->sdio_hip_handshake))   \
+    CHIP_HELPER_DEF0(m, (CsrUint16, SDIO_HOST_INT, regs->sdio_host_int))   \
+    CHIP_HELPER_DEF0(m, (CsrUint16, COEX_STATUS, regs->coex_status))       \
+    CHIP_HELPER_DEF0(m, (CsrUint16, SHARED_IO_INTERRUPT, regs->shared_io_interrupt)) \
+    CHIP_HELPER_DEF0(m, (CsrUint32, PROGRAM_MEMORY_RAM_OFFSET, prog_offset.ram)) \
+    CHIP_HELPER_DEF0(m, (CsrUint32, PROGRAM_MEMORY_ROM_OFFSET, prog_offset.rom)) \
+    CHIP_HELPER_DEF0(m, (CsrUint32, PROGRAM_MEMORY_FLASH_OFFSET, prog_offset.flash)) \
+    CHIP_HELPER_DEF0(m, (CsrUint32, PROGRAM_MEMORY_EXT_SRAM_OFFSET, prog_offset.ext_sram)) \
+    CHIP_HELPER_DEF0(m, (CsrUint16, DATA_MEMORY_RAM_OFFSET, data_offset.ram)) \
+    CHIP_HELPER_DEF0(m, (CsrInt32, HasFlash, bools.has_flash))              \
+    CHIP_HELPER_DEF0(m, (CsrInt32, HasExtSram, bools.has_ext_sram))         \
+    CHIP_HELPER_DEF0(m, (CsrInt32, HasRom, bools.has_rom))                  \
+    CHIP_HELPER_DEF0(m, (CsrInt32, HasBt, bools.has_bt))                    \
+    CHIP_HELPER_DEF0(m, (CsrInt32, HasWLan, bools.has_wlan))                \
+    CHIP_HELPER_DEF1(m, (CsrUint16, WINDOW_ADDRESS, enum chip_helper_window_index, window)) \
+    CHIP_HELPER_DEF1(m, (CsrUint16, WINDOW_SIZE, enum chip_helper_window_index, window)) \
+    CHIP_HELPER_DEF1(m, (CsrUint16, MapAddress_SPI2HOST, CsrUint16, addr))          \
+    CHIP_HELPER_DEF1(m, (CsrUint16, MapAddress_HOST2SPI, CsrUint16, addr))          \
+    CHIP_HELPER_DEF1(m, (CsrUint32, ClockStartupSequence, const struct chip_helper_init_values **, val)) \
+    CHIP_HELPER_DEF1(m, (CsrUint32, HostResetSequence, const struct chip_helper_reset_values **, val))
+
+/* Some magic to help the expansion */
+#define CHIP_HELPER_DEF0(a, b) \
+    CHIP_HELPER_DEF0_ ## a b
+#define CHIP_HELPER_DEF1(a, b) \
+    CHIP_HELPER_DEF1_ ## a b
+
+/* Macros so that when we expand the list we get "C" function prototypes. */
+#define CHIP_HELPER_DEF0_C_DEC(ret_type, name, info)    \
+    ret_type ChipHelper_ ## name(ChipDescript * chip_help);
+#define CHIP_HELPER_DEF1_C_DEC(ret_type, name, type1, name1)   \
+    ret_type ChipHelper_ ## name(ChipDescript * chip_help, type1 name1);
+
+CHIP_HELPER_LIST(C_DEC)
+
+/* FriendlyName
+   MarketingName
+
+   These two functions return human readable strings that describe
+   the chip.  FriendlyName returns something that a software engineer
+   at CSR might understand.  MarketingName returns something more like
+   an external name for a CSR chip.
+*/
+/* DBG_EMU_CMD
+   WATCHDOG_DISABLE
+   PROC_PC_SNOOP
+   GBL_CHIP_VERSION
+   XAP_PCH
+   XAP_PCL
+
+   These registers are used to control the XAPs.
+*/
+/* DBG_HOST_PROC_SELECT  DBG_HOST_STOP_STATUS
+   HOST_WINDOW1_PAGE HOST_WINDOW2_PAGE HOST_WINDOW3_PAGE
+   HOST_IO_LOG_ADDR
+   DBG_SPI_PROC_SELECT  DBG_SPI_STOP_STATUS
+   SPI_WINDOW1_PAGE SPI_WINDOW2_PAGE SPI_WINDOW3_PAGE
+   SPI_IO_LOG_ADDR
+
+   These register are used to control the XAPs and the memory
+   windows, normally while debugging the code on chip.  There
+   are two versons of these registers, one for access via SPI
+   and another for access via the host interface.
+*/
+/*  DBG_RESET
+    DBG_RESET_VALUE
+    DBG_RESET_WARN
+    DBG_RESET_WARN_VALUE
+    DBG_RESET_RESULT
+
+    These registers are used to reset the XAP.  This can be
+    quite complex for some chips.  If DBG_RESET_WARN is non
+    zero the DBG_RESET_WARN_VALUE should be written to address
+    DBG_RESET_WARN before the reset is perfeormed.  DBG_RESET_VALUE
+    should then be written to DBG_RESET to make the reset happen.
+    The DBG_RESET_RESULT register should contain 0 if the reset
+    was successful.
+*/
+/*  GBL_MISC_ENABLES
+
+    This register controls some special chip features.  It
+    should be used with care is it changes quite a lot between
+    chip versions.
+*/
+/*  MAILBOX0
+    MAILBOX1
+    MAILBOX2
+    MAILBOX3
+
+    The mailbox registers are for communication between the host
+    and the firmware.  There use is described in part by the host
+    interface protcol specifcation.
+*/
+/*  SDIO_HIP_HANDSHAKE
+
+    This is one of the more important SDIO HIP registers.  On some
+    chips it has the same value as one of the mailbox registers
+    and on other chips it is different.
+*/
+/*  SDIO_HOST_INT
+    SHARED_IO_INTERRUPT
+
+    These registers are used by some versions of the host interface
+    protocol specification.  Their names should probably be changed
+    to hide the registers and to expose the functions more.
+*/
+/*  COEX_STATUS
+
+    Coex status register, contains interrupt status and reset
+    pullup status.  The latter is used to detect WAPI.
+*/
+/*  PROGRAM_MEMORY_RAM_OFFSET
+    PROGRAM_MEMORY_ROM_OFFSET
+    PROGRAM_MEMORY_FLASH_OFFSET
+    PROGRAM_MEMORY_EXT_SRAM_OFFSET
+    DATA_MEMORY_RAM_OFFSET
+
+    These are constants that describe the offset of the different
+    memory types in the two different address spaces.
+*/
+/*  HasFlash HasExtSram HasRom
+    HasBt HasWLan
+
+    These are a set of bools describing the chip.
+*/
+/*  WINDOW_ADDRESS WINDOW_SIZE
+
+    These two functions return the size and address of the windows.
+    The address is the address of the lowest value in the address
+    map that is part of the window and the size is the number of
+    visible words.
+
+    Some of the windows have thier lowest portion covered by
+    registers.  For these windows address is the first address
+    after the registers and size is the siave excluding the part
+    covered by registers.
+*/
+/*  MapAddress_SPI2HOST
+    MapAddress_HOST2SPI
+
+    The debugging interface is duplicated on UniFi and later chips
+    so that there are two versions - one over the SPI interaface and
+    the other over the SDIO interface.  These functions map the
+    registers between these two interfaces.
+*/
+/*  ClockStartupSequence
+
+    This function returns the list of register value pairs that
+    should be forced into UniFi to enable SPI communication.  This
+    set of registers is not needed if the firmware is running, but
+    will be needed if the device is being booted from cold.  These
+    register writes enable the clocks and setup the PLL to a basic
+    working state.  SPI access might be unreliable until these writes
+    have occured (And they may take mulitple goes).
+*/
+/*  HostResetSequence
+
+    This returns a number of chunks of data and generic pointers.
+    All of the XAPs should be stopped.  The data should be written
+    to the generic pointers.  The instruction pointer for the MAC
+    should then be set to the start of program memory and then the
+    MAC should be "go"d.  This will reset the chip in a reliable
+    and orderly manner without resetting the SDIO interface.  It
+    is therefore not needed if the chip is being accessed by the
+    SPI interface (the DBG_RESET_ mechanism can be used instead).
+*/
+
+/* The Decode Window function is more complex.  For the window
+   'window' it tries to return the address and page register
+   value needed to see offset 'offset' of memory type 'type'.
+
+   It return 1 on success and 0 on failure.  'page' is what
+   should be written to the page register.  'addr' is the
+   address in the XAPs 16 address map to read from.  'len'
+   is the length that we can read without having to change
+   the page registers. */
+CsrInt32 ChipHelper_DecodeWindow(ChipDescript *chip_help,
+                                 enum chip_helper_window_index window,
+                                 enum chip_helper_window_type type,
+                                 CsrUint32 offset,
+                                 CsrUint16 *page, CsrUint16 *addr, CsrUint32 *len);
+
+#ifdef __cplusplus
+/* Close the extern "C" */
+}
+
+/*
+ * This is the C++ API.
+ */
+
+class ChipHelper
+{
+public:
+    /* If this constructor is used then a GetVersionXXX function
+       should be called next. */
+    ChipHelper();
+
+    /* copy constructor */
+    ChipHelper(ChipDescript * desc);
+
+    /* The default constructor assume a BC7 / UF105x series chip
+       and that the number given is the value of UNIFI_GBL_CHIP_VERSION
+       (0xFE81) */
+    ChipHelper(CsrUint16 version);
+
+    /* This returns the C interface magic token from a C++ instance. */
+    ChipDescript* GetDescript() const
+    {
+        return m_desc;
+    }
+
+
+    /* Clear out theis class (set it to the null token). */
+    void ClearVersion();
+
+    /* Load this class with data for a specific chip. */
+    void GetVersionAny(CsrUint16 from_FF9A, CsrUint16 from_FE81);
+    void GetVersionUniFi(CsrUint16 version);
+    void GetVersionBlueCore(chip_helper_bluecore_age age, CsrUint16 version);
+    void GetVersionSdio(CsrUint8 sdio_version);
+
+    /* Helpers to build the definitions of the member functions. */
+#define CHIP_HELPER_DEF0_CPP_DEC(ret_type, name, info)    \
+    ret_type name() const;
+#define CHIP_HELPER_DEF1_CPP_DEC(ret_type, name, type1, name1)   \
+    ret_type name(type1 name1) const;
+
+    CHIP_HELPER_LIST(CPP_DEC)
+
+
+    /* The DecodeWindow function, see the description of the C version. */
+    CsrInt32 DecodeWindow(chip_helper_window_index window,
+                          chip_helper_window_type type,
+                          CsrUint32 offset,
+                          CsrUint16 &page, CsrUint16 &addr, CsrUint32 &len) const;
+
+private:
+    ChipDescript *m_desc;
+};
+
+#endif /* __cplusplus */
+
+#endif
diff --git a/drivers/staging/csr/csr_wifi_hip_chiphelper_private.h b/drivers/staging/csr/csr_wifi_hip_chiphelper_private.h
new file mode 100644
index 0000000..7ab8173
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_chiphelper_private.h
@@ -0,0 +1,208 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifndef CSR_WIFI_HIP_CHIPHELPER_PRIVATE_H__
+#define CSR_WIFI_HIP_CHIPHELPER_PRIVATE_H__
+
+
+#include "csr_wifi_hip_chiphelper.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* This GP stuff should be somewhere else? */
+
+/* Memory spaces encoded in top byte of Generic Pointer type */
+#define UNIFI_SH_DMEM   0x01    /* Shared Data Memory */
+#define UNIFI_EXT_FLASH 0x02    /* External FLASH */
+#define UNIFI_EXT_SRAM  0x03    /* External SRAM */
+#define UNIFI_REGISTERS 0x04    /* Registers */
+#define UNIFI_PHY_DMEM  0x10    /* PHY Data Memory */
+#define UNIFI_PHY_PMEM  0x11    /* PHY Program Memory */
+#define UNIFI_PHY_ROM   0x12    /* PHY ROM */
+#define UNIFI_MAC_DMEM  0x20    /* MAC Data Memory */
+#define UNIFI_MAC_PMEM  0x21    /* MAC Program Memory */
+#define UNIFI_MAC_ROM   0x22    /* MAC ROM */
+#define UNIFI_BT_DMEM   0x30    /* BT Data Memory */
+#define UNIFI_BT_PMEM   0x31    /* BT Program Memory */
+#define UNIFI_BT_ROM    0x32    /* BT ROM */
+
+#define MAKE_GP(R, O)  (((UNIFI_ ## R) << 24) | (O))
+#define GP_OFFSET(GP)  ((GP) & 0xFFFFFF)
+#define GP_SPACE(GP)   (((GP) >> 24) & 0xFF)
+
+
+/* Address value pairs */
+struct val_array_t
+{
+    CsrUint32                             len;
+    const struct chip_helper_init_values *vals;
+};
+
+/* Just a (counted) CsrUint16 array */
+struct data_array_t
+{
+    CsrUint32        len;
+    const CsrUint16 *vals;
+};
+
+struct reset_prog_t
+{
+    CsrUint32                              len;
+    const struct chip_helper_reset_values *vals;
+};
+
+/* The addresses of registers that are equivalent but on
+   different host transports. */
+struct chip_map_address_t
+{
+    CsrUint16 spi, host;
+};
+
+struct map_array_t
+{
+    CsrUint32                        len;
+    const struct chip_map_address_t *vals;
+};
+
+struct chip_device_regs_per_transport_t
+{
+    CsrUint16 dbg_proc_select;
+    CsrUint16 dbg_stop_status;
+    CsrUint16 window1_page;    /* PROG_PMEM1 or GW1 */
+    CsrUint16 window2_page;    /* PROG_PMEM2 or GW2 */
+    CsrUint16 window3_page;    /* SHARED or GW3 */
+    CsrUint16 io_log_addr;
+};
+
+struct chip_device_regs_t
+{
+    CsrUint16                               gbl_chip_version;
+    CsrUint16                               gbl_misc_enables;
+    CsrUint16                               dbg_emu_cmd;
+    struct chip_device_regs_per_transport_t host;
+    struct chip_device_regs_per_transport_t spi;
+    CsrUint16                               dbg_reset;
+    CsrUint16                               dbg_reset_value;
+    CsrUint16                               dbg_reset_warn;
+    CsrUint16                               dbg_reset_warn_value;
+    CsrUint16                               dbg_reset_result;
+    CsrUint16                               xap_pch;
+    CsrUint16                               xap_pcl;
+    CsrUint16                               proc_pc_snoop;
+    CsrUint16                               watchdog_disable;
+    CsrUint16                               mailbox0;
+    CsrUint16                               mailbox1;
+    CsrUint16                               mailbox2;
+    CsrUint16                               mailbox3;
+    CsrUint16                               sdio_host_int;
+    CsrUint16                               shared_io_interrupt;
+    CsrUint16                               sdio_hip_handshake;
+    CsrUint16                               coex_status; /* Allows WAPI detection */
+};
+
+/* If allowed is false then this window does not provide this
+   type of access.
+   This describes how addresses should be shifted to make the
+   "page" address.  The address is shifted left by 'page_shift'
+   and then has 'page_offset' added.  This value should then be
+   written to the page register. */
+struct window_shift_info_t
+{
+    CsrInt32  allowed;
+    CsrUint32 page_shift;
+    CsrUint16 page_offset;
+};
+
+/* Each window has an address and size.  These are obvious.  It then
+   has a description for each type of memory that might be accessed
+   through it.  There might also be a start to the offset of the window.
+   This means that that number of addresses at the start of the window
+   are unusable. */
+struct window_info_t
+{
+    CsrUint16                         address;
+    CsrUint16                         size;
+    CsrUint16                         blocked;
+    const struct window_shift_info_t *mode;
+};
+
+/* If GBL_CHIP_VERSION and'ed with 'mask' and is equal to 'result'
+   then this is the correct set of info.  If pre_bc7 is true then the
+   address of GBL_CHIP_VERSION is FF9A, else its FE81. */
+struct chip_version_t
+{
+    CsrInt32  pre_bc7;
+    CsrUint16 mask;
+    CsrUint16 result;
+    CsrUint8  sdio;
+};
+
+struct chip_device_desc_t
+{
+    struct chip_version_t chip_version;
+
+    /* This is a text string that a human might find useful (BC02, UF105x) */
+    const CsrCharString *friendly_name;
+    /* This is what we show to customers */
+    const CsrCharString *marketing_name;
+
+    /* Initialisation values to write following a reset */
+    struct val_array_t init;
+
+    /* Binary sequence for hard reset */
+    struct reset_prog_t reset_prog;
+
+    /* The register map */
+    const struct chip_device_regs_t *regs;
+
+    /* Some misc. info on the chip */
+    struct
+    {
+        CsrUint32 has_flash     : 1;
+        CsrUint32 has_ext_sram  : 1;
+        CsrUint32 has_rom       : 1;
+        CsrUint32 has_bt        : 1;
+        CsrUint32 has_wlan      : 1;
+    } bools;
+
+    /* This table is used to remap register addresses depending on what
+       host interface is used.  On the BC7 and later chips there are
+       multiple sets of memory window registers, on for each host
+       interafce (SDIO / SPI).  The correct one is needed. */
+    struct map_array_t map;
+
+    /* The offsets into the program address space of the different types of memory.
+       The RAM offset is probably the most useful. */
+    struct
+    {
+        CsrUint32 ram;
+        CsrUint32 rom;
+        CsrUint32 flash;
+        CsrUint32 ext_sram;
+    } prog_offset;
+
+    /* The offsets into the data address space of interesting things. */
+    struct
+    {
+        CsrUint16 ram;
+        /* maybe add shared / page tables? */
+    } data_offset;
+
+    /* Information on the different windows */
+    const struct window_info_t *windows[CHIP_HELPER_WINDOW_COUNT];
+};
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CSR_WIFI_HIP_CHIPHELPER_PRIVATE_H__ */
diff --git a/drivers/staging/csr/csr_wifi_hip_conversions.h b/drivers/staging/csr/csr_wifi_hip_conversions.h
new file mode 100644
index 0000000..6a4647d
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_conversions.h
@@ -0,0 +1,81 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * FILE: csr_wifi_hip_conversions.h
+ *
+ * PURPOSE:
+ *      This header file provides the macros for converting to and from
+ *      wire format.
+ *      These macros *MUST* work for little-endian AND big-endian hosts.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#ifndef __CSR_WIFI_HIP_CONVERSIONS_H__
+#define __CSR_WIFI_HIP_CONVERSIONS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SIZEOF_UINT16           2
+#define SIZEOF_UINT32           4
+#define SIZEOF_UINT64           8
+
+#define SIZEOF_SIGNAL_HEADER    6
+#define SIZEOF_DATAREF          4
+
+
+/*
+ * Macro to retrieve the signal ID from a wire-format signal.
+ */
+#define GET_SIGNAL_ID(_buf)     CSR_GET_UINT16_FROM_LITTLE_ENDIAN((_buf))
+
+/*
+ * Macros to retrieve and set the DATAREF fields in a packed (i.e. wire-format)
+ * HIP signal.
+ */
+#define GET_PACKED_DATAREF_SLOT(_buf, _ref)                             \
+    CSR_GET_UINT16_FROM_LITTLE_ENDIAN(((_buf) + SIZEOF_SIGNAL_HEADER + ((_ref) * SIZEOF_DATAREF) + 0))
+
+#define GET_PACKED_DATAREF_LEN(_buf, _ref)                              \
+    CSR_GET_UINT16_FROM_LITTLE_ENDIAN(((_buf) + SIZEOF_SIGNAL_HEADER + ((_ref) * SIZEOF_DATAREF) + 2))
+
+#define SET_PACKED_DATAREF_SLOT(_buf, _ref, _slot)                      \
+    CSR_COPY_UINT16_TO_LITTLE_ENDIAN((_slot), ((_buf) + SIZEOF_SIGNAL_HEADER + ((_ref) * SIZEOF_DATAREF) + 0))
+
+#define SET_PACKED_DATAREF_LEN(_buf, _ref, _len)                        \
+    CSR_COPY_UINT16_TO_LITTLE_ENDIAN((_len), ((_buf) + SIZEOF_SIGNAL_HEADER + ((_ref) * SIZEOF_DATAREF) + 2))
+
+#define GET_PACKED_MA_PACKET_REQUEST_FRAME_PRIORITY(_buf)              \
+    CSR_GET_UINT16_FROM_LITTLE_ENDIAN(((_buf) + SIZEOF_SIGNAL_HEADER + UNIFI_MAX_DATA_REFERENCES * SIZEOF_DATAREF + 8))
+
+#define GET_PACKED_MA_PACKET_REQUEST_HOST_TAG(_buf)                     \
+    CSR_GET_UINT32_FROM_LITTLE_ENDIAN(((_buf) + SIZEOF_SIGNAL_HEADER + UNIFI_MAX_DATA_REFERENCES * SIZEOF_DATAREF + 4))
+
+#define GET_PACKED_MA_PACKET_CONFIRM_HOST_TAG(_buf)                     \
+    CSR_GET_UINT32_FROM_LITTLE_ENDIAN(((_buf) + SIZEOF_SIGNAL_HEADER + UNIFI_MAX_DATA_REFERENCES * SIZEOF_DATAREF + 8))
+
+#define GET_PACKED_MA_PACKET_CONFIRM_TRANSMISSION_STATUS(_buf)                     \
+    CSR_GET_UINT16_FROM_LITTLE_ENDIAN(((_buf) + SIZEOF_SIGNAL_HEADER + UNIFI_MAX_DATA_REFERENCES * SIZEOF_DATAREF + 2))
+
+
+CsrInt32 get_packed_struct_size(const CsrUint8 *buf);
+CsrResult read_unpack_signal(const CsrUint8 *ptr, CSR_SIGNAL *sig);
+CsrResult write_pack(const CSR_SIGNAL *sig, CsrUint8 *ptr, CsrUint16 *sig_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CSR_WIFI_HIP_CONVERSIONS_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_hip_download.c b/drivers/staging/csr/csr_wifi_hip_download.c
new file mode 100644
index 0000000..47178af
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_download.c
@@ -0,0 +1,834 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ * FILE: csr_wifi_hip_download.c
+ *
+ * PURPOSE:
+ *      Routines for downloading firmware to UniFi.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_unifiversion.h"
+#include "csr_wifi_hip_card.h"
+#include "csr_wifi_hip_xbv.h"
+
+#undef CSR_WIFI_IGNORE_PATCH_VERSION_MISMATCH
+
+static CsrResult do_patch_download(card_t *card, void *dlpriv,
+                                   xbv1_t *pfwinfo, CsrUint32 boot_ctrl_addr);
+
+static CsrResult do_patch_convert_download(card_t *card,
+                                           void *dlpriv, xbv1_t *pfwinfo);
+
+/*
+ * ---------------------------------------------------------------------------
+ *  _find_in_slut
+ *
+ *      Find the offset of the appropriate object in the SLUT of a card
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      psym            Pointer to symbol object.
+ *                         id set up by caller
+ *                         obj will be set up by this function
+ *      pslut           Pointer to SLUT address, if 0xffffffff then it must be
+ *                         read from the chip.
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success
+ *      Non-zero on error,
+ *      CSR_WIFI_HIP_RESULT_NOT_FOUND if not found
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult _find_in_slut(card_t *card, symbol_t *psym, CsrUint32 *pslut)
+{
+    CsrUint32 slut_address;
+    CsrUint16 finger_print;
+    CsrResult r;
+    CsrResult csrResult;
+
+    /* Get SLUT address */
+    if (*pslut == 0xffffffff)
+    {
+        r = card_wait_for_firmware_to_start(card, &slut_address);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Firmware hasn't started\n");
+            func_exit_r(r);
+            return r;
+        }
+        *pslut = slut_address;
+
+        /*
+         * Firmware has started so set the SDIO bus clock to the initial speed,
+         * faster than UNIFI_SDIO_CLOCK_SAFE_HZ, to speed up the f/w download.
+         */
+        csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_INIT_HZ);
+        if (csrResult != CSR_RESULT_SUCCESS)
+        {
+            r = ConvertCsrSdioToCsrHipResult(card, csrResult);
+            func_exit_r(r);
+            return r;
+        }
+        card->sdio_clock_speed = UNIFI_SDIO_CLOCK_INIT_HZ;
+    }
+    else
+    {
+        slut_address = *pslut;  /* Use previously discovered address */
+    }
+    unifi_trace(card->ospriv, UDBG4, "SLUT addr: 0x%lX\n", slut_address);
+
+    /*
+     * Check the SLUT fingerprint.
+     * The slut_address is a generic pointer so we must use unifi_card_read16().
+     */
+    unifi_trace(card->ospriv, UDBG4, "Looking for SLUT finger print\n");
+    finger_print = 0;
+    r = unifi_card_read16(card, slut_address, &finger_print);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        return r;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to read SLUT finger print\n");
+        func_exit_r(r);
+        return r;
+    }
+
+    if (finger_print != SLUT_FINGERPRINT)
+    {
+        unifi_error(card->ospriv, "Failed to find SLUT fingerprint\n");
+        func_exit_r(CSR_RESULT_FAILURE);
+        return CSR_RESULT_FAILURE;
+    }
+
+    /* Symbol table starts imedately after the fingerprint */
+    slut_address += 2;
+
+    while (1)
+    {
+        CsrUint16 id;
+        CsrUint32 obj;
+
+        r = unifi_card_read16(card, slut_address, &id);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            func_exit_r(r);
+            return r;
+        }
+        slut_address += 2;
+
+        if (id == CSR_SLT_END)
+        {
+            /* End of table reached: not found */
+            r = CSR_WIFI_HIP_RESULT_RANGE;
+            break;
+        }
+
+        r = unifi_read32(card, slut_address, &obj);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            func_exit_r(r);
+            return r;
+        }
+        slut_address += 4;
+
+        unifi_trace(card->ospriv, UDBG3, "  found SLUT id %02d.%08lx\n", id, obj);
+
+        r = CSR_WIFI_HIP_RESULT_NOT_FOUND;
+        /* Found search term? */
+        if (id == psym->id)
+        {
+            unifi_trace(card->ospriv, UDBG1, " matched SLUT id %02d.%08lx\n", id, obj);
+            psym->obj = obj;
+            r = CSR_RESULT_SUCCESS;
+            break;
+        }
+    }
+
+    func_exit_r(r);
+    return r;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  do_patch_convert_download
+ *
+ *      Download the given firmware image to the UniFi, converting from FWDL
+ *      to PTDL XBV format.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      dlpriv          Pointer to source firmware image
+ *      fwinfo          Pointer to source firmware info struct
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR error code on error
+ *
+ *  Notes:
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult do_patch_convert_download(card_t *card, void *dlpriv, xbv1_t *pfwinfo)
+{
+    CsrResult r;
+    CsrUint32 slut_base = 0xffffffff;
+    void *pfw;
+    CsrUint32 psize;
+    symbol_t sym;
+
+    /* Reset the chip to guarantee that the ROM loader is running */
+    r = unifi_init(card);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv,
+                    "do_patch_convert_download: failed to re-init UniFi\n");
+        return r;
+    }
+
+    /* If no unifi_helper is running, the firmware version must be read */
+    if (card->build_id == 0)
+    {
+        CsrUint32 ver = 0;
+        sym.id = CSR_SLT_BUILD_ID_NUMBER;
+        sym.obj = 0; /* To be updated by _find_in_slut() */
+
+        unifi_trace(card->ospriv, UDBG1, "Need f/w version\n");
+
+        /* Find chip build id entry in SLUT */
+        r = _find_in_slut(card, &sym, &slut_base);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to find CSR_SLT_BUILD_ID_NUMBER\n");
+            return CSR_RESULT_FAILURE;
+        }
+
+        /* Read running f/w version */
+        r = unifi_read32(card, sym.obj, &ver);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to read f/w id\n");
+            return CSR_RESULT_FAILURE;
+        }
+        card->build_id = ver;
+    }
+
+    /* Convert the ptest firmware to a patch against the running firmware */
+    pfw = xbv_to_patch(card, unifi_fw_read, dlpriv, pfwinfo, &psize);
+    if (!pfw)
+    {
+        unifi_error(card->ospriv, "Failed to convert f/w to patch");
+        return CSR_WIFI_HIP_RESULT_NO_MEMORY;
+    }
+    else
+    {
+        void *desc;
+        sym.id = CSR_SLT_BOOT_LOADER_CONTROL;
+        sym.obj = 0; /* To be updated by _find_in_slut() */
+
+        /* Find boot loader control entry in SLUT */
+        r = _find_in_slut(card, &sym, &slut_base);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to find BOOT_LOADER_CONTROL\n");
+            return CSR_RESULT_FAILURE;
+        }
+
+        r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to wake UniFi\n");
+        }
+
+        /* Get a dlpriv for the patch buffer so that unifi_fw_read() can
+         * access it.
+         */
+        desc = unifi_fw_open_buffer(card->ospriv, pfw, psize);
+        if (!desc)
+        {
+            return CSR_WIFI_HIP_RESULT_NO_MEMORY;
+        }
+
+        /* Download the patch */
+        unifi_info(card->ospriv, "Downloading converted f/w as patch\n");
+        r = unifi_dl_patch(card, desc, sym.obj);
+        CsrMemFree(pfw);
+        unifi_fw_close_buffer(card->ospriv, desc);
+
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Converted patch download failed\n");
+            func_exit_r(r);
+            return r;
+        }
+        else
+        {
+            unifi_trace(card->ospriv, UDBG1, "Converted patch downloaded\n");
+        }
+
+        /* This command starts the firmware */
+        r = unifi_do_loader_op(card, sym.obj + 6, UNIFI_BOOT_LOADER_RESTART);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to write loader restart cmd\n");
+        }
+
+        func_exit_r(r);
+        return r;
+    }
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_dl_firmware
+ *
+ *      Download the given firmware image to the UniFi.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      dlpriv          A context pointer from the calling function to be
+ *                      passed when calling unifi_fw_read().
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success,
+ *      CSR_WIFI_HIP_RESULT_NO_MEMORY         memory allocation failed
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE         error in XBV file
+ *      CSR_RESULT_FAILURE            SDIO error
+ *
+ *  Notes:
+ *      Stops and resets the chip, does the download and runs the new
+ *      firmware.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_dl_firmware(card_t *card, void *dlpriv)
+{
+    xbv1_t *fwinfo;
+    CsrResult r;
+
+    func_enter();
+
+    fwinfo = CsrMemAlloc(sizeof(xbv1_t));
+    if (fwinfo == NULL)
+    {
+        unifi_error(card->ospriv, "Failed to allocate memory for firmware\n");
+        return CSR_WIFI_HIP_RESULT_NO_MEMORY;
+    }
+
+    /*
+     * Scan the firmware file to find the TLVs we are interested in.
+     * These are:
+     *   - check we support the file format version in VERF
+     *   - SLTP Symbol Lookup Table Pointer
+     *   - FWDL firmware download segments
+     *   - FWOV firmware overlay segment
+     *   - VMEQ Register probe tests to verify matching h/w
+     */
+    r = xbv1_parse(card, unifi_fw_read, dlpriv, fwinfo);
+    if (r != CSR_RESULT_SUCCESS || fwinfo->mode != xbv_firmware)
+    {
+        unifi_error(card->ospriv, "File type is %s, expected firmware.\n",
+                    fwinfo->mode == xbv_patch?"patch" : "unknown");
+        CsrMemFree(fwinfo);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    /* UF6xxx doesn't accept firmware, only patches. Therefore we convert
+     * the file to patch format with version numbers matching the current
+     * running firmware, and then download via the patch mechanism.
+     * The sole purpose of this is to support production test firmware across
+     * different ROM releases, the test firmware being provided in non-patch
+     * format.
+     */
+    if (card->chip_id > SDIO_CARD_ID_UNIFI_2)
+    {
+        unifi_info(card->ospriv, "Must convert f/w to patch format\n");
+        r = do_patch_convert_download(card, dlpriv, fwinfo);
+    }
+    else
+    {
+        /* Older UniFi chips allowed firmware to be directly loaded onto the
+         * chip, which is no longer supported.
+         */
+        unifi_error(card->ospriv, "Only patch downloading supported\n");
+        r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    CsrMemFree(fwinfo);
+    func_exit_r(r);
+    return r;
+} /* unifi_dl_firmware() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_dl_patch
+ *
+ *      Load the given patch set into UniFi.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      dlpriv          The os specific handle to the firmware file.
+ *      boot_ctrl       The address of the boot loader control structure.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success,
+ *      CSR_WIFI_HIP_RESULT_NO_MEMORY         memory allocation failed
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE         error in XBV file
+ *      CSR_RESULT_FAILURE            SDIO error
+ *
+ *  Notes:
+ *      This ends up telling UniFi to restart.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_dl_patch(card_t *card, void *dlpriv, CsrUint32 boot_ctrl)
+{
+    xbv1_t *fwinfo;
+    CsrResult r;
+
+    func_enter();
+
+    unifi_info(card->ospriv, "unifi_dl_patch %p %08x\n", dlpriv, boot_ctrl);
+
+    fwinfo = CsrMemAlloc(sizeof(xbv1_t));
+    if (fwinfo == NULL)
+    {
+        unifi_error(card->ospriv, "Failed to allocate memory for patches\n");
+        func_exit();
+        return CSR_WIFI_HIP_RESULT_NO_MEMORY;
+    }
+
+    /*
+     * Scan the firmware file to find the TLVs we are interested in.
+     * These are:
+     *   - check we support the file format version in VERF
+     *   - FWID The build ID of the ROM that we can patch
+     *   - PTDL patch download segments
+     */
+    r = xbv1_parse(card, unifi_fw_read, dlpriv, fwinfo);
+    if (r != CSR_RESULT_SUCCESS || fwinfo->mode != xbv_patch)
+    {
+        CsrMemFree(fwinfo);
+        unifi_error(card->ospriv, "Failed to read in patch file\n");
+        func_exit();
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    /*
+     * We have to check the build id read from the SLUT against that
+     * for the patch file.  They have to match exactly.
+     *    "card->build_id" == XBV1.PTCH.FWID
+     */
+    if (card->build_id != fwinfo->build_id)
+    {
+        unifi_error(card->ospriv, "Wrong patch file for chip (chip = %lu, file = %lu)\n",
+                    card->build_id, fwinfo->build_id);
+        CsrMemFree(fwinfo);
+#ifndef CSR_WIFI_IGNORE_PATCH_VERSION_MISMATCH
+        func_exit();
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+#else
+        fwinfo = NULL;
+        dlpriv = NULL;
+        return CSR_RESULT_SUCCESS;
+#endif
+    }
+
+    r = do_patch_download(card, dlpriv, fwinfo, boot_ctrl);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to patch image\n");
+    }
+
+    CsrMemFree(fwinfo);
+
+    func_exit_r(r);
+    return r;
+} /* unifi_dl_patch() */
+
+
+void* unifi_dl_fw_read_start(card_t *card, CsrInt8 is_fw)
+{
+    card_info_t card_info;
+
+    unifi_card_info(card, &card_info);
+    unifi_trace(card->ospriv, UDBG5,
+                "id=%d, ver=0x%x, fw_build=%u, fw_hip=0x%x, block_size=%d\n",
+                card_info.chip_id, card_info.chip_version,
+                card_info.fw_build, card_info.fw_hip_version,
+                card_info.sdio_block_size);
+
+    return unifi_fw_read_start(card->ospriv, is_fw, &card_info);
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  safe_read_shared_location
+ *
+ *      Read a shared memory location repeatedly until we get two readings
+ *      the same.
+ *
+ *  Arguments:
+ *      card            Pointer to card context struct.
+ *      unifi_addr      UniFi shared-data-memory address to access.
+ *      pdata           Pointer to a byte variable for the value read.
+ *
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR error code on failure
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult safe_read_shared_location(card_t *card, CsrUint32 address, CsrUint8 *pdata)
+{
+    CsrResult r;
+    CsrUint16 limit = 1000;
+    CsrUint8 b, b2;
+
+    *pdata = 0;
+
+    r = unifi_read_8_or_16(card, address, &b);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        return r;
+    }
+
+    while (limit--)
+    {
+        r = unifi_read_8_or_16(card, address, &b2);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            return r;
+        }
+
+        /* When we have a stable value, return it */
+        if (b == b2)
+        {
+            *pdata = b;
+            return CSR_RESULT_SUCCESS;
+        }
+
+        b = b2;
+    }
+
+    return CSR_RESULT_FAILURE;
+} /* safe_read_shared_location() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_do_loader_op
+ *
+ *      Send a loader / boot_loader command to the UniFi and wait for
+ *      it to complete.
+ *
+ *  Arguments:
+ *      card            Pointer to card context struct.
+ *      op_addr         The address of the loader operation control word.
+ *      opcode          The operation to perform.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS    on success
+ *      CSR_RESULT_FAILURE    SDIO error or SDIO/XAP timeout
+ * ---------------------------------------------------------------------------
+ */
+
+/*
+ * Ideally instead of sleeping, we want to busy wait.
+ * Currently there is no framework API to do this. When it becomes available,
+ * we can use it to busy wait using usecs
+ */
+#define OPERATION_TIMEOUT_LOOPS (100)  /* when OPERATION_TIMEOUT_DELAY==1, (500) otherwise */
+#define OPERATION_TIMEOUT_DELAY 1      /* msec, or 200usecs */
+
+CsrResult unifi_do_loader_op(card_t *card, CsrUint32 op_addr, CsrUint8 opcode)
+{
+    CsrResult r;
+    CsrInt16 op_retries;
+
+    unifi_trace(card->ospriv, UDBG4, "Loader cmd 0x%0x -> 0x%08x\n", opcode, op_addr);
+
+    /* Set the Operation command byte to the opcode */
+    r = unifi_write_8_or_16(card, op_addr, opcode);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to write loader copy command\n");
+        return r;
+    }
+
+    /* Wait for Operation command byte to be Idle */
+    /* Typically takes ~100us */
+    op_retries = 0;
+    r = CSR_RESULT_SUCCESS;
+    while (1)
+    {
+        CsrUint8 op;
+
+        /*
+         * Read the memory location until two successive reads give
+         * the same value.
+         * Then handle it.
+         */
+        r = safe_read_shared_location(card, op_addr, &op);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Failed to read loader status\n");
+            break;
+        }
+
+        if (op == UNIFI_LOADER_IDLE)
+        {
+            /* Success */
+            break;
+        }
+
+        if (op != opcode)
+        {
+            unifi_error(card->ospriv, "Error reported by loader: 0x%X\n", op);
+            r = CSR_RESULT_FAILURE;
+            break;
+        }
+
+        /* Allow 500us timeout */
+        if (++op_retries >= OPERATION_TIMEOUT_LOOPS)
+        {
+            unifi_error(card->ospriv, "Timeout waiting for loader to ack transfer\n");
+            /* Stop XAPs to aid post-mortem */
+            r = unifi_card_stop_processor(card, UNIFI_PROC_BOTH);
+            if (r != CSR_RESULT_SUCCESS)
+            {
+                unifi_error(card->ospriv, "Failed to stop UniFi processors\n");
+            }
+            else
+            {
+                r = CSR_RESULT_FAILURE;
+            }
+            break;
+        }
+        CsrThreadSleep(OPERATION_TIMEOUT_DELAY);
+    } /* Loop exits with r != CSR_RESULT_SUCCESS on error */
+
+    return r;
+}     /* unifi_do_loader_op() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  send_ptdl_to_unifi
+ *
+ *      Copy a patch block from userland to the UniFi.
+ *      This function reads data, 2K at a time, from userland and writes
+ *      it to the UniFi.
+ *
+ *  Arguments:
+ *      card            A pointer to the card structure
+ *      dlpriv          The os specific handle for the firmware file
+ *      ptdl            A pointer ot the PTDL block
+ *      handle          The buffer handle to use for the xfer
+ *      op_addr         The address of the loader operation control word
+ *
+ *  Returns:
+ *      Number of bytes sent (Positive) or negative value indicating
+ *      error code:
+ *      CSR_WIFI_HIP_RESULT_NO_MEMORY         memory allocation failed
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE         error in XBV file
+ *      CSR_RESULT_FAILURE            SDIO error
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult send_ptdl_to_unifi(card_t *card, void *dlpriv,
+                                    const struct PTDL *ptdl, CsrUint32 handle,
+                                    CsrUint32 op_addr)
+{
+    CsrUint32 offset;
+    CsrUint8 *buf;
+    CsrInt32 data_len;
+    CsrUint32 write_len;
+    CsrResult r;
+    const CsrUint16 buf_size = 2 * 1024;
+
+    offset = ptdl->dl_offset;
+    data_len = ptdl->dl_size;
+
+    if (data_len > buf_size)
+    {
+        unifi_error(card->ospriv, "PTDL block is too large (%u)\n",
+                    ptdl->dl_size);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    buf = CsrMemAllocDma(buf_size);
+    if (buf == NULL)
+    {
+        unifi_error(card->ospriv, "Failed to allocate transfer buffer for firmware download\n");
+        return CSR_WIFI_HIP_RESULT_NO_MEMORY;
+    }
+
+    r = CSR_RESULT_SUCCESS;
+
+    if (unifi_fw_read(card->ospriv, dlpriv, offset, buf, data_len) != data_len)
+    {
+        unifi_error(card->ospriv, "Failed to read from file\n");
+    }
+    else
+    {
+        /* We can always round these if the host wants to */
+        if (card->sdio_io_block_pad)
+        {
+            write_len = (data_len + (card->sdio_io_block_size - 1)) &
+                        ~(card->sdio_io_block_size - 1);
+
+            /* Zero out the rest of the buffer (This isn't needed, but it
+             * makes debugging things later much easier). */
+            CsrMemSet(buf + data_len, 0, write_len - data_len);
+        }
+        else
+        {
+            write_len = data_len;
+        }
+
+        r = unifi_bulk_rw_noretry(card, handle, buf, write_len, UNIFI_SDIO_WRITE);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "CMD53 failed writing %d bytes to handle %ld\n",
+                        data_len, handle);
+        }
+        else
+        {
+            /*
+             * Can change the order of things to overlap read from file
+             * with copy to unifi
+             */
+            r = unifi_do_loader_op(card, op_addr, UNIFI_BOOT_LOADER_PATCH);
+        }
+    }
+
+    CsrMemFreeDma(buf);
+
+    if (r != CSR_RESULT_SUCCESS && r != CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        unifi_error(card->ospriv, "Failed to copy block of %u bytes to UniFi\n",
+                    ptdl->dl_size);
+    }
+
+    return r;
+} /* send_ptdl_to_unifi() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  do_patch_download
+ *
+ *      This function downloads a set of patches to UniFi and then
+ *      causes it to restart.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct.
+ *      dlpriv          A context pointer from the calling function to be
+ *                      used when reading the XBV file.  This can be NULL
+ *                      in which case not patches are applied.
+ *      pfwinfo         Pointer to a fwinfo struct describing the f/w
+ *                      XBV file.
+ *      boot_ctrl_addr  The address of the boot loader control structure.
+ *
+ *  Returns:
+ *      0 on success, or an error code
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE for a bad laoader version number
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult do_patch_download(card_t *card, void *dlpriv, xbv1_t *pfwinfo, CsrUint32 boot_ctrl_addr)
+{
+    CsrResult r;
+    CsrInt32 i;
+    CsrUint16 loader_version;
+    CsrUint16 handle;
+    CsrUint32 total_bytes;
+
+    /*
+     * Read info from the SDIO Loader Control Data Structure
+     */
+    /* Check the loader version */
+    r = unifi_card_read16(card, boot_ctrl_addr, &loader_version);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Patch download: Failed to read loader version\n");
+        return r;
+    }
+    unifi_trace(card->ospriv, UDBG2, "Patch download: boot loader version 0x%04X\n", loader_version);
+    switch (loader_version)
+    {
+        case 0x0000:
+            break;
+
+        default:
+            unifi_error(card->ospriv, "Patch loader version (0x%04X) is not supported by this driver\n",
+                        loader_version);
+            return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    /* Retrieve the handle to use with CMD53 */
+    r = unifi_card_read16(card, boot_ctrl_addr + 4, &handle);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Patch download: Failed to read loader handle\n");
+        return r;
+    }
+
+    /* Set the mask of LEDs to flash */
+    if (card->loader_led_mask)
+    {
+        r = unifi_card_write16(card, boot_ctrl_addr + 2,
+                               (CsrUint16)card->loader_led_mask);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Patch download: Failed to write LED mask\n");
+            return r;
+        }
+    }
+
+    total_bytes = 0;
+
+    /* Copy download data to UniFi memory */
+    for (i = 0; i < pfwinfo->num_ptdl; i++)
+    {
+        unifi_trace(card->ospriv, UDBG3, "Patch download: %d Downloading for %d from offset %d\n",
+                    i,
+                    pfwinfo->ptdl[i].dl_size,
+                    pfwinfo->ptdl[i].dl_offset);
+
+        r = send_ptdl_to_unifi(card, dlpriv, &pfwinfo->ptdl[i],
+                               handle, boot_ctrl_addr + 6);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            return r;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Patch failed after %u bytes\n",
+                        total_bytes);
+            return r;
+        }
+        total_bytes += pfwinfo->ptdl[i].dl_size;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* do_patch_download() */
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_dump.c b/drivers/staging/csr/csr_wifi_hip_dump.c
new file mode 100644
index 0000000..5297f10
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_dump.c
@@ -0,0 +1,872 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ * FILE: csr_wifi_hip_dump.c
+ *
+ * PURPOSE:
+ *      Routines for retrieving and buffering core status from the UniFi
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_unifiversion.h"
+#include "csr_wifi_hip_card.h"
+
+/* Locations to capture in dump (XAP words) */
+#define HIP_CDUMP_FIRST_CPUREG      (0xFFE0) /* First CPU register */
+#define HIP_CDUMP_FIRST_LO          (0)      /* Start of low address range */
+#define HIP_CDUMP_FIRST_HI_MAC      (0x3C00) /* Start of MAC high area */
+#define HIP_CDUMP_FIRST_HI_PHY      (0x1C00) /* Start of PHY high area */
+#define HIP_CDUMP_FIRST_SH          (0)      /* Start of shared memory area */
+
+#define HIP_CDUMP_NCPUREGS    (10)           /* No. of 16-bit XAP registers */
+#define HIP_CDUMP_NWORDS_LO   (0x0100)       /* Low area size in 16-bit words */
+#define HIP_CDUMP_NWORDS_HI   (0x0400)       /* High area size in 16-bit words */
+#define HIP_CDUMP_NWORDS_SH   (0x0500)       /* Shared memory area size, 16-bit words */
+
+#define HIP_CDUMP_NUM_ZONES 7                /* Number of UniFi memory areas to capture */
+
+/* Mini-coredump state */
+typedef struct coredump_buf
+{
+    CsrUint16  count;                       /* serial number of dump */
+    CsrTime    timestamp;                   /* host's system time at capture */
+    CsrInt16   requestor;                   /* request: 0=auto dump, 1=manual */
+    CsrUint16  chip_ver;
+    CsrUint32  fw_ver;
+    CsrUint16 *zone[HIP_CDUMP_NUM_ZONES];
+
+    struct coredump_buf *next;              /* circular list */
+    struct coredump_buf *prev;              /* circular list */
+} coredump_buffer;
+
+/* Structure used to describe a zone of chip memory captured by mini-coredump */
+struct coredump_zone
+{
+    unifi_coredump_space_t           space;  /* XAP memory space this zone covers */
+    enum unifi_dbg_processors_select cpu;    /* XAP CPU core selector */
+    CsrUint32                        gp;     /* Generic Pointer to memory zone on XAP */
+    CsrUint16                        offset; /* 16-bit XAP word offset of zone in memory space */
+    CsrUint16                        length; /* Length of zone in XAP words */
+};
+
+static CsrResult unifi_coredump_from_sdio(card_t *card, coredump_buffer *dump_buf);
+static CsrResult unifi_coredump_read_zones(card_t *card, coredump_buffer *dump_buf);
+static CsrResult unifi_coredump_read_zone(card_t *card, CsrUint16 *zone,
+                                          const struct coredump_zone *def);
+static CsrInt32 get_value_from_coredump(const coredump_buffer *dump,
+                                        const unifi_coredump_space_t space, const CsrUint16 offset);
+
+/* Table of chip memory zones we capture on mini-coredump */
+static const struct coredump_zone zonedef_table[HIP_CDUMP_NUM_ZONES] = {
+    { UNIFI_COREDUMP_MAC_REG,  UNIFI_PROC_MAC, UNIFI_MAKE_GP(REGISTERS, HIP_CDUMP_FIRST_CPUREG * 2), HIP_CDUMP_FIRST_CPUREG, HIP_CDUMP_NCPUREGS },
+    { UNIFI_COREDUMP_PHY_REG,  UNIFI_PROC_PHY, UNIFI_MAKE_GP(REGISTERS, HIP_CDUMP_FIRST_CPUREG * 2), HIP_CDUMP_FIRST_CPUREG, HIP_CDUMP_NCPUREGS },
+    { UNIFI_COREDUMP_SH_DMEM,  UNIFI_PROC_INVALID, UNIFI_MAKE_GP(SH_DMEM, HIP_CDUMP_FIRST_SH * 2),   HIP_CDUMP_FIRST_SH,     HIP_CDUMP_NWORDS_SH },
+    { UNIFI_COREDUMP_MAC_DMEM, UNIFI_PROC_MAC, UNIFI_MAKE_GP(MAC_DMEM, HIP_CDUMP_FIRST_LO * 2),      HIP_CDUMP_FIRST_LO,     HIP_CDUMP_NWORDS_LO },
+    { UNIFI_COREDUMP_MAC_DMEM, UNIFI_PROC_MAC, UNIFI_MAKE_GP(MAC_DMEM, HIP_CDUMP_FIRST_HI_MAC * 2),  HIP_CDUMP_FIRST_HI_MAC, HIP_CDUMP_NWORDS_HI },
+    { UNIFI_COREDUMP_PHY_DMEM, UNIFI_PROC_PHY, UNIFI_MAKE_GP(PHY_DMEM, HIP_CDUMP_FIRST_LO * 2),      HIP_CDUMP_FIRST_LO,     HIP_CDUMP_NWORDS_LO },
+    { UNIFI_COREDUMP_PHY_DMEM, UNIFI_PROC_PHY, UNIFI_MAKE_GP(PHY_DMEM, HIP_CDUMP_FIRST_HI_PHY * 2),  HIP_CDUMP_FIRST_HI_PHY, HIP_CDUMP_NWORDS_HI },
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_coredump_request_at_next_reset
+ *
+ *      Request that a mini-coredump is performed when the driver has
+ *      completed resetting the UniFi device.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      enable          If non-zero, sets the request.
+ *                      If zero, cancels any pending request.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS or CSR HIP error code
+ *
+ *  Notes:
+ *      This function is typically called once the driver has detected that
+ *      the UniFi device has become unresponsive due to crash, or internal
+ *      watchdog reset. The driver must reset it to regain communication and,
+ *      immediately after that, the mini-coredump can be captured.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_coredump_request_at_next_reset(card_t *card, CsrInt8 enable)
+{
+    CsrResult r;
+
+    func_enter();
+
+    if (enable)
+    {
+        unifi_trace(card->ospriv, UDBG2, "Mini-coredump requested after reset\n");
+    }
+
+    if (card == NULL)
+    {
+        r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+    else
+    {
+        card->request_coredump_on_reset = enable?1 : 0;
+        r = CSR_RESULT_SUCCESS;
+    }
+
+    func_exit_r(r);
+    return r;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_coredump_handle_request
+ *
+ *      Performs a coredump now, if one was requested, and clears the request.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS or CSR HIP error code
+ *
+ *  Notes:
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_coredump_handle_request(card_t *card)
+{
+    CsrResult r = CSR_RESULT_SUCCESS;
+
+    func_enter();
+
+    if (card == NULL)
+    {
+        r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+    else
+    {
+        if (card->request_coredump_on_reset == 1)
+        {
+            card->request_coredump_on_reset = 0;
+            r = unifi_coredump_capture(card, NULL);
+        }
+    }
+
+    func_exit_r(r);
+    return r;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_coredump_capture
+ *
+ *      Capture the current status of the UniFi device.
+ *      Various registers are buffered for future offline inspection.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      req             Pointer to request struct, or NULL:
+ *                          A coredump requested manually by the user app
+ *                          will have a request struct pointer, an automatic
+ *                          coredump will have a NULL pointer.
+ *  Returns:
+ *      CSR_RESULT_SUCCESS  on success,
+ *      CSR_RESULT_FAILURE  SDIO error
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE  Initialisation not complete
+ *
+ *  Notes:
+ *      The result is a filled entry in the circular buffer of core dumps,
+ *      values from which can be extracted to userland via an ioctl.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_coredump_capture(card_t *card, struct unifi_coredump_req *req)
+{
+    CsrResult r = CSR_RESULT_SUCCESS;
+    static CsrUint16 dump_seq_no = 1;
+    CsrTime time_of_capture;
+
+    func_enter();
+
+    if (card->dump_next_write == NULL)
+    {
+        r = CSR_RESULT_SUCCESS;
+        goto done;
+    }
+
+    /* Reject forced capture before initialisation has happened */
+    if (card->helper == NULL)
+    {
+        r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+        goto done;
+    }
+
+
+    /*
+     * Force a mini-coredump capture right now
+     */
+    time_of_capture = CsrTimeGet(NULL);
+    unifi_info(card->ospriv, "Mini-coredump capture at t=%u\n", time_of_capture);
+
+    /* Wake up the processors so we can talk to them */
+    r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to wake UniFi\n");
+        goto done;
+    }
+    CsrThreadSleep(20);
+
+    /* Stop both XAPs */
+    unifi_trace(card->ospriv, UDBG4, "Stopping XAPs for coredump capture\n");
+    r = unifi_card_stop_processor(card, UNIFI_PROC_BOTH);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to stop UniFi XAPs\n");
+        goto done;
+    }
+
+    /* Dump core into the next available slot in the circular list */
+    r = unifi_coredump_from_sdio(card, card->dump_next_write);
+    if (r == CSR_RESULT_SUCCESS)
+    {
+        /* Record whether the dump was manual or automatic */
+        card->dump_next_write->requestor = (req?1 : 0);
+        card->dump_next_write->timestamp = time_of_capture;
+        /* Advance to the next buffer */
+        card->dump_next_write->count = dump_seq_no++;
+        card->dump_cur_read = card->dump_next_write;
+        card->dump_next_write = card->dump_next_write->next;
+
+        /* Sequence no. of zero indicates slot not in use, so handle wrap */
+        if (dump_seq_no == 0)
+        {
+            dump_seq_no = 1;
+        }
+
+        unifi_trace(card->ospriv, UDBG3,
+                    "Coredump (%p), SeqNo=%d, cur_read=%p, next_write=%p\n",
+                    req,
+                    card->dump_cur_read->count,
+                    card->dump_cur_read, card->dump_next_write);
+    }
+
+    /* Start both XAPs */
+    unifi_trace(card->ospriv, UDBG4, "Restart XAPs after coredump\n");
+    r = card_start_processor(card, UNIFI_PROC_BOTH);
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Failed to start UniFi XAPs\n");
+        goto done;
+    }
+
+done:
+    func_exit_r(r);
+    return r;
+} /* unifi_coredump_capture() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  get_value_from_coredump
+ *
+ *
+ *
+ *  Arguments:
+ *      dump                Pointer to buffered coredump data
+ *      offset_in_space     XAP memory space to retrieve from the buffer (there
+ *                          may be more than one zone covering the same memory
+ *                          space, but starting from different offsets).
+ *      offset              Offset within the XAP memory space to be retrieved
+ *
+ *  Returns:
+ *      >=0                  Register value on success
+ *      <0                   Register out of range of any captured zones
+ *
+ *  Notes:
+ * ---------------------------------------------------------------------------
+ */
+static CsrInt32 get_value_from_coredump(const coredump_buffer       *coreDump,
+                                        const unifi_coredump_space_t space,
+                                        const CsrUint16              offset_in_space)
+{
+    CsrInt32 r = -1;
+    CsrUint16 offset_in_zone;
+    CsrUint32 zone_end_offset;
+    CsrInt32 i;
+    const struct coredump_zone *def = &zonedef_table[0];
+
+    /* Search zone def table for a match with the requested memory space */
+    for (i = 0; i < HIP_CDUMP_NUM_ZONES; i++, def++)
+    {
+        if (space == def->space)
+        {
+            zone_end_offset = def->offset + def->length;
+
+            /* Is the space offset contained in this zone? */
+            if (offset_in_space < zone_end_offset &&
+                offset_in_space >= def->offset)
+            {
+                /* Calculate the offset of data within the zone buffer */
+                offset_in_zone = offset_in_space - def->offset;
+                r = (CsrInt32) * (coreDump->zone[i] + offset_in_zone);
+
+                unifi_trace(NULL, UDBG6,
+                            "sp %d, offs 0x%04x = 0x%04x (in z%d 0x%04x->0x%04x)\n",
+                            space, offset_in_space, r,
+                            i, def->offset, zone_end_offset - 1);
+                break;
+            }
+        }
+    }
+    return r;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_coredump_get_value
+ *
+ *      Retrieve the value of a register buffered from a previous core dump,
+ *      so that it may be reported back to application code.
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      req_reg         Pointer to request parameter partially filled. This
+ *                      function puts in the values retrieved from the dump.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, or:
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE         Null parameter error
+ *      CSR_WIFI_HIP_RESULT_RANGE                 Register out of range
+ *      CSR_WIFI_HIP_RESULT_NOT_FOUND             Dump index not (yet) captured
+ *
+ *  Notes:
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_coredump_get_value(card_t *card, struct unifi_coredump_req *req)
+{
+    CsrResult r;
+    CsrInt32 i = 0;
+    coredump_buffer *find_dump = NULL;
+
+    func_enter();
+
+    if (req == NULL || card == NULL)
+    {
+        r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+        goto done;
+    }
+    req->value = -1;
+    if (card->dump_buf == NULL)
+    {
+        unifi_trace(card->ospriv, UDBG2, "No coredump buffers\n");
+        r = CSR_WIFI_HIP_RESULT_NOT_FOUND;     /* Coredumping disabled */
+        goto done;
+    }
+    if (card->dump_cur_read == NULL)
+    {
+        unifi_trace(card->ospriv, UDBG4, "No coredumps captured\n");
+        r = CSR_WIFI_HIP_RESULT_NOT_FOUND;     /* No coredump yet captured */
+        goto done;
+    }
+
+    /* Find the requested dump buffer */
+    switch (req->index)
+    {
+        case 0:     /* Newest */
+            find_dump = card->dump_cur_read;
+            break;
+        case -1:    /* Oldest: The next used slot forward */
+            for (find_dump = card->dump_cur_read->next;
+                 (find_dump->count == 0) && (find_dump != card->dump_cur_read);
+                 find_dump = card->dump_cur_read->next)
+            {
+            }
+            break;
+        default:    /* Number of steps back from current read position */
+            for (i = 0, find_dump = card->dump_cur_read;
+                 i < req->index;
+                 i++, find_dump = find_dump->prev)
+            {
+                /* Walk the list for the index'th entry, but
+                 * stop when about to wrap. */
+                unifi_trace(card->ospriv, UDBG6,
+                            "%d: %d, @%p, p=%p, n=%p, cr=%p, h=%p\n",
+                            i, find_dump->count, find_dump, find_dump->prev,
+                            find_dump->next, card->dump_cur_read, card->dump_buf);
+                if (find_dump->prev == card->dump_cur_read)
+                {
+                    /* Wrapped but still not found, index out of range */
+                    if (i != req->index)
+                    {
+                        unifi_trace(card->ospriv, UDBG6,
+                                    "Dump index %d not found %d\n", req->index, i);
+                        r = CSR_WIFI_HIP_RESULT_NOT_FOUND;
+                        goto done;
+                    }
+                    break;
+                }
+            }
+            break;
+    }
+
+    /* Check if the slot is actually filled with a core dump */
+    if (find_dump->count == 0)
+    {
+        unifi_trace(card->ospriv, UDBG4, "Not captured %d\n", req->index);
+        r = CSR_WIFI_HIP_RESULT_NOT_FOUND;
+        goto done;
+    }
+
+    unifi_trace(card->ospriv, UDBG6, "Req index %d, found seq %d at step %d\n",
+                req->index, find_dump->count, i);
+
+    /* Find the appropriate entry in the buffer */
+    req->value = get_value_from_coredump(find_dump, req->space, (CsrUint16)req->offset);
+    if (req->value < 0)
+    {
+        r = CSR_WIFI_HIP_RESULT_RANGE;     /* Un-captured register */
+        unifi_trace(card->ospriv, UDBG4,
+                    "Can't read space %d, reg 0x%x from coredump buffer %d\n",
+                    req->space, req->offset, req->index);
+    }
+    else
+    {
+        r = CSR_RESULT_SUCCESS;
+    }
+
+    /* Update the private request structure with the found values */
+    req->chip_ver = find_dump->chip_ver;
+    req->fw_ver = find_dump->fw_ver;
+    req->timestamp = find_dump->timestamp;
+    req->requestor = find_dump->requestor;
+    req->serial = find_dump->count;
+
+done:
+    func_exit_r(r);
+    return r;
+} /* unifi_coredump_get_value() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_coredump_read_zone
+ *
+ *      Captures a UniFi memory zone into a buffer on the host
+ *
+ *  Arguments:
+ *      card          Pointer to card struct
+ *      zonebuf       Pointer to on-host buffer to dump the memory zone into
+ *      def           Pointer to description of the memory zone to read from UniFi.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS                   on success, or:
+ *      CSR_RESULT_FAILURE                   SDIO error
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE         Parameter error
+ *
+ *  Notes:
+ *      It is assumed that the caller has already stopped the XAPs
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult unifi_coredump_read_zone(card_t *card, CsrUint16 *zonebuf, const struct coredump_zone *def)
+{
+    CsrResult r;
+
+    func_enter();
+
+    if (zonebuf == NULL || def == NULL)
+    {
+        r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+        goto done;
+    }
+
+    /* Select XAP CPU if necessary */
+    if (def->cpu != UNIFI_PROC_INVALID)
+    {
+        if (def->cpu != UNIFI_PROC_MAC && def->cpu != UNIFI_PROC_PHY)
+        {
+            r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            goto done;
+        }
+        r = unifi_set_proc_select(card, def->cpu);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            goto done;
+        }
+    }
+
+    unifi_trace(card->ospriv, UDBG4,
+                "Dump sp %d, offs 0x%04x, 0x%04x words @GP=%08x CPU %d\n",
+                def->space, def->offset, def->length, def->gp, def->cpu);
+
+    /* Read on-chip RAM (byte-wise) */
+    r = unifi_card_readn(card, def->gp, zonebuf, (CsrUint16)(def->length * 2));
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        goto done;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Can't read UniFi shared data area\n");
+        goto done;
+    }
+
+done:
+    func_exit_r(r);
+    return r;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_coredump_read_zones
+ *
+ *      Walks through the table of on-chip memory zones defined in zonedef_table,
+ *      and reads each of them from the UniFi chip
+ *
+ *  Arguments:
+ *      card          Pointer to card struct
+ *      dump_buf      Buffer into which register values will be dumped
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS                   on success, or:
+ *      CSR_RESULT_FAILURE                   SDIO error
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE         Parameter error
+ *
+ *  Notes:
+ *      It is assumed that the caller has already stopped the XAPs
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult unifi_coredump_read_zones(card_t *card, coredump_buffer *dump_buf)
+{
+    CsrResult r = CSR_RESULT_SUCCESS;
+    CsrInt32 i;
+
+    func_enter();
+
+    /* Walk the table of coredump zone definitions and read them from the chip */
+    for (i = 0;
+         (i < HIP_CDUMP_NUM_ZONES) && (r == 0);
+         i++)
+    {
+        r = unifi_coredump_read_zone(card, dump_buf->zone[i], &zonedef_table[i]);
+    }
+
+    func_exit_r(r);
+    return r;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_coredump_from_sdio
+ *
+ *      Capture the status of the UniFi processors, over SDIO
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *      reg_buffer      Buffer into which register values will be dumped
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS                   on success, or:
+ *      CSR_RESULT_FAILURE                   SDIO error
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE         Parameter error
+ *
+ *  Notes:
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult unifi_coredump_from_sdio(card_t *card, coredump_buffer *dump_buf)
+{
+    CsrUint16 val;
+    CsrResult r;
+    CsrUint32 sdio_addr;
+
+    func_enter();
+
+    if (dump_buf == NULL)
+    {
+        r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+        goto done;
+    }
+
+
+    /* Chip and firmware version */
+    unifi_trace(card->ospriv, UDBG4, "Get chip version\n");
+    sdio_addr = 2 * ChipHelper_GBL_CHIP_VERSION(card->helper);
+    if (sdio_addr != 0)
+    {
+        r = unifi_read_direct16(card, sdio_addr, &val);
+        if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+        {
+            goto done;
+        }
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "Can't read GBL_CHIP_VERSION\n");
+            goto done;
+        }
+    }
+    dump_buf->chip_ver = val;
+    dump_buf->fw_ver = card->build_id;
+
+    unifi_trace(card->ospriv, UDBG4, "chip_ver 0x%04x, fw_ver %u\n",
+                dump_buf->chip_ver, dump_buf->fw_ver);
+
+    /* Capture the memory zones required from UniFi */
+    r = unifi_coredump_read_zones(card, dump_buf);
+    if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
+    {
+        goto done;
+    }
+    if (r != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(card->ospriv, "Can't read UniFi memory areas\n");
+        goto done;
+    }
+
+done:
+    func_exit_r(r);
+    return r;
+} /* unifi_coredump_from_sdio() */
+
+
+#ifndef UNIFI_DISABLE_COREDUMP
+/*
+ * ---------------------------------------------------------------------------
+ *  new_coredump_node
+ *
+ *      Allocates a coredump linked-list node, and links it to the previous.
+ *
+ *  Arguments:
+ *      ospriv          OS context
+ *      prevnode        Previous node to link into
+ *
+ *  Returns:
+ *      Pointer to valid coredump_buffer on success
+ *      NULL on memory allocation failure
+ *
+ *  Notes:
+ *      Allocates "all or nothing"
+ * ---------------------------------------------------------------------------
+ */
+static
+coredump_buffer* new_coredump_node(void *ospriv, coredump_buffer *prevnode)
+{
+    coredump_buffer *newnode = NULL;
+    CsrUint16 *newzone = NULL;
+    CsrInt32 i;
+    CsrUint32 zone_size;
+
+    /* Allocate node header */
+    newnode = (coredump_buffer *)CsrMemAlloc(sizeof(coredump_buffer));
+    if (newnode == NULL)
+    {
+        return NULL;
+    }
+    CsrMemSet(newnode, 0, sizeof(coredump_buffer));
+
+    /* Allocate chip memory zone capture buffers */
+    for (i = 0; i < HIP_CDUMP_NUM_ZONES; i++)
+    {
+        zone_size = sizeof(CsrUint16) * zonedef_table[i].length;
+        newzone = (CsrUint16 *)CsrMemAlloc(zone_size);
+        newnode->zone[i] = newzone;
+        if (newzone != NULL)
+        {
+            CsrMemSet(newzone, 0, zone_size);
+        }
+        else
+        {
+            unifi_error(ospriv, "Out of memory on coredump zone %d (%d words)\n",
+                        i, zonedef_table[i].length);
+            break;
+        }
+    }
+
+    /* Clean up if any zone alloc failed */
+    if (newzone == NULL)
+    {
+        for (i = 0; newnode->zone[i] != NULL; i++)
+        {
+            CsrMemFree(newnode->zone[i]);
+            newnode->zone[i] = NULL;
+        }
+    }
+
+    /* Link to previous node */
+    newnode->prev = prevnode;
+    if (prevnode)
+    {
+        prevnode->next = newnode;
+    }
+    newnode->next = NULL;
+
+    return newnode;
+}
+
+
+#endif /* UNIFI_DISABLE_COREDUMP */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_coredump_init
+ *
+ *      Allocates buffers for the automatic SDIO core dump
+ *
+ *  Arguments:
+ *      card                Pointer to card struct
+ *      num_dump_buffers    Number of buffers to reserve for coredumps
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS               on success, or:
+ *      CSR_WIFI_HIP_RESULT_NO_MEMORY         memory allocation failed
+ *
+ *  Notes:
+ *      Allocates space in advance, to be used for the last n coredump buffers
+ *      the intention being that the size is sufficient for at least one dump,
+ *      probably several.
+ *      It's probably advisable to have at least 2 coredump buffers to allow
+ *      one to be enquired with the unifi_coredump tool, while leaving another
+ *      free for capturing.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_coredump_init(card_t *card, CsrUint16 num_dump_buffers)
+{
+#ifndef UNIFI_DISABLE_COREDUMP
+    void *ospriv = card->ospriv;
+    coredump_buffer *prev = NULL;
+    coredump_buffer *newnode = NULL;
+    CsrUint32 i = 0;
+#endif
+
+    func_enter();
+
+    card->request_coredump_on_reset = 0;
+    card->dump_next_write = NULL;
+    card->dump_cur_read = NULL;
+    card->dump_buf = NULL;
+
+#ifndef UNIFI_DISABLE_COREDUMP
+    unifi_trace(ospriv, UDBG1,
+                "Allocate buffers for %d core dumps\n", num_dump_buffers);
+    if (num_dump_buffers == 0)
+    {
+        goto done;
+    }
+
+    /* Root node */
+    card->dump_buf = new_coredump_node(ospriv, NULL);
+    if (card->dump_buf == NULL)
+    {
+        goto fail;
+    }
+    prev = card->dump_buf;
+    newnode = card->dump_buf;
+
+    /* Add each subsequent node at tail */
+    for (i = 1; i < num_dump_buffers; i++)
+    {
+        newnode = new_coredump_node(ospriv, prev);
+        if (newnode == NULL)
+        {
+            goto fail;
+        }
+        prev = newnode;
+    }
+
+    /* Link the first and last nodes to make the list circular */
+    card->dump_buf->prev = newnode;
+    newnode->next = card->dump_buf;
+
+    /* Set initial r/w access pointers */
+    card->dump_next_write = card->dump_buf;
+    card->dump_cur_read = NULL;
+
+    unifi_trace(ospriv, UDBG2, "Core dump configured (%d dumps max)\n", i);
+
+done:
+#endif
+    func_exit();
+    return CSR_RESULT_SUCCESS;
+
+#ifndef UNIFI_DISABLE_COREDUMP
+fail:
+    /* Unwind what we allocated so far */
+    unifi_error(ospriv, "Out of memory allocating core dump node %d\n", i);
+    unifi_coredump_free(card);
+    func_exit();
+    return CSR_WIFI_HIP_RESULT_NO_MEMORY;
+#endif
+} /* unifi_coreump_init() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_coredump_free
+ *
+ *      Free all memory dynamically allocated for core dump
+ *
+ *  Arguments:
+ *      card            Pointer to card struct
+ *
+ *  Returns:
+ *      None
+ *
+ *  Notes:
+ * ---------------------------------------------------------------------------
+ */
+void unifi_coredump_free(card_t *card)
+{
+    void *ospriv = card->ospriv;
+    coredump_buffer *node, *del_node;
+    CsrInt16 i = 0;
+    CsrInt16 j;
+
+    func_enter();
+    unifi_trace(ospriv, UDBG2, "Core dump de-configured\n");
+
+    if (card->dump_buf == NULL)
+    {
+        return;
+    }
+
+    node = card->dump_buf;
+    do
+    {
+        /* Free payload zones */
+        for (j = 0; j < HIP_CDUMP_NUM_ZONES; j++)
+        {
+            if (node->zone[j] != NULL)
+            {
+                CsrMemFree(node->zone[j]);
+                node->zone[j] = NULL;
+            }
+        }
+
+        /* Detach */
+        del_node = node;
+        node = node->next;
+
+        /* Free header */
+        CsrMemFree(del_node);
+        i++;
+    } while ((node != NULL) && (node != card->dump_buf));
+
+    unifi_trace(ospriv, UDBG3, "Freed %d coredump buffers\n", i);
+
+    card->dump_buf = NULL;
+    card->dump_next_write = NULL;
+    card->dump_cur_read = NULL;
+
+    func_exit();
+} /* unifi_coredump_free() */
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_packing.c b/drivers/staging/csr/csr_wifi_hip_packing.c
new file mode 100644
index 0000000..4e98da9
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_packing.c
@@ -0,0 +1,4804 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_wifi_hip_signals.h"
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_conversions.h"
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  get_packed_struct_size
+ *
+ *      Examine a buffer containing a UniFi signal in wire-format.
+ *      The first two bytes contain the signal ID, decode the signal ID and
+ *      return the size, in  bytes, of the signal, not including any bulk
+ *      data.
+ *
+ *      WARNING: This function is auto-generated, DO NOT EDIT!
+ *
+ *  Arguments:
+ *      buf     Pointer to buffer to decode.
+ *
+ *  Returns:
+ *      0 if the signal ID is not recognised (i.e. zero length),
+ *      otherwise the number of bytes occupied by the signal in the buffer.
+ *      This is useful for stepping past the signal to the object in the buffer.
+ * ---------------------------------------------------------------------------
+ */
+CsrInt32 get_packed_struct_size(const CsrUint8 *buf)
+{
+    CsrInt32 size = 0;
+    CsrUint16 sig_id;
+
+    sig_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(buf);
+
+    size += SIZEOF_UINT16;
+    size += SIZEOF_UINT16;
+    size += SIZEOF_UINT16;
+    switch (sig_id)
+    {
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_DEBUG_WORD16_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+        case CSR_DEBUG_GENERIC_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+        case CSR_MA_PACKET_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT64;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+        case CSR_MLME_SET_TIM_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECTED_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_TRIGGERED_GET_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT32;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            break;
+#endif
+        case CSR_DEBUG_GENERIC_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CANCEL_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT32;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MLME_SET_TIM_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_DEBUG_GENERIC_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+        case CSR_MA_PACKET_CANCEL_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT32;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_PACKET_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT32;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_VIF_AVAILABILITY_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLACKOUT_ENDED_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_DONE_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_LOSS_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            break;
+#endif
+        case CSR_MA_VIF_AVAILABILITY_RESPONSE_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT32;
+            size += SIZEOF_UINT32;
+            size += SIZEOF_UINT32;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT32;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 32 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_PACKET_ERROR_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT32;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT32;
+            size += SIZEOF_UINT32;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_DEBUG_STRING_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLOCKACK_ERROR_INDICATION_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += 48 / 8;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_PACKET_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT32;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_CONFIRM_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_REQUEST_ID:
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            size += SIZEOF_UINT16;
+            break;
+#endif
+        default:
+            size = 0;
+    }
+    return size;
+} /* get_packed_struct_size() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  read_unpack_signal
+ *
+ *      Unpack a wire-format signal into a host-native structure.
+ *      This function handles any necessary conversions for endianness and
+ *      places no restrictions on packing or alignment for the structure
+ *      definition.
+ *
+ *      WARNING: This function is auto-generated, DO NOT EDIT!
+ *
+ *  Arguments:
+ *      ptr             Signal buffer to unpack.
+ *      sig             Pointer to destination structure to populate.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success,
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE if the ID of signal was not recognised.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult read_unpack_signal(const CsrUint8 *ptr, CSR_SIGNAL *sig)
+{
+    CsrInt32 index = 0;
+
+    sig->SignalPrimitiveHeader.SignalId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+    index += SIZEOF_UINT16;
+
+    sig->SignalPrimitiveHeader.ReceiverProcessId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+    index += SIZEOF_UINT16;
+
+    sig->SignalPrimitiveHeader.SenderProcessId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+    index += SIZEOF_UINT16;
+
+    switch (sig->SignalPrimitiveHeader.SignalId)
+    {
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_CONFIRM_ID:
+            sig->u.MlmeSetPacketFilterConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetPacketFilterConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetPacketFilterConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetPacketFilterConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetPacketFilterConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetPacketFilterConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_CONFIRM_ID:
+            sig->u.MlmeSetkeysConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_CONFIRM_ID:
+            sig->u.MlmeConfigQueueConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM_ID:
+            sig->u.MlmeAddAutonomousScanConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanConfirm.AutonomousScanId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_CONFIRM_ID:
+            sig->u.MlmeAddBlackoutConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutConfirm.BlackoutId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_REQUEST_ID:
+            sig->u.MlmeDelBlackoutRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelBlackoutRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelBlackoutRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelBlackoutRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelBlackoutRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelBlackoutRequest.BlackoutId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_CONFIRM_ID:
+            sig->u.MlmeGetKeySequenceConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[0] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[1] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[2] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[3] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[4] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[5] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[6] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[7] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_CONFIRM_ID:
+            sig->u.MlmeSmStartConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_CONFIRM_ID:
+            sig->u.MlmeStopAggregationConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopAggregationConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopAggregationConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopAggregationConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopAggregationConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeStopAggregationConfirm.PeerQstaAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeStopAggregationConfirm.UserPriority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopAggregationConfirm.Direction = (CSR_DIRECTION) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopAggregationConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_REQUEST_ID:
+            sig->u.MlmeDelTspecRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecRequest.UserPriority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecRequest.Direction = (CSR_DIRECTION) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_DEBUG_WORD16_INDICATION_ID:
+            sig->u.DebugWord16Indication.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[0] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[1] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[2] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[3] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[4] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[5] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[6] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[7] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[8] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[9] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[10] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[11] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[12] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[13] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[14] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugWord16Indication.DebugWords[15] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+        case CSR_DEBUG_GENERIC_CONFIRM_ID:
+            sig->u.DebugGenericConfirm.DebugVariable.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericConfirm.DebugVariable.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericConfirm.DebugWords[0] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericConfirm.DebugWords[1] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericConfirm.DebugWords[2] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericConfirm.DebugWords[3] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericConfirm.DebugWords[4] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericConfirm.DebugWords[5] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericConfirm.DebugWords[6] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericConfirm.DebugWords[7] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+        case CSR_MA_PACKET_INDICATION_ID:
+            sig->u.MaPacketIndication.Data.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketIndication.Data.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketIndication.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MaPacketIndication.LocalTime.x, &ptr[index], 64 / 8);
+            index += 64 / 8;
+            sig->u.MaPacketIndication.Ifindex = (CSR_IFINTERFACE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketIndication.Channel = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketIndication.ReceptionStatus = (CSR_RECEPTION_STATUS) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketIndication.Rssi = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketIndication.Snr = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketIndication.ReceivedRate = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+        case CSR_MLME_SET_TIM_REQUEST_ID:
+            sig->u.MlmeSetTimRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetTimRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetTimRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetTimRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetTimRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetTimRequest.AssociationId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetTimRequest.TimValue = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECTED_INDICATION_ID:
+            sig->u.MlmeConnectedIndication.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectedIndication.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectedIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectedIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectedIndication.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectedIndication.ConnectionStatus = (CSR_CONNECTION_STATUS) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeConnectedIndication.PeerMacAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_REQUEST_ID:
+            sig->u.MlmeDelRxTriggerRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelRxTriggerRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelRxTriggerRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelRxTriggerRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelRxTriggerRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelRxTriggerRequest.TriggerId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_TRIGGERED_GET_INDICATION_ID:
+            sig->u.MlmeTriggeredGetIndication.MibAttributeValue.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeTriggeredGetIndication.MibAttributeValue.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeTriggeredGetIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeTriggeredGetIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeTriggeredGetIndication.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeTriggeredGetIndication.Status = (CSR_MIB_STATUS) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeTriggeredGetIndication.ErrorIndex = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeTriggeredGetIndication.TriggeredId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_REQUEST_ID:
+            sig->u.MlmeScanRequest.ChannelList.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanRequest.ChannelList.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanRequest.InformationElements.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanRequest.InformationElements.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanRequest.Ifindex = (CSR_IFINTERFACE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanRequest.ScanType = (CSR_SCAN_TYPE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanRequest.ProbeDelay = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            sig->u.MlmeScanRequest.MinChannelTime = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanRequest.MaxChannelTime = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_CONFIRM_ID:
+            sig->u.MlmeDeletekeysConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDeletekeysConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDeletekeysConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDeletekeysConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDeletekeysConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDeletekeysConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_REQUEST_ID:
+            sig->u.MlmeGetNextRequest.MibAttribute.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetNextRequest.MibAttribute.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetNextRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetNextRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_CONFIRM_ID:
+            sig->u.MlmeSetChannelConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_REQUEST_ID:
+            sig->u.MlmeStartAggregationRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeStartAggregationRequest.PeerQstaAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeStartAggregationRequest.UserPriority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationRequest.Direction = (CSR_DIRECTION) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationRequest.StartingSequenceNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationRequest.BufferSize = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationRequest.BlockAckTimeout = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_REQUEST_ID:
+            sig->u.MlmeHlSyncRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeHlSyncRequest.GroupAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+        case CSR_DEBUG_GENERIC_REQUEST_ID:
+            sig->u.DebugGenericRequest.DebugVariable.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericRequest.DebugVariable.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericRequest.DebugWords[0] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericRequest.DebugWords[1] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericRequest.DebugWords[2] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericRequest.DebugWords[3] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericRequest.DebugWords[4] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericRequest.DebugWords[5] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericRequest.DebugWords[6] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericRequest.DebugWords[7] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_CONFIRM_ID:
+            sig->u.MlmeLeaveConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeLeaveConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeLeaveConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeLeaveConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeLeaveConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeLeaveConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_REQUEST_ID:
+            sig->u.MlmeDelTriggeredGetRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTriggeredGetRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTriggeredGetRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTriggeredGetRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTriggeredGetRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTriggeredGetRequest.TriggeredId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_REQUEST_ID:
+            sig->u.MlmeAddMulticastAddressRequest.Data.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddMulticastAddressRequest.Data.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddMulticastAddressRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddMulticastAddressRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddMulticastAddressRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddMulticastAddressRequest.NumberOfMulticastGroupAddresses = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_REQUEST_ID:
+            sig->u.MlmeResetRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeResetRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeResetRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeResetRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeResetRequest.StaAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeResetRequest.SetDefaultMib = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CANCEL_REQUEST_ID:
+            sig->u.MlmeScanCancelRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanCancelRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanCancelRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanCancelRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanCancelRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_CONFIRM_ID:
+            sig->u.MlmeAddTriggeredGetConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTriggeredGetConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTriggeredGetConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTriggeredGetConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTriggeredGetConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTriggeredGetConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTriggeredGetConfirm.TriggeredId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_REQUEST_ID:
+            sig->u.MlmeSetPacketFilterRequest.InformationElements.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetPacketFilterRequest.InformationElements.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetPacketFilterRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetPacketFilterRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetPacketFilterRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetPacketFilterRequest.PacketFilterMode = (CSR_PACKET_FILTER_MODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetPacketFilterRequest.ArpFilterAddress = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_CONFIRM_ID:
+            sig->u.MlmeDelRxTriggerConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelRxTriggerConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelRxTriggerConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelRxTriggerConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelRxTriggerConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelRxTriggerConfirm.TriggerId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelRxTriggerConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_REQUEST_ID:
+            sig->u.MlmeConnectStatusRequest.InformationElements.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectStatusRequest.InformationElements.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectStatusRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectStatusRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectStatusRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectStatusRequest.ConnectionStatus = (CSR_CONNECTION_STATUS) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeConnectStatusRequest.StaAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeConnectStatusRequest.AssociationId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectStatusRequest.AssociationCapabilityInformation = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_REQUEST_ID:
+            sig->u.MlmeLeaveRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeLeaveRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeLeaveRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeLeaveRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeLeaveRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_REQUEST_ID:
+            sig->u.MlmeConfigQueueRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueRequest.QueueIndex = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueRequest.Aifs = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueRequest.Cwmin = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueRequest.Cwmax = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConfigQueueRequest.TxopLimit = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_CONFIRM_ID:
+            sig->u.MlmeDelTspecConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecConfirm.UserPriority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTspecConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MLME_SET_TIM_CONFIRM_ID:
+            sig->u.MlmeSetTimConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetTimConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetTimConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetTimConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetTimConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetTimConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_INDICATION_ID:
+            sig->u.MlmeMeasureIndication.MeasurementReportSet.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureIndication.MeasurementReportSet.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureIndication.DialogToken = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_CONFIRM_ID:
+            sig->u.MlmeDelBlackoutConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelBlackoutConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelBlackoutConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelBlackoutConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelBlackoutConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelBlackoutConfirm.BlackoutId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelBlackoutConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_CONFIRM_ID:
+            sig->u.MlmeDelTriggeredGetConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTriggeredGetConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTriggeredGetConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTriggeredGetConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTriggeredGetConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTriggeredGetConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelTriggeredGetConfirm.TriggeredId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_DEBUG_GENERIC_INDICATION_ID:
+            sig->u.DebugGenericIndication.DebugVariable.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericIndication.DebugVariable.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericIndication.DebugWords[0] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericIndication.DebugWords[1] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericIndication.DebugWords[2] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericIndication.DebugWords[3] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericIndication.DebugWords[4] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericIndication.DebugWords[5] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericIndication.DebugWords[6] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugGenericIndication.DebugWords[7] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+        case CSR_MA_PACKET_CANCEL_REQUEST_ID:
+            sig->u.MaPacketCancelRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketCancelRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketCancelRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketCancelRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketCancelRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketCancelRequest.HostTag = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM_ID:
+            sig->u.MlmeModifyBssParameterConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM_ID:
+            sig->u.MlmePauseAutonomousScanConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanConfirm.AutonomousScanId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_PACKET_REQUEST_ID:
+            sig->u.MaPacketRequest.Data.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketRequest.Data.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketRequest.TransmitRate = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketRequest.HostTag = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            sig->u.MaPacketRequest.Priority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MaPacketRequest.Ra.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MaPacketRequest.TransmissionControl = (CSR_TRANSMISSION_CONTROL) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_REQUEST_ID:
+            sig->u.MlmeModifyBssParameterRequest.Data.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterRequest.Data.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterRequest.BeaconPeriod = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterRequest.DtimPeriod = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeModifyBssParameterRequest.CapabilityInformation = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeModifyBssParameterRequest.Bssid.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeModifyBssParameterRequest.RtsThreshold = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_REQUEST_ID:
+            sig->u.MlmeAddRxTriggerRequest.InformationElements.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerRequest.InformationElements.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerRequest.TriggerId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerRequest.Priority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_VIF_AVAILABILITY_INDICATION_ID:
+            sig->u.MaVifAvailabilityIndication.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaVifAvailabilityIndication.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaVifAvailabilityIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaVifAvailabilityIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaVifAvailabilityIndication.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaVifAvailabilityIndication.Multicast = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_REQUEST_ID:
+            sig->u.MlmeHlSyncCancelRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncCancelRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncCancelRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncCancelRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeHlSyncCancelRequest.GroupAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_REQUEST_ID:
+            sig->u.MlmeDelAutonomousScanRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelAutonomousScanRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelAutonomousScanRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelAutonomousScanRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelAutonomousScanRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelAutonomousScanRequest.AutonomousScanId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLACKOUT_ENDED_INDICATION_ID:
+            sig->u.MlmeBlackoutEndedIndication.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeBlackoutEndedIndication.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeBlackoutEndedIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeBlackoutEndedIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeBlackoutEndedIndication.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeBlackoutEndedIndication.BlackoutId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_DONE_INDICATION_ID:
+            sig->u.MlmeAutonomousScanDoneIndication.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAutonomousScanDoneIndication.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAutonomousScanDoneIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAutonomousScanDoneIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAutonomousScanDoneIndication.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAutonomousScanDoneIndication.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAutonomousScanDoneIndication.AutonomousScanId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_REQUEST_ID:
+            sig->u.MlmeGetKeySequenceRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceRequest.KeyId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetKeySequenceRequest.KeyType = (CSR_KEY_TYPE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeGetKeySequenceRequest.Address.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_REQUEST_ID:
+            sig->u.MlmeSetChannelRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelRequest.Ifindex = (CSR_IFINTERFACE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelRequest.Channel = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeSetChannelRequest.Address.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeSetChannelRequest.AvailabilityDuration = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetChannelRequest.AvailabilityInterval = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_CONFIRM_ID:
+            sig->u.MlmeMeasureConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureConfirm.DialogToken = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_REQUEST_ID:
+            sig->u.MlmeAddTriggeredGetRequest.MibAttribute.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTriggeredGetRequest.MibAttribute.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTriggeredGetRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTriggeredGetRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTriggeredGetRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTriggeredGetRequest.TriggeredId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_LOSS_INDICATION_ID:
+            sig->u.MlmeAutonomousScanLossIndication.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAutonomousScanLossIndication.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAutonomousScanLossIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAutonomousScanLossIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAutonomousScanLossIndication.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeAutonomousScanLossIndication.Bssid.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+        case CSR_MA_VIF_AVAILABILITY_RESPONSE_ID:
+            sig->u.MaVifAvailabilityResponse.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaVifAvailabilityResponse.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaVifAvailabilityResponse.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaVifAvailabilityResponse.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaVifAvailabilityResponse.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaVifAvailabilityResponse.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_REQUEST_ID:
+            sig->u.MlmeAddTemplateRequest.Data1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateRequest.Data1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateRequest.Data2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateRequest.Data2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateRequest.FrameType = (CSR_FRAME_TYPE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateRequest.MinTransmitRate = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_CONFIRM_ID:
+            sig->u.MlmePowermgtConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_CONFIRM_ID:
+            sig->u.MlmeAddPeriodicConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicConfirm.PeriodicId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_CONFIRM_ID:
+            sig->u.MlmeGetConfirm.MibAttributeValue.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetConfirm.MibAttributeValue.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetConfirm.Status = (CSR_MIB_STATUS) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetConfirm.ErrorIndex = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_CONFIRM_ID:
+            sig->u.MlmeGetNextConfirm.MibAttributeValue.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetNextConfirm.MibAttributeValue.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetNextConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetNextConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetNextConfirm.Status = (CSR_MIB_STATUS) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetNextConfirm.ErrorIndex = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_REQUEST_ID:
+            sig->u.MlmeStopAggregationRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopAggregationRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopAggregationRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopAggregationRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopAggregationRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeStopAggregationRequest.PeerQstaAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeStopAggregationRequest.UserPriority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopAggregationRequest.Direction = (CSR_DIRECTION) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_CONFIRM_ID:
+            sig->u.MlmeAddRxTriggerConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerConfirm.TriggerId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddRxTriggerConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_REQUEST_ID:
+            sig->u.MlmeAddBlackoutRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutRequest.BlackoutId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutRequest.BlackoutType = (CSR_BLACKOUT_TYPE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutRequest.BlackoutSource = (CSR_BLACKOUT_SOURCE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddBlackoutRequest.BlackoutStartReference = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            sig->u.MlmeAddBlackoutRequest.BlackoutPeriod = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            sig->u.MlmeAddBlackoutRequest.BlackoutDuration = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            CsrMemCpy(sig->u.MlmeAddBlackoutRequest.PeerStaAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeAddBlackoutRequest.BlackoutCount = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_REQUEST_ID:
+            sig->u.MlmeDeletekeysRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDeletekeysRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDeletekeysRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDeletekeysRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDeletekeysRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDeletekeysRequest.KeyId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDeletekeysRequest.KeyType = (CSR_KEY_TYPE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeDeletekeysRequest.Address.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_CONFIRM_ID:
+            sig->u.MlmeResetConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeResetConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeResetConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeResetConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeResetConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CONFIRM_ID:
+            sig->u.MlmeHlSyncConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeHlSyncConfirm.GroupAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeHlSyncConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_REQUEST_ID:
+            sig->u.MlmeAddAutonomousScanRequest.ChannelList.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanRequest.ChannelList.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanRequest.InformationElements.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanRequest.InformationElements.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanRequest.AutonomousScanId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanRequest.Ifindex = (CSR_IFINTERFACE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanRequest.ChannelStartingFactor = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanRequest.ScanType = (CSR_SCAN_TYPE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanRequest.ProbeDelay = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            sig->u.MlmeAddAutonomousScanRequest.MinChannelTime = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddAutonomousScanRequest.MaxChannelTime = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_REQUEST_ID:
+            sig->u.MlmeSetRequest.MibAttributeValue.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetRequest.MibAttributeValue.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_REQUEST_ID:
+            sig->u.MlmeSmStartRequest.Beacon.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartRequest.Beacon.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartRequest.BssParameters.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartRequest.BssParameters.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartRequest.Ifindex = (CSR_IFINTERFACE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartRequest.Channel = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeSmStartRequest.InterfaceAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            CsrMemCpy(sig->u.MlmeSmStartRequest.Bssid.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeSmStartRequest.BeaconPeriod = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartRequest.DtimPeriod = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSmStartRequest.CapabilityInformation = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_CONFIRM_ID:
+            sig->u.MlmeConnectStatusConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectStatusConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectStatusConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectStatusConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectStatusConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeConnectStatusConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM_ID:
+            sig->u.MlmeDelAutonomousScanConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelAutonomousScanConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelAutonomousScanConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelAutonomousScanConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelAutonomousScanConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelAutonomousScanConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelAutonomousScanConfirm.AutonomousScanId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_REQUEST_ID:
+            sig->u.MlmeDelPeriodicRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelPeriodicRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelPeriodicRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelPeriodicRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelPeriodicRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelPeriodicRequest.PeriodicId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_REQUEST_ID:
+            sig->u.MlmeSetkeysRequest.Key.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.Key.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.Length = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.KeyId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.KeyType = (CSR_KEY_TYPE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeSetkeysRequest.Address.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeSetkeysRequest.SequenceNumber[0] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.SequenceNumber[1] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.SequenceNumber[2] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.SequenceNumber[3] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.SequenceNumber[4] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.SequenceNumber[5] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.SequenceNumber[6] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetkeysRequest.SequenceNumber[7] = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(&sig->u.MlmeSetkeysRequest.CipherSuiteSelector, &ptr[index], 32 / 8);
+            index += 32 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_REQUEST_ID:
+            sig->u.MlmePauseAutonomousScanRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanRequest.AutonomousScanId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePauseAutonomousScanRequest.Pause = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_REQUEST_ID:
+            sig->u.MlmeGetRequest.MibAttribute.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetRequest.MibAttribute.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeGetRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_REQUEST_ID:
+            sig->u.MlmePowermgtRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtRequest.PowerManagementMode = (CSR_POWER_MANAGEMENT_MODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtRequest.ReceiveDtims = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtRequest.ListenInterval = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmePowermgtRequest.TrafficWindow = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_PACKET_ERROR_INDICATION_ID:
+            sig->u.MaPacketErrorIndication.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketErrorIndication.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketErrorIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketErrorIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketErrorIndication.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MaPacketErrorIndication.PeerQstaAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MaPacketErrorIndication.UserPriority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketErrorIndication.SequenceNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_REQUEST_ID:
+            sig->u.MlmeAddPeriodicRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicRequest.PeriodicId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicRequest.MaximumLatency = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            sig->u.MlmeAddPeriodicRequest.PeriodicSchedulingMode = (CSR_PERIODIC_SCHEDULING_MODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicRequest.WakeHost = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddPeriodicRequest.UserPriority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_REQUEST_ID:
+            sig->u.MlmeAddTspecRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecRequest.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecRequest.UserPriority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecRequest.Direction = (CSR_DIRECTION) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecRequest.PsScheme = (CSR_PS_SCHEME) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecRequest.MediumTime = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecRequest.ServiceStartTime = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            sig->u.MlmeAddTspecRequest.ServiceInterval = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            sig->u.MlmeAddTspecRequest.MinimumDataRate = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM_ID:
+            sig->u.MlmeAddMulticastAddressConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddMulticastAddressConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddMulticastAddressConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddMulticastAddressConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddMulticastAddressConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddMulticastAddressConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_CONFIRM_ID:
+            sig->u.MlmeAddTspecConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecConfirm.UserPriority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTspecConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_CONFIRM_ID:
+            sig->u.MlmeHlSyncCancelConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncCancelConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncCancelConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncCancelConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeHlSyncCancelConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CONFIRM_ID:
+            sig->u.MlmeScanConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeScanConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_DEBUG_STRING_INDICATION_ID:
+            sig->u.DebugStringIndication.DebugMessage.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugStringIndication.DebugMessage.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugStringIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.DebugStringIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_CONFIRM_ID:
+            sig->u.MlmeAddTemplateConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateConfirm.FrameType = (CSR_FRAME_TYPE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeAddTemplateConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLOCKACK_ERROR_INDICATION_ID:
+            sig->u.MlmeBlockackErrorIndication.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeBlockackErrorIndication.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeBlockackErrorIndication.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeBlockackErrorIndication.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeBlockackErrorIndication.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeBlockackErrorIndication.ResultCode = (CSR_REASON_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeBlockackErrorIndication.PeerQstaAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CONFIRM_ID:
+            sig->u.MlmeSetConfirm.MibAttributeValue.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetConfirm.MibAttributeValue.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetConfirm.Status = (CSR_MIB_STATUS) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeSetConfirm.ErrorIndex = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_REQUEST_ID:
+            sig->u.MlmeMeasureRequest.MeasurementRequestSet.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureRequest.MeasurementRequestSet.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeMeasureRequest.DialogToken = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_CONFIRM_ID:
+            sig->u.MlmeStartAggregationConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(sig->u.MlmeStartAggregationConfirm.PeerQstaAddress.x, &ptr[index], 48 / 8);
+            index += 48 / 8;
+            sig->u.MlmeStartAggregationConfirm.UserPriority = (CSR_PRIORITY) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationConfirm.Direction = (CSR_DIRECTION) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStartAggregationConfirm.SequenceNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_CONFIRM_ID:
+            sig->u.MlmeStopMeasureConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopMeasureConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopMeasureConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopMeasureConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopMeasureConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopMeasureConfirm.DialogToken = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_PACKET_CONFIRM_ID:
+            sig->u.MaPacketConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketConfirm.TransmissionStatus = (CSR_TRANSMISSION_STATUS) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketConfirm.RetryCount = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketConfirm.Rate = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MaPacketConfirm.HostTag = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT32;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_CONFIRM_ID:
+            sig->u.MlmeDelPeriodicConfirm.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelPeriodicConfirm.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelPeriodicConfirm.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelPeriodicConfirm.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelPeriodicConfirm.VirtualInterfaceIdentifier = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelPeriodicConfirm.PeriodicId = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeDelPeriodicConfirm.ResultCode = (CSR_RESULT_CODE) CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_REQUEST_ID:
+            sig->u.MlmeStopMeasureRequest.Dummydataref1.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopMeasureRequest.Dummydataref1.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopMeasureRequest.Dummydataref2.SlotNumber = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopMeasureRequest.Dummydataref2.DataLength = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            sig->u.MlmeStopMeasureRequest.DialogToken = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+
+        default:
+            return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+    return CSR_RESULT_SUCCESS;
+} /* read_unpack_signal() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  write_pack
+ *
+ *      Convert a signal structure, in host-native format, to the
+ *      little-endian wire format specified in the UniFi Host Interface
+ *      Protocol Specification.
+ *
+ *      WARNING: This function is auto-generated, DO NOT EDIT!
+ *
+ *  Arguments:
+ *      sig             Pointer to signal structure to pack.
+ *      ptr             Destination buffer to pack into.
+ *      sig_len         Returns the length of the packed signal, i.e. the
+ *                      number of bytes written to ptr.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success,
+ *      CSR_WIFI_HIP_RESULT_INVALID_VALUE if the ID of signal was not recognised.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult write_pack(const CSR_SIGNAL *sig, CsrUint8 *ptr, CsrUint16 *sig_len)
+{
+    CsrInt16 index = 0;
+
+    CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->SignalPrimitiveHeader.SignalId, ptr + index);
+    index += SIZEOF_UINT16;
+
+    CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->SignalPrimitiveHeader.ReceiverProcessId, ptr + index);
+    index += SIZEOF_UINT16;
+
+    CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->SignalPrimitiveHeader.SenderProcessId, ptr + index);
+    index += SIZEOF_UINT16;
+
+    switch (sig->SignalPrimitiveHeader.SignalId)
+    {
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanConfirm.AutonomousScanId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutConfirm.BlackoutId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutRequest.BlackoutId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[0], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[1], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[2], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[3], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[4], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[5], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[6], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceConfirm.SequenceNumber[7], ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeStopAggregationConfirm.PeerQstaAddress.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationConfirm.UserPriority, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationConfirm.Direction, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecRequest.UserPriority, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecRequest.Direction, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_DEBUG_WORD16_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[0], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[1], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[2], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[3], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[4], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[5], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[6], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[7], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[8], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[9], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[10], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[11], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[12], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[13], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[14], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugWord16Indication.DebugWords[15], ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+        case CSR_DEBUG_GENERIC_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.DebugVariable.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.DebugVariable.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.DebugWords[0], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.DebugWords[1], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.DebugWords[2], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.DebugWords[3], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.DebugWords[4], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.DebugWords[5], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.DebugWords[6], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericConfirm.DebugWords[7], ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+        case CSR_MA_PACKET_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketIndication.Data.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketIndication.Data.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketIndication.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MaPacketIndication.LocalTime.x, 64 / 8);
+            index += 64 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketIndication.Ifindex, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketIndication.Channel, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketIndication.ReceptionStatus, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketIndication.Rssi, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketIndication.Snr, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketIndication.ReceivedRate, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+        case CSR_MLME_SET_TIM_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimRequest.AssociationId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimRequest.TimValue, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECTED_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectedIndication.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectedIndication.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectedIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectedIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectedIndication.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectedIndication.ConnectionStatus, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeConnectedIndication.PeerMacAddress.x, 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerRequest.TriggerId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_TRIGGERED_GET_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeTriggeredGetIndication.MibAttributeValue.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeTriggeredGetIndication.MibAttributeValue.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeTriggeredGetIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeTriggeredGetIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeTriggeredGetIndication.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeTriggeredGetIndication.Status, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeTriggeredGetIndication.ErrorIndex, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeTriggeredGetIndication.TriggeredId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanRequest.ChannelList.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanRequest.ChannelList.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanRequest.InformationElements.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanRequest.InformationElements.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanRequest.Ifindex, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanRequest.ScanType, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MlmeScanRequest.ProbeDelay, ptr + index);
+            index += SIZEOF_UINT32;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanRequest.MinChannelTime, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanRequest.MaxChannelTime, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetNextRequest.MibAttribute.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetNextRequest.MibAttribute.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetNextRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetNextRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeStartAggregationRequest.PeerQstaAddress.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationRequest.UserPriority, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationRequest.Direction, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationRequest.StartingSequenceNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationRequest.BufferSize, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationRequest.BlockAckTimeout, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeHlSyncRequest.GroupAddress.x, 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+        case CSR_DEBUG_GENERIC_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.DebugVariable.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.DebugVariable.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.DebugWords[0], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.DebugWords[1], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.DebugWords[2], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.DebugWords[3], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.DebugWords[4], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.DebugWords[5], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.DebugWords[6], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericRequest.DebugWords[7], ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeLeaveConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeLeaveConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeLeaveConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeLeaveConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeLeaveConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeLeaveConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetRequest.TriggeredId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressRequest.Data.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressRequest.Data.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressRequest.NumberOfMulticastGroupAddresses, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeResetRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeResetRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeResetRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeResetRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeResetRequest.StaAddress.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeResetRequest.SetDefaultMib, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CANCEL_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanCancelRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanCancelRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanCancelRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanCancelRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanCancelRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetConfirm.TriggeredId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterRequest.InformationElements.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterRequest.InformationElements.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterRequest.PacketFilterMode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MlmeSetPacketFilterRequest.ArpFilterAddress, ptr + index);
+            index += SIZEOF_UINT32;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerConfirm.TriggerId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelRxTriggerConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusRequest.InformationElements.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusRequest.InformationElements.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusRequest.ConnectionStatus, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeConnectStatusRequest.StaAddress.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusRequest.AssociationId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusRequest.AssociationCapabilityInformation, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeLeaveRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeLeaveRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeLeaveRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeLeaveRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeLeaveRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueRequest.QueueIndex, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueRequest.Aifs, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueRequest.Cwmin, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueRequest.Cwmax, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConfigQueueRequest.TxopLimit, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecConfirm.UserPriority, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTspecConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MLME_SET_TIM_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetTimConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureIndication.MeasurementReportSet.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureIndication.MeasurementReportSet.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureIndication.DialogToken, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutConfirm.BlackoutId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelBlackoutConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelTriggeredGetConfirm.TriggeredId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_DEBUG_GENERIC_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.DebugVariable.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.DebugVariable.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.DebugWords[0], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.DebugWords[1], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.DebugWords[2], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.DebugWords[3], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.DebugWords[4], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.DebugWords[5], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.DebugWords[6], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugGenericIndication.DebugWords[7], ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+        case CSR_MA_PACKET_CANCEL_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketCancelRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketCancelRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketCancelRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketCancelRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketCancelRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MaPacketCancelRequest.HostTag, ptr + index);
+            index += SIZEOF_UINT32;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanConfirm.AutonomousScanId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_PACKET_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketRequest.Data.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketRequest.Data.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketRequest.TransmitRate, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MaPacketRequest.HostTag, ptr + index);
+            index += SIZEOF_UINT32;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketRequest.Priority, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MaPacketRequest.Ra.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketRequest.TransmissionControl, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterRequest.Data.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterRequest.Data.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterRequest.BeaconPeriod, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterRequest.DtimPeriod, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterRequest.CapabilityInformation, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeModifyBssParameterRequest.Bssid.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeModifyBssParameterRequest.RtsThreshold, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerRequest.InformationElements.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerRequest.InformationElements.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerRequest.TriggerId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerRequest.Priority, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_VIF_AVAILABILITY_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityIndication.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityIndication.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityIndication.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityIndication.Multicast, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncCancelRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncCancelRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncCancelRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncCancelRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeHlSyncCancelRequest.GroupAddress.x, 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanRequest.AutonomousScanId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLACKOUT_ENDED_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlackoutEndedIndication.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlackoutEndedIndication.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlackoutEndedIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlackoutEndedIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlackoutEndedIndication.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlackoutEndedIndication.BlackoutId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_DONE_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanDoneIndication.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanDoneIndication.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanDoneIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanDoneIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanDoneIndication.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanDoneIndication.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanDoneIndication.AutonomousScanId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceRequest.KeyId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetKeySequenceRequest.KeyType, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeGetKeySequenceRequest.Address.x, 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelRequest.Ifindex, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelRequest.Channel, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeSetChannelRequest.Address.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelRequest.AvailabilityDuration, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetChannelRequest.AvailabilityInterval, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureConfirm.DialogToken, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetRequest.MibAttribute.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetRequest.MibAttribute.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTriggeredGetRequest.TriggeredId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_LOSS_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanLossIndication.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanLossIndication.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanLossIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanLossIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAutonomousScanLossIndication.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeAutonomousScanLossIndication.Bssid.x, 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+        case CSR_MA_VIF_AVAILABILITY_RESPONSE_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityResponse.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityResponse.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityResponse.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityResponse.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityResponse.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaVifAvailabilityResponse.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateRequest.Data1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateRequest.Data1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateRequest.Data2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateRequest.Data2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateRequest.FrameType, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateRequest.MinTransmitRate, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicConfirm.PeriodicId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetConfirm.MibAttributeValue.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetConfirm.MibAttributeValue.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetConfirm.Status, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetConfirm.ErrorIndex, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetNextConfirm.MibAttributeValue.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetNextConfirm.MibAttributeValue.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetNextConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetNextConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetNextConfirm.Status, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetNextConfirm.ErrorIndex, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeStopAggregationRequest.PeerQstaAddress.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationRequest.UserPriority, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopAggregationRequest.Direction, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerConfirm.TriggerId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddRxTriggerConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.BlackoutId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.BlackoutType, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.BlackoutSource, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.BlackoutStartReference, ptr + index);
+            index += SIZEOF_UINT32;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.BlackoutPeriod, ptr + index);
+            index += SIZEOF_UINT32;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.BlackoutDuration, ptr + index);
+            index += SIZEOF_UINT32;
+            CsrMemCpy(ptr + index, sig->u.MlmeAddBlackoutRequest.PeerStaAddress.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddBlackoutRequest.BlackoutCount, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysRequest.KeyId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDeletekeysRequest.KeyType, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeDeletekeysRequest.Address.x, 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeResetConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeResetConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeResetConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeResetConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeResetConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeHlSyncConfirm.GroupAddress.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.ChannelList.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.ChannelList.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.InformationElements.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.InformationElements.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.AutonomousScanId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.Ifindex, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.ChannelStartingFactor, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.ScanType, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.ProbeDelay, ptr + index);
+            index += SIZEOF_UINT32;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.MinChannelTime, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddAutonomousScanRequest.MaxChannelTime, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetRequest.MibAttributeValue.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetRequest.MibAttributeValue.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartRequest.Beacon.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartRequest.Beacon.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartRequest.BssParameters.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartRequest.BssParameters.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartRequest.Ifindex, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartRequest.Channel, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeSmStartRequest.InterfaceAddress.x, 48 / 8);
+            index += 48 / 8;
+            CsrMemCpy(ptr + index, sig->u.MlmeSmStartRequest.Bssid.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartRequest.BeaconPeriod, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartRequest.DtimPeriod, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSmStartRequest.CapabilityInformation, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeConnectStatusConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelAutonomousScanConfirm.AutonomousScanId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicRequest.PeriodicId, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.Key.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.Key.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.Length, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.KeyId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.KeyType, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeSetkeysRequest.Address.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.SequenceNumber[0], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.SequenceNumber[1], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.SequenceNumber[2], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.SequenceNumber[3], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.SequenceNumber[4], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.SequenceNumber[5], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.SequenceNumber[6], ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetkeysRequest.SequenceNumber[7], ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, &sig->u.MlmeSetkeysRequest.CipherSuiteSelector, 32 / 8);
+            index += 32 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanRequest.AutonomousScanId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePauseAutonomousScanRequest.Pause, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetRequest.MibAttribute.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetRequest.MibAttribute.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeGetRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtRequest.PowerManagementMode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtRequest.ReceiveDtims, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtRequest.ListenInterval, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmePowermgtRequest.TrafficWindow, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_PACKET_ERROR_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketErrorIndication.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketErrorIndication.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketErrorIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketErrorIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketErrorIndication.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MaPacketErrorIndication.PeerQstaAddress.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketErrorIndication.UserPriority, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketErrorIndication.SequenceNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicRequest.PeriodicId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicRequest.MaximumLatency, ptr + index);
+            index += SIZEOF_UINT32;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicRequest.PeriodicSchedulingMode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicRequest.WakeHost, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddPeriodicRequest.UserPriority, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.UserPriority, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.Direction, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.PsScheme, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.MediumTime, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.ServiceStartTime, ptr + index);
+            index += SIZEOF_UINT32;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.ServiceInterval, ptr + index);
+            index += SIZEOF_UINT32;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecRequest.MinimumDataRate, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddMulticastAddressConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecConfirm.UserPriority, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTspecConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncCancelConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncCancelConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncCancelConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncCancelConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeHlSyncCancelConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeScanConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_DEBUG_STRING_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugStringIndication.DebugMessage.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugStringIndication.DebugMessage.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugStringIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.DebugStringIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateConfirm.FrameType, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeAddTemplateConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLOCKACK_ERROR_INDICATION_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlockackErrorIndication.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlockackErrorIndication.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlockackErrorIndication.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlockackErrorIndication.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlockackErrorIndication.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeBlockackErrorIndication.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeBlockackErrorIndication.PeerQstaAddress.x, 48 / 8);
+            index += 48 / 8;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetConfirm.MibAttributeValue.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetConfirm.MibAttributeValue.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetConfirm.Status, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeSetConfirm.ErrorIndex, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureRequest.MeasurementRequestSet.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureRequest.MeasurementRequestSet.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeMeasureRequest.DialogToken, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CsrMemCpy(ptr + index, sig->u.MlmeStartAggregationConfirm.PeerQstaAddress.x, 48 / 8);
+            index += 48 / 8;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationConfirm.UserPriority, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationConfirm.Direction, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStartAggregationConfirm.SequenceNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopMeasureConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopMeasureConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopMeasureConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopMeasureConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopMeasureConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopMeasureConfirm.DialogToken, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+        case CSR_MA_PACKET_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketConfirm.TransmissionStatus, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketConfirm.RetryCount, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MaPacketConfirm.Rate, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT32_TO_LITTLE_ENDIAN(sig->u.MaPacketConfirm.HostTag, ptr + index);
+            index += SIZEOF_UINT32;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_CONFIRM_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicConfirm.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicConfirm.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicConfirm.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicConfirm.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicConfirm.VirtualInterfaceIdentifier, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicConfirm.PeriodicId, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeDelPeriodicConfirm.ResultCode, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_REQUEST_ID:
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopMeasureRequest.Dummydataref1.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopMeasureRequest.Dummydataref1.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopMeasureRequest.Dummydataref2.SlotNumber, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopMeasureRequest.Dummydataref2.DataLength, ptr + index);
+            index += SIZEOF_UINT16;
+            CSR_COPY_UINT16_TO_LITTLE_ENDIAN(sig->u.MlmeStopMeasureRequest.DialogToken, ptr + index);
+            index += SIZEOF_UINT16;
+            break;
+#endif
+
+        default:
+            return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    *sig_len = index;
+
+    return CSR_RESULT_SUCCESS;
+} /* write_pack() */
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_send.c b/drivers/staging/csr/csr_wifi_hip_send.c
new file mode 100644
index 0000000..624f3bb
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_send.c
@@ -0,0 +1,422 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ***************************************************************************
+ *
+ *  FILE:     csr_wifi_hip_send.c
+ *
+ *  PURPOSE:
+ *      Code for adding a signal request to the from-host queue.
+ *      When the driver bottom-half is run, it will take requests from the
+ *      queue and pass them to the UniFi.
+ *
+ * ***************************************************************************
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_conversions.h"
+#include "csr_wifi_hip_sigs.h"
+#include "csr_wifi_hip_card.h"
+
+unifi_TrafficQueue unifi_frame_priority_to_queue(CSR_PRIORITY priority)
+{
+    switch (priority)
+    {
+        case CSR_QOS_UP0:
+        case CSR_QOS_UP3:
+            return UNIFI_TRAFFIC_Q_BE;
+        case CSR_QOS_UP1:
+        case CSR_QOS_UP2:
+            return UNIFI_TRAFFIC_Q_BK;
+        case CSR_QOS_UP4:
+        case CSR_QOS_UP5:
+            return UNIFI_TRAFFIC_Q_VI;
+        case CSR_QOS_UP6:
+        case CSR_QOS_UP7:
+        case CSR_MANAGEMENT:
+            return UNIFI_TRAFFIC_Q_VO;
+        default:
+            return UNIFI_TRAFFIC_Q_BE;
+    }
+}
+
+
+CSR_PRIORITY unifi_get_default_downgrade_priority(unifi_TrafficQueue queue)
+{
+    switch (queue)
+    {
+        case UNIFI_TRAFFIC_Q_BE:
+            return CSR_QOS_UP0;
+        case UNIFI_TRAFFIC_Q_BK:
+            return CSR_QOS_UP1;
+        case UNIFI_TRAFFIC_Q_VI:
+            return CSR_QOS_UP5;
+        case UNIFI_TRAFFIC_Q_VO:
+            return CSR_QOS_UP6;
+        default:
+            return CSR_QOS_UP0;
+    }
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  send_signal
+ *
+ *      This function queues a signal for sending to UniFi.  It first checks
+ *      that there is space on the fh_signal_queue for another entry, then
+ *      claims any bulk data slots required and copies data into them. Then
+ *      increments the fh_signal_queue write count.
+ *
+ *      The fh_signal_queue is later processed by the driver bottom half
+ *      (in unifi_bh()).
+ *
+ *      This function call unifi_pause_xmit() to pause the flow of data plane
+ *      packets when:
+ *        - the fh_signal_queue ring buffer is full
+ *        - there are less than UNIFI_MAX_DATA_REFERENCES (2) bulk data
+ *          slots available.
+ *
+ *  Arguments:
+ *      card            Pointer to card context structure
+ *      sigptr          Pointer to the signal to write to UniFi.
+ *      siglen          Number of bytes pointer to by sigptr.
+ *      bulkdata        Array of pointers to an associated bulk data.
+ *      sigq            To which from-host queue to add the signal.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success
+ *      CSR_WIFI_HIP_RESULT_NO_SPACE if there were insufficient data slots or
+ *                              no free signal queue entry
+ *
+ * Notes:
+ *      Calls unifi_pause_xmit() when the last slots are used.
+ * ---------------------------------------------------------------------------
+ */
+static CsrResult send_signal(card_t *card, const CsrUint8 *sigptr, CsrUint32 siglen,
+                             const bulk_data_param_t *bulkdata,
+                             q_t *sigq, CsrUint32 priority_q, CsrUint32 run_bh)
+{
+    CsrUint16 i, data_slot_size;
+    card_signal_t *csptr;
+    CsrInt16 qe;
+    CsrResult r;
+    CsrInt16 debug_print = 0;
+
+    data_slot_size = CardGetDataSlotSize(card);
+
+    /* Check that the fh_data_queue has a free slot */
+    if (!CSR_WIFI_HIP_Q_SLOTS_FREE(sigq))
+    {
+        unifi_trace(card->ospriv, UDBG3, "send_signal: %s full\n", sigq->name);
+
+        return CSR_WIFI_HIP_RESULT_NO_SPACE;
+    }
+
+    /*
+     * Now add the signal to the From Host signal queue
+     */
+    /* Get next slot on queue */
+    qe = CSR_WIFI_HIP_Q_NEXT_W_SLOT(sigq);
+    csptr = CSR_WIFI_HIP_Q_SLOT_DATA(sigq, qe);
+
+    /* Make up the card_signal struct */
+    csptr->signal_length = (CsrUint16)siglen;
+    CsrMemCpy((void *)csptr->sigbuf, (void *)sigptr, siglen);
+
+    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; ++i)
+    {
+        if ((bulkdata != NULL) && (bulkdata->d[i].data_length != 0))
+        {
+            CsrUint32 datalen = bulkdata->d[i].data_length;
+
+            /* Make sure data will fit in a bulk data slot */
+            if (bulkdata->d[i].os_data_ptr == NULL)
+            {
+                unifi_error(card->ospriv, "send_signal - NULL bulkdata[%d]\n", i);
+                debug_print++;
+                csptr->bulkdata[i].data_length = 0;
+            }
+            else
+            {
+                if (datalen > data_slot_size)
+                {
+                    unifi_error(card->ospriv,
+                                "send_signal - Invalid data length %u (@%p), "
+                                "truncating\n",
+                                datalen, bulkdata->d[i].os_data_ptr);
+                    datalen = data_slot_size;
+                    debug_print++;
+                }
+                /* Store the bulk data info in the soft queue. */
+                csptr->bulkdata[i].os_data_ptr = (CsrUint8 *)bulkdata->d[i].os_data_ptr;
+                csptr->bulkdata[i].os_net_buf_ptr = (CsrUint8 *)bulkdata->d[i].os_net_buf_ptr;
+                csptr->bulkdata[i].net_buf_length = bulkdata->d[i].net_buf_length;
+                csptr->bulkdata[i].data_length = datalen;
+            }
+        }
+        else
+        {
+            UNIFI_INIT_BULK_DATA(&csptr->bulkdata[i]);
+        }
+    }
+
+    if (debug_print)
+    {
+        const CsrUint8 *sig = sigptr;
+
+        unifi_error(card->ospriv, "Signal(%d): %02x %02x %02x %02x %02x %02x %02x %02x"
+                    " %02x %02x %02x %02x %02x %02x %02x %02x\n",
+                    siglen,
+                    sig[0], sig[1], sig[2], sig[3],
+                    sig[4], sig[5], sig[6], sig[7],
+                    sig[8], sig[9], sig[10], sig[11],
+                    sig[12], sig[13], sig[14], sig[15]);
+        unifi_error(card->ospriv, "Bulkdata pointer %p(%d), %p(%d)\n",
+                    bulkdata != NULL?bulkdata->d[0].os_data_ptr : NULL,
+                    bulkdata != NULL?bulkdata->d[0].data_length : 0,
+                    bulkdata != NULL?bulkdata->d[1].os_data_ptr : NULL,
+                    bulkdata != NULL?bulkdata->d[1].data_length : 0);
+    }
+
+    /* Advance the written count to say there is a new entry */
+    CSR_WIFI_HIP_Q_INC_W(sigq);
+
+    /*
+     * Set the flag to say reason for waking was a host request.
+     * Then ask the OS layer to run the unifi_bh.
+     */
+    if (run_bh == 1)
+    {
+        card->bh_reason_host = 1;
+        r = unifi_run_bh(card->ospriv);
+        if (r != CSR_RESULT_SUCCESS)
+        {
+            unifi_error(card->ospriv, "failed to run bh.\n");
+            card->bh_reason_host = 0;
+
+            /*
+             * The bulk data buffer will be freed by the caller.
+             * We need to invalidate the description of the bulk data in our
+             * soft queue, to prevent the core freeing the bulk data again later.
+             */
+            for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; ++i)
+            {
+                if (csptr->bulkdata[i].data_length != 0)
+                {
+                    csptr->bulkdata[i].os_data_ptr = csptr->bulkdata[i].os_net_buf_ptr = NULL;
+                    csptr->bulkdata[i].net_buf_length = csptr->bulkdata[i].data_length = 0;
+                }
+            }
+            return r;
+        }
+    }
+    else
+    {
+        unifi_error(card->ospriv, "run_bh=%d, bh not called.\n", run_bh);
+    }
+
+    /*
+     * Have we used up all the fh signal list entries?
+     */
+    if (CSR_WIFI_HIP_Q_SLOTS_FREE(sigq) == 0)
+    {
+        /* We have filled the queue, so stop the upper layer. The command queue
+         * is an exception, as suspending due to that being full could delay
+         * resume/retry until new commands or data are received.
+         */
+        if (sigq != &card->fh_command_queue)
+        {
+            /*
+             * Must call unifi_pause_xmit() *before* setting the paused flag.
+             * (the unifi_pause_xmit call should not be after setting the flag because of the possibility of being interrupted
+             * by the bh thread between our setting the flag and the call to unifi_pause_xmit()
+             * If bh thread then cleared the flag, we would end up paused, but without the flag set)
+             * Instead, setting it afterwards means that if this thread is interrupted by the bh thread
+             * the pause flag is still guaranteed to end up set
+             * However the potential deadlock now is that if bh thread emptied the queue and cleared the flag before this thread's
+             * call to unifi_pause_xmit(), then bh thread may not run again because it will be waiting for
+             * a packet to appear in the queue but nothing ever will because xmit is paused.
+             * So we will end up with the queue paused, and the flag set to say it is paused, but bh never runs to unpause it.
+             * (Note even this bad situation would not persist long in practice, because something else (eg rx, or tx in different queue)
+             * is likely to wake bh thread quite soon)
+             * But to avoid this deadlock completely, after setting the flag we check that there is something left in the queue.
+             * If there is, we know that bh thread has not emptied the queue yet.
+             * Since bh thread checks to unpause the queue *after* taking packets from the queue, we know that it is still going to make at
+             * least one more check to see whether it needs to unpause the queue.  So all is well.
+             * If there are no packets in the queue, then the deadlock described above might happen.  To make sure it does not, we
+             * unpause the queue here. A possible side effect is that unifi_restart_xmit() may (rarely) be called for second time
+             *  unnecessarily, which is harmless
+             */
+
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+            unifi_debug_log_to_buf("P");
+#endif
+            unifi_pause_xmit(card->ospriv, (unifi_TrafficQueue)priority_q);
+            card_tx_q_pause(card, priority_q);
+            if (CSR_WIFI_HIP_Q_SLOTS_USED(sigq) == 0)
+            {
+                card_tx_q_unpause(card, priority_q);
+                unifi_restart_xmit(card->ospriv, (unifi_TrafficQueue) priority_q);
+            }
+        }
+        else
+        {
+            unifi_warning(card->ospriv,
+                          "send_signal: fh_cmd_q full, not pausing (run_bh=%d)\n",
+                          run_bh);
+        }
+    }
+
+    func_exit();
+
+    return CSR_RESULT_SUCCESS;
+} /*  send_signal() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_send_signal
+ *
+ *    Invokes send_signal() to queue a signal in the command or traffic queue
+ *    If sigptr pointer is NULL, it pokes the bh to check if UniFi is responsive.
+ *
+ *  Arguments:
+ *      card        Pointer to card context struct
+ *      sigptr      Pointer to signal from card.
+ *      siglen      Size of the signal
+ *      bulkdata    Pointer to the bulk data of the signal
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success
+ *      CSR_WIFI_HIP_RESULT_NO_SPACE if there were insufficient data slots or no free signal queue entry
+ *
+ *  Notes:
+ *      unifi_send_signal() is used to queue signals, created by the driver,
+ *      to the device. Signals are constructed using the UniFi packed structures.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_send_signal(card_t *card, const CsrUint8 *sigptr, CsrUint32 siglen,
+                            const bulk_data_param_t *bulkdata)
+{
+    q_t *sig_soft_q;
+    CsrUint16 signal_id;
+    CsrResult r;
+    CsrUint32 run_bh;
+    CsrUint32 priority_q;
+
+    /* A NULL signal pointer is a request to check if UniFi is responsive */
+    if (sigptr == NULL)
+    {
+        card->bh_reason_host = 1;
+        return unifi_run_bh(card->ospriv);
+    }
+
+    priority_q = 0;
+    run_bh = 1;
+    signal_id = GET_SIGNAL_ID(sigptr);
+    /*
+     * If the signal is a CSR_MA_PACKET_REQUEST ,
+     * we send it using the traffic soft queue. Else we use the command soft queue.
+     */
+    if (signal_id == CSR_MA_PACKET_REQUEST_ID)
+    {
+        CsrUint16 frame_priority;
+
+        if (card->periodic_wake_mode == UNIFI_PERIODIC_WAKE_HOST_ENABLED)
+        {
+            run_bh = 0;
+        }
+
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
+        unifi_debug_log_to_buf("D");
+#endif
+        /* Sanity check: MA-PACKET.req must have a valid bulk data */
+        if ((bulkdata->d[0].data_length == 0) || (bulkdata->d[0].os_data_ptr == NULL))
+        {
+            unifi_error(card->ospriv, "MA-PACKET.req with empty bulk data (%d bytes in %p)\n",
+                        bulkdata->d[0].data_length, bulkdata->d[0].os_data_ptr);
+            dump((void *)sigptr, siglen);
+            return CSR_RESULT_FAILURE;
+        }
+
+        /* Map the frame priority to a traffic queue index. */
+        frame_priority = GET_PACKED_MA_PACKET_REQUEST_FRAME_PRIORITY(sigptr);
+        priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY)frame_priority);
+
+        sig_soft_q = &card->fh_traffic_queue[priority_q];
+    }
+    else
+    {
+        sig_soft_q = &card->fh_command_queue;
+    }
+
+    r = send_signal(card, sigptr, siglen, bulkdata, sig_soft_q, priority_q, run_bh);
+    /* On error, the caller must free or requeue bulkdata buffers */
+
+    return r;
+} /* unifi_send_signal() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_send_resources_available
+ *
+ *      Examines whether there is available space to queue
+ *      a signal in the command or traffic queue
+ *
+ *  Arguments:
+ *      card        Pointer to card context struct
+ *      sigptr      Pointer to signal.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS if resources available
+ *      CSR_WIFI_HIP_RESULT_NO_SPACE if there was no free signal queue entry
+ *
+ *  Notes:
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_send_resources_available(card_t *card, const CsrUint8 *sigptr)
+{
+    q_t *sig_soft_q;
+    CsrUint16 signal_id = GET_SIGNAL_ID(sigptr);
+
+    /*
+     * If the signal is a CSR_MA_PACKET_REQUEST ,
+     * we send it using the traffic soft queue. Else we use the command soft queue.
+     */
+    if (signal_id == CSR_MA_PACKET_REQUEST_ID)
+    {
+        CsrUint16 frame_priority;
+        CsrUint32 priority_q;
+
+        /* Map the frame priority to a traffic queue index. */
+        frame_priority = GET_PACKED_MA_PACKET_REQUEST_FRAME_PRIORITY(sigptr);
+        priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY)frame_priority);
+
+        sig_soft_q = &card->fh_traffic_queue[priority_q];
+    }
+    else
+    {
+        sig_soft_q = &card->fh_command_queue;
+    }
+
+    /* Check that the fh_data_queue has a free slot */
+    if (!CSR_WIFI_HIP_Q_SLOTS_FREE(sig_soft_q))
+    {
+        unifi_notice(card->ospriv, "unifi_send_resources_available: %s full\n",
+                     sig_soft_q->name);
+        return CSR_WIFI_HIP_RESULT_NO_SPACE;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_send_resources_available() */
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_signals.c b/drivers/staging/csr/csr_wifi_hip_signals.c
new file mode 100644
index 0000000..5d0be53
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_signals.c
@@ -0,0 +1,1313 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+
+/* Generated by hip_dd_l_c_gen.pl */
+
+#include "csr_wifi_hip_signals.h"
+
+#include "csr_wifi_hip_unifi.h"
+
+CsrInt32 SigGetSize(const CSR_SIGNAL *aSignal)
+{
+    switch (aSignal->SignalPrimitiveHeader.SignalId)
+    {
+        case CSR_MA_PACKET_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MA_PACKET_REQUEST);
+        case CSR_MA_PACKET_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MA_PACKET_CONFIRM);
+        case CSR_MA_PACKET_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MA_PACKET_INDICATION);
+        case CSR_MA_PACKET_CANCEL_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MA_PACKET_CANCEL_REQUEST);
+        case CSR_MA_VIF_AVAILABILITY_RESPONSE_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MA_VIF_AVAILABILITY_RESPONSE);
+        case CSR_MA_VIF_AVAILABILITY_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MA_VIF_AVAILABILITY_INDICATION);
+        case CSR_MA_PACKET_ERROR_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MA_PACKET_ERROR_INDICATION);
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_RESET_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_RESET_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_GET_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_GET_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SET_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SET_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_GET_NEXT_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_GET_NEXT_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_POWERMGT_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_POWERMGT_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SCAN_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SCAN_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_HL_SYNC_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_HL_SYNC_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_MEASURE_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_MEASURE_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_MEASURE_INDICATION);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SETKEYS_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SETKEYS_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DELETEKEYS_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DELETEKEYS_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_LOSS_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_AUTONOMOUS_SCAN_LOSS_INDICATION);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECTED_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_CONNECTED_INDICATION);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CANCEL_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SCAN_CANCEL_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_HL_SYNC_CANCEL_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_HL_SYNC_CANCEL_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_PERIODIC_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_PERIODIC_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_PERIODIC_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_PERIODIC_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_AUTONOMOUS_SCAN_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_AUTONOMOUS_SCAN_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SET_PACKET_FILTER_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SET_PACKET_FILTER_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_STOP_MEASURE_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_STOP_MEASURE_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_PAUSE_AUTONOMOUS_SCAN_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_DONE_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_AUTONOMOUS_SCAN_DONE_INDICATION);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_TRIGGERED_GET_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_TRIGGERED_GET_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_TRIGGERED_GET_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_TRIGGERED_GET_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_TRIGGERED_GET_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_TRIGGERED_GET_INDICATION);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_BLACKOUT_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_BLACKOUT_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLACKOUT_ENDED_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_BLACKOUT_ENDED_INDICATION);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_BLACKOUT_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_BLACKOUT_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_RX_TRIGGER_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_RX_TRIGGER_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_RX_TRIGGER_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_RX_TRIGGER_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_CONNECT_STATUS_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_CONNECT_STATUS_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_MODIFY_BSS_PARAMETER_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_TEMPLATE_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_TEMPLATE_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_CONFIG_QUEUE_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_CONFIG_QUEUE_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_TSPEC_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_TSPEC_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_TSPEC_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_DEL_TSPEC_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_START_AGGREGATION_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_START_AGGREGATION_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLOCKACK_ERROR_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_BLOCKACK_ERROR_INDICATION);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_STOP_AGGREGATION_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_STOP_AGGREGATION_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SM_START_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SM_START_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_LEAVE_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_LEAVE_CONFIRM);
+#endif
+        case CSR_MLME_SET_TIM_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SET_TIM_REQUEST);
+        case CSR_MLME_SET_TIM_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SET_TIM_CONFIRM);
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_GET_KEY_SEQUENCE_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_GET_KEY_SEQUENCE_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SET_CHANNEL_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_SET_CHANNEL_CONFIRM);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_MULTICAST_ADDRESS_REQUEST);
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM);
+#endif
+        case CSR_DEBUG_STRING_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_DEBUG_STRING_INDICATION);
+        case CSR_DEBUG_WORD16_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_DEBUG_WORD16_INDICATION);
+        case CSR_DEBUG_GENERIC_REQUEST_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_DEBUG_GENERIC_REQUEST);
+        case CSR_DEBUG_GENERIC_CONFIRM_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_DEBUG_GENERIC_CONFIRM);
+        case CSR_DEBUG_GENERIC_INDICATION_ID:
+            return CsrOffsetOf(struct CSR_SIGNAL_PRIMITIVE, u) + sizeof(CSR_DEBUG_GENERIC_INDICATION);
+        default:
+            return 0;
+    }
+}
+
+
+CsrInt32 SigGetDataRefs(CSR_SIGNAL *aSignal, CSR_DATAREF **aDataRef)
+{
+    CsrInt32 numRefs = 0;
+
+    switch (aSignal->SignalPrimitiveHeader.SignalId)
+    {
+        case CSR_MA_PACKET_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MaPacketRequest.Data;
+            aDataRef[numRefs++] = &aSignal->u.MaPacketRequest.Dummydataref2;
+            break;
+        case CSR_MA_PACKET_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MaPacketConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MaPacketConfirm.Dummydataref2;
+            break;
+        case CSR_MA_PACKET_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.MaPacketIndication.Data;
+            aDataRef[numRefs++] = &aSignal->u.MaPacketIndication.Dummydataref2;
+            break;
+        case CSR_MA_PACKET_CANCEL_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MaPacketCancelRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MaPacketCancelRequest.Dummydataref2;
+            break;
+        case CSR_MA_VIF_AVAILABILITY_RESPONSE_ID:
+            aDataRef[numRefs++] = &aSignal->u.MaVifAvailabilityResponse.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MaVifAvailabilityResponse.Dummydataref2;
+            break;
+        case CSR_MA_VIF_AVAILABILITY_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.MaVifAvailabilityIndication.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MaVifAvailabilityIndication.Dummydataref2;
+            break;
+        case CSR_MA_PACKET_ERROR_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.MaPacketErrorIndication.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MaPacketErrorIndication.Dummydataref2;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeResetRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeResetRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeResetConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeResetConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetRequest.MibAttribute;
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetConfirm.MibAttributeValue;
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetRequest.MibAttributeValue;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetConfirm.MibAttributeValue;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetNextRequest.MibAttribute;
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetNextRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetNextConfirm.MibAttributeValue;
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetNextConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmePowermgtRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmePowermgtRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmePowermgtConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmePowermgtConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeScanRequest.ChannelList;
+            aDataRef[numRefs++] = &aSignal->u.MlmeScanRequest.InformationElements;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeScanConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeScanConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeHlSyncRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeHlSyncRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeHlSyncConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeHlSyncConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeMeasureRequest.MeasurementRequestSet;
+            aDataRef[numRefs++] = &aSignal->u.MlmeMeasureRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeMeasureConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeMeasureConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeMeasureIndication.MeasurementReportSet;
+            aDataRef[numRefs++] = &aSignal->u.MlmeMeasureIndication.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetkeysRequest.Key;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetkeysRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetkeysConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetkeysConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDeletekeysRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDeletekeysRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDeletekeysConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDeletekeysConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_LOSS_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAutonomousScanLossIndication.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAutonomousScanLossIndication.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECTED_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeConnectedIndication.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeConnectedIndication.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CANCEL_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeScanCancelRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeScanCancelRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeHlSyncCancelRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeHlSyncCancelRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeHlSyncCancelConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeHlSyncCancelConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddPeriodicRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddPeriodicRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddPeriodicConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddPeriodicConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelPeriodicRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelPeriodicRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelPeriodicConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelPeriodicConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddAutonomousScanRequest.ChannelList;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddAutonomousScanRequest.InformationElements;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddAutonomousScanConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddAutonomousScanConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelAutonomousScanRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelAutonomousScanRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelAutonomousScanConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelAutonomousScanConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetPacketFilterRequest.InformationElements;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetPacketFilterRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetPacketFilterConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetPacketFilterConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeStopMeasureRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeStopMeasureRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeStopMeasureConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeStopMeasureConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmePauseAutonomousScanRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmePauseAutonomousScanRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmePauseAutonomousScanConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmePauseAutonomousScanConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_DONE_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAutonomousScanDoneIndication.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAutonomousScanDoneIndication.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTriggeredGetRequest.MibAttribute;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTriggeredGetRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTriggeredGetConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTriggeredGetConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelTriggeredGetRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelTriggeredGetRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelTriggeredGetConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelTriggeredGetConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_TRIGGERED_GET_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeTriggeredGetIndication.MibAttributeValue;
+            aDataRef[numRefs++] = &aSignal->u.MlmeTriggeredGetIndication.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddBlackoutRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddBlackoutRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddBlackoutConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddBlackoutConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLACKOUT_ENDED_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeBlackoutEndedIndication.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeBlackoutEndedIndication.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelBlackoutRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelBlackoutRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelBlackoutConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelBlackoutConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddRxTriggerRequest.InformationElements;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddRxTriggerRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddRxTriggerConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddRxTriggerConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelRxTriggerRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelRxTriggerRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelRxTriggerConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelRxTriggerConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeConnectStatusRequest.InformationElements;
+            aDataRef[numRefs++] = &aSignal->u.MlmeConnectStatusRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeConnectStatusConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeConnectStatusConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeModifyBssParameterRequest.Data;
+            aDataRef[numRefs++] = &aSignal->u.MlmeModifyBssParameterRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeModifyBssParameterConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeModifyBssParameterConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTemplateRequest.Data1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTemplateRequest.Data2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTemplateConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTemplateConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeConfigQueueRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeConfigQueueRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeConfigQueueConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeConfigQueueConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTspecRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTspecRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTspecConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddTspecConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelTspecRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelTspecRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelTspecConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeDelTspecConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeStartAggregationRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeStartAggregationRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeStartAggregationConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeStartAggregationConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLOCKACK_ERROR_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeBlockackErrorIndication.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeBlockackErrorIndication.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeStopAggregationRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeStopAggregationRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeStopAggregationConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeStopAggregationConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSmStartRequest.Beacon;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSmStartRequest.BssParameters;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSmStartConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSmStartConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeLeaveRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeLeaveRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeLeaveConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeLeaveConfirm.Dummydataref2;
+            break;
+#endif
+        case CSR_MLME_SET_TIM_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetTimRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetTimRequest.Dummydataref2;
+            break;
+        case CSR_MLME_SET_TIM_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetTimConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetTimConfirm.Dummydataref2;
+            break;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetKeySequenceRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetKeySequenceRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetKeySequenceConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeGetKeySequenceConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetChannelRequest.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetChannelRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetChannelConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeSetChannelConfirm.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddMulticastAddressRequest.Data;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddMulticastAddressRequest.Dummydataref2;
+            break;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddMulticastAddressConfirm.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.MlmeAddMulticastAddressConfirm.Dummydataref2;
+            break;
+#endif
+        case CSR_DEBUG_STRING_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.DebugStringIndication.DebugMessage;
+            aDataRef[numRefs++] = &aSignal->u.DebugStringIndication.Dummydataref2;
+            break;
+        case CSR_DEBUG_WORD16_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.DebugWord16Indication.Dummydataref1;
+            aDataRef[numRefs++] = &aSignal->u.DebugWord16Indication.Dummydataref2;
+            break;
+        case CSR_DEBUG_GENERIC_REQUEST_ID:
+            aDataRef[numRefs++] = &aSignal->u.DebugGenericRequest.DebugVariable;
+            aDataRef[numRefs++] = &aSignal->u.DebugGenericRequest.Dummydataref2;
+            break;
+        case CSR_DEBUG_GENERIC_CONFIRM_ID:
+            aDataRef[numRefs++] = &aSignal->u.DebugGenericConfirm.DebugVariable;
+            aDataRef[numRefs++] = &aSignal->u.DebugGenericConfirm.Dummydataref2;
+            break;
+        case CSR_DEBUG_GENERIC_INDICATION_ID:
+            aDataRef[numRefs++] = &aSignal->u.DebugGenericIndication.DebugVariable;
+            aDataRef[numRefs++] = &aSignal->u.DebugGenericIndication.Dummydataref2;
+            break;
+        default:
+            return 0;
+    }
+    return numRefs;
+}
+
+
+CsrUint32 SigGetFilterPos(CsrUint16 aSigID)
+{
+    switch (aSigID)
+    {
+        case CSR_MA_PACKET_REQUEST_ID:
+            return 0x00000001;
+        case CSR_MA_PACKET_CONFIRM_ID:
+            return 0x00000002;
+        case CSR_MA_PACKET_INDICATION_ID:
+            return 0x00000004;
+        case CSR_MA_PACKET_CANCEL_REQUEST_ID:
+            return 0x00000008;
+        case CSR_MA_VIF_AVAILABILITY_RESPONSE_ID:
+            return 0x00000010;
+        case CSR_MA_VIF_AVAILABILITY_INDICATION_ID:
+            return 0x00000020;
+        case CSR_MA_PACKET_ERROR_INDICATION_ID:
+            return 0x00000040;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_REQUEST_ID:
+            return 0x00000080;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_RESET_CONFIRM_ID:
+            return 0x00000100;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_REQUEST_ID:
+            return 0x00000200;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_CONFIRM_ID:
+            return 0x00000400;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_REQUEST_ID:
+            return 0x00000800;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CONFIRM_ID:
+            return 0x00001000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_REQUEST_ID:
+            return 0x00002000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_NEXT_CONFIRM_ID:
+            return 0x00004000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_REQUEST_ID:
+            return 0x00008000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_POWERMGT_CONFIRM_ID:
+            return 0x00010001;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_REQUEST_ID:
+            return 0x00010002;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CONFIRM_ID:
+            return 0x00010004;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_REQUEST_ID:
+            return 0x00010008;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CONFIRM_ID:
+            return 0x00010010;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_REQUEST_ID:
+            return 0x00010020;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_CONFIRM_ID:
+            return 0x00010040;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MEASURE_INDICATION_ID:
+            return 0x00010080;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_REQUEST_ID:
+            return 0x00010100;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SETKEYS_CONFIRM_ID:
+            return 0x00010200;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_REQUEST_ID:
+            return 0x00010400;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DELETEKEYS_CONFIRM_ID:
+            return 0x00010800;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_LOSS_INDICATION_ID:
+            return 0x00011000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECTED_INDICATION_ID:
+            return 0x00012000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SCAN_CANCEL_REQUEST_ID:
+            return 0x00014000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_REQUEST_ID:
+            return 0x00018000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_HL_SYNC_CANCEL_CONFIRM_ID:
+            return 0x00020001;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_REQUEST_ID:
+            return 0x00020002;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_PERIODIC_CONFIRM_ID:
+            return 0x00020004;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_REQUEST_ID:
+            return 0x00020008;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_PERIODIC_CONFIRM_ID:
+            return 0x00020010;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_REQUEST_ID:
+            return 0x00020020;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM_ID:
+            return 0x00020040;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_REQUEST_ID:
+            return 0x00020080;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM_ID:
+            return 0x00020100;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_REQUEST_ID:
+            return 0x00020200;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_PACKET_FILTER_CONFIRM_ID:
+            return 0x00020400;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_REQUEST_ID:
+            return 0x00020800;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_MEASURE_CONFIRM_ID:
+            return 0x00021000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_REQUEST_ID:
+            return 0x00022000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM_ID:
+            return 0x00024000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_AUTONOMOUS_SCAN_DONE_INDICATION_ID:
+            return 0x00028000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_REQUEST_ID:
+            return 0x00030001;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TRIGGERED_GET_CONFIRM_ID:
+            return 0x00030002;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_REQUEST_ID:
+            return 0x00030004;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TRIGGERED_GET_CONFIRM_ID:
+            return 0x00030008;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_TRIGGERED_GET_INDICATION_ID:
+            return 0x00030010;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_REQUEST_ID:
+            return 0x00030020;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_BLACKOUT_CONFIRM_ID:
+            return 0x00030040;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLACKOUT_ENDED_INDICATION_ID:
+            return 0x00030080;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_REQUEST_ID:
+            return 0x00030100;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_BLACKOUT_CONFIRM_ID:
+            return 0x00030200;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_REQUEST_ID:
+            return 0x00030400;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_RX_TRIGGER_CONFIRM_ID:
+            return 0x00030800;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_REQUEST_ID:
+            return 0x00031000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_RX_TRIGGER_CONFIRM_ID:
+            return 0x00032000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_REQUEST_ID:
+            return 0x00034000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONNECT_STATUS_CONFIRM_ID:
+            return 0x00038000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_REQUEST_ID:
+            return 0x00040001;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM_ID:
+            return 0x00040002;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_REQUEST_ID:
+            return 0x00040004;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TEMPLATE_CONFIRM_ID:
+            return 0x00040008;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_REQUEST_ID:
+            return 0x00040010;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_CONFIG_QUEUE_CONFIRM_ID:
+            return 0x00040020;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_REQUEST_ID:
+            return 0x00040040;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_TSPEC_CONFIRM_ID:
+            return 0x00040080;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_REQUEST_ID:
+            return 0x00040100;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_DEL_TSPEC_CONFIRM_ID:
+            return 0x00040200;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_REQUEST_ID:
+            return 0x00040400;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_START_AGGREGATION_CONFIRM_ID:
+            return 0x00040800;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_BLOCKACK_ERROR_INDICATION_ID:
+            return 0x00041000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_REQUEST_ID:
+            return 0x00042000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_STOP_AGGREGATION_CONFIRM_ID:
+            return 0x00044000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_REQUEST_ID:
+            return 0x00048000;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SM_START_CONFIRM_ID:
+            return 0x00050001;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_REQUEST_ID:
+            return 0x00050002;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_LEAVE_CONFIRM_ID:
+            return 0x00050004;
+#endif
+        case CSR_MLME_SET_TIM_REQUEST_ID:
+            return 0x00050008;
+        case CSR_MLME_SET_TIM_CONFIRM_ID:
+            return 0x00050010;
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_REQUEST_ID:
+            return 0x00050020;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_GET_KEY_SEQUENCE_CONFIRM_ID:
+            return 0x00050040;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_REQUEST_ID:
+            return 0x00050080;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_SET_CHANNEL_CONFIRM_ID:
+            return 0x00050100;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_REQUEST_ID:
+            return 0x00050200;
+#endif
+#ifdef CSR_WIFI_HIP_FULL_SIGNAL_SET
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM_ID:
+            return 0x00050400;
+#endif
+        case CSR_DEBUG_STRING_INDICATION_ID:
+            return 0x00050800;
+        case CSR_DEBUG_WORD16_INDICATION_ID:
+            return 0x00051000;
+        case CSR_DEBUG_GENERIC_REQUEST_ID:
+            return 0x00052000;
+        case CSR_DEBUG_GENERIC_CONFIRM_ID:
+            return 0x00054000;
+        case CSR_DEBUG_GENERIC_INDICATION_ID:
+            return 0x00058000;
+        default:
+            break;
+    }
+    return 0xffffffff;
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_signals.h b/drivers/staging/csr/csr_wifi_hip_signals.h
new file mode 100644
index 0000000..c48fddd
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_signals.h
@@ -0,0 +1,137 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ *****************************************************************************
+ *
+ * FILE: csr_wifi_hip_signals.h
+ *
+ * PURPOSE:
+ *      Header file wrapping the auto-generated code in csr_wifi_hip_sigs.h
+ *      and csr_wifi_hip_signals.c -
+ *      csr_wifi_hip_sigs.h provides structures defining UniFi signals and
+ *      csr_wifi_hip_signals.c provides SigGetSize() and SigGetDataRefs().
+ *
+ *****************************************************************************
+ */
+#ifndef __CSR_WIFI_HIP_SIGNALS_H__
+#define __CSR_WIFI_HIP_SIGNALS_H__
+
+#include "csr_types.h"
+#include "csr_wifi_hip_sigs.h"
+
+
+/****************************************************************************/
+/* INFORMATION ELEMENTS */
+/****************************************************************************/
+
+/* Information Element ID's - shouldn't be in here, but nowhere better yet */
+#define IE_SSID_ID                       0
+#define IE_SUPPORTED_RATES_ID            1
+#define IE_FH_PARAM_SET_ID               2
+#define IE_DS_PARAM_SET_ID               3
+#define IE_CF_PARAM_SET_ID               4
+#define IE_TIM_ID                        5
+#define IE_IBSS_PARAM_SET_ID             6
+#define IE_COUNTRY_ID                    7
+#define IE_HOPPING_PATTERN_PARAMS_ID     8
+#define IE_HOPPING_PATTERN_TABLE_ID      9
+#define IE_REQUEST_ID                    10
+#define IE_QBSS_LOAD_ID                  11
+#define IE_EDCA_PARAM_SET_ID             12
+#define IE_TRAFFIC_SPEC_ID               13
+#define IE_TRAFFIC_CLASS_ID              14
+#define IE_SCHEDULE_ID                   15
+#define IE_CHALLENGE_TEXT_ID             16
+#define IE_POWER_CONSTRAINT_ID           32
+#define IE_POWER_CAPABILITY_ID           33
+#define IE_TPC_REQUEST_ID                34
+#define IE_TPC_REPORT_ID                 35
+#define IE_SUPPORTED_CHANNELS_ID         36
+#define IE_CHANNEL_SWITCH_ANNOUNCE_ID    37
+#define IE_MEASUREMENT_REQUEST_ID        38
+#define IE_MEASUREMENT_REPORT_ID         39
+#define IE_QUIET_ID                      40
+#define IE_IBSS_DFS_ID                   41
+#define IE_ERP_INFO_ID                   42
+#define IE_TS_DELAY_ID                   43
+#define IE_TCLAS_PROCESSING_ID           44
+#define IE_QOS_CAPABILITY_ID             46
+#define IE_RSN_ID                        48
+#define IE_EXTENDED_SUPPORTED_RATES_ID   50
+#define IE_AP_CHANNEL_REPORT_ID          52
+#define IE_RCPI_ID                       53
+#define IE_WPA_ID                       221
+
+
+/* The maximum number of data references in a signal structure */
+#define UNIFI_MAX_DATA_REFERENCES 2
+
+/* The space to allow for a wire-format signal structure */
+#define UNIFI_PACKED_SIGBUF_SIZE   64
+
+
+/******************************************************************************/
+/* SIGNAL PARAMETER VALUES */
+/******************************************************************************/
+
+/* ifIndex */
+#define UNIFI_IF_2G4 1
+#define UNIFI_IF_5G  2
+
+/* SendProcessId */
+#define HOST_PROC_ID 0xc000
+
+#define SIG_CAP_ESS             0x0001
+#define SIG_CAP_IBSS            0x0002
+#define SIG_CAP_CF_POLLABLE     0x0004
+#define SIG_CAP_CF_POLL_REQUEST 0x0008
+#define SIG_CAP_PRIVACY         0x0010
+#define SIG_CAP_SHORT_PREAMBLE  0x0020
+#define SIG_CAP_DSSSOFDM        0x2000
+
+/******************************************************************************/
+/* FUNCTION DECLARATIONS */
+/******************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/******************************************************************************
+ * SigGetNumDataRefs - Retrieve pointers to data-refs from a signal.
+ *
+ * PARAMETERS:
+ *   aSignal  - Pointer to signal to retrieve the data refs of.
+ *   aDataRef - Address of a pointer to the structure that the data refs
+ *              pointers will be stored.
+ *
+ * RETURNS:
+ *   The number of data-refs in the signal.
+ */
+CsrInt32 SigGetDataRefs(CSR_SIGNAL *aSignal, CSR_DATAREF **aDataRef);
+
+/******************************************************************************
+ * SigGetSize - Retrieve the size (in bytes) of a given signal.
+ *
+ * PARAMETERS:
+ *   aSignal  - Pointer to signal to retrieve size of.
+ *
+ * RETURNS:
+ *   The size (in bytes) of the given signal.
+ */
+CsrInt32 SigGetSize(const CSR_SIGNAL *aSignal);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __CSR_WIFI_HIP_SIGNALS_H__ */
diff --git a/drivers/staging/csr/csr_wifi_hip_sigs.h b/drivers/staging/csr/csr_wifi_hip_sigs.h
new file mode 100644
index 0000000..c94e2a4
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_sigs.h
@@ -0,0 +1,1425 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+
+/* Generated by hip_dd_l_h_gen.pl */
+
+#ifndef CSR_WIFI_HIP_SIGS_H
+#define CSR_WIFI_HIP_SIGS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef CsrInt16 csr_place_holding_type;
+
+typedef CsrUint16 CSR_ASSOCIATION_ID;
+
+typedef CsrUint16 CSR_AUTONOMOUS_SCAN_ID;
+
+typedef CsrUint16 CSR_BEACON_PERIODS;
+
+typedef CsrUint16 CSR_BLACKOUT_ID;
+
+typedef enum CSR_BLACKOUT_SOURCE
+{
+    CSR_DOT11_LOCAL                               = 0x0000,
+    CSR_DOT11_REMOTE                              = 0x0001,
+    CSR_OTHER_RADIO                               = 0x0002,
+    CSR_NOT_LINKED                                = 0x0004
+} CSR_BLACKOUT_SOURCE;
+
+typedef enum CSR_BLACKOUT_TYPE
+{
+    CSR_LOCAL_DEVICE_ONLY                         = 0x0001,
+    CSR_SPECIFIED_PEER                            = 0x0002,
+    CSR_CURRENT_CHANNEL                           = 0x0004,
+    CSR_P2P                                       = 0x0008
+} CSR_BLACKOUT_TYPE;
+
+typedef enum CSR_BOOT_LOADER_OPERATION
+{
+    CSR_BOOT_LOADER_IDLE                          = 0x00,
+    CSR_BOOT_LOADER_RESTART                       = 0x01,
+    CSR_BOOT_LOADER_PATCH                         = 0x02,
+    CSR_BOOT_LOADER_IMAGE_0                       = 0x10,
+    CSR_BOOT_LOADER_IMAGE_1                       = 0x11,
+    CSR_BOOT_LOADER_IMAGE_2                       = 0x12,
+    CSR_BOOT_LOADER_IMAGE_3                       = 0x13
+} CSR_BOOT_LOADER_OPERATION;
+
+typedef CsrUint16 CSR_CAPABILITY_INFORMATION;
+
+typedef CsrUint16 CSR_CHANNEL_STARTING_FACTOR;
+
+typedef CsrUint32 CSR_CIPHER_SUITE_SELECTOR;
+
+typedef CsrUint32 CSR_CLIENT_TAG;
+
+typedef enum CSR_CONNECTION_STATUS
+{
+    CSR_DISCONNECTED                              = 0x0000,
+    CSR_CONNECTED_AWAKE                           = 0x0001
+} CSR_CONNECTION_STATUS;
+
+typedef CsrInt16 CSR_DECIBELS;
+
+typedef enum CSR_DIRECTION
+{
+    CSR_TRANSMIT                                  = 0x0000,
+    CSR_RECEIVE                                   = 0x0001,
+    CSR_BIDIRECTIONAL                             = 0x0003
+} CSR_DIRECTION;
+
+typedef enum CSR_FRAME_TYPE
+{
+    CSR_RESERVED                                  = 0x0000,
+    CSR_BEACON                                    = 0x0001,
+    CSR_PROBE_RESPONSE                            = 0x0002,
+    CSR_BEACON_AND_PROBE_RESPONSE                 = 0x0003,
+    CSR_PROBE_REQUEST                             = 0x0004
+} CSR_FRAME_TYPE;
+
+typedef CsrUint32 CSR_IPV4_ADDRESS;
+
+typedef enum CSR_IFINTERFACE
+{
+    CSR_INDEX_2G4                                 = 0x0001,
+    CSR_INDEX_5G                                  = 0x0002
+} CSR_IFINTERFACE;
+
+typedef enum CSR_KEY_TYPE
+{
+    CSR_GROUP                                     = 0x0000,
+    CSR_PAIRWISE                                  = 0x0001,
+    CSR_PEER_KEY                                  = 0x0002,
+    CSR_IGTK                                      = 0x0003
+} CSR_KEY_TYPE;
+
+typedef enum CSR_LOADER_OPERATION
+{
+    CSR_LOADER_IDLE                               = 0x0000,
+    CSR_LOADER_COPY                               = 0x0001
+} CSR_LOADER_OPERATION;
+
+typedef struct CSR_MAC_ADDRESS
+{
+    CsrUint8 x[6];
+} CSR_MACADDRESS;
+
+typedef enum CSR_MIB_STATUS
+{
+    CSR_MIB_SUCCESSFUL                            = 0x0000,
+    CSR_MIB_INVALID_PARAMETERS                    = 0x0001,
+    CSR_MIB_WRITE_ONLY                            = 0x0002,
+    CSR_MIB_READ_ONLY                             = 0x0003
+} CSR_MIB_STATUS;
+
+typedef enum CSR_MEMORY_SPACE
+{
+    CSR_NONE                                      = 0x00,
+    CSR_SHARED_DATA_MEMORY                        = 0x01,
+    CSR_EXTERNAL_FLASH_MEMORY                     = 0x02,
+    CSR_EXTERNAL_SRAM                             = 0x03,
+    CSR_REGISTERS                                 = 0x04,
+    CSR_PHY_PROCESSOR_DATA_MEMORY                 = 0x10,
+    CSR_PHY_PROCESSOR_PROGRAM_MEMORY              = 0x11,
+    CSR_PHY_PROCESSOR_ROM                         = 0x12,
+    CSR_MAC_PROCESSOR_DATA_MEMORY                 = 0x20,
+    CSR_MAC_PROCESSOR_PROGRAM_MEMORY              = 0x21,
+    CSR_MAC_PROCESSOR_ROM                         = 0x22,
+    CSR_BT_PROCESSOR_DATA_MEMORY                  = 0x30,
+    CSR_BT_PROCESSOR_PROGRAM_MEMORY               = 0x31,
+    CSR_BT_PROCESSOR_ROM                          = 0x32
+} CSR_MEMORY_SPACE;
+
+typedef CsrUint16 CSR_MICROSECONDS16;
+
+typedef CsrUint32 CSR_MICROSECONDS32;
+
+typedef CsrUint16 CSR_NATURAL16;
+
+typedef enum CSR_PS_SCHEME
+{
+    CSR_LEGACY_PS                                 = 0x0001,
+    CSR_U_APSD                                    = 0x0002,
+    CSR_S_APSD                                    = 0x0004
+} CSR_PS_SCHEME;
+
+typedef enum CSR_PACKET_FILTER_MODE
+{
+    CSR_PFM_OPT_OUT                               = 0x0000,
+    CSR_PFM_OPT_IN                                = 0x0003
+} CSR_PACKET_FILTER_MODE;
+
+typedef CsrUint16 CSR_PERIODIC_ID;
+
+typedef enum CSR_PERIODIC_SCHEDULING_MODE
+{
+    CSR_PSM_PERIODIC_SCHEDULE_PS_POLL             = 0x0001,
+    CSR_PSM_PERIODIC_SCHEDULE_PM_BIT              = 0x0002,
+    CSR_PSM_PERIODIC_SCHEDULE_UAPSD               = 0x0004,
+    CSR_PSM_PERIODIC_SCHEDULE_SAPSD               = 0x0008
+} CSR_PERIODIC_SCHEDULING_MODE;
+
+typedef enum CSR_POWER_MANAGEMENT_MODE
+{
+    CSR_PMM_ACTIVE_MODE                           = 0x0000,
+    CSR_PMM_POWER_SAVE                            = 0x0001,
+    CSR_PMM_FAST_POWER_SAVE                       = 0x0002
+} CSR_POWER_MANAGEMENT_MODE;
+
+typedef enum CSR_PRIORITY
+{
+    CSR_QOS_UP0                                   = 0x0000,
+    CSR_QOS_UP1                                   = 0x0001,
+    CSR_QOS_UP2                                   = 0x0002,
+    CSR_QOS_UP3                                   = 0x0003,
+    CSR_QOS_UP4                                   = 0x0004,
+    CSR_QOS_UP5                                   = 0x0005,
+    CSR_QOS_UP6                                   = 0x0006,
+    CSR_QOS_UP7                                   = 0x0007,
+    CSR_CONTENTION                                = 0x8000,
+    CSR_MANAGEMENT                                = 0x8010
+} CSR_PRIORITY;
+
+typedef enum CSR_REASON_CODE
+{
+    CSR_UNSPECIFIED_REASON                        = 0x0001,
+    CSR_INVALID_INFORMATION_ELEMENT               = 0x000d,
+    CSR_QOS_UNSPECIFIED_REASON                    = 0x0020,
+    CSR_QOS_EXCESSIVE_NOT_ACK                     = 0x0022,
+    CSR_QOS_TXOP_LIMIT_EXCEEDED                   = 0x0023,
+    CSR_QSTA_LEAVING                              = 0x0024,
+    CSR_UNKNOWN_BA                                = 0x0026,
+    CSR_UNKNOWN_TS                                = 0x0026,
+    CSR_TIMEOUT                                   = 0x0027
+} CSR_REASON_CODE;
+
+typedef enum CSR_RECEPTION_STATUS
+{
+    CSR_RX_SUCCESS                                = 0x0000,
+    CSR_RX_FAILURE_UNSPECIFIED                    = 0x0001,
+    CSR_MICHAEL_MIC_ERROR                         = 0x0002,
+    CSR_DECRYPTION_ERROR                          = 0x0003,
+    CSR_NO_TEMPORAL_KEY_AVAILABLE                 = 0x0004,
+    CSR_UNSUPPORTED_MODULATION                    = 0x0011,
+    CSR_BAD_FCS                                   = 0x0012,
+    CSR_BAD_SIGNAL                                = 0x0013
+} CSR_RECEPTION_STATUS;
+
+typedef enum CSR_RESULT_CODE
+{
+    CSR_RC_SUCCESS                                = 0x0000,
+    CSR_RC_UNSPECIFIED_FAILURE                    = 0x0001,
+    CSR_RC_REFUSED                                = 0x0003,
+    CSR_RC_INVALID_PARAMETERS                     = 0x0026,
+    CSR_RC_REJECTED_INVALID_IE                    = 0x0028,
+    CSR_RC_REJECTED_INVALID_GROUP_CIPHER          = 0x0029,
+    CSR_RC_REJECTED_INVALID_PAIRWISE_CIPHER       = 0x002a,
+    CSR_RC_TIMEOUT                                = 0x8000,
+    CSR_RC_TOO_MANY_SIMULTANEOUS_REQUESTS         = 0x8001,
+    CSR_RC_BSS_ALREADY_STARTED_OR_JOINED          = 0x8002,
+    CSR_RC_NOT_SUPPORTED                          = 0x8003,
+    CSR_RC_TRANSMISSION_FAILURE                   = 0x8004,
+    CSR_RC_RESET_REQUIRED_BEFORE_START            = 0x8006,
+    CSR_RC_INSUFFICIENT_RESOURCE                  = 0x8007,
+    CSR_RC_NO_BUFFERED_BROADCAST_MULTICAST_FRAMES = 0x8008,
+    CSR_RC_INVALID_UNICAST_CIPHER                 = 0xf02f,
+    CSR_RC_INVALID_MULTICAST_CIPHER               = 0xf030
+} CSR_RESULT_CODE;
+
+typedef enum CSR_SCAN_TYPE
+{
+    CSR_SC_ACTIVE_SCAN                            = 0x0000,
+    CSR_SC_PASSIVE_SCAN                           = 0x0001
+} CSR_SCAN_TYPE;
+
+typedef enum CSR_SIGNAL_ID
+{
+    CSR_MA_PACKET_REQUEST_ID                      = 0x0110,
+    CSR_MA_PACKET_CONFIRM_ID                      = 0x0111,
+    CSR_MA_PACKET_INDICATION_ID                   = 0x0113,
+    CSR_MA_PACKET_CANCEL_REQUEST_ID               = 0x0114,
+    CSR_MA_VIF_AVAILABILITY_RESPONSE_ID           = 0x0116,
+    CSR_MA_VIF_AVAILABILITY_INDICATION_ID         = 0x0117,
+    CSR_MA_PACKET_ERROR_INDICATION_ID             = 0x011b,
+    CSR_MLME_RESET_REQUEST_ID                     = 0x0200,
+    CSR_MLME_RESET_CONFIRM_ID                     = 0x0201,
+    CSR_MLME_GET_REQUEST_ID                       = 0x0204,
+    CSR_MLME_GET_CONFIRM_ID                       = 0x0205,
+    CSR_MLME_SET_REQUEST_ID                       = 0x0208,
+    CSR_MLME_SET_CONFIRM_ID                       = 0x0209,
+    CSR_MLME_GET_NEXT_REQUEST_ID                  = 0x020c,
+    CSR_MLME_GET_NEXT_CONFIRM_ID                  = 0x020d,
+    CSR_MLME_POWERMGT_REQUEST_ID                  = 0x0210,
+    CSR_MLME_POWERMGT_CONFIRM_ID                  = 0x0211,
+    CSR_MLME_SCAN_REQUEST_ID                      = 0x0214,
+    CSR_MLME_SCAN_CONFIRM_ID                      = 0x0215,
+    CSR_MLME_HL_SYNC_REQUEST_ID                   = 0x0244,
+    CSR_MLME_HL_SYNC_CONFIRM_ID                   = 0x0245,
+    CSR_MLME_MEASURE_REQUEST_ID                   = 0x0258,
+    CSR_MLME_MEASURE_CONFIRM_ID                   = 0x0259,
+    CSR_MLME_MEASURE_INDICATION_ID                = 0x025b,
+    CSR_MLME_SETKEYS_REQUEST_ID                   = 0x0268,
+    CSR_MLME_SETKEYS_CONFIRM_ID                   = 0x0269,
+    CSR_MLME_DELETEKEYS_REQUEST_ID                = 0x026c,
+    CSR_MLME_DELETEKEYS_CONFIRM_ID                = 0x026d,
+    CSR_MLME_AUTONOMOUS_SCAN_LOSS_INDICATION_ID   = 0x0287,
+    CSR_MLME_CONNECTED_INDICATION_ID              = 0x028b,
+    CSR_MLME_SCAN_CANCEL_REQUEST_ID               = 0x028c,
+    CSR_MLME_HL_SYNC_CANCEL_REQUEST_ID            = 0x0298,
+    CSR_MLME_HL_SYNC_CANCEL_CONFIRM_ID            = 0x0299,
+    CSR_MLME_ADD_PERIODIC_REQUEST_ID              = 0x02a0,
+    CSR_MLME_ADD_PERIODIC_CONFIRM_ID              = 0x02a1,
+    CSR_MLME_DEL_PERIODIC_REQUEST_ID              = 0x02a4,
+    CSR_MLME_DEL_PERIODIC_CONFIRM_ID              = 0x02a5,
+    CSR_MLME_ADD_AUTONOMOUS_SCAN_REQUEST_ID       = 0x02a8,
+    CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM_ID       = 0x02a9,
+    CSR_MLME_DEL_AUTONOMOUS_SCAN_REQUEST_ID       = 0x02ac,
+    CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM_ID       = 0x02ad,
+    CSR_MLME_SET_PACKET_FILTER_REQUEST_ID         = 0x02b8,
+    CSR_MLME_SET_PACKET_FILTER_CONFIRM_ID         = 0x02b9,
+    CSR_MLME_STOP_MEASURE_REQUEST_ID              = 0x02bc,
+    CSR_MLME_STOP_MEASURE_CONFIRM_ID              = 0x02bd,
+    CSR_MLME_PAUSE_AUTONOMOUS_SCAN_REQUEST_ID     = 0x02cc,
+    CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM_ID     = 0x02cd,
+    CSR_MLME_AUTONOMOUS_SCAN_DONE_INDICATION_ID   = 0x02db,
+    CSR_MLME_ADD_TRIGGERED_GET_REQUEST_ID         = 0x02dc,
+    CSR_MLME_ADD_TRIGGERED_GET_CONFIRM_ID         = 0x02dd,
+    CSR_MLME_DEL_TRIGGERED_GET_REQUEST_ID         = 0x02e0,
+    CSR_MLME_DEL_TRIGGERED_GET_CONFIRM_ID         = 0x02e1,
+    CSR_MLME_TRIGGERED_GET_INDICATION_ID          = 0x02e7,
+    CSR_MLME_ADD_BLACKOUT_REQUEST_ID              = 0x02f8,
+    CSR_MLME_ADD_BLACKOUT_CONFIRM_ID              = 0x02f9,
+    CSR_MLME_BLACKOUT_ENDED_INDICATION_ID         = 0x02fb,
+    CSR_MLME_DEL_BLACKOUT_REQUEST_ID              = 0x02fc,
+    CSR_MLME_DEL_BLACKOUT_CONFIRM_ID              = 0x02fd,
+    CSR_MLME_ADD_RX_TRIGGER_REQUEST_ID            = 0x0304,
+    CSR_MLME_ADD_RX_TRIGGER_CONFIRM_ID            = 0x0305,
+    CSR_MLME_DEL_RX_TRIGGER_REQUEST_ID            = 0x0308,
+    CSR_MLME_DEL_RX_TRIGGER_CONFIRM_ID            = 0x0309,
+    CSR_MLME_CONNECT_STATUS_REQUEST_ID            = 0x0310,
+    CSR_MLME_CONNECT_STATUS_CONFIRM_ID            = 0x0311,
+    CSR_MLME_MODIFY_BSS_PARAMETER_REQUEST_ID      = 0x0314,
+    CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM_ID      = 0x0315,
+    CSR_MLME_ADD_TEMPLATE_REQUEST_ID              = 0x0318,
+    CSR_MLME_ADD_TEMPLATE_CONFIRM_ID              = 0x0319,
+    CSR_MLME_CONFIG_QUEUE_REQUEST_ID              = 0x031c,
+    CSR_MLME_CONFIG_QUEUE_CONFIRM_ID              = 0x031d,
+    CSR_MLME_ADD_TSPEC_REQUEST_ID                 = 0x0320,
+    CSR_MLME_ADD_TSPEC_CONFIRM_ID                 = 0x0321,
+    CSR_MLME_DEL_TSPEC_REQUEST_ID                 = 0x0324,
+    CSR_MLME_DEL_TSPEC_CONFIRM_ID                 = 0x0325,
+    CSR_MLME_START_AGGREGATION_REQUEST_ID         = 0x0328,
+    CSR_MLME_START_AGGREGATION_CONFIRM_ID         = 0x0329,
+    CSR_MLME_BLOCKACK_ERROR_INDICATION_ID         = 0x032b,
+    CSR_MLME_STOP_AGGREGATION_REQUEST_ID          = 0x032c,
+    CSR_MLME_STOP_AGGREGATION_CONFIRM_ID          = 0x032d,
+    CSR_MLME_SM_START_REQUEST_ID                  = 0x0334,
+    CSR_MLME_SM_START_CONFIRM_ID                  = 0x0335,
+    CSR_MLME_LEAVE_REQUEST_ID                     = 0x0338,
+    CSR_MLME_LEAVE_CONFIRM_ID                     = 0x0339,
+    CSR_MLME_SET_TIM_REQUEST_ID                   = 0x033c,
+    CSR_MLME_SET_TIM_CONFIRM_ID                   = 0x033d,
+    CSR_MLME_GET_KEY_SEQUENCE_REQUEST_ID          = 0x0340,
+    CSR_MLME_GET_KEY_SEQUENCE_CONFIRM_ID          = 0x0341,
+    CSR_MLME_SET_CHANNEL_REQUEST_ID               = 0x034c,
+    CSR_MLME_SET_CHANNEL_CONFIRM_ID               = 0x034d,
+    CSR_MLME_ADD_MULTICAST_ADDRESS_REQUEST_ID     = 0x040c,
+    CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM_ID     = 0x040d,
+    CSR_DEBUG_STRING_INDICATION_ID                = 0x0803,
+    CSR_DEBUG_WORD16_INDICATION_ID                = 0x0807,
+    CSR_DEBUG_GENERIC_REQUEST_ID                  = 0x0808,
+    CSR_DEBUG_GENERIC_CONFIRM_ID                  = 0x0809,
+    CSR_DEBUG_GENERIC_INDICATION_ID               = 0x080b
+} CSR_SIGNAL_ID;
+
+typedef CsrUint16 CSR_SIMPLE_POINTER;
+
+typedef CsrUint16 CSR_STARTING_SEQUENCE_NUMBER;
+
+typedef enum CSR_SYMBOL_ID
+{
+    CSR_SLT_END                                   = 0x0000,
+    CSR_SLT_PCI_SLOT_CONFIG                       = 0x0001,
+    CSR_SLT_SDIO_SLOT_CONFIG                      = 0x0002,
+    CSR_SLT_BUILD_ID_NUMBER                       = 0x0003,
+    CSR_SLT_BUILD_ID_STRING                       = 0x0004,
+    CSR_SLT_PERSISTENT_STORE_DB                   = 0x0005,
+    CSR_SLT_RESET_VECTOR_PHY                      = 0x0006,
+    CSR_SLT_RESET_VECTOR_MAC                      = 0x0007,
+    CSR_SLT_SDIO_LOADER_CONTROL                   = 0x0008,
+    CSR_SLT_TEST_CMD                              = 0x0009,
+    CSR_SLT_TEST_ALIVE_COUNTER                    = 0x000a,
+    CSR_SLT_TEST_PARAMETERS                       = 0x000b,
+    CSR_SLT_TEST_RESULTS                          = 0x000c,
+    CSR_SLT_TEST_VERSION                          = 0x000d,
+    CSR_SLT_MIB_PSID_RANGES                       = 0x000e,
+    CSR_SLT_KIP_TABLE                             = 0x000f,
+    CSR_SLT_PANIC_DATA_PHY                        = 0x0010,
+    CSR_SLT_PANIC_DATA_MAC                        = 0x0011,
+    CSR_SLT_BOOT_LOADER_CONTROL                   = 0x0012,
+    CSR_SLT_SOFT_MAC                              = 0x0013
+} CSR_SYMBOL_ID;
+
+typedef struct CSR_TSF_TIME
+{
+    CsrUint8 x[8];
+} CSR_TSF_TIME;
+
+typedef CsrUint16 CSR_TIME_UNITS;
+
+typedef enum CSR_TRANSMISSION_CONTROL
+{
+    CSR_TRIGGERED                                 = 0x0001,
+    CSR_END_OF_SERVICE                            = 0x0002,
+    CSR_NO_CONFIRM_REQUIRED                       = 0x0004,
+    CSR_ALLOW_BA                                  = 0x0008
+} CSR_TRANSMISSION_CONTROL;
+
+typedef enum CSR_TRANSMISSION_STATUS
+{
+    CSR_TX_SUCCESSFUL                             = 0x0000,
+    CSR_TX_RETRY_LIMIT                            = 0x0001,
+    CSR_TX_LIFETIME                               = 0x0002,
+    CSR_TX_NO_BSS                                 = 0x0003,
+    CSR_TX_EXCESSIVE_DATA_LENGTH                  = 0x0004,
+    CSR_TX_UNSUPPORTED_PRIORITY                   = 0x0006,
+    CSR_TX_UNAVAILABLE_PRIORITY                   = 0x0007,
+    CSR_TX_UNAVAILABLE_KEY_MAPPING                = 0x000a,
+    CSR_TX_EDCA_TIMEOUT                           = 0x000b,
+    CSR_TX_BLOCK_ACK_TIMEOUT                      = 0x000c,
+    CSR_TX_FAIL_TRANSMISSION_VIF_INTERRUPTED      = 0x000d,
+    CSR_TX_REJECTED_PEER_STATION_SLEEPING         = 0x000e,
+    CSR_TX_REJECTED_DTIM_ENDED                    = 0x000f,
+    CSR_TX_REJECTED_DTIM_STARTED                  = 0x0010
+} CSR_TRANSMISSION_STATUS;
+
+typedef CsrUint16 CSR_TRIGGER_ID;
+
+typedef CsrUint16 CSR_TRIGGERED_ID;
+
+typedef enum CSR_HIP_VERSIONS
+{
+    CSR_HIP_ENG_VERSION                           = 0x0001,
+    CSR_HIP_VERSION                               = 0x0900
+} CSR_HIP_VERSIONS;
+
+typedef CsrUint16 CSR_BUFFER_HANDLE;
+
+typedef CsrUint16 CSR_CHANNEL_NUMBER;
+
+typedef struct CSR_DATA_REFERENCE
+{
+    CsrUint16 SlotNumber;
+    CsrUint16 DataLength;
+} CSR_DATAREF;
+
+typedef CsrUint16 CSR_DIALOG_TOKEN;
+
+typedef struct CSR_GENERIC_POINTER
+{
+    CsrUint24        MemoryOffset;
+    CSR_MEMORY_SPACE MemorySpace;
+} CSR_GENERIC_POINTER;
+
+typedef struct CSR_MLME_CONFIG_QUEUE_CONFIRM
+{
+    CSR_DATAREF     Dummydataref1;
+    CSR_DATAREF     Dummydataref2;
+    CSR_RESULT_CODE ResultCode;
+} CSR_MLME_CONFIG_QUEUE_CONFIRM;
+
+typedef struct CSR_MLME_CONFIG_QUEUE_REQUEST
+{
+    CSR_DATAREF   Dummydataref1;
+    CSR_DATAREF   Dummydataref2;
+    CSR_NATURAL16 QueueIndex;
+    CSR_NATURAL16 Aifs;
+    CSR_NATURAL16 Cwmin;
+    CSR_NATURAL16 Cwmax;
+    CSR_NATURAL16 TxopLimit;
+} CSR_MLME_CONFIG_QUEUE_REQUEST;
+
+typedef struct CSR_MLME_GET_CONFIRM
+{
+    CSR_DATAREF    MibAttributeValue;
+    CSR_DATAREF    Dummydataref2;
+    CSR_MIB_STATUS Status;
+    CSR_NATURAL16  ErrorIndex;
+} CSR_MLME_GET_CONFIRM;
+
+typedef struct CSR_MLME_GET_REQUEST
+{
+    CSR_DATAREF MibAttribute;
+    CSR_DATAREF Dummydataref2;
+} CSR_MLME_GET_REQUEST;
+
+typedef struct CSR_MLME_GET_NEXT_CONFIRM
+{
+    CSR_DATAREF    MibAttributeValue;
+    CSR_DATAREF    Dummydataref2;
+    CSR_MIB_STATUS Status;
+    CSR_NATURAL16  ErrorIndex;
+} CSR_MLME_GET_NEXT_CONFIRM;
+
+typedef struct CSR_MLME_GET_NEXT_REQUEST
+{
+    CSR_DATAREF MibAttribute;
+    CSR_DATAREF Dummydataref2;
+} CSR_MLME_GET_NEXT_REQUEST;
+
+typedef struct CSR_MLME_HL_SYNC_CONFIRM
+{
+    CSR_DATAREF     Dummydataref1;
+    CSR_DATAREF     Dummydataref2;
+    CSR_MACADDRESS  GroupAddress;
+    CSR_RESULT_CODE ResultCode;
+} CSR_MLME_HL_SYNC_CONFIRM;
+
+typedef struct CSR_MLME_HL_SYNC_REQUEST
+{
+    CSR_DATAREF    Dummydataref1;
+    CSR_DATAREF    Dummydataref2;
+    CSR_MACADDRESS GroupAddress;
+} CSR_MLME_HL_SYNC_REQUEST;
+
+typedef struct CSR_MLME_HL_SYNC_CANCEL_CONFIRM
+{
+    CSR_DATAREF     Dummydataref1;
+    CSR_DATAREF     Dummydataref2;
+    CSR_RESULT_CODE ResultCode;
+} CSR_MLME_HL_SYNC_CANCEL_CONFIRM;
+
+typedef struct CSR_MLME_HL_SYNC_CANCEL_REQUEST
+{
+    CSR_DATAREF    Dummydataref1;
+    CSR_DATAREF    Dummydataref2;
+    CSR_MACADDRESS GroupAddress;
+} CSR_MLME_HL_SYNC_CANCEL_REQUEST;
+
+typedef struct CSR_MLME_MEASURE_CONFIRM
+{
+    CSR_DATAREF      Dummydataref1;
+    CSR_DATAREF      Dummydataref2;
+    CSR_RESULT_CODE  ResultCode;
+    CSR_DIALOG_TOKEN DialogToken;
+} CSR_MLME_MEASURE_CONFIRM;
+
+typedef struct CSR_MLME_MEASURE_INDICATION
+{
+    CSR_DATAREF      MeasurementReportSet;
+    CSR_DATAREF      Dummydataref2;
+    CSR_DIALOG_TOKEN DialogToken;
+} CSR_MLME_MEASURE_INDICATION;
+
+typedef struct CSR_MLME_MEASURE_REQUEST
+{
+    CSR_DATAREF      MeasurementRequestSet;
+    CSR_DATAREF      Dummydataref2;
+    CSR_DIALOG_TOKEN DialogToken;
+} CSR_MLME_MEASURE_REQUEST;
+
+typedef struct CSR_MLME_RESET_CONFIRM
+{
+    CSR_DATAREF     Dummydataref1;
+    CSR_DATAREF     Dummydataref2;
+    CSR_RESULT_CODE ResultCode;
+} CSR_MLME_RESET_CONFIRM;
+
+typedef struct CSR_MLME_RESET_REQUEST
+{
+    CSR_DATAREF    Dummydataref1;
+    CSR_DATAREF    Dummydataref2;
+    CSR_MACADDRESS StaAddress;
+    CsrInt16       SetDefaultMib;
+} CSR_MLME_RESET_REQUEST;
+
+typedef struct CSR_MLME_SET_CONFIRM
+{
+    CSR_DATAREF    MibAttributeValue;
+    CSR_DATAREF    Dummydataref2;
+    CSR_MIB_STATUS Status;
+    CSR_NATURAL16  ErrorIndex;
+} CSR_MLME_SET_CONFIRM;
+
+typedef struct CSR_MLME_SET_REQUEST
+{
+    CSR_DATAREF MibAttributeValue;
+    CSR_DATAREF Dummydataref2;
+} CSR_MLME_SET_REQUEST;
+
+typedef struct CSR_MLME_STOP_MEASURE_CONFIRM
+{
+    CSR_DATAREF      Dummydataref1;
+    CSR_DATAREF      Dummydataref2;
+    CSR_RESULT_CODE  ResultCode;
+    CSR_DIALOG_TOKEN DialogToken;
+} CSR_MLME_STOP_MEASURE_CONFIRM;
+
+typedef struct CSR_MLME_STOP_MEASURE_REQUEST
+{
+    CSR_DATAREF      Dummydataref1;
+    CSR_DATAREF      Dummydataref2;
+    CSR_DIALOG_TOKEN DialogToken;
+} CSR_MLME_STOP_MEASURE_REQUEST;
+
+typedef CsrUint16 CSR_PROCESS_ID;
+
+typedef CsrUint16 CSR_RATE;
+
+typedef CsrUint16 CSR_SEQUENCE_NUMBER;
+
+typedef struct CSR_SIGNAL_PRIMITIVE_HEADER
+{
+    CsrInt16       SignalId;
+    CSR_PROCESS_ID ReceiverProcessId;
+    CSR_PROCESS_ID SenderProcessId;
+} CSR_SIGNAL_PRIMITIVE_HEADER;
+
+typedef CsrUint16 CSR_TRAFFIC_WINDOW;
+
+typedef CsrUint16 CSR_VIF_IDENTIFIER;
+
+typedef struct CSR_DEBUG_GENERIC_CONFIRM
+{
+    CSR_DATAREF   DebugVariable;
+    CSR_DATAREF   Dummydataref2;
+    CSR_NATURAL16 DebugWords[8];
+} CSR_DEBUG_GENERIC_CONFIRM;
+
+typedef struct CSR_DEBUG_GENERIC_INDICATION
+{
+    CSR_DATAREF   DebugVariable;
+    CSR_DATAREF   Dummydataref2;
+    CSR_NATURAL16 DebugWords[8];
+} CSR_DEBUG_GENERIC_INDICATION;
+
+typedef struct CSR_DEBUG_GENERIC_REQUEST
+{
+    CSR_DATAREF   DebugVariable;
+    CSR_DATAREF   Dummydataref2;
+    CSR_NATURAL16 DebugWords[8];
+} CSR_DEBUG_GENERIC_REQUEST;
+
+typedef struct CSR_DEBUG_STRING_INDICATION
+{
+    CSR_DATAREF DebugMessage;
+    CSR_DATAREF Dummydataref2;
+} CSR_DEBUG_STRING_INDICATION;
+
+typedef struct CSR_DEBUG_WORD16_INDICATION
+{
+    CSR_DATAREF   Dummydataref1;
+    CSR_DATAREF   Dummydataref2;
+    CSR_NATURAL16 DebugWords[16];
+} CSR_DEBUG_WORD16_INDICATION;
+
+typedef struct CSR_MA_PACKET_CONFIRM
+{
+    CSR_DATAREF             Dummydataref1;
+    CSR_DATAREF             Dummydataref2;
+    CSR_VIF_IDENTIFIER      VirtualInterfaceIdentifier;
+    CSR_TRANSMISSION_STATUS TransmissionStatus;
+    CSR_NATURAL16           RetryCount;
+    CSR_RATE                Rate;
+    CSR_CLIENT_TAG          HostTag;
+} CSR_MA_PACKET_CONFIRM;
+
+typedef struct CSR_MA_PACKET_INDICATION
+{
+    CSR_DATAREF          Data;
+    CSR_DATAREF          Dummydataref2;
+    CSR_VIF_IDENTIFIER   VirtualInterfaceIdentifier;
+    CSR_TSF_TIME         LocalTime;
+    CSR_IFINTERFACE      Ifindex;
+    CSR_CHANNEL_NUMBER   Channel;
+    CSR_RECEPTION_STATUS ReceptionStatus;
+    CSR_DECIBELS         Rssi;
+    CSR_DECIBELS         Snr;
+    CSR_RATE             ReceivedRate;
+} CSR_MA_PACKET_INDICATION;
+
+typedef struct CSR_MA_PACKET_REQUEST
+{
+    CSR_DATAREF              Data;
+    CSR_DATAREF              Dummydataref2;
+    CSR_VIF_IDENTIFIER       VirtualInterfaceIdentifier;
+    CSR_RATE                 TransmitRate;
+    CSR_CLIENT_TAG           HostTag;
+    CSR_PRIORITY             Priority;
+    CSR_MACADDRESS           Ra;
+    CSR_TRANSMISSION_CONTROL TransmissionControl;
+} CSR_MA_PACKET_REQUEST;
+
+typedef struct CSR_MA_PACKET_CANCEL_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_CLIENT_TAG     HostTag;
+} CSR_MA_PACKET_CANCEL_REQUEST;
+
+typedef struct CSR_MA_PACKET_ERROR_INDICATION
+{
+    CSR_DATAREF         Dummydataref1;
+    CSR_DATAREF         Dummydataref2;
+    CSR_VIF_IDENTIFIER  VirtualInterfaceIdentifier;
+    CSR_MACADDRESS      PeerQstaAddress;
+    CSR_PRIORITY        UserPriority;
+    CSR_SEQUENCE_NUMBER SequenceNumber;
+} CSR_MA_PACKET_ERROR_INDICATION;
+
+typedef struct CSR_MA_VIF_AVAILABILITY_INDICATION
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CsrInt16           Multicast;
+} CSR_MA_VIF_AVAILABILITY_INDICATION;
+
+typedef struct CSR_MA_VIF_AVAILABILITY_RESPONSE
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MA_VIF_AVAILABILITY_RESPONSE;
+
+typedef struct CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM
+{
+    CSR_DATAREF            Dummydataref1;
+    CSR_DATAREF            Dummydataref2;
+    CSR_VIF_IDENTIFIER     VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE        ResultCode;
+    CSR_AUTONOMOUS_SCAN_ID AutonomousScanId;
+} CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM;
+
+typedef struct CSR_MLME_ADD_AUTONOMOUS_SCAN_REQUEST
+{
+    CSR_DATAREF                 ChannelList;
+    CSR_DATAREF                 InformationElements;
+    CSR_VIF_IDENTIFIER          VirtualInterfaceIdentifier;
+    CSR_AUTONOMOUS_SCAN_ID      AutonomousScanId;
+    CSR_IFINTERFACE             Ifindex;
+    CSR_CHANNEL_STARTING_FACTOR ChannelStartingFactor;
+    CSR_SCAN_TYPE               ScanType;
+    CSR_MICROSECONDS32          ProbeDelay;
+    CSR_TIME_UNITS              MinChannelTime;
+    CSR_TIME_UNITS              MaxChannelTime;
+} CSR_MLME_ADD_AUTONOMOUS_SCAN_REQUEST;
+
+typedef struct CSR_MLME_ADD_BLACKOUT_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_BLACKOUT_ID    BlackoutId;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_ADD_BLACKOUT_CONFIRM;
+
+typedef struct CSR_MLME_ADD_BLACKOUT_REQUEST
+{
+    CSR_DATAREF         Dummydataref1;
+    CSR_DATAREF         Dummydataref2;
+    CSR_VIF_IDENTIFIER  VirtualInterfaceIdentifier;
+    CSR_BLACKOUT_ID     BlackoutId;
+    CSR_BLACKOUT_TYPE   BlackoutType;
+    CSR_BLACKOUT_SOURCE BlackoutSource;
+    CSR_MICROSECONDS32  BlackoutStartReference;
+    CSR_MICROSECONDS32  BlackoutPeriod;
+    CSR_MICROSECONDS32  BlackoutDuration;
+    CSR_MACADDRESS      PeerStaAddress;
+    CSR_NATURAL16       BlackoutCount;
+} CSR_MLME_ADD_BLACKOUT_REQUEST;
+
+typedef struct CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM;
+
+typedef struct CSR_MLME_ADD_MULTICAST_ADDRESS_REQUEST
+{
+    CSR_DATAREF        Data;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_NATURAL16      NumberOfMulticastGroupAddresses;
+} CSR_MLME_ADD_MULTICAST_ADDRESS_REQUEST;
+
+typedef struct CSR_MLME_ADD_PERIODIC_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_PERIODIC_ID    PeriodicId;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_ADD_PERIODIC_CONFIRM;
+
+typedef struct CSR_MLME_ADD_PERIODIC_REQUEST
+{
+    CSR_DATAREF                  Dummydataref1;
+    CSR_DATAREF                  Dummydataref2;
+    CSR_VIF_IDENTIFIER           VirtualInterfaceIdentifier;
+    CSR_PERIODIC_ID              PeriodicId;
+    CSR_MICROSECONDS32           MaximumLatency;
+    CSR_PERIODIC_SCHEDULING_MODE PeriodicSchedulingMode;
+    CsrInt16                     WakeHost;
+    CSR_PRIORITY                 UserPriority;
+} CSR_MLME_ADD_PERIODIC_REQUEST;
+
+typedef struct CSR_MLME_ADD_RX_TRIGGER_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_TRIGGER_ID     TriggerId;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_ADD_RX_TRIGGER_CONFIRM;
+
+typedef struct CSR_MLME_ADD_RX_TRIGGER_REQUEST
+{
+    CSR_DATAREF        InformationElements;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_TRIGGER_ID     TriggerId;
+    CSR_PRIORITY       Priority;
+} CSR_MLME_ADD_RX_TRIGGER_REQUEST;
+
+typedef struct CSR_MLME_ADD_TEMPLATE_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_FRAME_TYPE     FrameType;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_ADD_TEMPLATE_CONFIRM;
+
+typedef struct CSR_MLME_ADD_TEMPLATE_REQUEST
+{
+    CSR_DATAREF        Data1;
+    CSR_DATAREF        Data2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_FRAME_TYPE     FrameType;
+    CSR_RATE           MinTransmitRate;
+} CSR_MLME_ADD_TEMPLATE_REQUEST;
+
+typedef struct CSR_MLME_ADD_TRIGGERED_GET_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+    CSR_TRIGGERED_ID   TriggeredId;
+} CSR_MLME_ADD_TRIGGERED_GET_CONFIRM;
+
+typedef struct CSR_MLME_ADD_TRIGGERED_GET_REQUEST
+{
+    CSR_DATAREF        MibAttribute;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_TRIGGERED_ID   TriggeredId;
+} CSR_MLME_ADD_TRIGGERED_GET_REQUEST;
+
+typedef struct CSR_MLME_ADD_TSPEC_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_PRIORITY       UserPriority;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_ADD_TSPEC_CONFIRM;
+
+typedef struct CSR_MLME_ADD_TSPEC_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_PRIORITY       UserPriority;
+    CSR_DIRECTION      Direction;
+    CSR_PS_SCHEME      PsScheme;
+    CSR_NATURAL16      MediumTime;
+    CSR_MICROSECONDS32 ServiceStartTime;
+    CSR_MICROSECONDS32 ServiceInterval;
+    CSR_RATE           MinimumDataRate;
+} CSR_MLME_ADD_TSPEC_REQUEST;
+
+typedef struct CSR_MLME_AUTONOMOUS_SCAN_DONE_INDICATION
+{
+    CSR_DATAREF            Dummydataref1;
+    CSR_DATAREF            Dummydataref2;
+    CSR_VIF_IDENTIFIER     VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE        ResultCode;
+    CSR_AUTONOMOUS_SCAN_ID AutonomousScanId;
+} CSR_MLME_AUTONOMOUS_SCAN_DONE_INDICATION;
+
+typedef struct CSR_MLME_AUTONOMOUS_SCAN_LOSS_INDICATION
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_MACADDRESS     Bssid;
+} CSR_MLME_AUTONOMOUS_SCAN_LOSS_INDICATION;
+
+typedef struct CSR_MLME_BLACKOUT_ENDED_INDICATION
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_BLACKOUT_ID    BlackoutId;
+} CSR_MLME_BLACKOUT_ENDED_INDICATION;
+
+typedef struct CSR_MLME_BLOCKACK_ERROR_INDICATION
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_REASON_CODE    ResultCode;
+    CSR_MACADDRESS     PeerQstaAddress;
+} CSR_MLME_BLOCKACK_ERROR_INDICATION;
+
+typedef struct CSR_MLME_CONNECTED_INDICATION
+{
+    CSR_DATAREF           Dummydataref1;
+    CSR_DATAREF           Dummydataref2;
+    CSR_VIF_IDENTIFIER    VirtualInterfaceIdentifier;
+    CSR_CONNECTION_STATUS ConnectionStatus;
+    CSR_MACADDRESS        PeerMacAddress;
+} CSR_MLME_CONNECTED_INDICATION;
+
+typedef struct CSR_MLME_CONNECT_STATUS_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_CONNECT_STATUS_CONFIRM;
+
+typedef struct CSR_MLME_CONNECT_STATUS_REQUEST
+{
+    CSR_DATAREF                InformationElements;
+    CSR_DATAREF                Dummydataref2;
+    CSR_VIF_IDENTIFIER         VirtualInterfaceIdentifier;
+    CSR_CONNECTION_STATUS      ConnectionStatus;
+    CSR_MACADDRESS             StaAddress;
+    CSR_ASSOCIATION_ID         AssociationId;
+    CSR_CAPABILITY_INFORMATION AssociationCapabilityInformation;
+} CSR_MLME_CONNECT_STATUS_REQUEST;
+
+typedef struct CSR_MLME_DELETEKEYS_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_DELETEKEYS_CONFIRM;
+
+typedef struct CSR_MLME_DELETEKEYS_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_NATURAL16      KeyId;
+    CSR_KEY_TYPE       KeyType;
+    CSR_MACADDRESS     Address;
+} CSR_MLME_DELETEKEYS_REQUEST;
+
+typedef struct CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM
+{
+    CSR_DATAREF            Dummydataref1;
+    CSR_DATAREF            Dummydataref2;
+    CSR_VIF_IDENTIFIER     VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE        ResultCode;
+    CSR_AUTONOMOUS_SCAN_ID AutonomousScanId;
+} CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM;
+
+typedef struct CSR_MLME_DEL_AUTONOMOUS_SCAN_REQUEST
+{
+    CSR_DATAREF            Dummydataref1;
+    CSR_DATAREF            Dummydataref2;
+    CSR_VIF_IDENTIFIER     VirtualInterfaceIdentifier;
+    CSR_AUTONOMOUS_SCAN_ID AutonomousScanId;
+} CSR_MLME_DEL_AUTONOMOUS_SCAN_REQUEST;
+
+typedef struct CSR_MLME_DEL_BLACKOUT_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_BLACKOUT_ID    BlackoutId;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_DEL_BLACKOUT_CONFIRM;
+
+typedef struct CSR_MLME_DEL_BLACKOUT_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_BLACKOUT_ID    BlackoutId;
+} CSR_MLME_DEL_BLACKOUT_REQUEST;
+
+typedef struct CSR_MLME_DEL_PERIODIC_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_PERIODIC_ID    PeriodicId;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_DEL_PERIODIC_CONFIRM;
+
+typedef struct CSR_MLME_DEL_PERIODIC_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_PERIODIC_ID    PeriodicId;
+} CSR_MLME_DEL_PERIODIC_REQUEST;
+
+typedef struct CSR_MLME_DEL_RX_TRIGGER_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_TRIGGER_ID     TriggerId;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_DEL_RX_TRIGGER_CONFIRM;
+
+typedef struct CSR_MLME_DEL_RX_TRIGGER_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_TRIGGER_ID     TriggerId;
+} CSR_MLME_DEL_RX_TRIGGER_REQUEST;
+
+typedef struct CSR_MLME_DEL_TRIGGERED_GET_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+    CSR_TRIGGERED_ID   TriggeredId;
+} CSR_MLME_DEL_TRIGGERED_GET_CONFIRM;
+
+typedef struct CSR_MLME_DEL_TRIGGERED_GET_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_TRIGGERED_ID   TriggeredId;
+} CSR_MLME_DEL_TRIGGERED_GET_REQUEST;
+
+typedef struct CSR_MLME_DEL_TSPEC_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_PRIORITY       UserPriority;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_DEL_TSPEC_CONFIRM;
+
+typedef struct CSR_MLME_DEL_TSPEC_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_PRIORITY       UserPriority;
+    CSR_DIRECTION      Direction;
+} CSR_MLME_DEL_TSPEC_REQUEST;
+
+typedef struct CSR_MLME_GET_KEY_SEQUENCE_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+    CSR_NATURAL16      SequenceNumber[8];
+} CSR_MLME_GET_KEY_SEQUENCE_CONFIRM;
+
+typedef struct CSR_MLME_GET_KEY_SEQUENCE_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_NATURAL16      KeyId;
+    CSR_KEY_TYPE       KeyType;
+    CSR_MACADDRESS     Address;
+} CSR_MLME_GET_KEY_SEQUENCE_REQUEST;
+
+typedef struct CSR_MLME_LEAVE_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_LEAVE_CONFIRM;
+
+typedef struct CSR_MLME_LEAVE_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+} CSR_MLME_LEAVE_REQUEST;
+
+typedef struct CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM;
+
+typedef struct CSR_MLME_MODIFY_BSS_PARAMETER_REQUEST
+{
+    CSR_DATAREF                Data;
+    CSR_DATAREF                Dummydataref2;
+    CSR_VIF_IDENTIFIER         VirtualInterfaceIdentifier;
+    CSR_TIME_UNITS             BeaconPeriod;
+    CSR_BEACON_PERIODS         DtimPeriod;
+    CSR_CAPABILITY_INFORMATION CapabilityInformation;
+    CSR_MACADDRESS             Bssid;
+    CSR_NATURAL16              RtsThreshold;
+} CSR_MLME_MODIFY_BSS_PARAMETER_REQUEST;
+
+typedef struct CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM
+{
+    CSR_DATAREF            Dummydataref1;
+    CSR_DATAREF            Dummydataref2;
+    CSR_VIF_IDENTIFIER     VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE        ResultCode;
+    CSR_AUTONOMOUS_SCAN_ID AutonomousScanId;
+} CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM;
+
+typedef struct CSR_MLME_PAUSE_AUTONOMOUS_SCAN_REQUEST
+{
+    CSR_DATAREF            Dummydataref1;
+    CSR_DATAREF            Dummydataref2;
+    CSR_VIF_IDENTIFIER     VirtualInterfaceIdentifier;
+    CSR_AUTONOMOUS_SCAN_ID AutonomousScanId;
+    CsrInt16               Pause;
+} CSR_MLME_PAUSE_AUTONOMOUS_SCAN_REQUEST;
+
+typedef struct CSR_MLME_POWERMGT_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_POWERMGT_CONFIRM;
+
+typedef struct CSR_MLME_POWERMGT_REQUEST
+{
+    CSR_DATAREF               Dummydataref1;
+    CSR_DATAREF               Dummydataref2;
+    CSR_VIF_IDENTIFIER        VirtualInterfaceIdentifier;
+    CSR_POWER_MANAGEMENT_MODE PowerManagementMode;
+    CsrInt16                  ReceiveDtims;
+    CSR_BEACON_PERIODS        ListenInterval;
+    CSR_TRAFFIC_WINDOW        TrafficWindow;
+} CSR_MLME_POWERMGT_REQUEST;
+
+typedef struct CSR_MLME_SCAN_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_SCAN_CONFIRM;
+
+typedef struct CSR_MLME_SCAN_REQUEST
+{
+    CSR_DATAREF        ChannelList;
+    CSR_DATAREF        InformationElements;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_IFINTERFACE    Ifindex;
+    CSR_SCAN_TYPE      ScanType;
+    CSR_MICROSECONDS32 ProbeDelay;
+    CSR_TIME_UNITS     MinChannelTime;
+    CSR_TIME_UNITS     MaxChannelTime;
+} CSR_MLME_SCAN_REQUEST;
+
+typedef struct CSR_MLME_SCAN_CANCEL_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+} CSR_MLME_SCAN_CANCEL_REQUEST;
+
+typedef struct CSR_MLME_SETKEYS_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_SETKEYS_CONFIRM;
+
+typedef struct CSR_MLME_SETKEYS_REQUEST
+{
+    CSR_DATAREF               Key;
+    CSR_DATAREF               Dummydataref2;
+    CSR_VIF_IDENTIFIER        VirtualInterfaceIdentifier;
+    CSR_NATURAL16             Length;
+    CSR_NATURAL16             KeyId;
+    CSR_KEY_TYPE              KeyType;
+    CSR_MACADDRESS            Address;
+    CSR_NATURAL16             SequenceNumber[8];
+    CSR_CIPHER_SUITE_SELECTOR CipherSuiteSelector;
+} CSR_MLME_SETKEYS_REQUEST;
+
+typedef struct CSR_MLME_SET_CHANNEL_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_SET_CHANNEL_CONFIRM;
+
+typedef struct CSR_MLME_SET_CHANNEL_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_IFINTERFACE    Ifindex;
+    CSR_CHANNEL_NUMBER Channel;
+    CSR_MACADDRESS     Address;
+    CSR_TIME_UNITS     AvailabilityDuration;
+    CSR_TIME_UNITS     AvailabilityInterval;
+} CSR_MLME_SET_CHANNEL_REQUEST;
+
+typedef struct CSR_MLME_SET_PACKET_FILTER_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_SET_PACKET_FILTER_CONFIRM;
+
+typedef struct CSR_MLME_SET_PACKET_FILTER_REQUEST
+{
+    CSR_DATAREF            InformationElements;
+    CSR_DATAREF            Dummydataref2;
+    CSR_VIF_IDENTIFIER     VirtualInterfaceIdentifier;
+    CSR_PACKET_FILTER_MODE PacketFilterMode;
+    CSR_IPV4_ADDRESS       ArpFilterAddress;
+} CSR_MLME_SET_PACKET_FILTER_REQUEST;
+
+typedef struct CSR_MLME_SET_TIM_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_SET_TIM_CONFIRM;
+
+typedef struct CSR_MLME_SET_TIM_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_ASSOCIATION_ID AssociationId;
+    CsrInt16           TimValue;
+} CSR_MLME_SET_TIM_REQUEST;
+
+typedef struct CSR_MLME_SM_START_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_SM_START_CONFIRM;
+
+typedef struct CSR_MLME_SM_START_REQUEST
+{
+    CSR_DATAREF                Beacon;
+    CSR_DATAREF                BssParameters;
+    CSR_VIF_IDENTIFIER         VirtualInterfaceIdentifier;
+    CSR_IFINTERFACE            Ifindex;
+    CSR_CHANNEL_NUMBER         Channel;
+    CSR_MACADDRESS             InterfaceAddress;
+    CSR_MACADDRESS             Bssid;
+    CSR_TIME_UNITS             BeaconPeriod;
+    CSR_BEACON_PERIODS         DtimPeriod;
+    CSR_CAPABILITY_INFORMATION CapabilityInformation;
+} CSR_MLME_SM_START_REQUEST;
+
+typedef struct CSR_MLME_START_AGGREGATION_CONFIRM
+{
+    CSR_DATAREF         Dummydataref1;
+    CSR_DATAREF         Dummydataref2;
+    CSR_VIF_IDENTIFIER  VirtualInterfaceIdentifier;
+    CSR_MACADDRESS      PeerQstaAddress;
+    CSR_PRIORITY        UserPriority;
+    CSR_DIRECTION       Direction;
+    CSR_RESULT_CODE     ResultCode;
+    CSR_SEQUENCE_NUMBER SequenceNumber;
+} CSR_MLME_START_AGGREGATION_CONFIRM;
+
+typedef struct CSR_MLME_START_AGGREGATION_REQUEST
+{
+    CSR_DATAREF                  Dummydataref1;
+    CSR_DATAREF                  Dummydataref2;
+    CSR_VIF_IDENTIFIER           VirtualInterfaceIdentifier;
+    CSR_MACADDRESS               PeerQstaAddress;
+    CSR_PRIORITY                 UserPriority;
+    CSR_DIRECTION                Direction;
+    CSR_STARTING_SEQUENCE_NUMBER StartingSequenceNumber;
+    CSR_NATURAL16                BufferSize;
+    CSR_TIME_UNITS               BlockAckTimeout;
+} CSR_MLME_START_AGGREGATION_REQUEST;
+
+typedef struct CSR_MLME_STOP_AGGREGATION_CONFIRM
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_MACADDRESS     PeerQstaAddress;
+    CSR_PRIORITY       UserPriority;
+    CSR_DIRECTION      Direction;
+    CSR_RESULT_CODE    ResultCode;
+} CSR_MLME_STOP_AGGREGATION_CONFIRM;
+
+typedef struct CSR_MLME_STOP_AGGREGATION_REQUEST
+{
+    CSR_DATAREF        Dummydataref1;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_MACADDRESS     PeerQstaAddress;
+    CSR_PRIORITY       UserPriority;
+    CSR_DIRECTION      Direction;
+} CSR_MLME_STOP_AGGREGATION_REQUEST;
+
+typedef struct CSR_MLME_TRIGGERED_GET_INDICATION
+{
+    CSR_DATAREF        MibAttributeValue;
+    CSR_DATAREF        Dummydataref2;
+    CSR_VIF_IDENTIFIER VirtualInterfaceIdentifier;
+    CSR_MIB_STATUS     Status;
+    CSR_NATURAL16      ErrorIndex;
+    CSR_TRIGGERED_ID   TriggeredId;
+} CSR_MLME_TRIGGERED_GET_INDICATION;
+
+typedef struct CSR_SIGNAL_PRIMITIVE
+{
+    CSR_SIGNAL_PRIMITIVE_HEADER SignalPrimitiveHeader;
+    union
+    {
+        CSR_MA_PACKET_REQUEST                    MaPacketRequest;
+        CSR_MA_PACKET_CONFIRM                    MaPacketConfirm;
+        CSR_MA_PACKET_INDICATION                 MaPacketIndication;
+        CSR_MA_PACKET_CANCEL_REQUEST             MaPacketCancelRequest;
+        CSR_MA_VIF_AVAILABILITY_RESPONSE         MaVifAvailabilityResponse;
+        CSR_MA_VIF_AVAILABILITY_INDICATION       MaVifAvailabilityIndication;
+        CSR_MA_PACKET_ERROR_INDICATION           MaPacketErrorIndication;
+        CSR_MLME_RESET_REQUEST                   MlmeResetRequest;
+        CSR_MLME_RESET_CONFIRM                   MlmeResetConfirm;
+        CSR_MLME_GET_REQUEST                     MlmeGetRequest;
+        CSR_MLME_GET_CONFIRM                     MlmeGetConfirm;
+        CSR_MLME_SET_REQUEST                     MlmeSetRequest;
+        CSR_MLME_SET_CONFIRM                     MlmeSetConfirm;
+        CSR_MLME_GET_NEXT_REQUEST                MlmeGetNextRequest;
+        CSR_MLME_GET_NEXT_CONFIRM                MlmeGetNextConfirm;
+        CSR_MLME_POWERMGT_REQUEST                MlmePowermgtRequest;
+        CSR_MLME_POWERMGT_CONFIRM                MlmePowermgtConfirm;
+        CSR_MLME_SCAN_REQUEST                    MlmeScanRequest;
+        CSR_MLME_SCAN_CONFIRM                    MlmeScanConfirm;
+        CSR_MLME_HL_SYNC_REQUEST                 MlmeHlSyncRequest;
+        CSR_MLME_HL_SYNC_CONFIRM                 MlmeHlSyncConfirm;
+        CSR_MLME_MEASURE_REQUEST                 MlmeMeasureRequest;
+        CSR_MLME_MEASURE_CONFIRM                 MlmeMeasureConfirm;
+        CSR_MLME_MEASURE_INDICATION              MlmeMeasureIndication;
+        CSR_MLME_SETKEYS_REQUEST                 MlmeSetkeysRequest;
+        CSR_MLME_SETKEYS_CONFIRM                 MlmeSetkeysConfirm;
+        CSR_MLME_DELETEKEYS_REQUEST              MlmeDeletekeysRequest;
+        CSR_MLME_DELETEKEYS_CONFIRM              MlmeDeletekeysConfirm;
+        CSR_MLME_AUTONOMOUS_SCAN_LOSS_INDICATION MlmeAutonomousScanLossIndication;
+        CSR_MLME_CONNECTED_INDICATION            MlmeConnectedIndication;
+        CSR_MLME_SCAN_CANCEL_REQUEST             MlmeScanCancelRequest;
+        CSR_MLME_HL_SYNC_CANCEL_REQUEST          MlmeHlSyncCancelRequest;
+        CSR_MLME_HL_SYNC_CANCEL_CONFIRM          MlmeHlSyncCancelConfirm;
+        CSR_MLME_ADD_PERIODIC_REQUEST            MlmeAddPeriodicRequest;
+        CSR_MLME_ADD_PERIODIC_CONFIRM            MlmeAddPeriodicConfirm;
+        CSR_MLME_DEL_PERIODIC_REQUEST            MlmeDelPeriodicRequest;
+        CSR_MLME_DEL_PERIODIC_CONFIRM            MlmeDelPeriodicConfirm;
+        CSR_MLME_ADD_AUTONOMOUS_SCAN_REQUEST     MlmeAddAutonomousScanRequest;
+        CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM     MlmeAddAutonomousScanConfirm;
+        CSR_MLME_DEL_AUTONOMOUS_SCAN_REQUEST     MlmeDelAutonomousScanRequest;
+        CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM     MlmeDelAutonomousScanConfirm;
+        CSR_MLME_SET_PACKET_FILTER_REQUEST       MlmeSetPacketFilterRequest;
+        CSR_MLME_SET_PACKET_FILTER_CONFIRM       MlmeSetPacketFilterConfirm;
+        CSR_MLME_STOP_MEASURE_REQUEST            MlmeStopMeasureRequest;
+        CSR_MLME_STOP_MEASURE_CONFIRM            MlmeStopMeasureConfirm;
+        CSR_MLME_PAUSE_AUTONOMOUS_SCAN_REQUEST   MlmePauseAutonomousScanRequest;
+        CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM   MlmePauseAutonomousScanConfirm;
+        CSR_MLME_AUTONOMOUS_SCAN_DONE_INDICATION MlmeAutonomousScanDoneIndication;
+        CSR_MLME_ADD_TRIGGERED_GET_REQUEST       MlmeAddTriggeredGetRequest;
+        CSR_MLME_ADD_TRIGGERED_GET_CONFIRM       MlmeAddTriggeredGetConfirm;
+        CSR_MLME_DEL_TRIGGERED_GET_REQUEST       MlmeDelTriggeredGetRequest;
+        CSR_MLME_DEL_TRIGGERED_GET_CONFIRM       MlmeDelTriggeredGetConfirm;
+        CSR_MLME_TRIGGERED_GET_INDICATION        MlmeTriggeredGetIndication;
+        CSR_MLME_ADD_BLACKOUT_REQUEST            MlmeAddBlackoutRequest;
+        CSR_MLME_ADD_BLACKOUT_CONFIRM            MlmeAddBlackoutConfirm;
+        CSR_MLME_BLACKOUT_ENDED_INDICATION       MlmeBlackoutEndedIndication;
+        CSR_MLME_DEL_BLACKOUT_REQUEST            MlmeDelBlackoutRequest;
+        CSR_MLME_DEL_BLACKOUT_CONFIRM            MlmeDelBlackoutConfirm;
+        CSR_MLME_ADD_RX_TRIGGER_REQUEST          MlmeAddRxTriggerRequest;
+        CSR_MLME_ADD_RX_TRIGGER_CONFIRM          MlmeAddRxTriggerConfirm;
+        CSR_MLME_DEL_RX_TRIGGER_REQUEST          MlmeDelRxTriggerRequest;
+        CSR_MLME_DEL_RX_TRIGGER_CONFIRM          MlmeDelRxTriggerConfirm;
+        CSR_MLME_CONNECT_STATUS_REQUEST          MlmeConnectStatusRequest;
+        CSR_MLME_CONNECT_STATUS_CONFIRM          MlmeConnectStatusConfirm;
+        CSR_MLME_MODIFY_BSS_PARAMETER_REQUEST    MlmeModifyBssParameterRequest;
+        CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM    MlmeModifyBssParameterConfirm;
+        CSR_MLME_ADD_TEMPLATE_REQUEST            MlmeAddTemplateRequest;
+        CSR_MLME_ADD_TEMPLATE_CONFIRM            MlmeAddTemplateConfirm;
+        CSR_MLME_CONFIG_QUEUE_REQUEST            MlmeConfigQueueRequest;
+        CSR_MLME_CONFIG_QUEUE_CONFIRM            MlmeConfigQueueConfirm;
+        CSR_MLME_ADD_TSPEC_REQUEST               MlmeAddTspecRequest;
+        CSR_MLME_ADD_TSPEC_CONFIRM               MlmeAddTspecConfirm;
+        CSR_MLME_DEL_TSPEC_REQUEST               MlmeDelTspecRequest;
+        CSR_MLME_DEL_TSPEC_CONFIRM               MlmeDelTspecConfirm;
+        CSR_MLME_START_AGGREGATION_REQUEST       MlmeStartAggregationRequest;
+        CSR_MLME_START_AGGREGATION_CONFIRM       MlmeStartAggregationConfirm;
+        CSR_MLME_BLOCKACK_ERROR_INDICATION       MlmeBlockackErrorIndication;
+        CSR_MLME_STOP_AGGREGATION_REQUEST        MlmeStopAggregationRequest;
+        CSR_MLME_STOP_AGGREGATION_CONFIRM        MlmeStopAggregationConfirm;
+        CSR_MLME_SM_START_REQUEST                MlmeSmStartRequest;
+        CSR_MLME_SM_START_CONFIRM                MlmeSmStartConfirm;
+        CSR_MLME_LEAVE_REQUEST                   MlmeLeaveRequest;
+        CSR_MLME_LEAVE_CONFIRM                   MlmeLeaveConfirm;
+        CSR_MLME_SET_TIM_REQUEST                 MlmeSetTimRequest;
+        CSR_MLME_SET_TIM_CONFIRM                 MlmeSetTimConfirm;
+        CSR_MLME_GET_KEY_SEQUENCE_REQUEST        MlmeGetKeySequenceRequest;
+        CSR_MLME_GET_KEY_SEQUENCE_CONFIRM        MlmeGetKeySequenceConfirm;
+        CSR_MLME_SET_CHANNEL_REQUEST             MlmeSetChannelRequest;
+        CSR_MLME_SET_CHANNEL_CONFIRM             MlmeSetChannelConfirm;
+        CSR_MLME_ADD_MULTICAST_ADDRESS_REQUEST   MlmeAddMulticastAddressRequest;
+        CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM   MlmeAddMulticastAddressConfirm;
+        CSR_DEBUG_STRING_INDICATION              DebugStringIndication;
+        CSR_DEBUG_WORD16_INDICATION              DebugWord16Indication;
+        CSR_DEBUG_GENERIC_REQUEST                DebugGenericRequest;
+        CSR_DEBUG_GENERIC_CONFIRM                DebugGenericConfirm;
+        CSR_DEBUG_GENERIC_INDICATION             DebugGenericIndication;
+    } u;
+} CSR_SIGNAL;
+
+#define SIG_FILTER_SIZE 6
+
+CsrUint32 SigGetFilterPos(CsrUint16 aSigID);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/csr_wifi_hip_ta_sampling.c b/drivers/staging/csr/csr_wifi_hip_ta_sampling.c
new file mode 100644
index 0000000..7afcd3c
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_ta_sampling.c
@@ -0,0 +1,541 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     csr_wifi_hip_ta_sampling.c
+ *
+ *  PURPOSE:
+ *      The traffic analysis sampling module.
+ *      This gathers data which is sent to the SME and used to analyse
+ *      the traffic behaviour.
+ *
+ * Provides:
+ *      unifi_ta_sampling_init - Initialise the internal state
+ *      unifi_ta_sample        - Sampling function, call this for every data packet
+ *
+ * Calls these external functions which must be provided:
+ *      unifi_ta_indicate_sampling - Pass sample data to the SME.
+ *      unifi_ta_indicate_protocol - Report certain data packet types to the SME.
+ * ---------------------------------------------------------------------------
+ */
+
+#include "csr_wifi_hip_card_sdio.h"
+
+/* Maximum number of Tx frames we store each CYCLE_1, for detecting period */
+#define TA_MAX_INTERVALS_IN_C1          100
+
+/* Number of intervals in CYCLE_1 (one second), for detecting periodic */
+/* Must match size of unifi_TrafficStats.intervals - 1 */
+#define TA_INTERVALS_NUM               10
+
+/* Step (in msecs) between intervals, for detecting periodic */
+/* We are only interested in periods up to 100ms, i.e. between beacons */
+/* This is correct for TA_INTERVALS_NUM=10 */
+#define TA_INTERVALS_STEP               10
+
+
+enum ta_frame_identity
+{
+    TA_FRAME_UNKNOWN,
+    TA_FRAME_ETHERNET_UNINTERESTING,
+    TA_FRAME_ETHERNET_INTERESTING
+};
+
+
+#define TA_ETHERNET_TYPE_OFFSET     6
+#define TA_LLC_HEADER_SIZE          8
+#define TA_IP_TYPE_OFFSET           17
+#define TA_UDP_SOURCE_PORT_OFFSET   28
+#define TA_UDP_DEST_PORT_OFFSET     (TA_UDP_SOURCE_PORT_OFFSET + 2)
+#define TA_BOOTP_CLIENT_MAC_ADDR_OFFSET 64
+#define TA_DHCP_MESSAGE_TYPE_OFFSET 278
+#define TA_DHCP_MESSAGE_TYPE_ACK    0x05
+#define TA_PROTO_TYPE_IP            0x0800
+#define TA_PROTO_TYPE_EAP           0x888E
+#define TA_PROTO_TYPE_WAI           0x8864
+#define TA_PROTO_TYPE_ARP           0x0806
+#define TA_IP_TYPE_TCP              0x06
+#define TA_IP_TYPE_UDP              0x11
+#define TA_UDP_PORT_BOOTPC          0x0044
+#define TA_UDP_PORT_BOOTPS          0x0043
+#define TA_EAPOL_TYPE_OFFSET        9
+#define TA_EAPOL_TYPE_START         0x01
+
+#define snap_802_2                  0xAAAA0300
+#define oui_rfc1042                 0x00000000
+#define oui_8021h                   0x0000f800
+static const CsrUint8 aironet_snap[5] = { 0x00, 0x40, 0x96, 0x00, 0x00 };
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  ta_detect_protocol
+ *
+ *      Internal only.
+ *      Detects a specific protocol in a frame and indicates a TA event.
+ *
+ *  Arguments:
+ *      ta              The pointer to the TA module.
+ *      direction       The direction of the frame (tx or rx).
+ *      data            Pointer to the structure that contains the data.
+ *
+ *  Returns:
+ *      None
+ * ---------------------------------------------------------------------------
+ */
+static enum ta_frame_identity ta_detect_protocol(card_t *card, CsrWifiRouterCtrlProtocolDirection direction,
+                                                 const bulk_data_desc_t *data,
+                                                 const CsrUint8 *saddr,
+                                                 const CsrUint8 *sta_macaddr)
+{
+    ta_data_t *tad = &card->ta_sampling;
+    CsrUint16 proto;
+    CsrUint16 source_port, dest_port;
+    CsrWifiMacAddress srcAddress;
+    CsrUint32 snap_hdr, oui_hdr;
+
+    if (data->data_length < TA_LLC_HEADER_SIZE)
+    {
+        return TA_FRAME_UNKNOWN;
+    }
+
+    snap_hdr = (((CsrUint32)data->os_data_ptr[0]) << 24) |
+               (((CsrUint32)data->os_data_ptr[1]) << 16) |
+               (((CsrUint32)data->os_data_ptr[2]) << 8);
+    if (snap_hdr != snap_802_2)
+    {
+        return TA_FRAME_UNKNOWN;
+    }
+
+    if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
+    {
+        /*
+         * Here we would use the custom filter to detect interesting frames.
+         */
+    }
+
+    oui_hdr = (((CsrUint32)data->os_data_ptr[3]) << 24) |
+              (((CsrUint32)data->os_data_ptr[4]) << 16) |
+              (((CsrUint32)data->os_data_ptr[5]) << 8);
+    if ((oui_hdr == oui_rfc1042) || (oui_hdr == oui_8021h))
+    {
+        proto = (data->os_data_ptr[TA_ETHERNET_TYPE_OFFSET] * 256) +
+                data->os_data_ptr[TA_ETHERNET_TYPE_OFFSET + 1];
+
+        /* The only interesting IP frames are the DHCP */
+        if (proto == TA_PROTO_TYPE_IP)
+        {
+            if (data->data_length > TA_IP_TYPE_OFFSET)
+            {
+                if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
+                {
+                    ta_l4stats_t *ta_l4stats = &tad->ta_l4stats;
+                    CsrUint8 l4proto = data->os_data_ptr[TA_IP_TYPE_OFFSET];
+
+                    if (l4proto == TA_IP_TYPE_TCP)
+                    {
+                        if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX)
+                        {
+                            ta_l4stats->txTcpBytesCount += data->data_length;
+                        }
+                        else
+                        {
+                            ta_l4stats->rxTcpBytesCount += data->data_length;
+                        }
+                    }
+                    else if (l4proto == TA_IP_TYPE_UDP)
+                    {
+                        if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX)
+                        {
+                            ta_l4stats->txUdpBytesCount += data->data_length;
+                        }
+                        else
+                        {
+                            ta_l4stats->rxUdpBytesCount += data->data_length;
+                        }
+                    }
+                }
+
+                /* detect DHCP frames */
+                if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP)
+                {
+                    /* DHCP frames are UDP frames with BOOTP ports */
+                    if (data->os_data_ptr[TA_IP_TYPE_OFFSET] == TA_IP_TYPE_UDP)
+                    {
+                        if (data->data_length > TA_UDP_DEST_PORT_OFFSET)
+                        {
+                            source_port = (data->os_data_ptr[TA_UDP_SOURCE_PORT_OFFSET] * 256) +
+                                          data->os_data_ptr[TA_UDP_SOURCE_PORT_OFFSET + 1];
+                            dest_port = (data->os_data_ptr[TA_UDP_DEST_PORT_OFFSET] * 256) +
+                                        data->os_data_ptr[TA_UDP_DEST_PORT_OFFSET + 1];
+
+                            if (((source_port == TA_UDP_PORT_BOOTPC) && (dest_port == TA_UDP_PORT_BOOTPS)) ||
+                                ((source_port == TA_UDP_PORT_BOOTPS) && (dest_port == TA_UDP_PORT_BOOTPC)))
+                            {
+                                /* The DHCP should have at least a message type (request, ack, nack, etc) */
+                                if (data->data_length > TA_DHCP_MESSAGE_TYPE_OFFSET + 6)
+                                {
+                                    UNIFI_MAC_ADDRESS_COPY(srcAddress.a, saddr);
+
+                                    if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX)
+                                    {
+                                        unifi_ta_indicate_protocol(card->ospriv,
+                                                                   CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP,
+                                                                   direction,
+                                                                   &srcAddress);
+                                        return TA_FRAME_ETHERNET_UNINTERESTING;
+                                    }
+
+                                    /* DHCPACK is a special indication */
+                                    if (UNIFI_MAC_ADDRESS_CMP(data->os_data_ptr + TA_BOOTP_CLIENT_MAC_ADDR_OFFSET, sta_macaddr) == TRUE)
+                                    {
+                                        if (data->os_data_ptr[TA_DHCP_MESSAGE_TYPE_OFFSET] == TA_DHCP_MESSAGE_TYPE_ACK)
+                                        {
+                                            unifi_ta_indicate_protocol(card->ospriv,
+                                                                       CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP_ACK,
+                                                                       direction,
+                                                                       &srcAddress);
+                                        }
+                                        else
+                                        {
+                                            unifi_ta_indicate_protocol(card->ospriv,
+                                                                       CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP,
+                                                                       direction,
+                                                                       &srcAddress);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            return TA_FRAME_ETHERNET_INTERESTING;
+        }
+
+        /* detect protocol type EAPOL or WAI (treated as equivalent here) */
+        if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_EAPOL)
+        {
+            if (TA_PROTO_TYPE_EAP == proto || TA_PROTO_TYPE_WAI == proto)
+            {
+                if ((TA_PROTO_TYPE_WAI == proto) || (direction != CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX) ||
+                    (data->os_data_ptr[TA_EAPOL_TYPE_OFFSET] == TA_EAPOL_TYPE_START))
+                {
+                    UNIFI_MAC_ADDRESS_COPY(srcAddress.a, saddr);
+                    unifi_ta_indicate_protocol(card->ospriv,
+                                               CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_EAPOL,
+                                               direction, &srcAddress);
+                }
+                return TA_FRAME_ETHERNET_UNINTERESTING;
+            }
+        }
+
+        /* detect protocol type 0x0806 (ARP) */
+        if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_ARP)
+        {
+            if (proto == TA_PROTO_TYPE_ARP)
+            {
+                UNIFI_MAC_ADDRESS_COPY(srcAddress.a, saddr);
+                unifi_ta_indicate_protocol(card->ospriv,
+                                           CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_ARP,
+                                           direction, &srcAddress);
+                return TA_FRAME_ETHERNET_UNINTERESTING;
+            }
+        }
+
+        return TA_FRAME_ETHERNET_INTERESTING;
+    }
+    else if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_AIRONET)
+    {
+        /* detect Aironet frames */
+        if (!CsrMemCmp(data->os_data_ptr + 3, aironet_snap, 5))
+        {
+            UNIFI_MAC_ADDRESS_COPY(srcAddress.a, saddr);
+            unifi_ta_indicate_protocol(card->ospriv, CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_AIRONET,
+                                       direction, &srcAddress);
+        }
+    }
+
+    return TA_FRAME_ETHERNET_UNINTERESTING;
+} /* ta_detect_protocol() */
+
+
+static void tas_reset_data(ta_data_t *tad)
+{
+    CsrInt16 i;
+
+    for (i = 0; i < (TA_INTERVALS_NUM + 1); i++)
+    {
+        tad->stats.intervals[i] = 0;
+    }
+
+    tad->stats.rxFramesNum = 0;
+    tad->stats.txFramesNum = 0;
+    tad->stats.rxBytesCount = 0;
+    tad->stats.txBytesCount = 0;
+    tad->stats.rxMeanRate = 0;
+
+    tad->rx_sum_rate = 0;
+
+    tad->ta_l4stats.rxTcpBytesCount = 0;
+    tad->ta_l4stats.txTcpBytesCount = 0;
+    tad->ta_l4stats.rxUdpBytesCount = 0;
+    tad->ta_l4stats.txUdpBytesCount = 0;
+} /* tas_reset_data() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  API.
+ *  unifi_ta_sampling_init
+ *
+ *      (Re)Initialise the Traffic Analysis sampling module.
+ *      Resets the counters and timestamps.
+ *
+ *  Arguments:
+ *      tad             Pointer to a ta_data_t structure containing the
+ *                      context for this device instance.
+ *      drv_priv        An opaque pointer that the TA sampling module will
+ *                      pass in call-outs.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void unifi_ta_sampling_init(card_t *card)
+{
+    (void)unifi_ta_configure(card, CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_RESET, NULL);
+
+    card->ta_sampling.packet_filter = CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_NONE;
+    card->ta_sampling.traffic_type = CSR_WIFI_ROUTER_CTRL_TRAFFIC_TYPE_OCCASIONAL;
+} /* unifi_ta_sampling_init() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  API.
+ *  unifi_ta_sample
+ *
+ *      Sample a data frame for the TA module.
+ *      This function stores all the useful information it can extract from
+ *      the frame and detects any specific protocols.
+ *
+ *  Arguments:
+ *      tad             The pointer to the TA sampling context struct.
+ *      direction       The direction of the frame (rx, tx)
+ *      data            Pointer to the frame data
+ *      saddr           Source MAC address of frame.
+ *      timestamp       Time (in msecs) that the frame was received.
+ *      rate            Reported data rate for the rx frame (0 for tx frames)
+ *
+ *  Returns:
+ *      None
+ * ---------------------------------------------------------------------------
+ */
+void unifi_ta_sample(card_t                            *card,
+                     CsrWifiRouterCtrlProtocolDirection direction,
+                     const bulk_data_desc_t            *data,
+                     const CsrUint8                    *saddr,
+                     const CsrUint8                    *sta_macaddr,
+                     CsrUint32                          timestamp,
+                     CsrUint16                          rate)
+{
+    ta_data_t *tad = &card->ta_sampling;
+    enum ta_frame_identity identity;
+    CsrUint32 time_delta;
+
+
+
+    /* Step1: Check for specific frames */
+    if (tad->packet_filter != CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_NONE)
+    {
+        identity = ta_detect_protocol(card, direction, data, saddr, sta_macaddr);
+    }
+    else
+    {
+        identity = TA_FRAME_ETHERNET_INTERESTING;
+    }
+
+
+    /* Step2: Update the information in the current record */
+    if (direction == CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_RX)
+    {
+        /* Update the Rx packet count and the throughput count */
+        tad->stats.rxFramesNum++;
+        tad->stats.rxBytesCount += data->data_length;
+
+        /* Accumulate packet Rx rates for later averaging */
+        tad->rx_sum_rate += rate;
+    }
+    else
+    {
+        if (identity == TA_FRAME_ETHERNET_INTERESTING)
+        {
+            /*
+             * Store the period between the last and the current frame.
+             * There is not point storing more than TA_MAX_INTERVALS_IN_C1 periods,
+             * the traffic will be bursty or continuous.
+             */
+            if (tad->stats.txFramesNum < TA_MAX_INTERVALS_IN_C1)
+            {
+                CsrUint32 interval;
+                CsrUint32 index_in_intervals;
+
+                interval = timestamp - tad->tx_last_ts;
+                tad->tx_last_ts = timestamp;
+                index_in_intervals = (interval + TA_INTERVALS_STEP / 2 - 1) / TA_INTERVALS_STEP;
+
+                /* If the interval is interesting, update the t1_intervals count */
+                if (index_in_intervals <= TA_INTERVALS_NUM)
+                {
+                    unifi_trace(card->ospriv, UDBG5,
+                                "unifi_ta_sample: TX interval=%d index=%d\n",
+                                interval, index_in_intervals);
+                    tad->stats.intervals[index_in_intervals]++;
+                }
+            }
+        }
+
+        /* Update the Tx packet count... */
+        tad->stats.txFramesNum++;
+        /* ... and the number of bytes for throughput. */
+        tad->stats.txBytesCount += data->data_length;
+    }
+
+    /*
+     * If more than one second has elapsed since the last report, send
+     * another one.
+     */
+    /* Unsigned subtraction handles wrap-around from 0xFFFFFFFF to 0 */
+    time_delta = timestamp - tad->last_indication_time;
+    if (time_delta >= 1000)
+    {
+        /*
+         * rxFramesNum can be flashed in tas_reset_data() by another thread.
+         * Use a temp to avoid division by zero.
+         */
+        CsrUint32 temp_rxFramesNum;
+        temp_rxFramesNum = tad->stats.rxFramesNum;
+
+        /* Calculate this interval's mean frame Rx rate from the sum */
+        if (temp_rxFramesNum)
+        {
+            tad->stats.rxMeanRate = tad->rx_sum_rate / temp_rxFramesNum;
+        }
+        unifi_trace(card->ospriv, UDBG5,
+                    "unifi_ta_sample: RX fr=%lu, r=%u, sum=%lu, av=%lu\n",
+                    tad->stats.rxFramesNum, rate,
+                    tad->rx_sum_rate, tad->stats.rxMeanRate);
+
+        /*
+         * Send the information collected in the stats struct
+         * to the SME and reset the counters.
+         */
+        if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
+        {
+            CsrUint32 rxTcpThroughput = tad->ta_l4stats.rxTcpBytesCount / time_delta;
+            CsrUint32 txTcpThroughput = tad->ta_l4stats.txTcpBytesCount / time_delta;
+            CsrUint32 rxUdpThroughput = tad->ta_l4stats.rxUdpBytesCount / time_delta;
+            CsrUint32 txUdpThroughput = tad->ta_l4stats.txUdpBytesCount / time_delta;
+
+            unifi_ta_indicate_l4stats(card->ospriv,
+                                      rxTcpThroughput,
+                                      txTcpThroughput,
+                                      rxUdpThroughput,
+                                      txUdpThroughput
+                                      );
+        }
+        unifi_ta_indicate_sampling(card->ospriv, &tad->stats);
+        tas_reset_data(tad);
+        tad->last_indication_time = timestamp;
+    }
+} /* unifi_ta_sample() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  External API.
+ *  unifi_ta_configure
+ *
+ *      Configures the TA module parameters.
+ *
+ *  Arguments:
+ *      ta              The pointer to the TA module.
+ *      config_type     The type of the configuration request
+ *      config          Pointer to the configuration parameters.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR error code otherwise
+ * ---------------------------------------------------------------------------
+ */
+CsrResult unifi_ta_configure(card_t                               *card,
+                             CsrWifiRouterCtrlTrafficConfigType    config_type,
+                             const CsrWifiRouterCtrlTrafficConfig *config)
+{
+    ta_data_t *tad = &card->ta_sampling;
+
+    /* Reinitialise our data when we are reset */
+    if (config_type == CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_RESET)
+    {
+        /* Reset the stats to zero */
+        tas_reset_data(tad);
+
+        /* Reset the timer variables */
+        tad->tx_last_ts = 0;
+        tad->last_indication_time = 0;
+
+        return CSR_RESULT_SUCCESS;
+    }
+
+    if (config_type == CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_FILTER)
+    {
+        tad->packet_filter = config->packetFilter;
+
+        if (tad->packet_filter & CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM)
+        {
+            tad->custom_filter = config->customFilter;
+        }
+
+        return CSR_RESULT_SUCCESS;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_ta_configure() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  External API.
+ *  unifi_ta_classification
+ *
+ *      Configures the current TA classification.
+ *
+ *  Arguments:
+ *      ta              The pointer to the TA module.
+ *      traffic_type    The classification type
+ *      period          The traffic period if the type is periodic
+ *
+ *  Returns:
+ *      None
+ * ---------------------------------------------------------------------------
+ */
+void unifi_ta_classification(card_t                      *card,
+                             CsrWifiRouterCtrlTrafficType traffic_type,
+                             CsrUint16                    period)
+{
+    unifi_trace(card->ospriv, UDBG3,
+                "Changed current ta classification to: %d\n", traffic_type);
+
+    card->ta_sampling.traffic_type = traffic_type;
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_ta_sampling.h b/drivers/staging/csr/csr_wifi_hip_ta_sampling.h
new file mode 100644
index 0000000..602943e
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_ta_sampling.h
@@ -0,0 +1,75 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     csr_wifi_hip_ta_sampling.h
+ *
+ *  PURPOSE:
+ *      This file contains Traffic Analysis definitions common to the
+ *      sampling and analysis modules.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#ifndef __TA_SAMPLING_H__
+#define __TA_SAMPLING_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "csr_wifi_hip_unifi.h"
+
+typedef struct ta_l4stats
+{
+    CsrUint32 rxTcpBytesCount;
+    CsrUint32 txTcpBytesCount;
+    CsrUint32 rxUdpBytesCount;
+    CsrUint32 txUdpBytesCount;
+} ta_l4stats_t;
+
+/*
+ * Context structure to preserve state between calls.
+ */
+
+typedef struct ta_data
+{
+    /* Current packet filter configuration */
+    CsrUint16 packet_filter;
+
+    /* Current packet custom filter configuration */
+    CsrWifiRouterCtrlTrafficFilter custom_filter;
+
+    /* The timestamp of the last tx packet processed. */
+    CsrUint32 tx_last_ts;
+
+    /* The timestamp of the last packet processed. */
+    CsrUint32 last_indication_time;
+
+    /* Statistics */
+    CsrWifiRouterCtrlTrafficStats stats;
+
+    /* Current traffic classification */
+    CsrWifiRouterCtrlTrafficType traffic_type;
+
+    /* Sum of packet rx rates for this interval used to calculate mean */
+    CsrUint32    rx_sum_rate;
+    ta_l4stats_t ta_l4stats;
+} ta_data_t;
+
+
+void unifi_ta_sampling_init(card_t *card);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TA_SAMPLING_H__ */
diff --git a/drivers/staging/csr/csr_wifi_hip_udi.c b/drivers/staging/csr/csr_wifi_hip_udi.c
new file mode 100644
index 0000000..2cf0281
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_udi.c
@@ -0,0 +1,268 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     csr_wifi_hip_card_udi.c
+ *
+ *  PURPOSE:
+ *      Maintain a list of callbacks to log UniFi exchanges to one or more
+ *      debug/monitoring client applications.
+ *
+ * NOTES:
+ *      Just call the UDI driver log fn directly for now.
+ *      When done properly, each open() on the UDI device will install
+ *      a log function. We will call all log fns whenever a signal is written
+ *      to or read form the UniFi.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_card.h"
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_print_status
+ *
+ *      Print status info to given character buffer.
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+CsrInt32 unifi_print_status(card_t *card, CsrCharString *str, CsrInt32 *remain)
+{
+    CsrCharString *p = str;
+    sdio_config_data_t *cfg;
+    CsrUint16 i, n;
+    CsrInt32 remaining = *remain;
+    CsrInt32 written;
+#ifdef CSR_UNSAFE_SDIO_ACCESS
+    CsrInt32 iostate;
+    CsrResult r;
+    static const CsrCharString *const states[] = {
+        "AWAKE", "DROWSY", "TORPID"
+    };
+    #define SHARED_READ_RETRY_LIMIT 10
+    CsrUint8 b;
+#endif
+
+    if (remaining <= 0)
+    {
+        return 0;
+    }
+
+    i = n = 0;
+    written = CsrSnprintf(p, remaining, "Chip ID %u\n",
+                          (CsrUint16)card->chip_id);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "Chip Version %04X\n",
+                          card->chip_version);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "HIP v%u.%u\n",
+                          (card->config_data.version >> 8) & 0xFF,
+                          card->config_data.version & 0xFF);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "Build %lu: %s\n",
+                          card->build_id, card->build_id_string);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    cfg = &card->config_data;
+
+    written = CsrSnprintf(p, remaining, "sdio ctrl offset          %u\n",
+                          cfg->sdio_ctrl_offset);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "fromhost sigbuf handle    %u\n",
+                          cfg->fromhost_sigbuf_handle);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "tohost_sigbuf_handle      %u\n",
+                          cfg->tohost_sigbuf_handle);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "num_fromhost_sig_frags    %u\n",
+                          cfg->num_fromhost_sig_frags);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "num_tohost_sig_frags      %u\n",
+                          cfg->num_tohost_sig_frags);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "num_fromhost_data_slots   %u\n",
+                          cfg->num_fromhost_data_slots);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "num_tohost_data_slots     %u\n",
+                          cfg->num_tohost_data_slots);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "data_slot_size            %u\n",
+                          cfg->data_slot_size);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    /* Added by protocol version 0x0001 */
+    written = CsrSnprintf(p, remaining, "overlay_size              %u\n",
+                          (CsrUint16)cfg->overlay_size);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    /* Added by protocol version 0x0300 */
+    written = CsrSnprintf(p, remaining, "data_slot_round           %u\n",
+                          cfg->data_slot_round);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "sig_frag_size             %u\n",
+                          cfg->sig_frag_size);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    /* Added by protocol version 0x0300 */
+    written = CsrSnprintf(p, remaining, "tohost_sig_pad            %u\n",
+                          cfg->tohost_signal_padding);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    written = CsrSnprintf(p, remaining, "\nInternal state:\n");
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    written = CsrSnprintf(p, remaining, "Last PHY PANIC: %04x:%04x\n",
+                          card->last_phy_panic_code, card->last_phy_panic_arg);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "Last MAC PANIC: %04x:%04x\n",
+                          card->last_mac_panic_code, card->last_mac_panic_arg);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    written = CsrSnprintf(p, remaining, "fhsr: %u\n",
+                          (CsrUint16)card->from_host_signals_r);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "fhsw: %u\n",
+                          (CsrUint16)card->from_host_signals_w);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "thsr: %u\n",
+                          (CsrUint16)card->to_host_signals_r);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "thsw: %u\n",
+                          (CsrUint16)card->to_host_signals_w);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining,
+                          "fh buffer contains: %u signals, %u bytes\n",
+                          card->fh_buffer.count,
+                          card->fh_buffer.ptr - card->fh_buffer.buf);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    written = CsrSnprintf(p, remaining, "paused: ");
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    for (i = 0; i < sizeof(card->tx_q_paused_flag) / sizeof(card->tx_q_paused_flag[0]); i++)
+    {
+        written = CsrSnprintf(p, remaining, card->tx_q_paused_flag[i]?"1" : "0");
+        UNIFI_SNPRINTF_RET(p, remaining, written);
+    }
+    written = CsrSnprintf(p, remaining, "\n");
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    written = CsrSnprintf(p, remaining,
+                          "fh command q: %u waiting, %u free of %u:\n",
+                          CSR_WIFI_HIP_Q_SLOTS_USED(&card->fh_command_queue),
+                          CSR_WIFI_HIP_Q_SLOTS_FREE(&card->fh_command_queue),
+                          UNIFI_SOFT_COMMAND_Q_LENGTH);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
+    {
+        written = CsrSnprintf(p, remaining,
+                              "fh traffic q[%u]: %u waiting, %u free of %u:\n",
+                              i,
+                              CSR_WIFI_HIP_Q_SLOTS_USED(&card->fh_traffic_queue[i]),
+                              CSR_WIFI_HIP_Q_SLOTS_FREE(&card->fh_traffic_queue[i]),
+                              UNIFI_SOFT_TRAFFIC_Q_LENGTH);
+        UNIFI_SNPRINTF_RET(p, remaining, written);
+    }
+
+    written = CsrSnprintf(p, remaining, "fh data slots free: %u\n",
+                          card->from_host_data?CardGetFreeFromHostDataSlots(card) : 0);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+
+    written = CsrSnprintf(p, remaining, "From host data slots:");
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    n = card->config_data.num_fromhost_data_slots;
+    for (i = 0; i < n && card->from_host_data; i++)
+    {
+        written = CsrSnprintf(p, remaining, " %u",
+                              (CsrUint16)card->from_host_data[i].bd.data_length);
+        UNIFI_SNPRINTF_RET(p, remaining, written);
+    }
+    written = CsrSnprintf(p, remaining, "\n");
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    written = CsrSnprintf(p, remaining, "To host data slots:");
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    n = card->config_data.num_tohost_data_slots;
+    for (i = 0; i < n && card->to_host_data; i++)
+    {
+        written = CsrSnprintf(p, remaining, " %u",
+                              (CsrUint16)card->to_host_data[i].data_length);
+        UNIFI_SNPRINTF_RET(p, remaining, written);
+    }
+
+    written = CsrSnprintf(p, remaining, "\n");
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+#ifdef CSR_UNSAFE_SDIO_ACCESS
+    written = CsrSnprintf(p, remaining, "Host State: %s\n", states[card->host_state]);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    r = unifi_check_io_status(card, &iostate);
+    if (iostate == 1)
+    {
+        written = CsrSnprintf(p, remaining, "I/O Check: F1 disabled\n");
+        UNIFI_SNPRINTF_RET(p, remaining, written);
+    }
+    else
+    {
+        if (iostate == 1)
+        {
+            written = CsrSnprintf(p, remaining, "I/O Check: pending interrupt\n");
+            UNIFI_SNPRINTF_RET(p, remaining, written);
+        }
+
+        written = CsrSnprintf(p, remaining, "BH reason interrupt = %d\n",
+                              card->bh_reason_unifi);
+        UNIFI_SNPRINTF_RET(p, remaining, written);
+        written = CsrSnprintf(p, remaining, "BH reason host      = %d\n",
+                              card->bh_reason_host);
+        UNIFI_SNPRINTF_RET(p, remaining, written);
+
+        for (i = 0; i < SHARED_READ_RETRY_LIMIT; i++)
+        {
+            r = unifi_read_8_or_16(card, card->sdio_ctrl_addr + 2, &b);
+            if ((r == CSR_RESULT_SUCCESS) && (!(b & 0x80)))
+            {
+                written = CsrSnprintf(p, remaining, "fhsr: %u (driver thinks is %u)\n",
+                                      b, card->from_host_signals_r);
+                UNIFI_SNPRINTF_RET(p, remaining, written);
+                break;
+            }
+        }
+        iostate = unifi_read_shared_count(card, card->sdio_ctrl_addr + 4);
+        written = CsrSnprintf(p, remaining, "thsw: %u (driver thinks is %u)\n",
+                              iostate, card->to_host_signals_w);
+        UNIFI_SNPRINTF_RET(p, remaining, written);
+    }
+#endif
+
+    written = CsrSnprintf(p, remaining, "\nStats:\n");
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "Total SDIO bytes: R=%lu W=%lu\n",
+                          card->sdio_bytes_read, card->sdio_bytes_written);
+
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+    written = CsrSnprintf(p, remaining, "Interrupts generated on card: %lu\n",
+                          card->unifi_interrupt_seq);
+    UNIFI_SNPRINTF_RET(p, remaining, written);
+
+    *remain = remaining;
+    return (p - str);
+} /* unifi_print_status() */
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_unifi.h b/drivers/staging/csr/csr_wifi_hip_unifi.h
new file mode 100644
index 0000000..5f1c67b
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_unifi.h
@@ -0,0 +1,882 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * FILE : csr_wifi_hip_unifi.h
+ *
+ * PURPOSE : Public API for the UniFi HIP core library.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#ifndef __CSR_WIFI_HIP_UNIFI_H__
+#define __CSR_WIFI_HIP_UNIFI_H__ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_HIP_TA_DISABLE
+#include "csr_wifi_router_ctrl_prim.h"
+#include "csr_wifi_router_prim.h"
+#else
+#include "csr_time.h"
+#endif
+
+/* SDIO chip ID numbers */
+
+/* Manufacturer id */
+#define SDIO_MANF_ID_CSR              0x032a
+
+/* Device id */
+#define SDIO_CARD_ID_UNIFI_1          0x0001
+#define SDIO_CARD_ID_UNIFI_2          0x0002
+#define SDIO_CARD_ID_UNIFI_3          0x0007
+#define SDIO_CARD_ID_UNIFI_4          0x0008
+
+/* Function number for WLAN */
+#define SDIO_WLAN_FUNC_ID_UNIFI_1          0x0001
+#define SDIO_WLAN_FUNC_ID_UNIFI_2          0x0001
+#define SDIO_WLAN_FUNC_ID_UNIFI_3          0x0001
+#define SDIO_WLAN_FUNC_ID_UNIFI_4          0x0002
+
+/* Maximum SDIO bus clock supported. */
+#define UNIFI_SDIO_CLOCK_MAX_HZ    50000000  /* Hz */
+
+/*
+ * Initialisation SDIO bus clock.
+ *
+ * The initialisation clock speed should be used from when the chip has been
+ * reset until the first MLME-reset has been received (i.e. during firmware
+ * initialisation), unless UNIFI_SDIO_CLOCK_SAFE_HZ applies.
+ */
+#define UNIFI_SDIO_CLOCK_INIT_HZ    12500000 /* Hz */
+
+/*
+ * Safe SDIO bus clock.
+ *
+ * The safe speed should be used when the chip is in deep sleep or
+ * it's state is unknown (just after reset / power on).
+ */
+#define UNIFI_SDIO_CLOCK_SAFE_HZ    1000000  /* Hz */
+
+/* I/O default block size to use for UniFi. */
+#define UNIFI_IO_BLOCK_SIZE     64
+
+#define UNIFI_WOL_OFF   0
+#define UNIFI_WOL_SDIO  1
+#define UNIFI_WOL_PIO   2
+
+/* The number of Tx traffic queues */
+#define UNIFI_NO_OF_TX_QS              4
+
+#define CSR_WIFI_HIP_RESERVED_HOST_TAG 0xFFFFFFFF
+
+/*
+ * The number of slots in the from-host queues.
+ *
+ * UNIFI_SOFT_TRAFFIC_Q_LENGTH is the number of slots in the traffic queues
+ * and there will be UNIFI_NO_OF_TX_QS of them.
+ * Traffic queues are used for data packets.
+ *
+ * UNIFI_SOFT_COMMAND_Q_LENGTH is the number of slots in the command queue.
+ * The command queue is used for MLME management requests.
+ *
+ * Queues are ring buffers and so must always have 1 unused slot.
+ */
+#define UNIFI_SOFT_TRAFFIC_Q_LENGTH (20 + 1)
+#define UNIFI_SOFT_COMMAND_Q_LENGTH (16 + 1)
+
+#include "csr_types.h"          /* from the synergy porting folder */
+#include "csr_framework_ext.h"  /* from the synergy porting folder */
+#include "csr_sdio.h"           /* from the synergy porting folder */
+#include "csr_pmem.h"           /* from the synergy porting folder */
+#include "csr_util.h"           /* from the synergy porting folder */
+#include "csr_formatted_io.h"   /* from the synergy gsp folder */
+#include "csr_wifi_result.h"
+
+/* Utility MACROS. Note that UNIFI_MAC_ADDRESS_CMP returns TRUE on success */
+#define UNIFI_MAC_ADDRESS_COPY(dst, src) \
+    do { (dst)[0] = (src)[0]; (dst)[1] = (src)[1]; \
+         (dst)[2] = (src)[2]; (dst)[3] = (src)[3]; \
+         (dst)[4] = (src)[4]; (dst)[5] = (src)[5]; \
+    } while (0)
+
+#define UNIFI_MAC_ADDRESS_CMP(addr1, addr2) \
+    (((addr1)[0] == (addr2)[0]) && ((addr1)[1] == (addr2)[1]) && \
+     ((addr1)[2] == (addr2)[2]) && ((addr1)[3] == (addr2)[3]) && \
+     ((addr1)[4] == (addr2)[4]) && ((addr1)[5] == (addr2)[5]))
+
+/* Traffic queue ordered according to priority
+ * EAPOL/Uncontrolled port Queue should be the last
+ */
+typedef enum
+{
+    UNIFI_TRAFFIC_Q_BK = 0,
+    UNIFI_TRAFFIC_Q_BE,
+    UNIFI_TRAFFIC_Q_VI,
+    UNIFI_TRAFFIC_Q_VO,
+    UNIFI_TRAFFIC_Q_EAPOL,    /* Non existant in HIP */
+    UNIFI_TRAFFIC_Q_MAX,      /* Non existant */
+    UNIFI_TRAFFIC_Q_MLME      /* Non existant */
+} unifi_TrafficQueue;
+
+/*
+ * Structure describing a bulk data slot.
+ * This structure is shared between the HIP core library and the OS
+ * layer. See the definition of unifi_net_data_malloc() for more details.
+ *
+ * The data_length field is used to indicate empty/occupied state.
+ * Needs to be defined before #include "unifi_os.h".
+ */
+typedef struct _bulk_data_desc
+{
+    const CsrUint8 *os_data_ptr;
+    CsrUint32       data_length;
+    const void     *os_net_buf_ptr;
+    CsrUint32       net_buf_length;
+} bulk_data_desc_t;
+
+/* Structure of an entry in the Symbol Look Up Table (SLUT). */
+typedef struct _symbol
+{
+    CsrUint16 id;
+    CsrUint32 obj;
+} symbol_t;
+
+/*
+ * Header files need to be included from the current directory,
+ * the SME library, the synergy framework and the OS layer.
+ * A thin OS layer needs to be implemented in the porting exercise.
+ *
+ * Note that unifi_os.h should be included only in unifi.h
+ */
+
+#include "unifi_os.h"
+
+/*
+ * Contains the HIP core definitions selected in the porting exercise, such as
+ * UNIFI_PAD_BULK_DATA_TO_BLOCK_SIZE and UNIFI_PAD_SIGNALS_TO_BLOCK_SIZE.
+ * Implemented in the OS layer, as part of the porting exersice.
+ */
+#include "unifi_config.h"
+
+#include "csr_wifi_hip_signals.h" /* from this dir */
+
+/*
+ * The card structure is an opaque pointer that is used to pass context
+ * to the upper-edge API functions.
+ */
+typedef struct card card_t;
+
+
+/*
+ * This structure describes all of the bulk data that 'might' be
+ * associated with a signal.
+ */
+typedef struct _bulk_data_param
+{
+    bulk_data_desc_t d[UNIFI_MAX_DATA_REFERENCES];
+} bulk_data_param_t;
+
+
+/*
+ * This structure describes the chip and HIP core lib
+ * information that exposed to the OS layer.
+ */
+typedef struct _card_info
+{
+    CsrUint16 chip_id;
+    CsrUint16 chip_version;
+    CsrUint32 fw_build;
+    CsrUint16 fw_hip_version;
+    CsrUint32 sdio_block_size;
+} card_info_t;
+
+
+/*
+ * Mini-coredump definitions
+ */
+/* Definition of XAP memory ranges used by the mini-coredump system.
+ * Note that, these values are NOT the same as UNIFI_REGISTERS, etc
+ * in unifihw.h which don't allow selection of register areas for each XAP.
+ */
+typedef enum unifi_coredump_space
+{
+    UNIFI_COREDUMP_MAC_REG,
+    UNIFI_COREDUMP_PHY_REG,
+    UNIFI_COREDUMP_SH_DMEM,
+    UNIFI_COREDUMP_MAC_DMEM,
+    UNIFI_COREDUMP_PHY_DMEM,
+    UNIFI_COREDUMP_TRIGGER_MAGIC = 0xFEED
+} unifi_coredump_space_t;
+
+/* Structure used to request a register value from a mini-coredump buffer */
+typedef struct unifi_coredump_req
+{
+    /* From user */
+    CsrInt32               index;       /* 0=newest, -1=oldest */
+    unifi_coredump_space_t space;       /* memory space */
+    CsrUint32              offset;      /* register offset in space */
+    /* From driver */
+    CsrUint32 drv_build;                /* Driver build id */
+    CsrUint32 chip_ver;                 /* Chip version */
+    CsrUint32 fw_ver;                   /* Firmware version */
+    CsrInt32  requestor;                /* Requestor: 0=auto dump, 1=manual */
+    CsrTime   timestamp;                /* time of capture by driver */
+    CsrUint32 serial;                   /* capture serial number */
+    CsrInt32  value;                    /* register value */
+} unifi_coredump_req_t;                 /* mini-coredumped reg value request */
+
+
+/**
+ * @defgroup upperedge Upper edge API
+ *
+ * The following functions are implemented in the HIP core lib.
+ */
+
+/**
+ *
+ * Initialise the HIP core lib.
+ * Note that the OS layer must initialise the SDIO glue layer and obtain
+ * an SDIO function context, prior to this call.
+ *
+ * @param sdiopriv the SDIO function context.
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @return \p card_t the HIP core lib API context.
+ *
+ * @ingroup upperedge
+ */
+card_t* unifi_alloc_card(CsrSdioFunction *sdiopriv, void *ospriv);
+
+
+/**
+ *
+ * Initialise the UniFi chip.
+ *
+ * @param card the HIP core lib API context.
+ *
+ * @param led_mask the led mask to apply to UniFi.
+ *
+ * @return \b 0 if UniFi is initialized.
+ *
+ * @return \b -CSR_EIO if an I/O error occured while initializing UniFi
+ *
+ * @return \b -CSR_ENODEV if the card is no longer present.
+ *
+ * @ingroup upperedge
+ */
+CsrResult unifi_init_card(card_t *card, CsrInt32 led_mask);
+
+/**
+ *
+ * De-Initialise the HIP core lib.
+ *
+ * @param card the HIP core lib API context.
+ *
+ * @ingroup upperedge
+ */
+void unifi_free_card(card_t *card);
+
+/**
+ *
+ * Cancel all the signals pending in the HIP core lib.
+ * Normally used during a system suspend when the power is retained on UniFi.
+ *
+ * @param card the HIP core lib API context.
+ *
+ * @ingroup upperedge
+ */
+void unifi_cancel_pending_signals(card_t *card);
+
+/**
+ *
+ * Send a signal to UniFi.
+ * Normally it is called from unifi_sys_hip_req() and the OS layer
+ * Tx data plane.
+ *
+ * Note that the bulkdata buffers ownership is passed to the HIP core lib.
+ * These buffers must be allocated using unifi_net_data_malloc().
+ *
+ * @param card the HIP core lib API context.
+ *
+ * @param sigptr pointer to the signal.
+ *
+ * @param siglen size of the signal.
+ *
+ * @param bulkdata pointer to the bulk data associated with the signal.
+ *
+ * @return \b 0 signal is sent.
+ *
+ * @return \b -CSR_EIO if an error occured while sending the signal
+ *
+ * @return \b -CSR_ENODEV if the card is no longer present.
+ *
+ * @ingroup upperedge
+ */
+CsrResult unifi_send_signal(card_t *card, const CsrUint8 *sigptr,
+                            CsrUint32 siglen,
+                            const bulk_data_param_t *bulkdata);
+
+/**
+ *
+ * Check if the HIP core lib has resources to send a signal.
+ * Normally there no need to use this function.
+ *
+ * @param card the HIP core lib API context.
+ *
+ * @param sigptr pointer to the signal.
+ *
+ * @return \b 0 if there are resources for the signal.
+ *
+ * @return \b -CSR_ENOSPC if there are not enough resources
+ *
+ * @ingroup upperedge
+ */
+CsrResult unifi_send_resources_available(card_t *card, const CsrUint8 *sigptr);
+
+/**
+ *
+ * Read the UniFi chip and the HIP core lib information.
+ *
+ * @param card the HIP core lib API context.
+ *
+ * @param card_info pointer to save the information.
+ *
+ * @ingroup upperedge
+ */
+void unifi_card_info(card_t *card, card_info_t *card_info);
+
+/**
+ *
+ * Print the UniFi I/O and Interrupt status.
+ * Normally it is used for debug purposes only.
+ *
+ * @param card the HIP core lib API context.
+
+ * @param status buffer for the chip status
+ *
+ * @return \b 0 if the check was performed.
+ *
+ * @return \b -CSR_EIO if an error occured while checking the status.
+ *
+ * @return \b -CSR_ENODEV if the card is no longer present.
+ *
+ * @ingroup upperedge
+ */
+CsrResult unifi_check_io_status(card_t *card, CsrInt32 *status);
+
+
+/**
+ *
+ * Run the HIP core lib Botton-Half.
+ * Whenever the HIP core lib want this function to be called
+ * by the OS layer, it calls unifi_run_bh().
+ *
+ * @param card the HIP core lib API context.
+ *
+ * @param remaining pointer to return the time (in msecs) that this function
+ * should be re-scheduled. A return value of 0 means that no re-scheduling
+ * is required. If unifi_bh() is called before the timeout expires,
+ * the caller must pass in the remaining time.
+ *
+ * @return \b 0 if no error occured.
+ *
+ * @return \b -CSR_ENODEV if the card is no longer present.
+ *
+ * @return \b -CSR_E* if an error occured while running the bottom half.
+ *
+ * @ingroup upperedge
+ */
+CsrResult unifi_bh(card_t *card, CsrUint32 *remaining);
+
+
+/**
+ * UniFi Low Power Mode (Deep Sleep Signaling)
+ *
+ * unifi_low_power_mode defines the UniFi Deep Sleep Signaling status.
+ * Use with unifi_configure_low_power_mode() to enable/disable
+ * the Deep Sleep Signaling.
+ */
+enum unifi_low_power_mode
+{
+    UNIFI_LOW_POWER_DISABLED,
+    UNIFI_LOW_POWER_ENABLED
+};
+
+/**
+ * Periodic Wake Host Mode
+ *
+ * unifi_periodic_wake_mode defines the Periodic Wake Host Mode.
+ * It can only be set to UNIFI_PERIODIC_WAKE_HOST_ENABLED if
+ * low_power_mode == UNIFI_LOW_POWER_ENABLED.
+ */
+enum unifi_periodic_wake_mode
+{
+    UNIFI_PERIODIC_WAKE_HOST_DISABLED,
+    UNIFI_PERIODIC_WAKE_HOST_ENABLED
+};
+
+/**
+ *
+ * Run the HIP core lib Botton-Half.
+ * Whenever the HIP core lib want this function to be called
+ * by the OS layer, it calls unifi_run_bh().
+ *
+ * Typically, the SME is responsible for configuring these parameters,
+ * so unifi_sys_configure_power_mode_req() is usually implemented
+ * as a direct call to unifi_configure_low_power_mode().
+ *
+ * Note: When polling mode is used instead of interrupts,
+ * low_power_mode must never be set to UNIFI_LOW_POWER_ENABLED.
+ *
+ * @param card the HIP core lib API context.
+ *
+ * @param low_power_mode the Low Power Mode.
+ *
+ * @param periodic_wake_mode the Periodic Wake Mode.
+ *
+ * @return \b 0 if no error occured.
+ *
+ * @return \b -CSR_E* if the request failed.
+ *
+ * @ingroup upperedge
+ */
+CsrResult unifi_configure_low_power_mode(card_t                       *card,
+                                         enum unifi_low_power_mode     low_power_mode,
+                                         enum unifi_periodic_wake_mode periodic_wake_mode);
+
+/**
+ *
+ * Forces the UniFi chip to enter a Deep Sleep state.
+ * This is normally called by the OS layer when the platform suspends.
+ *
+ * Note that if the UniFi Low Power Mode is disabled this call fails.
+ *
+ * @param card the HIP core lib API context.
+ *
+ * @return \b 0 if no error occured.
+ *
+ * @return \b -CSR_ENODEV if the card is no longer present.
+ *
+ * @return \b -CSR_E* if the request failed.
+ *
+ * @ingroup upperedge
+ */
+CsrResult unifi_force_low_power_mode(card_t *card);
+
+#ifndef CSR_WIFI_HIP_TA_DISABLE
+/**
+ * Configure the Traffic Analysis sampling
+ *
+ * Enable or disable statistics gathering.
+ * Enable or disable particular packet detection.
+ *
+ * @param card the HIP core context
+ * @param config_type the item to configure
+ * @param config pointer to struct containing config info
+ *
+ * @return \b 0 if configuration was successful
+ *
+ * @return \b -CSR_EINVAL if a parameter had an invalid value
+ *
+ * @ingroup upperedge
+ */
+CsrResult unifi_ta_configure(card_t                               *card,
+                             CsrWifiRouterCtrlTrafficConfigType    config_type,
+                             const CsrWifiRouterCtrlTrafficConfig *config);
+
+/**
+ * Pass a packet for Traffic Analysis sampling
+ *
+ * @param card the HIP core context
+ * @param direction the direction (Rx or Tx) of the frame.
+ * @param data pointer to bulkdata struct containing the packet
+ * @param saddr the source address of the packet
+ * @param sta_macaddr the MAC address of the UniFi chip
+ * @param timestamp the current time in msecs
+ *
+ * @ingroup upperedge
+ */
+void unifi_ta_sample(card_t                            *card,
+                     CsrWifiRouterCtrlProtocolDirection direction,
+                     const bulk_data_desc_t            *data,
+                     const CsrUint8                    *saddr,
+                     const CsrUint8                    *sta_macaddr,
+                     CsrUint32                          timestamp,
+                     CsrUint16                          rate);
+
+/**
+ * Notify the HIP core lib for a detected Traffic Classification.
+ * Typically, the SME is responsible for configuring these parameters,
+ * so unifi_sys_traffic_classification_req() is usually implemented
+ * as a direct call to unifi_ta_classification().
+ *
+ * @param card the HIP core context.
+ * @param traffic_type the detected traffic type.
+ * @param period The detected period of the traffic.
+ *
+ * @ingroup upperedge
+ */
+void unifi_ta_classification(card_t                      *card,
+                             CsrWifiRouterCtrlTrafficType traffic_type,
+                             CsrUint16                    period);
+
+#endif
+/**
+ * Use software to hard reset the chip.
+ * This is a subset of the unifi_init_card() functionality and should
+ * only be used only to reset a paniced chip before a coredump is taken.
+ *
+ * @param card the HIP core context.
+ *
+ * @ingroup upperedge
+ */
+CsrResult unifi_card_hard_reset(card_t *card);
+
+
+CsrResult unifi_card_readn(card_t *card, CsrUint32 unifi_addr, void *pdata, CsrUint16 len);
+CsrResult unifi_card_read16(card_t *card, CsrUint32 unifi_addr, CsrUint16 *pdata);
+CsrResult unifi_card_write16(card_t *card, CsrUint32 unifi_addr, CsrUint16 data);
+
+
+enum unifi_dbg_processors_select
+{
+    UNIFI_PROC_MAC,
+    UNIFI_PROC_PHY,
+    UNIFI_PROC_BT,
+    UNIFI_PROC_BOTH,
+    UNIFI_PROC_INVALID
+};
+
+CsrResult unifi_card_stop_processor(card_t *card, enum unifi_dbg_processors_select which);
+
+/**
+ * Call-outs from the HIP core lib to the OS layer.
+ * The following functions need to be implemented during the porting exercise.
+ */
+
+/**
+ * Selects appropriate queue according to priority
+ * Helps maintain uniformity in queue selection between the HIP
+ * and the OS layers.
+ *
+ * @param priority priority of the packet
+ *
+ * @return \b Traffic queue to which a packet of this priority belongs
+ *
+ * @ingroup upperedge
+ */
+unifi_TrafficQueue
+unifi_frame_priority_to_queue(CSR_PRIORITY priority);
+
+/**
+ * Returns the priority corresponding to a particular Queue when that is used
+ * when downgrading a packet to a lower AC.
+ * Helps maintain uniformity in queue - priority mapping between the HIP
+ * and the OS layers.
+ *
+ * @param queue
+ *
+ * @return \b Highest priority corresponding to this queue
+ *
+ * @ingroup upperedge
+ */
+CSR_PRIORITY unifi_get_default_downgrade_priority(unifi_TrafficQueue queue);
+
+/**
+ *
+ * Flow control callbacks.
+ * unifi_pause_xmit() is called when the HIP core lib does not have any
+ * resources to store data packets. The OS layer needs to pause
+ * the Tx data plane until unifi_restart_xmit() is called.
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @ingroup upperedge
+ */
+void unifi_pause_xmit(void *ospriv, unifi_TrafficQueue queue);
+void unifi_restart_xmit(void *ospriv, unifi_TrafficQueue queue);
+
+/**
+ *
+ * Request to run the Bottom-Half.
+ * The HIP core lib calls this function to request that unifi_bh()
+ * needs to be run by the OS layer. It can be called anytime, i.e.
+ * when the unifi_bh() is running.
+ * Since unifi_bh() is not re-entrant, usually unifi_run_bh() sets
+ * an event to a thread that schedules a call to unifi_bh().
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @ingroup upperedge
+ */
+CsrResult unifi_run_bh(void *ospriv);
+
+/**
+ *
+ * Delivers a signal received from UniFi to the OS layer.
+ * Normally, the data signals should be delivered to the data plane
+ * and all the rest to the SME (unifi_sys_hip_ind()).
+ *
+ * Note that the OS layer is responsible for freeing the bulkdata
+ * buffers, using unifi_net_data_free().
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @param sigptr pointer to the signal.
+ *
+ * @param siglen size of the signal.
+ *
+ * @param bulkdata pointer to the bulk data associated with the signal.
+ *
+ * @ingroup upperedge
+ */
+void unifi_receive_event(void *ospriv,
+                         CsrUint8 *sigdata, CsrUint32 siglen,
+                         const bulk_data_param_t *bulkdata);
+
+#ifdef CSR_WIFI_REQUEUE_PACKET_TO_HAL
+/**
+ *
+ * Used to reque the failed ma packet request back to hal queues
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @param host_tag host tag for the packet to requeue.
+ *
+ * @param bulkDataDesc pointer to the bulk data.
+ *
+ * @ingroup upperedge
+ */
+CsrResult unifi_reque_ma_packet_request(void *ospriv, CsrUint32 host_tag,
+                                        CsrUint16 status,
+                                        bulk_data_desc_t *bulkDataDesc);
+
+#endif
+typedef struct
+{
+    CsrUint16 free_fh_sig_queue_slots[UNIFI_NO_OF_TX_QS];
+    CsrUint16 free_fh_bulkdata_slots;
+    CsrUint16 free_fh_fw_slots;
+} unifi_HipQosInfo;
+
+void unifi_get_hip_qos_info(card_t *card, unifi_HipQosInfo *hipqosinfo);
+
+
+/**
+ * Functions that read a portion of a firmware file.
+ *
+ * Note: If the UniFi chip runs the f/w from ROM, the HIP core may never
+ * call these functions. Also, the HIP core may call these functions even if
+ * a f/w file is not available. In this case, it is safe to fail the request.
+ */
+#define UNIFI_FW_STA    1   /* Identify STA firmware file */
+
+/**
+ *
+ * Ask the OS layer to initialise a read from a f/w file.
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @param is_fw if 0 the request if for the loader file, if 1 the request
+ * is for a f/w file.
+ *
+ * @param info a card_info_t structure containing versions information.
+ * Note that some members of the structure may not be initialised.
+ *
+ * @return \p NULL if the file is not available, or a pointer which contains
+ * OS specific information for the file (typically the contents of the file)
+ * that the HIP core uses when calling unifi_fw_read() and unifi_fw_read_stop()
+ *
+ * @ingroup upperedge
+ */
+void* unifi_fw_read_start(void *ospriv, CsrInt8 is_fw, const card_info_t *info);
+
+/**
+ *
+ * Ask the OS layer to return a portion from a f/w file.
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @param arg the OS pointer returned by unifi_fw_read_start().
+ *
+ * @param offset the offset in the f/w file to read the read from.
+ *
+ * @param buf the buffer to store the returned data.
+ *
+ * @param len the size in bytes of the requested read.
+ *
+ * @ingroup upperedge
+ */
+CsrInt32 unifi_fw_read(void *ospriv, void *arg, CsrUint32 offset, void *buf, CsrUint32 len);
+
+/**
+ *
+ * Ask the OS layer to finish reading from a f/w file.
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @param dlpriv the OS pointer returned by unifi_fw_read_start().
+ *
+ * @ingroup upperedge
+ */
+void unifi_fw_read_stop(void *ospriv, void *dlpriv);
+
+/**
+ *
+ * Ask OS layer for a handle to a dynamically allocated firmware buffer
+ * (primarily intended for production test images which may need conversion)
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @param fwbuf pointer to dynamically allocated buffer
+ *
+ * @param len length of provided buffer in bytes
+ *
+ * @ingroup upperedge
+ */
+void* unifi_fw_open_buffer(void *ospriv, void *fwbuf, CsrUint32 len);
+
+/**
+ *
+ * Release a handle to a dynamically allocated firmware buffer
+ * (primarily intended for production test images which may need conversion)
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @param fwbuf pointer to dynamically allocated buffer
+ *
+ * @ingroup upperedge
+ */
+void unifi_fw_close_buffer(void *ospriv, void *fwbuf);
+
+#ifndef CSR_WIFI_HIP_TA_DISABLE
+/*
+ * Driver must provide these.
+ *
+ * A simple implementation will just call
+ * unifi_sys_traffic_protocol_ind() or unifi_sys_traffic_classification_ind()
+ * respectively. See sme_csr_userspace/sme_userspace.c.
+ */
+/**
+ *
+ * Indicates a detected packet of type packet_type.
+ * Typically, this information is processed by the SME so
+ * unifi_ta_indicate_protocol() needs to schedule a call to
+ * unifi_sys_traffic_protocol_ind().
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @param packet_type the detected packet type.
+ *
+ * @param direction the direction of the packet (Rx, Tx).
+ *
+ * @param src_addr the source address of the packet.
+ *
+ * @ingroup upperedge
+ */
+void unifi_ta_indicate_protocol(void                              *ospriv,
+                                CsrWifiRouterCtrlTrafficPacketType packet_type,
+                                CsrWifiRouterCtrlProtocolDirection direction,
+                                const CsrWifiMacAddress           *src_addr);
+
+/**
+ *
+ * Indicates statistics for the sample data over a period.
+ * Typically, this information is processed by the SME so
+ * unifi_ta_indicate_sampling() needs to schedule a call to
+ * unifi_sys_traffic_sample_ind().
+ *
+ * @param ospriv the OS layer context.
+ *
+ * @param stats the pointer to the structure that contains the statistics.
+ *
+ * @ingroup upperedge
+ */
+void unifi_ta_indicate_sampling(void *ospriv, CsrWifiRouterCtrlTrafficStats *stats);
+void unifi_ta_indicate_l4stats(void     *ospriv,
+                               CsrUint32 rxTcpThroughput,
+                               CsrUint32 txTcpThroughput,
+                               CsrUint32 rxUdpThroughput,
+                               CsrUint32 txUdpThroughput);
+#endif
+
+void unifi_rx_queue_flush(void *ospriv);
+
+/**
+ * Call-out from the SDIO glue layer.
+ *
+ * The glue layer needs to call unifi_sdio_interrupt_handler() every time
+ * an interrupts occurs.
+ *
+ * @param card the HIP core context.
+ *
+ * @ingroup bottomedge
+ */
+void unifi_sdio_interrupt_handler(card_t *card);
+
+
+/* HELPER FUNCTIONS */
+
+/*
+ * unifi_init() and unifi_download() implement a subset of unifi_init_card functionality
+ * that excludes HIP initialization.
+ */
+CsrResult unifi_init(card_t *card);
+CsrResult unifi_download(card_t *card, CsrInt32 led_mask);
+
+/*
+ * unifi_start_processors() ensures both on-chip processors are running
+ */
+CsrResult unifi_start_processors(card_t *card);
+
+CsrResult unifi_capture_panic(card_t *card);
+
+/*
+ * Configure HIP interrupt processing mode
+ */
+#define CSR_WIFI_INTMODE_DEFAULT        0
+#define CSR_WIFI_INTMODE_RUN_BH_ONCE    1       /* Run BH once per interrupt */
+
+void unifi_set_interrupt_mode(card_t *card, CsrUint32 mode);
+
+/*
+ * unifi_request_max_clock() requests that max SDIO clock speed is set at the
+ * next suitable opportunity.
+ */
+void unifi_request_max_sdio_clock(card_t *card);
+
+
+/* Functions to lookup bulk data command names. */
+const CsrCharString* lookup_bulkcmd_name(CsrUint16 id);
+
+/* Function to log HIP's global debug buffer */
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+void unifi_debug_buf_dump(void);
+void unifi_debug_log_to_buf(const CsrCharString *fmt, ...);
+void unifi_debug_hex_to_buf(const CsrCharString *buff, CsrUint16 length);
+#endif
+
+/* Mini-coredump utility functions */
+CsrResult unifi_coredump_get_value(card_t *card, struct unifi_coredump_req *req);
+CsrResult unifi_coredump_capture(card_t *card, struct unifi_coredump_req *req);
+CsrResult unifi_coredump_request_at_next_reset(card_t *card, CsrInt8 enable);
+CsrResult unifi_coredump_init(card_t *card, CsrUint16 num_dump_buffers);
+void unifi_coredump_free(card_t *card);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CSR_WIFI_HIP_UNIFI_H__ */
diff --git a/drivers/staging/csr/csr_wifi_hip_unifi_signal_names.c b/drivers/staging/csr/csr_wifi_hip_unifi_signal_names.c
new file mode 100644
index 0000000..ee1970d
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_unifi_signal_names.c
@@ -0,0 +1,46 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include "csr_wifi_hip_unifi.h"
+
+struct sig_name
+{
+    CsrInt16             id;
+    const CsrCharString *name;
+};
+
+static const struct sig_name Unifi_bulkcmd_names[] = {
+    {  0, "SignalCmd" },
+    {  1, "CopyToHost" },
+    {  2, "CopyToHostAck" },
+    {  3, "CopyFromHost" },
+    {  4, "CopyFromHostAck" },
+    {  5, "ClearSlot" },
+    {  6, "CopyOverlay" },
+    {  7, "CopyOverlayAck" },
+    {  8, "CopyFromHostAndClearSlot" },
+    {  15, "Padding" }
+};
+
+const CsrCharString* lookup_bulkcmd_name(CsrUint16 id)
+{
+    if (id < 9)
+    {
+        return Unifi_bulkcmd_names[id].name;
+    }
+    if (id == 15)
+    {
+        return "Padding";
+    }
+
+    return "UNKNOWN";
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_unifi_udi.h b/drivers/staging/csr/csr_wifi_hip_unifi_udi.h
new file mode 100644
index 0000000..0873b7b
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_unifi_udi.h
@@ -0,0 +1,76 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     csr_wifi_hip_unifi_udi.h
+ *
+ *  PURPOSE:
+ *      Declarations and definitions for the UniFi Debug Interface.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#ifndef __CSR_WIFI_HIP_UNIFI_UDI_H__
+#define __CSR_WIFI_HIP_UNIFI_UDI_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_signals.h"
+
+
+/*
+ * Support for tracing the wire protocol.
+ */
+enum udi_log_direction
+{
+    UDI_LOG_FROM_HOST   = 0x0000,
+    UDI_LOG_TO_HOST     = 0x0001
+};
+
+typedef void (*udi_func_t)(void *ospriv, CsrUint8 *sigdata,
+                           CsrUint32 signal_len,
+                           const bulk_data_param_t *bulkdata,
+                           enum udi_log_direction dir);
+
+CsrResult unifi_set_udi_hook(card_t *card, udi_func_t udi_fn);
+CsrResult unifi_remove_udi_hook(card_t *card, udi_func_t udi_fn);
+
+
+/*
+ * Function to print current status info to a string.
+ * This is used in the linux /proc interface and might be useful
+ * in other systems.
+ */
+CsrInt32 unifi_print_status(card_t *card, CsrCharString *str, CsrInt32 *remain);
+
+#define UNIFI_SNPRINTF_RET(buf_p, remain, written)                  \
+    do {                                                            \
+        if (written >= remain) {                                    \
+            if (remain >= 2) {                                      \
+                buf_p[remain - 2] = '\n';                           \
+                buf_p[remain - 1] = 0;                              \
+            }                                                       \
+            buf_p += remain;                                        \
+            remain = 0;                                             \
+        } else if (written > 0) {                                   \
+            buf_p += written;                                       \
+            remain -= written;                                      \
+        }                                                           \
+    } while (0)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CSR_WIFI_HIP_UNIFI_UDI_H__ */
diff --git a/drivers/staging/csr/csr_wifi_hip_unifihw.h b/drivers/staging/csr/csr_wifi_hip_unifihw.h
new file mode 100644
index 0000000..5ffd6ba
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_unifihw.h
@@ -0,0 +1,67 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * File: csr_wifi_hip_unifihw.h
+ *
+ *      Definitions of various chip registers, addresses, values etc.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#ifndef __UNIFIHW_H__
+#define __UNIFIHW_H__ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Symbol Look Up Table fingerprint. IDs are in sigs.h */
+#define SLUT_FINGERPRINT        0xD397
+
+
+/* Values of LoaderOperation */
+#define UNIFI_LOADER_IDLE       0x00
+#define UNIFI_LOADER_COPY       0x01
+#define UNIFI_LOADER_ERROR_MASK 0xF0
+
+/* Values of BootLoaderOperation */
+#define UNIFI_BOOT_LOADER_IDLE       0x00
+#define UNIFI_BOOT_LOADER_RESTART    0x01
+#define UNIFI_BOOT_LOADER_PATCH      0x02
+#define UNIFI_BOOT_LOADER_LOAD_STA   0x10
+#define UNIFI_BOOT_LOADER_LOAD_PTEST 0x11
+
+
+/* Memory spaces encoded in top byte of Generic Pointer type */
+#define UNIFI_SH_DMEM   0x01    /* Shared Data Memory */
+#define UNIFI_EXT_FLASH 0x02    /* External FLASH */
+#define UNIFI_EXT_SRAM  0x03    /* External SRAM */
+#define UNIFI_REGISTERS 0x04    /* Registers */
+#define UNIFI_PHY_DMEM  0x10    /* PHY Data Memory */
+#define UNIFI_PHY_PMEM  0x11    /* PHY Program Memory */
+#define UNIFI_PHY_ROM   0x12    /* PHY ROM */
+#define UNIFI_MAC_DMEM  0x20    /* MAC Data Memory */
+#define UNIFI_MAC_PMEM  0x21    /* MAC Program Memory */
+#define UNIFI_MAC_ROM   0x22    /* MAC ROM */
+#define UNIFI_BT_DMEM   0x30    /* BT Data Memory */
+#define UNIFI_BT_PMEM   0x31    /* BT Program Memory */
+#define UNIFI_BT_ROM    0x32    /* BT ROM */
+
+#define UNIFI_MAKE_GP(R, O)  (((UNIFI_ ## R) << 24) | (O))
+#define UNIFI_GP_OFFSET(GP)  ((GP) & 0xFFFFFF)
+#define UNIFI_GP_SPACE(GP)   (((GP) >> 24) & 0xFF)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UNIFIHW_H__ */
diff --git a/drivers/staging/csr/csr_wifi_hip_unifiversion.h b/drivers/staging/csr/csr_wifi_hip_unifiversion.h
new file mode 100644
index 0000000..e1fdbb2
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_unifiversion.h
@@ -0,0 +1,38 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     unifiversion.h
+ *
+ *  PURPOSE:
+ *      Version information for the portable UniFi driver.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+#ifndef __UNIFIVERSION_H__
+#define __UNIFIVERSION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The minimum version of Host Interface Protocol required by the driver.
+ */
+#define UNIFI_HIP_MAJOR_VERSION 9
+#define UNIFI_HIP_MINOR_VERSION 1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UNIFIVERSION_H__ */
diff --git a/drivers/staging/csr/csr_wifi_hip_xbv.c b/drivers/staging/csr/csr_wifi_hip_xbv.c
new file mode 100644
index 0000000..5aaec4d
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_xbv.c
@@ -0,0 +1,1075 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ * FILE: csr_wifi_hip_xbv.c
+ *
+ * PURPOSE:
+ *      Routines for downloading firmware to UniFi.
+ *
+ *      UniFi firmware files use a nested TLV (Tag-Length-Value) format.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+#ifdef CSR_WIFI_XBV_TEST
+/* Standalone test harness */
+#include "unifi_xbv.h"
+#include "csr_wifi_hip_unifihw.h"
+#else
+/* Normal driver build */
+#include "csr_wifi_hip_unifiversion.h"
+#include "csr_wifi_hip_card.h"
+#define DBG_TAG(t)
+#endif
+
+#include "csr_wifi_hip_xbv.h"
+
+#define STREAM_CHECKSUM 0x6d34        /* Sum of uint16s in each patch stream */
+
+/* XBV sizes used in patch conversion
+ */
+#define PTDL_MAX_SIZE 2048            /* Max bytes allowed per PTDL */
+#define PTDL_HDR_SIZE (4 + 2 + 6 + 2) /* sizeof(fw_id, sec_len, patch_cmd, csum) */
+
+/* Struct to represent a buffer for reading firmware file */
+
+typedef struct
+{
+    void      *dlpriv;
+    CsrInt32   ioffset;
+    fwreadfn_t iread;
+} ct_t;
+
+/* Struct to represent a TLV field */
+typedef struct
+{
+    CsrCharString t_name[4];
+    CsrUint32     t_len;
+} tag_t;
+
+
+#define TAG_EQ(i, v)    (((i)[0] == (v)[0]) &&  \
+                         ((i)[1] == (v)[1]) &&  \
+                         ((i)[2] == (v)[2]) &&  \
+                         ((i)[3] == (v)[3]))
+
+/* We create a small stack on the stack that contains an enum
+ * indicating the containing list segments, and the offset at which
+ * those lists end.  This enables a lot more error checking. */
+typedef enum
+{
+    xbv_xbv1,
+    /*xbv_info,*/
+    xbv_fw,
+    xbv_vers,
+    xbv_vand,
+    xbv_ptch,
+    xbv_other
+} xbv_container;
+
+#define XBV_STACK_SIZE 6
+#define XBV_MAX_OFFS   0x7fffffff
+
+typedef struct
+{
+    struct
+    {
+        xbv_container container;
+        CsrInt32      ioffset_end;
+    } s[XBV_STACK_SIZE];
+    CsrUint32 ptr;
+} xbv_stack_t;
+
+static CsrInt32 read_tag(card_t *card, ct_t *ct, tag_t *tag);
+static CsrInt32 read_bytes(card_t *card, ct_t *ct, void *buf, CsrUint32 len);
+static CsrInt32 read_uint(card_t *card, ct_t *ct, CsrUint32 *u, CsrUint32 len);
+static CsrInt32 xbv_check(xbv1_t *fwinfo, const xbv_stack_t *stack,
+                          xbv_mode new_mode, xbv_container old_cont);
+static CsrInt32 xbv_push(xbv1_t *fwinfo, xbv_stack_t *stack,
+                         xbv_mode new_mode, xbv_container old_cont,
+                         xbv_container new_cont, CsrUint32 ioff);
+
+static CsrUint32 write_uint16(void *buf, const CsrUint32 offset,
+                              const CsrUint16 val);
+static CsrUint32 write_uint32(void *buf, const CsrUint32 offset,
+                              const CsrUint32 val);
+static CsrUint32 write_bytes(void *buf, const CsrUint32 offset,
+                             const CsrUint8 *data, const CsrUint32 len);
+static CsrUint32 write_tag(void *buf, const CsrUint32 offset,
+                           const CsrCharString *tag_str);
+static CsrUint32 write_chunk(void *buf, const CsrUint32 offset,
+                             const CsrCharString *tag_str,
+                             const CsrUint32 payload_len);
+static CsrUint16 calc_checksum(void *buf, const CsrUint32 offset,
+                               const CsrUint32 bytes_len);
+static CsrUint32 calc_patch_size(const xbv1_t *fwinfo);
+
+static CsrUint32 write_xbv_header(void *buf, const CsrUint32 offset,
+                                  const CsrUint32 file_payload_length);
+static CsrUint32 write_ptch_header(void *buf, const CsrUint32 offset,
+                                   const CsrUint32 fw_id);
+static CsrUint32 write_patchcmd(void *buf, const CsrUint32 offset,
+                                const CsrUint32 dst_genaddr, const CsrUint16 len);
+static CsrUint32 write_reset_ptdl(void *buf, const CsrUint32 offset,
+                                  const xbv1_t *fwinfo, CsrUint32 fw_id);
+static CsrUint32 write_fwdl_to_ptdl(void *buf, const CsrUint32 offset,
+                                    fwreadfn_t readfn, const struct FWDL *fwdl,
+                                    const void *fw_buf, const CsrUint32 fw_id,
+                                    void *rdbuf);
+
+/*
+ * ---------------------------------------------------------------------------
+ *  parse_xbv1
+ *
+ *      Scan the firmware file to find the TLVs we are interested in.
+ *      Actions performed:
+ *        - check we support the file format version in VERF
+ *      Store these TLVs if we have a firmware image:
+ *        - SLTP Symbol Lookup Table Pointer
+ *        - FWDL firmware download segments
+ *        - FWOL firmware overlay segment
+ *        - VMEQ Register probe tests to verify matching h/w
+ *      Store these TLVs if we have a patch file:
+ *        - FWID the firmware build ID that this file patches
+ *        - PTDL The actual patches
+ *
+ *      The structure pointed to by fwinfo is cleared and
+ *      'fwinfo->mode' is set to 'unknown'.  The 'fwinfo->mode'
+ *      variable is set to 'firmware' or 'patch' once we know which
+ *      sort of XBV file we have.
+ *
+ *  Arguments:
+ *      readfn          Pointer to function to call to read from the file.
+ *      dlpriv          Opaque pointer arg to pass to readfn.
+ *      fwinfo          Pointer to fwinfo struct to fill in.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR error code on failure
+ * ---------------------------------------------------------------------------
+ */
+CsrResult xbv1_parse(card_t *card, fwreadfn_t readfn, void *dlpriv, xbv1_t *fwinfo)
+{
+    ct_t ct;
+    tag_t tag;
+    xbv_stack_t stack;
+
+    ct.dlpriv = dlpriv;
+    ct.ioffset = 0;
+    ct.iread = readfn;
+
+    CsrMemSet(fwinfo, 0, sizeof(xbv1_t));
+    fwinfo->mode = xbv_unknown;
+
+    /* File must start with XBV1 triplet */
+    if (read_tag(card, &ct, &tag) <= 0)
+    {
+        unifi_error(NULL, "File is not UniFi firmware\n");
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    DBG_TAG(tag.t_name);
+
+    if (!TAG_EQ(tag.t_name, "XBV1"))
+    {
+        unifi_error(NULL, "File is not UniFi firmware (%s)\n", tag.t_name);
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    stack.ptr = 0;
+    stack.s[stack.ptr].container = xbv_xbv1;
+    stack.s[stack.ptr].ioffset_end = XBV_MAX_OFFS;
+
+    /* Now scan the file */
+    while (1)
+    {
+        CsrInt32 n;
+
+        n = read_tag(card, &ct, &tag);
+        if (n < 0)
+        {
+            unifi_error(NULL, "No tag\n");
+            return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+        }
+        if (n == 0)
+        {
+            /* End of file */
+            break;
+        }
+
+        DBG_TAG(tag.t_name);
+
+        /* File format version */
+        if (TAG_EQ(tag.t_name, "VERF"))
+        {
+            CsrUint32 version;
+
+            if (xbv_check(fwinfo, &stack, xbv_unknown, xbv_xbv1) ||
+                (tag.t_len != 2) ||
+                read_uint(card, &ct, &version, 2))
+            {
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+            if (version != 0)
+            {
+                unifi_error(NULL, "Unsupported firmware file version: %d.%d\n",
+                            version >> 8, version & 0xFF);
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+        }
+        else if (TAG_EQ(tag.t_name, "LIST"))
+        {
+            CsrCharString name[4];
+            CsrUint32 list_end;
+
+            list_end = ct.ioffset + tag.t_len;
+
+            if (read_bytes(card, &ct, name, 4))
+            {
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+
+            DBG_TAG(name);
+            if (TAG_EQ(name, "FW  "))
+            {
+                if (xbv_push(fwinfo, &stack, xbv_firmware, xbv_xbv1, xbv_fw, list_end))
+                {
+                    return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+                }
+            }
+            else if (TAG_EQ(name, "VERS"))
+            {
+                if (xbv_push(fwinfo, &stack, xbv_firmware, xbv_fw, xbv_vers, list_end) ||
+                    (fwinfo->vers.num_vand != 0))
+                {
+                    return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+                }
+            }
+            else if (TAG_EQ(name, "VAND"))
+            {
+                struct VAND *vand;
+
+                if (xbv_push(fwinfo, &stack, xbv_firmware, xbv_vers, xbv_vand, list_end) ||
+                    (fwinfo->vers.num_vand >= MAX_VAND))
+                {
+                    return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+                }
+
+                /* Get a new VAND */
+                vand = fwinfo->vand + fwinfo->vers.num_vand++;
+
+                /* Fill it in */
+                vand->first = fwinfo->num_vmeq;
+                vand->count = 0;
+            }
+            else if (TAG_EQ(name, "PTCH"))
+            {
+                if (xbv_push(fwinfo, &stack, xbv_patch, xbv_xbv1, xbv_ptch, list_end))
+                {
+                    return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+                }
+            }
+            else
+            {
+                /* Skip over any other lists.  We dont bother to push
+                 * the new list type now as we would only pop it at
+                 * the end of the outer loop. */
+                ct.ioffset += tag.t_len - 4;
+            }
+        }
+        else if (TAG_EQ(tag.t_name, "SLTP"))
+        {
+            CsrUint32 addr;
+
+            if (xbv_check(fwinfo, &stack, xbv_firmware, xbv_fw) ||
+                (tag.t_len != 4) ||
+                (fwinfo->slut_addr != 0) ||
+                read_uint(card, &ct, &addr, 4))
+            {
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+
+            fwinfo->slut_addr = addr;
+        }
+        else if (TAG_EQ(tag.t_name, "FWDL"))
+        {
+            CsrUint32 addr;
+            struct FWDL *fwdl;
+
+            if (xbv_check(fwinfo, &stack, xbv_firmware, xbv_fw) ||
+                (fwinfo->num_fwdl >= MAX_FWDL) ||
+                (read_uint(card, &ct, &addr, 4)))
+            {
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+
+            fwdl = fwinfo->fwdl + fwinfo->num_fwdl++;
+
+            fwdl->dl_size = tag.t_len - 4;
+            fwdl->dl_addr = addr;
+            fwdl->dl_offset = ct.ioffset;
+
+            ct.ioffset += tag.t_len - 4;
+        }
+        else if (TAG_EQ(tag.t_name, "FWOV"))
+        {
+            if (xbv_check(fwinfo, &stack, xbv_firmware, xbv_fw) ||
+                (fwinfo->fwov.dl_size != 0) ||
+                (fwinfo->fwov.dl_offset != 0))
+            {
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+
+            fwinfo->fwov.dl_size = tag.t_len;
+            fwinfo->fwov.dl_offset = ct.ioffset;
+
+            ct.ioffset += tag.t_len;
+        }
+        else if (TAG_EQ(tag.t_name, "VMEQ"))
+        {
+            CsrUint32 temp[3];
+            struct VAND *vand;
+            struct VMEQ *vmeq;
+
+            if (xbv_check(fwinfo, &stack, xbv_firmware, xbv_vand) ||
+                (fwinfo->num_vmeq >= MAX_VMEQ) ||
+                (fwinfo->vers.num_vand == 0) ||
+                (tag.t_len != 8) ||
+                read_uint(card, &ct, &temp[0], 4) ||
+                read_uint(card, &ct, &temp[1], 2) ||
+                read_uint(card, &ct, &temp[2], 2))
+            {
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+
+            /* Get the last VAND */
+            vand = fwinfo->vand + (fwinfo->vers.num_vand - 1);
+
+            /* Get a new VMEQ */
+            vmeq = fwinfo->vmeq + fwinfo->num_vmeq++;
+
+            /* Note that this VAND contains another VMEQ */
+            vand->count++;
+
+            /* Fill in the VMEQ */
+            vmeq->addr = temp[0];
+            vmeq->mask = (CsrUint16)temp[1];
+            vmeq->value = (CsrUint16)temp[2];
+        }
+        else if (TAG_EQ(tag.t_name, "FWID"))
+        {
+            CsrUint32 build_id;
+
+            if (xbv_check(fwinfo, &stack, xbv_patch, xbv_ptch) ||
+                (tag.t_len != 4) ||
+                (fwinfo->build_id != 0) ||
+                read_uint(card, &ct, &build_id, 4))
+            {
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+
+            fwinfo->build_id = build_id;
+        }
+        else if (TAG_EQ(tag.t_name, "PTDL"))
+        {
+            struct PTDL *ptdl;
+
+            if (xbv_check(fwinfo, &stack, xbv_patch, xbv_ptch) ||
+                (fwinfo->num_ptdl >= MAX_PTDL))
+            {
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+
+            /* Allocate a new PTDL */
+            ptdl = fwinfo->ptdl + fwinfo->num_ptdl++;
+
+            ptdl->dl_size = tag.t_len;
+            ptdl->dl_offset = ct.ioffset;
+
+            ct.ioffset += tag.t_len;
+        }
+        else
+        {
+            /*
+             * If we get here it is a tag we are not interested in,
+             * just skip over it.
+             */
+            ct.ioffset += tag.t_len;
+        }
+
+        /* Check to see if we are at the end of the currently stacked
+         * segment.  We could finish more than one list at a time. */
+        while (ct.ioffset >= stack.s[stack.ptr].ioffset_end)
+        {
+            if (ct.ioffset > stack.s[stack.ptr].ioffset_end)
+            {
+                unifi_error(NULL,
+                            "XBV file has overrun stack'd segment %d (%d > %d)\n",
+                            stack.ptr, ct.ioffset, stack.s[stack.ptr].ioffset_end);
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+            if (stack.ptr <= 0)
+            {
+                unifi_error(NULL, "XBV file has underrun stack pointer\n");
+                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+            }
+            stack.ptr--;
+        }
+    }
+
+    if (stack.ptr != 0)
+    {
+        unifi_error(NULL, "Last list of XBV is not complete.\n");
+        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* xbv1_parse() */
+
+
+/* Check the the XBV file is of a consistant sort (either firmware or
+ * patch) and that we are in the correct containing list type. */
+static CsrInt32 xbv_check(xbv1_t *fwinfo, const xbv_stack_t *stack,
+                          xbv_mode new_mode, xbv_container old_cont)
+{
+    /* If the new file mode is unknown the current packet could be in
+     * either (any) type of XBV file, and we cant make a decission at
+     * this time. */
+    if (new_mode != xbv_unknown)
+    {
+        if (fwinfo->mode == xbv_unknown)
+        {
+            fwinfo->mode = new_mode;
+        }
+        else if (fwinfo->mode != new_mode)
+        {
+            return -1;
+        }
+    }
+    /* If the current stack top doesn't match what we expect then the
+     * file is corrupt. */
+    if (stack->s[stack->ptr].container != old_cont)
+    {
+        return -1;
+    }
+    return 0;
+}
+
+
+/* Make checks as above and then enter a new list */
+static CsrInt32 xbv_push(xbv1_t *fwinfo, xbv_stack_t *stack,
+                         xbv_mode new_mode, xbv_container old_cont,
+                         xbv_container new_cont, CsrUint32 new_ioff)
+{
+    if (xbv_check(fwinfo, stack, new_mode, old_cont))
+    {
+        return -1;
+    }
+
+    /* Check that our stack won't overflow. */
+    if (stack->ptr >= (XBV_STACK_SIZE - 1))
+    {
+        return -1;
+    }
+
+    /* Add the new list element to the top of the stack. */
+    stack->ptr++;
+    stack->s[stack->ptr].container = new_cont;
+    stack->s[stack->ptr].ioffset_end = new_ioff;
+
+    return 0;
+}
+
+
+static CsrUint32 xbv2uint(CsrUint8 *ptr, CsrInt32 len)
+{
+    CsrUint32 u = 0;
+    CsrInt16 i;
+
+    for (i = 0; i < len; i++)
+    {
+        CsrUint32 b;
+        b = ptr[i];
+        u += b << (i * 8);
+    }
+    return u;
+}
+
+
+static CsrInt32 read_tag(card_t *card, ct_t *ct, tag_t *tag)
+{
+    CsrUint8 buf[8];
+    CsrInt32 n;
+
+    n = (*ct->iread)(card->ospriv, ct->dlpriv, ct->ioffset, buf, 8);
+    if (n <= 0)
+    {
+        return n;
+    }
+
+    /* read the tag and length */
+    if (n != 8)
+    {
+        return -1;
+    }
+
+    /* get section tag */
+    CsrMemCpy(tag->t_name, buf, 4);
+
+    /* get section length */
+    tag->t_len = xbv2uint(buf + 4, 4);
+
+    ct->ioffset += 8;
+
+    return 8;
+} /* read_tag() */
+
+
+static CsrInt32 read_bytes(card_t *card, ct_t *ct, void *buf, CsrUint32 len)
+{
+    /* read the tag value */
+    if ((*ct->iread)(card->ospriv, ct->dlpriv, ct->ioffset, buf, len) != (CsrInt32)len)
+    {
+        return -1;
+    }
+
+    ct->ioffset += len;
+
+    return 0;
+} /* read_bytes() */
+
+
+static CsrInt32 read_uint(card_t *card, ct_t *ct, CsrUint32 *u, CsrUint32 len)
+{
+    CsrUint8 buf[4];
+
+    /* Integer cannot be more than 4 bytes */
+    if (len > 4)
+    {
+        return -1;
+    }
+
+    if (read_bytes(card, ct, buf, len))
+    {
+        return -1;
+    }
+
+    *u = xbv2uint(buf, len);
+
+    return 0;
+} /* read_uint() */
+
+
+static CsrUint32 write_uint16(void *buf, const CsrUint32 offset, const CsrUint16 val)
+{
+    CsrUint8 *dst = (CsrUint8 *)buf + offset;
+    *dst++ = (CsrUint8)(val & 0xff); /* LSB first */
+    *dst = (CsrUint8)(val >> 8);
+    return sizeof(CsrUint16);
+}
+
+
+static CsrUint32 write_uint32(void *buf, const CsrUint32 offset, const CsrUint32 val)
+{
+    (void)write_uint16(buf, offset + 0, (CsrUint16)(val & 0xffff));
+    (void)write_uint16(buf, offset + 2, (CsrUint16)(val >> 16));
+    return sizeof(CsrUint32);
+}
+
+
+static CsrUint32 write_bytes(void *buf, const CsrUint32 offset, const CsrUint8 *data, const CsrUint32 len)
+{
+    CsrUint32 i;
+    CsrUint8 *dst = (CsrUint8 *)buf + offset;
+
+    for (i = 0; i < len; i++)
+    {
+        *dst++ = *((CsrUint8 *)data + i);
+    }
+    return len;
+}
+
+
+static CsrUint32 write_tag(void *buf, const CsrUint32 offset, const CsrCharString *tag_str)
+{
+    CsrUint8 *dst = (CsrUint8 *)buf + offset;
+    CsrMemCpy(dst, tag_str, 4);
+    return 4;
+}
+
+
+static CsrUint32 write_chunk(void *buf, const CsrUint32 offset, const CsrCharString *tag_str, const CsrUint32 payload_len)
+{
+    CsrUint32 written = 0;
+    written += write_tag(buf, offset, tag_str);
+    written += write_uint32(buf, written + offset, (CsrUint32)payload_len);
+
+    return written;
+}
+
+
+static CsrUint16 calc_checksum(void *buf, const CsrUint32 offset, const CsrUint32 bytes_len)
+{
+    CsrUint32 i;
+    CsrUint8 *src = (CsrUint8 *)buf + offset;
+    CsrUint16 sum = 0;
+    CsrUint16 val;
+
+    for (i = 0; i < bytes_len / 2; i++)
+    {
+        /* Contents copied to file is LE, host might not be */
+        val = (CsrUint16) * src++;         /* LSB */
+        val += (CsrUint16)(*src++) << 8;   /* MSB */
+        sum += val;
+    }
+
+    /* Total of uint16s in the stream plus the stored check value
+     * should equal STREAM_CHECKSUM when decoded.
+     */
+    return (STREAM_CHECKSUM - sum);
+}
+
+
+#define PTDL_RESET_DATA_SIZE  20  /* Size of reset vectors PTDL */
+
+static CsrUint32 calc_patch_size(const xbv1_t *fwinfo)
+{
+    CsrInt16 i;
+    CsrUint32 size = 0;
+
+    /*
+     * Work out how big an equivalent patch format file must be for this image.
+     * This only needs to be approximate, so long as it's large enough.
+     */
+    if (fwinfo->mode != xbv_firmware)
+    {
+        return 0;
+    }
+
+    /* Payload (which will get put into a series of PTDLs) */
+    for (i = 0; i < fwinfo->num_fwdl; i++)
+    {
+        size += fwinfo->fwdl[i].dl_size;
+    }
+
+    /* Another PTDL at the end containing reset vectors */
+    size += PTDL_RESET_DATA_SIZE;
+
+    /* PTDL headers. Add one for remainder, one for reset vectors */
+    size += ((fwinfo->num_fwdl / PTDL_MAX_SIZE) + 2) * PTDL_HDR_SIZE;
+
+    /* Another 1K sufficient to cover miscellaneous headers */
+    size += 1024;
+
+    return size;
+}
+
+
+static CsrUint32 write_xbv_header(void *buf, const CsrUint32 offset, const CsrUint32 file_payload_length)
+{
+    CsrUint32 written = 0;
+
+    /* The length value given to the XBV chunk is the length of all subsequent
+     * contents of the file, excluding the 8 byte size of the XBV1 header itself
+     * (The added 6 bytes thus accounts for the size of the VERF)
+     */
+    written += write_chunk(buf, offset + written, (CsrCharString *)"XBV1", file_payload_length + 6);
+
+    written += write_chunk(buf, offset + written, (CsrCharString *)"VERF", 2);
+    written += write_uint16(buf,  offset + written, 0);      /* File version */
+
+    return written;
+}
+
+
+static CsrUint32 write_ptch_header(void *buf, const CsrUint32 offset, const CsrUint32 fw_id)
+{
+    CsrUint32 written = 0;
+
+    /* LIST is written with a zero length, to be updated later */
+    written += write_chunk(buf, offset + written, (CsrCharString *)"LIST", 0);
+    written += write_tag(buf, offset + written, (CsrCharString *)"PTCH");        /* List type */
+
+    written += write_chunk(buf, offset + written, (CsrCharString *)"FWID", 4);
+    written += write_uint32(buf, offset + written, fw_id);
+
+
+    return written;
+}
+
+
+#define UF_REGION_PHY  1
+#define UF_REGION_MAC  2
+#define UF_MEMPUT_MAC  0x0000
+#define UF_MEMPUT_PHY  0x1000
+
+static CsrUint32 write_patchcmd(void *buf, const CsrUint32 offset, const CsrUint32 dst_genaddr, const CsrUint16 len)
+{
+    CsrUint32 written = 0;
+    CsrUint32 region = (dst_genaddr >> 28);
+    CsrUint16 cmd_and_len = UF_MEMPUT_MAC;
+
+    if (region == UF_REGION_PHY)
+    {
+        cmd_and_len = UF_MEMPUT_PHY;
+    }
+    else if (region != UF_REGION_MAC)
+    {
+        return 0; /* invalid */
+    }
+
+    /* Write the command and data length */
+    cmd_and_len |= len;
+    written += write_uint16(buf, offset + written, cmd_and_len);
+
+    /* Write the destination generic address */
+    written += write_uint16(buf, offset + written, (CsrUint16)(dst_genaddr >> 16));
+    written += write_uint16(buf, offset + written, (CsrUint16)(dst_genaddr & 0xffff));
+
+    /* The data payload should be appended to the command */
+    return written;
+}
+
+
+static CsrUint32 write_fwdl_to_ptdl(void *buf, const CsrUint32 offset, fwreadfn_t readfn,
+                                    const struct FWDL *fwdl, const void *dlpriv,
+                                    const CsrUint32 fw_id, void *fw_buf)
+{
+    CsrUint32 written = 0;
+    CsrInt16 chunks = 0;
+    CsrUint32 left = fwdl->dl_size;      /* Bytes left in this fwdl */
+    CsrUint32 dl_addr = fwdl->dl_addr;   /* Target address of fwdl image on XAP */
+    CsrUint32 dl_offs = fwdl->dl_offset; /* Offset of fwdl image data in source */
+    CsrUint16 csum;
+    CsrUint32 csum_start_offs;           /* first offset to include in checksum */
+    CsrUint32 sec_data_len;              /* section data byte count */
+    CsrUint32 sec_len;                   /* section data + header byte count */
+
+    /* FWDL maps to one or more PTDLs, as max size for a PTDL is 1K words */
+    while (left)
+    {
+        /* Calculate amount to be transferred */
+        sec_data_len = CSRMIN(left, PTDL_MAX_SIZE - PTDL_HDR_SIZE);
+        sec_len = sec_data_len + PTDL_HDR_SIZE;
+
+        /* Write PTDL header + entire PTDL size */
+        written += write_chunk(buf, offset + written, (CsrCharString *)"PTDL", sec_len);
+        /* bug digest implies 4 bytes of padding here, but that seems wrong */
+
+        /* Checksum starts here */
+        csum_start_offs = offset + written;
+
+        /* Patch-chunk header: fw_id. Note that this is in XAP word order */
+        written += write_uint16(buf, offset + written, (CsrUint16)(fw_id >> 16));
+        written += write_uint16(buf, offset + written, (CsrUint16)(fw_id & 0xffff));
+
+        /* Patch-chunk header: section length in uint16s */
+        written += write_uint16(buf, offset + written, (CsrUint16)(sec_len / 2));
+
+
+        /* Write the appropriate patch command for the data's destination ptr */
+        written += write_patchcmd(buf, offset + written, dl_addr, (CsrUint16)(sec_data_len / 2));
+
+        /* Write the data itself (limited to the max chunk length) */
+        if (readfn(NULL, (void *)dlpriv, dl_offs, fw_buf, sec_data_len) < 0)
+        {
+            return 0;
+        }
+
+        written += write_bytes(buf,
+                               offset + written,
+                               fw_buf,
+                               sec_data_len);
+
+        /* CsrUint16 checksum calculated over data written */
+        csum = calc_checksum(buf, csum_start_offs, written - (csum_start_offs - offset));
+        written += write_uint16(buf, offset + written, csum);
+
+        left -= sec_data_len;
+        dl_addr += sec_data_len;
+        dl_offs += sec_data_len;
+        chunks++;
+    }
+
+    return written;
+}
+
+
+#define SEC_CMD_LEN         ((4 + 2) * 2) /* sizeof(cmd, vector) per XAP */
+#define PTDL_VEC_HDR_SIZE   (4 + 2 + 2)   /* sizeof(fw_id, sec_len, csum) */
+#define UF_MAC_START_VEC    0x00c00000    /* Start address of image on MAC */
+#define UF_PHY_START_VEC    0x00c00000    /* Start address of image on PHY */
+#define UF_MAC_START_CMD    0x6000        /* MAC "Set start address" command */
+#define UF_PHY_START_CMD    0x7000        /* PHY "Set start address" command */
+
+static CsrUint32 write_reset_ptdl(void *buf, const CsrUint32 offset, const xbv1_t *fwinfo, CsrUint32 fw_id)
+{
+    CsrUint32 written = 0;
+    CsrUint16 csum;
+    CsrUint32 csum_start_offs;                 /* first offset to include in checksum */
+    CsrUint32 sec_len;                         /* section data + header byte count */
+
+    sec_len = SEC_CMD_LEN + PTDL_VEC_HDR_SIZE; /* Total section byte length */
+
+    /* Write PTDL header + entire PTDL size */
+    written += write_chunk(buf, offset + written, (CsrCharString *)"PTDL", sec_len);
+
+    /* Checksum starts here */
+    csum_start_offs = offset + written;
+
+    /* Patch-chunk header: fw_id. Note that this is in XAP word order */
+    written += write_uint16(buf, offset + written, (CsrUint16)(fw_id >> 16));
+    written += write_uint16(buf, offset + written, (CsrUint16)(fw_id & 0xffff));
+
+    /* Patch-chunk header: section length in uint16s */
+    written += write_uint16(buf, offset + written, (CsrUint16)(sec_len / 2));
+
+    /*
+     * Restart addresses to be executed on subsequent loader restart command.
+     */
+
+    /* Setup the MAC start address, note word ordering */
+    written += write_uint16(buf, offset + written, UF_MAC_START_CMD);
+    written += write_uint16(buf, offset + written, (UF_MAC_START_VEC >> 16));
+    written += write_uint16(buf, offset + written, (UF_MAC_START_VEC & 0xffff));
+
+    /* Setup the PHY start address, note word ordering */
+    written += write_uint16(buf, offset + written, UF_PHY_START_CMD);
+    written += write_uint16(buf, offset + written, (UF_PHY_START_VEC >> 16));
+    written += write_uint16(buf, offset + written, (UF_PHY_START_VEC & 0xffff));
+
+    /* CsrUint16 checksum calculated over data written */
+    csum = calc_checksum(buf, csum_start_offs, written - (csum_start_offs - offset));
+    written += write_uint16(buf, offset + written, csum);
+
+    return written;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  read_slut
+ *
+ *      desc
+ *
+ *  Arguments:
+ *      readfn          Pointer to function to call to read from the file.
+ *      dlpriv          Opaque pointer arg to pass to readfn.
+ *      addr            Offset into firmware image of SLUT.
+ *      fwinfo          Pointer to fwinfo struct to fill in.
+ *
+ *  Returns:
+ *      Number of SLUT entries in the f/w, or -1 if the image was corrupt.
+ * ---------------------------------------------------------------------------
+ */
+CsrInt32 xbv1_read_slut(card_t *card, fwreadfn_t readfn, void *dlpriv, xbv1_t *fwinfo,
+                        symbol_t *slut, CsrUint32 slut_len)
+{
+    CsrInt16 i;
+    CsrInt32 offset;
+    CsrUint32 magic;
+    CsrUint32 count = 0;
+    ct_t ct;
+
+    if (fwinfo->mode != xbv_firmware)
+    {
+        return -1;
+    }
+
+    /* Find the d/l segment containing the SLUT */
+    /* This relies on the SLUT being entirely contained in one segment */
+    offset = -1;
+    for (i = 0; i < fwinfo->num_fwdl; i++)
+    {
+        if ((fwinfo->slut_addr >= fwinfo->fwdl[i].dl_addr) &&
+            (fwinfo->slut_addr < (fwinfo->fwdl[i].dl_addr + fwinfo->fwdl[i].dl_size)))
+        {
+            offset = fwinfo->fwdl[i].dl_offset +
+                     (fwinfo->slut_addr - fwinfo->fwdl[i].dl_addr);
+        }
+    }
+    if (offset < 0)
+    {
+        return -1;
+    }
+
+    ct.dlpriv = dlpriv;
+    ct.ioffset = offset;
+    ct.iread = readfn;
+
+    if (read_uint(card, &ct, &magic, 2))
+    {
+        return -1;
+    }
+    if (magic != SLUT_FINGERPRINT)
+    {
+        return -1;
+    }
+
+    while (count < slut_len)
+    {
+        CsrUint32 id, obj;
+
+        /* Read Symbol Id */
+        if (read_uint(card, &ct, &id, 2))
+        {
+            return -1;
+        }
+
+        /* Check for end of table marker */
+        if (id == CSR_SLT_END)
+        {
+            break;
+        }
+
+        /* Read Symbol Value */
+        if (read_uint(card, &ct, &obj, 4))
+        {
+            return -1;
+        }
+
+        slut[count].id  = (CsrUint16)id;
+        slut[count].obj = obj;
+        count++;
+    }
+
+    return count;
+} /* read_slut() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  xbv_to_patch
+ *
+ *      Convert (the relevant parts of) a firmware xbv file into a patch xbv
+ *
+ *  Arguments:
+ *      card
+ *      fw_buf - pointer to xbv firmware image
+ *      fwinfo - structure describing the firmware image
+ *      size   - pointer to location into which size of f/w is written.
+ *
+ *  Returns:
+ *      Pointer to firmware image, or NULL on error. Caller must free this
+ *      buffer via CsrMemFree() once it's finished with.
+ *
+ *  Notes:
+ *      The input fw_buf should have been checked via xbv1_parse prior to
+ *      calling this function, so the input image is assumed valid.
+ * ---------------------------------------------------------------------------
+ */
+#define PTCH_LIST_SIZE 16         /* sizeof PTCH+FWID chunk in LIST header */
+
+void* xbv_to_patch(card_t *card, fwreadfn_t readfn,
+                   const void *fw_buf, const xbv1_t *fwinfo, CsrUint32 *size)
+{
+    void *patch_buf = NULL;
+    CsrUint32 patch_buf_size;
+    CsrUint32 payload_offs = 0;           /* Start of XBV payload */
+    CsrInt16 i;
+    CsrUint32 patch_offs = 0;
+    CsrUint32 list_len_offs = 0;          /* Offset of PTDL LIST length parameter */
+    CsrUint32 ptdl_start_offs = 0;        /* Offset of first PTDL chunk */
+    CsrUint32 fw_id;
+    void *rdbuf;
+
+    if (!fw_buf || !fwinfo || !card)
+    {
+        return NULL;
+    }
+
+    if (fwinfo->mode != xbv_firmware)
+    {
+        unifi_error(NULL, "Not a firmware file\n");
+        return NULL;
+    }
+
+    /* Pre-allocate read buffer for chunk conversion */
+    rdbuf = CsrMemAlloc(PTDL_MAX_SIZE);
+    if (!rdbuf)
+    {
+        unifi_error(card, "Couldn't alloc conversion buffer\n");
+        return NULL;
+    }
+
+    /* Loader requires patch file's build ID to match the running firmware's */
+    fw_id = card->build_id;
+
+    /* Firmware XBV1 contains VERF, optional INFO, SLUT(s), FWDL(s)          */
+    /* Other chunks should get skipped.                                      */
+    /* VERF should be sanity-checked against chip version                    */
+
+    /* Patch    XBV1 contains VERF, optional INFO, PTCH                      */
+    /*          PTCH contains FWID, optional INFO, PTDL(s), PTDL(start_vec)  */
+    /* Each FWDL is split into PTDLs (each is 1024 XAP words max)            */
+    /* Each PTDL contains running ROM f/w version, and checksum              */
+    /* MAC/PHY reset addresses (known) are added into a final PTDL           */
+
+    /* The input image has already been parsed, and loaded into fwinfo, so we
+     * can use that to build the output image
+     */
+    patch_buf_size = calc_patch_size(fwinfo);
+
+    patch_buf = (void *)CsrMemAlloc(patch_buf_size);
+    if (!patch_buf)
+    {
+        CsrMemFree(rdbuf);
+        unifi_error(NULL, "Can't malloc buffer for patch conversion\n");
+        return NULL;
+    }
+
+    CsrMemSet(patch_buf, 0xdd, patch_buf_size);
+
+    /* Write XBV + VERF headers */
+    patch_offs += write_xbv_header(patch_buf, patch_offs, 0);
+    payload_offs = patch_offs;
+
+    /* Write patch (LIST) header */
+    list_len_offs = patch_offs + 4;    /* Save LIST.length offset for later update */
+    patch_offs += write_ptch_header(patch_buf, patch_offs, fw_id);
+
+    /* Save start offset of the PTDL chunks */
+    ptdl_start_offs = patch_offs;
+
+    /* Write LIST of firmware PTDL blocks */
+    for (i = 0; i < fwinfo->num_fwdl; i++)
+    {
+        patch_offs += write_fwdl_to_ptdl(patch_buf,
+                                         patch_offs,
+                                         readfn,
+                                         &fwinfo->fwdl[i],
+                                         fw_buf,
+                                         fw_id,
+                                         rdbuf);
+    }
+
+    /* Write restart-vector PTDL last */
+    patch_offs += write_reset_ptdl(patch_buf, patch_offs, fwinfo, fw_id);
+
+    /* Now the length is known, update the LIST.length */
+    (void)write_uint32(patch_buf, list_len_offs,
+                       (patch_offs - ptdl_start_offs) + PTCH_LIST_SIZE);
+
+    /* Re write XBV headers just to fill in the correct file size */
+    (void)write_xbv_header(patch_buf, 0, (patch_offs - payload_offs));
+
+    unifi_trace(card->ospriv, UDBG1, "XBV:PTCH size %u, fw_id %u\n",
+                patch_offs, fw_id);
+    if (size)
+    {
+        *size = patch_offs;
+    }
+    CsrMemFree(rdbuf);
+
+    return patch_buf;
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_hip_xbv.h b/drivers/staging/csr/csr_wifi_hip_xbv.h
new file mode 100644
index 0000000..fdc4560
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_xbv.h
@@ -0,0 +1,127 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/*
+ * ---------------------------------------------------------------------------
+ * FILE: csr_wifi_hip_xbv.h
+ *
+ * PURPOSE:
+ *      Definitions and declarations for code to read XBV files - the UniFi
+ *      firmware download file format.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#ifndef __XBV_H__
+#define __XBV_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_XBV_TEST
+/* Driver includes */
+#include "csr_wifi_hip_unifi.h"
+#endif
+
+
+struct VMEQ
+{
+    CsrUint32 addr;
+    CsrUint16 mask;
+    CsrUint16 value;
+};
+
+struct VAND
+{
+    CsrUint32 first;
+    CsrUint32 count;
+};
+
+struct VERS
+{
+    CsrUint32 num_vand;
+};
+
+struct FWDL
+{
+    CsrUint32 dl_addr;
+    CsrUint32 dl_size;
+    CsrUint32 dl_offset;
+};
+
+struct FWOV
+{
+    CsrUint32 dl_size;
+    CsrUint32 dl_offset;
+};
+
+struct PTDL
+{
+    CsrUint32 dl_size;
+    CsrUint32 dl_offset;
+};
+
+#define MAX_VMEQ 64
+#define MAX_VAND 64
+#define MAX_FWDL 256
+#define MAX_PTDL 256
+
+/* An XBV1 file can either contain firmware or patches (at the
+ * moment).  The 'mode' member of the xbv1_t structure tells us which
+ * one is the case. */
+typedef enum
+{
+    xbv_unknown,
+    xbv_firmware,
+    xbv_patch
+} xbv_mode;
+
+typedef struct
+{
+    xbv_mode mode;
+
+    /* Parts of a Firmware XBV1 */
+
+    struct VMEQ vmeq[MAX_VMEQ];
+    CsrUint32   num_vmeq;
+    struct VAND vand[MAX_VAND];
+    struct VERS vers;
+
+    CsrUint32 slut_addr;
+
+    /* F/W download image, possibly more than one part */
+    struct FWDL fwdl[MAX_FWDL];
+    CsrInt16    num_fwdl;
+
+    /* F/W overlay image, add r not used */
+    struct FWOV fwov;
+
+    /* Parts of a Patch XBV1 */
+
+    CsrUint32 build_id;
+
+    struct PTDL ptdl[MAX_PTDL];
+    CsrInt16    num_ptdl;
+}  xbv1_t;
+
+
+typedef CsrInt32 (*fwreadfn_t)(void *ospriv, void *dlpriv, CsrUint32 offset, void *buf, CsrUint32 len);
+
+CsrResult xbv1_parse(card_t *card, fwreadfn_t readfn, void *dlpriv, xbv1_t *fwinfo);
+CsrInt32 xbv1_read_slut(card_t *card, fwreadfn_t readfn, void *dlpriv, xbv1_t *fwinfo,
+                        symbol_t *slut, CsrUint32 slut_len);
+void* xbv_to_patch(card_t *card, fwreadfn_t readfn, const void *fw_buf, const xbv1_t *fwinfo,
+                   CsrUint32 *size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XBV_H__ */
diff --git a/drivers/staging/csr/csr_wifi_hostio_prim.h b/drivers/staging/csr/csr_wifi_hostio_prim.h
new file mode 100644
index 0000000..bf7c55c
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hostio_prim.h
@@ -0,0 +1,27 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+
+#ifndef CSR_WIFI_HOSTIO_H
+#define CSR_WIFI_HOSTIO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define CSR_WIFI_HOSTIO_PRIM 0x0453
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_HOSTIO_H */
+
diff --git a/drivers/staging/csr/csr_wifi_lib.h b/drivers/staging/csr/csr_wifi_lib.h
new file mode 100644
index 0000000..4c691fc
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_lib.h
@@ -0,0 +1,113 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+#ifndef CSR_WIFI_LIB_H__
+#define CSR_WIFI_LIB_H__
+
+#include "csr_types.h"
+#include "csr_wifi_fsm_event.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiFsmEventInit
+ *
+ *  DESCRIPTION
+ *      Macro to initialise the members of a CsrWifiFsmEvent.
+ *----------------------------------------------------------------------------*/
+#define CsrWifiFsmEventInit(evt, p_primtype, p_msgtype, p_dst, p_src) \
+    (evt)->primtype = p_primtype; \
+    (evt)->type = p_msgtype; \
+    (evt)->destination = p_dst; \
+    (evt)->source = p_src
+
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiEvent_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrWifiEvent
+ *
+ *----------------------------------------------------------------------------*/
+CsrWifiFsmEvent* CsrWifiEvent_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrSchedQid dst, CsrSchedQid src);
+
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint8        value;
+} CsrWifiEventCsrUint8;
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiEventCsrUint8_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrWifiEventCsrUint8
+ *
+ *----------------------------------------------------------------------------*/
+CsrWifiEventCsrUint8* CsrWifiEventCsrUint8_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrSchedQid dst, CsrSchedQid src, CsrUint8 value);
+
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       value;
+} CsrWifiEventCsrUint16;
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiEventCsrUint16_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrWifiEventCsrUint16
+ *
+ *----------------------------------------------------------------------------*/
+CsrWifiEventCsrUint16* CsrWifiEventCsrUint16_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrSchedQid dst, CsrSchedQid src, CsrUint16 value);
+
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint32       value;
+} CsrWifiEventCsrUint32;
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiEventCsrUint32_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrWifiEventCsrUint32
+ *
+ *----------------------------------------------------------------------------*/
+CsrWifiEventCsrUint32* CsrWifiEventCsrUint32_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrSchedQid dst, CsrSchedQid src, CsrUint32 value);
+
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       value16;
+    CsrUint8        value8;
+} CsrWifiEventCsrUint16CsrUint8;
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiEventCsrUint16CsrUint8_struct
+ *
+ *  DESCRIPTION
+ *      Generic message creator.
+ *      Allocates and fills in a message with the signature CsrWifiEventCsrUint16CsrUint8
+ *
+ *----------------------------------------------------------------------------*/
+CsrWifiEventCsrUint16CsrUint8* CsrWifiEventCsrUint16CsrUint8_struct(CsrUint16 primtype, CsrUint16 msgtype, CsrSchedQid dst, CsrSchedQid src, CsrUint16 value16, CsrUint8 value8);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_LIB_H__ */
diff --git a/drivers/staging/csr/csr_wifi_msgconv.h b/drivers/staging/csr/csr_wifi_msgconv.h
new file mode 100644
index 0000000..d74e595
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_msgconv.h
@@ -0,0 +1,60 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifndef CSR_WIFI_MSGCONV_H__
+#define CSR_WIFI_MSGCONV_H__
+
+#include "csr_types.h"
+#include "csr_prim_defs.h"
+#include "csr_sched.h"
+#include "csr_unicode.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void CsrUint16SerBigEndian(CsrUint8 *ptr, CsrSize *len, CsrUint16 v);
+void CsrUint24SerBigEndian(CsrUint8 *ptr, CsrSize *len, CsrUint32 v);
+void CsrUint32SerBigEndian(CsrUint8 *ptr, CsrSize *len, CsrUint32 v);
+
+void CsrUint16DesBigEndian(CsrUint16 *v, CsrUint8 *buffer, CsrSize *offset);
+void CsrUint24DesBigEndian(CsrUint32 *v, CsrUint8 *buffer, CsrSize *offset);
+void CsrUint32DesBigEndian(CsrUint32 *v, CsrUint8 *buffer, CsrSize *offset);
+
+void CsrUint24Ser(CsrUint8 *ptr, CsrSize *len, CsrUint32 v);
+void CsrUint24Des(CsrUint32 *v, CsrUint8 *buffer, CsrSize *offset);
+
+
+CsrSize CsrWifiEventSizeof(void *msg);
+CsrUint8* CsrWifiEventSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+void* CsrWifiEventDes(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrWifiEventCsrUint8Sizeof(void *msg);
+CsrUint8* CsrWifiEventCsrUint8Ser(CsrUint8 *ptr, CsrSize *len, void *msg);
+void* CsrWifiEventCsrUint8Des(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrWifiEventCsrUint16Sizeof(void *msg);
+CsrUint8* CsrWifiEventCsrUint16Ser(CsrUint8 *ptr, CsrSize *len, void *msg);
+void* CsrWifiEventCsrUint16Des(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrWifiEventCsrUint32Sizeof(void *msg);
+CsrUint8* CsrWifiEventCsrUint32Ser(CsrUint8 *ptr, CsrSize *len, void *msg);
+void* CsrWifiEventCsrUint32Des(CsrUint8 *buffer, CsrSize length);
+
+CsrSize CsrWifiEventCsrUint16CsrUint8Sizeof(void *msg);
+CsrUint8* CsrWifiEventCsrUint16CsrUint8Ser(CsrUint8 *ptr, CsrSize *len, void *msg);
+void* CsrWifiEventCsrUint16CsrUint8Des(CsrUint8 *buffer, CsrSize length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_MSGCONV_H__ */
diff --git a/drivers/staging/csr/csr_wifi_nme_ap_converter_init.c b/drivers/staging/csr/csr_wifi_nme_ap_converter_init.c
new file mode 100644
index 0000000..83b3727
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_ap_converter_init.c
@@ -0,0 +1,91 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_msgconv.h"
+#include "csr_pmem.h"
+#include "csr_util.h"
+
+#ifdef CSR_WIFI_NME_ENABLE
+#ifdef CSR_WIFI_AP_ENABLE
+
+#ifdef CSR_LOG_ENABLE
+#include "csr_log.h"
+#endif
+
+#ifndef EXCLUDE_CSR_WIFI_NME_AP_MODULE
+#include "csr_wifi_nme_ap_serialize.h"
+#include "csr_wifi_nme_ap_prim.h"
+
+static CsrMsgConvMsgEntry csrwifinmeap_conv_lut[] = {
+    { CSR_WIFI_NME_AP_CONFIG_SET_REQ, CsrWifiNmeApConfigSetReqSizeof, CsrWifiNmeApConfigSetReqSer, CsrWifiNmeApConfigSetReqDes, CsrWifiNmeApConfigSetReqSerFree },
+    { CSR_WIFI_NME_AP_WPS_REGISTER_REQ, CsrWifiNmeApWpsRegisterReqSizeof, CsrWifiNmeApWpsRegisterReqSer, CsrWifiNmeApWpsRegisterReqDes, CsrWifiNmeApWpsRegisterReqSerFree },
+    { CSR_WIFI_NME_AP_START_REQ, CsrWifiNmeApStartReqSizeof, CsrWifiNmeApStartReqSer, CsrWifiNmeApStartReqDes, CsrWifiNmeApStartReqSerFree },
+    { CSR_WIFI_NME_AP_STOP_REQ, CsrWifiNmeApStopReqSizeof, CsrWifiNmeApStopReqSer, CsrWifiNmeApStopReqDes, CsrWifiNmeApStopReqSerFree },
+    { CSR_WIFI_NME_AP_WMM_PARAM_UPDATE_REQ, CsrWifiNmeApWmmParamUpdateReqSizeof, CsrWifiNmeApWmmParamUpdateReqSer, CsrWifiNmeApWmmParamUpdateReqDes, CsrWifiNmeApWmmParamUpdateReqSerFree },
+    { CSR_WIFI_NME_AP_STA_REMOVE_REQ, CsrWifiNmeApStaRemoveReqSizeof, CsrWifiNmeApStaRemoveReqSer, CsrWifiNmeApStaRemoveReqDes, CsrWifiNmeApStaRemoveReqSerFree },
+    { CSR_WIFI_NME_AP_CONFIG_SET_CFM, CsrWifiNmeApConfigSetCfmSizeof, CsrWifiNmeApConfigSetCfmSer, CsrWifiNmeApConfigSetCfmDes, CsrWifiNmeApConfigSetCfmSerFree },
+    { CSR_WIFI_NME_AP_WPS_REGISTER_CFM, CsrWifiNmeApWpsRegisterCfmSizeof, CsrWifiNmeApWpsRegisterCfmSer, CsrWifiNmeApWpsRegisterCfmDes, CsrWifiNmeApWpsRegisterCfmSerFree },
+    { CSR_WIFI_NME_AP_START_CFM, CsrWifiNmeApStartCfmSizeof, CsrWifiNmeApStartCfmSer, CsrWifiNmeApStartCfmDes, CsrWifiNmeApStartCfmSerFree },
+    { CSR_WIFI_NME_AP_STOP_CFM, CsrWifiNmeApStopCfmSizeof, CsrWifiNmeApStopCfmSer, CsrWifiNmeApStopCfmDes, CsrWifiNmeApStopCfmSerFree },
+    { CSR_WIFI_NME_AP_STOP_IND, CsrWifiNmeApStopIndSizeof, CsrWifiNmeApStopIndSer, CsrWifiNmeApStopIndDes, CsrWifiNmeApStopIndSerFree },
+    { CSR_WIFI_NME_AP_WMM_PARAM_UPDATE_CFM, CsrWifiNmeApWmmParamUpdateCfmSizeof, CsrWifiNmeApWmmParamUpdateCfmSer, CsrWifiNmeApWmmParamUpdateCfmDes, CsrWifiNmeApWmmParamUpdateCfmSerFree },
+    { CSR_WIFI_NME_AP_STATION_IND, CsrWifiNmeApStationIndSizeof, CsrWifiNmeApStationIndSer, CsrWifiNmeApStationIndDes, CsrWifiNmeApStationIndSerFree },
+
+    { 0, NULL, NULL, NULL, NULL },
+};
+
+CsrMsgConvMsgEntry* CsrWifiNmeApConverterLookup(CsrMsgConvMsgEntry *ce, CsrUint16 msgType)
+{
+    if (msgType & CSR_PRIM_UPSTREAM)
+    {
+        CsrUint16 idx = (msgType & ~CSR_PRIM_UPSTREAM) + CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_COUNT;
+        if (idx < (CSR_WIFI_NME_AP_PRIM_UPSTREAM_COUNT + CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_COUNT) &&
+            csrwifinmeap_conv_lut[idx].msgType == msgType)
+        {
+            return &csrwifinmeap_conv_lut[idx];
+        }
+    }
+    else
+    {
+        if (msgType < CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_COUNT &&
+            csrwifinmeap_conv_lut[msgType].msgType == msgType)
+        {
+            return &csrwifinmeap_conv_lut[msgType];
+        }
+    }
+    return NULL;
+}
+
+
+void CsrWifiNmeApConverterInit(void)
+{
+    CsrMsgConvInsert(CSR_WIFI_NME_AP_PRIM, csrwifinmeap_conv_lut);
+    CsrMsgConvCustomLookupRegister(CSR_WIFI_NME_AP_PRIM, CsrWifiNmeApConverterLookup);
+}
+
+
+#ifdef CSR_LOG_ENABLE
+static const CsrLogPrimitiveInformation csrwifinmeap_conv_info = {
+    CSR_WIFI_NME_AP_PRIM,
+    (CsrCharString *)"CSR_WIFI_NME_AP_PRIM",
+    csrwifinmeap_conv_lut
+};
+const CsrLogPrimitiveInformation* CsrWifiNmeApTechInfoGet(void)
+{
+    return &csrwifinmeap_conv_info;
+}
+
+
+#endif /* CSR_LOG_ENABLE */
+#endif /* EXCLUDE_CSR_WIFI_NME_AP_MODULE */
+#endif /* CSR_WIFI_NME_ENABLE */
+#endif /* CSR_WIFI_AP_ENABLE */
diff --git a/drivers/staging/csr/csr_wifi_nme_ap_converter_init.h b/drivers/staging/csr/csr_wifi_nme_ap_converter_init.h
new file mode 100644
index 0000000..4072c06
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_ap_converter_init.h
@@ -0,0 +1,49 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_NME_AP_CONVERTER_INIT_H__
+#define CSR_WIFI_NME_AP_CONVERTER_INIT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_NME_ENABLE
+#error CSR_WIFI_NME_ENABLE MUST be defined inorder to use csr_wifi_nme_ap_converter_init.h
+#endif
+#ifndef CSR_WIFI_AP_ENABLE
+#error CSR_WIFI_AP_ENABLE MUST be defined inorder to use csr_wifi_nme_ap_converter_init.h
+#endif
+
+#ifndef EXCLUDE_CSR_WIFI_NME_AP_MODULE
+
+#include "csr_msgconv.h"
+
+#ifdef CSR_LOG_ENABLE
+#include "csr_log.h"
+
+extern const CsrLogPrimitiveInformation* CsrWifiNmeApTechInfoGet(void);
+#endif /* CSR_LOG_ENABLE */
+
+extern void CsrWifiNmeApConverterInit(void);
+
+#else /* EXCLUDE_CSR_WIFI_NME_AP_MODULE */
+
+#define CsrWifiNmeApConverterInit()
+
+#endif /* EXCLUDE_CSR_WIFI_NME_AP_MODULE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_NME_AP_CONVERTER_INIT_H__ */
diff --git a/drivers/staging/csr/csr_wifi_nme_ap_free_downstream_contents.c b/drivers/staging/csr/csr_wifi_nme_ap_free_downstream_contents.c
new file mode 100644
index 0000000..8a95f3c
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_ap_free_downstream_contents.c
@@ -0,0 +1,85 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_wifi_nme_ap_prim.h"
+#include "csr_wifi_nme_ap_lib.h"
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrWifiNmeApFreeDownstreamMessageContents
+ *
+ *  DESCRIPTION
+ *
+ *
+ *  PARAMETERS
+ *      eventClass: only the value CSR_WIFI_NME_AP_PRIM will be handled
+ *      message:    the message to free
+ *----------------------------------------------------------------------------*/
+void CsrWifiNmeApFreeDownstreamMessageContents(CsrUint16 eventClass, void *message)
+{
+    if (eventClass != CSR_WIFI_NME_AP_PRIM)
+    {
+        return;
+    }
+    if (NULL == message)
+    {
+        return;
+    }
+
+    switch (*((CsrWifiNmeApPrim *) message))
+    {
+        case CSR_WIFI_NME_AP_CONFIG_SET_REQ:
+        {
+            CsrWifiNmeApConfigSetReq *p = (CsrWifiNmeApConfigSetReq *)message;
+            CsrPmemFree(p->apMacConfig.macAddressList);
+            p->apMacConfig.macAddressList = NULL;
+            break;
+        }
+        case CSR_WIFI_NME_AP_START_REQ:
+        {
+            CsrWifiNmeApStartReq *p = (CsrWifiNmeApStartReq *)message;
+            switch (p->apCredentials.authType)
+            {
+                case CSR_WIFI_SME_AP_AUTH_TYPE_PERSONAL:
+                    switch (p->apCredentials.nmeAuthType.authTypePersonal.pskOrPassphrase)
+                    {
+                        case CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PASSPHRASE:
+                            CsrPmemFree(p->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.passphrase.passphrase);
+                            p->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.passphrase.passphrase = NULL;
+                            break;
+                        default:
+                            break;
+                    }
+                    break;
+                default:
+                    break;
+            }
+            {
+                CsrUint16 i3;
+                for (i3 = 0; i3 < p->p2pGoParam.operatingChanList.channelEntryListCount; i3++)
+                {
+                    CsrPmemFree(p->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannel);
+                    p->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannel = NULL;
+                }
+            }
+            CsrPmemFree(p->p2pGoParam.operatingChanList.channelEntryList);
+            p->p2pGoParam.operatingChanList.channelEntryList = NULL;
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_nme_ap_free_upstream_contents.c b/drivers/staging/csr/csr_wifi_nme_ap_free_upstream_contents.c
new file mode 100644
index 0000000..7740dc3
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_ap_free_upstream_contents.c
@@ -0,0 +1,40 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_wifi_nme_ap_prim.h"
+#include "csr_wifi_nme_ap_lib.h"
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrWifiNmeApFreeUpstreamMessageContents
+ *
+ *  DESCRIPTION
+ *
+ *
+ *  PARAMETERS
+ *      eventClass: only the value CSR_WIFI_NME_AP_PRIM will be handled
+ *      message:    the message to free
+ *----------------------------------------------------------------------------*/
+void CsrWifiNmeApFreeUpstreamMessageContents(CsrUint16 eventClass, void *message)
+{
+    if (eventClass != CSR_WIFI_NME_AP_PRIM)
+    {
+        return;
+    }
+    if (NULL == message)
+    {
+        return;
+    }
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_nme_ap_lib.h b/drivers/staging/csr/csr_wifi_nme_ap_lib.h
new file mode 100644
index 0000000..aa632d5
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_ap_lib.h
@@ -0,0 +1,525 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_NME_AP_LIB_H__
+#define CSR_WIFI_NME_AP_LIB_H__
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_sched.h"
+#include "csr_util.h"
+#include "csr_msg_transport.h"
+
+#include "csr_wifi_lib.h"
+
+#include "csr_wifi_nme_ap_prim.h"
+#include "csr_wifi_nme_task.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_NME_ENABLE
+#error CSR_WIFI_NME_ENABLE MUST be defined inorder to use csr_wifi_nme_ap_lib.h
+#endif
+#ifndef CSR_WIFI_AP_ENABLE
+#error CSR_WIFI_AP_ENABLE MUST be defined inorder to use csr_wifi_nme_ap_lib.h
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiNmeApFreeUpstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_NME_AP upstream message. Does not
+ *      free the message itself, and can only be used for upstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_NME_AP upstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiNmeApFreeUpstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiNmeApFreeDownstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_NME_AP downstream message. Does not
+ *      free the message itself, and can only be used for downstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_NME_AP downstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiNmeApFreeDownstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ * Enum to string functions
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiNmeApPersCredentialTypeToString(CsrWifiNmeApPersCredentialType value);
+
+
+/*----------------------------------------------------------------------------*
+ * CsrPrim Type toString function.
+ * Converts a message type to the String name of the Message
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiNmeApPrimTypeToString(CsrPrim msgType);
+
+/*----------------------------------------------------------------------------*
+ * Lookup arrays for PrimType name Strings
+ *----------------------------------------------------------------------------*/
+extern const CsrCharString *CsrWifiNmeApUpstreamPrimNames[CSR_WIFI_NME_AP_PRIM_UPSTREAM_COUNT];
+extern const CsrCharString *CsrWifiNmeApDownstreamPrimNames[CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_COUNT];
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApConfigSetReqSend
+
+  DESCRIPTION
+    This primitive passes AP configuration info for NME. This can be sent at
+    any time but will be acted upon when the AP is started again. This
+    information is common to both P2P GO and AP
+
+  PARAMETERS
+    queue       - Message Source Task Queue (Cfm's will be sent to this Queue)
+    apConfig    - AP configuration for the NME.
+    apMacConfig - MAC configuration to be acted on when
+                  CSR_WIFI_NME_AP_START.request is sent.
+
+*******************************************************************************/
+#define CsrWifiNmeApConfigSetReqCreate(msg__, dst__, src__, apConfig__, apMacConfig__) \
+    msg__ = (CsrWifiNmeApConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiNmeApConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_CONFIG_SET_REQ, dst__, src__); \
+    msg__->apConfig = (apConfig__); \
+    msg__->apMacConfig = (apMacConfig__);
+
+#define CsrWifiNmeApConfigSetReqSendTo(dst__, src__, apConfig__, apMacConfig__) \
+    { \
+        CsrWifiNmeApConfigSetReq *msg__; \
+        CsrWifiNmeApConfigSetReqCreate(msg__, dst__, src__, apConfig__, apMacConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApConfigSetReqSend(src__, apConfig__, apMacConfig__) \
+    CsrWifiNmeApConfigSetReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, apConfig__, apMacConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApConfigSetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Status of the request.
+
+*******************************************************************************/
+#define CsrWifiNmeApConfigSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiNmeApConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeApConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_CONFIG_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeApConfigSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiNmeApConfigSetCfm *msg__; \
+        CsrWifiNmeApConfigSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApConfigSetCfmSend(dst__, status__) \
+    CsrWifiNmeApConfigSetCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStaRemoveReqSend
+
+  DESCRIPTION
+    This primitive disconnects a connected station. If keepBlocking is set to
+    TRUE, the station with the specified MAC address is not allowed to
+    connect. If the requested station is not already connected,it may be
+    blocked based on keepBlocking parameter.
+
+  PARAMETERS
+    queue         - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    staMacAddress - Mac Address of the station to be disconnected or blocked
+    keepBlocking  - If TRUE, the station is blocked. If FALSE and the station is
+                    connected, disconnect the station. If FALSE and the station
+                    is not connected, no action is taken.
+
+*******************************************************************************/
+#define CsrWifiNmeApStaRemoveReqCreate(msg__, dst__, src__, interfaceTag__, staMacAddress__, keepBlocking__) \
+    msg__ = (CsrWifiNmeApStaRemoveReq *) CsrPmemAlloc(sizeof(CsrWifiNmeApStaRemoveReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_STA_REMOVE_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->staMacAddress = (staMacAddress__); \
+    msg__->keepBlocking = (keepBlocking__);
+
+#define CsrWifiNmeApStaRemoveReqSendTo(dst__, src__, interfaceTag__, staMacAddress__, keepBlocking__) \
+    { \
+        CsrWifiNmeApStaRemoveReq *msg__; \
+        CsrWifiNmeApStaRemoveReqCreate(msg__, dst__, src__, interfaceTag__, staMacAddress__, keepBlocking__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApStaRemoveReqSend(src__, interfaceTag__, staMacAddress__, keepBlocking__) \
+    CsrWifiNmeApStaRemoveReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, interfaceTag__, staMacAddress__, keepBlocking__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStartReqSend
+
+  DESCRIPTION
+    This primitive requests NME to started the AP operation.
+
+  PARAMETERS
+    queue          - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag   - Interface identifier; unique identifier of an interface
+    apType         - AP Type specifies the Legacy AP or P2P GO operation
+    cloakSsid      - Indicates whether the SSID should be cloaked (hidden and
+                     not broadcast in beacon) or not
+    ssid           - Service Set Identifier
+    ifIndex        - Radio interface
+    channel        - Channel number of the channel to use
+    apCredentials  - Security credential configuration.
+    maxConnections - Maximum number of stations/P2P clients allowed
+    p2pGoParam     - P2P specific GO parameters.
+    wpsEnabled     - Indicates whether WPS should be enabled or not
+
+*******************************************************************************/
+#define CsrWifiNmeApStartReqCreate(msg__, dst__, src__, interfaceTag__, apType__, cloakSsid__, ssid__, ifIndex__, channel__, apCredentials__, maxConnections__, p2pGoParam__, wpsEnabled__) \
+    msg__ = (CsrWifiNmeApStartReq *) CsrPmemAlloc(sizeof(CsrWifiNmeApStartReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_START_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->apType = (apType__); \
+    msg__->cloakSsid = (cloakSsid__); \
+    msg__->ssid = (ssid__); \
+    msg__->ifIndex = (ifIndex__); \
+    msg__->channel = (channel__); \
+    msg__->apCredentials = (apCredentials__); \
+    msg__->maxConnections = (maxConnections__); \
+    msg__->p2pGoParam = (p2pGoParam__); \
+    msg__->wpsEnabled = (wpsEnabled__);
+
+#define CsrWifiNmeApStartReqSendTo(dst__, src__, interfaceTag__, apType__, cloakSsid__, ssid__, ifIndex__, channel__, apCredentials__, maxConnections__, p2pGoParam__, wpsEnabled__) \
+    { \
+        CsrWifiNmeApStartReq *msg__; \
+        CsrWifiNmeApStartReqCreate(msg__, dst__, src__, interfaceTag__, apType__, cloakSsid__, ssid__, ifIndex__, channel__, apCredentials__, maxConnections__, p2pGoParam__, wpsEnabled__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApStartReqSend(src__, interfaceTag__, apType__, cloakSsid__, ssid__, ifIndex__, channel__, apCredentials__, maxConnections__, p2pGoParam__, wpsEnabled__) \
+    CsrWifiNmeApStartReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, interfaceTag__, apType__, cloakSsid__, ssid__, ifIndex__, channel__, apCredentials__, maxConnections__, p2pGoParam__, wpsEnabled__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStartCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of CSR_WIFI_NME_AP_START.request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface identifier; unique identifier of an interface
+    status       - Status of the request.
+    ssid         - Service Set Identifier
+
+*******************************************************************************/
+#define CsrWifiNmeApStartCfmCreate(msg__, dst__, src__, interfaceTag__, status__, ssid__) \
+    msg__ = (CsrWifiNmeApStartCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeApStartCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_START_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->ssid = (ssid__);
+
+#define CsrWifiNmeApStartCfmSendTo(dst__, src__, interfaceTag__, status__, ssid__) \
+    { \
+        CsrWifiNmeApStartCfm *msg__; \
+        CsrWifiNmeApStartCfmCreate(msg__, dst__, src__, interfaceTag__, status__, ssid__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApStartCfmSend(dst__, interfaceTag__, status__, ssid__) \
+    CsrWifiNmeApStartCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, status__, ssid__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStationIndSend
+
+  DESCRIPTION
+    This primitive indicates that a station has joined or a previously joined
+    station has left the BSS/group
+
+  PARAMETERS
+    queue             - Destination Task Queue
+    interfaceTag      - Interface Identifier; unique identifier of an interface
+    mediaStatus       - Indicates whether the station is connected or
+                        disconnected
+    peerMacAddress    - MAC address of the station
+    peerDeviceAddress - P2P Device Address
+
+*******************************************************************************/
+#define CsrWifiNmeApStationIndCreate(msg__, dst__, src__, interfaceTag__, mediaStatus__, peerMacAddress__, peerDeviceAddress__) \
+    msg__ = (CsrWifiNmeApStationInd *) CsrPmemAlloc(sizeof(CsrWifiNmeApStationInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_STATION_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->mediaStatus = (mediaStatus__); \
+    msg__->peerMacAddress = (peerMacAddress__); \
+    msg__->peerDeviceAddress = (peerDeviceAddress__);
+
+#define CsrWifiNmeApStationIndSendTo(dst__, src__, interfaceTag__, mediaStatus__, peerMacAddress__, peerDeviceAddress__) \
+    { \
+        CsrWifiNmeApStationInd *msg__; \
+        CsrWifiNmeApStationIndCreate(msg__, dst__, src__, interfaceTag__, mediaStatus__, peerMacAddress__, peerDeviceAddress__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApStationIndSend(dst__, interfaceTag__, mediaStatus__, peerMacAddress__, peerDeviceAddress__) \
+    CsrWifiNmeApStationIndSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, mediaStatus__, peerMacAddress__, peerDeviceAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStopReqSend
+
+  DESCRIPTION
+    This primitive requests NME to stop the AP operation.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiNmeApStopReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiNmeApStopReq *) CsrPmemAlloc(sizeof(CsrWifiNmeApStopReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_STOP_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiNmeApStopReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiNmeApStopReq *msg__; \
+        CsrWifiNmeApStopReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApStopReqSend(src__, interfaceTag__) \
+    CsrWifiNmeApStopReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStopIndSend
+
+  DESCRIPTION
+    Indicates that AP operation had stopped because of some unrecoverable
+    error after AP operation was started successfully. NME sends this signal
+    after failing to restart the AP operation internally following an error
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    apType       - Reports AP Type (P2PGO or AP)
+    status       - Error Status
+
+*******************************************************************************/
+#define CsrWifiNmeApStopIndCreate(msg__, dst__, src__, interfaceTag__, apType__, status__) \
+    msg__ = (CsrWifiNmeApStopInd *) CsrPmemAlloc(sizeof(CsrWifiNmeApStopInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_STOP_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->apType = (apType__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeApStopIndSendTo(dst__, src__, interfaceTag__, apType__, status__) \
+    { \
+        CsrWifiNmeApStopInd *msg__; \
+        CsrWifiNmeApStopIndCreate(msg__, dst__, src__, interfaceTag__, apType__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApStopIndSend(dst__, interfaceTag__, apType__, status__) \
+    CsrWifiNmeApStopIndSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, apType__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStopCfmSend
+
+  DESCRIPTION
+    This primitive confirms that the AP operation is stopped. NME shall send
+    this primitive in response to the request even if AP operation has
+    already been stopped
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface identifier; unique identifier of an interface
+    status       - Status of the request.
+
+*******************************************************************************/
+#define CsrWifiNmeApStopCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiNmeApStopCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeApStopCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_STOP_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeApStopCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiNmeApStopCfm *msg__; \
+        CsrWifiNmeApStopCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApStopCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiNmeApStopCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApWmmParamUpdateReqSend
+
+  DESCRIPTION
+    Application uses this primitive to update the WMM parameters
+
+  PARAMETERS
+    queue         - Message Source Task Queue (Cfm's will be sent to this Queue)
+    wmmApParams   - WMM Access point parameters per access category. The array
+                    index corresponds to the ACI
+    wmmApBcParams - WMM station parameters per access category to be advertised
+                    in the beacons and probe response The array index
+                    corresponds to the ACI
+
+*******************************************************************************/
+#define CsrWifiNmeApWmmParamUpdateReqCreate(msg__, dst__, src__, wmmApParams__, wmmApBcParams__) \
+    msg__ = (CsrWifiNmeApWmmParamUpdateReq *) CsrPmemAlloc(sizeof(CsrWifiNmeApWmmParamUpdateReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_WMM_PARAM_UPDATE_REQ, dst__, src__); \
+    CsrMemCpy(msg__->wmmApParams, (wmmApParams__), sizeof(CsrWifiSmeWmmAcParams) * 4); \
+    CsrMemCpy(msg__->wmmApBcParams, (wmmApBcParams__), sizeof(CsrWifiSmeWmmAcParams) * 4);
+
+#define CsrWifiNmeApWmmParamUpdateReqSendTo(dst__, src__, wmmApParams__, wmmApBcParams__) \
+    { \
+        CsrWifiNmeApWmmParamUpdateReq *msg__; \
+        CsrWifiNmeApWmmParamUpdateReqCreate(msg__, dst__, src__, wmmApParams__, wmmApBcParams__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApWmmParamUpdateReqSend(src__, wmmApParams__, wmmApBcParams__) \
+    CsrWifiNmeApWmmParamUpdateReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, wmmApParams__, wmmApBcParams__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApWmmParamUpdateCfmSend
+
+  DESCRIPTION
+    A confirm for for the WMM parameters update
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Status of the request.
+
+*******************************************************************************/
+#define CsrWifiNmeApWmmParamUpdateCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiNmeApWmmParamUpdateCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeApWmmParamUpdateCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_WMM_PARAM_UPDATE_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeApWmmParamUpdateCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiNmeApWmmParamUpdateCfm *msg__; \
+        CsrWifiNmeApWmmParamUpdateCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApWmmParamUpdateCfmSend(dst__, status__) \
+    CsrWifiNmeApWmmParamUpdateCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApWpsRegisterReqSend
+
+  DESCRIPTION
+    This primitive allows the NME to accept the WPS registration from an
+    enrollee. Such registration procedure can be cancelled by sending
+    CSR_WIFI_NME_WPS_CANCEL.request.
+
+  PARAMETERS
+    queue                    - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag             - Interface Identifier; unique identifier of an
+                               interface
+    selectedDevicePasswordId - Selected password type
+    selectedConfigMethod     - Selected WPS configuration method type
+    pin                      - PIN value.
+                               Relevant if selected device password ID is PIN.4
+                               digit pin is passed by sending the pin digits in
+                               pin[0]..pin[3] and rest of the contents filled
+                               with '-'.
+
+*******************************************************************************/
+#define CsrWifiNmeApWpsRegisterReqCreate(msg__, dst__, src__, interfaceTag__, selectedDevicePasswordId__, selectedConfigMethod__, pin__) \
+    msg__ = (CsrWifiNmeApWpsRegisterReq *) CsrPmemAlloc(sizeof(CsrWifiNmeApWpsRegisterReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_WPS_REGISTER_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->selectedDevicePasswordId = (selectedDevicePasswordId__); \
+    msg__->selectedConfigMethod = (selectedConfigMethod__); \
+    CsrMemCpy(msg__->pin, (pin__), sizeof(CsrUint8) * 8);
+
+#define CsrWifiNmeApWpsRegisterReqSendTo(dst__, src__, interfaceTag__, selectedDevicePasswordId__, selectedConfigMethod__, pin__) \
+    { \
+        CsrWifiNmeApWpsRegisterReq *msg__; \
+        CsrWifiNmeApWpsRegisterReqCreate(msg__, dst__, src__, interfaceTag__, selectedDevicePasswordId__, selectedConfigMethod__, pin__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApWpsRegisterReqSend(src__, interfaceTag__, selectedDevicePasswordId__, selectedConfigMethod__, pin__) \
+    CsrWifiNmeApWpsRegisterReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, interfaceTag__, selectedDevicePasswordId__, selectedConfigMethod__, pin__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApWpsRegisterCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of WPS procedure.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface identifier; unique identifier of an interface
+    status       - Status of the request.
+
+*******************************************************************************/
+#define CsrWifiNmeApWpsRegisterCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiNmeApWpsRegisterCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeApWpsRegisterCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_AP_PRIM, CSR_WIFI_NME_AP_WPS_REGISTER_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeApWpsRegisterCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiNmeApWpsRegisterCfm *msg__; \
+        CsrWifiNmeApWpsRegisterCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeApWpsRegisterCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiNmeApWpsRegisterCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, status__)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_NME_AP_LIB_H__ */
diff --git a/drivers/staging/csr/csr_wifi_nme_ap_prim.h b/drivers/staging/csr/csr_wifi_nme_ap_prim.h
new file mode 100644
index 0000000..561c2fd
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_ap_prim.h
@@ -0,0 +1,503 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_NME_AP_PRIM_H__
+#define CSR_WIFI_NME_AP_PRIM_H__
+
+#include "csr_types.h"
+#include "csr_prim_defs.h"
+#include "csr_sched.h"
+#include "csr_wifi_common.h"
+#include "csr_result.h"
+#include "csr_wifi_fsm_event.h"
+#include "csr_wifi_sme_ap_prim.h"
+#include "csr_wifi_nme_prim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_NME_ENABLE
+#error CSR_WIFI_NME_ENABLE MUST be defined inorder to use csr_wifi_nme_ap_prim.h
+#endif
+#ifndef CSR_WIFI_AP_ENABLE
+#error CSR_WIFI_AP_ENABLE MUST be defined inorder to use csr_wifi_nme_ap_prim.h
+#endif
+
+#define CSR_WIFI_NME_AP_PRIM                                            (0x0426)
+
+typedef CsrPrim CsrWifiNmeApPrim;
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApPersCredentialType
+
+  DESCRIPTION
+    NME Credential Types
+
+ VALUES
+    CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PSK
+                   - Use PSK as credential.
+    CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PASSPHRASE
+                   - Use the specified passphrase as credential
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiNmeApPersCredentialType;
+#define CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PSK          ((CsrWifiNmeApPersCredentialType) 0x00)
+#define CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PASSPHRASE   ((CsrWifiNmeApPersCredentialType) 0x01)
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApConfig
+
+  DESCRIPTION
+    Structure holding AP config data.
+
+  MEMBERS
+    apGroupkeyTimeout - Access point group key timeout.
+    apStrictGtkRekey  - Access point strict GTK rekey flag. If set TRUE, the AP
+                        shall rekey GTK every time a connected STA leaves BSS.
+    apGmkTimeout      - Access point GMK timeout
+    apResponseTimeout - Response timeout
+    apRetransLimit    - Max allowed retransmissions
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint16 apGroupkeyTimeout;
+    CsrBool   apStrictGtkRekey;
+    CsrUint16 apGmkTimeout;
+    CsrUint16 apResponseTimeout;
+    CsrUint8  apRetransLimit;
+} CsrWifiNmeApConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApAuthPers
+
+  DESCRIPTION
+
+  MEMBERS
+    authSupport                     - Credential type value (as defined in the
+                                      enumeration type).
+    rsnCapabilities                 - RSN capabilities mask
+    wapiCapabilities                - WAPI capabilities mask
+    pskOrPassphrase                 - Credential type value (as defined in the
+                                      enumeration type).
+    authPers_credentials            - Union containing credentials which depends
+                                      on credentialType parameter.
+    authPers_credentialspsk         -
+    authPers_credentialspassphrase  -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeApAuthSupportMask      authSupport;
+    CsrWifiSmeApRsnCapabilitiesMask  rsnCapabilities;
+    CsrWifiSmeApWapiCapabilitiesMask wapiCapabilities;
+    CsrWifiNmeApPersCredentialType   pskOrPassphrase;
+    union {
+        CsrWifiNmePsk        psk;
+        CsrWifiNmePassphrase passphrase;
+    } authPers_credentials;
+} CsrWifiNmeApAuthPers;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApCredentials
+
+  DESCRIPTION
+    Structure containing the Credentials data.
+
+  MEMBERS
+    authType                     - Authentication type
+    nmeAuthType                  - Authentication parameters
+    nmeAuthTypeopenSystemEmpty   -
+    nmeAuthTypeauthwep           -
+    nmeAuthTypeauthTypePersonal  -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeApAuthType authType;
+    union {
+        CsrWifiSmeEmpty      openSystemEmpty;
+        CsrWifiSmeWepAuth    authwep;
+        CsrWifiNmeApAuthPers authTypePersonal;
+    } nmeAuthType;
+} CsrWifiNmeApCredentials;
+
+
+/* Downstream */
+#define CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_LOWEST            (0x0000)
+
+#define CSR_WIFI_NME_AP_CONFIG_SET_REQ                    ((CsrWifiNmeApPrim) (0x0000 + CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_AP_WPS_REGISTER_REQ                  ((CsrWifiNmeApPrim) (0x0001 + CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_AP_START_REQ                         ((CsrWifiNmeApPrim) (0x0002 + CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_AP_STOP_REQ                          ((CsrWifiNmeApPrim) (0x0003 + CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_AP_WMM_PARAM_UPDATE_REQ              ((CsrWifiNmeApPrim) (0x0004 + CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_AP_STA_REMOVE_REQ                    ((CsrWifiNmeApPrim) (0x0005 + CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_LOWEST))
+
+
+#define CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_HIGHEST           (0x0005 + CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_LOWEST)
+
+/* Upstream */
+#define CSR_WIFI_NME_AP_PRIM_UPSTREAM_LOWEST              (0x0000 + CSR_PRIM_UPSTREAM)
+
+#define CSR_WIFI_NME_AP_CONFIG_SET_CFM                    ((CsrWifiNmeApPrim)(0x0000 + CSR_WIFI_NME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_AP_WPS_REGISTER_CFM                  ((CsrWifiNmeApPrim)(0x0001 + CSR_WIFI_NME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_AP_START_CFM                         ((CsrWifiNmeApPrim)(0x0002 + CSR_WIFI_NME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_AP_STOP_CFM                          ((CsrWifiNmeApPrim)(0x0003 + CSR_WIFI_NME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_AP_STOP_IND                          ((CsrWifiNmeApPrim)(0x0004 + CSR_WIFI_NME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_AP_WMM_PARAM_UPDATE_CFM              ((CsrWifiNmeApPrim)(0x0005 + CSR_WIFI_NME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_AP_STATION_IND                       ((CsrWifiNmeApPrim)(0x0006 + CSR_WIFI_NME_AP_PRIM_UPSTREAM_LOWEST))
+
+#define CSR_WIFI_NME_AP_PRIM_UPSTREAM_HIGHEST             (0x0006 + CSR_WIFI_NME_AP_PRIM_UPSTREAM_LOWEST)
+
+#define CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_COUNT             (CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_HIGHEST + 1 - CSR_WIFI_NME_AP_PRIM_DOWNSTREAM_LOWEST)
+#define CSR_WIFI_NME_AP_PRIM_UPSTREAM_COUNT               (CSR_WIFI_NME_AP_PRIM_UPSTREAM_HIGHEST   + 1 - CSR_WIFI_NME_AP_PRIM_UPSTREAM_LOWEST)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApConfigSetReq
+
+  DESCRIPTION
+    This primitive passes AP configuration info for NME. This can be sent at
+    any time but will be acted upon when the AP is started again. This
+    information is common to both P2P GO and AP
+
+  MEMBERS
+    common      - Common header for use with the CsrWifiFsm Module
+    apConfig    - AP configuration for the NME.
+    apMacConfig - MAC configuration to be acted on when
+                  CSR_WIFI_NME_AP_START.request is sent.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrWifiNmeApConfig    apConfig;
+    CsrWifiSmeApMacConfig apMacConfig;
+} CsrWifiNmeApConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApWpsRegisterReq
+
+  DESCRIPTION
+    This primitive allows the NME to accept the WPS registration from an
+    enrollee. Such registration procedure can be cancelled by sending
+    CSR_WIFI_NME_WPS_CANCEL.request.
+
+  MEMBERS
+    common                   - Common header for use with the CsrWifiFsm Module
+    interfaceTag             - Interface Identifier; unique identifier of an
+                               interface
+    selectedDevicePasswordId - Selected password type
+    selectedConfigMethod     - Selected WPS configuration method type
+    pin                      - PIN value.
+                               Relevant if selected device password ID is PIN.4
+                               digit pin is passed by sending the pin digits in
+                               pin[0]..pin[3] and rest of the contents filled
+                               with '-'.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent         common;
+    CsrUint16               interfaceTag;
+    CsrWifiSmeWpsDpid       selectedDevicePasswordId;
+    CsrWifiSmeWpsConfigType selectedConfigMethod;
+    CsrUint8                pin[8];
+} CsrWifiNmeApWpsRegisterReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStartReq
+
+  DESCRIPTION
+    This primitive requests NME to started the AP operation.
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   - Interface identifier; unique identifier of an interface
+    apType         - AP Type specifies the Legacy AP or P2P GO operation
+    cloakSsid      - Indicates whether the SSID should be cloaked (hidden and
+                     not broadcast in beacon) or not
+    ssid           - Service Set Identifier
+    ifIndex        - Radio interface
+    channel        - Channel number of the channel to use
+    apCredentials  - Security credential configuration.
+    maxConnections - Maximum number of stations/P2P clients allowed
+    p2pGoParam     - P2P specific GO parameters.
+    wpsEnabled     - Indicates whether WPS should be enabled or not
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent         common;
+    CsrUint16               interfaceTag;
+    CsrWifiSmeApType        apType;
+    CsrBool                 cloakSsid;
+    CsrWifiSsid             ssid;
+    CsrWifiSmeRadioIF       ifIndex;
+    CsrUint8                channel;
+    CsrWifiNmeApCredentials apCredentials;
+    CsrUint8                maxConnections;
+    CsrWifiSmeApP2pGoConfig p2pGoParam;
+    CsrBool                 wpsEnabled;
+} CsrWifiNmeApStartReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStopReq
+
+  DESCRIPTION
+    This primitive requests NME to stop the AP operation.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiNmeApStopReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApWmmParamUpdateReq
+
+  DESCRIPTION
+    Application uses this primitive to update the WMM parameters
+
+  MEMBERS
+    common        - Common header for use with the CsrWifiFsm Module
+    wmmApParams   - WMM Access point parameters per access category. The array
+                    index corresponds to the ACI
+    wmmApBcParams - WMM station parameters per access category to be advertised
+                    in the beacons and probe response The array index
+                    corresponds to the ACI
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrWifiSmeWmmAcParams wmmApParams[4];
+    CsrWifiSmeWmmAcParams wmmApBcParams[4];
+} CsrWifiNmeApWmmParamUpdateReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStaRemoveReq
+
+  DESCRIPTION
+    This primitive disconnects a connected station. If keepBlocking is set to
+    TRUE, the station with the specified MAC address is not allowed to
+    connect. If the requested station is not already connected,it may be
+    blocked based on keepBlocking parameter.
+
+  MEMBERS
+    common        - Common header for use with the CsrWifiFsm Module
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    staMacAddress - Mac Address of the station to be disconnected or blocked
+    keepBlocking  - If TRUE, the station is blocked. If FALSE and the station is
+                    connected, disconnect the station. If FALSE and the station
+                    is not connected, no action is taken.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrUint16         interfaceTag;
+    CsrWifiMacAddress staMacAddress;
+    CsrBool           keepBlocking;
+} CsrWifiNmeApStaRemoveReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApConfigSetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Status of the request.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiNmeApConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApWpsRegisterCfm
+
+  DESCRIPTION
+    This primitive reports the result of WPS procedure.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface identifier; unique identifier of an interface
+    status       - Status of the request.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiNmeApWpsRegisterCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStartCfm
+
+  DESCRIPTION
+    This primitive reports the result of CSR_WIFI_NME_AP_START.request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface identifier; unique identifier of an interface
+    status       - Status of the request.
+    ssid         - Service Set Identifier
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+    CsrWifiSsid     ssid;
+} CsrWifiNmeApStartCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStopCfm
+
+  DESCRIPTION
+    This primitive confirms that the AP operation is stopped. NME shall send
+    this primitive in response to the request even if AP operation has
+    already been stopped
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface identifier; unique identifier of an interface
+    status       - Status of the request.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiNmeApStopCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStopInd
+
+  DESCRIPTION
+    Indicates that AP operation had stopped because of some unrecoverable
+    error after AP operation was started successfully. NME sends this signal
+    after failing to restart the AP operation internally following an error
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    apType       - Reports AP Type (P2PGO or AP)
+    status       - Error Status
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent  common;
+    CsrUint16        interfaceTag;
+    CsrWifiSmeApType apType;
+    CsrResult        status;
+} CsrWifiNmeApStopInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApWmmParamUpdateCfm
+
+  DESCRIPTION
+    A confirm for for the WMM parameters update
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Status of the request.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiNmeApWmmParamUpdateCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeApStationInd
+
+  DESCRIPTION
+    This primitive indicates that a station has joined or a previously joined
+    station has left the BSS/group
+
+  MEMBERS
+    common            - Common header for use with the CsrWifiFsm Module
+    interfaceTag      - Interface Identifier; unique identifier of an interface
+    mediaStatus       - Indicates whether the station is connected or
+                        disconnected
+    peerMacAddress    - MAC address of the station
+    peerDeviceAddress - P2P Device Address
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrUint16             interfaceTag;
+    CsrWifiSmeMediaStatus mediaStatus;
+    CsrWifiMacAddress     peerMacAddress;
+    CsrWifiMacAddress     peerDeviceAddress;
+} CsrWifiNmeApStationInd;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_NME_AP_PRIM_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_nme_ap_sef.c b/drivers/staging/csr/csr_wifi_nme_ap_sef.c
new file mode 100644
index 0000000..e048848
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_ap_sef.c
@@ -0,0 +1,30 @@
+/*****************************************************************************
+
+  FILE: csr_wifi_nme_sef.c
+
+  (c) Cambridge Silicon Radio Limited 2010
+
+  Refer to LICENSE.txt included with this source for details
+  on the license terms.
+
+ *****************************************************************************/
+#include "csr_wifi_nme_ap_sef.h"
+#include "unifi_priv.h"
+
+void CsrWifiNmeApUpstreamStateHandlers(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    switch(msg->type) {
+        case CSR_WIFI_NME_AP_START_CFM:
+            CsrWifiNmeApStartCfmHandler(drvpriv, msg);
+            break;
+        case CSR_WIFI_NME_AP_STOP_CFM:
+            CsrWifiNmeApStopCfmHandler(drvpriv, msg);
+            break;
+        case CSR_WIFI_NME_AP_CONFIG_SET_CFM:
+            CsrWifiNmeApConfigSetCfmHandler(drvpriv,msg);
+            break;
+        default:
+	    unifi_error(drvpriv, "CsrWifiNmeApUpstreamStateHandlers: unhandled NME_AP message type 0x%.4X\n",msg->type);
+            break;
+    }
+}
diff --git a/drivers/staging/csr/csr_wifi_nme_ap_sef.h b/drivers/staging/csr/csr_wifi_nme_ap_sef.h
new file mode 100644
index 0000000..3f35363
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_ap_sef.h
@@ -0,0 +1,31 @@
+/*****************************************************************************
+    FILE: csr_wifi_nme_sef.h
+    (c) Cambridge Silicon Radio Limited 2010
+
+    Refer to LICENSE.txt included with this source for details
+    on the license terms.
+
+*****************************************************************************/
+#ifndef CSR_WIFI_ROUTER_SEF_CSR_WIFI_NME_H__
+#define CSR_WIFI_ROUTER_SEF_CSR_WIFI_NME_H__
+
+#include "csr_wifi_nme_prim.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void CsrWifiNmeApUpstreamStateHandlers(void* drvpriv, CsrWifiFsmEvent* msg);
+
+
+extern void CsrWifiNmeApConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiNmeApStartCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiNmeApStopCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_ROUTER_SEF_CSR_WIFI_NME_H__ */
diff --git a/drivers/staging/csr/csr_wifi_nme_ap_serialize.c b/drivers/staging/csr/csr_wifi_nme_ap_serialize.c
new file mode 100644
index 0000000..947f86a
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_ap_serialize.c
@@ -0,0 +1,910 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_msgconv.h"
+#include "csr_unicode.h"
+
+#ifdef CSR_WIFI_NME_ENABLE
+#ifdef CSR_WIFI_AP_ENABLE
+
+#include "csr_wifi_nme_ap_prim.h"
+#include "csr_wifi_nme_ap_serialize.h"
+
+void CsrWifiNmeApPfree(void *ptr)
+{
+    CsrPmemFree(ptr);
+}
+
+
+CsrSize CsrWifiNmeApConfigSetReqSizeof(void *msg)
+{
+    CsrWifiNmeApConfigSetReq *primitive = (CsrWifiNmeApConfigSetReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 104) */
+    bufferSize += 2;  /* CsrUint16 primitive->apConfig.apGroupkeyTimeout */
+    bufferSize += 1;  /* CsrBool primitive->apConfig.apStrictGtkRekey */
+    bufferSize += 2;  /* CsrUint16 primitive->apConfig.apGmkTimeout */
+    bufferSize += 2;  /* CsrUint16 primitive->apConfig.apResponseTimeout */
+    bufferSize += 1;  /* CsrUint8 primitive->apConfig.apRetransLimit */
+    bufferSize += 1;  /* CsrWifiSmeApPhySupportMask primitive->apMacConfig.phySupportedBitmap */
+    bufferSize += 2;  /* CsrUint16 primitive->apMacConfig.beaconInterval */
+    bufferSize += 1;  /* CsrUint8 primitive->apMacConfig.dtimPeriod */
+    bufferSize += 2;  /* CsrUint16 primitive->apMacConfig.maxListenInterval */
+    bufferSize += 1;  /* CsrUint8 primitive->apMacConfig.supportedRatesCount */
+    bufferSize += 20; /* CsrUint8 primitive->apMacConfig.supportedRates[20] */
+    bufferSize += 1;  /* CsrWifiSmePreambleType primitive->apMacConfig.preamble */
+    bufferSize += 1;  /* CsrBool primitive->apMacConfig.shortSlotTimeEnabled */
+    bufferSize += 1;  /* CsrWifiSmeCtsProtectionType primitive->apMacConfig.ctsProtectionType */
+    bufferSize += 1;  /* CsrBool primitive->apMacConfig.wmmEnabled */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            bufferSize += 1; /* CsrUint8 primitive->apMacConfig.wmmApParams[i2].cwMin */
+            bufferSize += 1; /* CsrUint8 primitive->apMacConfig.wmmApParams[i2].cwMax */
+            bufferSize += 1; /* CsrUint8 primitive->apMacConfig.wmmApParams[i2].aifs */
+            bufferSize += 2; /* CsrUint16 primitive->apMacConfig.wmmApParams[i2].txopLimit */
+            bufferSize += 1; /* CsrBool primitive->apMacConfig.wmmApParams[i2].admissionControlMandatory */
+        }
+    }
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            bufferSize += 1; /* CsrUint8 primitive->apMacConfig.wmmApBcParams[i2].cwMin */
+            bufferSize += 1; /* CsrUint8 primitive->apMacConfig.wmmApBcParams[i2].cwMax */
+            bufferSize += 1; /* CsrUint8 primitive->apMacConfig.wmmApBcParams[i2].aifs */
+            bufferSize += 2; /* CsrUint16 primitive->apMacConfig.wmmApBcParams[i2].txopLimit */
+            bufferSize += 1; /* CsrBool primitive->apMacConfig.wmmApBcParams[i2].admissionControlMandatory */
+        }
+    }
+    bufferSize += 1;         /* CsrWifiSmeApAccessType primitive->apMacConfig.accessType */
+    bufferSize += 1;         /* CsrUint8 primitive->apMacConfig.macAddressListCount */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->apMacConfig.macAddressListCount; i2++)
+        {
+            bufferSize += 6; /* CsrUint8 primitive->apMacConfig.macAddressList[i2].a[6] */
+        }
+    }
+    bufferSize += 1;         /* CsrBool primitive->apMacConfig.apHtParams.greenfieldSupported */
+    bufferSize += 1;         /* CsrBool primitive->apMacConfig.apHtParams.shortGi20MHz */
+    bufferSize += 1;         /* CsrUint8 primitive->apMacConfig.apHtParams.rxStbc */
+    bufferSize += 1;         /* CsrBool primitive->apMacConfig.apHtParams.rifsModeAllowed */
+    bufferSize += 1;         /* CsrUint8 primitive->apMacConfig.apHtParams.htProtection */
+    bufferSize += 1;         /* CsrBool primitive->apMacConfig.apHtParams.dualCtsProtection */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiNmeApConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiNmeApConfigSetReq *primitive = (CsrWifiNmeApConfigSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->apConfig.apGroupkeyTimeout);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apConfig.apStrictGtkRekey);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->apConfig.apGmkTimeout);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->apConfig.apResponseTimeout);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apConfig.apRetransLimit);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.phySupportedBitmap);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->apMacConfig.beaconInterval);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.dtimPeriod);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->apMacConfig.maxListenInterval);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.supportedRatesCount);
+    CsrMemCpySer(ptr, len, (const void *) primitive->apMacConfig.supportedRates, ((CsrUint16) (20)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.preamble);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.shortSlotTimeEnabled);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.ctsProtectionType);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.wmmEnabled);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.wmmApParams[i2].cwMin);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.wmmApParams[i2].cwMax);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.wmmApParams[i2].aifs);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->apMacConfig.wmmApParams[i2].txopLimit);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.wmmApParams[i2].admissionControlMandatory);
+        }
+    }
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.wmmApBcParams[i2].cwMin);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.wmmApBcParams[i2].cwMax);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.wmmApBcParams[i2].aifs);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->apMacConfig.wmmApBcParams[i2].txopLimit);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.wmmApBcParams[i2].admissionControlMandatory);
+        }
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.accessType);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.macAddressListCount);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->apMacConfig.macAddressListCount; i2++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->apMacConfig.macAddressList[i2].a, ((CsrUint16) (6)));
+        }
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.apHtParams.greenfieldSupported);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.apHtParams.shortGi20MHz);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.apHtParams.rxStbc);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.apHtParams.rifsModeAllowed);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.apHtParams.htProtection);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apMacConfig.apHtParams.dualCtsProtection);
+    return(ptr);
+}
+
+
+void* CsrWifiNmeApConfigSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiNmeApConfigSetReq *primitive = (CsrWifiNmeApConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiNmeApConfigSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->apConfig.apGroupkeyTimeout, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apConfig.apStrictGtkRekey, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->apConfig.apGmkTimeout, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->apConfig.apResponseTimeout, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apConfig.apRetransLimit, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.phySupportedBitmap, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->apMacConfig.beaconInterval, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.dtimPeriod, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->apMacConfig.maxListenInterval, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.supportedRatesCount, buffer, &offset);
+    CsrMemCpyDes(primitive->apMacConfig.supportedRates, buffer, &offset, ((CsrUint16) (20)));
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.preamble, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.shortSlotTimeEnabled, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.ctsProtectionType, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.wmmEnabled, buffer, &offset);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.wmmApParams[i2].cwMin, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.wmmApParams[i2].cwMax, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.wmmApParams[i2].aifs, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->apMacConfig.wmmApParams[i2].txopLimit, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.wmmApParams[i2].admissionControlMandatory, buffer, &offset);
+        }
+    }
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.wmmApBcParams[i2].cwMin, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.wmmApBcParams[i2].cwMax, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.wmmApBcParams[i2].aifs, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->apMacConfig.wmmApBcParams[i2].txopLimit, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.wmmApBcParams[i2].admissionControlMandatory, buffer, &offset);
+        }
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.accessType, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.macAddressListCount, buffer, &offset);
+    primitive->apMacConfig.macAddressList = NULL;
+    if (primitive->apMacConfig.macAddressListCount)
+    {
+        primitive->apMacConfig.macAddressList = (CsrWifiMacAddress *)CsrPmemAlloc(sizeof(CsrWifiMacAddress) * primitive->apMacConfig.macAddressListCount);
+    }
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->apMacConfig.macAddressListCount; i2++)
+        {
+            CsrMemCpyDes(primitive->apMacConfig.macAddressList[i2].a, buffer, &offset, ((CsrUint16) (6)));
+        }
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.apHtParams.greenfieldSupported, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.apHtParams.shortGi20MHz, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.apHtParams.rxStbc, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.apHtParams.rifsModeAllowed, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.apHtParams.htProtection, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apMacConfig.apHtParams.dualCtsProtection, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiNmeApConfigSetReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiNmeApConfigSetReq *primitive = (CsrWifiNmeApConfigSetReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->apMacConfig.macAddressList);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiNmeApWpsRegisterReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 17) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiSmeWpsDpid primitive->selectedDevicePasswordId */
+    bufferSize += 2; /* CsrWifiSmeWpsConfigType primitive->selectedConfigMethod */
+    bufferSize += 8; /* CsrUint8 primitive->pin[8] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiNmeApWpsRegisterReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiNmeApWpsRegisterReq *primitive = (CsrWifiNmeApWpsRegisterReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->selectedDevicePasswordId);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->selectedConfigMethod);
+    CsrMemCpySer(ptr, len, (const void *) primitive->pin, ((CsrUint16) (8)));
+    return(ptr);
+}
+
+
+void* CsrWifiNmeApWpsRegisterReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiNmeApWpsRegisterReq *primitive = (CsrWifiNmeApWpsRegisterReq *) CsrPmemAlloc(sizeof(CsrWifiNmeApWpsRegisterReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->selectedDevicePasswordId, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->selectedConfigMethod, buffer, &offset);
+    CsrMemCpyDes(primitive->pin, buffer, &offset, ((CsrUint16) (8)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiNmeApStartReqSizeof(void *msg)
+{
+    CsrWifiNmeApStartReq *primitive = (CsrWifiNmeApStartReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 112) */
+    bufferSize += 2;  /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1;  /* CsrWifiSmeApType primitive->apType */
+    bufferSize += 1;  /* CsrBool primitive->cloakSsid */
+    bufferSize += 32; /* CsrUint8 primitive->ssid.ssid[32] */
+    bufferSize += 1;  /* CsrUint8 primitive->ssid.length */
+    bufferSize += 1;  /* CsrWifiSmeRadioIF primitive->ifIndex */
+    bufferSize += 1;  /* CsrUint8 primitive->channel */
+    bufferSize += 1;  /* CsrWifiSmeApAuthType primitive->apCredentials.authType */
+    switch (primitive->apCredentials.authType)
+    {
+        case CSR_WIFI_SME_AP_AUTH_TYPE_OPEN_SYSTEM:
+            bufferSize += 1; /* CsrUint8 primitive->apCredentials.nmeAuthType.openSystemEmpty.empty */
+            break;
+        case CSR_WIFI_SME_AP_AUTH_TYPE_WEP:
+            bufferSize += 1; /* CsrWifiSmeWepCredentialType primitive->apCredentials.nmeAuthType.authwep.wepKeyType */
+            switch (primitive->apCredentials.nmeAuthType.authwep.wepKeyType)
+            {
+                case CSR_WIFI_SME_CREDENTIAL_TYPE_WEP128:
+                    bufferSize += 1;  /* CsrWifiSmeWepAuthMode primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.wepAuthType */
+                    bufferSize += 1;  /* CsrUint8 primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.selectedWepKey */
+                    bufferSize += 13; /* CsrUint8 primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key1[13] */
+                    bufferSize += 13; /* CsrUint8 primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key2[13] */
+                    bufferSize += 13; /* CsrUint8 primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key3[13] */
+                    bufferSize += 13; /* CsrUint8 primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key4[13] */
+                    break;
+                case CSR_WIFI_SME_CREDENTIAL_TYPE_WEP64:
+                    bufferSize += 1;  /* CsrWifiSmeWepAuthMode primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.wepAuthType */
+                    bufferSize += 1;  /* CsrUint8 primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.selectedWepKey */
+                    bufferSize += 5;  /* CsrUint8 primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key1[5] */
+                    bufferSize += 5;  /* CsrUint8 primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key2[5] */
+                    bufferSize += 5;  /* CsrUint8 primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key3[5] */
+                    bufferSize += 5;  /* CsrUint8 primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key4[5] */
+                    break;
+                default:
+                    break;
+            }
+            break;
+        case CSR_WIFI_SME_AP_AUTH_TYPE_PERSONAL:
+            bufferSize += 1; /* CsrWifiSmeApAuthSupportMask primitive->apCredentials.nmeAuthType.authTypePersonal.authSupport */
+            bufferSize += 2; /* CsrWifiSmeApRsnCapabilitiesMask primitive->apCredentials.nmeAuthType.authTypePersonal.rsnCapabilities */
+            bufferSize += 2; /* CsrWifiSmeApWapiCapabilitiesMask primitive->apCredentials.nmeAuthType.authTypePersonal.wapiCapabilities */
+            bufferSize += 1; /* CsrWifiNmeApPersCredentialType primitive->apCredentials.nmeAuthType.authTypePersonal.pskOrPassphrase */
+            switch (primitive->apCredentials.nmeAuthType.authTypePersonal.pskOrPassphrase)
+            {
+                case CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PSK:
+                    bufferSize += 2;                                                                                                                                                                                                                      /* CsrUint16 primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.psk.encryptionMode */
+                    bufferSize += 32;                                                                                                                                                                                                                     /* CsrUint8 primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.psk.psk[32] */
+                    break;
+                case CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PASSPHRASE:
+                    bufferSize += 2;                                                                                                                                                                                                                      /* CsrUint16 primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.passphrase.encryptionMode */
+                    bufferSize += (primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.passphrase.passphrase?CsrStrLen(primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.passphrase.passphrase) : 0) + 1; /* CsrCharString* primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.passphrase.passphrase (0 byte len + 1 for NULL Term) */
+                    break;
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+    bufferSize += 1; /* CsrUint8 primitive->maxConnections */
+    bufferSize += 1; /* CsrWifiSmeP2pGroupCapabilityMask primitive->p2pGoParam.groupCapability */
+    bufferSize += 3; /* CsrUint8 primitive->p2pGoParam.operatingChanList.country[3] */
+    bufferSize += 1; /* CsrUint8 primitive->p2pGoParam.operatingChanList.channelEntryListCount */
+    {
+        CsrUint16 i3;
+        for (i3 = 0; i3 < primitive->p2pGoParam.operatingChanList.channelEntryListCount; i3++)
+        {
+            bufferSize += 1;                                                                                  /* CsrUint8 primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingClass */
+            bufferSize += 1;                                                                                  /* CsrUint8 primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannelCount */
+            bufferSize += primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannelCount; /* CsrUint8 primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannel */
+        }
+    }
+    bufferSize += 1;                                                                                          /* CsrBool primitive->p2pGoParam.opPsEnabled */
+    bufferSize += 1;                                                                                          /* CsrUint8 primitive->p2pGoParam.ctWindow */
+    bufferSize += 1;                                                                                          /* CsrWifiSmeP2pNoaConfigMethod primitive->p2pGoParam.noaConfigMethod */
+    bufferSize += 1;                                                                                          /* CsrBool primitive->p2pGoParam.allowNoaWithNonP2pDevices */
+    bufferSize += 1;                                                                                          /* CsrBool primitive->wpsEnabled */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiNmeApStartReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiNmeApStartReq *primitive = (CsrWifiNmeApStartReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apType);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->cloakSsid);
+    CsrMemCpySer(ptr, len, (const void *) primitive->ssid.ssid, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ssid.length);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ifIndex);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->channel);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apCredentials.authType);
+    switch (primitive->apCredentials.authType)
+    {
+        case CSR_WIFI_SME_AP_AUTH_TYPE_OPEN_SYSTEM:
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apCredentials.nmeAuthType.openSystemEmpty.empty);
+            break;
+        case CSR_WIFI_SME_AP_AUTH_TYPE_WEP:
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apCredentials.nmeAuthType.authwep.wepKeyType);
+            switch (primitive->apCredentials.nmeAuthType.authwep.wepKeyType)
+            {
+                case CSR_WIFI_SME_CREDENTIAL_TYPE_WEP128:
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.wepAuthType);
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.selectedWepKey);
+                    CsrMemCpySer(ptr, len, (const void *) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key1, ((CsrUint16) (13)));
+                    CsrMemCpySer(ptr, len, (const void *) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key2, ((CsrUint16) (13)));
+                    CsrMemCpySer(ptr, len, (const void *) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key3, ((CsrUint16) (13)));
+                    CsrMemCpySer(ptr, len, (const void *) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key4, ((CsrUint16) (13)));
+                    break;
+                case CSR_WIFI_SME_CREDENTIAL_TYPE_WEP64:
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.wepAuthType);
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.selectedWepKey);
+                    CsrMemCpySer(ptr, len, (const void *) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key1, ((CsrUint16) (5)));
+                    CsrMemCpySer(ptr, len, (const void *) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key2, ((CsrUint16) (5)));
+                    CsrMemCpySer(ptr, len, (const void *) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key3, ((CsrUint16) (5)));
+                    CsrMemCpySer(ptr, len, (const void *) primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key4, ((CsrUint16) (5)));
+                    break;
+                default:
+                    break;
+            }
+            break;
+        case CSR_WIFI_SME_AP_AUTH_TYPE_PERSONAL:
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apCredentials.nmeAuthType.authTypePersonal.authSupport);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->apCredentials.nmeAuthType.authTypePersonal.rsnCapabilities);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->apCredentials.nmeAuthType.authTypePersonal.wapiCapabilities);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->apCredentials.nmeAuthType.authTypePersonal.pskOrPassphrase);
+            switch (primitive->apCredentials.nmeAuthType.authTypePersonal.pskOrPassphrase)
+            {
+                case CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PSK:
+                    CsrUint16Ser(ptr, len, (CsrUint16) primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.psk.encryptionMode);
+                    CsrMemCpySer(ptr, len, (const void *) primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.psk.psk, ((CsrUint16) (32)));
+                    break;
+                case CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PASSPHRASE:
+                    CsrUint16Ser(ptr, len, (CsrUint16) primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.passphrase.encryptionMode);
+                    CsrCharStringSer(ptr, len, primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.passphrase.passphrase);
+                    break;
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->maxConnections);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->p2pGoParam.groupCapability);
+    CsrMemCpySer(ptr, len, (const void *) primitive->p2pGoParam.operatingChanList.country, ((CsrUint16) (3)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->p2pGoParam.operatingChanList.channelEntryListCount);
+    {
+        CsrUint16 i3;
+        for (i3 = 0; i3 < primitive->p2pGoParam.operatingChanList.channelEntryListCount; i3++)
+        {
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingClass);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannelCount);
+            if (primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannelCount)
+            {
+                CsrMemCpySer(ptr, len, (const void *) primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannel, ((CsrUint16) (primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannelCount)));
+            }
+        }
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->p2pGoParam.opPsEnabled);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->p2pGoParam.ctWindow);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->p2pGoParam.noaConfigMethod);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->p2pGoParam.allowNoaWithNonP2pDevices);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->wpsEnabled);
+    return(ptr);
+}
+
+
+void* CsrWifiNmeApStartReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiNmeApStartReq *primitive = (CsrWifiNmeApStartReq *) CsrPmemAlloc(sizeof(CsrWifiNmeApStartReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apType, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->cloakSsid, buffer, &offset);
+    CsrMemCpyDes(primitive->ssid.ssid, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->ssid.length, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->ifIndex, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->channel, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apCredentials.authType, buffer, &offset);
+    switch (primitive->apCredentials.authType)
+    {
+        case CSR_WIFI_SME_AP_AUTH_TYPE_OPEN_SYSTEM:
+            CsrUint8Des((CsrUint8 *) &primitive->apCredentials.nmeAuthType.openSystemEmpty.empty, buffer, &offset);
+            break;
+        case CSR_WIFI_SME_AP_AUTH_TYPE_WEP:
+            CsrUint8Des((CsrUint8 *) &primitive->apCredentials.nmeAuthType.authwep.wepKeyType, buffer, &offset);
+            switch (primitive->apCredentials.nmeAuthType.authwep.wepKeyType)
+            {
+                case CSR_WIFI_SME_CREDENTIAL_TYPE_WEP128:
+                    CsrUint8Des((CsrUint8 *) &primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.wepAuthType, buffer, &offset);
+                    CsrUint8Des((CsrUint8 *) &primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.selectedWepKey, buffer, &offset);
+                    CsrMemCpyDes(primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key1, buffer, &offset, ((CsrUint16) (13)));
+                    CsrMemCpyDes(primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key2, buffer, &offset, ((CsrUint16) (13)));
+                    CsrMemCpyDes(primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key3, buffer, &offset, ((CsrUint16) (13)));
+                    CsrMemCpyDes(primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep128Key.key4, buffer, &offset, ((CsrUint16) (13)));
+                    break;
+                case CSR_WIFI_SME_CREDENTIAL_TYPE_WEP64:
+                    CsrUint8Des((CsrUint8 *) &primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.wepAuthType, buffer, &offset);
+                    CsrUint8Des((CsrUint8 *) &primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.selectedWepKey, buffer, &offset);
+                    CsrMemCpyDes(primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key1, buffer, &offset, ((CsrUint16) (5)));
+                    CsrMemCpyDes(primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key2, buffer, &offset, ((CsrUint16) (5)));
+                    CsrMemCpyDes(primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key3, buffer, &offset, ((CsrUint16) (5)));
+                    CsrMemCpyDes(primitive->apCredentials.nmeAuthType.authwep.wepCredentials.wep64Key.key4, buffer, &offset, ((CsrUint16) (5)));
+                    break;
+                default:
+                    break;
+            }
+            break;
+        case CSR_WIFI_SME_AP_AUTH_TYPE_PERSONAL:
+            CsrUint8Des((CsrUint8 *) &primitive->apCredentials.nmeAuthType.authTypePersonal.authSupport, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->apCredentials.nmeAuthType.authTypePersonal.rsnCapabilities, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->apCredentials.nmeAuthType.authTypePersonal.wapiCapabilities, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->apCredentials.nmeAuthType.authTypePersonal.pskOrPassphrase, buffer, &offset);
+            switch (primitive->apCredentials.nmeAuthType.authTypePersonal.pskOrPassphrase)
+            {
+                case CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PSK:
+                    CsrUint16Des((CsrUint16 *) &primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.psk.encryptionMode, buffer, &offset);
+                    CsrMemCpyDes(primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.psk.psk, buffer, &offset, ((CsrUint16) (32)));
+                    break;
+                case CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PASSPHRASE:
+                    CsrUint16Des((CsrUint16 *) &primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.passphrase.encryptionMode, buffer, &offset);
+                    CsrCharStringDes(&primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.passphrase.passphrase, buffer, &offset);
+                    break;
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->maxConnections, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->p2pGoParam.groupCapability, buffer, &offset);
+    CsrMemCpyDes(primitive->p2pGoParam.operatingChanList.country, buffer, &offset, ((CsrUint16) (3)));
+    CsrUint8Des((CsrUint8 *) &primitive->p2pGoParam.operatingChanList.channelEntryListCount, buffer, &offset);
+    primitive->p2pGoParam.operatingChanList.channelEntryList = NULL;
+    if (primitive->p2pGoParam.operatingChanList.channelEntryListCount)
+    {
+        primitive->p2pGoParam.operatingChanList.channelEntryList = (CsrWifiSmeApP2pOperatingChanEntry *)CsrPmemAlloc(sizeof(CsrWifiSmeApP2pOperatingChanEntry) * primitive->p2pGoParam.operatingChanList.channelEntryListCount);
+    }
+    {
+        CsrUint16 i3;
+        for (i3 = 0; i3 < primitive->p2pGoParam.operatingChanList.channelEntryListCount; i3++)
+        {
+            CsrUint8Des((CsrUint8 *) &primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingClass, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannelCount, buffer, &offset);
+            if (primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannelCount)
+            {
+                primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannel = (CsrUint8 *)CsrPmemAlloc(primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannelCount);
+                CsrMemCpyDes(primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannel, buffer, &offset, ((CsrUint16) (primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannelCount)));
+            }
+            else
+            {
+                primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannel = NULL;
+            }
+        }
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->p2pGoParam.opPsEnabled, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->p2pGoParam.ctWindow, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->p2pGoParam.noaConfigMethod, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->p2pGoParam.allowNoaWithNonP2pDevices, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->wpsEnabled, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiNmeApStartReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiNmeApStartReq *primitive = (CsrWifiNmeApStartReq *) voidPrimitivePointer;
+    switch (primitive->apCredentials.authType)
+    {
+        case CSR_WIFI_SME_AP_AUTH_TYPE_PERSONAL:
+            switch (primitive->apCredentials.nmeAuthType.authTypePersonal.pskOrPassphrase)
+            {
+                case CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PASSPHRASE:
+                    CsrPmemFree(primitive->apCredentials.nmeAuthType.authTypePersonal.authPers_credentials.passphrase.passphrase);
+                    break;
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+    {
+        CsrUint16 i3;
+        for (i3 = 0; i3 < primitive->p2pGoParam.operatingChanList.channelEntryListCount; i3++)
+        {
+            CsrPmemFree(primitive->p2pGoParam.operatingChanList.channelEntryList[i3].operatingChannel);
+        }
+    }
+    CsrPmemFree(primitive->p2pGoParam.operatingChanList.channelEntryList);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiNmeApWmmParamUpdateReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 51) */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 4; i1++)
+        {
+            bufferSize += 1; /* CsrUint8 primitive->wmmApParams[i1].cwMin */
+            bufferSize += 1; /* CsrUint8 primitive->wmmApParams[i1].cwMax */
+            bufferSize += 1; /* CsrUint8 primitive->wmmApParams[i1].aifs */
+            bufferSize += 2; /* CsrUint16 primitive->wmmApParams[i1].txopLimit */
+            bufferSize += 1; /* CsrBool primitive->wmmApParams[i1].admissionControlMandatory */
+        }
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 4; i1++)
+        {
+            bufferSize += 1; /* CsrUint8 primitive->wmmApBcParams[i1].cwMin */
+            bufferSize += 1; /* CsrUint8 primitive->wmmApBcParams[i1].cwMax */
+            bufferSize += 1; /* CsrUint8 primitive->wmmApBcParams[i1].aifs */
+            bufferSize += 2; /* CsrUint16 primitive->wmmApBcParams[i1].txopLimit */
+            bufferSize += 1; /* CsrBool primitive->wmmApBcParams[i1].admissionControlMandatory */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiNmeApWmmParamUpdateReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiNmeApWmmParamUpdateReq *primitive = (CsrWifiNmeApWmmParamUpdateReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 4; i1++)
+        {
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->wmmApParams[i1].cwMin);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->wmmApParams[i1].cwMax);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->wmmApParams[i1].aifs);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->wmmApParams[i1].txopLimit);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->wmmApParams[i1].admissionControlMandatory);
+        }
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 4; i1++)
+        {
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->wmmApBcParams[i1].cwMin);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->wmmApBcParams[i1].cwMax);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->wmmApBcParams[i1].aifs);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->wmmApBcParams[i1].txopLimit);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->wmmApBcParams[i1].admissionControlMandatory);
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiNmeApWmmParamUpdateReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiNmeApWmmParamUpdateReq *primitive = (CsrWifiNmeApWmmParamUpdateReq *) CsrPmemAlloc(sizeof(CsrWifiNmeApWmmParamUpdateReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 4; i1++)
+        {
+            CsrUint8Des((CsrUint8 *) &primitive->wmmApParams[i1].cwMin, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->wmmApParams[i1].cwMax, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->wmmApParams[i1].aifs, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->wmmApParams[i1].txopLimit, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->wmmApParams[i1].admissionControlMandatory, buffer, &offset);
+        }
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 4; i1++)
+        {
+            CsrUint8Des((CsrUint8 *) &primitive->wmmApBcParams[i1].cwMin, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->wmmApBcParams[i1].cwMax, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->wmmApBcParams[i1].aifs, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->wmmApBcParams[i1].txopLimit, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->wmmApBcParams[i1].admissionControlMandatory, buffer, &offset);
+        }
+    }
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiNmeApStaRemoveReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 12) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 6; /* CsrUint8 primitive->staMacAddress.a[6] */
+    bufferSize += 1; /* CsrBool primitive->keepBlocking */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiNmeApStaRemoveReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiNmeApStaRemoveReq *primitive = (CsrWifiNmeApStaRemoveReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrMemCpySer(ptr, len, (const void *) primitive->staMacAddress.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->keepBlocking);
+    return(ptr);
+}
+
+
+void* CsrWifiNmeApStaRemoveReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiNmeApStaRemoveReq *primitive = (CsrWifiNmeApStaRemoveReq *) CsrPmemAlloc(sizeof(CsrWifiNmeApStaRemoveReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrMemCpyDes(primitive->staMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->keepBlocking, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiNmeApWpsRegisterCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiNmeApWpsRegisterCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiNmeApWpsRegisterCfm *primitive = (CsrWifiNmeApWpsRegisterCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiNmeApWpsRegisterCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiNmeApWpsRegisterCfm *primitive = (CsrWifiNmeApWpsRegisterCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeApWpsRegisterCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiNmeApStartCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 40) */
+    bufferSize += 2;  /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;  /* CsrResult primitive->status */
+    bufferSize += 32; /* CsrUint8 primitive->ssid.ssid[32] */
+    bufferSize += 1;  /* CsrUint8 primitive->ssid.length */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiNmeApStartCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiNmeApStartCfm *primitive = (CsrWifiNmeApStartCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrMemCpySer(ptr, len, (const void *) primitive->ssid.ssid, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ssid.length);
+    return(ptr);
+}
+
+
+void* CsrWifiNmeApStartCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiNmeApStartCfm *primitive = (CsrWifiNmeApStartCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeApStartCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrMemCpyDes(primitive->ssid.ssid, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->ssid.length, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiNmeApStopCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiNmeApStopCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiNmeApStopCfm *primitive = (CsrWifiNmeApStopCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiNmeApStopCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiNmeApStopCfm *primitive = (CsrWifiNmeApStopCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeApStopCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiNmeApStopIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiSmeApType primitive->apType */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiNmeApStopIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiNmeApStopInd *primitive = (CsrWifiNmeApStopInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->apType);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiNmeApStopIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiNmeApStopInd *primitive = (CsrWifiNmeApStopInd *) CsrPmemAlloc(sizeof(CsrWifiNmeApStopInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->apType, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiNmeApStationIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 18) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiSmeMediaStatus primitive->mediaStatus */
+    bufferSize += 6; /* CsrUint8 primitive->peerMacAddress.a[6] */
+    bufferSize += 6; /* CsrUint8 primitive->peerDeviceAddress.a[6] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiNmeApStationIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiNmeApStationInd *primitive = (CsrWifiNmeApStationInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->mediaStatus);
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerMacAddress.a, ((CsrUint16) (6)));
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerDeviceAddress.a, ((CsrUint16) (6)));
+    return(ptr);
+}
+
+
+void* CsrWifiNmeApStationIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiNmeApStationInd *primitive = (CsrWifiNmeApStationInd *) CsrPmemAlloc(sizeof(CsrWifiNmeApStationInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->mediaStatus, buffer, &offset);
+    CsrMemCpyDes(primitive->peerMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrMemCpyDes(primitive->peerDeviceAddress.a, buffer, &offset, ((CsrUint16) (6)));
+
+    return primitive;
+}
+
+
+#endif /* CSR_WIFI_NME_ENABLE */
+#endif /* CSR_WIFI_AP_ENABLE */
diff --git a/drivers/staging/csr/csr_wifi_nme_ap_serialize.h b/drivers/staging/csr/csr_wifi_nme_ap_serialize.h
new file mode 100644
index 0000000..d59abf9
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_ap_serialize.h
@@ -0,0 +1,105 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_NME_AP_SERIALIZE_H__
+#define CSR_WIFI_NME_AP_SERIALIZE_H__
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_wifi_msgconv.h"
+
+#include "csr_wifi_nme_ap_prim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_NME_ENABLE
+#error CSR_WIFI_NME_ENABLE MUST be defined inorder to use csr_wifi_nme_ap_serialize.h
+#endif
+#ifndef CSR_WIFI_AP_ENABLE
+#error CSR_WIFI_AP_ENABLE MUST be defined inorder to use csr_wifi_nme_ap_serialize.h
+#endif
+
+extern void CsrWifiNmeApPfree(void *ptr);
+
+extern CsrUint8* CsrWifiNmeApConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeApConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeApConfigSetReqSizeof(void *msg);
+extern void CsrWifiNmeApConfigSetReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiNmeApWpsRegisterReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeApWpsRegisterReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeApWpsRegisterReqSizeof(void *msg);
+#define CsrWifiNmeApWpsRegisterReqSerFree CsrWifiNmeApPfree
+
+extern CsrUint8* CsrWifiNmeApStartReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeApStartReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeApStartReqSizeof(void *msg);
+extern void CsrWifiNmeApStartReqSerFree(void *msg);
+
+#define CsrWifiNmeApStopReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiNmeApStopReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiNmeApStopReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiNmeApStopReqSerFree CsrWifiNmeApPfree
+
+extern CsrUint8* CsrWifiNmeApWmmParamUpdateReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeApWmmParamUpdateReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeApWmmParamUpdateReqSizeof(void *msg);
+#define CsrWifiNmeApWmmParamUpdateReqSerFree CsrWifiNmeApPfree
+
+extern CsrUint8* CsrWifiNmeApStaRemoveReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeApStaRemoveReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeApStaRemoveReqSizeof(void *msg);
+#define CsrWifiNmeApStaRemoveReqSerFree CsrWifiNmeApPfree
+
+#define CsrWifiNmeApConfigSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiNmeApConfigSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiNmeApConfigSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiNmeApConfigSetCfmSerFree CsrWifiNmeApPfree
+
+extern CsrUint8* CsrWifiNmeApWpsRegisterCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeApWpsRegisterCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeApWpsRegisterCfmSizeof(void *msg);
+#define CsrWifiNmeApWpsRegisterCfmSerFree CsrWifiNmeApPfree
+
+extern CsrUint8* CsrWifiNmeApStartCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeApStartCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeApStartCfmSizeof(void *msg);
+#define CsrWifiNmeApStartCfmSerFree CsrWifiNmeApPfree
+
+extern CsrUint8* CsrWifiNmeApStopCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeApStopCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeApStopCfmSizeof(void *msg);
+#define CsrWifiNmeApStopCfmSerFree CsrWifiNmeApPfree
+
+extern CsrUint8* CsrWifiNmeApStopIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeApStopIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeApStopIndSizeof(void *msg);
+#define CsrWifiNmeApStopIndSerFree CsrWifiNmeApPfree
+
+#define CsrWifiNmeApWmmParamUpdateCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiNmeApWmmParamUpdateCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiNmeApWmmParamUpdateCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiNmeApWmmParamUpdateCfmSerFree CsrWifiNmeApPfree
+
+extern CsrUint8* CsrWifiNmeApStationIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeApStationIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeApStationIndSizeof(void *msg);
+#define CsrWifiNmeApStationIndSerFree CsrWifiNmeApPfree
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* CSR_WIFI_NME_AP_SERIALIZE_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_nme_converter_init.h b/drivers/staging/csr/csr_wifi_nme_converter_init.h
new file mode 100644
index 0000000..6661914
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_converter_init.h
@@ -0,0 +1,46 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_NME_CONVERTER_INIT_H__
+#define CSR_WIFI_NME_CONVERTER_INIT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_NME_ENABLE
+#error CSR_WIFI_NME_ENABLE MUST be defined inorder to use csr_wifi_nme_converter_init.h
+#endif
+
+#ifndef EXCLUDE_CSR_WIFI_NME_MODULE
+
+#include "csr_msgconv.h"
+
+#ifdef CSR_LOG_ENABLE
+#include "csr_log.h"
+
+extern const CsrLogPrimitiveInformation* CsrWifiNmeTechInfoGet(void);
+#endif /* CSR_LOG_ENABLE */
+
+extern void CsrWifiNmeConverterInit(void);
+
+#else /* EXCLUDE_CSR_WIFI_NME_MODULE */
+
+#define CsrWifiNmeConverterInit()
+
+#endif /* EXCLUDE_CSR_WIFI_NME_MODULE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_NME_CONVERTER_INIT_H__ */
diff --git a/drivers/staging/csr/csr_wifi_nme_lib.h b/drivers/staging/csr/csr_wifi_nme_lib.h
new file mode 100644
index 0000000..897afbf
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_lib.h
@@ -0,0 +1,1056 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_NME_LIB_H__
+#define CSR_WIFI_NME_LIB_H__
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_sched.h"
+#include "csr_util.h"
+#include "csr_msg_transport.h"
+
+#include "csr_wifi_lib.h"
+
+#include "csr_wifi_nme_prim.h"
+#include "csr_wifi_nme_task.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_NME_ENABLE
+#error CSR_WIFI_NME_ENABLE MUST be defined inorder to use csr_wifi_nme_lib.h
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiNmeFreeUpstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_NME upstream message. Does not
+ *      free the message itself, and can only be used for upstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_NME upstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiNmeFreeUpstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiNmeFreeDownstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_NME downstream message. Does not
+ *      free the message itself, and can only be used for downstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_NME downstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiNmeFreeDownstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ * Enum to string functions
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiNmeAuthModeToString(CsrWifiNmeAuthMode value);
+const CsrCharString* CsrWifiNmeBssTypeToString(CsrWifiNmeBssType value);
+const CsrCharString* CsrWifiNmeCcxOptionsMaskToString(CsrWifiNmeCcxOptionsMask value);
+const CsrCharString* CsrWifiNmeConfigActionToString(CsrWifiNmeConfigAction value);
+const CsrCharString* CsrWifiNmeConnectionStatusToString(CsrWifiNmeConnectionStatus value);
+const CsrCharString* CsrWifiNmeCredentialTypeToString(CsrWifiNmeCredentialType value);
+const CsrCharString* CsrWifiNmeEapMethodToString(CsrWifiNmeEapMethod value);
+const CsrCharString* CsrWifiNmeEncryptionToString(CsrWifiNmeEncryption value);
+const CsrCharString* CsrWifiNmeIndicationsToString(CsrWifiNmeIndications value);
+const CsrCharString* CsrWifiNmeSecErrorToString(CsrWifiNmeSecError value);
+const CsrCharString* CsrWifiNmeSimCardTypeToString(CsrWifiNmeSimCardType value);
+const CsrCharString* CsrWifiNmeUmtsAuthResultToString(CsrWifiNmeUmtsAuthResult value);
+const CsrCharString* CsrWifiNmeWmmQosInfoToString(CsrWifiNmeWmmQosInfo value);
+
+
+/*----------------------------------------------------------------------------*
+ * CsrPrim Type toString function.
+ * Converts a message type to the String name of the Message
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiNmePrimTypeToString(CsrPrim msgType);
+
+/*----------------------------------------------------------------------------*
+ * Lookup arrays for PrimType name Strings
+ *----------------------------------------------------------------------------*/
+extern const CsrCharString *CsrWifiNmeUpstreamPrimNames[CSR_WIFI_NME_PRIM_UPSTREAM_COUNT];
+extern const CsrCharString *CsrWifiNmeDownstreamPrimNames[CSR_WIFI_NME_PRIM_DOWNSTREAM_COUNT];
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeConnectionStatusGetReqSend
+
+  DESCRIPTION
+    Requests the current connection status of the NME.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiNmeConnectionStatusGetReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiNmeConnectionStatusGetReq *) CsrPmemAlloc(sizeof(CsrWifiNmeConnectionStatusGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_CONNECTION_STATUS_GET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiNmeConnectionStatusGetReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiNmeConnectionStatusGetReq *msg__; \
+        CsrWifiNmeConnectionStatusGetReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeConnectionStatusGetReqSend(src__, interfaceTag__) \
+    CsrWifiNmeConnectionStatusGetReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeConnectionStatusGetCfmSend
+
+  DESCRIPTION
+    Reports the connection status of the NME.
+
+  PARAMETERS
+    queue            - Destination Task Queue
+    interfaceTag     - Interface Identifier; unique identifier of an interface
+    status           - Indicates the success or otherwise of the requested
+                       operation.
+    connectionStatus - NME current connection status
+
+*******************************************************************************/
+#define CsrWifiNmeConnectionStatusGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, connectionStatus__) \
+    msg__ = (CsrWifiNmeConnectionStatusGetCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeConnectionStatusGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_CONNECTION_STATUS_GET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->connectionStatus = (connectionStatus__);
+
+#define CsrWifiNmeConnectionStatusGetCfmSendTo(dst__, src__, interfaceTag__, status__, connectionStatus__) \
+    { \
+        CsrWifiNmeConnectionStatusGetCfm *msg__; \
+        CsrWifiNmeConnectionStatusGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, connectionStatus__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeConnectionStatusGetCfmSend(dst__, interfaceTag__, status__, connectionStatus__) \
+    CsrWifiNmeConnectionStatusGetCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, status__, connectionStatus__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeEventMaskSetReqSend
+
+  DESCRIPTION
+    The wireless manager application may register with the NME to receive
+    notification of interesting events. Indications will be sent only if the
+    wireless manager explicitly registers to be notified of that event.
+    indMask is a bit mask of values defined in CsrWifiNmeIndicationsMask.
+
+  PARAMETERS
+    queue   - Message Source Task Queue (Cfm's will be sent to this Queue)
+    indMask - Set mask with values from CsrWifiNmeIndications
+
+*******************************************************************************/
+#define CsrWifiNmeEventMaskSetReqCreate(msg__, dst__, src__, indMask__) \
+    msg__ = (CsrWifiNmeEventMaskSetReq *) CsrPmemAlloc(sizeof(CsrWifiNmeEventMaskSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_EVENT_MASK_SET_REQ, dst__, src__); \
+    msg__->indMask = (indMask__);
+
+#define CsrWifiNmeEventMaskSetReqSendTo(dst__, src__, indMask__) \
+    { \
+        CsrWifiNmeEventMaskSetReq *msg__; \
+        CsrWifiNmeEventMaskSetReqCreate(msg__, dst__, src__, indMask__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeEventMaskSetReqSend(src__, indMask__) \
+    CsrWifiNmeEventMaskSetReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, indMask__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeEventMaskSetCfmSend
+
+  DESCRIPTION
+    The NME calls the primitive to report the result of the request
+    primitive.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiNmeEventMaskSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiNmeEventMaskSetCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeEventMaskSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_EVENT_MASK_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeEventMaskSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiNmeEventMaskSetCfm *msg__; \
+        CsrWifiNmeEventMaskSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeEventMaskSetCfmSend(dst__, status__) \
+    CsrWifiNmeEventMaskSetCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileConnectReqSend
+
+  DESCRIPTION
+    Requests the NME to attempt to connect to the specified profile.
+    Overrides any current connection attempt.
+
+  PARAMETERS
+    queue           - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    profileIdentity - Identity (BSSID, SSID) of profile to be connected to.
+                      It must match an existing profile in the NME.
+
+*******************************************************************************/
+#define CsrWifiNmeProfileConnectReqCreate(msg__, dst__, src__, interfaceTag__, profileIdentity__) \
+    msg__ = (CsrWifiNmeProfileConnectReq *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileConnectReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_CONNECT_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->profileIdentity = (profileIdentity__);
+
+#define CsrWifiNmeProfileConnectReqSendTo(dst__, src__, interfaceTag__, profileIdentity__) \
+    { \
+        CsrWifiNmeProfileConnectReq *msg__; \
+        CsrWifiNmeProfileConnectReqCreate(msg__, dst__, src__, interfaceTag__, profileIdentity__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileConnectReqSend(src__, interfaceTag__, profileIdentity__) \
+    CsrWifiNmeProfileConnectReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, interfaceTag__, profileIdentity__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileConnectCfmSend
+
+  DESCRIPTION
+    Reports the status of the NME PROFILE CONNECT REQ. If unsuccessful the
+    connectAttempt parameters contain details of the APs that the NME
+    attempted to connect to before reporting the failure of the request.
+
+  PARAMETERS
+    queue                - Destination Task Queue
+    interfaceTag         - Interface Identifier; unique identifier of an
+                           interface
+    status               - Indicates the success or otherwise of the requested
+                           operation.
+    connectAttemptsCount - This parameter is relevant only if
+                           status!=CSR_WIFI_NME_STATUS_SUCCESS.
+                           Number of connection attempt elements provided with
+                           this primitive
+    connectAttempts      - This parameter is relevant only if
+                           status!=CSR_WIFI_NME_STATUS_SUCCESS.
+                           Points to the list of connection attempt elements
+                           provided with this primitive
+                           Each element of the list provides information about
+                           an AP on which the connection attempt was made and
+                           the error that occurred during the attempt.
+
+*******************************************************************************/
+#define CsrWifiNmeProfileConnectCfmCreate(msg__, dst__, src__, interfaceTag__, status__, connectAttemptsCount__, connectAttempts__) \
+    msg__ = (CsrWifiNmeProfileConnectCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileConnectCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_CONNECT_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->connectAttemptsCount = (connectAttemptsCount__); \
+    msg__->connectAttempts = (connectAttempts__);
+
+#define CsrWifiNmeProfileConnectCfmSendTo(dst__, src__, interfaceTag__, status__, connectAttemptsCount__, connectAttempts__) \
+    { \
+        CsrWifiNmeProfileConnectCfm *msg__; \
+        CsrWifiNmeProfileConnectCfmCreate(msg__, dst__, src__, interfaceTag__, status__, connectAttemptsCount__, connectAttempts__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileConnectCfmSend(dst__, interfaceTag__, status__, connectAttemptsCount__, connectAttempts__) \
+    CsrWifiNmeProfileConnectCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, status__, connectAttemptsCount__, connectAttempts__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileDeleteAllReqSend
+
+  DESCRIPTION
+    Deletes all profiles present in the NME, but does NOT modify the
+    preferred profile list.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiNmeProfileDeleteAllReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiNmeProfileDeleteAllReq *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileDeleteAllReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_DELETE_ALL_REQ, dst__, src__);
+
+#define CsrWifiNmeProfileDeleteAllReqSendTo(dst__, src__) \
+    { \
+        CsrWifiNmeProfileDeleteAllReq *msg__; \
+        CsrWifiNmeProfileDeleteAllReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileDeleteAllReqSend(src__) \
+    CsrWifiNmeProfileDeleteAllReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileDeleteAllCfmSend
+
+  DESCRIPTION
+    Reports the status of the CSR_WIFI_NME_PROFILE_DELETE_ALL_REQ.
+    Returns always CSR_WIFI_NME_STATUS_SUCCESS.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Indicates the success or otherwise of the requested operation, but
+             in this case it always set to success.
+
+*******************************************************************************/
+#define CsrWifiNmeProfileDeleteAllCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiNmeProfileDeleteAllCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileDeleteAllCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_DELETE_ALL_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeProfileDeleteAllCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiNmeProfileDeleteAllCfm *msg__; \
+        CsrWifiNmeProfileDeleteAllCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileDeleteAllCfmSend(dst__, status__) \
+    CsrWifiNmeProfileDeleteAllCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileDeleteReqSend
+
+  DESCRIPTION
+    Will delete the profile with a matching identity, but does NOT modify the
+    preferred profile list.
+
+  PARAMETERS
+    queue           - Message Source Task Queue (Cfm's will be sent to this Queue)
+    profileIdentity - Identity (BSSID, SSID) of profile to be deleted.
+
+*******************************************************************************/
+#define CsrWifiNmeProfileDeleteReqCreate(msg__, dst__, src__, profileIdentity__) \
+    msg__ = (CsrWifiNmeProfileDeleteReq *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileDeleteReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_DELETE_REQ, dst__, src__); \
+    msg__->profileIdentity = (profileIdentity__);
+
+#define CsrWifiNmeProfileDeleteReqSendTo(dst__, src__, profileIdentity__) \
+    { \
+        CsrWifiNmeProfileDeleteReq *msg__; \
+        CsrWifiNmeProfileDeleteReqCreate(msg__, dst__, src__, profileIdentity__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileDeleteReqSend(src__, profileIdentity__) \
+    CsrWifiNmeProfileDeleteReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, profileIdentity__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileDeleteCfmSend
+
+  DESCRIPTION
+    Reports the status of the CSR_WIFI_NME_PROFILE_DELETE_REQ.
+    Returns CSR_WIFI_NME_STATUS_NOT_FOUND if there is no matching profile.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Indicates the success or otherwise of the requested operation.
+
+*******************************************************************************/
+#define CsrWifiNmeProfileDeleteCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiNmeProfileDeleteCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileDeleteCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_DELETE_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeProfileDeleteCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiNmeProfileDeleteCfm *msg__; \
+        CsrWifiNmeProfileDeleteCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileDeleteCfmSend(dst__, status__) \
+    CsrWifiNmeProfileDeleteCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileDisconnectIndSend
+
+  DESCRIPTION
+    Indication generated from the NME (if an application subscribes to
+    receive it) that informs that application that the current profile
+    connection has disconnected. The indication will contain information
+    about APs that it attempted to maintain the connection via i.e. in the
+    case of failed roaming.
+
+  PARAMETERS
+    queue                - Destination Task Queue
+    interfaceTag         - Interface Identifier; unique identifier of an
+                           interface
+    connectAttemptsCount - Number of connection attempt elements provided with
+                           this primitive
+    connectAttempts      - Points to the list of connection attempt elements
+                           provided with this primitive
+                           Each element of the list provides information about
+                           an AP on which the connection attempt was made and
+                           the error occurred during the attempt.
+
+*******************************************************************************/
+#define CsrWifiNmeProfileDisconnectIndCreate(msg__, dst__, src__, interfaceTag__, connectAttemptsCount__, connectAttempts__) \
+    msg__ = (CsrWifiNmeProfileDisconnectInd *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileDisconnectInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_DISCONNECT_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->connectAttemptsCount = (connectAttemptsCount__); \
+    msg__->connectAttempts = (connectAttempts__);
+
+#define CsrWifiNmeProfileDisconnectIndSendTo(dst__, src__, interfaceTag__, connectAttemptsCount__, connectAttempts__) \
+    { \
+        CsrWifiNmeProfileDisconnectInd *msg__; \
+        CsrWifiNmeProfileDisconnectIndCreate(msg__, dst__, src__, interfaceTag__, connectAttemptsCount__, connectAttempts__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileDisconnectIndSend(dst__, interfaceTag__, connectAttemptsCount__, connectAttempts__) \
+    CsrWifiNmeProfileDisconnectIndSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, connectAttemptsCount__, connectAttempts__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileOrderSetReqSend
+
+  DESCRIPTION
+    Defines the preferred order that profiles present in the NME should be
+    used during the NME auto-connect behaviour.
+    If profileIdentitysCount == 0, it removes any existing preferred profile
+    list already present in the NME, effectively disabling the auto-connect
+    behaviour.
+    NOTE: Profile identities that do not match any profile stored in the NME
+    are ignored during the auto-connect procedure.
+    NOTE: during auto-connect the NME will only attempt to join an existing
+    adhoc network and it will never attempt to host an adhoc network; for
+    hosting and adhoc network, use CSR_WIFI_NME_PROFILE_CONNECT_REQ
+
+  PARAMETERS
+    queue                 - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag          - Interface Identifier; unique identifier of an
+                            interface
+    profileIdentitysCount - The number of profiles identities in the list.
+    profileIdentitys      - Points to the list of profile identities.
+
+*******************************************************************************/
+#define CsrWifiNmeProfileOrderSetReqCreate(msg__, dst__, src__, interfaceTag__, profileIdentitysCount__, profileIdentitys__) \
+    msg__ = (CsrWifiNmeProfileOrderSetReq *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileOrderSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_ORDER_SET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->profileIdentitysCount = (profileIdentitysCount__); \
+    msg__->profileIdentitys = (profileIdentitys__);
+
+#define CsrWifiNmeProfileOrderSetReqSendTo(dst__, src__, interfaceTag__, profileIdentitysCount__, profileIdentitys__) \
+    { \
+        CsrWifiNmeProfileOrderSetReq *msg__; \
+        CsrWifiNmeProfileOrderSetReqCreate(msg__, dst__, src__, interfaceTag__, profileIdentitysCount__, profileIdentitys__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileOrderSetReqSend(src__, interfaceTag__, profileIdentitysCount__, profileIdentitys__) \
+    CsrWifiNmeProfileOrderSetReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, interfaceTag__, profileIdentitysCount__, profileIdentitys__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileOrderSetCfmSend
+
+  DESCRIPTION
+    Confirmation to UNIFI_NME_PROFILE_ORDER_SET.request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Indicates the success or otherwise of the requested
+                   operation.
+
+*******************************************************************************/
+#define CsrWifiNmeProfileOrderSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiNmeProfileOrderSetCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileOrderSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_ORDER_SET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeProfileOrderSetCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiNmeProfileOrderSetCfm *msg__; \
+        CsrWifiNmeProfileOrderSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileOrderSetCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiNmeProfileOrderSetCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileSetReqSend
+
+  DESCRIPTION
+    Creates or updates an existing profile in the NME that matches the unique
+    identity of the profile. Each profile is identified by the combination of
+    BSSID and SSID. The profile contains all the required credentials for
+    attempting to connect to the network. Creating or updating a profile via
+    the NME PROFILE SET REQ does NOT add the profile to the preferred profile
+    list within the NME used for the NME auto-connect behaviour.
+
+  PARAMETERS
+    queue   - Message Source Task Queue (Cfm's will be sent to this Queue)
+    profile - Specifies the identity and credentials of the network.
+
+*******************************************************************************/
+#define CsrWifiNmeProfileSetReqCreate(msg__, dst__, src__, profile__) \
+    msg__ = (CsrWifiNmeProfileSetReq *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_SET_REQ, dst__, src__); \
+    msg__->profile = (profile__);
+
+#define CsrWifiNmeProfileSetReqSendTo(dst__, src__, profile__) \
+    { \
+        CsrWifiNmeProfileSetReq *msg__; \
+        CsrWifiNmeProfileSetReqCreate(msg__, dst__, src__, profile__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileSetReqSend(src__, profile__) \
+    CsrWifiNmeProfileSetReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, profile__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileSetCfmSend
+
+  DESCRIPTION
+    Reports the status of the NME PROFILE SET REQ; the request will only fail
+    if the details specified in the profile contains an invalid combination
+    of parameters for example specifying the profile as cloaked but not
+    specifying the SSID. The NME doesn't limit the number of profiles that
+    may be created. The NME assumes that the entity configuring it is aware
+    of the appropriate limits.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Indicates the success or otherwise of the requested operation.
+
+*******************************************************************************/
+#define CsrWifiNmeProfileSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiNmeProfileSetCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeProfileSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiNmeProfileSetCfm *msg__; \
+        CsrWifiNmeProfileSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileSetCfmSend(dst__, status__) \
+    CsrWifiNmeProfileSetCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileUpdateIndSend
+
+  DESCRIPTION
+    Indication generated from the NME (if an application subscribes to
+    receive it) that informs that application that the contained profile has
+    changed.
+    For example, either the credentials EAP-FAST PAC file or the session data
+    within the profile has changed.
+    It is up to the application whether it stores this updated profile or
+    not.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    profile      - The identity and credentials of the network.
+
+*******************************************************************************/
+#define CsrWifiNmeProfileUpdateIndCreate(msg__, dst__, src__, interfaceTag__, profile__) \
+    msg__ = (CsrWifiNmeProfileUpdateInd *) CsrPmemAlloc(sizeof(CsrWifiNmeProfileUpdateInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_PROFILE_UPDATE_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->profile = (profile__);
+
+#define CsrWifiNmeProfileUpdateIndSendTo(dst__, src__, interfaceTag__, profile__) \
+    { \
+        CsrWifiNmeProfileUpdateInd *msg__; \
+        CsrWifiNmeProfileUpdateIndCreate(msg__, dst__, src__, interfaceTag__, profile__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeProfileUpdateIndSend(dst__, interfaceTag__, profile__) \
+    CsrWifiNmeProfileUpdateIndSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, profile__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimGsmAuthIndSend
+
+  DESCRIPTION
+    Indication generated from the NME (if an application subscribes to
+    receive it) that requests the UICC Manager to perform a GSM
+    authentication on behalf of the NME. This indication is generated when
+    the NME is attempting to connect to a profile configured for EAP-SIM. An
+    application MUST register to receive this indication for the NME to
+    support the EAP-SIM credential types. Otherwise the NME has no route to
+    obtain the information from the UICC. EAP-SIM authentication requires 2
+    or 3 GSM authentication rounds and therefore 2 or 3 RANDS (GSM Random
+    Challenges) are included.
+
+  PARAMETERS
+    queue       - Destination Task Queue
+    randsLength - GSM RAND is 16 bytes long hence valid values are 32 (2 RANDS)
+                  or 48 (3 RANDs).
+    rands       - 2 or 3 RANDs values.
+
+*******************************************************************************/
+#define CsrWifiNmeSimGsmAuthIndCreate(msg__, dst__, src__, randsLength__, rands__) \
+    msg__ = (CsrWifiNmeSimGsmAuthInd *) CsrPmemAlloc(sizeof(CsrWifiNmeSimGsmAuthInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_SIM_GSM_AUTH_IND, dst__, src__); \
+    msg__->randsLength = (randsLength__); \
+    msg__->rands = (rands__);
+
+#define CsrWifiNmeSimGsmAuthIndSendTo(dst__, src__, randsLength__, rands__) \
+    { \
+        CsrWifiNmeSimGsmAuthInd *msg__; \
+        CsrWifiNmeSimGsmAuthIndCreate(msg__, dst__, src__, randsLength__, rands__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeSimGsmAuthIndSend(dst__, randsLength__, rands__) \
+    CsrWifiNmeSimGsmAuthIndSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, randsLength__, rands__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimGsmAuthResSend
+
+  DESCRIPTION
+    Response from the application that received the NME SIM GSM AUTH IND. For
+    each GSM authentication round a GSM Ciphering key (Kc) and a signed
+    response (SRES) are produced. Since 2 or 3 GSM authentication rounds are
+    used the 2 or 3 Kc's obtained respectively are combined into one buffer
+    and similarly the 2 or 3 SRES's obtained are combined into another
+    buffer. The order of Kc values (SRES values respectively) in their buffer
+    is the same as that of their corresponding RAND values in the incoming
+    indication.
+
+  PARAMETERS
+    status     - Indicates the outcome of the requested operation:
+                 STATUS_SUCCESS or STATUS_ERROR
+    kcsLength  - Length in Bytes of Kc buffer. Legal values are: 16 or 24.
+    kcs        - Kc buffer holding 2 or 3 Kc values.
+    sresLength - Length in Bytes of SRES buffer. Legal values are: 8 or 12.
+    sres       - SRES buffer holding 2 or 3 SRES values.
+
+*******************************************************************************/
+#define CsrWifiNmeSimGsmAuthResCreate(msg__, dst__, src__, status__, kcsLength__, kcs__, sresLength__, sres__) \
+    msg__ = (CsrWifiNmeSimGsmAuthRes *) CsrPmemAlloc(sizeof(CsrWifiNmeSimGsmAuthRes)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_SIM_GSM_AUTH_RES, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->kcsLength = (kcsLength__); \
+    msg__->kcs = (kcs__); \
+    msg__->sresLength = (sresLength__); \
+    msg__->sres = (sres__);
+
+#define CsrWifiNmeSimGsmAuthResSendTo(dst__, src__, status__, kcsLength__, kcs__, sresLength__, sres__) \
+    { \
+        CsrWifiNmeSimGsmAuthRes *msg__; \
+        CsrWifiNmeSimGsmAuthResCreate(msg__, dst__, src__, status__, kcsLength__, kcs__, sresLength__, sres__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeSimGsmAuthResSend(src__, status__, kcsLength__, kcs__, sresLength__, sres__) \
+    CsrWifiNmeSimGsmAuthResSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, status__, kcsLength__, kcs__, sresLength__, sres__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimImsiGetIndSend
+
+  DESCRIPTION
+    Indication generated from the NME (if an application subscribes to
+    receive it) that requests the IMSI and UICC type from the UICC Manager.
+    This indication is generated when the NME is attempting to connect to a
+    profile configured for EAP-SIM/AKA. An application MUST register to
+    receive this indication for the NME to support the EAP-SIM/AKA credential
+    types. Otherwise the NME has no route to obtain the information from the
+    UICC.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+
+*******************************************************************************/
+#define CsrWifiNmeSimImsiGetIndCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiNmeSimImsiGetInd *) CsrPmemAlloc(sizeof(CsrWifiNmeSimImsiGetInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_SIM_IMSI_GET_IND, dst__, src__);
+
+#define CsrWifiNmeSimImsiGetIndSendTo(dst__, src__) \
+    { \
+        CsrWifiNmeSimImsiGetInd *msg__; \
+        CsrWifiNmeSimImsiGetIndCreate(msg__, dst__, src__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeSimImsiGetIndSend(dst__) \
+    CsrWifiNmeSimImsiGetIndSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimImsiGetResSend
+
+  DESCRIPTION
+    Response from the application that received the NME SIM IMSI GET IND.
+
+  PARAMETERS
+    status   - Indicates the outcome of the requested operation: STATUS_SUCCESS
+               or STATUS_ERROR.
+    imsi     - The value of the IMSI obtained from the UICC.
+    cardType - The UICC type (GSM only (SIM), UMTS only (USIM), Both).
+
+*******************************************************************************/
+#define CsrWifiNmeSimImsiGetResCreate(msg__, dst__, src__, status__, imsi__, cardType__) \
+    msg__ = (CsrWifiNmeSimImsiGetRes *) CsrPmemAlloc(sizeof(CsrWifiNmeSimImsiGetRes)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_SIM_IMSI_GET_RES, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->imsi = (imsi__); \
+    msg__->cardType = (cardType__);
+
+#define CsrWifiNmeSimImsiGetResSendTo(dst__, src__, status__, imsi__, cardType__) \
+    { \
+        CsrWifiNmeSimImsiGetRes *msg__; \
+        CsrWifiNmeSimImsiGetResCreate(msg__, dst__, src__, status__, imsi__, cardType__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeSimImsiGetResSend(src__, status__, imsi__, cardType__) \
+    CsrWifiNmeSimImsiGetResSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, status__, imsi__, cardType__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimUmtsAuthIndSend
+
+  DESCRIPTION
+    Indication generated from the NME (if an application subscribes to
+    receive it) that requests the UICC Manager to perform a UMTS
+    authentication on behalf of the NME. This indication is generated when
+    the NME is attempting to connect to a profile configured for EAP-AKA. An
+    application MUST register to receive this indication for the NME to
+    support the EAP-AKA credential types. Otherwise the NME has no route to
+    obtain the information from the USIM. EAP-AKA requires one UMTS
+    authentication round and therefore only one RAND and one AUTN values are
+    included.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    rand   - UMTS RAND value.
+    autn   - UMTS AUTN value.
+
+*******************************************************************************/
+#define CsrWifiNmeSimUmtsAuthIndCreate(msg__, dst__, src__, rand__, autn__) \
+    msg__ = (CsrWifiNmeSimUmtsAuthInd *) CsrPmemAlloc(sizeof(CsrWifiNmeSimUmtsAuthInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_SIM_UMTS_AUTH_IND, dst__, src__); \
+    CsrMemCpy(msg__->rand, (rand__), sizeof(CsrUint8) * 16); \
+    CsrMemCpy(msg__->autn, (autn__), sizeof(CsrUint8) * 16);
+
+#define CsrWifiNmeSimUmtsAuthIndSendTo(dst__, src__, rand__, autn__) \
+    { \
+        CsrWifiNmeSimUmtsAuthInd *msg__; \
+        CsrWifiNmeSimUmtsAuthIndCreate(msg__, dst__, src__, rand__, autn__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeSimUmtsAuthIndSend(dst__, rand__, autn__) \
+    CsrWifiNmeSimUmtsAuthIndSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, rand__, autn__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimUmtsAuthResSend
+
+  DESCRIPTION
+    Response from the application that received the NME SIM UMTS AUTH IND.
+    The values of umtsCipherKey, umtsIntegrityKey, resParameterLength and
+    resParameter are only meanigful when result = UMTS_AUTH_RESULT_SUCCESS.
+    The value of auts is only meaningful when
+    result=UMTS_AUTH_RESULT_SYNC_FAIL.
+
+  PARAMETERS
+    status             - Indicates the outcome of the requested operation:
+                         STATUS_SUCCESS or STATUS_ERROR.
+    result             - The result of UMTS authentication as performed by the
+                         UICC which could be: Success, Authentication Reject or
+                         Synchronisation Failure. For all these 3 outcomes the
+                         value of status is success.
+    umtsCipherKey      - The UMTS Cipher Key as calculated and returned by the
+                         UICC.
+    umtsIntegrityKey   - The UMTS Integrity Key as calculated and returned by
+                         the UICC.
+    resParameterLength - The length (in bytes) of the RES parameter (min=4; max
+                         = 16).
+    resParameter       - The RES parameter as calculated and returned by the
+                         UICC.
+    auts               - The AUTS parameter as calculated and returned by the
+                         UICC.
+
+*******************************************************************************/
+#define CsrWifiNmeSimUmtsAuthResCreate(msg__, dst__, src__, status__, result__, umtsCipherKey__, umtsIntegrityKey__, resParameterLength__, resParameter__, auts__) \
+    msg__ = (CsrWifiNmeSimUmtsAuthRes *) CsrPmemAlloc(sizeof(CsrWifiNmeSimUmtsAuthRes)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_SIM_UMTS_AUTH_RES, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->result = (result__); \
+    CsrMemCpy(msg__->umtsCipherKey, (umtsCipherKey__), sizeof(CsrUint8) * 16); \
+    CsrMemCpy(msg__->umtsIntegrityKey, (umtsIntegrityKey__), sizeof(CsrUint8) * 16); \
+    msg__->resParameterLength = (resParameterLength__); \
+    msg__->resParameter = (resParameter__); \
+    CsrMemCpy(msg__->auts, (auts__), sizeof(CsrUint8) * 14);
+
+#define CsrWifiNmeSimUmtsAuthResSendTo(dst__, src__, status__, result__, umtsCipherKey__, umtsIntegrityKey__, resParameterLength__, resParameter__, auts__) \
+    { \
+        CsrWifiNmeSimUmtsAuthRes *msg__; \
+        CsrWifiNmeSimUmtsAuthResCreate(msg__, dst__, src__, status__, result__, umtsCipherKey__, umtsIntegrityKey__, resParameterLength__, resParameter__, auts__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeSimUmtsAuthResSend(src__, status__, result__, umtsCipherKey__, umtsIntegrityKey__, resParameterLength__, resParameter__, auts__) \
+    CsrWifiNmeSimUmtsAuthResSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, status__, result__, umtsCipherKey__, umtsIntegrityKey__, resParameterLength__, resParameter__, auts__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsCancelReqSend
+
+  DESCRIPTION
+    Requests the NME to cancel any WPS procedure that it is currently
+    performing. This includes WPS registrar activities started because of
+    CSR_WIFI_NME_AP_REGISTER.request
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiNmeWpsCancelReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiNmeWpsCancelReq *) CsrPmemAlloc(sizeof(CsrWifiNmeWpsCancelReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_WPS_CANCEL_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiNmeWpsCancelReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiNmeWpsCancelReq *msg__; \
+        CsrWifiNmeWpsCancelReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeWpsCancelReqSend(src__, interfaceTag__) \
+    CsrWifiNmeWpsCancelReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsCancelCfmSend
+
+  DESCRIPTION
+    Reports the status of the NME WPS REQ, the request is always SUCCESSFUL.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Only returns CSR_WIFI_NME_STATUS_SUCCESS
+
+*******************************************************************************/
+#define CsrWifiNmeWpsCancelCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiNmeWpsCancelCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeWpsCancelCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_WPS_CANCEL_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeWpsCancelCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiNmeWpsCancelCfm *msg__; \
+        CsrWifiNmeWpsCancelCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeWpsCancelCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiNmeWpsCancelCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsCfmSend
+
+  DESCRIPTION
+    Reports the status of the NME WPS REQ.
+    If CSR_WIFI_NME_STATUS_SUCCESS, the profile parameter contains the
+    identity and credentials of the AP.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Indicates the success or otherwise of the requested
+                   operation.
+    profile      - This parameter is relevant only if
+                   status==CSR_WIFI_NME_STATUS_SUCCESS.
+                   The identity and credentials of the network.
+
+*******************************************************************************/
+#define CsrWifiNmeWpsCfmCreate(msg__, dst__, src__, interfaceTag__, status__, profile__) \
+    msg__ = (CsrWifiNmeWpsCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeWpsCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_WPS_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->profile = (profile__);
+
+#define CsrWifiNmeWpsCfmSendTo(dst__, src__, interfaceTag__, status__, profile__) \
+    { \
+        CsrWifiNmeWpsCfm *msg__; \
+        CsrWifiNmeWpsCfmCreate(msg__, dst__, src__, interfaceTag__, status__, profile__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeWpsCfmSend(dst__, interfaceTag__, status__, profile__) \
+    CsrWifiNmeWpsCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, interfaceTag__, status__, profile__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsConfigSetReqSend
+
+  DESCRIPTION
+    This primitive passes the WPS information for the device to NME. This may
+    be accepted only if no interface is active.
+
+  PARAMETERS
+    queue     - Message Source Task Queue (Cfm's will be sent to this Queue)
+    wpsConfig - WPS config.
+
+*******************************************************************************/
+#define CsrWifiNmeWpsConfigSetReqCreate(msg__, dst__, src__, wpsConfig__) \
+    msg__ = (CsrWifiNmeWpsConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiNmeWpsConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_WPS_CONFIG_SET_REQ, dst__, src__); \
+    msg__->wpsConfig = (wpsConfig__);
+
+#define CsrWifiNmeWpsConfigSetReqSendTo(dst__, src__, wpsConfig__) \
+    { \
+        CsrWifiNmeWpsConfigSetReq *msg__; \
+        CsrWifiNmeWpsConfigSetReqCreate(msg__, dst__, src__, wpsConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeWpsConfigSetReqSend(src__, wpsConfig__) \
+    CsrWifiNmeWpsConfigSetReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, wpsConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsConfigSetCfmSend
+
+  DESCRIPTION
+    Confirm.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Status of the request.
+
+*******************************************************************************/
+#define CsrWifiNmeWpsConfigSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiNmeWpsConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiNmeWpsConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_WPS_CONFIG_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiNmeWpsConfigSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiNmeWpsConfigSetCfm *msg__; \
+        CsrWifiNmeWpsConfigSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeWpsConfigSetCfmSend(dst__, status__) \
+    CsrWifiNmeWpsConfigSetCfmSendTo(dst__, CSR_WIFI_NME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsReqSend
+
+  DESCRIPTION
+    Requests the NME to look for WPS enabled APs and attempt to perform WPS
+    to determine the appropriate security credentials to connect to the AP.
+    If the PIN == '00000000' then 'push button mode' is indicated, otherwise
+    the PIN has to match that of the AP. 4 digit pin is passed by sending the
+    pin digits in pin[0]..pin[3] and rest of the contents filled with '-'.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    pin          - PIN value.
+    ssid         - Service Set identifier
+    bssid        - ID of Basic Service Set for which a WPS connection attempt is
+                   being made.
+
+*******************************************************************************/
+#define CsrWifiNmeWpsReqCreate(msg__, dst__, src__, interfaceTag__, pin__, ssid__, bssid__) \
+    msg__ = (CsrWifiNmeWpsReq *) CsrPmemAlloc(sizeof(CsrWifiNmeWpsReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_NME_PRIM, CSR_WIFI_NME_WPS_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    CsrMemCpy(msg__->pin, (pin__), sizeof(CsrUint8) * 8); \
+    msg__->ssid = (ssid__); \
+    msg__->bssid = (bssid__);
+
+#define CsrWifiNmeWpsReqSendTo(dst__, src__, interfaceTag__, pin__, ssid__, bssid__) \
+    { \
+        CsrWifiNmeWpsReq *msg__; \
+        CsrWifiNmeWpsReqCreate(msg__, dst__, src__, interfaceTag__, pin__, ssid__, bssid__); \
+        CsrMsgTransport(dst__, CSR_WIFI_NME_PRIM, msg__); \
+    }
+
+#define CsrWifiNmeWpsReqSend(src__, interfaceTag__, pin__, ssid__, bssid__) \
+    CsrWifiNmeWpsReqSendTo(CSR_WIFI_NME_IFACEQUEUE, src__, interfaceTag__, pin__, ssid__, bssid__)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_NME_LIB_H__ */
diff --git a/drivers/staging/csr/csr_wifi_nme_prim.h b/drivers/staging/csr/csr_wifi_nme_prim.h
new file mode 100644
index 0000000..4d77d2f
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_prim.h
@@ -0,0 +1,1666 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_NME_PRIM_H__
+#define CSR_WIFI_NME_PRIM_H__
+
+#include "csr_types.h"
+#include "csr_prim_defs.h"
+#include "csr_sched.h"
+#include "csr_wifi_common.h"
+#include "csr_result.h"
+#include "csr_wifi_fsm_event.h"
+#include "csr_wifi_sme_prim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_NME_ENABLE
+#error CSR_WIFI_NME_ENABLE MUST be defined inorder to use csr_wifi_nme_prim.h
+#endif
+
+#define CSR_WIFI_NME_PRIM                                               (0x0424)
+
+typedef CsrPrim CsrWifiNmePrim;
+
+typedef void (*CsrWifiNmeFrameFreeFunction)(void *frame);
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeAuthMode
+
+  DESCRIPTION
+    WiFi Authentication Mode
+
+ VALUES
+    CSR_WIFI_NME_AUTH_MODE_80211_OPEN
+                   - Connects to an open system network (i.e. no authentication,
+                     no encryption) or to a WEP enabled network.
+    CSR_WIFI_NME_AUTH_MODE_80211_SHARED
+                   - Connect to a WEP enabled network.
+    CSR_WIFI_NME_AUTH_MODE_8021X_WPA
+                   - Connects to a WPA Enterprise enabled network.
+    CSR_WIFI_NME_AUTH_MODE_8021X_WPAPSK
+                   - Connects to a WPA with Pre-Shared Key enabled network.
+    CSR_WIFI_NME_AUTH_MODE_8021X_WPA2
+                   - Connects to a WPA2 Enterprise enabled network.
+    CSR_WIFI_NME_AUTH_MODE_8021X_WPA2PSK
+                   - Connects to a WPA2 with Pre-Shared Key enabled network.
+    CSR_WIFI_NME_AUTH_MODE_8021X_CCKM
+                   - Connects to a CCKM enabled network.
+    CSR_WIFI_NME_AUTH_MODE_WAPI_WAI
+                   - Connects to a WAPI Enterprise enabled network.
+    CSR_WIFI_NME_AUTH_MODE_WAPI_WAIPSK
+                   - Connects to a WAPI with Pre-Shared Key enabled network.
+    CSR_WIFI_NME_AUTH_MODE_8021X_OTHER1X
+                   - For future use.
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiNmeAuthMode;
+#define CSR_WIFI_NME_AUTH_MODE_80211_OPEN      ((CsrWifiNmeAuthMode) 0x0001)
+#define CSR_WIFI_NME_AUTH_MODE_80211_SHARED    ((CsrWifiNmeAuthMode) 0x0002)
+#define CSR_WIFI_NME_AUTH_MODE_8021X_WPA       ((CsrWifiNmeAuthMode) 0x0004)
+#define CSR_WIFI_NME_AUTH_MODE_8021X_WPAPSK    ((CsrWifiNmeAuthMode) 0x0008)
+#define CSR_WIFI_NME_AUTH_MODE_8021X_WPA2      ((CsrWifiNmeAuthMode) 0x0010)
+#define CSR_WIFI_NME_AUTH_MODE_8021X_WPA2PSK   ((CsrWifiNmeAuthMode) 0x0020)
+#define CSR_WIFI_NME_AUTH_MODE_8021X_CCKM      ((CsrWifiNmeAuthMode) 0x0040)
+#define CSR_WIFI_NME_AUTH_MODE_WAPI_WAI        ((CsrWifiNmeAuthMode) 0x0080)
+#define CSR_WIFI_NME_AUTH_MODE_WAPI_WAIPSK     ((CsrWifiNmeAuthMode) 0x0100)
+#define CSR_WIFI_NME_AUTH_MODE_8021X_OTHER1X   ((CsrWifiNmeAuthMode) 0x0200)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeBssType
+
+  DESCRIPTION
+    Type of BSS
+
+ VALUES
+    CSR_WIFI_NME_BSS_TYPE_INFRASTRUCTURE
+                   - Infrastructure BSS type where access to the network is via
+                     one or several Access Points.
+    CSR_WIFI_NME_BSS_TYPE_ADHOC
+                   - Adhoc or Independent BSS Type where one Station acts as a
+                     host and future stations can join the adhoc network without
+                     needing an access point.
+    CSR_WIFI_NME_BSS_TYPE_RESERVED
+                   - To be in sync with SME.This is not used.
+    CSR_WIFI_NME_BSS_TYPE_P2P
+                   - P2P mode of operation.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiNmeBssType;
+#define CSR_WIFI_NME_BSS_TYPE_INFRASTRUCTURE   ((CsrWifiNmeBssType) 0x00)
+#define CSR_WIFI_NME_BSS_TYPE_ADHOC            ((CsrWifiNmeBssType) 0x01)
+#define CSR_WIFI_NME_BSS_TYPE_RESERVED         ((CsrWifiNmeBssType) 0x02)
+#define CSR_WIFI_NME_BSS_TYPE_P2P              ((CsrWifiNmeBssType) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeCcxOptionsMask
+
+  DESCRIPTION
+    Enumeration type defining possible mask values for setting CCX options.
+
+ VALUES
+    CSR_WIFI_NME_CCX_OPTION_NONE - No CCX option is set.
+    CSR_WIFI_NME_CCX_OPTION_CCKM - CCX option cckm is set.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiNmeCcxOptionsMask;
+#define CSR_WIFI_NME_CCX_OPTION_NONE   ((CsrWifiNmeCcxOptionsMask) 0x00)
+#define CSR_WIFI_NME_CCX_OPTION_CCKM   ((CsrWifiNmeCcxOptionsMask) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeConfigAction
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_PIN_ENTRY_PUSH_BUTTON -
+    CSR_WIFI_PIN_ENTRY_DISPLAY_PIN -
+    CSR_WIFI_PIN_ENTRY_ENTER_PIN   -
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiNmeConfigAction;
+#define CSR_WIFI_PIN_ENTRY_PUSH_BUTTON   ((CsrWifiNmeConfigAction) 0x00)
+#define CSR_WIFI_PIN_ENTRY_DISPLAY_PIN   ((CsrWifiNmeConfigAction) 0x01)
+#define CSR_WIFI_PIN_ENTRY_ENTER_PIN     ((CsrWifiNmeConfigAction) 0x02)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeConnectionStatus
+
+  DESCRIPTION
+    Indicate the NME Connection Status when connecting or when disconnecting
+
+ VALUES
+    CSR_WIFI_NME_CONNECTION_STATUS_CONNECTION_STATUS_DISCONNECTED
+                   - NME is disconnected.
+    CSR_WIFI_NME_CONNECTION_STATUS_CONNECTION_STATUS_CONNECTING
+                   - NME is in the process of connecting.
+    CSR_WIFI_NME_CONNECTION_STATUS_CONNECTION_STATUS_AUTHENTICATING
+                   - NME is in the authentication stage of a connection attempt.
+    CSR_WIFI_NME_CONNECTION_STATUS_CONNECTION_STATUS_CONNECTED
+                   - NME is connected.
+    CSR_WIFI_NME_CONNECTION_STATUS_CONNECTION_STATUS_DISCONNECTING
+                   - NME is in the process of disconnecting.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiNmeConnectionStatus;
+#define CSR_WIFI_NME_CONNECTION_STATUS_CONNECTION_STATUS_DISCONNECTED     ((CsrWifiNmeConnectionStatus) 0x00)
+#define CSR_WIFI_NME_CONNECTION_STATUS_CONNECTION_STATUS_CONNECTING       ((CsrWifiNmeConnectionStatus) 0x01)
+#define CSR_WIFI_NME_CONNECTION_STATUS_CONNECTION_STATUS_AUTHENTICATING   ((CsrWifiNmeConnectionStatus) 0x02)
+#define CSR_WIFI_NME_CONNECTION_STATUS_CONNECTION_STATUS_CONNECTED        ((CsrWifiNmeConnectionStatus) 0x03)
+#define CSR_WIFI_NME_CONNECTION_STATUS_CONNECTION_STATUS_DISCONNECTING    ((CsrWifiNmeConnectionStatus) 0x04)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeCredentialType
+
+  DESCRIPTION
+    NME Credential Types
+
+ VALUES
+    CSR_WIFI_NME_CREDENTIAL_TYPE_OPEN_SYSTEM
+                   - Credential Type Open System.
+    CSR_WIFI_NME_CREDENTIAL_TYPE_WEP64
+                   - Credential Type WEP-64
+    CSR_WIFI_NME_CREDENTIAL_TYPE_WEP128
+                   - Credential Type WEP-128
+    CSR_WIFI_NME_CREDENTIAL_TYPE_WPA_PSK
+                   - Credential Type WPA Pre-Shared Key
+    CSR_WIFI_NME_CREDENTIAL_TYPE_WPA_PASSPHRASE
+                   - Credential Type WPA pass phrase
+    CSR_WIFI_NME_CREDENTIAL_TYPE_WPA2_PSK
+                   - Credential Type WPA2 Pre-Shared Key.
+    CSR_WIFI_NME_CREDENTIAL_TYPE_WPA2_PASSPHRASE
+                   - Credential Type WPA2 pass phrase
+    CSR_WIFI_NME_CREDENTIAL_TYPE_WAPI_PSK
+                   - Credential Type WAPI Pre-Shared Key.
+    CSR_WIFI_NME_CREDENTIAL_TYPE_WAPI_PASSPHRASE
+                   - Credential Type WAPI pass phrase
+    CSR_WIFI_NME_CREDENTIAL_TYPE_WAPI
+                   - Credential Type WAPI certificates
+    CSR_WIFI_NME_CREDENTIAL_TYPE_8021X
+                   - Credential Type 802.1X: the associated type supports
+                     FAST/LEAP/TLS/TTLS/PEAP/etc.
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiNmeCredentialType;
+#define CSR_WIFI_NME_CREDENTIAL_TYPE_OPEN_SYSTEM       ((CsrWifiNmeCredentialType) 0x0000)
+#define CSR_WIFI_NME_CREDENTIAL_TYPE_WEP64             ((CsrWifiNmeCredentialType) 0x0001)
+#define CSR_WIFI_NME_CREDENTIAL_TYPE_WEP128            ((CsrWifiNmeCredentialType) 0x0002)
+#define CSR_WIFI_NME_CREDENTIAL_TYPE_WPA_PSK           ((CsrWifiNmeCredentialType) 0x0003)
+#define CSR_WIFI_NME_CREDENTIAL_TYPE_WPA_PASSPHRASE    ((CsrWifiNmeCredentialType) 0x0004)
+#define CSR_WIFI_NME_CREDENTIAL_TYPE_WPA2_PSK          ((CsrWifiNmeCredentialType) 0x0005)
+#define CSR_WIFI_NME_CREDENTIAL_TYPE_WPA2_PASSPHRASE   ((CsrWifiNmeCredentialType) 0x0006)
+#define CSR_WIFI_NME_CREDENTIAL_TYPE_WAPI_PSK          ((CsrWifiNmeCredentialType) 0x0007)
+#define CSR_WIFI_NME_CREDENTIAL_TYPE_WAPI_PASSPHRASE   ((CsrWifiNmeCredentialType) 0x0008)
+#define CSR_WIFI_NME_CREDENTIAL_TYPE_WAPI              ((CsrWifiNmeCredentialType) 0x0009)
+#define CSR_WIFI_NME_CREDENTIAL_TYPE_8021X             ((CsrWifiNmeCredentialType) 0x000A)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeEapMethod
+
+  DESCRIPTION
+    Outer EAP method with possibly inner method.
+
+ VALUES
+    CSR_WIFI_NME_EAP_METHOD_TLS
+                   - EAP-TLS Method.
+    CSR_WIFI_NME_EAP_METHOD_TTLS_MSCHAPV2
+                   - EAP-TTLS Method with MSCHAPV2.
+    CSR_WIFI_NME_EAP_METHOD_PEAP_GTC
+                   - EAP-PEAP Method with GTC.
+    CSR_WIFI_NME_EAP_METHOD_PEAP_MSCHAPV2
+                   - EAP-PEAP Method with MSCHAPV2.
+    CSR_WIFI_NME_EAP_METHOD_SIM
+                   - EAP-SIM Method.
+    CSR_WIFI_NME_EAP_METHOD_AKA
+                   - EAP-AKA Method.
+    CSR_WIFI_NME_EAP_METHOD_FAST_GTC
+                   - EAP-FAST Method with GTC.
+    CSR_WIFI_NME_EAP_METHOD_FAST_MSCHAPV2
+                   - EAP-FAST Method with MSCHAPV2.
+    CSR_WIFI_NME_EAP_METHOD_LEAP
+                   - EAP-LEAP Method.
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiNmeEapMethod;
+#define CSR_WIFI_NME_EAP_METHOD_TLS             ((CsrWifiNmeEapMethod) 0x0001)
+#define CSR_WIFI_NME_EAP_METHOD_TTLS_MSCHAPV2   ((CsrWifiNmeEapMethod) 0x0002)
+#define CSR_WIFI_NME_EAP_METHOD_PEAP_GTC        ((CsrWifiNmeEapMethod) 0x0004)
+#define CSR_WIFI_NME_EAP_METHOD_PEAP_MSCHAPV2   ((CsrWifiNmeEapMethod) 0x0008)
+#define CSR_WIFI_NME_EAP_METHOD_SIM             ((CsrWifiNmeEapMethod) 0x0010)
+#define CSR_WIFI_NME_EAP_METHOD_AKA             ((CsrWifiNmeEapMethod) 0x0020)
+#define CSR_WIFI_NME_EAP_METHOD_FAST_GTC        ((CsrWifiNmeEapMethod) 0x0040)
+#define CSR_WIFI_NME_EAP_METHOD_FAST_MSCHAPV2   ((CsrWifiNmeEapMethod) 0x0080)
+#define CSR_WIFI_NME_EAP_METHOD_LEAP            ((CsrWifiNmeEapMethod) 0x0100)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeEncryption
+
+  DESCRIPTION
+    WiFi Encryption method
+
+ VALUES
+    CSR_WIFI_NME_ENCRYPTION_CIPHER_NONE
+                   - No encryprion set.
+    CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_WEP40
+                   - 40 bytes WEP key for peer to peer communication.
+    CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_WEP104
+                   - 104 bytes WEP key for peer to peer communication.
+    CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_TKIP
+                   - TKIP key for peer to peer communication.
+    CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_CCMP
+                   - CCMP key for peer to peer communication.
+    CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_SMS4
+                   - SMS4 key for peer to peer communication.
+    CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_WEP40
+                   - 40 bytes WEP key for broadcast messages.
+    CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_WEP104
+                   - 104 bytes WEP key for broadcast messages.
+    CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_TKIP
+                   - TKIP key for broadcast messages.
+    CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_CCMP
+                   - CCMP key for broadcast messages
+    CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_SMS4
+                   - SMS4 key for broadcast messages.
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiNmeEncryption;
+#define CSR_WIFI_NME_ENCRYPTION_CIPHER_NONE              ((CsrWifiNmeEncryption) 0x0000)
+#define CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_WEP40    ((CsrWifiNmeEncryption) 0x0001)
+#define CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_WEP104   ((CsrWifiNmeEncryption) 0x0002)
+#define CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_TKIP     ((CsrWifiNmeEncryption) 0x0004)
+#define CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_CCMP     ((CsrWifiNmeEncryption) 0x0008)
+#define CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_SMS4     ((CsrWifiNmeEncryption) 0x0010)
+#define CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_WEP40       ((CsrWifiNmeEncryption) 0x0020)
+#define CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_WEP104      ((CsrWifiNmeEncryption) 0x0040)
+#define CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_TKIP        ((CsrWifiNmeEncryption) 0x0080)
+#define CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_CCMP        ((CsrWifiNmeEncryption) 0x0100)
+#define CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_SMS4        ((CsrWifiNmeEncryption) 0x0200)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeIndications
+
+  DESCRIPTION
+    NME indications
+
+ VALUES
+    CSR_WIFI_NME_INDICATIONS_IND_AP_STATION
+                   - NME AP Station Indication.
+    CSR_WIFI_NME_INDICATIONS_IND_AP_STOP
+                   - NME AP Stop Indication.
+    CSR_WIFI_NME_INDICATIONS_IND_SIM_UMTS_AUTH
+                   - NME UMTS Authentication Indication.
+    CSR_WIFI_NME_INDICATIONS_IND_P2P_GROUP_START
+                   - NME P2P Group Start Indication.
+    CSR_WIFI_NME_INDICATIONS_IND_P2P_GROUP_STATUS
+                   - NME P2P Group Status Indication.
+    CSR_WIFI_NME_INDICATIONS_IND_P2P_GROUP_ROLE
+                   - NME P2P Group Role Indication.
+    CSR_WIFI_NME_INDICATIONS_IND_PROFILE_DISCONNECT
+                   - NME Profile Disconnect Indication.
+    CSR_WIFI_NME_INDICATIONS_IND_PROFILE_UPDATE
+                   - NME Profile Update Indication.
+    CSR_WIFI_NME_INDICATIONS_IND_SIM_IMSI_GET
+                   - NME GET IMSI Indication.
+    CSR_WIFI_NME_INDICATIONS_IND_SIM_GSM_AUTH
+                   - NME GSM Authentication Indication.
+    CSR_WIFI_NME_INDICATIONS_ALL
+                   - Used to register for all available indications
+
+*******************************************************************************/
+typedef CsrUint32 CsrWifiNmeIndications;
+#define CSR_WIFI_NME_INDICATIONS_IND_AP_STATION           ((CsrWifiNmeIndications) 0x00100000)
+#define CSR_WIFI_NME_INDICATIONS_IND_AP_STOP              ((CsrWifiNmeIndications) 0x00200000)
+#define CSR_WIFI_NME_INDICATIONS_IND_SIM_UMTS_AUTH        ((CsrWifiNmeIndications) 0x01000000)
+#define CSR_WIFI_NME_INDICATIONS_IND_P2P_GROUP_START      ((CsrWifiNmeIndications) 0x02000000)
+#define CSR_WIFI_NME_INDICATIONS_IND_P2P_GROUP_STATUS     ((CsrWifiNmeIndications) 0x04000000)
+#define CSR_WIFI_NME_INDICATIONS_IND_P2P_GROUP_ROLE       ((CsrWifiNmeIndications) 0x08000000)
+#define CSR_WIFI_NME_INDICATIONS_IND_PROFILE_DISCONNECT   ((CsrWifiNmeIndications) 0x10000000)
+#define CSR_WIFI_NME_INDICATIONS_IND_PROFILE_UPDATE       ((CsrWifiNmeIndications) 0x20000000)
+#define CSR_WIFI_NME_INDICATIONS_IND_SIM_IMSI_GET         ((CsrWifiNmeIndications) 0x40000000)
+#define CSR_WIFI_NME_INDICATIONS_IND_SIM_GSM_AUTH         ((CsrWifiNmeIndications) 0x80000000)
+#define CSR_WIFI_NME_INDICATIONS_ALL                      ((CsrWifiNmeIndications) 0xFFFFFFFF)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSecError
+
+  DESCRIPTION
+    NME Security Errors
+    place holder for the security library abort reason
+
+ VALUES
+    CSR_WIFI_NME_SEC_ERROR_SEC_ERROR_UNKNOWN
+                   - Unknown Security Error.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiNmeSecError;
+#define CSR_WIFI_NME_SEC_ERROR_SEC_ERROR_UNKNOWN   ((CsrWifiNmeSecError) 0x00)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimCardType
+
+  DESCRIPTION
+    (U)SIM Card (or UICC) types
+
+ VALUES
+    CSR_WIFI_NME_SIM_CARD_TYPE_2G   - 2G SIM card, capable of performing GSM
+                                      authentication only.
+    CSR_WIFI_NME_SIM_CARD_TYPE_3G   - UICC supporting USIM application, capable
+                                      of performing UMTS authentication only.
+    CSR_WIFI_NME_SIM_CARD_TYPE_2G3G - UICC supporting both USIM and SIM
+                                      applications, capable of performing both
+                                      UMTS and GSM authentications.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiNmeSimCardType;
+#define CSR_WIFI_NME_SIM_CARD_TYPE_2G     ((CsrWifiNmeSimCardType) 0x01)
+#define CSR_WIFI_NME_SIM_CARD_TYPE_3G     ((CsrWifiNmeSimCardType) 0x02)
+#define CSR_WIFI_NME_SIM_CARD_TYPE_2G3G   ((CsrWifiNmeSimCardType) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeUmtsAuthResult
+
+  DESCRIPTION
+    Only relevant for UMTS Authentication. It indicates if the UICC has
+    successfully authenticated the network or otherwise.
+
+ VALUES
+    CSR_WIFI_NME_UMTS_AUTH_RESULT_SUCCESS
+                   - Successful outcome from USIM indicating that the card has
+                     successfully authenticated the network.
+    CSR_WIFI_NME_UMTS_AUTH_RESULT_SYNC_FAIL
+                   - Unsuccessful outcome from USIM indicating that the card is
+                     requesting the network to synchronise and re-try again. If
+                     no further request is received an NME timer will expire and
+                     the authentication is aborted.
+    CSR_WIFI_NME_UMTS_AUTH_RESULT_REJECT
+                   - Unsuccessful outcome from USIM indicating that the card has
+                     rejected the network and that the authentication is
+                     aborted.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiNmeUmtsAuthResult;
+#define CSR_WIFI_NME_UMTS_AUTH_RESULT_SUCCESS     ((CsrWifiNmeUmtsAuthResult) 0x00)
+#define CSR_WIFI_NME_UMTS_AUTH_RESULT_SYNC_FAIL   ((CsrWifiNmeUmtsAuthResult) 0x01)
+#define CSR_WIFI_NME_UMTS_AUTH_RESULT_REJECT      ((CsrWifiNmeUmtsAuthResult) 0x02)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWmmQosInfo
+
+  DESCRIPTION
+    Defines bits for the QoS Info octect as defined in the WMM specification.
+    The values of this type are used across the NME/SME/Router API's and they
+    must be kept consistent with the corresponding types in the .xml of the
+    other interfaces
+
+ VALUES
+    CSR_WIFI_NME_WMM_QOS_INFO_AC_MAX_SP_ALL
+                   - WMM AP may deliver all buffered frames.
+    CSR_WIFI_NME_WMM_QOS_INFO_AC_VO
+                   - To enable the triggering and delivery of QoS Voice.
+    CSR_WIFI_NME_WMM_QOS_INFO_AC_VI
+                   - To enable the triggering and delivery of QoS Video.
+    CSR_WIFI_NME_WMM_QOS_INFO_AC_BK
+                   - To enable the triggering and delivery of QoS Background.
+    CSR_WIFI_NME_WMM_QOS_INFO_AC_BE
+                   - To enable the triggering and delivery of QoS Best Effort.
+    CSR_WIFI_NME_WMM_QOS_INFO_AC_MAX_SP_TWO
+                   - WMM AP may deliver a maximum of 2 buffered frames per
+                     Unscheduled Service Period (USP).
+    CSR_WIFI_NME_WMM_QOS_INFO_AC_MAX_SP_FOUR
+                   - WMM AP may deliver a maximum of 4 buffered frames per USP.
+    CSR_WIFI_NME_WMM_QOS_INFO_AC_MAX_SP_SIX
+                   - WMM AP may deliver a maximum of 6 buffered frames per USP.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiNmeWmmQosInfo;
+#define CSR_WIFI_NME_WMM_QOS_INFO_AC_MAX_SP_ALL    ((CsrWifiNmeWmmQosInfo) 0x00)
+#define CSR_WIFI_NME_WMM_QOS_INFO_AC_VO            ((CsrWifiNmeWmmQosInfo) 0x01)
+#define CSR_WIFI_NME_WMM_QOS_INFO_AC_VI            ((CsrWifiNmeWmmQosInfo) 0x02)
+#define CSR_WIFI_NME_WMM_QOS_INFO_AC_BK            ((CsrWifiNmeWmmQosInfo) 0x04)
+#define CSR_WIFI_NME_WMM_QOS_INFO_AC_BE            ((CsrWifiNmeWmmQosInfo) 0x08)
+#define CSR_WIFI_NME_WMM_QOS_INFO_AC_MAX_SP_TWO    ((CsrWifiNmeWmmQosInfo) 0x20)
+#define CSR_WIFI_NME_WMM_QOS_INFO_AC_MAX_SP_FOUR   ((CsrWifiNmeWmmQosInfo) 0x40)
+#define CSR_WIFI_NME_WMM_QOS_INFO_AC_MAX_SP_SIX    ((CsrWifiNmeWmmQosInfo) 0x60)
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeEapMethodMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiNmeEapMethod.
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiNmeEapMethodMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeEncryptionMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiNmeEncryption
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiNmeEncryptionMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeIndicationsMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiNmeIndications
+
+*******************************************************************************/
+typedef CsrUint32 CsrWifiNmeIndicationsMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeNmeIndicationsMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiNmeNmeIndications.
+    Used to overlap the unused portion of the unifi_IndicationsMask For NME
+    specific indications
+
+*******************************************************************************/
+typedef CsrUint32 CsrWifiNmeNmeIndicationsMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWmmQosInfoMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiNmeWmmQosInfo
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiNmeWmmQosInfoMask;
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeEmpty
+
+  DESCRIPTION
+    Empty Structure to indicate that no credentials are available.
+
+  MEMBERS
+    empty  - Only element of the empty structure (always set to 0).
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8 empty;
+} CsrWifiNmeEmpty;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmePassphrase
+
+  DESCRIPTION
+    Structure holding the ASCII Pass Phrase data.
+
+  MEMBERS
+    encryptionMode - Encryption type as defined in CsrWifiSmeEncryption.
+    passphrase     - Pass phrase ASCII value.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint16      encryptionMode;
+    CsrCharString *passphrase;
+} CsrWifiNmePassphrase;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmePsk
+
+  DESCRIPTION
+    Structure holding the Pre-Shared Key data.
+
+  MEMBERS
+    encryptionMode - Encryption type as defined in CsrWifiSmeEncryption.
+    psk            - Pre-Shared Key value.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint16 encryptionMode;
+    CsrUint8  psk[32];
+} CsrWifiNmePsk;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWapiCredentials
+
+  DESCRIPTION
+    Structure holding WAPI credentials data.
+
+  MEMBERS
+    certificateLength   - Length in bytes of the following client certificate.
+    certificate         - The actual client certificate data (if present).
+                          DER/PEM format supported.
+    privateKeyLength    - Length in bytes of the following private key.
+    privateKey          - The actual private key. DER/PEM format.
+    caCertificateLength - Length in bytes of the following certificate authority
+                          certificate.
+    caCertificate       - The actual certificate authority certificate data. If
+                          not supplied the received certificate authority
+                          certificate is assumed to be validate, if present the
+                          received certificate is validated against it. DER/PEM
+                          format supported.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint32 certificateLength;
+    CsrUint8 *certificate;
+    CsrUint16 privateKeyLength;
+    CsrUint8 *privateKey;
+    CsrUint32 caCertificateLength;
+    CsrUint8 *caCertificate;
+} CsrWifiNmeWapiCredentials;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeConnectAttempt
+
+  DESCRIPTION
+    Structure holding Connection attempt data.
+
+  MEMBERS
+    bssid         - Id of Basic Service Set connections attempt have been made
+                    to.
+    status        - Status returned to indicate the success or otherwise of the
+                    connection attempt.
+    securityError - Security error status indicating the nature of the failure
+                    to connect.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiMacAddress  bssid;
+    CsrResult          status;
+    CsrWifiNmeSecError securityError;
+} CsrWifiNmeConnectAttempt;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeEapCredentials
+
+  DESCRIPTION
+    Supports the use of multiple EAP methods via a single structure. The
+    methods required are indicated by the value set in the eapMethodMask
+
+  MEMBERS
+    eapMethodMask
+                   - Bit mask of supported EAP methods
+                     Currently only supports the setting of one bit.
+                     Required for all the EAP methods.
+    authMode
+                   - Bit mask representing the authentication types that may be
+                     supported by a suitable AP. An AP must support at least one
+                     of the authentication types specified to be considered for
+                     connection. Required for all EAP methods.
+    encryptionMode
+                   - Bit mask representing the encryption types that may be
+                     supported by a suitable AP. An AP must support a suitable
+                     mix of the pairwise and group encryption types requested to
+                     be considered for connection. Required for all EAP methods.
+    userName
+                   - User name. Required for all EAP methods except: SIM or AKA.
+    userPassword
+                   - User Password. Required for all EAP methods except: TLS,
+                     SIM or AKA.
+    authServerUserIdentity
+                   - Authentication server user Identity. Required for all EAP
+                     methods except: TLS, SIM, AKA or FAST.
+    clientCertificateLength
+                   - Length in bytes of the following client certificate (if
+                     present). Only required for TLS.
+    clientCertificate
+                   - The actual client certificate data (if present). Only
+                     required for TLS. DER/PEM format supported.
+    certificateAuthorityCertificateLength
+                   - Length in bytes of the following certificate authority
+                     certificate (if present). Optional for TLS, TTLS, PEAP.
+    certificateAuthorityCertificate
+                   - The actual certificate authority certificate data (if
+                     present). If not supplied the received certificate
+                     authority certificate is assumed to be valid, if present
+                     the received certificate is validated against it. Optional
+                     for TLS, TTLS, PEAP. DER/PEM format supported.
+    privateKeyLength
+                   - Length in bytes of the following private key (if present).
+                     Only required for TLS.
+    privateKey
+                   - The actual private key (if present). Only required for TLS.
+                     DER/PEM format, maybe password protected.
+    privateKeyPassword
+                   - Optional password to protect the private key.
+    sessionLength
+                   - Length in bytes of the following session field Supported
+                     for all EAP methods except: SIM or AKA.
+    session
+                   - Session information to support faster re-authentication.
+                     Supported for all EAP methods except: SIM or AKA.
+    allowPacProvisioning
+                   - If TRUE: PAC provisioning is allowed 'over-the_air';
+                     If FALSE: a PAC must be supplied.
+                     Only required for FAST.
+    pacLength
+                   - Length the following PAC field. If allowPacProvisioning is
+                     FALSE then the PAC MUST be supplied (i.e. non-zero). Only
+                     required for FAST.
+    pac
+                   - The actual PAC data. If allowPacProvisioning is FALSE then
+                     the PAC MUST be supplied. Only required for FAST.
+    pacPassword
+                   - Optional password to protect the PAC. Only required for
+                     FAST.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiNmeEapMethodMask  eapMethodMask;
+    CsrWifiSmeAuthModeMask   authMode;
+    CsrWifiNmeEncryptionMask encryptionMode;
+    CsrCharString           *userName;
+    CsrCharString           *userPassword;
+    CsrCharString           *authServerUserIdentity;
+    CsrUint32                clientCertificateLength;
+    CsrUint8                *clientCertificate;
+    CsrUint32                certificateAuthorityCertificateLength;
+    CsrUint8                *certificateAuthorityCertificate;
+    CsrUint16                privateKeyLength;
+    CsrUint8                *privateKey;
+    CsrCharString           *privateKeyPassword;
+    CsrUint32                sessionLength;
+    CsrUint8                *session;
+    CsrBool                  allowPacProvisioning;
+    CsrUint32                pacLength;
+    CsrUint8                *pac;
+    CsrCharString           *pacPassword;
+} CsrWifiNmeEapCredentials;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmePeerConfig
+
+  DESCRIPTION
+    Structure holding Peer Config data.
+
+  MEMBERS
+    p2pDeviceId         -
+    groupCapabilityMask -
+    groupOwnerIntent    -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiMacAddress                p2pDeviceId;
+    CsrWifiSmeP2pGroupCapabilityMask groupCapabilityMask;
+    CsrUint8                         groupOwnerIntent;
+} CsrWifiNmePeerConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileIdentity
+
+  DESCRIPTION
+    The identity of a profile is defined as the unique combination the BSSID
+    and SSID.
+
+  MEMBERS
+    bssid  - ID of Basic Service Set for or the P2pDevice address of the GO for
+             which a connection attempt was made.
+    ssid   - Service Set Id.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiMacAddress bssid;
+    CsrWifiSsid       ssid;
+} CsrWifiNmeProfileIdentity;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWep128Keys
+
+  DESCRIPTION
+    Structure holding WEP Authentication Type and WEP keys that can be used
+    when using WEP128.
+
+  MEMBERS
+    wepAuthType    - Mask to select the WEP authentication type (Open or Shared)
+    selectedWepKey - Index to one of the four keys below indicating the
+                     currently used WEP key.
+    key1           - Value for key number 1.
+    key2           - Value for key number 2.
+    key3           - Value for key number 3.
+    key4           - Value for key number 4.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeAuthModeMask wepAuthType;
+    CsrUint8               selectedWepKey;
+    CsrUint8               key1[13];
+    CsrUint8               key2[13];
+    CsrUint8               key3[13];
+    CsrUint8               key4[13];
+} CsrWifiNmeWep128Keys;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWep64Keys
+
+  DESCRIPTION
+    Structure for holding WEP Authentication Type and WEP keys that can be
+    used when using WEP64.
+
+  MEMBERS
+    wepAuthType    - Mask to select the WEP authentication type (Open or Shared)
+    selectedWepKey - Index to one of the four keys below indicating the
+                     currently used WEP key.
+    key1           - Value for key number 1.
+    key2           - Value for key number 2.
+    key3           - Value for key number 3.
+    key4           - Value for key number 4.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeAuthModeMask wepAuthType;
+    CsrUint8               selectedWepKey;
+    CsrUint8               key1[5];
+    CsrUint8               key2[5];
+    CsrUint8               key3[5];
+    CsrUint8               key4[5];
+} CsrWifiNmeWep64Keys;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeCredentials
+
+  DESCRIPTION
+    Structure containing the Credentials data.
+
+  MEMBERS
+    credentialType            - Credential type value (as defined in the
+                                enumeration type).
+    credential                - Union containing credentials which depends on
+                                credentialType parameter.
+    credentialeap             -
+    credentialwapiPassphrase  -
+    credentialwpa2Passphrase  -
+    credentialwpa2Psk         -
+    credentialwapiPsk         -
+    credentialwpaPassphrase   -
+    credentialwapi            -
+    credentialwep128Key       -
+    credentialwpaPsk          -
+    credentialopenSystem      -
+    credentialwep64Key        -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiNmeCredentialType credentialType;
+    union {
+        CsrWifiNmeEapCredentials  eap;
+        CsrWifiNmePassphrase      wapiPassphrase;
+        CsrWifiNmePassphrase      wpa2Passphrase;
+        CsrWifiNmePsk             wpa2Psk;
+        CsrWifiNmePsk             wapiPsk;
+        CsrWifiNmePassphrase      wpaPassphrase;
+        CsrWifiNmeWapiCredentials wapi;
+        CsrWifiNmeWep128Keys      wep128Key;
+        CsrWifiNmePsk             wpaPsk;
+        CsrWifiNmeEmpty           openSystem;
+        CsrWifiNmeWep64Keys       wep64Key;
+    } credential;
+} CsrWifiNmeCredentials;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfile
+
+  DESCRIPTION
+    Structure containing the Profile data.
+
+  MEMBERS
+    profileIdentity - Profile Identity.
+    wmmQosInfoMask  - Mask for WMM QoS information.
+    bssType         - Type of BSS (Infrastructure or Adhoc).
+    channelNo       - Channel Number.
+    ccxOptionsMask  - Options mask for Cisco Compatible Extentions.
+    cloakedSsid     - Flag to decide whether the SSID is cloaked (not
+                      transmitted) or not.
+    credentials     - Credentials data.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiNmeProfileIdentity profileIdentity;
+    CsrWifiNmeWmmQosInfoMask  wmmQosInfoMask;
+    CsrWifiNmeBssType         bssType;
+    CsrUint8                  channelNo;
+    CsrUint8                  ccxOptionsMask;
+    CsrBool                   cloakedSsid;
+    CsrWifiNmeCredentials     credentials;
+} CsrWifiNmeProfile;
+
+
+/* Downstream */
+#define CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST            (0x0000)
+
+#define CSR_WIFI_NME_PROFILE_SET_REQ                      ((CsrWifiNmePrim) (0x0000 + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_PROFILE_DELETE_REQ                   ((CsrWifiNmePrim) (0x0001 + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_PROFILE_DELETE_ALL_REQ               ((CsrWifiNmePrim) (0x0002 + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_PROFILE_ORDER_SET_REQ                ((CsrWifiNmePrim) (0x0003 + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_PROFILE_CONNECT_REQ                  ((CsrWifiNmePrim) (0x0004 + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_WPS_REQ                              ((CsrWifiNmePrim) (0x0005 + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_WPS_CANCEL_REQ                       ((CsrWifiNmePrim) (0x0006 + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_CONNECTION_STATUS_GET_REQ            ((CsrWifiNmePrim) (0x0007 + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_SIM_IMSI_GET_RES                     ((CsrWifiNmePrim) (0x0008 + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_SIM_GSM_AUTH_RES                     ((CsrWifiNmePrim) (0x0009 + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_SIM_UMTS_AUTH_RES                    ((CsrWifiNmePrim) (0x000A + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_WPS_CONFIG_SET_REQ                   ((CsrWifiNmePrim) (0x000B + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_NME_EVENT_MASK_SET_REQ                   ((CsrWifiNmePrim) (0x000C + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST))
+
+
+#define CSR_WIFI_NME_PRIM_DOWNSTREAM_HIGHEST           (0x000C + CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST)
+
+/* Upstream */
+#define CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST              (0x0000 + CSR_PRIM_UPSTREAM)
+
+#define CSR_WIFI_NME_PROFILE_SET_CFM                      ((CsrWifiNmePrim)(0x0000 + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_PROFILE_DELETE_CFM                   ((CsrWifiNmePrim)(0x0001 + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_PROFILE_DELETE_ALL_CFM               ((CsrWifiNmePrim)(0x0002 + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_PROFILE_ORDER_SET_CFM                ((CsrWifiNmePrim)(0x0003 + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_PROFILE_CONNECT_CFM                  ((CsrWifiNmePrim)(0x0004 + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_WPS_CFM                              ((CsrWifiNmePrim)(0x0005 + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_WPS_CANCEL_CFM                       ((CsrWifiNmePrim)(0x0006 + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_CONNECTION_STATUS_GET_CFM            ((CsrWifiNmePrim)(0x0007 + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_PROFILE_UPDATE_IND                   ((CsrWifiNmePrim)(0x0008 + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_PROFILE_DISCONNECT_IND               ((CsrWifiNmePrim)(0x0009 + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_SIM_IMSI_GET_IND                     ((CsrWifiNmePrim)(0x000A + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_SIM_GSM_AUTH_IND                     ((CsrWifiNmePrim)(0x000B + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_SIM_UMTS_AUTH_IND                    ((CsrWifiNmePrim)(0x000C + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_WPS_CONFIG_SET_CFM                   ((CsrWifiNmePrim)(0x000D + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_NME_EVENT_MASK_SET_CFM                   ((CsrWifiNmePrim)(0x000E + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST))
+
+#define CSR_WIFI_NME_PRIM_UPSTREAM_HIGHEST             (0x000E + CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST)
+
+#define CSR_WIFI_NME_PRIM_DOWNSTREAM_COUNT             (CSR_WIFI_NME_PRIM_DOWNSTREAM_HIGHEST + 1 - CSR_WIFI_NME_PRIM_DOWNSTREAM_LOWEST)
+#define CSR_WIFI_NME_PRIM_UPSTREAM_COUNT               (CSR_WIFI_NME_PRIM_UPSTREAM_HIGHEST   + 1 - CSR_WIFI_NME_PRIM_UPSTREAM_LOWEST)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileSetReq
+
+  DESCRIPTION
+    Creates or updates an existing profile in the NME that matches the unique
+    identity of the profile. Each profile is identified by the combination of
+    BSSID and SSID. The profile contains all the required credentials for
+    attempting to connect to the network. Creating or updating a profile via
+    the NME PROFILE SET REQ does NOT add the profile to the preferred profile
+    list within the NME used for the NME auto-connect behaviour.
+
+  MEMBERS
+    common  - Common header for use with the CsrWifiFsm Module
+    profile - Specifies the identity and credentials of the network.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrWifiNmeProfile profile;
+} CsrWifiNmeProfileSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileDeleteReq
+
+  DESCRIPTION
+    Will delete the profile with a matching identity, but does NOT modify the
+    preferred profile list.
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    profileIdentity - Identity (BSSID, SSID) of profile to be deleted.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrWifiNmeProfileIdentity profileIdentity;
+} CsrWifiNmeProfileDeleteReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileDeleteAllReq
+
+  DESCRIPTION
+    Deletes all profiles present in the NME, but does NOT modify the
+    preferred profile list.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiNmeProfileDeleteAllReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileOrderSetReq
+
+  DESCRIPTION
+    Defines the preferred order that profiles present in the NME should be
+    used during the NME auto-connect behaviour.
+    If profileIdentitysCount == 0, it removes any existing preferred profile
+    list already present in the NME, effectively disabling the auto-connect
+    behaviour.
+    NOTE: Profile identities that do not match any profile stored in the NME
+    are ignored during the auto-connect procedure.
+    NOTE: during auto-connect the NME will only attempt to join an existing
+    adhoc network and it will never attempt to host an adhoc network; for
+    hosting and adhoc network, use CSR_WIFI_NME_PROFILE_CONNECT_REQ
+
+  MEMBERS
+    common                - Common header for use with the CsrWifiFsm Module
+    interfaceTag          - Interface Identifier; unique identifier of an
+                            interface
+    profileIdentitysCount - The number of profiles identities in the list.
+    profileIdentitys      - Points to the list of profile identities.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent            common;
+    CsrUint16                  interfaceTag;
+    CsrUint8                   profileIdentitysCount;
+    CsrWifiNmeProfileIdentity *profileIdentitys;
+} CsrWifiNmeProfileOrderSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileConnectReq
+
+  DESCRIPTION
+    Requests the NME to attempt to connect to the specified profile.
+    Overrides any current connection attempt.
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    profileIdentity - Identity (BSSID, SSID) of profile to be connected to.
+                      It must match an existing profile in the NME.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrWifiNmeProfileIdentity profileIdentity;
+} CsrWifiNmeProfileConnectReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsReq
+
+  DESCRIPTION
+    Requests the NME to look for WPS enabled APs and attempt to perform WPS
+    to determine the appropriate security credentials to connect to the AP.
+    If the PIN == '00000000' then 'push button mode' is indicated, otherwise
+    the PIN has to match that of the AP. 4 digit pin is passed by sending the
+    pin digits in pin[0]..pin[3] and rest of the contents filled with '-'.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    pin          - PIN value.
+    ssid         - Service Set identifier
+    bssid        - ID of Basic Service Set for which a WPS connection attempt is
+                   being made.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrUint16         interfaceTag;
+    CsrUint8          pin[8];
+    CsrWifiSsid       ssid;
+    CsrWifiMacAddress bssid;
+} CsrWifiNmeWpsReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsCancelReq
+
+  DESCRIPTION
+    Requests the NME to cancel any WPS procedure that it is currently
+    performing. This includes WPS registrar activities started because of
+    CSR_WIFI_NME_AP_REGISTER.request
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiNmeWpsCancelReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeConnectionStatusGetReq
+
+  DESCRIPTION
+    Requests the current connection status of the NME.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiNmeConnectionStatusGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimImsiGetRes
+
+  DESCRIPTION
+    Response from the application that received the NME SIM IMSI GET IND.
+
+  MEMBERS
+    common   - Common header for use with the CsrWifiFsm Module
+    status   - Indicates the outcome of the requested operation: STATUS_SUCCESS
+               or STATUS_ERROR.
+    imsi     - The value of the IMSI obtained from the UICC.
+    cardType - The UICC type (GSM only (SIM), UMTS only (USIM), Both).
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrResult             status;
+    CsrCharString        *imsi;
+    CsrWifiNmeSimCardType cardType;
+} CsrWifiNmeSimImsiGetRes;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimGsmAuthRes
+
+  DESCRIPTION
+    Response from the application that received the NME SIM GSM AUTH IND. For
+    each GSM authentication round a GSM Ciphering key (Kc) and a signed
+    response (SRES) are produced. Since 2 or 3 GSM authentication rounds are
+    used the 2 or 3 Kc's obtained respectively are combined into one buffer
+    and similarly the 2 or 3 SRES's obtained are combined into another
+    buffer. The order of Kc values (SRES values respectively) in their buffer
+    is the same as that of their corresponding RAND values in the incoming
+    indication.
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    status     - Indicates the outcome of the requested operation:
+                 STATUS_SUCCESS or STATUS_ERROR
+    kcsLength  - Length in Bytes of Kc buffer. Legal values are: 16 or 24.
+    kcs        - Kc buffer holding 2 or 3 Kc values.
+    sresLength - Length in Bytes of SRES buffer. Legal values are: 8 or 12.
+    sres       - SRES buffer holding 2 or 3 SRES values.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+    CsrUint8        kcsLength;
+    CsrUint8       *kcs;
+    CsrUint8        sresLength;
+    CsrUint8       *sres;
+} CsrWifiNmeSimGsmAuthRes;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimUmtsAuthRes
+
+  DESCRIPTION
+    Response from the application that received the NME SIM UMTS AUTH IND.
+    The values of umtsCipherKey, umtsIntegrityKey, resParameterLength and
+    resParameter are only meanigful when result = UMTS_AUTH_RESULT_SUCCESS.
+    The value of auts is only meaningful when
+    result=UMTS_AUTH_RESULT_SYNC_FAIL.
+
+  MEMBERS
+    common             - Common header for use with the CsrWifiFsm Module
+    status             - Indicates the outcome of the requested operation:
+                         STATUS_SUCCESS or STATUS_ERROR.
+    result             - The result of UMTS authentication as performed by the
+                         UICC which could be: Success, Authentication Reject or
+                         Synchronisation Failure. For all these 3 outcomes the
+                         value of status is success.
+    umtsCipherKey      - The UMTS Cipher Key as calculated and returned by the
+                         UICC.
+    umtsIntegrityKey   - The UMTS Integrity Key as calculated and returned by
+                         the UICC.
+    resParameterLength - The length (in bytes) of the RES parameter (min=4; max
+                         = 16).
+    resParameter       - The RES parameter as calculated and returned by the
+                         UICC.
+    auts               - The AUTS parameter as calculated and returned by the
+                         UICC.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent          common;
+    CsrResult                status;
+    CsrWifiNmeUmtsAuthResult result;
+    CsrUint8                 umtsCipherKey[16];
+    CsrUint8                 umtsIntegrityKey[16];
+    CsrUint8                 resParameterLength;
+    CsrUint8                *resParameter;
+    CsrUint8                 auts[14];
+} CsrWifiNmeSimUmtsAuthRes;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsConfigSetReq
+
+  DESCRIPTION
+    This primitive passes the WPS information for the device to NME. This may
+    be accepted only if no interface is active.
+
+  MEMBERS
+    common    - Common header for use with the CsrWifiFsm Module
+    wpsConfig - WPS config.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent     common;
+    CsrWifiSmeWpsConfig wpsConfig;
+} CsrWifiNmeWpsConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeEventMaskSetReq
+
+  DESCRIPTION
+    The wireless manager application may register with the NME to receive
+    notification of interesting events. Indications will be sent only if the
+    wireless manager explicitly registers to be notified of that event.
+    indMask is a bit mask of values defined in CsrWifiNmeIndicationsMask.
+
+  MEMBERS
+    common  - Common header for use with the CsrWifiFsm Module
+    indMask - Set mask with values from CsrWifiNmeIndications
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrWifiNmeIndicationsMask indMask;
+} CsrWifiNmeEventMaskSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileSetCfm
+
+  DESCRIPTION
+    Reports the status of the NME PROFILE SET REQ; the request will only fail
+    if the details specified in the profile contains an invalid combination
+    of parameters for example specifying the profile as cloaked but not
+    specifying the SSID. The NME doesn't limit the number of profiles that
+    may be created. The NME assumes that the entity configuring it is aware
+    of the appropriate limits.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Indicates the success or otherwise of the requested operation.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiNmeProfileSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileDeleteCfm
+
+  DESCRIPTION
+    Reports the status of the CSR_WIFI_NME_PROFILE_DELETE_REQ.
+    Returns CSR_WIFI_NME_STATUS_NOT_FOUND if there is no matching profile.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Indicates the success or otherwise of the requested operation.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiNmeProfileDeleteCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileDeleteAllCfm
+
+  DESCRIPTION
+    Reports the status of the CSR_WIFI_NME_PROFILE_DELETE_ALL_REQ.
+    Returns always CSR_WIFI_NME_STATUS_SUCCESS.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Indicates the success or otherwise of the requested operation, but
+             in this case it always set to success.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiNmeProfileDeleteAllCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileOrderSetCfm
+
+  DESCRIPTION
+    Confirmation to UNIFI_NME_PROFILE_ORDER_SET.request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Indicates the success or otherwise of the requested
+                   operation.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiNmeProfileOrderSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileConnectCfm
+
+  DESCRIPTION
+    Reports the status of the NME PROFILE CONNECT REQ. If unsuccessful the
+    connectAttempt parameters contain details of the APs that the NME
+    attempted to connect to before reporting the failure of the request.
+
+  MEMBERS
+    common               - Common header for use with the CsrWifiFsm Module
+    interfaceTag         - Interface Identifier; unique identifier of an
+                           interface
+    status               - Indicates the success or otherwise of the requested
+                           operation.
+    connectAttemptsCount - This parameter is relevant only if
+                           status!=CSR_WIFI_NME_STATUS_SUCCESS.
+                           Number of connection attempt elements provided with
+                           this primitive
+    connectAttempts      - This parameter is relevant only if
+                           status!=CSR_WIFI_NME_STATUS_SUCCESS.
+                           Points to the list of connection attempt elements
+                           provided with this primitive
+                           Each element of the list provides information about
+                           an AP on which the connection attempt was made and
+                           the error that occurred during the attempt.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrResult                 status;
+    CsrUint8                  connectAttemptsCount;
+    CsrWifiNmeConnectAttempt *connectAttempts;
+} CsrWifiNmeProfileConnectCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsCfm
+
+  DESCRIPTION
+    Reports the status of the NME WPS REQ.
+    If CSR_WIFI_NME_STATUS_SUCCESS, the profile parameter contains the
+    identity and credentials of the AP.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Indicates the success or otherwise of the requested
+                   operation.
+    profile      - This parameter is relevant only if
+                   status==CSR_WIFI_NME_STATUS_SUCCESS.
+                   The identity and credentials of the network.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrUint16         interfaceTag;
+    CsrResult         status;
+    CsrWifiNmeProfile profile;
+} CsrWifiNmeWpsCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsCancelCfm
+
+  DESCRIPTION
+    Reports the status of the NME WPS REQ, the request is always SUCCESSFUL.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Only returns CSR_WIFI_NME_STATUS_SUCCESS
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiNmeWpsCancelCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeConnectionStatusGetCfm
+
+  DESCRIPTION
+    Reports the connection status of the NME.
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    interfaceTag     - Interface Identifier; unique identifier of an interface
+    status           - Indicates the success or otherwise of the requested
+                       operation.
+    connectionStatus - NME current connection status
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent            common;
+    CsrUint16                  interfaceTag;
+    CsrResult                  status;
+    CsrWifiNmeConnectionStatus connectionStatus;
+} CsrWifiNmeConnectionStatusGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileUpdateInd
+
+  DESCRIPTION
+    Indication generated from the NME (if an application subscribes to
+    receive it) that informs that application that the contained profile has
+    changed.
+    For example, either the credentials EAP-FAST PAC file or the session data
+    within the profile has changed.
+    It is up to the application whether it stores this updated profile or
+    not.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    profile      - The identity and credentials of the network.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrUint16         interfaceTag;
+    CsrWifiNmeProfile profile;
+} CsrWifiNmeProfileUpdateInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeProfileDisconnectInd
+
+  DESCRIPTION
+    Indication generated from the NME (if an application subscribes to
+    receive it) that informs that application that the current profile
+    connection has disconnected. The indication will contain information
+    about APs that it attempted to maintain the connection via i.e. in the
+    case of failed roaming.
+
+  MEMBERS
+    common               - Common header for use with the CsrWifiFsm Module
+    interfaceTag         - Interface Identifier; unique identifier of an
+                           interface
+    connectAttemptsCount - Number of connection attempt elements provided with
+                           this primitive
+    connectAttempts      - Points to the list of connection attempt elements
+                           provided with this primitive
+                           Each element of the list provides information about
+                           an AP on which the connection attempt was made and
+                           the error occurred during the attempt.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrUint8                  connectAttemptsCount;
+    CsrWifiNmeConnectAttempt *connectAttempts;
+} CsrWifiNmeProfileDisconnectInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimImsiGetInd
+
+  DESCRIPTION
+    Indication generated from the NME (if an application subscribes to
+    receive it) that requests the IMSI and UICC type from the UICC Manager.
+    This indication is generated when the NME is attempting to connect to a
+    profile configured for EAP-SIM/AKA. An application MUST register to
+    receive this indication for the NME to support the EAP-SIM/AKA credential
+    types. Otherwise the NME has no route to obtain the information from the
+    UICC.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiNmeSimImsiGetInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimGsmAuthInd
+
+  DESCRIPTION
+    Indication generated from the NME (if an application subscribes to
+    receive it) that requests the UICC Manager to perform a GSM
+    authentication on behalf of the NME. This indication is generated when
+    the NME is attempting to connect to a profile configured for EAP-SIM. An
+    application MUST register to receive this indication for the NME to
+    support the EAP-SIM credential types. Otherwise the NME has no route to
+    obtain the information from the UICC. EAP-SIM authentication requires 2
+    or 3 GSM authentication rounds and therefore 2 or 3 RANDS (GSM Random
+    Challenges) are included.
+
+  MEMBERS
+    common      - Common header for use with the CsrWifiFsm Module
+    randsLength - GSM RAND is 16 bytes long hence valid values are 32 (2 RANDS)
+                  or 48 (3 RANDs).
+    rands       - 2 or 3 RANDs values.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint8        randsLength;
+    CsrUint8       *rands;
+} CsrWifiNmeSimGsmAuthInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeSimUmtsAuthInd
+
+  DESCRIPTION
+    Indication generated from the NME (if an application subscribes to
+    receive it) that requests the UICC Manager to perform a UMTS
+    authentication on behalf of the NME. This indication is generated when
+    the NME is attempting to connect to a profile configured for EAP-AKA. An
+    application MUST register to receive this indication for the NME to
+    support the EAP-AKA credential types. Otherwise the NME has no route to
+    obtain the information from the USIM. EAP-AKA requires one UMTS
+    authentication round and therefore only one RAND and one AUTN values are
+    included.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    rand   - UMTS RAND value.
+    autn   - UMTS AUTN value.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint8        rand[16];
+    CsrUint8        autn[16];
+} CsrWifiNmeSimUmtsAuthInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeWpsConfigSetCfm
+
+  DESCRIPTION
+    Confirm.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Status of the request.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiNmeWpsConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiNmeEventMaskSetCfm
+
+  DESCRIPTION
+    The NME calls the primitive to report the result of the request
+    primitive.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiNmeEventMaskSetCfm;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_NME_PRIM_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_nme_serialize.h b/drivers/staging/csr/csr_wifi_nme_serialize.h
new file mode 100644
index 0000000..aeca9c8
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_serialize.h
@@ -0,0 +1,177 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_NME_SERIALIZE_H__
+#define CSR_WIFI_NME_SERIALIZE_H__
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_wifi_msgconv.h"
+
+#include "csr_wifi_nme_prim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_NME_ENABLE
+#error CSR_WIFI_NME_ENABLE MUST be defined inorder to use csr_wifi_nme_serialize.h
+#endif
+
+extern void CsrWifiNmePfree(void *ptr);
+
+extern CsrUint8* CsrWifiNmeProfileSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeProfileSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeProfileSetReqSizeof(void *msg);
+extern void CsrWifiNmeProfileSetReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiNmeProfileDeleteReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeProfileDeleteReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeProfileDeleteReqSizeof(void *msg);
+#define CsrWifiNmeProfileDeleteReqSerFree CsrWifiNmePfree
+
+#define CsrWifiNmeProfileDeleteAllReqSer CsrWifiEventSer
+#define CsrWifiNmeProfileDeleteAllReqDes CsrWifiEventDes
+#define CsrWifiNmeProfileDeleteAllReqSizeof CsrWifiEventSizeof
+#define CsrWifiNmeProfileDeleteAllReqSerFree CsrWifiNmePfree
+
+extern CsrUint8* CsrWifiNmeProfileOrderSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeProfileOrderSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeProfileOrderSetReqSizeof(void *msg);
+extern void CsrWifiNmeProfileOrderSetReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiNmeProfileConnectReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeProfileConnectReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeProfileConnectReqSizeof(void *msg);
+#define CsrWifiNmeProfileConnectReqSerFree CsrWifiNmePfree
+
+extern CsrUint8* CsrWifiNmeWpsReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeWpsReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeWpsReqSizeof(void *msg);
+#define CsrWifiNmeWpsReqSerFree CsrWifiNmePfree
+
+#define CsrWifiNmeWpsCancelReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiNmeWpsCancelReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiNmeWpsCancelReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiNmeWpsCancelReqSerFree CsrWifiNmePfree
+
+#define CsrWifiNmeConnectionStatusGetReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiNmeConnectionStatusGetReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiNmeConnectionStatusGetReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiNmeConnectionStatusGetReqSerFree CsrWifiNmePfree
+
+extern CsrUint8* CsrWifiNmeSimImsiGetResSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeSimImsiGetResDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeSimImsiGetResSizeof(void *msg);
+extern void CsrWifiNmeSimImsiGetResSerFree(void *msg);
+
+extern CsrUint8* CsrWifiNmeSimGsmAuthResSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeSimGsmAuthResDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeSimGsmAuthResSizeof(void *msg);
+extern void CsrWifiNmeSimGsmAuthResSerFree(void *msg);
+
+extern CsrUint8* CsrWifiNmeSimUmtsAuthResSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeSimUmtsAuthResDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeSimUmtsAuthResSizeof(void *msg);
+extern void CsrWifiNmeSimUmtsAuthResSerFree(void *msg);
+
+extern CsrUint8* CsrWifiNmeWpsConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeWpsConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeWpsConfigSetReqSizeof(void *msg);
+extern void CsrWifiNmeWpsConfigSetReqSerFree(void *msg);
+
+#define CsrWifiNmeEventMaskSetReqSer CsrWifiEventCsrUint32Ser
+#define CsrWifiNmeEventMaskSetReqDes CsrWifiEventCsrUint32Des
+#define CsrWifiNmeEventMaskSetReqSizeof CsrWifiEventCsrUint32Sizeof
+#define CsrWifiNmeEventMaskSetReqSerFree CsrWifiNmePfree
+
+#define CsrWifiNmeProfileSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiNmeProfileSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiNmeProfileSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiNmeProfileSetCfmSerFree CsrWifiNmePfree
+
+#define CsrWifiNmeProfileDeleteCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiNmeProfileDeleteCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiNmeProfileDeleteCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiNmeProfileDeleteCfmSerFree CsrWifiNmePfree
+
+#define CsrWifiNmeProfileDeleteAllCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiNmeProfileDeleteAllCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiNmeProfileDeleteAllCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiNmeProfileDeleteAllCfmSerFree CsrWifiNmePfree
+
+extern CsrUint8* CsrWifiNmeProfileOrderSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeProfileOrderSetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeProfileOrderSetCfmSizeof(void *msg);
+#define CsrWifiNmeProfileOrderSetCfmSerFree CsrWifiNmePfree
+
+extern CsrUint8* CsrWifiNmeProfileConnectCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeProfileConnectCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeProfileConnectCfmSizeof(void *msg);
+extern void CsrWifiNmeProfileConnectCfmSerFree(void *msg);
+
+extern CsrUint8* CsrWifiNmeWpsCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeWpsCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeWpsCfmSizeof(void *msg);
+extern void CsrWifiNmeWpsCfmSerFree(void *msg);
+
+extern CsrUint8* CsrWifiNmeWpsCancelCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeWpsCancelCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeWpsCancelCfmSizeof(void *msg);
+#define CsrWifiNmeWpsCancelCfmSerFree CsrWifiNmePfree
+
+extern CsrUint8* CsrWifiNmeConnectionStatusGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeConnectionStatusGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeConnectionStatusGetCfmSizeof(void *msg);
+#define CsrWifiNmeConnectionStatusGetCfmSerFree CsrWifiNmePfree
+
+extern CsrUint8* CsrWifiNmeProfileUpdateIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeProfileUpdateIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeProfileUpdateIndSizeof(void *msg);
+extern void CsrWifiNmeProfileUpdateIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiNmeProfileDisconnectIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeProfileDisconnectIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeProfileDisconnectIndSizeof(void *msg);
+extern void CsrWifiNmeProfileDisconnectIndSerFree(void *msg);
+
+#define CsrWifiNmeSimImsiGetIndSer CsrWifiEventSer
+#define CsrWifiNmeSimImsiGetIndDes CsrWifiEventDes
+#define CsrWifiNmeSimImsiGetIndSizeof CsrWifiEventSizeof
+#define CsrWifiNmeSimImsiGetIndSerFree CsrWifiNmePfree
+
+extern CsrUint8* CsrWifiNmeSimGsmAuthIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeSimGsmAuthIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeSimGsmAuthIndSizeof(void *msg);
+extern void CsrWifiNmeSimGsmAuthIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiNmeSimUmtsAuthIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiNmeSimUmtsAuthIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiNmeSimUmtsAuthIndSizeof(void *msg);
+#define CsrWifiNmeSimUmtsAuthIndSerFree CsrWifiNmePfree
+
+#define CsrWifiNmeWpsConfigSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiNmeWpsConfigSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiNmeWpsConfigSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiNmeWpsConfigSetCfmSerFree CsrWifiNmePfree
+
+#define CsrWifiNmeEventMaskSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiNmeEventMaskSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiNmeEventMaskSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiNmeEventMaskSetCfmSerFree CsrWifiNmePfree
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* CSR_WIFI_NME_SERIALIZE_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_nme_task.h b/drivers/staging/csr/csr_wifi_nme_task.h
new file mode 100644
index 0000000..2a03a19
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_nme_task.h
@@ -0,0 +1,38 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_NME_TASK_H__
+#define CSR_WIFI_NME_TASK_H__
+
+#include "csr_types.h"
+#include "csr_sched.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_NME_ENABLE
+#error CSR_WIFI_NME_ENABLE MUST be defined inorder to use csr_wifi_nme_task.h
+#endif
+
+#define CSR_WIFI_NME_LOG_ID 0x1203FFFF
+extern CsrSchedQid CSR_WIFI_NME_IFACEQUEUE;
+void CsrWifiNmeInit(void **gash);
+void CsrWifiNmeDeinit(void **gash);
+void CsrWifiNmeHandler(void **gash);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_NME_TASK_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_private_common.h b/drivers/staging/csr/csr_wifi_private_common.h
new file mode 100644
index 0000000..b1d1239
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_private_common.h
@@ -0,0 +1,91 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifndef CSR_WIFI_PRIVATE_COMMON_H__
+#define CSR_WIFI_PRIVATE_COMMON_H__
+
+#include "csr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief maximum number of STAs allowed to be connected
+ *
+ * @par Description
+ *   min & max Beacon Interval
+ */
+#define CSR_WIFI_AP_MAX_ASSOC_STA   8
+
+/** Number of only b rates */
+#define CSR_WIFI_SME_AP_MAX_ONLY_B_RATES        4
+
+
+/** Number of mandatory b rates */
+#define CSR_WIFI_SME_AP_MAX_MANDATORY_B_RATES   2
+
+
+/** Number of mandatory bg rates */
+#define CSR_WIFI_SME_AP_MAX_MANDATORY_BG_RATES  4
+
+
+/** Number of bg rates */
+#define CSR_WIFI_SME_AP_MAX_BG_RATES            12
+
+
+/** Number of no b only g rates */
+#define CSR_WIFI_SME_AP_MAX_NO_B_ONLY_G_RATES   8
+
+
+/** Number of mandatory g rates */
+#define CSR_WIFI_SME_AP_MAX_MANDATORY_G_RATES   7
+
+
+/* Number of g mandatory rates */
+#define CSR_WIFI_SME_AP_G_MANDATORY_RATES_NUM   7
+
+
+/* Number of b mandatory rates */
+#define CSR_WIFI_SME_AP_B_MANDATORY_RATES_NUM   2
+
+
+/* Number of b/g mandatory rates */
+#define CSR_WIFI_SME_AP_BG_MANDATORY_RATES_NUM   4
+
+
+/* The maximum allowed length of SSID */
+#define CSR_WIFI_SME_AP_SSID_MAX_LENGTH         32
+
+/* Refer 8.4.2.27 RSN element - we support TKIP, WPA2, WAPI and PSK only, no pmkid, group cipher suite */
+#define CSR_WIFI_SME_RSN_PACKED_SIZE (1 + 1 + 2 + 4 + 2 + 4 * 2 + 2 + 4 * 1 + 2 + 24)
+
+/* Refer 7.3.2.9 (ISO/IEC 8802-11:2006) WAPI element - we support WAPI PSK only, no bkid, group cipher suite */
+#define CSR_WIFI_SME_WAPI_PACKED_SIZE (1 + 1 + 2 + 2 + 4 * 1 + 2 + 4 * 1 + 4 + 2 + 24)
+
+
+/* Common structure for NME and SME to maintain Interface mode*/
+typedef CsrUint8 CsrWifiInterfaceMode;
+#define  CSR_WIFI_MODE_NONE                             ((CsrWifiInterfaceMode) 0xFF)
+#define  CSR_WIFI_MODE_STA                              ((CsrWifiInterfaceMode) 0x00)
+#define  CSR_WIFI_MODE_AP                               ((CsrWifiInterfaceMode) 0x01)
+#define  CSR_WIFI_MODE_P2P_DEVICE                       ((CsrWifiInterfaceMode) 0x02)
+#define  CSR_WIFI_MODE_P2P_CLI                          ((CsrWifiInterfaceMode) 0x03)
+#define  CSR_WIFI_MODE_P2P_GO                           ((CsrWifiInterfaceMode) 0x04)
+#define  CSR_WIFI_MODE_AMP                              ((CsrWifiInterfaceMode) 0x05)
+#define  CSR_WIFI_MODE_WPS_ENROLLEE                     ((CsrWifiInterfaceMode) 0x06)
+#define  CSR_WIFI_MODE_IBSS                             ((CsrWifiInterfaceMode) 0x07)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/drivers/staging/csr/csr_wifi_result.h b/drivers/staging/csr/csr_wifi_result.h
new file mode 100644
index 0000000..95b73a0
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_result.h
@@ -0,0 +1,36 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifndef CSR_WIFI_RESULT_H__
+#define CSR_WIFI_RESULT_H__
+
+#include "csr_types.h"
+#include "csr_result.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* THIS FILE SHOULD CONTAIN ONLY RESULT CODES */
+
+/* Result Codes */
+#define CSR_WIFI_HIP_RESULT_INVALID_VALUE    ((CsrResult) 1) /* Invalid argument value */
+#define CSR_WIFI_HIP_RESULT_NO_DEVICE        ((CsrResult) 2) /* The specified device is no longer present */
+#define CSR_WIFI_HIP_RESULT_NO_SPACE         ((CsrResult) 3) /* A queue or buffer is full */
+#define CSR_WIFI_HIP_RESULT_NO_MEMORY        ((CsrResult) 4) /* Fatal error, no memory */
+#define CSR_WIFI_HIP_RESULT_RANGE            ((CsrResult) 5) /* Request exceeds the range of a file or a buffer */
+#define CSR_WIFI_HIP_RESULT_NOT_FOUND        ((CsrResult) 6) /* A file (typically a f/w patch) is not found */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_RESULT_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_router_converter_init.c b/drivers/staging/csr/csr_wifi_router_converter_init.c
new file mode 100644
index 0000000..6ff59c0
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_converter_init.c
@@ -0,0 +1,83 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_msgconv.h"
+#include "csr_pmem.h"
+#include "csr_util.h"
+
+
+#ifdef CSR_LOG_ENABLE
+#include "csr_log.h"
+#endif
+
+#ifndef EXCLUDE_CSR_WIFI_ROUTER_MODULE
+#include "csr_wifi_router_serialize.h"
+#include "csr_wifi_router_prim.h"
+
+static CsrMsgConvMsgEntry csrwifirouter_conv_lut[] = {
+    { CSR_WIFI_ROUTER_MA_PACKET_SUBSCRIBE_REQ, CsrWifiRouterMaPacketSubscribeReqSizeof, CsrWifiRouterMaPacketSubscribeReqSer, CsrWifiRouterMaPacketSubscribeReqDes, CsrWifiRouterMaPacketSubscribeReqSerFree },
+    { CSR_WIFI_ROUTER_MA_PACKET_UNSUBSCRIBE_REQ, CsrWifiRouterMaPacketUnsubscribeReqSizeof, CsrWifiRouterMaPacketUnsubscribeReqSer, CsrWifiRouterMaPacketUnsubscribeReqDes, CsrWifiRouterMaPacketUnsubscribeReqSerFree },
+    { CSR_WIFI_ROUTER_MA_PACKET_REQ, CsrWifiRouterMaPacketReqSizeof, CsrWifiRouterMaPacketReqSer, CsrWifiRouterMaPacketReqDes, CsrWifiRouterMaPacketReqSerFree },
+    { CSR_WIFI_ROUTER_MA_PACKET_RES, CsrWifiRouterMaPacketResSizeof, CsrWifiRouterMaPacketResSer, CsrWifiRouterMaPacketResDes, CsrWifiRouterMaPacketResSerFree },
+    { CSR_WIFI_ROUTER_MA_PACKET_CANCEL_REQ, CsrWifiRouterMaPacketCancelReqSizeof, CsrWifiRouterMaPacketCancelReqSer, CsrWifiRouterMaPacketCancelReqDes, CsrWifiRouterMaPacketCancelReqSerFree },
+    { CSR_WIFI_ROUTER_MA_PACKET_SUBSCRIBE_CFM, CsrWifiRouterMaPacketSubscribeCfmSizeof, CsrWifiRouterMaPacketSubscribeCfmSer, CsrWifiRouterMaPacketSubscribeCfmDes, CsrWifiRouterMaPacketSubscribeCfmSerFree },
+    { CSR_WIFI_ROUTER_MA_PACKET_UNSUBSCRIBE_CFM, CsrWifiRouterMaPacketUnsubscribeCfmSizeof, CsrWifiRouterMaPacketUnsubscribeCfmSer, CsrWifiRouterMaPacketUnsubscribeCfmDes, CsrWifiRouterMaPacketUnsubscribeCfmSerFree },
+    { CSR_WIFI_ROUTER_MA_PACKET_CFM, CsrWifiRouterMaPacketCfmSizeof, CsrWifiRouterMaPacketCfmSer, CsrWifiRouterMaPacketCfmDes, CsrWifiRouterMaPacketCfmSerFree },
+    { CSR_WIFI_ROUTER_MA_PACKET_IND, CsrWifiRouterMaPacketIndSizeof, CsrWifiRouterMaPacketIndSer, CsrWifiRouterMaPacketIndDes, CsrWifiRouterMaPacketIndSerFree },
+
+    { 0, NULL, NULL, NULL, NULL },
+};
+
+CsrMsgConvMsgEntry* CsrWifiRouterConverterLookup(CsrMsgConvMsgEntry *ce, CsrUint16 msgType)
+{
+    if (msgType & CSR_PRIM_UPSTREAM)
+    {
+        CsrUint16 idx = (msgType & ~CSR_PRIM_UPSTREAM) + CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_COUNT;
+        if (idx < (CSR_WIFI_ROUTER_PRIM_UPSTREAM_COUNT + CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_COUNT) &&
+            csrwifirouter_conv_lut[idx].msgType == msgType)
+        {
+            return &csrwifirouter_conv_lut[idx];
+        }
+    }
+    else
+    {
+        if (msgType < CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_COUNT &&
+            csrwifirouter_conv_lut[msgType].msgType == msgType)
+        {
+            return &csrwifirouter_conv_lut[msgType];
+        }
+    }
+    return NULL;
+}
+
+
+void CsrWifiRouterConverterInit(void)
+{
+    CsrMsgConvInsert(CSR_WIFI_ROUTER_PRIM, csrwifirouter_conv_lut);
+    CsrMsgConvCustomLookupRegister(CSR_WIFI_ROUTER_PRIM, CsrWifiRouterConverterLookup);
+}
+
+
+#ifdef CSR_LOG_ENABLE
+static const CsrLogPrimitiveInformation csrwifirouter_conv_info = {
+    CSR_WIFI_ROUTER_PRIM,
+    (CsrCharString *)"CSR_WIFI_ROUTER_PRIM",
+    csrwifirouter_conv_lut
+};
+const CsrLogPrimitiveInformation* CsrWifiRouterTechInfoGet(void)
+{
+    return &csrwifirouter_conv_info;
+}
+
+
+#endif /* CSR_LOG_ENABLE */
+#endif /* EXCLUDE_CSR_WIFI_ROUTER_MODULE */
diff --git a/drivers/staging/csr/csr_wifi_router_converter_init.h b/drivers/staging/csr/csr_wifi_router_converter_init.h
new file mode 100644
index 0000000..2a293e4
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_converter_init.h
@@ -0,0 +1,42 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_ROUTER_CONVERTER_INIT_H__
+#define CSR_WIFI_ROUTER_CONVERTER_INIT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef EXCLUDE_CSR_WIFI_ROUTER_MODULE
+
+#include "csr_msgconv.h"
+
+#ifdef CSR_LOG_ENABLE
+#include "csr_log.h"
+
+extern const CsrLogPrimitiveInformation* CsrWifiRouterTechInfoGet(void);
+#endif /* CSR_LOG_ENABLE */
+
+extern void CsrWifiRouterConverterInit(void);
+
+#else /* EXCLUDE_CSR_WIFI_ROUTER_MODULE */
+
+#define CsrWifiRouterConverterInit()
+
+#endif /* EXCLUDE_CSR_WIFI_ROUTER_MODULE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_ROUTER_CONVERTER_INIT_H__ */
diff --git a/drivers/staging/csr/csr_wifi_router_ctrl_converter_init.c b/drivers/staging/csr/csr_wifi_router_ctrl_converter_init.c
new file mode 100644
index 0000000..32d0bb6
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_ctrl_converter_init.c
@@ -0,0 +1,136 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_msgconv.h"
+#include "csr_pmem.h"
+#include "csr_util.h"
+
+
+#ifdef CSR_LOG_ENABLE
+#include "csr_log.h"
+#endif
+
+#ifndef EXCLUDE_CSR_WIFI_ROUTER_CTRL_MODULE
+#include "csr_wifi_router_ctrl_serialize.h"
+#include "csr_wifi_router_ctrl_prim.h"
+
+static CsrMsgConvMsgEntry csrwifirouterctrl_conv_lut[] = {
+    { CSR_WIFI_ROUTER_CTRL_CONFIGURE_POWER_MODE_REQ, CsrWifiRouterCtrlConfigurePowerModeReqSizeof, CsrWifiRouterCtrlConfigurePowerModeReqSer, CsrWifiRouterCtrlConfigurePowerModeReqDes, CsrWifiRouterCtrlConfigurePowerModeReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_HIP_REQ, CsrWifiRouterCtrlHipReqSizeof, CsrWifiRouterCtrlHipReqSer, CsrWifiRouterCtrlHipReqDes, CsrWifiRouterCtrlHipReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_MEDIA_STATUS_REQ, CsrWifiRouterCtrlMediaStatusReqSizeof, CsrWifiRouterCtrlMediaStatusReqSer, CsrWifiRouterCtrlMediaStatusReqDes, CsrWifiRouterCtrlMediaStatusReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_MULTICAST_ADDRESS_RES, CsrWifiRouterCtrlMulticastAddressResSizeof, CsrWifiRouterCtrlMulticastAddressResSer, CsrWifiRouterCtrlMulticastAddressResDes, CsrWifiRouterCtrlMulticastAddressResSerFree },
+    { CSR_WIFI_ROUTER_CTRL_PORT_CONFIGURE_REQ, CsrWifiRouterCtrlPortConfigureReqSizeof, CsrWifiRouterCtrlPortConfigureReqSer, CsrWifiRouterCtrlPortConfigureReqDes, CsrWifiRouterCtrlPortConfigureReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_QOS_CONTROL_REQ, CsrWifiRouterCtrlQosControlReqSizeof, CsrWifiRouterCtrlQosControlReqSer, CsrWifiRouterCtrlQosControlReqDes, CsrWifiRouterCtrlQosControlReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_SUSPEND_RES, CsrWifiRouterCtrlSuspendResSizeof, CsrWifiRouterCtrlSuspendResSer, CsrWifiRouterCtrlSuspendResDes, CsrWifiRouterCtrlSuspendResSerFree },
+    { CSR_WIFI_ROUTER_CTRL_TCLAS_ADD_REQ, CsrWifiRouterCtrlTclasAddReqSizeof, CsrWifiRouterCtrlTclasAddReqSer, CsrWifiRouterCtrlTclasAddReqDes, CsrWifiRouterCtrlTclasAddReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_RESUME_RES, CsrWifiRouterCtrlResumeResSizeof, CsrWifiRouterCtrlResumeResSer, CsrWifiRouterCtrlResumeResDes, CsrWifiRouterCtrlResumeResSerFree },
+    { CSR_WIFI_ROUTER_CTRL_RAW_SDIO_DEINITIALISE_REQ, CsrWifiRouterCtrlRawSdioDeinitialiseReqSizeof, CsrWifiRouterCtrlRawSdioDeinitialiseReqSer, CsrWifiRouterCtrlRawSdioDeinitialiseReqDes, CsrWifiRouterCtrlRawSdioDeinitialiseReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_RAW_SDIO_INITIALISE_REQ, CsrWifiRouterCtrlRawSdioInitialiseReqSizeof, CsrWifiRouterCtrlRawSdioInitialiseReqSer, CsrWifiRouterCtrlRawSdioInitialiseReqDes, CsrWifiRouterCtrlRawSdioInitialiseReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_TCLAS_DEL_REQ, CsrWifiRouterCtrlTclasDelReqSizeof, CsrWifiRouterCtrlTclasDelReqSer, CsrWifiRouterCtrlTclasDelReqDes, CsrWifiRouterCtrlTclasDelReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_TRAFFIC_CLASSIFICATION_REQ, CsrWifiRouterCtrlTrafficClassificationReqSizeof, CsrWifiRouterCtrlTrafficClassificationReqSer, CsrWifiRouterCtrlTrafficClassificationReqDes, CsrWifiRouterCtrlTrafficClassificationReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_REQ, CsrWifiRouterCtrlTrafficConfigReqSizeof, CsrWifiRouterCtrlTrafficConfigReqSer, CsrWifiRouterCtrlTrafficConfigReqDes, CsrWifiRouterCtrlTrafficConfigReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WIFI_OFF_REQ, CsrWifiRouterCtrlWifiOffReqSizeof, CsrWifiRouterCtrlWifiOffReqSer, CsrWifiRouterCtrlWifiOffReqDes, CsrWifiRouterCtrlWifiOffReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WIFI_OFF_RES, CsrWifiRouterCtrlWifiOffResSizeof, CsrWifiRouterCtrlWifiOffResSer, CsrWifiRouterCtrlWifiOffResDes, CsrWifiRouterCtrlWifiOffResSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WIFI_ON_REQ, CsrWifiRouterCtrlWifiOnReqSizeof, CsrWifiRouterCtrlWifiOnReqSer, CsrWifiRouterCtrlWifiOnReqDes, CsrWifiRouterCtrlWifiOnReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WIFI_ON_RES, CsrWifiRouterCtrlWifiOnResSizeof, CsrWifiRouterCtrlWifiOnResSer, CsrWifiRouterCtrlWifiOnResDes, CsrWifiRouterCtrlWifiOnResSerFree },
+    { CSR_WIFI_ROUTER_CTRL_M4_TRANSMIT_REQ, CsrWifiRouterCtrlM4TransmitReqSizeof, CsrWifiRouterCtrlM4TransmitReqSer, CsrWifiRouterCtrlM4TransmitReqDes, CsrWifiRouterCtrlM4TransmitReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_MODE_SET_REQ, CsrWifiRouterCtrlModeSetReqSizeof, CsrWifiRouterCtrlModeSetReqSer, CsrWifiRouterCtrlModeSetReqDes, CsrWifiRouterCtrlModeSetReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_PEER_ADD_REQ, CsrWifiRouterCtrlPeerAddReqSizeof, CsrWifiRouterCtrlPeerAddReqSer, CsrWifiRouterCtrlPeerAddReqDes, CsrWifiRouterCtrlPeerAddReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_PEER_DEL_REQ, CsrWifiRouterCtrlPeerDelReqSizeof, CsrWifiRouterCtrlPeerDelReqSer, CsrWifiRouterCtrlPeerDelReqDes, CsrWifiRouterCtrlPeerDelReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_PEER_UPDATE_REQ, CsrWifiRouterCtrlPeerUpdateReqSizeof, CsrWifiRouterCtrlPeerUpdateReqSer, CsrWifiRouterCtrlPeerUpdateReqDes, CsrWifiRouterCtrlPeerUpdateReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_CAPABILITIES_REQ, CsrWifiRouterCtrlCapabilitiesReqSizeof, CsrWifiRouterCtrlCapabilitiesReqSer, CsrWifiRouterCtrlCapabilitiesReqDes, CsrWifiRouterCtrlCapabilitiesReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ENABLE_REQ, CsrWifiRouterCtrlBlockAckEnableReqSizeof, CsrWifiRouterCtrlBlockAckEnableReqSer, CsrWifiRouterCtrlBlockAckEnableReqDes, CsrWifiRouterCtrlBlockAckEnableReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_DISABLE_REQ, CsrWifiRouterCtrlBlockAckDisableReqSizeof, CsrWifiRouterCtrlBlockAckDisableReqSer, CsrWifiRouterCtrlBlockAckDisableReqDes, CsrWifiRouterCtrlBlockAckDisableReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WAPI_RX_PKT_REQ, CsrWifiRouterCtrlWapiRxPktReqSizeof, CsrWifiRouterCtrlWapiRxPktReqSer, CsrWifiRouterCtrlWapiRxPktReqDes, CsrWifiRouterCtrlWapiRxPktReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WAPI_MULTICAST_FILTER_REQ, CsrWifiRouterCtrlWapiMulticastFilterReqSizeof, CsrWifiRouterCtrlWapiMulticastFilterReqSer, CsrWifiRouterCtrlWapiMulticastFilterReqDes, CsrWifiRouterCtrlWapiMulticastFilterReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WAPI_UNICAST_FILTER_REQ, CsrWifiRouterCtrlWapiUnicastFilterReqSizeof, CsrWifiRouterCtrlWapiUnicastFilterReqSer, CsrWifiRouterCtrlWapiUnicastFilterReqDes, CsrWifiRouterCtrlWapiUnicastFilterReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WAPI_UNICAST_TX_PKT_REQ, CsrWifiRouterCtrlWapiUnicastTxPktReqSizeof, CsrWifiRouterCtrlWapiUnicastTxPktReqSer, CsrWifiRouterCtrlWapiUnicastTxPktReqDes, CsrWifiRouterCtrlWapiUnicastTxPktReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WAPI_FILTER_REQ, CsrWifiRouterCtrlWapiFilterReqSizeof, CsrWifiRouterCtrlWapiFilterReqSer, CsrWifiRouterCtrlWapiFilterReqDes, CsrWifiRouterCtrlWapiFilterReqSerFree },
+    { CSR_WIFI_ROUTER_CTRL_HIP_IND, CsrWifiRouterCtrlHipIndSizeof, CsrWifiRouterCtrlHipIndSer, CsrWifiRouterCtrlHipIndDes, CsrWifiRouterCtrlHipIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_MULTICAST_ADDRESS_IND, CsrWifiRouterCtrlMulticastAddressIndSizeof, CsrWifiRouterCtrlMulticastAddressIndSer, CsrWifiRouterCtrlMulticastAddressIndDes, CsrWifiRouterCtrlMulticastAddressIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_PORT_CONFIGURE_CFM, CsrWifiRouterCtrlPortConfigureCfmSizeof, CsrWifiRouterCtrlPortConfigureCfmSer, CsrWifiRouterCtrlPortConfigureCfmDes, CsrWifiRouterCtrlPortConfigureCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_RESUME_IND, CsrWifiRouterCtrlResumeIndSizeof, CsrWifiRouterCtrlResumeIndSer, CsrWifiRouterCtrlResumeIndDes, CsrWifiRouterCtrlResumeIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_SUSPEND_IND, CsrWifiRouterCtrlSuspendIndSizeof, CsrWifiRouterCtrlSuspendIndSer, CsrWifiRouterCtrlSuspendIndDes, CsrWifiRouterCtrlSuspendIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_TCLAS_ADD_CFM, CsrWifiRouterCtrlTclasAddCfmSizeof, CsrWifiRouterCtrlTclasAddCfmSer, CsrWifiRouterCtrlTclasAddCfmDes, CsrWifiRouterCtrlTclasAddCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_RAW_SDIO_DEINITIALISE_CFM, CsrWifiRouterCtrlRawSdioDeinitialiseCfmSizeof, CsrWifiRouterCtrlRawSdioDeinitialiseCfmSer, CsrWifiRouterCtrlRawSdioDeinitialiseCfmDes, CsrWifiRouterCtrlRawSdioDeinitialiseCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_RAW_SDIO_INITIALISE_CFM, CsrWifiRouterCtrlRawSdioInitialiseCfmSizeof, CsrWifiRouterCtrlRawSdioInitialiseCfmSer, CsrWifiRouterCtrlRawSdioInitialiseCfmDes, CsrWifiRouterCtrlRawSdioInitialiseCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_TCLAS_DEL_CFM, CsrWifiRouterCtrlTclasDelCfmSizeof, CsrWifiRouterCtrlTclasDelCfmSer, CsrWifiRouterCtrlTclasDelCfmDes, CsrWifiRouterCtrlTclasDelCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_TRAFFIC_PROTOCOL_IND, CsrWifiRouterCtrlTrafficProtocolIndSizeof, CsrWifiRouterCtrlTrafficProtocolIndSer, CsrWifiRouterCtrlTrafficProtocolIndDes, CsrWifiRouterCtrlTrafficProtocolIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_TRAFFIC_SAMPLE_IND, CsrWifiRouterCtrlTrafficSampleIndSizeof, CsrWifiRouterCtrlTrafficSampleIndSer, CsrWifiRouterCtrlTrafficSampleIndDes, CsrWifiRouterCtrlTrafficSampleIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WIFI_OFF_IND, CsrWifiRouterCtrlWifiOffIndSizeof, CsrWifiRouterCtrlWifiOffIndSer, CsrWifiRouterCtrlWifiOffIndDes, CsrWifiRouterCtrlWifiOffIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WIFI_OFF_CFM, CsrWifiRouterCtrlWifiOffCfmSizeof, CsrWifiRouterCtrlWifiOffCfmSer, CsrWifiRouterCtrlWifiOffCfmDes, CsrWifiRouterCtrlWifiOffCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WIFI_ON_IND, CsrWifiRouterCtrlWifiOnIndSizeof, CsrWifiRouterCtrlWifiOnIndSer, CsrWifiRouterCtrlWifiOnIndDes, CsrWifiRouterCtrlWifiOnIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WIFI_ON_CFM, CsrWifiRouterCtrlWifiOnCfmSizeof, CsrWifiRouterCtrlWifiOnCfmSer, CsrWifiRouterCtrlWifiOnCfmDes, CsrWifiRouterCtrlWifiOnCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_M4_READY_TO_SEND_IND, CsrWifiRouterCtrlM4ReadyToSendIndSizeof, CsrWifiRouterCtrlM4ReadyToSendIndSer, CsrWifiRouterCtrlM4ReadyToSendIndDes, CsrWifiRouterCtrlM4ReadyToSendIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_M4_TRANSMITTED_IND, CsrWifiRouterCtrlM4TransmittedIndSizeof, CsrWifiRouterCtrlM4TransmittedIndSer, CsrWifiRouterCtrlM4TransmittedIndDes, CsrWifiRouterCtrlM4TransmittedIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_MIC_FAILURE_IND, CsrWifiRouterCtrlMicFailureIndSizeof, CsrWifiRouterCtrlMicFailureIndSer, CsrWifiRouterCtrlMicFailureIndDes, CsrWifiRouterCtrlMicFailureIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_CONNECTED_IND, CsrWifiRouterCtrlConnectedIndSizeof, CsrWifiRouterCtrlConnectedIndSer, CsrWifiRouterCtrlConnectedIndDes, CsrWifiRouterCtrlConnectedIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_PEER_ADD_CFM, CsrWifiRouterCtrlPeerAddCfmSizeof, CsrWifiRouterCtrlPeerAddCfmSer, CsrWifiRouterCtrlPeerAddCfmDes, CsrWifiRouterCtrlPeerAddCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_PEER_DEL_CFM, CsrWifiRouterCtrlPeerDelCfmSizeof, CsrWifiRouterCtrlPeerDelCfmSer, CsrWifiRouterCtrlPeerDelCfmDes, CsrWifiRouterCtrlPeerDelCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_UNEXPECTED_FRAME_IND, CsrWifiRouterCtrlUnexpectedFrameIndSizeof, CsrWifiRouterCtrlUnexpectedFrameIndSer, CsrWifiRouterCtrlUnexpectedFrameIndDes, CsrWifiRouterCtrlUnexpectedFrameIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_PEER_UPDATE_CFM, CsrWifiRouterCtrlPeerUpdateCfmSizeof, CsrWifiRouterCtrlPeerUpdateCfmSer, CsrWifiRouterCtrlPeerUpdateCfmDes, CsrWifiRouterCtrlPeerUpdateCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_CAPABILITIES_CFM, CsrWifiRouterCtrlCapabilitiesCfmSizeof, CsrWifiRouterCtrlCapabilitiesCfmSer, CsrWifiRouterCtrlCapabilitiesCfmDes, CsrWifiRouterCtrlCapabilitiesCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ENABLE_CFM, CsrWifiRouterCtrlBlockAckEnableCfmSizeof, CsrWifiRouterCtrlBlockAckEnableCfmSer, CsrWifiRouterCtrlBlockAckEnableCfmDes, CsrWifiRouterCtrlBlockAckEnableCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_DISABLE_CFM, CsrWifiRouterCtrlBlockAckDisableCfmSizeof, CsrWifiRouterCtrlBlockAckDisableCfmSer, CsrWifiRouterCtrlBlockAckDisableCfmDes, CsrWifiRouterCtrlBlockAckDisableCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ERROR_IND, CsrWifiRouterCtrlBlockAckErrorIndSizeof, CsrWifiRouterCtrlBlockAckErrorIndSer, CsrWifiRouterCtrlBlockAckErrorIndDes, CsrWifiRouterCtrlBlockAckErrorIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_STA_INACTIVE_IND, CsrWifiRouterCtrlStaInactiveIndSizeof, CsrWifiRouterCtrlStaInactiveIndSer, CsrWifiRouterCtrlStaInactiveIndDes, CsrWifiRouterCtrlStaInactiveIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WAPI_RX_MIC_CHECK_IND, CsrWifiRouterCtrlWapiRxMicCheckIndSizeof, CsrWifiRouterCtrlWapiRxMicCheckIndSer, CsrWifiRouterCtrlWapiRxMicCheckIndDes, CsrWifiRouterCtrlWapiRxMicCheckIndSerFree },
+    { CSR_WIFI_ROUTER_CTRL_MODE_SET_CFM, CsrWifiRouterCtrlModeSetCfmSizeof, CsrWifiRouterCtrlModeSetCfmSer, CsrWifiRouterCtrlModeSetCfmDes, CsrWifiRouterCtrlModeSetCfmSerFree },
+    { CSR_WIFI_ROUTER_CTRL_WAPI_UNICAST_TX_ENCRYPT_IND, CsrWifiRouterCtrlWapiUnicastTxEncryptIndSizeof, CsrWifiRouterCtrlWapiUnicastTxEncryptIndSer, CsrWifiRouterCtrlWapiUnicastTxEncryptIndDes, CsrWifiRouterCtrlWapiUnicastTxEncryptIndSerFree },
+
+    { 0, NULL, NULL, NULL, NULL },
+};
+
+CsrMsgConvMsgEntry* CsrWifiRouterCtrlConverterLookup(CsrMsgConvMsgEntry *ce, CsrUint16 msgType)
+{
+    if (msgType & CSR_PRIM_UPSTREAM)
+    {
+        CsrUint16 idx = (msgType & ~CSR_PRIM_UPSTREAM) + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_COUNT;
+        if (idx < (CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_COUNT + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_COUNT) &&
+            csrwifirouterctrl_conv_lut[idx].msgType == msgType)
+        {
+            return &csrwifirouterctrl_conv_lut[idx];
+        }
+    }
+    else
+    {
+        if (msgType < CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_COUNT &&
+            csrwifirouterctrl_conv_lut[msgType].msgType == msgType)
+        {
+            return &csrwifirouterctrl_conv_lut[msgType];
+        }
+    }
+    return NULL;
+}
+
+
+void CsrWifiRouterCtrlConverterInit(void)
+{
+    CsrMsgConvInsert(CSR_WIFI_ROUTER_CTRL_PRIM, csrwifirouterctrl_conv_lut);
+    CsrMsgConvCustomLookupRegister(CSR_WIFI_ROUTER_CTRL_PRIM, CsrWifiRouterCtrlConverterLookup);
+}
+
+
+#ifdef CSR_LOG_ENABLE
+static const CsrLogPrimitiveInformation csrwifirouterctrl_conv_info = {
+    CSR_WIFI_ROUTER_CTRL_PRIM,
+    (CsrCharString *)"CSR_WIFI_ROUTER_CTRL_PRIM",
+    csrwifirouterctrl_conv_lut
+};
+const CsrLogPrimitiveInformation* CsrWifiRouterCtrlTechInfoGet(void)
+{
+    return &csrwifirouterctrl_conv_info;
+}
+
+
+#endif /* CSR_LOG_ENABLE */
+#endif /* EXCLUDE_CSR_WIFI_ROUTER_CTRL_MODULE */
diff --git a/drivers/staging/csr/csr_wifi_router_ctrl_converter_init.h b/drivers/staging/csr/csr_wifi_router_ctrl_converter_init.h
new file mode 100644
index 0000000..0c9d26b
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_ctrl_converter_init.h
@@ -0,0 +1,42 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_ROUTER_CTRL_CONVERTER_INIT_H__
+#define CSR_WIFI_ROUTER_CTRL_CONVERTER_INIT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef EXCLUDE_CSR_WIFI_ROUTER_CTRL_MODULE
+
+#include "csr_msgconv.h"
+
+#ifdef CSR_LOG_ENABLE
+#include "csr_log.h"
+
+extern const CsrLogPrimitiveInformation* CsrWifiRouterCtrlTechInfoGet(void);
+#endif /* CSR_LOG_ENABLE */
+
+extern void CsrWifiRouterCtrlConverterInit(void);
+
+#else /* EXCLUDE_CSR_WIFI_ROUTER_CTRL_MODULE */
+
+#define CsrWifiRouterCtrlConverterInit()
+
+#endif /* EXCLUDE_CSR_WIFI_ROUTER_CTRL_MODULE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_ROUTER_CTRL_CONVERTER_INIT_H__ */
diff --git a/drivers/staging/csr/csr_wifi_router_ctrl_free_downstream_contents.c b/drivers/staging/csr/csr_wifi_router_ctrl_free_downstream_contents.c
new file mode 100644
index 0000000..d161fad
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_ctrl_free_downstream_contents.c
@@ -0,0 +1,109 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_wifi_router_ctrl_prim.h"
+#include "csr_wifi_router_ctrl_lib.h"
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrWifiRouterCtrlFreeDownstreamMessageContents
+ *
+ *  DESCRIPTION
+ *
+ *
+ *  PARAMETERS
+ *      eventClass: only the value CSR_WIFI_ROUTER_CTRL_PRIM will be handled
+ *      message:    the message to free
+ *----------------------------------------------------------------------------*/
+void CsrWifiRouterCtrlFreeDownstreamMessageContents(CsrUint16 eventClass, void *message)
+{
+    if (eventClass != CSR_WIFI_ROUTER_CTRL_PRIM)
+    {
+        return;
+    }
+    if (NULL == message)
+    {
+        return;
+    }
+
+    switch (*((CsrWifiRouterCtrlPrim *) message))
+    {
+        case CSR_WIFI_ROUTER_CTRL_HIP_REQ:
+        {
+            CsrWifiRouterCtrlHipReq *p = (CsrWifiRouterCtrlHipReq *)message;
+            CsrPmemFree(p->mlmeCommand);
+            p->mlmeCommand = NULL;
+            CsrPmemFree(p->dataRef1);
+            p->dataRef1 = NULL;
+            CsrPmemFree(p->dataRef2);
+            p->dataRef2 = NULL;
+            break;
+        }
+        case CSR_WIFI_ROUTER_CTRL_MULTICAST_ADDRESS_RES:
+        {
+            CsrWifiRouterCtrlMulticastAddressRes *p = (CsrWifiRouterCtrlMulticastAddressRes *)message;
+            CsrPmemFree(p->getAddresses);
+            p->getAddresses = NULL;
+            break;
+        }
+        case CSR_WIFI_ROUTER_CTRL_TCLAS_ADD_REQ:
+        {
+            CsrWifiRouterCtrlTclasAddReq *p = (CsrWifiRouterCtrlTclasAddReq *)message;
+            CsrPmemFree(p->tclas);
+            p->tclas = NULL;
+            break;
+        }
+        case CSR_WIFI_ROUTER_CTRL_TCLAS_DEL_REQ:
+        {
+            CsrWifiRouterCtrlTclasDelReq *p = (CsrWifiRouterCtrlTclasDelReq *)message;
+            CsrPmemFree(p->tclas);
+            p->tclas = NULL;
+            break;
+        }
+        case CSR_WIFI_ROUTER_CTRL_WIFI_ON_REQ:
+        {
+            CsrWifiRouterCtrlWifiOnReq *p = (CsrWifiRouterCtrlWifiOnReq *)message;
+            CsrPmemFree(p->data);
+            p->data = NULL;
+            break;
+        }
+        case CSR_WIFI_ROUTER_CTRL_WIFI_ON_RES:
+        {
+            CsrWifiRouterCtrlWifiOnRes *p = (CsrWifiRouterCtrlWifiOnRes *)message;
+            CsrPmemFree(p->smeVersions.smeBuild);
+            p->smeVersions.smeBuild = NULL;
+            break;
+        }
+        case CSR_WIFI_ROUTER_CTRL_WAPI_RX_PKT_REQ:
+        {
+            CsrWifiRouterCtrlWapiRxPktReq *p = (CsrWifiRouterCtrlWapiRxPktReq *)message;
+            CsrPmemFree(p->signal);
+            p->signal = NULL;
+            CsrPmemFree(p->data);
+            p->data = NULL;
+            break;
+        }
+        case CSR_WIFI_ROUTER_CTRL_WAPI_UNICAST_TX_PKT_REQ:
+        {
+            CsrWifiRouterCtrlWapiUnicastTxPktReq *p = (CsrWifiRouterCtrlWapiUnicastTxPktReq *)message;
+            CsrPmemFree(p->data);
+            p->data = NULL;
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_router_ctrl_free_upstream_contents.c b/drivers/staging/csr/csr_wifi_router_ctrl_free_upstream_contents.c
new file mode 100644
index 0000000..b6bf11d
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_ctrl_free_upstream_contents.c
@@ -0,0 +1,88 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_wifi_router_ctrl_prim.h"
+#include "csr_wifi_router_ctrl_lib.h"
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrWifiRouterCtrlFreeUpstreamMessageContents
+ *
+ *  DESCRIPTION
+ *
+ *
+ *  PARAMETERS
+ *      eventClass: only the value CSR_WIFI_ROUTER_CTRL_PRIM will be handled
+ *      message:    the message to free
+ *----------------------------------------------------------------------------*/
+void CsrWifiRouterCtrlFreeUpstreamMessageContents(CsrUint16 eventClass, void *message)
+{
+    if (eventClass != CSR_WIFI_ROUTER_CTRL_PRIM)
+    {
+        return;
+    }
+    if (NULL == message)
+    {
+        return;
+    }
+
+    switch (*((CsrWifiRouterCtrlPrim *) message))
+    {
+        case CSR_WIFI_ROUTER_CTRL_HIP_IND:
+        {
+            CsrWifiRouterCtrlHipInd *p = (CsrWifiRouterCtrlHipInd *)message;
+            CsrPmemFree(p->mlmeCommand);
+            p->mlmeCommand = NULL;
+            CsrPmemFree(p->dataRef1);
+            p->dataRef1 = NULL;
+            CsrPmemFree(p->dataRef2);
+            p->dataRef2 = NULL;
+            break;
+        }
+        case CSR_WIFI_ROUTER_CTRL_MULTICAST_ADDRESS_IND:
+        {
+            CsrWifiRouterCtrlMulticastAddressInd *p = (CsrWifiRouterCtrlMulticastAddressInd *)message;
+            CsrPmemFree(p->setAddresses);
+            p->setAddresses = NULL;
+            break;
+        }
+        case CSR_WIFI_ROUTER_CTRL_WIFI_ON_IND:
+        {
+            CsrWifiRouterCtrlWifiOnInd *p = (CsrWifiRouterCtrlWifiOnInd *)message;
+            CsrPmemFree(p->versions.routerBuild);
+            p->versions.routerBuild = NULL;
+            break;
+        }
+        case CSR_WIFI_ROUTER_CTRL_WAPI_RX_MIC_CHECK_IND:
+        {
+            CsrWifiRouterCtrlWapiRxMicCheckInd *p = (CsrWifiRouterCtrlWapiRxMicCheckInd *)message;
+            CsrPmemFree(p->signal);
+            p->signal = NULL;
+            CsrPmemFree(p->data);
+            p->data = NULL;
+            break;
+        }
+        case CSR_WIFI_ROUTER_CTRL_WAPI_UNICAST_TX_ENCRYPT_IND:
+        {
+            CsrWifiRouterCtrlWapiUnicastTxEncryptInd *p = (CsrWifiRouterCtrlWapiUnicastTxEncryptInd *)message;
+            CsrPmemFree(p->data);
+            p->data = NULL;
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_router_ctrl_lib.h b/drivers/staging/csr/csr_wifi_router_ctrl_lib.h
new file mode 100644
index 0000000..6c7e974
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_ctrl_lib.h
@@ -0,0 +1,2094 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_ROUTER_CTRL_LIB_H__
+#define CSR_WIFI_ROUTER_CTRL_LIB_H__
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_sched.h"
+#include "csr_util.h"
+#include "csr_msg_transport.h"
+
+#include "csr_wifi_lib.h"
+
+#include "csr_wifi_router_ctrl_prim.h"
+#include "csr_wifi_router_task.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiRouterCtrlFreeUpstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_ROUTER_CTRL upstream message. Does not
+ *      free the message itself, and can only be used for upstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_ROUTER_CTRL upstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiRouterCtrlFreeUpstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiRouterCtrlFreeDownstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_ROUTER_CTRL downstream message. Does not
+ *      free the message itself, and can only be used for downstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_ROUTER_CTRL downstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiRouterCtrlFreeDownstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ * Enum to string functions
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiRouterCtrlBlockAckRoleToString(CsrWifiRouterCtrlBlockAckRole value);
+const CsrCharString* CsrWifiRouterCtrlControlIndicationToString(CsrWifiRouterCtrlControlIndication value);
+const CsrCharString* CsrWifiRouterCtrlListActionToString(CsrWifiRouterCtrlListAction value);
+const CsrCharString* CsrWifiRouterCtrlLowPowerModeToString(CsrWifiRouterCtrlLowPowerMode value);
+const CsrCharString* CsrWifiRouterCtrlMediaStatusToString(CsrWifiRouterCtrlMediaStatus value);
+const CsrCharString* CsrWifiRouterCtrlModeToString(CsrWifiRouterCtrlMode value);
+const CsrCharString* CsrWifiRouterCtrlPeerStatusToString(CsrWifiRouterCtrlPeerStatus value);
+const CsrCharString* CsrWifiRouterCtrlPortActionToString(CsrWifiRouterCtrlPortAction value);
+const CsrCharString* CsrWifiRouterCtrlPowersaveTypeToString(CsrWifiRouterCtrlPowersaveType value);
+const CsrCharString* CsrWifiRouterCtrlProtocolDirectionToString(CsrWifiRouterCtrlProtocolDirection value);
+const CsrCharString* CsrWifiRouterCtrlQoSControlToString(CsrWifiRouterCtrlQoSControl value);
+const CsrCharString* CsrWifiRouterCtrlQueueConfigToString(CsrWifiRouterCtrlQueueConfig value);
+const CsrCharString* CsrWifiRouterCtrlTrafficConfigTypeToString(CsrWifiRouterCtrlTrafficConfigType value);
+const CsrCharString* CsrWifiRouterCtrlTrafficPacketTypeToString(CsrWifiRouterCtrlTrafficPacketType value);
+const CsrCharString* CsrWifiRouterCtrlTrafficTypeToString(CsrWifiRouterCtrlTrafficType value);
+
+
+/*----------------------------------------------------------------------------*
+ * CsrPrim Type toString function.
+ * Converts a message type to the String name of the Message
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiRouterCtrlPrimTypeToString(CsrPrim msgType);
+
+/*----------------------------------------------------------------------------*
+ * Lookup arrays for PrimType name Strings
+ *----------------------------------------------------------------------------*/
+extern const CsrCharString *CsrWifiRouterCtrlUpstreamPrimNames[CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_COUNT];
+extern const CsrCharString *CsrWifiRouterCtrlDownstreamPrimNames[CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_COUNT];
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlBlockAckDisableReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue           - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag    -
+    clientData      -
+    macAddress      -
+    trafficStreamID -
+    role            -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlBlockAckDisableReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, macAddress__, trafficStreamID__, role__) \
+    msg__ = (CsrWifiRouterCtrlBlockAckDisableReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlBlockAckDisableReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_DISABLE_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->macAddress = (macAddress__); \
+    msg__->trafficStreamID = (trafficStreamID__); \
+    msg__->role = (role__);
+
+#define CsrWifiRouterCtrlBlockAckDisableReqSendTo(dst__, src__, interfaceTag__, clientData__, macAddress__, trafficStreamID__, role__) \
+    { \
+        CsrWifiRouterCtrlBlockAckDisableReq *msg__; \
+        CsrWifiRouterCtrlBlockAckDisableReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, macAddress__, trafficStreamID__, role__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlBlockAckDisableReqSend(src__, interfaceTag__, clientData__, macAddress__, trafficStreamID__, role__) \
+    CsrWifiRouterCtrlBlockAckDisableReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, macAddress__, trafficStreamID__, role__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlBlockAckDisableCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlBlockAckDisableCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__) \
+    msg__ = (CsrWifiRouterCtrlBlockAckDisableCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlBlockAckDisableCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_DISABLE_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlBlockAckDisableCfmSendTo(dst__, src__, clientData__, interfaceTag__, status__) \
+    { \
+        CsrWifiRouterCtrlBlockAckDisableCfm *msg__; \
+        CsrWifiRouterCtrlBlockAckDisableCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlBlockAckDisableCfmSend(dst__, clientData__, interfaceTag__, status__) \
+    CsrWifiRouterCtrlBlockAckDisableCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlBlockAckEnableReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue           - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag    -
+    clientData      -
+    macAddress      -
+    trafficStreamID -
+    role            -
+    bufferSize      -
+    timeout         -
+    ssn             -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlBlockAckEnableReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, macAddress__, trafficStreamID__, role__, bufferSize__, timeout__, ssn__) \
+    msg__ = (CsrWifiRouterCtrlBlockAckEnableReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlBlockAckEnableReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ENABLE_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->macAddress = (macAddress__); \
+    msg__->trafficStreamID = (trafficStreamID__); \
+    msg__->role = (role__); \
+    msg__->bufferSize = (bufferSize__); \
+    msg__->timeout = (timeout__); \
+    msg__->ssn = (ssn__);
+
+#define CsrWifiRouterCtrlBlockAckEnableReqSendTo(dst__, src__, interfaceTag__, clientData__, macAddress__, trafficStreamID__, role__, bufferSize__, timeout__, ssn__) \
+    { \
+        CsrWifiRouterCtrlBlockAckEnableReq *msg__; \
+        CsrWifiRouterCtrlBlockAckEnableReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, macAddress__, trafficStreamID__, role__, bufferSize__, timeout__, ssn__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlBlockAckEnableReqSend(src__, interfaceTag__, clientData__, macAddress__, trafficStreamID__, role__, bufferSize__, timeout__, ssn__) \
+    CsrWifiRouterCtrlBlockAckEnableReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, macAddress__, trafficStreamID__, role__, bufferSize__, timeout__, ssn__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlBlockAckEnableCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlBlockAckEnableCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__) \
+    msg__ = (CsrWifiRouterCtrlBlockAckEnableCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlBlockAckEnableCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ENABLE_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlBlockAckEnableCfmSendTo(dst__, src__, clientData__, interfaceTag__, status__) \
+    { \
+        CsrWifiRouterCtrlBlockAckEnableCfm *msg__; \
+        CsrWifiRouterCtrlBlockAckEnableCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlBlockAckEnableCfmSend(dst__, clientData__, interfaceTag__, status__) \
+    CsrWifiRouterCtrlBlockAckEnableCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlBlockAckErrorIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue           - Destination Task Queue
+    clientData      -
+    interfaceTag    -
+    trafficStreamID -
+    peerMacAddress  -
+    status          -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlBlockAckErrorIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, trafficStreamID__, peerMacAddress__, status__) \
+    msg__ = (CsrWifiRouterCtrlBlockAckErrorInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlBlockAckErrorInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ERROR_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->trafficStreamID = (trafficStreamID__); \
+    msg__->peerMacAddress = (peerMacAddress__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlBlockAckErrorIndSendTo(dst__, src__, clientData__, interfaceTag__, trafficStreamID__, peerMacAddress__, status__) \
+    { \
+        CsrWifiRouterCtrlBlockAckErrorInd *msg__; \
+        CsrWifiRouterCtrlBlockAckErrorIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, trafficStreamID__, peerMacAddress__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlBlockAckErrorIndSend(dst__, clientData__, interfaceTag__, trafficStreamID__, peerMacAddress__, status__) \
+    CsrWifiRouterCtrlBlockAckErrorIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, trafficStreamID__, peerMacAddress__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlCapabilitiesReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue      - Message Source Task Queue (Cfm's will be sent to this Queue)
+    clientData -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlCapabilitiesReqCreate(msg__, dst__, src__, clientData__) \
+    msg__ = (CsrWifiRouterCtrlCapabilitiesReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlCapabilitiesReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_CAPABILITIES_REQ, dst__, src__); \
+    msg__->clientData = (clientData__);
+
+#define CsrWifiRouterCtrlCapabilitiesReqSendTo(dst__, src__, clientData__) \
+    { \
+        CsrWifiRouterCtrlCapabilitiesReq *msg__; \
+        CsrWifiRouterCtrlCapabilitiesReqCreate(msg__, dst__, src__, clientData__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlCapabilitiesReqSend(src__, clientData__) \
+    CsrWifiRouterCtrlCapabilitiesReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, clientData__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlCapabilitiesCfmSend
+
+  DESCRIPTION
+    The router sends this primitive to confirm the size of the queues of the
+    HIP.
+
+  PARAMETERS
+    queue            - Destination Task Queue
+    clientData       -
+    commandQueueSize - Size of command queue
+    trafficQueueSize - Size of traffic queue (per AC)
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlCapabilitiesCfmCreate(msg__, dst__, src__, clientData__, commandQueueSize__, trafficQueueSize__) \
+    msg__ = (CsrWifiRouterCtrlCapabilitiesCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlCapabilitiesCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_CAPABILITIES_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->commandQueueSize = (commandQueueSize__); \
+    msg__->trafficQueueSize = (trafficQueueSize__);
+
+#define CsrWifiRouterCtrlCapabilitiesCfmSendTo(dst__, src__, clientData__, commandQueueSize__, trafficQueueSize__) \
+    { \
+        CsrWifiRouterCtrlCapabilitiesCfm *msg__; \
+        CsrWifiRouterCtrlCapabilitiesCfmCreate(msg__, dst__, src__, clientData__, commandQueueSize__, trafficQueueSize__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlCapabilitiesCfmSend(dst__, clientData__, commandQueueSize__, trafficQueueSize__) \
+    CsrWifiRouterCtrlCapabilitiesCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, commandQueueSize__, trafficQueueSize__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlConfigurePowerModeReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue      - Message Source Task Queue (Cfm's will be sent to this Queue)
+    clientData -
+    mode       -
+    wakeHost   -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlConfigurePowerModeReqCreate(msg__, dst__, src__, clientData__, mode__, wakeHost__) \
+    msg__ = (CsrWifiRouterCtrlConfigurePowerModeReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlConfigurePowerModeReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_CONFIGURE_POWER_MODE_REQ, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->mode = (mode__); \
+    msg__->wakeHost = (wakeHost__);
+
+#define CsrWifiRouterCtrlConfigurePowerModeReqSendTo(dst__, src__, clientData__, mode__, wakeHost__) \
+    { \
+        CsrWifiRouterCtrlConfigurePowerModeReq *msg__; \
+        CsrWifiRouterCtrlConfigurePowerModeReqCreate(msg__, dst__, src__, clientData__, mode__, wakeHost__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlConfigurePowerModeReqSend(src__, clientData__, mode__, wakeHost__) \
+    CsrWifiRouterCtrlConfigurePowerModeReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, clientData__, mode__, wakeHost__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlConnectedIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    clientData     -
+    interfaceTag   -
+    peerMacAddress -
+    peerStatus     -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlConnectedIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__, peerStatus__) \
+    msg__ = (CsrWifiRouterCtrlConnectedInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlConnectedInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_CONNECTED_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->peerMacAddress = (peerMacAddress__); \
+    msg__->peerStatus = (peerStatus__);
+
+#define CsrWifiRouterCtrlConnectedIndSendTo(dst__, src__, clientData__, interfaceTag__, peerMacAddress__, peerStatus__) \
+    { \
+        CsrWifiRouterCtrlConnectedInd *msg__; \
+        CsrWifiRouterCtrlConnectedIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__, peerStatus__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlConnectedIndSend(dst__, clientData__, interfaceTag__, peerMacAddress__, peerStatus__) \
+    CsrWifiRouterCtrlConnectedIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, peerMacAddress__, peerStatus__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlHipReqSend
+
+  DESCRIPTION
+    This primitive is used for transferring MLME messages to the HIP.
+
+  PARAMETERS
+    queue             - Message Source Task Queue (Cfm's will be sent to this Queue)
+    mlmeCommandLength - Length of the MLME signal
+    mlmeCommand       - Pointer to the MLME signal
+    dataRef1Length    - Length of the dataRef1 bulk data
+    dataRef1          - Pointer to the bulk data 1
+    dataRef2Length    - Length of the dataRef2 bulk data
+    dataRef2          - Pointer to the bulk data 2
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlHipReqCreate(msg__, dst__, src__, mlmeCommandLength__, mlmeCommand__, dataRef1Length__, dataRef1__, dataRef2Length__, dataRef2__) \
+    msg__ = (CsrWifiRouterCtrlHipReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlHipReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_HIP_REQ, dst__, src__); \
+    msg__->mlmeCommandLength = (mlmeCommandLength__); \
+    msg__->mlmeCommand = (mlmeCommand__); \
+    msg__->dataRef1Length = (dataRef1Length__); \
+    msg__->dataRef1 = (dataRef1__); \
+    msg__->dataRef2Length = (dataRef2Length__); \
+    msg__->dataRef2 = (dataRef2__);
+
+#define CsrWifiRouterCtrlHipReqSendTo(dst__, src__, mlmeCommandLength__, mlmeCommand__, dataRef1Length__, dataRef1__, dataRef2Length__, dataRef2__) \
+    { \
+        CsrWifiRouterCtrlHipReq *msg__; \
+        CsrWifiRouterCtrlHipReqCreate(msg__, dst__, src__, mlmeCommandLength__, mlmeCommand__, dataRef1Length__, dataRef1__, dataRef2Length__, dataRef2__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlHipReqSend(src__, mlmeCommandLength__, mlmeCommand__, dataRef1Length__, dataRef1__, dataRef2Length__, dataRef2__) \
+    CsrWifiRouterCtrlHipReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, mlmeCommandLength__, mlmeCommand__, dataRef1Length__, dataRef1__, dataRef2Length__, dataRef2__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlHipIndSend
+
+  DESCRIPTION
+    This primitive is used for transferring MLME messages from the HIP.
+
+  PARAMETERS
+    queue             - Destination Task Queue
+    mlmeCommandLength - Length of the MLME signal
+    mlmeCommand       - Pointer to the MLME signal
+    dataRef1Length    - Length of the dataRef1 bulk data
+    dataRef1          - Pointer to the bulk data 1
+    dataRef2Length    - Length of the dataRef2 bulk data
+    dataRef2          - Pointer to the bulk data 2
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlHipIndCreate(msg__, dst__, src__, mlmeCommandLength__, mlmeCommand__, dataRef1Length__, dataRef1__, dataRef2Length__, dataRef2__) \
+    msg__ = (CsrWifiRouterCtrlHipInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlHipInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_HIP_IND, dst__, src__); \
+    msg__->mlmeCommandLength = (mlmeCommandLength__); \
+    msg__->mlmeCommand = (mlmeCommand__); \
+    msg__->dataRef1Length = (dataRef1Length__); \
+    msg__->dataRef1 = (dataRef1__); \
+    msg__->dataRef2Length = (dataRef2Length__); \
+    msg__->dataRef2 = (dataRef2__);
+
+#define CsrWifiRouterCtrlHipIndSendTo(dst__, src__, mlmeCommandLength__, mlmeCommand__, dataRef1Length__, dataRef1__, dataRef2Length__, dataRef2__) \
+    { \
+        CsrWifiRouterCtrlHipInd *msg__; \
+        CsrWifiRouterCtrlHipIndCreate(msg__, dst__, src__, mlmeCommandLength__, mlmeCommand__, dataRef1Length__, dataRef1__, dataRef2Length__, dataRef2__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlHipIndSend(dst__, mlmeCommandLength__, mlmeCommand__, dataRef1Length__, dataRef1__, dataRef2Length__, dataRef2__) \
+    CsrWifiRouterCtrlHipIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, mlmeCommandLength__, mlmeCommand__, dataRef1Length__, dataRef1__, dataRef2Length__, dataRef2__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlM4ReadyToSendIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    clientData     -
+    interfaceTag   -
+    peerMacAddress -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlM4ReadyToSendIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__) \
+    msg__ = (CsrWifiRouterCtrlM4ReadyToSendInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlM4ReadyToSendInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_M4_READY_TO_SEND_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->peerMacAddress = (peerMacAddress__);
+
+#define CsrWifiRouterCtrlM4ReadyToSendIndSendTo(dst__, src__, clientData__, interfaceTag__, peerMacAddress__) \
+    { \
+        CsrWifiRouterCtrlM4ReadyToSendInd *msg__; \
+        CsrWifiRouterCtrlM4ReadyToSendIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlM4ReadyToSendIndSend(dst__, clientData__, interfaceTag__, peerMacAddress__) \
+    CsrWifiRouterCtrlM4ReadyToSendIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, peerMacAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlM4TransmitReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+    clientData   -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlM4TransmitReqCreate(msg__, dst__, src__, interfaceTag__, clientData__) \
+    msg__ = (CsrWifiRouterCtrlM4TransmitReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlM4TransmitReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_M4_TRANSMIT_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__);
+
+#define CsrWifiRouterCtrlM4TransmitReqSendTo(dst__, src__, interfaceTag__, clientData__) \
+    { \
+        CsrWifiRouterCtrlM4TransmitReq *msg__; \
+        CsrWifiRouterCtrlM4TransmitReqCreate(msg__, dst__, src__, interfaceTag__, clientData__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlM4TransmitReqSend(src__, interfaceTag__, clientData__) \
+    CsrWifiRouterCtrlM4TransmitReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlM4TransmittedIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    clientData     -
+    interfaceTag   -
+    peerMacAddress -
+    status         -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlM4TransmittedIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__, status__) \
+    msg__ = (CsrWifiRouterCtrlM4TransmittedInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlM4TransmittedInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_M4_TRANSMITTED_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->peerMacAddress = (peerMacAddress__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlM4TransmittedIndSendTo(dst__, src__, clientData__, interfaceTag__, peerMacAddress__, status__) \
+    { \
+        CsrWifiRouterCtrlM4TransmittedInd *msg__; \
+        CsrWifiRouterCtrlM4TransmittedIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlM4TransmittedIndSend(dst__, clientData__, interfaceTag__, peerMacAddress__, status__) \
+    CsrWifiRouterCtrlM4TransmittedIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, peerMacAddress__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlMediaStatusReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+    clientData   -
+    mediaStatus  -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlMediaStatusReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, mediaStatus__) \
+    msg__ = (CsrWifiRouterCtrlMediaStatusReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlMediaStatusReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_MEDIA_STATUS_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->mediaStatus = (mediaStatus__);
+
+#define CsrWifiRouterCtrlMediaStatusReqSendTo(dst__, src__, interfaceTag__, clientData__, mediaStatus__) \
+    { \
+        CsrWifiRouterCtrlMediaStatusReq *msg__; \
+        CsrWifiRouterCtrlMediaStatusReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, mediaStatus__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlMediaStatusReqSend(src__, interfaceTag__, clientData__, mediaStatus__) \
+    CsrWifiRouterCtrlMediaStatusReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, mediaStatus__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlMicFailureIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    clientData     -
+    interfaceTag   -
+    peerMacAddress -
+    unicastPdu     -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlMicFailureIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__, unicastPdu__) \
+    msg__ = (CsrWifiRouterCtrlMicFailureInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlMicFailureInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_MIC_FAILURE_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->peerMacAddress = (peerMacAddress__); \
+    msg__->unicastPdu = (unicastPdu__);
+
+#define CsrWifiRouterCtrlMicFailureIndSendTo(dst__, src__, clientData__, interfaceTag__, peerMacAddress__, unicastPdu__) \
+    { \
+        CsrWifiRouterCtrlMicFailureInd *msg__; \
+        CsrWifiRouterCtrlMicFailureIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__, unicastPdu__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlMicFailureIndSend(dst__, clientData__, interfaceTag__, peerMacAddress__, unicastPdu__) \
+    CsrWifiRouterCtrlMicFailureIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, peerMacAddress__, unicastPdu__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlModeSetReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue               - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag        -
+    clientData          -
+    mode                -
+    bssid               - BSSID of the network the device is going to be a part
+                          of
+    protection          - Set to TRUE if encryption is enabled for the
+                          connection/broadcast frames
+    intraBssDistEnabled - If set to TRUE, intra BSS destribution will be
+                          enabled. If set to FALSE, any unicast PDU which does
+                          not have the RA as the the local MAC address, shall be
+                          ignored. This field is interpreted by the receive if
+                          mode is set to CSR_WIFI_ROUTER_CTRL_MODE_P2PGO
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlModeSetReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, mode__, bssid__, protection__, intraBssDistEnabled__) \
+    msg__ = (CsrWifiRouterCtrlModeSetReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlModeSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_MODE_SET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->mode = (mode__); \
+    msg__->bssid = (bssid__); \
+    msg__->protection = (protection__); \
+    msg__->intraBssDistEnabled = (intraBssDistEnabled__);
+
+#define CsrWifiRouterCtrlModeSetReqSendTo(dst__, src__, interfaceTag__, clientData__, mode__, bssid__, protection__, intraBssDistEnabled__) \
+    { \
+        CsrWifiRouterCtrlModeSetReq *msg__; \
+        CsrWifiRouterCtrlModeSetReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, mode__, bssid__, protection__, intraBssDistEnabled__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlModeSetReqSend(src__, interfaceTag__, clientData__, mode__, bssid__, protection__, intraBssDistEnabled__) \
+    CsrWifiRouterCtrlModeSetReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, mode__, bssid__, protection__, intraBssDistEnabled__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlModeSetCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    mode         -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlModeSetCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, mode__, status__) \
+    msg__ = (CsrWifiRouterCtrlModeSetCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlModeSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_MODE_SET_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->mode = (mode__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlModeSetCfmSendTo(dst__, src__, clientData__, interfaceTag__, mode__, status__) \
+    { \
+        CsrWifiRouterCtrlModeSetCfm *msg__; \
+        CsrWifiRouterCtrlModeSetCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, mode__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlModeSetCfmSend(dst__, clientData__, interfaceTag__, mode__, status__) \
+    CsrWifiRouterCtrlModeSetCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, mode__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlMulticastAddressIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue             - Destination Task Queue
+    clientData        -
+    interfaceTag      -
+    action            -
+    setAddressesCount -
+    setAddresses      -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlMulticastAddressIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, action__, setAddressesCount__, setAddresses__) \
+    msg__ = (CsrWifiRouterCtrlMulticastAddressInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlMulticastAddressInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_MULTICAST_ADDRESS_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->action = (action__); \
+    msg__->setAddressesCount = (setAddressesCount__); \
+    msg__->setAddresses = (setAddresses__);
+
+#define CsrWifiRouterCtrlMulticastAddressIndSendTo(dst__, src__, clientData__, interfaceTag__, action__, setAddressesCount__, setAddresses__) \
+    { \
+        CsrWifiRouterCtrlMulticastAddressInd *msg__; \
+        CsrWifiRouterCtrlMulticastAddressIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, action__, setAddressesCount__, setAddresses__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlMulticastAddressIndSend(dst__, clientData__, interfaceTag__, action__, setAddressesCount__, setAddresses__) \
+    CsrWifiRouterCtrlMulticastAddressIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, action__, setAddressesCount__, setAddresses__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlMulticastAddressResSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    interfaceTag      -
+    clientData        -
+    status            -
+    action            -
+    getAddressesCount -
+    getAddresses      -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlMulticastAddressResCreate(msg__, dst__, src__, interfaceTag__, clientData__, status__, action__, getAddressesCount__, getAddresses__) \
+    msg__ = (CsrWifiRouterCtrlMulticastAddressRes *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlMulticastAddressRes)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_MULTICAST_ADDRESS_RES, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->status = (status__); \
+    msg__->action = (action__); \
+    msg__->getAddressesCount = (getAddressesCount__); \
+    msg__->getAddresses = (getAddresses__);
+
+#define CsrWifiRouterCtrlMulticastAddressResSendTo(dst__, src__, interfaceTag__, clientData__, status__, action__, getAddressesCount__, getAddresses__) \
+    { \
+        CsrWifiRouterCtrlMulticastAddressRes *msg__; \
+        CsrWifiRouterCtrlMulticastAddressResCreate(msg__, dst__, src__, interfaceTag__, clientData__, status__, action__, getAddressesCount__, getAddresses__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlMulticastAddressResSend(src__, interfaceTag__, clientData__, status__, action__, getAddressesCount__, getAddresses__) \
+    CsrWifiRouterCtrlMulticastAddressResSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, status__, action__, getAddressesCount__, getAddresses__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerAddReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue          - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag   -
+    clientData     -
+    peerMacAddress -
+    associationId  -
+    staInfo        -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlPeerAddReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, peerMacAddress__, associationId__, staInfo__) \
+    msg__ = (CsrWifiRouterCtrlPeerAddReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerAddReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_PEER_ADD_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->peerMacAddress = (peerMacAddress__); \
+    msg__->associationId = (associationId__); \
+    msg__->staInfo = (staInfo__);
+
+#define CsrWifiRouterCtrlPeerAddReqSendTo(dst__, src__, interfaceTag__, clientData__, peerMacAddress__, associationId__, staInfo__) \
+    { \
+        CsrWifiRouterCtrlPeerAddReq *msg__; \
+        CsrWifiRouterCtrlPeerAddReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, peerMacAddress__, associationId__, staInfo__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlPeerAddReqSend(src__, interfaceTag__, clientData__, peerMacAddress__, associationId__, staInfo__) \
+    CsrWifiRouterCtrlPeerAddReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, peerMacAddress__, associationId__, staInfo__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerAddCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue            - Destination Task Queue
+    clientData       -
+    interfaceTag     -
+    peerMacAddress   -
+    peerRecordHandle -
+    status           -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlPeerAddCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__, peerRecordHandle__, status__) \
+    msg__ = (CsrWifiRouterCtrlPeerAddCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerAddCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_PEER_ADD_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->peerMacAddress = (peerMacAddress__); \
+    msg__->peerRecordHandle = (peerRecordHandle__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlPeerAddCfmSendTo(dst__, src__, clientData__, interfaceTag__, peerMacAddress__, peerRecordHandle__, status__) \
+    { \
+        CsrWifiRouterCtrlPeerAddCfm *msg__; \
+        CsrWifiRouterCtrlPeerAddCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__, peerRecordHandle__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlPeerAddCfmSend(dst__, clientData__, interfaceTag__, peerMacAddress__, peerRecordHandle__, status__) \
+    CsrWifiRouterCtrlPeerAddCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, peerMacAddress__, peerRecordHandle__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerDelReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue            - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag     -
+    clientData       -
+    peerRecordHandle -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlPeerDelReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, peerRecordHandle__) \
+    msg__ = (CsrWifiRouterCtrlPeerDelReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerDelReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_PEER_DEL_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->peerRecordHandle = (peerRecordHandle__);
+
+#define CsrWifiRouterCtrlPeerDelReqSendTo(dst__, src__, interfaceTag__, clientData__, peerRecordHandle__) \
+    { \
+        CsrWifiRouterCtrlPeerDelReq *msg__; \
+        CsrWifiRouterCtrlPeerDelReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, peerRecordHandle__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlPeerDelReqSend(src__, interfaceTag__, clientData__, peerRecordHandle__) \
+    CsrWifiRouterCtrlPeerDelReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, peerRecordHandle__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerDelCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlPeerDelCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__) \
+    msg__ = (CsrWifiRouterCtrlPeerDelCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerDelCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_PEER_DEL_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlPeerDelCfmSendTo(dst__, src__, clientData__, interfaceTag__, status__) \
+    { \
+        CsrWifiRouterCtrlPeerDelCfm *msg__; \
+        CsrWifiRouterCtrlPeerDelCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlPeerDelCfmSend(dst__, clientData__, interfaceTag__, status__) \
+    CsrWifiRouterCtrlPeerDelCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerUpdateReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue            - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag     -
+    clientData       -
+    peerRecordHandle -
+    powersaveMode    -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlPeerUpdateReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, peerRecordHandle__, powersaveMode__) \
+    msg__ = (CsrWifiRouterCtrlPeerUpdateReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerUpdateReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_PEER_UPDATE_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->peerRecordHandle = (peerRecordHandle__); \
+    msg__->powersaveMode = (powersaveMode__);
+
+#define CsrWifiRouterCtrlPeerUpdateReqSendTo(dst__, src__, interfaceTag__, clientData__, peerRecordHandle__, powersaveMode__) \
+    { \
+        CsrWifiRouterCtrlPeerUpdateReq *msg__; \
+        CsrWifiRouterCtrlPeerUpdateReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, peerRecordHandle__, powersaveMode__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlPeerUpdateReqSend(src__, interfaceTag__, clientData__, peerRecordHandle__, powersaveMode__) \
+    CsrWifiRouterCtrlPeerUpdateReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, peerRecordHandle__, powersaveMode__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerUpdateCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlPeerUpdateCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__) \
+    msg__ = (CsrWifiRouterCtrlPeerUpdateCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerUpdateCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_PEER_UPDATE_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlPeerUpdateCfmSendTo(dst__, src__, clientData__, interfaceTag__, status__) \
+    { \
+        CsrWifiRouterCtrlPeerUpdateCfm *msg__; \
+        CsrWifiRouterCtrlPeerUpdateCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlPeerUpdateCfmSend(dst__, clientData__, interfaceTag__, status__) \
+    CsrWifiRouterCtrlPeerUpdateCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPortConfigureReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue                  - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag           -
+    clientData             -
+    uncontrolledPortAction -
+    controlledPortAction   -
+    macAddress             -
+    setProtection          -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlPortConfigureReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, uncontrolledPortAction__, controlledPortAction__, macAddress__, setProtection__) \
+    msg__ = (CsrWifiRouterCtrlPortConfigureReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPortConfigureReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_PORT_CONFIGURE_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->uncontrolledPortAction = (uncontrolledPortAction__); \
+    msg__->controlledPortAction = (controlledPortAction__); \
+    msg__->macAddress = (macAddress__); \
+    msg__->setProtection = (setProtection__);
+
+#define CsrWifiRouterCtrlPortConfigureReqSendTo(dst__, src__, interfaceTag__, clientData__, uncontrolledPortAction__, controlledPortAction__, macAddress__, setProtection__) \
+    { \
+        CsrWifiRouterCtrlPortConfigureReq *msg__; \
+        CsrWifiRouterCtrlPortConfigureReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, uncontrolledPortAction__, controlledPortAction__, macAddress__, setProtection__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlPortConfigureReqSend(src__, interfaceTag__, clientData__, uncontrolledPortAction__, controlledPortAction__, macAddress__, setProtection__) \
+    CsrWifiRouterCtrlPortConfigureReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, uncontrolledPortAction__, controlledPortAction__, macAddress__, setProtection__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPortConfigureCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    status       -
+    macAddress   -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlPortConfigureCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__, macAddress__) \
+    msg__ = (CsrWifiRouterCtrlPortConfigureCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPortConfigureCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_PORT_CONFIGURE_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->macAddress = (macAddress__);
+
+#define CsrWifiRouterCtrlPortConfigureCfmSendTo(dst__, src__, clientData__, interfaceTag__, status__, macAddress__) \
+    { \
+        CsrWifiRouterCtrlPortConfigureCfm *msg__; \
+        CsrWifiRouterCtrlPortConfigureCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__, macAddress__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlPortConfigureCfmSend(dst__, clientData__, interfaceTag__, status__, macAddress__) \
+    CsrWifiRouterCtrlPortConfigureCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, status__, macAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlQosControlReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+    clientData   -
+    control      -
+    queueConfig  -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlQosControlReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, control__, queueConfig__) \
+    msg__ = (CsrWifiRouterCtrlQosControlReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlQosControlReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_QOS_CONTROL_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->control = (control__); \
+    msg__->queueConfig = (queueConfig__);
+
+#define CsrWifiRouterCtrlQosControlReqSendTo(dst__, src__, interfaceTag__, clientData__, control__, queueConfig__) \
+    { \
+        CsrWifiRouterCtrlQosControlReq *msg__; \
+        CsrWifiRouterCtrlQosControlReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, control__, queueConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlQosControlReqSend(src__, interfaceTag__, clientData__, control__, queueConfig__) \
+    CsrWifiRouterCtrlQosControlReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, control__, queueConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlRawSdioDeinitialiseReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue      - Message Source Task Queue (Cfm's will be sent to this Queue)
+    clientData -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlRawSdioDeinitialiseReqCreate(msg__, dst__, src__, clientData__) \
+    msg__ = (CsrWifiRouterCtrlRawSdioDeinitialiseReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlRawSdioDeinitialiseReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_RAW_SDIO_DEINITIALISE_REQ, dst__, src__); \
+    msg__->clientData = (clientData__);
+
+#define CsrWifiRouterCtrlRawSdioDeinitialiseReqSendTo(dst__, src__, clientData__) \
+    { \
+        CsrWifiRouterCtrlRawSdioDeinitialiseReq *msg__; \
+        CsrWifiRouterCtrlRawSdioDeinitialiseReqCreate(msg__, dst__, src__, clientData__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlRawSdioDeinitialiseReqSend(src__, clientData__) \
+    CsrWifiRouterCtrlRawSdioDeinitialiseReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, clientData__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlRawSdioDeinitialiseCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue      - Destination Task Queue
+    clientData -
+    result     -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlRawSdioDeinitialiseCfmCreate(msg__, dst__, src__, clientData__, result__) \
+    msg__ = (CsrWifiRouterCtrlRawSdioDeinitialiseCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlRawSdioDeinitialiseCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_RAW_SDIO_DEINITIALISE_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->result = (result__);
+
+#define CsrWifiRouterCtrlRawSdioDeinitialiseCfmSendTo(dst__, src__, clientData__, result__) \
+    { \
+        CsrWifiRouterCtrlRawSdioDeinitialiseCfm *msg__; \
+        CsrWifiRouterCtrlRawSdioDeinitialiseCfmCreate(msg__, dst__, src__, clientData__, result__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlRawSdioDeinitialiseCfmSend(dst__, clientData__, result__) \
+    CsrWifiRouterCtrlRawSdioDeinitialiseCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, result__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlRawSdioInitialiseReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue      - Message Source Task Queue (Cfm's will be sent to this Queue)
+    clientData -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlRawSdioInitialiseReqCreate(msg__, dst__, src__, clientData__) \
+    msg__ = (CsrWifiRouterCtrlRawSdioInitialiseReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlRawSdioInitialiseReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_RAW_SDIO_INITIALISE_REQ, dst__, src__); \
+    msg__->clientData = (clientData__);
+
+#define CsrWifiRouterCtrlRawSdioInitialiseReqSendTo(dst__, src__, clientData__) \
+    { \
+        CsrWifiRouterCtrlRawSdioInitialiseReq *msg__; \
+        CsrWifiRouterCtrlRawSdioInitialiseReqCreate(msg__, dst__, src__, clientData__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlRawSdioInitialiseReqSend(src__, clientData__) \
+    CsrWifiRouterCtrlRawSdioInitialiseReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, clientData__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlRawSdioInitialiseCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue            - Destination Task Queue
+    clientData       -
+    result           -
+    byteRead         -
+    byteWrite        -
+    firmwareDownload -
+    reset            -
+    coreDumpPrepare  -
+    byteBlockRead    -
+    gpRead16         -
+    gpWrite16        -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlRawSdioInitialiseCfmCreate(msg__, dst__, src__, clientData__, result__, byteRead__, byteWrite__, firmwareDownload__, reset__, coreDumpPrepare__, byteBlockRead__, gpRead16__, gpWrite16__) \
+    msg__ = (CsrWifiRouterCtrlRawSdioInitialiseCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlRawSdioInitialiseCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_RAW_SDIO_INITIALISE_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->result = (result__); \
+    msg__->byteRead = (byteRead__); \
+    msg__->byteWrite = (byteWrite__); \
+    msg__->firmwareDownload = (firmwareDownload__); \
+    msg__->reset = (reset__); \
+    msg__->coreDumpPrepare = (coreDumpPrepare__); \
+    msg__->byteBlockRead = (byteBlockRead__); \
+    msg__->gpRead16 = (gpRead16__); \
+    msg__->gpWrite16 = (gpWrite16__);
+
+#define CsrWifiRouterCtrlRawSdioInitialiseCfmSendTo(dst__, src__, clientData__, result__, byteRead__, byteWrite__, firmwareDownload__, reset__, coreDumpPrepare__, byteBlockRead__, gpRead16__, gpWrite16__) \
+    { \
+        CsrWifiRouterCtrlRawSdioInitialiseCfm *msg__; \
+        CsrWifiRouterCtrlRawSdioInitialiseCfmCreate(msg__, dst__, src__, clientData__, result__, byteRead__, byteWrite__, firmwareDownload__, reset__, coreDumpPrepare__, byteBlockRead__, gpRead16__, gpWrite16__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlRawSdioInitialiseCfmSend(dst__, clientData__, result__, byteRead__, byteWrite__, firmwareDownload__, reset__, coreDumpPrepare__, byteBlockRead__, gpRead16__, gpWrite16__) \
+    CsrWifiRouterCtrlRawSdioInitialiseCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, result__, byteRead__, byteWrite__, firmwareDownload__, reset__, coreDumpPrepare__, byteBlockRead__, gpRead16__, gpWrite16__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlResumeIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue           - Destination Task Queue
+    clientData      -
+    powerMaintained -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlResumeIndCreate(msg__, dst__, src__, clientData__, powerMaintained__) \
+    msg__ = (CsrWifiRouterCtrlResumeInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlResumeInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_RESUME_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->powerMaintained = (powerMaintained__);
+
+#define CsrWifiRouterCtrlResumeIndSendTo(dst__, src__, clientData__, powerMaintained__) \
+    { \
+        CsrWifiRouterCtrlResumeInd *msg__; \
+        CsrWifiRouterCtrlResumeIndCreate(msg__, dst__, src__, clientData__, powerMaintained__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlResumeIndSend(dst__, clientData__, powerMaintained__) \
+    CsrWifiRouterCtrlResumeIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, powerMaintained__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlResumeResSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    clientData -
+    status     -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlResumeResCreate(msg__, dst__, src__, clientData__, status__) \
+    msg__ = (CsrWifiRouterCtrlResumeRes *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlResumeRes)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_RESUME_RES, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlResumeResSendTo(dst__, src__, clientData__, status__) \
+    { \
+        CsrWifiRouterCtrlResumeRes *msg__; \
+        CsrWifiRouterCtrlResumeResCreate(msg__, dst__, src__, clientData__, status__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlResumeResSend(src__, clientData__, status__) \
+    CsrWifiRouterCtrlResumeResSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, clientData__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlStaInactiveIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    staAddress   -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlStaInactiveIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, staAddress__) \
+    msg__ = (CsrWifiRouterCtrlStaInactiveInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlStaInactiveInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_STA_INACTIVE_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->staAddress = (staAddress__);
+
+#define CsrWifiRouterCtrlStaInactiveIndSendTo(dst__, src__, clientData__, interfaceTag__, staAddress__) \
+    { \
+        CsrWifiRouterCtrlStaInactiveInd *msg__; \
+        CsrWifiRouterCtrlStaInactiveIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, staAddress__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlStaInactiveIndSend(dst__, clientData__, interfaceTag__, staAddress__) \
+    CsrWifiRouterCtrlStaInactiveIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, staAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlSuspendIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue       - Destination Task Queue
+    clientData  -
+    hardSuspend -
+    d3Suspend   -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlSuspendIndCreate(msg__, dst__, src__, clientData__, hardSuspend__, d3Suspend__) \
+    msg__ = (CsrWifiRouterCtrlSuspendInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlSuspendInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_SUSPEND_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->hardSuspend = (hardSuspend__); \
+    msg__->d3Suspend = (d3Suspend__);
+
+#define CsrWifiRouterCtrlSuspendIndSendTo(dst__, src__, clientData__, hardSuspend__, d3Suspend__) \
+    { \
+        CsrWifiRouterCtrlSuspendInd *msg__; \
+        CsrWifiRouterCtrlSuspendIndCreate(msg__, dst__, src__, clientData__, hardSuspend__, d3Suspend__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlSuspendIndSend(dst__, clientData__, hardSuspend__, d3Suspend__) \
+    CsrWifiRouterCtrlSuspendIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, hardSuspend__, d3Suspend__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlSuspendResSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    clientData -
+    status     -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlSuspendResCreate(msg__, dst__, src__, clientData__, status__) \
+    msg__ = (CsrWifiRouterCtrlSuspendRes *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlSuspendRes)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_SUSPEND_RES, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlSuspendResSendTo(dst__, src__, clientData__, status__) \
+    { \
+        CsrWifiRouterCtrlSuspendRes *msg__; \
+        CsrWifiRouterCtrlSuspendResCreate(msg__, dst__, src__, clientData__, status__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlSuspendResSend(src__, clientData__, status__) \
+    CsrWifiRouterCtrlSuspendResSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, clientData__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTclasAddReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+    clientData   -
+    tclasLength  -
+    tclas        -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlTclasAddReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, tclasLength__, tclas__) \
+    msg__ = (CsrWifiRouterCtrlTclasAddReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTclasAddReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_TCLAS_ADD_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->tclasLength = (tclasLength__); \
+    msg__->tclas = (tclas__);
+
+#define CsrWifiRouterCtrlTclasAddReqSendTo(dst__, src__, interfaceTag__, clientData__, tclasLength__, tclas__) \
+    { \
+        CsrWifiRouterCtrlTclasAddReq *msg__; \
+        CsrWifiRouterCtrlTclasAddReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, tclasLength__, tclas__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlTclasAddReqSend(src__, interfaceTag__, clientData__, tclasLength__, tclas__) \
+    CsrWifiRouterCtrlTclasAddReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, tclasLength__, tclas__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTclasAddCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlTclasAddCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__) \
+    msg__ = (CsrWifiRouterCtrlTclasAddCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTclasAddCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_TCLAS_ADD_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlTclasAddCfmSendTo(dst__, src__, clientData__, interfaceTag__, status__) \
+    { \
+        CsrWifiRouterCtrlTclasAddCfm *msg__; \
+        CsrWifiRouterCtrlTclasAddCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlTclasAddCfmSend(dst__, clientData__, interfaceTag__, status__) \
+    CsrWifiRouterCtrlTclasAddCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTclasDelReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+    clientData   -
+    tclasLength  -
+    tclas        -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlTclasDelReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, tclasLength__, tclas__) \
+    msg__ = (CsrWifiRouterCtrlTclasDelReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTclasDelReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_TCLAS_DEL_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->tclasLength = (tclasLength__); \
+    msg__->tclas = (tclas__);
+
+#define CsrWifiRouterCtrlTclasDelReqSendTo(dst__, src__, interfaceTag__, clientData__, tclasLength__, tclas__) \
+    { \
+        CsrWifiRouterCtrlTclasDelReq *msg__; \
+        CsrWifiRouterCtrlTclasDelReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, tclasLength__, tclas__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlTclasDelReqSend(src__, interfaceTag__, clientData__, tclasLength__, tclas__) \
+    CsrWifiRouterCtrlTclasDelReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, tclasLength__, tclas__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTclasDelCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlTclasDelCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__) \
+    msg__ = (CsrWifiRouterCtrlTclasDelCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTclasDelCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_TCLAS_DEL_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlTclasDelCfmSendTo(dst__, src__, clientData__, interfaceTag__, status__) \
+    { \
+        CsrWifiRouterCtrlTclasDelCfm *msg__; \
+        CsrWifiRouterCtrlTclasDelCfmCreate(msg__, dst__, src__, clientData__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlTclasDelCfmSend(dst__, clientData__, interfaceTag__, status__) \
+    CsrWifiRouterCtrlTclasDelCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficClassificationReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+    clientData   -
+    trafficType  -
+    period       -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlTrafficClassificationReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, trafficType__, period__) \
+    msg__ = (CsrWifiRouterCtrlTrafficClassificationReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTrafficClassificationReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_TRAFFIC_CLASSIFICATION_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->trafficType = (trafficType__); \
+    msg__->period = (period__);
+
+#define CsrWifiRouterCtrlTrafficClassificationReqSendTo(dst__, src__, interfaceTag__, clientData__, trafficType__, period__) \
+    { \
+        CsrWifiRouterCtrlTrafficClassificationReq *msg__; \
+        CsrWifiRouterCtrlTrafficClassificationReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, trafficType__, period__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlTrafficClassificationReqSend(src__, interfaceTag__, clientData__, trafficType__, period__) \
+    CsrWifiRouterCtrlTrafficClassificationReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, trafficType__, period__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficConfigReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue             - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag      -
+    clientData        -
+    trafficConfigType -
+    config            -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlTrafficConfigReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, trafficConfigType__, config__) \
+    msg__ = (CsrWifiRouterCtrlTrafficConfigReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTrafficConfigReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->clientData = (clientData__); \
+    msg__->trafficConfigType = (trafficConfigType__); \
+    msg__->config = (config__);
+
+#define CsrWifiRouterCtrlTrafficConfigReqSendTo(dst__, src__, interfaceTag__, clientData__, trafficConfigType__, config__) \
+    { \
+        CsrWifiRouterCtrlTrafficConfigReq *msg__; \
+        CsrWifiRouterCtrlTrafficConfigReqCreate(msg__, dst__, src__, interfaceTag__, clientData__, trafficConfigType__, config__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlTrafficConfigReqSend(src__, interfaceTag__, clientData__, trafficConfigType__, config__) \
+    CsrWifiRouterCtrlTrafficConfigReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, clientData__, trafficConfigType__, config__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficProtocolIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    packetType   -
+    direction    -
+    srcAddress   -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlTrafficProtocolIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, packetType__, direction__, srcAddress__) \
+    msg__ = (CsrWifiRouterCtrlTrafficProtocolInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTrafficProtocolInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_TRAFFIC_PROTOCOL_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->packetType = (packetType__); \
+    msg__->direction = (direction__); \
+    msg__->srcAddress = (srcAddress__);
+
+#define CsrWifiRouterCtrlTrafficProtocolIndSendTo(dst__, src__, clientData__, interfaceTag__, packetType__, direction__, srcAddress__) \
+    { \
+        CsrWifiRouterCtrlTrafficProtocolInd *msg__; \
+        CsrWifiRouterCtrlTrafficProtocolIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, packetType__, direction__, srcAddress__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlTrafficProtocolIndSend(dst__, clientData__, interfaceTag__, packetType__, direction__, srcAddress__) \
+    CsrWifiRouterCtrlTrafficProtocolIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, packetType__, direction__, srcAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficSampleIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    stats        -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlTrafficSampleIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, stats__) \
+    msg__ = (CsrWifiRouterCtrlTrafficSampleInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTrafficSampleInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_TRAFFIC_SAMPLE_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->stats = (stats__);
+
+#define CsrWifiRouterCtrlTrafficSampleIndSendTo(dst__, src__, clientData__, interfaceTag__, stats__) \
+    { \
+        CsrWifiRouterCtrlTrafficSampleInd *msg__; \
+        CsrWifiRouterCtrlTrafficSampleIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, stats__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlTrafficSampleIndSend(dst__, clientData__, interfaceTag__, stats__) \
+    CsrWifiRouterCtrlTrafficSampleIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, stats__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlUnexpectedFrameIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    clientData     -
+    interfaceTag   -
+    peerMacAddress -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlUnexpectedFrameIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__) \
+    msg__ = (CsrWifiRouterCtrlUnexpectedFrameInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlUnexpectedFrameInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_UNEXPECTED_FRAME_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->peerMacAddress = (peerMacAddress__);
+
+#define CsrWifiRouterCtrlUnexpectedFrameIndSendTo(dst__, src__, clientData__, interfaceTag__, peerMacAddress__) \
+    { \
+        CsrWifiRouterCtrlUnexpectedFrameInd *msg__; \
+        CsrWifiRouterCtrlUnexpectedFrameIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, peerMacAddress__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlUnexpectedFrameIndSend(dst__, clientData__, interfaceTag__, peerMacAddress__) \
+    CsrWifiRouterCtrlUnexpectedFrameIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, peerMacAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiFilterReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue           - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag    -
+    isWapiConnected -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWapiFilterReqCreate(msg__, dst__, src__, interfaceTag__, isWapiConnected__) \
+    msg__ = (CsrWifiRouterCtrlWapiFilterReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWapiFilterReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WAPI_FILTER_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->isWapiConnected = (isWapiConnected__);
+
+#define CsrWifiRouterCtrlWapiFilterReqSendTo(dst__, src__, interfaceTag__, isWapiConnected__) \
+    { \
+        CsrWifiRouterCtrlWapiFilterReq *msg__; \
+        CsrWifiRouterCtrlWapiFilterReqCreate(msg__, dst__, src__, interfaceTag__, isWapiConnected__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWapiFilterReqSend(src__, interfaceTag__, isWapiConnected__) \
+    CsrWifiRouterCtrlWapiFilterReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, isWapiConnected__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiMulticastFilterReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWapiMulticastFilterReqCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiRouterCtrlWapiMulticastFilterReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWapiMulticastFilterReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WAPI_MULTICAST_FILTER_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlWapiMulticastFilterReqSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiRouterCtrlWapiMulticastFilterReq *msg__; \
+        CsrWifiRouterCtrlWapiMulticastFilterReqCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWapiMulticastFilterReqSend(src__, interfaceTag__, status__) \
+    CsrWifiRouterCtrlWapiMulticastFilterReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiRxMicCheckIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    signalLength -
+    signal       -
+    dataLength   -
+    data         -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWapiRxMicCheckIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, signalLength__, signal__, dataLength__, data__) \
+    msg__ = (CsrWifiRouterCtrlWapiRxMicCheckInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWapiRxMicCheckInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WAPI_RX_MIC_CHECK_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->signalLength = (signalLength__); \
+    msg__->signal = (signal__); \
+    msg__->dataLength = (dataLength__); \
+    msg__->data = (data__);
+
+#define CsrWifiRouterCtrlWapiRxMicCheckIndSendTo(dst__, src__, clientData__, interfaceTag__, signalLength__, signal__, dataLength__, data__) \
+    { \
+        CsrWifiRouterCtrlWapiRxMicCheckInd *msg__; \
+        CsrWifiRouterCtrlWapiRxMicCheckIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, signalLength__, signal__, dataLength__, data__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWapiRxMicCheckIndSend(dst__, clientData__, interfaceTag__, signalLength__, signal__, dataLength__, data__) \
+    CsrWifiRouterCtrlWapiRxMicCheckIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, signalLength__, signal__, dataLength__, data__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiRxPktReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+    signalLength -
+    signal       -
+    dataLength   -
+    data         -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWapiRxPktReqCreate(msg__, dst__, src__, interfaceTag__, signalLength__, signal__, dataLength__, data__) \
+    msg__ = (CsrWifiRouterCtrlWapiRxPktReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWapiRxPktReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WAPI_RX_PKT_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->signalLength = (signalLength__); \
+    msg__->signal = (signal__); \
+    msg__->dataLength = (dataLength__); \
+    msg__->data = (data__);
+
+#define CsrWifiRouterCtrlWapiRxPktReqSendTo(dst__, src__, interfaceTag__, signalLength__, signal__, dataLength__, data__) \
+    { \
+        CsrWifiRouterCtrlWapiRxPktReq *msg__; \
+        CsrWifiRouterCtrlWapiRxPktReqCreate(msg__, dst__, src__, interfaceTag__, signalLength__, signal__, dataLength__, data__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWapiRxPktReqSend(src__, interfaceTag__, signalLength__, signal__, dataLength__, data__) \
+    CsrWifiRouterCtrlWapiRxPktReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, signalLength__, signal__, dataLength__, data__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiUnicastFilterReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWapiUnicastFilterReqCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiRouterCtrlWapiUnicastFilterReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWapiUnicastFilterReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WAPI_UNICAST_FILTER_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlWapiUnicastFilterReqSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiRouterCtrlWapiUnicastFilterReq *msg__; \
+        CsrWifiRouterCtrlWapiUnicastFilterReqCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWapiUnicastFilterReqSend(src__, interfaceTag__, status__) \
+    CsrWifiRouterCtrlWapiUnicastFilterReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiUnicastTxEncryptIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    clientData   -
+    interfaceTag -
+    dataLength   -
+    data         -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWapiUnicastTxEncryptIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, dataLength__, data__) \
+    msg__ = (CsrWifiRouterCtrlWapiUnicastTxEncryptInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWapiUnicastTxEncryptInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WAPI_UNICAST_TX_ENCRYPT_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->dataLength = (dataLength__); \
+    msg__->data = (data__);
+
+#define CsrWifiRouterCtrlWapiUnicastTxEncryptIndSendTo(dst__, src__, clientData__, interfaceTag__, dataLength__, data__) \
+    { \
+        CsrWifiRouterCtrlWapiUnicastTxEncryptInd *msg__; \
+        CsrWifiRouterCtrlWapiUnicastTxEncryptIndCreate(msg__, dst__, src__, clientData__, interfaceTag__, dataLength__, data__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWapiUnicastTxEncryptIndSend(dst__, clientData__, interfaceTag__, dataLength__, data__) \
+    CsrWifiRouterCtrlWapiUnicastTxEncryptIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, interfaceTag__, dataLength__, data__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiUnicastTxPktReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+    dataLength   -
+    data         -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWapiUnicastTxPktReqCreate(msg__, dst__, src__, interfaceTag__, dataLength__, data__) \
+    msg__ = (CsrWifiRouterCtrlWapiUnicastTxPktReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWapiUnicastTxPktReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WAPI_UNICAST_TX_PKT_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->dataLength = (dataLength__); \
+    msg__->data = (data__);
+
+#define CsrWifiRouterCtrlWapiUnicastTxPktReqSendTo(dst__, src__, interfaceTag__, dataLength__, data__) \
+    { \
+        CsrWifiRouterCtrlWapiUnicastTxPktReq *msg__; \
+        CsrWifiRouterCtrlWapiUnicastTxPktReqCreate(msg__, dst__, src__, interfaceTag__, dataLength__, data__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWapiUnicastTxPktReqSend(src__, interfaceTag__, dataLength__, data__) \
+    CsrWifiRouterCtrlWapiUnicastTxPktReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, dataLength__, data__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOffReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue      - Message Source Task Queue (Cfm's will be sent to this Queue)
+    clientData -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWifiOffReqCreate(msg__, dst__, src__, clientData__) \
+    msg__ = (CsrWifiRouterCtrlWifiOffReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOffReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WIFI_OFF_REQ, dst__, src__); \
+    msg__->clientData = (clientData__);
+
+#define CsrWifiRouterCtrlWifiOffReqSendTo(dst__, src__, clientData__) \
+    { \
+        CsrWifiRouterCtrlWifiOffReq *msg__; \
+        CsrWifiRouterCtrlWifiOffReqCreate(msg__, dst__, src__, clientData__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWifiOffReqSend(src__, clientData__) \
+    CsrWifiRouterCtrlWifiOffReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, clientData__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOffIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue             - Destination Task Queue
+    clientData        -
+    controlIndication -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWifiOffIndCreate(msg__, dst__, src__, clientData__, controlIndication__) \
+    msg__ = (CsrWifiRouterCtrlWifiOffInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOffInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WIFI_OFF_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->controlIndication = (controlIndication__);
+
+#define CsrWifiRouterCtrlWifiOffIndSendTo(dst__, src__, clientData__, controlIndication__) \
+    { \
+        CsrWifiRouterCtrlWifiOffInd *msg__; \
+        CsrWifiRouterCtrlWifiOffIndCreate(msg__, dst__, src__, clientData__, controlIndication__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWifiOffIndSend(dst__, clientData__, controlIndication__) \
+    CsrWifiRouterCtrlWifiOffIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, controlIndication__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOffResSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    clientData -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWifiOffResCreate(msg__, dst__, src__, clientData__) \
+    msg__ = (CsrWifiRouterCtrlWifiOffRes *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOffRes)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WIFI_OFF_RES, dst__, src__); \
+    msg__->clientData = (clientData__);
+
+#define CsrWifiRouterCtrlWifiOffResSendTo(dst__, src__, clientData__) \
+    { \
+        CsrWifiRouterCtrlWifiOffRes *msg__; \
+        CsrWifiRouterCtrlWifiOffResCreate(msg__, dst__, src__, clientData__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWifiOffResSend(src__, clientData__) \
+    CsrWifiRouterCtrlWifiOffResSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, clientData__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOffCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue      - Destination Task Queue
+    clientData -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWifiOffCfmCreate(msg__, dst__, src__, clientData__) \
+    msg__ = (CsrWifiRouterCtrlWifiOffCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOffCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WIFI_OFF_CFM, dst__, src__); \
+    msg__->clientData = (clientData__);
+
+#define CsrWifiRouterCtrlWifiOffCfmSendTo(dst__, src__, clientData__) \
+    { \
+        CsrWifiRouterCtrlWifiOffCfm *msg__; \
+        CsrWifiRouterCtrlWifiOffCfmCreate(msg__, dst__, src__, clientData__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWifiOffCfmSend(dst__, clientData__) \
+    CsrWifiRouterCtrlWifiOffCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOnReqSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue      - Message Source Task Queue (Cfm's will be sent to this Queue)
+    clientData -
+    dataLength - Number of bytes in the buffer pointed to by 'data'
+    data       - Pointer to the buffer containing 'dataLength' bytes
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWifiOnReqCreate(msg__, dst__, src__, clientData__, dataLength__, data__) \
+    msg__ = (CsrWifiRouterCtrlWifiOnReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOnReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WIFI_ON_REQ, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->dataLength = (dataLength__); \
+    msg__->data = (data__);
+
+#define CsrWifiRouterCtrlWifiOnReqSendTo(dst__, src__, clientData__, dataLength__, data__) \
+    { \
+        CsrWifiRouterCtrlWifiOnReq *msg__; \
+        CsrWifiRouterCtrlWifiOnReqCreate(msg__, dst__, src__, clientData__, dataLength__, data__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWifiOnReqSend(src__, clientData__, dataLength__, data__) \
+    CsrWifiRouterCtrlWifiOnReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, clientData__, dataLength__, data__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOnIndSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue      - Destination Task Queue
+    clientData -
+    status     -
+    versions   -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWifiOnIndCreate(msg__, dst__, src__, clientData__, status__, versions__) \
+    msg__ = (CsrWifiRouterCtrlWifiOnInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOnInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WIFI_ON_IND, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->status = (status__); \
+    msg__->versions = (versions__);
+
+#define CsrWifiRouterCtrlWifiOnIndSendTo(dst__, src__, clientData__, status__, versions__) \
+    { \
+        CsrWifiRouterCtrlWifiOnInd *msg__; \
+        CsrWifiRouterCtrlWifiOnIndCreate(msg__, dst__, src__, clientData__, status__, versions__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWifiOnIndSend(dst__, clientData__, status__, versions__) \
+    CsrWifiRouterCtrlWifiOnIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, status__, versions__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOnResSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    clientData          -
+    status              -
+    numInterfaceAddress -
+    stationMacAddress   - array size 1 MUST match CSR_WIFI_NUM_INTERFACES
+    smeVersions         -
+    scheduledInterrupt  -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWifiOnResCreate(msg__, dst__, src__, clientData__, status__, numInterfaceAddress__, stationMacAddress__, smeVersions__, scheduledInterrupt__) \
+    msg__ = (CsrWifiRouterCtrlWifiOnRes *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOnRes)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WIFI_ON_RES, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->status = (status__); \
+    msg__->numInterfaceAddress = (numInterfaceAddress__); \
+    CsrMemCpy(msg__->stationMacAddress, (stationMacAddress__), sizeof(CsrWifiMacAddress) * 2); \
+    msg__->smeVersions = (smeVersions__); \
+    msg__->scheduledInterrupt = (scheduledInterrupt__);
+
+#define CsrWifiRouterCtrlWifiOnResSendTo(dst__, src__, clientData__, status__, numInterfaceAddress__, stationMacAddress__, smeVersions__, scheduledInterrupt__) \
+    { \
+        CsrWifiRouterCtrlWifiOnRes *msg__; \
+        CsrWifiRouterCtrlWifiOnResCreate(msg__, dst__, src__, clientData__, status__, numInterfaceAddress__, stationMacAddress__, smeVersions__, scheduledInterrupt__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWifiOnResSend(src__, clientData__, status__, numInterfaceAddress__, stationMacAddress__, smeVersions__, scheduledInterrupt__) \
+    CsrWifiRouterCtrlWifiOnResSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, clientData__, status__, numInterfaceAddress__, stationMacAddress__, smeVersions__, scheduledInterrupt__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOnCfmSend
+
+  DESCRIPTION
+
+  PARAMETERS
+    queue      - Destination Task Queue
+    clientData -
+    status     -
+
+*******************************************************************************/
+#define CsrWifiRouterCtrlWifiOnCfmCreate(msg__, dst__, src__, clientData__, status__) \
+    msg__ = (CsrWifiRouterCtrlWifiOnCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOnCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_CTRL_PRIM, CSR_WIFI_ROUTER_CTRL_WIFI_ON_CFM, dst__, src__); \
+    msg__->clientData = (clientData__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterCtrlWifiOnCfmSendTo(dst__, src__, clientData__, status__) \
+    { \
+        CsrWifiRouterCtrlWifiOnCfm *msg__; \
+        CsrWifiRouterCtrlWifiOnCfmCreate(msg__, dst__, src__, clientData__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_CTRL_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterCtrlWifiOnCfmSend(dst__, clientData__, status__) \
+    CsrWifiRouterCtrlWifiOnCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, clientData__, status__)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_ROUTER_CTRL_LIB_H__ */
diff --git a/drivers/staging/csr/csr_wifi_router_ctrl_prim.h b/drivers/staging/csr/csr_wifi_router_ctrl_prim.h
new file mode 100644
index 0000000..810482a
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_ctrl_prim.h
@@ -0,0 +1,2122 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_ROUTER_CTRL_PRIM_H__
+#define CSR_WIFI_ROUTER_CTRL_PRIM_H__
+
+#include "csr_types.h"
+#include "csr_prim_defs.h"
+#include "csr_sched.h"
+#include "csr_wifi_common.h"
+#include "csr_result.h"
+#include "csr_wifi_fsm_event.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CSR_WIFI_ROUTER_CTRL_PRIM                                       (0x0401)
+
+typedef CsrPrim CsrWifiRouterCtrlPrim;
+
+typedef CsrResult (*CsrWifiRouterCtrlRawSdioByteWrite)(CsrUint8 func, CsrUint32 address, CsrUint8 data);
+typedef CsrResult (*CsrWifiRouterCtrlRawSdioByteRead)(CsrUint8 func, CsrUint32 address, CsrUint8 *pdata);
+typedef CsrResult (*CsrWifiRouterCtrlRawSdioFirmwareDownload)(CsrUint32 length, const CsrUint8 *pdata);
+typedef CsrResult (*CsrWifiRouterCtrlRawSdioReset)(void);
+typedef CsrResult (*CsrWifiRouterCtrlRawSdioCoreDumpPrepare)(CsrBool suspendSme);
+typedef CsrResult (*CsrWifiRouterCtrlRawSdioByteBlockRead)(CsrUint8 func, CsrUint32 address, CsrUint8 *pdata, CsrUint32 length);
+typedef CsrResult (*CsrWifiRouterCtrlRawSdioGpRead16)(CsrUint8 func, CsrUint32 address, CsrUint16 *pdata);
+typedef CsrResult (*CsrWifiRouterCtrlRawSdioGpWrite16)(CsrUint8 func, CsrUint32 address, CsrUint16 data);
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlBlockAckRole
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ORIGINATOR
+                   -
+    CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_RECIPIENT
+                   -
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterCtrlBlockAckRole;
+#define CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ORIGINATOR   ((CsrWifiRouterCtrlBlockAckRole) 0x00)
+#define CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_RECIPIENT    ((CsrWifiRouterCtrlBlockAckRole) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlControlIndication
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_CONTROL_INDICATION_ERROR
+                   -
+    CSR_WIFI_ROUTER_CTRL_CONTROL_INDICATION_EXIT
+                   -
+    CSR_WIFI_ROUTER_CTRL_CONTROL_INDICATION_USER_REQUESTED
+                   -
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterCtrlControlIndication;
+#define CSR_WIFI_ROUTER_CTRL_CONTROL_INDICATION_ERROR            ((CsrWifiRouterCtrlControlIndication) 0x01)
+#define CSR_WIFI_ROUTER_CTRL_CONTROL_INDICATION_EXIT             ((CsrWifiRouterCtrlControlIndication) 0x02)
+#define CSR_WIFI_ROUTER_CTRL_CONTROL_INDICATION_USER_REQUESTED   ((CsrWifiRouterCtrlControlIndication) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlListAction
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_LIST_ACTION_GET
+                   -
+    CSR_WIFI_ROUTER_CTRL_LIST_ACTION_ADD
+                   -
+    CSR_WIFI_ROUTER_CTRL_LIST_ACTION_REMOVE
+                   -
+    CSR_WIFI_ROUTER_CTRL_LIST_ACTION_FLUSH
+                   -
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterCtrlListAction;
+#define CSR_WIFI_ROUTER_CTRL_LIST_ACTION_GET      ((CsrWifiRouterCtrlListAction) 0x00)
+#define CSR_WIFI_ROUTER_CTRL_LIST_ACTION_ADD      ((CsrWifiRouterCtrlListAction) 0x01)
+#define CSR_WIFI_ROUTER_CTRL_LIST_ACTION_REMOVE   ((CsrWifiRouterCtrlListAction) 0x02)
+#define CSR_WIFI_ROUTER_CTRL_LIST_ACTION_FLUSH    ((CsrWifiRouterCtrlListAction) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlLowPowerMode
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_LOW_POWER_MODE_DISABLED
+                   -
+    CSR_WIFI_ROUTER_CTRL_LOW_POWER_MODE_ENABLED
+                   -
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiRouterCtrlLowPowerMode;
+#define CSR_WIFI_ROUTER_CTRL_LOW_POWER_MODE_DISABLED   ((CsrWifiRouterCtrlLowPowerMode) 0x0000)
+#define CSR_WIFI_ROUTER_CTRL_LOW_POWER_MODE_ENABLED    ((CsrWifiRouterCtrlLowPowerMode) 0x0001)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlMediaStatus
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_MEDIA_STATUS_CONNECTED
+                   -
+    CSR_WIFI_ROUTER_CTRL_MEDIA_STATUS_DISCONNECTED
+                   -
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterCtrlMediaStatus;
+#define CSR_WIFI_ROUTER_CTRL_MEDIA_STATUS_CONNECTED      ((CsrWifiRouterCtrlMediaStatus) 0x00)
+#define CSR_WIFI_ROUTER_CTRL_MEDIA_STATUS_DISCONNECTED   ((CsrWifiRouterCtrlMediaStatus) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlMode
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_MODE_NONE    -
+    CSR_WIFI_ROUTER_CTRL_MODE_IBSS    -
+    CSR_WIFI_ROUTER_CTRL_MODE_STA     -
+    CSR_WIFI_ROUTER_CTRL_MODE_AP      -
+    CSR_WIFI_ROUTER_CTRL_MODE_MONITOR -
+    CSR_WIFI_ROUTER_CTRL_MODE_AMP     -
+    CSR_WIFI_ROUTER_CTRL_MODE_P2P     -
+    CSR_WIFI_ROUTER_CTRL_MODE_P2PGO   -
+    CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI  -
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterCtrlMode;
+#define CSR_WIFI_ROUTER_CTRL_MODE_NONE      ((CsrWifiRouterCtrlMode) 0x00)
+#define CSR_WIFI_ROUTER_CTRL_MODE_IBSS      ((CsrWifiRouterCtrlMode) 0x01)
+#define CSR_WIFI_ROUTER_CTRL_MODE_STA       ((CsrWifiRouterCtrlMode) 0x02)
+#define CSR_WIFI_ROUTER_CTRL_MODE_AP        ((CsrWifiRouterCtrlMode) 0x03)
+#define CSR_WIFI_ROUTER_CTRL_MODE_MONITOR   ((CsrWifiRouterCtrlMode) 0x04)
+#define CSR_WIFI_ROUTER_CTRL_MODE_AMP       ((CsrWifiRouterCtrlMode) 0x05)
+#define CSR_WIFI_ROUTER_CTRL_MODE_P2P       ((CsrWifiRouterCtrlMode) 0x06)
+#define CSR_WIFI_ROUTER_CTRL_MODE_P2PGO     ((CsrWifiRouterCtrlMode) 0x07)
+#define CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI    ((CsrWifiRouterCtrlMode) 0x08)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerStatus
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE
+                   -
+    CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE
+                   -
+    CSR_WIFI_ROUTER_CTRL_PEER_DISCONNECTED
+                   -
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterCtrlPeerStatus;
+#define CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE       ((CsrWifiRouterCtrlPeerStatus) 0x00)
+#define CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE   ((CsrWifiRouterCtrlPeerStatus) 0x01)
+#define CSR_WIFI_ROUTER_CTRL_PEER_DISCONNECTED           ((CsrWifiRouterCtrlPeerStatus) 0x02)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPortAction
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN
+                   -
+    CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD
+                   -
+    CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_BLOCK
+                   -
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiRouterCtrlPortAction;
+#define CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN             ((CsrWifiRouterCtrlPortAction) 0x0000)
+#define CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD   ((CsrWifiRouterCtrlPortAction) 0x0001)
+#define CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_BLOCK     ((CsrWifiRouterCtrlPortAction) 0x0002)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPowersaveType
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_AC_BK_PS_INFO_PRESENT
+                   - If set, AC BK PS info is present in b4 and b5
+    CSR_WIFI_ROUTER_CTRL_AC_BE_PS_INFO_PRESENT
+                   - If set, AC BE PS info is present in b6 and b7
+    CSR_WIFI_ROUTER_CTRL_AC_VI_PS_INFO_PRESENT
+                   - If set, AC VI PS info is present in b8 and b9
+    CSR_WIFI_ROUTER_CTRL_AC_VO_PS_INFO_PRESENT
+                   - If set, AC VO PS info is present in b10 and b11
+    CSR_WIFI_ROUTER_CTRL_AC_BK_TRIGGER_ENABLED
+                   -
+    CSR_WIFI_ROUTER_CTRL_AC_BK_DELIVERY_ENABLED
+                   -
+    CSR_WIFI_ROUTER_CTRL_AC_BE_TRIGGER_ENABLED
+                   -
+    CSR_WIFI_ROUTER_CTRL_AC_BE_DELIVERY_ENABLED
+                   -
+    CSR_WIFI_ROUTER_CTRL_AC_VI_TRIGGER_ENABLED
+                   -
+    CSR_WIFI_ROUTER_CTRL_AC_VI_DELIVERY_ENABLED
+                   -
+    CSR_WIFI_ROUTER_CTRL_AC_VO_TRIGGER_ENABLED
+                   -
+    CSR_WIFI_ROUTER_CTRL_AC_VO_DELIVERY_ENABLED
+                   -
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiRouterCtrlPowersaveType;
+#define CSR_WIFI_ROUTER_CTRL_AC_BK_PS_INFO_PRESENT    ((CsrWifiRouterCtrlPowersaveType) 0x0001)
+#define CSR_WIFI_ROUTER_CTRL_AC_BE_PS_INFO_PRESENT    ((CsrWifiRouterCtrlPowersaveType) 0x0002)
+#define CSR_WIFI_ROUTER_CTRL_AC_VI_PS_INFO_PRESENT    ((CsrWifiRouterCtrlPowersaveType) 0x0004)
+#define CSR_WIFI_ROUTER_CTRL_AC_VO_PS_INFO_PRESENT    ((CsrWifiRouterCtrlPowersaveType) 0x0008)
+#define CSR_WIFI_ROUTER_CTRL_AC_BK_TRIGGER_ENABLED    ((CsrWifiRouterCtrlPowersaveType) 0x0010)
+#define CSR_WIFI_ROUTER_CTRL_AC_BK_DELIVERY_ENABLED   ((CsrWifiRouterCtrlPowersaveType) 0x0020)
+#define CSR_WIFI_ROUTER_CTRL_AC_BE_TRIGGER_ENABLED    ((CsrWifiRouterCtrlPowersaveType) 0x0040)
+#define CSR_WIFI_ROUTER_CTRL_AC_BE_DELIVERY_ENABLED   ((CsrWifiRouterCtrlPowersaveType) 0x0080)
+#define CSR_WIFI_ROUTER_CTRL_AC_VI_TRIGGER_ENABLED    ((CsrWifiRouterCtrlPowersaveType) 0x0100)
+#define CSR_WIFI_ROUTER_CTRL_AC_VI_DELIVERY_ENABLED   ((CsrWifiRouterCtrlPowersaveType) 0x0200)
+#define CSR_WIFI_ROUTER_CTRL_AC_VO_TRIGGER_ENABLED    ((CsrWifiRouterCtrlPowersaveType) 0x0400)
+#define CSR_WIFI_ROUTER_CTRL_AC_VO_DELIVERY_ENABLED   ((CsrWifiRouterCtrlPowersaveType) 0x0800)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlProtocolDirection
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_RX
+                   -
+    CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX
+                   -
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiRouterCtrlProtocolDirection;
+#define CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_RX   ((CsrWifiRouterCtrlProtocolDirection) 0x0000)
+#define CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX   ((CsrWifiRouterCtrlProtocolDirection) 0x0001)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlQoSControl
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_QOS_CONTROL_OFF
+                   -
+    CSR_WIFI_ROUTER_CTRL_QOS_CONTROL_WMM_ON
+                   -
+    CSR_WIFI_ROUTER_CTRL_QOS_CONTROL_80211_ON
+                   -
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiRouterCtrlQoSControl;
+#define CSR_WIFI_ROUTER_CTRL_QOS_CONTROL_OFF        ((CsrWifiRouterCtrlQoSControl) 0x0000)
+#define CSR_WIFI_ROUTER_CTRL_QOS_CONTROL_WMM_ON     ((CsrWifiRouterCtrlQoSControl) 0x0001)
+#define CSR_WIFI_ROUTER_CTRL_QOS_CONTROL_80211_ON   ((CsrWifiRouterCtrlQoSControl) 0x0002)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlQueueConfig
+
+  DESCRIPTION
+    Defines which Queues are enabled for use.
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_QUEUE_BE_ENABLE
+                   -
+    CSR_WIFI_ROUTER_CTRL_QUEUE_BK_ENABLE
+                   -
+    CSR_WIFI_ROUTER_CTRL_QUEUE_VI_ENABLE
+                   -
+    CSR_WIFI_ROUTER_CTRL_QUEUE_VO_ENABLE
+                   -
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterCtrlQueueConfig;
+#define CSR_WIFI_ROUTER_CTRL_QUEUE_BE_ENABLE   ((CsrWifiRouterCtrlQueueConfig) 0x01)
+#define CSR_WIFI_ROUTER_CTRL_QUEUE_BK_ENABLE   ((CsrWifiRouterCtrlQueueConfig) 0x02)
+#define CSR_WIFI_ROUTER_CTRL_QUEUE_VI_ENABLE   ((CsrWifiRouterCtrlQueueConfig) 0x04)
+#define CSR_WIFI_ROUTER_CTRL_QUEUE_VO_ENABLE   ((CsrWifiRouterCtrlQueueConfig) 0x08)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficConfigType
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_RESET
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_FILTER
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_CLS
+                   -
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiRouterCtrlTrafficConfigType;
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_RESET    ((CsrWifiRouterCtrlTrafficConfigType) 0x0000)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_FILTER   ((CsrWifiRouterCtrlTrafficConfigType) 0x0001)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_CLS      ((CsrWifiRouterCtrlTrafficConfigType) 0x0002)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficPacketType
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_NONE
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_EAPOL
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP_ACK
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_ARP
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_AIRONET
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_ALL
+                   -
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiRouterCtrlTrafficPacketType;
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_NONE       ((CsrWifiRouterCtrlTrafficPacketType) 0x0000)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_EAPOL      ((CsrWifiRouterCtrlTrafficPacketType) 0x0001)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP       ((CsrWifiRouterCtrlTrafficPacketType) 0x0002)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_DHCP_ACK   ((CsrWifiRouterCtrlTrafficPacketType) 0x0004)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_ARP        ((CsrWifiRouterCtrlTrafficPacketType) 0x0008)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_AIRONET    ((CsrWifiRouterCtrlTrafficPacketType) 0x0010)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM     ((CsrWifiRouterCtrlTrafficPacketType) 0x0020)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_ALL        ((CsrWifiRouterCtrlTrafficPacketType) 0x00FF)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficType
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_TYPE_OCCASIONAL
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_TYPE_BURSTY
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_TYPE_PERIODIC
+                   -
+    CSR_WIFI_ROUTER_CTRL_TRAFFIC_TYPE_CONTINUOUS
+                   -
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterCtrlTrafficType;
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_TYPE_OCCASIONAL   ((CsrWifiRouterCtrlTrafficType) 0x00)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_TYPE_BURSTY       ((CsrWifiRouterCtrlTrafficType) 0x01)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_TYPE_PERIODIC     ((CsrWifiRouterCtrlTrafficType) 0x02)
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_TYPE_CONTINUOUS   ((CsrWifiRouterCtrlTrafficType) 0x03)
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerRecordHandle
+
+  DESCRIPTION
+
+*******************************************************************************/
+typedef CsrUint32 CsrWifiRouterCtrlPeerRecordHandle;
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPowersaveTypeMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by
+    CsrWifiRouterCtrlPowersaveType
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiRouterCtrlPowersaveTypeMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlQueueConfigMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiRouterCtrlQueueConfig
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterCtrlQueueConfigMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlRequestorInfo
+
+  DESCRIPTION
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiRouterCtrlRequestorInfo;
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficStreamId
+
+  DESCRIPTION
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterCtrlTrafficStreamId;
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlSmeVersions
+
+  DESCRIPTION
+
+  MEMBERS
+    firmwarePatch -
+    smeBuild      -
+    smeHip        -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint32      firmwarePatch;
+    CsrCharString *smeBuild;
+    CsrUint32      smeHip;
+} CsrWifiRouterCtrlSmeVersions;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlStaInfo
+
+  DESCRIPTION
+
+  MEMBERS
+    wmmOrQosEnabled     -
+    powersaveMode       -
+    maxSpLength         -
+    listenIntervalInTus -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrBool                            wmmOrQosEnabled;
+    CsrWifiRouterCtrlPowersaveTypeMask powersaveMode;
+    CsrUint8                           maxSpLength;
+    CsrUint16                          listenIntervalInTus;
+} CsrWifiRouterCtrlStaInfo;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficFilter
+
+  DESCRIPTION
+
+  MEMBERS
+    etherType     -
+    ipType        -
+    udpSourcePort -
+    udpDestPort   -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint32 etherType;
+    CsrUint8  ipType;
+    CsrUint32 udpSourcePort;
+    CsrUint32 udpDestPort;
+} CsrWifiRouterCtrlTrafficFilter;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficStats
+
+  DESCRIPTION
+
+  MEMBERS
+    rxMeanRate   - Mean rx data rate over the interval
+    rxFramesNum  - Keep number of Rx frames per second, for CYCLE_3.
+    txFramesNum  - Keep number of Tx frames per second, for CYCLE_3.
+    rxBytesCount - Keep calculated Rx throughput per second, for CYCLE_2.
+    txBytesCount - Keep calculated Tx throughput per second, for CYCLE_2.
+    intervals    - array size 11 MUST match TA_INTERVALS_NUM
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint32 rxMeanRate;
+    CsrUint32 rxFramesNum;
+    CsrUint32 txFramesNum;
+    CsrUint32 rxBytesCount;
+    CsrUint32 txBytesCount;
+    CsrUint8  intervals[11];
+} CsrWifiRouterCtrlTrafficStats;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlVersions
+
+  DESCRIPTION
+
+  MEMBERS
+    chipId        -
+    chipVersion   -
+    firmwareBuild -
+    firmwareHip   -
+    routerBuild   -
+    routerHip     -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint32      chipId;
+    CsrUint32      chipVersion;
+    CsrUint32      firmwareBuild;
+    CsrUint32      firmwareHip;
+    CsrCharString *routerBuild;
+    CsrUint32      routerHip;
+} CsrWifiRouterCtrlVersions;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficConfig
+
+  DESCRIPTION
+
+  MEMBERS
+    packetFilter -
+    customFilter -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint16                      packetFilter;
+    CsrWifiRouterCtrlTrafficFilter customFilter;
+} CsrWifiRouterCtrlTrafficConfig;
+
+
+/* Downstream */
+#define CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST            (0x0000)
+
+#define CSR_WIFI_ROUTER_CTRL_CONFIGURE_POWER_MODE_REQ     ((CsrWifiRouterCtrlPrim) (0x0000 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_HIP_REQ                      ((CsrWifiRouterCtrlPrim) (0x0001 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_MEDIA_STATUS_REQ             ((CsrWifiRouterCtrlPrim) (0x0002 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_MULTICAST_ADDRESS_RES        ((CsrWifiRouterCtrlPrim) (0x0003 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_PORT_CONFIGURE_REQ           ((CsrWifiRouterCtrlPrim) (0x0004 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_QOS_CONTROL_REQ              ((CsrWifiRouterCtrlPrim) (0x0005 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_SUSPEND_RES                  ((CsrWifiRouterCtrlPrim) (0x0006 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_TCLAS_ADD_REQ                ((CsrWifiRouterCtrlPrim) (0x0007 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_RESUME_RES                   ((CsrWifiRouterCtrlPrim) (0x0008 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_RAW_SDIO_DEINITIALISE_REQ    ((CsrWifiRouterCtrlPrim) (0x0009 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_RAW_SDIO_INITIALISE_REQ      ((CsrWifiRouterCtrlPrim) (0x000A + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_TCLAS_DEL_REQ                ((CsrWifiRouterCtrlPrim) (0x000B + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_CLASSIFICATION_REQ   ((CsrWifiRouterCtrlPrim) (0x000C + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_REQ           ((CsrWifiRouterCtrlPrim) (0x000D + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WIFI_OFF_REQ                 ((CsrWifiRouterCtrlPrim) (0x000E + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WIFI_OFF_RES                 ((CsrWifiRouterCtrlPrim) (0x000F + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WIFI_ON_REQ                  ((CsrWifiRouterCtrlPrim) (0x0010 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WIFI_ON_RES                  ((CsrWifiRouterCtrlPrim) (0x0011 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_M4_TRANSMIT_REQ              ((CsrWifiRouterCtrlPrim) (0x0012 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_MODE_SET_REQ                 ((CsrWifiRouterCtrlPrim) (0x0013 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_PEER_ADD_REQ                 ((CsrWifiRouterCtrlPrim) (0x0014 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_PEER_DEL_REQ                 ((CsrWifiRouterCtrlPrim) (0x0015 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_PEER_UPDATE_REQ              ((CsrWifiRouterCtrlPrim) (0x0016 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_CAPABILITIES_REQ             ((CsrWifiRouterCtrlPrim) (0x0017 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ENABLE_REQ         ((CsrWifiRouterCtrlPrim) (0x0018 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_DISABLE_REQ        ((CsrWifiRouterCtrlPrim) (0x0019 + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WAPI_RX_PKT_REQ              ((CsrWifiRouterCtrlPrim) (0x001A + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WAPI_MULTICAST_FILTER_REQ    ((CsrWifiRouterCtrlPrim) (0x001B + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WAPI_UNICAST_FILTER_REQ      ((CsrWifiRouterCtrlPrim) (0x001C + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WAPI_UNICAST_TX_PKT_REQ      ((CsrWifiRouterCtrlPrim) (0x001D + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WAPI_FILTER_REQ              ((CsrWifiRouterCtrlPrim) (0x001E + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST))
+
+
+#define CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_HIGHEST           (0x001E + CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST)
+
+/* Upstream */
+#define CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST              (0x0000 + CSR_PRIM_UPSTREAM)
+
+#define CSR_WIFI_ROUTER_CTRL_HIP_IND                      ((CsrWifiRouterCtrlPrim)(0x0000 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_MULTICAST_ADDRESS_IND        ((CsrWifiRouterCtrlPrim)(0x0001 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_PORT_CONFIGURE_CFM           ((CsrWifiRouterCtrlPrim)(0x0002 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_RESUME_IND                   ((CsrWifiRouterCtrlPrim)(0x0003 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_SUSPEND_IND                  ((CsrWifiRouterCtrlPrim)(0x0004 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_TCLAS_ADD_CFM                ((CsrWifiRouterCtrlPrim)(0x0005 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_RAW_SDIO_DEINITIALISE_CFM    ((CsrWifiRouterCtrlPrim)(0x0006 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_RAW_SDIO_INITIALISE_CFM      ((CsrWifiRouterCtrlPrim)(0x0007 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_TCLAS_DEL_CFM                ((CsrWifiRouterCtrlPrim)(0x0008 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_PROTOCOL_IND         ((CsrWifiRouterCtrlPrim)(0x0009 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_TRAFFIC_SAMPLE_IND           ((CsrWifiRouterCtrlPrim)(0x000A + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WIFI_OFF_IND                 ((CsrWifiRouterCtrlPrim)(0x000B + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WIFI_OFF_CFM                 ((CsrWifiRouterCtrlPrim)(0x000C + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WIFI_ON_IND                  ((CsrWifiRouterCtrlPrim)(0x000D + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WIFI_ON_CFM                  ((CsrWifiRouterCtrlPrim)(0x000E + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_M4_READY_TO_SEND_IND         ((CsrWifiRouterCtrlPrim)(0x000F + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_M4_TRANSMITTED_IND           ((CsrWifiRouterCtrlPrim)(0x0010 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_MIC_FAILURE_IND              ((CsrWifiRouterCtrlPrim)(0x0011 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_CONNECTED_IND                ((CsrWifiRouterCtrlPrim)(0x0012 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_PEER_ADD_CFM                 ((CsrWifiRouterCtrlPrim)(0x0013 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_PEER_DEL_CFM                 ((CsrWifiRouterCtrlPrim)(0x0014 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_UNEXPECTED_FRAME_IND         ((CsrWifiRouterCtrlPrim)(0x0015 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_PEER_UPDATE_CFM              ((CsrWifiRouterCtrlPrim)(0x0016 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_CAPABILITIES_CFM             ((CsrWifiRouterCtrlPrim)(0x0017 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ENABLE_CFM         ((CsrWifiRouterCtrlPrim)(0x0018 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_DISABLE_CFM        ((CsrWifiRouterCtrlPrim)(0x0019 + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ERROR_IND          ((CsrWifiRouterCtrlPrim)(0x001A + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_STA_INACTIVE_IND             ((CsrWifiRouterCtrlPrim)(0x001B + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WAPI_RX_MIC_CHECK_IND        ((CsrWifiRouterCtrlPrim)(0x001C + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_MODE_SET_CFM                 ((CsrWifiRouterCtrlPrim)(0x001D + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_CTRL_WAPI_UNICAST_TX_ENCRYPT_IND  ((CsrWifiRouterCtrlPrim)(0x001E + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST))
+
+#define CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_HIGHEST             (0x001E + CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST)
+
+#define CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_COUNT             (CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_HIGHEST + 1 - CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST)
+#define CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_COUNT               (CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_HIGHEST   + 1 - CSR_WIFI_ROUTER_CTRL_PRIM_UPSTREAM_LOWEST)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlConfigurePowerModeReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+    mode       -
+    wakeHost   -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrWifiRouterCtrlLowPowerMode  mode;
+    CsrBool                        wakeHost;
+} CsrWifiRouterCtrlConfigurePowerModeReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlHipReq
+
+  DESCRIPTION
+    This primitive is used for transferring MLME messages to the HIP.
+
+  MEMBERS
+    common            - Common header for use with the CsrWifiFsm Module
+    mlmeCommandLength - Length of the MLME signal
+    mlmeCommand       - Pointer to the MLME signal
+    dataRef1Length    - Length of the dataRef1 bulk data
+    dataRef1          - Pointer to the bulk data 1
+    dataRef2Length    - Length of the dataRef2 bulk data
+    dataRef2          - Pointer to the bulk data 2
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       mlmeCommandLength;
+    CsrUint8       *mlmeCommand;
+    CsrUint16       dataRef1Length;
+    CsrUint8       *dataRef1;
+    CsrUint16       dataRef2Length;
+    CsrUint8       *dataRef2;
+} CsrWifiRouterCtrlHipReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlMediaStatusReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    clientData   -
+    mediaStatus  -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrWifiRouterCtrlMediaStatus   mediaStatus;
+} CsrWifiRouterCtrlMediaStatusReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlMulticastAddressRes
+
+  DESCRIPTION
+
+  MEMBERS
+    common            - Common header for use with the CsrWifiFsm Module
+    interfaceTag      -
+    clientData        -
+    status            -
+    action            -
+    getAddressesCount -
+    getAddresses      -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrResult                      status;
+    CsrWifiRouterCtrlListAction    action;
+    CsrUint8                       getAddressesCount;
+    CsrWifiMacAddress             *getAddresses;
+} CsrWifiRouterCtrlMulticastAddressRes;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPortConfigureReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common                 - Common header for use with the CsrWifiFsm Module
+    interfaceTag           -
+    clientData             -
+    uncontrolledPortAction -
+    controlledPortAction   -
+    macAddress             -
+    setProtection          -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrWifiRouterCtrlPortAction    uncontrolledPortAction;
+    CsrWifiRouterCtrlPortAction    controlledPortAction;
+    CsrWifiMacAddress              macAddress;
+    CsrBool                        setProtection;
+} CsrWifiRouterCtrlPortConfigureReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlQosControlReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    clientData   -
+    control      -
+    queueConfig  -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                  common;
+    CsrUint16                        interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo   clientData;
+    CsrWifiRouterCtrlQoSControl      control;
+    CsrWifiRouterCtrlQueueConfigMask queueConfig;
+} CsrWifiRouterCtrlQosControlReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlSuspendRes
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+    status     -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrResult                      status;
+} CsrWifiRouterCtrlSuspendRes;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTclasAddReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    clientData   -
+    tclasLength  -
+    tclas        -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      tclasLength;
+    CsrUint8                      *tclas;
+} CsrWifiRouterCtrlTclasAddReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlResumeRes
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+    status     -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrResult                      status;
+} CsrWifiRouterCtrlResumeRes;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlRawSdioDeinitialiseReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+} CsrWifiRouterCtrlRawSdioDeinitialiseReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlRawSdioInitialiseReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+} CsrWifiRouterCtrlRawSdioInitialiseReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTclasDelReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    clientData   -
+    tclasLength  -
+    tclas        -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      tclasLength;
+    CsrUint8                      *tclas;
+} CsrWifiRouterCtrlTclasDelReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficClassificationReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    clientData   -
+    trafficType  -
+    period       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrWifiRouterCtrlTrafficType   trafficType;
+    CsrUint16                      period;
+} CsrWifiRouterCtrlTrafficClassificationReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficConfigReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common            - Common header for use with the CsrWifiFsm Module
+    interfaceTag      -
+    clientData        -
+    trafficConfigType -
+    config            -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                    common;
+    CsrUint16                          interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo     clientData;
+    CsrWifiRouterCtrlTrafficConfigType trafficConfigType;
+    CsrWifiRouterCtrlTrafficConfig     config;
+} CsrWifiRouterCtrlTrafficConfigReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOffReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+} CsrWifiRouterCtrlWifiOffReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOffRes
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+} CsrWifiRouterCtrlWifiOffRes;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOnReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+    dataLength - Number of bytes in the buffer pointed to by 'data'
+    data       - Pointer to the buffer containing 'dataLength' bytes
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint32                      dataLength;
+    CsrUint8                      *data;
+} CsrWifiRouterCtrlWifiOnReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOnRes
+
+  DESCRIPTION
+
+  MEMBERS
+    common              - Common header for use with the CsrWifiFsm Module
+    clientData          -
+    status              -
+    numInterfaceAddress -
+    stationMacAddress   - array size 1 MUST match CSR_WIFI_NUM_INTERFACES
+    smeVersions         -
+    scheduledInterrupt  -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrResult                      status;
+    CsrUint16                      numInterfaceAddress;
+    CsrWifiMacAddress              stationMacAddress[2];
+    CsrWifiRouterCtrlSmeVersions   smeVersions;
+    CsrBool                        scheduledInterrupt;
+} CsrWifiRouterCtrlWifiOnRes;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlM4TransmitReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    clientData   -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+} CsrWifiRouterCtrlM4TransmitReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlModeSetReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common              - Common header for use with the CsrWifiFsm Module
+    interfaceTag        -
+    clientData          -
+    mode                -
+    bssid               - BSSID of the network the device is going to be a part
+                          of
+    protection          - Set to TRUE if encryption is enabled for the
+                          connection/broadcast frames
+    intraBssDistEnabled - If set to TRUE, intra BSS destribution will be
+                          enabled. If set to FALSE, any unicast PDU which does
+                          not have the RA as the the local MAC address, shall be
+                          ignored. This field is interpreted by the receive if
+                          mode is set to CSR_WIFI_ROUTER_CTRL_MODE_P2PGO
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrWifiRouterCtrlMode          mode;
+    CsrWifiMacAddress              bssid;
+    CsrBool                        protection;
+    CsrBool                        intraBssDistEnabled;
+} CsrWifiRouterCtrlModeSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerAddReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   -
+    clientData     -
+    peerMacAddress -
+    associationId  -
+    staInfo        -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrWifiMacAddress              peerMacAddress;
+    CsrUint16                      associationId;
+    CsrWifiRouterCtrlStaInfo       staInfo;
+} CsrWifiRouterCtrlPeerAddReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerDelReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    interfaceTag     -
+    clientData       -
+    peerRecordHandle -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                   common;
+    CsrUint16                         interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo    clientData;
+    CsrWifiRouterCtrlPeerRecordHandle peerRecordHandle;
+} CsrWifiRouterCtrlPeerDelReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerUpdateReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    interfaceTag     -
+    clientData       -
+    peerRecordHandle -
+    powersaveMode    -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                    common;
+    CsrUint16                          interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo     clientData;
+    CsrWifiRouterCtrlPeerRecordHandle  peerRecordHandle;
+    CsrWifiRouterCtrlPowersaveTypeMask powersaveMode;
+} CsrWifiRouterCtrlPeerUpdateReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlCapabilitiesReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+} CsrWifiRouterCtrlCapabilitiesReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlBlockAckEnableReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    interfaceTag    -
+    clientData      -
+    macAddress      -
+    trafficStreamID -
+    role            -
+    bufferSize      -
+    timeout         -
+    ssn             -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                  common;
+    CsrUint16                        interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo   clientData;
+    CsrWifiMacAddress                macAddress;
+    CsrWifiRouterCtrlTrafficStreamId trafficStreamID;
+    CsrWifiRouterCtrlBlockAckRole    role;
+    CsrUint16                        bufferSize;
+    CsrUint16                        timeout;
+    CsrUint16                        ssn;
+} CsrWifiRouterCtrlBlockAckEnableReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlBlockAckDisableReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    interfaceTag    -
+    clientData      -
+    macAddress      -
+    trafficStreamID -
+    role            -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                  common;
+    CsrUint16                        interfaceTag;
+    CsrWifiRouterCtrlRequestorInfo   clientData;
+    CsrWifiMacAddress                macAddress;
+    CsrWifiRouterCtrlTrafficStreamId trafficStreamID;
+    CsrWifiRouterCtrlBlockAckRole    role;
+} CsrWifiRouterCtrlBlockAckDisableReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiRxPktReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    signalLength -
+    signal       -
+    dataLength   -
+    data         -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrUint16       signalLength;
+    CsrUint8       *signal;
+    CsrUint16       dataLength;
+    CsrUint8       *data;
+} CsrWifiRouterCtrlWapiRxPktReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiMulticastFilterReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrUint8        status;
+} CsrWifiRouterCtrlWapiMulticastFilterReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiUnicastFilterReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrUint8        status;
+} CsrWifiRouterCtrlWapiUnicastFilterReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiUnicastTxPktReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    dataLength   -
+    data         -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrUint16       dataLength;
+    CsrUint8       *data;
+} CsrWifiRouterCtrlWapiUnicastTxPktReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiFilterReq
+
+  DESCRIPTION
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    interfaceTag    -
+    isWapiConnected -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrBool         isWapiConnected;
+} CsrWifiRouterCtrlWapiFilterReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlHipInd
+
+  DESCRIPTION
+    This primitive is used for transferring MLME messages from the HIP.
+
+  MEMBERS
+    common            - Common header for use with the CsrWifiFsm Module
+    mlmeCommandLength - Length of the MLME signal
+    mlmeCommand       - Pointer to the MLME signal
+    dataRef1Length    - Length of the dataRef1 bulk data
+    dataRef1          - Pointer to the bulk data 1
+    dataRef2Length    - Length of the dataRef2 bulk data
+    dataRef2          - Pointer to the bulk data 2
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       mlmeCommandLength;
+    CsrUint8       *mlmeCommand;
+    CsrUint16       dataRef1Length;
+    CsrUint8       *dataRef1;
+    CsrUint16       dataRef2Length;
+    CsrUint8       *dataRef2;
+} CsrWifiRouterCtrlHipInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlMulticastAddressInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common            - Common header for use with the CsrWifiFsm Module
+    clientData        -
+    interfaceTag      -
+    action            -
+    setAddressesCount -
+    setAddresses      -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlListAction    action;
+    CsrUint8                       setAddressesCount;
+    CsrWifiMacAddress             *setAddresses;
+} CsrWifiRouterCtrlMulticastAddressInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPortConfigureCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    status       -
+    macAddress   -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrResult                      status;
+    CsrWifiMacAddress              macAddress;
+} CsrWifiRouterCtrlPortConfigureCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlResumeInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    clientData      -
+    powerMaintained -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrBool                        powerMaintained;
+} CsrWifiRouterCtrlResumeInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlSuspendInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common      - Common header for use with the CsrWifiFsm Module
+    clientData  -
+    hardSuspend -
+    d3Suspend   -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrBool                        hardSuspend;
+    CsrBool                        d3Suspend;
+} CsrWifiRouterCtrlSuspendInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTclasAddCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrResult                      status;
+} CsrWifiRouterCtrlTclasAddCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlRawSdioDeinitialiseCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+    result     -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrResult                      result;
+} CsrWifiRouterCtrlRawSdioDeinitialiseCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlRawSdioInitialiseCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    clientData       -
+    result           -
+    byteRead         -
+    byteWrite        -
+    firmwareDownload -
+    reset            -
+    coreDumpPrepare  -
+    byteBlockRead    -
+    gpRead16         -
+    gpWrite16        -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                          common;
+    CsrWifiRouterCtrlRequestorInfo           clientData;
+    CsrResult                                result;
+    CsrWifiRouterCtrlRawSdioByteRead         byteRead;
+    CsrWifiRouterCtrlRawSdioByteWrite        byteWrite;
+    CsrWifiRouterCtrlRawSdioFirmwareDownload firmwareDownload;
+    CsrWifiRouterCtrlRawSdioReset            reset;
+    CsrWifiRouterCtrlRawSdioCoreDumpPrepare  coreDumpPrepare;
+    CsrWifiRouterCtrlRawSdioByteBlockRead    byteBlockRead;
+    CsrWifiRouterCtrlRawSdioGpRead16         gpRead16;
+    CsrWifiRouterCtrlRawSdioGpWrite16        gpWrite16;
+} CsrWifiRouterCtrlRawSdioInitialiseCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTclasDelCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrResult                      status;
+} CsrWifiRouterCtrlTclasDelCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficProtocolInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    packetType   -
+    direction    -
+    srcAddress   -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                    common;
+    CsrWifiRouterCtrlRequestorInfo     clientData;
+    CsrUint16                          interfaceTag;
+    CsrWifiRouterCtrlTrafficPacketType packetType;
+    CsrWifiRouterCtrlProtocolDirection direction;
+    CsrWifiMacAddress                  srcAddress;
+} CsrWifiRouterCtrlTrafficProtocolInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlTrafficSampleInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    stats        -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlTrafficStats  stats;
+} CsrWifiRouterCtrlTrafficSampleInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOffInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common            - Common header for use with the CsrWifiFsm Module
+    clientData        -
+    controlIndication -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                    common;
+    CsrWifiRouterCtrlRequestorInfo     clientData;
+    CsrWifiRouterCtrlControlIndication controlIndication;
+} CsrWifiRouterCtrlWifiOffInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOffCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+} CsrWifiRouterCtrlWifiOffCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOnInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+    status     -
+    versions   -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrResult                      status;
+    CsrWifiRouterCtrlVersions      versions;
+} CsrWifiRouterCtrlWifiOnInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWifiOnCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    clientData -
+    status     -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrResult                      status;
+} CsrWifiRouterCtrlWifiOnCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlM4ReadyToSendInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    clientData     -
+    interfaceTag   -
+    peerMacAddress -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrWifiMacAddress              peerMacAddress;
+} CsrWifiRouterCtrlM4ReadyToSendInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlM4TransmittedInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    clientData     -
+    interfaceTag   -
+    peerMacAddress -
+    status         -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrWifiMacAddress              peerMacAddress;
+    CsrResult                      status;
+} CsrWifiRouterCtrlM4TransmittedInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlMicFailureInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    clientData     -
+    interfaceTag   -
+    peerMacAddress -
+    unicastPdu     -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrWifiMacAddress              peerMacAddress;
+    CsrBool                        unicastPdu;
+} CsrWifiRouterCtrlMicFailureInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlConnectedInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    clientData     -
+    interfaceTag   -
+    peerMacAddress -
+    peerStatus     -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrWifiMacAddress              peerMacAddress;
+    CsrWifiRouterCtrlPeerStatus    peerStatus;
+} CsrWifiRouterCtrlConnectedInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerAddCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    clientData       -
+    interfaceTag     -
+    peerMacAddress   -
+    peerRecordHandle -
+    status           -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                   common;
+    CsrWifiRouterCtrlRequestorInfo    clientData;
+    CsrUint16                         interfaceTag;
+    CsrWifiMacAddress                 peerMacAddress;
+    CsrWifiRouterCtrlPeerRecordHandle peerRecordHandle;
+    CsrResult                         status;
+} CsrWifiRouterCtrlPeerAddCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerDelCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrResult                      status;
+} CsrWifiRouterCtrlPeerDelCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlUnexpectedFrameInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    clientData     -
+    interfaceTag   -
+    peerMacAddress -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrWifiMacAddress              peerMacAddress;
+} CsrWifiRouterCtrlUnexpectedFrameInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlPeerUpdateCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrResult                      status;
+} CsrWifiRouterCtrlPeerUpdateCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlCapabilitiesCfm
+
+  DESCRIPTION
+    The router sends this primitive to confirm the size of the queues of the
+    HIP.
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    clientData       -
+    commandQueueSize - Size of command queue
+    trafficQueueSize - Size of traffic queue (per AC)
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      commandQueueSize;
+    CsrUint16                      trafficQueueSize;
+} CsrWifiRouterCtrlCapabilitiesCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlBlockAckEnableCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrResult                      status;
+} CsrWifiRouterCtrlBlockAckEnableCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlBlockAckDisableCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrResult                      status;
+} CsrWifiRouterCtrlBlockAckDisableCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlBlockAckErrorInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    clientData      -
+    interfaceTag    -
+    trafficStreamID -
+    peerMacAddress  -
+    status          -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                  common;
+    CsrWifiRouterCtrlRequestorInfo   clientData;
+    CsrUint16                        interfaceTag;
+    CsrWifiRouterCtrlTrafficStreamId trafficStreamID;
+    CsrWifiMacAddress                peerMacAddress;
+    CsrResult                        status;
+} CsrWifiRouterCtrlBlockAckErrorInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlStaInactiveInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    staAddress   -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrWifiMacAddress              staAddress;
+} CsrWifiRouterCtrlStaInactiveInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiRxMicCheckInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    signalLength -
+    signal       -
+    dataLength   -
+    data         -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrUint16                      signalLength;
+    CsrUint8                      *signal;
+    CsrUint16                      dataLength;
+    CsrUint8                      *data;
+} CsrWifiRouterCtrlWapiRxMicCheckInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlModeSetCfm
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    mode         -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrWifiRouterCtrlMode          mode;
+    CsrResult                      status;
+} CsrWifiRouterCtrlModeSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterCtrlWapiUnicastTxEncryptInd
+
+  DESCRIPTION
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    clientData   -
+    interfaceTag -
+    dataLength   -
+    data         -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrWifiRouterCtrlRequestorInfo clientData;
+    CsrUint16                      interfaceTag;
+    CsrUint16                      dataLength;
+    CsrUint8                      *data;
+} CsrWifiRouterCtrlWapiUnicastTxEncryptInd;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_ROUTER_CTRL_PRIM_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_router_ctrl_sef.c b/drivers/staging/csr/csr_wifi_router_ctrl_sef.c
new file mode 100644
index 0000000..33d92b6
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_ctrl_sef.c
@@ -0,0 +1,45 @@
+/*****************************************************************************
+
+  (c) Cambridge Silicon Radio Limited 2010
+  Confidential information of CSR
+
+  Refer to LICENSE.txt included with this source for details
+  on the license terms.
+
+ *****************************************************************************/
+#include "csr_wifi_router_ctrl_sef.h"
+
+const CsrWifiRouterCtrlStateHandlerType CsrWifiRouterCtrlDownstreamStateHandlers[CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_COUNT] =
+{
+    /* 0x0000 */ CsrWifiRouterCtrlConfigurePowerModeReqHandler,
+    /* 0x0001 */ CsrWifiRouterCtrlHipReqHandler,
+    /* 0x0002 */ CsrWifiRouterCtrlMediaStatusReqHandler,
+    /* 0x0003 */ CsrWifiRouterCtrlMulticastAddressResHandler,
+    /* 0x0004 */ CsrWifiRouterCtrlPortConfigureReqHandler,
+    /* 0x0005 */ CsrWifiRouterCtrlQosControlReqHandler,
+    /* 0x0006 */ CsrWifiRouterCtrlSuspendResHandler,
+    /* 0x0007 */ CsrWifiRouterCtrlTclasAddReqHandler,
+    /* 0x0008 */ CsrWifiRouterCtrlResumeResHandler,
+    /* 0x0009 */ CsrWifiRouterCtrlRawSdioDeinitialiseReqHandler,
+    /* 0x000A */ CsrWifiRouterCtrlRawSdioInitialiseReqHandler,
+    /* 0x000B */ CsrWifiRouterCtrlTclasDelReqHandler,
+    /* 0x000C */ CsrWifiRouterCtrlTrafficClassificationReqHandler,
+    /* 0x000D */ CsrWifiRouterCtrlTrafficConfigReqHandler,
+    /* 0x000E */ CsrWifiRouterCtrlWifiOffReqHandler,
+    /* 0x000F */ CsrWifiRouterCtrlWifiOffResHandler,
+    /* 0x0010 */ CsrWifiRouterCtrlWifiOnReqHandler,
+    /* 0x0011 */ CsrWifiRouterCtrlWifiOnResHandler,
+    /* 0x0012 */ CsrWifiRouterCtrlM4TransmitReqHandler,
+    /* 0x0013 */ CsrWifiRouterCtrlModeSetReqHandler,
+    /* 0x0014 */ CsrWifiRouterCtrlPeerAddReqHandler,
+    /* 0x0015 */ CsrWifiRouterCtrlPeerDelReqHandler,
+    /* 0x0016 */ CsrWifiRouterCtrlPeerUpdateReqHandler,
+    /* 0x0017 */ CsrWifiRouterCtrlCapabilitiesReqHandler,
+    /* 0x0018 */ CsrWifiRouterCtrlBlockAckEnableReqHandler,
+    /* 0x0019 */ CsrWifiRouterCtrlBlockAckDisableReqHandler,
+    /* 0x001A */ CsrWifiRouterCtrlWapiRxPktReqHandler,
+    /* 0x001B */ CsrWifiRouterCtrlWapiMulticastFilterReqHandler,
+    /* 0x001C */ CsrWifiRouterCtrlWapiUnicastFilterReqHandler,
+    /* 0x001D */ CsrWifiRouterCtrlWapiUnicastTxPktReqHandler,
+    /* 0x001E */ CsrWifiRouterCtrlWapiFilterReqHandler,
+};
diff --git a/drivers/staging/csr/csr_wifi_router_ctrl_sef.h b/drivers/staging/csr/csr_wifi_router_ctrl_sef.h
new file mode 100644
index 0000000..e0ee5cf
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_ctrl_sef.h
@@ -0,0 +1,58 @@
+/*****************************************************************************
+
+  (c) Cambridge Silicon Radio Limited 2010
+  Confidential information of CSR
+
+  Refer to LICENSE.txt included with this source for details
+  on the license terms.
+
+ *****************************************************************************/
+#ifndef CSR_WIFI_ROUTER_SEF_CSR_WIFI_ROUTER_CTRL_H__
+#define CSR_WIFI_ROUTER_SEF_CSR_WIFI_ROUTER_CTRL_H__
+
+#include "csr_wifi_router_ctrl_prim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    typedef void (*CsrWifiRouterCtrlStateHandlerType)(void* drvpriv, CsrWifiFsmEvent* msg);
+
+    extern const CsrWifiRouterCtrlStateHandlerType CsrWifiRouterCtrlDownstreamStateHandlers[CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_COUNT];
+
+    extern void CsrWifiRouterCtrlConfigurePowerModeReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlHipReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlMediaStatusReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlMulticastAddressResHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlPortConfigureReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlQosControlReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlSuspendResHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlTclasAddReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlResumeResHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlRawSdioDeinitialiseReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlRawSdioInitialiseReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlTclasDelReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlTrafficClassificationReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlTrafficConfigReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlWifiOffReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlWifiOffResHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlWifiOnReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlWifiOnResHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlM4TransmitReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlModeSetReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlPeerAddReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlPeerDelReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlPeerUpdateReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlCapabilitiesReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlBlockAckEnableReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlBlockAckDisableReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlWapiMulticastFilterReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlWapiRxPktReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlWapiUnicastTxPktReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlWapiUnicastFilterReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterCtrlWapiFilterReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_ROUTER_SEF_CSR_WIFI_ROUTER_CTRL_H__ */
diff --git a/drivers/staging/csr/csr_wifi_router_ctrl_serialize.c b/drivers/staging/csr/csr_wifi_router_ctrl_serialize.c
new file mode 100644
index 0000000..3239c9b
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_ctrl_serialize.c
@@ -0,0 +1,2594 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_msgconv.h"
+#include "csr_unicode.h"
+
+
+#include "csr_wifi_router_ctrl_prim.h"
+#include "csr_wifi_router_ctrl_serialize.h"
+
+void CsrWifiRouterCtrlPfree(void *ptr)
+{
+    CsrPmemFree(ptr);
+}
+
+
+CsrSize CsrWifiRouterCtrlConfigurePowerModeReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrWifiRouterCtrlLowPowerMode primitive->mode */
+    bufferSize += 1; /* CsrBool primitive->wakeHost */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlConfigurePowerModeReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlConfigurePowerModeReq *primitive = (CsrWifiRouterCtrlConfigurePowerModeReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mode);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->wakeHost);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlConfigurePowerModeReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlConfigurePowerModeReq *primitive = (CsrWifiRouterCtrlConfigurePowerModeReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlConfigurePowerModeReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mode, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->wakeHost, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlHipReqSizeof(void *msg)
+{
+    CsrWifiRouterCtrlHipReq *primitive = (CsrWifiRouterCtrlHipReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 12) */
+    bufferSize += 2;                            /* CsrUint16 primitive->mlmeCommandLength */
+    bufferSize += primitive->mlmeCommandLength; /* CsrUint8 primitive->mlmeCommand */
+    bufferSize += 2;                            /* CsrUint16 primitive->dataRef1Length */
+    bufferSize += primitive->dataRef1Length;    /* CsrUint8 primitive->dataRef1 */
+    bufferSize += 2;                            /* CsrUint16 primitive->dataRef2Length */
+    bufferSize += primitive->dataRef2Length;    /* CsrUint8 primitive->dataRef2 */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlHipReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlHipReq *primitive = (CsrWifiRouterCtrlHipReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mlmeCommandLength);
+    if (primitive->mlmeCommandLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->mlmeCommand, ((CsrUint16) (primitive->mlmeCommandLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->dataRef1Length);
+    if (primitive->dataRef1Length)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->dataRef1, ((CsrUint16) (primitive->dataRef1Length)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->dataRef2Length);
+    if (primitive->dataRef2Length)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->dataRef2, ((CsrUint16) (primitive->dataRef2Length)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlHipReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlHipReq *primitive = (CsrWifiRouterCtrlHipReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlHipReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mlmeCommandLength, buffer, &offset);
+    if (primitive->mlmeCommandLength)
+    {
+        primitive->mlmeCommand = (CsrUint8 *)CsrPmemAlloc(primitive->mlmeCommandLength);
+        CsrMemCpyDes(primitive->mlmeCommand, buffer, &offset, ((CsrUint16) (primitive->mlmeCommandLength)));
+    }
+    else
+    {
+        primitive->mlmeCommand = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->dataRef1Length, buffer, &offset);
+    if (primitive->dataRef1Length)
+    {
+        primitive->dataRef1 = (CsrUint8 *)CsrPmemAlloc(primitive->dataRef1Length);
+        CsrMemCpyDes(primitive->dataRef1, buffer, &offset, ((CsrUint16) (primitive->dataRef1Length)));
+    }
+    else
+    {
+        primitive->dataRef1 = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->dataRef2Length, buffer, &offset);
+    if (primitive->dataRef2Length)
+    {
+        primitive->dataRef2 = (CsrUint8 *)CsrPmemAlloc(primitive->dataRef2Length);
+        CsrMemCpyDes(primitive->dataRef2, buffer, &offset, ((CsrUint16) (primitive->dataRef2Length)));
+    }
+    else
+    {
+        primitive->dataRef2 = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlHipReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlHipReq *primitive = (CsrWifiRouterCtrlHipReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->mlmeCommand);
+    CsrPmemFree(primitive->dataRef1);
+    CsrPmemFree(primitive->dataRef2);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlMediaStatusReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 1; /* CsrWifiRouterCtrlMediaStatus primitive->mediaStatus */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlMediaStatusReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlMediaStatusReq *primitive = (CsrWifiRouterCtrlMediaStatusReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->mediaStatus);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlMediaStatusReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlMediaStatusReq *primitive = (CsrWifiRouterCtrlMediaStatusReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlMediaStatusReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->mediaStatus, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlMulticastAddressResSizeof(void *msg)
+{
+    CsrWifiRouterCtrlMulticastAddressRes *primitive = (CsrWifiRouterCtrlMulticastAddressRes *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 17) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrWifiRouterCtrlListAction primitive->action */
+    bufferSize += 1; /* CsrUint8 primitive->getAddressesCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getAddressesCount; i1++)
+        {
+            bufferSize += 6; /* CsrUint8 primitive->getAddresses[i1].a[6] */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlMulticastAddressResSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlMulticastAddressRes *primitive = (CsrWifiRouterCtrlMulticastAddressRes *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->action);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->getAddressesCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getAddressesCount; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->getAddresses[i1].a, ((CsrUint16) (6)));
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlMulticastAddressResDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlMulticastAddressRes *primitive = (CsrWifiRouterCtrlMulticastAddressRes *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlMulticastAddressRes));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->action, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->getAddressesCount, buffer, &offset);
+    primitive->getAddresses = NULL;
+    if (primitive->getAddressesCount)
+    {
+        primitive->getAddresses = (CsrWifiMacAddress *)CsrPmemAlloc(sizeof(CsrWifiMacAddress) * primitive->getAddressesCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getAddressesCount; i1++)
+        {
+            CsrMemCpyDes(primitive->getAddresses[i1].a, buffer, &offset, ((CsrUint16) (6)));
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlMulticastAddressResSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlMulticastAddressRes *primitive = (CsrWifiRouterCtrlMulticastAddressRes *) voidPrimitivePointer;
+    CsrPmemFree(primitive->getAddresses);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlPortConfigureReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 18) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrWifiRouterCtrlPortAction primitive->uncontrolledPortAction */
+    bufferSize += 2; /* CsrWifiRouterCtrlPortAction primitive->controlledPortAction */
+    bufferSize += 6; /* CsrUint8 primitive->macAddress.a[6] */
+    bufferSize += 1; /* CsrBool primitive->setProtection */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlPortConfigureReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlPortConfigureReq *primitive = (CsrWifiRouterCtrlPortConfigureReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->uncontrolledPortAction);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->controlledPortAction);
+    CsrMemCpySer(ptr, len, (const void *) primitive->macAddress.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->setProtection);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlPortConfigureReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlPortConfigureReq *primitive = (CsrWifiRouterCtrlPortConfigureReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPortConfigureReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->uncontrolledPortAction, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->controlledPortAction, buffer, &offset);
+    CsrMemCpyDes(primitive->macAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->setProtection, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlQosControlReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrWifiRouterCtrlQoSControl primitive->control */
+    bufferSize += 1; /* CsrWifiRouterCtrlQueueConfigMask primitive->queueConfig */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlQosControlReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlQosControlReq *primitive = (CsrWifiRouterCtrlQosControlReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->control);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->queueConfig);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlQosControlReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlQosControlReq *primitive = (CsrWifiRouterCtrlQosControlReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlQosControlReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->control, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->queueConfig, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlSuspendResSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlSuspendResSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlSuspendRes *primitive = (CsrWifiRouterCtrlSuspendRes *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlSuspendResDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlSuspendRes *primitive = (CsrWifiRouterCtrlSuspendRes *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlSuspendRes));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlTclasAddReqSizeof(void *msg)
+{
+    CsrWifiRouterCtrlTclasAddReq *primitive = (CsrWifiRouterCtrlTclasAddReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 2;                      /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;                      /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2;                      /* CsrUint16 primitive->tclasLength */
+    bufferSize += primitive->tclasLength; /* CsrUint8 primitive->tclas */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlTclasAddReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlTclasAddReq *primitive = (CsrWifiRouterCtrlTclasAddReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->tclasLength);
+    if (primitive->tclasLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->tclas, ((CsrUint16) (primitive->tclasLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlTclasAddReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlTclasAddReq *primitive = (CsrWifiRouterCtrlTclasAddReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTclasAddReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->tclasLength, buffer, &offset);
+    if (primitive->tclasLength)
+    {
+        primitive->tclas = (CsrUint8 *)CsrPmemAlloc(primitive->tclasLength);
+        CsrMemCpyDes(primitive->tclas, buffer, &offset, ((CsrUint16) (primitive->tclasLength)));
+    }
+    else
+    {
+        primitive->tclas = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlTclasAddReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlTclasAddReq *primitive = (CsrWifiRouterCtrlTclasAddReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->tclas);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlResumeResSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlResumeResSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlResumeRes *primitive = (CsrWifiRouterCtrlResumeRes *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlResumeResDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlResumeRes *primitive = (CsrWifiRouterCtrlResumeRes *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlResumeRes));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlTclasDelReqSizeof(void *msg)
+{
+    CsrWifiRouterCtrlTclasDelReq *primitive = (CsrWifiRouterCtrlTclasDelReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 2;                      /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;                      /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2;                      /* CsrUint16 primitive->tclasLength */
+    bufferSize += primitive->tclasLength; /* CsrUint8 primitive->tclas */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlTclasDelReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlTclasDelReq *primitive = (CsrWifiRouterCtrlTclasDelReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->tclasLength);
+    if (primitive->tclasLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->tclas, ((CsrUint16) (primitive->tclasLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlTclasDelReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlTclasDelReq *primitive = (CsrWifiRouterCtrlTclasDelReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTclasDelReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->tclasLength, buffer, &offset);
+    if (primitive->tclasLength)
+    {
+        primitive->tclas = (CsrUint8 *)CsrPmemAlloc(primitive->tclasLength);
+        CsrMemCpyDes(primitive->tclas, buffer, &offset, ((CsrUint16) (primitive->tclasLength)));
+    }
+    else
+    {
+        primitive->tclas = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlTclasDelReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlTclasDelReq *primitive = (CsrWifiRouterCtrlTclasDelReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->tclas);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlTrafficClassificationReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 1; /* CsrWifiRouterCtrlTrafficType primitive->trafficType */
+    bufferSize += 2; /* CsrUint16 primitive->period */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlTrafficClassificationReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlTrafficClassificationReq *primitive = (CsrWifiRouterCtrlTrafficClassificationReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->trafficType);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->period);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlTrafficClassificationReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlTrafficClassificationReq *primitive = (CsrWifiRouterCtrlTrafficClassificationReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTrafficClassificationReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->trafficType, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->period, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlTrafficConfigReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 24) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrWifiRouterCtrlTrafficConfigType primitive->trafficConfigType */
+    bufferSize += 2; /* CsrUint16 primitive->config.packetFilter */
+    bufferSize += 4; /* CsrUint32 primitive->config.customFilter.etherType */
+    bufferSize += 1; /* CsrUint8 primitive->config.customFilter.ipType */
+    bufferSize += 4; /* CsrUint32 primitive->config.customFilter.udpSourcePort */
+    bufferSize += 4; /* CsrUint32 primitive->config.customFilter.udpDestPort */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlTrafficConfigReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlTrafficConfigReq *primitive = (CsrWifiRouterCtrlTrafficConfigReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->trafficConfigType);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->config.packetFilter);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->config.customFilter.etherType);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->config.customFilter.ipType);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->config.customFilter.udpSourcePort);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->config.customFilter.udpDestPort);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlTrafficConfigReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlTrafficConfigReq *primitive = (CsrWifiRouterCtrlTrafficConfigReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTrafficConfigReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->trafficConfigType, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->config.packetFilter, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->config.customFilter.etherType, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->config.customFilter.ipType, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->config.customFilter.udpSourcePort, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->config.customFilter.udpDestPort, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlWifiOnReqSizeof(void *msg)
+{
+    CsrWifiRouterCtrlWifiOnReq *primitive = (CsrWifiRouterCtrlWifiOnReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 2;                     /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 4;                     /* CsrUint32 primitive->dataLength */
+    bufferSize += primitive->dataLength; /* CsrUint8 primitive->data */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlWifiOnReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlWifiOnReq *primitive = (CsrWifiRouterCtrlWifiOnReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->dataLength);
+    if (primitive->dataLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->data, ((CsrUint16) (primitive->dataLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlWifiOnReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlWifiOnReq *primitive = (CsrWifiRouterCtrlWifiOnReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOnReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->dataLength, buffer, &offset);
+    if (primitive->dataLength)
+    {
+        primitive->data = (CsrUint8 *)CsrPmemAlloc(primitive->dataLength);
+        CsrMemCpyDes(primitive->data, buffer, &offset, ((CsrUint16) (primitive->dataLength)));
+    }
+    else
+    {
+        primitive->data = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlWifiOnReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlWifiOnReq *primitive = (CsrWifiRouterCtrlWifiOnReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->data);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlWifiOnResSizeof(void *msg)
+{
+    CsrWifiRouterCtrlWifiOnRes *primitive = (CsrWifiRouterCtrlWifiOnRes *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 30) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 2; /* CsrUint16 primitive->numInterfaceAddress */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 2; i1++)
+        {
+            bufferSize += 6;                                                                            /* CsrUint8 primitive->stationMacAddress[i1].a[6] */
+        }
+    }
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->smeVersions.firmwarePatch */
+    bufferSize += (primitive->smeVersions.smeBuild?CsrStrLen(primitive->smeVersions.smeBuild) : 0) + 1; /* CsrCharString* primitive->smeVersions.smeBuild (0 byte len + 1 for NULL Term) */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->smeVersions.smeHip */
+    bufferSize += 1;                                                                                    /* CsrBool primitive->scheduledInterrupt */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlWifiOnResSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlWifiOnRes *primitive = (CsrWifiRouterCtrlWifiOnRes *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->numInterfaceAddress);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 2; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->stationMacAddress[i1].a, ((CsrUint16) (6)));
+        }
+    }
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->smeVersions.firmwarePatch);
+    CsrCharStringSer(ptr, len, primitive->smeVersions.smeBuild);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->smeVersions.smeHip);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scheduledInterrupt);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlWifiOnResDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlWifiOnRes *primitive = (CsrWifiRouterCtrlWifiOnRes *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOnRes));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->numInterfaceAddress, buffer, &offset);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 2; i1++)
+        {
+            CsrMemCpyDes(primitive->stationMacAddress[i1].a, buffer, &offset, ((CsrUint16) (6)));
+        }
+    }
+    CsrUint32Des((CsrUint32 *) &primitive->smeVersions.firmwarePatch, buffer, &offset);
+    CsrCharStringDes(&primitive->smeVersions.smeBuild, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->smeVersions.smeHip, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scheduledInterrupt, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlWifiOnResSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlWifiOnRes *primitive = (CsrWifiRouterCtrlWifiOnRes *) voidPrimitivePointer;
+    CsrPmemFree(primitive->smeVersions.smeBuild);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlM4TransmitReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlM4TransmitReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlM4TransmitReq *primitive = (CsrWifiRouterCtrlM4TransmitReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlM4TransmitReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlM4TransmitReq *primitive = (CsrWifiRouterCtrlM4TransmitReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlM4TransmitReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlModeSetReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 16) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 1; /* CsrWifiRouterCtrlMode primitive->mode */
+    bufferSize += 6; /* CsrUint8 primitive->bssid.a[6] */
+    bufferSize += 1; /* CsrBool primitive->protection */
+    bufferSize += 1; /* CsrBool primitive->intraBssDistEnabled */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlModeSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlModeSetReq *primitive = (CsrWifiRouterCtrlModeSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->mode);
+    CsrMemCpySer(ptr, len, (const void *) primitive->bssid.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->protection);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->intraBssDistEnabled);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlModeSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlModeSetReq *primitive = (CsrWifiRouterCtrlModeSetReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlModeSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->mode, buffer, &offset);
+    CsrMemCpyDes(primitive->bssid.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->protection, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->intraBssDistEnabled, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlPeerAddReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 21) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 6; /* CsrUint8 primitive->peerMacAddress.a[6] */
+    bufferSize += 2; /* CsrUint16 primitive->associationId */
+    bufferSize += 1; /* CsrBool primitive->staInfo.wmmOrQosEnabled */
+    bufferSize += 2; /* CsrWifiRouterCtrlPowersaveTypeMask primitive->staInfo.powersaveMode */
+    bufferSize += 1; /* CsrUint8 primitive->staInfo.maxSpLength */
+    bufferSize += 2; /* CsrUint16 primitive->staInfo.listenIntervalInTus */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlPeerAddReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlPeerAddReq *primitive = (CsrWifiRouterCtrlPeerAddReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerMacAddress.a, ((CsrUint16) (6)));
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->associationId);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->staInfo.wmmOrQosEnabled);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->staInfo.powersaveMode);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->staInfo.maxSpLength);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->staInfo.listenIntervalInTus);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlPeerAddReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlPeerAddReq *primitive = (CsrWifiRouterCtrlPeerAddReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerAddReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrMemCpyDes(primitive->peerMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint16Des((CsrUint16 *) &primitive->associationId, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->staInfo.wmmOrQosEnabled, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->staInfo.powersaveMode, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->staInfo.maxSpLength, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->staInfo.listenIntervalInTus, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlPeerDelReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 11) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 4; /* CsrWifiRouterCtrlPeerRecordHandle primitive->peerRecordHandle */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlPeerDelReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlPeerDelReq *primitive = (CsrWifiRouterCtrlPeerDelReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->peerRecordHandle);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlPeerDelReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlPeerDelReq *primitive = (CsrWifiRouterCtrlPeerDelReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerDelReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->peerRecordHandle, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlPeerUpdateReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 4; /* CsrWifiRouterCtrlPeerRecordHandle primitive->peerRecordHandle */
+    bufferSize += 2; /* CsrWifiRouterCtrlPowersaveTypeMask primitive->powersaveMode */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlPeerUpdateReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlPeerUpdateReq *primitive = (CsrWifiRouterCtrlPeerUpdateReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->peerRecordHandle);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->powersaveMode);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlPeerUpdateReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlPeerUpdateReq *primitive = (CsrWifiRouterCtrlPeerUpdateReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerUpdateReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->peerRecordHandle, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->powersaveMode, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlBlockAckEnableReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 21) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 6; /* CsrUint8 primitive->macAddress.a[6] */
+    bufferSize += 1; /* CsrWifiRouterCtrlTrafficStreamId primitive->trafficStreamID */
+    bufferSize += 1; /* CsrWifiRouterCtrlBlockAckRole primitive->role */
+    bufferSize += 2; /* CsrUint16 primitive->bufferSize */
+    bufferSize += 2; /* CsrUint16 primitive->timeout */
+    bufferSize += 2; /* CsrUint16 primitive->ssn */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlBlockAckEnableReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlBlockAckEnableReq *primitive = (CsrWifiRouterCtrlBlockAckEnableReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrMemCpySer(ptr, len, (const void *) primitive->macAddress.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->trafficStreamID);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->role);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->bufferSize);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->timeout);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->ssn);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlBlockAckEnableReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlBlockAckEnableReq *primitive = (CsrWifiRouterCtrlBlockAckEnableReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlBlockAckEnableReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrMemCpyDes(primitive->macAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->trafficStreamID, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->role, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->bufferSize, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->timeout, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->ssn, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlBlockAckDisableReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 15) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 6; /* CsrUint8 primitive->macAddress.a[6] */
+    bufferSize += 1; /* CsrWifiRouterCtrlTrafficStreamId primitive->trafficStreamID */
+    bufferSize += 1; /* CsrWifiRouterCtrlBlockAckRole primitive->role */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlBlockAckDisableReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlBlockAckDisableReq *primitive = (CsrWifiRouterCtrlBlockAckDisableReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrMemCpySer(ptr, len, (const void *) primitive->macAddress.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->trafficStreamID);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->role);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlBlockAckDisableReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlBlockAckDisableReq *primitive = (CsrWifiRouterCtrlBlockAckDisableReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlBlockAckDisableReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrMemCpyDes(primitive->macAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->trafficStreamID, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->role, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlWapiRxPktReqSizeof(void *msg)
+{
+    CsrWifiRouterCtrlWapiRxPktReq *primitive = (CsrWifiRouterCtrlWapiRxPktReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 11) */
+    bufferSize += 2;                       /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;                       /* CsrUint16 primitive->signalLength */
+    bufferSize += primitive->signalLength; /* CsrUint8 primitive->signal */
+    bufferSize += 2;                       /* CsrUint16 primitive->dataLength */
+    bufferSize += primitive->dataLength;   /* CsrUint8 primitive->data */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlWapiRxPktReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlWapiRxPktReq *primitive = (CsrWifiRouterCtrlWapiRxPktReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->signalLength);
+    if (primitive->signalLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->signal, ((CsrUint16) (primitive->signalLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->dataLength);
+    if (primitive->dataLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->data, ((CsrUint16) (primitive->dataLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlWapiRxPktReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlWapiRxPktReq *primitive = (CsrWifiRouterCtrlWapiRxPktReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWapiRxPktReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->signalLength, buffer, &offset);
+    if (primitive->signalLength)
+    {
+        primitive->signal = (CsrUint8 *)CsrPmemAlloc(primitive->signalLength);
+        CsrMemCpyDes(primitive->signal, buffer, &offset, ((CsrUint16) (primitive->signalLength)));
+    }
+    else
+    {
+        primitive->signal = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->dataLength, buffer, &offset);
+    if (primitive->dataLength)
+    {
+        primitive->data = (CsrUint8 *)CsrPmemAlloc(primitive->dataLength);
+        CsrMemCpyDes(primitive->data, buffer, &offset, ((CsrUint16) (primitive->dataLength)));
+    }
+    else
+    {
+        primitive->data = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlWapiRxPktReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlWapiRxPktReq *primitive = (CsrWifiRouterCtrlWapiRxPktReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->signal);
+    CsrPmemFree(primitive->data);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlWapiUnicastTxPktReqSizeof(void *msg)
+{
+    CsrWifiRouterCtrlWapiUnicastTxPktReq *primitive = (CsrWifiRouterCtrlWapiUnicastTxPktReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 2;                     /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;                     /* CsrUint16 primitive->dataLength */
+    bufferSize += primitive->dataLength; /* CsrUint8 primitive->data */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlWapiUnicastTxPktReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlWapiUnicastTxPktReq *primitive = (CsrWifiRouterCtrlWapiUnicastTxPktReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->dataLength);
+    if (primitive->dataLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->data, ((CsrUint16) (primitive->dataLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlWapiUnicastTxPktReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlWapiUnicastTxPktReq *primitive = (CsrWifiRouterCtrlWapiUnicastTxPktReq *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWapiUnicastTxPktReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->dataLength, buffer, &offset);
+    if (primitive->dataLength)
+    {
+        primitive->data = (CsrUint8 *)CsrPmemAlloc(primitive->dataLength);
+        CsrMemCpyDes(primitive->data, buffer, &offset, ((CsrUint16) (primitive->dataLength)));
+    }
+    else
+    {
+        primitive->data = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlWapiUnicastTxPktReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlWapiUnicastTxPktReq *primitive = (CsrWifiRouterCtrlWapiUnicastTxPktReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->data);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlHipIndSizeof(void *msg)
+{
+    CsrWifiRouterCtrlHipInd *primitive = (CsrWifiRouterCtrlHipInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 12) */
+    bufferSize += 2;                            /* CsrUint16 primitive->mlmeCommandLength */
+    bufferSize += primitive->mlmeCommandLength; /* CsrUint8 primitive->mlmeCommand */
+    bufferSize += 2;                            /* CsrUint16 primitive->dataRef1Length */
+    bufferSize += primitive->dataRef1Length;    /* CsrUint8 primitive->dataRef1 */
+    bufferSize += 2;                            /* CsrUint16 primitive->dataRef2Length */
+    bufferSize += primitive->dataRef2Length;    /* CsrUint8 primitive->dataRef2 */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlHipIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlHipInd *primitive = (CsrWifiRouterCtrlHipInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mlmeCommandLength);
+    if (primitive->mlmeCommandLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->mlmeCommand, ((CsrUint16) (primitive->mlmeCommandLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->dataRef1Length);
+    if (primitive->dataRef1Length)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->dataRef1, ((CsrUint16) (primitive->dataRef1Length)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->dataRef2Length);
+    if (primitive->dataRef2Length)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->dataRef2, ((CsrUint16) (primitive->dataRef2Length)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlHipIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlHipInd *primitive = (CsrWifiRouterCtrlHipInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlHipInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mlmeCommandLength, buffer, &offset);
+    if (primitive->mlmeCommandLength)
+    {
+        primitive->mlmeCommand = (CsrUint8 *)CsrPmemAlloc(primitive->mlmeCommandLength);
+        CsrMemCpyDes(primitive->mlmeCommand, buffer, &offset, ((CsrUint16) (primitive->mlmeCommandLength)));
+    }
+    else
+    {
+        primitive->mlmeCommand = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->dataRef1Length, buffer, &offset);
+    if (primitive->dataRef1Length)
+    {
+        primitive->dataRef1 = (CsrUint8 *)CsrPmemAlloc(primitive->dataRef1Length);
+        CsrMemCpyDes(primitive->dataRef1, buffer, &offset, ((CsrUint16) (primitive->dataRef1Length)));
+    }
+    else
+    {
+        primitive->dataRef1 = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->dataRef2Length, buffer, &offset);
+    if (primitive->dataRef2Length)
+    {
+        primitive->dataRef2 = (CsrUint8 *)CsrPmemAlloc(primitive->dataRef2Length);
+        CsrMemCpyDes(primitive->dataRef2, buffer, &offset, ((CsrUint16) (primitive->dataRef2Length)));
+    }
+    else
+    {
+        primitive->dataRef2 = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlHipIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlHipInd *primitive = (CsrWifiRouterCtrlHipInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->mlmeCommand);
+    CsrPmemFree(primitive->dataRef1);
+    CsrPmemFree(primitive->dataRef2);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlMulticastAddressIndSizeof(void *msg)
+{
+    CsrWifiRouterCtrlMulticastAddressInd *primitive = (CsrWifiRouterCtrlMulticastAddressInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 15) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiRouterCtrlListAction primitive->action */
+    bufferSize += 1; /* CsrUint8 primitive->setAddressesCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setAddressesCount; i1++)
+        {
+            bufferSize += 6; /* CsrUint8 primitive->setAddresses[i1].a[6] */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlMulticastAddressIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlMulticastAddressInd *primitive = (CsrWifiRouterCtrlMulticastAddressInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->action);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->setAddressesCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setAddressesCount; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->setAddresses[i1].a, ((CsrUint16) (6)));
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlMulticastAddressIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlMulticastAddressInd *primitive = (CsrWifiRouterCtrlMulticastAddressInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlMulticastAddressInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->action, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->setAddressesCount, buffer, &offset);
+    primitive->setAddresses = NULL;
+    if (primitive->setAddressesCount)
+    {
+        primitive->setAddresses = (CsrWifiMacAddress *)CsrPmemAlloc(sizeof(CsrWifiMacAddress) * primitive->setAddressesCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setAddressesCount; i1++)
+        {
+            CsrMemCpyDes(primitive->setAddresses[i1].a, buffer, &offset, ((CsrUint16) (6)));
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlMulticastAddressIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlMulticastAddressInd *primitive = (CsrWifiRouterCtrlMulticastAddressInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->setAddresses);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlPortConfigureCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 15) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 6; /* CsrUint8 primitive->macAddress.a[6] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlPortConfigureCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlPortConfigureCfm *primitive = (CsrWifiRouterCtrlPortConfigureCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrMemCpySer(ptr, len, (const void *) primitive->macAddress.a, ((CsrUint16) (6)));
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlPortConfigureCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlPortConfigureCfm *primitive = (CsrWifiRouterCtrlPortConfigureCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPortConfigureCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrMemCpyDes(primitive->macAddress.a, buffer, &offset, ((CsrUint16) (6)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlSuspendIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 1; /* CsrBool primitive->hardSuspend */
+    bufferSize += 1; /* CsrBool primitive->d3Suspend */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlSuspendIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlSuspendInd *primitive = (CsrWifiRouterCtrlSuspendInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->hardSuspend);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->d3Suspend);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlSuspendIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlSuspendInd *primitive = (CsrWifiRouterCtrlSuspendInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlSuspendInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->hardSuspend, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->d3Suspend, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlTclasAddCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 9) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlTclasAddCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlTclasAddCfm *primitive = (CsrWifiRouterCtrlTclasAddCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlTclasAddCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlTclasAddCfm *primitive = (CsrWifiRouterCtrlTclasAddCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTclasAddCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlRawSdioDeinitialiseCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrResult primitive->result */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlRawSdioDeinitialiseCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlRawSdioDeinitialiseCfm *primitive = (CsrWifiRouterCtrlRawSdioDeinitialiseCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlRawSdioDeinitialiseCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlRawSdioDeinitialiseCfm *primitive = (CsrWifiRouterCtrlRawSdioDeinitialiseCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlRawSdioDeinitialiseCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->result, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlRawSdioInitialiseCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 39) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrResult primitive->result */
+    bufferSize += 4; /* CsrWifiRouterCtrlRawSdioByteRead primitive->byteRead */
+    bufferSize += 4; /* CsrWifiRouterCtrlRawSdioByteWrite primitive->byteWrite */
+    bufferSize += 4; /* CsrWifiRouterCtrlRawSdioFirmwareDownload primitive->firmwareDownload */
+    bufferSize += 4; /* CsrWifiRouterCtrlRawSdioReset primitive->reset */
+    bufferSize += 4; /* CsrWifiRouterCtrlRawSdioCoreDumpPrepare primitive->coreDumpPrepare */
+    bufferSize += 4; /* CsrWifiRouterCtrlRawSdioByteBlockRead primitive->byteBlockRead */
+    bufferSize += 4; /* CsrWifiRouterCtrlRawSdioGpRead16 primitive->gpRead16 */
+    bufferSize += 4; /* CsrWifiRouterCtrlRawSdioGpWrite16 primitive->gpWrite16 */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlRawSdioInitialiseCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlRawSdioInitialiseCfm *primitive = (CsrWifiRouterCtrlRawSdioInitialiseCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result);
+    CsrUint32Ser(ptr, len, 0); /* Special for Function Pointers... primitive->byteRead */
+    CsrUint32Ser(ptr, len, 0); /* Special for Function Pointers... primitive->byteWrite */
+    CsrUint32Ser(ptr, len, 0); /* Special for Function Pointers... primitive->firmwareDownload */
+    CsrUint32Ser(ptr, len, 0); /* Special for Function Pointers... primitive->reset */
+    CsrUint32Ser(ptr, len, 0); /* Special for Function Pointers... primitive->coreDumpPrepare */
+    CsrUint32Ser(ptr, len, 0); /* Special for Function Pointers... primitive->byteBlockRead */
+    CsrUint32Ser(ptr, len, 0); /* Special for Function Pointers... primitive->gpRead16 */
+    CsrUint32Ser(ptr, len, 0); /* Special for Function Pointers... primitive->gpWrite16 */
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlRawSdioInitialiseCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlRawSdioInitialiseCfm *primitive = (CsrWifiRouterCtrlRawSdioInitialiseCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlRawSdioInitialiseCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->result, buffer, &offset);
+    primitive->byteRead = NULL;         /* Special for Function Pointers... */
+    offset += 4;
+    primitive->byteWrite = NULL;        /* Special for Function Pointers... */
+    offset += 4;
+    primitive->firmwareDownload = NULL; /* Special for Function Pointers... */
+    offset += 4;
+    primitive->reset = NULL;            /* Special for Function Pointers... */
+    offset += 4;
+    primitive->coreDumpPrepare = NULL;  /* Special for Function Pointers... */
+    offset += 4;
+    primitive->byteBlockRead = NULL;    /* Special for Function Pointers... */
+    offset += 4;
+    primitive->gpRead16 = NULL;         /* Special for Function Pointers... */
+    offset += 4;
+    primitive->gpWrite16 = NULL;        /* Special for Function Pointers... */
+    offset += 4;
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlTclasDelCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 9) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlTclasDelCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlTclasDelCfm *primitive = (CsrWifiRouterCtrlTclasDelCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlTclasDelCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlTclasDelCfm *primitive = (CsrWifiRouterCtrlTclasDelCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTclasDelCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlTrafficProtocolIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 17) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrWifiRouterCtrlTrafficPacketType primitive->packetType */
+    bufferSize += 2; /* CsrWifiRouterCtrlProtocolDirection primitive->direction */
+    bufferSize += 6; /* CsrUint8 primitive->srcAddress.a[6] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlTrafficProtocolIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlTrafficProtocolInd *primitive = (CsrWifiRouterCtrlTrafficProtocolInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->packetType);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->direction);
+    CsrMemCpySer(ptr, len, (const void *) primitive->srcAddress.a, ((CsrUint16) (6)));
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlTrafficProtocolIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlTrafficProtocolInd *primitive = (CsrWifiRouterCtrlTrafficProtocolInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTrafficProtocolInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->packetType, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->direction, buffer, &offset);
+    CsrMemCpyDes(primitive->srcAddress.a, buffer, &offset, ((CsrUint16) (6)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlTrafficSampleIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 38) */
+    bufferSize += 2;  /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2;  /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 4;  /* CsrUint32 primitive->stats.rxMeanRate */
+    bufferSize += 4;  /* CsrUint32 primitive->stats.rxFramesNum */
+    bufferSize += 4;  /* CsrUint32 primitive->stats.txFramesNum */
+    bufferSize += 4;  /* CsrUint32 primitive->stats.rxBytesCount */
+    bufferSize += 4;  /* CsrUint32 primitive->stats.txBytesCount */
+    bufferSize += 11; /* CsrUint8 primitive->stats.intervals[11] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlTrafficSampleIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlTrafficSampleInd *primitive = (CsrWifiRouterCtrlTrafficSampleInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->stats.rxMeanRate);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->stats.rxFramesNum);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->stats.txFramesNum);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->stats.rxBytesCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->stats.txBytesCount);
+    CsrMemCpySer(ptr, len, (const void *) primitive->stats.intervals, ((CsrUint16) (11)));
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlTrafficSampleIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlTrafficSampleInd *primitive = (CsrWifiRouterCtrlTrafficSampleInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlTrafficSampleInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->stats.rxMeanRate, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->stats.rxFramesNum, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->stats.txFramesNum, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->stats.rxBytesCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->stats.txBytesCount, buffer, &offset);
+    CsrMemCpyDes(primitive->stats.intervals, buffer, &offset, ((CsrUint16) (11)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlWifiOnIndSizeof(void *msg)
+{
+    CsrWifiRouterCtrlWifiOnInd *primitive = (CsrWifiRouterCtrlWifiOnInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 27) */
+    bufferSize += 2;                                                                                    /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2;                                                                                    /* CsrResult primitive->status */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.chipId */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.chipVersion */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.firmwareBuild */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.firmwareHip */
+    bufferSize += (primitive->versions.routerBuild?CsrStrLen(primitive->versions.routerBuild) : 0) + 1; /* CsrCharString* primitive->versions.routerBuild (0 byte len + 1 for NULL Term) */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.routerHip */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlWifiOnIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlWifiOnInd *primitive = (CsrWifiRouterCtrlWifiOnInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.chipId);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.chipVersion);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.firmwareBuild);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.firmwareHip);
+    CsrCharStringSer(ptr, len, primitive->versions.routerBuild);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.routerHip);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlWifiOnIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlWifiOnInd *primitive = (CsrWifiRouterCtrlWifiOnInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOnInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.chipId, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.chipVersion, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.firmwareBuild, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.firmwareHip, buffer, &offset);
+    CsrCharStringDes(&primitive->versions.routerBuild, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.routerHip, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlWifiOnIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlWifiOnInd *primitive = (CsrWifiRouterCtrlWifiOnInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->versions.routerBuild);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlWifiOnCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlWifiOnCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlWifiOnCfm *primitive = (CsrWifiRouterCtrlWifiOnCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlWifiOnCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlWifiOnCfm *primitive = (CsrWifiRouterCtrlWifiOnCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWifiOnCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlM4ReadyToSendIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 6; /* CsrUint8 primitive->peerMacAddress.a[6] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlM4ReadyToSendIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlM4ReadyToSendInd *primitive = (CsrWifiRouterCtrlM4ReadyToSendInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerMacAddress.a, ((CsrUint16) (6)));
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlM4ReadyToSendIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlM4ReadyToSendInd *primitive = (CsrWifiRouterCtrlM4ReadyToSendInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlM4ReadyToSendInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrMemCpyDes(primitive->peerMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlM4TransmittedIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 15) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 6; /* CsrUint8 primitive->peerMacAddress.a[6] */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlM4TransmittedIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlM4TransmittedInd *primitive = (CsrWifiRouterCtrlM4TransmittedInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerMacAddress.a, ((CsrUint16) (6)));
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlM4TransmittedIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlM4TransmittedInd *primitive = (CsrWifiRouterCtrlM4TransmittedInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlM4TransmittedInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrMemCpyDes(primitive->peerMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlMicFailureIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 14) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 6; /* CsrUint8 primitive->peerMacAddress.a[6] */
+    bufferSize += 1; /* CsrBool primitive->unicastPdu */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlMicFailureIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlMicFailureInd *primitive = (CsrWifiRouterCtrlMicFailureInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerMacAddress.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->unicastPdu);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlMicFailureIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlMicFailureInd *primitive = (CsrWifiRouterCtrlMicFailureInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlMicFailureInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrMemCpyDes(primitive->peerMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->unicastPdu, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlConnectedIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 14) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 6; /* CsrUint8 primitive->peerMacAddress.a[6] */
+    bufferSize += 1; /* CsrWifiRouterCtrlPeerStatus primitive->peerStatus */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlConnectedIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlConnectedInd *primitive = (CsrWifiRouterCtrlConnectedInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerMacAddress.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->peerStatus);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlConnectedIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlConnectedInd *primitive = (CsrWifiRouterCtrlConnectedInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlConnectedInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrMemCpyDes(primitive->peerMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->peerStatus, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlPeerAddCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 19) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 6; /* CsrUint8 primitive->peerMacAddress.a[6] */
+    bufferSize += 4; /* CsrWifiRouterCtrlPeerRecordHandle primitive->peerRecordHandle */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlPeerAddCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlPeerAddCfm *primitive = (CsrWifiRouterCtrlPeerAddCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerMacAddress.a, ((CsrUint16) (6)));
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->peerRecordHandle);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlPeerAddCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlPeerAddCfm *primitive = (CsrWifiRouterCtrlPeerAddCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerAddCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrMemCpyDes(primitive->peerMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint32Des((CsrUint32 *) &primitive->peerRecordHandle, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlPeerDelCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 9) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlPeerDelCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlPeerDelCfm *primitive = (CsrWifiRouterCtrlPeerDelCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlPeerDelCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlPeerDelCfm *primitive = (CsrWifiRouterCtrlPeerDelCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerDelCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlUnexpectedFrameIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 6; /* CsrUint8 primitive->peerMacAddress.a[6] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlUnexpectedFrameIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlUnexpectedFrameInd *primitive = (CsrWifiRouterCtrlUnexpectedFrameInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerMacAddress.a, ((CsrUint16) (6)));
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlUnexpectedFrameIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlUnexpectedFrameInd *primitive = (CsrWifiRouterCtrlUnexpectedFrameInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlUnexpectedFrameInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrMemCpyDes(primitive->peerMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlPeerUpdateCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 9) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlPeerUpdateCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlPeerUpdateCfm *primitive = (CsrWifiRouterCtrlPeerUpdateCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlPeerUpdateCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlPeerUpdateCfm *primitive = (CsrWifiRouterCtrlPeerUpdateCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlPeerUpdateCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlCapabilitiesCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 9) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->commandQueueSize */
+    bufferSize += 2; /* CsrUint16 primitive->trafficQueueSize */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlCapabilitiesCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlCapabilitiesCfm *primitive = (CsrWifiRouterCtrlCapabilitiesCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->commandQueueSize);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->trafficQueueSize);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlCapabilitiesCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlCapabilitiesCfm *primitive = (CsrWifiRouterCtrlCapabilitiesCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlCapabilitiesCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->commandQueueSize, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->trafficQueueSize, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlBlockAckEnableCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 9) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlBlockAckEnableCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlBlockAckEnableCfm *primitive = (CsrWifiRouterCtrlBlockAckEnableCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlBlockAckEnableCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlBlockAckEnableCfm *primitive = (CsrWifiRouterCtrlBlockAckEnableCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlBlockAckEnableCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlBlockAckDisableCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 9) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlBlockAckDisableCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlBlockAckDisableCfm *primitive = (CsrWifiRouterCtrlBlockAckDisableCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlBlockAckDisableCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlBlockAckDisableCfm *primitive = (CsrWifiRouterCtrlBlockAckDisableCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlBlockAckDisableCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlBlockAckErrorIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 16) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiRouterCtrlTrafficStreamId primitive->trafficStreamID */
+    bufferSize += 6; /* CsrUint8 primitive->peerMacAddress.a[6] */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlBlockAckErrorIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlBlockAckErrorInd *primitive = (CsrWifiRouterCtrlBlockAckErrorInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->trafficStreamID);
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerMacAddress.a, ((CsrUint16) (6)));
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlBlockAckErrorIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlBlockAckErrorInd *primitive = (CsrWifiRouterCtrlBlockAckErrorInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlBlockAckErrorInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->trafficStreamID, buffer, &offset);
+    CsrMemCpyDes(primitive->peerMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlStaInactiveIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 6; /* CsrUint8 primitive->staAddress.a[6] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlStaInactiveIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlStaInactiveInd *primitive = (CsrWifiRouterCtrlStaInactiveInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrMemCpySer(ptr, len, (const void *) primitive->staAddress.a, ((CsrUint16) (6)));
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlStaInactiveIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlStaInactiveInd *primitive = (CsrWifiRouterCtrlStaInactiveInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlStaInactiveInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrMemCpyDes(primitive->staAddress.a, buffer, &offset, ((CsrUint16) (6)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlWapiRxMicCheckIndSizeof(void *msg)
+{
+    CsrWifiRouterCtrlWapiRxMicCheckInd *primitive = (CsrWifiRouterCtrlWapiRxMicCheckInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2;                       /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2;                       /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;                       /* CsrUint16 primitive->signalLength */
+    bufferSize += primitive->signalLength; /* CsrUint8 primitive->signal */
+    bufferSize += 2;                       /* CsrUint16 primitive->dataLength */
+    bufferSize += primitive->dataLength;   /* CsrUint8 primitive->data */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlWapiRxMicCheckIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlWapiRxMicCheckInd *primitive = (CsrWifiRouterCtrlWapiRxMicCheckInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->signalLength);
+    if (primitive->signalLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->signal, ((CsrUint16) (primitive->signalLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->dataLength);
+    if (primitive->dataLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->data, ((CsrUint16) (primitive->dataLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlWapiRxMicCheckIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlWapiRxMicCheckInd *primitive = (CsrWifiRouterCtrlWapiRxMicCheckInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWapiRxMicCheckInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->signalLength, buffer, &offset);
+    if (primitive->signalLength)
+    {
+        primitive->signal = (CsrUint8 *)CsrPmemAlloc(primitive->signalLength);
+        CsrMemCpyDes(primitive->signal, buffer, &offset, ((CsrUint16) (primitive->signalLength)));
+    }
+    else
+    {
+        primitive->signal = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->dataLength, buffer, &offset);
+    if (primitive->dataLength)
+    {
+        primitive->data = (CsrUint8 *)CsrPmemAlloc(primitive->dataLength);
+        CsrMemCpyDes(primitive->data, buffer, &offset, ((CsrUint16) (primitive->dataLength)));
+    }
+    else
+    {
+        primitive->data = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlWapiRxMicCheckIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlWapiRxMicCheckInd *primitive = (CsrWifiRouterCtrlWapiRxMicCheckInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->signal);
+    CsrPmemFree(primitive->data);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterCtrlModeSetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 2; /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiRouterCtrlMode primitive->mode */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlModeSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlModeSetCfm *primitive = (CsrWifiRouterCtrlModeSetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->mode);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlModeSetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlModeSetCfm *primitive = (CsrWifiRouterCtrlModeSetCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlModeSetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->mode, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterCtrlWapiUnicastTxEncryptIndSizeof(void *msg)
+{
+    CsrWifiRouterCtrlWapiUnicastTxEncryptInd *primitive = (CsrWifiRouterCtrlWapiUnicastTxEncryptInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 2;                     /* CsrWifiRouterCtrlRequestorInfo primitive->clientData */
+    bufferSize += 2;                     /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;                     /* CsrUint16 primitive->dataLength */
+    bufferSize += primitive->dataLength; /* CsrUint8 primitive->data */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterCtrlWapiUnicastTxEncryptIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterCtrlWapiUnicastTxEncryptInd *primitive = (CsrWifiRouterCtrlWapiUnicastTxEncryptInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->clientData);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->dataLength);
+    if (primitive->dataLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->data, ((CsrUint16) (primitive->dataLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiRouterCtrlWapiUnicastTxEncryptIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterCtrlWapiUnicastTxEncryptInd *primitive = (CsrWifiRouterCtrlWapiUnicastTxEncryptInd *) CsrPmemAlloc(sizeof(CsrWifiRouterCtrlWapiUnicastTxEncryptInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->clientData, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->dataLength, buffer, &offset);
+    if (primitive->dataLength)
+    {
+        primitive->data = (CsrUint8 *)CsrPmemAlloc(primitive->dataLength);
+        CsrMemCpyDes(primitive->data, buffer, &offset, ((CsrUint16) (primitive->dataLength)));
+    }
+    else
+    {
+        primitive->data = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiRouterCtrlWapiUnicastTxEncryptIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterCtrlWapiUnicastTxEncryptInd *primitive = (CsrWifiRouterCtrlWapiUnicastTxEncryptInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->data);
+    CsrPmemFree(primitive);
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_router_ctrl_serialize.h b/drivers/staging/csr/csr_wifi_router_ctrl_serialize.h
new file mode 100644
index 0000000..3b7834d
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_ctrl_serialize.h
@@ -0,0 +1,343 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_ROUTER_CTRL_SERIALIZE_H__
+#define CSR_WIFI_ROUTER_CTRL_SERIALIZE_H__
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_wifi_msgconv.h"
+
+#include "csr_wifi_router_ctrl_prim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void CsrWifiRouterCtrlPfree(void *ptr);
+
+extern CsrUint8* CsrWifiRouterCtrlConfigurePowerModeReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlConfigurePowerModeReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlConfigurePowerModeReqSizeof(void *msg);
+#define CsrWifiRouterCtrlConfigurePowerModeReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlHipReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlHipReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlHipReqSizeof(void *msg);
+extern void CsrWifiRouterCtrlHipReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiRouterCtrlMediaStatusReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlMediaStatusReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlMediaStatusReqSizeof(void *msg);
+#define CsrWifiRouterCtrlMediaStatusReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlMulticastAddressResSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlMulticastAddressResDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlMulticastAddressResSizeof(void *msg);
+extern void CsrWifiRouterCtrlMulticastAddressResSerFree(void *msg);
+
+extern CsrUint8* CsrWifiRouterCtrlPortConfigureReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlPortConfigureReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlPortConfigureReqSizeof(void *msg);
+#define CsrWifiRouterCtrlPortConfigureReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlQosControlReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlQosControlReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlQosControlReqSizeof(void *msg);
+#define CsrWifiRouterCtrlQosControlReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlSuspendResSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlSuspendResDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlSuspendResSizeof(void *msg);
+#define CsrWifiRouterCtrlSuspendResSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlTclasAddReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlTclasAddReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlTclasAddReqSizeof(void *msg);
+extern void CsrWifiRouterCtrlTclasAddReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiRouterCtrlResumeResSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlResumeResDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlResumeResSizeof(void *msg);
+#define CsrWifiRouterCtrlResumeResSerFree CsrWifiRouterCtrlPfree
+
+#define CsrWifiRouterCtrlRawSdioDeinitialiseReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiRouterCtrlRawSdioDeinitialiseReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiRouterCtrlRawSdioDeinitialiseReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiRouterCtrlRawSdioDeinitialiseReqSerFree CsrWifiRouterCtrlPfree
+
+#define CsrWifiRouterCtrlRawSdioInitialiseReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiRouterCtrlRawSdioInitialiseReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiRouterCtrlRawSdioInitialiseReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiRouterCtrlRawSdioInitialiseReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlTclasDelReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlTclasDelReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlTclasDelReqSizeof(void *msg);
+extern void CsrWifiRouterCtrlTclasDelReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiRouterCtrlTrafficClassificationReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlTrafficClassificationReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlTrafficClassificationReqSizeof(void *msg);
+#define CsrWifiRouterCtrlTrafficClassificationReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlTrafficConfigReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlTrafficConfigReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlTrafficConfigReqSizeof(void *msg);
+#define CsrWifiRouterCtrlTrafficConfigReqSerFree CsrWifiRouterCtrlPfree
+
+#define CsrWifiRouterCtrlWifiOffReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiRouterCtrlWifiOffReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiRouterCtrlWifiOffReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiRouterCtrlWifiOffReqSerFree CsrWifiRouterCtrlPfree
+
+#define CsrWifiRouterCtrlWifiOffResSer CsrWifiEventCsrUint16Ser
+#define CsrWifiRouterCtrlWifiOffResDes CsrWifiEventCsrUint16Des
+#define CsrWifiRouterCtrlWifiOffResSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiRouterCtrlWifiOffResSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlWifiOnReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlWifiOnReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlWifiOnReqSizeof(void *msg);
+extern void CsrWifiRouterCtrlWifiOnReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiRouterCtrlWifiOnResSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlWifiOnResDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlWifiOnResSizeof(void *msg);
+extern void CsrWifiRouterCtrlWifiOnResSerFree(void *msg);
+
+extern CsrUint8* CsrWifiRouterCtrlM4TransmitReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlM4TransmitReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlM4TransmitReqSizeof(void *msg);
+#define CsrWifiRouterCtrlM4TransmitReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlModeSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlModeSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlModeSetReqSizeof(void *msg);
+#define CsrWifiRouterCtrlModeSetReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlPeerAddReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlPeerAddReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlPeerAddReqSizeof(void *msg);
+#define CsrWifiRouterCtrlPeerAddReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlPeerDelReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlPeerDelReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlPeerDelReqSizeof(void *msg);
+#define CsrWifiRouterCtrlPeerDelReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlPeerUpdateReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlPeerUpdateReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlPeerUpdateReqSizeof(void *msg);
+#define CsrWifiRouterCtrlPeerUpdateReqSerFree CsrWifiRouterCtrlPfree
+
+#define CsrWifiRouterCtrlCapabilitiesReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiRouterCtrlCapabilitiesReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiRouterCtrlCapabilitiesReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiRouterCtrlCapabilitiesReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlBlockAckEnableReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlBlockAckEnableReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlBlockAckEnableReqSizeof(void *msg);
+#define CsrWifiRouterCtrlBlockAckEnableReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlBlockAckDisableReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlBlockAckDisableReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlBlockAckDisableReqSizeof(void *msg);
+#define CsrWifiRouterCtrlBlockAckDisableReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlWapiRxPktReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlWapiRxPktReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlWapiRxPktReqSizeof(void *msg);
+extern void CsrWifiRouterCtrlWapiRxPktReqSerFree(void *msg);
+
+#define CsrWifiRouterCtrlWapiMulticastFilterReqSer CsrWifiEventCsrUint16CsrUint8Ser
+#define CsrWifiRouterCtrlWapiMulticastFilterReqDes CsrWifiEventCsrUint16CsrUint8Des
+#define CsrWifiRouterCtrlWapiMulticastFilterReqSizeof CsrWifiEventCsrUint16CsrUint8Sizeof
+#define CsrWifiRouterCtrlWapiMulticastFilterReqSerFree CsrWifiRouterCtrlPfree
+
+#define CsrWifiRouterCtrlWapiUnicastFilterReqSer CsrWifiEventCsrUint16CsrUint8Ser
+#define CsrWifiRouterCtrlWapiUnicastFilterReqDes CsrWifiEventCsrUint16CsrUint8Des
+#define CsrWifiRouterCtrlWapiUnicastFilterReqSizeof CsrWifiEventCsrUint16CsrUint8Sizeof
+#define CsrWifiRouterCtrlWapiUnicastFilterReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlWapiUnicastTxPktReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlWapiUnicastTxPktReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlWapiUnicastTxPktReqSizeof(void *msg);
+extern void CsrWifiRouterCtrlWapiUnicastTxPktReqSerFree(void *msg);
+
+#define CsrWifiRouterCtrlWapiFilterReqSer CsrWifiEventCsrUint16CsrUint8Ser
+#define CsrWifiRouterCtrlWapiFilterReqDes CsrWifiEventCsrUint16CsrUint8Des
+#define CsrWifiRouterCtrlWapiFilterReqSizeof CsrWifiEventCsrUint16CsrUint8Sizeof
+#define CsrWifiRouterCtrlWapiFilterReqSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlHipIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlHipIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlHipIndSizeof(void *msg);
+extern void CsrWifiRouterCtrlHipIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiRouterCtrlMulticastAddressIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlMulticastAddressIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlMulticastAddressIndSizeof(void *msg);
+extern void CsrWifiRouterCtrlMulticastAddressIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiRouterCtrlPortConfigureCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlPortConfigureCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlPortConfigureCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlPortConfigureCfmSerFree CsrWifiRouterCtrlPfree
+
+#define CsrWifiRouterCtrlResumeIndSer CsrWifiEventCsrUint16CsrUint8Ser
+#define CsrWifiRouterCtrlResumeIndDes CsrWifiEventCsrUint16CsrUint8Des
+#define CsrWifiRouterCtrlResumeIndSizeof CsrWifiEventCsrUint16CsrUint8Sizeof
+#define CsrWifiRouterCtrlResumeIndSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlSuspendIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlSuspendIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlSuspendIndSizeof(void *msg);
+#define CsrWifiRouterCtrlSuspendIndSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlTclasAddCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlTclasAddCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlTclasAddCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlTclasAddCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlRawSdioDeinitialiseCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlRawSdioDeinitialiseCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlRawSdioDeinitialiseCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlRawSdioDeinitialiseCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlRawSdioInitialiseCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlRawSdioInitialiseCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlRawSdioInitialiseCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlRawSdioInitialiseCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlTclasDelCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlTclasDelCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlTclasDelCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlTclasDelCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlTrafficProtocolIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlTrafficProtocolIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlTrafficProtocolIndSizeof(void *msg);
+#define CsrWifiRouterCtrlTrafficProtocolIndSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlTrafficSampleIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlTrafficSampleIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlTrafficSampleIndSizeof(void *msg);
+#define CsrWifiRouterCtrlTrafficSampleIndSerFree CsrWifiRouterCtrlPfree
+
+#define CsrWifiRouterCtrlWifiOffIndSer CsrWifiEventCsrUint16CsrUint8Ser
+#define CsrWifiRouterCtrlWifiOffIndDes CsrWifiEventCsrUint16CsrUint8Des
+#define CsrWifiRouterCtrlWifiOffIndSizeof CsrWifiEventCsrUint16CsrUint8Sizeof
+#define CsrWifiRouterCtrlWifiOffIndSerFree CsrWifiRouterCtrlPfree
+
+#define CsrWifiRouterCtrlWifiOffCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiRouterCtrlWifiOffCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiRouterCtrlWifiOffCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiRouterCtrlWifiOffCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlWifiOnIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlWifiOnIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlWifiOnIndSizeof(void *msg);
+extern void CsrWifiRouterCtrlWifiOnIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiRouterCtrlWifiOnCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlWifiOnCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlWifiOnCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlWifiOnCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlM4ReadyToSendIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlM4ReadyToSendIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlM4ReadyToSendIndSizeof(void *msg);
+#define CsrWifiRouterCtrlM4ReadyToSendIndSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlM4TransmittedIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlM4TransmittedIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlM4TransmittedIndSizeof(void *msg);
+#define CsrWifiRouterCtrlM4TransmittedIndSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlMicFailureIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlMicFailureIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlMicFailureIndSizeof(void *msg);
+#define CsrWifiRouterCtrlMicFailureIndSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlConnectedIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlConnectedIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlConnectedIndSizeof(void *msg);
+#define CsrWifiRouterCtrlConnectedIndSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlPeerAddCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlPeerAddCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlPeerAddCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlPeerAddCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlPeerDelCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlPeerDelCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlPeerDelCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlPeerDelCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlUnexpectedFrameIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlUnexpectedFrameIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlUnexpectedFrameIndSizeof(void *msg);
+#define CsrWifiRouterCtrlUnexpectedFrameIndSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlPeerUpdateCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlPeerUpdateCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlPeerUpdateCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlPeerUpdateCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlCapabilitiesCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlCapabilitiesCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlCapabilitiesCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlCapabilitiesCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlBlockAckEnableCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlBlockAckEnableCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlBlockAckEnableCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlBlockAckEnableCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlBlockAckDisableCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlBlockAckDisableCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlBlockAckDisableCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlBlockAckDisableCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlBlockAckErrorIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlBlockAckErrorIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlBlockAckErrorIndSizeof(void *msg);
+#define CsrWifiRouterCtrlBlockAckErrorIndSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlStaInactiveIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlStaInactiveIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlStaInactiveIndSizeof(void *msg);
+#define CsrWifiRouterCtrlStaInactiveIndSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlWapiRxMicCheckIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlWapiRxMicCheckIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlWapiRxMicCheckIndSizeof(void *msg);
+extern void CsrWifiRouterCtrlWapiRxMicCheckIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiRouterCtrlModeSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlModeSetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlModeSetCfmSizeof(void *msg);
+#define CsrWifiRouterCtrlModeSetCfmSerFree CsrWifiRouterCtrlPfree
+
+extern CsrUint8* CsrWifiRouterCtrlWapiUnicastTxEncryptIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterCtrlWapiUnicastTxEncryptIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterCtrlWapiUnicastTxEncryptIndSizeof(void *msg);
+extern void CsrWifiRouterCtrlWapiUnicastTxEncryptIndSerFree(void *msg);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* CSR_WIFI_ROUTER_CTRL_SERIALIZE_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_router_free_downstream_contents.c b/drivers/staging/csr/csr_wifi_router_free_downstream_contents.c
new file mode 100644
index 0000000..9ae6cff
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_free_downstream_contents.c
@@ -0,0 +1,54 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_wifi_router_prim.h"
+#include "csr_wifi_router_lib.h"
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrWifiRouterFreeDownstreamMessageContents
+ *
+ *  DESCRIPTION
+ *
+ *
+ *  PARAMETERS
+ *      eventClass: only the value CSR_WIFI_ROUTER_PRIM will be handled
+ *      message:    the message to free
+ *----------------------------------------------------------------------------*/
+void CsrWifiRouterFreeDownstreamMessageContents(CsrUint16 eventClass, void *message)
+{
+    if (eventClass != CSR_WIFI_ROUTER_PRIM)
+    {
+        return;
+    }
+    if (NULL == message)
+    {
+        return;
+    }
+
+    switch (*((CsrWifiRouterPrim *) message))
+    {
+        case CSR_WIFI_ROUTER_MA_PACKET_REQ:
+        {
+            CsrWifiRouterMaPacketReq *p = (CsrWifiRouterMaPacketReq *)message;
+            CsrPmemFree(p->frame);
+            p->frame = NULL;
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_router_free_upstream_contents.c b/drivers/staging/csr/csr_wifi_router_free_upstream_contents.c
new file mode 100644
index 0000000..19d9c23
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_free_upstream_contents.c
@@ -0,0 +1,54 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_wifi_router_prim.h"
+#include "csr_wifi_router_lib.h"
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrWifiRouterFreeUpstreamMessageContents
+ *
+ *  DESCRIPTION
+ *
+ *
+ *  PARAMETERS
+ *      eventClass: only the value CSR_WIFI_ROUTER_PRIM will be handled
+ *      message:    the message to free
+ *----------------------------------------------------------------------------*/
+void CsrWifiRouterFreeUpstreamMessageContents(CsrUint16 eventClass, void *message)
+{
+    if (eventClass != CSR_WIFI_ROUTER_PRIM)
+    {
+        return;
+    }
+    if (NULL == message)
+    {
+        return;
+    }
+
+    switch (*((CsrWifiRouterPrim *) message))
+    {
+        case CSR_WIFI_ROUTER_MA_PACKET_IND:
+        {
+            CsrWifiRouterMaPacketInd *p = (CsrWifiRouterMaPacketInd *)message;
+            CsrPmemFree(p->frame);
+            p->frame = NULL;
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_router_lib.h b/drivers/staging/csr/csr_wifi_router_lib.h
new file mode 100644
index 0000000..553e7d3
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_lib.h
@@ -0,0 +1,429 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_ROUTER_LIB_H__
+#define CSR_WIFI_ROUTER_LIB_H__
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_sched.h"
+#include "csr_util.h"
+#include "csr_msg_transport.h"
+
+#include "csr_wifi_lib.h"
+
+#include "csr_wifi_router_prim.h"
+#include "csr_wifi_router_task.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiRouterFreeUpstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_ROUTER upstream message. Does not
+ *      free the message itself, and can only be used for upstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_ROUTER upstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiRouterFreeUpstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiRouterFreeDownstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_ROUTER downstream message. Does not
+ *      free the message itself, and can only be used for downstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_ROUTER downstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiRouterFreeDownstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ * Enum to string functions
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiRouterAppTypeToString(CsrWifiRouterAppType value);
+const CsrCharString* CsrWifiRouterEncapsulationToString(CsrWifiRouterEncapsulation value);
+const CsrCharString* CsrWifiRouterOuiToString(CsrWifiRouterOui value);
+const CsrCharString* CsrWifiRouterPriorityToString(CsrWifiRouterPriority value);
+
+
+/*----------------------------------------------------------------------------*
+ * CsrPrim Type toString function.
+ * Converts a message type to the String name of the Message
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiRouterPrimTypeToString(CsrPrim msgType);
+
+/*----------------------------------------------------------------------------*
+ * Lookup arrays for PrimType name Strings
+ *----------------------------------------------------------------------------*/
+extern const CsrCharString *CsrWifiRouterUpstreamPrimNames[CSR_WIFI_ROUTER_PRIM_UPSTREAM_COUNT];
+extern const CsrCharString *CsrWifiRouterDownstreamPrimNames[CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_COUNT];
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketCancelReqSend
+
+  DESCRIPTION
+    This primitive is used to request cancellation of a previously send
+    CsrWifiRouterMaPacketReq.
+    The frame may already have been transmitted so there is no guarantees
+    that the CsrWifiRouterMaPacketCancelReq actually cancels the transmission
+    of the frame in question.
+    If the cancellation fails, the Router will send, if required,
+    CsrWifiRouterMaPacketCfm.
+    If the cancellation succeeds, the Router will not send
+    CsrWifiRouterMaPacketCfm.
+
+  PARAMETERS
+    queue          - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    hostTag        - The hostTag for the frame, which should be cancelled.
+    priority       - Priority of the frame, which should be cancelled
+    peerMacAddress - Destination MAC address of the frame, which should be
+                     cancelled
+
+*******************************************************************************/
+#define CsrWifiRouterMaPacketCancelReqCreate(msg__, dst__, src__, interfaceTag__, hostTag__, priority__, peerMacAddress__) \
+    msg__ = (CsrWifiRouterMaPacketCancelReq *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketCancelReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_PRIM, CSR_WIFI_ROUTER_MA_PACKET_CANCEL_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->hostTag = (hostTag__); \
+    msg__->priority = (priority__); \
+    msg__->peerMacAddress = (peerMacAddress__);
+
+#define CsrWifiRouterMaPacketCancelReqSendTo(dst__, src__, interfaceTag__, hostTag__, priority__, peerMacAddress__) \
+    { \
+        CsrWifiRouterMaPacketCancelReq *msg__; \
+        CsrWifiRouterMaPacketCancelReqCreate(msg__, dst__, src__, interfaceTag__, hostTag__, priority__, peerMacAddress__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterMaPacketCancelReqSend(src__, interfaceTag__, hostTag__, priority__, peerMacAddress__) \
+    CsrWifiRouterMaPacketCancelReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, hostTag__, priority__, peerMacAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketReqSend
+
+  DESCRIPTION
+    A task sends this primitive to transmit a frame.
+
+  PARAMETERS
+    queue              - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag       - Interface Identifier; unique identifier of an interface
+    subscriptionHandle - The handle of the subscription
+    frameLength        - Length of the frame to be sent in bytes
+    frame              - Pointer to the frame to be sent
+    freeFunction       - Pointer to function to be used to free the frame
+    priority           - Priority of the frame, which should be sent
+    hostTag            - An application shall set the bits b31..b28 using one of
+                         the CSR_WIFI_ROUTER_APP_TYPE_* masks. Bits b0..b27 can
+                         be used by the requestor without any restrictions, but
+                         the hostTag shall be unique so the hostTag for
+                         CSR_WIFI_ROUTER_APP _TYPE_OTHER should be constructured
+                         in the following way [ CSR_WIFI_ROUTER_APP_TYPE_OTHER
+                         (4 bits) | SubscriptionHandle (8 bits) | Sequence no.
+                         (20 bits) ]. If the hostTag is not unique, the
+                         behaviour of the system is unpredicatable with respect
+                         to data/management frame transfer.
+    cfmRequested       - Indicates if the requestor needs a confirm for packet
+                         requests sent under this subscription. If set to TRUE,
+                         the router will send a confirm, else it will not send
+                         any confirm
+
+*******************************************************************************/
+#define CsrWifiRouterMaPacketReqCreate(msg__, dst__, src__, interfaceTag__, subscriptionHandle__, frameLength__, frame__, freeFunction__, priority__, hostTag__, cfmRequested__) \
+    msg__ = (CsrWifiRouterMaPacketReq *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_PRIM, CSR_WIFI_ROUTER_MA_PACKET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->subscriptionHandle = (subscriptionHandle__); \
+    msg__->frameLength = (frameLength__); \
+    msg__->frame = (frame__); \
+    msg__->freeFunction = (freeFunction__); \
+    msg__->priority = (priority__); \
+    msg__->hostTag = (hostTag__); \
+    msg__->cfmRequested = (cfmRequested__);
+
+#define CsrWifiRouterMaPacketReqSendTo(dst__, src__, interfaceTag__, subscriptionHandle__, frameLength__, frame__, freeFunction__, priority__, hostTag__, cfmRequested__) \
+    { \
+        CsrWifiRouterMaPacketReq *msg__; \
+        CsrWifiRouterMaPacketReqCreate(msg__, dst__, src__, interfaceTag__, subscriptionHandle__, frameLength__, frame__, freeFunction__, priority__, hostTag__, cfmRequested__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterMaPacketReqSend(src__, interfaceTag__, subscriptionHandle__, frameLength__, frame__, freeFunction__, priority__, hostTag__, cfmRequested__) \
+    CsrWifiRouterMaPacketReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, subscriptionHandle__, frameLength__, frame__, freeFunction__, priority__, hostTag__, cfmRequested__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketIndSend
+
+  DESCRIPTION
+    The router sends the primitive to a subscribed task when it receives a
+    frame matching the subscription.
+
+  PARAMETERS
+    queue              - Destination Task Queue
+    interfaceTag       - Interface Identifier; unique identifier of an interface
+    subscriptionHandle - The handle of the subscription
+    result             - Status of the operation
+    frameLength        - Length of the received frame in bytes
+    frame              - Pointer to the received frame
+    freeFunction       - Pointer to function to be used to free the frame
+    rssi               - Received signal strength indication in dBm
+    snr                - Signal to Noise Ratio
+    rate               - Transmission/Reception rate
+
+*******************************************************************************/
+#define CsrWifiRouterMaPacketIndCreate(msg__, dst__, src__, interfaceTag__, subscriptionHandle__, result__, frameLength__, frame__, freeFunction__, rssi__, snr__, rate__) \
+    msg__ = (CsrWifiRouterMaPacketInd *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_PRIM, CSR_WIFI_ROUTER_MA_PACKET_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->subscriptionHandle = (subscriptionHandle__); \
+    msg__->result = (result__); \
+    msg__->frameLength = (frameLength__); \
+    msg__->frame = (frame__); \
+    msg__->freeFunction = (freeFunction__); \
+    msg__->rssi = (rssi__); \
+    msg__->snr = (snr__); \
+    msg__->rate = (rate__);
+
+#define CsrWifiRouterMaPacketIndSendTo(dst__, src__, interfaceTag__, subscriptionHandle__, result__, frameLength__, frame__, freeFunction__, rssi__, snr__, rate__) \
+    { \
+        CsrWifiRouterMaPacketInd *msg__; \
+        CsrWifiRouterMaPacketIndCreate(msg__, dst__, src__, interfaceTag__, subscriptionHandle__, result__, frameLength__, frame__, freeFunction__, rssi__, snr__, rate__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterMaPacketIndSend(dst__, interfaceTag__, subscriptionHandle__, result__, frameLength__, frame__, freeFunction__, rssi__, snr__, rate__) \
+    CsrWifiRouterMaPacketIndSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, interfaceTag__, subscriptionHandle__, result__, frameLength__, frame__, freeFunction__, rssi__, snr__, rate__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketResSend
+
+  DESCRIPTION
+    A task send this primitive to confirm the reception of the received
+    frame.
+
+  PARAMETERS
+    interfaceTag       - Interface Identifier; unique identifier of an interface
+    subscriptionHandle - The handle of the subscription
+    result             - Status of the operation
+
+*******************************************************************************/
+#define CsrWifiRouterMaPacketResCreate(msg__, dst__, src__, interfaceTag__, subscriptionHandle__, result__) \
+    msg__ = (CsrWifiRouterMaPacketRes *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketRes)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_PRIM, CSR_WIFI_ROUTER_MA_PACKET_RES, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->subscriptionHandle = (subscriptionHandle__); \
+    msg__->result = (result__);
+
+#define CsrWifiRouterMaPacketResSendTo(dst__, src__, interfaceTag__, subscriptionHandle__, result__) \
+    { \
+        CsrWifiRouterMaPacketRes *msg__; \
+        CsrWifiRouterMaPacketResCreate(msg__, dst__, src__, interfaceTag__, subscriptionHandle__, result__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterMaPacketResSend(src__, interfaceTag__, subscriptionHandle__, result__) \
+    CsrWifiRouterMaPacketResSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, subscriptionHandle__, result__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketCfmSend
+
+  DESCRIPTION
+    The router sends the primitive to confirm the result of the transmission
+    of the packet of the corresponding CSR_WIFI_ROUTER MA_PACKET_REQ request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    result       - Status of the operation
+    hostTag      - The hostTrag will match the hostTag sent in the request.
+    rate         - Transmission/Reception rate
+
+*******************************************************************************/
+#define CsrWifiRouterMaPacketCfmCreate(msg__, dst__, src__, interfaceTag__, result__, hostTag__, rate__) \
+    msg__ = (CsrWifiRouterMaPacketCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_PRIM, CSR_WIFI_ROUTER_MA_PACKET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->result = (result__); \
+    msg__->hostTag = (hostTag__); \
+    msg__->rate = (rate__);
+
+#define CsrWifiRouterMaPacketCfmSendTo(dst__, src__, interfaceTag__, result__, hostTag__, rate__) \
+    { \
+        CsrWifiRouterMaPacketCfm *msg__; \
+        CsrWifiRouterMaPacketCfmCreate(msg__, dst__, src__, interfaceTag__, result__, hostTag__, rate__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterMaPacketCfmSend(dst__, interfaceTag__, result__, hostTag__, rate__) \
+    CsrWifiRouterMaPacketCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, interfaceTag__, result__, hostTag__, rate__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketSubscribeReqSend
+
+  DESCRIPTION
+    A task can use this primitive to subscribe for a particular OUI/protocol
+    and transmit and receive frames matching the subscription.
+    NOTE: Multiple subscriptions for a given protocol and OUI will result in
+    the first subscription receiving the data and not the subsequent
+    subscriptions.
+
+  PARAMETERS
+    queue         - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    encapsulation - Specifies the encapsulation type, which will be used for the
+                    subscription
+    protocol      - Together with the OUI, specifies the protocol, which a task
+                    wants to subscribe to
+    oui           - Specifies the OUI for the protocol, which a task wants to
+                    subscribe to
+
+*******************************************************************************/
+#define CsrWifiRouterMaPacketSubscribeReqCreate(msg__, dst__, src__, interfaceTag__, encapsulation__, protocol__, oui__) \
+    msg__ = (CsrWifiRouterMaPacketSubscribeReq *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketSubscribeReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_PRIM, CSR_WIFI_ROUTER_MA_PACKET_SUBSCRIBE_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->encapsulation = (encapsulation__); \
+    msg__->protocol = (protocol__); \
+    msg__->oui = (oui__);
+
+#define CsrWifiRouterMaPacketSubscribeReqSendTo(dst__, src__, interfaceTag__, encapsulation__, protocol__, oui__) \
+    { \
+        CsrWifiRouterMaPacketSubscribeReq *msg__; \
+        CsrWifiRouterMaPacketSubscribeReqCreate(msg__, dst__, src__, interfaceTag__, encapsulation__, protocol__, oui__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterMaPacketSubscribeReqSend(src__, interfaceTag__, encapsulation__, protocol__, oui__) \
+    CsrWifiRouterMaPacketSubscribeReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, encapsulation__, protocol__, oui__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketSubscribeCfmSend
+
+  DESCRIPTION
+    The router sends this primitive to confirm the result of the
+    subscription.
+
+  PARAMETERS
+    queue              - Destination Task Queue
+    interfaceTag       - Interface Identifier; unique identifier of an interface
+    subscriptionHandle - Handle to the subscription
+                         This handle must be used in all subsequent requests
+    status             - Status of the operation
+    allocOffset        - Size of the offset for the frames of the subscription
+
+*******************************************************************************/
+#define CsrWifiRouterMaPacketSubscribeCfmCreate(msg__, dst__, src__, interfaceTag__, subscriptionHandle__, status__, allocOffset__) \
+    msg__ = (CsrWifiRouterMaPacketSubscribeCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketSubscribeCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_PRIM, CSR_WIFI_ROUTER_MA_PACKET_SUBSCRIBE_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->subscriptionHandle = (subscriptionHandle__); \
+    msg__->status = (status__); \
+    msg__->allocOffset = (allocOffset__);
+
+#define CsrWifiRouterMaPacketSubscribeCfmSendTo(dst__, src__, interfaceTag__, subscriptionHandle__, status__, allocOffset__) \
+    { \
+        CsrWifiRouterMaPacketSubscribeCfm *msg__; \
+        CsrWifiRouterMaPacketSubscribeCfmCreate(msg__, dst__, src__, interfaceTag__, subscriptionHandle__, status__, allocOffset__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterMaPacketSubscribeCfmSend(dst__, interfaceTag__, subscriptionHandle__, status__, allocOffset__) \
+    CsrWifiRouterMaPacketSubscribeCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, interfaceTag__, subscriptionHandle__, status__, allocOffset__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketUnsubscribeReqSend
+
+  DESCRIPTION
+    A task sends this primitive to unsubscribe a subscription
+
+  PARAMETERS
+    queue              - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag       - Interface Identifier; unique identifier of an interface
+    subscriptionHandle - The handle of the subscription
+
+*******************************************************************************/
+#define CsrWifiRouterMaPacketUnsubscribeReqCreate(msg__, dst__, src__, interfaceTag__, subscriptionHandle__) \
+    msg__ = (CsrWifiRouterMaPacketUnsubscribeReq *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketUnsubscribeReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_PRIM, CSR_WIFI_ROUTER_MA_PACKET_UNSUBSCRIBE_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->subscriptionHandle = (subscriptionHandle__);
+
+#define CsrWifiRouterMaPacketUnsubscribeReqSendTo(dst__, src__, interfaceTag__, subscriptionHandle__) \
+    { \
+        CsrWifiRouterMaPacketUnsubscribeReq *msg__; \
+        CsrWifiRouterMaPacketUnsubscribeReqCreate(msg__, dst__, src__, interfaceTag__, subscriptionHandle__); \
+        CsrMsgTransport(dst__, CSR_WIFI_ROUTER_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterMaPacketUnsubscribeReqSend(src__, interfaceTag__, subscriptionHandle__) \
+    CsrWifiRouterMaPacketUnsubscribeReqSendTo(CSR_WIFI_ROUTER_IFACEQUEUE, src__, interfaceTag__, subscriptionHandle__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketUnsubscribeCfmSend
+
+  DESCRIPTION
+    The router sends this primitive to confirm the result of the
+    unsubscription.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Status of the operation
+
+*******************************************************************************/
+#define CsrWifiRouterMaPacketUnsubscribeCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiRouterMaPacketUnsubscribeCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketUnsubscribeCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_ROUTER_PRIM, CSR_WIFI_ROUTER_MA_PACKET_UNSUBSCRIBE_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiRouterMaPacketUnsubscribeCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiRouterMaPacketUnsubscribeCfm *msg__; \
+        CsrWifiRouterMaPacketUnsubscribeCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_ROUTER_PRIM, msg__); \
+    }
+
+#define CsrWifiRouterMaPacketUnsubscribeCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiRouterMaPacketUnsubscribeCfmSendTo(dst__, CSR_WIFI_ROUTER_IFACEQUEUE, interfaceTag__, status__)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_ROUTER_LIB_H__ */
diff --git a/drivers/staging/csr/csr_wifi_router_prim.h b/drivers/staging/csr/csr_wifi_router_prim.h
new file mode 100644
index 0000000..67b71a4
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_prim.h
@@ -0,0 +1,430 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_ROUTER_PRIM_H__
+#define CSR_WIFI_ROUTER_PRIM_H__
+
+#include "csr_types.h"
+#include "csr_prim_defs.h"
+#include "csr_sched.h"
+#include "csr_wifi_common.h"
+#include "csr_result.h"
+#include "csr_wifi_fsm_event.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CSR_WIFI_ROUTER_PRIM                                            (0x0400)
+
+typedef CsrPrim CsrWifiRouterPrim;
+
+typedef void (*CsrWifiRouterFrameFreeFunction)(void *frame);
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterAppType
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_APP_TYPE_SME   -
+    CSR_WIFI_ROUTER_APP_TYPE_PAL   -
+    CSR_WIFI_ROUTER_APP_TYPE_NME   -
+    CSR_WIFI_ROUTER_APP_TYPE_OTHER -
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterAppType;
+#define CSR_WIFI_ROUTER_APP_TYPE_SME     ((CsrWifiRouterAppType) 0x0)
+#define CSR_WIFI_ROUTER_APP_TYPE_PAL     ((CsrWifiRouterAppType) 0x1)
+#define CSR_WIFI_ROUTER_APP_TYPE_NME     ((CsrWifiRouterAppType) 0x2)
+#define CSR_WIFI_ROUTER_APP_TYPE_OTHER   ((CsrWifiRouterAppType) 0x3)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterEncapsulation
+
+  DESCRIPTION
+    Indicates the type of encapsulation used for the subscription
+
+ VALUES
+    CSR_WIFI_ROUTER_ENCAPSULATION_ETHERNET
+                   - Ethernet encapsulation
+    CSR_WIFI_ROUTER_ENCAPSULATION_LLC_SNAP
+                   - LLC/SNAP encapsulation
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiRouterEncapsulation;
+#define CSR_WIFI_ROUTER_ENCAPSULATION_ETHERNET   ((CsrWifiRouterEncapsulation) 0x00)
+#define CSR_WIFI_ROUTER_ENCAPSULATION_LLC_SNAP   ((CsrWifiRouterEncapsulation) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterOui
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_ROUTER_OUI_RFC_1042 -
+    CSR_WIFI_ROUTER_OUI_BT       -
+
+*******************************************************************************/
+typedef CsrUint32 CsrWifiRouterOui;
+#define CSR_WIFI_ROUTER_OUI_RFC_1042   ((CsrWifiRouterOui) 0x000000)
+#define CSR_WIFI_ROUTER_OUI_BT         ((CsrWifiRouterOui) 0x001958)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterPriority
+
+  DESCRIPTION
+    As defined in the IEEE 802.11 standards
+
+ VALUES
+    CSR_WIFI_ROUTER_PRIORITY_QOS_UP0
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_ROUTER_PRIORITY_QOS_UP1
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_ROUTER_PRIORITY_QOS_UP2
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_ROUTER_PRIORITY_QOS_UP3
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_ROUTER_PRIORITY_QOS_UP4
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_ROUTER_PRIORITY_QOS_UP5
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_ROUTER_PRIORITY_QOS_UP6
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_ROUTER_PRIORITY_QOS_UP7
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_ROUTER_PRIORITY_CONTENTION
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_ROUTER_PRIORITY_MANAGEMENT
+                   - See IEEE 802.11 Standard
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiRouterPriority;
+#define CSR_WIFI_ROUTER_PRIORITY_QOS_UP0      ((CsrWifiRouterPriority) 0x0000)
+#define CSR_WIFI_ROUTER_PRIORITY_QOS_UP1      ((CsrWifiRouterPriority) 0x0001)
+#define CSR_WIFI_ROUTER_PRIORITY_QOS_UP2      ((CsrWifiRouterPriority) 0x0002)
+#define CSR_WIFI_ROUTER_PRIORITY_QOS_UP3      ((CsrWifiRouterPriority) 0x0003)
+#define CSR_WIFI_ROUTER_PRIORITY_QOS_UP4      ((CsrWifiRouterPriority) 0x0004)
+#define CSR_WIFI_ROUTER_PRIORITY_QOS_UP5      ((CsrWifiRouterPriority) 0x0005)
+#define CSR_WIFI_ROUTER_PRIORITY_QOS_UP6      ((CsrWifiRouterPriority) 0x0006)
+#define CSR_WIFI_ROUTER_PRIORITY_QOS_UP7      ((CsrWifiRouterPriority) 0x0007)
+#define CSR_WIFI_ROUTER_PRIORITY_CONTENTION   ((CsrWifiRouterPriority) 0x8000)
+#define CSR_WIFI_ROUTER_PRIORITY_MANAGEMENT   ((CsrWifiRouterPriority) 0x8010)
+
+
+/* Downstream */
+#define CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_LOWEST            (0x0000)
+
+#define CSR_WIFI_ROUTER_MA_PACKET_SUBSCRIBE_REQ           ((CsrWifiRouterPrim) (0x0000 + CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_MA_PACKET_UNSUBSCRIBE_REQ         ((CsrWifiRouterPrim) (0x0001 + CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_MA_PACKET_REQ                     ((CsrWifiRouterPrim) (0x0002 + CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_MA_PACKET_RES                     ((CsrWifiRouterPrim) (0x0003 + CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_MA_PACKET_CANCEL_REQ              ((CsrWifiRouterPrim) (0x0004 + CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_LOWEST))
+
+
+#define CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_HIGHEST           (0x0004 + CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_LOWEST)
+
+/* Upstream */
+#define CSR_WIFI_ROUTER_PRIM_UPSTREAM_LOWEST              (0x0000 + CSR_PRIM_UPSTREAM)
+
+#define CSR_WIFI_ROUTER_MA_PACKET_SUBSCRIBE_CFM           ((CsrWifiRouterPrim)(0x0000 + CSR_WIFI_ROUTER_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_MA_PACKET_UNSUBSCRIBE_CFM         ((CsrWifiRouterPrim)(0x0001 + CSR_WIFI_ROUTER_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_MA_PACKET_CFM                     ((CsrWifiRouterPrim)(0x0002 + CSR_WIFI_ROUTER_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_ROUTER_MA_PACKET_IND                     ((CsrWifiRouterPrim)(0x0003 + CSR_WIFI_ROUTER_PRIM_UPSTREAM_LOWEST))
+
+#define CSR_WIFI_ROUTER_PRIM_UPSTREAM_HIGHEST             (0x0003 + CSR_WIFI_ROUTER_PRIM_UPSTREAM_LOWEST)
+
+#define CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_COUNT             (CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_HIGHEST + 1 - CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_LOWEST)
+#define CSR_WIFI_ROUTER_PRIM_UPSTREAM_COUNT               (CSR_WIFI_ROUTER_PRIM_UPSTREAM_HIGHEST   + 1 - CSR_WIFI_ROUTER_PRIM_UPSTREAM_LOWEST)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketSubscribeReq
+
+  DESCRIPTION
+    A task can use this primitive to subscribe for a particular OUI/protocol
+    and transmit and receive frames matching the subscription.
+    NOTE: Multiple subscriptions for a given protocol and OUI will result in
+    the first subscription receiving the data and not the subsequent
+    subscriptions.
+
+  MEMBERS
+    common        - Common header for use with the CsrWifiFsm Module
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    encapsulation - Specifies the encapsulation type, which will be used for the
+                    subscription
+    protocol      - Together with the OUI, specifies the protocol, which a task
+                    wants to subscribe to
+    oui           - Specifies the OUI for the protocol, which a task wants to
+                    subscribe to
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent            common;
+    CsrUint16                  interfaceTag;
+    CsrWifiRouterEncapsulation encapsulation;
+    CsrUint16                  protocol;
+    CsrUint32                  oui;
+} CsrWifiRouterMaPacketSubscribeReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketUnsubscribeReq
+
+  DESCRIPTION
+    A task sends this primitive to unsubscribe a subscription
+
+  MEMBERS
+    common             - Common header for use with the CsrWifiFsm Module
+    interfaceTag       - Interface Identifier; unique identifier of an interface
+    subscriptionHandle - The handle of the subscription
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrUint8        subscriptionHandle;
+} CsrWifiRouterMaPacketUnsubscribeReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketReq
+
+  DESCRIPTION
+    A task sends this primitive to transmit a frame.
+
+  MEMBERS
+    common             - Common header for use with the CsrWifiFsm Module
+    interfaceTag       - Interface Identifier; unique identifier of an interface
+    subscriptionHandle - The handle of the subscription
+    frameLength        - Length of the frame to be sent in bytes
+    frame              - Pointer to the frame to be sent
+    freeFunction       - Pointer to function to be used to free the frame
+    priority           - Priority of the frame, which should be sent
+    hostTag            - An application shall set the bits b31..b28 using one of
+                         the CSR_WIFI_ROUTER_APP_TYPE_* masks. Bits b0..b27 can
+                         be used by the requestor without any restrictions, but
+                         the hostTag shall be unique so the hostTag for
+                         CSR_WIFI_ROUTER_APP _TYPE_OTHER should be constructured
+                         in the following way [ CSR_WIFI_ROUTER_APP_TYPE_OTHER
+                         (4 bits) | SubscriptionHandle (8 bits) | Sequence no.
+                         (20 bits) ]. If the hostTag is not unique, the
+                         behaviour of the system is unpredicatable with respect
+                         to data/management frame transfer.
+    cfmRequested       - Indicates if the requestor needs a confirm for packet
+                         requests sent under this subscription. If set to TRUE,
+                         the router will send a confirm, else it will not send
+                         any confirm
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrUint16                      interfaceTag;
+    CsrUint8                       subscriptionHandle;
+    CsrUint16                      frameLength;
+    CsrUint8                      *frame;
+    CsrWifiRouterFrameFreeFunction freeFunction;
+    CsrWifiRouterPriority          priority;
+    CsrUint32                      hostTag;
+    CsrBool                        cfmRequested;
+} CsrWifiRouterMaPacketReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketRes
+
+  DESCRIPTION
+    A task send this primitive to confirm the reception of the received
+    frame.
+
+  MEMBERS
+    common             - Common header for use with the CsrWifiFsm Module
+    interfaceTag       - Interface Identifier; unique identifier of an interface
+    subscriptionHandle - The handle of the subscription
+    result             - Status of the operation
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrUint8        subscriptionHandle;
+    CsrResult       result;
+} CsrWifiRouterMaPacketRes;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketCancelReq
+
+  DESCRIPTION
+    This primitive is used to request cancellation of a previously send
+    CsrWifiRouterMaPacketReq.
+    The frame may already have been transmitted so there is no guarantees
+    that the CsrWifiRouterMaPacketCancelReq actually cancels the transmission
+    of the frame in question.
+    If the cancellation fails, the Router will send, if required,
+    CsrWifiRouterMaPacketCfm.
+    If the cancellation succeeds, the Router will not send
+    CsrWifiRouterMaPacketCfm.
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    hostTag        - The hostTag for the frame, which should be cancelled.
+    priority       - Priority of the frame, which should be cancelled
+    peerMacAddress - Destination MAC address of the frame, which should be
+                     cancelled
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrUint16             interfaceTag;
+    CsrUint32             hostTag;
+    CsrWifiRouterPriority priority;
+    CsrWifiMacAddress     peerMacAddress;
+} CsrWifiRouterMaPacketCancelReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketSubscribeCfm
+
+  DESCRIPTION
+    The router sends this primitive to confirm the result of the
+    subscription.
+
+  MEMBERS
+    common             - Common header for use with the CsrWifiFsm Module
+    interfaceTag       - Interface Identifier; unique identifier of an interface
+    subscriptionHandle - Handle to the subscription
+                         This handle must be used in all subsequent requests
+    status             - Status of the operation
+    allocOffset        - Size of the offset for the frames of the subscription
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrUint8        subscriptionHandle;
+    CsrResult       status;
+    CsrUint16       allocOffset;
+} CsrWifiRouterMaPacketSubscribeCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketUnsubscribeCfm
+
+  DESCRIPTION
+    The router sends this primitive to confirm the result of the
+    unsubscription.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Status of the operation
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiRouterMaPacketUnsubscribeCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketCfm
+
+  DESCRIPTION
+    The router sends the primitive to confirm the result of the transmission
+    of the packet of the corresponding CSR_WIFI_ROUTER MA_PACKET_REQ request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    result       - Status of the operation
+    hostTag      - The hostTrag will match the hostTag sent in the request.
+    rate         - Transmission/Reception rate
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       result;
+    CsrUint32       hostTag;
+    CsrUint16       rate;
+} CsrWifiRouterMaPacketCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiRouterMaPacketInd
+
+  DESCRIPTION
+    The router sends the primitive to a subscribed task when it receives a
+    frame matching the subscription.
+
+  MEMBERS
+    common             - Common header for use with the CsrWifiFsm Module
+    interfaceTag       - Interface Identifier; unique identifier of an interface
+    subscriptionHandle - The handle of the subscription
+    result             - Status of the operation
+    frameLength        - Length of the received frame in bytes
+    frame              - Pointer to the received frame
+    freeFunction       - Pointer to function to be used to free the frame
+    rssi               - Received signal strength indication in dBm
+    snr                - Signal to Noise Ratio
+    rate               - Transmission/Reception rate
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrUint16                      interfaceTag;
+    CsrUint8                       subscriptionHandle;
+    CsrResult                      result;
+    CsrUint16                      frameLength;
+    CsrUint8                      *frame;
+    CsrWifiRouterFrameFreeFunction freeFunction;
+    CsrInt16                       rssi;
+    CsrInt16                       snr;
+    CsrUint16                      rate;
+} CsrWifiRouterMaPacketInd;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_ROUTER_PRIM_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_router_sef.c b/drivers/staging/csr/csr_wifi_router_sef.c
new file mode 100644
index 0000000..45a10fb
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_sef.c
@@ -0,0 +1,19 @@
+/*****************************************************************************
+
+  (c) Cambridge Silicon Radio Limited 2010
+  Confidential information of CSR
+
+  Refer to LICENSE.txt included with this source for details
+  on the license terms.
+
+ *****************************************************************************/
+#include "csr_wifi_router_sef.h"
+
+const CsrWifiRouterStateHandlerType CsrWifiRouterDownstreamStateHandlers[CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_COUNT] =
+{
+    /* 0x0000 */ CsrWifiRouterMaPacketSubscribeReqHandler,
+    /* 0x0001 */ CsrWifiRouterMaPacketUnsubscribeReqHandler,
+    /* 0x0002 */ CsrWifiRouterMaPacketReqHandler,
+    /* 0x0003 */ CsrWifiRouterMaPacketResHandler,
+    /* 0x0004 */ CsrWifiRouterMaPacketCancelReqHandler,
+};
diff --git a/drivers/staging/csr/csr_wifi_router_sef.h b/drivers/staging/csr/csr_wifi_router_sef.h
new file mode 100644
index 0000000..49dd158
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_sef.h
@@ -0,0 +1,33 @@
+/*****************************************************************************
+
+  (c) Cambridge Silicon Radio Limited 2010
+  Confidential information of CSR
+
+  Refer to LICENSE.txt included with this source for details
+  on the license terms.
+
+ *****************************************************************************/
+#ifndef CSR_WIFI_ROUTER_SEF_CSR_WIFI_ROUTER_H__
+#define CSR_WIFI_ROUTER_SEF_CSR_WIFI_ROUTER_H__
+
+#include "csr_wifi_router_prim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    typedef void (*CsrWifiRouterStateHandlerType)(void* drvpriv, CsrWifiFsmEvent* msg);
+
+    extern const CsrWifiRouterStateHandlerType CsrWifiRouterDownstreamStateHandlers[CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_COUNT];
+
+    extern void CsrWifiRouterMaPacketSubscribeReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterMaPacketUnsubscribeReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterMaPacketReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterMaPacketResHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+    extern void CsrWifiRouterMaPacketCancelReqHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_ROUTER_SEF_CSR_WIFI_ROUTER_H__ */
diff --git a/drivers/staging/csr/csr_wifi_router_serialize.c b/drivers/staging/csr/csr_wifi_router_serialize.c
new file mode 100644
index 0000000..e1adf8f
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_serialize.c
@@ -0,0 +1,422 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_msgconv.h"
+#include "csr_unicode.h"
+
+
+#include "csr_wifi_router_prim.h"
+#include "csr_wifi_router_serialize.h"
+
+void CsrWifiRouterPfree(void *ptr)
+{
+    CsrPmemFree(ptr);
+}
+
+
+CsrSize CsrWifiRouterMaPacketSubscribeReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 12) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiRouterEncapsulation primitive->encapsulation */
+    bufferSize += 2; /* CsrUint16 primitive->protocol */
+    bufferSize += 4; /* CsrUint32 primitive->oui */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterMaPacketSubscribeReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterMaPacketSubscribeReq *primitive = (CsrWifiRouterMaPacketSubscribeReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->encapsulation);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->protocol);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->oui);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterMaPacketSubscribeReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterMaPacketSubscribeReq *primitive = (CsrWifiRouterMaPacketSubscribeReq *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketSubscribeReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->encapsulation, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->protocol, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->oui, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterMaPacketReqSizeof(void *msg)
+{
+    CsrWifiRouterMaPacketReq *primitive = (CsrWifiRouterMaPacketReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 20) */
+    bufferSize += 2;                      /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1;                      /* CsrUint8 primitive->subscriptionHandle */
+    bufferSize += 2;                      /* CsrUint16 primitive->frameLength */
+    bufferSize += primitive->frameLength; /* CsrUint8 primitive->frame */
+    bufferSize += 4;                      /* CsrWifiRouterFrameFreeFunction primitive->freeFunction */
+    bufferSize += 2;                      /* CsrWifiRouterPriority primitive->priority */
+    bufferSize += 4;                      /* CsrUint32 primitive->hostTag */
+    bufferSize += 1;                      /* CsrBool primitive->cfmRequested */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterMaPacketReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterMaPacketReq *primitive = (CsrWifiRouterMaPacketReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->subscriptionHandle);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->frameLength);
+    if (primitive->frameLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->frame, ((CsrUint16) (primitive->frameLength)));
+    }
+    CsrUint32Ser(ptr, len, 0); /* Special for Function Pointers... primitive->freeFunction */
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->priority);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->hostTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->cfmRequested);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterMaPacketReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterMaPacketReq *primitive = (CsrWifiRouterMaPacketReq *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->subscriptionHandle, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->frameLength, buffer, &offset);
+    if (primitive->frameLength)
+    {
+        primitive->frame = (CsrUint8 *)CsrPmemAlloc(primitive->frameLength);
+        CsrMemCpyDes(primitive->frame, buffer, &offset, ((CsrUint16) (primitive->frameLength)));
+    }
+    else
+    {
+        primitive->frame = NULL;
+    }
+    primitive->freeFunction = NULL; /* Special for Function Pointers... */
+    offset += 4;
+    CsrUint16Des((CsrUint16 *) &primitive->priority, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->hostTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->cfmRequested, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiRouterMaPacketReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterMaPacketReq *primitive = (CsrWifiRouterMaPacketReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->frame);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiRouterMaPacketResSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrUint8 primitive->subscriptionHandle */
+    bufferSize += 2; /* CsrResult primitive->result */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterMaPacketResSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterMaPacketRes *primitive = (CsrWifiRouterMaPacketRes *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->subscriptionHandle);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterMaPacketResDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterMaPacketRes *primitive = (CsrWifiRouterMaPacketRes *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketRes));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->subscriptionHandle, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->result, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterMaPacketCancelReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 17) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 4; /* CsrUint32 primitive->hostTag */
+    bufferSize += 2; /* CsrWifiRouterPriority primitive->priority */
+    bufferSize += 6; /* CsrUint8 primitive->peerMacAddress.a[6] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterMaPacketCancelReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterMaPacketCancelReq *primitive = (CsrWifiRouterMaPacketCancelReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->hostTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->priority);
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerMacAddress.a, ((CsrUint16) (6)));
+    return(ptr);
+}
+
+
+void* CsrWifiRouterMaPacketCancelReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterMaPacketCancelReq *primitive = (CsrWifiRouterMaPacketCancelReq *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketCancelReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->hostTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->priority, buffer, &offset);
+    CsrMemCpyDes(primitive->peerMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterMaPacketSubscribeCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrUint8 primitive->subscriptionHandle */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 2; /* CsrUint16 primitive->allocOffset */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterMaPacketSubscribeCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterMaPacketSubscribeCfm *primitive = (CsrWifiRouterMaPacketSubscribeCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->subscriptionHandle);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->allocOffset);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterMaPacketSubscribeCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterMaPacketSubscribeCfm *primitive = (CsrWifiRouterMaPacketSubscribeCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketSubscribeCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->subscriptionHandle, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->allocOffset, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterMaPacketUnsubscribeCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterMaPacketUnsubscribeCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterMaPacketUnsubscribeCfm *primitive = (CsrWifiRouterMaPacketUnsubscribeCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterMaPacketUnsubscribeCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterMaPacketUnsubscribeCfm *primitive = (CsrWifiRouterMaPacketUnsubscribeCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketUnsubscribeCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterMaPacketCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->result */
+    bufferSize += 4; /* CsrUint32 primitive->hostTag */
+    bufferSize += 2; /* CsrUint16 primitive->rate */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterMaPacketCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterMaPacketCfm *primitive = (CsrWifiRouterMaPacketCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->hostTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->rate);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterMaPacketCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterMaPacketCfm *primitive = (CsrWifiRouterMaPacketCfm *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->result, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->hostTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->rate, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiRouterMaPacketIndSizeof(void *msg)
+{
+    CsrWifiRouterMaPacketInd *primitive = (CsrWifiRouterMaPacketInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 21) */
+    bufferSize += 2;                      /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1;                      /* CsrUint8 primitive->subscriptionHandle */
+    bufferSize += 2;                      /* CsrResult primitive->result */
+    bufferSize += 2;                      /* CsrUint16 primitive->frameLength */
+    bufferSize += primitive->frameLength; /* CsrUint8 primitive->frame */
+    bufferSize += 4;                      /* CsrWifiRouterFrameFreeFunction primitive->freeFunction */
+    bufferSize += 2;                      /* CsrInt16 primitive->rssi */
+    bufferSize += 2;                      /* CsrInt16 primitive->snr */
+    bufferSize += 2;                      /* CsrUint16 primitive->rate */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiRouterMaPacketIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiRouterMaPacketInd *primitive = (CsrWifiRouterMaPacketInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->subscriptionHandle);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->frameLength);
+    if (primitive->frameLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->frame, ((CsrUint16) (primitive->frameLength)));
+    }
+    CsrUint32Ser(ptr, len, 0); /* Special for Function Pointers... primitive->freeFunction */
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->rssi);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->snr);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->rate);
+    return(ptr);
+}
+
+
+void* CsrWifiRouterMaPacketIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiRouterMaPacketInd *primitive = (CsrWifiRouterMaPacketInd *) CsrPmemAlloc(sizeof(CsrWifiRouterMaPacketInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->subscriptionHandle, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->result, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->frameLength, buffer, &offset);
+    if (primitive->frameLength)
+    {
+        primitive->frame = (CsrUint8 *)CsrPmemAlloc(primitive->frameLength);
+        CsrMemCpyDes(primitive->frame, buffer, &offset, ((CsrUint16) (primitive->frameLength)));
+    }
+    else
+    {
+        primitive->frame = NULL;
+    }
+    primitive->freeFunction = NULL; /* Special for Function Pointers... */
+    offset += 4;
+    CsrUint16Des((CsrUint16 *) &primitive->rssi, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->snr, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->rate, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiRouterMaPacketIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiRouterMaPacketInd *primitive = (CsrWifiRouterMaPacketInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->frame);
+    CsrPmemFree(primitive);
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_router_serialize.h b/drivers/staging/csr/csr_wifi_router_serialize.h
new file mode 100644
index 0000000..183a5a4
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_serialize.h
@@ -0,0 +1,78 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_ROUTER_SERIALIZE_H__
+#define CSR_WIFI_ROUTER_SERIALIZE_H__
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_wifi_msgconv.h"
+
+#include "csr_wifi_router_prim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void CsrWifiRouterPfree(void *ptr);
+
+extern CsrUint8* CsrWifiRouterMaPacketSubscribeReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterMaPacketSubscribeReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterMaPacketSubscribeReqSizeof(void *msg);
+#define CsrWifiRouterMaPacketSubscribeReqSerFree CsrWifiRouterPfree
+
+#define CsrWifiRouterMaPacketUnsubscribeReqSer CsrWifiEventCsrUint16CsrUint8Ser
+#define CsrWifiRouterMaPacketUnsubscribeReqDes CsrWifiEventCsrUint16CsrUint8Des
+#define CsrWifiRouterMaPacketUnsubscribeReqSizeof CsrWifiEventCsrUint16CsrUint8Sizeof
+#define CsrWifiRouterMaPacketUnsubscribeReqSerFree CsrWifiRouterPfree
+
+extern CsrUint8* CsrWifiRouterMaPacketReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterMaPacketReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterMaPacketReqSizeof(void *msg);
+extern void CsrWifiRouterMaPacketReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiRouterMaPacketResSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterMaPacketResDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterMaPacketResSizeof(void *msg);
+#define CsrWifiRouterMaPacketResSerFree CsrWifiRouterPfree
+
+extern CsrUint8* CsrWifiRouterMaPacketCancelReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterMaPacketCancelReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterMaPacketCancelReqSizeof(void *msg);
+#define CsrWifiRouterMaPacketCancelReqSerFree CsrWifiRouterPfree
+
+extern CsrUint8* CsrWifiRouterMaPacketSubscribeCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterMaPacketSubscribeCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterMaPacketSubscribeCfmSizeof(void *msg);
+#define CsrWifiRouterMaPacketSubscribeCfmSerFree CsrWifiRouterPfree
+
+extern CsrUint8* CsrWifiRouterMaPacketUnsubscribeCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterMaPacketUnsubscribeCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterMaPacketUnsubscribeCfmSizeof(void *msg);
+#define CsrWifiRouterMaPacketUnsubscribeCfmSerFree CsrWifiRouterPfree
+
+extern CsrUint8* CsrWifiRouterMaPacketCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterMaPacketCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterMaPacketCfmSizeof(void *msg);
+#define CsrWifiRouterMaPacketCfmSerFree CsrWifiRouterPfree
+
+extern CsrUint8* CsrWifiRouterMaPacketIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiRouterMaPacketIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiRouterMaPacketIndSizeof(void *msg);
+extern void CsrWifiRouterMaPacketIndSerFree(void *msg);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* CSR_WIFI_ROUTER_SERIALIZE_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_router_task.h b/drivers/staging/csr/csr_wifi_router_task.h
new file mode 100644
index 0000000..5bc460e
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_task.h
@@ -0,0 +1,34 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_ROUTER_TASK_H__
+#define CSR_WIFI_ROUTER_TASK_H__
+
+#include "csr_types.h"
+#include "csr_sched.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CSR_WIFI_ROUTER_LOG_ID 0x1201FFFF
+extern CsrSchedQid CSR_WIFI_ROUTER_IFACEQUEUE;
+void CsrWifiRouterInit(void **gash);
+void CsrWifiRouterDeinit(void **gash);
+void CsrWifiRouterHandler(void **gash);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_ROUTER_TASK_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_router_transport.c b/drivers/staging/csr/csr_wifi_router_transport.c
new file mode 100644
index 0000000..ec7e01d
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_router_transport.c
@@ -0,0 +1,210 @@
+/** @file router_transport.c
+ *
+ *
+ * Copyright (C) Cambridge Silicon Radio Ltd 2006-2010. All rights reserved.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ ****************************************************************************/
+
+#include "unifi_priv.h"
+
+#include "csr_types.h"
+#include "csr_sched.h"
+#include "csr_msgconv.h"
+
+#include "sme_userspace.h"
+
+#include "csr_wifi_hostio_prim.h"
+#include "csr_wifi_router_lib.h"
+#include "csr_wifi_router_sef.h"
+#include "csr_wifi_router_converter_init.h"
+#include "csr_wifi_router_ctrl_lib.h"
+#include "csr_wifi_router_ctrl_sef.h"
+#include "csr_wifi_router_ctrl_converter_init.h"
+#include "csr_wifi_sme_prim.h"
+#include "csr_wifi_sme_sef.h"
+#include "csr_wifi_sme_converter_init.h"
+#ifdef CSR_SUPPORT_WEXT
+#ifdef CSR_SUPPORT_WEXT_AP
+#include "csr_wifi_nme_ap_prim.h"
+#include "csr_wifi_nme_ap_sef.h"
+#include "csr_wifi_nme_ap_converter_init.h"
+#endif
+#endif
+
+static unifi_priv_t *drvpriv = NULL;
+void CsrWifiRouterTransportInit(unifi_priv_t *priv)
+{
+    unifi_trace(priv, UDBG1, "CsrWifiRouterTransportInit: \n");
+
+    drvpriv = priv;
+    (void)CsrMsgConvInit();
+    CsrWifiRouterConverterInit();
+    CsrWifiRouterCtrlConverterInit();
+    CsrWifiSmeConverterInit();
+#ifdef CSR_SUPPORT_WEXT
+#ifdef CSR_SUPPORT_WEXT_AP
+    CsrWifiNmeApConverterInit();
+#endif
+#endif
+}
+
+void CsrWifiRouterTransportDeinit(unifi_priv_t *priv)
+{
+    unifi_trace(priv, UDBG1, "CsrWifiRouterTransportDeinit: \n");
+    if (priv == drvpriv)
+    {
+        CsrMsgConvDeinit();
+        drvpriv = NULL;
+    }
+}
+
+void CsrWifiRouterTransportRecv(unifi_priv_t *priv, CsrUint8* buffer, CsrSize bufferLength)
+{
+    CsrMsgConvMsgEntry* msgEntry;
+    CsrUint16 primType;
+    CsrSchedQid src;
+    CsrSchedQid dest;
+    CsrUint16 msgType;
+    CsrSize offset = 0;
+    CsrWifiFsmEvent* msg;
+
+    /* Decode the prim and message type */
+    CsrUint16Des(&primType, buffer, &offset);
+    CsrUint16Des(&src, buffer, &offset);
+    CsrUint16Des(&dest, buffer, &offset);
+    CsrUint16Des(&msgType, buffer, &offset);
+    offset -= 2; /* Adjust as the Deserialise Function will read this as well */
+
+    unifi_trace(priv, UDBG4, "CsrWifiRouterTransportRecv: primType=0x%.4X, msgType=0x%.4X, bufferLength=%d\n",
+                primType, msgType, bufferLength);
+
+    /* Special handling for HOSTIO messages.... */
+    if (primType == CSR_WIFI_HOSTIO_PRIM)
+    {
+        CsrWifiRouterCtrlHipReq req = {{CSR_WIFI_ROUTER_CTRL_HIP_REQ, CSR_WIFI_ROUTER_CTRL_PRIM, dest, src, NULL}, 0, NULL, 0, NULL, 0, NULL};
+
+        req.mlmeCommandLength = bufferLength;
+        req.mlmeCommand = buffer;
+
+        offset += 8;/* Skip the id, src, dest and slot number */
+        CsrUint16Des(&req.dataRef1Length, buffer, &offset);
+        offset += 2; /* Skip the slot number */
+        CsrUint16Des(&req.dataRef2Length, buffer, &offset);
+
+        if (req.dataRef1Length)
+        {
+            CsrUint16 dr1Offset = (bufferLength - req.dataRef2Length) - req.dataRef1Length;
+            req.dataRef1 = &buffer[dr1Offset];
+        }
+
+        if (req.dataRef2Length)
+        {
+            CsrUint16 dr2Offset = bufferLength - req.dataRef2Length;
+            req.dataRef2 = &buffer[dr2Offset];
+        }
+
+        /* Copy the hip data but strip off the prim type */
+        req.mlmeCommandLength -= (req.dataRef1Length + req.dataRef2Length + 6);
+        req.mlmeCommand = &buffer[6];
+
+        CsrWifiRouterCtrlHipReqHandler(priv, &req.common);
+        return;
+    }
+
+    msgEntry = CsrMsgConvFindEntry(primType, msgType);
+    if (!msgEntry)
+    {
+        unifi_error(priv, "CsrWifiRouterTransportDeserialiseAndSend can not process the message. primType=0x%.4X, msgType=0x%.4X\n",
+                    primType, msgType);
+        dump(buffer, bufferLength);
+        return;
+    }
+
+    msg = (CsrWifiFsmEvent*)(msgEntry->deserFunc)(&buffer[offset], bufferLength - offset);
+
+    msg->primtype = primType;
+    msg->type = msgType;
+    msg->source = src;
+    msg->destination = dest;
+
+    switch(primType)
+    {
+    case CSR_WIFI_ROUTER_CTRL_PRIM:
+        CsrWifiRouterCtrlDownstreamStateHandlers[msg->type - CSR_WIFI_ROUTER_CTRL_PRIM_DOWNSTREAM_LOWEST](priv, msg);
+        CsrWifiRouterCtrlFreeDownstreamMessageContents(CSR_WIFI_ROUTER_CTRL_PRIM, msg);
+        break;
+    case CSR_WIFI_ROUTER_PRIM:
+        CsrWifiRouterDownstreamStateHandlers[msg->type - CSR_WIFI_ROUTER_PRIM_DOWNSTREAM_LOWEST](priv, msg);
+        CsrWifiRouterFreeDownstreamMessageContents(CSR_WIFI_ROUTER_PRIM, msg);
+        break;
+        case CSR_WIFI_SME_PRIM:
+            CsrWifiSmeUpstreamStateHandlers[msg->type - CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST](priv, msg);
+            CsrWifiSmeFreeUpstreamMessageContents(CSR_WIFI_SME_PRIM, msg);
+            break;
+#ifdef CSR_SUPPORT_WEXT
+#ifdef CSR_SUPPORT_WEXT_AP
+        case CSR_WIFI_NME_AP_PRIM:
+            CsrWifiNmeApUpstreamStateHandlers(priv, msg);
+            CsrWifiNmeApFreeUpstreamMessageContents(CSR_WIFI_NME_AP_PRIM, msg);
+            break;
+#endif
+#endif
+        default:
+            unifi_error(priv, "CsrWifiRouterTransportDeserialiseAndSend unhandled prim type 0x%.4X\n", primType);
+            break;
+    }
+    CsrPmemFree(msg);
+}
+
+static void CsrWifiRouterTransportSerialiseAndSend(CsrUint16 primType, void* msg)
+{
+    CsrWifiFsmEvent* evt = (CsrWifiFsmEvent*)msg;
+    CsrMsgConvMsgEntry* msgEntry;
+    CsrSize msgSize;
+    CsrSize encodeBufferLen = 0;
+    CsrSize offset = 0;
+    CsrUint8* encodeBuffer;
+
+    unifi_trace(drvpriv, UDBG4, "CsrWifiRouterTransportSerialiseAndSend: primType=0x%.4X, msgType=0x%.4X\n",
+                primType, evt->type);
+
+    msgEntry = CsrMsgConvFindEntry(primType, evt->type);
+    if (!msgEntry)
+    {
+        unifi_error(drvpriv, "CsrWifiRouterTransportSerialiseAndSend can not process the message. primType=0x%.4X, msgType=0x%.4X\n",
+                    primType, evt->type);
+        return;
+    }
+
+    msgSize = 6 + (msgEntry->sizeofFunc)((void*)msg);
+
+    encodeBuffer = CsrPmemAlloc(msgSize);
+
+    /* Encode PrimType */
+    CsrUint16Ser(encodeBuffer, &encodeBufferLen, primType);
+    CsrUint16Ser(encodeBuffer, &encodeBufferLen, evt->source);
+    CsrUint16Ser(encodeBuffer, &encodeBufferLen, evt->destination);
+
+    (void)(msgEntry->serFunc)(&encodeBuffer[encodeBufferLen], &offset, msg);
+    encodeBufferLen += offset;
+
+    uf_sme_queue_message(drvpriv, encodeBuffer, encodeBufferLen);
+
+    /* Do not use msgEntry->freeFunc because the memory is owned by the driver */
+    CsrPmemFree(msg);
+}
+
+#if defined(CSR_LOG_ENABLE) && defined(CSR_LOG_INCLUDE_FILE_NAME_AND_LINE_NUMBER)
+void CsrSchedMessagePutStringLog(CsrSchedQid q, CsrUint16 mi, void *mv, CsrUint32 line, CsrCharString *file)
+#else
+void CsrSchedMessagePut(CsrSchedQid q, CsrUint16 mi, void *mv)
+#endif
+{
+    CsrWifiFsmEvent* evt = (CsrWifiFsmEvent*)mv;
+    evt->destination = q;
+    CsrWifiRouterTransportSerialiseAndSend(mi, mv);
+}
+
diff --git a/drivers/staging/csr/csr_wifi_serialize_primitive_types.c b/drivers/staging/csr/csr_wifi_serialize_primitive_types.c
new file mode 100644
index 0000000..155bf65
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_serialize_primitive_types.c
@@ -0,0 +1,257 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#include <linux/module.h>
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_util.h"
+#include "csr_msgconv.h"
+#include "csr_wifi_msgconv.h"
+#include "csr_wifi_lib.h"
+
+void CsrUint24Des(CsrUint32 *v, CsrUint8 *buffer, CsrSize *offset)
+{
+    CsrUint32 val;
+
+    val = ((buffer[(*offset) + 2] << 16) |
+           (buffer[(*offset) + 1] << 8) |
+           (buffer[(*offset)]));
+
+    *offset += 3;
+    *v = val;
+}
+
+
+/* Big endian :e.g WSC, TCLAS */
+void CsrUint16DesBigEndian(CsrUint16 *v, CsrUint8 *buffer, CsrSize *offset)
+{
+    CsrUint16 val;
+
+    val = (buffer[(*offset)] << 8) | (buffer[(*offset) + 1]);
+    *offset += 2;
+
+    *v = val;
+}
+
+
+void CsrUint24DesBigEndian(CsrUint32 *v, CsrUint8 *buffer, CsrSize *offset)
+{
+    CsrUint32 val;
+
+    val = ((buffer[(*offset)] << 16) |
+           (buffer[(*offset) + 1] << 8) |
+           (buffer[(*offset) + 2]));
+
+    *offset += 3;
+    *v = val;
+}
+
+
+void CsrUint32DesBigEndian(CsrUint32 *v, CsrUint8 *buffer, CsrSize *offset)
+{
+    CsrUint32 val;
+
+    val = ((buffer[(*offset)] << 24) |
+           (buffer[(*offset) + 1] << 16) |
+           (buffer[(*offset) + 2] << 8) |
+           (buffer[(*offset) + 3]));
+
+    *offset += 4;
+    *v = val;
+}
+
+
+void CsrUint24Ser(CsrUint8 *ptr, CsrSize *len, CsrUint32 v)
+{
+    ptr[(*len) + 2] = (CsrUint8)((v & 0x00ff0000) >> 16);
+    ptr[(*len) + 1] = (CsrUint8)((v & 0x0000ff00) >> 8);
+    ptr[(*len)]     = (CsrUint8)((v & 0x000000ff));
+
+    *len += 3;
+}
+
+
+/* Big endian :e.g WSC, TCLAS */
+void CsrUint16SerBigEndian(CsrUint8 *ptr, CsrSize *len, CsrUint16 v)
+{
+    ptr[(*len)] = (CsrUint8)((v & 0xff00) >> 8);
+    ptr[(*len) + 1] = (CsrUint8)((v & 0x00ff));
+
+    *len += 2;
+}
+
+
+void CsrUint32SerBigEndian(CsrUint8 *ptr, CsrSize *len, CsrUint32 v)
+{
+    ptr[(*len)] = (CsrUint8)((v & 0xff000000) >> 24);
+    ptr[(*len) + 1] = (CsrUint8)((v & 0x00ff0000) >> 16);
+    ptr[(*len) + 2] = (CsrUint8)((v & 0x0000ff00) >> 8);
+    ptr[(*len) + 3] = (CsrUint8)((v & 0x000000ff));
+
+    *len += 4;
+}
+
+
+void CsrUint24SerBigEndian(CsrUint8 *ptr, CsrSize *len, CsrUint32 v)
+{
+    ptr[(*len)] = (CsrUint8)((v & 0x00ff0000) >> 16);
+    ptr[(*len) + 1] = (CsrUint8)((v & 0x0000ff00) >> 8);
+    ptr[(*len) + 2] = (CsrUint8)((v & 0x000000ff));
+
+    *len += 3;
+}
+
+
+CsrSize CsrWifiEventSizeof(void *msg)
+{
+    return 2;
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventSizeof);
+
+CsrUint8* CsrWifiEventSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiFsmEvent *primitive = (CsrWifiFsmEvent *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->type);
+    return(ptr);
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventSer);
+
+void* CsrWifiEventDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiFsmEvent *primitive = (CsrWifiFsmEvent *) CsrPmemAlloc(sizeof(CsrWifiFsmEvent));
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->type, buffer, &offset);
+
+    return primitive;
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventDes);
+
+CsrSize CsrWifiEventCsrUint8Sizeof(void *msg)
+{
+    return 3;
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint8Sizeof);
+
+CsrUint8* CsrWifiEventCsrUint8Ser(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiEventCsrUint8 *primitive = (CsrWifiEventCsrUint8 *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint8Ser(ptr, len, primitive->value);
+    return(ptr);
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint8Ser);
+
+
+void* CsrWifiEventCsrUint8Des(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiEventCsrUint8 *primitive = (CsrWifiEventCsrUint8 *) CsrPmemAlloc(sizeof(CsrWifiEventCsrUint8));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint8Des(&primitive->value, buffer, &offset);
+
+    return primitive;
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint8Des);
+
+
+CsrSize CsrWifiEventCsrUint16Sizeof(void *msg)
+{
+    return 4;
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint16Sizeof);
+
+
+CsrUint8* CsrWifiEventCsrUint16Ser(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiEventCsrUint16 *primitive = (CsrWifiEventCsrUint16 *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, primitive->value);
+    return(ptr);
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint16Ser);
+
+void* CsrWifiEventCsrUint16Des(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiEventCsrUint16 *primitive = (CsrWifiEventCsrUint16 *) CsrPmemAlloc(sizeof(CsrWifiEventCsrUint16));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des(&primitive->value, buffer, &offset);
+
+    return primitive;
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint16Des);
+
+
+CsrSize CsrWifiEventCsrUint32Sizeof(void *msg)
+{
+    return 6;
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint32Sizeof);
+
+CsrUint8* CsrWifiEventCsrUint32Ser(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiEventCsrUint32 *primitive = (CsrWifiEventCsrUint32 *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint32Ser(ptr, len, primitive->value);
+    return(ptr);
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint32Ser);
+
+
+void* CsrWifiEventCsrUint32Des(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiEventCsrUint32 *primitive = (CsrWifiEventCsrUint32 *) CsrPmemAlloc(sizeof(CsrWifiEventCsrUint32));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint32Des(&primitive->value, buffer, &offset);
+
+    return primitive;
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint32Des);
+
+CsrSize CsrWifiEventCsrUint16CsrUint8Sizeof(void *msg)
+{
+    return 5;
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint16CsrUint8Sizeof);
+
+CsrUint8* CsrWifiEventCsrUint16CsrUint8Ser(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiEventCsrUint16CsrUint8 *primitive = (CsrWifiEventCsrUint16CsrUint8 *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, primitive->value16);
+    CsrUint8Ser(ptr, len, primitive->value8);
+    return(ptr);
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint16CsrUint8Ser);
+
+
+void* CsrWifiEventCsrUint16CsrUint8Des(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiEventCsrUint16CsrUint8 *primitive = (CsrWifiEventCsrUint16CsrUint8 *) CsrPmemAlloc(sizeof(CsrWifiEventCsrUint16CsrUint8));
+
+    CsrSize offset = 0;
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des(&primitive->value16, buffer, &offset);
+    CsrUint8Des(&primitive->value8, buffer, &offset);
+
+    return primitive;
+}
+EXPORT_SYMBOL_GPL(CsrWifiEventCsrUint16CsrUint8Des);
+
+
diff --git a/drivers/staging/csr/csr_wifi_sme_ap_lib.h b/drivers/staging/csr/csr_wifi_sme_ap_lib.h
new file mode 100644
index 0000000..bb9e79f
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_ap_lib.h
@@ -0,0 +1,785 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_SME_AP_LIB_H__
+#define CSR_WIFI_SME_AP_LIB_H__
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_sched.h"
+#include "csr_util.h"
+#include "csr_msg_transport.h"
+
+#include "csr_wifi_lib.h"
+
+#include "csr_wifi_sme_ap_prim.h"
+#include "csr_wifi_sme_task.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_AP_ENABLE
+#error CSR_WIFI_AP_ENABLE MUST be defined inorder to use csr_wifi_sme_ap_lib.h
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiSmeApFreeUpstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_SME_AP upstream message. Does not
+ *      free the message itself, and can only be used for upstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_SME_AP upstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiSmeApFreeUpstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiSmeApFreeDownstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_SME_AP downstream message. Does not
+ *      free the message itself, and can only be used for downstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_SME_AP downstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiSmeApFreeDownstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ * Enum to string functions
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiSmeApAccessTypeToString(CsrWifiSmeApAccessType value);
+const CsrCharString* CsrWifiSmeApAuthSupportToString(CsrWifiSmeApAuthSupport value);
+const CsrCharString* CsrWifiSmeApAuthTypeToString(CsrWifiSmeApAuthType value);
+const CsrCharString* CsrWifiSmeApDirectionToString(CsrWifiSmeApDirection value);
+const CsrCharString* CsrWifiSmeApPhySupportToString(CsrWifiSmeApPhySupport value);
+const CsrCharString* CsrWifiSmeApTypeToString(CsrWifiSmeApType value);
+
+
+/*----------------------------------------------------------------------------*
+ * CsrPrim Type toString function.
+ * Converts a message type to the String name of the Message
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiSmeApPrimTypeToString(CsrPrim msgType);
+
+/*----------------------------------------------------------------------------*
+ * Lookup arrays for PrimType name Strings
+ *----------------------------------------------------------------------------*/
+extern const CsrCharString *CsrWifiSmeApUpstreamPrimNames[CSR_WIFI_SME_AP_PRIM_UPSTREAM_COUNT];
+extern const CsrCharString *CsrWifiSmeApDownstreamPrimNames[CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_COUNT];
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApActiveBaGetReqSend
+
+  DESCRIPTION
+    This primitive used to retrieve information related to the active block
+    ack sessions
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+
+*******************************************************************************/
+#define CsrWifiSmeApActiveBaGetReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeApActiveBaGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeApActiveBaGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_ACTIVE_BA_GET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeApActiveBaGetReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeApActiveBaGetReq *msg__; \
+        CsrWifiSmeApActiveBaGetReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApActiveBaGetReqSend(src__, interfaceTag__) \
+    CsrWifiSmeApActiveBaGetReqSendTo(CSR_WIFI_SME_IFACEQUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApActiveBaGetCfmSend
+
+  DESCRIPTION
+    This primitive carries the information related to the active ba sessions
+
+  PARAMETERS
+    queue            - Destination Task Queue
+    interfaceTag     -
+    status           - Reports the result of the request
+    activeBaCount    - Number of active block ack session
+    activeBaSessions - Points to a buffer containing an array of
+                       CsrWifiSmeApBaSession structures.
+
+*******************************************************************************/
+#define CsrWifiSmeApActiveBaGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, activeBaCount__, activeBaSessions__) \
+    msg__ = (CsrWifiSmeApActiveBaGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeApActiveBaGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_ACTIVE_BA_GET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->activeBaCount = (activeBaCount__); \
+    msg__->activeBaSessions = (activeBaSessions__);
+
+#define CsrWifiSmeApActiveBaGetCfmSendTo(dst__, src__, interfaceTag__, status__, activeBaCount__, activeBaSessions__) \
+    { \
+        CsrWifiSmeApActiveBaGetCfm *msg__; \
+        CsrWifiSmeApActiveBaGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, activeBaCount__, activeBaSessions__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApActiveBaGetCfmSend(dst__, interfaceTag__, status__, activeBaCount__, activeBaSessions__) \
+    CsrWifiSmeApActiveBaGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, activeBaCount__, activeBaSessions__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBaDeleteReqSend
+
+  DESCRIPTION
+    This primitive is used to delete an active block ack session
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+    reason       -
+    baSession    - BA session to be deleted
+
+*******************************************************************************/
+#define CsrWifiSmeApBaDeleteReqCreate(msg__, dst__, src__, interfaceTag__, reason__, baSession__) \
+    msg__ = (CsrWifiSmeApBaDeleteReq *) CsrPmemAlloc(sizeof(CsrWifiSmeApBaDeleteReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_BA_DELETE_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->reason = (reason__); \
+    msg__->baSession = (baSession__);
+
+#define CsrWifiSmeApBaDeleteReqSendTo(dst__, src__, interfaceTag__, reason__, baSession__) \
+    { \
+        CsrWifiSmeApBaDeleteReq *msg__; \
+        CsrWifiSmeApBaDeleteReqCreate(msg__, dst__, src__, interfaceTag__, reason__, baSession__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApBaDeleteReqSend(src__, interfaceTag__, reason__, baSession__) \
+    CsrWifiSmeApBaDeleteReqSendTo(CSR_WIFI_SME_IFACEQUEUE, src__, interfaceTag__, reason__, baSession__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBaDeleteCfmSend
+
+  DESCRIPTION
+    This primitive confirms the BA is deleted
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag -
+    status       - Reports the result of the request
+    baSession    - deleted BA session
+
+*******************************************************************************/
+#define CsrWifiSmeApBaDeleteCfmCreate(msg__, dst__, src__, interfaceTag__, status__, baSession__) \
+    msg__ = (CsrWifiSmeApBaDeleteCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeApBaDeleteCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_BA_DELETE_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->baSession = (baSession__);
+
+#define CsrWifiSmeApBaDeleteCfmSendTo(dst__, src__, interfaceTag__, status__, baSession__) \
+    { \
+        CsrWifiSmeApBaDeleteCfm *msg__; \
+        CsrWifiSmeApBaDeleteCfmCreate(msg__, dst__, src__, interfaceTag__, status__, baSession__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApBaDeleteCfmSend(dst__, interfaceTag__, status__, baSession__) \
+    CsrWifiSmeApBaDeleteCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, baSession__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBeaconingStartReqSend
+
+  DESCRIPTION
+    This primitive requests the SME to start AP or GO functionality
+
+  PARAMETERS
+    queue           - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag    -
+    initialPresence - Set to 0, if Not in a group fomration phase, set to 1 ,
+                      during group formation phase
+    apType          - apType : Legacy AP or P2PGO
+    cloakSsid       - cloakSsid flag.
+    ssid            - ssid.
+    ifIndex         - Radio Interface
+    channel         - channel.
+    maxConnections  - Maximum Stations + P2PClients allowed
+    apCredentials   - AP security credeitals used to advertise in beacon /probe
+                      response
+    smeApConfig     - AP configuration
+    p2pGoParam      - P2P specific GO parameters. Ignored if it is a leagacy AP
+
+*******************************************************************************/
+#define CsrWifiSmeApBeaconingStartReqCreate(msg__, dst__, src__, interfaceTag__, initialPresence__, apType__, cloakSsid__, ssid__, ifIndex__, channel__, maxConnections__, apCredentials__, smeApConfig__, p2pGoParam__) \
+    msg__ = (CsrWifiSmeApBeaconingStartReq *) CsrPmemAlloc(sizeof(CsrWifiSmeApBeaconingStartReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_BEACONING_START_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->initialPresence = (initialPresence__); \
+    msg__->apType = (apType__); \
+    msg__->cloakSsid = (cloakSsid__); \
+    msg__->ssid = (ssid__); \
+    msg__->ifIndex = (ifIndex__); \
+    msg__->channel = (channel__); \
+    msg__->maxConnections = (maxConnections__); \
+    msg__->apCredentials = (apCredentials__); \
+    msg__->smeApConfig = (smeApConfig__); \
+    msg__->p2pGoParam = (p2pGoParam__);
+
+#define CsrWifiSmeApBeaconingStartReqSendTo(dst__, src__, interfaceTag__, initialPresence__, apType__, cloakSsid__, ssid__, ifIndex__, channel__, maxConnections__, apCredentials__, smeApConfig__, p2pGoParam__) \
+    { \
+        CsrWifiSmeApBeaconingStartReq *msg__; \
+        CsrWifiSmeApBeaconingStartReqCreate(msg__, dst__, src__, interfaceTag__, initialPresence__, apType__, cloakSsid__, ssid__, ifIndex__, channel__, maxConnections__, apCredentials__, smeApConfig__, p2pGoParam__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApBeaconingStartReqSend(src__, interfaceTag__, initialPresence__, apType__, cloakSsid__, ssid__, ifIndex__, channel__, maxConnections__, apCredentials__, smeApConfig__, p2pGoParam__) \
+    CsrWifiSmeApBeaconingStartReqSendTo(CSR_WIFI_SME_IFACEQUEUE, src__, interfaceTag__, initialPresence__, apType__, cloakSsid__, ssid__, ifIndex__, channel__, maxConnections__, apCredentials__, smeApConfig__, p2pGoParam__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBeaconingStartCfmSend
+
+  DESCRIPTION
+    This primitive confirms the completion of the request along with the
+    status
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag -
+    status       -
+    secIeLength  -
+    secIe        -
+
+*******************************************************************************/
+#define CsrWifiSmeApBeaconingStartCfmCreate(msg__, dst__, src__, interfaceTag__, status__, secIeLength__, secIe__) \
+    msg__ = (CsrWifiSmeApBeaconingStartCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeApBeaconingStartCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_BEACONING_START_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->secIeLength = (secIeLength__); \
+    msg__->secIe = (secIe__);
+
+#define CsrWifiSmeApBeaconingStartCfmSendTo(dst__, src__, interfaceTag__, status__, secIeLength__, secIe__) \
+    { \
+        CsrWifiSmeApBeaconingStartCfm *msg__; \
+        CsrWifiSmeApBeaconingStartCfmCreate(msg__, dst__, src__, interfaceTag__, status__, secIeLength__, secIe__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApBeaconingStartCfmSend(dst__, interfaceTag__, status__, secIeLength__, secIe__) \
+    CsrWifiSmeApBeaconingStartCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, secIeLength__, secIe__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBeaconingStopReqSend
+
+  DESCRIPTION
+    This primitive requests the SME to STOP AP or P2PGO operation
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+
+*******************************************************************************/
+#define CsrWifiSmeApBeaconingStopReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeApBeaconingStopReq *) CsrPmemAlloc(sizeof(CsrWifiSmeApBeaconingStopReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_BEACONING_STOP_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeApBeaconingStopReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeApBeaconingStopReq *msg__; \
+        CsrWifiSmeApBeaconingStopReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApBeaconingStopReqSend(src__, interfaceTag__) \
+    CsrWifiSmeApBeaconingStopReqSendTo(CSR_WIFI_SME_IFACEQUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBeaconingStopCfmSend
+
+  DESCRIPTION
+    This primitive confirms AP or P2PGO operation is terminated
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiSmeApBeaconingStopCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmeApBeaconingStopCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeApBeaconingStopCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_BEACONING_STOP_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeApBeaconingStopCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmeApBeaconingStopCfm *msg__; \
+        CsrWifiSmeApBeaconingStopCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApBeaconingStopCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmeApBeaconingStopCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApErrorIndSend
+
+  DESCRIPTION
+    This primitve is sent by SME to indicate some error in AP operationi
+    after AP operations were started successfully and continuing the AP
+    operation may lead to undesired behaviour. It is the responsibility of
+    the upper layers to stop AP operation if needed
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Range 0-1
+    apType       -
+    status       - Contains the error status
+
+*******************************************************************************/
+#define CsrWifiSmeApErrorIndCreate(msg__, dst__, src__, interfaceTag__, apType__, status__) \
+    msg__ = (CsrWifiSmeApErrorInd *) CsrPmemAlloc(sizeof(CsrWifiSmeApErrorInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_ERROR_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->apType = (apType__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeApErrorIndSendTo(dst__, src__, interfaceTag__, apType__, status__) \
+    { \
+        CsrWifiSmeApErrorInd *msg__; \
+        CsrWifiSmeApErrorIndCreate(msg__, dst__, src__, interfaceTag__, apType__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApErrorIndSend(dst__, interfaceTag__, apType__, status__) \
+    CsrWifiSmeApErrorIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, apType__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApStaConnectStartIndSend
+
+  DESCRIPTION
+    This primitive indicates that a stations request to join the group/BSS is
+    accepted
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    interfaceTag   -
+    peerMacAddress -
+
+*******************************************************************************/
+#define CsrWifiSmeApStaConnectStartIndCreate(msg__, dst__, src__, interfaceTag__, peerMacAddress__) \
+    msg__ = (CsrWifiSmeApStaConnectStartInd *) CsrPmemAlloc(sizeof(CsrWifiSmeApStaConnectStartInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_STA_CONNECT_START_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->peerMacAddress = (peerMacAddress__);
+
+#define CsrWifiSmeApStaConnectStartIndSendTo(dst__, src__, interfaceTag__, peerMacAddress__) \
+    { \
+        CsrWifiSmeApStaConnectStartInd *msg__; \
+        CsrWifiSmeApStaConnectStartIndCreate(msg__, dst__, src__, interfaceTag__, peerMacAddress__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApStaConnectStartIndSend(dst__, interfaceTag__, peerMacAddress__) \
+    CsrWifiSmeApStaConnectStartIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, peerMacAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApStaDisconnectReqSend
+
+  DESCRIPTION
+    This primitive tells SME to deauth ot disassociate a particular station
+    within BSS
+
+  PARAMETERS
+    queue          - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag   -
+    deauthReason   -
+    disassocReason -
+    peerMacaddress -
+    keepBlocking   - If TRUE, the station is blocked. If FALSE and the station
+                     is connected, disconnect the station. If FALSE and the
+                     station is not connected, no action is taken.
+
+*******************************************************************************/
+#define CsrWifiSmeApStaDisconnectReqCreate(msg__, dst__, src__, interfaceTag__, deauthReason__, disassocReason__, peerMacaddress__, keepBlocking__) \
+    msg__ = (CsrWifiSmeApStaDisconnectReq *) CsrPmemAlloc(sizeof(CsrWifiSmeApStaDisconnectReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_STA_DISCONNECT_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->deauthReason = (deauthReason__); \
+    msg__->disassocReason = (disassocReason__); \
+    msg__->peerMacaddress = (peerMacaddress__); \
+    msg__->keepBlocking = (keepBlocking__);
+
+#define CsrWifiSmeApStaDisconnectReqSendTo(dst__, src__, interfaceTag__, deauthReason__, disassocReason__, peerMacaddress__, keepBlocking__) \
+    { \
+        CsrWifiSmeApStaDisconnectReq *msg__; \
+        CsrWifiSmeApStaDisconnectReqCreate(msg__, dst__, src__, interfaceTag__, deauthReason__, disassocReason__, peerMacaddress__, keepBlocking__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApStaDisconnectReqSend(src__, interfaceTag__, deauthReason__, disassocReason__, peerMacaddress__, keepBlocking__) \
+    CsrWifiSmeApStaDisconnectReqSendTo(CSR_WIFI_SME_IFACEQUEUE, src__, interfaceTag__, deauthReason__, disassocReason__, peerMacaddress__, keepBlocking__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApStaDisconnectCfmSend
+
+  DESCRIPTION
+    This primitive confirms the station is disconnected
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    interfaceTag   -
+    status         -
+    peerMacaddress -
+
+*******************************************************************************/
+#define CsrWifiSmeApStaDisconnectCfmCreate(msg__, dst__, src__, interfaceTag__, status__, peerMacaddress__) \
+    msg__ = (CsrWifiSmeApStaDisconnectCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeApStaDisconnectCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_STA_DISCONNECT_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->peerMacaddress = (peerMacaddress__);
+
+#define CsrWifiSmeApStaDisconnectCfmSendTo(dst__, src__, interfaceTag__, status__, peerMacaddress__) \
+    { \
+        CsrWifiSmeApStaDisconnectCfm *msg__; \
+        CsrWifiSmeApStaDisconnectCfmCreate(msg__, dst__, src__, interfaceTag__, status__, peerMacaddress__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApStaDisconnectCfmSend(dst__, interfaceTag__, status__, peerMacaddress__) \
+    CsrWifiSmeApStaDisconnectCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, peerMacaddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApStaNotifyIndSend
+
+  DESCRIPTION
+    This primitive indicates that a station has joined or a previously joined
+    station has left the BSS/group
+
+  PARAMETERS
+    queue             - Destination Task Queue
+    interfaceTag      -
+    mediaStatus       -
+    peerMacAddress    -
+    peerDeviceAddress -
+    disassocReason    -
+    deauthReason      -
+    WpsRegistration   -
+    secIeLength       -
+    secIe             -
+    groupKeyId        -
+    seqNumber         -
+
+*******************************************************************************/
+#define CsrWifiSmeApStaNotifyIndCreate(msg__, dst__, src__, interfaceTag__, mediaStatus__, peerMacAddress__, peerDeviceAddress__, disassocReason__, deauthReason__, WpsRegistration__, secIeLength__, secIe__, groupKeyId__, seqNumber__) \
+    msg__ = (CsrWifiSmeApStaNotifyInd *) CsrPmemAlloc(sizeof(CsrWifiSmeApStaNotifyInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_STA_NOTIFY_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->mediaStatus = (mediaStatus__); \
+    msg__->peerMacAddress = (peerMacAddress__); \
+    msg__->peerDeviceAddress = (peerDeviceAddress__); \
+    msg__->disassocReason = (disassocReason__); \
+    msg__->deauthReason = (deauthReason__); \
+    msg__->WpsRegistration = (WpsRegistration__); \
+    msg__->secIeLength = (secIeLength__); \
+    msg__->secIe = (secIe__); \
+    msg__->groupKeyId = (groupKeyId__); \
+    CsrMemCpy(msg__->seqNumber, (seqNumber__), sizeof(CsrUint16) * 8);
+
+#define CsrWifiSmeApStaNotifyIndSendTo(dst__, src__, interfaceTag__, mediaStatus__, peerMacAddress__, peerDeviceAddress__, disassocReason__, deauthReason__, WpsRegistration__, secIeLength__, secIe__, groupKeyId__, seqNumber__) \
+    { \
+        CsrWifiSmeApStaNotifyInd *msg__; \
+        CsrWifiSmeApStaNotifyIndCreate(msg__, dst__, src__, interfaceTag__, mediaStatus__, peerMacAddress__, peerDeviceAddress__, disassocReason__, deauthReason__, WpsRegistration__, secIeLength__, secIe__, groupKeyId__, seqNumber__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApStaNotifyIndSend(dst__, interfaceTag__, mediaStatus__, peerMacAddress__, peerDeviceAddress__, disassocReason__, deauthReason__, WpsRegistration__, secIeLength__, secIe__, groupKeyId__, seqNumber__) \
+    CsrWifiSmeApStaNotifyIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, mediaStatus__, peerMacAddress__, peerDeviceAddress__, disassocReason__, deauthReason__, WpsRegistration__, secIeLength__, secIe__, groupKeyId__, seqNumber__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWmmParamUpdateReqSend
+
+  DESCRIPTION
+    Application uses this primitive to update the WMM parameters on the fly
+
+  PARAMETERS
+    queue         - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag  -
+    wmmApParams   - WMM parameters to be used for local firmware queue
+                    configuration
+    wmmApBcParams - WMM parameters to be advertised in beacon/probe response
+
+*******************************************************************************/
+#define CsrWifiSmeApWmmParamUpdateReqCreate(msg__, dst__, src__, interfaceTag__, wmmApParams__, wmmApBcParams__) \
+    msg__ = (CsrWifiSmeApWmmParamUpdateReq *) CsrPmemAlloc(sizeof(CsrWifiSmeApWmmParamUpdateReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_WMM_PARAM_UPDATE_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    CsrMemCpy(msg__->wmmApParams, (wmmApParams__), sizeof(CsrWifiSmeWmmAcParams) * 4); \
+    CsrMemCpy(msg__->wmmApBcParams, (wmmApBcParams__), sizeof(CsrWifiSmeWmmAcParams) * 4);
+
+#define CsrWifiSmeApWmmParamUpdateReqSendTo(dst__, src__, interfaceTag__, wmmApParams__, wmmApBcParams__) \
+    { \
+        CsrWifiSmeApWmmParamUpdateReq *msg__; \
+        CsrWifiSmeApWmmParamUpdateReqCreate(msg__, dst__, src__, interfaceTag__, wmmApParams__, wmmApBcParams__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApWmmParamUpdateReqSend(src__, interfaceTag__, wmmApParams__, wmmApBcParams__) \
+    CsrWifiSmeApWmmParamUpdateReqSendTo(CSR_WIFI_SME_IFACEQUEUE, src__, interfaceTag__, wmmApParams__, wmmApBcParams__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWmmParamUpdateCfmSend
+
+  DESCRIPTION
+    A confirm for CSR_WIFI_SME_AP_WMM_PARAM_UPDATE.request
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiSmeApWmmParamUpdateCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmeApWmmParamUpdateCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeApWmmParamUpdateCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_WMM_PARAM_UPDATE_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeApWmmParamUpdateCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmeApWmmParamUpdateCfm *msg__; \
+        CsrWifiSmeApWmmParamUpdateCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApWmmParamUpdateCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmeApWmmParamUpdateCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsConfigurationReqSend
+
+  DESCRIPTION
+    This primitive passes the WPS information for the device to SME. This may
+    be accepted only if no interface is active.
+
+  PARAMETERS
+    queue     - Message Source Task Queue (Cfm's will be sent to this Queue)
+    wpsConfig - WPS config.
+
+*******************************************************************************/
+#define CsrWifiSmeApWpsConfigurationReqCreate(msg__, dst__, src__, wpsConfig__) \
+    msg__ = (CsrWifiSmeApWpsConfigurationReq *) CsrPmemAlloc(sizeof(CsrWifiSmeApWpsConfigurationReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_WPS_CONFIGURATION_REQ, dst__, src__); \
+    msg__->wpsConfig = (wpsConfig__);
+
+#define CsrWifiSmeApWpsConfigurationReqSendTo(dst__, src__, wpsConfig__) \
+    { \
+        CsrWifiSmeApWpsConfigurationReq *msg__; \
+        CsrWifiSmeApWpsConfigurationReqCreate(msg__, dst__, src__, wpsConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApWpsConfigurationReqSend(src__, wpsConfig__) \
+    CsrWifiSmeApWpsConfigurationReqSendTo(CSR_WIFI_SME_IFACEQUEUE, src__, wpsConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsConfigurationCfmSend
+
+  DESCRIPTION
+    Confirm.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Status of the request.
+
+*******************************************************************************/
+#define CsrWifiSmeApWpsConfigurationCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeApWpsConfigurationCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeApWpsConfigurationCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_WPS_CONFIGURATION_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeApWpsConfigurationCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeApWpsConfigurationCfm *msg__; \
+        CsrWifiSmeApWpsConfigurationCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApWpsConfigurationCfmSend(dst__, status__) \
+    CsrWifiSmeApWpsConfigurationCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsRegistrationFinishedReqSend
+
+  DESCRIPTION
+    This primitive tells SME that WPS registration procedure has finished
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag -
+
+*******************************************************************************/
+#define CsrWifiSmeApWpsRegistrationFinishedReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeApWpsRegistrationFinishedReq *) CsrPmemAlloc(sizeof(CsrWifiSmeApWpsRegistrationFinishedReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_WPS_REGISTRATION_FINISHED_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeApWpsRegistrationFinishedReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeApWpsRegistrationFinishedReq *msg__; \
+        CsrWifiSmeApWpsRegistrationFinishedReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApWpsRegistrationFinishedReqSend(src__, interfaceTag__) \
+    CsrWifiSmeApWpsRegistrationFinishedReqSendTo(CSR_WIFI_SME_IFACEQUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsRegistrationFinishedCfmSend
+
+  DESCRIPTION
+    A confirm for UNIFI_MGT_AP_WPS_REGISTRATION_FINISHED.request
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiSmeApWpsRegistrationFinishedCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmeApWpsRegistrationFinishedCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeApWpsRegistrationFinishedCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_WPS_REGISTRATION_FINISHED_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeApWpsRegistrationFinishedCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmeApWpsRegistrationFinishedCfm *msg__; \
+        CsrWifiSmeApWpsRegistrationFinishedCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApWpsRegistrationFinishedCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmeApWpsRegistrationFinishedCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsRegistrationStartedReqSend
+
+  DESCRIPTION
+    This primitive tells SME that WPS registration procedure has started
+
+  PARAMETERS
+    queue                    - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag             -
+    SelectedDevicePasswordId -
+    SelectedconfigMethod     -
+
+*******************************************************************************/
+#define CsrWifiSmeApWpsRegistrationStartedReqCreate(msg__, dst__, src__, interfaceTag__, SelectedDevicePasswordId__, SelectedconfigMethod__) \
+    msg__ = (CsrWifiSmeApWpsRegistrationStartedReq *) CsrPmemAlloc(sizeof(CsrWifiSmeApWpsRegistrationStartedReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_WPS_REGISTRATION_STARTED_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->SelectedDevicePasswordId = (SelectedDevicePasswordId__); \
+    msg__->SelectedconfigMethod = (SelectedconfigMethod__);
+
+#define CsrWifiSmeApWpsRegistrationStartedReqSendTo(dst__, src__, interfaceTag__, SelectedDevicePasswordId__, SelectedconfigMethod__) \
+    { \
+        CsrWifiSmeApWpsRegistrationStartedReq *msg__; \
+        CsrWifiSmeApWpsRegistrationStartedReqCreate(msg__, dst__, src__, interfaceTag__, SelectedDevicePasswordId__, SelectedconfigMethod__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApWpsRegistrationStartedReqSend(src__, interfaceTag__, SelectedDevicePasswordId__, SelectedconfigMethod__) \
+    CsrWifiSmeApWpsRegistrationStartedReqSendTo(CSR_WIFI_SME_IFACEQUEUE, src__, interfaceTag__, SelectedDevicePasswordId__, SelectedconfigMethod__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsRegistrationStartedCfmSend
+
+  DESCRIPTION
+    A confirm for UNIFI_MGT_AP_WPS_REGISTRATION_STARTED.request
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+#define CsrWifiSmeApWpsRegistrationStartedCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmeApWpsRegistrationStartedCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeApWpsRegistrationStartedCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_AP_PRIM, CSR_WIFI_SME_AP_WPS_REGISTRATION_STARTED_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeApWpsRegistrationStartedCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmeApWpsRegistrationStartedCfm *msg__; \
+        CsrWifiSmeApWpsRegistrationStartedCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_AP_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeApWpsRegistrationStartedCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmeApWpsRegistrationStartedCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_SME_AP_LIB_H__ */
diff --git a/drivers/staging/csr/csr_wifi_sme_ap_prim.h b/drivers/staging/csr/csr_wifi_sme_ap_prim.h
new file mode 100644
index 0000000..4159439
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_ap_prim.h
@@ -0,0 +1,1039 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_SME_AP_PRIM_H__
+#define CSR_WIFI_SME_AP_PRIM_H__
+
+#include "csr_types.h"
+#include "csr_prim_defs.h"
+#include "csr_sched.h"
+#include "csr_wifi_common.h"
+#include "csr_result.h"
+#include "csr_wifi_fsm_event.h"
+#include "csr_wifi_sme_prim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CSR_WIFI_AP_ENABLE
+#error CSR_WIFI_AP_ENABLE MUST be defined inorder to use csr_wifi_sme_ap_prim.h
+#endif
+
+#define CSR_WIFI_SME_AP_PRIM                                            (0x0407)
+
+typedef CsrPrim CsrWifiSmeApPrim;
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApAccessType
+
+  DESCRIPTION
+    Allow or deny STAs based on MAC address
+
+ VALUES
+    CSR_WIFI_AP_ACCESS_TYPE_NONE  - None
+    CSR_WIFI_AP_ACCESS_TYPE_ALLOW - Allow only if MAC address is from the list
+    CSR_WIFI_AP_ACCESS_TYPE_DENY  - Disallow if MAC address is from the list
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeApAccessType;
+#define CSR_WIFI_AP_ACCESS_TYPE_NONE    ((CsrWifiSmeApAccessType) 0x00)
+#define CSR_WIFI_AP_ACCESS_TYPE_ALLOW   ((CsrWifiSmeApAccessType) 0x01)
+#define CSR_WIFI_AP_ACCESS_TYPE_DENY    ((CsrWifiSmeApAccessType) 0x02)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApAuthSupport
+
+  DESCRIPTION
+    Define bits for AP authentication support
+
+ VALUES
+    CSR_WIFI_SME_RSN_AUTH_WPAPSK  - RSN WPA-PSK Support
+    CSR_WIFI_SME_RSN_AUTH_WPA2PSK - RSN WPA2-PSK Support
+    CSR_WIFI_SME_AUTH_WAPIPSK     - WAPI-PSK Support
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeApAuthSupport;
+#define CSR_WIFI_SME_RSN_AUTH_WPAPSK    ((CsrWifiSmeApAuthSupport) 0x01)
+#define CSR_WIFI_SME_RSN_AUTH_WPA2PSK   ((CsrWifiSmeApAuthSupport) 0x02)
+#define CSR_WIFI_SME_AUTH_WAPIPSK       ((CsrWifiSmeApAuthSupport) 0x04)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApAuthType
+
+  DESCRIPTION
+    Definition of the SME AP Authentication Options
+
+ VALUES
+    CSR_WIFI_SME_AP_AUTH_TYPE_OPEN_SYSTEM
+                   - Open  authentication
+    CSR_WIFI_SME_AP_AUTH_TYPE_PERSONAL
+                   - Personal authentication using a passphrase or a pre-shared
+                     key.
+    CSR_WIFI_SME_AP_AUTH_TYPE_WEP
+                   - WEP authentication. This can be either open or shared key
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeApAuthType;
+#define CSR_WIFI_SME_AP_AUTH_TYPE_OPEN_SYSTEM   ((CsrWifiSmeApAuthType) 0x00)
+#define CSR_WIFI_SME_AP_AUTH_TYPE_PERSONAL      ((CsrWifiSmeApAuthType) 0x01)
+#define CSR_WIFI_SME_AP_AUTH_TYPE_WEP           ((CsrWifiSmeApAuthType) 0x02)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApDirection
+
+  DESCRIPTION
+    Definition of Direction
+
+ VALUES
+    CSR_WIFI_AP_DIRECTION_RECEIPIENT - Receipient
+    CSR_WIFI_AP_DIRECTION_ORIGINATOR - Originator
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeApDirection;
+#define CSR_WIFI_AP_DIRECTION_RECEIPIENT   ((CsrWifiSmeApDirection) 0x00)
+#define CSR_WIFI_AP_DIRECTION_ORIGINATOR   ((CsrWifiSmeApDirection) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApPhySupport
+
+  DESCRIPTION
+    Define bits for CsrWifiSmeApPhySupportMask
+
+ VALUES
+    CSR_WIFI_SME_AP_PHY_SUPPORT_A - 802.11a. It is not supported in the current
+                                    release.
+    CSR_WIFI_SME_AP_PHY_SUPPORT_B - 802.11b
+    CSR_WIFI_SME_AP_PHY_SUPPORT_G - 802.11g
+    CSR_WIFI_SME_AP_PHY_SUPPORT_N - 802.11n
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeApPhySupport;
+#define CSR_WIFI_SME_AP_PHY_SUPPORT_A   ((CsrWifiSmeApPhySupport) 0x01)
+#define CSR_WIFI_SME_AP_PHY_SUPPORT_B   ((CsrWifiSmeApPhySupport) 0x02)
+#define CSR_WIFI_SME_AP_PHY_SUPPORT_G   ((CsrWifiSmeApPhySupport) 0x04)
+#define CSR_WIFI_SME_AP_PHY_SUPPORT_N   ((CsrWifiSmeApPhySupport) 0x08)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApType
+
+  DESCRIPTION
+    Definition of AP types
+
+ VALUES
+    CSR_WIFI_AP_TYPE_LEGACY - Legacy AP
+    CSR_WIFI_AP_TYPE_P2P    - P2P Group Owner(GO)
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeApType;
+#define CSR_WIFI_AP_TYPE_LEGACY   ((CsrWifiSmeApType) 0x00)
+#define CSR_WIFI_AP_TYPE_P2P      ((CsrWifiSmeApType) 0x01)
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApAuthSupportMask
+
+  DESCRIPTION
+    See CsrWifiSmeApAuthSupport for bit definitions
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeApAuthSupportMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApPhySupportMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeApPhySupport
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeApPhySupportMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApRsnCapabilities
+
+  DESCRIPTION
+    Set to 0 for the current release
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeApRsnCapabilities;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApRsnCapabilitiesMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeApRsnCapabilities
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeApRsnCapabilitiesMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWapiCapabilities
+
+  DESCRIPTION
+    Ignored by the stack as WAPI is not supported for AP operations in the
+    current release
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeApWapiCapabilities;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWapiCapabilitiesMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeApWapiCapabilities
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeApWapiCapabilitiesMask;
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApHtParams
+
+  DESCRIPTION
+    Structure holding HT parameters
+
+  MEMBERS
+    greenfieldSupported - Indicates if the AP supports Htgreenfield operation
+                          subject to the chip capability. If the chip does not
+                          support Htgreenfield operation, this parameter will be
+                          ignored.
+                          NOTE: if shortGi20MHz is set to TRUE and the chip
+                          supports short GI operation for 20MHz this field will
+                          be be ignored and the AP will not support Htgreenfield
+                          operation.
+                          NOTE: This field is ignored by the Wi-Fi stack for the
+                          current release. It implies that AP does not support
+                          greenfield operation.
+    shortGi20MHz        - Indicates if the AP support short GI operation for
+                          20MHz subject to the chip capability.If the chip does
+                          not support short GI for 20MHz, this parameter is
+                          ignored
+    rxStbc              - Support for STBC for receive. 0 => No support for STBC
+                          , 1=> Use STBC for Rx
+    rifsModeAllowed     - RIFS Mode is allowed to protect overlapping non-HT BSS
+    htProtection        - Deprecated
+    dualCtsProtection   - Dual CTS Protection enabled
+
+*******************************************************************************/
+typedef struct
+{
+    CsrBool  greenfieldSupported;
+    CsrBool  shortGi20MHz;
+    CsrUint8 rxStbc;
+    CsrBool  rifsModeAllowed;
+    CsrUint8 htProtection;
+    CsrBool  dualCtsProtection;
+} CsrWifiSmeApHtParams;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApP2pOperatingChanEntry
+
+  DESCRIPTION
+
+  MEMBERS
+    operatingClass        - Channel operating class
+    operatingChannelCount - Number of channels in this entry
+    operatingChannel      - List of channels
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8  operatingClass;
+    CsrUint8  operatingChannelCount;
+    CsrUint8 *operatingChannel;
+} CsrWifiSmeApP2pOperatingChanEntry;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApP2pOperatingChanList
+
+  DESCRIPTION
+    This structure contains the lists of P2P operating channels
+
+  MEMBERS
+    country               - Country
+    channelEntryListCount - Number of entries
+    channelEntryList      - List of entries
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8                           country[3];
+    CsrUint8                           channelEntryListCount;
+    CsrWifiSmeApP2pOperatingChanEntry *channelEntryList;
+} CsrWifiSmeApP2pOperatingChanList;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApAuthPers
+
+  DESCRIPTION
+
+  MEMBERS
+    authSupport        -
+    encryptionModeMask -
+    rsnCapabilities    -
+    wapiCapabilities   -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeApAuthSupportMask      authSupport;
+    CsrWifiSmeEncryptionMask         encryptionModeMask;
+    CsrWifiSmeApRsnCapabilitiesMask  rsnCapabilities;
+    CsrWifiSmeApWapiCapabilitiesMask wapiCapabilities;
+} CsrWifiSmeApAuthPers;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBaSession
+
+  DESCRIPTION
+
+  MEMBERS
+    peerMacAddress - Indicates MAC address of the peer station
+    tid            - Specifies the TID of the MSDUs for which this Block Ack has
+                     been set up. Range: 0-15
+    direction      - Specifies if the AP is the originator or the recipient of
+                     the data stream that uses the Block Ack.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiMacAddress     peerMacAddress;
+    CsrUint8              tid;
+    CsrWifiSmeApDirection direction;
+} CsrWifiSmeApBaSession;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApMacConfig
+
+  DESCRIPTION
+    Structure holding AP MAC configuration.
+
+  MEMBERS
+    phySupportedBitmap   - Indicates supported physical layers
+    beaconInterval       - Beacon interval in terms of TUs
+    dtimPeriod           - DTIM period in terms of number of beacon intervals
+    maxListenInterval    - Maximum allowed listen interval as number of beacon
+                           intervals
+    supportedRatesCount  - Number of supported rates. Range : 0  to 20
+    supportedRates       - List of supportedRates. A rate is specied in the
+                           units of 500kbps. An entry for a basic rate shall
+                           have the MSB set to 1.
+    preamble             - Preamble to be advertised in beacons and probe
+                           responses
+    shortSlotTimeEnabled - TRUE indicates the AP shall use short slot time if
+                           all the stations use short slot operation.
+    ctsProtectionType    - CTS protection to be used
+    wmmEnabled           - Indicate whether WMM is enabled or not. If set to
+                           FALSE,the WMM parameters shall be ignored by the
+                           receiver.
+    wmmApParams          - WMM parameters to be used for local firmware queue
+                           configuration. Array index corresponds to the ACI.
+    wmmApBcParams        - WMM parameters to be advertised in beacon/probe
+                           response. Array index corresponds to the ACI
+    accessType           - Specifies whether the MAC addresses from the list
+                           should be allowed or denied
+    macAddressListCount  - Number of MAC addresses
+    macAddressList       - List of MAC addresses
+    apHtParams           - AP HT parameters. The stack shall use these
+                           parameters only if phySupportedBitmap indicates
+                           support for IEEE 802.11n
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeApPhySupportMask  phySupportedBitmap;
+    CsrUint16                   beaconInterval;
+    CsrUint8                    dtimPeriod;
+    CsrUint16                   maxListenInterval;
+    CsrUint8                    supportedRatesCount;
+    CsrUint8                    supportedRates[20];
+    CsrWifiSmePreambleType      preamble;
+    CsrBool                     shortSlotTimeEnabled;
+    CsrWifiSmeCtsProtectionType ctsProtectionType;
+    CsrBool                     wmmEnabled;
+    CsrWifiSmeWmmAcParams       wmmApParams[4];
+    CsrWifiSmeWmmAcParams       wmmApBcParams[4];
+    CsrWifiSmeApAccessType      accessType;
+    CsrUint8                    macAddressListCount;
+    CsrWifiMacAddress          *macAddressList;
+    CsrWifiSmeApHtParams        apHtParams;
+} CsrWifiSmeApMacConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApP2pGoConfig
+
+  DESCRIPTION
+
+  MEMBERS
+    groupCapability           - Indicates the P2P group capabilities
+    operatingChanList         - List of operating channels in the order of
+                                decreasing priority. It may contain channel
+                                entry/entries not supported by the wifi stack.
+                                These shall be filtered out by the wifi stack
+    opPsEnabled               - Indicates whether opportunistic power save can
+                                be used.
+                                Note: This parameter is ignored by the WiFi
+                                stack for the current release
+    ctWindow                  - Define Client Traffic window to be used in terms
+                                of number of TUs. Range: 0 to 127.
+                                Note: This parameter is ignored by the WiFi
+                                stack for the current release.
+    noaConfigMethod           - Notice of Absence configuration method.
+                                Note: This parameter is ignored by the WiFi
+                                stack for the current release.
+    allowNoaWithNonP2pDevices - Indicates if NOA should be allowed if non P2P
+                                devices are connected. If allowed the non P2P
+                                devices may suffer in throughput.
+                                Note: This parameter is ignored by the WiFi
+                                stack for the current release.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeP2pGroupCapabilityMask groupCapability;
+    CsrWifiSmeApP2pOperatingChanList operatingChanList;
+    CsrBool                          opPsEnabled;
+    CsrUint8                         ctWindow;
+    CsrWifiSmeP2pNoaConfigMethod     noaConfigMethod;
+    CsrBool                          allowNoaWithNonP2pDevices;
+} CsrWifiSmeApP2pGoConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApCredentials
+
+  DESCRIPTION
+
+  MEMBERS
+    authType                    -
+    smeAuthType                 -
+    smeAuthTypeopenSystemEmpty  -
+    smeAuthTypeauthwep          -
+    smeAuthTypeauthPers         -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeApAuthType authType;
+    union {
+        CsrWifiSmeEmpty      openSystemEmpty;
+        CsrWifiSmeWepAuth    authwep;
+        CsrWifiSmeApAuthPers authPers;
+    } smeAuthType;
+} CsrWifiSmeApCredentials;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApSecConfig
+
+  DESCRIPTION
+
+  MEMBERS
+    apCredentials -
+    wpsEnabled    -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeApCredentials apCredentials;
+    CsrBool                 wpsEnabled;
+} CsrWifiSmeApSecConfig;
+
+
+/* Downstream */
+#define CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST            (0x0000)
+
+#define CSR_WIFI_SME_AP_BEACONING_START_REQ               ((CsrWifiSmeApPrim) (0x0000 + CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_BEACONING_STOP_REQ                ((CsrWifiSmeApPrim) (0x0001 + CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_WPS_REGISTRATION_STARTED_REQ      ((CsrWifiSmeApPrim) (0x0002 + CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_WPS_REGISTRATION_FINISHED_REQ     ((CsrWifiSmeApPrim) (0x0003 + CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_WMM_PARAM_UPDATE_REQ              ((CsrWifiSmeApPrim) (0x0004 + CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_STA_DISCONNECT_REQ                ((CsrWifiSmeApPrim) (0x0005 + CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_WPS_CONFIGURATION_REQ             ((CsrWifiSmeApPrim) (0x0006 + CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_ACTIVE_BA_GET_REQ                 ((CsrWifiSmeApPrim) (0x0007 + CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_BA_DELETE_REQ                     ((CsrWifiSmeApPrim) (0x0008 + CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST))
+
+
+#define CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_HIGHEST           (0x0008 + CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST)
+
+/* Upstream */
+#define CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST              (0x0000 + CSR_PRIM_UPSTREAM)
+
+#define CSR_WIFI_SME_AP_BEACONING_START_CFM               ((CsrWifiSmeApPrim)(0x0000 + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_BEACONING_STOP_CFM                ((CsrWifiSmeApPrim)(0x0001 + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_STA_NOTIFY_IND                    ((CsrWifiSmeApPrim)(0x0002 + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_STA_CONNECT_START_IND             ((CsrWifiSmeApPrim)(0x0003 + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_WPS_REGISTRATION_STARTED_CFM      ((CsrWifiSmeApPrim)(0x0004 + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_WPS_REGISTRATION_FINISHED_CFM     ((CsrWifiSmeApPrim)(0x0005 + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_WMM_PARAM_UPDATE_CFM              ((CsrWifiSmeApPrim)(0x0006 + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_STA_DISCONNECT_CFM                ((CsrWifiSmeApPrim)(0x0007 + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_WPS_CONFIGURATION_CFM             ((CsrWifiSmeApPrim)(0x0008 + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_ERROR_IND                         ((CsrWifiSmeApPrim)(0x0009 + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_ACTIVE_BA_GET_CFM                 ((CsrWifiSmeApPrim)(0x000A + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AP_BA_DELETE_CFM                     ((CsrWifiSmeApPrim)(0x000B + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST))
+
+#define CSR_WIFI_SME_AP_PRIM_UPSTREAM_HIGHEST             (0x000B + CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST)
+
+#define CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_COUNT             (CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_HIGHEST + 1 - CSR_WIFI_SME_AP_PRIM_DOWNSTREAM_LOWEST)
+#define CSR_WIFI_SME_AP_PRIM_UPSTREAM_COUNT               (CSR_WIFI_SME_AP_PRIM_UPSTREAM_HIGHEST   + 1 - CSR_WIFI_SME_AP_PRIM_UPSTREAM_LOWEST)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBeaconingStartReq
+
+  DESCRIPTION
+    This primitive requests the SME to start AP or GO functionality
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    interfaceTag    -
+    initialPresence - Set to 0, if Not in a group fomration phase, set to 1 ,
+                      during group formation phase
+    apType          - apType : Legacy AP or P2PGO
+    cloakSsid       - cloakSsid flag.
+    ssid            - ssid.
+    ifIndex         - Radio Interface
+    channel         - channel.
+    maxConnections  - Maximum Stations + P2PClients allowed
+    apCredentials   - AP security credeitals used to advertise in beacon /probe
+                      response
+    smeApConfig     - AP configuration
+    p2pGoParam      - P2P specific GO parameters. Ignored if it is a leagacy AP
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent         common;
+    CsrUint16               interfaceTag;
+    CsrUint8                initialPresence;
+    CsrWifiSmeApType        apType;
+    CsrBool                 cloakSsid;
+    CsrWifiSsid             ssid;
+    CsrWifiSmeRadioIF       ifIndex;
+    CsrUint8                channel;
+    CsrUint8                maxConnections;
+    CsrWifiSmeApSecConfig   apCredentials;
+    CsrWifiSmeApMacConfig   smeApConfig;
+    CsrWifiSmeApP2pGoConfig p2pGoParam;
+} CsrWifiSmeApBeaconingStartReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBeaconingStopReq
+
+  DESCRIPTION
+    This primitive requests the SME to STOP AP or P2PGO operation
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeApBeaconingStopReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsRegistrationStartedReq
+
+  DESCRIPTION
+    This primitive tells SME that WPS registration procedure has started
+
+  MEMBERS
+    common                   - Common header for use with the CsrWifiFsm Module
+    interfaceTag             -
+    SelectedDevicePasswordId -
+    SelectedconfigMethod     -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent         common;
+    CsrUint16               interfaceTag;
+    CsrWifiSmeWpsDpid       SelectedDevicePasswordId;
+    CsrWifiSmeWpsConfigType SelectedconfigMethod;
+} CsrWifiSmeApWpsRegistrationStartedReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsRegistrationFinishedReq
+
+  DESCRIPTION
+    This primitive tells SME that WPS registration procedure has finished
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeApWpsRegistrationFinishedReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWmmParamUpdateReq
+
+  DESCRIPTION
+    Application uses this primitive to update the WMM parameters on the fly
+
+  MEMBERS
+    common        - Common header for use with the CsrWifiFsm Module
+    interfaceTag  -
+    wmmApParams   - WMM parameters to be used for local firmware queue
+                    configuration
+    wmmApBcParams - WMM parameters to be advertised in beacon/probe response
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrUint16             interfaceTag;
+    CsrWifiSmeWmmAcParams wmmApParams[4];
+    CsrWifiSmeWmmAcParams wmmApBcParams[4];
+} CsrWifiSmeApWmmParamUpdateReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApStaDisconnectReq
+
+  DESCRIPTION
+    This primitive tells SME to deauth ot disassociate a particular station
+    within BSS
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   -
+    deauthReason   -
+    disassocReason -
+    peerMacaddress -
+    keepBlocking   - If TRUE, the station is blocked. If FALSE and the station
+                     is connected, disconnect the station. If FALSE and the
+                     station is not connected, no action is taken.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrWifiSmeIEEE80211Reason deauthReason;
+    CsrWifiSmeIEEE80211Reason disassocReason;
+    CsrWifiMacAddress         peerMacaddress;
+    CsrBool                   keepBlocking;
+} CsrWifiSmeApStaDisconnectReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsConfigurationReq
+
+  DESCRIPTION
+    This primitive passes the WPS information for the device to SME. This may
+    be accepted only if no interface is active.
+
+  MEMBERS
+    common    - Common header for use with the CsrWifiFsm Module
+    wpsConfig - WPS config.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent     common;
+    CsrWifiSmeWpsConfig wpsConfig;
+} CsrWifiSmeApWpsConfigurationReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApActiveBaGetReq
+
+  DESCRIPTION
+    This primitive used to retrieve information related to the active block
+    ack sessions
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeApActiveBaGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBaDeleteReq
+
+  DESCRIPTION
+    This primitive is used to delete an active block ack session
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    reason       -
+    baSession    - BA session to be deleted
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrWifiSmeIEEE80211Reason reason;
+    CsrWifiSmeApBaSession     baSession;
+} CsrWifiSmeApBaDeleteReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBeaconingStartCfm
+
+  DESCRIPTION
+    This primitive confirms the completion of the request along with the
+    status
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    status       -
+    secIeLength  -
+    secIe        -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+    CsrUint16       secIeLength;
+    CsrUint8       *secIe;
+} CsrWifiSmeApBeaconingStartCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBeaconingStopCfm
+
+  DESCRIPTION
+    This primitive confirms AP or P2PGO operation is terminated
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmeApBeaconingStopCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApStaNotifyInd
+
+  DESCRIPTION
+    This primitive indicates that a station has joined or a previously joined
+    station has left the BSS/group
+
+  MEMBERS
+    common            - Common header for use with the CsrWifiFsm Module
+    interfaceTag      -
+    mediaStatus       -
+    peerMacAddress    -
+    peerDeviceAddress -
+    disassocReason    -
+    deauthReason      -
+    WpsRegistration   -
+    secIeLength       -
+    secIe             -
+    groupKeyId        -
+    seqNumber         -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrWifiSmeMediaStatus     mediaStatus;
+    CsrWifiMacAddress         peerMacAddress;
+    CsrWifiMacAddress         peerDeviceAddress;
+    CsrWifiSmeIEEE80211Reason disassocReason;
+    CsrWifiSmeIEEE80211Reason deauthReason;
+    CsrWifiSmeWpsRegistration WpsRegistration;
+    CsrUint8                  secIeLength;
+    CsrUint8                 *secIe;
+    CsrUint8                  groupKeyId;
+    CsrUint16                 seqNumber[8];
+} CsrWifiSmeApStaNotifyInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApStaConnectStartInd
+
+  DESCRIPTION
+    This primitive indicates that a stations request to join the group/BSS is
+    accepted
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   -
+    peerMacAddress -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrUint16         interfaceTag;
+    CsrWifiMacAddress peerMacAddress;
+} CsrWifiSmeApStaConnectStartInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsRegistrationStartedCfm
+
+  DESCRIPTION
+    A confirm for UNIFI_MGT_AP_WPS_REGISTRATION_STARTED.request
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmeApWpsRegistrationStartedCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsRegistrationFinishedCfm
+
+  DESCRIPTION
+    A confirm for UNIFI_MGT_AP_WPS_REGISTRATION_FINISHED.request
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmeApWpsRegistrationFinishedCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWmmParamUpdateCfm
+
+  DESCRIPTION
+    A confirm for CSR_WIFI_SME_AP_WMM_PARAM_UPDATE.request
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    status       -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmeApWmmParamUpdateCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApStaDisconnectCfm
+
+  DESCRIPTION
+    This primitive confirms the station is disconnected
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   -
+    status         -
+    peerMacaddress -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrUint16         interfaceTag;
+    CsrResult         status;
+    CsrWifiMacAddress peerMacaddress;
+} CsrWifiSmeApStaDisconnectCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApWpsConfigurationCfm
+
+  DESCRIPTION
+    Confirm.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Status of the request.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeApWpsConfigurationCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApErrorInd
+
+  DESCRIPTION
+    This primitve is sent by SME to indicate some error in AP operationi
+    after AP operations were started successfully and continuing the AP
+    operation may lead to undesired behaviour. It is the responsibility of
+    the upper layers to stop AP operation if needed
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Range 0-1
+    apType       -
+    status       - Contains the error status
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent  common;
+    CsrUint16        interfaceTag;
+    CsrWifiSmeApType apType;
+    CsrResult        status;
+} CsrWifiSmeApErrorInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApActiveBaGetCfm
+
+  DESCRIPTION
+    This primitive carries the information related to the active ba sessions
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    interfaceTag     -
+    status           - Reports the result of the request
+    activeBaCount    - Number of active block ack session
+    activeBaSessions - Points to a buffer containing an array of
+                       CsrWifiSmeApBaSession structures.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent        common;
+    CsrUint16              interfaceTag;
+    CsrResult              status;
+    CsrUint16              activeBaCount;
+    CsrWifiSmeApBaSession *activeBaSessions;
+} CsrWifiSmeApActiveBaGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeApBaDeleteCfm
+
+  DESCRIPTION
+    This primitive confirms the BA is deleted
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag -
+    status       - Reports the result of the request
+    baSession    - deleted BA session
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrUint16             interfaceTag;
+    CsrResult             status;
+    CsrWifiSmeApBaSession baSession;
+} CsrWifiSmeApBaDeleteCfm;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_SME_AP_PRIM_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_sme_converter_init.c b/drivers/staging/csr/csr_wifi_sme_converter_init.c
new file mode 100644
index 0000000..6897a77
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_converter_init.c
@@ -0,0 +1,202 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_msgconv.h"
+#include "csr_pmem.h"
+#include "csr_util.h"
+
+
+#ifdef CSR_LOG_ENABLE
+#include "csr_log.h"
+#endif
+
+#ifndef EXCLUDE_CSR_WIFI_SME_MODULE
+#include "csr_wifi_sme_serialize.h"
+#include "csr_wifi_sme_prim.h"
+
+static CsrMsgConvMsgEntry csrwifisme_conv_lut[] = {
+    { CSR_WIFI_SME_ACTIVATE_REQ, CsrWifiSmeActivateReqSizeof, CsrWifiSmeActivateReqSer, CsrWifiSmeActivateReqDes, CsrWifiSmeActivateReqSerFree },
+    { CSR_WIFI_SME_ADHOC_CONFIG_GET_REQ, CsrWifiSmeAdhocConfigGetReqSizeof, CsrWifiSmeAdhocConfigGetReqSer, CsrWifiSmeAdhocConfigGetReqDes, CsrWifiSmeAdhocConfigGetReqSerFree },
+    { CSR_WIFI_SME_ADHOC_CONFIG_SET_REQ, CsrWifiSmeAdhocConfigSetReqSizeof, CsrWifiSmeAdhocConfigSetReqSer, CsrWifiSmeAdhocConfigSetReqDes, CsrWifiSmeAdhocConfigSetReqSerFree },
+    { CSR_WIFI_SME_BLACKLIST_REQ, CsrWifiSmeBlacklistReqSizeof, CsrWifiSmeBlacklistReqSer, CsrWifiSmeBlacklistReqDes, CsrWifiSmeBlacklistReqSerFree },
+    { CSR_WIFI_SME_CALIBRATION_DATA_GET_REQ, CsrWifiSmeCalibrationDataGetReqSizeof, CsrWifiSmeCalibrationDataGetReqSer, CsrWifiSmeCalibrationDataGetReqDes, CsrWifiSmeCalibrationDataGetReqSerFree },
+    { CSR_WIFI_SME_CALIBRATION_DATA_SET_REQ, CsrWifiSmeCalibrationDataSetReqSizeof, CsrWifiSmeCalibrationDataSetReqSer, CsrWifiSmeCalibrationDataSetReqDes, CsrWifiSmeCalibrationDataSetReqSerFree },
+    { CSR_WIFI_SME_CCX_CONFIG_GET_REQ, CsrWifiSmeCcxConfigGetReqSizeof, CsrWifiSmeCcxConfigGetReqSer, CsrWifiSmeCcxConfigGetReqDes, CsrWifiSmeCcxConfigGetReqSerFree },
+    { CSR_WIFI_SME_CCX_CONFIG_SET_REQ, CsrWifiSmeCcxConfigSetReqSizeof, CsrWifiSmeCcxConfigSetReqSer, CsrWifiSmeCcxConfigSetReqDes, CsrWifiSmeCcxConfigSetReqSerFree },
+    { CSR_WIFI_SME_COEX_CONFIG_GET_REQ, CsrWifiSmeCoexConfigGetReqSizeof, CsrWifiSmeCoexConfigGetReqSer, CsrWifiSmeCoexConfigGetReqDes, CsrWifiSmeCoexConfigGetReqSerFree },
+    { CSR_WIFI_SME_COEX_CONFIG_SET_REQ, CsrWifiSmeCoexConfigSetReqSizeof, CsrWifiSmeCoexConfigSetReqSer, CsrWifiSmeCoexConfigSetReqDes, CsrWifiSmeCoexConfigSetReqSerFree },
+    { CSR_WIFI_SME_COEX_INFO_GET_REQ, CsrWifiSmeCoexInfoGetReqSizeof, CsrWifiSmeCoexInfoGetReqSer, CsrWifiSmeCoexInfoGetReqDes, CsrWifiSmeCoexInfoGetReqSerFree },
+    { CSR_WIFI_SME_CONNECT_REQ, CsrWifiSmeConnectReqSizeof, CsrWifiSmeConnectReqSer, CsrWifiSmeConnectReqDes, CsrWifiSmeConnectReqSerFree },
+    { CSR_WIFI_SME_CONNECTION_CONFIG_GET_REQ, CsrWifiSmeConnectionConfigGetReqSizeof, CsrWifiSmeConnectionConfigGetReqSer, CsrWifiSmeConnectionConfigGetReqDes, CsrWifiSmeConnectionConfigGetReqSerFree },
+    { CSR_WIFI_SME_CONNECTION_INFO_GET_REQ, CsrWifiSmeConnectionInfoGetReqSizeof, CsrWifiSmeConnectionInfoGetReqSer, CsrWifiSmeConnectionInfoGetReqDes, CsrWifiSmeConnectionInfoGetReqSerFree },
+    { CSR_WIFI_SME_CONNECTION_STATS_GET_REQ, CsrWifiSmeConnectionStatsGetReqSizeof, CsrWifiSmeConnectionStatsGetReqSer, CsrWifiSmeConnectionStatsGetReqDes, CsrWifiSmeConnectionStatsGetReqSerFree },
+    { CSR_WIFI_SME_DEACTIVATE_REQ, CsrWifiSmeDeactivateReqSizeof, CsrWifiSmeDeactivateReqSer, CsrWifiSmeDeactivateReqDes, CsrWifiSmeDeactivateReqSerFree },
+    { CSR_WIFI_SME_DISCONNECT_REQ, CsrWifiSmeDisconnectReqSizeof, CsrWifiSmeDisconnectReqSer, CsrWifiSmeDisconnectReqDes, CsrWifiSmeDisconnectReqSerFree },
+    { CSR_WIFI_SME_EVENT_MASK_SET_REQ, CsrWifiSmeEventMaskSetReqSizeof, CsrWifiSmeEventMaskSetReqSer, CsrWifiSmeEventMaskSetReqDes, CsrWifiSmeEventMaskSetReqSerFree },
+    { CSR_WIFI_SME_HOST_CONFIG_GET_REQ, CsrWifiSmeHostConfigGetReqSizeof, CsrWifiSmeHostConfigGetReqSer, CsrWifiSmeHostConfigGetReqDes, CsrWifiSmeHostConfigGetReqSerFree },
+    { CSR_WIFI_SME_HOST_CONFIG_SET_REQ, CsrWifiSmeHostConfigSetReqSizeof, CsrWifiSmeHostConfigSetReqSer, CsrWifiSmeHostConfigSetReqDes, CsrWifiSmeHostConfigSetReqSerFree },
+    { CSR_WIFI_SME_KEY_REQ, CsrWifiSmeKeyReqSizeof, CsrWifiSmeKeyReqSer, CsrWifiSmeKeyReqDes, CsrWifiSmeKeyReqSerFree },
+    { CSR_WIFI_SME_LINK_QUALITY_GET_REQ, CsrWifiSmeLinkQualityGetReqSizeof, CsrWifiSmeLinkQualityGetReqSer, CsrWifiSmeLinkQualityGetReqDes, CsrWifiSmeLinkQualityGetReqSerFree },
+    { CSR_WIFI_SME_MIB_CONFIG_GET_REQ, CsrWifiSmeMibConfigGetReqSizeof, CsrWifiSmeMibConfigGetReqSer, CsrWifiSmeMibConfigGetReqDes, CsrWifiSmeMibConfigGetReqSerFree },
+    { CSR_WIFI_SME_MIB_CONFIG_SET_REQ, CsrWifiSmeMibConfigSetReqSizeof, CsrWifiSmeMibConfigSetReqSer, CsrWifiSmeMibConfigSetReqDes, CsrWifiSmeMibConfigSetReqSerFree },
+    { CSR_WIFI_SME_MIB_GET_NEXT_REQ, CsrWifiSmeMibGetNextReqSizeof, CsrWifiSmeMibGetNextReqSer, CsrWifiSmeMibGetNextReqDes, CsrWifiSmeMibGetNextReqSerFree },
+    { CSR_WIFI_SME_MIB_GET_REQ, CsrWifiSmeMibGetReqSizeof, CsrWifiSmeMibGetReqSer, CsrWifiSmeMibGetReqDes, CsrWifiSmeMibGetReqSerFree },
+    { CSR_WIFI_SME_MIB_SET_REQ, CsrWifiSmeMibSetReqSizeof, CsrWifiSmeMibSetReqSer, CsrWifiSmeMibSetReqDes, CsrWifiSmeMibSetReqSerFree },
+    { CSR_WIFI_SME_MULTICAST_ADDRESS_REQ, CsrWifiSmeMulticastAddressReqSizeof, CsrWifiSmeMulticastAddressReqSer, CsrWifiSmeMulticastAddressReqDes, CsrWifiSmeMulticastAddressReqSerFree },
+    { CSR_WIFI_SME_PACKET_FILTER_SET_REQ, CsrWifiSmePacketFilterSetReqSizeof, CsrWifiSmePacketFilterSetReqSer, CsrWifiSmePacketFilterSetReqDes, CsrWifiSmePacketFilterSetReqSerFree },
+    { CSR_WIFI_SME_PERMANENT_MAC_ADDRESS_GET_REQ, CsrWifiSmePermanentMacAddressGetReqSizeof, CsrWifiSmePermanentMacAddressGetReqSer, CsrWifiSmePermanentMacAddressGetReqDes, CsrWifiSmePermanentMacAddressGetReqSerFree },
+    { CSR_WIFI_SME_PMKID_REQ, CsrWifiSmePmkidReqSizeof, CsrWifiSmePmkidReqSer, CsrWifiSmePmkidReqDes, CsrWifiSmePmkidReqSerFree },
+    { CSR_WIFI_SME_POWER_CONFIG_GET_REQ, CsrWifiSmePowerConfigGetReqSizeof, CsrWifiSmePowerConfigGetReqSer, CsrWifiSmePowerConfigGetReqDes, CsrWifiSmePowerConfigGetReqSerFree },
+    { CSR_WIFI_SME_POWER_CONFIG_SET_REQ, CsrWifiSmePowerConfigSetReqSizeof, CsrWifiSmePowerConfigSetReqSer, CsrWifiSmePowerConfigSetReqDes, CsrWifiSmePowerConfigSetReqSerFree },
+    { CSR_WIFI_SME_REGULATORY_DOMAIN_INFO_GET_REQ, CsrWifiSmeRegulatoryDomainInfoGetReqSizeof, CsrWifiSmeRegulatoryDomainInfoGetReqSer, CsrWifiSmeRegulatoryDomainInfoGetReqDes, CsrWifiSmeRegulatoryDomainInfoGetReqSerFree },
+    { CSR_WIFI_SME_ROAMING_CONFIG_GET_REQ, CsrWifiSmeRoamingConfigGetReqSizeof, CsrWifiSmeRoamingConfigGetReqSer, CsrWifiSmeRoamingConfigGetReqDes, CsrWifiSmeRoamingConfigGetReqSerFree },
+    { CSR_WIFI_SME_ROAMING_CONFIG_SET_REQ, CsrWifiSmeRoamingConfigSetReqSizeof, CsrWifiSmeRoamingConfigSetReqSer, CsrWifiSmeRoamingConfigSetReqDes, CsrWifiSmeRoamingConfigSetReqSerFree },
+    { CSR_WIFI_SME_SCAN_CONFIG_GET_REQ, CsrWifiSmeScanConfigGetReqSizeof, CsrWifiSmeScanConfigGetReqSer, CsrWifiSmeScanConfigGetReqDes, CsrWifiSmeScanConfigGetReqSerFree },
+    { CSR_WIFI_SME_SCAN_CONFIG_SET_REQ, CsrWifiSmeScanConfigSetReqSizeof, CsrWifiSmeScanConfigSetReqSer, CsrWifiSmeScanConfigSetReqDes, CsrWifiSmeScanConfigSetReqSerFree },
+    { CSR_WIFI_SME_SCAN_FULL_REQ, CsrWifiSmeScanFullReqSizeof, CsrWifiSmeScanFullReqSer, CsrWifiSmeScanFullReqDes, CsrWifiSmeScanFullReqSerFree },
+    { CSR_WIFI_SME_SCAN_RESULTS_FLUSH_REQ, CsrWifiSmeScanResultsFlushReqSizeof, CsrWifiSmeScanResultsFlushReqSer, CsrWifiSmeScanResultsFlushReqDes, CsrWifiSmeScanResultsFlushReqSerFree },
+    { CSR_WIFI_SME_SCAN_RESULTS_GET_REQ, CsrWifiSmeScanResultsGetReqSizeof, CsrWifiSmeScanResultsGetReqSer, CsrWifiSmeScanResultsGetReqDes, CsrWifiSmeScanResultsGetReqSerFree },
+    { CSR_WIFI_SME_SME_STA_CONFIG_GET_REQ, CsrWifiSmeSmeStaConfigGetReqSizeof, CsrWifiSmeSmeStaConfigGetReqSer, CsrWifiSmeSmeStaConfigGetReqDes, CsrWifiSmeSmeStaConfigGetReqSerFree },
+    { CSR_WIFI_SME_SME_STA_CONFIG_SET_REQ, CsrWifiSmeSmeStaConfigSetReqSizeof, CsrWifiSmeSmeStaConfigSetReqSer, CsrWifiSmeSmeStaConfigSetReqDes, CsrWifiSmeSmeStaConfigSetReqSerFree },
+    { CSR_WIFI_SME_STATION_MAC_ADDRESS_GET_REQ, CsrWifiSmeStationMacAddressGetReqSizeof, CsrWifiSmeStationMacAddressGetReqSer, CsrWifiSmeStationMacAddressGetReqDes, CsrWifiSmeStationMacAddressGetReqSerFree },
+    { CSR_WIFI_SME_TSPEC_REQ, CsrWifiSmeTspecReqSizeof, CsrWifiSmeTspecReqSer, CsrWifiSmeTspecReqDes, CsrWifiSmeTspecReqSerFree },
+    { CSR_WIFI_SME_VERSIONS_GET_REQ, CsrWifiSmeVersionsGetReqSizeof, CsrWifiSmeVersionsGetReqSer, CsrWifiSmeVersionsGetReqDes, CsrWifiSmeVersionsGetReqSerFree },
+    { CSR_WIFI_SME_WIFI_FLIGHTMODE_REQ, CsrWifiSmeWifiFlightmodeReqSizeof, CsrWifiSmeWifiFlightmodeReqSer, CsrWifiSmeWifiFlightmodeReqDes, CsrWifiSmeWifiFlightmodeReqSerFree },
+    { CSR_WIFI_SME_WIFI_OFF_REQ, CsrWifiSmeWifiOffReqSizeof, CsrWifiSmeWifiOffReqSer, CsrWifiSmeWifiOffReqDes, CsrWifiSmeWifiOffReqSerFree },
+    { CSR_WIFI_SME_WIFI_ON_REQ, CsrWifiSmeWifiOnReqSizeof, CsrWifiSmeWifiOnReqSer, CsrWifiSmeWifiOnReqDes, CsrWifiSmeWifiOnReqSerFree },
+    { CSR_WIFI_SME_CLOAKED_SSIDS_SET_REQ, CsrWifiSmeCloakedSsidsSetReqSizeof, CsrWifiSmeCloakedSsidsSetReqSer, CsrWifiSmeCloakedSsidsSetReqDes, CsrWifiSmeCloakedSsidsSetReqSerFree },
+    { CSR_WIFI_SME_CLOAKED_SSIDS_GET_REQ, CsrWifiSmeCloakedSsidsGetReqSizeof, CsrWifiSmeCloakedSsidsGetReqSer, CsrWifiSmeCloakedSsidsGetReqDes, CsrWifiSmeCloakedSsidsGetReqSerFree },
+    { CSR_WIFI_SME_SME_COMMON_CONFIG_GET_REQ, CsrWifiSmeSmeCommonConfigGetReqSizeof, CsrWifiSmeSmeCommonConfigGetReqSer, CsrWifiSmeSmeCommonConfigGetReqDes, CsrWifiSmeSmeCommonConfigGetReqSerFree },
+    { CSR_WIFI_SME_SME_COMMON_CONFIG_SET_REQ, CsrWifiSmeSmeCommonConfigSetReqSizeof, CsrWifiSmeSmeCommonConfigSetReqSer, CsrWifiSmeSmeCommonConfigSetReqDes, CsrWifiSmeSmeCommonConfigSetReqSerFree },
+    { CSR_WIFI_SME_INTERFACE_CAPABILITY_GET_REQ, CsrWifiSmeInterfaceCapabilityGetReqSizeof, CsrWifiSmeInterfaceCapabilityGetReqSer, CsrWifiSmeInterfaceCapabilityGetReqDes, CsrWifiSmeInterfaceCapabilityGetReqSerFree },
+    { CSR_WIFI_SME_WPS_CONFIGURATION_REQ, CsrWifiSmeWpsConfigurationReqSizeof, CsrWifiSmeWpsConfigurationReqSer, CsrWifiSmeWpsConfigurationReqDes, CsrWifiSmeWpsConfigurationReqSerFree },
+    { CSR_WIFI_SME_SET_REQ, CsrWifiSmeSetReqSizeof, CsrWifiSmeSetReqSer, CsrWifiSmeSetReqDes, CsrWifiSmeSetReqSerFree },
+    { CSR_WIFI_SME_ACTIVATE_CFM, CsrWifiSmeActivateCfmSizeof, CsrWifiSmeActivateCfmSer, CsrWifiSmeActivateCfmDes, CsrWifiSmeActivateCfmSerFree },
+    { CSR_WIFI_SME_ADHOC_CONFIG_GET_CFM, CsrWifiSmeAdhocConfigGetCfmSizeof, CsrWifiSmeAdhocConfigGetCfmSer, CsrWifiSmeAdhocConfigGetCfmDes, CsrWifiSmeAdhocConfigGetCfmSerFree },
+    { CSR_WIFI_SME_ADHOC_CONFIG_SET_CFM, CsrWifiSmeAdhocConfigSetCfmSizeof, CsrWifiSmeAdhocConfigSetCfmSer, CsrWifiSmeAdhocConfigSetCfmDes, CsrWifiSmeAdhocConfigSetCfmSerFree },
+    { CSR_WIFI_SME_ASSOCIATION_COMPLETE_IND, CsrWifiSmeAssociationCompleteIndSizeof, CsrWifiSmeAssociationCompleteIndSer, CsrWifiSmeAssociationCompleteIndDes, CsrWifiSmeAssociationCompleteIndSerFree },
+    { CSR_WIFI_SME_ASSOCIATION_START_IND, CsrWifiSmeAssociationStartIndSizeof, CsrWifiSmeAssociationStartIndSer, CsrWifiSmeAssociationStartIndDes, CsrWifiSmeAssociationStartIndSerFree },
+    { CSR_WIFI_SME_BLACKLIST_CFM, CsrWifiSmeBlacklistCfmSizeof, CsrWifiSmeBlacklistCfmSer, CsrWifiSmeBlacklistCfmDes, CsrWifiSmeBlacklistCfmSerFree },
+    { CSR_WIFI_SME_CALIBRATION_DATA_GET_CFM, CsrWifiSmeCalibrationDataGetCfmSizeof, CsrWifiSmeCalibrationDataGetCfmSer, CsrWifiSmeCalibrationDataGetCfmDes, CsrWifiSmeCalibrationDataGetCfmSerFree },
+    { CSR_WIFI_SME_CALIBRATION_DATA_SET_CFM, CsrWifiSmeCalibrationDataSetCfmSizeof, CsrWifiSmeCalibrationDataSetCfmSer, CsrWifiSmeCalibrationDataSetCfmDes, CsrWifiSmeCalibrationDataSetCfmSerFree },
+    { CSR_WIFI_SME_CCX_CONFIG_GET_CFM, CsrWifiSmeCcxConfigGetCfmSizeof, CsrWifiSmeCcxConfigGetCfmSer, CsrWifiSmeCcxConfigGetCfmDes, CsrWifiSmeCcxConfigGetCfmSerFree },
+    { CSR_WIFI_SME_CCX_CONFIG_SET_CFM, CsrWifiSmeCcxConfigSetCfmSizeof, CsrWifiSmeCcxConfigSetCfmSer, CsrWifiSmeCcxConfigSetCfmDes, CsrWifiSmeCcxConfigSetCfmSerFree },
+    { CSR_WIFI_SME_COEX_CONFIG_GET_CFM, CsrWifiSmeCoexConfigGetCfmSizeof, CsrWifiSmeCoexConfigGetCfmSer, CsrWifiSmeCoexConfigGetCfmDes, CsrWifiSmeCoexConfigGetCfmSerFree },
+    { CSR_WIFI_SME_COEX_CONFIG_SET_CFM, CsrWifiSmeCoexConfigSetCfmSizeof, CsrWifiSmeCoexConfigSetCfmSer, CsrWifiSmeCoexConfigSetCfmDes, CsrWifiSmeCoexConfigSetCfmSerFree },
+    { CSR_WIFI_SME_COEX_INFO_GET_CFM, CsrWifiSmeCoexInfoGetCfmSizeof, CsrWifiSmeCoexInfoGetCfmSer, CsrWifiSmeCoexInfoGetCfmDes, CsrWifiSmeCoexInfoGetCfmSerFree },
+    { CSR_WIFI_SME_CONNECT_CFM, CsrWifiSmeConnectCfmSizeof, CsrWifiSmeConnectCfmSer, CsrWifiSmeConnectCfmDes, CsrWifiSmeConnectCfmSerFree },
+    { CSR_WIFI_SME_CONNECTION_CONFIG_GET_CFM, CsrWifiSmeConnectionConfigGetCfmSizeof, CsrWifiSmeConnectionConfigGetCfmSer, CsrWifiSmeConnectionConfigGetCfmDes, CsrWifiSmeConnectionConfigGetCfmSerFree },
+    { CSR_WIFI_SME_CONNECTION_INFO_GET_CFM, CsrWifiSmeConnectionInfoGetCfmSizeof, CsrWifiSmeConnectionInfoGetCfmSer, CsrWifiSmeConnectionInfoGetCfmDes, CsrWifiSmeConnectionInfoGetCfmSerFree },
+    { CSR_WIFI_SME_CONNECTION_QUALITY_IND, CsrWifiSmeConnectionQualityIndSizeof, CsrWifiSmeConnectionQualityIndSer, CsrWifiSmeConnectionQualityIndDes, CsrWifiSmeConnectionQualityIndSerFree },
+    { CSR_WIFI_SME_CONNECTION_STATS_GET_CFM, CsrWifiSmeConnectionStatsGetCfmSizeof, CsrWifiSmeConnectionStatsGetCfmSer, CsrWifiSmeConnectionStatsGetCfmDes, CsrWifiSmeConnectionStatsGetCfmSerFree },
+    { CSR_WIFI_SME_DEACTIVATE_CFM, CsrWifiSmeDeactivateCfmSizeof, CsrWifiSmeDeactivateCfmSer, CsrWifiSmeDeactivateCfmDes, CsrWifiSmeDeactivateCfmSerFree },
+    { CSR_WIFI_SME_DISCONNECT_CFM, CsrWifiSmeDisconnectCfmSizeof, CsrWifiSmeDisconnectCfmSer, CsrWifiSmeDisconnectCfmDes, CsrWifiSmeDisconnectCfmSerFree },
+    { CSR_WIFI_SME_EVENT_MASK_SET_CFM, CsrWifiSmeEventMaskSetCfmSizeof, CsrWifiSmeEventMaskSetCfmSer, CsrWifiSmeEventMaskSetCfmDes, CsrWifiSmeEventMaskSetCfmSerFree },
+    { CSR_WIFI_SME_HOST_CONFIG_GET_CFM, CsrWifiSmeHostConfigGetCfmSizeof, CsrWifiSmeHostConfigGetCfmSer, CsrWifiSmeHostConfigGetCfmDes, CsrWifiSmeHostConfigGetCfmSerFree },
+    { CSR_WIFI_SME_HOST_CONFIG_SET_CFM, CsrWifiSmeHostConfigSetCfmSizeof, CsrWifiSmeHostConfigSetCfmSer, CsrWifiSmeHostConfigSetCfmDes, CsrWifiSmeHostConfigSetCfmSerFree },
+    { CSR_WIFI_SME_IBSS_STATION_IND, CsrWifiSmeIbssStationIndSizeof, CsrWifiSmeIbssStationIndSer, CsrWifiSmeIbssStationIndDes, CsrWifiSmeIbssStationIndSerFree },
+    { CSR_WIFI_SME_KEY_CFM, CsrWifiSmeKeyCfmSizeof, CsrWifiSmeKeyCfmSer, CsrWifiSmeKeyCfmDes, CsrWifiSmeKeyCfmSerFree },
+    { CSR_WIFI_SME_LINK_QUALITY_GET_CFM, CsrWifiSmeLinkQualityGetCfmSizeof, CsrWifiSmeLinkQualityGetCfmSer, CsrWifiSmeLinkQualityGetCfmDes, CsrWifiSmeLinkQualityGetCfmSerFree },
+    { CSR_WIFI_SME_MEDIA_STATUS_IND, CsrWifiSmeMediaStatusIndSizeof, CsrWifiSmeMediaStatusIndSer, CsrWifiSmeMediaStatusIndDes, CsrWifiSmeMediaStatusIndSerFree },
+    { CSR_WIFI_SME_MIB_CONFIG_GET_CFM, CsrWifiSmeMibConfigGetCfmSizeof, CsrWifiSmeMibConfigGetCfmSer, CsrWifiSmeMibConfigGetCfmDes, CsrWifiSmeMibConfigGetCfmSerFree },
+    { CSR_WIFI_SME_MIB_CONFIG_SET_CFM, CsrWifiSmeMibConfigSetCfmSizeof, CsrWifiSmeMibConfigSetCfmSer, CsrWifiSmeMibConfigSetCfmDes, CsrWifiSmeMibConfigSetCfmSerFree },
+    { CSR_WIFI_SME_MIB_GET_CFM, CsrWifiSmeMibGetCfmSizeof, CsrWifiSmeMibGetCfmSer, CsrWifiSmeMibGetCfmDes, CsrWifiSmeMibGetCfmSerFree },
+    { CSR_WIFI_SME_MIB_GET_NEXT_CFM, CsrWifiSmeMibGetNextCfmSizeof, CsrWifiSmeMibGetNextCfmSer, CsrWifiSmeMibGetNextCfmDes, CsrWifiSmeMibGetNextCfmSerFree },
+    { CSR_WIFI_SME_MIB_SET_CFM, CsrWifiSmeMibSetCfmSizeof, CsrWifiSmeMibSetCfmSer, CsrWifiSmeMibSetCfmDes, CsrWifiSmeMibSetCfmSerFree },
+    { CSR_WIFI_SME_MIC_FAILURE_IND, CsrWifiSmeMicFailureIndSizeof, CsrWifiSmeMicFailureIndSer, CsrWifiSmeMicFailureIndDes, CsrWifiSmeMicFailureIndSerFree },
+    { CSR_WIFI_SME_MULTICAST_ADDRESS_CFM, CsrWifiSmeMulticastAddressCfmSizeof, CsrWifiSmeMulticastAddressCfmSer, CsrWifiSmeMulticastAddressCfmDes, CsrWifiSmeMulticastAddressCfmSerFree },
+    { CSR_WIFI_SME_PACKET_FILTER_SET_CFM, CsrWifiSmePacketFilterSetCfmSizeof, CsrWifiSmePacketFilterSetCfmSer, CsrWifiSmePacketFilterSetCfmDes, CsrWifiSmePacketFilterSetCfmSerFree },
+    { CSR_WIFI_SME_PERMANENT_MAC_ADDRESS_GET_CFM, CsrWifiSmePermanentMacAddressGetCfmSizeof, CsrWifiSmePermanentMacAddressGetCfmSer, CsrWifiSmePermanentMacAddressGetCfmDes, CsrWifiSmePermanentMacAddressGetCfmSerFree },
+    { CSR_WIFI_SME_PMKID_CANDIDATE_LIST_IND, CsrWifiSmePmkidCandidateListIndSizeof, CsrWifiSmePmkidCandidateListIndSer, CsrWifiSmePmkidCandidateListIndDes, CsrWifiSmePmkidCandidateListIndSerFree },
+    { CSR_WIFI_SME_PMKID_CFM, CsrWifiSmePmkidCfmSizeof, CsrWifiSmePmkidCfmSer, CsrWifiSmePmkidCfmDes, CsrWifiSmePmkidCfmSerFree },
+    { CSR_WIFI_SME_POWER_CONFIG_GET_CFM, CsrWifiSmePowerConfigGetCfmSizeof, CsrWifiSmePowerConfigGetCfmSer, CsrWifiSmePowerConfigGetCfmDes, CsrWifiSmePowerConfigGetCfmSerFree },
+    { CSR_WIFI_SME_POWER_CONFIG_SET_CFM, CsrWifiSmePowerConfigSetCfmSizeof, CsrWifiSmePowerConfigSetCfmSer, CsrWifiSmePowerConfigSetCfmDes, CsrWifiSmePowerConfigSetCfmSerFree },
+    { CSR_WIFI_SME_REGULATORY_DOMAIN_INFO_GET_CFM, CsrWifiSmeRegulatoryDomainInfoGetCfmSizeof, CsrWifiSmeRegulatoryDomainInfoGetCfmSer, CsrWifiSmeRegulatoryDomainInfoGetCfmDes, CsrWifiSmeRegulatoryDomainInfoGetCfmSerFree },
+    { CSR_WIFI_SME_ROAM_COMPLETE_IND, CsrWifiSmeRoamCompleteIndSizeof, CsrWifiSmeRoamCompleteIndSer, CsrWifiSmeRoamCompleteIndDes, CsrWifiSmeRoamCompleteIndSerFree },
+    { CSR_WIFI_SME_ROAM_START_IND, CsrWifiSmeRoamStartIndSizeof, CsrWifiSmeRoamStartIndSer, CsrWifiSmeRoamStartIndDes, CsrWifiSmeRoamStartIndSerFree },
+    { CSR_WIFI_SME_ROAMING_CONFIG_GET_CFM, CsrWifiSmeRoamingConfigGetCfmSizeof, CsrWifiSmeRoamingConfigGetCfmSer, CsrWifiSmeRoamingConfigGetCfmDes, CsrWifiSmeRoamingConfigGetCfmSerFree },
+    { CSR_WIFI_SME_ROAMING_CONFIG_SET_CFM, CsrWifiSmeRoamingConfigSetCfmSizeof, CsrWifiSmeRoamingConfigSetCfmSer, CsrWifiSmeRoamingConfigSetCfmDes, CsrWifiSmeRoamingConfigSetCfmSerFree },
+    { CSR_WIFI_SME_SCAN_CONFIG_GET_CFM, CsrWifiSmeScanConfigGetCfmSizeof, CsrWifiSmeScanConfigGetCfmSer, CsrWifiSmeScanConfigGetCfmDes, CsrWifiSmeScanConfigGetCfmSerFree },
+    { CSR_WIFI_SME_SCAN_CONFIG_SET_CFM, CsrWifiSmeScanConfigSetCfmSizeof, CsrWifiSmeScanConfigSetCfmSer, CsrWifiSmeScanConfigSetCfmDes, CsrWifiSmeScanConfigSetCfmSerFree },
+    { CSR_WIFI_SME_SCAN_FULL_CFM, CsrWifiSmeScanFullCfmSizeof, CsrWifiSmeScanFullCfmSer, CsrWifiSmeScanFullCfmDes, CsrWifiSmeScanFullCfmSerFree },
+    { CSR_WIFI_SME_SCAN_RESULT_IND, CsrWifiSmeScanResultIndSizeof, CsrWifiSmeScanResultIndSer, CsrWifiSmeScanResultIndDes, CsrWifiSmeScanResultIndSerFree },
+    { CSR_WIFI_SME_SCAN_RESULTS_FLUSH_CFM, CsrWifiSmeScanResultsFlushCfmSizeof, CsrWifiSmeScanResultsFlushCfmSer, CsrWifiSmeScanResultsFlushCfmDes, CsrWifiSmeScanResultsFlushCfmSerFree },
+    { CSR_WIFI_SME_SCAN_RESULTS_GET_CFM, CsrWifiSmeScanResultsGetCfmSizeof, CsrWifiSmeScanResultsGetCfmSer, CsrWifiSmeScanResultsGetCfmDes, CsrWifiSmeScanResultsGetCfmSerFree },
+    { CSR_WIFI_SME_SME_STA_CONFIG_GET_CFM, CsrWifiSmeSmeStaConfigGetCfmSizeof, CsrWifiSmeSmeStaConfigGetCfmSer, CsrWifiSmeSmeStaConfigGetCfmDes, CsrWifiSmeSmeStaConfigGetCfmSerFree },
+    { CSR_WIFI_SME_SME_STA_CONFIG_SET_CFM, CsrWifiSmeSmeStaConfigSetCfmSizeof, CsrWifiSmeSmeStaConfigSetCfmSer, CsrWifiSmeSmeStaConfigSetCfmDes, CsrWifiSmeSmeStaConfigSetCfmSerFree },
+    { CSR_WIFI_SME_STATION_MAC_ADDRESS_GET_CFM, CsrWifiSmeStationMacAddressGetCfmSizeof, CsrWifiSmeStationMacAddressGetCfmSer, CsrWifiSmeStationMacAddressGetCfmDes, CsrWifiSmeStationMacAddressGetCfmSerFree },
+    { CSR_WIFI_SME_TSPEC_IND, CsrWifiSmeTspecIndSizeof, CsrWifiSmeTspecIndSer, CsrWifiSmeTspecIndDes, CsrWifiSmeTspecIndSerFree },
+    { CSR_WIFI_SME_TSPEC_CFM, CsrWifiSmeTspecCfmSizeof, CsrWifiSmeTspecCfmSer, CsrWifiSmeTspecCfmDes, CsrWifiSmeTspecCfmSerFree },
+    { CSR_WIFI_SME_VERSIONS_GET_CFM, CsrWifiSmeVersionsGetCfmSizeof, CsrWifiSmeVersionsGetCfmSer, CsrWifiSmeVersionsGetCfmDes, CsrWifiSmeVersionsGetCfmSerFree },
+    { CSR_WIFI_SME_WIFI_FLIGHTMODE_CFM, CsrWifiSmeWifiFlightmodeCfmSizeof, CsrWifiSmeWifiFlightmodeCfmSer, CsrWifiSmeWifiFlightmodeCfmDes, CsrWifiSmeWifiFlightmodeCfmSerFree },
+    { CSR_WIFI_SME_WIFI_OFF_IND, CsrWifiSmeWifiOffIndSizeof, CsrWifiSmeWifiOffIndSer, CsrWifiSmeWifiOffIndDes, CsrWifiSmeWifiOffIndSerFree },
+    { CSR_WIFI_SME_WIFI_OFF_CFM, CsrWifiSmeWifiOffCfmSizeof, CsrWifiSmeWifiOffCfmSer, CsrWifiSmeWifiOffCfmDes, CsrWifiSmeWifiOffCfmSerFree },
+    { CSR_WIFI_SME_WIFI_ON_CFM, CsrWifiSmeWifiOnCfmSizeof, CsrWifiSmeWifiOnCfmSer, CsrWifiSmeWifiOnCfmDes, CsrWifiSmeWifiOnCfmSerFree },
+    { CSR_WIFI_SME_CLOAKED_SSIDS_SET_CFM, CsrWifiSmeCloakedSsidsSetCfmSizeof, CsrWifiSmeCloakedSsidsSetCfmSer, CsrWifiSmeCloakedSsidsSetCfmDes, CsrWifiSmeCloakedSsidsSetCfmSerFree },
+    { CSR_WIFI_SME_CLOAKED_SSIDS_GET_CFM, CsrWifiSmeCloakedSsidsGetCfmSizeof, CsrWifiSmeCloakedSsidsGetCfmSer, CsrWifiSmeCloakedSsidsGetCfmDes, CsrWifiSmeCloakedSsidsGetCfmSerFree },
+    { CSR_WIFI_SME_WIFI_ON_IND, CsrWifiSmeWifiOnIndSizeof, CsrWifiSmeWifiOnIndSer, CsrWifiSmeWifiOnIndDes, CsrWifiSmeWifiOnIndSerFree },
+    { CSR_WIFI_SME_SME_COMMON_CONFIG_GET_CFM, CsrWifiSmeSmeCommonConfigGetCfmSizeof, CsrWifiSmeSmeCommonConfigGetCfmSer, CsrWifiSmeSmeCommonConfigGetCfmDes, CsrWifiSmeSmeCommonConfigGetCfmSerFree },
+    { CSR_WIFI_SME_SME_COMMON_CONFIG_SET_CFM, CsrWifiSmeSmeCommonConfigSetCfmSizeof, CsrWifiSmeSmeCommonConfigSetCfmSer, CsrWifiSmeSmeCommonConfigSetCfmDes, CsrWifiSmeSmeCommonConfigSetCfmSerFree },
+    { CSR_WIFI_SME_INTERFACE_CAPABILITY_GET_CFM, CsrWifiSmeInterfaceCapabilityGetCfmSizeof, CsrWifiSmeInterfaceCapabilityGetCfmSer, CsrWifiSmeInterfaceCapabilityGetCfmDes, CsrWifiSmeInterfaceCapabilityGetCfmSerFree },
+    { CSR_WIFI_SME_ERROR_IND, CsrWifiSmeErrorIndSizeof, CsrWifiSmeErrorIndSer, CsrWifiSmeErrorIndDes, CsrWifiSmeErrorIndSerFree },
+    { CSR_WIFI_SME_INFO_IND, CsrWifiSmeInfoIndSizeof, CsrWifiSmeInfoIndSer, CsrWifiSmeInfoIndDes, CsrWifiSmeInfoIndSerFree },
+    { CSR_WIFI_SME_CORE_DUMP_IND, CsrWifiSmeCoreDumpIndSizeof, CsrWifiSmeCoreDumpIndSer, CsrWifiSmeCoreDumpIndDes, CsrWifiSmeCoreDumpIndSerFree },
+    { CSR_WIFI_SME_AMP_STATUS_CHANGE_IND, CsrWifiSmeAmpStatusChangeIndSizeof, CsrWifiSmeAmpStatusChangeIndSer, CsrWifiSmeAmpStatusChangeIndDes, CsrWifiSmeAmpStatusChangeIndSerFree },
+    { CSR_WIFI_SME_WPS_CONFIGURATION_CFM, CsrWifiSmeWpsConfigurationCfmSizeof, CsrWifiSmeWpsConfigurationCfmSer, CsrWifiSmeWpsConfigurationCfmDes, CsrWifiSmeWpsConfigurationCfmSerFree },
+
+    { 0, NULL, NULL, NULL, NULL },
+};
+
+CsrMsgConvMsgEntry* CsrWifiSmeConverterLookup(CsrMsgConvMsgEntry *ce, CsrUint16 msgType)
+{
+    if (msgType & CSR_PRIM_UPSTREAM)
+    {
+        CsrUint16 idx = (msgType & ~CSR_PRIM_UPSTREAM) + CSR_WIFI_SME_PRIM_DOWNSTREAM_COUNT;
+        if (idx < (CSR_WIFI_SME_PRIM_UPSTREAM_COUNT + CSR_WIFI_SME_PRIM_DOWNSTREAM_COUNT) &&
+            csrwifisme_conv_lut[idx].msgType == msgType)
+        {
+            return &csrwifisme_conv_lut[idx];
+        }
+    }
+    else
+    {
+        if (msgType < CSR_WIFI_SME_PRIM_DOWNSTREAM_COUNT &&
+            csrwifisme_conv_lut[msgType].msgType == msgType)
+        {
+            return &csrwifisme_conv_lut[msgType];
+        }
+    }
+    return NULL;
+}
+
+
+void CsrWifiSmeConverterInit(void)
+{
+    CsrMsgConvInsert(CSR_WIFI_SME_PRIM, csrwifisme_conv_lut);
+    CsrMsgConvCustomLookupRegister(CSR_WIFI_SME_PRIM, CsrWifiSmeConverterLookup);
+}
+
+
+#ifdef CSR_LOG_ENABLE
+static const CsrLogPrimitiveInformation csrwifisme_conv_info = {
+    CSR_WIFI_SME_PRIM,
+    (CsrCharString *)"CSR_WIFI_SME_PRIM",
+    csrwifisme_conv_lut
+};
+const CsrLogPrimitiveInformation* CsrWifiSmeTechInfoGet(void)
+{
+    return &csrwifisme_conv_info;
+}
+
+
+#endif /* CSR_LOG_ENABLE */
+#endif /* EXCLUDE_CSR_WIFI_SME_MODULE */
diff --git a/drivers/staging/csr/csr_wifi_sme_converter_init.h b/drivers/staging/csr/csr_wifi_sme_converter_init.h
new file mode 100644
index 0000000..fb895de
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_converter_init.h
@@ -0,0 +1,42 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_SME_CONVERTER_INIT_H__
+#define CSR_WIFI_SME_CONVERTER_INIT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef EXCLUDE_CSR_WIFI_SME_MODULE
+
+#include "csr_msgconv.h"
+
+#ifdef CSR_LOG_ENABLE
+#include "csr_log.h"
+
+extern const CsrLogPrimitiveInformation* CsrWifiSmeTechInfoGet(void);
+#endif /* CSR_LOG_ENABLE */
+
+extern void CsrWifiSmeConverterInit(void);
+
+#else /* EXCLUDE_CSR_WIFI_SME_MODULE */
+
+#define CsrWifiSmeConverterInit()
+
+#endif /* EXCLUDE_CSR_WIFI_SME_MODULE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_SME_CONVERTER_INIT_H__ */
diff --git a/drivers/staging/csr/csr_wifi_sme_free_downstream_contents.c b/drivers/staging/csr/csr_wifi_sme_free_downstream_contents.c
new file mode 100644
index 0000000..93e75e5
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_free_downstream_contents.c
@@ -0,0 +1,188 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_wifi_sme_prim.h"
+#include "csr_wifi_sme_lib.h"
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrWifiSmeFreeDownstreamMessageContents
+ *
+ *  DESCRIPTION
+ *
+ *
+ *  PARAMETERS
+ *      eventClass: only the value CSR_WIFI_SME_PRIM will be handled
+ *      message:    the message to free
+ *----------------------------------------------------------------------------*/
+void CsrWifiSmeFreeDownstreamMessageContents(CsrUint16 eventClass, void *message)
+{
+    if (eventClass != CSR_WIFI_SME_PRIM)
+    {
+        return;
+    }
+    if (NULL == message)
+    {
+        return;
+    }
+
+    switch (*((CsrWifiSmePrim *) message))
+    {
+        case CSR_WIFI_SME_BLACKLIST_REQ:
+        {
+            CsrWifiSmeBlacklistReq *p = (CsrWifiSmeBlacklistReq *)message;
+            CsrPmemFree(p->setAddresses);
+            p->setAddresses = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_CALIBRATION_DATA_SET_REQ:
+        {
+            CsrWifiSmeCalibrationDataSetReq *p = (CsrWifiSmeCalibrationDataSetReq *)message;
+            CsrPmemFree(p->calibrationData);
+            p->calibrationData = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_CONNECT_REQ:
+        {
+            CsrWifiSmeConnectReq *p = (CsrWifiSmeConnectReq *)message;
+            CsrPmemFree(p->connectionConfig.mlmeAssociateReqInformationElements);
+            p->connectionConfig.mlmeAssociateReqInformationElements = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_MIB_GET_NEXT_REQ:
+        {
+            CsrWifiSmeMibGetNextReq *p = (CsrWifiSmeMibGetNextReq *)message;
+            CsrPmemFree(p->mibAttribute);
+            p->mibAttribute = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_MIB_GET_REQ:
+        {
+            CsrWifiSmeMibGetReq *p = (CsrWifiSmeMibGetReq *)message;
+            CsrPmemFree(p->mibAttribute);
+            p->mibAttribute = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_MIB_SET_REQ:
+        {
+            CsrWifiSmeMibSetReq *p = (CsrWifiSmeMibSetReq *)message;
+            CsrPmemFree(p->mibAttribute);
+            p->mibAttribute = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_MULTICAST_ADDRESS_REQ:
+        {
+            CsrWifiSmeMulticastAddressReq *p = (CsrWifiSmeMulticastAddressReq *)message;
+            CsrPmemFree(p->setAddresses);
+            p->setAddresses = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_PACKET_FILTER_SET_REQ:
+        {
+            CsrWifiSmePacketFilterSetReq *p = (CsrWifiSmePacketFilterSetReq *)message;
+            CsrPmemFree(p->filter);
+            p->filter = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_PMKID_REQ:
+        {
+            CsrWifiSmePmkidReq *p = (CsrWifiSmePmkidReq *)message;
+            CsrPmemFree(p->setPmkids);
+            p->setPmkids = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_SCAN_CONFIG_SET_REQ:
+        {
+            CsrWifiSmeScanConfigSetReq *p = (CsrWifiSmeScanConfigSetReq *)message;
+            CsrPmemFree(p->scanConfig.passiveChannelList);
+            p->scanConfig.passiveChannelList = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_SCAN_FULL_REQ:
+        {
+            CsrWifiSmeScanFullReq *p = (CsrWifiSmeScanFullReq *)message;
+            CsrPmemFree(p->ssid);
+            p->ssid = NULL;
+            CsrPmemFree(p->channelList);
+            p->channelList = NULL;
+            CsrPmemFree(p->probeIe);
+            p->probeIe = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_TSPEC_REQ:
+        {
+            CsrWifiSmeTspecReq *p = (CsrWifiSmeTspecReq *)message;
+            CsrPmemFree(p->tspec);
+            p->tspec = NULL;
+            CsrPmemFree(p->tclas);
+            p->tclas = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_WIFI_FLIGHTMODE_REQ:
+        {
+            CsrWifiSmeWifiFlightmodeReq *p = (CsrWifiSmeWifiFlightmodeReq *)message;
+            {
+                CsrUint16 i1;
+                for (i1 = 0; i1 < p->mibFilesCount; i1++)
+                {
+                    CsrPmemFree(p->mibFiles[i1].data);
+                    p->mibFiles[i1].data = NULL;
+                }
+            }
+            CsrPmemFree(p->mibFiles);
+            p->mibFiles = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_WIFI_ON_REQ:
+        {
+            CsrWifiSmeWifiOnReq *p = (CsrWifiSmeWifiOnReq *)message;
+            {
+                CsrUint16 i1;
+                for (i1 = 0; i1 < p->mibFilesCount; i1++)
+                {
+                    CsrPmemFree(p->mibFiles[i1].data);
+                    p->mibFiles[i1].data = NULL;
+                }
+            }
+            CsrPmemFree(p->mibFiles);
+            p->mibFiles = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_CLOAKED_SSIDS_SET_REQ:
+        {
+            CsrWifiSmeCloakedSsidsSetReq *p = (CsrWifiSmeCloakedSsidsSetReq *)message;
+            CsrPmemFree(p->cloakedSsids.cloakedSsids);
+            p->cloakedSsids.cloakedSsids = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_WPS_CONFIGURATION_REQ:
+        {
+            CsrWifiSmeWpsConfigurationReq *p = (CsrWifiSmeWpsConfigurationReq *)message;
+            CsrPmemFree(p->wpsConfig.secondaryDeviceType);
+            p->wpsConfig.secondaryDeviceType = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_SET_REQ:
+        {
+            CsrWifiSmeSetReq *p = (CsrWifiSmeSetReq *)message;
+            CsrPmemFree(p->data);
+            p->data = NULL;
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_sme_free_upstream_contents.c b/drivers/staging/csr/csr_wifi_sme_free_upstream_contents.c
new file mode 100644
index 0000000..c32bf68
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_free_upstream_contents.c
@@ -0,0 +1,276 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_wifi_sme_prim.h"
+#include "csr_wifi_sme_lib.h"
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrWifiSmeFreeUpstreamMessageContents
+ *
+ *  DESCRIPTION
+ *
+ *
+ *  PARAMETERS
+ *      eventClass: only the value CSR_WIFI_SME_PRIM will be handled
+ *      message:    the message to free
+ *----------------------------------------------------------------------------*/
+void CsrWifiSmeFreeUpstreamMessageContents(CsrUint16 eventClass, void *message)
+{
+    if (eventClass != CSR_WIFI_SME_PRIM)
+    {
+        return;
+    }
+    if (NULL == message)
+    {
+        return;
+    }
+
+    switch (*((CsrWifiSmePrim *) message))
+    {
+        case CSR_WIFI_SME_ASSOCIATION_COMPLETE_IND:
+        {
+            CsrWifiSmeAssociationCompleteInd *p = (CsrWifiSmeAssociationCompleteInd *)message;
+            CsrPmemFree(p->connectionInfo.beaconFrame);
+            p->connectionInfo.beaconFrame = NULL;
+            CsrPmemFree(p->connectionInfo.associationReqFrame);
+            p->connectionInfo.associationReqFrame = NULL;
+            CsrPmemFree(p->connectionInfo.associationRspFrame);
+            p->connectionInfo.associationRspFrame = NULL;
+            CsrPmemFree(p->connectionInfo.assocScanInfoElements);
+            p->connectionInfo.assocScanInfoElements = NULL;
+            CsrPmemFree(p->connectionInfo.assocReqInfoElements);
+            p->connectionInfo.assocReqInfoElements = NULL;
+            CsrPmemFree(p->connectionInfo.assocRspInfoElements);
+            p->connectionInfo.assocRspInfoElements = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_BLACKLIST_CFM:
+        {
+            CsrWifiSmeBlacklistCfm *p = (CsrWifiSmeBlacklistCfm *)message;
+            CsrPmemFree(p->getAddresses);
+            p->getAddresses = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_CALIBRATION_DATA_GET_CFM:
+        {
+            CsrWifiSmeCalibrationDataGetCfm *p = (CsrWifiSmeCalibrationDataGetCfm *)message;
+            CsrPmemFree(p->calibrationData);
+            p->calibrationData = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_CONNECTION_CONFIG_GET_CFM:
+        {
+            CsrWifiSmeConnectionConfigGetCfm *p = (CsrWifiSmeConnectionConfigGetCfm *)message;
+            CsrPmemFree(p->connectionConfig.mlmeAssociateReqInformationElements);
+            p->connectionConfig.mlmeAssociateReqInformationElements = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_CONNECTION_INFO_GET_CFM:
+        {
+            CsrWifiSmeConnectionInfoGetCfm *p = (CsrWifiSmeConnectionInfoGetCfm *)message;
+            CsrPmemFree(p->connectionInfo.beaconFrame);
+            p->connectionInfo.beaconFrame = NULL;
+            CsrPmemFree(p->connectionInfo.associationReqFrame);
+            p->connectionInfo.associationReqFrame = NULL;
+            CsrPmemFree(p->connectionInfo.associationRspFrame);
+            p->connectionInfo.associationRspFrame = NULL;
+            CsrPmemFree(p->connectionInfo.assocScanInfoElements);
+            p->connectionInfo.assocScanInfoElements = NULL;
+            CsrPmemFree(p->connectionInfo.assocReqInfoElements);
+            p->connectionInfo.assocReqInfoElements = NULL;
+            CsrPmemFree(p->connectionInfo.assocRspInfoElements);
+            p->connectionInfo.assocRspInfoElements = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_MEDIA_STATUS_IND:
+        {
+            CsrWifiSmeMediaStatusInd *p = (CsrWifiSmeMediaStatusInd *)message;
+            CsrPmemFree(p->connectionInfo.beaconFrame);
+            p->connectionInfo.beaconFrame = NULL;
+            CsrPmemFree(p->connectionInfo.associationReqFrame);
+            p->connectionInfo.associationReqFrame = NULL;
+            CsrPmemFree(p->connectionInfo.associationRspFrame);
+            p->connectionInfo.associationRspFrame = NULL;
+            CsrPmemFree(p->connectionInfo.assocScanInfoElements);
+            p->connectionInfo.assocScanInfoElements = NULL;
+            CsrPmemFree(p->connectionInfo.assocReqInfoElements);
+            p->connectionInfo.assocReqInfoElements = NULL;
+            CsrPmemFree(p->connectionInfo.assocRspInfoElements);
+            p->connectionInfo.assocRspInfoElements = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_MIB_GET_CFM:
+        {
+            CsrWifiSmeMibGetCfm *p = (CsrWifiSmeMibGetCfm *)message;
+            CsrPmemFree(p->mibAttribute);
+            p->mibAttribute = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_MIB_GET_NEXT_CFM:
+        {
+            CsrWifiSmeMibGetNextCfm *p = (CsrWifiSmeMibGetNextCfm *)message;
+            CsrPmemFree(p->mibAttribute);
+            p->mibAttribute = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_MULTICAST_ADDRESS_CFM:
+        {
+            CsrWifiSmeMulticastAddressCfm *p = (CsrWifiSmeMulticastAddressCfm *)message;
+            CsrPmemFree(p->getAddresses);
+            p->getAddresses = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_PMKID_CANDIDATE_LIST_IND:
+        {
+            CsrWifiSmePmkidCandidateListInd *p = (CsrWifiSmePmkidCandidateListInd *)message;
+            CsrPmemFree(p->pmkidCandidates);
+            p->pmkidCandidates = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_PMKID_CFM:
+        {
+            CsrWifiSmePmkidCfm *p = (CsrWifiSmePmkidCfm *)message;
+            CsrPmemFree(p->getPmkids);
+            p->getPmkids = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_SCAN_CONFIG_GET_CFM:
+        {
+            CsrWifiSmeScanConfigGetCfm *p = (CsrWifiSmeScanConfigGetCfm *)message;
+            CsrPmemFree(p->scanConfig.passiveChannelList);
+            p->scanConfig.passiveChannelList = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_SCAN_RESULT_IND:
+        {
+            CsrWifiSmeScanResultInd *p = (CsrWifiSmeScanResultInd *)message;
+            CsrPmemFree(p->result.informationElements);
+            p->result.informationElements = NULL;
+            switch (p->result.p2pDeviceRole)
+            {
+                case CSR_WIFI_SME_P2P_ROLE_GO:
+                {
+                    CsrUint16 i4;
+                    for (i4 = 0; i4 < p->result.deviceInfo.groupInfo.p2pClientInfoCount; i4++)
+                    {
+                        CsrPmemFree(p->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType);
+                        p->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType = NULL;
+                    }
+                }
+                    CsrPmemFree(p->result.deviceInfo.groupInfo.p2PClientInfo);
+                    p->result.deviceInfo.groupInfo.p2PClientInfo = NULL;
+                    break;
+                case CSR_WIFI_SME_P2P_ROLE_STANDALONE:
+                    CsrPmemFree(p->result.deviceInfo.standalonedevInfo.secDeviceType);
+                    p->result.deviceInfo.standalonedevInfo.secDeviceType = NULL;
+                    break;
+                default:
+                    break;
+            }
+            break;
+        }
+        case CSR_WIFI_SME_SCAN_RESULTS_GET_CFM:
+        {
+            CsrWifiSmeScanResultsGetCfm *p = (CsrWifiSmeScanResultsGetCfm *)message;
+            {
+                CsrUint16 i1;
+                for (i1 = 0; i1 < p->scanResultsCount; i1++)
+                {
+                    CsrPmemFree(p->scanResults[i1].informationElements);
+                    p->scanResults[i1].informationElements = NULL;
+                    switch (p->scanResults[i1].p2pDeviceRole)
+                    {
+                        case CSR_WIFI_SME_P2P_ROLE_GO:
+                        {
+                            CsrUint16 i4;
+                            for (i4 = 0; i4 < p->scanResults[i1].deviceInfo.groupInfo.p2pClientInfoCount; i4++)
+                            {
+                                CsrPmemFree(p->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType);
+                                p->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType = NULL;
+                            }
+                        }
+                            CsrPmemFree(p->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo);
+                            p->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo = NULL;
+                            break;
+                        case CSR_WIFI_SME_P2P_ROLE_STANDALONE:
+                            CsrPmemFree(p->scanResults[i1].deviceInfo.standalonedevInfo.secDeviceType);
+                            p->scanResults[i1].deviceInfo.standalonedevInfo.secDeviceType = NULL;
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+            CsrPmemFree(p->scanResults);
+            p->scanResults = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_TSPEC_IND:
+        {
+            CsrWifiSmeTspecInd *p = (CsrWifiSmeTspecInd *)message;
+            CsrPmemFree(p->tspec);
+            p->tspec = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_TSPEC_CFM:
+        {
+            CsrWifiSmeTspecCfm *p = (CsrWifiSmeTspecCfm *)message;
+            CsrPmemFree(p->tspec);
+            p->tspec = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_VERSIONS_GET_CFM:
+        {
+            CsrWifiSmeVersionsGetCfm *p = (CsrWifiSmeVersionsGetCfm *)message;
+            CsrPmemFree(p->versions.routerBuild);
+            p->versions.routerBuild = NULL;
+            CsrPmemFree(p->versions.smeBuild);
+            p->versions.smeBuild = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_CLOAKED_SSIDS_GET_CFM:
+        {
+            CsrWifiSmeCloakedSsidsGetCfm *p = (CsrWifiSmeCloakedSsidsGetCfm *)message;
+            CsrPmemFree(p->cloakedSsids.cloakedSsids);
+            p->cloakedSsids.cloakedSsids = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_ERROR_IND:
+        {
+            CsrWifiSmeErrorInd *p = (CsrWifiSmeErrorInd *)message;
+            CsrPmemFree(p->errorMessage);
+            p->errorMessage = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_INFO_IND:
+        {
+            CsrWifiSmeInfoInd *p = (CsrWifiSmeInfoInd *)message;
+            CsrPmemFree(p->infoMessage);
+            p->infoMessage = NULL;
+            break;
+        }
+        case CSR_WIFI_SME_CORE_DUMP_IND:
+        {
+            CsrWifiSmeCoreDumpInd *p = (CsrWifiSmeCoreDumpInd *)message;
+            CsrPmemFree(p->data);
+            p->data = NULL;
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_sme_lib.h b/drivers/staging/csr/csr_wifi_sme_lib.h
new file mode 100644
index 0000000..67dcb48
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_lib.h
@@ -0,0 +1,4315 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_SME_LIB_H__
+#define CSR_WIFI_SME_LIB_H__
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_sched.h"
+#include "csr_util.h"
+#include "csr_msg_transport.h"
+
+#include "csr_wifi_lib.h"
+
+#include "csr_wifi_sme_prim.h"
+#include "csr_wifi_sme_task.h"
+
+
+#ifndef CSR_WIFI_SME_LIB_DESTINATION_QUEUE
+# ifdef CSR_WIFI_NME_ENABLE
+# include "csr_wifi_nme_task.h"
+# define CSR_WIFI_SME_LIB_DESTINATION_QUEUE CSR_WIFI_NME_IFACEQUEUE
+# else
+# define CSR_WIFI_SME_LIB_DESTINATION_QUEUE CSR_WIFI_SME_IFACEQUEUE
+# endif
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiSmeFreeUpstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_SME upstream message. Does not
+ *      free the message itself, and can only be used for upstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_SME upstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiSmeFreeUpstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ *  CsrWifiSmeFreeDownstreamMessageContents
+ *
+ *  DESCRIPTION
+ *      Free the allocated memory in a CSR_WIFI_SME downstream message. Does not
+ *      free the message itself, and can only be used for downstream messages.
+ *
+ *  PARAMETERS
+ *      Deallocates the resources in a CSR_WIFI_SME downstream message
+ *----------------------------------------------------------------------------*/
+void CsrWifiSmeFreeDownstreamMessageContents(CsrUint16 eventClass, void *message);
+
+/*----------------------------------------------------------------------------*
+ * Enum to string functions
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiSme80211NetworkTypeToString(CsrWifiSme80211NetworkType value);
+const CsrCharString* CsrWifiSme80211PrivacyModeToString(CsrWifiSme80211PrivacyMode value);
+const CsrCharString* CsrWifiSme80211dTrustLevelToString(CsrWifiSme80211dTrustLevel value);
+const CsrCharString* CsrWifiSmeAmpStatusToString(CsrWifiSmeAmpStatus value);
+const CsrCharString* CsrWifiSmeAuthModeToString(CsrWifiSmeAuthMode value);
+const CsrCharString* CsrWifiSmeBasicUsabilityToString(CsrWifiSmeBasicUsability value);
+const CsrCharString* CsrWifiSmeBssTypeToString(CsrWifiSmeBssType value);
+const CsrCharString* CsrWifiSmeCoexSchemeToString(CsrWifiSmeCoexScheme value);
+const CsrCharString* CsrWifiSmeControlIndicationToString(CsrWifiSmeControlIndication value);
+const CsrCharString* CsrWifiSmeCtsProtectionTypeToString(CsrWifiSmeCtsProtectionType value);
+const CsrCharString* CsrWifiSmeD3AutoScanModeToString(CsrWifiSmeD3AutoScanMode value);
+const CsrCharString* CsrWifiSmeEncryptionToString(CsrWifiSmeEncryption value);
+const CsrCharString* CsrWifiSmeFirmwareDriverInterfaceToString(CsrWifiSmeFirmwareDriverInterface value);
+const CsrCharString* CsrWifiSmeHostPowerModeToString(CsrWifiSmeHostPowerMode value);
+const CsrCharString* CsrWifiSmeIEEE80211ReasonToString(CsrWifiSmeIEEE80211Reason value);
+const CsrCharString* CsrWifiSmeIEEE80211ResultToString(CsrWifiSmeIEEE80211Result value);
+const CsrCharString* CsrWifiSmeIndicationsToString(CsrWifiSmeIndications value);
+const CsrCharString* CsrWifiSmeKeyTypeToString(CsrWifiSmeKeyType value);
+const CsrCharString* CsrWifiSmeListActionToString(CsrWifiSmeListAction value);
+const CsrCharString* CsrWifiSmeMediaStatusToString(CsrWifiSmeMediaStatus value);
+const CsrCharString* CsrWifiSmeP2pCapabilityToString(CsrWifiSmeP2pCapability value);
+const CsrCharString* CsrWifiSmeP2pGroupCapabilityToString(CsrWifiSmeP2pGroupCapability value);
+const CsrCharString* CsrWifiSmeP2pNoaConfigMethodToString(CsrWifiSmeP2pNoaConfigMethod value);
+const CsrCharString* CsrWifiSmeP2pRoleToString(CsrWifiSmeP2pRole value);
+const CsrCharString* CsrWifiSmeP2pStatusToString(CsrWifiSmeP2pStatus value);
+const CsrCharString* CsrWifiSmePacketFilterModeToString(CsrWifiSmePacketFilterMode value);
+const CsrCharString* CsrWifiSmePowerSaveLevelToString(CsrWifiSmePowerSaveLevel value);
+const CsrCharString* CsrWifiSmePreambleTypeToString(CsrWifiSmePreambleType value);
+const CsrCharString* CsrWifiSmeRadioIFToString(CsrWifiSmeRadioIF value);
+const CsrCharString* CsrWifiSmeRegulatoryDomainToString(CsrWifiSmeRegulatoryDomain value);
+const CsrCharString* CsrWifiSmeRoamReasonToString(CsrWifiSmeRoamReason value);
+const CsrCharString* CsrWifiSmeScanTypeToString(CsrWifiSmeScanType value);
+const CsrCharString* CsrWifiSmeTrafficTypeToString(CsrWifiSmeTrafficType value);
+const CsrCharString* CsrWifiSmeTspecCtrlToString(CsrWifiSmeTspecCtrl value);
+const CsrCharString* CsrWifiSmeTspecResultCodeToString(CsrWifiSmeTspecResultCode value);
+const CsrCharString* CsrWifiSmeWepAuthModeToString(CsrWifiSmeWepAuthMode value);
+const CsrCharString* CsrWifiSmeWepCredentialTypeToString(CsrWifiSmeWepCredentialType value);
+const CsrCharString* CsrWifiSmeWmmModeToString(CsrWifiSmeWmmMode value);
+const CsrCharString* CsrWifiSmeWmmQosInfoToString(CsrWifiSmeWmmQosInfo value);
+const CsrCharString* CsrWifiSmeWpsConfigTypeToString(CsrWifiSmeWpsConfigType value);
+const CsrCharString* CsrWifiSmeWpsDeviceCategoryToString(CsrWifiSmeWpsDeviceCategory value);
+const CsrCharString* CsrWifiSmeWpsDeviceSubCategoryToString(CsrWifiSmeWpsDeviceSubCategory value);
+const CsrCharString* CsrWifiSmeWpsDpidToString(CsrWifiSmeWpsDpid value);
+const CsrCharString* CsrWifiSmeWpsRegistrationToString(CsrWifiSmeWpsRegistration value);
+
+
+/*----------------------------------------------------------------------------*
+ * CsrPrim Type toString function.
+ * Converts a message type to the String name of the Message
+ *----------------------------------------------------------------------------*/
+const CsrCharString* CsrWifiSmePrimTypeToString(CsrPrim msgType);
+
+/*----------------------------------------------------------------------------*
+ * Lookup arrays for PrimType name Strings
+ *----------------------------------------------------------------------------*/
+extern const CsrCharString *CsrWifiSmeUpstreamPrimNames[CSR_WIFI_SME_PRIM_UPSTREAM_COUNT];
+extern const CsrCharString *CsrWifiSmeDownstreamPrimNames[CSR_WIFI_SME_PRIM_DOWNSTREAM_COUNT];
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeActivateReqSend
+
+  DESCRIPTION
+    The WMA sends this primitive to activate the SME.
+    The WMA must activate the SME before it can send any other primitive.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeActivateReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeActivateReq *) CsrPmemAlloc(sizeof(CsrWifiSmeActivateReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ACTIVATE_REQ, dst__, src__);
+
+#define CsrWifiSmeActivateReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeActivateReq *msg__; \
+        CsrWifiSmeActivateReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeActivateReqSend(src__) \
+    CsrWifiSmeActivateReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeActivateCfmSend
+
+  DESCRIPTION
+    The SME sends this primitive when the activation is complete.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeActivateCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeActivateCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeActivateCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ACTIVATE_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeActivateCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeActivateCfm *msg__; \
+        CsrWifiSmeActivateCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeActivateCfmSend(dst__, status__) \
+    CsrWifiSmeActivateCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAdhocConfigGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the adHocConfig parameter.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeAdhocConfigGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeAdhocConfigGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeAdhocConfigGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ADHOC_CONFIG_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeAdhocConfigGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeAdhocConfigGetReq *msg__; \
+        CsrWifiSmeAdhocConfigGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeAdhocConfigGetReqSend(src__) \
+    CsrWifiSmeAdhocConfigGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAdhocConfigGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue       - Destination Task Queue
+    status      - Reports the result of the request
+    adHocConfig - Contains the values used when starting an Ad-hoc (IBSS)
+                  connection.
+
+*******************************************************************************/
+#define CsrWifiSmeAdhocConfigGetCfmCreate(msg__, dst__, src__, status__, adHocConfig__) \
+    msg__ = (CsrWifiSmeAdhocConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeAdhocConfigGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ADHOC_CONFIG_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->adHocConfig = (adHocConfig__);
+
+#define CsrWifiSmeAdhocConfigGetCfmSendTo(dst__, src__, status__, adHocConfig__) \
+    { \
+        CsrWifiSmeAdhocConfigGetCfm *msg__; \
+        CsrWifiSmeAdhocConfigGetCfmCreate(msg__, dst__, src__, status__, adHocConfig__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeAdhocConfigGetCfmSend(dst__, status__, adHocConfig__) \
+    CsrWifiSmeAdhocConfigGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, adHocConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAdhocConfigSetReqSend
+
+  DESCRIPTION
+    This primitive sets the value of the adHocConfig parameter.
+
+  PARAMETERS
+    queue       - Message Source Task Queue (Cfm's will be sent to this Queue)
+    adHocConfig - Sets the values to use when starting an ad hoc network.
+
+*******************************************************************************/
+#define CsrWifiSmeAdhocConfigSetReqCreate(msg__, dst__, src__, adHocConfig__) \
+    msg__ = (CsrWifiSmeAdhocConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeAdhocConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ADHOC_CONFIG_SET_REQ, dst__, src__); \
+    msg__->adHocConfig = (adHocConfig__);
+
+#define CsrWifiSmeAdhocConfigSetReqSendTo(dst__, src__, adHocConfig__) \
+    { \
+        CsrWifiSmeAdhocConfigSetReq *msg__; \
+        CsrWifiSmeAdhocConfigSetReqCreate(msg__, dst__, src__, adHocConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeAdhocConfigSetReqSend(src__, adHocConfig__) \
+    CsrWifiSmeAdhocConfigSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, adHocConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAdhocConfigSetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeAdhocConfigSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeAdhocConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeAdhocConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ADHOC_CONFIG_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeAdhocConfigSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeAdhocConfigSetCfm *msg__; \
+        CsrWifiSmeAdhocConfigSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeAdhocConfigSetCfmSend(dst__, status__) \
+    CsrWifiSmeAdhocConfigSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAmpStatusChangeIndSend
+
+  DESCRIPTION
+    Indication of change to AMP activity.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface on which the AMP activity changed.
+    ampStatus    - The new status of AMP activity.Range: {AMP_ACTIVE,
+                   AMP_INACTIVE}.
+
+*******************************************************************************/
+#define CsrWifiSmeAmpStatusChangeIndCreate(msg__, dst__, src__, interfaceTag__, ampStatus__) \
+    msg__ = (CsrWifiSmeAmpStatusChangeInd *) CsrPmemAlloc(sizeof(CsrWifiSmeAmpStatusChangeInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_AMP_STATUS_CHANGE_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->ampStatus = (ampStatus__);
+
+#define CsrWifiSmeAmpStatusChangeIndSendTo(dst__, src__, interfaceTag__, ampStatus__) \
+    { \
+        CsrWifiSmeAmpStatusChangeInd *msg__; \
+        CsrWifiSmeAmpStatusChangeIndCreate(msg__, dst__, src__, interfaceTag__, ampStatus__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeAmpStatusChangeIndSend(dst__, interfaceTag__, ampStatus__) \
+    CsrWifiSmeAmpStatusChangeIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, ampStatus__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAssociationCompleteIndSend
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive it whenever it completes an attempt to associate with an AP. If
+    the association was successful, status will be set to
+    CSR_WIFI_SME_STATUS_SUCCESS, otherwise status and deauthReason shall be
+    set to appropriate error codes.
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    status         - Reports the result of the association procedure
+    connectionInfo - This parameter is relevant only if result is
+                     CSR_WIFI_SME_STATUS_SUCCESS:
+                     it points to the connection information for the new network
+    deauthReason   - This parameter is relevant only if result is not
+                     CSR_WIFI_SME_STATUS_SUCCESS:
+                     if the AP deauthorised the station, it gives the reason of
+                     the deauthorization
+
+*******************************************************************************/
+#define CsrWifiSmeAssociationCompleteIndCreate(msg__, dst__, src__, interfaceTag__, status__, connectionInfo__, deauthReason__) \
+    msg__ = (CsrWifiSmeAssociationCompleteInd *) CsrPmemAlloc(sizeof(CsrWifiSmeAssociationCompleteInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ASSOCIATION_COMPLETE_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->connectionInfo = (connectionInfo__); \
+    msg__->deauthReason = (deauthReason__);
+
+#define CsrWifiSmeAssociationCompleteIndSendTo(dst__, src__, interfaceTag__, status__, connectionInfo__, deauthReason__) \
+    { \
+        CsrWifiSmeAssociationCompleteInd *msg__; \
+        CsrWifiSmeAssociationCompleteIndCreate(msg__, dst__, src__, interfaceTag__, status__, connectionInfo__, deauthReason__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeAssociationCompleteIndSend(dst__, interfaceTag__, status__, connectionInfo__, deauthReason__) \
+    CsrWifiSmeAssociationCompleteIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, connectionInfo__, deauthReason__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAssociationStartIndSend
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive it whenever it begins an attempt to associate with an AP.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    address      - BSSID of the associating network
+    ssid         - Service Set identifier of the associating network
+
+*******************************************************************************/
+#define CsrWifiSmeAssociationStartIndCreate(msg__, dst__, src__, interfaceTag__, address__, ssid__) \
+    msg__ = (CsrWifiSmeAssociationStartInd *) CsrPmemAlloc(sizeof(CsrWifiSmeAssociationStartInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ASSOCIATION_START_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->address = (address__); \
+    msg__->ssid = (ssid__);
+
+#define CsrWifiSmeAssociationStartIndSendTo(dst__, src__, interfaceTag__, address__, ssid__) \
+    { \
+        CsrWifiSmeAssociationStartInd *msg__; \
+        CsrWifiSmeAssociationStartIndCreate(msg__, dst__, src__, interfaceTag__, address__, ssid__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeAssociationStartIndSend(dst__, interfaceTag__, address__, ssid__) \
+    CsrWifiSmeAssociationStartIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, address__, ssid__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeBlacklistReqSend
+
+  DESCRIPTION
+    The wireless manager application should call this primitive to notify the
+    driver of any networks that should not be connected to. The interface
+    allows the wireless manager application to query, add, remove, and flush
+    the BSSIDs that the driver may not connect or roam to.
+    When this primitive adds to the black list the BSSID to which the SME is
+    currently connected, the SME will try to roam, if applicable, to another
+    BSSID in the same ESS; if the roaming procedure fails, the SME will
+    disconnect.
+
+  PARAMETERS
+    queue           - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    action          - The value of the CsrWifiSmeListAction parameter instructs
+                      the driver to modify or provide the list of blacklisted
+                      networks.
+    setAddressCount - Number of BSSIDs sent with this primitive
+    setAddresses    - Pointer to the list of BBSIDs sent with the primitive, set
+                      to NULL if none is sent.
+
+*******************************************************************************/
+#define CsrWifiSmeBlacklistReqCreate(msg__, dst__, src__, interfaceTag__, action__, setAddressCount__, setAddresses__) \
+    msg__ = (CsrWifiSmeBlacklistReq *) CsrPmemAlloc(sizeof(CsrWifiSmeBlacklistReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_BLACKLIST_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->action = (action__); \
+    msg__->setAddressCount = (setAddressCount__); \
+    msg__->setAddresses = (setAddresses__);
+
+#define CsrWifiSmeBlacklistReqSendTo(dst__, src__, interfaceTag__, action__, setAddressCount__, setAddresses__) \
+    { \
+        CsrWifiSmeBlacklistReq *msg__; \
+        CsrWifiSmeBlacklistReqCreate(msg__, dst__, src__, interfaceTag__, action__, setAddressCount__, setAddresses__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeBlacklistReqSend(src__, interfaceTag__, action__, setAddressCount__, setAddresses__) \
+    CsrWifiSmeBlacklistReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__, action__, setAddressCount__, setAddresses__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeBlacklistCfmSend
+
+  DESCRIPTION
+    The SME will call this primitive when the action on the blacklist has
+    completed. For a GET action, this primitive also reports the list of
+    BBSIDs in the blacklist.
+
+  PARAMETERS
+    queue           - Destination Task Queue
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    status          - Reports the result of the request
+    action          - Action in the request
+    getAddressCount - This parameter is only relevant if action is
+                      CSR_WIFI_SME_LIST_ACTION_GET:
+                      number of BSSIDs sent with this primitive
+    getAddresses    - Pointer to the list of BBSIDs sent with the primitive, set
+                      to NULL if none is sent.
+
+*******************************************************************************/
+#define CsrWifiSmeBlacklistCfmCreate(msg__, dst__, src__, interfaceTag__, status__, action__, getAddressCount__, getAddresses__) \
+    msg__ = (CsrWifiSmeBlacklistCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeBlacklistCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_BLACKLIST_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->action = (action__); \
+    msg__->getAddressCount = (getAddressCount__); \
+    msg__->getAddresses = (getAddresses__);
+
+#define CsrWifiSmeBlacklistCfmSendTo(dst__, src__, interfaceTag__, status__, action__, getAddressCount__, getAddresses__) \
+    { \
+        CsrWifiSmeBlacklistCfm *msg__; \
+        CsrWifiSmeBlacklistCfmCreate(msg__, dst__, src__, interfaceTag__, status__, action__, getAddressCount__, getAddresses__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeBlacklistCfmSend(dst__, interfaceTag__, status__, action__, getAddressCount__, getAddresses__) \
+    CsrWifiSmeBlacklistCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, action__, getAddressCount__, getAddresses__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCalibrationDataGetReqSend
+
+  DESCRIPTION
+    This primitive retrieves the Wi-Fi radio calibration data.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeCalibrationDataGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeCalibrationDataGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCalibrationDataGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CALIBRATION_DATA_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeCalibrationDataGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeCalibrationDataGetReq *msg__; \
+        CsrWifiSmeCalibrationDataGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCalibrationDataGetReqSend(src__) \
+    CsrWifiSmeCalibrationDataGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCalibrationDataGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue                 - Destination Task Queue
+    status                - Reports the result of the request
+    calibrationDataLength - Number of bytes in the buffer pointed by
+                            calibrationData
+    calibrationData       - Pointer to a buffer of length calibrationDataLength
+                            containing the calibration data
+
+*******************************************************************************/
+#define CsrWifiSmeCalibrationDataGetCfmCreate(msg__, dst__, src__, status__, calibrationDataLength__, calibrationData__) \
+    msg__ = (CsrWifiSmeCalibrationDataGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCalibrationDataGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CALIBRATION_DATA_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->calibrationDataLength = (calibrationDataLength__); \
+    msg__->calibrationData = (calibrationData__);
+
+#define CsrWifiSmeCalibrationDataGetCfmSendTo(dst__, src__, status__, calibrationDataLength__, calibrationData__) \
+    { \
+        CsrWifiSmeCalibrationDataGetCfm *msg__; \
+        CsrWifiSmeCalibrationDataGetCfmCreate(msg__, dst__, src__, status__, calibrationDataLength__, calibrationData__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCalibrationDataGetCfmSend(dst__, status__, calibrationDataLength__, calibrationData__) \
+    CsrWifiSmeCalibrationDataGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, calibrationDataLength__, calibrationData__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCalibrationDataSetReqSend
+
+  DESCRIPTION
+    This primitive sets the Wi-Fi radio calibration data.
+    The usage of the primitive with proper calibration data will avoid
+    time-consuming configuration after power-up.
+
+  PARAMETERS
+    queue                 - Message Source Task Queue (Cfm's will be sent to this Queue)
+    calibrationDataLength - Number of bytes in the buffer pointed by
+                            calibrationData
+    calibrationData       - Pointer to a buffer of length calibrationDataLength
+                            containing the calibration data
+
+*******************************************************************************/
+#define CsrWifiSmeCalibrationDataSetReqCreate(msg__, dst__, src__, calibrationDataLength__, calibrationData__) \
+    msg__ = (CsrWifiSmeCalibrationDataSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCalibrationDataSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CALIBRATION_DATA_SET_REQ, dst__, src__); \
+    msg__->calibrationDataLength = (calibrationDataLength__); \
+    msg__->calibrationData = (calibrationData__);
+
+#define CsrWifiSmeCalibrationDataSetReqSendTo(dst__, src__, calibrationDataLength__, calibrationData__) \
+    { \
+        CsrWifiSmeCalibrationDataSetReq *msg__; \
+        CsrWifiSmeCalibrationDataSetReqCreate(msg__, dst__, src__, calibrationDataLength__, calibrationData__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCalibrationDataSetReqSend(src__, calibrationDataLength__, calibrationData__) \
+    CsrWifiSmeCalibrationDataSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, calibrationDataLength__, calibrationData__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCalibrationDataSetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeCalibrationDataSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeCalibrationDataSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCalibrationDataSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CALIBRATION_DATA_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeCalibrationDataSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeCalibrationDataSetCfm *msg__; \
+        CsrWifiSmeCalibrationDataSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCalibrationDataSetCfmSend(dst__, status__) \
+    CsrWifiSmeCalibrationDataSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCcxConfigGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the CcxConfig parameter.
+    CURRENTLY NOT SUPPORTED.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiSmeCcxConfigGetReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeCcxConfigGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCcxConfigGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CCX_CONFIG_GET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeCcxConfigGetReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeCcxConfigGetReq *msg__; \
+        CsrWifiSmeCcxConfigGetReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCcxConfigGetReqSend(src__, interfaceTag__) \
+    CsrWifiSmeCcxConfigGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCcxConfigGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+    ccxConfig    - Currently not supported
+
+*******************************************************************************/
+#define CsrWifiSmeCcxConfigGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, ccxConfig__) \
+    msg__ = (CsrWifiSmeCcxConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCcxConfigGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CCX_CONFIG_GET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->ccxConfig = (ccxConfig__);
+
+#define CsrWifiSmeCcxConfigGetCfmSendTo(dst__, src__, interfaceTag__, status__, ccxConfig__) \
+    { \
+        CsrWifiSmeCcxConfigGetCfm *msg__; \
+        CsrWifiSmeCcxConfigGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, ccxConfig__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCcxConfigGetCfmSend(dst__, interfaceTag__, status__, ccxConfig__) \
+    CsrWifiSmeCcxConfigGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, ccxConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCcxConfigSetReqSend
+
+  DESCRIPTION
+    This primitive sets the value of the CcxConfig parameter.
+    CURRENTLY NOT SUPPORTED.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    ccxConfig    - Currently not supported
+
+*******************************************************************************/
+#define CsrWifiSmeCcxConfigSetReqCreate(msg__, dst__, src__, interfaceTag__, ccxConfig__) \
+    msg__ = (CsrWifiSmeCcxConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCcxConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CCX_CONFIG_SET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->ccxConfig = (ccxConfig__);
+
+#define CsrWifiSmeCcxConfigSetReqSendTo(dst__, src__, interfaceTag__, ccxConfig__) \
+    { \
+        CsrWifiSmeCcxConfigSetReq *msg__; \
+        CsrWifiSmeCcxConfigSetReqCreate(msg__, dst__, src__, interfaceTag__, ccxConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCcxConfigSetReqSend(src__, interfaceTag__, ccxConfig__) \
+    CsrWifiSmeCcxConfigSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__, ccxConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCcxConfigSetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeCcxConfigSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmeCcxConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCcxConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CCX_CONFIG_SET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeCcxConfigSetCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmeCcxConfigSetCfm *msg__; \
+        CsrWifiSmeCcxConfigSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCcxConfigSetCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmeCcxConfigSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCloakedSsidsGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the CloakedSsids parameter.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeCloakedSsidsGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeCloakedSsidsGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCloakedSsidsGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CLOAKED_SSIDS_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeCloakedSsidsGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeCloakedSsidsGetReq *msg__; \
+        CsrWifiSmeCloakedSsidsGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCloakedSsidsGetReqSend(src__) \
+    CsrWifiSmeCloakedSsidsGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCloakedSsidsGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    status       - Reports the result of the request
+    cloakedSsids - Reports list of cloaked SSIDs that are explicitly scanned for
+                   by the driver
+
+*******************************************************************************/
+#define CsrWifiSmeCloakedSsidsGetCfmCreate(msg__, dst__, src__, status__, cloakedSsids__) \
+    msg__ = (CsrWifiSmeCloakedSsidsGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCloakedSsidsGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CLOAKED_SSIDS_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->cloakedSsids = (cloakedSsids__);
+
+#define CsrWifiSmeCloakedSsidsGetCfmSendTo(dst__, src__, status__, cloakedSsids__) \
+    { \
+        CsrWifiSmeCloakedSsidsGetCfm *msg__; \
+        CsrWifiSmeCloakedSsidsGetCfmCreate(msg__, dst__, src__, status__, cloakedSsids__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCloakedSsidsGetCfmSend(dst__, status__, cloakedSsids__) \
+    CsrWifiSmeCloakedSsidsGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, cloakedSsids__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCloakedSsidsSetReqSend
+
+  DESCRIPTION
+    This primitive sets the list of cloaked SSIDs for which the WMA possesses
+    profiles.
+    When the driver detects a cloaked AP, the SME will explicitly scan for it
+    using the list of cloaked SSIDs provided it, and, if the scan succeeds,
+    it will report the AP to the WMA either via CSR_WIFI_SME_SCAN_RESULT_IND
+    (if registered) or via CSR_WIFI_SCAN_RESULT_GET_CFM.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    cloakedSsids - Sets the list of cloaked SSIDs
+
+*******************************************************************************/
+#define CsrWifiSmeCloakedSsidsSetReqCreate(msg__, dst__, src__, cloakedSsids__) \
+    msg__ = (CsrWifiSmeCloakedSsidsSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCloakedSsidsSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CLOAKED_SSIDS_SET_REQ, dst__, src__); \
+    msg__->cloakedSsids = (cloakedSsids__);
+
+#define CsrWifiSmeCloakedSsidsSetReqSendTo(dst__, src__, cloakedSsids__) \
+    { \
+        CsrWifiSmeCloakedSsidsSetReq *msg__; \
+        CsrWifiSmeCloakedSsidsSetReqCreate(msg__, dst__, src__, cloakedSsids__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCloakedSsidsSetReqSend(src__, cloakedSsids__) \
+    CsrWifiSmeCloakedSsidsSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, cloakedSsids__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCloakedSsidsSetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeCloakedSsidsSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeCloakedSsidsSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCloakedSsidsSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CLOAKED_SSIDS_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeCloakedSsidsSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeCloakedSsidsSetCfm *msg__; \
+        CsrWifiSmeCloakedSsidsSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCloakedSsidsSetCfmSend(dst__, status__) \
+    CsrWifiSmeCloakedSsidsSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexConfigGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the CoexConfig parameter.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeCoexConfigGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeCoexConfigGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCoexConfigGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_COEX_CONFIG_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeCoexConfigGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeCoexConfigGetReq *msg__; \
+        CsrWifiSmeCoexConfigGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCoexConfigGetReqSend(src__) \
+    CsrWifiSmeCoexConfigGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexConfigGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue      - Destination Task Queue
+    status     - Reports the result of the request
+    coexConfig - Reports the parameters used to configure the coexistence
+                 behaviour
+
+*******************************************************************************/
+#define CsrWifiSmeCoexConfigGetCfmCreate(msg__, dst__, src__, status__, coexConfig__) \
+    msg__ = (CsrWifiSmeCoexConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCoexConfigGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_COEX_CONFIG_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->coexConfig = (coexConfig__);
+
+#define CsrWifiSmeCoexConfigGetCfmSendTo(dst__, src__, status__, coexConfig__) \
+    { \
+        CsrWifiSmeCoexConfigGetCfm *msg__; \
+        CsrWifiSmeCoexConfigGetCfmCreate(msg__, dst__, src__, status__, coexConfig__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCoexConfigGetCfmSend(dst__, status__, coexConfig__) \
+    CsrWifiSmeCoexConfigGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, coexConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexConfigSetReqSend
+
+  DESCRIPTION
+    This primitive sets the value of the CoexConfig parameter.
+
+  PARAMETERS
+    queue      - Message Source Task Queue (Cfm's will be sent to this Queue)
+    coexConfig - Configures the coexistence behaviour
+
+*******************************************************************************/
+#define CsrWifiSmeCoexConfigSetReqCreate(msg__, dst__, src__, coexConfig__) \
+    msg__ = (CsrWifiSmeCoexConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCoexConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_COEX_CONFIG_SET_REQ, dst__, src__); \
+    msg__->coexConfig = (coexConfig__);
+
+#define CsrWifiSmeCoexConfigSetReqSendTo(dst__, src__, coexConfig__) \
+    { \
+        CsrWifiSmeCoexConfigSetReq *msg__; \
+        CsrWifiSmeCoexConfigSetReqCreate(msg__, dst__, src__, coexConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCoexConfigSetReqSend(src__, coexConfig__) \
+    CsrWifiSmeCoexConfigSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, coexConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexConfigSetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeCoexConfigSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeCoexConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCoexConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_COEX_CONFIG_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeCoexConfigSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeCoexConfigSetCfm *msg__; \
+        CsrWifiSmeCoexConfigSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCoexConfigSetCfmSend(dst__, status__) \
+    CsrWifiSmeCoexConfigSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexInfoGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the CoexInfo parameter.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeCoexInfoGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeCoexInfoGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCoexInfoGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_COEX_INFO_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeCoexInfoGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeCoexInfoGetReq *msg__; \
+        CsrWifiSmeCoexInfoGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCoexInfoGetReqSend(src__) \
+    CsrWifiSmeCoexInfoGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexInfoGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue    - Destination Task Queue
+    status   - Reports the result of the request
+    coexInfo - Reports information and state related to coexistence.
+
+*******************************************************************************/
+#define CsrWifiSmeCoexInfoGetCfmCreate(msg__, dst__, src__, status__, coexInfo__) \
+    msg__ = (CsrWifiSmeCoexInfoGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCoexInfoGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_COEX_INFO_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->coexInfo = (coexInfo__);
+
+#define CsrWifiSmeCoexInfoGetCfmSendTo(dst__, src__, status__, coexInfo__) \
+    { \
+        CsrWifiSmeCoexInfoGetCfm *msg__; \
+        CsrWifiSmeCoexInfoGetCfmCreate(msg__, dst__, src__, status__, coexInfo__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCoexInfoGetCfmSend(dst__, status__, coexInfo__) \
+    CsrWifiSmeCoexInfoGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, coexInfo__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectReqSend
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to start the
+    process of joining an 802.11 wireless network or to start an ad hoc
+    network.
+    The structure pointed by connectionConfig contains parameters describing
+    the network to join or, in case of an ad hoc network, to host or join.
+    The SME will select a network, perform the IEEE 802.11 Join, Authenticate
+    and Associate exchanges.
+    The SME selects the networks from the current scan list that match both
+    the SSID and BSSID, however either or both of these may be the wildcard
+    value. Using this rule, the following operations are possible:
+      * To connect to a network by name, specify the SSID and set the BSSID to
+        0xFF 0xFF 0xFF 0xFF 0xFF 0xFF. If there are two or more networks visible,
+        the SME will select the one with the strongest signal.
+      * To connect to a specific network, specify the BSSID. The SSID is
+        optional, but if given it must match the SSID of the network. An empty
+        SSID may be specified by setting the SSID length to zero. Please note
+        that if the BSSID is specified (i.e. not equal to 0xFF 0xFF 0xFF 0xFF
+        0xFF 0xFF), the SME will not attempt to roam if signal conditions become
+        poor, even if there is an alternative AP with an SSID that matches the
+        current network SSID.
+      * To connect to any network matching the other parameters (i.e. security,
+        etc), set the SSID length to zero and set the BSSID to 0xFF 0xFF 0xFF
+        0xFF 0xFF 0xFF. In this case, the SME will order all available networks
+        by their signal strengths and will iterate through this list until it
+        successfully connects.
+    NOTE: Specifying the BSSID will restrict the selection to one specific
+    network. If SSID and BSSID are given, they must both match the network
+    for it to be selected. To select a network based on the SSID only, the
+    wireless manager application must set the BSSID to 0xFF 0xFF 0xFF 0xFF
+    0xFF 0xFF.
+    The SME will try to connect to each network that matches the provided
+    parameters, one by one, until it succeeds or has tried unsuccessfully
+    with all the matching networks.
+    If there is no network that matches the parameters and the request allows
+    to host an ad hoc network, the SME will advertise a new ad hoc network
+    instead.
+    If the SME cannot connect, it will notify the failure in the confirm.
+
+  PARAMETERS
+    queue            - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag     - Interface Identifier; unique identifier of an interface
+    connectionConfig - Describes the candidate network to join or to host.
+
+*******************************************************************************/
+#define CsrWifiSmeConnectReqCreate(msg__, dst__, src__, interfaceTag__, connectionConfig__) \
+    msg__ = (CsrWifiSmeConnectReq *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CONNECT_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->connectionConfig = (connectionConfig__);
+
+#define CsrWifiSmeConnectReqSendTo(dst__, src__, interfaceTag__, connectionConfig__) \
+    { \
+        CsrWifiSmeConnectReq *msg__; \
+        CsrWifiSmeConnectReqCreate(msg__, dst__, src__, interfaceTag__, connectionConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeConnectReqSend(src__, interfaceTag__, connectionConfig__) \
+    CsrWifiSmeConnectReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__, connectionConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectCfmSend
+
+  DESCRIPTION
+    The SME calls this primitive when the connection exchange is complete or
+    all connection attempts fail.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request.
+                   CSR_WIFI_SME_STATUS_NOT_FOUND: all attempts by the SME to
+                   locate the requested AP failed
+
+*******************************************************************************/
+#define CsrWifiSmeConnectCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmeConnectCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CONNECT_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeConnectCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmeConnectCfm *msg__; \
+        CsrWifiSmeConnectCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeConnectCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmeConnectCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionConfigGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the ConnectionConfig parameter.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiSmeConnectionConfigGetReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeConnectionConfigGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectionConfigGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CONNECTION_CONFIG_GET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeConnectionConfigGetReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeConnectionConfigGetReq *msg__; \
+        CsrWifiSmeConnectionConfigGetReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeConnectionConfigGetReqSend(src__, interfaceTag__) \
+    CsrWifiSmeConnectionConfigGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionConfigGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue            - Destination Task Queue
+    interfaceTag     - Interface Identifier; unique identifier of an interface
+    status           - Reports the result of the request
+    connectionConfig - Parameters used by the SME for selecting a network
+
+*******************************************************************************/
+#define CsrWifiSmeConnectionConfigGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, connectionConfig__) \
+    msg__ = (CsrWifiSmeConnectionConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectionConfigGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CONNECTION_CONFIG_GET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->connectionConfig = (connectionConfig__);
+
+#define CsrWifiSmeConnectionConfigGetCfmSendTo(dst__, src__, interfaceTag__, status__, connectionConfig__) \
+    { \
+        CsrWifiSmeConnectionConfigGetCfm *msg__; \
+        CsrWifiSmeConnectionConfigGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, connectionConfig__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeConnectionConfigGetCfmSend(dst__, interfaceTag__, status__, connectionConfig__) \
+    CsrWifiSmeConnectionConfigGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, connectionConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionInfoGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the ConnectionInfo parameter.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiSmeConnectionInfoGetReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeConnectionInfoGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectionInfoGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CONNECTION_INFO_GET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeConnectionInfoGetReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeConnectionInfoGetReq *msg__; \
+        CsrWifiSmeConnectionInfoGetReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeConnectionInfoGetReqSend(src__, interfaceTag__) \
+    CsrWifiSmeConnectionInfoGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionInfoGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    status         - Reports the result of the request
+    connectionInfo - Information about the current connection
+
+*******************************************************************************/
+#define CsrWifiSmeConnectionInfoGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, connectionInfo__) \
+    msg__ = (CsrWifiSmeConnectionInfoGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectionInfoGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CONNECTION_INFO_GET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->connectionInfo = (connectionInfo__);
+
+#define CsrWifiSmeConnectionInfoGetCfmSendTo(dst__, src__, interfaceTag__, status__, connectionInfo__) \
+    { \
+        CsrWifiSmeConnectionInfoGetCfm *msg__; \
+        CsrWifiSmeConnectionInfoGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, connectionInfo__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeConnectionInfoGetCfmSend(dst__, interfaceTag__, status__, connectionInfo__) \
+    CsrWifiSmeConnectionInfoGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, connectionInfo__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionQualityIndSend
+
+  DESCRIPTION
+    The SME sends this primitive to all the tasks that have registered to
+    receive it whenever the value of the current connection quality
+    parameters change by more than a certain configurable amount.
+    The wireless manager application may configure the trigger thresholds for
+    this indication using the field in smeConfig parameter of
+    CSR_WIFI_SME_SME_CONFIG_SET_REQ.
+    Connection quality messages can be suppressed by setting both thresholds
+    to zero.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    linkQuality  - Indicates the quality of the link
+
+*******************************************************************************/
+#define CsrWifiSmeConnectionQualityIndCreate(msg__, dst__, src__, interfaceTag__, linkQuality__) \
+    msg__ = (CsrWifiSmeConnectionQualityInd *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectionQualityInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CONNECTION_QUALITY_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->linkQuality = (linkQuality__);
+
+#define CsrWifiSmeConnectionQualityIndSendTo(dst__, src__, interfaceTag__, linkQuality__) \
+    { \
+        CsrWifiSmeConnectionQualityInd *msg__; \
+        CsrWifiSmeConnectionQualityIndCreate(msg__, dst__, src__, interfaceTag__, linkQuality__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeConnectionQualityIndSend(dst__, interfaceTag__, linkQuality__) \
+    CsrWifiSmeConnectionQualityIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, linkQuality__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionStatsGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the ConnectionStats parameter.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiSmeConnectionStatsGetReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeConnectionStatsGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectionStatsGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CONNECTION_STATS_GET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeConnectionStatsGetReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeConnectionStatsGetReq *msg__; \
+        CsrWifiSmeConnectionStatsGetReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeConnectionStatsGetReqSend(src__, interfaceTag__) \
+    CsrWifiSmeConnectionStatsGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionStatsGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue           - Destination Task Queue
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    status          - Reports the result of the request
+    connectionStats - Statistics for current connection.
+
+*******************************************************************************/
+#define CsrWifiSmeConnectionStatsGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, connectionStats__) \
+    msg__ = (CsrWifiSmeConnectionStatsGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectionStatsGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CONNECTION_STATS_GET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->connectionStats = (connectionStats__);
+
+#define CsrWifiSmeConnectionStatsGetCfmSendTo(dst__, src__, interfaceTag__, status__, connectionStats__) \
+    { \
+        CsrWifiSmeConnectionStatsGetCfm *msg__; \
+        CsrWifiSmeConnectionStatsGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, connectionStats__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeConnectionStatsGetCfmSend(dst__, interfaceTag__, status__, connectionStats__) \
+    CsrWifiSmeConnectionStatsGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, connectionStats__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoreDumpIndSend
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive Wi-Fi Chip core dump data.
+    The core dump data may be fragmented and sent using more than one
+    indication.
+    To indicate that all the data has been sent, the last indication contains
+    a 'length' of 0 and 'data' of NULL.
+
+  PARAMETERS
+    queue      - Destination Task Queue
+    dataLength - Number of bytes in the buffer pointed to by 'data'
+    data       - Pointer to the buffer containing 'dataLength' bytes of core
+                 dump data
+
+*******************************************************************************/
+#define CsrWifiSmeCoreDumpIndCreate(msg__, dst__, src__, dataLength__, data__) \
+    msg__ = (CsrWifiSmeCoreDumpInd *) CsrPmemAlloc(sizeof(CsrWifiSmeCoreDumpInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_CORE_DUMP_IND, dst__, src__); \
+    msg__->dataLength = (dataLength__); \
+    msg__->data = (data__);
+
+#define CsrWifiSmeCoreDumpIndSendTo(dst__, src__, dataLength__, data__) \
+    { \
+        CsrWifiSmeCoreDumpInd *msg__; \
+        CsrWifiSmeCoreDumpIndCreate(msg__, dst__, src__, dataLength__, data__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeCoreDumpIndSend(dst__, dataLength__, data__) \
+    CsrWifiSmeCoreDumpIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, dataLength__, data__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDeactivateReqSend
+
+  DESCRIPTION
+    The WMA sends this primitive to deactivate the SME.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeDeactivateReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeDeactivateReq *) CsrPmemAlloc(sizeof(CsrWifiSmeDeactivateReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_DEACTIVATE_REQ, dst__, src__);
+
+#define CsrWifiSmeDeactivateReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeDeactivateReq *msg__; \
+        CsrWifiSmeDeactivateReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeDeactivateReqSend(src__) \
+    CsrWifiSmeDeactivateReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDeactivateCfmSend
+
+  DESCRIPTION
+    The SME sends this primitive when the deactivation is complete.
+    The WMA cannot send any more primitives until it actives the SME again
+    sending another CSR_WIFI_SME_ACTIVATE_REQ.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeDeactivateCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeDeactivateCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeDeactivateCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_DEACTIVATE_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeDeactivateCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeDeactivateCfm *msg__; \
+        CsrWifiSmeDeactivateCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeDeactivateCfmSend(dst__, status__) \
+    CsrWifiSmeDeactivateCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDisconnectReqSend
+
+  DESCRIPTION
+    The wireless manager application may disconnect from the current network
+    by calling this primitive
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiSmeDisconnectReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeDisconnectReq *) CsrPmemAlloc(sizeof(CsrWifiSmeDisconnectReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_DISCONNECT_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeDisconnectReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeDisconnectReq *msg__; \
+        CsrWifiSmeDisconnectReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeDisconnectReqSend(src__, interfaceTag__) \
+    CsrWifiSmeDisconnectReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDisconnectCfmSend
+
+  DESCRIPTION
+    On reception of CSR_WIFI_SME_DISCONNECT_REQ the SME will perform a
+    disconnect operation, sending a CsrWifiSmeMediaStatusInd with
+    CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED and then call this primitive when
+    disconnection is complete.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeDisconnectCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmeDisconnectCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeDisconnectCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_DISCONNECT_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeDisconnectCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmeDisconnectCfm *msg__; \
+        CsrWifiSmeDisconnectCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeDisconnectCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmeDisconnectCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeErrorIndSend
+
+  DESCRIPTION
+    Important error message indicating a error of some importance
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    errorMessage - Contains the error message.
+
+*******************************************************************************/
+#define CsrWifiSmeErrorIndCreate(msg__, dst__, src__, errorMessage__) \
+    msg__ = (CsrWifiSmeErrorInd *) CsrPmemAlloc(sizeof(CsrWifiSmeErrorInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ERROR_IND, dst__, src__); \
+    msg__->errorMessage = (errorMessage__);
+
+#define CsrWifiSmeErrorIndSendTo(dst__, src__, errorMessage__) \
+    { \
+        CsrWifiSmeErrorInd *msg__; \
+        CsrWifiSmeErrorIndCreate(msg__, dst__, src__, errorMessage__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeErrorIndSend(dst__, errorMessage__) \
+    CsrWifiSmeErrorIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, errorMessage__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeEventMaskSetReqSend
+
+  DESCRIPTION
+    The wireless manager application may register with the SME to receive
+    notification of interesting events. Indications will be sent only if the
+    wireless manager explicitly registers to be notified of that event.
+    indMask is a bit mask of values defined in CsrWifiSmeIndicationsMask.
+
+  PARAMETERS
+    queue   - Message Source Task Queue (Cfm's will be sent to this Queue)
+    indMask - Set mask with values from CsrWifiSmeIndications
+
+*******************************************************************************/
+#define CsrWifiSmeEventMaskSetReqCreate(msg__, dst__, src__, indMask__) \
+    msg__ = (CsrWifiSmeEventMaskSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeEventMaskSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_EVENT_MASK_SET_REQ, dst__, src__); \
+    msg__->indMask = (indMask__);
+
+#define CsrWifiSmeEventMaskSetReqSendTo(dst__, src__, indMask__) \
+    { \
+        CsrWifiSmeEventMaskSetReq *msg__; \
+        CsrWifiSmeEventMaskSetReqCreate(msg__, dst__, src__, indMask__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeEventMaskSetReqSend(src__, indMask__) \
+    CsrWifiSmeEventMaskSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, indMask__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeEventMaskSetCfmSend
+
+  DESCRIPTION
+    The SME calls the primitive to report the result of the request
+    primitive.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeEventMaskSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeEventMaskSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeEventMaskSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_EVENT_MASK_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeEventMaskSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeEventMaskSetCfm *msg__; \
+        CsrWifiSmeEventMaskSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeEventMaskSetCfmSend(dst__, status__) \
+    CsrWifiSmeEventMaskSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeHostConfigGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the hostConfig parameter.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiSmeHostConfigGetReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeHostConfigGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeHostConfigGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_HOST_CONFIG_GET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeHostConfigGetReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeHostConfigGetReq *msg__; \
+        CsrWifiSmeHostConfigGetReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeHostConfigGetReqSend(src__, interfaceTag__) \
+    CsrWifiSmeHostConfigGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeHostConfigGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+    hostConfig   - Current host power state.
+
+*******************************************************************************/
+#define CsrWifiSmeHostConfigGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, hostConfig__) \
+    msg__ = (CsrWifiSmeHostConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeHostConfigGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_HOST_CONFIG_GET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->hostConfig = (hostConfig__);
+
+#define CsrWifiSmeHostConfigGetCfmSendTo(dst__, src__, interfaceTag__, status__, hostConfig__) \
+    { \
+        CsrWifiSmeHostConfigGetCfm *msg__; \
+        CsrWifiSmeHostConfigGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, hostConfig__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeHostConfigGetCfmSend(dst__, interfaceTag__, status__, hostConfig__) \
+    CsrWifiSmeHostConfigGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, hostConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeHostConfigSetReqSend
+
+  DESCRIPTION
+    This primitive sets the value of the hostConfig parameter.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    hostConfig   - Communicates a change of host power state (for example, on
+                   mains power, on battery power etc) and of the periodicity of
+                   traffic data
+
+*******************************************************************************/
+#define CsrWifiSmeHostConfigSetReqCreate(msg__, dst__, src__, interfaceTag__, hostConfig__) \
+    msg__ = (CsrWifiSmeHostConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeHostConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_HOST_CONFIG_SET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->hostConfig = (hostConfig__);
+
+#define CsrWifiSmeHostConfigSetReqSendTo(dst__, src__, interfaceTag__, hostConfig__) \
+    { \
+        CsrWifiSmeHostConfigSetReq *msg__; \
+        CsrWifiSmeHostConfigSetReqCreate(msg__, dst__, src__, interfaceTag__, hostConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeHostConfigSetReqSend(src__, interfaceTag__, hostConfig__) \
+    CsrWifiSmeHostConfigSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__, hostConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeHostConfigSetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeHostConfigSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmeHostConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeHostConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_HOST_CONFIG_SET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeHostConfigSetCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmeHostConfigSetCfm *msg__; \
+        CsrWifiSmeHostConfigSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeHostConfigSetCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmeHostConfigSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeIbssStationIndSend
+
+  DESCRIPTION
+    The SME will send this primitive to indicate that a station has joined or
+    left the ad-hoc network.
+
+  PARAMETERS
+    queue       - Destination Task Queue
+    address     - MAC address of the station that has joined or left
+    isconnected - TRUE if the station joined, FALSE if the station left
+
+*******************************************************************************/
+#define CsrWifiSmeIbssStationIndCreate(msg__, dst__, src__, address__, isconnected__) \
+    msg__ = (CsrWifiSmeIbssStationInd *) CsrPmemAlloc(sizeof(CsrWifiSmeIbssStationInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_IBSS_STATION_IND, dst__, src__); \
+    msg__->address = (address__); \
+    msg__->isconnected = (isconnected__);
+
+#define CsrWifiSmeIbssStationIndSendTo(dst__, src__, address__, isconnected__) \
+    { \
+        CsrWifiSmeIbssStationInd *msg__; \
+        CsrWifiSmeIbssStationIndCreate(msg__, dst__, src__, address__, isconnected__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeIbssStationIndSend(dst__, address__, isconnected__) \
+    CsrWifiSmeIbssStationIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, address__, isconnected__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeInfoIndSend
+
+  DESCRIPTION
+    Message indicating a some info about current activity. Mostly of interest
+    in testing but may be useful in the field.
+
+  PARAMETERS
+    queue       - Destination Task Queue
+    infoMessage - Contains the message.
+
+*******************************************************************************/
+#define CsrWifiSmeInfoIndCreate(msg__, dst__, src__, infoMessage__) \
+    msg__ = (CsrWifiSmeInfoInd *) CsrPmemAlloc(sizeof(CsrWifiSmeInfoInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_INFO_IND, dst__, src__); \
+    msg__->infoMessage = (infoMessage__);
+
+#define CsrWifiSmeInfoIndSendTo(dst__, src__, infoMessage__) \
+    { \
+        CsrWifiSmeInfoInd *msg__; \
+        CsrWifiSmeInfoIndCreate(msg__, dst__, src__, infoMessage__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeInfoIndSend(dst__, infoMessage__) \
+    CsrWifiSmeInfoIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, infoMessage__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeInterfaceCapabilityGetReqSend
+
+  DESCRIPTION
+    The Wireless Manager calls this primitive to ask the SME for the
+    capabilities of the supported interfaces
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeInterfaceCapabilityGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeInterfaceCapabilityGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeInterfaceCapabilityGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_INTERFACE_CAPABILITY_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeInterfaceCapabilityGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeInterfaceCapabilityGetReq *msg__; \
+        CsrWifiSmeInterfaceCapabilityGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeInterfaceCapabilityGetReqSend(src__) \
+    CsrWifiSmeInterfaceCapabilityGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeInterfaceCapabilityGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue         - Destination Task Queue
+    status        - Result of the request
+    numInterfaces - Number of the interfaces supported
+    capBitmap     - Points to the list of capabilities bitmaps provided for each
+                    interface.
+                    The bits represent the following capabilities:
+                    -bits 7 to 4-Reserved
+                    -bit 3-AMP
+                    -bit 2-P2P
+                    -bit 1-AP
+                    -bit 0-STA
+
+*******************************************************************************/
+#define CsrWifiSmeInterfaceCapabilityGetCfmCreate(msg__, dst__, src__, status__, numInterfaces__, capBitmap__) \
+    msg__ = (CsrWifiSmeInterfaceCapabilityGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeInterfaceCapabilityGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_INTERFACE_CAPABILITY_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->numInterfaces = (numInterfaces__); \
+    CsrMemCpy(msg__->capBitmap, (capBitmap__), sizeof(CsrUint8) * 2);
+
+#define CsrWifiSmeInterfaceCapabilityGetCfmSendTo(dst__, src__, status__, numInterfaces__, capBitmap__) \
+    { \
+        CsrWifiSmeInterfaceCapabilityGetCfm *msg__; \
+        CsrWifiSmeInterfaceCapabilityGetCfmCreate(msg__, dst__, src__, status__, numInterfaces__, capBitmap__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeInterfaceCapabilityGetCfmSend(dst__, status__, numInterfaces__, capBitmap__) \
+    CsrWifiSmeInterfaceCapabilityGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, numInterfaces__, capBitmap__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeKeyReqSend
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to add or remove
+    keys that the chip should use for encryption of data.
+    The interface allows the wireless manager application to add and remove
+    keys according to the specified action.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    action       - The value of the CsrWifiSmeListAction parameter instructs the
+                   driver to modify or provide the list of keys.
+                   CSR_WIFI_SME_LIST_ACTION_GET is not supported here.
+    key          - Key to be added or removed
+
+*******************************************************************************/
+#define CsrWifiSmeKeyReqCreate(msg__, dst__, src__, interfaceTag__, action__, key__) \
+    msg__ = (CsrWifiSmeKeyReq *) CsrPmemAlloc(sizeof(CsrWifiSmeKeyReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_KEY_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->action = (action__); \
+    msg__->key = (key__);
+
+#define CsrWifiSmeKeyReqSendTo(dst__, src__, interfaceTag__, action__, key__) \
+    { \
+        CsrWifiSmeKeyReq *msg__; \
+        CsrWifiSmeKeyReqCreate(msg__, dst__, src__, interfaceTag__, action__, key__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeKeyReqSend(src__, interfaceTag__, action__, key__) \
+    CsrWifiSmeKeyReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__, action__, key__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeKeyCfmSend
+
+  DESCRIPTION
+    The SME calls the primitive to report the result of the request
+    primitive.
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    status         - Reports the result of the request
+    action         - Action in the request
+    keyType        - Type of the key added/deleted
+    peerMacAddress - Peer MAC Address of the key added/deleted
+
+*******************************************************************************/
+#define CsrWifiSmeKeyCfmCreate(msg__, dst__, src__, interfaceTag__, status__, action__, keyType__, peerMacAddress__) \
+    msg__ = (CsrWifiSmeKeyCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeKeyCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_KEY_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->action = (action__); \
+    msg__->keyType = (keyType__); \
+    msg__->peerMacAddress = (peerMacAddress__);
+
+#define CsrWifiSmeKeyCfmSendTo(dst__, src__, interfaceTag__, status__, action__, keyType__, peerMacAddress__) \
+    { \
+        CsrWifiSmeKeyCfm *msg__; \
+        CsrWifiSmeKeyCfmCreate(msg__, dst__, src__, interfaceTag__, status__, action__, keyType__, peerMacAddress__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeKeyCfmSend(dst__, interfaceTag__, status__, action__, keyType__, peerMacAddress__) \
+    CsrWifiSmeKeyCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, action__, keyType__, peerMacAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeLinkQualityGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the LinkQuality parameter.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiSmeLinkQualityGetReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeLinkQualityGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeLinkQualityGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_LINK_QUALITY_GET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeLinkQualityGetReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeLinkQualityGetReq *msg__; \
+        CsrWifiSmeLinkQualityGetReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeLinkQualityGetReqSend(src__, interfaceTag__) \
+    CsrWifiSmeLinkQualityGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeLinkQualityGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+    linkQuality  - Indicates the quality of the link
+
+*******************************************************************************/
+#define CsrWifiSmeLinkQualityGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, linkQuality__) \
+    msg__ = (CsrWifiSmeLinkQualityGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeLinkQualityGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_LINK_QUALITY_GET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->linkQuality = (linkQuality__);
+
+#define CsrWifiSmeLinkQualityGetCfmSendTo(dst__, src__, interfaceTag__, status__, linkQuality__) \
+    { \
+        CsrWifiSmeLinkQualityGetCfm *msg__; \
+        CsrWifiSmeLinkQualityGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, linkQuality__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeLinkQualityGetCfmSend(dst__, interfaceTag__, status__, linkQuality__) \
+    CsrWifiSmeLinkQualityGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, linkQuality__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMediaStatusIndSend
+
+  DESCRIPTION
+    The SME sends this primitive to all the tasks that have registered to
+    receive it when a network connection is established, lost or has moved to
+    another AP.
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    mediaStatus    - Indicates the media status
+    connectionInfo - This parameter is relevant only if the mediaStatus is
+                     CSR_WIFI_SME_MEDIA_STATUS_CONNECTED:
+                     it points to the connection information for the new network
+    disassocReason - This parameter is relevant only if the mediaStatus is
+                     CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED:
+                     if a disassociation has occurred it gives the reason of the
+                     disassociation
+    deauthReason   - This parameter is relevant only if the mediaStatus is
+                     CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED:
+                     if a deauthentication has occurred it gives the reason of
+                     the deauthentication
+
+*******************************************************************************/
+#define CsrWifiSmeMediaStatusIndCreate(msg__, dst__, src__, interfaceTag__, mediaStatus__, connectionInfo__, disassocReason__, deauthReason__) \
+    msg__ = (CsrWifiSmeMediaStatusInd *) CsrPmemAlloc(sizeof(CsrWifiSmeMediaStatusInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MEDIA_STATUS_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->mediaStatus = (mediaStatus__); \
+    msg__->connectionInfo = (connectionInfo__); \
+    msg__->disassocReason = (disassocReason__); \
+    msg__->deauthReason = (deauthReason__);
+
+#define CsrWifiSmeMediaStatusIndSendTo(dst__, src__, interfaceTag__, mediaStatus__, connectionInfo__, disassocReason__, deauthReason__) \
+    { \
+        CsrWifiSmeMediaStatusInd *msg__; \
+        CsrWifiSmeMediaStatusIndCreate(msg__, dst__, src__, interfaceTag__, mediaStatus__, connectionInfo__, disassocReason__, deauthReason__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMediaStatusIndSend(dst__, interfaceTag__, mediaStatus__, connectionInfo__, disassocReason__, deauthReason__) \
+    CsrWifiSmeMediaStatusIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, mediaStatus__, connectionInfo__, disassocReason__, deauthReason__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibConfigGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the MibConfig parameter.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeMibConfigGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeMibConfigGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeMibConfigGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MIB_CONFIG_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeMibConfigGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeMibConfigGetReq *msg__; \
+        CsrWifiSmeMibConfigGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMibConfigGetReqSend(src__) \
+    CsrWifiSmeMibConfigGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibConfigGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue     - Destination Task Queue
+    status    - Reports the result of the request
+    mibConfig - Reports various IEEE 802.11 attributes as currently configured
+
+*******************************************************************************/
+#define CsrWifiSmeMibConfigGetCfmCreate(msg__, dst__, src__, status__, mibConfig__) \
+    msg__ = (CsrWifiSmeMibConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeMibConfigGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MIB_CONFIG_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->mibConfig = (mibConfig__);
+
+#define CsrWifiSmeMibConfigGetCfmSendTo(dst__, src__, status__, mibConfig__) \
+    { \
+        CsrWifiSmeMibConfigGetCfm *msg__; \
+        CsrWifiSmeMibConfigGetCfmCreate(msg__, dst__, src__, status__, mibConfig__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMibConfigGetCfmSend(dst__, status__, mibConfig__) \
+    CsrWifiSmeMibConfigGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, mibConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibConfigSetReqSend
+
+  DESCRIPTION
+    This primitive sets the value of the MibConfig parameter.
+
+  PARAMETERS
+    queue     - Message Source Task Queue (Cfm's will be sent to this Queue)
+    mibConfig - Conveys the desired value of various IEEE 802.11 attributes as
+                currently configured
+
+*******************************************************************************/
+#define CsrWifiSmeMibConfigSetReqCreate(msg__, dst__, src__, mibConfig__) \
+    msg__ = (CsrWifiSmeMibConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeMibConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MIB_CONFIG_SET_REQ, dst__, src__); \
+    msg__->mibConfig = (mibConfig__);
+
+#define CsrWifiSmeMibConfigSetReqSendTo(dst__, src__, mibConfig__) \
+    { \
+        CsrWifiSmeMibConfigSetReq *msg__; \
+        CsrWifiSmeMibConfigSetReqCreate(msg__, dst__, src__, mibConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMibConfigSetReqSend(src__, mibConfig__) \
+    CsrWifiSmeMibConfigSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, mibConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibConfigSetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeMibConfigSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeMibConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeMibConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MIB_CONFIG_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeMibConfigSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeMibConfigSetCfm *msg__; \
+        CsrWifiSmeMibConfigSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMibConfigSetCfmSend(dst__, status__) \
+    CsrWifiSmeMibConfigSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibGetCfmSend
+
+  DESCRIPTION
+    The SME calls this primitive to return the requested MIB variable values.
+
+  PARAMETERS
+    queue              - Destination Task Queue
+    status             - Reports the result of the request
+    mibAttributeLength - Length of mibAttribute
+    mibAttribute       - Points to the VarBind or VarBindList containing the
+                         names and values of the MIB variables requested
+
+*******************************************************************************/
+#define CsrWifiSmeMibGetCfmCreate(msg__, dst__, src__, status__, mibAttributeLength__, mibAttribute__) \
+    msg__ = (CsrWifiSmeMibGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeMibGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MIB_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->mibAttributeLength = (mibAttributeLength__); \
+    msg__->mibAttribute = (mibAttribute__);
+
+#define CsrWifiSmeMibGetCfmSendTo(dst__, src__, status__, mibAttributeLength__, mibAttribute__) \
+    { \
+        CsrWifiSmeMibGetCfm *msg__; \
+        CsrWifiSmeMibGetCfmCreate(msg__, dst__, src__, status__, mibAttributeLength__, mibAttribute__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMibGetCfmSend(dst__, status__, mibAttributeLength__, mibAttribute__) \
+    CsrWifiSmeMibGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, mibAttributeLength__, mibAttribute__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibGetNextReqSend
+
+  DESCRIPTION
+    To read a sequence of MIB parameters, for example a table, call this
+    primitive to find the name of the next MIB variable
+
+  PARAMETERS
+    queue              - Message Source Task Queue (Cfm's will be sent to this Queue)
+    mibAttributeLength - Length of mibAttribute
+    mibAttribute       - Points to a VarBind or VarBindList containing the
+                         name(s) of the MIB variable(s) to search from.
+
+*******************************************************************************/
+#define CsrWifiSmeMibGetNextReqCreate(msg__, dst__, src__, mibAttributeLength__, mibAttribute__) \
+    msg__ = (CsrWifiSmeMibGetNextReq *) CsrPmemAlloc(sizeof(CsrWifiSmeMibGetNextReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MIB_GET_NEXT_REQ, dst__, src__); \
+    msg__->mibAttributeLength = (mibAttributeLength__); \
+    msg__->mibAttribute = (mibAttribute__);
+
+#define CsrWifiSmeMibGetNextReqSendTo(dst__, src__, mibAttributeLength__, mibAttribute__) \
+    { \
+        CsrWifiSmeMibGetNextReq *msg__; \
+        CsrWifiSmeMibGetNextReqCreate(msg__, dst__, src__, mibAttributeLength__, mibAttribute__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMibGetNextReqSend(src__, mibAttributeLength__, mibAttribute__) \
+    CsrWifiSmeMibGetNextReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, mibAttributeLength__, mibAttribute__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibGetNextCfmSend
+
+  DESCRIPTION
+    The SME calls this primitive to return the requested MIB name(s).
+    The wireless manager application can then read the value of the MIB
+    variable using CSR_WIFI_SME_MIB_GET_REQ, using the names provided.
+
+  PARAMETERS
+    queue              - Destination Task Queue
+    status             - Reports the result of the request
+    mibAttributeLength - Length of mibAttribute
+    mibAttribute       - Points to a VarBind or VarBindList containing the
+                         name(s) of the MIB variable(s) lexicographically
+                         following the name(s) given in the request
+
+*******************************************************************************/
+#define CsrWifiSmeMibGetNextCfmCreate(msg__, dst__, src__, status__, mibAttributeLength__, mibAttribute__) \
+    msg__ = (CsrWifiSmeMibGetNextCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeMibGetNextCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MIB_GET_NEXT_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->mibAttributeLength = (mibAttributeLength__); \
+    msg__->mibAttribute = (mibAttribute__);
+
+#define CsrWifiSmeMibGetNextCfmSendTo(dst__, src__, status__, mibAttributeLength__, mibAttribute__) \
+    { \
+        CsrWifiSmeMibGetNextCfm *msg__; \
+        CsrWifiSmeMibGetNextCfmCreate(msg__, dst__, src__, status__, mibAttributeLength__, mibAttribute__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMibGetNextCfmSend(dst__, status__, mibAttributeLength__, mibAttribute__) \
+    CsrWifiSmeMibGetNextCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, mibAttributeLength__, mibAttribute__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibGetReqSend
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to retrieve one or
+    more MIB variables.
+
+  PARAMETERS
+    queue              - Message Source Task Queue (Cfm's will be sent to this Queue)
+    mibAttributeLength - Length of mibAttribute
+    mibAttribute       - Points to the VarBind or VarBindList containing the
+                         names of the MIB variables to be retrieved
+
+*******************************************************************************/
+#define CsrWifiSmeMibGetReqCreate(msg__, dst__, src__, mibAttributeLength__, mibAttribute__) \
+    msg__ = (CsrWifiSmeMibGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeMibGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MIB_GET_REQ, dst__, src__); \
+    msg__->mibAttributeLength = (mibAttributeLength__); \
+    msg__->mibAttribute = (mibAttribute__);
+
+#define CsrWifiSmeMibGetReqSendTo(dst__, src__, mibAttributeLength__, mibAttribute__) \
+    { \
+        CsrWifiSmeMibGetReq *msg__; \
+        CsrWifiSmeMibGetReqCreate(msg__, dst__, src__, mibAttributeLength__, mibAttribute__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMibGetReqSend(src__, mibAttributeLength__, mibAttribute__) \
+    CsrWifiSmeMibGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, mibAttributeLength__, mibAttribute__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibSetReqSend
+
+  DESCRIPTION
+    The SME provides raw access to the MIB on the chip, which may be used by
+    some configuration or diagnostic utilities, but is not normally needed by
+    the wireless manager application.
+    The MIB access functions use BER encoded names (OID) of the MIB
+    parameters and BER encoded values, as described in the chip Host
+    Interface Protocol Specification.
+    The MIB parameters are described in 'Wi-Fi 5.0.0 Management Information
+    Base Reference Guide'.
+    The wireless manager application calls this primitive to set one or more
+    MIB variables
+
+  PARAMETERS
+    queue              - Message Source Task Queue (Cfm's will be sent to this Queue)
+    mibAttributeLength - Length of mibAttribute
+    mibAttribute       - Points to the VarBind or VarBindList containing the
+                         names and values of the MIB variables to set
+
+*******************************************************************************/
+#define CsrWifiSmeMibSetReqCreate(msg__, dst__, src__, mibAttributeLength__, mibAttribute__) \
+    msg__ = (CsrWifiSmeMibSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeMibSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MIB_SET_REQ, dst__, src__); \
+    msg__->mibAttributeLength = (mibAttributeLength__); \
+    msg__->mibAttribute = (mibAttribute__);
+
+#define CsrWifiSmeMibSetReqSendTo(dst__, src__, mibAttributeLength__, mibAttribute__) \
+    { \
+        CsrWifiSmeMibSetReq *msg__; \
+        CsrWifiSmeMibSetReqCreate(msg__, dst__, src__, mibAttributeLength__, mibAttribute__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMibSetReqSend(src__, mibAttributeLength__, mibAttribute__) \
+    CsrWifiSmeMibSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, mibAttributeLength__, mibAttribute__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibSetCfmSend
+
+  DESCRIPTION
+    The SME calls the primitive to report the result of the set primitive.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeMibSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeMibSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeMibSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MIB_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeMibSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeMibSetCfm *msg__; \
+        CsrWifiSmeMibSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMibSetCfmSend(dst__, status__) \
+    CsrWifiSmeMibSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMicFailureIndSend
+
+  DESCRIPTION
+    The SME sends this primitive to all the tasks that have registered to
+    receive it whenever the chip firmware reports a MIC failure.
+
+  PARAMETERS
+    queue         - Destination Task Queue
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    secondFailure - TRUE if this indication is for a second failure in 60
+                    seconds
+    count         - The number of MIC failure events since the connection was
+                    established
+    address       - MAC address of the transmitter that caused the MIC failure
+    keyType       - Type of key for which the failure occurred
+
+*******************************************************************************/
+#define CsrWifiSmeMicFailureIndCreate(msg__, dst__, src__, interfaceTag__, secondFailure__, count__, address__, keyType__) \
+    msg__ = (CsrWifiSmeMicFailureInd *) CsrPmemAlloc(sizeof(CsrWifiSmeMicFailureInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MIC_FAILURE_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->secondFailure = (secondFailure__); \
+    msg__->count = (count__); \
+    msg__->address = (address__); \
+    msg__->keyType = (keyType__);
+
+#define CsrWifiSmeMicFailureIndSendTo(dst__, src__, interfaceTag__, secondFailure__, count__, address__, keyType__) \
+    { \
+        CsrWifiSmeMicFailureInd *msg__; \
+        CsrWifiSmeMicFailureIndCreate(msg__, dst__, src__, interfaceTag__, secondFailure__, count__, address__, keyType__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMicFailureIndSend(dst__, interfaceTag__, secondFailure__, count__, address__, keyType__) \
+    CsrWifiSmeMicFailureIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, secondFailure__, count__, address__, keyType__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMulticastAddressReqSend
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to specify the
+    multicast addresses which the chip should recognise. The interface allows
+    the wireless manager application to query, add, remove and flush the
+    multicast addresses for the network interface according to the specified
+    action.
+
+  PARAMETERS
+    queue             - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag      - Interface Identifier; unique identifier of an interface
+    action            - The value of the CsrWifiSmeListAction parameter
+                        instructs the driver to modify or provide the list of
+                        MAC addresses.
+    setAddressesCount - Number of MAC addresses sent with the primitive
+    setAddresses      - Pointer to the list of MAC Addresses sent with the
+                        primitive, set to NULL if none is sent.
+
+*******************************************************************************/
+#define CsrWifiSmeMulticastAddressReqCreate(msg__, dst__, src__, interfaceTag__, action__, setAddressesCount__, setAddresses__) \
+    msg__ = (CsrWifiSmeMulticastAddressReq *) CsrPmemAlloc(sizeof(CsrWifiSmeMulticastAddressReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MULTICAST_ADDRESS_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->action = (action__); \
+    msg__->setAddressesCount = (setAddressesCount__); \
+    msg__->setAddresses = (setAddresses__);
+
+#define CsrWifiSmeMulticastAddressReqSendTo(dst__, src__, interfaceTag__, action__, setAddressesCount__, setAddresses__) \
+    { \
+        CsrWifiSmeMulticastAddressReq *msg__; \
+        CsrWifiSmeMulticastAddressReqCreate(msg__, dst__, src__, interfaceTag__, action__, setAddressesCount__, setAddresses__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMulticastAddressReqSend(src__, interfaceTag__, action__, setAddressesCount__, setAddresses__) \
+    CsrWifiSmeMulticastAddressReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__, action__, setAddressesCount__, setAddresses__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMulticastAddressCfmSend
+
+  DESCRIPTION
+    The SME will call this primitive when the operation is complete. For a
+    GET action, this primitive reports the current list of MAC addresses.
+
+  PARAMETERS
+    queue             - Destination Task Queue
+    interfaceTag      - Interface Identifier; unique identifier of an interface
+    status            - Reports the result of the request
+    action            - Action in the request
+    getAddressesCount - This parameter is only relevant if action is
+                        CSR_WIFI_SME_LIST_ACTION_GET:
+                        number of MAC addresses sent with the primitive
+    getAddresses      - Pointer to the list of MAC Addresses sent with the
+                        primitive, set to NULL if none is sent.
+
+*******************************************************************************/
+#define CsrWifiSmeMulticastAddressCfmCreate(msg__, dst__, src__, interfaceTag__, status__, action__, getAddressesCount__, getAddresses__) \
+    msg__ = (CsrWifiSmeMulticastAddressCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeMulticastAddressCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_MULTICAST_ADDRESS_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->action = (action__); \
+    msg__->getAddressesCount = (getAddressesCount__); \
+    msg__->getAddresses = (getAddresses__);
+
+#define CsrWifiSmeMulticastAddressCfmSendTo(dst__, src__, interfaceTag__, status__, action__, getAddressesCount__, getAddresses__) \
+    { \
+        CsrWifiSmeMulticastAddressCfm *msg__; \
+        CsrWifiSmeMulticastAddressCfmCreate(msg__, dst__, src__, interfaceTag__, status__, action__, getAddressesCount__, getAddresses__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeMulticastAddressCfmSend(dst__, interfaceTag__, status__, action__, getAddressesCount__, getAddresses__) \
+    CsrWifiSmeMulticastAddressCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, action__, getAddressesCount__, getAddresses__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePacketFilterSetReqSend
+
+  DESCRIPTION
+    The wireless manager application should call this primitive to enable or
+    disable filtering of broadcast packets: uninteresting broadcast packets
+    will be dropped by the Wi-Fi chip, instead of passing them up to the
+    host.
+    This has the advantage of saving power in the host application processor
+    as it removes the need to process unwanted packets.
+    All broadcast packets are filtered according to the filter and the filter
+    mode provided, except ARP packets, which are filtered using
+    arpFilterAddress.
+    Filters are not cumulative: only the parameters specified in the most
+    recent successful request are significant.
+    For more information, see 'UniFi Firmware API Specification'.
+
+  PARAMETERS
+    queue            - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag     - Interface Identifier; unique identifier of an interface
+    filterLength     - Length of the filter in bytes.
+                       filterLength=0 disables the filter previously set
+    filter           - Points to the first byte of the filter provided, if any.
+                       This shall include zero or more instance of the
+                       information elements of one of these types
+                         * Traffic Classification (TCLAS) elements
+                         * WMM-SA TCLAS elements
+    mode             - Specifies whether the filter selects or excludes packets
+                       matching the filter
+    arpFilterAddress - IPv4 address to be used for filtering the ARP packets.
+                         * If the specified address is the IPv4 broadcast address
+                           (255.255.255.255), all ARP packets are reported to the
+                           host,
+                         * If the specified address is NOT the IPv4 broadcast
+                           address, only ARP packets with the specified address in
+                           the Source or Target Protocol Address fields are reported
+                           to the host
+
+*******************************************************************************/
+#define CsrWifiSmePacketFilterSetReqCreate(msg__, dst__, src__, interfaceTag__, filterLength__, filter__, mode__, arpFilterAddress__) \
+    msg__ = (CsrWifiSmePacketFilterSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmePacketFilterSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_PACKET_FILTER_SET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->filterLength = (filterLength__); \
+    msg__->filter = (filter__); \
+    msg__->mode = (mode__); \
+    msg__->arpFilterAddress = (arpFilterAddress__);
+
+#define CsrWifiSmePacketFilterSetReqSendTo(dst__, src__, interfaceTag__, filterLength__, filter__, mode__, arpFilterAddress__) \
+    { \
+        CsrWifiSmePacketFilterSetReq *msg__; \
+        CsrWifiSmePacketFilterSetReqCreate(msg__, dst__, src__, interfaceTag__, filterLength__, filter__, mode__, arpFilterAddress__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmePacketFilterSetReqSend(src__, interfaceTag__, filterLength__, filter__, mode__, arpFilterAddress__) \
+    CsrWifiSmePacketFilterSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__, filterLength__, filter__, mode__, arpFilterAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePacketFilterSetCfmSend
+
+  DESCRIPTION
+    The SME calls the primitive to report the result of the set primitive.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmePacketFilterSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmePacketFilterSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmePacketFilterSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_PACKET_FILTER_SET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmePacketFilterSetCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmePacketFilterSetCfm *msg__; \
+        CsrWifiSmePacketFilterSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmePacketFilterSetCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmePacketFilterSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePermanentMacAddressGetReqSend
+
+  DESCRIPTION
+    This primitive retrieves the MAC address stored in EEPROM
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmePermanentMacAddressGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmePermanentMacAddressGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmePermanentMacAddressGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_PERMANENT_MAC_ADDRESS_GET_REQ, dst__, src__);
+
+#define CsrWifiSmePermanentMacAddressGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmePermanentMacAddressGetReq *msg__; \
+        CsrWifiSmePermanentMacAddressGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmePermanentMacAddressGetReqSend(src__) \
+    CsrWifiSmePermanentMacAddressGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePermanentMacAddressGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue               - Destination Task Queue
+    status              - Reports the result of the request
+    permanentMacAddress - MAC address stored in the EEPROM
+
+*******************************************************************************/
+#define CsrWifiSmePermanentMacAddressGetCfmCreate(msg__, dst__, src__, status__, permanentMacAddress__) \
+    msg__ = (CsrWifiSmePermanentMacAddressGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmePermanentMacAddressGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_PERMANENT_MAC_ADDRESS_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->permanentMacAddress = (permanentMacAddress__);
+
+#define CsrWifiSmePermanentMacAddressGetCfmSendTo(dst__, src__, status__, permanentMacAddress__) \
+    { \
+        CsrWifiSmePermanentMacAddressGetCfm *msg__; \
+        CsrWifiSmePermanentMacAddressGetCfmCreate(msg__, dst__, src__, status__, permanentMacAddress__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmePermanentMacAddressGetCfmSend(dst__, status__, permanentMacAddress__) \
+    CsrWifiSmePermanentMacAddressGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, permanentMacAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePmkidCandidateListIndSend
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive it when a new network supporting preauthentication and/or PMK
+    caching is seen.
+
+  PARAMETERS
+    queue                - Destination Task Queue
+    interfaceTag         - Interface Identifier; unique identifier of an
+                           interface
+    pmkidCandidatesCount - Number of PMKID candidates provided
+    pmkidCandidates      - Points to the first PMKID candidate
+
+*******************************************************************************/
+#define CsrWifiSmePmkidCandidateListIndCreate(msg__, dst__, src__, interfaceTag__, pmkidCandidatesCount__, pmkidCandidates__) \
+    msg__ = (CsrWifiSmePmkidCandidateListInd *) CsrPmemAlloc(sizeof(CsrWifiSmePmkidCandidateListInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_PMKID_CANDIDATE_LIST_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->pmkidCandidatesCount = (pmkidCandidatesCount__); \
+    msg__->pmkidCandidates = (pmkidCandidates__);
+
+#define CsrWifiSmePmkidCandidateListIndSendTo(dst__, src__, interfaceTag__, pmkidCandidatesCount__, pmkidCandidates__) \
+    { \
+        CsrWifiSmePmkidCandidateListInd *msg__; \
+        CsrWifiSmePmkidCandidateListIndCreate(msg__, dst__, src__, interfaceTag__, pmkidCandidatesCount__, pmkidCandidates__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmePmkidCandidateListIndSend(dst__, interfaceTag__, pmkidCandidatesCount__, pmkidCandidates__) \
+    CsrWifiSmePmkidCandidateListIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, pmkidCandidatesCount__, pmkidCandidates__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePmkidReqSend
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to request an
+    operation on the SME PMKID list.
+    The action argument specifies the operation to perform.
+    When the connection is complete, the wireless manager application may
+    then send and receive EAPOL packets to complete WPA or WPA2
+    authentication if appropriate.
+    The wireless manager application can then pass the resulting encryption
+    keys using this primitive.
+
+  PARAMETERS
+    queue          - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    action         - The value of the CsrWifiSmeListAction parameter instructs
+                     the driver to modify or provide the list of PMKIDs.
+    setPmkidsCount - Number of PMKIDs sent with the primitive
+    setPmkids      - Pointer to the list of PMKIDs sent with the primitive, set
+                     to NULL if none is sent.
+
+*******************************************************************************/
+#define CsrWifiSmePmkidReqCreate(msg__, dst__, src__, interfaceTag__, action__, setPmkidsCount__, setPmkids__) \
+    msg__ = (CsrWifiSmePmkidReq *) CsrPmemAlloc(sizeof(CsrWifiSmePmkidReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_PMKID_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->action = (action__); \
+    msg__->setPmkidsCount = (setPmkidsCount__); \
+    msg__->setPmkids = (setPmkids__);
+
+#define CsrWifiSmePmkidReqSendTo(dst__, src__, interfaceTag__, action__, setPmkidsCount__, setPmkids__) \
+    { \
+        CsrWifiSmePmkidReq *msg__; \
+        CsrWifiSmePmkidReqCreate(msg__, dst__, src__, interfaceTag__, action__, setPmkidsCount__, setPmkids__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmePmkidReqSend(src__, interfaceTag__, action__, setPmkidsCount__, setPmkids__) \
+    CsrWifiSmePmkidReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__, action__, setPmkidsCount__, setPmkids__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePmkidCfmSend
+
+  DESCRIPTION
+    The SME will call this primitive when the operation is complete. For a
+    GET action, this primitive reports the current list of PMKIDs
+
+  PARAMETERS
+    queue          - Destination Task Queue
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    status         - Reports the result of the request
+    action         - Action in the request
+    getPmkidsCount - This parameter is only relevant if action is
+                     CSR_WIFI_SME_LIST_ACTION_GET:
+                     number of PMKIDs sent with the primitive
+    getPmkids      - Pointer to the list of PMKIDs sent with the primitive, set
+                     to NULL if none is sent.
+
+*******************************************************************************/
+#define CsrWifiSmePmkidCfmCreate(msg__, dst__, src__, interfaceTag__, status__, action__, getPmkidsCount__, getPmkids__) \
+    msg__ = (CsrWifiSmePmkidCfm *) CsrPmemAlloc(sizeof(CsrWifiSmePmkidCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_PMKID_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->action = (action__); \
+    msg__->getPmkidsCount = (getPmkidsCount__); \
+    msg__->getPmkids = (getPmkids__);
+
+#define CsrWifiSmePmkidCfmSendTo(dst__, src__, interfaceTag__, status__, action__, getPmkidsCount__, getPmkids__) \
+    { \
+        CsrWifiSmePmkidCfm *msg__; \
+        CsrWifiSmePmkidCfmCreate(msg__, dst__, src__, interfaceTag__, status__, action__, getPmkidsCount__, getPmkids__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmePmkidCfmSend(dst__, interfaceTag__, status__, action__, getPmkidsCount__, getPmkids__) \
+    CsrWifiSmePmkidCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, action__, getPmkidsCount__, getPmkids__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePowerConfigGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the PowerConfig parameter.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmePowerConfigGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmePowerConfigGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmePowerConfigGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_POWER_CONFIG_GET_REQ, dst__, src__);
+
+#define CsrWifiSmePowerConfigGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmePowerConfigGetReq *msg__; \
+        CsrWifiSmePowerConfigGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmePowerConfigGetReqSend(src__) \
+    CsrWifiSmePowerConfigGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePowerConfigGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue       - Destination Task Queue
+    status      - Reports the result of the request
+    powerConfig - Returns the current parameters for the power configuration of
+                  the firmware
+
+*******************************************************************************/
+#define CsrWifiSmePowerConfigGetCfmCreate(msg__, dst__, src__, status__, powerConfig__) \
+    msg__ = (CsrWifiSmePowerConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmePowerConfigGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_POWER_CONFIG_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->powerConfig = (powerConfig__);
+
+#define CsrWifiSmePowerConfigGetCfmSendTo(dst__, src__, status__, powerConfig__) \
+    { \
+        CsrWifiSmePowerConfigGetCfm *msg__; \
+        CsrWifiSmePowerConfigGetCfmCreate(msg__, dst__, src__, status__, powerConfig__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmePowerConfigGetCfmSend(dst__, status__, powerConfig__) \
+    CsrWifiSmePowerConfigGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, powerConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePowerConfigSetReqSend
+
+  DESCRIPTION
+    This primitive sets the value of the PowerConfig parameter.
+
+  PARAMETERS
+    queue       - Message Source Task Queue (Cfm's will be sent to this Queue)
+    powerConfig - Power saving configuration
+
+*******************************************************************************/
+#define CsrWifiSmePowerConfigSetReqCreate(msg__, dst__, src__, powerConfig__) \
+    msg__ = (CsrWifiSmePowerConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmePowerConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_POWER_CONFIG_SET_REQ, dst__, src__); \
+    msg__->powerConfig = (powerConfig__);
+
+#define CsrWifiSmePowerConfigSetReqSendTo(dst__, src__, powerConfig__) \
+    { \
+        CsrWifiSmePowerConfigSetReq *msg__; \
+        CsrWifiSmePowerConfigSetReqCreate(msg__, dst__, src__, powerConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmePowerConfigSetReqSend(src__, powerConfig__) \
+    CsrWifiSmePowerConfigSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, powerConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePowerConfigSetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmePowerConfigSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmePowerConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmePowerConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_POWER_CONFIG_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmePowerConfigSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmePowerConfigSetCfm *msg__; \
+        CsrWifiSmePowerConfigSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmePowerConfigSetCfmSend(dst__, status__) \
+    CsrWifiSmePowerConfigSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRegulatoryDomainInfoGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the RegulatoryDomainInfo parameter.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeRegulatoryDomainInfoGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeRegulatoryDomainInfoGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeRegulatoryDomainInfoGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_REGULATORY_DOMAIN_INFO_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeRegulatoryDomainInfoGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeRegulatoryDomainInfoGetReq *msg__; \
+        CsrWifiSmeRegulatoryDomainInfoGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeRegulatoryDomainInfoGetReqSend(src__) \
+    CsrWifiSmeRegulatoryDomainInfoGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRegulatoryDomainInfoGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue      - Destination Task Queue
+    status     - Reports the result of the request
+    regDomInfo - Reports information and state related to regulatory domain
+                 operation.
+
+*******************************************************************************/
+#define CsrWifiSmeRegulatoryDomainInfoGetCfmCreate(msg__, dst__, src__, status__, regDomInfo__) \
+    msg__ = (CsrWifiSmeRegulatoryDomainInfoGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeRegulatoryDomainInfoGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_REGULATORY_DOMAIN_INFO_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->regDomInfo = (regDomInfo__);
+
+#define CsrWifiSmeRegulatoryDomainInfoGetCfmSendTo(dst__, src__, status__, regDomInfo__) \
+    { \
+        CsrWifiSmeRegulatoryDomainInfoGetCfm *msg__; \
+        CsrWifiSmeRegulatoryDomainInfoGetCfmCreate(msg__, dst__, src__, status__, regDomInfo__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeRegulatoryDomainInfoGetCfmSend(dst__, status__, regDomInfo__) \
+    CsrWifiSmeRegulatoryDomainInfoGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, regDomInfo__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamCompleteIndSend
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive it whenever it completes an attempt to roam to an AP. If the roam
+    attempt was successful, status will be set to CSR_WIFI_SME_SUCCESS,
+    otherwise it shall be set to the appropriate error code.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the roaming procedure
+
+*******************************************************************************/
+#define CsrWifiSmeRoamCompleteIndCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmeRoamCompleteInd *) CsrPmemAlloc(sizeof(CsrWifiSmeRoamCompleteInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ROAM_COMPLETE_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeRoamCompleteIndSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmeRoamCompleteInd *msg__; \
+        CsrWifiSmeRoamCompleteIndCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeRoamCompleteIndSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmeRoamCompleteIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamStartIndSend
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive it whenever it begins an attempt to roam to an AP.
+    If the wireless manager application connect request specified the SSID
+    and the BSSID was set to the broadcast address (0xFF 0xFF 0xFF 0xFF 0xFF
+    0xFF), the SME monitors the signal quality and maintains a list of
+    candidates to roam to. When the signal quality of the current connection
+    falls below a threshold, and there is a candidate with better quality,
+    the SME will attempt to the candidate AP.
+    If the roaming procedure succeeds, the SME will also issue a Media
+    Connect indication to inform the wireless manager application of the
+    change.
+    NOTE: to prevent the SME from initiating roaming the WMA must specify the
+    BSSID in the connection request; this forces the SME to connect only to
+    that AP.
+    The wireless manager application can obtain statistics for roaming
+    purposes using CSR_WIFI_SME_CONNECTION_QUALITY_IND and
+    CSR_WIFI_SME_CONNECTION_STATS_GET_REQ.
+    When the wireless manager application wishes to roam to another AP, it
+    must issue a connection request specifying the BSSID of the desired AP.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    roamReason   - Indicates the reason for starting the roaming procedure
+    reason80211  - Indicates the reason for deauthentication or disassociation
+
+*******************************************************************************/
+#define CsrWifiSmeRoamStartIndCreate(msg__, dst__, src__, interfaceTag__, roamReason__, reason80211__) \
+    msg__ = (CsrWifiSmeRoamStartInd *) CsrPmemAlloc(sizeof(CsrWifiSmeRoamStartInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ROAM_START_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->roamReason = (roamReason__); \
+    msg__->reason80211 = (reason80211__);
+
+#define CsrWifiSmeRoamStartIndSendTo(dst__, src__, interfaceTag__, roamReason__, reason80211__) \
+    { \
+        CsrWifiSmeRoamStartInd *msg__; \
+        CsrWifiSmeRoamStartIndCreate(msg__, dst__, src__, interfaceTag__, roamReason__, reason80211__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeRoamStartIndSend(dst__, interfaceTag__, roamReason__, reason80211__) \
+    CsrWifiSmeRoamStartIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, roamReason__, reason80211__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamingConfigGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the RoamingConfig parameter.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiSmeRoamingConfigGetReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeRoamingConfigGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeRoamingConfigGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ROAMING_CONFIG_GET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeRoamingConfigGetReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeRoamingConfigGetReq *msg__; \
+        CsrWifiSmeRoamingConfigGetReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeRoamingConfigGetReqSend(src__, interfaceTag__) \
+    CsrWifiSmeRoamingConfigGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamingConfigGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue         - Destination Task Queue
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    status        - Reports the result of the request
+    roamingConfig - Reports the roaming behaviour of the driver and firmware
+
+*******************************************************************************/
+#define CsrWifiSmeRoamingConfigGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, roamingConfig__) \
+    msg__ = (CsrWifiSmeRoamingConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeRoamingConfigGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ROAMING_CONFIG_GET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->roamingConfig = (roamingConfig__);
+
+#define CsrWifiSmeRoamingConfigGetCfmSendTo(dst__, src__, interfaceTag__, status__, roamingConfig__) \
+    { \
+        CsrWifiSmeRoamingConfigGetCfm *msg__; \
+        CsrWifiSmeRoamingConfigGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, roamingConfig__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeRoamingConfigGetCfmSend(dst__, interfaceTag__, status__, roamingConfig__) \
+    CsrWifiSmeRoamingConfigGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, roamingConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamingConfigSetReqSend
+
+  DESCRIPTION
+    This primitive sets the value of the RoamingConfig parameter.
+
+  PARAMETERS
+    queue         - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    roamingConfig - Desired roaming behaviour values
+
+*******************************************************************************/
+#define CsrWifiSmeRoamingConfigSetReqCreate(msg__, dst__, src__, interfaceTag__, roamingConfig__) \
+    msg__ = (CsrWifiSmeRoamingConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeRoamingConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ROAMING_CONFIG_SET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->roamingConfig = (roamingConfig__);
+
+#define CsrWifiSmeRoamingConfigSetReqSendTo(dst__, src__, interfaceTag__, roamingConfig__) \
+    { \
+        CsrWifiSmeRoamingConfigSetReq *msg__; \
+        CsrWifiSmeRoamingConfigSetReqCreate(msg__, dst__, src__, interfaceTag__, roamingConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeRoamingConfigSetReqSend(src__, interfaceTag__, roamingConfig__) \
+    CsrWifiSmeRoamingConfigSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__, roamingConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamingConfigSetCfmSend
+
+  DESCRIPTION
+    This primitive sets the value of the RoamingConfig parameter.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeRoamingConfigSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmeRoamingConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeRoamingConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_ROAMING_CONFIG_SET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeRoamingConfigSetCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmeRoamingConfigSetCfm *msg__; \
+        CsrWifiSmeRoamingConfigSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeRoamingConfigSetCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmeRoamingConfigSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanConfigGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the ScanConfig parameter.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeScanConfigGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeScanConfigGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeScanConfigGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SCAN_CONFIG_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeScanConfigGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeScanConfigGetReq *msg__; \
+        CsrWifiSmeScanConfigGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeScanConfigGetReqSend(src__) \
+    CsrWifiSmeScanConfigGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanConfigGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue      - Destination Task Queue
+    status     - Reports the result of the request
+    scanConfig - Returns the current parameters for the autonomous scanning
+                 behaviour of the firmware
+
+*******************************************************************************/
+#define CsrWifiSmeScanConfigGetCfmCreate(msg__, dst__, src__, status__, scanConfig__) \
+    msg__ = (CsrWifiSmeScanConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeScanConfigGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SCAN_CONFIG_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->scanConfig = (scanConfig__);
+
+#define CsrWifiSmeScanConfigGetCfmSendTo(dst__, src__, status__, scanConfig__) \
+    { \
+        CsrWifiSmeScanConfigGetCfm *msg__; \
+        CsrWifiSmeScanConfigGetCfmCreate(msg__, dst__, src__, status__, scanConfig__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeScanConfigGetCfmSend(dst__, status__, scanConfig__) \
+    CsrWifiSmeScanConfigGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, scanConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanConfigSetReqSend
+
+  DESCRIPTION
+    This primitive sets the value of the ScanConfig parameter.
+    The SME normally configures the firmware to perform autonomous scanning
+    without involving the host.
+    The firmware passes beacon / probe response or indicates loss of beacon
+    on certain changes of state, for example:
+      * A new AP is seen for the first time
+      * An AP is no longer visible
+      * The signal strength of an AP changes by more than a certain amount, as
+        configured by the thresholds in the scanConfig parameter
+    In addition to the autonomous scan, the wireless manager application may
+    request a scan at any time using CSR_WIFI_SME_SCAN_FULL_REQ.
+
+  PARAMETERS
+    queue      - Message Source Task Queue (Cfm's will be sent to this Queue)
+    scanConfig - Reports the configuration for the autonomous scanning behaviour
+                 of the firmware
+
+*******************************************************************************/
+#define CsrWifiSmeScanConfigSetReqCreate(msg__, dst__, src__, scanConfig__) \
+    msg__ = (CsrWifiSmeScanConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeScanConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SCAN_CONFIG_SET_REQ, dst__, src__); \
+    msg__->scanConfig = (scanConfig__);
+
+#define CsrWifiSmeScanConfigSetReqSendTo(dst__, src__, scanConfig__) \
+    { \
+        CsrWifiSmeScanConfigSetReq *msg__; \
+        CsrWifiSmeScanConfigSetReqCreate(msg__, dst__, src__, scanConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeScanConfigSetReqSend(src__, scanConfig__) \
+    CsrWifiSmeScanConfigSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, scanConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanConfigSetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeScanConfigSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeScanConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeScanConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SCAN_CONFIG_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeScanConfigSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeScanConfigSetCfm *msg__; \
+        CsrWifiSmeScanConfigSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeScanConfigSetCfmSend(dst__, status__) \
+    CsrWifiSmeScanConfigSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanFullReqSend
+
+  DESCRIPTION
+    The wireless manager application should call this primitive to request a
+    full scan.
+    Channels are scanned actively or passively according to the requirement
+    set by regulatory domain.
+    If the SME receives this primitive while a full scan is going on, the new
+    request is buffered and it will be served after the current full scan is
+    completed.
+
+  PARAMETERS
+    queue            - Message Source Task Queue (Cfm's will be sent to this Queue)
+    ssidCount        - Number of SSIDs provided.
+                       If it is 0, the SME will attempt to detect any network
+    ssid             - Points to the first SSID provided, if any.
+    bssid            - BSS identifier.
+                       If it is equal to FF-FF-FF-FF-FF, the SME will listen for
+                       messages from any BSS.
+                       If it is different from FF-FF-FF-FF-FF and any SSID is
+                       provided, one SSID must match the network of the BSS.
+    forceScan        - Forces the scan even if the SME is in a state which would
+                       normally prevent it (e.g. autonomous scan is running).
+    bssType          - Type of BSS to scan for
+    scanType         - Type of scan to perform
+    channelListCount - Number of channels provided.
+                       If it is 0, the SME will initiate a scan of all the
+                       supported channels that are permitted by the current
+                       regulatory domain.
+    channelList      - Points to the first channel , or NULL if channelListCount
+                       is zero.
+    probeIeLength    - Length of the information element in bytes to be sent
+                       with the probe message.
+    probeIe          - Points to the first byte of the information element to be
+                       sent with the probe message.
+
+*******************************************************************************/
+#define CsrWifiSmeScanFullReqCreate(msg__, dst__, src__, ssidCount__, ssid__, bssid__, forceScan__, bssType__, scanType__, channelListCount__, channelList__, probeIeLength__, probeIe__) \
+    msg__ = (CsrWifiSmeScanFullReq *) CsrPmemAlloc(sizeof(CsrWifiSmeScanFullReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SCAN_FULL_REQ, dst__, src__); \
+    msg__->ssidCount = (ssidCount__); \
+    msg__->ssid = (ssid__); \
+    msg__->bssid = (bssid__); \
+    msg__->forceScan = (forceScan__); \
+    msg__->bssType = (bssType__); \
+    msg__->scanType = (scanType__); \
+    msg__->channelListCount = (channelListCount__); \
+    msg__->channelList = (channelList__); \
+    msg__->probeIeLength = (probeIeLength__); \
+    msg__->probeIe = (probeIe__);
+
+#define CsrWifiSmeScanFullReqSendTo(dst__, src__, ssidCount__, ssid__, bssid__, forceScan__, bssType__, scanType__, channelListCount__, channelList__, probeIeLength__, probeIe__) \
+    { \
+        CsrWifiSmeScanFullReq *msg__; \
+        CsrWifiSmeScanFullReqCreate(msg__, dst__, src__, ssidCount__, ssid__, bssid__, forceScan__, bssType__, scanType__, channelListCount__, channelList__, probeIeLength__, probeIe__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeScanFullReqSend(src__, ssidCount__, ssid__, bssid__, forceScan__, bssType__, scanType__, channelListCount__, channelList__, probeIeLength__, probeIe__) \
+    CsrWifiSmeScanFullReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, ssidCount__, ssid__, bssid__, forceScan__, bssType__, scanType__, channelListCount__, channelList__, probeIeLength__, probeIe__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanFullCfmSend
+
+  DESCRIPTION
+    The SME calls this primitive when the results from the scan are
+    available.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeScanFullCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeScanFullCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeScanFullCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SCAN_FULL_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeScanFullCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeScanFullCfm *msg__; \
+        CsrWifiSmeScanFullCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeScanFullCfmSend(dst__, status__) \
+    CsrWifiSmeScanFullCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanResultIndSend
+
+  DESCRIPTION
+    The SME sends this primitive to all the tasks that have registered to
+    receive it whenever a scan indication is received from the firmware.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    result - Points to a buffer containing a scan result.
+
+*******************************************************************************/
+#define CsrWifiSmeScanResultIndCreate(msg__, dst__, src__, result__) \
+    msg__ = (CsrWifiSmeScanResultInd *) CsrPmemAlloc(sizeof(CsrWifiSmeScanResultInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SCAN_RESULT_IND, dst__, src__); \
+    msg__->result = (result__);
+
+#define CsrWifiSmeScanResultIndSendTo(dst__, src__, result__) \
+    { \
+        CsrWifiSmeScanResultInd *msg__; \
+        CsrWifiSmeScanResultIndCreate(msg__, dst__, src__, result__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeScanResultIndSend(dst__, result__) \
+    CsrWifiSmeScanResultIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, result__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanResultsFlushReqSend
+
+  DESCRIPTION
+    The Wireless Manager calls this primitive to ask the SME to delete all
+    scan results from its cache, except for the scan result of any currently
+    connected network.
+    As scan results are received by the SME from the firmware, they are
+    cached in the SME memory.
+    Any time the Wireless Manager requests scan results, they are returned
+    from the SME internal cache.
+    For some applications it may be desirable to clear this cache prior to
+    requesting that a scan be performed; this will ensure that the cache then
+    only contains the networks detected in the most recent scan.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeScanResultsFlushReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeScanResultsFlushReq *) CsrPmemAlloc(sizeof(CsrWifiSmeScanResultsFlushReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SCAN_RESULTS_FLUSH_REQ, dst__, src__);
+
+#define CsrWifiSmeScanResultsFlushReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeScanResultsFlushReq *msg__; \
+        CsrWifiSmeScanResultsFlushReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeScanResultsFlushReqSend(src__) \
+    CsrWifiSmeScanResultsFlushReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanResultsFlushCfmSend
+
+  DESCRIPTION
+    The SME will call this primitive when the cache has been cleared.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeScanResultsFlushCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeScanResultsFlushCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeScanResultsFlushCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SCAN_RESULTS_FLUSH_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeScanResultsFlushCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeScanResultsFlushCfm *msg__; \
+        CsrWifiSmeScanResultsFlushCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeScanResultsFlushCfmSend(dst__, status__) \
+    CsrWifiSmeScanResultsFlushCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanResultsGetReqSend
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to retrieve the
+    current set of scan results, either after receiving a successful
+    CSR_WIFI_SME_SCAN_FULL_CFM, or to get autonomous scan results.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeScanResultsGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeScanResultsGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeScanResultsGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SCAN_RESULTS_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeScanResultsGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeScanResultsGetReq *msg__; \
+        CsrWifiSmeScanResultsGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeScanResultsGetReqSend(src__) \
+    CsrWifiSmeScanResultsGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanResultsGetCfmSend
+
+  DESCRIPTION
+    The SME sends this primitive to provide the current set of scan results.
+
+  PARAMETERS
+    queue            - Destination Task Queue
+    status           - Reports the result of the request
+    scanResultsCount - Number of scan results
+    scanResults      - Points to a buffer containing an array of
+                       CsrWifiSmeScanResult structures.
+
+*******************************************************************************/
+#define CsrWifiSmeScanResultsGetCfmCreate(msg__, dst__, src__, status__, scanResultsCount__, scanResults__) \
+    msg__ = (CsrWifiSmeScanResultsGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeScanResultsGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SCAN_RESULTS_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->scanResultsCount = (scanResultsCount__); \
+    msg__->scanResults = (scanResults__);
+
+#define CsrWifiSmeScanResultsGetCfmSendTo(dst__, src__, status__, scanResultsCount__, scanResults__) \
+    { \
+        CsrWifiSmeScanResultsGetCfm *msg__; \
+        CsrWifiSmeScanResultsGetCfmCreate(msg__, dst__, src__, status__, scanResultsCount__, scanResults__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeScanResultsGetCfmSend(dst__, status__, scanResultsCount__, scanResults__) \
+    CsrWifiSmeScanResultsGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, scanResultsCount__, scanResults__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSetReqSend
+
+  DESCRIPTION
+    Used to pass custom data to the SME. Format is the same as 802.11 Info
+    Elements => | Id | Length | Data
+    1) Cmanr Test Mode "Id:0 Length:1 Data:0x00 = OFF 0x01 = ON" "0x00 0x01
+    (0x00|0x01)"
+
+  PARAMETERS
+    queue      - Message Source Task Queue (Cfm's will be sent to this Queue)
+    dataLength - Number of bytes in the buffer pointed to by 'data'
+    data       - Pointer to the buffer containing 'dataLength' bytes
+
+*******************************************************************************/
+#define CsrWifiSmeSetReqCreate(msg__, dst__, src__, dataLength__, data__) \
+    msg__ = (CsrWifiSmeSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SET_REQ, dst__, src__); \
+    msg__->dataLength = (dataLength__); \
+    msg__->data = (data__);
+
+#define CsrWifiSmeSetReqSendTo(dst__, src__, dataLength__, data__) \
+    { \
+        CsrWifiSmeSetReq *msg__; \
+        CsrWifiSmeSetReqCreate(msg__, dst__, src__, dataLength__, data__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeSetReqSend(src__, dataLength__, data__) \
+    CsrWifiSmeSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, dataLength__, data__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeCommonConfigGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the Sme common parameter.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeSmeCommonConfigGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeSmeCommonConfigGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeCommonConfigGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SME_COMMON_CONFIG_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeSmeCommonConfigGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeSmeCommonConfigGetReq *msg__; \
+        CsrWifiSmeSmeCommonConfigGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeSmeCommonConfigGetReqSend(src__) \
+    CsrWifiSmeSmeCommonConfigGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeCommonConfigGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    status       - Reports the result of the request
+    deviceConfig - Configuration options in the SME
+
+*******************************************************************************/
+#define CsrWifiSmeSmeCommonConfigGetCfmCreate(msg__, dst__, src__, status__, deviceConfig__) \
+    msg__ = (CsrWifiSmeSmeCommonConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeCommonConfigGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SME_COMMON_CONFIG_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->deviceConfig = (deviceConfig__);
+
+#define CsrWifiSmeSmeCommonConfigGetCfmSendTo(dst__, src__, status__, deviceConfig__) \
+    { \
+        CsrWifiSmeSmeCommonConfigGetCfm *msg__; \
+        CsrWifiSmeSmeCommonConfigGetCfmCreate(msg__, dst__, src__, status__, deviceConfig__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeSmeCommonConfigGetCfmSend(dst__, status__, deviceConfig__) \
+    CsrWifiSmeSmeCommonConfigGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, deviceConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeCommonConfigSetReqSend
+
+  DESCRIPTION
+    This primitive sets the value of the Sme common.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    deviceConfig - Configuration options in the SME
+
+*******************************************************************************/
+#define CsrWifiSmeSmeCommonConfigSetReqCreate(msg__, dst__, src__, deviceConfig__) \
+    msg__ = (CsrWifiSmeSmeCommonConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeCommonConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SME_COMMON_CONFIG_SET_REQ, dst__, src__); \
+    msg__->deviceConfig = (deviceConfig__);
+
+#define CsrWifiSmeSmeCommonConfigSetReqSendTo(dst__, src__, deviceConfig__) \
+    { \
+        CsrWifiSmeSmeCommonConfigSetReq *msg__; \
+        CsrWifiSmeSmeCommonConfigSetReqCreate(msg__, dst__, src__, deviceConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeSmeCommonConfigSetReqSend(src__, deviceConfig__) \
+    CsrWifiSmeSmeCommonConfigSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, deviceConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeCommonConfigSetCfmSend
+
+  DESCRIPTION
+    Reports the result of the request
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeSmeCommonConfigSetCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeSmeCommonConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeCommonConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SME_COMMON_CONFIG_SET_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeSmeCommonConfigSetCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeSmeCommonConfigSetCfm *msg__; \
+        CsrWifiSmeSmeCommonConfigSetCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeSmeCommonConfigSetCfmSend(dst__, status__) \
+    CsrWifiSmeSmeCommonConfigSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeStaConfigGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the SmeStaConfig parameter.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+#define CsrWifiSmeSmeStaConfigGetReqCreate(msg__, dst__, src__, interfaceTag__) \
+    msg__ = (CsrWifiSmeSmeStaConfigGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeStaConfigGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SME_STA_CONFIG_GET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__);
+
+#define CsrWifiSmeSmeStaConfigGetReqSendTo(dst__, src__, interfaceTag__) \
+    { \
+        CsrWifiSmeSmeStaConfigGetReq *msg__; \
+        CsrWifiSmeSmeStaConfigGetReqCreate(msg__, dst__, src__, interfaceTag__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeSmeStaConfigGetReqSend(src__, interfaceTag__) \
+    CsrWifiSmeSmeStaConfigGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeStaConfigGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+    smeConfig    - Current SME Station Parameters
+
+*******************************************************************************/
+#define CsrWifiSmeSmeStaConfigGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, smeConfig__) \
+    msg__ = (CsrWifiSmeSmeStaConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeStaConfigGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SME_STA_CONFIG_GET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->smeConfig = (smeConfig__);
+
+#define CsrWifiSmeSmeStaConfigGetCfmSendTo(dst__, src__, interfaceTag__, status__, smeConfig__) \
+    { \
+        CsrWifiSmeSmeStaConfigGetCfm *msg__; \
+        CsrWifiSmeSmeStaConfigGetCfmCreate(msg__, dst__, src__, interfaceTag__, status__, smeConfig__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeSmeStaConfigGetCfmSend(dst__, interfaceTag__, status__, smeConfig__) \
+    CsrWifiSmeSmeStaConfigGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, smeConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeStaConfigSetReqSend
+
+  DESCRIPTION
+    This primitive sets the value of the SmeConfig parameter.
+
+  PARAMETERS
+    queue        - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    smeConfig    - SME Station Parameters to be set
+
+*******************************************************************************/
+#define CsrWifiSmeSmeStaConfigSetReqCreate(msg__, dst__, src__, interfaceTag__, smeConfig__) \
+    msg__ = (CsrWifiSmeSmeStaConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeStaConfigSetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SME_STA_CONFIG_SET_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->smeConfig = (smeConfig__);
+
+#define CsrWifiSmeSmeStaConfigSetReqSendTo(dst__, src__, interfaceTag__, smeConfig__) \
+    { \
+        CsrWifiSmeSmeStaConfigSetReq *msg__; \
+        CsrWifiSmeSmeStaConfigSetReqCreate(msg__, dst__, src__, interfaceTag__, smeConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeSmeStaConfigSetReqSend(src__, interfaceTag__, smeConfig__) \
+    CsrWifiSmeSmeStaConfigSetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__, smeConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeStaConfigSetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue        - Destination Task Queue
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeSmeStaConfigSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__) \
+    msg__ = (CsrWifiSmeSmeStaConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeStaConfigSetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_SME_STA_CONFIG_SET_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeSmeStaConfigSetCfmSendTo(dst__, src__, interfaceTag__, status__) \
+    { \
+        CsrWifiSmeSmeStaConfigSetCfm *msg__; \
+        CsrWifiSmeSmeStaConfigSetCfmCreate(msg__, dst__, src__, interfaceTag__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeSmeStaConfigSetCfmSend(dst__, interfaceTag__, status__) \
+    CsrWifiSmeSmeStaConfigSetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeStationMacAddressGetReqSend
+
+  DESCRIPTION
+    This primitives is used to retrieve the current MAC address used by the
+    station.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeStationMacAddressGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeStationMacAddressGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeStationMacAddressGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_STATION_MAC_ADDRESS_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeStationMacAddressGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeStationMacAddressGetReq *msg__; \
+        CsrWifiSmeStationMacAddressGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeStationMacAddressGetReqSend(src__) \
+    CsrWifiSmeStationMacAddressGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeStationMacAddressGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue             - Destination Task Queue
+    status            - Reports the result of the request
+    stationMacAddress - Current MAC address of the station.
+
+*******************************************************************************/
+#define CsrWifiSmeStationMacAddressGetCfmCreate(msg__, dst__, src__, status__, stationMacAddress__) \
+    msg__ = (CsrWifiSmeStationMacAddressGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeStationMacAddressGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_STATION_MAC_ADDRESS_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    CsrMemCpy(msg__->stationMacAddress, (stationMacAddress__), sizeof(CsrWifiMacAddress) * 2);
+
+#define CsrWifiSmeStationMacAddressGetCfmSendTo(dst__, src__, status__, stationMacAddress__) \
+    { \
+        CsrWifiSmeStationMacAddressGetCfm *msg__; \
+        CsrWifiSmeStationMacAddressGetCfmCreate(msg__, dst__, src__, status__, stationMacAddress__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeStationMacAddressGetCfmSend(dst__, status__, stationMacAddress__) \
+    CsrWifiSmeStationMacAddressGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, stationMacAddress__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeTspecReqSend
+
+  DESCRIPTION
+    The wireless manager application should call this primitive to use the
+    TSPEC feature.
+    The chip supports the use of TSPECs and TCLAS for the use of IEEE
+    802.11/WMM Quality of Service features.
+    The API allows the wireless manager application to supply a correctly
+    formatted TSPEC and TCLAS pair to the driver.
+    After performing basic validation, the driver negotiates the installation
+    of the TSPEC with the AP as defined by the 802.11 specification.
+    The driver retains all TSPEC and TCLAS pairs until they are specifically
+    removed.
+    It is not compulsory for a TSPEC to have a TCLAS (NULL is used to
+    indicate that no TCLAS is supplied), while a TCLASS always require a
+    TSPEC.
+    The format of the TSPEC element is specified in 'WMM (including WMM Power
+    Save) Specification - Version 1.1' and 'ANSI/IEEE Std 802.11-REVmb/D3.0'.
+    For more information, see 'UniFi Configuring WMM and WMM-PS'.
+
+  PARAMETERS
+    queue         - Message Source Task Queue (Cfm's will be sent to this Queue)
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    action        - Specifies the action to be carried out on the list of TSPECs.
+                    CSR_WIFI_SME_LIST_ACTION_FLUSH is not applicable here.
+    transactionId - Unique Transaction ID for the TSPEC, as assigned by the
+                    driver
+    strict        - If it set to false, allows the SME to perform automatic
+                    TSPEC negotiation
+    ctrlMask      - Additional TSPEC configuration for CCX.
+                    Set mask with values from CsrWifiSmeTspecCtrl.
+                    CURRENTLY NOT SUPPORTED
+    tspecLength   - Length of the TSPEC.
+    tspec         - Points to the first byte of the TSPEC
+    tclasLength   - Length of the TCLAS.
+                    If it is equal to 0, no TCLASS is provided for the TSPEC
+    tclas         - Points to the first byte of the TCLAS, if any.
+
+*******************************************************************************/
+#define CsrWifiSmeTspecReqCreate(msg__, dst__, src__, interfaceTag__, action__, transactionId__, strict__, ctrlMask__, tspecLength__, tspec__, tclasLength__, tclas__) \
+    msg__ = (CsrWifiSmeTspecReq *) CsrPmemAlloc(sizeof(CsrWifiSmeTspecReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_TSPEC_REQ, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->action = (action__); \
+    msg__->transactionId = (transactionId__); \
+    msg__->strict = (strict__); \
+    msg__->ctrlMask = (ctrlMask__); \
+    msg__->tspecLength = (tspecLength__); \
+    msg__->tspec = (tspec__); \
+    msg__->tclasLength = (tclasLength__); \
+    msg__->tclas = (tclas__);
+
+#define CsrWifiSmeTspecReqSendTo(dst__, src__, interfaceTag__, action__, transactionId__, strict__, ctrlMask__, tspecLength__, tspec__, tclasLength__, tclas__) \
+    { \
+        CsrWifiSmeTspecReq *msg__; \
+        CsrWifiSmeTspecReqCreate(msg__, dst__, src__, interfaceTag__, action__, transactionId__, strict__, ctrlMask__, tspecLength__, tspec__, tclasLength__, tclas__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeTspecReqSend(src__, interfaceTag__, action__, transactionId__, strict__, ctrlMask__, tspecLength__, tspec__, tclasLength__, tclas__) \
+    CsrWifiSmeTspecReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, interfaceTag__, action__, transactionId__, strict__, ctrlMask__, tspecLength__, tspec__, tclasLength__, tclas__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeTspecIndSend
+
+  DESCRIPTION
+    The SME will send this primitive to all the task that have registered to
+    receive it when a status change in the TSPEC occurs.
+
+  PARAMETERS
+    queue           - Destination Task Queue
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    transactionId   - Unique Transaction ID for the TSPEC, as assigned by the
+                      driver
+    tspecResultCode - Specifies the TSPEC operation requested by the peer
+                      station
+    tspecLength     - Length of the TSPEC.
+    tspec           - Points to the first byte of the TSPEC
+
+*******************************************************************************/
+#define CsrWifiSmeTspecIndCreate(msg__, dst__, src__, interfaceTag__, transactionId__, tspecResultCode__, tspecLength__, tspec__) \
+    msg__ = (CsrWifiSmeTspecInd *) CsrPmemAlloc(sizeof(CsrWifiSmeTspecInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_TSPEC_IND, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->transactionId = (transactionId__); \
+    msg__->tspecResultCode = (tspecResultCode__); \
+    msg__->tspecLength = (tspecLength__); \
+    msg__->tspec = (tspec__);
+
+#define CsrWifiSmeTspecIndSendTo(dst__, src__, interfaceTag__, transactionId__, tspecResultCode__, tspecLength__, tspec__) \
+    { \
+        CsrWifiSmeTspecInd *msg__; \
+        CsrWifiSmeTspecIndCreate(msg__, dst__, src__, interfaceTag__, transactionId__, tspecResultCode__, tspecLength__, tspec__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeTspecIndSend(dst__, interfaceTag__, transactionId__, tspecResultCode__, tspecLength__, tspec__) \
+    CsrWifiSmeTspecIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, transactionId__, tspecResultCode__, tspecLength__, tspec__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeTspecCfmSend
+
+  DESCRIPTION
+    The SME calls the primitive to report the result of the TSpec primitive
+    request.
+
+  PARAMETERS
+    queue           - Destination Task Queue
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    status          - Reports the result of the request
+    transactionId   - Unique Transaction ID for the TSPEC, as assigned by the
+                      driver
+    tspecResultCode - Specifies the result of the negotiated TSPEC operation
+    tspecLength     - Length of the TSPEC.
+    tspec           - Points to the first byte of the TSPEC
+
+*******************************************************************************/
+#define CsrWifiSmeTspecCfmCreate(msg__, dst__, src__, interfaceTag__, status__, transactionId__, tspecResultCode__, tspecLength__, tspec__) \
+    msg__ = (CsrWifiSmeTspecCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeTspecCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_TSPEC_CFM, dst__, src__); \
+    msg__->interfaceTag = (interfaceTag__); \
+    msg__->status = (status__); \
+    msg__->transactionId = (transactionId__); \
+    msg__->tspecResultCode = (tspecResultCode__); \
+    msg__->tspecLength = (tspecLength__); \
+    msg__->tspec = (tspec__);
+
+#define CsrWifiSmeTspecCfmSendTo(dst__, src__, interfaceTag__, status__, transactionId__, tspecResultCode__, tspecLength__, tspec__) \
+    { \
+        CsrWifiSmeTspecCfm *msg__; \
+        CsrWifiSmeTspecCfmCreate(msg__, dst__, src__, interfaceTag__, status__, transactionId__, tspecResultCode__, tspecLength__, tspec__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeTspecCfmSend(dst__, interfaceTag__, status__, transactionId__, tspecResultCode__, tspecLength__, tspec__) \
+    CsrWifiSmeTspecCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, interfaceTag__, status__, transactionId__, tspecResultCode__, tspecLength__, tspec__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeVersionsGetReqSend
+
+  DESCRIPTION
+    This primitive gets the value of the Versions parameter.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeVersionsGetReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeVersionsGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeVersionsGetReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_VERSIONS_GET_REQ, dst__, src__);
+
+#define CsrWifiSmeVersionsGetReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeVersionsGetReq *msg__; \
+        CsrWifiSmeVersionsGetReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeVersionsGetReqSend(src__) \
+    CsrWifiSmeVersionsGetReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeVersionsGetCfmSend
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  PARAMETERS
+    queue    - Destination Task Queue
+    status   - Reports the result of the request
+    versions - Version IDs of the product
+
+*******************************************************************************/
+#define CsrWifiSmeVersionsGetCfmCreate(msg__, dst__, src__, status__, versions__) \
+    msg__ = (CsrWifiSmeVersionsGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeVersionsGetCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_VERSIONS_GET_CFM, dst__, src__); \
+    msg__->status = (status__); \
+    msg__->versions = (versions__);
+
+#define CsrWifiSmeVersionsGetCfmSendTo(dst__, src__, status__, versions__) \
+    { \
+        CsrWifiSmeVersionsGetCfm *msg__; \
+        CsrWifiSmeVersionsGetCfmCreate(msg__, dst__, src__, status__, versions__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeVersionsGetCfmSend(dst__, status__, versions__) \
+    CsrWifiSmeVersionsGetCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__, versions__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiFlightmodeReqSend
+
+  DESCRIPTION
+    The wireless manager application may call this primitive on boot-up of
+    the platform to ensure that the chip is placed in a mode that prevents
+    any emission of RF energy.
+    This primitive is an alternative to CSR_WIFI_SME_WIFI_ON_REQ.
+    As in CSR_WIFI_SME_WIFI_ON_REQ, it causes the download of the patch file
+    (if any) and the programming of the initial MIB settings (if supplied by
+    the WMA), but it also ensures that the chip is left in its lowest
+    possible power-mode with the radio subsystems disabled.
+    This feature is useful on platforms where power cannot be removed from
+    the chip (leaving the chip not initialised will cause it to consume more
+    power so calling this function ensures that the chip is initialised into
+    a low power mode but without entering a state where it could emit any RF
+    energy).
+    NOTE: this primitive does not cause the Wi-Fi to change state: Wi-Fi
+    stays conceptually off. Configuration primitives can be sent after
+    CSR_WIFI_SME_WIFI_FLIGHTMODE_REQ and the configuration will be maintained.
+    Requests that require the state of the Wi-Fi to be ON will return
+    CSR_WIFI_SME_STATUS_WIFI_OFF in their confirms.
+
+  PARAMETERS
+    queue         - Message Source Task Queue (Cfm's will be sent to this Queue)
+    address       - Optionally specifies a station MAC address.
+                    In normal use, the manager should set the address to 0xFF
+                    0xFF 0xFF 0xFF 0xFF 0xFF, which will cause the chip to use
+                    the MAC address in the MIB.
+    mibFilesCount - Number of provided data blocks with initial MIB values
+    mibFiles      - Points to the first data block with initial MIB values.
+                    These data blocks are typically the contents of the provided
+                    files ufmib.dat and localmib.dat, available from the host
+                    file system, if they exist.
+                    These files typically contain radio tuning and calibration
+                    values.
+                    More values can be created using the Host Tools.
+
+*******************************************************************************/
+#define CsrWifiSmeWifiFlightmodeReqCreate(msg__, dst__, src__, address__, mibFilesCount__, mibFiles__) \
+    msg__ = (CsrWifiSmeWifiFlightmodeReq *) CsrPmemAlloc(sizeof(CsrWifiSmeWifiFlightmodeReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_WIFI_FLIGHTMODE_REQ, dst__, src__); \
+    msg__->address = (address__); \
+    msg__->mibFilesCount = (mibFilesCount__); \
+    msg__->mibFiles = (mibFiles__);
+
+#define CsrWifiSmeWifiFlightmodeReqSendTo(dst__, src__, address__, mibFilesCount__, mibFiles__) \
+    { \
+        CsrWifiSmeWifiFlightmodeReq *msg__; \
+        CsrWifiSmeWifiFlightmodeReqCreate(msg__, dst__, src__, address__, mibFilesCount__, mibFiles__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeWifiFlightmodeReqSend(src__, address__, mibFilesCount__, mibFiles__) \
+    CsrWifiSmeWifiFlightmodeReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, address__, mibFilesCount__, mibFiles__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiFlightmodeCfmSend
+
+  DESCRIPTION
+    The SME calls this primitive when the chip is initialised for low power
+    mode and with the radio subsystem disabled. To leave flight mode, and
+    enable Wi-Fi, the wireless manager application should call
+    CSR_WIFI_SME_WIFI_ON_REQ.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeWifiFlightmodeCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeWifiFlightmodeCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeWifiFlightmodeCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_WIFI_FLIGHTMODE_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeWifiFlightmodeCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeWifiFlightmodeCfm *msg__; \
+        CsrWifiSmeWifiFlightmodeCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeWifiFlightmodeCfmSend(dst__, status__) \
+    CsrWifiSmeWifiFlightmodeCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOffReqSend
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to turn off the
+    chip, thus saving power when Wi-Fi is not in use.
+
+  PARAMETERS
+    queue  - Message Source Task Queue (Cfm's will be sent to this Queue)
+
+*******************************************************************************/
+#define CsrWifiSmeWifiOffReqCreate(msg__, dst__, src__) \
+    msg__ = (CsrWifiSmeWifiOffReq *) CsrPmemAlloc(sizeof(CsrWifiSmeWifiOffReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_WIFI_OFF_REQ, dst__, src__);
+
+#define CsrWifiSmeWifiOffReqSendTo(dst__, src__) \
+    { \
+        CsrWifiSmeWifiOffReq *msg__; \
+        CsrWifiSmeWifiOffReqCreate(msg__, dst__, src__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeWifiOffReqSend(src__) \
+    CsrWifiSmeWifiOffReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOffIndSend
+
+  DESCRIPTION
+    The SME sends this primitive to all the tasks that have registered to
+    receive it to report that the chip has been turned off.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    reason - Indicates the reason why the Wi-Fi has been switched off.
+
+*******************************************************************************/
+#define CsrWifiSmeWifiOffIndCreate(msg__, dst__, src__, reason__) \
+    msg__ = (CsrWifiSmeWifiOffInd *) CsrPmemAlloc(sizeof(CsrWifiSmeWifiOffInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_WIFI_OFF_IND, dst__, src__); \
+    msg__->reason = (reason__);
+
+#define CsrWifiSmeWifiOffIndSendTo(dst__, src__, reason__) \
+    { \
+        CsrWifiSmeWifiOffInd *msg__; \
+        CsrWifiSmeWifiOffIndCreate(msg__, dst__, src__, reason__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeWifiOffIndSend(dst__, reason__) \
+    CsrWifiSmeWifiOffIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, reason__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOffCfmSend
+
+  DESCRIPTION
+    After receiving CSR_WIFI_SME_WIFI_OFF_REQ, if the chip is connected to a
+    network, the SME will perform a disconnect operation, will send a
+    CSR_WIFI_SME_MEDIA_STATUS_IND with
+    CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED, and then will call
+    CSR_WIFI_SME_WIFI_OFF_CFM when the chip is off.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeWifiOffCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeWifiOffCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeWifiOffCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_WIFI_OFF_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeWifiOffCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeWifiOffCfm *msg__; \
+        CsrWifiSmeWifiOffCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeWifiOffCfmSend(dst__, status__) \
+    CsrWifiSmeWifiOffCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOnReqSend
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to turn on the
+    Wi-Fi chip.
+    If the Wi-Fi chip is currently off, the SME turns the Wi-Fi chip on,
+    downloads the patch file (if any), and programs the initial MIB settings
+    (if supplied by the WMA).
+    The patch file is not provided with the SME API; its downloading is
+    automatic and handled internally by the system.
+    The MIB settings, when provided, override the default values that the
+    firmware loads from EEPROM.
+    If the Wi-Fi chip is already on, the SME takes no action and returns a
+    successful status in the confirm.
+
+  PARAMETERS
+    queue         - Message Source Task Queue (Cfm's will be sent to this Queue)
+    address       - Optionally specifies a station MAC address.
+                    In normal use, the manager should set the address to 0xFF
+                    0xFF 0xFF 0xFF 0xFF 0xFF, which will cause the chip to use
+                    the MAC address in the MIB
+    mibFilesCount - Number of provided data blocks with initial MIB values
+    mibFiles      - Points to the first data block with initial MIB values.
+                    These data blocks are typically the contents of the provided
+                    files ufmib.dat and localmib.dat, available from the host
+                    file system, if they exist.
+                    These files typically contain radio tuning and calibration
+                    values.
+                    More values can be created using the Host Tools.
+
+*******************************************************************************/
+#define CsrWifiSmeWifiOnReqCreate(msg__, dst__, src__, address__, mibFilesCount__, mibFiles__) \
+    msg__ = (CsrWifiSmeWifiOnReq *) CsrPmemAlloc(sizeof(CsrWifiSmeWifiOnReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_WIFI_ON_REQ, dst__, src__); \
+    msg__->address = (address__); \
+    msg__->mibFilesCount = (mibFilesCount__); \
+    msg__->mibFiles = (mibFiles__);
+
+#define CsrWifiSmeWifiOnReqSendTo(dst__, src__, address__, mibFilesCount__, mibFiles__) \
+    { \
+        CsrWifiSmeWifiOnReq *msg__; \
+        CsrWifiSmeWifiOnReqCreate(msg__, dst__, src__, address__, mibFilesCount__, mibFiles__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeWifiOnReqSend(src__, address__, mibFilesCount__, mibFiles__) \
+    CsrWifiSmeWifiOnReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, address__, mibFilesCount__, mibFiles__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOnIndSend
+
+  DESCRIPTION
+    The SME sends this primitive to all tasks that have registered to receive
+    it once the chip becomes available and ready to use.
+
+  PARAMETERS
+    queue   - Destination Task Queue
+    address - Current MAC address
+
+*******************************************************************************/
+#define CsrWifiSmeWifiOnIndCreate(msg__, dst__, src__, address__) \
+    msg__ = (CsrWifiSmeWifiOnInd *) CsrPmemAlloc(sizeof(CsrWifiSmeWifiOnInd)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_WIFI_ON_IND, dst__, src__); \
+    msg__->address = (address__);
+
+#define CsrWifiSmeWifiOnIndSendTo(dst__, src__, address__) \
+    { \
+        CsrWifiSmeWifiOnInd *msg__; \
+        CsrWifiSmeWifiOnIndCreate(msg__, dst__, src__, address__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeWifiOnIndSend(dst__, address__) \
+    CsrWifiSmeWifiOnIndSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, address__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOnCfmSend
+
+  DESCRIPTION
+    The SME sends this primitive to the task that has sent the request once
+    the chip has been initialised and is available for use.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Reports the result of the request
+
+*******************************************************************************/
+#define CsrWifiSmeWifiOnCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeWifiOnCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeWifiOnCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_WIFI_ON_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeWifiOnCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeWifiOnCfm *msg__; \
+        CsrWifiSmeWifiOnCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeWifiOnCfmSend(dst__, status__) \
+    CsrWifiSmeWifiOnCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsConfigurationReqSend
+
+  DESCRIPTION
+    This primitive passes the WPS information for the device to SME. This may
+    be accepted only if no interface is active.
+
+  PARAMETERS
+    queue     - Message Source Task Queue (Cfm's will be sent to this Queue)
+    wpsConfig - WPS config.
+
+*******************************************************************************/
+#define CsrWifiSmeWpsConfigurationReqCreate(msg__, dst__, src__, wpsConfig__) \
+    msg__ = (CsrWifiSmeWpsConfigurationReq *) CsrPmemAlloc(sizeof(CsrWifiSmeWpsConfigurationReq)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_WPS_CONFIGURATION_REQ, dst__, src__); \
+    msg__->wpsConfig = (wpsConfig__);
+
+#define CsrWifiSmeWpsConfigurationReqSendTo(dst__, src__, wpsConfig__) \
+    { \
+        CsrWifiSmeWpsConfigurationReq *msg__; \
+        CsrWifiSmeWpsConfigurationReqCreate(msg__, dst__, src__, wpsConfig__); \
+        CsrMsgTransport(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeWpsConfigurationReqSend(src__, wpsConfig__) \
+    CsrWifiSmeWpsConfigurationReqSendTo(CSR_WIFI_SME_LIB_DESTINATION_QUEUE, src__, wpsConfig__)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsConfigurationCfmSend
+
+  DESCRIPTION
+    Confirm.
+
+  PARAMETERS
+    queue  - Destination Task Queue
+    status - Status of the request.
+
+*******************************************************************************/
+#define CsrWifiSmeWpsConfigurationCfmCreate(msg__, dst__, src__, status__) \
+    msg__ = (CsrWifiSmeWpsConfigurationCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeWpsConfigurationCfm)); \
+    CsrWifiFsmEventInit(&msg__->common, CSR_WIFI_SME_PRIM, CSR_WIFI_SME_WPS_CONFIGURATION_CFM, dst__, src__); \
+    msg__->status = (status__);
+
+#define CsrWifiSmeWpsConfigurationCfmSendTo(dst__, src__, status__) \
+    { \
+        CsrWifiSmeWpsConfigurationCfm *msg__; \
+        CsrWifiSmeWpsConfigurationCfmCreate(msg__, dst__, src__, status__); \
+        CsrSchedMessagePut(dst__, CSR_WIFI_SME_PRIM, msg__); \
+    }
+
+#define CsrWifiSmeWpsConfigurationCfmSend(dst__, status__) \
+    CsrWifiSmeWpsConfigurationCfmSendTo(dst__, CSR_WIFI_SME_IFACEQUEUE, status__)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_SME_LIB_H__ */
diff --git a/drivers/staging/csr/csr_wifi_sme_prim.h b/drivers/staging/csr/csr_wifi_sme_prim.h
new file mode 100644
index 0000000..8ffa50a
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_prim.h
@@ -0,0 +1,6519 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_SME_PRIM_H__
+#define CSR_WIFI_SME_PRIM_H__
+
+#include "csr_types.h"
+#include "csr_prim_defs.h"
+#include "csr_sched.h"
+#include "csr_wifi_common.h"
+#include "csr_result.h"
+#include "csr_wifi_fsm_event.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CSR_WIFI_SME_PRIM                                               (0x0404)
+
+typedef CsrPrim CsrWifiSmePrim;
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSme80211NetworkType
+
+  DESCRIPTION
+    Indicates the physical layer of the network
+
+ VALUES
+    CSR_WIFI_SME_80211_NETWORK_TYPE_DS
+                   - Direct-sequence spread spectrum
+    CSR_WIFI_SME_80211_NETWORK_TYPE_OFDM24
+                   - Orthogonal Frequency Division Multiplexing at 2.4 GHz
+    CSR_WIFI_SME_80211_NETWORK_TYPE_OFDM5
+                   - Orthogonal Frequency Division Multiplexing at 5 GHz
+    CSR_WIFI_SME_80211_NETWORK_TYPE_AUTO
+                   - Automatic
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSme80211NetworkType;
+#define CSR_WIFI_SME_80211_NETWORK_TYPE_DS       ((CsrWifiSme80211NetworkType) 0x00)
+#define CSR_WIFI_SME_80211_NETWORK_TYPE_OFDM24   ((CsrWifiSme80211NetworkType) 0x01)
+#define CSR_WIFI_SME_80211_NETWORK_TYPE_OFDM5    ((CsrWifiSme80211NetworkType) 0x02)
+#define CSR_WIFI_SME_80211_NETWORK_TYPE_AUTO     ((CsrWifiSme80211NetworkType) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSme80211PrivacyMode
+
+  DESCRIPTION
+    Bits to enable or disable the privacy mode
+
+ VALUES
+    CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED
+                   - Privacy mode is enabled: use of WEP for confidentiality is
+                     required.
+    CSR_WIFI_SME_80211_PRIVACY_MODE_ENABLED
+                   - Privacy mode is disabled
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSme80211PrivacyMode;
+#define CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED   ((CsrWifiSme80211PrivacyMode) 0x00)
+#define CSR_WIFI_SME_80211_PRIVACY_MODE_ENABLED    ((CsrWifiSme80211PrivacyMode) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSme80211dTrustLevel
+
+  DESCRIPTION
+    Level of trust for the information coming from the network
+
+ VALUES
+    CSR_WIFI_SME_80211D_TRUST_LEVEL_STRICT
+                   - Start with passive scanning and only accept country IE for
+                     updating channel lists
+    CSR_WIFI_SME_80211D_TRUST_LEVEL_ADJUNCT
+                   - As above plus accept adjunct technology location
+                     information
+    CSR_WIFI_SME_80211D_TRUST_LEVEL_BSS
+                   - As above accept plus receiving channel from infrastructure
+                     networks
+    CSR_WIFI_SME_80211D_TRUST_LEVEL_IBSS
+                   - As above accept plus receiving channel from the ad hoc
+                     networks
+    CSR_WIFI_SME_80211D_TRUST_LEVEL_MIB
+                   - Start with active scanning with list of active channels
+                     from the MIB and accept as above
+    CSR_WIFI_SME_80211D_TRUST_LEVEL_DISABLED
+                   - Start with active scanning with list of active channels
+                     from the MIB and ignore any channel information from the
+                     network
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSme80211dTrustLevel;
+#define CSR_WIFI_SME_80211D_TRUST_LEVEL_STRICT     ((CsrWifiSme80211dTrustLevel) 0x01)
+#define CSR_WIFI_SME_80211D_TRUST_LEVEL_ADJUNCT    ((CsrWifiSme80211dTrustLevel) 0x02)
+#define CSR_WIFI_SME_80211D_TRUST_LEVEL_BSS        ((CsrWifiSme80211dTrustLevel) 0x03)
+#define CSR_WIFI_SME_80211D_TRUST_LEVEL_IBSS       ((CsrWifiSme80211dTrustLevel) 0x04)
+#define CSR_WIFI_SME_80211D_TRUST_LEVEL_MIB        ((CsrWifiSme80211dTrustLevel) 0x05)
+#define CSR_WIFI_SME_80211D_TRUST_LEVEL_DISABLED   ((CsrWifiSme80211dTrustLevel) 0x06)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAmpStatus
+
+  DESCRIPTION
+    AMP Current Status
+
+ VALUES
+    CSR_WIFI_SME_AMP_ACTIVE   - AMP ACTIVE.
+    CSR_WIFI_SME_AMP_INACTIVE - AMP INACTIVE
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeAmpStatus;
+#define CSR_WIFI_SME_AMP_ACTIVE     ((CsrWifiSmeAmpStatus) 0x00)
+#define CSR_WIFI_SME_AMP_INACTIVE   ((CsrWifiSmeAmpStatus) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAuthMode
+
+  DESCRIPTION
+    Define bits for CsrWifiSmeAuthMode
+
+ VALUES
+    CSR_WIFI_SME_AUTH_MODE_80211_OPEN
+                   - Connects to an open system network (i.e. no authentication,
+                     no encryption) or to a WEP enabled network.
+    CSR_WIFI_SME_AUTH_MODE_80211_SHARED
+                   - Connect to a WEP enabled network.
+    CSR_WIFI_SME_AUTH_MODE_8021X_WPA
+                   - Connects to a WPA Enterprise enabled network.
+    CSR_WIFI_SME_AUTH_MODE_8021X_WPAPSK
+                   - Connects to a WPA with Pre-Shared Key enabled network.
+    CSR_WIFI_SME_AUTH_MODE_8021X_WPA2
+                   - Connects to a WPA2 Enterprise enabled network.
+    CSR_WIFI_SME_AUTH_MODE_8021X_WPA2PSK
+                   - Connects to a WPA2 with Pre-Shared Key enabled network.
+    CSR_WIFI_SME_AUTH_MODE_8021X_CCKM
+                   - Connects to a CCKM enabled network.
+    CSR_WIFI_SME_AUTH_MODE_WAPI_WAI
+                   - Connects to a WAPI Enterprise enabled network.
+    CSR_WIFI_SME_AUTH_MODE_WAPI_WAIPSK
+                   - Connects to a WAPI with Pre-Shared Key enabled network.
+    CSR_WIFI_SME_AUTH_MODE_8021X_OTHER1X
+                   - For future use.
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeAuthMode;
+#define CSR_WIFI_SME_AUTH_MODE_80211_OPEN      ((CsrWifiSmeAuthMode) 0x0001)
+#define CSR_WIFI_SME_AUTH_MODE_80211_SHARED    ((CsrWifiSmeAuthMode) 0x0002)
+#define CSR_WIFI_SME_AUTH_MODE_8021X_WPA       ((CsrWifiSmeAuthMode) 0x0004)
+#define CSR_WIFI_SME_AUTH_MODE_8021X_WPAPSK    ((CsrWifiSmeAuthMode) 0x0008)
+#define CSR_WIFI_SME_AUTH_MODE_8021X_WPA2      ((CsrWifiSmeAuthMode) 0x0010)
+#define CSR_WIFI_SME_AUTH_MODE_8021X_WPA2PSK   ((CsrWifiSmeAuthMode) 0x0020)
+#define CSR_WIFI_SME_AUTH_MODE_8021X_CCKM      ((CsrWifiSmeAuthMode) 0x0040)
+#define CSR_WIFI_SME_AUTH_MODE_WAPI_WAI        ((CsrWifiSmeAuthMode) 0x0080)
+#define CSR_WIFI_SME_AUTH_MODE_WAPI_WAIPSK     ((CsrWifiSmeAuthMode) 0x0100)
+#define CSR_WIFI_SME_AUTH_MODE_8021X_OTHER1X   ((CsrWifiSmeAuthMode) 0x0200)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeBasicUsability
+
+  DESCRIPTION
+    Indicates the usability level of a channel
+
+ VALUES
+    CSR_WIFI_SME_BASIC_USABILITY_UNUSABLE
+                   - Not usable; connection not recommended
+    CSR_WIFI_SME_BASIC_USABILITY_POOR
+                   - Poor quality; connect only if nothing better is available
+    CSR_WIFI_SME_BASIC_USABILITY_SATISFACTORY
+                   - Quality is satisfactory
+    CSR_WIFI_SME_BASIC_USABILITY_NOT_CONNECTED
+                   - Not connected
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeBasicUsability;
+#define CSR_WIFI_SME_BASIC_USABILITY_UNUSABLE        ((CsrWifiSmeBasicUsability) 0x00)
+#define CSR_WIFI_SME_BASIC_USABILITY_POOR            ((CsrWifiSmeBasicUsability) 0x01)
+#define CSR_WIFI_SME_BASIC_USABILITY_SATISFACTORY    ((CsrWifiSmeBasicUsability) 0x02)
+#define CSR_WIFI_SME_BASIC_USABILITY_NOT_CONNECTED   ((CsrWifiSmeBasicUsability) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeBssType
+
+  DESCRIPTION
+    Indicates the BSS type
+
+ VALUES
+    CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE
+                   - Infrastructure BSS.
+    CSR_WIFI_SME_BSS_TYPE_ADHOC
+                   - Ad hoc or Independent BSS.
+    CSR_WIFI_SME_BSS_TYPE_ANY_BSS
+                   - Specifies any type of BSS
+    CSR_WIFI_SME_BSS_TYPE_P2P
+                   - Specifies P2P
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeBssType;
+#define CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE   ((CsrWifiSmeBssType) 0x00)
+#define CSR_WIFI_SME_BSS_TYPE_ADHOC            ((CsrWifiSmeBssType) 0x01)
+#define CSR_WIFI_SME_BSS_TYPE_ANY_BSS          ((CsrWifiSmeBssType) 0x02)
+#define CSR_WIFI_SME_BSS_TYPE_P2P              ((CsrWifiSmeBssType) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexScheme
+
+  DESCRIPTION
+    Options for the coexistence signalling
+    Same as MibValues
+
+ VALUES
+    CSR_WIFI_SME_COEX_SCHEME_DISABLED
+                   - The coexistence signalling is disabled
+    CSR_WIFI_SME_COEX_SCHEME_CSR
+                   - Basic CSR coexistence signalling
+    CSR_WIFI_SME_COEX_SCHEME_CSR_CHANNEL
+                   - Full CSR coexistence signalling
+    CSR_WIFI_SME_COEX_SCHEME_PTA
+                   - Packet Traffic Arbitrator coexistence signalling
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeCoexScheme;
+#define CSR_WIFI_SME_COEX_SCHEME_DISABLED      ((CsrWifiSmeCoexScheme) 0x00)
+#define CSR_WIFI_SME_COEX_SCHEME_CSR           ((CsrWifiSmeCoexScheme) 0x01)
+#define CSR_WIFI_SME_COEX_SCHEME_CSR_CHANNEL   ((CsrWifiSmeCoexScheme) 0x02)
+#define CSR_WIFI_SME_COEX_SCHEME_PTA           ((CsrWifiSmeCoexScheme) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeControlIndication
+
+  DESCRIPTION
+    Indicates the reason why the Wi-Fi has been switched off.
+    The values of this type are used across the NME/SME/Router API's and they
+    must be kept consistent with the corresponding types in the .xml of the
+    ottherinterfaces
+
+ VALUES
+    CSR_WIFI_SME_CONTROL_INDICATION_ERROR
+                   - An unrecoverable error (for example, an unrecoverable SDIO
+                     error) has occurred.
+                     The wireless manager application should reinitialise the
+                     chip by calling CSR_WIFI_SME_WIFI_ON_REQ.
+    CSR_WIFI_SME_CONTROL_INDICATION_EXIT
+                   - The chip became unavailable due to an external action, for
+                     example, when a plug-in card is ejected or the driver is
+                     unloaded.
+    CSR_WIFI_SME_CONTROL_INDICATION_USER_REQUESTED
+                   - The Wi-Fi has been switched off as the wireless manager
+                     application has sent CSR_WIFI_SME_WIFI_OFF_REQ
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeControlIndication;
+#define CSR_WIFI_SME_CONTROL_INDICATION_ERROR            ((CsrWifiSmeControlIndication) 0x01)
+#define CSR_WIFI_SME_CONTROL_INDICATION_EXIT             ((CsrWifiSmeControlIndication) 0x02)
+#define CSR_WIFI_SME_CONTROL_INDICATION_USER_REQUESTED   ((CsrWifiSmeControlIndication) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCtsProtectionType
+
+  DESCRIPTION
+    SME CTS Protection Types
+
+ VALUES
+    CSR_WIFI_SME_CTS_PROTECTION_AUTOMATIC
+                   - AP CTS Protection automatic based on non-ERP station in own
+                     BSS or neighbouring BSS on the same channel based on OLBC.
+                     This requires monitoring of beacons from other APs.
+    CSR_WIFI_SME_CTS_PROTECTION_FORCE_ENABLED
+                   - AP CTS Protection Force enabled
+    CSR_WIFI_SME_CTS_PROTECTION_FORCE_DISABLED
+                   - AP CTS Protection Force disabled.
+    CSR_WIFI_SME_CTS_PROTECTION_AUTOMATIC_NO_OLBC
+                   - AP CTS Protection automatic without considering OLBC but
+                     considering non-ERP station in the own BSS Valid only if AP
+                     is configured to work in 802.11bg or 802.11g mode otherwise
+                     this option specifies the same behaviour as AUTOMATIC
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeCtsProtectionType;
+#define CSR_WIFI_SME_CTS_PROTECTION_AUTOMATIC           ((CsrWifiSmeCtsProtectionType) 0x00)
+#define CSR_WIFI_SME_CTS_PROTECTION_FORCE_ENABLED       ((CsrWifiSmeCtsProtectionType) 0x01)
+#define CSR_WIFI_SME_CTS_PROTECTION_FORCE_DISABLED      ((CsrWifiSmeCtsProtectionType) 0x02)
+#define CSR_WIFI_SME_CTS_PROTECTION_AUTOMATIC_NO_OLBC   ((CsrWifiSmeCtsProtectionType) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeD3AutoScanMode
+
+  DESCRIPTION
+    Autonomous scan status while in D3 suspended period
+
+ VALUES
+    CSR_WIFI_SME_D3AUTO_SCAN_MODE_PSON
+                   - Autonomous scan stays on
+    CSR_WIFI_SME_D3AUTO_SCAN_MODE_PSOFF
+                   - Autonomous scan is switched off
+    CSR_WIFI_SME_D3AUTO_SCAN_MODE_PSAUTO
+                   - Automatically select autoscanning behaviour.
+                     CURRENTLY NOT SUPPORTED
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeD3AutoScanMode;
+#define CSR_WIFI_SME_D3AUTO_SCAN_MODE_PSON     ((CsrWifiSmeD3AutoScanMode) 0x00)
+#define CSR_WIFI_SME_D3AUTO_SCAN_MODE_PSOFF    ((CsrWifiSmeD3AutoScanMode) 0x01)
+#define CSR_WIFI_SME_D3AUTO_SCAN_MODE_PSAUTO   ((CsrWifiSmeD3AutoScanMode) 0x02)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeEncryption
+
+  DESCRIPTION
+    Defines bits for CsrWifiSmeEncryption
+    For a WEP enabled network, the caller must specify the correct
+    combination of flags in the encryptionModeMask.
+
+ VALUES
+    CSR_WIFI_SME_ENCRYPTION_CIPHER_NONE
+                   - No encryption set
+    CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP40
+                   - Selects 40 byte key WEP for unicast communication
+    CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP104
+                   - Selects 104 byte key WEP for unicast communication
+    CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_TKIP
+                   - Selects TKIP for unicast communication
+    CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_CCMP
+                   - Selects CCMP for unicast communication
+    CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_SMS4
+                   - Selects SMS4 for unicast communication
+    CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP40
+                   - Selects 40 byte key WEP for broadcast messages
+    CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP104
+                   - Selects 104 byte key WEP for broadcast messages
+    CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_TKIP
+                   - Selects a TKIP for broadcast messages
+    CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_CCMP
+                   - Selects CCMP for broadcast messages
+    CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_SMS4
+                   - Selects SMS4 for broadcast messages
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeEncryption;
+#define CSR_WIFI_SME_ENCRYPTION_CIPHER_NONE              ((CsrWifiSmeEncryption) 0x0000)
+#define CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP40    ((CsrWifiSmeEncryption) 0x0001)
+#define CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP104   ((CsrWifiSmeEncryption) 0x0002)
+#define CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_TKIP     ((CsrWifiSmeEncryption) 0x0004)
+#define CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_CCMP     ((CsrWifiSmeEncryption) 0x0008)
+#define CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_SMS4     ((CsrWifiSmeEncryption) 0x0010)
+#define CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP40       ((CsrWifiSmeEncryption) 0x0020)
+#define CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP104      ((CsrWifiSmeEncryption) 0x0040)
+#define CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_TKIP        ((CsrWifiSmeEncryption) 0x0080)
+#define CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_CCMP        ((CsrWifiSmeEncryption) 0x0100)
+#define CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_SMS4        ((CsrWifiSmeEncryption) 0x0200)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeFirmwareDriverInterface
+
+  DESCRIPTION
+    Type of communication between Host and Firmware
+
+ VALUES
+    CSR_WIFI_SME_FIRMWARE_DRIVER_INTERFACE_UNIT_DATA_INTERFACE
+                   - No preformated header. NOT SUPPORTED in the current release
+    CSR_WIFI_SME_FIRMWARE_DRIVER_INTERFACE_PACKET_INTERFACE
+                   - Preformated IEEE 802.11 header for user plane
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeFirmwareDriverInterface;
+#define CSR_WIFI_SME_FIRMWARE_DRIVER_INTERFACE_UNIT_DATA_INTERFACE   ((CsrWifiSmeFirmwareDriverInterface) 0x00)
+#define CSR_WIFI_SME_FIRMWARE_DRIVER_INTERFACE_PACKET_INTERFACE      ((CsrWifiSmeFirmwareDriverInterface) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeHostPowerMode
+
+  DESCRIPTION
+    Defines the power mode
+
+ VALUES
+    CSR_WIFI_SME_HOST_POWER_MODE_ACTIVE
+                   - Host device is running on external power.
+    CSR_WIFI_SME_HOST_POWER_MODE_POWER_SAVE
+                   - Host device is running on (internal) battery power.
+    CSR_WIFI_SME_HOST_POWER_MODE_FULL_POWER_SAVE
+                   - For future use.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeHostPowerMode;
+#define CSR_WIFI_SME_HOST_POWER_MODE_ACTIVE            ((CsrWifiSmeHostPowerMode) 0x00)
+#define CSR_WIFI_SME_HOST_POWER_MODE_POWER_SAVE        ((CsrWifiSmeHostPowerMode) 0x01)
+#define CSR_WIFI_SME_HOST_POWER_MODE_FULL_POWER_SAVE   ((CsrWifiSmeHostPowerMode) 0x02)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeIEEE80211Reason
+
+  DESCRIPTION
+    As definined in the IEEE 802.11 standards
+
+ VALUES
+    CSR_WIFI_SME_IEEE80211_REASON_SUCCESS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_UNSPECIFIED_REASON
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_AUTHENTICATION_NOT_VALID
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_DEAUTHENTICATED_LEAVE_BSS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_DISASSOCIATED_INACTIVITY
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_AP_OVERLOAD
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_CLASS_2FRAME_ERROR
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_CLASS_3FRAME_ERROR
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_DISASSOCIATED_LEAVE_BSS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_ASSOCIATION_NOT_AUTHENTICATED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_DISASSOCIATED_POWER_CAPABILITY
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_DISASSOCIATED_SUPPORTED_CHANNELS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_INVALID_INFORMATION_ELEMENT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_MICHAEL_MIC_FAILURE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_FOURWAY_HANDSHAKE_TIMEOUT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_GROUP_KEY_UPDATE_TIMEOUT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_HANDSHAKE_ELEMENT_DIFFERENT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_INVALID_GROUP_CIPHER
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_INVALID_PAIRWISE_CIPHER
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_INVALID_AKMP
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_UNSUPPORTED_RSN_IEVERSION
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_INVALID_RSN_IECAPABILITIES
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_DOT1X_AUTH_FAILED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_CIPHER_REJECTED_BY_POLICY
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_SERVICE_CHANGE_PRECLUDES_TS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_QOS_UNSPECIFIED_REASON
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_QOS_INSUFFICIENT_BANDWIDTH
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_QOS_EXCESSIVE_NOT_ACK
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_QOS_TXOPLIMIT_EXCEEDED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_QSTA_LEAVING
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_END_TS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_END_DLS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_END_BA
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_UNKNOWN_TS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_UNKNOWN_BA
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_UNKNOWN_DLS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_TIMEOUT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_STAKEY_MISMATCH
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_UNICAST_KEY_NEGOTIATION_TIMEOUT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_MULTICAST_KEY_ANNOUNCEMENT_TIMEOUT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_INCOMPATIBLE_UNICAST_KEY_NEGOTIATION_IE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_INVALID_MULTICAST_CIPHER
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_INVALID_UNICAST_CIPHER
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_UNSUPPORTED_WAPI_IE_VERSION
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_INVALID_WAPI_CAPABILITY_IE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_REASON_WAI_CERTIFICATE_AUTHENTICATION_FAILED
+                   - See IEEE 802.11 Standard
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeIEEE80211Reason;
+#define CSR_WIFI_SME_IEEE80211_REASON_SUCCESS                                   ((CsrWifiSmeIEEE80211Reason) 0x0000)
+#define CSR_WIFI_SME_IEEE80211_REASON_UNSPECIFIED_REASON                        ((CsrWifiSmeIEEE80211Reason) 0x0001)
+#define CSR_WIFI_SME_IEEE80211_REASON_AUTHENTICATION_NOT_VALID                  ((CsrWifiSmeIEEE80211Reason) 0x0002)
+#define CSR_WIFI_SME_IEEE80211_REASON_DEAUTHENTICATED_LEAVE_BSS                 ((CsrWifiSmeIEEE80211Reason) 0x0003)
+#define CSR_WIFI_SME_IEEE80211_REASON_DISASSOCIATED_INACTIVITY                  ((CsrWifiSmeIEEE80211Reason) 0x0004)
+#define CSR_WIFI_SME_IEEE80211_REASON_AP_OVERLOAD                               ((CsrWifiSmeIEEE80211Reason) 0x0005)
+#define CSR_WIFI_SME_IEEE80211_REASON_CLASS_2FRAME_ERROR                        ((CsrWifiSmeIEEE80211Reason) 0x0006)
+#define CSR_WIFI_SME_IEEE80211_REASON_CLASS_3FRAME_ERROR                        ((CsrWifiSmeIEEE80211Reason) 0x0007)
+#define CSR_WIFI_SME_IEEE80211_REASON_DISASSOCIATED_LEAVE_BSS                   ((CsrWifiSmeIEEE80211Reason) 0x0008)
+#define CSR_WIFI_SME_IEEE80211_REASON_ASSOCIATION_NOT_AUTHENTICATED             ((CsrWifiSmeIEEE80211Reason) 0x0009)
+#define CSR_WIFI_SME_IEEE80211_REASON_DISASSOCIATED_POWER_CAPABILITY            ((CsrWifiSmeIEEE80211Reason) 0x000a)
+#define CSR_WIFI_SME_IEEE80211_REASON_DISASSOCIATED_SUPPORTED_CHANNELS          ((CsrWifiSmeIEEE80211Reason) 0x000b)
+#define CSR_WIFI_SME_IEEE80211_REASON_INVALID_INFORMATION_ELEMENT               ((CsrWifiSmeIEEE80211Reason) 0x000d)
+#define CSR_WIFI_SME_IEEE80211_REASON_MICHAEL_MIC_FAILURE                       ((CsrWifiSmeIEEE80211Reason) 0x000e)
+#define CSR_WIFI_SME_IEEE80211_REASON_FOURWAY_HANDSHAKE_TIMEOUT                 ((CsrWifiSmeIEEE80211Reason) 0x000f)
+#define CSR_WIFI_SME_IEEE80211_REASON_GROUP_KEY_UPDATE_TIMEOUT                  ((CsrWifiSmeIEEE80211Reason) 0x0010)
+#define CSR_WIFI_SME_IEEE80211_REASON_HANDSHAKE_ELEMENT_DIFFERENT               ((CsrWifiSmeIEEE80211Reason) 0x0011)
+#define CSR_WIFI_SME_IEEE80211_REASON_INVALID_GROUP_CIPHER                      ((CsrWifiSmeIEEE80211Reason) 0x0012)
+#define CSR_WIFI_SME_IEEE80211_REASON_INVALID_PAIRWISE_CIPHER                   ((CsrWifiSmeIEEE80211Reason) 0x0013)
+#define CSR_WIFI_SME_IEEE80211_REASON_INVALID_AKMP                              ((CsrWifiSmeIEEE80211Reason) 0x0014)
+#define CSR_WIFI_SME_IEEE80211_REASON_UNSUPPORTED_RSN_IEVERSION                 ((CsrWifiSmeIEEE80211Reason) 0x0015)
+#define CSR_WIFI_SME_IEEE80211_REASON_INVALID_RSN_IECAPABILITIES                ((CsrWifiSmeIEEE80211Reason) 0x0016)
+#define CSR_WIFI_SME_IEEE80211_REASON_DOT1X_AUTH_FAILED                         ((CsrWifiSmeIEEE80211Reason) 0x0017)
+#define CSR_WIFI_SME_IEEE80211_REASON_CIPHER_REJECTED_BY_POLICY                 ((CsrWifiSmeIEEE80211Reason) 0x0018)
+#define CSR_WIFI_SME_IEEE80211_REASON_SERVICE_CHANGE_PRECLUDES_TS               ((CsrWifiSmeIEEE80211Reason) 0x001F)
+#define CSR_WIFI_SME_IEEE80211_REASON_QOS_UNSPECIFIED_REASON                    ((CsrWifiSmeIEEE80211Reason) 0x0020)
+#define CSR_WIFI_SME_IEEE80211_REASON_QOS_INSUFFICIENT_BANDWIDTH                ((CsrWifiSmeIEEE80211Reason) 0x0021)
+#define CSR_WIFI_SME_IEEE80211_REASON_QOS_EXCESSIVE_NOT_ACK                     ((CsrWifiSmeIEEE80211Reason) 0x0022)
+#define CSR_WIFI_SME_IEEE80211_REASON_QOS_TXOPLIMIT_EXCEEDED                    ((CsrWifiSmeIEEE80211Reason) 0x0023)
+#define CSR_WIFI_SME_IEEE80211_REASON_QSTA_LEAVING                              ((CsrWifiSmeIEEE80211Reason) 0x0024)
+#define CSR_WIFI_SME_IEEE80211_REASON_END_TS                                    ((CsrWifiSmeIEEE80211Reason) 0x0025)
+#define CSR_WIFI_SME_IEEE80211_REASON_END_DLS                                   ((CsrWifiSmeIEEE80211Reason) 0x0025)
+#define CSR_WIFI_SME_IEEE80211_REASON_END_BA                                    ((CsrWifiSmeIEEE80211Reason) 0x0025)
+#define CSR_WIFI_SME_IEEE80211_REASON_UNKNOWN_TS                                ((CsrWifiSmeIEEE80211Reason) 0x0026)
+#define CSR_WIFI_SME_IEEE80211_REASON_UNKNOWN_BA                                ((CsrWifiSmeIEEE80211Reason) 0x0026)
+#define CSR_WIFI_SME_IEEE80211_REASON_UNKNOWN_DLS                               ((CsrWifiSmeIEEE80211Reason) 0x0026)
+#define CSR_WIFI_SME_IEEE80211_REASON_TIMEOUT                                   ((CsrWifiSmeIEEE80211Reason) 0x0027)
+#define CSR_WIFI_SME_IEEE80211_REASON_STAKEY_MISMATCH                           ((CsrWifiSmeIEEE80211Reason) 0x002d)
+#define CSR_WIFI_SME_IEEE80211_REASON_UNICAST_KEY_NEGOTIATION_TIMEOUT           ((CsrWifiSmeIEEE80211Reason) 0xf019)
+#define CSR_WIFI_SME_IEEE80211_REASON_MULTICAST_KEY_ANNOUNCEMENT_TIMEOUT        ((CsrWifiSmeIEEE80211Reason) 0xf01a)
+#define CSR_WIFI_SME_IEEE80211_REASON_INCOMPATIBLE_UNICAST_KEY_NEGOTIATION_IE   ((CsrWifiSmeIEEE80211Reason) 0xf01b)
+#define CSR_WIFI_SME_IEEE80211_REASON_INVALID_MULTICAST_CIPHER                  ((CsrWifiSmeIEEE80211Reason) 0xf01c)
+#define CSR_WIFI_SME_IEEE80211_REASON_INVALID_UNICAST_CIPHER                    ((CsrWifiSmeIEEE80211Reason) 0xf01d)
+#define CSR_WIFI_SME_IEEE80211_REASON_UNSUPPORTED_WAPI_IE_VERSION               ((CsrWifiSmeIEEE80211Reason) 0xf01e)
+#define CSR_WIFI_SME_IEEE80211_REASON_INVALID_WAPI_CAPABILITY_IE                ((CsrWifiSmeIEEE80211Reason) 0xf01f)
+#define CSR_WIFI_SME_IEEE80211_REASON_WAI_CERTIFICATE_AUTHENTICATION_FAILED     ((CsrWifiSmeIEEE80211Reason) 0xf020)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeIEEE80211Result
+
+  DESCRIPTION
+    As definined in the IEEE 802.11 standards
+
+ VALUES
+    CSR_WIFI_SME_IEEE80211_RESULT_SUCCESS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_UNSPECIFIED_FAILURE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_CAPABILITIES_MISMATCH
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REASSOCIATION_DENIED_NO_ASSOCIATION
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_EXTERNAL_REASON
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_AUTHENTICATION_MISMATCH
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_INVALID_AUTHENTICATION_SEQUENCE_NUMBER
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_CHALLENGE_FAILURE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_AUTHENTICATION_TIMEOUT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_AP_OUT_OF_MEMORY
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_BASIC_RATES_MISMATCH
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_SHORT_PREAMBLE_REQUIRED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_PBCC_MODULATION_REQUIRED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_CHANNEL_AGILITY_REQUIRED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_SPECTRUM_MANAGEMENT_REQUIRED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_POWER_CAPABILITY_UNACCEPTABLE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_SUPPORTED_CHANNELS_UNACCEPTABLE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_SHORT_SLOT_REQUIRED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_DSSS_OFDMREQUIRED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_NO_HT_SUPPORT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_R0KH_UNREACHABLE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_PCO_TRANSITION_SUPPORT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_ASSOCIATION_REQUEST_REJECTED_TEMPORARILY
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_ROBUST_MANAGEMENT_FRAME_POLICY_VIOLATION
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_FAILURE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_AP_BANDWIDTH_INSUFFICIENT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_POOR_OPERATING_CHANNEL
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_QOS_REQUIRED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_REASON_UNSPECIFIED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_INVALID_PARAMETERS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_WITH_SUGGESTED_TSPEC_CHANGES
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_INVALID_IE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_INVALID_GROUP_CIPHER
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_INVALID_PAIRWISE_CIPHER
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_INVALID_AKMP
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_UNSUPPORTED_RSN_VERSION
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_INVALID_RSN_CAPABILITY
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_SECURITY_POLICY
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_FOR_DELAY_PERIOD
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_NOT_ALLOWED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_NOT_PRESENT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_NOT_QSTA
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_LISTEN_INTERVAL_TOO_LARGE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_INVALID_FT_ACTION_FRAME_COUNT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_INVALID_PMKID
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_INVALID_MDIE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_INVALID_FTIE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_UNSPECIFIED_QOS_FAILURE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_WRONG_POLICY
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_INSUFFICIENT_BANDWIDTH
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_INVALID_TSPEC_PARAMETERS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_TIMEOUT
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_TOO_MANY_SIMULTANEOUS_REQUESTS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_BSS_ALREADY_STARTED_OR_JOINED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_NOT_SUPPORTED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_TRANSMISSION_FAILURE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_NOT_AUTHENTICATED
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_RESET_REQUIRED_BEFORE_START
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_LM_INFO_UNAVAILABLE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_INVALID_UNICAST_CIPHER
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_INVALID_MULTICAST_CIPHER
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_UNSUPPORTED_WAPI_IE_VERSION
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_IEEE80211_RESULT_INVALID_WAPI_CAPABILITY_IE
+                   - See IEEE 802.11 Standard
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeIEEE80211Result;
+#define CSR_WIFI_SME_IEEE80211_RESULT_SUCCESS                                          ((CsrWifiSmeIEEE80211Result) 0x0000)
+#define CSR_WIFI_SME_IEEE80211_RESULT_UNSPECIFIED_FAILURE                              ((CsrWifiSmeIEEE80211Result) 0x0001)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_CAPABILITIES_MISMATCH                    ((CsrWifiSmeIEEE80211Result) 0x000a)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REASSOCIATION_DENIED_NO_ASSOCIATION              ((CsrWifiSmeIEEE80211Result) 0x000b)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_EXTERNAL_REASON                          ((CsrWifiSmeIEEE80211Result) 0x000c)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_AUTHENTICATION_MISMATCH                  ((CsrWifiSmeIEEE80211Result) 0x000d)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_INVALID_AUTHENTICATION_SEQUENCE_NUMBER   ((CsrWifiSmeIEEE80211Result) 0x000e)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_CHALLENGE_FAILURE                        ((CsrWifiSmeIEEE80211Result) 0x000f)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_AUTHENTICATION_TIMEOUT                   ((CsrWifiSmeIEEE80211Result) 0x0010)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_AP_OUT_OF_MEMORY                         ((CsrWifiSmeIEEE80211Result) 0x0011)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_BASIC_RATES_MISMATCH                     ((CsrWifiSmeIEEE80211Result) 0x0012)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_SHORT_PREAMBLE_REQUIRED                  ((CsrWifiSmeIEEE80211Result) 0x0013)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_PBCC_MODULATION_REQUIRED                 ((CsrWifiSmeIEEE80211Result) 0x0014)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_CHANNEL_AGILITY_REQUIRED                 ((CsrWifiSmeIEEE80211Result) 0x0015)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_SPECTRUM_MANAGEMENT_REQUIRED             ((CsrWifiSmeIEEE80211Result) 0x0016)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_POWER_CAPABILITY_UNACCEPTABLE            ((CsrWifiSmeIEEE80211Result) 0x0017)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_SUPPORTED_CHANNELS_UNACCEPTABLE          ((CsrWifiSmeIEEE80211Result) 0x0018)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_SHORT_SLOT_REQUIRED                      ((CsrWifiSmeIEEE80211Result) 0x0019)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_DSSS_OFDMREQUIRED                        ((CsrWifiSmeIEEE80211Result) 0x001a)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_NO_HT_SUPPORT                            ((CsrWifiSmeIEEE80211Result) 0x001b)
+#define CSR_WIFI_SME_IEEE80211_RESULT_R0KH_UNREACHABLE                                 ((CsrWifiSmeIEEE80211Result) 0x001c)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_PCO_TRANSITION_SUPPORT                   ((CsrWifiSmeIEEE80211Result) 0x001d)
+#define CSR_WIFI_SME_IEEE80211_RESULT_ASSOCIATION_REQUEST_REJECTED_TEMPORARILY         ((CsrWifiSmeIEEE80211Result) 0x001e)
+#define CSR_WIFI_SME_IEEE80211_RESULT_ROBUST_MANAGEMENT_FRAME_POLICY_VIOLATION         ((CsrWifiSmeIEEE80211Result) 0x001f)
+#define CSR_WIFI_SME_IEEE80211_RESULT_FAILURE                                          ((CsrWifiSmeIEEE80211Result) 0x0020)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_AP_BANDWIDTH_INSUFFICIENT                ((CsrWifiSmeIEEE80211Result) 0x0021)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_POOR_OPERATING_CHANNEL                   ((CsrWifiSmeIEEE80211Result) 0x0022)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_QOS_REQUIRED                             ((CsrWifiSmeIEEE80211Result) 0x0023)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_REASON_UNSPECIFIED                       ((CsrWifiSmeIEEE80211Result) 0x0025)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED                                          ((CsrWifiSmeIEEE80211Result) 0x0025)
+#define CSR_WIFI_SME_IEEE80211_RESULT_INVALID_PARAMETERS                               ((CsrWifiSmeIEEE80211Result) 0x0026)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_WITH_SUGGESTED_TSPEC_CHANGES            ((CsrWifiSmeIEEE80211Result) 0x0027)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_INVALID_IE                              ((CsrWifiSmeIEEE80211Result) 0x0028)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_INVALID_GROUP_CIPHER                    ((CsrWifiSmeIEEE80211Result) 0x0029)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_INVALID_PAIRWISE_CIPHER                 ((CsrWifiSmeIEEE80211Result) 0x002a)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_INVALID_AKMP                            ((CsrWifiSmeIEEE80211Result) 0x002b)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_UNSUPPORTED_RSN_VERSION                 ((CsrWifiSmeIEEE80211Result) 0x002c)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_INVALID_RSN_CAPABILITY                  ((CsrWifiSmeIEEE80211Result) 0x002d)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_SECURITY_POLICY                         ((CsrWifiSmeIEEE80211Result) 0x002e)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_FOR_DELAY_PERIOD                        ((CsrWifiSmeIEEE80211Result) 0x002f)
+#define CSR_WIFI_SME_IEEE80211_RESULT_NOT_ALLOWED                                      ((CsrWifiSmeIEEE80211Result) 0x0030)
+#define CSR_WIFI_SME_IEEE80211_RESULT_NOT_PRESENT                                      ((CsrWifiSmeIEEE80211Result) 0x0031)
+#define CSR_WIFI_SME_IEEE80211_RESULT_NOT_QSTA                                         ((CsrWifiSmeIEEE80211Result) 0x0032)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REJECTED_LISTEN_INTERVAL_TOO_LARGE               ((CsrWifiSmeIEEE80211Result) 0x0033)
+#define CSR_WIFI_SME_IEEE80211_RESULT_INVALID_FT_ACTION_FRAME_COUNT                    ((CsrWifiSmeIEEE80211Result) 0x0034)
+#define CSR_WIFI_SME_IEEE80211_RESULT_INVALID_PMKID                                    ((CsrWifiSmeIEEE80211Result) 0x0035)
+#define CSR_WIFI_SME_IEEE80211_RESULT_INVALID_MDIE                                     ((CsrWifiSmeIEEE80211Result) 0x0036)
+#define CSR_WIFI_SME_IEEE80211_RESULT_INVALID_FTIE                                     ((CsrWifiSmeIEEE80211Result) 0x0037)
+#define CSR_WIFI_SME_IEEE80211_RESULT_UNSPECIFIED_QOS_FAILURE                          ((CsrWifiSmeIEEE80211Result) 0x00c8)
+#define CSR_WIFI_SME_IEEE80211_RESULT_WRONG_POLICY                                     ((CsrWifiSmeIEEE80211Result) 0x00c9)
+#define CSR_WIFI_SME_IEEE80211_RESULT_INSUFFICIENT_BANDWIDTH                           ((CsrWifiSmeIEEE80211Result) 0x00ca)
+#define CSR_WIFI_SME_IEEE80211_RESULT_INVALID_TSPEC_PARAMETERS                         ((CsrWifiSmeIEEE80211Result) 0x00cb)
+#define CSR_WIFI_SME_IEEE80211_RESULT_TIMEOUT                                          ((CsrWifiSmeIEEE80211Result) 0x8000)
+#define CSR_WIFI_SME_IEEE80211_RESULT_TOO_MANY_SIMULTANEOUS_REQUESTS                   ((CsrWifiSmeIEEE80211Result) 0x8001)
+#define CSR_WIFI_SME_IEEE80211_RESULT_BSS_ALREADY_STARTED_OR_JOINED                    ((CsrWifiSmeIEEE80211Result) 0x8002)
+#define CSR_WIFI_SME_IEEE80211_RESULT_NOT_SUPPORTED                                    ((CsrWifiSmeIEEE80211Result) 0x8003)
+#define CSR_WIFI_SME_IEEE80211_RESULT_TRANSMISSION_FAILURE                             ((CsrWifiSmeIEEE80211Result) 0x8004)
+#define CSR_WIFI_SME_IEEE80211_RESULT_REFUSED_NOT_AUTHENTICATED                        ((CsrWifiSmeIEEE80211Result) 0x8005)
+#define CSR_WIFI_SME_IEEE80211_RESULT_RESET_REQUIRED_BEFORE_START                      ((CsrWifiSmeIEEE80211Result) 0x8006)
+#define CSR_WIFI_SME_IEEE80211_RESULT_LM_INFO_UNAVAILABLE                              ((CsrWifiSmeIEEE80211Result) 0x8007)
+#define CSR_WIFI_SME_IEEE80211_RESULT_INVALID_UNICAST_CIPHER                           ((CsrWifiSmeIEEE80211Result) 0xf02f)
+#define CSR_WIFI_SME_IEEE80211_RESULT_INVALID_MULTICAST_CIPHER                         ((CsrWifiSmeIEEE80211Result) 0xf030)
+#define CSR_WIFI_SME_IEEE80211_RESULT_UNSUPPORTED_WAPI_IE_VERSION                      ((CsrWifiSmeIEEE80211Result) 0xf031)
+#define CSR_WIFI_SME_IEEE80211_RESULT_INVALID_WAPI_CAPABILITY_IE                       ((CsrWifiSmeIEEE80211Result) 0xf032)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeIndications
+
+  DESCRIPTION
+    Defines bits for CsrWifiSmeIndicationsMask
+
+ VALUES
+    CSR_WIFI_SME_INDICATIONS_NONE
+                   - Used to cancel the registrations for receiving indications
+    CSR_WIFI_SME_INDICATIONS_WIFIOFF
+                   - Used to register for CSR_WIFI_SME_WIFI_OFF_IND events
+    CSR_WIFI_SME_INDICATIONS_SCANRESULT
+                   - Used to register for CSR_WIFI_SME_SCAN_RESULT_IND events
+    CSR_WIFI_SME_INDICATIONS_CONNECTIONQUALITY
+                   - Used to register for CSR_WIFI_SME_CONNECTION_QUALITY_IND
+                     events
+    CSR_WIFI_SME_INDICATIONS_MEDIASTATUS
+                   - Used to register for CSR_WIFI_SME_MEDIA_STATUS_IND events
+    CSR_WIFI_SME_INDICATIONS_MICFAILURE
+                   - Used to register for CSR_WIFI_SME_MICFAILURE_IND events
+    CSR_WIFI_SME_INDICATIONS_PMKIDCANDIDATELIST
+                   - Used to register for CSR_WIFI_SME_PMKIDCANDIDATE_LIST_IND
+                     events
+    CSR_WIFI_SME_INDICATIONS_TSPEC
+                   - Used to register for CSR_WIFI_SME_TSPEC_IND events
+    CSR_WIFI_SME_INDICATIONS_ROAMSTART
+                   - Used to register for CSR_WIFI_SME_ROAM_START_IND events
+    CSR_WIFI_SME_INDICATIONS_ROAMCOMPLETE
+                   - Used to register for CSR_WIFI_SME_ROAM_COMPLETE_IND events
+    CSR_WIFI_SME_INDICATIONS_ASSOCIATIONSTART
+                   - Used to register for CSR_WIFI_SME_ASSOCIATION_START_IND
+                     events
+    CSR_WIFI_SME_INDICATIONS_ASSOCIATIONCOMPLETE
+                   - Used to register for CSR_WIFI_SME_ASSOCIATION_COMPLETE_IND
+                     events
+    CSR_WIFI_SME_INDICATIONS_IBSSSTATION
+                   - Used to register for CSR_WIFI_SME_IBSS_STATION_IND events
+    CSR_WIFI_SME_INDICATIONS_WIFION
+                   - Used to register for CSR_WIFI_SME_WIFI_ON_IND events
+    CSR_WIFI_SME_INDICATIONS_ERROR
+                   - Used to register for CSR_WIFI_SME_ERROR_IND events
+    CSR_WIFI_SME_INDICATIONS_INFO
+                   - Used to register for CSR_WIFI_SME_INFO_IND events
+    CSR_WIFI_SME_INDICATIONS_COREDUMP
+                   - Used to register for CSR_WIFI_SME_CORE_DUMP_IND events
+    CSR_WIFI_SME_INDICATIONS_ALL
+                   - Used to register for all available indications
+
+*******************************************************************************/
+typedef CsrUint32 CsrWifiSmeIndications;
+#define CSR_WIFI_SME_INDICATIONS_NONE                  ((CsrWifiSmeIndications) 0x00000000)
+#define CSR_WIFI_SME_INDICATIONS_WIFIOFF               ((CsrWifiSmeIndications) 0x00000001)
+#define CSR_WIFI_SME_INDICATIONS_SCANRESULT            ((CsrWifiSmeIndications) 0x00000002)
+#define CSR_WIFI_SME_INDICATIONS_CONNECTIONQUALITY     ((CsrWifiSmeIndications) 0x00000004)
+#define CSR_WIFI_SME_INDICATIONS_MEDIASTATUS           ((CsrWifiSmeIndications) 0x00000008)
+#define CSR_WIFI_SME_INDICATIONS_MICFAILURE            ((CsrWifiSmeIndications) 0x00000010)
+#define CSR_WIFI_SME_INDICATIONS_PMKIDCANDIDATELIST    ((CsrWifiSmeIndications) 0x00000020)
+#define CSR_WIFI_SME_INDICATIONS_TSPEC                 ((CsrWifiSmeIndications) 0x00000040)
+#define CSR_WIFI_SME_INDICATIONS_ROAMSTART             ((CsrWifiSmeIndications) 0x00000080)
+#define CSR_WIFI_SME_INDICATIONS_ROAMCOMPLETE          ((CsrWifiSmeIndications) 0x00000100)
+#define CSR_WIFI_SME_INDICATIONS_ASSOCIATIONSTART      ((CsrWifiSmeIndications) 0x00000200)
+#define CSR_WIFI_SME_INDICATIONS_ASSOCIATIONCOMPLETE   ((CsrWifiSmeIndications) 0x00000400)
+#define CSR_WIFI_SME_INDICATIONS_IBSSSTATION           ((CsrWifiSmeIndications) 0x00000800)
+#define CSR_WIFI_SME_INDICATIONS_WIFION                ((CsrWifiSmeIndications) 0x00001000)
+#define CSR_WIFI_SME_INDICATIONS_ERROR                 ((CsrWifiSmeIndications) 0x00002000)
+#define CSR_WIFI_SME_INDICATIONS_INFO                  ((CsrWifiSmeIndications) 0x00004000)
+#define CSR_WIFI_SME_INDICATIONS_COREDUMP              ((CsrWifiSmeIndications) 0x00008000)
+#define CSR_WIFI_SME_INDICATIONS_ALL                   ((CsrWifiSmeIndications) 0xFFFFFFFF)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeKeyType
+
+  DESCRIPTION
+    Indicates the type of the key
+
+ VALUES
+    CSR_WIFI_SME_KEY_TYPE_GROUP    - Key for broadcast communication
+    CSR_WIFI_SME_KEY_TYPE_PAIRWISE - Key for unicast communication
+    CSR_WIFI_SME_KEY_TYPE_STAKEY   - Key for direct link communication to
+                                     another station in infrastructure networks
+    CSR_WIFI_SME_KEY_TYPE_IGTK     - Integrity Group Temporal Key
+    CSR_WIFI_SME_KEY_TYPE_CCKM     - Key for Cisco Centralized Key Management
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeKeyType;
+#define CSR_WIFI_SME_KEY_TYPE_GROUP      ((CsrWifiSmeKeyType) 0x00)
+#define CSR_WIFI_SME_KEY_TYPE_PAIRWISE   ((CsrWifiSmeKeyType) 0x01)
+#define CSR_WIFI_SME_KEY_TYPE_STAKEY     ((CsrWifiSmeKeyType) 0x02)
+#define CSR_WIFI_SME_KEY_TYPE_IGTK       ((CsrWifiSmeKeyType) 0x03)
+#define CSR_WIFI_SME_KEY_TYPE_CCKM       ((CsrWifiSmeKeyType) 0x04)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeListAction
+
+  DESCRIPTION
+    Identifies the type of action to be performed on a list of items
+    The values of this type are used across the NME/SME/Router API's and they
+    must be kept consistent with the corresponding types in the .xml of the
+    ottherinterfaces
+
+ VALUES
+    CSR_WIFI_SME_LIST_ACTION_GET    - Retrieve the current list of items
+    CSR_WIFI_SME_LIST_ACTION_ADD    - Add one or more items
+    CSR_WIFI_SME_LIST_ACTION_REMOVE - Remove one or more items
+    CSR_WIFI_SME_LIST_ACTION_FLUSH  - Remove all items
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeListAction;
+#define CSR_WIFI_SME_LIST_ACTION_GET      ((CsrWifiSmeListAction) 0x00)
+#define CSR_WIFI_SME_LIST_ACTION_ADD      ((CsrWifiSmeListAction) 0x01)
+#define CSR_WIFI_SME_LIST_ACTION_REMOVE   ((CsrWifiSmeListAction) 0x02)
+#define CSR_WIFI_SME_LIST_ACTION_FLUSH    ((CsrWifiSmeListAction) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMediaStatus
+
+  DESCRIPTION
+    Indicates the connection status
+    The values of this type are used across the NME/SME/Router API's and they
+    must be kept consistent with the corresponding types in the .xml of the
+    ottherinterfaces
+
+ VALUES
+    CSR_WIFI_SME_MEDIA_STATUS_CONNECTED
+                   - Value CSR_WIFI_SME_MEDIA_STATUS_CONNECTED can happen in two
+                     situations:
+                       * A network connection is established. Specifically, this is
+                         when the MLME_ASSOCIATION completes or the first peer
+                         relationship is established in an IBSS. In a WPA/WPA2
+                         network, this indicates that the stack is ready to perform
+                         the 4-way handshake or 802.1x authentication if CSR NME
+                         security library is not used. If CSR NME security library
+                         is used this indicates, completion of 4way handshake or
+                         802.1x authentication
+                       * The SME roams to another AP on the same ESS
+                     During the AP operation, it indicates that the peer station
+                     is connected to the AP and is ready for data transfer.
+    CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED
+                   - Value CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED can happen in
+                     two situations:
+                       * when the connection to a network is lost and there is no
+                         alternative on the same ESS to roam to
+                       * when a CSR_WIFI_SME_DISCONNECT_REQ request is issued
+                     During AP or P2PGO operation, it indicates that the peer
+                     station has disconnected from the AP
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeMediaStatus;
+#define CSR_WIFI_SME_MEDIA_STATUS_CONNECTED      ((CsrWifiSmeMediaStatus) 0x00)
+#define CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED   ((CsrWifiSmeMediaStatus) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeP2pCapability
+
+  DESCRIPTION
+    Defines P2P Device Capabilities
+
+ VALUES
+    CSR_WIFI_SME_P2P_SERVICE_DISCOVERY_CAPABILITY
+                   - This field is set to 1 if the P2P Device supports Service
+                     Discovery, and to 0 otherwise
+    CSR_WIFI_SME_P2P_CLIENT_DISCOVERABILITY_CAPABILITY
+                   - This field is set to 1 when the P2P Device supports P2P
+                     Client Discoverability, and to 0 otherwise.
+    CSR_WIFI_SME_P2P_CONCURRENT_OPERATION_CAPABILITY
+                   - This field is set to 1 when the P2P Device supports
+                     Concurrent Operation with WLAN, and to 0 otherwise.
+    CSR_WIFI_SME_P2P_MANAGED_DEVICE_CAPABILITY
+                   - This field is set to 1 when the P2P interface of the P2P
+                     Device is capable of being managed by the WLAN
+                     (infrastructure network) based on P2P coexistence
+                     parameters, and to 0 otherwise
+    CSR_WIFI_SME_P2P_INVITAION_CAPABILITY
+                   - This field is set to 1 if the P2P Device is capable of
+                     processing P2P Invitation Procedure signaling, and to 0
+                     otherwise.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeP2pCapability;
+#define CSR_WIFI_SME_P2P_SERVICE_DISCOVERY_CAPABILITY        ((CsrWifiSmeP2pCapability) 0x01)
+#define CSR_WIFI_SME_P2P_CLIENT_DISCOVERABILITY_CAPABILITY   ((CsrWifiSmeP2pCapability) 0x02)
+#define CSR_WIFI_SME_P2P_CONCURRENT_OPERATION_CAPABILITY     ((CsrWifiSmeP2pCapability) 0x04)
+#define CSR_WIFI_SME_P2P_MANAGED_DEVICE_CAPABILITY           ((CsrWifiSmeP2pCapability) 0x08)
+#define CSR_WIFI_SME_P2P_INVITAION_CAPABILITY                ((CsrWifiSmeP2pCapability) 0x20)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeP2pGroupCapability
+
+  DESCRIPTION
+    Define bits for P2P Group Capability
+
+ VALUES
+    CSR_WIFI_P2P_GRP_CAP_GO
+                   - Indicates if the local device has become a GO after GO
+                     negotiation
+    CSR_WIFI_P2P_GRP_CAP_PERSISTENT
+                   - Persistent group
+    CSR_WIFI_P2P_GRP_CAP_INTRABSS_DIST
+                   - Intra-BSS data distribution support
+    CSR_WIFI_P2P_GRP_CAP_CROSS_CONN
+                   - Support of cross connection
+    CSR_WIFI_P2P_GRP_CAP_PERSISTENT_RECONNECT
+                   - Support of persistent reconnect
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeP2pGroupCapability;
+#define CSR_WIFI_P2P_GRP_CAP_GO                     ((CsrWifiSmeP2pGroupCapability) 0x01)
+#define CSR_WIFI_P2P_GRP_CAP_PERSISTENT             ((CsrWifiSmeP2pGroupCapability) 0x02)
+#define CSR_WIFI_P2P_GRP_CAP_INTRABSS_DIST          ((CsrWifiSmeP2pGroupCapability) 0x08)
+#define CSR_WIFI_P2P_GRP_CAP_CROSS_CONN             ((CsrWifiSmeP2pGroupCapability) 0x10)
+#define CSR_WIFI_P2P_GRP_CAP_PERSISTENT_RECONNECT   ((CsrWifiSmeP2pGroupCapability) 0x20)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeP2pNoaConfigMethod
+
+  DESCRIPTION
+    Notice of Absece Configuration
+
+ VALUES
+    CSR_WIFI_P2P_NOA_NONE         - Do not use NOA
+    CSR_WIFI_P2P_NOA_AUTONOMOUS   - NOA based on the traffic analysis
+    CSR_WIFI_P2P_NOA_USER_DEFINED - NOA as specified by the user
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeP2pNoaConfigMethod;
+#define CSR_WIFI_P2P_NOA_NONE           ((CsrWifiSmeP2pNoaConfigMethod) 0x00)
+#define CSR_WIFI_P2P_NOA_AUTONOMOUS     ((CsrWifiSmeP2pNoaConfigMethod) 0x01)
+#define CSR_WIFI_P2P_NOA_USER_DEFINED   ((CsrWifiSmeP2pNoaConfigMethod) 0x02)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeP2pRole
+
+  DESCRIPTION
+    Definition of roles for a P2P Device
+
+ VALUES
+    CSR_WIFI_SME_P2P_ROLE_NONE       - A non-P2PDevice device
+    CSR_WIFI_SME_P2P_ROLE_STANDALONE - A Standalone P2P device
+    CSR_WIFI_SME_P2P_ROLE_GO         - Role Assumed is that of a Group Owner
+                                       within a P2P Group
+    CSR_WIFI_SME_P2P_ROLE_CLI        - Role Assumed is that of a P2P Client
+                                       within a P2P Group
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeP2pRole;
+#define CSR_WIFI_SME_P2P_ROLE_NONE         ((CsrWifiSmeP2pRole) 0x00)
+#define CSR_WIFI_SME_P2P_ROLE_STANDALONE   ((CsrWifiSmeP2pRole) 0x01)
+#define CSR_WIFI_SME_P2P_ROLE_GO           ((CsrWifiSmeP2pRole) 0x02)
+#define CSR_WIFI_SME_P2P_ROLE_CLI          ((CsrWifiSmeP2pRole) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeP2pStatus
+
+  DESCRIPTION
+    This data type enumerates the outcome of P2P procedure
+
+ VALUES
+    CSR_WIFI_SME_P2P_STATUS_SUCCESS
+                   - Success
+    CSR_WIFI_SME_P2P_STATUS_FAIL_INFO_UNAVAILABLE
+                   - Fail; information is currently unavailable
+    CSR_WIFI_SME_P2P_STATUS_FAIL_INCOMPATIBLE_PARAM
+                   - Fail; incompatible parameters
+    CSR_WIFI_SME_P2P_STATUS_FAIL_LIMIT_REACHED
+                   - Fail; limit reached
+    CSR_WIFI_SME_P2P_STATUS_FAIL_INVALID_PARAM
+                   - Fail; invalid parameters
+    CSR_WIFI_SME_P2P_STATUS_FAIL_ACCOMODATE
+                   - Fail; unable to accommodate request
+    CSR_WIFI_SME_P2P_STATUS_FAIL_PREV_ERROR
+                   - Fail; previous protocol error, or disruptive behavior
+    CSR_WIFI_SME_P2P_STATUS_FAIL_COMMON_CHANNELS
+                   - Fail; no common channels
+    CSR_WIFI_SME_P2P_STATUS_FAIL_UNKNOWN_GROUP
+                   - Fail; unknown P2P Group
+    CSR_WIFI_SME_P2P_STATUS_FAIL_GO_INTENT
+                   - Fail: both P2P Devices indicated an Intent of 15 in Group
+                     Owner Negotiation
+    CSR_WIFI_SME_P2P_STATUS_FAIL_PROVISION_METHOD_INCOMPATIBLE
+                   - Fail; incompatible provisioning method
+    CSR_WIFI_SME_P2P_STATUS_FAIL_REJECT
+                   - Fail: rejected by user
+    CSR_WIFI_SME_P2P_STATUS_FAIL_RESERVED
+                   - Fail; Status Reserved
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeP2pStatus;
+#define CSR_WIFI_SME_P2P_STATUS_SUCCESS                              ((CsrWifiSmeP2pStatus) 0x00)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_INFO_UNAVAILABLE                ((CsrWifiSmeP2pStatus) 0x01)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_INCOMPATIBLE_PARAM              ((CsrWifiSmeP2pStatus) 0x02)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_LIMIT_REACHED                   ((CsrWifiSmeP2pStatus) 0x03)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_INVALID_PARAM                   ((CsrWifiSmeP2pStatus) 0x04)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_ACCOMODATE                      ((CsrWifiSmeP2pStatus) 0x05)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_PREV_ERROR                      ((CsrWifiSmeP2pStatus) 0x06)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_COMMON_CHANNELS                 ((CsrWifiSmeP2pStatus) 0x07)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_UNKNOWN_GROUP                   ((CsrWifiSmeP2pStatus) 0x08)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_GO_INTENT                       ((CsrWifiSmeP2pStatus) 0x09)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_PROVISION_METHOD_INCOMPATIBLE   ((CsrWifiSmeP2pStatus) 0x0A)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_REJECT                          ((CsrWifiSmeP2pStatus) 0x0B)
+#define CSR_WIFI_SME_P2P_STATUS_FAIL_RESERVED                        ((CsrWifiSmeP2pStatus) 0xFF)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePacketFilterMode
+
+  DESCRIPTION
+    Options for the filter mode parameter.
+    The Values here match the HIP interface
+
+ VALUES
+    CSR_WIFI_SME_PACKET_FILTER_MODE_OPT_OUT
+                   - Broadcast packets are always reported to the host unless
+                     they match at least one of the specified TCLAS IEs.
+    CSR_WIFI_SME_PACKET_FILTER_MODE_OPT_IN
+                   - Broadcast packets are reported to the host only if they
+                     match at least one of the specified TCLAS IEs.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmePacketFilterMode;
+#define CSR_WIFI_SME_PACKET_FILTER_MODE_OPT_OUT   ((CsrWifiSmePacketFilterMode) 0x00)
+#define CSR_WIFI_SME_PACKET_FILTER_MODE_OPT_IN    ((CsrWifiSmePacketFilterMode) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePowerSaveLevel
+
+  DESCRIPTION
+    Power Save Level options as defined in the IEEE 802.11 standards
+    First 3 values are set to match the mlme PowerManagementMode
+
+ VALUES
+    CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW  - No power save: the driver will remain
+                                         active at all times
+    CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH - Enter power save after all packets in
+                                         the queues are transmitted and received
+    CSR_WIFI_SME_POWER_SAVE_LEVEL_MED  - Enter power save after all packets in
+                                         the queues are transmitted and received
+                                         and a further configurable delay
+                                         (default 1s) has elapsed
+    CSR_WIFI_SME_POWER_SAVE_LEVEL_AUTO - The SME will decide when to enter power
+                                         save mode according to the traffic
+                                         analysis
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmePowerSaveLevel;
+#define CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW    ((CsrWifiSmePowerSaveLevel) 0x00)
+#define CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH   ((CsrWifiSmePowerSaveLevel) 0x01)
+#define CSR_WIFI_SME_POWER_SAVE_LEVEL_MED    ((CsrWifiSmePowerSaveLevel) 0x02)
+#define CSR_WIFI_SME_POWER_SAVE_LEVEL_AUTO   ((CsrWifiSmePowerSaveLevel) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePreambleType
+
+  DESCRIPTION
+    SME Preamble Types
+
+ VALUES
+    CSR_WIFI_SME_USE_LONG_PREAMBLE  - Use legacy (long) preamble
+    CSR_WIFI_SME_USE_SHORT_PREAMBLE - Use short PPDU format
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmePreambleType;
+#define CSR_WIFI_SME_USE_LONG_PREAMBLE    ((CsrWifiSmePreambleType) 0x00)
+#define CSR_WIFI_SME_USE_SHORT_PREAMBLE   ((CsrWifiSmePreambleType) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRadioIF
+
+  DESCRIPTION
+    Indicates the frequency
+
+ VALUES
+    CSR_WIFI_SME_RADIO_IF_GHZ_2_4 - Indicates the 2.4 GHZ frequency
+    CSR_WIFI_SME_RADIO_IF_GHZ_5_0 - Future use: currently not supported
+    CSR_WIFI_SME_RADIO_IF_BOTH    - Future use: currently not supported
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeRadioIF;
+#define CSR_WIFI_SME_RADIO_IF_GHZ_2_4   ((CsrWifiSmeRadioIF) 0x01)
+#define CSR_WIFI_SME_RADIO_IF_GHZ_5_0   ((CsrWifiSmeRadioIF) 0x02)
+#define CSR_WIFI_SME_RADIO_IF_BOTH      ((CsrWifiSmeRadioIF) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRegulatoryDomain
+
+  DESCRIPTION
+    Indicates the regulatory domain as defined in IEEE 802.11 standards
+
+ VALUES
+    CSR_WIFI_SME_REGULATORY_DOMAIN_OTHER
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_REGULATORY_DOMAIN_FCC
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_REGULATORY_DOMAIN_IC
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_REGULATORY_DOMAIN_ETSI
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_REGULATORY_DOMAIN_SPAIN
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_REGULATORY_DOMAIN_FRANCE
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_REGULATORY_DOMAIN_JAPAN
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_REGULATORY_DOMAIN_JAPANBIS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_REGULATORY_DOMAIN_CHINA
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_REGULATORY_DOMAIN_CHINABIS
+                   - See IEEE 802.11 Standard
+    CSR_WIFI_SME_REGULATORY_DOMAIN_NONE
+                   - See IEEE 802.11 Standard
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeRegulatoryDomain;
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_OTHER      ((CsrWifiSmeRegulatoryDomain) 0x00)
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_FCC        ((CsrWifiSmeRegulatoryDomain) 0x10)
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_IC         ((CsrWifiSmeRegulatoryDomain) 0x20)
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_ETSI       ((CsrWifiSmeRegulatoryDomain) 0x30)
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_SPAIN      ((CsrWifiSmeRegulatoryDomain) 0x31)
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_FRANCE     ((CsrWifiSmeRegulatoryDomain) 0x32)
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_JAPAN      ((CsrWifiSmeRegulatoryDomain) 0x40)
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_JAPANBIS   ((CsrWifiSmeRegulatoryDomain) 0x41)
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_CHINA      ((CsrWifiSmeRegulatoryDomain) 0x50)
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_CHINABIS   ((CsrWifiSmeRegulatoryDomain) 0x51)
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_NONE       ((CsrWifiSmeRegulatoryDomain) 0xFF)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamReason
+
+  DESCRIPTION
+    Indicates the reason for roaming
+
+ VALUES
+    CSR_WIFI_SME_ROAM_REASON_BEACONLOST
+                   - The station cannot receive the beacon signal any more
+    CSR_WIFI_SME_ROAM_REASON_DISASSOCIATED
+                   - The station has been disassociated
+    CSR_WIFI_SME_ROAM_REASON_DEAUTHENTICATED
+                   - The station has been deauthenticated
+    CSR_WIFI_SME_ROAM_REASON_BETTERAPFOUND
+                   - A better AP has been found
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeRoamReason;
+#define CSR_WIFI_SME_ROAM_REASON_BEACONLOST        ((CsrWifiSmeRoamReason) 0x00)
+#define CSR_WIFI_SME_ROAM_REASON_DISASSOCIATED     ((CsrWifiSmeRoamReason) 0x01)
+#define CSR_WIFI_SME_ROAM_REASON_DEAUTHENTICATED   ((CsrWifiSmeRoamReason) 0x02)
+#define CSR_WIFI_SME_ROAM_REASON_BETTERAPFOUND     ((CsrWifiSmeRoamReason) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanType
+
+  DESCRIPTION
+    Identifies the type of scan to be performed
+
+ VALUES
+    CSR_WIFI_SME_SCAN_TYPE_ALL     - Scan actively or passively according to the
+                                     regulatory domain restrictions
+    CSR_WIFI_SME_SCAN_TYPE_ACTIVE  - Scan actively only: send probes and listen
+                                     for answers
+    CSR_WIFI_SME_SCAN_TYPE_PASSIVE - Scan passively only: listen for beacon
+                                     messages
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeScanType;
+#define CSR_WIFI_SME_SCAN_TYPE_ALL       ((CsrWifiSmeScanType) 0x00)
+#define CSR_WIFI_SME_SCAN_TYPE_ACTIVE    ((CsrWifiSmeScanType) 0x01)
+#define CSR_WIFI_SME_SCAN_TYPE_PASSIVE   ((CsrWifiSmeScanType) 0x02)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeTrafficType
+
+  DESCRIPTION
+    Identifies the type of traffic going on on the connection.
+    The values of this type are used across the NME/SME/Router API's and they
+    must be kept consistent with the corresponding types in the .xml of the
+    ottherinterfaces
+
+ VALUES
+    CSR_WIFI_SME_TRAFFIC_TYPE_OCCASIONAL
+                   - During the last 30 seconds there were fewer than 20 packets
+                     per seconds in each second in both directions
+    CSR_WIFI_SME_TRAFFIC_TYPE_BURSTY
+                   - During the last 30 seconds there was at least one second
+                     during which more than 20 packets were received in either
+                     direction
+    CSR_WIFI_SME_TRAFFIC_TYPE_PERIODIC
+                   - During the last 5 seconds there were at least 10 packets
+                     received each second and a defined period for the traffic
+                     can be recognized
+    CSR_WIFI_SME_TRAFFIC_TYPE_CONTINUOUS
+                   - During the last 5 seconds there were at least 20 packets
+                     received each second in either direction
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeTrafficType;
+#define CSR_WIFI_SME_TRAFFIC_TYPE_OCCASIONAL   ((CsrWifiSmeTrafficType) 0x00)
+#define CSR_WIFI_SME_TRAFFIC_TYPE_BURSTY       ((CsrWifiSmeTrafficType) 0x01)
+#define CSR_WIFI_SME_TRAFFIC_TYPE_PERIODIC     ((CsrWifiSmeTrafficType) 0x02)
+#define CSR_WIFI_SME_TRAFFIC_TYPE_CONTINUOUS   ((CsrWifiSmeTrafficType) 0x03)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeTspecCtrl
+
+  DESCRIPTION
+    Defines bits for CsrWifiSmeTspecCtrlMask for additional CCX configuration.
+    CURRENTLY NOT SUPPORTED.
+
+ VALUES
+    CSR_WIFI_SME_TSPEC_CTRL_STRICT
+                   - No automatic negotiation
+    CSR_WIFI_SME_TSPEC_CTRL_CCX_SIGNALLING
+                   - Signalling TSPEC
+    CSR_WIFI_SME_TSPEC_CTRL_CCX_VOICE
+                   - Voice traffic TSPEC
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeTspecCtrl;
+#define CSR_WIFI_SME_TSPEC_CTRL_STRICT           ((CsrWifiSmeTspecCtrl) 0x01)
+#define CSR_WIFI_SME_TSPEC_CTRL_CCX_SIGNALLING   ((CsrWifiSmeTspecCtrl) 0x02)
+#define CSR_WIFI_SME_TSPEC_CTRL_CCX_VOICE        ((CsrWifiSmeTspecCtrl) 0x04)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeTspecResultCode
+
+  DESCRIPTION
+    Defines the result of the TSPEC exchanges with the AP
+
+ VALUES
+    CSR_WIFI_SME_TSPEC_RESULT_SUCCESS
+                   - TSPEC command has been processed correctly
+    CSR_WIFI_SME_TSPEC_RESULT_UNSPECIFIED_QOS_FAILURE
+                   - The Access Point reported a failure
+    CSR_WIFI_SME_TSPEC_RESULT_FAILURE
+                   - Internal failure in the SME
+    CSR_WIFI_SME_TSPEC_RESULT_INVALID_TSPEC_PARAMETERS
+                   - The TSPEC parameters are invalid
+    CSR_WIFI_SME_TSPEC_RESULT_INVALID_TCLAS_PARAMETERS
+                   - The TCLASS parameters are invalid
+    CSR_WIFI_SME_TSPEC_RESULT_INSUFFICIENT_BANDWIDTH
+                   - As specified by the WMM Spec
+    CSR_WIFI_SME_TSPEC_RESULT_WRONG_POLICY
+                   - As specified by the WMM Spec
+    CSR_WIFI_SME_TSPEC_RESULT_REJECTED_WITH_SUGGESTED_CHANGES
+                   - As specified by the WMM Spec
+    CSR_WIFI_SME_TSPEC_RESULT_TIMEOUT
+                   - The TSPEC negotiation timed out
+    CSR_WIFI_SME_TSPEC_RESULT_NOT_SUPPORTED
+                   - The Access Point does not support the TSPEC
+    CSR_WIFI_SME_TSPEC_RESULT_IE_LENGTH_INCORRECT
+                   - The length of the TSPEC is not correct
+    CSR_WIFI_SME_TSPEC_RESULT_INVALID_TRANSACTION_ID
+                   - The TSPEC transaction id is not in the list
+    CSR_WIFI_SME_TSPEC_RESULT_INSTALLED
+                   - The TSPEC has been installed and it is now active.
+    CSR_WIFI_SME_TSPEC_RESULT_TID_ALREADY_INSTALLED
+                   - The Traffic ID has already been installed
+    CSR_WIFI_SME_TSPEC_RESULT_TSPEC_REMOTELY_DELETED
+                   - The AP has deleted the TSPEC
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeTspecResultCode;
+#define CSR_WIFI_SME_TSPEC_RESULT_SUCCESS                           ((CsrWifiSmeTspecResultCode) 0x00)
+#define CSR_WIFI_SME_TSPEC_RESULT_UNSPECIFIED_QOS_FAILURE           ((CsrWifiSmeTspecResultCode) 0x01)
+#define CSR_WIFI_SME_TSPEC_RESULT_FAILURE                           ((CsrWifiSmeTspecResultCode) 0x02)
+#define CSR_WIFI_SME_TSPEC_RESULT_INVALID_TSPEC_PARAMETERS          ((CsrWifiSmeTspecResultCode) 0x05)
+#define CSR_WIFI_SME_TSPEC_RESULT_INVALID_TCLAS_PARAMETERS          ((CsrWifiSmeTspecResultCode) 0x06)
+#define CSR_WIFI_SME_TSPEC_RESULT_INSUFFICIENT_BANDWIDTH            ((CsrWifiSmeTspecResultCode) 0x07)
+#define CSR_WIFI_SME_TSPEC_RESULT_WRONG_POLICY                      ((CsrWifiSmeTspecResultCode) 0x08)
+#define CSR_WIFI_SME_TSPEC_RESULT_REJECTED_WITH_SUGGESTED_CHANGES   ((CsrWifiSmeTspecResultCode) 0x09)
+#define CSR_WIFI_SME_TSPEC_RESULT_TIMEOUT                           ((CsrWifiSmeTspecResultCode) 0x0D)
+#define CSR_WIFI_SME_TSPEC_RESULT_NOT_SUPPORTED                     ((CsrWifiSmeTspecResultCode) 0x0E)
+#define CSR_WIFI_SME_TSPEC_RESULT_IE_LENGTH_INCORRECT               ((CsrWifiSmeTspecResultCode) 0x10)
+#define CSR_WIFI_SME_TSPEC_RESULT_INVALID_TRANSACTION_ID            ((CsrWifiSmeTspecResultCode) 0x11)
+#define CSR_WIFI_SME_TSPEC_RESULT_INSTALLED                         ((CsrWifiSmeTspecResultCode) 0x12)
+#define CSR_WIFI_SME_TSPEC_RESULT_TID_ALREADY_INSTALLED             ((CsrWifiSmeTspecResultCode) 0x13)
+#define CSR_WIFI_SME_TSPEC_RESULT_TSPEC_REMOTELY_DELETED            ((CsrWifiSmeTspecResultCode) 0x14)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWepAuthMode
+
+  DESCRIPTION
+    Define bits for CsrWifiSmeWepAuthMode
+
+ VALUES
+    CSR_WIFI_SME_WEP_AUTH_MODE_OPEN   - Open-WEP enabled network
+    CSR_WIFI_SME_WEP_AUTH_MODE_SHARED - Shared-key WEP enabled network.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeWepAuthMode;
+#define CSR_WIFI_SME_WEP_AUTH_MODE_OPEN     ((CsrWifiSmeWepAuthMode) 0x00)
+#define CSR_WIFI_SME_WEP_AUTH_MODE_SHARED   ((CsrWifiSmeWepAuthMode) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWepCredentialType
+
+  DESCRIPTION
+    Definition of types of WEP Credentials
+
+ VALUES
+    CSR_WIFI_SME_CREDENTIAL_TYPE_WEP64
+                   - WEP 64 credential
+    CSR_WIFI_SME_CREDENTIAL_TYPE_WEP128
+                   - WEP 128 credential
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeWepCredentialType;
+#define CSR_WIFI_SME_CREDENTIAL_TYPE_WEP64    ((CsrWifiSmeWepCredentialType) 0x00)
+#define CSR_WIFI_SME_CREDENTIAL_TYPE_WEP128   ((CsrWifiSmeWepCredentialType) 0x01)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWmmMode
+
+  DESCRIPTION
+    Defines bits for CsrWifiSmeWmmModeMask: enable/disable WMM features.
+
+ VALUES
+    CSR_WIFI_SME_WMM_MODE_DISABLED   - Disables the WMM features.
+    CSR_WIFI_SME_WMM_MODE_AC_ENABLED - Enables support for WMM-AC.
+    CSR_WIFI_SME_WMM_MODE_PS_ENABLED - Enables support for WMM Power Save.
+    CSR_WIFI_SME_WMM_MODE_SA_ENABLED - Currently not supported
+    CSR_WIFI_SME_WMM_MODE_ENABLED    - Enables support for all currently
+                                       available WMM features.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeWmmMode;
+#define CSR_WIFI_SME_WMM_MODE_DISABLED     ((CsrWifiSmeWmmMode) 0x00)
+#define CSR_WIFI_SME_WMM_MODE_AC_ENABLED   ((CsrWifiSmeWmmMode) 0x01)
+#define CSR_WIFI_SME_WMM_MODE_PS_ENABLED   ((CsrWifiSmeWmmMode) 0x02)
+#define CSR_WIFI_SME_WMM_MODE_SA_ENABLED   ((CsrWifiSmeWmmMode) 0x04)
+#define CSR_WIFI_SME_WMM_MODE_ENABLED      ((CsrWifiSmeWmmMode) 0xFF)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWmmQosInfo
+
+  DESCRIPTION
+    Defines bits for the QoS Info Octect as defined in the WMM specification.
+    The first four values define one bit each that can be set or cleared.
+    Each of the last four values define all the remaining 4 bits and only one
+    of them at the time shall be used.
+    For more information, see 'WMM (including WMM Power Save) Specification -
+    Version 1.1' and 'UniFi Configuring WMM and WMM-PS, Application Note'.
+
+ VALUES
+    CSR_WIFI_SME_WMM_QOS_INFO_AC_MAX_SP_ALL
+                   - WMM AP may deliver all buffered frames
+    CSR_WIFI_SME_WMM_QOS_INFO_AC_VO
+                   - Enable UAPSD(both trigger and delivery) for Voice Access
+                     Category
+    CSR_WIFI_SME_WMM_QOS_INFO_AC_VI
+                   - Enable UAPSD(both trigger and delivery) for  Video Access
+                     Category
+    CSR_WIFI_SME_WMM_QOS_INFO_AC_BK
+                   - Enable UAPSD(both trigger and delivery) for  Background
+                     Access Category
+    CSR_WIFI_SME_WMM_QOS_INFO_AC_BE
+                   - Enable UAPSD(both trigger and delivery) for  Best Effort
+                     Access Category
+    CSR_WIFI_SME_WMM_QOS_INFO_AC_MAX_SP_TWO
+                   - WMM AP may deliver a maximum of 2 buffered frames (MSDUs
+                     and MMPDUs) per USP
+    CSR_WIFI_SME_WMM_QOS_INFO_AC_MAX_SP_FOUR
+                   - WMM AP may deliver a maximum of 4 buffered frames (MSDUs
+                     and MMPDUs) per USP
+    CSR_WIFI_SME_WMM_QOS_INFO_AC_MAX_SP_SIX
+                   - WMM AP may deliver a maximum of 6 buffered frames (MSDUs
+                     and MMPDUs) per USP
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeWmmQosInfo;
+#define CSR_WIFI_SME_WMM_QOS_INFO_AC_MAX_SP_ALL    ((CsrWifiSmeWmmQosInfo) 0x00)
+#define CSR_WIFI_SME_WMM_QOS_INFO_AC_VO            ((CsrWifiSmeWmmQosInfo) 0x01)
+#define CSR_WIFI_SME_WMM_QOS_INFO_AC_VI            ((CsrWifiSmeWmmQosInfo) 0x02)
+#define CSR_WIFI_SME_WMM_QOS_INFO_AC_BK            ((CsrWifiSmeWmmQosInfo) 0x04)
+#define CSR_WIFI_SME_WMM_QOS_INFO_AC_BE            ((CsrWifiSmeWmmQosInfo) 0x08)
+#define CSR_WIFI_SME_WMM_QOS_INFO_AC_MAX_SP_TWO    ((CsrWifiSmeWmmQosInfo) 0x20)
+#define CSR_WIFI_SME_WMM_QOS_INFO_AC_MAX_SP_FOUR   ((CsrWifiSmeWmmQosInfo) 0x40)
+#define CSR_WIFI_SME_WMM_QOS_INFO_AC_MAX_SP_SIX    ((CsrWifiSmeWmmQosInfo) 0x60)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsConfigType
+
+  DESCRIPTION
+    WPS config methods supported/used by a device
+
+ VALUES
+    CSR_WIFI_WPS_CONFIG_LABEL
+                   - Label
+    CSR_WIFI_WPS_CONFIG_DISPLAY
+                   - Display
+    CSR_WIFI_WPS_CONFIG_EXT_NFC
+                   - External NFC : Not supported in this release
+    CSR_WIFI_WPS_CONFIG_INT_NFC
+                   - Internal NFC : Not supported in this release
+    CSR_WIFI_WPS_CONFIG_NFC_IFACE
+                   - NFC interface : Not supported in this release
+    CSR_WIFI_WPS_CONFIG_PBC
+                   - PBC
+    CSR_WIFI_WPS_CONFIG_KEYPAD
+                   - KeyPad
+    CSR_WIFI_WPS_CONFIG_VIRTUAL_PBC
+                   - PBC through software user interface
+    CSR_WIFI_WPS_CONFIG_PHYSICAL_PBC
+                   - Physical PBC
+    CSR_WIFI_WPS_CONFIG_VIRTUAL_DISPLAY
+                   - Virtual Display : via html config page etc
+    CSR_WIFI_WPS_CONFIG_PHYSICAL_DISPLAY
+                   - Physical Display : Attached to the device
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeWpsConfigType;
+#define CSR_WIFI_WPS_CONFIG_LABEL              ((CsrWifiSmeWpsConfigType) 0x0004)
+#define CSR_WIFI_WPS_CONFIG_DISPLAY            ((CsrWifiSmeWpsConfigType) 0x0008)
+#define CSR_WIFI_WPS_CONFIG_EXT_NFC            ((CsrWifiSmeWpsConfigType) 0x0010)
+#define CSR_WIFI_WPS_CONFIG_INT_NFC            ((CsrWifiSmeWpsConfigType) 0x0020)
+#define CSR_WIFI_WPS_CONFIG_NFC_IFACE          ((CsrWifiSmeWpsConfigType) 0x0040)
+#define CSR_WIFI_WPS_CONFIG_PBC                ((CsrWifiSmeWpsConfigType) 0x0080)
+#define CSR_WIFI_WPS_CONFIG_KEYPAD             ((CsrWifiSmeWpsConfigType) 0x0100)
+#define CSR_WIFI_WPS_CONFIG_VIRTUAL_PBC        ((CsrWifiSmeWpsConfigType) 0x0280)
+#define CSR_WIFI_WPS_CONFIG_PHYSICAL_PBC       ((CsrWifiSmeWpsConfigType) 0x0480)
+#define CSR_WIFI_WPS_CONFIG_VIRTUAL_DISPLAY    ((CsrWifiSmeWpsConfigType) 0x2008)
+#define CSR_WIFI_WPS_CONFIG_PHYSICAL_DISPLAY   ((CsrWifiSmeWpsConfigType) 0x4008)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsDeviceCategory
+
+  DESCRIPTION
+    Wps Primary Device Types
+
+ VALUES
+    CSR_WIFI_SME_WPS_CATEGORY_UNSPECIFIED
+                   - Unspecified.
+    CSR_WIFI_SME_WPS_CATEGORY_COMPUTER
+                   - Computer.
+    CSR_WIFI_SME_WPS_CATEGORY_INPUT_DEV
+                   - Input device
+    CSR_WIFI_SME_WPS_CATEGORY_PRT_SCAN_FX_CP
+                   - Printer Scanner Fax Copier etc
+    CSR_WIFI_SME_WPS_CATEGORY_CAMERA
+                   - Camera
+    CSR_WIFI_SME_WPS_CATEGORY_STORAGE
+                   - Storage
+    CSR_WIFI_SME_WPS_CATEGORY_NET_INFRA
+                   - Net Infra
+    CSR_WIFI_SME_WPS_CATEGORY_DISPLAY
+                   - Display
+    CSR_WIFI_SME_WPS_CATEGORY_MULTIMEDIA
+                   - Multimedia
+    CSR_WIFI_SME_WPS_CATEGORY_GAMING
+                   - Gaming.
+    CSR_WIFI_SME_WPS_CATEGORY_TELEPHONE
+                   - Telephone.
+    CSR_WIFI_SME_WPS_CATEGORY_AUDIO
+                   - Audio
+    CSR_WIFI_SME_WPS_CATEOARY_OTHERS
+                   - Others.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeWpsDeviceCategory;
+#define CSR_WIFI_SME_WPS_CATEGORY_UNSPECIFIED      ((CsrWifiSmeWpsDeviceCategory) 0x00)
+#define CSR_WIFI_SME_WPS_CATEGORY_COMPUTER         ((CsrWifiSmeWpsDeviceCategory) 0x01)
+#define CSR_WIFI_SME_WPS_CATEGORY_INPUT_DEV        ((CsrWifiSmeWpsDeviceCategory) 0x02)
+#define CSR_WIFI_SME_WPS_CATEGORY_PRT_SCAN_FX_CP   ((CsrWifiSmeWpsDeviceCategory) 0x03)
+#define CSR_WIFI_SME_WPS_CATEGORY_CAMERA           ((CsrWifiSmeWpsDeviceCategory) 0x04)
+#define CSR_WIFI_SME_WPS_CATEGORY_STORAGE          ((CsrWifiSmeWpsDeviceCategory) 0x05)
+#define CSR_WIFI_SME_WPS_CATEGORY_NET_INFRA        ((CsrWifiSmeWpsDeviceCategory) 0x06)
+#define CSR_WIFI_SME_WPS_CATEGORY_DISPLAY          ((CsrWifiSmeWpsDeviceCategory) 0x07)
+#define CSR_WIFI_SME_WPS_CATEGORY_MULTIMEDIA       ((CsrWifiSmeWpsDeviceCategory) 0x08)
+#define CSR_WIFI_SME_WPS_CATEGORY_GAMING           ((CsrWifiSmeWpsDeviceCategory) 0x09)
+#define CSR_WIFI_SME_WPS_CATEGORY_TELEPHONE        ((CsrWifiSmeWpsDeviceCategory) 0x0A)
+#define CSR_WIFI_SME_WPS_CATEGORY_AUDIO            ((CsrWifiSmeWpsDeviceCategory) 0x0B)
+#define CSR_WIFI_SME_WPS_CATEOARY_OTHERS           ((CsrWifiSmeWpsDeviceCategory) 0xFF)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsDeviceSubCategory
+
+  DESCRIPTION
+    Wps Secondary Device Types
+
+ VALUES
+    CSR_WIFI_SME_WPS_SUB_CATEGORY_UNSPECIFIED
+                   - Unspecied
+    CSR_WIFI_SME_WPS_STORAGE_SUB_CATEGORY_NAS
+                   - Network Associated Storage
+    CSR_WIFI_SME_WPS_PSFC_SUB_CATEGORY_PRNTR
+                   - Printer or print server
+    CSR_WIFI_SME_WPS_TELEPHONE_SUB_CATEGORY_WM
+                   - Windows mobile
+    CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_TUNER
+                   - Audio tuner/receiver
+    CSR_WIFI_SME_WPS_CAMERA_SUB_CATEGORY_DIG_STL
+                   - Digital still camera
+    CSR_WIFI_SME_WPS_NET_INFRA_SUB_CATEGORY_AP
+                   - Access Point
+    CSR_WIFI_SME_WPS_DISPLAY_SUB_CATEGORY_TV
+                   - TV.
+    CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_DAR
+                   - DAR.
+    CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_KEYBD
+                   - Keyboard.
+    CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_PC
+                   - PC.
+    CSR_WIFI_SME_WPS_GAMING_SUB_CATEGORY_XBOX
+                   - Xbox.
+    CSR_WIFI_SME_WPS_PSFC_SUB_CATEGORY_SCNR
+                   - Scanner
+    CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_SERVER
+                   - Server
+    CSR_WIFI_SME_WPS_NET_INFRA_SUB_CATEGORY_ROUTER
+                   - Router
+    CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_PVR
+                   - PVR
+    CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_SPEAKER
+                   - Speaker
+    CSR_WIFI_SME_WPS_TELEPHONE_SUB_CATEGORY_FP_SM
+                   - Feature phone - Single mode
+    CSR_WIFI_SME_WPS_CAMERA_SUB_CATEGORY_VIDEO
+                   - Video camera
+    CSR_WIFI_SME_WPS_DISPLAY_SUB_CATEGORY_PIC_FRM
+                   - Picture frame
+    CSR_WIFI_SME_WPS_GAMING_SUB_CATEGORY_XBOX_360
+                   - Xbox360
+    CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_MOUSE
+                   - Mouse
+    CSR_WIFI_SME_WPS_NET_INFRA_SUB_CATEGORY_SWITCH
+                   - Switch
+    CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_PMP
+                   - Portable music player
+    CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_JOYSTK
+                   - Joy stick
+    CSR_WIFI_SME_WPS_GAMING_SUB_CATEGORY_PLAY_STN
+                   - Play-station
+    CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_MED_CENT
+                   - Media Center
+    CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_MCX
+                   - MCX
+    CSR_WIFI_SME_WPS_TELEPHONE_SUB_CATEGORY_FP_DM
+                   - Feature phone - Dual mode
+    CSR_WIFI_SME_WPS_CAMERA_SUB_CATEGORY_WEB
+                   - Web camera
+    CSR_WIFI_SME_WPS_PSFC_SUB_CATEGORY_FAX
+                   - Fax
+    CSR_WIFI_SME_WPS_DISPLAY_SUB_CATEGORY_PROJECTOR
+                   - Projector
+    CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_TRKBL
+                   - Track Ball
+    CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_ST_BOX
+                   - Set-Top-Box
+    CSR_WIFI_SME_WPS_NET_INFRA_SUB_CATEGORY_GATEWAY
+                   - GateWay.
+    CSR_WIFI_SME_WPS_CAMERA_SUB_CATEGORY_SECURITY
+                   - Security camera
+    CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_ULTRA_MOB_PC
+                   - Ultra mobile PC.
+    CSR_WIFI_SME_WPS_GAMING_SUB_CATEGORY_CONSOLE
+                   - Game console/Game console adapter
+    CSR_WIFI_SME_WPS_PSFC_SUB_CATEGORY_CPR
+                   - Copier
+    CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_HEADSET
+                   - Headset(headphones + microphone)
+    CSR_WIFI_SME_WPS_TELEPHONE_SUB_CATEGORY_SP_SM
+                   - Smart phone - Single mode
+    CSR_WIFI_SME_WPS_DISPLAY_SUB_CATEGORY_MONITOR
+                   - Monitor.
+    CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_GAME_CTRL
+                   - Game control.
+    CSR_WIFI_SME_WPS_PSFC_SUB_CATEGORY_ALL
+                   - All-in-One
+    CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_MEDIA
+                   - Media Server/Media Adapter/Media Extender
+    CSR_WIFI_SME_WPS_TELEPHONE_SUB_CATEGORY_SP_DM
+                   - Smart phone - Dual mode
+    CSR_WIFI_SME_WPS_GAMING_SUB_CATEGORY_PORT_DEV
+                   - Portable gaming device
+    CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_HEADPHONE
+                   - Headphone.
+    CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_NOTEBOOK
+                   - Notebook.
+    CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_REMOTE
+                   - Remote control
+    CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_MIC
+                   - Microphone
+    CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_DESKTOP
+                   - Desktop.
+    CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_VP
+                   - Portable video player
+    CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_MID
+                   - Mobile internet device
+    CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_TOUCH_SCRN
+                   - Touch screen
+    CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_BIOMET_RDR
+                   - Biometric reader
+    CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_NETBOOK
+                   - Netbook
+    CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_BRCD_RDR
+                   - Bar code reader.
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeWpsDeviceSubCategory;
+#define CSR_WIFI_SME_WPS_SUB_CATEGORY_UNSPECIFIED             ((CsrWifiSmeWpsDeviceSubCategory) 0x00)
+#define CSR_WIFI_SME_WPS_STORAGE_SUB_CATEGORY_NAS             ((CsrWifiSmeWpsDeviceSubCategory) 0x01)
+#define CSR_WIFI_SME_WPS_PSFC_SUB_CATEGORY_PRNTR              ((CsrWifiSmeWpsDeviceSubCategory) 0x01)
+#define CSR_WIFI_SME_WPS_TELEPHONE_SUB_CATEGORY_WM            ((CsrWifiSmeWpsDeviceSubCategory) 0x01)
+#define CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_TUNER             ((CsrWifiSmeWpsDeviceSubCategory) 0x01)
+#define CSR_WIFI_SME_WPS_CAMERA_SUB_CATEGORY_DIG_STL          ((CsrWifiSmeWpsDeviceSubCategory) 0x01)
+#define CSR_WIFI_SME_WPS_NET_INFRA_SUB_CATEGORY_AP            ((CsrWifiSmeWpsDeviceSubCategory) 0x01)
+#define CSR_WIFI_SME_WPS_DISPLAY_SUB_CATEGORY_TV              ((CsrWifiSmeWpsDeviceSubCategory) 0x01)
+#define CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_DAR                  ((CsrWifiSmeWpsDeviceSubCategory) 0x01)
+#define CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_KEYBD         ((CsrWifiSmeWpsDeviceSubCategory) 0x01)
+#define CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_PC             ((CsrWifiSmeWpsDeviceSubCategory) 0x01)
+#define CSR_WIFI_SME_WPS_GAMING_SUB_CATEGORY_XBOX             ((CsrWifiSmeWpsDeviceSubCategory) 0x01)
+#define CSR_WIFI_SME_WPS_PSFC_SUB_CATEGORY_SCNR               ((CsrWifiSmeWpsDeviceSubCategory) 0x02)
+#define CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_SERVER         ((CsrWifiSmeWpsDeviceSubCategory) 0x02)
+#define CSR_WIFI_SME_WPS_NET_INFRA_SUB_CATEGORY_ROUTER        ((CsrWifiSmeWpsDeviceSubCategory) 0x02)
+#define CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_PVR                  ((CsrWifiSmeWpsDeviceSubCategory) 0x02)
+#define CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_SPEAKER           ((CsrWifiSmeWpsDeviceSubCategory) 0x02)
+#define CSR_WIFI_SME_WPS_TELEPHONE_SUB_CATEGORY_FP_SM         ((CsrWifiSmeWpsDeviceSubCategory) 0x02)
+#define CSR_WIFI_SME_WPS_CAMERA_SUB_CATEGORY_VIDEO            ((CsrWifiSmeWpsDeviceSubCategory) 0x02)
+#define CSR_WIFI_SME_WPS_DISPLAY_SUB_CATEGORY_PIC_FRM         ((CsrWifiSmeWpsDeviceSubCategory) 0x02)
+#define CSR_WIFI_SME_WPS_GAMING_SUB_CATEGORY_XBOX_360         ((CsrWifiSmeWpsDeviceSubCategory) 0x02)
+#define CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_MOUSE         ((CsrWifiSmeWpsDeviceSubCategory) 0x02)
+#define CSR_WIFI_SME_WPS_NET_INFRA_SUB_CATEGORY_SWITCH        ((CsrWifiSmeWpsDeviceSubCategory) 0x03)
+#define CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_PMP               ((CsrWifiSmeWpsDeviceSubCategory) 0x03)
+#define CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_JOYSTK        ((CsrWifiSmeWpsDeviceSubCategory) 0x03)
+#define CSR_WIFI_SME_WPS_GAMING_SUB_CATEGORY_PLAY_STN         ((CsrWifiSmeWpsDeviceSubCategory) 0x03)
+#define CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_MED_CENT       ((CsrWifiSmeWpsDeviceSubCategory) 0x03)
+#define CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_MCX                  ((CsrWifiSmeWpsDeviceSubCategory) 0x03)
+#define CSR_WIFI_SME_WPS_TELEPHONE_SUB_CATEGORY_FP_DM         ((CsrWifiSmeWpsDeviceSubCategory) 0x03)
+#define CSR_WIFI_SME_WPS_CAMERA_SUB_CATEGORY_WEB              ((CsrWifiSmeWpsDeviceSubCategory) 0x03)
+#define CSR_WIFI_SME_WPS_PSFC_SUB_CATEGORY_FAX                ((CsrWifiSmeWpsDeviceSubCategory) 0x03)
+#define CSR_WIFI_SME_WPS_DISPLAY_SUB_CATEGORY_PROJECTOR       ((CsrWifiSmeWpsDeviceSubCategory) 0x03)
+#define CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_TRKBL         ((CsrWifiSmeWpsDeviceSubCategory) 0x04)
+#define CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_ST_BOX               ((CsrWifiSmeWpsDeviceSubCategory) 0x04)
+#define CSR_WIFI_SME_WPS_NET_INFRA_SUB_CATEGORY_GATEWAY       ((CsrWifiSmeWpsDeviceSubCategory) 0x04)
+#define CSR_WIFI_SME_WPS_CAMERA_SUB_CATEGORY_SECURITY         ((CsrWifiSmeWpsDeviceSubCategory) 0x04)
+#define CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_ULTRA_MOB_PC   ((CsrWifiSmeWpsDeviceSubCategory) 0x04)
+#define CSR_WIFI_SME_WPS_GAMING_SUB_CATEGORY_CONSOLE          ((CsrWifiSmeWpsDeviceSubCategory) 0x04)
+#define CSR_WIFI_SME_WPS_PSFC_SUB_CATEGORY_CPR                ((CsrWifiSmeWpsDeviceSubCategory) 0x04)
+#define CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_HEADSET           ((CsrWifiSmeWpsDeviceSubCategory) 0x04)
+#define CSR_WIFI_SME_WPS_TELEPHONE_SUB_CATEGORY_SP_SM         ((CsrWifiSmeWpsDeviceSubCategory) 0x04)
+#define CSR_WIFI_SME_WPS_DISPLAY_SUB_CATEGORY_MONITOR         ((CsrWifiSmeWpsDeviceSubCategory) 0x04)
+#define CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_GAME_CTRL     ((CsrWifiSmeWpsDeviceSubCategory) 0x05)
+#define CSR_WIFI_SME_WPS_PSFC_SUB_CATEGORY_ALL                ((CsrWifiSmeWpsDeviceSubCategory) 0x05)
+#define CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_MEDIA                ((CsrWifiSmeWpsDeviceSubCategory) 0x05)
+#define CSR_WIFI_SME_WPS_TELEPHONE_SUB_CATEGORY_SP_DM         ((CsrWifiSmeWpsDeviceSubCategory) 0x05)
+#define CSR_WIFI_SME_WPS_GAMING_SUB_CATEGORY_PORT_DEV         ((CsrWifiSmeWpsDeviceSubCategory) 0x05)
+#define CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_HEADPHONE         ((CsrWifiSmeWpsDeviceSubCategory) 0x05)
+#define CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_NOTEBOOK       ((CsrWifiSmeWpsDeviceSubCategory) 0x05)
+#define CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_REMOTE        ((CsrWifiSmeWpsDeviceSubCategory) 0x06)
+#define CSR_WIFI_SME_WPS_AUDIO_SUB_CATEGORY_MIC               ((CsrWifiSmeWpsDeviceSubCategory) 0x06)
+#define CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_DESKTOP        ((CsrWifiSmeWpsDeviceSubCategory) 0x06)
+#define CSR_WIFI_SME_WPS_MM_SUB_CATEGORY_VP                   ((CsrWifiSmeWpsDeviceSubCategory) 0x06)
+#define CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_MID            ((CsrWifiSmeWpsDeviceSubCategory) 0x07)
+#define CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_TOUCH_SCRN    ((CsrWifiSmeWpsDeviceSubCategory) 0x07)
+#define CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_BIOMET_RDR    ((CsrWifiSmeWpsDeviceSubCategory) 0x08)
+#define CSR_WIFI_SME_WPS_COMPUTER_SUB_CATEGORY_NETBOOK        ((CsrWifiSmeWpsDeviceSubCategory) 0x08)
+#define CSR_WIFI_SME_WPS_INPUT_DEV_SUB_CATEGORY_BRCD_RDR      ((CsrWifiSmeWpsDeviceSubCategory) 0x09)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsDpid
+
+  DESCRIPTION
+    Device Password ID for the chosen config method
+
+ VALUES
+    CSR_WIFI_SME_WPS_DPID_PIN       - PIN
+    CSR_WIFI_SME_WPS_DPID_USER      - User specified : Used only during P2P GO
+                                      negotiation procedure
+    CSR_WIFI_SME_WPS_DPID_MACHINE   - Machine specified i: Not used in this
+                                      release
+    CSR_WIFI_SME_WPS_DPID_REKEY     - Rekey : Not used in this release
+    CSR_WIFI_SME_WPS_DPID_PBC       - PBC
+    CSR_WIFI_SME_WPS_DPID_REGISTRAR - Registrar specified : Used only in P2P Go
+                                      negotiation procedure
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeWpsDpid;
+#define CSR_WIFI_SME_WPS_DPID_PIN         ((CsrWifiSmeWpsDpid) 0x0000)
+#define CSR_WIFI_SME_WPS_DPID_USER        ((CsrWifiSmeWpsDpid) 0x0001)
+#define CSR_WIFI_SME_WPS_DPID_MACHINE     ((CsrWifiSmeWpsDpid) 0x0002)
+#define CSR_WIFI_SME_WPS_DPID_REKEY       ((CsrWifiSmeWpsDpid) 0x0003)
+#define CSR_WIFI_SME_WPS_DPID_PBC         ((CsrWifiSmeWpsDpid) 0x0004)
+#define CSR_WIFI_SME_WPS_DPID_REGISTRAR   ((CsrWifiSmeWpsDpid) 0x0005)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsRegistration
+
+  DESCRIPTION
+
+ VALUES
+    CSR_WIFI_SME_WPS_REG_NOT_REQUIRED - No encryption set
+    CSR_WIFI_SME_WPS_REG_REQUIRED     - No encryption set
+    CSR_WIFI_SME_WPS_REG_UNKNOWN      - No encryption set
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeWpsRegistration;
+#define CSR_WIFI_SME_WPS_REG_NOT_REQUIRED   ((CsrWifiSmeWpsRegistration) 0x00)
+#define CSR_WIFI_SME_WPS_REG_REQUIRED       ((CsrWifiSmeWpsRegistration) 0x01)
+#define CSR_WIFI_SME_WPS_REG_UNKNOWN        ((CsrWifiSmeWpsRegistration) 0x02)
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAuthModeMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeAuthMode
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeAuthModeMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeEncryptionMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeEncryption
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeEncryptionMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeIndicationsMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeIndications
+
+*******************************************************************************/
+typedef CsrUint32 CsrWifiSmeIndicationsMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeP2pCapabilityMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeP2pCapability
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeP2pCapabilityMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeP2pGroupCapabilityMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeP2pGroupCapability
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeP2pGroupCapabilityMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeTspecCtrlMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeTspecCtrl
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeTspecCtrlMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWmmModeMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeWmmMode
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeWmmModeMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWmmQosInfoMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeWmmQosInfo
+
+*******************************************************************************/
+typedef CsrUint8 CsrWifiSmeWmmQosInfoMask;
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsConfigTypeMask
+
+  DESCRIPTION
+    Mask type for use with the values defined by CsrWifiSmeWpsConfigType
+
+*******************************************************************************/
+typedef CsrUint16 CsrWifiSmeWpsConfigTypeMask;
+
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAdHocConfig
+
+  DESCRIPTION
+    Defines values to use when starting an Ad-hoc (IBSS) network.
+
+  MEMBERS
+    atimWindowTu          - ATIM window specified for IBSS
+    beaconPeriodTu        - Interval between beacon packets
+    joinOnlyAttempts      - Maximum number of attempts to join an ad-hoc network.
+                            The default value is 1.
+                            Set to 0 for infinite attempts.
+    joinAttemptIntervalMs - Time between scans for joining the requested IBSS.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint16 atimWindowTu;
+    CsrUint16 beaconPeriodTu;
+    CsrUint16 joinOnlyAttempts;
+    CsrUint16 joinAttemptIntervalMs;
+} CsrWifiSmeAdHocConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAvailabilityConfig
+
+  DESCRIPTION
+
+  MEMBERS
+    listenChannel        -
+    availabilityDuration -
+    avalabilityPeriod    -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8  listenChannel;
+    CsrUint16 availabilityDuration;
+    CsrUint16 avalabilityPeriod;
+} CsrWifiSmeAvailabilityConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCcxConfig
+
+  DESCRIPTION
+    This type is reserved for future use and should not be used.
+
+  MEMBERS
+    keepAliveTimeMs    - NOT USED
+    apRoamingEnabled   - NOT USED
+    measurementsMask   - NOT USED
+    ccxRadioMgtEnabled - NOT USED
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8 keepAliveTimeMs;
+    CsrBool  apRoamingEnabled;
+    CsrUint8 measurementsMask;
+    CsrBool  ccxRadioMgtEnabled;
+} CsrWifiSmeCcxConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexConfig
+
+  DESCRIPTION
+    Parameters for the coexistence behaviour.
+
+  MEMBERS
+    coexEnableSchemeManagement     - Enables the Coexistence Management Scheme
+    coexPeriodicWakeHost           - If TRUE the firmware wakes up the host
+                                     periodically according to the traffic
+                                     period and latency parameters; the host
+                                     will then send the data to transmit only
+                                     when woken up.
+                                     If FALSE, the firmware does not wake up the
+                                     host and the host will send the data to
+                                     transmit to the firmware whenever there is
+                                     data to transmit
+    coexTrafficBurstyLatencyMs     - Period of awakening for the firmware used
+                                     when bursty traffic is detected
+    coexTrafficContinuousLatencyMs - Period of awakening for the firmware used
+                                     when continuous traffic is detected
+    coexObexBlackoutDurationMs     - Blackout Duration when a Obex Connection is
+                                     used
+    coexObexBlackoutPeriodMs       - Blackout Period when a Obex Connection is
+                                     used
+    coexA2dpBrBlackoutDurationMs   - Blackout Duration when a Basic Rate A2DP
+                                     Connection streaming data
+    coexA2dpBrBlackoutPeriodMs     - Blackout Period when a Basic Rate A2DP
+                                     Connection streaming data
+    coexA2dpEdrBlackoutDurationMs  - Blackout Duration when an Enhanced Data
+                                     Rate A2DP Connection streaming data
+    coexA2dpEdrBlackoutPeriodMs    - Blackout Period when an Enhanced Data Rate
+                                     A2DP Connection streaming data
+    coexPagingBlackoutDurationMs   - Blackout Duration when a BT page is active
+    coexPagingBlackoutPeriodMs     - Blackout Period when a BT page is active
+    coexInquiryBlackoutDurationMs  - Blackout Duration when a BT inquiry is
+                                     active
+    coexInquiryBlackoutPeriodMs    - Blackout Period when a BT inquiry is active
+
+*******************************************************************************/
+typedef struct
+{
+    CsrBool   coexEnableSchemeManagement;
+    CsrBool   coexPeriodicWakeHost;
+    CsrUint16 coexTrafficBurstyLatencyMs;
+    CsrUint16 coexTrafficContinuousLatencyMs;
+    CsrUint16 coexObexBlackoutDurationMs;
+    CsrUint16 coexObexBlackoutPeriodMs;
+    CsrUint16 coexA2dpBrBlackoutDurationMs;
+    CsrUint16 coexA2dpBrBlackoutPeriodMs;
+    CsrUint16 coexA2dpEdrBlackoutDurationMs;
+    CsrUint16 coexA2dpEdrBlackoutPeriodMs;
+    CsrUint16 coexPagingBlackoutDurationMs;
+    CsrUint16 coexPagingBlackoutPeriodMs;
+    CsrUint16 coexInquiryBlackoutDurationMs;
+    CsrUint16 coexInquiryBlackoutPeriodMs;
+} CsrWifiSmeCoexConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionStats
+
+  DESCRIPTION
+    Indicates the statistics of the connection.
+    The dot11 fields are defined in the Annex D of the IEEE 802.11 standard.
+
+  MEMBERS
+    unifiTxDataRate
+                   - The bit rate currently in use for transmissions of unicast
+                     data frames; a data rate in units of 500kbit/s.
+                     On an infrastructure BSS, this is the data rate used in
+                     communicating with the associated access point; if there is
+                     none, an error is returned.
+                     On an IBSS, this is the data rate used for the last
+                     transmission of a unicast data frame to any station in the
+                     IBSS. If no such transmission has been made, an error is
+                     returned.
+    unifiRxDataRate
+                   - As above for receiving data
+    dot11RetryCount
+                   - See IEEE 802.11 Standard
+    dot11MultipleRetryCount
+                   - See IEEE 802.11 Standard
+    dot11AckFailureCount
+                   - See IEEE 802.11 Standard
+    dot11FrameDuplicateCount
+                   - See IEEE 802.11 Standard
+    dot11FcsErrorCount
+                   - See IEEE 802.11 Standard
+    dot11RtsSuccessCount
+                   - See IEEE 802.11 Standard
+    dot11RtsFailureCount
+                   - See IEEE 802.11 Standard
+    dot11FailedCount
+                   - See IEEE 802.11 Standard
+    dot11TransmittedFragmentCount
+                   - See IEEE 802.11 Standard
+    dot11TransmittedFrameCount
+                   - See IEEE 802.11 Standard
+    dot11WepExcludedCount
+                   - See IEEE 802.11 Standard
+    dot11WepIcvErrorCount
+                   - See IEEE 802.11 Standard
+    dot11WepUndecryptableCount
+                   - See IEEE 802.11 Standard
+    dot11MulticastReceivedFrameCount
+                   - See IEEE 802.11 Standard
+    dot11MulticastTransmittedFrameCount
+                   - See IEEE 802.11 Standard
+    dot11ReceivedFragmentCount
+                   - See IEEE 802.11 Standard
+    dot11Rsna4WayHandshakeFailures
+                   - See IEEE 802.11 Standard
+    dot11RsnaTkipCounterMeasuresInvoked
+                   - See IEEE 802.11 Standard
+    dot11RsnaStatsTkipLocalMicFailures
+                   - See IEEE 802.11 Standard
+    dot11RsnaStatsTkipReplays
+                   - See IEEE 802.11 Standard
+    dot11RsnaStatsTkipIcvErrors
+                   - See IEEE 802.11 Standard
+    dot11RsnaStatsCcmpReplays
+                   - See IEEE 802.11 Standard
+    dot11RsnaStatsCcmpDecryptErrors
+                   - See IEEE 802.11 Standard
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8  unifiTxDataRate;
+    CsrUint8  unifiRxDataRate;
+    CsrUint32 dot11RetryCount;
+    CsrUint32 dot11MultipleRetryCount;
+    CsrUint32 dot11AckFailureCount;
+    CsrUint32 dot11FrameDuplicateCount;
+    CsrUint32 dot11FcsErrorCount;
+    CsrUint32 dot11RtsSuccessCount;
+    CsrUint32 dot11RtsFailureCount;
+    CsrUint32 dot11FailedCount;
+    CsrUint32 dot11TransmittedFragmentCount;
+    CsrUint32 dot11TransmittedFrameCount;
+    CsrUint32 dot11WepExcludedCount;
+    CsrUint32 dot11WepIcvErrorCount;
+    CsrUint32 dot11WepUndecryptableCount;
+    CsrUint32 dot11MulticastReceivedFrameCount;
+    CsrUint32 dot11MulticastTransmittedFrameCount;
+    CsrUint32 dot11ReceivedFragmentCount;
+    CsrUint32 dot11Rsna4WayHandshakeFailures;
+    CsrUint32 dot11RsnaTkipCounterMeasuresInvoked;
+    CsrUint32 dot11RsnaStatsTkipLocalMicFailures;
+    CsrUint32 dot11RsnaStatsTkipReplays;
+    CsrUint32 dot11RsnaStatsTkipIcvErrors;
+    CsrUint32 dot11RsnaStatsCcmpReplays;
+    CsrUint32 dot11RsnaStatsCcmpDecryptErrors;
+} CsrWifiSmeConnectionStats;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDataBlock
+
+  DESCRIPTION
+    Holds a generic data block to be passed through the interface
+
+  MEMBERS
+    length - Length of the data block
+    data   - Points to the first byte of the data block
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint16 length;
+    CsrUint8 *data;
+} CsrWifiSmeDataBlock;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeEmpty
+
+  DESCRIPTION
+    Empty Structure to indicate that no parameters are available.
+
+  MEMBERS
+    empty  - Only element of the empty structure (always set to 0).
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8 empty;
+} CsrWifiSmeEmpty;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeLinkQuality
+
+  DESCRIPTION
+    Indicates the quality of the link
+
+  MEMBERS
+    unifiRssi - Indicates the received signal strength indication of the link in
+                dBm
+    unifiSnr  - Indicates the signal to noise ratio of the link in dB
+
+*******************************************************************************/
+typedef struct
+{
+    CsrInt16 unifiRssi;
+    CsrInt16 unifiSnr;
+} CsrWifiSmeLinkQuality;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibConfig
+
+  DESCRIPTION
+    Allows low level configuration in the chip.
+
+  MEMBERS
+    unifiFixMaxTxDataRate       - This attribute is used in combination with
+                                  unifiFixTxDataRate. If it is FALSE, then
+                                  unifiFixTxDataRate specifies a specific data
+                                  rate to use. If it is TRUE, unifiFixTxDataRate
+                                  instead specifies a maximum data rate.
+    unifiFixTxDataRate          - Transmit rate for unicast data.
+                                  See MIB description for more details
+    dot11RtsThreshold           - See IEEE 802.11 Standard
+    dot11FragmentationThreshold - See IEEE 802.11 Standard
+    dot11CurrentTxPowerLevel    - See IEEE 802.11 Standard
+
+*******************************************************************************/
+typedef struct
+{
+    CsrBool   unifiFixMaxTxDataRate;
+    CsrUint8  unifiFixTxDataRate;
+    CsrUint16 dot11RtsThreshold;
+    CsrUint16 dot11FragmentationThreshold;
+    CsrUint16 dot11CurrentTxPowerLevel;
+} CsrWifiSmeMibConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeP2pProfileIdentity
+
+  DESCRIPTION
+    Details to be filled in
+
+  MEMBERS
+    listenChannel        -
+    availabilityDuration -
+    avalabilityPeriod    -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8  listenChannel;
+    CsrUint16 availabilityDuration;
+    CsrUint16 avalabilityPeriod;
+} CsrWifiSmeP2pProfileIdentity;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePmkid
+
+  DESCRIPTION
+    Defines a PMKID association with BSS
+
+  MEMBERS
+    bssid  - BSS identifier
+    pmkid  - PMKID
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiMacAddress bssid;
+    CsrUint8          pmkid[16];
+} CsrWifiSmePmkid;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePmkidCandidate
+
+  DESCRIPTION
+    Information for a PMKID candidate
+
+  MEMBERS
+    bssid          - BSS identifier
+    preAuthAllowed - Indicates whether preauthentication is allowed
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiMacAddress bssid;
+    CsrBool           preAuthAllowed;
+} CsrWifiSmePmkidCandidate;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePmkidList
+
+  DESCRIPTION
+    NOT USED
+    Used in the Sync access API
+
+  MEMBERS
+    pmkidsCount - Number of PMKIDs in the list
+    pmkids      - Points to the first PMKID in the list
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8         pmkidsCount;
+    CsrWifiSmePmkid *pmkids;
+} CsrWifiSmePmkidList;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRegulatoryDomainInfo
+
+  DESCRIPTION
+    Regulatory domain options.
+
+  MEMBERS
+    dot11MultiDomainCapabilityImplemented
+                   - TRUE is the multi domain capability is implemented
+    dot11MultiDomainCapabilityEnabled
+                   - TRUE is the multi domain capability is enabled
+    currentRegulatoryDomain
+                   - Current regulatory domain
+    currentCountryCode
+                   - Current country code as defined by the IEEE 802.11
+                     standards
+
+*******************************************************************************/
+typedef struct
+{
+    CsrBool                    dot11MultiDomainCapabilityImplemented;
+    CsrBool                    dot11MultiDomainCapabilityEnabled;
+    CsrWifiSmeRegulatoryDomain currentRegulatoryDomain;
+    CsrUint8                   currentCountryCode[2];
+} CsrWifiSmeRegulatoryDomainInfo;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamingBandData
+
+  DESCRIPTION
+    Thresholds to define one usability level category for the received signal
+
+  MEMBERS
+    rssiHighThreshold - Received Signal Strength Indication upper bound in dBm
+                        for the usability level
+    rssiLowThreshold  - Received Signal Strength Indication lower bound in dBm
+                        for the usability level
+    snrHighThreshold  - Signal to Noise Ratio upper bound in dB for the
+                        usability level
+    snrLowThreshold   - Signal to Noise Ratio lower bound in dB for the
+                        usability level
+
+*******************************************************************************/
+typedef struct
+{
+    CsrInt16 rssiHighThreshold;
+    CsrInt16 rssiLowThreshold;
+    CsrInt16 snrHighThreshold;
+    CsrInt16 snrLowThreshold;
+} CsrWifiSmeRoamingBandData;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanConfigData
+
+  DESCRIPTION
+    Configures the scanning behaviour of the driver and firmware
+
+  MEMBERS
+    intervalSeconds         - All the channels will be scanned once in this time
+                              interval.
+                              If connected, the channel scans are spread across
+                              the interval.
+                              If disconnected, all the channels will be scanned
+                              together
+    validitySeconds         - How long the scan result are cached
+    minActiveChannelTimeTu  - Minimum time of listening on a channel being
+                              actively scanned before leaving if no probe
+                              responses or beacon frames have been received
+    maxActiveChannelTimeTu  - Maximum time of listening on a channel being
+                              actively scanned
+    minPassiveChannelTimeTu - Minimum time of listening on a channel being
+                              passive scanned before leaving if no beacon frames
+                              have been received
+    maxPassiveChannelTimeTu - Maximum time of listening on a channel being
+                              passively scanned
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint16 intervalSeconds;
+    CsrUint16 validitySeconds;
+    CsrUint16 minActiveChannelTimeTu;
+    CsrUint16 maxActiveChannelTimeTu;
+    CsrUint16 minPassiveChannelTimeTu;
+    CsrUint16 maxPassiveChannelTimeTu;
+} CsrWifiSmeScanConfigData;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeTsfTime
+
+  DESCRIPTION
+    Time stamp representation
+
+  MEMBERS
+    data   - TSF Bytes
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8 data[8];
+} CsrWifiSmeTsfTime;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeVersions
+
+  DESCRIPTION
+    Reports version information for the chip, the firmware and the driver and
+    the SME.
+
+  MEMBERS
+    chipId        - Chip ID
+    chipVersion   - Chip version ID
+    firmwareBuild - Firmware Rom build number
+    firmwarePatch - Firmware Patch build number (if applicable)
+    firmwareHip   - Firmware HIP protocol version number
+    routerBuild   - Router build number
+    routerHip     - Router HIP protocol version number
+    smeBuild      - SME build number
+    smeHip        - SME HIP protocol version number
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint32      chipId;
+    CsrUint32      chipVersion;
+    CsrUint32      firmwareBuild;
+    CsrUint32      firmwarePatch;
+    CsrUint32      firmwareHip;
+    CsrCharString *routerBuild;
+    CsrUint32      routerHip;
+    CsrCharString *smeBuild;
+    CsrUint32      smeHip;
+} CsrWifiSmeVersions;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWmmAcParams
+
+  DESCRIPTION
+    Structure holding WMM AC params data.
+
+  MEMBERS
+    cwMin                     - Exponent for the calculation of CWmin. Range: 0
+                                to 15
+    cwMax                     - Exponent for the calculation of CWmax. Range: 0
+                                to15
+    aifs                      - Arbitration Inter Frame Spacing in terms of
+                                number of timeslots. Range 2 to 15
+    txopLimit                 - TXOP Limit in the units of 32 microseconds
+    admissionControlMandatory - Indicates whether the admission control is
+                                mandatory or not. Current release does not
+                                support admission control , hence shall be set
+                                to FALSE.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8  cwMin;
+    CsrUint8  cwMax;
+    CsrUint8  aifs;
+    CsrUint16 txopLimit;
+    CsrBool   admissionControlMandatory;
+} CsrWifiSmeWmmAcParams;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsDeviceType
+
+  DESCRIPTION
+    Structure holding AP WPS device type data.
+
+  MEMBERS
+    deviceDetails - category , sub category etc
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8 deviceDetails[8];
+} CsrWifiSmeWpsDeviceType;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsDeviceTypeCommon
+
+  DESCRIPTION
+
+  MEMBERS
+    spportWps  -
+    deviceType -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrBool  spportWps;
+    CsrUint8 deviceType;
+} CsrWifiSmeWpsDeviceTypeCommon;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsInfo
+
+  DESCRIPTION
+
+  MEMBERS
+    version         -
+    configMethods   -
+    devicePassworId -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint16 version;
+    CsrUint16 configMethods;
+    CsrUint16 devicePassworId;
+} CsrWifiSmeWpsInfo;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCloakedSsidConfig
+
+  DESCRIPTION
+    List of cloaked SSIDs .
+
+  MEMBERS
+    cloakedSsidsCount - Number of cloaked SSID
+    cloakedSsids      - Points to the first byte of the first SSID provided
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8     cloakedSsidsCount;
+    CsrWifiSsid *cloakedSsids;
+} CsrWifiSmeCloakedSsidConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexInfo
+
+  DESCRIPTION
+    Information and state related to coexistence.
+
+  MEMBERS
+    hasTrafficData            - TRUE if any Wi-Fi traffic is detected
+    currentTrafficType        - Current type of traffic
+    currentPeriodMs           - Period of the traffic as detected by the traffic
+                                analysis.
+                                If the traffic is not periodic, it is set to 0.
+    currentPowerSave          - Current power save level
+    currentCoexPeriodMs       - Period of awakening for the firmware used when
+                                periodic traffic is detected.
+                                If the traffic is not periodic, it is set to 0.
+    currentCoexLatencyMs      - Period of awakening for the firmware used when
+                                non-periodic traffic is detected
+    hasBtDevice               - TRUE if there is a Bluetooth device connected
+    currentBlackoutDurationUs - Current blackout duration for protecting
+                                Bluetooth
+    currentBlackoutPeriodUs   - Current blackout period
+    currentCoexScheme         - Defines the scheme for the coexistence
+                                signalling
+
+*******************************************************************************/
+typedef struct
+{
+    CsrBool                  hasTrafficData;
+    CsrWifiSmeTrafficType    currentTrafficType;
+    CsrUint16                currentPeriodMs;
+    CsrWifiSmePowerSaveLevel currentPowerSave;
+    CsrUint16                currentCoexPeriodMs;
+    CsrUint16                currentCoexLatencyMs;
+    CsrBool                  hasBtDevice;
+    CsrUint32                currentBlackoutDurationUs;
+    CsrUint32                currentBlackoutPeriodUs;
+    CsrWifiSmeCoexScheme     currentCoexScheme;
+} CsrWifiSmeCoexInfo;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionConfig
+
+  DESCRIPTION
+    Specifies the parameters that the SME should use in selecting a network.
+
+  MEMBERS
+    ssid
+                   - Service Set identifier
+    bssid
+                   - BSS identifier
+    bssType
+                   - Indicates the type of BSS
+    ifIndex
+                   - Indicates the radio interface
+    privacyMode
+                   - Specifies whether the privacy mode is enabled or disabled.
+    authModeMask
+                   - Sets the authentication options that the SME can use while
+                     associating to the AP
+                     Set mask with values from CsrWifiSmeAuthMode
+    encryptionModeMask
+                   - Sets the encryption options that the SME can use while
+                     associating to the AP
+                     Set mask with values from CsrWifiSmeEncryption
+    mlmeAssociateReqInformationElementsLength
+                   - Length in bytes of information elements to be sent in the
+                     Association Request.
+    mlmeAssociateReqInformationElements
+                   - Points to the first byte of the information elements, if
+                     any.
+    wmmQosInfo
+                   - This parameter allows the driver's WMM behaviour to be
+                     configured.
+                     To enable support for WMM, use
+                     CSR_WIFI_SME_SME_CONFIG_SET_REQ with the
+                     CSR_WIFI_SME_WMM_MODE_AC_ENABLED bit set in wmmModeMask
+                     field in smeConfig parameter.
+                     Set mask with values from CsrWifiSmeWmmQosInfo
+    adhocJoinOnly
+                   - This parameter is relevant only if bssType is NOT set to
+                     CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE:
+                     if TRUE the SME will only try to join an ad-hoc network if
+                     there is one already established;
+                     if FALSE the SME will try to join an ad-hoc network if
+                     there is one already established or it will try to
+                     establish a new one
+    adhocChannel
+                   - This parameter is relevant only if bssType is NOT set to
+                     CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE:
+                     it indicates the channel to use joining an ad hoc network.
+                     Setting this to 0 causes the SME to select a channel from
+                     those permitted in the regulatory domain.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSsid                ssid;
+    CsrWifiMacAddress          bssid;
+    CsrWifiSmeBssType          bssType;
+    CsrWifiSmeRadioIF          ifIndex;
+    CsrWifiSme80211PrivacyMode privacyMode;
+    CsrWifiSmeAuthModeMask     authModeMask;
+    CsrWifiSmeEncryptionMask   encryptionModeMask;
+    CsrUint16                  mlmeAssociateReqInformationElementsLength;
+    CsrUint8                  *mlmeAssociateReqInformationElements;
+    CsrWifiSmeWmmQosInfoMask   wmmQosInfo;
+    CsrBool                    adhocJoinOnly;
+    CsrUint8                   adhocChannel;
+} CsrWifiSmeConnectionConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionInfo
+
+  DESCRIPTION
+    Parameters that the SME should use in selecting a network
+
+  MEMBERS
+    ssid                        - Service set identifier
+    bssid                       - BSS identifier
+    networkType80211            - Physical layer used for the connection
+    channelNumber               - Channel number
+    channelFrequency            - Channel frequency
+    authMode                    - Authentication mode used for the connection
+    pairwiseCipher              - Encryption type for peer to peer communication
+    groupCipher                 - Encryption type for broadcast and multicast
+                                  communication
+    ifIndex                     - Indicates the radio interface
+    atimWindowTu                - ATIM window specified for IBSS
+    beaconPeriodTu              - Interval between beacon packets
+    reassociation               - Indicates whether a reassociation occurred
+    beaconFrameLength           - Indicates the number of bytes of the beacon
+                                  frame
+    beaconFrame                 - Points at the first byte of the beacon frame
+    associationReqFrameLength   - Indicates the number of bytes of the
+                                  association request frame
+    associationReqFrame         - Points at the first byte of the association
+                                  request frame
+    associationRspFrameLength   - Indicates the number of bytes of the
+                                  association response frame
+    associationRspFrame         - Points at the first byte of the association
+                                  response frame
+    assocScanInfoElementsLength - Indicates the number of bytes in the buffer
+                                  pointed by assocScanInfoElements
+    assocScanInfoElements       - Pointer to the buffer containing the
+                                  information elements of the probe response
+                                  received after the probe requests sent before
+                                  attempting to authenticate to the network
+    assocReqCapabilities        - Reports the content of the Capability
+                                  information element as specified in the
+                                  association request.
+    assocReqListenIntervalTu    - Listen Interval specified in the association
+                                  request
+    assocReqApAddress           - AP address to which the association requests
+                                  has been sent
+    assocReqInfoElementsLength  - Indicates the number of bytes of the
+                                  association request information elements
+    assocReqInfoElements        - Points at the first byte of the association
+                                  request information elements
+    assocRspResult              - Result reported in the association response
+    assocRspCapabilityInfo      - Reports the content of the Capability
+                                  information element as received in the
+                                  association response.
+    assocRspAssociationId       - Reports the association ID received in the
+                                  association response.
+    assocRspInfoElementsLength  - Indicates the number of bytes of the
+                                  association response information elements
+    assocRspInfoElements        - Points at the first byte of the association
+                                  response information elements
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSsid                ssid;
+    CsrWifiMacAddress          bssid;
+    CsrWifiSme80211NetworkType networkType80211;
+    CsrUint8                   channelNumber;
+    CsrUint16                  channelFrequency;
+    CsrWifiSmeAuthMode         authMode;
+    CsrWifiSmeEncryption       pairwiseCipher;
+    CsrWifiSmeEncryption       groupCipher;
+    CsrWifiSmeRadioIF          ifIndex;
+    CsrUint16                  atimWindowTu;
+    CsrUint16                  beaconPeriodTu;
+    CsrBool                    reassociation;
+    CsrUint16                  beaconFrameLength;
+    CsrUint8                  *beaconFrame;
+    CsrUint16                  associationReqFrameLength;
+    CsrUint8                  *associationReqFrame;
+    CsrUint16                  associationRspFrameLength;
+    CsrUint8                  *associationRspFrame;
+    CsrUint16                  assocScanInfoElementsLength;
+    CsrUint8                  *assocScanInfoElements;
+    CsrUint16                  assocReqCapabilities;
+    CsrUint16                  assocReqListenIntervalTu;
+    CsrWifiMacAddress          assocReqApAddress;
+    CsrUint16                  assocReqInfoElementsLength;
+    CsrUint8                  *assocReqInfoElements;
+    CsrWifiSmeIEEE80211Result  assocRspResult;
+    CsrUint16                  assocRspCapabilityInfo;
+    CsrUint16                  assocRspAssociationId;
+    CsrUint16                  assocRspInfoElementsLength;
+    CsrUint8                  *assocRspInfoElements;
+} CsrWifiSmeConnectionInfo;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDeviceConfig
+
+  DESCRIPTION
+    General configuration options in the SME
+
+  MEMBERS
+    trustLevel              - Level of trust of the information coming from the
+                              network
+    countryCode             - Country code as specified by IEEE 802.11 standard
+    firmwareDriverInterface - Specifies the type of communication between Host
+                              and Firmware
+    enableStrictDraftN      - If TRUE TKIP is disallowed when connecting to
+                              802.11n enabled access points
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSme80211dTrustLevel        trustLevel;
+    CsrUint8                          countryCode[2];
+    CsrWifiSmeFirmwareDriverInterface firmwareDriverInterface;
+    CsrBool                           enableStrictDraftN;
+} CsrWifiSmeDeviceConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDeviceInfo
+
+  DESCRIPTION
+    P2P Information for a P2P Device
+
+  MEMBERS
+    deviceAddress            - Device Address of the P2P device
+    configMethods            - Supported WPS configuration methods.
+    p2PDeviceCap             - P2P device capabilities
+    primDeviceType           - Primary WPS device type
+    secondaryDeviceTypeCount - Number of secondary device types
+    secDeviceType            - list of secondary WPS device types
+    deviceName               - Device name without up to 32 characters'\0'.
+    deviceNameLength         - Number of characters of the device name
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiMacAddress           deviceAddress;
+    CsrWifiSmeWpsConfigTypeMask configMethods;
+    CsrWifiSmeP2pCapabilityMask p2PDeviceCap;
+    CsrWifiSmeWpsDeviceType     primDeviceType;
+    CsrUint8                    secondaryDeviceTypeCount;
+    CsrWifiSmeWpsDeviceType    *secDeviceType;
+    CsrUint8                    deviceName[32];
+    CsrUint8                    deviceNameLength;
+} CsrWifiSmeDeviceInfo;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDeviceInfoCommon
+
+  DESCRIPTION
+    Structure holding device information.
+
+  MEMBERS
+    p2pDeviceAddress          -
+    primaryDeviceType         -
+    secondaryDeviceTypesCount -
+    secondaryDeviceTypes      -
+    deviceNameLength          -
+    deviceName                -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiMacAddress             p2pDeviceAddress;
+    CsrWifiSmeWpsDeviceTypeCommon primaryDeviceType;
+    CsrUint8                      secondaryDeviceTypesCount;
+    CsrUint8                      secondaryDeviceTypes[10];
+    CsrUint8                      deviceNameLength;
+    CsrUint8                      deviceName[32];
+} CsrWifiSmeDeviceInfoCommon;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeHostConfig
+
+  DESCRIPTION
+    Defines the host power state (for example, on mains power, on battery
+    power etc) and the periodicity of the traffic data.
+
+  MEMBERS
+    powerMode               - The wireless manager application should use the
+                              powerMode parameter to inform the SME of the host
+                              power state.
+    applicationDataPeriodMs - The applicationDataPeriodMs parameter allows a
+                              wireless manager application to inform the SME
+                              that an application is running that generates
+                              periodic network traffic and the period of the
+                              traffic.
+                              An example of such an application is a VoIP client.
+                              The wireless manager application should set
+                              applicationDataPeriodMs to the period in
+                              milliseconds between data packets or zero if no
+                              periodic application is running.
+                              Voip etc 0 = No Periodic Data
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeHostPowerMode powerMode;
+    CsrUint16               applicationDataPeriodMs;
+} CsrWifiSmeHostConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeKey
+
+  DESCRIPTION
+    Information for a key to be used for encryption
+
+  MEMBERS
+    keyType       - Specifies whether the key is a pairwise or group key; it
+                    should be set to CSR_WIFI_SME_GROUP_KEY or
+                    CSR_WIFI_SME_PAIRWISE_KEY, as required.
+    keyIndex      - Specifies which WEP key (0-3) to set; it should be set to 0
+                    for a WPA/WPA2 pairwise key and non-zero for a WPA/WPA2
+                    group key.
+    wepTxKey      - If wepTxKey is TRUE, and the key is a WEP key, the key will
+                    be selected for encrypting transmitted packets.
+                    To select a previously defined key as the transmit
+                    encryption key, set keyIndex to the required key, wepTxKey
+                    to TRUE and the keyLength to 0.
+    keyRsc        - Key Receive Sequence Counter
+    authenticator - If TRUE the WMA will act as authenticator.
+                    CURRENTLY NOT SUPPORTED
+    address       - BSS identifier of the AP
+    keyLength     - Length of the key in bytes
+    key           - Points to the first byte of the key
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeKeyType keyType;
+    CsrUint8          keyIndex;
+    CsrBool           wepTxKey;
+    CsrUint16         keyRsc[8];
+    CsrBool           authenticator;
+    CsrWifiMacAddress address;
+    CsrUint8          keyLength;
+    CsrUint8          key[32];
+} CsrWifiSmeKey;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeP2pClientInfoType
+
+  DESCRIPTION
+    P2P Information for a P2P Client
+
+  MEMBERS
+    p2PClientInterfaceAddress - MAC address of the P2P Client
+    clientDeviceInfo          - Device Information
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiMacAddress    p2PClientInterfaceAddress;
+    CsrWifiSmeDeviceInfo clientDeviceInfo;
+} CsrWifiSmeP2pClientInfoType;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeP2pGroupInfo
+
+  DESCRIPTION
+    P2P Information for a P2P Group
+
+  MEMBERS
+    groupCapability    - P2P group capabilities
+    p2pDeviceAddress   - Device Address of the GO
+    p2pClientInfoCount - Number of P2P Clients that belong to the group.
+    p2PClientInfo      - Pointer to the list containing client information for
+                         each client in the group
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeP2pGroupCapabilityMask groupCapability;
+    CsrWifiMacAddress                p2pDeviceAddress;
+    CsrUint8                         p2pClientInfoCount;
+    CsrWifiSmeP2pClientInfoType     *p2PClientInfo;
+} CsrWifiSmeP2pGroupInfo;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePowerConfig
+
+  DESCRIPTION
+    Configures the power-save behaviour of the driver and firmware.
+
+  MEMBERS
+    powerSaveLevel         - Power Save Level option
+    listenIntervalTu       - Interval for waking to receive beacon frames
+    rxDtims                - If TRUE, wake for DTIM every beacon period, to
+                             allow the reception broadcast packets
+    d3AutoScanMode         - Defines whether the autonomous scanning will be
+                             turned off or will stay on during a D3 suspended
+                             period
+    clientTrafficWindow    - Deprecated
+    opportunisticPowerSave - Deprecated
+    noticeOfAbsence        - Deprecated
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmePowerSaveLevel powerSaveLevel;
+    CsrUint16                listenIntervalTu;
+    CsrBool                  rxDtims;
+    CsrWifiSmeD3AutoScanMode d3AutoScanMode;
+    CsrUint8                 clientTrafficWindow;
+    CsrBool                  opportunisticPowerSave;
+    CsrBool                  noticeOfAbsence;
+} CsrWifiSmePowerConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamingConfig
+
+  DESCRIPTION
+    Configures the roaming behaviour of the driver and firmware
+
+  MEMBERS
+    roamingBands             - Defines the thresholds to determine the usability
+                               level of the current connection.
+                               roamingBands is indexed by the first 3 entries of
+                               the CsrWifiSmeBasicUsability enum
+    disableSmoothRoaming     - Disable the RSSI/SNR triggers from the Firmware
+                               that the SME uses to detect the quality of the
+                               connection.
+                               This implicitly disables disableRoamScans
+    disableRoamScans         - Disables the scanning for the roaming operation
+    reconnectLimit           - Maximum number of times SME may reconnect in the
+                               given interval
+    reconnectLimitIntervalMs - Interval for maximum number of times SME may
+                               reconnect to the same Access Point
+    roamScanCfg              - Scanning behaviour for the specifically aimed at
+                               improving roaming performance.
+                               roamScanCfg is indexed by the first 3 entries of
+                               the CsrWifiSmeBasicUsability enum
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeRoamingBandData roamingBands[3];
+    CsrBool                   disableSmoothRoaming;
+    CsrBool                   disableRoamScans;
+    CsrUint8                  reconnectLimit;
+    CsrUint16                 reconnectLimitIntervalMs;
+    CsrWifiSmeScanConfigData  roamScanCfg[3];
+} CsrWifiSmeRoamingConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanConfig
+
+  DESCRIPTION
+    Parameters for the autonomous scanning behaviour of the system
+
+  MEMBERS
+    scanCfg                 - Scan configuration data.
+                              Indexed by the CsrWifiSmeBasicUsability enum
+    disableAutonomousScans  - Enables or disables the autonomous scan
+    maxResults              - Maximum number of results to be cached in the SME
+    highRssiThreshold       - High received signal strength indication threshold
+                              in dBm for an AP above which the system will
+                              report scan indications
+    lowRssiThreshold        - Low received signal strength indication threshold
+                              in dBm for an AP below which the system will
+                              report scan indications
+    deltaRssiThreshold      - Minimum difference for received signal strength
+                              indication in dBm for an AP which trigger a scan
+                              indication to be sent.
+    highSnrThreshold        - High Signal to Noise Ratio threshold in dB for an
+                              AP above which the system will report scan
+                              indications
+    lowSnrThreshold         - Low Signal to Noise Ratio threshold in dB for an
+                              AP below which the system will report scan
+                              indications
+    deltaSnrThreshold       - Minimum difference for Signal to Noise Ratio in dB
+                              for an AP which trigger a scan indication to be
+                              sent.
+    passiveChannelListCount - Number of channels to be scanned passively.
+    passiveChannelList      - Points to the first channel to be scanned
+                              passively , if any.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeScanConfigData scanCfg[4];
+    CsrBool                  disableAutonomousScans;
+    CsrUint16                maxResults;
+    CsrInt8                  highRssiThreshold;
+    CsrInt8                  lowRssiThreshold;
+    CsrInt8                  deltaRssiThreshold;
+    CsrInt8                  highSnrThreshold;
+    CsrInt8                  lowSnrThreshold;
+    CsrInt8                  deltaSnrThreshold;
+    CsrUint16                passiveChannelListCount;
+    CsrUint8                *passiveChannelList;
+} CsrWifiSmeScanConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanResult
+
+  DESCRIPTION
+    This structure defines the scan result for each BSS found
+
+  MEMBERS
+    ssid                         - Service set identifier
+    bssid                        - BSS identifier
+    rssi                         - Received signal strength indication in dBm
+    snr                          - Signal to noise ratio in dB
+    ifIndex                      - Indicates the radio interface
+    beaconPeriodTu               - Interval between beacon frames
+    timeStamp                    - Timestamp in the BSS
+    localTime                    - Timestamp in the Access Point
+    channelFrequency             - Channel frequency
+    capabilityInformation        - Capabilities of the BSS.
+    channelNumber                - Channel number
+    usability                    - Indicates the usability level.
+    bssType                      - Type of BSS.
+    informationElementsLength    - Number of bytes of the information elements
+                                   received as part of the beacon or probe
+                                   response.
+    informationElements          - Points to the first byte of the IEs received
+                                   as part of the beacon or probe response.
+                                   The format of the IEs is as specified in the
+                                   IEEE 802.11 specification.
+    p2pDeviceRole                - Role of the P2P device.
+                                   Relevant only if bssType is
+                                   CSR_WIFI_SME_BSS_TYPE_P2P
+    deviceInfo                   - Union containing P2P device info which
+                                   depends on p2pDeviceRole parameter.
+    deviceInforeservedCli        -
+    deviceInfogroupInfo          -
+    deviceInforeservedNone       -
+    deviceInfostandalonedevInfo  -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSsid              ssid;
+    CsrWifiMacAddress        bssid;
+    CsrInt16                 rssi;
+    CsrInt16                 snr;
+    CsrWifiSmeRadioIF        ifIndex;
+    CsrUint16                beaconPeriodTu;
+    CsrWifiSmeTsfTime        timeStamp;
+    CsrWifiSmeTsfTime        localTime;
+    CsrUint16                channelFrequency;
+    CsrUint16                capabilityInformation;
+    CsrUint8                 channelNumber;
+    CsrWifiSmeBasicUsability usability;
+    CsrWifiSmeBssType        bssType;
+    CsrUint16                informationElementsLength;
+    CsrUint8                *informationElements;
+    CsrWifiSmeP2pRole        p2pDeviceRole;
+    union {
+        CsrWifiSmeEmpty        reservedCli;
+        CsrWifiSmeP2pGroupInfo groupInfo;
+        CsrWifiSmeEmpty        reservedNone;
+        CsrWifiSmeDeviceInfo   standalonedevInfo;
+    } deviceInfo;
+} CsrWifiSmeScanResult;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeStaConfig
+
+  DESCRIPTION
+    Station configuration options in the SME
+
+  MEMBERS
+    connectionQualityRssiChangeTrigger - Sets the difference of RSSI
+                                         measurements which triggers reports
+                                         from the Firmware
+    connectionQualitySnrChangeTrigger  - Sets the difference of SNR measurements
+                                         which triggers reports from the
+                                         Firmware
+    wmmModeMask                        - Mask containing one or more values from
+                                         CsrWifiSmeWmmMode
+    ifIndex                            - Indicates the band of frequencies used
+    allowUnicastUseGroupCipher         - If TRUE, it allows to use groupwise
+                                         keys if no pairwise key is specified
+    enableOpportunisticKeyCaching      - If TRUE, enables the Opportunistic Key
+                                         Caching feature
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8              connectionQualityRssiChangeTrigger;
+    CsrUint8              connectionQualitySnrChangeTrigger;
+    CsrWifiSmeWmmModeMask wmmModeMask;
+    CsrWifiSmeRadioIF     ifIndex;
+    CsrBool               allowUnicastUseGroupCipher;
+    CsrBool               enableOpportunisticKeyCaching;
+} CsrWifiSmeStaConfig;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWep128Keys
+
+  DESCRIPTION
+    Structure holding WEP Authentication Type and WEP keys that can be used
+    when using WEP128.
+
+  MEMBERS
+    wepAuthType    - Mask to select the WEP authentication type (Open or Shared)
+    selectedWepKey - Index to one of the four keys below indicating the
+                     currently used WEP key. Mapping From SME/User -> firmware.
+                     Key 1 -> Index 0. Key 2 -> Index 1. key 3 -> Index 2. Key
+                     4-> Index 3.
+    key1           - Value for key number 1.
+    key2           - Value for key number 2.
+    key3           - Value for key number 3.
+    key4           - Value for key number 4.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeWepAuthMode wepAuthType;
+    CsrUint8              selectedWepKey;
+    CsrUint8              key1[13];
+    CsrUint8              key2[13];
+    CsrUint8              key3[13];
+    CsrUint8              key4[13];
+} CsrWifiSmeWep128Keys;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWep64Keys
+
+  DESCRIPTION
+    Structure holding WEP Authentication Type and WEP keys that can be used
+    when using WEP64.
+
+  MEMBERS
+    wepAuthType    - Mask to select the WEP authentication type (Open or Shared)
+    selectedWepKey - Index to one of the four keys below indicating the
+                     currently used WEP key. Mapping From SME/User -> firmware.
+                     Key 1 -> Index 0. Key 2 -> Index 1. key 3 -> Index 2. Key
+                     4-> Index 3.
+    key1           - Value for key number 1.
+    key2           - Value for key number 2.
+    key3           - Value for key number 3.
+    key4           - Value for key number 4.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeWepAuthMode wepAuthType;
+    CsrUint8              selectedWepKey;
+    CsrUint8              key1[5];
+    CsrUint8              key2[5];
+    CsrUint8              key3[5];
+    CsrUint8              key4[5];
+} CsrWifiSmeWep64Keys;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWepAuth
+
+  DESCRIPTION
+    WEP authentication parameter structure
+
+  MEMBERS
+    wepKeyType               - WEP key try (128 bit or 64 bit)
+    wepCredentials           - Union containing credentials which depends on
+                               wepKeyType parameter.
+    wepCredentialswep128Key  -
+    wepCredentialswep64Key   -
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiSmeWepCredentialType wepKeyType;
+    union {
+        CsrWifiSmeWep128Keys wep128Key;
+        CsrWifiSmeWep64Keys  wep64Key;
+    } wepCredentials;
+} CsrWifiSmeWepAuth;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsConfig
+
+  DESCRIPTION
+    Structure holding AP WPS Config data.
+
+  MEMBERS
+    wpsVersion               - wpsVersion should be 0x10 for WPS1.0h or 0x20 for
+                               WSC2.0
+    uuid                     - uuid.
+    deviceName               - Device name upto 32 characters without '\0'.
+    deviceNameLength         - deviceNameLen.
+    manufacturer             - manufacturer: CSR
+    manufacturerLength       - manufacturerLen.
+    modelName                - modelName Unifi
+    modelNameLength          - modelNameLen.
+    modelNumber              - modelNumber
+    modelNumberLength        - modelNumberLen.
+    serialNumber             - serialNumber
+    primDeviceType           - Primary WPS device type
+    secondaryDeviceTypeCount - Number of secondary device types
+    secondaryDeviceType      - list of secondary WPS device types
+    configMethods            - Supported WPS config methods
+    rfBands                  - RfBands.
+    osVersion                - Os version on which the device is running
+
+*******************************************************************************/
+typedef struct
+{
+    CsrUint8                    wpsVersion;
+    CsrUint8                    uuid[16];
+    CsrUint8                    deviceName[32];
+    CsrUint8                    deviceNameLength;
+    CsrUint8                    manufacturer[64];
+    CsrUint8                    manufacturerLength;
+    CsrUint8                    modelName[32];
+    CsrUint8                    modelNameLength;
+    CsrUint8                    modelNumber[32];
+    CsrUint8                    modelNumberLength;
+    CsrUint8                    serialNumber[32];
+    CsrWifiSmeWpsDeviceType     primDeviceType;
+    CsrUint8                    secondaryDeviceTypeCount;
+    CsrWifiSmeWpsDeviceType    *secondaryDeviceType;
+    CsrWifiSmeWpsConfigTypeMask configMethods;
+    CsrUint8                    rfBands;
+    CsrUint8                    osVersion[4];
+} CsrWifiSmeWpsConfig;
+
+
+/* Downstream */
+#define CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST            (0x0000)
+
+#define CSR_WIFI_SME_ACTIVATE_REQ                         ((CsrWifiSmePrim) (0x0000 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_ADHOC_CONFIG_GET_REQ                 ((CsrWifiSmePrim) (0x0001 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_ADHOC_CONFIG_SET_REQ                 ((CsrWifiSmePrim) (0x0002 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_BLACKLIST_REQ                        ((CsrWifiSmePrim) (0x0003 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_CALIBRATION_DATA_GET_REQ             ((CsrWifiSmePrim) (0x0004 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_CALIBRATION_DATA_SET_REQ             ((CsrWifiSmePrim) (0x0005 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_CCX_CONFIG_GET_REQ                   ((CsrWifiSmePrim) (0x0006 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_CCX_CONFIG_SET_REQ                   ((CsrWifiSmePrim) (0x0007 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_COEX_CONFIG_GET_REQ                  ((CsrWifiSmePrim) (0x0008 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_COEX_CONFIG_SET_REQ                  ((CsrWifiSmePrim) (0x0009 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_COEX_INFO_GET_REQ                    ((CsrWifiSmePrim) (0x000A + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_CONNECT_REQ                          ((CsrWifiSmePrim) (0x000B + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_CONNECTION_CONFIG_GET_REQ            ((CsrWifiSmePrim) (0x000C + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_CONNECTION_INFO_GET_REQ              ((CsrWifiSmePrim) (0x000D + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_CONNECTION_STATS_GET_REQ             ((CsrWifiSmePrim) (0x000E + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_DEACTIVATE_REQ                       ((CsrWifiSmePrim) (0x000F + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_DISCONNECT_REQ                       ((CsrWifiSmePrim) (0x0010 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_EVENT_MASK_SET_REQ                   ((CsrWifiSmePrim) (0x0011 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_HOST_CONFIG_GET_REQ                  ((CsrWifiSmePrim) (0x0012 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_HOST_CONFIG_SET_REQ                  ((CsrWifiSmePrim) (0x0013 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_KEY_REQ                              ((CsrWifiSmePrim) (0x0014 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_LINK_QUALITY_GET_REQ                 ((CsrWifiSmePrim) (0x0015 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_MIB_CONFIG_GET_REQ                   ((CsrWifiSmePrim) (0x0016 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_MIB_CONFIG_SET_REQ                   ((CsrWifiSmePrim) (0x0017 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_MIB_GET_NEXT_REQ                     ((CsrWifiSmePrim) (0x0018 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_MIB_GET_REQ                          ((CsrWifiSmePrim) (0x0019 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_MIB_SET_REQ                          ((CsrWifiSmePrim) (0x001A + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_MULTICAST_ADDRESS_REQ                ((CsrWifiSmePrim) (0x001B + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_PACKET_FILTER_SET_REQ                ((CsrWifiSmePrim) (0x001C + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_PERMANENT_MAC_ADDRESS_GET_REQ        ((CsrWifiSmePrim) (0x001D + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_PMKID_REQ                            ((CsrWifiSmePrim) (0x001E + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_POWER_CONFIG_GET_REQ                 ((CsrWifiSmePrim) (0x001F + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_POWER_CONFIG_SET_REQ                 ((CsrWifiSmePrim) (0x0020 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_INFO_GET_REQ       ((CsrWifiSmePrim) (0x0021 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_ROAMING_CONFIG_GET_REQ               ((CsrWifiSmePrim) (0x0022 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_ROAMING_CONFIG_SET_REQ               ((CsrWifiSmePrim) (0x0023 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_SCAN_CONFIG_GET_REQ                  ((CsrWifiSmePrim) (0x0024 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_SCAN_CONFIG_SET_REQ                  ((CsrWifiSmePrim) (0x0025 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_SCAN_FULL_REQ                        ((CsrWifiSmePrim) (0x0026 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_SCAN_RESULTS_FLUSH_REQ               ((CsrWifiSmePrim) (0x0027 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_SCAN_RESULTS_GET_REQ                 ((CsrWifiSmePrim) (0x0028 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_SME_STA_CONFIG_GET_REQ               ((CsrWifiSmePrim) (0x0029 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_SME_STA_CONFIG_SET_REQ               ((CsrWifiSmePrim) (0x002A + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_STATION_MAC_ADDRESS_GET_REQ          ((CsrWifiSmePrim) (0x002B + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_TSPEC_REQ                            ((CsrWifiSmePrim) (0x002C + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_VERSIONS_GET_REQ                     ((CsrWifiSmePrim) (0x002D + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_WIFI_FLIGHTMODE_REQ                  ((CsrWifiSmePrim) (0x002E + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_WIFI_OFF_REQ                         ((CsrWifiSmePrim) (0x002F + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_WIFI_ON_REQ                          ((CsrWifiSmePrim) (0x0030 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_CLOAKED_SSIDS_SET_REQ                ((CsrWifiSmePrim) (0x0031 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_CLOAKED_SSIDS_GET_REQ                ((CsrWifiSmePrim) (0x0032 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_SME_COMMON_CONFIG_GET_REQ            ((CsrWifiSmePrim) (0x0033 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_SME_COMMON_CONFIG_SET_REQ            ((CsrWifiSmePrim) (0x0034 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_INTERFACE_CAPABILITY_GET_REQ         ((CsrWifiSmePrim) (0x0035 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_WPS_CONFIGURATION_REQ                ((CsrWifiSmePrim) (0x0036 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+#define CSR_WIFI_SME_SET_REQ                              ((CsrWifiSmePrim) (0x0037 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST))
+
+
+#define CSR_WIFI_SME_PRIM_DOWNSTREAM_HIGHEST           (0x0037 + CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST)
+
+/* Upstream */
+#define CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST              (0x0000 + CSR_PRIM_UPSTREAM)
+
+#define CSR_WIFI_SME_ACTIVATE_CFM                         ((CsrWifiSmePrim)(0x0000 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_ADHOC_CONFIG_GET_CFM                 ((CsrWifiSmePrim)(0x0001 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_ADHOC_CONFIG_SET_CFM                 ((CsrWifiSmePrim)(0x0002 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_ASSOCIATION_COMPLETE_IND             ((CsrWifiSmePrim)(0x0003 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_ASSOCIATION_START_IND                ((CsrWifiSmePrim)(0x0004 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_BLACKLIST_CFM                        ((CsrWifiSmePrim)(0x0005 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CALIBRATION_DATA_GET_CFM             ((CsrWifiSmePrim)(0x0006 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CALIBRATION_DATA_SET_CFM             ((CsrWifiSmePrim)(0x0007 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CCX_CONFIG_GET_CFM                   ((CsrWifiSmePrim)(0x0008 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CCX_CONFIG_SET_CFM                   ((CsrWifiSmePrim)(0x0009 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_COEX_CONFIG_GET_CFM                  ((CsrWifiSmePrim)(0x000A + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_COEX_CONFIG_SET_CFM                  ((CsrWifiSmePrim)(0x000B + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_COEX_INFO_GET_CFM                    ((CsrWifiSmePrim)(0x000C + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CONNECT_CFM                          ((CsrWifiSmePrim)(0x000D + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CONNECTION_CONFIG_GET_CFM            ((CsrWifiSmePrim)(0x000E + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CONNECTION_INFO_GET_CFM              ((CsrWifiSmePrim)(0x000F + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CONNECTION_QUALITY_IND               ((CsrWifiSmePrim)(0x0010 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CONNECTION_STATS_GET_CFM             ((CsrWifiSmePrim)(0x0011 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_DEACTIVATE_CFM                       ((CsrWifiSmePrim)(0x0012 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_DISCONNECT_CFM                       ((CsrWifiSmePrim)(0x0013 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_EVENT_MASK_SET_CFM                   ((CsrWifiSmePrim)(0x0014 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_HOST_CONFIG_GET_CFM                  ((CsrWifiSmePrim)(0x0015 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_HOST_CONFIG_SET_CFM                  ((CsrWifiSmePrim)(0x0016 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_IBSS_STATION_IND                     ((CsrWifiSmePrim)(0x0017 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_KEY_CFM                              ((CsrWifiSmePrim)(0x0018 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_LINK_QUALITY_GET_CFM                 ((CsrWifiSmePrim)(0x0019 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_MEDIA_STATUS_IND                     ((CsrWifiSmePrim)(0x001A + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_MIB_CONFIG_GET_CFM                   ((CsrWifiSmePrim)(0x001B + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_MIB_CONFIG_SET_CFM                   ((CsrWifiSmePrim)(0x001C + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_MIB_GET_CFM                          ((CsrWifiSmePrim)(0x001D + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_MIB_GET_NEXT_CFM                     ((CsrWifiSmePrim)(0x001E + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_MIB_SET_CFM                          ((CsrWifiSmePrim)(0x001F + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_MIC_FAILURE_IND                      ((CsrWifiSmePrim)(0x0020 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_MULTICAST_ADDRESS_CFM                ((CsrWifiSmePrim)(0x0021 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_PACKET_FILTER_SET_CFM                ((CsrWifiSmePrim)(0x0022 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_PERMANENT_MAC_ADDRESS_GET_CFM        ((CsrWifiSmePrim)(0x0023 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_PMKID_CANDIDATE_LIST_IND             ((CsrWifiSmePrim)(0x0024 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_PMKID_CFM                            ((CsrWifiSmePrim)(0x0025 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_POWER_CONFIG_GET_CFM                 ((CsrWifiSmePrim)(0x0026 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_POWER_CONFIG_SET_CFM                 ((CsrWifiSmePrim)(0x0027 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_REGULATORY_DOMAIN_INFO_GET_CFM       ((CsrWifiSmePrim)(0x0028 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_ROAM_COMPLETE_IND                    ((CsrWifiSmePrim)(0x0029 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_ROAM_START_IND                       ((CsrWifiSmePrim)(0x002A + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_ROAMING_CONFIG_GET_CFM               ((CsrWifiSmePrim)(0x002B + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_ROAMING_CONFIG_SET_CFM               ((CsrWifiSmePrim)(0x002C + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_SCAN_CONFIG_GET_CFM                  ((CsrWifiSmePrim)(0x002D + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_SCAN_CONFIG_SET_CFM                  ((CsrWifiSmePrim)(0x002E + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_SCAN_FULL_CFM                        ((CsrWifiSmePrim)(0x002F + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_SCAN_RESULT_IND                      ((CsrWifiSmePrim)(0x0030 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_SCAN_RESULTS_FLUSH_CFM               ((CsrWifiSmePrim)(0x0031 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_SCAN_RESULTS_GET_CFM                 ((CsrWifiSmePrim)(0x0032 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_SME_STA_CONFIG_GET_CFM               ((CsrWifiSmePrim)(0x0033 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_SME_STA_CONFIG_SET_CFM               ((CsrWifiSmePrim)(0x0034 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_STATION_MAC_ADDRESS_GET_CFM          ((CsrWifiSmePrim)(0x0035 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_TSPEC_IND                            ((CsrWifiSmePrim)(0x0036 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_TSPEC_CFM                            ((CsrWifiSmePrim)(0x0037 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_VERSIONS_GET_CFM                     ((CsrWifiSmePrim)(0x0038 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_WIFI_FLIGHTMODE_CFM                  ((CsrWifiSmePrim)(0x0039 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_WIFI_OFF_IND                         ((CsrWifiSmePrim)(0x003A + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_WIFI_OFF_CFM                         ((CsrWifiSmePrim)(0x003B + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_WIFI_ON_CFM                          ((CsrWifiSmePrim)(0x003C + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CLOAKED_SSIDS_SET_CFM                ((CsrWifiSmePrim)(0x003D + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CLOAKED_SSIDS_GET_CFM                ((CsrWifiSmePrim)(0x003E + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_WIFI_ON_IND                          ((CsrWifiSmePrim)(0x003F + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_SME_COMMON_CONFIG_GET_CFM            ((CsrWifiSmePrim)(0x0040 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_SME_COMMON_CONFIG_SET_CFM            ((CsrWifiSmePrim)(0x0041 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_INTERFACE_CAPABILITY_GET_CFM         ((CsrWifiSmePrim)(0x0042 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_ERROR_IND                            ((CsrWifiSmePrim)(0x0043 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_INFO_IND                             ((CsrWifiSmePrim)(0x0044 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_CORE_DUMP_IND                        ((CsrWifiSmePrim)(0x0045 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_AMP_STATUS_CHANGE_IND                ((CsrWifiSmePrim)(0x0046 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+#define CSR_WIFI_SME_WPS_CONFIGURATION_CFM                ((CsrWifiSmePrim)(0x0047 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST))
+
+#define CSR_WIFI_SME_PRIM_UPSTREAM_HIGHEST             (0x0047 + CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST)
+
+#define CSR_WIFI_SME_PRIM_DOWNSTREAM_COUNT             (CSR_WIFI_SME_PRIM_DOWNSTREAM_HIGHEST + 1 - CSR_WIFI_SME_PRIM_DOWNSTREAM_LOWEST)
+#define CSR_WIFI_SME_PRIM_UPSTREAM_COUNT               (CSR_WIFI_SME_PRIM_UPSTREAM_HIGHEST   + 1 - CSR_WIFI_SME_PRIM_UPSTREAM_LOWEST)
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeActivateReq
+
+  DESCRIPTION
+    The WMA sends this primitive to activate the SME.
+    The WMA must activate the SME before it can send any other primitive.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeActivateReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAdhocConfigGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the adHocConfig parameter.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeAdhocConfigGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAdhocConfigSetReq
+
+  DESCRIPTION
+    This primitive sets the value of the adHocConfig parameter.
+
+  MEMBERS
+    common      - Common header for use with the CsrWifiFsm Module
+    adHocConfig - Sets the values to use when starting an ad hoc network.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrWifiSmeAdHocConfig adHocConfig;
+} CsrWifiSmeAdhocConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeBlacklistReq
+
+  DESCRIPTION
+    The wireless manager application should call this primitive to notify the
+    driver of any networks that should not be connected to. The interface
+    allows the wireless manager application to query, add, remove, and flush
+    the BSSIDs that the driver may not connect or roam to.
+    When this primitive adds to the black list the BSSID to which the SME is
+    currently connected, the SME will try to roam, if applicable, to another
+    BSSID in the same ESS; if the roaming procedure fails, the SME will
+    disconnect.
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    action          - The value of the CsrWifiSmeListAction parameter instructs
+                      the driver to modify or provide the list of blacklisted
+                      networks.
+    setAddressCount - Number of BSSIDs sent with this primitive
+    setAddresses    - Pointer to the list of BBSIDs sent with the primitive, set
+                      to NULL if none is sent.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrUint16            interfaceTag;
+    CsrWifiSmeListAction action;
+    CsrUint8             setAddressCount;
+    CsrWifiMacAddress   *setAddresses;
+} CsrWifiSmeBlacklistReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCalibrationDataGetReq
+
+  DESCRIPTION
+    This primitive retrieves the Wi-Fi radio calibration data.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeCalibrationDataGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCalibrationDataSetReq
+
+  DESCRIPTION
+    This primitive sets the Wi-Fi radio calibration data.
+    The usage of the primitive with proper calibration data will avoid
+    time-consuming configuration after power-up.
+
+  MEMBERS
+    common                - Common header for use with the CsrWifiFsm Module
+    calibrationDataLength - Number of bytes in the buffer pointed by
+                            calibrationData
+    calibrationData       - Pointer to a buffer of length calibrationDataLength
+                            containing the calibration data
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       calibrationDataLength;
+    CsrUint8       *calibrationData;
+} CsrWifiSmeCalibrationDataSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCcxConfigGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the CcxConfig parameter.
+    CURRENTLY NOT SUPPORTED.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeCcxConfigGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCcxConfigSetReq
+
+  DESCRIPTION
+    This primitive sets the value of the CcxConfig parameter.
+    CURRENTLY NOT SUPPORTED.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    ccxConfig    - Currently not supported
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent     common;
+    CsrUint16           interfaceTag;
+    CsrWifiSmeCcxConfig ccxConfig;
+} CsrWifiSmeCcxConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexConfigGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the CoexConfig parameter.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeCoexConfigGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexConfigSetReq
+
+  DESCRIPTION
+    This primitive sets the value of the CoexConfig parameter.
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    coexConfig - Configures the coexistence behaviour
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrWifiSmeCoexConfig coexConfig;
+} CsrWifiSmeCoexConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexInfoGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the CoexInfo parameter.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeCoexInfoGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectReq
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to start the
+    process of joining an 802.11 wireless network or to start an ad hoc
+    network.
+    The structure pointed by connectionConfig contains parameters describing
+    the network to join or, in case of an ad hoc network, to host or join.
+    The SME will select a network, perform the IEEE 802.11 Join, Authenticate
+    and Associate exchanges.
+    The SME selects the networks from the current scan list that match both
+    the SSID and BSSID, however either or both of these may be the wildcard
+    value. Using this rule, the following operations are possible:
+      * To connect to a network by name, specify the SSID and set the BSSID to
+        0xFF 0xFF 0xFF 0xFF 0xFF 0xFF. If there are two or more networks visible,
+        the SME will select the one with the strongest signal.
+      * To connect to a specific network, specify the BSSID. The SSID is
+        optional, but if given it must match the SSID of the network. An empty
+        SSID may be specified by setting the SSID length to zero. Please note
+        that if the BSSID is specified (i.e. not equal to 0xFF 0xFF 0xFF 0xFF
+        0xFF 0xFF), the SME will not attempt to roam if signal conditions become
+        poor, even if there is an alternative AP with an SSID that matches the
+        current network SSID.
+      * To connect to any network matching the other parameters (i.e. security,
+        etc), set the SSID length to zero and set the BSSID to 0xFF 0xFF 0xFF
+        0xFF 0xFF 0xFF. In this case, the SME will order all available networks
+        by their signal strengths and will iterate through this list until it
+        successfully connects.
+    NOTE: Specifying the BSSID will restrict the selection to one specific
+    network. If SSID and BSSID are given, they must both match the network
+    for it to be selected. To select a network based on the SSID only, the
+    wireless manager application must set the BSSID to 0xFF 0xFF 0xFF 0xFF
+    0xFF 0xFF.
+    The SME will try to connect to each network that matches the provided
+    parameters, one by one, until it succeeds or has tried unsuccessfully
+    with all the matching networks.
+    If there is no network that matches the parameters and the request allows
+    to host an ad hoc network, the SME will advertise a new ad hoc network
+    instead.
+    If the SME cannot connect, it will notify the failure in the confirm.
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    interfaceTag     - Interface Identifier; unique identifier of an interface
+    connectionConfig - Describes the candidate network to join or to host.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent            common;
+    CsrUint16                  interfaceTag;
+    CsrWifiSmeConnectionConfig connectionConfig;
+} CsrWifiSmeConnectReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionConfigGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the ConnectionConfig parameter.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeConnectionConfigGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionInfoGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the ConnectionInfo parameter.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeConnectionInfoGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionStatsGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the ConnectionStats parameter.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeConnectionStatsGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDeactivateReq
+
+  DESCRIPTION
+    The WMA sends this primitive to deactivate the SME.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeDeactivateReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDisconnectReq
+
+  DESCRIPTION
+    The wireless manager application may disconnect from the current network
+    by calling this primitive
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeDisconnectReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeEventMaskSetReq
+
+  DESCRIPTION
+    The wireless manager application may register with the SME to receive
+    notification of interesting events. Indications will be sent only if the
+    wireless manager explicitly registers to be notified of that event.
+    indMask is a bit mask of values defined in CsrWifiSmeIndicationsMask.
+
+  MEMBERS
+    common  - Common header for use with the CsrWifiFsm Module
+    indMask - Set mask with values from CsrWifiSmeIndications
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrWifiSmeIndicationsMask indMask;
+} CsrWifiSmeEventMaskSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeHostConfigGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the hostConfig parameter.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeHostConfigGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeHostConfigSetReq
+
+  DESCRIPTION
+    This primitive sets the value of the hostConfig parameter.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    hostConfig   - Communicates a change of host power state (for example, on
+                   mains power, on battery power etc) and of the periodicity of
+                   traffic data
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrUint16            interfaceTag;
+    CsrWifiSmeHostConfig hostConfig;
+} CsrWifiSmeHostConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeKeyReq
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to add or remove
+    keys that the chip should use for encryption of data.
+    The interface allows the wireless manager application to add and remove
+    keys according to the specified action.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    action       - The value of the CsrWifiSmeListAction parameter instructs the
+                   driver to modify or provide the list of keys.
+                   CSR_WIFI_SME_LIST_ACTION_GET is not supported here.
+    key          - Key to be added or removed
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrUint16            interfaceTag;
+    CsrWifiSmeListAction action;
+    CsrWifiSmeKey        key;
+} CsrWifiSmeKeyReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeLinkQualityGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the LinkQuality parameter.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeLinkQualityGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibConfigGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the MibConfig parameter.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeMibConfigGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibConfigSetReq
+
+  DESCRIPTION
+    This primitive sets the value of the MibConfig parameter.
+
+  MEMBERS
+    common    - Common header for use with the CsrWifiFsm Module
+    mibConfig - Conveys the desired value of various IEEE 802.11 attributes as
+                currently configured
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent     common;
+    CsrWifiSmeMibConfig mibConfig;
+} CsrWifiSmeMibConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibGetNextReq
+
+  DESCRIPTION
+    To read a sequence of MIB parameters, for example a table, call this
+    primitive to find the name of the next MIB variable
+
+  MEMBERS
+    common             - Common header for use with the CsrWifiFsm Module
+    mibAttributeLength - Length of mibAttribute
+    mibAttribute       - Points to a VarBind or VarBindList containing the
+                         name(s) of the MIB variable(s) to search from.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       mibAttributeLength;
+    CsrUint8       *mibAttribute;
+} CsrWifiSmeMibGetNextReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibGetReq
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to retrieve one or
+    more MIB variables.
+
+  MEMBERS
+    common             - Common header for use with the CsrWifiFsm Module
+    mibAttributeLength - Length of mibAttribute
+    mibAttribute       - Points to the VarBind or VarBindList containing the
+                         names of the MIB variables to be retrieved
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       mibAttributeLength;
+    CsrUint8       *mibAttribute;
+} CsrWifiSmeMibGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibSetReq
+
+  DESCRIPTION
+    The SME provides raw access to the MIB on the chip, which may be used by
+    some configuration or diagnostic utilities, but is not normally needed by
+    the wireless manager application.
+    The MIB access functions use BER encoded names (OID) of the MIB
+    parameters and BER encoded values, as described in the chip Host
+    Interface Protocol Specification.
+    The MIB parameters are described in 'Wi-Fi 5.0.0 Management Information
+    Base Reference Guide'.
+    The wireless manager application calls this primitive to set one or more
+    MIB variables
+
+  MEMBERS
+    common             - Common header for use with the CsrWifiFsm Module
+    mibAttributeLength - Length of mibAttribute
+    mibAttribute       - Points to the VarBind or VarBindList containing the
+                         names and values of the MIB variables to set
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       mibAttributeLength;
+    CsrUint8       *mibAttribute;
+} CsrWifiSmeMibSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMulticastAddressReq
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to specify the
+    multicast addresses which the chip should recognise. The interface allows
+    the wireless manager application to query, add, remove and flush the
+    multicast addresses for the network interface according to the specified
+    action.
+
+  MEMBERS
+    common            - Common header for use with the CsrWifiFsm Module
+    interfaceTag      - Interface Identifier; unique identifier of an interface
+    action            - The value of the CsrWifiSmeListAction parameter
+                        instructs the driver to modify or provide the list of
+                        MAC addresses.
+    setAddressesCount - Number of MAC addresses sent with the primitive
+    setAddresses      - Pointer to the list of MAC Addresses sent with the
+                        primitive, set to NULL if none is sent.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrUint16            interfaceTag;
+    CsrWifiSmeListAction action;
+    CsrUint8             setAddressesCount;
+    CsrWifiMacAddress   *setAddresses;
+} CsrWifiSmeMulticastAddressReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePacketFilterSetReq
+
+  DESCRIPTION
+    The wireless manager application should call this primitive to enable or
+    disable filtering of broadcast packets: uninteresting broadcast packets
+    will be dropped by the Wi-Fi chip, instead of passing them up to the
+    host.
+    This has the advantage of saving power in the host application processor
+    as it removes the need to process unwanted packets.
+    All broadcast packets are filtered according to the filter and the filter
+    mode provided, except ARP packets, which are filtered using
+    arpFilterAddress.
+    Filters are not cumulative: only the parameters specified in the most
+    recent successful request are significant.
+    For more information, see 'UniFi Firmware API Specification'.
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    interfaceTag     - Interface Identifier; unique identifier of an interface
+    filterLength     - Length of the filter in bytes.
+                       filterLength=0 disables the filter previously set
+    filter           - Points to the first byte of the filter provided, if any.
+                       This shall include zero or more instance of the
+                       information elements of one of these types
+                         * Traffic Classification (TCLAS) elements
+                         * WMM-SA TCLAS elements
+    mode             - Specifies whether the filter selects or excludes packets
+                       matching the filter
+    arpFilterAddress - IPv4 address to be used for filtering the ARP packets.
+                         * If the specified address is the IPv4 broadcast address
+                           (255.255.255.255), all ARP packets are reported to the
+                           host,
+                         * If the specified address is NOT the IPv4 broadcast
+                           address, only ARP packets with the specified address in
+                           the Source or Target Protocol Address fields are reported
+                           to the host
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent            common;
+    CsrUint16                  interfaceTag;
+    CsrUint16                  filterLength;
+    CsrUint8                  *filter;
+    CsrWifiSmePacketFilterMode mode;
+    CsrWifiIp4Address          arpFilterAddress;
+} CsrWifiSmePacketFilterSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePermanentMacAddressGetReq
+
+  DESCRIPTION
+    This primitive retrieves the MAC address stored in EEPROM
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmePermanentMacAddressGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePmkidReq
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to request an
+    operation on the SME PMKID list.
+    The action argument specifies the operation to perform.
+    When the connection is complete, the wireless manager application may
+    then send and receive EAPOL packets to complete WPA or WPA2
+    authentication if appropriate.
+    The wireless manager application can then pass the resulting encryption
+    keys using this primitive.
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    action         - The value of the CsrWifiSmeListAction parameter instructs
+                     the driver to modify or provide the list of PMKIDs.
+    setPmkidsCount - Number of PMKIDs sent with the primitive
+    setPmkids      - Pointer to the list of PMKIDs sent with the primitive, set
+                     to NULL if none is sent.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrUint16            interfaceTag;
+    CsrWifiSmeListAction action;
+    CsrUint8             setPmkidsCount;
+    CsrWifiSmePmkid     *setPmkids;
+} CsrWifiSmePmkidReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePowerConfigGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the PowerConfig parameter.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmePowerConfigGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePowerConfigSetReq
+
+  DESCRIPTION
+    This primitive sets the value of the PowerConfig parameter.
+
+  MEMBERS
+    common      - Common header for use with the CsrWifiFsm Module
+    powerConfig - Power saving configuration
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrWifiSmePowerConfig powerConfig;
+} CsrWifiSmePowerConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRegulatoryDomainInfoGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the RegulatoryDomainInfo parameter.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeRegulatoryDomainInfoGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamingConfigGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the RoamingConfig parameter.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeRoamingConfigGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamingConfigSetReq
+
+  DESCRIPTION
+    This primitive sets the value of the RoamingConfig parameter.
+
+  MEMBERS
+    common        - Common header for use with the CsrWifiFsm Module
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    roamingConfig - Desired roaming behaviour values
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent         common;
+    CsrUint16               interfaceTag;
+    CsrWifiSmeRoamingConfig roamingConfig;
+} CsrWifiSmeRoamingConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanConfigGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the ScanConfig parameter.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeScanConfigGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanConfigSetReq
+
+  DESCRIPTION
+    This primitive sets the value of the ScanConfig parameter.
+    The SME normally configures the firmware to perform autonomous scanning
+    without involving the host.
+    The firmware passes beacon / probe response or indicates loss of beacon
+    on certain changes of state, for example:
+      * A new AP is seen for the first time
+      * An AP is no longer visible
+      * The signal strength of an AP changes by more than a certain amount, as
+        configured by the thresholds in the scanConfig parameter
+    In addition to the autonomous scan, the wireless manager application may
+    request a scan at any time using CSR_WIFI_SME_SCAN_FULL_REQ.
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    scanConfig - Reports the configuration for the autonomous scanning behaviour
+                 of the firmware
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrWifiSmeScanConfig scanConfig;
+} CsrWifiSmeScanConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanFullReq
+
+  DESCRIPTION
+    The wireless manager application should call this primitive to request a
+    full scan.
+    Channels are scanned actively or passively according to the requirement
+    set by regulatory domain.
+    If the SME receives this primitive while a full scan is going on, the new
+    request is buffered and it will be served after the current full scan is
+    completed.
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    ssidCount        - Number of SSIDs provided.
+                       If it is 0, the SME will attempt to detect any network
+    ssid             - Points to the first SSID provided, if any.
+    bssid            - BSS identifier.
+                       If it is equal to FF-FF-FF-FF-FF, the SME will listen for
+                       messages from any BSS.
+                       If it is different from FF-FF-FF-FF-FF and any SSID is
+                       provided, one SSID must match the network of the BSS.
+    forceScan        - Forces the scan even if the SME is in a state which would
+                       normally prevent it (e.g. autonomous scan is running).
+    bssType          - Type of BSS to scan for
+    scanType         - Type of scan to perform
+    channelListCount - Number of channels provided.
+                       If it is 0, the SME will initiate a scan of all the
+                       supported channels that are permitted by the current
+                       regulatory domain.
+    channelList      - Points to the first channel , or NULL if channelListCount
+                       is zero.
+    probeIeLength    - Length of the information element in bytes to be sent
+                       with the probe message.
+    probeIe          - Points to the first byte of the information element to be
+                       sent with the probe message.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent    common;
+    CsrUint8           ssidCount;
+    CsrWifiSsid       *ssid;
+    CsrWifiMacAddress  bssid;
+    CsrBool            forceScan;
+    CsrWifiSmeBssType  bssType;
+    CsrWifiSmeScanType scanType;
+    CsrUint16          channelListCount;
+    CsrUint8          *channelList;
+    CsrUint16          probeIeLength;
+    CsrUint8          *probeIe;
+} CsrWifiSmeScanFullReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanResultsFlushReq
+
+  DESCRIPTION
+    The Wireless Manager calls this primitive to ask the SME to delete all
+    scan results from its cache, except for the scan result of any currently
+    connected network.
+    As scan results are received by the SME from the firmware, they are
+    cached in the SME memory.
+    Any time the Wireless Manager requests scan results, they are returned
+    from the SME internal cache.
+    For some applications it may be desirable to clear this cache prior to
+    requesting that a scan be performed; this will ensure that the cache then
+    only contains the networks detected in the most recent scan.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeScanResultsFlushReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanResultsGetReq
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to retrieve the
+    current set of scan results, either after receiving a successful
+    CSR_WIFI_SME_SCAN_FULL_CFM, or to get autonomous scan results.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeScanResultsGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeStaConfigGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the SmeStaConfig parameter.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+} CsrWifiSmeSmeStaConfigGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeStaConfigSetReq
+
+  DESCRIPTION
+    This primitive sets the value of the SmeConfig parameter.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    smeConfig    - SME Station Parameters to be set
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent     common;
+    CsrUint16           interfaceTag;
+    CsrWifiSmeStaConfig smeConfig;
+} CsrWifiSmeSmeStaConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeStationMacAddressGetReq
+
+  DESCRIPTION
+    This primitives is used to retrieve the current MAC address used by the
+    station.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeStationMacAddressGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeTspecReq
+
+  DESCRIPTION
+    The wireless manager application should call this primitive to use the
+    TSPEC feature.
+    The chip supports the use of TSPECs and TCLAS for the use of IEEE
+    802.11/WMM Quality of Service features.
+    The API allows the wireless manager application to supply a correctly
+    formatted TSPEC and TCLAS pair to the driver.
+    After performing basic validation, the driver negotiates the installation
+    of the TSPEC with the AP as defined by the 802.11 specification.
+    The driver retains all TSPEC and TCLAS pairs until they are specifically
+    removed.
+    It is not compulsory for a TSPEC to have a TCLAS (NULL is used to
+    indicate that no TCLAS is supplied), while a TCLASS always require a
+    TSPEC.
+    The format of the TSPEC element is specified in 'WMM (including WMM Power
+    Save) Specification - Version 1.1' and 'ANSI/IEEE Std 802.11-REVmb/D3.0'.
+    For more information, see 'UniFi Configuring WMM and WMM-PS'.
+
+  MEMBERS
+    common        - Common header for use with the CsrWifiFsm Module
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    action        - Specifies the action to be carried out on the list of TSPECs.
+                    CSR_WIFI_SME_LIST_ACTION_FLUSH is not applicable here.
+    transactionId - Unique Transaction ID for the TSPEC, as assigned by the
+                    driver
+    strict        - If it set to false, allows the SME to perform automatic
+                    TSPEC negotiation
+    ctrlMask      - Additional TSPEC configuration for CCX.
+                    Set mask with values from CsrWifiSmeTspecCtrl.
+                    CURRENTLY NOT SUPPORTED
+    tspecLength   - Length of the TSPEC.
+    tspec         - Points to the first byte of the TSPEC
+    tclasLength   - Length of the TCLAS.
+                    If it is equal to 0, no TCLASS is provided for the TSPEC
+    tclas         - Points to the first byte of the TCLAS, if any.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent         common;
+    CsrUint16               interfaceTag;
+    CsrWifiSmeListAction    action;
+    CsrUint32               transactionId;
+    CsrBool                 strict;
+    CsrWifiSmeTspecCtrlMask ctrlMask;
+    CsrUint16               tspecLength;
+    CsrUint8               *tspec;
+    CsrUint16               tclasLength;
+    CsrUint8               *tclas;
+} CsrWifiSmeTspecReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeVersionsGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the Versions parameter.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeVersionsGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiFlightmodeReq
+
+  DESCRIPTION
+    The wireless manager application may call this primitive on boot-up of
+    the platform to ensure that the chip is placed in a mode that prevents
+    any emission of RF energy.
+    This primitive is an alternative to CSR_WIFI_SME_WIFI_ON_REQ.
+    As in CSR_WIFI_SME_WIFI_ON_REQ, it causes the download of the patch file
+    (if any) and the programming of the initial MIB settings (if supplied by
+    the WMA), but it also ensures that the chip is left in its lowest
+    possible power-mode with the radio subsystems disabled.
+    This feature is useful on platforms where power cannot be removed from
+    the chip (leaving the chip not initialised will cause it to consume more
+    power so calling this function ensures that the chip is initialised into
+    a low power mode but without entering a state where it could emit any RF
+    energy).
+    NOTE: this primitive does not cause the Wi-Fi to change state: Wi-Fi
+    stays conceptually off. Configuration primitives can be sent after
+    CSR_WIFI_SME_WIFI_FLIGHTMODE_REQ and the configuration will be maintained.
+    Requests that require the state of the Wi-Fi to be ON will return
+    CSR_WIFI_SME_STATUS_WIFI_OFF in their confirms.
+
+  MEMBERS
+    common        - Common header for use with the CsrWifiFsm Module
+    address       - Optionally specifies a station MAC address.
+                    In normal use, the manager should set the address to 0xFF
+                    0xFF 0xFF 0xFF 0xFF 0xFF, which will cause the chip to use
+                    the MAC address in the MIB.
+    mibFilesCount - Number of provided data blocks with initial MIB values
+    mibFiles      - Points to the first data block with initial MIB values.
+                    These data blocks are typically the contents of the provided
+                    files ufmib.dat and localmib.dat, available from the host
+                    file system, if they exist.
+                    These files typically contain radio tuning and calibration
+                    values.
+                    More values can be created using the Host Tools.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrWifiMacAddress    address;
+    CsrUint16            mibFilesCount;
+    CsrWifiSmeDataBlock *mibFiles;
+} CsrWifiSmeWifiFlightmodeReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOffReq
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to turn off the
+    chip, thus saving power when Wi-Fi is not in use.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeWifiOffReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOnReq
+
+  DESCRIPTION
+    The wireless manager application calls this primitive to turn on the
+    Wi-Fi chip.
+    If the Wi-Fi chip is currently off, the SME turns the Wi-Fi chip on,
+    downloads the patch file (if any), and programs the initial MIB settings
+    (if supplied by the WMA).
+    The patch file is not provided with the SME API; its downloading is
+    automatic and handled internally by the system.
+    The MIB settings, when provided, override the default values that the
+    firmware loads from EEPROM.
+    If the Wi-Fi chip is already on, the SME takes no action and returns a
+    successful status in the confirm.
+
+  MEMBERS
+    common        - Common header for use with the CsrWifiFsm Module
+    address       - Optionally specifies a station MAC address.
+                    In normal use, the manager should set the address to 0xFF
+                    0xFF 0xFF 0xFF 0xFF 0xFF, which will cause the chip to use
+                    the MAC address in the MIB
+    mibFilesCount - Number of provided data blocks with initial MIB values
+    mibFiles      - Points to the first data block with initial MIB values.
+                    These data blocks are typically the contents of the provided
+                    files ufmib.dat and localmib.dat, available from the host
+                    file system, if they exist.
+                    These files typically contain radio tuning and calibration
+                    values.
+                    More values can be created using the Host Tools.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrWifiMacAddress    address;
+    CsrUint16            mibFilesCount;
+    CsrWifiSmeDataBlock *mibFiles;
+} CsrWifiSmeWifiOnReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCloakedSsidsSetReq
+
+  DESCRIPTION
+    This primitive sets the list of cloaked SSIDs for which the WMA possesses
+    profiles.
+    When the driver detects a cloaked AP, the SME will explicitly scan for it
+    using the list of cloaked SSIDs provided it, and, if the scan succeeds,
+    it will report the AP to the WMA either via CSR_WIFI_SME_SCAN_RESULT_IND
+    (if registered) or via CSR_WIFI_SCAN_RESULT_GET_CFM.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    cloakedSsids - Sets the list of cloaked SSIDs
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent             common;
+    CsrWifiSmeCloakedSsidConfig cloakedSsids;
+} CsrWifiSmeCloakedSsidsSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCloakedSsidsGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the CloakedSsids parameter.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeCloakedSsidsGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeCommonConfigGetReq
+
+  DESCRIPTION
+    This primitive gets the value of the Sme common parameter.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeSmeCommonConfigGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeCommonConfigSetReq
+
+  DESCRIPTION
+    This primitive sets the value of the Sme common.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    deviceConfig - Configuration options in the SME
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent        common;
+    CsrWifiSmeDeviceConfig deviceConfig;
+} CsrWifiSmeSmeCommonConfigSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeInterfaceCapabilityGetReq
+
+  DESCRIPTION
+    The Wireless Manager calls this primitive to ask the SME for the
+    capabilities of the supported interfaces
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+} CsrWifiSmeInterfaceCapabilityGetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsConfigurationReq
+
+  DESCRIPTION
+    This primitive passes the WPS information for the device to SME. This may
+    be accepted only if no interface is active.
+
+  MEMBERS
+    common    - Common header for use with the CsrWifiFsm Module
+    wpsConfig - WPS config.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent     common;
+    CsrWifiSmeWpsConfig wpsConfig;
+} CsrWifiSmeWpsConfigurationReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSetReq
+
+  DESCRIPTION
+    Used to pass custom data to the SME. Format is the same as 802.11 Info
+    Elements => | Id | Length | Data
+    1) Cmanr Test Mode "Id:0 Length:1 Data:0x00 = OFF 0x01 = ON" "0x00 0x01
+    (0x00|0x01)"
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    dataLength - Number of bytes in the buffer pointed to by 'data'
+    data       - Pointer to the buffer containing 'dataLength' bytes
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint32       dataLength;
+    CsrUint8       *data;
+} CsrWifiSmeSetReq;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeActivateCfm
+
+  DESCRIPTION
+    The SME sends this primitive when the activation is complete.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeActivateCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAdhocConfigGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common      - Common header for use with the CsrWifiFsm Module
+    status      - Reports the result of the request
+    adHocConfig - Contains the values used when starting an Ad-hoc (IBSS)
+                  connection.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrResult             status;
+    CsrWifiSmeAdHocConfig adHocConfig;
+} CsrWifiSmeAdhocConfigGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAdhocConfigSetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeAdhocConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAssociationCompleteInd
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive it whenever it completes an attempt to associate with an AP. If
+    the association was successful, status will be set to
+    CSR_WIFI_SME_STATUS_SUCCESS, otherwise status and deauthReason shall be
+    set to appropriate error codes.
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    status         - Reports the result of the association procedure
+    connectionInfo - This parameter is relevant only if result is
+                     CSR_WIFI_SME_STATUS_SUCCESS:
+                     it points to the connection information for the new network
+    deauthReason   - This parameter is relevant only if result is not
+                     CSR_WIFI_SME_STATUS_SUCCESS:
+                     if the AP deauthorised the station, it gives the reason of
+                     the deauthorization
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrResult                 status;
+    CsrWifiSmeConnectionInfo  connectionInfo;
+    CsrWifiSmeIEEE80211Reason deauthReason;
+} CsrWifiSmeAssociationCompleteInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAssociationStartInd
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive it whenever it begins an attempt to associate with an AP.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    address      - BSSID of the associating network
+    ssid         - Service Set identifier of the associating network
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrUint16         interfaceTag;
+    CsrWifiMacAddress address;
+    CsrWifiSsid       ssid;
+} CsrWifiSmeAssociationStartInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeBlacklistCfm
+
+  DESCRIPTION
+    The SME will call this primitive when the action on the blacklist has
+    completed. For a GET action, this primitive also reports the list of
+    BBSIDs in the blacklist.
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    status          - Reports the result of the request
+    action          - Action in the request
+    getAddressCount - This parameter is only relevant if action is
+                      CSR_WIFI_SME_LIST_ACTION_GET:
+                      number of BSSIDs sent with this primitive
+    getAddresses    - Pointer to the list of BBSIDs sent with the primitive, set
+                      to NULL if none is sent.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrUint16            interfaceTag;
+    CsrResult            status;
+    CsrWifiSmeListAction action;
+    CsrUint8             getAddressCount;
+    CsrWifiMacAddress   *getAddresses;
+} CsrWifiSmeBlacklistCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCalibrationDataGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common                - Common header for use with the CsrWifiFsm Module
+    status                - Reports the result of the request
+    calibrationDataLength - Number of bytes in the buffer pointed by
+                            calibrationData
+    calibrationData       - Pointer to a buffer of length calibrationDataLength
+                            containing the calibration data
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+    CsrUint16       calibrationDataLength;
+    CsrUint8       *calibrationData;
+} CsrWifiSmeCalibrationDataGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCalibrationDataSetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeCalibrationDataSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCcxConfigGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+    ccxConfig    - Currently not supported
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent     common;
+    CsrUint16           interfaceTag;
+    CsrResult           status;
+    CsrWifiSmeCcxConfig ccxConfig;
+} CsrWifiSmeCcxConfigGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCcxConfigSetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmeCcxConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexConfigGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    status     - Reports the result of the request
+    coexConfig - Reports the parameters used to configure the coexistence
+                 behaviour
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrResult            status;
+    CsrWifiSmeCoexConfig coexConfig;
+} CsrWifiSmeCoexConfigGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexConfigSetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeCoexConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoexInfoGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common   - Common header for use with the CsrWifiFsm Module
+    status   - Reports the result of the request
+    coexInfo - Reports information and state related to coexistence.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent    common;
+    CsrResult          status;
+    CsrWifiSmeCoexInfo coexInfo;
+} CsrWifiSmeCoexInfoGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectCfm
+
+  DESCRIPTION
+    The SME calls this primitive when the connection exchange is complete or
+    all connection attempts fail.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request.
+                   CSR_WIFI_SME_STATUS_NOT_FOUND: all attempts by the SME to
+                   locate the requested AP failed
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmeConnectCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionConfigGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    interfaceTag     - Interface Identifier; unique identifier of an interface
+    status           - Reports the result of the request
+    connectionConfig - Parameters used by the SME for selecting a network
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent            common;
+    CsrUint16                  interfaceTag;
+    CsrResult                  status;
+    CsrWifiSmeConnectionConfig connectionConfig;
+} CsrWifiSmeConnectionConfigGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionInfoGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    status         - Reports the result of the request
+    connectionInfo - Information about the current connection
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent          common;
+    CsrUint16                interfaceTag;
+    CsrResult                status;
+    CsrWifiSmeConnectionInfo connectionInfo;
+} CsrWifiSmeConnectionInfoGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionQualityInd
+
+  DESCRIPTION
+    The SME sends this primitive to all the tasks that have registered to
+    receive it whenever the value of the current connection quality
+    parameters change by more than a certain configurable amount.
+    The wireless manager application may configure the trigger thresholds for
+    this indication using the field in smeConfig parameter of
+    CSR_WIFI_SME_SME_CONFIG_SET_REQ.
+    Connection quality messages can be suppressed by setting both thresholds
+    to zero.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    linkQuality  - Indicates the quality of the link
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrUint16             interfaceTag;
+    CsrWifiSmeLinkQuality linkQuality;
+} CsrWifiSmeConnectionQualityInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeConnectionStatsGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    status          - Reports the result of the request
+    connectionStats - Statistics for current connection.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrResult                 status;
+    CsrWifiSmeConnectionStats connectionStats;
+} CsrWifiSmeConnectionStatsGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDeactivateCfm
+
+  DESCRIPTION
+    The SME sends this primitive when the deactivation is complete.
+    The WMA cannot send any more primitives until it actives the SME again
+    sending another CSR_WIFI_SME_ACTIVATE_REQ.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeDeactivateCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeDisconnectCfm
+
+  DESCRIPTION
+    On reception of CSR_WIFI_SME_DISCONNECT_REQ the SME will perform a
+    disconnect operation, sending a CsrWifiSmeMediaStatusInd with
+    CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED and then call this primitive when
+    disconnection is complete.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmeDisconnectCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeEventMaskSetCfm
+
+  DESCRIPTION
+    The SME calls the primitive to report the result of the request
+    primitive.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeEventMaskSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeHostConfigGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+    hostConfig   - Current host power state.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrUint16            interfaceTag;
+    CsrResult            status;
+    CsrWifiSmeHostConfig hostConfig;
+} CsrWifiSmeHostConfigGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeHostConfigSetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmeHostConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeIbssStationInd
+
+  DESCRIPTION
+    The SME will send this primitive to indicate that a station has joined or
+    left the ad-hoc network.
+
+  MEMBERS
+    common      - Common header for use with the CsrWifiFsm Module
+    address     - MAC address of the station that has joined or left
+    isconnected - TRUE if the station joined, FALSE if the station left
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrWifiMacAddress address;
+    CsrBool           isconnected;
+} CsrWifiSmeIbssStationInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeKeyCfm
+
+  DESCRIPTION
+    The SME calls the primitive to report the result of the request
+    primitive.
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    status         - Reports the result of the request
+    action         - Action in the request
+    keyType        - Type of the key added/deleted
+    peerMacAddress - Peer MAC Address of the key added/deleted
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrUint16            interfaceTag;
+    CsrResult            status;
+    CsrWifiSmeListAction action;
+    CsrWifiSmeKeyType    keyType;
+    CsrWifiMacAddress    peerMacAddress;
+} CsrWifiSmeKeyCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeLinkQualityGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+    linkQuality  - Indicates the quality of the link
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrUint16             interfaceTag;
+    CsrResult             status;
+    CsrWifiSmeLinkQuality linkQuality;
+} CsrWifiSmeLinkQualityGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMediaStatusInd
+
+  DESCRIPTION
+    The SME sends this primitive to all the tasks that have registered to
+    receive it when a network connection is established, lost or has moved to
+    another AP.
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    mediaStatus    - Indicates the media status
+    connectionInfo - This parameter is relevant only if the mediaStatus is
+                     CSR_WIFI_SME_MEDIA_STATUS_CONNECTED:
+                     it points to the connection information for the new network
+    disassocReason - This parameter is relevant only if the mediaStatus is
+                     CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED:
+                     if a disassociation has occurred it gives the reason of the
+                     disassociation
+    deauthReason   - This parameter is relevant only if the mediaStatus is
+                     CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED:
+                     if a deauthentication has occurred it gives the reason of
+                     the deauthentication
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrWifiSmeMediaStatus     mediaStatus;
+    CsrWifiSmeConnectionInfo  connectionInfo;
+    CsrWifiSmeIEEE80211Reason disassocReason;
+    CsrWifiSmeIEEE80211Reason deauthReason;
+} CsrWifiSmeMediaStatusInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibConfigGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common    - Common header for use with the CsrWifiFsm Module
+    status    - Reports the result of the request
+    mibConfig - Reports various IEEE 802.11 attributes as currently configured
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent     common;
+    CsrResult           status;
+    CsrWifiSmeMibConfig mibConfig;
+} CsrWifiSmeMibConfigGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibConfigSetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeMibConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibGetCfm
+
+  DESCRIPTION
+    The SME calls this primitive to return the requested MIB variable values.
+
+  MEMBERS
+    common             - Common header for use with the CsrWifiFsm Module
+    status             - Reports the result of the request
+    mibAttributeLength - Length of mibAttribute
+    mibAttribute       - Points to the VarBind or VarBindList containing the
+                         names and values of the MIB variables requested
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+    CsrUint16       mibAttributeLength;
+    CsrUint8       *mibAttribute;
+} CsrWifiSmeMibGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibGetNextCfm
+
+  DESCRIPTION
+    The SME calls this primitive to return the requested MIB name(s).
+    The wireless manager application can then read the value of the MIB
+    variable using CSR_WIFI_SME_MIB_GET_REQ, using the names provided.
+
+  MEMBERS
+    common             - Common header for use with the CsrWifiFsm Module
+    status             - Reports the result of the request
+    mibAttributeLength - Length of mibAttribute
+    mibAttribute       - Points to a VarBind or VarBindList containing the
+                         name(s) of the MIB variable(s) lexicographically
+                         following the name(s) given in the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+    CsrUint16       mibAttributeLength;
+    CsrUint8       *mibAttribute;
+} CsrWifiSmeMibGetNextCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMibSetCfm
+
+  DESCRIPTION
+    The SME calls the primitive to report the result of the set primitive.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeMibSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMicFailureInd
+
+  DESCRIPTION
+    The SME sends this primitive to all the tasks that have registered to
+    receive it whenever the chip firmware reports a MIC failure.
+
+  MEMBERS
+    common        - Common header for use with the CsrWifiFsm Module
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    secondFailure - TRUE if this indication is for a second failure in 60
+                    seconds
+    count         - The number of MIC failure events since the connection was
+                    established
+    address       - MAC address of the transmitter that caused the MIC failure
+    keyType       - Type of key for which the failure occurred
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrUint16         interfaceTag;
+    CsrBool           secondFailure;
+    CsrUint16         count;
+    CsrWifiMacAddress address;
+    CsrWifiSmeKeyType keyType;
+} CsrWifiSmeMicFailureInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeMulticastAddressCfm
+
+  DESCRIPTION
+    The SME will call this primitive when the operation is complete. For a
+    GET action, this primitive reports the current list of MAC addresses.
+
+  MEMBERS
+    common            - Common header for use with the CsrWifiFsm Module
+    interfaceTag      - Interface Identifier; unique identifier of an interface
+    status            - Reports the result of the request
+    action            - Action in the request
+    getAddressesCount - This parameter is only relevant if action is
+                        CSR_WIFI_SME_LIST_ACTION_GET:
+                        number of MAC addresses sent with the primitive
+    getAddresses      - Pointer to the list of MAC Addresses sent with the
+                        primitive, set to NULL if none is sent.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrUint16            interfaceTag;
+    CsrResult            status;
+    CsrWifiSmeListAction action;
+    CsrUint8             getAddressesCount;
+    CsrWifiMacAddress   *getAddresses;
+} CsrWifiSmeMulticastAddressCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePacketFilterSetCfm
+
+  DESCRIPTION
+    The SME calls the primitive to report the result of the set primitive.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmePacketFilterSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePermanentMacAddressGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common              - Common header for use with the CsrWifiFsm Module
+    status              - Reports the result of the request
+    permanentMacAddress - MAC address stored in the EEPROM
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrResult         status;
+    CsrWifiMacAddress permanentMacAddress;
+} CsrWifiSmePermanentMacAddressGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePmkidCandidateListInd
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive it when a new network supporting preauthentication and/or PMK
+    caching is seen.
+
+  MEMBERS
+    common               - Common header for use with the CsrWifiFsm Module
+    interfaceTag         - Interface Identifier; unique identifier of an
+                           interface
+    pmkidCandidatesCount - Number of PMKID candidates provided
+    pmkidCandidates      - Points to the first PMKID candidate
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrUint8                  pmkidCandidatesCount;
+    CsrWifiSmePmkidCandidate *pmkidCandidates;
+} CsrWifiSmePmkidCandidateListInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePmkidCfm
+
+  DESCRIPTION
+    The SME will call this primitive when the operation is complete. For a
+    GET action, this primitive reports the current list of PMKIDs
+
+  MEMBERS
+    common         - Common header for use with the CsrWifiFsm Module
+    interfaceTag   - Interface Identifier; unique identifier of an interface
+    status         - Reports the result of the request
+    action         - Action in the request
+    getPmkidsCount - This parameter is only relevant if action is
+                     CSR_WIFI_SME_LIST_ACTION_GET:
+                     number of PMKIDs sent with the primitive
+    getPmkids      - Pointer to the list of PMKIDs sent with the primitive, set
+                     to NULL if none is sent.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrUint16            interfaceTag;
+    CsrResult            status;
+    CsrWifiSmeListAction action;
+    CsrUint8             getPmkidsCount;
+    CsrWifiSmePmkid     *getPmkids;
+} CsrWifiSmePmkidCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePowerConfigGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common      - Common header for use with the CsrWifiFsm Module
+    status      - Reports the result of the request
+    powerConfig - Returns the current parameters for the power configuration of
+                  the firmware
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrResult             status;
+    CsrWifiSmePowerConfig powerConfig;
+} CsrWifiSmePowerConfigGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmePowerConfigSetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmePowerConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRegulatoryDomainInfoGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    status     - Reports the result of the request
+    regDomInfo - Reports information and state related to regulatory domain
+                 operation.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent                common;
+    CsrResult                      status;
+    CsrWifiSmeRegulatoryDomainInfo regDomInfo;
+} CsrWifiSmeRegulatoryDomainInfoGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamCompleteInd
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive it whenever it completes an attempt to roam to an AP. If the roam
+    attempt was successful, status will be set to CSR_WIFI_SME_SUCCESS,
+    otherwise it shall be set to the appropriate error code.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the roaming procedure
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmeRoamCompleteInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamStartInd
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive it whenever it begins an attempt to roam to an AP.
+    If the wireless manager application connect request specified the SSID
+    and the BSSID was set to the broadcast address (0xFF 0xFF 0xFF 0xFF 0xFF
+    0xFF), the SME monitors the signal quality and maintains a list of
+    candidates to roam to. When the signal quality of the current connection
+    falls below a threshold, and there is a candidate with better quality,
+    the SME will attempt to the candidate AP.
+    If the roaming procedure succeeds, the SME will also issue a Media
+    Connect indication to inform the wireless manager application of the
+    change.
+    NOTE: to prevent the SME from initiating roaming the WMA must specify the
+    BSSID in the connection request; this forces the SME to connect only to
+    that AP.
+    The wireless manager application can obtain statistics for roaming
+    purposes using CSR_WIFI_SME_CONNECTION_QUALITY_IND and
+    CSR_WIFI_SME_CONNECTION_STATS_GET_REQ.
+    When the wireless manager application wishes to roam to another AP, it
+    must issue a connection request specifying the BSSID of the desired AP.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    roamReason   - Indicates the reason for starting the roaming procedure
+    reason80211  - Indicates the reason for deauthentication or disassociation
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrWifiSmeRoamReason      roamReason;
+    CsrWifiSmeIEEE80211Reason reason80211;
+} CsrWifiSmeRoamStartInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamingConfigGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common        - Common header for use with the CsrWifiFsm Module
+    interfaceTag  - Interface Identifier; unique identifier of an interface
+    status        - Reports the result of the request
+    roamingConfig - Reports the roaming behaviour of the driver and firmware
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent         common;
+    CsrUint16               interfaceTag;
+    CsrResult               status;
+    CsrWifiSmeRoamingConfig roamingConfig;
+} CsrWifiSmeRoamingConfigGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeRoamingConfigSetCfm
+
+  DESCRIPTION
+    This primitive sets the value of the RoamingConfig parameter.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmeRoamingConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanConfigGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    status     - Reports the result of the request
+    scanConfig - Returns the current parameters for the autonomous scanning
+                 behaviour of the firmware
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrResult            status;
+    CsrWifiSmeScanConfig scanConfig;
+} CsrWifiSmeScanConfigGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanConfigSetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeScanConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanFullCfm
+
+  DESCRIPTION
+    The SME calls this primitive when the results from the scan are
+    available.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeScanFullCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanResultInd
+
+  DESCRIPTION
+    The SME sends this primitive to all the tasks that have registered to
+    receive it whenever a scan indication is received from the firmware.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    result - Points to a buffer containing a scan result.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent      common;
+    CsrWifiSmeScanResult result;
+} CsrWifiSmeScanResultInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanResultsFlushCfm
+
+  DESCRIPTION
+    The SME will call this primitive when the cache has been cleared.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeScanResultsFlushCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeScanResultsGetCfm
+
+  DESCRIPTION
+    The SME sends this primitive to provide the current set of scan results.
+
+  MEMBERS
+    common           - Common header for use with the CsrWifiFsm Module
+    status           - Reports the result of the request
+    scanResultsCount - Number of scan results
+    scanResults      - Points to a buffer containing an array of
+                       CsrWifiSmeScanResult structures.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent       common;
+    CsrResult             status;
+    CsrUint16             scanResultsCount;
+    CsrWifiSmeScanResult *scanResults;
+} CsrWifiSmeScanResultsGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeStaConfigGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+    smeConfig    - Current SME Station Parameters
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent     common;
+    CsrUint16           interfaceTag;
+    CsrResult           status;
+    CsrWifiSmeStaConfig smeConfig;
+} CsrWifiSmeSmeStaConfigGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeStaConfigSetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface Identifier; unique identifier of an interface
+    status       - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint16       interfaceTag;
+    CsrResult       status;
+} CsrWifiSmeSmeStaConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeStationMacAddressGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common            - Common header for use with the CsrWifiFsm Module
+    status            - Reports the result of the request
+    stationMacAddress - Current MAC address of the station.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrResult         status;
+    CsrWifiMacAddress stationMacAddress[2];
+} CsrWifiSmeStationMacAddressGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeTspecInd
+
+  DESCRIPTION
+    The SME will send this primitive to all the task that have registered to
+    receive it when a status change in the TSPEC occurs.
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    transactionId   - Unique Transaction ID for the TSPEC, as assigned by the
+                      driver
+    tspecResultCode - Specifies the TSPEC operation requested by the peer
+                      station
+    tspecLength     - Length of the TSPEC.
+    tspec           - Points to the first byte of the TSPEC
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrUint32                 transactionId;
+    CsrWifiSmeTspecResultCode tspecResultCode;
+    CsrUint16                 tspecLength;
+    CsrUint8                 *tspec;
+} CsrWifiSmeTspecInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeTspecCfm
+
+  DESCRIPTION
+    The SME calls the primitive to report the result of the TSpec primitive
+    request.
+
+  MEMBERS
+    common          - Common header for use with the CsrWifiFsm Module
+    interfaceTag    - Interface Identifier; unique identifier of an interface
+    status          - Reports the result of the request
+    transactionId   - Unique Transaction ID for the TSPEC, as assigned by the
+                      driver
+    tspecResultCode - Specifies the result of the negotiated TSPEC operation
+    tspecLength     - Length of the TSPEC.
+    tspec           - Points to the first byte of the TSPEC
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent           common;
+    CsrUint16                 interfaceTag;
+    CsrResult                 status;
+    CsrUint32                 transactionId;
+    CsrWifiSmeTspecResultCode tspecResultCode;
+    CsrUint16                 tspecLength;
+    CsrUint8                 *tspec;
+} CsrWifiSmeTspecCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeVersionsGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common   - Common header for use with the CsrWifiFsm Module
+    status   - Reports the result of the request
+    versions - Version IDs of the product
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent    common;
+    CsrResult          status;
+    CsrWifiSmeVersions versions;
+} CsrWifiSmeVersionsGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiFlightmodeCfm
+
+  DESCRIPTION
+    The SME calls this primitive when the chip is initialised for low power
+    mode and with the radio subsystem disabled. To leave flight mode, and
+    enable Wi-Fi, the wireless manager application should call
+    CSR_WIFI_SME_WIFI_ON_REQ.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeWifiFlightmodeCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOffInd
+
+  DESCRIPTION
+    The SME sends this primitive to all the tasks that have registered to
+    receive it to report that the chip has been turned off.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    reason - Indicates the reason why the Wi-Fi has been switched off.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent             common;
+    CsrWifiSmeControlIndication reason;
+} CsrWifiSmeWifiOffInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOffCfm
+
+  DESCRIPTION
+    After receiving CSR_WIFI_SME_WIFI_OFF_REQ, if the chip is connected to a
+    network, the SME will perform a disconnect operation, will send a
+    CSR_WIFI_SME_MEDIA_STATUS_IND with
+    CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED, and then will call
+    CSR_WIFI_SME_WIFI_OFF_CFM when the chip is off.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeWifiOffCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOnCfm
+
+  DESCRIPTION
+    The SME sends this primitive to the task that has sent the request once
+    the chip has been initialised and is available for use.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeWifiOnCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCloakedSsidsSetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeCloakedSsidsSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCloakedSsidsGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    status       - Reports the result of the request
+    cloakedSsids - Reports list of cloaked SSIDs that are explicitly scanned for
+                   by the driver
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent             common;
+    CsrResult                   status;
+    CsrWifiSmeCloakedSsidConfig cloakedSsids;
+} CsrWifiSmeCloakedSsidsGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWifiOnInd
+
+  DESCRIPTION
+    The SME sends this primitive to all tasks that have registered to receive
+    it once the chip becomes available and ready to use.
+
+  MEMBERS
+    common  - Common header for use with the CsrWifiFsm Module
+    address - Current MAC address
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent   common;
+    CsrWifiMacAddress address;
+} CsrWifiSmeWifiOnInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeCommonConfigGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    status       - Reports the result of the request
+    deviceConfig - Configuration options in the SME
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent        common;
+    CsrResult              status;
+    CsrWifiSmeDeviceConfig deviceConfig;
+} CsrWifiSmeSmeCommonConfigGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeSmeCommonConfigSetCfm
+
+  DESCRIPTION
+    Reports the result of the request
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Reports the result of the request
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeSmeCommonConfigSetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeInterfaceCapabilityGetCfm
+
+  DESCRIPTION
+    This primitive reports the result of the request.
+
+  MEMBERS
+    common        - Common header for use with the CsrWifiFsm Module
+    status        - Result of the request
+    numInterfaces - Number of the interfaces supported
+    capBitmap     - Points to the list of capabilities bitmaps provided for each
+                    interface.
+                    The bits represent the following capabilities:
+                    -bits 7 to 4-Reserved
+                    -bit 3-AMP
+                    -bit 2-P2P
+                    -bit 1-AP
+                    -bit 0-STA
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+    CsrUint16       numInterfaces;
+    CsrUint8        capBitmap[2];
+} CsrWifiSmeInterfaceCapabilityGetCfm;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeErrorInd
+
+  DESCRIPTION
+    Important error message indicating a error of some importance
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    errorMessage - Contains the error message.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrCharString  *errorMessage;
+} CsrWifiSmeErrorInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeInfoInd
+
+  DESCRIPTION
+    Message indicating a some info about current activity. Mostly of interest
+    in testing but may be useful in the field.
+
+  MEMBERS
+    common      - Common header for use with the CsrWifiFsm Module
+    infoMessage - Contains the message.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrCharString  *infoMessage;
+} CsrWifiSmeInfoInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeCoreDumpInd
+
+  DESCRIPTION
+    The SME will send this primitive to all the tasks that have registered to
+    receive Wi-Fi Chip core dump data.
+    The core dump data may be fragmented and sent using more than one
+    indication.
+    To indicate that all the data has been sent, the last indication contains
+    a 'length' of 0 and 'data' of NULL.
+
+  MEMBERS
+    common     - Common header for use with the CsrWifiFsm Module
+    dataLength - Number of bytes in the buffer pointed to by 'data'
+    data       - Pointer to the buffer containing 'dataLength' bytes of core
+                 dump data
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrUint32       dataLength;
+    CsrUint8       *data;
+} CsrWifiSmeCoreDumpInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeAmpStatusChangeInd
+
+  DESCRIPTION
+    Indication of change to AMP activity.
+
+  MEMBERS
+    common       - Common header for use with the CsrWifiFsm Module
+    interfaceTag - Interface on which the AMP activity changed.
+    ampStatus    - The new status of AMP activity.Range: {AMP_ACTIVE,
+                   AMP_INACTIVE}.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent     common;
+    CsrUint16           interfaceTag;
+    CsrWifiSmeAmpStatus ampStatus;
+} CsrWifiSmeAmpStatusChangeInd;
+
+/*******************************************************************************
+
+  NAME
+    CsrWifiSmeWpsConfigurationCfm
+
+  DESCRIPTION
+    Confirm.
+
+  MEMBERS
+    common - Common header for use with the CsrWifiFsm Module
+    status - Status of the request.
+
+*******************************************************************************/
+typedef struct
+{
+    CsrWifiFsmEvent common;
+    CsrResult       status;
+} CsrWifiSmeWpsConfigurationCfm;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_SME_PRIM_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_sme_sef.c b/drivers/staging/csr/csr_wifi_sme_sef.c
new file mode 100644
index 0000000..cf32254
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_sef.c
@@ -0,0 +1,85 @@
+/*****************************************************************************
+
+  (c) Cambridge Silicon Radio Limited 2010
+  Confidential information of CSR
+
+  Refer to LICENSE.txt included with this source for details
+  on the license terms.
+
+ *****************************************************************************/
+#include "csr_wifi_sme_sef.h"
+
+const CsrWifiSmeStateHandlerType CsrWifiSmeUpstreamStateHandlers[CSR_WIFI_SME_PRIM_UPSTREAM_COUNT] =
+{
+    /* 0x8000 */ CsrWifiSmeActivateCfmHandler,
+    /* 0x8001 */ CsrWifiSmeAdhocConfigGetCfmHandler,
+    /* 0x8002 */ CsrWifiSmeAdhocConfigSetCfmHandler,
+    /* 0x8003 */ CsrWifiSmeAssociationCompleteIndHandler,
+    /* 0x8004 */ CsrWifiSmeAssociationStartIndHandler,
+    /* 0x8005 */ CsrWifiSmeBlacklistCfmHandler,
+    /* 0x8006 */ CsrWifiSmeCalibrationDataGetCfmHandler,
+    /* 0x8007 */ CsrWifiSmeCalibrationDataSetCfmHandler,
+    /* 0x8008 */ CsrWifiSmeCcxConfigGetCfmHandler,
+    /* 0x8009 */ CsrWifiSmeCcxConfigSetCfmHandler,
+    /* 0x800A */ CsrWifiSmeCoexConfigGetCfmHandler,
+    /* 0x800B */ CsrWifiSmeCoexConfigSetCfmHandler,
+    /* 0x800C */ CsrWifiSmeCoexInfoGetCfmHandler,
+    /* 0x800D */ CsrWifiSmeConnectCfmHandler,
+    /* 0x800E */ CsrWifiSmeConnectionConfigGetCfmHandler,
+    /* 0x800F */ CsrWifiSmeConnectionInfoGetCfmHandler,
+    /* 0x8010 */ CsrWifiSmeConnectionQualityIndHandler,
+    /* 0x8011 */ CsrWifiSmeConnectionStatsGetCfmHandler,
+    /* 0x8012 */ CsrWifiSmeDeactivateCfmHandler,
+    /* 0x8013 */ CsrWifiSmeDisconnectCfmHandler,
+    /* 0x8014 */ CsrWifiSmeEventMaskSetCfmHandler,
+    /* 0x8015 */ CsrWifiSmeHostConfigGetCfmHandler,
+    /* 0x8016 */ CsrWifiSmeHostConfigSetCfmHandler,
+    /* 0x8017 */ CsrWifiSmeIbssStationIndHandler,
+    /* 0x8018 */ CsrWifiSmeKeyCfmHandler,
+    /* 0x8019 */ CsrWifiSmeLinkQualityGetCfmHandler,
+    /* 0x801A */ CsrWifiSmeMediaStatusIndHandler,
+    /* 0x801B */ CsrWifiSmeMibConfigGetCfmHandler,
+    /* 0x801C */ CsrWifiSmeMibConfigSetCfmHandler,
+    /* 0x801D */ CsrWifiSmeMibGetCfmHandler,
+    /* 0x801E */ CsrWifiSmeMibGetNextCfmHandler,
+    /* 0x801F */ CsrWifiSmeMibSetCfmHandler,
+    /* 0x8020 */ CsrWifiSmeMicFailureIndHandler,
+    /* 0x8021 */ CsrWifiSmeMulticastAddressCfmHandler,
+    /* 0x8022 */ CsrWifiSmePacketFilterSetCfmHandler,
+    /* 0x8023 */ CsrWifiSmePermanentMacAddressGetCfmHandler,
+    /* 0x8024 */ CsrWifiSmePmkidCandidateListIndHandler,
+    /* 0x8025 */ CsrWifiSmePmkidCfmHandler,
+    /* 0x8026 */ CsrWifiSmePowerConfigGetCfmHandler,
+    /* 0x8027 */ CsrWifiSmePowerConfigSetCfmHandler,
+    /* 0x8028 */ CsrWifiSmeRegulatoryDomainInfoGetCfmHandler,
+    /* 0x8029 */ CsrWifiSmeRoamCompleteIndHandler,
+    /* 0x802A */ CsrWifiSmeRoamStartIndHandler,
+    /* 0x802B */ CsrWifiSmeRoamingConfigGetCfmHandler,
+    /* 0x802C */ CsrWifiSmeRoamingConfigSetCfmHandler,
+    /* 0x802D */ CsrWifiSmeScanConfigGetCfmHandler,
+    /* 0x802E */ CsrWifiSmeScanConfigSetCfmHandler,
+    /* 0x802F */ CsrWifiSmeScanFullCfmHandler,
+    /* 0x8030 */ CsrWifiSmeScanResultIndHandler,
+    /* 0x8031 */ CsrWifiSmeScanResultsFlushCfmHandler,
+    /* 0x8032 */ CsrWifiSmeScanResultsGetCfmHandler,
+    /* 0x8033 */ CsrWifiSmeSmeStaConfigGetCfmHandler,
+    /* 0x8034 */ CsrWifiSmeSmeStaConfigSetCfmHandler,
+    /* 0x8035 */ CsrWifiSmeStationMacAddressGetCfmHandler,
+    /* 0x8036 */ CsrWifiSmeTspecIndHandler,
+    /* 0x8037 */ CsrWifiSmeTspecCfmHandler,
+    /* 0x8038 */ CsrWifiSmeVersionsGetCfmHandler,
+    /* 0x8039 */ CsrWifiSmeWifiFlightmodeCfmHandler,
+    /* 0x803A */ CsrWifiSmeWifiOffIndHandler,
+    /* 0x803B */ CsrWifiSmeWifiOffCfmHandler,
+    /* 0x803C */ CsrWifiSmeWifiOnCfmHandler,
+    /* 0x803D */ CsrWifiSmeCloakedSsidsSetCfmHandler,
+    /* 0x803E */ CsrWifiSmeCloakedSsidsGetCfmHandler,
+    /* 0x803F */ CsrWifiSmeWifiOnIndHandler,
+    /* 0x8040 */ CsrWifiSmeSmeCommonConfigGetCfmHandler,
+    /* 0x8041 */ CsrWifiSmeSmeCommonConfigSetCfmHandler,
+    /* 0x8042 */ CsrWifiSmeGetInterfaceCapabilityCfmHandler,
+    /* 0x8043 */ CsrWifiSmeErrorIndHandler,
+    /* 0x8044 */ CsrWifiSmeInfoIndHandler,
+    /* 0x8045 */ CsrWifiSmeCoreDumpIndHandler,
+    /* 0x8046 */ CsrWifiSmeAmpStatusChangeIndHandler,
+};
diff --git a/drivers/staging/csr/csr_wifi_sme_sef.h b/drivers/staging/csr/csr_wifi_sme_sef.h
new file mode 100644
index 0000000..c874181
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_sef.h
@@ -0,0 +1,101 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2010
+            Confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+#ifndef CSR_WIFI_ROUTER_SEF_CSR_WIFI_SME_H__
+#define CSR_WIFI_ROUTER_SEF_CSR_WIFI_SME_H__
+
+#include "csr_wifi_sme_prim.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*CsrWifiSmeStateHandlerType)(void* drvpriv, CsrWifiFsmEvent* msg);
+
+extern const CsrWifiSmeStateHandlerType CsrWifiSmeUpstreamStateHandlers[CSR_WIFI_SME_PRIM_UPSTREAM_COUNT];
+
+
+extern void CsrWifiSmeActivateCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeAdhocConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeAdhocConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeAssociationCompleteIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeAssociationStartIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeBlacklistCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeCalibrationDataGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeCalibrationDataSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeCcxConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeCcxConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeCoexConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeCoexConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeCoexInfoGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeConnectCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeConnectionConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeConnectionInfoGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeConnectionQualityIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeConnectionStatsGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeDeactivateCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeDisconnectCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeEventMaskSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeHostConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeHostConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeIbssStationIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeKeyCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeLinkQualityGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeMediaStatusIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeMibConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeMibConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeMibGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeMibGetNextCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeMibSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeMicFailureIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeMulticastAddressCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmePacketFilterSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmePermanentMacAddressGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmePmkidCandidateListIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmePmkidCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmePowerConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmePowerConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeRegulatoryDomainInfoGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeRoamCompleteIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeRoamStartIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeRoamingConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeRoamingConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeScanConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeScanConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeScanFullCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeScanResultIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeScanResultsFlushCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeScanResultsGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeSmeStaConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeSmeStaConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeStationMacAddressGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeTspecIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeTspecCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeVersionsGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeWifiFlightmodeCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeWifiOffIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeWifiOffCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeWifiOnCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeCloakedSsidsSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeCloakedSsidsGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeWifiOnIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeSmeCommonConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeSmeCommonConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeGetInterfaceCapabilityCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeErrorIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeInfoIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeCoreDumpIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+extern void CsrWifiSmeAmpStatusChangeIndHandler(void* drvpriv, CsrWifiFsmEvent* msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_ROUTER_SEF_CSR_WIFI_SME_H__ */
diff --git a/drivers/staging/csr/csr_wifi_sme_serialize.c b/drivers/staging/csr/csr_wifi_sme_serialize.c
new file mode 100644
index 0000000..5c1bc31
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_serialize.c
@@ -0,0 +1,5812 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#include "csr_pmem.h"
+#include "csr_msgconv.h"
+#include "csr_unicode.h"
+
+
+#include "csr_wifi_sme_prim.h"
+#include "csr_wifi_sme_serialize.h"
+
+void CsrWifiSmePfree(void *ptr)
+{
+    CsrPmemFree(ptr);
+}
+
+
+CsrSize CsrWifiSmeAdhocConfigSetReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 11) */
+    bufferSize += 2; /* CsrUint16 primitive->adHocConfig.atimWindowTu */
+    bufferSize += 2; /* CsrUint16 primitive->adHocConfig.beaconPeriodTu */
+    bufferSize += 2; /* CsrUint16 primitive->adHocConfig.joinOnlyAttempts */
+    bufferSize += 2; /* CsrUint16 primitive->adHocConfig.joinAttemptIntervalMs */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeAdhocConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeAdhocConfigSetReq *primitive = (CsrWifiSmeAdhocConfigSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->adHocConfig.atimWindowTu);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->adHocConfig.beaconPeriodTu);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->adHocConfig.joinOnlyAttempts);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->adHocConfig.joinAttemptIntervalMs);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeAdhocConfigSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeAdhocConfigSetReq *primitive = (CsrWifiSmeAdhocConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeAdhocConfigSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->adHocConfig.atimWindowTu, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->adHocConfig.beaconPeriodTu, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->adHocConfig.joinOnlyAttempts, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->adHocConfig.joinAttemptIntervalMs, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeBlacklistReqSizeof(void *msg)
+{
+    CsrWifiSmeBlacklistReq *primitive = (CsrWifiSmeBlacklistReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiSmeListAction primitive->action */
+    bufferSize += 1; /* CsrUint8 primitive->setAddressCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setAddressCount; i1++)
+        {
+            bufferSize += 6; /* CsrUint8 primitive->setAddresses[i1].a[6] */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeBlacklistReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeBlacklistReq *primitive = (CsrWifiSmeBlacklistReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->action);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->setAddressCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setAddressCount; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->setAddresses[i1].a, ((CsrUint16) (6)));
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeBlacklistReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeBlacklistReq *primitive = (CsrWifiSmeBlacklistReq *) CsrPmemAlloc(sizeof(CsrWifiSmeBlacklistReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->action, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->setAddressCount, buffer, &offset);
+    primitive->setAddresses = NULL;
+    if (primitive->setAddressCount)
+    {
+        primitive->setAddresses = (CsrWifiMacAddress *)CsrPmemAlloc(sizeof(CsrWifiMacAddress) * primitive->setAddressCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setAddressCount; i1++)
+        {
+            CsrMemCpyDes(primitive->setAddresses[i1].a, buffer, &offset, ((CsrUint16) (6)));
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeBlacklistReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeBlacklistReq *primitive = (CsrWifiSmeBlacklistReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->setAddresses);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeCalibrationDataSetReqSizeof(void *msg)
+{
+    CsrWifiSmeCalibrationDataSetReq *primitive = (CsrWifiSmeCalibrationDataSetReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 6) */
+    bufferSize += 2;                                /* CsrUint16 primitive->calibrationDataLength */
+    bufferSize += primitive->calibrationDataLength; /* CsrUint8 primitive->calibrationData */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeCalibrationDataSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeCalibrationDataSetReq *primitive = (CsrWifiSmeCalibrationDataSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->calibrationDataLength);
+    if (primitive->calibrationDataLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->calibrationData, ((CsrUint16) (primitive->calibrationDataLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeCalibrationDataSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeCalibrationDataSetReq *primitive = (CsrWifiSmeCalibrationDataSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCalibrationDataSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->calibrationDataLength, buffer, &offset);
+    if (primitive->calibrationDataLength)
+    {
+        primitive->calibrationData = (CsrUint8 *)CsrPmemAlloc(primitive->calibrationDataLength);
+        CsrMemCpyDes(primitive->calibrationData, buffer, &offset, ((CsrUint16) (primitive->calibrationDataLength)));
+    }
+    else
+    {
+        primitive->calibrationData = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeCalibrationDataSetReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeCalibrationDataSetReq *primitive = (CsrWifiSmeCalibrationDataSetReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->calibrationData);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeCcxConfigSetReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 9) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrUint8 primitive->ccxConfig.keepAliveTimeMs */
+    bufferSize += 1; /* CsrBool primitive->ccxConfig.apRoamingEnabled */
+    bufferSize += 1; /* CsrUint8 primitive->ccxConfig.measurementsMask */
+    bufferSize += 1; /* CsrBool primitive->ccxConfig.ccxRadioMgtEnabled */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeCcxConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeCcxConfigSetReq *primitive = (CsrWifiSmeCcxConfigSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ccxConfig.keepAliveTimeMs);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ccxConfig.apRoamingEnabled);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ccxConfig.measurementsMask);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ccxConfig.ccxRadioMgtEnabled);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeCcxConfigSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeCcxConfigSetReq *primitive = (CsrWifiSmeCcxConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCcxConfigSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->ccxConfig.keepAliveTimeMs, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->ccxConfig.apRoamingEnabled, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->ccxConfig.measurementsMask, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->ccxConfig.ccxRadioMgtEnabled, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeCoexConfigSetReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 29) */
+    bufferSize += 1; /* CsrBool primitive->coexConfig.coexEnableSchemeManagement */
+    bufferSize += 1; /* CsrBool primitive->coexConfig.coexPeriodicWakeHost */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexTrafficBurstyLatencyMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexTrafficContinuousLatencyMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexObexBlackoutDurationMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexObexBlackoutPeriodMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexA2dpBrBlackoutDurationMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexA2dpBrBlackoutPeriodMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexA2dpEdrBlackoutDurationMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexA2dpEdrBlackoutPeriodMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexPagingBlackoutDurationMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexPagingBlackoutPeriodMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexInquiryBlackoutDurationMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexInquiryBlackoutPeriodMs */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeCoexConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeCoexConfigSetReq *primitive = (CsrWifiSmeCoexConfigSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->coexConfig.coexEnableSchemeManagement);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->coexConfig.coexPeriodicWakeHost);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexTrafficBurstyLatencyMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexTrafficContinuousLatencyMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexObexBlackoutDurationMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexObexBlackoutPeriodMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexA2dpBrBlackoutDurationMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexA2dpBrBlackoutPeriodMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexA2dpEdrBlackoutDurationMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexA2dpEdrBlackoutPeriodMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexPagingBlackoutDurationMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexPagingBlackoutPeriodMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexInquiryBlackoutDurationMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexInquiryBlackoutPeriodMs);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeCoexConfigSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeCoexConfigSetReq *primitive = (CsrWifiSmeCoexConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCoexConfigSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->coexConfig.coexEnableSchemeManagement, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->coexConfig.coexPeriodicWakeHost, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexTrafficBurstyLatencyMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexTrafficContinuousLatencyMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexObexBlackoutDurationMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexObexBlackoutPeriodMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexA2dpBrBlackoutDurationMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexA2dpBrBlackoutPeriodMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexA2dpEdrBlackoutDurationMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexA2dpEdrBlackoutPeriodMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexPagingBlackoutDurationMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexPagingBlackoutPeriodMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexInquiryBlackoutDurationMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexInquiryBlackoutPeriodMs, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeConnectReqSizeof(void *msg)
+{
+    CsrWifiSmeConnectReq *primitive = (CsrWifiSmeConnectReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 57) */
+    bufferSize += 2;                                                                     /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 32;                                                                    /* CsrUint8 primitive->connectionConfig.ssid.ssid[32] */
+    bufferSize += 1;                                                                     /* CsrUint8 primitive->connectionConfig.ssid.length */
+    bufferSize += 6;                                                                     /* CsrUint8 primitive->connectionConfig.bssid.a[6] */
+    bufferSize += 1;                                                                     /* CsrWifiSmeBssType primitive->connectionConfig.bssType */
+    bufferSize += 1;                                                                     /* CsrWifiSmeRadioIF primitive->connectionConfig.ifIndex */
+    bufferSize += 1;                                                                     /* CsrWifiSme80211PrivacyMode primitive->connectionConfig.privacyMode */
+    bufferSize += 2;                                                                     /* CsrWifiSmeAuthModeMask primitive->connectionConfig.authModeMask */
+    bufferSize += 2;                                                                     /* CsrWifiSmeEncryptionMask primitive->connectionConfig.encryptionModeMask */
+    bufferSize += 2;                                                                     /* CsrUint16 primitive->connectionConfig.mlmeAssociateReqInformationElementsLength */
+    bufferSize += primitive->connectionConfig.mlmeAssociateReqInformationElementsLength; /* CsrUint8 primitive->connectionConfig.mlmeAssociateReqInformationElements */
+    bufferSize += 1;                                                                     /* CsrWifiSmeWmmQosInfoMask primitive->connectionConfig.wmmQosInfo */
+    bufferSize += 1;                                                                     /* CsrBool primitive->connectionConfig.adhocJoinOnly */
+    bufferSize += 1;                                                                     /* CsrUint8 primitive->connectionConfig.adhocChannel */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeConnectReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeConnectReq *primitive = (CsrWifiSmeConnectReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionConfig.ssid.ssid, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.ssid.length);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionConfig.bssid.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.bssType);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.ifIndex);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.privacyMode);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionConfig.authModeMask);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionConfig.encryptionModeMask);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionConfig.mlmeAssociateReqInformationElementsLength);
+    if (primitive->connectionConfig.mlmeAssociateReqInformationElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionConfig.mlmeAssociateReqInformationElements, ((CsrUint16) (primitive->connectionConfig.mlmeAssociateReqInformationElementsLength)));
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.wmmQosInfo);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.adhocJoinOnly);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.adhocChannel);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeConnectReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeConnectReq *primitive = (CsrWifiSmeConnectReq *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionConfig.ssid.ssid, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.ssid.length, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionConfig.bssid.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.bssType, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.ifIndex, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.privacyMode, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionConfig.authModeMask, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionConfig.encryptionModeMask, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionConfig.mlmeAssociateReqInformationElementsLength, buffer, &offset);
+    if (primitive->connectionConfig.mlmeAssociateReqInformationElementsLength)
+    {
+        primitive->connectionConfig.mlmeAssociateReqInformationElements = (CsrUint8 *)CsrPmemAlloc(primitive->connectionConfig.mlmeAssociateReqInformationElementsLength);
+        CsrMemCpyDes(primitive->connectionConfig.mlmeAssociateReqInformationElements, buffer, &offset, ((CsrUint16) (primitive->connectionConfig.mlmeAssociateReqInformationElementsLength)));
+    }
+    else
+    {
+        primitive->connectionConfig.mlmeAssociateReqInformationElements = NULL;
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.wmmQosInfo, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.adhocJoinOnly, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.adhocChannel, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiSmeConnectReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeConnectReq *primitive = (CsrWifiSmeConnectReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->connectionConfig.mlmeAssociateReqInformationElements);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeHostConfigSetReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiSmeHostPowerMode primitive->hostConfig.powerMode */
+    bufferSize += 2; /* CsrUint16 primitive->hostConfig.applicationDataPeriodMs */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeHostConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeHostConfigSetReq *primitive = (CsrWifiSmeHostConfigSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->hostConfig.powerMode);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->hostConfig.applicationDataPeriodMs);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeHostConfigSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeHostConfigSetReq *primitive = (CsrWifiSmeHostConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeHostConfigSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->hostConfig.powerMode, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->hostConfig.applicationDataPeriodMs, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeKeyReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 65) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiSmeListAction primitive->action */
+    bufferSize += 1; /* CsrWifiSmeKeyType primitive->key.keyType */
+    bufferSize += 1; /* CsrUint8 primitive->key.keyIndex */
+    bufferSize += 1; /* CsrBool primitive->key.wepTxKey */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 8; i2++)
+        {
+            bufferSize += 2; /* CsrUint16 primitive->key.keyRsc[8] */
+        }
+    }
+    bufferSize += 1;         /* CsrBool primitive->key.authenticator */
+    bufferSize += 6;         /* CsrUint8 primitive->key.address.a[6] */
+    bufferSize += 1;         /* CsrUint8 primitive->key.keyLength */
+    bufferSize += 32;        /* CsrUint8 primitive->key.key[32] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeKeyReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeKeyReq *primitive = (CsrWifiSmeKeyReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->action);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->key.keyType);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->key.keyIndex);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->key.wepTxKey);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 8; i2++)
+        {
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->key.keyRsc[i2]);
+        }
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->key.authenticator);
+    CsrMemCpySer(ptr, len, (const void *) primitive->key.address.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->key.keyLength);
+    CsrMemCpySer(ptr, len, (const void *) primitive->key.key, ((CsrUint16) (32)));
+    return(ptr);
+}
+
+
+void* CsrWifiSmeKeyReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeKeyReq *primitive = (CsrWifiSmeKeyReq *) CsrPmemAlloc(sizeof(CsrWifiSmeKeyReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->action, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->key.keyType, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->key.keyIndex, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->key.wepTxKey, buffer, &offset);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 8; i2++)
+        {
+            CsrUint16Des((CsrUint16 *) &primitive->key.keyRsc[i2], buffer, &offset);
+        }
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->key.authenticator, buffer, &offset);
+    CsrMemCpyDes(primitive->key.address.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->key.keyLength, buffer, &offset);
+    CsrMemCpyDes(primitive->key.key, buffer, &offset, ((CsrUint16) (32)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeMibConfigSetReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 11) */
+    bufferSize += 1; /* CsrBool primitive->mibConfig.unifiFixMaxTxDataRate */
+    bufferSize += 1; /* CsrUint8 primitive->mibConfig.unifiFixTxDataRate */
+    bufferSize += 2; /* CsrUint16 primitive->mibConfig.dot11RtsThreshold */
+    bufferSize += 2; /* CsrUint16 primitive->mibConfig.dot11FragmentationThreshold */
+    bufferSize += 2; /* CsrUint16 primitive->mibConfig.dot11CurrentTxPowerLevel */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeMibConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeMibConfigSetReq *primitive = (CsrWifiSmeMibConfigSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->mibConfig.unifiFixMaxTxDataRate);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->mibConfig.unifiFixTxDataRate);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibConfig.dot11RtsThreshold);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibConfig.dot11FragmentationThreshold);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibConfig.dot11CurrentTxPowerLevel);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeMibConfigSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeMibConfigSetReq *primitive = (CsrWifiSmeMibConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeMibConfigSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->mibConfig.unifiFixMaxTxDataRate, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->mibConfig.unifiFixTxDataRate, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mibConfig.dot11RtsThreshold, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mibConfig.dot11FragmentationThreshold, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mibConfig.dot11CurrentTxPowerLevel, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeMibGetNextReqSizeof(void *msg)
+{
+    CsrWifiSmeMibGetNextReq *primitive = (CsrWifiSmeMibGetNextReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 6) */
+    bufferSize += 2;                             /* CsrUint16 primitive->mibAttributeLength */
+    bufferSize += primitive->mibAttributeLength; /* CsrUint8 primitive->mibAttribute */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeMibGetNextReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeMibGetNextReq *primitive = (CsrWifiSmeMibGetNextReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibAttributeLength);
+    if (primitive->mibAttributeLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->mibAttribute, ((CsrUint16) (primitive->mibAttributeLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeMibGetNextReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeMibGetNextReq *primitive = (CsrWifiSmeMibGetNextReq *) CsrPmemAlloc(sizeof(CsrWifiSmeMibGetNextReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mibAttributeLength, buffer, &offset);
+    if (primitive->mibAttributeLength)
+    {
+        primitive->mibAttribute = (CsrUint8 *)CsrPmemAlloc(primitive->mibAttributeLength);
+        CsrMemCpyDes(primitive->mibAttribute, buffer, &offset, ((CsrUint16) (primitive->mibAttributeLength)));
+    }
+    else
+    {
+        primitive->mibAttribute = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeMibGetNextReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeMibGetNextReq *primitive = (CsrWifiSmeMibGetNextReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->mibAttribute);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeMibGetReqSizeof(void *msg)
+{
+    CsrWifiSmeMibGetReq *primitive = (CsrWifiSmeMibGetReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 6) */
+    bufferSize += 2;                             /* CsrUint16 primitive->mibAttributeLength */
+    bufferSize += primitive->mibAttributeLength; /* CsrUint8 primitive->mibAttribute */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeMibGetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeMibGetReq *primitive = (CsrWifiSmeMibGetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibAttributeLength);
+    if (primitive->mibAttributeLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->mibAttribute, ((CsrUint16) (primitive->mibAttributeLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeMibGetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeMibGetReq *primitive = (CsrWifiSmeMibGetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeMibGetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mibAttributeLength, buffer, &offset);
+    if (primitive->mibAttributeLength)
+    {
+        primitive->mibAttribute = (CsrUint8 *)CsrPmemAlloc(primitive->mibAttributeLength);
+        CsrMemCpyDes(primitive->mibAttribute, buffer, &offset, ((CsrUint16) (primitive->mibAttributeLength)));
+    }
+    else
+    {
+        primitive->mibAttribute = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeMibGetReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeMibGetReq *primitive = (CsrWifiSmeMibGetReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->mibAttribute);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeMibSetReqSizeof(void *msg)
+{
+    CsrWifiSmeMibSetReq *primitive = (CsrWifiSmeMibSetReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 6) */
+    bufferSize += 2;                             /* CsrUint16 primitive->mibAttributeLength */
+    bufferSize += primitive->mibAttributeLength; /* CsrUint8 primitive->mibAttribute */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeMibSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeMibSetReq *primitive = (CsrWifiSmeMibSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibAttributeLength);
+    if (primitive->mibAttributeLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->mibAttribute, ((CsrUint16) (primitive->mibAttributeLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeMibSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeMibSetReq *primitive = (CsrWifiSmeMibSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeMibSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mibAttributeLength, buffer, &offset);
+    if (primitive->mibAttributeLength)
+    {
+        primitive->mibAttribute = (CsrUint8 *)CsrPmemAlloc(primitive->mibAttributeLength);
+        CsrMemCpyDes(primitive->mibAttribute, buffer, &offset, ((CsrUint16) (primitive->mibAttributeLength)));
+    }
+    else
+    {
+        primitive->mibAttribute = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeMibSetReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeMibSetReq *primitive = (CsrWifiSmeMibSetReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->mibAttribute);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeMulticastAddressReqSizeof(void *msg)
+{
+    CsrWifiSmeMulticastAddressReq *primitive = (CsrWifiSmeMulticastAddressReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiSmeListAction primitive->action */
+    bufferSize += 1; /* CsrUint8 primitive->setAddressesCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setAddressesCount; i1++)
+        {
+            bufferSize += 6; /* CsrUint8 primitive->setAddresses[i1].a[6] */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeMulticastAddressReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeMulticastAddressReq *primitive = (CsrWifiSmeMulticastAddressReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->action);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->setAddressesCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setAddressesCount; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->setAddresses[i1].a, ((CsrUint16) (6)));
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeMulticastAddressReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeMulticastAddressReq *primitive = (CsrWifiSmeMulticastAddressReq *) CsrPmemAlloc(sizeof(CsrWifiSmeMulticastAddressReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->action, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->setAddressesCount, buffer, &offset);
+    primitive->setAddresses = NULL;
+    if (primitive->setAddressesCount)
+    {
+        primitive->setAddresses = (CsrWifiMacAddress *)CsrPmemAlloc(sizeof(CsrWifiMacAddress) * primitive->setAddressesCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setAddressesCount; i1++)
+        {
+            CsrMemCpyDes(primitive->setAddresses[i1].a, buffer, &offset, ((CsrUint16) (6)));
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeMulticastAddressReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeMulticastAddressReq *primitive = (CsrWifiSmeMulticastAddressReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->setAddresses);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmePacketFilterSetReqSizeof(void *msg)
+{
+    CsrWifiSmePacketFilterSetReq *primitive = (CsrWifiSmePacketFilterSetReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2;                       /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;                       /* CsrUint16 primitive->filterLength */
+    bufferSize += primitive->filterLength; /* CsrUint8 primitive->filter */
+    bufferSize += 1;                       /* CsrWifiSmePacketFilterMode primitive->mode */
+    bufferSize += 4;                       /* CsrUint8 primitive->arpFilterAddress.a[4] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmePacketFilterSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmePacketFilterSetReq *primitive = (CsrWifiSmePacketFilterSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->filterLength);
+    if (primitive->filterLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->filter, ((CsrUint16) (primitive->filterLength)));
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->mode);
+    CsrMemCpySer(ptr, len, (const void *) primitive->arpFilterAddress.a, ((CsrUint16) (4)));
+    return(ptr);
+}
+
+
+void* CsrWifiSmePacketFilterSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmePacketFilterSetReq *primitive = (CsrWifiSmePacketFilterSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmePacketFilterSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->filterLength, buffer, &offset);
+    if (primitive->filterLength)
+    {
+        primitive->filter = (CsrUint8 *)CsrPmemAlloc(primitive->filterLength);
+        CsrMemCpyDes(primitive->filter, buffer, &offset, ((CsrUint16) (primitive->filterLength)));
+    }
+    else
+    {
+        primitive->filter = NULL;
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->mode, buffer, &offset);
+    CsrMemCpyDes(primitive->arpFilterAddress.a, buffer, &offset, ((CsrUint16) (4)));
+
+    return primitive;
+}
+
+
+void CsrWifiSmePacketFilterSetReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmePacketFilterSetReq *primitive = (CsrWifiSmePacketFilterSetReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->filter);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmePmkidReqSizeof(void *msg)
+{
+    CsrWifiSmePmkidReq *primitive = (CsrWifiSmePmkidReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 29) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiSmeListAction primitive->action */
+    bufferSize += 1; /* CsrUint8 primitive->setPmkidsCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setPmkidsCount; i1++)
+        {
+            bufferSize += 6;  /* CsrUint8 primitive->setPmkids[i1].bssid.a[6] */
+            bufferSize += 16; /* CsrUint8 primitive->setPmkids[i1].pmkid[16] */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmePmkidReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmePmkidReq *primitive = (CsrWifiSmePmkidReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->action);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->setPmkidsCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setPmkidsCount; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->setPmkids[i1].bssid.a, ((CsrUint16) (6)));
+            CsrMemCpySer(ptr, len, (const void *) primitive->setPmkids[i1].pmkid, ((CsrUint16) (16)));
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmePmkidReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmePmkidReq *primitive = (CsrWifiSmePmkidReq *) CsrPmemAlloc(sizeof(CsrWifiSmePmkidReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->action, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->setPmkidsCount, buffer, &offset);
+    primitive->setPmkids = NULL;
+    if (primitive->setPmkidsCount)
+    {
+        primitive->setPmkids = (CsrWifiSmePmkid *)CsrPmemAlloc(sizeof(CsrWifiSmePmkid) * primitive->setPmkidsCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->setPmkidsCount; i1++)
+        {
+            CsrMemCpyDes(primitive->setPmkids[i1].bssid.a, buffer, &offset, ((CsrUint16) (6)));
+            CsrMemCpyDes(primitive->setPmkids[i1].pmkid, buffer, &offset, ((CsrUint16) (16)));
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmePmkidReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmePmkidReq *primitive = (CsrWifiSmePmkidReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->setPmkids);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmePowerConfigSetReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 11) */
+    bufferSize += 1; /* CsrWifiSmePowerSaveLevel primitive->powerConfig.powerSaveLevel */
+    bufferSize += 2; /* CsrUint16 primitive->powerConfig.listenIntervalTu */
+    bufferSize += 1; /* CsrBool primitive->powerConfig.rxDtims */
+    bufferSize += 1; /* CsrWifiSmeD3AutoScanMode primitive->powerConfig.d3AutoScanMode */
+    bufferSize += 1; /* CsrUint8 primitive->powerConfig.clientTrafficWindow */
+    bufferSize += 1; /* CsrBool primitive->powerConfig.opportunisticPowerSave */
+    bufferSize += 1; /* CsrBool primitive->powerConfig.noticeOfAbsence */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmePowerConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmePowerConfigSetReq *primitive = (CsrWifiSmePowerConfigSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.powerSaveLevel);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->powerConfig.listenIntervalTu);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.rxDtims);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.d3AutoScanMode);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.clientTrafficWindow);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.opportunisticPowerSave);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.noticeOfAbsence);
+    return(ptr);
+}
+
+
+void* CsrWifiSmePowerConfigSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmePowerConfigSetReq *primitive = (CsrWifiSmePowerConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmePowerConfigSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.powerSaveLevel, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->powerConfig.listenIntervalTu, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.rxDtims, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.d3AutoScanMode, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.clientTrafficWindow, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.opportunisticPowerSave, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.noticeOfAbsence, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeRoamingConfigSetReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 70) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            bufferSize += 2; /* CsrInt16 primitive->roamingConfig.roamingBands[i2].rssiHighThreshold */
+            bufferSize += 2; /* CsrInt16 primitive->roamingConfig.roamingBands[i2].rssiLowThreshold */
+            bufferSize += 2; /* CsrInt16 primitive->roamingConfig.roamingBands[i2].snrHighThreshold */
+            bufferSize += 2; /* CsrInt16 primitive->roamingConfig.roamingBands[i2].snrLowThreshold */
+        }
+    }
+    bufferSize += 1;         /* CsrBool primitive->roamingConfig.disableSmoothRoaming */
+    bufferSize += 1;         /* CsrBool primitive->roamingConfig.disableRoamScans */
+    bufferSize += 1;         /* CsrUint8 primitive->roamingConfig.reconnectLimit */
+    bufferSize += 2;         /* CsrUint16 primitive->roamingConfig.reconnectLimitIntervalMs */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].intervalSeconds */
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].validitySeconds */
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].minActiveChannelTimeTu */
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].maxActiveChannelTimeTu */
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].minPassiveChannelTimeTu */
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].maxPassiveChannelTimeTu */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeRoamingConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeRoamingConfigSetReq *primitive = (CsrWifiSmeRoamingConfigSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamingBands[i2].rssiHighThreshold);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamingBands[i2].rssiLowThreshold);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamingBands[i2].snrHighThreshold);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamingBands[i2].snrLowThreshold);
+        }
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->roamingConfig.disableSmoothRoaming);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->roamingConfig.disableRoamScans);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->roamingConfig.reconnectLimit);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.reconnectLimitIntervalMs);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].intervalSeconds);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].validitySeconds);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].minActiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].maxActiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].minPassiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].maxPassiveChannelTimeTu);
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeRoamingConfigSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeRoamingConfigSetReq *primitive = (CsrWifiSmeRoamingConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeRoamingConfigSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamingBands[i2].rssiHighThreshold, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamingBands[i2].rssiLowThreshold, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamingBands[i2].snrHighThreshold, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamingBands[i2].snrLowThreshold, buffer, &offset);
+        }
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->roamingConfig.disableSmoothRoaming, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->roamingConfig.disableRoamScans, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->roamingConfig.reconnectLimit, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.reconnectLimitIntervalMs, buffer, &offset);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].intervalSeconds, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].validitySeconds, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].minActiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].maxActiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].minPassiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].maxPassiveChannelTimeTu, buffer, &offset);
+        }
+    }
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeScanConfigSetReqSizeof(void *msg)
+{
+    CsrWifiSmeScanConfigSetReq *primitive = (CsrWifiSmeScanConfigSetReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 63) */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].intervalSeconds */
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].validitySeconds */
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].minActiveChannelTimeTu */
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].maxActiveChannelTimeTu */
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].minPassiveChannelTimeTu */
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].maxPassiveChannelTimeTu */
+        }
+    }
+    bufferSize += 1;                                             /* CsrBool primitive->scanConfig.disableAutonomousScans */
+    bufferSize += 2;                                             /* CsrUint16 primitive->scanConfig.maxResults */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.highRssiThreshold */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.lowRssiThreshold */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.deltaRssiThreshold */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.highSnrThreshold */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.lowSnrThreshold */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.deltaSnrThreshold */
+    bufferSize += 2;                                             /* CsrUint16 primitive->scanConfig.passiveChannelListCount */
+    bufferSize += primitive->scanConfig.passiveChannelListCount; /* CsrUint8 primitive->scanConfig.passiveChannelList */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeScanConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeScanConfigSetReq *primitive = (CsrWifiSmeScanConfigSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].intervalSeconds);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].validitySeconds);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].minActiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].maxActiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].minPassiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].maxPassiveChannelTimeTu);
+        }
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.disableAutonomousScans);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.maxResults);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.highRssiThreshold);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.lowRssiThreshold);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.deltaRssiThreshold);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.highSnrThreshold);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.lowSnrThreshold);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.deltaSnrThreshold);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.passiveChannelListCount);
+    if (primitive->scanConfig.passiveChannelListCount)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->scanConfig.passiveChannelList, ((CsrUint16) (primitive->scanConfig.passiveChannelListCount)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeScanConfigSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeScanConfigSetReq *primitive = (CsrWifiSmeScanConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeScanConfigSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].intervalSeconds, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].validitySeconds, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].minActiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].maxActiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].minPassiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].maxPassiveChannelTimeTu, buffer, &offset);
+        }
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.disableAutonomousScans, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->scanConfig.maxResults, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.highRssiThreshold, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.lowRssiThreshold, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.deltaRssiThreshold, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.highSnrThreshold, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.lowSnrThreshold, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.deltaSnrThreshold, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->scanConfig.passiveChannelListCount, buffer, &offset);
+    if (primitive->scanConfig.passiveChannelListCount)
+    {
+        primitive->scanConfig.passiveChannelList = (CsrUint8 *)CsrPmemAlloc(primitive->scanConfig.passiveChannelListCount);
+        CsrMemCpyDes(primitive->scanConfig.passiveChannelList, buffer, &offset, ((CsrUint16) (primitive->scanConfig.passiveChannelListCount)));
+    }
+    else
+    {
+        primitive->scanConfig.passiveChannelList = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeScanConfigSetReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeScanConfigSetReq *primitive = (CsrWifiSmeScanConfigSetReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->scanConfig.passiveChannelList);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeScanFullReqSizeof(void *msg)
+{
+    CsrWifiSmeScanFullReq *primitive = (CsrWifiSmeScanFullReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 52) */
+    bufferSize += 1; /* CsrUint8 primitive->ssidCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->ssidCount; i1++)
+        {
+            bufferSize += 32;                  /* CsrUint8 primitive->ssid[i1].ssid[32] */
+            bufferSize += 1;                   /* CsrUint8 primitive->ssid[i1].length */
+        }
+    }
+    bufferSize += 6;                           /* CsrUint8 primitive->bssid.a[6] */
+    bufferSize += 1;                           /* CsrBool primitive->forceScan */
+    bufferSize += 1;                           /* CsrWifiSmeBssType primitive->bssType */
+    bufferSize += 1;                           /* CsrWifiSmeScanType primitive->scanType */
+    bufferSize += 2;                           /* CsrUint16 primitive->channelListCount */
+    bufferSize += primitive->channelListCount; /* CsrUint8 primitive->channelList */
+    bufferSize += 2;                           /* CsrUint16 primitive->probeIeLength */
+    bufferSize += primitive->probeIeLength;    /* CsrUint8 primitive->probeIe */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeScanFullReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeScanFullReq *primitive = (CsrWifiSmeScanFullReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ssidCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->ssidCount; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->ssid[i1].ssid, ((CsrUint16) (32)));
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->ssid[i1].length);
+        }
+    }
+    CsrMemCpySer(ptr, len, (const void *) primitive->bssid.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->forceScan);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->bssType);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanType);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->channelListCount);
+    if (primitive->channelListCount)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->channelList, ((CsrUint16) (primitive->channelListCount)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->probeIeLength);
+    if (primitive->probeIeLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->probeIe, ((CsrUint16) (primitive->probeIeLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeScanFullReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeScanFullReq *primitive = (CsrWifiSmeScanFullReq *) CsrPmemAlloc(sizeof(CsrWifiSmeScanFullReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->ssidCount, buffer, &offset);
+    primitive->ssid = NULL;
+    if (primitive->ssidCount)
+    {
+        primitive->ssid = (CsrWifiSsid *)CsrPmemAlloc(sizeof(CsrWifiSsid) * primitive->ssidCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->ssidCount; i1++)
+        {
+            CsrMemCpyDes(primitive->ssid[i1].ssid, buffer, &offset, ((CsrUint16) (32)));
+            CsrUint8Des((CsrUint8 *) &primitive->ssid[i1].length, buffer, &offset);
+        }
+    }
+    CsrMemCpyDes(primitive->bssid.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->forceScan, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->bssType, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanType, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->channelListCount, buffer, &offset);
+    if (primitive->channelListCount)
+    {
+        primitive->channelList = (CsrUint8 *)CsrPmemAlloc(primitive->channelListCount);
+        CsrMemCpyDes(primitive->channelList, buffer, &offset, ((CsrUint16) (primitive->channelListCount)));
+    }
+    else
+    {
+        primitive->channelList = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->probeIeLength, buffer, &offset);
+    if (primitive->probeIeLength)
+    {
+        primitive->probeIe = (CsrUint8 *)CsrPmemAlloc(primitive->probeIeLength);
+        CsrMemCpyDes(primitive->probeIe, buffer, &offset, ((CsrUint16) (primitive->probeIeLength)));
+    }
+    else
+    {
+        primitive->probeIe = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeScanFullReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeScanFullReq *primitive = (CsrWifiSmeScanFullReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->ssid);
+    CsrPmemFree(primitive->channelList);
+    CsrPmemFree(primitive->probeIe);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeSmeStaConfigSetReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 11) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrUint8 primitive->smeConfig.connectionQualityRssiChangeTrigger */
+    bufferSize += 1; /* CsrUint8 primitive->smeConfig.connectionQualitySnrChangeTrigger */
+    bufferSize += 1; /* CsrWifiSmeWmmModeMask primitive->smeConfig.wmmModeMask */
+    bufferSize += 1; /* CsrWifiSmeRadioIF primitive->smeConfig.ifIndex */
+    bufferSize += 1; /* CsrBool primitive->smeConfig.allowUnicastUseGroupCipher */
+    bufferSize += 1; /* CsrBool primitive->smeConfig.enableOpportunisticKeyCaching */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeSmeStaConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeSmeStaConfigSetReq *primitive = (CsrWifiSmeSmeStaConfigSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.connectionQualityRssiChangeTrigger);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.connectionQualitySnrChangeTrigger);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.wmmModeMask);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.ifIndex);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.allowUnicastUseGroupCipher);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.enableOpportunisticKeyCaching);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeSmeStaConfigSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeSmeStaConfigSetReq *primitive = (CsrWifiSmeSmeStaConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeStaConfigSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.connectionQualityRssiChangeTrigger, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.connectionQualitySnrChangeTrigger, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.wmmModeMask, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.ifIndex, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.allowUnicastUseGroupCipher, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.enableOpportunisticKeyCaching, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeTspecReqSizeof(void *msg)
+{
+    CsrWifiSmeTspecReq *primitive = (CsrWifiSmeTspecReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 18) */
+    bufferSize += 2;                      /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1;                      /* CsrWifiSmeListAction primitive->action */
+    bufferSize += 4;                      /* CsrUint32 primitive->transactionId */
+    bufferSize += 1;                      /* CsrBool primitive->strict */
+    bufferSize += 1;                      /* CsrWifiSmeTspecCtrlMask primitive->ctrlMask */
+    bufferSize += 2;                      /* CsrUint16 primitive->tspecLength */
+    bufferSize += primitive->tspecLength; /* CsrUint8 primitive->tspec */
+    bufferSize += 2;                      /* CsrUint16 primitive->tclasLength */
+    bufferSize += primitive->tclasLength; /* CsrUint8 primitive->tclas */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeTspecReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeTspecReq *primitive = (CsrWifiSmeTspecReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->action);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->transactionId);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->strict);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ctrlMask);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->tspecLength);
+    if (primitive->tspecLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->tspec, ((CsrUint16) (primitive->tspecLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->tclasLength);
+    if (primitive->tclasLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->tclas, ((CsrUint16) (primitive->tclasLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeTspecReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeTspecReq *primitive = (CsrWifiSmeTspecReq *) CsrPmemAlloc(sizeof(CsrWifiSmeTspecReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->action, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->transactionId, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->strict, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->ctrlMask, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->tspecLength, buffer, &offset);
+    if (primitive->tspecLength)
+    {
+        primitive->tspec = (CsrUint8 *)CsrPmemAlloc(primitive->tspecLength);
+        CsrMemCpyDes(primitive->tspec, buffer, &offset, ((CsrUint16) (primitive->tspecLength)));
+    }
+    else
+    {
+        primitive->tspec = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->tclasLength, buffer, &offset);
+    if (primitive->tclasLength)
+    {
+        primitive->tclas = (CsrUint8 *)CsrPmemAlloc(primitive->tclasLength);
+        CsrMemCpyDes(primitive->tclas, buffer, &offset, ((CsrUint16) (primitive->tclasLength)));
+    }
+    else
+    {
+        primitive->tclas = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeTspecReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeTspecReq *primitive = (CsrWifiSmeTspecReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->tspec);
+    CsrPmemFree(primitive->tclas);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeWifiFlightmodeReqSizeof(void *msg)
+{
+    CsrWifiSmeWifiFlightmodeReq *primitive = (CsrWifiSmeWifiFlightmodeReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 14) */
+    bufferSize += 6; /* CsrUint8 primitive->address.a[6] */
+    bufferSize += 2; /* CsrUint16 primitive->mibFilesCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->mibFilesCount; i1++)
+        {
+            bufferSize += 2;                              /* CsrUint16 primitive->mibFiles[i1].length */
+            bufferSize += primitive->mibFiles[i1].length; /* CsrUint8 primitive->mibFiles[i1].data */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeWifiFlightmodeReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeWifiFlightmodeReq *primitive = (CsrWifiSmeWifiFlightmodeReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrMemCpySer(ptr, len, (const void *) primitive->address.a, ((CsrUint16) (6)));
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibFilesCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->mibFilesCount; i1++)
+        {
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibFiles[i1].length);
+            if (primitive->mibFiles[i1].length)
+            {
+                CsrMemCpySer(ptr, len, (const void *) primitive->mibFiles[i1].data, ((CsrUint16) (primitive->mibFiles[i1].length)));
+            }
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeWifiFlightmodeReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeWifiFlightmodeReq *primitive = (CsrWifiSmeWifiFlightmodeReq *) CsrPmemAlloc(sizeof(CsrWifiSmeWifiFlightmodeReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrMemCpyDes(primitive->address.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint16Des((CsrUint16 *) &primitive->mibFilesCount, buffer, &offset);
+    primitive->mibFiles = NULL;
+    if (primitive->mibFilesCount)
+    {
+        primitive->mibFiles = (CsrWifiSmeDataBlock *)CsrPmemAlloc(sizeof(CsrWifiSmeDataBlock) * primitive->mibFilesCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->mibFilesCount; i1++)
+        {
+            CsrUint16Des((CsrUint16 *) &primitive->mibFiles[i1].length, buffer, &offset);
+            if (primitive->mibFiles[i1].length)
+            {
+                primitive->mibFiles[i1].data = (CsrUint8 *)CsrPmemAlloc(primitive->mibFiles[i1].length);
+                CsrMemCpyDes(primitive->mibFiles[i1].data, buffer, &offset, ((CsrUint16) (primitive->mibFiles[i1].length)));
+            }
+            else
+            {
+                primitive->mibFiles[i1].data = NULL;
+            }
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeWifiFlightmodeReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeWifiFlightmodeReq *primitive = (CsrWifiSmeWifiFlightmodeReq *) voidPrimitivePointer;
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->mibFilesCount; i1++)
+        {
+            CsrPmemFree(primitive->mibFiles[i1].data);
+        }
+    }
+    CsrPmemFree(primitive->mibFiles);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeWifiOnReqSizeof(void *msg)
+{
+    CsrWifiSmeWifiOnReq *primitive = (CsrWifiSmeWifiOnReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 14) */
+    bufferSize += 6; /* CsrUint8 primitive->address.a[6] */
+    bufferSize += 2; /* CsrUint16 primitive->mibFilesCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->mibFilesCount; i1++)
+        {
+            bufferSize += 2;                              /* CsrUint16 primitive->mibFiles[i1].length */
+            bufferSize += primitive->mibFiles[i1].length; /* CsrUint8 primitive->mibFiles[i1].data */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeWifiOnReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeWifiOnReq *primitive = (CsrWifiSmeWifiOnReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrMemCpySer(ptr, len, (const void *) primitive->address.a, ((CsrUint16) (6)));
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibFilesCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->mibFilesCount; i1++)
+        {
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibFiles[i1].length);
+            if (primitive->mibFiles[i1].length)
+            {
+                CsrMemCpySer(ptr, len, (const void *) primitive->mibFiles[i1].data, ((CsrUint16) (primitive->mibFiles[i1].length)));
+            }
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeWifiOnReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeWifiOnReq *primitive = (CsrWifiSmeWifiOnReq *) CsrPmemAlloc(sizeof(CsrWifiSmeWifiOnReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrMemCpyDes(primitive->address.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint16Des((CsrUint16 *) &primitive->mibFilesCount, buffer, &offset);
+    primitive->mibFiles = NULL;
+    if (primitive->mibFilesCount)
+    {
+        primitive->mibFiles = (CsrWifiSmeDataBlock *)CsrPmemAlloc(sizeof(CsrWifiSmeDataBlock) * primitive->mibFilesCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->mibFilesCount; i1++)
+        {
+            CsrUint16Des((CsrUint16 *) &primitive->mibFiles[i1].length, buffer, &offset);
+            if (primitive->mibFiles[i1].length)
+            {
+                primitive->mibFiles[i1].data = (CsrUint8 *)CsrPmemAlloc(primitive->mibFiles[i1].length);
+                CsrMemCpyDes(primitive->mibFiles[i1].data, buffer, &offset, ((CsrUint16) (primitive->mibFiles[i1].length)));
+            }
+            else
+            {
+                primitive->mibFiles[i1].data = NULL;
+            }
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeWifiOnReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeWifiOnReq *primitive = (CsrWifiSmeWifiOnReq *) voidPrimitivePointer;
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->mibFilesCount; i1++)
+        {
+            CsrPmemFree(primitive->mibFiles[i1].data);
+        }
+    }
+    CsrPmemFree(primitive->mibFiles);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeCloakedSsidsSetReqSizeof(void *msg)
+{
+    CsrWifiSmeCloakedSsidsSetReq *primitive = (CsrWifiSmeCloakedSsidsSetReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 37) */
+    bufferSize += 1; /* CsrUint8 primitive->cloakedSsids.cloakedSsidsCount */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->cloakedSsids.cloakedSsidsCount; i2++)
+        {
+            bufferSize += 32; /* CsrUint8 primitive->cloakedSsids.cloakedSsids[i2].ssid[32] */
+            bufferSize += 1;  /* CsrUint8 primitive->cloakedSsids.cloakedSsids[i2].length */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeCloakedSsidsSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeCloakedSsidsSetReq *primitive = (CsrWifiSmeCloakedSsidsSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->cloakedSsids.cloakedSsidsCount);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->cloakedSsids.cloakedSsidsCount; i2++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->cloakedSsids.cloakedSsids[i2].ssid, ((CsrUint16) (32)));
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->cloakedSsids.cloakedSsids[i2].length);
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeCloakedSsidsSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeCloakedSsidsSetReq *primitive = (CsrWifiSmeCloakedSsidsSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeCloakedSsidsSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->cloakedSsids.cloakedSsidsCount, buffer, &offset);
+    primitive->cloakedSsids.cloakedSsids = NULL;
+    if (primitive->cloakedSsids.cloakedSsidsCount)
+    {
+        primitive->cloakedSsids.cloakedSsids = (CsrWifiSsid *)CsrPmemAlloc(sizeof(CsrWifiSsid) * primitive->cloakedSsids.cloakedSsidsCount);
+    }
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->cloakedSsids.cloakedSsidsCount; i2++)
+        {
+            CsrMemCpyDes(primitive->cloakedSsids.cloakedSsids[i2].ssid, buffer, &offset, ((CsrUint16) (32)));
+            CsrUint8Des((CsrUint8 *) &primitive->cloakedSsids.cloakedSsids[i2].length, buffer, &offset);
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeCloakedSsidsSetReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeCloakedSsidsSetReq *primitive = (CsrWifiSmeCloakedSsidsSetReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->cloakedSsids.cloakedSsids);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeSmeCommonConfigSetReqSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 1; /* CsrWifiSme80211dTrustLevel primitive->deviceConfig.trustLevel */
+    bufferSize += 2; /* CsrUint8 primitive->deviceConfig.countryCode[2] */
+    bufferSize += 1; /* CsrWifiSmeFirmwareDriverInterface primitive->deviceConfig.firmwareDriverInterface */
+    bufferSize += 1; /* CsrBool primitive->deviceConfig.enableStrictDraftN */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeSmeCommonConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeSmeCommonConfigSetReq *primitive = (CsrWifiSmeSmeCommonConfigSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->deviceConfig.trustLevel);
+    CsrMemCpySer(ptr, len, (const void *) primitive->deviceConfig.countryCode, ((CsrUint16) (2)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->deviceConfig.firmwareDriverInterface);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->deviceConfig.enableStrictDraftN);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeSmeCommonConfigSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeSmeCommonConfigSetReq *primitive = (CsrWifiSmeSmeCommonConfigSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeCommonConfigSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->deviceConfig.trustLevel, buffer, &offset);
+    CsrMemCpyDes(primitive->deviceConfig.countryCode, buffer, &offset, ((CsrUint16) (2)));
+    CsrUint8Des((CsrUint8 *) &primitive->deviceConfig.firmwareDriverInterface, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->deviceConfig.enableStrictDraftN, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeWpsConfigurationReqSizeof(void *msg)
+{
+    CsrWifiSmeWpsConfigurationReq *primitive = (CsrWifiSmeWpsConfigurationReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 240) */
+    bufferSize += 1;  /* CsrUint8 primitive->wpsConfig.wpsVersion */
+    bufferSize += 16; /* CsrUint8 primitive->wpsConfig.uuid[16] */
+    bufferSize += 32; /* CsrUint8 primitive->wpsConfig.deviceName[32] */
+    bufferSize += 1;  /* CsrUint8 primitive->wpsConfig.deviceNameLength */
+    bufferSize += 64; /* CsrUint8 primitive->wpsConfig.manufacturer[64] */
+    bufferSize += 1;  /* CsrUint8 primitive->wpsConfig.manufacturerLength */
+    bufferSize += 32; /* CsrUint8 primitive->wpsConfig.modelName[32] */
+    bufferSize += 1;  /* CsrUint8 primitive->wpsConfig.modelNameLength */
+    bufferSize += 32; /* CsrUint8 primitive->wpsConfig.modelNumber[32] */
+    bufferSize += 1;  /* CsrUint8 primitive->wpsConfig.modelNumberLength */
+    bufferSize += 32; /* CsrUint8 primitive->wpsConfig.serialNumber[32] */
+    bufferSize += 8;  /* CsrUint8 primitive->wpsConfig.primDeviceType.deviceDetails[8] */
+    bufferSize += 1;  /* CsrUint8 primitive->wpsConfig.secondaryDeviceTypeCount */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->wpsConfig.secondaryDeviceTypeCount; i2++)
+        {
+            bufferSize += 8; /* CsrUint8 primitive->wpsConfig.secondaryDeviceType[i2].deviceDetails[8] */
+        }
+    }
+    bufferSize += 2;         /* CsrWifiSmeWpsConfigTypeMask primitive->wpsConfig.configMethods */
+    bufferSize += 1;         /* CsrUint8 primitive->wpsConfig.rfBands */
+    bufferSize += 4;         /* CsrUint8 primitive->wpsConfig.osVersion[4] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeWpsConfigurationReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeWpsConfigurationReq *primitive = (CsrWifiSmeWpsConfigurationReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->wpsConfig.wpsVersion);
+    CsrMemCpySer(ptr, len, (const void *) primitive->wpsConfig.uuid, ((CsrUint16) (16)));
+    CsrMemCpySer(ptr, len, (const void *) primitive->wpsConfig.deviceName, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->wpsConfig.deviceNameLength);
+    CsrMemCpySer(ptr, len, (const void *) primitive->wpsConfig.manufacturer, ((CsrUint16) (64)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->wpsConfig.manufacturerLength);
+    CsrMemCpySer(ptr, len, (const void *) primitive->wpsConfig.modelName, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->wpsConfig.modelNameLength);
+    CsrMemCpySer(ptr, len, (const void *) primitive->wpsConfig.modelNumber, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->wpsConfig.modelNumberLength);
+    CsrMemCpySer(ptr, len, (const void *) primitive->wpsConfig.serialNumber, ((CsrUint16) (32)));
+    CsrMemCpySer(ptr, len, (const void *) primitive->wpsConfig.primDeviceType.deviceDetails, ((CsrUint16) (8)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->wpsConfig.secondaryDeviceTypeCount);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->wpsConfig.secondaryDeviceTypeCount; i2++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->wpsConfig.secondaryDeviceType[i2].deviceDetails, ((CsrUint16) (8)));
+        }
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->wpsConfig.configMethods);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->wpsConfig.rfBands);
+    CsrMemCpySer(ptr, len, (const void *) primitive->wpsConfig.osVersion, ((CsrUint16) (4)));
+    return(ptr);
+}
+
+
+void* CsrWifiSmeWpsConfigurationReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeWpsConfigurationReq *primitive = (CsrWifiSmeWpsConfigurationReq *) CsrPmemAlloc(sizeof(CsrWifiSmeWpsConfigurationReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->wpsConfig.wpsVersion, buffer, &offset);
+    CsrMemCpyDes(primitive->wpsConfig.uuid, buffer, &offset, ((CsrUint16) (16)));
+    CsrMemCpyDes(primitive->wpsConfig.deviceName, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->wpsConfig.deviceNameLength, buffer, &offset);
+    CsrMemCpyDes(primitive->wpsConfig.manufacturer, buffer, &offset, ((CsrUint16) (64)));
+    CsrUint8Des((CsrUint8 *) &primitive->wpsConfig.manufacturerLength, buffer, &offset);
+    CsrMemCpyDes(primitive->wpsConfig.modelName, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->wpsConfig.modelNameLength, buffer, &offset);
+    CsrMemCpyDes(primitive->wpsConfig.modelNumber, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->wpsConfig.modelNumberLength, buffer, &offset);
+    CsrMemCpyDes(primitive->wpsConfig.serialNumber, buffer, &offset, ((CsrUint16) (32)));
+    CsrMemCpyDes(primitive->wpsConfig.primDeviceType.deviceDetails, buffer, &offset, ((CsrUint16) (8)));
+    CsrUint8Des((CsrUint8 *) &primitive->wpsConfig.secondaryDeviceTypeCount, buffer, &offset);
+    primitive->wpsConfig.secondaryDeviceType = NULL;
+    if (primitive->wpsConfig.secondaryDeviceTypeCount)
+    {
+        primitive->wpsConfig.secondaryDeviceType = (CsrWifiSmeWpsDeviceType *)CsrPmemAlloc(sizeof(CsrWifiSmeWpsDeviceType) * primitive->wpsConfig.secondaryDeviceTypeCount);
+    }
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->wpsConfig.secondaryDeviceTypeCount; i2++)
+        {
+            CsrMemCpyDes(primitive->wpsConfig.secondaryDeviceType[i2].deviceDetails, buffer, &offset, ((CsrUint16) (8)));
+        }
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->wpsConfig.configMethods, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->wpsConfig.rfBands, buffer, &offset);
+    CsrMemCpyDes(primitive->wpsConfig.osVersion, buffer, &offset, ((CsrUint16) (4)));
+
+    return primitive;
+}
+
+
+void CsrWifiSmeWpsConfigurationReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeWpsConfigurationReq *primitive = (CsrWifiSmeWpsConfigurationReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->wpsConfig.secondaryDeviceType);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeSetReqSizeof(void *msg)
+{
+    CsrWifiSmeSetReq *primitive = (CsrWifiSmeSetReq *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 4;                     /* CsrUint32 primitive->dataLength */
+    bufferSize += primitive->dataLength; /* CsrUint8 primitive->data */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeSetReq *primitive = (CsrWifiSmeSetReq *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->dataLength);
+    if (primitive->dataLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->data, ((CsrUint16) (primitive->dataLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeSetReqDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeSetReq *primitive = (CsrWifiSmeSetReq *) CsrPmemAlloc(sizeof(CsrWifiSmeSetReq));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->dataLength, buffer, &offset);
+    if (primitive->dataLength)
+    {
+        primitive->data = (CsrUint8 *)CsrPmemAlloc(primitive->dataLength);
+        CsrMemCpyDes(primitive->data, buffer, &offset, ((CsrUint16) (primitive->dataLength)));
+    }
+    else
+    {
+        primitive->data = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeSetReqSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeSetReq *primitive = (CsrWifiSmeSetReq *) voidPrimitivePointer;
+    CsrPmemFree(primitive->data);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeAdhocConfigGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 2; /* CsrUint16 primitive->adHocConfig.atimWindowTu */
+    bufferSize += 2; /* CsrUint16 primitive->adHocConfig.beaconPeriodTu */
+    bufferSize += 2; /* CsrUint16 primitive->adHocConfig.joinOnlyAttempts */
+    bufferSize += 2; /* CsrUint16 primitive->adHocConfig.joinAttemptIntervalMs */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeAdhocConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeAdhocConfigGetCfm *primitive = (CsrWifiSmeAdhocConfigGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->adHocConfig.atimWindowTu);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->adHocConfig.beaconPeriodTu);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->adHocConfig.joinOnlyAttempts);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->adHocConfig.joinAttemptIntervalMs);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeAdhocConfigGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeAdhocConfigGetCfm *primitive = (CsrWifiSmeAdhocConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeAdhocConfigGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->adHocConfig.atimWindowTu, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->adHocConfig.beaconPeriodTu, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->adHocConfig.joinOnlyAttempts, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->adHocConfig.joinAttemptIntervalMs, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeAssociationCompleteIndSizeof(void *msg)
+{
+    CsrWifiSmeAssociationCompleteInd *primitive = (CsrWifiSmeAssociationCompleteInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 98) */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;                                                     /* CsrResult primitive->status */
+    bufferSize += 32;                                                    /* CsrUint8 primitive->connectionInfo.ssid.ssid[32] */
+    bufferSize += 1;                                                     /* CsrUint8 primitive->connectionInfo.ssid.length */
+    bufferSize += 6;                                                     /* CsrUint8 primitive->connectionInfo.bssid.a[6] */
+    bufferSize += 1;                                                     /* CsrWifiSme80211NetworkType primitive->connectionInfo.networkType80211 */
+    bufferSize += 1;                                                     /* CsrUint8 primitive->connectionInfo.channelNumber */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.channelFrequency */
+    bufferSize += 2;                                                     /* CsrWifiSmeAuthMode primitive->connectionInfo.authMode */
+    bufferSize += 2;                                                     /* CsrWifiSmeEncryption primitive->connectionInfo.pairwiseCipher */
+    bufferSize += 2;                                                     /* CsrWifiSmeEncryption primitive->connectionInfo.groupCipher */
+    bufferSize += 1;                                                     /* CsrWifiSmeRadioIF primitive->connectionInfo.ifIndex */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.atimWindowTu */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.beaconPeriodTu */
+    bufferSize += 1;                                                     /* CsrBool primitive->connectionInfo.reassociation */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.beaconFrameLength */
+    bufferSize += primitive->connectionInfo.beaconFrameLength;           /* CsrUint8 primitive->connectionInfo.beaconFrame */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.associationReqFrameLength */
+    bufferSize += primitive->connectionInfo.associationReqFrameLength;   /* CsrUint8 primitive->connectionInfo.associationReqFrame */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.associationRspFrameLength */
+    bufferSize += primitive->connectionInfo.associationRspFrameLength;   /* CsrUint8 primitive->connectionInfo.associationRspFrame */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocScanInfoElementsLength */
+    bufferSize += primitive->connectionInfo.assocScanInfoElementsLength; /* CsrUint8 primitive->connectionInfo.assocScanInfoElements */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocReqCapabilities */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocReqListenIntervalTu */
+    bufferSize += 6;                                                     /* CsrUint8 primitive->connectionInfo.assocReqApAddress.a[6] */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocReqInfoElementsLength */
+    bufferSize += primitive->connectionInfo.assocReqInfoElementsLength;  /* CsrUint8 primitive->connectionInfo.assocReqInfoElements */
+    bufferSize += 2;                                                     /* CsrWifiSmeIEEE80211Result primitive->connectionInfo.assocRspResult */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocRspCapabilityInfo */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocRspAssociationId */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocRspInfoElementsLength */
+    bufferSize += primitive->connectionInfo.assocRspInfoElementsLength;  /* CsrUint8 primitive->connectionInfo.assocRspInfoElements */
+    bufferSize += 2;                                                     /* CsrWifiSmeIEEE80211Reason primitive->deauthReason */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeAssociationCompleteIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeAssociationCompleteInd *primitive = (CsrWifiSmeAssociationCompleteInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.ssid.ssid, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.ssid.length);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.bssid.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.networkType80211);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.channelNumber);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.channelFrequency);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.authMode);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.pairwiseCipher);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.groupCipher);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.ifIndex);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.atimWindowTu);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.beaconPeriodTu);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.reassociation);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.beaconFrameLength);
+    if (primitive->connectionInfo.beaconFrameLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.beaconFrame, ((CsrUint16) (primitive->connectionInfo.beaconFrameLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.associationReqFrameLength);
+    if (primitive->connectionInfo.associationReqFrameLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.associationReqFrame, ((CsrUint16) (primitive->connectionInfo.associationReqFrameLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.associationRspFrameLength);
+    if (primitive->connectionInfo.associationRspFrameLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.associationRspFrame, ((CsrUint16) (primitive->connectionInfo.associationRspFrameLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocScanInfoElementsLength);
+    if (primitive->connectionInfo.assocScanInfoElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocScanInfoElements, ((CsrUint16) (primitive->connectionInfo.assocScanInfoElementsLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocReqCapabilities);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocReqListenIntervalTu);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocReqApAddress.a, ((CsrUint16) (6)));
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocReqInfoElementsLength);
+    if (primitive->connectionInfo.assocReqInfoElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocReqInfoElements, ((CsrUint16) (primitive->connectionInfo.assocReqInfoElementsLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspResult);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspCapabilityInfo);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspAssociationId);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspInfoElementsLength);
+    if (primitive->connectionInfo.assocRspInfoElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocRspInfoElements, ((CsrUint16) (primitive->connectionInfo.assocRspInfoElementsLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->deauthReason);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeAssociationCompleteIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeAssociationCompleteInd *primitive = (CsrWifiSmeAssociationCompleteInd *) CsrPmemAlloc(sizeof(CsrWifiSmeAssociationCompleteInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionInfo.ssid.ssid, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.ssid.length, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionInfo.bssid.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.networkType80211, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.channelNumber, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.channelFrequency, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.authMode, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.pairwiseCipher, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.groupCipher, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.ifIndex, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.atimWindowTu, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.beaconPeriodTu, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.reassociation, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.beaconFrameLength, buffer, &offset);
+    if (primitive->connectionInfo.beaconFrameLength)
+    {
+        primitive->connectionInfo.beaconFrame = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.beaconFrameLength);
+        CsrMemCpyDes(primitive->connectionInfo.beaconFrame, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.beaconFrameLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.beaconFrame = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.associationReqFrameLength, buffer, &offset);
+    if (primitive->connectionInfo.associationReqFrameLength)
+    {
+        primitive->connectionInfo.associationReqFrame = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.associationReqFrameLength);
+        CsrMemCpyDes(primitive->connectionInfo.associationReqFrame, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.associationReqFrameLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.associationReqFrame = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.associationRspFrameLength, buffer, &offset);
+    if (primitive->connectionInfo.associationRspFrameLength)
+    {
+        primitive->connectionInfo.associationRspFrame = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.associationRspFrameLength);
+        CsrMemCpyDes(primitive->connectionInfo.associationRspFrame, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.associationRspFrameLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.associationRspFrame = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocScanInfoElementsLength, buffer, &offset);
+    if (primitive->connectionInfo.assocScanInfoElementsLength)
+    {
+        primitive->connectionInfo.assocScanInfoElements = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.assocScanInfoElementsLength);
+        CsrMemCpyDes(primitive->connectionInfo.assocScanInfoElements, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.assocScanInfoElementsLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.assocScanInfoElements = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocReqCapabilities, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocReqListenIntervalTu, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionInfo.assocReqApAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocReqInfoElementsLength, buffer, &offset);
+    if (primitive->connectionInfo.assocReqInfoElementsLength)
+    {
+        primitive->connectionInfo.assocReqInfoElements = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.assocReqInfoElementsLength);
+        CsrMemCpyDes(primitive->connectionInfo.assocReqInfoElements, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.assocReqInfoElementsLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.assocReqInfoElements = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspResult, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspCapabilityInfo, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspAssociationId, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspInfoElementsLength, buffer, &offset);
+    if (primitive->connectionInfo.assocRspInfoElementsLength)
+    {
+        primitive->connectionInfo.assocRspInfoElements = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.assocRspInfoElementsLength);
+        CsrMemCpyDes(primitive->connectionInfo.assocRspInfoElements, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.assocRspInfoElementsLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.assocRspInfoElements = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->deauthReason, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiSmeAssociationCompleteIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeAssociationCompleteInd *primitive = (CsrWifiSmeAssociationCompleteInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->connectionInfo.beaconFrame);
+    CsrPmemFree(primitive->connectionInfo.associationReqFrame);
+    CsrPmemFree(primitive->connectionInfo.associationRspFrame);
+    CsrPmemFree(primitive->connectionInfo.assocScanInfoElements);
+    CsrPmemFree(primitive->connectionInfo.assocReqInfoElements);
+    CsrPmemFree(primitive->connectionInfo.assocRspInfoElements);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeAssociationStartIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 44) */
+    bufferSize += 2;  /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 6;  /* CsrUint8 primitive->address.a[6] */
+    bufferSize += 32; /* CsrUint8 primitive->ssid.ssid[32] */
+    bufferSize += 1;  /* CsrUint8 primitive->ssid.length */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeAssociationStartIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeAssociationStartInd *primitive = (CsrWifiSmeAssociationStartInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrMemCpySer(ptr, len, (const void *) primitive->address.a, ((CsrUint16) (6)));
+    CsrMemCpySer(ptr, len, (const void *) primitive->ssid.ssid, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ssid.length);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeAssociationStartIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeAssociationStartInd *primitive = (CsrWifiSmeAssociationStartInd *) CsrPmemAlloc(sizeof(CsrWifiSmeAssociationStartInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrMemCpyDes(primitive->address.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrMemCpyDes(primitive->ssid.ssid, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->ssid.length, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeBlacklistCfmSizeof(void *msg)
+{
+    CsrWifiSmeBlacklistCfm *primitive = (CsrWifiSmeBlacklistCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 15) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrWifiSmeListAction primitive->action */
+    bufferSize += 1; /* CsrUint8 primitive->getAddressCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getAddressCount; i1++)
+        {
+            bufferSize += 6; /* CsrUint8 primitive->getAddresses[i1].a[6] */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeBlacklistCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeBlacklistCfm *primitive = (CsrWifiSmeBlacklistCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->action);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->getAddressCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getAddressCount; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->getAddresses[i1].a, ((CsrUint16) (6)));
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeBlacklistCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeBlacklistCfm *primitive = (CsrWifiSmeBlacklistCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeBlacklistCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->action, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->getAddressCount, buffer, &offset);
+    primitive->getAddresses = NULL;
+    if (primitive->getAddressCount)
+    {
+        primitive->getAddresses = (CsrWifiMacAddress *)CsrPmemAlloc(sizeof(CsrWifiMacAddress) * primitive->getAddressCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getAddressCount; i1++)
+        {
+            CsrMemCpyDes(primitive->getAddresses[i1].a, buffer, &offset, ((CsrUint16) (6)));
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeBlacklistCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeBlacklistCfm *primitive = (CsrWifiSmeBlacklistCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->getAddresses);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeCalibrationDataGetCfmSizeof(void *msg)
+{
+    CsrWifiSmeCalibrationDataGetCfm *primitive = (CsrWifiSmeCalibrationDataGetCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 2;                                /* CsrResult primitive->status */
+    bufferSize += 2;                                /* CsrUint16 primitive->calibrationDataLength */
+    bufferSize += primitive->calibrationDataLength; /* CsrUint8 primitive->calibrationData */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeCalibrationDataGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeCalibrationDataGetCfm *primitive = (CsrWifiSmeCalibrationDataGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->calibrationDataLength);
+    if (primitive->calibrationDataLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->calibrationData, ((CsrUint16) (primitive->calibrationDataLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeCalibrationDataGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeCalibrationDataGetCfm *primitive = (CsrWifiSmeCalibrationDataGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCalibrationDataGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->calibrationDataLength, buffer, &offset);
+    if (primitive->calibrationDataLength)
+    {
+        primitive->calibrationData = (CsrUint8 *)CsrPmemAlloc(primitive->calibrationDataLength);
+        CsrMemCpyDes(primitive->calibrationData, buffer, &offset, ((CsrUint16) (primitive->calibrationDataLength)));
+    }
+    else
+    {
+        primitive->calibrationData = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeCalibrationDataGetCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeCalibrationDataGetCfm *primitive = (CsrWifiSmeCalibrationDataGetCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->calibrationData);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeCcxConfigGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 11) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrUint8 primitive->ccxConfig.keepAliveTimeMs */
+    bufferSize += 1; /* CsrBool primitive->ccxConfig.apRoamingEnabled */
+    bufferSize += 1; /* CsrUint8 primitive->ccxConfig.measurementsMask */
+    bufferSize += 1; /* CsrBool primitive->ccxConfig.ccxRadioMgtEnabled */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeCcxConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeCcxConfigGetCfm *primitive = (CsrWifiSmeCcxConfigGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ccxConfig.keepAliveTimeMs);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ccxConfig.apRoamingEnabled);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ccxConfig.measurementsMask);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->ccxConfig.ccxRadioMgtEnabled);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeCcxConfigGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeCcxConfigGetCfm *primitive = (CsrWifiSmeCcxConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCcxConfigGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->ccxConfig.keepAliveTimeMs, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->ccxConfig.apRoamingEnabled, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->ccxConfig.measurementsMask, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->ccxConfig.ccxRadioMgtEnabled, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeCcxConfigSetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeCcxConfigSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeCcxConfigSetCfm *primitive = (CsrWifiSmeCcxConfigSetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeCcxConfigSetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeCcxConfigSetCfm *primitive = (CsrWifiSmeCcxConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCcxConfigSetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeCoexConfigGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 31) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrBool primitive->coexConfig.coexEnableSchemeManagement */
+    bufferSize += 1; /* CsrBool primitive->coexConfig.coexPeriodicWakeHost */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexTrafficBurstyLatencyMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexTrafficContinuousLatencyMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexObexBlackoutDurationMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexObexBlackoutPeriodMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexA2dpBrBlackoutDurationMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexA2dpBrBlackoutPeriodMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexA2dpEdrBlackoutDurationMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexA2dpEdrBlackoutPeriodMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexPagingBlackoutDurationMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexPagingBlackoutPeriodMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexInquiryBlackoutDurationMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexConfig.coexInquiryBlackoutPeriodMs */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeCoexConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeCoexConfigGetCfm *primitive = (CsrWifiSmeCoexConfigGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->coexConfig.coexEnableSchemeManagement);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->coexConfig.coexPeriodicWakeHost);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexTrafficBurstyLatencyMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexTrafficContinuousLatencyMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexObexBlackoutDurationMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexObexBlackoutPeriodMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexA2dpBrBlackoutDurationMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexA2dpBrBlackoutPeriodMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexA2dpEdrBlackoutDurationMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexA2dpEdrBlackoutPeriodMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexPagingBlackoutDurationMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexPagingBlackoutPeriodMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexInquiryBlackoutDurationMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexConfig.coexInquiryBlackoutPeriodMs);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeCoexConfigGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeCoexConfigGetCfm *primitive = (CsrWifiSmeCoexConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCoexConfigGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->coexConfig.coexEnableSchemeManagement, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->coexConfig.coexPeriodicWakeHost, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexTrafficBurstyLatencyMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexTrafficContinuousLatencyMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexObexBlackoutDurationMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexObexBlackoutPeriodMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexA2dpBrBlackoutDurationMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexA2dpBrBlackoutPeriodMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexA2dpEdrBlackoutDurationMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexA2dpEdrBlackoutPeriodMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexPagingBlackoutDurationMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexPagingBlackoutPeriodMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexInquiryBlackoutDurationMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexConfig.coexInquiryBlackoutPeriodMs, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeCoexInfoGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 24) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrBool primitive->coexInfo.hasTrafficData */
+    bufferSize += 1; /* CsrWifiSmeTrafficType primitive->coexInfo.currentTrafficType */
+    bufferSize += 2; /* CsrUint16 primitive->coexInfo.currentPeriodMs */
+    bufferSize += 1; /* CsrWifiSmePowerSaveLevel primitive->coexInfo.currentPowerSave */
+    bufferSize += 2; /* CsrUint16 primitive->coexInfo.currentCoexPeriodMs */
+    bufferSize += 2; /* CsrUint16 primitive->coexInfo.currentCoexLatencyMs */
+    bufferSize += 1; /* CsrBool primitive->coexInfo.hasBtDevice */
+    bufferSize += 4; /* CsrUint32 primitive->coexInfo.currentBlackoutDurationUs */
+    bufferSize += 4; /* CsrUint32 primitive->coexInfo.currentBlackoutPeriodUs */
+    bufferSize += 1; /* CsrWifiSmeCoexScheme primitive->coexInfo.currentCoexScheme */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeCoexInfoGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeCoexInfoGetCfm *primitive = (CsrWifiSmeCoexInfoGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->coexInfo.hasTrafficData);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->coexInfo.currentTrafficType);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexInfo.currentPeriodMs);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->coexInfo.currentPowerSave);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexInfo.currentCoexPeriodMs);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->coexInfo.currentCoexLatencyMs);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->coexInfo.hasBtDevice);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->coexInfo.currentBlackoutDurationUs);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->coexInfo.currentBlackoutPeriodUs);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->coexInfo.currentCoexScheme);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeCoexInfoGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeCoexInfoGetCfm *primitive = (CsrWifiSmeCoexInfoGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCoexInfoGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->coexInfo.hasTrafficData, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->coexInfo.currentTrafficType, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexInfo.currentPeriodMs, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->coexInfo.currentPowerSave, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexInfo.currentCoexPeriodMs, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->coexInfo.currentCoexLatencyMs, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->coexInfo.hasBtDevice, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->coexInfo.currentBlackoutDurationUs, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->coexInfo.currentBlackoutPeriodUs, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->coexInfo.currentCoexScheme, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeConnectCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeConnectCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeConnectCfm *primitive = (CsrWifiSmeConnectCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeConnectCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeConnectCfm *primitive = (CsrWifiSmeConnectCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeConnectionConfigGetCfmSizeof(void *msg)
+{
+    CsrWifiSmeConnectionConfigGetCfm *primitive = (CsrWifiSmeConnectionConfigGetCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 59) */
+    bufferSize += 2;                                                                     /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;                                                                     /* CsrResult primitive->status */
+    bufferSize += 32;                                                                    /* CsrUint8 primitive->connectionConfig.ssid.ssid[32] */
+    bufferSize += 1;                                                                     /* CsrUint8 primitive->connectionConfig.ssid.length */
+    bufferSize += 6;                                                                     /* CsrUint8 primitive->connectionConfig.bssid.a[6] */
+    bufferSize += 1;                                                                     /* CsrWifiSmeBssType primitive->connectionConfig.bssType */
+    bufferSize += 1;                                                                     /* CsrWifiSmeRadioIF primitive->connectionConfig.ifIndex */
+    bufferSize += 1;                                                                     /* CsrWifiSme80211PrivacyMode primitive->connectionConfig.privacyMode */
+    bufferSize += 2;                                                                     /* CsrWifiSmeAuthModeMask primitive->connectionConfig.authModeMask */
+    bufferSize += 2;                                                                     /* CsrWifiSmeEncryptionMask primitive->connectionConfig.encryptionModeMask */
+    bufferSize += 2;                                                                     /* CsrUint16 primitive->connectionConfig.mlmeAssociateReqInformationElementsLength */
+    bufferSize += primitive->connectionConfig.mlmeAssociateReqInformationElementsLength; /* CsrUint8 primitive->connectionConfig.mlmeAssociateReqInformationElements */
+    bufferSize += 1;                                                                     /* CsrWifiSmeWmmQosInfoMask primitive->connectionConfig.wmmQosInfo */
+    bufferSize += 1;                                                                     /* CsrBool primitive->connectionConfig.adhocJoinOnly */
+    bufferSize += 1;                                                                     /* CsrUint8 primitive->connectionConfig.adhocChannel */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeConnectionConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeConnectionConfigGetCfm *primitive = (CsrWifiSmeConnectionConfigGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionConfig.ssid.ssid, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.ssid.length);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionConfig.bssid.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.bssType);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.ifIndex);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.privacyMode);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionConfig.authModeMask);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionConfig.encryptionModeMask);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionConfig.mlmeAssociateReqInformationElementsLength);
+    if (primitive->connectionConfig.mlmeAssociateReqInformationElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionConfig.mlmeAssociateReqInformationElements, ((CsrUint16) (primitive->connectionConfig.mlmeAssociateReqInformationElementsLength)));
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.wmmQosInfo);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.adhocJoinOnly);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionConfig.adhocChannel);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeConnectionConfigGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeConnectionConfigGetCfm *primitive = (CsrWifiSmeConnectionConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectionConfigGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionConfig.ssid.ssid, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.ssid.length, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionConfig.bssid.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.bssType, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.ifIndex, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.privacyMode, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionConfig.authModeMask, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionConfig.encryptionModeMask, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionConfig.mlmeAssociateReqInformationElementsLength, buffer, &offset);
+    if (primitive->connectionConfig.mlmeAssociateReqInformationElementsLength)
+    {
+        primitive->connectionConfig.mlmeAssociateReqInformationElements = (CsrUint8 *)CsrPmemAlloc(primitive->connectionConfig.mlmeAssociateReqInformationElementsLength);
+        CsrMemCpyDes(primitive->connectionConfig.mlmeAssociateReqInformationElements, buffer, &offset, ((CsrUint16) (primitive->connectionConfig.mlmeAssociateReqInformationElementsLength)));
+    }
+    else
+    {
+        primitive->connectionConfig.mlmeAssociateReqInformationElements = NULL;
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.wmmQosInfo, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.adhocJoinOnly, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionConfig.adhocChannel, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiSmeConnectionConfigGetCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeConnectionConfigGetCfm *primitive = (CsrWifiSmeConnectionConfigGetCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->connectionConfig.mlmeAssociateReqInformationElements);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeConnectionInfoGetCfmSizeof(void *msg)
+{
+    CsrWifiSmeConnectionInfoGetCfm *primitive = (CsrWifiSmeConnectionInfoGetCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 96) */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;                                                     /* CsrResult primitive->status */
+    bufferSize += 32;                                                    /* CsrUint8 primitive->connectionInfo.ssid.ssid[32] */
+    bufferSize += 1;                                                     /* CsrUint8 primitive->connectionInfo.ssid.length */
+    bufferSize += 6;                                                     /* CsrUint8 primitive->connectionInfo.bssid.a[6] */
+    bufferSize += 1;                                                     /* CsrWifiSme80211NetworkType primitive->connectionInfo.networkType80211 */
+    bufferSize += 1;                                                     /* CsrUint8 primitive->connectionInfo.channelNumber */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.channelFrequency */
+    bufferSize += 2;                                                     /* CsrWifiSmeAuthMode primitive->connectionInfo.authMode */
+    bufferSize += 2;                                                     /* CsrWifiSmeEncryption primitive->connectionInfo.pairwiseCipher */
+    bufferSize += 2;                                                     /* CsrWifiSmeEncryption primitive->connectionInfo.groupCipher */
+    bufferSize += 1;                                                     /* CsrWifiSmeRadioIF primitive->connectionInfo.ifIndex */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.atimWindowTu */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.beaconPeriodTu */
+    bufferSize += 1;                                                     /* CsrBool primitive->connectionInfo.reassociation */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.beaconFrameLength */
+    bufferSize += primitive->connectionInfo.beaconFrameLength;           /* CsrUint8 primitive->connectionInfo.beaconFrame */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.associationReqFrameLength */
+    bufferSize += primitive->connectionInfo.associationReqFrameLength;   /* CsrUint8 primitive->connectionInfo.associationReqFrame */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.associationRspFrameLength */
+    bufferSize += primitive->connectionInfo.associationRspFrameLength;   /* CsrUint8 primitive->connectionInfo.associationRspFrame */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocScanInfoElementsLength */
+    bufferSize += primitive->connectionInfo.assocScanInfoElementsLength; /* CsrUint8 primitive->connectionInfo.assocScanInfoElements */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocReqCapabilities */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocReqListenIntervalTu */
+    bufferSize += 6;                                                     /* CsrUint8 primitive->connectionInfo.assocReqApAddress.a[6] */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocReqInfoElementsLength */
+    bufferSize += primitive->connectionInfo.assocReqInfoElementsLength;  /* CsrUint8 primitive->connectionInfo.assocReqInfoElements */
+    bufferSize += 2;                                                     /* CsrWifiSmeIEEE80211Result primitive->connectionInfo.assocRspResult */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocRspCapabilityInfo */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocRspAssociationId */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocRspInfoElementsLength */
+    bufferSize += primitive->connectionInfo.assocRspInfoElementsLength;  /* CsrUint8 primitive->connectionInfo.assocRspInfoElements */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeConnectionInfoGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeConnectionInfoGetCfm *primitive = (CsrWifiSmeConnectionInfoGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.ssid.ssid, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.ssid.length);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.bssid.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.networkType80211);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.channelNumber);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.channelFrequency);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.authMode);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.pairwiseCipher);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.groupCipher);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.ifIndex);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.atimWindowTu);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.beaconPeriodTu);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.reassociation);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.beaconFrameLength);
+    if (primitive->connectionInfo.beaconFrameLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.beaconFrame, ((CsrUint16) (primitive->connectionInfo.beaconFrameLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.associationReqFrameLength);
+    if (primitive->connectionInfo.associationReqFrameLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.associationReqFrame, ((CsrUint16) (primitive->connectionInfo.associationReqFrameLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.associationRspFrameLength);
+    if (primitive->connectionInfo.associationRspFrameLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.associationRspFrame, ((CsrUint16) (primitive->connectionInfo.associationRspFrameLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocScanInfoElementsLength);
+    if (primitive->connectionInfo.assocScanInfoElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocScanInfoElements, ((CsrUint16) (primitive->connectionInfo.assocScanInfoElementsLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocReqCapabilities);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocReqListenIntervalTu);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocReqApAddress.a, ((CsrUint16) (6)));
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocReqInfoElementsLength);
+    if (primitive->connectionInfo.assocReqInfoElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocReqInfoElements, ((CsrUint16) (primitive->connectionInfo.assocReqInfoElementsLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspResult);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspCapabilityInfo);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspAssociationId);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspInfoElementsLength);
+    if (primitive->connectionInfo.assocRspInfoElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocRspInfoElements, ((CsrUint16) (primitive->connectionInfo.assocRspInfoElementsLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeConnectionInfoGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeConnectionInfoGetCfm *primitive = (CsrWifiSmeConnectionInfoGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectionInfoGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionInfo.ssid.ssid, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.ssid.length, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionInfo.bssid.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.networkType80211, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.channelNumber, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.channelFrequency, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.authMode, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.pairwiseCipher, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.groupCipher, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.ifIndex, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.atimWindowTu, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.beaconPeriodTu, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.reassociation, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.beaconFrameLength, buffer, &offset);
+    if (primitive->connectionInfo.beaconFrameLength)
+    {
+        primitive->connectionInfo.beaconFrame = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.beaconFrameLength);
+        CsrMemCpyDes(primitive->connectionInfo.beaconFrame, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.beaconFrameLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.beaconFrame = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.associationReqFrameLength, buffer, &offset);
+    if (primitive->connectionInfo.associationReqFrameLength)
+    {
+        primitive->connectionInfo.associationReqFrame = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.associationReqFrameLength);
+        CsrMemCpyDes(primitive->connectionInfo.associationReqFrame, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.associationReqFrameLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.associationReqFrame = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.associationRspFrameLength, buffer, &offset);
+    if (primitive->connectionInfo.associationRspFrameLength)
+    {
+        primitive->connectionInfo.associationRspFrame = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.associationRspFrameLength);
+        CsrMemCpyDes(primitive->connectionInfo.associationRspFrame, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.associationRspFrameLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.associationRspFrame = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocScanInfoElementsLength, buffer, &offset);
+    if (primitive->connectionInfo.assocScanInfoElementsLength)
+    {
+        primitive->connectionInfo.assocScanInfoElements = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.assocScanInfoElementsLength);
+        CsrMemCpyDes(primitive->connectionInfo.assocScanInfoElements, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.assocScanInfoElementsLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.assocScanInfoElements = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocReqCapabilities, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocReqListenIntervalTu, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionInfo.assocReqApAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocReqInfoElementsLength, buffer, &offset);
+    if (primitive->connectionInfo.assocReqInfoElementsLength)
+    {
+        primitive->connectionInfo.assocReqInfoElements = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.assocReqInfoElementsLength);
+        CsrMemCpyDes(primitive->connectionInfo.assocReqInfoElements, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.assocReqInfoElementsLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.assocReqInfoElements = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspResult, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspCapabilityInfo, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspAssociationId, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspInfoElementsLength, buffer, &offset);
+    if (primitive->connectionInfo.assocRspInfoElementsLength)
+    {
+        primitive->connectionInfo.assocRspInfoElements = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.assocRspInfoElementsLength);
+        CsrMemCpyDes(primitive->connectionInfo.assocRspInfoElements, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.assocRspInfoElementsLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.assocRspInfoElements = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeConnectionInfoGetCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeConnectionInfoGetCfm *primitive = (CsrWifiSmeConnectionInfoGetCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->connectionInfo.beaconFrame);
+    CsrPmemFree(primitive->connectionInfo.associationReqFrame);
+    CsrPmemFree(primitive->connectionInfo.associationRspFrame);
+    CsrPmemFree(primitive->connectionInfo.assocScanInfoElements);
+    CsrPmemFree(primitive->connectionInfo.assocReqInfoElements);
+    CsrPmemFree(primitive->connectionInfo.assocRspInfoElements);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeConnectionQualityIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 9) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrInt16 primitive->linkQuality.unifiRssi */
+    bufferSize += 2; /* CsrInt16 primitive->linkQuality.unifiSnr */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeConnectionQualityIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeConnectionQualityInd *primitive = (CsrWifiSmeConnectionQualityInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->linkQuality.unifiRssi);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->linkQuality.unifiSnr);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeConnectionQualityIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeConnectionQualityInd *primitive = (CsrWifiSmeConnectionQualityInd *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectionQualityInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->linkQuality.unifiRssi, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->linkQuality.unifiSnr, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeConnectionStatsGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 101) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrUint8 primitive->connectionStats.unifiTxDataRate */
+    bufferSize += 1; /* CsrUint8 primitive->connectionStats.unifiRxDataRate */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11RetryCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11MultipleRetryCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11AckFailureCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11FrameDuplicateCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11FcsErrorCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11RtsSuccessCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11RtsFailureCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11FailedCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11TransmittedFragmentCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11TransmittedFrameCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11WepExcludedCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11WepIcvErrorCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11WepUndecryptableCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11MulticastReceivedFrameCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11MulticastTransmittedFrameCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11ReceivedFragmentCount */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11Rsna4WayHandshakeFailures */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11RsnaTkipCounterMeasuresInvoked */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11RsnaStatsTkipLocalMicFailures */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11RsnaStatsTkipReplays */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11RsnaStatsTkipIcvErrors */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11RsnaStatsCcmpReplays */
+    bufferSize += 4; /* CsrUint32 primitive->connectionStats.dot11RsnaStatsCcmpDecryptErrors */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeConnectionStatsGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeConnectionStatsGetCfm *primitive = (CsrWifiSmeConnectionStatsGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionStats.unifiTxDataRate);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionStats.unifiRxDataRate);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11RetryCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11MultipleRetryCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11AckFailureCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11FrameDuplicateCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11FcsErrorCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11RtsSuccessCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11RtsFailureCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11FailedCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11TransmittedFragmentCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11TransmittedFrameCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11WepExcludedCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11WepIcvErrorCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11WepUndecryptableCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11MulticastReceivedFrameCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11MulticastTransmittedFrameCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11ReceivedFragmentCount);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11Rsna4WayHandshakeFailures);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11RsnaTkipCounterMeasuresInvoked);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11RsnaStatsTkipLocalMicFailures);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11RsnaStatsTkipReplays);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11RsnaStatsTkipIcvErrors);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11RsnaStatsCcmpReplays);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->connectionStats.dot11RsnaStatsCcmpDecryptErrors);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeConnectionStatsGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeConnectionStatsGetCfm *primitive = (CsrWifiSmeConnectionStatsGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeConnectionStatsGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionStats.unifiTxDataRate, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionStats.unifiRxDataRate, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11RetryCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11MultipleRetryCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11AckFailureCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11FrameDuplicateCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11FcsErrorCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11RtsSuccessCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11RtsFailureCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11FailedCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11TransmittedFragmentCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11TransmittedFrameCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11WepExcludedCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11WepIcvErrorCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11WepUndecryptableCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11MulticastReceivedFrameCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11MulticastTransmittedFrameCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11ReceivedFragmentCount, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11Rsna4WayHandshakeFailures, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11RsnaTkipCounterMeasuresInvoked, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11RsnaStatsTkipLocalMicFailures, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11RsnaStatsTkipReplays, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11RsnaStatsTkipIcvErrors, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11RsnaStatsCcmpReplays, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->connectionStats.dot11RsnaStatsCcmpDecryptErrors, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeDisconnectCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeDisconnectCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeDisconnectCfm *primitive = (CsrWifiSmeDisconnectCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeDisconnectCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeDisconnectCfm *primitive = (CsrWifiSmeDisconnectCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeDisconnectCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeHostConfigGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrWifiSmeHostPowerMode primitive->hostConfig.powerMode */
+    bufferSize += 2; /* CsrUint16 primitive->hostConfig.applicationDataPeriodMs */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeHostConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeHostConfigGetCfm *primitive = (CsrWifiSmeHostConfigGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->hostConfig.powerMode);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->hostConfig.applicationDataPeriodMs);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeHostConfigGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeHostConfigGetCfm *primitive = (CsrWifiSmeHostConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeHostConfigGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->hostConfig.powerMode, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->hostConfig.applicationDataPeriodMs, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeHostConfigSetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeHostConfigSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeHostConfigSetCfm *primitive = (CsrWifiSmeHostConfigSetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeHostConfigSetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeHostConfigSetCfm *primitive = (CsrWifiSmeHostConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeHostConfigSetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeIbssStationIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 6; /* CsrUint8 primitive->address.a[6] */
+    bufferSize += 1; /* CsrBool primitive->isconnected */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeIbssStationIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeIbssStationInd *primitive = (CsrWifiSmeIbssStationInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrMemCpySer(ptr, len, (const void *) primitive->address.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->isconnected);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeIbssStationIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeIbssStationInd *primitive = (CsrWifiSmeIbssStationInd *) CsrPmemAlloc(sizeof(CsrWifiSmeIbssStationInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrMemCpyDes(primitive->address.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->isconnected, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeKeyCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 15) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrWifiSmeListAction primitive->action */
+    bufferSize += 1; /* CsrWifiSmeKeyType primitive->keyType */
+    bufferSize += 6; /* CsrUint8 primitive->peerMacAddress.a[6] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeKeyCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeKeyCfm *primitive = (CsrWifiSmeKeyCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->action);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->keyType);
+    CsrMemCpySer(ptr, len, (const void *) primitive->peerMacAddress.a, ((CsrUint16) (6)));
+    return(ptr);
+}
+
+
+void* CsrWifiSmeKeyCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeKeyCfm *primitive = (CsrWifiSmeKeyCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeKeyCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->action, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->keyType, buffer, &offset);
+    CsrMemCpyDes(primitive->peerMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeLinkQualityGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 11) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 2; /* CsrInt16 primitive->linkQuality.unifiRssi */
+    bufferSize += 2; /* CsrInt16 primitive->linkQuality.unifiSnr */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeLinkQualityGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeLinkQualityGetCfm *primitive = (CsrWifiSmeLinkQualityGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->linkQuality.unifiRssi);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->linkQuality.unifiSnr);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeLinkQualityGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeLinkQualityGetCfm *primitive = (CsrWifiSmeLinkQualityGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeLinkQualityGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->linkQuality.unifiRssi, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->linkQuality.unifiSnr, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeMediaStatusIndSizeof(void *msg)
+{
+    CsrWifiSmeMediaStatusInd *primitive = (CsrWifiSmeMediaStatusInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 99) */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1;                                                     /* CsrWifiSmeMediaStatus primitive->mediaStatus */
+    bufferSize += 32;                                                    /* CsrUint8 primitive->connectionInfo.ssid.ssid[32] */
+    bufferSize += 1;                                                     /* CsrUint8 primitive->connectionInfo.ssid.length */
+    bufferSize += 6;                                                     /* CsrUint8 primitive->connectionInfo.bssid.a[6] */
+    bufferSize += 1;                                                     /* CsrWifiSme80211NetworkType primitive->connectionInfo.networkType80211 */
+    bufferSize += 1;                                                     /* CsrUint8 primitive->connectionInfo.channelNumber */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.channelFrequency */
+    bufferSize += 2;                                                     /* CsrWifiSmeAuthMode primitive->connectionInfo.authMode */
+    bufferSize += 2;                                                     /* CsrWifiSmeEncryption primitive->connectionInfo.pairwiseCipher */
+    bufferSize += 2;                                                     /* CsrWifiSmeEncryption primitive->connectionInfo.groupCipher */
+    bufferSize += 1;                                                     /* CsrWifiSmeRadioIF primitive->connectionInfo.ifIndex */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.atimWindowTu */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.beaconPeriodTu */
+    bufferSize += 1;                                                     /* CsrBool primitive->connectionInfo.reassociation */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.beaconFrameLength */
+    bufferSize += primitive->connectionInfo.beaconFrameLength;           /* CsrUint8 primitive->connectionInfo.beaconFrame */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.associationReqFrameLength */
+    bufferSize += primitive->connectionInfo.associationReqFrameLength;   /* CsrUint8 primitive->connectionInfo.associationReqFrame */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.associationRspFrameLength */
+    bufferSize += primitive->connectionInfo.associationRspFrameLength;   /* CsrUint8 primitive->connectionInfo.associationRspFrame */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocScanInfoElementsLength */
+    bufferSize += primitive->connectionInfo.assocScanInfoElementsLength; /* CsrUint8 primitive->connectionInfo.assocScanInfoElements */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocReqCapabilities */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocReqListenIntervalTu */
+    bufferSize += 6;                                                     /* CsrUint8 primitive->connectionInfo.assocReqApAddress.a[6] */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocReqInfoElementsLength */
+    bufferSize += primitive->connectionInfo.assocReqInfoElementsLength;  /* CsrUint8 primitive->connectionInfo.assocReqInfoElements */
+    bufferSize += 2;                                                     /* CsrWifiSmeIEEE80211Result primitive->connectionInfo.assocRspResult */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocRspCapabilityInfo */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocRspAssociationId */
+    bufferSize += 2;                                                     /* CsrUint16 primitive->connectionInfo.assocRspInfoElementsLength */
+    bufferSize += primitive->connectionInfo.assocRspInfoElementsLength;  /* CsrUint8 primitive->connectionInfo.assocRspInfoElements */
+    bufferSize += 2;                                                     /* CsrWifiSmeIEEE80211Reason primitive->disassocReason */
+    bufferSize += 2;                                                     /* CsrWifiSmeIEEE80211Reason primitive->deauthReason */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeMediaStatusIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeMediaStatusInd *primitive = (CsrWifiSmeMediaStatusInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->mediaStatus);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.ssid.ssid, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.ssid.length);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.bssid.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.networkType80211);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.channelNumber);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.channelFrequency);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.authMode);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.pairwiseCipher);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.groupCipher);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.ifIndex);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.atimWindowTu);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.beaconPeriodTu);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->connectionInfo.reassociation);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.beaconFrameLength);
+    if (primitive->connectionInfo.beaconFrameLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.beaconFrame, ((CsrUint16) (primitive->connectionInfo.beaconFrameLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.associationReqFrameLength);
+    if (primitive->connectionInfo.associationReqFrameLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.associationReqFrame, ((CsrUint16) (primitive->connectionInfo.associationReqFrameLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.associationRspFrameLength);
+    if (primitive->connectionInfo.associationRspFrameLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.associationRspFrame, ((CsrUint16) (primitive->connectionInfo.associationRspFrameLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocScanInfoElementsLength);
+    if (primitive->connectionInfo.assocScanInfoElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocScanInfoElements, ((CsrUint16) (primitive->connectionInfo.assocScanInfoElementsLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocReqCapabilities);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocReqListenIntervalTu);
+    CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocReqApAddress.a, ((CsrUint16) (6)));
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocReqInfoElementsLength);
+    if (primitive->connectionInfo.assocReqInfoElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocReqInfoElements, ((CsrUint16) (primitive->connectionInfo.assocReqInfoElementsLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspResult);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspCapabilityInfo);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspAssociationId);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->connectionInfo.assocRspInfoElementsLength);
+    if (primitive->connectionInfo.assocRspInfoElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->connectionInfo.assocRspInfoElements, ((CsrUint16) (primitive->connectionInfo.assocRspInfoElementsLength)));
+    }
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->disassocReason);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->deauthReason);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeMediaStatusIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeMediaStatusInd *primitive = (CsrWifiSmeMediaStatusInd *) CsrPmemAlloc(sizeof(CsrWifiSmeMediaStatusInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->mediaStatus, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionInfo.ssid.ssid, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.ssid.length, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionInfo.bssid.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.networkType80211, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.channelNumber, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.channelFrequency, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.authMode, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.pairwiseCipher, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.groupCipher, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.ifIndex, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.atimWindowTu, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.beaconPeriodTu, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->connectionInfo.reassociation, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.beaconFrameLength, buffer, &offset);
+    if (primitive->connectionInfo.beaconFrameLength)
+    {
+        primitive->connectionInfo.beaconFrame = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.beaconFrameLength);
+        CsrMemCpyDes(primitive->connectionInfo.beaconFrame, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.beaconFrameLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.beaconFrame = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.associationReqFrameLength, buffer, &offset);
+    if (primitive->connectionInfo.associationReqFrameLength)
+    {
+        primitive->connectionInfo.associationReqFrame = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.associationReqFrameLength);
+        CsrMemCpyDes(primitive->connectionInfo.associationReqFrame, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.associationReqFrameLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.associationReqFrame = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.associationRspFrameLength, buffer, &offset);
+    if (primitive->connectionInfo.associationRspFrameLength)
+    {
+        primitive->connectionInfo.associationRspFrame = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.associationRspFrameLength);
+        CsrMemCpyDes(primitive->connectionInfo.associationRspFrame, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.associationRspFrameLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.associationRspFrame = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocScanInfoElementsLength, buffer, &offset);
+    if (primitive->connectionInfo.assocScanInfoElementsLength)
+    {
+        primitive->connectionInfo.assocScanInfoElements = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.assocScanInfoElementsLength);
+        CsrMemCpyDes(primitive->connectionInfo.assocScanInfoElements, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.assocScanInfoElementsLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.assocScanInfoElements = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocReqCapabilities, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocReqListenIntervalTu, buffer, &offset);
+    CsrMemCpyDes(primitive->connectionInfo.assocReqApAddress.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocReqInfoElementsLength, buffer, &offset);
+    if (primitive->connectionInfo.assocReqInfoElementsLength)
+    {
+        primitive->connectionInfo.assocReqInfoElements = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.assocReqInfoElementsLength);
+        CsrMemCpyDes(primitive->connectionInfo.assocReqInfoElements, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.assocReqInfoElementsLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.assocReqInfoElements = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspResult, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspCapabilityInfo, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspAssociationId, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->connectionInfo.assocRspInfoElementsLength, buffer, &offset);
+    if (primitive->connectionInfo.assocRspInfoElementsLength)
+    {
+        primitive->connectionInfo.assocRspInfoElements = (CsrUint8 *)CsrPmemAlloc(primitive->connectionInfo.assocRspInfoElementsLength);
+        CsrMemCpyDes(primitive->connectionInfo.assocRspInfoElements, buffer, &offset, ((CsrUint16) (primitive->connectionInfo.assocRspInfoElementsLength)));
+    }
+    else
+    {
+        primitive->connectionInfo.assocRspInfoElements = NULL;
+    }
+    CsrUint16Des((CsrUint16 *) &primitive->disassocReason, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->deauthReason, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiSmeMediaStatusIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeMediaStatusInd *primitive = (CsrWifiSmeMediaStatusInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->connectionInfo.beaconFrame);
+    CsrPmemFree(primitive->connectionInfo.associationReqFrame);
+    CsrPmemFree(primitive->connectionInfo.associationRspFrame);
+    CsrPmemFree(primitive->connectionInfo.assocScanInfoElements);
+    CsrPmemFree(primitive->connectionInfo.assocReqInfoElements);
+    CsrPmemFree(primitive->connectionInfo.assocRspInfoElements);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeMibConfigGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrBool primitive->mibConfig.unifiFixMaxTxDataRate */
+    bufferSize += 1; /* CsrUint8 primitive->mibConfig.unifiFixTxDataRate */
+    bufferSize += 2; /* CsrUint16 primitive->mibConfig.dot11RtsThreshold */
+    bufferSize += 2; /* CsrUint16 primitive->mibConfig.dot11FragmentationThreshold */
+    bufferSize += 2; /* CsrUint16 primitive->mibConfig.dot11CurrentTxPowerLevel */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeMibConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeMibConfigGetCfm *primitive = (CsrWifiSmeMibConfigGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->mibConfig.unifiFixMaxTxDataRate);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->mibConfig.unifiFixTxDataRate);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibConfig.dot11RtsThreshold);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibConfig.dot11FragmentationThreshold);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibConfig.dot11CurrentTxPowerLevel);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeMibConfigGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeMibConfigGetCfm *primitive = (CsrWifiSmeMibConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeMibConfigGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->mibConfig.unifiFixMaxTxDataRate, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->mibConfig.unifiFixTxDataRate, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mibConfig.dot11RtsThreshold, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mibConfig.dot11FragmentationThreshold, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mibConfig.dot11CurrentTxPowerLevel, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeMibGetCfmSizeof(void *msg)
+{
+    CsrWifiSmeMibGetCfm *primitive = (CsrWifiSmeMibGetCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 2;                             /* CsrResult primitive->status */
+    bufferSize += 2;                             /* CsrUint16 primitive->mibAttributeLength */
+    bufferSize += primitive->mibAttributeLength; /* CsrUint8 primitive->mibAttribute */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeMibGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeMibGetCfm *primitive = (CsrWifiSmeMibGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibAttributeLength);
+    if (primitive->mibAttributeLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->mibAttribute, ((CsrUint16) (primitive->mibAttributeLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeMibGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeMibGetCfm *primitive = (CsrWifiSmeMibGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeMibGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mibAttributeLength, buffer, &offset);
+    if (primitive->mibAttributeLength)
+    {
+        primitive->mibAttribute = (CsrUint8 *)CsrPmemAlloc(primitive->mibAttributeLength);
+        CsrMemCpyDes(primitive->mibAttribute, buffer, &offset, ((CsrUint16) (primitive->mibAttributeLength)));
+    }
+    else
+    {
+        primitive->mibAttribute = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeMibGetCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeMibGetCfm *primitive = (CsrWifiSmeMibGetCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->mibAttribute);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeMibGetNextCfmSizeof(void *msg)
+{
+    CsrWifiSmeMibGetNextCfm *primitive = (CsrWifiSmeMibGetNextCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 2;                             /* CsrResult primitive->status */
+    bufferSize += 2;                             /* CsrUint16 primitive->mibAttributeLength */
+    bufferSize += primitive->mibAttributeLength; /* CsrUint8 primitive->mibAttribute */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeMibGetNextCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeMibGetNextCfm *primitive = (CsrWifiSmeMibGetNextCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->mibAttributeLength);
+    if (primitive->mibAttributeLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->mibAttribute, ((CsrUint16) (primitive->mibAttributeLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeMibGetNextCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeMibGetNextCfm *primitive = (CsrWifiSmeMibGetNextCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeMibGetNextCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->mibAttributeLength, buffer, &offset);
+    if (primitive->mibAttributeLength)
+    {
+        primitive->mibAttribute = (CsrUint8 *)CsrPmemAlloc(primitive->mibAttributeLength);
+        CsrMemCpyDes(primitive->mibAttribute, buffer, &offset, ((CsrUint16) (primitive->mibAttributeLength)));
+    }
+    else
+    {
+        primitive->mibAttribute = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeMibGetNextCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeMibGetNextCfm *primitive = (CsrWifiSmeMibGetNextCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->mibAttribute);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeMicFailureIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 15) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrBool primitive->secondFailure */
+    bufferSize += 2; /* CsrUint16 primitive->count */
+    bufferSize += 6; /* CsrUint8 primitive->address.a[6] */
+    bufferSize += 1; /* CsrWifiSmeKeyType primitive->keyType */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeMicFailureIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeMicFailureInd *primitive = (CsrWifiSmeMicFailureInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->secondFailure);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->count);
+    CsrMemCpySer(ptr, len, (const void *) primitive->address.a, ((CsrUint16) (6)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->keyType);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeMicFailureIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeMicFailureInd *primitive = (CsrWifiSmeMicFailureInd *) CsrPmemAlloc(sizeof(CsrWifiSmeMicFailureInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->secondFailure, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->count, buffer, &offset);
+    CsrMemCpyDes(primitive->address.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint8Des((CsrUint8 *) &primitive->keyType, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeMulticastAddressCfmSizeof(void *msg)
+{
+    CsrWifiSmeMulticastAddressCfm *primitive = (CsrWifiSmeMulticastAddressCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 15) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrWifiSmeListAction primitive->action */
+    bufferSize += 1; /* CsrUint8 primitive->getAddressesCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getAddressesCount; i1++)
+        {
+            bufferSize += 6; /* CsrUint8 primitive->getAddresses[i1].a[6] */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeMulticastAddressCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeMulticastAddressCfm *primitive = (CsrWifiSmeMulticastAddressCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->action);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->getAddressesCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getAddressesCount; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->getAddresses[i1].a, ((CsrUint16) (6)));
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeMulticastAddressCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeMulticastAddressCfm *primitive = (CsrWifiSmeMulticastAddressCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeMulticastAddressCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->action, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->getAddressesCount, buffer, &offset);
+    primitive->getAddresses = NULL;
+    if (primitive->getAddressesCount)
+    {
+        primitive->getAddresses = (CsrWifiMacAddress *)CsrPmemAlloc(sizeof(CsrWifiMacAddress) * primitive->getAddressesCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getAddressesCount; i1++)
+        {
+            CsrMemCpyDes(primitive->getAddresses[i1].a, buffer, &offset, ((CsrUint16) (6)));
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeMulticastAddressCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeMulticastAddressCfm *primitive = (CsrWifiSmeMulticastAddressCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->getAddresses);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmePacketFilterSetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmePacketFilterSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmePacketFilterSetCfm *primitive = (CsrWifiSmePacketFilterSetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiSmePacketFilterSetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmePacketFilterSetCfm *primitive = (CsrWifiSmePacketFilterSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmePacketFilterSetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmePermanentMacAddressGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 11) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 6; /* CsrUint8 primitive->permanentMacAddress.a[6] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmePermanentMacAddressGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmePermanentMacAddressGetCfm *primitive = (CsrWifiSmePermanentMacAddressGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrMemCpySer(ptr, len, (const void *) primitive->permanentMacAddress.a, ((CsrUint16) (6)));
+    return(ptr);
+}
+
+
+void* CsrWifiSmePermanentMacAddressGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmePermanentMacAddressGetCfm *primitive = (CsrWifiSmePermanentMacAddressGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmePermanentMacAddressGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrMemCpyDes(primitive->permanentMacAddress.a, buffer, &offset, ((CsrUint16) (6)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmePmkidCandidateListIndSizeof(void *msg)
+{
+    CsrWifiSmePmkidCandidateListInd *primitive = (CsrWifiSmePmkidCandidateListInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrUint8 primitive->pmkidCandidatesCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->pmkidCandidatesCount; i1++)
+        {
+            bufferSize += 6; /* CsrUint8 primitive->pmkidCandidates[i1].bssid.a[6] */
+            bufferSize += 1; /* CsrBool primitive->pmkidCandidates[i1].preAuthAllowed */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmePmkidCandidateListIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmePmkidCandidateListInd *primitive = (CsrWifiSmePmkidCandidateListInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->pmkidCandidatesCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->pmkidCandidatesCount; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->pmkidCandidates[i1].bssid.a, ((CsrUint16) (6)));
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->pmkidCandidates[i1].preAuthAllowed);
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmePmkidCandidateListIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmePmkidCandidateListInd *primitive = (CsrWifiSmePmkidCandidateListInd *) CsrPmemAlloc(sizeof(CsrWifiSmePmkidCandidateListInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->pmkidCandidatesCount, buffer, &offset);
+    primitive->pmkidCandidates = NULL;
+    if (primitive->pmkidCandidatesCount)
+    {
+        primitive->pmkidCandidates = (CsrWifiSmePmkidCandidate *)CsrPmemAlloc(sizeof(CsrWifiSmePmkidCandidate) * primitive->pmkidCandidatesCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->pmkidCandidatesCount; i1++)
+        {
+            CsrMemCpyDes(primitive->pmkidCandidates[i1].bssid.a, buffer, &offset, ((CsrUint16) (6)));
+            CsrUint8Des((CsrUint8 *) &primitive->pmkidCandidates[i1].preAuthAllowed, buffer, &offset);
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmePmkidCandidateListIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmePmkidCandidateListInd *primitive = (CsrWifiSmePmkidCandidateListInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->pmkidCandidates);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmePmkidCfmSizeof(void *msg)
+{
+    CsrWifiSmePmkidCfm *primitive = (CsrWifiSmePmkidCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 31) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrWifiSmeListAction primitive->action */
+    bufferSize += 1; /* CsrUint8 primitive->getPmkidsCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getPmkidsCount; i1++)
+        {
+            bufferSize += 6;  /* CsrUint8 primitive->getPmkids[i1].bssid.a[6] */
+            bufferSize += 16; /* CsrUint8 primitive->getPmkids[i1].pmkid[16] */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmePmkidCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmePmkidCfm *primitive = (CsrWifiSmePmkidCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->action);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->getPmkidsCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getPmkidsCount; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->getPmkids[i1].bssid.a, ((CsrUint16) (6)));
+            CsrMemCpySer(ptr, len, (const void *) primitive->getPmkids[i1].pmkid, ((CsrUint16) (16)));
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmePmkidCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmePmkidCfm *primitive = (CsrWifiSmePmkidCfm *) CsrPmemAlloc(sizeof(CsrWifiSmePmkidCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->action, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->getPmkidsCount, buffer, &offset);
+    primitive->getPmkids = NULL;
+    if (primitive->getPmkidsCount)
+    {
+        primitive->getPmkids = (CsrWifiSmePmkid *)CsrPmemAlloc(sizeof(CsrWifiSmePmkid) * primitive->getPmkidsCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->getPmkidsCount; i1++)
+        {
+            CsrMemCpyDes(primitive->getPmkids[i1].bssid.a, buffer, &offset, ((CsrUint16) (6)));
+            CsrMemCpyDes(primitive->getPmkids[i1].pmkid, buffer, &offset, ((CsrUint16) (16)));
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmePmkidCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmePmkidCfm *primitive = (CsrWifiSmePmkidCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->getPmkids);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmePowerConfigGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrWifiSmePowerSaveLevel primitive->powerConfig.powerSaveLevel */
+    bufferSize += 2; /* CsrUint16 primitive->powerConfig.listenIntervalTu */
+    bufferSize += 1; /* CsrBool primitive->powerConfig.rxDtims */
+    bufferSize += 1; /* CsrWifiSmeD3AutoScanMode primitive->powerConfig.d3AutoScanMode */
+    bufferSize += 1; /* CsrUint8 primitive->powerConfig.clientTrafficWindow */
+    bufferSize += 1; /* CsrBool primitive->powerConfig.opportunisticPowerSave */
+    bufferSize += 1; /* CsrBool primitive->powerConfig.noticeOfAbsence */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmePowerConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmePowerConfigGetCfm *primitive = (CsrWifiSmePowerConfigGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.powerSaveLevel);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->powerConfig.listenIntervalTu);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.rxDtims);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.d3AutoScanMode);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.clientTrafficWindow);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.opportunisticPowerSave);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->powerConfig.noticeOfAbsence);
+    return(ptr);
+}
+
+
+void* CsrWifiSmePowerConfigGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmePowerConfigGetCfm *primitive = (CsrWifiSmePowerConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmePowerConfigGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.powerSaveLevel, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->powerConfig.listenIntervalTu, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.rxDtims, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.d3AutoScanMode, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.clientTrafficWindow, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.opportunisticPowerSave, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->powerConfig.noticeOfAbsence, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeRegulatoryDomainInfoGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrBool primitive->regDomInfo.dot11MultiDomainCapabilityImplemented */
+    bufferSize += 1; /* CsrBool primitive->regDomInfo.dot11MultiDomainCapabilityEnabled */
+    bufferSize += 1; /* CsrWifiSmeRegulatoryDomain primitive->regDomInfo.currentRegulatoryDomain */
+    bufferSize += 2; /* CsrUint8 primitive->regDomInfo.currentCountryCode[2] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeRegulatoryDomainInfoGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeRegulatoryDomainInfoGetCfm *primitive = (CsrWifiSmeRegulatoryDomainInfoGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->regDomInfo.dot11MultiDomainCapabilityImplemented);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->regDomInfo.dot11MultiDomainCapabilityEnabled);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->regDomInfo.currentRegulatoryDomain);
+    CsrMemCpySer(ptr, len, (const void *) primitive->regDomInfo.currentCountryCode, ((CsrUint16) (2)));
+    return(ptr);
+}
+
+
+void* CsrWifiSmeRegulatoryDomainInfoGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeRegulatoryDomainInfoGetCfm *primitive = (CsrWifiSmeRegulatoryDomainInfoGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeRegulatoryDomainInfoGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->regDomInfo.dot11MultiDomainCapabilityImplemented, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->regDomInfo.dot11MultiDomainCapabilityEnabled, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->regDomInfo.currentRegulatoryDomain, buffer, &offset);
+    CsrMemCpyDes(primitive->regDomInfo.currentCountryCode, buffer, &offset, ((CsrUint16) (2)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeRoamCompleteIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeRoamCompleteIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeRoamCompleteInd *primitive = (CsrWifiSmeRoamCompleteInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeRoamCompleteIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeRoamCompleteInd *primitive = (CsrWifiSmeRoamCompleteInd *) CsrPmemAlloc(sizeof(CsrWifiSmeRoamCompleteInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeRoamStartIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 1; /* CsrWifiSmeRoamReason primitive->roamReason */
+    bufferSize += 2; /* CsrWifiSmeIEEE80211Reason primitive->reason80211 */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeRoamStartIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeRoamStartInd *primitive = (CsrWifiSmeRoamStartInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->roamReason);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->reason80211);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeRoamStartIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeRoamStartInd *primitive = (CsrWifiSmeRoamStartInd *) CsrPmemAlloc(sizeof(CsrWifiSmeRoamStartInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->roamReason, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->reason80211, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeRoamingConfigGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 72) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            bufferSize += 2; /* CsrInt16 primitive->roamingConfig.roamingBands[i2].rssiHighThreshold */
+            bufferSize += 2; /* CsrInt16 primitive->roamingConfig.roamingBands[i2].rssiLowThreshold */
+            bufferSize += 2; /* CsrInt16 primitive->roamingConfig.roamingBands[i2].snrHighThreshold */
+            bufferSize += 2; /* CsrInt16 primitive->roamingConfig.roamingBands[i2].snrLowThreshold */
+        }
+    }
+    bufferSize += 1;         /* CsrBool primitive->roamingConfig.disableSmoothRoaming */
+    bufferSize += 1;         /* CsrBool primitive->roamingConfig.disableRoamScans */
+    bufferSize += 1;         /* CsrUint8 primitive->roamingConfig.reconnectLimit */
+    bufferSize += 2;         /* CsrUint16 primitive->roamingConfig.reconnectLimitIntervalMs */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].intervalSeconds */
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].validitySeconds */
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].minActiveChannelTimeTu */
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].maxActiveChannelTimeTu */
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].minPassiveChannelTimeTu */
+            bufferSize += 2; /* CsrUint16 primitive->roamingConfig.roamScanCfg[i2].maxPassiveChannelTimeTu */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeRoamingConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeRoamingConfigGetCfm *primitive = (CsrWifiSmeRoamingConfigGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamingBands[i2].rssiHighThreshold);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamingBands[i2].rssiLowThreshold);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamingBands[i2].snrHighThreshold);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamingBands[i2].snrLowThreshold);
+        }
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->roamingConfig.disableSmoothRoaming);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->roamingConfig.disableRoamScans);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->roamingConfig.reconnectLimit);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.reconnectLimitIntervalMs);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].intervalSeconds);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].validitySeconds);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].minActiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].maxActiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].minPassiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->roamingConfig.roamScanCfg[i2].maxPassiveChannelTimeTu);
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeRoamingConfigGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeRoamingConfigGetCfm *primitive = (CsrWifiSmeRoamingConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeRoamingConfigGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamingBands[i2].rssiHighThreshold, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamingBands[i2].rssiLowThreshold, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamingBands[i2].snrHighThreshold, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamingBands[i2].snrLowThreshold, buffer, &offset);
+        }
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->roamingConfig.disableSmoothRoaming, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->roamingConfig.disableRoamScans, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->roamingConfig.reconnectLimit, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.reconnectLimitIntervalMs, buffer, &offset);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 3; i2++)
+        {
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].intervalSeconds, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].validitySeconds, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].minActiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].maxActiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].minPassiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->roamingConfig.roamScanCfg[i2].maxPassiveChannelTimeTu, buffer, &offset);
+        }
+    }
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeRoamingConfigSetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeRoamingConfigSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeRoamingConfigSetCfm *primitive = (CsrWifiSmeRoamingConfigSetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeRoamingConfigSetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeRoamingConfigSetCfm *primitive = (CsrWifiSmeRoamingConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeRoamingConfigSetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeScanConfigGetCfmSizeof(void *msg)
+{
+    CsrWifiSmeScanConfigGetCfm *primitive = (CsrWifiSmeScanConfigGetCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 65) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].intervalSeconds */
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].validitySeconds */
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].minActiveChannelTimeTu */
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].maxActiveChannelTimeTu */
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].minPassiveChannelTimeTu */
+            bufferSize += 2;                                     /* CsrUint16 primitive->scanConfig.scanCfg[i2].maxPassiveChannelTimeTu */
+        }
+    }
+    bufferSize += 1;                                             /* CsrBool primitive->scanConfig.disableAutonomousScans */
+    bufferSize += 2;                                             /* CsrUint16 primitive->scanConfig.maxResults */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.highRssiThreshold */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.lowRssiThreshold */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.deltaRssiThreshold */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.highSnrThreshold */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.lowSnrThreshold */
+    bufferSize += 1;                                             /* CsrInt8 primitive->scanConfig.deltaSnrThreshold */
+    bufferSize += 2;                                             /* CsrUint16 primitive->scanConfig.passiveChannelListCount */
+    bufferSize += primitive->scanConfig.passiveChannelListCount; /* CsrUint8 primitive->scanConfig.passiveChannelList */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeScanConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeScanConfigGetCfm *primitive = (CsrWifiSmeScanConfigGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].intervalSeconds);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].validitySeconds);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].minActiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].maxActiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].minPassiveChannelTimeTu);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.scanCfg[i2].maxPassiveChannelTimeTu);
+        }
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.disableAutonomousScans);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.maxResults);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.highRssiThreshold);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.lowRssiThreshold);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.deltaRssiThreshold);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.highSnrThreshold);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.lowSnrThreshold);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanConfig.deltaSnrThreshold);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanConfig.passiveChannelListCount);
+    if (primitive->scanConfig.passiveChannelListCount)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->scanConfig.passiveChannelList, ((CsrUint16) (primitive->scanConfig.passiveChannelListCount)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeScanConfigGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeScanConfigGetCfm *primitive = (CsrWifiSmeScanConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeScanConfigGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < 4; i2++)
+        {
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].intervalSeconds, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].validitySeconds, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].minActiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].maxActiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].minPassiveChannelTimeTu, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanConfig.scanCfg[i2].maxPassiveChannelTimeTu, buffer, &offset);
+        }
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.disableAutonomousScans, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->scanConfig.maxResults, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.highRssiThreshold, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.lowRssiThreshold, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.deltaRssiThreshold, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.highSnrThreshold, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.lowSnrThreshold, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->scanConfig.deltaSnrThreshold, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->scanConfig.passiveChannelListCount, buffer, &offset);
+    if (primitive->scanConfig.passiveChannelListCount)
+    {
+        primitive->scanConfig.passiveChannelList = (CsrUint8 *)CsrPmemAlloc(primitive->scanConfig.passiveChannelListCount);
+        CsrMemCpyDes(primitive->scanConfig.passiveChannelList, buffer, &offset, ((CsrUint16) (primitive->scanConfig.passiveChannelListCount)));
+    }
+    else
+    {
+        primitive->scanConfig.passiveChannelList = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeScanConfigGetCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeScanConfigGetCfm *primitive = (CsrWifiSmeScanConfigGetCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->scanConfig.passiveChannelList);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeScanResultIndSizeof(void *msg)
+{
+    CsrWifiSmeScanResultInd *primitive = (CsrWifiSmeScanResultInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 149) */
+    bufferSize += 32;                                          /* CsrUint8 primitive->result.ssid.ssid[32] */
+    bufferSize += 1;                                           /* CsrUint8 primitive->result.ssid.length */
+    bufferSize += 6;                                           /* CsrUint8 primitive->result.bssid.a[6] */
+    bufferSize += 2;                                           /* CsrInt16 primitive->result.rssi */
+    bufferSize += 2;                                           /* CsrInt16 primitive->result.snr */
+    bufferSize += 1;                                           /* CsrWifiSmeRadioIF primitive->result.ifIndex */
+    bufferSize += 2;                                           /* CsrUint16 primitive->result.beaconPeriodTu */
+    bufferSize += 8;                                           /* CsrUint8 primitive->result.timeStamp.data[8] */
+    bufferSize += 8;                                           /* CsrUint8 primitive->result.localTime.data[8] */
+    bufferSize += 2;                                           /* CsrUint16 primitive->result.channelFrequency */
+    bufferSize += 2;                                           /* CsrUint16 primitive->result.capabilityInformation */
+    bufferSize += 1;                                           /* CsrUint8 primitive->result.channelNumber */
+    bufferSize += 1;                                           /* CsrWifiSmeBasicUsability primitive->result.usability */
+    bufferSize += 1;                                           /* CsrWifiSmeBssType primitive->result.bssType */
+    bufferSize += 2;                                           /* CsrUint16 primitive->result.informationElementsLength */
+    bufferSize += primitive->result.informationElementsLength; /* CsrUint8 primitive->result.informationElements */
+    bufferSize += 1;                                           /* CsrWifiSmeP2pRole primitive->result.p2pDeviceRole */
+    switch (primitive->result.p2pDeviceRole)
+    {
+        case CSR_WIFI_SME_P2P_ROLE_CLI:
+            bufferSize += 1; /* CsrUint8 primitive->result.deviceInfo.reservedCli.empty */
+            break;
+        case CSR_WIFI_SME_P2P_ROLE_GO:
+            bufferSize += 1; /* CsrWifiSmeP2pGroupCapabilityMask primitive->result.deviceInfo.groupInfo.groupCapability */
+            bufferSize += 6; /* CsrUint8 primitive->result.deviceInfo.groupInfo.p2pDeviceAddress.a[6] */
+            bufferSize += 1; /* CsrUint8 primitive->result.deviceInfo.groupInfo.p2pClientInfoCount */
+            {
+                CsrUint16 i4;
+                for (i4 = 0; i4 < primitive->result.deviceInfo.groupInfo.p2pClientInfoCount; i4++)
+                {
+                    bufferSize += 6; /* CsrUint8 primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].p2PClientInterfaceAddress.a[6] */
+                    bufferSize += 6; /* CsrUint8 primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceAddress.a[6] */
+                    bufferSize += 2; /* CsrWifiSmeWpsConfigTypeMask primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.configMethods */
+                    bufferSize += 1; /* CsrWifiSmeP2pCapabilityMask primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.p2PDeviceCap */
+                    bufferSize += 8; /* CsrUint8 primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.primDeviceType.deviceDetails[8] */
+                    bufferSize += 1; /* CsrUint8 primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount */
+                    {
+                        CsrUint16 i6;
+                        for (i6 = 0; i6 < primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount; i6++)
+                        {
+                            bufferSize += 8; /* CsrUint8 primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType[i6].deviceDetails[8] */
+                        }
+                    }
+                    bufferSize += 32;        /* CsrUint8 primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceName[32] */
+                    bufferSize += 1;         /* CsrUint8 primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceNameLength */
+                }
+            }
+            break;
+        case CSR_WIFI_SME_P2P_ROLE_NONE:
+            bufferSize += 1; /* CsrUint8 primitive->result.deviceInfo.reservedNone.empty */
+            break;
+        case CSR_WIFI_SME_P2P_ROLE_STANDALONE:
+            bufferSize += 6; /* CsrUint8 primitive->result.deviceInfo.standalonedevInfo.deviceAddress.a[6] */
+            bufferSize += 2; /* CsrWifiSmeWpsConfigTypeMask primitive->result.deviceInfo.standalonedevInfo.configMethods */
+            bufferSize += 1; /* CsrWifiSmeP2pCapabilityMask primitive->result.deviceInfo.standalonedevInfo.p2PDeviceCap */
+            bufferSize += 8; /* CsrUint8 primitive->result.deviceInfo.standalonedevInfo.primDeviceType.deviceDetails[8] */
+            bufferSize += 1; /* CsrUint8 primitive->result.deviceInfo.standalonedevInfo.secondaryDeviceTypeCount */
+            {
+                CsrUint16 i4;
+                for (i4 = 0; i4 < primitive->result.deviceInfo.standalonedevInfo.secondaryDeviceTypeCount; i4++)
+                {
+                    bufferSize += 8; /* CsrUint8 primitive->result.deviceInfo.standalonedevInfo.secDeviceType[i4].deviceDetails[8] */
+                }
+            }
+            bufferSize += 32;        /* CsrUint8 primitive->result.deviceInfo.standalonedevInfo.deviceName[32] */
+            bufferSize += 1;         /* CsrUint8 primitive->result.deviceInfo.standalonedevInfo.deviceNameLength */
+            break;
+        default:
+            break;
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeScanResultIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeScanResultInd *primitive = (CsrWifiSmeScanResultInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrMemCpySer(ptr, len, (const void *) primitive->result.ssid.ssid, ((CsrUint16) (32)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.ssid.length);
+    CsrMemCpySer(ptr, len, (const void *) primitive->result.bssid.a, ((CsrUint16) (6)));
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result.rssi);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result.snr);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.ifIndex);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result.beaconPeriodTu);
+    CsrMemCpySer(ptr, len, (const void *) primitive->result.timeStamp.data, ((CsrUint16) (8)));
+    CsrMemCpySer(ptr, len, (const void *) primitive->result.localTime.data, ((CsrUint16) (8)));
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result.channelFrequency);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result.capabilityInformation);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.channelNumber);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.usability);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.bssType);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result.informationElementsLength);
+    if (primitive->result.informationElementsLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->result.informationElements, ((CsrUint16) (primitive->result.informationElementsLength)));
+    }
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.p2pDeviceRole);
+    switch (primitive->result.p2pDeviceRole)
+    {
+        case CSR_WIFI_SME_P2P_ROLE_CLI:
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.deviceInfo.reservedCli.empty);
+            break;
+        case CSR_WIFI_SME_P2P_ROLE_GO:
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.deviceInfo.groupInfo.groupCapability);
+            CsrMemCpySer(ptr, len, (const void *) primitive->result.deviceInfo.groupInfo.p2pDeviceAddress.a, ((CsrUint16) (6)));
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.deviceInfo.groupInfo.p2pClientInfoCount);
+            {
+                CsrUint16 i4;
+                for (i4 = 0; i4 < primitive->result.deviceInfo.groupInfo.p2pClientInfoCount; i4++)
+                {
+                    CsrMemCpySer(ptr, len, (const void *) primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].p2PClientInterfaceAddress.a, ((CsrUint16) (6)));
+                    CsrMemCpySer(ptr, len, (const void *) primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceAddress.a, ((CsrUint16) (6)));
+                    CsrUint16Ser(ptr, len, (CsrUint16) primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.configMethods);
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.p2PDeviceCap);
+                    CsrMemCpySer(ptr, len, (const void *) primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.primDeviceType.deviceDetails, ((CsrUint16) (8)));
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount);
+                    {
+                        CsrUint16 i6;
+                        for (i6 = 0; i6 < primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount; i6++)
+                        {
+                            CsrMemCpySer(ptr, len, (const void *) primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType[i6].deviceDetails, ((CsrUint16) (8)));
+                        }
+                    }
+                    CsrMemCpySer(ptr, len, (const void *) primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceName, ((CsrUint16) (32)));
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceNameLength);
+                }
+            }
+            break;
+        case CSR_WIFI_SME_P2P_ROLE_NONE:
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.deviceInfo.reservedNone.empty);
+            break;
+        case CSR_WIFI_SME_P2P_ROLE_STANDALONE:
+            CsrMemCpySer(ptr, len, (const void *) primitive->result.deviceInfo.standalonedevInfo.deviceAddress.a, ((CsrUint16) (6)));
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->result.deviceInfo.standalonedevInfo.configMethods);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.deviceInfo.standalonedevInfo.p2PDeviceCap);
+            CsrMemCpySer(ptr, len, (const void *) primitive->result.deviceInfo.standalonedevInfo.primDeviceType.deviceDetails, ((CsrUint16) (8)));
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.deviceInfo.standalonedevInfo.secondaryDeviceTypeCount);
+            {
+                CsrUint16 i4;
+                for (i4 = 0; i4 < primitive->result.deviceInfo.standalonedevInfo.secondaryDeviceTypeCount; i4++)
+                {
+                    CsrMemCpySer(ptr, len, (const void *) primitive->result.deviceInfo.standalonedevInfo.secDeviceType[i4].deviceDetails, ((CsrUint16) (8)));
+                }
+            }
+            CsrMemCpySer(ptr, len, (const void *) primitive->result.deviceInfo.standalonedevInfo.deviceName, ((CsrUint16) (32)));
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->result.deviceInfo.standalonedevInfo.deviceNameLength);
+            break;
+        default:
+            break;
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeScanResultIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeScanResultInd *primitive = (CsrWifiSmeScanResultInd *) CsrPmemAlloc(sizeof(CsrWifiSmeScanResultInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrMemCpyDes(primitive->result.ssid.ssid, buffer, &offset, ((CsrUint16) (32)));
+    CsrUint8Des((CsrUint8 *) &primitive->result.ssid.length, buffer, &offset);
+    CsrMemCpyDes(primitive->result.bssid.a, buffer, &offset, ((CsrUint16) (6)));
+    CsrUint16Des((CsrUint16 *) &primitive->result.rssi, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->result.snr, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->result.ifIndex, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->result.beaconPeriodTu, buffer, &offset);
+    CsrMemCpyDes(primitive->result.timeStamp.data, buffer, &offset, ((CsrUint16) (8)));
+    CsrMemCpyDes(primitive->result.localTime.data, buffer, &offset, ((CsrUint16) (8)));
+    CsrUint16Des((CsrUint16 *) &primitive->result.channelFrequency, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->result.capabilityInformation, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->result.channelNumber, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->result.usability, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->result.bssType, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->result.informationElementsLength, buffer, &offset);
+    if (primitive->result.informationElementsLength)
+    {
+        primitive->result.informationElements = (CsrUint8 *)CsrPmemAlloc(primitive->result.informationElementsLength);
+        CsrMemCpyDes(primitive->result.informationElements, buffer, &offset, ((CsrUint16) (primitive->result.informationElementsLength)));
+    }
+    else
+    {
+        primitive->result.informationElements = NULL;
+    }
+    CsrUint8Des((CsrUint8 *) &primitive->result.p2pDeviceRole, buffer, &offset);
+    switch (primitive->result.p2pDeviceRole)
+    {
+        case CSR_WIFI_SME_P2P_ROLE_CLI:
+            CsrUint8Des((CsrUint8 *) &primitive->result.deviceInfo.reservedCli.empty, buffer, &offset);
+            break;
+        case CSR_WIFI_SME_P2P_ROLE_GO:
+            CsrUint8Des((CsrUint8 *) &primitive->result.deviceInfo.groupInfo.groupCapability, buffer, &offset);
+            CsrMemCpyDes(primitive->result.deviceInfo.groupInfo.p2pDeviceAddress.a, buffer, &offset, ((CsrUint16) (6)));
+            CsrUint8Des((CsrUint8 *) &primitive->result.deviceInfo.groupInfo.p2pClientInfoCount, buffer, &offset);
+            primitive->result.deviceInfo.groupInfo.p2PClientInfo = NULL;
+            if (primitive->result.deviceInfo.groupInfo.p2pClientInfoCount)
+            {
+                primitive->result.deviceInfo.groupInfo.p2PClientInfo = (CsrWifiSmeP2pClientInfoType *)CsrPmemAlloc(sizeof(CsrWifiSmeP2pClientInfoType) * primitive->result.deviceInfo.groupInfo.p2pClientInfoCount);
+            }
+            {
+                CsrUint16 i4;
+                for (i4 = 0; i4 < primitive->result.deviceInfo.groupInfo.p2pClientInfoCount; i4++)
+                {
+                    CsrMemCpyDes(primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].p2PClientInterfaceAddress.a, buffer, &offset, ((CsrUint16) (6)));
+                    CsrMemCpyDes(primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceAddress.a, buffer, &offset, ((CsrUint16) (6)));
+                    CsrUint16Des((CsrUint16 *) &primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.configMethods, buffer, &offset);
+                    CsrUint8Des((CsrUint8 *) &primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.p2PDeviceCap, buffer, &offset);
+                    CsrMemCpyDes(primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.primDeviceType.deviceDetails, buffer, &offset, ((CsrUint16) (8)));
+                    CsrUint8Des((CsrUint8 *) &primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount, buffer, &offset);
+                    primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType = NULL;
+                    if (primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount)
+                    {
+                        primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType = (CsrWifiSmeWpsDeviceType *)CsrPmemAlloc(sizeof(CsrWifiSmeWpsDeviceType) * primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount);
+                    }
+                    {
+                        CsrUint16 i6;
+                        for (i6 = 0; i6 < primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount; i6++)
+                        {
+                            CsrMemCpyDes(primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType[i6].deviceDetails, buffer, &offset, ((CsrUint16) (8)));
+                        }
+                    }
+                    CsrMemCpyDes(primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceName, buffer, &offset, ((CsrUint16) (32)));
+                    CsrUint8Des((CsrUint8 *) &primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceNameLength, buffer, &offset);
+                }
+            }
+            break;
+        case CSR_WIFI_SME_P2P_ROLE_NONE:
+            CsrUint8Des((CsrUint8 *) &primitive->result.deviceInfo.reservedNone.empty, buffer, &offset);
+            break;
+        case CSR_WIFI_SME_P2P_ROLE_STANDALONE:
+            CsrMemCpyDes(primitive->result.deviceInfo.standalonedevInfo.deviceAddress.a, buffer, &offset, ((CsrUint16) (6)));
+            CsrUint16Des((CsrUint16 *) &primitive->result.deviceInfo.standalonedevInfo.configMethods, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->result.deviceInfo.standalonedevInfo.p2PDeviceCap, buffer, &offset);
+            CsrMemCpyDes(primitive->result.deviceInfo.standalonedevInfo.primDeviceType.deviceDetails, buffer, &offset, ((CsrUint16) (8)));
+            CsrUint8Des((CsrUint8 *) &primitive->result.deviceInfo.standalonedevInfo.secondaryDeviceTypeCount, buffer, &offset);
+            primitive->result.deviceInfo.standalonedevInfo.secDeviceType = NULL;
+            if (primitive->result.deviceInfo.standalonedevInfo.secondaryDeviceTypeCount)
+            {
+                primitive->result.deviceInfo.standalonedevInfo.secDeviceType = (CsrWifiSmeWpsDeviceType *)CsrPmemAlloc(sizeof(CsrWifiSmeWpsDeviceType) * primitive->result.deviceInfo.standalonedevInfo.secondaryDeviceTypeCount);
+            }
+            {
+                CsrUint16 i4;
+                for (i4 = 0; i4 < primitive->result.deviceInfo.standalonedevInfo.secondaryDeviceTypeCount; i4++)
+                {
+                    CsrMemCpyDes(primitive->result.deviceInfo.standalonedevInfo.secDeviceType[i4].deviceDetails, buffer, &offset, ((CsrUint16) (8)));
+                }
+            }
+            CsrMemCpyDes(primitive->result.deviceInfo.standalonedevInfo.deviceName, buffer, &offset, ((CsrUint16) (32)));
+            CsrUint8Des((CsrUint8 *) &primitive->result.deviceInfo.standalonedevInfo.deviceNameLength, buffer, &offset);
+            break;
+        default:
+            break;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeScanResultIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeScanResultInd *primitive = (CsrWifiSmeScanResultInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->result.informationElements);
+    switch (primitive->result.p2pDeviceRole)
+    {
+        case CSR_WIFI_SME_P2P_ROLE_GO:
+        {
+            CsrUint16 i4;
+            for (i4 = 0; i4 < primitive->result.deviceInfo.groupInfo.p2pClientInfoCount; i4++)
+            {
+                CsrPmemFree(primitive->result.deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType);
+            }
+        }
+            CsrPmemFree(primitive->result.deviceInfo.groupInfo.p2PClientInfo);
+            break;
+        case CSR_WIFI_SME_P2P_ROLE_STANDALONE:
+            CsrPmemFree(primitive->result.deviceInfo.standalonedevInfo.secDeviceType);
+            break;
+        default:
+            break;
+    }
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeScanResultsGetCfmSizeof(void *msg)
+{
+    CsrWifiSmeScanResultsGetCfm *primitive = (CsrWifiSmeScanResultsGetCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 153) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 2; /* CsrUint16 primitive->scanResultsCount */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->scanResultsCount; i1++)
+        {
+            bufferSize += 32;                                                   /* CsrUint8 primitive->scanResults[i1].ssid.ssid[32] */
+            bufferSize += 1;                                                    /* CsrUint8 primitive->scanResults[i1].ssid.length */
+            bufferSize += 6;                                                    /* CsrUint8 primitive->scanResults[i1].bssid.a[6] */
+            bufferSize += 2;                                                    /* CsrInt16 primitive->scanResults[i1].rssi */
+            bufferSize += 2;                                                    /* CsrInt16 primitive->scanResults[i1].snr */
+            bufferSize += 1;                                                    /* CsrWifiSmeRadioIF primitive->scanResults[i1].ifIndex */
+            bufferSize += 2;                                                    /* CsrUint16 primitive->scanResults[i1].beaconPeriodTu */
+            bufferSize += 8;                                                    /* CsrUint8 primitive->scanResults[i1].timeStamp.data[8] */
+            bufferSize += 8;                                                    /* CsrUint8 primitive->scanResults[i1].localTime.data[8] */
+            bufferSize += 2;                                                    /* CsrUint16 primitive->scanResults[i1].channelFrequency */
+            bufferSize += 2;                                                    /* CsrUint16 primitive->scanResults[i1].capabilityInformation */
+            bufferSize += 1;                                                    /* CsrUint8 primitive->scanResults[i1].channelNumber */
+            bufferSize += 1;                                                    /* CsrWifiSmeBasicUsability primitive->scanResults[i1].usability */
+            bufferSize += 1;                                                    /* CsrWifiSmeBssType primitive->scanResults[i1].bssType */
+            bufferSize += 2;                                                    /* CsrUint16 primitive->scanResults[i1].informationElementsLength */
+            bufferSize += primitive->scanResults[i1].informationElementsLength; /* CsrUint8 primitive->scanResults[i1].informationElements */
+            bufferSize += 1;                                                    /* CsrWifiSmeP2pRole primitive->scanResults[i1].p2pDeviceRole */
+            switch (primitive->scanResults[i1].p2pDeviceRole)
+            {
+                case CSR_WIFI_SME_P2P_ROLE_CLI:
+                    bufferSize += 1; /* CsrUint8 primitive->scanResults[i1].deviceInfo.reservedCli.empty */
+                    break;
+                case CSR_WIFI_SME_P2P_ROLE_GO:
+                    bufferSize += 1; /* CsrWifiSmeP2pGroupCapabilityMask primitive->scanResults[i1].deviceInfo.groupInfo.groupCapability */
+                    bufferSize += 6; /* CsrUint8 primitive->scanResults[i1].deviceInfo.groupInfo.p2pDeviceAddress.a[6] */
+                    bufferSize += 1; /* CsrUint8 primitive->scanResults[i1].deviceInfo.groupInfo.p2pClientInfoCount */
+                    {
+                        CsrUint16 i4;
+                        for (i4 = 0; i4 < primitive->scanResults[i1].deviceInfo.groupInfo.p2pClientInfoCount; i4++)
+                        {
+                            bufferSize += 6; /* CsrUint8 primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].p2PClientInterfaceAddress.a[6] */
+                            bufferSize += 6; /* CsrUint8 primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceAddress.a[6] */
+                            bufferSize += 2; /* CsrWifiSmeWpsConfigTypeMask primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.configMethods */
+                            bufferSize += 1; /* CsrWifiSmeP2pCapabilityMask primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.p2PDeviceCap */
+                            bufferSize += 8; /* CsrUint8 primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.primDeviceType.deviceDetails[8] */
+                            bufferSize += 1; /* CsrUint8 primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount */
+                            {
+                                CsrUint16 i6;
+                                for (i6 = 0; i6 < primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount; i6++)
+                                {
+                                    bufferSize += 8; /* CsrUint8 primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType[i6].deviceDetails[8] */
+                                }
+                            }
+                            bufferSize += 32;        /* CsrUint8 primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceName[32] */
+                            bufferSize += 1;         /* CsrUint8 primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceNameLength */
+                        }
+                    }
+                    break;
+                case CSR_WIFI_SME_P2P_ROLE_NONE:
+                    bufferSize += 1; /* CsrUint8 primitive->scanResults[i1].deviceInfo.reservedNone.empty */
+                    break;
+                case CSR_WIFI_SME_P2P_ROLE_STANDALONE:
+                    bufferSize += 6; /* CsrUint8 primitive->scanResults[i1].deviceInfo.standalonedevInfo.deviceAddress.a[6] */
+                    bufferSize += 2; /* CsrWifiSmeWpsConfigTypeMask primitive->scanResults[i1].deviceInfo.standalonedevInfo.configMethods */
+                    bufferSize += 1; /* CsrWifiSmeP2pCapabilityMask primitive->scanResults[i1].deviceInfo.standalonedevInfo.p2PDeviceCap */
+                    bufferSize += 8; /* CsrUint8 primitive->scanResults[i1].deviceInfo.standalonedevInfo.primDeviceType.deviceDetails[8] */
+                    bufferSize += 1; /* CsrUint8 primitive->scanResults[i1].deviceInfo.standalonedevInfo.secondaryDeviceTypeCount */
+                    {
+                        CsrUint16 i4;
+                        for (i4 = 0; i4 < primitive->scanResults[i1].deviceInfo.standalonedevInfo.secondaryDeviceTypeCount; i4++)
+                        {
+                            bufferSize += 8; /* CsrUint8 primitive->scanResults[i1].deviceInfo.standalonedevInfo.secDeviceType[i4].deviceDetails[8] */
+                        }
+                    }
+                    bufferSize += 32;        /* CsrUint8 primitive->scanResults[i1].deviceInfo.standalonedevInfo.deviceName[32] */
+                    bufferSize += 1;         /* CsrUint8 primitive->scanResults[i1].deviceInfo.standalonedevInfo.deviceNameLength */
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeScanResultsGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeScanResultsGetCfm *primitive = (CsrWifiSmeScanResultsGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanResultsCount);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->scanResultsCount; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].ssid.ssid, ((CsrUint16) (32)));
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].ssid.length);
+            CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].bssid.a, ((CsrUint16) (6)));
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanResults[i1].rssi);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanResults[i1].snr);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].ifIndex);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanResults[i1].beaconPeriodTu);
+            CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].timeStamp.data, ((CsrUint16) (8)));
+            CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].localTime.data, ((CsrUint16) (8)));
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanResults[i1].channelFrequency);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanResults[i1].capabilityInformation);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].channelNumber);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].usability);
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].bssType);
+            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanResults[i1].informationElementsLength);
+            if (primitive->scanResults[i1].informationElementsLength)
+            {
+                CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].informationElements, ((CsrUint16) (primitive->scanResults[i1].informationElementsLength)));
+            }
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].p2pDeviceRole);
+            switch (primitive->scanResults[i1].p2pDeviceRole)
+            {
+                case CSR_WIFI_SME_P2P_ROLE_CLI:
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].deviceInfo.reservedCli.empty);
+                    break;
+                case CSR_WIFI_SME_P2P_ROLE_GO:
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].deviceInfo.groupInfo.groupCapability);
+                    CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].deviceInfo.groupInfo.p2pDeviceAddress.a, ((CsrUint16) (6)));
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].deviceInfo.groupInfo.p2pClientInfoCount);
+                    {
+                        CsrUint16 i4;
+                        for (i4 = 0; i4 < primitive->scanResults[i1].deviceInfo.groupInfo.p2pClientInfoCount; i4++)
+                        {
+                            CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].p2PClientInterfaceAddress.a, ((CsrUint16) (6)));
+                            CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceAddress.a, ((CsrUint16) (6)));
+                            CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.configMethods);
+                            CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.p2PDeviceCap);
+                            CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.primDeviceType.deviceDetails, ((CsrUint16) (8)));
+                            CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount);
+                            {
+                                CsrUint16 i6;
+                                for (i6 = 0; i6 < primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount; i6++)
+                                {
+                                    CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType[i6].deviceDetails, ((CsrUint16) (8)));
+                                }
+                            }
+                            CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceName, ((CsrUint16) (32)));
+                            CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceNameLength);
+                        }
+                    }
+                    break;
+                case CSR_WIFI_SME_P2P_ROLE_NONE:
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].deviceInfo.reservedNone.empty);
+                    break;
+                case CSR_WIFI_SME_P2P_ROLE_STANDALONE:
+                    CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].deviceInfo.standalonedevInfo.deviceAddress.a, ((CsrUint16) (6)));
+                    CsrUint16Ser(ptr, len, (CsrUint16) primitive->scanResults[i1].deviceInfo.standalonedevInfo.configMethods);
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].deviceInfo.standalonedevInfo.p2PDeviceCap);
+                    CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].deviceInfo.standalonedevInfo.primDeviceType.deviceDetails, ((CsrUint16) (8)));
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].deviceInfo.standalonedevInfo.secondaryDeviceTypeCount);
+                    {
+                        CsrUint16 i4;
+                        for (i4 = 0; i4 < primitive->scanResults[i1].deviceInfo.standalonedevInfo.secondaryDeviceTypeCount; i4++)
+                        {
+                            CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].deviceInfo.standalonedevInfo.secDeviceType[i4].deviceDetails, ((CsrUint16) (8)));
+                        }
+                    }
+                    CsrMemCpySer(ptr, len, (const void *) primitive->scanResults[i1].deviceInfo.standalonedevInfo.deviceName, ((CsrUint16) (32)));
+                    CsrUint8Ser(ptr, len, (CsrUint8) primitive->scanResults[i1].deviceInfo.standalonedevInfo.deviceNameLength);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeScanResultsGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeScanResultsGetCfm *primitive = (CsrWifiSmeScanResultsGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeScanResultsGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->scanResultsCount, buffer, &offset);
+    primitive->scanResults = NULL;
+    if (primitive->scanResultsCount)
+    {
+        primitive->scanResults = (CsrWifiSmeScanResult *)CsrPmemAlloc(sizeof(CsrWifiSmeScanResult) * primitive->scanResultsCount);
+    }
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->scanResultsCount; i1++)
+        {
+            CsrMemCpyDes(primitive->scanResults[i1].ssid.ssid, buffer, &offset, ((CsrUint16) (32)));
+            CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].ssid.length, buffer, &offset);
+            CsrMemCpyDes(primitive->scanResults[i1].bssid.a, buffer, &offset, ((CsrUint16) (6)));
+            CsrUint16Des((CsrUint16 *) &primitive->scanResults[i1].rssi, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanResults[i1].snr, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].ifIndex, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanResults[i1].beaconPeriodTu, buffer, &offset);
+            CsrMemCpyDes(primitive->scanResults[i1].timeStamp.data, buffer, &offset, ((CsrUint16) (8)));
+            CsrMemCpyDes(primitive->scanResults[i1].localTime.data, buffer, &offset, ((CsrUint16) (8)));
+            CsrUint16Des((CsrUint16 *) &primitive->scanResults[i1].channelFrequency, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanResults[i1].capabilityInformation, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].channelNumber, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].usability, buffer, &offset);
+            CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].bssType, buffer, &offset);
+            CsrUint16Des((CsrUint16 *) &primitive->scanResults[i1].informationElementsLength, buffer, &offset);
+            if (primitive->scanResults[i1].informationElementsLength)
+            {
+                primitive->scanResults[i1].informationElements = (CsrUint8 *)CsrPmemAlloc(primitive->scanResults[i1].informationElementsLength);
+                CsrMemCpyDes(primitive->scanResults[i1].informationElements, buffer, &offset, ((CsrUint16) (primitive->scanResults[i1].informationElementsLength)));
+            }
+            else
+            {
+                primitive->scanResults[i1].informationElements = NULL;
+            }
+            CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].p2pDeviceRole, buffer, &offset);
+            switch (primitive->scanResults[i1].p2pDeviceRole)
+            {
+                case CSR_WIFI_SME_P2P_ROLE_CLI:
+                    CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].deviceInfo.reservedCli.empty, buffer, &offset);
+                    break;
+                case CSR_WIFI_SME_P2P_ROLE_GO:
+                    CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].deviceInfo.groupInfo.groupCapability, buffer, &offset);
+                    CsrMemCpyDes(primitive->scanResults[i1].deviceInfo.groupInfo.p2pDeviceAddress.a, buffer, &offset, ((CsrUint16) (6)));
+                    CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].deviceInfo.groupInfo.p2pClientInfoCount, buffer, &offset);
+                    primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo = NULL;
+                    if (primitive->scanResults[i1].deviceInfo.groupInfo.p2pClientInfoCount)
+                    {
+                        primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo = (CsrWifiSmeP2pClientInfoType *)CsrPmemAlloc(sizeof(CsrWifiSmeP2pClientInfoType) * primitive->scanResults[i1].deviceInfo.groupInfo.p2pClientInfoCount);
+                    }
+                    {
+                        CsrUint16 i4;
+                        for (i4 = 0; i4 < primitive->scanResults[i1].deviceInfo.groupInfo.p2pClientInfoCount; i4++)
+                        {
+                            CsrMemCpyDes(primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].p2PClientInterfaceAddress.a, buffer, &offset, ((CsrUint16) (6)));
+                            CsrMemCpyDes(primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceAddress.a, buffer, &offset, ((CsrUint16) (6)));
+                            CsrUint16Des((CsrUint16 *) &primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.configMethods, buffer, &offset);
+                            CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.p2PDeviceCap, buffer, &offset);
+                            CsrMemCpyDes(primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.primDeviceType.deviceDetails, buffer, &offset, ((CsrUint16) (8)));
+                            CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount, buffer, &offset);
+                            primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType = NULL;
+                            if (primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount)
+                            {
+                                primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType = (CsrWifiSmeWpsDeviceType *)CsrPmemAlloc(sizeof(CsrWifiSmeWpsDeviceType) * primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount);
+                            }
+                            {
+                                CsrUint16 i6;
+                                for (i6 = 0; i6 < primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secondaryDeviceTypeCount; i6++)
+                                {
+                                    CsrMemCpyDes(primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType[i6].deviceDetails, buffer, &offset, ((CsrUint16) (8)));
+                                }
+                            }
+                            CsrMemCpyDes(primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceName, buffer, &offset, ((CsrUint16) (32)));
+                            CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.deviceNameLength, buffer, &offset);
+                        }
+                    }
+                    break;
+                case CSR_WIFI_SME_P2P_ROLE_NONE:
+                    CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].deviceInfo.reservedNone.empty, buffer, &offset);
+                    break;
+                case CSR_WIFI_SME_P2P_ROLE_STANDALONE:
+                    CsrMemCpyDes(primitive->scanResults[i1].deviceInfo.standalonedevInfo.deviceAddress.a, buffer, &offset, ((CsrUint16) (6)));
+                    CsrUint16Des((CsrUint16 *) &primitive->scanResults[i1].deviceInfo.standalonedevInfo.configMethods, buffer, &offset);
+                    CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].deviceInfo.standalonedevInfo.p2PDeviceCap, buffer, &offset);
+                    CsrMemCpyDes(primitive->scanResults[i1].deviceInfo.standalonedevInfo.primDeviceType.deviceDetails, buffer, &offset, ((CsrUint16) (8)));
+                    CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].deviceInfo.standalonedevInfo.secondaryDeviceTypeCount, buffer, &offset);
+                    primitive->scanResults[i1].deviceInfo.standalonedevInfo.secDeviceType = NULL;
+                    if (primitive->scanResults[i1].deviceInfo.standalonedevInfo.secondaryDeviceTypeCount)
+                    {
+                        primitive->scanResults[i1].deviceInfo.standalonedevInfo.secDeviceType = (CsrWifiSmeWpsDeviceType *)CsrPmemAlloc(sizeof(CsrWifiSmeWpsDeviceType) * primitive->scanResults[i1].deviceInfo.standalonedevInfo.secondaryDeviceTypeCount);
+                    }
+                    {
+                        CsrUint16 i4;
+                        for (i4 = 0; i4 < primitive->scanResults[i1].deviceInfo.standalonedevInfo.secondaryDeviceTypeCount; i4++)
+                        {
+                            CsrMemCpyDes(primitive->scanResults[i1].deviceInfo.standalonedevInfo.secDeviceType[i4].deviceDetails, buffer, &offset, ((CsrUint16) (8)));
+                        }
+                    }
+                    CsrMemCpyDes(primitive->scanResults[i1].deviceInfo.standalonedevInfo.deviceName, buffer, &offset, ((CsrUint16) (32)));
+                    CsrUint8Des((CsrUint8 *) &primitive->scanResults[i1].deviceInfo.standalonedevInfo.deviceNameLength, buffer, &offset);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeScanResultsGetCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeScanResultsGetCfm *primitive = (CsrWifiSmeScanResultsGetCfm *) voidPrimitivePointer;
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < primitive->scanResultsCount; i1++)
+        {
+            CsrPmemFree(primitive->scanResults[i1].informationElements);
+            switch (primitive->scanResults[i1].p2pDeviceRole)
+            {
+                case CSR_WIFI_SME_P2P_ROLE_GO:
+                {
+                    CsrUint16 i4;
+                    for (i4 = 0; i4 < primitive->scanResults[i1].deviceInfo.groupInfo.p2pClientInfoCount; i4++)
+                    {
+                        CsrPmemFree(primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo[i4].clientDeviceInfo.secDeviceType);
+                    }
+                }
+                    CsrPmemFree(primitive->scanResults[i1].deviceInfo.groupInfo.p2PClientInfo);
+                    break;
+                case CSR_WIFI_SME_P2P_ROLE_STANDALONE:
+                    CsrPmemFree(primitive->scanResults[i1].deviceInfo.standalonedevInfo.secDeviceType);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+    CsrPmemFree(primitive->scanResults);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeSmeStaConfigGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrUint8 primitive->smeConfig.connectionQualityRssiChangeTrigger */
+    bufferSize += 1; /* CsrUint8 primitive->smeConfig.connectionQualitySnrChangeTrigger */
+    bufferSize += 1; /* CsrWifiSmeWmmModeMask primitive->smeConfig.wmmModeMask */
+    bufferSize += 1; /* CsrWifiSmeRadioIF primitive->smeConfig.ifIndex */
+    bufferSize += 1; /* CsrBool primitive->smeConfig.allowUnicastUseGroupCipher */
+    bufferSize += 1; /* CsrBool primitive->smeConfig.enableOpportunisticKeyCaching */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeSmeStaConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeSmeStaConfigGetCfm *primitive = (CsrWifiSmeSmeStaConfigGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.connectionQualityRssiChangeTrigger);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.connectionQualitySnrChangeTrigger);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.wmmModeMask);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.ifIndex);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.allowUnicastUseGroupCipher);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->smeConfig.enableOpportunisticKeyCaching);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeSmeStaConfigGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeSmeStaConfigGetCfm *primitive = (CsrWifiSmeSmeStaConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeStaConfigGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.connectionQualityRssiChangeTrigger, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.connectionQualitySnrChangeTrigger, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.wmmModeMask, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.ifIndex, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.allowUnicastUseGroupCipher, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->smeConfig.enableOpportunisticKeyCaching, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeSmeStaConfigSetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 7) */
+    bufferSize += 2; /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2; /* CsrResult primitive->status */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeSmeStaConfigSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeSmeStaConfigSetCfm *primitive = (CsrWifiSmeSmeStaConfigSetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeSmeStaConfigSetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeSmeStaConfigSetCfm *primitive = (CsrWifiSmeSmeStaConfigSetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeStaConfigSetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeStationMacAddressGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 17) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 2; i1++)
+        {
+            bufferSize += 6; /* CsrUint8 primitive->stationMacAddress[i1].a[6] */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeStationMacAddressGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeStationMacAddressGetCfm *primitive = (CsrWifiSmeStationMacAddressGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 2; i1++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->stationMacAddress[i1].a, ((CsrUint16) (6)));
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeStationMacAddressGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeStationMacAddressGetCfm *primitive = (CsrWifiSmeStationMacAddressGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeStationMacAddressGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    {
+        CsrUint16 i1;
+        for (i1 = 0; i1 < 2; i1++)
+        {
+            CsrMemCpyDes(primitive->stationMacAddress[i1].a, buffer, &offset, ((CsrUint16) (6)));
+        }
+    }
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeTspecIndSizeof(void *msg)
+{
+    CsrWifiSmeTspecInd *primitive = (CsrWifiSmeTspecInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 13) */
+    bufferSize += 2;                      /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 4;                      /* CsrUint32 primitive->transactionId */
+    bufferSize += 1;                      /* CsrWifiSmeTspecResultCode primitive->tspecResultCode */
+    bufferSize += 2;                      /* CsrUint16 primitive->tspecLength */
+    bufferSize += primitive->tspecLength; /* CsrUint8 primitive->tspec */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeTspecIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeTspecInd *primitive = (CsrWifiSmeTspecInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->transactionId);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->tspecResultCode);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->tspecLength);
+    if (primitive->tspecLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->tspec, ((CsrUint16) (primitive->tspecLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeTspecIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeTspecInd *primitive = (CsrWifiSmeTspecInd *) CsrPmemAlloc(sizeof(CsrWifiSmeTspecInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->transactionId, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->tspecResultCode, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->tspecLength, buffer, &offset);
+    if (primitive->tspecLength)
+    {
+        primitive->tspec = (CsrUint8 *)CsrPmemAlloc(primitive->tspecLength);
+        CsrMemCpyDes(primitive->tspec, buffer, &offset, ((CsrUint16) (primitive->tspecLength)));
+    }
+    else
+    {
+        primitive->tspec = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeTspecIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeTspecInd *primitive = (CsrWifiSmeTspecInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->tspec);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeTspecCfmSizeof(void *msg)
+{
+    CsrWifiSmeTspecCfm *primitive = (CsrWifiSmeTspecCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 15) */
+    bufferSize += 2;                      /* CsrUint16 primitive->interfaceTag */
+    bufferSize += 2;                      /* CsrResult primitive->status */
+    bufferSize += 4;                      /* CsrUint32 primitive->transactionId */
+    bufferSize += 1;                      /* CsrWifiSmeTspecResultCode primitive->tspecResultCode */
+    bufferSize += 2;                      /* CsrUint16 primitive->tspecLength */
+    bufferSize += primitive->tspecLength; /* CsrUint8 primitive->tspec */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeTspecCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeTspecCfm *primitive = (CsrWifiSmeTspecCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->interfaceTag);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->transactionId);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->tspecResultCode);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->tspecLength);
+    if (primitive->tspecLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->tspec, ((CsrUint16) (primitive->tspecLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeTspecCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeTspecCfm *primitive = (CsrWifiSmeTspecCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeTspecCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->interfaceTag, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->transactionId, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->tspecResultCode, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->tspecLength, buffer, &offset);
+    if (primitive->tspecLength)
+    {
+        primitive->tspec = (CsrUint8 *)CsrPmemAlloc(primitive->tspecLength);
+        CsrMemCpyDes(primitive->tspec, buffer, &offset, ((CsrUint16) (primitive->tspecLength)));
+    }
+    else
+    {
+        primitive->tspec = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeTspecCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeTspecCfm *primitive = (CsrWifiSmeTspecCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->tspec);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeVersionsGetCfmSizeof(void *msg)
+{
+    CsrWifiSmeVersionsGetCfm *primitive = (CsrWifiSmeVersionsGetCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 33) */
+    bufferSize += 2;                                                                                    /* CsrResult primitive->status */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.chipId */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.chipVersion */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.firmwareBuild */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.firmwarePatch */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.firmwareHip */
+    bufferSize += (primitive->versions.routerBuild?CsrStrLen(primitive->versions.routerBuild) : 0) + 1; /* CsrCharString* primitive->versions.routerBuild (0 byte len + 1 for NULL Term) */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.routerHip */
+    bufferSize += (primitive->versions.smeBuild?CsrStrLen(primitive->versions.smeBuild) : 0) + 1;       /* CsrCharString* primitive->versions.smeBuild (0 byte len + 1 for NULL Term) */
+    bufferSize += 4;                                                                                    /* CsrUint32 primitive->versions.smeHip */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeVersionsGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeVersionsGetCfm *primitive = (CsrWifiSmeVersionsGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.chipId);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.chipVersion);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.firmwareBuild);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.firmwarePatch);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.firmwareHip);
+    CsrCharStringSer(ptr, len, primitive->versions.routerBuild);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.routerHip);
+    CsrCharStringSer(ptr, len, primitive->versions.smeBuild);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->versions.smeHip);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeVersionsGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeVersionsGetCfm *primitive = (CsrWifiSmeVersionsGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeVersionsGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.chipId, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.chipVersion, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.firmwareBuild, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.firmwarePatch, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.firmwareHip, buffer, &offset);
+    CsrCharStringDes(&primitive->versions.routerBuild, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.routerHip, buffer, &offset);
+    CsrCharStringDes(&primitive->versions.smeBuild, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->versions.smeHip, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiSmeVersionsGetCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeVersionsGetCfm *primitive = (CsrWifiSmeVersionsGetCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->versions.routerBuild);
+    CsrPmemFree(primitive->versions.smeBuild);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeCloakedSsidsGetCfmSizeof(void *msg)
+{
+    CsrWifiSmeCloakedSsidsGetCfm *primitive = (CsrWifiSmeCloakedSsidsGetCfm *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 39) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrUint8 primitive->cloakedSsids.cloakedSsidsCount */
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->cloakedSsids.cloakedSsidsCount; i2++)
+        {
+            bufferSize += 32; /* CsrUint8 primitive->cloakedSsids.cloakedSsids[i2].ssid[32] */
+            bufferSize += 1;  /* CsrUint8 primitive->cloakedSsids.cloakedSsids[i2].length */
+        }
+    }
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeCloakedSsidsGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeCloakedSsidsGetCfm *primitive = (CsrWifiSmeCloakedSsidsGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->cloakedSsids.cloakedSsidsCount);
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->cloakedSsids.cloakedSsidsCount; i2++)
+        {
+            CsrMemCpySer(ptr, len, (const void *) primitive->cloakedSsids.cloakedSsids[i2].ssid, ((CsrUint16) (32)));
+            CsrUint8Ser(ptr, len, (CsrUint8) primitive->cloakedSsids.cloakedSsids[i2].length);
+        }
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeCloakedSsidsGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeCloakedSsidsGetCfm *primitive = (CsrWifiSmeCloakedSsidsGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeCloakedSsidsGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->cloakedSsids.cloakedSsidsCount, buffer, &offset);
+    primitive->cloakedSsids.cloakedSsids = NULL;
+    if (primitive->cloakedSsids.cloakedSsidsCount)
+    {
+        primitive->cloakedSsids.cloakedSsids = (CsrWifiSsid *)CsrPmemAlloc(sizeof(CsrWifiSsid) * primitive->cloakedSsids.cloakedSsidsCount);
+    }
+    {
+        CsrUint16 i2;
+        for (i2 = 0; i2 < primitive->cloakedSsids.cloakedSsidsCount; i2++)
+        {
+            CsrMemCpyDes(primitive->cloakedSsids.cloakedSsids[i2].ssid, buffer, &offset, ((CsrUint16) (32)));
+            CsrUint8Des((CsrUint8 *) &primitive->cloakedSsids.cloakedSsids[i2].length, buffer, &offset);
+        }
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeCloakedSsidsGetCfmSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeCloakedSsidsGetCfm *primitive = (CsrWifiSmeCloakedSsidsGetCfm *) voidPrimitivePointer;
+    CsrPmemFree(primitive->cloakedSsids.cloakedSsids);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeWifiOnIndSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 9) */
+    bufferSize += 6; /* CsrUint8 primitive->address.a[6] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeWifiOnIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeWifiOnInd *primitive = (CsrWifiSmeWifiOnInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrMemCpySer(ptr, len, (const void *) primitive->address.a, ((CsrUint16) (6)));
+    return(ptr);
+}
+
+
+void* CsrWifiSmeWifiOnIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeWifiOnInd *primitive = (CsrWifiSmeWifiOnInd *) CsrPmemAlloc(sizeof(CsrWifiSmeWifiOnInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrMemCpyDes(primitive->address.a, buffer, &offset, ((CsrUint16) (6)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeSmeCommonConfigGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 10) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 1; /* CsrWifiSme80211dTrustLevel primitive->deviceConfig.trustLevel */
+    bufferSize += 2; /* CsrUint8 primitive->deviceConfig.countryCode[2] */
+    bufferSize += 1; /* CsrWifiSmeFirmwareDriverInterface primitive->deviceConfig.firmwareDriverInterface */
+    bufferSize += 1; /* CsrBool primitive->deviceConfig.enableStrictDraftN */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeSmeCommonConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeSmeCommonConfigGetCfm *primitive = (CsrWifiSmeSmeCommonConfigGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->deviceConfig.trustLevel);
+    CsrMemCpySer(ptr, len, (const void *) primitive->deviceConfig.countryCode, ((CsrUint16) (2)));
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->deviceConfig.firmwareDriverInterface);
+    CsrUint8Ser(ptr, len, (CsrUint8) primitive->deviceConfig.enableStrictDraftN);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeSmeCommonConfigGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeSmeCommonConfigGetCfm *primitive = (CsrWifiSmeSmeCommonConfigGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeSmeCommonConfigGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->deviceConfig.trustLevel, buffer, &offset);
+    CsrMemCpyDes(primitive->deviceConfig.countryCode, buffer, &offset, ((CsrUint16) (2)));
+    CsrUint8Des((CsrUint8 *) &primitive->deviceConfig.firmwareDriverInterface, buffer, &offset);
+    CsrUint8Des((CsrUint8 *) &primitive->deviceConfig.enableStrictDraftN, buffer, &offset);
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeInterfaceCapabilityGetCfmSizeof(void *msg)
+{
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 9) */
+    bufferSize += 2; /* CsrResult primitive->status */
+    bufferSize += 2; /* CsrUint16 primitive->numInterfaces */
+    bufferSize += 2; /* CsrUint8 primitive->capBitmap[2] */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeInterfaceCapabilityGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeInterfaceCapabilityGetCfm *primitive = (CsrWifiSmeInterfaceCapabilityGetCfm *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->status);
+    CsrUint16Ser(ptr, len, (CsrUint16) primitive->numInterfaces);
+    CsrMemCpySer(ptr, len, (const void *) primitive->capBitmap, ((CsrUint16) (2)));
+    return(ptr);
+}
+
+
+void* CsrWifiSmeInterfaceCapabilityGetCfmDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeInterfaceCapabilityGetCfm *primitive = (CsrWifiSmeInterfaceCapabilityGetCfm *) CsrPmemAlloc(sizeof(CsrWifiSmeInterfaceCapabilityGetCfm));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->status, buffer, &offset);
+    CsrUint16Des((CsrUint16 *) &primitive->numInterfaces, buffer, &offset);
+    CsrMemCpyDes(primitive->capBitmap, buffer, &offset, ((CsrUint16) (2)));
+
+    return primitive;
+}
+
+
+CsrSize CsrWifiSmeErrorIndSizeof(void *msg)
+{
+    CsrWifiSmeErrorInd *primitive = (CsrWifiSmeErrorInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 3) */
+    bufferSize += (primitive->errorMessage?CsrStrLen(primitive->errorMessage) : 0) + 1; /* CsrCharString* primitive->errorMessage (0 byte len + 1 for NULL Term) */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeErrorIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeErrorInd *primitive = (CsrWifiSmeErrorInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrCharStringSer(ptr, len, primitive->errorMessage);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeErrorIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeErrorInd *primitive = (CsrWifiSmeErrorInd *) CsrPmemAlloc(sizeof(CsrWifiSmeErrorInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrCharStringDes(&primitive->errorMessage, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiSmeErrorIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeErrorInd *primitive = (CsrWifiSmeErrorInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->errorMessage);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeInfoIndSizeof(void *msg)
+{
+    CsrWifiSmeInfoInd *primitive = (CsrWifiSmeInfoInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 3) */
+    bufferSize += (primitive->infoMessage?CsrStrLen(primitive->infoMessage) : 0) + 1; /* CsrCharString* primitive->infoMessage (0 byte len + 1 for NULL Term) */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeInfoIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeInfoInd *primitive = (CsrWifiSmeInfoInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrCharStringSer(ptr, len, primitive->infoMessage);
+    return(ptr);
+}
+
+
+void* CsrWifiSmeInfoIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeInfoInd *primitive = (CsrWifiSmeInfoInd *) CsrPmemAlloc(sizeof(CsrWifiSmeInfoInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrCharStringDes(&primitive->infoMessage, buffer, &offset);
+
+    return primitive;
+}
+
+
+void CsrWifiSmeInfoIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeInfoInd *primitive = (CsrWifiSmeInfoInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->infoMessage);
+    CsrPmemFree(primitive);
+}
+
+
+CsrSize CsrWifiSmeCoreDumpIndSizeof(void *msg)
+{
+    CsrWifiSmeCoreDumpInd *primitive = (CsrWifiSmeCoreDumpInd *) msg;
+    CsrSize bufferSize = 2;
+
+    /* Calculate the Size of the Serialised Data. Could be more efficient (Try 8) */
+    bufferSize += 4;                     /* CsrUint32 primitive->dataLength */
+    bufferSize += primitive->dataLength; /* CsrUint8 primitive->data */
+    return bufferSize;
+}
+
+
+CsrUint8* CsrWifiSmeCoreDumpIndSer(CsrUint8 *ptr, CsrSize *len, void *msg)
+{
+    CsrWifiSmeCoreDumpInd *primitive = (CsrWifiSmeCoreDumpInd *)msg;
+    *len = 0;
+    CsrUint16Ser(ptr, len, primitive->common.type);
+    CsrUint32Ser(ptr, len, (CsrUint32) primitive->dataLength);
+    if (primitive->dataLength)
+    {
+        CsrMemCpySer(ptr, len, (const void *) primitive->data, ((CsrUint16) (primitive->dataLength)));
+    }
+    return(ptr);
+}
+
+
+void* CsrWifiSmeCoreDumpIndDes(CsrUint8 *buffer, CsrSize length)
+{
+    CsrWifiSmeCoreDumpInd *primitive = (CsrWifiSmeCoreDumpInd *) CsrPmemAlloc(sizeof(CsrWifiSmeCoreDumpInd));
+    CsrSize offset;
+    offset = 0;
+
+    CsrUint16Des(&primitive->common.type, buffer, &offset);
+    CsrUint32Des((CsrUint32 *) &primitive->dataLength, buffer, &offset);
+    if (primitive->dataLength)
+    {
+        primitive->data = (CsrUint8 *)CsrPmemAlloc(primitive->dataLength);
+        CsrMemCpyDes(primitive->data, buffer, &offset, ((CsrUint16) (primitive->dataLength)));
+    }
+    else
+    {
+        primitive->data = NULL;
+    }
+
+    return primitive;
+}
+
+
+void CsrWifiSmeCoreDumpIndSerFree(void *voidPrimitivePointer)
+{
+    CsrWifiSmeCoreDumpInd *primitive = (CsrWifiSmeCoreDumpInd *) voidPrimitivePointer;
+    CsrPmemFree(primitive->data);
+    CsrPmemFree(primitive);
+}
+
+
diff --git a/drivers/staging/csr/csr_wifi_sme_serialize.h b/drivers/staging/csr/csr_wifi_sme_serialize.h
new file mode 100644
index 0000000..0080bf4
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_serialize.h
@@ -0,0 +1,673 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2012
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_SME_SERIALIZE_H__
+#define CSR_WIFI_SME_SERIALIZE_H__
+
+#include "csr_types.h"
+#include "csr_pmem.h"
+#include "csr_wifi_msgconv.h"
+
+#include "csr_wifi_sme_prim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void CsrWifiSmePfree(void *ptr);
+
+#define CsrWifiSmeActivateReqSer CsrWifiEventSer
+#define CsrWifiSmeActivateReqDes CsrWifiEventDes
+#define CsrWifiSmeActivateReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeActivateReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeAdhocConfigGetReqSer CsrWifiEventSer
+#define CsrWifiSmeAdhocConfigGetReqDes CsrWifiEventDes
+#define CsrWifiSmeAdhocConfigGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeAdhocConfigGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeAdhocConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeAdhocConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeAdhocConfigSetReqSizeof(void *msg);
+#define CsrWifiSmeAdhocConfigSetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeBlacklistReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeBlacklistReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeBlacklistReqSizeof(void *msg);
+extern void CsrWifiSmeBlacklistReqSerFree(void *msg);
+
+#define CsrWifiSmeCalibrationDataGetReqSer CsrWifiEventSer
+#define CsrWifiSmeCalibrationDataGetReqDes CsrWifiEventDes
+#define CsrWifiSmeCalibrationDataGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeCalibrationDataGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeCalibrationDataSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeCalibrationDataSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeCalibrationDataSetReqSizeof(void *msg);
+extern void CsrWifiSmeCalibrationDataSetReqSerFree(void *msg);
+
+#define CsrWifiSmeCcxConfigGetReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeCcxConfigGetReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeCcxConfigGetReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeCcxConfigGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeCcxConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeCcxConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeCcxConfigSetReqSizeof(void *msg);
+#define CsrWifiSmeCcxConfigSetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeCoexConfigGetReqSer CsrWifiEventSer
+#define CsrWifiSmeCoexConfigGetReqDes CsrWifiEventDes
+#define CsrWifiSmeCoexConfigGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeCoexConfigGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeCoexConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeCoexConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeCoexConfigSetReqSizeof(void *msg);
+#define CsrWifiSmeCoexConfigSetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeCoexInfoGetReqSer CsrWifiEventSer
+#define CsrWifiSmeCoexInfoGetReqDes CsrWifiEventDes
+#define CsrWifiSmeCoexInfoGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeCoexInfoGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeConnectReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeConnectReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeConnectReqSizeof(void *msg);
+extern void CsrWifiSmeConnectReqSerFree(void *msg);
+
+#define CsrWifiSmeConnectionConfigGetReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeConnectionConfigGetReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeConnectionConfigGetReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeConnectionConfigGetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeConnectionInfoGetReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeConnectionInfoGetReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeConnectionInfoGetReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeConnectionInfoGetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeConnectionStatsGetReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeConnectionStatsGetReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeConnectionStatsGetReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeConnectionStatsGetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeDeactivateReqSer CsrWifiEventSer
+#define CsrWifiSmeDeactivateReqDes CsrWifiEventDes
+#define CsrWifiSmeDeactivateReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeDeactivateReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeDisconnectReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeDisconnectReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeDisconnectReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeDisconnectReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeEventMaskSetReqSer CsrWifiEventCsrUint32Ser
+#define CsrWifiSmeEventMaskSetReqDes CsrWifiEventCsrUint32Des
+#define CsrWifiSmeEventMaskSetReqSizeof CsrWifiEventCsrUint32Sizeof
+#define CsrWifiSmeEventMaskSetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeHostConfigGetReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeHostConfigGetReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeHostConfigGetReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeHostConfigGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeHostConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeHostConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeHostConfigSetReqSizeof(void *msg);
+#define CsrWifiSmeHostConfigSetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeKeyReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeKeyReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeKeyReqSizeof(void *msg);
+#define CsrWifiSmeKeyReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeLinkQualityGetReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeLinkQualityGetReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeLinkQualityGetReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeLinkQualityGetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeMibConfigGetReqSer CsrWifiEventSer
+#define CsrWifiSmeMibConfigGetReqDes CsrWifiEventDes
+#define CsrWifiSmeMibConfigGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeMibConfigGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeMibConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeMibConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeMibConfigSetReqSizeof(void *msg);
+#define CsrWifiSmeMibConfigSetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeMibGetNextReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeMibGetNextReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeMibGetNextReqSizeof(void *msg);
+extern void CsrWifiSmeMibGetNextReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeMibGetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeMibGetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeMibGetReqSizeof(void *msg);
+extern void CsrWifiSmeMibGetReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeMibSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeMibSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeMibSetReqSizeof(void *msg);
+extern void CsrWifiSmeMibSetReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeMulticastAddressReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeMulticastAddressReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeMulticastAddressReqSizeof(void *msg);
+extern void CsrWifiSmeMulticastAddressReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmePacketFilterSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmePacketFilterSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmePacketFilterSetReqSizeof(void *msg);
+extern void CsrWifiSmePacketFilterSetReqSerFree(void *msg);
+
+#define CsrWifiSmePermanentMacAddressGetReqSer CsrWifiEventSer
+#define CsrWifiSmePermanentMacAddressGetReqDes CsrWifiEventDes
+#define CsrWifiSmePermanentMacAddressGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmePermanentMacAddressGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmePmkidReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmePmkidReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmePmkidReqSizeof(void *msg);
+extern void CsrWifiSmePmkidReqSerFree(void *msg);
+
+#define CsrWifiSmePowerConfigGetReqSer CsrWifiEventSer
+#define CsrWifiSmePowerConfigGetReqDes CsrWifiEventDes
+#define CsrWifiSmePowerConfigGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmePowerConfigGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmePowerConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmePowerConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmePowerConfigSetReqSizeof(void *msg);
+#define CsrWifiSmePowerConfigSetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeRegulatoryDomainInfoGetReqSer CsrWifiEventSer
+#define CsrWifiSmeRegulatoryDomainInfoGetReqDes CsrWifiEventDes
+#define CsrWifiSmeRegulatoryDomainInfoGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeRegulatoryDomainInfoGetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeRoamingConfigGetReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeRoamingConfigGetReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeRoamingConfigGetReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeRoamingConfigGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeRoamingConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeRoamingConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeRoamingConfigSetReqSizeof(void *msg);
+#define CsrWifiSmeRoamingConfigSetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeScanConfigGetReqSer CsrWifiEventSer
+#define CsrWifiSmeScanConfigGetReqDes CsrWifiEventDes
+#define CsrWifiSmeScanConfigGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeScanConfigGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeScanConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeScanConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeScanConfigSetReqSizeof(void *msg);
+extern void CsrWifiSmeScanConfigSetReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeScanFullReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeScanFullReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeScanFullReqSizeof(void *msg);
+extern void CsrWifiSmeScanFullReqSerFree(void *msg);
+
+#define CsrWifiSmeScanResultsFlushReqSer CsrWifiEventSer
+#define CsrWifiSmeScanResultsFlushReqDes CsrWifiEventDes
+#define CsrWifiSmeScanResultsFlushReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeScanResultsFlushReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeScanResultsGetReqSer CsrWifiEventSer
+#define CsrWifiSmeScanResultsGetReqDes CsrWifiEventDes
+#define CsrWifiSmeScanResultsGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeScanResultsGetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeSmeStaConfigGetReqSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeSmeStaConfigGetReqDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeSmeStaConfigGetReqSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeSmeStaConfigGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeSmeStaConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeSmeStaConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeSmeStaConfigSetReqSizeof(void *msg);
+#define CsrWifiSmeSmeStaConfigSetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeStationMacAddressGetReqSer CsrWifiEventSer
+#define CsrWifiSmeStationMacAddressGetReqDes CsrWifiEventDes
+#define CsrWifiSmeStationMacAddressGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeStationMacAddressGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeTspecReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeTspecReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeTspecReqSizeof(void *msg);
+extern void CsrWifiSmeTspecReqSerFree(void *msg);
+
+#define CsrWifiSmeVersionsGetReqSer CsrWifiEventSer
+#define CsrWifiSmeVersionsGetReqDes CsrWifiEventDes
+#define CsrWifiSmeVersionsGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeVersionsGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeWifiFlightmodeReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeWifiFlightmodeReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeWifiFlightmodeReqSizeof(void *msg);
+extern void CsrWifiSmeWifiFlightmodeReqSerFree(void *msg);
+
+#define CsrWifiSmeWifiOffReqSer CsrWifiEventSer
+#define CsrWifiSmeWifiOffReqDes CsrWifiEventDes
+#define CsrWifiSmeWifiOffReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeWifiOffReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeWifiOnReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeWifiOnReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeWifiOnReqSizeof(void *msg);
+extern void CsrWifiSmeWifiOnReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeCloakedSsidsSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeCloakedSsidsSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeCloakedSsidsSetReqSizeof(void *msg);
+extern void CsrWifiSmeCloakedSsidsSetReqSerFree(void *msg);
+
+#define CsrWifiSmeCloakedSsidsGetReqSer CsrWifiEventSer
+#define CsrWifiSmeCloakedSsidsGetReqDes CsrWifiEventDes
+#define CsrWifiSmeCloakedSsidsGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeCloakedSsidsGetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeSmeCommonConfigGetReqSer CsrWifiEventSer
+#define CsrWifiSmeSmeCommonConfigGetReqDes CsrWifiEventDes
+#define CsrWifiSmeSmeCommonConfigGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeSmeCommonConfigGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeSmeCommonConfigSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeSmeCommonConfigSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeSmeCommonConfigSetReqSizeof(void *msg);
+#define CsrWifiSmeSmeCommonConfigSetReqSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeInterfaceCapabilityGetReqSer CsrWifiEventSer
+#define CsrWifiSmeInterfaceCapabilityGetReqDes CsrWifiEventDes
+#define CsrWifiSmeInterfaceCapabilityGetReqSizeof CsrWifiEventSizeof
+#define CsrWifiSmeInterfaceCapabilityGetReqSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeWpsConfigurationReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeWpsConfigurationReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeWpsConfigurationReqSizeof(void *msg);
+extern void CsrWifiSmeWpsConfigurationReqSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeSetReqSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeSetReqDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeSetReqSizeof(void *msg);
+extern void CsrWifiSmeSetReqSerFree(void *msg);
+
+#define CsrWifiSmeActivateCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeActivateCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeActivateCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeActivateCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeAdhocConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeAdhocConfigGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeAdhocConfigGetCfmSizeof(void *msg);
+#define CsrWifiSmeAdhocConfigGetCfmSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeAdhocConfigSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeAdhocConfigSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeAdhocConfigSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeAdhocConfigSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeAssociationCompleteIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeAssociationCompleteIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeAssociationCompleteIndSizeof(void *msg);
+extern void CsrWifiSmeAssociationCompleteIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeAssociationStartIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeAssociationStartIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeAssociationStartIndSizeof(void *msg);
+#define CsrWifiSmeAssociationStartIndSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeBlacklistCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeBlacklistCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeBlacklistCfmSizeof(void *msg);
+extern void CsrWifiSmeBlacklistCfmSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeCalibrationDataGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeCalibrationDataGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeCalibrationDataGetCfmSizeof(void *msg);
+extern void CsrWifiSmeCalibrationDataGetCfmSerFree(void *msg);
+
+#define CsrWifiSmeCalibrationDataSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeCalibrationDataSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeCalibrationDataSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeCalibrationDataSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeCcxConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeCcxConfigGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeCcxConfigGetCfmSizeof(void *msg);
+#define CsrWifiSmeCcxConfigGetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeCcxConfigSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeCcxConfigSetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeCcxConfigSetCfmSizeof(void *msg);
+#define CsrWifiSmeCcxConfigSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeCoexConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeCoexConfigGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeCoexConfigGetCfmSizeof(void *msg);
+#define CsrWifiSmeCoexConfigGetCfmSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeCoexConfigSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeCoexConfigSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeCoexConfigSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeCoexConfigSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeCoexInfoGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeCoexInfoGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeCoexInfoGetCfmSizeof(void *msg);
+#define CsrWifiSmeCoexInfoGetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeConnectCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeConnectCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeConnectCfmSizeof(void *msg);
+#define CsrWifiSmeConnectCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeConnectionConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeConnectionConfigGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeConnectionConfigGetCfmSizeof(void *msg);
+extern void CsrWifiSmeConnectionConfigGetCfmSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeConnectionInfoGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeConnectionInfoGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeConnectionInfoGetCfmSizeof(void *msg);
+extern void CsrWifiSmeConnectionInfoGetCfmSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeConnectionQualityIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeConnectionQualityIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeConnectionQualityIndSizeof(void *msg);
+#define CsrWifiSmeConnectionQualityIndSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeConnectionStatsGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeConnectionStatsGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeConnectionStatsGetCfmSizeof(void *msg);
+#define CsrWifiSmeConnectionStatsGetCfmSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeDeactivateCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeDeactivateCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeDeactivateCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeDeactivateCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeDisconnectCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeDisconnectCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeDisconnectCfmSizeof(void *msg);
+#define CsrWifiSmeDisconnectCfmSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeEventMaskSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeEventMaskSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeEventMaskSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeEventMaskSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeHostConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeHostConfigGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeHostConfigGetCfmSizeof(void *msg);
+#define CsrWifiSmeHostConfigGetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeHostConfigSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeHostConfigSetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeHostConfigSetCfmSizeof(void *msg);
+#define CsrWifiSmeHostConfigSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeIbssStationIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeIbssStationIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeIbssStationIndSizeof(void *msg);
+#define CsrWifiSmeIbssStationIndSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeKeyCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeKeyCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeKeyCfmSizeof(void *msg);
+#define CsrWifiSmeKeyCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeLinkQualityGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeLinkQualityGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeLinkQualityGetCfmSizeof(void *msg);
+#define CsrWifiSmeLinkQualityGetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeMediaStatusIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeMediaStatusIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeMediaStatusIndSizeof(void *msg);
+extern void CsrWifiSmeMediaStatusIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeMibConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeMibConfigGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeMibConfigGetCfmSizeof(void *msg);
+#define CsrWifiSmeMibConfigGetCfmSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeMibConfigSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeMibConfigSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeMibConfigSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeMibConfigSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeMibGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeMibGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeMibGetCfmSizeof(void *msg);
+extern void CsrWifiSmeMibGetCfmSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeMibGetNextCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeMibGetNextCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeMibGetNextCfmSizeof(void *msg);
+extern void CsrWifiSmeMibGetNextCfmSerFree(void *msg);
+
+#define CsrWifiSmeMibSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeMibSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeMibSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeMibSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeMicFailureIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeMicFailureIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeMicFailureIndSizeof(void *msg);
+#define CsrWifiSmeMicFailureIndSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeMulticastAddressCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeMulticastAddressCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeMulticastAddressCfmSizeof(void *msg);
+extern void CsrWifiSmeMulticastAddressCfmSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmePacketFilterSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmePacketFilterSetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmePacketFilterSetCfmSizeof(void *msg);
+#define CsrWifiSmePacketFilterSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmePermanentMacAddressGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmePermanentMacAddressGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmePermanentMacAddressGetCfmSizeof(void *msg);
+#define CsrWifiSmePermanentMacAddressGetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmePmkidCandidateListIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmePmkidCandidateListIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmePmkidCandidateListIndSizeof(void *msg);
+extern void CsrWifiSmePmkidCandidateListIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmePmkidCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmePmkidCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmePmkidCfmSizeof(void *msg);
+extern void CsrWifiSmePmkidCfmSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmePowerConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmePowerConfigGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmePowerConfigGetCfmSizeof(void *msg);
+#define CsrWifiSmePowerConfigGetCfmSerFree CsrWifiSmePfree
+
+#define CsrWifiSmePowerConfigSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmePowerConfigSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmePowerConfigSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmePowerConfigSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeRegulatoryDomainInfoGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeRegulatoryDomainInfoGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeRegulatoryDomainInfoGetCfmSizeof(void *msg);
+#define CsrWifiSmeRegulatoryDomainInfoGetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeRoamCompleteIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeRoamCompleteIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeRoamCompleteIndSizeof(void *msg);
+#define CsrWifiSmeRoamCompleteIndSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeRoamStartIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeRoamStartIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeRoamStartIndSizeof(void *msg);
+#define CsrWifiSmeRoamStartIndSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeRoamingConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeRoamingConfigGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeRoamingConfigGetCfmSizeof(void *msg);
+#define CsrWifiSmeRoamingConfigGetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeRoamingConfigSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeRoamingConfigSetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeRoamingConfigSetCfmSizeof(void *msg);
+#define CsrWifiSmeRoamingConfigSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeScanConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeScanConfigGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeScanConfigGetCfmSizeof(void *msg);
+extern void CsrWifiSmeScanConfigGetCfmSerFree(void *msg);
+
+#define CsrWifiSmeScanConfigSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeScanConfigSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeScanConfigSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeScanConfigSetCfmSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeScanFullCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeScanFullCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeScanFullCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeScanFullCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeScanResultIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeScanResultIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeScanResultIndSizeof(void *msg);
+extern void CsrWifiSmeScanResultIndSerFree(void *msg);
+
+#define CsrWifiSmeScanResultsFlushCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeScanResultsFlushCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeScanResultsFlushCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeScanResultsFlushCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeScanResultsGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeScanResultsGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeScanResultsGetCfmSizeof(void *msg);
+extern void CsrWifiSmeScanResultsGetCfmSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeSmeStaConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeSmeStaConfigGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeSmeStaConfigGetCfmSizeof(void *msg);
+#define CsrWifiSmeSmeStaConfigGetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeSmeStaConfigSetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeSmeStaConfigSetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeSmeStaConfigSetCfmSizeof(void *msg);
+#define CsrWifiSmeSmeStaConfigSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeStationMacAddressGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeStationMacAddressGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeStationMacAddressGetCfmSizeof(void *msg);
+#define CsrWifiSmeStationMacAddressGetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeTspecIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeTspecIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeTspecIndSizeof(void *msg);
+extern void CsrWifiSmeTspecIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeTspecCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeTspecCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeTspecCfmSizeof(void *msg);
+extern void CsrWifiSmeTspecCfmSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeVersionsGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeVersionsGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeVersionsGetCfmSizeof(void *msg);
+extern void CsrWifiSmeVersionsGetCfmSerFree(void *msg);
+
+#define CsrWifiSmeWifiFlightmodeCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeWifiFlightmodeCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeWifiFlightmodeCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeWifiFlightmodeCfmSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeWifiOffIndSer CsrWifiEventCsrUint8Ser
+#define CsrWifiSmeWifiOffIndDes CsrWifiEventCsrUint8Des
+#define CsrWifiSmeWifiOffIndSizeof CsrWifiEventCsrUint8Sizeof
+#define CsrWifiSmeWifiOffIndSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeWifiOffCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeWifiOffCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeWifiOffCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeWifiOffCfmSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeWifiOnCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeWifiOnCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeWifiOnCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeWifiOnCfmSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeCloakedSsidsSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeCloakedSsidsSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeCloakedSsidsSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeCloakedSsidsSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeCloakedSsidsGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeCloakedSsidsGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeCloakedSsidsGetCfmSizeof(void *msg);
+extern void CsrWifiSmeCloakedSsidsGetCfmSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeWifiOnIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeWifiOnIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeWifiOnIndSizeof(void *msg);
+#define CsrWifiSmeWifiOnIndSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeSmeCommonConfigGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeSmeCommonConfigGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeSmeCommonConfigGetCfmSizeof(void *msg);
+#define CsrWifiSmeSmeCommonConfigGetCfmSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeSmeCommonConfigSetCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeSmeCommonConfigSetCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeSmeCommonConfigSetCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeSmeCommonConfigSetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeInterfaceCapabilityGetCfmSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeInterfaceCapabilityGetCfmDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeInterfaceCapabilityGetCfmSizeof(void *msg);
+#define CsrWifiSmeInterfaceCapabilityGetCfmSerFree CsrWifiSmePfree
+
+extern CsrUint8* CsrWifiSmeErrorIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeErrorIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeErrorIndSizeof(void *msg);
+extern void CsrWifiSmeErrorIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeInfoIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeInfoIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeInfoIndSizeof(void *msg);
+extern void CsrWifiSmeInfoIndSerFree(void *msg);
+
+extern CsrUint8* CsrWifiSmeCoreDumpIndSer(CsrUint8 *ptr, CsrSize *len, void *msg);
+extern void* CsrWifiSmeCoreDumpIndDes(CsrUint8 *buffer, CsrSize len);
+extern CsrSize CsrWifiSmeCoreDumpIndSizeof(void *msg);
+extern void CsrWifiSmeCoreDumpIndSerFree(void *msg);
+
+#define CsrWifiSmeAmpStatusChangeIndSer CsrWifiEventCsrUint16CsrUint8Ser
+#define CsrWifiSmeAmpStatusChangeIndDes CsrWifiEventCsrUint16CsrUint8Des
+#define CsrWifiSmeAmpStatusChangeIndSizeof CsrWifiEventCsrUint16CsrUint8Sizeof
+#define CsrWifiSmeAmpStatusChangeIndSerFree CsrWifiSmePfree
+
+#define CsrWifiSmeWpsConfigurationCfmSer CsrWifiEventCsrUint16Ser
+#define CsrWifiSmeWpsConfigurationCfmDes CsrWifiEventCsrUint16Des
+#define CsrWifiSmeWpsConfigurationCfmSizeof CsrWifiEventCsrUint16Sizeof
+#define CsrWifiSmeWpsConfigurationCfmSerFree CsrWifiSmePfree
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* CSR_WIFI_SME_SERIALIZE_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_sme_task.h b/drivers/staging/csr/csr_wifi_sme_task.h
new file mode 100644
index 0000000..62cc8b7
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_sme_task.h
@@ -0,0 +1,34 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+/* Note: this is an auto-generated file. */
+
+#ifndef CSR_WIFI_SME_TASK_H__
+#define CSR_WIFI_SME_TASK_H__
+
+#include "csr_types.h"
+#include "csr_sched.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CSR_WIFI_SME_LOG_ID 0x1202FFFF
+extern CsrSchedQid CSR_WIFI_SME_IFACEQUEUE;
+void CsrWifiSmeInit(void **gash);
+void CsrWifiSmeDeinit(void **gash);
+void CsrWifiSmeHandler(void **gash);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_SME_TASK_H__ */
+
diff --git a/drivers/staging/csr/csr_wifi_vif_utils.h b/drivers/staging/csr/csr_wifi_vif_utils.h
new file mode 100644
index 0000000..c534588
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_vif_utils.h
@@ -0,0 +1,108 @@
+/*****************************************************************************
+
+            (c) Cambridge Silicon Radio Limited 2011
+            All rights reserved and confidential information of CSR
+
+            Refer to LICENSE.txt included with this source for details
+            on the license terms.
+
+*****************************************************************************/
+
+#ifndef CSR_WIFI_VIF_UTILS_H
+#define CSR_WIFI_VIF_UTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* STANDARD INCLUDES ********************************************************/
+
+/* PROJECT INCLUDES *********************************************************/
+/* including this file for CsrWifiInterfaceMode*/
+#include "csr_wifi_private_common.h"
+
+/* MACROS *******************************************************************/
+
+/* Common macros for NME and SME to be used temporarily until SoftMAC changes are made */
+#define CSR_WIFI_NUM_INTERFACES        (CsrUint8)0x1
+#define CSR_WIFI_INTERFACE_IN_USE      (CsrUint16)0x0
+
+/* This is used at places where interface Id isn't available*/
+#define CSR_WIFI_INTERFACE_ZERO        0
+#define CSR_WIFI_INTERFACE_STA         0
+#define CSR_WIFI_INTERFACE_AMP         0
+
+
+#define CSR_WIFI_VIF_UTILS_UNDEFINED_TAG 0xFFFF
+
+/* Extract the Interface Id from the event */
+#define CsrWifiVifUtilsGetVifTagFromEvent(msg) \
+    ((CsrUint16) * ((CsrUint16 *) ((CsrUint8 *) (msg) + sizeof(CsrWifiFsmEvent))))
+
+/* The HPI Vif combines the type and the interface id */
+#define CsrWifiVifUtilsGetVifTagFromHipEvent(msg) \
+    ((msg)->virtualInterfaceIdentifier & 0x00FF)
+
+#define CsrWifiVifUtilsPackHipEventVif(type, interfaceId) \
+    ((CsrUint16)((interfaceId) | ((type) << 8)))
+
+
+/* TYPES DEFINITIONS ********************************************************/
+
+/* GLOBAL VARIABLE DECLARATIONS *********************************************/
+
+/* PUBLIC FUNCTION PROTOTYPES ***********************************************/
+
+/**
+ * @brief
+ *     First checks if the mode is supported capability bitmap of the interface.
+ *     If this succeeds, then checks if running this mode on this interface is allowed.
+ *
+ * @param[in] CsrUint8 : interface capability bitmap
+ * @param[in] CsrUint8* : pointer to the array of current interface modes
+ * @param[in] CsrUint16 : interfaceTag
+ * @param[in] CsrWifiInterfaceMode : mode
+ *
+ * @return
+ *     CsrBool : returns true if the interface is allowed to operate in the mode otherwise false.
+ */
+extern CsrBool CsrWifiVifUtilsCheckCompatibility(CsrUint8             interfaceCapability,
+                                                 CsrUint8            *currentInterfaceModes,
+                                                 CsrUint16            interfaceTag,
+                                                 CsrWifiInterfaceMode mode);
+
+/**
+ * @brief
+ *     Checks if the specified interface is supported.
+ *     NOTE: Only checks that the interface is supported, no checks are made to
+ *     determine whether a supported interface may be made active.
+ *
+ * @param[in] CsrUint16 : interfaceTag
+ *
+ * @return
+ *     CsrBool : returns true if the interface is supported, otherwise false.
+ */
+extern CsrBool CsrWifiVifUtilsIsSupported(CsrUint16 interfaceTag);
+
+#ifdef CSR_LOG_ENABLE
+/**
+ * @brief
+ *     Registers the virtual interface utils logging details.
+ *     Should only be called once at initialisation.
+ *
+ * @param[in/out] None
+ *
+ * @return
+ *     None
+ */
+void CsrWifiVifUtilsLogTextRegister(void);
+#else
+#define CsrWifiVifUtilsLogTextRegister()
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CSR_WIFI_VIF_UTILS_H */
+
diff --git a/drivers/staging/csr/data_tx.c b/drivers/staging/csr/data_tx.c
new file mode 100644
index 0000000..c5858a5
--- /dev/null
+++ b/drivers/staging/csr/data_tx.c
@@ -0,0 +1,57 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     data_tx.c
+ *
+ * PURPOSE:
+ *      This file provides functions to send data requests to the UniFi.
+ *
+ * Copyright (C) 2007-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "unifi_priv.h"
+
+int
+uf_verify_m4(unifi_priv_t *priv, const unsigned char *packet, unsigned int length)
+{
+    const unsigned char *p = packet;
+    CsrUint16 keyinfo;
+
+
+    if (length < (4 + 5 + 8 + 32 + 16 + 8 + 8 + 16 + 1 + 8)) {
+        return 1;
+    }
+
+    p += 8;
+    keyinfo = p[5] << 8 | p[6]; /* big-endian */
+    if (
+          (p[0] == 1 || p[0] == 2) /* protocol version 802.1X-2001 (WPA) or -2004 (WPA2) */ &&
+          p[1] == 3 /* EAPOL-Key */ &&
+          /* don't bother checking p[2] p[3] (hh ll, packet body length) */
+          (p[4] == 254 || p[4] == 2) /* descriptor type P802.1i-D3.0 (WPA) or 802.11i-2004 (WPA2) */ &&
+          ((keyinfo & 0x0007) == 1 || (keyinfo & 0x0007) == 2) /* key descriptor version */ &&
+         (keyinfo & ~0x0207U) == 0x0108 && /* key info for 4/4 or 4/2 -- ignore key desc version and sec bit (since varies in WPA 4/4) */
+          (p[4 + 5 + 8 + 32 + 16 + 8 + 8 + 16 + 0] == 0 && /* key data length (2 octets) 0 for 4/4 only */
+           p[4 + 5 + 8 + 32 + 16 + 8 + 8 + 16 + 1] == 0)
+        ) {
+        unifi_trace(priv, UDBG1, "uf_verify_m4: M4 detected \n");
+        return 0;
+    }
+    else
+    {
+        return 1;
+    }
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ *      Data transport signals.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
diff --git a/drivers/staging/csr/drv.c b/drivers/staging/csr/drv.c
new file mode 100644
index 0000000..fbe8630
--- /dev/null
+++ b/drivers/staging/csr/drv.c
@@ -0,0 +1,2263 @@
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     drv.c
+ *
+ *  PURPOSE:
+ *      Conventional device interface for debugging/monitoring of the
+ *      driver and h/w using unicli. This interface is also being used
+ *      by the SME linux implementation and the helper apps.
+ *
+ * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+
+
+/*
+ * Porting Notes:
+ * Part of this file contains an example for how to glue the OS layer
+ * with the HIP core lib, the SDIO glue layer, and the SME.
+ *
+ * When the unifi_sdio.ko modules loads, the linux kernel calls unifi_load().
+ * unifi_load() calls uf_sdio_load() which is exported by the SDIO glue
+ * layer. uf_sdio_load() registers this driver with the underlying SDIO driver.
+ * When a card is detected, the SDIO glue layer calls register_unifi_sdio()
+ * to pass the SDIO function context and ask the OS layer to initialise
+ * the card. register_unifi_sdio() allocates all the private data of the OS
+ * layer and calls uf_run_unifihelper() to start the SME. The SME calls
+ * unifi_sys_wifi_on_req() which uses the HIP core lib to initialise the card.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include <linux/jiffies.h>
+
+#include "csr_wifi_hip_unifiversion.h"
+#include "unifi_priv.h"
+#include "csr_wifi_hip_conversions.h"
+#include "unifi_native.h"
+
+/* Module parameter variables */
+int buswidth = 0;               /* 0 means use default, values 1,4 */
+int sdio_clock = 50000;         /* kHz */
+int unifi_debug = 0;
+/* fw_init prevents f/w initialisation on error. */
+int fw_init[MAX_UNIFI_DEVS] = {-1, -1};
+int use_5g = 0;
+int led_mask = 0;               /* 0x0c00 for dev-pc-1503c, dev-pc-1528a */
+int disable_hw_reset = 0;
+int disable_power_control = 0;
+int enable_wol = UNIFI_WOL_OFF; /* 0 for none, 1 for SDIO IRQ, 2 for PIO */
+#if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
+int tl_80211d = (int)CSR_WIFI_SME_80211D_TRUST_LEVEL_MIB;
+#endif
+int sdio_block_size = -1;      /* Override SDIO block size */
+int sdio_byte_mode = 0;        /* 0 for block mode + padding, 1 for byte mode */
+int coredump_max = CSR_WIFI_HIP_NUM_COREDUMP_BUFFERS;
+int run_bh_once = -1;          /* Set for scheduled interrupt mode, -1 = default */
+int bh_priority = -1;
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+#define UNIFI_LOG_HIP_SIGNALS_FILTER_SIGNAL     (1 << 0)
+#define UNIFI_LOG_HIP_SIGNALS_FILTER_BULKDATA   (1 << 1)
+#define UNIFI_LOG_HIP_SIGNALS_FILTER_TIMESTAMP  (1 << 2)
+int log_hip_signals = 0;
+#endif
+
+MODULE_DESCRIPTION("CSR UniFi (SDIO)");
+
+module_param(buswidth,    int, S_IRUGO|S_IWUSR);
+module_param(sdio_clock,  int, S_IRUGO|S_IWUSR);
+module_param(unifi_debug, int, S_IRUGO|S_IWUSR);
+module_param_array(fw_init, int, NULL, S_IRUGO|S_IWUSR);
+module_param(use_5g,      int, S_IRUGO|S_IWUSR);
+module_param(led_mask,    int, S_IRUGO|S_IWUSR);
+module_param(disable_hw_reset,  int, S_IRUGO|S_IWUSR);
+module_param(disable_power_control,  int, S_IRUGO|S_IWUSR);
+module_param(enable_wol,  int, S_IRUGO|S_IWUSR);
+#if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
+module_param(tl_80211d,   int, S_IRUGO|S_IWUSR);
+#endif
+module_param(sdio_block_size, int, S_IRUGO|S_IWUSR);
+module_param(sdio_byte_mode, int, S_IRUGO|S_IWUSR);
+module_param(coredump_max, int, S_IRUGO|S_IWUSR);
+module_param(run_bh_once, int, S_IRUGO|S_IWUSR);
+module_param(bh_priority, int, S_IRUGO|S_IWUSR);
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+module_param(log_hip_signals, int, S_IRUGO|S_IWUSR);
+#endif
+
+MODULE_PARM_DESC(buswidth, "SDIO bus width (0=default), set 1 for 1-bit or 4 for 4-bit mode");
+MODULE_PARM_DESC(sdio_clock, "SDIO bus frequency in kHz, (default = 50 MHz)");
+MODULE_PARM_DESC(unifi_debug, "Diagnostic reporting level");
+MODULE_PARM_DESC(fw_init, "Set to 0 to prevent f/w initialization on error");
+MODULE_PARM_DESC(use_5g, "Use the 5G (802.11a) radio band");
+MODULE_PARM_DESC(led_mask, "LED mask flags");
+MODULE_PARM_DESC(disable_hw_reset, "Set to 1 to disable hardware reset");
+MODULE_PARM_DESC(disable_power_control, "Set to 1 to disable SDIO power control");
+MODULE_PARM_DESC(enable_wol, "Enable wake-on-wlan function 0=off, 1=SDIO, 2=PIO");
+#if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
+MODULE_PARM_DESC(tl_80211d, "802.11d Trust Level (1-6, default = 5)");
+#endif
+MODULE_PARM_DESC(sdio_block_size, "Set to override SDIO block size");
+MODULE_PARM_DESC(sdio_byte_mode, "Set to 1 for byte mode SDIO");
+MODULE_PARM_DESC(coredump_max, "Number of chip mini-coredump buffers to allocate");
+MODULE_PARM_DESC(run_bh_once, "Run BH only when firmware interrupts");
+MODULE_PARM_DESC(bh_priority, "Modify the BH thread priority");
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+MODULE_PARM_DESC(log_hip_signals, "Set to 1 to enable HIP signal offline logging");
+#endif
+
+
+/* Callback for event logging to UDI clients */
+static void udi_log_event(ul_client_t *client,
+                          const u8 *signal, int signal_len,
+                          const bulk_data_param_t *bulkdata,
+                          int dir);
+
+static void udi_set_log_filter(ul_client_t *pcli,
+                               unifiio_filter_t *udi_filter);
+
+
+/* Mutex to protect access to  priv->sme_cli */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+DEFINE_SEMAPHORE(udi_mutex);
+#else
+DECLARE_MUTEX(udi_mutex);
+#endif
+
+CsrInt32 CsrHipResultToStatus(CsrResult csrResult)
+{
+    CsrInt32 r = -EIO;
+
+    switch (csrResult)
+    {
+    case CSR_RESULT_SUCCESS:
+        r = 0;
+        break;
+    case CSR_WIFI_HIP_RESULT_RANGE:
+        r = -ERANGE;
+        break;
+    case CSR_WIFI_HIP_RESULT_NO_DEVICE:
+        r = -ENODEV;
+        break;
+    case CSR_WIFI_HIP_RESULT_INVALID_VALUE:
+        r = -EINVAL;
+        break;
+    case CSR_WIFI_HIP_RESULT_NOT_FOUND:
+        r = -ENOENT;
+        break;
+    case CSR_WIFI_HIP_RESULT_NO_SPACE:
+        r = -ENOSPC;
+        break;
+    case CSR_WIFI_HIP_RESULT_NO_MEMORY:
+        r = -ENOMEM;
+        break;
+    case CSR_RESULT_FAILURE:
+        r = -EIO;
+        break;
+    default:
+        /*unifi_warning(card->ospriv, "CsrHipResultToStatus: Unrecognised csrResult error code: %d\n", csrResult);*/
+        r = -EIO;
+    }
+    return r;
+}
+
+
+static const char*
+trace_putest_cmdid(unifi_putest_command_t putest_cmd)
+{
+    switch (putest_cmd)
+    {
+        case UNIFI_PUTEST_START:
+            return "START";
+        case UNIFI_PUTEST_STOP:
+            return "STOP";
+        case UNIFI_PUTEST_SET_SDIO_CLOCK:
+            return "SET CLOCK";
+        case UNIFI_PUTEST_CMD52_READ:
+            return "CMD52R";
+        case UNIFI_PUTEST_CMD52_BLOCK_READ:
+            return "CMD52BR";
+        case UNIFI_PUTEST_CMD52_WRITE:
+            return "CMD52W";
+        case UNIFI_PUTEST_DL_FW:
+            return "D/L FW";
+        case UNIFI_PUTEST_DL_FW_BUFF:
+            return "D/L FW BUFFER";
+        case UNIFI_PUTEST_COREDUMP_PREPARE:
+            return "PREPARE COREDUMP";
+        case UNIFI_PUTEST_GP_READ16:
+            return "GP16R";
+        case UNIFI_PUTEST_GP_WRITE16:
+            return "GP16W";
+        default:
+            return "ERROR: unrecognised command";
+    }
+ }
+
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+int uf_register_hip_offline_debug(unifi_priv_t *priv)
+{
+    ul_client_t *udi_cli;
+    int i;
+
+    udi_cli = ul_register_client(priv, CLI_USING_WIRE_FORMAT, udi_log_event);
+    if (udi_cli == NULL) {
+        /* Too many clients already using this device */
+        unifi_error(priv, "Too many UDI clients already open\n");
+        return -ENOSPC;
+    }
+    unifi_trace(priv, UDBG1, "Offline HIP client is registered\n");
+
+    down(&priv->udi_logging_mutex);
+    udi_cli->event_hook = udi_log_event;
+    unifi_set_udi_hook(priv->card, logging_handler);
+    /* Log all signals by default */
+    for (i = 0; i < SIG_FILTER_SIZE; i++) {
+        udi_cli->signal_filter[i] = 0xFFFF;
+    }
+    priv->logging_client = udi_cli;
+    up(&priv->udi_logging_mutex);
+
+    return 0;
+}
+
+int uf_unregister_hip_offline_debug(unifi_priv_t *priv)
+{
+    ul_client_t *udi_cli = priv->logging_client;
+    if (udi_cli == NULL)
+    {
+        unifi_error(priv, "Unknown HIP client unregister request\n");
+        return -ERANGE;
+    }
+
+    unifi_trace(priv, UDBG1, "Offline HIP client is unregistered\n");
+
+    down(&priv->udi_logging_mutex);
+    priv->logging_client = NULL;
+    udi_cli->event_hook = NULL;
+    up(&priv->udi_logging_mutex);
+
+    ul_deregister_client(udi_cli);
+
+    return 0;
+}
+#endif
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_open
+ *  unifi_release
+ *
+ *      Open and release entry points for the UniFi debug driver.
+ *
+ *  Arguments:
+ *      Normal linux driver args.
+ *
+ *  Returns:
+ *      Linux error code.
+ * ---------------------------------------------------------------------------
+ */
+static int
+unifi_open(struct inode *inode, struct file *file)
+{
+    int devno;
+    unifi_priv_t *priv;
+    ul_client_t *udi_cli;
+
+    func_enter();
+
+    devno = MINOR(inode->i_rdev) >> 1;
+
+    /*
+     * Increase the ref_count for the char device clients.
+     * Make sure you call uf_put_instance() to decreace it if
+     * unifi_open returns an error.
+     */
+    priv = uf_get_instance(devno);
+    if (priv == NULL) {
+        unifi_error(NULL, "unifi_open: No device present\n");
+        func_exit();
+        return -ENODEV;
+    }
+
+    /* Register this instance in the client's list. */
+    /* The minor number determines the nature of the client (Unicli or SME). */
+    if (MINOR(inode->i_rdev) & 0x1) {
+        udi_cli = ul_register_client(priv, CLI_USING_WIRE_FORMAT, udi_log_event);
+        if (udi_cli == NULL) {
+            /* Too many clients already using this device */
+            unifi_error(priv, "Too many clients already open\n");
+            uf_put_instance(devno);
+            func_exit();
+            return -ENOSPC;
+        }
+        unifi_trace(priv, UDBG1, "Client is registered to /dev/unifiudi%d\n", devno);
+    } else {
+        /*
+         * Even-numbered device nodes are the control application.
+         * This is the userspace helper containing SME or
+         * unifi_manager.
+         */
+
+        down(&udi_mutex);
+
+#ifdef CSR_SME_USERSPACE
+        /* Check if a config client is already attached */
+        if (priv->sme_cli) {
+            up(&udi_mutex);
+            uf_put_instance(devno);
+
+            unifi_info(priv, "There is already a configuration client using the character device\n");
+            func_exit();
+            return -EBUSY;
+        }
+#endif /* CSR_SME_USERSPACE */
+
+#ifdef CSR_SUPPORT_SME
+        udi_cli = ul_register_client(priv,
+                                     CLI_USING_WIRE_FORMAT | CLI_SME_USERSPACE,
+                                     sme_log_event);
+#else
+        /* Config client for native driver */
+        udi_cli = ul_register_client(priv,
+                                     0,
+                                     sme_native_log_event);
+#endif
+        if (udi_cli == NULL) {
+            /* Too many clients already using this device */
+            up(&udi_mutex);
+            uf_put_instance(devno);
+
+            unifi_error(priv, "Too many clients already open\n");
+            func_exit();
+            return -ENOSPC;
+        }
+
+        /*
+         * Fill-in the pointer to the configuration client.
+         * This is the SME userspace helper or unifi_manager.
+         * Not used in the SME embedded version.
+         */
+        unifi_trace(priv, UDBG1, "SME client (id:%d s:0x%X) is registered\n",
+                    udi_cli->client_id, udi_cli->sender_id);
+        /* Store the SME UniFi Linux Client */
+        if (priv->sme_cli == NULL) {
+            priv->sme_cli = udi_cli;
+        }
+
+        up(&udi_mutex);
+    }
+
+
+    /*
+     * Store the pointer to the client.
+     * All char driver's entry points will pass this pointer.
+     */
+    file->private_data = udi_cli;
+
+    func_exit();
+    return 0;
+} /* unifi_open() */
+
+
+static int
+unifi_release(struct inode *inode, struct file *filp)
+{
+    ul_client_t *udi_cli = (void*)filp->private_data;
+    int devno;
+    unifi_priv_t *priv;
+
+    func_enter();
+
+    priv = uf_find_instance(udi_cli->instance);
+    if (!priv) {
+        unifi_error(priv, "unifi_close: instance for device not found\n");
+        return -ENODEV;
+    }
+
+    devno = MINOR(inode->i_rdev) >> 1;
+
+    /* Even device nodes are the config client (i.e. SME or unifi_manager) */
+    if ((MINOR(inode->i_rdev) & 0x1) == 0) {
+
+        if (priv->sme_cli != udi_cli) {
+            unifi_notice(priv, "Surprise closing config device: not the sme client\n");
+        }
+        unifi_notice(priv, "SME client close (unifi%d)\n", devno);
+
+        /*
+         * Clear sme_cli before calling unifi_sys_... so it doesn't try to
+         * queue a reply to the (now gone) SME.
+         */
+        down(&udi_mutex);
+        priv->sme_cli = NULL;
+        up(&udi_mutex);
+
+#ifdef CSR_SME_USERSPACE
+        /* Power-down when config client closes */
+        {
+            CsrWifiRouterCtrlWifiOffReq req = {{CSR_WIFI_ROUTER_CTRL_HIP_REQ, 0, 0, 0, NULL}};
+            CsrWifiRouterCtrlWifiOffReqHandler(priv, &req.common);
+        }
+
+        uf_sme_deinit(priv);
+
+       /* It is possible that a blocking SME request was made from another process
+        * which did not get read by the SME before the WifiOffReq.
+        * So check for a pending request which will go unanswered and cancel
+        * the wait for event. As only one blocking request can be in progress at
+        * a time, up to one event should be completed.
+        */
+       uf_sme_cancel_request(priv, 0);
+
+#endif /* CSR_SME_USERSPACE */
+    } else {
+
+        unifi_trace(priv, UDBG2, "UDI client close (unifiudi%d)\n", devno);
+
+        /* If the pointer matches the logging client, stop logging. */
+        down(&priv->udi_logging_mutex);
+        if (udi_cli == priv->logging_client) {
+            priv->logging_client = NULL;
+        }
+        up(&priv->udi_logging_mutex);
+
+        if (udi_cli == priv->amp_client) {
+            priv->amp_client = NULL;
+        }
+    }
+
+    /* Deregister this instance from the client's list. */
+    ul_deregister_client(udi_cli);
+
+    uf_put_instance(devno);
+
+    return 0;
+} /* unifi_release() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_read
+ *
+ *      The read() driver entry point.
+ *
+ *  Arguments:
+ *      filp        The file descriptor returned by unifi_open()
+ *      p           The user space buffer to copy the read data
+ *      len         The size of the p buffer
+ *      poff
+ *
+ *  Returns:
+ *      number of bytes read or an error code on failure
+ * ---------------------------------------------------------------------------
+ */
+static ssize_t
+unifi_read(struct file *filp, char *p, size_t len, loff_t *poff)
+{
+    ul_client_t *pcli = (void*)filp->private_data;
+    unifi_priv_t *priv;
+    udi_log_t *logptr = NULL;
+    udi_msg_t *msgptr;
+    struct list_head *l;
+    int msglen;
+
+    func_enter();
+
+    priv = uf_find_instance(pcli->instance);
+    if (!priv) {
+        unifi_error(priv, "invalid priv\n");
+        return -ENODEV;
+    }
+
+    if (!pcli->udi_enabled) {
+        unifi_error(priv, "unifi_read: unknown client.");
+        return -EINVAL;
+    }
+
+    if (list_empty(&pcli->udi_log)) {
+        if (filp->f_flags & O_NONBLOCK) {
+            /* Non-blocking - just return if the udi_log is empty */
+            return 0;
+        } else {
+            /* Blocking - wait on the UDI wait queue */
+            if (wait_event_interruptible(pcli->udi_wq,
+                !list_empty(&pcli->udi_log)))
+            {
+                unifi_error(priv, "unifi_read: wait_event_interruptible failed.");
+                return -ERESTARTSYS;
+            }
+        }
+    }
+
+    /* Read entry from list head and remove it from the list */
+    if (down_interruptible(&pcli->udi_sem)) {
+        return -ERESTARTSYS;
+    }
+    l = pcli->udi_log.next;
+    list_del(l);
+    up(&pcli->udi_sem);
+
+    /* Get a pointer to whole struct */
+    logptr = list_entry(l, udi_log_t, q);
+    if (logptr == NULL) {
+        unifi_error(priv, "unifi_read: failed to get event.\n");
+        return -EINVAL;
+    }
+
+    /* Get the real message */
+    msgptr = &logptr->msg;
+    msglen = msgptr->length;
+    if (msglen > len) {
+        printk(KERN_WARNING "truncated read to %d actual msg len is %lu\n", msglen, (long unsigned int)len);
+        msglen = len;
+    }
+
+    /* and pass it to the client (SME or Unicli). */
+    if (copy_to_user(p, msgptr, msglen))
+    {
+        printk(KERN_ERR "Failed to copy UDI log to user\n");
+        kfree(logptr);
+        return -EFAULT;
+    }
+
+    /* It is our resposibility to free the message buffer. */
+    kfree(logptr);
+
+    func_exit_r(msglen);
+    return msglen;
+
+} /* unifi_read() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * udi_send_signal_unpacked
+ *
+ *      Sends an unpacked signal to UniFi.
+ *
+ * Arguments:
+ *      priv            Pointer to private context struct
+ *      data            Pointer to request structure and data to send
+ *      data_len        Length of data in data pointer.
+ *
+ * Returns:
+ *      Number of bytes written, error otherwise.
+ *
+ * Notes:
+ *      All clients that use this function to send a signal to the unifi
+ *      must use the host formatted structures.
+ * ---------------------------------------------------------------------------
+ */
+static int
+udi_send_signal_unpacked(unifi_priv_t *priv, unsigned char* data, uint data_len)
+{
+    CSR_SIGNAL *sigptr = (CSR_SIGNAL*)data;
+    CSR_DATAREF *datarefptr;
+    bulk_data_param_t bulk_data;
+    uint signal_size, i;
+    uint bulk_data_offset = 0;
+    int bytecount, r;
+    CsrResult csrResult;
+
+    /* Number of bytes in the signal */
+    signal_size = SigGetSize(sigptr);
+    if (!signal_size || (signal_size > data_len)) {
+        unifi_error(priv, "unifi_sme_mlme_req - Invalid signal 0x%x size should be %d bytes\n",
+                    sigptr->SignalPrimitiveHeader.SignalId,
+                    signal_size);
+        return -EINVAL;
+    }
+    bytecount = signal_size;
+
+    /* Get a pointer to the information of the first data reference */
+    datarefptr = (CSR_DATAREF*)&sigptr->u;
+
+    /* Initialize the offset in the data buffer, bulk data is right after the signal. */
+    bulk_data_offset = signal_size;
+
+    /* store the references and the size of the bulk data to the bulkdata structure */
+    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
+        /* the length of the bulk data is in the signal */
+        if ((datarefptr+i)->DataLength) {
+            void *dest;
+
+            csrResult = unifi_net_data_malloc(priv, &bulk_data.d[i], (datarefptr+i)->DataLength);
+            if (csrResult != CSR_RESULT_SUCCESS) {
+                unifi_error(priv, "udi_send_signal_unpacked: failed to allocate request_data.\n");
+                return -EIO;
+            }
+
+            dest = (void*)bulk_data.d[i].os_data_ptr;
+            memcpy(dest, data + bulk_data_offset, bulk_data.d[i].data_length);
+        } else {
+            bulk_data.d[i].data_length = 0;
+        }
+
+        bytecount += bulk_data.d[i].data_length;
+        /* advance the offset, to point the next bulk data */
+        bulk_data_offset += bulk_data.d[i].data_length;
+    }
+
+
+    unifi_trace(priv, UDBG3, "SME Send: signal 0x%.4X\n", sigptr->SignalPrimitiveHeader.SignalId);
+
+    /* Send the signal. */
+    r = ul_send_signal_unpacked(priv, sigptr, &bulk_data);
+    if (r < 0) {
+        unifi_error(priv, "udi_send_signal_unpacked: send failed (%d)\n", r);
+        for(i=0;i<UNIFI_MAX_DATA_REFERENCES;i++) {
+            if(bulk_data.d[i].data_length != 0) {
+                unifi_net_data_free(priv, &bulk_data.d[i]);
+            }
+        }
+        func_exit();
+        return -EIO;
+    }
+
+    return bytecount;
+} /* udi_send_signal_unpacked() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * udi_send_signal_raw
+ *
+ *      Sends a packed signal to UniFi.
+ *
+ * Arguments:
+ *      priv            Pointer to private context struct
+ *      buf             Pointer to request structure and data to send
+ *      buflen          Length of data in data pointer.
+ *
+ * Returns:
+ *      Number of bytes written, error otherwise.
+ *
+ * Notes:
+ *      All clients that use this function to send a signal to the unifi
+ *      must use the wire formatted structures.
+ * ---------------------------------------------------------------------------
+ */
+static int
+udi_send_signal_raw(unifi_priv_t *priv, unsigned char *buf, int buflen)
+{
+    int signal_size;
+    int sig_id;
+    bulk_data_param_t data_ptrs;
+    int i, r;
+    unsigned int num_data_refs;
+    int bytecount;
+    CsrResult csrResult;
+
+    func_enter();
+
+    /*
+     * The signal is the first thing in buf, the signal id is the
+     * first 16 bits of the signal.
+     */
+    /* Number of bytes in the signal */
+    sig_id = GET_SIGNAL_ID(buf);
+    signal_size = buflen;
+    signal_size -= GET_PACKED_DATAREF_LEN(buf, 0);
+    signal_size -= GET_PACKED_DATAREF_LEN(buf, 1);
+    if ((signal_size <= 0) || (signal_size > buflen)) {
+        unifi_error(priv, "udi_send_signal_raw - Couldn't find length of signal 0x%x\n",
+                    sig_id);
+        func_exit();
+        return -EINVAL;
+    }
+    unifi_trace(priv, UDBG2, "udi_send_signal_raw: signal 0x%.4X len:%d\n",
+                sig_id, signal_size);
+    /* Zero the data ref arrays */
+    memset(&data_ptrs, 0, sizeof(data_ptrs));
+
+    /*
+     * Find the number of associated bulk data packets.  Scan through
+     * the data refs to check that we have enough data and pick out
+     * pointers to appended bulk data.
+     */
+    num_data_refs = 0;
+    bytecount = signal_size;
+
+    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; ++i)
+    {
+        unsigned int len = GET_PACKED_DATAREF_LEN(buf, i);
+        unifi_trace(priv, UDBG3, "udi_send_signal_raw: data_ref length = %d\n", len);
+
+        if (len != 0) {
+            void *dest;
+
+            csrResult = unifi_net_data_malloc(priv, &data_ptrs.d[i], len);
+            if (csrResult != CSR_RESULT_SUCCESS) {
+                unifi_error(priv, "udi_send_signal_raw: failed to allocate request_data.\n");
+                return -EIO;
+            }
+
+            dest = (void*)data_ptrs.d[i].os_data_ptr;
+            memcpy(dest, buf + bytecount, len);
+
+            bytecount += len;
+            num_data_refs++;
+        }
+        data_ptrs.d[i].data_length = len;
+    }
+
+    unifi_trace(priv, UDBG3, "Queueing signal 0x%.4X from UDI with %u data refs\n",
+          sig_id,
+          num_data_refs);
+
+    if (bytecount > buflen) {
+        unifi_error(priv, "udi_send_signal_raw: Not enough data (%d instead of %d)\n", buflen, bytecount);
+        func_exit();
+        return -EINVAL;
+    }
+
+    /* Send the signal calling the function that uses the wire-formatted signals. */
+    r = ul_send_signal_raw(priv, buf, signal_size, &data_ptrs);
+    if (r < 0) {
+        unifi_error(priv, "udi_send_signal_raw: send failed (%d)\n", r);
+        func_exit();
+        return -EIO;
+    }
+
+#ifdef CSR_NATIVE_LINUX
+    if (sig_id == CSR_MLME_POWERMGT_REQUEST_ID) {
+        int power_mode = CSR_GET_UINT16_FROM_LITTLE_ENDIAN((buf +
+                                              SIZEOF_SIGNAL_HEADER + (UNIFI_MAX_DATA_REFERENCES*SIZEOF_DATAREF)));
+#ifdef CSR_SUPPORT_WEXT
+        /* Overide the wext power mode to the new value */
+        priv->wext_conf.power_mode = power_mode;
+#endif
+        /* Configure deep sleep signaling */
+        if (power_mode || (priv->interfacePriv[0]->connected == UnifiNotConnected)) {
+            csrResult = unifi_configure_low_power_mode(priv->card,
+                                                   UNIFI_LOW_POWER_ENABLED,
+                                                   UNIFI_PERIODIC_WAKE_HOST_DISABLED);
+        } else {
+            csrResult = unifi_configure_low_power_mode(priv->card,
+                                                   UNIFI_LOW_POWER_DISABLED,
+                                                   UNIFI_PERIODIC_WAKE_HOST_DISABLED);
+        }
+    }
+#endif
+
+    func_exit_r(bytecount);
+
+    return bytecount;
+} /* udi_send_signal_raw */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_write
+ *
+ *      The write() driver entry point.
+ *      A UniFi Debug Interface client such as unicli can write a signal
+ *      plus bulk data to the driver for sending to the UniFi chip.
+ *
+ *      Only one signal may be sent per write operation.
+ *
+ *  Arguments:
+ *      filp        The file descriptor returned by unifi_open()
+ *      p           The user space buffer to get the data from
+ *      len         The size of the p buffer
+ *      poff
+ *
+ *  Returns:
+ *      number of bytes written or an error code on failure
+ * ---------------------------------------------------------------------------
+ */
+static ssize_t
+unifi_write(struct file *filp, const char *p, size_t len, loff_t *poff)
+{
+    ul_client_t *pcli = (ul_client_t*)filp->private_data;
+    unifi_priv_t *priv;
+    unsigned char *buf;
+    unsigned char *bufptr;
+    int remaining;
+    int bytes_written;
+    int r;
+    bulk_data_param_t bulkdata;
+    CsrResult csrResult;
+
+    func_enter();
+
+    priv = uf_find_instance(pcli->instance);
+    if (!priv) {
+        unifi_error(priv, "invalid priv\n");
+        return -ENODEV;
+    }
+
+    unifi_trace(priv, UDBG5, "unifi_write: len = %d\n", len);
+
+    if (!pcli->udi_enabled) {
+        unifi_error(priv, "udi disabled\n");
+        return -EINVAL;
+    }
+
+    /*
+     * AMP client sends only one signal at a time, so we can use
+     * unifi_net_data_malloc to save the extra copy.
+     */
+    if (pcli == priv->amp_client) {
+        int signal_size;
+        int sig_id;
+        unsigned char *signal_buf;
+        char *user_data_buf;
+
+        csrResult = unifi_net_data_malloc(priv, &bulkdata.d[0], len);
+        if (csrResult != CSR_RESULT_SUCCESS) {
+            unifi_error(priv, "unifi_write: failed to allocate request_data.\n");
+            func_exit();
+            return -ENOMEM;
+        }
+
+        user_data_buf = (char*)bulkdata.d[0].os_data_ptr;
+
+        /* Get the data from the AMP client. */
+        if (copy_from_user((void*)user_data_buf, p, len)) {
+            unifi_error(priv, "unifi_write: copy from user failed\n");
+            unifi_net_data_free(priv, &bulkdata.d[0]);
+            func_exit();
+            return -EFAULT;
+        }
+
+        bulkdata.d[1].os_data_ptr = NULL;
+        bulkdata.d[1].data_length = 0;
+
+        /* Number of bytes in the signal */
+        sig_id = GET_SIGNAL_ID(bulkdata.d[0].os_data_ptr);
+        signal_size = len;
+        signal_size -= GET_PACKED_DATAREF_LEN(bulkdata.d[0].os_data_ptr, 0);
+        signal_size -= GET_PACKED_DATAREF_LEN(bulkdata.d[0].os_data_ptr, 1);
+        if ((signal_size <= 0) || (signal_size > len)) {
+            unifi_error(priv, "unifi_write - Couldn't find length of signal 0x%x\n",
+                        sig_id);
+            unifi_net_data_free(priv, &bulkdata.d[0]);
+            func_exit();
+            return -EINVAL;
+        }
+
+        unifi_trace(priv, UDBG2, "unifi_write: signal 0x%.4X len:%d\n",
+                    sig_id, signal_size);
+
+        /* Allocate a buffer for the signal */
+        signal_buf = kmalloc(signal_size, GFP_KERNEL);
+        if (!signal_buf) {
+            unifi_net_data_free(priv, &bulkdata.d[0]);
+            func_exit();
+            return -ENOMEM;
+        }
+
+        /* Get the signal from the os_data_ptr */
+        memcpy(signal_buf, bulkdata.d[0].os_data_ptr, signal_size);
+        signal_buf[5] = (pcli->sender_id >> 8) & 0xff;
+
+        if (signal_size < len) {
+            /* Remove the signal from the os_data_ptr */
+            bulkdata.d[0].data_length -= signal_size;
+            bulkdata.d[0].os_data_ptr += signal_size;
+        } else {
+            bulkdata.d[0].data_length = 0;
+            bulkdata.d[0].os_data_ptr = NULL;
+        }
+
+        /* Send the signal calling the function that uses the wire-formatted signals. */
+        r = ul_send_signal_raw(priv, signal_buf, signal_size, &bulkdata);
+        if (r < 0) {
+            unifi_error(priv, "unifi_write: send failed (%d)\n", r);
+            if (bulkdata.d[0].os_data_ptr != NULL) {
+                unifi_net_data_free(priv, &bulkdata.d[0]);
+            }
+        }
+
+        /* Free the signal buffer and return */
+        kfree(signal_buf);
+        return len;
+    }
+
+    buf = kmalloc(len, GFP_KERNEL);
+    if (!buf) {
+        return -ENOMEM;
+    }
+
+    /* Get the data from the client (SME or Unicli). */
+    if (copy_from_user((void*)buf, p, len)) {
+        unifi_error(priv, "copy from user failed\n");
+        kfree(buf);
+        return -EFAULT;
+    }
+
+    /*
+     * In SME userspace build read() contains a SYS or MGT message.
+     * Note that even though the SME sends one signal at a time, we can not
+     * use unifi_net_data_malloc because in the early stages, before having
+     * initialised the core, it will fail since the I/O block size is unknown.
+     */
+#ifdef CSR_SME_USERSPACE
+    if (pcli->configuration & CLI_SME_USERSPACE) {
+        CsrWifiRouterTransportRecv(priv, buf, len);
+        kfree(buf);
+        return len;
+    }
+#endif
+
+    /* ul_send_signal_raw will  do a sanity check of len against signal content */
+
+    /*
+     * udi_send_signal_raw() and udi_send_signal_unpacked() return the number of bytes consumed.
+     * A write call can pass multiple signal concatenated together.
+     */
+    bytes_written = 0;
+    remaining = len;
+    bufptr = buf;
+    while (remaining > 0)
+    {
+        int r;
+
+        /*
+         * Set the SenderProcessId.
+         * The SignalPrimitiveHeader is the first 3 16-bit words of the signal,
+         * the SenderProcessId is bytes 4,5.
+         * The MSB of the sender ID needs to be set to the client ID.
+         * The LSB is controlled by the SME.
+         */
+        bufptr[5] = (pcli->sender_id >> 8) & 0xff;
+
+        /* use the appropriate interface, depending on the clients' configuration */
+        if (pcli->configuration & CLI_USING_WIRE_FORMAT) {
+            unifi_trace(priv, UDBG1, "unifi_write: call udi_send_signal().\n");
+            r = udi_send_signal_raw(priv, bufptr, remaining);
+        } else {
+            r = udi_send_signal_unpacked(priv, bufptr, remaining);
+        }
+        if (r < 0) {
+            /* Set the return value to the error code */
+            unifi_error(priv, "unifi_write: (udi or sme)_send_signal() returns %d\n", r);
+            bytes_written = r;
+            break;
+        }
+        bufptr += r;
+        remaining -= r;
+        bytes_written += r;
+    }
+
+    kfree(buf);
+
+    func_exit_r(bytes_written);
+
+    return bytes_written;
+} /* unifi_write() */
+
+
+static const char* build_type_to_string(unsigned char build_type)
+{
+    switch (build_type)
+    {
+    case UNIFI_BUILD_NME: return "NME";
+    case UNIFI_BUILD_WEXT: return "WEXT";
+    case UNIFI_BUILD_AP: return "AP";
+    }
+    return "unknown";
+}
+
+
+/*
+ * ----------------------------------------------------------------
+ *  unifi_ioctl
+ *
+ *      Ioctl handler for unifi driver.
+ *
+ * Arguments:
+ *  inodep          Pointer to inode structure.
+ *  filp            Pointer to file structure.
+ *  cmd             Ioctl cmd passed by user.
+ *  arg             Ioctl arg passed by user.
+ *
+ * Returns:
+ *      0 on success, -ve error code on error.
+ * ----------------------------------------------------------------
+ */
+static long
+unifi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+    ul_client_t *pcli = (ul_client_t*)filp->private_data;
+    unifi_priv_t *priv;
+    struct net_device *dev;
+    int r = 0;
+    int int_param, i;
+    u8* buf;
+    CsrResult csrResult;
+#if (defined CSR_SUPPORT_SME)
+    unifi_cfg_command_t cfg_cmd;
+#if (defined CSR_SUPPORT_WEXT)
+    CsrWifiSmeCoexConfig coex_config;
+    unsigned char uchar_param;
+    unsigned char varbind[MAX_VARBIND_LENGTH];
+    int vblen;
+#endif
+#endif
+    unifi_putest_command_t putest_cmd;
+
+    priv = uf_find_instance(pcli->instance);
+    if (!priv) {
+        unifi_error(priv, "ioctl error: unknown instance=%d\n", pcli->instance);
+        r = -ENODEV;
+        goto out;
+    }
+    unifi_trace(priv, UDBG5, "unifi_ioctl: cmd=0x%X, arg=0x%lX\n", cmd, arg);
+
+    switch (cmd) {
+
+      case UNIFI_GET_UDI_ENABLE:
+        unifi_trace(priv, UDBG4, "UniFi Get UDI Enable\n");
+
+        down(&priv->udi_logging_mutex);
+        int_param = (priv->logging_client == NULL) ? 0 : 1;
+        up(&priv->udi_logging_mutex);
+
+        if (put_user(int_param, (int*)arg))
+        {
+            unifi_error(priv, "UNIFI_GET_UDI_ENABLE: Failed to copy to user\n");
+            r = -EFAULT;
+            goto out;
+        }
+        break;
+
+      case UNIFI_SET_UDI_ENABLE:
+        unifi_trace(priv, UDBG4, "UniFi Set UDI Enable\n");
+        if (get_user(int_param, (int*)arg))
+        {
+            unifi_error(priv, "UNIFI_SET_UDI_ENABLE: Failed to copy from user\n");
+            r = -EFAULT;
+            goto out;
+        }
+
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+        if (log_hip_signals) {
+            unifi_error(priv, "omnicli cannot be used when log_hip_signals is used\n");
+            r = -EFAULT;
+            goto out;
+        }
+#endif
+
+        down(&priv->udi_logging_mutex);
+        if (int_param) {
+            pcli->event_hook = udi_log_event;
+            unifi_set_udi_hook(priv->card, logging_handler);
+            /* Log all signals by default */
+            for (i = 0; i < SIG_FILTER_SIZE; i++) {
+                pcli->signal_filter[i] = 0xFFFF;
+            }
+            priv->logging_client = pcli;
+
+        } else {
+            priv->logging_client = NULL;
+            pcli->event_hook = NULL;
+        }
+        up(&priv->udi_logging_mutex);
+
+        break;
+
+      case UNIFI_SET_MIB:
+        unifi_trace(priv, UDBG4, "UniFi Set MIB\n");
+#if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
+        /* Read first 2 bytes and check length */
+        if (copy_from_user((void*)varbind, (void*)arg, 2)) {
+            unifi_error(priv,
+                        "UNIFI_SET_MIB: Failed to copy in varbind header\n");
+            r = -EFAULT;
+            goto out;
+        }
+        vblen = varbind[1];
+        if ((vblen + 2) > MAX_VARBIND_LENGTH) {
+            unifi_error(priv,
+                        "UNIFI_SET_MIB: Varbind too long (%d, limit %d)\n",
+                        (vblen+2), MAX_VARBIND_LENGTH);
+            r = -EINVAL;
+            goto out;
+        }
+        /* Read rest of varbind */
+        if (copy_from_user((void*)(varbind+2), (void*)(arg+2), vblen)) {
+            unifi_error(priv, "UNIFI_SET_MIB: Failed to copy in varbind\n");
+            r = -EFAULT;
+            goto out;
+        }
+
+        /* send to SME */
+        vblen += 2;
+        r = sme_mgt_mib_set(priv, varbind, vblen);
+        if (r) {
+            goto out;
+        }
+#else
+        unifi_notice(priv, "UNIFI_SET_MIB: Unsupported.\n");
+#endif /* CSR_SUPPORT_WEXT */
+        break;
+
+      case UNIFI_GET_MIB:
+        unifi_trace(priv, UDBG4, "UniFi Get MIB\n");
+#if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
+        /* Read first 2 bytes and check length */
+        if (copy_from_user((void*)varbind, (void*)arg, 2)) {
+            unifi_error(priv, "UNIFI_GET_MIB: Failed to copy in varbind header\n");
+            r = -EFAULT;
+            goto out;
+        }
+        vblen = varbind[1];
+        if ((vblen+2) > MAX_VARBIND_LENGTH) {
+            unifi_error(priv, "UNIFI_GET_MIB: Varbind too long (%d, limit %d)\n",
+                        (vblen+2), MAX_VARBIND_LENGTH);
+            r = -EINVAL;
+            goto out;
+        }
+        /* Read rest of varbind */
+        if (copy_from_user((void*)(varbind+2), (void*)(arg+2), vblen)) {
+            unifi_error(priv, "UNIFI_GET_MIB: Failed to copy in varbind\n");
+            r = -EFAULT;
+            goto out;
+        }
+
+        vblen += 2;
+        r = sme_mgt_mib_get(priv, varbind, &vblen);
+        if (r) {
+            goto out;
+        }
+        /* copy out varbind */
+        if (vblen > MAX_VARBIND_LENGTH) {
+            unifi_error(priv,
+                        "UNIFI_GET_MIB: Varbind result too long (%d, limit %d)\n",
+                        vblen, MAX_VARBIND_LENGTH);
+            r = -EINVAL;
+            goto out;
+        }
+        if (copy_to_user((void*)arg, varbind, vblen)) {
+            r = -EFAULT;
+            goto out;
+        }
+#else
+        unifi_notice(priv, "UNIFI_GET_MIB: Unsupported.\n");
+#endif /* CSR_SUPPORT_WEXT */
+        break;
+
+      case UNIFI_CFG:
+#if (defined CSR_SUPPORT_SME)
+        if (get_user(cfg_cmd, (unifi_cfg_command_t*)arg))
+        {
+            unifi_error(priv, "UNIFI_CFG: Failed to get the command\n");
+            r = -EFAULT;
+            goto out;
+        }
+
+        unifi_trace(priv, UDBG1, "UNIFI_CFG: Command is %d (t=%u) sz=%d\n",
+                    cfg_cmd, jiffies_to_msecs(jiffies), sizeof(unifi_cfg_command_t));
+        switch (cfg_cmd) {
+          case UNIFI_CFG_POWER:
+            r = unifi_cfg_power(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_CFG_POWERSAVE:
+            r = unifi_cfg_power_save(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_CFG_POWERSUPPLY:
+            r = unifi_cfg_power_supply(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_CFG_FILTER:
+            r = unifi_cfg_packet_filters(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_CFG_GET:
+            r = unifi_cfg_get_info(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_CFG_WMM_QOSINFO:
+            r = unifi_cfg_wmm_qos_info(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_CFG_WMM_ADDTS:
+            r = unifi_cfg_wmm_addts(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_CFG_WMM_DELTS:
+            r = unifi_cfg_wmm_delts(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_CFG_STRICT_DRAFT_N:
+            r = unifi_cfg_strict_draft_n(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_CFG_ENABLE_OKC:
+            r = unifi_cfg_enable_okc(priv, (unsigned char*)arg);
+            break;
+#ifdef CSR_SUPPORT_SME
+          case UNIFI_CFG_CORE_DUMP:
+            CsrWifiRouterCtrlWifiOffIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,CSR_WIFI_SME_CONTROL_INDICATION_ERROR);
+            unifi_trace(priv, UDBG2, "UNIFI_CFG_CORE_DUMP: sent wifi off indication\n");
+            break;
+#endif
+#ifdef CSR_SUPPORT_WEXT_AP
+          case UNIFI_CFG_SET_AP_CONFIG:
+            r= unifi_cfg_set_ap_config(priv,(unsigned char*)arg);
+            break;
+#endif
+          default:
+            unifi_error(priv, "UNIFI_CFG: Unknown Command (%d)\n", cfg_cmd);
+            r = -EINVAL;
+            goto out;
+        }
+#endif
+
+        break;
+
+      case UNIFI_PUTEST:
+        if (get_user(putest_cmd, (unifi_putest_command_t*)arg))
+        {
+            unifi_error(priv, "UNIFI_PUTEST: Failed to get the command\n");
+            r = -EFAULT;
+            goto out;
+        }
+
+        unifi_trace(priv, UDBG1, "UNIFI_PUTEST: Command is %s\n",
+                    trace_putest_cmdid(putest_cmd));
+        switch (putest_cmd) {
+          case UNIFI_PUTEST_START:
+            r = unifi_putest_start(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_PUTEST_STOP:
+            r = unifi_putest_stop(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_PUTEST_SET_SDIO_CLOCK:
+            r = unifi_putest_set_sdio_clock(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_PUTEST_CMD52_READ:
+            r = unifi_putest_cmd52_read(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_PUTEST_CMD52_BLOCK_READ:
+            r = unifi_putest_cmd52_block_read(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_PUTEST_CMD52_WRITE:
+            r = unifi_putest_cmd52_write(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_PUTEST_DL_FW:
+            r = unifi_putest_dl_fw(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_PUTEST_DL_FW_BUFF:
+            r = unifi_putest_dl_fw_buff(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_PUTEST_COREDUMP_PREPARE:
+            r = unifi_putest_coredump_prepare(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_PUTEST_GP_READ16:
+            r = unifi_putest_gp_read16(priv, (unsigned char*)arg);
+            break;
+          case UNIFI_PUTEST_GP_WRITE16:
+            r = unifi_putest_gp_write16(priv, (unsigned char*)arg);
+            break;
+          default:
+            unifi_error(priv, "UNIFI_PUTEST: Unknown Command (%d)\n", putest_cmd);
+            r = -EINVAL;
+            goto out;
+        }
+
+        break;
+      case UNIFI_BUILD_TYPE:
+        unifi_trace(priv, UDBG2, "UNIFI_BUILD_TYPE userspace=%s\n", build_type_to_string(*(unsigned char*)arg));
+#ifndef CSR_SUPPORT_WEXT_AP
+        if (UNIFI_BUILD_AP == *(unsigned char*)arg)
+        {
+            unifi_error(priv, "Userspace has AP support, which is incompatible\n");
+        }
+#endif
+
+#ifndef CSR_SUPPORT_WEXT
+        if (UNIFI_BUILD_WEXT == *(unsigned char*)arg)
+        {
+            unifi_error(priv, "Userspace has WEXT support, which is incompatible\n");
+        }
+#endif
+        break;
+      case UNIFI_INIT_HW:
+        unifi_trace(priv, UDBG2, "UNIFI_INIT_HW.\n");
+        priv->init_progress = UNIFI_INIT_NONE;
+
+#if defined(CSR_SUPPORT_WEXT) || defined (CSR_NATIVE_LINUX)
+        /* At this point we are ready to start the SME. */
+        r = sme_mgt_wifi_on(priv);
+        if (r) {
+            goto out;
+        }
+#endif
+
+        break;
+
+      case UNIFI_INIT_NETDEV:
+        {
+            /* get the proper interfaceTagId */
+            CsrUint16 interfaceTag=0;
+            netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+            dev = priv->netdev[interfaceTag];
+            unifi_trace(priv, UDBG2, "UNIFI_INIT_NETDEV.\n");
+
+            if (copy_from_user((void*)dev->dev_addr, (void*)arg, 6)) {
+                r = -EFAULT;
+                goto out;
+            }
+
+            /* Attach the network device to the stack */
+            if (!interfacePriv->netdev_registered)
+            {
+                r = uf_register_netdev(priv,interfaceTag);
+                if (r) {
+                    unifi_error(priv, "Failed to register the network device.\n");
+                    goto out;
+                }
+            }
+
+            /* Apply scheduled interrupt mode, if requested by module param */
+            if (run_bh_once != -1) {
+                unifi_set_interrupt_mode(priv->card, (CsrUint32)run_bh_once);
+            }
+
+            priv->init_progress = UNIFI_INIT_COMPLETED;
+
+            /* Firmware initialisation is complete, so let the SDIO bus
+             * clock be raised when convienent to the core.
+             */
+            unifi_request_max_sdio_clock(priv->card);
+
+#ifdef CSR_SUPPORT_WEXT
+            /* Notify the Android wpa_supplicant that we are ready */
+            wext_send_started_event(priv);
+#endif
+
+            unifi_info(priv, "UniFi ready\n");
+
+#ifdef ANDROID_BUILD
+            /* Release the wakelock */
+            unifi_trace(priv, UDBG1, "netdev_init: release wake lock\n");
+            wake_unlock(&unifi_sdio_wake_lock);
+#endif
+#ifdef CSR_NATIVE_SOFTMAC /* For softmac dev, force-enable the network interface rather than wait for a connected-ind */
+            {
+                struct net_device *dev = priv->netdev[interfaceTag];
+#ifdef CSR_SUPPORT_WEXT
+                interfacePriv->wait_netdev_change = TRUE;
+#endif
+                netif_carrier_on(dev);
+            }
+#endif
+        }
+        break;
+      case UNIFI_GET_INIT_STATUS:
+        unifi_trace(priv, UDBG2, "UNIFI_GET_INIT_STATUS.\n");
+        if (put_user(priv->init_progress, (int*)arg))
+        {
+            printk(KERN_ERR "UNIFI_GET_INIT_STATUS: Failed to copy to user\n");
+            r = -EFAULT;
+            goto out;
+        }
+        break;
+
+      case UNIFI_KICK:
+        unifi_trace(priv, UDBG4, "Kick UniFi\n");
+        unifi_sdio_interrupt_handler(priv->card);
+        break;
+
+      case UNIFI_SET_DEBUG:
+        unifi_debug = arg;
+        unifi_trace(priv, UDBG4, "unifi_debug set to %d\n", unifi_debug);
+        break;
+
+      case UNIFI_SET_TRACE:
+        /* no longer supported */
+        r = -EINVAL;
+        break;
+
+
+      case UNIFI_SET_UDI_LOG_MASK:
+        {
+            unifiio_filter_t udi_filter;
+            uint16_t *sig_ids_addr;
+#define UF_MAX_SIG_IDS  128     /* Impose a sensible limit */
+
+            if (copy_from_user((void*)(&udi_filter), (void*)arg, sizeof(udi_filter))) {
+                r = -EFAULT;
+                goto out;
+            }
+            if ((udi_filter.action < UfSigFil_AllOn) ||
+                (udi_filter.action > UfSigFil_SelectOff))
+            {
+                printk(KERN_WARNING
+                       "UNIFI_SET_UDI_LOG_MASK: Bad action value: %d\n",
+                       udi_filter.action);
+                r = -EINVAL;
+                goto out;
+            }
+            /* No signal list for "All" actions */
+            if ((udi_filter.action == UfSigFil_AllOn) ||
+                (udi_filter.action == UfSigFil_AllOff))
+            {
+                udi_filter.num_sig_ids = 0;
+            }
+
+            if (udi_filter.num_sig_ids > UF_MAX_SIG_IDS) {
+                printk(KERN_WARNING
+                       "UNIFI_SET_UDI_LOG_MASK: too many signal ids (%d, max %d)\n",
+                       udi_filter.num_sig_ids, UF_MAX_SIG_IDS);
+                r = -EINVAL;
+                goto out;
+            }
+
+            /* Copy in signal id list if given */
+            if (udi_filter.num_sig_ids > 0) {
+                /* Preserve userspace address of sig_ids array */
+                sig_ids_addr = udi_filter.sig_ids;
+                /* Allocate kernel memory for sig_ids and copy to it */
+                udi_filter.sig_ids =
+                    kmalloc(udi_filter.num_sig_ids * sizeof(uint16_t), GFP_KERNEL);
+                if (!udi_filter.sig_ids) {
+                    r = -ENOMEM;
+                    goto out;
+                }
+                if (copy_from_user((void*)udi_filter.sig_ids,
+                                   (void*)sig_ids_addr,
+                                   udi_filter.num_sig_ids * sizeof(uint16_t)))
+                {
+                    kfree(udi_filter.sig_ids);
+                    r = -EFAULT;
+                    goto out;
+                }
+            }
+
+            udi_set_log_filter(pcli, &udi_filter);
+
+            if (udi_filter.num_sig_ids > 0) {
+                kfree(udi_filter.sig_ids);
+            }
+        }
+        break;
+
+      case UNIFI_SET_AMP_ENABLE:
+        unifi_trace(priv, UDBG4, "UniFi Set AMP Enable\n");
+        if (get_user(int_param, (int*)arg))
+        {
+            unifi_error(priv, "UNIFI_SET_AMP_ENABLE: Failed to copy from user\n");
+            r = -EFAULT;
+            goto out;
+        }
+
+        if (int_param) {
+            priv->amp_client = pcli;
+        } else {
+            priv->amp_client = NULL;
+        }
+
+        int_param = 0;
+        buf = (u8*)&int_param;
+        buf[0] = UNIFI_SOFT_COMMAND_Q_LENGTH - 1;
+        buf[1] = UNIFI_SOFT_TRAFFIC_Q_LENGTH - 1;
+        if (copy_to_user((void*)arg, &int_param, sizeof(int))) {
+            r = -EFAULT;
+            goto out;
+        }
+        break;
+
+      case UNIFI_SET_UDI_SNAP_MASK:
+        {
+            unifiio_snap_filter_t snap_filter;
+
+            if (copy_from_user((void*)(&snap_filter), (void*)arg, sizeof(snap_filter))) {
+                r = -EFAULT;
+                goto out;
+            }
+
+            if (pcli->snap_filter.count) {
+                pcli->snap_filter.count = 0;
+                CsrPmemFree(pcli->snap_filter.protocols);
+            }
+
+            if (snap_filter.count == 0) {
+                break;
+            }
+
+            pcli->snap_filter.protocols = CsrPmemAlloc(snap_filter.count * sizeof(CsrUint16));
+            if (!pcli->snap_filter.protocols) {
+                r = -ENOMEM;
+                goto out;
+            }
+            if (copy_from_user((void*)pcli->snap_filter.protocols,
+                               (void*)snap_filter.protocols,
+                               snap_filter.count * sizeof(CsrUint16)))
+            {
+                CsrPmemFree(pcli->snap_filter.protocols);
+                r = -EFAULT;
+                goto out;
+            }
+
+            pcli->snap_filter.count = snap_filter.count;
+
+        }
+        break;
+
+      case UNIFI_SME_PRESENT:
+        {
+            u8 ind;
+            unifi_trace(priv, UDBG4, "UniFi SME Present IOCTL.\n");
+            if (copy_from_user((void*)(&int_param), (void*)arg, sizeof(int)))
+            {
+                printk(KERN_ERR "UNIFI_SME_PRESENT: Failed to copy from user\n");
+                r = -EFAULT;
+                goto out;
+            }
+
+            priv->sme_is_present = int_param;
+            if (priv->sme_is_present == 1) {
+                ind = CONFIG_SME_PRESENT;
+            } else {
+                ind = CONFIG_SME_NOT_PRESENT;
+            }
+            /* Send an indication to the helper app. */
+            ul_log_config_ind(priv, &ind, sizeof(u8));
+        }
+        break;
+
+      case UNIFI_CFG_PERIOD_TRAFFIC:
+      {
+#if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
+          CsrWifiSmeCoexConfig coexConfig;
+#endif /* CSR_SUPPORT_SME && CSR_SUPPORT_WEXT */
+        unifi_trace(priv, UDBG4, "UniFi Configure Periodic Traffic.\n");
+#if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
+        if (copy_from_user((void*)(&uchar_param), (void*)arg, sizeof(unsigned char))) {
+            unifi_error(priv, "UNIFI_CFG_PERIOD_TRAFFIC: Failed to copy from user\n");
+            r = -EFAULT;
+            goto out;
+        }
+
+        if (uchar_param == 0) {
+            r = sme_mgt_coex_config_get(priv, &coexConfig);
+            if (r) {
+                unifi_error(priv, "UNIFI_CFG_PERIOD_TRAFFIC: Get unifi_CoexInfoValue failed.\n");
+                goto out;
+            }
+            if (copy_to_user((void*)(arg + 1),
+                             (void*)&coexConfig,
+                             sizeof(CsrWifiSmeCoexConfig))) {
+                r = -EFAULT;
+                goto out;
+            }
+            goto out;
+        }
+
+        if (copy_from_user((void*)(&coex_config), (void*)(arg + 1), sizeof(CsrWifiSmeCoexConfig)))
+        {
+            unifi_error(priv, "UNIFI_CFG_PERIOD_TRAFFIC: Failed to copy from user\n");
+            r = -EFAULT;
+            goto out;
+        }
+
+        coexConfig = coex_config;
+        r = sme_mgt_coex_config_set(priv, &coexConfig);
+        if (r) {
+            unifi_error(priv, "UNIFI_CFG_PERIOD_TRAFFIC: Set unifi_CoexInfoValue failed.\n");
+            goto out;
+        }
+
+#endif /* CSR_SUPPORT_SME && CSR_SUPPORT_WEXT */
+        break;
+      }
+      case UNIFI_CFG_UAPSD_TRAFFIC:
+        unifi_trace(priv, UDBG4, "UniFi Configure U-APSD Mask.\n");
+#if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
+        if (copy_from_user((void*)(&uchar_param), (void*)arg, sizeof(unsigned char))) {
+            unifi_error(priv, "UNIFI_CFG_UAPSD_TRAFFIC: Failed to copy from user\n");
+            r = -EFAULT;
+            goto out;
+        }
+        unifi_trace(priv, UDBG4, "New U-APSD Mask: 0x%x\n", uchar_param);
+#endif /* CSR_SUPPORT_SME && CSR_SUPPORT_WEXT */
+        break;
+
+#ifndef UNIFI_DISABLE_COREDUMP
+      case UNIFI_COREDUMP_GET_REG:
+        unifi_trace(priv, UDBG4, "Mini-coredump data request\n");
+        {
+            unifiio_coredump_req_t dump_req;    /* Public OS layer structure */
+            unifi_coredump_req_t priv_req;      /* Private HIP structure */
+
+            if (copy_from_user((void*)(&dump_req), (void*)arg, sizeof(dump_req))) {
+                r = -EFAULT;
+                goto out;
+            }
+            memset(&priv_req, 0, sizeof(priv_req));
+            priv_req.index = dump_req.index;
+            priv_req.offset = dump_req.offset;
+
+            /* Convert OS-layer's XAP memory space ID to HIP's ID in case they differ */
+            switch (dump_req.space) {
+                case UNIFIIO_COREDUMP_MAC_REG: priv_req.space = UNIFI_COREDUMP_MAC_REG; break;
+                case UNIFIIO_COREDUMP_PHY_REG: priv_req.space = UNIFI_COREDUMP_PHY_REG; break;
+                case UNIFIIO_COREDUMP_SH_DMEM: priv_req.space = UNIFI_COREDUMP_SH_DMEM; break;
+                case UNIFIIO_COREDUMP_MAC_DMEM: priv_req.space = UNIFI_COREDUMP_MAC_DMEM; break;
+                case UNIFIIO_COREDUMP_PHY_DMEM: priv_req.space = UNIFI_COREDUMP_PHY_DMEM; break;
+                case UNIFIIO_COREDUMP_TRIGGER_MAGIC: priv_req.space = UNIFI_COREDUMP_TRIGGER_MAGIC; break;
+                default:
+                  r = -EINVAL;
+                  goto out;
+            }
+
+            if (priv_req.space == UNIFI_COREDUMP_TRIGGER_MAGIC) {
+                /* Force a coredump grab now */
+                unifi_trace(priv, UDBG2, "UNIFI_COREDUMP_GET_REG: Force capture\n");
+                csrResult = unifi_coredump_capture(priv->card, &priv_req);
+                r = CsrHipResultToStatus(csrResult);
+                unifi_trace(priv, UDBG5, "UNIFI_COREDUMP_GET_REG: status %d\n", r);
+            } else {
+                /* Retrieve the appropriate register entry */
+                csrResult = unifi_coredump_get_value(priv->card, &priv_req);
+                r = CsrHipResultToStatus(csrResult);
+                if (r) {
+                    unifi_trace(priv, UDBG5, "UNIFI_COREDUMP_GET_REG: Status %d\n", r);
+                    goto out;
+                }
+                /* Update the OS-layer structure with values returned in the private */
+                dump_req.value = priv_req.value;
+                dump_req.timestamp = priv_req.timestamp;
+                dump_req.requestor = priv_req.requestor;
+                dump_req.serial = priv_req.serial;
+                dump_req.chip_ver = priv_req.chip_ver;
+                dump_req.fw_ver = priv_req.fw_ver;
+                dump_req.drv_build = 0;
+
+                unifi_trace(priv, UDBG6,
+                            "Dump: %d (seq %d): V:0x%04x (%d) @0x%02x:%04x = 0x%04x\n",
+                            dump_req.index, dump_req.serial,
+                            dump_req.chip_ver, dump_req.drv_build,
+                            dump_req.space, dump_req.offset, dump_req.value);
+            }
+            if (copy_to_user((void*)arg, (void*)&dump_req, sizeof(dump_req))) {
+                r = -EFAULT;
+                goto out;
+            }
+        }
+        break;
+#endif
+      default:
+        r = -EINVAL;
+    }
+
+out:
+    return (long)r;
+} /* unifi_ioctl() */
+
+
+
+static unsigned int
+unifi_poll(struct file *filp, poll_table *wait)
+{
+    ul_client_t *pcli = (ul_client_t*)filp->private_data;
+    unsigned int mask = 0;
+    int ready;
+
+    func_enter();
+
+    ready = !list_empty(&pcli->udi_log);
+
+    poll_wait(filp, &pcli->udi_wq, wait);
+
+    if (ready) {
+        mask |= POLLIN | POLLRDNORM;    /* readable */
+    }
+
+    func_exit();
+
+    return mask;
+} /* unifi_poll() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  udi_set_log_filter
+ *
+ *      Configure the bit mask that determines which signal primitives are
+ *      passed to the logging process.
+ *
+ *  Arguments:
+ *      pcli            Pointer to the client to configure.
+ *      udi_filter      Pointer to a unifiio_filter_t containing instructions.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *      SigGetFilterPos() returns a 32-bit value that contains an index and a
+ *      mask for accessing a signal_filter array. The top 16 bits specify an
+ *      index into a signal_filter, the bottom 16 bits specify a mask to
+ *      apply.
+ * ---------------------------------------------------------------------------
+ */
+static void
+udi_set_log_filter(ul_client_t *pcli, unifiio_filter_t *udi_filter)
+{
+    CsrUint32 filter_pos;
+    int i;
+
+    if (udi_filter->action == UfSigFil_AllOn)
+    {
+        for (i = 0; i < SIG_FILTER_SIZE; i++) {
+            pcli->signal_filter[i] = 0xFFFF;
+        }
+    }
+    else if (udi_filter->action == UfSigFil_AllOff)
+    {
+        for (i = 0; i < SIG_FILTER_SIZE; i++) {
+            pcli->signal_filter[i] = 0;
+        }
+    }
+    else if (udi_filter->action == UfSigFil_SelectOn)
+    {
+        for (i = 0; i < udi_filter->num_sig_ids; i++) {
+            filter_pos = SigGetFilterPos(udi_filter->sig_ids[i]);
+            if (filter_pos == 0xFFFFFFFF)
+            {
+                printk(KERN_WARNING
+                       "Unrecognised signal id (0x%X) specifed in logging filter\n",
+                       udi_filter->sig_ids[i]);
+            } else {
+                pcli->signal_filter[filter_pos >> 16] |= (filter_pos & 0xFFFF);
+            }
+        }
+    }
+    else if (udi_filter->action == UfSigFil_SelectOff)
+    {
+        for (i = 0; i < udi_filter->num_sig_ids; i++) {
+            filter_pos = SigGetFilterPos(udi_filter->sig_ids[i]);
+            if (filter_pos == 0xFFFFFFFF)
+            {
+                printk(KERN_WARNING
+                       "Unrecognised signal id (0x%X) specifed in logging filter\n",
+                       udi_filter->sig_ids[i]);
+            } else {
+                pcli->signal_filter[filter_pos >> 16] &= ~(filter_pos & 0xFFFF);
+            }
+        }
+    }
+
+} /* udi_set_log_filter() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  udi_log_event
+ *
+ *      Callback function to be registered as the UDI hook callback.
+ *      Copies the signal content into a new udi_log_t struct and adds
+ *      it to the read queue for this UDI client.
+ *
+ *  Arguments:
+ *      pcli            A pointer to the client instance.
+ *      signal          Pointer to the received signal.
+ *      signal_len      Size of the signal structure in bytes.
+ *      bulkdata        Pointers to any associated bulk data.
+ *      dir             Direction of the signal. Zero means from host,
+ *                      non-zero means to host.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+udi_log_event(ul_client_t *pcli,
+              const u8 *signal, int signal_len,
+              const bulk_data_param_t *bulkdata,
+              int dir)
+{
+    udi_log_t *logptr;
+    u8 *p;
+    int i;
+    int total_len;
+    udi_msg_t *msgptr;
+    CsrUint32 filter_pos;
+#ifdef OMNICLI_LINUX_EXTRA_LOG
+    static volatile unsigned int printk_cpu = UINT_MAX;
+    unsigned long long t;
+    unsigned long nanosec_rem;
+    unsigned long n_1000;
+#endif
+
+    func_enter();
+
+    /* Just a sanity check */
+    if ((signal == NULL) || (signal_len <= 0)) {
+        return;
+    }
+
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+    /* When HIP offline signal logging is enabled, omnicli cannot run */
+    if (log_hip_signals)
+    {
+        /* Add timestamp */
+        if (log_hip_signals & UNIFI_LOG_HIP_SIGNALS_FILTER_TIMESTAMP)
+        {
+            int timestamp = jiffies_to_msecs(jiffies);
+            unifi_debug_log_to_buf("T:");
+            unifi_debug_log_to_buf("%04X%04X ", *(((CsrUint16*)&timestamp) + 1),
+                                   *(CsrUint16*)&timestamp);
+        }
+
+        /* Add signal */
+        unifi_debug_log_to_buf("S%s:%04X R:%04X D:%04X ",
+                               dir ? "T" : "F",
+                               *(CsrUint16*)signal,
+                               *(CsrUint16*)(signal + 2),
+                               *(CsrUint16*)(signal + 4));
+        unifi_debug_hex_to_buf(signal + 6, signal_len - 6);
+
+        /* Add bulk data (assume 1 bulk data per signal) */
+        if ((log_hip_signals & UNIFI_LOG_HIP_SIGNALS_FILTER_BULKDATA) &&
+            (bulkdata->d[0].data_length > 0))
+        {
+            unifi_debug_log_to_buf("\nD:");
+            unifi_debug_hex_to_buf(bulkdata->d[0].os_data_ptr, bulkdata->d[0].data_length);
+        }
+        unifi_debug_log_to_buf("\n");
+
+        return;
+    }
+#endif
+
+#ifdef CSR_NATIVE_LINUX
+    uf_native_process_udi_signal(pcli, signal, signal_len, bulkdata, dir);
+#endif
+
+    /*
+     * Apply the logging filter - only report signals that have their
+     * bit set in the filter mask.
+     */
+    filter_pos = SigGetFilterPos(GET_SIGNAL_ID(signal));
+
+    if ((filter_pos != 0xFFFFFFFF) &&
+        ((pcli->signal_filter[filter_pos >> 16] & (filter_pos & 0xFFFF)) == 0))
+    {
+        /* Signal is not wanted by client */
+        return;
+    }
+
+
+    /* Calculate the buffer we need to store signal plus bulk data */
+    total_len = signal_len;
+    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
+        total_len += bulkdata->d[i].data_length;
+    }
+
+    /* Allocate log structure plus actual signal. */
+    logptr = (udi_log_t *)kmalloc(sizeof(udi_log_t) + total_len, GFP_KERNEL);
+
+    if (logptr == NULL) {
+        printk(KERN_ERR
+               "Failed to allocate %lu bytes for a UDI log record\n",
+               (long unsigned int)(sizeof(udi_log_t) + total_len));
+        return;
+    }
+
+    /* Fill in udi_log struct */
+    INIT_LIST_HEAD(&logptr->q);
+    msgptr = &logptr->msg;
+    msgptr->length = sizeof(udi_msg_t) + total_len;
+#ifdef OMNICLI_LINUX_EXTRA_LOG
+    t = cpu_clock(printk_cpu);
+    nanosec_rem = do_div(t, 1000000000);
+    n_1000 = nanosec_rem/1000;
+    msgptr->timestamp = (t <<10 ) | ((unsigned long)(n_1000 >> 10) & 0x3ff);
+#else
+    msgptr->timestamp = jiffies_to_msecs(jiffies);
+#endif
+    msgptr->direction = dir;
+    msgptr->signal_length = signal_len;
+
+    /* Copy signal and bulk data to the log */
+    p = (u8 *)(msgptr + 1);
+    memcpy(p, signal, signal_len);
+    p += signal_len;
+
+    /* Append any bulk data */
+    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
+        int len = bulkdata->d[i].data_length;
+
+        /*
+         * Len here might not be the same as the length in the bulk data slot.
+         * The slot length will always be even, but len could be odd.
+         */
+        if (len > 0) {
+            if (bulkdata->d[i].os_data_ptr) {
+                memcpy(p, bulkdata->d[i].os_data_ptr, len);
+            } else {
+                memset(p, 0, len);
+            }
+            p += len;
+        }
+    }
+
+    /* Add to tail of log queue */
+    if (down_interruptible(&pcli->udi_sem)) {
+        printk(KERN_WARNING "udi_log_event_q: Failed to get udi sem\n");
+        kfree(logptr);
+        func_exit();
+        return;
+    }
+    list_add_tail(&logptr->q, &pcli->udi_log);
+    up(&pcli->udi_sem);
+
+    /* Wake any waiting user process */
+    wake_up_interruptible(&pcli->udi_wq);
+
+    func_exit();
+} /* udi_log_event() */
+
+#ifdef CSR_SME_USERSPACE
+int
+uf_sme_queue_message(unifi_priv_t *priv, u8 *buffer, int length)
+{
+    udi_log_t *logptr;
+    udi_msg_t *msgptr;
+    u8 *p;
+
+    func_enter();
+
+    /* Just a sanity check */
+    if ((buffer == NULL) || (length <= 0)) {
+        return -EINVAL;
+    }
+
+    /* Allocate log structure plus actual signal. */
+    logptr = (udi_log_t *)kmalloc(sizeof(udi_log_t) + length, GFP_ATOMIC);
+    if (logptr == NULL) {
+        unifi_error(priv, "Failed to allocate %d bytes for an SME message\n",
+                    sizeof(udi_log_t) + length);
+                    CsrPmemFree(buffer);
+                    return -ENOMEM;
+    }
+
+    /* Fill in udi_log struct */
+    INIT_LIST_HEAD(&logptr->q);
+    msgptr = &logptr->msg;
+    msgptr->length = sizeof(udi_msg_t) + length;
+    msgptr->signal_length = length;
+
+    /* Copy signal and bulk data to the log */
+    p = (u8 *)(msgptr + 1);
+    memcpy(p, buffer, length);
+
+    /* Add to tail of log queue */
+    down(&udi_mutex);
+    if (priv->sme_cli == NULL) {
+        kfree(logptr);
+        CsrPmemFree(buffer);
+        up(&udi_mutex);
+        unifi_info(priv, "Message for the SME dropped, SME has gone away\n");
+        return 0;
+    }
+
+    down(&priv->sme_cli->udi_sem);
+    list_add_tail(&logptr->q, &priv->sme_cli->udi_log);
+    up(&priv->sme_cli->udi_sem);
+
+    /* Wake any waiting user process */
+    wake_up_interruptible(&priv->sme_cli->udi_wq);
+    up(&udi_mutex);
+
+    /* It is our responsibility to free the buffer allocated in build_packed_*() */
+    CsrPmemFree(buffer);
+
+    func_exit();
+
+    return 0;
+
+} /* uf_sme_queue_message() */
+#endif
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
+    device_create(_class, _parent, _devno, _priv, _fmt, _args)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
+    device_create_drvdata(_class, _parent, _devno, _priv, _fmt, _args)
+#else
+#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
+    device_create(_class, _parent, _devno, _fmt, _args)
+#endif
+
+/*
+ ****************************************************************************
+ *
+ *      Driver instantiation
+ *
+ ****************************************************************************
+ */
+static struct file_operations unifi_fops = {
+    .owner      = THIS_MODULE,
+    .open       = unifi_open,
+    .release    = unifi_release,
+    .read       = unifi_read,
+    .write      = unifi_write,
+    .unlocked_ioctl = unifi_ioctl,
+    .poll       = unifi_poll,
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
+    device_create(_class, _parent, _devno, _priv, _fmt, _args)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
+    device_create_drvdata(_class, _parent, _devno, _priv, _fmt, _args)
+#else
+#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args)       \
+    device_create(_class, _parent, _devno, _fmt, _args)
+#endif
+
+static dev_t unifi_first_devno;
+static struct class *unifi_class;
+
+
+int uf_create_device_nodes(unifi_priv_t *priv, int bus_id)
+{
+    dev_t devno;
+    int r;
+
+    cdev_init(&priv->unifi_cdev, &unifi_fops);
+
+    /* cdev_init() should set the cdev owner, but it does not */
+    priv->unifi_cdev.owner = THIS_MODULE;
+
+    devno = MKDEV(MAJOR(unifi_first_devno),
+                  MINOR(unifi_first_devno) + (bus_id * 2));
+    r = cdev_add(&priv->unifi_cdev, devno, 1);
+    if (r) {
+        return r;
+    }
+
+#ifdef SDIO_EXPORTS_STRUCT_DEVICE
+    if (!UF_DEVICE_CREATE(unifi_class, priv->unifi_device,
+                          devno, priv, "unifi%d", bus_id)) {
+#else
+    priv->unifi_device = UF_DEVICE_CREATE(unifi_class, NULL,
+                                          devno, priv, "unifi%d", bus_id);
+    if (priv->unifi_device == NULL) {
+#endif /* SDIO_EXPORTS_STRUCT_DEVICE */
+
+        cdev_del(&priv->unifi_cdev);
+        return -EINVAL;
+    }
+
+    cdev_init(&priv->unifiudi_cdev, &unifi_fops);
+
+    /* cdev_init() should set the cdev owner, but it does not */
+    priv->unifiudi_cdev.owner = THIS_MODULE;
+
+    devno = MKDEV(MAJOR(unifi_first_devno),
+                  MINOR(unifi_first_devno) + (bus_id * 2) + 1);
+    r = cdev_add(&priv->unifiudi_cdev, devno, 1);
+    if (r) {
+        device_destroy(unifi_class, priv->unifi_cdev.dev);
+        cdev_del(&priv->unifi_cdev);
+        return r;
+    }
+
+    if (!UF_DEVICE_CREATE(unifi_class,
+#ifdef SDIO_EXPORTS_STRUCT_DEVICE
+                          priv->unifi_device,
+#else
+                          NULL,
+#endif /* SDIO_EXPORTS_STRUCT_DEVICE */
+                          devno, priv, "unifiudi%d", bus_id)) {
+        device_destroy(unifi_class, priv->unifi_cdev.dev);
+        cdev_del(&priv->unifiudi_cdev);
+        cdev_del(&priv->unifi_cdev);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+
+void uf_destroy_device_nodes(unifi_priv_t *priv)
+{
+    device_destroy(unifi_class, priv->unifiudi_cdev.dev);
+    device_destroy(unifi_class, priv->unifi_cdev.dev);
+    cdev_del(&priv->unifiudi_cdev);
+    cdev_del(&priv->unifi_cdev);
+}
+
+
+
+/*
+ * ----------------------------------------------------------------
+ *  uf_create_debug_device
+ *
+ *      Allocates device numbers for unifi character device nodes
+ *      and creates a unifi class in sysfs
+ *
+ * Arguments:
+ *  fops          Pointer to the char device operations structure.
+ *
+ * Returns:
+ *      0 on success, -ve error code on error.
+ * ----------------------------------------------------------------
+ */
+static int
+uf_create_debug_device(struct file_operations *fops)
+{
+    int ret;
+
+    /* Allocate two device numbers for each device. */
+    ret = alloc_chrdev_region(&unifi_first_devno, 0, MAX_UNIFI_DEVS*2, UNIFI_NAME);
+    if (ret) {
+        unifi_error(NULL, "Failed to add alloc dev numbers: %d\n", ret);
+        return ret;
+    }
+
+    /* Create a UniFi class */
+    unifi_class = class_create(THIS_MODULE, UNIFI_NAME);
+    if (IS_ERR(unifi_class)) {
+        unifi_error(NULL, "Failed to create UniFi class\n");
+
+        /* Release device numbers */
+        unregister_chrdev_region(unifi_first_devno, MAX_UNIFI_DEVS*2);
+        unifi_first_devno = 0;
+        return -EINVAL;
+    }
+
+    return 0;
+} /* uf_create_debug_device() */
+
+
+/*
+ * ----------------------------------------------------------------
+ *  uf_remove_debug_device
+ *
+ *      Destroys the unifi class and releases the allocated
+ *      device numbers for unifi character device nodes.
+ *
+ * Arguments:
+ *
+ * Returns:
+ * ----------------------------------------------------------------
+ */
+static void
+uf_remove_debug_device(void)
+{
+    /* Destroy the UniFi class */
+    class_destroy(unifi_class);
+
+    /* Release device numbers */
+    unregister_chrdev_region(unifi_first_devno, MAX_UNIFI_DEVS*2);
+    unifi_first_devno = 0;
+
+} /* uf_remove_debug_device() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ *      Module loading.
+ *
+ * ---------------------------------------------------------------------------
+ */
+int __init
+unifi_load(void)
+{
+    int r;
+
+    printk("UniFi SDIO Driver: %s %s %s\n",
+            CSR_WIFI_VERSION,
+           __DATE__, __TIME__);
+
+#ifdef CSR_SME_USERSPACE
+#ifdef CSR_SUPPORT_WEXT
+    printk("CSR SME with WEXT support\n");
+#else
+    printk("CSR SME no WEXT support\n");
+#endif /* CSR_SUPPORT_WEXT */
+#endif /* CSR_SME_USERSPACE */
+
+#ifdef CSR_NATIVE_LINUX
+#ifdef CSR_SUPPORT_WEXT
+#error WEXT unsupported in the native driver
+#endif
+    printk("CSR native no WEXT support\n");
+#endif
+#ifdef CSR_WIFI_SPLIT_PATCH
+    printk("Split patch support\n");
+#endif
+    printk("Kernel %d.%d.%d\n",
+           ((LINUX_VERSION_CODE) >> 16) & 0xff,
+           ((LINUX_VERSION_CODE) >> 8) & 0xff,
+           (LINUX_VERSION_CODE) & 0xff);
+    /*
+     * Instantiate the /dev/unifi* device nodes.
+     * We must do this before registering with the SDIO driver because it
+     * will immediately call the "insert" callback if the card is
+     * already present.
+     */
+    r = uf_create_debug_device(&unifi_fops);
+    if (r) {
+        return r;
+    }
+
+    /* Now register with the SDIO driver */
+    r = uf_sdio_load();
+    if (r) {
+        uf_remove_debug_device();
+        return r;
+    }
+
+    if (sdio_block_size > -1) {
+        unifi_info(NULL, "sdio_block_size %d\n", sdio_block_size);
+    }
+
+    if (sdio_byte_mode) {
+        unifi_info(NULL, "sdio_byte_mode\n");
+    }
+
+    if (disable_power_control) {
+        unifi_info(NULL, "disable_power_control\n");
+    }
+
+    if (disable_hw_reset) {
+        unifi_info(NULL, "disable_hw_reset\n");
+    }
+
+    if (enable_wol) {
+        unifi_info(NULL, "enable_wol %d\n", enable_wol);
+    }
+
+    if (run_bh_once != -1) {
+        unifi_info(NULL, "run_bh_once %d\n", run_bh_once);
+    }
+
+    return 0;
+} /* unifi_load() */
+
+
+void __exit
+unifi_unload(void)
+{
+    /* The SDIO remove hook will call unifi_disconnect(). */
+    uf_sdio_unload();
+
+    uf_remove_debug_device();
+
+} /* unifi_unload() */
+
+module_init(unifi_load);
+module_exit(unifi_unload);
+
+MODULE_DESCRIPTION("UniFi Device driver");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/staging/csr/firmware.c b/drivers/staging/csr/firmware.c
new file mode 100644
index 0000000..03da0d5
--- /dev/null
+++ b/drivers/staging/csr/firmware.c
@@ -0,0 +1,414 @@
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     firmware.c
+ *
+ *  PURPOSE:
+ *      Implements the f/w related HIP core lib API.
+ *      It is part of the porting exercise in Linux.
+ *
+ *      Also, it contains example code for reading the loader and f/w files
+ *      from the userspace and starting the SME in Linux.
+ *
+ * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <asm/uaccess.h>
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_unifi_udi.h"
+#include "unifiio.h"
+#include "unifi_priv.h"
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ *      F/W download. Part of the HIP core API
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_fw_read_start
+ *
+ *      Returns a structure to be passed in unifi_fw_read().
+ *      This structure is an OS specific description of the f/w file.
+ *      In the linux implementation it is a buffer with the f/w and its' length.
+ *      The HIP driver calls this functions to request for the loader or
+ *      the firmware file.
+ *      The structure pointer can be freed when unifi_fw_read_stop() is called.
+ *
+ *  Arguments:
+ *      ospriv          Pointer to driver context.
+ *      is_fw           Type of firmware to retrieve
+ *      info            Versions information. Can be used to determine
+ *                      the appropriate f/w file to load.
+ *
+ *  Returns:
+ *      O on success, non-zero otherwise.
+ *
+ * ---------------------------------------------------------------------------
+ */
+void*
+unifi_fw_read_start(void *ospriv, CsrInt8 is_fw, const card_info_t *info)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+    CSR_UNUSED(info);
+
+    func_enter();
+
+    if (is_fw == UNIFI_FW_STA) {
+        /* F/w may have been released after a previous successful download. */
+        if (priv->fw_sta.dl_data == NULL) {
+            unifi_trace(priv, UDBG2, "Attempt reload of sta f/w\n");
+            uf_request_firmware_files(priv, UNIFI_FW_STA);
+        }
+        /* Set up callback struct for readfunc() */
+        if (priv->fw_sta.dl_data != NULL) {
+            func_exit();
+            return &priv->fw_sta;
+        }
+
+    } else {
+        unifi_error(priv, "downloading firmware... unknown request: %d\n", is_fw);
+    }
+
+    func_exit();
+    return NULL;
+} /* unifi_fw_read_start() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_fw_read_stop
+ *
+ *      Called when the HIP driver has finished using the loader or
+ *      the firmware file.
+ *      The firmware buffer may be released now.
+ *
+ *  Arguments:
+ *      ospriv          Pointer to driver context.
+ *      dlpriv          The pointer returned by unifi_fw_read_start()
+ *
+ * ---------------------------------------------------------------------------
+ */
+void
+unifi_fw_read_stop(void *ospriv, void *dlpriv)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+    struct dlpriv *dl_struct = (struct dlpriv *)dlpriv;
+    func_enter();
+
+    if (dl_struct != NULL) {
+        if (dl_struct->dl_data != NULL) {
+            unifi_trace(priv, UDBG2, "Release f/w buffer %p, %d bytes\n",
+                        dl_struct->dl_data, dl_struct->dl_len);
+        }
+        uf_release_firmware(priv, dl_struct);
+    }
+
+    func_exit();
+} /* unifi_fw_read_stop() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_fw_open_buffer
+ *
+ *  Returns a handle for a buffer dynamically allocated by the driver,
+ *  e.g. into which a firmware file may have been converted from another format
+ *  which is the case with some production test images.
+ *
+ *  The handle may then be used by unifi_fw_read() to access the contents of
+ *  the buffer.
+ *
+ *  Arguments:
+ *      ospriv          Pointer to driver context.
+ *      fwbuf           Buffer containing firmware image
+ *      len             Length of buffer in bytes
+ *
+ *  Returns
+ *      Handle for buffer, or NULL on error
+ * ---------------------------------------------------------------------------
+ */
+void *
+unifi_fw_open_buffer(void *ospriv, void *fwbuf, CsrUint32 len)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+    func_enter();
+
+    if (fwbuf == NULL) {
+        func_exit();
+        return NULL;
+    }
+    priv->fw_conv.dl_data = fwbuf;
+    priv->fw_conv.dl_len = len;
+    priv->fw_conv.fw_desc = NULL;   /* No OS f/w resource is associated */
+
+    func_exit();
+    return &priv->fw_conv;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_fw_close_buffer
+ *
+ *  Releases any handle for a buffer dynamically allocated by the driver,
+ *  e.g. into which a firmware file may have been converted from another format
+ *  which is the case with some production test images.
+ *
+ *
+ *  Arguments:
+ *      ospriv          Pointer to driver context.
+ *      fwbuf           Buffer containing firmware image
+ *
+ *  Returns
+ *      Handle for buffer, or NULL on error
+ * ---------------------------------------------------------------------------
+ */
+void unifi_fw_close_buffer(void *ospriv, void *fwbuf)
+{
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_fw_read
+ *
+ *      The HIP driver calls this function to ask for a part of the loader or
+ *      the firmware file.
+ *
+ *  Arguments:
+ *      ospriv          Pointer to driver context.
+ *      arg             The pointer returned by unifi_fw_read_start().
+ *      offset          The offset in the file to return from.
+ *      buf             A buffer to store the requested data.
+ *      len             The size of the buf and the size of the requested data.
+ *
+ *  Returns
+ *      The number of bytes read from the firmware image, or -ve on error
+ * ---------------------------------------------------------------------------
+ */
+CsrInt32
+unifi_fw_read(void *ospriv, void *arg, CsrUint32 offset, void *buf, CsrUint32 len)
+{
+    const struct dlpriv *dlpriv = arg;
+
+    if (offset >= dlpriv->dl_len) {
+        /* at end of file */
+        return 0;
+    }
+
+    if ((offset + len) > dlpriv->dl_len) {
+        /* attempt to read past end of file */
+        return -1;
+    }
+
+    memcpy(buf, dlpriv->dl_data+offset, len);
+
+    return len;
+
+} /* unifi_fw_read() */
+
+
+
+
+#define UNIFIHELPER_INIT_MODE_SMEEMB    0
+#define UNIFIHELPER_INIT_MODE_SMEUSER   2
+#define UNIFIHELPER_INIT_MODE_NATIVE    1
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_run_unifihelper
+ *
+ *      Ask userspace to send us firmware for download by running
+ *      '/usr/sbin/unififw'.
+ *      The same script starts the SME userspace application.
+ *      Derived from net_run_sbin_hotplug().
+ *
+ *  Arguments:
+ *      priv            Pointer to OS private struct.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+int
+uf_run_unifihelper(unifi_priv_t *priv)
+{
+#ifdef CONFIG_HOTPLUG
+
+#ifdef ANDROID_BUILD
+    char *prog = "/system/bin/unififw";
+#else
+    char *prog = "/usr/sbin/unififw";
+#endif /* ANDROID_BUILD */
+
+    char *argv[6], *envp[4];
+    char inst_str[8];
+    char init_mode[8];
+    int i, r;
+
+#if (defined CSR_SME_USERSPACE) && (!defined CSR_SUPPORT_WEXT)
+    unifi_trace(priv, UDBG1, "SME userspace build: run unifi_helper manually\n");
+    return 0;
+#endif
+
+    unifi_trace(priv, UDBG1, "starting %s\n", prog);
+
+    snprintf(inst_str,   8, "%d", priv->instance);
+#if (defined CSR_SME_USERSPACE)
+    snprintf(init_mode, 8, "%d", UNIFIHELPER_INIT_MODE_SMEUSER);
+#else
+    snprintf(init_mode, 8, "%d", UNIFIHELPER_INIT_MODE_NATIVE);
+#endif /* CSR_SME_USERSPACE */
+
+    i = 0;
+    argv[i++] = prog;
+    argv[i++] = inst_str;
+    argv[i++] = init_mode;
+    argv[i++] = 0;
+    argv[i] = 0;
+    /* Don't add more args without making argv bigger */
+
+    /* minimal command environment */
+    i = 0;
+    envp[i++] = "HOME=/";
+    envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+    envp[i] = 0;
+    /* Don't add more without making envp bigger */
+
+    unifi_trace(priv, UDBG2, "running %s %s %s\n", argv[0], argv[1], argv[2]);
+
+    r = call_usermodehelper(argv[0], argv, envp, 0);
+
+    return r;
+#else
+    unifi_trace(priv, UDBG1, "Can't automatically download firmware because kernel does not have HOTPLUG\n");
+    return -1;
+#endif
+} /* uf_run_unifihelper() */
+
+#ifdef CSR_WIFI_SPLIT_PATCH
+static CsrBool is_ap_mode(unifi_priv_t *priv)
+{
+    if (priv == NULL || priv->interfacePriv[0] == NULL)
+    {
+        return FALSE;
+    }
+
+    /* Test for mode requiring AP patch */
+    return(CSR_WIFI_HIP_IS_AP_FW(priv->interfacePriv[0]->interfaceMode));
+}
+#endif
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_request_firmware_files
+ *
+ *      Get the firmware files from userspace.
+ *
+ *  Arguments:
+ *      priv            Pointer to OS private struct.
+ *      is_fw           type of firmware to load (UNIFI_FW_STA/LOADER)
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+int uf_request_firmware_files(unifi_priv_t *priv, int is_fw)
+{
+    /* uses the default method to get the firmware */
+    const struct firmware *fw_entry;
+    int postfix;
+#define UNIFI_MAX_FW_PATH_LEN       32
+    char fw_name[UNIFI_MAX_FW_PATH_LEN];
+    int r;
+
+#if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
+    if (priv->mib_data.length) {
+        vfree(priv->mib_data.data);
+        priv->mib_data.data = NULL;
+        priv->mib_data.length = 0;
+    }
+#endif /* CSR_SUPPORT_SME && CSR_SUPPORT_WEXT*/
+
+    postfix = priv->instance;
+
+    if (is_fw == UNIFI_FW_STA) {
+        /* Free kernel buffer and reload */
+        uf_release_firmware(priv, &priv->fw_sta);
+#ifdef CSR_WIFI_SPLIT_PATCH
+        scnprintf(fw_name, UNIFI_MAX_FW_PATH_LEN, "unifi-sdio-%d/%s",
+                  postfix, (is_ap_mode(priv) ? "ap.xbv" : "staonly.xbv") );
+#else
+        scnprintf(fw_name, UNIFI_MAX_FW_PATH_LEN, "unifi-sdio-%d/%s",
+                  postfix, "sta.xbv" );
+#endif
+        r = request_firmware(&fw_entry, fw_name, priv->unifi_device);
+        if (r == 0) {
+            priv->fw_sta.dl_data = fw_entry->data;
+            priv->fw_sta.dl_len = fw_entry->size;
+            priv->fw_sta.fw_desc = (void *)fw_entry;
+        } else {
+            unifi_trace(priv, UDBG2, "Firmware file not available\n");
+        }
+    }
+
+    return 0;
+
+} /* uf_request_firmware_files() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_release_firmware_files
+ *
+ *      Release all buffers used to store firmware files
+ *
+ *  Arguments:
+ *      priv            Pointer to OS private struct.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+int uf_release_firmware_files(unifi_priv_t *priv)
+{
+    uf_release_firmware(priv, &priv->fw_sta);
+
+    return 0;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_release_firmware
+ *
+ *      Release specific buffer used to store firmware
+ *
+ *  Arguments:
+ *      priv            Pointer to OS private struct.
+ *      to_free         Pointer to specific buffer to release
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+int uf_release_firmware(unifi_priv_t *priv, struct dlpriv *to_free)
+{
+    if (to_free != NULL) {
+        if (to_free->fw_desc != NULL) {
+            release_firmware((const struct firmware *)to_free->fw_desc);
+        }
+        to_free->fw_desc = NULL;
+        to_free->dl_data = NULL;
+        to_free->dl_len = 0;
+    }
+    return 0;
+}
diff --git a/drivers/staging/csr/indications.c b/drivers/staging/csr/indications.c
new file mode 100644
index 0000000..834b5f3
--- /dev/null
+++ b/drivers/staging/csr/indications.c
@@ -0,0 +1,18 @@
+/*
+ * ***************************************************************************
+ * FILE:     indications.c
+ *
+ * PURPOSE:
+ *      Callbacks to process signals sent to us by the UniFi chip.
+ *
+ *      This file is linux-specific.
+ *
+ * Copyright (C) 2005-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ***************************************************************************
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "unifi_priv.h"
diff --git a/drivers/staging/csr/inet.c b/drivers/staging/csr/inet.c
new file mode 100644
index 0000000..b4acb54
--- /dev/null
+++ b/drivers/staging/csr/inet.c
@@ -0,0 +1,106 @@
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     inet.c
+ *
+ *  PURPOSE:
+ *      Routines related to IP address changes.
+ *      Optional part of the porting exercise. It uses system network
+ *      handlers to obtain the UniFi IP address and pass it to the SME
+ *      using the unifi_sys_ip_configured_ind().
+ *
+ * Copyright (C) 2008-2009 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include <linux/inetdevice.h>
+#include <linux/notifier.h>
+
+#include "unifi_priv.h"
+#include "csr_wifi_hip_conversions.h"
+
+/*
+ * The inet notifier is global and not per-netdev.  To avoid having a
+ * notifier registered when there are no unifi devices present, it's
+ * registered after the first unifi network device is registered, and
+ * unregistered when the last unifi network device is unregistered.
+ */
+
+static atomic_t inet_notif_refs = ATOMIC_INIT(0);
+
+static int uf_inetaddr_event(struct notifier_block *notif, unsigned long event, void *ifa)
+{
+    struct net_device *ndev;
+    unifi_priv_t *priv;
+    struct in_ifaddr *if_addr;
+    netInterface_priv_t *InterfacePriv = (netInterface_priv_t *)NULL;
+
+    if (!ifa || !((struct in_ifaddr *)ifa)->ifa_dev) {
+        unifi_trace(NULL, UDBG1, "uf_inetaddr_event (%lu) ifa=%p\n", event, ifa);
+        return NOTIFY_DONE;
+    }
+
+    ndev = ((struct in_ifaddr *)ifa)->ifa_dev->dev;
+    InterfacePriv = (netInterface_priv_t*) netdev_priv(ndev);
+
+    /* As the notifier is global, the call may be for a non-UniFi netdev.
+     * Therefore check the netdev_priv to make sure it's a known UniFi one.
+     */
+    if (uf_find_netdev_priv(InterfacePriv) == -1) {
+        unifi_trace(NULL, UDBG1, "uf_inetaddr_event (%lu) ndev=%p, other netdev_priv=%p\n",
+                    event, ndev, InterfacePriv);
+        return NOTIFY_DONE;
+    }
+
+    if (!InterfacePriv->privPtr) {
+        unifi_error(NULL, "uf_inetaddr_event null priv (%lu) ndev=%p, InterfacePriv=%p\n",
+                    event, ndev, InterfacePriv);
+        return NOTIFY_DONE;
+    }
+
+    priv = InterfacePriv->privPtr;
+    if_addr = (struct in_ifaddr *)ifa;
+
+    /* If this event is for a UniFi device, notify the SME that an IP
+     * address has been added or removed. */
+    if (uf_find_priv(priv) != -1) {
+        switch (event) {
+            case NETDEV_UP:
+                unifi_info(priv, "IP address assigned for %s\n", priv->netdev[InterfacePriv->InterfaceTag]->name);
+                priv->sta_ip_address = if_addr->ifa_address;
+#ifdef CSR_SUPPORT_WEXT
+                sme_mgt_packet_filter_set(priv);
+#endif
+                break;
+            case NETDEV_DOWN:
+                unifi_info(priv, "IP address removed for %s\n", priv->netdev[InterfacePriv->InterfaceTag]->name);
+                priv->sta_ip_address = 0xFFFFFFFF;
+#ifdef CSR_SUPPORT_WEXT
+                sme_mgt_packet_filter_set(priv);
+#endif
+                break;
+        }
+    }
+
+    return NOTIFY_DONE;
+}
+
+static struct notifier_block uf_inetaddr_notifier = {
+    .notifier_call = uf_inetaddr_event,
+};
+
+void uf_register_inet_notifier(void)
+{
+    if (atomic_inc_return(&inet_notif_refs) == 1) {
+        register_inetaddr_notifier(&uf_inetaddr_notifier);
+    }
+}
+
+void uf_unregister_inet_notifier(void)
+{
+    if (atomic_dec_return(&inet_notif_refs) == 0) {
+        unregister_inetaddr_notifier(&uf_inetaddr_notifier);
+    }
+}
diff --git a/drivers/staging/csr/init_hw.c b/drivers/staging/csr/init_hw.c
new file mode 100644
index 0000000..3b8a4ba
--- /dev/null
+++ b/drivers/staging/csr/init_hw.c
@@ -0,0 +1,108 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     init_hw.c
+ *
+ * PURPOSE:
+ *      Use the HIP core lib to initialise the UniFi chip.
+ *      It is part of the porting exercise in Linux.
+ *
+ * Copyright (C) 2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "unifi_priv.h"
+
+
+#define MAX_INIT_ATTEMPTS        4
+
+extern int led_mask;
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_init_hw
+ *
+ *      Resets hardware, downloads and initialises f/w.
+ *      This function demonstrates how to use the HIP core lib API
+ *      to implement the SME unifi_sys_wifi_on_req() part of the SYS API.
+ *
+ *      In a simple implementation, all this function needs to do is call
+ *      unifi_init_card() and then unifi_card_info().
+ *      In the Linux implementation, it will retry to initialise UniFi or
+ *      try to debug the reasons if unifi_init_card() returns an error.
+ *
+ *  Arguments:
+ *      ospriv          Pointer to OS driver structure for the device.
+ *
+ *  Returns:
+ *      O on success, non-zero otherwise.
+ *
+ * ---------------------------------------------------------------------------
+ */
+int
+uf_init_hw(unifi_priv_t *priv)
+{
+    int attempts = 0;
+    int priv_instance;
+    CsrResult csrResult = CSR_RESULT_FAILURE;
+
+    priv_instance = uf_find_priv(priv);
+    if (priv_instance == -1) {
+        unifi_warning(priv, "uf_init_hw: Unknown priv instance, will use fw_init[0]\n");
+        priv_instance = 0;
+    }
+
+    while (1) {
+        if (attempts > MAX_INIT_ATTEMPTS) {
+            unifi_error(priv, "Failed to initialise UniFi after %d attempts, "
+                        "giving up.\n",
+                        attempts);
+            break;
+        }
+        attempts++;
+
+        unifi_info(priv, "Initialising UniFi, attempt %d\n", attempts);
+
+        if (fw_init[priv_instance] > 0) {
+            unifi_notice(priv, "f/w init prevented by module parameter\n");
+            break;
+        } else if (fw_init[priv_instance] == 0) {
+            fw_init[priv_instance] ++;
+        }
+
+        /*
+         * Initialise driver core. This will perform a reset of UniFi
+         * internals, but not the SDIO CCCR.
+         */
+        CsrSdioClaim(priv->sdio);
+        csrResult = unifi_init_card(priv->card, led_mask);
+        CsrSdioRelease(priv->sdio);
+
+        if (csrResult == CSR_WIFI_HIP_RESULT_NO_DEVICE) {
+            return CsrHipResultToStatus(csrResult);
+        }
+        if (csrResult == CSR_WIFI_HIP_RESULT_NOT_FOUND) {
+            unifi_error(priv, "Firmware file required, but not found.\n");
+            return CsrHipResultToStatus(csrResult);
+        }
+        if (csrResult != CSR_RESULT_SUCCESS) {
+            /* failed. Reset h/w and try again */
+            unifi_error(priv, "Failed to initialise UniFi chip.\n");
+            continue;
+        }
+
+        /* Get the version information from the lib_hip */
+        unifi_card_info(priv->card, &priv->card_info);
+
+        return CsrHipResultToStatus(csrResult);
+    }
+
+    return CsrHipResultToStatus(csrResult);
+
+} /* uf_init_hw */
+
+
diff --git a/drivers/staging/csr/io.c b/drivers/staging/csr/io.c
new file mode 100644
index 0000000..f489ade
--- /dev/null
+++ b/drivers/staging/csr/io.c
@@ -0,0 +1,1166 @@
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     io.c
+ *
+ *  PURPOSE:
+ *      This file contains routines that the SDIO driver can call when a
+ *      UniFi card is first inserted (or detected) and removed.
+ *
+ *      When used with sdioemb, the udev scripts (at least on Ubuntu) don't
+ *      recognise a UniFi being added to the system. This is because sdioemb
+ *      does not register itself as a device_driver, it uses it's own code
+ *      to handle insert and remove.
+ *      To have Ubuntu recognise UniFi, edit /etc/udev/rules.d/85-ifupdown.rules
+ *      to change this line:
+ *          SUBSYSTEM=="net", DRIVERS=="?*", GOTO="net_start"
+ *      to these:
+ *          #SUBSYSTEM=="net", DRIVERS=="?*", GOTO="net_start"
+ *          SUBSYSTEM=="net", GOTO="net_start"
+ *
+ *      Then you can add a stanza to /etc/network/interfaces like this:
+ *          auto eth1
+ *          iface eth1 inet dhcp
+ *          wpa-conf /etc/wpa_supplicant.conf
+ *      This will then automatically associate when a car dis inserted.
+ *
+ * Copyright (C) 2006-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include <linux/proc_fs.h>
+
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_unifiversion.h"
+#include "csr_wifi_hip_unifi_udi.h"   /* for unifi_print_status() */
+#include "unifiio.h"
+#include "unifi_priv.h"
+
+
+/*
+ * Array of pointers to context structs for unifi devices that are present.
+ * The index in the array corresponds to the wlan interface number
+ * (if "wlan*" is used). If "eth*" is used, the eth* numbers are allocated
+ * after any Ethernet cards.
+ *
+ * The Arasan PCI-SDIO controller card supported by this driver has 2 slots,
+ * hence a max of 2 devices.
+ */
+static unifi_priv_t *Unifi_instances[MAX_UNIFI_DEVS];
+
+/* Array of pointers to netdev objects used by the UniFi driver, as there
+ * are now many per instance. This is used to determine which netdev events
+ * are for UniFi as opposed to other net interfaces.
+ */
+static netInterface_priv_t *Unifi_netdev_instances[MAX_UNIFI_DEVS * CSR_WIFI_NUM_INTERFACES];
+
+/*
+ * Array to hold the status of each unifi device in each slot.
+ * We only process an insert event when In_use[] for the slot is
+ * UNIFI_DEV_NOT_IN_USE. Otherwise, it means that the slot is in use or
+ * we are in the middle of a cleanup (the action on unplug).
+ */
+#define UNIFI_DEV_NOT_IN_USE    0
+#define UNIFI_DEV_IN_USE        1
+#define UNIFI_DEV_CLEANUP       2
+static int In_use[MAX_UNIFI_DEVS];
+/*
+ * Mutex to prevent UDI clients to open the character device before the priv
+ * is created and initialised.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+DEFINE_SEMAPHORE(Unifi_instance_mutex);
+#else
+DECLARE_MUTEX(Unifi_instance_mutex);
+#endif
+/*
+ * When the device is removed, unregister waits on Unifi_cleanup_wq
+ * until all the UDI clients release the character device.
+ */
+DECLARE_WAIT_QUEUE_HEAD(Unifi_cleanup_wq);
+
+
+static int uf_read_proc(char *page, char **start, off_t offset, int count,
+                        int *eof, void *data);
+
+#ifdef CSR_WIFI_RX_PATH_SPLIT
+
+static CsrResult signal_buffer_init(unifi_priv_t * priv, int size)
+{
+    int i;
+    func_enter();
+
+    priv->rxSignalBuffer.writePointer =
+    priv->rxSignalBuffer.readPointer = 0;
+    priv->rxSignalBuffer.size = size;
+    /* Allocating Memory for Signal primitive pointer */
+    for(i=0; i<size; i++)
+    {
+         priv->rxSignalBuffer.rx_buff[i].sig_len=0;
+         priv->rxSignalBuffer.rx_buff[i].bufptr = CsrMemAlloc(UNIFI_PACKED_SIGBUF_SIZE);
+         if (priv->rxSignalBuffer.rx_buff[i].bufptr == NULL)
+         {
+             int j;
+             unifi_error(priv,"signal_buffer_init:Failed to Allocate shared memory for T-H signals \n");
+             for(j=0;j<i;j++)
+             {
+                 priv->rxSignalBuffer.rx_buff[j].sig_len=0;
+                 CsrMemFree(priv->rxSignalBuffer.rx_buff[j].bufptr);
+                 priv->rxSignalBuffer.rx_buff[j].bufptr = NULL;
+             }
+             func_exit();
+             return -1;
+         }
+    }
+    func_exit();
+    return 0;
+}
+
+
+static void signal_buffer_free(unifi_priv_t * priv, int size)
+{
+    int i;
+
+    for(i=0; i<size; i++)
+    {
+         priv->rxSignalBuffer.rx_buff[i].sig_len=0;
+         CsrMemFree(priv->rxSignalBuffer.rx_buff[i].bufptr);
+         priv->rxSignalBuffer.rx_buff[i].bufptr = NULL;
+    }
+}
+#endif
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_register_netdev
+ *
+ *      Registers the network interface, installes the qdisc,
+ *      and registers the inet handler.
+ *      In the porting exercise, register the driver to the network
+ *      stack if necessary.
+ *
+ *  Arguments:
+ *      priv          Pointer to driver context.
+ *
+ *  Returns:
+ *      O on success, non-zero otherwise.
+ *
+ *  Notes:
+ *      We will only unregister when the card is ejected, so we must
+ *      only do it once.
+ * ---------------------------------------------------------------------------
+ */
+int
+uf_register_netdev(unifi_priv_t *priv, int interfaceTag)
+{
+    int r;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "uf_register_netdev bad interfaceTag\n");
+        return -EINVAL;
+    }
+
+    /*
+     * Allocates a device number and registers device with the network
+     * stack.
+     */
+    unifi_trace(priv, UDBG5, "uf_register_netdev: netdev %d - 0x%p\n",
+            interfaceTag, priv->netdev[interfaceTag]);
+    r = register_netdev(priv->netdev[interfaceTag]);
+    if (r) {
+        unifi_error(priv, "Failed to register net device\n");
+        return -EINVAL;
+    }
+
+    /* The device is registed */
+    interfacePriv->netdev_registered = 1;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+#ifdef CONFIG_NET_SCHED
+    /*
+     * IMPORTANT:
+     * uf_install_qdisc() holds the network device lock, we can not
+     * install the qdisk before the network device is registered.
+     */
+    r = uf_install_qdisc(priv->netdev[interfaceTag]);
+    if (r) {
+        unifi_error(priv, "Failed to install qdisc\n");
+        return r;
+    }
+#endif /* CONFIG_NET_SCHED */
+#endif /* LINUX_VERSION_CODE */
+
+#ifdef CSR_SUPPORT_SME
+    /*
+     * Register the inet handler; it notifies us for changes in the IP address.
+     */
+    uf_register_inet_notifier();
+#endif /* CSR_SUPPORT_SME */
+
+    unifi_notice(priv, "unifi%d is %s\n",
+            priv->instance, priv->netdev[interfaceTag]->name);
+
+    return 0;
+} /* uf_register_netdev */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_unregister_netdev
+ *
+ *      Unregisters the network interface and the inet handler.
+ *
+ *  Arguments:
+ *      priv          Pointer to driver context.
+ *
+ *  Returns:
+ *      None.
+ *
+ * ---------------------------------------------------------------------------
+ */
+void
+uf_unregister_netdev(unifi_priv_t *priv)
+{
+    int i=0;
+
+#ifdef CSR_SUPPORT_SME
+    /* Unregister the inet handler... */
+    uf_unregister_inet_notifier();
+#endif /* CSR_SUPPORT_SME */
+
+    for (i=0; i<CSR_WIFI_NUM_INTERFACES; i++) {
+        netInterface_priv_t *interfacePriv = priv->interfacePriv[i];
+        if (interfacePriv->netdev_registered) {
+            unifi_trace(priv, UDBG5,
+                    "uf_unregister_netdev: netdev %d - 0x%p\n",
+                    i, priv->netdev[i]);
+
+            /* ... and the netdev */
+            unregister_netdev(priv->netdev[i]);
+            interfacePriv->netdev_registered = 0;
+        }
+
+        interfacePriv->interfaceMode = 0;
+
+        /* Enable all queues by default */
+        interfacePriv->queueEnabled[0] = 1;
+        interfacePriv->queueEnabled[1] = 1;
+        interfacePriv->queueEnabled[2] = 1;
+        interfacePriv->queueEnabled[3] = 1;
+    }
+
+    priv->totalInterfaceCount = 0;
+} /* uf_unregister_netdev() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  register_unifi_sdio
+ *
+ *      This function is called from the Probe (or equivalent) method of
+ *      the SDIO driver when a UniFi card is detected.
+ *      We allocate the Linux net_device struct, initialise the HIP core
+ *      lib, create the char device nodes and start the userspace helper
+ *      to initialise the device.
+ *
+ *  Arguments:
+ *      sdio_dev        Pointer to SDIO context handle to use for all
+ *                      SDIO ops.
+ *      bus_id          A small number indicating the SDIO card position on the
+ *                      bus. Typically this is the slot number, e.g. 0, 1 etc.
+ *                      Valid values are 0 to MAX_UNIFI_DEVS-1.
+ *      dev             Pointer to kernel device manager struct.
+ *
+ *  Returns:
+ *      Pointer to the unifi instance, or NULL on error.
+ * ---------------------------------------------------------------------------
+ */
+static unifi_priv_t *
+register_unifi_sdio(CsrSdioFunction *sdio_dev, int bus_id, struct device *dev)
+{
+    unifi_priv_t *priv = NULL;
+    int r = -1;
+    CsrResult csrResult;
+
+    func_enter();
+
+    if ((bus_id < 0) || (bus_id >= MAX_UNIFI_DEVS)) {
+        unifi_error(priv, "register_unifi_sdio: invalid device %d\n",
+                bus_id);
+        return NULL;
+    }
+
+    down(&Unifi_instance_mutex);
+
+    if (In_use[bus_id] != UNIFI_DEV_NOT_IN_USE) {
+        unifi_error(priv, "register_unifi_sdio: device %d is already in use\n",
+                bus_id);
+        goto failed0;
+    }
+
+
+    /* Allocate device private and net_device structs */
+    priv = uf_alloc_netdevice(sdio_dev, bus_id);
+    if (priv == NULL) {
+        unifi_error(priv, "Failed to allocate driver private\n");
+        goto failed0;
+    }
+
+    priv->unifi_device = dev;
+
+    SET_NETDEV_DEV(priv->netdev[0], dev);
+
+    /* We are not ready to send data yet. */
+    netif_carrier_off(priv->netdev[0]);
+
+    /* Allocate driver context. */
+    priv->card = unifi_alloc_card(priv->sdio, priv);
+    if (priv->card == NULL) {
+        unifi_error(priv, "Failed to allocate UniFi driver card struct.\n");
+        goto failed1;
+    }
+
+    if (Unifi_instances[bus_id]) {
+        unifi_error(priv, "Internal error: instance for slot %d is already taken\n",
+                bus_id);
+    }
+    Unifi_instances[bus_id] = priv;
+    In_use[bus_id] = UNIFI_DEV_IN_USE;
+
+    /* Save the netdev_priv for use by the netdev event callback mechanism */
+    Unifi_netdev_instances[bus_id * CSR_WIFI_NUM_INTERFACES] = netdev_priv(priv->netdev[0]);
+
+    /* Initialise the mini-coredump capture buffers */
+    csrResult = unifi_coredump_init(priv->card, (CsrUint16)coredump_max);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv, "Couldn't allocate mini-coredump buffers\n");
+    }
+
+    /* Create the character device nodes */
+    r = uf_create_device_nodes(priv, bus_id);
+    if (r) {
+        goto failed1;
+    }
+
+    /*
+     * We use the slot number as unifi device index.
+     */
+    snprintf(priv->proc_entry_name, 64, "driver/unifi%d", priv->instance);
+    /*
+     * The following complex casting is in place in order to eliminate 64-bit compilation warning
+     * "cast to/from pointer from/to integer of different size"
+     */
+    if (!create_proc_read_entry(priv->proc_entry_name, 0, 0,
+                uf_read_proc, (void *)(long)priv->instance))
+    {
+        unifi_error(priv, "unifi: can't create /proc/driver/unifi\n");
+    }
+
+    /* Allocate the net_device for interfaces other than 0. */
+    {
+        int i;
+        priv->totalInterfaceCount =0;
+
+        for(i=1;i<CSR_WIFI_NUM_INTERFACES;i++)
+        {
+            if( !uf_alloc_netdevice_for_other_interfaces(priv,i) )
+            {
+                /* error occured while allocating the net_device for interface[i]. The net_device are
+                 * allocated for the interfaces with id<i. Dont worry, all the allocated net_device will
+                 * be releasing chen the control goes to the label failed0.
+                 */
+                unifi_error(priv, "Failed to allocate driver private for interface[%d]\n",i);
+                goto failed0;
+            }
+            else
+            {
+                SET_NETDEV_DEV(priv->netdev[i], dev);
+
+                /* We are not ready to send data yet. */
+                netif_carrier_off(priv->netdev[i]);
+
+                /* Save the netdev_priv for use by the netdev event callback mechanism */
+                Unifi_netdev_instances[bus_id * CSR_WIFI_NUM_INTERFACES + i] = netdev_priv(priv->netdev[i]);
+            }
+        }
+
+        for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++)
+        {
+            netInterface_priv_t *interfacePriv = priv->interfacePriv[i];
+            interfacePriv->netdev_registered=0;
+        }
+    }
+
+#ifdef CSR_WIFI_RX_PATH_SPLIT
+    if (signal_buffer_init(priv, CSR_WIFI_RX_SIGNAL_BUFFER_SIZE))
+    {
+        unifi_error(priv,"Failed to allocate shared memory for T-H signals\n");
+        goto failed2;
+    }
+    priv->rx_workqueue = create_singlethread_workqueue("rx_workq");
+    if (priv->rx_workqueue == NULL) {
+        unifi_error(priv,"create_singlethread_workqueue failed \n");
+        goto failed3;
+    }
+    INIT_WORK(&priv->rx_work_struct, rx_wq_handler);
+#endif
+
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+    if (log_hip_signals)
+    {
+        uf_register_hip_offline_debug(priv);
+    }
+#endif
+
+    /* Initialise the SME related threads and parameters */
+    r = uf_sme_init(priv);
+    if (r) {
+        unifi_error(priv, "SME initialisation failed.\n");
+        goto failed4;
+    }
+
+    /*
+     * Run the userspace helper program (unififw) to perform
+     * the device initialisation.
+     */
+    unifi_trace(priv, UDBG1, "run UniFi helper app...\n");
+    r = uf_run_unifihelper(priv);
+    if (r) {
+        unifi_notice(priv, "unable to run UniFi helper app\n");
+        /* Not a fatal error. */
+    }
+
+    up(&Unifi_instance_mutex);
+
+    func_exit();
+    return priv;
+
+failed4:
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+if (log_hip_signals)
+{
+    uf_unregister_hip_offline_debug(priv);
+}
+#endif
+#ifdef CSR_WIFI_RX_PATH_SPLIT
+    flush_workqueue(priv->rx_workqueue);
+    destroy_workqueue(priv->rx_workqueue);
+failed3:
+    signal_buffer_free(priv,CSR_WIFI_RX_SIGNAL_BUFFER_SIZE);
+failed2:
+#endif
+    /* Remove the device nodes */
+    uf_destroy_device_nodes(priv);
+failed1:
+    /* Deregister priv->netdev_client */
+    ul_deregister_client(priv->netdev_client);
+
+failed0:
+    if (priv && priv->card) {
+        unifi_coredump_free(priv->card);
+        unifi_free_card(priv->card);
+    }
+    if (priv) {
+        uf_free_netdevice(priv);
+    }
+
+    up(&Unifi_instance_mutex);
+
+    func_exit();
+    return NULL;
+} /* register_unifi_sdio() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  ask_unifi_sdio_cleanup
+ *
+ *      We can not free our private context, until all the char device
+ *      clients have closed the file handles. unregister_unifi_sdio() which
+ *      is called when a card is removed, waits on Unifi_cleanup_wq until
+ *      the reference count becomes zero. It is time to wake it up now.
+ *
+ *  Arguments:
+ *      priv          Pointer to driver context.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void
+ask_unifi_sdio_cleanup(unifi_priv_t *priv)
+{
+    func_enter();
+
+    /*
+     * Now clear the flag that says the old instance is in use.
+     * This is used to prevent a new instance being started before old
+     * one has finshed closing down, for example if bounce makes the card
+     * appear to be ejected and re-inserted quickly.
+     */
+    In_use[priv->instance] = UNIFI_DEV_CLEANUP;
+
+    unifi_trace(NULL, UDBG5, "ask_unifi_sdio_cleanup: wake up cleanup workqueue.\n");
+    wake_up(&Unifi_cleanup_wq);
+
+    func_exit();
+
+} /* ask_unifi_sdio_cleanup() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  cleanup_unifi_sdio
+ *
+ *      Release any resources owned by a unifi instance.
+ *
+ *  Arguments:
+ *      priv          Pointer to the instance to free.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void
+cleanup_unifi_sdio(unifi_priv_t *priv)
+{
+    int priv_instance;
+    int i;
+    static const CsrWifiMacAddress broadcast_address = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
+
+    func_enter();
+
+    /* Remove the device nodes */
+    uf_destroy_device_nodes(priv);
+
+    /* Mark this device as gone away by NULLing the entry in Unifi_instances */
+    Unifi_instances[priv->instance] = NULL;
+
+    unifi_trace(priv, UDBG5, "cleanup_unifi_sdio: remove_proc_entry\n");
+    /*
+     * Free the children of priv before unifi_free_netdevice() frees
+     * the priv struct
+     */
+    remove_proc_entry(priv->proc_entry_name, 0);
+
+
+    /* Unregister netdev as a client. */
+    if (priv->netdev_client) {
+        unifi_trace(priv, UDBG2, "Netdev client (id:%d s:0x%X) is unregistered\n",
+                priv->netdev_client->client_id, priv->netdev_client->sender_id);
+        ul_deregister_client(priv->netdev_client);
+    }
+
+    /* Destroy the SME related threads and parameters */
+    uf_sme_deinit(priv);
+
+#ifdef CSR_SME_USERSPACE
+    priv->smepriv = NULL;
+#endif
+
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+    if (log_hip_signals)
+    {
+        uf_unregister_hip_offline_debug(priv);
+    }
+#endif
+
+    /* Free any packets left in the Rx queues */
+    for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++)
+    {
+        uf_free_pending_rx_packets(priv, UF_UNCONTROLLED_PORT_Q, broadcast_address,i);
+        uf_free_pending_rx_packets(priv, UF_CONTROLLED_PORT_Q, broadcast_address,i);
+    }
+    /*
+     * We need to free the resources held by the core, which include tx skbs,
+     * otherwise we can not call unregister_netdev().
+     */
+    if (priv->card) {
+        unifi_trace(priv, UDBG5, "cleanup_unifi_sdio: free card\n");
+        unifi_coredump_free(priv->card);
+        unifi_free_card(priv->card);
+        priv->card = NULL;
+    }
+
+    /*
+     * Unregister the network device.
+     * We can not unregister the netdev before we release
+     * all pending packets in the core.
+     */
+    uf_unregister_netdev(priv);
+    priv->totalInterfaceCount = 0;
+
+    /* Clear the table of registered netdev_priv's */
+    for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) {
+        Unifi_netdev_instances[priv->instance * CSR_WIFI_NUM_INTERFACES + i] = NULL;
+    }
+
+    unifi_trace(priv, UDBG5, "cleanup_unifi_sdio: uf_free_netdevice\n");
+    /*
+     * When uf_free_netdevice() returns, the priv is invalid
+     * so we need to remember the instance to clear the global flag later.
+     */
+    priv_instance = priv->instance;
+
+#ifdef CSR_WIFI_RX_PATH_SPLIT
+    flush_workqueue(priv->rx_workqueue);
+    destroy_workqueue(priv->rx_workqueue);
+    signal_buffer_free(priv,CSR_WIFI_RX_SIGNAL_BUFFER_SIZE);
+#endif
+
+    /* Priv is freed as part of the net_device */
+    uf_free_netdevice(priv);
+
+    /*
+     * Now clear the flag that says the old instance is in use.
+     * This is used to prevent a new instance being started before old
+     * one has finshed closing down, for example if bounce makes the card
+     * appear to be ejected and re-inserted quickly.
+     */
+    In_use[priv_instance] = UNIFI_DEV_NOT_IN_USE;
+
+    unifi_trace(NULL, UDBG5, "cleanup_unifi_sdio: DONE.\n");
+
+    func_exit();
+
+} /* cleanup_unifi_sdio() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unregister_unifi_sdio
+ *
+ *      Call from SDIO driver when it detects that UniFi has been removed.
+ *
+ *  Arguments:
+ *      bus_id          Number of the card that was ejected.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void
+unregister_unifi_sdio(int bus_id)
+{
+    unifi_priv_t *priv;
+    int interfaceTag=0;
+    u8 reason = CONFIG_IND_EXIT;
+
+    if ((bus_id < 0) || (bus_id >= MAX_UNIFI_DEVS)) {
+        unifi_error(NULL, "unregister_unifi_sdio: invalid device %d\n",
+                bus_id);
+        return;
+    }
+
+    priv = Unifi_instances[bus_id];
+    if (priv == NULL) {
+        unifi_error(priv, "unregister_unifi_sdio: device %d is not registered\n",
+                bus_id);
+        func_exit();
+        return;
+    }
+
+    /* Stop the network traffic before freeing the core. */
+    for(interfaceTag=0;interfaceTag<priv->totalInterfaceCount;interfaceTag++)
+    {
+        netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+        if(interfacePriv->netdev_registered)
+        {
+            netif_carrier_off(priv->netdev[interfaceTag]);
+            UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[interfaceTag]);
+        }
+    }
+
+#ifdef CSR_NATIVE_LINUX
+    /*
+     * If the unifi thread was started, signal it to stop.  This
+     * should cause any userspace processes with open unifi device to
+     * close them.
+     */
+    uf_stop_thread(priv, &priv->bh_thread);
+
+    /* Unregister the interrupt handler */
+    if (csr_sdio_linux_remove_irq(priv->sdio)) {
+        unifi_notice(priv,
+                "csr_sdio_linux_remove_irq failed to talk to card.\n");
+    }
+
+    /* Ensure no MLME functions are waiting on a the mlme_event semaphore. */
+    uf_abort_mlme(priv);
+#endif /* CSR_NATIVE_LINUX */
+
+    ul_log_config_ind(priv, &reason, sizeof(u8));
+
+    /* Deregister the UDI hook from the core. */
+    unifi_remove_udi_hook(priv->card, logging_handler);
+
+    uf_put_instance(bus_id);
+
+    /*
+     * Wait until the device is cleaned up. i.e., when all userspace
+     * processes have closed any open unifi devices.
+     */
+    wait_event(Unifi_cleanup_wq, In_use[bus_id] == UNIFI_DEV_CLEANUP);
+    unifi_trace(NULL, UDBG5, "Received clean up event\n");
+
+    /* Now we can free the private context and the char device nodes */
+    cleanup_unifi_sdio(priv);
+
+} /* unregister_unifi_sdio() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_find_instance
+ *
+ *      Find the context structure for a given UniFi device instance.
+ *
+ *  Arguments:
+ *      inst            The instance number to look for.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+unifi_priv_t *
+uf_find_instance(int inst)
+{
+    if ((inst < 0) || (inst >= MAX_UNIFI_DEVS)) {
+        return NULL;
+    }
+    return Unifi_instances[inst];
+} /* uf_find_instance() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_find_priv
+ *
+ *      Find the device instance for a given context structure.
+ *
+ *  Arguments:
+ *      priv            The context structure pointer to look for.
+ *
+ *  Returns:
+ *      index of instance, -1 otherwise.
+ * ---------------------------------------------------------------------------
+ */
+int
+uf_find_priv(unifi_priv_t *priv)
+{
+    int inst;
+
+    if (!priv) {
+        return -1;
+    }
+
+    for (inst = 0; inst < MAX_UNIFI_DEVS; inst++) {
+        if (Unifi_instances[inst] == priv) {
+            return inst;
+        }
+    }
+
+    return -1;
+} /* uf_find_priv() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_find_netdev_priv
+ *
+ *      Find the device instance for a given netdev context structure.
+ *
+ *  Arguments:
+ *      priv            The context structure pointer to look for.
+ *
+ *  Returns:
+ *      index of instance, -1 otherwise.
+ * ---------------------------------------------------------------------------
+ */
+int
+uf_find_netdev_priv(netInterface_priv_t *priv)
+{
+    int inst;
+
+    if (!priv) {
+        return -1;
+    }
+
+    for (inst = 0; inst < MAX_UNIFI_DEVS * CSR_WIFI_NUM_INTERFACES; inst++) {
+        if (Unifi_netdev_instances[inst] == priv) {
+            return inst;
+        }
+    }
+
+    return -1;
+} /* uf_find_netdev_priv() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_get_instance
+ *
+ *      Find the context structure for a given UniFi device instance
+ *      and increment the reference count.
+ *
+ *  Arguments:
+ *      inst            The instance number to look for.
+ *
+ *  Returns:
+ *      Pointer to the instance or NULL if no instance exists.
+ * ---------------------------------------------------------------------------
+ */
+unifi_priv_t *
+uf_get_instance(int inst)
+{
+    unifi_priv_t *priv;
+
+    down(&Unifi_instance_mutex);
+
+    priv = uf_find_instance(inst);
+    if (priv) {
+        priv->ref_count++;
+    }
+
+    up(&Unifi_instance_mutex);
+
+    return priv;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_put_instance
+ *
+ *      Decrement the context reference count, freeing resources and
+ *      shutting down the driver when the count reaches zero.
+ *
+ *  Arguments:
+ *      inst            The instance number to look for.
+ *
+ *  Returns:
+ *      Pointer to the instance or NULL if no instance exists.
+ * ---------------------------------------------------------------------------
+ */
+void
+uf_put_instance(int inst)
+{
+    unifi_priv_t *priv;
+
+    down(&Unifi_instance_mutex);
+
+    priv = uf_find_instance(inst);
+    if (priv) {
+        priv->ref_count--;
+        if (priv->ref_count == 0) {
+            ask_unifi_sdio_cleanup(priv);
+        }
+    }
+
+    up(&Unifi_instance_mutex);
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_read_proc
+ *
+ *      Read method for driver node in /proc/driver/unifi0
+ *
+ *  Arguments:
+ *      page
+ *      start
+ *      offset
+ *      count
+ *      eof
+ *      data
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+#ifdef CONFIG_PROC_FS
+static int
+uf_read_proc(char *page, char **start, off_t offset, int count,
+        int *eof, void *data)
+{
+#define UNIFI_DEBUG_TXT_BUFFER 8*1024
+    unifi_priv_t *priv;
+    int actual_amount_to_copy;
+    char *p, *orig_p;
+    CsrInt32 remain = UNIFI_DEBUG_TXT_BUFFER;
+    CsrInt32 written;
+    int i;
+
+    /*
+    * The following complex casting is in place in order to eliminate 64-bit compilation warning
+    * "cast to/from pointer from/to integer of different size"
+    */
+    priv = uf_find_instance((int)(long)data);
+    if (!priv) {
+        return 0;
+    }
+
+    p = kmalloc( UNIFI_DEBUG_TXT_BUFFER, GFP_KERNEL );
+
+    orig_p = p;
+
+    written = CsrSnprintf(p, remain, "UniFi SDIO Driver: %s %s %s\n",
+            CSR_WIFI_VERSION, __DATE__, __TIME__);
+    UNIFI_SNPRINTF_RET(p, remain, written);
+#ifdef CSR_SME_USERSPACE
+    written = CsrSnprintf(p, remain, "SME: CSR userspace ");
+    UNIFI_SNPRINTF_RET(p, remain, written);
+#ifdef CSR_SUPPORT_WEXT
+    written = CsrSnprintf(p, remain, "with WEXT support\n");
+#else
+    written = CsrSnprintf(p, remain, "\n");
+#endif /* CSR_SUPPORT_WEXT */
+    UNIFI_SNPRINTF_RET(p, remain, written);
+#endif /* CSR_SME_USERSPACE */
+#ifdef CSR_NATIVE_LINUX
+    written = CsrSnprintf(p, remain, "SME: native\n");
+    UNIFI_SNPRINTF_RET(p, remain, written);
+#endif
+
+#ifdef CSR_SUPPORT_SME
+    written = CsrSnprintf(p, remain,
+            "Firmware (ROM) build:%lu, Patch:%lu\n",
+            priv->card_info.fw_build,
+            priv->sme_versions.firmwarePatch);
+    UNIFI_SNPRINTF_RET(p, remain, written);
+#endif
+    p += unifi_print_status(priv->card, p, &remain);
+
+    written = CsrSnprintf(p, remain, "Last dbg str: %s\n",
+            priv->last_debug_string);
+    UNIFI_SNPRINTF_RET(p, remain, written);
+
+    written = CsrSnprintf(p, remain, "Last dbg16:");
+    UNIFI_SNPRINTF_RET(p, remain, written);
+    for (i = 0; i < 8; i++) {
+        written = CsrSnprintf(p, remain, " %04X",
+                priv->last_debug_word16[i]);
+        UNIFI_SNPRINTF_RET(p, remain, written);
+    }
+    written = CsrSnprintf(p, remain, "\n");
+    UNIFI_SNPRINTF_RET(p, remain, written);
+    written = CsrSnprintf(p, remain, "           ");
+    UNIFI_SNPRINTF_RET(p, remain, written);
+    for (; i < 16; i++) {
+        written = CsrSnprintf(p, remain, " %04X",
+                priv->last_debug_word16[i]);
+        UNIFI_SNPRINTF_RET(p, remain, written);
+    }
+    written = CsrSnprintf(p, remain, "\n");
+    UNIFI_SNPRINTF_RET(p, remain, written);
+    *start = page;
+
+    written = UNIFI_DEBUG_TXT_BUFFER - remain;
+
+    if( offset >= written )
+    {
+        *eof = 1;
+        kfree( orig_p );
+        return(0);
+    }
+
+    if( offset + count > written )
+    {
+        actual_amount_to_copy = written - offset;
+        *eof = 1;
+    }
+    else
+    {
+        actual_amount_to_copy = count;
+    }
+
+    memcpy( page, &(orig_p[offset]), actual_amount_to_copy );
+
+    kfree( orig_p );
+
+    return( actual_amount_to_copy );
+} /* uf_read_proc() */
+#endif
+
+
+
+
+static void
+uf_lx_suspend(CsrSdioFunction *sdio_ctx)
+{
+    unifi_priv_t *priv = sdio_ctx->driverData;
+    unifi_suspend(priv);
+
+    CsrSdioSuspendAcknowledge(sdio_ctx, CSR_RESULT_SUCCESS);
+}
+
+static void
+uf_lx_resume(CsrSdioFunction *sdio_ctx)
+{
+    unifi_priv_t *priv = sdio_ctx->driverData;
+    unifi_resume(priv);
+
+    CsrSdioResumeAcknowledge(sdio_ctx, CSR_RESULT_SUCCESS);
+}
+
+static int active_slot = MAX_UNIFI_DEVS;
+static struct device *os_devices[MAX_UNIFI_DEVS];
+
+void
+uf_add_os_device(int bus_id, struct device *os_device)
+{
+    if ((bus_id < 0) || (bus_id >= MAX_UNIFI_DEVS)) {
+        unifi_error(NULL, "uf_add_os_device: invalid device %d\n",
+                bus_id);
+        return;
+    }
+
+    active_slot = bus_id;
+    os_devices[bus_id] = os_device;
+} /* uf_add_os_device() */
+
+void
+uf_remove_os_device(int bus_id)
+{
+    if ((bus_id < 0) || (bus_id >= MAX_UNIFI_DEVS)) {
+        unifi_error(NULL, "uf_remove_os_device: invalid device %d\n",
+                bus_id);
+        return;
+    }
+
+    active_slot = bus_id;
+    os_devices[bus_id] = NULL;
+} /* uf_remove_os_device() */
+
+static void
+uf_sdio_inserted(CsrSdioFunction *sdio_ctx)
+{
+    unifi_priv_t *priv;
+
+    unifi_trace(NULL, UDBG5, "uf_sdio_inserted(0x%p), slot_id=%d, dev=%p\n",
+            sdio_ctx, active_slot, os_devices[active_slot]);
+
+    priv = register_unifi_sdio(sdio_ctx, active_slot, os_devices[active_slot]);
+    if (priv == NULL) {
+        CsrSdioInsertedAcknowledge(sdio_ctx, CSR_RESULT_FAILURE);
+        return;
+    }
+
+    sdio_ctx->driverData = priv;
+
+    CsrSdioInsertedAcknowledge(sdio_ctx, CSR_RESULT_SUCCESS);
+} /* uf_sdio_inserted() */
+
+
+static void
+uf_sdio_removed(CsrSdioFunction *sdio_ctx)
+{
+    unregister_unifi_sdio(active_slot);
+    CsrSdioRemovedAcknowledge(sdio_ctx);
+} /* uf_sdio_removed() */
+
+
+static void
+uf_sdio_dsr_handler(CsrSdioFunction *sdio_ctx)
+{
+    unifi_priv_t *priv = sdio_ctx->driverData;
+
+    unifi_sdio_interrupt_handler(priv->card);
+} /* uf_sdio_dsr_handler() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_sdio_int_handler
+ *
+ *      Interrupt callback function for SDIO interrupts.
+ *      This is called in kernel context (i.e. not interrupt context).
+ *      We retrieve the unifi context pointer and call the main UniFi
+ *      interrupt handler.
+ *
+ *  Arguments:
+ *      fdev      SDIO context pointer
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static CsrSdioInterruptDsrCallback
+uf_sdio_int_handler(CsrSdioFunction *sdio_ctx)
+{
+    return uf_sdio_dsr_handler;
+} /* uf_sdio_int_handler() */
+
+
+
+
+static CsrSdioFunctionId unifi_ids[] =
+{
+    {
+        .manfId = SDIO_MANF_ID_CSR,
+        .cardId = SDIO_CARD_ID_UNIFI_3,
+        .sdioFunction = SDIO_WLAN_FUNC_ID_UNIFI_3,
+        .sdioInterface = CSR_SDIO_ANY_SDIO_INTERFACE,
+    },
+    {
+        .manfId = SDIO_MANF_ID_CSR,
+        .cardId = SDIO_CARD_ID_UNIFI_4,
+        .sdioFunction = SDIO_WLAN_FUNC_ID_UNIFI_4,
+        .sdioInterface = CSR_SDIO_ANY_SDIO_INTERFACE,
+    }
+};
+
+
+/*
+ * Structure to register with the glue layer.
+ */
+static CsrSdioFunctionDriver unifi_sdioFunction_drv =
+{
+    .inserted = uf_sdio_inserted,
+    .removed = uf_sdio_removed,
+    .intr = uf_sdio_int_handler,
+    .suspend = uf_lx_suspend,
+    .resume = uf_lx_resume,
+
+    .ids = unifi_ids,
+    .idsCount = sizeof(unifi_ids) / sizeof(unifi_ids[0])
+};
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_sdio_load
+ *  uf_sdio_unload
+ *
+ *      These functions are called from the main module load and unload
+ *      functions. They perform the appropriate operations for the monolithic
+ *      driver.
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+int __init
+uf_sdio_load(void)
+{
+    CsrResult csrResult;
+
+    csrResult = CsrSdioFunctionDriverRegister(&unifi_sdioFunction_drv);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(NULL, "Failed to register UniFi SDIO driver: csrResult=%d\n", csrResult);
+        return -EIO;
+    }
+
+    return 0;
+} /* uf_sdio_load() */
+
+
+
+void __exit
+uf_sdio_unload(void)
+{
+    CsrSdioFunctionDriverUnregister(&unifi_sdioFunction_drv);
+} /* uf_sdio_unload() */
+
diff --git a/drivers/staging/csr/mlme.c b/drivers/staging/csr/mlme.c
new file mode 100644
index 0000000..790d5d7
--- /dev/null
+++ b/drivers/staging/csr/mlme.c
@@ -0,0 +1,441 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     mlme.c
+ *
+ * PURPOSE:
+ *      This file provides functions to send MLME requests to the UniFi.
+ *
+ * Copyright (C) 2007-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "unifi_priv.h"
+
+
+/* The additional time taken by the UniFi to do a scan per channel */
+#define SCAN_STARTUP_TIME       300 /* in millisecs */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * unifi_mlme_wait_for_reply
+ *
+ *      Wait for a reply after sending a signal.
+ *
+ * Arguments:
+ *      priv            Pointer to device private context struct
+ *      ul_client       Pointer to linux client
+ *      sig_reply_id    ID of the expected reply (defined in sigs.h).
+ *      timeout         timeout in ms
+ *
+ * Returns:
+ *      0 on success, -ve POSIX code on error.
+ *
+ * Notes:
+ *      This function waits for a specific (sig_reply_id) signal from UniFi.
+ *      It also match the sequence number of the received (cfm) signal, with
+ *      the latest sequence number of the signal (req) we have sent.
+ *      These two number match be equal.
+ *      Should only be used for waiting xxx.cfm signals and only after
+ *      we have sent the matching xxx.req signal to UniFi.
+ *      If no response is received within the expected time (timeout), we assume
+ *      that the UniFi is busy and return an error.
+ *      If the wait is aborted by a kernel signal arriving, we stop waiting.
+ *      If a response from UniFi is not what we expected, we discard it and
+ *      wait again. This could be a response from an aborted request. If we
+ *      see several bad responses we assume we have lost synchronisation with
+ *      UniFi.
+ * ---------------------------------------------------------------------------
+ */
+static int
+unifi_mlme_wait_for_reply(unifi_priv_t *priv, ul_client_t *pcli, int sig_reply_id, int timeout)
+{
+    int retries = 0;
+    long r;
+    long t = timeout;
+    unsigned int sent_seq_no;
+
+    /* Convert t in ms to jiffies */
+    t = msecs_to_jiffies(t);
+
+    do {
+        /* Wait for the confirm or timeout. */
+        r = wait_event_interruptible_timeout(pcli->udi_wq,
+                                             (pcli->wake_up_wq_id) || (priv->io_aborted == 1),
+                                             t);
+        /* Check for general i/o error */
+        if (priv->io_aborted) {
+            unifi_error(priv, "MLME operation aborted\n");
+            return -EIO;
+        }
+
+        /*
+         * If r=0 the request has timed-out.
+         * If r>0 the request has completed successfully.
+         * If r=-ERESTARTSYS an event (kill signal) has interrupted the wait_event.
+         */
+        if ((r == 0) && (pcli->wake_up_wq_id == 0)) {
+            unifi_error(priv, "mlme_wait: timed-out waiting for 0x%.4X, after %lu msec.\n",
+                        sig_reply_id,  jiffies_to_msecs(t));
+            pcli->wake_up_wq_id = 0;
+            return -ETIMEDOUT;
+        } else if (r == -ERESTARTSYS) {
+            unifi_error(priv, "mlme_wait: waiting for 0x%.4X was aborted.\n", sig_reply_id);
+            pcli->wake_up_wq_id = 0;
+            return -EINTR;
+        } else {
+            /* Get the sequence number of the signal that we previously set. */
+            if (pcli->seq_no != 0) {
+                sent_seq_no = pcli->seq_no - 1;
+            } else {
+                sent_seq_no = 0x0F;
+            }
+
+            unifi_trace(priv, UDBG5, "Received 0x%.4X, seq: (r:%d, s:%d)\n",
+                        pcli->wake_up_wq_id,
+                        pcli->wake_seq_no, sent_seq_no);
+
+            /* The two sequence ids must match. */
+            if (pcli->wake_seq_no == sent_seq_no) {
+                /* and the signal ids must match. */
+                if (sig_reply_id == pcli->wake_up_wq_id) {
+                    /* Found the expected signal */
+                    break;
+                } else {
+                    /* This should never happen ... */
+                    unifi_error(priv, "mlme_wait: mismatching signal id (0x%.4X - exp 0x%.4X) (seq %d)\n",
+                                pcli->wake_up_wq_id,
+                                sig_reply_id,
+                                pcli->wake_seq_no);
+                    pcli->wake_up_wq_id = 0;
+                    return -EIO;
+                }
+            }
+            /* Wait for the next signal. */
+            pcli->wake_up_wq_id = 0;
+
+            retries ++;
+            if (retries >= 3) {
+                unifi_error(priv, "mlme_wait: confirm wait retries exhausted (0x%.4X - exp 0x%.4X)\n",
+                            pcli->wake_up_wq_id,
+                            sig_reply_id);
+                pcli->wake_up_wq_id = 0;
+                return -EIO;
+            }
+        }
+    } while (1);
+
+    pcli->wake_up_wq_id = 0;
+
+    return 0;
+} /* unifi_mlme_wait_for_reply() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * unifi_mlme_blocking_request
+ *
+ *      Send a MLME request signal to UniFi.
+ *
+ * Arguments:
+ *      priv            Pointer to device private context struct
+ *      pcli            Pointer to context of calling process
+ *      sig             Pointer to the signal to send
+ *      data_ptrs       Pointer to the bulk data of the signal
+ *      timeout         The request's timeout.
+ *
+ * Returns:
+ *      0 on success, 802.11 result code on error.
+ * ---------------------------------------------------------------------------
+ */
+int
+unifi_mlme_blocking_request(unifi_priv_t *priv, ul_client_t *pcli,
+                            CSR_SIGNAL *sig, bulk_data_param_t *data_ptrs,
+                            int timeout)
+{
+    int r;
+
+    func_enter();
+
+    if (sig->SignalPrimitiveHeader.SignalId == 0) {
+        unifi_error(priv, "unifi_mlme_blocking_request: Invalid Signal Id (0x%x)\n",
+                    sig->SignalPrimitiveHeader.SignalId);
+        return -EINVAL;
+    }
+
+    down(&priv->mlme_blocking_mutex);
+
+    sig->SignalPrimitiveHeader.ReceiverProcessId = 0;
+    sig->SignalPrimitiveHeader.SenderProcessId = pcli->sender_id | pcli->seq_no;
+
+    unifi_trace(priv, UDBG2, "Send client=%d, S:0x%04X, sig 0x%.4X\n",
+                pcli->client_id,
+                sig->SignalPrimitiveHeader.SenderProcessId,
+                sig->SignalPrimitiveHeader.SignalId);
+    /* Send the signal to UniFi */
+    r = ul_send_signal_unpacked(priv, sig, data_ptrs);
+    if (r) {
+        up(&priv->mlme_blocking_mutex);
+        unifi_error(priv, "Error queueing MLME REQUEST signal\n");
+        return r;
+    }
+
+    unifi_trace(priv, UDBG5, "Send 0x%.4X, seq = %d\n",
+                sig->SignalPrimitiveHeader.SignalId, pcli->seq_no);
+
+    /*
+     * Advance the sequence number of the last sent signal, only
+     * if the signal has been successfully set.
+     */
+    pcli->seq_no++;
+    if (pcli->seq_no > 0x0F) {
+        pcli->seq_no = 0;
+    }
+
+    r = unifi_mlme_wait_for_reply(priv, pcli, (sig->SignalPrimitiveHeader.SignalId + 1), timeout);
+    up(&priv->mlme_blocking_mutex);
+
+    if (r) {
+        unifi_error(priv, "Error waiting for MLME CONFIRM signal\n");
+        return r;
+    }
+
+    func_exit();
+    return 0;
+} /* unifi_mlme_blocking_request() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_mlme_copy_reply_and_wakeup_client
+ *
+ *      Copy the reply signal from UniFi to the client's structure
+ *      and wake up the waiting client.
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+unifi_mlme_copy_reply_and_wakeup_client(ul_client_t *pcli,
+                                        CSR_SIGNAL *signal, int signal_len,
+                                        const bulk_data_param_t *bulkdata)
+{
+    int i;
+
+    /* Copy the signal to the reply */
+    memcpy(pcli->reply_signal, signal, signal_len);
+
+    /* Get the sequence number of the signal that woke us up. */
+    pcli->wake_seq_no = pcli->reply_signal->SignalPrimitiveHeader.ReceiverProcessId & 0x0F;
+
+    /* Append any bulk data */
+    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
+        if (bulkdata->d[i].data_length > 0) {
+            if (bulkdata->d[i].os_data_ptr) {
+                memcpy(pcli->reply_bulkdata[i]->ptr, bulkdata->d[i].os_data_ptr, bulkdata->d[i].data_length);
+                pcli->reply_bulkdata[i]->length = bulkdata->d[i].data_length;
+            } else {
+                pcli->reply_bulkdata[i]->length = 0;
+            }
+        }
+    }
+
+    /* Wake the requesting MLME function. */
+    pcli->wake_up_wq_id = pcli->reply_signal->SignalPrimitiveHeader.SignalId;
+    wake_up_interruptible(&pcli->udi_wq);
+
+} /* unifi_mlme_copy_reply_and_wakeup_client() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_abort_mlme
+ *
+ *      Abort any MLME operation in progress.
+ *      This is used in the error recovery mechanism.
+ *
+ *  Arguments:
+ *      priv          Pointer to driver context.
+ *
+ *  Returns:
+ *      0 on success.
+ * ---------------------------------------------------------------------------
+ */
+int
+uf_abort_mlme(unifi_priv_t *priv)
+{
+    ul_client_t *ul_cli;
+
+    /* Ensure no MLME functions are waiting on a the mlme_event semaphore. */
+    priv->io_aborted = 1;
+
+    ul_cli = priv->netdev_client;
+    if (ul_cli) {
+        wake_up_interruptible(&ul_cli->udi_wq);
+    }
+
+    ul_cli = priv->wext_client;
+    if (ul_cli) {
+        wake_up_interruptible(&ul_cli->udi_wq);
+    }
+
+    return 0;
+} /* uf_abort_mlme() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ *      Human-readable decoding of Reason and Result codes.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+struct mlme_code {
+    const char *name;
+    int id;
+};
+
+static const struct mlme_code Result_codes[] = {
+    { "Success",                             0x0000 },
+    { "Unspecified Failure",                 0x0001 },
+    /* (Reserved)                      0x0002 - 0x0009 */
+    { "Refused Capabilities Mismatch",       0x000A },
+    /* (Reserved)                          0x000B */
+    { "Refused External Reason",             0x000C },
+    /* (Reserved)                      0x000D - 0x0010 */
+    { "Refused AP Out Of Memory",            0x0011 },
+    { "Refused Basic Rates Mismatch",        0x0012 },
+    /* (Reserved)                      0x0013 - 0x001F */
+    { "Failure",                             0x0020 },
+    /* (Reserved)                      0x0021 - 0x0024 */
+    { "Refused Reason Unspecified",          0x0025 },
+    { "Invalid Parameters",                  0x0026 },
+    { "Rejected With Suggested Changes",     0x0027 },
+    /* (Reserved)                      0x0028 - 0x002E */
+    { "Rejected For Delay Period",           0x002F },
+    { "Not Allowed",                         0x0030 },
+    { "Not Present",                         0x0031 },
+    { "Not QSTA",                            0x0032 },
+    /* (Reserved)                      0x0033 - 0x7FFF */
+    { "Timeout",                             0x8000 },
+    { "Too Many Simultaneous Requests",      0x8001 },
+    { "BSS Already Started Or Joined",       0x8002 },
+    { "Not Supported",                       0x8003 },
+    { "Transmission Failure",                0x8004 },
+    { "Refused Not Authenticated",           0x8005 },
+    { "Reset Required Before Start",         0x8006 },
+    { "LM Info Unavailable",                 0x8007 },
+    { NULL, -1 }
+};
+
+static const struct mlme_code Reason_codes[] = {
+    /* (Reserved)                      0x0000 */
+    { "Unspecified Reason",              0x0001 },
+    { "Authentication Not Valid",        0x0002 },
+    { "Deauthenticated Leave BSS",       0x0003 },
+    { "Disassociated Inactivity",        0x0004 },
+    { "AP Overload",                     0x0005 },
+    { "Class2 Frame Error",              0x0006 },
+    { "Class3 Frame Error",              0x0007 },
+    { "Disassociated Leave BSS",         0x0008 },
+    { "Association Not Authenticated",   0x0009 },
+    { "Disassociated Power Capability",  0x000A },
+    { "Disassociated Supported Channels", 0x000B },
+    /* (Reserved)                      0x000C */
+    { "Invalid Information Element",     0x000D },
+    { "Michael MIC Failure",             0x000E },
+    { "Fourway Handshake Timeout",       0x000F },
+    { "Group Key Update Timeout",        0x0010 },
+    { "Handshake Element Different",     0x0011 },
+    { "Invalid Group Cipher",            0x0012 },
+    { "Invalid Pairwise Cipher",         0x0013 },
+    { "Invalid AKMP",                    0x0014 },
+    { "Unsupported RSN IE Version",      0x0015 },
+    { "Invalid RSN IE Capabilities",     0x0016 },
+    { "Dot1X Auth Failed",               0x0017 },
+    { "Cipher Rejected By Policy",       0x0018 },
+    /* (Reserved)                  0x0019 - 0x001F */
+    { "QoS Unspecified Reason",          0x0020 },
+    { "QoS Insufficient Bandwidth",      0x0021 },
+    { "QoS Excessive Not Ack",           0x0022 },
+    { "QoS TXOP Limit Exceeded",         0x0023 },
+    { "QSTA Leaving",                    0x0024 },
+    { "End TS, End DLS, End BA",         0x0025 },
+    { "Unknown TS, Unknown DLS, Unknown BA", 0x0026 },
+    { "Timeout",                         0x0027 },
+    /* (Reserved)                  0x0028 - 0x002C */
+    { "STAKey Mismatch",                 0x002D },
+    { NULL, -1 }
+};
+
+
+static const char *
+lookup_something(const struct mlme_code *n, int id)
+{
+    for (; n->name; n++) {
+        if (n->id == id) {
+            return n->name;
+        }
+    }
+
+    /* not found */
+    return NULL;
+} /* lookup_something() */
+
+
+const char *
+lookup_result_code(int result)
+{
+    static char fallback[16];
+    const char *str;
+
+    str = lookup_something(Result_codes, result);
+
+    if (str == NULL) {
+        snprintf(fallback, 16, "%d", result);
+        str = fallback;
+    }
+
+    return str;
+} /* lookup_result_code() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  lookup_reason
+ *
+ *      Return a description string for a WiFi MLME ReasonCode.
+ *
+ *  Arguments:
+ *      reason          The ReasonCode to interpret.
+ *
+ *  Returns:
+ *      Pointer to description string.
+ * ---------------------------------------------------------------------------
+ */
+const char *
+lookup_reason_code(int reason)
+{
+    static char fallback[16];
+    const char *str;
+
+    str = lookup_something(Reason_codes, reason);
+
+    if (str == NULL) {
+        snprintf(fallback, 16, "%d", reason);
+        str = fallback;
+    }
+
+    return str;
+} /* lookup_reason_code() */
+
diff --git a/drivers/staging/csr/monitor.c b/drivers/staging/csr/monitor.c
new file mode 100644
index 0000000..7648d2b
--- /dev/null
+++ b/drivers/staging/csr/monitor.c
@@ -0,0 +1,458 @@
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     monitor.c
+ *
+ * Copyright (C) 2006-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+#include "unifi_priv.h"
+
+#ifdef UNIFI_SNIFF_ARPHRD
+
+
+#if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
+#include <net/ieee80211_radiotap.h>
+#endif
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW ETH_P_ALL
+#endif
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_start_sniff
+ *
+ *      Start UniFi capture in SNIFF mode, i.e capture everything it hears.
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *
+ *  Returns:
+ *      0 on success or kernel error code
+ * ---------------------------------------------------------------------------
+ */
+int
+uf_start_sniff(unifi_priv_t *priv)
+{
+    ul_client_t *pcli = priv->wext_client;
+    CSR_SIGNAL signal;
+    CSR_MLME_SNIFFJOIN_REQUEST *req = &signal.u.MlmeSniffjoinRequest;
+    int timeout = 1000;
+    int r;
+
+    req->Ifindex = priv->if_index;
+    req->Channel = priv->wext_conf.channel;
+    req->ChannelStartingFactor = 0;
+
+#if 0
+    printk("SniffJoin: Ifindex=%d, Channel=%d, ChannelStartingFactor=%d\n",
+           req->Ifindex,
+           req->Channel,
+           req->ChannelStartingFactor);
+#endif
+
+    signal.SignalPrimitiveHeader.SignalId = CSR_MLME_SNIFFJOIN_REQUEST_ID;
+
+    r = unifi_mlme_blocking_request(priv, pcli, &signal, NULL, timeout);
+    if (r < 0) {
+        unifi_error(priv, "failed to send SNIFFJOIN request, error %d\n", r);
+        return r;
+    }
+
+    r = pcli->reply_signal->u.MlmeSniffjoinConfirm.Resultcode;
+    if (r) {
+        unifi_notice(priv, "SNIFFJOIN request was rejected with result 0x%X (%s)\n",
+                     r, lookup_result_code(r));
+        return -EIO;
+    }
+
+    return 0;
+} /* uf_start_sniff() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * netrx_radiotap
+ *
+ *      Reformat a UniFi SNIFFDATA signal into a radiotap packet.
+ *
+ * Arguments:
+ *      priv            OS private context pointer.
+ *      ind             Pointer to a MA_UNITDATA_INDICATION or
+ *                      DS_UNITDATA_INDICATION indication structure.
+ *
+ * Notes:
+ *      Radiotap header values are all little-endian, UniFi signals will have
+ *      been converted to host-endian.
+ * ---------------------------------------------------------------------------
+ */
+#if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
+static void
+netrx_radiotap(unifi_priv_t *priv,
+               const CSR_MA_SNIFFDATA_INDICATION *ind,
+               struct sk_buff *skb_orig)
+{
+    struct net_device *dev = priv->netdev;
+    struct sk_buff *skb = NULL;
+    unsigned char *ptr;
+    unsigned char *base;
+    int ind_data_len = skb_orig->len - 2 - ETH_HLEN;
+    struct unifi_rx_radiotap_header {
+        struct ieee80211_radiotap_header rt_hdr;
+        /* IEEE80211_RADIOTAP_TSFT */
+        u64 rt_tsft;
+        /* IEEE80211_RADIOTAP_FLAGS */
+        u8  rt_flags;
+        /* IEEE80211_RADIOTAP_RATE */
+        u8  rt_rate;
+        /* IEEE80211_RADIOTAP_CHANNEL */
+        u16 rt_chan;
+        u16 rt_chan_flags;
+        /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
+        u8  rt_dbm_antsignal;
+        /* IEEE80211_RADIOTAP_DBM_ANTNOISE */
+        u8  rt_dbm_antnoise;
+        /* IEEE80211_RADIOTAP_ANTENNA */
+        u8  rt_antenna;
+
+        /* pad to 4-byte boundary */
+        u8 pad[3];
+    } __attribute__((__packed__));
+
+    struct unifi_rx_radiotap_header *unifi_rt;
+    int signal, noise, snr;
+
+    func_enter();
+
+    if (ind_data_len <= 0) {
+        unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
+        return;
+    }
+
+    /*
+     * Allocate a SKB for the received data packet, including radiotap
+     * header.
+     */
+    skb = dev_alloc_skb(ind_data_len + sizeof(struct unifi_rx_radiotap_header) + 4);
+    if (! skb) {
+        unifi_error(priv, "alloc_skb failed.\n");
+        priv->stats.rx_errors++;
+        return;
+    }
+
+    base = skb->data;
+
+    /* Reserve the radiotap header at the front of skb */
+    unifi_rt = (struct unifi_rx_radiotap_header *)
+        skb_put(skb, sizeof(struct unifi_rx_radiotap_header));
+
+    /* Copy in the 802.11 frame */
+    ptr = skb_put(skb, ind_data_len);
+    memcpy(ptr, skb_orig->data, ind_data_len);
+
+    unifi_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+    unifi_rt->rt_hdr.it_pad = 0;	/* always good to zero */
+    unifi_rt->rt_hdr.it_len = sizeof(struct unifi_rx_radiotap_header);
+
+    /* Big bitfield of all the fields we provide in radiotap */
+    unifi_rt->rt_hdr.it_present = 0
+        | (1 << IEEE80211_RADIOTAP_TSFT)
+        | (1 << IEEE80211_RADIOTAP_FLAGS)
+        | (1 << IEEE80211_RADIOTAP_RATE)
+        | (1 << IEEE80211_RADIOTAP_CHANNEL)
+        | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL)
+        | (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)
+        | (1 << IEEE80211_RADIOTAP_ANTENNA)
+        ;
+
+
+    /* No flags to set */
+    unifi_rt->rt_tsft = (((u64)ind->Timestamp.x[7]) | (((u64)ind->Timestamp.x[6]) << 8) |
+                         (((u64)ind->Timestamp.x[5]) << 16) | (((u64)ind->Timestamp.x[4]) << 24) |
+                         (((u64)ind->Timestamp.x[3]) << 32) | (((u64)ind->Timestamp.x[2]) << 40) |
+                         (((u64)ind->Timestamp.x[1]) << 48) | (((u64)ind->Timestamp.x[0]) << 56));
+
+    unifi_rt->rt_flags = 0;
+
+    unifi_rt->rt_rate = ind->Rate;
+
+    unifi_rt->rt_chan = cpu_to_le16(ieee80211chan2mhz(priv->wext_conf.channel));
+    unifi_rt->rt_chan_flags = 0;
+
+    /* Convert signal to dBm */
+    signal = (s16)unifi2host_16(ind->Rssi);  /* in dBm */
+    snr    = (s16)unifi2host_16(ind->Snr);   /* in dB */
+    noise  = signal - snr;
+
+    unifi_rt->rt_dbm_antsignal = signal;
+    unifi_rt->rt_dbm_antnoise = noise;
+
+    unifi_rt->rt_antenna = ind->AntennaId;
+
+
+#if 0
+    printk("skb datalen=%d\n", skb->len);
+    dump(skb->data, 48);
+#endif
+
+    skb->dev = dev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+    skb->mac_header = skb->data;
+#else
+    skb->mac.raw = skb->data;
+#endif
+    skb->pkt_type = PACKET_OTHERHOST;
+    skb->protocol = __constant_htons(ETH_P_80211_RAW);
+    memset(skb->cb, 0, sizeof(skb->cb));
+
+    /* Pass up to Linux network stack */
+    netif_rx_ni(skb);
+
+    dev->last_rx = jiffies;
+
+    /* Bump the rx stats */
+    priv->stats.rx_packets++;
+    priv->stats.rx_bytes += ind_data_len;
+
+    func_exit();
+} /* netrx_radiotap() */
+#endif /* RADIOTAP */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * netrx_prism
+ *
+ *      Reformat a UniFi SNIFFDATA signal into a Prism format sniff packet.
+ *
+ * Arguments:
+ *      priv            OS private context pointer.
+ *      ind             Pointer to a MA_UNITDATA_INDICATION or
+ *                      DS_UNITDATA_INDICATION indication structure.
+ *
+ * Notes:
+ *      Radiotap header values are all little-endian, UniFi signals will have
+ *      been converted to host-endian.
+ * ---------------------------------------------------------------------------
+ */
+#if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
+static void
+netrx_prism(unifi_priv_t *priv,
+            const CSR_MA_SNIFFDATA_INDICATION *ind,
+            struct sk_buff *skb_orig)
+{
+    struct net_device *dev = priv->netdev;
+    struct sk_buff *skb = NULL;
+    unsigned char *ptr;
+    unsigned char *base;
+    int ind_data_len = skb_orig->len - 2 - ETH_HLEN;
+#define WLANCAP_MAGIC_COOKIE_BASE 0x80211000
+#define WLANCAP_MAGIC_COOKIE_V1 0x80211001
+#define WLANCAP_MAGIC_COOKIE_V2 0x80211002
+    struct avs_header_v1 {
+        uint32  version;
+        uint32  length;
+        uint64  mactime;
+        uint64  hosttime;
+        uint32  phytype;
+        uint32  channel;
+        uint32  datarate;
+        uint32  antenna;
+        uint32  priority;
+        uint32  ssi_type;
+        int32   ssi_signal;
+        int32   ssi_noise;
+        uint32  preamble;
+        uint32  encoding;
+    } *avs;
+    int signal, noise, snr;
+
+    func_enter();
+
+    if (ind_data_len <= 0) {
+        unifi_error(priv, "Invalid length in CSR_MA_SNIFFDATA_INDICATION.\n");
+        return;
+    }
+
+#if 0
+    printk("MA-SINFFDATA.ind: DataLen=%d bytes, TSF %02X %02X %02X %02X %02X %02X %02X %02X, Rate=%d, Antenna=%d\n",
+           ind->Data.DataLength,
+           ind->Timestamp.x[0],
+           ind->Timestamp.x[1],
+           ind->Timestamp.x[2],
+           ind->Timestamp.x[3],
+           ind->Timestamp.x[4],
+           ind->Timestamp.x[5],
+           ind->Timestamp.x[6],
+           ind->Timestamp.x[7],
+           ind->Rate,
+           ind->Antenna);
+
+    printk("payload, len %d\n", length);
+    dump((unsigned char *)payload, 32);
+#endif
+
+    /*
+     * Allocate a SKB for the received data packet, including radiotap
+     * header.
+     */
+    skb = dev_alloc_skb(ind_data_len + sizeof(struct avs_header_v1) + 4);
+    if (! skb) {
+        unifi_error(priv, "alloc_skb failed.\n");
+        priv->stats.rx_errors++;
+        return;
+    }
+
+    base = skb->data;
+
+    /* Reserve the radiotap header at the front of skb */
+    avs = (struct avs_header_v1 *)skb_put(skb, sizeof(struct avs_header_v1));
+
+    /* Copy in the 802.11 frame */
+    ptr = skb_put(skb, ind_data_len);
+    memcpy(ptr, skb_orig->data, ind_data_len);
+
+    /* Convert signal to dBm */
+    signal = 0x10000 - ((s16)unifi2host_16(ind->Rssi));  /* in dBm */
+    snr    = (s16)unifi2host_16(ind->Snr);   /* in dB */
+    noise  = signal - snr;
+
+    avs->version        = htonl(WLANCAP_MAGIC_COOKIE_V1);
+    avs->length         = htonl(sizeof(struct avs_header_v1));
+    avs->mactime        = __cpu_to_be64(ind->Timestamp);
+    avs->hosttime       = __cpu_to_be64(jiffies);
+    avs->phytype        = htonl(9);             /* dss_ofdm_dot11_g */
+    avs->channel        = htonl(priv->wext_conf.channel);
+    avs->datarate       = htonl(ind->Rate * 5);
+    avs->antenna        = htonl(ind->Antenna);
+    avs->priority       = htonl(0);             /* unknown */
+    avs->ssi_type       = htonl(2);             /* dBm */
+    avs->ssi_signal     = htonl(signal);
+    avs->ssi_noise      = htonl(noise);
+    avs->preamble       = htonl(0); /* unknown */
+    avs->encoding       = htonl(0); /* unknown */
+
+
+#if 0
+    printk("skb datalen=%d\n", skb->len);
+    dump(skb->data, 48);
+#endif
+
+    skb->dev = dev;
+    skb->mac.raw = skb->data;
+    skb->pkt_type = PACKET_OTHERHOST;
+    skb->protocol = __constant_htons(ETH_P_80211_RAW);
+    memset(skb->cb, 0, sizeof(skb->cb));
+
+    /* Pass up to Linux network stack */
+    netif_rx_ni(skb);
+
+    dev->last_rx = jiffies;
+
+    /* Bump the rx stats */
+    priv->stats.rx_packets++;
+    priv->stats.rx_bytes += ind_data_len;
+
+    func_exit();
+} /* netrx_prism() */
+#endif /* PRISM */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * ma_sniffdata_ind
+ *
+ *      Reformat a UniFi SNIFFDATA signal into a network
+ *
+ * Arguments:
+ *      ospriv          OS private context pointer.
+ *      ind             Pointer to a MA_UNITDATA_INDICATION or
+ *                      DS_UNITDATA_INDICATION indication structure.
+ *      bulkdata        Pointer to a bulk data structure, describing
+ *                      the data received.
+ *
+ * Notes:
+ *      Radiotap header values are all little-endian, UniFi signals will have
+ *      been converted to host-endian.
+ * ---------------------------------------------------------------------------
+ */
+void
+ma_sniffdata_ind(void *ospriv,
+                 const CSR_MA_SNIFFDATA_INDICATION *ind,
+                 const bulk_data_param_t *bulkdata)
+{
+    unifi_priv_t *priv = ospriv;
+    struct net_device *dev = priv->netdev;
+    struct sk_buff *skb = (struct sk_buff*)bulkdata->d[0].os_net_buf_ptr;
+
+    func_enter();
+
+    if (bulkdata->d[0].data_length == 0) {
+        unifi_warning(priv, "rx: MA-SNIFFDATA indication with zero bulk data\n");
+        func_exit();
+        return;
+    }
+
+    skb->len = bulkdata->d[0].data_length;
+#if 0
+    printk("MA-SNIFFDATA.ind: DataLen=%d bytes, TSF %02X %02X %02X %02X %02X %02X %02X %02X, Rate=%d, Antenna=%d\n",
+           ind->Data.DataLength,
+           ind->Timestamp.x[0],
+           ind->Timestamp.x[1],
+           ind->Timestamp.x[2],
+           ind->Timestamp.x[3],
+           ind->Timestamp.x[4],
+           ind->Timestamp.x[5],
+           ind->Timestamp.x[6],
+           ind->Timestamp.x[7],
+           ind->Rate,
+           ind->AntennaId);
+
+    printk("payload, len %lu\n", bulkdata->d[0].data_length);
+    if (bulkdata->d[0].os_data_ptr && (bulkdata->d[0].data_length >= 32)) {
+        dump((unsigned char *)bulkdata->d[0].os_data_ptr, 32);
+    }
+#endif
+
+    /* We only process data packets if the interface is open */
+    if (unlikely(!netif_running(dev))) {
+        priv->stats.rx_dropped++;
+        priv->wext_conf.wireless_stats.discard.misc++;
+#if 0
+        printk("Dropping packet while interface is not up.\n");
+#endif
+        dev_kfree_skb(skb);
+        return;
+    }
+
+    if (ind->ReceptionStatus) {
+        priv->stats.rx_dropped++;
+        priv->wext_conf.wireless_stats.discard.misc++;
+        printk(KERN_INFO "unifi: Dropping corrupt sniff packet\n");
+        dev_kfree_skb(skb);
+        return;
+    }
+
+#if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_PRISM)
+    netrx_prism(priv, ind, skb);
+#endif /* PRISM */
+
+#if (UNIFI_SNIFF_ARPHRD == ARPHRD_IEEE80211_RADIOTAP)
+    netrx_radiotap(priv, ind, skb);
+#endif /* RADIOTAP */
+
+    dev_kfree_skb(skb);
+
+} /* ma_sniffdata_ind() */
+
+
+#endif /* UNIFI_SNIFF_ARPHRD */
+
diff --git a/drivers/staging/csr/netdev.c b/drivers/staging/csr/netdev.c
new file mode 100644
index 0000000..cf19f11
--- /dev/null
+++ b/drivers/staging/csr/netdev.c
@@ -0,0 +1,3998 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     netdev.c
+ *
+ * PURPOSE:
+ *      This file provides the upper edge interface to the linux netdevice
+ *      and wireless extensions.
+ *      It is part of the porting exercise.
+ *
+ * Copyright (C) 2005-2010 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+
+/*
+ * Porting Notes:
+ * This file implements the data plane of the UniFi linux driver.
+ *
+ * All the Tx packets are passed to the HIP core lib, using the
+ * unifi_send_signal() API. For EAPOL packets use the MLME-EAPOL.req
+ * signal, for all other use the MLME-UNITDATA.req. The unifi_send_signal()
+ * expects the wire-formatted (packed) signal. For convenience, in the OS
+ * layer we only use the native (unpacked) signal structures. The HIP core lib
+ * provides the write_pack() helper function to convert to the packed signal.
+ * The packet is stored in the bulk data of the signal. We do not need to
+ * allocate new memory to store the packet, because unifi_net_data_malloc()
+ * is implemented to return a skb, which is the format of packet in Linux.
+ * The HIP core lib frees the bulk data buffers, so we do not need to do
+ * this in the OS layer.
+ *
+ * All the Rx packets are MLME-UNITDATA.ind signals, passed by the HIP core lib
+ * in unifi_receive_event(). We do not need to allocate an skb and copy the
+ * received packet because the HIP core lib has stored in memory allocated by
+ * unifi_net_data_malloc(). Also, we can perform the 802.11 to Ethernet
+ * translation in-place because we allocate the extra memory allocated in
+ * unifi_net_data_malloc().
+ *
+ * If possible, the porting exercise should appropriately implement
+ * unifi_net_data_malloc() and unifi_net_data_free() to save copies between
+ * network and driver buffers.
+ */
+
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include <linux/mutex.h>
+#include <linux/semaphore.h>
+
+#include <linux/vmalloc.h>
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_conversions.h"
+#include "unifi_priv.h"
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
+#include <net/iw_handler.h>
+#endif
+#include <net/pkt_sched.h>
+
+
+/* ALLOW_Q_PAUSE: Pre 2.6.28 kernels do not support multiple driver queues (required for QoS).
+ * In order to support QoS in these kernels, multiple queues are implemented in the driver. But since
+ * there is only a single queue in the kernel (leading to multiple queues in the driver) there is no possibility
+ * of stopping a particular queue in the kernel. Stopping the single kernel queue leads to undesirable starvation
+ * of driver queues. One of the proposals is to not stop the kernel queue but to prevent dequeuing from the
+ * 'stopped' driver queue. Allow q pause is an experimental implementation of this scheme for pre 2.6.28 kernels.
+ * When NOT defined, queues are paused locally in the driver and packets are dequeued for transmission only from the
+ * unpaused queues. When Allow q pause is defined the kernel queue is stopped whenever any driver queue is paused.
+ */
+#define ALLOW_Q_PAUSE
+
+#define ieee2host16(n)  __le16_to_cpu(n)
+#define ieee2host32(n)  __le32_to_cpu(n)
+#define host2ieee16(n)  __cpu_to_le16(n)
+#define host2ieee32(n)  __cpu_to_le32(n)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+#ifdef UNIFI_NET_NAME
+#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues)     \
+    do {                                                                \
+        static char name[8];                                           \
+        sprintf(name, "%s%s", UNIFI_NET_NAME, _name);                   \
+        _dev = alloc_netdev_mq(_size, name, _setup, _num_of_queues);    \
+    } while (0);
+#else
+#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues)     \
+    do {                                                                \
+        _dev = alloc_etherdev_mq(_size, _num_of_queues);                \
+    } while (0);
+#endif /* UNIFI_NET_NAME */
+#else
+#ifdef UNIFI_NET_NAME
+#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues)     \
+    do {                                                                \
+        static char name[8];                                           \
+        sprintf(name, "%s%s", UNIFI_NET_NAME, _name);                   \
+        _dev = alloc_netdev(_size, name, _setup);                       \
+    } while (0);
+#else
+#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues)     \
+    do {                                                                \
+        _dev = alloc_etherdev(_size);                                   \
+    } while (0);
+#endif /* UNIFI_NET_NAME */
+#endif /* LINUX_VERSION_CODE */
+
+
+/* Wext handler is suported only if CSR_SUPPORT_WEXT is defined */
+#ifdef CSR_SUPPORT_WEXT
+extern struct iw_handler_def unifi_iw_handler_def;
+#endif /* CSR_SUPPORT_WEXT */
+static void check_ba_frame_age_timeout( unifi_priv_t *priv,
+                                            netInterface_priv_t *interfacePriv,
+                                            ba_session_rx_struct *ba_session);
+static void process_ba_frame(unifi_priv_t *priv,
+                             netInterface_priv_t *interfacePriv,
+                             ba_session_rx_struct *ba_session,
+                             frame_desc_struct *frame_desc);
+static void process_ba_complete(unifi_priv_t *priv, netInterface_priv_t *interfacePriv);
+static void process_ma_packet_error_ind(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata);
+static void process_amsdu(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata);
+static int uf_net_open(struct net_device *dev);
+static int uf_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int uf_net_stop(struct net_device *dev);
+static struct net_device_stats *uf_net_get_stats(struct net_device *dev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+static u16 uf_net_select_queue(struct net_device *dev, struct sk_buff *skb);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+static netdev_tx_t uf_net_xmit(struct sk_buff *skb, struct net_device *dev);
+#else
+static int uf_net_xmit(struct sk_buff *skb, struct net_device *dev);
+#ifndef NETDEV_TX_OK
+#define NETDEV_TX_OK        0
+#endif
+#ifndef NETDEV_TX_BUSY
+#define NETDEV_TX_BUSY      1
+#endif
+#endif
+static void uf_set_multicast_list(struct net_device *dev);
+
+
+typedef int (*tx_signal_handler)(unifi_priv_t *priv, struct sk_buff *skb, const struct ethhdr *ehdr, CSR_PRIORITY priority);
+
+#ifdef CONFIG_NET_SCHED
+/*
+ * Queueing Discipline Interface
+ * Only used if kernel is configured with CONFIG_NET_SCHED
+ */
+
+/*
+ * The driver uses the qdisc interface to buffer and control all
+ * outgoing traffic. We create a root qdisc, register our qdisc operations
+ * and later we create two subsiduary pfifo queues for the uncontrolled
+ * and controlled ports.
+ *
+ * The network stack delivers all outgoing packets in our enqueue handler.
+ * There, we classify the packet and decide whether to store it or drop it
+ * (if the controlled port state is set to "discard").
+ * If the packet is enqueued, the network stack call our dequeue handler.
+ * There, we decide whether we can send the packet, delay it or drop it
+ * (the controlled port configuration might have changed meanwhile).
+ * If a packet is dequeued, then the network stack calls our hard_start_xmit
+ * handler where finally we send the packet.
+ *
+ * If the hard_start_xmit handler fails to send the packet, we return
+ * NETDEV_TX_BUSY and the network stack call our requeue handler where
+ * we put the packet back in the same queue in came from.
+ *
+ */
+
+struct uf_sched_data
+{
+    /* Traffic Classifier TBD */
+    struct tcf_proto *filter_list;
+    /* Our two queues */
+    struct Qdisc *queues[UNIFI_TRAFFIC_Q_MAX];
+};
+
+struct uf_tx_packet_data {
+    /* Queue the packet is stored in */
+    unifi_TrafficQueue queue;
+    /* QoS Priority determined when enqueing packet */
+    CSR_PRIORITY priority;
+    /* Debug */
+    unsigned long host_tag;
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+static int uf_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd);
+static int uf_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd);
+static struct sk_buff *uf_qdiscop_dequeue(struct Qdisc* qd);
+static void uf_qdiscop_reset(struct Qdisc* qd);
+static void uf_qdiscop_destroy(struct Qdisc* qd);
+static int uf_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+static int uf_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt);
+static int uf_qdiscop_init(struct Qdisc *qd, struct nlattr *opt);
+#else
+static int uf_qdiscop_tune(struct Qdisc *qd, struct rtattr *opt);
+static int uf_qdiscop_init(struct Qdisc *qd, struct rtattr *opt);
+#endif
+#endif
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+/* queueing discipline operations */
+static struct Qdisc_ops uf_qdisc_ops =
+{
+    .next = NULL,
+    .cl_ops = NULL,
+    .id = "UniFi Qdisc",
+    .priv_size = sizeof(struct uf_sched_data),
+
+    .enqueue = uf_qdiscop_enqueue,
+    .dequeue = uf_qdiscop_dequeue,
+    .requeue = uf_qdiscop_requeue,
+    .drop = NULL, /* drop not needed since we are always the root qdisc */
+
+    .init = uf_qdiscop_init,
+    .reset = uf_qdiscop_reset,
+    .destroy = uf_qdiscop_destroy,
+    .change = uf_qdiscop_tune,
+
+    .dump = uf_qdiscop_dump,
+};
+#endif /* LINUX_VERSION_CODE */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root)         \
+    qdisc_create_dflt(dev, netdev_get_tx_queue(_dev, 0), _ops, _root)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root)         \
+    qdisc_create_dflt(dev, _ops, _root)
+#else
+#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root)         \
+    qdisc_create_dflt(dev, _ops)
+#endif /* LINUX_VERSION_CODE */
+
+#endif /* CONFIG_NET_SCHED */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+static const struct net_device_ops uf_netdev_ops =
+{
+    .ndo_open = uf_net_open,
+    .ndo_stop = uf_net_stop,
+    .ndo_start_xmit = uf_net_xmit,
+    .ndo_do_ioctl = uf_net_ioctl,
+    .ndo_get_stats = uf_net_get_stats, /* called by /proc/net/dev */
+    .ndo_set_rx_mode = uf_set_multicast_list,
+    .ndo_select_queue = uf_net_select_queue,
+};
+#endif
+
+static u8 oui_rfc1042[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
+static u8 oui_8021h[P80211_OUI_LEN]   = { 0x00, 0x00, 0xf8 };
+
+
+/* Callback for event logging to blocking clients */
+static void netdev_mlme_event_handler(ul_client_t  *client,
+                                      const u8 *sig_packed, int sig_len,
+                                      const bulk_data_param_t *bulkdata,
+                                      int dir);
+
+#ifdef CSR_SUPPORT_WEXT
+/* Declare netdev_notifier block which will contain the state change
+ * handler callback function
+ */
+static struct notifier_block uf_netdev_notifier;
+#endif
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_alloc_netdevice
+ *
+ *      Allocate memory for the net_device and device private structs
+ *      for this interface.
+ *      Fill in the fields, but don't register the interface yet.
+ *      We need to configure the UniFi first.
+ *
+ *  Arguments:
+ *      sdio_dev        Pointer to SDIO context handle to use for all
+ *                      SDIO ops.
+ *      bus_id          A small number indicating the SDIO card position on the
+ *                      bus. Typically this is the slot number, e.g. 0, 1 etc.
+ *                      Valid values are 0 to MAX_UNIFI_DEVS-1.
+ *
+ *  Returns:
+ *      Pointer to device private struct.
+ *
+ *  Notes:
+ *      The net_device and device private structs are allocated together
+ *      and should be freed by freeing the net_device pointer.
+ * ---------------------------------------------------------------------------
+ */
+unifi_priv_t *
+uf_alloc_netdevice(CsrSdioFunction *sdio_dev, int bus_id)
+{
+    struct net_device *dev;
+    unifi_priv_t *priv;
+    netInterface_priv_t *interfacePriv;
+#ifdef CSR_SUPPORT_WEXT
+    int rc;
+#endif
+    unsigned char i; /* loop index */
+
+    /*
+     * Allocate netdevice struct, assign name template and
+     * setup as an ethernet device.
+     * The net_device and private structs are zeroed. Ether_setup() then
+     * sets up ethernet handlers and values.
+     * The RedHat 9 redhat-config-network tool doesn't recognise wlan* devices,
+     * so use "eth*" (like other wireless extns drivers).
+     */
+    UF_ALLOC_NETDEV(dev, sizeof(unifi_priv_t)+sizeof(netInterface_priv_t), "%d", ether_setup, UNIFI_TRAFFIC_Q_MAX);
+
+    if (dev == NULL) {
+        return NULL;
+    }
+
+    /* Set up back pointer from priv to netdev */
+    interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    priv = (unifi_priv_t *)(interfacePriv + 1);
+    interfacePriv->privPtr = priv;
+    interfacePriv->InterfaceTag = 0;
+
+
+    /* Initialize all supported netdev interface to be NULL */
+    for(i=0; i<CSR_WIFI_NUM_INTERFACES; i++) {
+        priv->netdev[i] = NULL;
+        priv->interfacePriv[i] = NULL;
+    }
+    priv->netdev[0] = dev;
+    priv->interfacePriv[0] = interfacePriv;
+
+    /* Setup / override net_device fields */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+    dev->netdev_ops = &uf_netdev_ops;
+#else
+    dev->open             = uf_net_open;
+    dev->stop             = uf_net_stop;
+    dev->hard_start_xmit  = uf_net_xmit;
+    dev->do_ioctl         = uf_net_ioctl;
+
+    /* called by /proc/net/dev */
+    dev->get_stats = uf_net_get_stats;
+
+    dev->set_multicast_list = uf_set_multicast_list;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+    dev->select_queue       = uf_net_select_queue;
+#endif
+#endif
+
+#ifdef CSR_SUPPORT_WEXT
+    dev->wireless_handlers = &unifi_iw_handler_def;
+#if IW_HANDLER_VERSION < 6
+    dev->get_wireless_stats = unifi_get_wireless_stats;
+#endif /* IW_HANDLER_VERSION */
+#endif /* CSR_SUPPORT_WEXT */
+
+    /* This gives us enough headroom to add the 802.11 header */
+    dev->needed_headroom = 32;
+
+    /* Use bus_id as instance number */
+    priv->instance = bus_id;
+    /* Store SDIO pointer to pass in the core */
+    priv->sdio = sdio_dev;
+
+    sdio_dev->driverData = (void*)priv;
+    /* Consider UniFi to be uninitialised */
+    priv->init_progress = UNIFI_INIT_NONE;
+
+    priv->prev_queue = 0;
+
+    /*
+     * Initialise the clients structure array.
+     * We do not need protection around ul_init_clients() because
+     * the character device can not be used until uf_alloc_netdevice()
+     * returns and Unifi_instances[bus_id]=priv is set, since unifi_open()
+     * will return -ENODEV.
+     */
+    ul_init_clients(priv);
+
+    /*
+     * Register a new ul client to send the multicast list signals.
+     * Note: priv->instance must be set before calling this.
+     */
+    priv->netdev_client = ul_register_client(priv,
+            0,
+            netdev_mlme_event_handler);
+    if (priv->netdev_client == NULL) {
+        unifi_error(priv,
+                "Failed to register a unifi client for background netdev processing\n");
+        free_netdev(priv->netdev[0]);
+        return NULL;
+    }
+    unifi_trace(priv, UDBG2, "Netdev %p client (id:%d s:0x%X) is registered\n",
+            dev, priv->netdev_client->client_id, priv->netdev_client->sender_id);
+
+    priv->sta_wmm_capabilities = 0;
+
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_SUPPORT_SME))
+    priv->wapi_multicast_filter = 0;
+    priv->wapi_unicast_filter = 0;
+    priv->wapi_unicast_queued_pkt_filter = 0;
+#ifdef CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND
+    priv->isWapiConnection = FALSE;
+#endif
+#endif
+
+    /* Enable all queues by default */
+    interfacePriv->queueEnabled[0] = 1;
+    interfacePriv->queueEnabled[1] = 1;
+    interfacePriv->queueEnabled[2] = 1;
+    interfacePriv->queueEnabled[3] = 1;
+
+#ifdef CSR_SUPPORT_SME
+    priv->allPeerDozing = 0;
+#endif
+    /*
+     * Initialise the OS private struct.
+     */
+    /*
+     * Instead of deciding in advance to use 11bg or 11a, we could do a more
+     * clever scan on both radios.
+     */
+    if (use_5g) {
+        priv->if_index = CSR_INDEX_5G;
+        unifi_info(priv, "Using the 802.11a radio\n");
+    } else {
+        priv->if_index = CSR_INDEX_2G4;
+    }
+
+    /* Initialise bh thread structure */
+    priv->bh_thread.thread_task = NULL;
+    priv->bh_thread.block_thread = 1;
+    init_waitqueue_head(&priv->bh_thread.wakeup_q);
+    priv->bh_thread.wakeup_flag = 0;
+    sprintf(priv->bh_thread.name, "uf_bh_thread");
+
+    /* reset the connected state for the interface */
+    interfacePriv->connected = UnifiConnectedUnknown;  /* -1 unknown, 0 no, 1 yes */
+
+#ifdef USE_DRIVER_LOCK
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+    sema_init(&priv->lock, 1);
+#else
+    init_MUTEX(&priv->lock);
+#endif
+#endif /* USE_DRIVER_LOCK */
+
+    spin_lock_init(&priv->send_signal_lock);
+
+    spin_lock_init(&priv->m4_lock);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+    sema_init(&priv->ba_mutex, 1);
+#else
+    init_MUTEX(&priv->ba_mutex);
+#endif
+
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
+    spin_lock_init(&priv->wapi_lock);
+#endif
+
+#ifdef CSR_SUPPORT_SME
+    spin_lock_init(&priv->staRecord_lock);
+    spin_lock_init(&priv->tx_q_lock);
+#endif
+
+    /* Create the Traffic Analysis workqueue */
+    priv->unifi_workqueue = create_singlethread_workqueue("unifi_workq");
+    if (priv->unifi_workqueue == NULL) {
+        /* Deregister priv->netdev_client */
+        ul_deregister_client(priv->netdev_client);
+        free_netdev(priv->netdev[0]);
+        return NULL;
+    }
+
+#ifdef CSR_SUPPORT_SME
+    /* Create the Multicast Addresses list work structure */
+    INIT_WORK(&priv->multicast_list_task, uf_multicast_list_wq);
+
+    /* Create m4 buffering work structure */
+    INIT_WORK(&interfacePriv->send_m4_ready_task, uf_send_m4_ready_wq);
+
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
+    /* Create work structure to buffer the WAPI data packets to be sent to SME for encryption */
+    INIT_WORK(&interfacePriv->send_pkt_to_encrypt, uf_send_pkt_to_encrypt);
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+#ifdef CONFIG_NET_SCHED
+    /* Register the qdisc operations */
+    register_qdisc(&uf_qdisc_ops);
+#endif /* CONFIG_NET_SCHED */
+#endif /* LINUX_VERSION_CODE */
+
+    priv->ref_count = 1;
+
+
+    priv->amp_client = NULL;
+    priv->coredump_mode = 0;
+    priv->ptest_mode = 0;
+    priv->wol_suspend = FALSE;
+    INIT_LIST_HEAD(&interfacePriv->rx_uncontrolled_list);
+    INIT_LIST_HEAD(&interfacePriv->rx_controlled_list);
+    sema_init(&priv->rx_q_sem, 1);
+
+#ifdef CSR_SUPPORT_WEXT
+    interfacePriv->netdev_callback_registered = FALSE;
+    interfacePriv->wait_netdev_change = FALSE;
+    /* Register callback for netdevice state changes */
+    if ((rc = register_netdevice_notifier(&uf_netdev_notifier)) == 0) {
+        interfacePriv->netdev_callback_registered = TRUE;
+    }
+    else {
+        unifi_warning(priv, "Failed to register netdevice notifier : %d %p\n", rc, dev);
+    }
+#endif /* CSR_SUPPORT_WEXT */
+
+#ifdef CSR_WIFI_SPLIT_PATCH
+    /* set it to some invalid value */
+    priv->pending_mode_set.common.destination = 0xaaaa;
+#endif
+
+    return priv;
+} /* uf_alloc_netdevice() */
+
+/*
+ *---------------------------------------------------------------------------
+ *  uf_alloc_netdevice_for_other_interfaces
+ *
+ *      Allocate memory for the net_device and device private structs
+ *      for this interface.
+ *      Fill in the fields, but don't register the interface yet.
+ *      We need to configure the UniFi first.
+ *
+ *  Arguments:
+ *      interfaceTag   Interface number.
+ *      sdio_dev        Pointer to SDIO context handle to use for all
+ *                      SDIO ops.
+ *      bus_id          A small number indicating the SDIO card position on the
+ *                      bus. Typically this is the slot number, e.g. 0, 1 etc.
+ *                      Valid values are 0 to MAX_UNIFI_DEVS-1.
+ *
+ *  Returns:
+ *      Pointer to device private struct.
+ *
+ *  Notes:
+ *      The device private structure contains the interfaceTag and pointer to the unifi_priv
+ *      structure created allocated by net_device od interface0.
+ *      The net_device and device private structs are allocated together
+ *      and should be freed by freeing the net_device pointer.
+ * ---------------------------------------------------------------------------
+ */
+CsrBool
+uf_alloc_netdevice_for_other_interfaces(unifi_priv_t *priv, CsrUint16 interfaceTag)
+{
+    struct net_device *dev;
+    netInterface_priv_t *interfacePriv;
+
+    /*
+     * Allocate netdevice struct, assign name template and
+     * setup as an ethernet device.
+     * The net_device and private structs are zeroed. Ether_setup() then
+     * sets up ethernet handlers and values.
+     * The RedHat 9 redhat-config-network tool doesn't recognise wlan* devices,
+     * so use "eth*" (like other wireless extns drivers).
+     */
+    UF_ALLOC_NETDEV(dev, sizeof(netInterface_priv_t), "%d", ether_setup, 1);
+    if (dev == NULL) {
+        return FALSE;
+    }
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "uf_alloc_netdevice_for_other_interfaces bad interfaceTag\n");
+        return FALSE;
+    }
+
+    /* Set up back pointer from priv to netdev */
+    interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    interfacePriv->privPtr = priv;
+    interfacePriv->InterfaceTag = interfaceTag;
+    priv->netdev[interfaceTag] = dev;
+    priv->interfacePriv[interfacePriv->InterfaceTag] = interfacePriv;
+
+    /* reset the connected state for the interface */
+    interfacePriv->connected = UnifiConnectedUnknown;  /* -1 unknown, 0 no, 1 yes */
+    INIT_LIST_HEAD(&interfacePriv->rx_uncontrolled_list);
+    INIT_LIST_HEAD(&interfacePriv->rx_controlled_list);
+
+    /* Setup / override net_device fields */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+    dev->netdev_ops = &uf_netdev_ops;
+#else
+    dev->open             = uf_net_open;
+    dev->stop             = uf_net_stop;
+    dev->hard_start_xmit  = uf_net_xmit;
+    dev->do_ioctl         = uf_net_ioctl;
+
+    /* called by /proc/net/dev */
+    dev->get_stats = uf_net_get_stats;
+
+    dev->set_multicast_list = uf_set_multicast_list;
+#endif
+
+#ifdef CSR_SUPPORT_WEXT
+    dev->wireless_handlers = &unifi_iw_handler_def;
+#if IW_HANDLER_VERSION < 6
+    dev->get_wireless_stats = unifi_get_wireless_stats;
+#endif /* IW_HANDLER_VERSION */
+#endif /* CSR_SUPPORT_WEXT */
+    return TRUE;
+} /* uf_alloc_netdevice() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_free_netdevice
+ *
+ *      Unregister the network device and free the memory allocated for it.
+ *      NB This includes the memory for the priv struct.
+ *
+ *  Arguments:
+ *      priv            Device private pointer.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+int
+uf_free_netdevice(unifi_priv_t *priv)
+{
+    int i;
+    unsigned long flags;
+
+    func_enter();
+
+    unifi_trace(priv, UDBG1, "uf_free_netdevice\n");
+
+    if (!priv) {
+        return -EINVAL;
+    }
+
+    /*
+     * Free any buffers used for holding firmware
+     */
+    uf_release_firmware_files(priv);
+
+#if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
+    if (priv->connection_config.mlmeAssociateReqInformationElements) {
+        kfree(priv->connection_config.mlmeAssociateReqInformationElements);
+    }
+    priv->connection_config.mlmeAssociateReqInformationElements = NULL;
+    priv->connection_config.mlmeAssociateReqInformationElementsLength = 0;
+
+    if (priv->mib_data.length) {
+        vfree(priv->mib_data.data);
+    }
+    priv->mib_data.data = NULL;
+    priv->mib_data.length = 0;
+
+#endif /* CSR_SUPPORT_SME && CSR_SUPPORT_WEXT*/
+
+    /* Free any bulkdata buffers allocated for M4 caching */
+    spin_lock_irqsave(&priv->m4_lock, flags);
+    for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) {
+        netInterface_priv_t *interfacePriv = priv->interfacePriv[i];
+        if (interfacePriv->m4_bulk_data.data_length > 0) {
+            unifi_trace(priv, UDBG5, "uf_free_netdevice: free M4 bulkdata %d\n", i);
+            unifi_net_data_free(priv, &interfacePriv->m4_bulk_data);
+        }
+    }
+    spin_unlock_irqrestore(&priv->m4_lock, flags);
+
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
+    /* Free any bulkdata buffers allocated for M4 caching */
+    spin_lock_irqsave(&priv->wapi_lock, flags);
+    for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) {
+        netInterface_priv_t *interfacePriv = priv->interfacePriv[i];
+        if (interfacePriv->wapi_unicast_bulk_data.data_length > 0) {
+            unifi_trace(priv, UDBG5, "uf_free_netdevice: free WAPI PKT bulk data %d\n", i);
+            unifi_net_data_free(priv, &interfacePriv->wapi_unicast_bulk_data);
+        }
+    }
+    spin_unlock_irqrestore(&priv->wapi_lock, flags);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+#ifdef CONFIG_NET_SCHED
+    /* Unregister the qdisc operations */
+    unregister_qdisc(&uf_qdisc_ops);
+#endif /* CONFIG_NET_SCHED */
+#endif /* LINUX_VERSION_CODE */
+
+#ifdef CSR_SUPPORT_WEXT
+    /* Unregister callback for netdevice state changes */
+    unregister_netdevice_notifier(&uf_netdev_notifier);
+#endif /* CSR_SUPPORT_WEXT */
+
+#ifdef CSR_SUPPORT_SME
+    /* Cancel work items and destroy the workqueue */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
+    cancel_work_sync(&priv->multicast_list_task);
+#endif
+#endif
+/* Destroy the workqueues. */
+    flush_workqueue(priv->unifi_workqueue);
+    destroy_workqueue(priv->unifi_workqueue);
+
+    /* Free up netdev in reverse order: priv is allocated with netdev[0].
+     * So, netdev[0] should be freed after all other netdevs are freed up
+     */
+    for (i=CSR_WIFI_NUM_INTERFACES-1; i>=0; i--) {
+        /*Free the netdev struct and priv, which are all one lump*/
+        if (priv->netdev[i]) {
+            unifi_error(priv, "uf_free_netdevice: netdev %d %p\n", i, priv->netdev[i]);
+            free_netdev(priv->netdev[i]);
+        }
+    }
+
+    func_exit();
+    return 0;
+} /* uf_free_netdevice() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_net_open
+ *
+ *      Called when userland does "ifconfig wlan0 up".
+ *
+ *  Arguments:
+ *      dev             Device pointer.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static int
+uf_net_open(struct net_device *dev)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+
+    func_enter();
+
+    /* If we haven't finished UniFi initialisation, we can't start */
+    if (priv->init_progress != UNIFI_INIT_COMPLETED) {
+        unifi_warning(priv, "%s: unifi not ready, failing net_open\n", __FUNCTION__);
+        return -EINVAL;
+    }
+
+#if (defined CSR_NATIVE_LINUX) && (defined UNIFI_SNIFF_ARPHRD) && defined(CSR_SUPPORT_WEXT)
+    /*
+     * To sniff, the user must do "iwconfig mode monitor", which sets
+     * priv->wext_conf.mode to IW_MODE_MONITOR.
+     * Then he/she must do "ifconfig ethn up", which calls this fn.
+     * There is no point in starting the sniff with SNIFFJOIN until
+     * this point.
+     */
+    if (priv->wext_conf.mode == IW_MODE_MONITOR) {
+        int err;
+        err = uf_start_sniff(priv);
+        if (err) {
+            return err;
+        }
+        netif_carrier_on(dev);
+    }
+#endif
+
+#ifdef CSR_SUPPORT_WEXT
+    if (interfacePriv->wait_netdev_change) {
+        unifi_trace(priv, UDBG1, "%s: Waiting for NETDEV_CHANGE, assume connected\n",
+                    __FUNCTION__);
+        interfacePriv->connected = UnifiConnected;
+        interfacePriv->wait_netdev_change = FALSE;
+    }
+#endif
+
+    UF_NETIF_TX_START_ALL_QUEUES(dev);
+
+    func_exit();
+    return 0;
+} /* uf_net_open() */
+
+
+static int
+uf_net_stop(struct net_device *dev)
+{
+#if defined(CSR_NATIVE_LINUX) && defined(UNIFI_SNIFF_ARPHRD) && defined(CSR_SUPPORT_WEXT)
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t*)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+
+    func_enter();
+
+    /* Stop sniffing if in Monitor mode */
+    if (priv->wext_conf.mode == IW_MODE_MONITOR) {
+        if (priv->card) {
+            int err;
+            err = unifi_reset_state(priv, dev->dev_addr, 1);
+            if (err) {
+                return err;
+            }
+        }
+    }
+#else
+    func_enter();
+#endif
+
+    UF_NETIF_TX_STOP_ALL_QUEUES(dev);
+
+    func_exit();
+    return 0;
+} /* uf_net_stop() */
+
+
+/* This is called after the WE handlers */
+static int
+uf_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+    int rc;
+
+    rc = -EOPNOTSUPP;
+
+    return rc;
+} /* uf_net_ioctl() */
+
+
+
+static struct net_device_stats *
+uf_net_get_stats(struct net_device *dev)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+
+    return &interfacePriv->stats;
+} /* uf_net_get_stats() */
+
+static CSR_PRIORITY uf_get_packet_priority(unifi_priv_t *priv, netInterface_priv_t *interfacePriv, struct sk_buff *skb, const int proto)
+{
+    CSR_PRIORITY priority = CSR_CONTENTION;
+
+    func_enter();
+    priority = (CSR_PRIORITY) (skb->priority >> 5);
+
+    if (priority == CSR_QOS_UP0) { /* 0 */
+
+        unifi_trace(priv, UDBG5, "uf_get_packet_priority: proto = 0x%.4X\n", proto);
+
+        switch (proto) {
+            case 0x0800:        /* IPv4 */
+            case 0x814C:        /* SNMP */
+            case 0x880C:        /* GSMP */
+                priority = (CSR_PRIORITY) (skb->data[1 + ETH_HLEN] >> 5);
+                break;
+
+            case 0x8100:        /* VLAN */
+                priority = (CSR_PRIORITY) (skb->data[0 + ETH_HLEN] >> 5);
+                break;
+
+            case 0x86DD:        /* IPv6 */
+                priority = (CSR_PRIORITY) ((skb->data[0 + ETH_HLEN] & 0x0E) >> 1);
+                break;
+
+            default:
+                priority = CSR_QOS_UP0;
+                break;
+        }
+    }
+
+    /* Check if we are allowed to transmit on this AC. Because of ACM we may have to downgrade to a lower
+     * priority */
+    if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA ||
+        interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI) {
+        unifi_TrafficQueue queue;
+
+        /* Keep trying lower priorities until we find a queue
+         * Priority to queue mapping is 1,2 - BK, 0,3 - BE, 4,5 - VI, 6,7 - VO */
+        queue = unifi_frame_priority_to_queue(priority);
+
+        while (queue > UNIFI_TRAFFIC_Q_BK && !interfacePriv->queueEnabled[queue]) {
+            queue--;
+            priority = unifi_get_default_downgrade_priority(queue);
+        }
+    }
+
+    unifi_trace(priv, UDBG5, "Packet priority = %d\n", priority);
+
+    func_exit();
+    return priority;
+}
+
+/*
+ */
+/*
+ * ---------------------------------------------------------------------------
+ *  get_packet_priority
+ *
+ *  Arguments:
+ *      priv             private data area of functional driver
+ *      skb              socket buffer
+ *      ehdr             ethernet header to fetch protocol
+ *      interfacePriv    For accessing station record database
+ *
+ *
+ *  Returns:
+ *      CSR_PRIORITY.
+ * ---------------------------------------------------------------------------
+ */
+CSR_PRIORITY
+get_packet_priority(unifi_priv_t *priv, struct sk_buff *skb, const struct ethhdr *ehdr, netInterface_priv_t *interfacePriv)
+{
+    CSR_PRIORITY priority = CSR_CONTENTION;
+    const int proto = ntohs(ehdr->h_proto);
+
+    CsrUint8 interfaceMode = interfacePriv->interfaceMode;
+
+    func_enter();
+
+    /* Priority Mapping for all the Modes */
+    switch(interfaceMode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_STA:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI:
+            unifi_trace(priv, UDBG4, "mode is STA \n");
+            if ((priv->sta_wmm_capabilities & QOS_CAPABILITY_WMM_ENABLED) == 1) {
+                priority = uf_get_packet_priority(priv, interfacePriv, skb, proto);
+            } else {
+                priority = CSR_CONTENTION;
+            }
+            break;
+#ifdef CSR_SUPPORT_SME
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+        case CSR_WIFI_ROUTER_CTRL_MODE_IBSS:
+            {
+                CsrWifiRouterCtrlStaInfo_t * dstStaInfo =
+                    CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv,ehdr->h_dest, interfacePriv->InterfaceTag);
+                unifi_trace(priv, UDBG4, "mode is AP \n");
+                if (!(ehdr->h_dest[0] & 0x01) && dstStaInfo && dstStaInfo->wmmOrQosEnabled) {
+                    /* If packet is not Broadcast/multicast */
+                    priority = uf_get_packet_priority(priv, interfacePriv, skb, proto);
+                } else {
+                    /* Since packet destination is not QSTA, set priority to CSR_CONTENTION */
+                    unifi_trace(priv, UDBG4, "Destination is not QSTA or BroadCast/Multicast\n");
+                    priority = CSR_CONTENTION;
+                }
+            }
+            break;
+#endif
+        default:
+            unifi_trace(priv, UDBG3, " mode unknown in %s func, mode=%x\n", __FUNCTION__, interfaceMode);
+    }
+    unifi_trace(priv, UDBG5, "priority = %x\n", priority);
+
+    func_exit();
+    return priority;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_net_select_queue
+ *
+ *      Called by the kernel to select which queue to put the packet in
+ *
+ *  Arguments:
+ *      dev             Device pointer
+ *      skb             Packet
+ *
+ *  Returns:
+ *      Queue index
+ * ---------------------------------------------------------------------------
+ */
+static u16
+uf_net_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = (unifi_priv_t *)interfacePriv->privPtr;
+    struct ethhdr ehdr;
+    unifi_TrafficQueue queue;
+    int proto;
+    CSR_PRIORITY priority;
+
+    func_enter();
+
+    memcpy(&ehdr, skb->data, ETH_HLEN);
+    proto = ntohs(ehdr.h_proto);
+
+    /* 802.1x - apply controlled/uncontrolled port rules */
+    if ((proto != ETH_P_PAE)
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+            && (proto != ETH_P_WAI)
+#endif
+       ) {
+        /* queues 0 - 3 */
+        priority = get_packet_priority(priv, skb, &ehdr, interfacePriv);
+        queue = unifi_frame_priority_to_queue(priority);
+    } else {
+        /* queue 4 */
+        queue = UNIFI_TRAFFIC_Q_EAPOL;
+    }
+
+
+    func_exit();
+    return (u16)queue;
+} /* uf_net_select_queue() */
+#endif
+
+int
+skb_add_llc_snap(struct net_device *dev, struct sk_buff *skb, int proto)
+{
+    llc_snap_hdr_t *snap;
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int headroom;
+
+    /* get the headroom available in skb */
+    headroom = skb_headroom(skb);
+    /* step 1: classify ether frame, DIX or 802.3? */
+
+    if (proto < 0x600) {
+        /* codes <= 1500 reserved for 802.3 lengths */
+        /* it's 802.3, pass ether payload unchanged,  */
+        unifi_trace(priv, UDBG3, "802.3 len: %d\n", skb->len);
+
+        /*   leave off any PAD octets.  */
+        skb_trim(skb, proto);
+    } else if (proto == ETH_P_8021Q) {
+
+        /* Store the VLAN SNAP (should be 87-65). */
+        u16 vlan_snap = *(u16*)skb->data;
+        /* check for headroom availability before skb_push 14 = (4 + 10) */
+        if (headroom < 14) {
+            unifi_trace(priv, UDBG3, "cant append vlan snap: debug\n");
+            return -1;
+        }
+        /* Add AA-AA-03-00-00-00 */
+        snap = (llc_snap_hdr_t *)skb_push(skb, 4);
+        snap->dsap = snap->ssap = 0xAA;
+        snap->ctrl = 0x03;
+        memcpy(snap->oui, oui_rfc1042, P80211_OUI_LEN);
+
+        /* Add AA-AA-03-00-00-00 */
+        snap = (llc_snap_hdr_t *)skb_push(skb, 10);
+        snap->dsap = snap->ssap = 0xAA;
+        snap->ctrl = 0x03;
+        memcpy(snap->oui, oui_rfc1042, P80211_OUI_LEN);
+
+        /* Add the VLAN specific information */
+        snap->protocol = htons(proto);
+        *(u16*)(snap + 1) = vlan_snap;
+
+    } else
+    {
+        /* it's DIXII, time for some conversion */
+        unifi_trace(priv, UDBG3, "DIXII len: %d\n", skb->len);
+
+        /* check for headroom availability before skb_push */
+        if (headroom < sizeof(llc_snap_hdr_t)) {
+            unifi_trace(priv, UDBG3, "cant append snap: debug\n");
+            return -1;
+        }
+        /* tack on SNAP */
+        snap = (llc_snap_hdr_t *)skb_push(skb, sizeof(llc_snap_hdr_t));
+        snap->dsap = snap->ssap = 0xAA;
+        snap->ctrl = 0x03;
+        /* Use the appropriate OUI. */
+        if ((proto == ETH_P_AARP) || (proto == ETH_P_IPX)) {
+            memcpy(snap->oui, oui_8021h, P80211_OUI_LEN);
+        } else {
+            memcpy(snap->oui, oui_rfc1042, P80211_OUI_LEN);
+        }
+        snap->protocol = htons(proto);
+    }
+
+    return 0;
+} /* skb_add_llc_snap() */
+
+#ifdef CSR_SUPPORT_SME
+static int
+_identify_sme_ma_pkt_ind(unifi_priv_t *priv,
+                         const CsrInt8 *oui, CsrUint16 protocol,
+                         const CSR_SIGNAL *signal,
+                         bulk_data_param_t *bulkdata,
+                         const unsigned char *daddr,
+                         const unsigned char *saddr)
+{
+    CSR_MA_PACKET_INDICATION *pkt_ind = (CSR_MA_PACKET_INDICATION*)&signal->u.MaPacketIndication;
+    int r;
+    CsrUint8 i;
+
+    unifi_trace(priv, UDBG5,
+            "_identify_sme_ma_pkt_ind -->\n");
+    for (i = 0; i < MAX_MA_UNIDATA_IND_FILTERS; i++) {
+        if (priv->sme_unidata_ind_filters[i].in_use) {
+            if (!memcmp(oui, priv->sme_unidata_ind_filters[i].oui, 3) &&
+                    (protocol == priv->sme_unidata_ind_filters[i].protocol)) {
+
+                /* Send to client */
+                if (priv->sme_cli) {
+                    /*
+                     * Pass the packet to the SME, using unifi_sys_ma_unitdata_ind().
+                     * The frame needs to be converted according to the encapsulation.
+                     */
+                    unifi_trace(priv, UDBG1,
+                            "_identify_sme_ma_pkt_ind: handle=%d, encap=%d, proto=%x\n",
+                            i, priv->sme_unidata_ind_filters[i].encapsulation,
+                            priv->sme_unidata_ind_filters[i].protocol);
+                    if (priv->sme_unidata_ind_filters[i].encapsulation == CSR_WIFI_ROUTER_ENCAPSULATION_ETHERNET) {
+                        struct sk_buff *skb;
+                        /* The translation is performed on skb... */
+                        skb = (struct sk_buff*)bulkdata->d[0].os_net_buf_ptr;
+                        skb->len = bulkdata->d[0].data_length;
+
+                        unifi_trace(priv, UDBG1,
+                                "_identify_sme_ma_pkt_ind: skb_80211_to_ether -->\n");
+                        r = skb_80211_to_ether(priv, skb, daddr, saddr,
+                                signal, bulkdata);
+                        unifi_trace(priv, UDBG1,
+                                "_identify_sme_ma_pkt_ind: skb_80211_to_ether <--\n");
+                        if (r) {
+                            return -EINVAL;
+                        }
+
+                        /* ... but we indicate buffer and length */
+                        bulkdata->d[0].os_data_ptr = skb->data;
+                        bulkdata->d[0].data_length = skb->len;
+                    } else {
+                        /* Add the MAC addresses before the SNAP */
+                        bulkdata->d[0].os_data_ptr -= 2*ETH_ALEN;
+                        bulkdata->d[0].data_length += 2*ETH_ALEN;
+                        memcpy((void*)bulkdata->d[0].os_data_ptr, daddr, ETH_ALEN);
+                        memcpy((void*)bulkdata->d[0].os_data_ptr + ETH_ALEN, saddr, ETH_ALEN);
+                    }
+
+                    unifi_trace(priv, UDBG1,
+                            "_identify_sme_ma_pkt_ind: unifi_sys_ma_pkt_ind -->\n");
+                    CsrWifiRouterMaPacketIndSend(priv->sme_unidata_ind_filters[i].appHandle,
+                            (pkt_ind->VirtualInterfaceIdentifier & 0xff),
+                            i,
+                            pkt_ind->ReceptionStatus,
+                            bulkdata->d[0].data_length,
+                            (CsrUint8*)bulkdata->d[0].os_data_ptr,
+                            NULL,
+                            pkt_ind->Rssi,
+                            pkt_ind->Snr,
+                            pkt_ind->ReceivedRate);
+
+
+                    unifi_trace(priv, UDBG1,
+                            "_identify_sme_ma_pkt_ind: unifi_sys_ma_pkt_ind <--\n");
+                }
+
+                return 1;
+            }
+        }
+    }
+
+    return -1;
+}
+#endif /* CSR_SUPPORT_SME */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  skb_80211_to_ether
+ *
+ *      Make sure the received frame is in Ethernet (802.3) form.
+ *      De-encapsulates SNAP if necessary, adds a ethernet header.
+ *      The source buffer should not contain an 802.11 MAC header
+ *
+ *  Arguments:
+ *      payload         Pointer to packet data received from UniFi.
+ *      payload_length  Number of bytes of data received from UniFi.
+ *      daddr           Destination MAC address.
+ *      saddr           Source MAC address.
+ *
+ *  Returns:
+ *      0 on success, -1 if the packet is bad and should be dropped,
+ *      1 if the packet was forwarded to the SME or AMP client.
+ * ---------------------------------------------------------------------------
+ */
+int
+skb_80211_to_ether(unifi_priv_t *priv, struct sk_buff *skb,
+                   const unsigned char *daddr, const unsigned char *saddr,
+                   const CSR_SIGNAL *signal,
+                   bulk_data_param_t *bulkdata)
+{
+    unsigned char *payload;
+    int payload_length;
+    struct ethhdr *eth;
+    llc_snap_hdr_t *snap;
+    int headroom;
+#define UF_VLAN_LLC_HEADER_SIZE     18
+    static const u8 vlan_inner_snap[] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00 };
+#if defined(CSR_NATIVE_SOFTMAC) && defined(CSR_SUPPORT_SME)
+    const CSR_MA_PACKET_INDICATION *pkt_ind = &signal->u.MaPacketIndication;
+#endif
+
+    if(skb== NULL || daddr == NULL || saddr == NULL){
+        unifi_error(priv,"skb_80211_to_ether: PBC fail\n");
+        return 1;
+    }
+
+    payload = skb->data;
+    payload_length = skb->len;
+
+    snap = (llc_snap_hdr_t *)payload;
+    eth  = (struct ethhdr *)payload;
+
+    /* get the skb headroom size */
+    headroom = skb_headroom(skb);
+
+    /*
+     * Test for the various encodings
+     */
+    if ((payload_length >= sizeof(llc_snap_hdr_t)) &&
+            (snap->dsap == 0xAA) &&
+            (snap->ssap == 0xAA) &&
+            (snap->ctrl == 0x03) &&
+            (snap->oui[0] == 0) &&
+            (snap->oui[1] == 0) &&
+            ((snap->oui[2] == 0) || (snap->oui[2] == 0xF8)))
+    {
+        /* AppleTalk AARP (2) or IPX SNAP */
+        if ((snap->oui[2] == 0) &&
+                ((ntohs(snap->protocol) == ETH_P_AARP) || (ntohs(snap->protocol) == ETH_P_IPX)))
+        {
+            u16 len;
+
+            unifi_trace(priv, UDBG3, "%s len: %d\n",
+                    (ntohs(snap->protocol) == ETH_P_AARP) ? "ETH_P_AARP" : "ETH_P_IPX",
+                    payload_length);
+
+            /* check for headroom availability before skb_push */
+            if (headroom < (2 * ETH_ALEN + 2)) {
+                unifi_warning(priv, "headroom not available to skb_push ether header\n");
+                return -1;
+            }
+
+            /* Add 802.3 header and leave full payload */
+            len = htons(skb->len);
+            memcpy(skb_push(skb, 2), &len, 2);
+            memcpy(skb_push(skb, ETH_ALEN), saddr, ETH_ALEN);
+            memcpy(skb_push(skb, ETH_ALEN), daddr, ETH_ALEN);
+
+            return 0;
+        }
+        /* VLAN-tagged IP */
+        if ((snap->oui[2] == 0) && (ntohs(snap->protocol) == ETH_P_8021Q))
+        {
+            /*
+             * The translation doesn't change the packet length, so is done in-place.
+             *
+             * Example header (from Std 802.11-2007 Annex M):
+             * AA-AA-03-00-00-00-81-00-87-65-AA-AA-03-00-00-00-08-06
+             * -------SNAP-------p1-p1-ll-ll-------SNAP--------p2-p2
+             * dd-dd-dd-dd-dd-dd-aa-aa-aa-aa-aa-aa-p1-p1-ll-ll-p2-p2
+             * dd-dd-dd-dd-dd-dd-aa-aa-aa-aa-aa-aa-81-00-87-65-08-06
+             */
+            u16 vlan_snap;
+
+            if (payload_length < UF_VLAN_LLC_HEADER_SIZE) {
+                unifi_warning(priv, "VLAN SNAP header too short: %d bytes\n", payload_length);
+                return -1;
+            }
+
+            if (memcmp(payload + 10, vlan_inner_snap, 6)) {
+                unifi_warning(priv, "VLAN malformatted SNAP header.\n");
+                return -1;
+            }
+
+            unifi_trace(priv, UDBG3, "VLAN SNAP: %02x-%02x\n", payload[8], payload[9]);
+            unifi_trace(priv, UDBG3, "VLAN len: %d\n", payload_length);
+
+            /* Create the 802.3 header */
+
+            vlan_snap = *((u16*)(payload + 8));
+
+            /* Create LLC header without byte-swapping */
+            eth->h_proto = snap->protocol;
+
+            memcpy(eth->h_dest, daddr, ETH_ALEN);
+            memcpy(eth->h_source, saddr, ETH_ALEN);
+            *(u16*)(eth + 1) = vlan_snap;
+            return 0;
+        }
+
+        /* it's a SNAP + RFC1042 frame */
+        unifi_trace(priv, UDBG3, "SNAP+RFC1042 len: %d\n", payload_length);
+
+        /* chop SNAP+llc header from skb. */
+        skb_pull(skb, sizeof(llc_snap_hdr_t));
+
+        /* Since skb_pull called above to chop snap+llc, no need to check for headroom
+         * availability before skb_push
+         */
+        /* create 802.3 header at beginning of skb. */
+        eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+        memcpy(eth->h_dest, daddr, ETH_ALEN);
+        memcpy(eth->h_source, saddr, ETH_ALEN);
+        /* Copy protocol field without byte-swapping */
+        eth->h_proto = snap->protocol;
+    } else {
+        u16 len;
+
+        /* check for headroom availability before skb_push */
+        if (headroom < (2 * ETH_ALEN + 2)) {
+            unifi_warning(priv, "headroom not available to skb_push ether header\n");
+            return -1;
+        }
+        /* Add 802.3 header and leave full payload */
+        len = htons(skb->len);
+        memcpy(skb_push(skb, 2), &len, 2);
+        memcpy(skb_push(skb, ETH_ALEN), saddr, ETH_ALEN);
+        memcpy(skb_push(skb, ETH_ALEN), daddr, ETH_ALEN);
+
+        return 1;
+    }
+
+    return 0;
+} /* skb_80211_to_ether() */
+
+
+static CsrWifiRouterCtrlPortAction verify_port(unifi_priv_t *priv, unsigned char *address, int queue, CsrUint16 interfaceTag)
+{
+#ifdef CSR_NATIVE_LINUX
+#ifdef CSR_SUPPORT_WEXT
+    if (queue == UF_CONTROLLED_PORT_Q) {
+        return priv->wext_conf.block_controlled_port;
+    } else {
+        return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN;
+    }
+#else
+    return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN; /* default to open for softmac dev */
+#endif
+#else
+    return uf_sme_port_state(priv, address, queue, interfaceTag);
+#endif
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  prepare_and_add_macheader
+ *
+ *
+ *      These functions adds mac header for packet from netdev
+ *      to UniFi for transmission.
+ *      EAP protocol packets are also appended with Mac header &
+ *      sent using send_ma_pkt_request().
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *      skb             Socket buffer containing data packet to transmit
+ *      newSkb          Socket buffer containing data packet + Mac header if no sufficient headroom in skb
+ *      serviceClass    to append QOS control header in Mac header
+ *      bulkdata        if newSkb allocated then bulkdata updated to send to unifi
+ *      interfaceTag    the interfaceID on which activity going on
+ *      daddr           destination address
+ *      saddr           source address
+ *      protection      protection bit set in framce control of mac header
+ *
+ *  Returns:
+ *      Zero on success or error code.
+ * ---------------------------------------------------------------------------
+ */
+
+int prepare_and_add_macheader(unifi_priv_t *priv, struct sk_buff *skb, struct sk_buff *newSkb,
+                              CSR_PRIORITY priority,
+                              bulk_data_param_t *bulkdata,
+                              CsrUint16 interfaceTag,
+                              const CsrUint8 *daddr,
+                              const CsrUint8 *saddr,
+                              CsrBool protection)
+{
+    CsrUint16 fc = 0;
+    CsrUint8 qc = 0;
+    CsrUint8 macHeaderLengthInBytes = MAC_HEADER_SIZE, *bufPtr = NULL;
+    bulk_data_param_t data_ptrs;
+    CsrResult csrResult;
+    int headroom =0;
+    CsrUint8 direction = 0;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    CsrUint8 *addressOne;
+    CsrBool bQosNull = false;
+
+    if (skb == NULL) {
+        unifi_error(priv,"prepare_and_add_macheader: Invalid SKB reference\n");
+        return -1;
+    }
+
+    /* add a MAC header refer: 7.1.3.1 Frame Control field in P802.11REVmb.book */
+    if (priority != CSR_CONTENTION) {
+        /* EAPOL packets don't go as QOS_DATA */
+        if (priority == CSR_MANAGEMENT) {
+            fc |= cpu_to_le16(IEEE802_11_FC_TYPE_DATA);
+        } else {
+            /* Qos Control Field */
+            macHeaderLengthInBytes += QOS_CONTROL_HEADER_SIZE;
+
+            if (skb->len) {
+
+                fc |= cpu_to_le16(IEEE802_11_FC_TYPE_QOS_DATA);
+            } else {
+                fc |= cpu_to_le16(IEEE802_11_FC_TYPE_QOS_NULL);
+                bQosNull = true;
+            }
+        }
+    } else {
+        if(skb->len == 0) {
+            fc |= cpu_to_le16(IEEE802_11_FC_TYPE_NULL);
+        } else {
+            fc |= cpu_to_le16(IEEE802_11_FC_TYPE_DATA);
+        }
+    }
+
+    switch (interfacePriv->interfaceMode)
+    {
+        case  CSR_WIFI_ROUTER_CTRL_MODE_STA:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI:
+            direction = 2;
+            fc |= cpu_to_le16(IEEE802_11_FC_TO_DS_MASK);
+            break;
+        case  CSR_WIFI_ROUTER_CTRL_MODE_IBSS:
+            direction = 0;
+            break;
+        case  CSR_WIFI_ROUTER_CTRL_MODE_AP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+            direction = 1;
+            fc |= cpu_to_le16(IEEE802_11_FC_FROM_DS_MASK);
+            break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_AMP:
+            if (priority == CSR_MANAGEMENT ) {
+
+                direction = 2;
+                fc |= cpu_to_le16(IEEE802_11_FC_TO_DS_MASK);
+            } else {
+                /* Data frames have to use WDS 4 address frames */
+                direction = 3;
+                fc |= cpu_to_le16(IEEE802_11_FC_TO_DS_MASK | IEEE802_11_FC_FROM_DS_MASK);
+                macHeaderLengthInBytes += 6;
+            }
+            break;
+        default:
+            unifi_warning(priv, "prepare_and_add_macheader: Unknown mode %d\n",
+                          interfacePriv->interfaceMode);
+    }
+
+
+    /* If Sta is QOS & HTC is supported then need to set 'order' bit */
+    /* We don't support HT Control for now */
+
+    if(protection) {
+        fc |= cpu_to_le16(IEEE802_11_FC_PROTECTED_MASK);
+    }
+
+    /* check the skb headroom before pushing mac header */
+    headroom = skb_headroom(skb);
+
+    if (headroom < macHeaderLengthInBytes) {
+        unifi_trace(priv, UDBG5,
+                    "prepare_and_add_macheader: Allocate headroom extra %d bytes\n",
+                    macHeaderLengthInBytes);
+
+        csrResult = unifi_net_data_malloc(priv, &data_ptrs.d[0], skb->len + macHeaderLengthInBytes);
+
+        if (csrResult != CSR_RESULT_SUCCESS) {
+            unifi_error(priv, " failed to allocate request_data. in %s func\n", __FUNCTION__);
+            return -1;
+        }
+        newSkb = (struct sk_buff *)(data_ptrs.d[0].os_net_buf_ptr);
+        newSkb->len = skb->len + macHeaderLengthInBytes;
+
+        memcpy((void*)data_ptrs.d[0].os_data_ptr + macHeaderLengthInBytes,
+                skb->data, skb->len);
+
+        bulkdata->d[0].os_data_ptr = newSkb->data;
+        bulkdata->d[0].os_net_buf_ptr = (unsigned char*)newSkb;
+        bulkdata->d[0].data_length = newSkb->len;
+
+        bufPtr = (CsrUint8*)data_ptrs.d[0].os_data_ptr;
+
+        /* The old skb will not be used again */
+            kfree_skb(skb);
+    } else {
+
+        /* headroom has sufficient size, so will get proper pointer */
+        bufPtr = (CsrUint8*)skb_push(skb, macHeaderLengthInBytes);
+        bulkdata->d[0].os_data_ptr = skb->data;
+        bulkdata->d[0].os_net_buf_ptr = (unsigned char*)skb;
+        bulkdata->d[0].data_length = skb->len;
+    }
+
+    /* Frame the actual MAC header */
+
+    memset(bufPtr, 0, macHeaderLengthInBytes);
+
+    /* copy frameControl field */
+    memcpy(bufPtr, &fc, sizeof(fc));
+    bufPtr += sizeof(fc);
+    macHeaderLengthInBytes -= sizeof(fc);
+
+    /* Duration/ID field which is 2 bytes */
+    bufPtr += 2;
+    macHeaderLengthInBytes -= 2;
+
+    switch(direction)
+    {
+        case 0:
+            /* Its an Ad-Hoc no need to route it through AP */
+            /* Address1: MAC address of the destination from eth header */
+            memcpy(bufPtr, daddr, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+
+            /* Address2: MAC address of the source */
+            memcpy(bufPtr, saddr, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+
+            /* Address3: the BSSID (locally generated in AdHoc (creators Bssid)) */
+            memcpy(bufPtr, &interfacePriv->bssid, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+            break;
+        case 1:
+           /* Address1: MAC address of the actual destination */
+            memcpy(bufPtr, daddr, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+            /* Address2: The MAC address of the AP */
+            memcpy(bufPtr, &interfacePriv->bssid, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+
+            /* Address3: MAC address of the source from eth header */
+            memcpy(bufPtr, saddr, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+            break;
+        case  2:
+            /* Address1: To AP is the MAC address of the AP to which its associated */
+            memcpy(bufPtr, &interfacePriv->bssid, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+
+            /* Address2: MAC address of the source from eth header */
+            memcpy(bufPtr, saddr, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+
+            /* Address3: MAC address of the actual destination on the distribution system */
+            memcpy(bufPtr, daddr, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+            break;
+        case 3:
+            memcpy(bufPtr, &interfacePriv->bssid, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+
+            /* Address2: MAC address of the source from eth header */
+            memcpy(bufPtr, saddr, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+
+            /* Address3: MAC address of the actual destination on the distribution system */
+            memcpy(bufPtr, daddr, ETH_ALEN);
+            bufPtr += ETH_ALEN;
+            macHeaderLengthInBytes -= ETH_ALEN;
+            break;
+        default:
+            unifi_error(priv,"Unknown direction =%d : Not handled now\n",direction);
+            return -1;
+    }
+    /* 2 bytes of frame control field, appended by firmware */
+    bufPtr += 2;
+    macHeaderLengthInBytes -= 2;
+
+    if (3 == direction) {
+        /* Address4: MAC address of the source */
+        memcpy(bufPtr, saddr, ETH_ALEN);
+        bufPtr += ETH_ALEN;
+        macHeaderLengthInBytes -= ETH_ALEN;
+    }
+
+    /* IF Qos Data or Qos Null Data then set QosControl field */
+    if ((priority != CSR_CONTENTION) && (macHeaderLengthInBytes >= QOS_CONTROL_HEADER_SIZE)) {
+
+        if (priority > 7) {
+            unifi_trace(priv, UDBG1, "data packets priority is more than 7, priority = %x\n", priority);
+            qc |= 7;
+        } else {
+            qc |= priority;
+        }
+        /*assigning address1
+        * Address1 offset taken fromm bufPtr(currently bufPtr pointing to Qos contorl) variable in reverse direction
+        * Address4 don't exit
+        */
+
+        addressOne = bufPtr- ADDRESS_ONE_OFFSET;
+
+        if (addressOne[0] & 0x1) {
+            /* multicast/broadcast frames, no acknowledgement needed */
+            qc |= 1 << 5;
+        }
+        /* non-AP mode only for now */
+        if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA ||
+           interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_IBSS ||
+           interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI) {
+           /* In case of STA and IBSS case eosp and txop limit is 0. */
+        } else {
+            if(bQosNull) {
+                qc |= 1 << 4;
+            }
+        }
+
+        /* append Qos control field to mac header */
+        bufPtr[0] = qc;
+        /* txop limit is 0 */
+        bufPtr[1] = 0;
+        macHeaderLengthInBytes -= QOS_CONTROL_HEADER_SIZE;
+    }
+    if (macHeaderLengthInBytes) {
+        unifi_warning(priv, " Mac header not appended properly\n");
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  send_ma_pkt_request
+ *
+ *      These functions send a data packet to UniFi for transmission.
+ *      EAP protocol packets are also sent as send_ma_pkt_request().
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *      skb             Socket buffer containing data packet to transmit
+ *      ehdr            Pointer to Ethernet header within skb.
+ *
+ *  Returns:
+ *      Zero on success or error code.
+ * ---------------------------------------------------------------------------
+ */
+
+static int
+send_ma_pkt_request(unifi_priv_t *priv, struct sk_buff *skb, const struct ethhdr *ehdr, CSR_PRIORITY priority)
+{
+    int r;
+    CsrUint16 i;
+    CsrBool eapolStore = FALSE;
+    struct sk_buff *newSkb = NULL;
+    bulk_data_param_t bulkdata;
+    const int proto = ntohs(ehdr->h_proto);
+    CsrUint16 interfaceTag;
+    CsrWifiMacAddress peerAddress;
+    CSR_TRANSMISSION_CONTROL transmissionControl = CSR_NO_CONFIRM_REQUIRED;
+    CsrInt8 protection;
+    netInterface_priv_t *interfacePriv = NULL;
+    CSR_RATE TransmitRate = (CSR_RATE)0;
+
+    unifi_trace(priv, UDBG5, "entering send_ma_pkt_request\n");
+
+    /* Get the interface Tag by means of source Mac address */
+    for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) {
+        if (!memcmp(priv->netdev[i]->dev_addr, ehdr->h_source, ETH_ALEN)) {
+            interfaceTag = i;
+            interfacePriv = priv->interfacePriv[interfaceTag];
+            break;
+        }
+    }
+
+    if (interfacePriv == NULL) {
+        /* No match found - error */
+        interfaceTag = 0;
+        interfacePriv = priv->interfacePriv[interfaceTag];
+        unifi_warning(priv, "Mac address not matching ... debugging needed\n");
+        interfacePriv->stats.tx_dropped++;
+        kfree_skb(skb);
+        return -1;
+    }
+
+    /* Add a SNAP header if necessary */
+    if (skb_add_llc_snap(priv->netdev[interfaceTag], skb, proto) != 0) {
+        /* convert failed */
+        unifi_error(priv, "skb_add_llc_snap failed.\n");
+        kfree_skb(skb);
+        return -1;
+    }
+
+    bulkdata.d[0].os_data_ptr = skb->data;
+    bulkdata.d[0].os_net_buf_ptr = (unsigned char*)skb;
+    bulkdata.d[0].net_buf_length = bulkdata.d[0].data_length = skb->len;
+    bulkdata.d[1].os_data_ptr = NULL;
+    bulkdata.d[1].os_net_buf_ptr = NULL;
+    bulkdata.d[1].net_buf_length = bulkdata.d[1].data_length = 0;
+
+#ifdef CSR_SUPPORT_SME
+    /* Notify the TA module for the Tx frame  for non AP/P2PGO mode*/
+    if ((interfacePriv->interfaceMode != CSR_WIFI_ROUTER_CTRL_MODE_AP) &&
+        (interfacePriv->interfaceMode != CSR_WIFI_ROUTER_CTRL_MODE_P2PGO)) {
+        unifi_ta_sample(priv->card, CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_TX,
+                        &bulkdata.d[0], ehdr->h_source,
+                        priv->netdev[interfaceTag]->dev_addr,
+                        jiffies_to_msecs(jiffies),
+                        0);     /* rate is unknown on tx */
+    }
+#endif /* CSR_SUPPORT_SME */
+
+    if ((proto == ETH_P_PAE)
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+            || (proto == ETH_P_WAI)
+#endif
+       )
+    {
+        /* check for m4 detection */
+        if (0 == uf_verify_m4(priv, bulkdata.d[0].os_data_ptr, bulkdata.d[0].data_length)) {
+            eapolStore = TRUE;
+        }
+    }
+
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+    if (proto == ETH_P_WAI)
+     {
+        protection = 0; /*WAI packets always sent unencrypted*/
+     }
+   else
+     {
+#endif
+#ifdef CSR_SUPPORT_SME
+    if ((protection = uf_get_protection_bit_from_interfacemode(priv, interfaceTag, ehdr->h_dest)) < 0) {
+        unifi_warning(priv, "unicast address, but destination not in station record database\n");
+        unifi_net_data_free(priv, &bulkdata.d[0]);
+        return -1;
+    }
+#else
+    protection = 0;
+#endif
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+   }
+#endif
+
+    /* append Mac header for Eapol as well as data packet */
+    if (prepare_and_add_macheader(priv, skb, newSkb, priority, &bulkdata, interfaceTag, ehdr->h_dest, ehdr->h_source, protection)) {
+        unifi_error(priv, "failed to create MAC header\n");
+        unifi_net_data_free(priv, &bulkdata.d[0]);
+        return -1;
+    }
+
+    /* RA adrress must contain the immediate destination MAC address that is similiar to
+     * the Address 1 field of 802.11 Mac header here 4 is: (sizeof(framecontrol) + sizeof (durationID))
+     * which is address 1 field
+     */
+    memcpy(peerAddress.a, ((CsrUint8 *) bulkdata.d[0].os_data_ptr) + 4, ETH_ALEN);
+
+    unifi_trace(priv, UDBG5, "RA[0]=%x, RA[1]=%x, RA[2]=%x, RA[3]=%x, RA[4]=%x, RA[5]=%x\n",
+                peerAddress.a[0],peerAddress.a[1], peerAddress.a[2], peerAddress.a[3],
+                peerAddress.a[4],peerAddress.a[5]);
+
+
+    if ((proto == ETH_P_PAE)
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+            || (proto == ETH_P_WAI)
+#endif
+       )
+    {
+        CSR_SIGNAL signal;
+        CSR_MA_PACKET_REQUEST *req = &signal.u.MaPacketRequest;
+
+        /* initialize signal to zero */
+        memset(&signal, 0, sizeof(CSR_SIGNAL));
+
+        /* Frame MA_PACKET request */
+        signal.SignalPrimitiveHeader.SignalId = CSR_MA_PACKET_REQUEST_ID;
+        signal.SignalPrimitiveHeader.ReceiverProcessId = 0;
+        signal.SignalPrimitiveHeader.SenderProcessId = priv->netdev_client->sender_id;
+
+        transmissionControl = req->TransmissionControl = 0;
+#ifdef CSR_SUPPORT_SME
+        if (eapolStore)
+        {
+            netInterface_priv_t *netpriv = (netInterface_priv_t *)netdev_priv(priv->netdev[interfaceTag]);
+
+            /* Fill the MA-PACKET.req */
+
+            req->Priority = priority;
+            unifi_trace(priv, UDBG3, "Tx Frame with Priority: %x\n", req->Priority);
+
+            /* rate selected by firmware */
+            req->TransmitRate = 0;
+            req->HostTag = CSR_WIFI_EAPOL_M4_HOST_TAG;
+            /* RA address matching with address 1 of Mac header */
+            memcpy(req->Ra.x, ((CsrUint8 *) bulkdata.d[0].os_data_ptr) + 4, ETH_ALEN);
+
+            spin_lock(&priv->m4_lock);
+            /* Store the M4-PACKET.req for later */
+            interfacePriv->m4_signal = signal;
+            interfacePriv->m4_bulk_data.net_buf_length = bulkdata.d[0].net_buf_length;
+            interfacePriv->m4_bulk_data.data_length = bulkdata.d[0].data_length;
+            interfacePriv->m4_bulk_data.os_data_ptr = bulkdata.d[0].os_data_ptr;
+            interfacePriv->m4_bulk_data.os_net_buf_ptr = bulkdata.d[0].os_net_buf_ptr;
+            spin_unlock(&priv->m4_lock);
+
+            /* Signal the workqueue to call CsrWifiRouterCtrlM4ReadyToSendIndSend().
+             * It cannot be called directly from the tx path because it
+             * does a non-atomic kmalloc via the framework's CsrPmemAlloc().
+             */
+            queue_work(priv->unifi_workqueue, &netpriv->send_m4_ready_task);
+
+            return 0;
+        }
+#endif
+    }/*EAPOL or WAI packet*/
+
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
+    if ((CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode) && \
+        (priv->wapi_unicast_filter) && \
+        (proto != ETH_P_PAE) && \
+        (proto != ETH_P_WAI) && \
+        (skb->len > 0))
+    {
+        CSR_SIGNAL signal;
+        CSR_MA_PACKET_REQUEST *req = &signal.u.MaPacketRequest;
+        netInterface_priv_t *netpriv = (netInterface_priv_t *)netdev_priv(priv->netdev[interfaceTag]);
+
+        unifi_trace(priv, UDBG4, "send_ma_pkt_request() - WAPI unicast data packet when USKID = 1 \n");
+
+        /* initialize signal to zero */
+        memset(&signal, 0, sizeof(CSR_SIGNAL));
+        /* Frame MA_PACKET request */
+        signal.SignalPrimitiveHeader.SignalId = CSR_MA_PACKET_REQUEST_ID;
+        signal.SignalPrimitiveHeader.ReceiverProcessId = 0;
+        signal.SignalPrimitiveHeader.SenderProcessId = priv->netdev_client->sender_id;
+
+        /* Fill the MA-PACKET.req */
+        req->TransmissionControl = 0;
+        req->Priority = priority;
+        unifi_trace(priv, UDBG3, "Tx Frame with Priority: %x\n", req->Priority);
+        req->TransmitRate = (CSR_RATE) 0; /* rate selected by firmware */
+        req->HostTag = 0xffffffff;        /* Ask for a new HostTag */
+        /* RA address matching with address 1 of Mac header */
+        memcpy(req->Ra.x, ((CsrUint8 *) bulkdata.d[0].os_data_ptr) + 4, ETH_ALEN);
+
+        /* Store the M4-PACKET.req for later */
+        spin_lock(&priv->wapi_lock);
+        interfacePriv->wapi_unicast_ma_pkt_sig = signal;
+        interfacePriv->wapi_unicast_bulk_data.net_buf_length = bulkdata.d[0].net_buf_length;
+        interfacePriv->wapi_unicast_bulk_data.data_length = bulkdata.d[0].data_length;
+        interfacePriv->wapi_unicast_bulk_data.os_data_ptr = bulkdata.d[0].os_data_ptr;
+        interfacePriv->wapi_unicast_bulk_data.os_net_buf_ptr = bulkdata.d[0].os_net_buf_ptr;
+        spin_unlock(&priv->wapi_lock);
+
+        /* Signal the workqueue to call CsrWifiRouterCtrlWapiUnicastTxEncryptIndSend().
+         * It cannot be called directly from the tx path because it
+         * does a non-atomic kmalloc via the framework's CsrPmemAlloc().
+         */
+        queue_work(priv->unifi_workqueue, &netpriv->send_pkt_to_encrypt);
+
+        return 0;
+    }
+#endif
+
+    if(priv->cmanrTestMode)
+    {
+        TransmitRate = priv->cmanrTestModeTransmitRate;
+        unifi_trace(priv, UDBG2, "send_ma_pkt_request: cmanrTestModeTransmitRate = %d TransmitRate=%d\n",
+                    priv->cmanrTestModeTransmitRate,
+                    TransmitRate
+                   );
+    }
+
+    /* Send UniFi msg */
+    /* Here hostTag is been sent as 0xffffffff, its been appended properly while framing MA-Packet request in pdu_processing.c file */
+    r = uf_process_ma_packet_req(priv,
+                                 peerAddress.a,
+                                 0xffffffff,  /* Ask for a new HostTag */
+                                 interfaceTag,
+                                 transmissionControl,
+                                 TransmitRate,
+                                 priority,
+                                 priv->netdev_client->sender_id,
+                                 &bulkdata);
+
+    if (r) {
+        unifi_trace(priv, UDBG1, "(HIP validation failure) r = %x\n", r);
+        unifi_net_data_free(priv, &bulkdata.d[0]);
+        return -1;
+    }
+
+    unifi_trace(priv, UDBG3, "leaving send_ma_pkt_request, UNITDATA result code = %d\n", r);
+
+    return r;
+} /* send_ma_pkt_request() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_net_xmit
+ *
+ *      This function is called by the higher level stack to transmit an
+ *      ethernet packet.
+ *
+ *  Arguments:
+ *      skb     Ethernet packet to send.
+ *      dev     Pointer to the linux net device.
+ *
+ *  Returns:
+ *      0   on success (packet was consumed, not necessarily transmitted)
+ *      1   if packet was requeued
+ *     -1   on error
+ *
+ *
+ *  Notes:
+ *      The controlled port is handled in the qdisc dequeue handler.
+ * ---------------------------------------------------------------------------
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+static netdev_tx_t
+#else
+static int
+#endif
+uf_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct ethhdr ehdr;
+    int proto, port;
+    int result;
+    static tx_signal_handler tx_handler;
+    CSR_PRIORITY priority;
+#if !defined (CONFIG_NET_SCHED) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
+    CsrWifiRouterCtrlPortAction port_action;
+#endif /* CONFIG_NET_SCHED */
+
+    func_enter();
+
+    unifi_trace(priv, UDBG5, "unifi_net_xmit: skb = %x\n", skb);
+
+    memcpy(&ehdr, skb->data, ETH_HLEN);
+    proto = ntohs(ehdr.h_proto);
+    priority = get_packet_priority(priv, skb, &ehdr, interfacePriv);
+
+    /* All frames are sent as MA-PACKET.req (EAPOL also) */
+    tx_handler = send_ma_pkt_request;
+
+    /* 802.1x - apply controlled/uncontrolled port rules */
+    if ((proto != ETH_P_PAE)
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+            && (proto != ETH_P_WAI)
+#endif
+       ) {
+        port = UF_CONTROLLED_PORT_Q;
+    } else {
+        /* queue 4 */
+        port = UF_UNCONTROLLED_PORT_Q;
+    }
+
+#if defined (CONFIG_NET_SCHED) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28))
+    /* Remove the ethernet header */
+    skb_pull(skb, ETH_HLEN);
+    result = tx_handler(priv, skb, &ehdr, priority);
+#else
+    /* Uncontrolled port rules apply */
+    port_action = verify_port(priv
+        , (((CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode)||(CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI== interfacePriv->interfaceMode))? interfacePriv->bssid.a: ehdr.h_dest)
+        , port
+        , interfacePriv->InterfaceTag);
+
+    if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN) {
+        unifi_trace(priv, UDBG5,
+                    "uf_net_xmit: %s controlled port open\n",
+                    port ? "" : "un");
+        /* Remove the ethernet header */
+        skb_pull(skb, ETH_HLEN);
+        result = tx_handler(priv, skb, &ehdr, priority);
+    } else {
+
+        /* Discard the packet if necessary */
+        unifi_trace(priv, UDBG2,
+                "uf_net_xmit: %s controlled port %s\n",
+                port ? "" : "un", port_action==CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_BLOCK ? "blocked" : "closed");
+        interfacePriv->stats.tx_dropped++;
+        kfree_skb(skb);
+
+        func_exit();
+        return NETDEV_TX_OK;
+    }
+#endif /* CONFIG_NET_SCHED */
+
+    if (result == NETDEV_TX_OK) {
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
+    	/* Don't update the tx stats when the pkt is to be sent for sw encryption*/
+    	if (!((CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode) &&
+              (priv->wapi_unicast_filter == 1)))
+        {
+            dev->trans_start = jiffies;
+            /* Should really count tx stats in the UNITDATA.status signal but
+             * that doesn't have the length.
+             */
+            interfacePriv->stats.tx_packets++;
+            /* count only the packet payload */
+            interfacePriv->stats.tx_bytes += skb->len;
+
+        }
+#else
+    	dev->trans_start = jiffies;
+
+        /*
+         * Should really count tx stats in the UNITDATA.status signal but
+         * that doesn't have the length.
+         */
+        interfacePriv->stats.tx_packets++;
+        /* count only the packet payload */
+        interfacePriv->stats.tx_bytes += skb->len;
+#endif
+    } else if (result < 0) {
+
+        /* Failed to send: fh queue was full, and the skb was discarded.
+         * Return OK to indicate that the buffer was consumed, to stop the
+         * kernel re-transmitting the freed buffer.
+         */
+        interfacePriv->stats.tx_dropped++;
+        unifi_trace(priv, UDBG1, "unifi_net_xmit: (Packet Drop), dropped count = %x\n", interfacePriv->stats.tx_dropped);
+        result = NETDEV_TX_OK;
+    }
+
+    /* The skb will have been freed by send_XXX_request() */
+
+    func_exit();
+    return result;
+} /* uf_net_xmit() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_pause_xmit
+ *  unifi_restart_xmit
+ *
+ *      These functions are called from the UniFi core to control the flow
+ *      of packets from the upper layers.
+ *      unifi_pause_xmit() is called when the internal queue is full and
+ *      should take action to stop unifi_ma_unitdata() being called.
+ *      When the queue has drained, unifi_restart_xmit() will be called to
+ *      re-enable the flow of packets for transmission.
+ *
+ *  Arguments:
+ *      ospriv          OS private context pointer.
+ *
+ *  Returns:
+ *      unifi_pause_xmit() is called from interrupt context.
+ * ---------------------------------------------------------------------------
+ */
+void
+unifi_pause_xmit(void *ospriv, unifi_TrafficQueue queue)
+{
+    unifi_priv_t *priv = ospriv;
+    int i; /* used as a loop counter */
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "Stopping queue %d\n", queue);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+    for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++)
+    {
+        if (netif_running(priv->netdev[i]))
+        {
+            netif_stop_subqueue(priv->netdev[i], (u16)queue);
+        }
+    }
+#else
+#ifdef ALLOW_Q_PAUSE
+    unifi_trace(priv, UDBG2, "Stopping netif\n");
+    /* stop the traffic from all the interfaces. */
+    for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++)
+    {
+        if (netif_running(priv->netdev[i])) {
+            UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[i]);
+        }
+    }
+#else
+    if (net_is_tx_q_paused(priv, queue)) {
+        unifi_trace(priv, UDBG2, "Queue already stopped\n");
+        return;
+    }
+    net_tx_q_pause(priv, queue);
+#endif
+#endif
+
+#ifdef CSR_SUPPORT_SME
+    if(queue<=3) {
+        routerStartBuffering(priv,queue);
+        unifi_trace(priv,UDBG2,"Start buffering %d\n", queue);
+     } else {
+        routerStartBuffering(priv,0);
+        unifi_error(priv, "Start buffering %d defaulting to 0\n", queue);
+     }
+#endif
+    func_exit();
+
+} /* unifi_pause_xmit() */
+
+void
+unifi_restart_xmit(void *ospriv, unifi_TrafficQueue queue)
+{
+    unifi_priv_t *priv = ospriv;
+    int i=0; /* used as a loop counter */
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "Waking queue %d\n", queue);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+    for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++)
+    {
+        if (netif_running(priv->netdev[i]))
+        {
+            netif_wake_subqueue(priv->netdev[i], (u16)queue);
+        }
+    }
+#else
+#ifdef ALLOW_Q_PAUSE
+    /* Need to supply queue number depending on Kernel support */
+    /* Resume the traffic from all the interfaces */
+    for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++)
+    {
+        if (netif_running(priv->netdev[i])) {
+            UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[i]);
+        }
+    }
+#else
+    if (!(net_is_tx_q_paused(priv, queue))) {
+        unifi_trace(priv, UDBG2, "Queue already running\n");
+        func_exit();
+        return;
+    }
+    net_tx_q_unpause(priv, queue);
+#endif
+#endif
+
+#ifdef CSR_SUPPORT_SME
+    if(queue <=3) {
+        routerStopBuffering(priv,queue);
+        uf_send_buffered_frames(priv,queue);
+    } else {
+        routerStopBuffering(priv,0);
+        uf_send_buffered_frames(priv,0);
+    }
+#endif
+    func_exit();
+} /* unifi_restart_xmit() */
+
+
+static void
+indicate_rx_skb(unifi_priv_t *priv, CsrUint16 ifTag, CsrUint8* dst_a, CsrUint8* src_a, struct sk_buff *skb, CSR_SIGNAL *signal,
+                bulk_data_param_t *bulkdata)
+{
+    int r, sr = 0;
+    struct net_device *dev;
+
+#ifdef CSR_SUPPORT_SME
+    llc_snap_hdr_t *snap;
+
+    snap = (llc_snap_hdr_t *)skb->data;
+
+    sr = _identify_sme_ma_pkt_ind(priv,
+                                  snap->oui, ntohs(snap->protocol),
+                                  signal,
+                                  bulkdata,
+                                  dst_a, src_a );
+#endif
+
+    /*
+     * Decapsulate any SNAP header and
+     * prepend an ethernet header so that the skb manipulation and ARP
+     * stuff works.
+     */
+    r = skb_80211_to_ether(priv, skb, dst_a, src_a,
+                           signal, bulkdata);
+    if (r == -1) {
+        /* Drop the packet and return */
+        priv->interfacePriv[ifTag]->stats.rx_errors++;
+        priv->interfacePriv[ifTag]->stats.rx_frame_errors++;
+        unifi_net_data_free(priv, &bulkdata->d[0]);
+        unifi_notice(priv, "indicate_rx_skb: Discard unknown frame.\n");
+        func_exit();
+        return;
+    }
+
+    /* Handle the case where packet is sent up through the subscription
+     * API but should not be given to the network stack (AMP PAL case)
+     * LLC header is different from WiFi and the packet has been subscribed for
+     */
+    if (r == 1 && sr == 1) {
+        unifi_net_data_free(priv, &bulkdata->d[0]);
+        unifi_trace(priv, UDBG5, "indicate_rx_skb: Data given to subscription"
+                "API, not being given to kernel\n");
+        func_exit();
+        return;
+    }
+
+    dev = priv->netdev[ifTag];
+    /* Now we look like a regular ethernet frame */
+    /* Fill in SKB meta data */
+    skb->dev = dev;
+    skb->protocol = eth_type_trans(skb, dev);
+    skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+    /* Test for an overlength frame */
+    if (skb->len > (dev->mtu + ETH_HLEN)) {
+        /* A bogus length ethfrm has been encap'd. */
+        /* Is someone trying an oflow attack? */
+        unifi_error(priv, "%s: oversize frame (%d > %d)\n",
+                    dev->name,
+                    skb->len, dev->mtu + ETH_HLEN);
+
+        /* Drop the packet and return */
+        priv->interfacePriv[ifTag]->stats.rx_errors++;
+        priv->interfacePriv[ifTag]->stats.rx_length_errors++;
+        unifi_net_data_free(priv, &bulkdata->d[0]);
+        func_exit();
+        return;
+    }
+
+
+    if(priv->cmanrTestMode)
+    {
+        const CSR_MA_PACKET_INDICATION *pkt_ind = &signal->u.MaPacketIndication;
+        priv->cmanrTestModeTransmitRate = pkt_ind->ReceivedRate;
+        unifi_trace(priv, UDBG2, "indicate_rx_skb: cmanrTestModeTransmitRate=%d\n", priv->cmanrTestModeTransmitRate);
+    }
+
+    /* Pass SKB up the stack */
+#ifdef CSR_WIFI_USE_NETIF_RX
+        netif_rx(skb);
+#else
+        netif_rx_ni(skb);
+#endif
+
+    if (dev != NULL) {
+        dev->last_rx = jiffies;
+    }
+
+    /* Bump rx stats */
+    priv->interfacePriv[ifTag]->stats.rx_packets++;
+    priv->interfacePriv[ifTag]->stats.rx_bytes += bulkdata->d[0].data_length;
+
+    func_exit();
+    return;
+}
+
+void
+uf_process_rx_pending_queue(unifi_priv_t *priv, int queue,
+                            CsrWifiMacAddress source_address,
+                            int indicate, CsrUint16 interfaceTag)
+{
+    rx_buffered_packets_t *rx_q_item;
+    struct list_head *rx_list;
+    struct list_head *n;
+    struct list_head *l_h;
+    static const CsrWifiMacAddress broadcast_address = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "uf_process_rx_pending_queue bad interfaceTag\n");
+        return;
+    }
+
+    if (queue == UF_CONTROLLED_PORT_Q) {
+        rx_list = &interfacePriv->rx_controlled_list;
+    } else {
+        rx_list = &interfacePriv->rx_uncontrolled_list;
+    }
+
+    down(&priv->rx_q_sem);
+    list_for_each_safe(l_h, n, rx_list) {
+        rx_q_item = list_entry(l_h, rx_buffered_packets_t, q);
+
+        /* Validate against the source address */
+        if (memcmp(broadcast_address.a, source_address.a, ETH_ALEN) &&
+                memcmp(rx_q_item->sa.a, source_address.a, ETH_ALEN)) {
+
+            unifi_trace(priv, UDBG2,
+                        "uf_process_rx_pending_queue: Skipping sa=%02X%02X%02X%02X%02X%02X skb=%p, bulkdata=%p\n",
+                        rx_q_item->sa.a[0], rx_q_item->sa.a[1],
+                        rx_q_item->sa.a[2], rx_q_item->sa.a[3],
+                        rx_q_item->sa.a[4], rx_q_item->sa.a[5],
+                        rx_q_item->skb, &rx_q_item->bulkdata.d[0]);
+            continue;
+        }
+
+        list_del(l_h);
+
+
+        unifi_trace(priv, UDBG2,
+                    "uf_process_rx_pending_queue: Was Blocked skb=%p, bulkdata=%p\n",
+                    rx_q_item->skb, &rx_q_item->bulkdata);
+
+        if (indicate) {
+            indicate_rx_skb(priv, interfaceTag, rx_q_item->da.a, rx_q_item->sa.a, rx_q_item->skb, &rx_q_item->signal, &rx_q_item->bulkdata);
+        } else {
+            interfacePriv->stats.rx_dropped++;
+            unifi_net_data_free(priv, &rx_q_item->bulkdata.d[0]);
+        }
+
+        /* It is our resposibility to free the Rx structure object. */
+        kfree(rx_q_item);
+    }
+    up(&priv->rx_q_sem);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_resume_data_plane
+ *
+ *      Is called when the (un)controlled port is set to open,
+ *      to notify the network stack to schedule for transmission
+ *      any packets queued in the qdisk while port was closed and
+ *      indicated to the stack any packets buffered in the Rx queues.
+ *
+ *  Arguments:
+ *      priv        Pointer to device private struct
+ *
+ *  Returns:
+ * ---------------------------------------------------------------------------
+ */
+void
+uf_resume_data_plane(unifi_priv_t *priv, int queue,
+                     CsrWifiMacAddress peer_address,
+                     CsrUint16 interfaceTag)
+{
+#ifdef CSR_SUPPORT_WEXT
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+#endif
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "uf_resume_data_plane bad interfaceTag\n");
+        return;
+    }
+
+    unifi_trace(priv, UDBG2, "Resuming netif\n");
+
+    /*
+     * If we are waiting for the net device to enter the up state, don't
+     * process the rx queue yet as it will be done by the callback when
+     * the device is ready.
+     */
+#ifdef CSR_SUPPORT_WEXT
+    if (!interfacePriv->wait_netdev_change)
+#endif
+    {
+#ifdef CONFIG_NET_SCHED
+        if (netif_running(priv->netdev[interfaceTag])) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+            netif_tx_schedule_all(priv->netdev[interfaceTag]);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+            netif_schedule_queue(netdev_get_tx_queue(priv->netdev[interfaceTag], 0));
+#else
+            netif_schedule(priv->netdev[interfaceTag]);
+#endif /* LINUX_VERSION_CODE */
+        }
+#endif
+        uf_process_rx_pending_queue(priv, queue, peer_address, 1,interfaceTag);
+    }
+} /* uf_resume_data_plane() */
+
+
+void uf_free_pending_rx_packets(unifi_priv_t *priv, int queue, CsrWifiMacAddress peer_address,CsrUint16 interfaceTag)
+{
+    uf_process_rx_pending_queue(priv, queue, peer_address, 0,interfaceTag);
+
+} /* uf_free_pending_rx_packets() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_rx
+ *
+ *      Reformat a UniFi data received packet into a p80211 packet and
+ *      pass it up the protocol stack.
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void
+unifi_rx(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata)
+{
+    CsrUint16 interfaceTag;
+    bulk_data_desc_t *pData;
+    const CSR_MA_PACKET_INDICATION *pkt_ind = &signal->u.MaPacketIndication;
+    struct sk_buff *skb;
+    CsrWifiRouterCtrlPortAction port_action;
+    CsrUint8 dataFrameType;
+    int proto;
+    int queue;
+
+    CsrUint8 da[ETH_ALEN], sa[ETH_ALEN];
+    CsrUint8 toDs, fromDs, frameType, macHeaderLengthInBytes = MAC_HEADER_SIZE;
+    CsrUint16 frameControl;
+    netInterface_priv_t *interfacePriv;
+    struct ethhdr ehdr;
+
+    func_enter();
+
+    interfaceTag = (pkt_ind->VirtualInterfaceIdentifier & 0xff);
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    /* Sanity check that the VIF refers to a sensible interface */
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES)
+    {
+        unifi_error(priv, "%s: MA-PACKET indication with bad interfaceTag %d\n", __FUNCTION__, interfaceTag);
+        unifi_net_data_free(priv,&bulkdata->d[0]);
+        func_exit();
+        return;
+    }
+
+    /* Sanity check that the VIF refers to an allocated netdev */
+    if (!interfacePriv->netdev_registered)
+    {
+        unifi_error(priv, "%s: MA-PACKET indication with unallocated interfaceTag %d\n", __FUNCTION__, interfaceTag);
+        unifi_net_data_free(priv, &bulkdata->d[0]);
+        func_exit();
+        return;
+    }
+
+    if (bulkdata->d[0].data_length == 0) {
+        unifi_warning(priv, "%s: MA-PACKET indication with zero bulk data\n", __FUNCTION__);
+        unifi_net_data_free(priv,&bulkdata->d[0]);
+        func_exit();
+        return;
+    }
+
+
+    skb = (struct sk_buff*)bulkdata->d[0].os_net_buf_ptr;
+    skb->len = bulkdata->d[0].data_length;
+
+    /* Point to the addresses */
+    toDs = (skb->data[1] & 0x01) ? 1 : 0;
+    fromDs = (skb->data[1] & 0x02) ? 1 : 0;
+
+    memcpy(da,(skb->data+4+toDs*12),ETH_ALEN);/* Address1 or 3 */
+    memcpy(sa,(skb->data+10+fromDs*(6+toDs*8)),ETH_ALEN); /* Address2, 3 or 4 */
+
+
+    pData = &bulkdata->d[0];
+    frameControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(pData->os_data_ptr);
+    frameType = ((frameControl & 0x000C) >> 2);
+
+    dataFrameType =((frameControl & 0x00f0) >> 4);
+    unifi_trace(priv, UDBG6,
+                "%s: Receive Data Frame Type %d \n", __FUNCTION__,dataFrameType);
+
+    switch(dataFrameType)
+    {
+        case QOS_DATA:
+        case QOS_DATA_NULL:
+            /* If both are set then the Address4 exists (only for AP) */
+            if (fromDs && toDs)
+            {
+                /* 6 is the size of Address4 field */
+                macHeaderLengthInBytes += (QOS_CONTROL_HEADER_SIZE + 6);
+            }
+            else
+            {
+                macHeaderLengthInBytes += QOS_CONTROL_HEADER_SIZE;
+            }
+
+            /* If order bit set then HT control field is the part of MAC header */
+            if (frameControl & FRAME_CONTROL_ORDER_BIT)
+                macHeaderLengthInBytes += HT_CONTROL_HEADER_SIZE;
+            break;
+        default:
+            if (fromDs && toDs)
+                macHeaderLengthInBytes += 6;
+    }
+
+    /* Prepare the ethernet header from snap header of skb data */
+    switch(dataFrameType)
+    {
+        case DATA_NULL:
+        case QOS_DATA_NULL:
+            /* This is for only queue info fetching, EAPOL wont come as
+             * null data so the proto is initialized as zero
+             */
+            proto = 0x0;
+            break;
+        default:
+            {
+                llc_snap_hdr_t *snap;
+                /* Fetch a snap header to find protocol (for IPV4/IPV6 packets
+                 * the snap header fetching offset is same)
+                 */
+                snap = (llc_snap_hdr_t *) (skb->data + macHeaderLengthInBytes);
+
+                /* prepare the ethernet header from the snap header & addresses */
+                ehdr.h_proto = snap->protocol;
+                memcpy(ehdr.h_dest, da, ETH_ALEN);
+                memcpy(ehdr.h_source, sa, ETH_ALEN);
+            }
+            proto = ntohs(ehdr.h_proto);
+    }
+    unifi_trace(priv, UDBG3, "in unifi_rx protocol from snap header = 0x%x\n", proto);
+
+    if ((proto != ETH_P_PAE)
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+            && (proto != ETH_P_WAI)
+#endif
+       ) {
+        queue = UF_CONTROLLED_PORT_Q;
+    } else {
+        queue = UF_UNCONTROLLED_PORT_Q;
+    }
+
+    port_action = verify_port(priv, (unsigned char*)sa, queue, interfaceTag);
+    unifi_trace(priv, UDBG3, "in unifi_rx port action is = 0x%x & queue = %x\n", port_action, queue);
+
+#ifdef CSR_SUPPORT_SME
+    /* Notify the TA module for the Rx frame for non P2PGO and AP cases*/
+    if((interfacePriv->interfaceMode != CSR_WIFI_ROUTER_CTRL_MODE_AP) &&
+            (interfacePriv->interfaceMode != CSR_WIFI_ROUTER_CTRL_MODE_P2PGO))
+    {
+        /* Remove MAC header of length(macHeaderLengthInBytes) before sampling */
+        skb_pull(skb, macHeaderLengthInBytes);
+        pData->os_data_ptr = skb->data;
+        pData->data_length -= macHeaderLengthInBytes;
+
+        if (pData->data_length) {
+            unifi_ta_sample(priv->card, CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_RX,
+                            &bulkdata->d[0],
+                            sa, priv->netdev[interfaceTag]->dev_addr,
+                            jiffies_to_msecs(jiffies),
+                            pkt_ind->ReceivedRate);
+        }
+    } else {
+
+        /* AP/P2PGO specific handling here */
+        CsrWifiRouterCtrlStaInfo_t * srcStaInfo =
+            CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv,sa,interfaceTag);
+
+        /* Defensive check only; Source address is already checked in
+        process_ma_packet_ind and we should have a valid source address here */
+
+         if(srcStaInfo == NULL) {
+            CsrWifiMacAddress peerMacAddress;
+            /* Unknown data PDU */
+            memcpy(peerMacAddress.a,sa,ETH_ALEN);
+            unifi_trace(priv, UDBG1, "%s: Unexpected frame from peer = %x:%x:%x:%x:%x:%x\n", __FUNCTION__,
+            sa[0], sa[1],sa[2], sa[3], sa[4],sa[5]);
+            CsrWifiRouterCtrlUnexpectedFrameIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,interfaceTag,peerMacAddress);
+            unifi_net_data_free(priv, &bulkdata->d[0]);
+            func_exit();
+            return;
+        }
+
+       /* For AP GO mode, don't store the PDUs */
+        if (port_action != CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN) {
+            /* Drop the packet and return */
+            CsrWifiMacAddress peerMacAddress;
+            memcpy(peerMacAddress.a,sa,ETH_ALEN);
+            unifi_trace(priv, UDBG3, "%s: Port is not open: unexpected frame from peer = %x:%x:%x:%x:%x:%x\n",
+                        __FUNCTION__, sa[0], sa[1],sa[2], sa[3], sa[4],sa[5]);
+
+            CsrWifiRouterCtrlUnexpectedFrameIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,interfaceTag,peerMacAddress);
+            interfacePriv->stats.rx_dropped++;
+            unifi_net_data_free(priv, &bulkdata->d[0]);
+            unifi_notice(priv, "%s: Dropping packet, proto=0x%04x, %s port\n", __FUNCTION__,
+                         proto, queue ? "Controlled" : "Un-controlled");
+            func_exit();
+            return;
+        }
+
+         /* Qos NULL/Data NULL  are freed here and not processed further */
+        if((dataFrameType == QOS_DATA_NULL) || (dataFrameType == DATA_NULL)){
+            unifi_trace(priv, UDBG5, "%s: Null Frame Received and Freed\n", __FUNCTION__);
+            unifi_net_data_free(priv, &bulkdata->d[0]);
+            func_exit();
+            return;
+        }
+
+        /* Now we have done with MAC header so proceed with the real data part*/
+        /* This function takes care of appropriate routing for AP/P2PGO case*/
+        /* the function hadnles following things
+           2. Routing the PDU to appropriate location
+           3. Error case handling
+           */
+        if(!(uf_ap_process_data_pdu(priv, skb, &ehdr, srcStaInfo,
+             signal,
+             bulkdata,
+             macHeaderLengthInBytes)))
+        {
+            func_exit();
+            return;
+        }
+        unifi_trace(priv, UDBG5, "unifi_rx: no specific AP handling process as normal frame, MAC Header len %d\n",macHeaderLengthInBytes);
+        /* Remove the MAC header for subsequent conversion */
+        skb_pull(skb, macHeaderLengthInBytes);
+        pData->os_data_ptr = skb->data;
+        pData->data_length -= macHeaderLengthInBytes;
+        pData->os_net_buf_ptr = (unsigned char*)skb;
+        pData->net_buf_length = skb->len;
+    }
+#endif /* CSR_SUPPORT_SME */
+
+
+    /* Now that the MAC header is removed, null-data frames have zero length
+     * and can be dropped
+     */
+    if (pData->data_length == 0) {
+        if (((frameControl & 0x00f0) >> 4) != QOS_DATA_NULL &&
+            ((frameControl & 0x00f0) >> 4) != DATA_NULL) {
+            unifi_trace(priv, UDBG1, "Zero length frame, but not null-data %04x\n", frameControl);
+        }
+        unifi_net_data_free(priv, &bulkdata->d[0]);
+        func_exit();
+        return;
+    }
+
+    if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD) {
+        /* Drop the packet and return */
+        interfacePriv->stats.rx_dropped++;
+        unifi_net_data_free(priv, &bulkdata->d[0]);
+        unifi_notice(priv, "%s: Dropping packet, proto=0x%04x, %s port\n",
+                     __FUNCTION__, proto, queue ? "controlled" : "uncontrolled");
+        func_exit();
+        return;
+    } else if ( (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_BLOCK) ||
+                   (interfacePriv->connected != UnifiConnected) ) {
+
+        /* Buffer the packet into the Rx queues */
+        rx_buffered_packets_t *rx_q_item;
+        struct list_head *rx_list;
+
+        rx_q_item = (rx_buffered_packets_t *)kmalloc(sizeof(rx_buffered_packets_t),
+                GFP_KERNEL);
+        if (rx_q_item == NULL) {
+            unifi_error(priv, "%s: Failed to allocate %d bytes for rx packet record\n",
+                        __FUNCTION__, sizeof(rx_buffered_packets_t));
+            interfacePriv->stats.rx_dropped++;
+            unifi_net_data_free(priv, &bulkdata->d[0]);
+            func_exit();
+            return;
+        }
+
+        INIT_LIST_HEAD(&rx_q_item->q);
+        rx_q_item->bulkdata = *bulkdata;
+        rx_q_item->skb = skb;
+        rx_q_item->signal = *signal;
+        memcpy(rx_q_item->sa.a, sa, ETH_ALEN);
+        memcpy(rx_q_item->da.a, da, ETH_ALEN);
+        unifi_trace(priv, UDBG2, "%s: Blocked skb=%p, bulkdata=%p\n",
+                    __FUNCTION__, rx_q_item->skb, &rx_q_item->bulkdata);
+
+        if (queue == UF_CONTROLLED_PORT_Q) {
+            rx_list = &interfacePriv->rx_controlled_list;
+        } else {
+            rx_list = &interfacePriv->rx_uncontrolled_list;
+        }
+
+        /* Add to tail of packets queue */
+        down(&priv->rx_q_sem);
+        list_add_tail(&rx_q_item->q, rx_list);
+        up(&priv->rx_q_sem);
+
+        func_exit();
+        return;
+
+    }
+
+    indicate_rx_skb(priv, interfaceTag, da, sa, skb, signal, bulkdata);
+
+    func_exit();
+
+} /* unifi_rx() */
+
+static void process_ma_packet_cfm(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata)
+{
+    CsrUint16 interfaceTag;
+    const CSR_MA_PACKET_CONFIRM *pkt_cfm = &signal->u.MaPacketConfirm;
+    netInterface_priv_t *interfacePriv;
+
+    func_enter();
+    interfaceTag = (pkt_cfm->VirtualInterfaceIdentifier & 0xff);
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    /* Sanity check that the VIF refers to a sensible interface */
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES)
+    {
+        unifi_error(priv, "%s: MA-PACKET confirm with bad interfaceTag %d\n", __FUNCTION__, interfaceTag);
+        func_exit();
+        return;
+    }
+#ifdef CSR_SUPPORT_SME
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+
+        uf_process_ma_pkt_cfm_for_ap(priv,interfaceTag,pkt_cfm);
+    } else if (interfacePriv->m4_sent && (pkt_cfm->HostTag == interfacePriv->m4_hostTag)) {
+        /* Check if this is a confirm for EAPOL M4 frame and we need to send transmistted ind*/
+        CsrResult result = pkt_cfm->TransmissionStatus == CSR_TX_SUCCESSFUL?CSR_RESULT_SUCCESS:CSR_RESULT_FAILURE;
+        CsrWifiMacAddress peerMacAddress;
+        memcpy(peerMacAddress.a, interfacePriv->m4_signal.u.MaPacketRequest.Ra.x, ETH_ALEN);
+
+        unifi_trace(priv, UDBG1, "%s: Sending M4 Transmit CFM\n", __FUNCTION__);
+        CsrWifiRouterCtrlM4TransmittedIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0,
+                                              interfaceTag,
+                                              peerMacAddress,
+                                              result);
+        interfacePriv->m4_sent = FALSE;
+        interfacePriv->m4_hostTag = 0xffffffff;
+    }
+#endif
+    func_exit();
+    return;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_rx
+ *
+ *      Reformat a UniFi data received packet into a p80211 packet and
+ *      pass it up the protocol stack.
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void process_ma_packet_ind(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata)
+{
+    CsrUint16 interfaceTag;
+    bulk_data_desc_t *pData;
+    CSR_MA_PACKET_INDICATION *pkt_ind = (CSR_MA_PACKET_INDICATION*)&signal->u.MaPacketIndication;
+    struct sk_buff *skb;
+    CsrUint16 frameControl;
+    netInterface_priv_t *interfacePriv;
+    CsrUint8 da[ETH_ALEN], sa[ETH_ALEN];
+    CsrUint8 *bssid = NULL, *ba_addr = NULL;
+    CsrUint8 toDs, fromDs, frameType;
+    CsrUint8 i =0;
+
+#ifdef CSR_SUPPORT_SME
+    CsrUint8 dataFrameType = 0;
+    CsrBool powerSaveChanged = FALSE;
+    CsrUint8 pmBit = 0;
+    CsrWifiRouterCtrlStaInfo_t *srcStaInfo = NULL;
+    CsrUint16 qosControl;
+
+#endif
+
+    func_enter();
+
+    interfaceTag = (pkt_ind->VirtualInterfaceIdentifier & 0xff);
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+
+    /* Sanity check that the VIF refers to a sensible interface */
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES)
+    {
+        unifi_error(priv, "%s: MA-PACKET indication with bad interfaceTag %d\n", __FUNCTION__, interfaceTag);
+        unifi_net_data_free(priv,&bulkdata->d[0]);
+        func_exit();
+        return;
+    }
+
+    /* Sanity check that the VIF refers to an allocated netdev */
+    if (!interfacePriv->netdev_registered)
+    {
+        unifi_error(priv, "%s: MA-PACKET indication with unallocated interfaceTag %d\n", __FUNCTION__, interfaceTag);
+        unifi_net_data_free(priv, &bulkdata->d[0]);
+        func_exit();
+        return;
+    }
+
+    if (bulkdata->d[0].data_length == 0) {
+        unifi_warning(priv, "%s: MA-PACKET indication with zero bulk data\n", __FUNCTION__);
+        unifi_net_data_free(priv,&bulkdata->d[0]);
+        func_exit();
+        return;
+    }
+    /* For monitor mode we need to pass this indication to the registered application
+    handle this seperately*/
+    /* MIC failure is already taken care of so no need to send the PDUs which are not successfully received in non-monitor mode*/
+    if(pkt_ind->ReceptionStatus != CSR_RX_SUCCESS)
+    {
+        unifi_warning(priv, "%s: MA-PACKET indication with status = %d\n",__FUNCTION__, pkt_ind->ReceptionStatus);
+        unifi_net_data_free(priv,&bulkdata->d[0]);
+        func_exit();
+        return;
+    }
+
+
+    skb = (struct sk_buff*)bulkdata->d[0].os_net_buf_ptr;
+    skb->len = bulkdata->d[0].data_length;
+
+    /* Point to the addresses */
+    toDs = (skb->data[1] & 0x01) ? 1 : 0;
+    fromDs = (skb->data[1] & 0x02) ? 1 : 0;
+
+    memcpy(da,(skb->data+4+toDs*12),ETH_ALEN);/* Address1 or 3 */
+    memcpy(sa,(skb->data+10+fromDs*(6+toDs*8)),ETH_ALEN); /* Address2, 3 or 4 */
+
+    /* Find the BSSID, which will be used to match the BA session */
+    if (toDs && fromDs)
+    {
+        unifi_trace(priv, UDBG6, "4 address frame - don't try to find BSSID\n");
+        bssid = NULL;
+    }
+    else
+    {
+        bssid = (CsrUint8 *) (skb->data + 4 + 12 - (fromDs * 6) - (toDs * 12));
+    }
+
+    pData = &bulkdata->d[0];
+    frameControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(pData->os_data_ptr);
+    frameType = ((frameControl & 0x000C) >> 2);
+
+    unifi_trace(priv, UDBG3, "Rx Frame Type: %d sn: %d\n",frameType,
+         (le16_to_cpu(*((CsrUint16*)(bulkdata->d[0].os_data_ptr + IEEE802_11_SEQUENCE_CONTROL_OFFSET))) >> 4) & 0xfff);
+    if(frameType == IEEE802_11_FRAMETYPE_CONTROL){
+#ifdef CSR_SUPPORT_SME
+        unifi_trace(priv, UDBG6, "%s: Received Control Frame\n", __FUNCTION__);
+
+        if((frameControl & 0x00f0) == 0x00A0){
+            /* This is a PS-POLL request */
+            CsrUint8 pmBit = (frameControl & 0x1000)?0x01:0x00;
+            unifi_trace(priv, UDBG6, "%s: Received PS-POLL Frame\n", __FUNCTION__);
+
+            uf_process_ps_poll(priv,sa,da,pmBit,interfaceTag);
+        }
+        else {
+            unifi_warning(priv, "%s: Non PS-POLL control frame is received\n", __FUNCTION__);
+        }
+#endif
+        unifi_net_data_free(priv,&bulkdata->d[0]);
+        func_exit();
+        return;
+    }
+    if(frameType != IEEE802_11_FRAMETYPE_DATA) {
+        unifi_warning(priv, "%s: Non control Non Data frame is received\n",__FUNCTION__);
+        unifi_net_data_free(priv,&bulkdata->d[0]);
+        func_exit();
+        return;
+    }
+
+#ifdef CSR_SUPPORT_SME
+    if((interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP) ||
+       (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO)){
+
+        srcStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv,sa,interfaceTag);
+
+        if(srcStaInfo == NULL) {
+            CsrWifiMacAddress peerMacAddress;
+            /* Unknown data PDU */
+            memcpy(peerMacAddress.a,sa,ETH_ALEN);
+            unifi_trace(priv, UDBG1, "%s: Unexpected frame from peer = %x:%x:%x:%x:%x:%x\n", __FUNCTION__,
+            sa[0], sa[1],sa[2], sa[3], sa[4],sa[5]);
+            CsrWifiRouterCtrlUnexpectedFrameIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,interfaceTag,peerMacAddress);
+            unifi_net_data_free(priv, &bulkdata->d[0]);
+            func_exit();
+            return;
+        }
+
+        /*
+        verify power management bit here so as to ensure host and unifi are always
+        in sync with power management status of peer.
+
+        If we do it later, it may so happen we have stored the frame in BA re-ordering
+        buffer and hence host and unifi are out of sync for power management status
+        */
+
+        pmBit = (frameControl & 0x1000)?0x01:0x00;
+        powerSaveChanged = uf_process_pm_bit_for_peer(priv,srcStaInfo,pmBit,interfaceTag);
+
+        /* Update station last activity time */
+        srcStaInfo->activity_flag = TRUE;
+
+        /* For Qos Frame if PM bit is toggled to indicate the change in power save state then it shall not be
+        considered as Trigger Frame. Enter only if WMM STA and peer is in Power save */
+
+        dataFrameType = ((frameControl & 0x00f0) >> 4);
+
+        if((powerSaveChanged == FALSE)&&(srcStaInfo->wmmOrQosEnabled == TRUE)&&
+        (srcStaInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE)){
+
+            if((dataFrameType == QOS_DATA) || (dataFrameType == QOS_DATA_NULL)){
+
+                /*
+                 * QoS control field is offset from frame control by 2 (frame control)
+                 * + 2 (duration/ID) + 2 (sequence control) + 3*ETH_ALEN or 4*ETH_ALEN
+                 */
+                if((frameControl & IEEE802_11_FC_TO_DS_MASK) && (frameControl & IEEE802_11_FC_FROM_DS_MASK)){
+                    qosControl= CSR_GET_UINT16_FROM_LITTLE_ENDIAN(pData->os_data_ptr + 30);
+                }
+                else{
+                    qosControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(pData->os_data_ptr + 24);
+                }
+                unifi_trace(priv, UDBG5, "%s: Check if U-APSD operations are triggered for qosControl: 0x%x\n",__FUNCTION__,qosControl);
+                uf_process_wmm_deliver_ac_uapsd(priv,srcStaInfo,qosControl,interfaceTag);
+            }
+        }
+    }
+
+#endif
+
+    if( ((frameControl & 0x00f0) >> 4) == QOS_DATA) {
+        CsrUint8 *qos_control_ptr = (CsrUint8*)bulkdata->d[0].os_data_ptr + (((frameControl & IEEE802_11_FC_TO_DS_MASK) && (frameControl & IEEE802_11_FC_FROM_DS_MASK))?30: 24);
+        int tID = *qos_control_ptr & IEEE802_11_QC_TID_MASK; /* using ls octet of qos control */
+        ba_session_rx_struct *ba_session;
+        CsrUint8 ba_session_idx = 0;
+        /* Get the BA originator address */
+        if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+           interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO){
+            ba_addr = sa;
+        }else{
+            ba_addr = bssid;
+        }
+
+        down(&priv->ba_mutex);
+        for (ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_RX; ba_session_idx++){
+            ba_session = interfacePriv->ba_session_rx[ba_session_idx];
+            if (ba_session){
+                unifi_trace(priv, UDBG6, "found ba_session=0x%x ba_session_idx=%d", ba_session, ba_session_idx);
+                if ((!memcmp(ba_session->macAddress.a, ba_addr, ETH_ALEN)) && (ba_session->tID == tID)){
+                        frame_desc_struct frame_desc;
+                        frame_desc.bulkdata = *bulkdata;
+                        frame_desc.signal = *signal;
+                        frame_desc.sn = (le16_to_cpu(*((CsrUint16*)(bulkdata->d[0].os_data_ptr + IEEE802_11_SEQUENCE_CONTROL_OFFSET))) >> 4) & 0xfff;
+                        frame_desc.active = TRUE;
+                        unifi_trace(priv, UDBG6, "%s: calling process_ba_frame (session=%d)\n", __FUNCTION__, ba_session_idx);
+                        process_ba_frame(priv, interfacePriv, ba_session, &frame_desc);
+                        up(&priv->ba_mutex);
+                        process_ba_complete(priv, interfacePriv);
+                        break;
+                }
+            }
+        }
+        if (ba_session_idx == MAX_SUPPORTED_BA_SESSIONS_RX){
+            up(&priv->ba_mutex);
+            unifi_trace(priv, UDBG6, "%s: calling process_amsdu()", __FUNCTION__);
+            process_amsdu(priv, signal, bulkdata);
+        }
+    } else {
+        unifi_trace(priv, UDBG6, "calling unifi_rx()");
+        unifi_rx(priv, signal, bulkdata);
+    }
+
+    /* check if the frames in reorder buffer has aged, the check
+     * is done after receive processing so that if the missing frame
+     * has arrived in this receive process, then it is handled cleanly.
+     *
+     * And also this code here takes care that timeout check is made for all
+     * the receive indications
+     */
+    down(&priv->ba_mutex);
+    for (i=0; i < MAX_SUPPORTED_BA_SESSIONS_RX; i++){
+        ba_session_rx_struct *ba_session;
+        ba_session = interfacePriv->ba_session_rx[i];
+            if (ba_session){
+                check_ba_frame_age_timeout(priv, interfacePriv, ba_session);
+            }
+    }
+    up(&priv->ba_mutex);
+    process_ba_complete(priv, interfacePriv);
+
+    func_exit();
+}
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_set_multicast_list
+ *
+ *      This function is called by the higher level stack to set
+ *      a list of multicast rx addresses.
+ *
+ *  Arguments:
+ *      dev             Network Device pointer.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ * ---------------------------------------------------------------------------
+ */
+
+static void
+uf_set_multicast_list(struct net_device *dev)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+
+#ifdef CSR_NATIVE_LINUX
+    unifi_trace(priv, UDBG3, "uf_set_multicast_list unsupported\n");
+    return;
+#else
+
+    u8 *mc_list = interfacePriv->mc_list;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34)
+    struct netdev_hw_addr *mc_addr;
+    int mc_addr_count;
+#else
+    struct dev_mc_list *p;      /* Pointer to the addresses structure. */
+    int i;
+#endif
+
+    if (priv->init_progress != UNIFI_INIT_COMPLETED) {
+        return;
+    }
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34)
+    mc_addr_count = netdev_mc_count(dev);
+
+    unifi_trace(priv, UDBG3,
+            "uf_set_multicast_list (count=%d)\n", mc_addr_count);
+
+
+    /* Not enough space? */
+    if (mc_addr_count > UNIFI_MAX_MULTICAST_ADDRESSES) {
+        return;
+    }
+
+    /* Store the list to be processed by the work item. */
+    interfacePriv->mc_list_count = mc_addr_count;
+    netdev_hw_addr_list_for_each(mc_addr, &dev->mc) {
+        memcpy(mc_list, mc_addr->addr, ETH_ALEN);
+        mc_list += ETH_ALEN;
+    }
+
+#else
+    unifi_trace(priv, UDBG3,
+            "uf_set_multicast_list (count=%d)\n", dev->mc_count);
+
+    /* Not enough space? */
+    if (dev->mc_count > UNIFI_MAX_MULTICAST_ADDRESSES) {
+        return;
+    }
+
+    /* Store the list to be processed by the work item. */
+    interfacePriv->mc_list_count = dev->mc_count;
+    p = dev->mc_list;
+    for (i = 0; i < dev->mc_count; i++) {
+        memcpy(mc_list, p->dmi_addr, ETH_ALEN);
+        p = p->next;
+        mc_list += ETH_ALEN;
+    }
+#endif
+
+    /* Send a message to the workqueue */
+    queue_work(priv->unifi_workqueue, &priv->multicast_list_task);
+#endif
+
+} /* uf_set_multicast_list() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  netdev_mlme_event_handler
+ *
+ *      Callback function to be used as the udi_event_callback when registering
+ *      as a netdev client.
+ *      To use it, a client specifies this function as the udi_event_callback
+ *      to ul_register_client(). The signal dispatcher in
+ *      unifi_receive_event() will call this function to deliver a signal.
+ *
+ *  Arguments:
+ *      pcli            Pointer to the client instance.
+ *      signal          Pointer to the received signal.
+ *      signal_len      Size of the signal structure in bytes.
+ *      bulkdata        Pointer to structure containing any associated bulk data.
+ *      dir             Direction of the signal. Zero means from host,
+ *                      non-zero means to host.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void
+netdev_mlme_event_handler(ul_client_t *pcli, const u8 *sig_packed, int sig_len,
+                          const bulk_data_param_t *bulkdata_o, int dir)
+{
+    CSR_SIGNAL signal;
+    unifi_priv_t *priv = uf_find_instance(pcli->instance);
+    int id, r;
+    bulk_data_param_t bulkdata;
+
+    func_enter();
+
+    /* Just a sanity check */
+    if (sig_packed == NULL) {
+        return;
+    }
+
+    /*
+     * This copy is to silence a compiler warning about discarding the
+     * const qualifier.
+     */
+    bulkdata = *bulkdata_o;
+
+    /* Get the unpacked signal */
+    r = read_unpack_signal(sig_packed, &signal);
+    if (r) {
+        /*
+         * The CSR_MLME_CONNECTED_INDICATION_ID has a receiverID=0 so will
+         * fall through this case. It is safe to ignore this signal.
+         */
+        unifi_trace(priv, UDBG1,
+                    "Netdev - Received unknown signal 0x%.4X.\n",
+                    CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
+        return;
+    }
+
+    id = signal.SignalPrimitiveHeader.SignalId;
+    unifi_trace(priv, UDBG3, "Netdev - Process signal 0x%.4X\n", id);
+
+    /*
+     * Take the appropriate action for the signal.
+     */
+    switch (id) {
+        case CSR_MA_PACKET_ERROR_INDICATION_ID:
+            process_ma_packet_error_ind(priv, &signal, &bulkdata);
+            break;
+        case CSR_MA_PACKET_INDICATION_ID:
+            process_ma_packet_ind(priv, &signal, &bulkdata);
+            break;
+        case  CSR_MA_PACKET_CONFIRM_ID:
+            process_ma_packet_cfm(priv, &signal, &bulkdata);
+            break;
+#ifdef CSR_SUPPORT_SME
+        case CSR_MLME_SET_TIM_CONFIRM_ID:
+            /* Handle TIM confirms from FW & set the station record's TIM state appropriately,
+             * In case of failures, tries with max_retransmit limit
+             */
+            uf_handle_tim_cfm(priv, &signal.u.MlmeSetTimConfirm, signal.SignalPrimitiveHeader.ReceiverProcessId);
+            break;
+#endif
+        case CSR_DEBUG_STRING_INDICATION_ID:
+            debug_string_indication(priv, bulkdata.d[0].os_data_ptr, bulkdata.d[0].data_length);
+            break;
+
+        case CSR_DEBUG_WORD16_INDICATION_ID:
+            debug_word16_indication(priv, &signal);
+            break;
+
+        case CSR_DEBUG_GENERIC_CONFIRM_ID:
+        case CSR_DEBUG_GENERIC_INDICATION_ID:
+            debug_generic_indication(priv, &signal);
+            break;
+        default:
+            break;
+    }
+
+    func_exit();
+} /* netdev_mlme_event_handler() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_net_get_name
+ *
+ *      Retrieve the name (e.g. eth1) associated with this network device
+ *
+ *  Arguments:
+ *      dev             Pointer to the network device.
+ *      name            Buffer to write name
+ *      len             Size of buffer in bytes
+ *
+ *  Returns:
+ *      None
+ *
+ *  Notes:
+ * ---------------------------------------------------------------------------
+ */
+void uf_net_get_name(struct net_device *dev, char *name, int len)
+{
+    *name = '\0';
+    if (dev) {
+        strlcpy(name, dev->name, (len > IFNAMSIZ) ? IFNAMSIZ : len);
+    }
+
+} /* uf_net_get_name */
+
+
+
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+#ifdef CONFIG_NET_SCHED
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_install_qdisc
+ *
+ *      Creates a root qdisc, registers our qdisc handlers and
+ *      overrides the device's qdisc_sleeping to prevent the system
+ *      from creating a new one for our network device.
+ *
+ *  Arguments:
+ *      dev             Pointer to the network device.
+ *
+ *  Returns:
+ *      0 on success, Linux error code otherwise.
+ *
+ *  Notes:
+ *      This function holds the qdisk lock so it needs to be called
+ *      after registering the network device in uf_register_netdev().
+ *      Also, the qdisc_create_dflt() API has changed in 2.6.20 to
+ *      include the parentid.
+ * ---------------------------------------------------------------------------
+ */
+int uf_install_qdisc(struct net_device *dev)
+{
+    struct Qdisc *qdisc;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+    struct netdev_queue *queue0;
+#endif /* LINUX_VERSION_CODE */
+
+
+    func_enter();
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+    /*
+     * check that there is no qdisc currently attached to device
+     * this ensures that we will be the root qdisc. (I can't find a better
+     * way to test this explicitly)
+     */
+    if (dev->qdisc_sleeping != &noop_qdisc) {
+        func_exit_r(-EFAULT);
+        return -EINVAL;
+    }
+#endif /* LINUX_VERSION_CODE */
+
+    qdisc = UF_QDISC_CREATE_DFLT(dev, &uf_qdisc_ops, TC_H_ROOT);
+    if (!qdisc) {
+        unifi_error(NULL, "%s: qdisc installation failed\n", dev->name);
+        func_exit_r(-EFAULT);
+        return -EFAULT;
+    }
+    unifi_trace(NULL, UDBG5, "%s: parent qdisc=0x%p\n",
+            dev->name, qdisc);
+
+    qdisc->handle = 0x80020000;
+    qdisc->flags = 0x0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+    queue0 = netdev_get_tx_queue(dev, 0);
+    if (queue0 == NULL) {
+        unifi_error(NULL, "%s: netdev_get_tx_queue returned no queue\n",
+                dev->name);
+        func_exit_r(-EFAULT);
+        return -EFAULT;
+    }
+    queue0->qdisc = qdisc;
+    queue0->qdisc_sleeping = qdisc;
+#else
+    qdisc_lock_tree(dev);
+    list_add_tail(&qdisc->list, &dev->qdisc_list);
+    dev->qdisc_sleeping = qdisc;
+    qdisc_unlock_tree(dev);
+#endif /* LINUX_VERSION_CODE */
+
+    func_exit_r(0);
+    return 0;
+
+} /* uf_install_qdisc() */
+
+static int uf_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev_queue->dev);
+#else
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev);
+#endif /* LINUX_VERSION_CODE */
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct uf_sched_data *q = qdisc_priv(qd);
+    struct uf_tx_packet_data *pkt_data = (struct uf_tx_packet_data *) skb->cb;
+    struct ethhdr ehdr;
+    struct Qdisc *qdisc;
+    int r, proto;
+
+    func_enter();
+
+    memcpy(&ehdr, skb->data, ETH_HLEN);
+    proto = ntohs(ehdr.h_proto);
+
+    /* 802.1x - apply controlled/uncontrolled port rules */
+    if ((proto != ETH_P_PAE)
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+            && (proto != ETH_P_WAI)
+#endif
+       ) {
+        /* queues 0 - 3 */
+        pkt_data->priority = get_packet_priority(priv, skb, &ehdr, interfacePriv);
+        pkt_data->queue = unifi_frame_priority_to_queue(pkt_data->priority);
+    } else {
+        pkt_data->queue = UNIFI_TRAFFIC_Q_EAPOL;
+    }
+
+    qdisc = q->queues[pkt_data->queue];
+    r = qdisc->enqueue(skb, qdisc);
+    if (r == NET_XMIT_SUCCESS) {
+        qd->q.qlen++;
+        qd->bstats.bytes += skb->len;
+        qd->bstats.packets++;
+        func_exit_r(NET_XMIT_SUCCESS);
+        return NET_XMIT_SUCCESS;
+    }
+
+    unifi_error(priv, "uf_qdiscop_enqueue: dropped\n");
+    qd->qstats.drops++;
+
+    func_exit_r(r);
+    return r;
+
+} /* uf_qdiscop_enqueue() */
+
+
+static int uf_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t*)netdev_priv(qd->dev_queue->dev);
+#else
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t*)netdev_priv(qd->dev);
+#endif /* LINUX_VERSION_CODE */
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct uf_sched_data *q = qdisc_priv(qd);
+    struct uf_tx_packet_data *pkt_data = (struct uf_tx_packet_data *) skb->cb;
+    struct Qdisc *qdisc;
+    int r;
+
+    func_enter();
+
+    unifi_trace(priv, UDBG5, "uf_qdiscop_requeue: (q=%d), tag=%u\n",
+            pkt_data->queue, pkt_data->host_tag);
+
+    /* we recorded which queue to use earlier! */
+    qdisc = q->queues[pkt_data->queue];
+
+    if ((r = qdisc->ops->requeue(skb, qdisc)) == 0) {
+        qd->q.qlen++;
+        func_exit_r(0);
+        return 0;
+    }
+
+    unifi_error(priv, "uf_qdiscop_requeue: dropped\n");
+    qd->qstats.drops++;
+
+    func_exit_r(r);
+    return r;
+} /* uf_qdiscop_requeue() */
+
+static struct sk_buff *uf_qdiscop_dequeue(struct Qdisc* qd)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev_queue->dev);
+#else
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev);
+#endif /* LINUX_VERSION_CODE */
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct uf_sched_data *q = qdisc_priv(qd);
+    struct sk_buff *skb;
+    struct Qdisc *qdisc;
+    int queue, i;
+    struct ethhdr ehdr;
+    struct uf_tx_packet_data *pkt_data;
+    CsrWifiRouterCtrlPortAction port_action;
+
+    func_enter();
+
+    /* check all the queues */
+    for (i = UNIFI_TRAFFIC_Q_MAX - 1; i >= 0; i--) {
+
+        if (i != UNIFI_TRAFFIC_Q_EAPOL) {
+            queue = priv->prev_queue;
+            if (++priv->prev_queue >= UNIFI_TRAFFIC_Q_EAPOL) {
+                priv->prev_queue = 0;
+            }
+        } else {
+            queue = i;
+        }
+
+#ifndef ALLOW_Q_PAUSE
+        /* If queue is paused, do not dequeue */
+        if (net_is_tx_q_paused(priv, queue)) {
+            unifi_trace(priv, UDBG5,
+                    "uf_qdiscop_dequeue: tx queue paused (q=%d)\n", queue);
+            continue;
+        }
+#endif
+
+        qdisc = q->queues[queue];
+        skb = qdisc->dequeue(qdisc);
+        if (skb) {
+            /* A packet has been dequeued, decrease the queued packets count */
+            qd->q.qlen--;
+
+            pkt_data = (struct uf_tx_packet_data *) skb->cb;
+
+            /* Check the (un)controlled port status */
+            memcpy(&ehdr, skb->data, ETH_HLEN);
+
+            port_action = verify_port(priv
+                            , (((CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode) ||(CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI == interfacePriv->interfaceMode))? interfacePriv->bssid.a: ehdr.h_dest)
+                            , (UNIFI_TRAFFIC_Q_EAPOL == queue? UF_UNCONTROLLED_PORT_Q: UF_CONTROLLED_PORT_Q)
+                            , interfacePriv->InterfaceTag);
+
+            /* Dequeue packet if port is open */
+            if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN) {
+                unifi_trace(priv, UDBG5,
+                        "uf_qdiscop_dequeue: new (q=%d), tag=%u\n",
+                        queue, pkt_data->host_tag);
+
+                func_exit();
+                return skb;
+            }
+
+            /* Discard or block the packet if necessary */
+            if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD) {
+                unifi_trace(priv, UDBG5,
+                        "uf_qdiscop_dequeue: drop (q=%d), tag=%u\n",
+                        queue, pkt_data->host_tag);
+                kfree_skb(skb);
+                break;
+            }
+
+            /* We can not send the packet now, put it back to the queue */
+            if (qdisc->ops->requeue(skb, qdisc) != 0) {
+                unifi_error(priv,
+                        "uf_qdiscop_dequeue: requeue (q=%d) failed, tag=%u, drop it\n",
+                        queue, pkt_data->host_tag);
+
+                /* Requeue failed, drop the packet */
+                kfree_skb(skb);
+                break;
+            }
+            /* We requeued the packet, increase the queued packets count */
+            qd->q.qlen++;
+
+            unifi_trace(priv, UDBG5,
+                    "uf_qdiscop_dequeue: skip (q=%d), tag=%u\n",
+                    queue, pkt_data->host_tag);
+        }
+    }
+
+    func_exit();
+    return NULL;
+} /* uf_qdiscop_dequeue() */
+
+
+static void uf_qdiscop_reset(struct Qdisc* qd)
+{
+    struct uf_sched_data *q = qdisc_priv(qd);
+    int queue;
+    func_enter();
+
+    for (queue = 0; queue < UNIFI_TRAFFIC_Q_MAX; queue++) {
+        qdisc_reset(q->queues[queue]);
+    }
+    qd->q.qlen = 0;
+
+    func_exit();
+} /* uf_qdiscop_reset() */
+
+
+static void uf_qdiscop_destroy(struct Qdisc* qd)
+{
+    struct uf_sched_data *q = qdisc_priv(qd);
+    int queue;
+
+    func_enter();
+
+    for (queue=0; queue < UNIFI_TRAFFIC_Q_MAX; queue++) {
+        qdisc_destroy(q->queues[queue]);
+        q->queues[queue] = &noop_qdisc;
+    }
+
+    func_exit();
+} /* uf_qdiscop_destroy() */
+
+
+/* called whenever parameters are updated on existing qdisc */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+static int uf_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt)
+#else
+static int uf_qdiscop_tune(struct Qdisc *qd, struct rtattr *opt)
+#endif
+{
+    func_enter();
+    func_exit();
+    return 0;
+} /* uf_qdiscop_tune() */
+
+
+/* called during initial creation of qdisc on device */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+static int uf_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
+#else
+static int uf_qdiscop_init(struct Qdisc *qd, struct rtattr *opt)
+#endif
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+    struct net_device *dev = qd->dev_queue->dev;
+#else
+    struct net_device *dev = qd->dev;
+#endif /* LINUX_VERSION_CODE */
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct uf_sched_data *q = qdisc_priv(qd);
+    int err = 0, i;
+
+    func_enter();
+
+    /* make sure we do not mess with the ingress qdisc */
+    if (qd->flags & TCQ_F_INGRESS) {
+        func_exit();
+        return -EINVAL;
+    }
+
+    /* if options were passed in, set them */
+    if (opt) {
+        err = uf_qdiscop_tune(qd, opt);
+    }
+
+    /* create child queues */
+    for (i = 0; i < UNIFI_TRAFFIC_Q_MAX; i++) {
+        q->queues[i] = UF_QDISC_CREATE_DFLT(dev, &pfifo_qdisc_ops,
+                qd->handle);
+        if (!q->queues[i]) {
+            q->queues[i] = &noop_qdisc;
+            unifi_error(priv, "%s child qdisc %i creation failed\n");
+        }
+
+        unifi_trace(priv, UDBG5, "%s: child qdisc=0x%p\n",
+                dev->name, q->queues[i]);
+    }
+
+    func_exit_r(err);
+    return err;
+} /* uf_qdiscop_init() */
+
+
+static int uf_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb)
+{
+    func_enter();
+    func_exit_r(skb->len);
+    return skb->len;
+} /* uf_qdiscop_dump() */
+
+#endif /* CONFIG_NET_SCHED */
+#endif /* LINUX_VERSION_CODE */
+
+#ifdef CSR_SUPPORT_WEXT
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_netdev_event
+ *
+ *     Callback function to handle netdev state changes
+ *
+ *  Arguments:
+ *      notif           Pointer to a notifier_block.
+ *      event           Event prompting notification
+ *      ptr             net_device pointer
+ *
+ *  Returns:
+ *      None
+ *
+ *  Notes:
+ *   The event handler is global, and may occur on non-UniFi netdevs.
+ * ---------------------------------------------------------------------------
+ */
+static int
+uf_netdev_event(struct notifier_block *notif, unsigned long event, void* ptr) {
+    struct net_device *netdev = ptr;
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(netdev);
+    unifi_priv_t *priv = NULL;
+    static const CsrWifiMacAddress broadcast_address = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
+
+    /* Check that the event is for a UniFi netdev. If it's not, the netdev_priv
+     * structure is not safe to use.
+     */
+    if (uf_find_netdev_priv(interfacePriv) == -1) {
+        unifi_trace(NULL, UDBG1, "uf_netdev_event: ignore e=%d, ptr=%p, priv=%p %s\n",
+                    event, ptr, interfacePriv, netdev->name);
+        return 0;
+    }
+
+    switch(event) {
+    case NETDEV_CHANGE:
+        priv = interfacePriv->privPtr;
+        unifi_trace(priv, UDBG1, "NETDEV_CHANGE: %p %s %s waiting for it\n",
+                    ptr,
+                    netdev->name,
+                    interfacePriv->wait_netdev_change ? "" : "not");
+
+        if (interfacePriv->wait_netdev_change) {
+            UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[interfacePriv->InterfaceTag]);
+            interfacePriv->connected = UnifiConnected;
+            interfacePriv->wait_netdev_change = FALSE;
+            /* Note: passing the broadcast address here will allow anyone to attempt to join our adhoc network */
+            uf_process_rx_pending_queue(priv, UF_UNCONTROLLED_PORT_Q, broadcast_address, 1,interfacePriv->InterfaceTag);
+            uf_process_rx_pending_queue(priv, UF_CONTROLLED_PORT_Q, broadcast_address, 1,interfacePriv->InterfaceTag);
+        }
+        break;
+
+    default:
+        break;
+    }
+    return 0;
+}
+
+static struct notifier_block uf_netdev_notifier = {
+    .notifier_call = uf_netdev_event,
+};
+#endif /* CSR_SUPPORT_WEXT */
+
+
+static void
+        process_amsdu(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata)
+{
+    CsrUint32 offset;
+    CsrUint32 length = bulkdata->d[0].data_length;
+    CsrUint32 subframe_length, subframe_body_length, dot11_hdr_size;
+    CsrUint8 *ptr;
+    bulk_data_param_t subframe_bulkdata;
+    CsrUint8 *dot11_hdr_ptr = (CsrUint8*)bulkdata->d[0].os_data_ptr;
+    CsrResult csrResult;
+    CsrUint16 frameControl;
+    CsrUint8 *qos_control_ptr;
+
+    frameControl = le16_to_cpu(*((CsrUint16*)dot11_hdr_ptr));
+    qos_control_ptr = dot11_hdr_ptr + (((frameControl & IEEE802_11_FC_TO_DS_MASK) && (frameControl & IEEE802_11_FC_FROM_DS_MASK))?30: 24);
+    if(!(*qos_control_ptr & IEEE802_11_QC_A_MSDU_PRESENT)) {
+        unifi_trace(priv, UDBG6, "%s: calling unifi_rx()", __FUNCTION__);
+        unifi_rx(priv, signal, bulkdata);
+        return;
+    }
+    *qos_control_ptr &= ~(IEEE802_11_QC_A_MSDU_PRESENT);
+
+    ptr = qos_control_ptr + 2;
+    offset = dot11_hdr_size = ptr - dot11_hdr_ptr;
+
+    while(length > (offset + sizeof(struct ethhdr) + sizeof(llc_snap_hdr_t))) {
+        subframe_body_length = ntohs(((struct ethhdr*)ptr)->h_proto);
+        if(subframe_body_length > IEEE802_11_MAX_DATA_LEN) {
+            unifi_error(priv, "%s: bad subframe_body_length = %d\n", __FUNCTION__, subframe_body_length);
+            break;
+        }
+        subframe_length = sizeof(struct ethhdr) + subframe_body_length;
+        memset(&subframe_bulkdata, 0, sizeof(bulk_data_param_t));
+
+        csrResult = unifi_net_data_malloc(priv, &subframe_bulkdata.d[0], dot11_hdr_size + subframe_body_length);
+
+        if (csrResult != CSR_RESULT_SUCCESS) {
+            unifi_error(priv, "%s: unifi_net_data_malloc failed\n", __FUNCTION__);
+            break;
+        }
+
+        memcpy((CsrUint8*)subframe_bulkdata.d[0].os_data_ptr, dot11_hdr_ptr, dot11_hdr_size);
+
+
+        /* When to DS=0 and from DS=0, address 3 will already have BSSID so no need to re-program */
+        if ((frameControl & IEEE802_11_FC_TO_DS_MASK) && !(frameControl & IEEE802_11_FC_FROM_DS_MASK)){
+                memcpy((CsrUint8*)subframe_bulkdata.d[0].os_data_ptr + IEEE802_11_ADDR3_OFFSET, ((struct ethhdr*)ptr)->h_dest, ETH_ALEN);
+        }
+        else if (!(frameControl & IEEE802_11_FC_TO_DS_MASK) && (frameControl & IEEE802_11_FC_FROM_DS_MASK)){
+                memcpy((CsrUint8*)subframe_bulkdata.d[0].os_data_ptr + IEEE802_11_ADDR3_OFFSET,
+                         ((struct ethhdr*)ptr)->h_source,
+                           ETH_ALEN);
+        }
+
+        memcpy((CsrUint8*)subframe_bulkdata.d[0].os_data_ptr + dot11_hdr_size,
+                ptr + sizeof(struct ethhdr),
+                             subframe_body_length);
+        unifi_trace(priv, UDBG6, "%s: calling unifi_rx. length = %d subframe_length = %d\n", __FUNCTION__, length, subframe_length);
+        unifi_rx(priv, signal, &subframe_bulkdata);
+
+        subframe_length = (subframe_length + 3)&(~0x3);
+        ptr += subframe_length;
+        offset += subframe_length;
+    }
+    unifi_net_data_free(priv, &bulkdata->d[0]);
+}
+
+
+#define SN_TO_INDEX(__ba_session, __sn) (((__sn - __ba_session->start_sn) & 0xFFF) % __ba_session->wind_size)
+
+
+#define ADVANCE_EXPECTED_SN(__ba_session) \
+{ \
+    __ba_session->expected_sn++; \
+    __ba_session->expected_sn &= 0xFFF; \
+}
+
+#define FREE_BUFFER_SLOT(__ba_session, __index) \
+{ \
+    __ba_session->occupied_slots--; \
+    __ba_session->buffer[__index].active = FALSE; \
+    ADVANCE_EXPECTED_SN(__ba_session); \
+}
+
+static void add_frame_to_ba_complete(unifi_priv_t *priv,
+                          netInterface_priv_t *interfacePriv,
+                          frame_desc_struct *frame_desc)
+{
+    interfacePriv->ba_complete[interfacePriv->ba_complete_index] = *frame_desc;
+    interfacePriv->ba_complete_index++;
+}
+
+
+static void update_expected_sn(unifi_priv_t *priv,
+                          netInterface_priv_t *interfacePriv,
+                          ba_session_rx_struct *ba_session,
+                          CsrUint16 sn)
+{
+    int i, j;
+    CsrUint16 gap;
+
+    gap = (sn - ba_session->expected_sn) & 0xFFF;
+    unifi_trace(priv, UDBG6, "%s: proccess the frames up to new_expected_sn = %d gap = %d\n", __FUNCTION__, sn, gap);
+    for(j = 0; j < gap && j < ba_session->wind_size; j++) {
+        i = SN_TO_INDEX(ba_session, ba_session->expected_sn);
+        unifi_trace(priv, UDBG6, "%s: proccess the slot index = %d\n", __FUNCTION__, i);
+        if(ba_session->buffer[i].active) {
+            add_frame_to_ba_complete(priv, interfacePriv, &ba_session->buffer[i]);
+            unifi_trace(priv, UDBG6, "%s: proccess the frame at index = %d expected_sn = %d\n", __FUNCTION__, i, ba_session->expected_sn);
+            FREE_BUFFER_SLOT(ba_session, i);
+        } else {
+            unifi_trace(priv, UDBG6, "%s: empty slot at index = %d\n", __FUNCTION__, i);
+            ADVANCE_EXPECTED_SN(ba_session);
+        }
+    }
+    ba_session->expected_sn = sn;
+}
+
+
+static void complete_ready_sequence(unifi_priv_t *priv,
+                               netInterface_priv_t *interfacePriv,
+                               ba_session_rx_struct *ba_session)
+{
+    int i;
+
+    i = SN_TO_INDEX(ba_session, ba_session->expected_sn);
+    while (ba_session->buffer[i].active) {
+        add_frame_to_ba_complete(priv, interfacePriv, &ba_session->buffer[i]);
+        unifi_trace(priv, UDBG6, "%s: completed stored frame(expected_sn=%d) at i = %d\n", __FUNCTION__, ba_session->expected_sn, i);
+        FREE_BUFFER_SLOT(ba_session, i);
+        i = SN_TO_INDEX(ba_session, ba_session->expected_sn);
+    }
+}
+
+
+void scroll_ba_window(unifi_priv_t *priv,
+                                netInterface_priv_t *interfacePriv,
+                                ba_session_rx_struct *ba_session,
+                                CsrUint16 sn)
+{
+    if(((sn - ba_session->expected_sn) & 0xFFF) <= 2048) {
+        update_expected_sn(priv, interfacePriv, ba_session, sn);
+        complete_ready_sequence(priv, interfacePriv, ba_session);
+    }
+}
+
+
+static int consume_frame_or_get_buffer_index(unifi_priv_t *priv,
+                                            netInterface_priv_t *interfacePriv,
+                                            ba_session_rx_struct *ba_session,
+                                            CsrUint16 sn,
+                                            frame_desc_struct *frame_desc) {
+    int i;
+    CsrUint16 sn_temp;
+
+    if(((sn - ba_session->expected_sn) & 0xFFF) <= 2048) {
+
+        /* once we are in BA window, set the flag for BA trigger */
+        if(!ba_session->trigger_ba_after_ssn){
+            ba_session->trigger_ba_after_ssn = TRUE;
+        }
+
+        sn_temp = ba_session->expected_sn + ba_session->wind_size;
+        unifi_trace(priv, UDBG6, "%s: new frame: sn=%d\n", __FUNCTION__, sn);
+        if(!(((sn - sn_temp) & 0xFFF) > 2048)) {
+            CsrUint16 new_expected_sn;
+            unifi_trace(priv, UDBG6, "%s: frame is out of window\n", __FUNCTION__);
+            sn_temp = (sn - ba_session->wind_size) & 0xFFF;
+            new_expected_sn = (sn_temp + 1) & 0xFFF;
+            update_expected_sn(priv, interfacePriv, ba_session, new_expected_sn);
+        }
+        i = -1;
+        if (sn == ba_session->expected_sn) {
+            unifi_trace(priv, UDBG6, "%s: sn = ba_session->expected_sn = %d\n", __FUNCTION__, sn);
+            ADVANCE_EXPECTED_SN(ba_session);
+            add_frame_to_ba_complete(priv, interfacePriv, frame_desc);
+        } else {
+            i = SN_TO_INDEX(ba_session, sn);
+            unifi_trace(priv, UDBG6, "%s: sn(%d) != ba_session->expected_sn(%d), i = %d\n", __FUNCTION__, sn, ba_session->expected_sn, i);
+            if (ba_session->buffer[i].active) {
+                unifi_trace(priv, UDBG6, "%s: free frame at i = %d\n", __FUNCTION__, i);
+                i = -1;
+                unifi_net_data_free(priv, &frame_desc->bulkdata.d[0]);
+            }
+        }
+    } else {
+        i = -1;
+        if(!ba_session->trigger_ba_after_ssn){
+            unifi_trace(priv, UDBG6, "%s: frame before ssn, pass it up: sn=%d\n", __FUNCTION__, sn);
+            add_frame_to_ba_complete(priv, interfacePriv, frame_desc);
+        }else{
+            unifi_trace(priv, UDBG6, "%s: old frame, drop: sn=%d, expected_sn=%d\n", __FUNCTION__, sn, ba_session->expected_sn);
+            unifi_net_data_free(priv, &frame_desc->bulkdata.d[0]);
+        }
+    }
+    return i;
+}
+
+
+
+static void process_ba_frame(unifi_priv_t *priv,
+                                             netInterface_priv_t *interfacePriv,
+                                             ba_session_rx_struct *ba_session,
+                                             frame_desc_struct *frame_desc)
+{
+    int i;
+    CsrUint16 sn = frame_desc->sn;
+
+    if (ba_session->timeout) {
+        mod_timer(&ba_session->timer, (jiffies + usecs_to_jiffies((ba_session->timeout) * 1024)));
+    }
+    unifi_trace(priv, UDBG6, "%s: got frame(sn=%d)\n", __FUNCTION__, sn);
+
+    i = consume_frame_or_get_buffer_index(priv, interfacePriv, ba_session, sn, frame_desc);
+    if(i >= 0) {
+        unifi_trace(priv, UDBG6, "%s: store frame(sn=%d) at i = %d\n", __FUNCTION__, sn, i);
+        ba_session->buffer[i] = *frame_desc;
+        ba_session->buffer[i].recv_time = CsrTimeGet(NULL);
+        ba_session->occupied_slots++;
+    } else {
+        unifi_trace(priv, UDBG6, "%s: frame consumed - sn = %d\n", __FUNCTION__, sn);
+    }
+    complete_ready_sequence(priv, interfacePriv, ba_session);
+}
+
+
+static void process_ba_complete(unifi_priv_t *priv, netInterface_priv_t *interfacePriv)
+{
+    frame_desc_struct *frame_desc;
+    CsrUint8 i;
+
+    for(i = 0; i < interfacePriv->ba_complete_index; i++) {
+        frame_desc = &interfacePriv->ba_complete[i];
+        unifi_trace(priv, UDBG6, "%s: calling process_amsdu()\n", __FUNCTION__);
+        process_amsdu(priv, &frame_desc->signal, &frame_desc->bulkdata);
+    }
+    interfacePriv->ba_complete_index = 0;
+
+}
+
+
+/* Check if the frames in BA reoder buffer has aged and
+ * if so release the frames to upper processes and move
+ * the window
+ */
+static void check_ba_frame_age_timeout( unifi_priv_t *priv,
+                                        netInterface_priv_t *interfacePriv,
+                                        ba_session_rx_struct *ba_session)
+{
+    CsrTime now;
+    CsrTime age;
+    CsrUint8 i, j;
+    CsrUint16 sn_temp;
+
+    /* gap is started at 1 because we have buffered frames and
+     * hence a minimum gap of 1 exists
+     */
+    CsrUint8 gap=1;
+
+    now = CsrTimeGet(NULL);
+
+    if (ba_session->occupied_slots)
+    {
+        /* expected sequence has not arrived so start searching from next
+         * sequence number until a frame is available and determine the gap.
+         * Check if the frame available has timedout, if so advance the
+         * expected sequence number and release the frames
+         */
+        sn_temp = (ba_session->expected_sn + 1) & 0xFFF;
+
+        for(j = 0; j < ba_session->wind_size; j++)
+        {
+            i = SN_TO_INDEX(ba_session, sn_temp);
+
+            if(ba_session->buffer[i].active)
+            {
+                unifi_trace(priv, UDBG6, "check age at slot index = %d sn = %d recv_time = %u now = %u\n",
+                                        i,
+                                        ba_session->buffer[i].sn,
+                                        ba_session->buffer[i].recv_time,
+                                        now);
+
+                if (ba_session->buffer[i].recv_time > now)
+                {
+                    /* timer wrap */
+                    age = CsrTimeAdd((CsrTime)CsrTimeSub(CSR_SCHED_TIME_MAX, ba_session->buffer[i].recv_time), now);
+                }
+                else
+                {
+                    age = (CsrTime)CsrTimeSub(now, ba_session->buffer[i].recv_time);
+                }
+
+                if (age >= CSR_WIFI_BA_MPDU_FRAME_AGE_TIMEOUT)
+                {
+                    unifi_trace(priv, UDBG2, "release the frame at index = %d gap = %d expected_sn = %d sn = %d\n",
+                                            i,
+                                            gap,
+                                            ba_session->expected_sn,
+                                            ba_session->buffer[i].sn);
+
+                    /* if it has timedout don't wait for missing frames, move the window */
+                    while (gap--)
+                    {
+                        ADVANCE_EXPECTED_SN(ba_session);
+                    }
+                    add_frame_to_ba_complete(priv, interfacePriv, &ba_session->buffer[i]);
+                    FREE_BUFFER_SLOT(ba_session, i);
+                    complete_ready_sequence(priv, interfacePriv, ba_session);
+                }
+                break;
+
+            }
+            else
+            {
+                /* advance temp sequence number and frame gap */
+                sn_temp = (sn_temp + 1) & 0xFFF;
+                gap++;
+            }
+        }
+    }
+}
+
+
+static void process_ma_packet_error_ind(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata)
+{
+    CsrUint16 interfaceTag;
+    const CSR_MA_PACKET_ERROR_INDICATION *pkt_err_ind = &signal->u.MaPacketErrorIndication;
+    netInterface_priv_t *interfacePriv;
+    ba_session_rx_struct *ba_session;
+    CsrUint8 ba_session_idx = 0;
+    CSR_PRIORITY        UserPriority;
+    CSR_SEQUENCE_NUMBER sn;
+
+    func_enter();
+
+    interfaceTag = (pkt_err_ind->VirtualInterfaceIdentifier & 0xff);
+
+
+    /* Sanity check that the VIF refers to a sensible interface */
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES)
+    {
+        unifi_error(priv, "%s: MaPacketErrorIndication indication with bad interfaceTag %d\n", __FUNCTION__, interfaceTag);
+        func_exit();
+        return;
+    }
+
+    interfacePriv = priv->interfacePriv[interfaceTag];
+    UserPriority = pkt_err_ind->UserPriority;
+    if(UserPriority > 15) {
+        unifi_error(priv, "%s: MaPacketErrorIndication indication with bad UserPriority=%d\n", __FUNCTION__, UserPriority);
+        func_exit();
+    }
+    sn = pkt_err_ind->SequenceNumber;
+
+    down(&priv->ba_mutex);
+    /* To find the right ba_session loop through the BA sessions, compare MAC address and tID */
+    for (ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_RX; ba_session_idx++){
+        ba_session = interfacePriv->ba_session_rx[ba_session_idx];
+        if (ba_session){
+            if ((!memcmp(ba_session->macAddress.a, pkt_err_ind->PeerQstaAddress.x, ETH_ALEN)) && (ba_session->tID == UserPriority)){
+                if (ba_session->timeout) {
+                    mod_timer(&ba_session->timer, (jiffies + usecs_to_jiffies((ba_session->timeout) * 1024)));
+                }
+                scroll_ba_window(priv, interfacePriv, ba_session, sn);
+                break;
+            }
+        }
+    }
+
+    up(&priv->ba_mutex);
+    process_ba_complete(priv, interfacePriv);
+    func_exit();
+}
+
+
diff --git a/drivers/staging/csr/os.c b/drivers/staging/csr/os.c
new file mode 100644
index 0000000..f5a9352
--- /dev/null
+++ b/drivers/staging/csr/os.c
@@ -0,0 +1,483 @@
+/*
+ * ---------------------------------------------------------------------------
+ *  FILE:     os.c
+ *
+ *  PURPOSE:
+ *      Routines to fulfil the OS-abstraction for the HIP lib.
+ *      It is part of the porting exercise.
+ *
+ * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+/**
+ * The HIP lib OS abstraction consists of the implementation
+ * of the functions in this file. It is part of the porting exercise.
+ */
+
+#include "unifi_priv.h"
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_net_data_malloc
+ *
+ *      Allocate an OS specific net data buffer of "size" bytes.
+ *      The bulk_data_slot.os_data_ptr must be initialised to point
+ *      to the buffer allocated. The bulk_data_slot.length must be
+ *      initialised to the requested size, zero otherwise.
+ *      The bulk_data_slot.os_net_buf_ptr can be initialised to
+ *      an OS specific pointer to be used in the unifi_net_data_free().
+ *
+ *
+ *  Arguments:
+ *      ospriv              Pointer to device private context struct.
+ *      bulk_data_slot      Pointer to the bulk data structure to initialise.
+ *      size                Size of the buffer to be allocated.
+ *
+ *  Returns:
+ *      CSR_RESULT_SUCCESS on success, CSR_RESULT_FAILURE otherwise.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+unifi_net_data_malloc(void *ospriv, bulk_data_desc_t *bulk_data_slot, unsigned int size)
+{
+    struct sk_buff *skb;
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+    int rounded_length;
+
+    if (priv->card_info.sdio_block_size == 0) {
+        unifi_error(priv, "unifi_net_data_malloc: Invalid SDIO block size\n");
+        return CSR_RESULT_FAILURE;
+    }
+
+    rounded_length = (size + priv->card_info.sdio_block_size - 1) & ~(priv->card_info.sdio_block_size - 1);
+
+    /*
+     * (ETH_HLEN + 2) bytes tailroom for header manipulation
+     * CSR_WIFI_ALIGN_BYTES bytes headroom for alignment manipulation
+     */
+    skb = dev_alloc_skb(rounded_length + 2 + ETH_HLEN + CSR_WIFI_ALIGN_BYTES);
+    if (! skb) {
+        unifi_error(ospriv, "alloc_skb failed.\n");
+        bulk_data_slot->os_net_buf_ptr = NULL;
+        bulk_data_slot->net_buf_length = 0;
+        bulk_data_slot->os_data_ptr = NULL;
+        bulk_data_slot->data_length = 0;
+        return CSR_RESULT_FAILURE;
+    }
+
+    bulk_data_slot->os_net_buf_ptr = (const unsigned char*)skb;
+    bulk_data_slot->net_buf_length = rounded_length + 2 + ETH_HLEN + CSR_WIFI_ALIGN_BYTES;
+    bulk_data_slot->os_data_ptr = (const void*)skb->data;
+    bulk_data_slot->data_length = size;
+
+    return CSR_RESULT_SUCCESS;
+} /* unifi_net_data_malloc() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_net_data_free
+ *
+ *      Free an OS specific net data buffer.
+ *      The bulk_data_slot.length must be initialised to 0.
+ *
+ *
+ *  Arguments:
+ *      ospriv              Pointer to device private context struct.
+ *      bulk_data_slot      Pointer to the bulk data structure that
+ *                          holds the data to be freed.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+unifi_net_data_free(void *ospriv, bulk_data_desc_t *bulk_data_slot)
+{
+    struct sk_buff *skb;
+    CSR_UNUSED(ospriv);
+
+    skb = (struct sk_buff *)bulk_data_slot->os_net_buf_ptr;
+    dev_kfree_skb(skb);
+
+    bulk_data_slot->net_buf_length = 0;
+    bulk_data_slot->data_length = 0;
+    bulk_data_slot->os_data_ptr = bulk_data_slot->os_net_buf_ptr = NULL;
+
+} /* unifi_net_data_free() */
+
+
+/*
+* ---------------------------------------------------------------------------
+*  unifi_net_dma_align
+*
+*      DMA align an OS specific net data buffer.
+*      The buffer must be empty.
+*
+*
+*  Arguments:
+*      ospriv              Pointer to device private context struct.
+*      bulk_data_slot      Pointer to the bulk data structure that
+*                          holds the data to be aligned.
+*
+*  Returns:
+*      None.
+* ---------------------------------------------------------------------------
+*/
+CsrResult
+unifi_net_dma_align(void *ospriv, bulk_data_desc_t *bulk_data_slot)
+{
+    struct sk_buff *skb;
+    unsigned long buf_address;
+    int offset;
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+
+    if ((bulk_data_slot == NULL) || (CSR_WIFI_ALIGN_BYTES == 0)) {
+        return CSR_RESULT_SUCCESS;
+    }
+
+    if ((bulk_data_slot->os_data_ptr == NULL) || (bulk_data_slot->data_length == 0)) {
+        return CSR_RESULT_SUCCESS;
+    }
+
+    buf_address = (unsigned long)(bulk_data_slot->os_data_ptr) & (CSR_WIFI_ALIGN_BYTES - 1);
+
+    unifi_trace(priv, UDBG5,
+                "unifi_net_dma_align: Allign buffer (0x%p) by %d bytes\n",
+                bulk_data_slot->os_data_ptr, buf_address);
+
+    offset = CSR_WIFI_ALIGN_BYTES - buf_address;
+    if (offset < 0) {
+        unifi_error(priv, "unifi_net_dma_align: Failed (offset=%d)\n", offset);
+        return CSR_RESULT_FAILURE;
+    }
+
+    skb = (struct sk_buff*)(bulk_data_slot->os_net_buf_ptr);
+    skb_reserve(skb, offset);
+    bulk_data_slot->os_net_buf_ptr = (const unsigned char*)skb;
+    bulk_data_slot->os_data_ptr = (const void*)(skb->data);
+
+    return CSR_RESULT_SUCCESS;
+
+} /* unifi_net_dma_align() */
+
+#ifdef ANDROID_TIMESTAMP
+static volatile unsigned int printk_cpu = UINT_MAX;
+char tbuf[30];
+
+char* print_time(void )
+{
+    unsigned long long t;
+    unsigned long nanosec_rem;
+
+    t = cpu_clock(printk_cpu);
+    nanosec_rem = do_div(t, 1000000000);
+    sprintf(tbuf, "[%5lu.%06lu] ",
+                    (unsigned long) t,
+                    nanosec_rem / 1000);
+
+    return tbuf;
+}
+#endif
+
+
+/* Module parameters */
+extern int unifi_debug;
+
+#ifdef UNIFI_DEBUG
+#define DEBUG_BUFFER_SIZE       120
+
+#define FORMAT_TRACE(_s, _len, _args, _fmt)             \
+    do {                                                \
+        va_start(_args, _fmt);                          \
+        _len += vsnprintf(&(_s)[_len],                  \
+                         (DEBUG_BUFFER_SIZE - _len),    \
+                         _fmt, _args);                  \
+        va_end(_args);                                  \
+        if (_len >= DEBUG_BUFFER_SIZE) {                \
+            (_s)[DEBUG_BUFFER_SIZE - 2] = '\n';         \
+            (_s)[DEBUG_BUFFER_SIZE - 1] = 0;            \
+        }                                               \
+    } while (0)
+
+void
+unifi_error(void* ospriv, const char *fmt, ...)
+{
+    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
+    char s[DEBUG_BUFFER_SIZE];
+    va_list args;
+    unsigned int len;
+#ifdef ANDROID_TIMESTAMP
+    if (priv != NULL) {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "%s unifi%d: ", print_time(), priv->instance);
+    } else {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "%s unifi: ", print_time());
+    }
+#else
+    if (priv != NULL) {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "unifi%d: ", priv->instance);
+    } else {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "unifi: ");
+    }
+#endif /* ANDROID_TIMESTAMP */
+    FORMAT_TRACE(s, len, args, fmt);
+
+    printk("%s", s);
+}
+
+void
+unifi_warning(void* ospriv, const char *fmt, ...)
+{
+    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
+    char s[DEBUG_BUFFER_SIZE];
+    va_list args;
+    unsigned int len;
+
+#ifdef ANDROID_TIMESTAMP
+    if (priv != NULL) {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_WARNING "%s unifi%d: ", print_time(), priv->instance);
+    } else {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_WARNING "%s unifi: ", print_time());
+    }
+#else
+    if (priv != NULL) {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_WARNING "unifi%d: ", priv->instance);
+    } else {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_WARNING "unifi: ");
+    }
+#endif /* ANDROID_TIMESTAMP */
+
+    FORMAT_TRACE(s, len, args, fmt);
+
+    printk("%s", s);
+}
+
+
+void
+unifi_notice(void* ospriv, const char *fmt, ...)
+{
+    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
+    char s[DEBUG_BUFFER_SIZE];
+    va_list args;
+    unsigned int len;
+
+#ifdef ANDROID_TIMESTAMP
+    if (priv != NULL) {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_NOTICE "%s unifi%d: ", print_time(), priv->instance);
+    } else {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_NOTICE "%s unifi: ", print_time());
+    }
+#else
+    if (priv != NULL) {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_NOTICE "unifi%d: ", priv->instance);
+    } else {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_NOTICE "unifi: ");
+    }
+#endif /* ANDROID_TIMESTAMP */
+
+    FORMAT_TRACE(s, len, args, fmt);
+
+    printk("%s", s);
+}
+
+
+void
+unifi_info(void* ospriv, const char *fmt, ...)
+{
+    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
+    char s[DEBUG_BUFFER_SIZE];
+    va_list args;
+    unsigned int len;
+
+#ifdef ANDROID_TIMESTAMP
+    if (priv != NULL) {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_INFO "%s unifi%d: ", print_time(), priv->instance);
+    } else {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_INFO "%s unifi: ", print_time());
+    }
+#else
+    if (priv != NULL) {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_INFO "unifi%d: ", priv->instance);
+    } else {
+        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_INFO "unifi: ");
+    }
+#endif /* ANDROID_TIMESTAMP */
+
+    FORMAT_TRACE(s, len, args, fmt);
+
+    printk("%s", s);
+}
+
+/* debugging */
+void
+unifi_trace(void* ospriv, int level, const char *fmt, ...)
+{
+    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
+    char s[DEBUG_BUFFER_SIZE];
+    va_list args;
+    unsigned int len;
+
+    if (unifi_debug >= level) {
+#ifdef ANDROID_TIMESTAMP
+        if (priv != NULL) {
+            len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "%s unifi%d: ", print_time(), priv->instance);
+        } else {
+            len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "%s unifi: ", print_time());
+        }
+#else
+        if (priv != NULL) {
+            len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "unifi%d: ", priv->instance);
+        } else {
+            len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "unifi: ");
+        }
+#endif /* ANDROID_TIMESTAMP */
+
+        FORMAT_TRACE(s, len, args, fmt);
+
+        printk("%s", s);
+    }
+}
+
+#else
+
+void
+unifi_error_nop(void* ospriv, const char *fmt, ...)
+{
+}
+
+void
+unifi_trace_nop(void* ospriv, int level, const char *fmt, ...)
+{
+}
+
+#endif /* UNIFI_DEBUG */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ *      Debugging support.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+#ifdef UNIFI_DEBUG
+
+/* Memory dump with level filter controlled by unifi_debug */
+void
+unifi_dump(void *ospriv, int level, const char *msg, void *mem, CsrUint16 len)
+{
+    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
+
+    if (unifi_debug >= level) {
+#ifdef ANDROID_TIMESTAMP
+        if (priv != NULL) {
+            printk(KERN_ERR "%s unifi%d: --- dump: %s ---\n", print_time(), priv->instance, msg ? msg : "");
+        } else {
+            printk(KERN_ERR "%s unifi: --- dump: %s ---\n", print_time(), msg ? msg : "");
+        }
+#else
+        if (priv != NULL) {
+            printk(KERN_ERR "unifi%d: --- dump: %s ---\n", priv->instance, msg ? msg : "");
+        } else {
+            printk(KERN_ERR "unifi: --- dump: %s ---\n", msg ? msg : "");
+        }
+#endif /* ANDROID_TIMESTAMP */
+        dump(mem, len);
+
+        if (priv != NULL) {
+            printk(KERN_ERR "unifi%d: --- end of dump ---\n", priv->instance);
+        } else {
+            printk(KERN_ERR "unifi: --- end of dump ---\n");
+        }
+    }
+}
+
+/* Memory dump that appears all the time, use sparingly */
+void
+dump(void *mem, CsrUint16 len)
+{
+    int i, col = 0;
+    unsigned char *pdata = (unsigned char *)mem;
+#ifdef ANDROID_TIMESTAMP
+    printk("timestamp %s \n", print_time());
+#endif /* ANDROID_TIMESTAMP */
+    if (mem == NULL) {
+        printk("(null dump)\n");
+        return;
+    }
+    for (i = 0; i < len; i++) {
+        if (col == 0) {
+            printk("0x%02X: ", i);
+        }
+
+        printk(" %02X", pdata[i]);
+
+        if (++col == 16) {
+            printk("\n");
+            col = 0;
+        }
+    }
+    if (col) {
+        printk("\n");
+    }
+} /* dump() */
+
+
+void
+dump16(void *mem, CsrUint16 len)
+{
+    int i, col=0;
+    unsigned short *p = (unsigned short *)mem;
+#ifdef ANDROID_TIMESTAMP
+    printk("timestamp %s \n", print_time());
+#endif /* ANDROID_TIMESTAMP */
+    for (i = 0; i < len; i+=2) {
+        if (col == 0) {
+            printk("0x%02X: ", i);
+        }
+
+        printk(" %04X", *p++);
+
+        if (++col == 8) {
+            printk("\n");
+            col = 0;
+        }
+    }
+    if (col) {
+        printk("\n");
+    }
+}
+
+
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+void
+dump_str(void *mem, CsrUint16 len)
+{
+    int i, col = 0;
+    unsigned char *pdata = (unsigned char *)mem;
+#ifdef ANDROID_TIMESTAMP
+    printk("timestamp %s \n", print_time());
+#endif /* ANDROID_TIMESTAMP */
+    for (i = 0; i < len; i++) {
+        printk("%c", pdata[i]);
+    }
+    if (col) {
+        printk("\n");
+    }
+
+} /* dump_str() */
+#endif /* CSR_ONLY_NOTES */
+
+
+#endif /* UNIFI_DEBUG */
+
+
+/* ---------------------------------------------------------------------------
+ *                              - End -
+ * ------------------------------------------------------------------------- */
diff --git a/drivers/staging/csr/oska/Makefile b/drivers/staging/csr/oska/Makefile
new file mode 100644
index 0000000..3a0b648
--- /dev/null
+++ b/drivers/staging/csr/oska/Makefile
@@ -0,0 +1,12 @@
+obj-$(CONFIG_CSR_WIFI) := csr_oska.o
+
+csr_oska-y := \
+       list.o \
+       refcount.o \
+       compat.o \
+       event.o \
+       oska_module.o \
+       print.o  \
+       thread.o \
+       timer.o
+
diff --git a/drivers/staging/csr/oska/all.h b/drivers/staging/csr/oska/all.h
new file mode 100644
index 0000000..5fe8583
--- /dev/null
+++ b/drivers/staging/csr/oska/all.h
@@ -0,0 +1,61 @@
+/*
+ * Operating system kernel abstraction -- all functions
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_ALL_H
+#define __OSKA_ALL_H
+
+/**
+ * @mainpage Operating System Kernel Abstraction
+ *
+ * @section intro Introduction
+ *
+ * The Operating System Kernel Abstraction (oska) is a software
+ * package providing an abstraction for various operating system
+ * kernel facilities for use by device drivers and other OS kernel
+ * software (e.g., SDIO stacks).  Oska is modularized and intended to
+ * be a lightweight wrapper around an OSes interfaces.
+ *
+ * @section modules Modules
+ *
+ * Oska is organized into the modules, each of which has it's own
+ * header file providing the interface.
+ *
+ *   - \ref alloc "Memory allocation" <oska/alloc.h>
+ *   - \ref event "Events" <oska/event.h>
+ *   - \ref mutex "Mutexes" <oska/mutex.h>
+ *   - \ref print "Console output" <oska/print.h>
+ *   - \ref spinlock "Spinlocks" <oska/spinlock.h>
+ *   - \ref thread "Threading" <oska/thread.h>
+ *   - \ref time "Timing and delays" <oska/time.h>
+ *   - \ref timer "Timers" <oska/timer.h>
+ *   - \ref types "Standard Types" <oska/types.h>
+ *   - \ref util "Miscellaneous utilities" <oska/util.h>
+ *
+ * An <oska/all.h> header is provided which includes all the above
+ * modules.
+ *
+ * There are additional modules that are not included in <oska/all.h>.
+ *
+ *   - \ref io "Memory mapped I/O" <oska/io.h>
+ *   - \ref refcount "Reference Counting" <oska/refcount.h>
+ *   - \ref list "Linked lists" <oska/list.h>
+ *   - \ref trace "Tracing messages" <oska/trace.h>
+ */
+
+#include "alloc.h"
+#include "event.h"
+#include "mutex.h"
+#include "print.h"
+#include "spinlock.h"
+#include "thread.h"
+#include "time.h"
+#include "timer.h"
+#include "types.h"
+#include "util.h"
+
+#endif /* __OSKA_ALL_H */
diff --git a/drivers/staging/csr/oska/alloc.h b/drivers/staging/csr/oska/alloc.h
new file mode 100644
index 0000000..0f10601
--- /dev/null
+++ b/drivers/staging/csr/oska/alloc.h
@@ -0,0 +1,41 @@
+/*
+ * OSKA Linux implementation -- memory allocation
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_ALLOC_H
+#define __OSKA_LINUX_ALLOC_H
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+static inline void *os_alloc(size_t size)
+{
+    return kzalloc(size, GFP_ATOMIC);
+}
+
+static inline void *os_alloc_nonzeroed(size_t size)
+{
+    return kmalloc(size, GFP_KERNEL);
+}
+
+static inline void os_free(void *ptr)
+{
+    kfree(ptr);
+}
+
+static inline void *os_alloc_big(size_t size)
+{
+    return vmalloc(size);
+}
+
+static inline void os_free_big(void *ptr)
+{
+    vfree(ptr);
+}
+
+#endif /* #ifndef __OSKA_LINUX_ALLOC_H */
diff --git a/drivers/staging/csr/oska/compat.c b/drivers/staging/csr/oska/compat.c
new file mode 100644
index 0000000..790b97a
--- /dev/null
+++ b/drivers/staging/csr/oska/compat.c
@@ -0,0 +1,54 @@
+/*
+ * Linux version compatibility functions.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#include "kernel-compat.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+
+int dev_set_name(struct device *dev, const char *fmt, ...)
+{
+    va_list vargs;
+
+    va_start(vargs, fmt);
+    vsnprintf(dev->bus_id, sizeof(dev->bus_id), fmt, vargs);
+    va_end(vargs);
+    return 0;
+}
+EXPORT_SYMBOL_GPL(dev_set_name);
+
+#endif /* Linux kernel < 2.6.26 */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+
+struct device *class_find_device(struct class *class, struct device *start,
+                                 void *data, int (*match)(struct device *, void *))
+{
+    struct device *dev;
+
+    list_for_each_entry(dev, &class->devices, node) {
+        if (match(dev, data)) {
+            get_device(dev);
+            return dev;
+        }
+    }
+    return NULL;
+}
+EXPORT_SYMBOL_GPL(class_find_device);
+
+#endif /* Linux kernel < 2.6.25 */
diff --git a/drivers/staging/csr/oska/event.c b/drivers/staging/csr/oska/event.c
new file mode 100644
index 0000000..4aedaaa
--- /dev/null
+++ b/drivers/staging/csr/oska/event.c
@@ -0,0 +1,82 @@
+/*
+ * Linux event functions.
+ *
+ * Copyright (C) 2009 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#include <linux/module.h>
+#include <linux/sched.h>
+
+#include "event.h"
+
+void os_event_init(os_event_t *evt)
+{
+    init_waitqueue_head(&evt->wq);
+    spin_lock_init(&evt->lock);
+    evt->events = 0;
+}
+EXPORT_SYMBOL(os_event_init);
+
+uint16_t os_event_wait(os_event_t *evt)
+{
+    uint16_t e;
+    unsigned long flags;
+
+    wait_event(evt->wq, evt->events != 0);
+
+    spin_lock_irqsave(&evt->lock, flags);
+    e = evt->events;
+    evt->events &= ~e;
+    spin_unlock_irqrestore(&evt->lock, flags);
+
+    return e;
+}
+EXPORT_SYMBOL(os_event_wait);
+
+uint16_t os_event_wait_interruptible(os_event_t *evt)
+{
+    uint16_t e;
+    unsigned long flags;
+
+    wait_event_interruptible(evt->wq, evt->events != 0);
+
+    spin_lock_irqsave(&evt->lock, flags);
+    e = evt->events;
+    evt->events &= ~e;
+    spin_unlock_irqrestore(&evt->lock, flags);
+
+    return e;
+}
+EXPORT_SYMBOL(os_event_wait_interruptible);
+
+uint16_t os_event_wait_timed(os_event_t *evt, unsigned timeout_ms)
+{
+    uint16_t e;
+    unsigned long flags;
+
+    wait_event_interruptible_timeout(evt->wq,
+                                     evt->events != 0,
+                                     msecs_to_jiffies(timeout_ms));
+
+    spin_lock_irqsave(&evt->lock, flags);
+    e = evt->events;
+    evt->events &= ~e;
+    spin_unlock_irqrestore(&evt->lock, flags);
+
+    return e;
+}
+EXPORT_SYMBOL(os_event_wait_timed);
+
+void os_event_raise(os_event_t *evt, uint16_t events)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&evt->lock, flags);
+    evt->events |= events;
+    spin_unlock_irqrestore(&evt->lock, flags);
+
+    wake_up(&evt->wq);
+}
+EXPORT_SYMBOL(os_event_raise);
diff --git a/drivers/staging/csr/oska/event.h b/drivers/staging/csr/oska/event.h
new file mode 100644
index 0000000..be52e42
--- /dev/null
+++ b/drivers/staging/csr/oska/event.h
@@ -0,0 +1,33 @@
+/*
+ * OSKA Linux implementation -- events
+ *
+ * Copyright (C) 2009 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_EVENT_H
+#define __OSKA_LINUX_EVENT_H
+
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+
+typedef struct {
+    wait_queue_head_t wq;
+    spinlock_t lock;
+    uint16_t events;
+} os_event_t;
+
+void os_event_init(os_event_t *evt);
+
+static inline void os_event_destroy(os_event_t *evt)
+{
+}
+
+uint16_t os_event_wait(os_event_t *evt);
+uint16_t os_event_wait_interruptible(os_event_t *evt);
+uint16_t os_event_wait_timed(os_event_t *evt, unsigned timeout_ms);
+void os_event_raise(os_event_t *evt, uint16_t events);
+
+#endif /* #ifndef __OSKA_LINUX_EVENT_H */
diff --git a/drivers/staging/csr/oska/io.h b/drivers/staging/csr/oska/io.h
new file mode 100644
index 0000000..c6c406c
--- /dev/null
+++ b/drivers/staging/csr/oska/io.h
@@ -0,0 +1,63 @@
+/*
+ * OSKA Linux implementation -- memory mapped I/O.
+ *
+ * Copyright (C) 2009 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_IO_H
+#define __OSKA_LINUX_IO_H
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/kernel-compat.h>
+
+typedef void __iomem *os_io_mem_t;
+
+static inline uint8_t os_io_read8(os_io_mem_t base, unsigned offset)
+{
+    return readb(base + offset);
+}
+
+static inline uint16_t os_io_read16(os_io_mem_t base, unsigned offset)
+{
+    return readw(base + offset);
+}
+
+static inline uint32_t os_io_read32(os_io_mem_t base, unsigned offset)
+{
+    return readl(base + offset);
+}
+
+static inline uint64_t os_io_read64(os_io_mem_t base, unsigned offset)
+{
+    return readq(base + offset);
+}
+
+static inline void os_io_write8(os_io_mem_t base, unsigned offset, uint8_t val)
+{
+    writeb(val, base + offset);
+}
+
+static inline void os_io_write16(os_io_mem_t base, unsigned offset, uint16_t val)
+{
+    writew(val, base + offset);
+}
+
+static inline void os_io_write32(os_io_mem_t base, unsigned offset, uint32_t val)
+{
+    writel(val, base + offset);
+}
+
+static inline void os_io_write64(os_io_mem_t base, unsigned offset, uint64_t val)
+{
+    writeq(val, base + offset);
+}
+
+static inline void os_io_memory_barrier(void)
+{
+    mb();
+}
+
+#endif /* #ifndef __OSKA_LINUX_IO_H */
diff --git a/drivers/staging/csr/oska/kernel-compat.h b/drivers/staging/csr/oska/kernel-compat.h
new file mode 100644
index 0000000..b6d27d3
--- /dev/null
+++ b/drivers/staging/csr/oska/kernel-compat.h
@@ -0,0 +1,199 @@
+/*
+ * Kernel version compatibility.
+ *
+ * Copyright (C) 2007-2008 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * Wherever possible compatible implementations of newer APIs are
+ * provided for older kernel versions.
+ */
+#ifndef __LINUX_KERNEL_COMPAT_H
+#define __LINUX_KERNEL_COMPAT_H
+
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+
+#include <asm/io.h>
+
+/*
+ * linux/semaphore.h replaces asm/semaphore.h in 2.6.27.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+#  include <asm/semaphore.h>
+#else
+#  include <linux/semaphore.h>
+#endif
+
+/*
+ * Workqueue API changes in 2.6.20
+ *
+ * See http://lwn.net/Articles/211279/ for details.
+ *
+ * We deliberately don't provide the non-automatic release (NAR)
+ * variants as a simple compatible implementation is not possible.
+ * This shouldn't be a problem as all usage so far is to embed the
+ * struct work_struct into another struct and the NAR variants aren't
+ * useful in this case (see http://lwn.net/Articles/213149/).
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+
+#include <linux/workqueue.h>
+
+#undef INIT_WORK
+#define INIT_WORK(_work, _func)                                         \
+    do {                                                                \
+        INIT_LIST_HEAD(&(_work)->entry);                                \
+        (_work)->pending = 0;                                           \
+        PREPARE_WORK((_work), (_func), (_work));                        \
+        init_timer(&(_work)->timer);                                    \
+    } while(0)
+
+#undef DECLARE_WORK
+#define DECLARE_WORK(n, f) \
+    struct work_struct n = __WORK_INITIALIZER((n), (f), &(n))
+
+struct delayed_work {
+    struct work_struct work;
+};
+
+#define INIT_DELAYED_WORK(dw, fn) \
+    INIT_WORK(&(dw)->work, (fn))
+
+#define queue_delayed_work(wq, dw, delay) \
+    queue_delayed_work((wq), &(dw)->work, (delay))
+
+#define schedule_delayed_work(dw, delay) \
+    schedule_delayed_work(&(dw)->work, (delay))
+
+#define cancel_delayed_work(dw) \
+    cancel_delayed_work(&(dw)->work)
+
+#endif  /* Linux kernel < 2.6.20 */
+
+/*
+ * device_create()/class_device_create()
+ *
+ * device_create() gains a drvdata parameter in 2.6.27. Since all
+ * users of device_create() in CSR code don't use drvdata just ignore
+ * it.
+ *
+ * device_create() replaces class_device_create() in 2.6.21.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
+
+#define device_create(class, parent, devt, drvdata, fmt, args...) \
+    class_device_create((class), (parent), (devt), NULL, (fmt), ## args)
+#define device_destroy(class, devt) \
+    class_device_destroy(class, devt)
+
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+
+#define device_create(class, parent, devt, drvdata, fmt, args...) \
+    device_create((class), (parent), (devt), (fmt), ## args)
+
+#endif /* Linux kernel < 2.6.26 */
+
+/*
+ * dev_name() and dev_set_name() added in 2.6.26.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+
+static inline char *dev_name(struct device *dev)
+{
+    return dev->bus_id;
+}
+
+int dev_set_name(struct device *dev, const char *fmt, ...);
+
+#endif /* Linux kernel < 2.6.26 */
+
+/*
+ * class_find_device() in 2.6.25
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+
+struct device *class_find_device(struct class *class, struct device *start,
+                                 void *data, int (*match)(struct device *, void *));
+
+#endif /* Linux kernel < 2.6.25 */
+
+/*
+ * list_first_entry in 2.6.22.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+
+#define list_first_entry(ptr, type, member) \
+    list_entry((ptr)->next, type, member)
+
+#endif /* Linux kernel < 2.6.22 */
+
+/*
+ * 2.6.19 adds a bool type.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+
+typedef _Bool bool;
+enum {
+        false   = 0,
+        true    = 1
+};
+
+#endif /* Linux kernel < 2.6.19 */
+
+/*
+ * Provide readq() and writeq() if unavailable.
+ */
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+    const volatile u32 __iomem *p = addr;
+    u32 low, high;
+
+    low = readl(p);
+    high = readl(p + 1);
+
+    return low + ((u64)high << 32);
+}
+#endif
+
+#ifndef writeq
+static inline void writeq(__u64 val, volatile void __iomem *addr)
+{
+    writel(val, addr);
+    writel(val >> 32, addr+4);
+}
+#endif
+
+/*
+ * get_unaligned_le16() and friends added in 2.6.26.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+#include <asm/unaligned.h>
+
+static inline __u16 get_unaligned_le16(const void *p)
+{
+    return le16_to_cpu(get_unaligned((__le16 *)p));
+}
+
+static inline void put_unaligned_le16(__u16 val, const void *p)
+{
+    put_unaligned(cpu_to_le16(val), (__le16 *)p);
+}
+#endif /* Linux kernel < 2.6.26 */
+
+/*
+ * Various device or vendor IDs may not exist.
+ */
+#ifndef PCI_VENDOR_ID_CSR
+#  define PCI_VENDOR_ID_CSR 0x18e5
+#endif
+
+#ifndef PCI_DEVICE_ID_JMICRON_JMB38X_SD
+#  define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381
+#endif
+
+#endif /* #ifndef __LINUX_KERNEL_COMPAT_H */
diff --git a/drivers/staging/csr/oska/list.c b/drivers/staging/csr/oska/list.c
new file mode 100644
index 0000000..b5e884e
--- /dev/null
+++ b/drivers/staging/csr/oska/list.c
@@ -0,0 +1,103 @@
+/*
+ * Operating system kernel abstraction -- linked lists.
+ *
+ * Copyright (C) 2009-2010 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+
+#include <stddef.h>
+
+#include "list.h"
+#include "util.h"
+
+/**
+ * Initialize an empty list.
+ *
+ * @ingroup list
+ */
+void os_list_init(struct os_list *list)
+{
+    list->head.next = list->head.prev = &list->head;
+}
+
+/**
+ * Is the list empty?
+ *
+ * @return true iff the list contains no nodes.
+ *
+ * @ingroup list
+ */
+int os_list_empty(struct os_list *list)
+{
+    return list->head.next == &list->head;
+}
+
+static void os_list_add(struct os_list_node *prev, struct os_list_node *new,
+                        struct os_list_node *next)
+{
+    OS_ASSERT(new->next == NULL && new->prev == NULL);
+
+    next->prev = new;
+    new->next  = next;
+    new->prev  = prev;
+    prev->next = new;
+}
+
+/**
+ * Add a node to the tail of the list.
+ *
+ * @param list the list.
+ * @param node the list node to add.
+ *
+ * @ingroup list
+ */
+void os_list_add_tail(struct os_list *list, struct os_list_node *node)
+{
+    os_list_add(list->head.prev, node, &list->head);
+}
+
+/**
+ * Remove a node from a list.
+ *
+ * @param node the node to remove.
+ *
+ * @ingroup list
+ */
+void os_list_del(struct os_list_node *node)
+{
+    node->prev->next = node->next;
+    node->next->prev = node->prev;
+
+    node->prev = node->next = NULL;
+}
+
+/**
+ * The node at the head of the list.
+ *
+ * @param list the list.
+ *
+ * @return the node at the head of the list; or os_list_end() if the
+ * list is empty.
+ *
+ * @ingroup list
+ */
+struct os_list_node *os_list_head(struct os_list *list)
+{
+    return list->head.next;
+}
+
+/**
+ * The node marking the end of a list.
+ *
+ * @param list the list.
+ *
+ * @return the node that marks the end of the list.
+ *
+ * @ingroup list
+ */
+struct os_list_node *os_list_end(struct os_list *list)
+{
+    return &list->head;
+}
diff --git a/drivers/staging/csr/oska/list.h b/drivers/staging/csr/oska/list.h
new file mode 100644
index 0000000..a69b3b7
--- /dev/null
+++ b/drivers/staging/csr/oska/list.h
@@ -0,0 +1,115 @@
+/*
+ * Operating system kernel abstraction -- linked lists.
+ *
+ * Copyright (C) 2009-2010 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LIST_H
+#define __OSKA_LIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup list Linked Lists
+ *
+ * Generic linked list implementations suitable for all platforms.
+ *
+ *   - Circular, doubly-linked list (struct os_list).
+ */
+
+/**
+ * A list node.
+ *
+ * This list node structure should be the first field within any
+ * structure that is to be stored in a list.
+ *
+ * @see struct os_list
+ * @ingroup list
+ */
+struct os_list_node {
+    /**
+     * The pointer to the previous node in the list, or os_list_end()
+     * if the end of the list has been reached.
+     */
+    struct os_list_node *prev;
+    /**
+     * The pointer to the next node in the list, or os_list_end() if
+     * the end of the list has been reached.
+     */
+    struct os_list_node *next;
+};
+
+/**
+ * A circular, doubly-linked list of nodes.
+ *
+ * Structures to be stored in a list should contains a struct
+ * os_list_node as the \e first field.
+ * \code
+ *   struct foo {
+ *      struct os_list_node node;
+ *      int bar;
+ *      ...
+ *   };
+ * \endcode
+ * Going to/from a struct foo to a list node is then simple.
+ * \code
+ *   struct os_list_node *node;
+ *   struct foo *foo;
+ *   [...]
+ *   node = &foo->node;
+ *   foo = (struct foo *)node
+ * \endcode
+ * Lists must be initialized with os_list_init() before adding nodes
+ * with os_list_add_tail().  The node at the head of the list is
+ * obtained with os_list_head().  Nodes are removed from the list with
+ * os_list_del().
+ *
+ * A list can be interated from the head to the tail using:
+ * \code
+ *   struct os_list_node *node;
+ *   for (node = os_list_head(list); node != os_list_end(list); node = node->next) {
+ *      struct foo *foo = (struct foo *)node;
+ *      ...
+ *   }
+ * \endcode
+ *
+ * In the above loop, the current list node cannot be removed (with
+ * os_list_del()).  If this is required use this form of loop:
+ * \code
+ *   struct os_list_node *node, *next;
+ *   for (node = os_list_head(list), next = node->next;
+ *        node != os_list_end(list);
+ *        node = next, next = node->next) {
+ *      struct foo *foo = (struct foo *)node;
+ *      ...
+ *      os_list_del(node);
+ *      ...
+ *   }
+ * \endcode
+ *
+ * @ingroup list
+ */
+struct os_list {
+    /**
+     * @internal
+     * The dummy node marking the end of the list.
+     */
+    struct os_list_node head;
+};
+
+void os_list_init(struct os_list *list);
+int os_list_empty(struct os_list *list);
+void os_list_add_tail(struct os_list *list, struct os_list_node *node);
+void os_list_del(struct os_list_node *node);
+struct os_list_node *os_list_head(struct os_list *list);
+struct os_list_node *os_list_end(struct os_list *list);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef __OSKA_LIST_H */
diff --git a/drivers/staging/csr/oska/mutex.h b/drivers/staging/csr/oska/mutex.h
new file mode 100644
index 0000000..9138b28
--- /dev/null
+++ b/drivers/staging/csr/oska/mutex.h
@@ -0,0 +1,42 @@
+/*
+ * OSKA Linux implementation -- mutexes
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_MUTEX_H
+#define __OSKA_LINUX_MUTEX_H
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+
+#include "kernel-compat.h"
+
+/* Real mutexes were only added to 2.6.16 so use semaphores
+   instead. */
+typedef struct semaphore os_mutex_t;
+
+static inline void os_mutex_init(os_mutex_t *mutex)
+{
+    //init_MUTEX(mutex);
+    sema_init(mutex, 1);
+}
+
+static inline void os_mutex_destroy(os_mutex_t *mutex)
+{
+    /* no op */
+}
+
+static inline void os_mutex_lock(os_mutex_t *mutex)
+{
+    down(mutex);
+}
+
+static inline void os_mutex_unlock(os_mutex_t *mutex)
+{
+    up(mutex);
+}
+
+#endif /* __OSKA_LINUX_MUTEX_H */
diff --git a/drivers/staging/csr/oska/oska_module.c b/drivers/staging/csr/oska/oska_module.c
new file mode 100644
index 0000000..da12564
--- /dev/null
+++ b/drivers/staging/csr/oska/oska_module.c
@@ -0,0 +1,21 @@
+/*
+ * Linux kernel module support.
+ *
+ * Copyright (C) 2010 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#include <linux/module.h>
+
+#include "all.h"
+#include "refcount.h"
+
+EXPORT_SYMBOL(os_refcount_init);
+EXPORT_SYMBOL(os_refcount_destroy);
+EXPORT_SYMBOL(os_refcount_get);
+EXPORT_SYMBOL(os_refcount_put);
+
+MODULE_DESCRIPTION("Operating System Kernel Abstraction");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/staging/csr/oska/print.c b/drivers/staging/csr/oska/print.c
new file mode 100644
index 0000000..5f5b263
--- /dev/null
+++ b/drivers/staging/csr/oska/print.c
@@ -0,0 +1,44 @@
+/*
+ * Linux console printing functions.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#include <linux/module.h>
+
+#include "print.h"
+
+void os_print(enum os_print_level level, const char *prefix, const char *name,
+              const char *format, ...)
+{
+    va_list va_args;
+
+    va_start(va_args, format);
+    os_vprint(level, prefix, name, format, va_args);
+    va_end(va_args);
+}
+EXPORT_SYMBOL(os_print);
+
+void os_vprint(enum os_print_level level, const char *prefix, const char *name,
+               const char *format, va_list args)
+{
+    const char *level_str[] = {
+        [OS_PRINT_ERROR]   = KERN_ERR,
+        [OS_PRINT_WARNING] = KERN_WARNING,
+        [OS_PRINT_INFO]    = KERN_INFO,
+        [OS_PRINT_DEBUG]   = KERN_DEBUG,
+    };
+    char buf[80];
+    int w = 0;
+
+    if (name) {
+        w += snprintf(buf + w, sizeof(buf) - w, "%s%s%s: ", level_str[level], prefix, name);
+    } else {
+        w += snprintf(buf + w, sizeof(buf) - w, "%s%s", level_str[level], prefix);
+    }
+    w += vsnprintf(buf + w, sizeof(buf) - w, format, args);
+    printk("%s\n", buf);
+}
+EXPORT_SYMBOL(os_vprint);
diff --git a/drivers/staging/csr/oska/print.h b/drivers/staging/csr/oska/print.h
new file mode 100644
index 0000000..f48bb83
--- /dev/null
+++ b/drivers/staging/csr/oska/print.h
@@ -0,0 +1,32 @@
+/*
+ * OSKA Linux implementation -- console printing
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_PRINT_H
+#define __OSKA_LINUX_PRINT_H
+
+#include <linux/kernel.h>
+
+/**
+ * Severity of a console or log message.
+ *
+ * @ingroup print
+ */
+enum os_print_level {
+    OS_PRINT_ERROR,
+    OS_PRINT_WARNING,
+    OS_PRINT_INFO,
+    OS_PRINT_DEBUG,
+};
+
+void os_print(enum os_print_level level, const char *prefix, const char *name,
+              const char *format, ...);
+void os_vprint(enum os_print_level level, const char *prefix, const char *name,
+               const char *format, va_list args);
+
+
+#endif /* #ifndef __OSKA_LINUX_PRINT_H */
diff --git a/drivers/staging/csr/oska/refcount.c b/drivers/staging/csr/oska/refcount.c
new file mode 100644
index 0000000..28abb64
--- /dev/null
+++ b/drivers/staging/csr/oska/refcount.c
@@ -0,0 +1,47 @@
+/*
+ * OSKA generic implementation -- reference counting.
+ *
+ * Copyright (C) 2010 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#include "refcount.h"
+#include "types.h"
+
+void os_refcount_init(os_refcount_t *refcount, os_refcount_callback_f func, void *arg)
+{
+    os_spinlock_init(&refcount->lock);
+    refcount->count = 1;
+    refcount->func  = func;
+    refcount->arg   = arg;
+}
+
+void os_refcount_destroy(os_refcount_t *refcount)
+{
+    os_spinlock_destroy(&refcount->lock);
+}
+
+void os_refcount_get(os_refcount_t *refcount)
+{
+    os_int_status_t istate;
+
+    os_spinlock_lock_intsave(&refcount->lock, &istate);
+    refcount->count++;
+    os_spinlock_unlock_intrestore(&refcount->lock, &istate);
+}
+
+void os_refcount_put(os_refcount_t *refcount)
+{
+    bool is_zero;
+    os_int_status_t istate;
+
+    os_spinlock_lock_intsave(&refcount->lock, &istate);
+    refcount->count--;
+    is_zero = refcount->count == 0;
+    os_spinlock_unlock_intrestore(&refcount->lock, &istate);
+
+    if (is_zero) {
+        refcount->func(refcount->arg);
+    }
+}
diff --git a/drivers/staging/csr/oska/refcount.h b/drivers/staging/csr/oska/refcount.h
new file mode 100644
index 0000000..741b00a
--- /dev/null
+++ b/drivers/staging/csr/oska/refcount.h
@@ -0,0 +1,86 @@
+/*
+ * Operating system kernel abstraction -- reference counting.
+ *
+ * Copyright (C) 2010 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_REFCOUNT_H
+#define __OSKA_REFCOUNT_H
+
+#include "spinlock.h"
+
+/**
+ * @defgroup refcount Reference Counting
+ *
+ * A reference count is an atomic counter.  A callback function is
+ * called whenever the count reaches zero.
+ *
+ * A generic implementation is provided that is suitable for all
+ * platforms that support the spinlock API in <oska/spinlock.h> (see
+ * \ref spinlock).
+ */
+
+typedef void (*os_refcount_callback_f)(void *arg);
+
+struct __os_refcount_impl {
+    unsigned count;
+    os_spinlock_t lock;
+    os_refcount_callback_f func;
+    void *arg;
+};
+
+/**
+ * A reference count object.
+ *
+ * @ingroup refcount
+ */
+typedef struct __os_refcount_impl os_refcount_t;
+
+/**
+ * Initialize a reference count to 1.
+ *
+ * Initialized reference counts must be destroyed by calling
+ * os_refcount_destroy().
+ *
+ * @param refcount the reference count.
+ * @param func     the function which will be called when the
+ *                 reference count reaches 0.
+ * @param arg      an argument to pass to func.
+ *
+ * @ingroup refcount
+ */
+void os_refcount_init(os_refcount_t *refcount, os_refcount_callback_f func, void *arg);
+
+/**
+ * Destroy a reference count object.
+ *
+ * @param refcount the reference count.
+ *
+ * @ingroup refcount
+ */
+void os_refcount_destroy(os_refcount_t *refcount);
+
+/**
+ * Atomically increase the reference count by 1.
+ *
+ * @param refcount the reference count.
+ *
+ * @ingroup refcount
+ */
+void os_refcount_get(os_refcount_t *refcount);
+
+/**
+ * Atomically decrease the reference count by 1.
+ *
+ * The callback function passed to the call to os_refcount_init() is
+ * called if the count was decreased to zero.
+ *
+ * @param refcount the reference count.
+ *
+ * @ingroup refcount
+ */
+void os_refcount_put(os_refcount_t *refcount);
+
+#endif /* #ifndef __OSKA_REFCOUNT_H */
diff --git a/drivers/staging/csr/oska/semaphore.h b/drivers/staging/csr/oska/semaphore.h
new file mode 100644
index 0000000..965bfe8
--- /dev/null
+++ b/drivers/staging/csr/oska/semaphore.h
@@ -0,0 +1,70 @@
+/*
+ * OSKA Linux implementation -- semaphores
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_SEMAPHORE_H
+#define __OSKA_LINUX_SEMAPHORE_H
+
+#include <linux/kernel.h>
+
+#include <linux/kernel-compat.h>
+
+typedef struct semaphore os_semaphore_t;
+
+static inline void os_semaphore_init(os_semaphore_t *sem)
+{
+    sema_init(sem, 0);
+}
+
+static inline void os_semaphore_destroy(os_semaphore_t *sem)
+{
+}
+
+static inline void os_semaphore_wait(os_semaphore_t *sem)
+{
+    down(sem);
+}
+
+/*
+ * down_timeout() was added in 2.6.26 with the generic semaphore
+ * implementation.  For now, only support it on recent kernels as
+ * semaphores may be replaced by an event API that would be
+ * implemented with wait_event(), and wait_event_timeout().
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+
+static inline int os_semaphore_wait_timed(os_semaphore_t *sem,
+                                           int time_ms)
+{
+    if (down_timeout(sem, msecs_to_jiffies(time_ms)) < 0) {
+        return -ETIMEDOUT;
+    }
+    return 0;
+}
+
+#else
+
+static inline int os_semaphore_wait_timed(os_semaphore_t *sem, int time_ms)
+{
+	unsigned long now = jiffies;
+	do{
+		if(!down_trylock(sem))
+			return 0;
+		msleep(1);
+	} while(time_before(jiffies, now + msecs_to_jiffies(time_ms)));
+
+	return -ETIMEDOUT;
+}
+
+#endif
+
+static inline void os_semaphore_post(os_semaphore_t *sem)
+{
+    up(sem);
+}
+
+#endif /* __OSKA_LINUX_SEMAPHORE_H */
diff --git a/drivers/staging/csr/oska/spinlock.h b/drivers/staging/csr/oska/spinlock.h
new file mode 100644
index 0000000..157b350
--- /dev/null
+++ b/drivers/staging/csr/oska/spinlock.h
@@ -0,0 +1,43 @@
+/*
+ * OSKA Linux implementation -- spinlocks
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_SPINLOCK_H
+#define __OSKA_LINUX_SPINLOCK_H
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+
+typedef spinlock_t os_spinlock_t;
+typedef unsigned long os_int_status_t;
+
+static inline void os_spinlock_init(os_spinlock_t *lock)
+{
+    spinlock_t *l = (spinlock_t *)lock;
+    spin_lock_init(l);
+}
+
+static inline void os_spinlock_destroy(os_spinlock_t *lock)
+{
+    /* no op */
+}
+
+static inline void os_spinlock_lock_intsave(os_spinlock_t *lock,
+					    os_int_status_t *int_state)
+{
+    spinlock_t *l = (spinlock_t *)lock;
+    spin_lock_irqsave(l, *int_state);
+}
+
+static inline void os_spinlock_unlock_intrestore(os_spinlock_t *lock,
+						 os_int_status_t *int_state)
+{
+    spinlock_t *l = (spinlock_t *)lock;
+    spin_unlock_irqrestore(l, *int_state);
+}
+
+#endif /* #ifndef __OSKA_LINUX_SPINLOCK_H */
diff --git a/drivers/staging/csr/oska/thread.c b/drivers/staging/csr/oska/thread.c
new file mode 100644
index 0000000..f680cef
--- /dev/null
+++ b/drivers/staging/csr/oska/thread.c
@@ -0,0 +1,66 @@
+/*
+ * Linux thread functions.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#include <linux/module.h>
+
+#include "thread.h"
+
+static int thread_func(void *data)
+{
+    os_thread_t *thread = data;
+
+    thread->func(thread->arg);
+
+    /*
+     * kthread_stop() cannot handle the thread exiting while
+     * kthread_should_stop() is false, so sleep until kthread_stop()
+     * wakes us up.
+     */
+    set_current_state(TASK_INTERRUPTIBLE);
+    if (!kthread_should_stop())
+        schedule();
+
+    return 0;
+}
+
+int os_thread_create(os_thread_t *thread, const char *name, void (*func)(void *), void *arg)
+{
+    thread->func = func;
+    thread->arg = arg;
+
+    thread->stop = 0;
+
+    thread->task = kthread_run(thread_func, thread, name);
+    if (IS_ERR(thread->task)) {
+        return PTR_ERR(thread->task);
+    }
+    return 0;
+}
+EXPORT_SYMBOL(os_thread_create);
+
+void os_thread_stop(os_thread_t *thread, os_event_t *evt)
+{
+    /*
+     * Stop flag must be set before the event is raised so
+     * kthread_should_stop() cannot be used.
+     */
+    thread->stop = 1;
+
+    if (evt) {
+        os_event_raise(evt, ~0);
+    }
+
+    kthread_stop(thread->task);
+}
+EXPORT_SYMBOL(os_thread_stop);
+
+int os_thread_should_stop(os_thread_t *thread)
+{
+    return thread->stop;
+}
+EXPORT_SYMBOL(os_thread_should_stop);
diff --git a/drivers/staging/csr/oska/thread.h b/drivers/staging/csr/oska/thread.h
new file mode 100644
index 0000000..8816dc8
--- /dev/null
+++ b/drivers/staging/csr/oska/thread.h
@@ -0,0 +1,39 @@
+/*
+ * OSKA Linux implementation -- threading
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_THREAD_H
+#define __OSKA_LINUX_THREAD_H
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
+#include <linux/freezer.h>
+#endif
+#include "event.h"
+
+struct os_thread_lx {
+    void (*func)(void *);
+    void *arg;
+    struct task_struct *task;
+    int stop;
+};
+
+typedef struct os_thread_lx os_thread_t;
+
+int os_thread_create(os_thread_t *thread, const char *name,
+                     void (*func)(void *), void *arg);
+void os_thread_stop(os_thread_t *thread, os_event_t *evt);
+int os_thread_should_stop(os_thread_t *thread);
+
+static inline void os_try_suspend_thread(os_thread_t *thread)
+{
+    try_to_freeze();
+}
+
+#endif /* __OSKA_LINUX_THREAD_H */
diff --git a/drivers/staging/csr/oska/time.h b/drivers/staging/csr/oska/time.h
new file mode 100644
index 0000000..d246ce9
--- /dev/null
+++ b/drivers/staging/csr/oska/time.h
@@ -0,0 +1,34 @@
+/*
+ * OSKA Linux implementation -- timing
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_TIME_H
+#define __OSKA_LINUX_TIME_H
+
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+
+static inline unsigned long os_current_time_ms(void)
+{
+    return jiffies_to_msecs(jiffies);
+}
+
+static inline void os_sleep_ms(unsigned ms)
+{
+    msleep_interruptible(ms);
+}
+
+static inline void os_delay_us(unsigned us)
+{
+    udelay(us);
+}
+
+#define os_time_after(a, b) time_after((a), (b))
+
+#endif /* __OSKA_LINUX_TIME_H */
diff --git a/drivers/staging/csr/oska/timer.c b/drivers/staging/csr/oska/timer.c
new file mode 100644
index 0000000..67d3423
--- /dev/null
+++ b/drivers/staging/csr/oska/timer.c
@@ -0,0 +1,28 @@
+/*
+ * OSKA Linux implementation -- timers.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#include <linux/module.h>
+
+#include "timer.h"
+
+static void timer_func(unsigned long data)
+{
+    os_timer_t *timer = (os_timer_t *)data;
+
+    timer->func(timer->arg);
+}
+
+void os_timer_init(os_timer_t *timer, os_timer_func_t func, void *arg)
+{
+    timer->func = func;
+    timer->arg = arg;
+    timer->timer.function = timer_func;
+    timer->timer.data = (unsigned long)timer;
+    init_timer(&timer->timer);
+}
+EXPORT_SYMBOL(os_timer_init);
diff --git a/drivers/staging/csr/oska/timer.h b/drivers/staging/csr/oska/timer.h
new file mode 100644
index 0000000..3045fc3
--- /dev/null
+++ b/drivers/staging/csr/oska/timer.h
@@ -0,0 +1,40 @@
+/*
+ * OSKA Linux implementation -- timers.
+ *
+ * Copyright (C) 2009 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_TIMER_H
+#define __OSKA_LINUX_TIMER_H
+
+#include <linux/kernel.h>
+#include <linux/timer.h>
+
+typedef void (*os_timer_func_t)(void *arg);
+
+typedef struct {
+    os_timer_func_t func;
+    void *arg;
+    struct timer_list timer;
+} os_timer_t;
+
+void os_timer_init(os_timer_t *timer, os_timer_func_t func, void *arg);
+
+static inline void os_timer_destroy(os_timer_t *timer)
+{
+    del_timer_sync(&timer->timer);
+}
+
+static inline void os_timer_set(os_timer_t *timer, unsigned long expires_ms)
+{
+    mod_timer(&timer->timer, jiffies + msecs_to_jiffies(expires_ms));
+}
+
+static inline void os_timer_cancel(os_timer_t *timer)
+{
+    del_timer(&timer->timer);
+}
+
+#endif /* #ifndef __OSKA_LINUX_TIMER_H */
diff --git a/drivers/staging/csr/oska/trace.h b/drivers/staging/csr/oska/trace.h
new file mode 100644
index 0000000..b28f37d
--- /dev/null
+++ b/drivers/staging/csr/oska/trace.h
@@ -0,0 +1,23 @@
+/*
+ * OSKA Linux implementation -- tracing messages.
+ *
+ * Copyright (C) 2009 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_TRACE_H
+#define __OSKA_LINUX_TRACE_H
+
+#include <linux/kernel.h>
+
+#ifndef OS_TRACE_PREFIX
+#  define OS_TRACE_PREFIX ""
+#endif
+
+#define os_trace_err(format, ...)  printk(KERN_ERR OS_TRACE_PREFIX format "\n", ## __VA_ARGS__)
+#define os_trace_warn(format, ...) printk(KERN_WARNING OS_TRACE_PREFIX format "\n", ##  __VA_ARGS__)
+#define os_trace_info(format, ...) printk(KERN_INFO OS_TRACE_PREFIX format "\n", ## __VA_ARGS__)
+#define os_trace_dbg(format, ...)  printk(KERN_DEBUG OS_TRACE_PREFIX format "\n", ## __VA_ARGS__)
+
+#endif /* #ifndef __OSKA_LINUX_TRACE_H */
diff --git a/drivers/staging/csr/oska/types.h b/drivers/staging/csr/oska/types.h
new file mode 100644
index 0000000..18d7c11
--- /dev/null
+++ b/drivers/staging/csr/oska/types.h
@@ -0,0 +1,14 @@
+/*
+ * OSKA Linux implementation -- types
+ *
+ * Copyright (C) 2009 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_TYPES_H
+#define __OSKA_LINUX_TYPES_H
+
+#include <linux/types.h>
+
+#endif /* #ifndef __OSKA_LINUX_TYPES_H */
diff --git a/drivers/staging/csr/oska/util.h b/drivers/staging/csr/oska/util.h
new file mode 100644
index 0000000..bf29e2d
--- /dev/null
+++ b/drivers/staging/csr/oska/util.h
@@ -0,0 +1,48 @@
+/*
+ * OSKA Linux implementation -- misc. utility functions
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef __OSKA_LINUX_UTILS_H
+#define __OSKA_LINUX_UTILS_H
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <asm/byteorder.h>
+
+#define OS_ASSERT(expr) BUG_ON(!(expr))
+
+static inline uint16_t os_le16_to_cpu(uint16_t x)
+{
+    return le16_to_cpu(x);
+}
+
+static inline uint16_t os_cpu_to_le16(uint16_t x)
+{
+    return cpu_to_le16(x);
+}
+
+static inline uint32_t os_le32_to_cpu(uint32_t x)
+{
+    return le32_to_cpu(x);
+}
+
+static inline uint32_t os_cpu_to_le32(uint32_t x)
+{
+    return cpu_to_le32(x);
+}
+
+static inline uint64_t os_le64_to_cpu(uint64_t x)
+{
+    return le64_to_cpu(x);
+}
+
+static inline uint64_t os_cpu_to_le64(uint64_t x)
+{
+    return cpu_to_le64(x);
+}
+
+#endif /* __OSKA_LINUX_UTILS_H */
diff --git a/drivers/staging/csr/putest.c b/drivers/staging/csr/putest.c
new file mode 100644
index 0000000..22614e7
--- /dev/null
+++ b/drivers/staging/csr/putest.c
@@ -0,0 +1,685 @@
+/*
+ * ***************************************************************************
+ *  FILE:     putest.c
+ *
+ *  PURPOSE:    putest related functions.
+ *
+ *  Copyright (C) 2008-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ***************************************************************************
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+
+#include "unifi_priv.h"
+#include "csr_wifi_hip_chiphelper.h"
+
+#define UNIFI_PROC_BOTH 3
+
+
+int unifi_putest_cmd52_read(unifi_priv_t *priv, unsigned char *arg)
+{
+    struct unifi_putest_cmd52 cmd52_params;
+    CsrUint8 *arg_pos;
+    unsigned int cmd_param_size;
+    int r;
+    CsrResult csrResult;
+    unsigned char ret_buffer[32];
+    CsrUint8 *ret_buffer_pos;
+    CsrUint8 retries;
+
+    arg_pos = (CsrUint8*)(((unifi_putest_command_t*)arg) + 1);
+    if (get_user(cmd_param_size, (int*)arg_pos)) {
+        unifi_error(priv,
+                    "unifi_putest_cmd52_read: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    if (cmd_param_size != sizeof(struct unifi_putest_cmd52)) {
+        unifi_error(priv,
+                    "unifi_putest_cmd52_read: cmd52 struct mismatch\n");
+        return -EINVAL;
+    }
+
+    arg_pos += sizeof(unsigned int);
+    if (copy_from_user(&cmd52_params,
+                       (void*)arg_pos,
+                       sizeof(struct unifi_putest_cmd52))) {
+        unifi_error(priv,
+                    "unifi_putest_cmd52_read: Failed to get the cmd52 params\n");
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG2, "cmd52r: func=%d addr=0x%x ",
+                cmd52_params.funcnum, cmd52_params.addr);
+
+    retries = 3;
+    CsrSdioClaim(priv->sdio);
+    do {
+        if (cmd52_params.funcnum == 0) {
+            csrResult = CsrSdioF0Read8(priv->sdio, cmd52_params.addr, &cmd52_params.data);
+        } else {
+            csrResult = CsrSdioRead8(priv->sdio, cmd52_params.addr, &cmd52_params.data);
+        }
+    } while (--retries && ((csrResult == CSR_SDIO_RESULT_CRC_ERROR) || (csrResult == CSR_SDIO_RESULT_TIMEOUT)));
+    CsrSdioRelease(priv->sdio);
+
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv,
+                    "\nunifi_putest_cmd52_read: Read8() failed (csrResult=0x%x)\n", csrResult);
+        return -EFAULT;
+    }
+    unifi_trace(priv, UDBG2, "data=%d\n", cmd52_params.data);
+
+    /* Copy the info to the out buffer */
+    *(unifi_putest_command_t*)ret_buffer = UNIFI_PUTEST_CMD52_READ;
+    ret_buffer_pos = (CsrUint8*)(((unifi_putest_command_t*)ret_buffer) + 1);
+    *(unsigned int*)ret_buffer_pos = sizeof(struct unifi_putest_cmd52);
+    ret_buffer_pos += sizeof(unsigned int);
+    memcpy(ret_buffer_pos, &cmd52_params, sizeof(struct unifi_putest_cmd52));
+    ret_buffer_pos += sizeof(struct unifi_putest_cmd52);
+
+    r = copy_to_user((void*)arg,
+                     ret_buffer,
+                     ret_buffer_pos - ret_buffer);
+    if (r) {
+        unifi_error(priv,
+                    "unifi_putest_cmd52_read: Failed to return the data\n");
+        return -EFAULT;
+    }
+
+    return 0;
+}
+
+
+int unifi_putest_cmd52_write(unifi_priv_t *priv, unsigned char *arg)
+{
+    struct unifi_putest_cmd52 cmd52_params;
+    CsrUint8 *arg_pos;
+    unsigned int cmd_param_size;
+    CsrResult csrResult;
+    CsrUint8 retries;
+
+    arg_pos = (CsrUint8*)(((unifi_putest_command_t*)arg) + 1);
+    if (get_user(cmd_param_size, (int*)arg_pos)) {
+        unifi_error(priv,
+                    "unifi_putest_cmd52_write: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    if (cmd_param_size != sizeof(struct unifi_putest_cmd52)) {
+        unifi_error(priv,
+                    "unifi_putest_cmd52_write: cmd52 struct mismatch\n");
+        return -EINVAL;
+    }
+
+    arg_pos += sizeof(unsigned int);
+    if (copy_from_user(&cmd52_params,
+                       (void*)(arg_pos),
+                       sizeof(struct unifi_putest_cmd52))) {
+        unifi_error(priv,
+                    "unifi_putest_cmd52_write: Failed to get the cmd52 params\n");
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG2, "cmd52w: func=%d addr=0x%x data=%d\n",
+                cmd52_params.funcnum, cmd52_params.addr, cmd52_params.data);
+
+    retries = 3;
+    CsrSdioClaim(priv->sdio);
+    do {
+        if (cmd52_params.funcnum == 0) {
+            csrResult = CsrSdioF0Write8(priv->sdio, cmd52_params.addr, cmd52_params.data);
+        } else {
+            csrResult = CsrSdioWrite8(priv->sdio, cmd52_params.addr, cmd52_params.data);
+        }
+    } while (--retries && ((csrResult == CSR_SDIO_RESULT_CRC_ERROR) || (csrResult == CSR_SDIO_RESULT_TIMEOUT)));
+    CsrSdioRelease(priv->sdio);
+
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv,
+                    "unifi_putest_cmd52_write: Write8() failed (csrResult=0x%x)\n", csrResult);
+        return -EFAULT;
+    }
+
+    return 0;
+}
+
+int unifi_putest_gp_read16(unifi_priv_t *priv, unsigned char *arg)
+{
+    struct unifi_putest_gp_rw16 gp_r16_params;
+    CsrUint8 *arg_pos;
+    unsigned int cmd_param_size;
+    int r;
+    CsrResult csrResult;
+    unsigned char ret_buffer[32];
+    CsrUint8 *ret_buffer_pos;
+
+    arg_pos = (CsrUint8*)(((unifi_putest_command_t*)arg) + 1);
+    if (get_user(cmd_param_size, (int*)arg_pos)) {
+        unifi_error(priv,
+                    "unifi_putest_gp_read16: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    if (cmd_param_size != sizeof(struct unifi_putest_gp_rw16)) {
+        unifi_error(priv,
+                    "unifi_putest_gp_read16: struct mismatch\n");
+        return -EINVAL;
+    }
+
+    arg_pos += sizeof(unsigned int);
+    if (copy_from_user(&gp_r16_params,
+                       (void*)arg_pos,
+                       sizeof(struct unifi_putest_gp_rw16))) {
+        unifi_error(priv,
+                    "unifi_putest_gp_read16: Failed to get the params\n");
+        return -EFAULT;
+    }
+    CsrSdioClaim(priv->sdio);
+    csrResult = unifi_card_read16(priv->card, gp_r16_params.addr, &gp_r16_params.data);
+    CsrSdioRelease(priv->sdio);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv,
+                    "unifi_putest_gp_read16: unifi_card_read16() GP=0x%x failed (csrResult=0x%x)\n", gp_r16_params.addr, csrResult);
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG2, "gp_r16: GP=0x%08x, data=0x%04x\n", gp_r16_params.addr, gp_r16_params.data);
+
+    /* Copy the info to the out buffer */
+    *(unifi_putest_command_t*)ret_buffer = UNIFI_PUTEST_GP_READ16;
+    ret_buffer_pos = (CsrUint8*)(((unifi_putest_command_t*)ret_buffer) + 1);
+    *(unsigned int*)ret_buffer_pos = sizeof(struct unifi_putest_gp_rw16);
+    ret_buffer_pos += sizeof(unsigned int);
+    memcpy(ret_buffer_pos, &gp_r16_params, sizeof(struct unifi_putest_gp_rw16));
+    ret_buffer_pos += sizeof(struct unifi_putest_gp_rw16);
+
+    r = copy_to_user((void*)arg,
+                     ret_buffer,
+                     ret_buffer_pos - ret_buffer);
+    if (r) {
+        unifi_error(priv,
+                    "unifi_putest_gp_read16: Failed to return the data\n");
+        return -EFAULT;
+    }
+
+    return 0;
+}
+
+int unifi_putest_gp_write16(unifi_priv_t *priv, unsigned char *arg)
+{
+    struct unifi_putest_gp_rw16 gp_w16_params;
+    CsrUint8 *arg_pos;
+    unsigned int cmd_param_size;
+    CsrResult csrResult;
+
+    arg_pos = (CsrUint8*)(((unifi_putest_command_t*)arg) + 1);
+    if (get_user(cmd_param_size, (int*)arg_pos)) {
+        unifi_error(priv,
+                    "unifi_putest_gp_write16: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    if (cmd_param_size != sizeof(struct unifi_putest_gp_rw16)) {
+        unifi_error(priv,
+                    "unifi_putest_gp_write16: struct mismatch\n");
+        return -EINVAL;
+    }
+
+    arg_pos += sizeof(unsigned int);
+    if (copy_from_user(&gp_w16_params,
+                       (void*)(arg_pos),
+                       sizeof(struct unifi_putest_gp_rw16))) {
+        unifi_error(priv,
+                    "unifi_putest_gp_write16: Failed to get the params\n");
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG2, "gp_w16: GP=0x%08x, data=0x%04x\n", gp_w16_params.addr, gp_w16_params.data);
+    CsrSdioClaim(priv->sdio);
+    csrResult = unifi_card_write16(priv->card, gp_w16_params.addr, gp_w16_params.data);
+    CsrSdioRelease(priv->sdio);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv,
+                    "unifi_putest_gp_write16: unifi_card_write16() GP=%x failed (csrResult=0x%x)\n", gp_w16_params.addr, csrResult);
+        return -EFAULT;
+    }
+
+    return 0;
+}
+
+int unifi_putest_set_sdio_clock(unifi_priv_t *priv, unsigned char *arg)
+{
+    int sdio_clock_speed;
+    CsrResult csrResult;
+
+    if (get_user(sdio_clock_speed, (int*)(((unifi_putest_command_t*)arg) + 1))) {
+        unifi_error(priv,
+                    "unifi_putest_set_sdio_clock: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG2, "set sdio clock: %d KHz\n", sdio_clock_speed);
+
+    CsrSdioClaim(priv->sdio);
+    csrResult = CsrSdioMaxBusClockFrequencySet(priv->sdio, sdio_clock_speed * 1000);
+    CsrSdioRelease(priv->sdio);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv,
+                    "unifi_putest_set_sdio_clock: Set clock failed (csrResult=0x%x)\n", csrResult);
+        return -EFAULT;
+    }
+
+    return 0;
+}
+
+
+int unifi_putest_start(unifi_priv_t *priv, unsigned char *arg)
+{
+    int r;
+    CsrResult csrResult;
+    int already_in_test = priv->ptest_mode;
+
+    /* Ensure that sme_sys_suspend() doesn't power down the chip because:
+     *  1) Power is needed anyway for ptest.
+     *  2) The app code uses the START ioctl as a reset, so it gets called
+     *     multiple times. If the app stops the XAPs, but the power_down/up
+     *     sequence doesn't actually power down the chip, there can be problems
+     *     resetting, because part of the power_up sequence disables function 1
+     */
+    priv->ptest_mode = 1;
+
+    /* Suspend the SME and UniFi */
+    if (priv->sme_cli) {
+        r = sme_sys_suspend(priv);
+        if (r) {
+            unifi_error(priv,
+                        "unifi_putest_start: failed to suspend UniFi\n");
+            return r;
+        }
+    }
+
+    /* Application may have stopped the XAPs, but they are needed for reset */
+    if (already_in_test) {
+        CsrSdioClaim(priv->sdio);
+        csrResult = unifi_start_processors(priv->card);
+        CsrSdioRelease(priv->sdio);
+        if (csrResult != CSR_RESULT_SUCCESS) {
+            unifi_error(priv, "Failed to start XAPs. Hard reset required.\n");
+        }
+    } else {
+        /* Ensure chip is powered for the case where there's no unifi_helper */
+        CsrSdioClaim(priv->sdio);
+        csrResult = CsrSdioPowerOn(priv->sdio);
+        CsrSdioRelease(priv->sdio);
+        if (csrResult != CSR_RESULT_SUCCESS) {
+            unifi_error(priv, "CsrSdioPowerOn csrResult = %d\n", csrResult);
+        }
+    }
+    CsrSdioClaim(priv->sdio);
+    csrResult = unifi_init(priv->card);
+    CsrSdioRelease(priv->sdio);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv,
+                    "unifi_putest_start: failed to init UniFi\n");
+        return CsrHipResultToStatus(csrResult);
+    }
+
+    return 0;
+}
+
+
+int unifi_putest_stop(unifi_priv_t *priv, unsigned char *arg)
+{
+    int r = 0;
+    CsrResult csrResult;
+
+    /* Application may have stopped the XAPs, but they are needed for reset */
+    CsrSdioClaim(priv->sdio);
+    csrResult = unifi_start_processors(priv->card);
+    CsrSdioRelease(priv->sdio);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv, "Failed to start XAPs. Hard reset required.\n");
+    }
+
+    /* PUTEST_STOP is also used to resume the XAPs after SME coredump.
+     * Don't power off the chip, leave that to the normal wifi-off which is
+     * about to carry on. No need to resume the SME either, as it wasn't suspended.
+     */
+    if (priv->coredump_mode) {
+        priv->coredump_mode = 0;
+        return 0;
+    }
+
+    /* At this point function 1 is enabled and the XAPs are running, so it is
+     * safe to let the card power down. Power is restored later, asynchronously,
+     * during the wifi_on requested by the SME.
+     */
+    CsrSdioClaim(priv->sdio);
+    CsrSdioPowerOff(priv->sdio);
+    CsrSdioRelease(priv->sdio);
+
+    /* Resume the SME and UniFi */
+    if (priv->sme_cli) {
+        r = sme_sys_resume(priv);
+        if (r) {
+            unifi_error(priv,
+                        "unifi_putest_stop: failed to resume SME\n");
+        }
+    }
+    priv->ptest_mode = 0;
+
+    return r;
+}
+
+
+int unifi_putest_dl_fw(unifi_priv_t *priv, unsigned char *arg)
+{
+#define UF_PUTEST_MAX_FW_FILE_NAME      16
+#define UNIFI_MAX_FW_PATH_LEN           32
+    unsigned int fw_name_length;
+    unsigned char fw_name[UF_PUTEST_MAX_FW_FILE_NAME+1];
+    unsigned char *name_buffer;
+    int postfix;
+    char fw_path[UNIFI_MAX_FW_PATH_LEN];
+    const struct firmware *fw_entry;
+    struct dlpriv temp_fw_sta;
+    int r;
+    CsrResult csrResult;
+
+    /* Get the f/w file name length */
+    if (get_user(fw_name_length, (unsigned int*)(((unifi_putest_command_t*)arg) + 1))) {
+        unifi_error(priv,
+                    "unifi_putest_dl_fw: Failed to get the length argument\n");
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG2, "unifi_putest_dl_fw: file name size = %d\n", fw_name_length);
+
+    /* Sanity check for the f/w file name length */
+    if (fw_name_length > UF_PUTEST_MAX_FW_FILE_NAME) {
+        unifi_error(priv,
+                    "unifi_putest_dl_fw: F/W file name is too long\n");
+        return -EINVAL;
+    }
+
+    /* Get the f/w file name */
+    name_buffer = ((unsigned char*)arg) + sizeof(unifi_putest_command_t) + sizeof(unsigned int);
+    if (copy_from_user(fw_name, (void*)name_buffer, fw_name_length)) {
+        unifi_error(priv, "unifi_putest_dl_fw: Failed to get the file name\n");
+        return -EFAULT;
+    }
+    fw_name[fw_name_length] = '\0';
+    unifi_trace(priv, UDBG2, "unifi_putest_dl_fw: file = %s\n", fw_name);
+
+    /* Keep the existing f/w to a temp, we need to restore it later */
+    temp_fw_sta = priv->fw_sta;
+
+    /* Get the putest f/w */
+    postfix = priv->instance;
+    scnprintf(fw_path, UNIFI_MAX_FW_PATH_LEN, "unifi-sdio-%d/%s",
+              postfix, fw_name);
+    r = request_firmware(&fw_entry, fw_path, priv->unifi_device);
+    if (r == 0) {
+        priv->fw_sta.fw_desc = (void *)fw_entry;
+        priv->fw_sta.dl_data = fw_entry->data;
+        priv->fw_sta.dl_len = fw_entry->size;
+    } else {
+        unifi_error(priv, "Firmware file not available\n");
+        return -EINVAL;
+    }
+
+    /* Application may have stopped the XAPs, but they are needed for reset */
+    CsrSdioClaim(priv->sdio);
+    csrResult = unifi_start_processors(priv->card);
+    CsrSdioRelease(priv->sdio);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv, "Failed to start XAPs. Hard reset required.\n");
+    }
+
+    /* Download the f/w. On UF6xxx this will cause the f/w file to convert
+     * into patch format and download via the ROM boot loader
+     */
+    CsrSdioClaim(priv->sdio);
+    csrResult = unifi_download(priv->card, 0x0c00);
+    CsrSdioRelease(priv->sdio);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv,
+                    "unifi_putest_dl_fw: failed to download the f/w\n");
+        goto free_fw;
+    }
+
+    /* Free the putest f/w... */
+free_fw:
+    uf_release_firmware(priv, &priv->fw_sta);
+    /* ... and restore the original f/w */
+    priv->fw_sta = temp_fw_sta;
+
+    return CsrHipResultToStatus(csrResult);
+}
+
+
+int unifi_putest_dl_fw_buff(unifi_priv_t *priv, unsigned char *arg)
+{
+    unsigned int fw_length;
+    unsigned char *fw_buf = NULL;
+    unsigned char *fw_user_ptr;
+    struct dlpriv temp_fw_sta;
+    CsrResult csrResult;
+
+    /* Get the f/w buffer length */
+    if (get_user(fw_length, (unsigned int*)(((unifi_putest_command_t*)arg) + 1))) {
+        unifi_error(priv,
+                    "unifi_putest_dl_fw_buff: Failed to get the length arg\n");
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG2, "unifi_putest_dl_fw_buff: size = %d\n", fw_length);
+
+    /* Sanity check for the buffer length */
+    if (fw_length == 0 || fw_length > 0xfffffff) {
+        unifi_error(priv,
+                    "unifi_putest_dl_fw_buff: buffer length bad %u\n", fw_length);
+        return -EINVAL;
+    }
+
+    /* Buffer for kernel copy of the f/w image */
+    fw_buf = CsrPmemAlloc(fw_length);
+    if (!fw_buf) {
+        unifi_error(priv, "unifi_putest_dl_fw_buff: malloc fail\n");
+        return -ENOMEM;
+    }
+
+    /* Get the f/w image */
+    fw_user_ptr = ((unsigned char*)arg) + sizeof(unifi_putest_command_t) + sizeof(unsigned int);
+    if (copy_from_user(fw_buf, (void*)fw_user_ptr, fw_length)) {
+        unifi_error(priv, "unifi_putest_dl_fw_buff: Failed to get the buffer\n");
+        CsrPmemFree(fw_buf);
+        return -EFAULT;
+    }
+
+    /* Save the existing f/w to a temp, we need to restore it later */
+    temp_fw_sta = priv->fw_sta;
+
+    /* Setting fw_desc NULL indicates to the core that no f/w file was loaded
+     * via the kernel request_firmware() mechanism. This indicates to the core
+     * that it shouldn't call release_firmware() after the download is done.
+     */
+    priv->fw_sta.fw_desc = NULL;            /* No OS f/w resource */
+    priv->fw_sta.dl_data = fw_buf;
+    priv->fw_sta.dl_len = fw_length;
+
+    /* Application may have stopped the XAPs, but they are needed for reset */
+    CsrSdioClaim(priv->sdio);
+    csrResult = unifi_start_processors(priv->card);
+    CsrSdioRelease(priv->sdio);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv, "Failed to start XAPs. Hard reset required.\n");
+    }
+
+    /* Download the f/w. On UF6xxx this will cause the f/w file to convert
+     * into patch format and download via the ROM boot loader
+     */
+    CsrSdioClaim(priv->sdio);
+    csrResult = unifi_download(priv->card, 0x0c00);
+    CsrSdioRelease(priv->sdio);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv,
+                    "unifi_putest_dl_fw_buff: failed to download the f/w\n");
+        goto free_fw;
+    }
+
+free_fw:
+    /* Finished with the putest f/w, so restore the station f/w */
+    priv->fw_sta = temp_fw_sta;
+    CsrPmemFree(fw_buf);
+
+    return CsrHipResultToStatus(csrResult);
+}
+
+
+int unifi_putest_coredump_prepare(unifi_priv_t *priv, unsigned char *arg)
+{
+    CsrUint16 data_u16;
+    CsrInt32 i;
+    CsrResult r;
+
+    unifi_info(priv, "Preparing for SDIO coredump\n");
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE)
+    unifi_debug_buf_dump();
+#endif
+
+    /* Sanity check that userspace hasn't called a PUTEST_START, because that
+     * would have reset UniFi, potentially power cycling it and losing context
+     */
+    if (priv->ptest_mode) {
+        unifi_error(priv, "PUTEST_START shouldn't be used before a coredump\n");
+    }
+
+    /* Flag that the userspace has requested coredump. Even if this preparation
+     * fails, the SME will call PUTEST_STOP to tidy up.
+     */
+    priv->coredump_mode = 1;
+
+    for (i = 0; i < 3; i++) {
+        CsrSdioClaim(priv->sdio);
+        r = CsrSdioRead16(priv->sdio, CHIP_HELPER_UNIFI_GBL_CHIP_VERSION*2, &data_u16);
+        CsrSdioRelease(priv->sdio);
+        if (r != CSR_RESULT_SUCCESS) {
+            unifi_info(priv, "Failed to read chip version! Try %d\n", i);
+
+            /* First try, re-enable function which may have been disabled by f/w panic */
+            if (i == 0) {
+                unifi_info(priv, "Try function enable\n");
+                CsrSdioClaim(priv->sdio);
+                r = CsrSdioFunctionEnable(priv->sdio);
+                CsrSdioRelease(priv->sdio);
+                if (r != CSR_RESULT_SUCCESS) {
+                    unifi_error(priv, "CsrSdioFunctionEnable failed %d\n", r);
+                }
+                continue;
+            }
+
+            /* Subsequent tries, reset */
+
+            /* Set clock speed low */
+            CsrSdioClaim(priv->sdio);
+            r = CsrSdioMaxBusClockFrequencySet(priv->sdio, UNIFI_SDIO_CLOCK_SAFE_HZ);
+            CsrSdioRelease(priv->sdio);
+            if (r != CSR_RESULT_SUCCESS) {
+                unifi_error(priv, "CsrSdioMaxBusClockFrequencySet() failed %d\n", r);
+            }
+
+            /* Card software reset */
+            CsrSdioClaim(priv->sdio);
+            r = unifi_card_hard_reset(priv->card);
+            CsrSdioRelease(priv->sdio);
+            if (r != CSR_RESULT_SUCCESS) {
+                unifi_error(priv, "unifi_card_hard_reset() failed %d\n", r);
+            }
+        } else {
+            unifi_info(priv, "Read chip version of 0x%04x\n", data_u16);
+            break;
+        }
+    }
+
+    if (r != CSR_RESULT_SUCCESS) {
+        unifi_error(priv, "Failed to prepare chip\n");
+        return -EIO;
+    }
+
+    /* Stop the XAPs for coredump. The PUTEST_STOP must be called, e.g. at
+     * Raw SDIO deinit, to resume them.
+     */
+    CsrSdioClaim(priv->sdio);
+    r = unifi_card_stop_processor(priv->card, UNIFI_PROC_BOTH);
+    CsrSdioRelease(priv->sdio);
+    if (r != CSR_RESULT_SUCCESS) {
+        unifi_error(priv, "Failed to stop processors\n");
+    }
+
+    return 0;
+}
+
+int unifi_putest_cmd52_block_read(unifi_priv_t *priv, unsigned char *arg)
+{
+    struct unifi_putest_block_cmd52_r block_cmd52;
+    CsrUint8 *arg_pos;
+    unsigned int cmd_param_size;
+    CsrResult r;
+    CsrUint8 *block_local_buffer;
+
+    arg_pos = (CsrUint8*)(((unifi_putest_command_t*)arg) + 1);
+    if (get_user(cmd_param_size, (int*)arg_pos)) {
+        unifi_error(priv,
+                    "cmd52r_block: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    if (cmd_param_size != sizeof(struct unifi_putest_block_cmd52_r)) {
+        unifi_error(priv,
+                    "cmd52r_block: cmd52 struct mismatch\n");
+        return -EINVAL;
+    }
+
+    arg_pos += sizeof(unsigned int);
+    if (copy_from_user(&block_cmd52,
+                       (void*)arg_pos,
+                       sizeof(struct unifi_putest_block_cmd52_r))) {
+        unifi_error(priv,
+                    "cmd52r_block: Failed to get the cmd52 params\n");
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG2, "cmd52r_block: func=%d addr=0x%x len=0x%x ",
+                block_cmd52.funcnum, block_cmd52.addr, block_cmd52.length);
+
+    block_local_buffer = vmalloc(block_cmd52.length);
+    if (block_local_buffer == NULL) {
+        unifi_error(priv, "cmd52r_block: Failed to allocate buffer\n");
+        return -ENOMEM;
+    }
+
+    CsrSdioClaim(priv->sdio);
+    r = unifi_card_readn(priv->card, block_cmd52.addr, block_local_buffer, block_cmd52.length);
+    CsrSdioRelease(priv->sdio);
+    if (r != CSR_RESULT_SUCCESS) {
+        unifi_error(priv, "cmd52r_block: unifi_readn failed\n");
+        return -EIO;
+    }
+
+    if (copy_to_user((void*)block_cmd52.data,
+                     block_local_buffer,
+                     block_cmd52.length)) {
+        unifi_error(priv,
+                    "cmd52r_block: Failed to return the data\n");
+        return -EFAULT;
+    }
+
+    return 0;
+}
diff --git a/drivers/staging/csr/sdio_emb.c b/drivers/staging/csr/sdio_emb.c
new file mode 100644
index 0000000..b6a7d6f
--- /dev/null
+++ b/drivers/staging/csr/sdio_emb.c
@@ -0,0 +1,891 @@
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * FILE: sdio_emb.c
+ *
+ * PURPOSE: Driver instantiation and deletion for SDIO on Linux.
+ *
+ *      This file brings together the SDIO bus interface, the UniFi
+ *      driver core and the Linux net_device stack.
+ *
+ * Copyright (C) 2007-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include "csr_wifi_hip_unifi.h"
+#include "unifi_priv.h"
+
+#include "sdioemb/sdio_api.h"
+
+/* The function driver context, i.e the UniFi Driver */
+static CsrSdioFunctionDriver *sdio_func_drv;
+
+#ifdef CONFIG_PM
+static int uf_sdio_emb_power_event(struct notifier_block *this, unsigned long event, void *ptr);
+#endif
+
+/* The Android wakelock is here for completeness. Typically the MMC driver is used
+ * instead of sdioemb, but sdioemb may be used for CSPI.
+ */
+#ifdef ANDROID_BUILD
+struct wake_lock unifi_sdio_wake_lock; /* wakelock to prevent suspend while resuming */
+#endif
+
+/* sdioemb driver uses POSIX error codes */
+static CsrResult
+ConvertSdioToCsrSdioResult(int r)
+{
+    CsrResult csrResult = CSR_RESULT_FAILURE;
+
+    switch (r) {
+        case 0:
+            csrResult = CSR_RESULT_SUCCESS;
+            break;
+        case -EIO:
+            csrResult = CSR_SDIO_RESULT_CRC_ERROR;
+            break;
+            /* Timeout errors */
+        case -ETIMEDOUT:
+        case -EBUSY:
+            csrResult = CSR_SDIO_RESULT_TIMEOUT;
+            break;
+        case -ENODEV:
+        case -ENOMEDIUM:
+            csrResult = CSR_SDIO_RESULT_NO_DEVICE;
+            break;
+        case -EINVAL:
+            csrResult = CSR_SDIO_RESULT_INVALID_VALUE;
+            break;
+        case -ENOMEM:
+        case -ENOSYS:
+        case -EILSEQ:
+        case -ERANGE:
+        case -ENXIO:
+            csrResult = CSR_RESULT_FAILURE;
+            break;
+        default:
+            unifi_warning(NULL, "Unrecognised SDIO error code: %d\n", r);
+            break;
+    }
+
+    return csrResult;
+}
+
+
+CsrResult
+CsrSdioRead8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int err;
+    err = sdioemb_read8(fdev, address, data);
+    if (err) {
+        return ConvertSdioToCsrSdioResult(err);
+    }
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioRead8() */
+
+CsrResult
+CsrSdioWrite8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int err;
+    err = sdioemb_write8(fdev, address, data);
+    if (err) {
+        return ConvertSdioToCsrSdioResult(err);
+    }
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioWrite8() */
+
+CsrResult
+CsrSdioRead16(CsrSdioFunction *function, CsrUint32 address, CsrUint16 *data)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int r;
+
+    r = sdioemb_read16(fdev, address, data);
+    if (r) {
+        return ConvertSdioToCsrSdioResult(r);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioRead16() */
+
+CsrResult
+CsrSdioWrite16(CsrSdioFunction *function, CsrUint32 address, CsrUint16 data)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int r;
+
+    r = sdioemb_write16(fdev, address, data);
+    if (r) {
+        return ConvertSdioToCsrSdioResult(r);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioWrite16() */
+
+
+CsrResult
+CsrSdioF0Read8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int err;
+    err = sdioemb_f0_read8(fdev, address, data);
+    if (err) {
+        return ConvertSdioToCsrSdioResult(err);
+    }
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioF0Read8() */
+
+
+CsrResult
+CsrSdioF0Write8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int err;
+    err = sdioemb_f0_write8(fdev, address, data);
+    if (err) {
+        return ConvertSdioToCsrSdioResult(err);
+    }
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioF0Write8() */
+
+CsrResult
+CsrSdioRead(CsrSdioFunction *function, CsrUint32 address, void *data, CsrUint32 length)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int err;
+    err = sdioemb_read(fdev, address, data, length);
+    if (err) {
+        return ConvertSdioToCsrSdioResult(err);
+    }
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioRead() */
+
+CsrResult
+CsrSdioWrite(CsrSdioFunction *function, CsrUint32 address, const void *data, CsrUint32 length)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int err;
+    err = sdioemb_write(fdev, address, data, length);
+    if (err) {
+        return ConvertSdioToCsrSdioResult(err);
+    }
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioWrite() */
+
+
+CsrResult
+CsrSdioBlockSizeSet(CsrSdioFunction *function, CsrUint16 blockSize)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int r = 0;
+
+    /* Module parameter overrides */
+    if (sdio_block_size > -1) {
+        blockSize = sdio_block_size;
+    }
+
+    unifi_trace(NULL, UDBG1, "Set SDIO function block size to %d\n",
+            blockSize);
+
+    r = sdioemb_set_block_size(fdev, blockSize);
+    if (r) {
+        unifi_error(NULL, "Error %d setting block size\n", r);
+    }
+
+    /* Determine the achieved block size to report to the core */
+    function->blockSize = fdev->blocksize;
+
+    return ConvertSdioToCsrSdioResult(r);
+} /* CsrSdioBlockSizeSet() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioMaxBusClockFrequencySet
+ *
+ *      Set the maximum SDIO bus clock speed to use.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ *      maxFrequency         maximum clock speed in Hz
+ *
+ *  Returns:
+ *      an error code.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioMaxBusClockFrequencySet(CsrSdioFunction *function, CsrUint32 maxFrequency)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    CsrUint32 max_khz = maxFrequency/1000;
+
+    if (!max_khz || max_khz > sdio_clock) {
+        max_khz = sdio_clock;
+    }
+    unifi_trace(NULL, UDBG1, "Setting SDIO bus clock to %d kHz\n", max_khz);
+    sdioemb_set_max_bus_freq(fdev, 1000 * max_khz);
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioMaxBusClockFrequencySet() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioInterruptEnable
+ *  CsrSdioInterruptDisable
+ *
+ *      Enable or disable the SDIO interrupt.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ *
+ *  Returns:
+ *      Zero on success or a UniFi driver error code.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioInterruptEnable(CsrSdioFunction *function)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int r;
+
+    r = sdioemb_interrupt_enable(fdev);
+    if (r) {
+        return ConvertSdioToCsrSdioResult(r);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioInterruptEnable() */
+
+CsrResult
+CsrSdioInterruptDisable(CsrSdioFunction *function)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int r;
+
+    r = sdioemb_interrupt_disable(fdev);
+    if (r) {
+        return ConvertSdioToCsrSdioResult(r);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioInterruptDisable() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioInterruptAcknowledge
+ *
+ *      Acknowledge an SDIO interrupt.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ *
+ *  Returns:
+ *      Zero on success or a UniFi driver error code.
+ * ---------------------------------------------------------------------------
+ */
+void CsrSdioInterruptAcknowledge(CsrSdioFunction *function)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+
+    sdioemb_interrupt_acknowledge(fdev);
+} /* CsrSdioInterruptAcknowledge() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioFunctionEnable
+ *
+ *      Enable i/o on this function.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ *
+ * Returns:
+ *      UniFi driver error code.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioFunctionEnable(CsrSdioFunction *function)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int r;
+
+    /* Enable UniFi function (the 802.11 part). */
+    r = sdioemb_enable_function(fdev);
+    if (r) {
+        unifi_error(NULL, "Failed to enable SDIO function %d\n", fdev->function);
+        return ConvertSdioToCsrSdioResult(r);
+    }
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioFunctionEnable() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioFunctionDisable
+ *
+ *      Disable i/o on this function.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ *
+ * Returns:
+ *      UniFi driver error code.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioFunctionDisable(CsrSdioFunction *function)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int r;
+
+    /* Disable UniFi function (the 802.11 part). */
+    r = sdioemb_disable_function(fdev);
+    if (r) {
+        unifi_error(NULL, "Failed to disable SDIO function %d\n", fdev->function);
+        return ConvertSdioToCsrSdioResult(r);
+    }
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioFunctionDisable() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioFunctionActive
+ *
+ *      No-op as the bus goes to an active state at the start of every
+ *      command.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ * ---------------------------------------------------------------------------
+ */
+void
+CsrSdioFunctionActive(CsrSdioFunction *function)
+{
+} /* CsrSdioFunctionActive() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioFunctionIdle
+ *
+ *      Set the function as idle.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ * ---------------------------------------------------------------------------
+ */
+void
+CsrSdioFunctionIdle(CsrSdioFunction *function)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+
+    sdioemb_idle_function(fdev);
+} /* CsrSdioFunctionIdle() */
+
+
+CsrResult
+CsrSdioPowerOn(CsrSdioFunction *function)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+
+    if (disable_power_control != 1) {
+        sdioemb_power_on(fdev);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioPowerOn() */
+
+void
+CsrSdioPowerOff(CsrSdioFunction *function)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    if (disable_power_control != 1) {
+        sdioemb_power_off(fdev);
+    }
+} /* CsrSdioPowerOff() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioHardReset
+ *
+ *      Hard Resets UniFi is possible.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ *
+ * Returns:
+ *      1       if the SDIO driver is not capable of doing a hard reset.
+ *      0       if a hard reset was successfully performed.
+ *      -CSR_EIO if an I/O error occured while re-initializing the card.
+ *              This is a fatal, non-recoverable error.
+ *      -CSR_ENODEV if the card is no longer present.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioHardReset(CsrSdioFunction *function)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+    int r;
+
+    /* Hard reset can be disabled by a module parameter */
+    r = 1;
+    if (disable_hw_reset != 1) {
+        r = sdioemb_hard_reset(fdev); /* may return 1 if can't reset */
+        if (r < 0) {
+            return ConvertSdioToCsrSdioResult(r);   /* fatal error */
+        }
+    }
+
+    /* Set the SDIO bus width after a hard reset */
+    if (buswidth == 1) {
+        unifi_info(NULL, "Setting SDIO bus width to 1\n");
+        sdioemb_set_bus_width(fdev, buswidth);
+    } else if (buswidth == 4) {
+        unifi_info(NULL, "Setting SDIO bus width to 4\n");
+        sdioemb_set_bus_width(fdev, buswidth);
+    }
+
+    if(r == 1)
+    {
+        return CSR_SDIO_RESULT_NOT_RESET;
+    }
+
+    return ConvertSdioToCsrSdioResult(r);
+
+} /* CsrSdioHardReset() */
+
+
+int csr_sdio_linux_remove_irq(CsrSdioFunction *function)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+
+    return sdioemb_interrupt_disable(fdev);
+}
+
+int csr_sdio_linux_install_irq(CsrSdioFunction *function)
+{
+    struct sdioemb_dev *fdev = (struct sdioemb_dev *)function->priv;
+
+    return sdioemb_interrupt_enable(fdev);
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_glue_sdio_int_handler
+ *      Card interrupt callback.
+ *
+ * Arguments:
+ *      fdev            SDIO context pointer
+ *
+ * Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void
+uf_glue_sdio_int_handler(struct sdioemb_dev *fdev)
+{
+    CsrSdioFunction *sdio_ctx = fdev->drv_data;
+    CsrSdioInterruptDsrCallback func_dsr_callback;
+
+    /* If the function driver has registered a handler, call it */
+    if (sdio_func_drv && sdio_func_drv->intr) {
+        /* The function driver may return a DSR. */
+        func_dsr_callback = sdio_func_drv->intr(sdio_ctx);
+        /* If it did return a DSR handle, call it */
+        if (func_dsr_callback) {
+            func_dsr_callback(sdio_ctx);
+        }
+    }
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * Power Management notifier
+ */
+struct uf_sdio_emb_pm_notifier
+{
+    struct list_head list;
+
+    CsrSdioFunction *sdio_ctx;
+    struct notifier_block pm_notifier;
+};
+
+/* PM notifier list head */
+static struct uf_sdio_emb_pm_notifier uf_sdio_emb_pm_notifiers = {
+    .sdio_ctx = NULL,
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * uf_sdio_emb_register_pm_notifier
+ * uf_sdio_emb_unregister_pm_notifier
+ *
+ *      Register/unregister for power management events. A list is used to
+ *	allow multiple card instances to be supported.
+ *
+ *  Arguments:
+ *      sdio_ctx - CSR SDIO context to associate PM notifier to
+ *
+ *  Returns:
+ *      Register function returns NULL on error
+ * ---------------------------------------------------------------------------
+ */
+static struct uf_sdio_emb_pm_notifier *
+uf_sdio_emb_register_pm_notifier(CsrSdioFunction *sdio_ctx)
+{
+    /* Allocate notifier context for this card instance */
+    struct uf_sdio_emb_pm_notifier *notifier_ctx = kmalloc(sizeof(struct uf_sdio_emb_pm_notifier), GFP_KERNEL);
+
+    if (notifier_ctx)
+    {
+        notifier_ctx->sdio_ctx = sdio_ctx;
+        notifier_ctx->pm_notifier.notifier_call = uf_sdio_emb_power_event;
+
+        list_add(&notifier_ctx->list, &uf_sdio_emb_pm_notifiers.list);
+
+        if (register_pm_notifier(&notifier_ctx->pm_notifier)) {
+            printk(KERN_ERR "unifi: register_pm_notifier failed\n");
+        }
+    }
+
+    return notifier_ctx;
+}
+
+static void
+uf_sdio_emb_unregister_pm_notifier(CsrSdioFunction *sdio_ctx)
+{
+    struct uf_sdio_emb_pm_notifier *notifier_ctx;
+    struct list_head *node, *q;
+
+    list_for_each_safe(node, q, &uf_sdio_emb_pm_notifiers.list) {
+        notifier_ctx = list_entry(node, struct uf_sdio_emb_pm_notifier, list);
+
+        /* If it matches, unregister and free the notifier context */
+        if (notifier_ctx && notifier_ctx->sdio_ctx == sdio_ctx)
+        {
+            if (unregister_pm_notifier(&notifier_ctx->pm_notifier)) {
+                printk(KERN_ERR "unifi: unregister_pm_notifier failed\n");
+            }
+
+            /* Remove from list */
+            notifier_ctx->sdio_ctx = NULL;
+            list_del(node);
+            kfree(notifier_ctx);
+        }
+    }
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * uf_sdio_emb_power_event
+ *
+ *      Handler for power management events.
+ *
+ *      We need to handle suspend/resume events while the userspace is unsuspended
+ *      to allow the SME to run its suspend/resume state machines.
+ *
+ *  Arguments:
+ *      event   event ID
+ *
+ *  Returns:
+ *      Status of the event handling
+ * ---------------------------------------------------------------------------
+ */
+static int
+uf_sdio_emb_power_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+    struct uf_sdio_emb_pm_notifier *notifier_ctx = container_of(this,
+                                                                struct uf_sdio_emb_pm_notifier,
+                                                                pm_notifier);
+
+    /* Call the CSR SDIO function driver's suspend/resume method
+     * while the userspace is unsuspended.
+     */
+    switch (event) {
+        case PM_POST_HIBERNATION:
+        case PM_POST_SUSPEND:
+            printk(KERN_INFO "%s:%d resume\n", __FUNCTION__, __LINE__ );
+            if (sdio_func_drv && sdio_func_drv->resume) {
+                sdio_func_drv->resume(notifier_ctx->sdio_ctx);
+            }
+            break;
+
+        case PM_HIBERNATION_PREPARE:
+        case PM_SUSPEND_PREPARE:
+            printk(KERN_INFO "%s:%d suspend\n", __FUNCTION__, __LINE__ );
+            if (sdio_func_drv && sdio_func_drv->suspend) {
+                sdio_func_drv->suspend(notifier_ctx->sdio_ctx);
+            }
+            break;
+    }
+    return NOTIFY_DONE;
+}
+
+#endif /* CONFIG_PM */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_glue_sdio_probe
+ *
+ *      Card insert callback.
+ *
+ * Arguments:
+ *      fdev            SDIO context pointer
+ *
+ * Returns:
+ *      UniFi driver error code.
+ * ---------------------------------------------------------------------------
+ */
+static int
+uf_glue_sdio_probe(struct sdioemb_dev *fdev)
+{
+    CsrSdioFunction *sdio_ctx;
+
+    unifi_info(NULL, "UniFi card inserted\n");
+
+    /* Allocate context and private in one lump */
+    sdio_ctx = (CsrSdioFunction *)kmalloc(sizeof(CsrSdioFunction),
+                                          GFP_KERNEL);
+    if (sdio_ctx == NULL) {
+        return -ENOMEM;
+    }
+
+
+    sdio_ctx->sdioId.manfId = fdev->vendor_id;
+    sdio_ctx->sdioId.cardId = fdev->device_id;
+    sdio_ctx->sdioId.sdioFunction = fdev->function;
+    sdio_ctx->sdioId.sdioInterface = 0;
+    sdio_ctx->blockSize = fdev->blocksize;
+    sdio_ctx->priv = (void *)fdev;
+    sdio_ctx->features = 0;
+
+    /* Module parameter enables byte mode */
+    if (sdio_byte_mode) {
+        sdio_ctx->features |= CSR_SDIO_FEATURE_BYTE_MODE;
+    }
+
+    /* Set up pointer to func_priv in middle of lump */
+    fdev->drv_data = sdio_ctx;
+
+    /* Always override default SDIO bus clock */
+    unifi_trace(NULL, UDBG1, "Setting SDIO bus clock to %d kHz\n", sdio_clock);
+    sdioemb_set_max_bus_freq(fdev, 1000 * sdio_clock);
+
+#ifdef CONFIG_PM
+    /* Register to get PM events */
+    if (uf_sdio_emb_register_pm_notifier(sdio_ctx) == NULL) {
+        unifi_error(NULL, "%s: Failed to register for PM events\n", __FUNCTION__);
+    }
+#endif
+
+    /* Call the main UniFi driver inserted handler */
+    if (sdio_func_drv && sdio_func_drv->inserted) {
+        uf_add_os_device(fdev->slot_id, fdev->os_device);
+        sdio_func_drv->inserted(sdio_ctx);
+    }
+
+#ifdef ANDROID_BUILD
+    /* Take the wakelock */
+    unifi_trace(NULL, UDBG1, "emb probe: take wake lock\n");
+    wake_lock(&unifi_sdio_wake_lock);
+#endif
+
+    return 0;
+} /* uf_glue_sdio_probe() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_sdio_remove
+ *
+ *      Card removal callback.
+ *
+ * Arguments:
+ *      fdev            SDIO device
+ *
+ * Returns:
+ *      UniFi driver error code.
+ * ---------------------------------------------------------------------------
+ */
+static void
+uf_sdio_remove(struct sdioemb_dev *fdev)
+{
+    CsrSdioFunction *sdio_ctx = fdev->drv_data;
+
+    unifi_info(NULL, "UniFi card removed\n");
+
+    /* Clean up the SDIO function driver */
+    if (sdio_func_drv && sdio_func_drv->removed) {
+        sdio_func_drv->removed(sdio_ctx);
+    }
+
+#ifdef CONFIG_PM
+    /* Unregister for PM events */
+    uf_sdio_emb_unregister_pm_notifier(sdio_ctx);
+#endif
+
+    kfree(sdio_ctx);
+
+} /* uf_sdio_remove */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_glue_sdio_suspend
+ *
+ *      System suspend callback.
+ *
+ * Arguments:
+ *      fdev            SDIO device
+ *
+ * Returns:
+ *
+ * ---------------------------------------------------------------------------
+ */
+static void
+uf_glue_sdio_suspend(struct sdioemb_dev *fdev)
+{
+    unifi_info(NULL, "Suspending...\n");
+
+} /* uf_glue_sdio_suspend() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_glue_sdio_resume
+ *
+ *      System resume callback.
+ *
+ * Arguments:
+ *      fdev            SDIO device
+ *
+ * Returns:
+ *
+ * ---------------------------------------------------------------------------
+ */
+static void
+uf_glue_sdio_resume(struct sdioemb_dev *fdev)
+{
+    unifi_info(NULL, "Resuming...\n");
+
+#ifdef ANDROID_BUILD
+    unifi_trace(NULL, UDBG1, "emb resume: take wakelock\n");
+    wake_lock(&unifi_sdio_wake_lock);
+#endif
+
+} /* uf_glue_sdio_resume() */
+
+
+
+
+static struct sdioemb_func_driver unifi_sdioemb = {
+    .name = "unifi",
+    .id_table = NULL,           /* Filled in when main driver registers */
+
+    .probe  = uf_glue_sdio_probe,
+    .remove = uf_sdio_remove,
+    .card_int_handler = uf_glue_sdio_int_handler,
+    .suspend  = uf_glue_sdio_suspend,
+    .resume = uf_glue_sdio_resume,
+};
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioFunctionDriverRegister
+ *  CsrSdioFunctionDriverUnregister
+ *
+ *      These functions are called from the main module load and unload
+ *      functions. They perform the appropriate operations for the
+ *      SDIOemb driver.
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioFunctionDriverRegister(CsrSdioFunctionDriver *sdio_drv)
+{
+    int r;
+    int i;
+
+    printk("Unifi: Using CSR embedded SDIO driver\n");
+
+    if (sdio_func_drv) {
+        unifi_error(NULL, "sdio_emb: UniFi driver already registered\n");
+        return CSR_SDIO_RESULT_INVALID_VALUE;
+    }
+
+    /* Build ID table to pass to sdioemb */
+    unifi_sdioemb.id_table = CsrPmemAlloc(sizeof(struct sdioemb_id_table) * (sdio_drv->idsCount + 1));
+    if (unifi_sdioemb.id_table == NULL) {
+        unifi_error(NULL, "sdio_emb: Failed to allocate memory for ID table (%d IDs)\n", sdio_drv->idsCount);
+        return CSR_RESULT_FAILURE;
+    }
+    for (i = 0; i < sdio_drv->idsCount; i++) {
+        unifi_sdioemb.id_table[i].vendor_id = sdio_drv->ids[i].manfId;
+        unifi_sdioemb.id_table[i].device_id = sdio_drv->ids[i].cardId;
+        unifi_sdioemb.id_table[i].function  = sdio_drv->ids[i].sdioFunction;
+        unifi_sdioemb.id_table[i].interface = sdio_drv->ids[i].sdioInterface;
+    }
+    unifi_sdioemb.id_table[i].vendor_id = 0;
+    unifi_sdioemb.id_table[i].device_id = 0;
+    unifi_sdioemb.id_table[i].function  = 0;
+    unifi_sdioemb.id_table[i].interface = 0;
+
+    /* Save the registered driver description */
+    sdio_func_drv = sdio_drv;
+
+#ifdef CONFIG_PM
+    /* Initialise PM notifier list */
+    INIT_LIST_HEAD(&uf_sdio_emb_pm_notifiers.list);
+#endif
+
+#ifdef ANDROID_BUILD
+    wake_lock_init(&unifi_sdio_wake_lock, WAKE_LOCK_SUSPEND, "unifi_sdio_work");
+#endif
+
+    /* Register ourself with sdioemb */
+    r = sdioemb_driver_register(&unifi_sdioemb);
+    if (r) {
+        unifi_error(NULL, "Failed to register UniFi SDIO driver: %d\n", r);
+        return ConvertSdioToCsrSdioResult(r);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioFunctionDriverRegister() */
+
+
+void
+CsrSdioFunctionDriverUnregister(CsrSdioFunctionDriver *sdio_drv)
+{
+    sdioemb_driver_unregister(&unifi_sdioemb);
+
+#ifdef ANDROID_BUILD
+    wake_lock_destroy(&unifi_sdio_wake_lock);
+#endif
+
+    sdio_func_drv = NULL;
+
+    CsrPmemFree(unifi_sdioemb.id_table);
+    unifi_sdioemb.id_table = NULL;
+} /* CsrSdioFunctionDriverUnregister() */
+
diff --git a/drivers/staging/csr/sdio_events.c b/drivers/staging/csr/sdio_events.c
new file mode 100644
index 0000000..6892c2e
--- /dev/null
+++ b/drivers/staging/csr/sdio_events.c
@@ -0,0 +1,134 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     sdio_events.c
+ *
+ * PURPOSE:
+ *      Process the events received by the SDIO glue layer.
+ *      Optional part of the porting exercise.
+ *
+ * Copyright (C) 2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include "unifi_priv.h"
+
+
+/*
+ * Porting Notes:
+ * There are two ways to support the suspend/resume system events in a driver.
+ * In some operating systems these events are delivered to the OS driver
+ * directly from the system. In this case, the OS driver needs to pass these
+ * events to the API described in the CSR SDIO Abstration API document.
+ * In Linux, and other embedded operating systems, the suspend/resume events
+ * come from the SDIO driver. In this case, simply get these events in the
+ * SDIO glue layer and notify the OS layer.
+ *
+ * In either case, typically, the events are processed by the SME.
+ * Use the unifi_sys_suspend_ind() and unifi_sys_resume_ind() to pass
+ * the events to the SME.
+ */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_suspend
+ *
+ *      Handles a suspend request from the SDIO driver.
+ *
+ *  Arguments:
+ *      ospriv          Pointer to OS driver context.
+ *
+ * ---------------------------------------------------------------------------
+ */
+void unifi_suspend(void *ospriv)
+{
+    unifi_priv_t *priv = ospriv;
+    int interfaceTag=0;
+
+    /* For powered suspend, tell the resume's wifi_on() not to reinit UniFi */
+    priv->wol_suspend = (enable_wol == UNIFI_WOL_OFF) ? FALSE : TRUE;
+
+    unifi_trace(priv, UDBG1, "unifi_suspend: wol_suspend %d, enable_wol %d",
+                priv->wol_suspend, enable_wol );
+
+    /* Stop network traffic. */
+    /* need to stop all the netdevices*/
+    for( interfaceTag=0;interfaceTag<CSR_WIFI_NUM_INTERFACES;interfaceTag++)
+    {
+        netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+        if (interfacePriv->netdev_registered == 1)
+        {
+            if( priv->wol_suspend ) {
+                unifi_trace(priv, UDBG1, "unifi_suspend: Don't netif_carrier_off");
+            } else {
+                unifi_trace(priv, UDBG1, "unifi_suspend: netif_carrier_off");
+                netif_carrier_off(priv->netdev[interfaceTag]);
+            }
+            UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[interfaceTag]);
+        }
+    }
+
+    unifi_trace(priv, UDBG1, "unifi_suspend: suspend SME");
+
+    sme_sys_suspend(priv);
+
+} /* unifi_suspend() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_resume
+ *
+ *      Handles a resume request from the SDIO driver.
+ *
+ *  Arguments:
+ *      ospriv          Pointer to OS driver context.
+ *
+ * ---------------------------------------------------------------------------
+ */
+void unifi_resume(void *ospriv)
+{
+    unifi_priv_t *priv = ospriv;
+    int interfaceTag=0;
+    int r;
+    int wol = priv->wol_suspend;
+
+    unifi_trace(priv, UDBG1, "unifi_resume: resume SME, enable_wol=%d", enable_wol);
+
+    /* The resume causes wifi-on which will re-enable the BH and reinstall the ISR */
+    r = sme_sys_resume(priv);
+    if (r) {
+        unifi_error(priv, "Failed to resume UniFi\n");
+    }
+
+    /* Resume the network interfaces. For the cold resume case, this will
+     * happen upon reconnection.
+     */
+    if (wol) {
+        unifi_trace(priv, UDBG1, "unifi_resume: try to enable carrier");
+
+        /* need to start all the netdevices*/
+        for( interfaceTag=0;interfaceTag<CSR_WIFI_NUM_INTERFACES;interfaceTag++) {
+            netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+            unifi_trace(priv, UDBG1, "unifi_resume: interfaceTag %d netdev_registered %d mode %d\n",
+                   interfaceTag, interfacePriv->netdev_registered, interfacePriv->interfaceMode);
+
+            if (interfacePriv->netdev_registered == 1)
+            {
+                netif_carrier_on(priv->netdev[interfaceTag]);
+                UF_NETIF_TX_START_ALL_QUEUES(priv->netdev[interfaceTag]);
+            }
+        }
+
+        /* Kick the BH thread (with reason=host) to poll for data that may have
+         * arrived during a powered suspend. This caters for the case where the SME
+         * doesn't interact with the chip (e.g install autonomous scans) during resume.
+         */
+        unifi_send_signal(priv->card, NULL, 0, NULL);
+    }
+
+} /* unifi_resume() */
+
diff --git a/drivers/staging/csr/sdio_mmc.c b/drivers/staging/csr/sdio_mmc.c
new file mode 100644
index 0000000..24be087
--- /dev/null
+++ b/drivers/staging/csr/sdio_mmc.c
@@ -0,0 +1,1340 @@
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * FILE: sdio_mmc.c
+ *
+ * PURPOSE: SDIO driver interface for generic MMC stack.
+ *
+ * Copyright (C) 2008-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/gfp.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#include <linux/suspend.h>
+
+#include "unifi_priv.h"
+
+#ifdef ANDROID_BUILD
+struct wake_lock unifi_sdio_wake_lock; /* wakelock to prevent suspend while resuming */
+#endif
+
+static CsrSdioFunctionDriver *sdio_func_drv;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+#ifdef CONFIG_PM
+static int uf_sdio_mmc_power_event(struct notifier_block *this, unsigned long event, void *ptr);
+#endif
+
+/*
+ * We need to keep track of the power on/off because we can not call
+ * mmc_power_restore_host() when the card is already powered.
+ * Even then, we need to patch the MMC driver to add a power_restore handler
+ * in the mmc_sdio_ops structure. If the MMC driver before 2.6.37 is not patched,
+ * mmc_power_save_host() and mmc_power_restore_host() are no-ops in the kernel,
+ * returning immediately (at least on x86).
+ */
+static int card_is_powered = 1;
+#endif /* 2.6.32 */
+
+/* MMC uses ENOMEDIUM to indicate card gone away */
+
+static CsrResult
+ConvertSdioToCsrSdioResult(int r)
+{
+    CsrResult csrResult = CSR_RESULT_FAILURE;
+
+    switch (r) {
+    case 0:
+        csrResult = CSR_RESULT_SUCCESS;
+    break;
+    case -EIO:
+    case -EILSEQ:
+        csrResult = CSR_SDIO_RESULT_CRC_ERROR;
+    break;
+    /* Timeout errors */
+    case -ETIMEDOUT:
+    case -EBUSY:
+        csrResult = CSR_SDIO_RESULT_TIMEOUT;
+    break;
+    case -ENODEV:
+    case -ENOMEDIUM:
+        csrResult = CSR_SDIO_RESULT_NO_DEVICE;
+    break;
+    case -EINVAL:
+        csrResult = CSR_SDIO_RESULT_INVALID_VALUE;
+    break;
+    case -ENOMEM:
+    case -ENOSYS:
+    case -ERANGE:
+    case -ENXIO:
+        csrResult = CSR_RESULT_FAILURE;
+    break;
+    default:
+        unifi_warning(NULL, "Unrecognised SDIO error code: %d\n", r);
+    break;
+    }
+
+    return csrResult;
+}
+
+
+static int
+csr_io_rw_direct(struct mmc_card *card, int write, uint8_t fn,
+                 uint32_t addr, uint8_t in, uint8_t* out)
+{
+    struct mmc_command cmd;
+    int err;
+
+    BUG_ON(!card);
+    BUG_ON(fn > 7);
+
+    memset(&cmd, 0, sizeof(struct mmc_command));
+
+    cmd.opcode = SD_IO_RW_DIRECT;
+    cmd.arg = write ? 0x80000000 : 0x00000000;
+    cmd.arg |= fn << 28;
+    cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
+    cmd.arg |= addr << 9;
+    cmd.arg |= in;
+    cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
+
+    err = mmc_wait_for_cmd(card->host, &cmd, 0);
+    if (err)
+        return err;
+
+    /* this function is not exported, so we will need to sort it out here
+     * for now, lets hard code it to sdio */
+    if (0) {
+        /* old arg (mmc_host_is_spi(card->host)) { */
+        /* host driver already reported errors */
+    } else {
+        if (cmd.resp[0] & R5_ERROR) {
+            printk(KERN_ERR "%s: r5 error 0x%02x\n",
+                   __FUNCTION__, cmd.resp[0]);
+            return -EIO;
+        }
+        if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+            return -EINVAL;
+        if (cmd.resp[0] & R5_OUT_OF_RANGE)
+            return -ERANGE;
+    }
+
+    if (out) {
+        if (0) {    /* old argument (mmc_host_is_spi(card->host)) */
+            *out = (cmd.resp[0] >> 8) & 0xFF;
+        }
+        else {
+            *out = cmd.resp[0] & 0xFF;
+        }
+    }
+
+    return CSR_RESULT_SUCCESS;
+}
+
+
+CsrResult
+CsrSdioRead8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err = 0;
+
+    _sdio_claim_host(func);
+    *data = sdio_readb(func, address, &err);
+    _sdio_release_host(func);
+
+    if (err) {
+        func_exit_r(err);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioRead8() */
+
+CsrResult
+CsrSdioWrite8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err = 0;
+
+    _sdio_claim_host(func);
+    sdio_writeb(func, data, address, &err);
+    _sdio_release_host(func);
+
+    if (err) {
+        func_exit_r(err);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioWrite8() */
+
+CsrResult
+CsrSdioRead16(CsrSdioFunction *function, CsrUint32 address, CsrUint16 *data)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err;
+    uint8_t b0, b1;
+
+    _sdio_claim_host(func);
+    b0 = sdio_readb(func, address, &err);
+    if (err) {
+        _sdio_release_host(func);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+
+    b1 = sdio_readb(func, address+1, &err);
+    if (err) {
+        _sdio_release_host(func);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+    _sdio_release_host(func);
+
+    *data = ((uint16_t)b1 << 8) | b0;
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioRead16() */
+
+
+CsrResult
+CsrSdioWrite16(CsrSdioFunction *function, CsrUint32 address, CsrUint16 data)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err;
+    uint8_t b0, b1;
+
+    _sdio_claim_host(func);
+    b1 = (data >> 8) & 0xFF;
+    sdio_writeb(func, b1, address+1, &err);
+    if (err) {
+        _sdio_release_host(func);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+
+    b0 = data & 0xFF;
+    sdio_writeb(func, b0, address, &err);
+    if (err) {
+        _sdio_release_host(func);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+
+    _sdio_release_host(func);
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioWrite16() */
+
+
+CsrResult
+CsrSdioF0Read8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err = 0;
+
+    _sdio_claim_host(func);
+#ifdef MMC_QUIRK_LENIENT_FN0
+    *data = sdio_f0_readb(func, address, &err);
+#else
+    err = csr_io_rw_direct(func->card, 0, 0, address, 0, data);
+#endif
+    _sdio_release_host(func);
+
+    if (err) {
+        func_exit_r(err);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioF0Read8() */
+
+CsrResult
+CsrSdioF0Write8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err = 0;
+
+    _sdio_claim_host(func);
+#ifdef MMC_QUIRK_LENIENT_FN0
+    sdio_f0_writeb(func, data, address, &err);
+#else
+    err = csr_io_rw_direct(func->card, 1, 0, address, data, NULL);
+#endif
+    _sdio_release_host(func);
+
+    if (err) {
+        func_exit_r(err);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioF0Write8() */
+
+
+CsrResult
+CsrSdioRead(CsrSdioFunction *function, CsrUint32 address, void *data, CsrUint32 length)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err;
+
+    _sdio_claim_host(func);
+    err = sdio_readsb(func, data, address, length);
+    _sdio_release_host(func);
+
+    if (err) {
+        func_exit_r(err);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioRead() */
+
+CsrResult
+CsrSdioWrite(CsrSdioFunction *function, CsrUint32 address, const void *data, CsrUint32 length)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err;
+
+    _sdio_claim_host(func);
+    err = sdio_writesb(func, address, (void*)data, length);
+    _sdio_release_host(func);
+
+    if (err) {
+        func_exit_r(err);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioWrite() */
+
+
+static int
+csr_sdio_enable_hs(struct mmc_card *card)
+{
+    int ret;
+    u8 speed;
+
+    if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED)) {
+        /* We've asked for HS clock rates, but controller doesn't
+         * claim to support it. We should limit the clock
+         * to 25MHz via module parameter.
+         */
+        printk(KERN_INFO "unifi: request HS but not MMC_CAP_SD_HIGHSPEED");
+        return 0;
+    }
+
+    if (!card->cccr.high_speed)
+        return 0;
+
+#if 1
+    ret = csr_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
+    if (ret)
+        return ret;
+
+    speed |= SDIO_SPEED_EHS;
+#else
+    /* Optimisation: Eliminate read by always assuming SHS and that reserved bits can be zero */
+    speed = SDIO_SPEED_EHS | SDIO_SPEED_SHS;
+#endif
+
+    ret = csr_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
+    if (ret)
+        return ret;
+
+    mmc_card_set_highspeed(card);
+    card->host->ios.timing = MMC_TIMING_SD_HS;
+    card->host->ops->set_ios(card->host, &card->host->ios);
+
+    return 0;
+}
+
+static int
+csr_sdio_disable_hs(struct mmc_card *card)
+{
+    int ret;
+    u8 speed;
+
+    if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
+        return 0;
+
+    if (!card->cccr.high_speed)
+        return 0;
+#if 1
+    ret = csr_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
+    if (ret)
+        return ret;
+
+    speed &= ~SDIO_SPEED_EHS;
+#else
+    /* Optimisation: Eliminate read by always assuming SHS and that reserved bits can be zero */
+    speed = SDIO_SPEED_SHS; /* clear SDIO_SPEED_EHS */
+#endif
+
+    ret = csr_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
+    if (ret)
+        return ret;
+
+    card->state &= ~MMC_STATE_HIGHSPEED;
+    card->host->ios.timing = MMC_TIMING_LEGACY;
+    card->host->ops->set_ios(card->host, &card->host->ios);
+
+    return 0;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioMaxBusClockFrequencySet
+ *
+ *      Set the maximum SDIO bus clock speed to use.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ *      maxFrequency         maximum clock speed in Hz
+ *
+ *  Returns:
+ *      an error code.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioMaxBusClockFrequencySet(CsrSdioFunction *function, CsrUint32 maxFrequency)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    struct mmc_host *host = func->card->host;
+    struct mmc_ios *ios = &host->ios;
+    unsigned int max_hz;
+    int err;
+	CsrUint32 max_khz = maxFrequency/1000;
+
+    if (!max_khz || max_khz > sdio_clock) {
+        max_khz = sdio_clock;
+    }
+
+    _sdio_claim_host(func);
+    max_hz = 1000 * max_khz;
+    if (max_hz > host->f_max) {
+        max_hz = host->f_max;
+    }
+
+    if (max_hz > 25000000) {
+        err = csr_sdio_enable_hs(func->card);
+    } else {
+        err = csr_sdio_disable_hs(func->card);
+    }
+    if (err) {
+        printk(KERN_ERR "SDIO warning: Failed to configure SDIO clock mode\n");
+        _sdio_release_host(func);
+		return CSR_RESULT_SUCCESS;
+    }
+
+    ios->clock = max_hz;
+    host->ops->set_ios(host, ios);
+
+    _sdio_release_host(func);
+
+	return CSR_RESULT_SUCCESS;
+} /* CsrSdioMaxBusClockFrequencySet() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioInterruptEnable
+ *  CsrSdioInterruptDisable
+ *
+ *      Enable or disable the SDIO interrupt.
+ *      The driver disables the SDIO interrupt until the i/o thread can
+ *      process it.
+ *      The SDIO interrupt can be disabled by modifying the SDIO_INT_ENABLE
+ *      register in the Card Common Control Register block, but this requires
+ *      two CMD52 operations. A better solution is to mask the interrupt at
+ *      the host controller.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ *
+ *  Returns:
+ *      Zero on success or a UniFi driver error code.
+ *
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioInterruptEnable(CsrSdioFunction *function)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err = 0;
+
+#ifdef CSR_CONFIG_MMC_INT_BYPASS_KSOFTIRQD
+    sdio_unblock_card_irq(func);
+#else
+    _sdio_claim_host(func);
+    /* Write the Int Enable in CCCR block */
+#ifdef MMC_QUIRK_LENIENT_FN0
+    sdio_f0_writeb(func, 0x3, SDIO_CCCR_IENx, &err);
+#else
+    err = csr_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, 0x03, NULL);
+#endif
+    _sdio_release_host(func);
+
+    func_exit();
+    if (err) {
+        printk(KERN_ERR "unifi: %s: error %d writing IENx\n", __FUNCTION__, err);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+#endif
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioInterruptEnable() */
+
+CsrResult
+CsrSdioInterruptDisable(CsrSdioFunction *function)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err = 0;
+
+#ifdef CSR_CONFIG_MMC_INT_BYPASS_KSOFTIRQD
+    sdio_block_card_irq(func);
+#else
+    _sdio_claim_host(func);
+    /* Write the Int Enable in CCCR block */
+#ifdef MMC_QUIRK_LENIENT_FN0
+    sdio_f0_writeb(func, 0, SDIO_CCCR_IENx, &err);
+#else
+    err = csr_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, 0x00, NULL);
+#endif
+    _sdio_release_host(func);
+
+    func_exit();
+    if (err) {
+        printk(KERN_ERR "unifi: %s: error %d writing IENx\n", __FUNCTION__, err);
+        return ConvertSdioToCsrSdioResult(err);
+    }
+#endif
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioInterruptDisable() */
+
+
+void CsrSdioInterruptAcknowledge(CsrSdioFunction *function)
+{
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioFunctionEnable
+ *
+ *      Enable i/o on function 1.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ *
+ * Returns:
+ *      UniFi driver error code.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioFunctionEnable(CsrSdioFunction *function)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err;
+
+    func_enter();
+
+    /* Enable UniFi function 1 (the 802.11 part). */
+    _sdio_claim_host(func);
+    err = sdio_enable_func(func);
+    _sdio_release_host(func);
+    if (err) {
+        unifi_error(NULL, "Failed to enable SDIO function %d\n", func->num);
+    }
+
+    func_exit();
+    return ConvertSdioToCsrSdioResult(err);
+} /* CsrSdioFunctionEnable() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioFunctionDisable
+ *
+ *      Enable i/o on function 1.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ *
+ * Returns:
+ *      UniFi driver error code.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioFunctionDisable(CsrSdioFunction *function)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int err;
+
+    func_enter();
+
+    /* Disable UniFi function 1 (the 802.11 part). */
+    _sdio_claim_host(func);
+    err = sdio_disable_func(func);
+    _sdio_release_host(func);
+    if (err) {
+        unifi_error(NULL, "Failed to disable SDIO function %d\n", func->num);
+    }
+
+    func_exit();
+    return ConvertSdioToCsrSdioResult(err);
+} /* CsrSdioFunctionDisable() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioFunctionActive
+ *
+ *      No-op as the bus goes to an active state at the start of every
+ *      command.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ * ---------------------------------------------------------------------------
+ */
+void
+CsrSdioFunctionActive(CsrSdioFunction *function)
+{
+} /* CsrSdioFunctionActive() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioFunctionIdle
+ *
+ *      Set the function as idle.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ * ---------------------------------------------------------------------------
+ */
+void
+CsrSdioFunctionIdle(CsrSdioFunction *function)
+{
+} /* CsrSdioFunctionIdle() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioPowerOn
+ *
+ *      Power on UniFi.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioPowerOn(CsrSdioFunction *function)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    struct mmc_host *host = func->card->host;
+
+    _sdio_claim_host(func);
+    if (!card_is_powered) {
+        mmc_power_restore_host(host);
+        card_is_powered = 1;
+    } else {
+        printk(KERN_INFO "SDIO: Skip power on; card is already powered.\n");
+    }
+    _sdio_release_host(func);
+#endif /* 2.6.32 */
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioPowerOn() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioPowerOff
+ *
+ *      Power off UniFi.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ * ---------------------------------------------------------------------------
+ */
+void
+CsrSdioPowerOff(CsrSdioFunction *function)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    struct mmc_host *host = func->card->host;
+
+    _sdio_claim_host(func);
+    if (card_is_powered) {
+        mmc_power_save_host(host);
+        card_is_powered = 0;
+    } else {
+        printk(KERN_INFO "SDIO: Skip power off; card is already powered off.\n");
+    }
+    _sdio_release_host(func);
+#endif /* 2.6.32 */
+} /* CsrSdioPowerOff() */
+
+
+static int
+sdio_set_block_size_ignore_first_error(struct sdio_func *func, unsigned blksz)
+{
+    int ret;
+
+    if (blksz > func->card->host->max_blk_size)
+        return -EINVAL;
+
+    if (blksz == 0) {
+        blksz = min(func->max_blksize, func->card->host->max_blk_size);
+        blksz = min(blksz, 512u);
+    }
+
+    /*
+     * Ignore -ERANGE (OUT_OF_RANGE in R5) on the first byte as
+     * the block size may be invalid until both bytes are written.
+     */
+    ret = csr_io_rw_direct(func->card, 1, 0,
+                           SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE,
+                           blksz & 0xff, NULL);
+    if (ret && ret != -ERANGE)
+        return ret;
+    ret = csr_io_rw_direct(func->card, 1, 0,
+                           SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE + 1,
+                           (blksz >> 8) & 0xff, NULL);
+    if (ret)
+        return ret;
+    func->cur_blksize = blksz;
+
+    return 0;
+}
+
+CsrResult
+CsrSdioBlockSizeSet(CsrSdioFunction *function, CsrUint16 blockSize)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int r = 0;
+
+    /* Module parameter overrides */
+    if (sdio_block_size > -1) {
+        blockSize = sdio_block_size;
+    }
+
+    unifi_trace(NULL, UDBG1, "Set SDIO function block size to %d\n",
+                blockSize);
+
+    _sdio_claim_host(func);
+    r = sdio_set_block_size(func, blockSize);
+    _sdio_release_host(func);
+
+    /*
+     * The MMC driver for kernels prior to 2.6.32 may fail this request
+     * with -ERANGE. In this case use our workaround.
+     */
+    if (r == -ERANGE) {
+        _sdio_claim_host(func);
+        r = sdio_set_block_size_ignore_first_error(func, blockSize);
+        _sdio_release_host(func);
+    }
+    if (r) {
+        unifi_error(NULL, "Error %d setting block size\n", r);
+    }
+
+    /* Determine the achieved block size to pass to the core */
+    function->blockSize = func->cur_blksize;
+
+    return ConvertSdioToCsrSdioResult(r);
+} /* CsrSdioBlockSizeSet() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioHardReset
+ *
+ *      Hard Resets UniFi is possible.
+ *
+ *  Arguments:
+ *      sdio            SDIO context pointer
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioHardReset(CsrSdioFunction *function)
+{
+    return CSR_RESULT_FAILURE;
+} /* CsrSdioHardReset() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_glue_sdio_int_handler
+ *
+ *      Interrupt callback function for SDIO interrupts.
+ *      This is called in kernel context (i.e. not interrupt context).
+ *
+ *  Arguments:
+ *      func      SDIO context pointer
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Note: Called with host already claimed.
+ * ---------------------------------------------------------------------------
+ */
+static void
+uf_glue_sdio_int_handler(struct sdio_func *func)
+{
+    CsrSdioFunction *sdio_ctx;
+    CsrSdioInterruptDsrCallback func_dsr_callback;
+    int r;
+
+    sdio_ctx = sdio_get_drvdata(func);
+    if (!sdio_ctx) {
+        return;
+    }
+
+#ifndef CSR_CONFIG_MMC_INT_BYPASS_KSOFTIRQD
+    /*
+     * Normally, we are not allowed to do any SDIO commands here.
+     * However, this is called in a thread context and with the SDIO lock
+     * so we disable the interrupts here instead of trying to do complicated
+     * things with the SDIO lock.
+     */
+#ifdef MMC_QUIRK_LENIENT_FN0
+    sdio_f0_writeb(func, 0, SDIO_CCCR_IENx, &r);
+#else
+    r = csr_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, 0x00, NULL);
+#endif
+    if (r) {
+        printk(KERN_ERR "UniFi MMC Int handler: Failed to disable interrupts %d\n", r);
+    }
+#endif
+
+    /* If the function driver has registered a handler, call it */
+    if (sdio_func_drv && sdio_func_drv->intr) {
+
+        func_dsr_callback = sdio_func_drv->intr(sdio_ctx);
+
+        /* If interrupt handle returns a DSR handle, call it */
+        if (func_dsr_callback) {
+            func_dsr_callback(sdio_ctx);
+        }
+    }
+
+} /* uf_glue_sdio_int_handler() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  csr_sdio_linux_remove_irq
+ *
+ *      Unregister the interrupt handler.
+ *      This means that the linux layer can not process interrupts any more.
+ *
+ *  Arguments:
+ *      sdio      SDIO context pointer
+ *
+ *  Returns:
+ *      Status of the removal.
+ * ---------------------------------------------------------------------------
+ */
+int
+csr_sdio_linux_remove_irq(CsrSdioFunction *function)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int r;
+
+    unifi_trace(NULL, UDBG1, "csr_sdio_linux_remove_irq\n");
+
+    sdio_claim_host(func);
+    r = sdio_release_irq(func);
+    sdio_release_host(func);
+
+    return r;
+
+} /* csr_sdio_linux_remove_irq() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  csr_sdio_linux_install_irq
+ *
+ *      Register the interrupt handler.
+ *      This means that the linux layer can process interrupts.
+ *
+ *  Arguments:
+ *      sdio      SDIO context pointer
+ *
+ *  Returns:
+ *      Status of the removal.
+ * ---------------------------------------------------------------------------
+ */
+int
+csr_sdio_linux_install_irq(CsrSdioFunction *function)
+{
+    struct sdio_func *func = (struct sdio_func *)function->priv;
+    int r;
+
+    unifi_trace(NULL, UDBG1, "csr_sdio_linux_install_irq\n");
+
+    /* Register our interrupt handle */
+    sdio_claim_host(func);
+    r = sdio_claim_irq(func, uf_glue_sdio_int_handler);
+    sdio_release_host(func);
+
+    /* If the interrupt was installed earlier, is fine */
+    if (r == -EBUSY) {
+        r = 0;
+    }
+
+    return r;
+} /* csr_sdio_linux_install_irq() */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+#ifdef CONFIG_PM
+
+/*
+ * Power Management notifier
+ */
+struct uf_sdio_mmc_pm_notifier
+{
+    struct list_head list;
+
+    CsrSdioFunction *sdio_ctx;
+    struct notifier_block pm_notifier;
+};
+
+/* PM notifier list head */
+static struct uf_sdio_mmc_pm_notifier uf_sdio_mmc_pm_notifiers = {
+    .sdio_ctx = NULL,
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * uf_sdio_mmc_register_pm_notifier
+ * uf_sdio_mmc_unregister_pm_notifier
+ *
+ *      Register/unregister for power management events. A list is used to
+ *      allow multiple card instances to be supported.
+ *
+ *  Arguments:
+ *      sdio_ctx - CSR SDIO context to associate PM notifier to
+ *
+ *  Returns:
+ *      Register function returns NULL on error
+ * ---------------------------------------------------------------------------
+ */
+static struct uf_sdio_mmc_pm_notifier *
+uf_sdio_mmc_register_pm_notifier(CsrSdioFunction *sdio_ctx)
+{
+    /* Allocate notifier context for this card instance */
+    struct uf_sdio_mmc_pm_notifier *notifier_ctx = kmalloc(sizeof(struct uf_sdio_mmc_pm_notifier), GFP_KERNEL);
+
+    if (notifier_ctx)
+    {
+        notifier_ctx->sdio_ctx = sdio_ctx;
+        notifier_ctx->pm_notifier.notifier_call = uf_sdio_mmc_power_event;
+
+        list_add(&notifier_ctx->list, &uf_sdio_mmc_pm_notifiers.list);
+
+        if (register_pm_notifier(&notifier_ctx->pm_notifier)) {
+            printk(KERN_ERR "unifi: register_pm_notifier failed\n");
+        }
+    }
+
+    return notifier_ctx;
+}
+
+static void
+uf_sdio_mmc_unregister_pm_notifier(CsrSdioFunction *sdio_ctx)
+{
+    struct uf_sdio_mmc_pm_notifier *notifier_ctx;
+    struct list_head *node, *q;
+
+    list_for_each_safe(node, q, &uf_sdio_mmc_pm_notifiers.list) {
+        notifier_ctx = list_entry(node, struct uf_sdio_mmc_pm_notifier, list);
+
+        /* If it matches, unregister and free the notifier context */
+        if (notifier_ctx && notifier_ctx->sdio_ctx == sdio_ctx)
+        {
+            if (unregister_pm_notifier(&notifier_ctx->pm_notifier)) {
+                printk(KERN_ERR "unifi: unregister_pm_notifier failed\n");
+            }
+
+            /* Remove from list */
+            notifier_ctx->sdio_ctx = NULL;
+            list_del(node);
+            kfree(notifier_ctx);
+        }
+    }
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * uf_sdio_mmc_power_event
+ *
+ *      Handler for power management events.
+ *
+ *      We need to handle suspend/resume events while the userspace is unsuspended
+ *      to allow the SME to run its suspend/resume state machines.
+ *
+ *  Arguments:
+ *      event   event ID
+ *
+ *  Returns:
+ *      Status of the event handling
+ * ---------------------------------------------------------------------------
+ */
+static int
+uf_sdio_mmc_power_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+    struct uf_sdio_mmc_pm_notifier *notifier_ctx = container_of(this,
+                                                                struct uf_sdio_mmc_pm_notifier,
+                                                                pm_notifier);
+
+    /* Call the CSR SDIO function driver's suspend/resume method
+     * while the userspace is unsuspended.
+     */
+    switch (event) {
+        case PM_POST_HIBERNATION:
+        case PM_POST_SUSPEND:
+            printk(KERN_INFO "%s:%d resume\n", __FUNCTION__, __LINE__ );
+            if (sdio_func_drv && sdio_func_drv->resume) {
+                sdio_func_drv->resume(notifier_ctx->sdio_ctx);
+            }
+            break;
+
+        case PM_HIBERNATION_PREPARE:
+        case PM_SUSPEND_PREPARE:
+            printk(KERN_INFO "%s:%d suspend\n", __FUNCTION__, __LINE__ );
+            if (sdio_func_drv && sdio_func_drv->suspend) {
+                sdio_func_drv->suspend(notifier_ctx->sdio_ctx);
+            }
+            break;
+    }
+    return NOTIFY_DONE;
+}
+
+#endif /* CONFIG_PM */
+#endif /* 2.6.32 */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_glue_sdio_probe
+ *
+ *      Card insert callback.
+ *
+ * Arguments:
+ *      func            Our (glue layer) context pointer.
+ *
+ * Returns:
+ *      UniFi driver error code.
+ * ---------------------------------------------------------------------------
+ */
+static int
+uf_glue_sdio_probe(struct sdio_func *func,
+                   const struct sdio_device_id *id)
+{
+    int instance;
+    CsrSdioFunction *sdio_ctx;
+
+    func_enter();
+
+    /* First of all claim the SDIO driver */
+    sdio_claim_host(func);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+    /* Assume that the card is already powered */
+    card_is_powered = 1;
+#endif
+
+    /* Assumes one card per host, which is true for SDIO */
+    instance = func->card->host->index;
+    printk("sdio bus_id: %16s - UniFi card 0x%X inserted\n",
+           sdio_func_id(func), instance);
+
+    /* Allocate context */
+    sdio_ctx = (CsrSdioFunction *)kmalloc(sizeof(CsrSdioFunction),
+                                          GFP_KERNEL);
+    if (sdio_ctx == NULL) {
+        sdio_release_host(func);
+        return -ENOMEM;
+    }
+
+    /* Initialise the context */
+    sdio_ctx->sdioId.manfId  = func->vendor;
+    sdio_ctx->sdioId.cardId  = func->device;
+    sdio_ctx->sdioId.sdioFunction  = func->num;
+    sdio_ctx->sdioId.sdioInterface = func->class;
+    sdio_ctx->blockSize = func->cur_blksize;
+    sdio_ctx->priv = (void *)func;
+    sdio_ctx->features = 0;
+
+    /* Module parameter enables byte mode */
+    if (sdio_byte_mode) {
+        sdio_ctx->features |= CSR_SDIO_FEATURE_BYTE_MODE;
+    }
+
+    if (func->card->host->caps & MMC_CAP_SD_HIGHSPEED) {
+        unifi_trace(NULL, UDBG1, "MMC_CAP_SD_HIGHSPEED is available\n");
+    }
+
+#ifdef MMC_QUIRK_LENIENT_FN0
+    func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+#endif
+
+    /* Pass context to the SDIO driver */
+    sdio_set_drvdata(func, sdio_ctx);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+#ifdef CONFIG_PM
+    /* Register to get PM events */
+    if (uf_sdio_mmc_register_pm_notifier(sdio_ctx) == NULL) {
+        unifi_error(NULL, "%s: Failed to register for PM events\n", __FUNCTION__);
+    }
+#endif
+#endif
+
+    /* Register this device with the SDIO function driver */
+    /* Call the main UniFi driver inserted handler */
+    if (sdio_func_drv && sdio_func_drv->inserted) {
+        uf_add_os_device(instance, &func->dev);
+        sdio_func_drv->inserted(sdio_ctx);
+    }
+
+    /* We have finished, so release the SDIO driver */
+    sdio_release_host(func);
+
+#ifdef ANDROID_BUILD
+    /* Take the wakelock */
+    unifi_trace(NULL, UDBG1, "probe: take wake lock\n");
+    wake_lock(&unifi_sdio_wake_lock);
+#endif
+
+    func_exit();
+    return 0;
+} /* uf_glue_sdio_probe() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_glue_sdio_remove
+ *
+ *      Card removal callback.
+ *
+ * Arguments:
+ *      func            Our (glue layer) context pointer.
+ *
+ * Returns:
+ *      UniFi driver error code.
+ * ---------------------------------------------------------------------------
+ */
+static void
+uf_glue_sdio_remove(struct sdio_func *func)
+{
+    CsrSdioFunction *sdio_ctx;
+
+    sdio_ctx = sdio_get_drvdata(func);
+    if (!sdio_ctx) {
+        return;
+    }
+
+    func_enter();
+
+    unifi_info(NULL, "UniFi card removed\n");
+
+    /* Clean up the SDIO function driver */
+    if (sdio_func_drv && sdio_func_drv->removed) {
+        uf_remove_os_device(func->card->host->index);
+        sdio_func_drv->removed(sdio_ctx);
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+#ifdef CONFIG_PM
+    /* Unregister for PM events */
+    uf_sdio_mmc_unregister_pm_notifier(sdio_ctx);
+#endif
+#endif
+
+    kfree(sdio_ctx);
+
+    func_exit();
+
+} /* uf_glue_sdio_remove */
+
+
+/*
+ * SDIO ids *must* be statically declared, so we can't take
+ * them from the list passed in csr_sdio_register_driver().
+ */
+static const struct sdio_device_id unifi_ids[] = {
+    { SDIO_DEVICE(SDIO_MANF_ID_CSR,SDIO_CARD_ID_UNIFI_3) },
+    { SDIO_DEVICE(SDIO_MANF_ID_CSR,SDIO_CARD_ID_UNIFI_4) },
+    { /* end: all zeroes */				},
+};
+
+MODULE_DEVICE_TABLE(sdio, unifi_ids);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+#ifdef CONFIG_PM
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_glue_sdio_suspend
+ *
+ *      Card suspend callback. The userspace will already be suspended.
+ *
+ * Arguments:
+ *      dev            The struct device owned by the MMC driver
+ *
+ * Returns:
+ *      None
+ * ---------------------------------------------------------------------------
+ */
+static int
+uf_glue_sdio_suspend(struct device *dev)
+{
+    func_enter();
+
+    unifi_trace(NULL, UDBG1, "uf_glue_sdio_suspend");
+
+    func_exit();
+    return 0;
+} /* uf_glue_sdio_suspend */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_glue_sdio_resume
+ *
+ *      Card resume callback. The userspace will still be suspended.
+ *
+ * Arguments:
+ *      dev            The struct device owned by the MMC driver
+ *
+ * Returns:
+ *      None
+ * ---------------------------------------------------------------------------
+ */
+static int
+uf_glue_sdio_resume(struct device *dev)
+{
+    func_enter();
+
+    unifi_trace(NULL, UDBG1, "uf_glue_sdio_resume");
+
+#ifdef ANDROID_BUILD
+    unifi_trace(NULL, UDBG1, "resume: take wakelock\n");
+    wake_lock(&unifi_sdio_wake_lock);
+#endif
+
+    func_exit();
+    return 0;
+
+} /* uf_glue_sdio_resume */
+
+static struct dev_pm_ops unifi_pm_ops = {
+    .suspend = uf_glue_sdio_suspend,
+    .resume  = uf_glue_sdio_resume,
+};
+
+#define UNIFI_PM_OPS  (&unifi_pm_ops)
+
+#else
+
+#define UNIFI_PM_OPS  NULL
+
+#endif /* CONFIG_PM */
+#endif /* 2.6.32 */
+
+static struct sdio_driver unifi_driver = {
+    .probe      = uf_glue_sdio_probe,
+    .remove     = uf_glue_sdio_remove,
+    .name       = "unifi",
+    .id_table	= unifi_ids,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+    .drv.pm     = UNIFI_PM_OPS,
+#endif /* 2.6.32 */
+};
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  CsrSdioFunctionDriverRegister
+ *  CsrSdioFunctionDriverUnregister
+ *
+ *      These functions are called from the main module load and unload
+ *      functions. They perform the appropriate operations for the
+ *      linux MMC/SDIO driver.
+ *
+ *  Arguments:
+ *      sdio_drv    Pointer to the function driver's SDIO structure.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+CsrResult
+CsrSdioFunctionDriverRegister(CsrSdioFunctionDriver *sdio_drv)
+{
+    int r;
+
+    printk("UniFi: Using native Linux MMC driver for SDIO.\n");
+
+    if (sdio_func_drv) {
+        unifi_error(NULL, "sdio_mmc: UniFi driver already registered\n");
+        return CSR_SDIO_RESULT_INVALID_VALUE;
+    }
+
+#ifdef ANDROID_BUILD
+    wake_lock_init(&unifi_sdio_wake_lock, WAKE_LOCK_SUSPEND, "unifi_sdio_work");
+#endif
+
+    /* Save the registered driver description */
+    /*
+     * FIXME:
+     * Need a table here to handle a call to register for just one function.
+     * mmc only allows us to register for the whole device
+     */
+    sdio_func_drv = sdio_drv;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+#ifdef CONFIG_PM
+    /* Initialise PM notifier list */
+    INIT_LIST_HEAD(&uf_sdio_mmc_pm_notifiers.list);
+#endif
+#endif
+
+    /* Register ourself with mmc_core */
+    r = sdio_register_driver(&unifi_driver);
+    if (r) {
+        printk(KERN_ERR "unifi_sdio: Failed to register UniFi SDIO driver: %d\n", r);
+        return ConvertSdioToCsrSdioResult(r);
+    }
+
+    return CSR_RESULT_SUCCESS;
+} /* CsrSdioFunctionDriverRegister() */
+
+
+
+void
+CsrSdioFunctionDriverUnregister(CsrSdioFunctionDriver *sdio_drv)
+{
+    printk(KERN_INFO "UniFi: unregister from MMC sdio\n");
+
+#ifdef ANDROID_BUILD
+    wake_lock_destroy(&unifi_sdio_wake_lock);
+#endif
+    sdio_unregister_driver(&unifi_driver);
+
+    sdio_func_drv = NULL;
+
+} /* CsrSdioFunctionDriverUnregister() */
+
diff --git a/drivers/staging/csr/sdio_stubs.c b/drivers/staging/csr/sdio_stubs.c
new file mode 100644
index 0000000..bc6a369
--- /dev/null
+++ b/drivers/staging/csr/sdio_stubs.c
@@ -0,0 +1,82 @@
+/*
+ * Stubs for some of the bottom edge functions.
+ *
+ * These stubs are optional functions in the bottom edge (SDIO driver
+ * interface) API that not all platforms or SDIO drivers may support.
+ *
+ * They're declared as weak symbols so they can be overridden by
+ * simply providing a non-weak declaration.
+ *
+ * Copyright (C) 2007-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ */
+#include "csr_wifi_hip_unifi.h"
+
+void __attribute__((weak)) CsrSdioFunctionIdle(CsrSdioFunction *function)
+{
+}
+
+void __attribute__((weak)) CsrSdioFunctionActive(CsrSdioFunction *function)
+{
+}
+
+CsrResult __attribute__((weak)) CsrSdioPowerOn(CsrSdioFunction *function)
+{
+    return CSR_RESULT_SUCCESS;
+}
+
+void __attribute__((weak)) CsrSdioPowerOff(CsrSdioFunction *function)
+{
+}
+
+CsrResult __attribute__((weak)) CsrSdioHardReset(CsrSdioFunction *function)
+{
+    return CSR_SDIO_RESULT_NOT_RESET;
+}
+
+CsrResult __attribute__((weak)) CsrSdioBlockSizeSet(CsrSdioFunction *function,
+                                                   CsrUint16 blockSize)
+{
+    return CSR_RESULT_SUCCESS;
+}
+
+CsrResult __attribute__((weak)) CsrSdioSuspend(CsrSdioFunction *function)
+{
+    return CSR_RESULT_SUCCESS;
+}
+
+CsrResult __attribute__((weak)) CsrSdioResume(CsrSdioFunction *function)
+{
+    return CSR_RESULT_SUCCESS;
+}
+
+int __attribute__((weak)) csr_sdio_linux_install_irq(CsrSdioFunction *function)
+{
+    return 0;
+}
+
+int __attribute__((weak)) csr_sdio_linux_remove_irq(CsrSdioFunction *function)
+{
+    return 0;
+}
+
+void __attribute__((weak)) CsrSdioInsertedAcknowledge(CsrSdioFunction *function, CsrResult result)
+{
+}
+
+void __attribute__((weak)) CsrSdioRemovedAcknowledge(CsrSdioFunction *function)
+{
+}
+
+void __attribute__((weak)) CsrSdioSuspendAcknowledge(CsrSdioFunction *function, CsrResult result)
+{
+}
+
+void __attribute__((weak)) CsrSdioResumeAcknowledge(CsrSdioFunction *function, CsrResult result)
+{
+}
+
+
diff --git a/drivers/staging/csr/sdioemb/cspi.h b/drivers/staging/csr/sdioemb/cspi.h
new file mode 100644
index 0000000..b0a2886
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/cspi.h
@@ -0,0 +1,62 @@
+/*
+ * CSPI definitions.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef SDIOEMB_CSPI_H
+#define SDIOEMB_CSPI_H
+
+/**
+ * @addtogroup sdriver
+ *@{*/
+
+#define CSPI_FUNC(f) (f)
+#define CSPI_READ    0x10
+#define CSPI_WRITE   0x20
+#define CSPI_BURST   0x40
+#define CSPI_TYPE_MASK 0x70
+
+/**
+ * CSPI_MODE function 0 register.
+ *
+ * Various CSPI mode settings.
+ *
+ * @see CSPI specification (CS-110124-SP)
+ */
+#define CSPI_MODE 0xf7
+#  define CSPI_MODE_PADDED_WRITE_HDRS      (1 << 7)
+#  define CSPI_MODE_PADDED_READ_HDRS       (1 << 6)
+/**
+ * BigEndianRegisters bit of \ref CSPI_MODE -- enable big-endian CSPI
+ * register reads and writes.
+ *
+ * @warning This bit should never be set as it's not possible to use
+ * this mode without knowledge of which registers are 8 bit and which
+ * are 16 bit.
+ */
+#  define CSPI_MODE_BE_REG                 (1 << 5)
+#  define CSPI_MODE_BE_BURST               (1 << 4)
+#  define CSPI_MODE_INT_ACTIVE_HIGH        (1 << 3)
+#  define CSPI_MODE_INT_ON_ERR             (1 << 2)
+#  define CSPI_MODE_LEN_FIELD_PRESENT      (1 << 1)
+#  define CSPI_MODE_DRV_MISO_ON_RISING_CLK (1 << 0)
+
+#define CSPI_STATUS 0xf8
+
+#define CSPI_PADDING 0xf9
+#  define CSPI_PADDING_REG(p)   ((p) << 0)
+#  define CSPI_PADDING_BURST(p) ((p) << 4)
+
+#define CSPI_PADDING_MAX       15
+#define CSPI_PADDING_REG_DFLT   0
+#define CSPI_PADDING_BURST_DFLT 2
+
+/* cmd byte, 3 byte addr, padding, error byte, data word */
+#define CSPI_REG_TRANSFER_LEN (1 + 3 + CSPI_PADDING_MAX + 1 + 2)
+
+/*@}*/
+
+#endif /* #ifndef SDIOEMB_CSPI_H */
diff --git a/drivers/staging/csr/sdioemb/csr_result.h b/drivers/staging/csr/sdioemb/csr_result.h
new file mode 100644
index 0000000..9813f3f
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/csr_result.h
@@ -0,0 +1,16 @@
+/*
+ * Synergy compatible API -- common result codes.
+ *
+ * Copyright (C) 2010 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef CSR_RESULT_H__
+#define CSR_RESULT_H__
+
+typedef CsrUint16 CsrResult;
+#define CSR_RESULT_SUCCESS ((CsrResult) 0x0000)
+#define CSR_RESULT_FAILURE ((CsrResult) 0xffff)
+
+#endif
diff --git a/drivers/staging/csr/sdioemb/csr_sdio.h b/drivers/staging/csr/sdioemb/csr_sdio.h
new file mode 100644
index 0000000..5d05d96
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/csr_sdio.h
@@ -0,0 +1,711 @@
+/*
+ * Synergy compatible API -- SDIO.
+ *
+ * Copyright (C) 2010 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef CSR_SDIO_H__
+#define CSR_SDIO_H__
+
+#include "csr_types.h"
+#include "csr_result.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Result Codes */
+#define CSR_SDIO_RESULT_INVALID_VALUE   ((CsrResult) 1) /* Invalid argument value */
+#define CSR_SDIO_RESULT_NO_DEVICE       ((CsrResult) 2) /* The specified device is no longer present */
+#define CSR_SDIO_RESULT_CRC_ERROR       ((CsrResult) 3) /* The transmitted/received data or command response contained a CRC error */
+#define CSR_SDIO_RESULT_TIMEOUT         ((CsrResult) 4) /* No command response or data received from device, or function enable/disable did not succeed within timeout period */
+#define CSR_SDIO_RESULT_NOT_RESET       ((CsrResult) 5) /* The device was not reset */
+
+/* Features (for use in features member of CsrSdioFunction) */
+#define CSR_SDIO_FEATURE_BYTE_MODE                   0x00000001 /* Transfer sizes do not have to be a multiple of block size */
+#define CSR_SDIO_FEATURE_DMA_CAPABLE_MEM_REQUIRED    0x00000002 /* Bulk operations require DMA friendly memory */
+
+/* CsrSdioFunctionId wildcards (for use in CsrSdioFunctionId members) */
+#define CSR_SDIO_ANY_MANF_ID        0xFFFF
+#define CSR_SDIO_ANY_CARD_ID        0xFFFF
+#define CSR_SDIO_ANY_SDIO_FUNCTION  0xFF
+#define CSR_SDIO_ANY_SDIO_INTERFACE 0xFF
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunctionId
+ *
+ *  DESCRIPTION
+ *      This structure describes one or more functions of a device, based on
+ *      four qualitative measures. The CsrSdioFunctionId wildcard defines can be
+ *      used for making the CsrSdioFunctionId match more than one function.
+ *
+ *  MEMBERS
+ *      manfId - Vendor ID (or CSR_SDIO_ANY_MANF_ID).
+ *      cardId - Device ID (or CSR_SDIO_ANY_CARD_ID).
+ *      sdioFunction - SDIO Function number (or CSR_SDIO_ANY_SDIO_FUNCTION).
+ *      sdioInterface - SDIO Standard Interface Code (or CSR_SDIO_ANY_SDIO_INTERFACE)
+ *
+ *----------------------------------------------------------------------------*/
+typedef struct
+{
+    CsrUint16 manfId;       /* Vendor ID to match or CSR_SDIO_ANY_MANF_ID */
+    CsrUint16 cardId;       /* Device ID to match or CSR_SDIO_ANY_CARD_ID */
+    CsrUint8 sdioFunction;  /* SDIO Function number to match or CSR_SDIO_ANY_SDIO_FUNCTION */
+    CsrUint8 sdioInterface; /* SDIO Standard Interface Code to match or CSR_SDIO_ANY_SDIO_INTERFACE */
+} CsrSdioFunctionId;
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunction
+ *
+ *  DESCRIPTION
+ *      This structure represents a single function on a device.
+ *
+ *  MEMBERS
+ *      sdioId - A CsrSdioFunctionId describing this particular function. The
+ *               subfield shall not contain any CsrSdioFunctionId wildcards. The
+ *               subfields shall describe the specific single function
+ *               represented by this structure.
+ *      blockSize - Actual configured block size, or 0 if unconfigured.
+ *      features - Bit mask with any of CSR_SDIO_FEATURE_* set.
+ *      driverData - For use by the Function Driver. The SDIO Driver shall not
+ *                   attempt to dereference the pointer.
+ *      priv - For use by the SDIO Driver. The Function Driver shall not attempt
+ *             to dereference the pointer.
+ *
+ *----------------------------------------------------------------------------*/
+typedef struct
+{
+    CsrSdioFunctionId sdioId;
+    CsrUint16 blockSize;    /* Actual configured block size, or 0 if unconfigured */
+    CsrUint32 features;     /* Bit mask with any of CSR_SDIO_FEATURE_* set */
+    void *cardHandle;       /* An opaque handle for this function's card. */
+    void *osDevice;
+    void *driverData;       /* For use by the Function Driver */
+    void *priv;             /* For use by the SDIO Driver */
+} CsrSdioFunction;
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioInsertedCallback, CsrSdioRemovedCallback
+ *
+ *  DESCRIPTION
+ *      CsrSdioInsertedCallback is called when a function becomes available to
+ *      a registered Function Driver that supports the function.
+ *      CsrSdioRemovedCallback is called when a function is no longer available
+ *      to a Function Driver, either because the device has been removed, or the
+ *      Function Driver has been unregistered.
+ *
+ *      NOTE: These functions are implemented by the Function Driver, and are
+ *            passed as function pointers in the CsrSdioFunctionDriver struct.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *----------------------------------------------------------------------------*/
+typedef void (*CsrSdioInsertedCallback)(CsrSdioFunction *function);
+typedef void (*CsrSdioRemovedCallback)(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioInterruptDsrCallback, CsrSdioInterruptCallback
+ *
+ *  DESCRIPTION
+ *      CsrSdioInterruptCallback is called when an interrupt occurs on the
+ *      the device associated with the specified function.
+ *
+ *      NOTE: These functions are implemented by the Function Driver, and are
+ *            passed as function pointers in the CsrSdioFunctionDriver struct.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *  RETURNS (only CsrSdioInterruptCallback)
+ *      A pointer to a CsrSdioInterruptDsrCallback function.
+ *
+ *----------------------------------------------------------------------------*/
+typedef void (*CsrSdioInterruptDsrCallback)(CsrSdioFunction *function);
+typedef CsrSdioInterruptDsrCallback (*CsrSdioInterruptCallback)(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioSuspendCallback, CsrSdioResumeCallback
+ *
+ *  DESCRIPTION
+ *      CsrSdioSuspendCallback is called when the system is preparing to go
+ *      into a suspended state. CsrSdioResumeCallback is called when the system
+ *      has entered an active state again.
+ *
+ *      NOTE: These functions are implemented by the Function Driver, and are
+ *            passed as function pointers in the CsrSdioFunctionDriver struct.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *----------------------------------------------------------------------------*/
+typedef void (*CsrSdioSuspendCallback)(CsrSdioFunction *function);
+typedef void (*CsrSdioResumeCallback)(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioAsyncCallback, CsrSdioAsyncDsrCallback
+ *
+ *  DESCRIPTION
+ *      CsrSdioAsyncCallback is called when an asynchronous operation completes.
+ *
+ *      NOTE: These functions are implemented by the Function Driver, and are
+ *            passed as function pointers in the function calls that initiate
+ *            the operation.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      result - The result of the operation that completed. See the description
+ *               of the initiating function for possible result values.
+ *
+ *  RETURNS (only CsrSdioAsyncCallback)
+ *      A pointer to a CsrSdioAsyncDsrCallback function.
+ *
+ *----------------------------------------------------------------------------*/
+typedef void (*CsrSdioAsyncDsrCallback)(CsrSdioFunction *function, CsrResult result);
+typedef CsrSdioAsyncDsrCallback (*CsrSdioAsyncCallback)(CsrSdioFunction *function, CsrResult result);
+
+typedef struct
+{
+    CsrSdioInsertedCallback     inserted;
+    CsrSdioRemovedCallback      removed;
+    CsrSdioInterruptCallback    intr;
+    CsrSdioSuspendCallback      suspend;
+    CsrSdioResumeCallback       resume;
+    CsrSdioFunctionId           *ids;
+    CsrUint8                    idsCount;
+    void                        *priv;
+} CsrSdioFunctionDriver;
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunctionDriverRegister
+ *
+ *  DESCRIPTION
+ *      Register a Function Driver.
+ *
+ *  PARAMETERS
+ *      functionDriver - Pointer to struct describing the Function Driver.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The Function Driver was successfully
+ *                           registered.
+ *      CSR_RESULT_FAILURE - Unable to register the function driver,
+ *                                because of an unspecified/unknown error. The
+ *                                Function Driver has not been registered.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - The specified Function Driver pointer
+ *                                      does not point at a valid Function
+ *                                      Driver structure, or some of the members
+ *                                      contain invalid entries.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioFunctionDriverRegister(CsrSdioFunctionDriver *functionDriver);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunctionDriverUnregister
+ *
+ *  DESCRIPTION
+ *      Unregister a previously registered Function Driver.
+ *
+ *  PARAMETERS
+ *      functionDriver - pointer to struct describing the Function Driver.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSdioFunctionDriverUnregister(CsrSdioFunctionDriver *functionDriver);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunctionEnable, CsrSdioFunctionDisable
+ *
+ *  DESCRIPTION
+ *      Enable/disable the specified function by setting/clearing the
+ *      corresponding bit in the I/O Enable register in function 0, and then
+ *      periodically reading the related bit in the I/O Ready register until it
+ *      is set/clear, limited by an implementation defined timeout.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The specified function was enabled/disabled.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. The state of the
+ *                                  related bit in the I/O Enable register is
+ *                                  undefined.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device, or the related
+ *                                bit in the I/O ready register was not
+ *                                set/cleared within the timeout period.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioFunctionEnable(CsrSdioFunction *function);
+CsrResult CsrSdioFunctionDisable(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioInterruptEnable, CsrSdioInterruptDisable
+ *
+ *  DESCRIPTION
+ *      Enable/disable the interrupt for the specified function by
+ *      setting/clearing the corresponding bit in the INT Enable register in
+ *      function 0.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The specified function was enabled/disabled.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. The state of the
+ *                                  related bit in the INT Enable register is
+ *                                  unchanged.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - The specified function cannot be
+ *                                      enabled/disabled, because it either
+ *                                      does not exist or it is not possible to
+ *                                      individually enable/disable functions.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioInterruptEnable(CsrSdioFunction *function);
+CsrResult CsrSdioInterruptDisable(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioInterruptAcknowledge
+ *
+ *  DESCRIPTION
+ *      Acknowledge that a signalled interrupt has been handled. Shall only
+ *      be called once, and exactly once for each signalled interrupt to the
+ *      corresponding function.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function to which the
+ *                 event was signalled.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSdioInterruptAcknowledge(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioInsertedAcknowledge, CsrSdioRemovedAcknowledge
+ *
+ *  DESCRIPTION
+ *      Acknowledge that a signalled inserted/removed event has been handled.
+ *      Shall only be called once, and exactly once for each signalled event to
+ *      the corresponding function.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function to which the
+ *                 inserted was signalled.
+ *      result (CsrSdioInsertedAcknowledge only)
+ *          CSR_RESULT_SUCCESS - The Function Driver has accepted the
+ *                                    function, and the function is attached to
+ *                                    the Function Driver until the
+ *                                    CsrSdioRemovedCallback is called and
+ *                                    acknowledged.
+ *          CSR_RESULT_FAILURE - Unable to accept the function. The
+ *                                    function is not attached to the Function
+ *                                    Driver, and it may be passed to another
+ *                                    Function Driver which supports the
+ *                                    function.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSdioInsertedAcknowledge(CsrSdioFunction *function, CsrResult result);
+void CsrSdioRemovedAcknowledge(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioSuspendAcknowledge, CsrSdioResumeAcknowledge
+ *
+ *  DESCRIPTION
+ *      Acknowledge that a signalled suspend event has been handled. Shall only
+ *      be called once, and exactly once for each signalled event to the
+ *      corresponding function.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function to which the
+ *                 event was signalled.
+ *      result
+ *          CSR_RESULT_SUCCESS - Successfully suspended/resumed.
+ *          CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSdioSuspendAcknowledge(CsrSdioFunction *function, CsrResult result);
+void CsrSdioResumeAcknowledge(CsrSdioFunction *function, CsrResult result);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioBlockSizeSet
+ *
+ *  DESCRIPTION
+ *      Set the block size to use for the function. The actual configured block
+ *      size shall be the minimum of:
+ *          1) Maximum block size supported by the function.
+ *          2) Maximum block size supported by the host controller.
+ *          3) The block size specified by the blockSize argument.
+ *
+ *      When this function returns, the actual configured block size is
+ *      available in the blockSize member of the function struct.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      blockSize - Block size to use for the function. Valid range is 1 to
+ *                  2048.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The block size register on the chip
+ *                                was updated.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. The configured block
+ *                                  size is undefined.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and the FUNCTION_NUMBER
+ *            bits is set, CSR_SDIO_RESULT_INVALID_VALUE shall be returned.
+ *            If the ERROR bit is set (but not FUNCTION_NUMBER),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *      NOTE: Setting the block size requires two individual operations. The
+ *            implementation shall ignore the OUT_OF_RANGE bit of the SDIO R5
+ *            response for the first operation, as the partially configured
+ *            block size may be out of range, even if the final block size
+ *            (after the second operation) is in the valid range.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioBlockSizeSet(CsrSdioFunction *function, CsrUint16 blockSize);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioMaxBusClockFrequencySet
+ *
+ *  DESCRIPTION
+ *      Set the maximum clock frequency to use for the device associated with
+ *      the specified function. The actual configured clock frequency for the
+ *      device shall be the minimum of:
+ *          1) Maximum clock frequency supported by the device.
+ *          2) Maximum clock frequency supported by the host controller.
+ *          3) Maximum clock frequency specified for any function on the same
+ *             device.
+ *
+ *      If the clock frequency exceeds 25MHz, it is the responsibility of the
+ *      SDIO driver to enable high speed mode on the device, using the standard
+ *      defined procedure, before increasing the frequency beyond the limit.
+ *
+ *      Note that the clock frequency configured affects all functions on the
+ *      same device.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      maxFrequency - The maximum clock frequency for the function in Hertz.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The maximum clock frequency was succesfully
+ *                                set for the function.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *
+ *      NOTE: If the SDIO R5 response is available, and the FUNCTION_NUMBER
+ *            bits is set, CSR_SDIO_RESULT_INVALID_VALUE shall be returned.
+ *            If the ERROR bit is set (but not FUNCTION_NUMBER),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioMaxBusClockFrequencySet(CsrSdioFunction *function, CsrUint32 maxFrequency);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioRead8, CsrSdioWrite8, CsrSdioRead8Async, CsrSdioWrite8Async
+ *
+ *  DESCRIPTION
+ *      Read/write an 8bit value from/to the specified register address.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      address - Register address within the function.
+ *      data - The data to read/write.
+ *      callback - The function to call on operation completion.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The data was successfully read/written.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. No data read/written.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *      NOTE: The CsrSdioRead8Async and CsrSdioWrite8Async functions return
+ *            immediately, and the supplied callback function is called when the
+ *            operation is complete. The result value is given as an argument to
+ *            the callback function.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioRead8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data);
+CsrResult CsrSdioWrite8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data);
+void CsrSdioRead8Async(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data, CsrSdioAsyncCallback callback);
+void CsrSdioWrite8Async(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data, CsrSdioAsyncCallback callback);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioRead16, CsrSdioWrite16, CsrSdioRead16Async, CsrSdioWrite16Async
+ *
+ *  DESCRIPTION
+ *      Read/write a 16bit value from/to the specified register address.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      address - Register address within the function.
+ *      data - The data to read/write.
+ *      callback - The function to call on operation completion.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The data was successfully read/written.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. Data may have been
+ *                                  partially read/written.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *      NOTE: The CsrSdioRead16Async and CsrSdioWrite16Async functions return
+ *            immediately, and the supplied callback function is called when the
+ *            operation is complete. The result value is given as an argument to
+ *            the callback function.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioRead16(CsrSdioFunction *function, CsrUint32 address, CsrUint16 *data);
+CsrResult CsrSdioWrite16(CsrSdioFunction *function, CsrUint32 address, CsrUint16 data);
+void CsrSdioRead16Async(CsrSdioFunction *function, CsrUint32 address, CsrUint16 *data, CsrSdioAsyncCallback callback);
+void CsrSdioWrite16Async(CsrSdioFunction *function, CsrUint32 address, CsrUint16 data, CsrSdioAsyncCallback callback);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioF0Read8, CsrSdioF0Write8, CsrSdioF0Read8Async,
+ *      CsrSdioF0Write8Async
+ *
+ *  DESCRIPTION
+ *      Read/write an 8bit value from/to the specified register address in
+ *      function 0.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      address - Register address within the function.
+ *      data - The data to read/write.
+ *      callback - The function to call on operation completion.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The data was successfully read/written.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. No data read/written.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *      NOTE: The CsrSdioF0Read8Async and CsrSdioF0Write8Async functions return
+ *            immediately, and the supplied callback function is called when the
+ *            operation is complete. The result value is given as an argument to
+ *            the callback function.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioF0Read8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data);
+CsrResult CsrSdioF0Write8(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data);
+void CsrSdioF0Read8Async(CsrSdioFunction *function, CsrUint32 address, CsrUint8 *data, CsrSdioAsyncCallback callback);
+void CsrSdioF0Write8Async(CsrSdioFunction *function, CsrUint32 address, CsrUint8 data, CsrSdioAsyncCallback callback);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioRead, CsrSdioWrite, CsrSdioReadAsync, CsrSdioWriteAsync
+ *
+ *  DESCRIPTION
+ *      Read/write a specified number of bytes from/to the specified register
+ *      address.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *      address - Register address within the function.
+ *      data - The data to read/write.
+ *      length - Number of byte to read/write.
+ *      callback - The function to call on operation completion.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - The data was successfully read/written.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. Data may have been
+ *                                  partially read/written.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device.
+ *
+ *      NOTE: If the SDIO R5 response is available, and either of the
+ *            FUNCTION_NUMBER or OUT_OF_RANGE bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE shall be returned. If the ERROR bit
+ *            is set (but none of FUNCTION_NUMBER or OUT_OF_RANGE),
+ *            CSR_RESULT_FAILURE shall be returned. The ILLEGAL_COMMAND and
+ *            COM_CRC_ERROR bits shall be ignored.
+ *
+ *            If the CSPI response is available, and any of the
+ *            FUNCTION_DISABLED or CLOCK_DISABLED bits are set,
+ *            CSR_SDIO_RESULT_INVALID_VALUE will be returned.
+ *
+ *      NOTE: The CsrSdioF0Read8Async and CsrSdioF0Write8Async functions return
+ *            immediately, and the supplied callback function is called when the
+ *            operation is complete. The result value is given as an argument to
+ *            the callback function.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioRead(CsrSdioFunction *function, CsrUint32 address, void *data, CsrUint32 length);
+CsrResult CsrSdioWrite(CsrSdioFunction *function, CsrUint32 address, const void *data, CsrUint32 length);
+void CsrSdioReadAsync(CsrSdioFunction *function, CsrUint32 address, void *data, CsrUint32 length, CsrSdioAsyncCallback callback);
+void CsrSdioWriteAsync(CsrSdioFunction *function, CsrUint32 address, const void *data, CsrUint32 length, CsrSdioAsyncCallback callback);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioPowerOn, CsrSdioPowerOff
+ *
+ *  DESCRIPTION
+ *      Power on/off the device.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function that resides on
+ *                 the device to power on/off.
+ *
+ *  RETURNS (only CsrSdioPowerOn)
+ *      CSR_RESULT_SUCCESS - Power was succesfully reapplied and the device
+ *                                has been reinitialised.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured during reinitialisation.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device during
+ *                                reinitialisation.
+ *      CSR_SDIO_RESULT_NOT_RESET - The power was not removed by the
+ *                                  CsrSdioPowerOff call. The state of the
+ *                                  device is unchanged.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioPowerOn(CsrSdioFunction *function);
+void CsrSdioPowerOff(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioHardReset
+ *
+ *  DESCRIPTION
+ *      Perform a hardware reset of the device.
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function that resides on
+ *                 the device to hard reset.
+ *
+ *  RETURNS
+ *      CSR_RESULT_SUCCESS - Reset was succesfully performed and the device
+ *                                has been reinitialised.
+ *      CSR_RESULT_FAILURE - Unspecified/unknown error.
+ *      CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
+ *      CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured during reinitialisation.
+ *      CSR_SDIO_RESULT_TIMEOUT - No response from the device during
+ *                                reinitialisation.
+ *      CSR_SDIO_RESULT_NOT_RESET - The reset was not applied because it is not
+ *                                  supported. The state of the device is
+ *                                  unchanged.
+ *
+ *----------------------------------------------------------------------------*/
+CsrResult CsrSdioHardReset(CsrSdioFunction *function);
+
+/*----------------------------------------------------------------------------*
+ *  NAME
+ *      CsrSdioFunctionActive, CsrSdioFunctionIdle
+ *
+ *  DESCRIPTION
+ *
+ *  PARAMETERS
+ *      function - Pointer to struct representing the function.
+ *
+ *----------------------------------------------------------------------------*/
+void CsrSdioFunctionActive(CsrSdioFunction *function);
+void CsrSdioFunctionIdle(CsrSdioFunction *function);
+
+void CsrSdioCallbackInhibitEnter(CsrSdioFunction *function);
+void CsrSdioCallbackInhibitLeave(CsrSdioFunction *function);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/staging/csr/sdioemb/csr_sdio_lib.h b/drivers/staging/csr/sdioemb/csr_sdio_lib.h
new file mode 100644
index 0000000..15c70f6
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/csr_sdio_lib.h
@@ -0,0 +1,30 @@
+/*
+ * Synergy compatible API -- SDIO utility library.
+ *
+ * Copyright (C) 2010 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef CSR_SDIO_LIB_H__
+#define CSR_SDIO_LIB_H__
+
+#include <csr_sdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CsrResult CsrSdioFunctionReenable(CsrSdioFunction *function);
+
+typedef int CsrStatus; /* platform specific */
+#define CSR_STATUS_FAILURE(status) ((status) < 0) /* platform specific */
+
+CsrResult CsrSdioStatusToResult(CsrStatus status);
+CsrStatus CsrSdioResultToStatus(CsrResult result);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef CSR_SDIO_LIB_H__ */
diff --git a/drivers/staging/csr/sdioemb/csr_sdio_wdf.h b/drivers/staging/csr/sdioemb/csr_sdio_wdf.h
new file mode 100644
index 0000000..6f0d71c
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/csr_sdio_wdf.h
@@ -0,0 +1,22 @@
+/*
+ * Synergy compatible API -- helpers for Windows Driver Framework drivers.
+ *
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef CSR_SDIO_WDF_H__
+#define CSR_SDIO_WDF_H__
+
+#include <wdf.h>
+
+NTSTATUS CsrSdioWdfDeviceInit(WDFDEVICE device);
+void CsrSdioWdfDeviceCleanup(WDFDEVICE device);
+
+NTSTATUS CsrSdioWdfDeviceAdd(WDFDEVICE device);
+void CsrSdioWdfDeviceDel(WDFDEVICE device);
+
+NTSTATUS CsrSdioWdfDeviceSuspend(WDFDEVICE device);
+NTSTATUS CsrSdioWdfDeviceResume(WDFDEVICE device);
+
+#endif /* #ifndef CSR_SDIO_WDF_H__ */
diff --git a/drivers/staging/csr/sdioemb/csr_types.h b/drivers/staging/csr/sdioemb/csr_types.h
new file mode 100644
index 0000000..c0d95b3
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/csr_types.h
@@ -0,0 +1,53 @@
+/*
+ * Synergy compatible API -- basic types.
+ *
+ * Copyright (C) 2010 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef CSR_TYPES_H__
+#define CSR_TYPES_H__
+
+#include <oska/types.h>
+
+#ifndef FALSE
+#define FALSE false
+#endif
+
+#ifndef TRUE
+#define TRUE true
+#endif
+
+/* Data types */
+
+typedef size_t                  CsrSize;
+
+typedef uint8_t                 CsrUint8;
+typedef uint16_t                CsrUint16;
+typedef uint32_t                CsrUint32;
+
+typedef int8_t                  CsrInt8;
+typedef int16_t                 CsrInt16;
+typedef int32_t                 CsrInt32;
+
+typedef bool                    CsrBool;
+
+typedef char                    CsrCharString;
+typedef unsigned char           CsrUtf8String;
+typedef CsrUint16               CsrUtf16String; /* 16-bit UTF16 strings */
+typedef CsrUint32               CsrUint24;
+
+/*
+ * 64-bit integers
+ *
+ * Note: If a given compiler does not support 64-bit types, it is
+ * OK to omit these definitions;  32-bit versions of the code using
+ * these types may be available.  Consult the relevant documentation
+ * or the customer support group for information on this.
+ */
+#define CSR_HAVE_64_BIT_INTEGERS
+typedef uint64_t    CsrUint64;
+typedef int64_t     CsrInt64;
+
+#endif
diff --git a/drivers/staging/csr/sdioemb/libsdio.h b/drivers/staging/csr/sdioemb/libsdio.h
new file mode 100644
index 0000000..29ac411
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/libsdio.h
@@ -0,0 +1,404 @@
+/*
+ * SDIO Userspace Interface library.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef SDIOEMB_LIBSDIO_H
+#define SDIOEMB_LIBSDIO_H
+
+/**
+ * \defgroup libsdio Userspace SDIO library (libsdio)
+ *
+ * \brief \e libsdio is a Linux C library for accessing SDIO cards.
+ *
+ * Use of this library requires several \e sdioemb kernel modules to be
+ * loaded:
+ *   - \c sdio.
+ *   - \c An SDIO slot driver (e.g., \c slot_shc for a standard PCI
+ *     SDIO Host Controller).
+ *   - \c sdio_uif which provides the required character devices
+ *     (/dev/sdio_uif0 for the card in SDIO slot 0 etc.).
+ */
+/*@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+#  define LIBSDIOAPI __stdcall
+#else
+#  define LIBSDIOAPI
+#endif
+
+struct sdio_uif;
+
+/**
+ * Handle to an opened SDIO Userspace Interface device.
+ */
+typedef struct sdio_uif *sdio_uif_t;
+
+enum sdio_status {
+    SDIO_SUCCESS   = 0,
+    SDIO_EAGAIN    = -1,
+    SDIO_EINVAL    = -2,
+    SDIO_EIO       = -3,
+    SDIO_ENODEV    = -4,
+    SDIO_ENOMEM    = -5,
+    SDIO_ENOTSUPP  = -6,
+    SDIO_ENXIO     = -7,
+    SDIO_ETIMEDOUT = -8,
+};
+
+/**
+ * Card interrupt handler function.
+ *
+ * @param uif handle to the interrupting device.
+ * @param arg data supplied by the caller of sdio_open().
+ */
+typedef void (LIBSDIOAPI *sdio_int_handler_t)(sdio_uif_t uif, void *arg);
+
+/**
+ * Asynchronous IO completion callback function.
+ *
+ * @param uif    handle to the device that completed the IO operation.
+ * @param arg    data supplied by the caller of the asynchronous IO operation.
+ * @param status status of the IO operation. 0 is success; -EIO,
+ *               -EINVAL, -ETIMEDOUT etc. on an error.
+ */
+typedef void (LIBSDIOAPI *sdio_io_callback_t)(sdio_uif_t uif, void *arg, int status);
+
+/**
+ * Open a SDIO Userspace Interface device and (optionally) register a
+ * card interrupt handler and enable card interrupts.
+ *
+ * Card interrupts are masked before calling int_handler and are
+ * unmasked when int_handler returns (unless sdio_interrupt_mask() is
+ * called).
+ *
+ * @param dev_filename  filename of the device to open.
+ * @param int_handler   card interrupt handler; or NULL if no
+ *                      interrupt handler is required.
+ * @param arg           argument to be passed to the interrupt handler.
+ *
+ * @return handle to the opened device; or NULL on error with errno
+ * set.
+ */
+sdio_uif_t LIBSDIOAPI sdio_open(const char *dev_filename,
+                                sdio_int_handler_t int_handler, void *arg);
+
+/**
+ * Mask the SDIO interrupt.
+ *
+ * Call this in an interrupt handler to allow the processing of
+ * interrupts to be deferred until after the interrupt handler has
+ * returned.
+ *
+ * @note \e Must only be called from within the interrupt handler
+ * registered with sdio_open().
+ *
+ * @param uif device handle.
+ */
+void LIBSDIOAPI sdio_interrupt_mask(sdio_uif_t uif);
+
+/**
+ * Unmask the SDIO interrupt.
+ *
+ * Unmasks the SDIO interrupt if it had previously been masked with
+ * sdio_interrupt_mask().
+ *
+ * @param uif device handle.
+ */
+void LIBSDIOAPI sdio_interrupt_unmask(sdio_uif_t uif);
+
+/**
+ * Close an opened SDIO Userspace Interface device, freeing all
+ * associated resources.
+ *
+ * @param uif handle to the device.
+ */
+void LIBSDIOAPI sdio_close(sdio_uif_t uif);
+
+/**
+ * Return the number of functions the card has.
+ *
+ * @param uif device handle.
+ *
+ * @return number of card functions.
+ */
+int LIBSDIOAPI sdio_num_functions(sdio_uif_t uif);
+
+/**
+ * Set an SDIO bus to 1 bit or 4 bit wide mode.
+ *
+ * The CCCR bus interface control register will be read and rewritten
+ * with the new bus width.
+ *
+ * @param uif       device handle.
+ * @param bus_width bus width (1 or 4).
+ *
+ * @return 0 on success; -ve on error with errno set.
+ *
+ * @note The card capabilities are \e not checked.  The user should
+ * ensure 4 bit mode is not enabled on a card that does not support
+ * it.
+ */
+int LIBSDIOAPI sdio_set_bus_width(sdio_uif_t uif, int bus_width);
+
+/**
+ * Limit the frequency of (or stop) the SD bus clock.
+ *
+ * The frequency cannot be set greater than that supported by the card
+ * or the controller.
+ *
+ * @note Stopping the bus clock while other device drivers are
+ * executing commands may result in those commands not completing
+ * until the bus clock is restarted.
+ *
+ * @param uif      device handle.
+ * @param max_freq maximum frequency (Hz) or 0 to stop the bus clock
+ *                 until the start of the next command.
+ */
+void LIBSDIOAPI sdio_set_max_bus_freq(sdio_uif_t uif, int max_freq);
+
+/**
+ * Return the card's manufacturer (vendor) ID.
+ *
+ * @param uif device handle.
+ *
+ * @return manufacturer ID.
+ */
+uint16_t LIBSDIOAPI sdio_manf_id(sdio_uif_t uif);
+
+/**
+ * Return the card's card (device) ID.
+ *
+ * @param uif device handle.
+ *
+ * @return card ID.
+ */
+uint16_t LIBSDIOAPI sdio_card_id(sdio_uif_t uif);
+
+/**
+ * Return the standard interface code for a function.
+ *
+ * @param uif  device handle.
+ * @param func card function to query.
+ *
+ * @return the standard interface.
+ */
+uint8_t LIBSDIOAPI sdio_std_if(sdio_uif_t uif, int func);
+
+/**
+ * Return a function's maximum supported block size.
+ *
+ * @param uif  device handle.
+ * @param func card function to query.
+ *
+ * @return maximum block size.
+ */
+int LIBSDIOAPI sdio_max_block_size(sdio_uif_t uif, int func);
+
+/**
+ * Return a function's current block size.
+ *
+ * @note This returns the driver's view of the block size and not the
+ * value in the function's block size register.
+ *
+ * @param uif  device handle.
+ * @param func card function to query.
+ *
+ * @return the current block size.
+ */
+int LIBSDIOAPI sdio_block_size(sdio_uif_t uif, int func);
+
+/**
+ * Set a function's block size.
+ *
+ * The function's block size registers will be written if necessary.
+ *
+ * @param uif   device handle.
+ * @param func  function to modify.
+ * @param blksz the new block size; or 0 for the default size.
+ *
+ * @return 0 on success; or -ve on error with errno set.
+ */
+int LIBSDIOAPI sdio_set_block_size(sdio_uif_t uif, int func, int blksz);
+
+/**
+ * Read an 8 bit register.
+ *
+ * @param uif  device handle.
+ * @param func card function.
+ * @param addr register address.
+ * @param data the data read.
+ *
+ * @return 0 on success; or -ve on error with errno set.
+ */
+int LIBSDIOAPI sdio_read8(sdio_uif_t uif, int func, uint32_t addr, uint8_t *data);
+
+/**
+ * Write an 8 bit register.
+ *
+ * @param uif  device handle.
+ * @param func card function.
+ * @param addr register address.
+ * @param data the data to write.
+ *
+ * @return 0 on success; or -ve on error with errno set.
+ */
+int LIBSDIOAPI sdio_write8(sdio_uif_t uif, int func, uint32_t addr, uint8_t data);
+
+/**
+ * Read a buffer from a 8 bit wide register/FIFO.
+ *
+ * The buffer read uses a fixed (not incrementing) address.
+ *
+ * \a block_size \e must be set to the value writted into \a func's
+ * I/O block size FBR register.
+ *
+ * If \a len % \a block_size == 0, a block mode transfer is used; a
+ * byte mode transfer is used if \a len < \a block_size.
+ *
+ * @param uif        device handle.
+ * @param func       card function.
+ * @param addr       register/FIFO address.
+ * @param data       buffer to store the data read.
+ * @param len        length of data to read.
+ * @param block_size block size to use for this transfer.
+ *
+ * @return 0 on success; or -ve on error with errno set.
+ */
+int LIBSDIOAPI sdio_read(sdio_uif_t uif, int func, uint32_t addr, uint8_t *data,
+                      size_t len, int block_size);
+
+/**
+ * Write a buffer to an 8 bit wide register/FIFO.
+ *
+ * The buffer write uses a fixed (not incrementing) address.
+ *
+ * \a block_size \e must be set to the value writted into \a func's
+ * I/O block size FBR register.
+ *
+ * If \a len % \a block_size == 0, a block mode transfer is used; a
+ * byte mode transfer is used if \a len < \a block_size.
+ *
+ * @param uif        device handle.
+ * @param func       card function.
+ * @param addr       register/FIFO address.
+ * @param data       buffer of data to write.
+ * @param len        length of the data to write.
+ * @param block_size block size to use for this transfer.
+ *
+ * @return 0 on success; or -ve on error with errno set.
+ */
+int LIBSDIOAPI sdio_write(sdio_uif_t uif, int func, uint32_t addr, const uint8_t *data,
+                          size_t len, int block_size);
+
+/**
+ * Read an 8 bit register, without waiting for completion.
+ *
+ * @param uif      device handle.
+ * @param func     card function.
+ * @param addr     register address.
+ * @param data     the data read.
+ * @param callback function to be called when the read completes.
+ * @param arg      argument to be passed to callback.
+ *
+ * @return 0 on success; or -ve on error with errno set.
+ */
+int LIBSDIOAPI sdio_read8_async(sdio_uif_t uif, int func, uint32_t addr, uint8_t *data,
+                                sdio_io_callback_t callback, void *arg);
+
+/**
+ * Write an 8 bit register, without waiting for completion.
+ *
+ * @param uif      device handle.
+ * @param func     card function.
+ * @param addr     register address.
+ * @param data     the data to write.
+ * @param callback function to be called when the write completes.
+ * @param arg      argument to be passed to callback.
+ *
+ * @return 0 on success; or -ve on error with errno set.
+ */
+int LIBSDIOAPI sdio_write8_async(sdio_uif_t uif, int func, uint32_t addr, uint8_t data,
+                                 sdio_io_callback_t callback, void *arg);
+
+/**
+ * Read a buffer from a 8 bit wide register/FIFO, without waiting for
+ * completion.
+ *
+ * The buffer read uses a fixed (not incrementing) address.
+ *
+ * \a block_size \e must be set to the value writted into \a func's
+ * I/O block size FBR register.
+ *
+ * If \a len % \a block_size == 0, a block mode transfer is used; a
+ * byte mode transfer is used if \a len < \a block_size.
+ *
+ * @param uif        device handle.
+ * @param func       card function.
+ * @param addr       register/FIFO address.
+ * @param data       buffer to store the data read.
+ * @param len        length of data to read.
+ * @param block_size block size to use for this transfer.
+ * @param callback   function to be called when the read completes.
+ * @param arg        argument to be passed to callback.
+ *
+ * @return 0 on success; or -ve on error with errno set.
+ */
+int LIBSDIOAPI sdio_read_async(sdio_uif_t uif, int func, uint32_t addr, uint8_t *data,
+                               size_t len, int block_size,
+                               sdio_io_callback_t callback, void *arg);
+
+/**
+ * Write a buffer to an 8 bit wide register/FIFO, without waiting for
+ * completion.
+ *
+ * The buffer write uses a fixed (not incrementing) address.
+ *
+ * \a block_size \e must be set to the value writted into \a func's
+ * I/O block size FBR register.
+ *
+ * If \a len % \a block_size == 0, a block mode transfer is used; a
+ * byte mode transfer is used if \a len < \a block_size.
+ *
+ * @param uif        device handle.
+ * @param func       card function.
+ * @param addr       register/FIFO address.
+ * @param data       buffer of data to write.
+ * @param len        length of the data to write.
+ * @param block_size block size to use for this transfer.
+ * @param callback   function to be called when the write completes.
+ * @param arg        argument to be passed to callback.
+ *
+ * @return 0 on success; or -ve on error with errno set.
+ */
+int LIBSDIOAPI sdio_write_async(sdio_uif_t uif, int func, uint32_t addr, const uint8_t *data,
+                                size_t len, int block_size,
+                                sdio_io_callback_t callback, void *arg);
+/**
+ * Force a card removal and reinsertion.
+ *
+ * This will power cycle the card if the slot hardware supports power
+ * control.
+ *
+ * @note The device handle will no longer be valid.
+ *
+ * @param uif device handle.
+ *
+ * @return 0 on success; or -ve on error with errno set.
+ */
+int LIBSDIOAPI sdio_reinsert_card(sdio_uif_t uif);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+/*@}*/
+
+#endif /* #ifndef SDIOEMB_LIBSDIO_H */
diff --git a/drivers/staging/csr/sdioemb/linux.h b/drivers/staging/csr/sdioemb/linux.h
new file mode 100644
index 0000000..f574f71
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/linux.h
@@ -0,0 +1,16 @@
+/*
+ * Linux helpers for slot drivers.
+ *
+ * Copyright (C) 2009 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef SDIOEMB_LINUX_H
+#define SDIOEMB_LINUX_H
+
+#include <sdioemb/slot_api.h>
+
+int sdioemb_linux_slot_register(struct sdioemb_slot *slot);
+
+#endif /* #ifndef SDIOEMB_LINUX_H */
diff --git a/drivers/staging/csr/sdioemb/sdio.h b/drivers/staging/csr/sdioemb/sdio.h
new file mode 100644
index 0000000..50bb8fd
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/sdio.h
@@ -0,0 +1,117 @@
+/*
+ * Standard SDIO definitions.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef SDIOEMB_SDIO_H
+#define SDIOEMB_SDIO_H
+
+/* Maximum time for VDD to rise to VDD min. */
+#define SDIO_POWER_UP_TIME_MS 250
+
+/* Minimum SD bus clock a card must support (Hz). */
+#define SDIO_CLOCK_FREQ_MIN 400000
+
+/* Maximum clock frequency for normal mode (Hz).
+ *
+ * Although high speed mode should be suitable for all speeds not all
+ * controller/card combinations are capable of meeting the higher
+ * tolerances for (e.g.) clock rise/fall times.  Therefore, default
+ * mode is used where possible for improved compatibility. */
+#define SDIO_CLOCK_FREQ_NORMAL_SPD 25000000
+
+/* Maximum clock frequency for high speed mode (Hz). */
+#define SDIO_CLOCK_FREQ_HIGH_SPD   50000000
+
+#define SDIO_MAX_FUNCTIONS 8 /* incl. F0 */
+
+/* Command argument format. */
+
+#define SDIO_CMD52_ARG_WRITE   0x80000000
+#define SDIO_CMD52_ARG_FUNC(f) ((f) << 28)
+#define SDIO_CMD52_ARG_ADDR(a) ((a) << 9)
+#define SDIO_CMD52_ARG_DATA(d) ((d) << 0)
+
+#define SDIO_CMD53_ARG_WRITE    0x80000000
+#define SDIO_CMD53_ARG_FUNC(f)  ((f) << 28)
+#define SDIO_CMD53_ARG_BLK_MODE 0x08000000
+#define SDIO_CMD53_ARG_ADDR(a)  ((a) << 9)
+#define SDIO_CMD53_ARG_CNT(c)   ((c) << 0)
+
+/* Response format. */
+
+#define SDIO_R5_DATA(r) (((r) >> 0) & 0xff)
+#define SDIO_R5_OUT_OF_RANGE    (1 <<  8)
+#define SDIO_R5_FUNCTION_NUMBER (1 <<  9)
+#define SDIO_R5_ERROR           (1 << 11)
+
+/* Register offsets and bits. */
+
+#define SDIO_OCR_CARD_READY     0x80000000
+#define SDIO_OCR_NUM_FUNCS_MASK 0x70000000
+#define SDIO_OCR_NUM_FUNCS_OFFSET 28
+#define SDIO_OCR_VOLTAGE_3V3    0x00300000 /* 3.2-3.3V & 3.3-3.4V */
+
+#define SDIO_CCCR_SDIO_REV       0x00
+#define SDIO_CCCR_SD_REV         0x01
+#define SDIO_CCCR_IO_EN          0x02
+#define SDIO_CCCR_IO_READY       0x03
+#define SDIO_CCCR_INT_EN         0x04
+#  define SDIO_CCCR_INT_EN_MIE   0x01
+#define SDIO_CCCR_INT_PENDING    0x05
+#define SDIO_CCCR_IO_ABORT       0x06
+#define SDIO_CCCR_BUS_IFACE_CNTL 0x07
+#  define SDIO_CCCR_BUS_IFACE_CNTL_CD_R_DISABLE 0x80
+#  define SDIO_CCCR_BUS_IFACE_CNTL_ECSI         0x20
+#  define SDIO_CCCR_BUS_IFACE_CNTL_4BIT_BUS     0x02
+#define SDIO_CCCR_CARD_CAPS      0x08
+#  define SDIO_CCCR_CARD_CAPS_LSC  0x40
+#  define SDIO_CCCR_CARD_CAPS_4BLS 0x80
+#define SDIO_CCCR_CIS_PTR        0x09
+#define SDIO_CCCR_BUS_SUSPEND    0x0c
+#define SDIO_CCCR_FUNC_SEL       0x0d
+#define SDIO_CCCR_EXEC_FLAGS     0x0e
+#define SDIO_CCCR_READY_FLAGS    0x0f
+#define SDIO_CCCR_F0_BLK_SIZE    0x10
+#define SDIO_CCCR_PWR_CNTL       0x12
+#define SDIO_CCCR_HIGH_SPEED     0x13
+#  define SDIO_CCCR_HIGH_SPEED_SHS 0x01
+#  define SDIO_CCCR_HIGH_SPEED_EHS 0x02
+
+#define SDIO_FBR_REG(f, r) (0x100*(f) + (r))
+
+#define SDIO_FBR_STD_IFACE(f)     SDIO_FBR_REG(f, 0x00)
+#define SDIO_FBR_STD_IFACE_EXT(f) SDIO_FBR_REG(f, 0x01)
+#define SDIO_FBR_CIS_PTR(f)       SDIO_FBR_REG(f, 0x09)
+#define SDIO_FBR_CSA_PTR(f)       SDIO_FBR_REG(f, 0x0c)
+#define SDIO_FBR_CSA_DATA(f)      SDIO_FBR_REG(f, 0x0f)
+#define SDIO_FBR_BLK_SIZE(f)      SDIO_FBR_REG(f, 0x10)
+
+#define SDIO_STD_IFACE_UART      0x01
+#define SDIO_STD_IFACE_BT_TYPE_A 0x02
+#define SDIO_STD_IFACE_BT_TYPE_B 0x03
+#define SDIO_STD_IFACE_GPS       0x04
+#define SDIO_STD_IFACE_CAMERA    0x05
+#define SDIO_STD_IFACE_PHS       0x06
+#define SDIO_STD_IFACE_WLAN      0x07
+#define SDIO_STD_IFACE_BT_TYPE_A_AMP 0x09
+
+/*
+ * Manufacturer and card IDs.
+ */
+#define SDIO_MANF_ID_CSR        0x032a
+
+#define SDIO_CARD_ID_CSR_UNIFI_1        0x0001
+#define SDIO_CARD_ID_CSR_UNIFI_2        0x0002
+#define SDIO_CARD_ID_CSR_BC6            0x0004
+#define SDIO_CARD_ID_CSR_DASH_D00       0x0005
+#define SDIO_CARD_ID_CSR_BC7            0x0006
+#define SDIO_CARD_ID_CSR_CINDERELLA     0x0007
+#define SDIO_CARD_ID_CSR_UNIFI_3        0x0007
+#define SDIO_CARD_ID_CSR_UNIFI_4        0x0008
+#define SDIO_CARD_ID_CSR_DASH           0x0010
+
+#endif /* #ifndef SDIOEMB_SDIO_H */
diff --git a/drivers/staging/csr/sdioemb/sdio_api.h b/drivers/staging/csr/sdioemb/sdio_api.h
new file mode 100644
index 0000000..cd8aded
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/sdio_api.h
@@ -0,0 +1,408 @@
+/*
+ * SDIO device driver API.
+ *
+ * Copyright (C) 2007-2008 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef _SDIO_API_H
+#define _SDIO_API_H
+
+/**
+ * @defgroup fdriver SDIO function driver API
+ *
+ * @brief The SDIO function driver API is used to implement drivers
+ * for SDIO card functions.
+ *
+ * Function drivers register with the SDIO driver core
+ * (sdio_register_driver()), listing which functions it supports and
+ * providing callback functions for card inserts, removes and
+ * interrupts.
+ *
+ * @par \anchor card_io_ops Card I/O operations:
+ *
+ * - \link sdioemb_read8(struct sdioemb_dev *, uint32_t, uint8_t *) sdioemb_read8()\endlink
+ * - \link sdioemb_read16(struct sdioemb_dev *, uint32_t, uint16_t *) sdioemb_read16()\endlink
+ * - \link sdioemb_write8(struct sdioemb_dev *, uint32_t, uint8_t) sdioemb_write8()\endlink
+ * - \link sdioemb_write16(struct sdioemb_dev *, uint32_t, uint16_t) sdioemb_write16()\endlink
+ * - \link sdioemb_f0_read8(struct sdioemb_dev *, uint32_t, uint8_t *) sdioemb_f0_read8()\endlink
+ * - \link sdioemb_f0_write8(struct sdioemb_dev *, uint32_t, uint8_t) sdioemb_f0_write8()\endlink
+ * - \link sdioemb_read(struct sdioemb_dev *, uint32_t, void *, size_t) sdioemb_read()\endlink
+ * - \link sdioemb_write(struct sdioemb_dev *, uint32_t, const void *, size_t) sdioemb_write()\endlink
+ */
+
+struct sdioemb_func_driver;
+struct sdioemb_dev;
+struct sdioemb_dev_priv;
+
+/**
+ * An SDIO device.
+ *
+ * Each SDIO card will have an sdio_dev for each function.
+ *
+ * None of the fields (except for drv_data) should be written.
+ *
+ * @ingroup fdriver
+ */
+struct sdioemb_dev {
+    struct sdioemb_func_driver *driver;        /**< Function driver for this device. */
+    uint16_t                 vendor_id;     /**< Vendor ID of the card. */
+    uint16_t                 device_id;     /**< Device ID of the card. */
+    int                      function;      /**< Function number of this device. */
+    uint8_t                  interface;     /**< SDIO standard interface number. */
+    uint16_t                 max_blocksize; /**< Maximum block size supported. */
+    uint16_t                 blocksize;     /**< Blocksize in use. */
+    int                      slot_id;       /**< ID of the slot this card is inserted into. */
+    void *                   os_device;     /**< Pointer to an OS-specific device structure. */
+    struct sdioemb_dev_priv *priv;          /**< Data private to the SDIO core. */
+    void *                   drv_data;      /**< Data private to the function driver. */
+};
+
+#define SDIOEMB_ANY_ID    0xffff
+#define SDIOEMB_UIF_FUNC  0
+#define SDIOEMB_ANY_FUNC  0xff
+#define SDIOEMB_ANY_IFACE 0xff
+
+/**
+ * An entry for an SDIO device ID table.
+ *
+ * Functions are matched to drivers using any combination of vendor
+ * ID, device ID, function number or standard interface.
+ *
+ * Matching on #function == SDIOEMB_UIF_FUNC is reserved for the SDIO
+ * Userspace Interface driver. Card management drivers can match on
+ * #function == 0, these will be probed before any function drivers.
+ *
+ * @ingroup fdriver
+ */
+struct sdioemb_id_table {
+    uint16_t vendor_id; /**< Vendor ID to match or SDIOEMB_ANY_ID */
+    uint16_t device_id; /**< Device ID to match or SDIOEMB_ANY_ID */
+    int      function;  /**< Function number to match or SDIOEMB_ANY_FUNC */
+    uint8_t  interface; /**< SDIO standard interface to match or SDIOEMB_ANY_IFACE */
+};
+
+/**
+ * A driver for an SDIO function.
+ *
+ * @ingroup fdriver
+ */
+struct sdioemb_func_driver {
+    /**
+     * Driver name used in diagnostics.
+     */
+    const char *name;
+
+    /**
+     * 0 terminated array of functions supported by this device.
+     *
+     * The driver may (for example) match on a number of vendor
+     * ID/device ID/function number triplets or on an SDIO standard
+     * interface.
+     */
+    struct sdioemb_id_table *id_table;
+
+    /**
+     * Called by the core when an inserted card has functions which
+     * match those listed in id_table.
+     *
+     * The driver's implementation should (if required):
+     *
+     *   - perform any additional probing
+     *   - do function specific initialization
+     *   - allocate and register any function/OS specific devices or interfaces.
+     *
+     * Called in: thread context.
+     *
+     * @param fdev the newly inserted device.
+     *
+     * @return 0 on success; -ve on error.
+     */
+    int (*probe)(struct sdioemb_dev *fdev);
+
+    /**
+     * Called by the core when a card is removed.  This is only called
+     * if the probe() call succeeded.
+     *
+     * The driver's implementation should (if required);
+     *
+     *   - do any function specific shutdown.
+     *   - cleanup any data structures created/registers during probe().
+     *
+     * Called in: thread context.
+     *
+     * @param fdev the device being removed.
+     */
+    void (*remove)(struct sdioemb_dev *fdev);
+
+    /**
+     * Called by the core to signal an SDIO interrupt for this card
+     * occurs, if interrupts have been enabled with
+     * sdioemb_interrupt_enable().
+     *
+     * The driver's implementation should signal a thread (or similar)
+     * to actually handle the interrupt as no card I/O may be
+     * performed whilst in interrupt context. When the interrupt is
+     * handled, the driver should call sdioemb_interrupt_acknowledge() to
+     * enable further interrupts to be signalled.
+     *
+     * Called in: interrupt context.
+     *
+     * @param fdev the device which may have raised the interrupt.
+     */
+    void (*card_int_handler)(struct sdioemb_dev *fdev);
+
+    /**
+     * Called by the core to signal a suspend power management
+     * event occured.
+     *
+     * The driver's implementation should (if required)
+     * set the card to a low power mode and return as soon
+     * as possible. After this function returns, the
+     * driver should not start any SDIO commands.
+     *
+     * Called in: thread context.
+     *
+     * @param fdev the device handler.
+     */
+    void (*suspend)(struct sdioemb_dev *fdev);
+
+    /**
+     * Called by the core to signal a resume power management
+     * event occured.
+     *
+     * The driver's implementation should (if required)
+     * initialise the card to an operational mode and return
+     * as soon as possible. If the card has been powered off
+     * during suspend, the driver would have to initialise
+     * the card from scratch (f/w download, h/w initialisation, etc.).
+     *
+     * Called in: thread context.
+     *
+     * @param fdev the device handler.
+     */
+    void (*resume)(struct sdioemb_dev *fdev);
+};
+
+int  sdioemb_driver_register(struct sdioemb_func_driver *fdriver);
+void sdioemb_driver_unregister(struct sdioemb_func_driver *fdriver);
+
+int sdioemb_driver_probe(struct sdioemb_func_driver *fdriver, struct sdioemb_dev *fdev);
+void sdioemb_driver_remove(struct sdioemb_func_driver *fdriver, struct sdioemb_dev *fdev);
+
+/* For backward compatibility. */
+#define sdio_register_driver sdioemb_driver_register
+#define sdio_unregister_driver sdioemb_driver_unregister
+
+int sdioemb_set_block_size(struct sdioemb_dev *fdev, uint16_t blksz);
+void sdioemb_set_max_bus_freq(struct sdioemb_dev *fdev, int max_freq);
+int sdioemb_set_bus_width(struct sdioemb_dev *fdev, int bus_width);
+
+int sdioemb_enable_function(struct sdioemb_dev *fdev);
+int sdioemb_disable_function(struct sdioemb_dev *fdev);
+int sdioemb_reenable_csr_function(struct sdioemb_dev *dev);
+void sdioemb_idle_function(struct sdioemb_dev *fdev);
+
+int sdioemb_read8(struct sdioemb_dev *fdev, uint32_t addr, uint8_t *val);
+int sdioemb_read16(struct sdioemb_dev *fdev, uint32_t addr, uint16_t *val);
+int sdioemb_write8(struct sdioemb_dev *fdev, uint32_t addr, uint8_t val);
+int sdioemb_write16(struct sdioemb_dev *fdev, uint32_t addr, uint16_t val);
+int sdioemb_f0_read8(struct sdioemb_dev *fdev, uint32_t addr, uint8_t *val);
+int sdioemb_f0_write8(struct sdioemb_dev *fdev, uint32_t addr, uint8_t val);
+int sdioemb_read(struct sdioemb_dev *fdev, uint32_t addr, void *data, size_t len);
+int sdioemb_write(struct sdioemb_dev *fdev, uint32_t addr, const void *data, size_t len);
+
+int sdioemb_hard_reset(struct sdioemb_dev *fdev);
+
+void sdioemb_power_on(struct sdioemb_dev *fdev);
+void sdioemb_power_off(struct sdioemb_dev *fdev);
+
+int sdioemb_interrupt_enable(struct sdioemb_dev *fdev);
+int sdioemb_interrupt_disable(struct sdioemb_dev *fdev);
+void sdioemb_interrupt_acknowledge(struct sdioemb_dev *fdev);
+
+int sdioemb_cis_get_tuple(struct sdioemb_dev *fdev, uint8_t tuple,
+                       void *buf, size_t len);
+
+void sdioemb_suspend_function(struct sdioemb_dev *fdev);
+void sdioemb_resume_function(struct sdioemb_dev *fdev);
+
+/**
+ * SDIO command status.
+ *
+ * @ingroup fdriver
+ */
+enum sdioemb_cmd_status {
+    SDIOEMB_CMD_OK          = 0x00, /**< Command successful. */
+
+    SDIOEMB_CMD_ERR_CMD     = 0x01,
+    SDIOEMB_CMD_ERR_DAT     = 0x02,
+
+    SDIOEMB_CMD_ERR_CRC     = 0x10,
+    SDIOEMB_CMD_ERR_TIMEOUT = 0x20,
+    SDIOEMB_CMD_ERR_OTHER   = 0x40,
+
+    SDIOEMB_CMD_ERR_CMD_CRC     = SDIOEMB_CMD_ERR_CMD | SDIOEMB_CMD_ERR_CRC,     /**< Response CRC error. */
+    SDIOEMB_CMD_ERR_CMD_TIMEOUT = SDIOEMB_CMD_ERR_CMD | SDIOEMB_CMD_ERR_TIMEOUT, /**< Response time out. */
+    SDIOEMB_CMD_ERR_CMD_OTHER   = SDIOEMB_CMD_ERR_CMD | SDIOEMB_CMD_ERR_OTHER,   /**< Other response error. */
+    SDIOEMB_CMD_ERR_DAT_CRC     = SDIOEMB_CMD_ERR_DAT | SDIOEMB_CMD_ERR_CRC,     /**< Data CRC error. */
+    SDIOEMB_CMD_ERR_DAT_TIMEOUT = SDIOEMB_CMD_ERR_DAT | SDIOEMB_CMD_ERR_TIMEOUT, /**< Data receive time out. */
+    SDIOEMB_CMD_ERR_DAT_OTHER   = SDIOEMB_CMD_ERR_DAT | SDIOEMB_CMD_ERR_OTHER,   /**< Other data error. */
+
+    SDIOEMB_CMD_ERR_NO_CARD = 0x04, /**< No card present. */
+
+    SDIOEMB_CMD_IN_PROGRESS = 0xff, /**< Command still in progress. */
+};
+
+/**
+ * A response to an SDIO command.
+ *
+ * For R1, R4, R5, and R6 responses only the middle 32 bits of the
+ * response are stored, the leading octet (start and direction bits
+ * and command index) and trailing octet (CRC and stop bit) are
+ * discarded.
+ *
+ * @bug R2 and R3 responses are not used by SDIO and are not
+ * supported.
+ *
+ * @ingroup fdriver
+ */
+union sdioemb_response {
+    uint32_t r1;
+    uint32_t r4;
+    uint32_t r5;
+    uint32_t r6;
+};
+
+/**
+ * SDIO command parameters and response.
+ */
+struct sdioemb_cmd_resp {
+    uint8_t  cmd;                 /**< Command index (0 to 63). */
+    uint32_t arg;                 /**< Command argument. */
+    union sdioemb_response response; /**< Response to the command. Valid
+                                     iff the command has completed and
+                                     (sdio_cmd::status & SDIOEMB_CMD_ERR_CMD) == 0.*/
+};
+
+/**
+ * CSPI command parameters and response.
+ */
+struct cspi_cmd_resp {
+    unsigned cmd : 8;  /**< Command octet (type, and function). */
+    unsigned addr: 24; /**< 24 bit address. */
+    uint16_t val;      /**< Word to write or read from the card (for non-burst commands). */
+    uint8_t  response; /**< Response octet.  Valid iff the command has completed and
+                          (sdio_cmd::status & SDIOEMB_CMD_ERR_CMD) == 0. */
+};
+
+
+/**
+ * An SDIO command, its status and response.
+ *
+ * sdio_cmd is used to submit SDIO commands to a device and return its
+ * status and any response or data.
+ *
+ * @ingroup fdriver
+ */
+struct sdioemb_cmd {
+    /**
+     * The SDIO device which submitted the command.  Set by the
+     * core.
+     */
+    struct sdioemb_dev *owner;
+
+    /**
+     * Called by the core when the command has been completed.
+     *
+     * Called in: interrupt context.
+     *
+     * @param cmd the completed command.
+     */
+    void (*callback)(struct sdioemb_cmd *cmd);
+
+    /**
+     * Set of flags specifying the response type, data transfer
+     * direction and other parameters.
+     *
+     * For SDIO commands set at least one of the response types:
+     *   - #SDIOEMB_CMD_FLAG_RESP_NONE
+     *   - #SDIOEMB_CMD_FLAG_RESP_R1
+     *   - #SDIOEMB_CMD_FLAG_RESP_R1B
+     *   - #SDIOEMB_CMD_FLAG_RESP_R2
+     *   - #SDIOEMB_CMD_FLAG_RESP_R3
+     *   - #SDIOEMB_CMD_FLAG_RESP_R4
+     *   - #SDIOEMB_CMD_FLAG_RESP_R5
+     *   - #SDIOEMB_CMD_FLAG_RESP_R5B
+     *   - #SDIOEMB_CMD_FLAG_RESP_R6
+     *
+     * and any of the additional flags:
+     *   - #SDIOEMB_CMD_FLAG_READ
+     *
+     * For CSPI commands set:
+     *   - #SDIOEMB_CMD_FLAG_CSPI
+     */
+    unsigned flags;
+
+    /**
+     * SDIO command parameters and response.
+     *
+     * Valid only if #SDIOEMB_CMD_FLAG_CSPI is \e not set in #flags.
+     */
+    struct sdioemb_cmd_resp sdio;
+
+    /**
+     * CSPI command parameters and response.
+     *
+     * Valid only if #SDIOEMB_CMD_FLAG_CSPI is set in #flags.
+     */
+    struct cspi_cmd_resp cspi;
+
+    /**
+     * Buffer of data to read or write.
+     *
+     * Must be set to NULL if the command is not a data transfer.
+     */
+    uint8_t *data;
+
+    /**
+     * Length of #data in octets.
+     *
+     * len must be either: less than the device's sdio_dev::blocksize;
+     * or a multiple of the device's sdio_dev::blocksize.
+     */
+    size_t len;
+
+    /**
+     * Status of the command after it has completed.
+     */
+    enum sdioemb_cmd_status status;
+
+    /**
+     * Data private to caller of sdioemb_start_cmd().
+     */
+    void *priv;
+};
+
+/** @addtogroup fdriver
+ *@{*/
+#define SDIOEMB_CMD_FLAG_RESP_NONE 0x00 /**< No response. */
+#define SDIOEMB_CMD_FLAG_RESP_R1   0x01 /**< R1 response. */
+#define SDIOEMB_CMD_FLAG_RESP_R1B  0x02 /**< R1b response. */
+#define SDIOEMB_CMD_FLAG_RESP_R2   0x03 /**< R2 response. */
+#define SDIOEMB_CMD_FLAG_RESP_R3   0x04 /**< R3 response. */
+#define SDIOEMB_CMD_FLAG_RESP_R4   0x05 /**< R4 response. */
+#define SDIOEMB_CMD_FLAG_RESP_R5   0x06 /**< R5 response. */
+#define SDIOEMB_CMD_FLAG_RESP_R5B  0x07 /**< R5b response. */
+#define SDIOEMB_CMD_FLAG_RESP_R6   0x08 /**< R6 response. */
+#define SDIOEMB_CMD_FLAG_RESP_MASK 0xff /**< Mask for response type. */
+#define SDIOEMB_CMD_FLAG_RAW     0x0100 /**< @internal Bypass the command queues. */
+#define SDIOEMB_CMD_FLAG_READ    0x0200 /**< Data transfer is a read, not a write. */
+#define SDIOEMB_CMD_FLAG_CSPI    0x0400 /**< CSPI transfer, not SDIO or SDIO-SPI. */
+#define SDIOEMB_CMD_FLAG_ABORT   0x0800 /**< Data transfer abort command. */
+/*@}*/
+
+int sdioemb_start_cmd(struct sdioemb_dev *fdev, struct sdioemb_cmd *cmd);
+
+#endif /* #ifndef _SDIO_API_H */
diff --git a/drivers/staging/csr/sdioemb/sdio_bt_a.h b/drivers/staging/csr/sdioemb/sdio_bt_a.h
new file mode 100644
index 0000000..9efe4a39
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/sdio_bt_a.h
@@ -0,0 +1,143 @@
+/*
+ * SDIO Bluetooth Type-A interface definitions.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef SDIOEMB_SDIO_BT_A_H
+#define SDIOEMB_SDIO_BT_A_H
+
+#include <sdioemb/sdio_csr.h>
+#include <csr_sdio.h>
+
+/*
+ * Standard SDIO function registers for a Bluetooth Type-A interface.
+ */
+#define SDIO_BT_A_RD 0x00
+#define SDIO_BT_A_TD 0x00
+
+#define SDIO_BT_A_RX_PKT_CTRL 0x10
+#  define PC_RRT 0x01
+
+#define SDIO_BT_A_TX_PKT_CTRL 0x11
+#  define PC_WRT 0x01
+
+#define SDIO_BT_A_RETRY_CTRL  0x12
+#  define RTC_STAT 0x01
+#  define RTC_SET  0x01
+
+#define SDIO_BT_A_INTRD       0x13
+#  define INTRD 0x01
+#  define CL_INTRD 0x01
+
+#define SDIO_BT_A_INT_EN      0x14
+#  define EN_INTRD 0x01
+
+#define SDIO_BT_A_BT_MODE     0x20
+#  define MD_STAT 0x01
+
+/*
+ * Length of the Type-A header.
+ *
+ * Packet length (3 octets) plus Service ID (1 octet).
+ */
+#define SDIO_BT_A_HEADER_LEN 4
+
+/*
+ * Maximum length of a Type-A transport packet.
+ *
+ * Type-A header length and maximum length of a HCI packet (65535
+ * octets).
+ */
+#define SDIO_BT_A_PACKET_LEN_MAX 65543
+
+enum sdioemb_bt_a_service_id {
+    SDIO_BT_A_SID_CMD    = 0x01,
+    SDIO_BT_A_SID_ACL    = 0x02,
+    SDIO_BT_A_SID_SCO    = 0x03,
+    SDIO_BT_A_SID_EVT    = 0x04,
+    SDIO_BT_A_SID_VENDOR = 0xfe,
+};
+
+static __inline int sdioemb_bt_a_packet_len(const char *p)
+{
+    return (p[0] & 0xff) | ((p[1] & 0xff) << 8) | ((p[2] & 0xff) << 16);
+}
+
+static __inline int sdioemb_bt_a_service_id(const char *p)
+{
+    return p[3];
+}
+
+/*
+ * Minimum amount to read (including the Type-A header). This allows
+ * short packets (e.g., flow control packets) to be read with a single
+ * command.
+ */
+#define SDIO_BT_A_MIN_READ 32
+
+#define SDIO_BT_A_NAME_LEN 16
+
+struct sdioemb_bt_a_dev {
+    CsrSdioFunction *func;
+    char name[SDIO_BT_A_NAME_LEN];
+    void *drv_data;
+
+    /**
+     * Get a buffer to receive a packet into.
+     *
+     * @param bt the BT device.
+     * @param header a buffer of length #SDIO_BT_A_MIN_READ containing
+     *      (part of) the packet the buffer is for.  It will contain
+     *      the Type-A header and as much of the payload that will
+     *      fit.
+     * @param buffer_min_len the minimum length of buffer required to
+     *     receive the whole packet.  This includes space for padding
+     *     the read to a whole number of blocks (if more than 512
+     *     octets is still to be read).
+     * @param buffer returns the buffer. The packet (including the
+     *     Type-A header will be placed at the beginning of this
+     *     buffer.
+     * @param buffer_handle returns a buffer handle passed to the
+     *     subsequent call of the receive() callback.
+     *
+     * @return 0 if a buffer was provided.
+     * @return -ENOMEM if no buffer could be provided.
+     */
+    int (*get_rx_buffer)(struct sdioemb_bt_a_dev *bt, const uint8_t *header,
+                         size_t buffer_min_len, uint8_t **buffer, void **buffer_handle);
+    void (*receive)(struct sdioemb_bt_a_dev *bt, void *buffer_handle, int status);
+    void (*sleep_state_changed)(struct sdioemb_bt_a_dev *bt);
+
+    enum sdio_sleep_state sleep_state;
+
+    uint8_t  max_tx_retries;
+    uint8_t  max_rx_retries;
+    unsigned needs_read_ack:1;
+    unsigned wait_for_firmware:1;
+
+    unsigned rx_off:1;
+
+    /**
+     * A buffer to read the packet header into before the real buffer
+     * is requested with the get_rx_buffer() callback.
+     *
+     * @internal
+     */
+    uint8_t *header;
+};
+
+int  sdioemb_bt_a_setup(struct sdioemb_bt_a_dev *bt, CsrSdioFunction *func);
+void sdioemb_bt_a_cleanup(struct sdioemb_bt_a_dev *bt);
+int  sdioemb_bt_a_send(struct sdioemb_bt_a_dev *bt, const uint8_t *packet, size_t len);
+void sdioemb_bt_a_handle_interrupt(struct sdioemb_bt_a_dev *bt);
+void sdioemb_bt_a_set_sleep_state(struct sdioemb_bt_a_dev *bt, enum sdio_sleep_state state);
+int  sdioemb_bt_a_check_for_reset(struct sdioemb_bt_a_dev *bt);
+void sdioemb_bt_a_start(struct sdioemb_bt_a_dev *bt);
+void sdioemb_bt_a_stop(struct sdioemb_bt_a_dev *bt);
+void sdioemb_bt_a_rx_on(struct sdioemb_bt_a_dev *bt);
+void sdioemb_bt_a_rx_off(struct sdioemb_bt_a_dev *bt);
+
+#endif /* #ifndef SDIOEMB_SDIO_BT_A_H */
diff --git a/drivers/staging/csr/sdioemb/sdio_cis.h b/drivers/staging/csr/sdioemb/sdio_cis.h
new file mode 100644
index 0000000..ec5e8fc
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/sdio_cis.h
@@ -0,0 +1,27 @@
+/*
+ * SDIO CIS definitions.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef _SDIO_CIS_H
+#define _SDIO_CIS_H
+
+#define CISTPL_NULL     0x00
+#define CISTPL_CHECKSUM 0x10
+#define CISTPL_VERS_1   0x15
+#define CISTPL_ALTSTR   0x16
+#define CISTPL_MANFID   0x20
+#  define CISTPL_MANFID_SIZE 0x04
+#define CISTPL_FUNCID   0x21
+#define CISTPL_FUNCE    0x22
+#define CISTPL_SDIO_STD 0x91
+#define CISTPL_SDIO_EXT 0x92
+#define CISTPL_END      0xff
+#define CISTPL_FUNCE  0x22
+#  define CISTPL_FUNCE_00_SIZE 0x04
+#  define CISTPL_FUNCE_01_SIZE 0x2a
+
+#endif /* #ifndef _SDIO_CIS_H */
diff --git a/drivers/staging/csr/sdioemb/sdio_csr.h b/drivers/staging/csr/sdioemb/sdio_csr.h
new file mode 100644
index 0000000..3b00e46
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/sdio_csr.h
@@ -0,0 +1,134 @@
+/*
+ * CSR specific SDIO registers.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef SDIOEMB_SDIO_CSR_H
+#define SDIOEMB_SDIO_CSR_H
+
+/**
+ * @defgroup registers CSR specific SDIO registers
+ *
+ * Registers at 0xF0 - 0xFF in the CCCR are reserved for vendor
+ * specific registers.  The registers documented here are specific to
+ * following CSR chips:
+ *
+ *   - BlueCore (6 and later)
+ *   - UltraCore
+ *@{
+ */
+
+/**
+ * Interrupt status/host wakeup register.
+ *
+ * This controls a function's deep sleep state.
+ *
+ * @see enum sdio_sleep_state
+ */
+#define SDIO_CSR_SLEEP_STATE 0xf0
+#  define SDIO_CSR_SLEEP_STATE_FUNC(f) ((f) << 4)
+#  define SDIO_CSR_SLEEP_STATE_RDY_INT_EN  0x02
+#  define SDIO_CSR_SLEEP_STATE_WAKE_REQ    0x01
+
+/**
+ * Host interrupt clear register.
+ *
+ * Writing a 1 to bit 0 clears an SDIO interrupt raised by a generic
+ * function.
+ */
+#define SDIO_CSR_HOST_INT 0xf1
+#  define SDIO_CSR_HOST_INT_CL 0x01
+
+/**
+ * From host scratch register 0.
+ *
+ * A read/write register that can be used for signalling between the
+ * host and the chip.
+ *
+ * The usage of this register depends on the version of the chip or
+ * firmware.
+ */
+#define SDIO_CSR_FROM_HOST_SCRATCH0 0xf2
+
+/**
+ * From host scratch register 1.
+ *
+ * @see SDIO_CSR_FROM_HOST_SCRATCH0
+ */
+#define SDIO_CSR_FROM_HOST_SCRATCH1 0xf3
+
+/**
+ * To host scratch register 0.
+ *
+ * A read only register that may be used for signalling between the
+ * chip and the host.
+ *
+ * The usage of this register depends on the version of the chip or
+ * firmware.
+ */
+#define SDIO_CSR_TO_HOST_SCRATCH0 0xf4
+
+/**
+ * To host scratch register 1.
+ *
+ * @see SDIO_CSR_TO_HOST_SCRATCH0
+ */
+#define SDIO_CSR_TO_HOST_SCRATCH1 0xf5
+
+/**
+ * Extended I/O enable.
+ *
+ * Similar to the standard CCCR I/O Enable register, this is used to
+ * detect if an internal reset of a function has occured and
+ * (optionally) reenable it.
+ *
+ * An internal reset is detected by CCCR I/O Enable bit being set and
+ * the corresponding EXT_IO_EN bit being clear.
+ */
+#define SDIO_CSR_EXT_IO_EN 0xf6
+
+/**
+ * Deep sleep states as set via the sleep state register.
+ *
+ * These states are used to control when the chip may go into a deep
+ * sleep (a low power mode).
+ *
+ * Since a chip in deep sleep may not respond to SDIO commands, the
+ * host should ensure that the chip is not in deep sleep before
+ * attempting SDIO commands to functions 1 to 7.
+ *
+ * The available states are:
+ *
+ * AWAKE - chip must not enter deep sleep and should exit deep sleep
+ * if it's currently sleeping.
+ *
+ * TORPID - chip may enter deep sleep.
+ *
+ * DROWSY - a transition state between TORPID and AWAKE.  This is
+ * AWAKE plus the chip asserts an interrupt when the chip is awake.
+ *
+ * @see SDIO_CSR_SLEEP_STATE
+ */
+enum sdio_sleep_state {
+    SLEEP_STATE_AWAKE  = SDIO_CSR_SLEEP_STATE_WAKE_REQ,
+    SLEEP_STATE_DROWSY = SDIO_CSR_SLEEP_STATE_WAKE_REQ | SDIO_CSR_SLEEP_STATE_RDY_INT_EN,
+    SLEEP_STATE_TORPID = 0x00,
+};
+
+/*@}*/
+
+/*
+ * Generic function registers (with byte addresses).
+ */
+
+/*
+ * SDIO_MODE is chip dependant, see the sdio_mode table in sdio_cspi.c
+ * to add support for new chips.
+ */
+#define SDIO_MODE /* chip dependant */
+#  define SDIO_MODE_CSPI_EN 0x40
+
+#endif /* SDIOEMB_SDIO_CSR_H */
diff --git a/drivers/staging/csr/sdioemb/slot_api.h b/drivers/staging/csr/sdioemb/slot_api.h
new file mode 100644
index 0000000..777bdd4
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/slot_api.h
@@ -0,0 +1,313 @@
+/*
+ * Slot driver API.
+ *
+ * Copyright (C) 2007-2009 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef _SLOT_API_H
+#define _SLOT_API_H
+
+#include <sdioemb/sdio_api.h>
+
+struct sdioemb_slot;
+
+/**
+ * @defgroup sdriver SDIO slot driver API
+ *
+ * @brief The SDIO slot driver API provides an interface for the SDIO
+ * layer to driver an SDIO slot (socket).
+ *
+ * Slot drivers register with the SDIO layer (sdioemb_slot_register()),
+ * providing functions to starting commands, enabling/disable card
+ * interrupts, card detection and bus power control.
+ *
+ * Functions are provided to notify the SDIO layer when a command has
+ * completed (sdioemb_cmd_complete()) and when an SDIO card interrupt has
+ * occurred (sdioemb_interrupt()).
+ */
+
+#define SDIOEMB_BUS_FREQ_OFF      0
+#define SDIOEMB_BUS_FREQ_DEFAULT -1
+#define SDIOEMB_BUS_FREQ_IDLE    -2
+
+/**
+ * Valid SDIO bus voltage levels.
+ *
+ * @ingroup sdriver
+ */
+enum sdioemb_power {
+    SDIOEMB_POWER_OFF  =   0, /**< Power switched off. */
+    SDIOEMB_POWER_3V3  =  33, /**< Voltage set to 3.3V. */
+};
+
+/**
+ * SDIO slot capabilities.
+ *
+ * @ingroup sdriver
+ */
+struct slot_caps {
+    int max_bus_freq;  /**< Maximum bus frequency (Hz). */
+    int max_bus_width; /**< Maximum bus width supported (1 or 4 data lines). */
+    uint8_t cspi_mode; /**< CSPI_MODE register value (for CSPI capable slots). */
+};
+
+/**
+ * Controller hardware type.
+ *
+ * @ingroup sdriver
+ */
+enum slot_controller_type {
+    SDIOEMB_SLOT_TYPE_SD = 0,   /**< SD/SDIO controller. */
+    SDIOEMB_SLOT_TYPE_SPI,      /**< SPI controller. */
+    SDIOEMB_SLOT_TYPE_SPI_CSPI, /**< SPI controller capable of CSPI. */
+};
+
+/**
+ * Return values from the add_function() notifier.
+ *
+ * @ingroup sdriver
+ */
+enum sdioemb_add_func_status {
+    /**
+     * The core will call sdioemb_add_function().
+     */
+    SDIOEMB_ADD_FUNC_NOW = 0,
+    /**
+     * The slot driver will call sdioemb_add_function() or the
+     * function driver will call sdioemb_driver_probe() directly.
+     */
+    SDIOEMB_ADD_FUNC_DEFERRED = 1,
+};
+
+/**
+ * Slot/card event notifiers.
+ *
+ * A slot driver may be notified when certain slot or card events
+ * occur.
+ *
+ * @ingroup sdriver
+ */
+struct sdioemb_slot_notifiers {
+    /**
+     * This is called when a card function has been enumerated
+     * and initialized but before can be bound to a function driver.
+     *
+     * A slot driver may use this to create an OS-specific object for
+     * the function.  The slot driver must either (a) return
+     * SDIOEMB_ADD_FUNC_NOW; (b) return SDIOEMB_ADD_FUNC_DEFERRED and
+     * call sdioemb_add_function() later on; (c) return
+     * SDIOEMB_ADD_FUNC_DEFERRED and pass the fdev to the function
+     * driver for it to call sdioemb_driver_probe() directly; or (d)
+     * return an error.
+     *
+     * The slot driver may need to get a reference to the fdev with
+     * sdioemb_get_function() if the lifetime of the OS-specific
+     * object extends beyond the subsequent return of the
+     * del_function() callback.
+     *
+     * If this is non-NULL the slot driver must also provide
+     * del_function().
+     *
+     * @param slot the SDIO slot producing the notification.
+     * @param fdev the SDIO function being added.
+     *
+     * @return SDIOEMB_ADD_FUNC_NOW if the function is ready for use.
+     * @return SDIOEMB_ADD_FUNC_DEFERRED if sdioemb_add_function() or
+     *         sdioemb_driver_probe() will be called later.
+     * @return -ve on a error.
+     */
+    int (*add_function)(struct sdioemb_slot *slot, struct sdioemb_dev *fdev);
+
+    /**
+     * This is called when a card function is being removed and after
+     * any function driver has been unbound.
+     *
+     * A slot driver may use this to delete any OS-specific object
+     * created by the add_function() notifier.
+     *
+     * @param slot the SDIO slot producing the notification.
+     * @param fdev the SDIO function being deleted.
+     */
+    void (*del_function)(struct sdioemb_slot *slot, struct sdioemb_dev *fdev);
+};
+
+struct sdioemb_slot_priv;
+
+/**
+ * An SDIO slot driver.
+ *
+ * Allocate and free with sdioemb_slot_alloc() and sdioemb_slot_free().
+ *
+ * @ingroup sdriver
+ */
+struct sdioemb_slot {
+    /**
+     * Name of the slot used in diagnostic messages.
+     *
+     * This would typically include the name of the SDIO controller
+     * and the slot number if the controller has multiple slots.
+     *
+     * This will be set by sdioemb_slot_register() if it is left as an
+     * empty string.
+     */
+    char name[64];
+
+    /**
+     * Controller hardware type.
+     */
+    enum slot_controller_type type;
+
+    /**
+     * Set the SD bus clock frequency.
+     *
+     * The driver's implementation should set the SD bus clock to not
+     * more than \a clk Hz (unless \a clk is equal to
+     * #SDIOEMB_BUS_FREQ_OFF or #SDIOEMB_BUS_FREQ_IDLE).
+     *
+     * If \a clk == SDIOEMB_BUS_FREQ_OFF the clock should be stopped.
+     *
+     * \a clk == SDIOEMB_BUS_FREQ_IDLE indicates that the bus is idle
+     * (currently unused) and the host controller may slow (or stop)
+     * the SD bus clock to save power on the card.  During this idle
+     * state the host controller must be capable of receiving SDIO
+     * interrupts (for certain host controllers this may require
+     * leaving the clock running).
+     *
+     * If \a clk is greater than #SDIO_CLOCK_FREQ_NORMAL_SPD (25 MHz)
+     * subsequent commands should be done with the controller in high
+     * speed mode.
+     *
+     * Called from: interrupt context.
+     *
+     * @param slot  the slot to configure.
+     * @param clk   new SD bus clock frequency in Hz, SDIOEMB_BUS_FREQ_OFF
+     *              or SDIOEMB_BUS_FREQ_IDLE.
+     *
+     * @return The bus frequency actually configured in Hz.
+     */
+    int (*set_bus_freq)(struct sdioemb_slot *slot, int clk);
+
+    /**
+     * Set the SD bus width.
+     *
+     * The driver's implementation should set the width of the SD bus
+     * for all subsequent data transfers to the specified value.
+     *
+     * This may be NULL if the driver sets the bus width when starting
+     * a command, or the driver is for an SDIO-SPI or CSPI controller.
+     *
+     * Called from: thread context.
+     *
+     * @param slot      the slot to configure.
+     * @param bus_width new SD bus width (either 1 or 4).
+     *
+     * @return 0 on success.
+     * @return -ve if a low-level error occured when setting the bus width.
+     */
+    int (*set_bus_width)(struct sdioemb_slot *slot, int bus_width);
+
+    /**
+     * Start an SDIO command.
+     *
+     * The driver's implementation should:
+     *
+     *   - set the controller's bus width to #bus_width,
+     *   - program the controller to start the command.
+     *
+     * Called from: interrupt context.
+     *
+     * @param slot  slot to perform the command.
+     * @param cmd   SDIO command to start.
+     */
+    int (*start_cmd)(struct sdioemb_slot *slot, struct sdioemb_cmd *cmd);
+
+    /**
+     * Detect if a card is inserted into the slot.
+     *
+     * Called from: thread context.
+     *
+     * @param slot slot to check.
+     *
+     * @return non-zero if a card is inserted; 0 otherwise.
+     */
+    int (*card_present)(struct sdioemb_slot *slot);
+
+    /**
+     * Switch on/off the SDIO bus power and set the SDIO bus voltage.
+     *
+     * Called from: thread context.
+     *
+     * @param slot  the slot.
+     * @param power the requested voltage.
+     *
+     * @return 0 on success; -ve on error: -EINVAL - requested voltage
+     * is not supported.
+     */
+    int (*card_power)(struct sdioemb_slot *slot, enum sdioemb_power power);
+
+    /**
+     * Enable (unmask) the SDIO card interrupt on the controller.
+     *
+     * Called from: interrupt context.
+     *
+     * @param slot the slot to enable the interrupt on..
+     */
+    void (*enable_card_int)(struct sdioemb_slot *slot);
+
+    /**
+     * Disable (mask) the SDIO card interrupt on the controller.
+     *
+     * Called from: thread context.
+     *
+     * @param slot the slot to disable the interrupt on.
+     */
+    void (*disable_card_int)(struct sdioemb_slot *slot);
+
+    /**
+     * Perform a hard reset of the card.
+     *
+     * Hard resets can be achieved in two ways:
+     *
+     * -# Power cycle (if the slot has power control).
+     * -# Platform-specific assertion of a card/chip reset line.
+     *
+     * If hard resets are not supported, either return 0 or set
+     * hard_reset to NULL.
+     *
+     * @param slot the slot for the card to reset.
+     *
+     * @return 0 if a hard reset was performed.
+     * @return 1 if hard resets are not supported.
+     */
+    int (*hard_reset)(struct sdioemb_slot *slot);
+
+    struct slot_caps         caps;           /**< Slot capabilities. */
+    int                      clock_freq;     /**< SD bus frequency requested by the SDIO layer. */
+    int                      bus_width;      /**< Bus width requested by the SDIO layer. */
+    struct sdioemb_slot_notifiers notifs;    /**< Slot event notifiers. */
+    int                      cspi_reg_pad;   /**< Padding for CSPI register reads. */
+    int                      cspi_burst_pad; /**< Padding for CSPI burst reads. */
+    struct sdioemb_slot_priv *priv;          /**< Data private to the SDIO layer. */
+    void *                   drv_data;       /**< Data private to the slot driver. */
+};
+
+struct sdioemb_slot *sdioemb_slot_alloc(size_t drv_data_size);
+void sdioemb_slot_free(struct sdioemb_slot *slot);
+int sdioemb_slot_register(struct sdioemb_slot *slot);
+void sdioemb_slot_unregister(struct sdioemb_slot *slot);
+int sdioemb_card_inserted(struct sdioemb_slot *slot);
+void sdioemb_card_removed(struct sdioemb_slot *slot);
+void sdioemb_interrupt(struct sdioemb_slot *slot);
+void sdioemb_cmd_complete(struct sdioemb_slot *slot, struct sdioemb_cmd *cmd);
+
+void sdioemb_suspend(struct sdioemb_slot *slot);
+void sdioemb_resume(struct sdioemb_slot *slot);
+
+void sdioemb_add_function(struct sdioemb_dev *fdev);
+void sdioemb_del_function(struct sdioemb_dev *fdev);
+void sdioemb_get_function(struct sdioemb_dev *fdev);
+void sdioemb_put_function(struct sdioemb_dev *fdev);
+
+#endif /* #ifndef _SLOT_API_H */
diff --git a/drivers/staging/csr/sdioemb/slot_imx27.h b/drivers/staging/csr/sdioemb/slot_imx27.h
new file mode 100644
index 0000000..3aa2235
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/slot_imx27.h
@@ -0,0 +1,86 @@
+/*
+ * i.MX27 SDHC definitions.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef _SLOT_IMX27_H
+#define _SLOT_IMX27_H
+
+/*
+ * i.MX27 SDHC registers.
+ */
+
+#define SDHC_STR_STP_CLK  0x00
+#  define STR_STP_CLK_MMCSD_RESET 0x0008
+#  define STR_STP_CLK_START_CLK   0x0002
+#  define STR_STP_CLK_STOP_CLK    0x0001
+
+#define SDHC_STATUS       0x04
+#  define STATUS_CARD_PRESENCE    0x8000
+#  define STATUS_SDIO_INT_ACTIVE  0x4000
+#  define STATUS_END_CMD_RESP     0x2000
+#  define STATUS_WRITE_OP_DONE    0x1000
+#  define STATUS_READ_OP_DONE     0x0800
+#  define STATUS_CARD_BUS_CLK_RUN 0x0100
+#  define STATUS_APPL_BUFF_FF     0x0080
+#  define STATUS_APPL_BUFF_FE     0x0040
+#  define STATUS_RESP_CRC_ERR     0x0020
+#  define STATUS_CRC_READ_ERR     0x0008
+#  define STATUS_CRC_WRITE_ERR    0x0004
+#  define STATUS_TIME_OUT_RESP    0x0002
+#  define STATUS_TIME_OUT_READ    0x0001
+#  define STATUS_ERR_CMD_MASK     (STATUS_RESP_CRC_ERR | STATUS_TIME_OUT_RESP)
+#  define STATUS_ERR_DATA_MASK    (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR | STATUS_TIME_OUT_READ)
+#  define STATUS_ERR_MASK         (STATUS_ERR_CMD_MASK | STATUS_ERR_DATA_MASK)
+
+#define SDHC_CLK_RATE     0x08
+
+#define SDHC_CMD_DAT_CTRL 0x0c /* CMD_DAT_CONT */
+#  define CMD_DAT_CTRL_CMD_RESUME        0x8000
+#  define CMD_DAT_CTRL_CMD_RESP_LONG_OFF 0x1000
+#  define CMD_DAT_CTRL_STOP_READ_WAIT    0x0800
+#  define CMD_DAT_CTRL_START_READ_WAIT   0x0400
+#  define CMD_DAT_CTRL_BUS_WIDTH_4       0x0200
+#  define CMD_DAT_CTRL_INIT              0x0080
+#  define CMD_DAT_CTRL_WRITE             0x0010
+#  define CMD_DAT_CTRL_DATA_ENABLE       0x0008
+#  define CMD_DAT_CTRL_RESP_NONE         0x0000
+#  define CMD_DAT_CTRL_RESP_R1_R5_R6     0x0001
+#  define CMD_DAT_CTRL_RESP_R2           0x0002
+#  define CMD_DAT_CTRL_RESP_R3_R4        0x0003
+
+#define SDHC_RES_TO       0x10
+
+#define SDHC_READ_TO      0x14
+#  define READ_TO_RECOMMENDED 0x2db4
+
+#define SDHC_BLK_LEN      0x18
+
+#define SDHC_NOB          0x1c
+
+#define SDHC_REV_NO       0x20
+
+#define SDHC_INT_CTRL     0x24 /* INT_CNTR */
+#  define INT_CTRL_CARD_INSERTION_EN 0x8000
+#  define INT_CTRL_SDIO_REMOVAL_EN   0x4000
+#  define INT_CTRL_SDIO_IRQ_EN       0x2000
+#  define INT_CTRL_DAT0_EN           0x1000
+#  define INT_CTRL_BUF_READ_EN       0x0010
+#  define INT_CTRL_BUF_WRITE_EN      0x0008
+#  define INT_CTRL_END_CMD_RES       0x0004
+#  define INT_CTRL_WRITE_OP_DONE     0x0002
+#  define INT_CTRL_READ_OP_DONE      0x0001
+#  define INT_CTRL_INT_EN_MASK       0xe01f
+
+#define SDHC_CMD          0x28
+
+#define SDHC_ARG          0x2c
+
+#define SDHC_RES_FIFO     0x34
+
+#define SDHC_BUFFER_ACCESS 0x38
+
+#endif /* #ifndef _SLOT_IMX27_H */
diff --git a/drivers/staging/csr/sdioemb/slot_imx31.h b/drivers/staging/csr/sdioemb/slot_imx31.h
new file mode 100644
index 0000000..b11894a
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/slot_imx31.h
@@ -0,0 +1,86 @@
+/*
+ * i.MX31 SDHC definitions.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef _SLOT_IMX31_H
+#define _SLOT_IMX31_H
+
+/*
+ * i.MX31 SDHC registers.
+ */
+
+#define SDHC_STR_STP_CLK  0x00
+#  define STR_STP_CLK_MMCSD_RESET 0x0008
+#  define STR_STP_CLK_START_CLK   0x0002
+#  define STR_STP_CLK_STOP_CLK    0x0001
+
+#define SDHC_STATUS       0x04
+#  define STATUS_CARD_PRESENCE    0x8000
+#  define STATUS_SDIO_INT_ACTIVE  0x4000
+#  define STATUS_END_CMD_RESP     0x2000
+#  define STATUS_WRITE_OP_DONE    0x1000
+#  define STATUS_READ_OP_DONE     0x0800
+#  define STATUS_CARD_BUS_CLK_RUN 0x0100
+#  define STATUS_APPL_BUFF_FF     0x0080
+#  define STATUS_APPL_BUFF_FE     0x0040
+#  define STATUS_RESP_CRC_ERR     0x0020
+#  define STATUS_CRC_READ_ERR     0x0008
+#  define STATUS_CRC_WRITE_ERR    0x0004
+#  define STATUS_TIME_OUT_RESP    0x0002
+#  define STATUS_TIME_OUT_READ    0x0001
+#  define STATUS_ERR_CMD_MASK     (STATUS_RESP_CRC_ERR | STATUS_TIME_OUT_RESP)
+#  define STATUS_ERR_DATA_MASK    (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR | STATUS_TIME_OUT_READ)
+#  define STATUS_ERR_MASK         (STATUS_ERR_CMD_MASK | STATUS_ERR_DATA_MASK)
+
+#define SDHC_CLK_RATE     0x08
+
+#define SDHC_CMD_DAT_CTRL 0x0c /* CMD_DAT_CONT */
+#  define CMD_DAT_CTRL_CMD_RESUME        0x8000
+#  define CMD_DAT_CTRL_CMD_RESP_LONG_OFF 0x1000
+#  define CMD_DAT_CTRL_STOP_READ_WAIT    0x0800
+#  define CMD_DAT_CTRL_START_READ_WAIT   0x0400
+#  define CMD_DAT_CTRL_BUS_WIDTH_4       0x0200
+#  define CMD_DAT_CTRL_INIT              0x0080
+#  define CMD_DAT_CTRL_WRITE             0x0010
+#  define CMD_DAT_CTRL_DATA_ENABLE       0x0008
+#  define CMD_DAT_CTRL_RESP_NONE         0x0000
+#  define CMD_DAT_CTRL_RESP_R1_R5_R6     0x0001
+#  define CMD_DAT_CTRL_RESP_R2           0x0002
+#  define CMD_DAT_CTRL_RESP_R3_R4        0x0003
+
+#define SDHC_RES_TO       0x10
+
+#define SDHC_READ_TO      0x14
+#  define READ_TO_RECOMMENDED 0x2db4
+
+#define SDHC_BLK_LEN      0x18
+
+#define SDHC_NOB          0x1c
+
+#define SDHC_REV_NO       0x20
+
+#define SDHC_INT_CTRL     0x24 /* INT_CNTR */
+#  define INT_CTRL_CARD_INSERTION_EN 0x8000
+#  define INT_CTRL_SDIO_REMOVAL_EN   0x4000
+#  define INT_CTRL_SDIO_IRQ_EN       0x2000
+#  define INT_CTRL_DAT0_EN           0x1000
+#  define INT_CTRL_BUF_READ_EN       0x0010
+#  define INT_CTRL_BUF_WRITE_EN      0x0008
+#  define INT_CTRL_END_CMD_RES       0x0004
+#  define INT_CTRL_WRITE_OP_DONE     0x0002
+#  define INT_CTRL_READ_OP_DONE      0x0001
+#  define INT_CTRL_INT_EN_MASK       0xe01f
+
+#define SDHC_CMD          0x28
+
+#define SDHC_ARG          0x2c
+
+#define SDHC_RES_FIFO     0x34
+
+#define SDHC_BUFFER_ACCESS 0x38
+
+#endif /* #ifndef _SLOT_IMX31_H */
diff --git a/drivers/staging/csr/sdioemb/slot_pxa27x.h b/drivers/staging/csr/sdioemb/slot_pxa27x.h
new file mode 100644
index 0000000..cca853a
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/slot_pxa27x.h
@@ -0,0 +1,70 @@
+/*
+ * PXA27x MMC/SD controller definitions.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef _SLOT_PXA27X_H
+#define _SLOT_PXA27X_H
+
+#define PXA27X_MMC_MMCLK_BASE_FREQ 19500000
+#define PXA27X_MMC_FIFO_SIZE 32
+
+#define STOP_CLOCK              (1 << 0)
+#define START_CLOCK             (2 << 0)
+
+#define STAT_END_CMD_RES                (1 << 13)
+#define STAT_PRG_DONE                   (1 << 12)
+#define STAT_DATA_TRAN_DONE             (1 << 11)
+#define STAT_CLK_EN                     (1 << 8)
+#define STAT_RECV_FIFO_FULL             (1 << 7)
+#define STAT_XMIT_FIFO_EMPTY            (1 << 6)
+#define STAT_RES_CRC_ERR                (1 << 5)
+#define STAT_SPI_READ_ERROR_TOKEN       (1 << 4)
+#define STAT_CRC_READ_ERROR             (1 << 3)
+#define STAT_CRC_WRITE_ERROR            (1 << 2)
+#define STAT_TIME_OUT_RESPONSE          (1 << 1)
+#define STAT_READ_TIME_OUT              (1 << 0)
+
+#define SPI_CS_ADDRESS          (1 << 3)
+#define SPI_CS_EN               (1 << 2)
+#define CRC_ON                  (1 << 1)
+#define SPI_EN                  (1 << 0)
+
+#define CMDAT_SDIO_INT_EN       (1 << 11)
+#define CMDAT_STOP_TRAN         (1 << 10)
+#define CMDAT_SD_4DAT           (1 << 8)
+#define CMDAT_DMAEN             (1 << 7)
+#define CMDAT_INIT              (1 << 6)
+#define CMDAT_BUSY              (1 << 5)
+#define CMDAT_STREAM            (1 << 4)        /* 1 = stream */
+#define CMDAT_WRITE             (1 << 3)        /* 1 = write */
+#define CMDAT_DATAEN            (1 << 2)
+#define CMDAT_RESP_NONE         (0 << 0)
+#define CMDAT_RESP_SHORT        (1 << 0)
+#define CMDAT_RESP_R2           (2 << 0)
+#define CMDAT_RESP_R3           (3 << 0)
+
+#define RDTO_MAX                0xffff
+
+#define BUF_PART_FULL           (1 << 0)
+
+#define SDIO_SUSPEND_ACK        (1 << 12)
+#define SDIO_INT                (1 << 11)
+#define RD_STALLED              (1 << 10)
+#define RES_ERR                 (1 << 9)
+#define DAT_ERR                 (1 << 8)
+#define TINT                    (1 << 7)
+#define TXFIFO_WR_REQ           (1 << 6)
+#define RXFIFO_RD_REQ           (1 << 5)
+#define CLK_IS_OFF              (1 << 4)
+#define STOP_CMD                (1 << 3)
+#define END_CMD_RES             (1 << 2)
+#define PRG_DONE                (1 << 1)
+#define DATA_TRAN_DONE          (1 << 0)
+
+#define MMC_I_MASK_ALL          0x00001fff
+
+#endif /* #ifndef _SLOT_PXA27X_H */
diff --git a/drivers/staging/csr/sdioemb/slot_shc.h b/drivers/staging/csr/sdioemb/slot_shc.h
new file mode 100644
index 0000000..0eb5e53
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/slot_shc.h
@@ -0,0 +1,223 @@
+/*
+ * Standard Host Controller definitions.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef _SLOT_SHC_H
+#define _SLOT_SHC_H
+
+#include <oska/io.h>
+
+/* SHC registers */
+#define SHC_SYSTEM_ADDRESS  0x00
+
+#define SHC_BLOCK_SIZE      0x04
+#  define SHC_BLOCK_SIZE_DMA_BOUNDARY_4K   (0x0 << 12)
+#  define SHC_BLOCK_SIZE_DMA_BOUNDARY_512K (0x7 << 12)
+
+#define SHC_BLOCK_COUNT     0x06
+#define SHC_ARG             0x08
+
+#define SHC_TRANSFER_MODE   0x0c
+#  define SHC_TRANSFER_MODE_DMA_EN        0x0001
+#  define SHC_TRANSFER_MODE_BLK_CNT_EN    0x0002
+#  define SHC_TRANSFER_MODE_AUTO_CMD12_EN 0x0004
+#  define SHC_TRANSFER_MODE_DATA_READ     0x0010
+#  define SHC_TRANSFER_MODE_MULTI_BLK     0x0020
+
+#define SHC_CMD             0x0e
+#  define SHC_CMD_RESP_NONE     0x0000
+#  define SHC_CMD_RESP_136      0x0001
+#  define SHC_CMD_RESP_48       0x0002
+#  define SHC_CMD_RESP_48B      0x0003
+#  define SHC_CMD_RESP_CRC_CHK  0x0008
+#  define SHC_CMD_RESP_IDX_CHK  0x0010
+#  define SHC_CMD_DATA_PRESENT  0x0020
+#  define SHC_CMD_TYPE_ABORT    (0x3 << 6)
+#  define SHC_CMD_IDX(c)        ((c) << 8)
+
+#define SHC_RESPONSE_0_31   0x10
+
+#define SHC_BUFFER_DATA_PORT    0x20
+
+#define SHC_PRESENT_STATE       0x24
+#  define SHC_PRESENT_STATE_CMD_INHIBIT     0x00000001
+#  define SHC_PRESENT_STATE_DAT_INHIBIT     0x00000002
+#  define SHC_PRESENT_STATE_CARD_PRESENT    0x00010000
+
+#define SHC_HOST_CTRL           0x28
+#  define SHC_HOST_CTRL_LED_ON          0x01
+#  define SHC_HOST_CTRL_4BIT            0x02
+#  define SHC_HOST_CTRL_HIGH_SPD_EN     0x04
+
+
+#define SHC_PWR_CTRL        0x29
+#  define SHC_PWR_CTRL_3V3      0x0e
+#  define SHC_PWR_CTRL_ON       0x01
+
+#define SHC_BLOCK_GAP_CTRL  0x2a
+#define SHC_WAKEUP_CTRL     0x2b
+
+#define SHC_CLOCK_CTRL      0x2c
+#  define SHC_CLOCK_CTRL_INT_CLK_EN     0x01
+#  define SHC_CLOCK_CTRL_INT_CLK_STABLE 0x02
+#  define SHC_CLOCK_CTRL_SD_CLK_EN      0x04
+#  define SHC_CLOCK_CTRL_DIV(d)         (((d) >> 1) << 8) /* divisor must be power of 2 */
+
+#define SHC_TIMEOUT_CTRL    0x2e
+#  define SHC_TIMEOUT_CTRL_MAX          0x0e
+
+#define SHC_SOFTWARE_RST    0x2f
+#  define SHC_SOFTWARE_RST_ALL 0x01
+#  define SHC_SOFTWARE_RST_CMD 0x02
+#  define SHC_SOFTWARE_RST_DAT 0x04
+
+#define SHC_INT_STATUS      0x30
+#define SHC_INT_STATUS_EN   0x34
+#define SHC_INT_SIGNAL_EN   0x38
+#  define SHC_INT_CMD_COMPLETE      0x00000001
+#  define SHC_INT_TRANSFER_COMPLETE 0x00000002
+#  define SHC_INT_BLOCK_GAP         0x00000004
+#  define SHC_INT_DMA               0x00000008
+#  define SHC_INT_WR_BUF_RDY        0x00000010
+#  define SHC_INT_RD_BUF_RDY        0x00000020
+#  define SHC_INT_CARD_INSERTED     0x00000040
+#  define SHC_INT_CARD_REMOVED      0x00000080
+#  define SHC_INT_CARD_INT          0x00000100
+#  define SHC_INT_ERR_ANY           0x00008000
+#  define SHC_INT_ERR_CMD_TIMEOUT   0x00010000
+#  define SHC_INT_ERR_CMD_CRC       0x00020000
+#  define SHC_INT_ERR_CMD_ENDBIT    0x00040000
+#  define SHC_INT_ERR_CMD_INDEX     0x00080000
+#  define SHC_INT_ERR_CMD_ALL       0x000f0000
+#  define SHC_INT_ERR_DAT_TIMEOUT   0x00100000
+#  define SHC_INT_ERR_DAT_CRC       0x00200000
+#  define SHC_INT_ERR_DAT_ENDBIT    0x00400000
+#  define SHC_INT_ERR_DAT_ALL       0x00700000
+#  define SHC_INT_ERR_CURRENT_LIMIT 0x00800000
+#  define SHC_INT_ERR_AUTO_CMD12    0x01000000
+#  define SHC_INT_ERR_ALL           0x01ff0000
+#  define SHC_INT_ALL               0x01ff81ff
+
+#define SHC_AUTO_CMD12_STATUS   0x3c
+
+#define SHC_CAPS                0x40
+#  define SHC_CAPS_TO_BASE_CLK_FREQ(c)  (((c) & 0x00003f00) >> 8)
+#  define SHC_CAPS_PWR_3V3              (1 << 24)
+
+#define SHC_MAX_CURRENT_CAPS    0x4c
+
+/* PCI configuration registers. */
+#define PCI_SHC_SLOT_INFO 0x40
+
+/* Maximum time to wait for a software reset. */
+#define SHC_RESET_TIMEOUT_MS 100 /* ms */
+
+/* Maximum time to wait for internal clock to stabilize */
+#define SHC_INT_CLK_STABLE_TIMEOUT_MS 100
+
+/*
+ * No supported voltages in the capabilities register.
+ *
+ * Workaround: Assume 3.3V is supported.
+ */
+#define SLOT_SHC_QUIRK_NO_VOLTAGE_CAPS (1 << 0)
+
+/*
+ * Commands with an R5B (busy) response do not complete.
+ *
+ * Workaround: Use R5 instead. This will only work if the busy signal
+ * is cleared sufficiently quickly before the next command is started.
+ */
+#define SLOT_SHC_QUIRK_R5B_BROKEN      (1 << 1)
+
+/*
+ * High speed mode doesn't work.
+ *
+ * Workaround: limit maximum bus frequency to 25 MHz.
+ */
+#define SLOT_SHC_QUIRK_HIGH_SPD_BROKEN (1 << 2)
+
+/*
+ * Data timeout (TIMEOUT_CTRL) uses SDCLK and not TMCLK.
+ *
+ * Workaround: set TIMEOUT_CTRL using SDCLK.
+ */
+#define SLOT_SHC_QUIRK_DATA_TIMEOUT_USES_SDCLK (1 << 3)
+
+/*
+ * Controller can only start DMA on dword (32 bit) aligned addresses.
+ *
+ * Workaround: PIO is used on data transfers with a non-dword aligned
+ * address.
+ */
+#define SHC_QUIRK_DMA_NEEDS_DWORD_ALIGNED_ADDR (1 << 4)
+
+/*
+ * Controller is unreliable following multiple transfers
+ *
+ * Workaround: The controller is reset following every command, not just
+ * erroneous ones
+ */
+#define SHC_QUIRK_RESET_EVERY_CMD_COMPLETE (1 << 5)
+
+/*
+ * JMicron JMB381 to JMB385 controllers require some non-standard PCI
+ * config space writes.
+ */
+#define SHC_QUIRK_JMICRON_JMB38X (1 << 6)
+
+/*
+ * Controller can only do DMA if the length is a whole number of
+ * dwords.
+ *
+ * Controller with this quirk probably also need
+ * SHC_QUIRK_DMA_NEEDS_DWORD_ALIGNED_ADDR.
+ *
+ * Workaround: PIO is used on data transfers that don't end on an
+ * aligned address.
+ */
+#define SHC_QUIRK_DMA_NEEDS_DWORD_ALIGNED_LEN (1 << 7)
+
+struct sdioemb_shc {
+    struct sdioemb_slot *slot;
+    void (*enable_int)(struct sdioemb_slot *slot, uint32_t ints);
+    void (*disable_int)(struct sdioemb_slot *slot, uint32_t ints);
+    void (*cmd_complete)(struct sdioemb_slot *slot, struct sdioemb_cmd *cmd);
+    uint32_t quirks;
+    os_io_mem_t addr;
+
+    os_spinlock_t lock;
+    os_timer_t lockup_timer;
+    uint32_t base_clk;
+    struct sdioemb_cmd *current_cmd;
+    uint8_t *data;
+    size_t remaining;
+    size_t block_size;
+};
+
+void sdioemb_shc_init(struct sdioemb_shc *shc);
+void sdioemb_shc_clean_up(struct sdioemb_shc *shc);
+
+int sdioemb_shc_start(struct sdioemb_shc *shc);
+void sdioemb_shc_stop(struct sdioemb_shc *shc);
+
+bool sdioemb_shc_isr(struct sdioemb_shc *shc, uint32_t *int_stat);
+void sdioemb_shc_dsr(struct sdioemb_shc *shc, uint32_t int_stat);
+
+int sdioemb_shc_set_bus_freq(struct sdioemb_shc *shc, int clk);
+int sdioemb_shc_set_bus_width(struct sdioemb_shc *shc, int bus_width);
+int sdioemb_shc_start_cmd(struct sdioemb_shc *shc, struct sdioemb_cmd *cmd,
+                          bool use_dma, uint64_t dma_addr);
+int sdioemb_shc_card_present(struct sdioemb_shc *shc);
+int sdioemb_shc_card_power(struct sdioemb_shc *shc, enum sdioemb_power power);
+void sdioemb_shc_enable_card_int(struct sdioemb_shc *shc);
+void sdioemb_shc_disable_card_int(struct sdioemb_shc *shc);
+int sdioemb_shc_hard_reset(struct sdioemb_shc *shc);
+
+void sdioemb_shc_show_quirks(struct sdioemb_shc *shc);
+
+#endif /* #ifndef _SLOT_SHC_H */
diff --git a/drivers/staging/csr/sdioemb/slot_ushc.h b/drivers/staging/csr/sdioemb/slot_ushc.h
new file mode 100644
index 0000000..efe3310
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/slot_ushc.h
@@ -0,0 +1,133 @@
+/*
+ * USB Standard Host Controller definitions.
+ *
+ * Copyright (C) 2010 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef _SLOT_USHC_H
+#define _SLOT_USHC_H
+
+#include <oska/io.h>
+
+enum ushc_request
+{
+    USHC_GET_CAPS  = 0x00,
+    USHC_HOST_CTRL = 0x01,
+    USHC_PWR_CTRL  = 0x02,
+    USHC_CLK_FREQ  = 0x03,
+    USHC_EXEC_CMD  = 0x04,
+    USHC_READ_RESP = 0x05,
+    USHC_RESET     = 0x06
+};
+
+enum ushc_request_recipient
+{
+    USHC_RECIPIENT_DEVICE = 0x00,
+    USHC_RECIPIENT_INTERFACE = 0x01,
+    USHC_RECIPIENT_ENDPOINT = 0x02,
+    USHC_RECIPIENT_OTHER = 0x03
+};
+
+enum ushc_request_direction
+{
+    USHC_HOST_TO_DEVICE = 0x00,
+    USHC_DEVICE_TO_HOST = 0x01
+};
+
+struct sdioemb_ushc
+{
+    struct sdioemb_slot *slot;
+
+    void (*enable_int)(struct sdioemb_slot *slot, uint32_t ints);
+    void (*disable_int)(struct sdioemb_slot *slot, uint32_t ints);
+    void (*cmd_complete)(struct sdioemb_slot *slot, struct sdioemb_cmd *cmd);
+    int  (*set_host_ctrl)(struct sdioemb_slot *slot, uint16_t controler_state);
+    int  (*submit_vendor_request)(struct sdioemb_slot *slot,
+                                  enum ushc_request request,
+                                  enum ushc_request_direction direction,
+                                  enum ushc_request_recipient recipient,
+                                  uint16_t value,
+                                  uint16_t index,
+                                  void* io_buffer,
+                                  uint32_t io_buffer_length);
+    int  (*submit_cbw_request)(struct sdioemb_slot *slot, uint8_t cmd_index, uint16_t block_size, uint32_t cmd_arg);
+    int  (*submit_data_request)(struct sdioemb_slot *slot,
+                                enum ushc_request_direction direction,
+                                void* request_buffer,
+                                uint32_t request_buffer_length);
+    int  (*submit_csw_request)(struct sdioemb_slot *slot);
+
+    os_spinlock_t lock;
+
+    uint32_t base_clock;
+    uint32_t controler_capabilities;
+    uint16_t controler_state;
+    struct sdioemb_cmd* current_cmd;
+
+#define DISCONNECTED    0
+#define INT_EN          1
+#define IGNORE_NEXT_INT 2
+#define STOP            4
+    uint32_t flags;
+
+#define USHC_INT_STATUS_SDIO_INT     (1 << 1)
+#define USHC_INT_STATUS_CARD_PRESENT (1 << 0)
+    uint8_t interrupt_status;
+
+    size_t block_size;
+};
+
+#define USHC_GET_CAPS_VERSION_MASK 0xff
+#define USHC_GET_CAPS_3V3      (1 << 8)
+#define USHC_GET_CAPS_3V0      (1 << 9)
+#define USHC_GET_CAPS_1V8      (1 << 10)
+#define USHC_GET_CAPS_HIGH_SPD (1 << 16)
+
+#define USHC_PWR_CTRL_OFF 0x00
+#define USHC_PWR_CTRL_3V3 0x01
+#define USHC_PWR_CTRL_3V0 0x02
+#define USHC_PWR_CTRL_1V8 0x03
+
+#define USHC_HOST_CTRL_4BIT     (1 << 1)
+#define USHC_HOST_CTRL_HIGH_SPD (1 << 0)
+
+#define USHC_READ_RESP_BUSY        (1 << 4)
+#define USHC_READ_RESP_ERR_TIMEOUT (1 << 3)
+#define USHC_READ_RESP_ERR_CRC     (1 << 2)
+#define USHC_READ_RESP_ERR_DAT     (1 << 1)
+#define USHC_READ_RESP_ERR_CMD     (1 << 0)
+#define USHC_READ_RESP_ERR_MASK    0x0f
+
+void sdioemb_ushc_init(struct sdioemb_ushc* ushc);
+void sdioemb_ushc_clean_up(struct sdioemb_ushc* ushc);
+
+int sdioemb_ushc_start(struct sdioemb_ushc* ushc);
+void sdioemb_ushc_stop(struct sdioemb_ushc* ushc);
+
+bool sdioemb_ushc_isr(struct sdioemb_ushc* ushc, uint8_t int_stat);
+
+int sdioemb_ushc_set_bus_freq(struct sdioemb_ushc* ushc, int clk);
+int sdioemb_ushc_set_bus_width(struct sdioemb_ushc* ushc, int bus_width);
+int sdioemb_ushc_start_cmd(struct sdioemb_ushc* ushc, struct sdioemb_cmd *cmd);
+int sdioemb_ushc_card_present(struct sdioemb_ushc* ushc);
+int sdioemb_ushc_card_power(struct sdioemb_ushc* ushc, enum sdioemb_power power);
+void sdioemb_ushc_enable_card_int(struct sdioemb_ushc* ushc);
+void sdioemb_ushc_disable_card_int(struct sdioemb_ushc* ushc);
+int sdioemb_ushc_hard_reset(struct sdioemb_ushc* ushc);
+
+void sdioemb_ushc_command_complete(struct sdioemb_ushc* ushc, uint8_t status, uint32_t respones);
+
+int ushc_hw_get_caps(struct sdioemb_ushc* ushc);
+static int ushc_hw_set_host_ctrl(struct sdioemb_ushc* ushc, uint16_t mask, uint16_t val);
+static int ushc_hw_submit_vendor_request(struct sdioemb_ushc* ushc,
+                                       enum ushc_request request,
+                                       enum ushc_request_recipient recipient,
+                                       enum ushc_request_direction direction,
+                                       uint16_t value,
+                                       uint16_t index,
+                                       void* io_buffer,
+                                       uint32_t io_buffer_length);
+
+#endif
diff --git a/drivers/staging/csr/sdioemb/trace.h b/drivers/staging/csr/sdioemb/trace.h
new file mode 100644
index 0000000..57cbb01
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/trace.h
@@ -0,0 +1,19 @@
+/*
+ * Sdioemb trace messages.
+ *
+ * Copyright (C) 2009 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+
+#ifndef SDIOEMB_TRACE_H
+#define SDIOEMB_TRACE_H
+
+#if defined(__linux__)
+#  define OS_TRACE_PREFIX "sdioemb: "
+#endif
+
+#include <oska/trace.h>
+
+#endif /* #ifndef SDIOEMB_TRACE_H */
diff --git a/drivers/staging/csr/sdioemb/uif.h b/drivers/staging/csr/sdioemb/uif.h
new file mode 100644
index 0000000..c09357f
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/uif.h
@@ -0,0 +1,41 @@
+/*
+ * Userspace interface to the SDIO Userspace Interface driver.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ */
+#ifndef LINUX_SDIOEMB_UIF_H
+#define LINUX_SDIOEMB_UIF_H
+
+enum sdioemb_uif_cmd_type {
+    SDIOEMB_UIF_CMD52_READ, SDIOEMB_UIF_CMD52_WRITE,
+    SDIOEMB_UIF_CMD53_READ, SDIOEMB_UIF_CMD53_WRITE,
+};
+
+struct sdioemb_uif_cmd {
+    enum sdioemb_uif_cmd_type type;
+    int                    function;
+    uint32_t               address;
+    uint8_t *              data;
+    size_t                 len;
+    int                    block_size;
+};
+
+#define SDIOEMB_UIF_IOC_MAGIC 's'
+
+#define SDIOEMB_UIF_IOCQNUMFUNCS  _IO(SDIOEMB_UIF_IOC_MAGIC,   0)
+#define SDIOEMB_UIF_IOCCMD        _IOWR(SDIOEMB_UIF_IOC_MAGIC, 1, struct sdioemb_uif_cmd)
+#define SDIOEMB_UIF_IOCWAITFORINT _IO(SDIOEMB_UIF_IOC_MAGIC,   2)
+#define SDIOEMB_UIF_IOCTBUSWIDTH  _IO(SDIOEMB_UIF_IOC_MAGIC,   3)
+#define SDIOEMB_UIF_IOCREINSERT   _IO(SDIOEMB_UIF_IOC_MAGIC,   4)
+#define SDIOEMB_UIF_IOCTBUSFREQ   _IO(SDIOEMB_UIF_IOC_MAGIC,   5)
+#define SDIOEMB_UIF_IOCQMANFID    _IO(SDIOEMB_UIF_IOC_MAGIC,   6)
+#define SDIOEMB_UIF_IOCQCARDID    _IO(SDIOEMB_UIF_IOC_MAGIC,   7)
+#define SDIOEMB_UIF_IOCQSTDIF     _IO(SDIOEMB_UIF_IOC_MAGIC,   8)
+#define SDIOEMB_UIF_IOCQMAXBLKSZ  _IO(SDIOEMB_UIF_IOC_MAGIC,   9)
+#define SDIOEMB_UIF_IOCQBLKSZ     _IO(SDIOEMB_UIF_IOC_MAGIC,  10)
+#define SDIOEMB_UIF_IOCTBLKSZ     _IO(SDIOEMB_UIF_IOC_MAGIC,  11)
+
+#endif /* #ifndef LINUX_SDIOEMB_UIF_H */
diff --git a/drivers/staging/csr/sdioemb/version.h b/drivers/staging/csr/sdioemb/version.h
new file mode 100644
index 0000000..b88ef6e
--- /dev/null
+++ b/drivers/staging/csr/sdioemb/version.h
@@ -0,0 +1,11 @@
+/* Autogenerated by the sdioemb release procedure. */
+#ifndef SDIOEMB_VERSION_H
+#define SDIOEMB_VERSION_H
+
+#define SDIOEMB_RELEASE 31
+
+#ifndef SDIOEMB_RELEASE_EXTRA
+#define SDIOEMB_RELEASE_EXTRA ""
+#endif
+
+#endif /* #ifndef SDIOEMB_VERSION_H */
diff --git a/drivers/staging/csr/sme_blocking.c b/drivers/staging/csr/sme_blocking.c
new file mode 100644
index 0000000..8461bac
--- /dev/null
+++ b/drivers/staging/csr/sme_blocking.c
@@ -0,0 +1,1535 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     sme_mgt_blocking.c
+ *
+ * PURPOSE:
+ *      This file contains the driver specific implementation of
+ *      the WEXT <==> SME MGT interface for all SME builds that support WEXT.
+ *
+ * Copyright (C) 2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+#include "unifi_priv.h"
+
+
+/*
+ * This file also contains the implementation of the asyncronous
+ * requests to the SME.
+ *
+ * Before calling an asyncronous SME function, we call sme_init_request()
+ * which gets hold of the SME semaphore and updates the request status.
+ * The semaphore makes sure that there is only one pending request to
+ * the SME at a time.
+ *
+ * Now we are ready to call the SME function, but only if
+ * sme_init_request() has returned 0.
+ *
+ * When the SME function returns, we need to wait
+ * for the reply. This is done in sme_wait_for_reply().
+ * If the request times-out, the request status is set to SME_REQUEST_TIMEDOUT
+ * and the sme_wait_for_reply() returns.
+ *
+ * If the SME replies in time, we call sme_complete_request().
+ * There we change the request status to SME_REQUEST_RECEIVED. This will
+ * wake up the process waiting on sme_wait_for_reply().
+ * It is important that we copy the reply data in priv->sme_reply
+ * before calling sme_complete_request().
+ *
+ * Handling the wext requests, we need to block
+ * until the SME sends the response to our request.
+ * We use the sme_init_request() and sme_wait_for_reply()
+ * to implement this behavior in the following functions:
+ * sme_mgt_wifi_on()
+ * sme_mgt_wifi_off()
+ * sme_mgt_scan_full()
+ * sme_mgt_scan_results_get_async()
+ * sme_mgt_connect()
+ * unifi_mgt_media_status_ind()
+ * sme_mgt_disconnect()
+ * sme_mgt_pmkid()
+ * sme_mgt_key()
+ * sme_mgt_mib_get()
+ * sme_mgt_mib_set()
+ * sme_mgt_versions_get()
+ * sme_mgt_set_value()
+ * sme_mgt_get_value()
+ * sme_mgt_set_value_async()
+ * sme_mgt_get_value_async()
+ * sme_mgt_packet_filter_set()
+ * sme_mgt_tspec()
+ */
+
+
+/*
+ * Handling the suspend and resume system events, we need to block
+ * until the SME sends the response to our indication.
+ * We use the sme_init_request() and sme_wait_for_reply()
+ * to implement this behavior in the following functions:
+ * sme_sys_suspend()
+ * sme_sys_resume()
+ */
+
+#define UNIFI_SME_MGT_SHORT_TIMEOUT    10000
+#define UNIFI_SME_MGT_LONG_TIMEOUT     19000
+#define UNIFI_SME_SYS_LONG_TIMEOUT     10000
+
+#ifdef UNIFI_DEBUG
+# define sme_wait_for_reply(priv, t) _sme_wait_for_reply(priv, t, __func__)
+#else
+# define sme_wait_for_reply(priv, t) _sme_wait_for_reply(priv, t, NULL)
+#endif
+
+static int
+sme_init_request(unifi_priv_t *priv)
+{
+    if (priv == NULL) {
+        unifi_error(priv, "sme_init_request: Invalid priv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG5, "sme_init_request: wait sem\n");
+
+    /* Grab the SME semaphore until the reply comes, or timeout */
+    if (down_interruptible(&priv->sme_sem)) {
+        unifi_error(priv, "sme_init_request: Failed to get SME semaphore\n");
+        return -EIO;
+    }
+    unifi_trace(priv, UDBG5, "sme_init_request: got sem: pending\n");
+
+    priv->sme_reply.request_status = SME_REQUEST_PENDING;
+
+    return 0;
+
+} /* sme_init_request() */
+
+
+void
+uf_sme_complete_request(unifi_priv_t *priv, CsrResult reply_status, const char *func)
+{
+    if (priv == NULL) {
+        unifi_error(priv, "sme_complete_request: Invalid priv\n");
+        return;
+    }
+
+    if (priv->sme_reply.request_status != SME_REQUEST_PENDING) {
+        unifi_notice(priv,
+                    "sme_complete_request: request not pending %s (s:%d)\n",
+                    (func ? func : ""), priv->sme_reply.request_status);
+        return;
+    }
+    unifi_trace(priv, UDBG5,
+                "sme_complete_request: completed %s (s:%d)\n",
+                (func ? func : ""), priv->sme_reply.request_status);
+
+    priv->sme_reply.request_status = SME_REQUEST_RECEIVED;
+    priv->sme_reply.reply_status = reply_status;
+
+    wake_up_interruptible(&priv->sme_request_wq);
+
+    return;
+}
+
+
+void
+uf_sme_cancel_request(unifi_priv_t *priv, CsrResult reply_status)
+{
+    /* Check for a blocking SME request in progress, and cancel the wait.
+     * This should be used when the character device is closed.
+     */
+
+    if (priv == NULL) {
+        unifi_error(priv, "sme_cancel_request: Invalid priv\n");
+        return;
+    }
+
+    /* If no request is pending, nothing to wake up */
+    if (priv->sme_reply.request_status != SME_REQUEST_PENDING) {
+        unifi_trace(priv, UDBG5,
+                    "sme_cancel_request: no request was pending (s:%d)\n",
+                    priv->sme_reply.request_status);
+        /* Nothing to do */
+        return;
+    }
+    unifi_trace(priv, UDBG5,
+                "sme_cancel_request: request cancelled (s:%d)\n",
+                priv->sme_reply.request_status);
+
+    /* Wake up the wait with an error status */
+    priv->sme_reply.request_status = SME_REQUEST_CANCELLED;
+    priv->sme_reply.reply_status = reply_status; /* unimportant since the CANCELLED state will fail the ioctl */
+
+    wake_up_interruptible(&priv->sme_request_wq);
+
+    return;
+}
+
+
+static int
+_sme_wait_for_reply(unifi_priv_t *priv,
+        unsigned long timeout, const char *func)
+{
+    long r;
+
+    unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s sleep\n", func ? func : "");
+    r = wait_event_interruptible_timeout(priv->sme_request_wq,
+                                         (priv->sme_reply.request_status != SME_REQUEST_PENDING),
+                                         msecs_to_jiffies(timeout));
+    unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s awake (%d)\n", func ? func : "", r);
+
+    if (r == -ERESTARTSYS) {
+        /* The thread was killed */
+        unifi_info(priv, "ERESTARTSYS in _sme_wait_for_reply\n");
+        up(&priv->sme_sem);
+        return r;
+    }
+    if (priv->sme_reply.request_status == SME_REQUEST_CANCELLED) {
+        unifi_trace(priv, UDBG5, "Cancelled waiting for SME to reply (%s s:%d, t:%d, r:%d)\n",
+                    (func ? func : ""), priv->sme_reply.request_status, timeout, r);
+
+        /* Release the SME semaphore that was downed in sme_init_request() */
+        up(&priv->sme_sem);
+        return -EIO; /* fail the ioctl */
+    }
+    if ((r == 0) && (priv->sme_reply.request_status != SME_REQUEST_RECEIVED)) {
+        unifi_notice(priv, "Timeout waiting for SME to reply (%s s:%d, t:%d)\n",
+                     (func ? func : ""), priv->sme_reply.request_status, timeout);
+
+        priv->sme_reply.request_status = SME_REQUEST_TIMEDOUT;
+
+        /* Release the SME semaphore that was downed in sme_init_request() */
+        up(&priv->sme_sem);
+
+        return -ETIMEDOUT;
+    }
+
+    unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s received (%d)\n",
+                func ? func : "", r);
+
+    /* Release the SME semaphore that was downed in sme_init_request() */
+    up(&priv->sme_sem);
+
+    return 0;
+} /* sme_wait_for_reply() */
+
+
+
+
+#ifdef CSR_SUPPORT_WEXT
+int sme_mgt_wifi_on(unifi_priv_t *priv)
+{
+    CsrUint16 numElements;
+    CsrWifiSmeDataBlock* dataList;
+#ifdef CSR_SUPPORT_WEXT_AP
+    int r;
+#endif
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_wifi_on: invalid smepriv\n");
+        return -EIO;
+    }
+
+    if (priv->mib_data.length) {
+        numElements = 1;
+        dataList = &priv->mib_data;
+    } else {
+        numElements = 0;
+        dataList = NULL;
+    }
+    /* Start the SME */
+#ifdef CSR_SUPPORT_WEXT_AP
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+#endif
+    CsrWifiSmeWifiOnReqSend(0, priv->sta_mac_address, numElements, dataList);
+#ifdef CSR_SUPPORT_WEXT_AP
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT);
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_wifi_on: unifi_mgt_wifi_oo_req <-- (r=%d, status=%d)\n",
+                r, priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    return 0;
+#endif
+} /* sme_mgt_wifi_on() */
+
+
+int sme_mgt_wifi_off(unifi_priv_t *priv)
+{
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_wifi_off: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    /* Stop the SME */
+    CsrWifiSmeWifiOffReqSend(0);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_wifi_off: unifi_mgt_wifi_off_req <-- (r=%d, status=%d)\n",
+                r, priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+
+} /* sme_mgt_wifi_off */
+
+int sme_mgt_key(unifi_priv_t *priv, CsrWifiSmeKey *sme_key,
+        CsrWifiSmeListAction action)
+{
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_key: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeKeyReqSend(0, CSR_WIFI_INTERFACE_IN_USE, action, *sme_key);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+}
+
+
+int sme_mgt_scan_full(unifi_priv_t *priv,
+        CsrWifiSsid *specific_ssid,
+        int num_channels,
+        unsigned char *channel_list)
+{
+    CsrWifiMacAddress bcastAddress = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
+    CsrBool is_active = (num_channels > 0) ? TRUE : FALSE;
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_scan_full: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_scan_full: -->\n");
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    /* If a channel list is provided, do an active scan */
+    if (is_active) {
+        unifi_trace(priv, UDBG1,
+                    "channel list - num_channels: %d, active scan\n",
+                    num_channels);
+    }
+
+    CsrWifiSmeScanFullReqSend(0,
+                              specific_ssid->length?1:0, /* 0 or 1 SSIDS */
+                              specific_ssid,
+                              bcastAddress,
+                              is_active,
+                              CSR_WIFI_SME_BSS_TYPE_ANY_BSS,
+                              CSR_WIFI_SME_SCAN_TYPE_ALL,
+                              (CsrUint16)num_channels, channel_list,
+                              0, NULL);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_scan_full: <-- (status=%d)\n", priv->sme_reply.reply_status);
+    if (priv->sme_reply.reply_status == CSR_WIFI_RESULT_UNAVAILABLE) {
+        return 0; /* initial scan already underway */
+    } else {
+        return convert_sme_error(priv->sme_reply.reply_status);
+    }
+}
+
+
+int sme_mgt_scan_results_get_async(unifi_priv_t *priv,
+        struct iw_request_info *info,
+        char *scan_results,
+        long scan_results_len)
+{
+    CsrUint16 scan_result_list_count;
+    CsrWifiSmeScanResult *scan_result_list;
+    CsrWifiSmeScanResult *scan_result;
+    int r;
+    int i;
+    char *current_ev = scan_results;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_scan_results_get_async: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeScanResultsGetReqSend(0);
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    scan_result_list_count = priv->sme_reply.reply_scan_results_count;
+    scan_result_list = priv->sme_reply.reply_scan_results;
+    unifi_trace(priv, UDBG2,
+                "scan_results: Scan returned %d, numElements=%d\n",
+                r, scan_result_list_count);
+
+    /* OK, now we have the scan results */
+    for (i = 0; i < scan_result_list_count; ++i) {
+        scan_result = &scan_result_list[i];
+
+        unifi_trace(priv, UDBG2, "Scan Result: %.*s\n",
+                    scan_result->ssid.length,
+                    scan_result->ssid.ssid);
+
+        r = unifi_translate_scan(priv->netdev[0], info,
+                                 current_ev,
+                                 scan_results + scan_results_len,
+                                 scan_result, i+1);
+
+        if (r < 0) {
+            CsrPmemFree(scan_result_list);
+            priv->sme_reply.reply_scan_results_count = 0;
+            priv->sme_reply.reply_scan_results = NULL;
+            return r;
+        }
+
+        current_ev += r;
+    }
+
+    /*
+     * Free the scan results allocated in unifi_mgt_scan_results_get_cfm()
+     * and invalidate the reply_scan_results to avoid re-using
+     * the freed pointers.
+     */
+    CsrPmemFree(scan_result_list);
+    priv->sme_reply.reply_scan_results_count = 0;
+    priv->sme_reply.reply_scan_results = NULL;
+
+    unifi_trace(priv, UDBG2,
+                "scan_results: Scan translated to %d bytes\n",
+                current_ev - scan_results);
+    return (current_ev - scan_results);
+}
+
+
+int sme_mgt_connect(unifi_priv_t *priv)
+{
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_connect: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG2, "sme_mgt_connect: %.*s\n",
+                priv->connection_config.ssid.length,
+                priv->connection_config.ssid.ssid);
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeConnectReqSend(0, CSR_WIFI_INTERFACE_IN_USE, priv->connection_config);
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    if (priv->sme_reply.reply_status) {
+        unifi_trace(priv, UDBG1, "sme_mgt_connect: failed with SME status %d\n",
+                    priv->sme_reply.reply_status);
+    }
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+}
+
+
+int sme_mgt_disconnect(unifi_priv_t *priv)
+{
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_disconnect: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeDisconnectReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_disconnect: <-- (status=%d)\n", priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+}
+
+
+int sme_mgt_pmkid(unifi_priv_t *priv,
+        CsrWifiSmeListAction action,
+        CsrWifiSmePmkidList *pmkid_list)
+{
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_pmkid: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmePmkidReqSend(0, CSR_WIFI_INTERFACE_IN_USE, action,
+                        pmkid_list->pmkidsCount, pmkid_list->pmkids);
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_pmkid: <-- (status=%d)\n", priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+}
+
+
+int sme_mgt_mib_get(unifi_priv_t *priv,
+        unsigned char *varbind, int *length)
+{
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_mib_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    priv->mib_cfm_buffer = varbind;
+    priv->mib_cfm_buffer_length = MAX_VARBIND_LENGTH;
+
+    CsrWifiSmeMibGetReqSend(0, *length, varbind);
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        priv->mib_cfm_buffer_length = 0;
+        priv->mib_cfm_buffer = NULL;
+        return r;
+    }
+
+    *length = priv->mib_cfm_buffer_length;
+
+    priv->mib_cfm_buffer_length = 0;
+    priv->mib_cfm_buffer = NULL;
+    unifi_trace(priv, UDBG4, "sme_mgt_mib_get: <-- (status=%d)\n", priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+}
+
+int sme_mgt_mib_set(unifi_priv_t *priv,
+        unsigned char *varbind, int length)
+{
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_mib_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeMibSetReqSend(0, length, varbind);
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_mib_set: <-- (status=%d)\n", priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+}
+
+#endif /* CSR_SUPPORT_WEXT */
+
+int sme_mgt_power_config_set(unifi_priv_t *priv, CsrWifiSmePowerConfig *powerConfig)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_set_value_async: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmePowerConfigSetReqSend(0, *powerConfig);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_set_value_async: unifi_mgt_set_value_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_set_value: invalid smepriv\n");
+        return -EIO;
+    }
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtPowerConfigSetReq(priv->smepriv, *powerConfig);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+int sme_mgt_sme_config_set(unifi_priv_t *priv, CsrWifiSmeStaConfig *staConfig, CsrWifiSmeDeviceConfig *deviceConfig)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_sme_config_set: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeSmeStaConfigSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE, *staConfig);
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_sme_config_set: CsrWifiSmeSmeStaConfigSetReq <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeSmeCommonConfigSetReqSend(0, *deviceConfig);
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_sme_config_set: CsrWifiSmeSmeCommonConfigSetReq <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_sme_config_set: invalid smepriv\n");
+        return -EIO;
+    }
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtSmeConfigSetReq(priv->smepriv, *staConfig);
+    status = CsrWifiSmeMgtDeviceConfigSetReq(priv->smepriv, *deviceConfig);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+#ifdef CSR_SUPPORT_WEXT
+
+int sme_mgt_mib_config_set(unifi_priv_t *priv, CsrWifiSmeMibConfig *mibConfig)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_mib_config_set: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeMibConfigSetReqSend(0, *mibConfig);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_mib_config_set: unifi_mgt_set_mib_config_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_mib_config_set: invalid smepriv\n");
+        return -EIO;
+    }
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtMibConfigSetReq(priv->smepriv, *mibConfig);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+int sme_mgt_coex_config_set(unifi_priv_t *priv, CsrWifiSmeCoexConfig *coexConfig)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_coex_config_set: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeCoexConfigSetReqSend(0, *coexConfig);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_coex_config_set: unifi_mgt_set_mib_config_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_coex_config_set: invalid smepriv\n");
+        return -EIO;
+    }
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtCoexConfigSetReq(priv->smepriv, *coexConfig);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+#endif /* CSR_SUPPORT_WEXT */
+
+int sme_mgt_host_config_set(unifi_priv_t *priv, CsrWifiSmeHostConfig *hostConfig)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_host_config_set: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeHostConfigSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE, *hostConfig);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_host_config_set: unifi_mgt_set_host_config_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_host_config_set: invalid smepriv\n");
+        return -EIO;
+    }
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtHostConfigSetReq(priv->smepriv, *hostConfig);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+#ifdef CSR_SUPPORT_WEXT
+
+int sme_mgt_versions_get(unifi_priv_t *priv, CsrWifiSmeVersions *versions)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_versions_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_versions_get: unifi_mgt_versions_get_req -->\n");
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeVersionsGetReqSend(0);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    /* store the reply */
+    if (versions != NULL) {
+        memcpy((unsigned char*)versions,
+               (unsigned char*)&priv->sme_reply.versions,
+               sizeof(CsrWifiSmeVersions));
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_versions_get: unifi_mgt_versions_get_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtVersionsGetReq(priv->smepriv, versions);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+#endif /* CSR_SUPPORT_WEXT */
+
+int sme_mgt_power_config_get(unifi_priv_t *priv, CsrWifiSmePowerConfig *powerConfig)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_power_config_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_power_config_get: unifi_mgt_power_config_req -->\n");
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmePowerConfigGetReqSend(0);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    /* store the reply */
+    if (powerConfig != NULL) {
+        memcpy((unsigned char*)powerConfig,
+               (unsigned char*)&priv->sme_reply.powerConfig,
+               sizeof(CsrWifiSmePowerConfig));
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_get_versions: unifi_mgt_power_config_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtPowerConfigGetReq(priv->smepriv, powerConfig);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+int sme_mgt_host_config_get(unifi_priv_t *priv, CsrWifiSmeHostConfig *hostConfig)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_host_config_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_host_config_get: unifi_mgt_host_config_get_req -->\n");
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeHostConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    /* store the reply */
+    if (hostConfig != NULL) {
+        memcpy((unsigned char*)hostConfig,
+               (unsigned char*)&priv->sme_reply.hostConfig,
+               sizeof(CsrWifiSmeHostConfig));
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_host_config_get: unifi_mgt_host_config_get_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtHostConfigGetReq(priv->smepriv, hostConfig);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+int sme_mgt_sme_config_get(unifi_priv_t *priv, CsrWifiSmeStaConfig *staConfig, CsrWifiSmeDeviceConfig *deviceConfig)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_sme_config_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_sme_config_get: unifi_mgt_sme_config_get_req -->\n");
+
+    /* Common device config */
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeSmeCommonConfigGetReqSend(0);
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    /* store the reply */
+    if (deviceConfig != NULL) {
+        memcpy((unsigned char*)deviceConfig,
+               (unsigned char*)&priv->sme_reply.deviceConfig,
+               sizeof(CsrWifiSmeDeviceConfig));
+    }
+
+    /* STA config */
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeSmeStaConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    /* store the reply */
+    if (staConfig != NULL) {
+        memcpy((unsigned char*)staConfig,
+               (unsigned char*)&priv->sme_reply.staConfig,
+               sizeof(CsrWifiSmeStaConfig));
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_sme_config_get: unifi_mgt_sme_config_get_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtSmeConfigGetReq(priv->smepriv, staConfig);
+    status = CsrWifiSmeMgtDeviceConfigGetReq(priv->smepriv, deviceConfig);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+int sme_mgt_coex_info_get(unifi_priv_t *priv, CsrWifiSmeCoexInfo *coexInfo)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_coex_info_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_coex_info_get: unifi_mgt_coex_info_get_req -->\n");
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeCoexInfoGetReqSend(0);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    /* store the reply */
+    if (coexInfo != NULL) {
+        memcpy((unsigned char*)coexInfo,
+               (unsigned char*)&priv->sme_reply.coexInfo,
+               sizeof(CsrWifiSmeCoexInfo));
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_coex_info_get: unifi_mgt_coex_info_get_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtCoexInfoGetReq(priv->smepriv, coexInfo);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+#ifdef CSR_SUPPORT_WEXT
+
+int sme_mgt_coex_config_get(unifi_priv_t *priv, CsrWifiSmeCoexConfig *coexConfig)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_coex_config_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_coex_config_get: unifi_mgt_coex_config_get_req -->\n");
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeCoexConfigGetReqSend(0);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    /* store the reply */
+    if (coexConfig != NULL) {
+        memcpy((unsigned char*)coexConfig,
+               (unsigned char*)&priv->sme_reply.coexConfig,
+               sizeof(CsrWifiSmeCoexConfig));
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_coex_config_get: unifi_mgt_coex_config_get_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtCoexConfigGetReq(priv->smepriv, coexConfig);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+int sme_mgt_mib_config_get(unifi_priv_t *priv, CsrWifiSmeMibConfig *mibConfig)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_mib_config_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_mib_config_get: unifi_mgt_mib_config_get_req -->\n");
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeMibConfigGetReqSend(0);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    /* store the reply */
+    if (mibConfig != NULL) {
+        memcpy((unsigned char*)mibConfig,
+               (unsigned char*)&priv->sme_reply.mibConfig,
+               sizeof(CsrWifiSmeMibConfig));
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_mib_config_get: unifi_mgt_mib_config_get_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtMibConfigGetReq(priv->smepriv, mibConfig);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+int sme_mgt_connection_info_get(unifi_priv_t *priv, CsrWifiSmeConnectionInfo *connectionInfo)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_connection_info_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_connection_info_get: unifi_mgt_connection_info_get_req -->\n");
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeConnectionInfoGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    /* store the reply */
+    if (connectionInfo != NULL) {
+        memcpy((unsigned char*)connectionInfo,
+               (unsigned char*)&priv->sme_reply.connectionInfo,
+               sizeof(CsrWifiSmeConnectionInfo));
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_connection_info_get: unifi_mgt_connection_info_get_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtConnectionInfoGetReq(priv->smepriv, connectionInfo);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+int sme_mgt_connection_config_get(unifi_priv_t *priv, CsrWifiSmeConnectionConfig *connectionConfig)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_connection_config_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_connection_config_get: unifi_mgt_connection_config_get_req -->\n");
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeConnectionConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    /* store the reply */
+    if (connectionConfig != NULL) {
+        memcpy((unsigned char*)connectionConfig,
+               (unsigned char*)&priv->sme_reply.connectionConfig,
+               sizeof(CsrWifiSmeConnectionConfig));
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_connection_config_get: unifi_mgt_connection_config_get_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtConnectionConfigGetReq(priv->smepriv, connectionConfig);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+int sme_mgt_connection_stats_get(unifi_priv_t *priv, CsrWifiSmeConnectionStats *connectionStats)
+{
+#ifdef CSR_SME_USERSPACE
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_connection_stats_get: invalid smepriv\n");
+        return -EIO;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_connection_stats_get: unifi_mgt_connection_stats_get_req -->\n");
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeConnectionStatsGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    /* store the reply */
+    if (connectionStats != NULL) {
+        memcpy((unsigned char*)connectionStats,
+               (unsigned char*)&priv->sme_reply.connectionStats,
+               sizeof(CsrWifiSmeConnectionStats));
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_mgt_connection_stats_get: unifi_mgt_connection_stats_get_req <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+
+    return convert_sme_error(priv->sme_reply.reply_status);
+#else
+    CsrResult status;
+    CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
+    status = CsrWifiSmeMgtConnectionStatsGetReq(priv->smepriv, connectionStats);
+    CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
+    return convert_sme_error(status);
+#endif
+}
+
+#endif /* CSR_SUPPORT_WEXT */
+
+int sme_mgt_packet_filter_set(unifi_priv_t *priv)
+{
+    CsrWifiIp4Address ipAddress = {{0xFF, 0xFF, 0xFF, 0xFF }};
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_packet_filter_set: invalid smepriv\n");
+        return -EIO;
+    }
+    if (priv->packet_filters.arp_filter) {
+        ipAddress.a[0] = (priv->sta_ip_address      ) & 0xFF;
+        ipAddress.a[1] = (priv->sta_ip_address >>  8) & 0xFF;
+        ipAddress.a[2] = (priv->sta_ip_address >> 16) & 0xFF;
+        ipAddress.a[3] = (priv->sta_ip_address >> 24) & 0xFF;
+    }
+
+    unifi_trace(priv, UDBG5,
+                "sme_mgt_packet_filter_set: IP address %d.%d.%d.%d\n",
+                ipAddress.a[0], ipAddress.a[1],
+                ipAddress.a[2], ipAddress.a[3]);
+
+    /* Doesn't block for a confirm */
+    CsrWifiSmePacketFilterSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE,
+                                     priv->packet_filters.tclas_ies_length,
+                                     priv->filter_tclas_ies,
+                                     priv->packet_filters.filter_mode,
+                                     ipAddress);
+    return 0;
+}
+
+int sme_mgt_tspec(unifi_priv_t *priv, CsrWifiSmeListAction action,
+        CsrUint32 tid, CsrWifiSmeDataBlock *tspec, CsrWifiSmeDataBlock *tclas)
+{
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_mgt_tspec: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiSmeTspecReqSend(0, CSR_WIFI_INTERFACE_IN_USE,
+                           action, tid, TRUE, 0,
+                           tspec->length, tspec->data,
+                           tclas->length, tclas->data);
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4, "sme_mgt_tspec: <-- (status=%d)\n", priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+}
+
+
+
+int sme_sys_suspend(unifi_priv_t *priv)
+{
+    int r;
+    CsrResult csrResult;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_sys_suspend: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    /* Suspend the SME, which MAY cause it to power down UniFi */
+    CsrWifiRouterCtrlSuspendIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, 0, priv->wol_suspend);
+    r = sme_wait_for_reply(priv, UNIFI_SME_SYS_LONG_TIMEOUT);
+    if (r) {
+        /* No reply - forcibly power down in case the request wasn't processed */
+        unifi_notice(priv,
+                     "suspend: SME did not reply %s, ",
+                     (priv->ptest_mode | priv->wol_suspend) ? "leave powered" : "power off UniFi anyway\n");
+
+        /* Leave power on for production test, though */
+        if (!priv->ptest_mode) {
+            /* Put UniFi to deep sleep, in case we can not power it off */
+            CsrSdioClaim(priv->sdio);
+            unifi_trace(priv, UDBG1, "Force deep sleep");
+            csrResult = unifi_force_low_power_mode(priv->card);
+
+            /* For WOL, the UniFi must stay powered */
+            if (!priv->wol_suspend) {
+                unifi_trace(priv, UDBG1, "Power off\n");
+                CsrSdioPowerOff(priv->sdio);
+            }
+            CsrSdioRelease(priv->sdio);
+        }
+    }
+
+    if (priv->wol_suspend) {
+        unifi_trace(priv, UDBG1, "UniFi left powered for WOL\n");
+
+        /* Remove the IRQ, which also disables the card SDIO interrupt.
+         * Disabling the card SDIO interrupt enables the PIO WOL source.
+         * Removal of the of the handler ensures that in both SDIO and PIO cases
+         * the card interrupt only wakes the host. The card will be polled
+         * after resume to handle any pending data.
+         */
+        if (csr_sdio_linux_remove_irq(priv->sdio)) {
+            unifi_notice(priv, "WOL csr_sdio_linux_remove_irq failed\n");
+        }
+
+        if (enable_wol == UNIFI_WOL_SDIO) {
+            /* Because csr_sdio_linux_remove_irq() disabled the card SDIO interrupt,
+             * it must be left enabled to wake-on-SDIO.
+             */
+            unifi_trace(priv, UDBG1, "Enable card SDIO interrupt for SDIO WOL\n");
+
+            CsrSdioClaim(priv->sdio);
+            csrResult = CsrSdioInterruptEnable(priv->sdio);
+            CsrSdioRelease(priv->sdio);
+
+            if (csrResult != CSR_RESULT_SUCCESS) {
+                unifi_error(priv, "WOL CsrSdioInterruptEnable failed %d\n", csrResult);
+            }
+        } else {
+            unifi_trace(priv, UDBG1, "Disabled card SDIO interrupt for PIO WOL\n");
+        }
+
+        /* Prevent the BH thread from running during the suspend.
+         * Upon resume, sme_sys_resume() will trigger a wifi-on, this will cause
+         * the BH thread to be re-enabled and reinstall the ISR.
+         */
+        priv->bh_thread.block_thread = 1;
+
+        unifi_trace(priv, UDBG1, "unifi_suspend: suspended BH");
+    }
+
+    /* Consider UniFi to be uninitialised */
+    priv->init_progress = UNIFI_INIT_NONE;
+
+    unifi_trace(priv, UDBG1, "sme_sys_suspend: <-- (r=%d status=%d)\n", r, priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+}
+
+
+int sme_sys_resume(unifi_priv_t *priv)
+{
+    int r;
+
+    unifi_trace(priv, UDBG1, "sme_sys_resume %s\n", priv->wol_suspend ? "warm" : "");
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_sys_resume: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiRouterCtrlResumeIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, priv->wol_suspend);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_SYS_LONG_TIMEOUT);
+    if (r) {
+        unifi_notice(priv,
+                "resume: SME did not reply, return success anyway\n");
+    }
+
+    return 0;
+}
+
+#ifdef CSR_SUPPORT_WEXT_AP
+int sme_ap_stop(unifi_priv_t *priv,CsrUint16 interface_tag)
+{
+    int r;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_ap_stop: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiNmeApStopReqSend(0,interface_tag);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_ap_stop <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+
+}
+
+int sme_ap_start(unifi_priv_t *priv,CsrUint16 interface_tag,
+                 CsrWifiSmeApConfig_t * ap_config)
+{
+    int r;
+    CsrWifiSmeApP2pGoConfig p2p_go_param;
+    memset(&p2p_go_param,0,sizeof(CsrWifiSmeApP2pGoConfig));
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_ap_start: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiNmeApStartReqSend(0,interface_tag,CSR_WIFI_AP_TYPE_LEGACY,FALSE,
+                             ap_config->ssid,1,ap_config->channel,
+                             ap_config->credentials,ap_config->max_connections,
+                             p2p_go_param,FALSE);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+    if (r) {
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4,
+                "sme_ap_start <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+}
+
+int sme_ap_config(unifi_priv_t *priv,
+                  CsrWifiSmeApMacConfig *ap_mac_config,
+                  CsrWifiNmeApConfig *group_security_config)
+{
+    int r;
+    CsrWifiSmeApP2pGoConfig p2p_go_param;
+    memset(&p2p_go_param,0,sizeof(CsrWifiSmeApP2pGoConfig));
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_ap_config: invalid smepriv\n");
+        return -EIO;
+    }
+
+    r = sme_init_request(priv);
+    if (r) {
+        return -EIO;
+    }
+
+    CsrWifiNmeApConfigSetReqSend(0,*group_security_config,
+                                 *ap_mac_config);
+
+    r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
+
+    unifi_trace(priv, UDBG4,
+                "sme_ap_config <-- (r=%d status=%d)\n",
+                r, priv->sme_reply.reply_status);
+    return convert_sme_error(priv->sme_reply.reply_status);
+}
+#endif
diff --git a/drivers/staging/csr/sme_mgt.c b/drivers/staging/csr/sme_mgt.c
new file mode 100644
index 0000000..ab70216
--- /dev/null
+++ b/drivers/staging/csr/sme_mgt.c
@@ -0,0 +1,1018 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     sme_mgt.c
+ *
+ * PURPOSE:
+ *      This file contains the driver specific implementation of
+ *      the SME MGT SAP.
+ *      It is part of the porting exercise.
+ *
+ * Copyright (C) 2008-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+#include "csr_wifi_hip_unifiversion.h"
+#include "unifi_priv.h"
+#include "csr_wifi_hip_conversions.h"
+/*
+ * This file implements the SME MGT API. It contains the following functions:
+ * CsrWifiSmeWifiFlightmodeCfmSend()
+ * CsrWifiSmeWifiOnCfmSend()
+ * CsrWifiSmeWifiOffCfmSend()
+ * CsrWifiSmeWifiOffIndSend()
+ * CsrWifiSmeScanFullCfmSend()
+ * CsrWifiSmeScanResultsGetCfmSend()
+ * CsrWifiSmeScanResultIndSend()
+ * CsrWifiSmeScanResultsFlushCfmSend()
+ * CsrWifiSmeConnectCfmSend()
+ * CsrWifiSmeMediaStatusIndSend()
+ * CsrWifiSmeDisconnectCfmSend()
+ * CsrWifiSmeKeyCfmSend()
+ * CsrWifiSmeMulticastAddressCfmSend()
+ * CsrWifiSmeSetValueCfmSend()
+ * CsrWifiSmeGetValueCfmSend()
+ * CsrWifiSmeMicFailureIndSend()
+ * CsrWifiSmePmkidCfmSend()
+ * CsrWifiSmePmkidCandidateListIndSend()
+ * CsrWifiSmeMibSetCfmSend()
+ * CsrWifiSmeMibGetCfmSend()
+ * CsrWifiSmeMibGetNextCfmSend()
+ * CsrWifiSmeConnectionQualityIndSend()
+ * CsrWifiSmePacketFilterSetCfmSend()
+ * CsrWifiSmeTspecCfmSend()
+ * CsrWifiSmeTspecIndSend()
+ * CsrWifiSmeBlacklistCfmSend()
+ * CsrWifiSmeEventMaskSetCfmSend()
+ * CsrWifiSmeRoamStartIndSend()
+ * CsrWifiSmeRoamCompleteIndSend()
+ * CsrWifiSmeAssociationStartIndSend()
+ * CsrWifiSmeAssociationCompleteIndSend()
+ * CsrWifiSmeIbssStationIndSend()
+ */
+
+
+void CsrWifiSmeMicFailureIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeMicFailureInd* ind = (CsrWifiSmeMicFailureInd*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeMicFailureIndSend: invalid priv\n");
+        return;
+    }
+
+    unifi_trace(priv, UDBG1,
+                "CsrWifiSmeMicFailureIndSend: count=%d, KeyType=%d\n",
+                ind->count, ind->keyType);
+
+    wext_send_michaelmicfailure_event(priv, ind->count, ind->address, ind->keyType, ind->interfaceTag);
+#endif
+}
+
+
+void CsrWifiSmePmkidCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmePmkidCfm* cfm = (CsrWifiSmePmkidCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmePmkidCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    /*
+     * WEXT never does a GET operation the PMKIDs, so we don't need
+     * handle data returned in pmkids.
+     */
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+
+void CsrWifiSmePmkidCandidateListIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmePmkidCandidateListInd* ind = (CsrWifiSmePmkidCandidateListInd*)msg;
+    int i;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "CsrWifiSmePmkidCandidateListIndSend: invalid smepriv\n");
+        return;
+    }
+
+    for (i = 0; i < ind->pmkidCandidatesCount; i++)
+    {
+        wext_send_pmkid_candidate_event(priv, ind->pmkidCandidates[i].bssid, ind->pmkidCandidates[i].preAuthAllowed, ind->interfaceTag);
+    }
+#endif
+}
+
+void CsrWifiSmeScanResultsFlushCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeScanResultsGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeScanResultsGetCfm* cfm = (CsrWifiSmeScanResultsGetCfm*)msg;
+    int bytesRequired = cfm->scanResultsCount * sizeof(CsrWifiSmeScanResult);
+    int i;
+    CsrUint8* current_buff;
+    CsrWifiSmeScanResult* scanCopy;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeScanResultsGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    /* Calc the size of the buffer reuired */
+    for (i = 0; i < cfm->scanResultsCount; ++i) {
+        const CsrWifiSmeScanResult *scan_result = &cfm->scanResults[i];
+        bytesRequired += scan_result->informationElementsLength;
+    }
+
+    /* Take a Copy of the scan Results :-) */
+    scanCopy = CsrPmemAlloc(bytesRequired);
+    memcpy(scanCopy, cfm->scanResults, sizeof(CsrWifiSmeScanResult) * cfm->scanResultsCount);
+
+    /* Take a Copy of the Info Elements AND update the scan result pointers */
+    current_buff = (CsrUint8*)&scanCopy[cfm->scanResultsCount];
+    for (i = 0; i < cfm->scanResultsCount; ++i)
+    {
+        CsrWifiSmeScanResult *scan_result = &scanCopy[i];
+        CsrMemCpy(current_buff, scan_result->informationElements, scan_result->informationElementsLength);
+        scan_result->informationElements = current_buff;
+        current_buff += scan_result->informationElementsLength;
+    }
+
+    priv->sme_reply.reply_scan_results_count = cfm->scanResultsCount;
+    priv->sme_reply.reply_scan_results = scanCopy;
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+
+void CsrWifiSmeScanFullCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeScanFullCfm* cfm = (CsrWifiSmeScanFullCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeScanFullCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+
+void CsrWifiSmeScanResultIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+
+}
+
+
+void CsrWifiSmeConnectCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeConnectCfm* cfm = (CsrWifiSmeConnectCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeConnectCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+
+void CsrWifiSmeDisconnectCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeDisconnectCfm* cfm = (CsrWifiSmeDisconnectCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeDisconnectCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+
+void CsrWifiSmeKeyCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeKeyCfm* cfm = (CsrWifiSmeKeyCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeKeyCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+
+void CsrWifiSmeMulticastAddressCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeMulticastAddressCfm* cfm = (CsrWifiSmeMulticastAddressCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeMulticastAddressCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeWifiFlightmodeCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeWifiFlightmodeCfm* cfm = (CsrWifiSmeWifiFlightmodeCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeWifiFlightmodeCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeWifiOnCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeWifiOnCfm* cfm = (CsrWifiSmeWifiOnCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeWifiOnCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    unifi_trace(priv, UDBG4,
+                "CsrWifiSmeWifiOnCfmSend: wake up status %d\n", cfm->status);
+#ifdef CSR_SUPPORT_WEXT_AP
+    sme_complete_request(priv, cfm->status);
+#endif
+
+#endif
+}
+
+void CsrWifiSmeWifiOffCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeWifiOffCfm* cfm = (CsrWifiSmeWifiOffCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeWifiOffCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+
+void CsrWifiSmeWifiOffIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeWifiOffInd* ind = (CsrWifiSmeWifiOffInd*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiRouterCtrlStoppedReqSend: Invalid ospriv.\n");
+        return;
+    }
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlStoppedReqSend: invalid smepriv\n");
+        return;
+    }
+
+    /*
+     * If the status indicates an error, the SME is in a stopped state.
+     * We need to start it again in order to reinitialise UniFi.
+     */
+    switch (ind->reason) {
+        case CSR_WIFI_SME_CONTROL_INDICATION_ERROR:
+          unifi_trace(priv, UDBG1,
+                      "CsrWifiRouterCtrlStoppedReqSend: Restarting SME (ind:%d)\n",
+                      ind->reason);
+
+          /* On error, restart the SME */
+          sme_mgt_wifi_on(priv);
+          break;
+        case CSR_WIFI_SME_CONTROL_INDICATION_EXIT:
+#ifdef CSR_SUPPORT_WEXT_AP
+          sme_complete_request(priv, 0);
+#endif
+          break;
+        default:
+          break;
+    }
+
+#endif
+}
+
+void CsrWifiSmeVersionsGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeVersionsGetCfm* cfm = (CsrWifiSmeVersionsGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeVersionsGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    priv->sme_reply.versions = cfm->versions;
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmePowerConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmePowerConfigGetCfm* cfm = (CsrWifiSmePowerConfigGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmePowerConfigGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    priv->sme_reply.powerConfig = cfm->powerConfig;
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiSmeHostConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeHostConfigGetCfm* cfm = (CsrWifiSmeHostConfigGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeHostConfigGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    priv->sme_reply.hostConfig = cfm->hostConfig;
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiSmeCoexInfoGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeCoexInfoGetCfm* cfm = (CsrWifiSmeCoexInfoGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeCoexInfoGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    priv->sme_reply.coexInfo = cfm->coexInfo;
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiSmeCoexConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeCoexConfigGetCfm* cfm = (CsrWifiSmeCoexConfigGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeCoexConfigGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    priv->sme_reply.coexConfig = cfm->coexConfig;
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeMibConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeMibConfigGetCfm* cfm = (CsrWifiSmeMibConfigGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeMibConfigGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    priv->sme_reply.mibConfig = cfm->mibConfig;
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeConnectionInfoGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeConnectionInfoGetCfm* cfm = (CsrWifiSmeConnectionInfoGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeConnectionInfoGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    priv->sme_reply.connectionInfo = cfm->connectionInfo;
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeConnectionConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeConnectionConfigGetCfm* cfm = (CsrWifiSmeConnectionConfigGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeConnectionConfigGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    priv->sme_reply.connectionConfig = cfm->connectionConfig;
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeConnectionStatsGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeConnectionStatsGetCfm* cfm = (CsrWifiSmeConnectionStatsGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeConnectionStatsGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    priv->sme_reply.connectionStats = cfm->connectionStats;
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeMibSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeMibSetCfm* cfm = (CsrWifiSmeMibSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeMibSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeMibGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeMibGetCfm* cfm = (CsrWifiSmeMibGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeMibGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    if (cfm->mibAttribute == NULL) {
+        unifi_error(priv, "CsrWifiSmeMibGetCfmSend: Empty reply.\n");
+        sme_complete_request(priv, cfm->status);
+        return;
+    }
+
+    if ((priv->mib_cfm_buffer != NULL) &&
+        (priv->mib_cfm_buffer_length >= cfm->mibAttributeLength)) {
+        memcpy(priv->mib_cfm_buffer, cfm->mibAttribute, cfm->mibAttributeLength);
+        priv->mib_cfm_buffer_length = cfm->mibAttributeLength;
+    } else {
+        unifi_error(priv,
+                    "CsrWifiSmeMibGetCfmSend: No room to store MIB data (have=%d need=%d).\n",
+                    priv->mib_cfm_buffer_length, cfm->mibAttributeLength);
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeMibGetNextCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeMibGetNextCfm* cfm = (CsrWifiSmeMibGetNextCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeMibGetNextCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    /* Need to copy MIB data */
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeConnectionQualityIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeConnectionQualityInd* ind = (CsrWifiSmeConnectionQualityInd*)msg;
+    int signal, noise, snr;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeConnectionQualityIndSend: Invalid ospriv.\n");
+        return;
+    }
+
+    /*
+     * level and noise below are mapped into an unsigned 8 bit number,
+     * ranging from [-192; 63]. The way this is achieved is simply to
+     * add 0x100 onto the number if it is negative,
+     * once clipped to the correct range.
+     */
+    signal = ind->linkQuality.unifiRssi;
+    /* Clip range of snr */
+    snr    = (ind->linkQuality.unifiSnr > 0) ? ind->linkQuality.unifiSnr : 0; /* In dB relative, from 0 - 255 */
+    snr    = (snr < 255) ? snr : 255;
+    noise  = signal - snr;
+
+    /* Clip range of signal */
+    signal = (signal < 63) ? signal : 63;
+    signal = (signal > -192) ? signal : -192;
+
+    /* Clip range of noise */
+    noise = (noise < 63) ? noise : 63;
+    noise = (noise > -192) ? noise : -192;
+
+    /* Make u8 */
+    signal = ( signal < 0 ) ? signal + 0x100 : signal;
+    noise = ( noise < 0 ) ? noise + 0x100 : noise;
+
+    priv->wext_wireless_stats.qual.level   = (u8)signal; /* -192 : 63 */
+    priv->wext_wireless_stats.qual.noise   = (u8)noise;  /* -192 : 63 */
+    priv->wext_wireless_stats.qual.qual    = snr;         /* 0 : 255 */
+    priv->wext_wireless_stats.qual.updated = 0;
+
+#if WIRELESS_EXT > 16
+    priv->wext_wireless_stats.qual.updated |= IW_QUAL_LEVEL_UPDATED |
+                                              IW_QUAL_NOISE_UPDATED |
+                                              IW_QUAL_QUAL_UPDATED;
+#if WIRELESS_EXT > 18
+    priv->wext_wireless_stats.qual.updated |= IW_QUAL_DBM;
+#endif
+#endif
+#endif
+}
+
+void CsrWifiSmePacketFilterSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmePacketFilterSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    /* The packet filter set request does not block for a reply */
+}
+
+void CsrWifiSmeTspecCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeTspecCfm* cfm = (CsrWifiSmeTspecCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeTspecCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiSmeTspecIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeBlacklistCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeEventMaskSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+
+void CsrWifiSmeRoamStartIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeRoamCompleteIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    /* This is called when the association completes, before any 802.1x authentication */
+}
+
+void CsrWifiSmeAssociationStartIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeAssociationCompleteIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeIbssStationIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeWifiOnIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeRestrictedAccessEnableCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeRestrictedAccessDisableCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+
+void CsrWifiSmeAdhocConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeAdhocConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeAdhocConfigSetCfm* cfm = (CsrWifiSmeAdhocConfigSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeConfigSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeCalibrationDataGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeCalibrationDataSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeCalibrationDataSetCfm* cfm = (CsrWifiSmeCalibrationDataSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeConfigSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeCcxConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeCcxConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeCcxConfigSetCfm* cfm = (CsrWifiSmeCcxConfigSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeConfigSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeCloakedSsidsGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeCloakedSsidsSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeCloakedSsidsSetCfm* cfm = (CsrWifiSmeCloakedSsidsSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeConfigSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+
+void CsrWifiSmeCoexConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeCoexConfigSetCfm* cfm = (CsrWifiSmeCoexConfigSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeConfigSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeHostConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeHostConfigSetCfm* cfm = (CsrWifiSmeHostConfigSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeConfigSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiSmeLinkQualityGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+
+void CsrWifiSmeMibConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeMibConfigSetCfm* cfm = (CsrWifiSmeMibConfigSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeConfigSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmePermanentMacAddressGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmePowerConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmePowerConfigSetCfm* cfm = (CsrWifiSmePowerConfigSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeConfigSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiSmeRegulatoryDomainInfoGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeRoamingConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeMediaStatusIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeMediaStatusInd* ind = (CsrWifiSmeMediaStatusInd*)msg;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "CsrWifiSmeMediaStatusIndSend: invalid smepriv\n");
+        return;
+    }
+
+    if (ind->mediaStatus == CSR_WIFI_SME_MEDIA_STATUS_CONNECTED) {
+        /*
+         * Send wireless-extension event up to userland to announce
+         * connection.
+         */
+        wext_send_assoc_event(priv,
+                              (unsigned char *)ind->connectionInfo.bssid.a,
+                              (unsigned char *)ind->connectionInfo.assocReqInfoElements,
+                              ind->connectionInfo.assocReqInfoElementsLength,
+                              (unsigned char *)ind->connectionInfo.assocRspInfoElements,
+                              ind->connectionInfo.assocRspInfoElementsLength,
+                              (unsigned char *)ind->connectionInfo.assocScanInfoElements,
+                              ind->connectionInfo.assocScanInfoElementsLength);
+
+        unifi_trace(priv, UDBG2,
+                    "CsrWifiSmeMediaStatusIndSend: IBSS=%02X:%02X:%02X:%02X:%02X:%02X\n",
+                    ind->connectionInfo.bssid.a[0],
+                    ind->connectionInfo.bssid.a[1],
+                    ind->connectionInfo.bssid.a[2],
+                    ind->connectionInfo.bssid.a[3],
+                    ind->connectionInfo.bssid.a[4],
+                    ind->connectionInfo.bssid.a[5]);
+
+        sme_mgt_packet_filter_set(priv);
+
+    } else  {
+        /*
+         * Send wireless-extension event up to userland to announce
+         * connection lost to a BSS.
+         */
+        wext_send_disassoc_event(priv);
+    }
+#endif
+}
+
+void CsrWifiSmeRoamingConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeRoamingConfigSetCfm* cfm = (CsrWifiSmeRoamingConfigSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeRoamingConfigSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiSmeScanConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeScanConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_SUPPORT_WEXT
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeScanConfigSetCfm* cfm = (CsrWifiSmeScanConfigSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeConfigSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+#endif
+}
+
+void CsrWifiSmeStationMacAddressGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeSmeCommonConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeSmeCommonConfigGetCfm* cfm = (CsrWifiSmeSmeCommonConfigGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeCommonConfigGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    priv->sme_reply.deviceConfig = cfm->deviceConfig;
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiSmeSmeStaConfigGetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeSmeStaConfigGetCfm* cfm = (CsrWifiSmeSmeStaConfigGetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeStaConfigGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    priv->sme_reply.staConfig = cfm->smeConfig;
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiSmeSmeCommonConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeSmeCommonConfigSetCfm* cfm = (CsrWifiSmeSmeCommonConfigSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeCommonConfigGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiSmeSmeStaConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiSmeSmeStaConfigSetCfm* cfm = (CsrWifiSmeSmeStaConfigSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiSmeSmeStaConfigGetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiSmeGetInterfaceCapabilityCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeErrorIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeInfoIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeCoreDumpIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+void CsrWifiSmeAmpStatusChangeIndHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiSmeActivateCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+void CsrWifiSmeDeactivateCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+#ifdef CSR_SUPPORT_WEXT
+#ifdef CSR_SUPPORT_WEXT_AP
+void CsrWifiNmeApStartCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiNmeApStartCfm* cfm = (CsrWifiNmeApStartCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiNmeApStartCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiNmeApStopCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiNmeApStopCfm* cfm = (CsrWifiNmeApStopCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiNmeApStopCfmSend: Invalid ospriv.\n");
+        return;
+    }
+
+    sme_complete_request(priv, cfm->status);
+}
+
+void CsrWifiNmeApConfigSetCfmHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiNmeApConfigSetCfm* cfm = (CsrWifiNmeApConfigSetCfm*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiNmeApConfigSetCfmSend: Invalid ospriv.\n");
+        return;
+    }
+    sme_complete_request(priv, cfm->status);
+}
+#endif
+#endif
diff --git a/drivers/staging/csr/sme_native.c b/drivers/staging/csr/sme_native.c
new file mode 100644
index 0000000..2091109
--- /dev/null
+++ b/drivers/staging/csr/sme_native.c
@@ -0,0 +1,591 @@
+/*
+ * ***************************************************************************
+ *
+ *  FILE:     sme_native.c
+ *
+ * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ***************************************************************************
+ */
+
+#include <linux/netdevice.h>
+
+#include "unifi_priv.h"
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_conversions.h"
+
+static const unsigned char wildcard_address[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+int
+uf_sme_init(unifi_priv_t *priv)
+{
+    func_enter();
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+    sema_init(&priv->mlme_blocking_mutex, 1);
+#else
+    init_MUTEX(&priv->mlme_blocking_mutex);
+#endif
+
+#ifdef CSR_SUPPORT_WEXT
+    {
+        int r = uf_init_wext_interface(priv);
+        if (r != 0) {
+            func_exit();
+            return r;
+        }
+    }
+#endif
+
+
+
+    func_exit();
+    return 0;
+} /* uf_sme_init() */
+
+
+void
+uf_sme_deinit(unifi_priv_t *priv)
+{
+
+    func_enter();
+
+    /* Free memory allocated for the scan table */
+/*    unifi_clear_scan_table(priv); */
+
+    /* Cancel any pending workqueue tasks */
+    flush_workqueue(priv->unifi_workqueue);
+
+#ifdef CSR_SUPPORT_WEXT
+    uf_deinit_wext_interface(priv);
+#endif
+
+
+    func_exit();
+} /* uf_sme_deinit() */
+
+
+int sme_mgt_wifi_on(unifi_priv_t *priv)
+{
+    int r,i;
+    CsrInt32 csrResult;
+
+    if (priv == NULL) {
+        return -EINVAL;
+    }
+    /* Initialize the interface mode to None */
+    for (i=0; i<CSR_WIFI_NUM_INTERFACES; i++) {
+        priv->interfacePriv[i]->interfaceMode = 0;
+    }
+
+    /* Set up interface mode so that get_packet_priority() can
+     * select the right QOS priority when WMM is enabled.
+     */
+    priv->interfacePriv[0]->interfaceMode = CSR_WIFI_ROUTER_CTRL_MODE_STA;
+
+    r = uf_request_firmware_files(priv, UNIFI_FW_STA);
+    if (r) {
+        unifi_error(priv, "sme_mgt_wifi_on: Failed to get f/w\n");
+        return r;
+    }
+
+    /*
+     * The request to initialise UniFi might come while UniFi is running.
+     * We need to block all I/O activity until the reset completes, otherwise
+     * an SDIO error might occur resulting an indication to the SME which
+     * makes it think that the initialisation has failed.
+     */
+    priv->bh_thread.block_thread = 1;
+
+    /* Power on UniFi */
+    CsrSdioClaim(priv->sdio);
+    csrResult = CsrSdioPowerOn(priv->sdio);
+    CsrSdioRelease(priv->sdio);
+    if(csrResult != CSR_RESULT_SUCCESS && csrResult != CSR_SDIO_RESULT_NOT_RESET) {
+        return -EIO;
+    }
+
+    if (csrResult == CSR_RESULT_SUCCESS) {
+        /* Initialise UniFi hardware */
+        r = uf_init_hw(priv);
+        if (r) {
+            return r;
+        }
+    }
+
+    /* Re-enable the I/O thread */
+    priv->bh_thread.block_thread = 0;
+
+    /* Disable deep sleep signalling during the firmware initialisation, to
+     * prevent the wakeup mechanism raising the SDIO clock beyond INIT before
+     * the first MLME-RESET.ind. It gets re-enabled at the CONNECTED.ind,
+     * immediately after the MLME-RESET.ind
+     */
+    csrResult = unifi_configure_low_power_mode(priv->card,
+                                           UNIFI_LOW_POWER_DISABLED,
+                                           UNIFI_PERIODIC_WAKE_HOST_DISABLED);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_warning(priv,
+                      "sme_mgt_wifi_on: unifi_configure_low_power_mode() returned an error\n");
+    }
+
+
+    /* Start the I/O thread */
+    CsrSdioClaim(priv->sdio);
+    r = uf_init_bh(priv);
+    if (r) {
+        CsrSdioPowerOff(priv->sdio);
+        CsrSdioRelease(priv->sdio);
+        return r;
+    }
+    CsrSdioRelease(priv->sdio);
+
+    priv->init_progress = UNIFI_INIT_FW_DOWNLOADED;
+
+    return 0;
+}
+
+int
+sme_sys_suspend(unifi_priv_t *priv)
+{
+    const int interfaceNum = 0;     /* FIXME */
+    CsrResult csrResult;
+
+    /* Abort any pending requests. */
+    uf_abort_mlme(priv);
+
+    /* Allow our mlme request to go through. */
+    priv->io_aborted = 0;
+
+    /* Send MLME-RESET.req to UniFi. */
+    unifi_reset_state(priv, priv->netdev[interfaceNum]->dev_addr, 0);
+
+    /* Stop the network traffic */
+    netif_carrier_off(priv->netdev[interfaceNum]);
+
+    /* Put UniFi to deep sleep */
+    CsrSdioClaim(priv->sdio);
+    csrResult = unifi_force_low_power_mode(priv->card);
+    CsrSdioRelease(priv->sdio);
+
+    return 0;
+} /* sme_sys_suspend() */
+
+
+int
+sme_sys_resume(unifi_priv_t *priv)
+{
+#ifdef CSR_SUPPORT_WEXT
+    /* Send disconnect event so clients will re-initialise connection. */
+    memset(priv->wext_conf.current_ssid, 0, UNIFI_MAX_SSID_LEN);
+    memset((void*)priv->wext_conf.current_bssid, 0, ETH_ALEN);
+    priv->wext_conf.capability = 0;
+    wext_send_disassoc_event(priv);
+#endif
+    return 0;
+} /* sme_sys_resume() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  sme_native_log_event
+ *
+ *      Callback function to be registered as the SME event callback.
+ *      Copies the signal content into a new udi_log_t struct and adds
+ *      it to the read queue for the SME client.
+ *
+ *  Arguments:
+ *      arg             This is the value given to unifi_add_udi_hook, in
+ *                      this case a pointer to the client instance.
+ *      signal          Pointer to the received signal.
+ *      signal_len      Size of the signal structure in bytes.
+ *      bulkdata        Pointers to any associated bulk data.
+ *      dir             Direction of the signal. Zero means from host,
+ *                      non-zero means to host.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+sme_native_log_event(ul_client_t *pcli,
+                     const u8 *sig_packed, int sig_len,
+                     const bulk_data_param_t *bulkdata,
+                     int dir)
+{
+    unifi_priv_t *priv;
+    udi_log_t *logptr;
+    u8 *p;
+    int i, r;
+    int signal_len;
+    int total_len;
+    udi_msg_t *msgptr;
+    CSR_SIGNAL signal;
+    ul_client_t *client = pcli;
+
+    func_enter();
+
+    if (client == NULL) {
+        unifi_error(NULL, "sme_native_log_event: client has exited\n");
+        return;
+    }
+
+    priv = uf_find_instance(client->instance);
+    if (!priv) {
+        unifi_error(priv, "invalid priv\n");
+        return;
+    }
+
+    /* Just a sanity check */
+    if ((sig_packed == NULL) || (sig_len <= 0)) {
+        return;
+    }
+
+    /* Get the unpacked signal */
+    r = read_unpack_signal(sig_packed, &signal);
+    if (r == 0) {
+        signal_len = SigGetSize(&signal);
+    } else {
+        CsrUint16 receiver_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sig_packed) + sizeof(CsrUint16)) & 0xFF00;
+
+        /* The control indications are 1 byte, pass them to client. */
+        if (sig_len == 1) {
+            unifi_trace(priv, UDBG5,
+                        "Control indication (0x%x) for native SME.\n",
+                        *sig_packed);
+
+            *(u8*)&signal = *sig_packed;
+            signal_len = sig_len;
+        } else if (receiver_id == 0) {
+            /*
+             * Also "unknown" signals with a ReceiverId of 0 are passed to the client
+             * without unpacking. (This is a code size optimisation to allow signals
+             * that the driver not interested in to be dropped from the unpack code).
+             */
+            unifi_trace(priv, UDBG5,
+                        "Signal 0x%.4X with ReceiverId 0 for native SME.\n",
+                        CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
+
+            *(u8*)&signal = *sig_packed;
+            signal_len = sig_len;
+        } else {
+            unifi_error(priv,
+                        "sme_native_log_event - Received unknown signal 0x%.4X.\n",
+                        CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
+            return;
+        }
+    }
+
+    unifi_trace(priv, UDBG3, "sme_native_log_event: signal 0x%.4X for %d\n",
+                signal.SignalPrimitiveHeader.SignalId,
+                client->client_id);
+
+    total_len = signal_len;
+    /* Calculate the buffer we need to store signal plus bulk data */
+    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
+        total_len += bulkdata->d[i].data_length;
+    }
+
+    /* Allocate log structure plus actual signal. */
+    logptr = (udi_log_t *)kmalloc(sizeof(udi_log_t) + total_len, GFP_KERNEL);
+
+    if (logptr == NULL) {
+        unifi_error(priv,
+                    "Failed to allocate %d bytes for a UDI log record\n",
+                    sizeof(udi_log_t) + total_len);
+        return;
+    }
+
+    /* Fill in udi_log struct */
+    INIT_LIST_HEAD(&logptr->q);
+    msgptr = &logptr->msg;
+    msgptr->length = sizeof(udi_msg_t) + total_len;
+    msgptr->timestamp = jiffies_to_msecs(jiffies);
+    msgptr->direction = dir;
+    msgptr->signal_length = signal_len;
+
+    /* Copy signal and bulk data to the log */
+    p = (u8 *)(msgptr + 1);
+    memcpy(p, &signal, signal_len);
+    p += signal_len;
+
+    /* Append any bulk data */
+    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
+        int len = bulkdata->d[i].data_length;
+
+        /*
+         * Len here might not be the same as the length in the bulk data slot.
+         * The slot length will always be even, but len could be odd.
+         */
+        if (len > 0) {
+            if (bulkdata->d[i].os_data_ptr) {
+                memcpy(p, bulkdata->d[i].os_data_ptr, len);
+            } else {
+                memset(p, 0, len);
+            }
+            p += len;
+        }
+    }
+
+    /* Add to tail of log queue */
+    down(&client->udi_sem);
+    list_add_tail(&logptr->q, &client->udi_log);
+    up(&client->udi_sem);
+
+    /* Wake any waiting user process */
+    wake_up_interruptible(&client->udi_wq);
+
+    func_exit();
+
+} /* sme_native_log_event() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_ta_indicate_protocol
+ *
+ *      Report that a packet of a particular type has been seen
+ *
+ *  Arguments:
+ *      drv_priv        The device context pointer passed to ta_init.
+ *      protocol        The protocol type enum value.
+ *      direction       Whether the packet was a tx or rx.
+ *      src_addr        The source MAC address from the data packet.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *      We defer the actual sending to a background workqueue,
+ *      see uf_ta_ind_wq().
+ * ---------------------------------------------------------------------------
+ */
+void
+unifi_ta_indicate_protocol(void *ospriv,
+                           CsrWifiRouterCtrlTrafficPacketType packet_type,
+                           CsrWifiRouterCtrlProtocolDirection direction,
+                           const CsrWifiMacAddress *src_addr)
+{
+
+} /* unifi_ta_indicate_protocol */
+
+/*
+ * ---------------------------------------------------------------------------
+ * unifi_ta_indicate_sampling
+ *
+ *      Send the TA sampling information to the SME.
+ *
+ *  Arguments:
+ *      drv_priv        The device context pointer passed to ta_init.
+ *      stats           The TA sampling data to send.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+unifi_ta_indicate_sampling(void *ospriv, CsrWifiRouterCtrlTrafficStats *stats)
+{
+
+} /* unifi_ta_indicate_sampling() */
+
+
+void
+unifi_ta_indicate_l4stats(void *ospriv,
+                            CsrUint32 rxTcpThroughput,
+                            CsrUint32 txTcpThroughput,
+                            CsrUint32 rxUdpThroughput,
+                            CsrUint32 txUdpThroughput)
+{
+
+} /* unifi_ta_indicate_l4stats() */
+
+/*
+ * ---------------------------------------------------------------------------
+ * uf_native_process_udi_signal
+ *
+ *      Process interesting signals from the UDI interface.
+ *
+ *  Arguments:
+ *      pcli            A pointer to the client instance.
+ *      signal          Pointer to the received signal.
+ *      signal_len      Size of the signal structure in bytes.
+ *      bulkdata        Pointers to any associated bulk data.
+ *      dir             Direction of the signal. Zero means from host,
+ *                      non-zero means to host.
+ *
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+uf_native_process_udi_signal(ul_client_t *pcli,
+                             const u8 *packed_signal, int packed_signal_len,
+                             const bulk_data_param_t *bulkdata, int dir)
+{
+
+} /* uf_native_process_udi_signal() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  sme_native_mlme_event_handler
+ *
+ *      Callback function to be used as the udi_event_callback when registering
+ *      as a client.
+ *      This function implements a blocking request-reply interface for WEXT.
+ *      To use it, a client specifies this function as the udi_event_callback
+ *      to ul_register_client(). The signal dispatcher in
+ *      unifi_receive_event() will call this function to deliver a signal.
+ *
+ *  Arguments:
+ *      pcli            Pointer to the client instance.
+ *      signal          Pointer to the received signal.
+ *      signal_len      Size of the signal structure in bytes.
+ *      bulkdata        Pointer to structure containing any associated bulk data.
+ *      dir             Direction of the signal. Zero means from host,
+ *                      non-zero means to host.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+sme_native_mlme_event_handler(ul_client_t *pcli,
+                              const u8 *sig_packed, int sig_len,
+                              const bulk_data_param_t *bulkdata,
+                              int dir)
+{
+    CSR_SIGNAL signal;
+    int signal_len;
+    unifi_priv_t *priv = uf_find_instance(pcli->instance);
+    int id, r;
+
+    func_enter();
+
+    /* Just a sanity check */
+    if ((sig_packed == NULL) || (sig_len <= 0)) {
+        return;
+    }
+
+    /* Get the unpacked signal */
+    r = read_unpack_signal(sig_packed, &signal);
+    if (r == 0) {
+        signal_len = SigGetSize(&signal);
+    } else {
+        unifi_error(priv,
+                    "sme_native_mlme_event_handler - Received unknown signal 0x%.4X.\n",
+                    CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
+        return;
+    }
+
+    id = signal.SignalPrimitiveHeader.SignalId;
+    unifi_trace(priv, UDBG4, "wext - Process signal 0x%.4X\n", id);
+
+    /*
+     * Take the appropriate action for the signal.
+     */
+    switch (id) {
+        /*
+         * Confirm replies from UniFi.
+         * These all have zero or one CSR_DATAREF member. (FIXME: check this is still true for softmac)
+         */
+        case CSR_MA_PACKET_CONFIRM_ID:
+        case CSR_MLME_RESET_CONFIRM_ID:
+        case CSR_MLME_GET_CONFIRM_ID:
+        case CSR_MLME_SET_CONFIRM_ID:
+        case CSR_MLME_GET_NEXT_CONFIRM_ID:
+        case CSR_MLME_POWERMGT_CONFIRM_ID:
+        case CSR_MLME_SCAN_CONFIRM_ID:
+        case CSR_MLME_HL_SYNC_CONFIRM_ID:
+        case CSR_MLME_MEASURE_CONFIRM_ID:
+        case CSR_MLME_SETKEYS_CONFIRM_ID:
+        case CSR_MLME_DELETEKEYS_CONFIRM_ID:
+        case CSR_MLME_HL_SYNC_CANCEL_CONFIRM_ID:
+        case CSR_MLME_ADD_PERIODIC_CONFIRM_ID:
+        case CSR_MLME_DEL_PERIODIC_CONFIRM_ID:
+        case CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM_ID:
+        case CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM_ID:
+        case CSR_MLME_SET_PACKET_FILTER_CONFIRM_ID:
+        case CSR_MLME_STOP_MEASURE_CONFIRM_ID:
+        case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM_ID:
+        case CSR_MLME_ADD_TRIGGERED_GET_CONFIRM_ID:
+        case CSR_MLME_DEL_TRIGGERED_GET_CONFIRM_ID:
+        case CSR_MLME_ADD_BLACKOUT_CONFIRM_ID:
+        case CSR_MLME_DEL_BLACKOUT_CONFIRM_ID:
+        case CSR_MLME_ADD_RX_TRIGGER_CONFIRM_ID:
+        case CSR_MLME_DEL_RX_TRIGGER_CONFIRM_ID:
+        case CSR_MLME_CONNECT_STATUS_CONFIRM_ID:
+        case CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM_ID:
+        case CSR_MLME_ADD_TEMPLATE_CONFIRM_ID:
+        case CSR_MLME_CONFIG_QUEUE_CONFIRM_ID:
+        case CSR_MLME_ADD_TSPEC_CONFIRM_ID:
+        case CSR_MLME_DEL_TSPEC_CONFIRM_ID:
+        case CSR_MLME_START_AGGREGATION_CONFIRM_ID:
+        case CSR_MLME_STOP_AGGREGATION_CONFIRM_ID:
+        case CSR_MLME_SM_START_CONFIRM_ID:
+        case CSR_MLME_LEAVE_CONFIRM_ID:
+        case CSR_MLME_SET_TIM_CONFIRM_ID:
+        case CSR_MLME_GET_KEY_SEQUENCE_CONFIRM_ID:
+        case CSR_MLME_SET_CHANNEL_CONFIRM_ID:
+        case CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM_ID:
+        case CSR_DEBUG_GENERIC_CONFIRM_ID:
+            unifi_mlme_copy_reply_and_wakeup_client(pcli, &signal, signal_len, bulkdata);
+            break;
+
+        case CSR_MLME_CONNECTED_INDICATION_ID:
+            /* We currently ignore the connected-ind for softmac f/w development */
+            unifi_info(priv, "CSR_MLME_CONNECTED_INDICATION_ID ignored\n");
+            break;
+
+        default:
+            break;
+    }
+
+    func_exit();
+} /* sme_native_mlme_event_handler() */
+
+
+
+/*
+ * -------------------------------------------------------------------------
+ *  unifi_reset_state
+ *
+ *      Ensure that a MAC address has been set.
+ *      Send the MLME-RESET signal.
+ *      This must be called at least once before starting to do any
+ *      network activities (e.g. scan, join etc).
+ *
+ * Arguments:
+ *      priv            Pointer to device private context struct
+ *      macaddr         Pointer to chip MAC address.
+ *                      If this is FF:FF:FF:FF:FF:FF it will be replaced
+ *                      with the MAC address from the chip.
+ *      set_default_mib 1 if the f/w must reset the MIB to the default values
+ *                      0 otherwise
+ *
+ * Returns:
+ *      0 on success, an error code otherwise.
+ * -------------------------------------------------------------------------
+ */
+int
+unifi_reset_state(unifi_priv_t *priv, unsigned char *macaddr,
+                  unsigned char set_default_mib)
+{
+    int r = 0;
+
+    func_enter();
+
+#ifdef CSR_SUPPORT_WEXT
+    /* The reset clears any 802.11 association. */
+    priv->wext_conf.flag_associated = 0;
+#endif
+
+    func_exit();
+    return r;
+} /* unifi_reset_state() */
+
diff --git a/drivers/staging/csr/sme_sys.c b/drivers/staging/csr/sme_sys.c
new file mode 100644
index 0000000..283e302
--- /dev/null
+++ b/drivers/staging/csr/sme_sys.c
@@ -0,0 +1,3268 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     sme_sys.c
+ *
+ * PURPOSE:
+ *      Driver specific implementation of the SME SYS SAP.
+ *      It is part of the porting exercise.
+ *
+ * Copyright (C) 2008-2011 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+#include "csr_wifi_hip_unifiversion.h"
+#include "unifi_priv.h"
+#include "csr_wifi_hip_conversions.h"
+#ifdef CSR_SUPPORT_WEXT_AP
+#include "csr_wifi_sme_sef.h"
+#endif
+
+
+/*
+ * This file implements the SME SYS API and contains the following functions:
+ * CsrWifiRouterCtrlMediaStatusReqHandler()
+ * CsrWifiRouterCtrlHipReqHandler()
+ * CsrWifiRouterCtrlPortConfigureReqHandler()
+ * CsrWifiRouterCtrlWifiOnReqHandler()
+ * CsrWifiRouterCtrlWifiOffReqHandler()
+ * CsrWifiRouterCtrlSuspendResHandler()
+ * CsrWifiRouterCtrlResumeResHandler()
+ * CsrWifiRouterCtrlQosControlReqHandler()
+ * CsrWifiRouterCtrlConfigurePowerModeReqHandler()
+ * CsrWifiRouterCtrlWifiOnResHandler()
+ * CsrWifiRouterCtrlWifiOffRspHandler()
+ * CsrWifiRouterCtrlMulticastAddressResHandler()
+ * CsrWifiRouterCtrlTrafficConfigReqHandler()
+ * CsrWifiRouterCtrlTrafficClassificationReqHandler()
+ * CsrWifiRouterCtrlTclasAddReqHandler()
+ * CsrWifiRouterCtrlTclasDelReqHandler()
+ * CsrWifiRouterCtrlSetModeReqHandler()
+ * CsrWifiRouterCtrlWapiMulticastFilterReqHandler()
+ * CsrWifiRouterCtrlWapiUnicastFilterReqHandler()
+ * CsrWifiRouterCtrlWapiUnicastTxPktReqHandler()
+ * CsrWifiRouterCtrlWapiRxPktReqHandler()
+ * CsrWifiRouterCtrlWapiFilterReqHandler()
+ */
+
+#ifdef CSR_SUPPORT_SME
+static void check_inactivity_timer_expire_func(unsigned long data);
+void uf_send_disconnected_ind_wq(struct work_struct *work);
+#endif
+
+void send_auto_ma_packet_confirm(unifi_priv_t *priv,
+                                 netInterface_priv_t *interfacePriv,
+                                 struct list_head *buffered_frames_list)
+{
+    tx_buffered_packets_t *buffered_frame_item = NULL;
+    struct list_head *listHead;
+    struct list_head *placeHolder;
+    int client_id;
+
+    CSR_SIGNAL unpacked_signal;
+    CsrUint8 sigbuf[UNIFI_PACKED_SIGBUF_SIZE];
+    CsrUint16 packed_siglen;
+
+
+    list_for_each_safe(listHead, placeHolder, buffered_frames_list)
+    {
+        buffered_frame_item = list_entry(listHead, tx_buffered_packets_t, q);
+
+        if(!buffered_frame_item) {
+            unifi_error(priv, "Entry should exist, otherwise it is a (BUG)\n");
+            continue;
+        }
+
+        if ((interfacePriv->interfaceMode != CSR_WIFI_ROUTER_CTRL_MODE_NONE) &&
+            (priv->wifi_on_state == wifi_on_done))
+        {
+
+            unifi_warning(priv, "Send MA_PACKET_CONFIRM to SenderProcessId = %x for (HostTag = %x TransmissionControl = %x)\n",
+                                 (buffered_frame_item->leSenderProcessId),
+                                 buffered_frame_item->hostTag,
+                                 buffered_frame_item->transmissionControl);
+
+            client_id = buffered_frame_item->leSenderProcessId & 0xFF00;
+
+            if (client_id == priv->sme_cli->sender_id)
+            {
+                /* construct a MA-PACKET.confirm message for SME */
+                memset(&unpacked_signal, 0, sizeof(unpacked_signal));
+                unpacked_signal.SignalPrimitiveHeader.SignalId = CSR_MA_PACKET_CONFIRM_ID;
+                unpacked_signal.SignalPrimitiveHeader.ReceiverProcessId = buffered_frame_item->leSenderProcessId;
+                unpacked_signal.SignalPrimitiveHeader.SenderProcessId = CSR_WIFI_ROUTER_IFACEQUEUE;
+
+                unpacked_signal.u.MaPacketConfirm.VirtualInterfaceIdentifier = uf_get_vif_identifier(interfacePriv->interfaceMode,
+                                                                                                     interfacePriv->InterfaceTag);
+                unpacked_signal.u.MaPacketConfirm.TransmissionStatus = CSR_RESULT_FAILURE;
+                unpacked_signal.u.MaPacketConfirm.RetryCount = 0;
+                unpacked_signal.u.MaPacketConfirm.Rate = buffered_frame_item->rate;
+                unpacked_signal.u.MaPacketConfirm.HostTag = buffered_frame_item->hostTag;
+
+                write_pack(&unpacked_signal, sigbuf, &packed_siglen);
+                unifi_warning(priv, "MA_PACKET_CONFIRM for SME (0x%x, 0x%x, 0x%x, 0x%x)\n",
+                                         unpacked_signal.SignalPrimitiveHeader.ReceiverProcessId,
+                                         unpacked_signal.SignalPrimitiveHeader.SenderProcessId,
+                                         unpacked_signal.u.MaPacketConfirm.VirtualInterfaceIdentifier,
+                                         unpacked_signal.u.MaPacketConfirm.HostTag);
+
+                CsrWifiRouterCtrlHipIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,
+                                            packed_siglen,
+                                            (CsrUint8 *)sigbuf,
+                                            0, NULL,
+                                            0, NULL);
+            }
+            else if((buffered_frame_item->hostTag & 0x80000000))
+            {
+                /* construct a MA-PACKET.confirm message for NME */
+                unifi_warning(priv, "MA_PACKET_CONFIRM for NME (0x%x, 0x%x, 0x%x, 0x%x)\n",
+                                    buffered_frame_item->leSenderProcessId,
+                                    buffered_frame_item->interfaceTag,
+                                    buffered_frame_item->transmissionControl,
+                                    (buffered_frame_item->hostTag & 0x3FFFFFFF));
+
+                CsrWifiRouterMaPacketCfmSend((buffered_frame_item->leSenderProcessId & 0xFF),
+                                            buffered_frame_item->interfaceTag,
+                                            CSR_RESULT_FAILURE,
+                                            (buffered_frame_item->hostTag & 0x3FFFFFFF),
+                                            buffered_frame_item->rate);
+
+            }
+            else
+            {
+                unifi_warning(priv, "Buffered packet dropped without sending a confirm\n");
+            }
+
+        }
+
+        list_del(listHead);
+        kfree(buffered_frame_item);
+        buffered_frame_item = NULL;
+    }
+}
+
+void CsrWifiRouterCtrlMediaStatusReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlMediaStatusReq* req = (CsrWifiRouterCtrlMediaStatusReq*)msg;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[req->interfaceTag];
+    unsigned long flags;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlMediaStatusReqHandler: invalid smepriv\n");
+        return;
+    }
+    if (req->interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "CsrWifiRouterCtrlMediaStatusReqHandler: invalid interfaceTag\n");
+        return;
+    }
+    unifi_trace(priv, UDBG3, "CsrWifiRouterCtrlMediaStatusReqHandler: Mode = %d req->mediaStatus = %d\n",interfacePriv->interfaceMode,req->mediaStatus);
+    if (interfacePriv->interfaceMode != CSR_WIFI_ROUTER_CTRL_MODE_AMP) {
+        bulk_data_desc_t bulk_data;
+
+        bulk_data.data_length = 0;
+
+        spin_lock_irqsave(&priv->m4_lock, flags);
+        if (interfacePriv->m4_bulk_data.data_length > 0) {
+            bulk_data = interfacePriv->m4_bulk_data;
+            interfacePriv->m4_bulk_data.net_buf_length = 0;
+            interfacePriv->m4_bulk_data.data_length = 0;
+            interfacePriv->m4_bulk_data.os_data_ptr = interfacePriv->m4_bulk_data.os_net_buf_ptr = NULL;
+        }
+        spin_unlock_irqrestore(&priv->m4_lock, flags);
+
+        if (bulk_data.data_length != 0) {
+            unifi_trace(priv, UDBG5, "CsrWifiRouterCtrlMediaStatusReqHandler: free M4\n");
+            unifi_net_data_free(priv, &bulk_data);
+        }
+
+        if ((req->mediaStatus == CSR_WIFI_SME_MEDIA_STATUS_CONNECTED) &&
+            (interfacePriv->connected != UnifiConnected)) {
+
+            switch(interfacePriv->interfaceMode){
+                case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+                case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+                    interfacePriv->connected = UnifiConnected;
+                    netif_carrier_on(priv->netdev[req->interfaceTag]);
+#ifdef CSR_SUPPORT_WEXT
+                    wext_send_started_event(priv);
+#endif
+                    unifi_trace(priv, UDBG1,
+                                "CsrWifiRouterCtrlMediaStatusReqHandler: AP/P2PGO setting netif_carrier_on\n");
+                    UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[req->interfaceTag]);
+                    break;
+
+                default:
+#ifdef CSR_SUPPORT_WEXT
+                /* In the WEXT builds (sme and native), the userspace is not ready
+                 * to process any EAPOL or WAPI packets, until it has been informed
+                 * of the NETDEV_CHANGE.
+                 */
+                if (interfacePriv->netdev_callback_registered && (interfacePriv->interfaceMode != CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI)) {
+                    interfacePriv->wait_netdev_change = TRUE;
+                    unifi_trace(priv, UDBG1,
+                                "CsrWifiRouterCtrlMediaStatusReqHandler: waiting for NETDEV_CHANGE\n");
+                    /*
+                     * Carrier can go to on, only after wait_netdev_change is set to TRUE.
+                     * Otherwise there can be a race in uf_netdev_event().
+                     */
+                    netif_carrier_on(priv->netdev[req->interfaceTag]);
+                    unifi_trace(priv, UDBG1,
+                                "CsrWifiRouterCtrlMediaStatusReqHandler: STA/P2PCLI setting netif_carrier_on\n");
+                }
+                else
+#endif
+                {
+                    /* In the NME build, the userspace does not wait for the NETDEV_CHANGE
+                     * so it is ready to process all the EAPOL or WAPI packets.
+                     * At this point, we enable all the Tx queues, and we indicate any packets
+                     * that are queued (and the respective port is opened).
+                     */
+                    static const CsrWifiMacAddress broadcast_address = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
+                    interfacePriv->connected = UnifiConnected;
+                    unifi_trace(priv, UDBG1,
+                                "CsrWifiRouterMediaStatusReqHandler: UnifiConnected && netif_carrier_on\n");
+                    netif_carrier_on(priv->netdev[req->interfaceTag]);
+                    UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[req->interfaceTag]);
+                    uf_process_rx_pending_queue(priv, UF_UNCONTROLLED_PORT_Q, broadcast_address, 1, interfacePriv->InterfaceTag);
+                    uf_process_rx_pending_queue(priv, UF_CONTROLLED_PORT_Q, broadcast_address, 1, interfacePriv->InterfaceTag);
+                }
+                break;
+            }
+        }
+
+        if (req->mediaStatus == CSR_WIFI_SME_MEDIA_STATUS_DISCONNECTED) {
+#ifdef CSR_SUPPORT_WEXT
+            unifi_trace(priv, UDBG1,
+                        "CsrWifiRouterMediaStatusReqHandler: cancel waiting for NETDEV_CHANGE\n");
+            interfacePriv->wait_netdev_change = FALSE;
+#endif
+            unifi_trace(priv, UDBG1,
+                        "CsrWifiRouterMediaStatusReqHandler: setting netif_carrier_off\n");
+            netif_carrier_off(priv->netdev[req->interfaceTag]);
+#ifdef CSR_SUPPORT_WEXT
+            switch(interfacePriv->interfaceMode){
+                case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+                case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+                     wext_send_started_event(priv);
+                     break;
+                default:
+                     break;
+            }
+#endif
+            interfacePriv->connected = UnifiNotConnected;
+        }
+    } else {
+        /* For AMP, just update the L2 connected flag */
+        if (req->mediaStatus == CSR_WIFI_SME_MEDIA_STATUS_CONNECTED) {
+            unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlMediaStatusReqHandler: AMP connected\n");
+            interfacePriv->connected = UnifiConnected;
+        } else {
+            unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlMediaStatusReqHandler: AMP disconnected\n");
+            interfacePriv->connected = UnifiNotConnected;
+        }
+    }
+}
+
+
+void CsrWifiRouterCtrlHipReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlHipReq* hipreq = (CsrWifiRouterCtrlHipReq*)msg;
+    bulk_data_param_t bulkdata;
+    u8 *signal_ptr;
+    int signal_length;
+    int r=0;
+    void *dest;
+    CsrResult csrResult;
+    CSR_SIGNAL *signal;
+    CsrUint16 interfaceTag = 0;
+    CSR_MA_PACKET_REQUEST *req;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if (priv == NULL) {
+        return;
+    }
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlHipReqHandler: invalid smepriv\n");
+        return;
+    }
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "CsrWifiRouterCtrlHipReqHandler: invalid interfaceTag\n");
+        return;
+    }
+
+    /* Initialize bulkdata to avoid os_net_buf is garbage */
+    memset(&bulkdata, 0, sizeof(bulk_data_param_t));
+
+    signal = (CSR_SIGNAL *)hipreq->mlmeCommand;
+
+    unifi_trace(priv, UDBG4, "CsrWifiRouterCtrlHipReqHandler: 0x04%X ---->\n",
+                *((CsrUint16*)hipreq->mlmeCommand));
+
+    /* Construct the signal. */
+    signal_ptr = (u8*)hipreq->mlmeCommand;
+    signal_length = hipreq->mlmeCommandLength;
+
+    /*
+     * The MSB of the sender ID needs to be set to the client ID.
+     * The LSB is controlled by the SME.
+     */
+    signal_ptr[5] = (priv->sme_cli->sender_id >> 8) & 0xff;
+
+    /* Allocate buffers for the bulk data. */
+    if (hipreq->dataRef1Length) {
+        csrResult = unifi_net_data_malloc(priv, &bulkdata.d[0], hipreq->dataRef1Length);
+        if (csrResult == CSR_RESULT_SUCCESS) {
+            dest = (void*)bulkdata.d[0].os_data_ptr;
+            memcpy(dest, hipreq->dataRef1, hipreq->dataRef1Length);
+            bulkdata.d[0].data_length = hipreq->dataRef1Length;
+        } else {
+            unifi_warning(priv, "signal not sent down, allocation failed in CsrWifiRouterCtrlHipReqHandler\n");
+            return;
+        }
+    } else {
+        bulkdata.d[0].os_data_ptr = NULL;
+        bulkdata.d[0].data_length = 0;
+    }
+    if (hipreq->dataRef2Length) {
+        csrResult = unifi_net_data_malloc(priv, &bulkdata.d[1], hipreq->dataRef2Length);
+        if (csrResult == CSR_RESULT_SUCCESS) {
+            dest = (void*)bulkdata.d[1].os_data_ptr;
+            memcpy(dest, hipreq->dataRef2, hipreq->dataRef2Length);
+            bulkdata.d[1].data_length = hipreq->dataRef2Length;
+        } else {
+            if (bulkdata.d[0].data_length)
+            {
+                unifi_net_data_free(priv, &bulkdata.d[0]);
+            }
+            unifi_warning(priv, "signal not sent down, allocation failed in CsrWifiRouterCtrlHipReqHandler\n");
+            return;
+        }
+    } else {
+        bulkdata.d[1].os_data_ptr = NULL;
+        bulkdata.d[1].data_length = 0;
+    }
+
+    unifi_trace(priv, UDBG3, "SME SEND: Signal 0x%.4X \n",
+                *((CsrUint16*)signal_ptr));
+    if (signal->SignalPrimitiveHeader.SignalId == CSR_MA_PACKET_REQUEST_ID)
+    {
+        CSR_SIGNAL unpacked_signal;
+        read_unpack_signal((u8 *) signal, &unpacked_signal);
+        req = &unpacked_signal.u.MaPacketRequest;
+        interfaceTag = req->VirtualInterfaceIdentifier & 0xff;
+        switch(interfacePriv->interfaceMode)
+        {
+            case CSR_WIFI_ROUTER_CTRL_MODE_NONE:
+                unifi_error(priv, "CsrWifiRouterCtrlHipReqHandler: invalid mode: NONE \n");
+                break;
+            default:
+                unifi_trace(priv, UDBG5, "mode is %x\n", interfacePriv->interfaceMode);
+        }
+        /* While sending ensure that first 2 bits b31 and b30 are 00. These are used for local routing*/
+        r = uf_process_ma_packet_req(priv, req->Ra.x, (req->HostTag & 0x3FFFFFFF), interfaceTag,
+                                     req->TransmissionControl, req->TransmitRate,
+                                     req->Priority, signal->SignalPrimitiveHeader.SenderProcessId,
+                                     &bulkdata);
+        if (r)
+        {
+            if (bulkdata.d[0].data_length)
+            {
+                unifi_net_data_free(priv, &bulkdata.d[0]);
+            }
+            if (bulkdata.d[1].data_length)
+            {
+                unifi_net_data_free(priv, &bulkdata.d[1]);
+            }
+        }
+    } else {
+        /* ul_send_signal_raw frees the bulk data if it fails */
+        r = ul_send_signal_raw(priv, signal_ptr, signal_length, &bulkdata);
+    }
+
+    if (r) {
+        unifi_error(priv,
+                    "CsrWifiRouterCtrlHipReqHandler: Failed to send signal (0x%.4X - %u)\n",
+                    *((CsrUint16*)signal_ptr), r);
+        CsrWifiRouterCtrlWifiOffIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,CSR_WIFI_SME_CONTROL_INDICATION_ERROR);
+    }
+
+    unifi_trace(priv, UDBG4, "CsrWifiRouterCtrlHipReqHandler: <----\n");
+}
+
+#ifdef CSR_WIFI_SEND_GRATUITOUS_ARP
+static void
+uf_send_gratuitous_arp(unifi_priv_t *priv, CsrUint16 interfaceTag)
+{
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    CSR_PRIORITY priority;
+    CSR_SIGNAL signal;
+    bulk_data_param_t bulkdata;
+    CsrResult csrResult;
+    struct sk_buff *skb, *newSkb = NULL;
+    CsrInt8 protection;
+    int r;
+    static const CsrUint8 arp_req[36] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00,
+                                         0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01,
+                                         0x00, 0x02, 0x5f, 0x20, 0x2f, 0x02,
+                                         0xc0, 0xa8, 0x00, 0x02,
+                                         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                         0xc0, 0xa8, 0x00, 0x02};
+
+    func_enter();
+
+    csrResult = unifi_net_data_malloc(priv, &bulkdata.d[0], sizeof(arp_req));
+    if (csrResult != CSR_RESULT_SUCCESS)
+    {
+        unifi_error(priv, "Failed to allocate bulk data in CsrWifiSmeRoamCompleteIndHandler()\n");
+        return;
+    }
+    skb = (struct sk_buff *)(bulkdata.d[0].os_net_buf_ptr);
+    skb->len = bulkdata.d[0].data_length;
+
+    memcpy(skb->data, arp_req, sizeof(arp_req));
+    /* add MAC and IP address */
+    memcpy(skb->data + 16, priv->netdev[interfaceTag]->dev_addr, ETH_ALEN);
+    skb->data[22] = (priv->sta_ip_address      ) & 0xFF;
+    skb->data[23] = (priv->sta_ip_address >>  8) & 0xFF;
+    skb->data[24] = (priv->sta_ip_address >> 16) & 0xFF;
+    skb->data[25] = (priv->sta_ip_address >> 24) & 0xFF;
+    skb->data[32] = (priv->sta_ip_address      ) & 0xFF;
+    skb->data[33] = (priv->sta_ip_address >>  8) & 0xFF;
+    skb->data[34] = (priv->sta_ip_address >> 16) & 0xFF;
+    skb->data[35] = (priv->sta_ip_address >> 24) & 0xFF;
+
+    bulkdata.d[1].os_data_ptr = NULL;
+    bulkdata.d[1].os_net_buf_ptr = NULL;
+    bulkdata.d[1].net_buf_length = bulkdata.d[1].data_length = 0;
+
+    if ((protection = uf_get_protection_bit_from_interfacemode(priv, interfaceTag, &arp_req[26])) < 0)
+    {
+        unifi_error(priv, "CsrWifiSmeRoamCompleteIndHandler: Failed to determine protection mode\n");
+        unifi_net_data_free(priv, &bulkdata.d[0]);
+        return;
+    }
+
+    if ((priv->sta_wmm_capabilities & QOS_CAPABILITY_WMM_ENABLED) == 1)
+    {
+        priority = CSR_QOS_UP0;
+    }
+    else
+    {
+        priority = CSR_CONTENTION;
+    }
+
+    if (prepare_and_add_macheader(priv, skb, newSkb, priority, &bulkdata,
+                                  interfaceTag, &arp_req[26],
+                                  priv->netdev[interfaceTag]->dev_addr, protection))
+    {
+        unifi_error(priv, "CsrWifiSmeRoamCompleteIndHandler: failed to create MAC header\n");
+        unifi_net_data_free(priv, &bulkdata.d[0]);
+        return;
+    }
+    bulkdata.d[0].os_data_ptr = skb->data;
+    bulkdata.d[0].os_net_buf_ptr = skb;
+    bulkdata.d[0].data_length = skb->len;
+
+    unifi_frame_ma_packet_req(priv, priority, 0, 0xffffffff, interfaceTag,
+                              CSR_NO_CONFIRM_REQUIRED, priv->netdev_client->sender_id,
+                              interfacePriv->bssid.a, &signal);
+
+    r = ul_send_signal_unpacked(priv, &signal, &bulkdata);
+    if (r)
+    {
+        unifi_error(priv, "CsrWifiSmeRoamCompleteIndHandler: failed to send QOS data null packet result: %d\n",r);
+        unifi_net_data_free(priv, &bulkdata.d[0]);
+        return;
+    }
+
+    func_exit();
+
+}
+#endif /* CSR_WIFI_SEND_GRATUITOUS_ARP */
+
+/*
+ * ---------------------------------------------------------------------------
+ * configure_data_port
+ *
+ *      Store the new controlled port configuration.
+ *
+ * Arguments:
+ *      priv            Pointer to device private context struct
+ *      port_cfg        Pointer to the port configuration
+ *
+ * Returns:
+ *      An unifi_ControlledPortAction value.
+ * ---------------------------------------------------------------------------
+ */
+static int
+configure_data_port(unifi_priv_t *priv,
+        CsrWifiRouterCtrlPortAction port_action,
+        const CsrWifiMacAddress *macAddress,
+        const int queue,
+        CsrUint16 interfaceTag)
+{
+    const CsrUint8 broadcast_mac_address[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+    unifi_port_config_t *port;
+    netInterface_priv_t *interfacePriv;
+    int i;
+    const char* controlled_string; /* cosmetic "controlled"/"uncontrolled" for trace */
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "configure_data_port: bad interfaceTag\n");
+        return -EFAULT;
+    }
+
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if (queue == UF_CONTROLLED_PORT_Q) {
+        port = &interfacePriv->controlled_data_port;
+        controlled_string = "controlled";
+    } else {
+        port = &interfacePriv->uncontrolled_data_port;
+        controlled_string = "uncontrolled";
+    }
+
+    unifi_trace(priv, UDBG2, "port config request %02x:%02x:%02x:%02x:%02x:%02x %s with port_action %d.\n",
+                macAddress->a[0], macAddress->a[1], macAddress->a[2],
+                macAddress->a[3], macAddress->a[4], macAddress->a[5],
+                controlled_string, port_action);
+
+
+    /* If the new configuration has the broadcast MAC address or if we are in infrastructure mode then clear the list first and set port overide mode */
+    if ((CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode ||
+        interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI) ||
+        !memcmp(macAddress->a, broadcast_mac_address, ETH_ALEN)) {
+
+        port->port_cfg[0].port_action = port_action;
+        port->port_cfg[0].mac_address = *macAddress;
+        port->port_cfg[0].in_use = TRUE;
+        port->entries_in_use = 1;
+        port->overide_action = UF_DATA_PORT_OVERIDE;
+
+        unifi_trace(priv, UDBG2, "%s port override on\n",
+                    (queue == UF_CONTROLLED_PORT_Q) ? "Controlled" : "Uncontrolled");
+
+        /* Discard the remaining entries in the port config table */
+        for (i = 1; i < UNIFI_MAX_CONNECTIONS; i++) {
+            port->port_cfg[i].in_use = FALSE;
+        }
+
+        if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN) {
+            unifi_trace(priv, UDBG1, "%s port broadcast set to open.\n",
+                        (queue == UF_CONTROLLED_PORT_Q) ? "Controlled" : "Uncontrolled");
+
+            /*
+             * Ask stack to schedule for transmission any packets queued
+             * while controlled port was not open.
+             * Use netif_schedule() instead of netif_wake_queue() because
+             * transmission should be already enabled at this point. If it
+             * is not, probably the interface is down and should remain as is.
+             */
+            uf_resume_data_plane(priv, queue, *macAddress, interfaceTag);
+
+#ifdef CSR_WIFI_SEND_GRATUITOUS_ARP
+            if ((CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode) &&
+                (queue == UF_CONTROLLED_PORT_Q) && (priv->sta_ip_address != 0xFFFFFFFF))
+            {
+                uf_send_gratuitous_arp(priv, interfaceTag);
+            }
+#endif
+        } else {
+            unifi_trace(priv, UDBG1, "%s port broadcast set to %s.\n",
+                        (queue == UF_CONTROLLED_PORT_Q) ? "Controlled" : "Uncontrolled",
+                        (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD) ? "discard": "closed");
+
+            /* If port is closed, discard all the pending Rx packets */
+            if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD) {
+                uf_free_pending_rx_packets(priv, queue, *macAddress,interfaceTag);
+            }
+        }
+    } else {
+        /* store the new configuration, either in the entry with matching mac address (if already present),
+         * otherwise in a new entry
+         */
+
+        int found_entry_flag;
+        int first_free_slot = -1;
+
+        /* If leaving override mode, free the port entry used for override */
+        if (port->overide_action == UF_DATA_PORT_OVERIDE) {
+            port->port_cfg[0].in_use = FALSE;
+            port->entries_in_use = 0;
+            port->overide_action = UF_DATA_PORT_NOT_OVERIDE;
+
+            unifi_trace(priv, UDBG2, "%s port override off\n",
+                        (queue == UF_CONTROLLED_PORT_Q) ? "Controlled" : "Uncontrolled");
+        }
+
+        found_entry_flag = 0;
+        for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
+            if (port->port_cfg[i].in_use) {
+                if (!memcmp(&port->port_cfg[i].mac_address.a, macAddress->a, ETH_ALEN)) {
+                    /* We've seen this address before, reconfigure it */
+                    port->port_cfg[i].port_action = port_action;
+                    found_entry_flag = 1;
+                    break;
+                }
+            } else if (first_free_slot == -1) {
+                /* Remember the first free slot on the way past so it can be claimed
+                 * if this turns out to be a new MAC address (to save walking the list again).
+                 */
+                first_free_slot = i;
+            }
+        }
+
+        /* At this point we found an existing entry and have updated it, or need to
+         * add a new entry. If all slots are allocated, give up and return an error.
+         */
+        if (!found_entry_flag) {
+            if (first_free_slot == -1) {
+                unifi_error(priv, "no free slot found in port config array (%d used)\n", port->entries_in_use);
+                return -EFAULT;
+            } else {
+                port->entries_in_use++;
+            }
+
+            unifi_trace(priv, UDBG3, "port config index assigned in config_data_port = %d\n", first_free_slot);
+            port->port_cfg[first_free_slot].in_use = TRUE;
+            port->port_cfg[first_free_slot].port_action = port_action;
+            port->port_cfg[first_free_slot].mac_address = *macAddress;
+        }
+
+        if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN) {
+            /*
+             * Ask stack to schedule for transmission any packets queued
+             * while controlled port was not open.
+             * Use netif_schedule() instead of netif_wake_queue() because
+             * transmission should be already enabled at this point. If it
+             * is not, probably the interface is down and should remain as is.
+             */
+            uf_resume_data_plane(priv, queue, *macAddress, interfaceTag);
+        }
+
+        /*
+         * If port is closed, discard all the pending Rx packets
+         * coming from the peer station.
+         */
+        if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD) {
+            uf_free_pending_rx_packets(priv, queue, *macAddress,interfaceTag);
+        }
+
+        unifi_trace(priv, UDBG2, "port config %02x:%02x:%02x:%02x:%02x:%02x with port_action %d.\n",
+                    *(macAddress->a+0), *(macAddress->a+1), *(macAddress->a+2),
+                    *(macAddress->a+3), *(macAddress->a+4), *(macAddress->a+5),
+                    port_action);
+    }
+    return 0;
+} /* configure_data_port() */
+
+
+void CsrWifiRouterCtrlPortConfigureReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlPortConfigureReq* req = (CsrWifiRouterCtrlPortConfigureReq*)msg;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[req->interfaceTag];
+
+    unifi_trace(priv, UDBG3, "entering CsrWifiRouterCtrlPortConfigureReqHandler\n");
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlPortConfigureReqHandler: invalid smepriv\n");
+        return;
+    }
+
+    /* To update the protection status of the peer/station */
+    switch(interfacePriv->interfaceMode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_STA:
+	    case CSR_WIFI_ROUTER_CTRL_MODE_AMP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_IBSS:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI:
+            /* Since for Unifi as a station, the station record not maintained & interfaceID is
+             * only needed to update the peer protection status
+             */
+            interfacePriv->protect = req->setProtection;
+            break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+            {
+                CsrUint8 i;
+                CsrWifiRouterCtrlStaInfo_t *staRecord;
+                /* Ifscontrolled port is open means, The peer has been added to station record
+                 * so that the protection corresponding to the peer is valid in this req
+                 */
+                if (req->controlledPortAction == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN) {
+                    for(i =0; i < UNIFI_MAX_CONNECTIONS; i++) {
+                        staRecord = (CsrWifiRouterCtrlStaInfo_t *) (interfacePriv->staInfo[i]);
+                        if (staRecord) {
+                                /* Find the matching station record & set the protection type */
+                                if (!memcmp(req->macAddress.a, staRecord->peerMacAddress.a, ETH_ALEN)) {
+                                        staRecord->protection = req->setProtection;
+                                        break;
+                                }
+                        }
+                    }
+                }
+            }
+            break;
+        default:
+            unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlPortConfigureReqHandler(0x%.4X) Uncaught mode %d\n",
+                        msg->source, interfacePriv->interfaceMode);
+    }
+
+    configure_data_port(priv, req->uncontrolledPortAction, (const CsrWifiMacAddress *)&req->macAddress,
+                        UF_UNCONTROLLED_PORT_Q, req->interfaceTag);
+    configure_data_port(priv, req->controlledPortAction, (const CsrWifiMacAddress *)&req->macAddress,
+                        UF_CONTROLLED_PORT_Q, req->interfaceTag);
+
+    CsrWifiRouterCtrlPortConfigureCfmSend(msg->source,req->clientData,req->interfaceTag,
+                                      CSR_RESULT_SUCCESS, req->macAddress);
+    unifi_trace(priv, UDBG3, "leaving CsrWifiRouterCtrlPortConfigureReqHandler\n");
+}
+
+
+void CsrWifiRouterCtrlWifiOnReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlVersions versions;
+    CsrWifiRouterCtrlWifiOnReq* req = (CsrWifiRouterCtrlWifiOnReq*)msg;
+    int r,i;
+    CsrResult csrResult;
+
+    if (priv == NULL) {
+        return;
+    }
+    if( priv->wol_suspend ) {
+        unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlWifiOnReqHandler: Don't reset mode\n");
+    } else {
+#ifdef ANDROID_BUILD
+        /* Take the wakelock while Wi-Fi On is in progress */
+        unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlWifiOnReqHandler: take wake lock\n");
+        wake_lock(&unifi_sdio_wake_lock);
+#endif
+        for (i=0; i<CSR_WIFI_NUM_INTERFACES; i++) {
+            unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlWifiOnReqHandler: Setting interface %d to NONE\n", i );
+
+            priv->interfacePriv[i]->interfaceMode = 0;
+        }
+    }
+    unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlWifiOnReqHandler(0x%.4X) req->dataLength=%d req->data=0x%x\n", msg->source, req->dataLength, req->data);
+
+    if(req->dataLength==3 && req->data && req->data[0]==0 && req->data[1]==1 && req->data[2]==1)
+    {
+        priv->cmanrTestMode = TRUE;
+        unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlWifiOnReqHandler: cmanrTestMode=%d\n", priv->cmanrTestMode);
+    }
+    else
+    {
+        priv->cmanrTestMode = FALSE;
+    }
+
+    /*
+     * The request to initialise UniFi might come while UniFi is running.
+     * We need to block all I/O activity until the reset completes, otherwise
+     * an SDIO error might occur resulting an indication to the SME which
+     * makes it think that the initialisation has failed.
+     */
+    priv->bh_thread.block_thread = 1;
+
+    /* Update the wifi_on state */
+    priv->wifi_on_state = wifi_on_in_progress;
+
+    /* If UniFi was unpowered, acquire the firmware for download to chip */
+    if (!priv->wol_suspend) {
+        r = uf_request_firmware_files(priv, UNIFI_FW_STA);
+        if (r) {
+            unifi_error(priv, "CsrWifiRouterCtrlWifiOnReqHandler: Failed to get f/w\n");
+            CsrWifiRouterCtrlWifiOnCfmSend(msg->source, req->clientData, CSR_RESULT_FAILURE);
+            return;
+        }
+    } else {
+        unifi_trace(priv, UDBG1, "Don't need firmware\n");
+    }
+
+    /* Power on UniFi (which may not necessarily have been off) */
+    CsrSdioClaim(priv->sdio);
+    csrResult = CsrSdioPowerOn(priv->sdio);
+    CsrSdioRelease(priv->sdio);
+    if (csrResult != CSR_RESULT_SUCCESS && csrResult != CSR_SDIO_RESULT_NOT_RESET) {
+        unifi_error(priv, "CsrWifiRouterCtrlWifiOnReqHandler: Failed to power on UniFi\n");
+        CsrWifiRouterCtrlWifiOnCfmSend(msg->source, req->clientData, CSR_RESULT_FAILURE);
+        return;
+    }
+
+    /* If CsrSdioPowerOn() returns CSR_RESULT_SUCCESS, it means that we need to initialise UniFi */
+    if (csrResult == CSR_RESULT_SUCCESS && !priv->wol_suspend) {
+        /* Initialise UniFi hardware */
+        r = uf_init_hw(priv);
+        if (r) {
+            unifi_error(priv, "CsrWifiRouterCtrlWifiOnReqHandler: Failed to initialise h/w, error %d\n", r);
+            CsrWifiRouterCtrlWifiOnCfmSend(msg->source, req->clientData, CSR_RESULT_FAILURE);
+            return;
+        }
+    } else {
+        unifi_trace(priv, UDBG1, "UniFi already initialised\n");
+    }
+
+    /* Completed handling of wake up from suspend with UniFi powered */
+    priv->wol_suspend = FALSE;
+
+    /* Re-enable the I/O thread */
+    priv->bh_thread.block_thread = 0;
+
+    /*
+     * Start the I/O thread. The thread might be already running.
+     * This fine, just carry on with the request.
+     */
+    r = uf_init_bh(priv);
+    if (r) {
+        CsrSdioClaim(priv->sdio);
+        CsrSdioPowerOff(priv->sdio);
+        CsrSdioRelease(priv->sdio);
+        CsrWifiRouterCtrlWifiOnCfmSend(msg->source, req->clientData, CSR_RESULT_FAILURE);
+        return;
+    }
+
+    /* Get the version information from the core */
+    unifi_card_info(priv->card, &priv->card_info);
+
+    /* Set the sme queue id */
+    priv->CSR_WIFI_SME_IFACEQUEUE = msg->source;
+    CSR_WIFI_SME_IFACEQUEUE = msg->source;
+
+
+    /* Copy to the unifiio_card_info structure. */
+    versions.chipId = priv->card_info.chip_id;
+    versions.chipVersion = priv->card_info.chip_version;
+    versions.firmwareBuild = priv->card_info.fw_build;
+    versions.firmwareHip = priv->card_info.fw_hip_version;
+    versions.routerBuild = (CsrCharString*)CSR_WIFI_VERSION;
+    versions.routerHip = (UNIFI_HIP_MAJOR_VERSION << 8) | UNIFI_HIP_MINOR_VERSION;
+
+    CsrWifiRouterCtrlWifiOnIndSend(msg->source, 0, CSR_RESULT_SUCCESS, versions);
+
+    /* Update the wifi_on state */
+    priv->wifi_on_state = wifi_on_done;
+}
+
+
+/*
+ * wifi_off:
+ *      Common code for CsrWifiRouterCtrlWifiOffReqHandler() and
+ *      CsrWifiRouterCtrlWifiOffRspHandler().
+ */
+static void
+wifi_off(unifi_priv_t *priv)
+{
+    int power_off;
+    int priv_instance;
+    int i;
+    CsrResult csrResult;
+
+
+    /* Already off? */
+    if (priv->wifi_on_state == wifi_on_unspecified) {
+        unifi_trace(priv, UDBG1, "wifi_off already\n");
+        return;
+    }
+
+    unifi_trace(priv, UDBG1, "wifi_off\n");
+
+    /* Destroy the Traffic Analysis Module */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
+    cancel_work_sync(&priv->ta_ind_work.task);
+    cancel_work_sync(&priv->ta_sample_ind_work.task);
+#ifdef CSR_SUPPORT_WEXT
+    cancel_work_sync(&priv->sme_config_task);
+    wext_send_disassoc_event(priv);
+#endif
+
+    /* Cancel pending M4 stuff */
+    for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) {
+        if (priv->netdev[i]) {
+            netInterface_priv_t *netpriv = (netInterface_priv_t *) netdev_priv(priv->netdev[i]);
+            cancel_work_sync(&netpriv->send_m4_ready_task);
+        }
+    }
+#endif
+    flush_workqueue(priv->unifi_workqueue);
+
+    /* fw_init parameter can prevent power off UniFi, for debugging */
+    priv_instance = uf_find_priv(priv);
+    if (priv_instance == -1) {
+        unifi_warning(priv,
+                "CsrWifiRouterCtrlStopReqHandler: Unknown priv instance, will power off card.\n");
+        power_off = 1;
+    } else {
+        power_off = (fw_init[priv_instance] > 0) ? 0 : 1;
+    }
+
+    /* Production test mode requires power to the chip, too */
+    if (priv->ptest_mode) {
+        power_off = 0;
+    }
+
+    /* Stop the bh_thread */
+    uf_stop_thread(priv, &priv->bh_thread);
+
+    /* Read the f/w panic codes, if any. Protect against second wifi_off() call,
+     * which may happen if SME requests a wifi_off and closes the char device */
+    if (priv->init_progress != UNIFI_INIT_NONE) {
+        CsrSdioClaim(priv->sdio);
+        unifi_capture_panic(priv->card);
+        CsrSdioRelease(priv->sdio);
+    }
+
+    /* Unregister the interrupt handler */
+    if (csr_sdio_linux_remove_irq(priv->sdio)) {
+        unifi_notice(priv,
+                "csr_sdio_linux_remove_irq failed to talk to card.\n");
+    }
+
+    if (power_off) {
+        unifi_trace(priv, UDBG2,
+                    "Force low power and try to power off\n");
+        /* Put UniFi to deep sleep, in case we can not power it off */
+        CsrSdioClaim(priv->sdio);
+        csrResult = unifi_force_low_power_mode(priv->card);
+        CsrSdioRelease(priv->sdio);
+
+        CsrSdioPowerOff(priv->sdio);
+    }
+
+    /* Consider UniFi to be uninitialised */
+    priv->init_progress = UNIFI_INIT_NONE;
+    priv->wifi_on_state = wifi_on_unspecified;
+
+
+} /* wifi_off() */
+
+
+void CsrWifiRouterCtrlWifiOffReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlWifiOffReq* req = (CsrWifiRouterCtrlWifiOffReq*)msg;
+    int i = 0;
+
+    if (priv == NULL) {
+        return;
+    }
+
+    unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlWifiOffReqHandler(0x%.4X)\n", msg->source);
+
+    /* Stop the network traffic on all interfaces before freeing the core. */
+    for (i=0; i<CSR_WIFI_NUM_INTERFACES; i++) {
+        netInterface_priv_t *interfacePriv = priv->interfacePriv[i];
+        if (interfacePriv->netdev_registered == 1) {
+            netif_carrier_off(priv->netdev[i]);
+            UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[i]);
+            interfacePriv->connected = UnifiConnectedUnknown;
+        }
+        interfacePriv->interfaceMode = 0;
+
+        /* Enable all queues by default */
+        interfacePriv->queueEnabled[0] = 1;
+        interfacePriv->queueEnabled[1] = 1;
+        interfacePriv->queueEnabled[2] = 1;
+        interfacePriv->queueEnabled[3] = 1;
+    }
+    wifi_off(priv);
+
+    CsrWifiRouterCtrlWifiOffCfmSend(msg->source,req->clientData);
+
+    /* If this is called in response to closing the character device, the
+     * caller must use uf_sme_cancel_request() to terminate any pending SME
+     * blocking request or there will be a delay while the operation times out.
+     */
+}
+
+
+void CsrWifiRouterCtrlQosControlReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlQosControlReq* req = (CsrWifiRouterCtrlQosControlReq*)msg;
+    netInterface_priv_t *interfacePriv;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlQosControlReqHandler: invalid smepriv\n");
+        return;
+    }
+
+    unifi_trace(priv, UDBG4, "CsrWifiRouterCtrlQosControlReqHandler:scontrol = %d", req->control);
+
+    if (req->interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "CsrWifiRouterCtrlQosControlReqHandler: interfaceID >= CSR_WIFI_NUM_INTERFACES.\n");
+        return;
+    }
+    interfacePriv = priv->interfacePriv[req->interfaceTag];
+
+    if (req->control == CSR_WIFI_ROUTER_CTRL_QOS_CONTROL_WMM_ON) {
+        priv->sta_wmm_capabilities |= QOS_CAPABILITY_WMM_ENABLED;
+        unifi_trace(priv, UDBG1, "WMM enabled\n");
+
+        unifi_trace(priv, UDBG1, "Queue Config %x\n", req->queueConfig);
+
+        interfacePriv->queueEnabled[UNIFI_TRAFFIC_Q_BK] = (req->queueConfig & CSR_WIFI_ROUTER_CTRL_QUEUE_BK_ENABLE)?1:0;
+        interfacePriv->queueEnabled[UNIFI_TRAFFIC_Q_BE] = (req->queueConfig & CSR_WIFI_ROUTER_CTRL_QUEUE_BE_ENABLE)?1:0;
+        interfacePriv->queueEnabled[UNIFI_TRAFFIC_Q_VI] = (req->queueConfig & CSR_WIFI_ROUTER_CTRL_QUEUE_VI_ENABLE)?1:0;
+        interfacePriv->queueEnabled[UNIFI_TRAFFIC_Q_VO] = (req->queueConfig & CSR_WIFI_ROUTER_CTRL_QUEUE_VO_ENABLE)?1:0;
+
+    } else {
+        priv->sta_wmm_capabilities = 0;
+        unifi_trace(priv, UDBG1, "WMM disabled\n");
+    }
+}
+
+
+void CsrWifiRouterCtrlTclasAddReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlTclasAddReq* req = (CsrWifiRouterCtrlTclasAddReq*)msg;
+
+    if (priv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlTclasAddReqHandler: invalid smepriv\n");
+        return;
+    }
+
+    CsrWifiRouterCtrlTclasAddCfmSend(msg->source, req->clientData, req->interfaceTag , CSR_RESULT_SUCCESS);
+}
+
+void CsrWifiRouterCtrlTclasDelReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlTclasDelReq* req = (CsrWifiRouterCtrlTclasDelReq*)msg;
+
+    if (priv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlTclasDelReqHandler: invalid smepriv\n");
+        return;
+    }
+
+    CsrWifiRouterCtrlTclasDelCfmSend(msg->source, req->clientData, req->interfaceTag, CSR_RESULT_SUCCESS);
+}
+
+
+void CsrWifiRouterCtrlConfigurePowerModeReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlConfigurePowerModeReq* req = (CsrWifiRouterCtrlConfigurePowerModeReq*)msg;
+    enum unifi_low_power_mode pm;
+    CsrResult csrResult;
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlConfigurePowerModeReqHandler: invalid smepriv\n");
+        return;
+    }
+
+    if (req->mode == CSR_WIFI_ROUTER_CTRL_LOW_POWER_MODE_DISABLED) {
+        pm = UNIFI_LOW_POWER_DISABLED;
+    } else {
+        pm = UNIFI_LOW_POWER_ENABLED;
+    }
+
+    unifi_trace(priv, UDBG2,
+                "CsrWifiRouterCtrlConfigurePowerModeReqHandler (mode=%d, wake=%d)\n",
+                req->mode, req->wakeHost);
+    csrResult = unifi_configure_low_power_mode(priv->card, pm,
+                                               (req->wakeHost ? UNIFI_PERIODIC_WAKE_HOST_ENABLED : UNIFI_PERIODIC_WAKE_HOST_DISABLED));
+}
+
+
+void CsrWifiRouterCtrlWifiOnResHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlWifiOnRes* res = (CsrWifiRouterCtrlWifiOnRes*)msg;
+
+    if (priv == NULL) {
+        unifi_error(NULL, "CsrWifiRouterCtrlWifiOnResHandler: Invalid ospriv.\n");
+        return;
+    }
+
+    unifi_trace(priv, UDBG1,
+                "CsrWifiRouterCtrlWifiOnResHandler: status %d (patch %u)\n", res->status, res->smeVersions.firmwarePatch);
+
+    if (res->smeVersions.firmwarePatch != 0) {
+        unifi_info(priv, "Firmware patch %d\n", res->smeVersions.firmwarePatch);
+    }
+
+    if (res->numInterfaceAddress > CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "WifiOnResHandler bad numInterfaceAddress %d\n", res->numInterfaceAddress);
+        return;
+    }
+
+    /* UniFi is now initialised, complete the init. */
+    if (res->status == CSR_RESULT_SUCCESS)
+    {
+        int i; /* used as a loop counter */
+        CsrUint32 intmode = CSR_WIFI_INTMODE_DEFAULT;
+#ifdef CSR_WIFI_SPLIT_PATCH
+        CsrBool switching_ap_fw = FALSE;
+#endif
+        /* Register the UniFi device with the OS network manager */
+        unifi_trace(priv, UDBG3, "Card Init Completed Successfully\n");
+
+        /* Store the MAC address in the netdev */
+        for(i=0;i<res->numInterfaceAddress;i++)
+        {
+            memcpy(priv->netdev[i]->dev_addr, res->stationMacAddress[i].a, ETH_ALEN);
+        }
+
+        /* Copy version structure into the private versions field */
+        priv->sme_versions = res->smeVersions;
+
+        unifi_trace(priv, UDBG2, "network interfaces count = %d\n",
+                    res->numInterfaceAddress);
+
+        /* Register the netdevs for each interface. */
+        for(i=0;i<res->numInterfaceAddress;i++)
+        {
+            netInterface_priv_t *interfacePriv = priv->interfacePriv[i];
+            if(!interfacePriv->netdev_registered)
+            {
+                int r;
+                unifi_trace(priv, UDBG3, "registering net device %d\n", i);
+                r = uf_register_netdev(priv, i);
+                if (r)
+                {
+                    /* unregister the net_device that are registered in the previous iterations */
+                    uf_unregister_netdev(priv);
+                    unifi_error(priv, "Failed to register the network device.\n");
+                    CsrWifiRouterCtrlWifiOnCfmSend(msg->source, res->clientData, CSR_RESULT_FAILURE);
+                    return;
+                }
+            }
+#ifdef CSR_WIFI_SPLIT_PATCH
+            else
+            {
+                /* If a netdev is already registered, we have received this WifiOnRes
+                 * in response to switching AP/STA firmware in a ModeSetReq.
+                 * Rememeber this in order to send a ModeSetCfm once
+                 */
+                switching_ap_fw = TRUE;
+            }
+#endif
+        }
+        priv->totalInterfaceCount = res->numInterfaceAddress;
+
+        /* If the MIB has selected f/w scheduled interrupt mode, apply it now
+         * but let module param override.
+         */
+        if (run_bh_once != -1) {
+            intmode = (CsrUint32)run_bh_once;
+        } else if (res->scheduledInterrupt) {
+            intmode = CSR_WIFI_INTMODE_RUN_BH_ONCE;
+        }
+        unifi_set_interrupt_mode(priv->card, intmode);
+
+        priv->init_progress = UNIFI_INIT_COMPLETED;
+
+        /* Acknowledge the CsrWifiRouterCtrlWifiOnReq now */
+        CsrWifiRouterCtrlWifiOnCfmSend(msg->source, res->clientData, CSR_RESULT_SUCCESS);
+
+#ifdef CSR_WIFI_SPLIT_PATCH
+        if (switching_ap_fw && (priv->pending_mode_set.common.destination != 0xaaaa)) {
+            unifi_info(priv, "Completed firmware reload with %s patch\n",
+                CSR_WIFI_HIP_IS_AP_FW(priv->interfacePriv[0]->interfaceMode) ? "AP" : "STA");
+
+            /* Confirm the ModeSetReq that requested the AP/STA patch switch */
+            CsrWifiRouterCtrlModeSetCfmSend(priv->pending_mode_set.common.source,
+                                            priv->pending_mode_set.clientData,
+                                            priv->pending_mode_set.interfaceTag,
+                                            priv->pending_mode_set.mode,
+                                            CSR_RESULT_SUCCESS);
+            priv->pending_mode_set.common.destination = 0xaaaa;
+        }
+#endif
+        unifi_info(priv, "UniFi ready\n");
+
+#ifdef ANDROID_BUILD
+        /* Release the wakelock */
+        unifi_trace(priv, UDBG1, "ready: release wake lock\n");
+        wake_unlock(&unifi_sdio_wake_lock);
+#endif
+        /* Firmware initialisation is complete, so let the SDIO bus
+         * clock be raised when convienent to the core.
+         */
+        unifi_request_max_sdio_clock(priv->card);
+
+#ifdef CSR_SUPPORT_WEXT
+        /* Notify the Android wpa_supplicant that we are ready */
+        wext_send_started_event(priv);
+
+        queue_work(priv->unifi_workqueue, &priv->sme_config_task);
+#endif
+
+    } else {
+        /* Acknowledge the CsrWifiRouterCtrlWifiOnReq now */
+        CsrWifiRouterCtrlWifiOnCfmSend(msg->source, res->clientData, CSR_RESULT_FAILURE);
+    }
+}
+
+
+void CsrWifiRouterCtrlWifiOffResHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+
+void CsrWifiRouterCtrlMulticastAddressResHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+
+void CsrWifiRouterMaPacketSubscribeReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterMaPacketSubscribeReq* req = (CsrWifiRouterMaPacketSubscribeReq*)msg;
+    CsrUint8 i;
+    CsrResult result;
+
+    if (priv == NULL) {
+        unifi_error(priv, "CsrWifiRouterMaPacketSubscribeReqHandler: invalid priv\n");
+        return;
+    }
+
+    /* Look for an unused filter */
+
+    result = CSR_WIFI_RESULT_NO_ROOM;
+    for (i = 0; i < MAX_MA_UNIDATA_IND_FILTERS; i++) {
+
+        if (!priv->sme_unidata_ind_filters[i].in_use) {
+
+            priv->sme_unidata_ind_filters[i].in_use = 1;
+            priv->sme_unidata_ind_filters[i].appHandle = msg->source;
+            priv->sme_unidata_ind_filters[i].encapsulation = req->encapsulation;
+            priv->sme_unidata_ind_filters[i].protocol = req->protocol;
+
+            priv->sme_unidata_ind_filters[i].oui[2] = (CsrUint8)  (req->oui        & 0xFF);
+            priv->sme_unidata_ind_filters[i].oui[1] = (CsrUint8) ((req->oui >>  8) & 0xFF);
+            priv->sme_unidata_ind_filters[i].oui[0] = (CsrUint8) ((req->oui >> 16) & 0xFF);
+
+            result = CSR_RESULT_SUCCESS;
+            break;
+        }
+    }
+
+    unifi_trace(priv, UDBG1,
+                "subscribe_req: encap=%d, handle=%d, result=%d\n",
+                req->encapsulation, i, result);
+    CsrWifiRouterMaPacketSubscribeCfmSend(msg->source,req->interfaceTag, i, result, 0);
+}
+
+
+void CsrWifiRouterMaPacketUnsubscribeReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterMaPacketUnsubscribeReq* req = (CsrWifiRouterMaPacketUnsubscribeReq*)msg;
+    CsrResult result;
+
+    if (priv == NULL) {
+        unifi_error(priv, "CsrWifiRouterMaPacketUnsubscribeReqHandler: invalid priv\n");
+        return;
+    }
+
+    result = CSR_WIFI_RESULT_NOT_FOUND;
+
+    if (req->subscriptionHandle < MAX_MA_UNIDATA_IND_FILTERS) {
+        if (priv->sme_unidata_ind_filters[req->subscriptionHandle].in_use) {
+            priv->sme_unidata_ind_filters[req->subscriptionHandle].in_use = 0;
+            result = CSR_RESULT_SUCCESS;
+        } else {
+            result = CSR_WIFI_RESULT_NOT_FOUND;
+        }
+    }
+
+    unifi_trace(priv, UDBG1,
+                "unsubscribe_req: handle=%d, result=%d\n",
+                req->subscriptionHandle, result);
+    CsrWifiRouterMaPacketUnsubscribeCfmSend(msg->source,req->interfaceTag, result);
+}
+
+
+void CsrWifiRouterCtrlCapabilitiesReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlCapabilitiesReq* req = (CsrWifiRouterCtrlCapabilitiesReq*)msg;
+
+    if (priv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlCapabilitiesReqHandler: invalid priv\n");
+        return;
+    }
+
+    CsrWifiRouterCtrlCapabilitiesCfmSend(msg->source,req->clientData,
+            UNIFI_SOFT_COMMAND_Q_LENGTH - 1,
+            UNIFI_SOFT_TRAFFIC_Q_LENGTH - 1);
+}
+
+
+void CsrWifiRouterCtrlSuspendResHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlSuspendRes* res = (CsrWifiRouterCtrlSuspendRes*)msg;
+
+    if (priv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlSuspendResHandler: invalid priv\n");
+        return;
+    }
+
+    sme_complete_request(priv, res->status);
+}
+
+
+void CsrWifiRouterCtrlResumeResHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlResumeRes* res = (CsrWifiRouterCtrlResumeRes*)msg;
+
+    if (priv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlResumeResHandler: invalid priv\n");
+        return;
+    }
+
+    sme_complete_request(priv, res->status);
+}
+
+
+void CsrWifiRouterCtrlTrafficConfigReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlTrafficConfigReq* req = (CsrWifiRouterCtrlTrafficConfigReq*)msg;
+    CsrResult csrResult;
+
+    if (priv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlTrafficConfigReqHandler: invalid smepriv\n");
+        return;
+    }
+    if (req->trafficConfigType == CSR_WIFI_ROUTER_CTRL_TRAFFIC_CONFIG_TYPE_FILTER)
+    {
+        req->config.packetFilter |= CSR_WIFI_ROUTER_CTRL_TRAFFIC_PACKET_TYPE_CUSTOM;
+    }
+    csrResult = unifi_ta_configure(priv->card, req->trafficConfigType, (const CsrWifiRouterCtrlTrafficConfig *)&req->config);
+}
+
+void CsrWifiRouterCtrlTrafficClassificationReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlTrafficClassificationReq* req = (CsrWifiRouterCtrlTrafficClassificationReq*)msg;
+
+    if (priv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlTrafficClassificationReqHandler: invalid smepriv\n");
+        return;
+    }
+
+    unifi_ta_classification(priv->card, req->trafficType, req->period);
+}
+
+static int
+_sys_packet_req(unifi_priv_t *priv, const CSR_SIGNAL *signal,
+        CsrUint8 subscriptionHandle,
+        CsrUint16 frameLength, CsrUint8 *frame,
+        int proto)
+{
+    int r;
+    const sme_ma_unidata_ind_filter_t *subs;
+    bulk_data_param_t bulkdata;
+    CSR_MA_PACKET_REQUEST req = signal->u.MaPacketRequest;
+    struct sk_buff *skb, *newSkb = NULL;
+    CsrWifiMacAddress peerMacAddress;
+    CsrResult csrResult;
+    CsrUint16 interfaceTag = req.VirtualInterfaceIdentifier & 0xff;
+    CsrBool eapolStore = FALSE;
+    CsrInt8 protection = 0;
+    netInterface_priv_t *interfacePriv;
+    unsigned long flags;
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "_sys_packet_req: interfaceID >= CSR_WIFI_NUM_INTERFACES.\n");
+        return -EINVAL;
+    }
+    interfacePriv = priv->interfacePriv[interfaceTag];
+    if (!priv->sme_unidata_ind_filters[subscriptionHandle].in_use) {
+        unifi_error(priv, "_sys_packet_req: unknown subscription.\n");
+        return -EINVAL;
+    }
+
+    subs = &priv->sme_unidata_ind_filters[subscriptionHandle];
+    unifi_trace(priv, UDBG1,
+                "_sys_packet_req: handle=%d, subs=%p, encap=%d\n",
+                subscriptionHandle, subs, subs->encapsulation);
+
+    csrResult = unifi_net_data_malloc(priv, &bulkdata.d[0], frameLength);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv, "_sys_packet_req: failed to allocate bulkdata.\n");
+        return (int)CsrHipResultToStatus(csrResult);
+    }
+
+    /* get the peer Mac address */
+    memcpy(&peerMacAddress, frame, ETH_ALEN);
+
+    /* Determine if we need to add encapsulation header */
+    if (subs->encapsulation == CSR_WIFI_ROUTER_ENCAPSULATION_ETHERNET) {
+        memcpy((void*)bulkdata.d[0].os_data_ptr, frame, frameLength);
+
+        /* The translation is performed on the skb */
+        skb = (struct sk_buff*)bulkdata.d[0].os_net_buf_ptr;
+
+        unifi_trace(priv, UDBG1,
+                    "_sys_packet_req: skb_add_llc_snap -->\n");
+        r = skb_add_llc_snap(priv->netdev[interfaceTag], skb, proto);
+        unifi_trace(priv, UDBG1,
+                    "_sys_packet_req: skb_add_llc_snap <--\n");
+        if (r) {
+            unifi_error(priv,
+                        "_sys_packet_req: failed to translate eth frame.\n");
+            unifi_net_data_free(priv,&bulkdata.d[0]);
+            return r;
+        }
+
+        bulkdata.d[0].data_length = skb->len;
+    } else {
+        /* Crop the MAC addresses from the packet */
+        memcpy((void*)bulkdata.d[0].os_data_ptr, frame + 2*ETH_ALEN, frameLength - 2*ETH_ALEN);
+        bulkdata.d[0].data_length = frameLength - 2*ETH_ALEN;
+        skb = (struct sk_buff*)bulkdata.d[0].os_net_buf_ptr;
+        skb->len = bulkdata.d[0].data_length;
+
+    }
+
+    bulkdata.d[1].os_data_ptr = NULL;
+    bulkdata.d[1].os_net_buf_ptr = NULL;
+    bulkdata.d[1].data_length = 0;
+
+    /* check for m4 detection */
+    if (0 == uf_verify_m4(priv, bulkdata.d[0].os_data_ptr, bulkdata.d[0].data_length)) {
+        eapolStore = TRUE;
+    }
+
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+    if (proto == ETH_P_WAI)
+     {
+        protection = 0; /*WAI packets always sent unencrypted*/
+     }
+   else
+     {
+#endif
+
+#ifdef CSR_SUPPORT_SME
+    if ((protection = uf_get_protection_bit_from_interfacemode(priv, interfaceTag, peerMacAddress.a)) < 0) {
+        unifi_error(priv, "unicast address, but destination not in station record database\n");
+        unifi_net_data_free(priv,&bulkdata.d[0]);
+        return -1;
+    }
+#else
+    protection = 0;
+#endif
+
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+    }
+#endif
+
+    /* add Mac header */
+    if (prepare_and_add_macheader(priv, skb, newSkb, req.Priority, &bulkdata, interfaceTag, frame, frame + ETH_ALEN, protection)) {
+        unifi_error(priv, "failed to create MAC header\n");
+        unifi_net_data_free(priv,&bulkdata.d[0]);
+        return -1;
+    }
+
+    if (eapolStore) {
+        spin_lock_irqsave(&priv->m4_lock, flags);
+        /* Store the EAPOL M4 packet for later */
+        interfacePriv->m4_signal = *signal;
+        interfacePriv->m4_bulk_data.net_buf_length = bulkdata.d[0].net_buf_length;
+        interfacePriv->m4_bulk_data.data_length = bulkdata.d[0].data_length;
+        interfacePriv->m4_bulk_data.os_data_ptr = bulkdata.d[0].os_data_ptr;
+        interfacePriv->m4_bulk_data.os_net_buf_ptr = bulkdata.d[0].os_net_buf_ptr;
+        spin_unlock_irqrestore(&priv->m4_lock, flags);
+        /* Send a signal to SME */
+        unifi_trace(priv, UDBG1, "_sys_packet_req: Sending CsrWifiRouterCtrlM4ReadyToSendInd\n");
+        CsrWifiRouterCtrlM4ReadyToSendIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, interfaceTag, peerMacAddress);
+        return 0;
+    }
+
+    /* Send the signal to UniFi */
+      /* Set the B31 to 1 for local routing*/
+    r= uf_process_ma_packet_req(priv,  peerMacAddress.a, (req.HostTag | 0x80000000), interfaceTag, 0,
+                                (CSR_RATE)0, req.Priority, signal->SignalPrimitiveHeader.SenderProcessId, &bulkdata);
+    if (r) {
+        unifi_error(priv,
+                    "_sys_packet_req: failed to send signal.\n");
+        unifi_net_data_free(priv,&bulkdata.d[0]);
+        return r;
+    }
+    /* The final CsrWifiRouterMaPacketCfmSend() will called when the actual MA-PACKET.cfm is received from the chip */
+
+    return 0;
+}
+
+void CsrWifiRouterMaPacketReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    int r;
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterMaPacketReq* mareq = (CsrWifiRouterMaPacketReq*)msg;
+    llc_snap_hdr_t *snap;
+    CsrUint16 snap_protocol;
+    CSR_SIGNAL signal;
+    CSR_MA_PACKET_REQUEST *req = &signal.u.MaPacketRequest;
+    CsrWifiRouterCtrlPortAction controlPortaction;
+    CsrUint8 *daddr, *saddr;
+    CsrUint16 interfaceTag = mareq->interfaceTag & 0x00ff;
+    int queue;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if (!mareq->frame || !priv || !priv->smepriv)
+    {
+        unifi_error(priv, "CsrWifiRouterMaPacketReqHandler: invalid frame/priv/priv->smepriv\n");
+        return;
+    }
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "CsrWifiRouterMaPacketReqHandler: interfaceID >= CSR_WIFI_NUM_INTERFACES.\n");
+        return;
+    }
+    /* get a pointer to dest & source Mac address */
+    daddr = mareq->frame;
+    saddr = (mareq->frame + ETH_ALEN);
+    /* point to the proper position of frame, since frame has MAC header */
+    snap = (llc_snap_hdr_t *) (mareq->frame + 2 * ETH_ALEN);
+    snap_protocol = ntohs(snap->protocol);
+    if((snap_protocol == ETH_P_PAE)
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+       || (snap_protocol == ETH_P_WAI)
+#endif
+    )
+    {
+        queue = UF_UNCONTROLLED_PORT_Q;
+    }
+    else
+    {
+        queue = UF_CONTROLLED_PORT_Q;
+    }
+
+    /* Controlled port restrictions apply to the packets */
+    controlPortaction = uf_sme_port_state(priv, daddr, queue, interfaceTag);
+    if (controlPortaction != CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN)
+    {
+        unifi_warning(priv, "CsrWifiRouterMaPacketReqHandler: (%s)controlled port is closed.\n", (queue == UF_CONTROLLED_PORT_Q)?"":"un");
+        if(mareq->cfmRequested)
+        {
+            CsrWifiRouterMaPacketCfmSend(msg->source,
+                                     interfaceTag,
+                                     CSR_RESULT_FAILURE,
+                                     mareq->hostTag, 0);
+        }
+        return;
+    }
+
+    signal.SignalPrimitiveHeader.SignalId = CSR_MA_PACKET_REQUEST_ID;
+    /* Store the appHandle in the LSB of the SenderId. */
+    CSR_COPY_UINT16_TO_LITTLE_ENDIAN(((priv->sme_cli->sender_id & 0xff00) | (unsigned int)msg->source),
+                                     (u8*)&signal.SignalPrimitiveHeader.SenderProcessId);
+    signal.SignalPrimitiveHeader.ReceiverProcessId = 0;
+
+    /* Fill in the MA-PACKET.req signal */
+    memcpy(req->Ra.x, daddr, ETH_ALEN);
+    req->Priority = mareq->priority;
+    req->TransmitRate = 0; /* Let firmware select the rate*/
+    req->VirtualInterfaceIdentifier = uf_get_vif_identifier(interfacePriv->interfaceMode,interfaceTag);
+    req->HostTag = mareq->hostTag;
+
+    if(mareq->cfmRequested)
+        req->TransmissionControl = 0;
+    else
+        req->TransmissionControl = CSR_NO_CONFIRM_REQUIRED;
+
+    r = _sys_packet_req(priv, &signal, mareq->subscriptionHandle,
+            mareq->frameLength, mareq->frame, snap_protocol);
+
+#define MAX_RETRY 2
+    if (r && mareq->cfmRequested)
+    {
+        CsrWifiRouterMaPacketCfmSend(msg->source,interfaceTag,
+                                     CSR_RESULT_FAILURE,
+                                     mareq->hostTag, 0);
+    }
+    return;
+}
+
+void CsrWifiRouterMaPacketCancelReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+void CsrWifiRouterCtrlM4TransmitReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlM4TransmitReq* req = (CsrWifiRouterCtrlM4TransmitReq*)msg;
+    int r;
+    bulk_data_param_t bulkdata;
+    netInterface_priv_t *interfacePriv;
+    CSR_SIGNAL m4_signal;
+    unsigned long flags;
+
+    if (priv == NULL) {
+        unifi_error(priv, "CsrWifiRouterCtrlM4TransmitReqHandler: invalid smepriv\n");
+        return;
+    }
+    if (req->interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "M4TransmitReqHandler: interfaceTag >= CSR_WIFI_NUM_INTERFACES\n");
+        return;
+    }
+
+    interfacePriv = priv->interfacePriv[req->interfaceTag];
+    spin_lock_irqsave(&priv->m4_lock, flags);
+    if (interfacePriv->m4_bulk_data.data_length == 0) {
+        spin_unlock_irqrestore(&priv->m4_lock, flags);
+        unifi_error(priv, "CsrWifiRouterCtrlM4TransmitReqHandler: invalid buffer\n");
+        return;
+    }
+
+    memcpy(&bulkdata.d[0], &interfacePriv->m4_bulk_data, sizeof(bulk_data_desc_t));
+
+    interfacePriv->m4_bulk_data.net_buf_length = 0;
+    interfacePriv->m4_bulk_data.data_length = 0;
+    interfacePriv->m4_bulk_data.os_data_ptr = interfacePriv->m4_bulk_data.os_net_buf_ptr = NULL;
+    m4_signal = interfacePriv->m4_signal;
+    spin_unlock_irqrestore(&priv->m4_lock, flags);
+
+    bulkdata.d[1].os_data_ptr = NULL;
+    bulkdata.d[1].data_length = 0;
+
+    interfacePriv->m4_sent = TRUE;
+    m4_signal.u.MaPacketRequest.HostTag |= 0x80000000;
+    /* Store the hostTag for later varification */
+    interfacePriv->m4_hostTag = m4_signal.u.MaPacketRequest.HostTag;
+    r = ul_send_signal_unpacked(priv, &m4_signal, &bulkdata);
+    unifi_trace(priv, UDBG1,
+                "CsrWifiRouterCtrlM4TransmitReqHandler: sent\n");
+    if (r) {
+        unifi_error(priv,
+                    "CsrWifiRouterCtrlM4TransmitReqHandler: failed to send signal.\n");
+        unifi_net_data_free(priv, &bulkdata.d[0]);
+    }
+}
+
+/* reset the station records when the mode is set as CSR_WIFI_ROUTER_CTRL_MODE_NONE */
+static void CsrWifiRouterCtrlResetStationRecordList(unifi_priv_t *priv, CsrUint16 interfaceTag)
+{
+    CsrUint8 i,j;
+    CsrWifiRouterCtrlStaInfo_t *staInfo=NULL;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    unsigned long lock_flags;
+
+    /* create a list for sending confirms of un-delivered packets */
+    struct list_head send_cfm_list;
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "CsrWifiRouterCtrlResetStationRecordList: bad interfaceTag\n");
+        return;
+    }
+
+    INIT_LIST_HEAD(&send_cfm_list);
+
+    /* Reset the station record to NULL if mode is NONE */
+    for(i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
+        if ((staInfo=interfacePriv->staInfo[i]) != NULL) {
+            uf_prepare_send_cfm_list_for_queued_pkts(priv,
+                                                 &send_cfm_list,
+                                                 &(staInfo->mgtFrames));
+            uf_flush_list(priv,&(staInfo->mgtFrames));
+            for(j=0;j<MAX_ACCESS_CATOGORY;j++){
+                uf_prepare_send_cfm_list_for_queued_pkts(priv,
+                                                     &send_cfm_list,
+                                                     &(staInfo->dataPdu[j]));
+                uf_flush_list(priv,&(staInfo->dataPdu[j]));
+            }
+
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+            /* Removing station record information from port config array */
+            memset(staInfo->peerControlledPort, 0, sizeof(unifi_port_cfg_t));
+            staInfo->peerControlledPort->port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
+            staInfo->peerControlledPort->in_use = FALSE;
+            interfacePriv->controlled_data_port.entries_in_use--;
+
+            memset(staInfo->peerUnControlledPort, 0, sizeof(unifi_port_cfg_t));
+            staInfo->peerUnControlledPort->port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
+            staInfo->peerUnControlledPort->in_use = FALSE;
+            interfacePriv->uncontrolled_data_port.entries_in_use--;
+
+            kfree(interfacePriv->staInfo[i]);
+            interfacePriv->staInfo[i] = NULL;
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+        }
+    }
+    /* after the critical region process the list of frames that requested cfm
+     * and send cfm to requestor one by one
+     */
+    send_auto_ma_packet_confirm(priv, interfacePriv, &send_cfm_list);
+
+#ifdef CSR_SUPPORT_SME
+    /* Interface Independent, no of packet queued, incase of mode is None or AP set to 0 */
+    switch(interfacePriv->interfaceMode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+        case CSR_WIFI_ROUTER_CTRL_MODE_NONE:
+            if (priv->noOfPktQueuedInDriver) {
+                unifi_warning(priv, "After reset the noOfPktQueuedInDriver = %x\n", priv->noOfPktQueuedInDriver);
+                spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+                priv->noOfPktQueuedInDriver = 0;
+                spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+            }
+            break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_IBSS:
+            break;
+        default:
+            unifi_error(priv, "interfacemode is not correct in CsrWifiRouterCtrlResetStationRecordList: debug\n");
+    }
+#endif
+
+    if (((interfacePriv->controlled_data_port.entries_in_use != 0) || (interfacePriv->uncontrolled_data_port.entries_in_use != 0))
+            && (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_NONE)) {
+        /* Print in case if the value of entries goes to -ve/+ve (apart from 0)
+         * we expect the entries should be zero here if mode is set as NONE
+         */
+        unifi_trace(priv, UDBG3, "In %s controlled port entries = %d, uncontrolled port entries = %d\n",
+                   __FUNCTION__, interfacePriv->controlled_data_port.entries_in_use,
+                   interfacePriv->uncontrolled_data_port.entries_in_use);
+    }
+}
+
+void CsrWifiRouterCtrlInterfaceReset(unifi_priv_t *priv, CsrUint16 interfaceTag)
+{
+    netInterface_priv_t *interfacePriv;
+
+    /* create a list for sending confirms of un-delivered packets */
+    struct list_head send_cfm_list;
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "CsrWifiRouterCtrlInterfaceReset: bad interfaceTag\n");
+        return;
+    }
+
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    INIT_LIST_HEAD(&send_cfm_list);
+
+    /* Enable all queues by default */
+    interfacePriv->queueEnabled[0] = 1;
+    interfacePriv->queueEnabled[1] = 1;
+    interfacePriv->queueEnabled[2] = 1;
+    interfacePriv->queueEnabled[3] = 1;
+
+    uf_prepare_send_cfm_list_for_queued_pkts(priv,
+                                             &send_cfm_list,
+                                             &(interfacePriv->genericMgtFrames));
+    uf_flush_list(priv,&(interfacePriv->genericMgtFrames));
+
+    uf_prepare_send_cfm_list_for_queued_pkts(priv,
+                                             &send_cfm_list,
+                                             &(interfacePriv->genericMulticastOrBroadCastMgtFrames));
+    uf_flush_list(priv,&(interfacePriv->genericMulticastOrBroadCastMgtFrames));
+
+    uf_prepare_send_cfm_list_for_queued_pkts(priv,
+                                             &send_cfm_list,
+                                             &(interfacePriv->genericMulticastOrBroadCastFrames));
+
+    uf_flush_list(priv,&(interfacePriv->genericMulticastOrBroadCastFrames));
+
+    /*  process the list of frames that requested cfm
+    and send cfm to requestor one by one */
+    send_auto_ma_packet_confirm(priv, interfacePriv, &send_cfm_list);
+
+    /* Reset the station record to NULL if mode is tried to set as NONE */
+    switch(interfacePriv->interfaceMode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_STA:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI:
+        case CSR_WIFI_ROUTER_CTRL_MODE_MONITOR:
+        case CSR_WIFI_ROUTER_CTRL_MODE_AMP:
+            /* station records not available in these modes */
+            break;
+        default:
+            CsrWifiRouterCtrlResetStationRecordList(priv,interfaceTag);
+    }
+
+    interfacePriv->num_stations_joined = 0;
+    interfacePriv->sta_activity_check_enabled = FALSE;
+}
+
+
+void CsrWifiRouterCtrlModeSetReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlModeSetReq* req = (CsrWifiRouterCtrlModeSetReq*)msg;
+
+    if (priv == NULL)
+    {
+        unifi_error(priv, "CsrWifiRouterCtrlModeSetReqHandler: invalid smepriv\n");
+        return;
+    }
+
+    if (req->interfaceTag < CSR_WIFI_NUM_INTERFACES)
+    {
+        netInterface_priv_t *interfacePriv = priv->interfacePriv[req->interfaceTag];
+#ifdef CSR_WIFI_SPLIT_PATCH
+        CsrUint8 old_mode = interfacePriv->interfaceMode;
+#endif
+        unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlModeSetReqHandler: interfacePriv->interfaceMode = %d\n",
+                interfacePriv->interfaceMode);
+
+        interfacePriv->interfaceMode = req->mode;
+
+#ifdef CSR_WIFI_SPLIT_PATCH
+        /* Detect a change in mode that requires a switch to/from the AP firmware patch.
+         * This should only happen when transitioning in/out of AP modes.
+         */
+        if (CSR_WIFI_HIP_IS_AP_FW(req->mode) != CSR_WIFI_HIP_IS_AP_FW(old_mode))
+        {
+            CsrWifiRouterCtrlVersions versions;
+            int r;
+
+#ifdef ANDROID_BUILD
+            /* Take the wakelock while switching patch */
+            unifi_trace(priv, UDBG1, "patch switch: take wake lock\n");
+            wake_lock(&unifi_sdio_wake_lock);
+#endif
+            unifi_info(priv, "Resetting UniFi with %s patch\n", CSR_WIFI_HIP_IS_AP_FW(req->mode) ? "AP" : "STA");
+
+            r = uf_request_firmware_files(priv, UNIFI_FW_STA);
+            if (r) {
+                unifi_error(priv, "CsrWifiRouterCtrlModeSetReqHandler: Failed to get f/w\n");
+                CsrWifiRouterCtrlModeSetCfmSend(msg->source, req->clientData, req->interfaceTag,
+                                                req->mode, CSR_RESULT_FAILURE);
+                return;
+            }
+
+            /* Block the I/O thread */
+            priv->bh_thread.block_thread = 1;
+
+            /* Reset and download the new patch */
+            r = uf_init_hw(priv);
+            if (r) {
+                unifi_error(priv, "CsrWifiRouterCtrlWifiOnReqHandler: Failed to initialise h/w, error %d\n", r);
+                CsrWifiRouterCtrlModeSetCfmSend(msg->source, req->clientData, req->interfaceTag,
+                                                req->mode, CSR_RESULT_FAILURE);
+                return;
+            }
+
+            /* Re-enable the I/O thread */
+            priv->bh_thread.block_thread = 0;
+
+            /* Get the version information from the core */
+            unifi_card_info(priv->card, &priv->card_info);
+
+            /* Copy to the unifiio_card_info structure. */
+            versions.chipId = priv->card_info.chip_id;
+            versions.chipVersion = priv->card_info.chip_version;
+            versions.firmwareBuild = priv->card_info.fw_build;
+            versions.firmwareHip = priv->card_info.fw_hip_version;
+            versions.routerBuild = (CsrCharString*)CSR_WIFI_VERSION;
+            versions.routerHip = (UNIFI_HIP_MAJOR_VERSION << 8) | UNIFI_HIP_MINOR_VERSION;
+
+            /* Now that new firmware is running, send a WifiOnInd to the NME. This will
+             * cause it to retransfer the MIB.
+             */
+            CsrWifiRouterCtrlWifiOnIndSend(msg->source, 0, CSR_RESULT_SUCCESS, versions);
+
+            /* Store the request so we know where to send the ModeSetCfm */
+            priv->pending_mode_set = *req;
+        }
+        else
+#endif
+        {
+            /* No patch switch, confirm straightaway */
+            CsrWifiRouterCtrlModeSetCfmSend(msg->source, req->clientData, req->interfaceTag,
+                                            req->mode, CSR_RESULT_SUCCESS);
+        }
+
+        interfacePriv->bssid = req->bssid;
+        /* For modes other than AP/P2PGO, set below member FALSE */
+        interfacePriv->intraBssEnabled = FALSE;
+        /* Initialise the variable bcTimSet with a value
+         * other then CSR_WIFI_TIM_SET or CSR_WIFI_TIM_RESET value
+         */
+        interfacePriv->bcTimSet = 0xFF;
+        interfacePriv->bcTimSetReqPendingFlag = FALSE;
+        /* Initialise the variable bcTimSetReqQueued with a value
+         * other then CSR_WIFI_TIM_SET or CSR_WIFI_TIM_RESET value
+         */
+        interfacePriv->bcTimSetReqQueued =0xFF;
+        CsrWifiRouterCtrlInterfaceReset(priv,req->interfaceTag);
+
+        if(req->mode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+           req->mode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+            interfacePriv->protect = req->protection;
+            interfacePriv->dtimActive=FALSE;
+            interfacePriv->multicastPduHostTag = 0xffffffff;
+            /* For AP/P2PGO mode SME sending intraBssDistEnabled
+             * i.e. for AP: intraBssDistEnabled = TRUE, for P2PGO
+             * intraBssDistEnabled = TRUE/FALSE on requirement
+             */
+            interfacePriv->intraBssEnabled = req->intraBssDistEnabled;
+            unifi_trace(priv, UDBG3, "CsrWifiRouterCtrlModeSetReqHandler: IntraBssDisEnabled = %d\n",
+                        req->intraBssDistEnabled);
+        } else if (req->mode == CSR_WIFI_ROUTER_CTRL_MODE_NONE) {
+              netif_carrier_off(priv->netdev[req->interfaceTag]);
+              interfacePriv->connected = UnifiConnectedUnknown;
+        }
+    }
+    else {
+        unifi_error(priv, "CsrWifiRouterCtrlModeSetReqHandler: invalid interfaceTag :%d\n",req->interfaceTag);
+    }
+}
+
+void CsrWifiRouterMaPacketResHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+}
+
+/* delete the station record from the station record data base */
+static int peer_delete_record(unifi_priv_t *priv, CsrWifiRouterCtrlPeerDelReq *req)
+{
+    CsrUint8 j;
+    CsrWifiRouterCtrlStaInfo_t *staInfo = NULL;
+    unifi_port_config_t *controlledPort;
+    unifi_port_config_t *unControlledPort;
+    netInterface_priv_t *interfacePriv;
+
+    CsrUint8 ba_session_idx = 0;
+    ba_session_rx_struct *ba_session_rx = NULL;
+    ba_session_tx_struct *ba_session_tx = NULL;
+
+    /* create a list for sending confirms of un-delivered packets */
+    struct list_head send_cfm_list;
+
+    unsigned long lock_flags;
+
+    if ((req->peerRecordHandle >= UNIFI_MAX_CONNECTIONS) || (req->interfaceTag >= CSR_WIFI_NUM_INTERFACES)) {
+        unifi_error(priv, "handle/interfaceTag is not proper, handle = %d, interfaceTag = %d\n", req->peerRecordHandle, req->interfaceTag);
+        return CSR_RESULT_FAILURE;
+    }
+
+    INIT_LIST_HEAD(&send_cfm_list);
+
+    interfacePriv = priv->interfacePriv[req->interfaceTag];
+    /* remove the station record & make it NULL */
+    if ((staInfo=interfacePriv->staInfo[req->peerRecordHandle])!=NULL) {
+
+        uf_prepare_send_cfm_list_for_queued_pkts(priv,
+                                                 &send_cfm_list,
+                                                 &(staInfo->mgtFrames));
+
+        uf_flush_list(priv,&(staInfo->mgtFrames));
+        for(j=0;j<MAX_ACCESS_CATOGORY;j++){
+            uf_prepare_send_cfm_list_for_queued_pkts(priv,
+                                                     &send_cfm_list,
+                                                     &(staInfo->dataPdu[j]));
+            uf_flush_list(priv,&(staInfo->dataPdu[j]));
+        }
+
+        spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+        /* clear the port configure array info, for the corresponding peer entry */
+        controlledPort = &interfacePriv->controlled_data_port;
+        unControlledPort = &interfacePriv->uncontrolled_data_port;
+
+        unifi_trace(priv, UDBG1, "peer_delete_record: Peer found handle = %d, port in use: cont(%d), unCont(%d)\n",
+                    req->peerRecordHandle, controlledPort->entries_in_use, unControlledPort->entries_in_use);
+
+        memset(staInfo->peerControlledPort, 0, sizeof(unifi_port_cfg_t));
+        staInfo->peerControlledPort->port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
+        staInfo->peerControlledPort->in_use = FALSE;
+        if (controlledPort->entries_in_use) {
+            controlledPort->entries_in_use--;
+        } else {
+            unifi_warning(priv, "number of controlled port entries is zero, trying to decrement: debug\n");
+        }
+
+        memset(staInfo->peerUnControlledPort, 0, sizeof(unifi_port_cfg_t));
+        staInfo->peerUnControlledPort->port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
+        staInfo->peerUnControlledPort->in_use = FALSE;
+        if (unControlledPort->entries_in_use) {
+            unControlledPort->entries_in_use--;
+        } else {
+            unifi_warning(priv, "number of uncontrolled port entries is zero, trying to decrement: debug\n");
+        }
+
+        spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+        /* update the TIM with zero */
+        if (interfacePriv->interfaceMode != CSR_WIFI_ROUTER_CTRL_MODE_IBSS &&
+                staInfo->timSet == CSR_WIFI_TIM_SET) {
+            unifi_trace(priv, UDBG3, "peer is deleted so TIM updated to 0, in firmware\n");
+            update_tim(priv,staInfo->aid,0,req->interfaceTag, req->peerRecordHandle);
+        }
+
+
+        /* Stop BA session if it is active, for this peer address all BA sessions
+        (per tID per role) are closed */
+
+        down(&priv->ba_mutex);
+        for(ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_RX; ba_session_idx++){
+            ba_session_rx = priv->interfacePriv[req->interfaceTag]->ba_session_rx[ba_session_idx];
+            if(ba_session_rx) {
+                if(!memcmp(ba_session_rx->macAddress.a, staInfo->peerMacAddress.a, ETH_ALEN)){
+                    blockack_session_stop(priv,
+                                        req->interfaceTag,
+                                        CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_RECIPIENT,
+                                        ba_session_rx->tID,
+                                        ba_session_rx->macAddress);
+                }
+            }
+        }
+
+        for(ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_TX; ba_session_idx++){
+            ba_session_tx = priv->interfacePriv[req->interfaceTag]->ba_session_tx[ba_session_idx];
+            if(ba_session_tx) {
+                if(!memcmp(ba_session_tx->macAddress.a, staInfo->peerMacAddress.a, ETH_ALEN)){
+                    blockack_session_stop(priv,
+                                        req->interfaceTag,
+                                        CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ORIGINATOR,
+                                        ba_session_tx->tID,
+                                        ba_session_tx->macAddress);
+                }
+            }
+        }
+
+        up(&priv->ba_mutex);
+
+#ifdef CSR_SUPPORT_SME
+        unifi_trace(priv, UDBG1, "Canceling work queue for STA with AID: %d\n", staInfo->aid);
+        cancel_work_sync(&staInfo->send_disconnected_ind_task);
+#endif
+
+        spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+#ifdef CSR_SUPPORT_SME
+        interfacePriv->num_stations_joined--;
+
+        staInfo->nullDataHostTag = INVALID_HOST_TAG;
+
+        if ((interfacePriv->sta_activity_check_enabled) &&
+            (interfacePriv->num_stations_joined < STA_INACTIVE_DETECTION_TRIGGER_THRESHOLD))
+        {
+            unifi_trace(priv, UDBG1, "STOPPING the Inactivity Timer (num of stations = %d)\n", interfacePriv->num_stations_joined);
+            interfacePriv->sta_activity_check_enabled = FALSE;
+            del_timer_sync(&interfacePriv->sta_activity_check_timer);
+        }
+#endif
+
+        /* Free the station record for corresponding peer */
+        kfree(interfacePriv->staInfo[req->peerRecordHandle]);
+        interfacePriv->staInfo[req->peerRecordHandle] = NULL;
+        spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+
+        /* after the critical region process the list of frames that requested cfm
+        and send cfm to requestor one by one */
+        send_auto_ma_packet_confirm(priv, interfacePriv, &send_cfm_list);
+
+
+    }
+    else
+    {
+        unifi_trace(priv, UDBG3, " peer not found: Delete request Peer handle[%d]\n", req->peerRecordHandle);
+    }
+
+    return CSR_RESULT_SUCCESS;
+}
+
+void CsrWifiRouterCtrlPeerDelReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    CsrWifiRouterCtrlPeerDelReq* req = (CsrWifiRouterCtrlPeerDelReq*)msg;
+    CsrResult status = CSR_RESULT_SUCCESS;
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[req->interfaceTag];
+
+    unifi_trace(priv, UDBG2, "entering CsrWifiRouterCtrlPeerDelReqHandler \n");
+    if (priv == NULL)
+    {
+        unifi_error(priv, "CsrWifiRouterCtrlPeerDelReqHandler: invalid smepriv\n");
+        return;
+    }
+
+    if (req->interfaceTag >= CSR_WIFI_NUM_INTERFACES)
+    {
+        unifi_error(priv, "CsrWifiRouterCtrlPeerDelReqHandler: bad interfaceTag\n");
+        return;
+    }
+
+    switch(interfacePriv->interfaceMode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_IBSS:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+            /* remove the station from station record data base */
+            status = peer_delete_record(priv, req);
+            break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_STA:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI:
+        default:
+            /* No station record to maintain in these modes */
+            break;
+    }
+
+    CsrWifiRouterCtrlPeerDelCfmSend(msg->source,req->clientData,req->interfaceTag,status);
+    unifi_trace(priv, UDBG2, "leaving CsrWifiRouterCtrlPeerDelReqHandler \n");
+}
+
+/* Add the new station to the station record data base */
+static int peer_add_new_record(unifi_priv_t *priv,CsrWifiRouterCtrlPeerAddReq *req,CsrUint32 *handle)
+{
+    CsrUint8 i, powerModeTemp = 0;
+    CsrBool freeSlotFound = FALSE;
+    CsrWifiRouterCtrlStaInfo_t *newRecord = NULL;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[req->interfaceTag];
+    CsrTime currentTime, currentTimeHi;
+    unsigned long lock_flags;
+
+    if (req->interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "peer_add_new_record: bad interfaceTag\n");
+        return CSR_RESULT_FAILURE;
+    }
+
+    currentTime = CsrTimeGet(&currentTimeHi);
+
+    for(i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
+        if(interfacePriv->staInfo[i] == NULL) {
+            /* Slot is empty, so can be used for station record */
+            freeSlotFound = TRUE;
+            *handle = i;
+
+            /* Allocate for the new station record , to avoid race condition would happen between ADD_PEER &
+             * DEL_PEER the allocation made atomic memory rather than kernel memory
+             */
+            newRecord = (CsrWifiRouterCtrlStaInfo_t *) kmalloc(sizeof(CsrWifiRouterCtrlStaInfo_t), GFP_ATOMIC);
+            if (!newRecord) {
+                unifi_error(priv, "failed to allocate the %d bytes of mem for station record\n",
+                            sizeof(CsrWifiRouterCtrlStaInfo_t));
+                return CSR_RESULT_FAILURE;
+            }
+
+            unifi_trace(priv, UDBG1, "peer_add_new_record: handle = %d AID = %d addr = %x:%x:%x:%x:%x:%x LI=%u\n",
+                        *handle, req->associationId, req->peerMacAddress.a[0], req->peerMacAddress.a[1], req->peerMacAddress.a[2],
+                        req->peerMacAddress.a[3], req->peerMacAddress.a[4], req->peerMacAddress.a[5],
+                        req->staInfo.listenIntervalInTus);
+
+            /* disable the preemption until station record updated */
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+
+            interfacePriv->staInfo[i] = newRecord;
+            /* Initialize the record*/
+            memset(newRecord,0,sizeof(CsrWifiRouterCtrlStaInfo_t));
+            /* update the station record */
+            memcpy(newRecord->peerMacAddress.a, req->peerMacAddress.a, ETH_ALEN);
+            newRecord->wmmOrQosEnabled = req->staInfo.wmmOrQosEnabled;
+
+            /* maxSpLength is bit map in qosInfo field, so converting accordingly */
+            newRecord->maxSpLength = req->staInfo.maxSpLength * 2;
+
+            /*Max SP 0 mean any number of packets. since we buffer only 512
+            packets we are hard coding this to zero for the moment */
+
+            if(newRecord->maxSpLength == 0)
+                newRecord->maxSpLength=512;
+
+            newRecord->assignedHandle = i;
+
+             /* copy power save mode of all access catagory (Trigger/Delivery/both enabled/disabled) */
+            powerModeTemp = (CsrUint8) ((req->staInfo.powersaveMode >> 4) & 0xff);
+
+            if(!(req->staInfo.powersaveMode & 0x0001))
+                newRecord->powersaveMode[UNIFI_TRAFFIC_Q_BK]= CSR_WIFI_AC_LEGACY_POWER_SAVE;
+            else
+               newRecord->powersaveMode[UNIFI_TRAFFIC_Q_BK]= powerModeTemp & 0x03;
+
+            if(!(req->staInfo.powersaveMode & 0x0002))
+                newRecord->powersaveMode[UNIFI_TRAFFIC_Q_BE]= CSR_WIFI_AC_LEGACY_POWER_SAVE;
+            else
+               newRecord->powersaveMode[UNIFI_TRAFFIC_Q_BE]= ((powerModeTemp & 0x0C)>> 2);
+
+            if(!(req->staInfo.powersaveMode & 0x0004))
+                newRecord->powersaveMode[UNIFI_TRAFFIC_Q_VI]= CSR_WIFI_AC_LEGACY_POWER_SAVE;
+            else
+               newRecord->powersaveMode[UNIFI_TRAFFIC_Q_VI]= ((powerModeTemp & 0x30)>> 4);
+
+            if(!(req->staInfo.powersaveMode & 0x0008))
+                newRecord->powersaveMode[UNIFI_TRAFFIC_Q_VO]= CSR_WIFI_AC_LEGACY_POWER_SAVE;
+            else
+               newRecord->powersaveMode[UNIFI_TRAFFIC_Q_VO]= ((powerModeTemp & 0xC0)>> 6);
+
+            {
+                CsrUint8 k;
+                for(k=0; k< MAX_ACCESS_CATOGORY ;k++)
+                    unifi_trace(priv, UDBG2, "peer_add_new_record: WMM : %d ,AC %d, powersaveMode %x \n",
+                            req->staInfo.wmmOrQosEnabled,k,newRecord->powersaveMode[k]);
+            }
+
+            unifi_trace(priv, UDBG3, "newRecord->wmmOrQosEnabled : %d , MAX SP : %d\n",
+                    newRecord->wmmOrQosEnabled,newRecord->maxSpLength);
+
+            /* Initialize the mgtFrames & data Pdu list */
+            {
+                CsrUint8 j;
+                INIT_LIST_HEAD(&newRecord->mgtFrames);
+                for(j = 0; j < MAX_ACCESS_CATOGORY; j++) {
+                    INIT_LIST_HEAD(&newRecord->dataPdu[j]);
+                }
+            }
+
+            newRecord->lastActivity = currentTime;
+            newRecord->activity_flag = TRUE;
+
+            /* enable the preemption as station record updated */
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+
+            /* First time port actions are set for the peer with below information */
+            configure_data_port(priv, CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN, &newRecord->peerMacAddress,
+                                UF_UNCONTROLLED_PORT_Q, req->interfaceTag);
+
+            if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_IBSS) {
+                configure_data_port(priv, CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN, &newRecord->peerMacAddress,
+                                    UF_CONTROLLED_PORT_Q, req->interfaceTag);
+            } else {
+                configure_data_port(priv, CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD, &newRecord->peerMacAddress,
+                                    UF_CONTROLLED_PORT_Q, req->interfaceTag);
+            }
+
+
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+            /* Port status must be already set before calling the Add Peer request */
+            newRecord->peerControlledPort = uf_sme_port_config_handle(priv, newRecord->peerMacAddress.a,
+                                                                      UF_CONTROLLED_PORT_Q, req->interfaceTag);
+            newRecord->peerUnControlledPort = uf_sme_port_config_handle(priv, newRecord->peerMacAddress.a,
+                                                                        UF_UNCONTROLLED_PORT_Q, req->interfaceTag);
+
+            if (!newRecord->peerControlledPort || !newRecord->peerUnControlledPort) {
+                /* enable the preemption as station record failed to update */
+                unifi_warning(priv, "Un/ControlledPort record not found in port configuration array index = %d\n", i);
+                kfree(interfacePriv->staInfo[i]);
+                interfacePriv->staInfo[i] = NULL;
+                spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+                return CSR_RESULT_FAILURE;
+            }
+
+            newRecord->currentPeerState = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE;
+
+            /* changes done during block ack handling */
+            newRecord->txSuspend = FALSE;
+
+            /*U-APSD related data structure*/
+            newRecord->timRequestPendingFlag = FALSE;
+
+            /* Initialise the variable updateTimReqQueued with a value
+             * other then CSR_WIFI_TIM_SET or CSR_WIFI_TIM_RESET value
+             */
+            newRecord->updateTimReqQueued = 0xFF;
+            newRecord->timSet = CSR_WIFI_TIM_RESET;
+            newRecord->uapsdActive = FALSE;
+            newRecord->noOfSpFramesSent =0;
+            newRecord->triggerFramePriority = CSR_QOS_UP0;
+
+            /* The protection bit is updated once the port opens for corresponding peer in
+             * routerPortConfigure request */
+
+            /* update the association ID */
+            newRecord->aid = req->associationId;
+
+#ifdef CSR_SUPPORT_SME
+            interfacePriv->num_stations_joined++;
+            newRecord->interfacePriv = interfacePriv;
+            newRecord->listenIntervalInTus = req->staInfo.listenIntervalInTus;
+            newRecord->nullDataHostTag = INVALID_HOST_TAG;
+
+            INIT_WORK(&newRecord->send_disconnected_ind_task, uf_send_disconnected_ind_wq);
+
+            if(!(interfacePriv->sta_activity_check_enabled) &&
+               (interfacePriv->num_stations_joined >= STA_INACTIVE_DETECTION_TRIGGER_THRESHOLD)){
+                unifi_trace(priv, UDBG1,
+                            "peer_add_new_record: STARTING the Inactivity Timer (num of stations = %d)",
+                            interfacePriv->num_stations_joined);
+
+                interfacePriv->sta_activity_check_enabled = TRUE;
+                interfacePriv->sta_activity_check_timer.function = check_inactivity_timer_expire_func;
+                interfacePriv->sta_activity_check_timer.data = (unsigned long)interfacePriv;
+
+                init_timer(&interfacePriv->sta_activity_check_timer);
+                mod_timer(&interfacePriv->sta_activity_check_timer,
+                          (jiffies + usecs_to_jiffies(STA_INACTIVE_DETECTION_TIMER_INTERVAL * 1000 * 1000)));
+
+            }
+#endif
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+            break;
+        }
+    }
+
+    if(!freeSlotFound) {
+        unifi_error(priv, "Limited connectivity, Free slot not found for station record addition\n");
+        return CSR_RESULT_FAILURE;
+    }
+    return CSR_RESULT_SUCCESS;
+}
+
+#ifdef CSR_SUPPORT_SME
+static void check_inactivity_timer_expire_func(unsigned long data)
+{
+    struct unifi_priv *priv;
+    CsrWifiRouterCtrlStaInfo_t *sta_record = NULL;
+    CsrUint8 i = 0;
+    CsrTime now;
+    CsrTime inactive_time;
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *) data;
+
+    if (!interfacePriv)
+    {
+        return;
+    }
+
+    priv = interfacePriv->privPtr;
+
+    if (interfacePriv->InterfaceTag >= CSR_WIFI_NUM_INTERFACES)
+    {
+        unifi_error(priv, "check_inactivity_timer_expire_func: Invalid interfaceTag\n");
+        return;
+    }
+
+    /* RUN Algorithm to check inactivity for each connected station */
+    now = CsrTimeGet(NULL);
+
+    for(i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
+        if(interfacePriv->staInfo[i] != NULL) {
+            sta_record = interfacePriv->staInfo[i];
+
+            if (sta_record->activity_flag == TRUE){
+                sta_record->activity_flag = FALSE;
+                sta_record->lastActivity = now;
+                continue;
+            }
+
+            if (sta_record->lastActivity > now)
+            {
+                /* simple timer wrap (for 1 wrap) */
+                inactive_time = CsrTimeAdd((CsrTime)CsrTimeSub(CSR_SCHED_TIME_MAX, sta_record->lastActivity), now);
+            }
+            else
+            {
+                inactive_time = (CsrTime)CsrTimeSub(now, sta_record->lastActivity);
+            }
+
+            if (inactive_time >= STA_INACTIVE_TIMEOUT_VAL)
+            {
+                unifi_trace(priv, UDBG1, "STA is Inactive - AID = %d inactive_time = %d\n",
+                                        sta_record->aid,
+                                        inactive_time);
+
+                /* station is in-active, if it is in active mode send a null frame
+                 * and the station should acknowledge the null frame, if acknowledgement
+                 * is not received throw out the station.
+                 * If the station is in Power Save, update TIM for the station so
+                 * that it wakes up and register some activity through PS-Poll or
+                 * trigger frame.
+                 */
+                 if (sta_record->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE)
+                 {
+                    unifi_trace(priv, UDBG1, "STA power save state - Active, send a NULL frame to check if it is ALIVE\n");
+                    uf_send_nulldata ( priv,
+                                       sta_record->interfacePriv->InterfaceTag,
+                                       sta_record->peerMacAddress.a,
+                                       CSR_CONTENTION,
+                                       sta_record);
+                 }
+                 else if (sta_record->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE)
+                 {
+                    if((sta_record->timSet == CSR_WIFI_TIM_SET) ||
+                       (sta_record->timSet == CSR_WIFI_TIM_SETTING))
+                    {
+                        unifi_trace(priv, UDBG1, "STA power save state - PS, TIM is already SET\n");
+
+                        /* If TIM is set and we do not have any activity for
+                         * more than 3 listen intervals then send a disconnected
+                         * indication to SME, to delete the station from station
+                         * record list.
+                         * The inactivity is already more than STA_INACTIVE_TIMEOUT_VAL
+                         * and this check ensures if the listen interval is a larger
+                         * value than STA_INACTIVE_TIMEOUT_VAL.
+                         */
+                         if (inactive_time > (3 * (sta_record->listenIntervalInTus * 1024)))
+                         {
+                            unifi_trace(priv, UDBG1, "STA is inactive for more than 3 listen intervals\n");
+                            queue_work( priv->unifi_workqueue,
+                                        &sta_record->send_disconnected_ind_task);
+                         }
+
+                    }
+                    else
+                    {
+                        unifi_trace(priv, UDBG1, "STA power save state - PS, update TIM to see if it is ALIVE\n");
+                        update_tim(priv,
+                                   sta_record->aid,
+                                   CSR_WIFI_TIM_SET,
+                                   interfacePriv->InterfaceTag,
+                                   sta_record->assignedHandle);
+                    }
+                 }
+            }
+        }
+    }
+
+    /* re-run the timer interrupt */
+    mod_timer(&interfacePriv->sta_activity_check_timer,
+              (jiffies + usecs_to_jiffies(STA_INACTIVE_DETECTION_TIMER_INTERVAL * 1000 * 1000)));
+
+}
+
+
+void uf_send_disconnected_ind_wq(struct work_struct *work)
+{
+
+    CsrWifiRouterCtrlStaInfo_t *staInfo = container_of(work, CsrWifiRouterCtrlStaInfo_t, send_disconnected_ind_task);
+    unifi_priv_t *priv;
+    CsrUint16 interfaceTag;
+    struct list_head send_cfm_list;
+    CsrUint8 j;
+
+    func_enter();
+
+    if(!staInfo) {
+        return;
+    }
+
+    if(!staInfo->interfacePriv) {
+        return;
+    }
+
+    priv = staInfo->interfacePriv->privPtr;
+    interfaceTag =  staInfo->interfacePriv->InterfaceTag;
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "uf_send_disconnected_ind_wq: invalid interfaceTag\n");
+        return;
+    }
+
+    /* The SME/NME may be waiting for confirmation for requested frames to this station.
+     * So loop through buffered frames for this station and if confirmation is
+     * requested, send auto confirmation with failure status. Also flush the frames so
+     * that these are not processed again in PEER_DEL_REQ handler.
+     */
+    INIT_LIST_HEAD(&send_cfm_list);
+
+    uf_prepare_send_cfm_list_for_queued_pkts(priv,
+                                             &send_cfm_list,
+                                             &(staInfo->mgtFrames));
+
+    uf_flush_list(priv, &(staInfo->mgtFrames));
+
+    for(j = 0; j < MAX_ACCESS_CATOGORY; j++){
+        uf_prepare_send_cfm_list_for_queued_pkts(priv,
+                                                 &send_cfm_list,
+                                                 &(staInfo->dataPdu[j]));
+
+        uf_flush_list(priv,&(staInfo->dataPdu[j]));
+    }
+
+    send_auto_ma_packet_confirm(priv, staInfo->interfacePriv, &send_cfm_list);
+
+    unifi_warning(priv, "uf_send_disconnected_ind_wq: Router Disconnected IND Peer (%x-%x-%x-%x-%x-%x)\n",
+                staInfo->peerMacAddress.a[0],
+                staInfo->peerMacAddress.a[1],
+                staInfo->peerMacAddress.a[2],
+                staInfo->peerMacAddress.a[3],
+                staInfo->peerMacAddress.a[4],
+                staInfo->peerMacAddress.a[5]);
+
+    CsrWifiRouterCtrlConnectedIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,
+                                      0,
+                                      staInfo->interfacePriv->InterfaceTag,
+                                      staInfo->peerMacAddress,
+                                      CSR_WIFI_ROUTER_CTRL_PEER_DISCONNECTED);
+
+
+    return;
+}
+
+
+#endif
+void CsrWifiRouterCtrlPeerAddReqHandler(void* drvpriv,CsrWifiFsmEvent* msg)
+{
+    CsrWifiRouterCtrlPeerAddReq* req = (CsrWifiRouterCtrlPeerAddReq*)msg;
+    CsrResult status = CSR_RESULT_SUCCESS;
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrUint32 handle = 0;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[req->interfaceTag];
+
+    unifi_trace(priv, UDBG2, "entering CsrWifiRouterCtrlPeerAddReqHandler \n");
+    if (priv == NULL)
+    {
+        unifi_error(priv, "CsrWifiRouterCtrlPeerAddReqHandler: invalid smepriv\n");
+        return;
+    }
+
+    if (req->interfaceTag >= CSR_WIFI_NUM_INTERFACES)
+    {
+        unifi_error(priv, "CsrWifiRouterCtrlPeerAddReqHandler: bad interfaceTag\n");
+        return;
+    }
+
+    switch(interfacePriv->interfaceMode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_IBSS:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+            /* Add station record */
+            status = peer_add_new_record(priv,req,&handle);
+            break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_STA:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI:
+        default:
+            /* No station record to maintain in these modes */
+            break;
+    }
+
+    CsrWifiRouterCtrlPeerAddCfmSend(msg->source,req->clientData,req->interfaceTag,req->peerMacAddress,handle,status);
+    unifi_trace(priv, UDBG2, "leaving CsrWifiRouterCtrlPeerAddReqHandler \n");
+}
+
+void CsrWifiRouterCtrlPeerUpdateReqHandler(void* drvpriv,CsrWifiFsmEvent* msg)
+{
+    CsrWifiRouterCtrlPeerUpdateReq* req = (CsrWifiRouterCtrlPeerUpdateReq*)msg;
+    CsrResult status = CSR_RESULT_SUCCESS;
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+
+    unifi_trace(priv, UDBG2, "entering CsrWifiRouterCtrlPeerUpdateReqHandler \n");
+    if (priv == NULL)
+    {
+        unifi_error(priv, "CsrWifiRouterCtrlPeerUpdateReqHandler: invalid smepriv\n");
+        return;
+    }
+
+    CsrWifiRouterCtrlPeerUpdateCfmSend(msg->source,req->clientData,req->interfaceTag,status);
+    unifi_trace(priv, UDBG2, "leaving CsrWifiRouterCtrlPeerUpdateReqHandler \n");
+}
+
+
+ void CsrWifiRouterCtrlRawSdioDeinitialiseReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    /* This will never be called as it is intercepted in the Userspace */
+}
+
+void CsrWifiRouterCtrlRawSdioInitialiseReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    /* This will never be called as it is intercepted in the Userspace */
+}
+
+void
+uf_send_ba_err_wq(struct work_struct *work)
+{
+    ba_session_rx_struct *ba_session = container_of(work, ba_session_rx_struct, send_ba_err_task);
+    unifi_priv_t *priv;
+
+    if(!ba_session) {
+        return;
+    }
+
+    if(!ba_session->interfacePriv) {
+        return;
+    }
+
+    priv = ba_session->interfacePriv->privPtr;
+
+    if (ba_session->interfacePriv->InterfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "%s: invalid interfaceTag\n", __FUNCTION__);
+        return;
+    }
+
+    unifi_warning(priv, "%s: Calling CsrWifiRouterCtrlBlockAckErrorIndSend(%d, %d, %d, %d, %x:%x:%x:%x:%x:%x, %d)\n",
+                    __FUNCTION__,
+                    priv->CSR_WIFI_SME_IFACEQUEUE,
+                    0,
+                    ba_session->interfacePriv->InterfaceTag,
+                    ba_session->tID,
+                    ba_session->macAddress.a[0],
+                    ba_session->macAddress.a[1],
+                    ba_session->macAddress.a[2],
+                    ba_session->macAddress.a[3],
+                    ba_session->macAddress.a[4],
+                    ba_session->macAddress.a[5],
+                    CSR_RESULT_SUCCESS
+                 );
+    CsrWifiRouterCtrlBlockAckErrorIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,
+                    0,
+                    ba_session->interfacePriv->InterfaceTag,
+                    ba_session->tID,
+                    ba_session->macAddress,
+                    CSR_RESULT_SUCCESS);
+}
+
+
+static void ba_session_terminate_timer_func(unsigned long data)
+{
+    ba_session_rx_struct *ba_session = (ba_session_rx_struct*)data;
+    struct unifi_priv *priv;
+
+    if(!ba_session) {
+        return;
+    }
+
+    if(!ba_session->interfacePriv) {
+        return;
+    }
+
+    priv = ba_session->interfacePriv->privPtr;
+
+    if (ba_session->interfacePriv->InterfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "%s: invalid interfaceTag\n", __FUNCTION__);
+        return;
+    }
+
+    queue_work(priv->unifi_workqueue, &ba_session->send_ba_err_task);
+}
+
+
+CsrBool blockack_session_stop(unifi_priv_t *priv,
+                                     CsrUint16 interfaceTag,
+                                     CsrWifiRouterCtrlBlockAckRole role,
+                                     CsrUint16 tID,
+                                     CsrWifiMacAddress macAddress)
+{
+    netInterface_priv_t *interfacePriv;
+    ba_session_rx_struct *ba_session_rx = NULL;
+    ba_session_tx_struct *ba_session_tx = NULL;
+    CsrUint8 ba_session_idx = 0;
+    int i;
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "%s: bad interfaceTag = %d\n", __FUNCTION__, interfaceTag);
+        return FALSE;
+    }
+
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if(!interfacePriv) {
+        unifi_error(priv, "%s: bad interfacePriv\n", __FUNCTION__);
+        return FALSE;
+    }
+
+    if(tID > 15) {
+        unifi_error(priv, "%s: bad tID = %d\n", __FUNCTION__, tID);
+        return FALSE;
+    }
+
+    if((role != CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ORIGINATOR) &&
+        (role != CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_RECIPIENT)) {
+        unifi_error(priv, "%s: bad role = %d\n", __FUNCTION__, role);
+        return FALSE;
+        }
+
+    unifi_warning(priv, "%s: stopping ba_session for peer = %02x:%02x:%02x:%02x:%02x:%02x role = %d tID = %d\n", __FUNCTION__,
+                  macAddress.a[0], macAddress.a[1], macAddress.a[2],
+                  macAddress.a[3], macAddress.a[4], macAddress.a[5],
+                  role,
+                  tID);
+
+    /* find out the appropriate ba session (/station /tid /role) for which stop is requested */
+    if (role == CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_RECIPIENT){
+        for (ba_session_idx =0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_RX; ba_session_idx++){
+
+            ba_session_rx = interfacePriv->ba_session_rx[ba_session_idx];
+
+            if(ba_session_rx){
+                if ((!memcmp(ba_session_rx->macAddress.a, macAddress.a, ETH_ALEN)) && (ba_session_rx->tID == tID)){
+                    break;
+                }
+            }
+        }
+
+        if (!ba_session_rx || (ba_session_idx == MAX_SUPPORTED_BA_SESSIONS_RX)) {
+            unifi_error(priv, "%s: bad ba_session for Rx [tID=%d]\n", __FUNCTION__, tID);
+            return FALSE;
+        }
+
+
+        if(ba_session_rx->timeout) {
+            del_timer_sync(&ba_session_rx->timer);
+        }
+        cancel_work_sync(&ba_session_rx->send_ba_err_task);
+        for (i = 0; i < ba_session_rx->wind_size; i++) {
+            if(ba_session_rx->buffer[i].active) {
+                frame_desc_struct *frame_desc = &ba_session_rx->buffer[i];
+                unifi_net_data_free(priv, &frame_desc->bulkdata.d[0]);
+            }
+        }
+        kfree(ba_session_rx->buffer);
+
+        interfacePriv->ba_session_rx[ba_session_idx] = NULL;
+        kfree(ba_session_rx);
+    }else if (role == CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ORIGINATOR){
+        for (ba_session_idx =0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_TX; ba_session_idx++){
+        ba_session_tx = interfacePriv->ba_session_tx[ba_session_idx];
+            if(ba_session_tx){
+                if ((!memcmp(ba_session_tx->macAddress.a, macAddress.a, ETH_ALEN)) && (ba_session_tx->tID == tID)){
+                    break;
+                }
+            }
+        }
+
+        if (!ba_session_tx || (ba_session_idx == MAX_SUPPORTED_BA_SESSIONS_TX)) {
+            unifi_error(priv, "%s: bad ba_session for Tx [tID=%d]\n", __FUNCTION__, tID);
+            return FALSE;
+        }
+        interfacePriv->ba_session_tx[ba_session_idx] = NULL;
+        kfree(ba_session_tx);
+
+    }
+
+    return TRUE;
+}
+
+
+void CsrWifiRouterCtrlBlockAckDisableReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    CsrWifiRouterCtrlBlockAckDisableReq* req = (CsrWifiRouterCtrlBlockAckDisableReq*)msg;
+    CsrBool r;
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+
+    unifi_trace(priv, UDBG6, "%s: in ok\n", __FUNCTION__);
+
+    down(&priv->ba_mutex);
+    r = blockack_session_stop(priv,
+                              req->interfaceTag,
+                              req->role,
+                              req->trafficStreamID,
+                              req->macAddress);
+    up(&priv->ba_mutex);
+
+    CsrWifiRouterCtrlBlockAckDisableCfmSend(msg->source,
+                                            req->clientData,
+                                            req->interfaceTag,
+                                            r?CSR_RESULT_SUCCESS:CSR_RESULT_FAILURE);
+
+    unifi_trace(priv, UDBG6, "%s: out ok\n", __FUNCTION__);
+}
+
+
+CsrBool blockack_session_start(unifi_priv_t *priv,
+                               CsrUint16 interfaceTag,
+                               CsrUint16 tID,
+                               CsrUint16 timeout,
+                               CsrWifiRouterCtrlBlockAckRole role,
+                               CsrUint16 wind_size,
+                               CsrUint16 start_sn,
+                               CsrWifiMacAddress macAddress
+                              )
+{
+    netInterface_priv_t *interfacePriv;
+    ba_session_rx_struct *ba_session_rx = NULL;
+    ba_session_tx_struct *ba_session_tx = NULL;
+    CsrUint8 ba_session_idx = 0;
+
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "%s: bad interfaceTag = %d\n", __FUNCTION__, interfaceTag);
+        return FALSE;
+    }
+
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if(!interfacePriv) {
+        unifi_error(priv, "%s: bad interfacePriv\n", __FUNCTION__);
+        return FALSE;
+    }
+
+    if(tID > 15)
+    {
+        unifi_error(priv, "%s: bad tID=%d\n", __FUNCTION__, tID);
+        return FALSE;
+    }
+
+    if(wind_size > MAX_BA_WIND_SIZE) {
+        unifi_error(priv, "%s: bad wind_size = %d\n", __FUNCTION__, wind_size);
+        return FALSE;
+    }
+
+    if(role != CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ORIGINATOR &&
+       role != CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_RECIPIENT) {
+        unifi_error(priv, "%s: bad role = %d\n", __FUNCTION__, role);
+        return FALSE;
+    }
+
+    unifi_warning(priv, "%s: ba session with peer= (%02x:%02x:%02x:%02x:%02x:%02x)\n", __FUNCTION__,
+                  macAddress.a[0], macAddress.a[1], macAddress.a[2],
+                  macAddress.a[3], macAddress.a[4], macAddress.a[5]);
+
+    unifi_warning(priv, "%s: ba session for tID=%d timeout=%d role=%d wind_size=%d start_sn=%d\n", __FUNCTION__,
+                  tID,
+                  timeout,
+                  role,
+                  wind_size,
+                  start_sn);
+
+    /* Check if BA session exists for per station, per TID, per role or not.
+    if BA session exists update parameters and if it does not exist
+    create a new BA session */
+    if (role == CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ORIGINATOR){
+        for (ba_session_idx =0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_TX; ba_session_idx++){
+            ba_session_tx = interfacePriv->ba_session_tx[ba_session_idx];
+            if (ba_session_tx) {
+                if ((!memcmp(ba_session_tx->macAddress.a, macAddress.a, ETH_ALEN)) && (ba_session_tx->tID == tID)){
+                    unifi_warning(priv, "%s: ba_session for Tx already exists\n", __FUNCTION__);
+                    return TRUE;
+                }
+            }
+        }
+
+        /* we have to create new ba_session_tx struct */
+         ba_session_tx = NULL;
+
+        /* loop through until an empty BA session slot is there and save the session there */
+        for (ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_TX ; ba_session_idx++){
+            if (!(interfacePriv->ba_session_tx[ba_session_idx])){
+                break;
+            }
+        }
+        if (ba_session_idx == MAX_SUPPORTED_BA_SESSIONS_TX){
+            unifi_error(priv, "%s: All ba_session used for Tx, NO free session available\n", __FUNCTION__);
+            return FALSE;
+        }
+
+        /* create and populate the new BA session structure */
+        ba_session_tx = kmalloc(sizeof(ba_session_tx_struct), GFP_KERNEL);
+        if (!ba_session_tx) {
+            unifi_error(priv, "%s: kmalloc failed for ba_session_tx\n", __FUNCTION__);
+            return FALSE;
+        }
+        memset(ba_session_tx, 0, sizeof(ba_session_tx_struct));
+
+        ba_session_tx->interfacePriv = interfacePriv;
+        ba_session_tx->tID = tID;
+        ba_session_tx->macAddress = macAddress;
+
+        interfacePriv->ba_session_tx[ba_session_idx] = ba_session_tx;
+
+    } else if (role == CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_RECIPIENT){
+
+        for (ba_session_idx =0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_RX; ba_session_idx++){
+            ba_session_rx = interfacePriv->ba_session_rx[ba_session_idx];
+            if (ba_session_rx) {
+                if ((!memcmp(ba_session_rx->macAddress.a, macAddress.a, ETH_ALEN)) && (ba_session_rx->tID == tID)){
+                    unifi_warning(priv, "%s: ba_session for Rx[tID = %d] already exists\n", __FUNCTION__, tID);
+
+                    if(ba_session_rx->wind_size == wind_size &&
+                        ba_session_rx->timeout == timeout &&
+                        ba_session_rx->expected_sn == start_sn) {
+                        return TRUE;
+                    }
+
+                    if(ba_session_rx->timeout) {
+                        del_timer_sync(&ba_session_rx->timer);
+                        ba_session_rx->timeout = 0;
+                    }
+
+                    if(ba_session_rx->wind_size != wind_size) {
+                        blockack_session_stop(priv, interfaceTag, role, tID, macAddress);
+                    } else {
+                        if (timeout) {
+                            ba_session_rx->timeout = timeout;
+                            ba_session_rx->timer.function = ba_session_terminate_timer_func;
+                            ba_session_rx->timer.data = (unsigned long)ba_session_rx;
+                            init_timer(&ba_session_rx->timer);
+                            mod_timer(&ba_session_rx->timer, (jiffies + usecs_to_jiffies((ba_session_rx->timeout) * 1024)));
+                        }
+                        /*
+                         * The starting sequence number shall remain same if the BA
+                         * enable request is issued to update BA parameters only. If
+                         * it is not same, then we scroll our window to the new starting
+                         * sequence number. This could happen if the DELBA frame from
+                         * originator is lost and then we receive ADDBA frame with new SSN.
+                        */
+                        if(ba_session_rx->start_sn != start_sn) {
+                            scroll_ba_window(priv, interfacePriv, ba_session_rx, start_sn);
+                        }
+                        return TRUE;
+                    }
+                }
+            }
+        }
+
+        /* we could have a valid BA session pointer here or un-initialized
+        ba session pointer. but in any case we have to create a new session.
+        so re-initialize the ba_session pointer */
+        ba_session_rx = NULL;
+
+        /* loop through until an empty BA session slot is there and save the session there */
+        for (ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_RX ; ba_session_idx++){
+            if (!(interfacePriv->ba_session_rx[ba_session_idx])){
+                break;
+            }
+        }
+        if (ba_session_idx == MAX_SUPPORTED_BA_SESSIONS_RX){
+            unifi_error(priv, "%s: All ba_session used for Rx, NO free session available\n", __FUNCTION__);
+            return FALSE;
+        }
+
+        /* It is observed that with some devices there is a race between
+         * EAPOL exchanges and BA session establishment. This results in
+         * some EAPOL authentication packets getting stuck in BA reorder
+         * buffer and hence the conection cannot be established. To avoid
+         * this we check here if the EAPOL authentication is complete and
+         * if so then only allow the BA session to establish.
+         *
+         * It is verified that the peers normally re-establish
+         * the BA session after the initial rejection.
+         */
+        if (CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN != uf_sme_port_state(priv, macAddress.a, UF_CONTROLLED_PORT_Q, interfacePriv->InterfaceTag))
+        {
+            unifi_warning(priv, "blockack_session_start: Controlled port not opened, Reject BA request\n");
+            return FALSE;
+        }
+
+        ba_session_rx = kmalloc(sizeof(ba_session_rx_struct), GFP_KERNEL);
+        if (!ba_session_rx) {
+            unifi_error(priv, "%s: kmalloc failed for ba_session_rx\n", __FUNCTION__);
+            return FALSE;
+        }
+        memset(ba_session_rx, 0, sizeof(ba_session_rx_struct));
+
+        ba_session_rx->wind_size = wind_size;
+        ba_session_rx->start_sn = ba_session_rx->expected_sn = start_sn;
+        ba_session_rx->trigger_ba_after_ssn = FALSE;
+
+        ba_session_rx->buffer = kmalloc(ba_session_rx->wind_size*sizeof(frame_desc_struct), GFP_KERNEL);
+        if (!ba_session_rx->buffer) {
+            kfree(ba_session_rx);
+            unifi_error(priv, "%s: kmalloc failed for buffer\n", __FUNCTION__);
+            return FALSE;
+        }
+
+        memset(ba_session_rx->buffer, 0, ba_session_rx->wind_size*sizeof(frame_desc_struct));
+
+        INIT_WORK(&ba_session_rx->send_ba_err_task, uf_send_ba_err_wq);
+        if (timeout) {
+            ba_session_rx->timeout = timeout;
+            ba_session_rx->timer.function = ba_session_terminate_timer_func;
+            ba_session_rx->timer.data = (unsigned long)ba_session_rx;
+            init_timer(&ba_session_rx->timer);
+            mod_timer(&ba_session_rx->timer, (jiffies + usecs_to_jiffies((ba_session_rx->timeout) * 1024)));
+        }
+
+        ba_session_rx->interfacePriv = interfacePriv;
+        ba_session_rx->tID = tID;
+        ba_session_rx->macAddress = macAddress;
+
+        interfacePriv->ba_session_rx[ba_session_idx] = ba_session_rx;
+    }
+    return TRUE;
+}
+
+void CsrWifiRouterCtrlBlockAckEnableReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+    CsrWifiRouterCtrlBlockAckEnableReq* req = (CsrWifiRouterCtrlBlockAckEnableReq*)msg;
+    CsrBool r;
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+
+    unifi_trace(priv, UDBG6, ">>%s\n", __FUNCTION__);
+    down(&priv->ba_mutex);
+    r = blockack_session_start(priv,
+                               req->interfaceTag,
+                               req->trafficStreamID,
+                               req->timeout,
+                               req->role,
+                               req->bufferSize,
+                               req->ssn,
+                               req->macAddress
+                              );
+    up(&priv->ba_mutex);
+
+    CsrWifiRouterCtrlBlockAckEnableCfmSend(msg->source,
+                                           req->clientData,
+                                           req->interfaceTag,
+                                           r?CSR_RESULT_SUCCESS:CSR_RESULT_FAILURE);
+    unifi_trace(priv, UDBG6, "<<%s: r=%d\n", __FUNCTION__, r);
+
+}
+
+void CsrWifiRouterCtrlWapiMulticastFilterReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlWapiMulticastFilterReq* req = (CsrWifiRouterCtrlWapiMulticastFilterReq*)msg;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[req->interfaceTag];
+
+    if (CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode) {
+
+        unifi_trace(priv, UDBG6, ">>%s\n", __FUNCTION__);
+
+        unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlWapiMulticastFilterReq: req->status = %d\n", req->status);
+
+        /* status 1 - Filter on
+        * status 0 - Filter off */
+        priv->wapi_multicast_filter = req->status;
+
+        unifi_trace(priv, UDBG6, "<<%s\n", __FUNCTION__);
+    } else {
+
+    	unifi_warning(priv, "%s is NOT applicable for interface mode - %d\n", __FUNCTION__,interfacePriv->interfaceMode);
+
+    }
+#elif defined(UNIFI_DEBUG)
+    /*WAPI Disabled*/
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    unifi_error(priv,"CsrWifiRouterCtrlWapiMulticastFilterReqHandler: called when WAPI isn't enabled\n");
+#endif
+}
+
+void CsrWifiRouterCtrlWapiUnicastFilterReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlWapiUnicastFilterReq* req = (CsrWifiRouterCtrlWapiUnicastFilterReq*)msg;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[req->interfaceTag];
+
+    if (CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode) {
+
+        unifi_trace(priv, UDBG6, ">>%s\n", __FUNCTION__);
+
+        unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlWapiUnicastFilterReq: req->status= %d\n", req->status);
+
+        if ((priv->wapi_unicast_filter == 1) && (req->status == 0)) {
+            /* When we have successfully re-associated and obtained a new unicast key with keyid = 0 */
+            priv->wapi_unicast_queued_pkt_filter = 1;
+        }
+
+        /* status 1 - Filter ON
+         * status 0 - Filter OFF */
+        priv->wapi_unicast_filter = req->status;
+
+        unifi_trace(priv, UDBG6, "<<%s\n", __FUNCTION__);
+    } else {
+
+    	 unifi_warning(priv, "%s is NOT applicable for interface mode - %d\n", __FUNCTION__,interfacePriv->interfaceMode);
+
+    }
+#elif defined(UNIFI_DEBUG)
+    /*WAPI Disabled*/
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    unifi_error(priv,"CsrWifiRouterCtrlWapiUnicastFilterReqHandler: called when WAPI isn't enabled\n");
+#endif
+}
+
+void CsrWifiRouterCtrlWapiRxPktReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlWapiRxPktReq* req =  (CsrWifiRouterCtrlWapiRxPktReq*)msg;
+    int client_id, receiver_id;
+    bulk_data_param_t bulkdata;
+    CsrResult res;
+    ul_client_t *client;
+    CSR_SIGNAL signal;
+    CSR_MA_PACKET_INDICATION *pkt_ind;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[req->interfaceTag];
+
+    if (CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode) {
+
+    	unifi_trace(priv, UDBG6, ">>%s\n", __FUNCTION__);
+
+        if (priv == NULL) {
+            unifi_error(priv, "CsrWifiRouterCtrlWapiRxPktReq : invalid priv\n",__FUNCTION__);
+            return;
+        }
+
+        if (priv->smepriv == NULL) {
+             unifi_error(priv, "CsrWifiRouterCtrlWapiRxPktReq : invalid sme priv\n",__FUNCTION__);
+             return;
+        }
+
+        if (req->dataLength == 0 || req->data == NULL) {
+             unifi_error(priv, "CsrWifiRouterCtrlWapiRxPktReq: invalid request\n",__FUNCTION__);
+             return;
+        }
+
+        res = unifi_net_data_malloc(priv, &bulkdata.d[0], req->dataLength);
+        if (res != CSR_RESULT_SUCCESS) {
+             unifi_error(priv, "CsrWifiRouterCtrlWapiRxPktReq: Could not allocate net data\n",__FUNCTION__);
+             return;
+        }
+
+        /* This function is expected to be called only when the MIC has been verified by SME to be correct
+         * So reset the reception status to rx_success */
+        res = read_unpack_signal(req->signal, &signal);
+        if (res) {
+	          unifi_error(priv,"CsrWifiRouterCtrlWapiRxPktReqHandler: Received unknown or corrupted signal.\n");
+	          return;
+        }
+        pkt_ind = (CSR_MA_PACKET_INDICATION*) (&((&signal)->u).MaPacketIndication);
+        if (pkt_ind->ReceptionStatus != CSR_MICHAEL_MIC_ERROR) {
+	          unifi_error(priv,"CsrWifiRouterCtrlWapiRxPktReqHandler: Unknown signal with reception status = %d\n",pkt_ind->ReceptionStatus);
+	          return;
+        } else {
+	          unifi_trace(priv, UDBG4,"CsrWifiRouterCtrlWapiRxPktReqHandler: MIC verified , RX_SUCCESS \n",__FUNCTION__);
+	          pkt_ind->ReceptionStatus = CSR_RX_SUCCESS;
+	          write_pack(&signal, req->signal, &(req->signalLength));
+        }
+
+        memcpy((void*)bulkdata.d[0].os_data_ptr, req->data, req->dataLength);
+
+        receiver_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN((req->signal) + sizeof(CsrInt16)) & 0xFFF0;
+        client_id = (receiver_id & 0x0F00) >> UDI_SENDER_ID_SHIFT;
+
+        client = &priv->ul_clients[client_id];
+
+        if (client && client->event_hook) {
+              unifi_trace(priv, UDBG3,
+                          "CsrWifiRouterCtrlWapiRxPktReq: "
+                          "Sending signal to client %d, (s:0x%X, r:0x%X) - Signal 0x%X \n",
+                          client->client_id, client->sender_id, receiver_id,
+                          CSR_GET_UINT16_FROM_LITTLE_ENDIAN(req->signal));
+
+              client->event_hook(client, req->signal, req->signalLength, &bulkdata, UDI_TO_HOST);
+        } else {
+              unifi_trace(priv, UDBG4, "No client to give the packet to\n");
+              unifi_net_data_free(priv, &bulkdata.d[0]);
+        }
+
+        unifi_trace(priv, UDBG6, "<<%s\n", __FUNCTION__);
+    } else {
+    	unifi_warning(priv, "%s is NOT applicable for interface mode - %d\n", __FUNCTION__,interfacePriv->interfaceMode);
+    }
+#elif defined(UNIFI_DEBUG)
+    /*WAPI Disabled*/
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    unifi_error(priv,"CsrWifiRouterCtrlWapiRxPktReqHandler: called when WAPI isn't enabled\n");
+#endif
+}
+
+void CsrWifiRouterCtrlWapiUnicastTxPktReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
+
+	unifi_priv_t *priv = (unifi_priv_t*) drvpriv;
+    CsrWifiRouterCtrlWapiUnicastTxPktReq *req 	= (CsrWifiRouterCtrlWapiUnicastTxPktReq*) msg;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[req->interfaceTag];
+    bulk_data_param_t bulkdata;
+    CsrUint8 macHeaderLengthInBytes = MAC_HEADER_SIZE;
+    /*KeyID, Reserved, PN, MIC*/
+    CsrUint8 appendedCryptoFields = 1 + 1 + 16 + 16;
+    CsrResult result;
+    /* Retrieve the MA PACKET REQ fields from the Signal retained from send_ma_pkt_request() */
+    CSR_MA_PACKET_REQUEST *storedSignalMAPktReq = &interfacePriv->wapi_unicast_ma_pkt_sig.u.MaPacketRequest;
+
+    if (CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode) {
+
+        unifi_trace(priv, UDBG6, ">>%s\n", __FUNCTION__);
+
+        if (priv == NULL) {
+            unifi_error(priv, "CsrWifiRouterCtrlWapiUnicastTxPktReqHandler : invalid priv\n",__FUNCTION__);
+            return;
+        }
+        if (priv->smepriv == NULL) {
+            unifi_error(priv, "CsrWifiRouterCtrlWapiUnicastTxPktReqHandler : invalid sme priv\n",__FUNCTION__);
+            return;
+        }
+        if (req->data == NULL) {
+            unifi_error(priv, "CsrWifiRouterCtrlWapiUnicastTxPktReqHandler: invalid request\n",__FUNCTION__);
+            return;
+        } else {
+            /* If it is QoS data (type = data subtype = QoS), frame header contains QoS control field */
+            if ((req->data[0] & 0x88) == 0x88) {
+      	        macHeaderLengthInBytes  = macHeaderLengthInBytes + QOS_CONTROL_HEADER_SIZE;
+            }
+        }
+        if ( !(req->dataLength>(macHeaderLengthInBytes+appendedCryptoFields)) ) {
+            unifi_error(priv, "CsrWifiRouterCtrlWapiUnicastTxPktReqHandler: invalid dataLength\n",__FUNCTION__);
+            return;
+        }
+
+	    /* Encrypted DATA Packet contained in (req->data)
+         * -------------------------------------------------------------------
+         * |MAC Header|  KeyId   | Reserved |    PN    | xxDataxx | xxMICxxx |
+         * -------------------------------------------------------------------
+         *                                             (<-----Encrypted----->)
+         * -------------------------------------------------------------------
+         * |24/26(QoS)|    1     |    1     |    16    |    x     |    16    |
+         * -------------------------------------------------------------------
+         */
+        result = unifi_net_data_malloc(priv, &bulkdata.d[0], req->dataLength);
+        if (result != CSR_RESULT_SUCCESS) {
+             unifi_error(priv, "CsrWifiRouterCtrlWapiUnicastTxPktReqHandler: Could not allocate net data\n",__FUNCTION__);
+             return;
+        }
+        memcpy((void*)bulkdata.d[0].os_data_ptr, req->data, req->dataLength);
+        bulkdata.d[0].data_length = req->dataLength;
+        bulkdata.d[1].os_data_ptr = NULL;
+        bulkdata.d[1].data_length = 0;
+
+        /* Send UniFi msg */
+        /* Here hostTag is been sent as 0xffffffff, its been appended properly while framing MA-Packet request in pdu_processing.c file */
+        result = uf_process_ma_packet_req(priv,
+    	                                  storedSignalMAPktReq->Ra.x,
+                                          storedSignalMAPktReq->HostTag,/* Ask for a new HostTag */
+                                          req->interfaceTag,
+                                          storedSignalMAPktReq->TransmissionControl,
+                                          storedSignalMAPktReq->TransmitRate,
+                                          storedSignalMAPktReq->Priority, /* Retained value */
+                                          interfacePriv->wapi_unicast_ma_pkt_sig.SignalPrimitiveHeader.SenderProcessId, /*FIXME AP: VALIDATE ???*/
+                                          &bulkdata);
+
+        if (result == NETDEV_TX_OK) {
+             (priv->netdev[req->interfaceTag])->trans_start = jiffies;
+             /* Should really count tx stats in the UNITDATA.status signal but
+              * that doesn't have the length.
+              */
+             interfacePriv->stats.tx_packets++;
+
+             /* count only the packet payload */
+             interfacePriv->stats.tx_bytes += req->dataLength - macHeaderLengthInBytes - appendedCryptoFields;
+             unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlWapiUnicastTxPktReqHandler: (Packet Sent), sent count = %x\n", interfacePriv->stats.tx_packets);
+        } else {
+             /* Failed to send: fh queue was full, and the skb was discarded*/
+             unifi_trace(priv, UDBG1, "(HIP validation failure) Result = %d\n", result);
+             unifi_net_data_free(priv, &bulkdata.d[0]);
+
+             interfacePriv->stats.tx_dropped++;
+             unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlWapiUnicastTxPktReqHandler: (Packet Drop), dropped count = %x\n", interfacePriv->stats.tx_dropped);
+        }
+
+        unifi_trace(priv, UDBG6, "<<%s\n", __FUNCTION__);
+
+    } else {
+
+    	unifi_warning(priv, "%s is NOT applicable for interface mode - %d\n", __FUNCTION__,interfacePriv->interfaceMode);
+
+    }
+#elif defined(UNIFI_DEBUG)
+    /*WAPI Disabled*/
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    unifi_error(priv,"CsrWifiRouterCtrlWapiUnicastTxPktReqHandler: called when WAPI SW ENCRYPTION isn't enabled\n");
+#endif
+}
+
+void CsrWifiRouterCtrlWapiFilterReqHandler(void* drvpriv, CsrWifiFsmEvent* msg)
+{
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+
+#ifdef CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    CsrWifiRouterCtrlWapiFilterReq* req = (CsrWifiRouterCtrlWapiFilterReq*)msg;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[req->interfaceTag];
+
+    if (CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode) {
+
+        unifi_trace(priv, UDBG6, ">>%s\n", __FUNCTION__);
+
+        unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlWapiFilterReq: req->isWapiConnected [0/1] = %d \n",req->isWapiConnected);
+
+        priv->isWapiConnection = req->isWapiConnected;
+
+        unifi_trace(priv, UDBG6, "<<%s\n", __FUNCTION__);
+    } else {
+
+    	unifi_warning(priv, "%s is NOT applicable for interface mode - %d\n", __FUNCTION__,interfacePriv->interfaceMode);
+
+    }
+#endif
+
+#elif defined(UNIFI_DEBUG)
+    /*WAPI Disabled*/
+    unifi_priv_t *priv = (unifi_priv_t*)drvpriv;
+    unifi_error(priv,"CsrWifiRouterCtrlWapiFilterReq: called when WAPI isn't enabled\n");
+#endif
+}
diff --git a/drivers/staging/csr/sme_userspace.c b/drivers/staging/csr/sme_userspace.c
new file mode 100644
index 0000000..d87a6e3
--- /dev/null
+++ b/drivers/staging/csr/sme_userspace.c
@@ -0,0 +1,315 @@
+/*
+ *****************************************************************************
+ *
+ * FILE : sme_userspace.c
+ *
+ * PURPOSE : Support functions for userspace SME helper application.
+ *
+ *
+ * Copyright (C) 2008-2011 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ *****************************************************************************
+ */
+
+#include "unifi_priv.h"
+
+/*
+ * Fix Me..... These need to be the correct values...
+ * Dynamic from the user space.
+ */
+CsrSchedQid CSR_WIFI_ROUTER_IFACEQUEUE   = 0xFFFF;
+CsrSchedQid CSR_WIFI_SME_IFACEQUEUE      = 0xFFFF;
+#ifdef CSR_SUPPORT_WEXT_AP
+CsrSchedQid CSR_WIFI_NME_IFACEQUEUE      = 0xFFFF;
+#endif
+int
+uf_sme_init(unifi_priv_t *priv)
+{
+    int i, j;
+
+    CsrWifiRouterTransportInit(priv);
+
+    priv->smepriv = priv;
+
+    init_waitqueue_head(&priv->sme_request_wq);
+
+    priv->filter_tclas_ies = NULL;
+    memset(&priv->packet_filters, 0, sizeof(uf_cfg_bcast_packet_filter_t));
+
+#ifdef CSR_SUPPORT_WEXT
+    priv->ignore_bssid_join = FALSE;
+    priv->mib_data.length = 0;
+
+    uf_sme_wext_set_defaults(priv);
+#endif /* CSR_SUPPORT_WEXT*/
+
+    priv->sta_ip_address = 0xFFFFFFFF;
+
+    priv->wifi_on_state = wifi_on_unspecified;
+
+    sema_init(&priv->sme_sem, 1);
+    memset(&priv->sme_reply, 0, sizeof(sme_reply_t));
+
+    priv->ta_ind_work.in_use = 0;
+    priv->ta_sample_ind_work.in_use = 0;
+
+    priv->CSR_WIFI_SME_IFACEQUEUE = 0xFFFF;
+
+    for (i = 0; i < MAX_MA_UNIDATA_IND_FILTERS; i++) {
+        priv->sme_unidata_ind_filters[i].in_use = 0;
+    }
+
+    /* Create a work queue item for Traffic Analysis indications to SME */
+    INIT_WORK(&priv->ta_ind_work.task, uf_ta_ind_wq);
+    INIT_WORK(&priv->ta_sample_ind_work.task, uf_ta_sample_ind_wq);
+#ifdef CSR_SUPPORT_WEXT
+    INIT_WORK(&priv->sme_config_task, uf_sme_config_wq);
+#endif
+
+    for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) {
+        netInterface_priv_t *interfacePriv = priv->interfacePriv[i];
+        interfacePriv->m4_sent = FALSE;
+        interfacePriv->m4_bulk_data.net_buf_length = 0;
+        interfacePriv->m4_bulk_data.data_length = 0;
+        interfacePriv->m4_bulk_data.os_data_ptr = interfacePriv->m4_bulk_data.os_net_buf_ptr = NULL;
+
+        memset(&interfacePriv->controlled_data_port, 0, sizeof(unifi_port_config_t));
+        interfacePriv->controlled_data_port.entries_in_use = 1;
+        interfacePriv->controlled_data_port.port_cfg[0].in_use = TRUE;
+        interfacePriv->controlled_data_port.port_cfg[0].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
+        interfacePriv->controlled_data_port.overide_action = UF_DATA_PORT_OVERIDE;
+
+        memset(&interfacePriv->uncontrolled_data_port, 0, sizeof(unifi_port_config_t));
+        interfacePriv->uncontrolled_data_port.entries_in_use = 1;
+        interfacePriv->uncontrolled_data_port.port_cfg[0].in_use = TRUE;
+        interfacePriv->uncontrolled_data_port.port_cfg[0].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
+        interfacePriv->uncontrolled_data_port.overide_action = UF_DATA_PORT_OVERIDE;
+
+        /* Mark the remainder of the port config table as unallocated */
+        for(j = 1; j < UNIFI_MAX_CONNECTIONS; j++) {
+            interfacePriv->controlled_data_port.port_cfg[j].in_use = FALSE;
+            interfacePriv->controlled_data_port.port_cfg[j].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
+
+            interfacePriv->uncontrolled_data_port.port_cfg[j].in_use = FALSE;
+            interfacePriv->uncontrolled_data_port.port_cfg[j].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
+        }
+
+        /* intializing the lists */
+        INIT_LIST_HEAD(&interfacePriv->genericMgtFrames);
+        INIT_LIST_HEAD(&interfacePriv->genericMulticastOrBroadCastMgtFrames);
+        INIT_LIST_HEAD(&interfacePriv->genericMulticastOrBroadCastFrames);
+
+        for(j = 0; j < UNIFI_MAX_CONNECTIONS; j++) {
+            interfacePriv->staInfo[j] = NULL;
+        }
+
+        interfacePriv->num_stations_joined = 0;
+        interfacePriv->sta_activity_check_enabled = FALSE;
+    }
+
+
+    return 0;
+} /* uf_sme_init() */
+
+
+void
+uf_sme_deinit(unifi_priv_t *priv)
+{
+    int i,j;
+    CsrUint8 ba_session_idx;
+    ba_session_rx_struct *ba_session_rx = NULL;
+    ba_session_tx_struct *ba_session_tx = NULL;
+    CsrWifiRouterCtrlStaInfo_t *staInfo = NULL;
+    netInterface_priv_t *interfacePriv = NULL;
+
+    /* Free any TCLASs previously allocated */
+    if (priv->packet_filters.tclas_ies_length) {
+        priv->packet_filters.tclas_ies_length = 0;
+        CsrPmemFree(priv->filter_tclas_ies);
+        priv->filter_tclas_ies = NULL;
+    }
+
+    for (i = 0; i < MAX_MA_UNIDATA_IND_FILTERS; i++) {
+        priv->sme_unidata_ind_filters[i].in_use = 0;
+    }
+
+    /* Remove all the Peer database, before going down */
+    for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) {
+        down(&priv->ba_mutex);
+        for(ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_RX; ba_session_idx++){
+            ba_session_rx = priv->interfacePriv[i]->ba_session_rx[ba_session_idx];
+            if(ba_session_rx) {
+                blockack_session_stop(priv,
+                                    i,
+                                    CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_RECIPIENT,
+                                    ba_session_rx->tID,
+                                    ba_session_rx->macAddress);
+            }
+        }
+        for(ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_TX; ba_session_idx++){
+            ba_session_tx = priv->interfacePriv[i]->ba_session_tx[ba_session_idx];
+            if(ba_session_tx) {
+                blockack_session_stop(priv,
+                                    i,
+                                    CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ORIGINATOR,
+                                    ba_session_tx->tID,
+                                    ba_session_tx->macAddress);
+            }
+        }
+
+        up(&priv->ba_mutex);
+        interfacePriv = priv->interfacePriv[i];
+        if(interfacePriv){
+            for(j = 0; j < UNIFI_MAX_CONNECTIONS; j++) {
+                if ((staInfo=interfacePriv->staInfo[j]) != NULL) {
+                    /* Clear the STA activity parameters before freeing station Record */
+                    unifi_trace(priv, UDBG1, "uf_sme_deinit: Canceling work queue for STA with AID: %d\n", staInfo->aid);
+                    cancel_work_sync(&staInfo->send_disconnected_ind_task);
+                    staInfo->nullDataHostTag = INVALID_HOST_TAG;
+                }
+            }
+            if (interfacePriv->sta_activity_check_enabled){
+                interfacePriv->sta_activity_check_enabled = FALSE;
+                del_timer_sync(&interfacePriv->sta_activity_check_timer);
+            }
+        }
+        CsrWifiRouterCtrlInterfaceReset(priv, i);
+        priv->interfacePriv[i]->interfaceMode = CSR_WIFI_ROUTER_CTRL_MODE_NONE;
+    }
+
+
+} /* uf_sme_deinit() */
+
+
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_ta_indicate_protocol
+ *
+ *      Report that a packet of a particular type has been seen
+ *
+ *  Arguments:
+ *      drv_priv        The device context pointer passed to ta_init.
+ *      protocol        The protocol type enum value.
+ *      direction       Whether the packet was a tx or rx.
+ *      src_addr        The source MAC address from the data packet.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *      We defer the actual sending to a background workqueue,
+ *      see uf_ta_ind_wq().
+ * ---------------------------------------------------------------------------
+ */
+void
+unifi_ta_indicate_protocol(void *ospriv,
+                           CsrWifiRouterCtrlTrafficPacketType packet_type,
+                           CsrWifiRouterCtrlProtocolDirection direction,
+                           const CsrWifiMacAddress *src_addr)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+
+    if (priv->ta_ind_work.in_use) {
+        unifi_warning(priv,
+                "unifi_ta_indicate_protocol: workqueue item still in use, not sending\n");
+        return;
+    }
+
+    if (CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_RX == direction)
+    {
+        CsrUint16 interfaceTag = 0;
+        CsrWifiRouterCtrlTrafficProtocolIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,
+                interfaceTag,
+                packet_type,
+                direction,
+                *src_addr);
+    }
+    else
+    {
+        priv->ta_ind_work.packet_type = packet_type;
+        priv->ta_ind_work.direction = direction;
+        priv->ta_ind_work.src_addr = *src_addr;
+
+        queue_work(priv->unifi_workqueue, &priv->ta_ind_work.task);
+    }
+
+} /* unifi_ta_indicate_protocol() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * unifi_ta_indicate_sampling
+ *
+ *      Send the TA sampling information to the SME.
+ *
+ *  Arguments:
+ *      drv_priv        The device context pointer passed to ta_init.
+ *      stats   The TA sampling data to send.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+unifi_ta_indicate_sampling(void *ospriv, CsrWifiRouterCtrlTrafficStats *stats)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+
+    if (!priv) {
+        return;
+    }
+
+    if (priv->ta_sample_ind_work.in_use) {
+        unifi_warning(priv,
+                     "unifi_ta_indicate_sampling: workqueue item still in use, not sending\n");
+        return;
+    }
+
+    priv->ta_sample_ind_work.stats = *stats;
+
+    queue_work(priv->unifi_workqueue, &priv->ta_sample_ind_work.task);
+
+} /* unifi_ta_indicate_sampling() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * unifi_ta_indicate_l4stats
+ *
+ *      Send the TA TCP/UDP throughput information to the driver.
+ *
+ *  Arguments:
+ *    drv_priv        The device context pointer passed to ta_init.
+ *    rxTcpThroughput TCP RX throughput in KiloBytes
+ *    txTcpThroughput TCP TX throughput in KiloBytes
+ *    rxUdpThroughput UDP RX throughput in KiloBytes
+ *    txUdpThroughput UDP TX throughput in KiloBytes
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+unifi_ta_indicate_l4stats(void *ospriv,
+                          CsrUint32 rxTcpThroughput,
+                          CsrUint32 txTcpThroughput,
+                          CsrUint32 rxUdpThroughput,
+                          CsrUint32 txUdpThroughput)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+
+    if (!priv) {
+        return;
+    }
+    /* Save the info. The actual action will be taken in unifi_ta_indicate_sampling() */
+    priv->rxTcpThroughput = rxTcpThroughput;
+    priv->txTcpThroughput = txTcpThroughput;
+    priv->rxUdpThroughput = rxUdpThroughput;
+    priv->txUdpThroughput = txUdpThroughput;
+} /* unifi_ta_indicate_l4stats() */
diff --git a/drivers/staging/csr/sme_userspace.h b/drivers/staging/csr/sme_userspace.h
new file mode 100644
index 0000000..19f484f
--- /dev/null
+++ b/drivers/staging/csr/sme_userspace.h
@@ -0,0 +1,38 @@
+/*
+ * ***************************************************************************
+ *  FILE:     sme_userspace.h
+ *
+ *  PURPOSE:    SME related definitions.
+ *
+ *  Copyright (C) 2007-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ***************************************************************************
+ */
+#ifndef __LINUX_SME_USERSPACE_H__
+#define __LINUX_SME_USERSPACE_H__ 1
+
+#include <linux/kernel.h>
+
+int uf_sme_init(unifi_priv_t *priv);
+void uf_sme_deinit(unifi_priv_t *priv);
+int uf_sme_queue_message(unifi_priv_t *priv, u8 *buffer, int length);
+
+
+#include "csr_wifi_router_lib.h"
+#include "csr_wifi_router_sef.h"
+#include "csr_wifi_router_ctrl_lib.h"
+#include "csr_wifi_router_ctrl_sef.h"
+#include "csr_wifi_sme_task.h"
+#ifdef CSR_SUPPORT_WEXT_AP
+#include "csr_wifi_nme_ap_lib.h"
+#endif
+#include "csr_wifi_sme_lib.h"
+
+void CsrWifiRouterTransportInit(unifi_priv_t *priv);
+void CsrWifiRouterTransportRecv(unifi_priv_t *priv, CsrUint8* buffer, CsrSize bufferLength);
+void CsrWifiRouterTransportDeInit(unifi_priv_t *priv);
+
+#endif /* __LINUX_SME_USERSPACE_H__ */
diff --git a/drivers/staging/csr/sme_wext.c b/drivers/staging/csr/sme_wext.c
new file mode 100644
index 0000000..3ba7b4c
--- /dev/null
+++ b/drivers/staging/csr/sme_wext.c
@@ -0,0 +1,3396 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     sme_wext.c
+ *
+ * PURPOSE:
+ *      Handlers for ioctls from iwconfig.
+ *      These provide the control plane operations.
+ *
+ * Copyright (C) 2007-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include "unifi_priv.h"
+#include <linux/rtnetlink.h>
+
+#define CHECK_INITED(_priv)                             \
+    do {                                                    \
+        if (_priv->init_progress != UNIFI_INIT_COMPLETED) { \
+            unifi_trace(_priv, UDBG2, "%s unifi not ready, failing wext call\n", __FUNCTION__); \
+            return -ENODEV;                                 \
+        }                                                   \
+    } while (0)
+
+/* Workaround for the wpa_supplicant hanging issue - disabled on Android */
+#ifndef ANDROID_BUILD
+#define CSR_WIFI_WEXT_HANG_WORKAROUND
+#endif
+
+#ifdef CSR_WIFI_WEXT_HANG_WORKAROUND
+# define UF_RTNL_LOCK()    rtnl_lock()
+# define UF_RTNL_UNLOCK()  rtnl_unlock()
+#else
+# define UF_RTNL_LOCK()
+# define UF_RTNL_UNLOCK()
+#endif
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *      Helper functions
+ * ---------------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  wext_freq_to_channel
+ *  channel_to_mhz
+ *
+ *      These functions convert between channel number and frequency.
+ *
+ *  Arguments:
+ *      ch      Channel number, as defined in 802.11 specs
+ *      m, e    Mantissa and exponent as provided by wireless extension.
+ *
+ *  Returns:
+ *      channel or frequency (in MHz) value
+ * ---------------------------------------------------------------------------
+ */
+static int
+wext_freq_to_channel(int m, int e)
+{
+    int mhz;
+
+    mhz = m;
+    while (e < 6) {
+        mhz /= 10;
+        e++;
+    }
+    while (e > 6) {
+        mhz *= 10;
+        e--;
+    }
+
+    if (mhz >= 5000) {
+        return ((mhz - 5000) / 5);
+    }
+
+    if (mhz == 2482) {
+        return 14;
+    }
+
+    if (mhz >= 2407) {
+        return ((mhz - 2407) / 5);
+    }
+
+    return 0;
+} /* wext_freq_to_channel() */
+
+static int
+channel_to_mhz(int ch, int dot11a)
+{
+
+    if (ch == 0) return 0;
+    if (ch > 200) return 0;
+
+    /* 5G */
+    if (dot11a) {
+        return (5000 + (5 * ch));
+    }
+
+    /* 2.4G */
+    if (ch == 14) {
+        return 2484;
+    }
+
+    if ((ch < 14) && (ch > 0)) {
+        return (2407 + (5 * ch));
+    }
+
+    return 0;
+}
+#ifdef CSR_SUPPORT_WEXT_AP
+void uf_sme_wext_ap_set_defaults(unifi_priv_t *priv)
+{
+    memcpy(priv->ap_config.ssid.ssid,"defaultssid",sizeof("defaultssid"));
+
+    priv->ap_config.ssid.length = 8;
+    priv->ap_config.channel = 6;
+    priv->ap_config.if_index = 1;
+    priv->ap_config.credentials.authType = 0;
+    priv->ap_config.max_connections=8;
+
+    priv->group_sec_config.apGroupkeyTimeout = 0;
+    priv->group_sec_config.apStrictGtkRekey = 0;
+    priv->group_sec_config.apGmkTimeout = 0;
+    priv->group_sec_config.apResponseTimeout = 100; /* Default*/
+    priv->group_sec_config.apRetransLimit = 3; /* Default*/
+    /* Set default params even if they may not be used*/
+    /* Until Here*/
+
+    priv->ap_mac_config.preamble = CSR_WIFI_SME_USE_LONG_PREAMBLE;
+    priv->ap_mac_config.shortSlotTimeEnabled = FALSE;
+    priv->ap_mac_config.ctsProtectionType=CSR_WIFI_SME_CTS_PROTECTION_AUTOMATIC;
+
+    priv->ap_mac_config.wmmEnabled = TRUE;
+    priv->ap_mac_config.wmmApParams[0].cwMin=4;
+    priv->ap_mac_config.wmmApParams[0].cwMax=10;
+    priv->ap_mac_config.wmmApParams[0].aifs=3;
+    priv->ap_mac_config.wmmApParams[0].txopLimit=0;
+    priv->ap_mac_config.wmmApParams[0].admissionControlMandatory=FALSE;
+    priv->ap_mac_config.wmmApParams[1].cwMin=4;
+    priv->ap_mac_config.wmmApParams[1].cwMax=10;
+    priv->ap_mac_config.wmmApParams[1].aifs=7;
+    priv->ap_mac_config.wmmApParams[1].txopLimit=0;
+    priv->ap_mac_config.wmmApParams[1].admissionControlMandatory=FALSE;
+    priv->ap_mac_config.wmmApParams[2].cwMin=3;
+    priv->ap_mac_config.wmmApParams[2].cwMax=4;
+    priv->ap_mac_config.wmmApParams[2].aifs=1;
+    priv->ap_mac_config.wmmApParams[2].txopLimit=94;
+    priv->ap_mac_config.wmmApParams[2].admissionControlMandatory=FALSE;
+    priv->ap_mac_config.wmmApParams[3].cwMin=2;
+    priv->ap_mac_config.wmmApParams[3].cwMax=3;
+    priv->ap_mac_config.wmmApParams[3].aifs=1;
+    priv->ap_mac_config.wmmApParams[3].txopLimit=47;
+    priv->ap_mac_config.wmmApParams[3].admissionControlMandatory=FALSE;
+
+    priv->ap_mac_config.wmmApBcParams[0].cwMin=4;
+    priv->ap_mac_config.wmmApBcParams[0].cwMax=10;
+    priv->ap_mac_config.wmmApBcParams[0].aifs=3;
+    priv->ap_mac_config.wmmApBcParams[0].txopLimit=0;
+    priv->ap_mac_config.wmmApBcParams[0].admissionControlMandatory=FALSE;
+    priv->ap_mac_config.wmmApBcParams[1].cwMin=4;
+    priv->ap_mac_config.wmmApBcParams[1].cwMax=10;
+    priv->ap_mac_config.wmmApBcParams[1].aifs=7;
+    priv->ap_mac_config.wmmApBcParams[1].txopLimit=0;
+    priv->ap_mac_config.wmmApBcParams[1].admissionControlMandatory=FALSE;
+    priv->ap_mac_config.wmmApBcParams[2].cwMin=3;
+    priv->ap_mac_config.wmmApBcParams[2].cwMax=4;
+    priv->ap_mac_config.wmmApBcParams[2].aifs=2;
+    priv->ap_mac_config.wmmApBcParams[2].txopLimit=94;
+    priv->ap_mac_config.wmmApBcParams[2].admissionControlMandatory=FALSE;
+    priv->ap_mac_config.wmmApBcParams[3].cwMin=2;
+    priv->ap_mac_config.wmmApBcParams[3].cwMax=3;
+    priv->ap_mac_config.wmmApBcParams[3].aifs=2;
+    priv->ap_mac_config.wmmApBcParams[3].txopLimit=47;
+    priv->ap_mac_config.wmmApBcParams[3].admissionControlMandatory=FALSE;
+
+    priv->ap_mac_config.accessType=CSR_WIFI_AP_ACCESS_TYPE_NONE;
+    priv->ap_mac_config.macAddressListCount=0;
+    priv->ap_mac_config.macAddressList=NULL;
+
+    priv->ap_mac_config.apHtParams.rxStbc=1;
+    priv->ap_mac_config.apHtParams.rifsModeAllowed=TRUE;
+    priv->ap_mac_config.apHtParams.greenfieldSupported=FALSE;
+    priv->ap_mac_config.apHtParams.shortGi20MHz=TRUE;
+    priv->ap_mac_config.apHtParams.htProtection=0;
+    priv->ap_mac_config.apHtParams.dualCtsProtection=FALSE;
+
+    priv->ap_mac_config.phySupportedBitmap =
+            (CSR_WIFI_SME_AP_PHY_SUPPORT_B|CSR_WIFI_SME_AP_PHY_SUPPORT_G|CSR_WIFI_SME_AP_PHY_SUPPORT_N);
+    priv->ap_mac_config.beaconInterval= 100;
+    priv->ap_mac_config.dtimPeriod=3;
+    priv->ap_mac_config.maxListenInterval=0x00ff;/* Set it to a large value
+                                                    to enable different types of
+                                                    devices to join us */
+    priv->ap_mac_config.supportedRatesCount =
+           uf_configure_supported_rates(priv->ap_mac_config.supportedRates,priv->ap_mac_config.phySupportedBitmap);
+}
+#endif
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_sme_wext_set_defaults
+ *
+ *      Set up power-on defaults for driver config.
+ *
+ *      Note: The SME Management API *cannot* be used in this function.
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+uf_sme_wext_set_defaults(unifi_priv_t *priv)
+{
+    memset(&priv->connection_config, 0, sizeof(CsrWifiSmeConnectionConfig));
+
+    priv->connection_config.bssType = CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE;
+    priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN;
+    priv->connection_config.encryptionModeMask = CSR_WIFI_SME_ENCRYPTION_CIPHER_NONE;
+    priv->connection_config.privacyMode = CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED;
+    priv->connection_config.wmmQosInfo = 0xFF;
+    priv->connection_config.ifIndex = CSR_WIFI_SME_RADIO_IF_BOTH;
+    priv->connection_config.adhocJoinOnly = FALSE;
+    priv->connection_config.adhocChannel = 6;
+
+    priv->wep_tx_key_index = 0;
+
+    priv->wext_wireless_stats.qual.qual = 0;
+    priv->wext_wireless_stats.qual.level = 0;
+    priv->wext_wireless_stats.qual.noise = 0;
+    priv->wext_wireless_stats.qual.updated = 0x70;
+#ifdef CSR_SUPPORT_WEXT_AP
+    /* Initialize the default configuration for AP */
+    uf_sme_wext_ap_set_defaults(priv);
+#endif
+
+
+} /* uf_sme_wext_set_defaults() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *      WEXT methods
+ * ---------------------------------------------------------------------------
+ */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_giwname   - handler for SIOCGIWNAME
+ *  unifi_siwfreq   - handler for SIOCSIWFREQ
+ *  unifi_giwfreq   - handler for SIOCGIWFREQ
+ *  unifi_siwmode   - handler for SIOCSIWMODE
+ *  unifi_giwmode   - handler for SIOCGIWMODE
+ *  unifi_giwrange  - handler for SIOCGIWRANGE
+ *  unifi_siwap     - handler for SIOCSIWAP
+ *  unifi_giwap     - handler for SIOCGIWAP
+ *  unifi_siwscan   - handler for SIOCSIWSCAN
+ *  unifi_giwscan   - handler for SIOCGIWSCAN
+ *  unifi_siwessid  - handler for SIOCSIWESSID
+ *  unifi_giwessid  - handler for SIOCGIWESSID
+ *  unifi_siwencode - handler for SIOCSIWENCODE
+ *  unifi_giwencode - handler for SIOCGIWENCODE
+ *
+ *      Handler functions for IW extensions.
+ *      These are registered via the unifi_iw_handler_def struct below
+ *      and called by the generic IW driver support code.
+ *      See include/net/iw_handler.h.
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static int
+iwprivsdefs(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    int r;
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    CsrWifiSmeMibConfig mibConfig;
+    CsrWifiSmePowerConfig powerConfig;
+
+    unifi_trace(priv, UDBG1, "iwprivs80211defaults: reload defaults\n");
+
+    uf_sme_wext_set_defaults(priv);
+
+    /* Get, modify and set the MIB data */
+    r = sme_mgt_mib_config_get(priv, &mibConfig);
+    if (r) {
+        unifi_error(priv, "iwprivs80211defaults: Get CsrWifiSmeMibConfigValue failed.\n");
+        return r;
+    }
+    mibConfig.dot11RtsThreshold = 2347;
+    mibConfig.dot11FragmentationThreshold = 2346;
+    r = sme_mgt_mib_config_set(priv, &mibConfig);
+    if (r) {
+        unifi_error(priv, "iwprivs80211defaults: Set CsrWifiSmeMibConfigValue failed.\n");
+        return r;
+    }
+
+    powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW;
+    powerConfig.listenIntervalTu = 100;
+    powerConfig.rxDtims = 1;
+
+    r = sme_mgt_power_config_set(priv, &powerConfig);
+    if (r) {
+        unifi_error(priv, "iwprivs80211defaults: Set unifi_PowerConfigValue failed.\n");
+        return r;
+    }
+
+    return 0;
+} /* iwprivsdefs() */
+
+static int
+iwprivs80211ps(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    int r = 0;
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+
+    int ps_mode = (int)(*extra);
+    CsrWifiSmePowerConfig powerConfig;
+
+    unifi_trace(priv, UDBG1, "iwprivs80211ps: power save mode = %d\n", ps_mode);
+
+    r = sme_mgt_power_config_get(priv, &powerConfig);
+    if (r) {
+        unifi_error(priv, "iwprivs80211ps: Get unifi_PowerConfigValue failed.\n");
+        return r;
+    }
+
+    switch (ps_mode) {
+        case CSR_PMM_ACTIVE_MODE:
+            powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW;
+            break;
+        case CSR_PMM_POWER_SAVE:
+            powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH;
+            break;
+        case CSR_PMM_FAST_POWER_SAVE:
+            powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_MED;
+            break;
+        default:
+            powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_AUTO;
+            break;
+    }
+
+    r = sme_mgt_power_config_set(priv, &powerConfig);
+    if (r) {
+        unifi_error(priv, "iwprivs80211ps: Set unifi_PowerConfigValue failed.\n");
+    }
+
+    return r;
+}
+
+static int
+iwprivg80211ps(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+
+    CsrWifiSmePowerConfig powerConfig;
+    int r;
+
+    r = sme_mgt_power_config_get(priv, &powerConfig);
+    if (r) {
+        unifi_error(priv, "iwprivg80211ps: Get 802.11 power mode failed.\n");
+        return r;
+    }
+
+    switch (powerConfig.powerSaveLevel) {
+        case CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW:
+            snprintf(extra, IWPRIV_POWER_SAVE_MAX_STRING,
+                     "Power save mode: %d (Active)",
+                     powerConfig.powerSaveLevel);
+            break;
+        case CSR_WIFI_SME_POWER_SAVE_LEVEL_MED:
+            snprintf(extra, IWPRIV_POWER_SAVE_MAX_STRING,
+                     "Power save mode: %d (Fast)",
+                     powerConfig.powerSaveLevel);
+            break;
+        case CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH:
+            snprintf(extra, IWPRIV_POWER_SAVE_MAX_STRING,
+                     "Power save mode: %d (Full)",
+                     powerConfig.powerSaveLevel);
+            break;
+        case CSR_WIFI_SME_POWER_SAVE_LEVEL_AUTO:
+            snprintf(extra, IWPRIV_POWER_SAVE_MAX_STRING,
+                     "Power save mode: %d (Auto)",
+                     powerConfig.powerSaveLevel);
+            break;
+        default:
+            snprintf(extra, IWPRIV_POWER_SAVE_MAX_STRING,
+                     "Power save mode: %d (Unknown)",
+                     powerConfig.powerSaveLevel);
+            break;
+    }
+
+    wrqu->data.length = strlen(extra) + 1;
+
+    return 0;
+}
+
+static int
+iwprivssmedebug(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    /* No longer supported on the API */
+#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE)
+    unifi_debug_buf_dump();
+#endif
+
+    return 0;
+}
+
+#ifdef CSR_SUPPORT_WEXT_AP
+#define PARAM_TYPE_INT 0
+#define PARAM_TYPE_STRING 1
+#define CSR_WIFI_MAX_SSID_LEN 32
+#define CSR_WIFI_MAX_SEC_LEN 16
+#define CSR_WIFI_MAX_KEY_LEN 65
+
+static int hex_look_up(char x)
+{
+    if(x>='0' && x<='9')
+        return (x-48);
+    if(x>= 'a' && x <= 'f')
+        return (x-87);
+    return -1;
+}
+
+static int power (int a, int b)
+{
+    int i;
+    int num =1;
+    for(i=0;i<b;i++)
+       num *=a;
+    return num;
+}
+
+static int decode_parameter_from_string(unifi_priv_t* priv, char **str_ptr,
+                                        const char *token, int param_type,
+                                        void  *dst, int param_max_len)
+{
+    CsrUint8 int_str[7] = "0";
+    CsrUint32 param_str_len;
+    CsrUint8  *param_str_begin,*param_str_end;
+    CsrUint8  *orig_str = *str_ptr;
+
+    if (!strncmp(*str_ptr, token, strlen(token))) {
+        strsep(str_ptr, "=,");
+        param_str_begin = *str_ptr;
+        strsep(str_ptr, "=,");
+        if (*str_ptr == NULL) {
+            param_str_len = strlen(param_str_begin);
+        } else {
+            param_str_end = *str_ptr-1;
+            param_str_len = param_str_end - param_str_begin;
+        }
+        unifi_trace(priv,UDBG2,"'token:%s', len:%d, ", token, param_str_len);
+        if (param_str_len > param_max_len) {
+            unifi_notice(priv,"extracted param len:%d is > MAX:%d\n",param_str_len, param_max_len);
+            param_str_len = param_max_len;
+        }
+        switch (param_type) {
+            case PARAM_TYPE_INT:
+            {
+                CsrUint32 *pdst_int = dst,num =0;
+                int i,j=0;
+                if (param_str_len > sizeof(int_str)) {
+                    param_str_len = sizeof(int_str);
+                }
+                memcpy(int_str, param_str_begin, param_str_len);
+                for(i = param_str_len; i>0;i--) {
+                    if(int_str[i-1] >= '0' && int_str[i-1] <='9') {
+                        num += ((int_str[i-1]-'0')*power(10,j));
+                        j++;
+                    } else {
+                        unifi_error(priv,"decode_parameter_from_string:not a number %c\n",(int_str[i-1]));
+                        return -1;
+                    }
+                }
+                *pdst_int = num;
+                unifi_trace(priv,UDBG2,"decode_parameter_from_string:decoded int = %d\n",*pdst_int);
+            }
+            break;
+            default:
+                memcpy(dst, param_str_begin, param_str_len);
+                *((char *)dst + param_str_len) = 0;
+                unifi_trace(priv,UDBG2,"decode_parameter_from_string:decoded string = %s\n",(char *)dst);
+            break;
+        }
+    } else {
+        unifi_error(priv,"decode_parameter_from_string: Token:%s not found in %s \n",token,orig_str);
+        return -1;
+    }
+    return 0;
+}
+static int store_ap_advanced_config_from_string(unifi_priv_t *priv, char *param_str)
+{
+    char * str_ptr=param_str;
+    int ret = 0,tmp_var;
+    char phy_mode[6];
+    CsrWifiSmeApMacConfig * ap_mac_config = &priv->ap_mac_config;
+
+    /* Check for BI */
+    ret = decode_parameter_from_string(priv, &str_ptr, "BI=",
+                                       PARAM_TYPE_INT, &tmp_var, 5);
+    if(ret) {
+        unifi_error(priv,"store_ap_advanced_config_from_string: BI not found\n");
+        return -1;
+    }
+    ap_mac_config->beaconInterval = tmp_var;
+    ret = decode_parameter_from_string(priv, &str_ptr, "DTIM_PER=",
+                                        PARAM_TYPE_INT, &tmp_var, 5);
+    if(ret) {
+        unifi_error(priv,"store_ap_advanced_config_from_string: DTIM_PER not found\n");
+        return -1;
+    }
+    ap_mac_config->dtimPeriod = tmp_var;
+    ret = decode_parameter_from_string(priv, &str_ptr, "WMM=",
+                                        PARAM_TYPE_INT, &tmp_var, 5);
+    if(ret) {
+        unifi_error(priv,"store_ap_advanced_config_from_string: WMM not found\n");
+        return -1;
+    }
+    ap_mac_config->wmmEnabled = tmp_var;
+    ret = decode_parameter_from_string(priv, &str_ptr, "PHY=",
+                                        PARAM_TYPE_STRING, phy_mode, 5);
+    if(ret) {
+        unifi_error(priv,"store_ap_advanced_config_from_string: PHY not found\n");
+    } else {
+       if(strstr(phy_mode,"b")){
+           ap_mac_config->phySupportedBitmap = CSR_WIFI_SME_AP_PHY_SUPPORT_B;
+       }
+       if(strstr(phy_mode,"g")) {
+           ap_mac_config->phySupportedBitmap |= CSR_WIFI_SME_AP_PHY_SUPPORT_G;
+       }
+       if(strstr(phy_mode,"n")) {
+           ap_mac_config->phySupportedBitmap |= CSR_WIFI_SME_AP_PHY_SUPPORT_N;
+       }
+       ap_mac_config->supportedRatesCount =
+       uf_configure_supported_rates(ap_mac_config->supportedRates, ap_mac_config->phySupportedBitmap);
+    }
+    return ret;
+}
+
+static int store_ap_config_from_string( unifi_priv_t * priv,char *param_str)
+
+{
+    char *str_ptr = param_str;
+    char sub_cmd[16];
+    char sec[CSR_WIFI_MAX_SEC_LEN];
+    char key[CSR_WIFI_MAX_KEY_LEN];
+    int ret = 0,tmp_var;
+    CsrWifiSmeApConfig_t *ap_config = &priv->ap_config;
+    CsrWifiSmeApMacConfig * ap_mac_config = &priv->ap_mac_config;
+    memset(sub_cmd, 0, sizeof(sub_cmd));
+    if(!strstr(param_str,"END")) {
+        unifi_error(priv,"store_ap_config_from_string:Invalid config string:%s\n",param_str);
+        return -1;
+    }
+    if (decode_parameter_from_string(priv,&str_ptr, "ASCII_CMD=",
+        PARAM_TYPE_STRING, sub_cmd, 6) != 0) {
+         return -1;
+    }
+    if (strncmp(sub_cmd, "AP_CFG", 6)) {
+
+        if(!strncmp(sub_cmd ,"ADVCFG", 6)) {
+           return store_ap_advanced_config_from_string(priv, str_ptr);
+        }
+        unifi_error(priv,"store_ap_config_from_string: sub_cmd:%s != 'AP_CFG or ADVCFG'!\n", sub_cmd);
+        return -1;
+    }
+    memset(ap_config, 0, sizeof(CsrWifiSmeApConfig_t));
+    ret = decode_parameter_from_string(priv,&str_ptr, "SSID=",
+                                       PARAM_TYPE_STRING, ap_config->ssid.ssid,
+                                       CSR_WIFI_MAX_SSID_LEN);
+    if(ret) {
+        unifi_error(priv,"store_ap_config_from_string: SSID not found\n");
+        return -1;
+    }
+    ap_config->ssid.length = strlen(ap_config->ssid.ssid);
+
+    ret = decode_parameter_from_string(priv, &str_ptr, "SEC=",
+                                       PARAM_TYPE_STRING, sec, CSR_WIFI_MAX_SEC_LEN);
+    if(ret) {
+        unifi_error(priv,"store_ap_config_from_string: SEC not found\n");
+        return -1;
+    }
+    ret = decode_parameter_from_string(priv,&str_ptr, "KEY=",
+                         PARAM_TYPE_STRING,  key, CSR_WIFI_MAX_KEY_LEN);
+    if(!strcasecmp(sec,"open")) {
+        unifi_trace(priv,UDBG2,"store_ap_config_from_string: security open");
+        ap_config->credentials.authType = CSR_WIFI_SME_AP_AUTH_TYPE_OPEN_SYSTEM;
+        if(ret) {
+            unifi_notice(priv,"store_ap_config_from_string: KEY not found:fine with Open\n");
+        }
+    }
+    else if(!strcasecmp(sec,"wpa2-psk")) {
+        int i,j=0;
+        CsrWifiNmeApAuthPers *pers =
+                            ((CsrWifiNmeApAuthPers *)&(ap_config->credentials.nmeAuthType.authTypePersonal));
+        CsrUint8 *psk = pers->authPers_credentials.psk.psk;
+
+        unifi_trace(priv,UDBG2,"store_ap_config_from_string: security WPA2");
+        if(ret) {
+            unifi_error(priv,"store_ap_config_from_string: KEY not found for WPA2\n");
+            return -1;
+        }
+        ap_config->credentials.authType = CSR_WIFI_SME_AP_AUTH_TYPE_PERSONAL;
+        pers->authSupport = CSR_WIFI_SME_RSN_AUTH_WPA2PSK;
+        pers->rsnCapabilities =0;
+        pers->wapiCapabilities =0;
+        pers->pskOrPassphrase=CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PSK;
+        pers->authPers_credentials.psk.encryptionMode =
+                 (CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_CCMP |CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_CCMP) ;
+        for(i=0;i<32;i++){
+           psk[i] = (16*hex_look_up(key[j]))+hex_look_up(key[j+1]);
+           j+=2;
+        }
+
+    } else {
+       unifi_notice(priv,"store_ap_config_from_string: Unknown security: Assuming Open");
+       ap_config->credentials.authType = CSR_WIFI_SME_AP_AUTH_TYPE_OPEN_SYSTEM;
+       return -1;
+    }
+   /* Get the decoded value in a temp int variable to ensure that other fields within the struct
+      which are of type other than int are not over written */
+    ret = decode_parameter_from_string(priv,&str_ptr, "CHANNEL=", PARAM_TYPE_INT, &tmp_var, 5);
+    if(ret)
+        return -1;
+    ap_config->channel = tmp_var;
+    ret = decode_parameter_from_string(priv,&str_ptr, "PREAMBLE=", PARAM_TYPE_INT, &tmp_var, 5);
+    if(ret)
+        return -1;
+    ap_mac_config->preamble = tmp_var;
+    ret = decode_parameter_from_string(priv,&str_ptr, "MAX_SCB=", PARAM_TYPE_INT,  &tmp_var, 5);
+    ap_config->max_connections = tmp_var;
+    return ret;
+}
+
+static int
+iwprivsapstart(struct net_device *dev, struct iw_request_info *info,
+               union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int r;
+
+    unifi_trace(priv, UDBG1, "iwprivsapstart\n" );
+    r = sme_ap_start(priv,interfacePriv->InterfaceTag,&priv->ap_config);
+    if(r) {
+        unifi_error(priv,"iwprivsapstart AP START failed : %d\n",-r);
+    }
+    return r;
+}
+
+static int
+iwprivsapconfig(struct net_device *dev, struct iw_request_info *info,
+                union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    char  *cfg_str = NULL;
+    int r;
+
+    unifi_trace(priv, UDBG1, "iwprivsapconfig\n" );
+    if (wrqu->data.length != 0) {
+        char *str;
+        if (!(cfg_str = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
+        {
+            return -ENOMEM;
+        }
+        if (copy_from_user(cfg_str, wrqu->data.pointer, wrqu->data.length)) {
+            kfree(cfg_str);
+            return -EFAULT;
+        }
+        cfg_str[wrqu->data.length] = 0;
+        unifi_trace(priv,UDBG2,"length:%d\n",wrqu->data.length);
+        unifi_trace(priv,UDBG2,"AP configuration string:%s\n",cfg_str);
+        str = cfg_str;
+       if ((r = store_ap_config_from_string(priv,str))) {
+           unifi_error(priv, "iwprivsapconfig:Failed  to decode the string %d\n",r);
+           kfree(cfg_str);
+           return -EIO;
+
+       }
+    } else {
+        unifi_error(priv,"iwprivsapconfig argument length = 0 \n");
+        return -EIO;
+    }
+    r = sme_ap_config(priv, &priv->ap_mac_config, &priv->group_sec_config);
+    if(r) {
+        unifi_error(priv,"iwprivsapstop AP Config failed : %d\n",-r);
+    } else if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+        interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+        unifi_trace(priv, UDBG1, "iwprivsapconfig: Starting the AP");
+        r = sme_ap_start(priv,interfacePriv->InterfaceTag,&priv->ap_config);
+        if(r) {
+            unifi_error(priv,"iwprivsapstart AP START failed : %d\n",-r);
+        }
+    }
+    kfree(cfg_str);
+    return r;
+}
+
+static int
+iwprivsapstop(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int r;
+    CsrUint16 interface_tag = interfacePriv->InterfaceTag;
+
+    unifi_trace(priv, UDBG1, "iwprivsapstop\n" );
+    r = sme_ap_stop(priv,interface_tag);
+    if(r) {
+        unifi_error(priv,"iwprivsapstop AP STOP failed : %d\n",-r);
+    }
+    return r;
+}
+
+#ifdef ANDROID_BUILD
+static int
+iwprivsapfwreload(struct net_device *dev, struct iw_request_info *info,
+                  union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+
+    unifi_trace(priv, UDBG1, "iwprivsapfwreload\n" );
+    return 0;
+}
+
+static int
+iwprivsstackstart(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    unifi_trace(priv, UDBG1, "iwprivsstackstart\n" );
+    return 0;
+}
+
+static int
+iwprivsstackstop(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int r = 0;
+    CsrUint16 interface_tag = interfacePriv->InterfaceTag;
+
+    unifi_trace(priv, UDBG1, "iwprivsstackstop\n" );
+
+    switch(interfacePriv->interfaceMode) {
+        case CSR_WIFI_ROUTER_CTRL_MODE_STA:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI:
+        case CSR_WIFI_ROUTER_CTRL_MODE_IBSS:
+            r = sme_mgt_disconnect(priv);
+            break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+            r = sme_ap_stop(priv,interface_tag);
+            break;
+        default :
+            break;
+    }
+
+    if(r) {
+        unifi_error(priv,"iwprivsstackstop Stack stop failed : %d\n",-r);
+    }
+    return 0;
+}
+#endif /* ANDROID_BUILD */
+#endif /* CSR_SUPPORT_WEXT_AP */
+
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+static int
+iwprivsconfwapi(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    CsrUint8 enable;
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    func_enter();
+
+    unifi_trace(priv, UDBG1, "iwprivsconfwapi\n" );
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "iwprivsconfwapi: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+    enable = *(CsrUint8*)(extra);
+
+    if (enable) {
+        priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN;
+        priv->connection_config.authModeMask |= (CSR_WIFI_SME_AUTH_MODE_WAPI_WAIPSK | CSR_WIFI_SME_AUTH_MODE_WAPI_WAI);
+        priv->connection_config.encryptionModeMask |=
+            CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_SMS4 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_SMS4;
+    } else {
+        priv->connection_config.authModeMask &= ~(CSR_WIFI_SME_AUTH_MODE_WAPI_WAIPSK | CSR_WIFI_SME_AUTH_MODE_WAPI_WAI);
+        priv->connection_config.encryptionModeMask &=
+            ~(CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_SMS4 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_SMS4);
+    }
+
+    func_exit();
+    return 0;
+}
+
+static int
+iwprivswpikey(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    int r = 0, i;
+    CsrWifiSmeKey key;
+    unifiio_wapi_key_t inKey;
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    func_enter();
+
+    unifi_trace(priv, UDBG1, "iwprivswpikey\n" );
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "iwprivswpikey: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+    inKey = *(unifiio_wapi_key_t*)(extra);
+
+    if (inKey.unicastKey) {
+        key.keyType   = CSR_WIFI_SME_KEY_TYPE_PAIRWISE;
+    } else {
+        key.keyType   = CSR_WIFI_SME_KEY_TYPE_GROUP;
+    }
+
+    key.keyIndex  = inKey.keyIndex;
+
+    /* memcpy(key.keyRsc, inKey.keyRsc, 16); */
+    for (i = 0; i < 16; i+= 2)
+    {
+        key.keyRsc[i/2] = inKey.keyRsc[i+1] << 8 | inKey.keyRsc[i];
+    }
+
+    memcpy(key.address.a, inKey.address, 6);
+    key.keyLength = 32;
+    memcpy(key.key, inKey.key, 32);
+    key.authenticator = 0;
+    key.wepTxKey = 0;
+
+    unifi_trace(priv, UDBG1, "keyType = %d, keyIndex = %d, wepTxKey = %d, keyRsc = %x:%x, auth = %d, address = %x:%x, "
+                "keylength = %d, key = %x:%x\n", key.keyType, key.keyIndex, key.wepTxKey,
+                key.keyRsc[0], key.keyRsc[7], key.authenticator,
+                key.address.a[0], key.address.a[5], key.keyLength, key.key[0],
+                key.key[15]);
+
+    r = sme_mgt_key(priv, &key, CSR_WIFI_SME_LIST_ACTION_ADD);
+    if (r) {
+        unifi_error(priv, "SETKEYS request was rejected with result %d\n", r);
+        return convert_sme_error(r);
+    }
+
+    func_exit();
+    return r;
+}
+#endif
+
+
+static int
+unifi_giwname(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    char *name = wrqu->name;
+    unifi_trace(priv, UDBG2, "unifi_giwname\n");
+
+    if (priv->if_index == CSR_INDEX_5G) {
+        strcpy(name, "IEEE 802.11-a");
+    } else {
+        strcpy(name, "IEEE 802.11-bgn");
+    }
+    return 0;
+} /* unifi_giwname() */
+
+
+static int
+unifi_siwfreq(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct iw_freq *freq = (struct iw_freq *)wrqu;
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "unifi_siwfreq\n");
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwfreq: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    /*
+     * Channel is stored in the connection configuration,
+     * and set later when ask for a connection.
+     */
+    if ((freq->e == 0) && (freq->m <= 1000)) {
+        priv->connection_config.adhocChannel = freq->m;
+    } else {
+        priv->connection_config.adhocChannel = wext_freq_to_channel(freq->m, freq->e);
+    }
+
+    func_exit();
+    return 0;
+} /* unifi_siwfreq() */
+
+
+static int
+unifi_giwfreq(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct iw_freq *freq = (struct iw_freq *)wrqu;
+    int err = 0;
+    CsrWifiSmeConnectionInfo connectionInfo;
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "unifi_giwfreq\n");
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_giwfreq: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    UF_RTNL_UNLOCK();
+    err = sme_mgt_connection_info_get(priv, &connectionInfo);
+    UF_RTNL_LOCK();
+
+    freq->m = channel_to_mhz(connectionInfo.channelNumber,
+            (connectionInfo.networkType80211 == CSR_WIFI_SME_RADIO_IF_GHZ_5_0));
+    freq->e = 6;
+
+    func_exit();
+    return convert_sme_error(err);
+} /* unifi_giwfreq() */
+
+
+static int
+unifi_siwmode(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "unifi_siwmode\n");
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwmode: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    switch(wrqu->mode) {
+        case IW_MODE_ADHOC:
+            priv->connection_config.bssType = CSR_WIFI_SME_BSS_TYPE_ADHOC;
+            break;
+        case IW_MODE_INFRA:
+            priv->connection_config.bssType = CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE;
+            break;
+        case IW_MODE_AUTO:
+            priv->connection_config.bssType = CSR_WIFI_SME_BSS_TYPE_ANY_BSS;
+            break;
+        default:
+            unifi_notice(priv, "Unknown IW MODE value.\n");
+    }
+
+    /* Clear the SSID and BSSID configuration */
+    priv->connection_config.ssid.length = 0;
+    memset(priv->connection_config.bssid.a, 0xFF, ETH_ALEN);
+
+    func_exit();
+    return 0;
+} /* unifi_siwmode() */
+
+
+
+static int
+unifi_giwmode(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    int r = 0;
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    CsrWifiSmeConnectionConfig connectionConfig;
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "unifi_giwmode\n");
+    CHECK_INITED(priv);
+
+    unifi_trace(priv, UDBG2, "unifi_giwmode: Exisitng mode = 0x%x\n",
+                interfacePriv->interfaceMode);
+    switch(interfacePriv->interfaceMode) {
+        case CSR_WIFI_ROUTER_CTRL_MODE_STA:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI:
+           wrqu->mode = IW_MODE_INFRA;
+           break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+            wrqu->mode = IW_MODE_MASTER;
+            break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_IBSS:
+            wrqu->mode = IW_MODE_ADHOC;
+            break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2P:
+        case CSR_WIFI_ROUTER_CTRL_MODE_NONE:
+            UF_RTNL_UNLOCK();
+            r = sme_mgt_connection_config_get(priv, &connectionConfig);
+            UF_RTNL_LOCK();
+            if (r == 0) {
+                switch(connectionConfig.bssType) {
+                    case CSR_WIFI_SME_BSS_TYPE_ADHOC:
+                        wrqu->mode = IW_MODE_ADHOC;
+                        break;
+                    case CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE:
+                        wrqu->mode = IW_MODE_INFRA;
+                        break;
+                    default:
+                        wrqu->mode = IW_MODE_AUTO;
+                        unifi_notice(priv, "Unknown IW MODE value.\n");
+                }
+            }
+            break;
+        default:
+            wrqu->mode = IW_MODE_AUTO;
+            unifi_notice(priv, "Unknown IW MODE value.\n");
+
+    }
+    unifi_trace(priv, UDBG4, "unifi_giwmode: mode = 0x%x\n", wrqu->mode);
+    func_exit();
+    return r;
+} /* unifi_giwmode() */
+
+
+
+static int
+unifi_giwrange(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    struct iw_point *dwrq = &wrqu->data;
+    struct iw_range *range = (struct iw_range *) extra;
+    int i;
+
+    unifi_trace(NULL, UDBG2, "unifi_giwrange\n");
+
+    dwrq->length = sizeof(struct iw_range);
+    memset(range, 0, sizeof(*range));
+    range->min_nwid = 0x0000;
+    range->max_nwid = 0x0000;
+
+    /*
+     * Don't report the frequency/channel table, then the channel
+     * number returned elsewhere will be printed as a channel number.
+     */
+
+    /* Ranges of values reported in quality structs */
+    range->max_qual.qual  = 40;         /* Max expected qual value */
+    range->max_qual.level = -120;       /* Noise floor in dBm */
+    range->max_qual.noise = -120;       /* Noise floor in dBm */
+
+
+    /* space for IW_MAX_BITRATES (8 up to WE15, 32 later) */
+    i = 0;
+#if WIRELESS_EXT > 15
+    range->bitrate[i++] =   2 * 500000;
+    range->bitrate[i++] =   4 * 500000;
+    range->bitrate[i++] =  11 * 500000;
+    range->bitrate[i++] =  22 * 500000;
+    range->bitrate[i++] =  12 * 500000;
+    range->bitrate[i++] =  18 * 500000;
+    range->bitrate[i++] =  24 * 500000;
+    range->bitrate[i++] =  36 * 500000;
+    range->bitrate[i++] =  48 * 500000;
+    range->bitrate[i++] =  72 * 500000;
+    range->bitrate[i++] =  96 * 500000;
+    range->bitrate[i++] = 108 * 500000;
+#else
+    range->bitrate[i++] =   2 * 500000;
+    range->bitrate[i++] =   4 * 500000;
+    range->bitrate[i++] =  11 * 500000;
+    range->bitrate[i++] =  22 * 500000;
+    range->bitrate[i++] =  24 * 500000;
+    range->bitrate[i++] =  48 * 500000;
+    range->bitrate[i++] =  96 * 500000;
+    range->bitrate[i++] = 108 * 500000;
+#endif /* WIRELESS_EXT < 16 */
+    range->num_bitrates = i;
+
+    range->max_encoding_tokens = NUM_WEPKEYS;
+    range->num_encoding_sizes = 2;
+    range->encoding_size[0] = 5;
+    range->encoding_size[1] = 13;
+
+    range->we_version_source = 20;
+    range->we_version_compiled = WIRELESS_EXT;
+
+    /* Number of channels available in h/w */
+    range->num_channels = 14;
+    /* Number of entries in freq[] array */
+    range->num_frequency = 14;
+    for (i = 0; (i < range->num_frequency) && (i < IW_MAX_FREQUENCIES); i++) {
+        int chan = i + 1;
+        range->freq[i].i = chan;
+        range->freq[i].m = channel_to_mhz(chan, 0);
+        range->freq[i].e = 6;
+    }
+    if ((i+3) < IW_MAX_FREQUENCIES) {
+        range->freq[i].i = 36;
+        range->freq[i].m = channel_to_mhz(36, 1);
+        range->freq[i].e = 6;
+        range->freq[i+1].i = 40;
+        range->freq[i+1].m = channel_to_mhz(40, 1);
+        range->freq[i+1].e = 6;
+        range->freq[i+2].i = 44;
+        range->freq[i+2].m = channel_to_mhz(44, 1);
+        range->freq[i+2].e = 6;
+        range->freq[i+3].i = 48;
+        range->freq[i+3].m = channel_to_mhz(48, 1);
+        range->freq[i+3].e = 6;
+    }
+
+#if WIRELESS_EXT > 16
+    /* Event capability (kernel + driver) */
+    range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+            IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
+            IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+            IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+    range->event_capa[1] = IW_EVENT_CAPA_K_1;
+    range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) |
+            IW_EVENT_CAPA_MASK(IWEVCUSTOM) |
+            IW_EVENT_CAPA_MASK(IWEVREGISTERED) |
+            IW_EVENT_CAPA_MASK(IWEVEXPIRED));
+#endif /* WIRELESS_EXT > 16 */
+
+#if WIRELESS_EXT > 17
+    range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+        IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+#endif /* WIRELESS_EXT > 17 */
+
+
+    return 0;
+} /* unifi_giwrange() */
+
+
+static int
+unifi_siwap(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int err = 0;
+    const unsigned char zero_bssid[ETH_ALEN] = {0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00};
+
+    func_enter();
+
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwap: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) {
+        return -EINVAL;
+    }
+
+    unifi_trace(priv, UDBG1, "unifi_siwap: asked for %02X:%02X:%02X:%02X:%02X:%02X\n",
+                (u8)wrqu->ap_addr.sa_data[0],
+                (u8)wrqu->ap_addr.sa_data[1],
+                (u8)wrqu->ap_addr.sa_data[2],
+                (u8)wrqu->ap_addr.sa_data[3],
+                (u8)wrqu->ap_addr.sa_data[4],
+                (u8)wrqu->ap_addr.sa_data[5]);
+
+    if (!memcmp(wrqu->ap_addr.sa_data, zero_bssid, ETH_ALEN)) {
+        priv->ignore_bssid_join = FALSE;
+        err = sme_mgt_disconnect(priv);
+        if (err) {
+            unifi_trace(priv, UDBG4, "unifi_siwap: Disconnect failed, status %d\n", err);
+        }
+        return 0;
+    }
+
+    if (priv->ignore_bssid_join) {
+        unifi_trace(priv, UDBG4, "unifi_siwap: ignoring second join\n");
+        priv->ignore_bssid_join = FALSE;
+    } else {
+        memcpy(priv->connection_config.bssid.a, wrqu->ap_addr.sa_data, ETH_ALEN);
+        unifi_trace(priv, UDBG1, "unifi_siwap: Joining %X:%X:%X:%X:%X:%X\n",
+                    priv->connection_config.bssid.a[0],
+                    priv->connection_config.bssid.a[1],
+                    priv->connection_config.bssid.a[2],
+                    priv->connection_config.bssid.a[3],
+                    priv->connection_config.bssid.a[4],
+                    priv->connection_config.bssid.a[5]);
+        err = sme_mgt_connect(priv);
+        if (err) {
+            unifi_error(priv, "unifi_siwap: Join failed, status %d\n", err);
+            func_exit();
+            return convert_sme_error(err);
+        }
+    }
+    func_exit();
+
+    return 0;
+} /* unifi_siwap() */
+
+
+static int
+unifi_giwap(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    CsrWifiSmeConnectionInfo connectionInfo;
+    int r = 0;
+    CsrUint8 *bssid;
+
+    func_enter();
+
+    CHECK_INITED(priv);
+    unifi_trace(priv, UDBG2, "unifi_giwap\n");
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "iwprivswpikey: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_connection_info_get(priv, &connectionInfo);
+    UF_RTNL_LOCK();
+
+    if (r == 0) {
+        bssid = connectionInfo.bssid.a;
+        wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+        unifi_trace(priv, UDBG4,
+                    "unifi_giwap: BSSID = %02X:%02X:%02X:%02X:%02X:%02X\n",
+                    bssid[0], bssid[1], bssid[2],
+                    bssid[3], bssid[4], bssid[5]);
+
+        memcpy(wrqu->ap_addr.sa_data, bssid, ETH_ALEN);
+    } else {
+        memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+    }
+
+    func_exit();
+    return 0;
+} /* unifi_giwap() */
+
+
+static int
+unifi_siwscan(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int scantype;
+    int r;
+    CsrWifiSsid scan_ssid;
+    unsigned char *channel_list = NULL;
+    int chans_good = 0;
+#if WIRELESS_EXT > 17
+    struct iw_point *data = &wrqu->data;
+    struct iw_scan_req *req = (struct iw_scan_req *) extra;
+#endif
+
+    func_enter();
+
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwscan: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    scantype = UNIFI_SCAN_ACTIVE;
+
+#if WIRELESS_EXT > 17
+    /* Providing a valid channel list will force an active scan */
+    if (req) {
+        if ((req->num_channels > 0) && (req->num_channels < IW_MAX_FREQUENCIES)) {
+            channel_list = kmalloc(req->num_channels, GFP_KERNEL);
+            if (channel_list) {
+                int i;
+                for (i = 0; i < req->num_channels; i++) {
+                    /* Convert frequency to channel number */
+                    int ch = wext_freq_to_channel(req->channel_list[i].m,
+                            req->channel_list[i].e);
+                    if (ch) {
+                        channel_list[chans_good++] = ch;
+                    }
+                }
+                unifi_trace(priv, UDBG1,
+                            "SIWSCAN: Scanning %d channels\n", chans_good);
+            } else {
+                /* Fall back to scanning all */
+                unifi_error(priv, "SIWSCAN: Can't alloc channel_list (%d)\n",
+                        req->num_channels);
+            }
+        }
+    }
+
+    if (req && (data->flags & IW_SCAN_THIS_ESSID)) {
+        memcpy(scan_ssid.ssid, req->essid, req->essid_len);
+        scan_ssid.length = req->essid_len;
+        unifi_trace(priv, UDBG1,
+                    "SIWSCAN: Scanning for %.*s\n",
+                    scan_ssid.length, scan_ssid.ssid);
+    } else
+#endif
+    {
+        unifi_trace(priv, UDBG1, "SIWSCAN: Scanning for all APs\n");
+        scan_ssid.length = 0;
+    }
+
+    r = sme_mgt_scan_full(priv, &scan_ssid, chans_good, channel_list);
+    if (r) {
+        unifi_error(priv, "SIWSCAN: Scan returned error %d\n", r);
+    } else {
+        unifi_trace(priv, UDBG1, "SIWSCAN: Scan done\n");
+        wext_send_scan_results_event(priv);
+    }
+
+    if (channel_list) {
+        kfree(channel_list);
+    }
+
+    func_exit();
+    return r;
+
+} /* unifi_siwscan() */
+
+
+static const unsigned char *
+unifi_find_info_element(int id, const unsigned char *info, int len)
+{
+    const unsigned char *ie = info;
+
+    while (len > 1)
+    {
+        int e_id, e_len;
+        e_id = ie[0];
+        e_len = ie[1];
+
+        /* Return if we find a match */
+        if (e_id == id)
+        {
+            return ie;
+        }
+
+        len -= (e_len + 2);
+        ie  += (e_len + 2);
+    }
+
+    return NULL;
+} /* unifi_find_info_element() */
+
+
+/*
+ * Translate scan data returned from the card to a card independent
+ * format that the Wireless Tools will understand - Jean II
+ */
+int
+unifi_translate_scan(struct net_device *dev,
+                     struct iw_request_info *info,
+                     char *current_ev, char *end_buf,
+                     CsrWifiSmeScanResult *scan_data,
+                     int scan_index)
+{
+    struct iw_event iwe;                /* Temporary buffer */
+    unsigned char *info_elems;
+    int info_elem_len;
+    const unsigned char *elem;
+    u16 capabilities;
+    int signal, noise, snr;
+    char *start_buf = current_ev;
+    char *current_val;  /* For rates */
+    int i, r;
+
+    info_elems    = scan_data->informationElements;
+    info_elem_len = scan_data->informationElementsLength;
+
+    if (!scan_data->informationElementsLength || !scan_data->informationElements) {
+        unifi_error(NULL, "*** NULL SCAN IEs ***\n");
+        return -EIO;
+    }
+
+    /* get capinfo bits */
+    capabilities = scan_data->capabilityInformation;
+
+    unifi_trace(NULL, UDBG5, "Capabilities: 0x%x\n", capabilities);
+
+    /* First entry *MUST* be the AP MAC address */
+    memset(&iwe, 0, sizeof(iwe));
+    iwe.cmd = SIOCGIWAP;
+    iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+    memcpy(iwe.u.ap_addr.sa_data, scan_data->bssid.a, ETH_ALEN);
+    iwe.len = IW_EV_ADDR_LEN;
+    r = uf_iwe_stream_add_event(info, start_buf, end_buf, &iwe, IW_EV_ADDR_LEN);
+    if (r < 0) {
+        return r;
+    }
+    start_buf += r;
+
+    /* Other entries will be displayed in the order we give them */
+
+    /* Add the ESSID */
+    /* find SSID in Info Elems */
+    elem = unifi_find_info_element(IE_SSID_ID, info_elems, info_elem_len);
+    if (elem) {
+        int e_len = elem[1];
+        const unsigned char *e_ptr = elem + 2;
+        unsigned char buf[33];
+
+        memset(&iwe, 0, sizeof(iwe));
+        iwe.cmd = SIOCGIWESSID;
+        iwe.u.essid.length = e_len;
+        if (iwe.u.essid.length > 32) {
+            iwe.u.essid.length = 32;
+        }
+        iwe.u.essid.flags = scan_index;
+        memcpy(buf, e_ptr, iwe.u.essid.length);
+        buf[iwe.u.essid.length] = '\0';
+        r = uf_iwe_stream_add_point(info, start_buf, end_buf, &iwe, buf);
+        if (r < 0) {
+            return r;
+        }
+        start_buf += r;
+
+    }
+
+    /* Add mode */
+    memset(&iwe, 0, sizeof(iwe));
+    iwe.cmd = SIOCGIWMODE;
+    if (scan_data->bssType == CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE) {
+        iwe.u.mode = IW_MODE_INFRA;
+    } else {
+        iwe.u.mode = IW_MODE_ADHOC;
+    }
+    iwe.len = IW_EV_UINT_LEN;
+    r = uf_iwe_stream_add_event(info, start_buf, end_buf, &iwe, IW_EV_UINT_LEN);
+    if (r < 0) {
+        return r;
+    }
+    start_buf += r;
+
+    /* Add frequency. iwlist will convert to channel using table given in giwrange */
+    memset(&iwe, 0, sizeof(iwe));
+    iwe.cmd = SIOCGIWFREQ;
+    iwe.u.freq.m = scan_data->channelFrequency;
+    iwe.u.freq.e = 6;
+    r = uf_iwe_stream_add_event(info, start_buf, end_buf, &iwe, IW_EV_FREQ_LEN);
+    if (r < 0) {
+        return r;
+    }
+    start_buf += r;
+
+
+    /* Add quality statistics */
+    iwe.cmd = IWEVQUAL;
+    /*
+     * level and noise below are mapped into an unsigned 8 bit number,
+     * ranging from [-192; 63]. The way this is achieved is simply to
+     * add 0x100 onto the number if it is negative,
+     * once clipped to the correct range.
+     */
+    signal = scan_data->rssi; /* This value is in dBm */
+    /* Clip range of snr */
+    snr    = (scan_data->snr > 0) ? scan_data->snr : 0; /* In dB relative, from 0 - 255 */
+    snr    = (snr < 255) ? snr : 255;
+    noise  = signal - snr;
+
+    /* Clip range of signal */
+    signal = (signal < 63) ? signal : 63;
+    signal = (signal > -192) ? signal : -192;
+
+    /* Clip range of noise */
+    noise = (noise < 63) ? noise : 63;
+    noise = (noise > -192) ? noise : -192;
+
+    /* Make u8 */
+    signal = ( signal < 0 ) ? signal + 0x100 : signal;
+    noise = ( noise < 0 ) ? noise + 0x100 : noise;
+
+    iwe.u.qual.level = (u8)signal; /* -192 : 63 */
+    iwe.u.qual.noise = (u8)noise;  /* -192 : 63 */
+    iwe.u.qual.qual = snr;         /* 0 : 255 */
+    iwe.u.qual.updated = 0;
+#if WIRELESS_EXT > 16
+    iwe.u.qual.updated |= IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED |
+        IW_QUAL_QUAL_UPDATED;
+#if WIRELESS_EXT > 18
+    iwe.u.qual.updated |= IW_QUAL_DBM;
+#endif
+#endif
+    r = uf_iwe_stream_add_event(info, start_buf, end_buf, &iwe, IW_EV_QUAL_LEN);
+    if (r < 0) {
+        return r;
+    }
+    start_buf += r;
+
+    /* Add encryption capability */
+    iwe.cmd = SIOCGIWENCODE;
+    if (capabilities & SIG_CAP_PRIVACY) {
+        iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+    } else {
+        iwe.u.data.flags = IW_ENCODE_DISABLED;
+    }
+    iwe.u.data.length = 0;
+    iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+    r = uf_iwe_stream_add_point(info, start_buf, end_buf, &iwe, "");
+    if (r < 0) {
+        return r;
+    }
+    start_buf += r;
+
+
+    /*
+     * Rate : stuffing multiple values in a single event require a bit
+     * more of magic - Jean II
+     */
+    current_val = start_buf + IW_EV_LCP_LEN;
+
+    iwe.cmd = SIOCGIWRATE;
+    /* Those two flags are ignored... */
+    iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+    elem = unifi_find_info_element(IE_SUPPORTED_RATES_ID,
+            info_elems, info_elem_len);
+    if (elem) {
+        int e_len = elem[1];
+        const unsigned char *e_ptr = elem + 2;
+
+        /*
+         * Count how many rates we have.
+         * Zero marks the end of the list, if the list is not truncated.
+         */
+        /* Max 8 values */
+        for (i = 0; i < e_len; i++) {
+            if (e_ptr[i] == 0) {
+                break;
+            }
+            /* Bit rate given in 500 kb/s units (+ 0x80) */
+            iwe.u.bitrate.value = ((e_ptr[i] & 0x7f) * 500000);
+            /* Add new value to event */
+            r = uf_iwe_stream_add_value(info, start_buf, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
+            if (r < 0) {
+                return r;
+            }
+            current_val +=r;
+
+        }
+    }
+    elem = unifi_find_info_element(IE_EXTENDED_SUPPORTED_RATES_ID,
+            info_elems, info_elem_len);
+    if (elem) {
+        int e_len = elem[1];
+        const unsigned char *e_ptr = elem + 2;
+
+        /*
+         * Count how many rates we have.
+         * Zero marks the end of the list, if the list is not truncated.
+         */
+        /* Max 8 values */
+        for (i = 0; i < e_len; i++) {
+            if (e_ptr[i] == 0) {
+                break;
+            }
+            /* Bit rate given in 500 kb/s units (+ 0x80) */
+            iwe.u.bitrate.value = ((e_ptr[i] & 0x7f) * 500000);
+            /* Add new value to event */
+            r = uf_iwe_stream_add_value(info, start_buf, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
+            if (r < 0) {
+                return r;
+            }
+            current_val +=r;
+        }
+    }
+    /* Check if we added any rates event */
+    if ((current_val - start_buf) > IW_EV_LCP_LEN) {
+        start_buf = current_val;
+    }
+
+
+#if WIRELESS_EXT > 17
+    memset(&iwe, 0, sizeof(iwe));
+    iwe.cmd = IWEVGENIE;
+    iwe.u.data.length = info_elem_len;
+
+    r = uf_iwe_stream_add_point(info, start_buf, end_buf, &iwe, info_elems);
+    if (r < 0) {
+        return r;
+    }
+
+    start_buf += r;
+#endif /* WE > 17 */
+
+    return (start_buf - current_ev);
+} /* unifi_translate_scan() */
+
+
+
+static int
+unifi_giwscan(struct net_device *dev, struct iw_request_info *info,
+              union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct iw_point *dwrq = &wrqu->data;
+    int r;
+
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_giwscan: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    unifi_trace(priv, UDBG1,
+            "unifi_giwscan: buffer (%d bytes) \n",
+            dwrq->length);
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_scan_results_get_async(priv, info, extra, dwrq->length);
+    UF_RTNL_LOCK();
+    if (r < 0) {
+        unifi_trace(priv, UDBG1,
+                "unifi_giwscan: buffer (%d bytes) not big enough.\n",
+                dwrq->length);
+        return r;
+    }
+
+    dwrq->length = r;
+    dwrq->flags = 0;
+
+    return 0;
+} /* unifi_giwscan() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_siwessid
+ *
+ *      Request to join a network or start and AdHoc.
+ *
+ *  Arguments:
+ *      dev             Pointer to network device struct.
+ *      info            Pointer to broken-out ioctl request.
+ *      data            Pointer to argument data.
+ *      essid           Pointer to string giving name of network to join
+ *                      or start
+ *
+ *  Returns:
+ *      0 on success and everything complete
+ *      -EINPROGRESS to have the higher level call the commit method.
+ * ---------------------------------------------------------------------------
+ */
+static int
+unifi_siwessid(struct net_device *dev, struct iw_request_info *info,
+               struct iw_point *data, char *essid)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int len;
+    int err = 0;
+
+    func_enter();
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwessid: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    len = 0;
+    if (data->flags & 1) {
+        /* Limit length  */
+        len = data->length;
+        if (len > UNIFI_MAX_SSID_LEN) {
+            len = UNIFI_MAX_SSID_LEN;
+        }
+    }
+
+#ifdef UNIFI_DEBUG
+    {
+        char essid_str[UNIFI_MAX_SSID_LEN+1];
+        int i;
+
+        for (i = 0; i < len; i++) {
+            essid_str[i] = (isprint(essid[i]) ? essid[i] : '?');
+        }
+        essid_str[i] = '\0';
+
+        unifi_trace(priv, UDBG1, "unifi_siwessid: asked for '%*s' (%d)\n", len, essid_str, len);
+        unifi_trace(priv, UDBG2, " with authModeMask = %d", priv->connection_config.authModeMask);
+    }
+#endif
+
+    memset(priv->connection_config.bssid.a, 0xFF, ETH_ALEN);
+    if (len) {
+        if (essid[len - 1] == 0) {
+            len --;
+        }
+
+        memcpy(priv->connection_config.ssid.ssid, essid, len);
+        priv->connection_config.ssid.length = len;
+
+    } else {
+        priv->connection_config.ssid.length = 0;
+    }
+
+    UF_RTNL_UNLOCK();
+    err = sme_mgt_connect(priv);
+    UF_RTNL_LOCK();
+    if (err) {
+        unifi_error(priv, "unifi_siwessid: Join failed, status %d\n", err);
+        func_exit();
+        return convert_sme_error(err);
+    }
+
+    func_exit();
+    return 0;
+} /* unifi_siwessid() */
+
+
+static int
+unifi_giwessid(struct net_device *dev, struct iw_request_info *info,
+               union iwreq_data *wrqu, char *essid)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct iw_point *data = &wrqu->essid;
+    CsrWifiSmeConnectionInfo connectionInfo;
+    int r = 0;
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "unifi_giwessid\n");
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_giwessid: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_connection_info_get(priv, &connectionInfo);
+    UF_RTNL_LOCK();
+
+    if (r == 0) {
+        data->length = connectionInfo.ssid.length;
+        strncpy(essid,
+                connectionInfo.ssid.ssid,
+                data->length);
+        data->flags = 1;            /* active */
+
+        unifi_trace(priv, UDBG2, "unifi_giwessid: %.*s\n",
+                data->length, essid);
+    }
+
+    func_exit();
+
+    return 0;
+} /* unifi_giwessid() */
+
+
+static int
+unifi_siwrate(struct net_device *dev, struct iw_request_info *info,
+              union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct iw_param *args = &wrqu->bitrate;
+    CsrWifiSmeMibConfig mibConfig;
+    int r;
+
+    func_enter();
+
+    CHECK_INITED(priv);
+    unifi_trace(priv, UDBG2, "unifi_siwrate\n");
+
+    /*
+     * If args->fixed == 0, value is max rate or -1 for best
+     * If args->fixed == 1, value is rate to set or -1 for best
+     * args->disabled and args->flags are not used in SIOCSIWRATE
+     */
+
+    /* Get, modify and set the MIB data */
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_mib_config_get(priv, &mibConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_siwrate: Get CsrWifiSmeMibConfigValue failed.\n");
+        return r;
+    }
+
+    /* Default to auto rate algorithm */
+    /* in 500Kbit/s, 0 means auto */
+    mibConfig.unifiFixTxDataRate = 0;
+
+    if (args->value != -1) {
+        mibConfig.unifiFixTxDataRate = args->value / 500000;
+    }
+
+    /* 1 means rate is a maximum, 2 means rate is a set value */
+    if (args->fixed == 1) {
+        mibConfig.unifiFixMaxTxDataRate = 0;
+    } else {
+        mibConfig.unifiFixMaxTxDataRate = 1;
+    }
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_mib_config_set(priv, &mibConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_siwrate: Set CsrWifiSmeMibConfigValue failed.\n");
+        return r;
+    }
+
+    func_exit();
+
+    return 0;
+} /* unifi_siwrate() */
+
+
+
+static int
+unifi_giwrate(struct net_device *dev, struct iw_request_info *info,
+              union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct iw_param *args = &wrqu->bitrate;
+    int r;
+    int bitrate, flag;
+    CsrWifiSmeMibConfig mibConfig;
+    CsrWifiSmeConnectionStats connectionStats;
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "unifi_giwrate\n");
+    CHECK_INITED(priv);
+
+    flag = 0;
+    bitrate = 0;
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_mib_config_get(priv, &mibConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_giwrate: Get CsrWifiSmeMibConfigValue failed.\n");
+        return r;
+    }
+
+    bitrate = mibConfig.unifiFixTxDataRate;
+    flag = mibConfig.unifiFixMaxTxDataRate;
+
+    /* Used the value returned by the SME if MIB returns 0 */
+    if (bitrate == 0) {
+        UF_RTNL_UNLOCK();
+        r = sme_mgt_connection_stats_get(priv, &connectionStats);
+        UF_RTNL_LOCK();
+        /* Ignore errors, we may be disconnected */
+        if (r == 0) {
+            bitrate = connectionStats.unifiTxDataRate;
+        }
+    }
+
+    args->value = bitrate * 500000;
+    args->fixed = !flag;
+
+    func_exit();
+
+    return 0;
+} /* unifi_giwrate() */
+
+
+static int
+unifi_siwrts(struct net_device *dev, struct iw_request_info *info,
+             union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int val = wrqu->rts.value;
+    int r = 0;
+    CsrWifiSmeMibConfig mibConfig;
+
+    unifi_trace(priv, UDBG2, "unifi_siwrts\n");
+    CHECK_INITED(priv);
+
+    if (wrqu->rts.disabled) {
+        val = 2347;
+    }
+
+    if ( (val < 0) || (val > 2347) )
+    {
+        return -EINVAL;
+    }
+
+    /* Get, modify and set the MIB data */
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_mib_config_get(priv, &mibConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_siwrts: Get CsrWifiSmeMibConfigValue failed.\n");
+        return r;
+    }
+    mibConfig.dot11RtsThreshold = val;
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_mib_config_set(priv, &mibConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_siwrts: Set CsrWifiSmeMibConfigValue failed.\n");
+        return r;
+    }
+
+    return 0;
+}
+
+
+static int
+unifi_giwrts(struct net_device *dev, struct iw_request_info *info,
+             union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int r;
+    int rts_thresh;
+    CsrWifiSmeMibConfig mibConfig;
+
+    unifi_trace(priv, UDBG2, "unifi_giwrts\n");
+    CHECK_INITED(priv);
+
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_mib_config_get(priv, &mibConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_giwrts: Get CsrWifiSmeMibConfigValue failed.\n");
+        return r;
+    }
+
+    rts_thresh = mibConfig.dot11RtsThreshold;
+    if (rts_thresh > 2347) {
+        rts_thresh = 2347;
+    }
+
+    wrqu->rts.value = rts_thresh;
+    wrqu->rts.disabled = (rts_thresh == 2347);
+    wrqu->rts.fixed = 1;
+
+    return 0;
+}
+
+
+static int
+unifi_siwfrag(struct net_device *dev, struct iw_request_info *info,
+              union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int val = wrqu->frag.value;
+    int r = 0;
+    CsrWifiSmeMibConfig mibConfig;
+
+    unifi_trace(priv, UDBG2, "unifi_siwfrag\n");
+    CHECK_INITED(priv);
+
+    if (wrqu->frag.disabled)
+        val = 2346;
+
+    if ( (val < 256) || (val > 2347) )
+        return -EINVAL;
+
+    /* Get, modify and set the MIB data */
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_mib_config_get(priv, &mibConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_siwfrag: Get CsrWifiSmeMibConfigValue failed.\n");
+        return r;
+    }
+    /* Fragmentation Threashold must be even */
+    mibConfig.dot11FragmentationThreshold = (val & ~0x1);
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_mib_config_set(priv, &mibConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_siwfrag: Set CsrWifiSmeMibConfigValue failed.\n");
+        return r;
+    }
+
+    return 0;
+}
+
+
+static int
+unifi_giwfrag(struct net_device *dev, struct iw_request_info *info,
+              union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int r;
+    int frag_thresh;
+    CsrWifiSmeMibConfig mibConfig;
+
+    unifi_trace(priv, UDBG2, "unifi_giwfrag\n");
+    CHECK_INITED(priv);
+
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_mib_config_get(priv, &mibConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_giwfrag: Get CsrWifiSmeMibConfigValue failed.\n");
+        return r;
+    }
+
+    frag_thresh = mibConfig.dot11FragmentationThreshold;
+
+    /* Build the return structure */
+    wrqu->frag.value = frag_thresh;
+    wrqu->frag.disabled = (frag_thresh >= 2346);
+    wrqu->frag.fixed = 1;
+
+    return 0;
+}
+
+
+static int
+unifi_siwencode(struct net_device *dev, struct iw_request_info *info,
+                union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct iw_point *erq = &wrqu->encoding;
+    int index;
+    int rc = 0;
+    int privacy = -1;
+    CsrWifiSmeKey sme_key;
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "unifi_siwencode\n");
+
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwencode: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    /*
+     * Key index is encoded in the flags.
+     * 0 - use current default,
+     * 1-4 - if a key value is given set that key
+     *       if not use that key
+     */
+    index = (erq->flags & IW_ENCODE_INDEX);  /* key number, 1-4 */
+    if ((index < 0) || (index > 4)) {
+        unifi_error(priv, "unifi_siwencode: Request to set an invalid key (index:%d)", index);
+        return -EINVAL;
+    }
+
+    /*
+     * Basic checking: do we have a key to set ?
+     * The IW_ENCODE_NOKEY flag is set when no key is present (only change flags),
+     * but older versions rely on sending a key id 1-4.
+     */
+    if (erq->length > 0) {
+
+        /* Check the size of the key */
+        if ((erq->length > LARGE_KEY_SIZE) || (erq->length < SMALL_KEY_SIZE)) {
+            unifi_error(priv, "unifi_siwencode: Request to set an invalid key (length:%d)",
+                        erq->length);
+            return -EINVAL;
+        }
+
+        /* Check the index (none (i.e. 0) means use current) */
+        if ((index < 1) || (index > 4)) {
+            /* If we do not have a previous key, use 1 as default */
+            if (!priv->wep_tx_key_index) {
+                priv->wep_tx_key_index = 1;
+            }
+            index = priv->wep_tx_key_index;
+        }
+
+        /* If we didn't have a key and a valid index is set, we want to remember it*/
+        if (!priv->wep_tx_key_index) {
+            priv->wep_tx_key_index = index;
+        }
+
+        unifi_trace(priv, UDBG1, "Tx key Index is %d\n", priv->wep_tx_key_index);
+
+        privacy = 1;
+
+        /* Check if the key is not marked as invalid */
+        if ((erq->flags & IW_ENCODE_NOKEY) == 0) {
+
+            unifi_trace(priv, UDBG1, "New %s key (len=%d, index=%d)\n",
+                        (priv->wep_tx_key_index == index) ? "tx" : "",
+                        erq->length, index);
+
+            sme_key.wepTxKey = (priv->wep_tx_key_index == index);
+            if (priv->wep_tx_key_index == index) {
+                sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_PAIRWISE;
+            } else {
+                sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_GROUP;
+            }
+            /* Key index is zero based in SME but 1 based in wext */
+            sme_key.keyIndex = (index - 1);
+            sme_key.keyLength = erq->length;
+            sme_key.authenticator = 0;
+            memset(sme_key.address.a, 0xFF, ETH_ALEN);
+            memcpy(sme_key.key, extra, erq->length);
+
+            UF_RTNL_UNLOCK();
+            rc = sme_mgt_key(priv, &sme_key, CSR_WIFI_SME_LIST_ACTION_ADD);
+            UF_RTNL_LOCK();
+            if (rc) {
+                unifi_error(priv, "unifi_siwencode: Set key failed (%d)", rc);
+                return convert_sme_error(rc);
+            }
+
+            /* Store the key to be reported by the SIOCGIWENCODE handler */
+            priv->wep_keys[index - 1].len = erq->length;
+            memcpy(priv->wep_keys[index - 1].key, extra, erq->length);
+        }
+    } else {
+        /*
+         * No additional key data, so it must be a request to change the
+         * active key.
+         */
+        if (index != 0) {
+            unifi_trace(priv, UDBG1, "Tx key Index is %d\n", index - 1);
+
+            /* Store the index to be reported by the SIOCGIWENCODE handler */
+            priv->wep_tx_key_index = index;
+
+            sme_key.wepTxKey = 1;
+            sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_PAIRWISE;
+
+            /* Key index is zero based in SME but 1 based in wext */
+            sme_key.keyIndex = (index - 1);
+            sme_key.keyLength = 0;
+            sme_key.authenticator = 0;
+            UF_RTNL_UNLOCK();
+            rc = sme_mgt_key(priv, &sme_key, CSR_WIFI_SME_LIST_ACTION_ADD);
+            UF_RTNL_LOCK();
+            if (rc) {
+                unifi_error(priv, "unifi_siwencode: Set key failed (%d)", rc);
+                return convert_sme_error(rc);
+            }
+
+            /* Turn on encryption */
+            privacy = 1;
+        }
+    }
+
+    /* Read the flags */
+    if (erq->flags & IW_ENCODE_DISABLED) {
+        /* disable encryption */
+        unifi_trace(priv, UDBG1, "disable WEP encryption\n");
+        privacy = 0;
+
+        priv->wep_tx_key_index = 0;
+
+        unifi_trace(priv, UDBG1, "IW_ENCODE_DISABLED: CSR_WIFI_SME_AUTH_MODE_80211_OPEN\n");
+        priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN;
+    }
+
+    if (erq->flags & IW_ENCODE_RESTRICTED) {
+        /* Use shared key auth */
+        unifi_trace(priv, UDBG1, "IW_ENCODE_RESTRICTED: CSR_WIFI_SME_AUTH_MODE_80211_SHARED\n");
+        priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_SHARED;
+
+        /* Turn on encryption */
+        privacy = 1;
+    }
+    if (erq->flags & IW_ENCODE_OPEN) {
+        unifi_trace(priv, UDBG1, "IW_ENCODE_OPEN: CSR_WIFI_SME_AUTH_MODE_80211_OPEN\n");
+        priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN;
+    }
+
+    /* Commit the changes to flags if needed */
+    if (privacy != -1) {
+        priv->connection_config.privacyMode = privacy ? CSR_WIFI_SME_80211_PRIVACY_MODE_ENABLED : CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED;
+        priv->connection_config.encryptionModeMask = privacy ? (CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP40 |
+                CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP104 |
+                CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP40 |
+                CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP104) :
+            CSR_WIFI_SME_ENCRYPTION_CIPHER_NONE;
+    }
+
+    func_exit_r(rc);
+    return convert_sme_error(rc);
+
+} /* unifi_siwencode() */
+
+
+
+static int
+unifi_giwencode(struct net_device *dev, struct iw_request_info *info,
+                union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct iw_point *erq = &wrqu->encoding;
+
+    unifi_trace(priv, UDBG2, "unifi_giwencode\n");
+
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_giwencode: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    if (priv->connection_config.authModeMask == CSR_WIFI_SME_AUTH_MODE_80211_SHARED) {
+        erq->flags = IW_ENCODE_RESTRICTED;
+    }
+    else {
+        if (priv->connection_config.privacyMode == CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED) {
+            erq->flags = IW_ENCODE_DISABLED;
+        } else {
+            erq->flags = IW_ENCODE_OPEN;
+        }
+    }
+
+    erq->length = 0;
+
+    if (erq->flags != IW_ENCODE_DISABLED) {
+        int index = priv->wep_tx_key_index;
+
+        if ((index > 0) && (index <= NUM_WEPKEYS)) {
+            erq->flags |= (index & IW_ENCODE_INDEX);
+            erq->length = priv->wep_keys[index - 1].len;
+            memcpy(extra, priv->wep_keys[index - 1].key, erq->length);
+        } else {
+            unifi_notice(priv, "unifi_giwencode: Surprise, do not have a valid key index (%d)\n",
+                         index);
+        }
+    }
+
+    return 0;
+} /* unifi_giwencode() */
+
+
+static int
+unifi_siwpower(struct net_device *dev, struct iw_request_info *info,
+               union iwreq_data *wrqu, char *extra)
+{
+    struct iw_param *args = &wrqu->power;
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int listen_interval, wake_for_dtim;
+    int r = 0;
+    CsrWifiSmePowerConfig powerConfig;
+
+    unifi_trace(priv, UDBG2, "unifi_siwpower\n");
+
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwpower: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_power_config_get(priv, &powerConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_siwpower: Get unifi_PowerConfigValue failed.\n");
+        return r;
+    }
+
+    listen_interval = -1;
+    wake_for_dtim = -1;
+    if (args->disabled) {
+        powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW;
+    }
+    else
+    {
+        powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH;
+
+        switch (args->flags & IW_POWER_TYPE) {
+            case 0:
+                /* not specified */
+                break;
+            case IW_POWER_PERIOD:
+                listen_interval = args->value / 1000;
+                break;
+            default:
+                return -EINVAL;
+        }
+
+        switch (args->flags & IW_POWER_MODE) {
+            case 0:
+                /* not specified */
+                break;
+            case IW_POWER_UNICAST_R:
+                /* not interested in broadcast packets */
+                wake_for_dtim = 0;
+                break;
+            case IW_POWER_ALL_R:
+                /* yes, we are interested in broadcast packets */
+                wake_for_dtim = 1;
+                break;
+            default:
+                return -EINVAL;
+        }
+    }
+
+    if (listen_interval > 0) {
+        powerConfig.listenIntervalTu = listen_interval;
+        unifi_trace(priv, UDBG4, "unifi_siwpower: new Listen Interval = %d.\n",
+                    powerConfig.listenIntervalTu);
+    }
+
+    if (wake_for_dtim >= 0) {
+        powerConfig.rxDtims = wake_for_dtim;
+    }
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_power_config_set(priv, &powerConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_siwpower: Set unifi_PowerConfigValue failed.\n");
+        return r;
+    }
+
+    return 0;
+} /* unifi_siwpower() */
+
+
+static int
+unifi_giwpower(struct net_device *dev, struct iw_request_info *info,
+               union iwreq_data *wrqu, char *extra)
+{
+    struct iw_param *args = &wrqu->power;
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    CsrWifiSmePowerConfig powerConfig;
+    int r;
+
+    unifi_trace(priv, UDBG2, "unifi_giwpower\n");
+
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_giwpower: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    args->flags = 0;
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_power_config_get(priv, &powerConfig);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "unifi_giwpower: Get unifi_PowerConfigValue failed.\n");
+        return r;
+    }
+
+    unifi_trace(priv, UDBG4, "unifi_giwpower: mode=%d\n",
+                powerConfig.powerSaveLevel);
+
+    args->disabled = (powerConfig.powerSaveLevel == CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW);
+    if (args->disabled) {
+        args->flags = 0;
+        return 0;
+    }
+
+    args->value = powerConfig.listenIntervalTu * 1000;
+    args->flags |= IW_POWER_PERIOD;
+
+    if (powerConfig.rxDtims) {
+        args->flags |= IW_POWER_ALL_R;
+    } else {
+        args->flags |= IW_POWER_UNICAST_R;
+    }
+
+    return 0;
+} /* unifi_giwpower() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_siwcommit - handler for SIOCSIWCOMMIT
+ *
+ *      Apply all the parameters that have been set.
+ *      In practice this means:
+ *       - do a scan
+ *       - join a network or start an AdHoc
+ *       - authenticate and associate.
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static int
+unifi_siwcommit(struct net_device *dev, struct iw_request_info *info,
+                union iwreq_data *wrqu, char *extra)
+{
+    return 0;
+} /* unifi_siwcommit() */
+
+
+
+static int
+unifi_siwmlme(struct net_device *dev, struct iw_request_info *info,
+              union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct iw_mlme *mlme = (struct iw_mlme *)extra;
+    func_enter();
+
+    unifi_trace(priv, UDBG2, "unifi_siwmlme\n");
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwmlme: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    switch (mlme->cmd) {
+        case IW_MLME_DEAUTH:
+        case IW_MLME_DISASSOC:
+            UF_RTNL_UNLOCK();
+            sme_mgt_disconnect(priv);
+            UF_RTNL_LOCK();
+            break;
+        default:
+            func_exit_r(-EOPNOTSUPP);
+            return -EOPNOTSUPP;
+    }
+
+    func_exit();
+    return 0;
+} /* unifi_siwmlme() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_siwgenie
+ *  unifi_giwgenie
+ *
+ *      WPA : Generic IEEE 802.11 information element (e.g., for WPA/RSN/WMM).
+ *      Handlers for SIOCSIWGENIE, SIOCGIWGENIE - set/get generic IE
+ *
+ *      The host program (e.g. wpa_supplicant) uses this call to set the
+ *      additional IEs to accompany the next (Associate?) request.
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      None.
+ *  Notes:
+ *      From wireless.h:
+ *        This ioctl uses struct iw_point and data buffer that includes IE id
+ *        and len fields. More than one IE may be included in the
+ *        request. Setting the generic IE to empty buffer (len=0) removes the
+ *        generic IE from the driver.
+ * ---------------------------------------------------------------------------
+ */
+static int
+unifi_siwgenie(struct net_device *dev, struct iw_request_info *info,
+               union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int len;
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "unifi_siwgenie\n");
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwgenie: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    if ( priv->connection_config.mlmeAssociateReqInformationElements) {
+        kfree( priv->connection_config.mlmeAssociateReqInformationElements);
+    }
+    priv->connection_config.mlmeAssociateReqInformationElementsLength = 0;
+    priv->connection_config.mlmeAssociateReqInformationElements = NULL;
+
+    len = wrqu->data.length;
+    if (len == 0) {
+        func_exit();
+        return 0;
+    }
+
+    priv->connection_config.mlmeAssociateReqInformationElements = kmalloc(len, GFP_KERNEL);
+    if (priv->connection_config.mlmeAssociateReqInformationElements == NULL) {
+        func_exit();
+        return -ENOMEM;
+    }
+
+    priv->connection_config.mlmeAssociateReqInformationElementsLength = len;
+    memcpy( priv->connection_config.mlmeAssociateReqInformationElements, extra, len);
+
+    func_exit();
+    return 0;
+} /* unifi_siwgenie() */
+
+
+static int
+unifi_giwgenie(struct net_device *dev, struct iw_request_info *info,
+               union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    int len;
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "unifi_giwgenie\n");
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_giwgenie: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    len = priv->connection_config.mlmeAssociateReqInformationElementsLength;
+
+    if (len == 0) {
+        wrqu->data.length = 0;
+        return 0;
+    }
+
+    if (wrqu->data.length < len) {
+        return -E2BIG;
+    }
+
+    wrqu->data.length = len;
+    memcpy(extra, priv->connection_config.mlmeAssociateReqInformationElements, len);
+
+    func_exit();
+    return 0;
+} /* unifi_giwgenie() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_siwauth
+ *  unifi_giwauth
+ *
+ *      Handlers for SIOCSIWAUTH, SIOCGIWAUTH
+ *      Set/get various authentication parameters.
+ *
+ *  Arguments:
+ *
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static int
+_unifi_siwauth(struct net_device *dev, struct iw_request_info *info,
+               union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    CsrWifiSmeAuthModeMask new_auth;
+
+    func_enter();
+    unifi_trace(priv, UDBG2, "unifi_siwauth\n");
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwauth: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    /*
+     * This ioctl is safe to call even when UniFi is powered off.
+     * wpa_supplicant calls it to test whether we support WPA.
+     */
+
+    switch (wrqu->param.flags & IW_AUTH_INDEX) {
+
+        case IW_AUTH_WPA_ENABLED:
+            unifi_trace(priv, UDBG1, "IW_AUTH_WPA_ENABLED: %d\n", wrqu->param.value);
+
+            if (wrqu->param.value == 0) {
+                unifi_trace(priv, UDBG5, "IW_AUTH_WPA_ENABLED: CSR_WIFI_SME_AUTH_MODE_80211_OPEN\n");
+                priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN;
+            }
+            break;
+
+        case IW_AUTH_PRIVACY_INVOKED:
+            unifi_trace(priv, UDBG1, "IW_AUTH_PRIVACY_INVOKED: %d\n", wrqu->param.value);
+
+            priv->connection_config.privacyMode = wrqu->param.value ? CSR_WIFI_SME_80211_PRIVACY_MODE_ENABLED : CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED;
+            if (wrqu->param.value == CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED)
+            {
+                priv->connection_config.encryptionModeMask = CSR_WIFI_SME_ENCRYPTION_CIPHER_NONE;
+            }
+            break;
+
+        case IW_AUTH_80211_AUTH_ALG:
+            /*
+               IW_AUTH_ALG_OPEN_SYSTEM      0x00000001
+               IW_AUTH_ALG_SHARED_KEY       0x00000002
+               IW_AUTH_ALG_LEAP             0x00000004
+               */
+            new_auth = 0;
+            if (wrqu->param.value & IW_AUTH_ALG_OPEN_SYSTEM) {
+                unifi_trace(priv, UDBG1, "IW_AUTH_80211_AUTH_ALG: %d (IW_AUTH_ALG_OPEN_SYSTEM)\n", wrqu->param.value);
+                new_auth |= CSR_WIFI_SME_AUTH_MODE_80211_OPEN;
+            }
+            if (wrqu->param.value & IW_AUTH_ALG_SHARED_KEY) {
+                unifi_trace(priv, UDBG1, "IW_AUTH_80211_AUTH_ALG: %d (IW_AUTH_ALG_SHARED_KEY)\n", wrqu->param.value);
+                new_auth |= CSR_WIFI_SME_AUTH_MODE_80211_SHARED;
+            }
+            if (wrqu->param.value & IW_AUTH_ALG_LEAP) {
+                /* Initial exchanges using open-system to set EAP */
+                unifi_trace(priv, UDBG1, "IW_AUTH_80211_AUTH_ALG: %d (IW_AUTH_ALG_LEAP)\n", wrqu->param.value);
+                new_auth |= CSR_WIFI_SME_AUTH_MODE_8021X_OTHER1X;
+            }
+            if (new_auth == 0) {
+                unifi_trace(priv, UDBG1, "IW_AUTH_80211_AUTH_ALG: invalid value %d\n",
+                        wrqu->param.value);
+                return -EINVAL;
+            } else {
+                priv->connection_config.authModeMask = new_auth;
+            }
+            break;
+
+        case IW_AUTH_WPA_VERSION:
+            unifi_trace(priv, UDBG1, "IW_AUTH_WPA_VERSION: %d\n", wrqu->param.value);
+            priv->ignore_bssid_join = TRUE;
+            /*
+               IW_AUTH_WPA_VERSION_DISABLED 0x00000001
+               IW_AUTH_WPA_VERSION_WPA      0x00000002
+               IW_AUTH_WPA_VERSION_WPA2     0x00000004
+               */
+
+            if (!(wrqu->param.value & IW_AUTH_WPA_VERSION_DISABLED)) {
+
+                priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN;
+
+                if (wrqu->param.value & IW_AUTH_WPA_VERSION_WPA) {
+                    unifi_trace(priv, UDBG4, "IW_AUTH_WPA_VERSION: WPA, WPA-PSK\n");
+                    priv->connection_config.authModeMask |= (CSR_WIFI_SME_AUTH_MODE_8021X_WPA | CSR_WIFI_SME_AUTH_MODE_8021X_WPAPSK);
+                }
+                if (wrqu->param.value & IW_AUTH_WPA_VERSION_WPA2) {
+                    unifi_trace(priv, UDBG4, "IW_AUTH_WPA_VERSION: WPA2, WPA2-PSK\n");
+                    priv->connection_config.authModeMask |= (CSR_WIFI_SME_AUTH_MODE_8021X_WPA2 | CSR_WIFI_SME_AUTH_MODE_8021X_WPA2PSK);
+                }
+            }
+            break;
+
+        case IW_AUTH_CIPHER_PAIRWISE:
+            unifi_trace(priv, UDBG1, "IW_AUTH_CIPHER_PAIRWISE: %d\n", wrqu->param.value);
+            /*
+             * one of:
+             IW_AUTH_CIPHER_NONE	0x00000001
+             IW_AUTH_CIPHER_WEP40	0x00000002
+             IW_AUTH_CIPHER_TKIP	0x00000004
+             IW_AUTH_CIPHER_CCMP	0x00000008
+             IW_AUTH_CIPHER_WEP104	0x00000010
+             */
+
+            priv->connection_config.encryptionModeMask = CSR_WIFI_SME_ENCRYPTION_CIPHER_NONE;
+
+            if (wrqu->param.value & IW_AUTH_CIPHER_WEP40) {
+                priv->connection_config.encryptionModeMask |=
+                    CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP40 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP40;
+            }
+            if (wrqu->param.value & IW_AUTH_CIPHER_WEP104) {
+                priv->connection_config.encryptionModeMask |=
+                    CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP104 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP104;
+            }
+            if (wrqu->param.value & IW_AUTH_CIPHER_TKIP) {
+                priv->connection_config.encryptionModeMask |=
+                    CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_TKIP | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_TKIP;
+            }
+            if (wrqu->param.value & IW_AUTH_CIPHER_CCMP) {
+                priv->connection_config.encryptionModeMask |=
+                    CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_CCMP | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_CCMP;
+            }
+
+            break;
+
+        case IW_AUTH_CIPHER_GROUP:
+            unifi_trace(priv, UDBG1, "IW_AUTH_CIPHER_GROUP: %d\n", wrqu->param.value);
+            /*
+             * Use the WPA version and the group cipher suite to set the permitted
+             * group key in the MIB. f/w uses this value to validate WPA and RSN IEs
+             * in the probe responses from the desired BSS(ID)
+             */
+
+            priv->connection_config.encryptionModeMask &= ~(CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP40 |
+                    CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP104 |
+                    CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_TKIP |
+                    CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_CCMP);
+            if (wrqu->param.value & IW_AUTH_CIPHER_WEP40) {
+                priv->connection_config.encryptionModeMask |= CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP40;
+            }
+            if (wrqu->param.value & IW_AUTH_CIPHER_WEP104) {
+                priv->connection_config.encryptionModeMask |= CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP104;
+            }
+            if (wrqu->param.value & IW_AUTH_CIPHER_TKIP) {
+                priv->connection_config.encryptionModeMask |= CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_TKIP;
+            }
+            if (wrqu->param.value & IW_AUTH_CIPHER_CCMP) {
+                priv->connection_config.encryptionModeMask |= CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_CCMP;
+            }
+
+            break;
+
+        case IW_AUTH_KEY_MGMT:
+            unifi_trace(priv, UDBG1, "IW_AUTH_KEY_MGMT: %d\n", wrqu->param.value);
+            /*
+               IW_AUTH_KEY_MGMT_802_1X 1
+               IW_AUTH_KEY_MGMT_PSK    2
+               */
+            if (priv->connection_config.authModeMask & (CSR_WIFI_SME_AUTH_MODE_8021X_WPA | CSR_WIFI_SME_AUTH_MODE_8021X_WPAPSK)) {
+                /* Check for explicitly set mode. */
+                if (wrqu->param.value == IW_AUTH_KEY_MGMT_802_1X) {
+                    priv->connection_config.authModeMask &= ~CSR_WIFI_SME_AUTH_MODE_8021X_WPAPSK;
+                }
+                if (wrqu->param.value == IW_AUTH_KEY_MGMT_PSK) {
+                    priv->connection_config.authModeMask &= ~CSR_WIFI_SME_AUTH_MODE_8021X_WPA;
+                }
+                unifi_trace(priv, UDBG5, "IW_AUTH_KEY_MGMT: WPA: %d\n",
+                            priv->connection_config.authModeMask);
+            }
+            if (priv->connection_config.authModeMask & (CSR_WIFI_SME_AUTH_MODE_8021X_WPA2 | CSR_WIFI_SME_AUTH_MODE_8021X_WPA2PSK)) {
+                /* Check for explicitly set mode. */
+                if (wrqu->param.value == IW_AUTH_KEY_MGMT_802_1X) {
+                    priv->connection_config.authModeMask &= ~CSR_WIFI_SME_AUTH_MODE_8021X_WPA2PSK;
+                }
+                if (wrqu->param.value == IW_AUTH_KEY_MGMT_PSK) {
+                    priv->connection_config.authModeMask &= ~CSR_WIFI_SME_AUTH_MODE_8021X_WPA2;
+                }
+                unifi_trace(priv, UDBG5, "IW_AUTH_KEY_MGMT: WPA2: %d\n",
+                            priv->connection_config.authModeMask);
+            }
+
+            break;
+        case IW_AUTH_TKIP_COUNTERMEASURES:
+            /*
+             * Set to true at the start of the 60 second backup-off period
+             * following 2 MichaelMIC failures within 60s.
+             */
+            unifi_trace(priv, UDBG1, "IW_AUTH_TKIP_COUNTERMEASURES: %d\n", wrqu->param.value);
+            break;
+
+        case IW_AUTH_DROP_UNENCRYPTED:
+            /*
+             * Set to true on init.
+             * Set to false just before associate if encryption will not be
+             * required.
+             *
+             * Note this is not the same as the 802.1X controlled port
+             */
+            unifi_trace(priv, UDBG1, "IW_AUTH_DROP_UNENCRYPTED: %d\n", wrqu->param.value);
+            break;
+
+        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+            /*
+             * This is set by wpa_supplicant to allow unencrypted EAPOL messages
+             * even if pairwise keys are set when not using WPA. IEEE 802.1X
+             * specifies that these frames are not encrypted, but WPA encrypts
+             * them when pairwise keys are in use.
+             * I think the UniFi f/w handles this decision for us.
+             */
+            unifi_trace(priv, UDBG1, "IW_AUTH_RX_UNENCRYPTED_EAPOL: %d\n", wrqu->param.value);
+            break;
+
+        case IW_AUTH_ROAMING_CONTROL:
+            unifi_trace(priv, UDBG1, "IW_AUTH_ROAMING_CONTROL: %d\n", wrqu->param.value);
+            break;
+
+        default:
+            unifi_trace(priv, UDBG1, "Unsupported auth param %d to 0x%X\n",
+                        wrqu->param.flags & IW_AUTH_INDEX,
+                        wrqu->param.value);
+            return -EOPNOTSUPP;
+    }
+
+    unifi_trace(priv, UDBG2, "authModeMask = %d", priv->connection_config.authModeMask);
+    func_exit();
+
+    return 0;
+} /* _unifi_siwauth() */
+
+
+static int
+unifi_siwauth(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    int err = 0;
+
+    UF_RTNL_UNLOCK();
+    err = _unifi_siwauth(dev, info, wrqu, extra);
+    UF_RTNL_LOCK();
+
+    return err;
+} /* unifi_siwauth() */
+
+
+static int
+unifi_giwauth(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    unifi_trace(NULL, UDBG2, "unifi_giwauth\n");
+    return -EOPNOTSUPP;
+} /* unifi_giwauth() */
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_siwencodeext
+ *  unifi_giwencodeext
+ *
+ *      Handlers for SIOCSIWENCODEEXT, SIOCGIWENCODEEXT - set/get
+ *      encoding token & mode
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *      For WPA/WPA2 we don't take note of the IW_ENCODE_EXT_SET_TX_KEY flag.
+ *      This flag means "use this key to encode transmissions"; we just
+ *      assume only one key will be set and that is the one to use.
+ * ---------------------------------------------------------------------------
+ */
+static int
+_unifi_siwencodeext(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+    int r = 0;
+    unsigned char *keydata;
+    unsigned char tkip_key[32];
+    int keyid;
+    unsigned char *a = (unsigned char *)ext->addr.sa_data;
+    CsrWifiSmeKey sme_key;
+    CsrWifiSmeKeyType key_type;
+
+    func_enter();
+
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwencodeext: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    unifi_trace(priv, UDBG1, "siwencodeext: flags=0x%X, alg=%d, ext_flags=0x%X, len=%d, index=%d,\n",
+                wrqu->encoding.flags, ext->alg, ext->ext_flags,
+                ext->key_len, (wrqu->encoding.flags & IW_ENCODE_INDEX));
+    unifi_trace(priv, UDBG3, "              addr=%02X:%02X:%02X:%02X:%02X:%02X\n",
+                a[0], a[1], a[2], a[3], a[4], a[5]);
+
+    if ((ext->key_len == 0) && (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
+        /* This means use a different key (given by key_idx) for Tx. */
+        /* NYI */
+        unifi_trace(priv, UDBG1, KERN_ERR "unifi_siwencodeext: NYI should change tx key id here!!\n");
+        return -ENOTSUPP;
+    }
+
+    memset(&sme_key, 0, sizeof(sme_key));
+
+    keydata = (unsigned char *)(ext + 1);
+    keyid = (wrqu->encoding.flags & IW_ENCODE_INDEX);
+
+    /*
+     * Check for request to delete keys for an address.
+     */
+    /* Pick out request for no privacy. */
+    if (ext->alg == IW_ENCODE_ALG_NONE) {
+
+        unifi_trace(priv, UDBG1, "Deleting %s key %d\n",
+                    (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ? "GROUP" : "PAIRWISE",
+                    keyid);
+
+        if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+            sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_GROUP;
+        } else {
+            sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_PAIRWISE;
+        }
+        sme_key.keyIndex = (keyid - 1);
+        sme_key.keyLength = 0;
+        sme_key.authenticator = 0;
+        memcpy(sme_key.address.a, a, ETH_ALEN);
+        UF_RTNL_UNLOCK();
+        r = sme_mgt_key(priv, &sme_key, CSR_WIFI_SME_LIST_ACTION_REMOVE);
+        UF_RTNL_LOCK();
+        if (r) {
+            unifi_error(priv, "Delete key request was rejected with result %d\n", r);
+            return convert_sme_error(r);
+        }
+
+        return 0;
+    }
+
+    /*
+     * Request is to set a key, not delete
+     */
+
+    /* Pick out WEP and use set_wep_key(). */
+    if (ext->alg == IW_ENCODE_ALG_WEP) {
+        /* WEP-40, WEP-104 */
+
+        /* Check for valid key length */
+        if (!((ext->key_len == 5) || (ext->key_len == 13))) {
+            unifi_trace(priv, UDBG1, KERN_ERR "Invalid length for WEP key: %d\n", ext->key_len);
+            return -EINVAL;
+        }
+
+        unifi_trace(priv, UDBG1, "Setting WEP key %d tx:%d\n",
+                    keyid, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY);
+
+        if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+            sme_key.wepTxKey = TRUE;
+            sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_PAIRWISE;
+        } else {
+            sme_key.wepTxKey = FALSE;
+            sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_GROUP;
+        }
+        sme_key.keyIndex = (keyid - 1);
+        sme_key.keyLength = ext->key_len;
+        sme_key.authenticator = 0;
+        memset(sme_key.address.a, 0xFF, ETH_ALEN);
+        memcpy(sme_key.key, keydata, ext->key_len);
+        UF_RTNL_UNLOCK();
+        r = sme_mgt_key(priv, &sme_key, CSR_WIFI_SME_LIST_ACTION_ADD);
+        UF_RTNL_LOCK();
+        if (r) {
+            unifi_error(priv, "siwencodeext: Set key failed (%d)", r);
+            return convert_sme_error(r);
+        }
+
+        return 0;
+    }
+
+    /*
+     *
+     * If we reach here, we are dealing with a WPA/WPA2 key
+     *
+     */
+    if (ext->key_len > 32) {
+        return -EINVAL;
+    }
+
+    /*
+     * TKIP keys from wpa_supplicant need swapping.
+     * What about other supplicants (when they come along)?
+     */
+    if ((ext->alg == IW_ENCODE_ALG_TKIP) && (ext->key_len == 32)) {
+        memcpy(tkip_key, keydata, 16);
+        memcpy(tkip_key + 16, keydata + 24, 8);
+        memcpy(tkip_key + 24, keydata + 16, 8);
+        keydata = tkip_key;
+    }
+
+    key_type = (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ?
+        CSR_WIFI_SME_KEY_TYPE_GROUP : /* Group Key */
+        CSR_WIFI_SME_KEY_TYPE_PAIRWISE; /* Pairwise Key */
+
+    sme_key.keyType = key_type;
+    sme_key.keyIndex = (keyid - 1);
+    sme_key.keyLength = ext->key_len;
+    sme_key.authenticator = 0;
+    memcpy(sme_key.address.a, ext->addr.sa_data, ETH_ALEN);
+    if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+
+        unifi_trace(priv, UDBG5, "RSC first 6 bytes = %02X:%02X:%02X:%02X:%02X:%02X\n",
+                    ext->rx_seq[0], ext->rx_seq[1], ext->rx_seq[2], ext->rx_seq[3], ext->rx_seq[4], ext->rx_seq[5]);
+
+        /* memcpy((u8*)(&sme_key.keyRsc), ext->rx_seq, 8); */
+        sme_key.keyRsc[0] = ext->rx_seq[1] << 8 | ext->rx_seq[0];
+        sme_key.keyRsc[1] = ext->rx_seq[3] << 8 | ext->rx_seq[2];
+        sme_key.keyRsc[2] = ext->rx_seq[5] << 8 | ext->rx_seq[4];
+        sme_key.keyRsc[3] = ext->rx_seq[7] << 8 | ext->rx_seq[6];
+
+    }
+
+    memcpy(sme_key.key, keydata, ext->key_len);
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_key(priv, &sme_key, CSR_WIFI_SME_LIST_ACTION_ADD);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "SETKEYS request was rejected with result %d\n", r);
+        return convert_sme_error(r);
+    }
+
+    func_exit();
+    return r;
+} /* _unifi_siwencodeext() */
+
+
+static int
+unifi_siwencodeext(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    int err = 0;
+
+    err = _unifi_siwencodeext(dev, info, wrqu, extra);
+
+    return err;
+} /* unifi_siwencodeext() */
+
+
+static int
+unifi_giwencodeext(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    return -EOPNOTSUPP;
+} /* unifi_giwencodeext() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_siwpmksa
+ *
+ *      SIOCSIWPMKSA - PMKSA cache operation
+ *      The caller passes a pmksa structure:
+ *        - cmd         one of ADD, REMOVE, FLUSH
+ *        - bssid       MAC address
+ *        - pmkid       ID string (16 bytes)
+ *
+ *  Arguments:
+ *      None.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *      This is not needed since we provide a siwgenie method.
+ * ---------------------------------------------------------------------------
+ */
+#define UNIFI_PMKID_KEY_SIZE 16
+static int
+unifi_siwpmksa(struct net_device *dev, struct iw_request_info *info,
+        union iwreq_data *wrqu, char *extra)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+    struct iw_pmksa *pmksa = (struct iw_pmksa *)extra;
+    CsrResult r = 0;
+    CsrWifiSmePmkidList pmkid_list;
+    CsrWifiSmePmkid pmkid;
+    CsrWifiSmeListAction action;
+
+    CHECK_INITED(priv);
+
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+       unifi_error(priv, "unifi_siwpmksa: not permitted in Mode %d\n",
+                                      interfacePriv->interfaceMode);
+       return -EPERM;
+    }
+
+
+    unifi_trace(priv, UDBG1, "SIWPMKSA: cmd %d, %02x:%02x:%02x:%02x:%02x:%02x\n",
+                pmksa->cmd,
+                pmksa->bssid.sa_data[0],
+                pmksa->bssid.sa_data[1],
+                pmksa->bssid.sa_data[2],
+                pmksa->bssid.sa_data[3],
+                pmksa->bssid.sa_data[4],
+                pmksa->bssid.sa_data[5]);
+
+    pmkid_list.pmkids = NULL;
+    switch (pmksa->cmd) {
+      case IW_PMKSA_ADD:
+        pmkid_list.pmkids = &pmkid;
+        action = CSR_WIFI_SME_LIST_ACTION_ADD;
+        pmkid_list.pmkidsCount = 1;
+        memcpy(pmkid.bssid.a, pmksa->bssid.sa_data, ETH_ALEN);
+        memcpy(pmkid.pmkid, pmksa->pmkid, UNIFI_PMKID_KEY_SIZE);
+        break;
+      case IW_PMKSA_REMOVE:
+        pmkid_list.pmkids = &pmkid;
+        action = CSR_WIFI_SME_LIST_ACTION_REMOVE;
+        pmkid_list.pmkidsCount = 1;
+        memcpy(pmkid.bssid.a, pmksa->bssid.sa_data, ETH_ALEN);
+        memcpy(pmkid.pmkid, pmksa->pmkid, UNIFI_PMKID_KEY_SIZE);
+        break;
+      case IW_PMKSA_FLUSH:
+        /* Replace current PMKID's with an empty list */
+        pmkid_list.pmkidsCount = 0;
+        action = CSR_WIFI_SME_LIST_ACTION_FLUSH;
+        break;
+      default:
+        unifi_notice(priv, "SIWPMKSA: Unknown command (0x%x)\n", pmksa->cmd);
+        return -EINVAL;
+    }
+
+    /* Set the Value the pmkid's will have 1 added OR 1 removed OR be cleared at this point */
+    UF_RTNL_UNLOCK();
+    r = sme_mgt_pmkid(priv, action, &pmkid_list);
+    UF_RTNL_LOCK();
+    if (r) {
+        unifi_error(priv, "SIWPMKSA: Set PMKID's Failed.\n");
+    }
+
+    return r;
+
+} /* unifi_siwpmksa() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_get_wireless_stats
+ *
+ *      get_wireless_stats method for Linux wireless extensions.
+ *
+ *  Arguments:
+ *      dev             Pointer to associated netdevice.
+ *
+ *  Returns:
+ *      Pointer to iw_statistics struct.
+ * ---------------------------------------------------------------------------
+ */
+struct iw_statistics *
+unifi_get_wireless_stats(struct net_device *dev)
+{
+    netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
+    unifi_priv_t *priv = interfacePriv->privPtr;
+
+    if (priv->init_progress != UNIFI_INIT_COMPLETED) {
+        return NULL;
+    }
+
+    return &priv->wext_wireless_stats;
+} /* unifi_get_wireless_stats() */
+
+
+/*
+ * Structures to export the Wireless Handlers
+ */
+
+static const struct iw_priv_args unifi_private_args[] = {
+    /*{ cmd,         set_args,                            get_args, name } */
+    { SIOCIWS80211POWERSAVEPRIV, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE, "iwprivs80211ps" },
+    { SIOCIWG80211POWERSAVEPRIV, IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IWPRIV_POWER_SAVE_MAX_STRING, "iwprivg80211ps" },
+    { SIOCIWS80211RELOADDEFAULTSPRIV, IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_NONE, "iwprivsdefs" },
+    { SIOCIWSSMEDEBUGPRIV, IW_PRIV_TYPE_CHAR | IWPRIV_SME_DEBUG_MAX_STRING, IW_PRIV_TYPE_NONE, "iwprivssmedebug" },
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+    { SIOCIWSCONFWAPIPRIV, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE, "iwprivsconfwapi" },
+    { SIOCIWSWAPIKEYPRIV, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof(unifiio_wapi_key_t),
+        IW_PRIV_TYPE_NONE, "iwprivswpikey" },
+#endif
+#ifdef CSR_SUPPORT_WEXT_AP
+    { SIOCIWSAPCFGPRIV, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_NONE, "AP_SET_CFG" },
+    { SIOCIWSAPSTARTPRIV, 0,IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED|IWPRIV_SME_MAX_STRING,"AP_BSS_START" },
+    { SIOCIWSAPSTOPPRIV, IW_PRIV_TYPE_CHAR |IW_PRIV_SIZE_FIXED|0,
+      IW_PRIV_TYPE_CHAR |IW_PRIV_SIZE_FIXED|0, "AP_BSS_STOP" },
+#ifdef ANDROID_BUILD
+    { SIOCIWSFWRELOADPRIV, IW_PRIV_TYPE_CHAR |256,
+      IW_PRIV_TYPE_CHAR |IW_PRIV_SIZE_FIXED|0, "WL_FW_RELOAD" },
+    { SIOCIWSSTACKSTART, 0,
+      IW_PRIV_TYPE_CHAR |IW_PRIV_SIZE_FIXED|IWPRIV_SME_MAX_STRING, "START" },
+    { SIOCIWSSTACKSTOP, 0,
+      IW_PRIV_TYPE_CHAR |IW_PRIV_SIZE_FIXED|IWPRIV_SME_MAX_STRING, "STOP" },
+#endif /* ANDROID_BUILD */
+#endif /* CSR_SUPPORT_WEXT_AP */
+};
+
+static const iw_handler unifi_handler[] =
+{
+    (iw_handler) unifi_siwcommit,           /* SIOCSIWCOMMIT */
+    (iw_handler) unifi_giwname,             /* SIOCGIWNAME */
+    (iw_handler) NULL,                      /* SIOCSIWNWID */
+    (iw_handler) NULL,                      /* SIOCGIWNWID */
+    (iw_handler) unifi_siwfreq,             /* SIOCSIWFREQ */
+    (iw_handler) unifi_giwfreq,             /* SIOCGIWFREQ */
+    (iw_handler) unifi_siwmode,             /* SIOCSIWMODE */
+    (iw_handler) unifi_giwmode,             /* SIOCGIWMODE */
+    (iw_handler) NULL,                      /* SIOCSIWSENS */
+    (iw_handler) NULL,                      /* SIOCGIWSENS */
+    (iw_handler) NULL,                      /* SIOCSIWRANGE */
+    (iw_handler) unifi_giwrange,            /* SIOCGIWRANGE */
+    (iw_handler) NULL,                      /* SIOCSIWPRIV */
+    (iw_handler) NULL,                      /* SIOCGIWPRIV */
+    (iw_handler) NULL,                      /* SIOCSIWSTATS */
+    (iw_handler) NULL,                      /* SIOCGIWSTATS */
+    (iw_handler) NULL,                      /* SIOCSIWSPY */
+    (iw_handler) NULL,                      /* SIOCGIWSPY */
+    (iw_handler) NULL,                      /* SIOCSIWTHRSPY */
+    (iw_handler) NULL,                      /* SIOCGIWTHRSPY */
+    (iw_handler) unifi_siwap,               /* SIOCSIWAP */
+    (iw_handler) unifi_giwap,               /* SIOCGIWAP */
+#if WIRELESS_EXT > 17
+    /* WPA : IEEE 802.11 MLME requests */
+    unifi_siwmlme,              /* SIOCSIWMLME, request MLME operation */
+#else
+    (iw_handler) NULL,                      /* -- hole -- */
+#endif
+    (iw_handler) NULL,                      /* SIOCGIWAPLIST */
+    (iw_handler) unifi_siwscan,             /* SIOCSIWSCAN */
+    (iw_handler) unifi_giwscan,             /* SIOCGIWSCAN */
+    (iw_handler) unifi_siwessid,            /* SIOCSIWESSID */
+    (iw_handler) unifi_giwessid,            /* SIOCGIWESSID */
+    (iw_handler) NULL,                      /* SIOCSIWNICKN */
+    (iw_handler) NULL,                      /* SIOCGIWNICKN */
+    (iw_handler) NULL,                      /* -- hole -- */
+    (iw_handler) NULL,                      /* -- hole -- */
+    unifi_siwrate,                          /* SIOCSIWRATE */
+    unifi_giwrate,                          /* SIOCGIWRATE */
+    unifi_siwrts,                           /* SIOCSIWRTS */
+    unifi_giwrts,                           /* SIOCGIWRTS */
+    unifi_siwfrag,                          /* SIOCSIWFRAG */
+    unifi_giwfrag,                          /* SIOCGIWFRAG */
+    (iw_handler) NULL,                      /* SIOCSIWTXPOW */
+    (iw_handler) NULL,                      /* SIOCGIWTXPOW */
+    (iw_handler) NULL,                      /* SIOCSIWRETRY */
+    (iw_handler) NULL,                      /* SIOCGIWRETRY */
+    unifi_siwencode,                        /* SIOCSIWENCODE */
+    unifi_giwencode,                        /* SIOCGIWENCODE */
+    unifi_siwpower,                         /* SIOCSIWPOWER */
+    unifi_giwpower,                         /* SIOCGIWPOWER */
+#if WIRELESS_EXT > 17
+    (iw_handler) NULL,                      /* -- hole -- */
+    (iw_handler) NULL,                      /* -- hole -- */
+
+    /* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM). */
+    unifi_siwgenie,             /* SIOCSIWGENIE */      /* set generic IE */
+    unifi_giwgenie,             /* SIOCGIWGENIE */      /* get generic IE */
+
+    /* WPA : Authentication mode parameters */
+    unifi_siwauth,              /* SIOCSIWAUTH */       /* set authentication mode params */
+    unifi_giwauth,              /* SIOCGIWAUTH */       /* get authentication mode params */
+
+    /* WPA : Extended version of encoding configuration */
+    unifi_siwencodeext,         /* SIOCSIWENCODEEXT */  /* set encoding token & mode */
+    unifi_giwencodeext,         /* SIOCGIWENCODEEXT */  /* get encoding token & mode */
+
+    /* WPA2 : PMKSA cache management */
+    unifi_siwpmksa,             /* SIOCSIWPMKSA */      /* PMKSA cache operation */
+    (iw_handler) NULL,          /* -- hole -- */
+#endif /* WIRELESS_EXT > 17 */
+};
+
+
+static const iw_handler unifi_private_handler[] =
+{
+    iwprivs80211ps,                 /* SIOCIWFIRSTPRIV */
+    iwprivg80211ps,                 /* SIOCIWFIRSTPRIV + 1 */
+    iwprivsdefs,                    /* SIOCIWFIRSTPRIV + 2 */
+    (iw_handler) NULL,
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+    iwprivsconfwapi,                /* SIOCIWFIRSTPRIV + 4 */
+    (iw_handler) NULL,              /* SIOCIWFIRSTPRIV + 5 */
+    iwprivswpikey,                  /* SIOCIWFIRSTPRIV + 6 */
+#else
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+#endif
+    (iw_handler) NULL,
+    iwprivssmedebug,                /* SIOCIWFIRSTPRIV + 8 */
+#ifdef CSR_SUPPORT_WEXT_AP
+    (iw_handler) NULL,
+    iwprivsapconfig,
+    (iw_handler) NULL,
+    iwprivsapstart,
+    (iw_handler) NULL,
+    iwprivsapstop,
+    (iw_handler) NULL,
+#ifdef ANDROID_BUILD
+    iwprivsapfwreload,
+    (iw_handler) NULL,
+    iwprivsstackstart,
+    (iw_handler) NULL,
+    iwprivsstackstop,
+#else
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+#endif /* ANDROID_BUILD */
+#else
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+    (iw_handler) NULL,
+#endif /* CSR_SUPPORT_WEXT_AP */
+};
+
+struct iw_handler_def unifi_iw_handler_def =
+{
+    .num_standard       = sizeof(unifi_handler) / sizeof(iw_handler),
+    .num_private        = sizeof(unifi_private_handler) / sizeof(iw_handler),
+    .num_private_args   = sizeof(unifi_private_args) / sizeof(struct iw_priv_args),
+    .standard           = (iw_handler *) unifi_handler,
+    .private            = (iw_handler *) unifi_private_handler,
+    .private_args       = (struct iw_priv_args *) unifi_private_args,
+#if IW_HANDLER_VERSION >= 6
+    .get_wireless_stats = unifi_get_wireless_stats,
+#endif
+};
+
+
diff --git a/drivers/staging/csr/ul_int.c b/drivers/staging/csr/ul_int.c
new file mode 100644
index 0000000..958b8a1
--- /dev/null
+++ b/drivers/staging/csr/ul_int.c
@@ -0,0 +1,533 @@
+/*
+ * ***************************************************************************
+ *  FILE:     ul_int.c
+ *
+ *  PURPOSE:
+ *      Manage list of client applications using UniFi.
+ *
+ * Copyright (C) 2006-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ***************************************************************************
+ */
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_conversions.h"
+#include "unifi_priv.h"
+#include "unifiio.h"
+#include "unifi_os.h"
+
+static void free_bulkdata_buffers(unifi_priv_t *priv, bulk_data_param_t *bulkdata);
+static void reset_driver_status(unifi_priv_t *priv);
+
+/*
+ * ---------------------------------------------------------------------------
+ *  ul_init_clients
+ *
+ *      Initialise the clients array to empty.
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *      This function needs to be called before priv is stored in
+ *      Unifi_instances[].
+ * ---------------------------------------------------------------------------
+ */
+void
+ul_init_clients(unifi_priv_t *priv)
+{
+    int id;
+    ul_client_t *ul_clients;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+    sema_init(&priv->udi_logging_mutex, 1);
+#else
+    init_MUTEX(&priv->udi_logging_mutex);
+#endif
+    priv->logging_client = NULL;
+
+    ul_clients = priv->ul_clients;
+
+    for (id = 0; id < MAX_UDI_CLIENTS; id++) {
+        memset(&ul_clients[id], 0, sizeof(ul_client_t));
+
+        ul_clients[id].client_id = id;
+        ul_clients[id].sender_id = UDI_SENDER_ID_BASE + (id << UDI_SENDER_ID_SHIFT);
+        ul_clients[id].instance = -1;
+        ul_clients[id].event_hook = NULL;
+
+        INIT_LIST_HEAD(&ul_clients[id].udi_log);
+        init_waitqueue_head(&ul_clients[id].udi_wq);
+        sema_init(&ul_clients[id].udi_sem, 1);
+
+        ul_clients[id].wake_up_wq_id = 0;
+        ul_clients[id].seq_no = 0;
+        ul_clients[id].wake_seq_no = 0;
+        ul_clients[id].snap_filter.count = 0;
+    }
+} /* ul_init_clients() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  ul_register_client
+ *
+ *      This function registers a new ul client.
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *      configuration   Special configuration for the client.
+ *      udi_event_clbk  Callback for receiving event from unifi.
+ *
+ *  Returns:
+ *      0 if a new clients is registered, -1 otherwise.
+ * ---------------------------------------------------------------------------
+ */
+ul_client_t *
+ul_register_client(unifi_priv_t *priv, unsigned int configuration,
+                   udi_event_t udi_event_clbk)
+{
+    unsigned char id, ref;
+    ul_client_t *ul_clients;
+
+    ul_clients = priv->ul_clients;
+
+    /* check for an unused entry */
+    for (id = 0; id < MAX_UDI_CLIENTS; id++) {
+        if (ul_clients[id].udi_enabled == 0) {
+            ul_clients[id].instance = priv->instance;
+            ul_clients[id].udi_enabled = 1;
+            ul_clients[id].configuration = configuration;
+
+            /* Allocate memory for the reply signal.. */
+            ul_clients[id].reply_signal = (CSR_SIGNAL*) CsrPmemAlloc(sizeof(CSR_SIGNAL));
+            if (ul_clients[id].reply_signal == NULL) {
+                unifi_error(priv, "Failed to allocate reply signal for client.\n");
+                return NULL;
+            }
+            /* .. and the bulk data of the reply signal. */
+            for (ref = 0; ref < UNIFI_MAX_DATA_REFERENCES; ref ++) {
+                ul_clients[id].reply_bulkdata[ref] =
+                        (bulk_data_t*) CsrPmemAlloc(sizeof(bulk_data_t));
+                /* If allocation fails, free allocated memory. */
+                if (ul_clients[id].reply_bulkdata[ref] == NULL) {
+                    for (; ref > 0; ref --) {
+                        CsrPmemFree(ul_clients[id].reply_bulkdata[ref - 1]);
+                    }
+                    CsrPmemFree(ul_clients[id].reply_signal);
+                    unifi_error(priv, "Failed to allocate bulk data buffers for client.\n");
+                    return NULL;
+                }
+            }
+
+            /* Set the event callback. */
+            ul_clients[id].event_hook = udi_event_clbk;
+
+            unifi_trace(priv, UDBG2, "UDI %d (0x%x) registered. configuration = 0x%x\n",
+                        id, &ul_clients[id], configuration);
+            return &ul_clients[id];
+        }
+    }
+    return NULL;
+} /* ul_register_client() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  ul_deregister_client
+ *
+ *      This function deregisters a blocking UDI client.
+ *
+ *  Arguments:
+ *      client      Pointer to the client we deregister.
+ *
+ *  Returns:
+ *      0 if a new clients is deregistered.
+ * ---------------------------------------------------------------------------
+ */
+int
+ul_deregister_client(ul_client_t *ul_client)
+{
+    struct list_head *pos, *n;
+    udi_log_t *logptr;
+    unifi_priv_t *priv = uf_find_instance(ul_client->instance);
+    int ref;
+
+    ul_client->instance = -1;
+    ul_client->event_hook = NULL;
+    ul_client->udi_enabled = 0;
+    unifi_trace(priv, UDBG5, "UDI (0x%x) deregistered.\n", ul_client);
+
+    /* Free memory allocated for the reply signal and its bulk data. */
+    CsrPmemFree(ul_client->reply_signal);
+    for (ref = 0; ref < UNIFI_MAX_DATA_REFERENCES; ref ++) {
+        CsrPmemFree(ul_client->reply_bulkdata[ref]);
+    }
+
+    if (ul_client->snap_filter.count) {
+        ul_client->snap_filter.count = 0;
+        CsrPmemFree(ul_client->snap_filter.protocols);
+    }
+
+    /* Free anything pending on the udi_log list */
+    down(&ul_client->udi_sem);
+    list_for_each_safe(pos, n, &ul_client->udi_log)
+    {
+        logptr = list_entry(pos, udi_log_t, q);
+        list_del(pos);
+        kfree(logptr);
+    }
+    up(&ul_client->udi_sem);
+
+    return 0;
+} /* ul_deregister_client() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  logging_handler
+ *
+ *      This function is registered with the driver core.
+ *      It is called every time a UniFi HIP Signal is sent. It iterates over
+ *      the list of processes interested in receiving log events and
+ *      delivers the events to them.
+ *
+ *  Arguments:
+ *      ospriv      Pointer to driver's private data.
+ *      sigdata     Pointer to the packed signal buffer.
+ *      signal_len  Length of the packed signal.
+ *      bulkdata    Pointer to the signal's bulk data.
+ *      dir         Direction of the signal
+ *                  0 = from-host
+ *                  1 = to-host
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+logging_handler(void *ospriv,
+                CsrUint8 *sigdata, CsrUint32 signal_len,
+                const bulk_data_param_t *bulkdata,
+                enum udi_log_direction direction)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+    ul_client_t *client;
+    int dir;
+
+    dir = (direction == UDI_LOG_FROM_HOST) ? UDI_FROM_HOST : UDI_TO_HOST;
+
+    down(&priv->udi_logging_mutex);
+    client = priv->logging_client;
+    if (client != NULL) {
+        client->event_hook(client, sigdata, signal_len,
+                           bulkdata, dir);
+    }
+    up(&priv->udi_logging_mutex);
+
+} /* logging_handler() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  ul_log_config_ind
+ *
+ *      This function uses the client's register callback
+ *      to indicate configuration information e.g core errors.
+ *
+ *  Arguments:
+ *      priv        Pointer to driver's private data.
+ *      conf_param  Pointer to the configuration data.
+ *      len         Length of the configuration data.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+ul_log_config_ind(unifi_priv_t *priv, u8 *conf_param, int len)
+{
+#ifdef CSR_SUPPORT_SME
+    if (priv->smepriv == NULL)
+    {
+        return;
+    }
+    if ((CONFIG_IND_ERROR == (*conf_param)) && (priv->wifi_on_state == wifi_on_in_progress)) {
+        unifi_notice(priv, "ul_log_config_ind: wifi on in progress, suppress error\n");
+    } else {
+        /* wifi_off_ind (error or exit) */
+        CsrWifiRouterCtrlWifiOffIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, (CsrWifiRouterCtrlControlIndication)(*conf_param));
+    }
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+    unifi_debug_buf_dump();
+#endif
+#else
+    bulk_data_param_t bulkdata;
+
+    /*
+     * If someone killed unifi_managed before the driver was unloaded
+     * the g_drvpriv pointer is going to be NULL. In this case it is
+     * safe to assume that there is no client to get the indication.
+     */
+    if (!priv) {
+        unifi_notice(NULL, "uf_sme_event_ind: NULL priv\n");
+        return;
+    }
+
+    /* Create a null bulkdata structure. */
+    bulkdata.d[0].data_length = 0;
+    bulkdata.d[1].data_length = 0;
+
+    sme_native_log_event(priv->sme_cli, conf_param, sizeof(CsrUint8),
+                         &bulkdata, UDI_CONFIG_IND);
+
+#endif /* CSR_SUPPORT_SME */
+
+} /* ul_log_config_ind */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  free_bulkdata_buffers
+ *
+ *      Free the bulkdata buffers e.g. after a failed unifi_send_signal().
+ *
+ *  Arguments:
+ *      priv        Pointer to device private struct
+ *      bulkdata    Pointer to bulkdata parameter table
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void
+free_bulkdata_buffers(unifi_priv_t *priv, bulk_data_param_t *bulkdata)
+{
+    int i;
+
+    if (bulkdata) {
+        for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; ++i) {
+            if (bulkdata->d[i].data_length != 0) {
+                unifi_net_data_free(priv, (bulk_data_desc_t *)(&bulkdata->d[i]));
+                /* data_length is now 0 */
+            }
+        }
+    }
+
+} /* free_bulkdata_buffers */
+
+static int
+_align_bulk_data_buffers(unifi_priv_t *priv, CsrUint8 *signal,
+                         bulk_data_param_t *bulkdata)
+{
+    unsigned int i;
+
+    if ((bulkdata == NULL) || (CSR_WIFI_ALIGN_BYTES == 0)) {
+        return 0;
+    }
+
+    for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++)
+    {
+        struct sk_buff *skb;
+        /*
+        * The following complex casting is in place in order to eliminate 64-bit compilation warning
+        * "cast to/from pointer from/to integer of different size"
+        */
+        CsrUint32 align_offset = (CsrUint32)(long)(bulkdata->d[i].os_data_ptr) & (CSR_WIFI_ALIGN_BYTES-1);
+        if (align_offset)
+        {
+            skb = (struct sk_buff*)bulkdata->d[i].os_net_buf_ptr;
+            if (skb == NULL) {
+                unifi_warning(priv,
+                              "_align_bulk_data_buffers: Align offset found (%d) but skb is NULL!\n",
+                              align_offset);
+                return -EINVAL;
+            }
+            if (bulkdata->d[i].data_length == 0) {
+                unifi_warning(priv,
+                              "_align_bulk_data_buffers: Align offset found (%d) but length is zero\n",
+                              align_offset);
+                return CSR_RESULT_SUCCESS;
+            }
+            unifi_trace(priv, UDBG5,
+                        "Align f-h buffer (0x%p) by %d bytes (skb->data: 0x%p)\n",
+                        bulkdata->d[i].os_data_ptr, align_offset, skb->data);
+
+
+            /* Check if there is enough headroom... */
+            if (unlikely(skb_headroom(skb) < align_offset))
+            {
+                struct sk_buff *tmp = skb;
+
+                unifi_trace(priv, UDBG5, "Headroom not enough - realloc it\n");
+                skb = skb_realloc_headroom(skb, align_offset);
+                if (skb == NULL) {
+                    unifi_error(priv,
+                                "_align_bulk_data_buffers: skb_realloc_headroom failed - signal is dropped\n");
+                    return -EFAULT;
+                }
+                /* Free the old bulk data only if allocation succeeds */
+                kfree_skb(tmp);
+                /* Bulkdata needs to point to the new skb */
+                bulkdata->d[i].os_net_buf_ptr = (const unsigned char*)skb;
+                bulkdata->d[i].os_data_ptr = (const void*)skb->data;
+            }
+            /* ... before pushing the data to the right alignment offset */
+            skb_push(skb, align_offset);
+
+        }
+        /* The direction bit is zero for the from-host */
+        signal[SIZEOF_SIGNAL_HEADER + (i * SIZEOF_DATAREF) + 1] = align_offset;
+
+    }
+    return 0;
+} /* _align_bulk_data_buffers() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  ul_send_signal_unpacked
+ *
+ *      This function sends a host formatted signal to unifi.
+ *
+ *  Arguments:
+ *      priv        Pointer to driver's private data.
+ *      sigptr      Pointer to the signal.
+ *      bulkdata    Pointer to the signal's bulk data.
+ *
+ *  Returns:
+ *      O on success, error code otherwise.
+ *
+ *  Notes:
+ *  The signals have to be sent in the format described in the host interface
+ *  specification, i.e wire formatted. Certain clients use the host formatted
+ *  structures. The write_pack() transforms the host formatted signal
+ *  into the wired formatted signal. The code is in the core, since the signals
+ *  are defined therefore binded to the host interface specification.
+ * ---------------------------------------------------------------------------
+ */
+int
+ul_send_signal_unpacked(unifi_priv_t *priv, CSR_SIGNAL *sigptr,
+                        bulk_data_param_t *bulkdata)
+{
+    CsrUint8 sigbuf[UNIFI_PACKED_SIGBUF_SIZE];
+    CsrUint16 packed_siglen;
+    CsrResult csrResult;
+    unsigned long lock_flags;
+    int r;
+
+
+    csrResult = write_pack(sigptr, sigbuf, &packed_siglen);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv, "Malformed HIP signal in ul_send_signal_unpacked()\n");
+        return CsrHipResultToStatus(csrResult);
+    }
+    r = _align_bulk_data_buffers(priv, sigbuf, (bulk_data_param_t*)bulkdata);
+    if (r) {
+        return r;
+    }
+
+    spin_lock_irqsave(&priv->send_signal_lock, lock_flags);
+    csrResult = unifi_send_signal(priv->card, sigbuf, packed_siglen, bulkdata);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+  /*      free_bulkdata_buffers(priv, (bulk_data_param_t *)bulkdata); */
+        spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
+        return CsrHipResultToStatus(csrResult);
+    }
+    spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
+
+    return 0;
+} /* ul_send_signal_unpacked() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  reset_driver_status
+ *
+ *      This function is called from ul_send_signal_raw() when it detects
+ *      that the SME has sent a MLME-RESET request.
+ *
+ *  Arguments:
+ *      priv        Pointer to device private struct
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+static void
+reset_driver_status(unifi_priv_t *priv)
+{
+    priv->sta_wmm_capabilities = 0;
+#ifdef CSR_NATIVE_LINUX
+#ifdef CSR_SUPPORT_WEXT
+    priv->wext_conf.flag_associated = 0;
+    priv->wext_conf.block_controlled_port = CSR_WIFI_ROUTER_PORT_ACTION_8021X_PORT_OPEN;
+    priv->wext_conf.bss_wmm_capabilities = 0;
+    priv->wext_conf.disable_join_on_ssid_set = 0;
+#endif
+#endif
+} /* reset_driver_status() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  ul_send_signal_raw
+ *
+ *      This function sends a wire formatted data signal to unifi.
+ *
+ *  Arguments:
+ *      priv        Pointer to driver's private data.
+ *      sigptr      Pointer to the signal.
+ *      siglen      Length of the signal.
+ *      bulkdata    Pointer to the signal's bulk data.
+ *
+ *  Returns:
+ *      O on success, error code otherwise.
+ * ---------------------------------------------------------------------------
+ */
+int
+ul_send_signal_raw(unifi_priv_t *priv, unsigned char *sigptr, int siglen,
+                   bulk_data_param_t *bulkdata)
+{
+    CsrResult csrResult;
+    unsigned long lock_flags;
+    int r;
+
+    /*
+     * Make sure that the signal is updated with the bulk data
+     * alignment for DMA.
+     */
+    r = _align_bulk_data_buffers(priv, (CsrUint8*)sigptr, bulkdata);
+    if (r) {
+        return r;
+    }
+
+    spin_lock_irqsave(&priv->send_signal_lock, lock_flags);
+    csrResult = unifi_send_signal(priv->card, sigptr, siglen, bulkdata);
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        free_bulkdata_buffers(priv, bulkdata);
+        spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
+        return CsrHipResultToStatus(csrResult);
+    }
+    spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
+
+    /*
+     * Since this is use by unicli, if we get an MLME reset request
+     * we need to initialize a few status parameters
+     * that the driver uses to make decisions.
+     */
+    if (GET_SIGNAL_ID(sigptr) == CSR_MLME_RESET_REQUEST_ID) {
+        reset_driver_status(priv);
+    }
+
+    return 0;
+} /* ul_send_signal_raw() */
+
+
diff --git a/drivers/staging/csr/unifi_clients.h b/drivers/staging/csr/unifi_clients.h
new file mode 100644
index 0000000..206b8cf
--- /dev/null
+++ b/drivers/staging/csr/unifi_clients.h
@@ -0,0 +1,129 @@
+/*
+ *****************************************************************************
+ *
+ * FILE : unifi_clients.h
+ *
+ * PURPOSE : Private header file for unifi clients.
+ *
+ *           UDI = UniFi Debug Interface
+ *
+ * Copyright (C) 2005-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ *****************************************************************************
+ */
+#ifndef __LINUX_UNIFI_CLIENTS_H__
+#define __LINUX_UNIFI_CLIENTS_H__ 1
+
+#include <linux/kernel.h>
+
+#define MAX_UDI_CLIENTS 8
+
+/* The start of the range of process ids allocated for ul clients */
+#define UDI_SENDER_ID_BASE      0xC000
+#define UDI_SENDER_ID_SHIFT     8
+
+
+/* Structure to hold a UDI logged signal */
+typedef struct {
+
+    /* List link structure */
+    struct list_head q;
+
+    /* The message that will be passed to the user app */
+    udi_msg_t msg;
+
+    /* Signal body and data follow */
+
+} udi_log_t;
+
+
+
+typedef struct ul_client ul_client_t;
+
+typedef void (*udi_event_t)(ul_client_t *client,
+                            const u8 *sigdata, int signal_len,
+                            const bulk_data_param_t *bulkdata,
+                            int dir);
+
+void logging_handler(void *ospriv,
+                     CsrUint8 *sigdata, CsrUint32 signal_len,
+                     const bulk_data_param_t *bulkdata,
+                     enum udi_log_direction direction);
+
+
+/*
+ * Structure describing a bulk data slot.
+ * The length field is used to indicate empty/occupied state.
+ */
+typedef struct _bulk_data
+{
+    unsigned char ptr[2000];
+    unsigned int length;
+} bulk_data_t;
+
+
+struct ul_client {
+    /* Index of this client in the ul_clients array. */
+    int client_id;
+
+    /* Index of UniFi device to which this client is attached. */
+    int instance;
+
+    /* Flag to say whether this client has been enabled. */
+    int udi_enabled;
+
+    /* Value to use in signal->SenderProcessId */
+    int sender_id;
+
+    /* Configuration flags, e.g blocking, logging, etc. */
+    unsigned int configuration;
+
+    udi_event_t event_hook;
+
+    /* A list to hold signals received from UniFi for reading by read() */
+    struct list_head udi_log;
+
+    /* Semaphore to protect the udi_log list */
+    struct semaphore udi_sem;
+
+    /*
+     * Linux waitqueue to support blocking read and poll.
+     * Logging clients should wait on udi_log. while
+     * blocking clients should wait on wake_up_wq.
+     */
+    wait_queue_head_t udi_wq;
+    CSR_SIGNAL* reply_signal;
+    bulk_data_t* reply_bulkdata[UNIFI_MAX_DATA_REFERENCES];
+
+    CsrUint16 signal_filter[SIG_FILTER_SIZE];
+
+
+    /* ------------------------------------------------------------------- */
+    /* Code below here is used by the sme_native configuration only */
+
+    /* Flag to wake up blocking clients waiting on udi_wq. */
+    int wake_up_wq_id;
+
+    /*
+     * A 0x00 - 0x0F mask to apply in signal->SenderProcessId.
+     * Every time we do a blocking mlme request we increase this value.
+     * The mlme_wait_for_reply() will wait for this sequence number.
+     * Only the MLME blocking functions update this field.
+     */
+    unsigned char seq_no;
+
+    /*
+     * A 0x00 - 0x0F counter, containing the sequence number of
+     * the signal that this client has last received.
+     * Only the MLME blocking functions update this field.
+     */
+    unsigned char wake_seq_no;
+
+    unifiio_snap_filter_t snap_filter;
+}; /* struct ul_client */
+
+
+#endif /* __LINUX_UNIFI_CLIENTS_H__ */
diff --git a/drivers/staging/csr/unifi_config.h b/drivers/staging/csr/unifi_config.h
new file mode 100644
index 0000000..fe11970
--- /dev/null
+++ b/drivers/staging/csr/unifi_config.h
@@ -0,0 +1,34 @@
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * FILE: unifi_config.h
+ *
+ * PURPOSE:
+ *      This header file provides parameters that configure the operation
+ *      of the driver.
+ *
+ * Copyright (C) 2006-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#ifndef __UNIFI_CONFIG_H__
+#define __UNIFI_CONFIG_H__ 1
+
+/*
+ * Override for the SDIO function block size on this host. When byte mode CMD53s
+ * are not used/supported by the SD host controller, transfers are padded up to
+ * the next block boundary. The 512-byte default on UF6xxx wastes too much space
+ * on the chip, so the block size is reduced to support this configuration.
+ */
+#define CSR_WIFI_HIP_SDIO_BLOCK_SIZE  64
+
+/* Define the number of mini-coredump buffers to allocate at startup. These are
+ * used to record chip status for the last n unexpected resets.
+ */
+#define CSR_WIFI_HIP_NUM_COREDUMP_BUFFERS  5
+
+
+#endif /* __UNIFI_CONFIG_H__ */
diff --git a/drivers/staging/csr/unifi_dbg.c b/drivers/staging/csr/unifi_dbg.c
new file mode 100644
index 0000000..38d5708
--- /dev/null
+++ b/drivers/staging/csr/unifi_dbg.c
@@ -0,0 +1,110 @@
+/*
+ * ***************************************************************************
+ *  FILE:     unifi_dbg.c
+ *
+ *  PURPOSE:
+ *      Handle debug signals received from UniFi.
+ *
+ * Copyright (C) 2007-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ***************************************************************************
+ */
+#include "unifi_priv.h"
+
+/*
+ * ---------------------------------------------------------------------------
+ *  debug_string_indication
+ *  debug_word16_indication
+ *
+ *      Handlers for debug indications.
+ *
+ *  Arguments:
+ *      priv            Pointer to private context structure.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+debug_string_indication(unifi_priv_t *priv, const unsigned char *extra, unsigned int extralen)
+{
+    const unsigned int maxlen = sizeof(priv->last_debug_string) - 1;
+
+    if (extralen > maxlen) {
+        extralen = maxlen;
+    }
+
+    strncpy(priv->last_debug_string, extra, extralen);
+
+    /* Make sure the string is terminated */
+    priv->last_debug_string[extralen] = '\0';
+
+    unifi_info(priv, "unifi debug: %s\n", priv->last_debug_string);
+
+} /* debug_string_indication() */
+
+
+
+void
+debug_word16_indication(unifi_priv_t *priv, const CSR_SIGNAL *sigptr)
+{
+    int i;
+
+    if (priv == NULL) {
+        unifi_info(priv, "Priv is NULL\n");
+        return;
+    }
+
+    for (i = 0; i < 16; i++) {
+        priv->last_debug_word16[i] =
+                sigptr->u.DebugWord16Indication.DebugWords[i];
+    }
+
+    if (priv->last_debug_word16[0] == 0xFA11) {
+        unsigned long ts;
+        ts = (priv->last_debug_word16[6] << 16) | priv->last_debug_word16[5];
+        unifi_info(priv, " %10lu: %s fault %04x, arg %04x (x%d)\n",
+                   ts,
+                   priv->last_debug_word16[3] == 0x8000 ? "MAC" :
+                   priv->last_debug_word16[3] == 0x4000 ? "PHY" :
+                   "???",
+                   priv->last_debug_word16[1],
+                   priv->last_debug_word16[2],
+                   priv->last_debug_word16[4]);
+    }
+    else if (priv->last_debug_word16[0] != 0xDBAC)
+        /* suppress SDL Trace output (note: still available to unicli). */
+    {
+        unifi_info(priv, "unifi debug: %04X %04X %04X %04X %04X %04X %04X %04X\n",
+                   priv->last_debug_word16[0], priv->last_debug_word16[1],
+                   priv->last_debug_word16[2], priv->last_debug_word16[3],
+                   priv->last_debug_word16[4], priv->last_debug_word16[5],
+                   priv->last_debug_word16[6], priv->last_debug_word16[7]);
+        unifi_info(priv, "             %04X %04X %04X %04X %04X %04X %04X %04X\n",
+                   priv->last_debug_word16[8], priv->last_debug_word16[9],
+                   priv->last_debug_word16[10], priv->last_debug_word16[11],
+                   priv->last_debug_word16[12], priv->last_debug_word16[13],
+                   priv->last_debug_word16[14], priv->last_debug_word16[15]);
+    }
+
+} /* debug_word16_indication() */
+
+
+void
+debug_generic_indication(unifi_priv_t *priv, const CSR_SIGNAL *sigptr)
+{
+    unifi_info(priv, "debug: %04X %04X %04X %04X %04X %04X %04X %04X\n",
+               sigptr->u.DebugGenericIndication.DebugWords[0],
+               sigptr->u.DebugGenericIndication.DebugWords[1],
+               sigptr->u.DebugGenericIndication.DebugWords[2],
+               sigptr->u.DebugGenericIndication.DebugWords[3],
+               sigptr->u.DebugGenericIndication.DebugWords[4],
+               sigptr->u.DebugGenericIndication.DebugWords[5],
+               sigptr->u.DebugGenericIndication.DebugWords[6],
+               sigptr->u.DebugGenericIndication.DebugWords[7]);
+
+} /* debug_generic_indication() */
+
diff --git a/drivers/staging/csr/unifi_event.c b/drivers/staging/csr/unifi_event.c
new file mode 100644
index 0000000..8b5d466
--- /dev/null
+++ b/drivers/staging/csr/unifi_event.c
@@ -0,0 +1,700 @@
+/*
+ * ***************************************************************************
+ *  FILE:     unifi_event.c
+ *
+ *  PURPOSE:
+ *      Process the signals received by UniFi.
+ *      It is part of the porting exercise.
+ *
+ * Copyright (C) 2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ***************************************************************************
+ */
+
+
+/*
+ * Porting notes:
+ * The implementation of unifi_receive_event() in Linux is fairly complicated.
+ * The linux driver support multiple userspace applications and several
+ * build configurations, so the received signals are processed by different
+ * processes and multiple times.
+ * In a simple implementation, this function needs to deliver:
+ * - The MLME-UNITDATA.ind signals to the Rx data plane and to the Traffic
+ *   Analysis using unifi_ta_sample().
+ * - The MLME-UNITDATA-STATUS.ind signals to the Tx data plane.
+ * - All the other signals to the SME using unifi_sys_hip_ind().
+ */
+
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_conversions.h"
+#include "unifi_priv.h"
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  send_to_client
+ *
+ *      Helper for unifi_receive_event.
+ *
+ *      This function forwards a signal to one client.
+ *
+ *  Arguments:
+ *      priv        Pointer to driver's private data.
+ *      client      Pointer to the client structure.
+ *      receiver_id The reciever id of the signal.
+ *      sigdata     Pointer to the packed signal buffer.
+ *      siglen      Length of the packed signal.
+ *      bulkdata    Pointer to the signal's bulk data.
+ *
+ *  Returns:
+ *      None.
+ *
+ * ---------------------------------------------------------------------------
+ */
+static void send_to_client(unifi_priv_t *priv, ul_client_t *client,
+        int receiver_id,
+        unsigned char *sigdata, int siglen,
+        const bulk_data_param_t *bulkdata)
+{
+    if (client && client->event_hook) {
+        /*unifi_trace(priv, UDBG3,
+                "Receive: client %d, (s:0x%X, r:0x%X) - Signal 0x%.4X \n",
+                client->client_id, client->sender_id, receiver_id,
+                CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata));*/
+
+        client->event_hook(client, sigdata, siglen, bulkdata, UDI_TO_HOST);
+    }
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  process_pkt_data_ind
+ *
+ *      Dispatcher for received signals.
+ *
+ *      This function receives the 'to host' signals and forwards
+ *      them to the unifi linux clients.
+ *
+ *  Arguments:
+ *      priv         Context
+ *      sigdata      Pointer to the packed signal buffer(Its in form of MA-PACKET.ind).
+ *      bulkdata     Pointer to signal's bulkdata
+ *      freeBulkData Pointer to a flag which gets set if the bulkdata needs to
+ *                   be freed after calling the logging handlers. If it is not
+ *                   set the bulkdata must be freed by the MLME handler or
+ *                   passed to the network stack.
+ *  Returns:
+ *      TRUE if the packet should be routed to the SME etc.
+ *      FALSE if the packet is for the driver or network stack
+ * ---------------------------------------------------------------------------
+ */
+static CsrBool check_routing_pkt_data_ind(unifi_priv_t *priv,
+        CsrUint8 *sigdata,
+        const bulk_data_param_t* bulkdata,
+        CsrBool *freeBulkData,
+        netInterface_priv_t *interfacePriv)
+{
+    CsrUint16  frmCtrl, receptionStatus, frmCtrlSubType;
+    CsrUint8 *macHdrLocation;
+    CsrUint8 interfaceTag;
+    CsrBool isDataFrame;
+    CsrBool isProtocolVerInvalid = FALSE;
+    CsrBool isDataFrameSubTypeNoData = FALSE;
+
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+    static const CsrUint8 wapiProtocolIdSNAPHeader[] = {0x88,0xb4};
+    static const CsrUint8 wapiProtocolIdSNAPHeaderOffset = 6;
+    CsrUint8 *destAddr;
+    CsrUint8 *srcAddr;
+    CsrBool isWapiUnicastPkt = FALSE;
+
+#ifdef CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND
+    CsrUint16 qosControl;
+#endif
+
+    CsrUint8 llcSnapHeaderOffset = 0;
+
+    destAddr = (CsrUint8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR1_OFFSET;
+    srcAddr  = (CsrUint8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR2_OFFSET;
+
+    /*Individual/Group bit - Bit 0 of first byte*/
+    isWapiUnicastPkt = (!(destAddr[0] & 0x01)) ? TRUE : FALSE;
+#endif
+
+#define CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET    sizeof(CSR_SIGNAL_PRIMITIVE_HEADER) + 22
+
+    *freeBulkData = FALSE;
+
+    /* Fetch the MAC header location from  MA_PKT_IND packet */
+    macHdrLocation = (CsrUint8 *) bulkdata->d[0].os_data_ptr;
+    /* Fetch the Frame Control value from  MAC header */
+    frmCtrl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation);
+
+    /* Pull out interface tag from virtual interface identifier */
+    interfaceTag = (CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + 14)) & 0xff;
+
+    /* check for MIC failure before processing the signal */
+    receptionStatus = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET);
+
+    /* To discard any spurious MIC failures that could be reported by the firmware */
+    isDataFrame = ((frmCtrl & IEEE80211_FC_TYPE_MASK) == (IEEE802_11_FC_TYPE_DATA & IEEE80211_FC_TYPE_MASK)) ? TRUE : FALSE;
+    /* 0x00 is the only valid protocol version*/
+    isProtocolVerInvalid = (frmCtrl & IEEE80211_FC_PROTO_VERSION_MASK) ? TRUE : FALSE;
+    frmCtrlSubType = (frmCtrl & IEEE80211_FC_SUBTYPE_MASK) >> FRAME_CONTROL_SUBTYPE_FIELD_OFFSET;
+    /*Exclude the no data & reserved sub-types from MIC failure processing*/
+    isDataFrameSubTypeNoData = (((frmCtrlSubType>0x03)&&(frmCtrlSubType<0x08)) || (frmCtrlSubType>0x0B)) ? TRUE : FALSE;
+    if ((receptionStatus == CSR_MICHAEL_MIC_ERROR) &&
+        ((!isDataFrame) || isProtocolVerInvalid || (isDataFrame && isDataFrameSubTypeNoData))) {
+        /* Currently MIC errors are discarded for frames other than data frames. This might need changing when we start
+         * supporting 802.11w (Protected Management frames)
+         */
+        *freeBulkData = TRUE;
+        unifi_trace(priv, UDBG4, "Discarding this frame and ignoring the MIC failure as this is a garbage/non-data/no data frame\n");
+        return FALSE;
+     }
+
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+
+    if (receptionStatus == CSR_MICHAEL_MIC_ERROR) {
+
+        if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA) {
+
+#ifdef CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND
+            if ((isDataFrame) &&
+                ((IEEE802_11_FC_TYPE_QOS_DATA & IEEE80211_FC_SUBTYPE_MASK) == (frmCtrl & IEEE80211_FC_SUBTYPE_MASK)) &&
+                (priv->isWapiConnection))
+            {
+            	qosControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation + (((frmCtrl & IEEE802_11_FC_TO_DS_MASK) && (frmCtrl & IEEE802_11_FC_FROM_DS_MASK)) ? 30 : 24) );
+
+            	unifi_trace(priv, UDBG4, "check_routing_pkt_data_ind() :: Value of the QoS control field - 0x%04x \n", qosControl);
+
+                if (qosControl & IEEE802_11_QC_NON_TID_BITS_MASK)
+                {
+                	unifi_trace(priv, UDBG4, "Ignore the MIC failure and pass the MPDU to the stack when any of bits [4-15] is set in the QoS control field\n");
+
+            		/*Exclude the MIC [16] and the PN [16] that are appended by the firmware*/
+            		((bulk_data_param_t*)bulkdata)->d[0].data_length = bulkdata->d[0].data_length - 32;
+
+            		/*Clear the reception status of the signal (CSR_RX_SUCCESS)*/
+            		*(sigdata + CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET)     = 0x00;
+            		*(sigdata + CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET+1)   = 0x00;
+
+            		*freeBulkData = FALSE;
+
+            		return FALSE;
+                }
+            }
+#endif
+            /* If this MIC ERROR reported by the firmware is either for
+             *    [1] a WAPI Multicast MPDU and the Multicast filter has NOT been set (It is set only when group key index (MSKID) = 1 in Group Rekeying)   OR
+             *    [2] a WAPI Unicast MPDU and either the CONTROL PORT is open or the WAPI Unicast filter or filter(s) is NOT set
+             * then report a MIC FAILURE indication to the SME.
+             */
+#ifndef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION
+    	if ((priv->wapi_multicast_filter == 0) || isWapiUnicastPkt) {
+#else
+        /*When SW encryption is enabled and USKID=1 (wapi_unicast_filter = 1), we are expected
+		 *to receive MIC failure INDs for unicast MPDUs*/
+    	if ( ((priv->wapi_multicast_filter == 0) && !isWapiUnicastPkt) ||
+             ((priv->wapi_unicast_filter   == 0) &&  isWapiUnicastPkt) ) {
+#endif
+                /*Discard the frame*/
+                *freeBulkData = TRUE;
+                unifi_trace(priv, UDBG4, "Discarding the contents of the frame with MIC failure \n");
+
+                if (isWapiUnicastPkt &&
+                    ((uf_sme_port_state(priv,srcAddr,UF_CONTROLLED_PORT_Q,interfaceTag) != CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN)||
+#ifndef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION
+                    (priv->wapi_unicast_filter) ||
+#endif
+                    (priv->wapi_unicast_queued_pkt_filter))) {
+
+                    /* Workaround to handle MIC failures reported by the firmware for encrypted packets from the AP
+                     * while we are in the process of re-association induced by unsupported WAPI Unicast key index
+                     *             - Discard the packets with MIC failures "until" we have
+                     *               a. negotiated a key,
+                     *               b. opened the CONTROL PORT and
+                     *               c. the AP has started using the new key
+                     */
+                    unifi_trace(priv, UDBG4, "Ignoring the MIC failure as either a. CONTROL PORT isn't OPEN or b. Unicast filter is set or c. WAPI AP using old key for buffered pkts\n");
+
+                    /*Ignore this MIC failure*/
+                    return FALSE;
+
+                }/*WAPI re-key specific workaround*/
+
+                unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind - MIC FAILURE : interfaceTag %x Src Addr %x:%x:%x:%x:%x:%x\n",
+                            interfaceTag, srcAddr[0], srcAddr[1], srcAddr[2], srcAddr[3], srcAddr[4], srcAddr[5]);
+                unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind - MIC FAILURE : Dest Addr %x:%x:%x:%x:%x:%x\n",
+                            destAddr[0], destAddr[1], destAddr[2], destAddr[3], destAddr[4], destAddr[5]);
+                unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind - MIC FAILURE : Control Port State - 0x%.4X \n",
+                            uf_sme_port_state(priv,srcAddr,UF_CONTROLLED_PORT_Q,interfaceTag));
+
+                unifi_error(priv, "MIC failure in %s\n", __FUNCTION__);
+
+                /*Report the MIC failure to the SME*/
+                return TRUE;
+            }
+        }/* STA mode */
+        else {
+            /* Its AP Mode . Just Return */
+            *freeBulkData = TRUE;
+            unifi_error(priv, "MIC failure in %s\n", __FUNCTION__);
+            return TRUE;
+         } /* AP mode */
+    }/* MIC error */
+#else
+    if (receptionStatus == CSR_MICHAEL_MIC_ERROR) {
+        *freeBulkData = TRUE;
+        unifi_error(priv, "MIC failure in %s\n", __FUNCTION__);
+        return TRUE;
+    }
+#endif /*CSR_WIFI_SECURITY_WAPI_ENABLE*/
+
+    unifi_trace(priv, UDBG4, "frmCtrl = 0x%04x %s\n",
+                frmCtrl,
+                (((frmCtrl & 0x000c)>>FRAME_CONTROL_TYPE_FIELD_OFFSET) == IEEE802_11_FRAMETYPE_MANAGEMENT) ?
+                    "Mgt" : "Ctrl/Data");
+
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+    /* To ignore MIC failures reported due to the WAPI AP using the old key for queued packets before
+     * starting to use the new key negotiated as part of unicast re-keying
+     */
+    if ((interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA)&&
+        isWapiUnicastPkt &&
+        (receptionStatus == CSR_RX_SUCCESS) &&
+        (priv->wapi_unicast_queued_pkt_filter==1)) {
+
+        unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): WAPI unicast pkt received when the (wapi_unicast_queued_pkt_filter) is set\n");
+
+        if (isDataFrame) {
+            switch(frmCtrl & IEEE80211_FC_SUBTYPE_MASK) {
+                case IEEE802_11_FC_TYPE_QOS_DATA & IEEE80211_FC_SUBTYPE_MASK:
+                    llcSnapHeaderOffset = MAC_HEADER_SIZE + 2;
+                    break;
+                case IEEE802_11_FC_TYPE_QOS_NULL & IEEE80211_FC_SUBTYPE_MASK:
+                case IEEE802_11_FC_TYPE_NULL & IEEE80211_FC_SUBTYPE_MASK:
+                    break;
+                default:
+                    llcSnapHeaderOffset = MAC_HEADER_SIZE;
+            }
+        }
+
+        if (llcSnapHeaderOffset > 0) {
+        	/* QoS data or Data */
+            unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): SNAP header found & its offset %d\n",llcSnapHeaderOffset);
+            if (memcmp((CsrUint8 *)(bulkdata->d[0].os_data_ptr+llcSnapHeaderOffset+wapiProtocolIdSNAPHeaderOffset),
+                       wapiProtocolIdSNAPHeader,sizeof(wapiProtocolIdSNAPHeader))) {
+
+            	unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): This is a data & NOT a WAI protocol packet\n");
+                /* On the first unicast data pkt that is decrypted successfully after re-keying, reset the filter */
+                priv->wapi_unicast_queued_pkt_filter = 0;
+                unifi_trace(priv, UDBG4, "check_routing_pkt_data_ind(): WAPI AP has started using the new unicast key, no more MIC failures expected (reset filter)\n");
+            }
+            else {
+                unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): WAPI - This is a WAI protocol packet\n");
+            }
+        }
+	}
+#endif
+
+
+    switch ((frmCtrl & 0x000c)>>FRAME_CONTROL_TYPE_FIELD_OFFSET) {
+        case IEEE802_11_FRAMETYPE_MANAGEMENT:
+            *freeBulkData = TRUE;       /* Free (after SME handler copies it) */
+
+            /* In P2P device mode, filter the legacy AP beacons here */
+            if((interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2P)&&\
+               ((CSR_WIFI_80211_GET_FRAME_SUBTYPE(macHdrLocation)) == CSR_WIFI_80211_FRAME_SUBTYPE_BEACON)){
+
+                CsrUint8 *pSsid, *pSsidLen;
+                static CsrUint8 P2PWildCardSsid[CSR_WIFI_P2P_WILDCARD_SSID_LENGTH] = {'D', 'I', 'R', 'E', 'C', 'T', '-'};
+
+                pSsidLen = macHdrLocation + MAC_HEADER_SIZE + CSR_WIFI_BEACON_FIXED_LENGTH;
+                pSsid = pSsidLen + 2;
+
+                if(*(pSsidLen + 1) >= CSR_WIFI_P2P_WILDCARD_SSID_LENGTH){
+                    if(memcmp(pSsid, P2PWildCardSsid, CSR_WIFI_P2P_WILDCARD_SSID_LENGTH) == 0){
+                        unifi_trace(priv, UDBG6, "Received a P2P Beacon, pass it to SME\n");
+                        return TRUE;
+                    }
+                }
+                unifi_trace(priv, UDBG6, "Received a Legacy AP beacon in P2P mode, drop it\n");
+                return FALSE;
+            }
+            return TRUE;                /* Route to SME */
+        case IEEE802_11_FRAMETYPE_DATA:
+        case IEEE802_11_FRAMETYPE_CONTROL:
+            *freeBulkData = FALSE;      /* Network stack or MLME handler frees */
+            return FALSE;
+        default:
+            unifi_error(priv, "Unhandled frame type %04x\n", frmCtrl);
+            *freeBulkData = TRUE;       /* Not interested, but must free it */
+            return FALSE;
+    }
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_process_receive_event
+ *
+ *      Dispatcher for received signals.
+ *
+ *      This function receives the 'to host' signals and forwards
+ *      them to the unifi linux clients.
+ *
+ *  Arguments:
+ *      ospriv      Pointer to driver's private data.
+ *      sigdata     Pointer to the packed signal buffer.
+ *      siglen      Length of the packed signal.
+ *      bulkdata    Pointer to the signal's bulk data.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *  The signals are received in the format described in the host interface
+ *  specification, i.e wire formatted. Certain clients use the same format
+ *  to interpret them and other clients use the host formatted structures.
+ *  Each client has to call read_unpack_signal() to transform the wire
+ *  formatted signal into the host formatted signal, if necessary.
+ *  The code is in the core, since the signals are defined therefore
+ *  binded to the host interface specification.
+ * ---------------------------------------------------------------------------
+ */
+static void
+unifi_process_receive_event(void *ospriv,
+                            CsrUint8 *sigdata, CsrUint32 siglen,
+                            const bulk_data_param_t *bulkdata)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+    int i, receiver_id;
+    int client_id;
+    CsrInt16 signal_id;
+    CsrBool pktIndToSme = FALSE, freeBulkData = FALSE;
+
+    func_enter();
+
+    unifi_trace(priv, UDBG5, "unifi_process_receive_event: "
+                "%04x %04x %04x %04x %04x %04x %04x %04x (%d)\n",
+                CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*0) & 0xFFFF,
+                CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*1) & 0xFFFF,
+                CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*2) & 0xFFFF,
+                CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*3) & 0xFFFF,
+                CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*4) & 0xFFFF,
+                CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*5) & 0xFFFF,
+                CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*6) & 0xFFFF,
+                CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*7) & 0xFFFF,
+                siglen);
+
+    receiver_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)) & 0xFF00;
+    client_id = (receiver_id & 0x0F00) >> UDI_SENDER_ID_SHIFT;
+    signal_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata);
+
+
+
+    /* check for the type of frame received (checks for 802.11 management frames) */
+    if (signal_id == CSR_MA_PACKET_INDICATION_ID)
+    {
+#define CSR_MA_PACKET_INDICATION_INTERFACETAG_OFFSET    14
+        CsrUint8 interfaceTag;
+        netInterface_priv_t *interfacePriv;
+
+        /* Pull out interface tag from virtual interface identifier */
+        interfaceTag = (CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_MA_PACKET_INDICATION_INTERFACETAG_OFFSET)) & 0xff;
+        interfacePriv = priv->interfacePriv[interfaceTag];
+
+        /* Update activity for this station in case of IBSS */
+#ifdef CSR_SUPPORT_SME
+        if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_IBSS)
+        {
+            CsrUint8 *saddr;
+            /* Fetch the source address from  mac header */
+            saddr = (CsrUint8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR2_OFFSET;
+            unifi_trace(priv, UDBG5,
+                                    "Updating sta activity in IBSS interfaceTag %x Src Addr %x:%x:%x:%x:%x:%x\n",
+                                    interfaceTag, saddr[0], saddr[1], saddr[2], saddr[3], saddr[4], saddr[5]);
+
+            uf_update_sta_activity(priv, interfaceTag, saddr);
+        }
+#endif
+
+        pktIndToSme = check_routing_pkt_data_ind(priv, sigdata, bulkdata, &freeBulkData, interfacePriv);
+
+        unifi_trace(priv, UDBG6, "RX: packet entry point to driver from HIP,pkt to SME ?(%s) \n", (pktIndToSme)? "YES":"NO");
+
+    }
+
+    if (pktIndToSme)
+    {
+        /* Management MA_PACKET_IND for SME */
+        if(sigdata != NULL && bulkdata != NULL){
+            send_to_client(priv, priv->sme_cli, receiver_id, sigdata, siglen, bulkdata);
+        }
+        else{
+            unifi_error(priv, "unifi_receive_event2: sigdata or Bulkdata is NULL \n");
+        }
+#ifdef CSR_NATIVE_LINUX
+        send_to_client(priv, priv->wext_client,
+                receiver_id,
+                sigdata, siglen, bulkdata);
+#endif
+    }
+    else
+    {
+        /* Signals with ReceiverId==0 are also reported to SME / WEXT,
+         * unless they are data/control MA_PACKET_INDs or VIF_AVAILABILITY_INDs
+         */
+        if (!receiver_id) {
+               if(signal_id == CSR_MA_VIF_AVAILABILITY_INDICATION_ID) {
+                      uf_process_ma_vif_availibility_ind(priv, sigdata, siglen);
+               }
+               else if (signal_id != CSR_MA_PACKET_INDICATION_ID) {
+                      send_to_client(priv, priv->sme_cli, receiver_id, sigdata, siglen, bulkdata);
+#ifdef CSR_NATIVE_LINUX
+                      send_to_client(priv, priv->wext_client,
+                                     receiver_id,
+                                     sigdata, siglen, bulkdata);
+#endif
+               }
+               else
+               {
+
+#if (defined(CSR_SUPPORT_SME) && defined(CSR_WIFI_SECURITY_WAPI_ENABLE))
+                   #define CSR_MA_PACKET_INDICATION_RECEPTION_STATUS_OFFSET    sizeof(CSR_SIGNAL_PRIMITIVE_HEADER) + 22
+                   netInterface_priv_t *interfacePriv;
+                   CsrUint8 interfaceTag;
+                   CsrUint16 receptionStatus = CSR_RX_SUCCESS;
+
+                   /* Pull out interface tag from virtual interface identifier */
+                   interfaceTag = (CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_MA_PACKET_INDICATION_INTERFACETAG_OFFSET)) & 0xff;
+                   interfacePriv = priv->interfacePriv[interfaceTag];
+
+                   /* check for MIC failure */
+                   receptionStatus = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_MA_PACKET_INDICATION_RECEPTION_STATUS_OFFSET);
+
+                   /* Send a WAPI MPDU to SME for re-check MIC if the respective filter has been set*/
+                   if ((!freeBulkData) &&
+                       (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA) &&
+                       (receptionStatus == CSR_MICHAEL_MIC_ERROR) &&
+                       ((priv->wapi_multicast_filter == 1)
+#ifdef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION
+                         || (priv->wapi_unicast_filter == 1)
+#endif
+                       ))
+                   {
+                       CSR_SIGNAL signal;
+                       CsrUint8 *destAddr;
+                       CsrResult res;
+                       CsrUint16 interfaceTag = 0;
+                       CsrBool isMcastPkt = TRUE;
+
+                       unifi_trace(priv, UDBG6, "Received a WAPI data packet when the Unicast/Multicast filter is set\n");
+                       res = read_unpack_signal(sigdata, &signal);
+                       if (res) {
+                           unifi_error(priv, "Received unknown or corrupted signal (0x%x).\n",
+                                       CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata));
+                           return;
+                       }
+
+                       /* Check if the type of MPDU and the respective filter status*/
+                       destAddr = (CsrUint8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR1_OFFSET;
+                       isMcastPkt = (destAddr[0] & 0x01) ? TRUE : FALSE;
+                       unifi_trace(priv, UDBG6,
+                                   "1.MPDU type: (%s), 2.Multicast filter: (%s), 3. Unicast filter: (%s)\n",
+                                   ((isMcastPkt) ? "Multiast":"Unicast"),
+                                   ((priv->wapi_multicast_filter) ? "Enabled":"Disabled"),
+                                   ((priv->wapi_unicast_filter)  ? "Enabled":"Disabled"));
+
+                       if (((isMcastPkt) && (priv->wapi_multicast_filter == 1))
+#ifdef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION
+                           || ((!isMcastPkt) && (priv->wapi_unicast_filter == 1))
+#endif
+                          )
+                        {
+                            unifi_trace(priv, UDBG4, "Sending the WAPI MPDU for MIC check\n");
+                            CsrWifiRouterCtrlWapiRxMicCheckIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, interfaceTag, siglen, sigdata, bulkdata->d[0].data_length, (CsrUint8*)bulkdata->d[0].os_data_ptr);
+
+                            for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
+                                if (bulkdata->d[i].data_length != 0) {
+                                    unifi_net_data_free(priv, (void *)&bulkdata->d[i]);
+                                }
+                           }
+                           func_exit();
+                           return;
+                       }
+                   } /* CSR_MA_PACKET_INDICATION_ID */
+#endif /*CSR_SUPPORT_SME && CSR_WIFI_SECURITY_WAPI_ENABLE*/
+               }
+        }
+
+        /* calls the registered clients handler callback func.
+         * netdev_mlme_event_handler is one of the registered handler used to route
+         * data packet to network stack or AMP/EAPOL related data to SME
+         *
+         * The freeBulkData check ensures that, it has received a management frame and
+         * the frame needs to be freed here. So not to be passed to netdev handler
+         */
+        if(!freeBulkData){
+            if ((client_id < MAX_UDI_CLIENTS) &&
+                    (&priv->ul_clients[client_id] != priv->logging_client)) {
+            	unifi_trace(priv, UDBG6, "Call the registered clients handler callback func\n");
+                send_to_client(priv, &priv->ul_clients[client_id],
+                        receiver_id,
+                        sigdata, siglen, bulkdata);
+            }
+        }
+    }
+
+    /*
+     * Free bulk data buffers here unless it is a CSR_MA_PACKET_INDICATION
+     */
+    switch (signal_id)
+    {
+#ifdef UNIFI_SNIFF_ARPHRD
+        case CSR_MA_SNIFFDATA_INDICATION_ID:
+#endif
+            break;
+
+        case CSR_MA_PACKET_INDICATION_ID:
+            if (!freeBulkData)
+            {
+                break;
+            }
+            /* FALLS THROUGH... */
+        default:
+            for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
+                if (bulkdata->d[i].data_length != 0) {
+                    unifi_net_data_free(priv, (void *)&bulkdata->d[i]);
+                }
+            }
+    }
+
+    func_exit();
+} /* unifi_process_receive_event() */
+
+
+#ifdef CSR_WIFI_RX_PATH_SPLIT
+static CsrBool signal_buffer_is_full(unifi_priv_t* priv)
+{
+    return (((priv->rxSignalBuffer.writePointer + 1)% priv->rxSignalBuffer.size) == (priv->rxSignalBuffer.readPointer));
+}
+
+void unifi_rx_queue_flush(void *ospriv)
+{
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+
+    func_enter();
+    unifi_trace(priv, UDBG4, "rx_wq_handler: RdPtr = %d WritePtr =  %d\n",
+                priv->rxSignalBuffer.readPointer,priv->rxSignalBuffer.writePointer);
+    if(priv != NULL) {
+        CsrUint8 readPointer = priv->rxSignalBuffer.readPointer;
+        while (readPointer != priv->rxSignalBuffer.writePointer)
+        {
+             rx_buff_struct_t *buf = &priv->rxSignalBuffer.rx_buff[readPointer];
+             unifi_trace(priv, UDBG6, "rx_wq_handler: RdPtr = %d WritePtr =  %d\n",
+                         readPointer,priv->rxSignalBuffer.writePointer);
+             unifi_process_receive_event(priv, buf->bufptr, buf->sig_len, &buf->data_ptrs);
+             readPointer ++;
+             if(readPointer >= priv->rxSignalBuffer.size) {
+                    readPointer = 0;
+             }
+        }
+        priv->rxSignalBuffer.readPointer = readPointer;
+    }
+    func_exit();
+}
+
+void rx_wq_handler(struct work_struct *work)
+{
+    unifi_priv_t *priv = container_of(work, unifi_priv_t, rx_work_struct);
+    unifi_rx_queue_flush(priv);
+}
+#endif
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  unifi_receive_event
+ *
+ *      Dispatcher for received signals.
+ *
+ *      This function receives the 'to host' signals and forwards
+ *      them to the unifi linux clients.
+ *
+ *  Arguments:
+ *      ospriv      Pointer to driver's private data.
+ *      sigdata     Pointer to the packed signal buffer.
+ *      siglen      Length of the packed signal.
+ *      bulkdata    Pointer to the signal's bulk data.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *  The signals are received in the format described in the host interface
+ *  specification, i.e wire formatted. Certain clients use the same format
+ *  to interpret them and other clients use the host formatted structures.
+ *  Each client has to call read_unpack_signal() to transform the wire
+ *  formatted signal into the host formatted signal, if necessary.
+ *  The code is in the core, since the signals are defined therefore
+ *  binded to the host interface specification.
+ * ---------------------------------------------------------------------------
+ */
+void
+unifi_receive_event(void *ospriv,
+                    CsrUint8 *sigdata, CsrUint32 siglen,
+                    const bulk_data_param_t *bulkdata)
+{
+#ifdef CSR_WIFI_RX_PATH_SPLIT
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+    CsrUint8 writePointer;
+    int i;
+    rx_buff_struct_t * rx_buff;
+    func_enter();
+
+    unifi_trace(priv, UDBG5, "unifi_receive_event: "
+            "%04x %04x %04x %04x %04x %04x %04x %04x (%d)\n",
+            CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*0) & 0xFFFF,
+            CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*1) & 0xFFFF,
+            CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*2) & 0xFFFF,
+            CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*3) & 0xFFFF,
+            CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*4) & 0xFFFF,
+            CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*5) & 0xFFFF,
+            CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*6) & 0xFFFF,
+            CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(CsrInt16)*7) & 0xFFFF, siglen);
+    if(signal_buffer_is_full(priv)) {
+        unifi_error(priv,"TO HOST signal queue FULL dropping the PDU\n");
+        for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
+            if (bulkdata->d[i].data_length != 0) {
+                unifi_net_data_free(priv, (void *)&bulkdata->d[i]);
+            }
+        }
+        return;
+    }
+    writePointer = priv->rxSignalBuffer.writePointer;
+    rx_buff = &priv->rxSignalBuffer.rx_buff[writePointer];
+    memcpy(rx_buff->bufptr,sigdata,siglen);
+    rx_buff->sig_len = siglen;
+    rx_buff->data_ptrs = *bulkdata;
+    writePointer++;
+    if(writePointer >= priv->rxSignalBuffer.size) {
+        writePointer =0;
+    }
+    unifi_trace(priv, UDBG4, "unifi_receive_event:writePtr = %d\n",priv->rxSignalBuffer.writePointer);
+    priv->rxSignalBuffer.writePointer = writePointer;
+
+#ifndef CSR_WIFI_RX_PATH_SPLIT_DONT_USE_WQ
+    queue_work(priv->rx_workqueue, &priv->rx_work_struct);
+#endif
+
+#else
+    unifi_process_receive_event(ospriv, sigdata, siglen, bulkdata);
+#endif
+    func_exit();
+} /* unifi_receive_event() */
+
diff --git a/drivers/staging/csr/unifi_native.h b/drivers/staging/csr/unifi_native.h
new file mode 100644
index 0000000..a480c9e
--- /dev/null
+++ b/drivers/staging/csr/unifi_native.h
@@ -0,0 +1,276 @@
+/*
+ *****************************************************************************
+ *
+ * FILE : unifi_native.h
+ *
+ * PURPOSE : Private header file for unifi driver support to wireless extensions.
+ *
+ *           UDI = UniFi Debug Interface
+ *
+ * Copyright (C) 2005-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ *****************************************************************************
+ */
+#ifndef __LINUX_UNIFI_NATIVE_H__
+#define __LINUX_UNIFI_NATIVE_H__ 1
+
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+
+
+/*
+ *      scan.c wext.c autojoin.c
+ */
+/* Structure to hold results of a scan */
+typedef struct scan_info {
+
+/*    CSR_MLME_SCAN_INDICATION msi; */
+
+    unsigned char *info_elems;
+    int info_elem_length;
+
+} scan_info_t;
+
+
+#define IE_VECTOR_MAXLEN 1024
+
+#ifdef CSR_SUPPORT_WEXT
+/*
+ * Structre to hold the wireless network configuration info.
+ */
+struct wext_config {
+
+    /* Requested channel when setting up an adhoc network */
+    int channel;
+
+    /* wireless extns mode: IW_MODE_AUTO, ADHOC, INFRA, MASTER ... MONITOR */
+    int mode;
+
+    /* The capabilities of the currently joined network */
+    int capability;
+
+    /* The interval between beacons if we create an IBSS */
+    int beacon_period;
+
+    /*
+    * Power-save parameters
+    */
+    /* The listen interval to ask for in Associate req. */
+    int assoc_listen_interval;
+    /* Power-mode to put UniFi into */
+
+    unsigned char desired_ssid[UNIFI_MAX_SSID_LEN];     /* the last ESSID set by SIOCSIWESSID */
+    int power_mode;
+    /* Whether to wake for broadcast packets (using DTIM interval) */
+    int wakeup_for_dtims;
+
+    /* Currently selected WEP Key ID (0..3) */
+    int wep_key_id;
+
+    wep_key_t wep_keys[NUM_WEPKEYS];
+
+/*    CSR_AUTHENTICATION_TYPE auth_type; */
+    int privacy;
+
+    u32 join_failure_timeout;
+    u32 auth_failure_timeout;
+    u32 assoc_failure_timeout;
+
+    unsigned char generic_ie[IE_VECTOR_MAXLEN];
+    int generic_ie_len;
+
+    struct iw_statistics wireless_stats;
+
+
+    /* the ESSID we are currently associated to */
+    unsigned char current_ssid[UNIFI_MAX_SSID_LEN];
+    /* the BSSID we are currently associated to */
+    unsigned char current_bssid[6];
+
+    /*
+    * IW_AUTH_WPA_VERSION_DISABLED 0x00000001
+    * IW_AUTH_WPA_VERSION_WPA      0x00000002
+    * IW_AUTH_WPA_VERSION_WPA2     0x00000004
+    */
+    unsigned char wpa_version;
+
+    /*
+     * cipher selection:
+    * IW_AUTH_CIPHER_NONE	0x00000001
+    * IW_AUTH_CIPHER_WEP40	0x00000002
+    * IW_AUTH_CIPHER_TKIP	0x00000004
+    * IW_AUTH_CIPHER_CCMP	0x00000008
+    * IW_AUTH_CIPHER_WEP104	0x00000010
+    */
+    unsigned char pairwise_cipher_used;
+    unsigned char group_cipher_used;
+
+    unsigned int frag_thresh;
+    unsigned int rts_thresh;
+
+    /* U-APSD value, send with Association Request to WMM Enabled APs */
+    unsigned char wmm_bss_uapsd_mask;
+    /* The WMM capabilities of the selected BSS */
+    unsigned int bss_wmm_capabilities;
+
+    /* Flag to prevent a join when the ssid is set */
+    int disable_join_on_ssid_set;
+
+    /* Scan info */
+#define UNIFI_MAX_SCANS 32
+    scan_info_t scan_list[UNIFI_MAX_SCANS];
+    int num_scan_info;
+
+    /* Flag on whether non-802.1x packets are allowed out */
+/*    CsrWifiRouterPortAction block_controlled_port;*/
+
+    /* Flag on whether we have completed an authenticate/associate process */
+    unsigned int flag_associated        : 1;
+}; /* struct wext_config */
+
+#endif /* CSR_SUPPORT_WEXT */
+
+
+/*
+ *      wext.c
+ */
+/*int mlme_set_protection(unifi_priv_t *priv, unsigned char *addr,
+                        CSR_PROTECT_TYPE prot, CSR_KEY_TYPE key_type);
+*/
+
+/*
+ * scan.c
+ */
+/*
+void unifi_scan_indication_handler(unifi_priv_t *priv,
+                                   const CSR_MLME_SCAN_INDICATION *msg,
+                                   const unsigned char *extra,
+                                   unsigned int len);
+*/
+void unifi_clear_scan_table(unifi_priv_t *priv);
+scan_info_t *unifi_get_scan_report(unifi_priv_t *priv, int index);
+
+
+/*
+ * Utility functions
+ */
+const unsigned char *unifi_find_info_element(int id,
+                                             const unsigned char *info,
+                                             int len);
+int unifi_add_info_element(unsigned char *info,
+                           int ie_id,
+                           const unsigned char *ie_data,
+                           int ie_len);
+
+/*
+ *      autojoin.c
+ */
+/* Higher level fns */
+int unifi_autojoin(unifi_priv_t *priv, const char *ssid);
+/*
+int unifi_do_scan(unifi_priv_t *priv, int scantype, CSR_BSS_TYPE bsstype,
+                  const char *ssid, int ssid_len);
+*/
+int unifi_set_powermode(unifi_priv_t *priv);
+int unifi_join_ap(unifi_priv_t *priv, scan_info_t *si);
+int unifi_join_bss(unifi_priv_t *priv, unsigned char *macaddr);
+int unifi_leave(unifi_priv_t *priv);
+unsigned int unifi_get_wmm_bss_capabilities(unifi_priv_t *priv,
+                                            unsigned char *ie_vector,
+                                            int ie_len, int *ap_capabilities);
+
+/*
+ * Status and management.
+ */
+int uf_init_wext_interface(unifi_priv_t *priv);
+void uf_deinit_wext_interface(unifi_priv_t *priv);
+
+/*
+ * Function to reset UniFi's 802.11 state by sending MLME-RESET.req
+ */
+int unifi_reset_state(unifi_priv_t *priv, unsigned char *macaddr, unsigned char set_default_mib);
+
+
+/*
+ *      mlme.c
+ */
+/* Abort an MLME operation - useful in error recovery */
+int uf_abort_mlme(unifi_priv_t *priv);
+
+int unifi_mlme_blocking_request(unifi_priv_t *priv, ul_client_t *pcli,
+                                CSR_SIGNAL *sig, bulk_data_param_t *data_ptrs,
+                                int timeout);
+void unifi_mlme_copy_reply_and_wakeup_client(ul_client_t *pcli,
+                                             CSR_SIGNAL *signal, int signal_len,
+                                             const bulk_data_param_t *bulkdata);
+
+/*
+ * Utility functions
+ */
+const char *lookup_reason_code(int reason);
+const char *lookup_result_code(int result);
+
+
+/*
+ *      sme_native.c
+ */
+int uf_sme_init(unifi_priv_t *priv);
+void uf_sme_deinit(unifi_priv_t *priv);
+int sme_sys_suspend(unifi_priv_t *priv);
+int sme_sys_resume(unifi_priv_t *priv);
+int sme_mgt_wifi_on(unifi_priv_t *priv);
+
+/* Callback for event logging to SME clients (unifi_manager) */
+void sme_native_log_event(ul_client_t *client,
+                          const u8 *sig_packed, int sig_len,
+                          const bulk_data_param_t *bulkdata,
+                          int dir);
+
+void sme_native_mlme_event_handler(ul_client_t *pcli,
+                                   const u8 *sig_packed, int sig_len,
+                                   const bulk_data_param_t *bulkdata,
+                                   int dir);
+
+/* Task to query statistics from the MIB */
+#define UF_SME_STATS_WQ_TIMEOUT     2000    /* in msecs */
+void uf_sme_stats_wq(struct work_struct *work);
+
+void uf_native_process_udi_signal(ul_client_t *pcli,
+                                  const u8 *packed_signal,
+                                  int packed_signal_len,
+                                  const bulk_data_param_t *bulkdata, int dir);
+#if 0
+/*
+ * Choose one of these if available in linux/if_arp.h:
+ *  #define UNIFI_SNIFF_ARPHRD ARPHRD_IEEE80211_RADIOTAP
+ *  #define UNIFI_SNIFF_ARPHRD ARPHRD_IEEE80211_PRISM
+ *
+ * Radiotap is the newer standard for softmac WLAN devices, it works with
+ * Wireshark but not Ethereal (due to a bug in the Ethereal dissector).
+ * Prism is an older (less desirable) format but it does work with Ethereal.
+ */
+#ifdef ARPHRD_IEEE80211_RADIOTAP
+#define UNIFI_SNIFF_ARPHRD ARPHRD_IEEE80211_RADIOTAP
+#else
+#ifdef ARPHRD_IEEE80211_PRISM
+#define UNIFI_SNIFF_ARPHRD ARPHRD_IEEE80211_PRISM
+#endif
+#endif
+#endif
+
+#ifdef UNIFI_SNIFF_ARPHRD
+/*
+ * monitor.c
+ */
+int uf_start_sniff(unifi_priv_t *priv);
+/*
+void ma_sniffdata_ind(void *ospriv,
+                      const CSR_MA_SNIFFDATA_INDICATION *ind,
+                      const bulk_data_param_t *bulkdata);
+*/
+#endif /* ARPHRD_IEEE80211_PRISM */
+
+#endif /* __LINUX_UNIFI_NATIVE_H__ */
diff --git a/drivers/staging/csr/unifi_os.h b/drivers/staging/csr/unifi_os.h
new file mode 100644
index 0000000..0a97494
--- /dev/null
+++ b/drivers/staging/csr/unifi_os.h
@@ -0,0 +1,145 @@
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * FILE: os_linux/unifi_os.h
+ *
+ * PURPOSE:
+ *      This header file provides the OS-dependent facilities for a linux
+ *      environment.
+ *
+ * Copyright (C) 2005-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#ifndef __UNIFI_OS_LINUX_H__
+#define __UNIFI_OS_LINUX_H__ 1
+
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+
+/*
+ * Needed for core/signals.c
+ */
+#include <stddef.h>
+
+
+/* Define INLINE directive*/
+#define INLINE      inline
+
+/* Malloc and free */
+CsrResult unifi_net_data_malloc(void *ospriv, bulk_data_desc_t *bulk_data_slot, unsigned int size);
+void unifi_net_data_free(void *ospriv, bulk_data_desc_t *bulk_data_slot);
+#define CSR_WIFI_ALIGN_BYTES    4
+CsrResult unifi_net_dma_align(void *ospriv, bulk_data_desc_t *bulk_data_slot);
+
+/*
+ * Byte Order
+ * Note that __le*_to_cpu and __cpu_to_le* return an unsigned value!
+ */
+#ifdef __KERNEL__
+#define unifi2host_16(n)	(__le16_to_cpu((n)))
+#define unifi2host_32(n)	(__le32_to_cpu((n)))
+#define host2unifi_16(n)	(__cpu_to_le16((n)))
+#define host2unifi_32(n)	(__cpu_to_le32((n)))
+#endif
+
+/* Module parameters */
+extern int unifi_debug;
+
+/* debugging */
+#ifdef UNIFI_DEBUG
+/*
+ * unifi_debug is a verbosity level for debug messages
+ * UDBG0 msgs are always printed if UNIFI_DEBUG is defined
+ * UDBG1 msgs are printed if UNIFI_DEBUG is defined and unifi_debug > 0
+ * etc.
+ */
+
+#define func_enter()                                    \
+    do {                                                \
+        if (unifi_debug >= 5) {                         \
+            printk("unifi: => %s\n", __FUNCTION__);     \
+        }                                               \
+    } while (0)
+#define func_exit()                                     \
+    do {                                                \
+        if (unifi_debug >= 5) {                         \
+            printk("unifi: <= %s\n", __FUNCTION__);     \
+        }                                               \
+    } while (0)
+#define func_exit_r(_rc)                                        \
+    do {                                                        \
+        if (unifi_debug >= 5) {                                 \
+            printk("unifi: <= %s %d\n", __FUNCTION__, (int)(_rc));   \
+        }                                                       \
+    } while (0)
+
+
+#define ASSERT(cond)                                            \
+    do {                                                            \
+        if (!(cond)) {                                              \
+            printk("Assertion failed in %s at %s:%d: %s\n",         \
+                    __FUNCTION__, __FILE__, __LINE__, #cond);        \
+        }                                                           \
+    } while (0)
+
+
+void unifi_dump(void *ospriv, int lvl, const char *msg, void *mem, CsrUint16 len);
+void dump(void *mem, CsrUint16 len);
+void dump16(void *mem, CsrUint16 len);
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+void dump_str(void *mem, CsrUint16 len);
+#endif /* CSR_WIFI_HIP_DEBUG_OFFLINE */
+
+void unifi_error(void* ospriv, const char *fmt, ...);
+void unifi_warning(void* ospriv, const char *fmt, ...);
+void unifi_notice(void* ospriv, const char *fmt, ...);
+void unifi_info(void* ospriv, const char *fmt, ...);
+
+void unifi_trace(void* ospriv, int level, const char *fmt, ...);
+
+#else
+
+/* Stubs */
+#define func_enter()
+#define func_exit()
+#define func_exit_r(_rc)
+
+#define ASSERT(cond)
+
+static inline void unifi_dump(void *ospriv, int lvl, const char *msg, void *mem, CsrUint16 len) {}
+static inline void dump(void *mem, CsrUint16 len) {}
+static inline void dump16(void *mem, CsrUint16 len) {}
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+static inline void dump_str(void *mem, CsrUint16 len) {}
+#endif /* CSR_WIFI_HIP_DEBUG_OFFLINE */
+
+void unifi_error_nop(void* ospriv, const char *fmt, ...);
+void unifi_trace_nop(void* ospriv, int level, const char *fmt, ...);
+#define unifi_error if(1);else unifi_error_nop
+#define unifi_warning if(1);else unifi_error_nop
+#define unifi_notice if(1);else unifi_error_nop
+#define unifi_info if(1);else unifi_error_nop
+#define unifi_trace if(1);else unifi_trace_nop
+
+#endif /* UNIFI_DEBUG */
+
+
+/* Different levels of diagnostic detail... */
+#define UDBG0       0   /* always prints in debug build */
+#define UDBG1       1
+#define UDBG2       2
+#define UDBG3       3
+#define UDBG4       4
+#define UDBG5       5
+#define UDBG6       6
+#define UDBG7       7
+
+
+#endif /* __UNIFI_OS_LINUX_H__ */
diff --git a/drivers/staging/csr/unifi_pdu_processing.c b/drivers/staging/csr/unifi_pdu_processing.c
new file mode 100644
index 0000000..e35747c
--- /dev/null
+++ b/drivers/staging/csr/unifi_pdu_processing.c
@@ -0,0 +1,3751 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     unifi_pdu_processing.c
+ *
+ * PURPOSE:
+ *      This file provides the PDU handling functionality before it gets sent to unfi and after
+ *      receiving a PDU from unifi
+ *
+ * Copyright (C) 2010 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include <linux/vmalloc.h>
+
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_conversions.h"
+#include "csr_time.h"
+#include "unifi_priv.h"
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
+#include <net/iw_handler.h>
+#endif
+#include <net/pkt_sched.h>
+
+#ifdef CSR_SUPPORT_SME
+static void _update_buffered_pkt_params_after_alignment(unifi_priv_t *priv, bulk_data_param_t *bulkdata,
+                                                        tx_buffered_packets_t* buffered_pkt)
+{
+    struct sk_buff *skb ;
+    CsrUint32 align_offset;
+
+    if (priv == NULL || bulkdata == NULL || buffered_pkt == NULL){
+        return;
+    }
+
+    skb = (struct sk_buff*)bulkdata->d[0].os_net_buf_ptr;
+    align_offset = (CsrUint32)(long)(bulkdata->d[0].os_data_ptr) & (CSR_WIFI_ALIGN_BYTES-1);
+    if(align_offset){
+        skb_pull(skb,align_offset);
+    }
+
+    buffered_pkt->bulkdata.os_data_ptr = bulkdata->d[0].os_data_ptr;
+    buffered_pkt->bulkdata.data_length = bulkdata->d[0].data_length;
+    buffered_pkt->bulkdata.os_net_buf_ptr = bulkdata->d[0].os_net_buf_ptr;
+    buffered_pkt->bulkdata.net_buf_length = bulkdata->d[0].net_buf_length;
+}
+#endif
+
+void
+unifi_frame_ma_packet_req(unifi_priv_t *priv, CSR_PRIORITY priority,
+                          CSR_RATE TransmitRate, CSR_CLIENT_TAG hostTag,
+                          CsrUint16 interfaceTag, CSR_TRANSMISSION_CONTROL transmissionControl,
+                          CSR_PROCESS_ID leSenderProcessId, CsrUint8 *peerMacAddress,
+                          CSR_SIGNAL *signal)
+{
+
+    CSR_MA_PACKET_REQUEST *req = &signal->u.MaPacketRequest;
+    netInterface_priv_t *interfacePriv;
+    CsrUint8 ba_session_idx = 0;
+    ba_session_tx_struct *ba_session = NULL;
+    CsrUint8 *ba_addr = NULL;
+
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    UF_TRACE_MAC(priv, UDBG5, "In unifi_frame_ma_packet_req, Frame for Peer:", peerMacAddress);
+    signal->SignalPrimitiveHeader.SignalId = CSR_MA_PACKET_REQUEST_ID;
+    signal->SignalPrimitiveHeader.ReceiverProcessId = 0;
+    signal->SignalPrimitiveHeader.SenderProcessId = leSenderProcessId;
+
+    /* Fill the MA-PACKET.req */
+    req->Priority = priority;
+    unifi_trace(priv, UDBG3, "Tx Frame with Priority: 0x%x\n", req->Priority);
+
+    /* A value of 0 is used for auto selection of rates. But for P2P GO case
+     * for action frames the rate is governed by SME. Hence instead of 0,
+     * the rate is filled in with the value passed here
+     */
+    req->TransmitRate = TransmitRate;
+
+    /* packets from netdev then no confirm required but packets from
+     * Nme/Sme eapol data frames requires the confirmation
+     */
+    req->TransmissionControl = transmissionControl;
+    req->VirtualInterfaceIdentifier =
+           uf_get_vif_identifier(interfacePriv->interfaceMode,interfaceTag);
+    memcpy(req->Ra.x, peerMacAddress, ETH_ALEN);
+
+    if (hostTag == 0xffffffff) {
+        req->HostTag = interfacePriv->tag++;
+        req->HostTag |= 0x40000000;
+        unifi_trace(priv, UDBG3, "new host tag assigned = 0x%x\n", req->HostTag);
+        interfacePriv->tag &= 0x0fffffff;
+    } else {
+        req->HostTag = hostTag;
+        unifi_trace(priv, UDBG3, "host tag got from SME  = 0x%x\n", req->HostTag);
+    }
+    /* check if BA session exists for the peer MAC address on same tID */
+    if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+       interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO){
+        ba_addr = peerMacAddress;
+    }else{
+        ba_addr = interfacePriv->bssid.a;
+    }
+    for (ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_TX; ba_session_idx++){
+        ba_session = interfacePriv->ba_session_tx[ba_session_idx];
+        if (ba_session){
+           if ((!memcmp(ba_session->macAddress.a, ba_addr, ETH_ALEN)) && (ba_session->tID == priority)){
+                req->TransmissionControl |= CSR_ALLOW_BA;
+                break;
+            }
+        }
+    }
+
+    unifi_trace(priv, UDBG5, "leaving unifi_frame_ma_packet_req\n");
+}
+
+#ifdef CSR_SUPPORT_SME
+
+#define TRANSMISSION_CONTROL_TRIGGER_MASK 0x0001
+#define TRANSMISSION_CONTROL_EOSP_MASK 0x0002
+
+static
+int frame_and_send_queued_pdu(unifi_priv_t* priv,tx_buffered_packets_t* buffered_pkt,
+            CsrWifiRouterCtrlStaInfo_t *staRecord,CsrBool moreData , CsrBool eosp)
+{
+
+    CSR_SIGNAL signal;
+    bulk_data_param_t bulkdata;
+    int result;
+    CsrUint8 toDs, fromDs, macHeaderLengthInBytes = MAC_HEADER_SIZE;
+    CsrUint8 *qc;
+    CsrUint16 *fc = (CsrUint16*)(buffered_pkt->bulkdata.os_data_ptr);
+    unsigned long lock_flags;
+    unifi_trace(priv, UDBG3, "frame_and_send_queued_pdu with moreData: %d , EOSP: %d\n",moreData,eosp);
+    unifi_frame_ma_packet_req(priv, buffered_pkt->priority, buffered_pkt->rate, buffered_pkt->hostTag,
+               buffered_pkt->interfaceTag, buffered_pkt->transmissionControl,
+               buffered_pkt->leSenderProcessId, buffered_pkt->peerMacAddress.a, &signal);
+    bulkdata.d[0].os_data_ptr = buffered_pkt->bulkdata.os_data_ptr;
+    bulkdata.d[0].data_length = buffered_pkt->bulkdata.data_length;
+    bulkdata.d[0].os_net_buf_ptr = buffered_pkt->bulkdata.os_net_buf_ptr;
+    bulkdata.d[0].net_buf_length = buffered_pkt->bulkdata.net_buf_length;
+    bulkdata.d[1].os_data_ptr = NULL;
+    bulkdata.d[1].data_length = 0;
+    bulkdata.d[1].os_net_buf_ptr =0;
+    bulkdata.d[1].net_buf_length =0;
+
+    if(moreData) {
+        *fc |= cpu_to_le16(IEEE802_11_FC_MOREDATA_MASK);
+    } else {
+        *fc &= cpu_to_le16(~IEEE802_11_FC_MOREDATA_MASK);
+    }
+
+    if((staRecord != NULL)&& (staRecord->wmmOrQosEnabled == TRUE))
+    {
+        unifi_trace(priv, UDBG3, "frame_and_send_queued_pdu WMM Enabled: %d \n",staRecord->wmmOrQosEnabled);
+
+        toDs = (*fc & cpu_to_le16(IEEE802_11_FC_TO_DS_MASK))?1 : 0;
+        fromDs = (*fc & cpu_to_le16(IEEE802_11_FC_FROM_DS_MASK))? 1: 0;
+
+        switch(le16_to_cpu(*fc) & IEEE80211_FC_SUBTYPE_MASK)
+        {
+            case IEEE802_11_FC_TYPE_QOS_DATA & IEEE80211_FC_SUBTYPE_MASK:
+            case IEEE802_11_FC_TYPE_QOS_NULL & IEEE80211_FC_SUBTYPE_MASK:
+                /* If both are set then the Address4 exists (only for AP) */
+                if (fromDs && toDs) {
+                    /* 6 is the size of Address4 field */
+                    macHeaderLengthInBytes += (QOS_CONTROL_HEADER_SIZE + 6);
+                } else {
+                    macHeaderLengthInBytes += QOS_CONTROL_HEADER_SIZE;
+                }
+
+                /* If order bit set then HT control field is the part of MAC header */
+                if (*fc & cpu_to_le16(IEEE80211_FC_ORDER_MASK)) {
+                    macHeaderLengthInBytes += HT_CONTROL_HEADER_SIZE;
+                    qc = (CsrUint8*)(buffered_pkt->bulkdata.os_data_ptr + (macHeaderLengthInBytes-6));
+                } else {
+                    qc = (CsrUint8*)(buffered_pkt->bulkdata.os_data_ptr + (macHeaderLengthInBytes-2));
+                }
+                *qc = eosp ? *qc | (1 << 4) : *qc & (~(1 << 4));
+                break;
+            default:
+                if (fromDs && toDs)
+                    macHeaderLengthInBytes += 6;
+        }
+
+    }
+    result = ul_send_signal_unpacked(priv, &signal, &bulkdata);
+    if(result){
+        _update_buffered_pkt_params_after_alignment(priv, &bulkdata,buffered_pkt);
+    }
+
+ /* Decrement the packet counts queued in driver */
+    if (result != -ENOSPC) {
+        /* protect entire counter updation by disabling preemption */
+        if (!priv->noOfPktQueuedInDriver) {
+            unifi_error(priv, "packets queued in driver 0 still decrementing\n");
+        } else {
+            spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+            priv->noOfPktQueuedInDriver--;
+            spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+        }
+        /* Sta Record is available for all unicast (except genericMgt Frames) & in other case its NULL */
+        if (staRecord) {
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+            if (!staRecord->noOfPktQueued) {
+                unifi_error(priv, "packets queued in driver per station is 0 still decrementing\n");
+            } else {
+                staRecord->noOfPktQueued--;
+            }
+            /* if the STA alive probe frame has failed then reset the saved host tag */
+            if (result){
+                if (staRecord->nullDataHostTag == buffered_pkt->hostTag){
+                    staRecord->nullDataHostTag = INVALID_HOST_TAG;
+                }
+            }
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+        }
+
+    }
+    return result;
+}
+#ifdef CSR_SUPPORT_SME
+static
+void set_eosp_transmit_ctrl(unifi_priv_t *priv, struct list_head *txList)
+{
+    /* dequeue the tx data packets from the appropriate queue */
+    tx_buffered_packets_t *tx_q_item = NULL;
+    struct list_head *listHead;
+    struct list_head *placeHolder;
+    unsigned long lock_flags;
+
+
+    unifi_trace(priv, UDBG5, "entering set_eosp_transmit_ctrl\n");
+    /* check for list empty */
+    if (list_empty(txList)) {
+        unifi_warning(priv, "In set_eosp_transmit_ctrl, the list is empty\n");
+        return;
+    }
+
+    /* return the last node , and modify it. */
+
+    spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+    list_for_each_prev_safe(listHead, placeHolder, txList) {
+        tx_q_item = list_entry(listHead, tx_buffered_packets_t, q);
+        tx_q_item->transmissionControl |= TRANSMISSION_CONTROL_EOSP_MASK;
+        tx_q_item->transmissionControl = (tx_q_item->transmissionControl & ~(CSR_NO_CONFIRM_REQUIRED));
+        unifi_trace(priv, UDBG1,
+                "set_eosp_transmit_ctrl Transmission Control = 0x%x hostTag = 0x%x \n",tx_q_item->transmissionControl,tx_q_item->hostTag);
+        unifi_trace(priv,UDBG3,"in set_eosp_transmit_ctrl no.of buffered frames %d\n",priv->noOfPktQueuedInDriver);
+        break;
+    }
+    spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+    unifi_trace(priv, UDBG1,"List Empty %d\n",list_empty(txList));
+    unifi_trace(priv, UDBG5, "leaving set_eosp_transmit_ctrl\n");
+    return;
+}
+
+static
+void send_vif_availibility_rsp(unifi_priv_t *priv,CSR_VIF_IDENTIFIER vif,CSR_RESULT_CODE resultCode)
+{
+    CSR_SIGNAL signal;
+    CSR_MA_VIF_AVAILABILITY_RESPONSE *rsp;
+    bulk_data_param_t *bulkdata = NULL;
+    int r;
+
+    unifi_trace(priv, UDBG3, "send_vif_availibility_rsp : invoked with resultCode = %d \n", resultCode);
+
+    memset(&signal,0,sizeof(CSR_SIGNAL));
+    rsp = &signal.u.MaVifAvailabilityResponse;
+    rsp->VirtualInterfaceIdentifier = vif;
+    rsp->ResultCode = resultCode;
+    signal.SignalPrimitiveHeader.SignalId = CSR_MA_VIF_AVAILABILITY_RESPONSE_ID;
+    signal.SignalPrimitiveHeader.ReceiverProcessId = 0;
+    signal.SignalPrimitiveHeader.SenderProcessId = priv->netdev_client->sender_id;
+
+    /* Send the signal to UniFi */
+    r = ul_send_signal_unpacked(priv, &signal, bulkdata);
+    if(r) {
+        unifi_error(priv,"Availibility response sending failed %x status %d\n",vif,r);
+    }
+    else {
+        unifi_trace(priv, UDBG3, "send_vif_availibility_rsp : status = %d \n", r);
+    }
+}
+#endif
+
+static
+void verify_and_accomodate_tx_packet(unifi_priv_t *priv)
+{
+    tx_buffered_packets_t *tx_q_item;
+    unsigned long lock_flags;
+    struct list_head *listHead, *list;
+    struct list_head *placeHolder;
+    CsrUint8 i, j,eospFramedeleted=0;
+    CsrBool thresholdExcedeDueToBroadcast = TRUE;
+    /* it will be made it interface Specific in the future when multi interfaces are supported ,
+    right now interface 0 is considered */
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[0];
+    CsrWifiRouterCtrlStaInfo_t *staInfo = NULL;
+
+    unifi_trace(priv, UDBG3, "entering verify_and_accomodate_tx_packet\n");
+
+    for(i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
+        staInfo = interfacePriv->staInfo[i];
+            if (staInfo && (staInfo->noOfPktQueued >= CSR_WIFI_DRIVER_MAX_PKT_QUEUING_THRESHOLD_PER_PEER)) {
+            /* remove the first(oldest) packet from the all the access catogory, since data
+             * packets for station record crossed the threshold limit (64 for AP supporting
+             * 8 peers)
+             */
+            unifi_trace(priv,UDBG3,"number of station pkts queued=  %d for sta id = %d\n", staInfo->noOfPktQueued, staInfo->aid);
+            for(j = 0; j < MAX_ACCESS_CATOGORY; j++) {
+                list = &staInfo->dataPdu[j];
+                spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+                list_for_each_safe(listHead, placeHolder, list) {
+                    tx_q_item = list_entry(listHead, tx_buffered_packets_t, q);
+                    list_del(listHead);
+                    thresholdExcedeDueToBroadcast = FALSE;
+                    unifi_net_data_free(priv, &tx_q_item->bulkdata);
+                    kfree(tx_q_item);
+                    tx_q_item = NULL;
+                    if (!priv->noOfPktQueuedInDriver) {
+                        unifi_error(priv, "packets queued in driver 0 still decrementing in %s\n", __FUNCTION__);
+                    } else {
+                        /* protection provided by spinlock */
+                        priv->noOfPktQueuedInDriver--;
+
+                    }
+                    /* Sta Record is available for all unicast (except genericMgt Frames) & in other case its NULL */
+                    if (!staInfo->noOfPktQueued) {
+                        unifi_error(priv, "packets queued in driver per station is 0 still decrementing in %s\n", __FUNCTION__);
+                    } else {
+                        spin_lock(&priv->staRecord_lock);
+                        staInfo->noOfPktQueued--;
+                        spin_unlock(&priv->staRecord_lock);
+                    }
+                    break;
+                }
+                spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+            }
+        }
+    }
+    if (thresholdExcedeDueToBroadcast &&  interfacePriv->noOfbroadcastPktQueued > CSR_WIFI_DRIVER_MINIMUM_BROADCAST_PKT_THRESHOLD ) {
+        /* Remove the packets from genericMulticastOrBroadCastFrames queue
+         * (the max packets in driver is reached due to broadcast/multicast frames)
+         */
+        spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+        list_for_each_safe(listHead, placeHolder, &interfacePriv->genericMulticastOrBroadCastFrames) {
+            tx_q_item = list_entry(listHead, tx_buffered_packets_t, q);
+            if(eospFramedeleted){
+                tx_q_item->transmissionControl |= TRANSMISSION_CONTROL_EOSP_MASK;
+                tx_q_item->transmissionControl = (tx_q_item->transmissionControl & ~(CSR_NO_CONFIRM_REQUIRED));
+                unifi_trace(priv, UDBG1,"updating eosp for next packet hostTag:= 0x%x ",tx_q_item->hostTag);
+                eospFramedeleted =0;
+                break;
+            }
+
+            if(tx_q_item->transmissionControl & TRANSMISSION_CONTROL_EOSP_MASK ){
+               eospFramedeleted = 1;
+            }
+            unifi_trace(priv,UDBG1, "freeing of multicast packets ToC = 0x%x hostTag = 0x%x \n",tx_q_item->transmissionControl,tx_q_item->hostTag);
+            list_del(listHead);
+            unifi_net_data_free(priv, &tx_q_item->bulkdata);
+            kfree(tx_q_item);
+            priv->noOfPktQueuedInDriver--;
+            spin_lock(&priv->staRecord_lock);
+            interfacePriv->noOfbroadcastPktQueued--;
+            spin_unlock(&priv->staRecord_lock);
+            if(!eospFramedeleted){
+                break;
+            }
+        }
+        spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+    }
+    unifi_trace(priv, UDBG3, "leaving verify_and_accomodate_tx_packet\n");
+}
+
+static
+CsrResult enque_tx_data_pdu(unifi_priv_t *priv, bulk_data_param_t *bulkdata,
+                            struct list_head *list, CSR_SIGNAL *signal,
+                            CsrBool requeueOnSamePos)
+{
+
+    /* queue the tx data packets on to appropriate queue */
+    CSR_MA_PACKET_REQUEST *req = &signal->u.MaPacketRequest;
+    tx_buffered_packets_t *tx_q_item;
+    unsigned long lock_flags;
+
+    unifi_trace(priv, UDBG5, "entering enque_tx_data_pdu\n");
+    if(!list) {
+       unifi_error(priv,"List is not specified\n");
+       return CSR_RESULT_FAILURE;
+    }
+
+    /* Removes aged packets & adds the incoming packet */
+    if (priv->noOfPktQueuedInDriver >= CSR_WIFI_DRIVER_SUPPORT_FOR_MAX_PKT_QUEUEING) {
+        unifi_trace(priv,UDBG3,"number of pkts queued=  %d \n", priv->noOfPktQueuedInDriver);
+        verify_and_accomodate_tx_packet(priv);
+    }
+
+
+
+    tx_q_item = (tx_buffered_packets_t *)kmalloc(sizeof(tx_buffered_packets_t), GFP_ATOMIC);
+    if (tx_q_item == NULL) {
+        unifi_error(priv,
+                "Failed to allocate %d bytes for tx packet record\n",
+                sizeof(tx_buffered_packets_t));
+        func_exit();
+        return CSR_RESULT_FAILURE;
+    }
+
+    /* disable the preemption */
+    spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+    INIT_LIST_HEAD(&tx_q_item->q);
+    /* fill the tx_q structure members */
+    tx_q_item->bulkdata.os_data_ptr = bulkdata->d[0].os_data_ptr;
+    tx_q_item->bulkdata.data_length = bulkdata->d[0].data_length;
+    tx_q_item->bulkdata.os_net_buf_ptr = bulkdata->d[0].os_net_buf_ptr;
+    tx_q_item->bulkdata.net_buf_length = bulkdata->d[0].net_buf_length;
+    tx_q_item->interfaceTag = req->VirtualInterfaceIdentifier & 0xff;
+    tx_q_item->hostTag = req->HostTag;
+    tx_q_item->leSenderProcessId = signal->SignalPrimitiveHeader.SenderProcessId;
+    tx_q_item->transmissionControl = req->TransmissionControl;
+    tx_q_item->priority = req->Priority;
+    tx_q_item->rate = req->TransmitRate;
+    memcpy(tx_q_item->peerMacAddress.a, req->Ra.x, ETH_ALEN);
+
+
+
+    if (requeueOnSamePos) {
+        list_add(&tx_q_item->q, list);
+    } else {
+        list_add_tail(&tx_q_item->q, list);
+    }
+
+    /* Count of packet queued in driver */
+    priv->noOfPktQueuedInDriver++;
+    spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+    unifi_trace(priv, UDBG5, "leaving enque_tx_data_pdu\n");
+    return CSR_RESULT_SUCCESS;
+}
+
+#ifdef CSR_WIFI_REQUEUE_PACKET_TO_HAL
+CsrResult unifi_reque_ma_packet_request (void *ospriv, CsrUint32 host_tag,
+                                         CsrUint16 txStatus, bulk_data_desc_t *bulkDataDesc)
+{
+    CsrResult status = CSR_RESULT_SUCCESS;
+    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
+    netInterface_priv_t *interfacePriv;
+    struct list_head *list = NULL;
+    CsrWifiRouterCtrlStaInfo_t *staRecord = NULL;
+    bulk_data_param_t bulkData;
+    CSR_SIGNAL signal;
+    CSR_PRIORITY priority = 0;
+    CsrUint16 interfaceTag = 0;
+    unifi_TrafficQueue priority_q;
+    CsrUint16 frameControl = 0, frameType = 0;
+    unsigned long lock_flags;
+
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    /* If the current mode is not AP or P2PGO then just return failure
+     * to clear the hip slot
+     */
+    if(!((interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP) ||
+        (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO))) {
+        return CSR_RESULT_FAILURE;
+    }
+
+    unifi_trace(priv, UDBG6, "unifi_reque_ma_packet_request: host_tag = 0x%x\n", host_tag);
+
+    staRecord = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv,
+                                                                    (((CsrUint8 *) bulkDataDesc->os_data_ptr) + 4),
+                                                                    interfaceTag);
+    if (NULL == staRecord) {
+        unifi_trace(priv, UDBG5, "unifi_reque_ma_packet_request: Invalid STA record \n");
+        return CSR_RESULT_FAILURE;
+    }
+
+    /* Update TIM if MA-PACKET.cfm fails with status as Tx-retry-limit or No-BSS and then just return failure
+     * to clear the hip slot associated with the Packet
+     */
+    if (CSR_TX_RETRY_LIMIT == txStatus || CSR_TX_NO_BSS == txStatus) {
+        if (staRecord->timSet == CSR_WIFI_TIM_RESET || staRecord->timSet == CSR_WIFI_TIM_RESETTING)
+        {
+            unifi_trace(priv, UDBG2, "unifi_reque_ma_packet_request: CFM failed with Retry Limit or No BSS-->update TIM\n");
+            if (!staRecord->timRequestPendingFlag) {
+                update_tim(priv, staRecord->aid, 1, interfaceTag, staRecord->assignedHandle);
+            }
+            else {
+                /* Cache the TimSet value so that it will processed immidiatly after
+                 * completing the current setTim Request
+                 */
+                staRecord->updateTimReqQueued = 1;
+                unifi_trace(priv, UDBG6, "unifi_reque_ma_packet_request: One more UpdateTim Request(:%d)Queued for AID %x\n",
+                                         staRecord->updateTimReqQueued, staRecord->aid);
+            }
+        }
+        return CSR_RESULT_FAILURE;
+    }
+    else if ((CSR_TX_LIFETIME == txStatus) ||  (CSR_TX_BLOCK_ACK_TIMEOUT == txStatus) ||
+             (CSR_TX_FAIL_TRANSMISSION_VIF_INTERRUPTED == txStatus) ||
+             (CSR_TX_REJECTED_PEER_STATION_SLEEPING == txStatus)    ||
+             (CSR_TX_REJECTED_DTIM_STARTED == txStatus)) {
+        /* Extract the Frame control and the frame type */
+        frameControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(bulkDataDesc->os_data_ptr);
+        frameType =  ((frameControl & IEEE80211_FC_TYPE_MASK) >> FRAME_CONTROL_TYPE_FIELD_OFFSET);
+
+        /* Mgmt frames will not be re-queued for Tx
+         * so just return failure to clear the hip slot
+         */
+        if (IEEE802_11_FRAMETYPE_MANAGEMENT == frameType) {
+            return CSR_RESULT_FAILURE;
+        }
+        else if (IEEE802_11_FRAMETYPE_DATA == frameType) {
+            /* QOS NULL and DATA NULL frames will not be re-queued for Tx
+             * so just return failure to clear the hip slot
+             */
+            if ((((frameControl & IEEE80211_FC_SUBTYPE_MASK) >> FRAME_CONTROL_SUBTYPE_FIELD_OFFSET) == QOS_DATA_NULL) ||
+                (((frameControl & IEEE80211_FC_SUBTYPE_MASK) >> FRAME_CONTROL_SUBTYPE_FIELD_OFFSET)== DATA_NULL )) {
+                return CSR_RESULT_FAILURE;
+            }
+        }
+
+        /* Extract the Packet priority */
+        if (TRUE == staRecord->wmmOrQosEnabled) {
+            CsrUint16 qosControl = 0;
+            CsrUint8  dataFrameType = 0;
+
+            dataFrameType =((frameControl & IEEE80211_FC_SUBTYPE_MASK) >> 4);
+
+            if (dataFrameType == QOS_DATA) {
+                /* QoS control field is offset from frame control by 2 (frame control)
+                 * + 2 (duration/ID) + 2 (sequence control) + 3*ETH_ALEN or 4*ETH_ALEN
+                 */
+                if((frameControl & IEEE802_11_FC_TO_DS_MASK) && (frameControl & IEEE802_11_FC_FROM_DS_MASK)) {
+                    qosControl= CSR_GET_UINT16_FROM_LITTLE_ENDIAN(bulkDataDesc->os_data_ptr + 30);
+                }
+                else {
+                    qosControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(bulkDataDesc->os_data_ptr + 24);
+                }
+            }
+
+            priority = (CSR_PRIORITY)(qosControl & IEEE802_11_QC_TID_MASK);
+
+            if (priority < CSR_QOS_UP0 || priority > CSR_QOS_UP7) {
+                unifi_trace(priv, UDBG5, "unifi_reque_ma_packet_request: Invalid priority:%x \n", priority);
+                return CSR_RESULT_FAILURE;
+            }
+        }
+        else {
+            priority = CSR_CONTENTION;
+        }
+
+        /* Frame Bulk data to requeue it back to HAL Queues */
+        bulkData.d[0].os_data_ptr    = bulkDataDesc->os_data_ptr;
+        bulkData.d[0].data_length    = bulkDataDesc->data_length;
+        bulkData.d[0].os_net_buf_ptr = bulkDataDesc->os_net_buf_ptr;
+        bulkData.d[0].net_buf_length = bulkDataDesc->net_buf_length;
+
+        bulkData.d[1].os_data_ptr    = NULL;
+        bulkData.d[1].os_net_buf_ptr = NULL;
+        bulkData.d[1].data_length    = bulkData.d[1].net_buf_length = 0;
+
+        /* Initialize signal to zero */
+        memset(&signal, 0, sizeof(CSR_SIGNAL));
+
+        /* Frame MA Packet Req */
+        unifi_frame_ma_packet_req(priv, priority, 0, host_tag,
+                              interfaceTag, CSR_NO_CONFIRM_REQUIRED,
+                              priv->netdev_client->sender_id,
+                              staRecord->peerMacAddress.a, &signal);
+
+        /* Find the Q-Priority */
+        priority_q = unifi_frame_priority_to_queue(priority);
+        list = &staRecord->dataPdu[priority_q];
+
+        /* Place the Packet on to HAL Queue */
+        status = enque_tx_data_pdu(priv, &bulkData, list, &signal, TRUE);
+
+        /* Update the Per-station queued packet counter */
+        if (!status) {
+            spin_lock_irqsave(&priv->staRecord_lock, lock_flags);
+            staRecord->noOfPktQueued++;
+            spin_unlock_irqrestore(&priv->staRecord_lock, lock_flags);
+        }
+    }
+    else {
+        /* Packet will not be re-queued for any of the other MA Packet Tx failure
+         * reasons so just return failure to clear the hip slot
+         */
+        return CSR_RESULT_FAILURE;
+    }
+
+    return status;
+}
+#endif
+
+static void is_all_ac_deliver_enabled_and_moredata(CsrWifiRouterCtrlStaInfo_t *staRecord, CsrUint8 *allDeliveryEnabled, CsrUint8 *dataAvailable)
+{
+    CsrUint8 i;
+    *allDeliveryEnabled = TRUE;
+    for (i = 0 ;i < MAX_ACCESS_CATOGORY; i++) {
+        if (!IS_DELIVERY_ENABLED(staRecord->powersaveMode[i])) {
+            /* One is is not Delivery Enabled */
+            *allDeliveryEnabled = FALSE;
+            break;
+        }
+    }
+    if (*allDeliveryEnabled) {
+        *dataAvailable = (!list_empty(&staRecord->dataPdu[0]) || !list_empty(&staRecord->dataPdu[1])
+                          ||!list_empty(&staRecord->dataPdu[2]) ||!list_empty(&staRecord->dataPdu[3])
+                          ||!list_empty(&staRecord->mgtFrames));
+    }
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_handle_tim_cfm
+ *
+ *
+ *      This function updates tim status in host depending confirm status from firmware
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *      cfm             CSR_MLME_SET_TIM_CONFIRM
+ *      receiverProcessId SenderProcessID to fetch handle & timSet status
+ *
+ * ---------------------------------------------------------------------------
+ */
+void uf_handle_tim_cfm(unifi_priv_t *priv, CSR_MLME_SET_TIM_CONFIRM *cfm, CsrUint16 receiverProcessId)
+{
+    CsrUint8 handle = CSR_WIFI_GET_STATION_HANDLE_FROM_RECEIVER_ID(receiverProcessId);
+    CsrUint8 timSetStatus = CSR_WIFI_GET_TIMSET_STATE_FROM_RECEIVER_ID(receiverProcessId);
+    CsrUint16 interfaceTag = (cfm->VirtualInterfaceIdentifier & 0xff);
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    CsrWifiRouterCtrlStaInfo_t *staRecord = NULL;
+    /* This variable holds what TIM value we wanted to set in firmware */
+    CsrUint16 timSetValue = 0;
+    /* Irrespective of interface the count maintained */
+    static CsrUint8 retryCount = 0;
+    unsigned long lock_flags;
+    unifi_trace(priv, UDBG3, "entering %s, handle = %x, timSetStatus = %x\n", __FUNCTION__, handle, timSetStatus);
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_warning(priv, "bad interfaceTag = %x\n", interfaceTag);
+        return;
+    }
+
+    if ((handle != CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE) && (handle >= UNIFI_MAX_CONNECTIONS)) {
+        unifi_warning(priv, "bad station Handle = %x\n", handle);
+        return;
+    }
+
+    if (handle != CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE) {
+        spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+        if ((staRecord = ((CsrWifiRouterCtrlStaInfo_t *) (interfacePriv->staInfo[handle]))) == NULL) {
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+            unifi_warning(priv, "uf_handle_tim_cfm: station record is NULL  handle = %x\n", handle);
+            return;
+        }
+       spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+    }
+    switch(timSetStatus)
+    {
+        case CSR_WIFI_TIM_SETTING:
+            timSetValue = CSR_WIFI_TIM_SET;
+            break;
+        case CSR_WIFI_TIM_RESETTING:
+            timSetValue = CSR_WIFI_TIM_RESET;
+            break;
+        default:
+            unifi_warning(priv, "timSet state is %x: Debug\n", timSetStatus);
+            return;
+    }
+
+    /* check TIM confirm for success/failures */
+    switch(cfm->ResultCode)
+    {
+        case CSR_RC_SUCCESS:
+            if (handle != CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE) {
+                /* Unicast frame & station record available */
+                if (timSetStatus == staRecord->timSet) {
+                    staRecord->timSet = timSetValue;
+                    /* fh_cmd_q can also be full at some point of time!,
+                     * resetting count as queue is cleaned by firmware at this point
+                     */
+                    retryCount = 0;
+                    unifi_trace(priv, UDBG2, "tim (%s) successfully in firmware\n", (timSetValue)?"SET":"RESET");
+                } else {
+                    unifi_trace(priv, UDBG3, "receiver processID = %x, success: request & confirm states are not matching in TIM cfm: Debug status = %x, staRecord->timSet = %x, handle = %x\n",
+                                 receiverProcessId, timSetStatus, staRecord->timSet, handle);
+                }
+
+                /* Reset TIM pending flag to send next TIM request */
+                staRecord->timRequestPendingFlag = FALSE;
+
+                /* Make sure that one more UpdateTim request is queued, if Queued its value
+                 * should be CSR_WIFI_TIM_SET or CSR_WIFI_TIM_RESET
+                 */
+                if (0xFF != staRecord->updateTimReqQueued)
+                {
+                    /* Process the UpdateTim Request which is queued while previous UpdateTim was in progress */
+                    if (staRecord->timSet != staRecord->updateTimReqQueued)
+                    {
+                       unifi_trace(priv, UDBG2, "uf_handle_tim_cfm : Processing Queued UpdateTimReq \n");
+
+                       update_tim(priv, staRecord->aid, staRecord->updateTimReqQueued, interfaceTag, handle);
+
+                       staRecord->updateTimReqQueued = 0xFF;
+                    }
+                }
+            } else {
+
+                interfacePriv->bcTimSet = timSetValue;
+                /* fh_cmd_q can also be full at some point of time!,
+                 * resetting count as queue is cleaned by firmware at this point
+                 */
+                retryCount = 0;
+                unifi_trace(priv, UDBG3, "tim (%s) successfully for broadcast frame in firmware\n", (timSetValue)?"SET":"RESET");
+
+                /* Reset DTIM pending flag to send next DTIM request */
+                interfacePriv->bcTimSetReqPendingFlag = FALSE;
+
+                /* Make sure that one more UpdateDTim request is queued, if Queued its value
+                 * should be CSR_WIFI_TIM_SET or CSR_WIFI_TIM_RESET
+                 */
+                if (0xFF != interfacePriv->bcTimSetReqQueued)
+                {
+                    /* Process the UpdateTim Request which is queued while previous UpdateTim was in progress */
+                    if (interfacePriv->bcTimSet != interfacePriv->bcTimSetReqQueued)
+                    {
+                        unifi_trace(priv, UDBG2, "uf_handle_tim_cfm : Processing Queued UpdateDTimReq \n");
+
+                        update_tim(priv, 0, interfacePriv->bcTimSetReqQueued, interfaceTag, 0xFFFFFFFF);
+
+                        interfacePriv->bcTimSetReqQueued = 0xFF;
+                    }
+                }
+
+            }
+            break;
+        case CSR_RC_INVALID_PARAMETERS:
+        case CSR_RC_INSUFFICIENT_RESOURCE:
+            /* check for max retry limit & send again
+             * MAX_RETRY_LIMIT is not maintained for each set of transactions..Its generic
+             * If failure crosses this Limit, we have to take a call to FIX
+             */
+            if (retryCount > UNIFI_MAX_RETRY_LIMIT) {
+                CsrBool moreData = FALSE;
+                retryCount = 0;
+                /* Because of continuos traffic in fh_cmd_q the tim set request is failing (exceeding retry limit)
+                 * but if we didn't synchronize our timSet varible state with firmware then it can cause below issues
+                 * cond 1. We want to SET tim in firmware if its fails & max retry limit reached
+                 *   -> If host set's the timSet to 1, we wont try to send(as max retry reached) update tim but
+                 *   firmware is not updated with queue(TIM) status so it wont set TIM in beacon finally host start piling
+                 *    up data & wont try to set tim in firmware (This can cause worser performance)
+                 * cond 2. We want to reset tim in firmware it fails & reaches max retry limit
+                 *   -> If host sets the timSet to Zero, it wont try to set a TIM request unless we wont have any packets
+                 *   to be queued, so beacon unnecessarily advertizes the TIM
+                 */
+
+                if(staRecord) {
+                    if(!staRecord->wmmOrQosEnabled) {
+                        moreData = (!list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION]) ||
+                                !list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO]) ||
+                                !list_empty(&staRecord->mgtFrames));
+                    } else {
+                        /* Peer is QSTA */
+                        CsrUint8 allDeliveryEnabled = 0, dataAvailable = 0;
+                        /* Check if all AC's are Delivery Enabled */
+                        is_all_ac_deliver_enabled_and_moredata(staRecord, &allDeliveryEnabled, &dataAvailable);
+                        /*check for more data in non-delivery enabled queues*/
+                        moreData = (uf_is_more_data_for_non_delivery_ac(staRecord) || (allDeliveryEnabled && dataAvailable));
+
+                    }
+                    /* To avoid cond 1 & 2, check internal Queues status, if we have more Data then set RESET the timSet(0),
+                     *  so we are trying to be in sync with firmware & next packets before queuing atleast try to
+                     *  set TIM in firmware otherwise it SET timSet(1)
+                     */
+                    if (moreData) {
+                        staRecord->timSet = CSR_WIFI_TIM_RESET;
+                    } else {
+                        staRecord->timSet = CSR_WIFI_TIM_SET;
+                    }
+                } else {
+                    /* Its a broadcast frames */
+                    moreData = (!list_empty(&interfacePriv->genericMulticastOrBroadCastMgtFrames) ||
+                               !list_empty(&interfacePriv->genericMulticastOrBroadCastFrames));
+                    if (moreData) {
+                        update_tim(priv, 0, CSR_WIFI_TIM_SET, interfaceTag, 0xFFFFFFFF);
+                    } else {
+                        update_tim(priv, 0, CSR_WIFI_TIM_RESET, interfaceTag, 0xFFFFFFFF);
+                    }
+                }
+
+                unifi_error(priv, "no of error's for TIM setting crossed the Limit: verify\n");
+                return;
+            }
+            retryCount++;
+
+            if (handle != CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE) {
+                if (timSetStatus == staRecord->timSet) {
+                    unifi_warning(priv, "tim request failed, retry for AID = %x\n", staRecord->aid);
+                    update_tim(priv, staRecord->aid, timSetValue, interfaceTag, handle);
+                } else {
+                    unifi_trace(priv, UDBG1, "failure: request & confirm states are not matching in TIM cfm: Debug status = %x, staRecord->timSet = %x\n",
+                                  timSetStatus, staRecord->timSet);
+                }
+            } else {
+                unifi_warning(priv, "tim request failed, retry for broadcast frames\n");
+                update_tim(priv, 0, timSetValue, interfaceTag, 0xFFFFFFFF);
+            }
+            break;
+        default:
+            unifi_warning(priv, "tim update request failed resultcode = %x\n", cfm->ResultCode);
+    }
+
+    unifi_trace(priv, UDBG2, "leaving %s\n", __FUNCTION__);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  update_tim
+ *
+ *
+ *      This function updates tim status in firmware for AID[1 to UNIFI_MAX_CONNECTIONS] or
+ *       AID[0] for broadcast/multicast packets.
+ *
+ *      NOTE: The LSB (least significant BYTE) of senderId while sending this MLME premitive
+ *       has been modified(utilized) as below
+ *
+ *       SenderID in signal's SignalPrimitiveHeader is 2 byte the lowe byte bitmap is below
+ *
+ *       station handle(6 bits)      timSet Status (2 bits)
+ *       ---------------------       ----------------------
+ *       0  0  0  0  0  0        |       0  0
+ *
+ * timSet Status can be one of below:
+ *
+ * CSR_WIFI_TIM_RESET
+ * CSR_WIFI_TIM_RESETTING
+ * CSR_WIFI_TIM_SET
+ * CSR_WIFI_TIM_SETTING
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *      aid             can be 1 t0 UNIFI_MAX_CONNECTIONS & 0 means multicast/broadcast
+ *      setTim          value SET(1) / RESET(0)
+ *      interfaceTag    the interfaceID on which activity going on
+ *      handle          from  (0 <= handle < UNIFI_MAX_CONNECTIONS)
+ *
+ * ---------------------------------------------------------------------------
+ */
+void update_tim(unifi_priv_t * priv, CsrUint16 aid, CsrUint8 setTim, CsrUint16 interfaceTag, CsrUint32 handle)
+{
+    CSR_SIGNAL signal;
+    CsrInt32 r;
+    CSR_MLME_SET_TIM_REQUEST *req = &signal.u.MlmeSetTimRequest;
+    bulk_data_param_t *bulkdata = NULL;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    CsrUint8 senderIdLsb = 0;
+    CsrWifiRouterCtrlStaInfo_t *staRecord = NULL;
+    CsrUint32 oldTimSetStatus = 0, timSetStatus = 0;
+
+    unifi_trace(priv, UDBG5, "entering the update_tim routine\n");
+
+
+    if (handle == 0xFFFFFFFF) {
+        handle &= CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE;
+        if (setTim == interfacePriv->bcTimSet)
+        {
+            unifi_trace(priv, UDBG3, "update_tim, Drop:Hdl=%x, timval=%d, globalTim=%d\n", handle, setTim, interfacePriv->bcTimSet);
+            return;
+        }
+    } else if ((handle != 0xFFFFFFFF) && (handle >= UNIFI_MAX_CONNECTIONS)) {
+        unifi_warning(priv, "bad station Handle = %x\n", handle);
+        return;
+    }
+
+    if (setTim) {
+        timSetStatus =  CSR_WIFI_TIM_SETTING;
+    } else {
+        timSetStatus =  CSR_WIFI_TIM_RESETTING;
+    }
+
+    if (handle != CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE) {
+        if ((staRecord = ((CsrWifiRouterCtrlStaInfo_t *) (interfacePriv->staInfo[handle]))) == NULL) {
+            unifi_warning(priv, "station record is NULL in  update_tim: handle = %x :debug\n", handle);
+            return;
+        }
+        /* In case of signal sending failed, revert back to old state */
+        oldTimSetStatus = staRecord->timSet;
+        staRecord->timSet = timSetStatus;
+    }
+
+    /* pack senderID LSB */
+    senderIdLsb = CSR_WIFI_PACK_SENDER_ID_LSB_FOR_TIM_REQ(handle,  timSetStatus);
+
+    /* initialize signal to zero */
+    memset(&signal, 0, sizeof(CSR_SIGNAL));
+
+    /* Frame the MLME-SET-TIM request */
+    signal.SignalPrimitiveHeader.SignalId = CSR_MLME_SET_TIM_REQUEST_ID;
+    signal.SignalPrimitiveHeader.ReceiverProcessId = 0;
+    CSR_COPY_UINT16_TO_LITTLE_ENDIAN(((priv->netdev_client->sender_id & 0xff00) | senderIdLsb),
+                   (u8*)&signal.SignalPrimitiveHeader.SenderProcessId);
+
+    /* set The virtual interfaceIdentifier, aid, tim value */
+    req->VirtualInterfaceIdentifier = uf_get_vif_identifier(interfacePriv->interfaceMode,interfaceTag);
+    req->AssociationId = aid;
+    req->TimValue = setTim;
+
+
+    unifi_trace(priv, UDBG2, "update_tim:AID %x,senderIdLsb = 0x%x, handle = 0x%x, timSetStatus = %x, sender proceesID = %x \n",
+                aid,senderIdLsb, handle, timSetStatus, signal.SignalPrimitiveHeader.SenderProcessId);
+
+    /* Send the signal to UniFi */
+    r = ul_send_signal_unpacked(priv, &signal, bulkdata);
+    if (r) {
+        /* No need to free bulk data, as TIM request doesn't carries any data */
+        unifi_error(priv, "Error queueing CSR_MLME_SET_TIM_REQUEST signal\n");
+        if (staRecord) {
+            staRecord->timSet = oldTimSetStatus ;
+        }
+        else
+        {
+            /* MLME_SET_TIM.req sending failed here for AID0, so revert back our bcTimSet status */
+            interfacePriv->bcTimSet = !setTim;
+        }
+    }
+    else {
+        /* Update tim request pending flag and ensure no more TIM set requests are send
+           for the same station until TIM confirm is received */
+        if (staRecord) {
+            staRecord->timRequestPendingFlag = TRUE;
+        }
+        else
+        {
+            /* Update tim request (for AID 0) pending flag and ensure no more DTIM set requests are send
+             * for the same station until TIM confirm is received
+             */
+            interfacePriv->bcTimSetReqPendingFlag = TRUE;
+        }
+    }
+    unifi_trace(priv, UDBG5, "leaving the update_tim routine\n");
+}
+
+static
+void process_peer_active_transition(unifi_priv_t * priv,
+                                    CsrWifiRouterCtrlStaInfo_t *staRecord,
+                                    CsrUint16 interfaceTag)
+{
+    int r,i;
+    CsrBool spaceAvail[4] = {TRUE,TRUE,TRUE,TRUE};
+    tx_buffered_packets_t * buffered_pkt = NULL;
+    unsigned long lock_flags;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    unifi_trace(priv, UDBG5, "entering process_peer_active_transition\n");
+
+    if(IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag)) {
+        /* giving more priority to multicast packets so delaying unicast packets*/
+        unifi_trace(priv,UDBG2, "Multicast transmission is going on so resume unicast transmission after DTIM over\n");
+
+        /* As station is active now, even though AP is not able to send frames to it
+         * because of DTIM, it needs to reset the TIM here
+         */
+        if (!staRecord->timRequestPendingFlag){
+            if((staRecord->timSet == CSR_WIFI_TIM_SET) || (staRecord->timSet == CSR_WIFI_TIM_SETTING)){
+                update_tim(priv, staRecord->aid, 0, interfaceTag, staRecord->assignedHandle);
+            }
+        }
+        else
+        {
+            /* Cache the TimSet value so that it will processed immidiatly after
+             * completing the current setTim Request
+             */
+            staRecord->updateTimReqQueued = 0;
+            unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued,
+                        staRecord->aid);
+        }
+        return;
+    }
+    while((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->mgtFrames))) {
+        buffered_pkt->transmissionControl &=
+                     ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK);
+        if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,0,FALSE)) == -ENOSPC) {
+            unifi_trace(priv, UDBG2, "p_p_a_t:(ENOSPC) Mgt Frame queueing \n");
+            /* Enqueue at the head of the queue */
+            spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+            list_add(&buffered_pkt->q, &staRecord->mgtFrames);
+            spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+            priv->pausedStaHandle[3]=(CsrUint8)(staRecord->assignedHandle);
+            spaceAvail[3] = FALSE;
+            break;
+        } else {
+            if(r){
+                unifi_trace (priv, UDBG1, " HIP validation failure : PDU sending failed \n");
+                /* the PDU failed where we can't do any thing so free the storage */
+                unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+            }
+            kfree(buffered_pkt);
+        }
+    }
+    if (!staRecord->timRequestPendingFlag) {
+        if (staRecord->txSuspend) {
+            if(staRecord->timSet == CSR_WIFI_TIM_SET) {
+                update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle);
+            }
+            return;
+        }
+    }
+    else
+    {
+        /* Cache the TimSet value so that it will processed immidiatly after
+         * completing the current setTim Request
+         */
+        staRecord->updateTimReqQueued = 0;
+        unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued,
+                    staRecord->aid);
+    }
+    for(i=3;i>=0;i--) {
+        if(!spaceAvail[i])
+            continue;
+        unifi_trace(priv, UDBG6, "p_p_a_t:data pkt sending for AC %d \n",i);
+        while((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->dataPdu[i]))) {
+           buffered_pkt->transmissionControl &=
+                      ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK);
+           if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,0,FALSE)) == -ENOSPC) {
+               /* Clear the trigger bit transmission control*/
+               /* Enqueue at the head of the queue */
+               spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+               list_add(&buffered_pkt->q, &staRecord->dataPdu[i]);
+               spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+               priv->pausedStaHandle[i]=(CsrUint8)(staRecord->assignedHandle);
+               break;
+           } else {
+              if(r){
+                  unifi_trace (priv, UDBG1, " HIP validation failure : PDU sending failed \n");
+                  /* the PDU failed where we can't do any thing so free the storage */
+                  unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+               }
+              kfree(buffered_pkt);
+           }
+        }
+    }
+    if (!staRecord->timRequestPendingFlag){
+        if((staRecord->timSet  == CSR_WIFI_TIM_SET) || (staRecord->timSet  == CSR_WIFI_TIM_SETTING)) {
+            unifi_trace(priv, UDBG3, "p_p_a_t:resetting tim .....\n");
+            update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle);
+        }
+    }
+    else
+    {
+        /* Cache the TimSet value so that it will processed immidiatly after
+         * completing the current setTim Request
+         */
+        staRecord->updateTimReqQueued = 0;
+        unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued,
+                    staRecord->aid);
+    }
+    unifi_trace(priv, UDBG5, "leaving process_peer_active_transition\n");
+}
+
+
+
+void uf_process_ma_pkt_cfm_for_ap(unifi_priv_t *priv,CsrUint16 interfaceTag, const CSR_MA_PACKET_CONFIRM *pkt_cfm)
+{
+    netInterface_priv_t *interfacePriv;
+    CsrUint8 i;
+    CsrWifiRouterCtrlStaInfo_t *staRecord = NULL;
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+
+    if(pkt_cfm->HostTag == interfacePriv->multicastPduHostTag) {
+         unifi_trace(priv,UDBG2,"CFM for marked Multicast Tag = %x\n",interfacePriv->multicastPduHostTag);
+         interfacePriv->multicastPduHostTag = 0xffffffff;
+         resume_suspended_uapsd(priv,interfaceTag);
+         resume_unicast_buffered_frames(priv,interfaceTag);
+         if(list_empty(&interfacePriv->genericMulticastOrBroadCastMgtFrames) &&
+              list_empty(&interfacePriv->genericMulticastOrBroadCastFrames)) {
+            unifi_trace(priv,UDBG1,"Resetting multicastTIM");
+            if (!interfacePriv->bcTimSetReqPendingFlag)
+            {
+                update_tim(priv,0,CSR_WIFI_TIM_RESET,interfaceTag, 0xFFFFFFFF);
+            }
+            else
+            {
+                /* Cache the DTimSet value so that it will processed immidiatly after
+                 * completing the current setDTim Request
+                 */
+                 interfacePriv->bcTimSetReqQueued = CSR_WIFI_TIM_RESET;
+                 unifi_trace(priv, UDBG2, "uf_process_ma_pkt_cfm_for_ap : One more UpdateDTim Request(%d) Queued \n",
+                             interfacePriv->bcTimSetReqQueued);
+            }
+
+        }
+        return;
+    }
+
+    /* Check if it is a Confirm for null data frame used
+     * for probing station activity
+     */
+    for(i =0; i < UNIFI_MAX_CONNECTIONS; i++) {
+        staRecord = (CsrWifiRouterCtrlStaInfo_t *) (interfacePriv->staInfo[i]);
+        if (staRecord && (staRecord->nullDataHostTag == pkt_cfm->HostTag)) {
+
+            unifi_trace(priv, UDBG1, "CFM for Inactive probe Null frame (tag = %x, status = %d)\n",
+                                    pkt_cfm->HostTag,
+                                    pkt_cfm->TransmissionStatus
+                                    );
+            staRecord->nullDataHostTag = INVALID_HOST_TAG;
+
+            if(pkt_cfm->TransmissionStatus == CSR_TX_RETRY_LIMIT){
+                CsrTime now;
+                CsrTime inactive_time;
+
+                unifi_trace(priv, UDBG1, "Nulldata to probe STA ALIVE Failed with retry limit\n");
+                /* Recheck if there is some activity after null data is sent.
+                *
+                * If still there is no activity then send a disconnected indication
+                * to SME to delete the station record.
+                */
+                if (staRecord->activity_flag){
+                    return;
+                }
+                now = CsrTimeGet(NULL);
+
+                if (staRecord->lastActivity > now)
+                {
+                    /* simple timer wrap (for 1 wrap) */
+                    inactive_time = CsrTimeAdd((CsrTime)CsrTimeSub(CSR_SCHED_TIME_MAX, staRecord->lastActivity),
+                                               now);
+                }
+                else
+                {
+                    inactive_time = (CsrTime)CsrTimeSub(now, staRecord->lastActivity);
+                }
+
+                if (inactive_time >= STA_INACTIVE_TIMEOUT_VAL)
+                {
+                    struct list_head send_cfm_list;
+                    CsrUint8 j;
+
+                    /* The SME/NME may be waiting for confirmation for requested frames to this station.
+                     * Though this is --VERY UNLIKELY-- in case of station in active mode. But still as a
+                     * a defensive check, it loops through buffered frames for this station and if confirmation
+                     * is requested, send auto confirmation with failure status. Also flush the frames so
+                     * that these are not processed again in PEER_DEL_REQ handler.
+                     */
+                    INIT_LIST_HEAD(&send_cfm_list);
+
+                    uf_prepare_send_cfm_list_for_queued_pkts(priv,
+                                                             &send_cfm_list,
+                                                             &(staRecord->mgtFrames));
+
+                    uf_flush_list(priv, &(staRecord->mgtFrames));
+
+                    for(j = 0; j < MAX_ACCESS_CATOGORY; j++){
+                        uf_prepare_send_cfm_list_for_queued_pkts(priv,
+                                                                 &send_cfm_list,
+                                                                 &(staRecord->dataPdu[j]));
+
+                        uf_flush_list(priv,&(staRecord->dataPdu[j]));
+                    }
+
+                    send_auto_ma_packet_confirm(priv, staRecord->interfacePriv, &send_cfm_list);
+
+
+
+                    unifi_warning(priv, "uf_process_ma_pkt_cfm_for_ap: Router Disconnected IND Peer (%x-%x-%x-%x-%x-%x)\n",
+                                             staRecord->peerMacAddress.a[0],
+                                             staRecord->peerMacAddress.a[1],
+                                             staRecord->peerMacAddress.a[2],
+                                             staRecord->peerMacAddress.a[3],
+                                             staRecord->peerMacAddress.a[4],
+                                             staRecord->peerMacAddress.a[5]);
+
+                    CsrWifiRouterCtrlConnectedIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,
+                                                      0,
+                                                      staRecord->interfacePriv->InterfaceTag,
+                                                      staRecord->peerMacAddress,
+                                                      CSR_WIFI_ROUTER_CTRL_PEER_DISCONNECTED);
+                }
+
+            }
+            else if (pkt_cfm->TransmissionStatus == CSR_TX_SUCCESSFUL)
+            {
+                 staRecord->activity_flag = TRUE;
+            }
+        }
+    }
+}
+
+#endif
+CsrUint16 uf_get_vif_identifier (CsrWifiRouterCtrlMode mode, CsrUint16 tag)
+{
+    switch(mode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_STA:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI:
+            return (0x02<<8|tag);
+
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+            return (0x03<<8|tag);
+
+        case CSR_WIFI_ROUTER_CTRL_MODE_IBSS:
+            return (0x01<<8|tag);
+
+        case CSR_WIFI_ROUTER_CTRL_MODE_MONITOR:
+            return (0x04<<8|tag);
+        case CSR_WIFI_ROUTER_CTRL_MODE_AMP:
+            return (0x05<<8|tag);
+        default:
+            return tag;
+    }
+}
+
+#ifdef CSR_SUPPORT_SME
+
+/*
+ * ---------------------------------------------------------------------------
+ *  update_macheader
+ *
+ *
+ *      These functions updates mac header for intra BSS packet
+ *      routing.
+ *      NOTE: This function always has to be called in rx context which
+ *      is in bh thread context since GFP_KERNEL is used. In soft IRQ/ Interrupt
+ *      context shouldn't be used
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *      skb             Socket buffer containing data packet to transmit
+ *      newSkb          Socket buffer containing data packet + Mac header if no sufficient headroom in skb
+ *      priority        to append QOS control header in Mac header
+ *      bulkdata        if newSkb allocated then bulkdata updated to send to unifi
+ *      interfaceTag    the interfaceID on which activity going on
+ *      macHeaderLengthInBytes no. of bytes of mac header in received frame
+ *      qosDestination  used to append Qos control field
+ *
+ *  Returns:
+ *      Zero on success or -1 on error.
+ * ---------------------------------------------------------------------------
+ */
+
+static int update_macheader(unifi_priv_t *priv, struct sk_buff *skb,
+                            struct sk_buff *newSkb, CSR_PRIORITY *priority,
+                            bulk_data_param_t *bulkdata, CsrUint16 interfaceTag,
+                            CsrUint8 macHeaderLengthInBytes,
+                            CsrUint8 qosDestination)
+{
+
+    CsrUint16 *fc = NULL;
+    CsrUint8 direction = 0, toDs, fromDs;
+    CsrUint8 *bufPtr = NULL;
+    CsrUint8 sa[ETH_ALEN], da[ETH_ALEN];
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    int headroom;
+    CsrUint8 macHeaderBuf[IEEE802_11_DATA_FRAME_MAC_HEADER_SIZE] = {0};
+
+    unifi_trace(priv, UDBG5, "entering the update_macheader function\n");
+
+    /* temporary buffer for the Mac header storage */
+    memcpy(macHeaderBuf, skb->data, macHeaderLengthInBytes);
+
+    /* remove the Macheader from the skb */
+    skb_pull(skb, macHeaderLengthInBytes);
+
+    /* get the skb headroom for skb_push check */
+    headroom = skb_headroom(skb);
+
+    /*  pointer to frame control field */
+    fc = (CsrUint16*) macHeaderBuf;
+
+    toDs = (*fc & cpu_to_le16(IEEE802_11_FC_TO_DS_MASK))?1 : 0;
+    fromDs = (*fc & cpu_to_le16(IEEE802_11_FC_FROM_DS_MASK))? 1: 0;
+    unifi_trace(priv, UDBG5, "In update_macheader function, fromDs = %x, toDs = %x\n", fromDs, toDs);
+    direction = ((fromDs | (toDs << 1)) & 0x3);
+
+    /* Address1 or 3 from the macheader */
+    memcpy(da, macHeaderBuf+4+toDs*12, ETH_ALEN);
+    /* Address2, 3 or 4 from the mac header */
+    memcpy(sa, macHeaderBuf+10+fromDs*(6+toDs*8), ETH_ALEN);
+
+    unifi_trace(priv, UDBG3, "update_macheader:direction = %x\n", direction);
+    /* update the toDs, fromDs & address fields in Mac header */
+    switch(direction)
+    {
+        case 2:
+            /* toDs = 1 & fromDs = 0 , toAp when frames received from peer
+             * while sending this packet to Destination the Mac header changed
+             * as fromDs = 1 & toDs = 0, fromAp
+             */
+            *fc &= cpu_to_le16(~IEEE802_11_FC_TO_DS_MASK);
+            *fc |= cpu_to_le16(IEEE802_11_FC_FROM_DS_MASK);
+            /* Address1: MAC address of the actual destination (4 = 2+2) */
+            memcpy(macHeaderBuf + 4, da, ETH_ALEN);
+            /* Address2: The MAC address of the AP (10 = 2+2+6) */
+            memcpy(macHeaderBuf + 10, &interfacePriv->bssid, ETH_ALEN);
+            /* Address3: MAC address of the actual source from mac header (16 = 2+2+6+6) */
+            memcpy(macHeaderBuf + 16, sa, ETH_ALEN);
+            break;
+        case 3:
+            unifi_trace(priv, UDBG3, "when both the toDs & fromDS set, NOT SUPPORTED\n");
+            break;
+        default:
+            unifi_trace(priv, UDBG3, "problem in decoding packet in update_macheader \n");
+            return -1;
+    }
+
+    /* frameType is Data always, Validation is done before calling this function */
+
+    /* check for the souce station type */
+    switch(le16_to_cpu(*fc) & IEEE80211_FC_SUBTYPE_MASK)
+    {
+        case IEEE802_11_FC_TYPE_QOS_DATA & IEEE80211_FC_SUBTYPE_MASK:
+            /* No need to modify the qos control field */
+            if (!qosDestination) {
+
+                /* If source Sta is QOS enabled & if this bit set, then HTC is supported by
+                 * peer station & htc field present in macHeader
+                 */
+                if (*fc & cpu_to_le16(IEEE80211_FC_ORDER_MASK)) {
+                    /* HT control field present in Mac header
+                     * 6 = sizeof(qosControl) + sizeof(htc)
+                     */
+                    macHeaderLengthInBytes -= 6;
+                } else {
+                    macHeaderLengthInBytes -= 2;
+                }
+                /* Destination STA is non qos so change subtype to DATA */
+                *fc &= cpu_to_le16(~IEEE80211_FC_SUBTYPE_MASK);
+                *fc |= cpu_to_le16(IEEE802_11_FC_TYPE_DATA);
+                /* remove the qos control field & HTC(if present). new macHeaderLengthInBytes is less than old
+                 * macHeaderLengthInBytes so no need to verify skb headroom
+                 */
+                if (headroom < macHeaderLengthInBytes) {
+                    unifi_trace(priv, UDBG1, " sufficient headroom not there to push updated mac header \n");
+                    return -1;
+                }
+                bufPtr = (CsrUint8 *) skb_push(skb, macHeaderLengthInBytes);
+
+                /*  update bulk data os_data_ptr */
+                bulkdata->d[0].os_data_ptr = skb->data;
+                bulkdata->d[0].os_net_buf_ptr = (unsigned char*)skb;
+                bulkdata->d[0].data_length = skb->len;
+
+            } else {
+                /* pointing to QOS control field */
+                CsrUint8 qc;
+                if (*fc & cpu_to_le16(IEEE80211_FC_ORDER_MASK)) {
+                    qc = *((CsrUint8*)(macHeaderBuf + (macHeaderLengthInBytes - 4 - 2)));
+                } else {
+                    qc = *((CsrUint8*)(macHeaderBuf + (macHeaderLengthInBytes - 2)));
+                }
+
+                if ((qc & IEEE802_11_QC_TID_MASK) > 7) {
+                    *priority = 7;
+                } else {
+                    *priority = qc & IEEE802_11_QC_TID_MASK;
+                }
+
+                unifi_trace(priv, UDBG1, "Incoming packet priority from QSTA is %x\n", *priority);
+
+                if (headroom < macHeaderLengthInBytes) {
+                    unifi_trace(priv, UDBG3, " sufficient headroom not there to push updated mac header \n");
+                    return -1;
+                }
+                bufPtr = (CsrUint8 *) skb_push(skb, macHeaderLengthInBytes);
+            }
+            break;
+        default:
+            {
+                bulk_data_param_t data_ptrs;
+                CsrResult csrResult;
+                unifi_trace(priv, UDBG5, "normal Data packet, NO QOS \n");
+
+                if (qosDestination) {
+                    CsrUint8 qc = 0;
+                    unifi_trace(priv, UDBG3, "destination is QOS station \n");
+
+                    /* Set Ma-Packet.req UP to UP0 */
+                    *priority = CSR_QOS_UP0;
+
+                    /* prepare the qos control field */
+                    qc |= CSR_QOS_UP0;
+                    /* no Amsdu is in ap buffer so eosp is left 0 */
+                    if (da[0] & 0x1) {
+                        /* multicast/broadcast frames, no acknowledgement needed */
+                        qc |= 1 << 5;
+                    }
+
+                    /* update new Mac header Length with 2 = sizeof(qos control) */
+                    macHeaderLengthInBytes += 2;
+
+                    /* received DATA frame but destiantion is QOS station so update subtype to QOS*/
+                    *fc &= cpu_to_le16(~IEEE80211_FC_SUBTYPE_MASK);
+                    *fc |= cpu_to_le16(IEEE802_11_FC_TYPE_QOS_DATA);
+
+                    /* appendQosControlOffset = macHeaderLengthInBytes - 2, since source sta is not QOS */
+                    macHeaderBuf[macHeaderLengthInBytes - 2] = qc;
+                    /* txopLimit is 0 */
+                    macHeaderBuf[macHeaderLengthInBytes - 1] = 0;
+                    if (headroom < macHeaderLengthInBytes) {
+                        csrResult = unifi_net_data_malloc(priv, &data_ptrs.d[0], skb->len + macHeaderLengthInBytes);
+
+                        if (csrResult != CSR_RESULT_SUCCESS) {
+                            unifi_error(priv, " failed to allocate request_data. in update_macheader func\n");
+                            return -1;
+                        }
+                        newSkb = (struct sk_buff *)(data_ptrs.d[0].os_net_buf_ptr);
+                        newSkb->len = skb->len + macHeaderLengthInBytes;
+
+                        memcpy((void*)data_ptrs.d[0].os_data_ptr + macHeaderLengthInBytes,
+                                skb->data, skb->len);
+
+                        bulkdata->d[0].os_data_ptr = newSkb->data;
+                        bulkdata->d[0].os_net_buf_ptr = (unsigned char*)newSkb;
+                        bulkdata->d[0].data_length = newSkb->len;
+
+                        bufPtr = (CsrUint8*)data_ptrs.d[0].os_data_ptr;
+
+                        /* The old skb will not be used again */
+                        kfree_skb(skb);
+                    } else {
+                        /* skb headroom is sufficient to append Macheader */
+                        bufPtr = (CsrUint8*)skb_push(skb, macHeaderLengthInBytes);
+                        bulkdata->d[0].os_data_ptr = skb->data;
+                        bulkdata->d[0].os_net_buf_ptr = (unsigned char*)skb;
+                        bulkdata->d[0].data_length = skb->len;
+                    }
+                } else {
+                    unifi_trace(priv, UDBG3, "destination is not a QSTA\n");
+                    if (headroom < macHeaderLengthInBytes) {
+                        csrResult = unifi_net_data_malloc(priv, &data_ptrs.d[0], skb->len + macHeaderLengthInBytes);
+
+                        if (csrResult != CSR_RESULT_SUCCESS) {
+                            unifi_error(priv, " failed to allocate request_data. in update_macheader func\n");
+                            return -1;
+                        }
+                        newSkb = (struct sk_buff *)(data_ptrs.d[0].os_net_buf_ptr);
+                        newSkb->len = skb->len + macHeaderLengthInBytes;
+
+                        memcpy((void*)data_ptrs.d[0].os_data_ptr + macHeaderLengthInBytes,
+                                skb->data, skb->len);
+
+                        bulkdata->d[0].os_data_ptr = newSkb->data;
+                        bulkdata->d[0].os_net_buf_ptr = (unsigned char*)newSkb;
+                        bulkdata->d[0].data_length = newSkb->len;
+
+                        bufPtr = (CsrUint8*)data_ptrs.d[0].os_data_ptr;
+
+                        /* The old skb will not be used again */
+                        kfree_skb(skb);
+                    } else {
+                        /* skb headroom is sufficient to append Macheader */
+                        bufPtr = (CsrUint8*)skb_push(skb, macHeaderLengthInBytes);
+                        bulkdata->d[0].os_data_ptr = skb->data;
+                        bulkdata->d[0].os_net_buf_ptr = (unsigned char*)skb;
+                        bulkdata->d[0].data_length = skb->len;
+                    }
+                }
+            }
+    }
+
+    /* prepare the complete skb, by pushing the MAC header to the begining of the skb->data */
+    unifi_trace(priv, UDBG5, "updated Mac Header: %d \n",macHeaderLengthInBytes);
+    memcpy(bufPtr, macHeaderBuf, macHeaderLengthInBytes);
+
+    unifi_trace(priv, UDBG5, "leaving the update_macheader function\n");
+    return 0;
+}
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_ap_process_data_pdu
+ *
+ *
+ *      Takes care of intra BSS admission control & routing packets within BSS
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *      skb             Socket buffer containing data packet to transmit
+ *      ehdr            ethernet header to fetch priority of packet
+ *      srcStaInfo      source stations record for connection verification
+ *      packed_signal
+ *      signal_len
+ *      signal          MA-PACKET.indication signal
+ *      bulkdata        if newSkb allocated then bulkdata updated to send to unifi
+ *      macHeaderLengthInBytes no. of bytes of mac header in received frame
+ *
+ *  Returns:
+ *      Zero on success(ap processing complete) or -1 if packet also have to be sent to NETDEV.
+ * ---------------------------------------------------------------------------
+ */
+int
+uf_ap_process_data_pdu(unifi_priv_t *priv, struct sk_buff *skb,
+                       struct ethhdr *ehdr, CsrWifiRouterCtrlStaInfo_t * srcStaInfo,
+                       const CSR_SIGNAL *signal,
+                       bulk_data_param_t *bulkdata,
+                       CsrUint8 macHeaderLengthInBytes)
+{
+    const CSR_MA_PACKET_INDICATION *ind = &(signal->u.MaPacketIndication);
+    CsrUint16 interfaceTag = (ind->VirtualInterfaceIdentifier & 0x00ff);
+    struct sk_buff *newSkb = NULL;
+    /* pointer to skb or private skb created using skb_copy() */
+    struct sk_buff *skbPtr = skb;
+    CsrBool sendToNetdev = FALSE;
+    CsrBool qosDestination = FALSE;
+    CSR_PRIORITY priority = CSR_CONTENTION;
+    CsrWifiRouterCtrlStaInfo_t *dstStaInfo = NULL;
+    netInterface_priv_t *interfacePriv;
+
+    unifi_trace(priv, UDBG5, "entering  uf_ap_process_data_pdu %d\n",macHeaderLengthInBytes);
+    /* InterfaceTag validation from MA_PACKET.indication */
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_trace(priv, UDBG1, "Interface Tag is Invalid in uf_ap_process_data_pdu\n");
+        unifi_net_data_free(priv, &bulkdata->d[0]);
+        return 0;
+    }
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if((interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) &&
+       (interfacePriv->intraBssEnabled == FALSE)) {
+        unifi_trace(priv, UDBG2, "uf_ap_process_data_pdu:P2P GO intrabssEnabled?= %d\n", interfacePriv->intraBssEnabled);
+
+        /*In P2P GO case, if intraBSS distribution Disabled then don't do IntraBSS routing */
+        /* If destination in our BSS then drop otherwise give packet to netdev */
+        dstStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv, ehdr->h_dest, interfaceTag);
+        if (dstStaInfo) {
+            unifi_net_data_free(priv, &bulkdata->d[0]);
+            return 0;
+        }
+        /* May be associated P2PCLI trying to send the packets on backbone (Netdev) */
+        return -1;
+    }
+
+    if(!memcmp(ehdr->h_dest, interfacePriv->bssid.a, ETH_ALEN)) {
+        /* This packet will be given to the TCP/IP stack since this packet is for us(AP)
+         * No routing needed */
+        unifi_trace(priv, UDBG4, "destination address is csr_ap\n");
+        return -1;
+    }
+
+    /* fetch the destination record from staion record database */
+    dstStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv, ehdr->h_dest, interfaceTag);
+
+    /* AP mode processing, & if packet is unicast */
+    if(!dstStaInfo) {
+        if (!(ehdr->h_dest[0] & 0x1)) {
+            /* destination not in station record & its a unicast packet, so pass the packet to network stack */
+            unifi_trace(priv, UDBG3, "unicast frame & destination record not exist, send to netdev proto = %x\n", htons(skb->protocol));
+            return -1;
+        } else {
+            /* packet is multicast/broadcast */
+            /* copy the skb to skbPtr, send skb to netdev & skbPtr to multicast/broad cast list */
+            unifi_trace(priv, UDBG5, "skb_copy, in  uf_ap_process_data_pdu, protocol = %x\n", htons(skb->protocol));
+            skbPtr = skb_copy(skb, GFP_KERNEL);
+            if(skbPtr == NULL) {
+                /* We don't have memory to don't send the frame in BSS*/
+                unifi_notice(priv, "broacast/multicast frame can't be sent in BSS No memeory: proto = %x\n", htons(skb->protocol));
+                return -1;
+            }
+            sendToNetdev = TRUE;
+        }
+    } else {
+
+        /* validate the Peer & Destination Station record */
+        if (uf_process_station_records_for_sending_data(priv, interfaceTag, srcStaInfo, dstStaInfo)) {
+            unifi_notice(priv, "uf_ap_process_data_pdu: station record validation failed \n");
+            interfacePriv->stats.rx_errors++;
+            unifi_net_data_free(priv, &bulkdata->d[0]);
+            return 0;
+        }
+    }
+
+    /* BroadCast packet received and it's been sent as non QOS packets.
+     * Since WMM spec not mandates broadcast/multicast to be sent as QOS data only,
+     * if all Peers are QSTA
+     */
+    if(sendToNetdev) {
+       /* BroadCast packet and it's been sent as non QOS packets */
+        qosDestination = FALSE;
+    } else if(dstStaInfo && (dstStaInfo->wmmOrQosEnabled == TRUE)) {
+          qosDestination = TRUE;
+    }
+
+    unifi_trace(priv, UDBG3, "uf_ap_process_data_pdu QoS destination  = %s\n", (qosDestination)? "TRUE": "FALSE");
+
+    /* packet is allowed to send to unifi, update the Mac header */
+    if (update_macheader(priv, skbPtr, newSkb, &priority, bulkdata, interfaceTag, macHeaderLengthInBytes, qosDestination)) {
+        interfacePriv->stats.rx_errors++;
+        unifi_notice(priv, "(Packet Drop) failed to update the Mac header in uf_ap_process_data_pdu\n");
+        if (sendToNetdev) {
+            /*  Free's the skb_copy(skbPtr) data since packet processing failed */
+            bulkdata->d[0].os_data_ptr = skbPtr->data;
+            bulkdata->d[0].os_net_buf_ptr = (unsigned char*)skbPtr;
+            bulkdata->d[0].data_length = skbPtr->len;
+            unifi_net_data_free(priv, &bulkdata->d[0]);
+        }
+        return -1;
+    }
+
+    unifi_trace(priv, UDBG3, "Mac Header updated...calling uf_process_ma_packet_req \n");
+
+    /* Packet is ready to send to unifi ,transmissionControl = 0x0004, confirmation is not needed for data packets */
+    if (uf_process_ma_packet_req(priv,  ehdr->h_dest, 0xffffffff, interfaceTag, CSR_NO_CONFIRM_REQUIRED, (CSR_RATE)0,priority, priv->netdev_client->sender_id, bulkdata)) {
+        if (sendToNetdev) {
+            unifi_trace(priv, UDBG1, "In uf_ap_process_data_pdu, (Packet Drop) uf_process_ma_packet_req failed. freeing skb_copy data (original data sent to Netdev)\n");
+            /*  Free's the skb_copy(skbPtr) data since packet processing failed */
+            bulkdata->d[0].os_data_ptr = skbPtr->data;
+            bulkdata->d[0].os_net_buf_ptr = (unsigned char*)skbPtr;
+            bulkdata->d[0].data_length = skbPtr->len;
+            unifi_net_data_free(priv, &bulkdata->d[0]);
+        } else {
+            /* This free's the skb data */
+            unifi_trace(priv, UDBG1, "In uf_ap_process_data_pdu, (Packet Drop). Unicast data so freeing original skb \n");
+            unifi_net_data_free(priv, &bulkdata->d[0]);
+        }
+    }
+    unifi_trace(priv, UDBG5, "leaving  uf_ap_process_data_pdu\n");
+
+    if (sendToNetdev) {
+        /* The packet is multicast/broadcast, so after AP processing packet has to
+         * be sent to netdev, if peer port state is open
+        */
+        unifi_trace(priv, UDBG4, "Packet will be routed to NetDev\n");
+        return -1;
+    }
+    /* Ap handled the packet & its a unicast packet, no need to send to netdev */
+    return 0;
+}
+
+#endif
+
+CsrResult uf_process_ma_packet_req(unifi_priv_t *priv,
+                                   CsrUint8 *peerMacAddress,
+                                   CSR_CLIENT_TAG hostTag,
+                                   CsrUint16 interfaceTag,
+                                   CSR_TRANSMISSION_CONTROL transmissionControl,
+                                   CSR_RATE TransmitRate,
+                                   CSR_PRIORITY priority,
+                                   CSR_PROCESS_ID leSenderProcessId,
+                                   bulk_data_param_t *bulkdata)
+{
+    CsrResult status = CSR_RESULT_SUCCESS;
+    CSR_SIGNAL signal;
+    int result;
+#ifdef CSR_SUPPORT_SME
+   CsrWifiRouterCtrlStaInfo_t *staRecord = NULL;
+    const CsrUint8 *macHdrLocation =  bulkdata->d[0].os_data_ptr;
+    CsrWifiPacketType pktType;
+    int frameType = 0;
+    CsrBool queuePacketDozing = FALSE;
+    CsrUint32 priority_q;
+    CsrUint16 frmCtrl;
+    struct list_head * list = NULL; /* List to which buffered PDUs are to be enqueued*/
+    CsrBool setBcTim=FALSE;
+    netInterface_priv_t *interfacePriv;
+    CsrBool requeueOnSamePos = FALSE;
+    CsrUint32 handle = 0xFFFFFFFF;
+    unsigned long lock_flags;
+
+    UF_TRACE_MAC(priv, UDBG5, "entering uf_process_ma_packet_req, peer: ", peerMacAddress);
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "interfaceTag >= CSR_WIFI_NUM_INTERFACES, interfacetag = %d\n", interfaceTag);
+        return CSR_RESULT_FAILURE;
+    }
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+
+    /* fetch the station record for corresponding peer mac address */
+    if ((staRecord = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv, peerMacAddress, interfaceTag))) {
+        handle = staRecord->assignedHandle;
+    }
+
+    /* Frame ma-packet.req, this is saved/transmitted depend on queue state */
+    unifi_frame_ma_packet_req(priv, priority, TransmitRate, hostTag,
+                              interfaceTag, transmissionControl, leSenderProcessId,
+                              peerMacAddress, &signal);
+
+   /* Since it's common path between STA & AP mode, in case of STA packet
+     * need not to be queued but in AP case we have to queue PDU's in
+     * different scenarios
+     */
+    switch(interfacePriv->interfaceMode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+            /* For this mode processing done below */
+            break;
+        default:
+            /* In case of STA/IBSS/P2PCLI/AMP, no checks needed send the packet down & return */
+            unifi_trace(priv, UDBG5, "In %s, interface mode is %x \n", __FUNCTION__, interfacePriv->interfaceMode);
+            if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_NONE) {
+                unifi_warning(priv, "In %s, interface mode NONE \n", __FUNCTION__);
+            }
+            if ((result = ul_send_signal_unpacked(priv, &signal, bulkdata))) {
+                status = CSR_RESULT_FAILURE;
+            }
+            return status;
+    }
+
+    /* -----Only AP/P2pGO mode handling falls below----- */
+
+    /* convert priority to queue */
+    priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY) priority);
+
+    /* check the powersave status of the peer */
+    if (staRecord && (staRecord->currentPeerState ==
+                     CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE)) {
+        /* Peer is dozing & packet have to be delivered, so buffer the packet &
+         * update the TIM
+         */
+        queuePacketDozing = TRUE;
+    }
+
+    /* find the type of frame unicast or mulicast/broadcast */
+    if (*peerMacAddress & 0x1) {
+        /* Multicast/broadCast data are always triggered by vif_availability.ind
+         * at the DTIM
+         */
+        pktType = CSR_WIFI_MULTICAST_PDU;
+    } else {
+        pktType = CSR_WIFI_UNICAST_PDU;
+    }
+
+    /* Fetch the frame control field from mac header & check for frame type */
+    frmCtrl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation);
+
+    /* Processing done according to Frame/Packet type */
+    frameType =  ((frmCtrl & 0x000c) >> FRAME_CONTROL_TYPE_FIELD_OFFSET);
+    switch(frameType)
+    {
+        case IEEE802_11_FRAMETYPE_MANAGEMENT:
+
+            switch(pktType)
+            {
+                case CSR_WIFI_UNICAST_PDU:
+                    unifi_trace(priv, UDBG5, "management unicast PDU in uf_process_ma_packet_req \n");
+                    /* push the packet in to the queue with appropriate mgt list */
+                    if (!staRecord) {
+                        /* push the packet to the unifi if list is empty (if packet lost how to re-enque) */
+                        if (list_empty(&interfacePriv->genericMgtFrames)) {
+#ifdef CSR_SUPPORT_SME
+                            if(!(IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag))) {
+#endif
+
+                            unifi_trace(priv, UDBG3, "genericMgtFrames list is empty uf_process_ma_packet_req \n");
+                            result = ul_send_signal_unpacked(priv, &signal, bulkdata);
+                            /*  reque only on ENOSPC */
+                            if(result == -ENOSPC) {
+                                /* requeue the failed packet to genericMgtFrame with same position */
+                                unifi_trace(priv, UDBG1, "(ENOSPC) Sending genericMgtFrames Failed so buffering\n");
+                                list = &interfacePriv->genericMgtFrames;
+                                requeueOnSamePos = TRUE;
+                            }
+#ifdef CSR_SUPPORT_SME
+                            }else{
+                                list = &interfacePriv->genericMgtFrames;
+                                unifi_trace(priv, UDBG3, "genericMgtFrames queue empty and dtim started\n hosttag is 0x%x,\n",signal.u.MaPacketRequest.HostTag);
+                                update_eosp_to_head_of_broadcast_list_head(priv,interfaceTag);
+                           }
+#endif
+                        } else {
+                            /* Queue the packet to genericMgtFrame of unifi_priv_t data structure */
+                            list = &interfacePriv->genericMgtFrames;
+                            unifi_trace(priv, UDBG2, "genericMgtFrames queue not empty\n");
+                        }
+                    } else {
+                        /* check peer power state */
+                        if (queuePacketDozing || !list_empty(&staRecord->mgtFrames) || IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag)) {
+                            /* peer is in dozing mode, so queue packet in mgt frame list of station record */
+                           /*if multicast traffic is going on, buffer the unicast packets*/
+                            list = &staRecord->mgtFrames;
+
+                            unifi_trace(priv, UDBG1, "staRecord->MgtFrames list empty? = %s, handle = %d, queuePacketDozing = %d\n",
+                                        (list_empty(&staRecord->mgtFrames))? "YES": "NO", staRecord->assignedHandle, queuePacketDozing);
+                            if(IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag)){
+                                update_eosp_to_head_of_broadcast_list_head(priv,interfaceTag);
+                            }
+
+                        } else {
+                            unifi_trace(priv, UDBG5, "staRecord->mgtFrames list is empty uf_process_ma_packet_req \n");
+                            result = ul_send_signal_unpacked(priv, &signal, bulkdata);
+                            if(result == -ENOSPC) {
+                                /* requeue the failed packet to staRecord->mgtFrames with same position */
+                                list = &staRecord->mgtFrames;
+                                requeueOnSamePos = TRUE;
+                                unifi_trace(priv, UDBG1, "(ENOSPC) Sending MgtFrames Failed handle = %d so buffering\n",staRecord->assignedHandle);
+                                priv->pausedStaHandle[0]=(CsrUint8)(staRecord->assignedHandle);
+                            } else if (result) {
+                                status = CSR_RESULT_FAILURE;
+                            }
+                        }
+                    }
+                    break;
+                case CSR_WIFI_MULTICAST_PDU:
+                    unifi_trace(priv, UDBG5, "management multicast/broadcast PDU in uf_process_ma_packet_req 'QUEUE it' \n");
+                    /* Queue the packet to genericMulticastOrBroadCastMgtFrames of unifi_priv_t data structure
+                     * will be sent when we receive VIF AVAILABILITY from firmware as part of DTIM
+                     */
+
+                    list = &interfacePriv->genericMulticastOrBroadCastMgtFrames;
+                    if((interfacePriv->interfaceMode != CSR_WIFI_ROUTER_CTRL_MODE_IBSS) &&
+                            (list_empty(&interfacePriv->genericMulticastOrBroadCastMgtFrames))) {
+                        setBcTim=TRUE;
+                    }
+                    break;
+                default:
+                    unifi_error(priv, "condition never meets: packet type unrecognized\n");
+            }
+            break;
+        case IEEE802_11_FRAMETYPE_DATA:
+            switch(pktType)
+            {
+                case CSR_WIFI_UNICAST_PDU:
+                    unifi_trace(priv, UDBG5, "data unicast PDU in uf_process_ma_packet_req \n");
+                    /* check peer power state, list status & peer port status */
+                    if(!staRecord) {
+                        unifi_error(priv, "In %s unicast but staRecord = NULL\n", __FUNCTION__);
+                        return CSR_RESULT_FAILURE;
+                    } else if (queuePacketDozing || isRouterBufferEnabled(priv,priority_q)|| !list_empty(&staRecord->dataPdu[priority_q]) || IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag)) {
+                        /* peer is in dozing mode, so queue packet in mgt frame list of station record */
+                        /* if multicast traffic is going on, buffet the unicast packets */
+                        unifi_trace(priv, UDBG2, "Enqueued to staRecord->dataPdu[%d] queuePacketDozing=%d,\
+                                Buffering enabled = %d \n", priority_q,queuePacketDozing,isRouterBufferEnabled(priv,priority_q));
+                        list = &staRecord->dataPdu[priority_q];
+                    } else {
+                        unifi_trace(priv, UDBG5, "staRecord->dataPdu[%d] list is empty uf_process_ma_packet_req \n", priority_q);
+                        /* Pdu allowed to send to unifi */
+                        result = ul_send_signal_unpacked(priv, &signal, bulkdata);
+                        if(result == -ENOSPC) {
+                            /* requeue the failed packet to staRecord->dataPdu[priority_q] with same position */
+                            unifi_trace(priv, UDBG1, "(ENOSPC) Sending Unicast DataPDU to queue %d Failed so buffering\n",priority_q);
+                            requeueOnSamePos = TRUE;
+                            list = &staRecord->dataPdu[priority_q];
+                            priv->pausedStaHandle[priority_q]=(CsrUint8)(staRecord->assignedHandle);
+                            if(!isRouterBufferEnabled(priv,priority_q)) {
+                                unifi_error(priv,"Buffering Not enabled for queue %d \n",priority_q);
+                            }
+                        } else if (result) {
+                            status = CSR_RESULT_FAILURE;
+                        }
+                    }
+                    break;
+                case CSR_WIFI_MULTICAST_PDU:
+                    unifi_trace(priv, UDBG5, "data multicast/broadcast PDU in uf_process_ma_packet_req \n");
+                    /* Queue the packet to genericMulticastOrBroadCastFrames list of unifi_priv_t data structure
+                     * will be sent when we receive VIF AVAILABILITY from firmware as part of DTIM
+                     */
+                    list = &interfacePriv->genericMulticastOrBroadCastFrames;
+                    if(list_empty(&interfacePriv->genericMulticastOrBroadCastFrames)) {
+                        setBcTim = TRUE;
+                    }
+                    break;
+                default:
+                    unifi_error(priv, "condition never meets: packet type un recognized\n");
+            }
+            break;
+        default:
+            unifi_error(priv, "unrecognized frame type\n");
+    }
+    if(list) {
+        status = enque_tx_data_pdu(priv, bulkdata,list, &signal,requeueOnSamePos);
+        /* Record no. of packet queued for each peer */
+        if (staRecord && (pktType == CSR_WIFI_UNICAST_PDU) && (!status)) {
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+            staRecord->noOfPktQueued++;
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+        }
+        else if ((pktType == CSR_WIFI_MULTICAST_PDU) && (!status))
+        {
+            /* If broadcast Tim is set && queuing is successfull, then only update TIM */
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+            interfacePriv->noOfbroadcastPktQueued++;
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+        }
+    }
+    /* If broadcast Tim is set && queuing is successfull, then only update TIM */
+    if(setBcTim && !status) {
+        unifi_trace(priv, UDBG3, "tim set due to broadcast pkt\n");
+        if (!interfacePriv->bcTimSetReqPendingFlag)
+        {
+            update_tim(priv,0,CSR_WIFI_TIM_SET,interfaceTag, handle);
+        }
+        else
+        {
+            /* Cache the TimSet value so that it will processed immidiatly after
+            * completing the current setTim Request
+            */
+            interfacePriv->bcTimSetReqQueued = CSR_WIFI_TIM_SET;
+            unifi_trace(priv, UDBG2, "uf_process_ma_packet_req : One more UpdateDTim Request(:%d) Queued \n",
+                        interfacePriv->bcTimSetReqQueued);
+        }
+    } else if(staRecord && staRecord->currentPeerState ==
+                            CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE) {
+        if(staRecord->timSet == CSR_WIFI_TIM_RESET || staRecord->timSet == CSR_WIFI_TIM_RESETTING) {
+            if(!staRecord->wmmOrQosEnabled) {
+                if(!list_empty(&staRecord->mgtFrames) ||
+                   !list_empty(&staRecord->dataPdu[3]) ||
+                   !list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION])) {
+                    unifi_trace(priv, UDBG3, "tim set due to unicast pkt & peer in powersave\n");
+                    if (!staRecord->timRequestPendingFlag){
+                        update_tim(priv,staRecord->aid,1,interfaceTag, handle);
+                    }
+                    else
+                    {
+                        /* Cache the TimSet value so that it will processed immidiatly after
+                         * completing the current setTim Request
+                         */
+                        staRecord->updateTimReqQueued = 1;
+                        unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued,
+                                    staRecord->aid);
+                    }
+                }
+            } else {
+                /* Check for non delivery enable(i.e trigger enable), all delivery enable & legacy AC for TIM update in firmware */
+                CsrUint8 allDeliveryEnabled = 0, dataAvailable = 0;
+                /* Check if all AC's are Delivery Enabled */
+                is_all_ac_deliver_enabled_and_moredata(staRecord, &allDeliveryEnabled, &dataAvailable);
+                if (uf_is_more_data_for_non_delivery_ac(staRecord) || (allDeliveryEnabled && dataAvailable)
+                    || (!list_empty(&staRecord->mgtFrames))) {
+                    if (!staRecord->timRequestPendingFlag) {
+                        update_tim(priv,staRecord->aid,1,interfaceTag, handle);
+                    }
+                    else
+                    {
+                        /* Cache the TimSet value so that it will processed immidiatly after
+                         * completing the current setTim Request
+                         */
+                        staRecord->updateTimReqQueued = 1;
+                        unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued,
+                                    staRecord->aid);
+                    }
+                }
+            }
+        }
+    }
+
+    if((list) && (pktType == CSR_WIFI_UNICAST_PDU && !queuePacketDozing) && !(isRouterBufferEnabled(priv,priority_q)) && !(IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag))) {
+        unifi_trace(priv, UDBG2, "buffering cleared for queue = %d So resending buffered frames\n",priority_q);
+        uf_send_buffered_frames(priv, priority_q);
+    }
+    unifi_trace(priv, UDBG5, "leaving uf_process_ma_packet_req \n");
+    return status;
+#else
+#ifdef CSR_NATIVE_LINUX
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "interfaceTag >= CSR_WIFI_NUM_INTERFACES, interfacetag = %d\n", interfaceTag);
+        return CSR_RESULT_FAILURE;
+    }
+    /* Frame ma-packet.req, this is saved/transmitted depend on queue state */
+    unifi_frame_ma_packet_req(priv, priority, TransmitRate, hostTag, interfaceTag,
+            transmissionControl, leSenderProcessId,
+            peerMacAddress, &signal);
+    result = ul_send_signal_unpacked(priv, &signal, bulkdata);
+    if (result) {
+        return CSR_RESULT_FAILURE;
+    }
+#endif
+    return status;
+#endif
+}
+
+#ifdef CSR_SUPPORT_SME
+CsrInt8 uf_get_protection_bit_from_interfacemode(unifi_priv_t *priv, CsrUint16 interfaceTag, const CsrUint8 *daddr)
+{
+    CsrInt8 protection = 0;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    switch(interfacePriv->interfaceMode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_STA:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI:
+        case CSR_WIFI_ROUTER_CTRL_MODE_AMP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_IBSS:
+            protection = interfacePriv->protect;
+            break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+            {
+                CsrWifiRouterCtrlStaInfo_t *dstStaInfo = NULL;
+                if (daddr[0] & 0x1) {
+                    unifi_trace(priv, UDBG3, "broadcast/multicast packet in send_ma_pkt_request\n");
+                    /* In this mode, the protect member of priv structure has an information of how
+                     * AP/P2PGO has started, & the member updated in set mode request for AP/P2PGO
+                     */
+                    protection = interfacePriv->protect;
+                } else {
+                    /* fetch the destination record from staion record database */
+                    dstStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv, daddr, interfaceTag);
+                    if (!dstStaInfo) {
+                        unifi_trace(priv, UDBG3, "peer not found in station record in send_ma_pkt_request\n");
+                        return -1;
+                    }
+                    protection = dstStaInfo->protection;
+                }
+            }
+            break;
+        default:
+            unifi_trace(priv, UDBG2, "mode unknown in send_ma_pkt_request\n");
+    }
+    return protection;
+}
+#endif
+#ifdef CSR_SUPPORT_SME
+CsrUint8 send_multicast_frames(unifi_priv_t *priv, CsrUint16 interfaceTag)
+{
+    int r;
+    tx_buffered_packets_t * buffered_pkt = NULL;
+    CsrBool moreData = FALSE;
+    CsrUint8 pduSent =0;
+    unsigned long lock_flags;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    CsrUint32 hostTag = 0xffffffff;
+
+    func_enter();
+    if(!isRouterBufferEnabled(priv,UNIFI_TRAFFIC_Q_VO)) {
+        while((interfacePriv->dtimActive)&& (buffered_pkt=dequeue_tx_data_pdu(priv,&interfacePriv->genericMulticastOrBroadCastMgtFrames))) {
+            buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK);
+            moreData = (buffered_pkt->transmissionControl & TRANSMISSION_CONTROL_EOSP_MASK)?FALSE:TRUE;
+
+
+            unifi_trace(priv,UDBG2,"DTIM Occurred for interface:sending Mgt packet %d\n",interfaceTag);
+
+            if((r=frame_and_send_queued_pdu(priv,buffered_pkt,NULL,moreData,FALSE)) == -ENOSPC) {
+               unifi_trace(priv,UDBG1,"frame_and_send_queued_pdu failed with ENOSPC for host tag = %x\n", buffered_pkt->hostTag);
+               /* Enqueue at the head of the queue */
+               spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+               list_add(&buffered_pkt->q, &interfacePriv->genericMulticastOrBroadCastMgtFrames);
+               spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+               break;
+            } else {
+                unifi_trace(priv,UDBG1,"send_multicast_frames: Send genericMulticastOrBroadCastMgtFrames (%x, %x)\n",
+                                        buffered_pkt->hostTag,
+                                        r);
+                if(r) {
+                   unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+                }
+                if(!moreData) {
+
+                    interfacePriv->dtimActive = FALSE;
+                    if(!r) {
+                        hostTag = buffered_pkt->hostTag;
+                        pduSent++;
+                    } else {
+                        send_vif_availibility_rsp(priv,uf_get_vif_identifier(interfacePriv->interfaceMode,interfaceTag),CSR_RC_UNSPECIFIED_FAILURE);
+                    }
+                }
+                /* Buffered frame sent successfully */
+                spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+                interfacePriv->noOfbroadcastPktQueued--;
+                spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+                kfree(buffered_pkt);
+           }
+
+        }
+    }
+    if(!isRouterBufferEnabled(priv,UNIFI_TRAFFIC_Q_CONTENTION)) {
+        while((interfacePriv->dtimActive)&& (buffered_pkt=dequeue_tx_data_pdu(priv,&interfacePriv->genericMulticastOrBroadCastFrames))) {
+            buffered_pkt->transmissionControl |= TRANSMISSION_CONTROL_TRIGGER_MASK;
+            moreData = (buffered_pkt->transmissionControl & TRANSMISSION_CONTROL_EOSP_MASK)?FALSE:TRUE;
+
+
+            if((r=frame_and_send_queued_pdu(priv,buffered_pkt,NULL,moreData,FALSE)) == -ENOSPC) {
+                /* Clear the trigger bit transmission control*/
+                buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK);
+                /* Enqueue at the head of the queue */
+                spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+                list_add(&buffered_pkt->q, &interfacePriv->genericMulticastOrBroadCastFrames);
+                spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+                break;
+            } else {
+                if(r) {
+                    unifi_trace(priv,UDBG1,"send_multicast_frames: Send genericMulticastOrBroadCastFrame failed (%x, %x)\n",
+                                            buffered_pkt->hostTag,
+                                            r);
+                    unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+                }
+                if(!moreData) {
+                    interfacePriv->dtimActive = FALSE;
+                    if(!r) {
+                        pduSent ++;
+                        hostTag = buffered_pkt->hostTag;
+                    } else {
+                        send_vif_availibility_rsp(priv,uf_get_vif_identifier(interfacePriv->interfaceMode,interfaceTag),CSR_RC_UNSPECIFIED_FAILURE);
+                    }
+                }
+                /* Buffered frame sent successfully */
+                spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+                interfacePriv->noOfbroadcastPktQueued--;
+                spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+                kfree(buffered_pkt);
+            }
+        }
+    }
+    if((interfacePriv->dtimActive == FALSE)) {
+        /* Record the host Tag*/
+        unifi_trace(priv,UDBG2,"send_multicast_frames: Recorded hostTag of EOSP packet: = 0x%x\n",hostTag);
+        interfacePriv->multicastPduHostTag = hostTag;
+    }
+    return pduSent;
+}
+#endif
+void uf_process_ma_vif_availibility_ind(unifi_priv_t *priv,CsrUint8 *sigdata,
+                                        CsrUint32 siglen)
+{
+#ifdef CSR_SUPPORT_SME
+    CSR_SIGNAL signal;
+    CSR_MA_VIF_AVAILABILITY_INDICATION *ind;
+    int r;
+    CsrUint16 interfaceTag;
+    CsrUint8 pduSent =0;
+    CSR_RESULT_CODE resultCode = CSR_RC_SUCCESS;
+    netInterface_priv_t *interfacePriv;
+
+    func_enter();
+    unifi_trace(priv, UDBG3,
+            "uf_process_ma_vif_availibility_ind: Process signal 0x%.4X\n",
+            *((CsrUint16*)sigdata));
+
+    r = read_unpack_signal(sigdata, &signal);
+    if (r) {
+        unifi_error(priv,
+                    "uf_process_ma_vif_availibility_ind: Received unknown signal 0x%.4X.\n",
+                    CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata));
+        func_exit();
+        return;
+    }
+    ind = &signal.u.MaVifAvailabilityIndication;
+    interfaceTag=ind->VirtualInterfaceIdentifier & 0xff;
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "in vif_availability_ind interfaceTag is wrong\n");
+        return;
+    }
+
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if(ind->Multicast) {
+        if(list_empty(&interfacePriv->genericMulticastOrBroadCastFrames) &&
+            list_empty(&interfacePriv->genericMulticastOrBroadCastMgtFrames)) {
+            /* This condition can occur because of a potential race where the
+               TIM is not yet reset as host is waiting for confirm but it is sent
+               by firmware and DTIM occurs*/
+            unifi_notice(priv,"ma_vif_availibility_ind recevied for multicast but queues are empty%d\n",interfaceTag);
+            send_vif_availibility_rsp(priv,ind->VirtualInterfaceIdentifier,CSR_RC_NO_BUFFERED_BROADCAST_MULTICAST_FRAMES);
+            interfacePriv->dtimActive = FALSE;
+            if(interfacePriv->multicastPduHostTag == 0xffffffff) {
+                unifi_notice(priv,"ma_vif_availibility_ind recevied for multicast but queues are empty%d\n",interfaceTag);
+                /* This may be an extra request in very rare race conditions but it is fine as it would atleast remove the potential lock up */
+                if (!interfacePriv->bcTimSetReqPendingFlag)
+                {
+                    update_tim(priv,0,CSR_WIFI_TIM_RESET,interfaceTag, 0xFFFFFFFF);
+                }
+                else
+                {
+                    /* Cache the TimSet value so that it will processed immidiatly after
+                     * completing the current setTim Request
+                     */
+                    interfacePriv->bcTimSetReqQueued = CSR_WIFI_TIM_RESET;
+                    unifi_trace(priv, UDBG2, "uf_process_ma_vif_availibility_ind : One more UpdateDTim Request(%d) Queued \n",
+                                interfacePriv->bcTimSetReqQueued);
+                }
+            }
+            return;
+        }
+        if(interfacePriv->dtimActive) {
+            unifi_trace(priv,UDBG2,"DTIM Occurred for already active DTIM interface %d\n",interfaceTag);
+            return;
+        } else {
+            unifi_trace(priv,UDBG2,"DTIM Occurred for interface %d\n",interfaceTag);
+            if(list_empty(&interfacePriv->genericMulticastOrBroadCastFrames)) {
+                set_eosp_transmit_ctrl(priv,&interfacePriv->genericMulticastOrBroadCastMgtFrames);
+            } else {
+                set_eosp_transmit_ctrl(priv,&interfacePriv->genericMulticastOrBroadCastFrames);
+            }
+        }
+        interfacePriv->dtimActive = TRUE;
+        pduSent = send_multicast_frames(priv,interfaceTag);
+    }
+    else {
+        unifi_error(priv,"Interface switching is not supported %d\n",interfaceTag);
+        resultCode = CSR_RC_NOT_SUPPORTED;
+        send_vif_availibility_rsp(priv,ind->VirtualInterfaceIdentifier,CSR_RC_NOT_SUPPORTED);
+    }
+#endif
+}
+#ifdef CSR_SUPPORT_SME
+
+#define  GET_ACTIVE_INTERFACE_TAG(priv) 0
+
+static CsrBool uf_is_more_data_for_delivery_ac(unifi_priv_t *priv, CsrWifiRouterCtrlStaInfo_t *staRecord)
+{
+    CsrInt8 i;
+
+    for(i=UNIFI_TRAFFIC_Q_VO; i >= UNIFI_TRAFFIC_Q_BK; i--)
+    {
+        if(((staRecord->powersaveMode[i]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE)
+             ||(staRecord->powersaveMode[i]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED))
+             &&(!list_empty(&staRecord->dataPdu[i]))) {
+            unifi_trace(priv,UDBG2,"uf_is_more_data_for_delivery_ac: Data Available AC = %d\n", i);
+            return TRUE;
+        }
+    }
+
+    unifi_trace(priv,UDBG2,"uf_is_more_data_for_delivery_ac: Data NOT Available \n");
+    return FALSE;
+}
+
+static CsrBool uf_is_more_data_for_usp_delivery(unifi_priv_t *priv, CsrWifiRouterCtrlStaInfo_t *staRecord, unifi_TrafficQueue queue)
+{
+    CsrInt8 i;
+
+    for(i = queue; i >= UNIFI_TRAFFIC_Q_BK; i--)
+    {
+        if(((staRecord->powersaveMode[i]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE)
+             ||(staRecord->powersaveMode[i]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED))
+             &&(!list_empty(&staRecord->dataPdu[i]))) {
+            unifi_trace(priv,UDBG2,"uf_is_more_data_for_usp_delivery: Data Available AC = %d\n", i);
+            return TRUE;
+        }
+    }
+
+    unifi_trace(priv,UDBG2,"uf_is_more_data_for_usp_delivery: Data NOT Available \n");
+    return FALSE;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_send_buffered_data_from_delivery_ac
+ *
+ *      This function takes care of
+ *      -> Parsing the delivery enabled queue & sending frame down to HIP
+ *      -> Setting EOSP=1 when USP to be terminated
+ *      -> Depending on MAX SP length services the USP
+ *
+ * NOTE:This function always called from uf_handle_uspframes_delivery(), Dont
+ *      call this function from any other location in code
+ *
+ *  Arguments:
+ *      priv        Pointer to device private context struct
+ *      vif         interface specific HIP vif instance
+ *      staInfo     peer for which UAPSD to be scheduled
+ *      queue       AC from which Data to be sent in USP
+ *      txList      access category for processing list
+ * ---------------------------------------------------------------------------
+ */
+void uf_send_buffered_data_from_delivery_ac(unifi_priv_t *priv,
+                                            CsrWifiRouterCtrlStaInfo_t * staInfo,
+                                            CsrUint8 queue,
+                                            struct list_head *txList)
+{
+
+    CsrUint16 interfaceTag = GET_ACTIVE_INTERFACE_TAG(priv);
+    tx_buffered_packets_t * buffered_pkt = NULL;
+    unsigned long lock_flags;
+    CsrBool eosp=FALSE;
+    CsrInt8 r =0;
+    CsrBool moreData = FALSE;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    unifi_trace(priv, UDBG2, "++uf_send_buffered_data_from_delivery_ac, active=%x\n", staInfo->uapsdActive);
+
+    if (queue > UNIFI_TRAFFIC_Q_VO)
+    {
+        return;
+    }
+    while((buffered_pkt=dequeue_tx_data_pdu(priv, txList))) {
+        if((IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag))) {
+            unifi_trace(priv, UDBG2, "uf_send_buffered_data_from_delivery_ac: DTIM Active, suspend UAPSD, staId: 0x%x\n",
+                        staInfo->aid);
+
+            /* Once resume called, the U-APSD delivery operation will resume */
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+            staInfo->uspSuspend = TRUE;
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+            /* re-queueing the packet as DTIM started */
+            spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+            list_add(&buffered_pkt->q,txList);
+            spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+            break;
+        }
+
+        buffered_pkt->transmissionControl &=
+                 ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+
+
+        if((staInfo->wmmOrQosEnabled == TRUE)&&(staInfo->uapsdActive == TRUE)) {
+
+             buffered_pkt->transmissionControl = TRANSMISSION_CONTROL_TRIGGER_MASK;
+
+             /* Check All delivery enables Ac for more data, because caller of this
+              * function not aware about last packet
+              * (First check in moreData fetching helps in draining out Mgt frames Q)
+              */
+              moreData = (!list_empty(txList) || uf_is_more_data_for_usp_delivery(priv, staInfo, queue));
+
+              if(staInfo->noOfSpFramesSent == (staInfo->maxSpLength - 1)) {
+                  moreData = FALSE;
+              }
+
+              if(moreData == FALSE) {
+                  eosp = TRUE;
+                  buffered_pkt->transmissionControl =
+                      (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+              }
+        } else {
+            /* Non QoS and non U-APSD */
+            unifi_warning(priv, "uf_send_buffered_data_from_delivery_ac: non U-APSD !!! \n");
+        }
+
+        unifi_trace(priv,UDBG2,"uf_send_buffered_data_from_delivery_ac : MoreData:%d, EOSP:%d\n",moreData,eosp);
+
+        if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staInfo,moreData,eosp)) == -ENOSPC) {
+
+            unifi_trace(priv, UDBG2, "uf_send_buffered_data_from_delivery_ac: UASPD suspended, ENOSPC in hipQ=%x\n", queue);
+
+            /* Once resume called, the U-APSD delivery operation will resume */
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+            staInfo->uspSuspend = TRUE;
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+
+            spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+            list_add(&buffered_pkt->q,txList);
+            spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+            priv->pausedStaHandle[queue]=(CsrUint8)(staInfo->assignedHandle);
+            break;
+        } else {
+            if(r){
+                /* the PDU failed where we can't do any thing so free the storage */
+                unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+            }
+            kfree(buffered_pkt);
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+            staInfo->noOfSpFramesSent++;
+            if((!moreData) || (staInfo->noOfSpFramesSent == staInfo->maxSpLength)) {
+                unifi_trace(priv, UDBG2, "uf_send_buffered_data_from_delivery_ac: Terminating USP\n");
+                staInfo->uapsdActive = FALSE;
+                staInfo->uspSuspend = FALSE;
+                staInfo->noOfSpFramesSent = 0;
+                spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+                break;
+            }
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+        }
+    }
+    unifi_trace(priv, UDBG2, "--uf_send_buffered_data_from_delivery_ac, active=%x\n", staInfo->uapsdActive);
+}
+
+void uf_send_buffered_data_from_ac(unifi_priv_t *priv,
+                                   CsrWifiRouterCtrlStaInfo_t * staInfo,
+                                   CsrUint8 queue,
+                                   struct list_head *txList)
+{
+    tx_buffered_packets_t * buffered_pkt = NULL;
+    unsigned long lock_flags;
+    CsrBool eosp=FALSE;
+    CsrBool moreData = FALSE;
+    CsrInt8 r =0;
+
+    func_enter();
+
+    unifi_trace(priv,UDBG2,"uf_send_buffered_data_from_ac :\n");
+
+    while(!isRouterBufferEnabled(priv,queue) &&
+                    ((buffered_pkt=dequeue_tx_data_pdu(priv, txList))!=NULL)){
+
+        buffered_pkt->transmissionControl &=
+                 ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK);
+
+        unifi_trace(priv,UDBG3,"uf_send_buffered_data_from_ac : MoreData:%d, EOSP:%d\n",moreData,eosp);
+
+        if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staInfo,moreData,eosp)) == -ENOSPC) {
+           /* Enqueue at the head of the queue */
+           spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+           list_add(&buffered_pkt->q,txList);
+           spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+           if(staInfo != NULL){
+              priv->pausedStaHandle[queue]=(CsrUint8)(staInfo->assignedHandle);
+           }
+           unifi_trace(priv,UDBG3," uf_send_buffered_data_from_ac: PDU sending failed .. no space for queue %d \n",queue);
+           } else {
+            if(r){
+                /* the PDU failed where we can't do any thing so free the storage */
+                unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+            }
+            kfree(buffered_pkt);
+      }
+  }
+
+  func_exit();
+
+}
+
+void uf_send_buffered_frames(unifi_priv_t *priv,unifi_TrafficQueue q)
+{
+    CsrUint16 interfaceTag = GET_ACTIVE_INTERFACE_TAG(priv);
+    CsrUint32 startIndex=0,endIndex=0;
+    CsrWifiRouterCtrlStaInfo_t * staInfo = NULL;
+    CsrUint8 queue;
+    CsrBool moreData = FALSE;
+
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if(!((interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP) ||
+        (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO)))
+        return;
+    func_enter();
+
+    queue = (q<=3)?q:0;
+
+    if(interfacePriv->dtimActive) {
+        /* this function updates dtimActive*/
+        send_multicast_frames(priv,interfaceTag);
+        if(!interfacePriv->dtimActive) {
+            moreData = (!list_empty(&interfacePriv->genericMulticastOrBroadCastMgtFrames) ||
+             !list_empty(&interfacePriv->genericMulticastOrBroadCastFrames));
+            if(!moreData) {
+                if (!interfacePriv->bcTimSetReqPendingFlag)
+                {
+                    update_tim(priv,0,CSR_WIFI_TIM_RESET,interfaceTag, 0XFFFFFFFF);
+                }
+                else
+                {
+                    /* Cache the TimSet value so that it will processed immidiatly after
+                     * completing the current setTim Request
+                     */
+                    interfacePriv->bcTimSetReqQueued = CSR_WIFI_TIM_RESET;
+                    unifi_trace(priv, UDBG2, "uf_send_buffered_frames : One more UpdateDTim Request(%d) Queued \n",
+                                interfacePriv->bcTimSetReqQueued);
+                }
+            }
+        } else {
+            moreData = (!list_empty(&interfacePriv->genericMulticastOrBroadCastMgtFrames) ||
+                        !list_empty(&interfacePriv->genericMulticastOrBroadCastFrames));
+           if(!moreData) {
+               /* This should never happen but if it happens, we need a way out */
+               unifi_error(priv,"ERROR: No More Data but DTIM is active sending Response\n");
+               send_vif_availibility_rsp(priv,uf_get_vif_identifier(interfacePriv->interfaceMode,interfaceTag),CSR_RC_NO_BUFFERED_BROADCAST_MULTICAST_FRAMES);
+               interfacePriv->dtimActive = FALSE;
+           }
+        }
+        func_exit();
+        return;
+    }
+    if(priv->pausedStaHandle[queue] > 7) {
+        priv->pausedStaHandle[queue] = 0;
+    }
+
+    if(queue == UNIFI_TRAFFIC_Q_VO) {
+
+
+        unifi_trace(priv,UDBG2,"uf_send_buffered_frames : trying mgt from queue=%d\n",queue);
+        for(startIndex= 0; startIndex < UNIFI_MAX_CONNECTIONS;startIndex++) {
+            staInfo =  CsrWifiRouterCtrlGetStationRecordFromHandle(priv,startIndex,interfaceTag);
+            if(!staInfo ) {
+                continue;
+            } else if((staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE)
+                       &&(staInfo->uapsdActive == FALSE) ) {
+                continue;
+            }
+
+            if((staInfo != NULL)&&(staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE)
+                               &&(staInfo->uapsdActive == FALSE)){
+                            /*Non-UAPSD case push the management frames out*/
+               if(!list_empty(&staInfo->mgtFrames)){
+                    uf_send_buffered_data_from_ac(priv,staInfo, UNIFI_TRAFFIC_Q_VO, &staInfo->mgtFrames);
+                }
+            }
+
+            if(isRouterBufferEnabled(priv,queue)) {
+                unifi_notice(priv,"uf_send_buffered_frames : No space Left for queue = %d\n",queue);
+                break;
+            }
+        }
+        /*push generic management frames out*/
+        if(!list_empty(&interfacePriv->genericMgtFrames)) {
+            unifi_trace(priv,UDBG2,"uf_send_buffered_frames : trying generic mgt from queue=%d\n",queue);
+            uf_send_buffered_data_from_ac(priv,staInfo, UNIFI_TRAFFIC_Q_VO, &interfacePriv->genericMgtFrames);
+        }
+    }
+
+
+    unifi_trace(priv,UDBG2,"uf_send_buffered_frames : Resume called for Queue=%d\n",queue);
+    unifi_trace(priv,UDBG2,"uf_send_buffered_frames : start=%d end=%d\n",startIndex,endIndex);
+
+    startIndex = priv->pausedStaHandle[queue];
+    endIndex = (startIndex + UNIFI_MAX_CONNECTIONS -1) % UNIFI_MAX_CONNECTIONS;
+
+    while(startIndex != endIndex) {
+        staInfo =  CsrWifiRouterCtrlGetStationRecordFromHandle(priv,startIndex,interfaceTag);
+        if(!staInfo) {
+            startIndex ++;
+            if(startIndex >= UNIFI_MAX_CONNECTIONS) {
+                startIndex = 0;
+            }
+            continue;
+        } else if((staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE)
+                   &&(staInfo->uapsdActive == FALSE)) {
+            startIndex ++;
+            if(startIndex >= UNIFI_MAX_CONNECTIONS) {
+                startIndex = 0;
+            }
+            continue;
+        }
+        /* Peer is active or U-APSD is active so send PDUs to the peer */
+        unifi_trace(priv,UDBG2,"uf_send_buffered_frames : trying data from queue=%d\n",queue);
+
+
+        if((staInfo != NULL)&&(staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE)
+                           &&(staInfo->uapsdActive == FALSE)) {
+           if(!list_empty(&staInfo->dataPdu[queue])) {
+
+               /*Non-UAPSD case push the AC frames out*/
+               uf_send_buffered_data_from_ac(priv, staInfo, queue, (&staInfo->dataPdu[queue]));
+           }
+        }
+        startIndex ++;
+        if(startIndex >= UNIFI_MAX_CONNECTIONS) {
+           startIndex = 0;
+        }
+    }
+    if(isRouterBufferEnabled(priv,queue)) {
+        priv->pausedStaHandle[queue] = endIndex;
+    } else {
+        priv->pausedStaHandle[queue] = 0;
+    }
+
+    /* U-APSD might have stopped because of ENOSPC in lib_hip (pause activity).
+     * So restart it if U-APSD was active with any of the station
+     */
+    unifi_trace(priv, UDBG4, "csrWifiHipSendBufferedFrames: UAPSD Resume Q=%x\n", queue);
+    resume_suspended_uapsd(priv, interfaceTag);
+    func_exit();
+}
+
+
+CsrBool uf_is_more_data_for_non_delivery_ac(CsrWifiRouterCtrlStaInfo_t *staRecord)
+{
+    CsrUint8 i;
+
+    for(i=0;i<=3;i++)
+    {
+        if(((staRecord->powersaveMode[i]==CSR_WIFI_AC_TRIGGER_ONLY_ENABLED)
+                ||(staRecord->powersaveMode[i]==CSR_WIFI_AC_LEGACY_POWER_SAVE))
+                &&(!list_empty(&staRecord->dataPdu[i]))){
+
+         return TRUE;
+        }
+    }
+
+    if(((staRecord->powersaveMode[UNIFI_TRAFFIC_Q_VO]==CSR_WIFI_AC_TRIGGER_ONLY_ENABLED)
+            ||(staRecord->powersaveMode[UNIFI_TRAFFIC_Q_VO]==CSR_WIFI_AC_LEGACY_POWER_SAVE))
+            &&(!list_empty(&staRecord->mgtFrames))){
+
+     return TRUE;
+    }
+
+
+
+    return FALSE;
+}
+
+
+int uf_process_station_records_for_sending_data(unifi_priv_t *priv,CsrUint16 interfaceTag,
+                                                 CsrWifiRouterCtrlStaInfo_t *srcStaInfo,
+                                                 CsrWifiRouterCtrlStaInfo_t *dstStaInfo)
+{
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    unifi_trace(priv, UDBG5, "entering uf_process_station_records_for_sending_data\n");
+
+    if (srcStaInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_DISCONNECTED) {
+        unifi_error(priv, "Peer State not connected AID = %x, handle = %x, control port state = %x\n",
+                    srcStaInfo->aid, srcStaInfo->assignedHandle, srcStaInfo->peerControlledPort->port_action);
+        return -1;
+    }
+    switch (interfacePriv->interfaceMode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+            unifi_trace(priv, UDBG5, "mode is AP/P2PGO\n");
+            break;
+        default:
+            unifi_warning(priv, "mode is nor AP neither P2PGO, packet cant be xmit\n");
+            return -1;
+    }
+
+    switch(dstStaInfo->peerControlledPort->port_action)
+    {
+        case CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD:
+        case CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_BLOCK:
+            unifi_trace(priv, UDBG5, "destination port is closed/blocked, discarding the packet\n");
+            return -1;
+        default:
+            unifi_trace(priv, UDBG5, "destination port state is open\n");
+    }
+
+    /* port state is open, destination station record is valid, Power save state is
+     * validated in uf_process_ma_packet_req function
+     */
+    unifi_trace(priv, UDBG5, "leaving uf_process_station_records_for_sending_data\n");
+    return 0;
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_handle_uspframes_delivery
+ *
+ *      This function takes care of handling USP session for peer, when
+ *      -> trigger frame from peer
+ *      -> suspended USP to be processed (resumed)
+ *
+ *      NOTE: uf_send_buffered_data_from_delivery_ac() always called from this function, Dont
+ *      make a direct call to uf_send_buffered_data_from_delivery_ac() from any other part of
+ *      code
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *      staInfo         peer for which UAPSD to be scheduled
+ *      interfaceTag    virtual interface tag
+ * ---------------------------------------------------------------------------
+ */
+static void uf_handle_uspframes_delivery(unifi_priv_t * priv, CsrWifiRouterCtrlStaInfo_t *staInfo, CsrUint16 interfaceTag)
+{
+
+    CsrInt8 i;
+    CsrUint8 allDeliveryEnabled = 0, dataAvailable = 0;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    unsigned long lock_flags;
+
+    unifi_trace(priv, UDBG2, " ++ uf_handle_uspframes_delivery, uapsd active=%x, suspended?=%x\n",
+                staInfo->uapsdActive, staInfo->uspSuspend);
+
+    /* Check for Buffered frames according to priority order & deliver it
+     *  1. AC_VO delivery enable & Mgt frames available
+     *  2. Process remaining Ac's from order AC_VO to AC_BK
+     */
+
+    /* USP initiated by WMMPS enabled peer  & SET the status flag to TRUE */
+    if (!staInfo->uspSuspend && staInfo->uapsdActive)
+    {
+        unifi_notice(priv, "uf_handle_uspframes_delivery: U-APSD already active! STA=%x:%x:%x:%x:%x:%x\n",
+                staInfo->peerMacAddress.a[0], staInfo->peerMacAddress.a[1],
+                staInfo->peerMacAddress.a[2], staInfo->peerMacAddress.a[3],
+                staInfo->peerMacAddress.a[4], staInfo->peerMacAddress.a[5]);
+        return;
+    }
+
+    spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+    staInfo->uapsdActive = TRUE;
+    staInfo->uspSuspend = FALSE;
+    spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+
+    if(((staInfo->powersaveMode[UNIFI_TRAFFIC_Q_VO]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)||
+        (staInfo->powersaveMode[UNIFI_TRAFFIC_Q_VO]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE))
+        && (!list_empty(&staInfo->mgtFrames))) {
+
+         /* Management queue has data &&  UNIFI_TRAFFIC_Q_VO is delivery enable */
+        unifi_trace(priv, UDBG4, "uf_handle_uspframes_delivery: Sending buffered management frames\n");
+        uf_send_buffered_data_from_delivery_ac(priv, staInfo, UNIFI_TRAFFIC_Q_VO, &staInfo->mgtFrames);
+    }
+
+    if (!uf_is_more_data_for_delivery_ac(priv, staInfo)) {
+        /* All delivery enable AC's are empty, so QNULL to be sent to terminate the USP
+         * NOTE: If we have sent Mgt frame also, we must send QNULL followed to terminate USP
+         */
+        if (!staInfo->uspSuspend) {
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+            staInfo->uapsdActive = FALSE;
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+
+            unifi_trace(priv, UDBG2, "uf_handle_uspframes_delivery: sending QNull for trigger\n");
+            uf_send_qos_null(priv, interfaceTag, staInfo->peerMacAddress.a, (CSR_PRIORITY) staInfo->triggerFramePriority, staInfo);
+            staInfo->triggerFramePriority = CSR_QOS_UP0;
+        } else {
+            unifi_trace(priv, UDBG2, "uf_handle_uspframes_delivery: MgtQ xfer suspended\n");
+        }
+    } else {
+        for(i = UNIFI_TRAFFIC_Q_VO; i >= UNIFI_TRAFFIC_Q_BK; i--) {
+            if(((staInfo->powersaveMode[i]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE)
+                ||(staInfo->powersaveMode[i]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED))
+                && (!list_empty(&staInfo->dataPdu[i]))) {
+                /* Deliver Data according to AC priority (from VO to BK) as part of USP */
+                unifi_trace(priv, UDBG4, "uf_handle_uspframes_delivery: Buffered data frames from Queue (%d) for USP\n", i);
+                uf_send_buffered_data_from_delivery_ac(priv, staInfo, i, &staInfo->dataPdu[i]);
+            }
+
+            if ((!staInfo->uapsdActive) ||
+                    (staInfo->uspSuspend && IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag))) {
+                /* If DTIM active found on one AC, No need to parse the remaining AC's
+                 * as USP suspended. Break out of loop
+                 */
+                unifi_trace(priv, UDBG2, "uf_handle_uspframes_delivery: suspend=%x,  DTIM=%x, USP terminated=%s\n",
+                           staInfo->uspSuspend, IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag),
+                           staInfo->uapsdActive?"NO":"YES");
+                break;
+            }
+        }
+    }
+
+    /* Depending on the USP status, update the TIM accordingly for delivery enabled AC only
+     * (since we are not manipulating any Non-delivery list(AC))
+     */
+    is_all_ac_deliver_enabled_and_moredata(staInfo, &allDeliveryEnabled, &dataAvailable);
+    if ((allDeliveryEnabled && !dataAvailable)) {
+        if ((staInfo->timSet != CSR_WIFI_TIM_RESET) || (staInfo->timSet != CSR_WIFI_TIM_RESETTING)) {
+            staInfo->updateTimReqQueued = (CsrUint8) CSR_WIFI_TIM_RESET;
+            unifi_trace(priv, UDBG4, " --uf_handle_uspframes_delivery, UAPSD timset\n");
+            if (!staInfo->timRequestPendingFlag) {
+                update_tim(priv, staInfo->aid, 0, interfaceTag, staInfo->assignedHandle);
+            }
+        }
+    }
+    unifi_trace(priv, UDBG2, " --uf_handle_uspframes_delivery, uapsd active=%x, suspend?=%x\n",
+                staInfo->uapsdActive, staInfo->uspSuspend);
+}
+
+void uf_process_wmm_deliver_ac_uapsd(unifi_priv_t * priv,
+                                     CsrWifiRouterCtrlStaInfo_t * srcStaInfo,
+                                     CsrUint16 qosControl,
+                                     CsrUint16 interfaceTag)
+{
+    CSR_PRIORITY priority;
+    unifi_TrafficQueue priority_q;
+    unsigned long lock_flags;
+
+    unifi_trace(priv, UDBG2, "++uf_process_wmm_deliver_ac_uapsd: uapsdactive?=%x\n", srcStaInfo->uapsdActive);
+    /* If recceived Frames trigger Frame and Devlivery enabled AC has data
+     * then transmit from High priorty delivery enabled AC
+     */
+    priority = (CSR_PRIORITY)(qosControl & IEEE802_11_QC_TID_MASK);
+    priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY) priority);
+
+    if((srcStaInfo->powersaveMode[priority_q]==CSR_WIFI_AC_TRIGGER_ONLY_ENABLED)
+        ||(srcStaInfo->powersaveMode[priority_q]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)) {
+        spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+        srcStaInfo->triggerFramePriority = priority;
+        spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+        unifi_trace(priv, UDBG2, "uf_process_wmm_deliver_ac_uapsd: trigger frame, Begin U-APSD, triggerQ=%x\n", priority_q);
+        uf_handle_uspframes_delivery(priv, srcStaInfo, interfaceTag);
+    }
+    unifi_trace(priv, UDBG2, "--uf_process_wmm_deliver_ac_uapsd: uapsdactive?=%x\n", srcStaInfo->uapsdActive);
+}
+
+
+void uf_send_qos_null(unifi_priv_t * priv,CsrUint16 interfaceTag, const CsrUint8 *da,CSR_PRIORITY priority,CsrWifiRouterCtrlStaInfo_t * srcStaInfo)
+{
+    bulk_data_param_t bulkdata;
+    CsrResult csrResult;
+    struct sk_buff *skb, *newSkb = NULL;
+    CsrWifiMacAddress peerAddress;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    CSR_TRANSMISSION_CONTROL transmissionControl = (TRANSMISSION_CONTROL_EOSP_MASK | TRANSMISSION_CONTROL_TRIGGER_MASK);
+    int r;
+    CSR_SIGNAL signal;
+    CsrUint32 priority_q;
+    CSR_RATE transmitRate = 0;
+
+
+    func_enter();
+    /* Send a Null Frame to Peer,
+     * 32= size of mac header  */
+    csrResult = unifi_net_data_malloc(priv, &bulkdata.d[0], MAC_HEADER_SIZE + QOS_CONTROL_HEADER_SIZE);
+
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv, " failed to allocate request_data. in uf_send_qos_null func\n");
+        return ;
+    }
+    skb = (struct sk_buff *)(bulkdata.d[0].os_net_buf_ptr);
+    skb->len = 0;
+    bulkdata.d[0].os_data_ptr = skb->data;
+    bulkdata.d[0].os_net_buf_ptr = (unsigned char*)skb;
+    bulkdata.d[0].net_buf_length = bulkdata.d[0].data_length = skb->len;
+    bulkdata.d[1].os_data_ptr = NULL;
+    bulkdata.d[1].os_net_buf_ptr = NULL;
+    bulkdata.d[1].net_buf_length = bulkdata.d[1].data_length = 0;
+
+    /* For null frames protection bit should not be set in MAC header, so passing value 0 below for protection field */
+
+    if (prepare_and_add_macheader(priv, skb, newSkb, priority, &bulkdata, interfaceTag, da, interfacePriv->bssid.a, 0)) {
+        unifi_error(priv, "failed to create MAC header\n");
+        unifi_net_data_free(priv, &bulkdata.d[0]);
+        return;
+    }
+    memcpy(peerAddress.a, ((CsrUint8 *) bulkdata.d[0].os_data_ptr) + 4, ETH_ALEN);
+    /* convert priority to queue */
+    priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY) priority);
+
+    /* Frame ma-packet.req, this is saved/transmitted depend on queue state
+     * send the null frame at data rate of 1 Mb/s for AP or 6 Mb/s for P2PGO
+     */
+    switch (interfacePriv->interfaceMode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+            transmitRate = 2;
+            break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+            transmitRate = 12;
+            break;
+        default:
+            transmitRate = 0;
+    }
+    unifi_frame_ma_packet_req(priv, priority, transmitRate, 0xffffffff, interfaceTag,
+                              transmissionControl, priv->netdev_client->sender_id,
+                              peerAddress.a, &signal);
+
+    r = ul_send_signal_unpacked(priv, &signal, &bulkdata);
+    if(r) {
+        unifi_error(priv, "failed to send QOS data null packet result: %d\n",r);
+        unifi_net_data_free(priv, &bulkdata.d[0]);
+    }
+
+    func_exit();
+    return;
+
+}
+void uf_send_nulldata(unifi_priv_t * priv,CsrUint16 interfaceTag, const CsrUint8 *da,CSR_PRIORITY priority,CsrWifiRouterCtrlStaInfo_t * srcStaInfo)
+{
+    bulk_data_param_t bulkdata;
+    CsrResult csrResult;
+    struct sk_buff *skb, *newSkb = NULL;
+    CsrWifiMacAddress peerAddress;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    CSR_TRANSMISSION_CONTROL transmissionControl = 0;
+    int r;
+    CSR_SIGNAL signal;
+    CsrUint32 priority_q;
+    CSR_RATE transmitRate = 0;
+    CSR_MA_PACKET_REQUEST *req = &signal.u.MaPacketRequest;
+    unsigned long lock_flags;
+
+    func_enter();
+    /* Send a Null Frame to Peer, size = 24 for MAC header */
+    csrResult = unifi_net_data_malloc(priv, &bulkdata.d[0], MAC_HEADER_SIZE);
+
+    if (csrResult != CSR_RESULT_SUCCESS) {
+        unifi_error(priv, "uf_send_nulldata: Failed to allocate memory for NULL frame\n");
+        return ;
+    }
+    skb = (struct sk_buff *)(bulkdata.d[0].os_net_buf_ptr);
+    skb->len = 0;
+    bulkdata.d[0].os_data_ptr = skb->data;
+    bulkdata.d[0].os_net_buf_ptr = (unsigned char*)skb;
+    bulkdata.d[0].net_buf_length = bulkdata.d[0].data_length = skb->len;
+    bulkdata.d[1].os_data_ptr = NULL;
+    bulkdata.d[1].os_net_buf_ptr = NULL;
+    bulkdata.d[1].net_buf_length = bulkdata.d[1].data_length = 0;
+
+    /* For null frames protection bit should not be set in MAC header, so passing value 0 below for protection field */
+    if (prepare_and_add_macheader(priv, skb, newSkb, priority, &bulkdata, interfaceTag, da, interfacePriv->bssid.a, 0)) {
+        unifi_error(priv, "uf_send_nulldata: Failed to create MAC header\n");
+        unifi_net_data_free(priv, &bulkdata.d[0]);
+        return;
+    }
+    memcpy(peerAddress.a, ((CsrUint8 *) bulkdata.d[0].os_data_ptr) + 4, ETH_ALEN);
+    /* convert priority to queue */
+    priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY) priority);
+    transmissionControl &= ~(CSR_NO_CONFIRM_REQUIRED);
+
+    /* Frame ma-packet.req, this is saved/transmitted depend on queue state
+     * send the null frame at data rate of 1 Mb/s for AP or 6 Mb/s for P2PGO
+     */
+    switch (interfacePriv->interfaceMode)
+    {
+        case CSR_WIFI_ROUTER_CTRL_MODE_AP:
+            transmitRate = 2;
+            break;
+        case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO:
+            transmitRate = 12;
+            break;
+        default:
+            transmitRate = 0;
+    }
+    unifi_frame_ma_packet_req(priv, priority, transmitRate, INVALID_HOST_TAG, interfaceTag,
+                              transmissionControl, priv->netdev_client->sender_id,
+                              peerAddress.a, &signal);
+
+    /* Save host tag to check the status on reception of MA packet confirm */
+    srcStaInfo->nullDataHostTag = req->HostTag;
+    unifi_trace(priv, UDBG1, "uf_send_nulldata: STA AID = %d hostTag = %x\n", srcStaInfo->aid, req->HostTag);
+
+    r = ul_send_signal_unpacked(priv, &signal, &bulkdata);
+
+    if(r == -ENOSPC) {
+        unifi_trace(priv, UDBG1, "uf_send_nulldata: ENOSPC Requeue the Null frame\n");
+        enque_tx_data_pdu(priv, &bulkdata, &srcStaInfo->dataPdu[priority_q], &signal, 1);
+        spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+        srcStaInfo->noOfPktQueued++;
+        spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+
+
+    }
+    if(r && r != -ENOSPC){
+        unifi_error(priv, "uf_send_nulldata: Failed to send Null frame Error = %d\n",r);
+        unifi_net_data_free(priv, &bulkdata.d[0]);
+        srcStaInfo->nullDataHostTag = INVALID_HOST_TAG;
+    }
+
+    func_exit();
+    return;
+}
+
+CsrBool uf_check_broadcast_bssid(unifi_priv_t *priv, const bulk_data_param_t *bulkdata)
+{
+    CsrUint8 *bssid = NULL;
+    static const CsrWifiMacAddress broadcast_address = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
+    CsrUint8 toDs, fromDs;
+
+    toDs = (((bulkdata->d[0].os_data_ptr)[1]) & 0x01) ? 1 : 0;
+    fromDs =(((bulkdata->d[0].os_data_ptr)[1]) & 0x02) ? 1 : 0;
+
+     if (toDs && fromDs)
+    {
+        unifi_trace(priv, UDBG6, "Address 4 present, Don't try to find BSSID\n");
+        bssid = NULL;
+    }
+    else if((toDs == 0) && (fromDs ==0))
+    {
+        /* BSSID is Address 3 */
+        bssid = (CsrUint8 *) (bulkdata->d[0].os_data_ptr + 4 + (2 * ETH_ALEN));
+    }
+    else if(toDs)
+    {
+        /* BSSID is Address 1 */
+        bssid = (CsrUint8 *) (bulkdata->d[0].os_data_ptr + 4);
+    }
+    else if(fromDs)
+    {
+        /* BSSID is Address 2 */
+        bssid = (CsrUint8 *) (bulkdata->d[0].os_data_ptr + 4 + ETH_ALEN);
+    }
+
+    if (memcmp(broadcast_address.a, bssid, ETH_ALEN)== 0)
+    {
+        return TRUE;
+    }
+    else
+    {
+        return FALSE;
+    }
+}
+
+
+CsrBool uf_process_pm_bit_for_peer(unifi_priv_t * priv, CsrWifiRouterCtrlStaInfo_t * srcStaInfo,
+                                CsrUint8 pmBit,CsrUint16 interfaceTag)
+{
+    CsrBool moreData = FALSE;
+    CsrBool powerSaveChanged = FALSE;
+    unsigned long lock_flags;
+
+    unifi_trace(priv, UDBG3, "entering uf_process_pm_bit_for_peer\n");
+    if (pmBit) {
+        priv->allPeerDozing |= (0x01 << (srcStaInfo->assignedHandle));
+    } else {
+        priv->allPeerDozing &= ~(0x01 << (srcStaInfo->assignedHandle));
+    }
+    if(pmBit) {
+        if(srcStaInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE) {
+
+            /* disable the preemption */
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+            srcStaInfo->currentPeerState =CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE;
+            powerSaveChanged = TRUE;
+            /* enable the preemption */
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+        } else {
+            return powerSaveChanged;
+        }
+    } else {
+        if(srcStaInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE) {
+            /* disable the preemption */
+            spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+            srcStaInfo->currentPeerState = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE;
+            powerSaveChanged = TRUE;
+            /* enable the preemption */
+            spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+        }else {
+            return powerSaveChanged;
+        }
+    }
+
+
+    if(srcStaInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE) {
+        unifi_trace(priv,UDBG3, "Peer with AID = %d is active now\n",srcStaInfo->aid);
+        process_peer_active_transition(priv,srcStaInfo,interfaceTag);
+    } else {
+        unifi_trace(priv,UDBG3, "Peer with AID = %d is in PS Now\n",srcStaInfo->aid);
+        /* Set TIM if needed */
+        if(!srcStaInfo->wmmOrQosEnabled) {
+            moreData = (!list_empty(&srcStaInfo->mgtFrames) ||
+                        !list_empty(&srcStaInfo->dataPdu[UNIFI_TRAFFIC_Q_VO])||
+                        !list_empty(&srcStaInfo->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION]));
+            if(moreData && (srcStaInfo->timSet == CSR_WIFI_TIM_RESET)) {
+                unifi_trace(priv, UDBG3, "This condition should not occur\n");
+                if (!srcStaInfo->timRequestPendingFlag){
+                    update_tim(priv,srcStaInfo->aid,1,interfaceTag, srcStaInfo->assignedHandle);
+                }
+                else
+                {
+                    /* Cache the TimSet value so that it will processed immidiatly after
+                     * completing the current setTim Request
+                     */
+                    srcStaInfo->updateTimReqQueued = 1;
+                    unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", srcStaInfo->updateTimReqQueued,
+                                srcStaInfo->aid);
+                }
+
+            }
+        } else {
+            CsrUint8 allDeliveryEnabled = 0, dataAvailable = 0;
+            unifi_trace(priv, UDBG5, "Qos in AP Mode\n");
+            /* Check if all AC's are Delivery Enabled */
+            is_all_ac_deliver_enabled_and_moredata(srcStaInfo, &allDeliveryEnabled, &dataAvailable);
+            /*check for more data in non-delivery enabled queues*/
+            moreData = (uf_is_more_data_for_non_delivery_ac(srcStaInfo) || (allDeliveryEnabled && dataAvailable));
+
+            if(moreData && (srcStaInfo->timSet == CSR_WIFI_TIM_RESET)) {
+                if (!srcStaInfo->timRequestPendingFlag){
+                    update_tim(priv,srcStaInfo->aid,1,interfaceTag, srcStaInfo->assignedHandle);
+                }
+                else
+                {
+                    /* Cache the TimSet value so that it will processed immidiatly after
+                     * completing the current setTim Request
+                     */
+                    srcStaInfo->updateTimReqQueued = 1;
+                    unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", srcStaInfo->updateTimReqQueued,
+                                srcStaInfo->aid);
+                }
+            }
+        }
+    }
+    unifi_trace(priv, UDBG3, "leaving uf_process_pm_bit_for_peer\n");
+    return powerSaveChanged;
+}
+
+
+
+void uf_process_ps_poll(unifi_priv_t *priv,CsrUint8* sa,CsrUint8* da,CsrUint8 pmBit,CsrUint16 interfaceTag)
+{
+    CsrWifiRouterCtrlStaInfo_t *staRecord =
+    CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv, sa, interfaceTag);
+    tx_buffered_packets_t * buffered_pkt = NULL;
+    CsrWifiMacAddress peerMacAddress;
+    unsigned long lock_flags;
+    CsrInt8 r =0;
+    CsrBool moreData = FALSE;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    unifi_trace(priv, UDBG3, "entering uf_process_ps_poll\n");
+    if(!staRecord) {
+        memcpy(peerMacAddress.a,sa,ETH_ALEN);
+        unifi_trace(priv, UDBG3, "In uf_process_ps_poll, sta record not found:unexpected frame addr = %x:%x:%x:%x:%x:%x\n",
+                sa[0], sa[1],sa[2], sa[3], sa[4],sa[5]);
+        CsrWifiRouterCtrlUnexpectedFrameIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,interfaceTag,peerMacAddress);
+        return;
+    }
+
+    uf_process_pm_bit_for_peer(priv,staRecord,pmBit,interfaceTag);
+
+    /* Update station last activity time */
+    staRecord->activity_flag = TRUE;
+
+    /* This should not change the PM bit as PS-POLL has PM bit always set */
+    if(!pmBit) {
+        unifi_notice (priv," PM bit reset in PS-POLL\n");
+        return;
+    }
+
+    if(IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag)) {
+        /* giving more priority to multicast packets so dropping ps-poll*/
+        unifi_notice (priv," multicast transmission is going on so don't take action on PS-POLL\n");
+        return;
+    }
+
+    if(!staRecord->wmmOrQosEnabled) {
+        if((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->mgtFrames))) {
+            buffered_pkt->transmissionControl |= TRANSMISSION_CONTROL_TRIGGER_MASK;
+            moreData = (!list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION]) ||
+                        !list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO]) ||
+                        !list_empty(&staRecord->mgtFrames));
+
+            buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+            if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,moreData,FALSE)) == -ENOSPC) {
+                /* Clear the trigger bit transmission control*/
+                buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+                /* Enqueue at the head of the queue */
+                spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+                list_add(&buffered_pkt->q, &staRecord->mgtFrames);
+                spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+                unifi_trace(priv, UDBG1, "(ENOSPC) PS-POLL received : PDU sending failed \n");
+                priv->pausedStaHandle[3]=(CsrUint8)(staRecord->assignedHandle);
+            } else {
+                if(r){
+                    unifi_trace (priv, UDBG1, " HIP validation failure : PDU sending failed \n");
+                    /* the PDU failed where we can't do any thing so free the storage */
+                    unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+                }
+                kfree(buffered_pkt);
+            }
+        } else if((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO]))) {
+            buffered_pkt->transmissionControl |= TRANSMISSION_CONTROL_TRIGGER_MASK;
+            moreData = (!list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION]) ||
+                        !list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO]));
+
+            buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+            if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,moreData,FALSE)) == -ENOSPC) {
+                /* Clear the trigger bit transmission control*/
+                buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+                /* Enqueue at the head of the queue */
+                spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+                list_add(&buffered_pkt->q, &staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO]);
+                spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+                priv->pausedStaHandle[3]=(CsrUint8)(staRecord->assignedHandle);
+                unifi_trace(priv, UDBG1, "(ENOSPC) PS-POLL received : PDU sending failed \n");
+            } else {
+                if(r){
+                    unifi_trace (priv, UDBG1, " HIP validation failure : PDU sending failed \n");
+                    /* the PDU failed where we can't do any thing so free the storage */
+                    unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+                }
+                kfree(buffered_pkt);
+            }
+        } else  if((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION]))) {
+            buffered_pkt->transmissionControl |= TRANSMISSION_CONTROL_TRIGGER_MASK;
+            moreData = !list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION]);
+
+            buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+            if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,moreData,FALSE)) == -ENOSPC) {
+                /* Clear the trigger bit transmission control*/
+                buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+                /* Enqueue at the head of the queue */
+                spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+                list_add(&buffered_pkt->q, &staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION]);
+                spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+                priv->pausedStaHandle[0]=(CsrUint8)(staRecord->assignedHandle);
+                unifi_trace(priv, UDBG1, "(ENOSPC) PS-POLL received : PDU sending failed \n");
+            } else {
+                if(r){
+                    unifi_trace (priv, UDBG1, " HIP validation failure : PDU sending failed \n");
+                    /* the PDU failed where we can't do any thing so free the storage */
+                    unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+                }
+                kfree(buffered_pkt);
+            }
+        } else {
+         /* Actually since we have sent an ACK, there
+         * there is no need to send a NULL frame*/
+        }
+        moreData = (!list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO]) ||
+           !list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION]) ||
+            !list_empty(&staRecord->mgtFrames));
+        if(!moreData && (staRecord->timSet == CSR_WIFI_TIM_SET)) {
+            unifi_trace(priv, UDBG3, "more data = NULL, set tim to 0 in uf_process_ps_poll\n");
+            if (!staRecord->timRequestPendingFlag){
+                update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle);
+            }
+            else
+            {
+                /* Cache the TimSet value so that it will processed immidiatly after
+                 * completing the current setTim Request
+                 */
+                staRecord->updateTimReqQueued = 0;
+                unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued,
+                            staRecord->aid);
+            }
+        }
+    } else {
+
+        CsrUint8 allDeliveryEnabled = 0, dataAvailable = 0;
+        unifi_trace(priv, UDBG3,"Qos Support station.Processing PS-Poll\n");
+
+        /*Send Data From Management Frames*/
+        /* Priority orders for delivering the buffered packets are
+         * 1. Deliver the Management frames if there
+         * 2. Other access catagory frames which are non deliver enable including UNIFI_TRAFFIC_Q_VO
+         * priority is from VO->BK
+         */
+
+        /* Check if all AC's are Delivery Enabled */
+        is_all_ac_deliver_enabled_and_moredata(staRecord, &allDeliveryEnabled, &dataAvailable);
+
+        if (allDeliveryEnabled) {
+            unifi_trace(priv, UDBG3, "uf_process_ps_poll: All ACs are delivery enable so Sending QOS Null in response of Ps-poll\n");
+            uf_send_qos_null(priv,interfaceTag,sa,CSR_QOS_UP0,staRecord);
+            return;
+        }
+
+        if (!list_empty(&staRecord->mgtFrames)) {
+             if ((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->mgtFrames))) {
+                    /* We dont have packets in non delivery enabled UNIFI_TRAFFIC_Q_VO, So we are looking in management
+                     * queue of the station record
+                     */
+                    moreData = uf_is_more_data_for_non_delivery_ac(staRecord);
+                    buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+
+                    /* Last parameter is EOSP & its false always for PS-POLL processing */
+                    if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,moreData,FALSE)) == -ENOSPC) {
+                        /* Clear the trigger bit transmission control*/
+                        buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+                        /* Enqueue at the head of the queue */
+                        spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+                        list_add(&buffered_pkt->q, &staRecord->mgtFrames);
+                        spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+                        priv->pausedStaHandle[0]=(CsrUint8)(staRecord->assignedHandle);
+                        unifi_trace(priv, UDBG1, "(ENOSPC) PS-POLL received : PDU sending failed \n");
+                    } else {
+                        if(r){
+                            unifi_trace (priv, UDBG1, " HIP validation failure : PDU sending failed \n");
+                            /* the PDU failed where we can't do any thing so free the storage */
+                            unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+                        }
+                        kfree(buffered_pkt);
+                    }
+                } else {
+                    unifi_error(priv, "uf_process_ps_poll: Mgt frame list empty!! \n");
+                }
+
+        } else {
+            CsrInt8 i;
+            /* We dont have buffered packet in mangement frame queue (1 failed), So proceed with condition 2
+             * UNIFI_TRAFFIC_Q_VO -> VI -> BE -> BK
+             */
+            for(i= 3; i>=0; i--) {
+                if (!IS_DELIVERY_ENABLED(staRecord->powersaveMode[i])) {
+                    /* Send One packet, if queue is NULL then continue */
+                    if((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->dataPdu[i]))) {
+                        moreData = uf_is_more_data_for_non_delivery_ac(staRecord);
+
+                        buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+
+                        /* Last parameter is EOSP & its false always for PS-POLL processing */
+                        if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,moreData,FALSE)) == -ENOSPC) {
+                            /* Clear the trigger bit transmission control*/
+                            buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK);
+                            /* Enqueue at the head of the queue */
+                            spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+                            list_add(&buffered_pkt->q, &staRecord->dataPdu[i]);
+                            spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+                            priv->pausedStaHandle[0]=(CsrUint8)(staRecord->assignedHandle);
+                            unifi_trace(priv, UDBG1, "(ENOSPC) PS-POLL received : PDU sending failed \n");
+                        } else {
+                            if(r) {
+                                unifi_trace (priv, UDBG1, " HIP validation failure : PDU sending failed \n");
+                                /* the PDU failed where we can't do any thing so free the storage */
+                                unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+                            }
+                            kfree(buffered_pkt);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+        /* Check if all AC's are Delivery Enabled */
+        is_all_ac_deliver_enabled_and_moredata(staRecord, &allDeliveryEnabled, &dataAvailable);
+        /*check for more data in non-delivery enabled queues*/
+        moreData = (uf_is_more_data_for_non_delivery_ac(staRecord) || (allDeliveryEnabled && dataAvailable));
+        if(!moreData && (staRecord->timSet == CSR_WIFI_TIM_SET)) {
+            unifi_trace(priv, UDBG3, "more data = NULL, set tim to 0 in uf_process_ps_poll\n");
+            if (!staRecord->timRequestPendingFlag){
+                update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle);
+            }
+            else
+            {
+                /* Cache the TimSet value so that it will processed immidiatly after
+                 * completing the current setTim Request
+                 */
+                staRecord->updateTimReqQueued = 0;
+                unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued,
+                            staRecord->aid);
+            }
+
+        }
+    }
+
+        unifi_trace(priv, UDBG3, "leaving uf_process_ps_poll\n");
+}
+
+
+
+void add_to_send_cfm_list(unifi_priv_t * priv,
+                          tx_buffered_packets_t *tx_q_item,
+                          struct list_head *frames_need_cfm_list)
+{
+    tx_buffered_packets_t *send_cfm_list_item = NULL;
+
+    send_cfm_list_item = (tx_buffered_packets_t *) kmalloc(sizeof(tx_buffered_packets_t), GFP_ATOMIC);
+
+    if(send_cfm_list_item == NULL){
+        unifi_warning(priv, "%s: Failed to allocate memory for new list item \n");
+        return;
+    }
+
+    INIT_LIST_HEAD(&send_cfm_list_item->q);
+
+    send_cfm_list_item->hostTag = tx_q_item->hostTag;
+    send_cfm_list_item->interfaceTag = tx_q_item->interfaceTag;
+    send_cfm_list_item->transmissionControl = tx_q_item->transmissionControl;
+    send_cfm_list_item->leSenderProcessId = tx_q_item->leSenderProcessId;
+    send_cfm_list_item->rate = tx_q_item->rate;
+    memcpy(send_cfm_list_item->peerMacAddress.a, tx_q_item->peerMacAddress.a, ETH_ALEN);
+    send_cfm_list_item->priority = tx_q_item->priority;
+
+    list_add_tail(&send_cfm_list_item->q, frames_need_cfm_list);
+}
+
+void uf_prepare_send_cfm_list_for_queued_pkts(unifi_priv_t * priv,
+                                                 struct list_head *frames_need_cfm_list,
+                                                 struct list_head * list)
+{
+    tx_buffered_packets_t *tx_q_item = NULL;
+    struct list_head *listHead;
+    struct list_head *placeHolder;
+    unsigned long lock_flags;
+
+    func_enter();
+
+    spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+
+    /* Search through the list and if confirmation required for any frames,
+    add it to the send_cfm list */
+    list_for_each_safe(listHead, placeHolder, list) {
+        tx_q_item = list_entry(listHead, tx_buffered_packets_t, q);
+
+        if(!tx_q_item) {
+            unifi_error(priv, "Entry should exist, otherwise it is a (BUG)\n");
+            continue;
+        }
+
+        /* check if confirmation is requested and if the sender ID
+        is not netdevice client then save the entry in the list for need cfms */
+        if (!(tx_q_item->transmissionControl & CSR_NO_CONFIRM_REQUIRED) &&
+            (tx_q_item->leSenderProcessId != priv->netdev_client->sender_id)){
+             unifi_trace(priv, UDBG1, "%s: SenderProcessID=%x host tag=%x transmission control=%x\n",
+                __FUNCTION__,
+                tx_q_item->leSenderProcessId,
+                tx_q_item->hostTag,
+                tx_q_item->transmissionControl);
+
+             add_to_send_cfm_list(priv, tx_q_item, frames_need_cfm_list);
+        }
+    }
+
+    spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+
+    func_exit();
+}
+
+
+
+void uf_flush_list(unifi_priv_t * priv, struct list_head * list)
+{
+    tx_buffered_packets_t *tx_q_item;
+    struct list_head *listHead;
+    struct list_head *placeHolder;
+    unsigned long lock_flags;
+
+    unifi_trace(priv, UDBG5, "entering the uf_flush_list \n");
+
+    spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+    /* go through list, delete & free memory */
+    list_for_each_safe(listHead, placeHolder, list) {
+        tx_q_item = list_entry(listHead, tx_buffered_packets_t, q);
+
+        if(!tx_q_item) {
+            unifi_error(priv, "entry should exists, otherwise crashes (bug)\n");
+        }
+        unifi_trace(priv, UDBG5,
+                "proccess_tx:  in uf_flush_list peerMacAddress=%02X%02X%02X%02X%02X%02X senderProcessId=%x\n",
+                tx_q_item->peerMacAddress.a[0], tx_q_item->peerMacAddress.a[1],
+                tx_q_item->peerMacAddress.a[2], tx_q_item->peerMacAddress.a[3],
+                tx_q_item->peerMacAddress.a[4], tx_q_item->peerMacAddress.a[5],
+                tx_q_item->leSenderProcessId);
+
+        list_del(listHead);
+        /* free the allocated memory */
+        unifi_net_data_free(priv, &tx_q_item->bulkdata);
+        kfree(tx_q_item);
+        tx_q_item = NULL;
+        if (!priv->noOfPktQueuedInDriver) {
+            unifi_error(priv, "packets queued in driver 0 still decrementing in %s\n", __FUNCTION__);
+        } else {
+            priv->noOfPktQueuedInDriver--;
+        }
+    }
+    spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+}
+
+tx_buffered_packets_t *dequeue_tx_data_pdu(unifi_priv_t *priv, struct list_head *txList)
+{
+    /* dequeue the tx data packets from the appropriate queue */
+    tx_buffered_packets_t *tx_q_item = NULL;
+    struct list_head *listHead;
+    struct list_head *placeHolder;
+    unsigned long lock_flags;
+
+    unifi_trace(priv, UDBG5, "entering dequeue_tx_data_pdu\n");
+    /* check for list empty */
+    if (list_empty(txList)) {
+        unifi_trace(priv, UDBG5, "In dequeue_tx_data_pdu, the list is empty\n");
+        return NULL;
+    }
+
+    /* Verification, if packet count is negetive */
+    if (priv->noOfPktQueuedInDriver == 0xFFFF) {
+        unifi_warning(priv, "no packet available in queue: debug");
+        return NULL;
+    }
+
+    /* return first node after header, & delete from the list  && atleast one item exist */
+    spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+    list_for_each_safe(listHead, placeHolder, txList) {
+        tx_q_item = list_entry(listHead, tx_buffered_packets_t, q);
+        list_del(listHead);
+        break;
+    }
+    spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+
+    if (tx_q_item) {
+        unifi_trace(priv, UDBG5,
+                "proccess_tx:  In dequeue_tx_data_pdu peerMacAddress=%02X%02X%02X%02X%02X%02X senderProcessId=%x\n",
+                tx_q_item->peerMacAddress.a[0], tx_q_item->peerMacAddress.a[1],
+                tx_q_item->peerMacAddress.a[2], tx_q_item->peerMacAddress.a[3],
+                tx_q_item->peerMacAddress.a[4], tx_q_item->peerMacAddress.a[5],
+                tx_q_item->leSenderProcessId);
+    }
+
+    unifi_trace(priv, UDBG5, "leaving dequeue_tx_data_pdu\n");
+    return tx_q_item;
+}
+/* generic function to get the station record handler */
+CsrWifiRouterCtrlStaInfo_t *CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(unifi_priv_t *priv,
+        const CsrUint8 *peerMacAddress,
+        CsrUint16 interfaceTag)
+{
+    CsrUint8 i;
+    netInterface_priv_t *interfacePriv;
+    unsigned long lock_flags;
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "interfaceTag is not proper, interfaceTag = %d\n", interfaceTag);
+        return NULL;
+    }
+
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    /* disable the preemption untill station record is fetched */
+    spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+
+    for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
+        if (interfacePriv->staInfo[i]!= NULL) {
+            if (!memcmp(((CsrWifiRouterCtrlStaInfo_t *) (interfacePriv->staInfo[i]))->peerMacAddress.a, peerMacAddress, ETH_ALEN)) {
+                /* enable the preemption as station record is fetched */
+                spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+                unifi_trace(priv, UDBG5, "peer entry found in station record\n");
+                return ((CsrWifiRouterCtrlStaInfo_t *) (interfacePriv->staInfo[i]));
+            }
+        }
+    }
+    /* enable the preemption as station record is fetched */
+    spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+    unifi_trace(priv, UDBG5, "peer entry not found in station record\n");
+    return NULL;
+}
+/* generic function to get the station record handler from the handle */
+CsrWifiRouterCtrlStaInfo_t * CsrWifiRouterCtrlGetStationRecordFromHandle(unifi_priv_t *priv,
+                                                                 CsrUint32 handle,
+                                                                 CsrUint16 interfaceTag)
+{
+    netInterface_priv_t *interfacePriv;
+
+    if ((handle >= UNIFI_MAX_CONNECTIONS) || (interfaceTag >= CSR_WIFI_NUM_INTERFACES)) {
+        unifi_error(priv, "handle/interfaceTag is not proper, handle = %d, interfaceTag = %d\n", handle, interfaceTag);
+        return NULL;
+    }
+    interfacePriv = priv->interfacePriv[interfaceTag];
+    return ((CsrWifiRouterCtrlStaInfo_t *) (interfacePriv->staInfo[handle]));
+}
+
+/* Function to do inactivity */
+void uf_check_inactivity(unifi_priv_t *priv, CsrUint16 interfaceTag, CsrTime currentTime)
+{
+    CsrUint32 i;
+    CsrWifiRouterCtrlStaInfo_t *staInfo;
+    CsrTime elapsedTime;    /* Time in microseconds */
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    CsrWifiMacAddress peerMacAddress;
+    unsigned long lock_flags;
+
+    if (interfacePriv == NULL) {
+        unifi_trace(priv, UDBG3, "uf_check_inactivity: Interface priv is NULL \n");
+        return;
+    }
+
+    spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+    /* Go through the list of stations to check for inactivity */
+    for(i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
+        staInfo =  CsrWifiRouterCtrlGetStationRecordFromHandle(priv, i, interfaceTag);
+        if(!staInfo ) {
+            continue;
+        }
+
+        unifi_trace(priv, UDBG3, "Running Inactivity handler Time %xus station's last activity %xus\n",
+                currentTime, staInfo->lastActivity);
+
+
+        elapsedTime = (currentTime >= staInfo->lastActivity)?
+                (currentTime - staInfo->lastActivity):
+                (~((CsrUint32)0) - staInfo->lastActivity + currentTime);
+        spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+
+        if (elapsedTime > MAX_INACTIVITY_INTERVAL) {
+            memcpy((CsrUint8*)&peerMacAddress, (CsrUint8*)&staInfo->peerMacAddress, sizeof(CsrWifiMacAddress));
+
+            /* Indicate inactivity for the station */
+            unifi_trace(priv, UDBG3, "Station %x:%x:%x:%x:%x:%x inactive since %xus\n sending Inactive Ind\n",
+                        peerMacAddress.a[0], peerMacAddress.a[1],
+                        peerMacAddress.a[2], peerMacAddress.a[3],
+                        peerMacAddress.a[4], peerMacAddress.a[5],
+                        elapsedTime);
+
+            CsrWifiRouterCtrlStaInactiveIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, interfaceTag, peerMacAddress);
+        }
+    }
+
+    interfacePriv->last_inactivity_check = currentTime;
+}
+
+/* Function to update activity of a station */
+void uf_update_sta_activity(unifi_priv_t *priv, CsrUint16 interfaceTag, const CsrUint8 *peerMacAddress)
+{
+    CsrTime elapsedTime, currentTime;    /* Time in microseconds */
+    CsrTime timeHi;         /* Not used - Time in microseconds */
+    CsrWifiRouterCtrlStaInfo_t *staInfo;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    unsigned long lock_flags;
+
+    if (interfacePriv == NULL) {
+        unifi_trace(priv, UDBG3, "uf_check_inactivity: Interface priv is NULL \n");
+        return;
+    }
+
+    currentTime = CsrTimeGet(&timeHi);
+
+
+    staInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv, peerMacAddress, interfaceTag);
+
+    if (staInfo == NULL) {
+        unifi_trace(priv, UDBG4, "Sta does not exist yet");
+        return;
+    }
+
+    spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+    /* Update activity */
+    staInfo->lastActivity = currentTime;
+
+    /* See if inactivity handler needs to be run
+     * Here it is theoretically possible that the counter may have wrapped around. But
+     * since we just want to know when to run the inactivity handler it does not really matter.
+     * Especially since this is data path it makes sense in keeping it simple and avoiding
+     * 64 bit handling */
+    elapsedTime = (currentTime >= interfacePriv->last_inactivity_check)?
+                    (currentTime - interfacePriv->last_inactivity_check):
+                    (~((CsrUint32)0) - interfacePriv->last_inactivity_check + currentTime);
+
+    spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+
+    /* Check if it is time to run the inactivity handler */
+    if (elapsedTime > INACTIVITY_CHECK_INTERVAL) {
+        uf_check_inactivity(priv, interfaceTag, currentTime);
+    }
+}
+void resume_unicast_buffered_frames(unifi_priv_t *priv, CsrUint16 interfaceTag)
+{
+
+   netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+   CsrUint8 i;
+   int j;
+   tx_buffered_packets_t * buffered_pkt = NULL;
+   CsrBool hipslotFree[4] = {TRUE,TRUE,TRUE,TRUE};
+   int r;
+   unsigned long lock_flags;
+
+   func_enter();
+   while(!isRouterBufferEnabled(priv,3) &&
+                            ((buffered_pkt=dequeue_tx_data_pdu(priv,&interfacePriv->genericMgtFrames))!=NULL)) {
+        buffered_pkt->transmissionControl &=
+                     ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK);
+        if((r=frame_and_send_queued_pdu(priv,buffered_pkt,NULL,0,FALSE)) == -ENOSPC) {
+            /* Enqueue at the head of the queue */
+            spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+            list_add(&buffered_pkt->q, &interfacePriv->genericMgtFrames);
+            spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+            hipslotFree[3]=FALSE;
+            break;
+        }else {
+            if(r){
+                unifi_trace (priv, UDBG1, " HIP validation failure : PDU sending failed \n");
+                /* the PDU failed where we can't do any thing so free the storage */
+                unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+            }
+            kfree(buffered_pkt);
+        }
+   }
+   for(i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
+        CsrWifiRouterCtrlStaInfo_t *staInfo = interfacePriv->staInfo[i];
+        if(!hipslotFree[0] && !hipslotFree[1] && !hipslotFree[2] && !hipslotFree[3]) {
+            unifi_trace(priv, UDBG3, "(ENOSPC) in resume_unicast_buffered_frames:: hip slots are full \n");
+            break;
+        }
+        if (staInfo && (staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE)) {
+          while((( TRUE == hipslotFree[3] ) && (buffered_pkt=dequeue_tx_data_pdu(priv, &staInfo->mgtFrames)))) {
+              buffered_pkt->transmissionControl &=
+                           ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK);
+              if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staInfo,0,FALSE)) == -ENOSPC) {
+                  unifi_trace(priv, UDBG3, "(ENOSPC) in resume_unicast_buffered_frames:: hip slots are full for voice queue\n");
+                  /* Enqueue at the head of the queue */
+                  spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+                  list_add(&buffered_pkt->q, &staInfo->mgtFrames);
+                  spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+                  priv->pausedStaHandle[3]=(CsrUint8)(staInfo->assignedHandle);
+                  hipslotFree[3] = FALSE;
+                  break;
+              } else {
+                  if(r){
+                      unifi_trace (priv, UDBG1, " HIP validation failure : PDU sending failed \n");
+                      /* the PDU failed where we can't do any thing so free the storage */
+                      unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+                  }
+                  kfree(buffered_pkt);
+              }
+          }
+
+          for(j=3;j>=0;j--) {
+              if(!hipslotFree[j])
+                  continue;
+
+              while((buffered_pkt=dequeue_tx_data_pdu(priv, &staInfo->dataPdu[j]))) {
+                 buffered_pkt->transmissionControl &=
+                            ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK);
+                 if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staInfo,0,FALSE)) == -ENOSPC) {
+                     /* Enqueue at the head of the queue */
+                     spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+                     list_add(&buffered_pkt->q, &staInfo->dataPdu[j]);
+                     spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+                     priv->pausedStaHandle[j]=(CsrUint8)(staInfo->assignedHandle);
+                     hipslotFree[j]=FALSE;
+                     break;
+                 } else {
+                    if(r){
+                        unifi_trace (priv, UDBG1, " HIP validation failure : PDU sending failed \n");
+                        /* the PDU failed where we can't do any thing so free the storage */
+                        unifi_net_data_free(priv, &buffered_pkt->bulkdata);
+                     }
+                    kfree(buffered_pkt);
+                 }
+              }
+          }
+       }
+    }
+    func_exit();
+}
+void update_eosp_to_head_of_broadcast_list_head(unifi_priv_t *priv,CsrUint16 interfaceTag)
+{
+
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+    unsigned long lock_flags;
+    struct list_head *listHead;
+    struct list_head *placeHolder;
+    tx_buffered_packets_t *tx_q_item;
+
+    func_enter();
+    if (interfacePriv->noOfbroadcastPktQueued) {
+
+        /* Update the EOSP to the HEAD of b/c list
+         * beacuse we have received any mgmt packet so it should not hold for long time
+         * peer may time out.
+         */
+        spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
+        list_for_each_safe(listHead, placeHolder, &interfacePriv->genericMulticastOrBroadCastFrames) {
+            tx_q_item = list_entry(listHead, tx_buffered_packets_t, q);
+            tx_q_item->transmissionControl |= TRANSMISSION_CONTROL_EOSP_MASK;
+            tx_q_item->transmissionControl = (tx_q_item->transmissionControl & ~(CSR_NO_CONFIRM_REQUIRED));
+            unifi_trace(priv, UDBG1,"updating eosp for list Head hostTag:= 0x%x ",tx_q_item->hostTag);
+            break;
+        }
+        spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags);
+    }
+    func_exit();
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  resume_suspended_uapsd
+ *
+ *      This function takes care processing packets of Unscheduled Service Period,
+ *      which been suspended earlier due to DTIM/HIP ENOSPC scenarios
+ *
+ *  Arguments:
+ *      priv            Pointer to device private context struct
+ *      interfaceTag    For which resume should happen
+ * ---------------------------------------------------------------------------
+ */
+void resume_suspended_uapsd(unifi_priv_t* priv,CsrUint16 interfaceTag)
+{
+
+   CsrUint8 startIndex;
+   CsrWifiRouterCtrlStaInfo_t * staInfo = NULL;
+    unsigned long lock_flags;
+
+    unifi_trace(priv, UDBG2, "++resume_suspended_uapsd: \n");
+    for(startIndex= 0; startIndex < UNIFI_MAX_CONNECTIONS;startIndex++) {
+        staInfo =  CsrWifiRouterCtrlGetStationRecordFromHandle(priv,startIndex,interfaceTag);
+
+        if(!staInfo || !staInfo->wmmOrQosEnabled) {
+            continue;
+        } else if((staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE)
+                   &&staInfo->uapsdActive && staInfo->uspSuspend) {
+            /* U-APSD Still active & previously suspended either ENOSPC of FH queues OR
+             * due to DTIM activity
+             */
+            uf_handle_uspframes_delivery(priv, staInfo, interfaceTag);
+        } else {
+            unifi_trace(priv, UDBG2, "resume_suspended_uapsd: PS state=%x, uapsdActive?=%x, suspend?=%x\n",
+                        staInfo->currentPeerState, staInfo->uapsdActive, staInfo->uspSuspend);
+            if (staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE)
+            {
+                spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
+                staInfo->uapsdActive = FALSE;
+                staInfo->uspSuspend = FALSE;
+                spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
+            }
+        }
+    }
+    unifi_trace(priv, UDBG2, "--resume_suspended_uapsd:\n");
+}
+
+#endif
diff --git a/drivers/staging/csr/unifi_priv.h b/drivers/staging/csr/unifi_priv.h
new file mode 100644
index 0000000..b23c844
--- /dev/null
+++ b/drivers/staging/csr/unifi_priv.h
@@ -0,0 +1,1190 @@
+/*
+ *****************************************************************************
+ *
+ * FILE : unifi_priv.h
+ *
+ * PURPOSE : Private header file for unifi driver.
+ *
+ *           UDI = UniFi Debug Interface
+ *
+ * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ *****************************************************************************
+ */
+#ifndef __LINUX_UNIFI_PRIV_H__
+#define __LINUX_UNIFI_PRIV_H__ 1
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/cdev.h>
+#include <linux/kthread.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
+#include <linux/freezer.h>
+#endif
+
+#ifdef CSR_WIFI_SUPPORT_MMC_DRIVER
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#endif /* CSR_WIFI_SUPPORT_MMC_DRIVER */
+
+#include <linux/fs.h>
+
+#ifdef ANDROID_BUILD
+#include <linux/wakelock.h>
+#endif
+
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_unifi_udi.h"
+#include "csr_wifi_router_lib.h"
+#include "unifiio.h"
+#ifndef CSR_WIFI_HIP_TA_DISABLE
+#include "csr_wifi_vif_utils.h"
+#endif
+
+/* Define the unifi_priv_t before include the unifi_native.h */
+struct unifi_priv;
+typedef struct unifi_priv unifi_priv_t;
+#ifdef CSR_SUPPORT_WEXT_AP
+struct CsrWifiSmeApConfig;
+typedef struct CsrWifiSmeApConfig CsrWifiSmeApConfig_t;
+#endif
+#ifdef CSR_SUPPORT_WEXT
+#include "unifi_wext.h"
+#endif
+
+#ifdef ANDROID_BUILD
+extern struct wake_lock unifi_sdio_wake_lock;
+#endif
+
+#include "unifi_clients.h"
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#include <linux/workqueue.h>
+
+#undef INIT_WORK
+#define INIT_WORK(_work, _func)                                         \
+    do {                                                                \
+        INIT_LIST_HEAD(&(_work)->entry);                                \
+        (_work)->pending = 0;                                           \
+        PREPARE_WORK((_work), (_func), (_work));                        \
+        init_timer(&(_work)->timer);                                    \
+    } while(0)
+
+#endif  /* Linux kernel < 2.6.20 */
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#define UF_NETIF_TX_WAKE_ALL_QUEUES(_netdev)    netif_tx_wake_all_queues(_netdev)
+#define UF_NETIF_TX_START_ALL_QUEUES(_netdev)   netif_tx_start_all_queues(_netdev)
+#define UF_NETIF_TX_STOP_ALL_QUEUES(_netdev)    netif_tx_stop_all_queues(_netdev)
+#else
+#define UF_NETIF_TX_WAKE_ALL_QUEUES(_netdev)    netif_wake_queue(_netdev)
+#define UF_NETIF_TX_START_ALL_QUEUES(_netdev)   netif_start_queue(_netdev)
+#define UF_NETIF_TX_STOP_ALL_QUEUES(_netdev)    netif_stop_queue(_netdev)
+#endif  /* Linux kernel >= 2.6.27 */
+
+
+#ifdef CSR_NATIVE_LINUX
+#include "sme_native/unifi_native.h"
+#else
+#include "unifi_sme.h"
+#endif
+
+/* The device major number to use when registering the udi driver */
+#define UNIFI_NAME      "unifi"
+/*
+ * MAX_UNIFI_DEVS defines the maximum number of UniFi devices that can be present.
+ * This number should be set to the number of SDIO slots supported by the SDIO
+ * host controller on the platform.
+ * Note: If MAX_UNIFI_DEVS value changes, fw_init[] needs to be corrected in drv.c
+ */
+#define MAX_UNIFI_DEVS  2
+
+/* 802.11 Mac header offsets */
+#define MAC_HEADER_SIZE  24
+#define QOS_CONTROL_HEADER_SIZE 2
+#define HT_CONTROL_HEADER_SIZE  4
+#define QOS_DATA 0x8
+#define QOS_DATA_NULL 0xc
+#define DATA_NULL 0x04
+#define FRAME_CONTROL_ORDER_BIT 0x8000
+#define FRAME_CONTROL_TYPE_FIELD_OFFSET  2
+#define FRAME_CONTROL_SUBTYPE_FIELD_OFFSET  4
+#define IEEE802_11_FRAMETYPE_DATA 0x02
+#define IEEE802_11_FRAMETYPE_CONTROL 0x01
+#define IEEE802_11_FRAMETYPE_MANAGEMENT 0x00
+#define IEEE802_11_FRAMETYPE_RESERVED 0x03
+
+/* octet offset from start of mac header for certain fields */
+#define IEEE802_11_ADDR3_OFFSET 16
+#define IEEE802_11_SEQUENCE_CONTROL_OFFSET 22
+#define IEEE802_11_MAX_DATA_LEN 2304
+
+/* frame control (FC) masks, for frame control as 16 bit integer */
+#define IEEE802_11_FC_TO_DS_MASK 0x100
+#define IEEE802_11_FC_FROM_DS_MASK 0x200
+#define IEEE802_11_FC_MOREDATA_MASK 0x2000
+#define IEEE802_11_FC_PROTECTED_MASK 0x4000
+#define IEEE80211_FC_ORDER_MASK 0x8000
+#define IEEE80211_FC_SUBTYPE_MASK 0x00f0
+#define IEEE80211_FC_TYPE_MASK 0x000c
+#define IEEE80211_FC_PROTO_VERSION_MASK 0x0003
+
+/*  selected type and subtype combinations as in 7.1.3.1 table 1
+    For frame control as 16 bit integer, or for ls octet
+*/
+#define IEEE802_11_FC_TYPE_DATA 0x08
+#define IEEE802_11_FC_TYPE_NULL 0x48
+#define IEEE802_11_FC_TYPE_QOS_NULL 0xc8
+#define IEEE802_11_FC_TYPE_QOS_DATA 0x88
+
+#define IEEE802_11_FC_TYPE_DATA_SUBTYPE_RESERVED 0x0D
+
+/* qos control (QC) masks for qos control as 16 bit integer, or for ls octet */
+#define IEEE802_11_QC_TID_MASK 0x0f
+#define IEEE802_11_QC_A_MSDU_PRESENT 0x80
+
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND))
+#define IEEE802_11_QC_NON_TID_BITS_MASK 0xFFF0
+#endif
+
+#define CSR_WIFI_EAPOL_M4_HOST_TAG 0x50000000
+#define IEEE802_11_DATA_FRAME_MAC_HEADER_SIZE 36
+#define MAX_ACCESS_CATOGORY 4
+
+/* Time in us to check for inactivity of stations 5 mins */
+#define INACTIVITY_CHECK_INTERVAL   300000000
+/* Time in us before a station is flagged as inactive */
+#define MAX_INACTIVITY_INTERVAL     300000000
+
+
+/* Define for maximum BA session */
+#define MAX_SUPPORTED_BA_SESSIONS_TX   1
+#define MAX_SUPPORTED_BA_SESSIONS_RX   4
+
+#define MAX_BA_WIND_SIZE 64
+#define MAC_HEADER_ADDR1_OFFSET     4
+#define MAC_HEADER_ADDR2_OFFSET     10
+
+/* Define for age (in us) value for frames in MPDU reorder buffer */
+#define CSR_WIFI_BA_MPDU_FRAME_AGE_TIMEOUT  30000 /* 30 milli seconds */
+
+/* This macro used in prepare_and_add_macheader*/
+#define ADDRESS_ONE_OFFSET 20
+
+/* Defines for STA inactivity detection */
+#define     STA_INACTIVE_DETECTION_TRIGGER_THRESHOLD           1                /* in number of stations */
+#define     STA_INACTIVE_DETECTION_TIMER_INTERVAL              30               /* in seconds */
+#define     STA_INACTIVE_TIMEOUT_VAL                           120*1000*1000    /* 120 seconds */
+
+/* Test for modes requiring AP firmware patch */
+#define CSR_WIFI_HIP_IS_AP_FW(mode) ((((mode) == CSR_WIFI_ROUTER_CTRL_MODE_AP) || \
+                                      ((mode) == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO)) ? TRUE : FALSE)
+
+/* Defines used in beacon filtering in case of P2P */
+#define CSR_WIFI_P2P_WILDCARD_SSID_LENGTH        0x7
+#define CSR_WIFI_80211_FRAME_SUBTYPE_BEACON      0x8
+#define CSR_WIFI_BEACON_FIXED_LENGTH             12
+#define CSR_WIFI_FRAME_SUBTYPE_BIT_OFFSET        4
+#define CSR_WIFI_80211_FRAME_SUBTYPE_BIT_MASK    ((CsrUint8)(0xF << CSR_WIFI_FRAME_SUBTYPE_BIT_OFFSET))
+
+#define CSR_WIFI_80211_GET_FRAME_SUBTYPE(frameBuffer) \
+    ((CsrUint8)(((CsrUint8 *)frameBuffer)[0] & CSR_WIFI_80211_FRAME_SUBTYPE_BIT_MASK) >> CSR_WIFI_FRAME_SUBTYPE_BIT_OFFSET)
+
+/* For M4 request received via netdev*/
+
+typedef CsrUint8 CsrWifiPacketType;
+#define CSR_WIFI_UNICAST_PDU   ((CsrWifiPacketType) 0x00)
+#define CSR_WIFI_MULTICAST_PDU ((CsrWifiPacketType) 0x1)
+#define CSR_WIFI_BROADCAST_PDU ((CsrWifiPacketType) 0x2)
+
+#define PRIO_TO_NICE(prio)  ((prio) - MAX_RT_PRIO - 20)
+
+/* Module parameter variables */
+extern int buswidth;
+extern int sdio_clock;
+extern int use_5g;
+extern int disable_hw_reset;
+extern int disable_power_control;
+extern int enable_wol;
+extern int sme_debug;
+extern int fw_init[MAX_UNIFI_DEVS];
+extern int tl_80211d;
+extern int sdio_byte_mode;
+extern int sdio_block_size;
+extern int coredump_max;
+extern int run_bh_once;
+extern int bh_priority;
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+extern int log_hip_signals;
+#endif
+
+struct dlpriv {
+    const unsigned char *dl_data;
+    int dl_len;
+    void *fw_desc;
+};
+
+
+struct uf_thread {
+
+    struct task_struct *thread_task;
+
+    /* wait_queue for waking the unifi_thread kernel thread */
+    wait_queue_head_t wakeup_q;
+    unsigned int wakeup_flag;
+
+    /*
+     * Use it to block the I/O thread when
+     * an error occurs or UniFi is reinitialised.
+     */
+    int block_thread;
+
+    char name[16];
+    int prio;
+};
+
+/*
+ * Link list to hold the received packets for the period the port
+ * remains closed.
+ */
+typedef struct rx_buffered_packets {
+    /* List link structure */
+    struct list_head q;
+    /* Packet to indicate when the port reopens */
+    struct sk_buff *skb;
+    /* Bulkdata to free in case the port closes and need to discard the packet */
+    bulk_data_param_t bulkdata;
+    /* The source address of the packet */
+    CsrWifiMacAddress sa;
+    /* The destination address of the packet */
+    CsrWifiMacAddress da;
+    /* Corresponding signal */
+    CSR_SIGNAL signal;
+} rx_buffered_packets_t;
+
+
+typedef CsrUint8 CsrWifiAcPowersaveMode;
+#define CSR_WIFI_AC_TRIGGER_ONLY_ENABLED 0x00
+#define CSR_WIFI_AC_DELIVERY_ONLY_ENABLE 0X01
+#define CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED 0X03
+#define CSR_WIFI_AC_LEGACY_POWER_SAVE 0X02
+
+
+#define IS_DELIVERY_ENABLED(mode) (mode & CSR_WIFI_AC_DELIVERY_ONLY_ENABLE)? 1: 0
+#define IS_DELIVERY_AND_TRIGGER_ENABLED(mode) ((mode & CSR_WIFI_AC_DELIVERY_ONLY_ENABLE)||(mode & CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED))? 1: 0
+#define IS_DTIM_ACTIVE(flag,hostTag) ((flag == TRUE || hostTag != INVALID_HOST_TAG))
+#define INVALID_HOST_TAG 0xFFFFFFFF
+#define UNIFI_TRAFFIC_Q_CONTENTION UNIFI_TRAFFIC_Q_BE
+
+
+
+
+/* Queue to be used for contention priority */
+
+/*
+ * Link list to hold the tx packets for the period the peer
+ * powersave/free slots in unifi
+ */
+typedef struct tx_buffered_packets {
+    /* List link structure */
+    struct list_head q;
+    CsrUint16 interfaceTag;
+    CSR_CLIENT_TAG hostTag;
+    CSR_PROCESS_ID leSenderProcessId;
+    CSR_TRANSMISSION_CONTROL transmissionControl;
+    CSR_RATE rate;
+    /* Bulkdata to free in case the port closes and need to discard the packet */
+    bulk_data_desc_t bulkdata;
+    /* The source address of the packet */
+    CsrWifiMacAddress peerMacAddress;
+    CSR_PRIORITY priority;
+} tx_buffered_packets_t;
+
+/* station record has this data structure */
+typedef struct CsrWifiRouterCtrlStaInfo_t {
+
+    /* Sme sends these parameters */
+    CsrWifiMacAddress peerMacAddress;
+    CsrUint32 assignedHandle;
+    CsrBool wmmOrQosEnabled;
+    CsrWifiAcPowersaveMode powersaveMode[MAX_ACCESS_CATOGORY];
+    CsrUint16 maxSpLength;
+    CsrBool uapsdActive;
+    CsrUint16 noOfSpFramesSent;
+
+    /* Router/Driver database */
+#ifdef CSR_SUPPORT_SME
+    unifi_port_cfg_t *peerControlledPort;
+    unifi_port_cfg_t *peerUnControlledPort;
+
+    /* Inactivity feature parameters */
+    struct netInterface_priv *interfacePriv;
+    struct work_struct send_disconnected_ind_task;
+    CsrBool activity_flag;
+    CsrUint16 listenIntervalInTus;
+    CSR_CLIENT_TAG nullDataHostTag;
+
+    /* Activity timestamps for the station */
+    CsrTime lastActivity;
+
+    /* during m/c transmission sp suspended */
+    CsrBool uspSuspend;
+    CSR_PRIORITY triggerFramePriority;
+#endif
+    CsrWifiRouterCtrlPeerStatus currentPeerState;
+    struct list_head dataPdu[MAX_ACCESS_CATOGORY];
+    struct list_head mgtFrames;
+    CsrUint8 spStatus;
+    CsrUint8 prevFrmType;
+    CsrUint8 prevFrmAccessCatogory;
+    CsrBool protection;
+    CsrUint16 aid;
+    CsrBool txSuspend;
+    CsrUint8 timSet;
+    /* Dont change the value of below macro for SET & RESET */
+#define CSR_WIFI_TIM_RESET       0
+#define CSR_WIFI_TIM_SET         1
+#define CSR_WIFI_TIM_RESETTING   2
+#define CSR_WIFI_TIM_SETTING     3
+
+    CsrBool timRequestPendingFlag;
+    CsrUint8 updateTimReqQueued;
+    CsrUint16 noOfPktQueued;
+}CsrWifiRouterCtrlStaInfo_t;
+
+#ifdef CSR_SUPPORT_WEXT_AP
+struct CsrWifiSmeApConfig {
+    CsrWifiSsid ssid;
+    CsrUint16 channel;
+    CsrWifiNmeApCredentials credentials;
+    CsrUint8 max_connections;
+    CsrUint8 if_index;
+};
+#endif
+
+#ifdef CSR_WIFI_RX_PATH_SPLIT
+/* This is a test code and may be removed later*/
+#define CSR_WIFI_RX_SIGNAL_BUFFER_SIZE    (60+1)
+
+typedef struct
+{
+    CsrUint8 *bufptr; /* Signal Primitive */
+    bulk_data_param_t data_ptrs; /* Bulk Data pointers */
+    CsrUint16 sig_len;
+}rx_buff_struct_t;
+
+typedef struct
+{
+    CsrUint8 writePointer; /**< write pointer */
+    CsrUint8 readPointer;  /**< read pointer */
+    CsrUint8 size;         /**< size of circular buffer */
+    rx_buff_struct_t rx_buff[CSR_WIFI_RX_SIGNAL_BUFFER_SIZE];    /**< Element of ciruclar buffer */
+} rxCircularBuffer_t;
+
+void rx_wq_handler(struct work_struct *work);
+#endif
+
+struct unifi_priv {
+
+    card_t *card;
+    CsrSdioFunction *sdio;
+
+    /* Index into Unifi_instances[] for this device. */
+    int instance;
+    /* Reference count for this instance */
+    int ref_count;
+
+    /* Firmware images */
+    struct dlpriv fw_sta;
+    struct dlpriv fw_conv;  /* used for conversion of production test image */
+
+    /* Char device related structures */
+    struct cdev unifi_cdev;
+    struct cdev unifiudi_cdev;
+    struct device *unifi_device;
+
+    /* Which wireless interface to use (1 - 2.4GHz, 2 - 5GHz) */
+    CSR_IFINTERFACE if_index;
+
+    /* For multiple interface support */
+    struct net_device *netdev[CSR_WIFI_NUM_INTERFACES];
+    struct netInterface_priv *interfacePriv[CSR_WIFI_NUM_INTERFACES];
+
+    CsrUint8 totalInterfaceCount;
+
+    int prev_queue;
+
+    /* Name of node under /proc */
+    char proc_entry_name[64];
+
+    /*
+     * Flags:
+     *  drop_unencrypted
+     *                - Not used?
+     *  netdev_registered
+     *                - whether the netdev has been registered.
+     */
+    unsigned int drop_unencrypted       : 1;
+
+    /* Our list of unifi linux clients. */
+    ul_client_t ul_clients[MAX_UDI_CLIENTS];
+
+    /* Mutex to protect using the logging hook after UDI client is gone */
+    struct semaphore udi_logging_mutex;
+    /* Pointer to the ul_clients[] array */
+    ul_client_t *logging_client;
+
+    /* A ul_client_t* used to send the netdev related MIB requests. */
+    ul_client_t *netdev_client;
+
+    /* The SME ul_client_t pointer. */
+    ul_client_t *sme_cli;
+
+    /* The AMP ul_client_t pointer. */
+    ul_client_t *amp_client;
+
+    /*
+     * Semaphore for locking the top-half to one user process.
+     * This is necessary to prevent multiple processes calling driver
+     * operations. This can happen because the network driver entry points
+     * can be called from multiple processes.
+     */
+#ifdef USE_DRIVER_LOCK
+    struct semaphore lock;
+#endif /* USE_DRIVER_LOCK */
+
+    /* Flag to say that an operation was aborted */
+    int io_aborted;
+
+    struct uf_thread bh_thread;
+
+#define UNIFI_INIT_NONE         0x00
+#define UNIFI_INIT_IN_PROGRESS  0x01
+#define UNIFI_INIT_FW_DOWNLOADED 0x02
+#define UNIFI_INIT_COMPLETED    0x04
+    unsigned char init_progress;
+
+    int sme_is_present;
+
+    /* The WMM features that UniFi uses in the current BSS */
+    unsigned int sta_wmm_capabilities;
+
+    /* Debug only */
+    char last_debug_string[256];
+    unsigned short last_debug_word16[16];
+
+#ifdef CSR_SUPPORT_SME
+  /* lock to protect the tx queues list */
+    spinlock_t tx_q_lock;
+    CsrUint8 allPeerDozing;
+    CsrUint8 pausedStaHandle[MAX_ACCESS_CATOGORY];
+    /* Max packet the driver can queue, irrespective of interface number */
+    CsrUint16 noOfPktQueuedInDriver;
+#define CSR_WIFI_DRIVER_SUPPORT_FOR_MAX_PKT_QUEUEING 512
+#define CSR_WIFI_DRIVER_MAX_PKT_QUEUING_THRESHOLD_PER_PEER 64
+#define CSR_WIFI_DRIVER_MINIMUM_BROADCAST_PKT_THRESHOLD 3
+
+    CsrBool routerBufferEnable[MAX_ACCESS_CATOGORY];
+    /* lock to protect stainfo members and priv members*/
+    spinlock_t staRecord_lock;
+#endif
+#ifdef CSR_NATIVE_LINUX
+#ifdef CSR_SUPPORT_WEXT
+    /* wireless config */
+    struct wext_config wext_conf;
+#endif
+
+    /* Mutex to protect the MLME blocking requests */
+    struct semaphore mlme_blocking_mutex;
+
+    /* The ul_client that provides the blocking API for WEXT calls */
+    ul_client_t *wext_client;
+
+#endif /* CSR_NATIVE_LINUX */
+
+#ifdef CSR_SUPPORT_SME
+    wait_queue_head_t sme_request_wq;
+    /* Semaphore to protect the SME blocking requests */
+    struct semaphore sme_sem;
+    /* Structure to hold the SME blocking requests data*/
+    sme_reply_t sme_reply;
+
+    /* Structure to hold a traffic protocol indication */
+    struct ta_ind {
+        struct work_struct task;
+        CsrWifiRouterCtrlTrafficPacketType packet_type;
+        CsrWifiRouterCtrlProtocolDirection direction;
+        CsrWifiMacAddress src_addr;
+        int in_use;
+    } ta_ind_work;
+
+    struct ta_sample_ind {
+        struct work_struct task;
+        CsrWifiRouterCtrlTrafficStats stats;
+        int in_use;
+    } ta_sample_ind_work;
+
+    __be32 sta_ip_address;
+    CsrWifiRouterCtrlSmeVersions    sme_versions;
+
+    /*
+     * Flag to reflect state of unifi_sys_wifi_on_*() progress.
+     * This indicates whether we are in an "wifi on" state when we are
+     * allowed to indication errors with unifi_mgt_wifi_off_ind()
+     */
+    enum {
+        wifi_on_unspecified = -1,
+        wifi_on_in_progress = 0,
+        wifi_on_done = 1,
+    } wifi_on_state;
+
+    /* Userspace TaskId for the SME Set when a wifi on req is received */
+    CsrSchedQid CSR_WIFI_SME_IFACEQUEUE;
+
+    struct work_struct multicast_list_task;
+    /*
+     * The SME installs filters to ask for specific MA-UNITDATA.req
+     * to be passed to different SME components.
+     */
+#define MAX_MA_UNIDATA_IND_FILTERS      8
+    sme_ma_unidata_ind_filter_t sme_unidata_ind_filters[MAX_MA_UNIDATA_IND_FILTERS];
+
+/* UNIFI_CFG related parameters */
+    uf_cfg_bcast_packet_filter_t packet_filters;
+    unsigned char *filter_tclas_ies;
+ /* The structure that holds all the connection configuration. */
+    CsrWifiSmeConnectionConfig connection_config;
+#ifdef CSR_SUPPORT_WEXT
+
+    int ignore_bssid_join;
+    struct iw_statistics wext_wireless_stats;
+
+    /* The MIB and MAC address files contents, read from userspace */
+    CsrWifiSmeDataBlock mib_data;
+    CsrWifiMacAddress sta_mac_address;
+
+    int wep_tx_key_index;
+    wep_key_t wep_keys[NUM_WEPKEYS];
+
+
+#ifdef CSR_SUPPORT_WEXT_AP
+    CsrWifiSmeApMacConfig ap_mac_config;
+    CsrWifiNmeApConfig group_sec_config;
+    CsrWifiSmeApConfig_t ap_config;
+#endif
+    struct work_struct sme_config_task;
+
+#endif /* CSR_SUPPORT_WEXT */
+
+#endif /* CSR_SUPPORT_SME */
+
+#ifdef CSR_SME_USERSPACE
+    void *smepriv;
+#endif /* CSR_SME_USERSPACE */
+
+    card_info_t card_info;
+
+    /* Mutex to protect unifi_send_signal() */
+    spinlock_t send_signal_lock;
+
+
+    /*
+     * The workqueue to offload the TA run
+     * and the multicast addresses list set
+     */
+    struct workqueue_struct *unifi_workqueue;
+
+    unsigned char *mib_cfm_buffer;
+    unsigned int mib_cfm_buffer_length;
+
+    int ptest_mode;     /* Set when in production test mode */
+    int coredump_mode;  /* Set when SME has requested a coredump */
+    CsrBool wol_suspend; /* Set when suspending with UniFi powered */
+
+#define UF_UNCONTROLLED_PORT_Q      0
+#define UF_CONTROLLED_PORT_Q        1
+
+    /* Semaphore to protect the rx queues list */
+    struct semaphore rx_q_sem;
+
+    /* Spinlock to protect M4 data */
+    spinlock_t m4_lock;
+    /* Mutex to protect BA RX data */
+    struct semaphore ba_mutex;
+
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
+    /* Spinlock to protect the WAPI data */
+    spinlock_t wapi_lock;
+#endif
+
+#ifndef ALLOW_Q_PAUSE
+    /* Array to indicate if a particular Tx queue is paused, this may not be
+     * required in a multiqueue implementation since we can directly stop kernel
+     * queues */
+    CsrUint8 tx_q_paused_flag[UNIFI_TRAFFIC_Q_MAX];
+#endif
+
+#ifdef CSR_WIFI_RX_PATH_SPLIT
+    struct workqueue_struct *rx_workqueue;
+    struct work_struct rx_work_struct;
+    rxCircularBuffer_t rxSignalBuffer;
+
+#endif
+
+    CsrUint32 rxTcpThroughput;
+    CsrUint32 txTcpThroughput;
+    CsrUint32 rxUdpThroughput;
+    CsrUint32 txUdpThroughput;
+
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+    /*Set if multicast KeyID = 1*/
+    CsrUint8 wapi_multicast_filter;
+    /*Set if unicast KeyID = 1*/
+    CsrUint8 wapi_unicast_filter;
+    CsrUint8 wapi_unicast_queued_pkt_filter;
+#ifdef CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND
+    CsrBool  isWapiConnection;
+#endif
+#endif
+
+#ifdef CSR_WIFI_SPLIT_PATCH
+    CsrWifiRouterCtrlModeSetReq pending_mode_set;
+#endif
+
+    CsrBool cmanrTestMode;
+    CSR_RATE cmanrTestModeTransmitRate;
+
+};
+
+typedef struct {
+    CsrUint16 queue_length[4];
+    CsrUint8 os_queue_paused;
+} unifi_OsQosInfo;
+
+
+typedef struct {
+    CsrBool active;
+    bulk_data_param_t bulkdata;
+    CSR_SIGNAL signal;
+    CsrUint16 sn;
+    CsrTime recv_time;
+} frame_desc_struct;
+
+typedef struct {
+    frame_desc_struct *buffer;
+    CsrUint16 wind_size;
+    CsrUint16 occupied_slots;
+    struct timer_list timer;
+    CsrUint16 timeout;
+    CsrUint16 expected_sn;
+    CsrUint16 start_sn;
+    CsrBool   trigger_ba_after_ssn;
+    struct netInterface_priv *interfacePriv;
+    CsrUint16 tID;
+    CsrWifiMacAddress macAddress;
+    struct work_struct send_ba_err_task;
+} ba_session_rx_struct;
+
+
+typedef struct {
+    struct netInterface_priv *interfacePriv;
+    CsrUint16 tID;
+    CsrWifiMacAddress macAddress;
+} ba_session_tx_struct;
+
+typedef struct netInterface_priv
+{
+    CsrUint16 InterfaceTag;
+    struct unifi_priv *privPtr;
+    ba_session_tx_struct *ba_session_tx[MAX_SUPPORTED_BA_SESSIONS_TX];
+    ba_session_rx_struct *ba_session_rx[MAX_SUPPORTED_BA_SESSIONS_RX];
+    frame_desc_struct ba_complete[MAX_BA_WIND_SIZE];
+    CsrUint8 ba_complete_index;
+    CsrUint8 queueEnabled[UNIFI_NO_OF_TX_QS];
+    struct work_struct send_m4_ready_task;
+#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE
+    struct work_struct send_pkt_to_encrypt;
+#endif
+    struct net_device_stats stats;
+    CsrUint8 interfaceMode;
+    CsrBool protect;
+    CsrWifiMacAddress bssid;
+    /*
+    * Flag to reflect state of CONNECTED indication signal.
+    * This indicates whether we are "joined" an Access Point (i.e. have
+    * nominated an AP and are receiving beacons) but give no indication
+    * of whether we are authenticated and/or associated.
+    */
+    enum {
+        UnifiConnectedUnknown = -1,
+        UnifiNotConnected = 0,
+        UnifiConnected = 1,
+    } connected;
+#ifdef CSR_SUPPORT_WEXT
+    /* Tracks when we are waiting for a netdevice state change callback */
+    CsrBool wait_netdev_change;
+    /* True if we have successfully registered for netdev callbacks */
+    CsrBool netdev_callback_registered;
+#endif /* CSR_SUPPORT_WEXT */
+    unsigned int netdev_registered;
+#define UNIFI_MAX_MULTICAST_ADDRESSES 10
+    /* The multicast addresses list that the thread needs to set. */
+    u8 mc_list[UNIFI_MAX_MULTICAST_ADDRESSES*ETH_ALEN];
+    /* The multicast addresses count that the thread needs to set. */
+    int mc_list_count;
+    CsrUint32 tag;
+#ifdef CSR_SUPPORT_SME
+    /* (un)controlled port configuration */
+    unifi_port_config_t controlled_data_port;
+    unifi_port_config_t uncontrolled_data_port;
+
+    /* station record maintenance related data structures */
+    CsrUint8 num_stations_joined;
+    CsrWifiRouterCtrlStaInfo_t *(staInfo)[UNIFI_MAX_CONNECTIONS];
+    struct list_head genericMgtFrames;
+    struct list_head genericMulticastOrBroadCastFrames;
+    struct list_head genericMulticastOrBroadCastMgtFrames;
+
+    /* Timer for detecting station inactivity */
+    struct timer_list sta_activity_check_timer;
+    CsrBool sta_activity_check_enabled;
+
+    /* Timestamp when the last inactivity check was done */
+    CsrTime last_inactivity_check;
+
+    /*number of multicast or borad cast packets  queued*/
+    CsrUint16 noOfbroadcastPktQueued;
+#endif
+    /* A list to hold the buffered uncontrolled port packets */
+    struct list_head rx_uncontrolled_list;
+    /* A list to hold the buffered controlled port packets */
+    struct list_head rx_controlled_list;
+    /* Buffered M4 signal to take care of WPA race condition */
+    CSR_SIGNAL m4_signal;
+    bulk_data_desc_t m4_bulk_data;
+
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
+    /* Buffered WAPI Unicast MA Packet Request for encryption in Sme */
+    CSR_SIGNAL wapi_unicast_ma_pkt_sig;
+    bulk_data_desc_t wapi_unicast_bulk_data;
+#endif
+
+    /* This should be removed and m4_hostTag should be used for checking*/
+    CsrBool m4_sent;
+    CSR_CLIENT_TAG m4_hostTag;
+    CsrBool dtimActive;
+    CsrBool intraBssEnabled;
+    CsrUint32 multicastPduHostTag; /* Used to set the tim after getting
+       a confirm for it */
+    CsrBool bcTimSet;
+    CsrBool bcTimSetReqPendingFlag;
+    CsrBool bcTimSetReqQueued;
+} netInterface_priv_t;
+
+#ifndef ALLOW_Q_PAUSE
+#define net_is_tx_q_paused(priv, q)   (priv->tx_q_paused_flag[q])
+#define net_tx_q_unpause(priv, q)   (priv->tx_q_paused_flag[q] = 0)
+#define net_tx_q_pause(priv, q)   (priv->tx_q_paused_flag[q] = 1)
+#endif
+
+#ifdef CSR_SUPPORT_SME
+#define routerStartBuffering(priv,queue) priv->routerBufferEnable[(queue)] = TRUE;
+#define routerStopBuffering(priv,queue) priv->routerBufferEnable[(queue)]  = FALSE;
+#define isRouterBufferEnabled(priv,queue) priv->routerBufferEnable[(queue)]
+#endif
+
+#ifdef USE_DRIVER_LOCK
+#define LOCK_DRIVER(_p)         down_interruptible(&(_p)->lock)
+#define UNLOCK_DRIVER(_p)       up(&(_p)->lock)
+#else
+#define LOCK_DRIVER(_p)         (void)(_p); /* as nothing */
+#define UNLOCK_DRIVER(_p)       (void)(_p); /* as nothing */
+#endif /* USE_DRIVER_LOCK */
+
+CsrInt32 CsrHipResultToStatus(CsrResult csrResult);
+
+
+/*
+ * SDIO related functions and callbacks
+ */
+int  uf_sdio_load(void);
+void uf_sdio_unload(void);
+unifi_priv_t *uf_find_instance(int inst);
+int uf_find_priv(unifi_priv_t *priv);
+int uf_find_netdev_priv(netInterface_priv_t *priv);
+unifi_priv_t *uf_get_instance(int inst);
+void uf_put_instance(int inst);
+int csr_sdio_linux_install_irq(CsrSdioFunction *sdio);
+int csr_sdio_linux_remove_irq(CsrSdioFunction *sdio);
+
+void uf_add_os_device(int bus_id, struct device *os_device);
+void uf_remove_os_device(int bus_id);
+
+
+
+/*
+ * Claim/release SDIO
+ *
+ * For multifunction cards, we cannot grub the SDIO lock around the unifi_bh()
+ * as this prevents other functions using SDIO.
+ * Since some of CSR SDIO API is used regardless of trying to lock unifi_bh()
+ * we have followed this scheme:
+ * 1. If a function needs protection only when CSR_WIFI_SINGLE_FUNCTION is defined
+ *    then we call CsrSdioClaim/CsrSdioRelease().
+ * 2. If a function needs protection only when CSR_WIFI_SINGLE_FUNCTION is not defined
+ *    then we call _sdio_claim_host/_sdio_claim_host(). Use of this should be restricted
+ *    to the SDIO glue layer only (e.g. sdio_mmc.c).
+ * 3. If a function needs protection, regardless of the CSR_WIFI_SINGLE_FUNCTION
+ *    then we call directly the sdio_claim_host/sdio_release_host().
+ *    Use of this must be restricted to the SDIO glue layer only (e.g. sdio_mmc.c).
+ *
+ * Note: The _func and function pointers are _not_ the same.
+ * The former is the (struct sdio_func*) context, which restricts the use to the SDIO glue layer.
+ * The latter is the (CsrSdioFunction*) context, which allows calls from all layers.
+ */
+
+#ifdef CSR_WIFI_SUPPORT_MMC_DRIVER
+
+#ifdef CSR_WIFI_SINGLE_FUNCTION
+#define CsrSdioClaim(function)    sdio_claim_host((function)->priv);
+#define CsrSdioRelease(function)  sdio_release_host((function)->priv);
+
+#define _sdio_claim_host(_func)
+#define _sdio_release_host(_func)
+
+#else
+#define CsrSdioClaim(function)
+#define CsrSdioRelease(function)
+
+#define _sdio_claim_host(_func)     sdio_claim_host(_func)
+#define _sdio_release_host(_func)   sdio_release_host(_func)
+
+#endif /* CSR_WIFI_SINGLE_FUNCTION */
+
+#else
+#define _sdio_claim_host(_func)
+#define _sdio_release_host(_func)
+
+#define CsrSdioClaim(function)
+#define CsrSdioRelease(function)
+
+#endif /* CSR_WIFI_SUPPORT_MMC_DRIVER */
+
+
+/*
+ * Functions to allocate and free an ethernet device.
+ */
+unifi_priv_t *uf_alloc_netdevice(CsrSdioFunction *sdio_dev, int bus_id);
+int uf_free_netdevice(unifi_priv_t *priv);
+
+/* Allocating function for other interfaces */
+CsrBool uf_alloc_netdevice_for_other_interfaces(unifi_priv_t *priv, CsrUint16 interfaceTag);
+
+/*
+ * Firmware download related functions.
+ */
+int uf_run_unifihelper(unifi_priv_t *priv);
+int uf_request_firmware_files(unifi_priv_t *priv, int is_fw);
+int uf_release_firmware_files(unifi_priv_t *priv);
+int uf_release_firmware(unifi_priv_t *priv, struct dlpriv *to_free);
+
+/*
+ * Functions to create and delete the device nodes.
+ */
+int uf_create_device_nodes(unifi_priv_t *priv, int bus_id);
+void uf_destroy_device_nodes(unifi_priv_t *priv);
+
+/*
+ * Upper Edge Initialisation functions
+ */
+int uf_init_bh(unifi_priv_t *priv);
+int uf_init_hw(unifi_priv_t *priv);
+
+/* Thread related helper functions */
+int uf_start_thread(unifi_priv_t *priv, struct uf_thread *thread, int (*func)(void *));
+void uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread);
+void uf_wait_for_thread_to_stop(unifi_priv_t *priv, struct uf_thread *thread);
+
+
+/*
+ * Unifi Linux functions
+ */
+void ul_init_clients(unifi_priv_t *priv);
+
+/* Configuration flags */
+#define CLI_USING_WIRE_FORMAT   0x0002
+#define CLI_SME_USERSPACE       0x0020
+ul_client_t *ul_register_client(unifi_priv_t *priv,
+        unsigned int configuration,
+        udi_event_t udi_event_clbk);
+int ul_deregister_client(ul_client_t *pcli);
+
+int ul_send_signal_unpacked(unifi_priv_t *priv,
+                            CSR_SIGNAL *sigptr,
+                            bulk_data_param_t *bulkdata);
+int ul_send_signal_raw(unifi_priv_t *priv,
+                       unsigned char *sigptr, int siglen,
+                       bulk_data_param_t *bulkdata);
+
+void ul_log_config_ind(unifi_priv_t *priv, u8 *conf_param, int len);
+
+
+/*
+ * Data plane operations
+ */
+/*
+ *      data_tx.c
+ */
+int uf_verify_m4(unifi_priv_t *priv, const unsigned char *packet,
+        unsigned int length);
+
+#ifdef CSR_SUPPORT_SME
+CsrBool uf_check_broadcast_bssid(unifi_priv_t *priv, const bulk_data_param_t *bulkdata);
+CsrBool uf_process_pm_bit_for_peer(unifi_priv_t * priv, CsrWifiRouterCtrlStaInfo_t * srcStaInfo,CsrUint8 pmBit,CsrUint16 interfaceTag);
+void uf_process_ps_poll(unifi_priv_t *priv,CsrUint8* sa,CsrUint8* da,CsrUint8 pmBit,CsrUint16 interfaceTag);
+int uf_ap_process_data_pdu(unifi_priv_t *priv, struct sk_buff *skb,
+                   struct ethhdr *ehdr, CsrWifiRouterCtrlStaInfo_t * srcStaInfo,
+                   const CSR_SIGNAL *signal,
+                   bulk_data_param_t *bulkdata,
+                   CsrUint8 macHeaderLengthInBytes);
+CsrBool uf_is_more_data_for_non_delivery_ac(CsrWifiRouterCtrlStaInfo_t *staRecord);
+void uf_process_wmm_deliver_ac_uapsd (  unifi_priv_t * priv,
+                                        CsrWifiRouterCtrlStaInfo_t * srcStaInfo,
+                                        CsrUint16 qosControl,
+                                        CsrUint16 interfaceTag);
+
+void uf_send_buffered_data_from_ac(unifi_priv_t *priv, CsrWifiRouterCtrlStaInfo_t * staInfo, CsrUint8 queue, struct list_head *txList);
+void uf_send_buffered_data_from_delivery_ac(unifi_priv_t *priv, CsrWifiRouterCtrlStaInfo_t * staInfo, CsrUint8 queue, struct list_head *txList);
+
+void uf_continue_uapsd(unifi_priv_t *priv, CsrWifiRouterCtrlStaInfo_t * staInfo);
+void uf_send_qos_null(unifi_priv_t * priv,CsrUint16 interfaceTag, const CsrUint8 *da,CSR_PRIORITY priority,CsrWifiRouterCtrlStaInfo_t * srcStaInfo);
+void uf_send_nulldata(unifi_priv_t * priv,CsrUint16 interfaceTag, const CsrUint8 *da,CSR_PRIORITY priority,CsrWifiRouterCtrlStaInfo_t * srcStaInfo);
+
+
+
+#endif
+CsrResult uf_process_ma_packet_req(unifi_priv_t *priv,  CsrUint8 *peerMacAddress, CSR_CLIENT_TAG hostTag, CsrUint16 interfaceTag, CSR_TRANSMISSION_CONTROL transmissionControl, CSR_RATE TransmitRate, CSR_PRIORITY priority, CSR_PROCESS_ID senderId, bulk_data_param_t *bulkdata);
+void uf_process_ma_vif_availibility_ind(unifi_priv_t *priv,CsrUint8 *sigdata, CsrUint32 siglen);
+#ifdef CSR_SUPPORT_SME
+void uf_send_buffered_frames(unifi_priv_t *priv,unifi_TrafficQueue queue);
+int uf_process_station_records_for_sending_data(unifi_priv_t *priv,CsrUint16 interfaceTag,
+                                                 CsrWifiRouterCtrlStaInfo_t *srcStaInfo,
+                                                 CsrWifiRouterCtrlStaInfo_t *dstStaInfo);
+void uf_prepare_send_cfm_list_for_queued_pkts(unifi_priv_t * priv,
+                                                 struct list_head *frames_need_cfm_list,
+                                                 struct list_head * list);
+void send_auto_ma_packet_confirm(unifi_priv_t *priv,
+                                 netInterface_priv_t *interfacePriv,
+                                 struct list_head *buffered_frames_list);
+void uf_flush_list(unifi_priv_t * priv, struct list_head * list);
+tx_buffered_packets_t *dequeue_tx_data_pdu(unifi_priv_t *priv, struct list_head *txList);
+void resume_unicast_buffered_frames(unifi_priv_t *priv, CsrUint16 interfaceTag);
+void update_eosp_to_head_of_broadcast_list_head(unifi_priv_t *priv,CsrUint16 interfaceTag);
+void resume_suspended_uapsd(unifi_priv_t* priv,CsrUint16 interfaceTag);
+#endif
+/*
+ *      netdev.c
+ */
+
+#ifndef P80211_OUI_LEN
+#define P80211_OUI_LEN  3
+#endif
+typedef struct {
+    u8    dsap;   /* always 0xAA */
+    u8    ssap;   /* always 0xAA */
+    u8    ctrl;   /* always 0x03 */
+    u8    oui[P80211_OUI_LEN];    /* organizational universal id */
+    u16 protocol;
+} __attribute__ ((packed)) llc_snap_hdr_t;
+int skb_add_llc_snap(struct net_device *dev, struct sk_buff *skb, int proto);
+int skb_80211_to_ether(unifi_priv_t *priv, struct sk_buff *skb,
+        const unsigned char *daddr, const unsigned char *saddr,
+        const CSR_SIGNAL *signal,
+        bulk_data_param_t *bulkdata);
+
+const char *result_code_str(int result);
+
+
+/* prepares & appends the Mac header for the payload */
+int prepare_and_add_macheader(unifi_priv_t *priv,
+                              struct sk_buff *skb,
+                              struct sk_buff *newSkb,
+                              CSR_PRIORITY priority,
+                              bulk_data_param_t *bulkdata,
+                              CsrUint16 interfaceTag,
+                              const CsrUint8 *daddr,
+                              const CsrUint8 *saddr,
+                              CsrBool protection);
+CSR_PRIORITY
+get_packet_priority(unifi_priv_t *priv, struct sk_buff *skb, const struct ethhdr *ehdr, netInterface_priv_t *interfacePriv);
+
+void
+unifi_frame_ma_packet_req(unifi_priv_t *priv, CSR_PRIORITY priority,
+                          CSR_RATE TransmitRate, CSR_CLIENT_TAG hostTag,
+                          CsrUint16 interfaceTag, CSR_TRANSMISSION_CONTROL transmissionControl,
+                          CSR_PROCESS_ID leSenderProcessId, CsrUint8 *peerMacAddress,
+                          CSR_SIGNAL *signal);
+
+
+/* Pack the LSB to include station handle & status of tim set */
+#define CSR_WIFI_PACK_SENDER_ID_LSB_FOR_TIM_REQ(handle, timState)  ((handle << 2) | timState)
+/* get the station record handle from the sender ID */
+#define CSR_WIFI_GET_STATION_HANDLE_FROM_RECEIVER_ID(receiverProcessId) (CsrUint8) ((receiverProcessId & 0xff) >> 2)
+/* get the timSet status from the sender ID */
+#define CSR_WIFI_GET_TIMSET_STATE_FROM_RECEIVER_ID(receiverProcessId)  (CsrUint8) (receiverProcessId & 0x03)
+
+/* handle is 6 bits to accomodate in senderId LSB (only 64 station can be associated) */
+#define CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE 0x3F
+
+void update_tim(unifi_priv_t * priv, CsrUint16 aid, CsrUint8 setTim, CsrUint16 interfaceTag, CsrUint32 handle);
+void uf_handle_tim_cfm(unifi_priv_t *priv, CSR_MLME_SET_TIM_CONFIRM *cfm, CsrUint16 senderProcessId);
+
+/* Clear the Peer station Record, in case of wifioff/unexpected card removal */
+void CsrWifiRouterCtrlInterfaceReset(unifi_priv_t *priv, CsrUint16 interfaceTag);
+
+void scroll_ba_window(unifi_priv_t *priv,
+                      netInterface_priv_t *interfacePriv,
+                      ba_session_rx_struct *ba_session,
+                      CsrUint16 sn);
+
+CsrBool blockack_session_stop(unifi_priv_t *priv,
+                              CsrUint16 interfaceTag,
+                              CsrWifiRouterCtrlBlockAckRole role,
+                              CsrUint16 tID,
+                              CsrWifiMacAddress macAddress);
+#ifdef CSR_SUPPORT_SME
+/* Fetch the protection information from interface Mode */
+CsrInt8 uf_get_protection_bit_from_interfacemode(unifi_priv_t *priv, CsrUint16 interfaceTag, const CsrUint8 *daddr);
+#endif
+
+/* Fetch the station record handler from data base for matching Mac address */
+#ifdef CSR_SUPPORT_SME
+CsrWifiRouterCtrlStaInfo_t *CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(unifi_priv_t *priv,
+                                                                                const CsrUint8 *peerMacAddress,
+                                                                                CsrUint16 interfaceTag);
+
+/* Fetch the station record handler from data base for matching handle */
+CsrWifiRouterCtrlStaInfo_t * CsrWifiRouterCtrlGetStationRecordFromHandle(unifi_priv_t *priv,
+                                                                 CsrUint32 handle,
+                                                                 CsrUint16 interfaceTag);
+
+void uf_update_sta_activity(unifi_priv_t *priv, CsrUint16 interfaceTag, const CsrUint8 *peerMacAddress);
+void uf_process_ma_pkt_cfm_for_ap(unifi_priv_t *priv,CsrUint16 interfaceTag, const CSR_MA_PACKET_CONFIRM *pkt_cfm);
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+int uf_install_qdisc(struct net_device *dev);
+#endif
+
+void uf_resume_data_plane(unifi_priv_t *priv, int queue,
+                          CsrWifiMacAddress peer_address,
+                          CsrUint16 interfaceTag);
+void uf_free_pending_rx_packets(unifi_priv_t *priv, int queue,
+        CsrWifiMacAddress peer_address,CsrUint16 interfaceTag);
+
+int uf_register_netdev(unifi_priv_t *priv, int numOfInterface);
+void uf_unregister_netdev(unifi_priv_t *priv);
+
+void uf_net_get_name(struct net_device *dev, char *name, int len);
+
+void uf_send_queue_info(unifi_priv_t *priv);
+CsrUint16 uf_get_vif_identifier(CsrWifiRouterCtrlMode mode, CsrUint16 tag);
+
+void uf_process_rx_pending_queue(unifi_priv_t *priv, int queue,
+                                 CsrWifiMacAddress source_address,
+                                 int indicate, CsrUint16 interfaceTag);
+
+#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
+int uf_register_hip_offline_debug(unifi_priv_t *priv);
+int uf_unregister_hip_offline_debug(unifi_priv_t *priv);
+#endif
+
+/*
+ *      inet.c
+ */
+void uf_register_inet_notifier(void);
+void uf_unregister_inet_notifier(void);
+
+
+/*
+ * Suspend / Resume handlers
+ */
+void unifi_resume(void *ospriv);
+void unifi_suspend(void *ospriv);
+
+
+#define QOS_CAPABILITY_WMM_ENABLED      0x0001
+#define QOS_CAPABILITY_WMM_UAPSD        0x0002
+#define QOS_CAPABILITY_ACM_BE_ENABLED   0x0010
+#define QOS_CAPABILITY_ACM_BK_ENABLED   0x0020
+#define QOS_CAPABILITY_ACM_VI_ENABLED   0x0040
+#define QOS_CAPABILITY_ACM_VO_ENABLED   0x0080
+#define QOS_CAPABILITY_TS_BE_ENABLED    0x0100
+#define QOS_CAPABILITY_TS_BK_ENABLED    0x0200
+#define QOS_CAPABILITY_TS_VI_ENABLED    0x0400
+#define QOS_CAPABILITY_TS_VO_ENABLED    0x0800
+
+
+/* EAPOL PDUS */
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888e
+#endif
+#ifndef ETH_P_WAI
+#define ETH_P_WAI 0x88b4
+#endif
+/*
+ * unifi_dbg.c
+ */
+void debug_string_indication(unifi_priv_t *priv,
+        const unsigned char *extra,
+        unsigned int extralen);
+void debug_word16_indication(unifi_priv_t *priv, const CSR_SIGNAL *sigptr);
+void debug_generic_indication(unifi_priv_t *priv, const CSR_SIGNAL *sigptr);
+
+
+/*
+ * putest.c
+ */
+int unifi_putest_start(unifi_priv_t *priv, unsigned char *arg);
+int unifi_putest_cmd52_block_read(unifi_priv_t *priv, unsigned char *arg);
+int unifi_putest_stop(unifi_priv_t *priv, unsigned char *arg);
+int unifi_putest_set_sdio_clock(unifi_priv_t *priv, unsigned char *arg);
+int unifi_putest_cmd52_read(unifi_priv_t *priv, unsigned char *arg);
+int unifi_putest_coredump_prepare(unifi_priv_t *priv, unsigned char *arg);
+int unifi_putest_cmd52_write(unifi_priv_t *priv, unsigned char *arg);
+int unifi_putest_gp_read16(unifi_priv_t *priv, unsigned char *arg);
+int unifi_putest_gp_write16(unifi_priv_t *priv, unsigned char *arg);
+
+int unifi_putest_dl_fw(unifi_priv_t *priv, unsigned char *arg);
+int unifi_putest_dl_fw_buff(unifi_priv_t *priv, unsigned char *arg);
+
+
+/* Macro for formatting a MAC address with a prefix string */
+#define UF_TRACE_MAC(priv, lvl, msg, addr) \
+        unifi_trace(priv, lvl, \
+                                "%s %02x-%02x-%02x-%02x-%02x-%02x\n", \
+                                msg,    \
+                                *(((CsrUint8 *)addr)+0),  \
+                                *(((CsrUint8 *)addr)+1),  \
+                                *(((CsrUint8 *)addr)+2),  \
+                                *(((CsrUint8 *)addr)+3),  \
+                                *(((CsrUint8 *)addr)+4),  \
+                                *(((CsrUint8 *)addr)+5))
+
+#endif /* __LINUX_UNIFI_PRIV_H__ */
diff --git a/drivers/staging/csr/unifi_sme.c b/drivers/staging/csr/unifi_sme.c
new file mode 100644
index 0000000..54414ed
--- /dev/null
+++ b/drivers/staging/csr/unifi_sme.c
@@ -0,0 +1,1244 @@
+/*
+ * ***************************************************************************
+ *  FILE:     unifi_sme.c
+ *
+ *  PURPOSE:    SME related functions.
+ *
+ *  Copyright (C) 2007-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ***************************************************************************
+ */
+
+#include "unifi_priv.h"
+#include "csr_wifi_hip_unifi.h"
+#include "csr_wifi_hip_conversions.h"
+
+
+
+
+    int
+convert_sme_error(CsrResult error)
+{
+    switch (error) {
+        case CSR_RESULT_SUCCESS:
+            return 0;
+        case CSR_RESULT_FAILURE:
+        case CSR_WIFI_RESULT_NOT_FOUND:
+        case CSR_WIFI_RESULT_TIMED_OUT:
+        case CSR_WIFI_RESULT_CANCELLED:
+        case CSR_WIFI_RESULT_UNAVAILABLE:
+            return -EIO;
+        case CSR_WIFI_RESULT_NO_ROOM:
+            return -EBUSY;
+        case CSR_WIFI_RESULT_INVALID_PARAMETER:
+            return -EINVAL;
+        case CSR_WIFI_RESULT_UNSUPPORTED:
+            return -EOPNOTSUPP;
+        default:
+            return -EIO;
+    }
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  sme_log_event
+ *
+ *      Callback function to be registered as the SME event callback.
+ *      Copies the signal content into a new udi_log_t struct and adds
+ *      it to the read queue for the SME client.
+ *
+ *  Arguments:
+ *      arg             This is the value given to unifi_add_udi_hook, in
+ *                      this case a pointer to the client instance.
+ *      signal          Pointer to the received signal.
+ *      signal_len      Size of the signal structure in bytes.
+ *      bulkdata        Pointers to any associated bulk data.
+ *      dir             Direction of the signal. Zero means from host,
+ *                      non-zero means to host.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+    void
+sme_log_event(ul_client_t *pcli,
+        const u8 *signal, int signal_len,
+        const bulk_data_param_t *bulkdata,
+        int dir)
+{
+    unifi_priv_t *priv;
+    CSR_SIGNAL unpacked_signal;
+    CsrWifiSmeDataBlock mlmeCommand;
+    CsrWifiSmeDataBlock dataref1;
+    CsrWifiSmeDataBlock dataref2;
+    CsrResult result = CSR_RESULT_SUCCESS;
+    int r;
+
+    /* Following bits are encoded in hostTag These are there to ensure that hostTags are unique*/
+#define CSR_SME_DATA     0x00000000  /* Frames Sent by SME */
+#define CSR_PAL_DATA     0X10000000  /* Frames Sent by PAL-D*/
+#define CSR_NME_DATA     0x20000000  /* Frames Sent by NME*/
+#define APPLICATION_DATA 0x30000000  /* Frames Sent by Application*/
+
+    func_enter();
+    /* Just a sanity check */
+    if ((signal == NULL) || (signal_len <= 0)) {
+        func_exit();
+        return;
+    }
+
+    priv = uf_find_instance(pcli->instance);
+    if (!priv) {
+        unifi_error(priv, "sme_log_event: invalid priv\n");
+        func_exit();
+        return;
+    }
+
+    if (priv->smepriv == NULL) {
+        unifi_error(priv, "sme_log_event: invalid smepriv\n");
+        func_exit();
+        return;
+    }
+
+    unifi_trace(priv, UDBG3,
+            "sme_log_event: Process signal 0x%.4X\n",
+            CSR_GET_UINT16_FROM_LITTLE_ENDIAN(signal));
+
+
+    /* If the signal is known, then do any filtering required, otherwise it pass it to the SME. */
+    r = read_unpack_signal(signal, &unpacked_signal);
+    if (r == CSR_RESULT_SUCCESS) {
+        if ((unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_DEBUG_STRING_INDICATION_ID) ||
+            (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_DEBUG_WORD16_INDICATION_ID))
+        {
+            func_exit();
+            return;
+        }
+        if (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_MA_PACKET_INDICATION_ID)
+        {
+            CsrUint16 frmCtrl;
+            CsrBool unicastPdu = TRUE;
+            CsrUint8 *macHdrLocation;
+            CsrUint8 *raddr = NULL, *taddr = NULL;
+            CsrWifiMacAddress peerMacAddress;
+            /* Check if we need to send CsrWifiRouterCtrlMicFailureInd*/
+            CSR_MA_PACKET_INDICATION *ind = &unpacked_signal.u.MaPacketIndication;
+
+            macHdrLocation = (CsrUint8 *) bulkdata->d[0].os_data_ptr;
+            /* Fetch the frame control value from  mac header */
+            frmCtrl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation);
+
+            /* Point to the addresses */
+            raddr = macHdrLocation + MAC_HEADER_ADDR1_OFFSET;
+            taddr = macHdrLocation + MAC_HEADER_ADDR2_OFFSET;
+
+            CsrMemCpy(peerMacAddress.a, taddr, ETH_ALEN);
+
+            if(ind->ReceptionStatus == CSR_MICHAEL_MIC_ERROR)
+            {
+                if (*raddr & 0x1)
+                    unicastPdu = FALSE;
+
+                CsrWifiRouterCtrlMicFailureIndSend (priv->CSR_WIFI_SME_IFACEQUEUE, 0,
+                        (ind->VirtualInterfaceIdentifier & 0xff),peerMacAddress,
+                        unicastPdu);
+                return;
+            }
+            else
+            {
+                if(ind->ReceptionStatus == CSR_RX_SUCCESS)
+                {
+                    CsrUint8 pmBit = (frmCtrl & 0x1000)?0x01:0x00;
+                    CsrUint16 interfaceTag = (ind->VirtualInterfaceIdentifier & 0xff);
+                    CsrWifiRouterCtrlStaInfo_t *srcStaInfo =  CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv,taddr,interfaceTag);
+                    if((srcStaInfo != NULL) && (uf_check_broadcast_bssid(priv, bulkdata)== FALSE))
+                    {
+                        uf_process_pm_bit_for_peer(priv,srcStaInfo,pmBit,interfaceTag);
+
+                        /* Update station last activity flag */
+                        srcStaInfo->activity_flag = TRUE;
+                    }
+                }
+            }
+        }
+
+        if (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_MA_PACKET_CONFIRM_ID)
+        {
+            CSR_MA_PACKET_CONFIRM *cfm = &unpacked_signal.u.MaPacketConfirm;
+            CsrUint16 interfaceTag = (cfm->VirtualInterfaceIdentifier & 0xff);
+            netInterface_priv_t *interfacePriv;
+            CSR_MA_PACKET_REQUEST *req;
+            CsrWifiMacAddress peerMacAddress;
+
+            if (interfaceTag >= CSR_WIFI_NUM_INTERFACES)
+            {
+                unifi_error(priv, "Bad MA_PACKET_CONFIRM interfaceTag %d\n", interfaceTag);
+                func_exit();
+                return;
+            }
+
+            unifi_trace(priv,UDBG1,"MA-PACKET Confirm (%x, %x)\n", cfm->HostTag, cfm->TransmissionStatus);
+
+            interfacePriv = priv->interfacePriv[interfaceTag];
+#ifdef CSR_SUPPORT_SME
+            if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
+                 interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
+
+                if(cfm->HostTag == interfacePriv->multicastPduHostTag){
+                    uf_process_ma_pkt_cfm_for_ap(priv ,interfaceTag, cfm);
+                }
+            }
+#endif
+
+            req = &interfacePriv->m4_signal.u.MaPacketRequest;
+
+            if(cfm->HostTag & 0x80000000)
+            {
+                if (cfm->TransmissionStatus != CSR_TX_SUCCESSFUL)
+                {
+                    result = CSR_RESULT_FAILURE;
+                }
+#ifdef CSR_SUPPORT_SME
+                memcpy(peerMacAddress.a, req->Ra.x, ETH_ALEN);
+                /* Check if this is a confirm for EAPOL M4 frame and we need to send transmistted ind*/
+                if (interfacePriv->m4_sent && (cfm->HostTag == interfacePriv->m4_hostTag))
+                {
+                    unifi_trace(priv, UDBG1, "%s: Sending M4 Transmit CFM\n", __FUNCTION__);
+                    CsrWifiRouterCtrlM4TransmittedIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0,
+                            interfaceTag,
+                            peerMacAddress,
+                            result);
+                    interfacePriv->m4_sent = FALSE;
+                    interfacePriv->m4_hostTag = 0xffffffff;
+                }
+#endif
+                /* If EAPOL was requested via router APIs then send cfm else ignore*/
+                if((cfm->HostTag & 0x80000000) != CSR_WIFI_EAPOL_M4_HOST_TAG) {
+                    CsrWifiRouterMaPacketCfmSend((CsrUint16)signal[2],
+                        cfm->VirtualInterfaceIdentifier,
+                        result,
+                        (cfm->HostTag & 0x3fffffff), cfm->Rate);
+                } else {
+                    unifi_trace(priv, UDBG1, "%s: M4 received from netdevice\n", __FUNCTION__);
+                }
+                func_exit();
+                return;
+            }
+        }
+    }
+
+    mlmeCommand.length = signal_len;
+    mlmeCommand.data = (CsrUint8*)signal;
+
+    dataref1.length = bulkdata->d[0].data_length;
+    if (dataref1.length > 0) {
+        dataref1.data = (CsrUint8 *) bulkdata->d[0].os_data_ptr;
+    } else
+    {
+        dataref1.data = NULL;
+    }
+
+    dataref2.length = bulkdata->d[1].data_length;
+    if (dataref2.length > 0) {
+        dataref2.data = (CsrUint8 *) bulkdata->d[1].os_data_ptr;
+    } else
+    {
+        dataref2.data = NULL;
+    }
+
+    CsrWifiRouterCtrlHipIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, mlmeCommand.length, mlmeCommand.data,
+            dataref1.length, dataref1.data,
+            dataref2.length, dataref2.data);
+
+    func_exit();
+} /* sme_log_event() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * uf_sme_port_state
+ *
+ *      Return the state of the controlled port.
+ *
+ * Arguments:
+ *      priv            Pointer to device private context struct
+ *      address    Pointer to the destination for tx or sender for rx address
+ *      queue           Controlled or uncontrolled queue
+ *
+ * Returns:
+ *      An unifi_ControlledPortAction value.
+ * ---------------------------------------------------------------------------
+ */
+CsrWifiRouterCtrlPortAction
+uf_sme_port_state(unifi_priv_t *priv, unsigned char *address, int queue, CsrUint16 interfaceTag)
+{
+    int i;
+    unifi_port_config_t *port;
+    netInterface_priv_t *interfacePriv;
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "uf_sme_port_state: bad interfaceTag\n");
+        return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
+    }
+
+    interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if (queue == UF_CONTROLLED_PORT_Q) {
+        port = &interfacePriv->controlled_data_port;
+    } else {
+        port = &interfacePriv->uncontrolled_data_port;
+    }
+
+    if (!port->entries_in_use) {
+        unifi_trace(priv, UDBG5, "No port configurations, return Discard.\n");
+        return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
+    }
+
+    /* If the port configuration is common for all destinations, return it. */
+    if (port->overide_action == UF_DATA_PORT_OVERIDE) {
+        unifi_trace(priv, UDBG5, "Single port configuration (%d).\n",
+                port->port_cfg[0].port_action);
+        return port->port_cfg[0].port_action;
+    }
+
+    unifi_trace(priv, UDBG5, "Multiple (%d) port configurations.\n", port->entries_in_use);
+
+    /* If multiple configurations exist.. */
+    for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
+        /* .. go through the list and match the destination address. */
+        if (port->port_cfg[i].in_use &&
+            memcmp(address, port->port_cfg[i].mac_address.a, ETH_ALEN) == 0) {
+            /* Return the desired action. */
+            return port->port_cfg[i].port_action;
+        }
+    }
+
+    /* Could not find any information, return Open. */
+    unifi_trace(priv, UDBG5, "port configuration not found, return Open.\n");
+    return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN;
+} /* uf_sme_port_state() */
+
+/*
+ * ---------------------------------------------------------------------------
+ * uf_sme_port_config_handle
+ *
+ *      Return the port config handle of the controlled/uncontrolled port.
+ *
+ * Arguments:
+ *      priv            Pointer to device private context struct
+ *      address    Pointer to the destination for tx or sender for rx address
+ *      queue           Controlled or uncontrolled queue
+ *
+ * Returns:
+ *      An  unifi_port_cfg_t* .
+ * ---------------------------------------------------------------------------
+ */
+unifi_port_cfg_t*
+uf_sme_port_config_handle(unifi_priv_t *priv, unsigned char *address, int queue, CsrUint16 interfaceTag)
+{
+    int i;
+    unifi_port_config_t *port;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "uf_sme_port_config_handle: bad interfaceTag\n");
+        return NULL;
+    }
+
+    if (queue == UF_CONTROLLED_PORT_Q) {
+        port = &interfacePriv->controlled_data_port;
+    } else {
+        port = &interfacePriv->uncontrolled_data_port;
+    }
+
+    if (!port->entries_in_use) {
+        unifi_trace(priv, UDBG5, "No port configurations, return Discard.\n");
+        return NULL;
+    }
+
+    /* If the port configuration is common for all destinations, return it. */
+    if (port->overide_action == UF_DATA_PORT_OVERIDE) {
+        unifi_trace(priv, UDBG5, "Single port configuration (%d).\n",
+                port->port_cfg[0].port_action);
+        if (address) {
+            unifi_trace(priv, UDBG5, "addr[0] = %x, addr[1] = %x, addr[2] = %x, addr[3] = %x\n", address[0], address[1], address[2], address[3]);
+        }
+        return &port->port_cfg[0];
+    }
+
+    unifi_trace(priv, UDBG5, "Multiple port configurations.\n");
+
+    /* If multiple configurations exist.. */
+    for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
+        /* .. go through the list and match the destination address. */
+        if (port->port_cfg[i].in_use &&
+            memcmp(address, port->port_cfg[i].mac_address.a, ETH_ALEN) == 0) {
+            /* Return the desired action. */
+            return &port->port_cfg[i];
+        }
+    }
+
+    /* Could not find any information, return Open. */
+    unifi_trace(priv, UDBG5, "port configuration not found, returning NULL (debug).\n");
+    return NULL;
+} /* uf_sme_port_config_handle */
+
+void
+uf_multicast_list_wq(struct work_struct *work)
+{
+    unifi_priv_t *priv = container_of(work, unifi_priv_t,
+            multicast_list_task);
+    int i;
+    CsrUint16 interfaceTag = 0;
+    CsrWifiMacAddress* multicast_address_list = NULL;
+    int mc_count;
+    u8 *mc_list;
+    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "uf_multicast_list_wq: bad interfaceTag\n");
+        return;
+    }
+
+    unifi_trace(priv, UDBG5,
+            "uf_multicast_list_wq: list count = %d\n",
+            interfacePriv->mc_list_count);
+
+    /* Flush the current list */
+    CsrWifiRouterCtrlMulticastAddressIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, interfaceTag, CSR_WIFI_SME_LIST_ACTION_FLUSH, 0, NULL);
+
+    mc_count = interfacePriv->mc_list_count;
+    mc_list = interfacePriv->mc_list;
+    /*
+     * Allocate a new list, need to free it later
+     * in unifi_mgt_multicast_address_cfm().
+     */
+    multicast_address_list = CsrPmemAlloc(mc_count * sizeof(CsrWifiMacAddress));
+
+    if (multicast_address_list == NULL) {
+        return;
+    }
+
+    for (i = 0; i < mc_count; i++) {
+        memcpy(multicast_address_list[i].a, mc_list, ETH_ALEN);
+        mc_list += ETH_ALEN;
+    }
+
+    if (priv->smepriv == NULL) {
+        CsrPmemFree(multicast_address_list);
+        return;
+    }
+
+    CsrWifiRouterCtrlMulticastAddressIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,
+            interfaceTag,
+            CSR_WIFI_SME_LIST_ACTION_ADD,
+            mc_count, multicast_address_list);
+
+    /* The SME will take a copy of the addreses*/
+    CsrPmemFree(multicast_address_list);
+}
+
+
+int unifi_cfg_power(unifi_priv_t *priv, unsigned char *arg)
+{
+    unifi_cfg_power_t cfg_power;
+    int rc;
+    int wol;
+
+    if (get_user(cfg_power, (unifi_cfg_power_t*)(((unifi_cfg_command_t*)arg) + 1))) {
+        unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    switch (cfg_power) {
+        case UNIFI_CFG_POWER_OFF:
+            priv->wol_suspend = (enable_wol == UNIFI_WOL_OFF) ? FALSE : TRUE;
+            rc = sme_sys_suspend(priv);
+            if (rc) {
+                return rc;
+            }
+            break;
+        case UNIFI_CFG_POWER_ON:
+            wol = priv->wol_suspend;
+            rc = sme_sys_resume(priv);
+            if (rc) {
+                return rc;
+            }
+            if (wol) {
+                /* Kick the BH to ensure pending transfers are handled when
+                 * a suspend happened with card powered.
+                 */
+                unifi_send_signal(priv->card, NULL, 0, NULL);
+            }
+            break;
+        default:
+            unifi_error(priv, "WIFI POWER: Unknown value.\n");
+            return -EINVAL;
+    }
+
+    return 0;
+}
+
+
+int unifi_cfg_power_save(unifi_priv_t *priv, unsigned char *arg)
+{
+    unifi_cfg_powersave_t cfg_power_save;
+    CsrWifiSmePowerConfig powerConfig;
+    int rc;
+
+    if (get_user(cfg_power_save, (unifi_cfg_powersave_t*)(((unifi_cfg_command_t*)arg) + 1))) {
+        unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    /* Get the coex info from the SME */
+    rc = sme_mgt_power_config_get(priv, &powerConfig);
+    if (rc) {
+        unifi_error(priv, "UNIFI_CFG: Get unifi_PowerConfigValue failed.\n");
+        return rc;
+    }
+
+    switch (cfg_power_save) {
+        case UNIFI_CFG_POWERSAVE_NONE:
+            powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW;
+            break;
+        case UNIFI_CFG_POWERSAVE_FAST:
+            powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_MED;
+            break;
+        case UNIFI_CFG_POWERSAVE_FULL:
+            powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH;
+            break;
+        case UNIFI_CFG_POWERSAVE_AUTO:
+            powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_AUTO;
+            break;
+        default:
+            unifi_error(priv, "POWERSAVE: Unknown value.\n");
+            return -EINVAL;
+    }
+
+    rc = sme_mgt_power_config_set(priv, &powerConfig);
+
+    if (rc) {
+        unifi_error(priv, "UNIFI_CFG: Set unifi_PowerConfigValue failed.\n");
+    }
+
+    return rc;
+}
+
+
+int unifi_cfg_power_supply(unifi_priv_t *priv, unsigned char *arg)
+{
+    unifi_cfg_powersupply_t cfg_power_supply;
+    CsrWifiSmeHostConfig hostConfig;
+    int rc;
+
+    if (get_user(cfg_power_supply, (unifi_cfg_powersupply_t*)(((unifi_cfg_command_t*)arg) + 1))) {
+        unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    /* Get the coex info from the SME */
+    rc = sme_mgt_host_config_get(priv, &hostConfig);
+    if (rc) {
+        unifi_error(priv, "UNIFI_CFG: Get unifi_HostConfigValue failed.\n");
+        return rc;
+    }
+
+    switch (cfg_power_supply) {
+        case UNIFI_CFG_POWERSUPPLY_MAINS:
+            hostConfig.powerMode = CSR_WIFI_SME_HOST_POWER_MODE_ACTIVE;
+            break;
+        case UNIFI_CFG_POWERSUPPLY_BATTERIES:
+            hostConfig.powerMode = CSR_WIFI_SME_HOST_POWER_MODE_POWER_SAVE;
+            break;
+        default:
+            unifi_error(priv, "POWERSUPPLY: Unknown value.\n");
+            return -EINVAL;
+    }
+
+    rc = sme_mgt_host_config_set(priv, &hostConfig);
+    if (rc) {
+        unifi_error(priv, "UNIFI_CFG: Set unifi_HostConfigValue failed.\n");
+    }
+
+    return rc;
+}
+
+
+int unifi_cfg_packet_filters(unifi_priv_t *priv, unsigned char *arg)
+{
+    unsigned char *tclas_buffer;
+    unsigned int tclas_buffer_length;
+    tclas_t *dhcp_tclas;
+    int rc;
+
+    /* Free any TCLASs previously allocated */
+    if (priv->packet_filters.tclas_ies_length) {
+        CsrPmemFree(priv->filter_tclas_ies);
+        priv->filter_tclas_ies = NULL;
+    }
+
+    tclas_buffer = ((unsigned char*)arg) + sizeof(unifi_cfg_command_t) + sizeof(unsigned int);
+    if (copy_from_user(&priv->packet_filters, (void*)tclas_buffer,
+                sizeof(uf_cfg_bcast_packet_filter_t))) {
+        unifi_error(priv, "UNIFI_CFG: Failed to get the filter struct\n");
+        return -EFAULT;
+    }
+
+    tclas_buffer_length = priv->packet_filters.tclas_ies_length;
+
+    /* Allocate TCLASs if necessary */
+    if (priv->packet_filters.dhcp_filter) {
+        priv->packet_filters.tclas_ies_length += sizeof(tclas_t);
+    }
+    if (priv->packet_filters.tclas_ies_length > 0) {
+        priv->filter_tclas_ies = CsrPmemAlloc(priv->packet_filters.tclas_ies_length);
+        if (priv->filter_tclas_ies == NULL) {
+            return -ENOMEM;
+        }
+        if (tclas_buffer_length) {
+            tclas_buffer += sizeof(uf_cfg_bcast_packet_filter_t) - sizeof(unsigned char*);
+            if (copy_from_user(priv->filter_tclas_ies,
+                        tclas_buffer,
+                        tclas_buffer_length)) {
+                unifi_error(priv, "UNIFI_CFG: Failed to get the TCLAS buffer\n");
+                return -EFAULT;
+            }
+        }
+    }
+
+    if(priv->packet_filters.dhcp_filter)
+    {
+        /* Append the DHCP tclas IE */
+        dhcp_tclas = (tclas_t*)(priv->filter_tclas_ies + tclas_buffer_length);
+        memset(dhcp_tclas, 0, sizeof(tclas_t));
+        dhcp_tclas->element_id = 14;
+        dhcp_tclas->length = sizeof(tcpip_clsfr_t) + 1;
+        dhcp_tclas->user_priority = 0;
+        dhcp_tclas->tcp_ip_cls_fr.cls_fr_type = 1;
+        dhcp_tclas->tcp_ip_cls_fr.version = 4;
+        ((CsrUint8*)(&dhcp_tclas->tcp_ip_cls_fr.source_port))[0] = 0x00;
+        ((CsrUint8*)(&dhcp_tclas->tcp_ip_cls_fr.source_port))[1] = 0x44;
+        ((CsrUint8*)(&dhcp_tclas->tcp_ip_cls_fr.dest_port))[0] = 0x00;
+        ((CsrUint8*)(&dhcp_tclas->tcp_ip_cls_fr.dest_port))[1] = 0x43;
+        dhcp_tclas->tcp_ip_cls_fr.protocol = 0x11;
+        dhcp_tclas->tcp_ip_cls_fr.cls_fr_mask = 0x58; //bits: 3,4,6
+    }
+
+    rc = sme_mgt_packet_filter_set(priv);
+
+    return rc;
+}
+
+
+int unifi_cfg_wmm_qos_info(unifi_priv_t *priv, unsigned char *arg)
+{
+    CsrUint8 wmm_qos_info;
+    int rc = 0;
+
+    if (get_user(wmm_qos_info, (CsrUint8*)(((unifi_cfg_command_t*)arg) + 1))) {
+        unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    /* Store the value in the connection info */
+    priv->connection_config.wmmQosInfo = wmm_qos_info;
+
+    return rc;
+}
+
+
+int unifi_cfg_wmm_addts(unifi_priv_t *priv, unsigned char *arg)
+{
+    CsrUint32 addts_tid;
+    CsrUint8 addts_ie_length;
+    CsrUint8 *addts_ie;
+    CsrUint8 *addts_params;
+    CsrWifiSmeDataBlock tspec;
+    CsrWifiSmeDataBlock tclas;
+    int rc;
+
+    addts_params = (CsrUint8*)(((unifi_cfg_command_t*)arg) + 1);
+    if (get_user(addts_tid, (CsrUint32*)addts_params)) {
+        unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    addts_params += sizeof(CsrUint32);
+    if (get_user(addts_ie_length, (CsrUint8*)addts_params)) {
+        unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG4, "addts: tid = 0x%x ie_length = %d\n",
+            addts_tid, addts_ie_length);
+
+    addts_ie = CsrPmemAlloc(addts_ie_length);
+    if (addts_ie == NULL) {
+        unifi_error(priv,
+                "unifi_cfg_wmm_addts: Failed to malloc %d bytes for addts_ie buffer\n",
+                addts_ie_length);
+        return -ENOMEM;
+    }
+
+    addts_params += sizeof(CsrUint8);
+    rc = copy_from_user(addts_ie, addts_params, addts_ie_length);
+    if (rc) {
+        unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the addts buffer\n");
+        CsrPmemFree(addts_ie);
+        return -EFAULT;
+    }
+
+    tspec.data = addts_ie;
+    tspec.length = addts_ie_length;
+    tclas.data = NULL;
+    tclas.length = 0;
+
+    rc = sme_mgt_tspec(priv, CSR_WIFI_SME_LIST_ACTION_ADD, addts_tid,
+            &tspec, &tclas);
+
+    CsrPmemFree(addts_ie);
+    return rc;
+}
+
+
+int unifi_cfg_wmm_delts(unifi_priv_t *priv, unsigned char *arg)
+{
+    CsrUint32 delts_tid;
+    CsrUint8 *delts_params;
+    CsrWifiSmeDataBlock tspec;
+    CsrWifiSmeDataBlock tclas;
+    int rc;
+
+    delts_params = (CsrUint8*)(((unifi_cfg_command_t*)arg) + 1);
+    if (get_user(delts_tid, (CsrUint32*)delts_params)) {
+        unifi_error(priv, "unifi_cfg_wmm_delts: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG4, "delts: tid = 0x%x\n", delts_tid);
+
+    tspec.data = tclas.data = NULL;
+    tspec.length = tclas.length = 0;
+
+    rc = sme_mgt_tspec(priv, CSR_WIFI_SME_LIST_ACTION_REMOVE, delts_tid,
+            &tspec, &tclas);
+
+    return rc;
+}
+
+int unifi_cfg_strict_draft_n(unifi_priv_t *priv, unsigned char *arg)
+{
+    CsrBool strict_draft_n;
+    CsrUint8 *strict_draft_n_params;
+    int rc;
+
+    CsrWifiSmeStaConfig  staConfig;
+    CsrWifiSmeDeviceConfig  deviceConfig;
+
+    strict_draft_n_params = (CsrUint8*)(((unifi_cfg_command_t*)arg) + 1);
+    if (get_user(strict_draft_n, (CsrBool*)strict_draft_n_params)) {
+        unifi_error(priv, "unifi_cfg_strict_draft_n: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG4, "strict_draft_n: = %s\n", ((strict_draft_n) ? "yes":"no"));
+
+    rc = sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig);
+
+    if (rc) {
+        unifi_warning(priv, "unifi_cfg_strict_draft_n: Get unifi_SMEConfigValue failed.\n");
+        return -EFAULT;
+    }
+
+    deviceConfig.enableStrictDraftN = strict_draft_n;
+
+    rc = sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig);
+    if (rc) {
+        unifi_warning(priv, "unifi_cfg_strict_draft_n: Set unifi_SMEConfigValue failed.\n");
+        rc = -EFAULT;
+    }
+
+    return rc;
+}
+
+
+int unifi_cfg_enable_okc(unifi_priv_t *priv, unsigned char *arg)
+{
+    CsrBool enable_okc;
+    CsrUint8 *enable_okc_params;
+    int rc;
+
+    CsrWifiSmeStaConfig staConfig;
+    CsrWifiSmeDeviceConfig deviceConfig;
+
+    enable_okc_params = (CsrUint8*)(((unifi_cfg_command_t*)arg) + 1);
+    if (get_user(enable_okc, (CsrBool*)enable_okc_params)) {
+        unifi_error(priv, "unifi_cfg_enable_okc: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    unifi_trace(priv, UDBG4, "enable_okc: = %s\n", ((enable_okc) ? "yes":"no"));
+
+    rc = sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig);
+    if (rc) {
+        unifi_warning(priv, "unifi_cfg_enable_okc: Get unifi_SMEConfigValue failed.\n");
+        return -EFAULT;
+    }
+
+    staConfig.enableOpportunisticKeyCaching = enable_okc;
+
+    rc = sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig);
+    if (rc) {
+        unifi_warning(priv, "unifi_cfg_enable_okc: Set unifi_SMEConfigValue failed.\n");
+        rc = -EFAULT;
+    }
+
+    return rc;
+}
+
+
+int unifi_cfg_get_info(unifi_priv_t *priv, unsigned char *arg)
+{
+    unifi_cfg_get_t get_cmd;
+    char inst_name[IFNAMSIZ];
+    int rc;
+
+    if (get_user(get_cmd, (unifi_cfg_get_t*)(((unifi_cfg_command_t*)arg) + 1))) {
+        unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
+        return -EFAULT;
+    }
+
+    switch (get_cmd) {
+        case UNIFI_CFG_GET_COEX:
+            {
+                CsrWifiSmeCoexInfo coexInfo;
+                /* Get the coex info from the SME */
+                rc = sme_mgt_coex_info_get(priv, &coexInfo);
+                if (rc) {
+                    unifi_error(priv, "UNIFI_CFG: Get unifi_CoexInfoValue failed.\n");
+                    return rc;
+                }
+
+                /* Copy the info to the out buffer */
+                if (copy_to_user((void*)arg,
+                            &coexInfo,
+                            sizeof(CsrWifiSmeCoexInfo))) {
+                    unifi_error(priv, "UNIFI_CFG: Failed to copy the coex info\n");
+                    return -EFAULT;
+                }
+                break;
+            }
+        case UNIFI_CFG_GET_POWER_MODE:
+            {
+                CsrWifiSmePowerConfig powerConfig;
+                rc = sme_mgt_power_config_get(priv, &powerConfig);
+                if (rc) {
+                    unifi_error(priv, "UNIFI_CFG: Get unifi_PowerConfigValue failed.\n");
+                    return rc;
+                }
+
+                /* Copy the info to the out buffer */
+                if (copy_to_user((void*)arg,
+                            &powerConfig.powerSaveLevel,
+                            sizeof(CsrWifiSmePowerSaveLevel))) {
+                    unifi_error(priv, "UNIFI_CFG: Failed to copy the power save info\n");
+                    return -EFAULT;
+                }
+                break;
+            }
+        case UNIFI_CFG_GET_POWER_SUPPLY:
+            {
+                CsrWifiSmeHostConfig hostConfig;
+                rc = sme_mgt_host_config_get(priv, &hostConfig);
+                if (rc) {
+                    unifi_error(priv, "UNIFI_CFG: Get unifi_HostConfigValue failed.\n");
+                    return rc;
+                }
+
+                /* Copy the info to the out buffer */
+                if (copy_to_user((void*)arg,
+                            &hostConfig.powerMode,
+                            sizeof(CsrWifiSmeHostPowerMode))) {
+                    unifi_error(priv, "UNIFI_CFG: Failed to copy the host power mode\n");
+                    return -EFAULT;
+                }
+                break;
+            }
+        case UNIFI_CFG_GET_VERSIONS:
+            break;
+        case UNIFI_CFG_GET_INSTANCE:
+            {
+                CsrUint16 InterfaceId=0;
+                uf_net_get_name(priv->netdev[InterfaceId], &inst_name[0], sizeof(inst_name));
+
+                /* Copy the info to the out buffer */
+                if (copy_to_user((void*)arg,
+                            &inst_name[0],
+                            sizeof(inst_name))) {
+                    unifi_error(priv, "UNIFI_CFG: Failed to copy the instance name\n");
+                    return -EFAULT;
+                }
+            }
+            break;
+
+        case UNIFI_CFG_GET_AP_CONFIG:
+            {
+#ifdef CSR_SUPPORT_WEXT_AP
+                uf_cfg_ap_config_t cfg_ap_config;
+                cfg_ap_config.channel = priv->ap_config.channel;
+                cfg_ap_config.beaconInterval = priv->ap_mac_config.beaconInterval;
+                cfg_ap_config.wmmEnabled = priv->ap_mac_config.wmmEnabled;
+                cfg_ap_config.dtimPeriod = priv->ap_mac_config.dtimPeriod;
+                cfg_ap_config.phySupportedBitmap = priv->ap_mac_config.phySupportedBitmap;
+                if (copy_to_user((void*)arg,
+                            &cfg_ap_config,
+                            sizeof(uf_cfg_ap_config_t))) {
+                    unifi_error(priv, "UNIFI_CFG: Failed to copy the AP configuration\n");
+                    return -EFAULT;
+                }
+#else
+                   return -EPERM;
+#endif
+            }
+            break;
+
+
+        default:
+            unifi_error(priv, "unifi_cfg_get_info: Unknown value.\n");
+            return -EINVAL;
+    }
+
+    return 0;
+}
+#ifdef CSR_SUPPORT_WEXT_AP
+int
+ uf_configure_supported_rates(CsrUint8 * supportedRates, CsrUint8 phySupportedBitmap)
+{
+    int i=0;
+    CsrBool b=FALSE, g = FALSE, n = FALSE;
+    b = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_B;
+    n = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_N;
+    g = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_G;
+    if(b || g) {
+        supportedRates[i++]=0x82;
+        supportedRates[i++]=0x84;
+        supportedRates[i++]=0x8b;
+        supportedRates[i++]=0x96;
+    } else if(n) {
+        /* For some strange reasons WiFi stack needs both b and g rates*/
+        supportedRates[i++]=0x02;
+        supportedRates[i++]=0x04;
+        supportedRates[i++]=0x0b;
+        supportedRates[i++]=0x16;
+        supportedRates[i++]=0x0c;
+        supportedRates[i++]=0x12;
+        supportedRates[i++]=0x18;
+	supportedRates[i++]=0x24;
+        supportedRates[i++]=0x30;
+        supportedRates[i++]=0x48;
+        supportedRates[i++]=0x60;
+        supportedRates[i++]=0x6c;
+    }
+    if(g) {
+        if(!b) {
+            supportedRates[i++]=0x8c;
+            supportedRates[i++]=0x98;
+            supportedRates[i++]=0xb0;
+        } else {
+            supportedRates[i++]=0x0c;
+            supportedRates[i++]=0x18;
+            supportedRates[i++]=0x30;
+        }
+        supportedRates[i++]=0x48;
+        supportedRates[i++]=0x12;
+        supportedRates[i++]=0x24;
+        supportedRates[i++]=0x60;
+        supportedRates[i++]=0x6c;
+    }
+    return i;
+}
+int unifi_cfg_set_ap_config(unifi_priv_t * priv,unsigned char* arg)
+{
+    uf_cfg_ap_config_t cfg_ap_config;
+    char *buffer;
+
+    buffer = ((unsigned char*)arg) + sizeof(unifi_cfg_command_t) + sizeof(unsigned int);
+    if (copy_from_user(&cfg_ap_config, (void*)buffer,
+                sizeof(uf_cfg_ap_config_t))) {
+        unifi_error(priv, "UNIFI_CFG: Failed to get the ap config struct\n");
+        return -EFAULT;
+    }
+    priv->ap_config.channel = cfg_ap_config.channel;
+    priv->ap_mac_config.dtimPeriod = cfg_ap_config.dtimPeriod;
+    priv->ap_mac_config.beaconInterval = cfg_ap_config.beaconInterval;
+    priv->group_sec_config.apGroupkeyTimeout = cfg_ap_config.groupkeyTimeout;
+    priv->group_sec_config.apStrictGtkRekey = cfg_ap_config.strictGtkRekeyEnabled;
+    priv->group_sec_config.apGmkTimeout = cfg_ap_config.gmkTimeout;
+    priv->group_sec_config.apResponseTimeout = cfg_ap_config.responseTimeout;
+    priv->group_sec_config.apRetransLimit = cfg_ap_config.retransLimit;
+
+    priv->ap_mac_config.shortSlotTimeEnabled = cfg_ap_config.shortSlotTimeEnabled;
+    priv->ap_mac_config.ctsProtectionType=cfg_ap_config.ctsProtectionType;
+
+    priv->ap_mac_config.wmmEnabled = cfg_ap_config.wmmEnabled;
+
+    priv->ap_mac_config.apHtParams.rxStbc=cfg_ap_config.rxStbc;
+    priv->ap_mac_config.apHtParams.rifsModeAllowed=cfg_ap_config.rifsModeAllowed;
+
+    priv->ap_mac_config.phySupportedBitmap = cfg_ap_config.phySupportedBitmap;
+    priv->ap_mac_config.maxListenInterval=cfg_ap_config.maxListenInterval;
+
+    priv->ap_mac_config.supportedRatesCount=     uf_configure_supported_rates(priv->ap_mac_config.supportedRates,priv->ap_mac_config.phySupportedBitmap);
+
+    return 0;
+}
+
+#endif
+#ifdef CSR_SUPPORT_WEXT
+
+    void
+uf_sme_config_wq(struct work_struct *work)
+{
+    CsrWifiSmeStaConfig  staConfig;
+    CsrWifiSmeDeviceConfig  deviceConfig;
+    unifi_priv_t *priv = container_of(work, unifi_priv_t, sme_config_task);
+
+    /* Register to receive indications from the SME */
+    CsrWifiSmeEventMaskSetReqSend(0,
+            CSR_WIFI_SME_INDICATIONS_WIFIOFF | CSR_WIFI_SME_INDICATIONS_CONNECTIONQUALITY |
+            CSR_WIFI_SME_INDICATIONS_MEDIASTATUS | CSR_WIFI_SME_INDICATIONS_MICFAILURE);
+
+    if (sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig)) {
+        unifi_warning(priv, "uf_sme_config_wq: Get unifi_SMEConfigValue failed.\n");
+        return;
+    }
+
+    if (priv->if_index == CSR_INDEX_5G) {
+        staConfig.ifIndex = CSR_WIFI_SME_RADIO_IF_GHZ_5_0;
+    } else {
+        staConfig.ifIndex = CSR_WIFI_SME_RADIO_IF_GHZ_2_4;
+    }
+
+    deviceConfig.trustLevel = (CsrWifiSme80211dTrustLevel)tl_80211d;
+    if (sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig)) {
+        unifi_warning(priv,
+                "SME config for 802.11d Trust Level and Radio Band failed.\n");
+        return;
+    }
+
+} /* uf_sme_config_wq() */
+
+#endif /* CSR_SUPPORT_WEXT */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_ta_ind_wq
+ *
+ *      Deferred work queue function to send Traffic Analysis protocols
+ *      indications to the SME.
+ *      These are done in a deferred work queue for two reasons:
+ *       - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
+ *       - we want to load the main driver data path as lightly as possible
+ *
+ *      The TA classifications already come from a workqueue.
+ *
+ *  Arguments:
+ *      work    Pointer to work queue item.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+    void
+uf_ta_ind_wq(struct work_struct *work)
+{
+    struct ta_ind *ind = container_of(work, struct ta_ind, task);
+    unifi_priv_t *priv = container_of(ind, unifi_priv_t, ta_ind_work);
+    CsrUint16 interfaceTag = 0;
+
+
+    CsrWifiRouterCtrlTrafficProtocolIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,
+            interfaceTag,
+            ind->packet_type,
+            ind->direction,
+            ind->src_addr);
+    ind->in_use = 0;
+
+} /* uf_ta_ind_wq() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_ta_sample_ind_wq
+ *
+ *      Deferred work queue function to send Traffic Analysis sample
+ *      indications to the SME.
+ *      These are done in a deferred work queue for two reasons:
+ *       - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
+ *       - we want to load the main driver data path as lightly as possible
+ *
+ *      The TA classifications already come from a workqueue.
+ *
+ *  Arguments:
+ *      work    Pointer to work queue item.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+    void
+uf_ta_sample_ind_wq(struct work_struct *work)
+{
+    struct ta_sample_ind *ind = container_of(work, struct ta_sample_ind, task);
+    unifi_priv_t *priv = container_of(ind, unifi_priv_t, ta_sample_ind_work);
+    CsrUint16 interfaceTag = 0;
+
+     unifi_trace(priv, UDBG5, "rxtcp %d txtcp %d rxudp %d txudp %d prio %d\n",
+        priv->rxTcpThroughput,
+        priv->txTcpThroughput,
+        priv->rxUdpThroughput,
+        priv->txUdpThroughput,
+        priv->bh_thread.prio);
+
+    if(priv->rxTcpThroughput > 1000)
+    {
+        if (bh_priority == -1 && priv->bh_thread.prio != 1)
+        {
+            struct sched_param param;
+            priv->bh_thread.prio = 1;
+            unifi_trace(priv, UDBG1, "%s new thread (RT) priority = %d\n",
+                        priv->bh_thread.name, priv->bh_thread.prio);
+            param.sched_priority = priv->bh_thread.prio;
+            sched_setscheduler(priv->bh_thread.thread_task, SCHED_FIFO, &param);
+        }
+    } else
+    {
+        if (bh_priority == -1 && priv->bh_thread.prio != DEFAULT_PRIO)
+        {
+            struct sched_param param;
+            param.sched_priority = 0;
+            sched_setscheduler(priv->bh_thread.thread_task, SCHED_NORMAL, &param);
+            priv->bh_thread.prio = DEFAULT_PRIO;
+            unifi_trace(priv, UDBG1, "%s new thread priority = %d\n",
+                        priv->bh_thread.name, priv->bh_thread.prio);
+            set_user_nice(priv->bh_thread.thread_task, PRIO_TO_NICE(priv->bh_thread.prio));
+        }
+    }
+
+    CsrWifiRouterCtrlTrafficSampleIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, interfaceTag, ind->stats);
+
+    ind->in_use = 0;
+
+} /* uf_ta_sample_ind_wq() */
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_send_m4_ready_wq
+ *
+ *      Deferred work queue function to send M4 ReadyToSend inds to the SME.
+ *      These are done in a deferred work queue for two reasons:
+ *       - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
+ *       - we want to load the main driver data path as lightly as possible
+ *
+ *  Arguments:
+ *      work    Pointer to work queue item.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void
+uf_send_m4_ready_wq(struct work_struct *work)
+{
+    netInterface_priv_t *InterfacePriv = container_of(work, netInterface_priv_t, send_m4_ready_task);
+    CsrUint16 iface = InterfacePriv->InterfaceTag;
+    unifi_priv_t *priv = InterfacePriv->privPtr;
+    CSR_MA_PACKET_REQUEST *req = &InterfacePriv->m4_signal.u.MaPacketRequest;
+    CsrWifiMacAddress peer;
+    unsigned long flags;
+
+    func_enter();
+
+    /* The peer address was stored in the signal */
+    spin_lock_irqsave(&priv->m4_lock, flags);
+    memcpy(peer.a, req->Ra.x, sizeof(peer.a));
+    spin_unlock_irqrestore(&priv->m4_lock, flags);
+
+    /* Send a signal to SME */
+    CsrWifiRouterCtrlM4ReadyToSendIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, iface, peer);
+
+    UF_TRACE_MAC(priv, UDBG1, "M4ReadyToSendInd sent for peer", peer.a);
+
+    func_exit();
+
+} /* uf_send_m4_ready_wq() */
+
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
+/*
+ * ---------------------------------------------------------------------------
+ *  uf_send_pkt_to_encrypt
+ *
+ *      Deferred work queue function to send the WAPI data pkts to SME when unicast KeyId = 1
+ *      These are done in a deferred work queue for two reasons:
+ *       - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
+ *       - we want to load the main driver data path as lightly as possible
+ *
+ *  Arguments:
+ *      work    Pointer to work queue item.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+void uf_send_pkt_to_encrypt(struct work_struct *work)
+{
+    netInterface_priv_t *interfacePriv = container_of(work, netInterface_priv_t, send_pkt_to_encrypt);
+    CsrUint16 interfaceTag = interfacePriv->InterfaceTag;
+    unifi_priv_t *priv = interfacePriv->privPtr;
+
+    CsrUint32 pktBulkDataLength;
+    CsrUint8 *pktBulkData;
+    unsigned long flags;
+
+    if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA) {
+
+        func_enter();
+
+        pktBulkDataLength = interfacePriv->wapi_unicast_bulk_data.data_length;
+
+        if (pktBulkDataLength > 0) {
+		    pktBulkData = (CsrUint8 *)CsrPmemAlloc(pktBulkDataLength);
+		    CsrMemSet(pktBulkData, 0, pktBulkDataLength);
+	    } else {
+		    unifi_error(priv, "uf_send_pkt_to_encrypt() : invalid buffer\n");
+		    return;
+	    }
+
+        spin_lock_irqsave(&priv->wapi_lock, flags);
+        /* Copy over the MA PKT REQ bulk data */
+        CsrMemCpy(pktBulkData, (CsrUint8*)interfacePriv->wapi_unicast_bulk_data.os_data_ptr, pktBulkDataLength);
+        /* Free any bulk data buffers allocated for the WAPI Data pkt */
+        unifi_net_data_free(priv, &interfacePriv->wapi_unicast_bulk_data);
+        interfacePriv->wapi_unicast_bulk_data.net_buf_length = 0;
+        interfacePriv->wapi_unicast_bulk_data.data_length = 0;
+        interfacePriv->wapi_unicast_bulk_data.os_data_ptr = interfacePriv->wapi_unicast_bulk_data.os_net_buf_ptr = NULL;
+        spin_unlock_irqrestore(&priv->wapi_lock, flags);
+
+        CsrWifiRouterCtrlWapiUnicastTxEncryptIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, interfaceTag, pktBulkDataLength, pktBulkData);
+        unifi_trace(priv, UDBG1, "WapiUnicastTxEncryptInd sent to SME\n");
+
+        CsrPmemFree(pktBulkData); /* Would have been copied over by the SME Handler */
+
+        func_exit();
+    } else {
+	    unifi_warning(priv, "uf_send_pkt_to_encrypt() is NOT applicable for interface mode - %d\n",interfacePriv->interfaceMode);
+    }
+}/* uf_send_pkt_to_encrypt() */
+#endif
diff --git a/drivers/staging/csr/unifi_sme.h b/drivers/staging/csr/unifi_sme.h
new file mode 100644
index 0000000..3cbee81
--- /dev/null
+++ b/drivers/staging/csr/unifi_sme.h
@@ -0,0 +1,245 @@
+/*
+ * ***************************************************************************
+ *  FILE:     unifi_sme.h
+ *
+ *  PURPOSE:    SME related definitions.
+ *
+ *  Copyright (C) 2007-2011 by Cambridge Silicon Radio Ltd.
+ *
+ *  Refer to LICENSE.txt included with this source code for details on
+ *  the license terms.
+ *
+ * ***************************************************************************
+ */
+#ifndef __LINUX_UNIFI_SME_H__
+#define __LINUX_UNIFI_SME_H__ 1
+
+#include <linux/kernel.h>
+
+#ifdef CSR_SME_USERSPACE
+#include "sme_userspace.h"
+#endif
+
+#include "csr_wifi_sme_lib.h"
+
+typedef int unifi_data_port_action;
+
+typedef struct unifi_port_cfg
+{
+    /* TRUE if this port entry is allocated */
+    CsrBool in_use;
+    CsrWifiRouterCtrlPortAction port_action;
+    CsrWifiMacAddress mac_address;
+} unifi_port_cfg_t;
+
+#define UNIFI_MAX_CONNECTIONS           8
+#define UNIFI_MAX_RETRY_LIMIT           5
+#define UF_DATA_PORT_NOT_OVERIDE        0
+#define UF_DATA_PORT_OVERIDE            1
+
+typedef struct unifi_port_config
+{
+    int entries_in_use;
+    int overide_action;
+    unifi_port_cfg_t port_cfg[UNIFI_MAX_CONNECTIONS];
+} unifi_port_config_t;
+
+
+enum sme_request_status {
+    SME_REQUEST_EMPTY,
+    SME_REQUEST_PENDING,
+    SME_REQUEST_RECEIVED,
+    SME_REQUEST_TIMEDOUT,
+    SME_REQUEST_CANCELLED,
+};
+
+/* Structure to hold a UDI logged signal */
+typedef struct {
+
+    /* The current status of the request */
+    enum sme_request_status request_status;
+
+    /* The status the SME has passed to us */
+    CsrResult reply_status;
+
+    /* SME's reply to a get request */
+    CsrWifiSmeVersions versions;
+    CsrWifiSmePowerConfig powerConfig;
+    CsrWifiSmeHostConfig hostConfig;
+    CsrWifiSmeStaConfig staConfig;
+    CsrWifiSmeDeviceConfig deviceConfig;
+    CsrWifiSmeCoexInfo coexInfo;
+    CsrWifiSmeCoexConfig coexConfig;
+    CsrWifiSmeMibConfig mibConfig;
+    CsrWifiSmeConnectionInfo connectionInfo;
+    CsrWifiSmeConnectionConfig connectionConfig;
+    CsrWifiSmeConnectionStats connectionStats;
+
+
+    /* SME's reply to a scan request */
+    CsrUint16 reply_scan_results_count;
+    CsrWifiSmeScanResult* reply_scan_results;
+
+} sme_reply_t;
+
+
+typedef struct {
+    CsrUint16 appHandle;
+    CsrWifiRouterEncapsulation encapsulation;
+    CsrUint16 protocol;
+    CsrUint8 oui[3];
+    CsrUint8 in_use;
+} sme_ma_unidata_ind_filter_t;
+
+
+CsrWifiRouterCtrlPortAction uf_sme_port_state(unifi_priv_t *priv,
+                                          unsigned char *address,
+                                          int queue,
+                                          CsrUint16 interfaceTag);
+unifi_port_cfg_t *uf_sme_port_config_handle(unifi_priv_t *priv,
+                                            unsigned char *address,
+                                            int queue,
+                                            CsrUint16 interfaceTag);
+
+
+
+/* Callback for event logging to SME clients */
+void sme_log_event(ul_client_t *client, const u8 *signal, int signal_len,
+                   const bulk_data_param_t *bulkdata, int dir);
+
+/* The workqueue task to the set the multicast addresses list */
+void uf_multicast_list_wq(struct work_struct *work);
+
+/* The workqueue task to execute the TA module */
+void uf_ta_wq(struct work_struct *work);
+
+
+/*
+ * SME blocking helper functions
+ */
+#ifdef UNIFI_DEBUG
+# define sme_complete_request(priv, status)   uf_sme_complete_request(priv, status, __func__)
+#else
+# define sme_complete_request(priv, status)   uf_sme_complete_request(priv, status, NULL)
+#endif
+
+void uf_sme_complete_request(unifi_priv_t *priv, CsrResult reply_status, const char *func);
+void uf_sme_cancel_request(unifi_priv_t *priv, CsrResult reply_status);
+
+
+/*
+ * Blocking functions using the SME SYS API.
+ */
+int sme_sys_suspend(unifi_priv_t *priv);
+int sme_sys_resume(unifi_priv_t *priv);
+
+
+/*
+ * Traffic Analysis workqueue jobs
+ */
+void uf_ta_ind_wq(struct work_struct *work);
+void uf_ta_sample_ind_wq(struct work_struct *work);
+
+/*
+ * SME config workqueue job
+ */
+void uf_sme_config_wq(struct work_struct *work);
+
+/*
+ * To send M4 read to send IND
+ */
+void uf_send_m4_ready_wq(struct work_struct *work);
+
+#if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
+/*
+ * To send data pkt to Sme for encryption
+ */
+void uf_send_pkt_to_encrypt(struct work_struct *work);
+#endif
+
+int sme_mgt_power_config_set(unifi_priv_t *priv, CsrWifiSmePowerConfig *powerConfig);
+int sme_mgt_power_config_get(unifi_priv_t *priv, CsrWifiSmePowerConfig *powerConfig);
+int sme_mgt_host_config_set(unifi_priv_t *priv, CsrWifiSmeHostConfig *hostConfig);
+int sme_mgt_host_config_get(unifi_priv_t *priv, CsrWifiSmeHostConfig *hostConfig);
+int sme_mgt_sme_config_set(unifi_priv_t *priv, CsrWifiSmeStaConfig *staConfig, CsrWifiSmeDeviceConfig *deviceConfig);
+int sme_mgt_sme_config_get(unifi_priv_t *priv, CsrWifiSmeStaConfig *staConfig, CsrWifiSmeDeviceConfig *deviceConfig);
+int sme_mgt_coex_info_get(unifi_priv_t *priv, CsrWifiSmeCoexInfo *coexInfo);
+int sme_mgt_packet_filter_set(unifi_priv_t *priv);
+int sme_mgt_tspec(unifi_priv_t *priv, CsrWifiSmeListAction action,
+                  CsrUint32 tid, CsrWifiSmeDataBlock *tspec, CsrWifiSmeDataBlock *tclas);
+
+#ifdef CSR_SUPPORT_WEXT
+/*
+ * Blocking functions using the SME MGT API.
+ */
+int sme_mgt_wifi_on(unifi_priv_t *priv);
+int sme_mgt_wifi_off(unifi_priv_t *priv);
+/*int sme_mgt_set_value_async(unifi_priv_t *priv, unifi_AppValue *app_value);
+int sme_mgt_get_value_async(unifi_priv_t *priv, unifi_AppValue *app_value);
+int sme_mgt_get_value(unifi_priv_t *priv, unifi_AppValue *app_value);
+int sme_mgt_set_value(unifi_priv_t *priv, unifi_AppValue *app_value);
+*/
+int sme_mgt_coex_config_set(unifi_priv_t *priv, CsrWifiSmeCoexConfig *coexConfig);
+int sme_mgt_coex_config_get(unifi_priv_t *priv, CsrWifiSmeCoexConfig *coexConfig);
+int sme_mgt_mib_config_set(unifi_priv_t *priv, CsrWifiSmeMibConfig *mibConfig);
+int sme_mgt_mib_config_get(unifi_priv_t *priv, CsrWifiSmeMibConfig *mibConfig);
+
+int sme_mgt_connection_info_set(unifi_priv_t *priv, CsrWifiSmeConnectionInfo *connectionInfo);
+int sme_mgt_connection_info_get(unifi_priv_t *priv, CsrWifiSmeConnectionInfo *connectionInfo);
+int sme_mgt_connection_config_set(unifi_priv_t *priv, CsrWifiSmeConnectionConfig *connectionConfig);
+int sme_mgt_connection_config_get(unifi_priv_t *priv, CsrWifiSmeConnectionConfig *connectionConfig);
+int sme_mgt_connection_stats_get(unifi_priv_t *priv, CsrWifiSmeConnectionStats *connectionStats);
+
+int sme_mgt_versions_get(unifi_priv_t *priv, CsrWifiSmeVersions *versions);
+
+
+int sme_mgt_scan_full(unifi_priv_t *priv, CsrWifiSsid *specific_ssid,
+                      int num_channels, unsigned char *channel_list);
+int sme_mgt_scan_results_get_async(unifi_priv_t *priv,
+                                   struct iw_request_info *info,
+                                   char *scan_results,
+                                   long scan_results_len);
+int sme_mgt_disconnect(unifi_priv_t *priv);
+int sme_mgt_connect(unifi_priv_t *priv);
+int sme_mgt_key(unifi_priv_t *priv, CsrWifiSmeKey *sme_key,
+                CsrWifiSmeListAction action);
+int sme_mgt_pmkid(unifi_priv_t *priv, CsrWifiSmeListAction action,
+                  CsrWifiSmePmkidList *pmkid_list);
+int sme_mgt_mib_get(unifi_priv_t *priv,
+                    unsigned char *varbind, int *length);
+int sme_mgt_mib_set(unifi_priv_t *priv,
+                    unsigned char *varbind, int length);
+#ifdef CSR_SUPPORT_WEXT_AP
+int sme_ap_start(unifi_priv_t *priv,CsrUint16 interface_tag,CsrWifiSmeApConfig_t *ap_config);
+int sme_ap_stop(unifi_priv_t *priv,CsrUint16 interface_tag);
+int sme_ap_config(unifi_priv_t *priv,CsrWifiSmeApMacConfig *ap_mac_config, CsrWifiNmeApConfig *group_security_config);
+int uf_configure_supported_rates(CsrUint8 * supportedRates, CsrUint8 phySupportedBitmap);
+#endif
+int unifi_translate_scan(struct net_device *dev,
+                         struct iw_request_info *info,
+                         char *current_ev, char *end_buf,
+                         CsrWifiSmeScanResult *scan_data,
+                         int scan_index);
+
+#endif /* CSR_SUPPORT_WEXT */
+
+int unifi_cfg_power(unifi_priv_t *priv, unsigned char *arg);
+int unifi_cfg_power_save(unifi_priv_t *priv, unsigned char *arg);
+int unifi_cfg_power_supply(unifi_priv_t *priv, unsigned char *arg);
+int unifi_cfg_packet_filters(unifi_priv_t *priv, unsigned char *arg);
+int unifi_cfg_wmm_qos_info(unifi_priv_t *priv, unsigned char *arg);
+int unifi_cfg_wmm_addts(unifi_priv_t *priv, unsigned char *arg);
+int unifi_cfg_wmm_delts(unifi_priv_t *priv, unsigned char *arg);
+int unifi_cfg_get_info(unifi_priv_t *priv, unsigned char *arg);
+int unifi_cfg_strict_draft_n(unifi_priv_t *priv, unsigned char *arg);
+int unifi_cfg_enable_okc(unifi_priv_t *priv, unsigned char *arg);
+#ifdef CSR_SUPPORT_WEXT_AP
+int unifi_cfg_set_ap_config(unifi_priv_t * priv,unsigned char* arg);
+#endif
+
+
+
+int convert_sme_error(CsrResult error);
+
+
+#endif /* __LINUX_UNIFI_SME_H__ */
diff --git a/drivers/staging/csr/unifi_wext.h b/drivers/staging/csr/unifi_wext.h
new file mode 100644
index 0000000..ac86df9
--- /dev/null
+++ b/drivers/staging/csr/unifi_wext.h
@@ -0,0 +1,124 @@
+/*
+ *****************************************************************************
+ *
+ * FILE : unifi_wext.h
+ *
+ * PURPOSE : Private header file for unifi driver support to wireless extensions.
+ *
+ * Copyright (C) 2005-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+*****************************************************************************
+ */
+#ifndef __LINUX_UNIFI_WEXT_H__
+#define __LINUX_UNIFI_WEXT_H__ 1
+
+#include <linux/kernel.h>
+#include <net/iw_handler.h>
+#include "csr_wifi_sme_prim.h"
+
+/*
+ *      wext.c
+ */
+/* A few details needed for WEP (Wireless Equivalent Privacy) */
+#define UNIFI_MAX_KEY_SIZE      16
+#define NUM_WEPKEYS              4
+#define SMALL_KEY_SIZE           5
+#define LARGE_KEY_SIZE          13
+typedef struct wep_key_t {
+    int len;
+    unsigned char key[UNIFI_MAX_KEY_SIZE];  /* 40-bit and 104-bit keys */
+} wep_key_t;
+
+#define UNIFI_SCAN_ACTIVE       0
+#define UNIFI_SCAN_PASSIVE      1
+#define UNIFI_MAX_SSID_LEN      32
+
+#define MAX_WPA_IE_LEN 64
+#define MAX_RSN_IE_LEN 255
+
+/*
+ * Function to register in the netdev to report wireless stats.
+ */
+struct iw_statistics *unifi_get_wireless_stats(struct net_device *dev);
+
+void uf_sme_wext_set_defaults(unifi_priv_t *priv);
+
+
+/*
+ *      wext_events.c
+ */
+/* Functions to generate Wireless Extension events */
+void wext_send_scan_results_event(unifi_priv_t *priv);
+void wext_send_assoc_event(unifi_priv_t *priv, unsigned char *bssid,
+                           unsigned char *req_ie, int req_ie_len,
+                           unsigned char *resp_ie, int resp_ie_len,
+                           unsigned char *scan_ie, unsigned int scan_ie_len);
+void wext_send_disassoc_event(unifi_priv_t *priv);
+void wext_send_michaelmicfailure_event(unifi_priv_t *priv,
+                                       CsrUint16 count, CsrWifiMacAddress address,
+                                       CsrWifiSmeKeyType keyType, CsrUint16 interfaceTag);
+void wext_send_pmkid_candidate_event(unifi_priv_t *priv, CsrWifiMacAddress bssid, CsrBool preauth_allowed, CsrUint16 interfaceTag);
+void wext_send_started_event(unifi_priv_t *priv);
+
+
+static inline int
+uf_iwe_stream_add_point(struct iw_request_info *info, char *start, char *stop,
+                        struct iw_event *piwe, char *extra)
+{
+    char *new_start;
+
+    new_start = iwe_stream_add_point(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) || defined (IW_REQUEST_FLAG_COMPAT)
+                                     info,
+#endif
+                                     start, stop, piwe, extra);
+    if (unlikely(new_start == start))
+    {
+        return -E2BIG;
+    }
+
+    return (new_start - start);
+}
+
+
+static inline int
+uf_iwe_stream_add_event(struct iw_request_info *info, char *start, char *stop,
+                        struct iw_event *piwe, int len)
+{
+    char *new_start;
+
+    new_start = iwe_stream_add_event(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) || defined(IW_REQUEST_FLAG_COMPAT)
+                                     info,
+#endif
+                                     start, stop, piwe, len);
+    if (unlikely(new_start == start)) {
+        return -E2BIG;
+    }
+
+    return (new_start - start);
+}
+
+static inline int
+uf_iwe_stream_add_value(struct iw_request_info *info, char *stream, char *start,
+                        char *stop, struct iw_event *piwe, int len)
+{
+    char *new_start;
+
+    new_start = iwe_stream_add_value(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) || defined(IW_REQUEST_FLAG_COMPAT)
+                                     info,
+#endif
+                                     stream, start, stop, piwe, len);
+    if (unlikely(new_start == start)) {
+        return -E2BIG;
+    }
+
+    return (new_start - start);
+}
+
+
+#endif /* __LINUX_UNIFI_WEXT_H__ */
diff --git a/drivers/staging/csr/unifiio.h b/drivers/staging/csr/unifiio.h
new file mode 100644
index 0000000..4ab050b
--- /dev/null
+++ b/drivers/staging/csr/unifiio.h
@@ -0,0 +1,399 @@
+/*
+ * ---------------------------------------------------------------------------
+ *
+ *  FILE: unifiio.h
+ *
+ *      Public definitions for the UniFi linux driver.
+ *      This is mostly ioctl command values and structs.
+ *
+ *      Include <sys/ioctl.h> or similar before this file
+ *
+ * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#ifndef __UNIFIIO_H__
+#define __UNIFIIO_H__
+
+#include <linux/types.h>
+#include "csr_types.h"
+
+#define UNIFI_GET_UDI_ENABLE    _IOR('u',  1, int)
+#define UNIFI_SET_UDI_ENABLE    _IOW('u',  2, int)
+/* Values for UDI_ENABLE */
+#define UDI_ENABLE_DATA         0x1
+#define UDI_ENABLE_CONTROL      0x2
+
+/* MIB set/get. Arg is a pointer to a varbind */
+#define UNIFI_GET_MIB           _IOWR('u',  3, unsigned char *)
+#define UNIFI_SET_MIB           _IOW ('u',  4, unsigned char *)
+#define MAX_VARBIND_LENGTH 127
+
+/* Private IOCTLs */
+#define SIOCIWS80211POWERSAVEPRIV           SIOCIWFIRSTPRIV
+#define SIOCIWG80211POWERSAVEPRIV           SIOCIWFIRSTPRIV + 1
+#define SIOCIWS80211RELOADDEFAULTSPRIV      SIOCIWFIRSTPRIV + 2
+#define SIOCIWSCONFWAPIPRIV                 SIOCIWFIRSTPRIV + 4
+#define SIOCIWSWAPIKEYPRIV                  SIOCIWFIRSTPRIV + 6
+#define SIOCIWSSMEDEBUGPRIV                 SIOCIWFIRSTPRIV + 8
+#define SIOCIWSAPCFGPRIV                    SIOCIWFIRSTPRIV + 10
+#define SIOCIWSAPSTARTPRIV                  SIOCIWFIRSTPRIV + 12
+#define SIOCIWSAPSTOPPRIV                   SIOCIWFIRSTPRIV + 14
+#define SIOCIWSFWRELOADPRIV                 SIOCIWFIRSTPRIV + 16
+#define SIOCIWSSTACKSTART                   SIOCIWFIRSTPRIV + 18
+#define SIOCIWSSTACKSTOP                    SIOCIWFIRSTPRIV + 20
+
+
+
+#define IWPRIV_POWER_SAVE_MAX_STRING 32
+#define IWPRIV_SME_DEBUG_MAX_STRING 32
+#define IWPRIV_SME_MAX_STRING 120
+
+
+/* Private configuration commands */
+#define UNIFI_CFG               _IOWR('u',  5, unsigned char *)
+/*
+ * <------------------  Read/Write Buffer  -------------------->
+ * _____________________________________________________________
+ * |    Cmd    |    Arg    |   ...  Buffer (opt)  ...          |
+ * -------------------------------------------------------------
+ * <-- uint --><-- uint --><-----  unsigned char buffer  ------>
+ *
+ * Cmd:    A unifi_cfg_command_t command.
+ * Arg:    Out:Length     if Cmd==UNIFI_CFG_GET
+ *         In:PowerOnOff  if Cmd==UNIFI_CFG_POWER
+ *         In:PowerMode   if Cmd==UNIFI_CFG_POWERSAVE
+ *         In:Length      if Cmd==UNIFI_CFG_FILTER
+ *         In:WMM Qos Info if Cmd==UNIFI_CFG_WMM_QOS_INFO
+ * Buffer: Out:Data       if Cmd==UNIFI_CFG_GET
+ *         NULL           if Cmd==UNIFI_CFG_POWER
+ *         NULL           if Cmd==UNIFI_CFG_POWERSAVE
+ *         In:Filters     if Cmd==UNIFI_CFG_FILTER
+ *
+ * where Filters is a uf_cfg_bcast_packet_filter_t structure
+ * followed by 0 - n tclas_t structures. The length of the tclas_t
+ * structures is obtained by uf_cfg_bcast_packet_filter_t::tclas_ies_length.
+ */
+
+
+#define UNIFI_PUTEST            _IOWR('u',  6, unsigned char *)
+/*
+ * <------------------  Read/Write Buffer  -------------------->
+ * _____________________________________________________________
+ * |    Cmd    |    Arg    |   ...  Buffer (opt)  ...          |
+ * -------------------------------------------------------------
+ * <-- uint --><-- uint --><-----  unsigned char buffer  ------>
+ *
+ * Cmd:    A unifi_putest_command_t command.
+ * Arg:    N/A                           if Cmd==UNIFI_PUTEST_START
+ *         N/A                           if Cmd==UNIFI_PUTEST_STOP
+ *         In:int (Clock Speed)          if Cmd==UNIFI_PUTEST_SET_SDIO_CLOCK
+ *         In/Out:sizeof(unifi_putest_cmd52) if Cmd==UNIFI_PUTEST_CMD52_READ
+ *         In:sizeof(unifi_putest_cmd52) if Cmd==UNIFI_PUTEST_CMD52_WRITE
+ *         In:uint (f/w file name length) if Cmd==UNIFI_PUTEST_DL_FW
+ * Buffer: NULL                          if Cmd==UNIFI_PUTEST_START
+ *         NULL                          if Cmd==UNIFI_PUTEST_STOP
+ *         NULL                          if Cmd==UNIFI_PUTEST_SET_SDIO_CLOCK
+ *         In/Out:unifi_putest_cmd52     if Cmd==UNIFI_PUTEST_CMD52_READ
+ *         In:unifi_putest_cmd52         if Cmd==UNIFI_PUTEST_CMD52_WRITE
+ *         In:f/w file name              if Cmd==UNIFI_PUTEST_DL_FW
+ */
+
+#define UNIFI_BUILD_TYPE _IOWR('u', 7, unsigned char)
+#define UNIFI_BUILD_NME 1
+#define UNIFI_BUILD_WEXT 2
+#define UNIFI_BUILD_AP 3
+
+/* debugging */
+#define UNIFI_KICK              _IO ('u',  0x10)
+#define UNIFI_SET_DEBUG         _IO ('u',  0x11)
+#define UNIFI_SET_TRACE         _IO ('u',  0x12)
+
+#define UNIFI_GET_INIT_STATUS   _IOR ('u', 0x15, int)
+#define UNIFI_SET_UDI_LOG_MASK  _IOR('u',  0x18, unifiio_filter_t)
+#define UNIFI_SET_UDI_SNAP_MASK _IOW('u',  0x1a, unifiio_snap_filter_t)
+#define UNIFI_SET_AMP_ENABLE    _IOWR('u',  0x1b, int)
+
+#define UNIFI_INIT_HW           _IOR ('u', 0x13, unsigned char)
+#define UNIFI_INIT_NETDEV       _IOW ('u', 0x14, unsigned char[6])
+#define UNIFI_SME_PRESENT       _IOW ('u', 0x19, int)
+
+#define UNIFI_CFG_PERIOD_TRAFFIC _IOW ('u', 0x21, unsigned char *)
+#define UNIFI_CFG_UAPSD_TRAFFIC _IOW ('u', 0x22, unsigned char)
+
+#define UNIFI_COREDUMP_GET_REG  _IOWR('u', 0x23, unifiio_coredump_req_t)
+
+
+/*
+ * Following reset, f/w may only be downloaded using CMD52.
+ * This is slow, so there is a facility to download a secondary
+ * loader first which supports CMD53.
+ * If loader_len is > 0, then loader_data is assumed to point to
+ * a suitable secondary loader that can be used to download the
+ * main image.
+ *
+ * The driver will run the host protocol initialisation sequence
+ * after downloading the image.
+ *
+ * If both lengths are zero, then the f/w is assumed to have been
+ * booted from Flash and the host protocol initialisation sequence
+ * is run.
+ */
+typedef struct {
+
+    /* Number of bytes in the image */
+    int img_len;
+
+    /* Pointer to image data. */
+    unsigned char *img_data;
+
+
+    /* Number of bytes in the loader image */
+    int loader_len;
+
+    /* Pointer to loader image data. */
+    unsigned char *loader_data;
+
+} unifiio_img_t;
+
+
+/* Structure of data read from the unifi device. */
+typedef struct
+{
+    /* Length (in bytes) of entire structure including appended bulk data */
+    int length;
+
+    /* System time (in milliseconds) that signal was transferred */
+    int timestamp;
+
+    /* Direction in which signal was transferred. */
+    int direction;
+#define UDI_FROM_HOST   0
+#define UDI_TO_HOST     1
+#define UDI_CONFIG_IND  2
+
+    /* The length of the signal (in bytes) not including bulk data */
+    int signal_length;
+
+    /* Signal body follows, then any bulk data */
+
+} udi_msg_t;
+
+
+typedef enum
+{
+    UfSigFil_AllOn = 0,         /* Log all signal IDs */
+    UfSigFil_AllOff = 1,        /* Don't log any signal IDs */
+    UfSigFil_SelectOn = 2,      /* Log these signal IDs */
+    UfSigFil_SelectOff = 3      /* Don't log these signal IDs */
+} uf_sigfilter_action_t;
+
+typedef struct {
+
+    /* Number of 16-bit ints in the sig_ids array */
+    int num_sig_ids;
+    /* The action to perform */
+    uf_sigfilter_action_t action;
+    /* List of signal IDs to pass or block */
+    unsigned short *sig_ids;
+
+} unifiio_filter_t;
+
+
+typedef struct {
+    /* Number of 16-bit ints in the protocols array */
+    CsrUint16 count;
+    /* List of protocol ids to pass */
+    CsrUint16 *protocols;
+} unifiio_snap_filter_t;
+
+
+
+typedef CsrUint8 unifi_putest_command_t;
+
+#define UNIFI_PUTEST_START 0
+#define UNIFI_PUTEST_STOP 1
+#define UNIFI_PUTEST_SET_SDIO_CLOCK 2
+#define UNIFI_PUTEST_CMD52_READ 3
+#define UNIFI_PUTEST_CMD52_WRITE 4
+#define UNIFI_PUTEST_DL_FW 5
+#define UNIFI_PUTEST_DL_FW_BUFF 6
+#define UNIFI_PUTEST_CMD52_BLOCK_READ 7
+#define UNIFI_PUTEST_COREDUMP_PREPARE 8
+#define UNIFI_PUTEST_GP_READ16 9
+#define UNIFI_PUTEST_GP_WRITE16 10
+
+
+struct unifi_putest_cmd52 {
+    int funcnum;
+    unsigned long addr;
+    unsigned char data;
+};
+
+
+struct unifi_putest_block_cmd52_r {
+    int           funcnum;
+    unsigned long addr;
+    unsigned int  length;
+    unsigned char *data;
+};
+
+struct unifi_putest_gp_rw16 {
+    unsigned long addr;        /* generic address */
+    unsigned short data;
+};
+
+typedef enum unifi_cfg_command {
+    UNIFI_CFG_GET,
+    UNIFI_CFG_POWER,
+    UNIFI_CFG_POWERSAVE,
+    UNIFI_CFG_FILTER,
+    UNIFI_CFG_POWERSUPPLY,
+    UNIFI_CFG_WMM_QOSINFO,
+    UNIFI_CFG_WMM_ADDTS,
+    UNIFI_CFG_WMM_DELTS,
+    UNIFI_CFG_STRICT_DRAFT_N,
+    UNIFI_CFG_ENABLE_OKC,
+    UNIFI_CFG_SET_AP_CONFIG,
+    UNIFI_CFG_CORE_DUMP /* request to take a fw core dump */
+} unifi_cfg_command_t;
+
+typedef enum unifi_cfg_power {
+    UNIFI_CFG_POWER_UNSPECIFIED,
+    UNIFI_CFG_POWER_OFF,
+    UNIFI_CFG_POWER_ON
+} unifi_cfg_power_t;
+
+typedef enum unifi_cfg_powersupply {
+    UNIFI_CFG_POWERSUPPLY_UNSPECIFIED,
+    UNIFI_CFG_POWERSUPPLY_MAINS,
+    UNIFI_CFG_POWERSUPPLY_BATTERIES
+} unifi_cfg_powersupply_t;
+
+typedef enum unifi_cfg_powersave {
+    UNIFI_CFG_POWERSAVE_UNSPECIFIED,
+    UNIFI_CFG_POWERSAVE_NONE,
+    UNIFI_CFG_POWERSAVE_FAST,
+    UNIFI_CFG_POWERSAVE_FULL,
+    UNIFI_CFG_POWERSAVE_AUTO
+} unifi_cfg_powersave_t;
+
+typedef enum unifi_cfg_get {
+    UNIFI_CFG_GET_COEX,
+    UNIFI_CFG_GET_POWER_MODE,
+    UNIFI_CFG_GET_VERSIONS,
+    UNIFI_CFG_GET_POWER_SUPPLY,
+    UNIFI_CFG_GET_INSTANCE,
+    UNIFI_CFG_GET_AP_CONFIG
+} unifi_cfg_get_t;
+
+#define UNIFI_CFG_FILTER_NONE            0x0000
+#define UNIFI_CFG_FILTER_DHCP            0x0001
+#define UNIFI_CFG_FILTER_ARP             0x0002
+#define UNIFI_CFG_FILTER_NBNS            0x0004
+#define UNIFI_CFG_FILTER_NBDS            0x0008
+#define UNIFI_CFG_FILTER_CUPS            0x0010
+#define UNIFI_CFG_FILTER_ALL             0xFFFF
+
+
+typedef struct uf_cfg_bcast_packet_filter
+{
+    unsigned long filter_mode;     //as defined by HIP protocol
+    unsigned char arp_filter;
+    unsigned char dhcp_filter;
+    unsigned long tclas_ies_length; // length of tclas_ies in bytes
+    unsigned char tclas_ies[1];    // variable length depending on above field
+} uf_cfg_bcast_packet_filter_t;
+
+typedef struct uf_cfg_ap_config
+{
+    CsrUint8    phySupportedBitmap;
+    CsrUint8    channel;
+    CsrUint16   beaconInterval;
+    CsrUint8    dtimPeriod;
+    CsrBool     wmmEnabled;
+    CsrUint8    shortSlotTimeEnabled;
+    CsrUint16   groupkeyTimeout;
+    CsrBool     strictGtkRekeyEnabled;
+    CsrUint16   gmkTimeout;
+    CsrUint16   responseTimeout;
+    CsrUint8    retransLimit;
+    CsrUint8    rxStbc;
+    CsrBool     rifsModeAllowed;
+    CsrUint8    dualCtsProtection;
+    CsrUint8    ctsProtectionType;
+    CsrUint16   maxListenInterval;
+}uf_cfg_ap_config_t;
+
+typedef struct tcpic_clsfr
+{
+    __u8 cls_fr_type;
+    __u8 cls_fr_mask;
+    __u8 version;
+    __u8 source_ip_addr[4];
+    __u8 dest_ip_addr[4];
+    __u16 source_port;
+    __u16 dest_port;
+    __u8 dscp;
+    __u8 protocol;
+    __u8 reserved;
+} __attribute__ ((packed)) tcpip_clsfr_t;
+
+typedef struct tclas {
+    __u8 element_id;
+    __u8 length;
+    __u8 user_priority;
+    tcpip_clsfr_t tcp_ip_cls_fr;
+} __attribute__ ((packed)) tclas_t;
+
+
+#define CONFIG_IND_ERROR            0x01
+#define CONFIG_IND_EXIT             0x02
+#define CONFIG_SME_NOT_PRESENT      0x10
+#define CONFIG_SME_PRESENT          0x20
+
+/* WAPI Key */
+typedef struct
+{
+    CsrUint8                          unicastKey;
+    /* If non zero, then unicast key otherwise group key */
+    CsrUint8                          keyIndex;
+    CsrUint8                          keyRsc[16];
+    CsrUint8                          authenticator;
+    /* If non zero, then authenticator otherwise supplicant */
+    CsrUint8                          address[6];
+    CsrUint8                          key[32];
+} unifiio_wapi_key_t;
+
+/* Values describing XAP memory regions captured by the mini-coredump system */
+typedef enum unifiio_coredump_space {
+    UNIFIIO_COREDUMP_MAC_REG,
+    UNIFIIO_COREDUMP_PHY_REG,
+    UNIFIIO_COREDUMP_SH_DMEM,
+    UNIFIIO_COREDUMP_MAC_DMEM,
+    UNIFIIO_COREDUMP_PHY_DMEM,
+    UNIFIIO_COREDUMP_TRIGGER_MAGIC = 0xFEED
+} unifiio_coredump_space_t;
+
+/* Userspace tool uses this structure to retrieve a register value from a
+ * mini-coredump buffer previously saved by the HIP
+ */
+typedef struct unifiio_coredump_req {
+    /* From user */
+    int index;                      /* 0=newest, -1=oldest */
+    unsigned int offset;            /* register offset in space */
+    unifiio_coredump_space_t space; /* memory space */
+    /* Filled by driver */
+    unsigned int drv_build;         /* driver build id */
+    unsigned int chip_ver;          /* chip version */
+    unsigned int fw_ver;            /* firmware version */
+    int requestor;                  /* requestor: 0=auto dump, 1=manual */
+    unsigned int timestamp;         /* time of capture by driver */
+    unsigned int serial;            /* capture serial number */
+    int value;                      /* 16 bit register value, -ve for error */
+} unifiio_coredump_req_t;           /* Core-dumped register value request */
+
+#endif /* __UNIFIIO_H__ */
diff --git a/drivers/staging/csr/wext_events.c b/drivers/staging/csr/wext_events.c
new file mode 100644
index 0000000..5674782
--- /dev/null
+++ b/drivers/staging/csr/wext_events.c
@@ -0,0 +1,285 @@
+/*
+ * ---------------------------------------------------------------------------
+ * FILE:     wext_events.c
+ *
+ * PURPOSE:
+ *      Code to generate iwevents.
+ *
+ * Copyright (C) 2006-2008 by Cambridge Silicon Radio Ltd.
+ *
+ * Refer to LICENSE.txt included with this source code for details on
+ * the license terms.
+ *
+ * ---------------------------------------------------------------------------
+ */
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include "csr_wifi_hip_unifi.h"
+#include "unifi_priv.h"
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  wext_send_assoc_event
+ *
+ *      Send wireless-extension events up to userland to announce
+ *      successful association with an AP.
+ *
+ *  Arguments:
+ *      priv                    Pointer to driver context.
+ *      bssid                   MAC address of AP we associated with
+ *      req_ie, req_ie_len      IEs in the original request
+ *      resp_ie, resp_ie_len    IEs in the response
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *      This is sent on first successful association, and again if we
+ *      roam to another AP.
+ * ---------------------------------------------------------------------------
+ */
+void
+wext_send_assoc_event(unifi_priv_t *priv, unsigned char *bssid,
+                      unsigned char *req_ie, int req_ie_len,
+                      unsigned char *resp_ie, int resp_ie_len,
+                      unsigned char *scan_ie, unsigned int scan_ie_len)
+{
+#if WIRELESS_EXT > 17
+    union iwreq_data wrqu;
+
+    if (req_ie_len == 0) req_ie = NULL;
+    wrqu.data.length = req_ie_len;
+    wrqu.data.flags = 0;
+    wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVASSOCREQIE, &wrqu, req_ie);
+
+    if (resp_ie_len == 0) resp_ie = NULL;
+    wrqu.data.length = resp_ie_len;
+    wrqu.data.flags = 0;
+    wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVASSOCRESPIE, &wrqu, resp_ie);
+
+    if (scan_ie_len > 0) {
+        wrqu.data.length = scan_ie_len;
+        wrqu.data.flags = 0;
+        wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVGENIE, &wrqu, scan_ie);
+    }
+
+    memcpy(&wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
+    wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], SIOCGIWAP, &wrqu, NULL);
+#endif
+} /* wext_send_assoc_event() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  wext_send_disassoc_event
+ *
+ *      Send a wireless-extension event up to userland to announce
+ *      that we disassociated from an AP.
+ *
+ *  Arguments:
+ *      priv                    Pointer to driver context.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *      The semantics of wpa_supplicant (the userland SME application) are
+ *      that a SIOCGIWAP event with MAC address of all zero means
+ *      disassociate.
+ * ---------------------------------------------------------------------------
+ */
+void
+wext_send_disassoc_event(unifi_priv_t *priv)
+{
+#if WIRELESS_EXT > 17
+    union iwreq_data wrqu;
+
+    memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+    wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], SIOCGIWAP, &wrqu, NULL);
+#endif
+} /* wext_send_disassoc_event() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  wext_send_scan_results_event
+ *
+ *      Send wireless-extension events up to userland to announce
+ *      completion of a scan.
+ *
+ *  Arguments:
+ *      priv                    Pointer to driver context.
+ *
+ *  Returns:
+ *      None.
+ *
+ *  Notes:
+ *      This doesn't actually report the results, they are retrieved
+ *      using the SIOCGIWSCAN ioctl command.
+ * ---------------------------------------------------------------------------
+ */
+void
+wext_send_scan_results_event(unifi_priv_t *priv)
+{
+#if WIRELESS_EXT > 17
+    union iwreq_data wrqu;
+
+    wrqu.data.length = 0;
+    wrqu.data.flags = 0;
+    wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], SIOCGIWSCAN, &wrqu, NULL);
+
+#endif
+} /* wext_send_scan_results_event() */
+
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  wext_send_michaelmicfailure_event
+ *
+ *      Send wireless-extension events up to userland to announce
+ *      completion of a scan.
+ *
+ *  Arguments:
+ *      priv            Pointer to driver context.
+ *      count, macaddr, key_type, key_idx, tsc
+ *                      Parameters from report from UniFi.
+ *
+ *  Returns:
+ *      None.
+ * ---------------------------------------------------------------------------
+ */
+#if WIRELESS_EXT >= 18
+static inline void
+_send_michaelmicfailure_event(struct net_device *dev,
+                              int count, const unsigned char *macaddr,
+                              int key_type, int key_idx,
+                              unsigned char *tsc)
+{
+    union iwreq_data wrqu;
+    struct iw_michaelmicfailure mmf;
+
+    memset(&mmf, 0, sizeof(mmf));
+
+    mmf.flags = key_idx & IW_MICFAILURE_KEY_ID;
+    if (key_type == CSR_GROUP) {
+        mmf.flags |= IW_MICFAILURE_GROUP;
+    } else {
+        mmf.flags |= IW_MICFAILURE_PAIRWISE;
+    }
+    mmf.flags |= ((count << 5) & IW_MICFAILURE_COUNT);
+
+    mmf.src_addr.sa_family = ARPHRD_ETHER;
+    memcpy(mmf.src_addr.sa_data, macaddr, ETH_ALEN);
+
+    memcpy(mmf.tsc, tsc, IW_ENCODE_SEQ_MAX_SIZE);
+
+    memset(&wrqu, 0, sizeof(wrqu));
+    wrqu.data.length = sizeof(mmf);
+
+    wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&mmf);
+}
+#elif WIRELESS_EXT >= 15
+static inline void
+_send_michaelmicfailure_event(struct net_device *dev,
+                              int count, const unsigned char *macaddr,
+                              int key_type, int key_idx,
+                              unsigned char *tsc)
+{
+    union iwreq_data wrqu;
+    char buf[128];
+
+    sprintf(buf,
+            "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=%02x:%02x:%02x:%02x:%02x:%02x)",
+            key_idx, (key_type == CSR_GROUP) ? "broad" : "uni",
+            macaddr[0], macaddr[1], macaddr[2],
+            macaddr[3], macaddr[4], macaddr[5]);
+    memset(&wrqu, 0, sizeof(wrqu));
+    wrqu.data.length = strlen(buf);
+    wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+}
+#else /* WIRELESS_EXT >= 15 */
+static inline void
+_send_michaelmicfailure_event(struct net_device *dev,
+                              int count, const unsigned char *macaddr,
+                              int key_type, int key_idx,
+                              unsigned char *tsc)
+{
+    /* Not supported before WEXT 15 */
+}
+#endif /* WIRELESS_EXT >= 15 */
+
+
+void
+wext_send_michaelmicfailure_event(unifi_priv_t *priv,
+                                  CsrUint16 count,
+                                  CsrWifiMacAddress address,
+                                  CsrWifiSmeKeyType keyType,
+                                  CsrUint16 interfaceTag)
+{
+    unsigned char tsc[8] = {0};
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "wext_send_michaelmicfailure_event bad interfaceTag\n");
+        return;
+    }
+
+    _send_michaelmicfailure_event(priv->netdev[interfaceTag],
+                                  count,
+                                  address.a,
+                                  keyType,
+                                  0,
+                                  tsc);
+} /* wext_send_michaelmicfailure_event() */
+
+void
+wext_send_pmkid_candidate_event(unifi_priv_t *priv, CsrWifiMacAddress bssid, CsrBool preauth_allowed, CsrUint16 interfaceTag)
+{
+#if WIRELESS_EXT > 17
+    union iwreq_data wrqu;
+    struct iw_pmkid_cand pmkid_cand;
+
+    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
+        unifi_error(priv, "wext_send_pmkid_candidate_event bad interfaceTag\n");
+        return;
+    }
+
+    memset(&pmkid_cand, 0, sizeof(pmkid_cand));
+
+    if (preauth_allowed) {
+        pmkid_cand.flags |= IW_PMKID_CAND_PREAUTH;
+    }
+    pmkid_cand.bssid.sa_family = ARPHRD_ETHER;
+    memcpy(pmkid_cand.bssid.sa_data, bssid.a, ETH_ALEN);
+    /* Used as priority, smaller the number higher the priority, not really used in our case */
+    pmkid_cand.index = 1;
+
+    memset(&wrqu, 0, sizeof(wrqu));
+    wrqu.data.length = sizeof(pmkid_cand);
+
+    wireless_send_event(priv->netdev[interfaceTag], IWEVPMKIDCAND, &wrqu, (char *)&pmkid_cand);
+#endif
+} /* wext_send_pmkid_candidate_event() */
+
+/*
+ * Send a custom WEXT event to say we have completed initialisation
+ * and are now ready for WEXT ioctls. Used by Android wpa_supplicant.
+ */
+void
+wext_send_started_event(unifi_priv_t *priv)
+{
+#if WIRELESS_EXT > 17
+    union iwreq_data wrqu;
+    char data[] = "STARTED";
+
+    wrqu.data.length = sizeof(data);
+    wrqu.data.flags = 0;
+    wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVCUSTOM, &wrqu, data);
+#endif
+} /* wext_send_started_event() */
+
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
index 5b11c5e..8f3fc5f 100644
--- a/drivers/staging/et131x/et131x.c
+++ b/drivers/staging/et131x/et131x.c
@@ -85,8 +85,7 @@
 MODULE_AUTHOR("Victor Soriano <vjsoriano@agere.com>");
 MODULE_AUTHOR("Mark Einon <mark.einon@gmail.com>");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_DESCRIPTION("10/100/1000 Base-T Ethernet Driver "
-		   "for the ET1310 by Agere Systems");
+MODULE_DESCRIPTION("10/100/1000 Base-T Ethernet Driver for the ET1310 by Agere Systems");
 
 /* EEPROM defines */
 #define MAX_NUM_REGISTER_POLLS          1000
@@ -1767,8 +1766,8 @@ static void et131x_xcvr_init(struct et131x_adapter *adapter)
 	/* Set the link status interrupt only.  Bad behavior when link status
 	 * and auto neg are set, we run into a nested interrupt problem
 	 */
-	imr |= (ET_PHY_INT_MASK_AUTONEGSTAT &
-		ET_PHY_INT_MASK_LINKSTAT &
+	imr |= (ET_PHY_INT_MASK_AUTONEGSTAT |
+		ET_PHY_INT_MASK_LINKSTAT |
 		ET_PHY_INT_MASK_ENABLE);
 
 	et131x_mii_write(adapter, PHY_INTERRUPT_MASK, imr);
@@ -1784,7 +1783,7 @@ static void et131x_xcvr_init(struct et131x_adapter *adapter)
 	if ((adapter->eeprom_data[1] & 0x4) == 0) {
 		et131x_mii_read(adapter, PHY_LED_2, &lcr2);
 
-		lcr2 &= (ET_LED2_LED_100TX & ET_LED2_LED_1000T);
+		lcr2 &= (ET_LED2_LED_100TX | ET_LED2_LED_1000T);
 		lcr2 |= (LED_VAL_LINKON_ACTIVE << LED_LINK_SHIFT);
 
 		if ((adapter->eeprom_data[1] & 0x8) == 0)
@@ -2967,11 +2966,10 @@ static struct rfd *nic_rx_pkts(struct et131x_adapter *adapter)
 		(ring_index == 0 &&
 		buff_index > rx_local->fbr[1]->num_entries - 1) ||
 		(ring_index == 1 &&
-		buff_index > rx_local->fbr[0]->num_entries - 1))
+		buff_index > rx_local->fbr[0]->num_entries - 1)) {
 #else
-	if (ring_index != 1 || buff_index > rx_local->fbr[0]->num_entries - 1)
+	if (ring_index != 1 || buff_index > rx_local->fbr[0]->num_entries - 1) {
 #endif
-	{
 		/* Illegal buffer or ring index cannot be used by S/W*/
 		dev_err(&adapter->pdev->dev,
 			  "NICRxPkts PSR Entry %d indicates "
@@ -4326,8 +4324,7 @@ static int et131x_mii_probe(struct net_device *netdev)
 	phydev->advertising = phydev->supported;
 	adapter->phydev = phydev;
 
-	dev_info(&adapter->pdev->dev, "attached PHY driver [%s] "
-		 "(mii_bus:phy_addr=%s)\n",
+	dev_info(&adapter->pdev->dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
 		 phydev->drv->name, dev_name(&phydev->dev));
 
 	return 0;
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
index 43b1d36..c1f4f13 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
@@ -1178,7 +1178,6 @@ static int ft1000_open(struct net_device *dev)
 {
 	struct ft1000_info *pInfo = netdev_priv(dev);
 	struct timeval tv;
-	int ret;
 
 	DEBUG("ft1000_open is called for card %d\n", pInfo->CardNumber);
 
@@ -1194,9 +1193,7 @@ static int ft1000_open(struct net_device *dev)
 
 	netif_carrier_on(dev);
 
-	ret = ft1000_submit_rx_urb(pInfo);
-
-	return ret;
+	return ft1000_submit_rx_urb(pInfo);
 }
 
 //---------------------------------------------------------------------------
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c
index 84c38d5..bfead67 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c
@@ -67,15 +67,13 @@ static int ft1000_probe(struct usb_interface *interface,
 	struct ft1000_info *pft1000info = NULL;
 	const struct firmware *dsp_fw;
 
-	ft1000dev = kmalloc(sizeof(struct ft1000_device), GFP_KERNEL);
+	ft1000dev = kzalloc(sizeof(struct ft1000_device), GFP_KERNEL);
 
 	if (!ft1000dev) {
 		printk(KERN_ERR "out of memory allocating device structure\n");
-		return 0;
+		return -ENOMEM;
 	}
 
-	memset(ft1000dev, 0, sizeof(*ft1000dev));
-
 	dev = interface_to_usbdev(interface);
 	DEBUG("ft1000_probe: usb device descriptor info:\n");
 	DEBUG("ft1000_probe: number of configuration is %d\n",
diff --git a/drivers/staging/gdm72xx/gdm_qos.c b/drivers/staging/gdm72xx/gdm_qos.c
index 0217680..e7134e2 100644
--- a/drivers/staging/gdm72xx/gdm_qos.c
+++ b/drivers/staging/gdm72xx/gdm_qos.c
@@ -11,7 +11,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/version.h>
 #include <linux/etherdevice.h>
 #include <asm/byteorder.h>
 
diff --git a/drivers/staging/gdm72xx/gdm_sdio.c b/drivers/staging/gdm72xx/gdm_sdio.c
index e1a3dd2..5e19b09 100644
--- a/drivers/staging/gdm72xx/gdm_sdio.c
+++ b/drivers/staging/gdm72xx/gdm_sdio.c
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 
 #include <linux/mmc/core.h>
 #include <linux/mmc/card.h>
diff --git a/drivers/staging/gdm72xx/gdm_usb.c b/drivers/staging/gdm72xx/gdm_usb.c
index 1e9dc0d..89268c7 100644
--- a/drivers/staging/gdm72xx/gdm_usb.c
+++ b/drivers/staging/gdm72xx/gdm_usb.c
@@ -12,10 +12,10 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/usb.h>
 #include <asm/byteorder.h>
+#include <linux/kthread.h>
 
 #include "gdm_usb.h"
 #include "gdm_wimax.h"
@@ -270,20 +270,17 @@ static void release_usb(struct usbwm_dev *udev)
 	}
 }
 
-static void gdm_usb_send_complete(struct urb *urb)
+static void __gdm_usb_send_complete(struct urb *urb)
 {
 	struct usb_tx *t = urb->context;
 	struct tx_cxt *tx = t->tx_cxt;
 	u8 *pkt = t->buf;
 	u16 cmd_evt;
-	unsigned long flags;
 
 	/* Completion by usb_unlink_urb */
 	if (urb->status == -ECONNRESET)
 		return;
 
-	spin_lock_irqsave(&tx->lock, flags);
-
 	if (t->callback)
 		t->callback(t->cb_data);
 
@@ -295,7 +292,16 @@ static void gdm_usb_send_complete(struct urb *urb)
 		put_tx_struct(tx, t);
 	else
 		free_tx_struct(t);
+}
+
+static void gdm_usb_send_complete(struct urb *urb)
+{
+	struct usb_tx *t = urb->context;
+	struct tx_cxt *tx = t->tx_cxt;
+	unsigned long flags;
 
+	spin_lock_irqsave(&tx->lock, flags);
+	__gdm_usb_send_complete(urb);
 	spin_unlock_irqrestore(&tx->lock, flags);
 }
 
@@ -411,7 +417,7 @@ out:
 
 send_fail:
 	t->callback = NULL;
-	gdm_usb_send_complete(t->urb);
+	__gdm_usb_send_complete(t->urb);
 	spin_unlock_irqrestore(&tx->lock, flags);
 	return ret;
 }
@@ -540,7 +546,7 @@ static void do_pm_control(struct work_struct *work)
 
 			if (ret) {
 				t->callback = NULL;
-				gdm_usb_send_complete(t->urb);
+				__gdm_usb_send_complete(t->urb);
 			}
 		}
 	}
@@ -742,7 +748,7 @@ static int k_mode_thread(void *arg)
 
 				if (ret) {
 					t->callback = NULL;
-					gdm_usb_send_complete(t->urb);
+					__gdm_usb_send_complete(t->urb);
 				}
 			}
 
@@ -775,7 +781,7 @@ static struct usb_driver gdm_usb_driver = {
 static int __init usb_gdm_wimax_init(void)
 {
 #ifdef CONFIG_WIMAX_GDM72XX_K_MODE
-	kernel_thread(k_mode_thread, NULL, CLONE_KERNEL);
+	kthread_run(k_mode_thread, NULL, "WiMax_thread");
 #endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
 	return usb_register(&gdm_usb_driver);
 }
diff --git a/drivers/staging/gdm72xx/gdm_wimax.c b/drivers/staging/gdm72xx/gdm_wimax.c
index f1936b9..110bdbc 100644
--- a/drivers/staging/gdm72xx/gdm_wimax.c
+++ b/drivers/staging/gdm72xx/gdm_wimax.c
@@ -11,7 +11,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/version.h>
 #include <linux/etherdevice.h>
 #include <asm/byteorder.h>
 #include <linux/ip.h>
diff --git a/drivers/staging/gdm72xx/gdm_wimax.h b/drivers/staging/gdm72xx/gdm_wimax.h
index 023e649..6ec0ab4 100644
--- a/drivers/staging/gdm72xx/gdm_wimax.h
+++ b/drivers/staging/gdm72xx/gdm_wimax.h
@@ -15,7 +15,6 @@
 #define __GDM_WIMAX_H__
 
 #include <linux/netdevice.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include "wm_ioctl.h"
 #if defined(CONFIG_WIMAX_GDM72XX_QOS)
diff --git a/drivers/staging/gdm72xx/netlink_k.c b/drivers/staging/gdm72xx/netlink_k.c
index 5166513..064815b 100644
--- a/drivers/staging/gdm72xx/netlink_k.c
+++ b/drivers/staging/gdm72xx/netlink_k.c
@@ -11,7 +11,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/etherdevice.h>
 #include <linux/netlink.h>
@@ -127,8 +126,13 @@ int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
 	}
 
 	seq++;
-	nlh = NLMSG_PUT(skb, 0, seq, type, len);
-	memcpy(NLMSG_DATA(nlh), msg, len);
+	nlh = nlmsg_put(skb, 0, seq, type, len, 0);
+	if (!nlh) {
+		kfree_skb(skb);
+		return -EMSGSIZE;
+	}
+
+	memcpy(nlmsg_data(nlh), msg, len);
 
 	NETLINK_CB(skb).pid = 0;
 	NETLINK_CB(skb).dst_group = 0;
@@ -145,6 +149,5 @@ int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
 		ret = 0;
 	}
 
-nlmsg_failure:
 	return ret;
 }
diff --git a/drivers/staging/gdm72xx/sdio_boot.c b/drivers/staging/gdm72xx/sdio_boot.c
index 6ff4dc3..760efee 100644
--- a/drivers/staging/gdm72xx/sdio_boot.c
+++ b/drivers/staging/gdm72xx/sdio_boot.c
@@ -12,7 +12,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mm.h>
diff --git a/drivers/staging/gdm72xx/usb_boot.c b/drivers/staging/gdm72xx/usb_boot.c
index 5a0e030..c163bcc 100644
--- a/drivers/staging/gdm72xx/usb_boot.c
+++ b/drivers/staging/gdm72xx/usb_boot.c
@@ -13,7 +13,6 @@
 
 #include <linux/uaccess.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/usb.h>
diff --git a/drivers/staging/iio/Documentation/device.txt b/drivers/staging/iio/Documentation/device.txt
index f03fbd3..ea08d62 100644
--- a/drivers/staging/iio/Documentation/device.txt
+++ b/drivers/staging/iio/Documentation/device.txt
@@ -12,7 +12,7 @@ struct iio_dev *indio_dev = iio_device_alloc(sizeof(struct chip_state));
 where chip_state is a structure of local state data for this instance of
 the chip.
 
-That data can be accessed using iio_priv(struct iio_dev *)
+That data can be accessed using iio_priv(struct iio_dev *).
 
 Then fill in the following:
 
@@ -39,7 +39,7 @@ Then fill in the following:
 		and for associate parameters such as offsets and scales.
 	* info->write_raw:
 		Raw value writing function. Used for writable device values such
-		as DAC values and caliboffset.
+		as DAC values and calibbias.
 	* info->read_event_config:
 		Typically only set if there are some interrupt lines.  This
 		is used to read if an on sensor event detector is enabled.
@@ -62,8 +62,8 @@ Then fill in the following:
 	Poll function related elements. This controls what occurs when a trigger
 	to which this device is attached sends an event.
 - indio_dev->channels:
-	Specification of device channels. Most attributes etc are built
-	form this spec.
+	Specification of device channels. Most attributes etc. are built
+	from this spec.
 - indio_dev->num_channels:
 	How many channels are there?
 
@@ -76,4 +76,4 @@ be registered afterwards (otherwise the whole parentage of devices
 gets confused)
 
 On remove, iio_device_unregister(indio_dev) will remove the device from
-the core, and iio_device_free will clean up.
+the core, and iio_device_free(indio_dev) will clean up.
diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c
index bf55335..827e92d 100644
--- a/drivers/staging/iio/Documentation/generic_buffer.c
+++ b/drivers/staging/iio/Documentation/generic_buffer.c
@@ -18,6 +18,8 @@
  *
  */
 
+#define _GNU_SOURCE
+
 #include <unistd.h>
 #include <dirent.h>
 #include <fcntl.h>
@@ -29,12 +31,14 @@
 #include <string.h>
 #include <poll.h>
 #include <endian.h>
+#include <getopt.h>
+#include <inttypes.h>
 #include "iio_utils.h"
 
 /**
  * size_from_channelarray() - calculate the storage size of a scan
- * @channels: the channel info array
- * @num_channels: size of the channel info array
+ * @channels:		the channel info array
+ * @num_channels:	number of channels
  *
  * Has the side effect of filling the channels[i].location values used
  * in processing the buffer output.
@@ -58,22 +62,22 @@ int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
 void print2byte(int input, struct iio_channel_info *info)
 {
 	/* First swap if incorrect endian */
-
 	if (info->be)
 		input = be16toh((uint16_t)input);
 	else
 		input = le16toh((uint16_t)input);
 
-	/* shift before conversion to avoid sign extension
-	   of left aligned data */
+	/*
+	 * Shift before conversion to avoid sign extension
+	 * of left aligned data
+	 */
 	input = input >> info->shift;
 	if (info->is_signed) {
 		int16_t val = input;
 		val &= (1 << info->bits_used) - 1;
 		val = (int16_t)(val << (16 - info->bits_used)) >>
 			(16 - info->bits_used);
-		printf("%05f  ", val,
-		       (float)(val + info->offset)*info->scale);
+		printf("%05f ", ((float)val + info->offset)*info->scale);
 	} else {
 		uint16_t val = input;
 		val &= (1 << info->bits_used) - 1;
@@ -83,39 +87,39 @@ void print2byte(int input, struct iio_channel_info *info)
 /**
  * process_scan() - print out the values in SI units
  * @data:		pointer to the start of the scan
- * @infoarray:		information about the channels. Note
+ * @channels:		information about the channels. Note
  *  size_from_channelarray must have been called first to fill the
  *  location offsets.
- * @num_channels:	the number of active channels
+ * @num_channels:	number of channels
  **/
 void process_scan(char *data,
-		  struct iio_channel_info *infoarray,
+		  struct iio_channel_info *channels,
 		  int num_channels)
 {
 	int k;
 	for (k = 0; k < num_channels; k++)
-		switch (infoarray[k].bytes) {
+		switch (channels[k].bytes) {
 			/* only a few cases implemented so far */
 		case 2:
-			print2byte(*(uint16_t *)(data + infoarray[k].location),
-				   &infoarray[k]);
+			print2byte(*(uint16_t *)(data + channels[k].location),
+				   &channels[k]);
 			break;
 		case 8:
-			if (infoarray[k].is_signed) {
+			if (channels[k].is_signed) {
 				int64_t val = *(int64_t *)
 					(data +
-					 infoarray[k].location);
-				if ((val >> infoarray[k].bits_used) & 1)
-					val = (val & infoarray[k].mask) |
-						~infoarray[k].mask;
+					 channels[k].location);
+				if ((val >> channels[k].bits_used) & 1)
+					val = (val & channels[k].mask) |
+						~channels[k].mask;
 				/* special case for timestamp */
-				if (infoarray[k].scale == 1.0f &&
-				    infoarray[k].offset == 0.0f)
-					printf(" %lld", val);
+				if (channels[k].scale == 1.0f &&
+				    channels[k].offset == 0.0f)
+					printf("%" PRId64 " ", val);
 				else
 					printf("%05f ", ((float)val +
-							 infoarray[k].offset)*
-					       infoarray[k].scale);
+							 channels[k].offset)*
+					       channels[k].scale);
 			}
 			break;
 		default:
@@ -130,10 +134,7 @@ int main(int argc, char **argv)
 	unsigned long timedelay = 1000000;
 	unsigned long buf_len = 128;
 
-
 	int ret, c, i, j, toread;
-
-	FILE *fp_ev;
 	int fp;
 
 	int num_channels;
@@ -149,7 +150,7 @@ int main(int argc, char **argv)
 	int noevents = 0;
 	char *dummy;
 
-	struct iio_channel_info *infoarray;
+	struct iio_channel_info *channels;
 
 	while ((c = getopt(argc, argv, "l:w:c:et:n:")) != -1) {
 		switch (c) {
@@ -192,7 +193,7 @@ int main(int argc, char **argv)
 	asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
 	if (trigger_name == NULL) {
 		/*
-		 * Build the trigger name. If it is device associated it's
+		 * Build the trigger name. If it is device associated its
 		 * name is <device_name>_dev[n] where n matches the device
 		 * number found above
 		 */
@@ -217,7 +218,7 @@ int main(int argc, char **argv)
 	 * Parse the files in scan_elements to identify what channels are
 	 * present
 	 */
-	ret = build_channel_array(dev_dir_name, &infoarray, &num_channels);
+	ret = build_channel_array(dev_dir_name, &channels, &num_channels);
 	if (ret) {
 		printf("Problem reading scan element information\n");
 		printf("diag %s\n", dev_dir_name);
@@ -236,7 +237,7 @@ int main(int argc, char **argv)
 		goto error_free_triggername;
 	}
 	printf("%s %s\n", dev_dir_name, trigger_name);
-	/* Set the device trigger to be the data rdy trigger found above */
+	/* Set the device trigger to be the data ready trigger found above */
 	ret = write_sysfs_string_and_verify("trigger/current_trigger",
 					dev_dir_name,
 					trigger_name);
@@ -254,7 +255,7 @@ int main(int argc, char **argv)
 	ret = write_sysfs_int("enable", buf_dir_name, 1);
 	if (ret < 0)
 		goto error_free_buf_dir_name;
-	scan_size = size_from_channelarray(infoarray, num_channels);
+	scan_size = size_from_channelarray(channels, num_channels);
 	data = malloc(scan_size*buf_len);
 	if (!data) {
 		ret = -ENOMEM;
@@ -269,7 +270,7 @@ int main(int argc, char **argv)
 
 	/* Attempt to open non blocking the access dev */
 	fp = open(buffer_access, O_RDONLY | O_NONBLOCK);
-	if (fp == -1) { /*If it isn't there make the node */
+	if (fp == -1) { /* If it isn't there make the node */
 		printf("Failed to open %s\n", buffer_access);
 		ret = -errno;
 		goto error_free_buffer_access;
@@ -300,16 +301,16 @@ int main(int argc, char **argv)
 		}
 		for (i = 0; i < read_size/scan_size; i++)
 			process_scan(data + scan_size*i,
-				     infoarray,
+				     channels,
 				     num_channels);
 	}
 
-	/* Stop the ring buffer */
+	/* Stop the buffer */
 	ret = write_sysfs_int("enable", buf_dir_name, 0);
 	if (ret < 0)
 		goto error_close_buffer_access;
 
-	/* Disconnect from the trigger - just write a dummy name.*/
+	/* Disconnect the trigger - just write a dummy name. */
 	write_sysfs_string("trigger/current_trigger",
 			dev_dir_name, "NULL");
 
diff --git a/drivers/staging/iio/Documentation/iio_event_monitor.c b/drivers/staging/iio/Documentation/iio_event_monitor.c
index 2227584..4326e9e 100644
--- a/drivers/staging/iio/Documentation/iio_event_monitor.c
+++ b/drivers/staging/iio/Documentation/iio_event_monitor.c
@@ -45,6 +45,7 @@ static const char * const iio_chan_type_name_spec[] = {
 	[IIO_ANGL] = "angl",
 	[IIO_TIMESTAMP] = "timestamp",
 	[IIO_CAPACITANCE] = "capacitance",
+	[IIO_ALTVOLTAGE] = "altvoltage",
 };
 
 static const char * const iio_ev_type_text[] = {
@@ -92,6 +93,7 @@ static bool event_is_known(struct iio_event_data *event)
 	case IIO_ANGL:
 	case IIO_TIMESTAMP:
 	case IIO_CAPACITANCE:
+	case IIO_ALTVOLTAGE:
 		break;
 	default:
 		return false;
diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h
index 6f3a392..c0448b3 100644
--- a/drivers/staging/iio/Documentation/iio_utils.h
+++ b/drivers/staging/iio/Documentation/iio_utils.h
@@ -7,14 +7,15 @@
  * the Free Software Foundation.
  */
 
-/* Made up value to limit allocation sizes */
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <dirent.h>
+#include <errno.h>
 
+/* Made up value to limit allocation sizes */
 #define IIO_MAX_NAME_LENGTH 30
 
 #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements"
@@ -27,7 +28,7 @@ const char *iio_dir = "/sys/bus/iio/devices/";
  * @full_name: the full channel name
  * @generic_name: the output generic channel name
  **/
-static int iioutils_break_up_name(const char *full_name,
+inline int iioutils_break_up_name(const char *full_name,
 				  char **generic_name)
 {
 	char *current;
@@ -280,7 +281,7 @@ inline int build_channel_array(const char *device_dir,
 {
 	DIR *dp;
 	FILE *sysfsfp;
-	int count, temp, i;
+	int count, i;
 	struct iio_channel_info *current;
 	int ret;
 	const struct dirent *ent;
diff --git a/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583 b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583
old mode 100755
new mode 100644
diff --git a/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x
old mode 100755
new mode 100644
diff --git a/drivers/staging/iio/Documentation/overview.txt b/drivers/staging/iio/Documentation/overview.txt
index afc39ec..43f92b0 100644
--- a/drivers/staging/iio/Documentation/overview.txt
+++ b/drivers/staging/iio/Documentation/overview.txt
@@ -8,7 +8,7 @@ actual devices combine some ADCs with digital to analog converters
 The aim is to fill the gap between the somewhat similar hwmon and
 input subsystems.  Hwmon is very much directed at low sample rate
 sensors used in applications such as fan speed control and temperature
-measurement.  Input is, as it's name suggests focused on input
+measurement.  Input is, as its name suggests focused on input
 devices. In some cases there is considerable overlap between these and
 IIO.
 
diff --git a/drivers/staging/iio/Documentation/ring.txt b/drivers/staging/iio/Documentation/ring.txt
index e338077..e1da433 100644
--- a/drivers/staging/iio/Documentation/ring.txt
+++ b/drivers/staging/iio/Documentation/ring.txt
@@ -15,8 +15,8 @@ struct iio_ring_buffer contains a struct iio_ring_setup_ops *setup_ops
 which in turn contains the 4 function pointers
 (preenable, postenable, predisable and postdisable).
 These are used to perform device specific steps on either side
-of the core changing it's current mode to indicate that the buffer
-is enabled or disabled (along with enabling triggering etc as appropriate).
+of the core changing its current mode to indicate that the buffer
+is enabled or disabled (along with enabling triggering etc. as appropriate).
 
 Also in struct iio_ring_buffer is a struct iio_ring_access_funcs.
 The function pointers within here are used to allow the core to handle
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light b/drivers/staging/iio/Documentation/sysfs-bus-iio-light
index 715c74d..d52be03 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio-light
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light
@@ -34,7 +34,7 @@ Description:
 		it comes back in SI units, it should also include _input else it
 		should include _raw to signify it is not in SI units.
 
-What:		/sys/.../device[n]/proximity_on_chip_ambient_infrared_supression
+What:		/sys/.../device[n]/proximity_on_chip_ambient_infrared_suppression
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index 3c8e5ec..04cd6ec 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -29,7 +29,6 @@ source "drivers/staging/iio/accel/Kconfig"
 source "drivers/staging/iio/adc/Kconfig"
 source "drivers/staging/iio/addac/Kconfig"
 source "drivers/staging/iio/cdc/Kconfig"
-source "drivers/staging/iio/dac/Kconfig"
 source "drivers/staging/iio/frequency/Kconfig"
 source "drivers/staging/iio/gyro/Kconfig"
 source "drivers/staging/iio/impedance-analyzer/Kconfig"
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index 6a46d5a..fa6937d 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -17,7 +17,6 @@ obj-y += accel/
 obj-y += adc/
 obj-y += addac/
 obj-y += cdc/
-obj-y += dac/
 obj-y += frequency/
 obj-y += gyro/
 obj-y += impedance-analyzer/
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
index f6fd0d3..6fc426e 100644
--- a/drivers/staging/iio/accel/adis16209_core.c
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -606,8 +606,6 @@ static int adis16209_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
-	flush_scheduled_work();
-
 	iio_device_unregister(indio_dev);
 	adis16209_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c
index 6a9ac89..af5c576 100644
--- a/drivers/staging/iio/accel/adis16220_core.c
+++ b/drivers/staging/iio/accel/adis16220_core.c
@@ -694,8 +694,6 @@ static int adis16220_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
-	flush_scheduled_work();
-
 	sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc2_bin);
 	sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc1_bin);
 	sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c
index 8b15eae..2f59f83 100644
--- a/drivers/staging/iio/accel/adis16240_core.c
+++ b/drivers/staging/iio/accel/adis16240_core.c
@@ -641,8 +641,6 @@ static int adis16240_remove(struct spi_device *spi)
 
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
-	flush_scheduled_work();
-
 	iio_device_unregister(indio_dev);
 	adis16240_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index 8f1b3af..67711b7 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -13,7 +13,7 @@ config AD7291
 config AD7298
 	tristate "Analog Devices AD7298 ADC driver"
 	depends on SPI
-	select IIO_KFIFO_BUF if IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER if IIO_BUFFER
 	help
 	  Say yes here to build support for Analog Devices AD7298
 	  8 Channel ADC with temperature sensor.
@@ -25,8 +25,7 @@ config AD7606
 	tristate "Analog Devices AD7606 ADC driver"
 	depends on GPIOLIB
 	select IIO_BUFFER
-	select IIO_TRIGGER
-	select IIO_KFIFO_BUF
+	select IIO_TRIGGERED_BUFFER
 	help
 	  Say yes here to build support for Analog Devices:
 	  ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
@@ -64,7 +63,7 @@ config AD799X_RING_BUFFER
 	bool "Analog Devices AD799x: use ring buffer"
 	depends on AD799X
 	select IIO_BUFFER
-	select IIO_KFIFO_BUF
+	select IIO_TRIGGERED_BUFFER
 	help
 	  Say yes here to include ring buffer support in the AD799X
 	  ADC driver.
@@ -73,8 +72,7 @@ config AD7476
 	tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver"
 	depends on SPI
 	select IIO_BUFFER
-	select IIO_KFIFO_BUF
-	select IIO_TRIGGER
+	select IIO_TRIGGERED_BUFFER
 	help
 	  Say yes here to build support for Analog Devices
 	  AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495
@@ -88,8 +86,7 @@ config AD7887
 	tristate "Analog Devices AD7887 ADC driver"
 	depends on SPI
 	select IIO_BUFFER
-	select IIO_KFIFO_BUF
-	select IIO_TRIGGER
+	select IIO_TRIGGERED_BUFFER
 	help
 	  Say yes here to build support for Analog Devices
 	  AD7887 SPI analog to digital converter (ADC).
@@ -114,8 +111,7 @@ config AD7793
 	tristate "Analog Devices AD7792 AD7793 ADC driver"
 	depends on SPI
 	select IIO_BUFFER
-	select IIO_KFIFO_BUF
-	select IIO_TRIGGER
+	select IIO_TRIGGERED_BUFFER
 	help
 	  Say yes here to build support for Analog Devices
 	  AD7792 and AD7793 SPI analog to digital converters (ADC).
@@ -136,8 +132,7 @@ config AD7192
 	tristate "Analog Devices AD7190 AD7192 AD7195 ADC driver"
 	depends on SPI
 	select IIO_BUFFER
-	select IIO_KFIFO_BUF
-	select IIO_TRIGGER
+	select IIO_TRIGGERED_BUFFER
 	help
 	  Say yes here to build support for Analog Devices AD7190,
 	  AD7192 or AD7195 SPI analog to digital converters (ADC).
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index 5eaeaf1..839f17c 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -20,9 +20,9 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/buffer.h>
-#include <linux/iio/kfifo_buf.h>
 #include <linux/iio/trigger.h>
 #include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #include "ad7192.h"
 
@@ -542,41 +542,13 @@ static const struct iio_buffer_setup_ops ad7192_ring_setup_ops = {
 
 static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev)
 {
-	int ret;
-
-	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
-	if (!indio_dev->buffer) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
-						 &ad7192_trigger_handler,
-						 IRQF_ONESHOT,
-						 indio_dev,
-						 "ad7192_consumer%d",
-						 indio_dev->id);
-	if (indio_dev->pollfunc == NULL) {
-		ret = -ENOMEM;
-		goto error_deallocate_kfifo;
-	}
-
-	/* Ring buffer functions - here trigger setup related */
-	indio_dev->setup_ops = &ad7192_ring_setup_ops;
-
-	/* Flag that polled ring buffering is possible */
-	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
-	return 0;
-
-error_deallocate_kfifo:
-	iio_kfifo_free(indio_dev->buffer);
-error_ret:
-	return ret;
+	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+			&ad7192_trigger_handler, &ad7192_ring_setup_ops);
 }
 
 static void ad7192_ring_cleanup(struct iio_dev *indio_dev)
 {
-	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_kfifo_free(indio_dev->buffer);
+	iio_triggered_buffer_cleanup(indio_dev);
 }
 
 /**
@@ -1077,23 +1049,15 @@ static int __devinit ad7192_probe(struct spi_device *spi)
 	if (ret)
 		goto error_ring_cleanup;
 
-	ret = iio_buffer_register(indio_dev,
-				  indio_dev->channels,
-				  indio_dev->num_channels);
-	if (ret)
-		goto error_remove_trigger;
-
 	ret = ad7192_setup(st);
 	if (ret)
-		goto error_unreg_ring;
+		goto error_remove_trigger;
 
 	ret = iio_device_register(indio_dev);
 	if (ret < 0)
-		goto error_unreg_ring;
+		goto error_remove_trigger;
 	return 0;
 
-error_unreg_ring:
-	iio_buffer_unregister(indio_dev);
 error_remove_trigger:
 	ad7192_remove_trigger(indio_dev);
 error_ring_cleanup:
@@ -1116,7 +1080,6 @@ static int ad7192_remove(struct spi_device *spi)
 	struct ad7192_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	iio_buffer_unregister(indio_dev);
 	ad7192_remove_trigger(indio_dev);
 	ad7192_ring_cleanup(indio_dev);
 
diff --git a/drivers/staging/iio/adc/ad7298.h b/drivers/staging/iio/adc/ad7298.h
index 5051a7e..18f2787 100644
--- a/drivers/staging/iio/adc/ad7298.h
+++ b/drivers/staging/iio/adc/ad7298.h
@@ -55,6 +55,8 @@ struct ad7298_state {
 #ifdef CONFIG_IIO_BUFFER
 int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev);
 void ad7298_ring_cleanup(struct iio_dev *indio_dev);
+int ad7298_update_scan_mode(struct iio_dev *indio_dev,
+	const unsigned long *active_scan_mask);
 #else /* CONFIG_IIO_BUFFER */
 
 static inline int
@@ -66,5 +68,8 @@ ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
 static inline void ad7298_ring_cleanup(struct iio_dev *indio_dev)
 {
 }
+
+#define ad7298_update_scan_mode NULL
+
 #endif /* CONFIG_IIO_BUFFER */
 #endif /* IIO_ADC_AD7298_H_ */
diff --git a/drivers/staging/iio/adc/ad7298_core.c b/drivers/staging/iio/adc/ad7298_core.c
index c90f2b3..6141f4a 100644
--- a/drivers/staging/iio/adc/ad7298_core.c
+++ b/drivers/staging/iio/adc/ad7298_core.c
@@ -45,8 +45,8 @@ static struct iio_chan_spec ad7298_channels[] = {
 		.channel = 0,
 		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		.address = 9,
-		.scan_index = AD7298_CH_TEMP,
+		.address = AD7298_CH_TEMP,
+		.scan_index = -1,
 		.scan_type = {
 			.sign = 's',
 			.realbits = 32,
@@ -171,6 +171,7 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
 
 static const struct iio_info ad7298_info = {
 	.read_raw = &ad7298_read_raw,
+	.update_scan_mode = ad7298_update_scan_mode,
 	.driver_module = THIS_MODULE,
 };
 
@@ -231,19 +232,12 @@ static int __devinit ad7298_probe(struct spi_device *spi)
 	if (ret)
 		goto error_disable_reg;
 
-	ret = iio_buffer_register(indio_dev,
-				  &ad7298_channels[1], /* skip temp0 */
-				  ARRAY_SIZE(ad7298_channels) - 1);
-	if (ret)
-		goto error_cleanup_ring;
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_unregister_ring;
+		goto error_cleanup_ring;
 
 	return 0;
 
-error_unregister_ring:
-	iio_buffer_unregister(indio_dev);
 error_cleanup_ring:
 	ad7298_ring_cleanup(indio_dev);
 error_disable_reg:
@@ -263,7 +257,6 @@ static int __devexit ad7298_remove(struct spi_device *spi)
 	struct ad7298_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	iio_buffer_unregister(indio_dev);
 	ad7298_ring_cleanup(indio_dev);
 	if (!IS_ERR(st->reg)) {
 		regulator_disable(st->reg);
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
index 908a3e5..cd3e9cb 100644
--- a/drivers/staging/iio/adc/ad7298_ring.c
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -13,37 +13,29 @@
 
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
-#include <linux/iio/kfifo_buf.h>
 #include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #include "ad7298.h"
 
 /**
- * ad7298_ring_preenable() setup the parameters of the ring before enabling
- *
- * The complex nature of the setting of the number of bytes per datum is due
- * to this driver currently ensuring that the timestamp is stored at an 8
- * byte boundary.
+ * ad7298_update_scan_mode() setup the spi transfer buffer for the new scan mask
  **/
-static int ad7298_ring_preenable(struct iio_dev *indio_dev)
+int ad7298_update_scan_mode(struct iio_dev *indio_dev,
+	const unsigned long *active_scan_mask)
 {
 	struct ad7298_state *st = iio_priv(indio_dev);
 	int i, m;
 	unsigned short command;
-	int scan_count, ret;
-
-	ret = iio_sw_buffer_preenable(indio_dev);
-	if (ret < 0)
-		return ret;
+	int scan_count;
 
 	/* Now compute overall size */
-	scan_count = bitmap_weight(indio_dev->active_scan_mask,
-				   indio_dev->masklength);
+	scan_count = bitmap_weight(active_scan_mask, indio_dev->masklength);
 
 	command = AD7298_WRITE | st->ext_ref;
 
 	for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1)
-		if (test_bit(i, indio_dev->active_scan_mask))
+		if (test_bit(i, active_scan_mask))
 			command |= m;
 
 	st->tx_buf[0] = cpu_to_be16(command);
@@ -108,49 +100,13 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
 	return IRQ_HANDLED;
 }
 
-static const struct iio_buffer_setup_ops ad7298_ring_setup_ops = {
-	.preenable = &ad7298_ring_preenable,
-	.postenable = &iio_triggered_buffer_postenable,
-	.predisable = &iio_triggered_buffer_predisable,
-};
-
 int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
 {
-	int ret;
-
-	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
-	if (!indio_dev->buffer) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	indio_dev->pollfunc = iio_alloc_pollfunc(NULL,
-						 &ad7298_trigger_handler,
-						 IRQF_ONESHOT,
-						 indio_dev,
-						 "ad7298_consumer%d",
-						 indio_dev->id);
-
-	if (indio_dev->pollfunc == NULL) {
-		ret = -ENOMEM;
-		goto error_deallocate_kfifo;
-	}
-
-	/* Ring buffer functions - here trigger setup related */
-	indio_dev->setup_ops = &ad7298_ring_setup_ops;
-	indio_dev->buffer->scan_timestamp = true;
-
-	/* Flag that polled ring buffering is possible */
-	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
-	return 0;
-
-error_deallocate_kfifo:
-	iio_kfifo_free(indio_dev->buffer);
-error_ret:
-	return ret;
+	return iio_triggered_buffer_setup(indio_dev, NULL,
+			&ad7298_trigger_handler, NULL);
 }
 
 void ad7298_ring_cleanup(struct iio_dev *indio_dev)
 {
-	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_kfifo_free(indio_dev->buffer);
+	iio_triggered_buffer_cleanup(indio_dev);
 }
diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c
index be1c260..4d30a79 100644
--- a/drivers/staging/iio/adc/ad7476_core.c
+++ b/drivers/staging/iio/adc/ad7476_core.c
@@ -177,20 +177,12 @@ static int __devinit ad7476_probe(struct spi_device *spi)
 	if (ret)
 		goto error_disable_reg;
 
-	ret = iio_buffer_register(indio_dev,
-				  st->chip_info->channel,
-				  ARRAY_SIZE(st->chip_info->channel));
-	if (ret)
-		goto error_cleanup_ring;
-
 	ret = iio_device_register(indio_dev);
 	if (ret)
 		goto error_ring_unregister;
 	return 0;
 
 error_ring_unregister:
-	iio_buffer_unregister(indio_dev);
-error_cleanup_ring:
 	ad7476_ring_cleanup(indio_dev);
 error_disable_reg:
 	if (!IS_ERR(st->reg))
@@ -210,7 +202,6 @@ static int ad7476_remove(struct spi_device *spi)
 	struct ad7476_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	iio_buffer_unregister(indio_dev);
 	ad7476_ring_cleanup(indio_dev);
 	if (!IS_ERR(st->reg)) {
 		regulator_disable(st->reg);
diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c
index 383611b..10f8b8d 100644
--- a/drivers/staging/iio/adc/ad7476_ring.c
+++ b/drivers/staging/iio/adc/ad7476_ring.c
@@ -15,8 +15,8 @@
 
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
-#include <linux/iio/kfifo_buf.h>
 #include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #include "ad7476.h"
 
@@ -52,51 +52,13 @@ done:
 	return IRQ_HANDLED;
 }
 
-static const struct iio_buffer_setup_ops ad7476_ring_setup_ops = {
-	.preenable = &iio_sw_buffer_preenable,
-	.postenable = &iio_triggered_buffer_postenable,
-	.predisable = &iio_triggered_buffer_predisable,
-};
-
 int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
 {
-	struct ad7476_state *st = iio_priv(indio_dev);
-	int ret = 0;
-
-	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
-	if (!indio_dev->buffer) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	indio_dev->pollfunc
-		= iio_alloc_pollfunc(NULL,
-				     &ad7476_trigger_handler,
-				     IRQF_ONESHOT,
-				     indio_dev,
-				     "%s_consumer%d",
-				     spi_get_device_id(st->spi)->name,
-				     indio_dev->id);
-	if (indio_dev->pollfunc == NULL) {
-		ret = -ENOMEM;
-		goto error_deallocate_kfifo;
-	}
-
-	/* Ring buffer functions - here trigger setup related */
-	indio_dev->setup_ops = &ad7476_ring_setup_ops;
-	indio_dev->buffer->scan_timestamp = true;
-
-	/* Flag that polled ring buffering is possible */
-	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
-	return 0;
-
-error_deallocate_kfifo:
-	iio_kfifo_free(indio_dev->buffer);
-error_ret:
-	return ret;
+	return iio_triggered_buffer_setup(indio_dev, NULL,
+			&ad7476_trigger_handler, NULL);
 }
 
 void ad7476_ring_cleanup(struct iio_dev *indio_dev)
 {
-	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_kfifo_free(indio_dev->buffer);
+	iio_triggered_buffer_cleanup(indio_dev);
 }
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
index a13afff..ccb97fe 100644
--- a/drivers/staging/iio/adc/ad7606_core.c
+++ b/drivers/staging/iio/adc/ad7606_core.c
@@ -533,20 +533,12 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq,
 	if (ret)
 		goto error_free_irq;
 
-	ret = iio_buffer_register(indio_dev,
-				  indio_dev->channels,
-				  indio_dev->num_channels);
-	if (ret)
-		goto error_cleanup_ring;
 	ret = iio_device_register(indio_dev);
 	if (ret)
 		goto error_unregister_ring;
 
 	return indio_dev;
 error_unregister_ring:
-	iio_buffer_unregister(indio_dev);
-
-error_cleanup_ring:
 	ad7606_ring_cleanup(indio_dev);
 
 error_free_irq:
@@ -571,7 +563,6 @@ int ad7606_remove(struct iio_dev *indio_dev, int irq)
 	struct ad7606_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	iio_buffer_unregister(indio_dev);
 	ad7606_ring_cleanup(indio_dev);
 
 	free_irq(irq, indio_dev);
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
index 24ce8fc..f15afe4 100644
--- a/drivers/staging/iio/adc/ad7606_ring.c
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -13,8 +13,8 @@
 
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
-#include <linux/iio/kfifo_buf.h>
 #include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #include "ad7606.h"
 
@@ -91,54 +91,18 @@ done:
 	kfree(buf);
 }
 
-static const struct iio_buffer_setup_ops ad7606_ring_setup_ops = {
-	.preenable = &iio_sw_buffer_preenable,
-	.postenable = &iio_triggered_buffer_postenable,
-	.predisable = &iio_triggered_buffer_predisable,
-};
-
 int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev)
 {
 	struct ad7606_state *st = iio_priv(indio_dev);
-	int ret;
-
-	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
-	if (!indio_dev->buffer) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-
-	indio_dev->pollfunc = iio_alloc_pollfunc(&ad7606_trigger_handler_th_bh,
-						 &ad7606_trigger_handler_th_bh,
-						 0,
-						 indio_dev,
-						 "%s_consumer%d",
-						 indio_dev->name,
-						 indio_dev->id);
-	if (indio_dev->pollfunc == NULL) {
-		ret = -ENOMEM;
-		goto error_deallocate_kfifo;
-	}
-
-	/* Ring buffer functions - here trigger setup related */
-
-	indio_dev->setup_ops = &ad7606_ring_setup_ops;
-	indio_dev->buffer->scan_timestamp = true;
 
 	INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring);
 
-	/* Flag that polled ring buffering is possible */
-	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
-	return 0;
-
-error_deallocate_kfifo:
-	iio_kfifo_free(indio_dev->buffer);
-error_ret:
-	return ret;
+	return iio_triggered_buffer_setup(indio_dev,
+		&ad7606_trigger_handler_th_bh, &ad7606_trigger_handler_th_bh,
+		NULL);
 }
 
 void ad7606_ring_cleanup(struct iio_dev *indio_dev)
 {
-	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_kfifo_free(indio_dev->buffer);
+	iio_triggered_buffer_cleanup(indio_dev);
 }
diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c
index b36556f..2bb9f68 100644
--- a/drivers/staging/iio/adc/ad7793.c
+++ b/drivers/staging/iio/adc/ad7793.c
@@ -21,9 +21,9 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/buffer.h>
-#include <linux/iio/kfifo_buf.h>
 #include <linux/iio/trigger.h>
 #include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #include "ad7793.h"
 
@@ -407,41 +407,13 @@ static const struct iio_buffer_setup_ops ad7793_ring_setup_ops = {
 
 static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev)
 {
-	int ret;
-
-	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
-	if (!indio_dev->buffer) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
-						 &ad7793_trigger_handler,
-						 IRQF_ONESHOT,
-						 indio_dev,
-						 "ad7793_consumer%d",
-						 indio_dev->id);
-	if (indio_dev->pollfunc == NULL) {
-		ret = -ENOMEM;
-		goto error_deallocate_kfifo;
-	}
-
-	/* Ring buffer functions - here trigger setup related */
-	indio_dev->setup_ops = &ad7793_ring_setup_ops;
-
-	/* Flag that polled ring buffering is possible */
-	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
-	return 0;
-
-error_deallocate_kfifo:
-	iio_kfifo_free(indio_dev->buffer);
-error_ret:
-	return ret;
+	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+			&ad7793_trigger_handler, &ad7793_ring_setup_ops);
 }
 
 static void ad7793_ring_cleanup(struct iio_dev *indio_dev)
 {
-	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_kfifo_free(indio_dev->buffer);
+	iio_triggered_buffer_cleanup(indio_dev);
 }
 
 /**
@@ -959,24 +931,16 @@ static int __devinit ad7793_probe(struct spi_device *spi)
 	if (ret)
 		goto error_unreg_ring;
 
-	ret = iio_buffer_register(indio_dev,
-				  indio_dev->channels,
-				  indio_dev->num_channels);
-	if (ret)
-		goto error_remove_trigger;
-
 	ret = ad7793_setup(st);
 	if (ret)
-		goto error_uninitialize_ring;
+		goto error_remove_trigger;
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_uninitialize_ring;
+		goto error_remove_trigger;
 
 	return 0;
 
-error_uninitialize_ring:
-	iio_buffer_unregister(indio_dev);
 error_remove_trigger:
 	ad7793_remove_trigger(indio_dev);
 error_unreg_ring:
@@ -999,7 +963,6 @@ static int ad7793_remove(struct spi_device *spi)
 	struct ad7793_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	iio_buffer_unregister(indio_dev);
 	ad7793_remove_trigger(indio_dev);
 	ad7793_ring_cleanup(indio_dev);
 
diff --git a/drivers/staging/iio/adc/ad7887_core.c b/drivers/staging/iio/adc/ad7887_core.c
index 7186074..397b849 100644
--- a/drivers/staging/iio/adc/ad7887_core.c
+++ b/drivers/staging/iio/adc/ad7887_core.c
@@ -201,20 +201,12 @@ static int __devinit ad7887_probe(struct spi_device *spi)
 	if (ret)
 		goto error_disable_reg;
 
-	ret = iio_buffer_register(indio_dev,
-				  indio_dev->channels,
-				  indio_dev->num_channels);
-	if (ret)
-		goto error_cleanup_ring;
-
 	ret = iio_device_register(indio_dev);
 	if (ret)
 		goto error_unregister_ring;
 
 	return 0;
 error_unregister_ring:
-	iio_buffer_unregister(indio_dev);
-error_cleanup_ring:
 	ad7887_ring_cleanup(indio_dev);
 error_disable_reg:
 	if (!IS_ERR(st->reg))
@@ -233,7 +225,6 @@ static int ad7887_remove(struct spi_device *spi)
 	struct ad7887_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	iio_buffer_unregister(indio_dev);
 	ad7887_ring_cleanup(indio_dev);
 	if (!IS_ERR(st->reg)) {
 		regulator_disable(st->reg);
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index fd91384..1c406da 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -14,8 +14,8 @@
 
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
-#include <linux/iio/kfifo_buf.h>
 #include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #include "ad7887.h"
 
@@ -112,38 +112,11 @@ static const struct iio_buffer_setup_ops ad7887_ring_setup_ops = {
 
 int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
 {
-	int ret;
-
-	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
-	if (!indio_dev->buffer) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
-						 &ad7887_trigger_handler,
-						 IRQF_ONESHOT,
-						 indio_dev,
-						 "ad7887_consumer%d",
-						 indio_dev->id);
-	if (indio_dev->pollfunc == NULL) {
-		ret = -ENOMEM;
-		goto error_deallocate_kfifo;
-	}
-	/* Ring buffer functions - here trigger setup related */
-	indio_dev->setup_ops = &ad7887_ring_setup_ops;
-
-	/* Flag that polled ring buffering is possible */
-	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
-	return 0;
-
-error_deallocate_kfifo:
-	iio_kfifo_free(indio_dev->buffer);
-error_ret:
-	return ret;
+	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+			&ad7887_trigger_handler, &ad7887_ring_setup_ops);
 }
 
 void ad7887_ring_cleanup(struct iio_dev *indio_dev)
 {
-	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_kfifo_free(indio_dev->buffer);
+	iio_triggered_buffer_cleanup(indio_dev);
 }
diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h
index 99f8abe..3e363c4 100644
--- a/drivers/staging/iio/adc/ad799x.h
+++ b/drivers/staging/iio/adc/ad799x.h
@@ -120,8 +120,6 @@ struct ad799x_platform_data {
 	u16				vref_mv;
 };
 
-int ad7997_8_set_scan_mode(struct ad799x_state *st, unsigned mask);
-
 #ifdef CONFIG_AD799X_RING_BUFFER
 int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev);
 void ad799x_ring_cleanup(struct iio_dev *indio_dev);
diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c
index 80e0c6e..2d4bda9 100644
--- a/drivers/staging/iio/adc/ad799x_core.c
+++ b/drivers/staging/iio/adc/ad799x_core.c
@@ -99,10 +99,21 @@ static int ad799x_i2c_write8(struct ad799x_state *st, u8 reg, u8 data)
 	return ret;
 }
 
-int ad7997_8_set_scan_mode(struct ad799x_state *st, unsigned mask)
+static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev,
+	const unsigned long *scan_mask)
 {
-	return ad799x_i2c_write16(st, AD7998_CONF_REG,
-		st->config | (mask << AD799X_CHANNEL_SHIFT));
+	struct ad799x_state *st = iio_priv(indio_dev);
+
+	switch (st->id) {
+	case ad7997:
+	case ad7998:
+		return ad799x_i2c_write16(st, AD7998_CONF_REG,
+			st->config | (*scan_mask << AD799X_CHANNEL_SHIFT));
+	default:
+		break;
+	}
+
+	return 0;
 }
 
 static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch)
@@ -442,6 +453,7 @@ static const struct iio_info ad7993_4_7_8_info = {
 	.read_event_value = &ad799x_read_event_value,
 	.write_event_value = &ad799x_write_event_value,
 	.driver_module = THIS_MODULE,
+	.update_scan_mode = ad7997_8_update_scan_mode,
 };
 
 #define AD799X_EV_MASK (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
@@ -887,12 +899,6 @@ static int __devinit ad799x_probe(struct i2c_client *client,
 	if (ret)
 		goto error_disable_reg;
 
-	ret = iio_buffer_register(indio_dev,
-				  indio_dev->channels,
-				  indio_dev->num_channels);
-	if (ret)
-		goto error_cleanup_ring;
-
 	if (client->irq > 0) {
 		ret = request_threaded_irq(client->irq,
 					   NULL,
@@ -934,7 +940,6 @@ static __devexit int ad799x_remove(struct i2c_client *client)
 	if (client->irq > 0)
 		free_irq(client->irq, indio_dev);
 
-	iio_buffer_unregister(indio_dev);
 	ad799x_ring_cleanup(indio_dev);
 	if (!IS_ERR(st->reg)) {
 		regulator_disable(st->reg);
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 1c7ff44..0882c9e 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -18,33 +18,12 @@
 
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
-#include <linux/iio/kfifo_buf.h>
 #include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #include "ad799x.h"
 
 /**
- * ad799x_ring_preenable() setup the parameters of the ring before enabling
- *
- * The complex nature of the setting of the number of bytes per datum is due
- * to this driver currently ensuring that the timestamp is stored at an 8
- * byte boundary.
- **/
-static int ad799x_ring_preenable(struct iio_dev *indio_dev)
-{
-	struct ad799x_state *st = iio_priv(indio_dev);
-	/*
-	 * Need to figure out the current mode based upon the requested
-	 * scan mask in iio_dev
-	 */
-
-	if (st->id == ad7997 || st->id == ad7998)
-		ad7997_8_set_scan_mode(st, *indio_dev->active_scan_mask);
-
-	return iio_sw_buffer_preenable(indio_dev);
-}
-
-/**
  * ad799x_trigger_handler() bh of trigger launched polling to ring buffer
  *
  * Currently there is no option in this driver to disable the saving of
@@ -110,49 +89,13 @@ out:
 	return IRQ_HANDLED;
 }
 
-static const struct iio_buffer_setup_ops ad799x_buf_setup_ops = {
-	.preenable = &ad799x_ring_preenable,
-	.postenable = &iio_triggered_buffer_postenable,
-	.predisable = &iio_triggered_buffer_predisable,
-};
-
 int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
 {
-	int ret = 0;
-
-	indio_dev->buffer = iio_kfifo_allocate(indio_dev);
-	if (!indio_dev->buffer) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	indio_dev->pollfunc = iio_alloc_pollfunc(NULL,
-						 &ad799x_trigger_handler,
-						 IRQF_ONESHOT,
-						 indio_dev,
-						 "%s_consumer%d",
-						 indio_dev->name,
-						 indio_dev->id);
-	if (indio_dev->pollfunc == NULL) {
-		ret = -ENOMEM;
-		goto error_deallocate_kfifo;
-	}
-
-	/* Ring buffer functions - here trigger setup related */
-	indio_dev->setup_ops = &ad799x_buf_setup_ops;
-	indio_dev->buffer->scan_timestamp = true;
-
-	/* Flag that polled ring buffering is possible */
-	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
-	return 0;
-
-error_deallocate_kfifo:
-	iio_kfifo_free(indio_dev->buffer);
-error_ret:
-	return ret;
+	return iio_triggered_buffer_setup(indio_dev, NULL,
+		&ad799x_trigger_handler, NULL);
 }
 
 void ad799x_ring_cleanup(struct iio_dev *indio_dev)
 {
-	iio_dealloc_pollfunc(indio_dev->pollfunc);
-	iio_kfifo_free(indio_dev->buffer);
+	iio_triggered_buffer_cleanup(indio_dev);
 }
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig
deleted file mode 100644
index a626f03..0000000
--- a/drivers/staging/iio/dac/Kconfig
+++ /dev/null
@@ -1,121 +0,0 @@
-#
-# DAC drivers
-#
-menu "Digital to analog converters"
-
-config AD5064
-	tristate "Analog Devices AD5064/64-1/65/44/45/24/25, AD5628/48/66/68 DAC driver"
-	depends on SPI
-	help
-	  Say yes here to build support for Analog Devices AD5024, AD5025, AD5044,
-	  AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648, AD5666, AD5668 Digital
-	  to Analog Converter.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ad5064.
-
-config AD5360
-	tristate "Analog Devices Analog Devices AD5360/61/62/63/70/71/73 DAC driver"
-	depends on SPI
-	help
-	  Say yes here to build support for Analog Devices AD5360, AD5361,
-	  AD5362, AD5363, AD5370, AD5371, AD5373 multi-channel
-	  Digital to Analog Converters (DAC).
-
-	  To compile this driver as module choose M here: the module will be called
-	  ad5360.
-
-config AD5380
-	tristate "Analog Devices AD5380/81/82/83/84/90/91/92 DAC driver"
-	depends on (SPI_MASTER || I2C)
-	select REGMAP_I2C if I2C
-	select REGMAP_SPI if SPI_MASTER
-	help
-	  Say yes here to build support for Analog Devices AD5380, AD5381,
-	  AD5382, AD5383, AD5384, AD5390, AD5391, AD5392 multi-channel
-	  Digital to Analog Converters (DAC).
-
-	  To compile this driver as module choose M here: the module will be called
-	  ad5380.
-
-config AD5421
-	tristate "Analog Devices AD5421 DAC driver"
-	depends on SPI
-	help
-	  Say yes here to build support for Analog Devices AD5421 loop-powered
-	  digital-to-analog convertors (DAC).
-
-	  To compile this driver as module choose M here: the module will be called
-	  ad5421.
-
-config AD5624R_SPI
-	tristate "Analog Devices AD5624/44/64R DAC spi driver"
-	depends on SPI
-	help
-	  Say yes here to build support for Analog Devices AD5624R, AD5644R and
-	  AD5664R converters (DAC). This driver uses the common SPI interface.
-
-config AD5446
-	tristate "Analog Devices AD5446 and similar single channel DACs driver"
-	depends on SPI
-	help
-	  Say yes here to build support for Analog Devices AD5444, AD5446,
-	  AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620,
-	  AD5621, AD5640, AD5660, AD5662 DACs.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ad5446.
-
-config AD5504
-	tristate "Analog Devices AD5504/AD5501 DAC SPI driver"
-	depends on SPI
-	help
-	  Say yes here to build support for Analog Devices AD5504, AD5501,
-	  High Voltage Digital to Analog Converter.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ad5504.
-
-config AD5764
-	tristate "Analog Devices AD5764/64R/44/44R DAC driver"
-	depends on SPI_MASTER
-	help
-	  Say yes here to build support for Analog Devices AD5764, AD5764R, AD5744,
-	  AD5744R Digital to Analog Converter.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ad5764.
-
-config AD5791
-	tristate "Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC SPI driver"
-	depends on SPI
-	help
-	  Say yes here to build support for Analog Devices AD5760, AD5780,
-	  AD5781, AD5790, AD5791 High Resolution Voltage Output Digital to
-	  Analog Converter.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ad5791.
-
-config AD5686
-	tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver"
-	depends on SPI
-	help
-	  Say yes here to build support for Analog Devices AD5686R, AD5685R,
-	  AD5684R, AD5791 Voltage Output Digital to
-	  Analog Converter.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ad5686.
-
-config MAX517
-	tristate "Maxim MAX517/518/519 DAC driver"
-	depends on I2C && EXPERIMENTAL
-	help
-	  If you say yes here you get support for the Maxim chips MAX517,
-	  MAX518 and MAX519 (I2C 8-Bit DACs with rail-to-rail outputs).
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called max517.
-
-endmenu
diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile
deleted file mode 100644
index 8ab1d26..0000000
--- a/drivers/staging/iio/dac/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Makefile for industrial I/O DAC drivers
-#
-
-obj-$(CONFIG_AD5360) += ad5360.o
-obj-$(CONFIG_AD5380) += ad5380.o
-obj-$(CONFIG_AD5421) += ad5421.o
-obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
-obj-$(CONFIG_AD5064) += ad5064.o
-obj-$(CONFIG_AD5504) += ad5504.o
-obj-$(CONFIG_AD5446) += ad5446.o
-obj-$(CONFIG_AD5764) += ad5764.o
-obj-$(CONFIG_AD5791) += ad5791.o
-obj-$(CONFIG_AD5686) += ad5686.o
-obj-$(CONFIG_MAX517) += max517.o
diff --git a/drivers/staging/iio/dac/ad5064.c b/drivers/staging/iio/dac/ad5064.c
deleted file mode 100644
index 047148a..0000000
--- a/drivers/staging/iio/dac/ad5064.c
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
- * AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648,
- * AD5666, AD5668 Digital to analog converters driver
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/regulator/consumer.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include "dac.h"
-
-#define AD5064_MAX_DAC_CHANNELS			8
-#define AD5064_MAX_VREFS			4
-
-#define AD5064_ADDR(x)				((x) << 20)
-#define AD5064_CMD(x)				((x) << 24)
-
-#define AD5064_ADDR_DAC(chan)			(chan)
-#define AD5064_ADDR_ALL_DAC			0xF
-
-#define AD5064_CMD_WRITE_INPUT_N		0x0
-#define AD5064_CMD_UPDATE_DAC_N			0x1
-#define AD5064_CMD_WRITE_INPUT_N_UPDATE_ALL	0x2
-#define AD5064_CMD_WRITE_INPUT_N_UPDATE_N	0x3
-#define AD5064_CMD_POWERDOWN_DAC		0x4
-#define AD5064_CMD_CLEAR			0x5
-#define AD5064_CMD_LDAC_MASK			0x6
-#define AD5064_CMD_RESET			0x7
-#define AD5064_CMD_CONFIG			0x8
-
-#define AD5064_CONFIG_DAISY_CHAIN_ENABLE	BIT(1)
-#define AD5064_CONFIG_INT_VREF_ENABLE		BIT(0)
-
-#define AD5064_LDAC_PWRDN_NONE			0x0
-#define AD5064_LDAC_PWRDN_1K			0x1
-#define AD5064_LDAC_PWRDN_100K			0x2
-#define AD5064_LDAC_PWRDN_3STATE		0x3
-
-/**
- * struct ad5064_chip_info - chip specific information
- * @shared_vref:	whether the vref supply is shared between channels
- * @internal_vref:	internal reference voltage. 0 if the chip has no internal
- *			vref.
- * @channel:		channel specification
- * @num_channels:	number of channels
- */
-
-struct ad5064_chip_info {
-	bool shared_vref;
-	unsigned long internal_vref;
-	const struct iio_chan_spec *channels;
-	unsigned int num_channels;
-};
-
-/**
- * struct ad5064_state - driver instance specific data
- * @spi:		spi_device
- * @chip_info:		chip model specific constants, available modes etc
- * @vref_reg:		vref supply regulators
- * @pwr_down:		whether channel is powered down
- * @pwr_down_mode:	channel's current power down mode
- * @dac_cache:		current DAC raw value (chip does not support readback)
- * @use_internal_vref:	set to true if the internal reference voltage should be
- *			used.
- * @data:		spi transfer buffers
- */
-
-struct ad5064_state {
-	struct spi_device		*spi;
-	const struct ad5064_chip_info	*chip_info;
-	struct regulator_bulk_data	vref_reg[AD5064_MAX_VREFS];
-	bool				pwr_down[AD5064_MAX_DAC_CHANNELS];
-	u8				pwr_down_mode[AD5064_MAX_DAC_CHANNELS];
-	unsigned int			dac_cache[AD5064_MAX_DAC_CHANNELS];
-	bool				use_internal_vref;
-
-	/*
-	 * DMA (thus cache coherency maintenance) requires the
-	 * transfer buffers to live in their own cache lines.
-	 */
-	__be32 data ____cacheline_aligned;
-};
-
-enum ad5064_type {
-	ID_AD5024,
-	ID_AD5025,
-	ID_AD5044,
-	ID_AD5045,
-	ID_AD5064,
-	ID_AD5064_1,
-	ID_AD5065,
-	ID_AD5628_1,
-	ID_AD5628_2,
-	ID_AD5648_1,
-	ID_AD5648_2,
-	ID_AD5666_1,
-	ID_AD5666_2,
-	ID_AD5668_1,
-	ID_AD5668_2,
-};
-
-static int ad5064_spi_write(struct ad5064_state *st, unsigned int cmd,
-	unsigned int addr, unsigned int val, unsigned int shift)
-{
-	val <<= shift;
-
-	st->data = cpu_to_be32(AD5064_CMD(cmd) | AD5064_ADDR(addr) | val);
-
-	return spi_write(st->spi, &st->data, sizeof(st->data));
-}
-
-static int ad5064_sync_powerdown_mode(struct ad5064_state *st,
-	unsigned int channel)
-{
-	unsigned int val;
-	int ret;
-
-	val = (0x1 << channel);
-
-	if (st->pwr_down[channel])
-		val |= st->pwr_down_mode[channel] << 8;
-
-	ret = ad5064_spi_write(st, AD5064_CMD_POWERDOWN_DAC, 0, val, 0);
-
-	return ret;
-}
-
-static const char ad5064_powerdown_modes[][15] = {
-	[AD5064_LDAC_PWRDN_NONE]	= "",
-	[AD5064_LDAC_PWRDN_1K]		= "1kohm_to_gnd",
-	[AD5064_LDAC_PWRDN_100K]	= "100kohm_to_gnd",
-	[AD5064_LDAC_PWRDN_3STATE]	= "three_state",
-};
-
-static ssize_t ad5064_read_powerdown_mode_available(struct iio_dev *indio_dev,
-	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
-{
-	return sprintf(buf, "%s %s %s\n", ad5064_powerdown_modes[1],
-		ad5064_powerdown_modes[2], ad5064_powerdown_modes[3]);
-}
-
-static ssize_t ad5064_read_powerdown_mode(struct iio_dev *indio_dev,
-	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
-{
-	struct ad5064_state *st = iio_priv(indio_dev);
-
-	return sprintf(buf, "%s\n",
-		ad5064_powerdown_modes[st->pwr_down_mode[chan->channel]]);
-}
-
-static ssize_t ad5064_write_powerdown_mode(struct iio_dev *indio_dev,
-	uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
-	size_t len)
-{
-	struct ad5064_state *st = iio_priv(indio_dev);
-	unsigned int mode, i;
-	int ret;
-
-	mode = 0;
-
-	for (i = 1; i < ARRAY_SIZE(ad5064_powerdown_modes); ++i) {
-		if (sysfs_streq(buf, ad5064_powerdown_modes[i])) {
-			mode = i;
-			break;
-		}
-	}
-	if (mode == 0)
-		return  -EINVAL;
-
-	mutex_lock(&indio_dev->mlock);
-	st->pwr_down_mode[chan->channel] = mode;
-
-	ret = ad5064_sync_powerdown_mode(st, chan->channel);
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret ? ret : len;
-}
-
-static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev,
-	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
-{
-	struct ad5064_state *st = iio_priv(indio_dev);
-
-	return sprintf(buf, "%d\n", st->pwr_down[chan->channel]);
-}
-
-static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev,
-	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
-	 size_t len)
-{
-	struct ad5064_state *st = iio_priv(indio_dev);
-	bool pwr_down;
-	int ret;
-
-	ret = strtobool(buf, &pwr_down);
-	if (ret)
-		return ret;
-
-	mutex_lock(&indio_dev->mlock);
-	st->pwr_down[chan->channel] = pwr_down;
-
-	ret = ad5064_sync_powerdown_mode(st, chan->channel);
-	mutex_unlock(&indio_dev->mlock);
-	return ret ? ret : len;
-}
-
-static int ad5064_get_vref(struct ad5064_state *st,
-	struct iio_chan_spec const *chan)
-{
-	unsigned int i;
-
-	if (st->use_internal_vref)
-		return st->chip_info->internal_vref;
-
-	i = st->chip_info->shared_vref ? 0 : chan->channel;
-	return regulator_get_voltage(st->vref_reg[i].consumer);
-}
-
-static int ad5064_read_raw(struct iio_dev *indio_dev,
-			   struct iio_chan_spec const *chan,
-			   int *val,
-			   int *val2,
-			   long m)
-{
-	struct ad5064_state *st = iio_priv(indio_dev);
-	int scale_uv;
-
-	switch (m) {
-	case IIO_CHAN_INFO_RAW:
-		*val = st->dac_cache[chan->channel];
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_SCALE:
-		scale_uv = ad5064_get_vref(st, chan);
-		if (scale_uv < 0)
-			return scale_uv;
-
-		scale_uv = (scale_uv * 100) >> chan->scan_type.realbits;
-		*val =  scale_uv / 100000;
-		*val2 = (scale_uv % 100000) * 10;
-		return IIO_VAL_INT_PLUS_MICRO;
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-static int ad5064_write_raw(struct iio_dev *indio_dev,
-	struct iio_chan_spec const *chan, int val, int val2, long mask)
-{
-	struct ad5064_state *st = iio_priv(indio_dev);
-	int ret;
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		if (val > (1 << chan->scan_type.realbits) || val < 0)
-			return -EINVAL;
-
-		mutex_lock(&indio_dev->mlock);
-		ret = ad5064_spi_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N,
-				chan->address, val, chan->scan_type.shift);
-		if (ret == 0)
-			st->dac_cache[chan->channel] = val;
-		mutex_unlock(&indio_dev->mlock);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static const struct iio_info ad5064_info = {
-	.read_raw = ad5064_read_raw,
-	.write_raw = ad5064_write_raw,
-	.driver_module = THIS_MODULE,
-};
-
-static struct iio_chan_spec_ext_info ad5064_ext_info[] = {
-	{
-		.name = "powerdown",
-		.read = ad5064_read_dac_powerdown,
-		.write = ad5064_write_dac_powerdown,
-	},
-	{
-		.name = "powerdown_mode",
-		.read = ad5064_read_powerdown_mode,
-		.write = ad5064_write_powerdown_mode,
-	},
-	{
-		.name = "powerdown_mode_available",
-		.shared = true,
-		.read = ad5064_read_powerdown_mode_available,
-	},
-	{ },
-};
-
-#define AD5064_CHANNEL(chan, bits) {				\
-	.type = IIO_VOLTAGE,					\
-	.indexed = 1,						\
-	.output = 1,						\
-	.channel = (chan),					\
-	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
-	IIO_CHAN_INFO_SCALE_SEPARATE_BIT,			\
-	.address = AD5064_ADDR_DAC(chan),			\
-	.scan_type = IIO_ST('u', (bits), 16, 20 - (bits)),	\
-	.ext_info = ad5064_ext_info,				\
-}
-
-#define DECLARE_AD5064_CHANNELS(name, bits) \
-const struct iio_chan_spec name[] = { \
-	AD5064_CHANNEL(0, bits), \
-	AD5064_CHANNEL(1, bits), \
-	AD5064_CHANNEL(2, bits), \
-	AD5064_CHANNEL(3, bits), \
-	AD5064_CHANNEL(4, bits), \
-	AD5064_CHANNEL(5, bits), \
-	AD5064_CHANNEL(6, bits), \
-	AD5064_CHANNEL(7, bits), \
-}
-
-static DECLARE_AD5064_CHANNELS(ad5024_channels, 12);
-static DECLARE_AD5064_CHANNELS(ad5044_channels, 14);
-static DECLARE_AD5064_CHANNELS(ad5064_channels, 16);
-
-static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
-	[ID_AD5024] = {
-		.shared_vref = false,
-		.channels = ad5024_channels,
-		.num_channels = 4,
-	},
-	[ID_AD5025] = {
-		.shared_vref = false,
-		.channels = ad5024_channels,
-		.num_channels = 2,
-	},
-	[ID_AD5044] = {
-		.shared_vref = false,
-		.channels = ad5044_channels,
-		.num_channels = 4,
-	},
-	[ID_AD5045] = {
-		.shared_vref = false,
-		.channels = ad5044_channels,
-		.num_channels = 2,
-	},
-	[ID_AD5064] = {
-		.shared_vref = false,
-		.channels = ad5064_channels,
-		.num_channels = 4,
-	},
-	[ID_AD5064_1] = {
-		.shared_vref = true,
-		.channels = ad5064_channels,
-		.num_channels = 4,
-	},
-	[ID_AD5065] = {
-		.shared_vref = false,
-		.channels = ad5064_channels,
-		.num_channels = 2,
-	},
-	[ID_AD5628_1] = {
-		.shared_vref = true,
-		.internal_vref = 2500000,
-		.channels = ad5024_channels,
-		.num_channels = 8,
-	},
-	[ID_AD5628_2] = {
-		.shared_vref = true,
-		.internal_vref = 5000000,
-		.channels = ad5024_channels,
-		.num_channels = 8,
-	},
-	[ID_AD5648_1] = {
-		.shared_vref = true,
-		.internal_vref = 2500000,
-		.channels = ad5044_channels,
-		.num_channels = 8,
-	},
-	[ID_AD5648_2] = {
-		.shared_vref = true,
-		.internal_vref = 5000000,
-		.channels = ad5044_channels,
-		.num_channels = 8,
-	},
-	[ID_AD5666_1] = {
-		.shared_vref = true,
-		.internal_vref = 2500000,
-		.channels = ad5064_channels,
-		.num_channels = 4,
-	},
-	[ID_AD5666_2] = {
-		.shared_vref = true,
-		.internal_vref = 5000000,
-		.channels = ad5064_channels,
-		.num_channels = 4,
-	},
-	[ID_AD5668_1] = {
-		.shared_vref = true,
-		.internal_vref = 2500000,
-		.channels = ad5064_channels,
-		.num_channels = 8,
-	},
-	[ID_AD5668_2] = {
-		.shared_vref = true,
-		.internal_vref = 5000000,
-		.channels = ad5064_channels,
-		.num_channels = 8,
-	},
-};
-
-static inline unsigned int ad5064_num_vref(struct ad5064_state *st)
-{
-	return st->chip_info->shared_vref ? 1 : st->chip_info->num_channels;
-}
-
-static const char * const ad5064_vref_names[] = {
-	"vrefA",
-	"vrefB",
-	"vrefC",
-	"vrefD",
-};
-
-static const char * const ad5064_vref_name(struct ad5064_state *st,
-	unsigned int vref)
-{
-	return st->chip_info->shared_vref ? "vref" : ad5064_vref_names[vref];
-}
-
-static int __devinit ad5064_probe(struct spi_device *spi)
-{
-	enum ad5064_type type = spi_get_device_id(spi)->driver_data;
-	struct iio_dev *indio_dev;
-	struct ad5064_state *st;
-	unsigned int i;
-	int ret;
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL)
-		return  -ENOMEM;
-
-	st = iio_priv(indio_dev);
-	spi_set_drvdata(spi, indio_dev);
-
-	st->chip_info = &ad5064_chip_info_tbl[type];
-	st->spi = spi;
-
-	for (i = 0; i < ad5064_num_vref(st); ++i)
-		st->vref_reg[i].supply = ad5064_vref_name(st, i);
-
-	ret = regulator_bulk_get(&st->spi->dev, ad5064_num_vref(st),
-		st->vref_reg);
-	if (ret) {
-		if (!st->chip_info->internal_vref)
-			goto error_free;
-		st->use_internal_vref = true;
-		ret = ad5064_spi_write(st, AD5064_CMD_CONFIG, 0,
-			AD5064_CONFIG_INT_VREF_ENABLE, 0);
-		if (ret) {
-			dev_err(&spi->dev, "Failed to enable internal vref: %d\n",
-				ret);
-			goto error_free;
-		}
-	} else {
-		ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg);
-		if (ret)
-			goto error_free_reg;
-	}
-
-	for (i = 0; i < st->chip_info->num_channels; ++i) {
-		st->pwr_down_mode[i] = AD5064_LDAC_PWRDN_1K;
-		st->dac_cache[i] = 0x8000;
-	}
-
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->info = &ad5064_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = st->chip_info->channels;
-	indio_dev->num_channels = st->chip_info->num_channels;
-
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_disable_reg;
-
-	return 0;
-
-error_disable_reg:
-	if (!st->use_internal_vref)
-		regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
-error_free_reg:
-	if (!st->use_internal_vref)
-		regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
-error_free:
-	iio_device_free(indio_dev);
-
-	return ret;
-}
-
-
-static int __devexit ad5064_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad5064_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-
-	if (!st->use_internal_vref) {
-		regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
-		regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
-	}
-
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad5064_id[] = {
-	{"ad5024", ID_AD5024},
-	{"ad5025", ID_AD5025},
-	{"ad5044", ID_AD5044},
-	{"ad5045", ID_AD5045},
-	{"ad5064", ID_AD5064},
-	{"ad5064-1", ID_AD5064_1},
-	{"ad5065", ID_AD5065},
-	{"ad5628-1", ID_AD5628_1},
-	{"ad5628-2", ID_AD5628_2},
-	{"ad5648-1", ID_AD5648_1},
-	{"ad5648-2", ID_AD5648_2},
-	{"ad5666-1", ID_AD5666_1},
-	{"ad5666-2", ID_AD5666_2},
-	{"ad5668-1", ID_AD5668_1},
-	{"ad5668-2", ID_AD5668_2},
-	{"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */
-	{}
-};
-MODULE_DEVICE_TABLE(spi, ad5064_id);
-
-static struct spi_driver ad5064_driver = {
-	.driver = {
-		   .name = "ad5064",
-		   .owner = THIS_MODULE,
-	},
-	.probe = ad5064_probe,
-	.remove = __devexit_p(ad5064_remove),
-	.id_table = ad5064_id,
-};
-module_spi_driver(ad5064_driver);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("Analog Devices AD5024/25/44/45/64/64-1/65, AD5628/48/66/68 DAC");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/ad5360.c b/drivers/staging/iio/dac/ad5360.c
deleted file mode 100644
index 38660ef..0000000
--- a/drivers/staging/iio/dac/ad5360.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * Analog devices AD5360, AD5361, AD5362, AD5363, AD5370, AD5371, AD5373
- * multi-channel Digital to Analog Converters driver
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/regulator/consumer.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include "dac.h"
-
-#define AD5360_CMD(x)				((x) << 22)
-#define AD5360_ADDR(x)				((x) << 16)
-
-#define AD5360_READBACK_TYPE(x)			((x) << 13)
-#define AD5360_READBACK_ADDR(x)			((x) << 7)
-
-#define AD5360_CHAN_ADDR(chan)			((chan) + 0x8)
-
-#define AD5360_CMD_WRITE_DATA			0x3
-#define AD5360_CMD_WRITE_OFFSET			0x2
-#define AD5360_CMD_WRITE_GAIN			0x1
-#define AD5360_CMD_SPECIAL_FUNCTION		0x0
-
-/* Special function register addresses */
-#define AD5360_REG_SF_NOP			0x0
-#define AD5360_REG_SF_CTRL			0x1
-#define AD5360_REG_SF_OFS(x)			(0x2 + (x))
-#define AD5360_REG_SF_READBACK			0x5
-
-#define AD5360_SF_CTRL_PWR_DOWN			BIT(0)
-
-#define AD5360_READBACK_X1A			0x0
-#define AD5360_READBACK_X1B			0x1
-#define AD5360_READBACK_OFFSET			0x2
-#define AD5360_READBACK_GAIN			0x3
-#define AD5360_READBACK_SF			0x4
-
-
-/**
- * struct ad5360_chip_info - chip specific information
- * @channel_template:	channel specification template
- * @num_channels:	number of channels
- * @channels_per_group:	number of channels per group
- * @num_vrefs:		number of vref supplies for the chip
-*/
-
-struct ad5360_chip_info {
-	struct iio_chan_spec	channel_template;
-	unsigned int		num_channels;
-	unsigned int		channels_per_group;
-	unsigned int		num_vrefs;
-};
-
-/**
- * struct ad5360_state - driver instance specific data
- * @spi:		spi_device
- * @chip_info:		chip model specific constants, available modes etc
- * @vref_reg:		vref supply regulators
- * @ctrl:		control register cache
- * @data:		spi transfer buffers
- */
-
-struct ad5360_state {
-	struct spi_device		*spi;
-	const struct ad5360_chip_info	*chip_info;
-	struct regulator_bulk_data	vref_reg[3];
-	unsigned int			ctrl;
-
-	/*
-	 * DMA (thus cache coherency maintenance) requires the
-	 * transfer buffers to live in their own cache lines.
-	 */
-	union {
-		__be32 d32;
-		u8 d8[4];
-	} data[2] ____cacheline_aligned;
-};
-
-enum ad5360_type {
-	ID_AD5360,
-	ID_AD5361,
-	ID_AD5362,
-	ID_AD5363,
-	ID_AD5370,
-	ID_AD5371,
-	ID_AD5372,
-	ID_AD5373,
-};
-
-#define AD5360_CHANNEL(bits) {					\
-	.type = IIO_VOLTAGE,					\
-	.indexed = 1,						\
-	.output = 1,						\
-	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
-		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |		\
-		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |		\
-		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |	\
-		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,	\
-	.scan_type = IIO_ST('u', (bits), 16, 16 - (bits))	\
-}
-
-static const struct ad5360_chip_info ad5360_chip_info_tbl[] = {
-	[ID_AD5360] = {
-		.channel_template = AD5360_CHANNEL(16),
-		.num_channels = 16,
-		.channels_per_group = 8,
-		.num_vrefs = 2,
-	},
-	[ID_AD5361] = {
-		.channel_template = AD5360_CHANNEL(14),
-		.num_channels = 16,
-		.channels_per_group = 8,
-		.num_vrefs = 2,
-	},
-	[ID_AD5362] = {
-		.channel_template = AD5360_CHANNEL(16),
-		.num_channels = 8,
-		.channels_per_group = 4,
-		.num_vrefs = 2,
-	},
-	[ID_AD5363] = {
-		.channel_template = AD5360_CHANNEL(14),
-		.num_channels = 8,
-		.channels_per_group = 4,
-		.num_vrefs = 2,
-	},
-	[ID_AD5370] = {
-		.channel_template = AD5360_CHANNEL(16),
-		.num_channels = 40,
-		.channels_per_group = 8,
-		.num_vrefs = 2,
-	},
-	[ID_AD5371] = {
-		.channel_template = AD5360_CHANNEL(14),
-		.num_channels = 40,
-		.channels_per_group = 8,
-		.num_vrefs = 3,
-	},
-	[ID_AD5372] = {
-		.channel_template = AD5360_CHANNEL(16),
-		.num_channels = 32,
-		.channels_per_group = 8,
-		.num_vrefs = 2,
-	},
-	[ID_AD5373] = {
-		.channel_template = AD5360_CHANNEL(14),
-		.num_channels = 32,
-		.channels_per_group = 8,
-		.num_vrefs = 2,
-	},
-};
-
-static unsigned int ad5360_get_channel_vref_index(struct ad5360_state *st,
-	unsigned int channel)
-{
-	unsigned int i;
-
-	/* The first groups have their own vref, while the remaining groups
-	 * share the last vref */
-	i = channel / st->chip_info->channels_per_group;
-	if (i >= st->chip_info->num_vrefs)
-		i = st->chip_info->num_vrefs - 1;
-
-	return i;
-}
-
-static int ad5360_get_channel_vref(struct ad5360_state *st,
-	unsigned int channel)
-{
-	unsigned int i = ad5360_get_channel_vref_index(st, channel);
-
-	return regulator_get_voltage(st->vref_reg[i].consumer);
-}
-
-
-static int ad5360_write_unlocked(struct iio_dev *indio_dev,
-	unsigned int cmd, unsigned int addr, unsigned int val,
-	unsigned int shift)
-{
-	struct ad5360_state *st = iio_priv(indio_dev);
-
-	val <<= shift;
-	val |= AD5360_CMD(cmd) | AD5360_ADDR(addr);
-	st->data[0].d32 = cpu_to_be32(val);
-
-	return spi_write(st->spi, &st->data[0].d8[1], 3);
-}
-
-static int ad5360_write(struct iio_dev *indio_dev, unsigned int cmd,
-	unsigned int addr, unsigned int val, unsigned int shift)
-{
-	int ret;
-
-	mutex_lock(&indio_dev->mlock);
-	ret = ad5360_write_unlocked(indio_dev, cmd, addr, val, shift);
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret;
-}
-
-static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
-	unsigned int addr)
-{
-	struct ad5360_state *st = iio_priv(indio_dev);
-	struct spi_message m;
-	int ret;
-	struct spi_transfer t[] = {
-		{
-			.tx_buf = &st->data[0].d8[1],
-			.len = 3,
-			.cs_change = 1,
-		}, {
-			.rx_buf = &st->data[1].d8[1],
-			.len = 3,
-		},
-	};
-
-	spi_message_init(&m);
-	spi_message_add_tail(&t[0], &m);
-	spi_message_add_tail(&t[1], &m);
-
-	mutex_lock(&indio_dev->mlock);
-
-	st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) |
-		AD5360_ADDR(AD5360_REG_SF_READBACK) |
-		AD5360_READBACK_TYPE(type) |
-		AD5360_READBACK_ADDR(addr));
-
-	ret = spi_sync(st->spi, &m);
-	if (ret >= 0)
-		ret = be32_to_cpu(st->data[1].d32) & 0xffff;
-
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret;
-}
-
-static ssize_t ad5360_read_dac_powerdown(struct device *dev,
-					   struct device_attribute *attr,
-					   char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5360_state *st = iio_priv(indio_dev);
-
-	return sprintf(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN));
-}
-
-static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
-	unsigned int clr)
-{
-	struct ad5360_state *st = iio_priv(indio_dev);
-	unsigned int ret;
-
-	mutex_lock(&indio_dev->mlock);
-
-	st->ctrl |= set;
-	st->ctrl &= ~clr;
-
-	ret = ad5360_write_unlocked(indio_dev, AD5360_CMD_SPECIAL_FUNCTION,
-			AD5360_REG_SF_CTRL, st->ctrl, 0);
-
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret;
-}
-
-static ssize_t ad5360_write_dac_powerdown(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	bool pwr_down;
-	int ret;
-
-	ret = strtobool(buf, &pwr_down);
-	if (ret)
-		return ret;
-
-	if (pwr_down)
-		ret = ad5360_update_ctrl(indio_dev, AD5360_SF_CTRL_PWR_DOWN, 0);
-	else
-		ret = ad5360_update_ctrl(indio_dev, 0, AD5360_SF_CTRL_PWR_DOWN);
-
-	return ret ? ret : len;
-}
-
-static IIO_DEVICE_ATTR(out_voltage_powerdown,
-			S_IRUGO | S_IWUSR,
-			ad5360_read_dac_powerdown,
-			ad5360_write_dac_powerdown, 0);
-
-static struct attribute *ad5360_attributes[] = {
-	&iio_dev_attr_out_voltage_powerdown.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad5360_attribute_group = {
-	.attrs = ad5360_attributes,
-};
-
-static int ad5360_write_raw(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       int val,
-			       int val2,
-			       long mask)
-{
-	struct ad5360_state *st = iio_priv(indio_dev);
-	int max_val = (1 << chan->scan_type.realbits);
-	unsigned int ofs_index;
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		if (val >= max_val || val < 0)
-			return -EINVAL;
-
-		return ad5360_write(indio_dev, AD5360_CMD_WRITE_DATA,
-				 chan->address, val, chan->scan_type.shift);
-
-	case IIO_CHAN_INFO_CALIBBIAS:
-		if (val >= max_val || val < 0)
-			return -EINVAL;
-
-		return ad5360_write(indio_dev, AD5360_CMD_WRITE_OFFSET,
-				 chan->address, val, chan->scan_type.shift);
-
-	case IIO_CHAN_INFO_CALIBSCALE:
-		if (val >= max_val || val < 0)
-			return -EINVAL;
-
-		return ad5360_write(indio_dev, AD5360_CMD_WRITE_GAIN,
-				 chan->address, val, chan->scan_type.shift);
-
-	case IIO_CHAN_INFO_OFFSET:
-		if (val <= -max_val || val > 0)
-			return -EINVAL;
-
-		val = -val;
-
-		/* offset is supposed to have the same scale as raw, but it
-		 * is always 14bits wide, so on a chip where the raw value has
-		 * more bits, we need to shift offset. */
-		val >>= (chan->scan_type.realbits - 14);
-
-		/* There is one DAC offset register per vref. Changing one
-		 * channels offset will also change the offset for all other
-		 * channels which share the same vref supply. */
-		ofs_index = ad5360_get_channel_vref_index(st, chan->channel);
-		return ad5360_write(indio_dev, AD5360_CMD_SPECIAL_FUNCTION,
-				 AD5360_REG_SF_OFS(ofs_index), val, 0);
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
-static int ad5360_read_raw(struct iio_dev *indio_dev,
-			   struct iio_chan_spec const *chan,
-			   int *val,
-			   int *val2,
-			   long m)
-{
-	struct ad5360_state *st = iio_priv(indio_dev);
-	unsigned int ofs_index;
-	int scale_uv;
-	int ret;
-
-	switch (m) {
-	case IIO_CHAN_INFO_RAW:
-		ret = ad5360_read(indio_dev, AD5360_READBACK_X1A,
-			chan->address);
-		if (ret < 0)
-			return ret;
-		*val = ret >> chan->scan_type.shift;
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_SCALE:
-		/* vout = 4 * vref * dac_code */
-		scale_uv = ad5360_get_channel_vref(st, chan->channel) * 4 * 100;
-		if (scale_uv < 0)
-			return scale_uv;
-
-		scale_uv >>= (chan->scan_type.realbits);
-		*val =  scale_uv / 100000;
-		*val2 = (scale_uv % 100000) * 10;
-		return IIO_VAL_INT_PLUS_MICRO;
-	case IIO_CHAN_INFO_CALIBBIAS:
-		ret = ad5360_read(indio_dev, AD5360_READBACK_OFFSET,
-			chan->address);
-		if (ret < 0)
-			return ret;
-		*val = ret;
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_CALIBSCALE:
-		ret = ad5360_read(indio_dev, AD5360_READBACK_GAIN,
-			chan->address);
-		if (ret < 0)
-			return ret;
-		*val = ret;
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_OFFSET:
-		ofs_index = ad5360_get_channel_vref_index(st, chan->channel);
-		ret = ad5360_read(indio_dev, AD5360_READBACK_SF,
-			AD5360_REG_SF_OFS(ofs_index));
-		if (ret < 0)
-			return ret;
-
-		ret <<= (chan->scan_type.realbits - 14);
-		*val = -ret;
-		return IIO_VAL_INT;
-	}
-
-	return -EINVAL;
-}
-
-static const struct iio_info ad5360_info = {
-	.read_raw = ad5360_read_raw,
-	.write_raw = ad5360_write_raw,
-	.attrs = &ad5360_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static const char * const ad5360_vref_name[] = {
-	 "vref0", "vref1", "vref2"
-};
-
-static int __devinit ad5360_alloc_channels(struct iio_dev *indio_dev)
-{
-	struct ad5360_state *st = iio_priv(indio_dev);
-	struct iio_chan_spec *channels;
-	unsigned int i;
-
-	channels = kcalloc(st->chip_info->num_channels,
-			   sizeof(struct iio_chan_spec), GFP_KERNEL);
-
-	if (!channels)
-		return -ENOMEM;
-
-	for (i = 0; i < st->chip_info->num_channels; ++i) {
-		channels[i] = st->chip_info->channel_template;
-		channels[i].channel = i;
-		channels[i].address = AD5360_CHAN_ADDR(i);
-	}
-
-	indio_dev->channels = channels;
-
-	return 0;
-}
-
-static int __devinit ad5360_probe(struct spi_device *spi)
-{
-	enum ad5360_type type = spi_get_device_id(spi)->driver_data;
-	struct iio_dev *indio_dev;
-	struct ad5360_state *st;
-	unsigned int i;
-	int ret;
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		dev_err(&spi->dev, "Failed to allocate iio device\n");
-		return  -ENOMEM;
-	}
-
-	st = iio_priv(indio_dev);
-	spi_set_drvdata(spi, indio_dev);
-
-	st->chip_info = &ad5360_chip_info_tbl[type];
-	st->spi = spi;
-
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->info = &ad5360_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->num_channels = st->chip_info->num_channels;
-
-	ret = ad5360_alloc_channels(indio_dev);
-	if (ret) {
-		dev_err(&spi->dev, "Failed to allocate channel spec: %d\n", ret);
-		goto error_free;
-	}
-
-	for (i = 0; i < st->chip_info->num_vrefs; ++i)
-		st->vref_reg[i].supply = ad5360_vref_name[i];
-
-	ret = regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs,
-		st->vref_reg);
-	if (ret) {
-		dev_err(&spi->dev, "Failed to request vref regulators: %d\n", ret);
-		goto error_free_channels;
-	}
-
-	ret = regulator_bulk_enable(st->chip_info->num_vrefs, st->vref_reg);
-	if (ret) {
-		dev_err(&spi->dev, "Failed to enable vref regulators: %d\n", ret);
-		goto error_free_reg;
-	}
-
-	ret = iio_device_register(indio_dev);
-	if (ret) {
-		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
-		goto error_disable_reg;
-	}
-
-	return 0;
-
-error_disable_reg:
-	regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
-error_free_reg:
-	regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
-error_free_channels:
-	kfree(indio_dev->channels);
-error_free:
-	iio_device_free(indio_dev);
-
-	return ret;
-}
-
-static int __devexit ad5360_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad5360_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-
-	kfree(indio_dev->channels);
-
-	regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
-	regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
-
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad5360_ids[] = {
-	{ "ad5360", ID_AD5360 },
-	{ "ad5361", ID_AD5361 },
-	{ "ad5362", ID_AD5362 },
-	{ "ad5363", ID_AD5363 },
-	{ "ad5370", ID_AD5370 },
-	{ "ad5371", ID_AD5371 },
-	{ "ad5372", ID_AD5372 },
-	{ "ad5373", ID_AD5373 },
-	{}
-};
-MODULE_DEVICE_TABLE(spi, ad5360_ids);
-
-static struct spi_driver ad5360_driver = {
-	.driver = {
-		   .name = "ad5360",
-		   .owner = THIS_MODULE,
-	},
-	.probe = ad5360_probe,
-	.remove = __devexit_p(ad5360_remove),
-	.id_table = ad5360_ids,
-};
-module_spi_driver(ad5360_driver);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("Analog Devices AD5360/61/62/63/70/71/72/73 DAC");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/ad5380.c b/drivers/staging/iio/dac/ad5380.c
deleted file mode 100644
index 370d284..0000000
--- a/drivers/staging/iio/dac/ad5380.c
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Analog devices AD5380, AD5381, AD5382, AD5383, AD5390, AD5391, AD5392
- * multi-channel Digital to Analog Converters driver
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/regmap.h>
-#include <linux/regulator/consumer.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include "dac.h"
-
-
-#define AD5380_REG_DATA(x)	(((x) << 2) | 3)
-#define AD5380_REG_OFFSET(x)	(((x) << 2) | 2)
-#define AD5380_REG_GAIN(x)	(((x) << 2) | 1)
-#define AD5380_REG_SF_PWR_DOWN	(8 << 2)
-#define AD5380_REG_SF_PWR_UP	(9 << 2)
-#define AD5380_REG_SF_CTRL	(12 << 2)
-
-#define AD5380_CTRL_PWR_DOWN_MODE_OFFSET	13
-#define AD5380_CTRL_INT_VREF_2V5		BIT(12)
-#define AD5380_CTRL_INT_VREF_EN			BIT(10)
-
-/**
- * struct ad5380_chip_info - chip specific information
- * @channel_template:	channel specification template
- * @num_channels:	number of channels
- * @int_vref:		internal vref in uV
-*/
-
-struct ad5380_chip_info {
-	struct iio_chan_spec	channel_template;
-	unsigned int		num_channels;
-	unsigned int		int_vref;
-};
-
-/**
- * struct ad5380_state - driver instance specific data
- * @regmap:		regmap instance used by the device
- * @chip_info:		chip model specific constants, available modes etc
- * @vref_reg:		vref supply regulator
- * @vref:		actual reference voltage used in uA
- * @pwr_down:		whether the chip is currently in power down mode
- */
-
-struct ad5380_state {
-	struct regmap			*regmap;
-	const struct ad5380_chip_info	*chip_info;
-	struct regulator		*vref_reg;
-	int				vref;
-	bool				pwr_down;
-};
-
-enum ad5380_type {
-	ID_AD5380_3,
-	ID_AD5380_5,
-	ID_AD5381_3,
-	ID_AD5381_5,
-	ID_AD5382_3,
-	ID_AD5382_5,
-	ID_AD5383_3,
-	ID_AD5383_5,
-	ID_AD5390_3,
-	ID_AD5390_5,
-	ID_AD5391_3,
-	ID_AD5391_5,
-	ID_AD5392_3,
-	ID_AD5392_5,
-};
-
-#define AD5380_CHANNEL(_bits) {					\
-	.type = IIO_VOLTAGE,					\
-	.indexed = 1,						\
-	.output = 1,						\
-	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
-		IIO_CHAN_INFO_SCALE_SHARED_BIT |		\
-		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |		\
-		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,		\
-	.scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits))	\
-}
-
-static const struct ad5380_chip_info ad5380_chip_info_tbl[] = {
-	[ID_AD5380_3] = {
-		.channel_template = AD5380_CHANNEL(14),
-		.num_channels = 40,
-		.int_vref = 1250000,
-	},
-	[ID_AD5380_5] = {
-		.channel_template = AD5380_CHANNEL(14),
-		.num_channels = 40,
-		.int_vref = 2500000,
-	},
-	[ID_AD5381_3] = {
-		.channel_template = AD5380_CHANNEL(12),
-		.num_channels = 16,
-		.int_vref = 1250000,
-	},
-	[ID_AD5381_5] = {
-		.channel_template = AD5380_CHANNEL(12),
-		.num_channels = 16,
-		.int_vref = 2500000,
-	},
-	[ID_AD5382_3] = {
-		.channel_template = AD5380_CHANNEL(14),
-		.num_channels = 32,
-		.int_vref = 1250000,
-	},
-	[ID_AD5382_5] = {
-		.channel_template = AD5380_CHANNEL(14),
-		.num_channels = 32,
-		.int_vref = 2500000,
-	},
-	[ID_AD5383_3] = {
-		.channel_template = AD5380_CHANNEL(12),
-		.num_channels = 32,
-		.int_vref = 1250000,
-	},
-	[ID_AD5383_5] = {
-		.channel_template = AD5380_CHANNEL(12),
-		.num_channels = 32,
-		.int_vref = 2500000,
-	},
-	[ID_AD5390_3] = {
-		.channel_template = AD5380_CHANNEL(14),
-		.num_channels = 16,
-		.int_vref = 1250000,
-	},
-	[ID_AD5390_5] = {
-		.channel_template = AD5380_CHANNEL(14),
-		.num_channels = 16,
-		.int_vref = 2500000,
-	},
-	[ID_AD5391_3] = {
-		.channel_template = AD5380_CHANNEL(12),
-		.num_channels = 16,
-		.int_vref = 1250000,
-	},
-	[ID_AD5391_5] = {
-		.channel_template = AD5380_CHANNEL(12),
-		.num_channels = 16,
-		.int_vref = 2500000,
-	},
-	[ID_AD5392_3] = {
-		.channel_template = AD5380_CHANNEL(14),
-		.num_channels = 8,
-		.int_vref = 1250000,
-	},
-	[ID_AD5392_5] = {
-		.channel_template = AD5380_CHANNEL(14),
-		.num_channels = 8,
-		.int_vref = 2500000,
-	},
-};
-
-static ssize_t ad5380_read_dac_powerdown(struct device *dev,
-	struct device_attribute *attr, char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5380_state *st = iio_priv(indio_dev);
-
-	return sprintf(buf, "%d\n", st->pwr_down);
-}
-
-static ssize_t ad5380_write_dac_powerdown(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5380_state *st = iio_priv(indio_dev);
-	bool pwr_down;
-	int ret;
-
-	ret = strtobool(buf, &pwr_down);
-	if (ret)
-		return ret;
-
-	mutex_lock(&indio_dev->mlock);
-
-	if (pwr_down)
-		ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_DOWN, 0);
-	else
-		ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_UP, 0);
-
-	st->pwr_down = pwr_down;
-
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret ? ret : len;
-}
-
-static IIO_DEVICE_ATTR(out_voltage_powerdown,
-			S_IRUGO | S_IWUSR,
-			ad5380_read_dac_powerdown,
-			ad5380_write_dac_powerdown, 0);
-
-static const char ad5380_powerdown_modes[][15] = {
-	[0]	= "100kohm_to_gnd",
-	[1]	= "three_state",
-};
-
-static ssize_t ad5380_read_powerdown_mode(struct device *dev,
-	struct device_attribute *attr, char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5380_state *st = iio_priv(indio_dev);
-	unsigned int mode;
-	int ret;
-
-	ret = regmap_read(st->regmap, AD5380_REG_SF_CTRL, &mode);
-	if (ret)
-		return ret;
-
-	mode = (mode >> AD5380_CTRL_PWR_DOWN_MODE_OFFSET) & 1;
-
-	return sprintf(buf, "%s\n", ad5380_powerdown_modes[mode]);
-}
-
-static ssize_t ad5380_write_powerdown_mode(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5380_state *st = iio_priv(indio_dev);
-	unsigned int i;
-	int ret;
-
-	for (i = 0; i < ARRAY_SIZE(ad5380_powerdown_modes); ++i) {
-		if (sysfs_streq(buf, ad5380_powerdown_modes[i]))
-			break;
-	}
-
-	if (i == ARRAY_SIZE(ad5380_powerdown_modes))
-		return -EINVAL;
-
-	ret = regmap_update_bits(st->regmap, AD5380_REG_SF_CTRL,
-		1 << AD5380_CTRL_PWR_DOWN_MODE_OFFSET,
-		i << AD5380_CTRL_PWR_DOWN_MODE_OFFSET);
-
-	return ret ? ret : len;
-}
-
-static IIO_DEVICE_ATTR(out_voltage_powerdown_mode,
-			S_IRUGO | S_IWUSR,
-			ad5380_read_powerdown_mode,
-			ad5380_write_powerdown_mode, 0);
-
-static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
-			"100kohm_to_gnd three_state");
-
-static struct attribute *ad5380_attributes[] = {
-	&iio_dev_attr_out_voltage_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr,
-	&iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad5380_attribute_group = {
-	.attrs = ad5380_attributes,
-};
-
-static unsigned int ad5380_info_to_reg(struct iio_chan_spec const *chan,
-	long info)
-{
-	switch (info) {
-	case 0:
-		return AD5380_REG_DATA(chan->address);
-	case IIO_CHAN_INFO_CALIBBIAS:
-		return AD5380_REG_OFFSET(chan->address);
-	case IIO_CHAN_INFO_CALIBSCALE:
-		return AD5380_REG_GAIN(chan->address);
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int ad5380_write_raw(struct iio_dev *indio_dev,
-	struct iio_chan_spec const *chan, int val, int val2, long info)
-{
-	const unsigned int max_val = (1 << chan->scan_type.realbits);
-	struct ad5380_state *st = iio_priv(indio_dev);
-
-	switch (info) {
-	case IIO_CHAN_INFO_RAW:
-	case IIO_CHAN_INFO_CALIBSCALE:
-		if (val >= max_val || val < 0)
-			return -EINVAL;
-
-		return regmap_write(st->regmap,
-			ad5380_info_to_reg(chan, info),
-			val << chan->scan_type.shift);
-	case IIO_CHAN_INFO_CALIBBIAS:
-		val += (1 << chan->scan_type.realbits) / 2;
-		if (val >= max_val || val < 0)
-			return -EINVAL;
-
-		return regmap_write(st->regmap,
-			AD5380_REG_OFFSET(chan->address),
-			val << chan->scan_type.shift);
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-static int ad5380_read_raw(struct iio_dev *indio_dev,
-	struct iio_chan_spec const *chan, int *val, int *val2, long info)
-{
-	struct ad5380_state *st = iio_priv(indio_dev);
-	unsigned long scale_uv;
-	int ret;
-
-	switch (info) {
-	case IIO_CHAN_INFO_RAW:
-	case IIO_CHAN_INFO_CALIBSCALE:
-		ret = regmap_read(st->regmap, ad5380_info_to_reg(chan, info),
-					val);
-		if (ret)
-			return ret;
-		*val >>= chan->scan_type.shift;
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_CALIBBIAS:
-		ret = regmap_read(st->regmap, AD5380_REG_OFFSET(chan->address),
-					val);
-		if (ret)
-			return ret;
-		*val >>= chan->scan_type.shift;
-		val -= (1 << chan->scan_type.realbits) / 2;
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_SCALE:
-		scale_uv = ((2 * st->vref) >> chan->scan_type.realbits) * 100;
-		*val =  scale_uv / 100000;
-		*val2 = (scale_uv % 100000) * 10;
-		return IIO_VAL_INT_PLUS_MICRO;
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
-static const struct iio_info ad5380_info = {
-	.read_raw = ad5380_read_raw,
-	.write_raw = ad5380_write_raw,
-	.attrs = &ad5380_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad5380_alloc_channels(struct iio_dev *indio_dev)
-{
-	struct ad5380_state *st = iio_priv(indio_dev);
-	struct iio_chan_spec *channels;
-	unsigned int i;
-
-	channels = kcalloc(st->chip_info->num_channels,
-			   sizeof(struct iio_chan_spec), GFP_KERNEL);
-
-	if (!channels)
-		return -ENOMEM;
-
-	for (i = 0; i < st->chip_info->num_channels; ++i) {
-		channels[i] = st->chip_info->channel_template;
-		channels[i].channel = i;
-		channels[i].address = i;
-	}
-
-	indio_dev->channels = channels;
-
-	return 0;
-}
-
-static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap,
-	enum ad5380_type type, const char *name)
-{
-	struct iio_dev *indio_dev;
-	struct ad5380_state *st;
-	unsigned int ctrl = 0;
-	int ret;
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		dev_err(dev, "Failed to allocate iio device\n");
-		ret = -ENOMEM;
-		goto error_regmap_exit;
-	}
-
-	st = iio_priv(indio_dev);
-	dev_set_drvdata(dev, indio_dev);
-
-	st->chip_info = &ad5380_chip_info_tbl[type];
-	st->regmap = regmap;
-
-	indio_dev->dev.parent = dev;
-	indio_dev->name = name;
-	indio_dev->info = &ad5380_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->num_channels = st->chip_info->num_channels;
-
-	ret = ad5380_alloc_channels(indio_dev);
-	if (ret) {
-		dev_err(dev, "Failed to allocate channel spec: %d\n", ret);
-		goto error_free;
-	}
-
-	if (st->chip_info->int_vref == 2500000)
-		ctrl |= AD5380_CTRL_INT_VREF_2V5;
-
-	st->vref_reg = regulator_get(dev, "vref");
-	if (!IS_ERR(st->vref_reg)) {
-		ret = regulator_enable(st->vref_reg);
-		if (ret) {
-			dev_err(dev, "Failed to enable vref regulators: %d\n",
-				ret);
-			goto error_free_reg;
-		}
-
-		st->vref = regulator_get_voltage(st->vref_reg);
-	} else {
-		st->vref = st->chip_info->int_vref;
-		ctrl |= AD5380_CTRL_INT_VREF_EN;
-	}
-
-	ret = regmap_write(st->regmap, AD5380_REG_SF_CTRL, ctrl);
-	if (ret) {
-		dev_err(dev, "Failed to write to device: %d\n", ret);
-		goto error_disable_reg;
-	}
-
-	ret = iio_device_register(indio_dev);
-	if (ret) {
-		dev_err(dev, "Failed to register iio device: %d\n", ret);
-		goto error_disable_reg;
-	}
-
-	return 0;
-
-error_disable_reg:
-	if (!IS_ERR(st->vref_reg))
-		regulator_disable(st->vref_reg);
-error_free_reg:
-	if (!IS_ERR(st->vref_reg))
-		regulator_put(st->vref_reg);
-
-	kfree(indio_dev->channels);
-error_free:
-	iio_device_free(indio_dev);
-error_regmap_exit:
-	regmap_exit(regmap);
-
-	return ret;
-}
-
-static int __devexit ad5380_remove(struct device *dev)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	struct ad5380_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-
-	kfree(indio_dev->channels);
-
-	if (!IS_ERR(st->vref_reg)) {
-		regulator_disable(st->vref_reg);
-		regulator_put(st->vref_reg);
-	}
-
-	regmap_exit(st->regmap);
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static bool ad5380_reg_false(struct device *dev, unsigned int reg)
-{
-	return false;
-}
-
-static const struct regmap_config ad5380_regmap_config = {
-	.reg_bits = 10,
-	.val_bits = 14,
-
-	.max_register = AD5380_REG_DATA(40),
-	.cache_type = REGCACHE_RBTREE,
-
-	.volatile_reg = ad5380_reg_false,
-	.readable_reg = ad5380_reg_false,
-};
-
-#if IS_ENABLED(CONFIG_SPI_MASTER)
-
-static int __devinit ad5380_spi_probe(struct spi_device *spi)
-{
-	const struct spi_device_id *id = spi_get_device_id(spi);
-	struct regmap *regmap;
-
-	regmap = regmap_init_spi(spi, &ad5380_regmap_config);
-
-	if (IS_ERR(regmap))
-		return PTR_ERR(regmap);
-
-	return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name);
-}
-
-static int __devexit ad5380_spi_remove(struct spi_device *spi)
-{
-	return ad5380_remove(&spi->dev);
-}
-
-static const struct spi_device_id ad5380_spi_ids[] = {
-	{ "ad5380-3", ID_AD5380_3 },
-	{ "ad5380-5", ID_AD5380_5 },
-	{ "ad5381-3", ID_AD5381_3 },
-	{ "ad5381-5", ID_AD5381_5 },
-	{ "ad5382-3", ID_AD5382_3 },
-	{ "ad5382-5", ID_AD5382_5 },
-	{ "ad5383-3", ID_AD5383_3 },
-	{ "ad5383-5", ID_AD5383_5 },
-	{ "ad5384-3", ID_AD5380_3 },
-	{ "ad5384-5", ID_AD5380_5 },
-	{ "ad5390-3", ID_AD5390_3 },
-	{ "ad5390-5", ID_AD5390_5 },
-	{ "ad5391-3", ID_AD5391_3 },
-	{ "ad5391-5", ID_AD5391_5 },
-	{ "ad5392-3", ID_AD5392_3 },
-	{ "ad5392-5", ID_AD5392_5 },
-	{ }
-};
-MODULE_DEVICE_TABLE(spi, ad5380_spi_ids);
-
-static struct spi_driver ad5380_spi_driver = {
-	.driver = {
-		   .name = "ad5380",
-		   .owner = THIS_MODULE,
-	},
-	.probe = ad5380_spi_probe,
-	.remove = __devexit_p(ad5380_spi_remove),
-	.id_table = ad5380_spi_ids,
-};
-
-static inline int ad5380_spi_register_driver(void)
-{
-	return spi_register_driver(&ad5380_spi_driver);
-}
-
-static inline void ad5380_spi_unregister_driver(void)
-{
-	spi_unregister_driver(&ad5380_spi_driver);
-}
-
-#else
-
-static inline int ad5380_spi_register_driver(void)
-{
-	return 0;
-}
-
-static inline void ad5380_spi_unregister_driver(void)
-{
-}
-
-#endif
-
-#if IS_ENABLED(CONFIG_I2C)
-
-static int __devinit ad5380_i2c_probe(struct i2c_client *i2c,
-	const struct i2c_device_id *id)
-{
-	struct regmap *regmap;
-
-	regmap = regmap_init_i2c(i2c, &ad5380_regmap_config);
-
-	if (IS_ERR(regmap))
-		return PTR_ERR(regmap);
-
-	return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name);
-}
-
-static int __devexit ad5380_i2c_remove(struct i2c_client *i2c)
-{
-	return ad5380_remove(&i2c->dev);
-}
-
-static const struct i2c_device_id ad5380_i2c_ids[] = {
-	{ "ad5380-3", ID_AD5380_3 },
-	{ "ad5380-5", ID_AD5380_5 },
-	{ "ad5381-3", ID_AD5381_3 },
-	{ "ad5381-5", ID_AD5381_5 },
-	{ "ad5382-3", ID_AD5382_3 },
-	{ "ad5382-5", ID_AD5382_5 },
-	{ "ad5383-3", ID_AD5383_3 },
-	{ "ad5383-5", ID_AD5383_5 },
-	{ "ad5384-3", ID_AD5380_3 },
-	{ "ad5384-5", ID_AD5380_5 },
-	{ "ad5390-3", ID_AD5390_3 },
-	{ "ad5390-5", ID_AD5390_5 },
-	{ "ad5391-3", ID_AD5391_3 },
-	{ "ad5391-5", ID_AD5391_5 },
-	{ "ad5392-3", ID_AD5392_3 },
-	{ "ad5392-5", ID_AD5392_5 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids);
-
-static struct i2c_driver ad5380_i2c_driver = {
-	.driver = {
-		   .name = "ad5380",
-		   .owner = THIS_MODULE,
-	},
-	.probe = ad5380_i2c_probe,
-	.remove = __devexit_p(ad5380_i2c_remove),
-	.id_table = ad5380_i2c_ids,
-};
-
-static inline int ad5380_i2c_register_driver(void)
-{
-	return i2c_add_driver(&ad5380_i2c_driver);
-}
-
-static inline void ad5380_i2c_unregister_driver(void)
-{
-	i2c_del_driver(&ad5380_i2c_driver);
-}
-
-#else
-
-static inline int ad5380_i2c_register_driver(void)
-{
-	return 0;
-}
-
-static inline void ad5380_i2c_unregister_driver(void)
-{
-}
-
-#endif
-
-static int __init ad5380_spi_init(void)
-{
-	int ret;
-
-	ret = ad5380_spi_register_driver();
-	if (ret)
-		return ret;
-
-	ret = ad5380_i2c_register_driver();
-	if (ret) {
-		ad5380_spi_unregister_driver();
-		return ret;
-	}
-
-	return 0;
-}
-module_init(ad5380_spi_init);
-
-static void __exit ad5380_spi_exit(void)
-{
-	ad5380_i2c_unregister_driver();
-	ad5380_spi_unregister_driver();
-
-}
-module_exit(ad5380_spi_exit);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("Analog Devices AD5380/81/82/83/84/90/91/92 DAC");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/ad5421.c b/drivers/staging/iio/dac/ad5421.c
deleted file mode 100644
index ffbd4c2..0000000
--- a/drivers/staging/iio/dac/ad5421.c
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- * AD5421 Digital to analog converters  driver
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-#include "dac.h"
-#include "ad5421.h"
-
-
-#define AD5421_REG_DAC_DATA		0x1
-#define AD5421_REG_CTRL			0x2
-#define AD5421_REG_OFFSET		0x3
-#define AD5421_REG_GAIN			0x4
-/* load dac and fault shared the same register number. Writing to it will cause
- * a dac load command, reading from it will return the fault status register */
-#define AD5421_REG_LOAD_DAC		0x5
-#define AD5421_REG_FAULT		0x5
-#define AD5421_REG_FORCE_ALARM_CURRENT	0x6
-#define AD5421_REG_RESET		0x7
-#define AD5421_REG_START_CONVERSION	0x8
-#define AD5421_REG_NOOP			0x9
-
-#define AD5421_CTRL_WATCHDOG_DISABLE	BIT(12)
-#define AD5421_CTRL_AUTO_FAULT_READBACK	BIT(11)
-#define AD5421_CTRL_MIN_CURRENT		BIT(9)
-#define AD5421_CTRL_ADC_SOURCE_TEMP	BIT(8)
-#define AD5421_CTRL_ADC_ENABLE		BIT(7)
-#define AD5421_CTRL_PWR_DOWN_INT_VREF	BIT(6)
-
-#define AD5421_FAULT_SPI			BIT(15)
-#define AD5421_FAULT_PEC			BIT(14)
-#define AD5421_FAULT_OVER_CURRENT		BIT(13)
-#define AD5421_FAULT_UNDER_CURRENT		BIT(12)
-#define AD5421_FAULT_TEMP_OVER_140		BIT(11)
-#define AD5421_FAULT_TEMP_OVER_100		BIT(10)
-#define AD5421_FAULT_UNDER_VOLTAGE_6V		BIT(9)
-#define AD5421_FAULT_UNDER_VOLTAGE_12V		BIT(8)
-
-/* These bits will cause the fault pin to go high */
-#define AD5421_FAULT_TRIGGER_IRQ \
-	(AD5421_FAULT_SPI | AD5421_FAULT_PEC | AD5421_FAULT_OVER_CURRENT | \
-	AD5421_FAULT_UNDER_CURRENT | AD5421_FAULT_TEMP_OVER_140)
-
-/**
- * struct ad5421_state - driver instance specific data
- * @spi:		spi_device
- * @ctrl:		control register cache
- * @current_range:	current range which the device is configured for
- * @data:		spi transfer buffers
- * @fault_mask:		software masking of events
- */
-struct ad5421_state {
-	struct spi_device		*spi;
-	unsigned int			ctrl;
-	enum ad5421_current_range	current_range;
-	unsigned int			fault_mask;
-
-	/*
-	 * DMA (thus cache coherency maintenance) requires the
-	 * transfer buffers to live in their own cache lines.
-	 */
-	union {
-		u32 d32;
-		u8 d8[4];
-	} data[2] ____cacheline_aligned;
-};
-
-static const struct iio_chan_spec ad5421_channels[] = {
-	{
-		.type = IIO_CURRENT,
-		.indexed = 1,
-		.output = 1,
-		.channel = 0,
-		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-			IIO_CHAN_INFO_SCALE_SHARED_BIT |
-			IIO_CHAN_INFO_OFFSET_SHARED_BIT |
-			IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
-			IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
-		.scan_type = IIO_ST('u', 16, 16, 0),
-		.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
-			IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING),
-	},
-	{
-		.type = IIO_TEMP,
-		.channel = -1,
-		.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
-	},
-};
-
-static int ad5421_write_unlocked(struct iio_dev *indio_dev,
-	unsigned int reg, unsigned int val)
-{
-	struct ad5421_state *st = iio_priv(indio_dev);
-
-	st->data[0].d32 = cpu_to_be32((reg << 16) | val);
-
-	return spi_write(st->spi, &st->data[0].d8[1], 3);
-}
-
-static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg,
-	unsigned int val)
-{
-	int ret;
-
-	mutex_lock(&indio_dev->mlock);
-	ret = ad5421_write_unlocked(indio_dev, reg, val);
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret;
-}
-
-static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg)
-{
-	struct ad5421_state *st = iio_priv(indio_dev);
-	struct spi_message m;
-	int ret;
-	struct spi_transfer t[] = {
-		{
-			.tx_buf = &st->data[0].d8[1],
-			.len = 3,
-			.cs_change = 1,
-		}, {
-			.rx_buf = &st->data[1].d8[1],
-			.len = 3,
-		},
-	};
-
-	spi_message_init(&m);
-	spi_message_add_tail(&t[0], &m);
-	spi_message_add_tail(&t[1], &m);
-
-	mutex_lock(&indio_dev->mlock);
-
-	st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
-
-	ret = spi_sync(st->spi, &m);
-	if (ret >= 0)
-		ret = be32_to_cpu(st->data[1].d32) & 0xffff;
-
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret;
-}
-
-static int ad5421_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
-	unsigned int clr)
-{
-	struct ad5421_state *st = iio_priv(indio_dev);
-	unsigned int ret;
-
-	mutex_lock(&indio_dev->mlock);
-
-	st->ctrl &= ~clr;
-	st->ctrl |= set;
-
-	ret = ad5421_write_unlocked(indio_dev, AD5421_REG_CTRL, st->ctrl);
-
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret;
-}
-
-static irqreturn_t ad5421_fault_handler(int irq, void *data)
-{
-	struct iio_dev *indio_dev = data;
-	struct ad5421_state *st = iio_priv(indio_dev);
-	unsigned int fault;
-	unsigned int old_fault = 0;
-	unsigned int events;
-
-	fault = ad5421_read(indio_dev, AD5421_REG_FAULT);
-	if (!fault)
-		return IRQ_NONE;
-
-	/* If we had a fault, this might mean that the DAC has lost its state
-	 * and has been reset. Make sure that the control register actually
-	 * contains what we expect it to contain. Otherwise the watchdog might
-	 * be enabled and we get watchdog timeout faults, which will render the
-	 * DAC unusable. */
-	ad5421_update_ctrl(indio_dev, 0, 0);
-
-
-	/* The fault pin stays high as long as a fault condition is present and
-	 * it is not possible to mask fault conditions. For certain fault
-	 * conditions for example like over-temperature it takes some time
-	 * until the fault condition disappears. If we would exit the interrupt
-	 * handler immediately after handling the event it would be entered
-	 * again instantly. Thus we fall back to polling in case we detect that
-	 * a interrupt condition is still present.
-	 */
-	do {
-		/* 0xffff is a invalid value for the register and will only be
-		 * read if there has been a communication error */
-		if (fault == 0xffff)
-			fault = 0;
-
-		/* we are only interested in new events */
-		events = (old_fault ^ fault) & fault;
-		events &= st->fault_mask;
-
-		if (events & AD5421_FAULT_OVER_CURRENT) {
-			iio_push_event(indio_dev,
-				IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
-					0,
-					IIO_EV_TYPE_THRESH,
-					IIO_EV_DIR_RISING),
-			iio_get_time_ns());
-		}
-
-		if (events & AD5421_FAULT_UNDER_CURRENT) {
-			iio_push_event(indio_dev,
-				IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
-					0,
-					IIO_EV_TYPE_THRESH,
-					IIO_EV_DIR_FALLING),
-				iio_get_time_ns());
-		}
-
-		if (events & AD5421_FAULT_TEMP_OVER_140) {
-			iio_push_event(indio_dev,
-				IIO_UNMOD_EVENT_CODE(IIO_TEMP,
-					0,
-					IIO_EV_TYPE_MAG,
-					IIO_EV_DIR_RISING),
-				iio_get_time_ns());
-		}
-
-		old_fault = fault;
-		fault = ad5421_read(indio_dev, AD5421_REG_FAULT);
-
-		/* still active? go to sleep for some time */
-		if (fault & AD5421_FAULT_TRIGGER_IRQ)
-			msleep(1000);
-
-	} while (fault & AD5421_FAULT_TRIGGER_IRQ);
-
-
-	return IRQ_HANDLED;
-}
-
-static void ad5421_get_current_min_max(struct ad5421_state *st,
-	unsigned int *min, unsigned int *max)
-{
-	/* The current range is configured using external pins, which are
-	 * usually hard-wired and not run-time switchable. */
-	switch (st->current_range) {
-	case AD5421_CURRENT_RANGE_4mA_20mA:
-		*min = 4000;
-		*max = 20000;
-		break;
-	case AD5421_CURRENT_RANGE_3mA8_21mA:
-		*min = 3800;
-		*max = 21000;
-		break;
-	case AD5421_CURRENT_RANGE_3mA2_24mA:
-		*min = 3200;
-		*max = 24000;
-		break;
-	default:
-		*min = 0;
-		*max = 1;
-		break;
-	}
-}
-
-static inline unsigned int ad5421_get_offset(struct ad5421_state *st)
-{
-	unsigned int min, max;
-
-	ad5421_get_current_min_max(st, &min, &max);
-	return (min * (1 << 16)) / (max - min);
-}
-
-static inline unsigned int ad5421_get_scale(struct ad5421_state *st)
-{
-	unsigned int min, max;
-
-	ad5421_get_current_min_max(st, &min, &max);
-	return ((max - min) * 1000) / (1 << 16);
-}
-
-static int ad5421_read_raw(struct iio_dev *indio_dev,
-	struct iio_chan_spec const *chan, int *val, int *val2, long m)
-{
-	struct ad5421_state *st = iio_priv(indio_dev);
-	int ret;
-
-	if (chan->type != IIO_CURRENT)
-		return -EINVAL;
-
-	switch (m) {
-	case IIO_CHAN_INFO_RAW:
-		ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
-		if (ret < 0)
-			return ret;
-		*val = ret;
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_SCALE:
-		*val = 0;
-		*val2 = ad5421_get_scale(st);
-		return IIO_VAL_INT_PLUS_MICRO;
-	case IIO_CHAN_INFO_OFFSET:
-		*val = ad5421_get_offset(st);
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_CALIBBIAS:
-		ret = ad5421_read(indio_dev, AD5421_REG_OFFSET);
-		if (ret < 0)
-			return ret;
-		*val = ret - 32768;
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_CALIBSCALE:
-		ret = ad5421_read(indio_dev, AD5421_REG_GAIN);
-		if (ret < 0)
-			return ret;
-		*val = ret;
-		return IIO_VAL_INT;
-	}
-
-	return -EINVAL;
-}
-
-static int ad5421_write_raw(struct iio_dev *indio_dev,
-	struct iio_chan_spec const *chan, int val, int val2, long mask)
-{
-	const unsigned int max_val = 1 << 16;
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		if (val >= max_val || val < 0)
-			return -EINVAL;
-
-		return ad5421_write(indio_dev, AD5421_REG_DAC_DATA, val);
-	case IIO_CHAN_INFO_CALIBBIAS:
-		val += 32768;
-		if (val >= max_val || val < 0)
-			return -EINVAL;
-
-		return ad5421_write(indio_dev, AD5421_REG_OFFSET, val);
-	case IIO_CHAN_INFO_CALIBSCALE:
-		if (val >= max_val || val < 0)
-			return -EINVAL;
-
-		return ad5421_write(indio_dev, AD5421_REG_GAIN, val);
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
-static int ad5421_write_event_config(struct iio_dev *indio_dev,
-	u64 event_code, int state)
-{
-	struct ad5421_state *st = iio_priv(indio_dev);
-	unsigned int mask;
-
-	switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
-	case IIO_CURRENT:
-		if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
-			IIO_EV_DIR_RISING)
-			mask = AD5421_FAULT_OVER_CURRENT;
-		else
-			mask = AD5421_FAULT_UNDER_CURRENT;
-		break;
-	case IIO_TEMP:
-		mask = AD5421_FAULT_TEMP_OVER_140;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	mutex_lock(&indio_dev->mlock);
-	if (state)
-		st->fault_mask |= mask;
-	else
-		st->fault_mask &= ~mask;
-	mutex_unlock(&indio_dev->mlock);
-
-	return 0;
-}
-
-static int ad5421_read_event_config(struct iio_dev *indio_dev,
-	u64 event_code)
-{
-	struct ad5421_state *st = iio_priv(indio_dev);
-	unsigned int mask;
-
-	switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
-	case IIO_CURRENT:
-		if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
-			IIO_EV_DIR_RISING)
-			mask = AD5421_FAULT_OVER_CURRENT;
-		else
-			mask = AD5421_FAULT_UNDER_CURRENT;
-		break;
-	case IIO_TEMP:
-		mask = AD5421_FAULT_TEMP_OVER_140;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return (bool)(st->fault_mask & mask);
-}
-
-static int ad5421_read_event_value(struct iio_dev *indio_dev, u64 event_code,
-	int *val)
-{
-	int ret;
-
-	switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
-	case IIO_CURRENT:
-		ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
-		if (ret < 0)
-			return ret;
-		*val = ret;
-		break;
-	case IIO_TEMP:
-		*val = 140000;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static const struct iio_info ad5421_info = {
-	.read_raw =		ad5421_read_raw,
-	.write_raw =		ad5421_write_raw,
-	.read_event_config =	ad5421_read_event_config,
-	.write_event_config =	ad5421_write_event_config,
-	.read_event_value =	ad5421_read_event_value,
-	.driver_module =	THIS_MODULE,
-};
-
-static int __devinit ad5421_probe(struct spi_device *spi)
-{
-	struct ad5421_platform_data *pdata = dev_get_platdata(&spi->dev);
-	struct iio_dev *indio_dev;
-	struct ad5421_state *st;
-	int ret;
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		dev_err(&spi->dev, "Failed to allocate iio device\n");
-		return  -ENOMEM;
-	}
-
-	st = iio_priv(indio_dev);
-	spi_set_drvdata(spi, indio_dev);
-
-	st->spi = spi;
-
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = "ad5421";
-	indio_dev->info = &ad5421_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = ad5421_channels;
-	indio_dev->num_channels = ARRAY_SIZE(ad5421_channels);
-
-	st->ctrl = AD5421_CTRL_WATCHDOG_DISABLE |
-			AD5421_CTRL_AUTO_FAULT_READBACK;
-
-	if (pdata) {
-		st->current_range = pdata->current_range;
-		if (pdata->external_vref)
-			st->ctrl |= AD5421_CTRL_PWR_DOWN_INT_VREF;
-	} else {
-		st->current_range = AD5421_CURRENT_RANGE_4mA_20mA;
-	}
-
-	/* write initial ctrl register value */
-	ad5421_update_ctrl(indio_dev, 0, 0);
-
-	if (spi->irq) {
-		ret = request_threaded_irq(spi->irq,
-					   NULL,
-					   ad5421_fault_handler,
-					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-					   "ad5421 fault",
-					   indio_dev);
-		if (ret)
-			goto error_free;
-	}
-
-	ret = iio_device_register(indio_dev);
-	if (ret) {
-		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
-		goto error_free_irq;
-	}
-
-	return 0;
-
-error_free_irq:
-	if (spi->irq)
-		free_irq(spi->irq, indio_dev);
-error_free:
-	iio_device_free(indio_dev);
-
-	return ret;
-}
-
-static int __devexit ad5421_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-
-	iio_device_unregister(indio_dev);
-	if (spi->irq)
-		free_irq(spi->irq, indio_dev);
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static struct spi_driver ad5421_driver = {
-	.driver = {
-		   .name = "ad5421",
-		   .owner = THIS_MODULE,
-	},
-	.probe = ad5421_probe,
-	.remove = __devexit_p(ad5421_remove),
-};
-module_spi_driver(ad5421_driver);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("Analog Devices AD5421 DAC");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:ad5421");
diff --git a/drivers/staging/iio/dac/ad5421.h b/drivers/staging/iio/dac/ad5421.h
deleted file mode 100644
index cd2bb84..0000000
--- a/drivers/staging/iio/dac/ad5421.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __IIO_DAC_AD5421_H__
-#define __IIO_DAC_AD5421_H__
-
-/*
- * TODO: This file needs to go into include/linux/iio
- */
-
-/**
- * enum ad5421_current_range - Current range the AD5421 is configured for.
- * @AD5421_CURRENT_RANGE_4mA_20mA: 4 mA to 20 mA (RANGE1,0 pins = 00)
- * @AD5421_CURRENT_RANGE_3mA8_21mA: 3.8 mA to 21 mA (RANGE1,0 pins = x1)
- * @AD5421_CURRENT_RANGE_3mA2_24mA: 3.2 mA to 24 mA (RANGE1,0 pins = 10)
- */
-
-enum ad5421_current_range {
-	AD5421_CURRENT_RANGE_4mA_20mA,
-	AD5421_CURRENT_RANGE_3mA8_21mA,
-	AD5421_CURRENT_RANGE_3mA2_24mA,
-};
-
-/**
- * struct ad5421_platform_data - AD5421 DAC driver platform data
- * @external_vref: whether an external reference voltage is used or not
- * @current_range: Current range the AD5421 is configured for
- */
-
-struct ad5421_platform_data {
-	bool external_vref;
-	enum ad5421_current_range current_range;
-};
-
-#endif
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c
deleted file mode 100644
index daa65b3..0000000
--- a/drivers/staging/iio/dac/ad5446.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * AD5446 SPI DAC driver
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/list.h>
-#include <linux/spi/spi.h>
-#include <linux/regulator/consumer.h>
-#include <linux/err.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include "dac.h"
-
-#include "ad5446.h"
-
-static int ad5446_write(struct ad5446_state *st, unsigned val)
-{
-	__be16 data = cpu_to_be16(val);
-	return spi_write(st->spi, &data, sizeof(data));
-}
-
-static int ad5660_write(struct ad5446_state *st, unsigned val)
-{
-	uint8_t data[3];
-
-	data[0] = (val >> 16) & 0xFF;
-	data[1] = (val >> 8) & 0xFF;
-	data[2] = val & 0xFF;
-
-	return spi_write(st->spi, data, sizeof(data));
-}
-
-static const char * const ad5446_powerdown_modes[] = {
-	"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"
-};
-
-static ssize_t ad5446_read_powerdown_mode_available(struct iio_dev *indio_dev,
-	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
-{
-	return sprintf(buf, "%s %s %s\n", ad5446_powerdown_modes[1],
-		ad5446_powerdown_modes[2], ad5446_powerdown_modes[3]);
-}
-
-static ssize_t ad5446_write_powerdown_mode(struct iio_dev *indio_dev,
-					    uintptr_t private,
-					    const struct iio_chan_spec *chan,
-					    const char *buf, size_t len)
-{
-	struct ad5446_state *st = iio_priv(indio_dev);
-	int i;
-
-	for (i = 1; i < ARRAY_SIZE(ad5446_powerdown_modes); i++) {
-		if (sysfs_streq(buf, ad5446_powerdown_modes[i])) {
-			st->pwr_down_mode = i;
-			break;
-		}
-	}
-
-	if (i == ARRAY_SIZE(ad5446_powerdown_modes))
-		return -EINVAL;
-
-	return len;
-}
-
-static ssize_t ad5446_read_powerdown_mode(struct iio_dev *indio_dev,
-					   uintptr_t private,
-					   const struct iio_chan_spec *chan,
-					   char *buf)
-{
-	struct ad5446_state *st = iio_priv(indio_dev);
-
-	return sprintf(buf, "%s\n", ad5446_powerdown_modes[st->pwr_down_mode]);
-}
-
-static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev,
-					   uintptr_t private,
-					   const struct iio_chan_spec *chan,
-					   char *buf)
-{
-	struct ad5446_state *st = iio_priv(indio_dev);
-
-	return sprintf(buf, "%d\n", st->pwr_down);
-}
-
-static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev,
-					    uintptr_t private,
-					    const struct iio_chan_spec *chan,
-					    const char *buf, size_t len)
-{
-	struct ad5446_state *st = iio_priv(indio_dev);
-	unsigned int shift;
-	unsigned int val;
-	bool powerdown;
-	int ret;
-
-	ret = strtobool(buf, &powerdown);
-	if (ret)
-		return ret;
-
-	mutex_lock(&indio_dev->mlock);
-	st->pwr_down = powerdown;
-
-	if (st->pwr_down) {
-		shift = chan->scan_type.realbits + chan->scan_type.shift;
-		val = st->pwr_down_mode << shift;
-	} else {
-		val = st->cached_val;
-	}
-
-	ret = st->chip_info->write(st, val);
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret ? ret : len;
-}
-
-static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = {
-	{
-		.name = "powerdown",
-		.read = ad5446_read_dac_powerdown,
-		.write = ad5446_write_dac_powerdown,
-	}, {
-		.name = "powerdown_mode",
-		.read = ad5446_read_powerdown_mode,
-		.write = ad5446_write_powerdown_mode,
-	}, {
-		.name = "powerdown_mode_available",
-		.shared = true,
-		.read = ad5446_read_powerdown_mode_available,
-	},
-	{ },
-};
-
-#define _AD5446_CHANNEL(bits, storage, shift, ext) { \
-	.type = IIO_VOLTAGE, \
-	.indexed = 1, \
-	.output = 1, \
-	.channel = 0, \
-	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
-	IIO_CHAN_INFO_SCALE_SHARED_BIT,	\
-	.scan_type = IIO_ST('u', (bits), (storage), (shift)), \
-	.ext_info = (ext), \
-}
-
-#define AD5446_CHANNEL(bits, storage, shift) \
-	_AD5446_CHANNEL(bits, storage, shift, NULL)
-
-#define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \
-	_AD5446_CHANNEL(bits, storage, shift, ad5064_ext_info_powerdown)
-
-static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
-	[ID_AD5444] = {
-		.channel = AD5446_CHANNEL(12, 16, 2),
-		.write = ad5446_write,
-	},
-	[ID_AD5446] = {
-		.channel = AD5446_CHANNEL(14, 16, 0),
-		.write = ad5446_write,
-	},
-	[ID_AD5541A] = {
-		.channel = AD5446_CHANNEL(16, 16, 0),
-		.write = ad5446_write,
-	},
-	[ID_AD5512A] = {
-		.channel = AD5446_CHANNEL(12, 16, 4),
-		.write = ad5446_write,
-	},
-	[ID_AD5553] = {
-		.channel = AD5446_CHANNEL(14, 16, 0),
-		.write = ad5446_write,
-	},
-	[ID_AD5601] = {
-		.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
-		.write = ad5446_write,
-	},
-	[ID_AD5611] = {
-		.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4),
-		.write = ad5446_write,
-	},
-	[ID_AD5621] = {
-		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
-		.write = ad5446_write,
-	},
-	[ID_AD5620_2500] = {
-		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
-		.int_vref_mv = 2500,
-		.write = ad5446_write,
-	},
-	[ID_AD5620_1250] = {
-		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
-		.int_vref_mv = 1250,
-		.write = ad5446_write,
-	},
-	[ID_AD5640_2500] = {
-		.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
-		.int_vref_mv = 2500,
-		.write = ad5446_write,
-	},
-	[ID_AD5640_1250] = {
-		.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
-		.int_vref_mv = 1250,
-		.write = ad5446_write,
-	},
-	[ID_AD5660_2500] = {
-		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
-		.int_vref_mv = 2500,
-		.write = ad5660_write,
-	},
-	[ID_AD5660_1250] = {
-		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
-		.int_vref_mv = 1250,
-		.write = ad5660_write,
-	},
-	[ID_AD5662] = {
-		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
-		.write = ad5660_write,
-	},
-};
-
-static int ad5446_read_raw(struct iio_dev *indio_dev,
-			   struct iio_chan_spec const *chan,
-			   int *val,
-			   int *val2,
-			   long m)
-{
-	struct ad5446_state *st = iio_priv(indio_dev);
-	unsigned long scale_uv;
-
-	switch (m) {
-	case IIO_CHAN_INFO_RAW:
-		*val = st->cached_val;
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_SCALE:
-		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
-		*val =  scale_uv / 1000;
-		*val2 = (scale_uv % 1000) * 1000;
-		return IIO_VAL_INT_PLUS_MICRO;
-
-	}
-	return -EINVAL;
-}
-
-static int ad5446_write_raw(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       int val,
-			       int val2,
-			       long mask)
-{
-	struct ad5446_state *st = iio_priv(indio_dev);
-	int ret = 0;
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		if (val >= (1 << chan->scan_type.realbits) || val < 0)
-			return -EINVAL;
-
-		val <<= chan->scan_type.shift;
-		mutex_lock(&indio_dev->mlock);
-		st->cached_val = val;
-		if (!st->pwr_down)
-			ret = st->chip_info->write(st, val);
-		mutex_unlock(&indio_dev->mlock);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static const struct iio_info ad5446_info = {
-	.read_raw = ad5446_read_raw,
-	.write_raw = ad5446_write_raw,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad5446_probe(struct spi_device *spi)
-{
-	struct ad5446_state *st;
-	struct iio_dev *indio_dev;
-	struct regulator *reg;
-	int ret, voltage_uv = 0;
-
-	reg = regulator_get(&spi->dev, "vcc");
-	if (!IS_ERR(reg)) {
-		ret = regulator_enable(reg);
-		if (ret)
-			goto error_put_reg;
-
-		voltage_uv = regulator_get_voltage(reg);
-	}
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_disable_reg;
-	}
-	st = iio_priv(indio_dev);
-	st->chip_info =
-		&ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data];
-
-	spi_set_drvdata(spi, indio_dev);
-	st->reg = reg;
-	st->spi = spi;
-
-	/* Establish that the iio_dev is a child of the spi device */
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->info = &ad5446_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = &st->chip_info->channel;
-	indio_dev->num_channels = 1;
-
-	if (st->chip_info->int_vref_mv)
-		st->vref_mv = st->chip_info->int_vref_mv;
-	else if (voltage_uv)
-		st->vref_mv = voltage_uv / 1000;
-	else
-		dev_warn(&spi->dev, "reference voltage unspecified\n");
-
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_free_device;
-
-	return 0;
-
-error_free_device:
-	iio_device_free(indio_dev);
-error_disable_reg:
-	if (!IS_ERR(reg))
-		regulator_disable(reg);
-error_put_reg:
-	if (!IS_ERR(reg))
-		regulator_put(reg);
-
-	return ret;
-}
-
-static int ad5446_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad5446_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-	if (!IS_ERR(st->reg)) {
-		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad5446_id[] = {
-	{"ad5444", ID_AD5444},
-	{"ad5446", ID_AD5446},
-	{"ad5512a", ID_AD5512A},
-	{"ad5541a", ID_AD5541A},
-	{"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
-	{"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
-	{"ad5553", ID_AD5553},
-	{"ad5601", ID_AD5601},
-	{"ad5611", ID_AD5611},
-	{"ad5621", ID_AD5621},
-	{"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */
-	{"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */
-	{"ad5640-2500", ID_AD5640_2500},
-	{"ad5640-1250", ID_AD5640_1250},
-	{"ad5660-2500", ID_AD5660_2500},
-	{"ad5660-1250", ID_AD5660_1250},
-	{"ad5662", ID_AD5662},
-	{}
-};
-MODULE_DEVICE_TABLE(spi, ad5446_id);
-
-static struct spi_driver ad5446_driver = {
-	.driver = {
-		.name	= "ad5446",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= ad5446_probe,
-	.remove		= __devexit_p(ad5446_remove),
-	.id_table	= ad5446_id,
-};
-module_spi_driver(ad5446_driver);
-
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h
deleted file mode 100644
index dfd68ce..0000000
--- a/drivers/staging/iio/dac/ad5446.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * AD5446 SPI DAC driver
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-#ifndef IIO_DAC_AD5446_H_
-#define IIO_DAC_AD5446_H_
-
-/* DAC Control Bits */
-
-#define AD5446_LOAD		(0x0 << 14) /* Load and update */
-#define AD5446_SDO_DIS		(0x1 << 14) /* Disable SDO */
-#define AD5446_NOP		(0x2 << 14) /* No operation */
-#define AD5446_CLK_RISING	(0x3 << 14) /* Clock data on rising edge */
-
-#define AD5620_LOAD		(0x0 << 14) /* Load and update Norm Operation*/
-#define AD5620_PWRDWN_1k	(0x1 << 14) /* Power-down: 1kOhm to GND */
-#define AD5620_PWRDWN_100k	(0x2 << 14) /* Power-down: 100kOhm to GND */
-#define AD5620_PWRDWN_TRISTATE	(0x3 << 14) /* Power-down: Three-state */
-
-#define AD5660_LOAD		(0x0 << 16) /* Load and update Norm Operation*/
-#define AD5660_PWRDWN_1k	(0x1 << 16) /* Power-down: 1kOhm to GND */
-#define AD5660_PWRDWN_100k	(0x2 << 16) /* Power-down: 100kOhm to GND */
-#define AD5660_PWRDWN_TRISTATE	(0x3 << 16) /* Power-down: Three-state */
-
-#define MODE_PWRDWN_1k		0x1
-#define MODE_PWRDWN_100k	0x2
-#define MODE_PWRDWN_TRISTATE	0x3
-
-/**
- * struct ad5446_state - driver instance specific data
- * @spi:		spi_device
- * @chip_info:		chip model specific constants, available modes etc
- * @reg:		supply regulator
- * @vref_mv:		actual reference voltage used
- */
-
-struct ad5446_state {
-	struct spi_device		*spi;
-	const struct ad5446_chip_info	*chip_info;
-	struct regulator		*reg;
-	unsigned short			vref_mv;
-	unsigned			cached_val;
-	unsigned			pwr_down_mode;
-	unsigned			pwr_down;
-};
-
-/**
- * struct ad5446_chip_info - chip specific information
- * @channel:		channel spec for the DAC
- * @int_vref_mv:	AD5620/40/60: the internal reference voltage
- * @write:		chip specific helper function to write to the register
- */
-
-struct ad5446_chip_info {
-	struct iio_chan_spec	channel;
-	u16			int_vref_mv;
-	int			(*write)(struct ad5446_state *st, unsigned val);
-};
-
-/**
- * ad5446_supported_device_ids:
- * The AD5620/40/60 parts are available in different fixed internal reference
- * voltage options. The actual part numbers may look differently
- * (and a bit cryptic), however this style is used to make clear which
- * parts are supported here.
- */
-
-enum ad5446_supported_device_ids {
-	ID_AD5444,
-	ID_AD5446,
-	ID_AD5541A,
-	ID_AD5512A,
-	ID_AD5553,
-	ID_AD5601,
-	ID_AD5611,
-	ID_AD5621,
-	ID_AD5620_2500,
-	ID_AD5620_1250,
-	ID_AD5640_2500,
-	ID_AD5640_1250,
-	ID_AD5660_2500,
-	ID_AD5660_1250,
-	ID_AD5662,
-};
-
-#endif /* IIO_DAC_AD5446_H_ */
diff --git a/drivers/staging/iio/dac/ad5504.c b/drivers/staging/iio/dac/ad5504.c
deleted file mode 100644
index 019cf15..0000000
--- a/drivers/staging/iio/dac/ad5504.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * AD5504, AD5501 High Voltage Digital to Analog Converter
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/regulator/consumer.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-#include "dac.h"
-#include "ad5504.h"
-
-#define AD5504_CHANNEL(_chan) { \
-	.type = IIO_VOLTAGE, \
-	.indexed = 1, \
-	.output = 1, \
-	.channel = (_chan), \
-	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
-		     IIO_CHAN_INFO_SCALE_SHARED_BIT, \
-	.address = AD5504_ADDR_DAC(_chan), \
-	.scan_type = IIO_ST('u', 12, 16, 0), \
-}
-
-static const struct iio_chan_spec ad5504_channels[] = {
-	AD5504_CHANNEL(0),
-	AD5504_CHANNEL(1),
-	AD5504_CHANNEL(2),
-	AD5504_CHANNEL(3),
-};
-
-static int ad5504_spi_write(struct spi_device *spi, u8 addr, u16 val)
-{
-	u16 tmp = cpu_to_be16(AD5504_CMD_WRITE |
-			      AD5504_ADDR(addr) |
-			      (val & AD5504_RES_MASK));
-
-	return spi_write(spi, (u8 *)&tmp, 2);
-}
-
-static int ad5504_spi_read(struct spi_device *spi, u8 addr)
-{
-	u16 tmp = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr));
-	u16 val;
-	int ret;
-	struct spi_transfer	t = {
-			.tx_buf		= &tmp,
-			.rx_buf		= &val,
-			.len		= 2,
-		};
-	struct spi_message	m;
-
-	spi_message_init(&m);
-	spi_message_add_tail(&t, &m);
-	ret = spi_sync(spi, &m);
-
-	if (ret < 0)
-		return ret;
-
-	return be16_to_cpu(val) & AD5504_RES_MASK;
-}
-
-static int ad5504_read_raw(struct iio_dev *indio_dev,
-			   struct iio_chan_spec const *chan,
-			   int *val,
-			   int *val2,
-			   long m)
-{
-	struct ad5504_state *st = iio_priv(indio_dev);
-	unsigned long scale_uv;
-	int ret;
-
-	switch (m) {
-	case IIO_CHAN_INFO_RAW:
-		ret = ad5504_spi_read(st->spi, chan->address);
-		if (ret < 0)
-			return ret;
-
-		*val = ret;
-
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_SCALE:
-		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
-		*val =  scale_uv / 1000;
-		*val2 = (scale_uv % 1000) * 1000;
-		return IIO_VAL_INT_PLUS_MICRO;
-
-	}
-	return -EINVAL;
-}
-
-static int ad5504_write_raw(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       int val,
-			       int val2,
-			       long mask)
-{
-	struct ad5504_state *st = iio_priv(indio_dev);
-	int ret;
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		if (val >= (1 << chan->scan_type.realbits) || val < 0)
-			return -EINVAL;
-
-		return ad5504_spi_write(st->spi, chan->address, val);
-	default:
-		ret = -EINVAL;
-	}
-
-	return -EINVAL;
-}
-
-static ssize_t ad5504_read_powerdown_mode(struct device *dev,
-				      struct device_attribute *attr, char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5504_state *st = iio_priv(indio_dev);
-
-	const char mode[][14] = {"20kohm_to_gnd", "three_state"};
-
-	return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
-}
-
-static ssize_t ad5504_write_powerdown_mode(struct device *dev,
-				       struct device_attribute *attr,
-				       const char *buf, size_t len)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5504_state *st = iio_priv(indio_dev);
-	int ret;
-
-	if (sysfs_streq(buf, "20kohm_to_gnd"))
-		st->pwr_down_mode = AD5504_DAC_PWRDN_20K;
-	else if (sysfs_streq(buf, "three_state"))
-		st->pwr_down_mode = AD5504_DAC_PWRDN_3STATE;
-	else
-		ret = -EINVAL;
-
-	return ret ? ret : len;
-}
-
-static ssize_t ad5504_read_dac_powerdown(struct device *dev,
-					   struct device_attribute *attr,
-					   char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5504_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
-	return sprintf(buf, "%d\n",
-			!(st->pwr_down_mask & (1 << this_attr->address)));
-}
-
-static ssize_t ad5504_write_dac_powerdown(struct device *dev,
-					    struct device_attribute *attr,
-					    const char *buf, size_t len)
-{
-	long readin;
-	int ret;
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5504_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
-	ret = strict_strtol(buf, 10, &readin);
-	if (ret)
-		return ret;
-
-	if (readin == 0)
-		st->pwr_down_mask |= (1 << this_attr->address);
-	else if (readin == 1)
-		st->pwr_down_mask &= ~(1 << this_attr->address);
-	else
-		ret = -EINVAL;
-
-	ret = ad5504_spi_write(st->spi, AD5504_ADDR_CTRL,
-				AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) |
-				AD5504_DAC_PWR(st->pwr_down_mask));
-
-	/* writes to the CTRL register must be followed by a NOOP */
-	ad5504_spi_write(st->spi, AD5504_ADDR_NOOP, 0);
-
-	return ret ? ret : len;
-}
-
-static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO |
-			S_IWUSR, ad5504_read_powerdown_mode,
-			ad5504_write_powerdown_mode, 0);
-
-static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
-			"20kohm_to_gnd three_state");
-
-#define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr)		\
-	IIO_DEVICE_ATTR(out_voltage##_num##_powerdown,			\
-			S_IRUGO | S_IWUSR, _show, _store, _addr)
-static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5504_read_dac_powerdown,
-				   ad5504_write_dac_powerdown, 0);
-static IIO_DEV_ATTR_DAC_POWERDOWN(1, ad5504_read_dac_powerdown,
-				   ad5504_write_dac_powerdown, 1);
-static IIO_DEV_ATTR_DAC_POWERDOWN(2, ad5504_read_dac_powerdown,
-				   ad5504_write_dac_powerdown, 2);
-static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5504_read_dac_powerdown,
-				   ad5504_write_dac_powerdown, 3);
-
-static struct attribute *ad5504_attributes[] = {
-	&iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage1_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage2_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage3_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr,
-	&iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad5504_attribute_group = {
-	.attrs = ad5504_attributes,
-};
-
-static struct attribute *ad5501_attributes[] = {
-	&iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr,
-	&iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad5501_attribute_group = {
-	.attrs = ad5501_attributes,
-};
-
-static IIO_CONST_ATTR(temp0_thresh_rising_value, "110000");
-static IIO_CONST_ATTR(temp0_thresh_rising_en, "1");
-
-static struct attribute *ad5504_ev_attributes[] = {
-	&iio_const_attr_temp0_thresh_rising_value.dev_attr.attr,
-	&iio_const_attr_temp0_thresh_rising_en.dev_attr.attr,
-	NULL,
-};
-
-static struct attribute_group ad5504_ev_attribute_group = {
-	.attrs = ad5504_ev_attributes,
-	.name = "events",
-};
-
-static irqreturn_t ad5504_event_handler(int irq, void *private)
-{
-	iio_push_event(private,
-		       IIO_UNMOD_EVENT_CODE(IIO_TEMP,
-					    0,
-					    IIO_EV_TYPE_THRESH,
-					    IIO_EV_DIR_RISING),
-		       iio_get_time_ns());
-
-	return IRQ_HANDLED;
-}
-
-static const struct iio_info ad5504_info = {
-	.write_raw = ad5504_write_raw,
-	.read_raw = ad5504_read_raw,
-	.attrs = &ad5504_attribute_group,
-	.event_attrs = &ad5504_ev_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static const struct iio_info ad5501_info = {
-	.write_raw = ad5504_write_raw,
-	.read_raw = ad5504_read_raw,
-	.attrs = &ad5501_attribute_group,
-	.event_attrs = &ad5504_ev_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad5504_probe(struct spi_device *spi)
-{
-	struct ad5504_platform_data *pdata = spi->dev.platform_data;
-	struct iio_dev *indio_dev;
-	struct ad5504_state *st;
-	struct regulator *reg;
-	int ret, voltage_uv = 0;
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	reg = regulator_get(&spi->dev, "vcc");
-	if (!IS_ERR(reg)) {
-		ret = regulator_enable(reg);
-		if (ret)
-			goto error_put_reg;
-
-		voltage_uv = regulator_get_voltage(reg);
-	}
-
-	spi_set_drvdata(spi, indio_dev);
-	st = iio_priv(indio_dev);
-	if (voltage_uv)
-		st->vref_mv = voltage_uv / 1000;
-	else if (pdata)
-		st->vref_mv = pdata->vref_mv;
-	else
-		dev_warn(&spi->dev, "reference voltage unspecified\n");
-
-	st->reg = reg;
-	st->spi = spi;
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = spi_get_device_id(st->spi)->name;
-	if (spi_get_device_id(st->spi)->driver_data == ID_AD5501) {
-		indio_dev->info = &ad5501_info;
-		indio_dev->num_channels = 1;
-	} else {
-		indio_dev->info = &ad5504_info;
-		indio_dev->num_channels = 4;
-	}
-	indio_dev->channels = ad5504_channels;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-
-	if (spi->irq) {
-		ret = request_threaded_irq(spi->irq,
-					   NULL,
-					   &ad5504_event_handler,
-					   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-					   spi_get_device_id(st->spi)->name,
-					   indio_dev);
-		if (ret)
-			goto error_disable_reg;
-	}
-
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_free_irq;
-
-	return 0;
-
-error_free_irq:
-	free_irq(spi->irq, indio_dev);
-error_disable_reg:
-	if (!IS_ERR(reg))
-		regulator_disable(reg);
-error_put_reg:
-	if (!IS_ERR(reg))
-		regulator_put(reg);
-
-	iio_device_free(indio_dev);
-error_ret:
-	return ret;
-}
-
-static int __devexit ad5504_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad5504_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-	if (spi->irq)
-		free_irq(spi->irq, indio_dev);
-
-	if (!IS_ERR(st->reg)) {
-		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad5504_id[] = {
-	{"ad5504", ID_AD5504},
-	{"ad5501", ID_AD5501},
-	{}
-};
-MODULE_DEVICE_TABLE(spi, ad5504_id);
-
-static struct spi_driver ad5504_driver = {
-	.driver = {
-		   .name = "ad5504",
-		   .owner = THIS_MODULE,
-		   },
-	.probe = ad5504_probe,
-	.remove = __devexit_p(ad5504_remove),
-	.id_table = ad5504_id,
-};
-module_spi_driver(ad5504_driver);
-
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/ad5504.h b/drivers/staging/iio/dac/ad5504.h
deleted file mode 100644
index afe0952..0000000
--- a/drivers/staging/iio/dac/ad5504.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * AD5504 SPI DAC driver
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#ifndef SPI_AD5504_H_
-#define SPI_AD5504_H_
-
-#define AD5505_BITS			12
-#define AD5504_RES_MASK			((1 << (AD5505_BITS)) - 1)
-
-#define AD5504_CMD_READ			(1 << 15)
-#define AD5504_CMD_WRITE		(0 << 15)
-#define AD5504_ADDR(addr)		((addr) << 12)
-
-/* Registers */
-#define AD5504_ADDR_NOOP		0
-#define AD5504_ADDR_DAC(x)		((x) + 1)
-#define AD5504_ADDR_ALL_DAC		5
-#define AD5504_ADDR_CTRL		7
-
-/* Control Register */
-#define AD5504_DAC_PWR(ch)		((ch) << 2)
-#define AD5504_DAC_PWRDWN_MODE(mode)	((mode) << 6)
-#define AD5504_DAC_PWRDN_20K		0
-#define AD5504_DAC_PWRDN_3STATE		1
-
-/*
- * TODO: struct ad5504_platform_data needs to go into include/linux/iio
- */
-
-struct ad5504_platform_data {
-	u16				vref_mv;
-};
-
-/**
- * struct ad5446_state - driver instance specific data
- * @us:			spi_device
- * @reg:		supply regulator
- * @vref_mv:		actual reference voltage used
- * @pwr_down_mask	power down mask
- * @pwr_down_mode	current power down mode
- */
-
-struct ad5504_state {
-	struct spi_device		*spi;
-	struct regulator		*reg;
-	unsigned short			vref_mv;
-	unsigned			pwr_down_mask;
-	unsigned			pwr_down_mode;
-};
-
-/**
- * ad5504_supported_device_ids:
- */
-
-enum ad5504_supported_device_ids {
-	ID_AD5504,
-	ID_AD5501,
-};
-
-#endif /* SPI_AD5504_H_ */
diff --git a/drivers/staging/iio/dac/ad5624r.h b/drivers/staging/iio/dac/ad5624r.h
deleted file mode 100644
index 5dca302..0000000
--- a/drivers/staging/iio/dac/ad5624r.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * AD5624R SPI DAC driver
- *
- * Copyright 2010-2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-#ifndef SPI_AD5624R_H_
-#define SPI_AD5624R_H_
-
-#define AD5624R_DAC_CHANNELS			4
-
-#define AD5624R_ADDR_DAC0			0x0
-#define AD5624R_ADDR_DAC1			0x1
-#define AD5624R_ADDR_DAC2			0x2
-#define AD5624R_ADDR_DAC3			0x3
-#define AD5624R_ADDR_ALL_DAC			0x7
-
-#define AD5624R_CMD_WRITE_INPUT_N		0x0
-#define AD5624R_CMD_UPDATE_DAC_N		0x1
-#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_ALL	0x2
-#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_N	0x3
-#define AD5624R_CMD_POWERDOWN_DAC		0x4
-#define AD5624R_CMD_RESET			0x5
-#define AD5624R_CMD_LDAC_SETUP			0x6
-#define AD5624R_CMD_INTERNAL_REFER_SETUP	0x7
-
-#define AD5624R_LDAC_PWRDN_NONE			0x0
-#define AD5624R_LDAC_PWRDN_1K			0x1
-#define AD5624R_LDAC_PWRDN_100K			0x2
-#define AD5624R_LDAC_PWRDN_3STATE		0x3
-
-/**
- * struct ad5624r_chip_info - chip specific information
- * @channels:		channel spec for the DAC
- * @int_vref_mv:	AD5620/40/60: the internal reference voltage
- */
-
-struct ad5624r_chip_info {
-	const struct iio_chan_spec	*channels;
-	u16				int_vref_mv;
-};
-
-/**
- * struct ad5446_state - driver instance specific data
- * @indio_dev:		the industrial I/O device
- * @us:			spi_device
- * @chip_info:		chip model specific constants, available modes etc
- * @reg:		supply regulator
- * @vref_mv:		actual reference voltage used
- * @pwr_down_mask	power down mask
- * @pwr_down_mode	current power down mode
- */
-
-struct ad5624r_state {
-	struct spi_device		*us;
-	const struct ad5624r_chip_info	*chip_info;
-	struct regulator		*reg;
-	unsigned short			vref_mv;
-	unsigned			pwr_down_mask;
-	unsigned			pwr_down_mode;
-};
-
-/**
- * ad5624r_supported_device_ids:
- * The AD5624/44/64 parts are available in different
- * fixed internal reference voltage options.
- */
-
-enum ad5624r_supported_device_ids {
-	ID_AD5624R3,
-	ID_AD5644R3,
-	ID_AD5664R3,
-	ID_AD5624R5,
-	ID_AD5644R5,
-	ID_AD5664R5,
-};
-
-#endif /* SPI_AD5624R_H_ */
diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c
deleted file mode 100644
index 42ff644..0000000
--- a/drivers/staging/iio/dac/ad5624r_spi.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver
- *
- * Copyright 2010-2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/regulator/consumer.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include "dac.h"
-#include "ad5624r.h"
-
-#define AD5624R_CHANNEL(_chan, _bits) { \
-	.type = IIO_VOLTAGE, \
-	.indexed = 1, \
-	.output = 1, \
-	.channel = (_chan), \
-	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
-		     IIO_CHAN_INFO_SCALE_SHARED_BIT, \
-	.address = (_chan), \
-	.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \
-}
-
-#define DECLARE_AD5624R_CHANNELS(_name, _bits) \
-	const struct iio_chan_spec _name##_channels[] = { \
-		AD5624R_CHANNEL(0, _bits), \
-		AD5624R_CHANNEL(1, _bits), \
-		AD5624R_CHANNEL(2, _bits), \
-		AD5624R_CHANNEL(3, _bits), \
-}
-
-static DECLARE_AD5624R_CHANNELS(ad5624r, 12);
-static DECLARE_AD5624R_CHANNELS(ad5644r, 14);
-static DECLARE_AD5624R_CHANNELS(ad5664r, 16);
-
-static const struct ad5624r_chip_info ad5624r_chip_info_tbl[] = {
-	[ID_AD5624R3] = {
-		.channels = ad5624r_channels,
-		.int_vref_mv = 1250,
-	},
-	[ID_AD5624R5] = {
-		.channels = ad5624r_channels,
-		.int_vref_mv = 2500,
-	},
-	[ID_AD5644R3] = {
-		.channels = ad5644r_channels,
-		.int_vref_mv = 1250,
-	},
-	[ID_AD5644R5] = {
-		.channels = ad5644r_channels,
-		.int_vref_mv = 2500,
-	},
-	[ID_AD5664R3] = {
-		.channels = ad5664r_channels,
-		.int_vref_mv = 1250,
-	},
-	[ID_AD5664R5] = {
-		.channels = ad5664r_channels,
-		.int_vref_mv = 2500,
-	},
-};
-
-static int ad5624r_spi_write(struct spi_device *spi,
-			     u8 cmd, u8 addr, u16 val, u8 len)
-{
-	u32 data;
-	u8 msg[3];
-
-	/*
-	 * The input shift register is 24 bits wide. The first two bits are
-	 * don't care bits. The next three are the command bits, C2 to C0,
-	 * followed by the 3-bit DAC address, A2 to A0, and then the
-	 * 16-, 14-, 12-bit data-word. The data-word comprises the 16-,
-	 * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits,
-	 * for the AD5664R, AD5644R, and AD5624R, respectively.
-	 */
-	data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len));
-	msg[0] = data >> 16;
-	msg[1] = data >> 8;
-	msg[2] = data;
-
-	return spi_write(spi, msg, 3);
-}
-
-static int ad5624r_read_raw(struct iio_dev *indio_dev,
-			   struct iio_chan_spec const *chan,
-			   int *val,
-			   int *val2,
-			   long m)
-{
-	struct ad5624r_state *st = iio_priv(indio_dev);
-	unsigned long scale_uv;
-
-	switch (m) {
-	case IIO_CHAN_INFO_SCALE:
-		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
-		*val =  scale_uv / 1000;
-		*val2 = (scale_uv % 1000) * 1000;
-		return IIO_VAL_INT_PLUS_MICRO;
-
-	}
-	return -EINVAL;
-}
-
-static int ad5624r_write_raw(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       int val,
-			       int val2,
-			       long mask)
-{
-	struct ad5624r_state *st = iio_priv(indio_dev);
-	int ret;
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		if (val >= (1 << chan->scan_type.realbits) || val < 0)
-			return -EINVAL;
-
-		return ad5624r_spi_write(st->us,
-				AD5624R_CMD_WRITE_INPUT_N_UPDATE_N,
-				chan->address, val,
-				chan->scan_type.shift);
-	default:
-		ret = -EINVAL;
-	}
-
-	return -EINVAL;
-}
-
-static ssize_t ad5624r_read_powerdown_mode(struct device *dev,
-				      struct device_attribute *attr, char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5624r_state *st = iio_priv(indio_dev);
-
-	char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
-
-	return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
-}
-
-static ssize_t ad5624r_write_powerdown_mode(struct device *dev,
-				       struct device_attribute *attr,
-				       const char *buf, size_t len)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5624r_state *st = iio_priv(indio_dev);
-	int ret;
-
-	if (sysfs_streq(buf, "1kohm_to_gnd"))
-		st->pwr_down_mode = AD5624R_LDAC_PWRDN_1K;
-	else if (sysfs_streq(buf, "100kohm_to_gnd"))
-		st->pwr_down_mode = AD5624R_LDAC_PWRDN_100K;
-	else if (sysfs_streq(buf, "three_state"))
-		st->pwr_down_mode = AD5624R_LDAC_PWRDN_3STATE;
-	else
-		ret = -EINVAL;
-
-	return ret ? ret : len;
-}
-
-static ssize_t ad5624r_read_dac_powerdown(struct device *dev,
-					   struct device_attribute *attr,
-					   char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5624r_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
-	return sprintf(buf, "%d\n",
-			!!(st->pwr_down_mask & (1 << this_attr->address)));
-}
-
-static ssize_t ad5624r_write_dac_powerdown(struct device *dev,
-					    struct device_attribute *attr,
-					    const char *buf, size_t len)
-{
-	long readin;
-	int ret;
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5624r_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
-	ret = strict_strtol(buf, 10, &readin);
-	if (ret)
-		return ret;
-
-	if (readin == 1)
-		st->pwr_down_mask |= (1 << this_attr->address);
-	else if (!readin)
-		st->pwr_down_mask &= ~(1 << this_attr->address);
-	else
-		ret = -EINVAL;
-
-	ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0,
-				(st->pwr_down_mode << 4) |
-				st->pwr_down_mask, 16);
-
-	return ret ? ret : len;
-}
-
-static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO |
-			S_IWUSR, ad5624r_read_powerdown_mode,
-			ad5624r_write_powerdown_mode, 0);
-
-static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
-			"1kohm_to_gnd 100kohm_to_gnd three_state");
-
-#define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr)		\
-	IIO_DEVICE_ATTR(out_voltage##_num##_powerdown,			\
-			S_IRUGO | S_IWUSR, _show, _store, _addr)
-
-static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5624r_read_dac_powerdown,
-				   ad5624r_write_dac_powerdown, 0);
-static IIO_DEV_ATTR_DAC_POWERDOWN(1, ad5624r_read_dac_powerdown,
-				   ad5624r_write_dac_powerdown, 1);
-static IIO_DEV_ATTR_DAC_POWERDOWN(2, ad5624r_read_dac_powerdown,
-				   ad5624r_write_dac_powerdown, 2);
-static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5624r_read_dac_powerdown,
-				   ad5624r_write_dac_powerdown, 3);
-
-static struct attribute *ad5624r_attributes[] = {
-	&iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage1_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage2_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage3_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr,
-	&iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad5624r_attribute_group = {
-	.attrs = ad5624r_attributes,
-};
-
-static const struct iio_info ad5624r_info = {
-	.write_raw = ad5624r_write_raw,
-	.read_raw = ad5624r_read_raw,
-	.attrs = &ad5624r_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad5624r_probe(struct spi_device *spi)
-{
-	struct ad5624r_state *st;
-	struct iio_dev *indio_dev;
-	int ret, voltage_uv = 0;
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	st = iio_priv(indio_dev);
-	st->reg = regulator_get(&spi->dev, "vcc");
-	if (!IS_ERR(st->reg)) {
-		ret = regulator_enable(st->reg);
-		if (ret)
-			goto error_put_reg;
-
-		voltage_uv = regulator_get_voltage(st->reg);
-	}
-
-	spi_set_drvdata(spi, indio_dev);
-	st->chip_info =
-		&ad5624r_chip_info_tbl[spi_get_device_id(spi)->driver_data];
-
-	if (voltage_uv)
-		st->vref_mv = voltage_uv / 1000;
-	else
-		st->vref_mv = st->chip_info->int_vref_mv;
-
-	st->us = spi;
-
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->info = &ad5624r_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = st->chip_info->channels;
-	indio_dev->num_channels = AD5624R_DAC_CHANNELS;
-
-	ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0,
-				!!voltage_uv, 16);
-	if (ret)
-		goto error_disable_reg;
-
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_disable_reg;
-
-	return 0;
-
-error_disable_reg:
-	if (!IS_ERR(st->reg))
-		regulator_disable(st->reg);
-error_put_reg:
-	if (!IS_ERR(st->reg))
-		regulator_put(st->reg);
-	iio_device_free(indio_dev);
-error_ret:
-
-	return ret;
-}
-
-static int __devexit ad5624r_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad5624r_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-	if (!IS_ERR(st->reg)) {
-		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad5624r_id[] = {
-	{"ad5624r3", ID_AD5624R3},
-	{"ad5644r3", ID_AD5644R3},
-	{"ad5664r3", ID_AD5664R3},
-	{"ad5624r5", ID_AD5624R5},
-	{"ad5644r5", ID_AD5644R5},
-	{"ad5664r5", ID_AD5664R5},
-	{}
-};
-MODULE_DEVICE_TABLE(spi, ad5624r_id);
-
-static struct spi_driver ad5624r_driver = {
-	.driver = {
-		   .name = "ad5624r",
-		   .owner = THIS_MODULE,
-		   },
-	.probe = ad5624r_probe,
-	.remove = __devexit_p(ad5624r_remove),
-	.id_table = ad5624r_id,
-};
-module_spi_driver(ad5624r_driver);
-
-MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices AD5624/44/64R DAC spi driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/ad5686.c b/drivers/staging/iio/dac/ad5686.c
deleted file mode 100644
index c1e903e..0000000
--- a/drivers/staging/iio/dac/ad5686.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * AD5686R, AD5685R, AD5684R Digital to analog converters  driver
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/regulator/consumer.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include "dac.h"
-
-#define AD5686_DAC_CHANNELS			4
-
-#define AD5686_ADDR(x)				((x) << 16)
-#define AD5686_CMD(x)				((x) << 20)
-
-#define AD5686_ADDR_DAC(chan)		(0x1 << (chan))
-#define AD5686_ADDR_ALL_DAC			0xF
-
-#define AD5686_CMD_NOOP				0x0
-#define AD5686_CMD_WRITE_INPUT_N		0x1
-#define AD5686_CMD_UPDATE_DAC_N			0x2
-#define AD5686_CMD_WRITE_INPUT_N_UPDATE_N	0x3
-#define AD5686_CMD_POWERDOWN_DAC		0x4
-#define AD5686_CMD_LDAC_MASK			0x5
-#define AD5686_CMD_RESET			0x6
-#define AD5686_CMD_INTERNAL_REFER_SETUP		0x7
-#define AD5686_CMD_DAISY_CHAIN_ENABLE		0x8
-#define AD5686_CMD_READBACK_ENABLE		0x9
-
-#define AD5686_LDAC_PWRDN_NONE			0x0
-#define AD5686_LDAC_PWRDN_1K			0x1
-#define AD5686_LDAC_PWRDN_100K			0x2
-#define AD5686_LDAC_PWRDN_3STATE		0x3
-
-/**
- * struct ad5686_chip_info - chip specific information
- * @int_vref_mv:	AD5620/40/60: the internal reference voltage
- * @channel:		channel specification
-*/
-
-struct ad5686_chip_info {
-	u16				int_vref_mv;
-	struct iio_chan_spec		channel[AD5686_DAC_CHANNELS];
-};
-
-/**
- * struct ad5446_state - driver instance specific data
- * @spi:		spi_device
- * @chip_info:		chip model specific constants, available modes etc
- * @reg:		supply regulator
- * @vref_mv:		actual reference voltage used
- * @pwr_down_mask:	power down mask
- * @pwr_down_mode:	current power down mode
- * @data:		spi transfer buffers
- */
-
-struct ad5686_state {
-	struct spi_device		*spi;
-	const struct ad5686_chip_info	*chip_info;
-	struct regulator		*reg;
-	unsigned short			vref_mv;
-	unsigned			pwr_down_mask;
-	unsigned			pwr_down_mode;
-	/*
-	 * DMA (thus cache coherency maintenance) requires the
-	 * transfer buffers to live in their own cache lines.
-	 */
-
-	union {
-		u32 d32;
-		u8 d8[4];
-	} data[3] ____cacheline_aligned;
-};
-
-/**
- * ad5686_supported_device_ids:
- */
-
-enum ad5686_supported_device_ids {
-	ID_AD5684,
-	ID_AD5685,
-	ID_AD5686,
-};
-#define AD5868_CHANNEL(chan, bits, shift) {			\
-		.type = IIO_VOLTAGE,				\
-		.indexed = 1,					\
-		.output = 1,					\
-		.channel = chan,				\
-		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
-		IIO_CHAN_INFO_SCALE_SHARED_BIT,			\
-		.address = AD5686_ADDR_DAC(chan),			\
-		.scan_type = IIO_ST('u', bits, 16, shift)	\
-}
-static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
-	[ID_AD5684] = {
-		.channel[0] = AD5868_CHANNEL(0, 12, 4),
-		.channel[1] = AD5868_CHANNEL(1, 12, 4),
-		.channel[2] = AD5868_CHANNEL(2, 12, 4),
-		.channel[3] = AD5868_CHANNEL(3, 12, 4),
-		.int_vref_mv = 2500,
-	},
-	[ID_AD5685] = {
-		.channel[0] = AD5868_CHANNEL(0, 14, 2),
-		.channel[1] = AD5868_CHANNEL(1, 14, 2),
-		.channel[2] = AD5868_CHANNEL(2, 14, 2),
-		.channel[3] = AD5868_CHANNEL(3, 14, 2),
-		.int_vref_mv = 2500,
-	},
-	[ID_AD5686] = {
-		.channel[0] = AD5868_CHANNEL(0, 16, 0),
-		.channel[1] = AD5868_CHANNEL(1, 16, 0),
-		.channel[2] = AD5868_CHANNEL(2, 16, 0),
-		.channel[3] = AD5868_CHANNEL(3, 16, 0),
-		.int_vref_mv = 2500,
-	},
-};
-
-static int ad5686_spi_write(struct ad5686_state *st,
-			     u8 cmd, u8 addr, u16 val, u8 shift)
-{
-	val <<= shift;
-
-	st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
-			      AD5686_ADDR(addr) |
-			      val);
-
-	return spi_write(st->spi, &st->data[0].d8[1], 3);
-}
-
-static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
-{
-	struct spi_transfer t[] = {
-		{
-			.tx_buf = &st->data[0].d8[1],
-			.len = 3,
-			.cs_change = 1,
-		}, {
-			.tx_buf = &st->data[1].d8[1],
-			.rx_buf = &st->data[2].d8[1],
-			.len = 3,
-		},
-	};
-	struct spi_message m;
-	int ret;
-
-	spi_message_init(&m);
-	spi_message_add_tail(&t[0], &m);
-	spi_message_add_tail(&t[1], &m);
-
-	st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) |
-			      AD5686_ADDR(addr));
-	st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
-
-	ret = spi_sync(st->spi, &m);
-	if (ret < 0)
-		return ret;
-
-	return be32_to_cpu(st->data[2].d32);
-}
-
-static ssize_t ad5686_read_powerdown_mode(struct device *dev,
-				      struct device_attribute *attr, char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5686_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
-	char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
-
-	return sprintf(buf, "%s\n", mode[(st->pwr_down_mode >>
-					 (this_attr->address * 2)) & 0x3]);
-}
-
-static ssize_t ad5686_write_powerdown_mode(struct device *dev,
-				       struct device_attribute *attr,
-				       const char *buf, size_t len)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5686_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	unsigned mode;
-
-	if (sysfs_streq(buf, "1kohm_to_gnd"))
-		mode = AD5686_LDAC_PWRDN_1K;
-	else if (sysfs_streq(buf, "100kohm_to_gnd"))
-		mode = AD5686_LDAC_PWRDN_100K;
-	else if (sysfs_streq(buf, "three_state"))
-		mode = AD5686_LDAC_PWRDN_3STATE;
-	else
-		return  -EINVAL;
-
-	st->pwr_down_mode &= ~(0x3 << (this_attr->address * 2));
-	st->pwr_down_mode |= (mode << (this_attr->address * 2));
-
-	return len;
-}
-
-static ssize_t ad5686_read_dac_powerdown(struct device *dev,
-					   struct device_attribute *attr,
-					   char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5686_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
-	return sprintf(buf, "%d\n", !!(st->pwr_down_mask &
-			(0x3 << (this_attr->address * 2))));
-}
-
-static ssize_t ad5686_write_dac_powerdown(struct device *dev,
-					    struct device_attribute *attr,
-					    const char *buf, size_t len)
-{
-	bool readin;
-	int ret;
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5686_state *st = iio_priv(indio_dev);
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
-	ret = strtobool(buf, &readin);
-	if (ret)
-		return ret;
-
-	if (readin == true)
-		st->pwr_down_mask |= (0x3 << (this_attr->address * 2));
-	else
-		st->pwr_down_mask &= ~(0x3 << (this_attr->address * 2));
-
-	ret = ad5686_spi_write(st, AD5686_CMD_POWERDOWN_DAC, 0,
-			       st->pwr_down_mask & st->pwr_down_mode, 0);
-
-	return ret ? ret : len;
-}
-
-static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
-			"1kohm_to_gnd 100kohm_to_gnd three_state");
-
-#define IIO_DEV_ATTR_DAC_POWERDOWN_MODE(_num)				\
-	IIO_DEVICE_ATTR(out_voltage##_num##_powerdown_mode,		\
-			S_IRUGO | S_IWUSR,				\
-			ad5686_read_powerdown_mode,			\
-			ad5686_write_powerdown_mode, _num)
-
-static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(0);
-static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(1);
-static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(2);
-static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(3);
-
-#define IIO_DEV_ATTR_DAC_POWERDOWN(_num)				\
-	IIO_DEVICE_ATTR(out_voltage##_num##_powerdown,			\
-			S_IRUGO | S_IWUSR,				\
-			ad5686_read_dac_powerdown,			\
-			ad5686_write_dac_powerdown, _num)
-
-static IIO_DEV_ATTR_DAC_POWERDOWN(0);
-static IIO_DEV_ATTR_DAC_POWERDOWN(1);
-static IIO_DEV_ATTR_DAC_POWERDOWN(2);
-static IIO_DEV_ATTR_DAC_POWERDOWN(3);
-
-static struct attribute *ad5686_attributes[] = {
-	&iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage1_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage2_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage3_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage0_powerdown_mode.dev_attr.attr,
-	&iio_dev_attr_out_voltage1_powerdown_mode.dev_attr.attr,
-	&iio_dev_attr_out_voltage2_powerdown_mode.dev_attr.attr,
-	&iio_dev_attr_out_voltage3_powerdown_mode.dev_attr.attr,
-	&iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad5686_attribute_group = {
-	.attrs = ad5686_attributes,
-};
-
-static int ad5686_read_raw(struct iio_dev *indio_dev,
-			   struct iio_chan_spec const *chan,
-			   int *val,
-			   int *val2,
-			   long m)
-{
-	struct ad5686_state *st = iio_priv(indio_dev);
-	unsigned long scale_uv;
-	int ret;
-
-	switch (m) {
-	case IIO_CHAN_INFO_RAW:
-		mutex_lock(&indio_dev->mlock);
-		ret = ad5686_spi_read(st, chan->address);
-		mutex_unlock(&indio_dev->mlock);
-		if (ret < 0)
-			return ret;
-		*val = ret;
-		return IIO_VAL_INT;
-		break;
-	case IIO_CHAN_INFO_SCALE:
-		scale_uv = (st->vref_mv * 100000)
-			>> (chan->scan_type.realbits);
-		*val =  scale_uv / 100000;
-		*val2 = (scale_uv % 100000) * 10;
-		return IIO_VAL_INT_PLUS_MICRO;
-
-	}
-	return -EINVAL;
-}
-
-static int ad5686_write_raw(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       int val,
-			       int val2,
-			       long mask)
-{
-	struct ad5686_state *st = iio_priv(indio_dev);
-	int ret;
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		if (val > (1 << chan->scan_type.realbits) || val < 0)
-			return -EINVAL;
-
-		mutex_lock(&indio_dev->mlock);
-		ret = ad5686_spi_write(st,
-				 AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
-				 chan->address,
-				 val,
-				 chan->scan_type.shift);
-		mutex_unlock(&indio_dev->mlock);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static const struct iio_info ad5686_info = {
-	.read_raw = ad5686_read_raw,
-	.write_raw = ad5686_write_raw,
-	.attrs = &ad5686_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad5686_probe(struct spi_device *spi)
-{
-	struct ad5686_state *st;
-	struct iio_dev *indio_dev;
-	int ret, regdone = 0, voltage_uv = 0;
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL)
-		return  -ENOMEM;
-
-	st = iio_priv(indio_dev);
-	spi_set_drvdata(spi, indio_dev);
-
-	st->reg = regulator_get(&spi->dev, "vcc");
-	if (!IS_ERR(st->reg)) {
-		ret = regulator_enable(st->reg);
-		if (ret)
-			goto error_put_reg;
-
-		voltage_uv = regulator_get_voltage(st->reg);
-	}
-
-	st->chip_info =
-		&ad5686_chip_info_tbl[spi_get_device_id(spi)->driver_data];
-
-	if (voltage_uv)
-		st->vref_mv = voltage_uv / 1000;
-	else
-		st->vref_mv = st->chip_info->int_vref_mv;
-
-	st->spi = spi;
-
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->info = &ad5686_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = st->chip_info->channel;
-	indio_dev->num_channels = AD5686_DAC_CHANNELS;
-
-	regdone = 1;
-	ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0,
-				!!voltage_uv, 0);
-	if (ret)
-		goto error_disable_reg;
-
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_disable_reg;
-
-	return 0;
-
-error_disable_reg:
-	if (!IS_ERR(st->reg))
-		regulator_disable(st->reg);
-error_put_reg:
-	if (!IS_ERR(st->reg))
-		regulator_put(st->reg);
-
-	iio_device_free(indio_dev);
-
-	return ret;
-}
-
-static int __devexit ad5686_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad5686_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-	if (!IS_ERR(st->reg)) {
-		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad5686_id[] = {
-	{"ad5684", ID_AD5684},
-	{"ad5685", ID_AD5685},
-	{"ad5686", ID_AD5686},
-	{}
-};
-MODULE_DEVICE_TABLE(spi, ad5686_id);
-
-static struct spi_driver ad5686_driver = {
-	.driver = {
-		   .name = "ad5686",
-		   .owner = THIS_MODULE,
-		   },
-	.probe = ad5686_probe,
-	.remove = __devexit_p(ad5686_remove),
-	.id_table = ad5686_id,
-};
-module_spi_driver(ad5686_driver);
-
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/ad5764.c b/drivers/staging/iio/dac/ad5764.c
deleted file mode 100644
index 03dbd93..0000000
--- a/drivers/staging/iio/dac/ad5764.c
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * Analog devices AD5764, AD5764R, AD5744, AD5744R quad-channel
- * Digital to Analog Converters driver
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/regulator/consumer.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include "dac.h"
-
-#define AD5764_REG_SF_NOP			0x0
-#define AD5764_REG_SF_CONFIG			0x1
-#define AD5764_REG_SF_CLEAR			0x4
-#define AD5764_REG_SF_LOAD			0x5
-#define AD5764_REG_DATA(x)			((2 << 3) | (x))
-#define AD5764_REG_COARSE_GAIN(x)		((3 << 3) | (x))
-#define AD5764_REG_FINE_GAIN(x)			((4 << 3) | (x))
-#define AD5764_REG_OFFSET(x)			((5 << 3) | (x))
-
-#define AD5764_NUM_CHANNELS 4
-
-/**
- * struct ad5764_chip_info - chip specific information
- * @int_vref:	Value of the internal reference voltage in uV - 0 if external
- *		reference voltage is used
- * @channel	channel specification
-*/
-
-struct ad5764_chip_info {
-	unsigned long int_vref;
-	const struct iio_chan_spec *channels;
-};
-
-/**
- * struct ad5764_state - driver instance specific data
- * @spi:		spi_device
- * @chip_info:		chip info
- * @vref_reg:		vref supply regulators
- * @data:		spi transfer buffers
- */
-
-struct ad5764_state {
-	struct spi_device		*spi;
-	const struct ad5764_chip_info	*chip_info;
-	struct regulator_bulk_data	vref_reg[2];
-
-	/*
-	 * DMA (thus cache coherency maintenance) requires the
-	 * transfer buffers to live in their own cache lines.
-	 */
-	union {
-		__be32 d32;
-		u8 d8[4];
-	} data[2] ____cacheline_aligned;
-};
-
-enum ad5764_type {
-	ID_AD5744,
-	ID_AD5744R,
-	ID_AD5764,
-	ID_AD5764R,
-};
-
-#define AD5764_CHANNEL(_chan, _bits) {				\
-	.type = IIO_VOLTAGE,					\
-	.indexed = 1,						\
-	.output = 1,						\
-	.channel = (_chan),					\
-	.address = (_chan),					\
-	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
-		IIO_CHAN_INFO_OFFSET_SHARED_BIT |		\
-		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |		\
-		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |		\
-		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,		\
-	.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits))	\
-}
-
-#define DECLARE_AD5764_CHANNELS(_name, _bits) \
-const struct iio_chan_spec _name##_channels[] = { \
-	AD5764_CHANNEL(0, (_bits)), \
-	AD5764_CHANNEL(1, (_bits)), \
-	AD5764_CHANNEL(2, (_bits)), \
-	AD5764_CHANNEL(3, (_bits)), \
-};
-
-static DECLARE_AD5764_CHANNELS(ad5764, 16);
-static DECLARE_AD5764_CHANNELS(ad5744, 14);
-
-static const struct ad5764_chip_info ad5764_chip_infos[] = {
-	[ID_AD5744] = {
-		.int_vref = 0,
-		.channels = ad5744_channels,
-	},
-	[ID_AD5744R] = {
-		.int_vref = 5000000,
-		.channels = ad5744_channels,
-	},
-	[ID_AD5764] = {
-		.int_vref = 0,
-		.channels = ad5764_channels,
-	},
-	[ID_AD5764R] = {
-		.int_vref = 5000000,
-		.channels = ad5764_channels,
-	},
-};
-
-static int ad5764_write(struct iio_dev *indio_dev, unsigned int reg,
-	unsigned int val)
-{
-	struct ad5764_state *st = iio_priv(indio_dev);
-	int ret;
-
-	mutex_lock(&indio_dev->mlock);
-	st->data[0].d32 = cpu_to_be32((reg << 16) | val);
-
-	ret = spi_write(st->spi, &st->data[0].d8[1], 3);
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret;
-}
-
-static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg,
-	unsigned int *val)
-{
-	struct ad5764_state *st = iio_priv(indio_dev);
-	struct spi_message m;
-	int ret;
-	struct spi_transfer t[] = {
-		{
-			.tx_buf = &st->data[0].d8[1],
-			.len = 3,
-			.cs_change = 1,
-		}, {
-			.rx_buf = &st->data[1].d8[1],
-			.len = 3,
-		},
-	};
-
-	spi_message_init(&m);
-	spi_message_add_tail(&t[0], &m);
-	spi_message_add_tail(&t[1], &m);
-
-	mutex_lock(&indio_dev->mlock);
-
-	st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
-
-	ret = spi_sync(st->spi, &m);
-	if (ret >= 0)
-		*val = be32_to_cpu(st->data[1].d32) & 0xffff;
-
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret;
-}
-
-static int ad5764_chan_info_to_reg(struct iio_chan_spec const *chan, long info)
-{
-	switch (info) {
-	case 0:
-		return AD5764_REG_DATA(chan->address);
-	case IIO_CHAN_INFO_CALIBBIAS:
-		return AD5764_REG_OFFSET(chan->address);
-	case IIO_CHAN_INFO_CALIBSCALE:
-		return AD5764_REG_FINE_GAIN(chan->address);
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int ad5764_write_raw(struct iio_dev *indio_dev,
-	struct iio_chan_spec const *chan, int val, int val2, long info)
-{
-	const int max_val = (1 << chan->scan_type.realbits);
-	unsigned int reg;
-
-	switch (info) {
-	case IIO_CHAN_INFO_RAW:
-		if (val >= max_val || val < 0)
-			return -EINVAL;
-		val <<= chan->scan_type.shift;
-		break;
-	case IIO_CHAN_INFO_CALIBBIAS:
-		if (val >= 128 || val < -128)
-			return -EINVAL;
-		break;
-	case IIO_CHAN_INFO_CALIBSCALE:
-		if (val >= 32 || val < -32)
-			return -EINVAL;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	reg = ad5764_chan_info_to_reg(chan, info);
-	return ad5764_write(indio_dev, reg, (u16)val);
-}
-
-static int ad5764_get_channel_vref(struct ad5764_state *st,
-	unsigned int channel)
-{
-	if (st->chip_info->int_vref)
-		return st->chip_info->int_vref;
-	else
-		return regulator_get_voltage(st->vref_reg[channel / 2].consumer);
-}
-
-static int ad5764_read_raw(struct iio_dev *indio_dev,
-	struct iio_chan_spec const *chan, int *val, int *val2, long info)
-{
-	struct ad5764_state *st = iio_priv(indio_dev);
-	unsigned long scale_uv;
-	unsigned int reg;
-	int vref;
-	int ret;
-
-	switch (info) {
-	case IIO_CHAN_INFO_RAW:
-		reg = AD5764_REG_DATA(chan->address);
-		ret = ad5764_read(indio_dev, reg, val);
-		if (ret < 0)
-			return ret;
-		*val >>= chan->scan_type.shift;
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_CALIBBIAS:
-		reg = AD5764_REG_OFFSET(chan->address);
-		ret = ad5764_read(indio_dev, reg, val);
-		if (ret < 0)
-			return ret;
-		*val = sign_extend32(*val, 7);
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_CALIBSCALE:
-		reg = AD5764_REG_FINE_GAIN(chan->address);
-		ret = ad5764_read(indio_dev, reg, val);
-		if (ret < 0)
-			return ret;
-		*val = sign_extend32(*val, 5);
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_SCALE:
-		/* vout = 4 * vref + ((dac_code / 65535) - 0.5) */
-		vref = ad5764_get_channel_vref(st, chan->channel);
-		if (vref < 0)
-			return vref;
-
-		scale_uv = (vref * 4 * 100) >> chan->scan_type.realbits;
-		*val = scale_uv / 100000;
-		*val2 = (scale_uv % 100000) * 10;
-		return IIO_VAL_INT_PLUS_MICRO;
-	case IIO_CHAN_INFO_OFFSET:
-		*val = -(1 << chan->scan_type.realbits) / 2;
-		return IIO_VAL_INT;
-	}
-
-	return -EINVAL;
-}
-
-static const struct iio_info ad5764_info = {
-	.read_raw = ad5764_read_raw,
-	.write_raw = ad5764_write_raw,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad5764_probe(struct spi_device *spi)
-{
-	enum ad5764_type type = spi_get_device_id(spi)->driver_data;
-	struct iio_dev *indio_dev;
-	struct ad5764_state *st;
-	int ret;
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		dev_err(&spi->dev, "Failed to allocate iio device\n");
-		return -ENOMEM;
-	}
-
-	st = iio_priv(indio_dev);
-	spi_set_drvdata(spi, indio_dev);
-
-	st->spi = spi;
-	st->chip_info = &ad5764_chip_infos[type];
-
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->info = &ad5764_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->num_channels = AD5764_NUM_CHANNELS;
-	indio_dev->channels = st->chip_info->channels;
-
-	if (st->chip_info->int_vref == 0) {
-		st->vref_reg[0].supply = "vrefAB";
-		st->vref_reg[1].supply = "vrefCD";
-
-		ret = regulator_bulk_get(&st->spi->dev,
-			ARRAY_SIZE(st->vref_reg), st->vref_reg);
-		if (ret) {
-			dev_err(&spi->dev, "Failed to request vref regulators: %d\n",
-				ret);
-			goto error_free;
-		}
-
-		ret = regulator_bulk_enable(ARRAY_SIZE(st->vref_reg),
-			st->vref_reg);
-		if (ret) {
-			dev_err(&spi->dev, "Failed to enable vref regulators: %d\n",
-				ret);
-			goto error_free_reg;
-		}
-	}
-
-	ret = iio_device_register(indio_dev);
-	if (ret) {
-		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
-		goto error_disable_reg;
-	}
-
-	return 0;
-
-error_disable_reg:
-	if (st->chip_info->int_vref == 0)
-		regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
-error_free_reg:
-	if (st->chip_info->int_vref == 0)
-		regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
-error_free:
-	iio_device_free(indio_dev);
-
-	return ret;
-}
-
-static int __devexit ad5764_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad5764_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-
-	if (st->chip_info->int_vref == 0) {
-		regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
-		regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
-	}
-
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad5764_ids[] = {
-	{ "ad5744", ID_AD5744 },
-	{ "ad5744r", ID_AD5744R },
-	{ "ad5764", ID_AD5764 },
-	{ "ad5764r", ID_AD5764R },
-	{ }
-};
-MODULE_DEVICE_TABLE(spi, ad5764_ids);
-
-static struct spi_driver ad5764_driver = {
-	.driver = {
-		.name = "ad5764",
-		.owner = THIS_MODULE,
-	},
-	.probe = ad5764_probe,
-	.remove = __devexit_p(ad5764_remove),
-	.id_table = ad5764_ids,
-};
-module_spi_driver(ad5764_driver);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("Analog Devices AD5744/AD5744R/AD5764/AD5764R DAC");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/ad5791.c b/drivers/staging/iio/dac/ad5791.c
deleted file mode 100644
index 13d8b5b..0000000
--- a/drivers/staging/iio/dac/ad5791.c
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * AD5760, AD5780, AD5781, AD5790, AD5791 Voltage Output Digital to Analog
- * Converter
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/regulator/consumer.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include "dac.h"
-#include "ad5791.h"
-
-static int ad5791_spi_write(struct spi_device *spi, u8 addr, u32 val)
-{
-	union {
-		u32 d32;
-		u8 d8[4];
-	} data;
-
-	data.d32 = cpu_to_be32(AD5791_CMD_WRITE |
-			      AD5791_ADDR(addr) |
-			      (val & AD5791_DAC_MASK));
-
-	return spi_write(spi, &data.d8[1], 3);
-}
-
-static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val)
-{
-	union {
-		u32 d32;
-		u8 d8[4];
-	} data[3];
-	int ret;
-	struct spi_message msg;
-	struct spi_transfer xfers[] = {
-		{
-			.tx_buf = &data[0].d8[1],
-			.bits_per_word = 8,
-			.len = 3,
-			.cs_change = 1,
-		}, {
-			.tx_buf = &data[1].d8[1],
-			.rx_buf = &data[2].d8[1],
-			.bits_per_word = 8,
-			.len = 3,
-		},
-	};
-
-	data[0].d32 = cpu_to_be32(AD5791_CMD_READ |
-			      AD5791_ADDR(addr));
-	data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP));
-
-	spi_message_init(&msg);
-	spi_message_add_tail(&xfers[0], &msg);
-	spi_message_add_tail(&xfers[1], &msg);
-	ret = spi_sync(spi, &msg);
-
-	*val = be32_to_cpu(data[2].d32);
-
-	return ret;
-}
-
-#define AD5791_CHAN(bits, shift) {			\
-	.type = IIO_VOLTAGE,				\
-	.output = 1,					\
-	.indexed = 1,					\
-	.address = AD5791_ADDR_DAC0,			\
-	.channel = 0,					\
-	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
-		IIO_CHAN_INFO_SCALE_SHARED_BIT |	\
-		IIO_CHAN_INFO_OFFSET_SHARED_BIT,	\
-	.scan_type = IIO_ST('u', bits, 24, shift)	\
-}
-
-static const struct iio_chan_spec ad5791_channels[] = {
-	[ID_AD5760] = AD5791_CHAN(16, 4),
-	[ID_AD5780] = AD5791_CHAN(18, 2),
-	[ID_AD5781] = AD5791_CHAN(18, 2),
-	[ID_AD5791] = AD5791_CHAN(20, 0)
-};
-
-static ssize_t ad5791_read_powerdown_mode(struct device *dev,
-				      struct device_attribute *attr, char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5791_state *st = iio_priv(indio_dev);
-
-	const char mode[][14] = {"6kohm_to_gnd", "three_state"};
-
-	return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
-}
-
-static ssize_t ad5791_write_powerdown_mode(struct device *dev,
-				       struct device_attribute *attr,
-				       const char *buf, size_t len)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5791_state *st = iio_priv(indio_dev);
-	int ret;
-
-	if (sysfs_streq(buf, "6kohm_to_gnd"))
-		st->pwr_down_mode = AD5791_DAC_PWRDN_6K;
-	else if (sysfs_streq(buf, "three_state"))
-		st->pwr_down_mode = AD5791_DAC_PWRDN_3STATE;
-	else
-		ret = -EINVAL;
-
-	return ret ? ret : len;
-}
-
-static ssize_t ad5791_read_dac_powerdown(struct device *dev,
-					   struct device_attribute *attr,
-					   char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5791_state *st = iio_priv(indio_dev);
-
-	return sprintf(buf, "%d\n", st->pwr_down);
-}
-
-static ssize_t ad5791_write_dac_powerdown(struct device *dev,
-					    struct device_attribute *attr,
-					    const char *buf, size_t len)
-{
-	long readin;
-	int ret;
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ad5791_state *st = iio_priv(indio_dev);
-
-	ret = strict_strtol(buf, 10, &readin);
-	if (ret)
-		return ret;
-
-	if (readin == 0) {
-		st->pwr_down = false;
-		st->ctrl &= ~(AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
-	} else if (readin == 1) {
-		st->pwr_down = true;
-		if (st->pwr_down_mode == AD5791_DAC_PWRDN_6K)
-			st->ctrl |= AD5791_CTRL_OPGND;
-		else if (st->pwr_down_mode == AD5791_DAC_PWRDN_3STATE)
-			st->ctrl |= AD5791_CTRL_DACTRI;
-	} else
-		ret = -EINVAL;
-
-	ret = ad5791_spi_write(st->spi, AD5791_ADDR_CTRL, st->ctrl);
-
-	return ret ? ret : len;
-}
-
-static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO |
-			S_IWUSR, ad5791_read_powerdown_mode,
-			ad5791_write_powerdown_mode, 0);
-
-static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
-			"6kohm_to_gnd three_state");
-
-#define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr)		\
-	IIO_DEVICE_ATTR(out_voltage##_num##_powerdown,			\
-			S_IRUGO | S_IWUSR, _show, _store, _addr)
-
-static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5791_read_dac_powerdown,
-				   ad5791_write_dac_powerdown, 0);
-
-static struct attribute *ad5791_attributes[] = {
-	&iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
-	&iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr,
-	&iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group ad5791_attribute_group = {
-	.attrs = ad5791_attributes,
-};
-
-static int ad5791_get_lin_comp(unsigned int span)
-{
-	if (span <= 10000)
-		return AD5791_LINCOMP_0_10;
-	else if (span <= 12000)
-		return AD5791_LINCOMP_10_12;
-	else if (span <= 16000)
-		return AD5791_LINCOMP_12_16;
-	else if (span <= 19000)
-		return AD5791_LINCOMP_16_19;
-	else
-		return AD5791_LINCOMP_19_20;
-}
-
-static int ad5780_get_lin_comp(unsigned int span)
-{
-	if (span <= 10000)
-		return AD5780_LINCOMP_0_10;
-	else
-		return AD5780_LINCOMP_10_20;
-}
-static const struct ad5791_chip_info ad5791_chip_info_tbl[] = {
-	[ID_AD5760] = {
-		.get_lin_comp = ad5780_get_lin_comp,
-	},
-	[ID_AD5780] = {
-		.get_lin_comp = ad5780_get_lin_comp,
-	},
-	[ID_AD5781] = {
-		.get_lin_comp = ad5791_get_lin_comp,
-	},
-	[ID_AD5791] = {
-		.get_lin_comp = ad5791_get_lin_comp,
-	},
-};
-
-static int ad5791_read_raw(struct iio_dev *indio_dev,
-			   struct iio_chan_spec const *chan,
-			   int *val,
-			   int *val2,
-			   long m)
-{
-	struct ad5791_state *st = iio_priv(indio_dev);
-	u64 val64;
-	int ret;
-
-	switch (m) {
-	case IIO_CHAN_INFO_RAW:
-		ret = ad5791_spi_read(st->spi, chan->address, val);
-		if (ret)
-			return ret;
-		*val &= AD5791_DAC_MASK;
-		*val >>= chan->scan_type.shift;
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_SCALE:
-		*val = 0;
-		*val2 = (((u64)st->vref_mv) * 1000000ULL) >> chan->scan_type.realbits;
-		return IIO_VAL_INT_PLUS_MICRO;
-	case IIO_CHAN_INFO_OFFSET:
-		val64 = (((u64)st->vref_neg_mv) << chan->scan_type.realbits);
-		do_div(val64, st->vref_mv);
-		*val = -val64;
-		return IIO_VAL_INT;
-	default:
-		return -EINVAL;
-	}
-
-};
-
-
-static int ad5791_write_raw(struct iio_dev *indio_dev,
-			    struct iio_chan_spec const *chan,
-			    int val,
-			    int val2,
-			    long mask)
-{
-	struct ad5791_state *st = iio_priv(indio_dev);
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		val &= AD5791_RES_MASK(chan->scan_type.realbits);
-		val <<= chan->scan_type.shift;
-
-		return ad5791_spi_write(st->spi, chan->address, val);
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static const struct iio_info ad5791_info = {
-	.read_raw = &ad5791_read_raw,
-	.write_raw = &ad5791_write_raw,
-	.attrs = &ad5791_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int __devinit ad5791_probe(struct spi_device *spi)
-{
-	struct ad5791_platform_data *pdata = spi->dev.platform_data;
-	struct iio_dev *indio_dev;
-	struct ad5791_state *st;
-	int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
-
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	st = iio_priv(indio_dev);
-	st->reg_vdd = regulator_get(&spi->dev, "vdd");
-	if (!IS_ERR(st->reg_vdd)) {
-		ret = regulator_enable(st->reg_vdd);
-		if (ret)
-			goto error_put_reg_pos;
-
-		pos_voltage_uv = regulator_get_voltage(st->reg_vdd);
-	}
-
-	st->reg_vss = regulator_get(&spi->dev, "vss");
-	if (!IS_ERR(st->reg_vss)) {
-		ret = regulator_enable(st->reg_vss);
-		if (ret)
-			goto error_put_reg_neg;
-
-		neg_voltage_uv = regulator_get_voltage(st->reg_vss);
-	}
-
-	st->pwr_down = true;
-	st->spi = spi;
-
-	if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) {
-		st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000;
-		st->vref_neg_mv = neg_voltage_uv / 1000;
-	} else if (pdata) {
-		st->vref_mv = pdata->vref_pos_mv + pdata->vref_neg_mv;
-		st->vref_neg_mv = pdata->vref_neg_mv;
-	} else {
-		dev_warn(&spi->dev, "reference voltage unspecified\n");
-	}
-
-	ret = ad5791_spi_write(spi, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET);
-	if (ret)
-		goto error_disable_reg_neg;
-
-	st->chip_info =	&ad5791_chip_info_tbl[spi_get_device_id(spi)
-					      ->driver_data];
-
-
-	st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv))
-		  | ((pdata && pdata->use_rbuf_gain2) ? 0 : AD5791_CTRL_RBUF) |
-		  AD5791_CTRL_BIN2SC;
-
-	ret = ad5791_spi_write(spi, AD5791_ADDR_CTRL, st->ctrl |
-		AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
-	if (ret)
-		goto error_disable_reg_neg;
-
-	spi_set_drvdata(spi, indio_dev);
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->info = &ad5791_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels
-		= &ad5791_channels[spi_get_device_id(spi)->driver_data];
-	indio_dev->num_channels = 1;
-	indio_dev->name = spi_get_device_id(st->spi)->name;
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_disable_reg_neg;
-
-	return 0;
-
-error_disable_reg_neg:
-	if (!IS_ERR(st->reg_vss))
-		regulator_disable(st->reg_vss);
-error_put_reg_neg:
-	if (!IS_ERR(st->reg_vss))
-		regulator_put(st->reg_vss);
-
-	if (!IS_ERR(st->reg_vdd))
-		regulator_disable(st->reg_vdd);
-error_put_reg_pos:
-	if (!IS_ERR(st->reg_vdd))
-		regulator_put(st->reg_vdd);
-	iio_device_free(indio_dev);
-error_ret:
-
-	return ret;
-}
-
-static int __devexit ad5791_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct ad5791_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-	if (!IS_ERR(st->reg_vdd)) {
-		regulator_disable(st->reg_vdd);
-		regulator_put(st->reg_vdd);
-	}
-
-	if (!IS_ERR(st->reg_vss)) {
-		regulator_disable(st->reg_vss);
-		regulator_put(st->reg_vss);
-	}
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-static const struct spi_device_id ad5791_id[] = {
-	{"ad5760", ID_AD5760},
-	{"ad5780", ID_AD5780},
-	{"ad5781", ID_AD5781},
-	{"ad5790", ID_AD5791},
-	{"ad5791", ID_AD5791},
-	{}
-};
-MODULE_DEVICE_TABLE(spi, ad5791_id);
-
-static struct spi_driver ad5791_driver = {
-	.driver = {
-		   .name = "ad5791",
-		   .owner = THIS_MODULE,
-		   },
-	.probe = ad5791_probe,
-	.remove = __devexit_p(ad5791_remove),
-	.id_table = ad5791_id,
-};
-module_spi_driver(ad5791_driver);
-
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/ad5791.h b/drivers/staging/iio/dac/ad5791.h
deleted file mode 100644
index fd7edbd..0000000
--- a/drivers/staging/iio/dac/ad5791.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * AD5791 SPI DAC driver
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#ifndef SPI_AD5791_H_
-#define SPI_AD5791_H_
-
-#define AD5791_RES_MASK(x)		((1 << (x)) - 1)
-#define AD5791_DAC_MASK			AD5791_RES_MASK(20)
-#define AD5791_DAC_MSB			(1 << 19)
-
-#define AD5791_CMD_READ			(1 << 23)
-#define AD5791_CMD_WRITE		(0 << 23)
-#define AD5791_ADDR(addr)		((addr) << 20)
-
-/* Registers */
-#define AD5791_ADDR_NOOP		0
-#define AD5791_ADDR_DAC0		1
-#define AD5791_ADDR_CTRL		2
-#define AD5791_ADDR_CLRCODE		3
-#define AD5791_ADDR_SW_CTRL		4
-
-/* Control Register */
-#define AD5791_CTRL_RBUF		(1 << 1)
-#define AD5791_CTRL_OPGND		(1 << 2)
-#define AD5791_CTRL_DACTRI		(1 << 3)
-#define AD5791_CTRL_BIN2SC		(1 << 4)
-#define AD5791_CTRL_SDODIS		(1 << 5)
-#define AD5761_CTRL_LINCOMP(x)		((x) << 6)
-
-#define AD5791_LINCOMP_0_10		0
-#define AD5791_LINCOMP_10_12		1
-#define AD5791_LINCOMP_12_16		2
-#define AD5791_LINCOMP_16_19		3
-#define AD5791_LINCOMP_19_20		12
-
-#define AD5780_LINCOMP_0_10		0
-#define AD5780_LINCOMP_10_20		12
-
-/* Software Control Register */
-#define AD5791_SWCTRL_LDAC		(1 << 0)
-#define AD5791_SWCTRL_CLR		(1 << 1)
-#define AD5791_SWCTRL_RESET		(1 << 2)
-
-#define AD5791_DAC_PWRDN_6K		0
-#define AD5791_DAC_PWRDN_3STATE		1
-
-/*
- * TODO: struct ad5791_platform_data needs to go into include/linux/iio
- */
-
-/**
- * struct ad5791_platform_data - platform specific information
- * @vref_pos_mv:	Vdd Positive Analog Supply Volatge (mV)
- * @vref_neg_mv:	Vdd Negative Analog Supply Volatge (mV)
- * @use_rbuf_gain2:	ext. amplifier connected in gain of two configuration
- */
-
-struct ad5791_platform_data {
-	u16				vref_pos_mv;
-	u16				vref_neg_mv;
-	bool				use_rbuf_gain2;
-};
-
-/**
- * struct ad5791_chip_info - chip specific information
- * @get_lin_comp:	function pointer to the device specific function
- */
-
-struct ad5791_chip_info {
-	int (*get_lin_comp)	(unsigned int span);
-};
-
-/**
- * struct ad5791_state - driver instance specific data
- * @us:			spi_device
- * @reg_vdd:		positive supply regulator
- * @reg_vss:		negative supply regulator
- * @chip_info:		chip model specific constants
- * @vref_mv:		actual reference voltage used
- * @vref_neg_mv:	voltage of the negative supply
- * @pwr_down_mode	current power down mode
- */
-
-struct ad5791_state {
-	struct spi_device		*spi;
-	struct regulator		*reg_vdd;
-	struct regulator		*reg_vss;
-	const struct ad5791_chip_info	*chip_info;
-	unsigned short			vref_mv;
-	unsigned int			vref_neg_mv;
-	unsigned			ctrl;
-	unsigned			pwr_down_mode;
-	bool				pwr_down;
-};
-
-/**
- * ad5791_supported_device_ids:
- */
-
-enum ad5791_supported_device_ids {
-	ID_AD5760,
-	ID_AD5780,
-	ID_AD5781,
-	ID_AD5791,
-};
-
-#endif /* SPI_AD5791_H_ */
diff --git a/drivers/staging/iio/dac/dac.h b/drivers/staging/iio/dac/dac.h
deleted file mode 100644
index 0754d71..0000000
--- a/drivers/staging/iio/dac/dac.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
- * dac.h - sysfs attributes associated with DACs
- */
-
-#define IIO_DEV_ATTR_OUT_RAW(_num, _store, _addr)				\
-	IIO_DEVICE_ATTR(out_voltage##_num##_raw, S_IWUSR, NULL, _store, _addr)
diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c
deleted file mode 100644
index 5287cad..0000000
--- a/drivers/staging/iio/dac/max517.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- *  max517.c - Support for Maxim MAX517, MAX518 and MAX519
- *
- *  Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/err.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include "dac.h"
-
-#include "max517.h"
-
-#define MAX517_DRV_NAME	"max517"
-
-/* Commands */
-#define COMMAND_CHANNEL0	0x00
-#define COMMAND_CHANNEL1	0x01 /* for MAX518 and MAX519 */
-#define COMMAND_PD		0x08 /* Power Down */
-
-enum max517_device_ids {
-	ID_MAX517,
-	ID_MAX518,
-	ID_MAX519,
-};
-
-struct max517_data {
-	struct iio_dev		*indio_dev;
-	struct i2c_client	*client;
-	unsigned short		vref_mv[2];
-};
-
-/*
- * channel: bit 0: channel 1
- *          bit 1: channel 2
- * (this way, it's possible to set both channels at once)
- */
-static ssize_t max517_set_value(struct device *dev,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count, int channel)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct max517_data *data = iio_priv(indio_dev);
-	struct i2c_client *client = data->client;
-	u8 outbuf[4]; /* 1x or 2x command + value */
-	int outbuf_size = 0;
-	int res;
-	long val;
-
-	res = strict_strtol(buf, 10, &val);
-
-	if (res)
-		return res;
-
-	if (val < 0 || val > 255)
-		return -EINVAL;
-
-	if (channel & 1) {
-		outbuf[outbuf_size++] = COMMAND_CHANNEL0;
-		outbuf[outbuf_size++] = val;
-	}
-	if (channel & 2) {
-		outbuf[outbuf_size++] = COMMAND_CHANNEL1;
-		outbuf[outbuf_size++] = val;
-	}
-
-	/*
-	 * At this point, there are always 1 or 2 two-byte commands in
-	 * outbuf. With 2 commands, the device can set two outputs
-	 * simultaneously, latching the values upon the end of the I2C
-	 * transfer.
-	 */
-
-	res = i2c_master_send(client, outbuf, outbuf_size);
-	if (res < 0)
-		return res;
-
-	return count;
-}
-
-static ssize_t max517_set_value_1(struct device *dev,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	return max517_set_value(dev, attr, buf, count, 1);
-}
-static IIO_DEV_ATTR_OUT_RAW(1, max517_set_value_1, 0);
-
-static ssize_t max517_set_value_2(struct device *dev,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	return max517_set_value(dev, attr, buf, count, 2);
-}
-static IIO_DEV_ATTR_OUT_RAW(2, max517_set_value_2, 1);
-
-static ssize_t max517_set_value_both(struct device *dev,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	return max517_set_value(dev, attr, buf, count, 3);
-}
-static IIO_DEVICE_ATTR_NAMED(out_voltage1and2_raw,
-			     out_voltage1&2_raw, S_IWUSR, NULL,
-			     max517_set_value_both, -1);
-
-static ssize_t max517_show_scale(struct device *dev,
-				struct device_attribute *attr,
-				char *buf, int channel)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct max517_data *data = iio_priv(indio_dev);
-	/* Corresponds to Vref / 2^(bits) */
-	unsigned int scale_uv = (data->vref_mv[channel - 1] * 1000) >> 8;
-
-	return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
-}
-
-static ssize_t max517_show_scale1(struct device *dev,
-				struct device_attribute *attr,
-				char *buf)
-{
-	return max517_show_scale(dev, attr, buf, 1);
-}
-static IIO_DEVICE_ATTR(out_voltage1_scale, S_IRUGO,
-		       max517_show_scale1, NULL, 0);
-
-static ssize_t max517_show_scale2(struct device *dev,
-				struct device_attribute *attr,
-				char *buf)
-{
-	return max517_show_scale(dev, attr, buf, 2);
-}
-static IIO_DEVICE_ATTR(out_voltage2_scale, S_IRUGO,
-		       max517_show_scale2, NULL, 0);
-
-/* On MAX517 variant, we have one output */
-static struct attribute *max517_attributes[] = {
-	&iio_dev_attr_out_voltage1_raw.dev_attr.attr,
-	&iio_dev_attr_out_voltage1_scale.dev_attr.attr,
-	NULL
-};
-
-static struct attribute_group max517_attribute_group = {
-	.attrs = max517_attributes,
-};
-
-/* On MAX518 and MAX519 variant, we have two outputs */
-static struct attribute *max518_attributes[] = {
-	&iio_dev_attr_out_voltage1_raw.dev_attr.attr,
-	&iio_dev_attr_out_voltage1_scale.dev_attr.attr,
-	&iio_dev_attr_out_voltage2_raw.dev_attr.attr,
-	&iio_dev_attr_out_voltage2_scale.dev_attr.attr,
-	&iio_dev_attr_out_voltage1and2_raw.dev_attr.attr,
-	NULL
-};
-
-static struct attribute_group max518_attribute_group = {
-	.attrs = max518_attributes,
-};
-
-#ifdef CONFIG_PM_SLEEP
-static int max517_suspend(struct device *dev)
-{
-	u8 outbuf = COMMAND_PD;
-
-	return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
-}
-
-static int max517_resume(struct device *dev)
-{
-	u8 outbuf = 0;
-
-	return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
-}
-
-static SIMPLE_DEV_PM_OPS(max517_pm_ops, max517_suspend, max517_resume);
-#define MAX517_PM_OPS (&max517_pm_ops)
-#else
-#define MAX517_PM_OPS NULL
-#endif
-
-static const struct iio_info max517_info = {
-	.attrs = &max517_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static const struct iio_info max518_info = {
-	.attrs = &max518_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-static int max517_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
-{
-	struct max517_data *data;
-	struct iio_dev *indio_dev;
-	struct max517_platform_data *platform_data = client->dev.platform_data;
-	int err;
-
-	indio_dev = iio_device_alloc(sizeof(*data));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto exit;
-	}
-	data = iio_priv(indio_dev);
-	i2c_set_clientdata(client, indio_dev);
-	data->client = client;
-
-	/* establish that the iio_dev is a child of the i2c device */
-	indio_dev->dev.parent = &client->dev;
-
-	/* reduced attribute set for MAX517 */
-	if (id->driver_data == ID_MAX517)
-		indio_dev->info = &max517_info;
-	else
-		indio_dev->info = &max518_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-
-	/*
-	 * Reference voltage on MAX518 and default is 5V, else take vref_mv
-	 * from platform_data
-	 */
-	if (id->driver_data == ID_MAX518 || !platform_data) {
-		data->vref_mv[0] = data->vref_mv[1] = 5000; /* mV */
-	} else {
-		data->vref_mv[0] = platform_data->vref_mv[0];
-		data->vref_mv[1] = platform_data->vref_mv[1];
-	}
-
-	err = iio_device_register(indio_dev);
-	if (err)
-		goto exit_free_device;
-
-	dev_info(&client->dev, "DAC registered\n");
-
-	return 0;
-
-exit_free_device:
-	iio_device_free(indio_dev);
-exit:
-	return err;
-}
-
-static int max517_remove(struct i2c_client *client)
-{
-	iio_device_unregister(i2c_get_clientdata(client));
-	iio_device_free(i2c_get_clientdata(client));
-
-	return 0;
-}
-
-static const struct i2c_device_id max517_id[] = {
-	{ "max517", ID_MAX517 },
-	{ "max518", ID_MAX518 },
-	{ "max519", ID_MAX519 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, max517_id);
-
-static struct i2c_driver max517_driver = {
-	.driver = {
-		.name	= MAX517_DRV_NAME,
-		.pm		= MAX517_PM_OPS,
-	},
-	.probe		= max517_probe,
-	.remove		= max517_remove,
-	.id_table	= max517_id,
-};
-module_i2c_driver(max517_driver);
-
-MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
-MODULE_DESCRIPTION("MAX517/MAX518/MAX519 8-bit DAC");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/dac/max517.h b/drivers/staging/iio/dac/max517.h
deleted file mode 100644
index 8106cf2..0000000
--- a/drivers/staging/iio/dac/max517.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * MAX517 DAC driver
- *
- * Copyright 2011 Roland Stigge <stigge@antcom.de>
- *
- * Licensed under the GPL-2 or later.
- */
-#ifndef IIO_DAC_MAX517_H_
-#define IIO_DAC_MAX517_H_
-
-/*
- * TODO: struct max517_platform_data needs to go into include/linux/iio
- */
-
-struct max517_platform_data {
-	u16				vref_mv[2];
-};
-
-#endif /* IIO_DAC_MAX517_H_ */
diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c
index 11f1dcc..345e4fa 100644
--- a/drivers/staging/iio/gyro/adis16080_core.c
+++ b/drivers/staging/iio/gyro/adis16080_core.c
@@ -82,7 +82,7 @@ static int adis16080_read_raw(struct iio_dev *indio_dev,
 			     long mask)
 {
 	int ret = -EINVAL;
-	u16 ut;
+	u16 ut = 0;
 	/* Take the iio_dev status lock */
 
 	mutex_lock(&indio_dev->mlock);
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
index ec765f9..fdb84cc 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/staging/iio/gyro/adis16260_core.c
@@ -728,8 +728,6 @@ static int adis16260_remove(struct spi_device *spi)
 	if (ret)
 		goto err_ret;
 
-	flush_scheduled_work();
-
 	adis16260_remove_trigger(indio_dev);
 	iio_buffer_unregister(indio_dev);
 	adis16260_unconfigure_ring(indio_dev);
diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c
index 3104119..155a49a 100644
--- a/drivers/staging/iio/iio_simple_dummy.c
+++ b/drivers/staging/iio/iio_simple_dummy.c
@@ -27,7 +27,7 @@
 
 /*
  * A few elements needed to fake a bus for this driver
- * Note instances parmeter controls how many of these
+ * Note instances parameter controls how many of these
  * dummy devices are registered.
  */
 static unsigned instances = 1;
@@ -178,7 +178,7 @@ static struct iio_chan_spec iio_dummy_channels[] = {
 		.scan_index = accelx,
 		.scan_type = { /* Description of storage in buffer */
 			.sign = 's', /* signed */
-			.realbits = 16, /* 12 bits */
+			.realbits = 16, /* 16 bits */
 			.storagebits = 16, /* 16 bits used for storage */
 			.shift = 0, /* zero shift */
 		},
@@ -285,9 +285,9 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
  * iio_dummy_write_raw() - data write function.
  * @indio_dev:	the struct iio_dev associated with this device instance
  * @chan:	the channel whose data is to be read
- * @val:	first element of returned value (typically INT)
- * @val2:	second element of returned value (typically MICRO)
- * @mask:	what we actually want to read. 0 is the channel, everything else
+ * @val:	first element of value to set (typically INT)
+ * @val2:	second element of value to set (typically MICRO)
+ * @mask:	what we actually want to write. 0 is the channel, everything else
  *		is as per the info_mask in iio_chan_spec.
  *
  * Note that all raw writes are assumed IIO_VAL_INT and info mask elements
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index fdfc873..b9e6093 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -67,26 +67,25 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
 		 * software culled hardware scans:
 		 *   occasionally a driver may process the nearest hardware
 		 *   scan to avoid storing elements that are not desired. This
-		 *   is the fidliest option by far.
-		 * Here lets pretend we have random access. And the values are
+		 *   is the fiddliest option by far.
+		 * Here let's pretend we have random access. And the values are
 		 * in the constant table fakedata.
 		 */
 		int i, j;
 		for (i = 0, j = 0;
 		     i < bitmap_weight(indio_dev->active_scan_mask,
 				       indio_dev->masklength);
-		     i++) {
+		     i++, j++) {
 			j = find_next_bit(buffer->scan_mask,
-					  indio_dev->masklength, j + 1);
-			/* random access read form the 'device' */
+					  indio_dev->masklength, j);
+			/* random access read from the 'device' */
 			data[i] = fakedata[j];
 			len += 2;
 		}
 	}
-	/* Store a timestampe at an 8 byte boundary */
+	/* Store the timestamp at an 8 byte aligned offset */
 	if (indio_dev->scan_timestamp)
-		*(s64 *)(((phys_addr_t)data + len
-				+ sizeof(s64) - 1) & ~(sizeof(s64) - 1))
+		*(s64 *)((phys_addr_t)data + ALIGN(len, sizeof(s64)))
 			= iio_get_time_ns();
 	buffer->access->store_to(buffer, (u8 *)data, pf->timestamp);
 
diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h
index 83d133e..9dd9f14 100644
--- a/drivers/staging/iio/imu/adis16400.h
+++ b/drivers/staging/iio/imu/adis16400.h
@@ -42,7 +42,8 @@
 #define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */
 
 #define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */
-#define ADIS16300_ROLL_OUT  0x12 /* Y axis inclinometer output measurement */
+#define ADIS16300_ROLL_OUT  0x14 /* Y axis inclinometer output measurement */
+#define ADIS16300_AUX_ADC   0x16 /* Auxiliary ADC measurement */
 
 /* Calibration parameters */
 #define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */
diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c
index 1f6bd85..3873014 100644
--- a/drivers/staging/iio/imu/adis16400_core.c
+++ b/drivers/staging/iio/imu/adis16400_core.c
@@ -472,11 +472,12 @@ enum adis16400_chan {
 	temp,
 	temp0, temp1, temp2,
 	in1,
+	in2,
 	incli_x,
 	incli_y,
 };
 
-static u8 adis16400_addresses[17][2] = {
+static u8 adis16400_addresses[18][2] = {
 	[in_supply] = { ADIS16400_SUPPLY_OUT },
 	[gyro_x] = { ADIS16400_XGYRO_OUT, ADIS16400_XGYRO_OFF },
 	[gyro_y] = { ADIS16400_YGYRO_OUT, ADIS16400_YGYRO_OFF },
@@ -491,7 +492,8 @@ static u8 adis16400_addresses[17][2] = {
 	[temp0] = { ADIS16350_XTEMP_OUT },
 	[temp1] = { ADIS16350_YTEMP_OUT },
 	[temp2] = { ADIS16350_ZTEMP_OUT },
-	[in1] = { ADIS16400_AUX_ADC },
+	[in1] = { ADIS16300_AUX_ADC },
+	[in2] = { ADIS16400_AUX_ADC },
 	[incli_x] = { ADIS16300_PITCH_OUT },
 	[incli_y] = { ADIS16300_ROLL_OUT }
 };
@@ -752,7 +754,7 @@ static struct iio_chan_spec adis16400_channels[] = {
 		.channel = 1,
 		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		.address = in1,
+		.address = in2,
 		.scan_index = ADIS16400_SCAN_ADC_0,
 		.scan_type = IIO_ST('s', 12, 16, 0),
 	},
@@ -946,7 +948,7 @@ static struct iio_chan_spec adis16300_channels[] = {
 		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
-		.address = temp,
+		.address = temp0,
 		.scan_index = ADIS16400_SCAN_TEMP,
 		.scan_type = IIO_ST('s', 12, 16, 0),
 	}, {
@@ -1054,8 +1056,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
 		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
 		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
 		IIO_CHAN_INFO_SCALE_SHARED_BIT,
-		.address = accel_z,
-		.scan_index = ADIS16400_SCAN_ACC_Z,
+		.address = temp0,
+		.scan_index = ADIS16400_SCAN_TEMP,
 		.scan_type = IIO_ST('s', 14, 16, 0),
 	},
 	IIO_CHAN_SOFT_TIMESTAMP(12)
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c
index 0abbf18..31d22f5 100644
--- a/drivers/staging/iio/light/isl29018.c
+++ b/drivers/staging/iio/light/isl29018.c
@@ -292,18 +292,18 @@ static ssize_t store_resolution(struct device *dev,
 }
 
 /* proximity scheme */
-static ssize_t show_prox_infrared_supression(struct device *dev,
+static ssize_t show_prox_infrared_suppression(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct isl29018_chip *chip = iio_priv(indio_dev);
 
 	/* return the "proximity scheme" i.e. if the chip does on chip
-	infrared supression (1 means perform on chip supression) */
+	infrared suppression (1 means perform on chip suppression) */
 	return sprintf(buf, "%d\n", chip->prox_scheme);
 }
 
-static ssize_t store_prox_infrared_supression(struct device *dev,
+static ssize_t store_prox_infrared_suppression(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -318,7 +318,7 @@ static ssize_t store_prox_infrared_supression(struct device *dev,
 	}
 
 	/* get the  "proximity scheme" i.e. if the chip does on chip
-	infrared supression (1 means perform on chip supression) */
+	infrared suppression (1 means perform on chip suppression) */
 	mutex_lock(&chip->lock);
 	chip->prox_scheme = (int)lval;
 	mutex_unlock(&chip->lock);
@@ -413,10 +413,10 @@ static IIO_CONST_ATTR(range_available, "1000 4000 16000 64000");
 static IIO_CONST_ATTR(adc_resolution_available, "4 8 12 16");
 static IIO_DEVICE_ATTR(adc_resolution, S_IRUGO | S_IWUSR,
 					show_resolution, store_resolution, 0);
-static IIO_DEVICE_ATTR(proximity_on_chip_ambient_infrared_supression,
+static IIO_DEVICE_ATTR(proximity_on_chip_ambient_infrared_suppression,
 					S_IRUGO | S_IWUSR,
-					show_prox_infrared_supression,
-					store_prox_infrared_supression, 0);
+					show_prox_infrared_suppression,
+					store_prox_infrared_suppression, 0);
 
 #define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
 #define ISL29018_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)
@@ -425,7 +425,7 @@ static struct attribute *isl29018_attributes[] = {
 	ISL29018_CONST_ATTR(range_available),
 	ISL29018_DEV_ATTR(adc_resolution),
 	ISL29018_CONST_ATTR(adc_resolution_available),
-	ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_supression),
+	ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_suppression),
 	NULL
 };
 
diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c
index 5e23ad5..6d2f4c6 100644
--- a/drivers/staging/iio/light/tsl2583.c
+++ b/drivers/staging/iio/light/tsl2583.c
@@ -410,7 +410,7 @@ static int taos_chip_on(struct iio_dev *indio_dev)
 		return -EINVAL;
 	}
 
-	/* determine als integration regster */
+	/* determine als integration register */
 	als_count = (chip->taos_settings.als_time * 100 + 135) / 270;
 	if (als_count == 0)
 		als_count = 1; /* ensure at least one cycle */
diff --git a/drivers/staging/iio/light/tsl2x7x.h b/drivers/staging/iio/light/tsl2x7x.h
old mode 100755
new mode 100644
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
old mode 100755
new mode 100644
index c3b05a1..fdf75e4
--- a/drivers/staging/iio/light/tsl2x7x_core.c
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -27,7 +27,6 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/iio/events.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -737,7 +736,7 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
 		return -EINVAL;
 	}
 
-	/* determine als integration regster */
+	/* determine als integration register */
 	als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270;
 	if (als_count == 0)
 		als_count = 1; /* ensure at least one cycle */
diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
index b9d9325..df5e0d4 100644
--- a/drivers/staging/iio/magnetometer/Kconfig
+++ b/drivers/staging/iio/magnetometer/Kconfig
@@ -6,7 +6,7 @@ menu "Magnetometer sensors"
 config SENSORS_AK8975
 	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
 	depends on I2C
-	depends on GENERIC_GPIO
+	depends on GPIOLIB
 	help
 	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
 	  Magnetometer.
diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/staging/iio/magnetometer/ak8975.c
index 5834e4a..01b4b07 100644
--- a/drivers/staging/iio/magnetometer/ak8975.c
+++ b/drivers/staging/iio/magnetometer/ak8975.c
@@ -92,7 +92,6 @@ struct ak8975_data {
 	struct mutex		lock;
 	u8			asa[3];
 	long			raw_to_gauss[3];
-	bool			mode;
 	u8			reg_cache[AK8975_MAX_REGS];
 	int			eoc_gpio;
 	int			eoc_irq;
@@ -194,6 +193,17 @@ static int ak8975_setup(struct i2c_client *client)
 		return ret;
 	}
 
+	/* After reading fuse ROM data set power-down mode */
+	ret = ak8975_write_data(client,
+				AK8975_REG_CNTL,
+				AK8975_REG_CNTL_MODE_POWER_DOWN,
+				AK8975_REG_CNTL_MODE_MASK,
+				AK8975_REG_CNTL_MODE_SHIFT);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error in setting power-down mode\n");
+		return ret;
+	}
+
 /*
  * Precalculate scale factor (in Gauss units) for each axis and
  * store in the device data.
@@ -236,60 +246,6 @@ static int ak8975_setup(struct i2c_client *client)
 	return 0;
 }
 
-/*
- * Shows the device's mode.  0 = off, 1 = on.
- */
-static ssize_t show_mode(struct device *dev, struct device_attribute *devattr,
-			 char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ak8975_data *data = iio_priv(indio_dev);
-
-	return sprintf(buf, "%u\n", data->mode);
-}
-
-/*
- * Sets the device's mode.  0 = off, 1 = on.  The device's mode must be on
- * for the magn raw attributes to be available.
- */
-static ssize_t store_mode(struct device *dev, struct device_attribute *devattr,
-			  const char *buf, size_t count)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct ak8975_data *data = iio_priv(indio_dev);
-	struct i2c_client *client = data->client;
-	bool value;
-	int ret;
-
-	/* Convert mode string and do some basic sanity checking on it.
-	   only 0 or 1 are valid. */
-	ret = strtobool(buf, &value);
-	if (ret < 0)
-		return ret;
-
-	mutex_lock(&data->lock);
-
-	/* Write the mode to the device. */
-	if (data->mode != value) {
-		ret = ak8975_write_data(client,
-					AK8975_REG_CNTL,
-					(u8)value,
-					AK8975_REG_CNTL_MODE_MASK,
-					AK8975_REG_CNTL_MODE_SHIFT);
-
-		if (ret < 0) {
-			dev_err(&client->dev, "Error in setting mode\n");
-			mutex_unlock(&data->lock);
-			return ret;
-		}
-		data->mode = value;
-	}
-
-	mutex_unlock(&data->lock);
-
-	return count;
-}
-
 static int wait_conversion_complete_gpio(struct ak8975_data *data)
 {
 	struct i2c_client *client = data->client;
@@ -357,12 +313,6 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 
 	mutex_lock(&data->lock);
 
-	if (data->mode == 0) {
-		dev_err(&client->dev, "Operating mode is in power down mode\n");
-		ret = -EBUSY;
-		goto exit;
-	}
-
 	/* Set up the device for taking a sample. */
 	ret = ak8975_write_data(client,
 				AK8975_REG_CNTL,
@@ -454,24 +404,12 @@ static const struct iio_chan_spec ak8975_channels[] = {
 	AK8975_CHANNEL(X, 0), AK8975_CHANNEL(Y, 1), AK8975_CHANNEL(Z, 2),
 };
 
-static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, show_mode, store_mode, 0);
-
-static struct attribute *ak8975_attr[] = {
-	&iio_dev_attr_mode.dev_attr.attr,
-	NULL
-};
-
-static struct attribute_group ak8975_attr_group = {
-	.attrs = ak8975_attr,
-};
-
 static const struct iio_info ak8975_info = {
-	.attrs = &ak8975_attr_group,
 	.read_raw = &ak8975_read_raw,
 	.driver_module = THIS_MODULE,
 };
 
-static int ak8975_probe(struct i2c_client *client,
+static int __devinit ak8975_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
 	struct ak8975_data *data;
@@ -488,21 +426,13 @@ static int ak8975_probe(struct i2c_client *client,
 	/* We may not have a GPIO based IRQ to scan, that is fine, we will
 	   poll if so */
 	if (gpio_is_valid(eoc_gpio)) {
-		err = gpio_request(eoc_gpio, "ak_8975");
+		err = gpio_request_one(eoc_gpio, GPIOF_IN, "ak_8975");
 		if (err < 0) {
 			dev_err(&client->dev,
 				"failed to request GPIO %d, error %d\n",
 							eoc_gpio, err);
 			goto exit;
 		}
-
-		err = gpio_direction_input(eoc_gpio);
-		if (err < 0) {
-			dev_err(&client->dev,
-				"Failed to configure input direction for GPIO %d, error %d\n",
-						eoc_gpio, err);
-			goto exit_gpio;
-		}
 	}
 
 	/* Register with IIO */
@@ -545,7 +475,7 @@ exit:
 	return err;
 }
 
-static int ak8975_remove(struct i2c_client *client)
+static int __devexit ak8975_remove(struct i2c_client *client)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 	struct ak8975_data *data = iio_priv(indio_dev);
diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c
index c1fa09f..6c3e50f 100644
--- a/drivers/staging/iio/magnetometer/hmc5843.c
+++ b/drivers/staging/iio/magnetometer/hmc5843.c
@@ -665,7 +665,7 @@ static const struct iio_info hmc5843_info = {
 	.driver_module = THIS_MODULE,
 };
 
-static int hmc5843_probe(struct i2c_client *client,
+static int __devinit hmc5843_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
 	struct hmc5843_data *data;
@@ -704,7 +704,7 @@ exit:
 	return err;
 }
 
-static int hmc5843_remove(struct i2c_client *client)
+static int __devexit hmc5843_remove(struct i2c_client *client)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
@@ -755,7 +755,7 @@ static struct i2c_driver hmc5843_driver = {
 	},
 	.id_table	= hmc5843_id,
 	.probe		= hmc5843_probe,
-	.remove		= hmc5843_remove,
+	.remove		= __devexit_p(hmc5843_remove),
 	.detect		= hmc5843_detect,
 	.address_list	= normal_i2c,
 };
diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c
index 9358c6c..f61c8fd 100644
--- a/drivers/staging/iio/ring_sw.c
+++ b/drivers/staging/iio/ring_sw.c
@@ -24,7 +24,7 @@
  * @read_p:		read pointer (oldest available)
  * @write_p:		write pointer
  * @half_p:		half buffer length behind write_p (event generation)
- * @update_needed:	flag to indicated change in size requested
+ * @update_needed:	flag to indicate change in size requested
  *
  * Note that the first element of all ring buffers must be a
  * struct iio_buffer.
@@ -363,5 +363,5 @@ void iio_sw_rb_free(struct iio_buffer *r)
 }
 EXPORT_SYMBOL(iio_sw_rb_free);
 
-MODULE_DESCRIPTION("Industrialio I/O software ring buffer");
+MODULE_DESCRIPTION("Industrial I/O software ring buffer");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
index f85734d..ce6a7b1 100644
--- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
+++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
@@ -60,7 +60,7 @@ struct bfin_tmr_state {
 static ssize_t iio_bfin_tmr_frequency_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct iio_trigger *trig = dev_get_drvdata(dev);
+	struct iio_trigger *trig = to_iio_trigger(dev);
 	struct bfin_tmr_state *st = trig->private_data;
 	long val;
 	int ret;
@@ -97,7 +97,7 @@ static ssize_t iio_bfin_tmr_frequency_show(struct device *dev,
 				 struct device_attribute *attr,
 				 char *buf)
 {
-	struct iio_trigger *trig = dev_get_drvdata(dev);
+	struct iio_trigger *trig = to_iio_trigger(dev);
 	struct bfin_tmr_state *st = trig->private_data;
 
 	return sprintf(buf, "%lu\n",
diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
index 9f2d055..4ceaa18 100644
--- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
+++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
@@ -41,7 +41,7 @@ static ssize_t iio_trig_periodic_read_freq(struct device *dev,
 					   struct device_attribute *attr,
 					   char *buf)
 {
-	struct iio_trigger *trig = dev_get_drvdata(dev);
+	struct iio_trigger *trig = to_iio_trigger(dev);
 	struct iio_prtc_trigger_info *trig_info = trig->private_data;
 	return sprintf(buf, "%u\n", trig_info->frequency);
 }
@@ -51,7 +51,7 @@ static ssize_t iio_trig_periodic_write_freq(struct device *dev,
 					    const char *buf,
 					    size_t len)
 {
-	struct iio_trigger *trig = dev_get_drvdata(dev);
+	struct iio_trigger *trig = to_iio_trigger(dev);
 	struct iio_prtc_trigger_info *trig_info = trig->private_data;
 	unsigned long val;
 	int ret;
diff --git a/drivers/staging/iio/trigger/iio-trig-sysfs.c b/drivers/staging/iio/trigger/iio-trig-sysfs.c
index 552763b..fee4746 100644
--- a/drivers/staging/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/staging/iio/trigger/iio-trig-sysfs.c
@@ -92,7 +92,7 @@ static struct device iio_sysfs_trig_dev = {
 static ssize_t iio_sysfs_trigger_poll(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct iio_trigger *trig = dev_get_drvdata(dev);
+	struct iio_trigger *trig = to_iio_trigger(dev);
 	iio_trigger_poll_chained(trig, 0);
 
 	return count;
diff --git a/drivers/staging/ipack/TODO b/drivers/staging/ipack/TODO
index 3a45a53..0f8bf20 100644
--- a/drivers/staging/ipack/TODO
+++ b/drivers/staging/ipack/TODO
@@ -15,10 +15,6 @@ TODO
 TPCI-200
 --------
 
-* It receives the name of the mezzanine plugged in each slot by SYSFS.
-  No autodetection supported yet, because the mezzanine driver could not be
-  loaded at the time that the tpci200 driver loads.
-
 * It has a linked list with the tpci200 devices it is managing. Get rid of it
   and use driver_for_each_device() instead.
 
diff --git a/drivers/staging/ipack/bridges/tpci200.c b/drivers/staging/ipack/bridges/tpci200.c
index ad28707..2b83fa8 100644
--- a/drivers/staging/ipack/bridges/tpci200.c
+++ b/drivers/staging/ipack/bridges/tpci200.c
@@ -11,8 +11,6 @@
  * Software Foundation; version 2 of the License.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/module.h>
 #include "tpci200.h"
 
@@ -36,10 +34,8 @@ static struct tpci200_board *check_slot(struct ipack_device *dev)
 	struct tpci200_board *tpci200;
 	int found = 0;
 
-	if (dev == NULL) {
-		pr_info("Slot doesn't exist.\n");
+	if (dev == NULL)
 		return NULL;
-	}
 
 	list_for_each_entry(tpci200, &tpci200_list, list) {
 		if (tpci200->number == dev->bus_nr) {
@@ -49,20 +45,14 @@ static struct tpci200_board *check_slot(struct ipack_device *dev)
 	}
 
 	if (!found) {
-		pr_err("Carrier not found\n");
+		dev_err(&dev->dev, "Carrier not found\n");
 		return NULL;
 	}
 
 	if (dev->slot >= TPCI200_NB_SLOT) {
-		pr_info("Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n",
-			dev->bus_nr, dev->slot, TPCI200_NB_SLOT-1);
-		return NULL;
-	}
-
-	BUG_ON(tpci200->slots == NULL);
-	if (tpci200->slots[dev->slot].dev == NULL) {
-		pr_info("Slot [%d:%d] is not registered !\n", dev->bus_nr,
-			dev->slot);
+		dev_info(&dev->dev,
+			 "Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n",
+			 dev->bus_nr, dev->slot, TPCI200_NB_SLOT-1);
 		return NULL;
 	}
 
@@ -123,14 +113,15 @@ static struct ipack_addr_space *get_slot_address_space(struct ipack_device *dev,
 		addr = &dev->mem_space;
 		break;
 	default:
-		pr_err("Slot [%d:%d] space number %d doesn't exist !\n",
-		       dev->bus_nr, dev->slot, space);
+		dev_err(&dev->dev,
+			"Slot [%d:%d] space number %d doesn't exist !\n",
+			dev->bus_nr, dev->slot, space);
 		return NULL;
 		break;
 	}
 
 	if ((addr->size == 0) || (addr->address == NULL)) {
-		pr_err("Error, slot space not mapped !\n");
+		dev_err(&dev->dev, "Error, slot space not mapped !\n");
 		return NULL;
 	}
 
@@ -152,7 +143,7 @@ static int tpci200_read8(struct ipack_device *dev, int space,
 		return -EINVAL;
 
 	if (offset >= addr->size) {
-		pr_err("Error, slot space offset error !\n");
+		dev_err(&dev->dev, "Error, slot space offset error !\n");
 		return -EFAULT;
 	}
 
@@ -176,7 +167,7 @@ static int tpci200_read16(struct ipack_device *dev, int space,
 		return -EINVAL;
 
 	if ((offset+2) >= addr->size) {
-		pr_err("Error, slot space offset error !\n");
+		dev_err(&dev->dev, "Error, slot space offset error !\n");
 		return -EFAULT;
 	}
 	*value = __tpci200_read16(addr->address, offset);
@@ -199,7 +190,7 @@ static int tpci200_read32(struct ipack_device *dev, int space,
 		return -EINVAL;
 
 	if ((offset+4) >= addr->size) {
-		pr_err("Error, slot space offset error !\n");
+		dev_err(&dev->dev, "Error, slot space offset error !\n");
 		return -EFAULT;
 	}
 
@@ -223,7 +214,7 @@ static int tpci200_write8(struct ipack_device *dev, int space,
 		return -EINVAL;
 
 	if (offset >= addr->size) {
-		pr_err("Error, slot space offset error !\n");
+		dev_err(&dev->dev, "Error, slot space offset error !\n");
 		return -EFAULT;
 	}
 
@@ -247,7 +238,7 @@ static int tpci200_write16(struct ipack_device *dev, int space,
 		return -EINVAL;
 
 	if ((offset+2) >= addr->size) {
-		pr_err("Error, slot space offset error !\n");
+		dev_err(&dev->dev, "Error, slot space offset error !\n");
 		return -EFAULT;
 	}
 
@@ -271,7 +262,7 @@ static int tpci200_write32(struct ipack_device *dev, int space,
 		return -EINVAL;
 
 	if ((offset+4) >= addr->size) {
-		pr_err("Error, slot space offset error !\n");
+		dev_err(&dev->dev, "Error, slot space offset error !\n");
 		return -EFAULT;
 	}
 
@@ -297,8 +288,6 @@ static void tpci200_unregister(struct tpci200_board *tpci200)
 	pci_disable_device(tpci200->info->pdev);
 	pci_dev_put(tpci200->info->pdev);
 
-	kfree(tpci200->info);
-
 	for (i = 0; i < TPCI200_NB_SLOT; i++) {
 		tpci200->slots[i].io_phys.address = NULL;
 		tpci200->slots[i].io_phys.size = 0;
@@ -313,13 +302,10 @@ static irqreturn_t tpci200_interrupt(int irq, void *dev_id)
 {
 	struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id;
 	int i;
-	unsigned long flags;
 	unsigned short status_reg, reg_value;
 	unsigned short unhandled_ints = 0;
 	irqreturn_t ret = IRQ_NONE;
 
-	spin_lock_irqsave(&tpci200->info->access_lock, flags);
-
 	/* Read status register */
 	status_reg = readw(tpci200->info->interface_regs +
 			   TPCI200_STATUS_REG);
@@ -347,8 +333,9 @@ static irqreturn_t tpci200_interrupt(int irq, void *dev_id)
 	if (unhandled_ints) {
 		for (i = 0; i < TPCI200_NB_SLOT; i++) {
 			if (unhandled_ints & ((TPCI200_INT0_EN | TPCI200_INT1_EN) << (2*i))) {
-				pr_info("No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n",
-					tpci200->number, i);
+				dev_info(&tpci200->slots[i].dev->dev,
+					 "No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n",
+					 tpci200->number, i);
 				reg_value = readw(
 					tpci200->info->interface_regs +
 					control_reg[i]);
@@ -361,211 +348,12 @@ static irqreturn_t tpci200_interrupt(int irq, void *dev_id)
 		}
 	}
 
-	spin_unlock_irqrestore(&tpci200->info->access_lock, flags);
 	return ret;
 }
 
-#ifdef CONFIG_SYSFS
-
-static struct ipack_device *tpci200_slot_register(unsigned int tpci200_number,
-						  unsigned int slot_position)
-{
-	int found = 0;
-	struct ipack_device  *dev;
-	struct tpci200_board *tpci200;
-
-	list_for_each_entry(tpci200, &tpci200_list, list) {
-		if (tpci200->number == tpci200_number) {
-			found = 1;
-			break;
-		}
-	}
-
-	if (!found) {
-		pr_err("carrier board not found for the device\n");
-		return NULL;
-	}
-
-	if (slot_position >= TPCI200_NB_SLOT) {
-		pr_info("Slot [%d:%d] doesn't exist!\n", tpci200_number,
-			slot_position);
-		return NULL;
-	}
-
-	if (mutex_lock_interruptible(&tpci200->mutex))
-		return NULL;
-
-	if (tpci200->slots[slot_position].dev != NULL) {
-		pr_err("Slot [%d:%d] already installed !\n", tpci200_number,
-		       slot_position);
-		goto err_unlock;
-	}
-
-	/*
-	 * Give the same IRQ number as the slot number.
-	 * The TPCI200 has assigned his own two IRQ by PCI bus driver
-	 */
-	dev = ipack_device_register(tpci200->info->ipack_bus,
-				    slot_position, slot_position);
-	if (dev == NULL) {
-		pr_info("Slot [%d:%d] Unable to register an ipack device\n",
-			tpci200_number, slot_position);
-		goto err_unlock;
-	}
-
-	tpci200->slots[slot_position].dev = dev;
-	mutex_unlock(&tpci200->mutex);
-	return dev;
-
-err_unlock:
-	mutex_unlock(&tpci200->mutex);
-	return NULL;
-}
-
-static ssize_t tpci200_store_board(struct device *pdev, const char *buf,
-				   size_t count, int slot)
-{
-	struct tpci200_board *card = dev_get_drvdata(pdev);
-	struct ipack_device *dev = card->slots[slot].dev;
-
-	if (dev != NULL)
-		return -EBUSY;
-
-	dev = tpci200_slot_register(card->number, slot);
-	if (dev == NULL)
-		return -ENODEV;
-
-	return count;
-}
-
-static ssize_t tpci200_show_board(struct device *pdev, char *buf, int slot)
-{
-	struct tpci200_board *card = dev_get_drvdata(pdev);
-	struct ipack_device *dev = card->slots[slot].dev;
-
-	if (dev != NULL)
-		return snprintf(buf, PAGE_SIZE, "%s\n", dev_name(&dev->dev));
-	else
-		return snprintf(buf, PAGE_SIZE, "none\n");
-}
-
-static ssize_t tpci200_show_description(struct device *pdev,
-					struct device_attribute *attr,
-					char *buf)
-{
-	return snprintf(buf, PAGE_SIZE,
-			"TEWS tpci200 carrier PCI for Industry-pack mezzanines.\n");
-}
-
-static ssize_t tpci200_show_board_slot0(struct device *pdev,
-					struct device_attribute *attr,
-					char *buf)
-{
-	return tpci200_show_board(pdev, buf, 0);
-}
-
-static ssize_t tpci200_store_board_slot0(struct device *pdev,
-					 struct device_attribute *attr,
-					 const char *buf, size_t count)
-{
-	return tpci200_store_board(pdev, buf, count, 0);
-}
-
-static ssize_t tpci200_show_board_slot1(struct device *pdev,
-					struct device_attribute *attr,
-					char *buf)
-{
-	return tpci200_show_board(pdev, buf, 1);
-}
-
-static ssize_t tpci200_store_board_slot1(struct device *pdev,
-					 struct device_attribute *attr,
-					 const char *buf, size_t count)
-{
-	return tpci200_store_board(pdev, buf, count, 1);
-}
-
-static ssize_t tpci200_show_board_slot2(struct device *pdev,
-					struct device_attribute *attr,
-					char *buf)
-{
-	return tpci200_show_board(pdev, buf, 2);
-}
-
-static ssize_t tpci200_store_board_slot2(struct device *pdev,
-					 struct device_attribute *attr,
-					 const char *buf, size_t count)
-{
-	return tpci200_store_board(pdev, buf, count, 2);
-}
-
-
-static ssize_t tpci200_show_board_slot3(struct device *pdev,
-					struct device_attribute *attr,
-					char *buf)
-{
-	return tpci200_show_board(pdev, buf, 3);
-}
-
-static ssize_t tpci200_store_board_slot3(struct device *pdev,
-					 struct device_attribute *attr,
-					 const char *buf, size_t count)
-{
-	return tpci200_store_board(pdev, buf, count, 3);
-}
-
-/* Declaration of the device attributes for the TPCI200 */
-static DEVICE_ATTR(description, S_IRUGO,
-		   tpci200_show_description, NULL);
-static DEVICE_ATTR(board_slot0, S_IRUGO | S_IWUSR,
-		   tpci200_show_board_slot0, tpci200_store_board_slot0);
-static DEVICE_ATTR(board_slot1, S_IRUGO | S_IWUSR,
-		   tpci200_show_board_slot1, tpci200_store_board_slot1);
-static DEVICE_ATTR(board_slot2, S_IRUGO | S_IWUSR,
-		   tpci200_show_board_slot2, tpci200_store_board_slot2);
-static DEVICE_ATTR(board_slot3, S_IRUGO | S_IWUSR,
-		   tpci200_show_board_slot3, tpci200_store_board_slot3);
-
-static struct attribute *tpci200_attrs[] = {
-	&dev_attr_description.attr,
-	&dev_attr_board_slot0.attr,
-	&dev_attr_board_slot1.attr,
-	&dev_attr_board_slot2.attr,
-	&dev_attr_board_slot3.attr,
-	NULL,
-};
-
-static struct attribute_group tpci200_attr_group = {
-	.attrs = tpci200_attrs,
-};
-
-static int tpci200_create_sysfs_files(struct tpci200_board *card)
-{
-	return sysfs_create_group(&card->info->pdev->dev.kobj,
-				  &tpci200_attr_group);
-}
-
-static void tpci200_remove_sysfs_files(struct tpci200_board *card)
-{
-	sysfs_remove_group(&card->info->pdev->dev.kobj, &tpci200_attr_group);
-}
-
-#else
-
-static int tpci200_create_sysfs_files(struct tpci200_board *card)
-{
-	return 0;
-}
-
-static void tpci200_remove_sysfs_files(struct tpci200_board *card)
-{
-}
-
-#endif /* CONFIG_SYSFS */
-
 static int tpci200_register(struct tpci200_board *tpci200)
 {
-	int  i;
+	int i;
 	int res;
 	unsigned long ioidint_base;
 	unsigned long mem_base;
@@ -574,20 +362,15 @@ static int tpci200_register(struct tpci200_board *tpci200)
 	if (pci_enable_device(tpci200->info->pdev) < 0)
 		return -ENODEV;
 
-	if (tpci200_create_sysfs_files(tpci200) < 0) {
-		pr_err("failed creating sysfs files\n");
-		res = -EFAULT;
-		goto out_disable_pci;
-	}
-
 	/* Request IP interface register (Bar 2) */
 	res = pci_request_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR,
 				 "Carrier IP interface registers");
 	if (res) {
-		pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !",
-		       tpci200->info->pdev->bus->number,
-		       tpci200->info->pdev->devfn);
-		goto out_remove_sysfs;
+		dev_err(&tpci200->info->pdev->dev,
+			"(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !",
+			tpci200->info->pdev->bus->number,
+			tpci200->info->pdev->devfn);
+		goto out_disable_pci;
 	}
 
 	/* Request IO ID INT space (Bar 3) */
@@ -595,9 +378,10 @@ static int tpci200_register(struct tpci200_board *tpci200)
 				 TPCI200_IO_ID_INT_SPACES_BAR,
 				 "Carrier IO ID INT space");
 	if (res) {
-		pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !",
-		       tpci200->info->pdev->bus->number,
-		       tpci200->info->pdev->devfn);
+		dev_err(&tpci200->info->pdev->dev,
+			"(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !",
+			tpci200->info->pdev->bus->number,
+			tpci200->info->pdev->devfn);
 		goto out_release_ip_space;
 	}
 
@@ -605,9 +389,10 @@ static int tpci200_register(struct tpci200_board *tpci200)
 	res = pci_request_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR,
 				 "Carrier MEM space");
 	if (res) {
-		pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!",
-		       tpci200->info->pdev->bus->number,
-		       tpci200->info->pdev->devfn);
+		dev_err(&tpci200->info->pdev->dev,
+			"(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!",
+			tpci200->info->pdev->bus->number,
+			tpci200->info->pdev->devfn);
 		goto out_release_ioid_int_space;
 	}
 
@@ -625,7 +410,6 @@ static int tpci200_register(struct tpci200_board *tpci200)
 					   TPCI200_MEM8_SPACE_BAR),
 			TPCI200_MEM8_SIZE);
 
-	spin_lock_init(&tpci200->info->access_lock);
 	ioidint_base = pci_resource_start(tpci200->info->pdev,
 					  TPCI200_IO_ID_INT_SPACES_BAR);
 	mem_base = pci_resource_start(tpci200->info->pdev,
@@ -665,11 +449,11 @@ static int tpci200_register(struct tpci200_board *tpci200)
 			  tpci200_interrupt, IRQF_SHARED,
 			  KBUILD_MODNAME, (void *) tpci200);
 	if (res) {
-		pr_err("(bn 0x%X, sn 0x%X) unable to register IRQ !",
-		       tpci200->info->pdev->bus->number,
-		       tpci200->info->pdev->devfn);
-		tpci200_unregister(tpci200);
-		goto out_err;
+		dev_err(&tpci200->info->pdev->dev,
+			"(bn 0x%X, sn 0x%X) unable to register IRQ !",
+			tpci200->info->pdev->bus->number,
+			tpci200->info->pdev->devfn);
+		goto out_release_ioid_int_space;
 	}
 
 	return 0;
@@ -678,11 +462,8 @@ out_release_ioid_int_space:
 	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
 out_release_ip_space:
 	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
-out_remove_sysfs:
-	tpci200_remove_sysfs_files(tpci200);
 out_disable_pci:
 	pci_disable_device(tpci200->info->pdev);
-out_err:
 	return res;
 }
 
@@ -726,24 +507,19 @@ static void __tpci200_free_irq(struct tpci200_board *tpci200,
 
 static int tpci200_free_irq(struct ipack_device *dev)
 {
-	int res;
 	struct slot_irq *slot_irq;
 	struct tpci200_board *tpci200;
 
 	tpci200 = check_slot(dev);
-	if (tpci200 == NULL) {
-		res = -EINVAL;
-		goto out;
-	}
+	if (tpci200 == NULL)
+		return -EINVAL;
 
-	if (mutex_lock_interruptible(&tpci200->mutex)) {
-		res = -ERESTARTSYS;
-		goto out;
-	}
+	if (mutex_lock_interruptible(&tpci200->mutex))
+		return -ERESTARTSYS;
 
 	if (tpci200->slots[dev->slot].irq == NULL) {
-		res = -EINVAL;
-		goto out_unlock;
+		mutex_unlock(&tpci200->mutex);
+		return -EINVAL;
 	}
 
 	__tpci200_free_irq(tpci200, dev);
@@ -751,60 +527,56 @@ static int tpci200_free_irq(struct ipack_device *dev)
 	tpci200->slots[dev->slot].irq = NULL;
 	kfree(slot_irq);
 
-out_unlock:
 	mutex_unlock(&tpci200->mutex);
-out:
-	return res;
+	return 0;
 }
 
 static int tpci200_slot_unmap_space(struct ipack_device *dev, int space)
 {
-	int res;
 	struct ipack_addr_space *virt_addr_space;
 	struct tpci200_board *tpci200;
 
 	tpci200 = check_slot(dev);
-	if (tpci200 == NULL) {
-		res = -EINVAL;
-		goto out;
-	}
+	if (tpci200 == NULL)
+		return -EINVAL;
 
-	if (mutex_lock_interruptible(&tpci200->mutex)) {
-		res = -ERESTARTSYS;
-		goto out;
-	}
+	if (mutex_lock_interruptible(&tpci200->mutex))
+		return -ERESTARTSYS;
 
 	switch (space) {
 	case IPACK_IO_SPACE:
 		if (dev->io_space.address == NULL) {
-			pr_info("Slot [%d:%d] IO space not mapped !\n",
-				dev->bus_nr, dev->slot);
+			dev_info(&dev->dev,
+				 "Slot [%d:%d] IO space not mapped !\n",
+				 dev->bus_nr, dev->slot);
 			goto out_unlock;
 		}
 		virt_addr_space = &dev->io_space;
 		break;
 	case IPACK_ID_SPACE:
 		if (dev->id_space.address == NULL) {
-			pr_info("Slot [%d:%d] ID space not mapped !\n",
-				dev->bus_nr, dev->slot);
+			dev_info(&dev->dev,
+				 "Slot [%d:%d] ID space not mapped !\n",
+				 dev->bus_nr, dev->slot);
 			goto out_unlock;
 		}
 		virt_addr_space = &dev->id_space;
 		break;
 	case IPACK_MEM_SPACE:
 		if (dev->mem_space.address == NULL) {
-			pr_info("Slot [%d:%d] MEM space not mapped !\n",
-				dev->bus_nr, dev->slot);
-		goto out_unlock;
+			dev_info(&dev->dev,
+				 "Slot [%d:%d] MEM space not mapped !\n",
+				 dev->bus_nr, dev->slot);
+			goto out_unlock;
 		}
 		virt_addr_space = &dev->mem_space;
 		break;
 	default:
-		pr_err("Slot [%d:%d] space number %d doesn't exist !\n",
-		       dev->bus_nr, dev->slot, space);
-		res = -EINVAL;
-		goto out_unlock;
-		break;
+		dev_err(&dev->dev,
+			"Slot [%d:%d] space number %d doesn't exist !\n",
+			dev->bus_nr, dev->slot, space);
+		mutex_unlock(&tpci200->mutex);
+		return -EINVAL;
 	}
 
 	iounmap(virt_addr_space->address);
@@ -813,8 +585,7 @@ static int tpci200_slot_unmap_space(struct ipack_device *dev, int space)
 	virt_addr_space->size = 0;
 out_unlock:
 	mutex_unlock(&tpci200->mutex);
-out:
-	return res;
+	return 0;
 }
 
 static int tpci200_slot_unregister(struct ipack_device *dev)
@@ -843,28 +614,25 @@ static int tpci200_slot_unregister(struct ipack_device *dev)
 static int tpci200_slot_map_space(struct ipack_device *dev,
 				  unsigned int memory_size, int space)
 {
-	int res;
+	int res = 0;
 	unsigned int size_to_map;
 	void __iomem *phys_address;
 	struct ipack_addr_space *virt_addr_space;
 	struct tpci200_board *tpci200;
 
 	tpci200 = check_slot(dev);
-	if (tpci200 == NULL) {
-		res = -EINVAL;
-		goto out;
-	}
+	if (tpci200 == NULL)
+		return -EINVAL;
 
-	if (mutex_lock_interruptible(&tpci200->mutex)) {
-		res = -ERESTARTSYS;
-		goto out;
-	}
+	if (mutex_lock_interruptible(&tpci200->mutex))
+		return -ERESTARTSYS;
 
 	switch (space) {
 	case IPACK_IO_SPACE:
 		if (dev->io_space.address != NULL) {
-			pr_err("Slot [%d:%d] IO space already mapped !\n",
-			       tpci200->number, dev->slot);
+			dev_err(&dev->dev,
+				"Slot [%d:%d] IO space already mapped !\n",
+				tpci200->number, dev->slot);
 			res = -EINVAL;
 			goto out_unlock;
 		}
@@ -875,8 +643,9 @@ static int tpci200_slot_map_space(struct ipack_device *dev,
 		break;
 	case IPACK_ID_SPACE:
 		if (dev->id_space.address != NULL) {
-			pr_err("Slot [%d:%d] ID space already mapped !\n",
-			       tpci200->number, dev->slot);
+			dev_err(&dev->dev,
+				"Slot [%d:%d] ID space already mapped !\n",
+				tpci200->number, dev->slot);
 			res = -EINVAL;
 			goto out_unlock;
 		}
@@ -887,17 +656,19 @@ static int tpci200_slot_map_space(struct ipack_device *dev,
 		break;
 	case IPACK_MEM_SPACE:
 		if (dev->mem_space.address != NULL) {
-			pr_err("Slot [%d:%d] MEM space already mapped !\n",
-			       tpci200->number, dev->slot);
+			dev_err(&dev->dev,
+				"Slot [%d:%d] MEM space already mapped !\n",
+				tpci200->number, dev->slot);
 			res = -EINVAL;
 			goto out_unlock;
 		}
 		virt_addr_space = &dev->mem_space;
 
 		if (memory_size > tpci200->slots[dev->slot].mem_phys.size) {
-			pr_err("Slot [%d:%d] request is 0x%X memory, only 0x%X available !\n",
-			       dev->bus_nr, dev->slot, memory_size,
-			       tpci200->slots[dev->slot].mem_phys.size);
+			dev_err(&dev->dev,
+				"Slot [%d:%d] request is 0x%X memory, only 0x%X available !\n",
+				dev->bus_nr, dev->slot, memory_size,
+				tpci200->slots[dev->slot].mem_phys.size);
 			res = -EINVAL;
 			goto out_unlock;
 		}
@@ -906,11 +677,10 @@ static int tpci200_slot_map_space(struct ipack_device *dev,
 		size_to_map = memory_size;
 		break;
 	default:
-		pr_err("Slot [%d:%d] space %d doesn't exist !\n",
-		       tpci200->number, dev->slot, space);
+		dev_err(&dev->dev, "Slot [%d:%d] space %d doesn't exist !\n",
+			tpci200->number, dev->slot, space);
 		res = -EINVAL;
 		goto out_unlock;
-		break;
 	}
 
 	virt_addr_space->size = size_to_map;
@@ -919,7 +689,6 @@ static int tpci200_slot_map_space(struct ipack_device *dev,
 
 out_unlock:
 	mutex_unlock(&tpci200->mutex);
-out:
 	return res;
 }
 
@@ -931,27 +700,25 @@ static int tpci200_request_irq(struct ipack_device *dev, int vector,
 	struct tpci200_board *tpci200;
 
 	tpci200 = check_slot(dev);
-	if (tpci200 == NULL) {
-		res = -EINVAL;
-		goto out;
-	}
+	if (tpci200 == NULL)
+		return -EINVAL;
 
-	if (mutex_lock_interruptible(&tpci200->mutex)) {
-		res = -ERESTARTSYS;
-		goto out;
-	}
+	if (mutex_lock_interruptible(&tpci200->mutex))
+		return -ERESTARTSYS;
 
 	if (tpci200->slots[dev->slot].irq != NULL) {
-		pr_err("Slot [%d:%d] IRQ already registered !\n", dev->bus_nr,
-		       dev->slot);
+		dev_err(&dev->dev,
+			"Slot [%d:%d] IRQ already registered !\n", dev->bus_nr,
+			dev->slot);
 		res = -EINVAL;
 		goto out_unlock;
 	}
 
 	slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL);
 	if (slot_irq == NULL) {
-		pr_err("Slot [%d:%d] unable to allocate memory for IRQ !\n",
-		       dev->bus_nr, dev->slot);
+		dev_err(&dev->dev,
+			"Slot [%d:%d] unable to allocate memory for IRQ !\n",
+			dev->bus_nr, dev->slot);
 		res = -ENOMEM;
 		goto out_unlock;
 	}
@@ -965,32 +732,21 @@ static int tpci200_request_irq(struct ipack_device *dev, int vector,
 	slot_irq->vector = vector;
 	slot_irq->handler = handler;
 	slot_irq->arg = arg;
-	slot_irq->name = dev_name(&dev->dev);
 
 	tpci200->slots[dev->slot].irq = slot_irq;
 	res = __tpci200_request_irq(tpci200, dev);
 
 out_unlock:
 	mutex_unlock(&tpci200->mutex);
-out:
 	return res;
 }
 
-static void tpci200_slot_remove(struct tpci200_slot *slot)
-{
-	if ((slot->dev == NULL) ||
-	    (slot->dev->driver->ops->remove == NULL))
-		return;
-
-	slot->dev->driver->ops->remove(slot->dev);
-}
-
 static void tpci200_uninstall(struct tpci200_board *tpci200)
 {
 	int i;
 
 	for (i = 0; i < TPCI200_NB_SLOT; i++)
-		tpci200_slot_remove(&tpci200->slots[i]);
+		tpci200_slot_unregister(tpci200->slots[i].dev);
 
 	tpci200_unregister(tpci200);
 	kfree(tpci200->slots);
@@ -1016,29 +772,24 @@ static int tpci200_install(struct tpci200_board *tpci200)
 
 	tpci200->slots = kzalloc(
 		TPCI200_NB_SLOT * sizeof(struct tpci200_slot), GFP_KERNEL);
-	if (tpci200->slots == NULL) {
-		res = -ENOMEM;
-		goto out_err;
-	}
+	if (tpci200->slots == NULL)
+		return -ENOMEM;
 
 	res = tpci200_register(tpci200);
-	if (res)
-		goto out_free;
+	if (res) {
+		kfree(tpci200->slots);
+		tpci200->slots = NULL;
+		return res;
+	}
 
 	mutex_init(&tpci200->mutex);
 	return 0;
-
-out_free:
-	kfree(tpci200->slots);
-	tpci200->slots = NULL;
-out_err:
-	return res;
 }
 
 static int tpci200_pciprobe(struct pci_dev *pdev,
 			    const struct pci_device_id *id)
 {
-	int ret;
+	int ret, i;
 	struct tpci200_board *tpci200;
 
 	tpci200 = kzalloc(sizeof(struct tpci200_board), GFP_KERNEL);
@@ -1058,7 +809,7 @@ static int tpci200_pciprobe(struct pci_dev *pdev,
 	/* register the device and initialize it */
 	ret = tpci200_install(tpci200);
 	if (ret) {
-		pr_err("Error during tpci200 install !\n");
+		dev_err(&pdev->dev, "Error during tpci200 install !\n");
 		kfree(tpci200->info);
 		kfree(tpci200);
 		return -ENODEV;
@@ -1069,7 +820,8 @@ static int tpci200_pciprobe(struct pci_dev *pdev,
 						      TPCI200_NB_SLOT,
 						      &tpci200_bus_ops);
 	if (!tpci200->info->ipack_bus) {
-		pr_err("error registering the carrier on ipack driver\n");
+		dev_err(&pdev->dev,
+			"error registering the carrier on ipack driver\n");
 		tpci200_uninstall(tpci200);
 		kfree(tpci200->info);
 		kfree(tpci200);
@@ -1081,13 +833,20 @@ static int tpci200_pciprobe(struct pci_dev *pdev,
 	dev_set_drvdata(&pdev->dev, tpci200);
 	/* add the registered device in an internal linked list */
 	list_add_tail(&tpci200->list, &tpci200_list);
+
+	/*
+	 * Give the same IRQ number as the slot number.
+	 * The TPCI200 has assigned his own two IRQ by PCI bus driver
+	 */
+	for (i = 0; i < TPCI200_NB_SLOT; i++)
+		tpci200->slots[i].dev =
+			ipack_device_register(tpci200->info->ipack_bus, i, i);
 	return ret;
 }
 
 static void __tpci200_pci_remove(struct tpci200_board *tpci200)
 {
 	tpci200_uninstall(tpci200);
-	tpci200_remove_sysfs_files(tpci200);
 	list_del(&tpci200->list);
 	ipack_bus_unregister(tpci200->info->ipack_bus);
 	kfree(tpci200->info);
@@ -1107,12 +866,14 @@ static void __devexit tpci200_pci_remove(struct pci_dev *dev)
 	}
 }
 
-static struct pci_device_id tpci200_idtable[2] = {
+static DEFINE_PCI_DEVICE_TABLE(tpci200_idtable) = {
 	{ TPCI200_VENDOR_ID, TPCI200_DEVICE_ID, TPCI200_SUBVENDOR_ID,
 	  TPCI200_SUBDEVICE_ID },
 	{ 0, },
 };
 
+MODULE_DEVICE_TABLE(pci, tpci200_idtable);
+
 static struct pci_driver tpci200_pci_drv = {
 	.name = "tpci200",
 	.id_table = tpci200_idtable,
diff --git a/drivers/staging/ipack/bridges/tpci200.h b/drivers/staging/ipack/bridges/tpci200.h
index 0b547ee..d04510a 100644
--- a/drivers/staging/ipack/bridges/tpci200.h
+++ b/drivers/staging/ipack/bridges/tpci200.h
@@ -14,7 +14,6 @@
 #ifndef _TPCI200_H_
 #define _TPCI200_H_
 
-#include <linux/version.h>
 #include <linux/limits.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
@@ -106,14 +105,12 @@
  * @vector	Vector number
  * @handler	Handler called when IRQ arrives
  * @arg		Handler argument
- * @name	IRQ name
  *
  */
 struct slot_irq {
 	int		vector;
 	int		(*handler)(void *);
 	void		*arg;
-	const char	*name;
 };
 
 /**
@@ -139,7 +136,6 @@ struct tpci200_slot {
  * @interface_regs	Pointer to IP interface space (Bar 2)
  * @ioidint_space	Pointer to IP ID, IO and INT space (Bar 3)
  * @mem8_space		Pointer to MEM space (Bar 4)
- * @access_lock		Mutex lock for simultaneous access
  *
  */
 struct tpci200_infos {
@@ -148,7 +144,6 @@ struct tpci200_infos {
 	void __iomem			*interface_regs;
 	void __iomem			*ioidint_space;
 	void __iomem			*mem8_space;
-	spinlock_t			access_lock;
 	struct ipack_bus_device		*ipack_bus;
 };
 struct tpci200_board {
diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c
index 29f6fa8..ec7b2f9 100644
--- a/drivers/staging/ipack/devices/ipoctal.c
+++ b/drivers/staging/ipack/devices/ipoctal.c
@@ -11,20 +11,14 @@
  * Software Foundation; version 2 of the License.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/device.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/tty_flip.h>
 #include <linux/slab.h>
-#include <linux/uaccess.h>
 #include <linux/atomic.h>
 #include "../ipack.h"
 #include "ipoctal.h"
@@ -48,12 +42,9 @@ struct ipoctal {
 	struct scc2698_channel		*chan_regs;
 	struct scc2698_block		*block_regs;
 	struct ipoctal_stats		chan_stats[NR_CHANNELS];
-	char				*buffer[NR_CHANNELS];
 	unsigned int			nb_bytes[NR_CHANNELS];
 	unsigned int			count_wr[NR_CHANNELS];
-	struct ipoctal_config		chan_config[NR_CHANNELS];
 	wait_queue_head_t		queue[NR_CHANNELS];
-	unsigned short			error_flag[NR_CHANNELS];
 	spinlock_t			lock[NR_CHANNELS];
 	unsigned int			pointer_read[NR_CHANNELS];
 	unsigned int			pointer_write[NR_CHANNELS];
@@ -116,7 +107,8 @@ static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
 	ipoctal = ipoctal_find_board(tty);
 
 	if (ipoctal == NULL) {
-		pr_err("Device not found. Major %d\n", tty->driver->major);
+		dev_err(tty->dev, "Device not found. Major %d\n",
+			tty->driver->major);
 		return -ENODEV;
 	}
 
@@ -136,7 +128,8 @@ static int ipoctal_open(struct tty_struct *tty, struct file *file)
 	ipoctal = ipoctal_find_board(tty);
 
 	if (ipoctal == NULL) {
-		pr_err("Device not found. Major %d\n", tty->driver->major);
+		dev_err(tty->dev, "Device not found. Major %d\n",
+			tty->driver->major);
 		return -ENODEV;
 	}
 
@@ -276,23 +269,19 @@ static int ipoctal_irq_handler(void *arg)
 						     CR_CMD_RESET_ERR_STATUS);
 
 				if (sr & SR_OVERRUN_ERROR) {
-					ipoctal->error_flag[channel] |= UART_OVERRUN;
 					ipoctal->chan_stats[channel].overrun_err++;
 					/* Overrun doesn't affect the current character*/
 					tty_insert_flip_char(tty, 0, TTY_OVERRUN);
 				}
 				if (sr & SR_PARITY_ERROR) {
-					ipoctal->error_flag[channel] |= UART_PARITY;
 					ipoctal->chan_stats[channel].parity_err++;
 					flag = TTY_PARITY;
 				}
 				if (sr & SR_FRAMING_ERROR) {
-					ipoctal->error_flag[channel] |= UART_FRAMING;
 					ipoctal->chan_stats[channel].framing_err++;
 					flag = TTY_FRAME;
 				}
 				if (sr & SR_RECEIVED_BREAK) {
-					ipoctal->error_flag[channel] |= UART_BREAK;
 					ipoctal->chan_stats[channel].rcv_break++;
 					flag = TTY_BREAK;
 				}
@@ -310,8 +299,8 @@ static int ipoctal_irq_handler(void *arg)
 				ipoctal->nb_bytes[channel] = 0;
 				continue;
 			}
-			spin_lock(&ipoctal->lock[channel]);
-			value = ipoctal->buffer[channel][*pointer_write];
+
+			value = ipoctal->tty_port[channel].xmit_buf[*pointer_write];
 			ipoctal_write_io_reg(ipoctal,
 					     &ipoctal->chan_regs[channel].u.w.thr,
 					     value);
@@ -320,7 +309,6 @@ static int ipoctal_irq_handler(void *arg)
 			(*pointer_write)++;
 			*pointer_write = *pointer_write % PAGE_SIZE;
 			ipoctal->nb_bytes[channel]--;
-			spin_unlock(&ipoctal->lock[channel]);
 
 			if ((ipoctal->nb_bytes[channel] == 0) &&
 			    (waitqueue_active(&ipoctal->queue[channel]))) {
@@ -381,7 +369,9 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
 	res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0,
 						IPACK_ID_SPACE);
 	if (res) {
-		pr_err("Unable to map slot [%d:%d] ID space!\n", bus_nr, slot);
+		dev_err(&ipoctal->dev->dev,
+			"Unable to map slot [%d:%d] ID space!\n",
+			bus_nr, slot);
 		return res;
 	}
 
@@ -396,14 +386,18 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
 	res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0,
 						IPACK_IO_SPACE);
 	if (res) {
-		pr_err("Unable to map slot [%d:%d] IO space!\n", bus_nr, slot);
+		dev_err(&ipoctal->dev->dev,
+			"Unable to map slot [%d:%d] IO space!\n",
+			bus_nr, slot);
 		goto out_unregister_id_space;
 	}
 
 	res = ipoctal->dev->bus->ops->map_space(ipoctal->dev,
 					   0x8000, IPACK_MEM_SPACE);
 	if (res) {
-		pr_err("Unable to map slot [%d:%d] MEM space!\n", bus_nr, slot);
+		dev_err(&ipoctal->dev->dev,
+			"Unable to map slot [%d:%d] MEM space!\n",
+			bus_nr, slot);
 		goto out_unregister_io_space;
 	}
 
@@ -472,7 +466,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
 	tty_set_operations(tty, &ipoctal_fops);
 	res = tty_register_driver(tty);
 	if (res) {
-		pr_err("Can't register tty driver.\n");
+		dev_err(&ipoctal->dev->dev, "Can't register tty driver.\n");
 		put_tty_driver(tty);
 		goto out_unregister_slot_unmap;
 	}
@@ -488,7 +482,6 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
 		ipoctal_reset_stats(&ipoctal->chan_stats[i]);
 		ipoctal->nb_bytes[i] = 0;
 		init_waitqueue_head(&ipoctal->queue[i]);
-		ipoctal->error_flag[i] = UART_NOERROR;
 
 		spin_lock_init(&ipoctal->lock[i]);
 		ipoctal->pointer_read[i] = 0;
@@ -547,8 +540,6 @@ static int ipoctal_write(struct ipoctal *ipoctal, unsigned int channel,
 
 	ipoctal_copy_write_buffer(ipoctal, channel, buf, count);
 
-	ipoctal->error_flag[channel] = UART_NOERROR;
-
 	/* As the IP-OCTAL 485 only supports half duplex, do it manually */
 	if (ipoctal->board_id == IP_OCTAL_485_ID) {
 		ipoctal_write_io_reg(ipoctal,
@@ -665,22 +656,18 @@ static void ipoctal_set_termios(struct tty_struct *tty,
 		if (cflag & CRTSCTS) {
 			mr1 |= MR1_RxRTS_CONTROL_ON;
 			mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_ON;
-			ipoctal->chan_config[channel].flow_control = 1;
 		} else {
 			mr1 |= MR1_RxRTS_CONTROL_OFF;
 			mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF;
-			ipoctal->chan_config[channel].flow_control = 0;
 		}
 		break;
 	case IP_OCTAL_422_ID:
 		mr1 |= MR1_RxRTS_CONTROL_OFF;
 		mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF;
-		ipoctal->chan_config[channel].flow_control = 0;
 		break;
 	case IP_OCTAL_485_ID:
 		mr1 |= MR1_RxRTS_CONTROL_OFF;
 		mr2 |= MR2_TxRTS_CONTROL_ON | MR2_CTS_ENABLE_TX_OFF;
-		ipoctal->chan_config[channel].flow_control = 0;
 		break;
 	default:
 		return;
@@ -744,12 +731,6 @@ static void ipoctal_set_termios(struct tty_struct *tty,
 	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr2);
 	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.csr, csr);
 
-	/* save the setup in the structure */
-	ipoctal->chan_config[channel].baud = tty_get_baud_rate(tty);
-	ipoctal->chan_config[channel].bits_per_char = cflag & CSIZE;
-	ipoctal->chan_config[channel].parity = cflag & PARENB;
-	ipoctal->chan_config[channel].stop_bits = cflag & CSTOPB;
-
 	/* Enable again the RX */
 	ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
 			     CR_ENABLE_RX);
@@ -853,11 +834,6 @@ static void __ipoctal_remove(struct ipoctal *ipoctal)
 
 	tty_unregister_driver(ipoctal->tty_drv);
 	put_tty_driver(ipoctal->tty_drv);
-
-	/* Tell the carrier board to free all the resources for this device */
-	if (ipoctal->dev->bus->ops->remove_device != NULL)
-		ipoctal->dev->bus->ops->remove_device(ipoctal->dev);
-
 	list_del(&ipoctal->list);
 	kfree(ipoctal);
 }
@@ -889,7 +865,7 @@ static void __exit ipoctal_exit(void)
 	struct ipoctal *p, *next;
 
 	list_for_each_entry_safe(p, next, &ipoctal_list, list)
-		__ipoctal_remove(p);
+		p->dev->bus->ops->remove_device(p->dev);
 
 	ipack_driver_unregister(&driver);
 }
diff --git a/drivers/staging/ipack/devices/ipoctal.h b/drivers/staging/ipack/devices/ipoctal.h
index 266f361..c5b4ed4 100644
--- a/drivers/staging/ipack/devices/ipoctal.h
+++ b/drivers/staging/ipack/devices/ipoctal.h
@@ -20,45 +20,6 @@
 #define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
 
 /**
- * enum uart_parity_e - UART supported parity.
- */
-enum uart_parity_e {
-	UART_NONE  = 0,
-	UART_ODD   = 1,
-	UART_EVEN  = 2,
-};
-
-/**
- * enum uart_error - UART error type
- *
- */
-enum uart_error	{
-	UART_NOERROR = 0,      /* No error during transmission */
-	UART_TIMEOUT = 1 << 0, /* Timeout error */
-	UART_OVERRUN = 1 << 1, /* Overrun error */
-	UART_PARITY  = 1 << 2, /* Parity error */
-	UART_FRAMING = 1 << 3, /* Framing error */
-	UART_BREAK   = 1 << 4, /* Received break */
-};
-
-/**
- * struct ipoctal_config - Serial configuration
- *
- * @baud: Baud rate
- * @stop_bits: Stop bits (1 or 2)
- * @bits_per_char: data size in bits
- * @parity
- * @flow_control: Flow control management (RTS/CTS) (0 disabled, 1 enabled)
- */
-struct ipoctal_config {
-	unsigned int baud;
-	unsigned int stop_bits;
-	unsigned int bits_per_char;
-	unsigned short parity;
-	unsigned int flow_control;
-};
-
-/**
  * struct ipoctal_stats -- Stats since last reset
  *
  * @tx: Number of transmitted bytes
diff --git a/drivers/staging/ipack/ipack.c b/drivers/staging/ipack/ipack.c
index 2b4fa51..c1cd97a 100644
--- a/drivers/staging/ipack/ipack.c
+++ b/drivers/staging/ipack/ipack.c
@@ -9,25 +9,15 @@
  * Software Foundation; version 2 of the License.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/module.h>
-#include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/idr.h>
 #include "ipack.h"
 
 #define to_ipack_dev(device) container_of(device, struct ipack_device, dev)
 #define to_ipack_driver(drv) container_of(drv, struct ipack_driver, driver)
 
-/* used when allocating bus numbers */
-#define IPACK_MAXBUS              64
-
-static DEFINE_MUTEX(ipack_mutex);
-
-struct ipack_busmap {
-	unsigned long busmap[IPACK_MAXBUS / (8*sizeof(unsigned long))];
-};
-static struct ipack_busmap busmap;
+static DEFINE_IDA(ipack_ida);
 
 static void ipack_device_release(struct device *dev)
 {
@@ -48,7 +38,7 @@ static int ipack_bus_match(struct device *device, struct device_driver *driver)
 	if (ret)
 		dev->driver = drv;
 
-	return 0;
+	return ret;
 }
 
 static int ipack_bus_probe(struct device *device)
@@ -79,26 +69,6 @@ static struct bus_type ipack_bus_type = {
 	.remove = ipack_bus_remove,
 };
 
-static int ipack_assign_bus_number(void)
-{
-	int busnum;
-
-	mutex_lock(&ipack_mutex);
-	busnum = find_next_zero_bit(busmap.busmap, IPACK_MAXBUS, 1);
-
-	if (busnum >= IPACK_MAXBUS) {
-		pr_err("too many buses\n");
-		busnum = -1;
-		goto error_find_busnum;
-	}
-
-	set_bit(busnum, busmap.busmap);
-
-error_find_busnum:
-	mutex_unlock(&ipack_mutex);
-	return busnum;
-}
-
 struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
 					    struct ipack_bus_ops *ops)
 {
@@ -109,7 +79,7 @@ struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
 	if (!bus)
 		return NULL;
 
-	bus_nr = ipack_assign_bus_number();
+	bus_nr = ida_simple_get(&ipack_ida, 0, 0, GFP_KERNEL);
 	if (bus_nr < 0) {
 		kfree(bus);
 		return NULL;
@@ -125,9 +95,7 @@ EXPORT_SYMBOL_GPL(ipack_bus_register);
 
 int ipack_bus_unregister(struct ipack_bus_device *bus)
 {
-	mutex_lock(&ipack_mutex);
-	clear_bit(bus->bus_nr, busmap.busmap);
-	mutex_unlock(&ipack_mutex);
+	ida_simple_remove(&ipack_ida, bus->bus_nr);
 	kfree(bus);
 	return 0;
 }
@@ -171,8 +139,6 @@ struct ipack_device *ipack_device_register(struct ipack_bus_device *bus,
 
 	ret = device_register(&dev->dev);
 	if (ret < 0) {
-		pr_err("error registering the device.\n");
-		dev->driver->ops->remove(dev);
 		kfree(dev);
 		return NULL;
 	}
@@ -189,12 +155,14 @@ EXPORT_SYMBOL_GPL(ipack_device_unregister);
 
 static int __init ipack_init(void)
 {
+	ida_init(&ipack_ida);
 	return bus_register(&ipack_bus_type);
 }
 
 static void __exit ipack_exit(void)
 {
 	bus_unregister(&ipack_bus_type);
+	ida_destroy(&ipack_ida);
 }
 
 module_init(ipack_init);
diff --git a/drivers/staging/keucr/init.c b/drivers/staging/keucr/init.c
index 071bdc2..231611d 100644
--- a/drivers/staging/keucr/init.c
+++ b/drivers/staging/keucr/init.c
@@ -30,9 +30,8 @@ int ENE_InitMedia(struct us_data *us)
 	if (MiscReg03 & 0x02) {
 		if (!us->SM_Status.Ready && !us->MS_Status.Ready) {
 			result = ENE_SMInit(us);
-			if (result != USB_STOR_XFER_GOOD) {
+			if (result != USB_STOR_XFER_GOOD)
 				return USB_STOR_TRANSPORT_ERROR;
-			}
 		}
 
 	}
diff --git a/drivers/staging/keucr/scsiglue.c b/drivers/staging/keucr/scsiglue.c
index e1f3931..083b20e 100644
--- a/drivers/staging/keucr/scsiglue.c
+++ b/drivers/staging/keucr/scsiglue.c
@@ -230,7 +230,10 @@ void usb_stor_report_bus_reset(struct us_data *us)
 /* we use this macro to help us write into the buffer */
 #undef SPRINTF
 #define SPRINTF(args...) \
-	do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
+	do { \
+		if (pos < buffer+length) \
+			pos += sprintf(pos, ## args); \
+	} while (0)
 
 /*
  * proc_info()
@@ -279,8 +282,10 @@ static int proc_info(struct Scsi_Host *host, char *buffer, char **start,
 		pos += sprintf(pos, "       Quirks:");
 
 #define US_FLAG(name, value) \
-	if (us->fflags & value)\
-		pos += sprintf(pos, " " #name);
+	do { \
+		if (us->fflags & value) \
+			pos += sprintf(pos, " " #name); \
+	} while (0);
 US_DO_ALL_FLAGS
 #undef US_FLAG
 
diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c
index 3295ea6..97ef670 100644
--- a/drivers/staging/media/lirc/lirc_serial.c
+++ b/drivers/staging/media/lirc/lirc_serial.c
@@ -129,6 +129,7 @@ static void send_space_homebrew(long length);
 
 static struct lirc_serial hardware[] = {
 	[LIRC_HOMEBREW] = {
+		.lock = __SPIN_LOCK_UNLOCKED(hardware[LIRC_HOMEBREW].lock),
 		.signal_pin        = UART_MSR_DCD,
 		.signal_pin_change = UART_MSR_DDCD,
 		.on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
@@ -145,6 +146,7 @@ static struct lirc_serial hardware[] = {
 	},
 
 	[LIRC_IRDEO] = {
+		.lock = __SPIN_LOCK_UNLOCKED(hardware[LIRC_IRDEO].lock),
 		.signal_pin        = UART_MSR_DSR,
 		.signal_pin_change = UART_MSR_DDSR,
 		.on  = UART_MCR_OUT2,
@@ -156,6 +158,7 @@ static struct lirc_serial hardware[] = {
 	},
 
 	[LIRC_IRDEO_REMOTE] = {
+		.lock = __SPIN_LOCK_UNLOCKED(hardware[LIRC_IRDEO_REMOTE].lock),
 		.signal_pin        = UART_MSR_DSR,
 		.signal_pin_change = UART_MSR_DDSR,
 		.on  = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
@@ -167,6 +170,7 @@ static struct lirc_serial hardware[] = {
 	},
 
 	[LIRC_ANIMAX] = {
+		.lock = __SPIN_LOCK_UNLOCKED(hardware[LIRC_ANIMAX].lock),
 		.signal_pin        = UART_MSR_DCD,
 		.signal_pin_change = UART_MSR_DDCD,
 		.on  = 0,
@@ -177,6 +181,7 @@ static struct lirc_serial hardware[] = {
 	},
 
 	[LIRC_IGOR] = {
+		.lock = __SPIN_LOCK_UNLOCKED(hardware[LIRC_IGOR].lock),
 		.signal_pin        = UART_MSR_DSR,
 		.signal_pin_change = UART_MSR_DDSR,
 		.on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
@@ -201,6 +206,7 @@ static struct lirc_serial hardware[] = {
 	 * See also http://www.nslu2-linux.org for this device
 	 */
 	[LIRC_NSLU2] = {
+		.lock = __SPIN_LOCK_UNLOCKED(hardware[LIRC_NSLU2].lock),
 		.signal_pin        = UART_MSR_CTS,
 		.signal_pin_change = UART_MSR_DCTS,
 		.on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
diff --git a/drivers/staging/media/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c
index 945d962..4afc3b4 100644
--- a/drivers/staging/media/lirc/lirc_sir.c
+++ b/drivers/staging/media/lirc/lirc_sir.c
@@ -52,6 +52,7 @@
 #include <linux/io.h>
 #include <asm/irq.h>
 #include <linux/fcntl.h>
+#include <linux/platform_device.h>
 #ifdef LIRC_ON_SA1100
 #include <asm/hardware.h>
 #ifdef CONFIG_SA1100_COLLIE
@@ -487,9 +488,11 @@ static struct lirc_driver driver = {
 	.owner		= THIS_MODULE,
 };
 
+static struct platform_device *lirc_sir_dev;
 
 static int init_chrdev(void)
 {
+	driver.dev = &lirc_sir_dev->dev;
 	driver.minor = lirc_register_driver(&driver);
 	if (driver.minor < 0) {
 		printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n");
@@ -1215,20 +1218,71 @@ static int init_lirc_sir(void)
 	return 0;
 }
 
+static int __devinit lirc_sir_probe(struct platform_device *dev)
+{
+	return 0;
+}
+
+static int __devexit lirc_sir_remove(struct platform_device *dev)
+{
+	return 0;
+}
+
+static struct platform_driver lirc_sir_driver = {
+	.probe		= lirc_sir_probe,
+	.remove		= __devexit_p(lirc_sir_remove),
+	.driver		= {
+		.name	= "lirc_sir",
+		.owner	= THIS_MODULE,
+	},
+};
 
 static int __init lirc_sir_init(void)
 {
 	int retval;
 
+	retval = platform_driver_register(&lirc_sir_driver);
+	if (retval) {
+		printk(KERN_ERR LIRC_DRIVER_NAME ": Platform driver register "
+		       "failed!\n");
+		return -ENODEV;
+	}
+
+	lirc_sir_dev = platform_device_alloc("lirc_dev", 0);
+	if (!lirc_sir_dev) {
+		printk(KERN_ERR LIRC_DRIVER_NAME ": Platform device alloc "
+		       "failed!\n");
+		retval = -ENOMEM;
+		goto pdev_alloc_fail;
+	}
+
+	retval = platform_device_add(lirc_sir_dev);
+	if (retval) {
+		printk(KERN_ERR LIRC_DRIVER_NAME ": Platform device add "
+		       "failed!\n");
+		retval = -ENODEV;
+		goto pdev_add_fail;
+	}
+
 	retval = init_chrdev();
 	if (retval < 0)
-		return retval;
+		goto fail;
+
 	retval = init_lirc_sir();
 	if (retval) {
 		drop_chrdev();
-		return retval;
+		goto fail;
 	}
+
 	return 0;
+
+fail:
+	platform_device_del(lirc_sir_dev);
+pdev_add_fail:
+	platform_device_put(lirc_sir_dev);
+pdev_alloc_fail:
+	platform_driver_unregister(&lirc_sir_driver);
+	return retval;
 }
 
 static void __exit lirc_sir_exit(void)
@@ -1236,6 +1290,8 @@ static void __exit lirc_sir_exit(void)
 	drop_hardware();
 	drop_chrdev();
 	drop_port();
+	platform_device_unregister(lirc_sir_dev);
+	platform_driver_unregister(&lirc_sir_driver);
 	printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
 }
 
diff --git a/drivers/staging/media/solo6x10/i2c.c b/drivers/staging/media/solo6x10/i2c.c
index ef95a50..398070a 100644
--- a/drivers/staging/media/solo6x10/i2c.c
+++ b/drivers/staging/media/solo6x10/i2c.c
@@ -175,7 +175,7 @@ int solo_i2c_isr(struct solo_dev *solo_dev)
 
 	solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC);
 
-	if (status & (SOLO_IIC_STATE_TRNS & SOLO_IIC_STATE_SIG_ERR) ||
+	if (status & (SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR) ||
 	    solo_dev->i2c_id < 0) {
 		solo_i2c_stop(solo_dev);
 		return -ENXIO;
diff --git a/drivers/staging/nvec/Kconfig b/drivers/staging/nvec/Kconfig
index 731301f..43048e9 100644
--- a/drivers/staging/nvec/Kconfig
+++ b/drivers/staging/nvec/Kconfig
@@ -26,8 +26,9 @@ config NVEC_POWER
 	  Say Y to enable support for battery and charger interface for
 	  nVidia compliant embedded controllers.
 
-config NVEC_LEDS
-	bool "NVEC leds"
-	depends on MFD_NVEC && LEDS_CLASS
+config NVEC_PAZ00
+	bool "Support for OEM specific functions on Compal PAZ00 based devices"
+	depends on MFD_NVEC && LEDS_CLASS && MACH_PAZ00
 	help
-	  Say Y to enable yellow side leds on AC100 or other nVidia tegra nvec leds
+	  Say Y to enable control of the yellow side leds on Compal PAZ00 based
+	  devices, e.g. Toshbia AC100 and Dynabooks AZ netbooks.
diff --git a/drivers/staging/nvec/Makefile b/drivers/staging/nvec/Makefile
index b844d60..0db0e1f 100644
--- a/drivers/staging/nvec/Makefile
+++ b/drivers/staging/nvec/Makefile
@@ -2,4 +2,4 @@ obj-$(CONFIG_SERIO_NVEC_PS2)	+= nvec_ps2.o
 obj-$(CONFIG_MFD_NVEC)		+= nvec.o
 obj-$(CONFIG_NVEC_POWER) 	+= nvec_power.o
 obj-$(CONFIG_KEYBOARD_NVEC) 	+= nvec_kbd.o
-obj-$(CONFIG_NVEC_LEDS) 	+= nvec_leds.o
+obj-$(CONFIG_NVEC_PAZ00) 	+= nvec_paz00.o
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 3c60088..695ea35 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -97,7 +97,7 @@ static struct mfd_cell nvec_devices[] = {
 		.id = 2,
 	},
 	{
-		.name = "nvec-leds",
+		.name = "nvec-paz00",
 		.id = 1,
 	},
 };
@@ -127,12 +127,14 @@ EXPORT_SYMBOL_GPL(nvec_register_notifier);
 static int nvec_status_notifier(struct notifier_block *nb,
 				unsigned long event_type, void *data)
 {
+	struct nvec_chip *nvec = container_of(nb, struct nvec_chip,
+						nvec_status_notifier);
 	unsigned char *msg = (unsigned char *)data;
 
 	if (event_type != NVEC_CNTL)
 		return NOTIFY_DONE;
 
-	printk(KERN_WARNING "unhandled msg type %ld\n", event_type);
+	dev_warn(nvec->dev, "unhandled msg type %ld\n", event_type);
 	print_hex_dump(KERN_WARNING, "payload: ", DUMP_PREFIX_NONE, 16, 1,
 		msg, msg[1] + 2, true);
 
@@ -675,7 +677,7 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec)
 {
 	u32 val;
 
-	clk_enable(nvec->i2c_clk);
+	clk_prepare_enable(nvec->i2c_clk);
 
 	tegra_periph_reset_assert(nvec->i2c_clk);
 	udelay(2);
@@ -695,15 +697,17 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec)
 
 	enable_irq(nvec->irq);
 
-	clk_disable(nvec->i2c_clk);
+	clk_disable_unprepare(nvec->i2c_clk);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static void nvec_disable_i2c_slave(struct nvec_chip *nvec)
 {
 	disable_irq(nvec->irq);
 	writel(I2C_SL_NEWSL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG);
-	clk_disable(nvec->i2c_clk);
+	clk_disable_unprepare(nvec->i2c_clk);
 }
+#endif
 
 static void nvec_power_off(void)
 {
@@ -719,10 +723,9 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
 	struct nvec_chip *nvec;
 	struct nvec_msg *msg;
 	struct resource *res;
-	struct resource *iomem;
 	void __iomem *base;
 
-	nvec = kzalloc(sizeof(struct nvec_chip), GFP_KERNEL);
+	nvec = devm_kzalloc(&pdev->dev, sizeof(struct nvec_chip), GFP_KERNEL);
 	if (nvec == NULL) {
 		dev_err(&pdev->dev, "failed to reserve memory\n");
 		return -ENOMEM;
@@ -737,15 +740,15 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
 		nvec->gpio = of_get_named_gpio(nvec->dev->of_node, "request-gpios", 0);
 		if (nvec->gpio < 0) {
 			dev_err(&pdev->dev, "no gpio specified");
-			goto failed;
+			return -ENODEV;
 		}
 		if (of_property_read_u32(nvec->dev->of_node, "slave-addr", &nvec->i2c_addr)) {
 			dev_err(&pdev->dev, "no i2c address specified");
-			goto failed;
+			return -ENODEV;
 		}
 	} else {
 		dev_err(&pdev->dev, "no platform data\n");
-		goto failed;
+		return -ENODEV;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -754,13 +757,7 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	iomem = request_mem_region(res->start, resource_size(res), pdev->name);
-	if (!iomem) {
-		dev_err(&pdev->dev, "I2C region already claimed\n");
-		return -EBUSY;
-	}
-
-	base = ioremap(iomem->start, resource_size(iomem));
+	base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!base) {
 		dev_err(&pdev->dev, "Can't ioremap I2C region\n");
 		return -ENOMEM;
@@ -769,14 +766,13 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "no irq resource?\n");
-		ret = -ENODEV;
-		goto err_iounmap;
+		return -ENODEV;
 	}
 
 	i2c_clk = clk_get_sys("tegra-i2c.2", NULL);
 	if (IS_ERR(i2c_clk)) {
 		dev_err(nvec->dev, "failed to get controller clock\n");
-		goto err_iounmap;
+		return -ENODEV;
 	}
 
 	nvec->base = base;
@@ -797,22 +793,26 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
 	INIT_WORK(&nvec->tx_work, nvec_request_master);
 	nvec->wq = alloc_workqueue("nvec", WQ_NON_REENTRANT, 2);
 
-	err = gpio_request_one(nvec->gpio, GPIOF_OUT_INIT_HIGH, "nvec gpio");
+	err = devm_gpio_request_one(&pdev->dev, nvec->gpio, GPIOF_OUT_INIT_HIGH,
+					"nvec gpio");
 	if (err < 0) {
 		dev_err(nvec->dev, "couldn't request gpio\n");
-		goto failed;
+		destroy_workqueue(nvec->wq);
+		return -ENODEV;
 	}
 
-	err = request_irq(nvec->irq, nvec_interrupt, 0, "nvec", nvec);
+	err = devm_request_irq(&pdev->dev, nvec->irq, nvec_interrupt, 0,
+				"nvec", nvec);
 	if (err) {
 		dev_err(nvec->dev, "couldn't request irq\n");
-		goto failed;
+		destroy_workqueue(nvec->wq);
+		return -ENODEV;
 	}
 	disable_irq(nvec->irq);
 
 	tegra_init_i2c_slave(nvec);
 
-	clk_enable(i2c_clk);
+	clk_prepare_enable(i2c_clk);
 
 
 	/* enable event reporting */
@@ -851,12 +851,6 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
 	nvec_write_async(nvec, "\x01\x01\x01\x00\x00\x80\x00", 7);
 
 	return 0;
-
-err_iounmap:
-	iounmap(base);
-failed:
-	kfree(nvec);
-	return -ENOMEM;
 }
 
 static int __devexit tegra_nvec_remove(struct platform_device *pdev)
@@ -865,19 +859,15 @@ static int __devexit tegra_nvec_remove(struct platform_device *pdev)
 
 	nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3);
 	mfd_remove_devices(nvec->dev);
-	free_irq(nvec->irq, &nvec_interrupt);
-	iounmap(nvec->base);
-	gpio_free(nvec->gpio);
 	destroy_workqueue(nvec->wq);
-	kfree(nvec);
 
 	return 0;
 }
 
-#ifdef CONFIG_PM
-
-static int tegra_nvec_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int nvec_suspend(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	struct nvec_chip *nvec = platform_get_drvdata(pdev);
 	struct nvec_msg *msg;
 
@@ -894,8 +884,9 @@ static int tegra_nvec_suspend(struct platform_device *pdev, pm_message_t state)
 	return 0;
 }
 
-static int tegra_nvec_resume(struct platform_device *pdev)
+static int nvec_resume(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	struct nvec_chip *nvec = platform_get_drvdata(pdev);
 
 	dev_dbg(nvec->dev, "resuming\n");
@@ -904,12 +895,10 @@ static int tegra_nvec_resume(struct platform_device *pdev)
 
 	return 0;
 }
-
-#else
-#define tegra_nvec_suspend NULL
-#define tegra_nvec_resume NULL
 #endif
 
+static const SIMPLE_DEV_PM_OPS(nvec_pm_ops, nvec_suspend, nvec_resume);
+
 /* Match table for of_platform binding */
 static const struct of_device_id nvidia_nvec_of_match[] __devinitconst = {
 	{ .compatible = "nvidia,nvec", },
@@ -920,21 +909,15 @@ MODULE_DEVICE_TABLE(of, nvidia_nvec_of_match);
 static struct platform_driver nvec_device_driver = {
 	.probe   = tegra_nvec_probe,
 	.remove  = __devexit_p(tegra_nvec_remove),
-	.suspend = tegra_nvec_suspend,
-	.resume  = tegra_nvec_resume,
 	.driver  = {
 		.name = "nvec",
 		.owner = THIS_MODULE,
+		.pm = &nvec_pm_ops,
 		.of_match_table = nvidia_nvec_of_match,
 	}
 };
 
-static int __init tegra_nvec_init(void)
-{
-	return platform_driver_register(&nvec_device_driver);
-}
-
-module_init(tegra_nvec_init);
+module_platform_driver(nvec_device_driver);
 
 MODULE_ALIAS("platform:nvec");
 MODULE_DESCRIPTION("NVIDIA compliant embedded controller interface");
diff --git a/drivers/staging/nvec/nvec_kbd.c b/drivers/staging/nvec/nvec_kbd.c
index a4ce5a7..6cc30dc 100644
--- a/drivers/staging/nvec/nvec_kbd.c
+++ b/drivers/staging/nvec/nvec_kbd.c
@@ -159,20 +159,24 @@ fail:
 	return err;
 }
 
+static int __devexit nvec_kbd_remove(struct platform_device *pdev)
+{
+	input_unregister_device(keys_dev.input);
+	input_free_device(keys_dev.input);
+
+	return 0;
+}
+
 static struct platform_driver nvec_kbd_driver = {
 	.probe  = nvec_kbd_probe,
+	.remove = __devexit_p(nvec_kbd_remove),
 	.driver = {
 		.name = "nvec-kbd",
 		.owner = THIS_MODULE,
 	},
 };
 
-static int __init nvec_kbd_init(void)
-{
-	return platform_driver_register(&nvec_kbd_driver);
-}
-
-module_init(nvec_kbd_init);
+module_platform_driver(nvec_kbd_driver);
 
 MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
 MODULE_DESCRIPTION("NVEC keyboard driver");
diff --git a/drivers/staging/nvec/nvec_leds.c b/drivers/staging/nvec/nvec_leds.c
deleted file mode 100644
index f4cbcd6..0000000
--- a/drivers/staging/nvec/nvec_leds.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * nvec_leds: LED driver for a NVIDIA compliant embedded controller
- *
- * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.launchpad.net>
- *
- * Authors:  Ilya Petrov <ilya.muromec@gmail.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/leds.h>
-#include <linux/platform_device.h>
-#include "nvec.h"
-
-#define to_nvec_led(led_cdev) \
-	container_of(led_cdev, struct nvec_led, cdev)
-
-#define NVEC_LED_REQ {'\x0d', '\x10', '\x45', '\x10', '\x00'}
-
-#define NVEC_LED_MAX 8
-
-struct nvec_led {
-	struct led_classdev cdev;
-	struct nvec_chip *nvec;
-};
-
-static void nvec_led_brightness_set(struct led_classdev *led_cdev,
-				    enum led_brightness value)
-{
-	struct nvec_led *led = to_nvec_led(led_cdev);
-	unsigned char buf[] = NVEC_LED_REQ;
-	buf[4] = value;
-
-	nvec_write_async(led->nvec, buf, sizeof(buf));
-
-	led->cdev.brightness = value;
-
-}
-
-static int __devinit nvec_led_probe(struct platform_device *pdev)
-{
-	struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
-	struct nvec_led *led;
-	int ret = 0;
-
-	led = kzalloc(sizeof(*led), GFP_KERNEL);
-	if (led == NULL)
-		return -ENOMEM;
-
-	led->cdev.max_brightness = NVEC_LED_MAX;
-
-	led->cdev.brightness_set = nvec_led_brightness_set;
-	led->cdev.name = "nvec-led";
-	led->cdev.flags |= LED_CORE_SUSPENDRESUME;
-	led->nvec = nvec;
-
-	platform_set_drvdata(pdev, led);
-
-	ret = led_classdev_register(&pdev->dev, &led->cdev);
-	if (ret < 0)
-		goto err_led;
-
-	/* to expose the default value to userspace */
-	led->cdev.brightness = 0;
-
-	return 0;
-
-err_led:
-	kfree(led);
-	return ret;
-}
-
-static int __devexit nvec_led_remove(struct platform_device *pdev)
-{
-	struct nvec_led *led = platform_get_drvdata(pdev);
-
-	led_classdev_unregister(&led->cdev);
-	kfree(led);
-	return 0;
-}
-
-static struct platform_driver nvec_led_driver = {
-	.probe  = nvec_led_probe,
-	.remove = __devexit_p(nvec_led_remove),
-	.driver = {
-		   .name  = "nvec-leds",
-		   .owner = THIS_MODULE,
-	},
-};
-
-static int __init nvec_led_init(void)
-{
-	return platform_driver_register(&nvec_led_driver);
-}
-
-module_init(nvec_led_init);
-
-static void __exit nvec_led_exit(void)
-{
-	platform_driver_unregister(&nvec_led_driver);
-}
-
-module_exit(nvec_led_exit);
-
-MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>");
-MODULE_DESCRIPTION("Tegra NVEC LED driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:nvec-leds");
diff --git a/drivers/staging/nvec/nvec_paz00.c b/drivers/staging/nvec/nvec_paz00.c
new file mode 100644
index 0000000..b747e39
--- /dev/null
+++ b/drivers/staging/nvec/nvec_paz00.c
@@ -0,0 +1,98 @@
+/*
+ * nvec_paz00: OEM specific driver for Compal PAZ00 based devices
+ *
+ * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.launchpad.net>
+ *
+ * Authors:  Ilya Petrov <ilya.muromec@gmail.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include "nvec.h"
+
+#define to_nvec_led(led_cdev) \
+	container_of(led_cdev, struct nvec_led, cdev)
+
+#define NVEC_LED_REQ {'\x0d', '\x10', '\x45', '\x10', '\x00'}
+
+#define NVEC_LED_MAX 8
+
+struct nvec_led {
+	struct led_classdev cdev;
+	struct nvec_chip *nvec;
+};
+
+static void nvec_led_brightness_set(struct led_classdev *led_cdev,
+				    enum led_brightness value)
+{
+	struct nvec_led *led = to_nvec_led(led_cdev);
+	unsigned char buf[] = NVEC_LED_REQ;
+	buf[4] = value;
+
+	nvec_write_async(led->nvec, buf, sizeof(buf));
+
+	led->cdev.brightness = value;
+
+}
+
+static int __devinit nvec_paz00_probe(struct platform_device *pdev)
+{
+	struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
+	struct nvec_led *led;
+	int ret = 0;
+
+	led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
+	if (led == NULL)
+		return -ENOMEM;
+
+	led->cdev.max_brightness = NVEC_LED_MAX;
+
+	led->cdev.brightness_set = nvec_led_brightness_set;
+	led->cdev.name = "paz00-led";
+	led->cdev.flags |= LED_CORE_SUSPENDRESUME;
+	led->nvec = nvec;
+
+	platform_set_drvdata(pdev, led);
+
+	ret = led_classdev_register(&pdev->dev, &led->cdev);
+	if (ret < 0)
+		return ret;
+
+	/* to expose the default value to userspace */
+	led->cdev.brightness = 0;
+
+	return 0;
+}
+
+static int __devexit nvec_paz00_remove(struct platform_device *pdev)
+{
+	struct nvec_led *led = platform_get_drvdata(pdev);
+
+	led_classdev_unregister(&led->cdev);
+
+	return 0;
+}
+
+static struct platform_driver nvec_paz00_driver = {
+	.probe  = nvec_paz00_probe,
+	.remove = __devexit_p(nvec_paz00_remove),
+	.driver = {
+		.name  = "nvec-paz00",
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(nvec_paz00_driver);
+
+MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>");
+MODULE_DESCRIPTION("Tegra NVEC PAZ00 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nvec-paz00");
diff --git a/drivers/staging/nvec/nvec_power.c b/drivers/staging/nvec/nvec_power.c
index dfa966f..cc8ccd7 100644
--- a/drivers/staging/nvec/nvec_power.c
+++ b/drivers/staging/nvec/nvec_power.c
@@ -371,10 +371,13 @@ static void nvec_power_poll(struct work_struct *work)
 static int __devinit nvec_power_probe(struct platform_device *pdev)
 {
 	struct power_supply *psy;
-	struct nvec_power *power =
-	    kzalloc(sizeof(struct nvec_power), GFP_NOWAIT);
+	struct nvec_power *power;
 	struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
 
+	power = devm_kzalloc(&pdev->dev, sizeof(struct nvec_power), GFP_NOWAIT);
+	if (power == NULL)
+		return -ENOMEM;
+
 	dev_set_drvdata(&pdev->dev, power);
 	power->nvec = nvec;
 
@@ -393,7 +396,6 @@ static int __devinit nvec_power_probe(struct platform_device *pdev)
 		power->notifier.notifier_call = nvec_power_bat_notifier;
 		break;
 	default:
-		kfree(power);
 		return -ENODEV;
 	}
 
@@ -405,20 +407,32 @@ static int __devinit nvec_power_probe(struct platform_device *pdev)
 	return power_supply_register(&pdev->dev, psy);
 }
 
+static int __devexit nvec_power_remove(struct platform_device *pdev)
+{
+	struct nvec_power *power = platform_get_drvdata(pdev);
+
+	cancel_delayed_work_sync(&power->poller);
+	switch (pdev->id) {
+	case AC:
+		power_supply_unregister(&nvec_psy);
+		break;
+	case BAT:
+		power_supply_unregister(&nvec_bat_psy);
+	}
+
+	return 0;
+}
+
 static struct platform_driver nvec_power_driver = {
 	.probe = nvec_power_probe,
+	.remove = __devexit_p(nvec_power_remove),
 	.driver = {
 		   .name = "nvec-power",
 		   .owner = THIS_MODULE,
 		   }
 };
 
-static int __init nvec_power_init(void)
-{
-	return platform_driver_register(&nvec_power_driver);
-}
-
-module_init(nvec_power_init);
+module_platform_driver(nvec_power_driver);
 
 MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/nvec/nvec_ps2.c b/drivers/staging/nvec/nvec_ps2.c
index 14a6f68..d7c6511 100644
--- a/drivers/staging/nvec/nvec_ps2.c
+++ b/drivers/staging/nvec/nvec_ps2.c
@@ -96,7 +96,11 @@ static int nvec_ps2_notifier(struct notifier_block *nb,
 static int __devinit nvec_mouse_probe(struct platform_device *pdev)
 {
 	struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
-	struct serio *ser_dev = kzalloc(sizeof(struct serio), GFP_KERNEL);
+	struct serio *ser_dev;
+
+	ser_dev = devm_kzalloc(&pdev->dev, sizeof(struct serio), GFP_KERNEL);
+	if (ser_dev == NULL)
+		return -ENOMEM;
 
 	ser_dev->id.type = SERIO_PS_PSTHRU;
 	ser_dev->write = ps2_sendcommand;
@@ -119,8 +123,17 @@ static int __devinit nvec_mouse_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int nvec_mouse_suspend(struct platform_device *pdev, pm_message_t state)
+static int __devexit nvec_mouse_remove(struct platform_device *pdev)
+{
+	serio_unregister_port(ps2_dev.ser_dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int nvec_mouse_suspend(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
 
 	/* disable mouse */
@@ -132,8 +145,9 @@ static int nvec_mouse_suspend(struct platform_device *pdev, pm_message_t state)
 	return 0;
 }
 
-static int nvec_mouse_resume(struct platform_device *pdev)
+static int nvec_mouse_resume(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
 
 	ps2_startstreaming(ps2_dev.ser_dev);
@@ -143,23 +157,22 @@ static int nvec_mouse_resume(struct platform_device *pdev)
 
 	return 0;
 }
+#endif
+
+static const SIMPLE_DEV_PM_OPS(nvec_mouse_pm_ops, nvec_mouse_suspend,
+				nvec_mouse_resume);
 
 static struct platform_driver nvec_mouse_driver = {
 	.probe  = nvec_mouse_probe,
-	.suspend = nvec_mouse_suspend,
-	.resume = nvec_mouse_resume,
+	.remove = __devexit_p(nvec_mouse_remove),
 	.driver = {
 		.name = "nvec-mouse",
 		.owner = THIS_MODULE,
+		.pm = &nvec_mouse_pm_ops,
 	},
 };
 
-static int __init nvec_mouse_init(void)
-{
-	return platform_driver_register(&nvec_mouse_driver);
-}
-
-module_init(nvec_mouse_init);
+module_platform_driver(nvec_mouse_driver);
 
 MODULE_DESCRIPTION("NVEC mouse driver");
 MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
diff --git a/drivers/staging/omapdrm/omap_dmm_priv.h b/drivers/staging/omapdrm/omap_dmm_priv.h
index 2f529ab..08b22e9 100644
--- a/drivers/staging/omapdrm/omap_dmm_priv.h
+++ b/drivers/staging/omapdrm/omap_dmm_priv.h
@@ -181,7 +181,6 @@ struct dmm {
 
 	/* allocation list and lock */
 	struct list_head alloc_head;
-	spinlock_t list_lock;
 };
 
 #endif
diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.c b/drivers/staging/omapdrm/omap_dmm_tiler.c
index 9d83060..8619783 100644
--- a/drivers/staging/omapdrm/omap_dmm_tiler.c
+++ b/drivers/staging/omapdrm/omap_dmm_tiler.c
@@ -40,6 +40,9 @@
 static struct tcm *containers[TILFMT_NFORMATS];
 static struct dmm *omap_dmm;
 
+/* global spinlock for protecting lists */
+static DEFINE_SPINLOCK(list_lock);
+
 /* Geometry table */
 #define GEOM(xshift, yshift, bytes_per_pixel) { \
 		.x_shft = (xshift), \
@@ -147,13 +150,13 @@ static struct dmm_txn *dmm_txn_init(struct dmm *dmm, struct tcm *tcm)
 	down(&dmm->engine_sem);
 
 	/* grab an idle engine */
-	spin_lock(&dmm->list_lock);
+	spin_lock(&list_lock);
 	if (!list_empty(&dmm->idle_head)) {
 		engine = list_entry(dmm->idle_head.next, struct refill_engine,
 					idle_node);
 		list_del(&engine->idle_node);
 	}
-	spin_unlock(&dmm->list_lock);
+	spin_unlock(&list_lock);
 
 	BUG_ON(!engine);
 
@@ -256,9 +259,9 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait)
 	}
 
 cleanup:
-	spin_lock(&dmm->list_lock);
+	spin_lock(&list_lock);
 	list_add(&engine->idle_node, &dmm->idle_head);
-	spin_unlock(&dmm->list_lock);
+	spin_unlock(&list_lock);
 
 	up(&omap_dmm->engine_sem);
 	return ret;
@@ -351,9 +354,9 @@ struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w,
 	}
 
 	/* add to allocation list */
-	spin_lock(&omap_dmm->list_lock);
+	spin_lock(&list_lock);
 	list_add(&block->alloc_node, &omap_dmm->alloc_head);
-	spin_unlock(&omap_dmm->list_lock);
+	spin_unlock(&list_lock);
 
 	return block;
 }
@@ -374,9 +377,9 @@ struct tiler_block *tiler_reserve_1d(size_t size)
 		return ERR_PTR(-ENOMEM);
 	}
 
-	spin_lock(&omap_dmm->list_lock);
+	spin_lock(&list_lock);
 	list_add(&block->alloc_node, &omap_dmm->alloc_head);
-	spin_unlock(&omap_dmm->list_lock);
+	spin_unlock(&list_lock);
 
 	return block;
 }
@@ -389,9 +392,9 @@ int tiler_release(struct tiler_block *block)
 	if (block->area.tcm)
 		dev_err(omap_dmm->dev, "failed to release block\n");
 
-	spin_lock(&omap_dmm->list_lock);
+	spin_lock(&list_lock);
 	list_del(&block->alloc_node);
-	spin_unlock(&omap_dmm->list_lock);
+	spin_unlock(&list_lock);
 
 	kfree(block);
 	return ret;
@@ -479,13 +482,13 @@ static int omap_dmm_remove(struct platform_device *dev)
 
 	if (omap_dmm) {
 		/* free all area regions */
-		spin_lock(&omap_dmm->list_lock);
+		spin_lock(&list_lock);
 		list_for_each_entry_safe(block, _block, &omap_dmm->alloc_head,
 					alloc_node) {
 			list_del(&block->alloc_node);
 			kfree(block);
 		}
-		spin_unlock(&omap_dmm->list_lock);
+		spin_unlock(&list_lock);
 
 		for (i = 0; i < omap_dmm->num_lut; i++)
 			if (omap_dmm->tcm && omap_dmm->tcm[i])
@@ -503,7 +506,7 @@ static int omap_dmm_remove(struct platform_device *dev)
 
 		vfree(omap_dmm->lut);
 
-		if (omap_dmm->irq != -1)
+		if (omap_dmm->irq > 0)
 			free_irq(omap_dmm->irq, omap_dmm);
 
 		iounmap(omap_dmm->base);
@@ -527,6 +530,10 @@ static int omap_dmm_probe(struct platform_device *dev)
 		goto fail;
 	}
 
+	/* initialize lists */
+	INIT_LIST_HEAD(&omap_dmm->alloc_head);
+	INIT_LIST_HEAD(&omap_dmm->idle_head);
+
 	/* lookup hwmod data - base address and irq */
 	mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	if (!mem) {
@@ -629,7 +636,6 @@ static int omap_dmm_probe(struct platform_device *dev)
 	}
 
 	sema_init(&omap_dmm->engine_sem, omap_dmm->num_engines);
-	INIT_LIST_HEAD(&omap_dmm->idle_head);
 	for (i = 0; i < omap_dmm->num_engines; i++) {
 		omap_dmm->engines[i].id = i;
 		omap_dmm->engines[i].dmm = omap_dmm;
@@ -672,9 +678,6 @@ static int omap_dmm_probe(struct platform_device *dev)
 	containers[TILFMT_32BIT] = omap_dmm->tcm[0];
 	containers[TILFMT_PAGE] = omap_dmm->tcm[0];
 
-	INIT_LIST_HEAD(&omap_dmm->alloc_head);
-	spin_lock_init(&omap_dmm->list_lock);
-
 	area = (struct tcm_area) {
 		.is2d = true,
 		.tcm = NULL,
@@ -697,7 +700,8 @@ static int omap_dmm_probe(struct platform_device *dev)
 	return 0;
 
 fail:
-	omap_dmm_remove(dev);
+	if (omap_dmm_remove(dev))
+		dev_err(&dev->dev, "cleanup failed\n");
 	return ret;
 }
 
@@ -810,7 +814,7 @@ int tiler_map_show(struct seq_file *s, void *arg)
 		map[i] = global_map + i * (w_adj + 1);
 		map[i][w_adj] = 0;
 	}
-	spin_lock_irqsave(&omap_dmm->list_lock, flags);
+	spin_lock_irqsave(&list_lock, flags);
 
 	list_for_each_entry(block, &omap_dmm->alloc_head, alloc_node) {
 		if (block->fmt != TILFMT_PAGE) {
@@ -836,7 +840,7 @@ int tiler_map_show(struct seq_file *s, void *arg)
 		}
 	}
 
-	spin_unlock_irqrestore(&omap_dmm->list_lock, flags);
+	spin_unlock_irqrestore(&list_lock, flags);
 
 	if (s) {
 		seq_printf(s, "BEGIN DMM TILER MAP\n");
diff --git a/drivers/staging/ozwpan/TODO b/drivers/staging/ozwpan/TODO
index c2d30a7..b5db245 100644
--- a/drivers/staging/ozwpan/TODO
+++ b/drivers/staging/ozwpan/TODO
@@ -1,10 +1,11 @@
 TODO:
-	- review user mode interface and determine if ioctls can be replaced
-	  with something better. correctly export data structures to user mode
-	  if ioctls are still required and allocate ioctl numbers from
-	  ioctl-number.txt.
+	- Convert event tracing code to in-kernel tracing infrastructure
+	- Check for remaining ioctl & check if that can be converted into
+	  sysfs entries
+	- Convert debug prints to appropriate dev_debug or something better
+	- Modify Kconfig to add CONFIG option for enabling/disabling event
+	  tracing.
 	- check USB HCD implementation is complete and correct.
-	- remove any debug and trace code.
 	- code review by USB developer community.
 	- testing with as many devices as possible.
 
diff --git a/drivers/staging/ozwpan/ozappif.h b/drivers/staging/ozwpan/ozappif.h
index 1b59b07..449a6ba 100644
--- a/drivers/staging/ozwpan/ozappif.h
+++ b/drivers/staging/ozwpan/ozappif.h
@@ -30,9 +30,9 @@ struct oz_binding_info {
 #define OZ_IOCTL_GET_PD_LIST	_IOR(OZ_IOCTL_MAGIC, 0, struct oz_pd_list)
 #define OZ_IOCTL_SET_ACTIVE_PD	_IOW(OZ_IOCTL_MAGIC, 1, struct oz_mac_addr)
 #define OZ_IOCTL_GET_ACTIVE_PD	_IOR(OZ_IOCTL_MAGIC, 2, struct oz_mac_addr)
-#define OZ_IOCTL_ADD_BINDING	_IOW(OZ_IOCTL_MAGIC, 5, struct oz_binding_info)
-#define OZ_IOCTL_REMOVE_BINDING	_IOW(OZ_IOCTL_MAGIC, 8, struct oz_binding_info)
-#define OZ_IOCTL_MAX		9
+#define OZ_IOCTL_ADD_BINDING	_IOW(OZ_IOCTL_MAGIC, 3, struct oz_binding_info)
+#define OZ_IOCTL_REMOVE_BINDING	_IOW(OZ_IOCTL_MAGIC, 4, struct oz_binding_info)
+#define OZ_IOCTL_MAX		5
 
 
 #endif /* _OZAPPIF_H */
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index 27325f7..d983219 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -42,6 +42,7 @@ struct oz_serial_ctx {
 /*------------------------------------------------------------------------------
  */
 static struct oz_cdev g_cdev;
+struct class *g_oz_class;
 /*------------------------------------------------------------------------------
  * Context: process and softirq
  */
@@ -330,10 +331,11 @@ const struct file_operations oz_fops = {
 int oz_cdev_register(void)
 {
 	int err;
+	struct device *dev;
 	memset(&g_cdev, 0, sizeof(g_cdev));
 	err = alloc_chrdev_region(&g_cdev.devnum, 0, 1, "ozwpan");
 	if (err < 0)
-		return err;
+		goto out3;
 	oz_trace("Alloc dev number %d:%d\n", MAJOR(g_cdev.devnum),
 			MINOR(g_cdev.devnum));
 	cdev_init(&g_cdev.cdev, &oz_fops);
@@ -342,7 +344,27 @@ int oz_cdev_register(void)
 	spin_lock_init(&g_cdev.lock);
 	init_waitqueue_head(&g_cdev.rdq);
 	err = cdev_add(&g_cdev.cdev, g_cdev.devnum, 1);
+	if (err < 0) {
+		oz_trace("Failed to add cdev\n");
+		goto out2;
+	}
+	g_oz_class = class_create(THIS_MODULE, "ozmo_wpan");
+	if (IS_ERR(g_oz_class)) {
+		oz_trace("Failed to register ozmo_wpan class\n");
+		goto out1;
+	}
+	dev = device_create(g_oz_class, NULL, g_cdev.devnum, NULL, "ozwpan");
+	if (IS_ERR(dev)) {
+		oz_trace("Failed to create sysfs entry for cdev\n");
+		goto out1;
+	}
 	return 0;
+out1:
+	cdev_del(&g_cdev.cdev);
+out2:
+	unregister_chrdev_region(g_cdev.devnum, 1);
+out3:
+	return err;
 }
 /*------------------------------------------------------------------------------
  * Context: process
@@ -351,6 +373,10 @@ int oz_cdev_deregister(void)
 {
 	cdev_del(&g_cdev.cdev);
 	unregister_chrdev_region(g_cdev.devnum, 1);
+	if (g_oz_class) {
+		device_destroy(g_oz_class, g_cdev.devnum);
+		class_destroy(g_oz_class);
+	}
 	return 0;
 }
 /*------------------------------------------------------------------------------
diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c
index 7579645..c1ed6b2 100644
--- a/drivers/staging/ozwpan/ozmain.c
+++ b/drivers/staging/ozwpan/ozmain.c
@@ -59,6 +59,6 @@ module_exit(ozwpan_exit);
 
 MODULE_AUTHOR("Chris Kelly");
 MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver");
-MODULE_VERSION("1.0.9");
+MODULE_VERSION("1.0.10");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c
index 04cd57f..6c287ac 100644
--- a/drivers/staging/ozwpan/ozpd.c
+++ b/drivers/staging/ozwpan/ozpd.c
@@ -24,18 +24,22 @@
 /*------------------------------------------------------------------------------
  */
 #define OZ_MAX_TX_POOL_SIZE	6
-/* Maximum number of uncompleted isoc frames that can be pending.
+/* Maximum number of uncompleted isoc frames that can be pending in network.
  */
 #define OZ_MAX_SUBMITTED_ISOC	16
+/* Maximum number of uncompleted isoc frames that can be pending in Tx Queue.
+ */
+#define OZ_MAX_TX_QUEUE_ISOC	32
 /*------------------------------------------------------------------------------
  */
 static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
 static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f);
+static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f);
 static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f);
 static int oz_send_isoc_frame(struct oz_pd *pd);
 static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f);
 static void oz_isoc_stream_free(struct oz_isoc_stream *st);
-static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data);
+static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data);
 static void oz_isoc_destructor(struct sk_buff *skb);
 static int oz_def_app_init(void);
 static void oz_def_app_term(void);
@@ -208,6 +212,8 @@ void oz_pd_destroy(struct oz_pd *pd)
 	while (e != &pd->tx_queue) {
 		f = container_of(e, struct oz_tx_frame, link);
 		e = e->next;
+		if (f->skb != NULL)
+			kfree_skb(f->skb);
 		oz_retire_frame(pd, f);
 	}
 	oz_elt_buf_term(&pd->elt_buff);
@@ -375,6 +381,23 @@ static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
 /*------------------------------------------------------------------------------
  * Context: softirq or process
  */
+static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
+{
+	pd->nb_queued_isoc_frames--;
+	list_del_init(&f->link);
+	if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) {
+		f->link.next = pd->tx_pool;
+		pd->tx_pool = &f->link;
+		pd->tx_pool_count++;
+	} else {
+		kfree(f);
+	}
+	oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
+						pd->nb_queued_isoc_frames);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
 static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
 {
 	spin_lock_bh(&pd->tx_frame_lock);
@@ -389,6 +412,22 @@ static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
 		kfree(f);
 }
 /*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+void oz_set_more_bit(struct sk_buff *skb)
+{
+	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+	oz_hdr->control |= OZ_F_MORE_DATA;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
+{
+	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
+}
+/*------------------------------------------------------------------------------
  * Context: softirq
  */
 int oz_prepare_frame(struct oz_pd *pd, int empty)
@@ -403,6 +442,7 @@ int oz_prepare_frame(struct oz_pd *pd, int empty)
 	f = oz_tx_frame_alloc(pd);
 	if (f == 0)
 		return -1;
+	f->skb = NULL;
 	f->hdr.control =
 		(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ACK_REQUESTED;
 	++pd->last_tx_pkt_num;
@@ -486,24 +526,52 @@ static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
 /*------------------------------------------------------------------------------
  * Context: softirq-serialized
  */
-static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data)
+static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
 {
 	struct sk_buff *skb;
 	struct oz_tx_frame *f;
 	struct list_head *e;
-	*more_data = 0;
 	spin_lock(&pd->tx_frame_lock);
 	e = pd->last_sent_frame->next;
 	if (e == &pd->tx_queue) {
 		spin_unlock(&pd->tx_frame_lock);
 		return -1;
 	}
-	pd->last_sent_frame = e;
-	if (e->next != &pd->tx_queue)
-		*more_data = 1;
 	f = container_of(e, struct oz_tx_frame, link);
+
+	if (f->skb != NULL) {
+		skb = f->skb;
+		oz_tx_isoc_free(pd, f);
+		spin_unlock(&pd->tx_frame_lock);
+		if (more_data)
+			oz_set_more_bit(skb);
+		oz_set_last_pkt_nb(pd, skb);
+		if ((int)atomic_read(&g_submitted_isoc) <
+							OZ_MAX_SUBMITTED_ISOC) {
+			if (dev_queue_xmit(skb) < 0) {
+				oz_trace2(OZ_TRACE_TX_FRAMES,
+						"Dropping ISOC Frame\n");
+				oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
+				return -1;
+			}
+			atomic_inc(&g_submitted_isoc);
+			oz_trace2(OZ_TRACE_TX_FRAMES,
+					"Sending ISOC Frame, nb_isoc= %d\n",
+						pd->nb_queued_isoc_frames);
+			return 0;
+		} else {
+			kfree_skb(skb);
+			oz_trace2(OZ_TRACE_TX_FRAMES, "Dropping ISOC Frame>\n");
+			oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
+			return -1;
+		}
+	}
+
+	pd->last_sent_frame = e;
 	skb = oz_build_frame(pd, f);
 	spin_unlock(&pd->tx_frame_lock);
+	if (more_data)
+		oz_set_more_bit(skb);
 	oz_trace2(OZ_TRACE_TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
 	if (skb) {
 		oz_event_log(OZ_EVT_TX_FRAME,
@@ -512,6 +580,7 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data)
 			0, f->hdr.pkt_num);
 		if (dev_queue_xmit(skb) < 0)
 			return -1;
+
 	}
 	return 0;
 }
@@ -520,21 +589,38 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data)
  */
 void oz_send_queued_frames(struct oz_pd *pd, int backlog)
 {
-	int more;
-	if (backlog <  OZ_MAX_QUEUED_FRAMES) {
-		if (oz_send_next_queued_frame(pd, &more) >= 0) {
-			while (more && oz_send_next_queued_frame(pd, &more))
-				;
-		} else {
-			if (((pd->mode & OZ_F_ISOC_ANYTIME) == 0)
-				|| (pd->isoc_sent == 0)) {
-				if (oz_prepare_frame(pd, 1) >= 0)
-					oz_send_next_queued_frame(pd, &more);
-			}
+	while (oz_prepare_frame(pd, 0) >= 0)
+		backlog++;
+
+	switch (pd->mode & (OZ_F_ISOC_NO_ELTS | OZ_F_ISOC_ANYTIME)) {
+
+		case OZ_F_ISOC_NO_ELTS: {
+			backlog += pd->nb_queued_isoc_frames;
+			if (backlog <= 0)
+				goto out;
+			if (backlog > OZ_MAX_SUBMITTED_ISOC)
+				backlog = OZ_MAX_SUBMITTED_ISOC;
+			break;
+		}
+		case OZ_NO_ELTS_ANYTIME: {
+			if ((backlog <= 0) && (pd->isoc_sent == 0))
+				goto out;
+			break;
+		}
+		default: {
+			if (backlog <= 0)
+				goto out;
+			break;
 		}
-	} else {
-		oz_send_next_queued_frame(pd, &more);
 	}
+	while (backlog--) {
+		if (oz_send_next_queued_frame(pd, backlog) < 0)
+			break;
+	}
+	return;
+
+out:	oz_prepare_frame(pd, 1);
+	oz_send_next_queued_frame(pd, 0);
 }
 /*------------------------------------------------------------------------------
  * Context: softirq
@@ -603,8 +689,10 @@ void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
 		f = container_of(e, struct oz_tx_frame, link);
 		pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num));
 		diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
-		if (diff > OZ_LAST_PN_HALF_CYCLE)
+		if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
 			break;
+		oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
+						 pkt_num, pd->nb_queued_frames);
 		if (first == 0)
 			first = e;
 		last = e;
@@ -727,6 +815,8 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len)
 		skb_reset_network_header(skb);
 		skb->dev = dev;
 		skb->protocol = htons(OZ_ETHERTYPE);
+		/* For audio packet set priority to AC_VO */
+		skb->priority = 0x7;
 		size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large);
 		oz_hdr = (struct oz_hdr *)skb_put(skb, size);
 	}
@@ -756,21 +846,53 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len)
 		memcpy(oz_hdr, &oz, sizeof(oz));
 		memcpy(oz_hdr+1, &iso, sizeof(iso));
 		if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
-				dev->dev_addr, skb->len) < 0) {
-			kfree_skb(skb);
-			return -1;
+				dev->dev_addr, skb->len) < 0)
+			goto out;
+
+		skb->destructor = oz_isoc_destructor;
+		/*Queue for Xmit if mode is not ANYTIME*/
+		if (!(pd->mode & OZ_F_ISOC_ANYTIME)) {
+			struct oz_tx_frame *isoc_unit = NULL;
+			int nb = pd->nb_queued_isoc_frames;
+			if (nb >= OZ_MAX_TX_QUEUE_ISOC) {
+				oz_trace2(OZ_TRACE_TX_FRAMES,
+						"Dropping ISOC Unit nb= %d\n",
+									nb);
+				goto out;
+			}
+			isoc_unit = oz_tx_frame_alloc(pd);
+			if (isoc_unit == NULL)
+				goto out;
+			isoc_unit->hdr = oz;
+			isoc_unit->skb = skb;
+			spin_lock_bh(&pd->tx_frame_lock);
+			list_add_tail(&isoc_unit->link, &pd->tx_queue);
+			pd->nb_queued_isoc_frames++;
+			spin_unlock_bh(&pd->tx_frame_lock);
+			oz_trace2(OZ_TRACE_TX_FRAMES,
+			"Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
+			pd->nb_queued_isoc_frames, pd->nb_queued_frames);
+			oz_event_log(OZ_EVT_TX_ISOC, nb_units, iso.frame_number,
+					skb, atomic_read(&g_submitted_isoc));
+			return 0;
 		}
+
+		/*In ANYTIME mode Xmit unit immediately*/
 		if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) {
-			skb->destructor = oz_isoc_destructor;
 			atomic_inc(&g_submitted_isoc);
 			oz_event_log(OZ_EVT_TX_ISOC, nb_units, iso.frame_number,
-				skb, atomic_read(&g_submitted_isoc));
-			if (dev_queue_xmit(skb) < 0)
+					skb, atomic_read(&g_submitted_isoc));
+			if (dev_queue_xmit(skb) < 0) {
+				oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
 				return -1;
-		} else {
-			oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
-			kfree_skb(skb);
+			} else
+				return 0;
 		}
+
+out:	oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
+	kfree_skb(skb);
+	return -1;
+
 	}
 	return 0;
 }
diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h
index afc77f0..ddf1341 100644
--- a/drivers/staging/ozwpan/ozpd.h
+++ b/drivers/staging/ozwpan/ozpd.h
@@ -29,6 +29,7 @@ struct oz_tx_frame {
 	struct list_head link;
 	struct list_head elt_list;
 	struct oz_hdr hdr;
+	struct sk_buff *skb;
 	int total_size;
 };
 
@@ -83,6 +84,7 @@ struct oz_pd {
 	u8		ms_per_isoc;
 	unsigned	max_stream_buffering;
 	int		nb_queued_frames;
+	int		nb_queued_isoc_frames;
 	struct list_head *tx_pool;
 	int		tx_pool_count;
 	spinlock_t	tx_frame_lock;
@@ -118,4 +120,3 @@ void oz_apps_init(void);
 void oz_apps_term(void);
 
 #endif /* Sentry */
-
diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c
index ad857ee..a50ab18 100644
--- a/drivers/staging/ozwpan/ozproto.c
+++ b/drivers/staging/ozwpan/ozproto.c
@@ -217,7 +217,6 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
 	pd->mode = body->mode;
 	pd->pd_info = body->pd_info;
 	if (pd->mode & OZ_F_ISOC_NO_ELTS) {
-		pd->mode |= OZ_F_ISOC_ANYTIME;
 		pd->ms_per_isoc = body->ms_per_isoc;
 		if (!pd->ms_per_isoc)
 			pd->ms_per_isoc = 4;
@@ -366,6 +365,7 @@ static void oz_rx_frame(struct sk_buff *skb)
 	}
 
 	if (pd && !dup && ((pd->mode & OZ_MODE_MASK) == OZ_MODE_TRIGGERED)) {
+		oz_trace2(OZ_TRACE_RX_FRAMES, "Received TRIGGER Frame\n");
 		pd->last_sent_frame = &pd->tx_queue;
 		if (oz_hdr->control & OZ_F_ACK) {
 			/* Retire completed frames */
@@ -376,8 +376,6 @@ static void oz_rx_frame(struct sk_buff *skb)
 			int backlog = pd->nb_queued_frames;
 			pd->trigger_pkt_num = pkt_num;
 			/* Send queued frames */
-			while (oz_prepare_frame(pd, 0) >= 0)
-				;
 			oz_send_queued_frames(pd, backlog);
 		}
 	}
@@ -796,7 +794,7 @@ void oz_binding_add(char *net_dev)
 {
 	struct oz_binding *binding;
 
-	binding = kmalloc(sizeof(struct oz_binding), GFP_ATOMIC);
+	binding = kmalloc(sizeof(struct oz_binding), GFP_KERNEL);
 	if (binding) {
 		binding->ptype.type = __constant_htons(OZ_ETHERTYPE);
 		binding->ptype.func = oz_pkt_recv;
diff --git a/drivers/staging/ozwpan/ozprotocol.h b/drivers/staging/ozwpan/ozprotocol.h
index b3e7d77..1e4edbe 100644
--- a/drivers/staging/ozwpan/ozprotocol.h
+++ b/drivers/staging/ozwpan/ozprotocol.h
@@ -89,6 +89,7 @@ struct oz_elt_connect_req {
 #define OZ_MODE_MASK		0xf
 #define OZ_F_ISOC_NO_ELTS	0x40
 #define OZ_F_ISOC_ANYTIME	0x80
+#define OZ_NO_ELTS_ANYTIME	0xc0
 
 /* Keep alive field.
  */
diff --git a/drivers/staging/ramster/r2net.c b/drivers/staging/ramster/r2net.c
index 2ee0220..fc830c3 100644
--- a/drivers/staging/ramster/r2net.c
+++ b/drivers/staging/ramster/r2net.c
@@ -266,8 +266,8 @@ int ramster_remote_put(struct tmem_xhandle *xh, char *data, size_t size,
 		static unsigned long cnt;
 		cnt++;
 		if (!(cnt&(cnt-1)))
-			pr_err("ramster_remote_put: message failed, "
-				"ret=%d, cnt=%lu\n", ret, cnt);
+			pr_err("ramster_remote_put: message failed, ret=%d, cnt=%lu\n",
+				ret, cnt);
 		ret = -1;
 	}
 #endif
diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c
index 46ee6f4..52f63d7 100644
--- a/drivers/staging/rtl8187se/r8180_wx.c
+++ b/drivers/staging/rtl8187se/r8180_wx.c
@@ -615,10 +615,10 @@ static int r8180_wx_get_retry(struct net_device *dev,
 		return -EINVAL;
 
 	if (wrqu->retry.flags & IW_RETRY_MAX) {
-		wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX;
+		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
 		wrqu->retry.value = priv->retry_rts;
 	} else {
-		wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MIN;
+		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
 		wrqu->retry.value = priv->retry_data;
 	}
 
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
index 778d7ba..6202358 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
@@ -919,10 +919,10 @@ static int r8192_wx_get_retry(struct net_device *dev,
 		return -EINVAL;
 
 	if (wrqu->retry.flags & IW_RETRY_MAX) {
-		wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX;
+		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
 		wrqu->retry.value = priv->retry_rts;
 	} else {
-		wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MIN;
+		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
 		wrqu->retry.value = priv->retry_data;
 	}
 	return 0;
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index 69f616c..c758c40 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -41,8 +41,6 @@
 #include "usb_ops.h"
 #include "usb_osintf.h"
 
-#define DRVER  "v7_0.20100831"
-
 static struct usb_interface *pintf;
 
 static int r871xu_drv_init(struct usb_interface *pusb_intf,
@@ -374,7 +372,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
 	struct net_device *pnetdev;
 	struct usb_device *udev;
 
-	printk(KERN_INFO "r8712u: DriverVersion: %s\n", DRVER);
+	printk(KERN_INFO "r8712u: Staging version\n");
 	/* In this probe function, O.S. will provide the usb interface pointer
 	 * to driver. We have to increase the reference count of the usb device
 	 * structure by using the usb_get_dev function.
diff --git a/drivers/staging/rts5139/rts51x_chip.c b/drivers/staging/rts5139/rts51x_chip.c
index db88d7a..08dcae8 100644
--- a/drivers/staging/rts5139/rts51x_chip.c
+++ b/drivers/staging/rts5139/rts51x_chip.c
@@ -363,11 +363,10 @@ void rts51x_polling_func(struct rts51x_chip *chip)
 		break;
 	}
 
-	if (chip->option.auto_delink_en && !chip->card_ready) {
+	if (chip->option.auto_delink_en && !chip->card_ready)
 		rts51x_auto_delink(chip);
-	} else {
+	else
 		chip->auto_delink_counter = 0;
-	}
 }
 
 void rts51x_add_cmd(struct rts51x_chip *chip,
diff --git a/drivers/staging/rts5139/rts51x_chip.h b/drivers/staging/rts5139/rts51x_chip.h
index 6d395b6..64257ca 100644
--- a/drivers/staging/rts5139/rts51x_chip.h
+++ b/drivers/staging/rts5139/rts51x_chip.h
@@ -204,7 +204,7 @@ struct trace_msg_t {
 /*---- error code ----*/
 #define CUR_ERR                 0x70	/* current error                    */
 
-/*---- sense key Infomation ----*/
+/*---- sense key Information ----*/
 
 #define SKSV                    0x80
 #define CDB_ILLEGAL             0x40
diff --git a/drivers/staging/rts5139/rts51x_fop.c b/drivers/staging/rts5139/rts51x_fop.c
index ef893c8..e1200fe 100644
--- a/drivers/staging/rts5139/rts51x_fop.c
+++ b/drivers/staging/rts5139/rts51x_fop.c
@@ -36,7 +36,6 @@
 #include "rts51x_card.h"
 #include "rts51x_fop.h"
 #include "sd_cprm.h"
-#include "rts51x.h"
 
 #define RTS5139_IOC_MAGIC		0x39
 
diff --git a/drivers/staging/rts5139/rts51x_scsi.h b/drivers/staging/rts5139/rts51x_scsi.h
index 060d2c2..9042bc9 100644
--- a/drivers/staging/rts5139/rts51x_scsi.h
+++ b/drivers/staging/rts5139/rts51x_scsi.h
@@ -73,7 +73,7 @@
 #define GET_BATCHRSP		0x44
 
 #ifdef SUPPORT_CPRM
-/* SD Pass Through Command Extention */
+/* SD Pass Through Command Extension */
 #define SD_PASS_THRU_MODE	0xD0
 #define SD_EXECUTE_NO_DATA	0xD1
 #define SD_EXECUTE_READ		0xD2
diff --git a/drivers/staging/rts5139/sd_cprm.c b/drivers/staging/rts5139/sd_cprm.c
index f8c6071..0167f7f 100644
--- a/drivers/staging/rts5139/sd_cprm.c
+++ b/drivers/staging/rts5139/sd_cprm.c
@@ -201,9 +201,8 @@ RTY_SEND_CMD:
 			if (buf[1] & 0x80)
 				TRACE_RET(chip, STATUS_FAIL);
 		}
-		if (buf[1] & 0x7F) {
+		if (buf[1] & 0x7F)
 			TRACE_RET(chip, STATUS_FAIL);
-		}
 		if (buf[2] & 0xF8)
 			TRACE_RET(chip, STATUS_FAIL);
 
@@ -224,7 +223,8 @@ RTY_SEND_CMD:
 	return STATUS_SUCCESS;
 }
 
-static int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 *rsp, u8 rsp_type)
+static int ext_sd_get_rsp(struct rts51x_chip *chip, int len,
+			u8 *rsp, u8 rsp_type)
 {
 	int retval, rsp_len;
 	u16 reg_addr;
@@ -844,7 +844,7 @@ int sd_pass_thru_mode(struct scsi_cmnd *srb, struct rts51x_chip *chip)
 
 	buf[15] = chip->max_lun;
 
-	len = min(18, (int)scsi_bufflen(srb));
+	len = min_t(unsigned, 18, scsi_bufflen(srb));
 	rts51x_set_xfer_buf(buf, len, srb);
 
 	return TRANSPORT_GOOD;
diff --git a/drivers/staging/rts_pstor/ms.c b/drivers/staging/rts_pstor/ms.c
index 0bf6d95..7cc2b53 100644
--- a/drivers/staging/rts_pstor/ms.c
+++ b/drivers/staging/rts_pstor/ms.c
@@ -2488,7 +2488,7 @@ int reset_ms_card(struct rtsx_chip *chip)
 
 	if (!CHK_MSPRO(ms_card)) {
 		/* Build table for the last segment,
-		 * to check if L2P talbe block exist,erasing it
+		 * to check if L2P table block exists, erasing it
 		 */
 		retval = ms_build_l2p_tbl(chip, ms_card->total_block / 512 - 1);
 		if (retval != STATUS_SUCCESS) {
diff --git a/drivers/staging/rts_pstor/sd.c b/drivers/staging/rts_pstor/sd.c
index aab6909..b9474a8 100644
--- a/drivers/staging/rts_pstor/sd.c
+++ b/drivers/staging/rts_pstor/sd.c
@@ -1169,7 +1169,7 @@ static int sd_check_switch_mode(struct rtsx_chip *chip, u8 mode,
 		RTSX_DEBUGP("func_group4_mask = 0x%02x\n", buf[0x07]);
 	} else {
 		/* Maximum current consumption, check whether current is acceptable;
-		 * bit[511:496] = 0x0000 means some error happaned.
+		 * bit[511:496] = 0x0000 means some error happened.
 		 */
 		u16 cc = ((u16)buf[0] << 8) | buf[1];
 		RTSX_DEBUGP("Maximum current consumption: %dmA\n", cc);
diff --git a/drivers/staging/sbe-2t3e3/dc.c b/drivers/staging/sbe-2t3e3/dc.c
index 9dc4ec2..e897a43 100644
--- a/drivers/staging/sbe-2t3e3/dc.c
+++ b/drivers/staging/sbe-2t3e3/dc.c
@@ -81,7 +81,7 @@ void dc_init(struct channel *sc)
 		SBE_2T3E3_21143_VAL_NUMBER_OF_RECEIVE_PACKETS;
 	dc_write(sc->addr, SBE_2T3E3_21143_REG_GENERAL_PURPOSE_TIMER_AND_INTERRUPT_MITIGATION_CONTROL, val);
 
-	/* prepare descriptors and data for receive and transmit procecsses */
+	/* prepare descriptors and data for receive and transmit processes */
 	if (dc_init_descriptor_list(sc) != 0)
 		return;
 
diff --git a/drivers/staging/sbe-2t3e3/io.c b/drivers/staging/sbe-2t3e3/io.c
index 9a50bcc..d2391cb 100644
--- a/drivers/staging/sbe-2t3e3/io.c
+++ b/drivers/staging/sbe-2t3e3/io.c
@@ -17,7 +17,7 @@
 /* All access to registers done via the 21143 on port 0 must be
  * protected via the card->bootrom_lock. */
 
-/* priviate define to be used here only - must be protected by card->bootrom_lock */
+/* private define to be used here only - must be protected by card->bootrom_lock */
 #define cpld_write_nolock(channel, reg, val)			\
 	bootrom_write((channel), CPLD_MAP_REG(reg, channel), val)
 
diff --git a/drivers/staging/sep/sep_crypto.c b/drivers/staging/sep/sep_crypto.c
index 1cc790e..045493b 100644
--- a/drivers/staging/sep/sep_crypto.c
+++ b/drivers/staging/sep/sep_crypto.c
@@ -807,7 +807,7 @@ end_function:
  *	@size: size of parameter to copy (in bytes)
  *	@max_size: size to move up offset; SEP mesg is in word sizes
  *	@msg_offset: pointer to current offset (is updated)
- *	@byte_array: flag ti indicate wheter endian must be changed
+ *	@byte_array: flag ti indicate whether endian must be changed
  *	Copies data into the message area from caller
  */
 static void sep_write_msg(struct this_task_ctx *ta_ctx, void *in_addr,
@@ -855,7 +855,7 @@ static void sep_make_header(struct this_task_ctx *ta_ctx, u32 *msg_offset,
  *	@size: size of parameter to copy (in bytes)
  *	@max_size: size to move up offset; SEP mesg is in word sizes
  *	@msg_offset: pointer to current offset (is updated)
- *	@byte_array: flag ti indicate wheter endian must be changed
+ *	@byte_array: flag ti indicate whether endian must be changed
  *	Copies data out of the message area to caller
  */
 static void sep_read_msg(struct this_task_ctx *ta_ctx, void *in_addr,
@@ -990,7 +990,7 @@ static void sep_clear_out(struct this_task_ctx *ta_ctx)
 		/**
 		 * The following unlocks the sep and makes it available
 		 * to any other application
-		 * First, null out crypto entries in sep before relesing it
+		 * First, null out crypto entries in sep before releasing it
 		 */
 		ta_ctx->sep_used->current_hash_req = NULL;
 		ta_ctx->sep_used->current_cypher_req = NULL;
@@ -1001,7 +1001,7 @@ static void sep_clear_out(struct this_task_ctx *ta_ctx)
 
 		ta_ctx->call_status.status = 0;
 
-		/* Remove anything confidentail */
+		/* Remove anything confidential */
 		memset(ta_ctx->sep_used->shared_addr, 0,
 			SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
 
@@ -1095,8 +1095,8 @@ static int sep_crypto_take_sep(struct this_task_ctx *ta_ctx)
 		current->comm, sizeof(current->comm));
 
 	if (!ta_ctx->queue_elem) {
-		dev_dbg(&sep->pdev->dev, "[PID%d] updating queue"
-			" status error\n", current->pid);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] updating queue status error\n", current->pid);
 		return -EINVAL;
 	}
 
@@ -1207,7 +1207,7 @@ static int sep_crypto_block_data(struct ablkcipher_request *req)
 		req->nbytes, ta_ctx->walk.blocksize, &new_sg, 1);
 
 	if (int_error < 0) {
-		dev_warn(&ta_ctx->sep_used->pdev->dev, "oddball page eerror\n");
+		dev_warn(&ta_ctx->sep_used->pdev->dev, "oddball page error\n");
 		return -ENOMEM;
 	} else if (int_error == 1) {
 		ta_ctx->src_sg = new_sg;
@@ -1870,7 +1870,7 @@ static u32 hash_update_post_op(struct sep_device *sep)
 		sizeof(struct sep_hash_private_context));
 
 	/**
-	 * Following is only for finup; if we just completd the
+	 * Following is only for finup; if we just completed the
 	 * data portion of finup, we now need to kick off the
 	 * finish portion of finup.
 	 */
@@ -2011,7 +2011,7 @@ static u32 hash_digest_post_op(struct sep_device *sep)
 }
 
 /**
- * The sep_finish function is the function that is schedule (via tasket)
+ * The sep_finish function is the function that is scheduled (via tasklet)
  * by the interrupt service routine when the SEP sends and interrupt
  * This is only called by the interrupt handler as a tasklet.
  */
@@ -2249,7 +2249,7 @@ static void sep_hash_update(void *data)
 	head_len = (block_size - int_ctx->prev_update_bytes) % block_size;
 	tail_len = (req->nbytes - head_len) % block_size;
 
-	/* Make sure all pages are even block */
+	/* Make sure all pages are an even block */
 	int_error = sep_oddball_pages(ta_ctx->sep_used, req->src,
 		req->nbytes,
 		block_size, &new_sg, 1);
@@ -2482,7 +2482,7 @@ static void sep_hash_digest(void *data)
 	dev_dbg(&ta_ctx->sep_used->pdev->dev, "block_size is %x\n", block_size);
 	dev_dbg(&ta_ctx->sep_used->pdev->dev, "tail len is %x\n", tail_len);
 
-	/* Make sure all pages are even block */
+	/* Make sure all pages are an even block */
 	int_error = sep_oddball_pages(ta_ctx->sep_used, req->src,
 		req->nbytes,
 		block_size, &new_sg, 1);
diff --git a/drivers/staging/sep/sep_driver_api.h b/drivers/staging/sep/sep_driver_api.h
index 8b797d5..7ee1c3b 100644
--- a/drivers/staging/sep/sep_driver_api.h
+++ b/drivers/staging/sep/sep_driver_api.h
@@ -91,7 +91,7 @@ struct sep_dcblock {
 };
 
 /*
-	command structure for building dcb block (currently for ext app only
+	command structure for building dcb block (currently for ext app only)
 */
 struct build_dcb_struct {
 	/* address value of the data in */
@@ -234,7 +234,7 @@ struct sep_dma_context {
 	u32 dmatables_len;
 	/* size of input data */
 	u32 input_data_len;
-	/* secure dma use (for imr memory restriced area in output */
+	/* secure dma use (for imr memory restricted area in output) */
 	bool secure_dma;
 	struct sep_dma_resource dma_res_arr[SEP_MAX_NUM_SYNC_DMA_OPS];
 	/* Scatter gather for kernel crypto */
@@ -347,10 +347,10 @@ int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep,
 
 /**
  * sep_free_dma_table_data_handler - free DMA table
- * @sep: pointere to struct sep_device
+ * @sep: pointer to struct sep_device
  * @dma_ctx: dma context
  *
- * Handles the request to  free DMA table for synchronic actions
+ * Handles the request to free DMA table for synchronic actions
  */
 int sep_free_dma_table_data_handler(struct sep_device *sep,
 					   struct sep_dma_context **dma_ctx);
diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h
index 9d9fc7c..7d7c7ab 100644
--- a/drivers/staging/sep/sep_driver_config.h
+++ b/drivers/staging/sep/sep_driver_config.h
@@ -43,7 +43,7 @@
 #define SEP_DRIVER_POLLING_MODE                         0
 
 /* flag which defines if the shared area address should be
-	reconfiged (send to SEP anew) during init of the driver */
+	reconfigured (send to SEP anew) during init of the driver */
 #define SEP_DRIVER_RECONFIG_MESSAGE_AREA                0
 
 /* the mode for running on the ARM1172 Evaluation platform (flag is 1) */
@@ -166,7 +166,7 @@ held by the process (struct file) */
 	(SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES + \
 	SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES)
 
-/* synhronic dma tables area offset */
+/* synchronic dma tables area offset */
 #define SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES \
 	(SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + \
 	SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES)
diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c
index df1d13e..270fcb8 100644
--- a/drivers/staging/sep/sep_main.c
+++ b/drivers/staging/sep/sep_main.c
@@ -94,7 +94,7 @@
 #endif
 
 /**
- * Currenlty, there is only one SEP device per platform;
+ * Currently, there is only one SEP device per platform;
  * In event platforms in the future have more than one SEP
  * device, this will be a linked list
  */
@@ -106,7 +106,7 @@ struct sep_device *sep_dev;
  * @sep: SEP device
  * @sep_queue_info: pointer to status queue
  *
- * This function will removes information about transaction from the queue.
+ * This function will remove information about transaction from the queue.
  */
 void sep_queue_status_remove(struct sep_device *sep,
 				      struct sep_queue_info **queue_elem)
@@ -294,7 +294,7 @@ int sep_wait_transaction(struct sep_device *sep)
 end_function_setpid:
 	/*
 	 * The pid_doing_transaction indicates that this process
-	 * now owns the facilities to performa a transaction with
+	 * now owns the facilities to perform a transaction with
 	 * the SEP. While this process is performing a transaction,
 	 * no other process who has the SEP device open can perform
 	 * any transactions. This method allows more than one process
@@ -447,10 +447,10 @@ static int sep_open(struct inode *inode, struct file *filp)
 
 /**
  * sep_free_dma_table_data_handler - free DMA table
- * @sep: pointere to struct sep_device
+ * @sep: pointer to struct sep_device
  * @dma_ctx: dma context
  *
- * Handles the request to  free DMA table for synchronic actions
+ * Handles the request to free DMA table for synchronic actions
  */
 int sep_free_dma_table_data_handler(struct sep_device *sep,
 					   struct sep_dma_context **dma_ctx)
@@ -540,7 +540,7 @@ int sep_free_dma_table_data_handler(struct sep_device *sep,
 		 * don't have a page array; the page array is generated
 		 * only in the lock_user_pages, which is not called
 		 * for kernel crypto, which is what the sg (scatter gather
-		 * is used for exclusively
+		 * is used for exclusively)
 		 */
 		if (dma->src_sg) {
 			dma_unmap_sg(&sep->pdev->dev, dma->src_sg,
@@ -1227,7 +1227,7 @@ static int sep_lock_user_pages(struct sep_device *sep,
 	/* Map array */
 	struct sep_dma_map *map_array;
 
-	/* Set start and end pages  and num pages */
+	/* Set start and end pages and num pages */
 	end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT;
 	start_page = app_virt_addr >> PAGE_SHIFT;
 	num_pages = end_page - start_page + 1;
@@ -1431,13 +1431,14 @@ static int sep_lli_table_secure_dma(struct sep_device *sep,
 	/* Array of lli */
 	struct sep_lli_entry *lli_array;
 
-	/* Set start and end pages  and num pages */
+	/* Set start and end pages and num pages */
 	end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT;
 	start_page = app_virt_addr >> PAGE_SHIFT;
 	num_pages = end_page - start_page + 1;
 
-	dev_dbg(&sep->pdev->dev, "[PID%d] lock user pages"
-		" app_virt_addr is %x\n", current->pid, app_virt_addr);
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] lock user pages  app_virt_addr is %x\n",
+		current->pid, app_virt_addr);
 
 	dev_dbg(&sep->pdev->dev, "[PID%d] data_size is (hex) %x\n",
 		current->pid, data_size);
@@ -1601,7 +1602,7 @@ end_function:
  * @num_table_entries_ptr: pointer to number of tables
  * @table_data_size: total data size
  *
- * Builds ant lli table from the lli_array according to
+ * Builds an lli table from the lli_array according to
  * the given size of data
  */
 static void sep_build_lli_table(struct sep_device *sep,
@@ -1700,7 +1701,7 @@ static void sep_build_lli_table(struct sep_device *sep,
  * @virt_address: virtual address to convert
  *
  * This functions returns the physical address inside shared area according
- * to the virtual address. It can be either on the externa RAM device
+ * to the virtual address. It can be either on the external RAM device
  * (ioremapped), or on the system RAM
  * This implementation is for the external RAM
  */
@@ -1724,7 +1725,7 @@ static dma_addr_t sep_shared_area_virt_to_bus(struct sep_device *sep,
  *
  * This functions returns the virtual address inside shared area
  * according to the physical address. It can be either on the
- * externa RAM device (ioremapped), or on the system RAM
+ * external RAM device (ioremapped), or on the system RAM
  * This implementation is for the external RAM
  */
 static void *sep_shared_area_bus_to_virt(struct sep_device *sep,
@@ -1890,9 +1891,9 @@ static void sep_prepare_empty_lli_table(struct sep_device *sep,
  * @lli_table_ptr:
  * @num_entries_ptr:
  * @table_data_size_ptr:
- * @is_kva: set for kernel data (kernel cryptio call)
+ * @is_kva: set for kernel data (kernel crypt io call)
  *
- * This function prepares only input DMA table for synhronic symmetric
+ * This function prepares only input DMA table for synchronic symmetric
  * operations (HASH)
  * Note that all bus addresses that are passed to the SEP
  * are in 32 bit format; the SEP is a 32 bit device
@@ -1931,9 +1932,9 @@ static int sep_prepare_input_dma_table(struct sep_device *sep,
 	void *dma_lli_table_alloc_addr = NULL;
 	void *dma_in_lli_table_ptr = NULL;
 
-	dev_dbg(&sep->pdev->dev, "[PID%d] prepare intput dma "
-				 "tbl data size: (hex) %x\n",
-					current->pid, data_size);
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] prepare intput dma tbl data size: (hex) %x\n",
+		current->pid, data_size);
 
 	dev_dbg(&sep->pdev->dev, "[PID%d] block_size is (hex) %x\n",
 					current->pid, block_size);
@@ -2173,9 +2174,9 @@ static int sep_construct_dma_tables_from_lli(
 	u32 last_table_flag = 0;
 	/* The data size that should be in table */
 	u32 table_data_size = 0;
-	/* Number of etnries in the input table */
+	/* Number of entries in the input table */
 	u32 num_entries_in_table = 0;
-	/* Number of etnries in the output table */
+	/* Number of entries in the output table */
 	u32 num_entries_out_table = 0;
 
 	if (!dma_ctx) {
@@ -2400,7 +2401,7 @@ static int sep_construct_dma_tables_from_lli(
  * @table_data_size_ptr:
  * @is_kva: set for kernel data; used only for kernel crypto module
  *
- * This function builds input and output DMA tables for synhronic
+ * This function builds input and output DMA tables for synchronic
  * symmetric operations (AES, DES, HASH). It also checks that each table
  * is of the modular block size
  * Note that all bus addresses that are passed to the SEP
@@ -2542,19 +2543,20 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep,
 		}
 	}
 
-	dev_dbg(&sep->pdev->dev, "[PID%d] After lock; prep input output dma "
-		"table sep_in_num_pages is (hex) %x\n", current->pid,
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] After lock; prep input output dma table sep_in_num_pages is (hex) %x\n",
+		current->pid,
 		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages);
 
 	dev_dbg(&sep->pdev->dev, "[PID%d] sep_out_num_pages is (hex) %x\n",
 		current->pid,
 		dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].out_num_pages);
 
-	dev_dbg(&sep->pdev->dev, "[PID%d] SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP"
-		" is (hex) %x\n", current->pid,
-		SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is (hex) %x\n",
+		current->pid, SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
 
-	/* Call the fucntion that creates table from the lli arrays */
+	/* Call the function that creates table from the lli arrays */
 	dev_dbg(&sep->pdev->dev, "[PID%d] calling create table from lli\n",
 					current->pid);
 	error = sep_construct_dma_tables_from_lli(
@@ -3661,7 +3663,7 @@ static ssize_t sep_read(struct file *filp,
 		goto end_function;
 	}
 
-	/* Checks that user has called necessarry apis */
+	/* Checks that user has called necessary apis */
 	if (0 == test_bit(SEP_FASTCALL_WRITE_DONE_OFFSET,
 			&call_status->status)) {
 		dev_warn(&sep->pdev->dev,
@@ -3844,8 +3846,9 @@ static ssize_t sep_write(struct file *filp,
 	 * buffers created. Only SEP_DOUBLEBUF_USERS_LIMIT number
 	 * of threads can progress further at a time
 	 */
-	dev_dbg(&sep->pdev->dev, "[PID%d] waiting for double buffering "
-				 "region access\n", current->pid);
+	dev_dbg(&sep->pdev->dev,
+		"[PID%d] waiting for double buffering region access\n",
+		current->pid);
 	error = down_interruptible(&sep->sep_doublebuf);
 	dev_dbg(&sep->pdev->dev, "[PID%d] double buffering region start\n",
 					current->pid);
@@ -3889,8 +3892,8 @@ static ssize_t sep_write(struct file *filp,
 				     current->comm, sizeof(current->comm));
 
 	if (!my_queue_elem) {
-		dev_dbg(&sep->pdev->dev, "[PID%d] updating queue"
-					"status error\n", current->pid);
+		dev_dbg(&sep->pdev->dev,
+			"[PID%d] updating queue status error\n", current->pid);
 		error = -ENOMEM;
 		goto end_function_error_doublebuf;
 	}
@@ -4155,8 +4158,8 @@ static int __devinit sep_probe(struct pci_dev *pdev,
 
 	INIT_LIST_HEAD(&sep->sep_queue_status);
 
-	dev_dbg(&sep->pdev->dev, "sep probe: PCI obtained, "
-		"device being prepared\n");
+	dev_dbg(&sep->pdev->dev,
+		"sep probe: PCI obtained, device being prepared\n");
 
 	/* Set up our register area */
 	sep->reg_physical_addr = pci_resource_start(sep->pdev, 0);
@@ -4318,7 +4321,7 @@ static void sep_remove(struct pci_dev *pdev)
 static DEFINE_PCI_DEVICE_TABLE(sep_pci_id_tbl) = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0826)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08e9)},
- 	{0}
+	{0}
 };
 
 /* Export our pci_device_id structure to user space */
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index 43045db..8a362f7 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -609,7 +609,7 @@ static int BoxSetRegister(struct usb_serial *serial, unsigned short Uart_Number,
 
 /*
  * qt_setuart
- * issuse a SET_UART vendor-spcific request on the default control pipe
+ * issues a SET_UART vendor-specific request on the default control pipe
  * If successful sets baud rate divisor and LCR value
  */
 static int qt_setuart(struct usb_serial *serial, unsigned short Uart_Number,
@@ -1388,7 +1388,7 @@ static inline int qt_real_tiocmset(struct tty_struct *tty,
 		return -ESPIPE;
 
 	/*
-	 * Turn off the RTS and DTR and loopbcck and then only turn on what was
+	 * Turn off the RTS and DTR and loopback and then only turn on what was
 	 * asked for
 	 */
 	mcr &= ~(SERIAL_MCR_RTS | SERIAL_MCR_DTR | SERIAL_MCR_LOOP);
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index 77a0751..d2b82a7 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -47,7 +47,7 @@
  *      Oasis cards (single and dual port PCI-x Gigabit) copper and fiber
  *      Kalahari cards (dual and quad port PCI-e Gigabit) copper and fiber
  *
- * The driver was acutally tested on Oasis and Kalahari cards.
+ * The driver was actually tested on Oasis and Kalahari cards.
  *
  *
  * NOTE: This is the standard, non-accelerated version of Alacritech's
diff --git a/drivers/staging/sm7xx/Kconfig b/drivers/staging/sm7xx/Kconfig
deleted file mode 100644
index 315102c..0000000
--- a/drivers/staging/sm7xx/Kconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-config FB_SM7XX
-	tristate "Silicon Motion SM7XX Frame Buffer Support"
-	depends on FB
-	select FB_CFB_FILLRECT
-	select FB_CFB_COPYAREA
-	select FB_CFB_IMAGEBLIT
-	help
-	  Frame Buffer driver for the Silicon Motion SM7XX serial graphic card.
diff --git a/drivers/staging/sm7xx/Makefile b/drivers/staging/sm7xx/Makefile
deleted file mode 100644
index f43cb91..0000000
--- a/drivers/staging/sm7xx/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_FB_SM7XX) += sm7xx.o
-
-sm7xx-y := smtcfb.o
diff --git a/drivers/staging/sm7xx/TODO b/drivers/staging/sm7xx/TODO
deleted file mode 100644
index 7304021..0000000
--- a/drivers/staging/sm7xx/TODO
+++ /dev/null
@@ -1,9 +0,0 @@
-TODO:
-- Dual head support
-- 2D acceleration support
-- use kernel coding style
-- refine the code and remove unused code
-- move it to drivers/video/sm7xx/ or make it be drivers/video/sm7xxfb.c
-
-Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and
-Teddy Wang <teddy.wang@siliconmotion.com.cn>.
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
deleted file mode 100644
index 746c4cd..0000000
--- a/drivers/staging/sm7xx/smtcfb.c
+++ /dev/null
@@ -1,1096 +0,0 @@
-/*
- * Silicon Motion SM7XX frame buffer device
- *
- * Copyright (C) 2006 Silicon Motion Technology Corp.
- * Authors:  Ge Wang, gewang@siliconmotion.com
- *	     Boyod boyod.yang@siliconmotion.com.cn
- *
- * Copyright (C) 2009 Lemote, Inc.
- * Author:   Wu Zhangjin, wuzhangjin@gmail.com
- *
- * Copyright (C) 2011 Igalia, S.L.
- * Author:   Javier M. Mellid <jmunhoz@igalia.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
- */
-
-#include <linux/io.h>
-#include <linux/fb.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/screen_info.h>
-
-#ifdef CONFIG_PM
-#include <linux/pm.h>
-#endif
-
-#include "smtcfb.h"
-
-struct screen_info smtc_screen_info;
-
-/*
-* Private structure
-*/
-struct smtcfb_info {
-	struct fb_info fb;
-	struct pci_dev *pdev;
-	struct {
-		u8 red, green, blue;
-	} palette[NR_RGB];
-	u_int palette_size;
-
-	u16 chipID;
-	unsigned char __iomem *m_pMMIO;
-	char __iomem *m_pLFB;
-	char *m_pDPR;
-	char *m_pVPR;
-	char *m_pCPR;
-
-	u_int width;
-	u_int height;
-	u_int hz;
-	u_long BaseAddressInVRAM;
-	u8 chipRevID;
-};
-
-struct vesa_mode_table	{
-	char mode_index[6];
-	u16 lfb_width;
-	u16 lfb_height;
-	u16 lfb_depth;
-};
-
-static struct vesa_mode_table vesa_mode[] = {
-	{"0x301", 640,  480,  8},
-	{"0x303", 800,  600,  8},
-	{"0x305", 1024, 768,  8},
-	{"0x307", 1280, 1024, 8},
-
-	{"0x311", 640,  480,  16},
-	{"0x314", 800,  600,  16},
-	{"0x317", 1024, 768,  16},
-	{"0x31A", 1280, 1024, 16},
-
-	{"0x312", 640,  480,  24},
-	{"0x315", 800,  600,  24},
-	{"0x318", 1024, 768,  24},
-	{"0x31B", 1280, 1024, 24},
-};
-
-char __iomem *smtc_RegBaseAddress;	/* Memory Map IO starting address */
-char __iomem *smtc_VRAMBaseAddress;	/* video memory starting address */
-
-static u32 colreg[17];
-
-static struct fb_var_screeninfo smtcfb_var = {
-	.xres           = 1024,
-	.yres           = 600,
-	.xres_virtual   = 1024,
-	.yres_virtual   = 600,
-	.bits_per_pixel = 16,
-	.red            = {16, 8, 0},
-	.green          = {8, 8, 0},
-	.blue           = {0, 8, 0},
-	.activate       = FB_ACTIVATE_NOW,
-	.height         = -1,
-	.width          = -1,
-	.vmode          = FB_VMODE_NONINTERLACED,
-};
-
-static struct fb_fix_screeninfo smtcfb_fix = {
-	.id             = "sm712fb",
-	.type           = FB_TYPE_PACKED_PIXELS,
-	.visual         = FB_VISUAL_TRUECOLOR,
-	.line_length    = 800 * 3,
-	.accel          = FB_ACCEL_SMI_LYNX,
-};
-
-static void sm712_set_timing(struct smtcfb_info *sfb)
-{
-	int i = 0, j = 0;
-	u32 m_nScreenStride;
-
-	dev_dbg(&sfb->pdev->dev,
-		"sfb->width=%d sfb->height=%d "
-		"sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n",
-		sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz);
-
-	for (j = 0; j < numVGAModes; j++) {
-		if (VGAMode[j].mmSizeX == sfb->width &&
-		    VGAMode[j].mmSizeY == sfb->height &&
-		    VGAMode[j].bpp == sfb->fb.var.bits_per_pixel &&
-		    VGAMode[j].hz == sfb->hz) {
-
-			dev_dbg(&sfb->pdev->dev,
-				"VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d "
-				"VGAMode[j].bpp=%d VGAMode[j].hz=%d\n",
-				VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
-				VGAMode[j].bpp, VGAMode[j].hz);
-
-			dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j);
-
-			smtc_mmiowb(0x0, 0x3c6);
-
-			smtc_seqw(0, 0x1);
-
-			smtc_mmiowb(VGAMode[j].Init_MISC, 0x3c2);
-
-			/* init SEQ register SR00 - SR04 */
-			for (i = 0; i < SIZE_SR00_SR04; i++)
-				smtc_seqw(i, VGAMode[j].Init_SR00_SR04[i]);
-
-			/* init SEQ register SR10 - SR24 */
-			for (i = 0; i < SIZE_SR10_SR24; i++)
-				smtc_seqw(i + 0x10,
-					  VGAMode[j].Init_SR10_SR24[i]);
-
-			/* init SEQ register SR30 - SR75 */
-			for (i = 0; i < SIZE_SR30_SR75; i++)
-				if (((i + 0x30) != 0x62) \
-					&& ((i + 0x30) != 0x6a) \
-					&& ((i + 0x30) != 0x6b))
-					smtc_seqw(i + 0x30,
-						VGAMode[j].Init_SR30_SR75[i]);
-
-			/* init SEQ register SR80 - SR93 */
-			for (i = 0; i < SIZE_SR80_SR93; i++)
-				smtc_seqw(i + 0x80,
-					  VGAMode[j].Init_SR80_SR93[i]);
-
-			/* init SEQ register SRA0 - SRAF */
-			for (i = 0; i < SIZE_SRA0_SRAF; i++)
-				smtc_seqw(i + 0xa0,
-					  VGAMode[j].Init_SRA0_SRAF[i]);
-
-			/* init Graphic register GR00 - GR08 */
-			for (i = 0; i < SIZE_GR00_GR08; i++)
-				smtc_grphw(i, VGAMode[j].Init_GR00_GR08[i]);
-
-			/* init Attribute register AR00 - AR14 */
-			for (i = 0; i < SIZE_AR00_AR14; i++)
-				smtc_attrw(i, VGAMode[j].Init_AR00_AR14[i]);
-
-			/* init CRTC register CR00 - CR18 */
-			for (i = 0; i < SIZE_CR00_CR18; i++)
-				smtc_crtcw(i, VGAMode[j].Init_CR00_CR18[i]);
-
-			/* init CRTC register CR30 - CR4D */
-			for (i = 0; i < SIZE_CR30_CR4D; i++)
-				smtc_crtcw(i + 0x30,
-					   VGAMode[j].Init_CR30_CR4D[i]);
-
-			/* init CRTC register CR90 - CRA7 */
-			for (i = 0; i < SIZE_CR90_CRA7; i++)
-				smtc_crtcw(i + 0x90,
-					   VGAMode[j].Init_CR90_CRA7[i]);
-		}
-	}
-	smtc_mmiowb(0x67, 0x3c2);
-
-	/* set VPR registers */
-	writel(0x0, sfb->m_pVPR + 0x0C);
-	writel(0x0, sfb->m_pVPR + 0x40);
-
-	/* set data width */
-	m_nScreenStride =
-		(sfb->width * sfb->fb.var.bits_per_pixel) / 64;
-	switch (sfb->fb.var.bits_per_pixel) {
-	case 8:
-		writel(0x0, sfb->m_pVPR + 0x0);
-		break;
-	case 16:
-		writel(0x00020000, sfb->m_pVPR + 0x0);
-		break;
-	case 24:
-		writel(0x00040000, sfb->m_pVPR + 0x0);
-		break;
-	case 32:
-		writel(0x00030000, sfb->m_pVPR + 0x0);
-		break;
-	}
-	writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
-	       sfb->m_pVPR + 0x10);
-
-}
-
-static void sm712_setpalette(int regno, unsigned red, unsigned green,
-			     unsigned blue, struct fb_info *info)
-{
-	struct smtcfb_info *sfb = info->par;
-
-	if (sfb->BaseAddressInVRAM)
-		/*
-		 * second display palette for dual head. Enable CRT RAM, 6-bit
-		 * RAM
-		 */
-		smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x20);
-	else
-		/* primary display palette. Enable LCD RAM only, 6-bit RAM */
-		smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
-	smtc_mmiowb(regno, dac_reg);
-	smtc_mmiowb(red >> 10, dac_val);
-	smtc_mmiowb(green >> 10, dac_val);
-	smtc_mmiowb(blue >> 10, dac_val);
-}
-
-static void smtc_set_timing(struct smtcfb_info *sfb)
-{
-	switch (sfb->chipID) {
-	case 0x710:
-	case 0x712:
-	case 0x720:
-		sm712_set_timing(sfb);
-		break;
-	}
-}
-
-/* chan_to_field
- *
- * convert a colour value into a field position
- *
- * from pxafb.c
- */
-
-static inline unsigned int chan_to_field(unsigned int chan,
-					 struct fb_bitfield *bf)
-{
-	chan &= 0xffff;
-	chan >>= 16 - bf->length;
-	return chan << bf->offset;
-}
-
-static int smtc_blank(int blank_mode, struct fb_info *info)
-{
-	/* clear DPMS setting */
-	switch (blank_mode) {
-	case FB_BLANK_UNBLANK:
-		/* Screen On: HSync: On, VSync : On */
-		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
-		smtc_seqw(0x6a, 0x16);
-		smtc_seqw(0x6b, 0x02);
-		smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
-		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
-		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
-		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
-		smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
-		break;
-	case FB_BLANK_NORMAL:
-		/* Screen Off: HSync: On, VSync : On   Soft blank */
-		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
-		smtc_seqw(0x6a, 0x16);
-		smtc_seqw(0x6b, 0x02);
-		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
-		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
-		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
-		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
-		break;
-	case FB_BLANK_VSYNC_SUSPEND:
-		/* Screen On: HSync: On, VSync : Off */
-		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
-		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
-		smtc_seqw(0x6a, 0x0c);
-		smtc_seqw(0x6b, 0x02);
-		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
-		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
-		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
-		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
-		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
-		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
-		break;
-	case FB_BLANK_HSYNC_SUSPEND:
-		/* Screen On: HSync: Off, VSync : On */
-		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
-		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
-		smtc_seqw(0x6a, 0x0c);
-		smtc_seqw(0x6b, 0x02);
-		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
-		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
-		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
-		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
-		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
-		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
-		break;
-	case FB_BLANK_POWERDOWN:
-		/* Screen On: HSync: Off, VSync : Off */
-		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
-		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
-		smtc_seqw(0x6a, 0x0c);
-		smtc_seqw(0x6b, 0x02);
-		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
-		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
-		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
-		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
-		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
-		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
-			  unsigned blue, unsigned trans, struct fb_info *info)
-{
-	struct smtcfb_info *sfb = (struct smtcfb_info *)info;
-	u32 val;
-
-	if (regno > 255)
-		return 1;
-
-	switch (sfb->fb.fix.visual) {
-	case FB_VISUAL_DIRECTCOLOR:
-	case FB_VISUAL_TRUECOLOR:
-		/*
-		 * 16/32 bit true-colour, use pseuo-palette for 16 base color
-		 */
-		if (regno < 16) {
-			if (sfb->fb.var.bits_per_pixel == 16) {
-				u32 *pal = sfb->fb.pseudo_palette;
-				val = chan_to_field(red, &sfb->fb.var.red);
-				val |= chan_to_field(green, \
-						&sfb->fb.var.green);
-				val |= chan_to_field(blue, &sfb->fb.var.blue);
-#ifdef __BIG_ENDIAN
-				pal[regno] =
-				    ((red & 0xf800) >> 8) |
-				    ((green & 0xe000) >> 13) |
-				    ((green & 0x1c00) << 3) |
-				    ((blue & 0xf800) >> 3);
-#else
-				pal[regno] = val;
-#endif
-			} else {
-				u32 *pal = sfb->fb.pseudo_palette;
-				val = chan_to_field(red, &sfb->fb.var.red);
-				val |= chan_to_field(green, \
-						&sfb->fb.var.green);
-				val |= chan_to_field(blue, &sfb->fb.var.blue);
-#ifdef __BIG_ENDIAN
-				val =
-				    (val & 0xff00ff00 >> 8) |
-				    (val & 0x00ff00ff << 8);
-#endif
-				pal[regno] = val;
-			}
-		}
-		break;
-
-	case FB_VISUAL_PSEUDOCOLOR:
-		/* color depth 8 bit */
-		sm712_setpalette(regno, red, green, blue, info);
-		break;
-
-	default:
-		return 1;	/* unknown type */
-	}
-
-	return 0;
-
-}
-
-#ifdef __BIG_ENDIAN
-static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t
-				count, loff_t *ppos)
-{
-	unsigned long p = *ppos;
-
-	u32 *buffer, *dst;
-	u32 __iomem *src;
-	int c, i, cnt = 0, err = 0;
-	unsigned long total_size;
-
-	if (!info || !info->screen_base)
-		return -ENODEV;
-
-	if (info->state != FBINFO_STATE_RUNNING)
-		return -EPERM;
-
-	total_size = info->screen_size;
-
-	if (total_size == 0)
-		total_size = info->fix.smem_len;
-
-	if (p >= total_size)
-		return 0;
-
-	if (count >= total_size)
-		count = total_size;
-
-	if (count + p > total_size)
-		count = total_size - p;
-
-	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
-	if (!buffer)
-		return -ENOMEM;
-
-	src = (u32 __iomem *) (info->screen_base + p);
-
-	if (info->fbops->fb_sync)
-		info->fbops->fb_sync(info);
-
-	while (count) {
-		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-		dst = buffer;
-		for (i = c >> 2; i--;) {
-			*dst = fb_readl(src++);
-			*dst =
-			    (*dst & 0xff00ff00 >> 8) |
-			    (*dst & 0x00ff00ff << 8);
-			dst++;
-		}
-		if (c & 3) {
-			u8 *dst8 = (u8 *) dst;
-			u8 __iomem *src8 = (u8 __iomem *) src;
-
-			for (i = c & 3; i--;) {
-				if (i & 1) {
-					*dst8++ = fb_readb(++src8);
-				} else {
-					*dst8++ = fb_readb(--src8);
-					src8 += 2;
-				}
-			}
-			src = (u32 __iomem *) src8;
-		}
-
-		if (copy_to_user(buf, buffer, c)) {
-			err = -EFAULT;
-			break;
-		}
-		*ppos += c;
-		buf += c;
-		cnt += c;
-		count -= c;
-	}
-
-	kfree(buffer);
-
-	return (err) ? err : cnt;
-}
-
-static ssize_t
-smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
-	     loff_t *ppos)
-{
-	unsigned long p = *ppos;
-
-	u32 *buffer, *src;
-	u32 __iomem *dst;
-	int c, i, cnt = 0, err = 0;
-	unsigned long total_size;
-
-	if (!info || !info->screen_base)
-		return -ENODEV;
-
-	if (info->state != FBINFO_STATE_RUNNING)
-		return -EPERM;
-
-	total_size = info->screen_size;
-
-	if (total_size == 0)
-		total_size = info->fix.smem_len;
-
-	if (p > total_size)
-		return -EFBIG;
-
-	if (count > total_size) {
-		err = -EFBIG;
-		count = total_size;
-	}
-
-	if (count + p > total_size) {
-		if (!err)
-			err = -ENOSPC;
-
-		count = total_size - p;
-	}
-
-	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
-	if (!buffer)
-		return -ENOMEM;
-
-	dst = (u32 __iomem *) (info->screen_base + p);
-
-	if (info->fbops->fb_sync)
-		info->fbops->fb_sync(info);
-
-	while (count) {
-		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-		src = buffer;
-
-		if (copy_from_user(src, buf, c)) {
-			err = -EFAULT;
-			break;
-		}
-
-		for (i = c >> 2; i--;) {
-			fb_writel((*src & 0xff00ff00 >> 8) |
-				  (*src & 0x00ff00ff << 8), dst++);
-			src++;
-		}
-		if (c & 3) {
-			u8 *src8 = (u8 *) src;
-			u8 __iomem *dst8 = (u8 __iomem *) dst;
-
-			for (i = c & 3; i--;) {
-				if (i & 1) {
-					fb_writeb(*src8++, ++dst8);
-				} else {
-					fb_writeb(*src8++, --dst8);
-					dst8 += 2;
-				}
-			}
-			dst = (u32 __iomem *) dst8;
-		}
-
-		*ppos += c;
-		buf += c;
-		cnt += c;
-		count -= c;
-	}
-
-	kfree(buffer);
-
-	return (cnt) ? cnt : err;
-}
-#endif	/* ! __BIG_ENDIAN */
-
-void smtcfb_setmode(struct smtcfb_info *sfb)
-{
-	switch (sfb->fb.var.bits_per_pixel) {
-	case 32:
-		sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
-		sfb->fb.fix.line_length = sfb->fb.var.xres * 4;
-		sfb->fb.var.red.length = 8;
-		sfb->fb.var.green.length = 8;
-		sfb->fb.var.blue.length = 8;
-		sfb->fb.var.red.offset = 16;
-		sfb->fb.var.green.offset = 8;
-		sfb->fb.var.blue.offset = 0;
-
-		break;
-	case 8:
-		sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
-		sfb->fb.fix.line_length = sfb->fb.var.xres;
-		sfb->fb.var.red.offset = 5;
-		sfb->fb.var.red.length = 3;
-		sfb->fb.var.green.offset = 2;
-		sfb->fb.var.green.length = 3;
-		sfb->fb.var.blue.offset = 0;
-		sfb->fb.var.blue.length = 2;
-		break;
-	case 24:
-		sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
-		sfb->fb.fix.line_length = sfb->fb.var.xres * 3;
-		sfb->fb.var.red.length = 8;
-		sfb->fb.var.green.length = 8;
-		sfb->fb.var.blue.length = 8;
-
-		sfb->fb.var.red.offset = 16;
-		sfb->fb.var.green.offset = 8;
-		sfb->fb.var.blue.offset = 0;
-
-		break;
-	case 16:
-	default:
-		sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
-		sfb->fb.fix.line_length = sfb->fb.var.xres * 2;
-
-		sfb->fb.var.red.length = 5;
-		sfb->fb.var.green.length = 6;
-		sfb->fb.var.blue.length = 5;
-
-		sfb->fb.var.red.offset = 11;
-		sfb->fb.var.green.offset = 5;
-		sfb->fb.var.blue.offset = 0;
-
-		break;
-	}
-
-	sfb->width = sfb->fb.var.xres;
-	sfb->height = sfb->fb.var.yres;
-	sfb->hz = 60;
-	smtc_set_timing(sfb);
-}
-
-static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
-	/* sanity checks */
-	if (var->xres_virtual < var->xres)
-		var->xres_virtual = var->xres;
-
-	if (var->yres_virtual < var->yres)
-		var->yres_virtual = var->yres;
-
-	/* set valid default bpp */
-	if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
-	    (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
-		var->bits_per_pixel = 16;
-
-	return 0;
-}
-
-static int smtc_set_par(struct fb_info *info)
-{
-	struct smtcfb_info *sfb = (struct smtcfb_info *)info;
-
-	smtcfb_setmode(sfb);
-
-	return 0;
-}
-
-static struct fb_ops smtcfb_ops = {
-	.owner        = THIS_MODULE,
-	.fb_check_var = smtc_check_var,
-	.fb_set_par   = smtc_set_par,
-	.fb_setcolreg = smtc_setcolreg,
-	.fb_blank     = smtc_blank,
-	.fb_fillrect  = cfb_fillrect,
-	.fb_imageblit = cfb_imageblit,
-	.fb_copyarea  = cfb_copyarea,
-#ifdef __BIG_ENDIAN
-	.fb_read      = smtcfb_read,
-	.fb_write     = smtcfb_write,
-#endif
-};
-
-/*
- * Alloc struct smtcfb_info and assign the default value
- */
-static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev, char *name)
-{
-	struct smtcfb_info *sfb;
-
-	sfb = kzalloc(sizeof(*sfb), GFP_KERNEL);
-
-	if (!sfb)
-		return NULL;
-
-	sfb->pdev = pdev;
-
-	/*** Init sfb->fb with default value ***/
-	sfb->fb.flags = FBINFO_FLAG_DEFAULT;
-	sfb->fb.fbops = &smtcfb_ops;
-	sfb->fb.var = smtcfb_var;
-	sfb->fb.fix = smtcfb_fix;
-
-	strcpy(sfb->fb.fix.id, name);
-
-	sfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
-	sfb->fb.fix.type_aux = 0;
-	sfb->fb.fix.xpanstep = 0;
-	sfb->fb.fix.ypanstep = 0;
-	sfb->fb.fix.ywrapstep = 0;
-	sfb->fb.fix.accel = FB_ACCEL_SMI_LYNX;
-
-	sfb->fb.var.nonstd = 0;
-	sfb->fb.var.activate = FB_ACTIVATE_NOW;
-	sfb->fb.var.height = -1;
-	sfb->fb.var.width = -1;
-	/* text mode acceleration */
-	sfb->fb.var.accel_flags = FB_ACCELF_TEXT;
-	sfb->fb.var.vmode = FB_VMODE_NONINTERLACED;
-
-	sfb->fb.par = sfb;
-
-	sfb->fb.pseudo_palette = colreg;
-
-	return sfb;
-}
-
-/*
- * Unmap in the memory mapped IO registers
- */
-
-static void smtc_unmap_mmio(struct smtcfb_info *sfb)
-{
-	if (sfb && smtc_RegBaseAddress)
-		smtc_RegBaseAddress = NULL;
-}
-
-/*
- * Map in the screen memory
- */
-
-static int smtc_map_smem(struct smtcfb_info *sfb,
-		struct pci_dev *pdev, u_long smem_len)
-{
-	if (sfb->fb.var.bits_per_pixel == 32) {
-#ifdef __BIG_ENDIAN
-		sfb->fb.fix.smem_start = pci_resource_start(pdev, 0)
-			+ 0x800000;
-#else
-		sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
-#endif
-	} else {
-		sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
-	}
-
-	sfb->fb.fix.smem_len = smem_len;
-
-	sfb->fb.screen_base = smtc_VRAMBaseAddress;
-
-	if (!sfb->fb.screen_base) {
-		dev_err(&pdev->dev,
-			"%s: unable to map screen memory\n", sfb->fb.fix.id);
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-/*
- * Unmap in the screen memory
- *
- */
-static void smtc_unmap_smem(struct smtcfb_info *sfb)
-{
-	if (sfb && sfb->fb.screen_base) {
-		iounmap(sfb->fb.screen_base);
-		sfb->fb.screen_base = NULL;
-	}
-}
-
-/*
- * We need to wake up the LynxEM+, and make sure its in linear memory mode.
- */
-static inline void sm7xx_init_hw(void)
-{
-	outb_p(0x18, 0x3c4);
-	outb_p(0x11, 0x3c5);
-}
-
-static void smtc_free_fb_info(struct smtcfb_info *sfb)
-{
-	if (sfb) {
-		fb_alloc_cmap(&sfb->fb.cmap, 0, 0);
-		kfree(sfb);
-	}
-}
-
-/*
- *	sm712vga_setup - process command line options, get vga parameter
- *	@options: string of options
- *	Returns zero.
- *
- */
-static int __init sm712vga_setup(char *options)
-{
-	int index;
-
-	if (!options || !*options)
-		return -EINVAL;
-
-	smtc_screen_info.lfb_width = 0;
-	smtc_screen_info.lfb_height = 0;
-	smtc_screen_info.lfb_depth = 0;
-
-	pr_debug("sm712vga_setup = %s\n", options);
-
-	for (index = 0;
-	     index < ARRAY_SIZE(vesa_mode);
-	     index++) {
-		if (strstr(options, vesa_mode[index].mode_index)) {
-			smtc_screen_info.lfb_width = vesa_mode[index].lfb_width;
-			smtc_screen_info.lfb_height =
-					vesa_mode[index].lfb_height;
-			smtc_screen_info.lfb_depth = vesa_mode[index].lfb_depth;
-			return 0;
-		}
-	}
-
-	return -1;
-}
-__setup("vga=", sm712vga_setup);
-
-static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
-				   const struct pci_device_id *ent)
-{
-	struct smtcfb_info *sfb;
-	u_long smem_size = 0x00800000;	/* default 8MB */
-	char name[16];
-	int err;
-	unsigned long pFramebufferPhysical;
-
-	dev_info(&pdev->dev, "Silicon Motion display driver.");
-
-	err = pci_enable_device(pdev);	/* enable SMTC chip */
-	if (err)
-		return err;
-
-	sfb = smtc_alloc_fb_info(pdev, name);
-
-	if (!sfb)
-		goto failed_free;
-
-	sfb->chipID = ent->device;
-	sprintf(name, "sm%Xfb", sfb->chipID);
-
-	pci_set_drvdata(pdev, sfb);
-
-	sm7xx_init_hw();
-
-	/*get mode parameter from smtc_screen_info */
-	if (smtc_screen_info.lfb_width != 0) {
-		sfb->fb.var.xres = smtc_screen_info.lfb_width;
-		sfb->fb.var.yres = smtc_screen_info.lfb_height;
-		sfb->fb.var.bits_per_pixel = smtc_screen_info.lfb_depth;
-	} else {
-		/* default resolution 1024x600 16bit mode */
-		sfb->fb.var.xres = SCREEN_X_RES;
-		sfb->fb.var.yres = SCREEN_Y_RES;
-		sfb->fb.var.bits_per_pixel = SCREEN_BPP;
-	}
-
-#ifdef __BIG_ENDIAN
-	if (sfb->fb.var.bits_per_pixel == 24)
-		sfb->fb.var.bits_per_pixel = (smtc_screen_info.lfb_depth = 32);
-#endif
-	/* Map address and memory detection */
-	pFramebufferPhysical = pci_resource_start(pdev, 0);
-	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chipRevID);
-
-	switch (sfb->chipID) {
-	case 0x710:
-	case 0x712:
-		sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000;
-		sfb->fb.fix.mmio_len = 0x00400000;
-		smem_size = SM712_VIDEOMEMORYSIZE;
-#ifdef __BIG_ENDIAN
-		sfb->m_pLFB = (smtc_VRAMBaseAddress =
-		    ioremap(pFramebufferPhysical, 0x00c00000));
-#else
-		sfb->m_pLFB = (smtc_VRAMBaseAddress =
-		    ioremap(pFramebufferPhysical, 0x00800000));
-#endif
-		sfb->m_pMMIO = (smtc_RegBaseAddress =
-		    smtc_VRAMBaseAddress + 0x00700000);
-		sfb->m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
-		sfb->m_pVPR = sfb->m_pLFB + 0x0040c000;
-#ifdef __BIG_ENDIAN
-		if (sfb->fb.var.bits_per_pixel == 32) {
-			smtc_VRAMBaseAddress += 0x800000;
-			sfb->m_pLFB += 0x800000;
-			dev_info(&pdev->dev,
-				 "smtc_VRAMBaseAddress=%p sfb->m_pLFB=%p",
-				  smtc_VRAMBaseAddress, sfb->m_pLFB);
-		}
-#endif
-		if (!smtc_RegBaseAddress) {
-			dev_err(&pdev->dev,
-				"%s: unable to map memory mapped IO!",
-				sfb->fb.fix.id);
-			err = -ENOMEM;
-			goto failed_fb;
-		}
-
-		/* set MCLK = 14.31818 * (0x16 / 0x2) */
-		smtc_seqw(0x6a, 0x16);
-		smtc_seqw(0x6b, 0x02);
-		smtc_seqw(0x62, 0x3e);
-		/* enable PCI burst */
-		smtc_seqw(0x17, 0x20);
-		/* enable word swap */
-#ifdef __BIG_ENDIAN
-		if (sfb->fb.var.bits_per_pixel == 32)
-			smtc_seqw(0x17, 0x30);
-#endif
-		break;
-	case 0x720:
-		sfb->fb.fix.mmio_start = pFramebufferPhysical;
-		sfb->fb.fix.mmio_len = 0x00200000;
-		smem_size = SM722_VIDEOMEMORYSIZE;
-		sfb->m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
-		sfb->m_pLFB = (smtc_VRAMBaseAddress =
-		    sfb->m_pDPR + 0x00200000);
-		sfb->m_pMMIO = (smtc_RegBaseAddress =
-		    sfb->m_pDPR + 0x000c0000);
-		sfb->m_pVPR = sfb->m_pDPR + 0x800;
-
-		smtc_seqw(0x62, 0xff);
-		smtc_seqw(0x6a, 0x0d);
-		smtc_seqw(0x6b, 0x02);
-		break;
-	default:
-		dev_err(&pdev->dev,
-			"No valid Silicon Motion display chip was detected!");
-
-		goto failed_fb;
-	}
-
-	/* can support 32 bpp */
-	if (15 == sfb->fb.var.bits_per_pixel)
-		sfb->fb.var.bits_per_pixel = 16;
-
-	sfb->fb.var.xres_virtual = sfb->fb.var.xres;
-	sfb->fb.var.yres_virtual = sfb->fb.var.yres;
-	err = smtc_map_smem(sfb, pdev, smem_size);
-	if (err)
-		goto failed;
-
-	smtcfb_setmode(sfb);
-	/* Primary display starting from 0 position */
-	sfb->BaseAddressInVRAM = 0;
-
-	err = register_framebuffer(&sfb->fb);
-	if (err < 0)
-		goto failed;
-
-	dev_info(&pdev->dev,
-		 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.",
-		 sfb->chipID, sfb->chipRevID, sfb->fb.var.xres,
-		 sfb->fb.var.yres, sfb->fb.var.bits_per_pixel);
-
-	return 0;
-
-failed:
-	dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.");
-
-	smtc_unmap_smem(sfb);
-	smtc_unmap_mmio(sfb);
-failed_fb:
-	smtc_free_fb_info(sfb);
-
-failed_free:
-	pci_disable_device(pdev);
-
-	return err;
-}
-
-
-static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = {
-	{ PCI_DEVICE(0x126f, 0x710), },
-	{ PCI_DEVICE(0x126f, 0x712), },
-	{ PCI_DEVICE(0x126f, 0x720), },
-	{0,}
-};
-
-
-static void __devexit smtcfb_pci_remove(struct pci_dev *pdev)
-{
-	struct smtcfb_info *sfb;
-
-	sfb = pci_get_drvdata(pdev);
-	pci_set_drvdata(pdev, NULL);
-	smtc_unmap_smem(sfb);
-	smtc_unmap_mmio(sfb);
-	unregister_framebuffer(&sfb->fb);
-	smtc_free_fb_info(sfb);
-}
-
-#ifdef CONFIG_PM
-static int smtcfb_pci_suspend(struct device *device)
-{
-	struct pci_dev *pdev = to_pci_dev(device);
-	struct smtcfb_info *sfb;
-
-	sfb = pci_get_drvdata(pdev);
-
-	/* set the hw in sleep mode use externel clock and self memory refresh
-	 * so that we can turn off internal PLLs later on
-	 */
-	smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
-	smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
-
-	console_lock();
-	fb_set_suspend(&sfb->fb, 1);
-	console_unlock();
-
-	/* additionally turn off all function blocks including internal PLLs */
-	smtc_seqw(0x21, 0xff);
-
-	return 0;
-}
-
-static int smtcfb_pci_resume(struct device *device)
-{
-	struct pci_dev *pdev = to_pci_dev(device);
-	struct smtcfb_info *sfb;
-
-	sfb = pci_get_drvdata(pdev);
-
-	/* reinit hardware */
-	sm7xx_init_hw();
-	switch (sfb->chipID) {
-	case 0x710:
-	case 0x712:
-		/* set MCLK = 14.31818 *  (0x16 / 0x2) */
-		smtc_seqw(0x6a, 0x16);
-		smtc_seqw(0x6b, 0x02);
-		smtc_seqw(0x62, 0x3e);
-		/* enable PCI burst */
-		smtc_seqw(0x17, 0x20);
-#ifdef __BIG_ENDIAN
-		if (sfb->fb.var.bits_per_pixel == 32)
-			smtc_seqw(0x17, 0x30);
-#endif
-		break;
-	case 0x720:
-		smtc_seqw(0x62, 0xff);
-		smtc_seqw(0x6a, 0x0d);
-		smtc_seqw(0x6b, 0x02);
-		break;
-	}
-
-	smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
-	smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
-
-	smtcfb_setmode(sfb);
-
-	console_lock();
-	fb_set_suspend(&sfb->fb, 0);
-	console_unlock();
-
-	return 0;
-}
-
-static const struct dev_pm_ops sm7xx_pm_ops = {
-	.suspend = smtcfb_pci_suspend,
-	.resume = smtcfb_pci_resume,
-	.freeze = smtcfb_pci_suspend,
-	.thaw = smtcfb_pci_resume,
-	.poweroff = smtcfb_pci_suspend,
-	.restore = smtcfb_pci_resume,
-};
-
-#define SM7XX_PM_OPS (&sm7xx_pm_ops)
-
-#else  /* !CONFIG_PM */
-
-#define SM7XX_PM_OPS NULL
-
-#endif /* !CONFIG_PM */
-
-static struct pci_driver smtcfb_driver = {
-	.name = "smtcfb",
-	.id_table = smtcfb_pci_table,
-	.probe = smtcfb_pci_probe,
-	.remove = __devexit_p(smtcfb_pci_remove),
-	.driver.pm  = SM7XX_PM_OPS,
-};
-
-static int __init smtcfb_init(void)
-{
-	return pci_register_driver(&smtcfb_driver);
-}
-
-static void __exit smtcfb_exit(void)
-{
-	pci_unregister_driver(&smtcfb_driver);
-}
-
-module_init(smtcfb_init);
-module_exit(smtcfb_exit);
-
-MODULE_AUTHOR("Siliconmotion ");
-MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/sm7xx/smtcfb.h b/drivers/staging/sm7xx/smtcfb.h
deleted file mode 100644
index 43d86f8..0000000
--- a/drivers/staging/sm7xx/smtcfb.h
+++ /dev/null
@@ -1,780 +0,0 @@
-/*
- * Silicon Motion SM712 frame buffer device
- *
- * Copyright (C) 2006 Silicon Motion Technology Corp.
- * Authors:	Ge Wang, gewang@siliconmotion.com
- *		Boyod boyod.yang@siliconmotion.com.cn
- *
- * Copyright (C) 2009 Lemote, Inc.
- * Author: Wu Zhangjin, wuzhangjin@gmail.com
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License. See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#define NR_PALETTE        256
-#define NR_RGB            2
-
-#define FB_ACCEL_SMI_LYNX 88
-
-#define SCREEN_X_RES      1024
-#define SCREEN_Y_RES      600
-#define SCREEN_BPP        16
-
-/*Assume SM712 graphics chip has 4MB VRAM */
-#define SM712_VIDEOMEMORYSIZE	  0x00400000
-/*Assume SM722 graphics chip has 8MB VRAM */
-#define SM722_VIDEOMEMORYSIZE	  0x00800000
-
-#define dac_reg	(0x3c8)
-#define dac_val	(0x3c9)
-
-extern char __iomem *smtc_RegBaseAddress;
-#define smtc_mmiowb(dat, reg)	writeb(dat, smtc_RegBaseAddress + reg)
-#define smtc_mmioww(dat, reg)	writew(dat, smtc_RegBaseAddress + reg)
-#define smtc_mmiowl(dat, reg)	writel(dat, smtc_RegBaseAddress + reg)
-
-#define smtc_mmiorb(reg)	readb(smtc_RegBaseAddress + reg)
-#define smtc_mmiorw(reg)	readw(smtc_RegBaseAddress + reg)
-#define smtc_mmiorl(reg)	readl(smtc_RegBaseAddress + reg)
-
-#define SIZE_SR00_SR04      (0x04 - 0x00 + 1)
-#define SIZE_SR10_SR24      (0x24 - 0x10 + 1)
-#define SIZE_SR30_SR75      (0x75 - 0x30 + 1)
-#define SIZE_SR80_SR93      (0x93 - 0x80 + 1)
-#define SIZE_SRA0_SRAF      (0xAF - 0xA0 + 1)
-#define SIZE_GR00_GR08      (0x08 - 0x00 + 1)
-#define SIZE_AR00_AR14      (0x14 - 0x00 + 1)
-#define SIZE_CR00_CR18      (0x18 - 0x00 + 1)
-#define SIZE_CR30_CR4D      (0x4D - 0x30 + 1)
-#define SIZE_CR90_CRA7      (0xA7 - 0x90 + 1)
-#define SIZE_VPR		(0x6C + 1)
-#define SIZE_DPR		(0x44 + 1)
-
-static inline void smtc_crtcw(int reg, int val)
-{
-	smtc_mmiowb(reg, 0x3d4);
-	smtc_mmiowb(val, 0x3d5);
-}
-
-static inline unsigned int smtc_crtcr(int reg)
-{
-	smtc_mmiowb(reg, 0x3d4);
-	return smtc_mmiorb(0x3d5);
-}
-
-static inline void smtc_grphw(int reg, int val)
-{
-	smtc_mmiowb(reg, 0x3ce);
-	smtc_mmiowb(val, 0x3cf);
-}
-
-static inline unsigned int smtc_grphr(int reg)
-{
-	smtc_mmiowb(reg, 0x3ce);
-	return smtc_mmiorb(0x3cf);
-}
-
-static inline void smtc_attrw(int reg, int val)
-{
-	smtc_mmiorb(0x3da);
-	smtc_mmiowb(reg, 0x3c0);
-	smtc_mmiorb(0x3c1);
-	smtc_mmiowb(val, 0x3c0);
-}
-
-static inline void smtc_seqw(int reg, int val)
-{
-	smtc_mmiowb(reg, 0x3c4);
-	smtc_mmiowb(val, 0x3c5);
-}
-
-static inline unsigned int smtc_seqr(int reg)
-{
-	smtc_mmiowb(reg, 0x3c4);
-	return smtc_mmiorb(0x3c5);
-}
-
-/* The next structure holds all information relevant for a specific video mode.
- */
-
-struct ModeInit {
-	int mmSizeX;
-	int mmSizeY;
-	int bpp;
-	int hz;
-	unsigned char Init_MISC;
-	unsigned char Init_SR00_SR04[SIZE_SR00_SR04];
-	unsigned char Init_SR10_SR24[SIZE_SR10_SR24];
-	unsigned char Init_SR30_SR75[SIZE_SR30_SR75];
-	unsigned char Init_SR80_SR93[SIZE_SR80_SR93];
-	unsigned char Init_SRA0_SRAF[SIZE_SRA0_SRAF];
-	unsigned char Init_GR00_GR08[SIZE_GR00_GR08];
-	unsigned char Init_AR00_AR14[SIZE_AR00_AR14];
-	unsigned char Init_CR00_CR18[SIZE_CR00_CR18];
-	unsigned char Init_CR30_CR4D[SIZE_CR30_CR4D];
-	unsigned char Init_CR90_CRA7[SIZE_CR90_CRA7];
-};
-
-/**********************************************************************
-			 SM712 Mode table.
- **********************************************************************/
-struct ModeInit VGAMode[] = {
-	{
-	 /*  mode#0: 640 x 480  16Bpp  60Hz */
-	 640, 480, 16, 60,
-	 /*  Init_MISC */
-	 0xE3,
-	 {			/*  Init_SR0_SR4 */
-	  0x03, 0x01, 0x0F, 0x00, 0x0E,
-	  },
-	 {			/*  Init_SR10_SR24 */
-	  0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xC4, 0x30, 0x02, 0x01, 0x01,
-	  },
-	 {			/*  Init_SR30_SR75 */
-	  0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
-	  0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
-	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
-	  0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
-	  0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
-	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-	  0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
-	  0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
-	  },
-	 {			/*  Init_SR80_SR93 */
-	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
-	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
-	  0x00, 0x00, 0x00, 0x00,
-	  },
-	 {			/*  Init_SRA0_SRAF */
-	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
-	  },
-	 {			/*  Init_GR00_GR08 */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-	  0xFF,
-	  },
-	 {			/*  Init_AR00_AR14 */
-	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-	  0x41, 0x00, 0x0F, 0x00, 0x00,
-	  },
-	 {			/*  Init_CR00_CR18 */
-	  0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
-	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
-	  0xFF,
-	  },
-	 {			/*  Init_CR30_CR4D */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
-	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
-	  0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
-	  0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
-	  },
-	 {			/*  Init_CR90_CRA7 */
-	  0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
-	  0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
-	  0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
-	  },
-	 },
-	{
-	 /*  mode#1: 640 x 480  24Bpp  60Hz */
-	 640, 480, 24, 60,
-	 /*  Init_MISC */
-	 0xE3,
-	 {			/*  Init_SR0_SR4 */
-	  0x03, 0x01, 0x0F, 0x00, 0x0E,
-	  },
-	 {			/*  Init_SR10_SR24 */
-	  0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xC4, 0x30, 0x02, 0x01, 0x01,
-	  },
-	 {			/*  Init_SR30_SR75 */
-	  0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
-	  0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
-	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
-	  0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
-	  0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
-	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-	  0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
-	  0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
-	  },
-	 {			/*  Init_SR80_SR93 */
-	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
-	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
-	  0x00, 0x00, 0x00, 0x00,
-	  },
-	 {			/*  Init_SRA0_SRAF */
-	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
-	  },
-	 {			/*  Init_GR00_GR08 */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-	  0xFF,
-	  },
-	 {			/*  Init_AR00_AR14 */
-	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-	  0x41, 0x00, 0x0F, 0x00, 0x00,
-	  },
-	 {			/*  Init_CR00_CR18 */
-	  0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
-	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
-	  0xFF,
-	  },
-	 {			/*  Init_CR30_CR4D */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
-	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
-	  0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
-	  0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
-	  },
-	 {			/*  Init_CR90_CRA7 */
-	  0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
-	  0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
-	  0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
-	  },
-	 },
-	{
-	 /*  mode#0: 640 x 480  32Bpp  60Hz */
-	 640, 480, 32, 60,
-	 /*  Init_MISC */
-	 0xE3,
-	 {			/*  Init_SR0_SR4 */
-	  0x03, 0x01, 0x0F, 0x00, 0x0E,
-	  },
-	 {			/*  Init_SR10_SR24 */
-	  0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xC4, 0x30, 0x02, 0x01, 0x01,
-	  },
-	 {			/*  Init_SR30_SR75 */
-	  0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
-	  0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
-	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
-	  0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
-	  0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
-	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-	  0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
-	  0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
-	  },
-	 {			/*  Init_SR80_SR93 */
-	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
-	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
-	  0x00, 0x00, 0x00, 0x00,
-	  },
-	 {			/*  Init_SRA0_SRAF */
-	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
-	  },
-	 {			/*  Init_GR00_GR08 */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-	  0xFF,
-	  },
-	 {			/*  Init_AR00_AR14 */
-	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-	  0x41, 0x00, 0x0F, 0x00, 0x00,
-	  },
-	 {			/*  Init_CR00_CR18 */
-	  0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
-	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
-	  0xFF,
-	  },
-	 {			/*  Init_CR30_CR4D */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
-	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
-	  0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
-	  0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
-	  },
-	 {			/*  Init_CR90_CRA7 */
-	  0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
-	  0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
-	  0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
-	  },
-	 },
-
-	{			/*  mode#2: 800 x 600  16Bpp  60Hz */
-	 800, 600, 16, 60,
-	 /*  Init_MISC */
-	 0x2B,
-	 {			/*  Init_SR0_SR4 */
-	  0x03, 0x01, 0x0F, 0x03, 0x0E,
-	  },
-	 {			/*  Init_SR10_SR24 */
-	  0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-	  0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xC4, 0x30, 0x02, 0x01, 0x01,
-	  },
-	 {			/*  Init_SR30_SR75 */
-	  0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
-	  0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
-	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
-	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
-	  0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
-	  0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
-	  0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-	  0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
-	  0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
-	  },
-	 {			/*  Init_SR80_SR93 */
-	  0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
-	  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
-	  0x00, 0x00, 0x00, 0x00,
-	  },
-	 {			/*  Init_SRA0_SRAF */
-	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
-	  },
-	 {			/*  Init_GR00_GR08 */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-	  0xFF,
-	  },
-	 {			/*  Init_AR00_AR14 */
-	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-	  0x41, 0x00, 0x0F, 0x00, 0x00,
-	  },
-	 {			/*  Init_CR00_CR18 */
-	  0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
-	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
-	  0xFF,
-	  },
-	 {			/*  Init_CR30_CR4D */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
-	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
-	  0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
-	  0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
-	  },
-	 {			/*  Init_CR90_CRA7 */
-	  0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
-	  0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
-	  0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
-	  },
-	 },
-	{			/*  mode#3: 800 x 600  24Bpp  60Hz */
-	 800, 600, 24, 60,
-	 0x2B,
-	 {			/*  Init_SR0_SR4 */
-	  0x03, 0x01, 0x0F, 0x03, 0x0E,
-	  },
-	 {			/*  Init_SR10_SR24 */
-	  0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xC4, 0x30, 0x02, 0x01, 0x01,
-	  },
-	 {			/*  Init_SR30_SR75 */
-	  0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
-	  0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
-	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
-	  0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
-	  0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
-	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-	  0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
-	  0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
-	  },
-	 {			/*  Init_SR80_SR93 */
-	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
-	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
-	  0x00, 0x00, 0x00, 0x00,
-	  },
-	 {			/*  Init_SRA0_SRAF */
-	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
-	  },
-	 {			/*  Init_GR00_GR08 */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-	  0xFF,
-	  },
-	 {			/*  Init_AR00_AR14 */
-	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-	  0x41, 0x00, 0x0F, 0x00, 0x00,
-	  },
-	 {			/*  Init_CR00_CR18 */
-	  0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
-	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
-	  0xFF,
-	  },
-	 {			/*  Init_CR30_CR4D */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
-	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
-	  0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
-	  0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
-	  },
-	 {			/*  Init_CR90_CRA7 */
-	  0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
-	  0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
-	  0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
-	  },
-	 },
-	{			/*  mode#7: 800 x 600  32Bpp  60Hz */
-	 800, 600, 32, 60,
-	 /*  Init_MISC */
-	 0x2B,
-	 {			/*  Init_SR0_SR4 */
-	  0x03, 0x01, 0x0F, 0x03, 0x0E,
-	  },
-	 {			/*  Init_SR10_SR24 */
-	  0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-	  0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xC4, 0x30, 0x02, 0x01, 0x01,
-	  },
-	 {			/*  Init_SR30_SR75 */
-	  0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
-	  0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
-	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
-	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
-	  0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
-	  0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
-	  0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-	  0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
-	  0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
-	  },
-	 {			/*  Init_SR80_SR93 */
-	  0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
-	  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
-	  0x00, 0x00, 0x00, 0x00,
-	  },
-	 {			/*  Init_SRA0_SRAF */
-	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
-	  },
-	 {			/*  Init_GR00_GR08 */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-	  0xFF,
-	  },
-	 {			/*  Init_AR00_AR14 */
-	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-	  0x41, 0x00, 0x0F, 0x00, 0x00,
-	  },
-	 {			/*  Init_CR00_CR18 */
-	  0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
-	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
-	  0xFF,
-	  },
-	 {			/*  Init_CR30_CR4D */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
-	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
-	  0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
-	  0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
-	  },
-	 {			/*  Init_CR90_CRA7 */
-	  0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
-	  0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
-	  0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
-	  },
-	 },
-	/* We use 1024x768 table to light 1024x600 panel for lemote */
-	{			/*  mode#4: 1024 x 600  16Bpp  60Hz  */
-	 1024, 600, 16, 60,
-	 /*  Init_MISC */
-	 0xEB,
-	 {			/*  Init_SR0_SR4 */
-	  0x03, 0x01, 0x0F, 0x00, 0x0E,
-	  },
-	 {			/*  Init_SR10_SR24 */
-	  0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
-	  0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xC4, 0x30, 0x02, 0x00, 0x01,
-	  },
-	 {			/*  Init_SR30_SR75 */
-	  0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
-	  0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
-	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
-	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
-	  0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
-	  0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-	  0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
-	  0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
-	  },
-	 {			/*  Init_SR80_SR93 */
-	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
-	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
-	  0x00, 0x00, 0x00, 0x00,
-	  },
-	 {			/*  Init_SRA0_SRAF */
-	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
-	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
-	  },
-	 {			/*  Init_GR00_GR08 */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-	  0xFF,
-	  },
-	 {			/*  Init_AR00_AR14 */
-	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-	  0x41, 0x00, 0x0F, 0x00, 0x00,
-	  },
-	 {			/*  Init_CR00_CR18 */
-	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
-	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
-	  0xFF,
-	  },
-	 {			/*  Init_CR30_CR4D */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
-	  0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
-	  0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
-	  0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
-	  },
-	 {			/*  Init_CR90_CRA7 */
-	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
-	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
-	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
-	  },
-	 },
-	{			/*  mode#5: 1024 x 768  24Bpp  60Hz */
-	 1024, 768, 24, 60,
-	 /*  Init_MISC */
-	 0xEB,
-	 {			/*  Init_SR0_SR4 */
-	  0x03, 0x01, 0x0F, 0x03, 0x0E,
-	  },
-	 {			/*  Init_SR10_SR24 */
-	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
-	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xC4, 0x30, 0x02, 0x01, 0x01,
-	  },
-	 {			/*  Init_SR30_SR75 */
-	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
-	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
-	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
-	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
-	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
-	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-	  0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
-	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
-	  },
-	 {			/*  Init_SR80_SR93 */
-	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
-	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
-	  0x00, 0x00, 0x00, 0x00,
-	  },
-	 {			/*  Init_SRA0_SRAF */
-	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
-	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
-	  },
-	 {			/*  Init_GR00_GR08 */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-	  0xFF,
-	  },
-	 {			/*  Init_AR00_AR14 */
-	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-	  0x41, 0x00, 0x0F, 0x00, 0x00,
-	  },
-	 {			/*  Init_CR00_CR18 */
-	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
-	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
-	  0xFF,
-	  },
-	 {			/*  Init_CR30_CR4D */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
-	  0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
-	  0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
-	  0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
-	  },
-	 {			/*  Init_CR90_CRA7 */
-	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
-	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
-	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
-	  },
-	 },
-	{			/*  mode#4: 1024 x 768  32Bpp  60Hz */
-	 1024, 768, 32, 60,
-	 /*  Init_MISC */
-	 0xEB,
-	 {			/*  Init_SR0_SR4 */
-	  0x03, 0x01, 0x0F, 0x03, 0x0E,
-	  },
-	 {			/*  Init_SR10_SR24 */
-	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
-	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xC4, 0x32, 0x02, 0x01, 0x01,
-	  },
-	 {			/*  Init_SR30_SR75 */
-	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
-	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
-	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
-	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
-	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
-	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-	  0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
-	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
-	  },
-	 {			/*  Init_SR80_SR93 */
-	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
-	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
-	  0x00, 0x00, 0x00, 0x00,
-	  },
-	 {			/*  Init_SRA0_SRAF */
-	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
-	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
-	  },
-	 {			/*  Init_GR00_GR08 */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-	  0xFF,
-	  },
-	 {			/*  Init_AR00_AR14 */
-	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-	  0x41, 0x00, 0x0F, 0x00, 0x00,
-	  },
-	 {			/*  Init_CR00_CR18 */
-	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
-	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
-	  0xFF,
-	  },
-	 {			/*  Init_CR30_CR4D */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
-	  0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
-	  0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
-	  0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
-	  },
-	 {			/*  Init_CR90_CRA7 */
-	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
-	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
-	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
-	  },
-	 },
-	{			/*  mode#6: 320 x 240  16Bpp  60Hz */
-	 320, 240, 16, 60,
-	 /*  Init_MISC */
-	 0xEB,
-	 {			/*  Init_SR0_SR4 */
-	  0x03, 0x01, 0x0F, 0x03, 0x0E,
-	  },
-	 {			/*  Init_SR10_SR24 */
-	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
-	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xC4, 0x32, 0x02, 0x01, 0x01,
-	  },
-	 {			/*  Init_SR30_SR75 */
-	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
-	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
-	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
-	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
-	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
-	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-	  0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
-	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
-	  },
-	 {			/*  Init_SR80_SR93 */
-	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
-	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
-	  0x00, 0x00, 0x00, 0x00,
-	  },
-	 {			/*  Init_SRA0_SRAF */
-	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
-	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
-	  },
-	 {			/*  Init_GR00_GR08 */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-	  0xFF,
-	  },
-	 {			/*  Init_AR00_AR14 */
-	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-	  0x41, 0x00, 0x0F, 0x00, 0x00,
-	  },
-	 {			/*  Init_CR00_CR18 */
-	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
-	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
-	  0xFF,
-	  },
-	 {			/*  Init_CR30_CR4D */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
-	  0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
-	  0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
-	  0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
-	  },
-	 {			/*  Init_CR90_CRA7 */
-	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
-	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
-	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
-	  },
-	 },
-
-	{			/*  mode#8: 320 x 240  32Bpp  60Hz */
-	 320, 240, 32, 60,
-	 /*  Init_MISC */
-	 0xEB,
-	 {			/*  Init_SR0_SR4 */
-	  0x03, 0x01, 0x0F, 0x03, 0x0E,
-	  },
-	 {			/*  Init_SR10_SR24 */
-	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
-	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0xC4, 0x32, 0x02, 0x01, 0x01,
-	  },
-	 {			/*  Init_SR30_SR75 */
-	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
-	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
-	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
-	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
-	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
-	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-	  0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
-	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
-	  },
-	 {			/*  Init_SR80_SR93 */
-	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
-	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
-	  0x00, 0x00, 0x00, 0x00,
-	  },
-	 {			/*  Init_SRA0_SRAF */
-	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
-	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
-	  },
-	 {			/*  Init_GR00_GR08 */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-	  0xFF,
-	  },
-	 {			/*  Init_AR00_AR14 */
-	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-	  0x41, 0x00, 0x0F, 0x00, 0x00,
-	  },
-	 {			/*  Init_CR00_CR18 */
-	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
-	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
-	  0xFF,
-	  },
-	 {			/*  Init_CR30_CR4D */
-	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
-	  0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
-	  0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
-	  0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
-	  },
-	 {			/*  Init_CR90_CRA7 */
-	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
-	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
-	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
-	  },
-	 },
-};
-
-#define numVGAModes		ARRAY_SIZE(VGAMode)
diff --git a/drivers/staging/sm7xxfb/Kconfig b/drivers/staging/sm7xxfb/Kconfig
new file mode 100644
index 0000000..d5013f8
--- /dev/null
+++ b/drivers/staging/sm7xxfb/Kconfig
@@ -0,0 +1,13 @@
+config FB_SM7XX
+	tristate "Silicon Motion SM7XX framebuffer support"
+	depends on FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  Frame buffer driver for the Silicon Motion SM710, SM712, SM721
+	  and SM722 chips.
+
+	  This driver is also available as a module. The module will be
+	  called sm7xxfb. If you want to compile it as a module, say M
+	  here and read <file:Documentation/kbuild/modules.txt>.
diff --git a/drivers/staging/sm7xxfb/Makefile b/drivers/staging/sm7xxfb/Makefile
new file mode 100644
index 0000000..48f471c
--- /dev/null
+++ b/drivers/staging/sm7xxfb/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_FB_SM7XX) += sm7xxfb.o
diff --git a/drivers/staging/sm7xxfb/TODO b/drivers/staging/sm7xxfb/TODO
new file mode 100644
index 0000000..1fcead5
--- /dev/null
+++ b/drivers/staging/sm7xxfb/TODO
@@ -0,0 +1,9 @@
+TODO:
+- Dual head support
+- 2D acceleration support
+- use kernel coding style
+- refine the code and remove unused code
+- move it to drivers/video/sm7xxfb.c
+
+Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and
+Teddy Wang <teddy.wang@siliconmotion.com.cn>.
diff --git a/drivers/staging/sm7xxfb/sm7xx.h b/drivers/staging/sm7xxfb/sm7xx.h
new file mode 100644
index 0000000..333f33c
--- /dev/null
+++ b/drivers/staging/sm7xxfb/sm7xx.h
@@ -0,0 +1,779 @@
+/*
+ * Silicon Motion SM712 frame buffer device
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Authors:	Ge Wang, gewang@siliconmotion.com
+ *		Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#define NR_PALETTE        256
+
+#define FB_ACCEL_SMI_LYNX 88
+
+#define SCREEN_X_RES      1024
+#define SCREEN_Y_RES      600
+#define SCREEN_BPP        16
+
+/*Assume SM712 graphics chip has 4MB VRAM */
+#define SM712_VIDEOMEMORYSIZE	  0x00400000
+/*Assume SM722 graphics chip has 8MB VRAM */
+#define SM722_VIDEOMEMORYSIZE	  0x00800000
+
+#define dac_reg	(0x3c8)
+#define dac_val	(0x3c9)
+
+extern char __iomem *smtc_RegBaseAddress;
+#define smtc_mmiowb(dat, reg)	writeb(dat, smtc_RegBaseAddress + reg)
+#define smtc_mmioww(dat, reg)	writew(dat, smtc_RegBaseAddress + reg)
+#define smtc_mmiowl(dat, reg)	writel(dat, smtc_RegBaseAddress + reg)
+
+#define smtc_mmiorb(reg)	readb(smtc_RegBaseAddress + reg)
+#define smtc_mmiorw(reg)	readw(smtc_RegBaseAddress + reg)
+#define smtc_mmiorl(reg)	readl(smtc_RegBaseAddress + reg)
+
+#define SIZE_SR00_SR04      (0x04 - 0x00 + 1)
+#define SIZE_SR10_SR24      (0x24 - 0x10 + 1)
+#define SIZE_SR30_SR75      (0x75 - 0x30 + 1)
+#define SIZE_SR80_SR93      (0x93 - 0x80 + 1)
+#define SIZE_SRA0_SRAF      (0xAF - 0xA0 + 1)
+#define SIZE_GR00_GR08      (0x08 - 0x00 + 1)
+#define SIZE_AR00_AR14      (0x14 - 0x00 + 1)
+#define SIZE_CR00_CR18      (0x18 - 0x00 + 1)
+#define SIZE_CR30_CR4D      (0x4D - 0x30 + 1)
+#define SIZE_CR90_CRA7      (0xA7 - 0x90 + 1)
+#define SIZE_VPR		(0x6C + 1)
+#define SIZE_DPR		(0x44 + 1)
+
+static inline void smtc_crtcw(int reg, int val)
+{
+	smtc_mmiowb(reg, 0x3d4);
+	smtc_mmiowb(val, 0x3d5);
+}
+
+static inline unsigned int smtc_crtcr(int reg)
+{
+	smtc_mmiowb(reg, 0x3d4);
+	return smtc_mmiorb(0x3d5);
+}
+
+static inline void smtc_grphw(int reg, int val)
+{
+	smtc_mmiowb(reg, 0x3ce);
+	smtc_mmiowb(val, 0x3cf);
+}
+
+static inline unsigned int smtc_grphr(int reg)
+{
+	smtc_mmiowb(reg, 0x3ce);
+	return smtc_mmiorb(0x3cf);
+}
+
+static inline void smtc_attrw(int reg, int val)
+{
+	smtc_mmiorb(0x3da);
+	smtc_mmiowb(reg, 0x3c0);
+	smtc_mmiorb(0x3c1);
+	smtc_mmiowb(val, 0x3c0);
+}
+
+static inline void smtc_seqw(int reg, int val)
+{
+	smtc_mmiowb(reg, 0x3c4);
+	smtc_mmiowb(val, 0x3c5);
+}
+
+static inline unsigned int smtc_seqr(int reg)
+{
+	smtc_mmiowb(reg, 0x3c4);
+	return smtc_mmiorb(0x3c5);
+}
+
+/* The next structure holds all information relevant for a specific video mode.
+ */
+
+struct ModeInit {
+	int mmSizeX;
+	int mmSizeY;
+	int bpp;
+	int hz;
+	unsigned char Init_MISC;
+	unsigned char Init_SR00_SR04[SIZE_SR00_SR04];
+	unsigned char Init_SR10_SR24[SIZE_SR10_SR24];
+	unsigned char Init_SR30_SR75[SIZE_SR30_SR75];
+	unsigned char Init_SR80_SR93[SIZE_SR80_SR93];
+	unsigned char Init_SRA0_SRAF[SIZE_SRA0_SRAF];
+	unsigned char Init_GR00_GR08[SIZE_GR00_GR08];
+	unsigned char Init_AR00_AR14[SIZE_AR00_AR14];
+	unsigned char Init_CR00_CR18[SIZE_CR00_CR18];
+	unsigned char Init_CR30_CR4D[SIZE_CR30_CR4D];
+	unsigned char Init_CR90_CRA7[SIZE_CR90_CRA7];
+};
+
+/**********************************************************************
+			 SM712 Mode table.
+ **********************************************************************/
+struct ModeInit VGAMode[] = {
+	{
+	 /*  mode#0: 640 x 480  16Bpp  60Hz */
+	 640, 480, 16, 60,
+	 /*  Init_MISC */
+	 0xE3,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x00, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+	  0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+	  0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+	  0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+	  0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+	  0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+	  0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+	  0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+	  0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+	  },
+	 },
+	{
+	 /*  mode#1: 640 x 480  24Bpp  60Hz */
+	 640, 480, 24, 60,
+	 /*  Init_MISC */
+	 0xE3,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x00, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+	  0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+	  0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+	  0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+	  0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+	  0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+	  0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+	  0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+	  0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+	  },
+	 },
+	{
+	 /*  mode#0: 640 x 480  32Bpp  60Hz */
+	 640, 480, 32, 60,
+	 /*  Init_MISC */
+	 0xE3,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x00, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+	  0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+	  0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+	  0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+	  0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+	  0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+	  0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+	  0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+	  0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+	  },
+	 },
+
+	{			/*  mode#2: 800 x 600  16Bpp  60Hz */
+	 800, 600, 16, 60,
+	 /*  Init_MISC */
+	 0x2B,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
+	  0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
+	  0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+	  0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
+	  0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+	  0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
+	  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+	  0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+	  0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+	  0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+	  0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+	  },
+	 },
+	{			/*  mode#3: 800 x 600  24Bpp  60Hz */
+	 800, 600, 24, 60,
+	 0x2B,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
+	  0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
+	  0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+	  0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+	  0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
+	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+	  0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+	  0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+	  0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+	  0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+	  },
+	 },
+	{			/*  mode#7: 800 x 600  32Bpp  60Hz */
+	 800, 600, 32, 60,
+	 /*  Init_MISC */
+	 0x2B,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
+	  0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
+	  0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+	  0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
+	  0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+	  0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
+	  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+	  0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+	  0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+	  0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+	  0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+	  },
+	 },
+	/* We use 1024x768 table to light 1024x600 panel for lemote */
+	{			/*  mode#4: 1024 x 600  16Bpp  60Hz  */
+	 1024, 600, 16, 60,
+	 /*  Init_MISC */
+	 0xEB,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x00, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
+	  0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x00, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
+	  0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
+	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+	  0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
+	  0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
+	  0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+	  0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
+	  0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+	  },
+	 },
+	{			/*  mode#5: 1024 x 768  24Bpp  60Hz */
+	 1024, 768, 24, 60,
+	 /*  Init_MISC */
+	 0xEB,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
+	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+	  0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
+	  0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+	  },
+	 },
+	{			/*  mode#4: 1024 x 768  32Bpp  60Hz */
+	 1024, 768, 32, 60,
+	 /*  Init_MISC */
+	 0xEB,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x32, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
+	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+	  0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
+	  0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+	  },
+	 },
+	{			/*  mode#6: 320 x 240  16Bpp  60Hz */
+	 320, 240, 16, 60,
+	 /*  Init_MISC */
+	 0xEB,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x32, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
+	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+	  0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+	  0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
+	  0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+	  },
+	 },
+
+	{			/*  mode#8: 320 x 240  32Bpp  60Hz */
+	 320, 240, 32, 60,
+	 /*  Init_MISC */
+	 0xEB,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x32, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
+	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+	  0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+	  0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
+	  0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+	  },
+	 },
+};
+
+#define numVGAModes		ARRAY_SIZE(VGAMode)
diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c
new file mode 100644
index 0000000..16d2b5e
--- /dev/null
+++ b/drivers/staging/sm7xxfb/sm7xxfb.c
@@ -0,0 +1,1077 @@
+/*
+ * Silicon Motion SM7XX frame buffer device
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Authors:  Ge Wang, gewang@siliconmotion.com
+ *	     Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author:   Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * Copyright (C) 2011 Igalia, S.L.
+ * Author:   Javier M. Mellid <jmunhoz@igalia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips
+ */
+
+#include <linux/io.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/screen_info.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include "sm7xx.h"
+
+struct screen_info smtc_screen_info;
+
+/*
+* Private structure
+*/
+struct smtcfb_info {
+	struct fb_info fb;
+	struct pci_dev *pdev;
+
+	u16 chipID;
+	unsigned char __iomem *m_pMMIO;
+	char __iomem *m_pLFB;
+	char *m_pDPR;
+	char *m_pVPR;
+	char *m_pCPR;
+
+	u_int width;
+	u_int height;
+	u_int hz;
+
+	u8 chipRevID;
+};
+
+struct vesa_mode_table	{
+	char mode_index[6];
+	u16 lfb_width;
+	u16 lfb_height;
+	u16 lfb_depth;
+};
+
+static struct vesa_mode_table vesa_mode[] = {
+	{"0x301", 640,  480,  8},
+	{"0x303", 800,  600,  8},
+	{"0x305", 1024, 768,  8},
+	{"0x307", 1280, 1024, 8},
+
+	{"0x311", 640,  480,  16},
+	{"0x314", 800,  600,  16},
+	{"0x317", 1024, 768,  16},
+	{"0x31A", 1280, 1024, 16},
+
+	{"0x312", 640,  480,  24},
+	{"0x315", 800,  600,  24},
+	{"0x318", 1024, 768,  24},
+	{"0x31B", 1280, 1024, 24},
+};
+
+char __iomem *smtc_RegBaseAddress;	/* Memory Map IO starting address */
+char __iomem *smtc_VRAMBaseAddress;	/* video memory starting address */
+
+static u32 colreg[17];
+
+static struct fb_var_screeninfo smtcfb_var = {
+	.xres           = 1024,
+	.yres           = 600,
+	.xres_virtual   = 1024,
+	.yres_virtual   = 600,
+	.bits_per_pixel = 16,
+	.red            = {16, 8, 0},
+	.green          = {8, 8, 0},
+	.blue           = {0, 8, 0},
+	.activate       = FB_ACTIVATE_NOW,
+	.height         = -1,
+	.width          = -1,
+	.vmode          = FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo smtcfb_fix = {
+	.id             = "sm712fb",
+	.type           = FB_TYPE_PACKED_PIXELS,
+	.visual         = FB_VISUAL_TRUECOLOR,
+	.line_length    = 800 * 3,
+	.accel          = FB_ACCEL_SMI_LYNX,
+};
+
+static void sm712_set_timing(struct smtcfb_info *sfb)
+{
+	int i = 0, j = 0;
+	u32 m_nScreenStride;
+
+	dev_dbg(&sfb->pdev->dev,
+		"sfb->width=%d sfb->height=%d "
+		"sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n",
+		sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz);
+
+	for (j = 0; j < numVGAModes; j++) {
+		if (VGAMode[j].mmSizeX == sfb->width &&
+		    VGAMode[j].mmSizeY == sfb->height &&
+		    VGAMode[j].bpp == sfb->fb.var.bits_per_pixel &&
+		    VGAMode[j].hz == sfb->hz) {
+
+			dev_dbg(&sfb->pdev->dev,
+				"VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d "
+				"VGAMode[j].bpp=%d VGAMode[j].hz=%d\n",
+				VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
+				VGAMode[j].bpp, VGAMode[j].hz);
+
+			dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j);
+
+			smtc_mmiowb(0x0, 0x3c6);
+
+			smtc_seqw(0, 0x1);
+
+			smtc_mmiowb(VGAMode[j].Init_MISC, 0x3c2);
+
+			/* init SEQ register SR00 - SR04 */
+			for (i = 0; i < SIZE_SR00_SR04; i++)
+				smtc_seqw(i, VGAMode[j].Init_SR00_SR04[i]);
+
+			/* init SEQ register SR10 - SR24 */
+			for (i = 0; i < SIZE_SR10_SR24; i++)
+				smtc_seqw(i + 0x10,
+					  VGAMode[j].Init_SR10_SR24[i]);
+
+			/* init SEQ register SR30 - SR75 */
+			for (i = 0; i < SIZE_SR30_SR75; i++)
+				if (((i + 0x30) != 0x62) \
+					&& ((i + 0x30) != 0x6a) \
+					&& ((i + 0x30) != 0x6b))
+					smtc_seqw(i + 0x30,
+						VGAMode[j].Init_SR30_SR75[i]);
+
+			/* init SEQ register SR80 - SR93 */
+			for (i = 0; i < SIZE_SR80_SR93; i++)
+				smtc_seqw(i + 0x80,
+					  VGAMode[j].Init_SR80_SR93[i]);
+
+			/* init SEQ register SRA0 - SRAF */
+			for (i = 0; i < SIZE_SRA0_SRAF; i++)
+				smtc_seqw(i + 0xa0,
+					  VGAMode[j].Init_SRA0_SRAF[i]);
+
+			/* init Graphic register GR00 - GR08 */
+			for (i = 0; i < SIZE_GR00_GR08; i++)
+				smtc_grphw(i, VGAMode[j].Init_GR00_GR08[i]);
+
+			/* init Attribute register AR00 - AR14 */
+			for (i = 0; i < SIZE_AR00_AR14; i++)
+				smtc_attrw(i, VGAMode[j].Init_AR00_AR14[i]);
+
+			/* init CRTC register CR00 - CR18 */
+			for (i = 0; i < SIZE_CR00_CR18; i++)
+				smtc_crtcw(i, VGAMode[j].Init_CR00_CR18[i]);
+
+			/* init CRTC register CR30 - CR4D */
+			for (i = 0; i < SIZE_CR30_CR4D; i++)
+				smtc_crtcw(i + 0x30,
+					   VGAMode[j].Init_CR30_CR4D[i]);
+
+			/* init CRTC register CR90 - CRA7 */
+			for (i = 0; i < SIZE_CR90_CRA7; i++)
+				smtc_crtcw(i + 0x90,
+					   VGAMode[j].Init_CR90_CRA7[i]);
+		}
+	}
+	smtc_mmiowb(0x67, 0x3c2);
+
+	/* set VPR registers */
+	writel(0x0, sfb->m_pVPR + 0x0C);
+	writel(0x0, sfb->m_pVPR + 0x40);
+
+	/* set data width */
+	m_nScreenStride =
+		(sfb->width * sfb->fb.var.bits_per_pixel) / 64;
+	switch (sfb->fb.var.bits_per_pixel) {
+	case 8:
+		writel(0x0, sfb->m_pVPR + 0x0);
+		break;
+	case 16:
+		writel(0x00020000, sfb->m_pVPR + 0x0);
+		break;
+	case 24:
+		writel(0x00040000, sfb->m_pVPR + 0x0);
+		break;
+	case 32:
+		writel(0x00030000, sfb->m_pVPR + 0x0);
+		break;
+	}
+	writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
+	       sfb->m_pVPR + 0x10);
+
+}
+
+static void sm712_setpalette(int regno, unsigned red, unsigned green,
+			     unsigned blue, struct fb_info *info)
+{
+	/* set bit 5:4 = 01 (write LCD RAM only) */
+	smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
+
+	smtc_mmiowb(regno, dac_reg);
+	smtc_mmiowb(red >> 10, dac_val);
+	smtc_mmiowb(green >> 10, dac_val);
+	smtc_mmiowb(blue >> 10, dac_val);
+}
+
+static void smtc_set_timing(struct smtcfb_info *sfb)
+{
+	switch (sfb->chipID) {
+	case 0x710:
+	case 0x712:
+	case 0x720:
+		sm712_set_timing(sfb);
+		break;
+	}
+}
+
+/* chan_to_field
+ *
+ * convert a colour value into a field position
+ *
+ * from pxafb.c
+ */
+
+static inline unsigned int chan_to_field(unsigned int chan,
+					 struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int smtc_blank(int blank_mode, struct fb_info *info)
+{
+	/* clear DPMS setting */
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		/* Screen On: HSync: On, VSync : On */
+		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+		smtc_seqw(0x6a, 0x16);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
+		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
+		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
+		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+		smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
+		break;
+	case FB_BLANK_NORMAL:
+		/* Screen Off: HSync: On, VSync : On   Soft blank */
+		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+		smtc_seqw(0x6a, 0x16);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
+		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
+		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		/* Screen On: HSync: On, VSync : Off */
+		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+		smtc_seqw(0x6a, 0x0c);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
+		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
+		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		/* Screen On: HSync: Off, VSync : On */
+		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+		smtc_seqw(0x6a, 0x0c);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
+		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
+		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+		break;
+	case FB_BLANK_POWERDOWN:
+		/* Screen On: HSync: Off, VSync : Off */
+		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+		smtc_seqw(0x6a, 0x0c);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
+		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
+		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
+			  unsigned blue, unsigned trans, struct fb_info *info)
+{
+	struct smtcfb_info *sfb = (struct smtcfb_info *)info;
+	u32 val;
+
+	if (regno > 255)
+		return 1;
+
+	switch (sfb->fb.fix.visual) {
+	case FB_VISUAL_DIRECTCOLOR:
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 16/32 bit true-colour, use pseudo-palette for 16 base color
+		 */
+		if (regno < 16) {
+			if (sfb->fb.var.bits_per_pixel == 16) {
+				u32 *pal = sfb->fb.pseudo_palette;
+				val = chan_to_field(red, &sfb->fb.var.red);
+				val |= chan_to_field(green, \
+						&sfb->fb.var.green);
+				val |= chan_to_field(blue, &sfb->fb.var.blue);
+#ifdef __BIG_ENDIAN
+				pal[regno] =
+				    ((red & 0xf800) >> 8) |
+				    ((green & 0xe000) >> 13) |
+				    ((green & 0x1c00) << 3) |
+				    ((blue & 0xf800) >> 3);
+#else
+				pal[regno] = val;
+#endif
+			} else {
+				u32 *pal = sfb->fb.pseudo_palette;
+				val = chan_to_field(red, &sfb->fb.var.red);
+				val |= chan_to_field(green, \
+						&sfb->fb.var.green);
+				val |= chan_to_field(blue, &sfb->fb.var.blue);
+#ifdef __BIG_ENDIAN
+				val =
+				    (val & 0xff00ff00 >> 8) |
+				    (val & 0x00ff00ff << 8);
+#endif
+				pal[regno] = val;
+			}
+		}
+		break;
+
+	case FB_VISUAL_PSEUDOCOLOR:
+		/* color depth 8 bit */
+		sm712_setpalette(regno, red, green, blue, info);
+		break;
+
+	default:
+		return 1;	/* unknown type */
+	}
+
+	return 0;
+
+}
+
+#ifdef __BIG_ENDIAN
+static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t
+				count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+
+	u32 *buffer, *dst;
+	u32 __iomem *src;
+	int c, i, cnt = 0, err = 0;
+	unsigned long total_size;
+
+	if (!info || !info->screen_base)
+		return -ENODEV;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
+	total_size = info->screen_size;
+
+	if (total_size == 0)
+		total_size = info->fix.smem_len;
+
+	if (p >= total_size)
+		return 0;
+
+	if (count >= total_size)
+		count = total_size;
+
+	if (count + p > total_size)
+		count = total_size - p;
+
+	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	src = (u32 __iomem *) (info->screen_base + p);
+
+	if (info->fbops->fb_sync)
+		info->fbops->fb_sync(info);
+
+	while (count) {
+		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+		dst = buffer;
+		for (i = c >> 2; i--;) {
+			*dst = fb_readl(src++);
+			*dst =
+			    (*dst & 0xff00ff00 >> 8) |
+			    (*dst & 0x00ff00ff << 8);
+			dst++;
+		}
+		if (c & 3) {
+			u8 *dst8 = (u8 *) dst;
+			u8 __iomem *src8 = (u8 __iomem *) src;
+
+			for (i = c & 3; i--;) {
+				if (i & 1) {
+					*dst8++ = fb_readb(++src8);
+				} else {
+					*dst8++ = fb_readb(--src8);
+					src8 += 2;
+				}
+			}
+			src = (u32 __iomem *) src8;
+		}
+
+		if (copy_to_user(buf, buffer, c)) {
+			err = -EFAULT;
+			break;
+		}
+		*ppos += c;
+		buf += c;
+		cnt += c;
+		count -= c;
+	}
+
+	kfree(buffer);
+
+	return (err) ? err : cnt;
+}
+
+static ssize_t
+smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
+	     loff_t *ppos)
+{
+	unsigned long p = *ppos;
+
+	u32 *buffer, *src;
+	u32 __iomem *dst;
+	int c, i, cnt = 0, err = 0;
+	unsigned long total_size;
+
+	if (!info || !info->screen_base)
+		return -ENODEV;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
+	total_size = info->screen_size;
+
+	if (total_size == 0)
+		total_size = info->fix.smem_len;
+
+	if (p > total_size)
+		return -EFBIG;
+
+	if (count > total_size) {
+		err = -EFBIG;
+		count = total_size;
+	}
+
+	if (count + p > total_size) {
+		if (!err)
+			err = -ENOSPC;
+
+		count = total_size - p;
+	}
+
+	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	dst = (u32 __iomem *) (info->screen_base + p);
+
+	if (info->fbops->fb_sync)
+		info->fbops->fb_sync(info);
+
+	while (count) {
+		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+		src = buffer;
+
+		if (copy_from_user(src, buf, c)) {
+			err = -EFAULT;
+			break;
+		}
+
+		for (i = c >> 2; i--;) {
+			fb_writel((*src & 0xff00ff00 >> 8) |
+				  (*src & 0x00ff00ff << 8), dst++);
+			src++;
+		}
+		if (c & 3) {
+			u8 *src8 = (u8 *) src;
+			u8 __iomem *dst8 = (u8 __iomem *) dst;
+
+			for (i = c & 3; i--;) {
+				if (i & 1) {
+					fb_writeb(*src8++, ++dst8);
+				} else {
+					fb_writeb(*src8++, --dst8);
+					dst8 += 2;
+				}
+			}
+			dst = (u32 __iomem *) dst8;
+		}
+
+		*ppos += c;
+		buf += c;
+		cnt += c;
+		count -= c;
+	}
+
+	kfree(buffer);
+
+	return (cnt) ? cnt : err;
+}
+#endif	/* ! __BIG_ENDIAN */
+
+void smtcfb_setmode(struct smtcfb_info *sfb)
+{
+	switch (sfb->fb.var.bits_per_pixel) {
+	case 32:
+		sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
+		sfb->fb.fix.line_length  = sfb->fb.var.xres * 4;
+		sfb->fb.var.red.length   = 8;
+		sfb->fb.var.green.length = 8;
+		sfb->fb.var.blue.length  = 8;
+		sfb->fb.var.red.offset   = 16;
+		sfb->fb.var.green.offset = 8;
+		sfb->fb.var.blue.offset  = 0;
+		break;
+	case 24:
+		sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
+		sfb->fb.fix.line_length  = sfb->fb.var.xres * 3;
+		sfb->fb.var.red.length   = 8;
+		sfb->fb.var.green.length = 8;
+		sfb->fb.var.blue.length  = 8;
+		sfb->fb.var.red.offset   = 16;
+		sfb->fb.var.green.offset = 8;
+		sfb->fb.var.blue.offset  = 0;
+		break;
+	case 8:
+		sfb->fb.fix.visual       = FB_VISUAL_PSEUDOCOLOR;
+		sfb->fb.fix.line_length  = sfb->fb.var.xres;
+		sfb->fb.var.red.length   = 3;
+		sfb->fb.var.green.length = 3;
+		sfb->fb.var.blue.length  = 2;
+		sfb->fb.var.red.offset   = 5;
+		sfb->fb.var.green.offset = 2;
+		sfb->fb.var.blue.offset  = 0;
+		break;
+	case 16:
+	default:
+		sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
+		sfb->fb.fix.line_length  = sfb->fb.var.xres * 2;
+		sfb->fb.var.red.length   = 5;
+		sfb->fb.var.green.length = 6;
+		sfb->fb.var.blue.length  = 5;
+		sfb->fb.var.red.offset   = 11;
+		sfb->fb.var.green.offset = 5;
+		sfb->fb.var.blue.offset  = 0;
+		break;
+	}
+
+	sfb->width  = sfb->fb.var.xres;
+	sfb->height = sfb->fb.var.yres;
+	sfb->hz = 60;
+	smtc_set_timing(sfb);
+}
+
+static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	/* sanity checks */
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	/* set valid default bpp */
+	if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
+	    (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
+		var->bits_per_pixel = 16;
+
+	return 0;
+}
+
+static int smtc_set_par(struct fb_info *info)
+{
+	struct smtcfb_info *sfb = (struct smtcfb_info *)info;
+
+	smtcfb_setmode(sfb);
+
+	return 0;
+}
+
+static struct fb_ops smtcfb_ops = {
+	.owner        = THIS_MODULE,
+	.fb_check_var = smtc_check_var,
+	.fb_set_par   = smtc_set_par,
+	.fb_setcolreg = smtc_setcolreg,
+	.fb_blank     = smtc_blank,
+	.fb_fillrect  = cfb_fillrect,
+	.fb_imageblit = cfb_imageblit,
+	.fb_copyarea  = cfb_copyarea,
+#ifdef __BIG_ENDIAN
+	.fb_read      = smtcfb_read,
+	.fb_write     = smtcfb_write,
+#endif
+};
+
+/*
+ * Alloc struct smtcfb_info and assign the default value
+ */
+static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev, char *name)
+{
+	struct smtcfb_info *sfb;
+
+	sfb = kzalloc(sizeof(*sfb), GFP_KERNEL);
+
+	if (!sfb)
+		return NULL;
+
+	sfb->pdev = pdev;
+
+	/*** Init sfb->fb with default value ***/
+	sfb->fb.flags = FBINFO_FLAG_DEFAULT;
+	sfb->fb.fbops = &smtcfb_ops;
+	sfb->fb.var = smtcfb_var;
+	sfb->fb.fix = smtcfb_fix;
+
+	strcpy(sfb->fb.fix.id, name);
+
+	sfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+	sfb->fb.fix.type_aux = 0;
+	sfb->fb.fix.xpanstep = 0;
+	sfb->fb.fix.ypanstep = 0;
+	sfb->fb.fix.ywrapstep = 0;
+	sfb->fb.fix.accel = FB_ACCEL_SMI_LYNX;
+
+	sfb->fb.var.nonstd = 0;
+	sfb->fb.var.activate = FB_ACTIVATE_NOW;
+	sfb->fb.var.height = -1;
+	sfb->fb.var.width = -1;
+	/* text mode acceleration */
+	sfb->fb.var.accel_flags = FB_ACCELF_TEXT;
+	sfb->fb.var.vmode = FB_VMODE_NONINTERLACED;
+
+	sfb->fb.par = sfb;
+
+	sfb->fb.pseudo_palette = colreg;
+
+	return sfb;
+}
+
+/*
+ * free struct smtcfb_info
+ */
+static void smtc_free_fb_info(struct smtcfb_info *sfb)
+{
+	kfree(sfb);
+}
+
+/*
+ * Unmap in the memory mapped IO registers
+ */
+
+static void smtc_unmap_mmio(struct smtcfb_info *sfb)
+{
+	if (sfb && smtc_RegBaseAddress)
+		smtc_RegBaseAddress = NULL;
+}
+
+/*
+ * Map in the screen memory
+ */
+
+static int smtc_map_smem(struct smtcfb_info *sfb,
+		struct pci_dev *pdev, u_long smem_len)
+{
+
+	sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
+
+#ifdef __BIG_ENDIAN
+	if (sfb->fb.var.bits_per_pixel == 32)
+		sfb->fb.fix.smem_start += 0x800000;
+#endif
+
+	sfb->fb.fix.smem_len = smem_len;
+
+	sfb->fb.screen_base = smtc_VRAMBaseAddress;
+
+	if (!sfb->fb.screen_base) {
+		dev_err(&pdev->dev,
+			"%s: unable to map screen memory\n", sfb->fb.fix.id);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/*
+ * Unmap in the screen memory
+ *
+ */
+static void smtc_unmap_smem(struct smtcfb_info *sfb)
+{
+	if (sfb && sfb->fb.screen_base) {
+		iounmap(sfb->fb.screen_base);
+		sfb->fb.screen_base = NULL;
+	}
+}
+
+/*
+ * We need to wake up the device and make sure its in linear memory mode.
+ */
+static inline void sm7xx_init_hw(void)
+{
+	outb_p(0x18, 0x3c4);
+	outb_p(0x11, 0x3c5);
+}
+
+/*
+ *	sm712vga_setup - process command line options, get vga parameter
+ *	@options: string of options
+ *	Returns zero.
+ *
+ */
+static int __init sm712vga_setup(char *options)
+{
+	int index;
+
+	if (!options || !*options)
+		return -EINVAL;
+
+	smtc_screen_info.lfb_width = 0;
+	smtc_screen_info.lfb_height = 0;
+	smtc_screen_info.lfb_depth = 0;
+
+	pr_debug("sm712vga_setup = %s\n", options);
+
+	for (index = 0;
+	     index < ARRAY_SIZE(vesa_mode);
+	     index++) {
+		if (strstr(options, vesa_mode[index].mode_index)) {
+			smtc_screen_info.lfb_width = vesa_mode[index].lfb_width;
+			smtc_screen_info.lfb_height =
+					vesa_mode[index].lfb_height;
+			smtc_screen_info.lfb_depth = vesa_mode[index].lfb_depth;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+__setup("vga=", sm712vga_setup);
+
+static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
+				   const struct pci_device_id *ent)
+{
+	struct smtcfb_info *sfb;
+	u_long smem_size = 0x00800000;	/* default 8MB */
+	char name[16];
+	int err;
+	unsigned long pFramebufferPhysical;
+
+	dev_info(&pdev->dev, "Silicon Motion display driver.");
+
+	err = pci_enable_device(pdev);	/* enable SMTC chip */
+	if (err)
+		return err;
+
+	sfb = smtc_alloc_fb_info(pdev, name);
+
+	if (!sfb)
+		goto failed_free;
+
+	sfb->chipID = ent->device;
+	sprintf(name, "sm%Xfb", sfb->chipID);
+
+	pci_set_drvdata(pdev, sfb);
+
+	sm7xx_init_hw();
+
+	/*get mode parameter from smtc_screen_info */
+	if (smtc_screen_info.lfb_width != 0) {
+		sfb->fb.var.xres = smtc_screen_info.lfb_width;
+		sfb->fb.var.yres = smtc_screen_info.lfb_height;
+		sfb->fb.var.bits_per_pixel = smtc_screen_info.lfb_depth;
+	} else {
+		/* default resolution 1024x600 16bit mode */
+		sfb->fb.var.xres = SCREEN_X_RES;
+		sfb->fb.var.yres = SCREEN_Y_RES;
+		sfb->fb.var.bits_per_pixel = SCREEN_BPP;
+	}
+
+#ifdef __BIG_ENDIAN
+	if (sfb->fb.var.bits_per_pixel == 24)
+		sfb->fb.var.bits_per_pixel = (smtc_screen_info.lfb_depth = 32);
+#endif
+	/* Map address and memory detection */
+	pFramebufferPhysical = pci_resource_start(pdev, 0);
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chipRevID);
+
+	switch (sfb->chipID) {
+	case 0x710:
+	case 0x712:
+		sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000;
+		sfb->fb.fix.mmio_len = 0x00400000;
+		smem_size = SM712_VIDEOMEMORYSIZE;
+#ifdef __BIG_ENDIAN
+		sfb->m_pLFB = (smtc_VRAMBaseAddress =
+		    ioremap(pFramebufferPhysical, 0x00c00000));
+#else
+		sfb->m_pLFB = (smtc_VRAMBaseAddress =
+		    ioremap(pFramebufferPhysical, 0x00800000));
+#endif
+		sfb->m_pMMIO = (smtc_RegBaseAddress =
+		    smtc_VRAMBaseAddress + 0x00700000);
+		sfb->m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
+		sfb->m_pVPR = sfb->m_pLFB + 0x0040c000;
+#ifdef __BIG_ENDIAN
+		if (sfb->fb.var.bits_per_pixel == 32) {
+			smtc_VRAMBaseAddress += 0x800000;
+			sfb->m_pLFB += 0x800000;
+			dev_info(&pdev->dev,
+				 "smtc_VRAMBaseAddress=%p sfb->m_pLFB=%p",
+				  smtc_VRAMBaseAddress, sfb->m_pLFB);
+		}
+#endif
+		if (!smtc_RegBaseAddress) {
+			dev_err(&pdev->dev,
+				"%s: unable to map memory mapped IO!",
+				sfb->fb.fix.id);
+			err = -ENOMEM;
+			goto failed_fb;
+		}
+
+		/* set MCLK = 14.31818 * (0x16 / 0x2) */
+		smtc_seqw(0x6a, 0x16);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x62, 0x3e);
+		/* enable PCI burst */
+		smtc_seqw(0x17, 0x20);
+		/* enable word swap */
+#ifdef __BIG_ENDIAN
+		if (sfb->fb.var.bits_per_pixel == 32)
+			smtc_seqw(0x17, 0x30);
+#endif
+		break;
+	case 0x720:
+		sfb->fb.fix.mmio_start = pFramebufferPhysical;
+		sfb->fb.fix.mmio_len = 0x00200000;
+		smem_size = SM722_VIDEOMEMORYSIZE;
+		sfb->m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
+		sfb->m_pLFB = (smtc_VRAMBaseAddress =
+		    sfb->m_pDPR + 0x00200000);
+		sfb->m_pMMIO = (smtc_RegBaseAddress =
+		    sfb->m_pDPR + 0x000c0000);
+		sfb->m_pVPR = sfb->m_pDPR + 0x800;
+
+		smtc_seqw(0x62, 0xff);
+		smtc_seqw(0x6a, 0x0d);
+		smtc_seqw(0x6b, 0x02);
+		break;
+	default:
+		dev_err(&pdev->dev,
+			"No valid Silicon Motion display chip was detected!");
+
+		goto failed_fb;
+	}
+
+	/* can support 32 bpp */
+	if (15 == sfb->fb.var.bits_per_pixel)
+		sfb->fb.var.bits_per_pixel = 16;
+
+	sfb->fb.var.xres_virtual = sfb->fb.var.xres;
+	sfb->fb.var.yres_virtual = sfb->fb.var.yres;
+	err = smtc_map_smem(sfb, pdev, smem_size);
+	if (err)
+		goto failed;
+
+	smtcfb_setmode(sfb);
+
+	err = register_framebuffer(&sfb->fb);
+	if (err < 0)
+		goto failed;
+
+	dev_info(&pdev->dev,
+		 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.",
+		 sfb->chipID, sfb->chipRevID, sfb->fb.var.xres,
+		 sfb->fb.var.yres, sfb->fb.var.bits_per_pixel);
+
+	return 0;
+
+failed:
+	dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.");
+
+	smtc_unmap_smem(sfb);
+	smtc_unmap_mmio(sfb);
+failed_fb:
+	smtc_free_fb_info(sfb);
+
+failed_free:
+	pci_disable_device(pdev);
+
+	return err;
+}
+
+/*
+ * 0x710 (LynxEM)
+ * 0x712 (LynxEM+)
+ * 0x720 (Lynx3DM, Lynx3DM+)
+ */
+static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = {
+	{ PCI_DEVICE(0x126f, 0x710), },
+	{ PCI_DEVICE(0x126f, 0x712), },
+	{ PCI_DEVICE(0x126f, 0x720), },
+	{0,}
+};
+
+static void __devexit smtcfb_pci_remove(struct pci_dev *pdev)
+{
+	struct smtcfb_info *sfb;
+
+	sfb = pci_get_drvdata(pdev);
+	pci_set_drvdata(pdev, NULL);
+	smtc_unmap_smem(sfb);
+	smtc_unmap_mmio(sfb);
+	unregister_framebuffer(&sfb->fb);
+	smtc_free_fb_info(sfb);
+}
+
+#ifdef CONFIG_PM
+static int smtcfb_pci_suspend(struct device *device)
+{
+	struct pci_dev *pdev = to_pci_dev(device);
+	struct smtcfb_info *sfb;
+
+	sfb = pci_get_drvdata(pdev);
+
+	/* set the hw in sleep mode use external clock and self memory refresh
+	 * so that we can turn off internal PLLs later on
+	 */
+	smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
+	smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
+
+	console_lock();
+	fb_set_suspend(&sfb->fb, 1);
+	console_unlock();
+
+	/* additionally turn off all function blocks including internal PLLs */
+	smtc_seqw(0x21, 0xff);
+
+	return 0;
+}
+
+static int smtcfb_pci_resume(struct device *device)
+{
+	struct pci_dev *pdev = to_pci_dev(device);
+	struct smtcfb_info *sfb;
+
+	sfb = pci_get_drvdata(pdev);
+
+	/* reinit hardware */
+	sm7xx_init_hw();
+	switch (sfb->chipID) {
+	case 0x710:
+	case 0x712:
+		/* set MCLK = 14.31818 *  (0x16 / 0x2) */
+		smtc_seqw(0x6a, 0x16);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x62, 0x3e);
+		/* enable PCI burst */
+		smtc_seqw(0x17, 0x20);
+#ifdef __BIG_ENDIAN
+		if (sfb->fb.var.bits_per_pixel == 32)
+			smtc_seqw(0x17, 0x30);
+#endif
+		break;
+	case 0x720:
+		smtc_seqw(0x62, 0xff);
+		smtc_seqw(0x6a, 0x0d);
+		smtc_seqw(0x6b, 0x02);
+		break;
+	}
+
+	smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
+	smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
+
+	smtcfb_setmode(sfb);
+
+	console_lock();
+	fb_set_suspend(&sfb->fb, 0);
+	console_unlock();
+
+	return 0;
+}
+
+static const struct dev_pm_ops sm7xx_pm_ops = {
+	.suspend = smtcfb_pci_suspend,
+	.resume = smtcfb_pci_resume,
+	.freeze = smtcfb_pci_suspend,
+	.thaw = smtcfb_pci_resume,
+	.poweroff = smtcfb_pci_suspend,
+	.restore = smtcfb_pci_resume,
+};
+
+#define SM7XX_PM_OPS (&sm7xx_pm_ops)
+
+#else  /* !CONFIG_PM */
+
+#define SM7XX_PM_OPS NULL
+
+#endif /* !CONFIG_PM */
+
+static struct pci_driver smtcfb_driver = {
+	.name = "smtcfb",
+	.id_table = smtcfb_pci_table,
+	.probe = smtcfb_pci_probe,
+	.remove = __devexit_p(smtcfb_pci_remove),
+	.driver.pm  = SM7XX_PM_OPS,
+};
+
+static int __init smtcfb_init(void)
+{
+	return pci_register_driver(&smtcfb_driver);
+}
+
+static void __exit smtcfb_exit(void)
+{
+	pci_unregister_driver(&smtcfb_driver);
+}
+
+module_init(smtcfb_init);
+module_exit(smtcfb_exit);
+
+MODULE_AUTHOR("Siliconmotion ");
+MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c
index 92b34e2..40e2488 100644
--- a/drivers/staging/speakup/main.c
+++ b/drivers/staging/speakup/main.c
@@ -1854,7 +1854,7 @@ static void speakup_bits(struct vc_data *vc)
 
 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
 {
-	static u_char *goto_buf = "\0\0\0\0\0\0";
+	static u_char goto_buf[8];
 	static int num;
 	int maxlen, go_pos;
 	char *cp;
diff --git a/drivers/staging/speakup/selection.c b/drivers/staging/speakup/selection.c
index fe1f405..0612df0 100644
--- a/drivers/staging/speakup/selection.c
+++ b/drivers/staging/speakup/selection.c
@@ -68,7 +68,7 @@ int speakup_set_selection(struct tty_struct *tty)
 	if (spk_sel_cons != vc_cons[fg_console].d) {
 		speakup_clear_selection();
 		spk_sel_cons = vc_cons[fg_console].d;
-		printk(KERN_WARNING
+		dev_warn(tty->dev,
 			"Selection: mark console not the same as cut\n");
 		return -EINVAL;
 	}
@@ -95,7 +95,7 @@ int speakup_set_selection(struct tty_struct *tty)
 	/* Allocate a new buffer before freeing the old one ... */
 	bp = kmalloc((sel_end-sel_start)/2+1, GFP_ATOMIC);
 	if (!bp) {
-		printk(KERN_WARNING "selection: kmalloc() failed\n");
+		dev_warn(tty->dev, "selection: kmalloc() failed\n");
 		speakup_clear_selection();
 		return -ENOMEM;
 	}
@@ -141,7 +141,7 @@ int speakup_paste_selection(struct tty_struct *tty)
 		count = sel_buffer_lth - pasted;
 		count = min_t(int, count, tty->receive_room);
 		tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
-			0, count);
+			NULL, count);
 		pasted += count;
 	}
 	remove_wait_queue(&vc->paste_wait, &wait);
diff --git a/drivers/staging/usbip/userspace/src/Makefile.am b/drivers/staging/usbip/userspace/src/Makefile.am
index 3f09f6a..c365a3f 100644
--- a/drivers/staging/usbip/userspace/src/Makefile.am
+++ b/drivers/staging/usbip/userspace/src/Makefile.am
@@ -4,8 +4,9 @@ LDADD       = $(top_builddir)/libsrc/libusbip.la @PACKAGE_LIBS@
 
 sbin_PROGRAMS := usbip usbipd
 
-usbip_SOURCES := usbip.c utils.c usbip_network.c \
+usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \
 		 usbip_attach.c usbip_detach.c usbip_list.c \
 		 usbip_bind.c usbip_unbind.c
 
-usbipd_SOURCES := usbipd.c usbip_network.c
+
+usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c
diff --git a/drivers/staging/usbip/vhci.h b/drivers/staging/usbip/vhci.h
index 88b3298..c66b8b3 100644
--- a/drivers/staging/usbip/vhci.h
+++ b/drivers/staging/usbip/vhci.h
@@ -71,12 +71,7 @@ struct vhci_unlink {
 	unsigned long unlink_seqnum;
 };
 
-/*
- * The number of ports is less than 16 ?
- * USB_MAXCHILDREN is statically defined to 16 in usb.h.  Its maximum value
- * would be 31 because the event_bits[1] of struct usb_hub is defined as
- * unsigned long in hub.h
- */
+/* Number of supported ports. Value has an upperbound of USB_MAXCHILDREN */
 #define VHCI_NPORTS 8
 
 /* for usb_bus.hcpriv */
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index f708cba..12a9a5f 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -178,44 +178,32 @@ void rh_port_disconnect(int rhport)
 	  | USB_PORT_STAT_C_RESET) << 16)
 
 /*
- * This function is almostly the same as dummy_hcd.c:dummy_hub_status() without
- * suspend/resume support. But, it is modified to provide multiple ports.
+ * Returns 0 if the status hasn't changed, or the number of bytes in buf.
+ * Ports are 0-indexed from the HCD point of view,
+ * and 1-indexed from the USB core pointer of view.
  *
  * @buf: a bitmap to show which port status has been changed.
- *  bit  0: reserved or used for another purpose?
+ *  bit  0: reserved
  *  bit  1: the status of port 0 has been changed.
  *  bit  2: the status of port 1 has been changed.
  *  ...
- *  bit  7: the status of port 6 has been changed.
- *  bit  8: the status of port 7 has been changed.
- *  ...
- *  bit 15: the status of port 14 has been changed.
- *
- * So, the maximum number of ports is 31 ( port 0 to port 30) ?
- *
- * The return value is the actual transferred length in byte. If nothing has
- * been changed, return 0. In the case that the number of ports is less than or
- * equal to 6 (VHCI_NPORTS==7), return 1.
- *
  */
 static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
 {
 	struct vhci_hcd	*vhci;
 	unsigned long	flags;
-	int		retval = 0;
-
-	/* the enough buffer is allocated according to USB_MAXCHILDREN */
-	unsigned long	*event_bits = (unsigned long *) buf;
+	int		retval;
 	int		rhport;
 	int		changed = 0;
 
-	*event_bits = 0;
+	retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8);
+	memset(buf, 0, retval);
 
 	vhci = hcd_to_vhci(hcd);
 
 	spin_lock_irqsave(&vhci->lock, flags);
 	if (!HCD_HW_ACCESSIBLE(hcd)) {
-		usbip_dbg_vhci_rh("hw accessible flag in on?\n");
+		usbip_dbg_vhci_rh("hw accessible flag not on?\n");
 		goto done;
 	}
 
@@ -223,9 +211,9 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
 	for (rhport = 0; rhport < VHCI_NPORTS; rhport++) {
 		if ((vhci->port_status[rhport] & PORT_C_MASK)) {
 			/* The status of a port has been changed, */
-			usbip_dbg_vhci_rh("port %d is changed\n", rhport);
+			usbip_dbg_vhci_rh("port %d status changed\n", rhport);
 
-			*event_bits |= 1 << (rhport + 1);
+			buf[(rhport + 1) / 8] |= 1 << (rhport + 1) % 8;
 			changed = 1;
 		}
 	}
@@ -235,14 +223,9 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
 	if (hcd->state == HC_STATE_SUSPENDED)
 		usb_hcd_resume_root_hub(hcd);
 
-	if (changed)
-		retval = 1 + (VHCI_NPORTS / 8);
-	else
-		retval = 0;
-
 done:
 	spin_unlock_irqrestore(&vhci->lock, flags);
-	return retval;
+	return changed ? retval : 0;
 }
 
 /* See hub_configure in hub.c */
diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c
index b24e531..dc24096 100644
--- a/drivers/staging/vt6656/iwctl.c
+++ b/drivers/staging/vt6656/iwctl.c
@@ -47,20 +47,20 @@
 #include <net/iw_handler.h>
 
 #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
-#define SUPPORTED_WIRELESS_EXT                  18
+#define SUPPORTED_WIRELESS_EXT 18
 #else
-#define SUPPORTED_WIRELESS_EXT                  17
+#define SUPPORTED_WIRELESS_EXT 17
 #endif
 
 static const long frequency_list[] = {
-    2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484,
-    4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980,
-    5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210, 5220, 5230, 5240,
-    5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680,
-    5700, 5745, 5765, 5785, 5805, 5825
-	};
+	2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484,
+	4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980,
+	5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210, 5220, 5230, 5240,
+	5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680,
+	5700, 5745, 5765, 5785, 5805, 5825
+};
 
-static int          msglevel                =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
 
 struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev)
 {
@@ -68,9 +68,9 @@ struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev)
 	long ldBm;
 
 	pDevice->wstats.status = pDevice->eOPMode;
-	   if(pDevice->scStatistic.LinkQuality > 100)
-   	       pDevice->scStatistic.LinkQuality = 100;
-               pDevice->wstats.qual.qual =(BYTE) pDevice->scStatistic.LinkQuality;
+	if (pDevice->scStatistic.LinkQuality > 100)
+		pDevice->scStatistic.LinkQuality = 100;
+	pDevice->wstats.qual.qual =(BYTE)pDevice->scStatistic.LinkQuality;
 	RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
 	pDevice->wstats.qual.level = ldBm;
 	pDevice->wstats.qual.noise = 0;
@@ -81,93 +81,84 @@ struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev)
 	pDevice->wstats.discard.retries = pDevice->scStatistic.dwTsrErr;
 	pDevice->wstats.discard.misc = 0;
 	pDevice->wstats.miss.beacon = 0;
-
 	return &pDevice->wstats;
 }
 
 /*
- * Wireless Handler : get protocol name
+ * Wireless Handler: get protocol name
  */
-
-int iwctl_giwname(struct net_device *dev,
-			 struct iw_request_info *info,
-			 char *wrq,
-			 char *extra)
+int iwctl_giwname(struct net_device *dev, struct iw_request_info *info,
+		char *wrq, char *extra)
 {
 	strcpy(wrq, "802.11-a/b/g");
 	return 0;
 }
 
 /*
- * Wireless Handler : set scan
+ * Wireless Handler: set scan
  */
-
-int iwctl_siwscan(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_point *wrq,
-             char *extra)
+int iwctl_siwscan(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-	 PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-	struct iw_scan_req  *req = (struct iw_scan_req *)extra;
-	BYTE                abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
-	PWLAN_IE_SSID       pItemSSID=NULL;
-
-  if (!(pDevice->flags & DEVICE_FLAGS_OPENED))
-        return -EINVAL;
-
-    PRINT_K(" SIOCSIWSCAN \n");
-
-if (pMgmt->eScanState ==  WMAC_IS_SCANNING) {
-        // In scanning..
-     PRINT_K("SIOCSIWSCAN(overlap??)-->In scanning...\n");
-     return -EAGAIN;
-  }
-
-if(pDevice->byReAssocCount > 0) {   //reject scan when re-associating!
-//send scan event to wpa_Supplicant
-  union iwreq_data wrqu;
- PRINT_K("wireless_send_event--->SIOCGIWSCAN(scan done)\n");
- memset(&wrqu, 0, sizeof(wrqu));
- wireless_send_event(pDevice->dev, SIOCGIWSCAN, &wrqu, NULL);
-  return 0;
-}
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+	struct iw_scan_req *req = (struct iw_scan_req *)extra;
+	BYTE abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+	PWLAN_IE_SSID pItemSSID=NULL;
+
+	if (!(pDevice->flags & DEVICE_FLAGS_OPENED))
+		return -EINVAL;
+
+	PRINT_K(" SIOCSIWSCAN \n");
+
+	if (pMgmt->eScanState ==  WMAC_IS_SCANNING) {
+		// In scanning..
+		PRINT_K("SIOCSIWSCAN(overlap??)-->In scanning...\n");
+		return -EAGAIN;
+	}
+
+	if (pDevice->byReAssocCount > 0) { // reject scan when re-associating!
+		// send scan event to wpa_Supplicant
+		union iwreq_data wrqu;
+		PRINT_K("wireless_send_event--->SIOCGIWSCAN(scan done)\n");
+		memset(&wrqu, 0, sizeof(wrqu));
+		wireless_send_event(pDevice->dev, SIOCGIWSCAN, &wrqu, NULL);
+		return 0;
+	}
 
 	spin_lock_irq(&pDevice->lock);
 
-	BSSvClearBSSList((void *) pDevice, pDevice->bLinkPass);
-
-//mike add: active scan OR passive scan OR desire_ssid scan
- if(wrq->length == sizeof(struct iw_scan_req)) {
-   if (wrq->flags & IW_SCAN_THIS_ESSID)  {                               //desire_ssid scan
-       memset(abyScanSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
-       pItemSSID = (PWLAN_IE_SSID)abyScanSSID;
-       pItemSSID->byElementID = WLAN_EID_SSID;
-       memcpy(pItemSSID->abySSID, req->essid, (int)req->essid_len);
-         if (pItemSSID->abySSID[req->essid_len - 1] == '\0') {
-           if(req->essid_len>0)
-		pItemSSID->len = req->essid_len - 1;
-         }
-	else
-	  pItemSSID->len = req->essid_len;
-	  pMgmt->eScanType = WMAC_SCAN_PASSIVE;
-         PRINT_K("SIOCSIWSCAN:[desired_ssid=%s,len=%d]\n",((PWLAN_IE_SSID)abyScanSSID)->abySSID,
-		 	                                                                                ((PWLAN_IE_SSID)abyScanSSID)->len);
-	bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, abyScanSSID);
-	spin_unlock_irq(&pDevice->lock);
+	BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
+
+	// mike add: active scan OR passive scan OR desire_ssid scan
+	if (wrq->length == sizeof(struct iw_scan_req)) {
+		if (wrq->flags & IW_SCAN_THIS_ESSID) { // desire_ssid scan
+			memset(abyScanSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+			pItemSSID = (PWLAN_IE_SSID)abyScanSSID;
+			pItemSSID->byElementID = WLAN_EID_SSID;
+			memcpy(pItemSSID->abySSID, req->essid, (int)req->essid_len);
+			if (pItemSSID->abySSID[req->essid_len - 1] == '\0') {
+				if (req->essid_len > 0)
+					pItemSSID->len = req->essid_len - 1;
+			}
+			else
+				pItemSSID->len = req->essid_len;
+			pMgmt->eScanType = WMAC_SCAN_PASSIVE;
+			PRINT_K("SIOCSIWSCAN:[desired_ssid=%s,len=%d]\n", ((PWLAN_IE_SSID)abyScanSSID)->abySSID,
+				((PWLAN_IE_SSID)abyScanSSID)->len);
+			bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, abyScanSSID);
+			spin_unlock_irq(&pDevice->lock);
+
+			return 0;
+		} else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { // passive scan
+			pMgmt->eScanType = WMAC_SCAN_PASSIVE;
+		}
+	} else { // active scan
+		pMgmt->eScanType = WMAC_SCAN_ACTIVE;
+	}
 
-	return 0;
-   }
-   else if(req->scan_type == IW_SCAN_TYPE_PASSIVE) {          //passive scan
-       pMgmt->eScanType = WMAC_SCAN_PASSIVE;
-   }
- }
- else {           //active scan
-     pMgmt->eScanType = WMAC_SCAN_ACTIVE;
- }
-
-	 pMgmt->eScanType = WMAC_SCAN_PASSIVE;
-	bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
+	pMgmt->eScanType = WMAC_SCAN_PASSIVE;
+	bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, NULL);
 	spin_unlock_irq(&pDevice->lock);
 
 	return 0;
@@ -176,18 +167,18 @@ if(pDevice->byReAssocCount > 0) {   //reject scan when re-associating!
 /*
  * Wireless Handler : get scan results
  */
-
-int iwctl_giwscan(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_point *wrq,
-             char *extra)
+int iwctl_giwscan(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-    int ii, jj, kk;
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-    PKnownBSS           pBSS;
-    PWLAN_IE_SSID       pItemSSID;
-    PWLAN_IE_SUPP_RATES pSuppRates, pExtSuppRates;
+	int ii;
+	int jj;
+	int kk;
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+	PKnownBSS pBSS;
+	PWLAN_IE_SSID pItemSSID;
+	PWLAN_IE_SUPP_RATES pSuppRates;
+	PWLAN_IE_SUPP_RATES pExtSuppRates;
 	char *current_ev = extra;
 	char *end_buf = extra + IW_SCAN_MAX_DATA;
 	char *current_val = NULL;
@@ -195,194 +186,179 @@ int iwctl_giwscan(struct net_device *dev,
 	long ldBm;
 	char buf[MAX_WPA_IE_LEN * 2 + 30];
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSCAN\n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSCAN\n");
 
-    if (pMgmt->eScanState ==  WMAC_IS_SCANNING) {
-        // In scanning..
+	if (pMgmt->eScanState ==  WMAC_IS_SCANNING) {
+		// In scanning..
 		return -EAGAIN;
 	}
 	pBSS = &(pMgmt->sBSSList[0]);
-    for (ii = 0, jj = 0; jj < MAX_BSS_NUM ; jj++) {
+	for (ii = 0, jj = 0; jj < MAX_BSS_NUM ; jj++) {
 		if (current_ev >= end_buf)
 			break;
-        pBSS = &(pMgmt->sBSSList[jj]);
-        if (pBSS->bActive) {
-		//ADD mac address
-		    memset(&iwe, 0, sizeof(iwe));
-		    iwe.cmd = SIOCGIWAP;
-		    iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+		pBSS = &(pMgmt->sBSSList[jj]);
+		if (pBSS->bActive) {
+			// ADD mac address
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = SIOCGIWAP;
+			iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 			memcpy(iwe.u.ap_addr.sa_data, pBSS->abyBSSID, WLAN_BSSID_LEN);
-                           current_ev = iwe_stream_add_event(info,current_ev,end_buf, &iwe, IW_EV_ADDR_LEN);
-                 //ADD ssid
-	             memset(&iwe, 0, sizeof(iwe));
-                      iwe.cmd = SIOCGIWESSID;
-                      pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
-                       iwe.u.data.length = pItemSSID->len;
-                       iwe.u.data.flags = 1;
-                      current_ev = iwe_stream_add_point(info,current_ev,end_buf, &iwe, pItemSSID->abySSID);
-		//ADD mode
-		    memset(&iwe, 0, sizeof(iwe));
-		    iwe.cmd = SIOCGIWMODE;
-            if (WLAN_GET_CAP_INFO_ESS(pBSS->wCapInfo)) {
-		        iwe.u.mode = IW_MODE_INFRA;
-            }
-            else {
-                iwe.u.mode = IW_MODE_ADHOC;
-		    }
-	        iwe.len = IW_EV_UINT_LEN;
-                      current_ev = iwe_stream_add_event(info,current_ev, end_buf, &iwe,  IW_EV_UINT_LEN);
-           //ADD frequency
-            pSuppRates = (PWLAN_IE_SUPP_RATES)pBSS->abySuppRates;
-            pExtSuppRates = (PWLAN_IE_SUPP_RATES)pBSS->abyExtSuppRates;
-            memset(&iwe, 0, sizeof(iwe));
-           	iwe.cmd = SIOCGIWFREQ;
-           	iwe.u.freq.m = pBSS->uChannel;
-           	iwe.u.freq.e = 0;
-           	iwe.u.freq.i = 0;
-                  current_ev = iwe_stream_add_event(info,current_ev,end_buf, &iwe, IW_EV_FREQ_LEN);
+			current_ev = iwe_stream_add_event(info,current_ev,end_buf, &iwe, IW_EV_ADDR_LEN);
+			// ADD ssid
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = SIOCGIWESSID;
+			pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
+			iwe.u.data.length = pItemSSID->len;
+			iwe.u.data.flags = 1;
+			current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, pItemSSID->abySSID);
+			// ADD mode
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = SIOCGIWMODE;
+			if (WLAN_GET_CAP_INFO_ESS(pBSS->wCapInfo))
+				iwe.u.mode = IW_MODE_INFRA;
+			else
+				iwe.u.mode = IW_MODE_ADHOC;
+			iwe.len = IW_EV_UINT_LEN;
+			current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+			// ADD frequency
+			pSuppRates = (PWLAN_IE_SUPP_RATES)pBSS->abySuppRates;
+			pExtSuppRates = (PWLAN_IE_SUPP_RATES)pBSS->abyExtSuppRates;
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = SIOCGIWFREQ;
+			iwe.u.freq.m = pBSS->uChannel;
+			iwe.u.freq.e = 0;
+			iwe.u.freq.i = 0;
+			current_ev = iwe_stream_add_event(info, current_ev,end_buf, &iwe, IW_EV_FREQ_LEN);
 			{
-			int f = (int)pBSS->uChannel - 1;
-			if(f < 0)f = 0;
-			iwe.u.freq.m = frequency_list[f] * 100000;
-			iwe.u.freq.e = 1;
+				int f = (int)pBSS->uChannel - 1;
+				if (f < 0)
+					f = 0;
+				iwe.u.freq.m = frequency_list[f] * 100000;
+				iwe.u.freq.e = 1;
 			}
-                  current_ev = iwe_stream_add_event(info,current_ev,end_buf, &iwe, IW_EV_FREQ_LEN);
-       		//ADD quality
-            memset(&iwe, 0, sizeof(iwe));
-	        iwe.cmd = IWEVQUAL;
-	        RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm);
-		    iwe.u.qual.level = ldBm;
-	        iwe.u.qual.noise = 0;
-
-			if(-ldBm<50){
+			current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
+			// ADD quality
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVQUAL;
+			RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm);
+			iwe.u.qual.level = ldBm;
+			iwe.u.qual.noise = 0;
+
+			if (-ldBm<50)
 				iwe.u.qual.qual = 100;
-			}else  if(-ldBm > 90) {
-				 iwe.u.qual.qual = 0;
-			}else {
-				iwe.u.qual.qual=(40-(-ldBm-50))*100/40;
+			else  if (-ldBm > 90)
+				iwe.u.qual.qual = 0;
+			else
+				iwe.u.qual.qual = (40 - (-ldBm - 50)) * 100 / 40;
+			iwe.u.qual.updated = 7;
+
+			current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+			// ADD encryption
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = SIOCGIWENCODE;
+			iwe.u.data.length = 0;
+			if (WLAN_GET_CAP_INFO_PRIVACY(pBSS->wCapInfo))
+				iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+			else
+				iwe.u.data.flags = IW_ENCODE_DISABLED;
+			current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, pItemSSID->abySSID);
+
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = SIOCGIWRATE;
+			iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+			current_val = current_ev + IW_EV_LCP_LEN;
+
+			for (kk = 0; kk < 12; kk++) {
+				if (pSuppRates->abyRates[kk] == 0)
+					break;
+				// Bit rate given in 500 kb/s units (+ 0x80)
+				iwe.u.bitrate.value = ((pSuppRates->abyRates[kk] & 0x7f) * 500000);
+				current_val = iwe_stream_add_value(info, current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
+			}
+			for (kk = 0; kk < 8; kk++) {
+				if (pExtSuppRates->abyRates[kk] == 0)
+					break;
+				// Bit rate given in 500 kb/s units (+ 0x80)
+				iwe.u.bitrate.value = ((pExtSuppRates->abyRates[kk] & 0x7f) * 500000);
+				current_val = iwe_stream_add_value(info, current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
 			}
-			iwe.u.qual.updated=7;
-
-                 current_ev = iwe_stream_add_event(info,current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
-       	//ADD encryption
-            memset(&iwe, 0, sizeof(iwe));
-            iwe.cmd = SIOCGIWENCODE;
-            iwe.u.data.length = 0;
-            if (WLAN_GET_CAP_INFO_PRIVACY(pBSS->wCapInfo)) {
-                iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-            }else {
-                iwe.u.data.flags = IW_ENCODE_DISABLED;
-            }
-            current_ev = iwe_stream_add_point(info,current_ev,end_buf, &iwe, pItemSSID->abySSID);
-
-            memset(&iwe, 0, sizeof(iwe));
-            iwe.cmd = SIOCGIWRATE;
-           	iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-      		current_val = current_ev + IW_EV_LCP_LEN;
-
-       		for (kk = 0 ; kk < 12 ; kk++) {
-		        if (pSuppRates->abyRates[kk] == 0)
-			        break;
-		        // Bit rate given in 500 kb/s units (+ 0x80)
-		        iwe.u.bitrate.value = ((pSuppRates->abyRates[kk] & 0x7f) * 500000);
-                          current_val = iwe_stream_add_value(info,current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
-	        }
-       		for (kk = 0 ; kk < 8 ; kk++) {
-		        if (pExtSuppRates->abyRates[kk] == 0)
-			        break;
-		        // Bit rate given in 500 kb/s units (+ 0x80)
-		        iwe.u.bitrate.value = ((pExtSuppRates->abyRates[kk] & 0x7f) * 500000);
-                         current_val = iwe_stream_add_value(info,current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
-	        }
-
-	        if((current_val - current_ev) > IW_EV_LCP_LEN)
-		        current_ev = current_val;
-
-            memset(&iwe, 0, sizeof(iwe));
-            iwe.cmd = IWEVCUSTOM;
-            sprintf(buf, "bcn_int=%d", pBSS->wBeaconInterval);
-            iwe.u.data.length = strlen(buf);
-             current_ev = iwe_stream_add_point(info,current_ev, end_buf, &iwe, buf);
-
-            if ((pBSS->wWPALen > 0) && (pBSS->wWPALen <= MAX_WPA_IE_LEN)) {
-                memset(&iwe, 0, sizeof(iwe));
-                iwe.cmd = IWEVGENIE;
-                iwe.u.data.length = pBSS->wWPALen;
-                current_ev = iwe_stream_add_point(info,current_ev, end_buf, &iwe, pBSS->byWPAIE);
-            }
-
-            if ((pBSS->wRSNLen > 0) && (pBSS->wRSNLen <= MAX_WPA_IE_LEN)) {
-                memset(&iwe, 0, sizeof(iwe));
-                iwe.cmd = IWEVGENIE;
-                iwe.u.data.length = pBSS->wRSNLen;
-                current_ev = iwe_stream_add_point(info,current_ev, end_buf, &iwe, pBSS->byRSNIE);
-            }
-
-        }
-    }// for
 
+			if ((current_val - current_ev) > IW_EV_LCP_LEN)
+				current_ev = current_val;
+
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVCUSTOM;
+			sprintf(buf, "bcn_int=%d", pBSS->wBeaconInterval);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf);
+
+			if ((pBSS->wWPALen > 0) && (pBSS->wWPALen <= MAX_WPA_IE_LEN)) {
+				memset(&iwe, 0, sizeof(iwe));
+				iwe.cmd = IWEVGENIE;
+				iwe.u.data.length = pBSS->wWPALen;
+				current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, pBSS->byWPAIE);
+			}
+
+			if ((pBSS->wRSNLen > 0) && (pBSS->wRSNLen <= MAX_WPA_IE_LEN)) {
+				memset(&iwe, 0, sizeof(iwe));
+				iwe.cmd = IWEVGENIE;
+				iwe.u.data.length = pBSS->wRSNLen;
+				current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, pBSS->byRSNIE);
+			}
+		}
+	} // for
 	wrq->length = current_ev - extra;
 	return 0;
-
 }
 
-
 /*
- * Wireless Handler : set frequence or channel
+ * Wireless Handler: set frequence or channel
  */
-
-int iwctl_siwfreq(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_freq *wrq,
-             char *extra)
+int iwctl_siwfreq(struct net_device *dev, struct iw_request_info *info,
+		struct iw_freq *wrq, char *extra)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
+	PSDevice pDevice = netdev_priv(dev);
 	int rc = 0;
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWFREQ \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWFREQ \n");
 
 	// If setting by frequency, convert to a channel
-	if((wrq->e == 1) &&
-	   (wrq->m >= (int) 2.412e8) &&
-	   (wrq->m <= (int) 2.487e8)) {
+	if ((wrq->e == 1) && (wrq->m >= (int)2.412e8) &&
+		(wrq->m <= (int)2.487e8)) {
 		int f = wrq->m / 100000;
 		int c = 0;
-		while((c < 14) && (f != frequency_list[c]))
+		while ((c < 14) && (f != frequency_list[c]))
 			c++;
 		wrq->e = 0;
 		wrq->m = c + 1;
 	}
 	// Setting by channel number
-	if((wrq->m > 14) || (wrq->e > 0))
+	if ((wrq->m > 14) || (wrq->e > 0)) {
 		rc = -EOPNOTSUPP;
-	else {
+	} else {
 		int channel = wrq->m;
-		if((channel < 1) || (channel > 14)) {
+		if ((channel < 1) || (channel > 14)) {
 			DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: New channel value of %d is invalid!\n", dev->name, wrq->m);
 			rc = -EINVAL;
 		} else {
-			  // Yes ! We can set it !!!
-              DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Set to channel = %d\n", channel);
-			  pDevice->uChannel = channel;
+			// Yes ! We can set it !!!
+			DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Set to channel = %d\n", channel);
+			pDevice->uChannel = channel;
 		}
 	}
-
 	return rc;
 }
 
 /*
- * Wireless Handler : get frequence or channel
+ * Wireless Handler: get frequence or channel
  */
-
-int iwctl_giwfreq(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_freq *wrq,
-             char *extra)
+int iwctl_giwfreq(struct net_device *dev, struct iw_request_info *info,
+		struct iw_freq *wrq, char *extra)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWFREQ \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWFREQ \n");
 
 #ifdef WEXT_USECHANNELS
 	wrq->m = (int)pMgmt->uCurrChannel;
@@ -390,74 +366,66 @@ int iwctl_giwfreq(struct net_device *dev,
 #else
 	{
 		int f = (int)pMgmt->uCurrChannel - 1;
-		if(f < 0)
-		   f = 0;
+		if (f < 0)
+			f = 0;
 		wrq->m = frequency_list[f] * 100000;
 		wrq->e = 1;
 	}
 #endif
-
 	return 0;
 }
 
 /*
- * Wireless Handler : set operation mode
+ * Wireless Handler: set operation mode
  */
-
-int iwctl_siwmode(struct net_device *dev,
-             struct iw_request_info *info,
-             __u32 *wmode,
-             char *extra)
+int iwctl_siwmode(struct net_device *dev, struct iw_request_info *info,
+		__u32 *wmode, char *extra)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-    int rc = 0;
-
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWMODE \n");
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+	int rc = 0;
 
-    if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP && pDevice->bEnableHostapd) {
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Can't set operation mode, hostapd is running \n");
-        return rc;
-    }
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWMODE \n");
 
-	switch(*wmode) {
+	if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP && pDevice->bEnableHostapd) {
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Can't set operation mode, hostapd is running \n");
+		return rc;
+	}
 
+	switch (*wmode) {
 	case IW_MODE_ADHOC:
-	    if (pMgmt->eConfigMode != WMAC_CONFIG_IBSS_STA) {
-            pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA;
-            if (pDevice->flags & DEVICE_FLAGS_OPENED) {
-		        pDevice->bCommit = TRUE;
-   		    }
+		if (pMgmt->eConfigMode != WMAC_CONFIG_IBSS_STA) {
+			pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA;
+			if (pDevice->flags & DEVICE_FLAGS_OPENED)
+				pDevice->bCommit = TRUE;
 		}
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to ad-hoc \n");
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to ad-hoc \n");
 		break;
 	case IW_MODE_AUTO:
 	case IW_MODE_INFRA:
-	    if (pMgmt->eConfigMode != WMAC_CONFIG_ESS_STA) {
-            pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
-            if (pDevice->flags & DEVICE_FLAGS_OPENED) {
-		        pDevice->bCommit = TRUE;
-   		    }
+		if (pMgmt->eConfigMode != WMAC_CONFIG_ESS_STA) {
+			pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
+			if (pDevice->flags & DEVICE_FLAGS_OPENED)
+				pDevice->bCommit = TRUE;
 		}
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to infrastructure \n");
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to infrastructure \n");
 		break;
 	case IW_MODE_MASTER:
 
-        pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
+		pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
 		rc = -EOPNOTSUPP;
 		break;
 
-	    if (pMgmt->eConfigMode != WMAC_CONFIG_AP) {
-            pMgmt->eConfigMode = WMAC_CONFIG_AP;
-            if (pDevice->flags & DEVICE_FLAGS_OPENED) {
-		        pDevice->bCommit = TRUE;
-   		    }
+		if (pMgmt->eConfigMode != WMAC_CONFIG_AP) {
+			pMgmt->eConfigMode = WMAC_CONFIG_AP;
+			if (pDevice->flags & DEVICE_FLAGS_OPENED)
+				pDevice->bCommit = TRUE;
 		}
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to Access Point \n");
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to Access Point \n");
 		break;
 
 	case IW_MODE_REPEAT:
-        pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
+		pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
 		rc = -EOPNOTSUPP;
 		break;
 	default:
@@ -468,26 +436,22 @@ int iwctl_siwmode(struct net_device *dev,
 }
 
 /*
- * Wireless Handler : get operation mode
+ * Wireless Handler: get operation mode
  */
-
-void iwctl_giwmode(struct net_device *dev,
-             struct iw_request_info *info,
-             __u32 *wmode,
-             char *extra)
+void iwctl_giwmode(struct net_device *dev, struct iw_request_info *info,
+		__u32 *wmode, char *extra)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWMODE \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWMODE \n");
 	// If not managed, assume it's ad-hoc
 	switch (pMgmt->eConfigMode) {
 	case WMAC_CONFIG_ESS_STA:
 		*wmode = IW_MODE_INFRA;
 		break;
 	case WMAC_CONFIG_IBSS_STA:
-        *wmode = IW_MODE_ADHOC;
+		*wmode = IW_MODE_ADHOC;
 		break;
 	case WMAC_CONFIG_AUTO:
 		*wmode = IW_MODE_INFRA;
@@ -500,21 +464,21 @@ void iwctl_giwmode(struct net_device *dev,
 	}
 }
 
-
 /*
- * Wireless Handler : get capability range
+ * Wireless Handler: get capability range
  */
-
-void iwctl_giwrange(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra)
+void iwctl_giwrange(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-	struct iw_range *range = (struct iw_range *) extra;
-	int		i,k;
-    BYTE abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
+	struct iw_range *range = (struct iw_range *)extra;
+	int i;
+	int k;
+	BYTE abySupportedRates[13] = {
+		0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48,
+		0x60, 0x6C, 0x90
+	};
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRANGE\n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRANGE\n");
 	if (wrq->pointer) {
 		wrq->length = sizeof(struct iw_range);
 		memset(range, 0, sizeof(struct iw_range));
@@ -522,7 +486,7 @@ void iwctl_giwrange(struct net_device *dev,
 		range->max_nwid = 0x0000;
 		range->num_channels = 14;
 		// Should be based on cap_rid.country to give only
-		//  what the current card support
+		// what the current card support
 		k = 0;
 		for (i = 0; i < 14; i++) {
 			range->freq[k].i = i + 1; // List index
@@ -531,14 +495,14 @@ void iwctl_giwrange(struct net_device *dev,
 		}
 		range->num_frequency = k;
 		// Hum... Should put the right values there
-                 range->max_qual.qual = 100;
+		range->max_qual.qual = 100;
 		range->max_qual.level = 0;
 		range->max_qual.noise = 0;
 		range->sensitivity = 255;
 
-		for (i = 0 ; i < 13 ; i++) {
+		for (i = 0; i < 13; i++) {
 			range->bitrate[i] = abySupportedRates[i] * 500000;
-			if(range->bitrate[i] == 0)
+			if (range->bitrate[i] == 0)
 				break;
 		}
 		range->num_bitrates = i;
@@ -546,7 +510,7 @@ void iwctl_giwrange(struct net_device *dev,
 		// Set an indication of the max TCP throughput
 		// in bit/s that we can expect using this interface.
 		//  May be use for QoS stuff... Jean II
-		if(i > 2)
+		if (i > 2)
 			range->throughput = 5 * 1000 * 1000;
 		else
 			range->throughput = 1.5 * 1000 * 1000;
@@ -556,32 +520,30 @@ void iwctl_giwrange(struct net_device *dev,
 		range->min_frag = 256;
 		range->max_frag = 2312;
 
+		// the encoding capabilities
+		range->num_encoding_sizes = 3;
+		// 64(40) bits WEP
+		range->encoding_size[0] = 5;
+		// 128(104) bits WEP
+		range->encoding_size[1] = 13;
+		// 256 bits for WPA-PSK
+		range->encoding_size[2] = 32;
+		// 4 keys are allowed
+		range->max_encoding_tokens = 4;
 
-	    // the encoding capabilities
-	    range->num_encoding_sizes = 3;
-	    // 64(40) bits WEP
-	    range->encoding_size[0] = 5;
-	    // 128(104) bits WEP
-	    range->encoding_size[1] = 13;
-	    // 256 bits for WPA-PSK
-	    range->encoding_size[2] = 32;
-	    // 4 keys are allowed
-	    range->max_encoding_tokens = 4;
-
-	    range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
-		    IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+		range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+			IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
 
 		range->min_pmp = 0;
-		range->max_pmp = 1000000;// 1 secs
+		range->max_pmp = 1000000; // 1 secs
 		range->min_pmt = 0;
-		range->max_pmt = 1000000;// 1 secs
+		range->max_pmt = 1000000; // 1 secs
 		range->pmp_flags = IW_POWER_PERIOD;
 		range->pmt_flags = IW_POWER_TIMEOUT;
 		range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
 
 		// Transmit Power - values are in mW
-
-        range->txpower[0] = 100;
+		range->txpower[0] = 100;
 		range->num_txpower = 1;
 		range->txpower_capa = IW_TXPOW_MWATT;
 		range->we_version_source = SUPPORTED_WIRELESS_EXT;
@@ -597,111 +559,97 @@ void iwctl_giwrange(struct net_device *dev,
 		// Note : with or without the (local->rssi), results
 		//  are somewhat different. - Jean II
 		range->avg_qual.qual = 6;
-		range->avg_qual.level = 176;	// -80 dBm
+		range->avg_qual.level = 176; // -80 dBm
 		range->avg_qual.noise = 0;
 	}
 }
 
-
 /*
  * Wireless Handler : set ap mac address
  */
-
-int iwctl_siwap(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct sockaddr *wrq,
-             char *extra)
+int iwctl_siwap(struct net_device *dev, struct iw_request_info *info,
+		struct sockaddr *wrq, char *extra)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-    int rc = 0;
-    BYTE                 ZeroBSSID[WLAN_BSSID_LEN]={0x00,0x00,0x00,0x00,0x00,0x00};
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+	int rc = 0;
+	BYTE ZeroBSSID[WLAN_BSSID_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
-   PRINT_K(" SIOCSIWAP \n");
+	PRINT_K(" SIOCSIWAP \n");
 
 	if (wrq->sa_family != ARPHRD_ETHER)
 		rc = -EINVAL;
 	else {
 		memcpy(pMgmt->abyDesireBSSID, wrq->sa_data, 6);
+		// mike: add
+		if ((is_broadcast_ether_addr(pMgmt->abyDesireBSSID)) ||
+			(memcmp(pMgmt->abyDesireBSSID, ZeroBSSID, 6) == 0)) {
+			PRINT_K("SIOCSIWAP:invalid desired BSSID return!\n");
+			return rc;
+		}
+		// mike add: if desired AP is hidden ssid(there are
+		// two same BSSID in list), then ignore,because you
+		// don't known which one to be connect with??
+		{
+			unsigned ii;
+			unsigned uSameBssidNum = 0;
+			for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+				if (pMgmt->sBSSList[ii].bActive &&
+					!compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID,
+							pMgmt->abyDesireBSSID)) {
+					uSameBssidNum++;
+				}
+			}
+			if (uSameBssidNum >= 2) {  //hit: desired AP is in hidden ssid mode!!!
+				PRINT_K("SIOCSIWAP:ignore for desired AP in hidden mode\n");
+				return rc;
+			}
+		}
 
-	//mike :add
-	 if ((is_broadcast_ether_addr(pMgmt->abyDesireBSSID)) ||
-	     (memcmp(pMgmt->abyDesireBSSID, ZeroBSSID, 6) == 0)){
-	      PRINT_K("SIOCSIWAP:invalid desired BSSID return!\n");
-               return rc;
-         }
-       //mike add: if desired AP is hidden ssid(there are two same BSSID in list),
-       //                  then ignore,because you don't known which one to be connect with??
-       	{
-		unsigned int ii, uSameBssidNum = 0;
-                  for (ii = 0; ii < MAX_BSS_NUM; ii++) {
-                     if (pMgmt->sBSSList[ii].bActive &&
-			 !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID,
-					     pMgmt->abyDesireBSSID)) {
-                        uSameBssidNum++;
-                     }
-                  }
-	     if(uSameBssidNum >= 2) {  //hit: desired AP is in hidden ssid mode!!!
-                 PRINT_K("SIOCSIWAP:ignore for desired AP in hidden mode\n");
-	        return rc;
-	     }
-       	}
-
-        if (pDevice->flags & DEVICE_FLAGS_OPENED) {
-		    pDevice->bCommit = TRUE;
-   		}
+		if (pDevice->flags & DEVICE_FLAGS_OPENED)
+			pDevice->bCommit = TRUE;
 	}
 	return rc;
 }
 
 /*
- * Wireless Handler : get ap mac address
+ * Wireless Handler: get ap mac address
  */
-
-int iwctl_giwap(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct sockaddr *wrq,
-             char *extra)
+int iwctl_giwap(struct net_device *dev, struct iw_request_info *info,
+		struct sockaddr *wrq, char *extra)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWAP \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWAP \n");
 
-    memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6);
+	memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6);
 
- if ((pDevice->bLinkPass == FALSE) && (pMgmt->eCurrMode != WMAC_MODE_ESS_AP))
-        memset(wrq->sa_data, 0, 6);
+	if ((pDevice->bLinkPass == FALSE) && (pMgmt->eCurrMode != WMAC_MODE_ESS_AP))
+		memset(wrq->sa_data, 0, 6);
 
-    if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
-        memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6);
-    }
+	if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)
+		memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6);
 
 	wrq->sa_family = ARPHRD_ETHER;
-
 	return 0;
-
 }
 
-
 /*
- * Wireless Handler : get ap list
+ * Wireless Handler: get ap list
  */
-
-int iwctl_giwaplist(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra)
+int iwctl_giwaplist(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-	int ii,jj, rc = 0;
+	int ii;
+	int jj;
+	int rc = 0;
 	struct sockaddr sock[IW_MAX_AP];
 	struct iw_quality qual[IW_MAX_AP];
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWAPLIST \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWAPLIST \n");
 	// Only super-user can see AP list
 
 	if (!capable(CAP_NET_ADMIN)) {
@@ -710,15 +658,14 @@ int iwctl_giwaplist(struct net_device *dev,
 	}
 
 	if (wrq->pointer) {
-
 		PKnownBSS pBSS = &(pMgmt->sBSSList[0]);
 
 		for (ii = 0, jj= 0; ii < MAX_BSS_NUM; ii++) {
-		    pBSS = &(pMgmt->sBSSList[ii]);
-            if (!pBSS->bActive)
-                continue;
-            if ( jj >= IW_MAX_AP)
-                break;
+			pBSS = &(pMgmt->sBSSList[ii]);
+			if (!pBSS->bActive)
+				continue;
+			if (jj >= IW_MAX_AP)
+				break;
 			memcpy(sock[jj].sa_data, pBSS->abyBSSID, 6);
 			sock[jj].sa_family = ARPHRD_ETHER;
 			qual[jj].level = pBSS->uRSSI;
@@ -729,151 +676,137 @@ int iwctl_giwaplist(struct net_device *dev,
 
 		wrq->flags = 1; // Should be define'd
 		wrq->length = jj;
-		memcpy(extra, sock, sizeof(struct sockaddr)*jj);
-		memcpy(extra + sizeof(struct sockaddr)*jj, qual, sizeof(struct iw_quality)*jj);
+		memcpy(extra, sock, sizeof(struct sockaddr) * jj);
+		memcpy(extra + sizeof(struct sockaddr) * jj, qual, sizeof(struct iw_quality) * jj);
 	}
-
 	return rc;
 }
 
-
 /*
- * Wireless Handler : set essid
+ * Wireless Handler: set essid
  */
-
-int iwctl_siwessid(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra)
+int iwctl_siwessid(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-    PWLAN_IE_SSID       pItemSSID;
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+	PWLAN_IE_SSID pItemSSID;
 
-  if (!(pDevice->flags & DEVICE_FLAGS_OPENED))
-        return -EINVAL;
+	if (!(pDevice->flags & DEVICE_FLAGS_OPENED))
+		return -EINVAL;
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWESSID :\n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWESSID :\n");
 
-         pDevice->fWPA_Authened = FALSE;
+	pDevice->fWPA_Authened = FALSE;
 	// Check if we asked for `any'
-	if(wrq->flags == 0) {
+	if (wrq->flags == 0) {
 		// Just send an empty SSID list
 		memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
-                  memset(pMgmt->abyDesireBSSID, 0xFF,6);
-	    PRINT_K("set essid to 'any' \n");
-           #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
-             //Unknown desired AP,so here need not associate??
-                  return 0;
-            #endif
+		memset(pMgmt->abyDesireBSSID, 0xFF,6);
+		PRINT_K("set essid to 'any' \n");
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+		// Unknown desired AP, so here need not associate??
+		return 0;
+#endif
 	} else {
 		// Set the SSID
 		memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
-        pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
-        pItemSSID->byElementID = WLAN_EID_SSID;
+		pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
+		pItemSSID->byElementID = WLAN_EID_SSID;
 
 		memcpy(pItemSSID->abySSID, extra, wrq->length);
-         if (pItemSSID->abySSID[wrq->length - 1] == '\0') {
-           if(wrq->length>0)
-		pItemSSID->len = wrq->length - 1;
-         }
-	else
-	  pItemSSID->len = wrq->length;
-	PRINT_K("set essid to %s \n",pItemSSID->abySSID);
+		if (pItemSSID->abySSID[wrq->length - 1] == '\0') {
+			if (wrq->length>0)
+				pItemSSID->len = wrq->length - 1;
+		} else {
+			pItemSSID->len = wrq->length;
+		}
+		PRINT_K("set essid to %s \n", pItemSSID->abySSID);
 
-     //mike:need clear desiredBSSID
-     if(pItemSSID->len==0) {
-        memset(pMgmt->abyDesireBSSID, 0xFF,6);
-        return 0;
-     }
+		// mike: need clear desiredBSSID
+		if (pItemSSID->len==0) {
+			memset(pMgmt->abyDesireBSSID, 0xFF, 6);
+			return 0;
+		}
 
 #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- //Wext wil order another command of siwap to link with desired AP,
- //so here need not associate??
-  if(pDevice->bWPASuppWextEnabled == TRUE)  {
-        /*******search if  in hidden ssid mode ****/
-        {
-           PKnownBSS       pCurr = NULL;
-           BYTE                   abyTmpDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
-	  unsigned int ii, uSameBssidNum = 0;
-
-	  memcpy(abyTmpDesireSSID,pMgmt->abyDesireSSID,sizeof(abyTmpDesireSSID));
-            pCurr = BSSpSearchBSSList(pDevice,
-                                      NULL,
-                                      abyTmpDesireSSID,
-                                      pDevice->eConfigPHYMode
-                                      );
-
-            if (pCurr == NULL){
-               PRINT_K("SIOCSIWESSID:hidden ssid site survey before associate.......\n");
-	      vResetCommandTimer((void *) pDevice);
-	      pMgmt->eScanType = WMAC_SCAN_ACTIVE;
-	      bScheduleCommand((void *) pDevice,
-			       WLAN_CMD_BSSID_SCAN,
-			       pMgmt->abyDesireSSID);
-	      bScheduleCommand((void *) pDevice,
-			       WLAN_CMD_SSID,
-			       pMgmt->abyDesireSSID);
-          }
-	 else {  //mike:to find out if that desired SSID is a hidden-ssid AP ,
-                     //         by means of judging if there are two same BSSID exist in list ?
-                  for (ii = 0; ii < MAX_BSS_NUM; ii++) {
-                     if (pMgmt->sBSSList[ii].bActive &&
-			 !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID,
-					     pCurr->abyBSSID)) {
-                        uSameBssidNum++;
-                     }
-                  }
-	     if(uSameBssidNum >= 2) {  //hit: desired AP is in hidden ssid mode!!!
-                 PRINT_K("SIOCSIWESSID:hidden ssid directly associate.......\n");
-		 vResetCommandTimer((void *) pDevice);
-	        pMgmt->eScanType = WMAC_SCAN_PASSIVE;          //this scan type,you'll submit scan result!
-		bScheduleCommand((void *) pDevice,
-				 WLAN_CMD_BSSID_SCAN,
-				 pMgmt->abyDesireSSID);
-		bScheduleCommand((void *) pDevice,
-				 WLAN_CMD_SSID,
-				 pMgmt->abyDesireSSID);
-	     }
-	 }
-        }
-     return 0;
-  }
-	     #endif
-
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set essid = %s \n", pItemSSID->abySSID);
-	}
+		// Wext wil order another command of siwap to link
+		// with desired AP, so here need not associate??
+		if (pDevice->bWPASuppWextEnabled == TRUE)  {
+			/*******search if  in hidden ssid mode ****/
+			PKnownBSS pCurr = NULL;
+			BYTE abyTmpDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+			unsigned ii;
+			unsigned uSameBssidNum = 0;
+
+			memcpy(abyTmpDesireSSID, pMgmt->abyDesireSSID, sizeof(abyTmpDesireSSID));
+			pCurr = BSSpSearchBSSList(pDevice, NULL,
+						abyTmpDesireSSID,
+						pDevice->eConfigPHYMode);
+
+			if (pCurr == NULL) {
+				PRINT_K("SIOCSIWESSID:hidden ssid site survey before associate.......\n");
+				vResetCommandTimer((void *)pDevice);
+				pMgmt->eScanType = WMAC_SCAN_ACTIVE;
+				bScheduleCommand((void *)pDevice,
+						WLAN_CMD_BSSID_SCAN,
+						pMgmt->abyDesireSSID);
+				bScheduleCommand((void *)pDevice,
+						WLAN_CMD_SSID,
+						pMgmt->abyDesireSSID);
+			} else {  // mike: to find out if that desired SSID is a
+				// hidden-ssid AP, by means of judging if there
+				// are two same BSSID exist in list ?
+				for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+					if (pMgmt->sBSSList[ii].bActive &&
+						!compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID,
+								pCurr->abyBSSID)) {
+						uSameBssidNum++;
+					}
+				}
+				if (uSameBssidNum >= 2) { // hit: desired AP is in hidden ssid mode!!!
+					PRINT_K("SIOCSIWESSID:hidden ssid directly associate.......\n");
+					vResetCommandTimer((void *)pDevice);
+					pMgmt->eScanType = WMAC_SCAN_PASSIVE; // this scan type, you'll submit scan result!
+					bScheduleCommand((void *)pDevice,
+							WLAN_CMD_BSSID_SCAN,
+							pMgmt->abyDesireSSID);
+					bScheduleCommand((void *)pDevice,
+							WLAN_CMD_SSID,
+							pMgmt->abyDesireSSID);
+				}
+			}
+			return 0;
+		}
+#endif
 
-    if (pDevice->flags & DEVICE_FLAGS_OPENED) {
-	    pDevice->bCommit = TRUE;
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set essid = %s \n", pItemSSID->abySSID);
 	}
 
+	if (pDevice->flags & DEVICE_FLAGS_OPENED)
+		pDevice->bCommit = TRUE;
 
 	return 0;
 }
 
-
 /*
- * Wireless Handler : get essid
+ * Wireless Handler: get essid
  */
-void iwctl_giwessid(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra)
+void iwctl_giwessid(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+	PWLAN_IE_SSID pItemSSID;
 
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-	PWLAN_IE_SSID       pItemSSID;
-
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWESSID \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWESSID \n");
 
-	// Note : if wrq->u.data.flags != 0, we should
-	// get the relevant SSID from the SSID list...
+	// Note: if wrq->u.data.flags != 0, we should get the relevant
+	// SSID from the SSID list...
 
 	// Get the current SSID
-    pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
-	memcpy(extra, pItemSSID->abySSID , pItemSSID->len);
+	pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
+	memcpy(extra, pItemSSID->abySSID, pItemSSID->len);
 	extra[pItemSSID->len] = '\0';
 
         wrq->length = pItemSSID->len;
@@ -881,146 +814,139 @@ void iwctl_giwessid(struct net_device *dev,
 }
 
 /*
- * Wireless Handler : set data rate
+ * Wireless Handler: set data rate
  */
-
-int iwctl_siwrate(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra)
+int iwctl_siwrate(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    int rc = 0;
-	u8	brate = 0;
-	int	i;
-	BYTE abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
-
+	PSDevice pDevice = netdev_priv(dev);
+	int rc = 0;
+	u8 brate = 0;
+	int i;
+	BYTE abySupportedRates[13] = {
+		0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48,
+		0x60, 0x6C, 0x90
+	};
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRATE \n");
-    if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) {
-        rc = -EINVAL;
-        return rc;
-    }
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRATE \n");
+	if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) {
+		rc = -EINVAL;
+		return rc;
+	}
 
-	// First : get a valid bit rate value
+	// First: get a valid bit rate value
 
 	// Which type of value
-	if((wrq->value < 13) &&
-	   (wrq->value >= 0)) {
+	if ((wrq->value < 13) && (wrq->value >= 0)) {
 		// Setting by rate index
 		// Find value in the magic rate table
 		brate = wrq->value;
 	} else {
 		// Setting by frequency value
-		u8	normvalue = (u8) (wrq->value/500000);
+		u8 normvalue = (u8)(wrq->value/500000);
 
 		// Check if rate is valid
-		for (i = 0 ; i < 13 ; i++) {
-			if(normvalue == abySupportedRates[i]) {
+		for (i = 0; i < 13; i++) {
+			if (normvalue == abySupportedRates[i]) {
 				brate = i;
 				break;
 			}
 		}
 	}
 	// -1 designed the max rate (mostly auto mode)
-	if(wrq->value == -1) {
+	if (wrq->value == -1) {
 		// Get the highest available rate
-		for (i = 0 ; i < 13 ; i++) {
-			if(abySupportedRates[i] == 0)
+		for (i = 0; i < 13; i++) {
+			if (abySupportedRates[i] == 0)
 				break;
 		}
-		if(i != 0)
+		if (i != 0)
 			brate = i - 1;
 
 	}
 	// Check that it is valid
 	// brate is index of abySupportedRates[]
-	if(brate > 13 ) {
+	if (brate > 13 ) {
 		rc = -EINVAL;
 		return rc;
 	}
 
 	// Now, check if we want a fixed or auto value
-	if(wrq->fixed != 0) {
+	if (wrq->fixed != 0) {
 		// Fixed mode
 		// One rate, fixed
 		pDevice->bFixRate = TRUE;
-        if ((pDevice->byBBType == BB_TYPE_11B)&& (brate > 3)) {
-            pDevice->uConnectionRate = 3;
-        }
-        else {
-            pDevice->uConnectionRate = brate;
-            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Fixed to Rate %d \n", pDevice->uConnectionRate);
-        }
-
+		if ((pDevice->byBBType == BB_TYPE_11B) && (brate > 3)) {
+			pDevice->uConnectionRate = 3;
+		} else {
+			pDevice->uConnectionRate = brate;
+			DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Fixed to Rate %d \n", pDevice->uConnectionRate);
+		}
 	}
 	else {
-        pDevice->bFixRate = FALSE;
-        pDevice->uConnectionRate = 13;
-    }
+		pDevice->bFixRate = FALSE;
+		pDevice->uConnectionRate = 13;
+	}
 
 	return rc;
 }
 
 /*
- * Wireless Handler : get data rate
+ * Wireless Handler: get data rate
  */
-void iwctl_giwrate(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_param *wrq,
-             char *extra)
+void iwctl_giwrate(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRATE \n");
+	{
+		BYTE abySupportedRates[13] = {
+			0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30,
+			0x48, 0x60, 0x6C, 0x90
+		};
+		int brate = 0;
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRATE \n");
-    {
-        BYTE abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
-	    int brate = 0;
 		if (pDevice->uConnectionRate < 13) {
-	        brate = abySupportedRates[pDevice->uConnectionRate];
-	    }else {
-            if (pDevice->byBBType == BB_TYPE_11B)
-	            brate = 0x16;
-            if (pDevice->byBBType == BB_TYPE_11G)
-	            brate = 0x6C;
-            if (pDevice->byBBType == BB_TYPE_11A)
-	            brate = 0x6C;
-	    }
-
-	    if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
-            if (pDevice->byBBType == BB_TYPE_11B)
-	            brate = 0x16;
-            if (pDevice->byBBType == BB_TYPE_11G)
-	            brate = 0x6C;
-            if (pDevice->byBBType == BB_TYPE_11A)
-	            brate = 0x6C;
-	    }
+			brate = abySupportedRates[pDevice->uConnectionRate];
+		} else {
+			if (pDevice->byBBType == BB_TYPE_11B)
+				brate = 0x16;
+			if (pDevice->byBBType == BB_TYPE_11G)
+				brate = 0x6C;
+			if (pDevice->byBBType == BB_TYPE_11A)
+				brate = 0x6C;
+		}
+		if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+			if (pDevice->byBBType == BB_TYPE_11B)
+				brate = 0x16;
+			if (pDevice->byBBType == BB_TYPE_11G)
+				brate = 0x6C;
+			if (pDevice->byBBType == BB_TYPE_11A)
+				brate = 0x6C;
+		}
     		if (pDevice->uConnectionRate == 13)
-                brate = abySupportedRates[pDevice->wCurrentRate];
-	    wrq->value = brate * 500000;
-	    // If more than one rate, set auto
-	    if (pDevice->bFixRate == TRUE)
-	        wrq->fixed = TRUE;
-    }
+			brate = abySupportedRates[pDevice->wCurrentRate];
+		wrq->value = brate * 500000;
+		// If more than one rate, set auto
+		if (pDevice->bFixRate == TRUE)
+			wrq->fixed = TRUE;
+	}
 }
 
-
-
 /*
- * Wireless Handler : set rts threshold
+ * Wireless Handler: set rts threshold
  */
-int iwctl_siwrts(struct net_device *dev,
-		 struct iw_param *wrq)
+int iwctl_siwrts(struct net_device *dev, struct iw_param *wrq)
 {
-	PSDevice pDevice = (PSDevice)netdev_priv(dev);
+	PSDevice pDevice = netdev_priv(dev);
 
 	if ((wrq->value < 0 || wrq->value > 2312) && !wrq->disabled)
 		return -EINVAL;
 
 	else if (wrq->disabled)
 		pDevice->wRTSThreshold = 2312;
-
 	else
 		pDevice->wRTSThreshold = wrq->value;
 
@@ -1028,17 +954,14 @@ int iwctl_siwrts(struct net_device *dev,
 }
 
 /*
- * Wireless Handler : get rts
+ * Wireless Handler: get rts
  */
-
-int iwctl_giwrts(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra)
+int iwctl_giwrts(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
-	PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
+	PSDevice pDevice = netdev_priv(dev);
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRTS \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRTS \n");
 	wrq->value = pDevice->wRTSThreshold;
 	wrq->disabled = (wrq->value >= 2312);
 	wrq->fixed = 1;
@@ -1047,46 +970,37 @@ int iwctl_giwrts(struct net_device *dev,
 }
 
 /*
- * Wireless Handler : set fragment threshold
+ * Wireless Handler: set fragment threshold
  */
-
-int iwctl_siwfrag(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra)
+int iwctl_siwfrag(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
-    PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    int rc = 0;
-    int fthr = wrq->value;
-
-
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWFRAG \n");
+	PSDevice pDevice = netdev_priv(dev);
+	int rc = 0;
+	int fthr = wrq->value;
 
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWFRAG \n");
 
-    if (wrq->disabled)
+	if (wrq->disabled)
 		fthr = 2312;
-    if((fthr < 256) || (fthr > 2312)) {
+	if ((fthr < 256) || (fthr > 2312)) {
 		rc = -EINVAL;
-    }else {
-		 fthr &= ~0x1;	// Get an even value
-	     pDevice->wFragmentationThreshold = (u16)fthr;
-    }
-
+	} else {
+		fthr &= ~0x1; // Get an even value
+		pDevice->wFragmentationThreshold = (u16)fthr;
+	}
 	return rc;
 }
 
 /*
- * Wireless Handler : get fragment threshold
+ * Wireless Handler: get fragment threshold
  */
-
-int iwctl_giwfrag(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra)
+int iwctl_giwfrag(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
-    PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
+	PSDevice pDevice = netdev_priv(dev);
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWFRAG \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWFRAG \n");
 	wrq->value = pDevice->wFragmentationThreshold;
 	wrq->disabled = (wrq->value >= 2312);
 	wrq->fixed = 1;
@@ -1094,21 +1008,16 @@ int iwctl_giwfrag(struct net_device *dev,
 	return 0;
 }
 
-
-
 /*
- * Wireless Handler : set retry threshold
+ * Wireless Handler: set retry threshold
  */
-int iwctl_siwretry(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra)
+int iwctl_siwretry(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
-    PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    int rc = 0;
-
+	PSDevice pDevice = netdev_priv(dev);
+	int rc = 0;
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRETRY \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRETRY \n");
 
 	if (wrq->disabled) {
 		rc = -EINVAL;
@@ -1116,238 +1025,217 @@ int iwctl_siwretry(struct net_device *dev,
 	}
 
 	if (wrq->flags & IW_RETRY_LIMIT) {
-		if(wrq->flags & IW_RETRY_MAX)
+		if (wrq->flags & IW_RETRY_MAX) {
 			pDevice->byLongRetryLimit = wrq->value;
-		else if (wrq->flags & IW_RETRY_MIN)
+		} else if (wrq->flags & IW_RETRY_MIN) {
 			pDevice->byShortRetryLimit = wrq->value;
-		else {
+		} else {
 			// No modifier : set both
 			pDevice->byShortRetryLimit = wrq->value;
 			pDevice->byLongRetryLimit = wrq->value;
 		}
 	}
-	if (wrq->flags & IW_RETRY_LIFETIME) {
+	if (wrq->flags & IW_RETRY_LIFETIME)
 		pDevice->wMaxTransmitMSDULifetime = wrq->value;
-	}
-
-
 	return rc;
 }
 
 /*
- * Wireless Handler : get retry threshold
+ * Wireless Handler: get retry threshold
  */
-int iwctl_giwretry(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra)
+int iwctl_giwretry(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
-    PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRETRY \n");
-	wrq->disabled = 0;      // Can't be disabled
+	PSDevice pDevice = netdev_priv(dev);
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRETRY \n");
+	wrq->disabled = 0; // Can't be disabled
 
-	// Note : by default, display the min retry number
-	if((wrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+	// Note: by default, display the min retry number
+	if ((wrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
 		wrq->flags = IW_RETRY_LIFETIME;
-		wrq->value = (int)pDevice->wMaxTransmitMSDULifetime; //ms
-	} else if((wrq->flags & IW_RETRY_MAX)) {
+		wrq->value = (int)pDevice->wMaxTransmitMSDULifetime; // ms
+	} else if ((wrq->flags & IW_RETRY_MAX)) {
 		wrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
 		wrq->value = (int)pDevice->byLongRetryLimit;
 	} else {
 		wrq->flags = IW_RETRY_LIMIT;
 		wrq->value = (int)pDevice->byShortRetryLimit;
-		if((int)pDevice->byShortRetryLimit != (int)pDevice->byLongRetryLimit)
+		if ((int)pDevice->byShortRetryLimit != (int)pDevice->byLongRetryLimit)
 			wrq->flags |= IW_RETRY_MIN;
 	}
-
-
 	return 0;
 }
 
-
 /*
- * Wireless Handler : set encode mode
+ * Wireless Handler: set encode mode
  */
-int iwctl_siwencode(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra)
+int iwctl_siwencode(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-    PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
 	DWORD dwKeyIndex = (DWORD)(wrq->flags & IW_ENCODE_INDEX);
-	int ii,uu, rc = 0;
+	int ii;
+	int uu;
+	int rc = 0;
 	int index = (wrq->flags & IW_ENCODE_INDEX);
 
-
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWENCODE \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWENCODE \n");
 
 	// Check the size of the key
 	if (wrq->length > WLAN_WEP232_KEYLEN) {
 		rc = -EINVAL;
-        return rc;
+		return rc;
 	}
 
 	if (dwKeyIndex > WLAN_WEP_NKEYS) {
 		rc = -EINVAL;
-        return rc;
-    }
+		return rc;
+	}
 
-    if (dwKeyIndex > 0)
+	if (dwKeyIndex > 0)
 		dwKeyIndex--;
 
 	// Send the key to the card
 	if (wrq->length > 0) {
 
-        if (wrq->length ==  WLAN_WEP232_KEYLEN) {
-            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 232 bit wep key\n");
-        }
-        else if (wrq->length ==  WLAN_WEP104_KEYLEN) {
-            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 104 bit wep key\n");
-        }
-        else if (wrq->length == WLAN_WEP40_KEYLEN) {
-            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 40 bit wep key, index= %d\n", (int)dwKeyIndex);
-        }
-        memset(pDevice->abyKey, 0, WLAN_WEP232_KEYLEN);
-        memcpy(pDevice->abyKey, extra, wrq->length);
-
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyKey: ");
-        for (ii = 0; ii < wrq->length; ii++) {
-            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pDevice->abyKey[ii]);
-        }
-
-        if (pDevice->flags & DEVICE_FLAGS_OPENED) {
-            spin_lock_irq(&pDevice->lock);
-            KeybSetDefaultKey(  pDevice,
-                                &(pDevice->sKey),
-                                dwKeyIndex | (1 << 31),
-                                wrq->length,
-                                NULL,
-                                pDevice->abyKey,
-                                KEY_CTL_WEP
-                              );
-            spin_unlock_irq(&pDevice->lock);
-        }
-        pDevice->byKeyIndex = (BYTE)dwKeyIndex;
-        pDevice->uKeyLength = wrq->length;
-        pDevice->bTransmitKey = TRUE;
-        pDevice->bEncryptionEnable = TRUE;
-        pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
-
-		// Do we want to just set the transmit key index ?
-		if ( index < 4 ) {
-		    pDevice->byKeyIndex = index;
+		if (wrq->length ==  WLAN_WEP232_KEYLEN) {
+			DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 232 bit wep key\n");
+		} else if (wrq->length ==  WLAN_WEP104_KEYLEN) {
+			DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 104 bit wep key\n");
+		} else if (wrq->length == WLAN_WEP40_KEYLEN) {
+			DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 40 bit wep key, index= %d\n", (int)dwKeyIndex);
+		}
+		memset(pDevice->abyKey, 0, WLAN_WEP232_KEYLEN);
+		memcpy(pDevice->abyKey, extra, wrq->length);
+
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyKey: ");
+		for (ii = 0; ii < wrq->length; ii++)
+			DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pDevice->abyKey[ii]);
+
+		if (pDevice->flags & DEVICE_FLAGS_OPENED) {
+			spin_lock_irq(&pDevice->lock);
+			KeybSetDefaultKey(pDevice,
+					&(pDevice->sKey),
+					dwKeyIndex | (1 << 31),
+					wrq->length, NULL,
+					pDevice->abyKey,
+					KEY_CTL_WEP
+				);
+			spin_unlock_irq(&pDevice->lock);
+		}
+		pDevice->byKeyIndex = (BYTE)dwKeyIndex;
+		pDevice->uKeyLength = wrq->length;
+		pDevice->bTransmitKey = TRUE;
+		pDevice->bEncryptionEnable = TRUE;
+		pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
+
+		// Do we want to just set the transmit key index?
+		if (index < 4) {
+			pDevice->byKeyIndex = index;
 		} else if (!(wrq->flags & IW_ENCODE_MODE)) {
-				rc = -EINVAL;
-				return rc;
-	    }
+			rc = -EINVAL;
+			return rc;
+		}
 	}
 	// Read the flags
-	if(wrq->flags & IW_ENCODE_DISABLED){
-
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable WEP function\n");
+	if (wrq->flags & IW_ENCODE_DISABLED) {
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable WEP function\n");
 		pMgmt->bShareKeyAlgorithm = FALSE;
-        pDevice->bEncryptionEnable = FALSE;
-        pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
-        if (pDevice->flags & DEVICE_FLAGS_OPENED) {
-            spin_lock_irq(&pDevice->lock);
-	    for (uu = 0; uu < MAX_KEY_TABLE; uu++)
-		MACvDisableKeyEntry(pDevice, uu);
-            spin_unlock_irq(&pDevice->lock);
-        }
+		pDevice->bEncryptionEnable = FALSE;
+		pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
+		if (pDevice->flags & DEVICE_FLAGS_OPENED) {
+			spin_lock_irq(&pDevice->lock);
+			for (uu = 0; uu < MAX_KEY_TABLE; uu++)
+				MACvDisableKeyEntry(pDevice, uu);
+			spin_unlock_irq(&pDevice->lock);
+		}
 	}
-	if(wrq->flags & IW_ENCODE_RESTRICTED) {
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & ShareKey System\n");
+	if (wrq->flags & IW_ENCODE_RESTRICTED) {
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & ShareKey System\n");
 		pMgmt->bShareKeyAlgorithm = TRUE;
 	}
-	if(wrq->flags & IW_ENCODE_OPEN) {
-	    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & Open System\n");
+	if (wrq->flags & IW_ENCODE_OPEN) {
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & Open System\n");
 		pMgmt->bShareKeyAlgorithm = FALSE;
 	}
 
 #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
-	   memset(pMgmt->abyDesireBSSID, 0xFF,6);
+	memset(pMgmt->abyDesireBSSID, 0xFF, 6);
 #endif
-
 	return rc;
 }
 
-int iwctl_giwencode(struct net_device *dev,
-			struct iw_request_info *info,
-			struct iw_point *wrq,
-			char *extra)
+int iwctl_giwencode(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-	PSDevice			pDevice = (PSDevice)netdev_priv(dev);
-	PSMgmtObject		pMgmt = &(pDevice->sMgmtObj);
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
 	char abyKey[WLAN_WEP232_KEYLEN];
 
-	unsigned int index = (unsigned int)(wrq->flags & IW_ENCODE_INDEX);
-	PSKeyItem	pKey = NULL;
+	unsigned index = (unsigned)(wrq->flags & IW_ENCODE_INDEX);
+	PSKeyItem pKey = NULL;
 
 	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWENCODE\n");
 
-	if (index > WLAN_WEP_NKEYS) {
+	if (index > WLAN_WEP_NKEYS)
 		return	-EINVAL;
+	if (index < 1) { // get default key
+		if (pDevice->byKeyIndex < WLAN_WEP_NKEYS)
+			index = pDevice->byKeyIndex;
+         	else
+			index = 0;
+	} else {
+		index--;
 	}
-	if(index<1){//get default key
-		if(pDevice->byKeyIndex<WLAN_WEP_NKEYS){
-			index=pDevice->byKeyIndex;
-         	} else
-                      index=0;
-	}else
-             index--;
 
 	memset(abyKey, 0, WLAN_WEP232_KEYLEN);
 	// Check encryption mode
 	wrq->flags = IW_ENCODE_NOKEY;
 	// Is WEP enabled ???
 	if (pDevice->bEncryptionEnable)
-		wrq->flags |=  IW_ENCODE_ENABLED;
+		wrq->flags |= IW_ENCODE_ENABLED;
 	else
-		wrq->flags |=  IW_ENCODE_DISABLED;
+		wrq->flags |= IW_ENCODE_DISABLED;
 
 	if (pMgmt->bShareKeyAlgorithm)
-		wrq->flags |=  IW_ENCODE_RESTRICTED;
+		wrq->flags |= IW_ENCODE_RESTRICTED;
 	else
-		wrq->flags |=  IW_ENCODE_OPEN;
-		wrq->length=0;
-
-	if((index==0)&&(pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled||
-		pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)){//get wpa pairwise  key
-			if (KeybGetKey(&(pDevice->sKey),pMgmt->abyCurrBSSID, 0xffffffff, &pKey)){
-			   wrq->length = pKey->uKeyLength;
-				  memcpy(abyKey, pKey->abyKey,	pKey->uKeyLength);
-				  memcpy(extra,  abyKey, WLAN_WEP232_KEYLEN);
-			   }
-	}else if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (BYTE)index , &pKey)){
+		wrq->flags |= IW_ENCODE_OPEN;
+	wrq->length = 0;
+
+	if ((index == 0) && (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled ||
+				pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)){ // get wpa pairwise  key
+		if (KeybGetKey(&(pDevice->sKey), pMgmt->abyCurrBSSID, 0xffffffff, &pKey)) {
 			wrq->length = pKey->uKeyLength;
-			memcpy(abyKey, pKey->abyKey,  pKey->uKeyLength);
-		memcpy(extra,  abyKey, WLAN_WEP232_KEYLEN);
+			memcpy(abyKey, pKey->abyKey,	pKey->uKeyLength);
+			memcpy(extra,  abyKey, WLAN_WEP232_KEYLEN);
+		}
+	} else if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (BYTE)index, &pKey)) {
+		wrq->length = pKey->uKeyLength;
+		memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
+		memcpy(extra, abyKey, WLAN_WEP232_KEYLEN);
 	}
 
-	wrq->flags |= index+1;
-
+	wrq->flags |= index + 1;
 	return 0;
 }
 
-
 /*
- * Wireless Handler : set power mode
+ * Wireless Handler: set power mode
  */
-int iwctl_siwpower(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra)
+int iwctl_siwpower(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
-    PSDevice            pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-    int rc = 0;
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+	int rc = 0;
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER \n");
 
-    if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) {
-		 rc = -EINVAL;
-		 return rc;
+	if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) {
+		rc = -EINVAL;
+		return rc;
 	}
 
 	if (wrq->disabled) {
@@ -1356,23 +1244,23 @@ int iwctl_siwpower(struct net_device *dev,
 		return rc;
 	}
 	if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-         pDevice->ePSMode = WMAC_POWER_FAST;
-	 PSvEnablePowerSaving((void *) pDevice, pMgmt->wListenInterval);
+		pDevice->ePSMode = WMAC_POWER_FAST;
+		PSvEnablePowerSaving((void *)pDevice, pMgmt->wListenInterval);
 
 	} else if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
-	     pDevice->ePSMode = WMAC_POWER_FAST;
-	     PSvEnablePowerSaving((void *) pDevice, pMgmt->wListenInterval);
+		pDevice->ePSMode = WMAC_POWER_FAST;
+		PSvEnablePowerSaving((void *)pDevice, pMgmt->wListenInterval);
 	}
 	switch (wrq->flags & IW_POWER_MODE) {
 	case IW_POWER_UNICAST_R:
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_UNICAST_R \n");
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_UNICAST_R \n");
 		rc = -EINVAL;
 		break;
 	case IW_POWER_ALL_R:
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ALL_R \n");
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ALL_R \n");
 		rc = -EINVAL;
 	case IW_POWER_ON:
-        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ON \n");
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ON \n");
 		break;
 	default:
 		rc = -EINVAL;
@@ -1382,23 +1270,19 @@ int iwctl_siwpower(struct net_device *dev,
 }
 
 /*
- * Wireless Handler : get power mode
+ * Wireless Handler: get power mode
  */
-int iwctl_giwpower(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra)
+int iwctl_giwpower(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
-    PSDevice            pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject        pMgmt = &(pDevice->sMgmtObj);
-    int mode = pDevice->ePSMode;
-
-
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWPOWER \n");
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+	int mode = pDevice->ePSMode;
 
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWPOWER \n");
 
 	if ((wrq->disabled = (mode == WMAC_POWER_CAM)))
-	    return 0;
+		return 0;
 
 	if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
 		wrq->value = (int)((pMgmt->wListenInterval * pMgmt->wCurrBeaconPeriod) << 10);
@@ -1408,85 +1292,75 @@ int iwctl_giwpower(struct net_device *dev,
 		wrq->flags = IW_POWER_PERIOD;
 	}
 	wrq->flags |= IW_POWER_ALL_R;
-
 	return 0;
 }
 
-
 /*
- * Wireless Handler : get Sensitivity
+ * Wireless Handler: get Sensitivity
  */
-int iwctl_giwsens(struct net_device *dev,
-			 struct iw_request_info *info,
-			 struct iw_param *wrq,
-			 char *extra)
+int iwctl_giwsens(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
-    PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    long ldBm;
+	PSDevice pDevice = netdev_priv(dev);
+	long ldBm;
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSENS \n");
-    if (pDevice->bLinkPass == TRUE) {
-        RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
-	    wrq->value = ldBm;
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSENS \n");
+	if (pDevice->bLinkPass == TRUE) {
+		RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
+		wrq->value = ldBm;
+	} else {
+		wrq->value = 0;
 	}
-	else {
-	    wrq->value = 0;
-    };
 	wrq->disabled = (wrq->value == 0);
 	wrq->fixed = 1;
-
-
 	return 0;
 }
 
 #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
 
-int iwctl_siwauth(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct iw_param *wrq,
-			  char *extra)
+int iwctl_siwauth(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
-	PSDevice			pDevice = (PSDevice)netdev_priv(dev);
-	PSMgmtObject	pMgmt = &(pDevice->sMgmtObj);
-	int ret=0;
-	static int wpa_version=0;  //must be static to save the last value,einsn liu
-	static int pairwise=0;
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+	int ret = 0;
+	static int wpa_version = 0; // must be static to save the last value, einsn liu
+	static int pairwise = 0;
 
-    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWAUTH \n");
+	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWAUTH \n");
 	switch (wrq->flags & IW_AUTH_INDEX) {
 	case IW_AUTH_WPA_VERSION:
 		wpa_version = wrq->value;
-		if(wrq->value == IW_AUTH_WPA_VERSION_DISABLED) {
-		       PRINT_K("iwctl_siwauth:set WPADEV to disable at 1??????\n");
-		}
-		else if(wrq->value == IW_AUTH_WPA_VERSION_WPA) {
-                          PRINT_K("iwctl_siwauth:set WPADEV to WPA1******\n");
-		}
-		else {
-                          PRINT_K("iwctl_siwauth:set WPADEV to WPA2******\n");
+		if (wrq->value == IW_AUTH_WPA_VERSION_DISABLED) {
+			PRINT_K("iwctl_siwauth:set WPADEV to disable at 1??????\n");
+		} else if (wrq->value == IW_AUTH_WPA_VERSION_WPA) {
+			PRINT_K("iwctl_siwauth:set WPADEV to WPA1******\n");
+		} else {
+			PRINT_K("iwctl_siwauth:set WPADEV to WPA2******\n");
 		}
 		break;
 	case IW_AUTH_CIPHER_PAIRWISE:
 		pairwise = wrq->value;
-                   PRINT_K("iwctl_siwauth:set pairwise=%d\n",pairwise);
-		if(pairwise == IW_AUTH_CIPHER_CCMP){
+		PRINT_K("iwctl_siwauth:set pairwise=%d\n", pairwise);
+		if (pairwise == IW_AUTH_CIPHER_CCMP){
 			pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled;
-		}else if(pairwise == IW_AUTH_CIPHER_TKIP){
+		} else if (pairwise == IW_AUTH_CIPHER_TKIP) {
 			pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled;
 		} else if (pairwise == IW_AUTH_CIPHER_WEP40 ||
-			   pairwise == IW_AUTH_CIPHER_WEP104) {
+			pairwise == IW_AUTH_CIPHER_WEP104) {
 			pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
-		}else if(pairwise == IW_AUTH_CIPHER_NONE){
-			//do nothing,einsn liu
-		}else pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
-
+		} else if (pairwise == IW_AUTH_CIPHER_NONE) {
+			// do nothing, einsn liu
+		} else {
+			pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
+		}
 		break;
 	case IW_AUTH_CIPHER_GROUP:
-		 PRINT_K("iwctl_siwauth:set GROUP=%d\n",wrq->value);
-		if(wpa_version == IW_AUTH_WPA_VERSION_DISABLED)
+		PRINT_K("iwctl_siwauth:set GROUP=%d\n", wrq->value);
+		if (wpa_version == IW_AUTH_WPA_VERSION_DISABLED)
 			break;
-		if(pairwise == IW_AUTH_CIPHER_NONE){
-			if(wrq->value == IW_AUTH_CIPHER_CCMP){
+		if (pairwise == IW_AUTH_CIPHER_NONE) {
+			if (wrq->value == IW_AUTH_CIPHER_CCMP) {
 				pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled;
 			}else {
 				pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled;
@@ -1494,31 +1368,30 @@ int iwctl_siwauth(struct net_device *dev,
 		}
 		break;
 	case IW_AUTH_KEY_MGMT:
-                    PRINT_K("iwctl_siwauth(wpa_version=%d):set KEY_MGMT=%d\n",wpa_version,wrq->value);
-		if(wpa_version == IW_AUTH_WPA_VERSION_WPA2){
-			if(wrq->value == IW_AUTH_KEY_MGMT_PSK)
+		PRINT_K("iwctl_siwauth(wpa_version=%d):set KEY_MGMT=%d\n", wpa_version,wrq->value);
+		if (wpa_version == IW_AUTH_WPA_VERSION_WPA2){
+			if (wrq->value == IW_AUTH_KEY_MGMT_PSK)
 				pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK;
 			else pMgmt->eAuthenMode = WMAC_AUTH_WPA2;
-		}else if(wpa_version == IW_AUTH_WPA_VERSION_WPA){
-			if(wrq->value == 0){
+		} else if (wpa_version == IW_AUTH_WPA_VERSION_WPA) {
+			if (wrq->value == 0){
 				pMgmt->eAuthenMode = WMAC_AUTH_WPANONE;
-			}else if(wrq->value == IW_AUTH_KEY_MGMT_PSK)
+			} else if (wrq->value == IW_AUTH_KEY_MGMT_PSK)
 				pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK;
-			else pMgmt->eAuthenMode = WMAC_AUTH_WPA;
+		} else {
+			pMgmt->eAuthenMode = WMAC_AUTH_WPA;
 		}
-
 		break;
 	case IW_AUTH_TKIP_COUNTERMEASURES:
-		break;		/* FIXME */
+		break; /* FIXME */
 	case IW_AUTH_DROP_UNENCRYPTED:
 		break;
 	case IW_AUTH_80211_AUTH_ALG:
-		 PRINT_K("iwctl_siwauth:set AUTH_ALG=%d\n",wrq->value);
-		if(wrq->value==IW_AUTH_ALG_OPEN_SYSTEM){
-			pMgmt->bShareKeyAlgorithm=FALSE;
-		}else if(wrq->value==IW_AUTH_ALG_SHARED_KEY){
-			pMgmt->bShareKeyAlgorithm=TRUE;
-		}
+		PRINT_K("iwctl_siwauth:set AUTH_ALG=%d\n", wrq->value);
+		if (wrq->value == IW_AUTH_ALG_OPEN_SYSTEM)
+			pMgmt->bShareKeyAlgorithm = FALSE;
+		else if (wrq->value == IW_AUTH_ALG_SHARED_KEY)
+			pMgmt->bShareKeyAlgorithm = TRUE;
 		break;
 	case IW_AUTH_WPA_ENABLED:
 		break;
@@ -1529,54 +1402,46 @@ int iwctl_siwauth(struct net_device *dev,
 		break;
 	case IW_AUTH_PRIVACY_INVOKED:
 		pDevice->bEncryptionEnable = !!wrq->value;
-		if(pDevice->bEncryptionEnable == FALSE){
+		if (pDevice->bEncryptionEnable == FALSE) {
 			wpa_version = 0;
 			pairwise = 0;
 			pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
 			pMgmt->bShareKeyAlgorithm = FALSE;
 			pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
-			 PRINT_K("iwctl_siwauth:set WPADEV to disaable at 2?????\n");
+			PRINT_K("iwctl_siwauth:set WPADEV to disaable at 2?????\n");
 		}
-
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 		break;
 	}
-   return ret;
+	return ret;
 }
 
-
-int iwctl_giwauth(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct iw_param *wrq,
-			  char *extra)
+int iwctl_giwauth(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra)
 {
 	return -EOPNOTSUPP;
 }
 
-
-
-int iwctl_siwgenie(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct iw_point *wrq,
-			  char *extra)
+int iwctl_siwgenie(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-	PSDevice			pDevice = (PSDevice)netdev_priv(dev);
-	PSMgmtObject	pMgmt = &(pDevice->sMgmtObj);
-	int ret=0;
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+	int ret = 0;
 
-	if(wrq->length){
-		if ((wrq->length < 2) || (extra[1]+2 != wrq->length)) {
+	if (wrq->length){
+		if ((wrq->length < 2) || (extra[1] + 2 != wrq->length)) {
 			ret = -EINVAL;
 			goto out;
 		}
-		if(wrq->length > MAX_WPA_IE_LEN){
+		if (wrq->length > MAX_WPA_IE_LEN){
 			ret = -ENOMEM;
 			goto out;
 		}
 		memset(pMgmt->abyWPAIE, 0, MAX_WPA_IE_LEN);
-		if(copy_from_user(pMgmt->abyWPAIE, extra, wrq->length)){
+		if (copy_from_user(pMgmt->abyWPAIE, extra, wrq->length)){
 			ret = -EFAULT;
 			goto out;
 		}
@@ -1586,288 +1451,265 @@ int iwctl_siwgenie(struct net_device *dev,
 		pMgmt->wWPAIELen = 0;
 	}
 
-	out://not completely ...not necessary in wpa_supplicant 0.5.8
+out: // not completely ...not necessary in wpa_supplicant 0.5.8
 	return ret;
 }
 
-int iwctl_giwgenie(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct iw_point *wrq,
-			  char *extra)
+int iwctl_giwgenie(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-	PSDevice			pDevice = (PSDevice)netdev_priv(dev);
-	PSMgmtObject	pMgmt = &(pDevice->sMgmtObj);
-	int ret=0;
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+	int ret = 0;
 	int space = wrq->length;
 
 	wrq->length = 0;
-	if(pMgmt->wWPAIELen > 0){
+	if (pMgmt->wWPAIELen > 0) {
 		wrq->length = pMgmt->wWPAIELen;
-		if(pMgmt->wWPAIELen <= space){
-			if(copy_to_user(extra, pMgmt->abyWPAIE, pMgmt->wWPAIELen)){
+		if (pMgmt->wWPAIELen <= space) {
+			if (copy_to_user(extra, pMgmt->abyWPAIE, pMgmt->wWPAIELen)) {
 				ret = -EFAULT;
 			}
-		}else
+		} else
 			ret = -E2BIG;
 	}
-
 	return ret;
 }
 
-
-int iwctl_siwencodeext(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra)
+int iwctl_siwencodeext(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-    PSDevice	        pDevice = (PSDevice)netdev_priv(dev);
-    PSMgmtObject	pMgmt = &(pDevice->sMgmtObj);
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
 	struct iw_encode_ext *ext = (struct iw_encode_ext*)extra;
-    struct viawget_wpa_param *param=NULL;
-//original member
-    wpa_alg alg_name;
-    u8  addr[6];
-    int key_idx, set_tx=0;
-    u8  seq[IW_ENCODE_SEQ_MAX_SIZE];
-    u8 key[64];
-    size_t seq_len=0,key_len=0;
-    u8 *buf;
-    size_t blen;
-    u8 key_array[64];
-    int ret=0;
-
-PRINT_K("SIOCSIWENCODEEXT...... \n");
-
-blen = sizeof(*param);
-buf = kmalloc((int)blen, (int)GFP_KERNEL);
-if (buf == NULL)
-    return -ENOMEM;
-memset(buf, 0, blen);
-param = (struct viawget_wpa_param *) buf;
-
-//recover alg_name
-switch (ext->alg) {
-    case IW_ENCODE_ALG_NONE:
-                  alg_name = WPA_ALG_NONE;
+	struct viawget_wpa_param *param=NULL;
+// original member
+	wpa_alg alg_name;
+	u8 addr[6];
+	int key_idx;
+	int set_tx = 0;
+	u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
+	u8 key[64];
+	size_t seq_len = 0;
+	size_t key_len = 0;
+	u8 *buf;
+	size_t blen;
+	u8 key_array[64];
+	int ret = 0;
+
+	PRINT_K("SIOCSIWENCODEEXT...... \n");
+
+	blen = sizeof(*param);
+	buf = kmalloc((int)blen, (int)GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+	memset(buf, 0, blen);
+	param = (struct viawget_wpa_param *)buf;
+
+// recover alg_name
+	switch (ext->alg) {
+	case IW_ENCODE_ALG_NONE:
+		alg_name = WPA_ALG_NONE;
 		break;
-    case IW_ENCODE_ALG_WEP:
-                  alg_name = WPA_ALG_WEP;
+	case IW_ENCODE_ALG_WEP:
+		alg_name = WPA_ALG_WEP;
 		break;
-    case IW_ENCODE_ALG_TKIP:
-                  alg_name = WPA_ALG_TKIP;
+	case IW_ENCODE_ALG_TKIP:
+		alg_name = WPA_ALG_TKIP;
 		break;
-    case IW_ENCODE_ALG_CCMP:
-                  alg_name = WPA_ALG_CCMP;
+	case IW_ENCODE_ALG_CCMP:
+		alg_name = WPA_ALG_CCMP;
 		break;
-    default:
+	default:
 		PRINT_K("Unknown alg = %d\n",ext->alg);
 		ret= -ENOMEM;
 		goto error;
-		}
-//recover addr
- memcpy(addr, ext->addr.sa_data, ETH_ALEN);
-//recover key_idx
-  key_idx = (wrq->flags&IW_ENCODE_INDEX) - 1;
-//recover set_tx
-if(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
-   set_tx = 1;
-//recover seq,seq_len
-	if(ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
-   seq_len=IW_ENCODE_SEQ_MAX_SIZE;
-   memcpy(seq, ext->rx_seq, seq_len);
-		}
-//recover key,key_len
-if(ext->key_len) {
-  key_len=ext->key_len;
-  memcpy(key, &ext->key[0], key_len);
 	}
-
-memset(key_array, 0, 64);
-if ( key_len > 0) {
-     memcpy(key_array, key, key_len);
-    if (key_len == 32) {
-          // notice ! the oder
-	  memcpy(&key_array[16], &key[24], 8);
-	  memcpy(&key_array[24], &key[16], 8);
+// recover addr
+	memcpy(addr, ext->addr.sa_data, ETH_ALEN);
+// recover key_idx
+	key_idx = (wrq->flags&IW_ENCODE_INDEX) - 1;
+// recover set_tx
+	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+		set_tx = 1;
+// recover seq,seq_len
+	if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+		seq_len=IW_ENCODE_SEQ_MAX_SIZE;
+		memcpy(seq, ext->rx_seq, seq_len);
 	}
+// recover key,key_len
+	if (ext->key_len) {
+		key_len = ext->key_len;
+		memcpy(key, &ext->key[0], key_len);
+	}
+	memset(key_array, 0, 64);
+	if (key_len > 0) {
+		memcpy(key_array, key, key_len);
+		if (key_len == 32) {
+			// notice ! the oder
+			memcpy(&key_array[16], &key[24], 8);
+			memcpy(&key_array[24], &key[16], 8);
+		}
 	}
 
 /**************Translate iw_encode_ext to viawget_wpa_param****************/
-memcpy(param->addr, addr, ETH_ALEN);
-param->u.wpa_key.alg_name = (int)alg_name;
-param->u.wpa_key.set_tx = set_tx;
-param->u.wpa_key.key_index = key_idx;
-param->u.wpa_key.key_len = key_len;
-param->u.wpa_key.key = (u8 *)key_array;
-param->u.wpa_key.seq = (u8 *)seq;
-param->u.wpa_key.seq_len = seq_len;
-
-//****set if current action is Network Manager count??
-//****this method is so foolish,but there is no other way???
-if(param->u.wpa_key.alg_name == WPA_ALG_NONE) {
-   if(param->u.wpa_key.key_index ==0) {
-     pDevice->bwextstep0 = TRUE;
-    }
-   if((pDevice->bwextstep0 = TRUE)&&(param->u.wpa_key.key_index ==1)) {
-     pDevice->bwextstep0 = FALSE;
-     pDevice->bwextstep1 = TRUE;
-    }
-   if((pDevice->bwextstep1 = TRUE)&&(param->u.wpa_key.key_index ==2)) {
-     pDevice->bwextstep1 = FALSE;
-     pDevice->bwextstep2 = TRUE;
+	memcpy(param->addr, addr, ETH_ALEN);
+	param->u.wpa_key.alg_name = (int)alg_name;
+	param->u.wpa_key.set_tx = set_tx;
+	param->u.wpa_key.key_index = key_idx;
+	param->u.wpa_key.key_len = key_len;
+	param->u.wpa_key.key = (u8 *)key_array;
+	param->u.wpa_key.seq = (u8 *)seq;
+	param->u.wpa_key.seq_len = seq_len;
+
+/****set if current action is Network Manager count?? */
+/****this method is so foolish,but there is no other way??? */
+	if (param->u.wpa_key.alg_name == WPA_ALG_NONE) {
+		if (param->u.wpa_key.key_index ==0) {
+			pDevice->bwextstep0 = TRUE;
+		}
+		if ((pDevice->bwextstep0 == TRUE) && (param->u.wpa_key.key_index == 1)) {
+			pDevice->bwextstep0 = FALSE;
+			pDevice->bwextstep1 = TRUE;
+		}
+		if ((pDevice->bwextstep1 == TRUE) && (param->u.wpa_key.key_index == 2)) {
+			pDevice->bwextstep1 = FALSE;
+			pDevice->bwextstep2 = TRUE;
+		}
+		if ((pDevice->bwextstep2 == TRUE) && (param->u.wpa_key.key_index == 3)) {
+			pDevice->bwextstep2 = FALSE;
+			pDevice->bwextstep3 = TRUE;
+		}
+	}
+	if (pDevice->bwextstep3 == TRUE) {
+		PRINT_K("SIOCSIWENCODEEXT:Enable WPA WEXT SUPPORT!!!!!\n");
+		pDevice->bwextstep0 = FALSE;
+		pDevice->bwextstep1 = FALSE;
+		pDevice->bwextstep2 = FALSE;
+		pDevice->bwextstep3 = FALSE;
+		pDevice->bWPASuppWextEnabled = TRUE;
+		memset(pMgmt->abyDesireBSSID, 0xFF, 6);
+		KeyvInitTable(pDevice, &pDevice->sKey);
 	}
-   if((pDevice->bwextstep2 = TRUE)&&(param->u.wpa_key.key_index ==3)) {
-     pDevice->bwextstep2 = FALSE;
-     pDevice->bwextstep3 = TRUE;
-        }
-		 }
-if(pDevice->bwextstep3 == TRUE) {
-    PRINT_K("SIOCSIWENCODEEXT:Enable WPA WEXT SUPPORT!!!!!\n");
-     pDevice->bwextstep0 = FALSE;
-     pDevice->bwextstep1 = FALSE;
-     pDevice->bwextstep2 = FALSE;
-     pDevice->bwextstep3 = FALSE;
-     pDevice->bWPASuppWextEnabled = TRUE;
-     memset(pMgmt->abyDesireBSSID, 0xFF,6);
-     KeyvInitTable(pDevice,&pDevice->sKey);
-		 }
-//******
-
-		spin_lock_irq(&pDevice->lock);
- ret = wpa_set_keys(pDevice, param, TRUE);
-		spin_unlock_irq(&pDevice->lock);
+/*******/
+	spin_lock_irq(&pDevice->lock);
+	ret = wpa_set_keys(pDevice, param, TRUE);
+	spin_unlock_irq(&pDevice->lock);
 
 error:
-kfree(param);
+	kfree(param);
 	return ret;
 }
 
-
-
-int iwctl_giwencodeext(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra)
+int iwctl_giwencodeext(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-		return -EOPNOTSUPP;
+	return -EOPNOTSUPP;
 }
 
-int iwctl_siwmlme(struct net_device *dev,
-				struct iw_request_info * info,
-				struct iw_point *wrq,
-				char *extra)
+int iwctl_siwmlme(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra)
 {
-	PSDevice			pDevice = (PSDevice)netdev_priv(dev);
-	PSMgmtObject	pMgmt = &(pDevice->sMgmtObj);
+	PSDevice pDevice = netdev_priv(dev);
+	PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
 	struct iw_mlme *mlme = (struct iw_mlme *)extra;
 	int ret = 0;
 
-	if(memcmp(pMgmt->abyCurrBSSID, mlme->addr.sa_data, ETH_ALEN)){
+	if (memcmp(pMgmt->abyCurrBSSID, mlme->addr.sa_data, ETH_ALEN)) {
 		ret = -EINVAL;
 		return ret;
 	}
-	switch(mlme->cmd){
+	switch (mlme->cmd){
 	case IW_MLME_DEAUTH:
 	case IW_MLME_DISASSOC:
-		if(pDevice->bLinkPass == TRUE){
-		  PRINT_K("iwctl_siwmlme--->send DISASSOCIATE\n");
-		  bScheduleCommand((void *) pDevice,
-				   WLAN_CMD_DISASSOCIATE,
-				   NULL);
+		if (pDevice->bLinkPass == TRUE) {
+			PRINT_K("iwctl_siwmlme--->send DISASSOCIATE\n");
+			bScheduleCommand((void *)pDevice,
+					WLAN_CMD_DISASSOCIATE,
+					NULL);
 		}
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
-
 	return ret;
-
 }
 
 #endif
 
-static const iw_handler		iwctl_handler[] =
-{
-	(iw_handler) NULL,      /* SIOCSIWCOMMIT */
-	(iw_handler) NULL,      // SIOCGIWNAME
-	(iw_handler) NULL,				// SIOCSIWNWID
-	(iw_handler) NULL,				// SIOCGIWNWID
-	(iw_handler) NULL,		// SIOCSIWFREQ
-	(iw_handler) NULL,		// SIOCGIWFREQ
-	(iw_handler) NULL,		// SIOCSIWMODE
-	(iw_handler) NULL,		// SIOCGIWMODE
-	(iw_handler) NULL,		        // SIOCSIWSENS
-	(iw_handler) NULL,		        // SIOCGIWSENS
-	(iw_handler) NULL, 		        // SIOCSIWRANGE
-	(iw_handler) iwctl_giwrange,		// SIOCGIWRANGE
-	(iw_handler) NULL,         		    // SIOCSIWPRIV
-	(iw_handler) NULL,             		// SIOCGIWPRIV
-	(iw_handler) NULL,             		// SIOCSIWSTATS
-	(iw_handler) NULL,                  // SIOCGIWSTATS
-    (iw_handler) NULL,                  // SIOCSIWSPY
-	(iw_handler) NULL,		            // SIOCGIWSPY
-	(iw_handler) NULL,				    // -- hole --
-	(iw_handler) NULL,				    // -- hole --
-	(iw_handler) NULL,		    // SIOCSIWAP
-	(iw_handler) NULL,		    // SIOCGIWAP
-	(iw_handler) NULL,				    // -- hole -- 0x16
-	(iw_handler) NULL,       // SIOCGIWAPLIST
-	(iw_handler) iwctl_siwscan,         // SIOCSIWSCAN
-	(iw_handler) iwctl_giwscan,         // SIOCGIWSCAN
-	(iw_handler) NULL,		// SIOCSIWESSID
-	(iw_handler) NULL,		// SIOCGIWESSID
-	(iw_handler) NULL,		// SIOCSIWNICKN
-	(iw_handler) NULL,		// SIOCGIWNICKN
-	(iw_handler) NULL,		// -- hole --
-	(iw_handler) NULL,		// -- hole --
-	(iw_handler) NULL,		// SIOCSIWRATE 0x20
-	(iw_handler) NULL,		// SIOCGIWRATE
-	(iw_handler) NULL,		// SIOCSIWRTS
-	(iw_handler) NULL,		// SIOCGIWRTS
-	(iw_handler) NULL,		// SIOCSIWFRAG
-	(iw_handler) NULL,		// SIOCGIWFRAG
-	(iw_handler) NULL,		// SIOCSIWTXPOW
-	(iw_handler) NULL,		// SIOCGIWTXPOW
-	(iw_handler) NULL,		// SIOCSIWRETRY
-	(iw_handler) NULL,		// SIOCGIWRETRY
-	(iw_handler) NULL,		// SIOCSIWENCODE
-	(iw_handler) NULL,		// SIOCGIWENCODE
-	(iw_handler) NULL,		// SIOCSIWPOWER
-	(iw_handler) NULL,		// SIOCGIWPOWER
-	(iw_handler) NULL,			// -- hole --
-	(iw_handler) NULL,			// -- hole --
-	(iw_handler) NULL,    // SIOCSIWGENIE
-	(iw_handler) NULL,    // SIOCGIWGENIE
-	(iw_handler) NULL,		// SIOCSIWAUTH
-	(iw_handler) NULL,		// SIOCGIWAUTH
-	(iw_handler) NULL,		// SIOCSIWENCODEEXT
-	(iw_handler) NULL,		// SIOCGIWENCODEEXT
-	(iw_handler) NULL,				// SIOCSIWPMKSA
-	(iw_handler) NULL,				// -- hole --
+static const iw_handler iwctl_handler[] = {
+	(iw_handler)NULL, // SIOCSIWCOMMIT
+	(iw_handler)NULL, // SIOCGIWNAME
+	(iw_handler)NULL, // SIOCSIWNWID
+	(iw_handler)NULL, // SIOCGIWNWID
+	(iw_handler)NULL, // SIOCSIWFREQ
+	(iw_handler)NULL, // SIOCGIWFREQ
+	(iw_handler)NULL, // SIOCSIWMODE
+	(iw_handler)NULL, // SIOCGIWMODE
+	(iw_handler)NULL, // SIOCSIWSENS
+	(iw_handler)NULL, // SIOCGIWSENS
+	(iw_handler)NULL, // SIOCSIWRANGE
+	(iw_handler)iwctl_giwrange, // SIOCGIWRANGE
+	(iw_handler)NULL, // SIOCSIWPRIV
+	(iw_handler)NULL, // SIOCGIWPRIV
+	(iw_handler)NULL, // SIOCSIWSTATS
+	(iw_handler)NULL, // SIOCGIWSTATS
+	(iw_handler)NULL, // SIOCSIWSPY
+	(iw_handler)NULL, // SIOCGIWSPY
+	(iw_handler)NULL, // -- hole --
+	(iw_handler)NULL, // -- hole --
+	(iw_handler)NULL, // SIOCSIWAP
+	(iw_handler)NULL, // SIOCGIWAP
+	(iw_handler)NULL, // -- hole -- 0x16
+	(iw_handler)NULL, // SIOCGIWAPLIST
+	(iw_handler)iwctl_siwscan, // SIOCSIWSCAN
+	(iw_handler)iwctl_giwscan, // SIOCGIWSCAN
+	(iw_handler)NULL, // SIOCSIWESSID
+	(iw_handler)NULL, // SIOCGIWESSID
+	(iw_handler)NULL, // SIOCSIWNICKN
+	(iw_handler)NULL, // SIOCGIWNICKN
+	(iw_handler)NULL, // -- hole --
+	(iw_handler)NULL, // -- hole --
+	(iw_handler)NULL, // SIOCSIWRATE 0x20
+	(iw_handler)NULL, // SIOCGIWRATE
+	(iw_handler)NULL, // SIOCSIWRTS
+	(iw_handler)NULL, // SIOCGIWRTS
+	(iw_handler)NULL, // SIOCSIWFRAG
+	(iw_handler)NULL, // SIOCGIWFRAG
+	(iw_handler)NULL, // SIOCSIWTXPOW
+	(iw_handler)NULL, // SIOCGIWTXPOW
+	(iw_handler)NULL, // SIOCSIWRETRY
+	(iw_handler)NULL, // SIOCGIWRETRY
+	(iw_handler)NULL, // SIOCSIWENCODE
+	(iw_handler)NULL, // SIOCGIWENCODE
+	(iw_handler)NULL, // SIOCSIWPOWER
+	(iw_handler)NULL, // SIOCGIWPOWER
+	(iw_handler)NULL, // -- hole --
+	(iw_handler)NULL, // -- hole --
+	(iw_handler)NULL, // SIOCSIWGENIE
+	(iw_handler)NULL, // SIOCGIWGENIE
+	(iw_handler)NULL, // SIOCSIWAUTH
+	(iw_handler)NULL, // SIOCGIWAUTH
+	(iw_handler)NULL, // SIOCSIWENCODEEXT
+	(iw_handler)NULL, // SIOCGIWENCODEEXT
+	(iw_handler)NULL, // SIOCSIWPMKSA
+	(iw_handler)NULL, // -- hole --
 };
 
-
-static const iw_handler		iwctl_private_handler[] =
-{
-	NULL,				// SIOCIWFIRSTPRIV
+static const iw_handler iwctl_private_handler[] = {
+	NULL, // SIOCIWFIRSTPRIV
 };
 
-
 struct iw_priv_args iwctl_private_args[] = {
-{ IOCTL_CMD_SET,
-  IW_PRIV_TYPE_CHAR | 1024, 0,
-  "set"},
+	{ IOCTL_CMD_SET, IW_PRIV_TYPE_CHAR | 1024, 0, "set" },
 };
 
-
-
-const struct iw_handler_def	iwctl_handler_def =
-{
-	.get_wireless_stats = &iwctl_get_wireless_stats,
-	.num_standard	= sizeof(iwctl_handler)/sizeof(iw_handler),
-	.num_private	= 0,
-	.num_private_args = 0,
-	.standard	= (iw_handler *) iwctl_handler,
-	.private	= NULL,
-	.private_args	= NULL,
+const struct iw_handler_def iwctl_handler_def = {
+	.get_wireless_stats	= &iwctl_get_wireless_stats,
+	.num_standard		= sizeof(iwctl_handler) / sizeof(iw_handler),
+	.num_private		= 0,
+	.num_private_args	= 0,
+	.standard		= (iw_handler *)iwctl_handler,
+	.private		= NULL,
+	.private_args		= NULL,
 };
diff --git a/drivers/staging/vt6656/iwctl.h b/drivers/staging/vt6656/iwctl.h
index 0c6e049..d056f83 100644
--- a/drivers/staging/vt6656/iwctl.h
+++ b/drivers/staging/vt6656/iwctl.h
@@ -41,173 +41,107 @@
 
 struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev);
 
-int iwctl_siwap(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct sockaddr *wrq,
-             char *extra);
-
-void iwctl_giwrange(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra);
-
-
-void iwctl_giwmode(struct net_device *dev,
-             struct iw_request_info *info,
-             __u32 *wmode,
-             char *extra);
-
-int iwctl_siwmode(struct net_device *dev,
-             struct iw_request_info *info,
-             __u32 *wmode,
-             char *extra);
-
-int iwctl_giwfreq(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_freq *wrq,
-             char *extra);
-
-int iwctl_siwfreq(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_freq *wrq,
-             char *extra);
-
-int iwctl_giwname(struct net_device *dev,
-			 struct iw_request_info *info,
-			 char *wrq,
-			 char *extra);
-
-int iwctl_giwsens(struct net_device *dev,
-			 struct iw_request_info *info,
-			 struct iw_param *wrq,
-			 char *extra);
-
-int iwctl_giwap(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct sockaddr *wrq,
-             char *extra);
-
-int iwctl_giwaplist(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra);
-
-int iwctl_siwessid(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra);
-
-void iwctl_giwessid(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra);
-
-int iwctl_siwrate(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra);
-
-void iwctl_giwrate(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_param *wrq,
-             char *extra);
-
-int iwctl_siwrts(struct net_device *dev,
-		 struct iw_param *wrq);
-
-int iwctl_giwrts(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra);
-
-int iwctl_siwfrag(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra);
-
-int iwctl_giwfrag(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra);
-
-int iwctl_siwretry(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra);
-
-int iwctl_giwretry(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra);
-
-int iwctl_siwencode(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra);
-
-int iwctl_giwencode(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra);
-
-int iwctl_siwpower(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra);
-
-int iwctl_giwpower(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra);
-
-int iwctl_giwscan(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_point *wrq,
-             char *extra);
-
-int iwctl_siwscan(struct net_device *dev,
-             struct iw_request_info *info,
-			 struct iw_param *wrq,
-             char *extra);
+int iwctl_siwap(struct net_device *dev, struct iw_request_info *info,
+		struct sockaddr *wrq, char *extra);
+
+void iwctl_giwrange(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
+
+void iwctl_giwmode(struct net_device *dev, struct iw_request_info *info,
+		__u32 *wmode, char *extra);
+
+int iwctl_siwmode(struct net_device *dev, struct iw_request_info *info,
+		__u32 *wmode, char *extra);
+
+int iwctl_giwfreq(struct net_device *dev, struct iw_request_info *info,
+		struct iw_freq *wrq, char *extra);
+
+int iwctl_siwfreq(struct net_device *dev, struct iw_request_info *info,
+		struct iw_freq *wrq, char *extra);
+
+int iwctl_giwname(struct net_device *dev, struct iw_request_info *info,
+		char *wrq, char *extra);
+
+int iwctl_giwsens(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+int iwctl_giwap(struct net_device *dev, struct iw_request_info *info,
+		struct sockaddr *wrq, char *extra);
+
+int iwctl_giwaplist(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
+
+int iwctl_siwessid(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
+
+void iwctl_giwessid(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
+
+int iwctl_siwrate(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+void iwctl_giwrate(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+int iwctl_siwrts(struct net_device *dev, struct iw_param *wrq);
+
+int iwctl_giwrts(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+int iwctl_siwfrag(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+int iwctl_giwfrag(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+int iwctl_siwretry(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+int iwctl_giwretry(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+int iwctl_siwencode(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
+
+int iwctl_giwencode(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
+
+int iwctl_siwpower(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+int iwctl_giwpower(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+int iwctl_giwscan(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
+
+int iwctl_siwscan(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
 
 #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
-int iwctl_siwauth(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct iw_param *wrq,
-			  char *extra);
-
-int iwctl_giwauth(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct iw_param *wrq,
-			  char *extra);
-
-int iwctl_siwgenie(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct iw_point *wrq,
-			  char *extra);
-
-int iwctl_giwgenie(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct iw_point *wrq,
-			  char *extra);
-
-int iwctl_siwencodeext(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra);
-
-int iwctl_giwencodeext(struct net_device *dev,
-             struct iw_request_info *info,
-             struct iw_point *wrq,
-             char *extra);
-
-int iwctl_siwmlme(struct net_device *dev,
-			struct iw_request_info * info,
-			struct iw_point *wrq,
-			char *extra);
+int iwctl_siwauth(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+int iwctl_giwauth(struct net_device *dev, struct iw_request_info *info,
+		struct iw_param *wrq, char *extra);
+
+int iwctl_siwgenie(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
+
+int iwctl_giwgenie(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
+
+int iwctl_siwencodeext(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
+
+int iwctl_giwencodeext(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
+
+int iwctl_siwmlme(struct net_device *dev, struct iw_request_info *info,
+		struct iw_point *wrq, char *extra);
 #endif // #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
 
-extern const struct iw_handler_def	iwctl_handler_def;
-extern const struct iw_priv_args	iwctl_private_args;
+extern const struct iw_handler_def iwctl_handler_def;
+extern const struct iw_priv_args iwctl_private_args;
 
 #endif /* __IWCTL_H__ */
diff --git a/drivers/staging/winbond/mds_s.h b/drivers/staging/winbond/mds_s.h
index 07d835b..2972d66 100644
--- a/drivers/staging/winbond/mds_s.h
+++ b/drivers/staging/winbond/mds_s.h
@@ -40,7 +40,7 @@ enum {
 
 /*
  * ================================================================
- * Configration default value
+ * Configuration default value
  * ================================================================
  */
 #define DEFAULT_MULTICASTLISTMAX	32	/* standard */
diff --git a/drivers/staging/winbond/mto.c b/drivers/staging/winbond/mto.c
index 5250217..1b52ebd 100644
--- a/drivers/staging/winbond/mto.c
+++ b/drivers/staging/winbond/mto.c
@@ -33,7 +33,7 @@ u16 MTO_Frag_Th_Tbl[MTO_MAX_FRAG_TH_LEVELS] = {
 
 /*
  * Declare data rate table:
- * The following table will be changed at anytime if the opration rate
+ * The following table will be changed at anytime if the operation rate
  * supported by AP don't match the table
  */
 static u8 MTO_Data_Rate_Tbl[MTO_MAX_DATA_RATE_LEVELS] = {
diff --git a/drivers/staging/wlags49_h2/hcf.c b/drivers/staging/wlags49_h2/hcf.c
index 366e4a4..4235446 100644
--- a/drivers/staging/wlags49_h2/hcf.c
+++ b/drivers/staging/wlags49_h2/hcf.c
@@ -705,7 +705,7 @@ hcf_action( IFBP ifbp, hcf_16 action )
 			// 800 us latency before FW switches to high power
 			MSF_WAIT(800);                              // MSF-defined function to wait n microseconds.
 //OOR			if ( ifbp->IFB_DSLinkStat & CFG_LINK_STAT_DS_OOR ) { // OutOfRange
-//				printk( "<5>ACT_INT_OFF: Deepsleep phase terminated, enable and go to AwaitConnection\n" );     //;?remove me 1 day
+//				printk(KERN_NOTICE "ACT_INT_OFF: Deepsleep phase terminated, enable and go to AwaitConnection\n" );     //;?remove me 1 day
 //				hcf_cntl( ifbp, HCF_CNTL_ENABLE );
 //			}
 //			ifbp->IFB_DSLinkStat &= ~( CFG_LINK_STAT_DS_IR | CFG_LINK_STAT_DS_OOR); //clear IR/OOR state
@@ -2979,7 +2979,7 @@ hcf_service_nic( IFBP ifbp, wci_bufp bufp, unsigned int len )
 			ltv.typ = CFG_DDS_TICK_TIME;
 			ltv.tick_time = ( ( ifbp->IFB_DSLinkStat & CFG_LINK_STAT_TIMER ) + 0x10 ) *64; //78 is more right
 			hcf_put_info( ifbp, (LTVP)&ltv );
-			printk( "<5>Preparing for sleep, link_status: %04X, timer : %d\n",
+			printk(KERN_NOTICE "Preparing for sleep, link_status: %04X, timer : %d\n",
 				ifbp->IFB_DSLinkStat, ltv.tick_time );//;?remove me 1 day
 			ifbp->IFB_TickCnt++; //;?just to make sure we do not keep on printing above message
 			if ( ltv.tick_time < 300 * 125 ) ifbp->IFB_DSLinkStat += 0x0010;
@@ -4221,11 +4221,11 @@ isr_info( IFBP ifbp )
 // /*4*/    if ( info[1] == CFG_LINK_STAT ) {
 //          ifbp->IFB_DSLinkStat = IPW( HREG_DATA_1 ) | CFG_LINK_STAT_CHANGE;   //corrupts BAP !! ;?
 //          ifbp->IFB_LinkStat = ifbp->IFB_DSLinkStat & CFG_LINK_STAT_FW; //;? to be obsoleted
-//          printk( "<4>linkstatus: %04x\n", ifbp->IFB_DSLinkStat );        //;?remove me 1 day
+//          printk(KERN_ERR "linkstatus: %04x\n", ifbp->IFB_DSLinkStat );        //;?remove me 1 day
 // #if (HCF_SLEEP) & HCF_DDS
 //          if ( ( ifbp->IFB_DSLinkStat & CFG_LINK_STAT_CONNECTED ) == 0 ) {    //even values are disconnected etc.
 //              ifbp->IFB_TickCnt = 0;              //start 2 second period (with 1 tick uncertanty)
-//              printk( "<5>isr_info: AwaitConnection phase started, IFB_TickCnt = 0\n" );      //;?remove me 1 day
+//              printk(KERN_NOTICE "isr_info: AwaitConnection phase started, IFB_TickCnt = 0\n" );      //;?remove me 1 day
 //          }
 // #endif // HCF_DDS
 //      }
diff --git a/drivers/staging/wlags49_h2/wl_main.c b/drivers/staging/wlags49_h2/wl_main.c
index d5bf0a7..2041078 100644
--- a/drivers/staging/wlags49_h2/wl_main.c
+++ b/drivers/staging/wlags49_h2/wl_main.c
@@ -3822,7 +3822,7 @@ static int write_int(struct file *file, const char *buffer, unsigned long count,
 		lp->timer_oor.data = (unsigned long)lp;
 		lp->timer_oor.expires = RUN_AT( 3 * HZ );
 		add_timer( &lp->timer_oor );
-		printk( "<5>wl_enable: %ld\n", jiffies );		//;?remove me 1 day
+		printk(KERN_NOTICE "wl_enable: %ld\n", jiffies );		//;?remove me 1 day
 #endif //DN554
 #ifdef DN554
 /*******************************************************************************
@@ -3852,7 +3852,7 @@ void timer_oor( u_long arg )
     DBG_ENTER( DbgInfo );
     DBG_PARAM( DbgInfo, "arg", "0x%08lx", arg );
 
-	printk( "<5>timer_oor: %ld 0x%04X\n", jiffies, lp->timer_oor_cnt );		//;?remove me 1 day
+	printk(KERN_NOTICE "timer_oor: %ld 0x%04X\n", jiffies, lp->timer_oor_cnt );		//;?remove me 1 day
 	lp->timer_oor_cnt += 10;
     if ( (lp->timer_oor_cnt & ~DS_OOR) > 300 ) {
 		lp->timer_oor_cnt = 300;
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 8bc562b..fabff4d 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -127,7 +127,9 @@ int prism2_change_virtual_intf(struct wiphy *wiphy,
 	}
 
 	/* Set Operation mode to the PORT TYPE RID */
-	result = prism2_domibset_uint32(wlandev, DIDmib_p2_p2Static_p2CnfPortType, data);
+	result = prism2_domibset_uint32(wlandev,
+					DIDmib_p2_p2Static_p2CnfPortType,
+					data);
 
 	if (result)
 		err = -EFAULT;
@@ -363,7 +365,8 @@ int prism2_scan(struct wiphy *wiphy, struct net_device *dev,
 	if (request->n_ssids > 0) {
 		msg1.scantype.data = P80211ENUM_scantype_active;
 		msg1.ssid.data.len = request->ssids->ssid_len;
-		memcpy(msg1.ssid.data.data, request->ssids->ssid, request->ssids->ssid_len);
+		memcpy(msg1.ssid.data.data,
+			request->ssids->ssid, request->ssids->ssid_len);
 	} else {
 		msg1.scantype.data = 0;
 	}
@@ -540,7 +543,9 @@ int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
 				goto exit;
 			}
 
-			result = prism2_domibset_pstr32(wlandev, did, sme->key_len, (u8 *) sme->key);
+			result = prism2_domibset_pstr32(wlandev,
+							did, sme->key_len,
+							(u8 *)sme->key);
 			if (result)
 				goto exit;
 
@@ -662,10 +667,11 @@ int prism2_get_tx_power(struct wiphy *wiphy, int *dbm)
 	struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
 	wlandevice_t *wlandev = priv->wlandev;
 	struct p80211msg_dot11req_mibget msg;
-	p80211item_uint32_t *mibitem = (p80211item_uint32_t *) &msg.mibattribute.data;
+	p80211item_uint32_t *mibitem;
 	int result;
 	int err = 0;
 
+	mibitem = (p80211item_uint32_t *) &msg.mibattribute.data;
 	msg.msgcode = DIDmsg_dot11req_mibget;
 	mibitem->did =
 	    DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
@@ -689,7 +695,8 @@ exit:
 /* Interface callback functions, passing data back up to the cfg80211 layer */
 void prism2_connect_result(wlandevice_t *wlandev, u8 failed)
 {
-	u16 status = failed ? WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS;
+	u16 status = failed ?
+		     WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS;
 
 	cfg80211_connect_result(wlandev->netdev, wlandev->bssid,
 				NULL, 0, NULL, 0, status, GFP_KERNEL);
@@ -732,7 +739,8 @@ struct wiphy *wlan_create_wiphy(struct device *dev, wlandevice_t *wlandev)
 {
 	struct wiphy *wiphy;
 	struct prism2_wiphy_private *priv;
-	wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(struct prism2_wiphy_private));
+
+	wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv));
 	if (!wiphy)
 		return NULL;
 
diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c
index 3c40096..66c9aa9 100644
--- a/drivers/staging/wlan-ng/prism2fw.c
+++ b/drivers/staging/wlan-ng/prism2fw.c
@@ -172,7 +172,7 @@ static int read_cardpda(struct pda *pda, wlandevice_t *wlandev);
 static int mkpdrlist(struct pda *pda);
 
 static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
-	      struct s3plugrec *s3plug, unsigned int ns3plug, struct pda * pda);
+	      struct s3plugrec *s3plug, unsigned int ns3plug, struct pda *pda);
 
 static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
 	     struct s3crcrec *s3crc, unsigned int ns3crc);
@@ -207,7 +207,8 @@ int prism2_fwtry(struct usb_device *udev, wlandevice_t *wlandev)
 
 	printk(KERN_INFO "prism2_usb: Checking for firmware %s\n",
 	       PRISM2_USB_FWFILE);
-	if (request_ihex_firmware(&fw_entry, PRISM2_USB_FWFILE, &udev->dev) != 0) {
+	if (request_ihex_firmware(&fw_entry,
+				  PRISM2_USB_FWFILE, &udev->dev) != 0) {
 		printk(KERN_INFO
 		       "prism2_usb: Firmware not available, but not essential\n");
 		printk(KERN_INFO
@@ -593,7 +594,8 @@ int mkpdrlist(struct pda *pda)
 	       le16_to_cpu(pda16[curroff + 1]) != HFA384x_PDR_END_OF_PDA) {
 		pda->rec[pda->nrec] = (hfa384x_pdrec_t *) &(pda16[curroff]);
 
-		if (le16_to_cpu(pda->rec[pda->nrec]->code) == HFA384x_PDR_NICID) {
+		if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
+		    HFA384x_PDR_NICID) {
 			memcpy(&nicid, &pda->rec[pda->nrec]->data.nicid,
 			       sizeof(nicid));
 			nicid.id = le16_to_cpu(nicid.id);
@@ -655,7 +657,7 @@ int mkpdrlist(struct pda *pda)
 *	~0	failure
 ----------------------------------------------------------------*/
 int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
-	      struct s3plugrec *s3plug, unsigned int ns3plug, struct pda * pda)
+	      struct s3plugrec *s3plug, unsigned int ns3plug, struct pda *pda)
 {
 	int result = 0;
 	int i;			/* plug index */
@@ -980,9 +982,8 @@ int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
 	       unsigned int nfchunks)
 {
 	int result = 0;
-	struct p80211msg_p2req_ramdl_state rstatemsg;
-	struct p80211msg_p2req_ramdl_write rwritemsg;
-	struct p80211msg *msgp;
+	struct p80211msg_p2req_ramdl_state *rstmsg;
+	struct p80211msg_p2req_ramdl_write *rwrmsg;
 	u32 resultcode;
 	int i;
 	int j;
@@ -991,57 +992,68 @@ int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
 	u32 currlen;
 	u32 currdaddr;
 
+	rstmsg = kmalloc(sizeof(*rstmsg), GFP_KERNEL);
+	rwrmsg = kmalloc(sizeof(*rwrmsg), GFP_KERNEL);
+	if (!rstmsg || !rwrmsg) {
+		kfree(rstmsg);
+		kfree(rwrmsg);
+		printk(KERN_ERR
+		       "writeimage: no memory for firmware download, "
+		       "aborting download\n");
+		return -ENOMEM;
+	}
+
 	/* Initialize the messages */
-	memset(&rstatemsg, 0, sizeof(rstatemsg));
-	strcpy(rstatemsg.devname, wlandev->name);
-	rstatemsg.msgcode = DIDmsg_p2req_ramdl_state;
-	rstatemsg.msglen = sizeof(rstatemsg);
-	rstatemsg.enable.did = DIDmsg_p2req_ramdl_state_enable;
-	rstatemsg.exeaddr.did = DIDmsg_p2req_ramdl_state_exeaddr;
-	rstatemsg.resultcode.did = DIDmsg_p2req_ramdl_state_resultcode;
-	rstatemsg.enable.status = P80211ENUM_msgitem_status_data_ok;
-	rstatemsg.exeaddr.status = P80211ENUM_msgitem_status_data_ok;
-	rstatemsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
-	rstatemsg.enable.len = sizeof(u32);
-	rstatemsg.exeaddr.len = sizeof(u32);
-	rstatemsg.resultcode.len = sizeof(u32);
-
-	memset(&rwritemsg, 0, sizeof(rwritemsg));
-	strcpy(rwritemsg.devname, wlandev->name);
-	rwritemsg.msgcode = DIDmsg_p2req_ramdl_write;
-	rwritemsg.msglen = sizeof(rwritemsg);
-	rwritemsg.addr.did = DIDmsg_p2req_ramdl_write_addr;
-	rwritemsg.len.did = DIDmsg_p2req_ramdl_write_len;
-	rwritemsg.data.did = DIDmsg_p2req_ramdl_write_data;
-	rwritemsg.resultcode.did = DIDmsg_p2req_ramdl_write_resultcode;
-	rwritemsg.addr.status = P80211ENUM_msgitem_status_data_ok;
-	rwritemsg.len.status = P80211ENUM_msgitem_status_data_ok;
-	rwritemsg.data.status = P80211ENUM_msgitem_status_data_ok;
-	rwritemsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
-	rwritemsg.addr.len = sizeof(u32);
-	rwritemsg.len.len = sizeof(u32);
-	rwritemsg.data.len = WRITESIZE_MAX;
-	rwritemsg.resultcode.len = sizeof(u32);
+	memset(rstmsg, 0, sizeof(*rstmsg));
+	strcpy(rstmsg->devname, wlandev->name);
+	rstmsg->msgcode = DIDmsg_p2req_ramdl_state;
+	rstmsg->msglen = sizeof(*rstmsg);
+	rstmsg->enable.did = DIDmsg_p2req_ramdl_state_enable;
+	rstmsg->exeaddr.did = DIDmsg_p2req_ramdl_state_exeaddr;
+	rstmsg->resultcode.did = DIDmsg_p2req_ramdl_state_resultcode;
+	rstmsg->enable.status = P80211ENUM_msgitem_status_data_ok;
+	rstmsg->exeaddr.status = P80211ENUM_msgitem_status_data_ok;
+	rstmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
+	rstmsg->enable.len = sizeof(u32);
+	rstmsg->exeaddr.len = sizeof(u32);
+	rstmsg->resultcode.len = sizeof(u32);
+
+	memset(rwrmsg, 0, sizeof(*rwrmsg));
+	strcpy(rwrmsg->devname, wlandev->name);
+	rwrmsg->msgcode = DIDmsg_p2req_ramdl_write;
+	rwrmsg->msglen = sizeof(*rwrmsg);
+	rwrmsg->addr.did = DIDmsg_p2req_ramdl_write_addr;
+	rwrmsg->len.did = DIDmsg_p2req_ramdl_write_len;
+	rwrmsg->data.did = DIDmsg_p2req_ramdl_write_data;
+	rwrmsg->resultcode.did = DIDmsg_p2req_ramdl_write_resultcode;
+	rwrmsg->addr.status = P80211ENUM_msgitem_status_data_ok;
+	rwrmsg->len.status = P80211ENUM_msgitem_status_data_ok;
+	rwrmsg->data.status = P80211ENUM_msgitem_status_data_ok;
+	rwrmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
+	rwrmsg->addr.len = sizeof(u32);
+	rwrmsg->len.len = sizeof(u32);
+	rwrmsg->data.len = WRITESIZE_MAX;
+	rwrmsg->resultcode.len = sizeof(u32);
 
 	/* Send xxx_state(enable) */
 	pr_debug("Sending dl_state(enable) message.\n");
-	rstatemsg.enable.data = P80211ENUM_truth_true;
-	rstatemsg.exeaddr.data = startaddr;
+	rstmsg->enable.data = P80211ENUM_truth_true;
+	rstmsg->exeaddr.data = startaddr;
 
-	msgp = (struct p80211msg *) &rstatemsg;
-	result = prism2mgmt_ramdl_state(wlandev, msgp);
+	result = prism2mgmt_ramdl_state(wlandev, rstmsg);
 	if (result) {
 		printk(KERN_ERR
 		       "writeimage state enable failed w/ result=%d, "
 		       "aborting download\n", result);
-		return result;
+		goto free_result;
 	}
-	resultcode = rstatemsg.resultcode.data;
+	resultcode = rstmsg->resultcode.data;
 	if (resultcode != P80211ENUM_resultcode_success) {
 		printk(KERN_ERR
 		       "writeimage()->xxxdl_state msg indicates failure, "
 		       "w/ resultcode=%d, aborting download.\n", resultcode);
-		return 1;
+		result = 1;
+		goto free_result;
 	}
 
 	/* Now, loop through the data chunks and send WRITESIZE_MAX data */
@@ -1059,9 +1071,9 @@ int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
 			curroff = j * WRITESIZE_MAX;
 			currdaddr = fchunk[i].addr + curroff;
 			/* Setup the message */
-			rwritemsg.addr.data = currdaddr;
-			rwritemsg.len.data = currlen;
-			memcpy(rwritemsg.data.data,
+			rwrmsg->addr.data = currdaddr;
+			rwrmsg->len.data = currlen;
+			memcpy(rwrmsg->data.data,
 			       fchunk[i].data + curroff, currlen);
 
 			/* Send flashdl_write(pda) */
@@ -1069,23 +1081,23 @@ int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
 			    ("Sending xxxdl_write message addr=%06x len=%d.\n",
 			     currdaddr, currlen);
 
-			msgp = (struct p80211msg *) &rwritemsg;
-			result = prism2mgmt_ramdl_write(wlandev, msgp);
+			result = prism2mgmt_ramdl_write(wlandev, rwrmsg);
 
 			/* Check the results */
 			if (result) {
 				printk(KERN_ERR
 				       "writeimage chunk write failed w/ result=%d, "
 				       "aborting download\n", result);
-				return result;
+				goto free_result;
 			}
-			resultcode = rstatemsg.resultcode.data;
+			resultcode = rstmsg->resultcode.data;
 			if (resultcode != P80211ENUM_resultcode_success) {
 				printk(KERN_ERR
 				       "writeimage()->xxxdl_write msg indicates failure, "
 				       "w/ resultcode=%d, aborting download.\n",
 				       resultcode);
-				return 1;
+				result = 1;
+				goto free_result;
 			}
 
 		}
@@ -1093,24 +1105,28 @@ int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
 
 	/* Send xxx_state(disable) */
 	pr_debug("Sending dl_state(disable) message.\n");
-	rstatemsg.enable.data = P80211ENUM_truth_false;
-	rstatemsg.exeaddr.data = 0;
+	rstmsg->enable.data = P80211ENUM_truth_false;
+	rstmsg->exeaddr.data = 0;
 
-	msgp = (struct p80211msg *) &rstatemsg;
-	result = prism2mgmt_ramdl_state(wlandev, msgp);
+	result = prism2mgmt_ramdl_state(wlandev, rstmsg);
 	if (result) {
 		printk(KERN_ERR
 		       "writeimage state disable failed w/ result=%d, "
 		       "aborting download\n", result);
-		return result;
+		goto free_result;
 	}
-	resultcode = rstatemsg.resultcode.data;
+	resultcode = rstmsg->resultcode.data;
 	if (resultcode != P80211ENUM_resultcode_success) {
 		printk(KERN_ERR
 		       "writeimage()->xxxdl_state msg indicates failure, "
 		       "w/ resultcode=%d, aborting download.\n", resultcode);
-		return 1;
+		result = 1;
+		goto free_result;
 	}
+
+free_result:
+	kfree(rstmsg);
+	kfree(rwrmsg);
 	return result;
 }
 
diff --git a/drivers/staging/xgifb/XGI_main.h b/drivers/staging/xgifb/XGI_main.h
index 9c62aeb..be6bb7d 100644
--- a/drivers/staging/xgifb/XGI_main.h
+++ b/drivers/staging/xgifb/XGI_main.h
@@ -1,17 +1,9 @@
 #ifndef _XGIFB_MAIN
 #define _XGIFB_MAIN
-
-
 /* ------------------- Constant Definitions ------------------------- */
-
-
 #include "XGIfb.h"
-#include "vb_struct.h"
-#include "../../video/sis/sis.h"
 #include "vb_def.h"
 
-#define XGIFAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
-
 #ifndef PCI_DEVICE_ID_XGI_42
 #define PCI_DEVICE_ID_XGI_42      0x042
 #endif
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 85dbf32..fe9061d 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -6,36 +6,12 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-/* #include <linux/config.h> */
 #include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/console.h>
-#include <linux/selection.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/vt_kern.h>
-#include <linux/capability.h>
-#include <linux/fs.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-
-#include <linux/io.h>
+
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
 
-#include "XGIfb.h"
-#include "vgatypes.h"
 #include "XGI_main.h"
 #include "vb_init.h"
 #include "vb_util.h"
@@ -54,15 +30,7 @@ static unsigned int refresh_rate;
 
 /* -------------------- Macro definitions ---------------------------- */
 
-#undef XGIFBDEBUG
-
-#ifdef XGIFBDEBUG
-#define DPRINTK(fmt, args...) pr_debug("%s: " fmt, __func__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-#ifdef XGIFBDEBUG
+#ifdef DEBUG
 static void dumpVGAReg(void)
 {
 	u8 i, reg;
@@ -101,37 +69,37 @@ static void dumpVGAReg(void)
 
 	for (i = 0; i < 0x4f; i++) {
 		reg = xgifb_reg_get(XGISR, i);
-		printk("\no 3c4 %x", i);
-		printk("\ni 3c5 => %x", reg);
+		pr_debug("\no 3c4 %x", i);
+		pr_debug("\ni 3c5 => %x", reg);
 	}
 
 	for (i = 0; i < 0xF0; i++) {
 		reg = xgifb_reg_get(XGICR, i);
-		printk("\no 3d4 %x", i);
-		printk("\ni 3d5 => %x", reg);
+		pr_debug("\no 3d4 %x", i);
+		pr_debug("\ni 3d5 => %x", reg);
 	}
 	/*
 	xgifb_reg_set(XGIPART1,0x2F,1);
 	for (i=1; i < 0x50; i++) {
 		reg = xgifb_reg_get(XGIPART1, i);
-		printk("\no d004 %x", i);
-		printk("\ni d005 => %x", reg);
+		pr_debug("\no d004 %x", i);
+		pr_debug("\ni d005 => %x", reg);
 	}
 
 	for (i=0; i < 0x50; i++) {
 		 reg = xgifb_reg_get(XGIPART2, i);
-		 printk("\no d010 %x", i);
-		 printk("\ni d011 => %x", reg);
+		 pr_debug("\no d010 %x", i);
+		 pr_debug("\ni d011 => %x", reg);
 	}
 	for (i=0; i < 0x50; i++) {
 		reg = xgifb_reg_get(XGIPART3, i);
-		printk("\no d012 %x",i);
-		printk("\ni d013 => %x",reg);
+		pr_debug("\no d012 %x",i);
+		pr_debug("\ni d013 => %x",reg);
 	}
 	for (i=0; i < 0x50; i++) {
 		reg = xgifb_reg_get(XGIPART4, i);
-		printk("\no d014 %x",i);
-		printk("\ni d015 => %x",reg);
+		pr_debug("\no d014 %x",i);
+		pr_debug("\ni d015 => %x",reg);
 	}
 	*/
 }
@@ -141,12 +109,6 @@ static inline void dumpVGAReg(void)
 }
 #endif
 
-#if 1
-#define DEBUGPRN(x)
-#else
-#define DEBUGPRN(x) pr_info(x "\n");
-#endif
-
 /* --------------- Hardware Access Routines -------------------------- */
 
 static int XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr,
@@ -692,8 +654,8 @@ static u8 XGIfb_search_refresh_rate(struct xgifb_video_info *xgifb_info,
 				break;
 			} else if (XGIfb_vrate[i].refresh > rate) {
 				if ((XGIfb_vrate[i].refresh - rate) <= 3) {
-					DPRINTK("XGIfb: Adjusting rate from %d up to %d\n",
-						rate, XGIfb_vrate[i].refresh);
+					pr_debug("XGIfb: Adjusting rate from %d up to %d\n",
+						 rate, XGIfb_vrate[i].refresh);
 					xgifb_info->rate_idx =
 						XGIfb_vrate[i].idx;
 					xgifb_info->refresh_rate =
@@ -701,8 +663,8 @@ static u8 XGIfb_search_refresh_rate(struct xgifb_video_info *xgifb_info,
 				} else if (((rate - XGIfb_vrate[i - 1].refresh)
 						<= 2) && (XGIfb_vrate[i].idx
 						!= 1)) {
-					DPRINTK("XGIfb: Adjusting rate from %d down to %d\n",
-						rate, XGIfb_vrate[i-1].refresh);
+					pr_debug("XGIfb: Adjusting rate from %d down to %d\n",
+						 rate, XGIfb_vrate[i-1].refresh);
 					xgifb_info->rate_idx =
 						XGIfb_vrate[i - 1].idx;
 					xgifb_info->refresh_rate =
@@ -710,8 +672,8 @@ static u8 XGIfb_search_refresh_rate(struct xgifb_video_info *xgifb_info,
 				}
 				break;
 			} else if ((rate - XGIfb_vrate[i].refresh) <= 2) {
-				DPRINTK("XGIfb: Adjusting rate from %d down to %d\n",
-					rate, XGIfb_vrate[i].refresh);
+				pr_debug("XGIfb: Adjusting rate from %d down to %d\n",
+					 rate, XGIfb_vrate[i].refresh);
 				xgifb_info->rate_idx = XGIfb_vrate[i].idx;
 				break;
 			}
@@ -1025,15 +987,15 @@ static void XGIfb_post_setmode(struct xgifb_video_info *xgifb_info)
 			}
 
 			if ((filter >= 0) && (filter <= 7)) {
-				DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n",
-					filter_tb, filter,
-					XGI_TV_filter[filter_tb].
+				pr_debug("FilterTable[%d]-%d: %02x %02x %02x %02x\n",
+					 filter_tb, filter,
+					 XGI_TV_filter[filter_tb].
 						filter[filter][0],
-					XGI_TV_filter[filter_tb].
+					 XGI_TV_filter[filter_tb].
 						filter[filter][1],
-					XGI_TV_filter[filter_tb].
+					 XGI_TV_filter[filter_tb].
 						filter[filter][2],
-					XGI_TV_filter[filter_tb].
+					 XGI_TV_filter[filter_tb].
 						filter[filter][3]
 				);
 				xgifb_reg_set(
@@ -1078,9 +1040,6 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
 	int old_mode;
 	/* unsigned char reg, reg1; */
 
-	DEBUGPRN("Inside do_set_var");
-	/* printk(KERN_DEBUG "XGIfb:var->yres=%d, var->upper_margin=%d, var->lower_margin=%d, var->vsync_len=%d\n", var->yres, var->upper_margin, var->lower_margin, var->vsync_len); */
-
 	info->var.xres_virtual = var->xres_virtual;
 	info->var.yres_virtual = var->yres_virtual;
 	info->var.bits_per_pixel = var->bits_per_pixel;
@@ -1095,7 +1054,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
 	}
 
 	if (!htotal || !vtotal) {
-		DPRINTK("XGIfb: Invalid 'var' information\n");
+		pr_debug("XGIfb: Invalid 'var' information\n");
 		return -EINVAL;
 	} pr_debug("var->pixclock=%d, htotal=%d, vtotal=%d\n",
 			var->pixclock, htotal, vtotal);
@@ -1171,11 +1130,11 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
 
 		XGIfb_post_setmode(xgifb_info);
 
-		DPRINTK("XGIfb: Set new mode: %dx%dx%d-%d\n",
-				XGIbios_mode[xgifb_info->mode_idx].xres,
-				XGIbios_mode[xgifb_info->mode_idx].yres,
-				XGIbios_mode[xgifb_info->mode_idx].bpp,
-				xgifb_info->refresh_rate);
+		pr_debug("XGIfb: Set new mode: %dx%dx%d-%d\n",
+			 XGIbios_mode[xgifb_info->mode_idx].xres,
+			 XGIbios_mode[xgifb_info->mode_idx].yres,
+			 XGIbios_mode[xgifb_info->mode_idx].bpp,
+			 xgifb_info->refresh_rate);
 
 		xgifb_info->video_bpp = XGIbios_mode[xgifb_info->mode_idx].bpp;
 		xgifb_info->video_vwidth = info->var.xres_virtual;
@@ -1223,7 +1182,6 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
 		}
 	}
 	XGIfb_bpp_to_var(xgifb_info, var); /*update ARGB info*/
-	DEBUGPRN("End of do_set_var");
 
 	dumpVGAReg();
 	return 0;
@@ -1234,8 +1192,6 @@ static int XGIfb_pan_var(struct fb_var_screeninfo *var, struct fb_info *info)
 	struct xgifb_video_info *xgifb_info = info->par;
 	unsigned int base;
 
-	/* printk("Inside pan_var"); */
-
 	base = var->yoffset * info->var.xres_virtual + var->xoffset;
 
 	/* calculate base bpp dep. */
@@ -1269,7 +1225,6 @@ static int XGIfb_pan_var(struct fb_var_screeninfo *var, struct fb_info *info)
 				 0x7F,
 				 ((base >> 24) & 0x01) << 7);
 	}
-	/* printk("End of pan_var"); */
 	return 0;
 }
 
@@ -1345,13 +1300,21 @@ static int XGIfb_get_fix(struct fb_fix_screeninfo *fix, int con,
 {
 	struct xgifb_video_info *xgifb_info = info->par;
 
-	DEBUGPRN("inside get_fix");
 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
-	fix->smem_start = xgifb_info->video_base;
+	strncpy(fix->id, "XGI", sizeof(fix->id) - 1);
 
+	/* if register_framebuffer has been called, we must lock */
+	if (atomic_read(&info->count))
+		mutex_lock(&info->mm_lock);
+
+	fix->smem_start = xgifb_info->video_base;
 	fix->smem_len = xgifb_info->video_size;
 
+	/* if register_framebuffer has been called, we can unlock */
+	if (atomic_read(&info->count))
+		mutex_unlock(&info->mm_lock);
+
 	fix->type = FB_TYPE_PACKED_PIXELS;
 	fix->type_aux = 0;
 	if (xgifb_info->video_bpp == 8)
@@ -1367,7 +1330,6 @@ static int XGIfb_get_fix(struct fb_fix_screeninfo *fix, int con,
 	fix->mmio_len = xgifb_info->mmio_size;
 	fix->accel = FB_ACCEL_SIS_XABRE;
 
-	DEBUGPRN("end of get_fix");
 	return 0;
 }
 
@@ -1375,12 +1337,10 @@ static int XGIfb_set_par(struct fb_info *info)
 {
 	int err;
 
-	/* printk("XGIfb: inside set_par\n"); */
 	err = XGIfb_do_set_var(&info->var, 1, info);
 	if (err)
 		return err;
 	XGIfb_get_fix(&info->fix, -1, info);
-	/* printk("XGIfb: end of set_par\n"); */
 	return 0;
 }
 
@@ -1394,8 +1354,6 @@ static int XGIfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 	int found_mode = 0;
 	int refresh_rate, search_idx;
 
-	DEBUGPRN("Inside check_var");
-
 	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
 		vtotal = var->upper_margin + var->yres + var->lower_margin
 				+ var->vsync_len;
@@ -1411,8 +1369,10 @@ static int XGIfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 		vtotal = var->upper_margin + var->yres + var->lower_margin
 				+ var->vsync_len;
 
-	if (!(htotal) || !(vtotal))
-		XGIFAIL("XGIfb: no valid timing data");
+	if (!(htotal) || !(vtotal)) {
+		pr_debug("XGIfb: no valid timing data\n");
+		return -EINVAL;
+	}
 
 	if (var->pixclock && htotal && vtotal) {
 		drate = 1000000000 / var->pixclock;
@@ -1526,7 +1486,6 @@ static int XGIfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 	var->blue.msb_right =
 	var->transp.offset = var->transp.length = var->transp.msb_right = 0;
 
-	DEBUGPRN("end of check_var");
 	return 0;
 }
 
@@ -1535,8 +1494,6 @@ static int XGIfb_pan_display(struct fb_var_screeninfo *var,
 {
 	int err;
 
-	/* printk("\nInside pan_display:\n"); */
-
 	if (var->xoffset > (info->var.xres_virtual - info->var.xres))
 		return -EINVAL;
 	if (var->yoffset > (info->var.yres_virtual - info->var.yres))
@@ -1563,7 +1520,6 @@ static int XGIfb_pan_display(struct fb_var_screeninfo *var,
 	else
 		info->var.vmode &= ~FB_VMODE_YWRAP;
 
-	/* printk("End of pan_display\n"); */
 	return 0;
 }
 
@@ -1882,9 +1838,9 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
 	xgifb_info->mmio_base = pci_resource_start(pdev, 1);
 	xgifb_info->mmio_size = pci_resource_len(pdev, 1);
 	xgifb_info->vga_base = pci_resource_start(pdev, 2) + 0x30;
-	pr_info("Relocate IO address: %Lx [%08lx]\n",
-	       (u64) pci_resource_start(pdev, 2),
-	       xgifb_info->vga_base);
+	dev_info(&pdev->dev, "Relocate IO address: %Lx [%08lx]\n",
+		 (u64) pci_resource_start(pdev, 2),
+		 xgifb_info->vga_base);
 
 	if (pci_enable_device(pdev)) {
 		ret = -EIO;
@@ -1902,9 +1858,9 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
 	reg1 = xgifb_reg_get(XGISR, IND_SIS_PASSWORD);
 
 	if (reg1 != 0xa1) { /*I/O error */
-		pr_err("I/O error!!!");
+		dev_err(&pdev->dev, "I/O error!!!");
 		ret = -EIO;
-		goto error;
+		goto error_disable;
 	}
 
 	switch (xgifb_info->chip_id) {
@@ -1927,16 +1883,17 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
 		break;
 	default:
 		ret = -ENODEV;
-		goto error;
+		goto error_disable;
 	}
 
-	pr_info("chipid = %x\n", xgifb_info->chip);
+	dev_info(&pdev->dev, "chipid = %x\n", xgifb_info->chip);
 	hw_info->jChipType = xgifb_info->chip;
 
 	if (XGIfb_get_dram_size(xgifb_info)) {
-		pr_err("Fatal error: Unable to determine RAM size.\n");
+		dev_err(&pdev->dev,
+			"Fatal error: Unable to determine RAM size.\n");
 		ret = -ENODEV;
-		goto error;
+		goto error_disable;
 	}
 
 	/* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
@@ -1951,18 +1908,20 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
 	if (!request_mem_region(xgifb_info->video_base,
 				xgifb_info->video_size,
 				"XGIfb FB")) {
-		pr_err("unable request memory size %x\n",
+		dev_err(&pdev->dev, "unable request memory size %x\n",
 		       xgifb_info->video_size);
-		pr_err("Fatal error: Unable to reserve frame buffer memory\n");
-		pr_err("Is there another framebuffer driver active?\n");
+		dev_err(&pdev->dev,
+			"Fatal error: Unable to reserve frame buffer memory. "
+			"Is there another framebuffer driver active?\n");
 		ret = -ENODEV;
-		goto error;
+		goto error_disable;
 	}
 
 	if (!request_mem_region(xgifb_info->mmio_base,
 				xgifb_info->mmio_size,
 				"XGIfb MMIO")) {
-		pr_err("Fatal error: Unable to reserve MMIO region\n");
+		dev_err(&pdev->dev,
+			"Fatal error: Unable to reserve MMIO region\n");
 		ret = -ENODEV;
 		goto error_0;
 	}
@@ -1972,18 +1931,20 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
 	xgifb_info->mmio_vbase = ioremap(xgifb_info->mmio_base,
 					    xgifb_info->mmio_size);
 
-	pr_info("Framebuffer at 0x%Lx, mapped to 0x%p, size %dk\n",
-	       (u64) xgifb_info->video_base,
-	       xgifb_info->video_vbase,
-	       xgifb_info->video_size / 1024);
+	dev_info(&pdev->dev,
+		 "Framebuffer at 0x%Lx, mapped to 0x%p, size %dk\n",
+		 (u64) xgifb_info->video_base,
+		 xgifb_info->video_vbase,
+		 xgifb_info->video_size / 1024);
 
-	pr_info("MMIO at 0x%Lx, mapped to 0x%p, size %ldk\n",
-	       (u64) xgifb_info->mmio_base, xgifb_info->mmio_vbase,
-	       xgifb_info->mmio_size / 1024);
+	dev_info(&pdev->dev,
+		 "MMIO at 0x%Lx, mapped to 0x%p, size %ldk\n",
+		 (u64) xgifb_info->mmio_base, xgifb_info->mmio_vbase,
+		 xgifb_info->mmio_size / 1024);
 
 	pci_set_drvdata(pdev, xgifb_info);
 	if (!XGIInitNew(pdev))
-		pr_err("XGIInitNew() failed!\n");
+		dev_err(&pdev->dev, "XGIInitNew() failed!\n");
 
 	xgifb_info->mtrr = (unsigned int) 0;
 
@@ -2012,29 +1973,37 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
 		reg = xgifb_reg_get(XGIPART4, 0x01);
 		if (reg >= 0xE0) {
 			hw_info->ujVBChipID = VB_CHIP_302LV;
-			pr_info("XGI302LV bridge detected (revision 0x%02x)\n", reg);
+			dev_info(&pdev->dev,
+				 "XGI302LV bridge detected (revision 0x%02x)\n",
+				 reg);
 		} else if (reg >= 0xD0) {
 			hw_info->ujVBChipID = VB_CHIP_301LV;
-			pr_info("XGI301LV bridge detected (revision 0x%02x)\n", reg);
+			dev_info(&pdev->dev,
+				 "XGI301LV bridge detected (revision 0x%02x)\n",
+				 reg);
 		}
 		/* else if (reg >= 0xB0) {
 			hw_info->ujVBChipID = VB_CHIP_301B;
 			reg1 = xgifb_reg_get(XGIPART4, 0x23);
-			printk("XGIfb: XGI301B bridge detected\n");
+			pr_debug("XGIfb: XGI301B bridge detected\n");
 		} */
 		else {
 			hw_info->ujVBChipID = VB_CHIP_301;
-			pr_info("XGI301 bridge detected\n");
+			dev_info(&pdev->dev, "XGI301 bridge detected\n");
 		}
 		break;
 	case HASVB_302:
 		reg = xgifb_reg_get(XGIPART4, 0x01);
 		if (reg >= 0xE0) {
 			hw_info->ujVBChipID = VB_CHIP_302LV;
-			pr_info("XGI302LV bridge detected (revision 0x%02x)\n", reg);
+			dev_info(&pdev->dev,
+				 "XGI302LV bridge detected (revision 0x%02x)\n",
+				 reg);
 		} else if (reg >= 0xD0) {
 			hw_info->ujVBChipID = VB_CHIP_301LV;
-			pr_info("XGI302LV bridge detected (revision 0x%02x)\n", reg);
+			dev_info(&pdev->dev,
+				 "XGI302LV bridge detected (revision 0x%02x)\n",
+				 reg);
 		} else if (reg >= 0xB0) {
 			reg1 = xgifb_reg_get(XGIPART4, 0x23);
 
@@ -2042,27 +2011,28 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
 
 		} else {
 			hw_info->ujVBChipID = VB_CHIP_302;
-			pr_info("XGI302 bridge detected\n");
+			dev_info(&pdev->dev, "XGI302 bridge detected\n");
 		}
 		break;
 	case HASVB_LVDS:
 		hw_info->ulExternalChip = 0x1;
-		pr_info("LVDS transmitter detected\n");
+		dev_info(&pdev->dev, "LVDS transmitter detected\n");
 		break;
 	case HASVB_TRUMPION:
 		hw_info->ulExternalChip = 0x2;
-		pr_info("Trumpion Zurac LVDS scaler detected\n");
+		dev_info(&pdev->dev, "Trumpion Zurac LVDS scaler detected\n");
 		break;
 	case HASVB_CHRONTEL:
 		hw_info->ulExternalChip = 0x4;
-		pr_info("Chrontel TV encoder detected\n");
+		dev_info(&pdev->dev, "Chrontel TV encoder detected\n");
 		break;
 	case HASVB_LVDS_CHRONTEL:
 		hw_info->ulExternalChip = 0x5;
-		pr_info("LVDS transmitter and Chrontel TV encoder detected\n");
+		dev_info(&pdev->dev,
+			 "LVDS transmitter and Chrontel TV encoder detected\n");
 		break;
 	default:
-		pr_info("No or unknown bridge type detected\n");
+		dev_info(&pdev->dev, "No or unknown bridge type detected\n");
 		break;
 	}
 
@@ -2230,11 +2200,6 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
 
 	}
 
-	strncpy(fb_info->fix.id, "XGI", sizeof(fb_info->fix.id) - 1);
-	fb_info->fix.type	= FB_TYPE_PACKED_PIXELS;
-	fb_info->fix.xpanstep	= 1;
-	fb_info->fix.ypanstep	= 1;
-
 	fb_info->flags = FBINFO_FLAG_DEFAULT;
 	fb_info->screen_base = xgifb_info->video_vbase;
 	fb_info->fbops = &XGIfb_ops;
@@ -2271,6 +2236,8 @@ error_1:
 	release_mem_region(xgifb_info->mmio_base, xgifb_info->mmio_size);
 error_0:
 	release_mem_region(xgifb_info->video_base, xgifb_info->video_size);
+error_disable:
+	pci_disable_device(pdev);
 error:
 	framebuffer_release(fb_info);
 	return ret;
@@ -2295,6 +2262,7 @@ static void __devexit xgifb_remove(struct pci_dev *pdev)
 	iounmap(xgifb_info->video_vbase);
 	release_mem_region(xgifb_info->mmio_base, xgifb_info->mmio_size);
 	release_mem_region(xgifb_info->video_base, xgifb_info->video_size);
+	pci_disable_device(pdev);
 	framebuffer_release(fb_info);
 	pci_set_drvdata(pdev, NULL);
 }
@@ -2306,51 +2274,44 @@ static struct pci_driver xgifb_driver = {
 	.remove = __devexit_p(xgifb_remove)
 };
 
-static int __init xgifb_init(void)
-{
-	char *option = NULL;
-
-	if (forcecrt2type != NULL)
-		XGIfb_search_crt2type(forcecrt2type);
-	if (fb_get_options("xgifb", &option))
-		return -ENODEV;
-	XGIfb_setup(option);
-
-	return pci_register_driver(&xgifb_driver);
-}
 
-module_init(xgifb_init);
 
 /*****************************************************/
 /*                      MODULE                       */
 /*****************************************************/
 
-#ifdef MODULE
-
-MODULE_DESCRIPTION("Z7 Z9 Z9S Z11 framebuffer device driver");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("XGITECH , Others");
-
 module_param(mode, charp, 0);
-module_param(vesa, int, 0);
-module_param(filter, int, 0);
-module_param(forcecrt2type, charp, 0);
+MODULE_PARM_DESC(mode,
+	"Selects the desired default display mode in the format XxYxDepth "
+	"(eg. 1024x768x16).");
 
+module_param(forcecrt2type, charp, 0);
 MODULE_PARM_DESC(forcecrt2type,
-	"\nForce the second display output type. Possible values are NONE,\n"
-	"LCD, TV, VGA, SVIDEO or COMPOSITE.\n");
-
-MODULE_PARM_DESC(mode,
-	"\nSelects the desired default display mode in the format XxYxDepth,\n"
-	"eg. 1024x768x16.\n");
+	"Force the second display output type. Possible values are NONE, "
+	"LCD, TV, VGA, SVIDEO or COMPOSITE.");
 
+module_param(vesa, int, 0);
 MODULE_PARM_DESC(vesa,
-	"\nSelects the desired default display mode by VESA mode number, eg.\n"
-	"0x117.\n");
+	"Selects the desired default display mode by VESA mode number "
+	"(eg. 0x117).");
 
+module_param(filter, int, 0);
 MODULE_PARM_DESC(filter,
-		"\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
-		"(Possible values 0-7, default: [no filter])\n");
+	"Selects TV flicker filter type (only for systems with a SiS301 video bridge). "
+	"Possible values 0-7. Default: [no filter]).");
+
+static int __init xgifb_init(void)
+{
+	char *option = NULL;
+
+	if (forcecrt2type != NULL)
+		XGIfb_search_crt2type(forcecrt2type);
+	if (fb_get_options("xgifb", &option))
+		return -ENODEV;
+	XGIfb_setup(option);
+
+	return pci_register_driver(&xgifb_driver);
+}
 
 static void __exit xgifb_remove_module(void)
 {
@@ -2358,6 +2319,8 @@ static void __exit xgifb_remove_module(void)
 	pr_debug("Module unloaded\n");
 }
 
+MODULE_DESCRIPTION("Z7 Z9 Z9S Z11 framebuffer device driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("XGITECH , Others");
+module_init(xgifb_init);
 module_exit(xgifb_remove_module);
-
-#endif	/*  /MODULE  */
diff --git a/drivers/staging/xgifb/XGIfb.h b/drivers/staging/xgifb/XGIfb.h
index 9068c5a..741bba3 100644
--- a/drivers/staging/xgifb/XGIfb.h
+++ b/drivers/staging/xgifb/XGIfb.h
@@ -1,8 +1,5 @@
 #ifndef _LINUX_XGIFB
 #define _LINUX_XGIFB
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
 #include "vgatypes.h"
 #include "vb_struct.h"
 
diff --git a/drivers/staging/xgifb/vb_def.h b/drivers/staging/xgifb/vb_def.h
index c731793..5b987a6 100644
--- a/drivers/staging/xgifb/vb_def.h
+++ b/drivers/staging/xgifb/vb_def.h
@@ -264,4 +264,23 @@
 #define RES1280x960x85       0x46
 #define RES1280x960x120      0x47
 
+
+#define XG27_CR8F 0x0C
+#define XG27_SR36 0x30
+#define XG27_SR40 0x04
+#define XG27_SR41 0x00
+#define XG40_CRCF 0x13
+#define XGI330_CRT2Data_1_2 0
+#define XGI330_CRT2Data_4_D 0
+#define XGI330_CRT2Data_4_E 0
+#define XGI330_CRT2Data_4_10 0x80
+#define XGI330_SR07 0x18
+#define XGI330_SR1F 0
+#define XGI330_SR23 0xf6
+#define XGI330_SR24 0x0d
+#define XGI330_SR25 0
+#define XGI330_SR31 0xc0
+#define XGI330_SR32 0x11
+#define XGI330_SR33 0
+
 #endif
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
index c222d61..7c555a7 100644
--- a/drivers/staging/xgifb/vb_init.c
+++ b/drivers/staging/xgifb/vb_init.c
@@ -1,39 +1,30 @@
-#include <linux/types.h>
 #include <linux/delay.h> /* udelay */
-#include <linux/pci.h>
 #include <linux/vmalloc.h>
 
 #include "XGIfb.h"
-#include "vgatypes.h"
-
 #include "vb_def.h"
-#include "vb_struct.h"
 #include "vb_util.h"
 #include "vb_setmode.h"
 #include "vb_init.h"
-
-
-#include <linux/io.h>
-
-static const unsigned short XGINew_DDRDRAM_TYPE340[4][5] = {
-	{ 2, 13, 9, 64, 0x45},
-	{ 2, 12, 9, 32, 0x35},
-	{ 2, 12, 8, 16, 0x31},
-	{ 2, 11, 8,  8, 0x21} };
-
-static const unsigned short XGINew_DDRDRAM_TYPE20[12][5] = {
-	{ 2, 14, 11, 128, 0x5D},
-	{ 2, 14, 10, 64, 0x59},
-	{ 2, 13, 11, 64, 0x4D},
-	{ 2, 14,  9, 32, 0x55},
-	{ 2, 13, 10, 32, 0x49},
-	{ 2, 12, 11, 32, 0x3D},
-	{ 2, 14,  8, 16, 0x51},
-	{ 2, 13,  9, 16, 0x45},
-	{ 2, 12, 10, 16, 0x39},
-	{ 2, 13,  8,  8, 0x41},
-	{ 2, 12,  9,  8, 0x35},
-	{ 2, 12,  8,  4, 0x31} };
+static const unsigned short XGINew_DDRDRAM_TYPE340[4][2] = {
+	{ 16, 0x45},
+	{  8, 0x35},
+	{  4, 0x31},
+	{  2, 0x21} };
+
+static const unsigned short XGINew_DDRDRAM_TYPE20[12][2] = {
+	{ 128, 0x5D},
+	{ 64, 0x59},
+	{ 64, 0x4D},
+	{ 32, 0x55},
+	{ 32, 0x49},
+	{ 32, 0x3D},
+	{ 16, 0x51},
+	{ 16, 0x45},
+	{ 16, 0x39},
+	{  8, 0x41},
+	{  8, 0x35},
+	{  4, 0x31} };
 
 #define XGIFB_ROM_SIZE	65536
 
@@ -44,21 +35,12 @@ XGINew_GetXG20DRAMType(struct xgi_hw_device_info *HwDeviceExtension,
 	unsigned char data, temp;
 
 	if (HwDeviceExtension->jChipType < XG20) {
-		if (*pVBInfo->pSoftSetting & SoftDRAMType) {
-			data = *pVBInfo->pSoftSetting & 0x07;
-			return data;
-		} else {
-			data = xgifb_reg_get(pVBInfo->P3c4, 0x39) & 0x02;
-			if (data == 0)
-				data = (xgifb_reg_get(pVBInfo->P3c4, 0x3A) &
-				       0x02) >> 1;
-			return data;
-		}
+		data = xgifb_reg_get(pVBInfo->P3c4, 0x39) & 0x02;
+		if (data == 0)
+			data = (xgifb_reg_get(pVBInfo->P3c4, 0x3A) &
+				   0x02) >> 1;
+		return data;
 	} else if (HwDeviceExtension->jChipType == XG27) {
-		if (*pVBInfo->pSoftSetting & SoftDRAMType) {
-			data = *pVBInfo->pSoftSetting & 0x07;
-			return data;
-		}
 		temp = xgifb_reg_get(pVBInfo->P3c4, 0x3B);
 		/* SR3B[7][3]MAA15 MAA11 (Power on Trapping) */
 		if (((temp & 0x88) == 0x80) || ((temp & 0x88) == 0x08))
@@ -101,13 +83,11 @@ static void XGINew_DDR1x_MRS_340(unsigned long P3c4,
 	xgifb_reg_set(P3c4, 0x16, 0x00);
 	xgifb_reg_set(P3c4, 0x16, 0x80);
 
-	if (*pVBInfo->pXGINew_DRAMTypeDefinition != 0x0C) { /* Samsung F Die */
-		mdelay(3);
-		xgifb_reg_set(P3c4, 0x18, 0x00);
-		xgifb_reg_set(P3c4, 0x19, 0x20);
-		xgifb_reg_set(P3c4, 0x16, 0x00);
-		xgifb_reg_set(P3c4, 0x16, 0x80);
-	}
+	mdelay(3);
+	xgifb_reg_set(P3c4, 0x18, 0x00);
+	xgifb_reg_set(P3c4, 0x19, 0x20);
+	xgifb_reg_set(P3c4, 0x16, 0x00);
+	xgifb_reg_set(P3c4, 0x16, 0x80);
 
 	udelay(60);
 	xgifb_reg_set(P3c4,
@@ -181,7 +161,7 @@ static void XGINew_DDRII_Bootup_XG27(
 
 	/* Set Double Frequency */
 	/* xgifb_reg_set(P3d4, 0x97, 0x11); *//* CR97 */
-	xgifb_reg_set(P3d4, 0x97, *pVBInfo->pXGINew_CR97); /* CR97 */
+	xgifb_reg_set(P3d4, 0x97, pVBInfo->XGINew_CR97); /* CR97 */
 
 	udelay(200);
 
@@ -541,7 +521,7 @@ static void XGINew_SetDRAMDefaultRegister340(
 		      pVBInfo->CR40[0][pVBInfo->ram_type]); /* CR41 */
 
 	if (HwDeviceExtension->jChipType == XG27)
-		xgifb_reg_set(P3d4, 0x8F, *pVBInfo->pCR8F); /* CR8F */
+		xgifb_reg_set(P3d4, 0x8F, XG27_CR8F); /* CR8F */
 
 	for (j = 0; j <= 6; j++) /* CR90 - CR96 */
 		xgifb_reg_set(P3d4, (0x90 + j),
@@ -564,7 +544,7 @@ static void XGINew_SetDRAMDefaultRegister340(
 
 	xgifb_reg_set(P3d4, 0x83, 0x09); /* CR83 */
 	xgifb_reg_set(P3d4, 0x87, 0x00); /* CR87 */
-	xgifb_reg_set(P3d4, 0xCF, *pVBInfo->pCRCF); /* CRCF */
+	xgifb_reg_set(P3d4, 0xCF, XG40_CRCF); /* CRCF */
 	if (pVBInfo->ram_type) {
 		/* xgifb_reg_set(P3c4, 0x17, 0xC0); */ /* SR17 DDRII */
 		xgifb_reg_set(P3c4, 0x17, 0x80); /* SR17 DDRII */
@@ -588,71 +568,16 @@ static void XGINew_SetDRAMDefaultRegister340(
 		      pVBInfo->SR15[3][pVBInfo->ram_type]); /* SR1B */
 }
 
-static void XGINew_SetDRAMSizingType(int index,
-		const unsigned short DRAMTYPE_TABLE[][5],
-		struct vb_device_info *pVBInfo)
-{
-	unsigned short data;
-
-	data = DRAMTYPE_TABLE[index][4];
-	xgifb_reg_and_or(pVBInfo->P3c4, 0x13, 0x80, data);
-	udelay(15);
-	/* should delay 50 ns */
-}
 
-static unsigned short XGINew_SetDRAMSizeReg(int index,
-		const unsigned short DRAMTYPE_TABLE[][5],
+static unsigned short XGINew_SetDRAMSize20Reg(
+		unsigned short dram_size,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short data = 0, memsize = 0;
 	int RankSize;
 	unsigned char ChannelNo;
 
-	RankSize = DRAMTYPE_TABLE[index][3] * pVBInfo->ram_bus / 32;
-	data = xgifb_reg_get(pVBInfo->P3c4, 0x13);
-	data &= 0x80;
-
-	if (data == 0x80)
-		RankSize *= 2;
-
-	data = 0;
-
-	if (pVBInfo->ram_channel == 3)
-		ChannelNo = 4;
-	else
-		ChannelNo = pVBInfo->ram_channel;
-
-	if (ChannelNo * RankSize <= 256) {
-		while ((RankSize >>= 1) > 0)
-			data += 0x10;
-
-		memsize = data >> 4;
-
-		/* [2004/03/25] Vicent, Fix DRAM Sizing Error */
-		xgifb_reg_set(pVBInfo->P3c4,
-			      0x14,
-			      (xgifb_reg_get(pVBInfo->P3c4, 0x14) & 0x0F) |
-			       (data & 0xF0));
-
-		/* data |= pVBInfo->ram_channel << 2; */
-		/* data |= (pVBInfo->ram_bus / 64) << 1; */
-		/* xgifb_reg_set(pVBInfo->P3c4, 0x14, data); */
-
-		/* should delay */
-		/* XGINew_SetDRAMModeRegister340(pVBInfo); */
-	}
-	return memsize;
-}
-
-static unsigned short XGINew_SetDRAMSize20Reg(int index,
-		const unsigned short DRAMTYPE_TABLE[][5],
-		struct vb_device_info *pVBInfo)
-{
-	unsigned short data = 0, memsize = 0;
-	int RankSize;
-	unsigned char ChannelNo;
-
-	RankSize = DRAMTYPE_TABLE[index][3] * pVBInfo->ram_bus / 8;
+	RankSize = dram_size * pVBInfo->ram_bus / 8;
 	data = xgifb_reg_get(pVBInfo->P3c4, 0x13);
 	data &= 0x80;
 
@@ -946,52 +871,41 @@ static void XGINew_CheckChannel(struct xgi_hw_device_info *HwDeviceExtension,
 static int XGINew_DDRSizing340(struct xgi_hw_device_info *HwDeviceExtension,
 		struct vb_device_info *pVBInfo)
 {
-	int i;
-	unsigned short memsize, addr;
+	u8 i, size;
+	unsigned short memsize, start_addr;
+	const unsigned short (*dram_table)[2];
 
 	xgifb_reg_set(pVBInfo->P3c4, 0x15, 0x00); /* noninterleaving */
 	xgifb_reg_set(pVBInfo->P3c4, 0x1C, 0x00); /* nontiling */
 	XGINew_CheckChannel(HwDeviceExtension, pVBInfo);
 
 	if (HwDeviceExtension->jChipType >= XG20) {
-		for (i = 0; i < 12; i++) {
-			XGINew_SetDRAMSizingType(i,
-						 XGINew_DDRDRAM_TYPE20,
-						 pVBInfo);
-			memsize = XGINew_SetDRAMSize20Reg(i,
-							  XGINew_DDRDRAM_TYPE20,
-							  pVBInfo);
-			if (memsize == 0)
-				continue;
-
-			addr = memsize + (pVBInfo->ram_channel - 2) + 20;
-			if ((HwDeviceExtension->ulVideoMemorySize - 1) <
-			    (unsigned long) (1 << addr))
-				continue;
-
-			if (XGINew_ReadWriteRest(addr, 5, pVBInfo) == 1)
-				return 1;
-		}
+		dram_table = XGINew_DDRDRAM_TYPE20;
+		size = ARRAY_SIZE(XGINew_DDRDRAM_TYPE20);
+		start_addr = 5;
 	} else {
-		for (i = 0; i < 4; i++) {
-			XGINew_SetDRAMSizingType(i,
-						 XGINew_DDRDRAM_TYPE340,
-						 pVBInfo);
-			memsize = XGINew_SetDRAMSizeReg(i,
-							XGINew_DDRDRAM_TYPE340,
-							pVBInfo);
-
-			if (memsize == 0)
-				continue;
-
-			addr = memsize + (pVBInfo->ram_channel - 2) + 20;
-			if ((HwDeviceExtension->ulVideoMemorySize - 1) <
-			    (unsigned long) (1 << addr))
-				continue;
-
-			if (XGINew_ReadWriteRest(addr, 9, pVBInfo) == 1)
-				return 1;
-		}
+		dram_table = XGINew_DDRDRAM_TYPE340;
+		size = ARRAY_SIZE(XGINew_DDRDRAM_TYPE340);
+		start_addr = 9;
+	}
+
+	for (i = 0; i < size; i++) {
+		/* SetDRAMSizingType */
+		xgifb_reg_and_or(pVBInfo->P3c4, 0x13, 0x80, dram_table[i][1]);
+		udelay(15); /* should delay 50 ns */
+
+		memsize = XGINew_SetDRAMSize20Reg(dram_table[i][0], pVBInfo);
+
+		if (memsize == 0)
+			continue;
+
+		memsize += (pVBInfo->ram_channel - 2) + 20;
+		if ((HwDeviceExtension->ulVideoMemorySize - 1) <
+			(unsigned long) (1 << memsize))
+			continue;
+
+		if (XGINew_ReadWriteRest(memsize, start_addr, pVBInfo) == 1)
+			return 1;
 	}
 	return 0;
 }
@@ -1150,13 +1064,9 @@ static void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension,
 		CR3CData = xgifb_reg_get(pVBInfo->P3d4, 0x3c);
 		if (!(CR3CData & DisplayDeviceFromCMOS)) {
 			tempcx = 0x1FF0;
-			if (*pVBInfo->pSoftSetting & ModeSoftSetting)
-				tempbx = 0x1FF0;
 		}
 	} else {
 		tempcx = 0x1FF0;
-		if (*pVBInfo->pSoftSetting & ModeSoftSetting)
-			tempbx = 0x1FF0;
 	}
 
 	tempbx &= tempcx;
@@ -1409,22 +1319,17 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 	/* Newdebugcode(0x99); */
 
 	if (pVBInfo->FBAddr == NULL) {
-		printk("\n pVBInfo->FBAddr == 0 ");
+		dev_dbg(&pdev->dev, "pVBInfo->FBAddr == 0\n");
 		return 0;
 	}
-	printk("1");
 	if (pVBInfo->BaseAddr == 0) {
-		printk("\npVBInfo->BaseAddr == 0 ");
+		dev_dbg(&pdev->dev, "pVBInfo->BaseAddr == 0\n");
 		return 0;
 	}
-	printk("2");
 
 	outb(0x67, (pVBInfo->BaseAddr + 0x12)); /* 3c2 <- 67 ,ynlai */
 
 	pVBInfo->ISXPDOS = 0;
-	printk("3");
-
-	printk("4");
 
 	/* VBIOSVersion[4] = 0x0; */
 
@@ -1447,7 +1352,6 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 	pVBInfo->Part3Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_12;
 	pVBInfo->Part4Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_14;
 	pVBInfo->Part5Port = pVBInfo->BaseAddr + SIS_CRT2_PORT_14 + 2;
-	printk("5");
 
 	if (HwDeviceExtension->jChipType < XG20) /* kuku 2004/06/25 */
 		/* Run XGI_GetVBType before InitTo330Pointer */
@@ -1459,7 +1363,6 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 
 	/* 1.Openkey */
 	xgifb_reg_set(pVBInfo->P3c4, 0x05, 0x86);
-	printk("6");
 
 	/* GetXG21Sense (GPIO) */
 	if (HwDeviceExtension->jChipType == XG21)
@@ -1468,8 +1371,6 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 	if (HwDeviceExtension->jChipType == XG27)
 		XGINew_GetXG27Sense(HwDeviceExtension, pVBInfo);
 
-	printk("7");
-
 	/* 2.Reset Extended register */
 
 	for (i = 0x06; i < 0x20; i++)
@@ -1481,11 +1382,8 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 	/* for(i = 0x06; i <= 0x27; i++) */
 	/* xgifb_reg_set(pVBInfo->P3c4, i, 0); */
 
-	printk("8");
-
 	for (i = 0x31; i <= 0x3B; i++)
 		xgifb_reg_set(pVBInfo->P3c4, i, 0);
-	printk("9");
 
 	/* [Hsuan] 2004/08/20 Auto over driver for XG42 */
 	if (HwDeviceExtension->jChipType == XG42)
@@ -1497,39 +1395,33 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 	for (i = 0x79; i <= 0x7C; i++)
 		xgifb_reg_set(pVBInfo->P3d4, i, 0); /* shampoo 0208 */
 
-	printk("10");
-
 	if (HwDeviceExtension->jChipType >= XG20)
-		xgifb_reg_set(pVBInfo->P3d4, 0x97, *pVBInfo->pXGINew_CR97);
+		xgifb_reg_set(pVBInfo->P3d4, 0x97, pVBInfo->XGINew_CR97);
 
 	/* 3.SetMemoryClock
 
 	pVBInfo->ram_type = XGINew_GetXG20DRAMType(HwDeviceExtension, pVBInfo);
 	*/
 
-	printk("11");
-
 	/* 4.SetDefExt1Regs begin */
-	xgifb_reg_set(pVBInfo->P3c4, 0x07, *pVBInfo->pSR07);
+	xgifb_reg_set(pVBInfo->P3c4, 0x07, XGI330_SR07);
 	if (HwDeviceExtension->jChipType == XG27) {
-		xgifb_reg_set(pVBInfo->P3c4, 0x40, *pVBInfo->pSR40);
-		xgifb_reg_set(pVBInfo->P3c4, 0x41, *pVBInfo->pSR41);
+		xgifb_reg_set(pVBInfo->P3c4, 0x40, XG27_SR40);
+		xgifb_reg_set(pVBInfo->P3c4, 0x41, XG27_SR41);
 	}
 	xgifb_reg_set(pVBInfo->P3c4, 0x11, 0x0F);
-	xgifb_reg_set(pVBInfo->P3c4, 0x1F, *pVBInfo->pSR1F);
+	xgifb_reg_set(pVBInfo->P3c4, 0x1F, XGI330_SR1F);
 	/* xgifb_reg_set(pVBInfo->P3c4, 0x20, 0x20); */
 	/* alan, 2001/6/26 Frame buffer can read/write SR20 */
 	xgifb_reg_set(pVBInfo->P3c4, 0x20, 0xA0);
 	/* Hsuan, 2006/01/01 H/W request for slow corner chip */
 	xgifb_reg_set(pVBInfo->P3c4, 0x36, 0x70);
 	if (HwDeviceExtension->jChipType == XG27) /* Alan 12/07/2006 */
-		xgifb_reg_set(pVBInfo->P3c4, 0x36, *pVBInfo->pSR36);
+		xgifb_reg_set(pVBInfo->P3c4, 0x36, XG27_SR36);
 
 	/* SR11 = 0x0F; */
 	/* xgifb_reg_set(pVBInfo->P3c4, 0x11, SR11); */
 
-	printk("12");
-
 	if (HwDeviceExtension->jChipType < XG20) { /* kuku 2004/06/25 */
 		u32 Temp;
 
@@ -1575,8 +1467,6 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 		}
 		*/
 
-		printk("13");
-
 		/* Set AGP customize registers (in SetDefAGPRegs) Start */
 		for (i = 0x47; i <= 0x4C; i++)
 			xgifb_reg_set(pVBInfo->P3d4,
@@ -1605,14 +1495,12 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 
 		if (Temp == 1)
 			xgifb_reg_set(pVBInfo->P3d4, 0x48, 0x20); /* CR48 */
-		printk("14");
 	} /* != XG20 */
 
 	/* Set PCI */
-	xgifb_reg_set(pVBInfo->P3c4, 0x23, *pVBInfo->pSR23);
-	xgifb_reg_set(pVBInfo->P3c4, 0x24, *pVBInfo->pSR24);
-	xgifb_reg_set(pVBInfo->P3c4, 0x25, pVBInfo->SR25[0]);
-	printk("15");
+	xgifb_reg_set(pVBInfo->P3c4, 0x23, XGI330_SR23);
+	xgifb_reg_set(pVBInfo->P3c4, 0x24, XGI330_SR24);
+	xgifb_reg_set(pVBInfo->P3c4, 0x25, XGI330_SR25);
 
 	if (HwDeviceExtension->jChipType < XG20) { /* kuku 2004/06/25 */
 		/* Set VB */
@@ -1625,10 +1513,7 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 		temp = (unsigned char) ((temp1 >> 4) & 0x0F);
 
 		xgifb_reg_set(pVBInfo->Part1Port,
-			      0x02,
-			      (*pVBInfo->pCRT2Data_1_2));
-
-		printk("16");
+			      0x02, XGI330_CRT2Data_1_2);
 
 		xgifb_reg_set(pVBInfo->Part1Port, 0x2E, 0x08); /* use VB */
 	} /* != XG20 */
@@ -1640,16 +1525,15 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 		/* Not DDR */
 		xgifb_reg_set(pVBInfo->P3c4,
 			      0x31,
-			      (*pVBInfo->pSR31 & 0x3F) | 0x40);
+			      (XGI330_SR31 & 0x3F) | 0x40);
 		xgifb_reg_set(pVBInfo->P3c4,
 			      0x32,
-			      (*pVBInfo->pSR32 & 0xFC) | 0x01);
+			      (XGI330_SR32 & 0xFC) | 0x01);
 	} else {
-		xgifb_reg_set(pVBInfo->P3c4, 0x31, *pVBInfo->pSR31);
-		xgifb_reg_set(pVBInfo->P3c4, 0x32, *pVBInfo->pSR32);
+		xgifb_reg_set(pVBInfo->P3c4, 0x31, XGI330_SR31);
+		xgifb_reg_set(pVBInfo->P3c4, 0x32, XGI330_SR32);
 	}
-	xgifb_reg_set(pVBInfo->P3c4, 0x33, *pVBInfo->pSR33);
-	printk("17");
+	xgifb_reg_set(pVBInfo->P3c4, 0x33, XGI330_SR33);
 
 	/*
 	 SetPowerConsume (HwDeviceExtension, pVBInfo->P3c4);	*/
@@ -1659,32 +1543,22 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 			if (pVBInfo->IF_DEF_LVDS == 0) {
 				xgifb_reg_set(pVBInfo->Part2Port, 0x00, 0x1C);
 				xgifb_reg_set(pVBInfo->Part4Port,
-					      0x0D,
-					      *pVBInfo->pCRT2Data_4_D);
+					      0x0D, XGI330_CRT2Data_4_D);
 				xgifb_reg_set(pVBInfo->Part4Port,
-					      0x0E,
-					      *pVBInfo->pCRT2Data_4_E);
+					      0x0E, XGI330_CRT2Data_4_E);
 				xgifb_reg_set(pVBInfo->Part4Port,
-					      0x10,
-					      *pVBInfo->pCRT2Data_4_10);
+					      0x10, XGI330_CRT2Data_4_10);
 				xgifb_reg_set(pVBInfo->Part4Port, 0x0F, 0x3F);
 			}
 
 			XGI_LockCRT2(HwDeviceExtension, pVBInfo);
 		}
 	} /* != XG20 */
-	printk("18");
-
-	printk("181");
-
-	printk("182");
 
 	XGI_SenseCRT1(pVBInfo);
 
-	printk("183");
 	/* XGINew_DetectMonitor(HwDeviceExtension); */
 	if (HwDeviceExtension->jChipType == XG21) {
-		printk("186");
 
 		xgifb_reg_and_or(pVBInfo->P3d4,
 				 0x32,
@@ -1692,7 +1566,6 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 				 Monitor1Sense); /* Z9 default has CRT */
 		temp = GetXG21FPBits(pVBInfo);
 		xgifb_reg_and_or(pVBInfo->P3d4, 0x37, ~0x01, temp);
-		printk("187");
 
 	}
 	if (HwDeviceExtension->jChipType == XG27) {
@@ -1703,7 +1576,6 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 		temp = GetXG27FPBits(pVBInfo);
 		xgifb_reg_and_or(pVBInfo->P3d4, 0x37, ~0x03, temp);
 	}
-	printk("19");
 
 	pVBInfo->ram_type = XGINew_GetXG20DRAMType(HwDeviceExtension, pVBInfo);
 
@@ -1711,11 +1583,7 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 					 pVBInfo->P3d4,
 					 pVBInfo);
 
-	printk("20");
 	XGINew_SetDRAMSize_340(xgifb_info, HwDeviceExtension, pVBInfo);
-	printk("21");
-
-	printk("22");
 
 	/* SetDefExt2Regs begin */
 	/*
@@ -1726,12 +1594,12 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 		AGP = 0;
 
 	if (AGP == 0)
-		*pVBInfo->pSR21 &= 0xEF;
+		pVBInfo->SR21 &= 0xEF;
 
-	xgifb_reg_set(pVBInfo->P3c4, 0x21, *pVBInfo->pSR21);
+	xgifb_reg_set(pVBInfo->P3c4, 0x21, pVBInfo->SR21);
 	if (AGP == 1)
-		*pVBInfo->pSR22 &= 0x20;
-	xgifb_reg_set(pVBInfo->P3c4, 0x22, *pVBInfo->pSR22);
+		pVBInfo->SR22 &= 0x20;
+	xgifb_reg_set(pVBInfo->P3c4, 0x22, pVBInfo->SR22);
 	*/
 	/* base = 0x80000000; */
 	/* OutPortLong(0xcf8, base); */
@@ -1739,23 +1607,18 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
 	/* if (Temp == 0x1039) { */
 	xgifb_reg_set(pVBInfo->P3c4,
 		      0x22,
-		      (unsigned char) ((*pVBInfo->pSR22) & 0xFE));
+		      (unsigned char) ((pVBInfo->SR22) & 0xFE));
 	/* } else { */
-	/*	xgifb_reg_set(pVBInfo->P3c4, 0x22, *pVBInfo->pSR22); */
+	/*	xgifb_reg_set(pVBInfo->P3c4, 0x22, pVBInfo->SR22); */
 	/* } */
 
-	xgifb_reg_set(pVBInfo->P3c4, 0x21, *pVBInfo->pSR21);
-
-	printk("23");
+	xgifb_reg_set(pVBInfo->P3c4, 0x21, pVBInfo->SR21);
 
 	XGINew_ChkSenseStatus(HwDeviceExtension, pVBInfo);
 	XGINew_SetModeScratch(HwDeviceExtension, pVBInfo);
 
-	printk("24");
-
 	xgifb_reg_set(pVBInfo->P3d4, 0x8c, 0x87);
 	xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x31);
-	printk("25");
 
 	return 1;
 } /* end of init */
diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c
index b2f4338..479362e 100644
--- a/drivers/staging/xgifb/vb_setmode.c
+++ b/drivers/staging/xgifb/vb_setmode.c
@@ -1,20 +1,13 @@
-
-#include <linux/io.h>
 #include <linux/delay.h>
-#include <linux/types.h>
 #include "XGIfb.h"
 
-
 #include "vb_def.h"
-#include "vgatypes.h"
-#include "vb_struct.h"
-#include "vb_init.h"
 #include "vb_util.h"
 #include "vb_table.h"
 #include "vb_setmode.h"
 
-
 #define  IndexMask 0xff
+#define TVCLKBASE_315_25 (TVCLKBASE_315 + 25)
 
 static const unsigned short XGINew_VGA_DAC[] = {
 	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
@@ -45,9 +38,6 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
 	pVBInfo->ModeResInfo
 			= (struct SiS_ModeResInfo_S *) XGI330_ModeResInfo;
 
-	pVBInfo->pOutputSelect = &XGI330_OutputSelect;
-	pVBInfo->pSoftSetting = &XGI330_SoftSetting;
-	pVBInfo->pSR07 = &XGI330_SR07;
 	pVBInfo->LCDResInfo = 0;
 	pVBInfo->LCDTypeInfo = 0;
 	pVBInfo->LCDInfo = 0;
@@ -56,36 +46,15 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
 
 	pVBInfo->SR15 = XGI340_SR13;
 	pVBInfo->CR40 = XGI340_cr41;
-	pVBInfo->SR25 = XGI330_sr25;
-	pVBInfo->pSR31 = &XGI330_sr31;
-	pVBInfo->pSR32 = &XGI330_sr32;
 	pVBInfo->CR6B = XGI340_CR6B;
 	pVBInfo->CR6E = XGI340_CR6E;
 	pVBInfo->CR6F = XGI340_CR6F;
 	pVBInfo->CR89 = XGI340_CR89;
 	pVBInfo->AGPReg = XGI340_AGPReg;
 	pVBInfo->SR16 = XGI340_SR16;
-	pVBInfo->pCRCF = &XG40_CRCF;
-	pVBInfo->pXGINew_DRAMTypeDefinition = &XG40_DRAMTypeDefinition;
-
-	pVBInfo->CR49 = XGI330_CR49;
-	pVBInfo->pSR1F = &XGI330_SR1F;
-	pVBInfo->pSR21 = &XGI330_SR21;
-	pVBInfo->pSR22 = &XGI330_SR22;
-	pVBInfo->pSR23 = &XGI330_SR23;
-	pVBInfo->pSR24 = &XGI330_SR24;
-	pVBInfo->pSR33 = &XGI330_SR33;
-
-	pVBInfo->pCRT2Data_1_2 = &XGI330_CRT2Data_1_2;
-	pVBInfo->pCRT2Data_4_D = &XGI330_CRT2Data_4_D;
-	pVBInfo->pCRT2Data_4_E = &XGI330_CRT2Data_4_E;
-	pVBInfo->pCRT2Data_4_10 = &XGI330_CRT2Data_4_10;
-	pVBInfo->pRGBSenseData = &XGI330_RGBSenseData;
-	pVBInfo->pVideoSenseData = &XGI330_VideoSenseData;
-	pVBInfo->pYCSenseData = &XGI330_YCSenseData;
-	pVBInfo->pRGBSenseData2 = &XGI330_RGBSenseData2;
-	pVBInfo->pVideoSenseData2 = &XGI330_VideoSenseData2;
-	pVBInfo->pYCSenseData2 = &XGI330_YCSenseData2;
+
+	pVBInfo->SR21 = 0xa3;
+	pVBInfo->SR22 = 0xfb;
 
 	pVBInfo->NTSCTiming = XGI330_NTSCTiming;
 	pVBInfo->PALTiming = XGI330_PALTiming;
@@ -112,41 +81,22 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
 	else
 		pVBInfo->LCDCapList = XGI_LCDCapList;
 
-	pVBInfo->XGI_TVDelayList = XGI301TVDelayList;
-	pVBInfo->XGI_TVDelayList2 = XGI301TVDelayList2;
-
-	pVBInfo->pXGINew_I2CDefinition = &XG40_I2CDefinition;
-
 	if (ChipType >= XG20)
-		pVBInfo->pXGINew_CR97 = &XG20_CR97;
+		pVBInfo->XGINew_CR97 = 0x10;
 
 	if (ChipType == XG27) {
 		unsigned char temp;
 		pVBInfo->MCLKData
 			= (struct SiS_MCLKData *) XGI27New_MCLKData;
 		pVBInfo->CR40 = XGI27_cr41;
-		pVBInfo->pXGINew_CR97 = &XG27_CR97;
-		pVBInfo->pSR36 = &XG27_SR36;
-		pVBInfo->pCR8F = &XG27_CR8F;
-		pVBInfo->pCRD0 = XG27_CRD0;
-		pVBInfo->pCRDE = XG27_CRDE;
-		pVBInfo->pSR40 = &XG27_SR40;
-		pVBInfo->pSR41 = &XG27_SR41;
+		pVBInfo->XGINew_CR97 = 0xc1;
 		pVBInfo->SR15 = XG27_SR13;
 
 		/*Z11m DDR*/
 		temp = xgifb_reg_get(pVBInfo->P3c4, 0x3B);
 		/* SR3B[7][3]MAA15 MAA11 (Power on Trapping) */
 		if (((temp & 0x88) == 0x80) || ((temp & 0x88) == 0x08))
-			pVBInfo->pXGINew_CR97 = &Z11m_CR97;
-	}
-
-	if (ChipType >= XG20) {
-		pVBInfo->pDVOSetting = &XG21_DVOSetting;
-		pVBInfo->pCR2E = &XG21_CR2E;
-		pVBInfo->pCR2F = &XG21_CR2F;
-		pVBInfo->pCR46 = &XG21_CR46;
-		pVBInfo->pCR47 = &XG21_CR47;
+			pVBInfo->XGINew_CR97 = 0x80;
 	}
 
 }
@@ -793,13 +743,6 @@ static void xgifb_set_lcd(int chip_id,
 		}
 	}
 
-	if (((*pVBInfo->pDVOSetting) & 0xC0) == 0xC0) {
-		xgifb_reg_set(pVBInfo->P3d4, 0x2E, *pVBInfo->pCR2E);
-		xgifb_reg_set(pVBInfo->P3d4, 0x2F, *pVBInfo->pCR2F);
-		xgifb_reg_set(pVBInfo->P3d4, 0x46, *pVBInfo->pCR46);
-		xgifb_reg_set(pVBInfo->P3d4, 0x47, *pVBInfo->pCR47);
-	}
-
 	if (chip_id == XG27) {
 		XGI_SetXG27FPBits(pVBInfo);
 	} else {
@@ -1018,24 +961,6 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
 		struct xgi_hw_device_info *HwDeviceExtension,
 		struct vb_device_info *pVBInfo)
 {
-	unsigned short LCDXlat1VCLK[4] = { VCLK65_315 + 2,
-					   VCLK65_315 + 2,
-					   VCLK65_315 + 2,
-					   VCLK65_315 + 2 };
-	unsigned short LCDXlat2VCLK[4] = { VCLK108_2_315 + 5,
-					   VCLK108_2_315 + 5,
-					   VCLK108_2_315 + 5,
-					   VCLK108_2_315 + 5 };
-	unsigned short LVDSXlat1VCLK[4] = { VCLK40, VCLK40, VCLK40, VCLK40 };
-	unsigned short LVDSXlat2VCLK[4] = { VCLK65_315 + 2,
-					    VCLK65_315 + 2,
-					    VCLK65_315 + 2,
-					    VCLK65_315 + 2 };
-	unsigned short LVDSXlat3VCLK[4] = { VCLK65_315 + 2,
-					    VCLK65_315 + 2,
-					    VCLK65_315 + 2,
-					    VCLK65_315 + 2 };
-
 	unsigned short CRT2Index, VCLKIndex;
 	unsigned short modeflag, resinfo;
 
@@ -1048,25 +973,21 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
 		CRT2Index = CRT2Index >> 6; /*  for LCD */
 		if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) { /*301b*/
 			if (pVBInfo->LCDResInfo != Panel_1024x768)
-				VCLKIndex = LCDXlat2VCLK[CRT2Index];
+				VCLKIndex =  VCLK108_2_315 + 5; /* LCDXlat2VCLK */
 			else
-				VCLKIndex = LCDXlat1VCLK[CRT2Index];
+				VCLKIndex = VCLK65_315 + 2; /* LCDXlat1VCLK */
 		} else if (pVBInfo->VBInfo & SetCRT2ToHiVision) {
 			if (pVBInfo->SetFlag & RPLLDIV2XO) {
-				VCLKIndex = TVCLKBASE_315 + HiTVVCLKDIV2;
-				VCLKIndex += 25;
+				VCLKIndex = TVCLKBASE_315_25 + HiTVVCLKDIV2;
 			} else {
-				VCLKIndex = TVCLKBASE_315 + HiTVVCLK;
-				VCLKIndex += 25;
+				VCLKIndex = TVCLKBASE_315_25 + HiTVVCLK;
 			}
 
 			if (pVBInfo->SetFlag & TVSimuMode) {
 				if (modeflag & Charx8Dot) {
-					VCLKIndex = TVCLKBASE_315 + HiTVSimuVCLK;
-					VCLKIndex += 25;
+					VCLKIndex = TVCLKBASE_315_25 + HiTVSimuVCLK;
 				} else {
-					VCLKIndex = TVCLKBASE_315 + HiTVTextVCLK;
-					VCLKIndex += 25;
+					VCLKIndex = TVCLKBASE_315_25 + HiTVTextVCLK;
 				}
 			}
 
@@ -1084,11 +1005,9 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
 			}
 		} else if (pVBInfo->VBInfo & SetCRT2ToTV) {
 			if (pVBInfo->SetFlag & RPLLDIV2XO) {
-				VCLKIndex = TVCLKBASE_315 + TVVCLKDIV2;
-				VCLKIndex += 25;
+				VCLKIndex = TVCLKBASE_315_25 + TVVCLKDIV2;
 			} else {
-				VCLKIndex = TVCLKBASE_315 + TVVCLK;
-				VCLKIndex += 25;
+				VCLKIndex = TVCLKBASE_315_25 + TVVCLK;
 			}
 		} else { /* for CRT2 */
 			/* di+Ext_CRTVCLK */
@@ -1097,16 +1016,11 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
 			VCLKIndex &= IndexMask;
 		}
 	} else { /* LVDS */
-		VCLKIndex = CRT2Index;
-		VCLKIndex = VCLKIndex >> 6;
 		if ((pVBInfo->LCDResInfo == Panel_800x600) ||
 		    (pVBInfo->LCDResInfo == Panel_320x480))
-			VCLKIndex = LVDSXlat1VCLK[VCLKIndex];
-		else if ((pVBInfo->LCDResInfo == Panel_1024x768) ||
-			 (pVBInfo->LCDResInfo == Panel_1024x768x75))
-			VCLKIndex = LVDSXlat2VCLK[VCLKIndex];
+			VCLKIndex = VCLK40; /* LVDSXlat1VCLK */
 		else
-			VCLKIndex = LVDSXlat3VCLK[VCLKIndex];
+			VCLKIndex = VCLK65_315 + 2; /* LVDSXlat2VCLK, LVDSXlat3VCLK  */
 	}
 
 	return VCLKIndex;
@@ -2019,12 +1933,12 @@ static void XGI_GetLVDSData(unsigned short ModeNo, unsigned short ModeIdIndex,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short tempbx;
-	struct XGI330_LVDSDataStruct *LCDPtr = NULL;
+	struct SiS_LVDSData *LCDPtr = NULL;
 
 	tempbx = 2;
 
 	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
-		LCDPtr = (struct XGI330_LVDSDataStruct *) XGI_GetLcdPtr(tempbx,
+		LCDPtr = (struct SiS_LVDSData *)XGI_GetLcdPtr(tempbx,
 				ModeNo, ModeIdIndex, RefreshRateTableIndex,
 				pVBInfo);
 		pVBInfo->VGAHT = LCDPtr->VGAHT;
@@ -5748,32 +5662,19 @@ static void XGI_GetTVPtrIndex2(unsigned short *tempbx, unsigned char *tempcl,
 
 static void XGI_SetDelayComp(struct vb_device_info *pVBInfo)
 {
-	unsigned short index;
-
 	unsigned char tempah, tempbl, tempbh;
 
 	if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV
 			| VB_SIS302LV | VB_XGI301C)) {
 		if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA
 				| SetCRT2ToTV | SetCRT2ToRAMDAC)) {
-			tempbl = 0;
 			tempbh = 0;
-
-			index = XGI_GetTVPtrIndex(pVBInfo); /* Get TV Delay */
-			tempbl = pVBInfo->XGI_TVDelayList[index];
-
-			if (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B
-					| VB_SIS301LV | VB_SIS302LV
-					| VB_XGI301C))
-				tempbl = pVBInfo->XGI_TVDelayList2[index];
+			tempbl = XGI301TVDelay;
 
 			if (pVBInfo->VBInfo & SetCRT2ToDualEdge)
 				tempbl = tempbl >> 4;
 			if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
-				/* Get LCD Delay */
-				index = XGI_GetLCDCapPtr(pVBInfo);
-				tempbh = pVBInfo->LCDCapList[index].
-						LCD_DelayCompensation;
+				tempbh = XGI301LCDDelay;
 
 				if (!(pVBInfo->VBInfo & XGI_SetCRT2ToLCDA))
 					tempbl = tempbh;
@@ -5799,10 +5700,7 @@ static void XGI_SetDelayComp(struct vb_device_info *pVBInfo)
 		tempbl = 0;
 		tempbh = 0;
 		if (pVBInfo->VBInfo & SetCRT2ToLCD) {
-			/* / Get LCD Delay */
-			tempah = pVBInfo->LCDCapList[
-					XGI_GetLCDCapPtr(pVBInfo)].
-						LCD_DelayCompensation;
+			tempah = XGI301LCDDelay;
 			tempah &= 0x0f;
 			tempah = tempah << 4;
 			xgifb_reg_and_or(pVBInfo->Part1Port, 0x2D, 0x0f,
@@ -6265,17 +6163,6 @@ static void XGI_SetCRT2ModeRegs(unsigned short ModeNo,
 	}
 }
 
-static void XGI_CloseCRTC(struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
-{
-	unsigned short tempbx;
-
-	tempbx = 0;
-
-	if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)
-		tempbx = 0x08A0;
-
-}
 
 void XGI_UnLockCRT2(struct xgi_hw_device_info *HwDeviceExtension,
 		struct vb_device_info *pVBInfo)
@@ -6867,7 +6754,6 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
 
 		XGI_SetCRT2ModeRegs(ModeNo, HwDeviceExtension, pVBInfo);
 		XGI_OEM310Setting(ModeNo, ModeIdIndex, pVBInfo); /*0212*/
-		XGI_CloseCRTC(HwDeviceExtension, pVBInfo);
 		XGI_EnableBridge(xgifb_info, HwDeviceExtension, pVBInfo);
 	} /* !XG20 */
 	else {
diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h
index 38f47ff..aea760a 100644
--- a/drivers/staging/xgifb/vb_struct.h
+++ b/drivers/staging/xgifb/vb_struct.h
@@ -51,13 +51,6 @@ struct XGI_LCDDataTablStruct {
 	unsigned short DATAPTR;
 };
 
-struct XGI330_LVDSDataStruct {
-	unsigned short VGAHT;
-	unsigned short VGAVT;
-	unsigned short LCDHT;
-	unsigned short LCDVT;
-};
-
 struct XGI330_LCDDataDesStruct2 {
 	unsigned short LCDHDES;
 	unsigned short LCDHRS;
@@ -67,15 +60,6 @@ struct XGI330_LCDDataDesStruct2 {
 	unsigned short LCDVSync;
 };
 
-struct XGI330_LCDDataStruct {
-	unsigned short RVBHCMAX;
-	unsigned short RVBHCFACT;
-	unsigned short VGAHT;
-	unsigned short VGAVT;
-	unsigned short LCDHT;
-	unsigned short LCDVT;
-};
-
 
 struct XGI330_TVDataStruct {
 	unsigned short RVBHCMAX;
@@ -103,13 +87,6 @@ struct XGI330_TVDataTablStruct {
 };
 
 
-struct XGI330_CHTVDataStruct {
-	unsigned short VGAHT;
-	unsigned short VGAVT;
-	unsigned short LCDHT;
-	unsigned short LCDVT;
-};
-
 struct XGI_TimingHStruct {
 	unsigned char data[8];
 };
@@ -126,7 +103,6 @@ struct XGI330_LCDCapStruct {
 	unsigned char	LCD_ID;
 	unsigned short	LCD_Capability;
 	unsigned char	LCD_SetFlag;
-	unsigned char	LCD_DelayCompensation;
 	unsigned char	LCD_HSyncWidth;
 	unsigned char	LCD_VSyncWidth;
 	unsigned char	LCD_VCLK;
@@ -174,11 +150,6 @@ struct XGI_CRT1TableStruct {
 };
 
 
-struct XGI330_VCLKDataStruct {
-	unsigned char SR2B, SR2C;
-	unsigned short CLOCK;
-};
-
 struct XGI301C_Tap4TimingStruct {
 	unsigned short DE;
 	unsigned char  Reg[64];   /* C0-FF */
@@ -220,50 +191,14 @@ struct vb_device_info {
 	unsigned char (*SR15)[8];
 	unsigned char (*CR40)[8];
 
-	unsigned char  *pSoftSetting;
-	unsigned char  *pOutputSelect;
-
-	unsigned short *pRGBSenseData;
-	unsigned short *pRGBSenseData2; /*301b*/
-	unsigned short *pVideoSenseData;
-	unsigned short *pVideoSenseData2;
-	unsigned short *pYCSenseData;
-	unsigned short *pYCSenseData2;
-
-	unsigned char  *pSR07;
-	unsigned char  *CR49;
-	unsigned char  *pSR1F;
 	unsigned char  *AGPReg;
 	unsigned char  *SR16;
-	unsigned char  *pSR21;
-	unsigned char  *pSR22;
-	unsigned char  *pSR23;
-	unsigned char  *pSR24;
-	unsigned char  *SR25;
-	unsigned char  *pSR31;
-	unsigned char  *pSR32;
-	unsigned char  *pSR33;
-	unsigned char  *pSR36;      /* alan 12/07/2006 */
-	unsigned char  *pCRCF;
-	unsigned char  *pCRD0;      /* alan 12/07/2006 */
-	unsigned char  *pCRDE;      /* alan 12/07/2006 */
-	unsigned char  *pCR8F;      /* alan 12/07/2006 */
-	unsigned char  *pSR40;      /* alan 12/07/2006 */
-	unsigned char  *pSR41;      /* alan 12/07/2006 */
-	unsigned char  *pDVOSetting;
-	unsigned char  *pCR2E;
-	unsigned char  *pCR2F;
-	unsigned char  *pCR46;
-	unsigned char  *pCR47;
-	unsigned char  *pCRT2Data_1_2;
-	unsigned char  *pCRT2Data_4_D;
-	unsigned char  *pCRT2Data_4_E;
-	unsigned char  *pCRT2Data_4_10;
+	unsigned char  SR21;
+	unsigned char  SR22;
+	unsigned char  SR25;
 	struct SiS_MCLKData  *MCLKData;
 	struct XGI_ECLKDataStruct  *ECLKData;
 
-	unsigned char   *XGI_TVDelayList;
-	unsigned char   *XGI_TVDelayList2;
 	unsigned char   *NTSCTiming;
 	unsigned char   *PALTiming;
 	unsigned char   *HiTVExtTiming;
@@ -280,8 +215,7 @@ struct vb_device_info {
 	unsigned char   *Ren750pGroup3;
 	unsigned char   *ScreenOffset;
 	unsigned char   *pXGINew_DRAMTypeDefinition;
-	unsigned char   *pXGINew_I2CDefinition ;
-	unsigned char   *pXGINew_CR97 ;
+	unsigned char   XGINew_CR97;
 
 	struct XGI330_LCDCapStruct  *LCDCapList;
 
diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h
index d22e599..75da7c3 100644
--- a/drivers/staging/xgifb/vb_table.h
+++ b/drivers/staging/xgifb/vb_table.h
@@ -1,3 +1,5 @@
+#ifndef _VB_TABLE_
+#define _VB_TABLE_
 /* yilin modify for xgi20 */
 static struct SiS_MCLKData XGI340New_MCLKData[] = {
 	{0x16, 0x01, 0x01, 166},
@@ -128,13 +130,6 @@ static unsigned char XGI340_AGPReg[12] = {
 
 static unsigned char XGI340_SR16[4] = {0x03, 0x83, 0x03, 0x83};
 
-static unsigned char XGI330_sr25[2];
-static unsigned char XGI330_sr31 = 0xc0;
-static unsigned char XGI330_sr32 = 0x11;
-static unsigned char XGI330_SR33;
-static unsigned char XG40_CRCF = 0x13;
-static unsigned char XG40_DRAMTypeDefinition = 0xFF ;
-
 static struct XGI_ExtStruct XGI330_EModeIDTable[] = {
 	{0x2e, 0x0a1b, 0x0306, 0x06, 0x05, 0x06},
 	{0x2f, 0x0a1b, 0x0305, 0x05, 0x05, 0x05},
@@ -418,7 +413,7 @@ static unsigned char XGI_CH7017LV1400x1050[] = {
 	0xAD, 0xDB, 0xF6, 0xAC, 0xE0, 0x02};
 
 /*add for new UNIVGABIOS*/
-static struct XGI330_LCDDataStruct  XGI_StLCD1024x768Data[] = {
+static struct SiS_LCDData  XGI_StLCD1024x768Data[] = {
 	{62,  25, 800,  546, 1344, 806},
 	{32,  15, 930,  546, 1344, 806},
 	{62,  25, 800,  546, 1344, 806}, /*chiawenfordot9->dot8*/
@@ -428,7 +423,7 @@ static struct XGI330_LCDDataStruct  XGI_StLCD1024x768Data[] = {
 	{1,   1,  1344, 806, 1344, 806}
 };
 
-static struct XGI330_LCDDataStruct  XGI_ExtLCD1024x768Data[] = {
+static struct SiS_LCDData  XGI_ExtLCD1024x768Data[] = {
 	/* { 12, 5, 896, 512,1344, 806}, // alan 09/12/2003 */
 	{42, 25, 1536, 419, 1344, 806},
 	/* { 12, 5, 896, 510,1344, 806}, // alan 09/12/2003 */
@@ -448,7 +443,7 @@ static struct XGI330_LCDDataStruct  XGI_ExtLCD1024x768Data[] = {
 	{1,  1,  1344, 806, 1344, 806}
 };
 
-static struct XGI330_LCDDataStruct  XGI_CetLCD1024x768Data[] = {
+static struct SiS_LCDData  XGI_CetLCD1024x768Data[] = {
 	{1, 1, 1344, 806, 1344, 806}, /* ; 00 (320x200,320x400,
 					       640x200,640x400) */
 	{1, 1, 1344, 806, 1344, 806}, /* 01 (320x350,640x350) */
@@ -459,7 +454,7 @@ static struct XGI330_LCDDataStruct  XGI_CetLCD1024x768Data[] = {
 	{1, 1, 1344, 806, 1344, 806}  /* 06 (1024x768x60Hz) */
 };
 
-static struct XGI330_LCDDataStruct  XGI_StLCD1280x1024Data[] = {
+static struct SiS_LCDData  XGI_StLCD1280x1024Data[] = {
 	{22,  5,  800,  510,  1650, 1088},
 	{22,  5,  800,  510,  1650, 1088},
 	{176, 45, 900,  510,  1650, 1088},
@@ -470,7 +465,7 @@ static struct XGI330_LCDDataStruct  XGI_StLCD1280x1024Data[] = {
 	{1,   1,  1688, 1066, 1688, 1066}
 };
 
-static struct XGI330_LCDDataStruct  XGI_ExtLCD1280x1024Data[] = {
+static struct SiS_LCDData  XGI_ExtLCD1280x1024Data[] = {
 	{211, 60,  1024, 501,  1688, 1066},
 	{211, 60,  1024, 508,  1688, 1066},
 	{211, 60,  1024, 501,  1688, 1066},
@@ -481,7 +476,7 @@ static struct XGI330_LCDDataStruct  XGI_ExtLCD1280x1024Data[] = {
 	{1,   1,   1688, 1066, 1688, 1066}
 };
 
-static struct XGI330_LCDDataStruct  XGI_CetLCD1280x1024Data[] = {
+static struct SiS_LCDData  XGI_CetLCD1280x1024Data[] = {
 	{1, 1, 1688, 1066, 1688, 1066}, /* 00 (320x200,320x400,
 					       640x200,640x400) */
 	{1, 1, 1688, 1066, 1688, 1066}, /* 01 (320x350,640x350) */
@@ -494,7 +489,7 @@ static struct XGI330_LCDDataStruct  XGI_CetLCD1280x1024Data[] = {
 	{1, 1, 1688, 1066, 1688, 1066}  /* 08 (1400x1050x60Hz) */
 };
 
-static struct XGI330_LCDDataStruct xgifb_lcd_1400x1050[] = {
+static struct SiS_LCDData xgifb_lcd_1400x1050[] = {
 	{211, 100, 2100, 408,  1688, 1066}, /* 00 (320x200,320x400,
 						   640x200,640x400) */
 	{211, 64,  1536, 358,  1688, 1066}, /* 01 (320x350,640x350) */
@@ -508,7 +503,7 @@ static struct XGI330_LCDDataStruct xgifb_lcd_1400x1050[] = {
 	{1,   1,   1688, 1066, 1688, 1066}  /* 08 (1400x1050x60Hz) */
 };
 
-static struct XGI330_LCDDataStruct  XGI_ExtLCD1600x1200Data[] = {
+static struct SiS_LCDData  XGI_ExtLCD1600x1200Data[] = {
 	{4,  1,  1620, 420,  2160, 1250}, /* { 3,1,2160,425,2160,1250 },
 					  // 00 (320x200,320x400,
 					  //	 640x200,640x400)
@@ -526,7 +521,7 @@ static struct XGI330_LCDDataStruct  XGI_ExtLCD1600x1200Data[] = {
 	{1,  1,  2160, 1250, 2160, 1250}  /* 09 (1600x1200x60Hz) ;302lv */
 };
 
-static struct XGI330_LCDDataStruct  XGI_StLCD1600x1200Data[] = {
+static struct SiS_LCDData  XGI_StLCD1600x1200Data[] = {
 	{27,  4,  800,  500,  2160, 1250}, /* 00 (320x200,320x400,
 						  640x200,640x400) */
 	{27,  4,  800,  500,  2160, 1250}, /* 01 (320x350,640x350) */
@@ -540,7 +535,7 @@ static struct XGI330_LCDDataStruct  XGI_StLCD1600x1200Data[] = {
 	{1,   1,  2160, 1250, 2160, 1250}  /* 09 (1600x1200) */
 };
 
-static struct XGI330_LCDDataStruct  XGI_CetLCD1400x1050Data[] = {
+static struct SiS_LCDData  XGI_CetLCD1400x1050Data[] = {
 	{1, 1, 1688, 1066, 1688, 1066}, /* 00 (320x200,320x400,
 					       640x200,640x400) */
 	{1, 1, 1688, 1066, 1688, 1066}, /* 01 (320x350,640x350) */
@@ -553,7 +548,7 @@ static struct XGI330_LCDDataStruct  XGI_CetLCD1400x1050Data[] = {
 	{1, 1, 1688, 1066, 1688, 1066}  /* 08 (1400x1050x60Hz) */
 };
 
-static struct XGI330_LCDDataStruct  XGI_NoScalingData[] = {
+static struct SiS_LCDData  XGI_NoScalingData[] = {
 	{1, 1, 800,  449,  800,  449},
 	{1, 1, 800,  449,  800,  449},
 	{1, 1, 900,  449,  900,  449},
@@ -564,7 +559,7 @@ static struct XGI330_LCDDataStruct  XGI_NoScalingData[] = {
 	{1, 1, 1688, 1066, 1688, 1066}
 };
 
-static struct XGI330_LCDDataStruct  XGI_ExtLCD1024x768x75Data[] = {
+static struct SiS_LCDData  XGI_ExtLCD1024x768x75Data[] = {
 	{42, 25, 1536, 419, 1344, 806}, /* ; 00 (320x200,320x400,
 						 640x200,640x400) */
 	{48, 25, 1536, 369, 1344, 806}, /* ; 01 (320x350,640x350) */
@@ -575,7 +570,7 @@ static struct XGI330_LCDDataStruct  XGI_ExtLCD1024x768x75Data[] = {
 	{1,  1,  1312, 800, 1312, 800}  /* ; 06 (1024x768x75Hz) */
 };
 
-static struct XGI330_LCDDataStruct  XGI_CetLCD1024x768x75Data[] = {
+static struct SiS_LCDData  XGI_CetLCD1024x768x75Data[] = {
 	{1, 1, 1312, 800, 1312, 800}, /* ; 00 (320x200,320x400,
 					       640x200,640x400) */
 	{1, 1, 1312, 800, 1312, 800}, /* ; 01 (320x350,640x350) */
@@ -586,7 +581,7 @@ static struct XGI330_LCDDataStruct  XGI_CetLCD1024x768x75Data[] = {
 	{1, 1, 1312, 800, 1312, 800}  /* ; 06 (1024x768x75Hz) */
 };
 
-static struct XGI330_LCDDataStruct xgifb_lcd_1280x1024x75[] = {
+static struct SiS_LCDData xgifb_lcd_1280x1024x75[] = {
 	{211, 60,  1024, 501,  1688, 1066}, /* ; 00 (320x200,320x400,
 						     640x200,640x400) */
 	{211, 60,  1024, 508,  1688, 1066}, /* ; 01 (320x350,640x350) */
@@ -598,7 +593,7 @@ static struct XGI330_LCDDataStruct xgifb_lcd_1280x1024x75[] = {
 	{1,   1,   1688, 1066, 1688, 1066}  /* ; 07 (1280x1024x75Hz) */
 };
 
-static struct XGI330_LCDDataStruct  XGI_CetLCD1280x1024x75Data[] = {
+static struct SiS_LCDData  XGI_CetLCD1280x1024x75Data[] = {
 	{1, 1, 1688, 1066, 1688, 1066}, /* ; 00 (320x200,320x400,
 						 640x200,640x400) */
 	{1, 1, 1688, 1066, 1688, 1066}, /* ; 01 (320x350,640x350) */
@@ -610,7 +605,7 @@ static struct XGI330_LCDDataStruct  XGI_CetLCD1280x1024x75Data[] = {
 	{1, 1, 1688, 1066, 1688, 1066}  /* ; 07 (1280x1024x75Hz) */
 };
 
-static struct XGI330_LCDDataStruct  XGI_NoScalingDatax75[] = {
+static struct SiS_LCDData  XGI_NoScalingDatax75[] = {
 	{1, 1, 800,  449,  800,  449},  /* ; 00 (320x200, 320x400,
 						 640x200, 640x400) */
 	{1, 1, 800,  449,  800,  449},  /* ; 01 (320x350, 640x350) */
@@ -1220,7 +1215,7 @@ static unsigned char XGI330_Ren750pGroup3[] = {
 	0x18, 0x1D, 0x23, 0x28, 0x4C, 0xAA, 0x01
 };
 
-static struct XGI330_LVDSDataStruct  XGI_LVDS1024x768Data_1[] = {
+static struct SiS_LVDSData  XGI_LVDS1024x768Data_1[] = {
 	{ 960, 438, 1344, 806},	/* 00 (320x200,320x400,640x200,640x400) */
 	{ 960, 388, 1344, 806},	/* 01 (320x350,640x350) */
 	{1040, 438, 1344, 806},	/* 02 (360x400,720x400) */
@@ -1231,7 +1226,7 @@ static struct XGI330_LVDSDataStruct  XGI_LVDS1024x768Data_1[] = {
 };
 
 
-static struct XGI330_LVDSDataStruct  XGI_LVDS1024x768Data_2[] = {
+static struct SiS_LVDSData  XGI_LVDS1024x768Data_2[] = {
 	{1344, 806, 1344, 806},
 	{1344, 806, 1344, 806},
 	{1344, 806, 1344, 806},
@@ -1243,7 +1238,7 @@ static struct XGI330_LVDSDataStruct  XGI_LVDS1024x768Data_2[] = {
 	{800,  525, 1280, 813}
 };
 
-static struct XGI330_LVDSDataStruct  XGI_LVDS1280x1024Data_1[] = {
+static struct SiS_LVDSData  XGI_LVDS1280x1024Data_1[] = {
 	{1048, 442,  1688, 1066},
 	{1048, 392,  1688, 1066},
 	{1048, 442,  1688, 1066},
@@ -1254,7 +1249,7 @@ static struct XGI330_LVDSDataStruct  XGI_LVDS1280x1024Data_1[] = {
 	{1688, 1066, 1688, 1066}
 };
 
-static struct XGI330_LVDSDataStruct  XGI_LVDS1280x1024Data_2[] = {
+static struct SiS_LVDSData  XGI_LVDS1280x1024Data_2[] = {
 	{1344, 806, 1344, 806},
 	{1344, 806, 1344, 806},
 	{1344, 806, 1344, 806},
@@ -1266,7 +1261,7 @@ static struct XGI330_LVDSDataStruct  XGI_LVDS1280x1024Data_2[] = {
 	{800,  525, 1280, 813}
 };
 
-static struct XGI330_LVDSDataStruct  XGI_LVDS1400x1050Data_1[] = {
+static struct SiS_LVDSData  XGI_LVDS1400x1050Data_1[] = {
 	{928,   416, 1688, 1066},
 	{928,   366, 1688, 1066},
 	{928,   416, 1688, 1066},
@@ -1278,7 +1273,7 @@ static struct XGI330_LVDSDataStruct  XGI_LVDS1400x1050Data_1[] = {
 	{1688, 1066, 1688, 1066}
 };
 
-static struct XGI330_LVDSDataStruct  XGI_LVDS1400x1050Data_2[] = {
+static struct SiS_LVDSData  XGI_LVDS1400x1050Data_2[] = {
 	{1688, 1066, 1688, 1066},
 	{1688, 1066, 1688, 1066},
 	{1688, 1066, 1688, 1066},
@@ -1291,7 +1286,7 @@ static struct XGI330_LVDSDataStruct  XGI_LVDS1400x1050Data_2[] = {
 };
 
 /* ;;[ycchen] 12/05/02 LCDHTxLCDVT=2048x1320 */
-static struct XGI330_LVDSDataStruct XGI_LVDS1600x1200Data_1[] = {
+static struct SiS_LVDSData XGI_LVDS1600x1200Data_1[] = {
 	{1088, 520,  2048, 1320}, /* 00 (320x200,320x400,640x200,640x400) */
 	{1088, 470,  2048, 1320}, /* 01 (320x350,640x350) */
 	{1088, 520,  2048, 1320}, /* 02 (360x400,720x400) */
@@ -1304,7 +1299,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1600x1200Data_1[] = {
 	{2048, 1320, 2048, 1320}  /* 09 (1600x1200) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDSNoScalingData[] = {
+static struct SiS_LVDSData XGI_LVDSNoScalingData[] = {
 	{ 800,  449,  800,  449}, /* 00 (320x200,320x400,640x200,640x400) */
 	{ 800,  449,  800,  449}, /* 01 (320x350,640x350) */
 	{ 800,  449,  800,  449}, /* 02 (360x400,720x400) */
@@ -1318,7 +1313,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDSNoScalingData[] = {
 	{1688,  806, 1688,  806}  /* 0A (1280x768x60Hz) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1x75[] = {
+static struct SiS_LVDSData XGI_LVDS1024x768Data_1x75[] = {
 	{ 960, 438, 1312, 800}, /* 00 (320x200,320x400,640x200,640x400) */
 	{ 960, 388, 1312, 800}, /* 01 (320x350,640x350) */
 	{1040, 438, 1312, 800}, /* 02 (360x400,720x400) */
@@ -1329,7 +1324,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1x75[] = {
 };
 
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2x75[] = {
+static struct SiS_LVDSData XGI_LVDS1024x768Data_2x75[] = {
 	{1312, 800, 1312, 800}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{1312, 800, 1312, 800}, /* ; 01 (320x350,640x350) */
 	{1312, 800, 1312, 800}, /* ; 02 (360x400,720x400) */
@@ -1339,7 +1334,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2x75[] = {
 	{1312, 800, 1312, 800}, /* ; 06 (512x384,1024x768) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1x75[] = {
+static struct SiS_LVDSData XGI_LVDS1280x1024Data_1x75[] = {
 	{1048,  442, 1688, 1066  }, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{1048,  392, 1688, 1066  }, /* ; 01 (320x350,640x350) */
 	{1128,  442, 1688, 1066  }, /* ; 02 (360x400,720x400) */
@@ -1350,7 +1345,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1x75[] = {
 	{1688, 1066, 1688, 1066 },  /* ; 06; 07 (640x512,1280x1024) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2x75[] = {
+static struct SiS_LVDSData XGI_LVDS1280x1024Data_2x75[] = {
 	{1688, 1066, 1688, 1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{1688, 1066, 1688, 1066 }, /* ; 01 (320x350,640x350) */
 	{1688, 1066, 1688, 1066 }, /* ; 02 (360x400,720x400) */
@@ -1361,7 +1356,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2x75[] = {
 	{1688, 1066, 1688, 1066 }, /* ; 06; 07 (640x512,1280x1024) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDSNoScalingDatax75[] = {
+static struct SiS_LVDSData XGI_LVDSNoScalingDatax75[] = {
 	{ 800,  449,  800, 449},  /* ; 00 (320x200,320x400,640x200,640x400) */
 	{ 800,  449,  800, 449},  /* ; 01 (320x350,640x350) */
 	{ 900,  449,  900, 449},  /* ; 02 (360x400,720x400) */
@@ -1376,7 +1371,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDSNoScalingDatax75[] = {
 	{1688,  806, 1688, 806},  /* ; 0A (1280x768x75Hz) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1[] = {
+static struct SiS_LVDSData XGI_LVDS1024x768Des_1[] = {
 	{0, 1048,   0, 771}, /* 00 (320x200,320x400,640x200,640x400) */
 	{0, 1048,   0, 771}, /* 01 (320x350,640x350) */
 	{0, 1048,   0, 771}, /* 02 (360x400,720x400) */
@@ -1386,7 +1381,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1[] = {
 	{0, 1048, 805, 770}  /* 06 (1024x768x60Hz) */
 } ;
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2[] = {
+static struct SiS_LVDSData XGI_LVDS1024x768Des_2[] = {
 	{1142,  856, 622, 587}, /* 00 (320x200,320x400,640x200,640x400) */
 	{1142,  856, 597, 562}, /* 01 (320x350,640x350) */
 	{1142,  856, 622, 587}, /* 02 (360x400,720x400) */
@@ -1396,7 +1391,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2[] = {
 	{   0, 1048, 805, 771}  /* 06 (1024x768x60Hz) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3[] = {
+static struct SiS_LVDSData XGI_LVDS1024x768Des_3[] = {
 	{320, 24, 622, 587}, /* 00 (320x200,320x400,640x200,640x400) */
 	{320, 24, 597, 562}, /* 01 (320x350,640x350) */
 	{320, 24, 622, 587}, /* 02 (360x400,720x400) */
@@ -1404,7 +1399,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3[] = {
 	{320, 24, 722, 687}  /* 04 (640x480x60Hz) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1[] = {
+static struct SiS_LVDSData XGI_LVDS1280x1024Des_1[] = {
 	{0, 1328,    0, 1025}, /* 00 (320x200,320x400,640x200,640x400) */
 	{0, 1328,    0, 1025}, /* 01 (320x350,640x350) */
 	{0, 1328,    0, 1025}, /* 02 (360x400,720x400) */
@@ -1416,7 +1411,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1[] = {
 };
 
  /* The Display setting for DE Mode Panel */
-static struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2[] = {
+static struct SiS_LVDSData XGI_LVDS1280x1024Des_2[] = {
 	{1368, 1008, 752, 711}, /* 00 (320x200,320x400,640x200,640x400) */
 	{1368, 1008, 729, 688}, /* 01 (320x350,640x350) */
 	{1408, 1048, 752, 711}, /* 02 (360x400,720x400) */
@@ -1427,7 +1422,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2[] = {
 	{0000, 1328,   0, 1025} /* 07 (1280x1024x60Hz) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_1[] = {
+static struct SiS_LVDSData XGI_LVDS1400x1050Des_1[] = {
 	{0, 1448, 0, 1051}, /* 00 (320x200,320x400,640x200,640x400) */
 	{0, 1448, 0, 1051}, /* 01 (320x350,640x350) */
 	{0, 1448, 0, 1051}, /* 02 (360x400,720x400) */
@@ -1439,7 +1434,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_1[] = {
 	{0, 1448, 0, 1051}  /* 08 (1400x1050x60Hz) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_2[] = {
+static struct SiS_LVDSData XGI_LVDS1400x1050Des_2[] = {
 	{1308, 1068,  781,  766}, /* 00 (320x200,320x400,640x200,640x400) */
 	{1308, 1068,  781,  766}, /* 01 (320x350,640x350) */
 	{1308, 1068,  781,  766}, /* 02 (360x400,720x400) */
@@ -1451,7 +1446,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_2[] = {
 	{   0, 1448,    0, 1051}  /* 08 (1400x1050x60Hz) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1600x1200Des_1[] = {
+static struct SiS_LVDSData XGI_LVDS1600x1200Des_1[] = {
 	{0, 1664, 0, 1201}, /* 00 (320x200,320x400,640x200,640x400) */
 	{0, 1664, 0, 1201}, /* 01 (320x350,640x350) */
 	{0, 1664, 0, 1201}, /* 02 (360x400,720x400) */
@@ -1481,7 +1476,7 @@ static struct XGI330_LCDDataDesStruct2  XGI_LVDSNoScalingDesData[] = {
 };
 
 /* ; 1024x768 Full-screen */
-static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1x75[] = {
+static struct SiS_LVDSData XGI_LVDS1024x768Des_1x75[] = {
 	{0, 1040, 0, 769}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{0, 1040, 0, 769}, /* ; 01 (320x350,640x350) */
 	{0, 1040, 0, 769}, /* ; 02 (360x400,720x400) */
@@ -1492,7 +1487,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1x75[] = {
 };
 
 /* ; 1024x768 center-screen (Enh. Mode) */
-static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2x75[] = {
+static struct SiS_LVDSData XGI_LVDS1024x768Des_2x75[] = {
 	{1142,  856, 622, 587}, /* 00 (320x200,320x400,640x200,640x400) */
 	{1142,  856, 597, 562}, /* 01 (320x350,640x350) */
 	{1142,  856, 622, 587}, /* 02 (360x400,720x400) */
@@ -1503,7 +1498,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2x75[] = {
 };
 
 /* ; 1024x768 center-screen (St.Mode) */
-static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3x75[] =  {
+static struct SiS_LVDSData XGI_LVDS1024x768Des_3x75[] =  {
 	{320, 24, 622, 587}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{320, 24, 597, 562}, /* ; 01 (320x350,640x350) */
 	{320, 24, 622, 587}, /* ; 02 (360x400,720x400) */
@@ -1511,7 +1506,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3x75[] =  {
 	{320, 24, 722, 687}  /* ; 04 (640x480x60Hz) */
 };
 
-static struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1x75[] = {
+static struct SiS_LVDSData XGI_LVDS1280x1024Des_1x75[] = {
 	{0, 1296, 0, 1025}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{0, 1296, 0, 1025}, /* ; 01 (320x350,640x350) */
 	{0, 1296, 0, 1025}, /* ; 02 (360x400,720x400) */
@@ -1524,7 +1519,7 @@ static struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1x75[] = {
 
 /* The Display setting for DE Mode Panel */
 /* [ycchen] 02/18/03 Set DE as default */
-static struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2x75[] = {
+static struct SiS_LVDSData XGI_LVDS1280x1024Des_2x75[] = {
 	{1368,  976, 752,  711}, /* ; 00 (320x200,320x400,640x200,640x400) */
 	{1368,  976, 729,  688}, /* ; 01 (320x350,640x350) */
 	{1408,  976, 752,  711}, /* ; 02 (360x400,720x400) */
@@ -1552,7 +1547,7 @@ static struct XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesDatax75[] = {
 	{0, 1328,   0,  771, 112, 6}  /* ; 0A (1280x768x75Hz) */
 };
 
-static struct XGI330_CHTVDataStruct  XGI_CHTVUNTSCData[] = {
+static struct SiS_LVDSData  XGI_CHTVUNTSCData[] = {
 	{ 840, 600,  840, 600},
 	{ 840, 600,  840, 600},
 	{ 840, 600,  840, 600},
@@ -1561,7 +1556,7 @@ static struct XGI330_CHTVDataStruct  XGI_CHTVUNTSCData[] = {
 	{1064, 750, 1064, 750}
 };
 
-static struct XGI330_CHTVDataStruct  XGI_CHTVONTSCData[] = {
+static struct SiS_LVDSData  XGI_CHTVONTSCData[] = {
 	{ 840, 525,  840, 525},
 	{ 840, 525,  840, 525},
 	{ 840, 525,  840, 525},
@@ -1570,7 +1565,7 @@ static struct XGI330_CHTVDataStruct  XGI_CHTVONTSCData[] = {
 	{1040, 700, 1040, 700}
 };
 
-static struct XGI330_CHTVDataStruct  XGI_CHTVUPALData[] = {
+static struct SiS_LVDSData  XGI_CHTVUPALData[] = {
 	{1008, 625, 1008, 625},
 	{1008, 625, 1008, 625},
 	{1008, 625, 1008, 625},
@@ -1579,7 +1574,7 @@ static struct XGI330_CHTVDataStruct  XGI_CHTVUPALData[] = {
 	{ 936, 836,  936, 836}
 };
 
-static struct XGI330_CHTVDataStruct  XGI_CHTVOPALData[] = {
+static struct SiS_LVDSData  XGI_CHTVOPALData[] = {
 	{1008, 625, 1008, 625},
 	{1008, 625, 1008, 625},
 	{1008, 625, 1008, 625},
@@ -1991,70 +1986,70 @@ static unsigned short LCDLenList[] = {
 /* Dual link only */
 static struct XGI330_LCDCapStruct  XGI_LCDDLCapList[] = {
 /* LCDCap1024x768 */
-	{Panel_1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65_315,
+	{Panel_1024x768, DefaultLCDCap, 0, 0x88, 0x06, VCLK65_315,
 	0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
 /* LCDCap1280x1024 */
 	{Panel_1280x1024, XGI_LCDDualLink+DefaultLCDCap, StLCDBToA,
-	0x012, 0x70, 0x03, VCLK108_2_315,
+	0x70, 0x03, VCLK108_2_315,
 	0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1400x1050 */
 	{Panel_1400x1050, XGI_LCDDualLink+DefaultLCDCap, StLCDBToA,
-	0x012, 0x70, 0x03, VCLK108_2_315,
+	0x70, 0x03, VCLK108_2_315,
 	 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1600x1200 */
 	{Panel_1600x1200, XGI_LCDDualLink+DefaultLCDCap, LCDToFull,
-	0x012, 0xC0, 0x03, VCLK162,
+	0xC0, 0x03, VCLK162,
 	 0x43, 0x22, 0x70, 0x24, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1024x768x75 */
-	{Panel_1024x768x75, DefaultLCDCap, 0, 0x012, 0x60, 0, VCLK78_75,
+	{Panel_1024x768x75, DefaultLCDCap, 0, 0x60, 0, VCLK78_75,
 	 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
 /* LCDCap1280x1024x75 */
 	{Panel_1280x1024x75, XGI_LCDDualLink+DefaultLCDCap, StLCDBToA,
-	0x012, 0x90, 0x03, VCLK135_5,
+	 0x90, 0x03, VCLK135_5,
 	 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCapDefault */
-	{0xFF, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65_315,
+	{0xFF, DefaultLCDCap, 0, 0x88, 0x06, VCLK65_315,
 	0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
 };
 
 static struct XGI330_LCDCapStruct  XGI_LCDCapList[] = {
 /* LCDCap1024x768 */
-	{Panel_1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65_315,
+	{Panel_1024x768, DefaultLCDCap, 0, 0x88, 0x06, VCLK65_315,
 	0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
 /* LCDCap1280x1024 */
 	{Panel_1280x1024, DefaultLCDCap, StLCDBToA,
-	0x012, 0x70, 0x03, VCLK108_2_315,
+	0x70, 0x03, VCLK108_2_315,
 	0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1400x1050 */
 	{Panel_1400x1050, DefaultLCDCap, StLCDBToA,
-	0x012, 0x70, 0x03, VCLK108_2_315,
+	 0x70, 0x03, VCLK108_2_315,
 	 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1600x1200 */
 	{Panel_1600x1200, DefaultLCDCap, LCDToFull,
-	0x012, 0xC0, 0x03, VCLK162,
+	 0xC0, 0x03, VCLK162,
 	 0x5A, 0x23, 0x5A, 0x23, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCap1024x768x75 */
-	{Panel_1024x768x75, DefaultLCDCap, 0, 0x012, 0x60, 0, VCLK78_75,
+	{Panel_1024x768x75, DefaultLCDCap, 0, 0x60, 0, VCLK78_75,
 	 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
 /* LCDCap1280x1024x75 */
 	{Panel_1280x1024x75, DefaultLCDCap, StLCDBToA,
-	0x012, 0x90, 0x03, VCLK135_5,
+	 0x90, 0x03, VCLK135_5,
 	 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
 /* LCDCapDefault */
-	{0xFF, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65_315,
+	{0xFF, DefaultLCDCap, 0, 0x88, 0x06, VCLK65_315,
 	0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
 	0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
 };
@@ -2253,49 +2248,7 @@ static struct SiS_ModeResInfo_S XGI330_ModeResInfo[] = {
 	{1152,  864, 8, 16}
 };
 
-static unsigned char XGI330_OutputSelect = 0x40;
-static unsigned char XGI330_SoftSetting = 0x30;
-static unsigned char XGI330_SR07 = 0x18;
-
-static unsigned char XGI330_CR49[] = {0xaa, 0x88};
-static unsigned char XGI330_SR1F;
-static unsigned char XGI330_SR21 = 0xa3;
-static unsigned char XGI330_SR22 = 0xfb;
-static unsigned char XGI330_SR23 = 0xf6;
-static unsigned char XGI330_SR24 = 0xd;
-
-static unsigned char XGI330_CRT2Data_1_2;
-static unsigned char XGI330_CRT2Data_4_D;
-static unsigned char XGI330_CRT2Data_4_E;
-static unsigned char XGI330_CRT2Data_4_10 = 0x80;
-static unsigned short XGI330_RGBSenseData = 0xd1;
-static unsigned short XGI330_VideoSenseData = 0xb9;
-static unsigned short XGI330_YCSenseData = 0xb3;
-static unsigned short XGI330_RGBSenseData2 = 0x0190;     /*301b*/
-static unsigned short XGI330_VideoSenseData2 = 0x0110;
-static unsigned short XGI330_YCSenseData2 = 0x016B;
-static unsigned char XG40_I2CDefinition;
-static unsigned char XG20_CR97 = 0x10 ;
-
-static unsigned char XG21_DVOSetting;
-static unsigned char XG21_CR2E;
-static unsigned char XG21_CR2F;
-static unsigned char XG21_CR46;
-static unsigned char XG21_CR47;
-
-static unsigned char XG27_CR97 = 0xC1 ;
-static unsigned char XG27_SR36 = 0x30 ;
-static unsigned char XG27_CR8F = 0x0C ;
-static unsigned char XG27_CRD0[] = {
-	0, 0, 0, 0, 0, 0, 0, 0x82, 0x00, 0x66, 0x01, 0x00
-};
-static unsigned char XG27_CRDE[2];
-static unsigned char XG27_SR40 = 0x04 ;
-static unsigned char XG27_SR41 = 0x00 ;
-
-static unsigned char Z11m_CR97 = 0x80 ;
-
-static struct XGI330_VCLKDataStruct XGI_VCLKData[] = {
+static struct SiS_VCLKData XGI_VCLKData[] = {
 	/* SR2B,SR2C,SR2D */
 	{0x1B, 0xE1,  25}, /* 00 (25.175MHz) */
 	{0x4E, 0xE4,  28}, /* 01 (28.322MHz) */
@@ -2388,7 +2341,7 @@ static struct XGI330_VCLKDataStruct XGI_VCLKData[] = {
 	{0xFF, 0x00,   0}  /* End mark */
 };
 
-static struct XGI330_VCLKDataStruct XGI_VBVCLKData[] = {
+static struct SiS_VCLKData XGI_VBVCLKData[] = {
 	{0x1B, 0xE1,  25}, /* 00 (25.175MHz) */
 	{0x4E, 0xE4,  28}, /* 01 (28.322MHz) */
 	{0x57, 0xE4,  31}, /* 02 (31.500MHz) */
@@ -2480,36 +2433,8 @@ static struct XGI330_VCLKDataStruct XGI_VBVCLKData[] = {
 	{0xFF, 0x00,   0}  /* End mark */
 };
 
-static unsigned char XGI301TVDelayList[] = {
-	0x22, /* ; 0 ExtNTSCDelay */
-	0x22, /* ; 1 StNTSCDelay */
-	0x22, /* ; 2 ExtPALDelay */
-	0x22, /* ; 3 StPALDelay */
-	0x88, /* ; 4 ExtHiTVDelay(1080i) */
-	0xBB, /* ; 5 StHiTVDelay(1080i) */
-	0x22, /* ; 6 ExtYPbPrDelay(525i) */
-	0x22, /* ; 7 StYPbPrDealy(525i) */
-	0x22, /* ; 8 ExtYPbPrDelay(525p) */
-	0x22, /* ; 9 StYPbPrDealy(525p) */
-	0x22, /* ; A ExtYPbPrDelay(750p) */
-	0x22  /* B StYPbPrDealy(750p) */
-};
-
-static unsigned char XGI301TVDelayList2[] = {
-	0x22, /* ; 0 ExtNTSCDelay */
-	0x22, /* ; 1 StNTSCDelay */
-	0x22, /* ; 2 ExtPALDelay */
-	0x22, /* ; 3 StPALDelay */
-	0x22, /* ; 4 ExtHiTVDelay */
-	0x22, /* ; 5 StHiTVDelay */
-	0x22, /* ; 6 ExtYPbPrDelay(525i) */
-	0x22, /* ; 7 StYPbPrDealy(525i) */
-	0x22, /* ; 8 ExtYPbPrDelay(525p) */
-	0x22, /* ; 9 StYPbPrDealy(525p) */
-	0x22, /* ; A ExtYPbPrDelay(750p) */
-	0x22  /* ; B StYPbPrDealy(750p) */
-};
-
+#define XGI301TVDelay 0x22
+#define XGI301LCDDelay 0x12
 
 static unsigned char TVAntiFlickList[] = {/* NTSCAntiFlicker */
 	0x04, /* ; 0 Adaptive */
@@ -2696,3 +2621,4 @@ static struct XGI301C_Tap4TimingStruct YPbPr750pTap4Timing[] = {
 		 }
 	}
 };
+#endif
diff --git a/drivers/staging/xgifb/vb_util.c b/drivers/staging/xgifb/vb_util.c
index b5c9989..1b452f8 100644
--- a/drivers/staging/xgifb/vb_util.c
+++ b/drivers/staging/xgifb/vb_util.c
@@ -1,12 +1,4 @@
-#include <linux/io.h>
-#include <linux/types.h>
-
-#include "vb_def.h"
 #include "vgatypes.h"
-#include "vb_struct.h"
-
-#include "XGIfb.h"
-
 #include "vb_util.h"
 
 void xgifb_reg_set(unsigned long port, u8 index, u8 data)
diff --git a/drivers/staging/xgifb/vgatypes.h b/drivers/staging/xgifb/vgatypes.h
index 30cdd1a..7fc0719 100644
--- a/drivers/staging/xgifb/vgatypes.h
+++ b/drivers/staging/xgifb/vgatypes.h
@@ -1,7 +1,6 @@
 #ifndef _VGATYPES_
 #define _VGATYPES_
 
-#include <linux/ioctl.h>
 #include <linux/fb.h>	/* for struct fb_var_screeninfo for sis.h */
 #include "../../video/sis/vgatypes.h"
 #include "../../video/sis/sis.h"		/* for LCD_TYPE */
diff --git a/drivers/staging/zcache/Kconfig b/drivers/staging/zcache/Kconfig
index 7048e01..4881839 100644
--- a/drivers/staging/zcache/Kconfig
+++ b/drivers/staging/zcache/Kconfig
@@ -1,9 +1,6 @@
 config ZCACHE
 	bool "Dynamic compression of swap pages and clean pagecache pages"
-	# X86 dependency is because zsmalloc uses non-portable pte/tlb
-	# functions
-	depends on (CLEANCACHE || FRONTSWAP) && CRYPTO=y && X86
-	select ZSMALLOC
+	depends on (CLEANCACHE || FRONTSWAP) && CRYPTO=y && ZSMALLOC=y
 	select CRYPTO_LZO
 	default n
 	help
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
index 784c796..c9e08bb 100644
--- a/drivers/staging/zcache/zcache-main.c
+++ b/drivers/staging/zcache/zcache-main.c
@@ -31,6 +31,7 @@
 #include <linux/math64.h>
 #include <linux/crypto.h>
 #include <linux/string.h>
+#include <linux/idr.h>
 #include "tmem.h"
 
 #include "../zsmalloc/zsmalloc.h"
@@ -53,15 +54,13 @@
 	(__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC)
 #endif
 
-#define MAX_POOLS_PER_CLIENT 16
-
 #define MAX_CLIENTS 16
 #define LOCAL_CLIENT ((uint16_t)-1)
 
 MODULE_LICENSE("GPL");
 
 struct zcache_client {
-	struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
+	struct idr tmem_pools;
 	struct zs_pool *zspool;
 	bool allocated;
 	atomic_t refcount;
@@ -693,14 +692,14 @@ static unsigned int zv_max_mean_zsize = (PAGE_SIZE / 8) * 5;
 static atomic_t zv_curr_dist_counts[NCHUNKS];
 static atomic_t zv_cumul_dist_counts[NCHUNKS];
 
-static struct zv_hdr *zv_create(struct zs_pool *pool, uint32_t pool_id,
+static unsigned long zv_create(struct zs_pool *pool, uint32_t pool_id,
 				struct tmem_oid *oid, uint32_t index,
 				void *cdata, unsigned clen)
 {
 	struct zv_hdr *zv;
 	u32 size = clen + sizeof(struct zv_hdr);
 	int chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
-	void *handle = NULL;
+	unsigned long handle = 0;
 
 	BUG_ON(!irqs_disabled());
 	BUG_ON(chunks >= NCHUNKS);
@@ -721,7 +720,7 @@ out:
 	return handle;
 }
 
-static void zv_free(struct zs_pool *pool, void *handle)
+static void zv_free(struct zs_pool *pool, unsigned long handle)
 {
 	unsigned long flags;
 	struct zv_hdr *zv;
@@ -743,7 +742,7 @@ static void zv_free(struct zs_pool *pool, void *handle)
 	local_irq_restore(flags);
 }
 
-static void zv_decompress(struct page *page, void *handle)
+static void zv_decompress(struct page *page, unsigned long handle)
 {
 	unsigned int clen = PAGE_SIZE;
 	char *to_va;
@@ -949,11 +948,9 @@ static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid)
 			goto out;
 		atomic_inc(&cli->refcount);
 	}
-	if (poolid < MAX_POOLS_PER_CLIENT) {
-		pool = cli->tmem_pools[poolid];
-		if (pool != NULL)
-			atomic_inc(&pool->refcount);
-	}
+	pool = idr_find(&cli->tmem_pools, poolid);
+	if (pool != NULL)
+		atomic_inc(&pool->refcount);
 out:
 	return pool;
 }
@@ -987,6 +984,7 @@ int zcache_new_client(uint16_t cli_id)
 	cli->zspool = zs_create_pool("zcache", ZCACHE_GFP_MASK);
 	if (cli->zspool == NULL)
 		goto out;
+	idr_init(&cli->tmem_pools);
 #endif
 	ret = 0;
 out:
@@ -1247,7 +1245,7 @@ static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw,
 	int ret = 0;
 
 	BUG_ON(is_ephemeral(pool));
-	zv_decompress((struct page *)(data), pampd);
+	zv_decompress((struct page *)(data), (unsigned long)pampd);
 	return ret;
 }
 
@@ -1282,7 +1280,7 @@ static void zcache_pampd_free(void *pampd, struct tmem_pool *pool,
 		atomic_dec(&zcache_curr_eph_pampd_count);
 		BUG_ON(atomic_read(&zcache_curr_eph_pampd_count) < 0);
 	} else {
-		zv_free(cli->zspool, pampd);
+		zv_free(cli->zspool, (unsigned long)pampd);
 		atomic_dec(&zcache_curr_pers_pampd_count);
 		BUG_ON(atomic_read(&zcache_curr_pers_pampd_count) < 0);
 	}
@@ -1673,10 +1671,10 @@ static int zcache_destroy_pool(int cli_id, int pool_id)
 	if (cli == NULL)
 		goto out;
 	atomic_inc(&cli->refcount);
-	pool = cli->tmem_pools[pool_id];
+	pool = idr_find(&cli->tmem_pools, pool_id);
 	if (pool == NULL)
 		goto out;
-	cli->tmem_pools[pool_id] = NULL;
+	idr_remove(&cli->tmem_pools, pool_id);
 	/* wait for pool activity on other cpus to quiesce */
 	while (atomic_read(&pool->refcount) != 0)
 		;
@@ -1696,6 +1694,7 @@ static int zcache_new_pool(uint16_t cli_id, uint32_t flags)
 	int poolid = -1;
 	struct tmem_pool *pool;
 	struct zcache_client *cli = NULL;
+	int r;
 
 	if (cli_id == LOCAL_CLIENT)
 		cli = &zcache_host;
@@ -1710,20 +1709,25 @@ static int zcache_new_pool(uint16_t cli_id, uint32_t flags)
 		goto out;
 	}
 
-	for (poolid = 0; poolid < MAX_POOLS_PER_CLIENT; poolid++)
-		if (cli->tmem_pools[poolid] == NULL)
-			break;
-	if (poolid >= MAX_POOLS_PER_CLIENT) {
-		pr_info("zcache: pool creation failed: max exceeded\n");
+	do {
+		r = idr_pre_get(&cli->tmem_pools, GFP_ATOMIC);
+		if (r != 1) {
+			kfree(pool);
+			pr_info("zcache: pool creation failed: out of memory\n");
+			goto out;
+		}
+		r = idr_get_new(&cli->tmem_pools, pool, &poolid);
+	} while (r == -EAGAIN);
+	if (r) {
+		pr_info("zcache: pool creation failed: error %d\n", r);
 		kfree(pool);
-		poolid = -1;
 		goto out;
 	}
+
 	atomic_set(&pool->refcount, 0);
 	pool->client = cli;
 	pool->pool_id = poolid;
 	tmem_new_pool(pool, flags);
-	cli->tmem_pools[poolid] = pool;
 	pr_info("zcache: created %s tmem pool, id=%d, client=%d\n",
 		flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
 		poolid, cli_id);
diff --git a/drivers/staging/zram/Kconfig b/drivers/staging/zram/Kconfig
index 9d11a4c..be5abe8 100644
--- a/drivers/staging/zram/Kconfig
+++ b/drivers/staging/zram/Kconfig
@@ -1,9 +1,6 @@
 config ZRAM
 	tristate "Compressed RAM block device support"
-	# X86 dependency is because zsmalloc uses non-portable pte/tlb
-	# functions
-	depends on BLOCK && SYSFS && X86
-	select ZSMALLOC
+	depends on BLOCK && SYSFS && ZSMALLOC
 	select LZO_COMPRESS
 	select LZO_DECOMPRESS
 	default n
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 685d612..706cb62 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -135,7 +135,8 @@ static void zram_set_disksize(struct zram *zram, size_t totalram_bytes)
 
 static void zram_free_page(struct zram *zram, size_t index)
 {
-	void *handle = zram->table[index].handle;
+	unsigned long handle = zram->table[index].handle;
+	u16 size = zram->table[index].size;
 
 	if (unlikely(!handle)) {
 		/*
@@ -149,24 +150,19 @@ static void zram_free_page(struct zram *zram, size_t index)
 		return;
 	}
 
-	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
-		__free_page(handle);
-		zram_clear_flag(zram, index, ZRAM_UNCOMPRESSED);
-		zram_stat_dec(&zram->stats.pages_expand);
-		goto out;
-	}
+	if (unlikely(size > max_zpage_size))
+		zram_stat_dec(&zram->stats.bad_compress);
 
 	zs_free(zram->mem_pool, handle);
 
-	if (zram->table[index].size <= PAGE_SIZE / 2)
+	if (size <= PAGE_SIZE / 2)
 		zram_stat_dec(&zram->stats.good_compress);
 
-out:
 	zram_stat64_sub(zram, &zram->stats.compr_size,
 			zram->table[index].size);
 	zram_stat_dec(&zram->stats.pages_stored);
 
-	zram->table[index].handle = NULL;
+	zram->table[index].handle = 0;
 	zram->table[index].size = 0;
 }
 
@@ -182,22 +178,6 @@ static void handle_zero_page(struct bio_vec *bvec)
 	flush_dcache_page(page);
 }
 
-static void handle_uncompressed_page(struct zram *zram, struct bio_vec *bvec,
-				     u32 index, int offset)
-{
-	struct page *page = bvec->bv_page;
-	unsigned char *user_mem, *cmem;
-
-	user_mem = kmap_atomic(page);
-	cmem = kmap_atomic(zram->table[index].handle);
-
-	memcpy(user_mem + bvec->bv_offset, cmem + offset, bvec->bv_len);
-	kunmap_atomic(cmem);
-	kunmap_atomic(user_mem);
-
-	flush_dcache_page(page);
-}
-
 static inline int is_partial_io(struct bio_vec *bvec)
 {
 	return bvec->bv_len != PAGE_SIZE;
@@ -209,7 +189,6 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
 	int ret;
 	size_t clen;
 	struct page *page;
-	struct zobj_header *zheader;
 	unsigned char *user_mem, *cmem, *uncmem = NULL;
 
 	page = bvec->bv_page;
@@ -227,12 +206,6 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
 		return 0;
 	}
 
-	/* Page is stored uncompressed since it's incompressible */
-	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
-		handle_uncompressed_page(zram, bvec, index, offset);
-		return 0;
-	}
-
 	if (is_partial_io(bvec)) {
 		/* Use  a temporary buffer to decompress the page */
 		uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
@@ -249,8 +222,7 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
 
 	cmem = zs_map_object(zram->mem_pool, zram->table[index].handle);
 
-	ret = lzo1x_decompress_safe(cmem + sizeof(*zheader),
-				    zram->table[index].size,
+	ret = lzo1x_decompress_safe(cmem, zram->table[index].size,
 				    uncmem, &clen);
 
 	if (is_partial_io(bvec)) {
@@ -278,28 +250,18 @@ static int zram_read_before_write(struct zram *zram, char *mem, u32 index)
 {
 	int ret;
 	size_t clen = PAGE_SIZE;
-	struct zobj_header *zheader;
 	unsigned char *cmem;
+	unsigned long handle = zram->table[index].handle;
 
-	if (zram_test_flag(zram, index, ZRAM_ZERO) ||
-	    !zram->table[index].handle) {
+	if (zram_test_flag(zram, index, ZRAM_ZERO) || !handle) {
 		memset(mem, 0, PAGE_SIZE);
 		return 0;
 	}
 
-	cmem = zs_map_object(zram->mem_pool, zram->table[index].handle);
-
-	/* Page is stored uncompressed since it's incompressible */
-	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
-		memcpy(mem, cmem, PAGE_SIZE);
-		kunmap_atomic(cmem);
-		return 0;
-	}
-
-	ret = lzo1x_decompress_safe(cmem + sizeof(*zheader),
-				    zram->table[index].size,
+	cmem = zs_map_object(zram->mem_pool, handle);
+	ret = lzo1x_decompress_safe(cmem, zram->table[index].size,
 				    mem, &clen);
-	zs_unmap_object(zram->mem_pool, zram->table[index].handle);
+	zs_unmap_object(zram->mem_pool, handle);
 
 	/* Should NEVER happen. Return bio error if it does. */
 	if (unlikely(ret != LZO_E_OK)) {
@@ -315,11 +277,9 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
 			   int offset)
 {
 	int ret;
-	u32 store_offset;
 	size_t clen;
-	void *handle;
-	struct zobj_header *zheader;
-	struct page *page, *page_store;
+	unsigned long handle;
+	struct page *page;
 	unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
 
 	page = bvec->bv_page;
@@ -381,31 +341,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
 		goto out;
 	}
 
-	/*
-	 * Page is incompressible. Store it as-is (uncompressed)
-	 * since we do not want to return too many disk write
-	 * errors which has side effect of hanging the system.
-	 */
-	if (unlikely(clen > max_zpage_size)) {
-		clen = PAGE_SIZE;
-		page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
-		if (unlikely(!page_store)) {
-			pr_info("Error allocating memory for "
-				"incompressible page: %u\n", index);
-			ret = -ENOMEM;
-			goto out;
-		}
-
-		store_offset = 0;
-		zram_set_flag(zram, index, ZRAM_UNCOMPRESSED);
-		zram_stat_inc(&zram->stats.pages_expand);
-		handle = page_store;
-		src = kmap_atomic(page);
-		cmem = kmap_atomic(page_store);
-		goto memstore;
-	}
+	if (unlikely(clen > max_zpage_size))
+		zram_stat_inc(&zram->stats.bad_compress);
 
-	handle = zs_malloc(zram->mem_pool, clen + sizeof(*zheader));
+	handle = zs_malloc(zram->mem_pool, clen);
 	if (!handle) {
 		pr_info("Error allocating memory for compressed "
 			"page: %u, size=%zu\n", index, clen);
@@ -414,24 +353,9 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
 	}
 	cmem = zs_map_object(zram->mem_pool, handle);
 
-memstore:
-#if 0
-	/* Back-reference needed for memory defragmentation */
-	if (!zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)) {
-		zheader = (struct zobj_header *)cmem;
-		zheader->table_idx = index;
-		cmem += sizeof(*zheader);
-	}
-#endif
-
 	memcpy(cmem, src, clen);
 
-	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
-		kunmap_atomic(cmem);
-		kunmap_atomic(src);
-	} else {
-		zs_unmap_object(zram->mem_pool, handle);
-	}
+	zs_unmap_object(zram->mem_pool, handle);
 
 	zram->table[index].handle = handle;
 	zram->table[index].size = clen;
@@ -592,14 +516,11 @@ void __zram_reset_device(struct zram *zram)
 
 	/* Free all pages that are still in this zram device */
 	for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
-		void *handle = zram->table[index].handle;
+		unsigned long handle = zram->table[index].handle;
 		if (!handle)
 			continue;
 
-		if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
-			__free_page(handle);
-		else
-			zs_free(zram->mem_pool, handle);
+		zs_free(zram->mem_pool, handle);
 	}
 
 	vfree(zram->table);
@@ -724,7 +645,7 @@ static int create_device(struct zram *zram, int device_id)
 	zram->disk = alloc_disk(1);
 	if (!zram->disk) {
 		blk_cleanup_queue(zram->queue);
-		pr_warning("Error allocating disk structure for device %d\n",
+		pr_warn("Error allocating disk structure for device %d\n",
 			device_id);
 		ret = -ENOMEM;
 		goto out;
@@ -755,7 +676,7 @@ static int create_device(struct zram *zram, int device_id)
 	ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj,
 				&zram_disk_attr_group);
 	if (ret < 0) {
-		pr_warning("Error creating sysfs group");
+		pr_warn("Error creating sysfs group");
 		goto out;
 	}
 
@@ -789,7 +710,7 @@ static int __init zram_init(void)
 	int ret, dev_id;
 
 	if (num_devices > max_num_devices) {
-		pr_warning("Invalid value for num_devices: %u\n",
+		pr_warn("Invalid value for num_devices: %u\n",
 				num_devices);
 		ret = -EINVAL;
 		goto out;
@@ -797,7 +718,7 @@ static int __init zram_init(void)
 
 	zram_major = register_blkdev(0, "zram");
 	if (zram_major <= 0) {
-		pr_warning("Unable to get major number\n");
+		pr_warn("Unable to get major number\n");
 		ret = -EBUSY;
 		goto out;
 	}
diff --git a/drivers/staging/zram/zram_drv.h b/drivers/staging/zram/zram_drv.h
index fbe8ac9..572c0b1 100644
--- a/drivers/staging/zram/zram_drv.h
+++ b/drivers/staging/zram/zram_drv.h
@@ -26,18 +26,6 @@
  */
 static const unsigned max_num_devices = 32;
 
-/*
- * Stored at beginning of each compressed object.
- *
- * It stores back-reference to table entry which points to this
- * object. This is required to support memory defragmentation.
- */
-struct zobj_header {
-#if 0
-	u32 table_idx;
-#endif
-};
-
 /*-- Configurable parameters */
 
 /* Default zram disk size: 25% of total RAM */
@@ -68,9 +56,6 @@ static const size_t max_zpage_size = PAGE_SIZE / 4 * 3;
 
 /* Flags for zram pages (table[page_no].flags) */
 enum zram_pageflags {
-	/* Page is stored uncompressed */
-	ZRAM_UNCOMPRESSED,
-
 	/* Page consists entirely of zeros */
 	ZRAM_ZERO,
 
@@ -81,11 +66,11 @@ enum zram_pageflags {
 
 /* Allocated for each disk page */
 struct table {
-	void *handle;
+	unsigned long handle;
 	u16 size;	/* object size (excluding header) */
 	u8 count;	/* object ref count (not yet used) */
 	u8 flags;
-} __attribute__((aligned(4)));
+} __aligned(4);
 
 struct zram_stats {
 	u64 compr_size;		/* compressed size of pages stored */
@@ -98,7 +83,7 @@ struct zram_stats {
 	u32 pages_zero;		/* no. of zero filled pages */
 	u32 pages_stored;	/* no. of pages currently stored */
 	u32 good_compress;	/* % of pages with compression ratio<=50% */
-	u32 pages_expand;	/* % of incompressible pages */
+	u32 bad_compress;	/* % of pages with compression ratio>=75% */
 };
 
 struct zram {
diff --git a/drivers/staging/zram/zram_sysfs.c b/drivers/staging/zram/zram_sysfs.c
index a7f3771..edb0ed4 100644
--- a/drivers/staging/zram/zram_sysfs.c
+++ b/drivers/staging/zram/zram_sysfs.c
@@ -186,10 +186,8 @@ static ssize_t mem_used_total_show(struct device *dev,
 	u64 val = 0;
 	struct zram *zram = dev_to_zram(dev);
 
-	if (zram->init_done) {
-		val = zs_get_total_size_bytes(zram->mem_pool) +
-			((u64)(zram->stats.pages_expand) << PAGE_SHIFT);
-	}
+	if (zram->init_done)
+		val = zs_get_total_size_bytes(zram->mem_pool);
 
 	return sprintf(buf, "%llu\n", val);
 }
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 4496737..10b0d60 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -10,6 +10,54 @@
  * Released under the terms of GNU General Public License Version 2.0
  */
 
+
+/*
+ * This allocator is designed for use with zcache and zram. Thus, the
+ * allocator is supposed to work well under low memory conditions. In
+ * particular, it never attempts higher order page allocation which is
+ * very likely to fail under memory pressure. On the other hand, if we
+ * just use single (0-order) pages, it would suffer from very high
+ * fragmentation -- any object of size PAGE_SIZE/2 or larger would occupy
+ * an entire page. This was one of the major issues with its predecessor
+ * (xvmalloc).
+ *
+ * To overcome these issues, zsmalloc allocates a bunch of 0-order pages
+ * and links them together using various 'struct page' fields. These linked
+ * pages act as a single higher-order page i.e. an object can span 0-order
+ * page boundaries. The code refers to these linked pages as a single entity
+ * called zspage.
+ *
+ * Following is how we use various fields and flags of underlying
+ * struct page(s) to form a zspage.
+ *
+ * Usage of struct page fields:
+ *	page->first_page: points to the first component (0-order) page
+ *	page->index (union with page->freelist): offset of the first object
+ *		starting in this page. For the first page, this is
+ *		always 0, so we use this field (aka freelist) to point
+ *		to the first free object in zspage.
+ *	page->lru: links together all component pages (except the first page)
+ *		of a zspage
+ *
+ *	For _first_ page only:
+ *
+ *	page->private (union with page->first_page): refers to the
+ *		component page after the first page
+ *	page->freelist: points to the first free object in zspage.
+ *		Free objects are linked together using in-place
+ *		metadata.
+ *	page->objects: maximum number of objects we can store in this
+ *		zspage (class->zspage_order * PAGE_SIZE / class->size)
+ *	page->lru: links together first pages of various zspages.
+ *		Basically forming list of zspages in a fullness group.
+ *	page->mapping: class index and fullness group of the zspage
+ *
+ * Usage of struct page flags:
+ *	PG_private: identifies the first component page
+ *	PG_private2: identifies the last component page
+ *
+ */
+
 #ifdef CONFIG_ZSMALLOC_DEBUG
 #define DEBUG
 #endif
@@ -247,13 +295,11 @@ static void *obj_location_to_handle(struct page *page, unsigned long obj_idx)
 }
 
 /* Decode <page, obj_idx> pair from the given object handle */
-static void obj_handle_to_location(void *handle, struct page **page,
+static void obj_handle_to_location(unsigned long handle, struct page **page,
 				unsigned long *obj_idx)
 {
-	unsigned long hval = (unsigned long)handle;
-
-	*page = pfn_to_page(hval >> OBJ_INDEX_BITS);
-	*obj_idx = hval & OBJ_INDEX_MASK;
+	*page = pfn_to_page(handle >> OBJ_INDEX_BITS);
+	*obj_idx = handle & OBJ_INDEX_MASK;
 }
 
 static unsigned long obj_idx_to_offset(struct page *page,
@@ -354,7 +400,7 @@ static void init_zspage(struct page *first_page, struct size_class *class)
 static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
 {
 	int i, error;
-	struct page *first_page = NULL;
+	struct page *first_page = NULL, *uninitialized_var(prev_page);
 
 	/*
 	 * Allocate individual pages and link them together as:
@@ -369,7 +415,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
 	 */
 	error = -ENOMEM;
 	for (i = 0; i < class->pages_per_zspage; i++) {
-		struct page *page, *prev_page;
+		struct page *page;
 
 		page = alloc_page(flags);
 		if (!page)
@@ -425,12 +471,6 @@ static struct page *find_get_zspage(struct size_class *class)
 }
 
 
-/*
- * If this becomes a separate module, register zs_init() with
- * module_init(), zs_exit with module_exit(), and remove zs_initialized
-*/
-static int zs_initialized;
-
 static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action,
 				void *pcpu)
 {
@@ -489,7 +529,7 @@ fail:
 
 struct zs_pool *zs_create_pool(const char *name, gfp_t flags)
 {
-	int i, error, ovhd_size;
+	int i, ovhd_size;
 	struct zs_pool *pool;
 
 	if (!name)
@@ -516,28 +556,9 @@ struct zs_pool *zs_create_pool(const char *name, gfp_t flags)
 
 	}
 
-	/*
-	 * If this becomes a separate module, register zs_init with
-	 * module_init, and remove this block
-	*/
-	if (!zs_initialized) {
-		error = zs_init();
-		if (error)
-			goto cleanup;
-		zs_initialized = 1;
-	}
-
 	pool->flags = flags;
 	pool->name = name;
 
-	error = 0; /* Success */
-
-cleanup:
-	if (error) {
-		zs_destroy_pool(pool);
-		pool = NULL;
-	}
-
 	return pool;
 }
 EXPORT_SYMBOL_GPL(zs_create_pool);
@@ -568,12 +589,12 @@ EXPORT_SYMBOL_GPL(zs_destroy_pool);
  * @size: size of block to allocate
  *
  * On success, handle to the allocated object is returned,
- * otherwise NULL.
+ * otherwise 0.
  * Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
  */
-void *zs_malloc(struct zs_pool *pool, size_t size)
+unsigned long zs_malloc(struct zs_pool *pool, size_t size)
 {
-	void *obj;
+	unsigned long obj;
 	struct link_free *link;
 	int class_idx;
 	struct size_class *class;
@@ -582,7 +603,7 @@ void *zs_malloc(struct zs_pool *pool, size_t size)
 	unsigned long m_objidx, m_offset;
 
 	if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE))
-		return NULL;
+		return 0;
 
 	class_idx = get_size_class_index(size);
 	class = &pool->size_class[class_idx];
@@ -595,14 +616,14 @@ void *zs_malloc(struct zs_pool *pool, size_t size)
 		spin_unlock(&class->lock);
 		first_page = alloc_zspage(class, pool->flags);
 		if (unlikely(!first_page))
-			return NULL;
+			return 0;
 
 		set_zspage_mapping(first_page, class->index, ZS_EMPTY);
 		spin_lock(&class->lock);
 		class->pages_allocated += class->pages_per_zspage;
 	}
 
-	obj = first_page->freelist;
+	obj = (unsigned long)first_page->freelist;
 	obj_handle_to_location(obj, &m_page, &m_objidx);
 	m_offset = obj_idx_to_offset(m_page, m_objidx, class->size);
 
@@ -621,7 +642,7 @@ void *zs_malloc(struct zs_pool *pool, size_t size)
 }
 EXPORT_SYMBOL_GPL(zs_malloc);
 
-void zs_free(struct zs_pool *pool, void *obj)
+void zs_free(struct zs_pool *pool, unsigned long obj)
 {
 	struct link_free *link;
 	struct page *first_page, *f_page;
@@ -648,7 +669,7 @@ void zs_free(struct zs_pool *pool, void *obj)
 							+ f_offset);
 	link->next = first_page->freelist;
 	kunmap_atomic(link);
-	first_page->freelist = obj;
+	first_page->freelist = (void *)obj;
 
 	first_page->inuse--;
 	fullness = fix_fullness_group(pool, first_page);
@@ -672,7 +693,7 @@ EXPORT_SYMBOL_GPL(zs_free);
  * this function. When done with the object, it must be unmapped using
  * zs_unmap_object
 */
-void *zs_map_object(struct zs_pool *pool, void *handle)
+void *zs_map_object(struct zs_pool *pool, unsigned long handle)
 {
 	struct page *page;
 	unsigned long obj_idx, off;
@@ -712,7 +733,7 @@ void *zs_map_object(struct zs_pool *pool, void *handle)
 }
 EXPORT_SYMBOL_GPL(zs_map_object);
 
-void zs_unmap_object(struct zs_pool *pool, void *handle)
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
 {
 	struct page *page;
 	unsigned long obj_idx, off;
@@ -753,3 +774,9 @@ u64 zs_get_total_size_bytes(struct zs_pool *pool)
 	return npages << PAGE_SHIFT;
 }
 EXPORT_SYMBOL_GPL(zs_get_total_size_bytes);
+
+module_init(zs_init);
+module_exit(zs_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
diff --git a/drivers/staging/zsmalloc/zsmalloc.h b/drivers/staging/zsmalloc/zsmalloc.h
index 949384e..485cbb1 100644
--- a/drivers/staging/zsmalloc/zsmalloc.h
+++ b/drivers/staging/zsmalloc/zsmalloc.h
@@ -20,11 +20,11 @@ struct zs_pool;
 struct zs_pool *zs_create_pool(const char *name, gfp_t flags);
 void zs_destroy_pool(struct zs_pool *pool);
 
-void *zs_malloc(struct zs_pool *pool, size_t size);
-void zs_free(struct zs_pool *pool, void *obj);
+unsigned long zs_malloc(struct zs_pool *pool, size_t size);
+void zs_free(struct zs_pool *pool, unsigned long obj);
 
-void *zs_map_object(struct zs_pool *pool, void *handle);
-void zs_unmap_object(struct zs_pool *pool, void *handle);
+void *zs_map_object(struct zs_pool *pool, unsigned long handle);
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle);
 
 u64 zs_get_total_size_bytes(struct zs_pool *pool);
 
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
index 61648d8..9fdcb56 100644
--- a/drivers/target/Makefile
+++ b/drivers/target/Makefile
@@ -9,7 +9,8 @@ target_core_mod-y		:= target_core_configfs.o \
 				   target_core_tmr.o \
 				   target_core_tpg.o \
 				   target_core_transport.o \
-				   target_core_cdb.o \
+				   target_core_sbc.o \
+				   target_core_spc.o \
 				   target_core_ua.o \
 				   target_core_rd.o \
 				   target_core_stat.o
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 69dc8e3..a7b25e7 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -47,28 +47,6 @@ struct lio_target_configfs_attribute {
 	ssize_t (*store)(void *, const char *, size_t);
 };
 
-struct iscsi_portal_group *lio_get_tpg_from_tpg_item(
-	struct config_item *item,
-	struct iscsi_tiqn **tiqn_out)
-{
-	struct se_portal_group *se_tpg = container_of(to_config_group(item),
-					struct se_portal_group, tpg_group);
-	struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
-	int ret;
-
-	if (!tpg) {
-		pr_err("Unable to locate struct iscsi_portal_group "
-			"pointer\n");
-		return NULL;
-	}
-	ret = iscsit_get_tpg(tpg);
-	if (ret < 0)
-		return NULL;
-
-	*tiqn_out = tpg->tpg_tiqn;
-	return tpg;
-}
-
 /* Start items for lio_target_portal_cit */
 
 static ssize_t lio_target_np_show_sctp(
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
index 1c70144..63a8ed2 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/drivers/target/iscsi/iscsi_target_core.h
@@ -481,6 +481,7 @@ struct iscsi_tmr_req {
 	bool			task_reassign:1;
 	u32			ref_cmd_sn;
 	u32			exp_data_sn;
+	struct iscsi_cmd	*ref_cmd;
 	struct iscsi_conn_recovery *conn_recovery;
 	struct se_tmr_req	*se_tmr_req;
 };
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index f4e640b..1f75529 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -19,6 +19,7 @@
  ******************************************************************************/
 
 #include <asm/unaligned.h>
+#include <scsi/scsi_device.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
@@ -61,7 +62,7 @@ u8 iscsit_tmr_abort_task(
 	}
 
 	se_tmr->ref_task_tag		= hdr->rtt;
-	se_tmr->ref_cmd			= &ref_cmd->se_cmd;
+	tmr_req->ref_cmd		= ref_cmd;
 	tmr_req->ref_cmd_sn		= hdr->refcmdsn;
 	tmr_req->exp_data_sn		= hdr->exp_datasn;
 
@@ -121,7 +122,7 @@ u8 iscsit_tmr_task_reassign(
 	struct iscsi_tmr_req *tmr_req = cmd->tmr_req;
 	struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req;
 	struct iscsi_tm *hdr = (struct iscsi_tm *) buf;
-	int ret;
+	int ret, ref_lun;
 
 	pr_debug("Got TASK_REASSIGN TMR ITT: 0x%08x,"
 		" RefTaskTag: 0x%08x, ExpDataSN: 0x%08x, CID: %hu\n",
@@ -155,9 +156,16 @@ u8 iscsit_tmr_task_reassign(
 		return ISCSI_TMF_RSP_REJECTED;
 	}
 
+	ref_lun = scsilun_to_int(&hdr->lun);
+	if (ref_lun != ref_cmd->se_cmd.orig_fe_lun) {
+		pr_err("Unable to perform connection recovery for"
+			" differing ref_lun: %d ref_cmd orig_fe_lun: %u\n",
+			ref_lun, ref_cmd->se_cmd.orig_fe_lun);
+		return ISCSI_TMF_RSP_REJECTED;
+	}
+
 	se_tmr->ref_task_tag		= hdr->rtt;
-	se_tmr->ref_cmd			= &ref_cmd->se_cmd;
-	se_tmr->ref_task_lun		= get_unaligned_le64(&hdr->lun);
+	tmr_req->ref_cmd		= ref_cmd;
 	tmr_req->ref_cmd_sn		= hdr->refcmdsn;
 	tmr_req->exp_data_sn		= hdr->exp_datasn;
 	tmr_req->conn_recovery		= cr;
@@ -191,9 +199,7 @@ static int iscsit_task_reassign_complete_nop_out(
 	struct iscsi_tmr_req *tmr_req,
 	struct iscsi_conn *conn)
 {
-	struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
-	struct se_cmd *se_cmd = se_tmr->ref_cmd;
-	struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+	struct iscsi_cmd *cmd = tmr_req->ref_cmd;
 	struct iscsi_conn_recovery *cr;
 
 	if (!cmd->cr) {
@@ -360,9 +366,7 @@ static int iscsit_task_reassign_complete_scsi_cmnd(
 	struct iscsi_tmr_req *tmr_req,
 	struct iscsi_conn *conn)
 {
-	struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
-	struct se_cmd *se_cmd = se_tmr->ref_cmd;
-	struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+	struct iscsi_cmd *cmd = tmr_req->ref_cmd;
 	struct iscsi_conn_recovery *cr;
 
 	if (!cmd->cr) {
@@ -385,7 +389,7 @@ static int iscsit_task_reassign_complete_scsi_cmnd(
 	list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
 	spin_unlock_bh(&conn->cmd_lock);
 
-	if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+	if (cmd->se_cmd.se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
 		cmd->i_state = ISTATE_SEND_STATUS;
 		iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
 		return 0;
@@ -411,17 +415,14 @@ static int iscsit_task_reassign_complete(
 	struct iscsi_tmr_req *tmr_req,
 	struct iscsi_conn *conn)
 {
-	struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
-	struct se_cmd *se_cmd;
 	struct iscsi_cmd *cmd;
 	int ret = 0;
 
-	if (!se_tmr->ref_cmd) {
+	if (!tmr_req->ref_cmd) {
 		pr_err("TMR Request is missing a RefCmd struct iscsi_cmd.\n");
 		return -1;
 	}
-	se_cmd = se_tmr->ref_cmd;
-	cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+	cmd = tmr_req->ref_cmd;
 
 	cmd->conn = conn;
 
@@ -547,9 +548,7 @@ int iscsit_task_reassign_prepare_write(
 	struct iscsi_tmr_req *tmr_req,
 	struct iscsi_conn *conn)
 {
-	struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
-	struct se_cmd *se_cmd = se_tmr->ref_cmd;
-	struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+	struct iscsi_cmd *cmd = tmr_req->ref_cmd;
 	struct iscsi_pdu *pdu = NULL;
 	struct iscsi_r2t *r2t = NULL, *r2t_tmp;
 	int first_incomplete_r2t = 1, i = 0;
@@ -782,14 +781,12 @@ int iscsit_check_task_reassign_expdatasn(
 	struct iscsi_tmr_req *tmr_req,
 	struct iscsi_conn *conn)
 {
-	struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
-	struct se_cmd *se_cmd = se_tmr->ref_cmd;
-	struct iscsi_cmd *ref_cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+	struct iscsi_cmd *ref_cmd = tmr_req->ref_cmd;
 
 	if (ref_cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD)
 		return 0;
 
-	if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION)
+	if (ref_cmd->se_cmd.se_cmd_flags & SCF_SENT_CHECK_CONDITION)
 		return 0;
 
 	if (ref_cmd->data_direction == DMA_NONE)
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 38dfac2..f65dc9d 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -211,12 +211,11 @@ static void tcm_loop_submission_work(struct work_struct *work)
 	/*
 	 * Because some userspace code via scsi-generic do not memset their
 	 * associated read buffers, go ahead and do that here for type
-	 * SCF_SCSI_CONTROL_SG_IO_CDB.  Also note that this is currently
-	 * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
-	 * by target core in target_setup_cmd_from_cdb() ->
-	 * transport_generic_cmd_sequencer().
+	 * non-data CDBs.  Also note that this is currently guaranteed to be a
+	 * single SGL for this case by target core in
+	 * target_setup_cmd_from_cdb() -> transport_generic_cmd_sequencer().
 	 */
-	if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
+	if (!(se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) &&
 	    se_cmd->data_direction == DMA_FROM_DEVICE) {
 		struct scatterlist *sg = scsi_sglist(sc);
 		unsigned char *buf = kmap(sg_page(sg)) + sg->offset;
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c
deleted file mode 100644
index 9888693..0000000
--- a/drivers/target/target_core_cdb.c
+++ /dev/null
@@ -1,1130 +0,0 @@
-/*
- * CDB emulation for non-READ/WRITE commands.
- *
- * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
- * Copyright (c) 2005, 2006, 2007 SBE, Inc.
- * Copyright (c) 2007-2010 Rising Tide Systems
- * Copyright (c) 2008-2010 Linux-iSCSI.org
- *
- * Nicholas A. Bellinger <nab@kernel.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/unaligned.h>
-#include <scsi/scsi.h>
-
-#include <target/target_core_base.h>
-#include <target/target_core_backend.h>
-#include <target/target_core_fabric.h>
-
-#include "target_core_internal.h"
-#include "target_core_ua.h"
-
-static void
-target_fill_alua_data(struct se_port *port, unsigned char *buf)
-{
-	struct t10_alua_tg_pt_gp *tg_pt_gp;
-	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
-
-	/*
-	 * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS.
-	 */
-	buf[5]	= 0x80;
-
-	/*
-	 * Set TPGS field for explict and/or implict ALUA access type
-	 * and opteration.
-	 *
-	 * See spc4r17 section 6.4.2 Table 135
-	 */
-	if (!port)
-		return;
-	tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
-	if (!tg_pt_gp_mem)
-		return;
-
-	spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-	tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
-	if (tg_pt_gp)
-		buf[5] |= tg_pt_gp->tg_pt_gp_alua_access_type;
-	spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-}
-
-static int
-target_emulate_inquiry_std(struct se_cmd *cmd, char *buf)
-{
-	struct se_lun *lun = cmd->se_lun;
-	struct se_device *dev = cmd->se_dev;
-
-	/* Set RMB (removable media) for tape devices */
-	if (dev->transport->get_device_type(dev) == TYPE_TAPE)
-		buf[1] = 0x80;
-
-	buf[2] = dev->transport->get_device_rev(dev);
-
-	/*
-	 * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2
-	 *
-	 * SPC4 says:
-	 *   A RESPONSE DATA FORMAT field set to 2h indicates that the
-	 *   standard INQUIRY data is in the format defined in this
-	 *   standard. Response data format values less than 2h are
-	 *   obsolete. Response data format values greater than 2h are
-	 *   reserved.
-	 */
-	buf[3] = 2;
-
-	/*
-	 * Enable SCCS and TPGS fields for Emulated ALUA
-	 */
-	if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED)
-		target_fill_alua_data(lun->lun_sep, buf);
-
-	buf[7] = 0x2; /* CmdQue=1 */
-
-	snprintf(&buf[8], 8, "LIO-ORG");
-	snprintf(&buf[16], 16, "%s", dev->se_sub_dev->t10_wwn.model);
-	snprintf(&buf[32], 4, "%s", dev->se_sub_dev->t10_wwn.revision);
-	buf[4] = 31; /* Set additional length to 31 */
-
-	return 0;
-}
-
-/* unit serial number */
-static int
-target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
-{
-	struct se_device *dev = cmd->se_dev;
-	u16 len = 0;
-
-	if (dev->se_sub_dev->su_dev_flags &
-			SDF_EMULATED_VPD_UNIT_SERIAL) {
-		u32 unit_serial_len;
-
-		unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial);
-		unit_serial_len++; /* For NULL Terminator */
-
-		len += sprintf(&buf[4], "%s",
-			dev->se_sub_dev->t10_wwn.unit_serial);
-		len++; /* Extra Byte for NULL Terminator */
-		buf[3] = len;
-	}
-	return 0;
-}
-
-static void
-target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf)
-{
-	unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0];
-	int cnt;
-	bool next = true;
-
-	/*
-	 * Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on
-	 * byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field
-	 * format, followed by 64 bits of VENDOR SPECIFIC IDENTIFIER EXTENSION
-	 * to complete the payload.  These are based from VPD=0x80 PRODUCT SERIAL
-	 * NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure
-	 * per device uniqeness.
-	 */
-	for (cnt = 0; *p && cnt < 13; p++) {
-		int val = hex_to_bin(*p);
-
-		if (val < 0)
-			continue;
-
-		if (next) {
-			next = false;
-			buf[cnt++] |= val;
-		} else {
-			next = true;
-			buf[cnt] = val << 4;
-		}
-	}
-}
-
-/*
- * Device identification VPD, for a complete list of
- * DESIGNATOR TYPEs see spc4r17 Table 459.
- */
-static int
-target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
-{
-	struct se_device *dev = cmd->se_dev;
-	struct se_lun *lun = cmd->se_lun;
-	struct se_port *port = NULL;
-	struct se_portal_group *tpg = NULL;
-	struct t10_alua_lu_gp_member *lu_gp_mem;
-	struct t10_alua_tg_pt_gp *tg_pt_gp;
-	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
-	unsigned char *prod = &dev->se_sub_dev->t10_wwn.model[0];
-	u32 prod_len;
-	u32 unit_serial_len, off = 0;
-	u16 len = 0, id_len;
-
-	off = 4;
-
-	/*
-	 * NAA IEEE Registered Extended Assigned designator format, see
-	 * spc4r17 section 7.7.3.6.5
-	 *
-	 * We depend upon a target_core_mod/ConfigFS provided
-	 * /sys/kernel/config/target/core/$HBA/$DEV/wwn/vpd_unit_serial
-	 * value in order to return the NAA id.
-	 */
-	if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL))
-		goto check_t10_vend_desc;
-
-	/* CODE SET == Binary */
-	buf[off++] = 0x1;
-
-	/* Set ASSOCIATION == addressed logical unit: 0)b */
-	buf[off] = 0x00;
-
-	/* Identifier/Designator type == NAA identifier */
-	buf[off++] |= 0x3;
-	off++;
-
-	/* Identifier/Designator length */
-	buf[off++] = 0x10;
-
-	/*
-	 * Start NAA IEEE Registered Extended Identifier/Designator
-	 */
-	buf[off++] = (0x6 << 4);
-
-	/*
-	 * Use OpenFabrics IEEE Company ID: 00 14 05
-	 */
-	buf[off++] = 0x01;
-	buf[off++] = 0x40;
-	buf[off] = (0x5 << 4);
-
-	/*
-	 * Return ConfigFS Unit Serial Number information for
-	 * VENDOR_SPECIFIC_IDENTIFIER and
-	 * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION
-	 */
-	target_parse_naa_6h_vendor_specific(dev, &buf[off]);
-
-	len = 20;
-	off = (len + 4);
-
-check_t10_vend_desc:
-	/*
-	 * T10 Vendor Identifier Page, see spc4r17 section 7.7.3.4
-	 */
-	id_len = 8; /* For Vendor field */
-	prod_len = 4; /* For VPD Header */
-	prod_len += 8; /* For Vendor field */
-	prod_len += strlen(prod);
-	prod_len++; /* For : */
-
-	if (dev->se_sub_dev->su_dev_flags &
-			SDF_EMULATED_VPD_UNIT_SERIAL) {
-		unit_serial_len =
-			strlen(&dev->se_sub_dev->t10_wwn.unit_serial[0]);
-		unit_serial_len++; /* For NULL Terminator */
-
-		id_len += sprintf(&buf[off+12], "%s:%s", prod,
-				&dev->se_sub_dev->t10_wwn.unit_serial[0]);
-	}
-	buf[off] = 0x2; /* ASCII */
-	buf[off+1] = 0x1; /* T10 Vendor ID */
-	buf[off+2] = 0x0;
-	memcpy(&buf[off+4], "LIO-ORG", 8);
-	/* Extra Byte for NULL Terminator */
-	id_len++;
-	/* Identifier Length */
-	buf[off+3] = id_len;
-	/* Header size for Designation descriptor */
-	len += (id_len + 4);
-	off += (id_len + 4);
-	/*
-	 * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD
-	 */
-	port = lun->lun_sep;
-	if (port) {
-		struct t10_alua_lu_gp *lu_gp;
-		u32 padding, scsi_name_len;
-		u16 lu_gp_id = 0;
-		u16 tg_pt_gp_id = 0;
-		u16 tpgt;
-
-		tpg = port->sep_tpg;
-		/*
-		 * Relative target port identifer, see spc4r17
-		 * section 7.7.3.7
-		 *
-		 * Get the PROTOCOL IDENTIFIER as defined by spc4r17
-		 * section 7.5.1 Table 362
-		 */
-		buf[off] =
-			(tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
-		buf[off++] |= 0x1; /* CODE SET == Binary */
-		buf[off] = 0x80; /* Set PIV=1 */
-		/* Set ASSOCIATION == target port: 01b */
-		buf[off] |= 0x10;
-		/* DESIGNATOR TYPE == Relative target port identifer */
-		buf[off++] |= 0x4;
-		off++; /* Skip over Reserved */
-		buf[off++] = 4; /* DESIGNATOR LENGTH */
-		/* Skip over Obsolete field in RTPI payload
-		 * in Table 472 */
-		off += 2;
-		buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
-		buf[off++] = (port->sep_rtpi & 0xff);
-		len += 8; /* Header size + Designation descriptor */
-		/*
-		 * Target port group identifier, see spc4r17
-		 * section 7.7.3.8
-		 *
-		 * Get the PROTOCOL IDENTIFIER as defined by spc4r17
-		 * section 7.5.1 Table 362
-		 */
-		if (dev->se_sub_dev->t10_alua.alua_type !=
-				SPC3_ALUA_EMULATED)
-			goto check_scsi_name;
-
-		tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
-		if (!tg_pt_gp_mem)
-			goto check_lu_gp;
-
-		spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-		tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
-		if (!tg_pt_gp) {
-			spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-			goto check_lu_gp;
-		}
-		tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id;
-		spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-
-		buf[off] =
-			(tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
-		buf[off++] |= 0x1; /* CODE SET == Binary */
-		buf[off] = 0x80; /* Set PIV=1 */
-		/* Set ASSOCIATION == target port: 01b */
-		buf[off] |= 0x10;
-		/* DESIGNATOR TYPE == Target port group identifier */
-		buf[off++] |= 0x5;
-		off++; /* Skip over Reserved */
-		buf[off++] = 4; /* DESIGNATOR LENGTH */
-		off += 2; /* Skip over Reserved Field */
-		buf[off++] = ((tg_pt_gp_id >> 8) & 0xff);
-		buf[off++] = (tg_pt_gp_id & 0xff);
-		len += 8; /* Header size + Designation descriptor */
-		/*
-		 * Logical Unit Group identifier, see spc4r17
-		 * section 7.7.3.8
-		 */
-check_lu_gp:
-		lu_gp_mem = dev->dev_alua_lu_gp_mem;
-		if (!lu_gp_mem)
-			goto check_scsi_name;
-
-		spin_lock(&lu_gp_mem->lu_gp_mem_lock);
-		lu_gp = lu_gp_mem->lu_gp;
-		if (!lu_gp) {
-			spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
-			goto check_scsi_name;
-		}
-		lu_gp_id = lu_gp->lu_gp_id;
-		spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
-
-		buf[off++] |= 0x1; /* CODE SET == Binary */
-		/* DESIGNATOR TYPE == Logical Unit Group identifier */
-		buf[off++] |= 0x6;
-		off++; /* Skip over Reserved */
-		buf[off++] = 4; /* DESIGNATOR LENGTH */
-		off += 2; /* Skip over Reserved Field */
-		buf[off++] = ((lu_gp_id >> 8) & 0xff);
-		buf[off++] = (lu_gp_id & 0xff);
-		len += 8; /* Header size + Designation descriptor */
-		/*
-		 * SCSI name string designator, see spc4r17
-		 * section 7.7.3.11
-		 *
-		 * Get the PROTOCOL IDENTIFIER as defined by spc4r17
-		 * section 7.5.1 Table 362
-		 */
-check_scsi_name:
-		scsi_name_len = strlen(tpg->se_tpg_tfo->tpg_get_wwn(tpg));
-		/* UTF-8 ",t,0x<16-bit TPGT>" + NULL Terminator */
-		scsi_name_len += 10;
-		/* Check for 4-byte padding */
-		padding = ((-scsi_name_len) & 3);
-		if (padding != 0)
-			scsi_name_len += padding;
-		/* Header size + Designation descriptor */
-		scsi_name_len += 4;
-
-		buf[off] =
-			(tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
-		buf[off++] |= 0x3; /* CODE SET == UTF-8 */
-		buf[off] = 0x80; /* Set PIV=1 */
-		/* Set ASSOCIATION == target port: 01b */
-		buf[off] |= 0x10;
-		/* DESIGNATOR TYPE == SCSI name string */
-		buf[off++] |= 0x8;
-		off += 2; /* Skip over Reserved and length */
-		/*
-		 * SCSI name string identifer containing, $FABRIC_MOD
-		 * dependent information.  For LIO-Target and iSCSI
-		 * Target Port, this means "<iSCSI name>,t,0x<TPGT> in
-		 * UTF-8 encoding.
-		 */
-		tpgt = tpg->se_tpg_tfo->tpg_get_tag(tpg);
-		scsi_name_len = sprintf(&buf[off], "%s,t,0x%04x",
-					tpg->se_tpg_tfo->tpg_get_wwn(tpg), tpgt);
-		scsi_name_len += 1 /* Include  NULL terminator */;
-		/*
-		 * The null-terminated, null-padded (see 4.4.2) SCSI
-		 * NAME STRING field contains a UTF-8 format string.
-		 * The number of bytes in the SCSI NAME STRING field
-		 * (i.e., the value in the DESIGNATOR LENGTH field)
-		 * shall be no larger than 256 and shall be a multiple
-		 * of four.
-		 */
-		if (padding)
-			scsi_name_len += padding;
-
-		buf[off-1] = scsi_name_len;
-		off += scsi_name_len;
-		/* Header size + Designation descriptor */
-		len += (scsi_name_len + 4);
-	}
-	buf[2] = ((len >> 8) & 0xff);
-	buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */
-	return 0;
-}
-
-/* Extended INQUIRY Data VPD Page */
-static int
-target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
-{
-	buf[3] = 0x3c;
-	/* Set HEADSUP, ORDSUP, SIMPSUP */
-	buf[5] = 0x07;
-
-	/* If WriteCache emulation is enabled, set V_SUP */
-	if (cmd->se_dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0)
-		buf[6] = 0x01;
-	return 0;
-}
-
-/* Block Limits VPD page */
-static int
-target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
-{
-	struct se_device *dev = cmd->se_dev;
-	u32 max_sectors;
-	int have_tp = 0;
-
-	/*
-	 * Following sbc3r22 section 6.5.3 Block Limits VPD page, when
-	 * emulate_tpu=1 or emulate_tpws=1 we will be expect a
-	 * different page length for Thin Provisioning.
-	 */
-	if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
-		have_tp = 1;
-
-	buf[0] = dev->transport->get_device_type(dev);
-	buf[3] = have_tp ? 0x3c : 0x10;
-
-	/* Set WSNZ to 1 */
-	buf[4] = 0x01;
-
-	/*
-	 * Set OPTIMAL TRANSFER LENGTH GRANULARITY
-	 */
-	put_unaligned_be16(1, &buf[6]);
-
-	/*
-	 * Set MAXIMUM TRANSFER LENGTH
-	 */
-	max_sectors = min(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors,
-			  dev->se_sub_dev->se_dev_attrib.hw_max_sectors);
-	put_unaligned_be32(max_sectors, &buf[8]);
-
-	/*
-	 * Set OPTIMAL TRANSFER LENGTH
-	 */
-	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.optimal_sectors, &buf[12]);
-
-	/*
-	 * Exit now if we don't support TP.
-	 */
-	if (!have_tp)
-		return 0;
-
-	/*
-	 * Set MAXIMUM UNMAP LBA COUNT
-	 */
-	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count, &buf[20]);
-
-	/*
-	 * Set MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT
-	 */
-	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count,
-			   &buf[24]);
-
-	/*
-	 * Set OPTIMAL UNMAP GRANULARITY
-	 */
-	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity, &buf[28]);
-
-	/*
-	 * UNMAP GRANULARITY ALIGNMENT
-	 */
-	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment,
-			   &buf[32]);
-	if (dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment != 0)
-		buf[32] |= 0x80; /* Set the UGAVALID bit */
-
-	return 0;
-}
-
-/* Block Device Characteristics VPD page */
-static int
-target_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf)
-{
-	struct se_device *dev = cmd->se_dev;
-
-	buf[0] = dev->transport->get_device_type(dev);
-	buf[3] = 0x3c;
-	buf[5] = dev->se_sub_dev->se_dev_attrib.is_nonrot ? 1 : 0;
-
-	return 0;
-}
-
-/* Thin Provisioning VPD */
-static int
-target_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
-{
-	struct se_device *dev = cmd->se_dev;
-
-	/*
-	 * From sbc3r22 section 6.5.4 Thin Provisioning VPD page:
-	 *
-	 * The PAGE LENGTH field is defined in SPC-4. If the DP bit is set to
-	 * zero, then the page length shall be set to 0004h.  If the DP bit
-	 * is set to one, then the page length shall be set to the value
-	 * defined in table 162.
-	 */
-	buf[0] = dev->transport->get_device_type(dev);
-
-	/*
-	 * Set Hardcoded length mentioned above for DP=0
-	 */
-	put_unaligned_be16(0x0004, &buf[2]);
-
-	/*
-	 * The THRESHOLD EXPONENT field indicates the threshold set size in
-	 * LBAs as a power of 2 (i.e., the threshold set size is equal to
-	 * 2(threshold exponent)).
-	 *
-	 * Note that this is currently set to 0x00 as mkp says it will be
-	 * changing again.  We can enable this once it has settled in T10
-	 * and is actually used by Linux/SCSI ML code.
-	 */
-	buf[4] = 0x00;
-
-	/*
-	 * A TPU bit set to one indicates that the device server supports
-	 * the UNMAP command (see 5.25). A TPU bit set to zero indicates
-	 * that the device server does not support the UNMAP command.
-	 */
-	if (dev->se_sub_dev->se_dev_attrib.emulate_tpu != 0)
-		buf[5] = 0x80;
-
-	/*
-	 * A TPWS bit set to one indicates that the device server supports
-	 * the use of the WRITE SAME (16) command (see 5.42) to unmap LBAs.
-	 * A TPWS bit set to zero indicates that the device server does not
-	 * support the use of the WRITE SAME (16) command to unmap LBAs.
-	 */
-	if (dev->se_sub_dev->se_dev_attrib.emulate_tpws != 0)
-		buf[5] |= 0x40;
-
-	return 0;
-}
-
-static int
-target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf);
-
-static struct {
-	uint8_t		page;
-	int		(*emulate)(struct se_cmd *, unsigned char *);
-} evpd_handlers[] = {
-	{ .page = 0x00, .emulate = target_emulate_evpd_00 },
-	{ .page = 0x80, .emulate = target_emulate_evpd_80 },
-	{ .page = 0x83, .emulate = target_emulate_evpd_83 },
-	{ .page = 0x86, .emulate = target_emulate_evpd_86 },
-	{ .page = 0xb0, .emulate = target_emulate_evpd_b0 },
-	{ .page = 0xb1, .emulate = target_emulate_evpd_b1 },
-	{ .page = 0xb2, .emulate = target_emulate_evpd_b2 },
-};
-
-/* supported vital product data pages */
-static int
-target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
-{
-	int p;
-
-	/*
-	 * Only report the INQUIRY EVPD=1 pages after a valid NAA
-	 * Registered Extended LUN WWN has been set via ConfigFS
-	 * during device creation/restart.
-	 */
-	if (cmd->se_dev->se_sub_dev->su_dev_flags &
-			SDF_EMULATED_VPD_UNIT_SERIAL) {
-		buf[3] = ARRAY_SIZE(evpd_handlers);
-		for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p)
-			buf[p + 4] = evpd_handlers[p].page;
-	}
-
-	return 0;
-}
-
-int target_emulate_inquiry(struct se_cmd *cmd)
-{
-	struct se_device *dev = cmd->se_dev;
-	struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg;
-	unsigned char *buf, *map_buf;
-	unsigned char *cdb = cmd->t_task_cdb;
-	int p, ret;
-
-	map_buf = transport_kmap_data_sg(cmd);
-	/*
-	 * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we
-	 * know we actually allocated a full page.  Otherwise, if the
-	 * data buffer is too small, allocate a temporary buffer so we
-	 * don't have to worry about overruns in all our INQUIRY
-	 * emulation handling.
-	 */
-	if (cmd->data_length < SE_INQUIRY_BUF &&
-	    (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) {
-		buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
-		if (!buf) {
-			transport_kunmap_data_sg(cmd);
-			cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-			return -ENOMEM;
-		}
-	} else {
-		buf = map_buf;
-	}
-
-	if (dev == tpg->tpg_virt_lun0.lun_se_dev)
-		buf[0] = 0x3f; /* Not connected */
-	else
-		buf[0] = dev->transport->get_device_type(dev);
-
-	if (!(cdb[1] & 0x1)) {
-		if (cdb[2]) {
-			pr_err("INQUIRY with EVPD==0 but PAGE CODE=%02x\n",
-			       cdb[2]);
-			cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
-			ret = -EINVAL;
-			goto out;
-		}
-
-		ret = target_emulate_inquiry_std(cmd, buf);
-		goto out;
-	}
-
-	for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) {
-		if (cdb[2] == evpd_handlers[p].page) {
-			buf[1] = cdb[2];
-			ret = evpd_handlers[p].emulate(cmd, buf);
-			goto out;
-		}
-	}
-
-	pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]);
-	cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
-	ret = -EINVAL;
-
-out:
-	if (buf != map_buf) {
-		memcpy(map_buf, buf, cmd->data_length);
-		kfree(buf);
-	}
-	transport_kunmap_data_sg(cmd);
-
-	if (!ret)
-		target_complete_cmd(cmd, GOOD);
-	return ret;
-}
-
-int target_emulate_readcapacity(struct se_cmd *cmd)
-{
-	struct se_device *dev = cmd->se_dev;
-	unsigned char *buf;
-	unsigned long long blocks_long = dev->transport->get_blocks(dev);
-	u32 blocks;
-
-	if (blocks_long >= 0x00000000ffffffff)
-		blocks = 0xffffffff;
-	else
-		blocks = (u32)blocks_long;
-
-	buf = transport_kmap_data_sg(cmd);
-
-	buf[0] = (blocks >> 24) & 0xff;
-	buf[1] = (blocks >> 16) & 0xff;
-	buf[2] = (blocks >> 8) & 0xff;
-	buf[3] = blocks & 0xff;
-	buf[4] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
-	buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
-	buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
-	buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
-
-	transport_kunmap_data_sg(cmd);
-
-	target_complete_cmd(cmd, GOOD);
-	return 0;
-}
-
-int target_emulate_readcapacity_16(struct se_cmd *cmd)
-{
-	struct se_device *dev = cmd->se_dev;
-	unsigned char *buf;
-	unsigned long long blocks = dev->transport->get_blocks(dev);
-
-	buf = transport_kmap_data_sg(cmd);
-
-	buf[0] = (blocks >> 56) & 0xff;
-	buf[1] = (blocks >> 48) & 0xff;
-	buf[2] = (blocks >> 40) & 0xff;
-	buf[3] = (blocks >> 32) & 0xff;
-	buf[4] = (blocks >> 24) & 0xff;
-	buf[5] = (blocks >> 16) & 0xff;
-	buf[6] = (blocks >> 8) & 0xff;
-	buf[7] = blocks & 0xff;
-	buf[8] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
-	buf[9] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
-	buf[10] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
-	buf[11] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
-	/*
-	 * Set Thin Provisioning Enable bit following sbc3r22 in section
-	 * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled.
-	 */
-	if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
-		buf[14] = 0x80;
-
-	transport_kunmap_data_sg(cmd);
-
-	target_complete_cmd(cmd, GOOD);
-	return 0;
-}
-
-static int
-target_modesense_rwrecovery(unsigned char *p)
-{
-	p[0] = 0x01;
-	p[1] = 0x0a;
-
-	return 12;
-}
-
-static int
-target_modesense_control(struct se_device *dev, unsigned char *p)
-{
-	p[0] = 0x0a;
-	p[1] = 0x0a;
-	p[2] = 2;
-	/*
-	 * From spc4r23, 7.4.7 Control mode page
-	 *
-	 * The QUEUE ALGORITHM MODIFIER field (see table 368) specifies
-	 * restrictions on the algorithm used for reordering commands
-	 * having the SIMPLE task attribute (see SAM-4).
-	 *
-	 *                    Table 368 -- QUEUE ALGORITHM MODIFIER field
-	 *                         Code      Description
-	 *                          0h       Restricted reordering
-	 *                          1h       Unrestricted reordering allowed
-	 *                          2h to 7h    Reserved
-	 *                          8h to Fh    Vendor specific
-	 *
-	 * A value of zero in the QUEUE ALGORITHM MODIFIER field specifies that
-	 * the device server shall order the processing sequence of commands
-	 * having the SIMPLE task attribute such that data integrity is maintained
-	 * for that I_T nexus (i.e., if the transmission of new SCSI transport protocol
-	 * requests is halted at any time, the final value of all data observable
-	 * on the medium shall be the same as if all the commands had been processed
-	 * with the ORDERED task attribute).
-	 *
-	 * A value of one in the QUEUE ALGORITHM MODIFIER field specifies that the
-	 * device server may reorder the processing sequence of commands having the
-	 * SIMPLE task attribute in any manner. Any data integrity exposures related to
-	 * command sequence order shall be explicitly handled by the application client
-	 * through the selection of appropriate ommands and task attributes.
-	 */
-	p[3] = (dev->se_sub_dev->se_dev_attrib.emulate_rest_reord == 1) ? 0x00 : 0x10;
-	/*
-	 * From spc4r17, section 7.4.6 Control mode Page
-	 *
-	 * Unit Attention interlocks control (UN_INTLCK_CTRL) to code 00b
-	 *
-	 * 00b: The logical unit shall clear any unit attention condition
-	 * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
-	 * status and shall not establish a unit attention condition when a com-
-	 * mand is completed with BUSY, TASK SET FULL, or RESERVATION CONFLICT
-	 * status.
-	 *
-	 * 10b: The logical unit shall not clear any unit attention condition
-	 * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
-	 * status and shall not establish a unit attention condition when
-	 * a command is completed with BUSY, TASK SET FULL, or RESERVATION
-	 * CONFLICT status.
-	 *
-	 * 11b a The logical unit shall not clear any unit attention condition
-	 * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
-	 * status and shall establish a unit attention condition for the
-	 * initiator port associated with the I_T nexus on which the BUSY,
-	 * TASK SET FULL, or RESERVATION CONFLICT status is being returned.
-	 * Depending on the status, the additional sense code shall be set to
-	 * PREVIOUS BUSY STATUS, PREVIOUS TASK SET FULL STATUS, or PREVIOUS
-	 * RESERVATION CONFLICT STATUS. Until it is cleared by a REQUEST SENSE
-	 * command, a unit attention condition shall be established only once
-	 * for a BUSY, TASK SET FULL, or RESERVATION CONFLICT status regardless
-	 * to the number of commands completed with one of those status codes.
-	 */
-	p[4] = (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 2) ? 0x30 :
-	       (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 1) ? 0x20 : 0x00;
-	/*
-	 * From spc4r17, section 7.4.6 Control mode Page
-	 *
-	 * Task Aborted Status (TAS) bit set to zero.
-	 *
-	 * A task aborted status (TAS) bit set to zero specifies that aborted
-	 * tasks shall be terminated by the device server without any response
-	 * to the application client. A TAS bit set to one specifies that tasks
-	 * aborted by the actions of an I_T nexus other than the I_T nexus on
-	 * which the command was received shall be completed with TASK ABORTED
-	 * status (see SAM-4).
-	 */
-	p[5] = (dev->se_sub_dev->se_dev_attrib.emulate_tas) ? 0x40 : 0x00;
-	p[8] = 0xff;
-	p[9] = 0xff;
-	p[11] = 30;
-
-	return 12;
-}
-
-static int
-target_modesense_caching(struct se_device *dev, unsigned char *p)
-{
-	p[0] = 0x08;
-	p[1] = 0x12;
-	if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0)
-		p[2] = 0x04; /* Write Cache Enable */
-	p[12] = 0x20; /* Disabled Read Ahead */
-
-	return 20;
-}
-
-static void
-target_modesense_write_protect(unsigned char *buf, int type)
-{
-	/*
-	 * I believe that the WP bit (bit 7) in the mode header is the same for
-	 * all device types..
-	 */
-	switch (type) {
-	case TYPE_DISK:
-	case TYPE_TAPE:
-	default:
-		buf[0] |= 0x80; /* WP bit */
-		break;
-	}
-}
-
-static void
-target_modesense_dpofua(unsigned char *buf, int type)
-{
-	switch (type) {
-	case TYPE_DISK:
-		buf[0] |= 0x10; /* DPOFUA bit */
-		break;
-	default:
-		break;
-	}
-}
-
-int target_emulate_modesense(struct se_cmd *cmd)
-{
-	struct se_device *dev = cmd->se_dev;
-	char *cdb = cmd->t_task_cdb;
-	unsigned char *rbuf;
-	int type = dev->transport->get_device_type(dev);
-	int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10);
-	int offset = ten ? 8 : 4;
-	int length = 0;
-	unsigned char buf[SE_MODE_PAGE_BUF];
-
-	memset(buf, 0, SE_MODE_PAGE_BUF);
-
-	switch (cdb[2] & 0x3f) {
-	case 0x01:
-		length = target_modesense_rwrecovery(&buf[offset]);
-		break;
-	case 0x08:
-		length = target_modesense_caching(dev, &buf[offset]);
-		break;
-	case 0x0a:
-		length = target_modesense_control(dev, &buf[offset]);
-		break;
-	case 0x3f:
-		length = target_modesense_rwrecovery(&buf[offset]);
-		length += target_modesense_caching(dev, &buf[offset+length]);
-		length += target_modesense_control(dev, &buf[offset+length]);
-		break;
-	default:
-		pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n",
-		       cdb[2] & 0x3f, cdb[3]);
-		cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE;
-		return -EINVAL;
-	}
-	offset += length;
-
-	if (ten) {
-		offset -= 2;
-		buf[0] = (offset >> 8) & 0xff;
-		buf[1] = offset & 0xff;
-
-		if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
-		    (cmd->se_deve &&
-		    (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
-			target_modesense_write_protect(&buf[3], type);
-
-		if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) &&
-		    (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0))
-			target_modesense_dpofua(&buf[3], type);
-
-		if ((offset + 2) > cmd->data_length)
-			offset = cmd->data_length;
-
-	} else {
-		offset -= 1;
-		buf[0] = offset & 0xff;
-
-		if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
-		    (cmd->se_deve &&
-		    (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
-			target_modesense_write_protect(&buf[2], type);
-
-		if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) &&
-		    (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0))
-			target_modesense_dpofua(&buf[2], type);
-
-		if ((offset + 1) > cmd->data_length)
-			offset = cmd->data_length;
-	}
-
-	rbuf = transport_kmap_data_sg(cmd);
-	memcpy(rbuf, buf, offset);
-	transport_kunmap_data_sg(cmd);
-
-	target_complete_cmd(cmd, GOOD);
-	return 0;
-}
-
-int target_emulate_request_sense(struct se_cmd *cmd)
-{
-	unsigned char *cdb = cmd->t_task_cdb;
-	unsigned char *buf;
-	u8 ua_asc = 0, ua_ascq = 0;
-	int err = 0;
-
-	if (cdb[1] & 0x01) {
-		pr_err("REQUEST_SENSE description emulation not"
-			" supported\n");
-		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
-		return -ENOSYS;
-	}
-
-	buf = transport_kmap_data_sg(cmd);
-
-	if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) {
-		/*
-		 * CURRENT ERROR, UNIT ATTENTION
-		 */
-		buf[0] = 0x70;
-		buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
-
-		if (cmd->data_length < 18) {
-			buf[7] = 0x00;
-			err = -EINVAL;
-			goto end;
-		}
-		/*
-		 * The Additional Sense Code (ASC) from the UNIT ATTENTION
-		 */
-		buf[SPC_ASC_KEY_OFFSET] = ua_asc;
-		buf[SPC_ASCQ_KEY_OFFSET] = ua_ascq;
-		buf[7] = 0x0A;
-	} else {
-		/*
-		 * CURRENT ERROR, NO SENSE
-		 */
-		buf[0] = 0x70;
-		buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE;
-
-		if (cmd->data_length < 18) {
-			buf[7] = 0x00;
-			err = -EINVAL;
-			goto end;
-		}
-		/*
-		 * NO ADDITIONAL SENSE INFORMATION
-		 */
-		buf[SPC_ASC_KEY_OFFSET] = 0x00;
-		buf[7] = 0x0A;
-	}
-
-end:
-	transport_kunmap_data_sg(cmd);
-	target_complete_cmd(cmd, GOOD);
-	return 0;
-}
-
-/*
- * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
- * Note this is not used for TCM/pSCSI passthrough
- */
-int target_emulate_unmap(struct se_cmd *cmd)
-{
-	struct se_device *dev = cmd->se_dev;
-	unsigned char *buf, *ptr = NULL;
-	unsigned char *cdb = &cmd->t_task_cdb[0];
-	sector_t lba;
-	unsigned int size = cmd->data_length, range;
-	int ret = 0, offset;
-	unsigned short dl, bd_dl;
-
-	if (!dev->transport->do_discard) {
-		pr_err("UNMAP emulation not supported for: %s\n",
-				dev->transport->name);
-		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
-		return -ENOSYS;
-	}
-
-	/* First UNMAP block descriptor starts at 8 byte offset */
-	offset = 8;
-	size -= 8;
-	dl = get_unaligned_be16(&cdb[0]);
-	bd_dl = get_unaligned_be16(&cdb[2]);
-
-	buf = transport_kmap_data_sg(cmd);
-
-	ptr = &buf[offset];
-	pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu"
-		" ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
-
-	while (size) {
-		lba = get_unaligned_be64(&ptr[0]);
-		range = get_unaligned_be32(&ptr[8]);
-		pr_debug("UNMAP: Using lba: %llu and range: %u\n",
-				 (unsigned long long)lba, range);
-
-		ret = dev->transport->do_discard(dev, lba, range);
-		if (ret < 0) {
-			pr_err("blkdev_issue_discard() failed: %d\n",
-					ret);
-			goto err;
-		}
-
-		ptr += 16;
-		size -= 16;
-	}
-
-err:
-	transport_kunmap_data_sg(cmd);
-	if (!ret)
-		target_complete_cmd(cmd, GOOD);
-	return ret;
-}
-
-/*
- * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
- * Note this is not used for TCM/pSCSI passthrough
- */
-int target_emulate_write_same(struct se_cmd *cmd)
-{
-	struct se_device *dev = cmd->se_dev;
-	sector_t range;
-	sector_t lba = cmd->t_task_lba;
-	u32 num_blocks;
-	int ret;
-
-	if (!dev->transport->do_discard) {
-		pr_err("WRITE_SAME emulation not supported"
-				" for: %s\n", dev->transport->name);
-		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
-		return -ENOSYS;
-	}
-
-	if (cmd->t_task_cdb[0] == WRITE_SAME)
-		num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]);
-	else if (cmd->t_task_cdb[0] == WRITE_SAME_16)
-		num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
-	else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */
-		num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);
-
-	/*
-	 * Use the explicit range when non zero is supplied, otherwise calculate
-	 * the remaining range based on ->get_blocks() - starting LBA.
-	 */
-	if (num_blocks != 0)
-		range = num_blocks;
-	else
-		range = (dev->transport->get_blocks(dev) - lba);
-
-	pr_debug("WRITE_SAME UNMAP: LBA: %llu Range: %llu\n",
-		 (unsigned long long)lba, (unsigned long long)range);
-
-	ret = dev->transport->do_discard(dev, lba, range);
-	if (ret < 0) {
-		pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n");
-		return ret;
-	}
-
-	target_complete_cmd(cmd, GOOD);
-	return 0;
-}
-
-int target_emulate_synchronize_cache(struct se_cmd *cmd)
-{
-	if (!cmd->se_dev->transport->do_sync_cache) {
-		pr_err("SYNCHRONIZE_CACHE emulation not supported"
-			" for: %s\n", cmd->se_dev->transport->name);
-		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
-		return -ENOSYS;
-	}
-
-	cmd->se_dev->transport->do_sync_cache(cmd);
-	return 0;
-}
-
-int target_emulate_noop(struct se_cmd *cmd)
-{
-	target_complete_cmd(cmd, GOOD);
-	return 0;
-}
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 801efa8..37c4bf3 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -122,47 +122,9 @@ static struct config_group *target_core_register_fabric(
 	const char *name)
 {
 	struct target_fabric_configfs *tf;
-	int ret;
 
 	pr_debug("Target_Core_ConfigFS: REGISTER -> group: %p name:"
 			" %s\n", group, name);
-	/*
-	 * Below are some hardcoded request_module() calls to automatically
-	 * local fabric modules when the following is called:
-	 *
-	 * mkdir -p /sys/kernel/config/target/$MODULE_NAME
-	 *
-	 * Note that this does not limit which TCM fabric module can be
-	 * registered, but simply provids auto loading logic for modules with
-	 * mkdir(2) system calls with known TCM fabric modules.
-	 */
-	if (!strncmp(name, "iscsi", 5)) {
-		/*
-		 * Automatically load the LIO Target fabric module when the
-		 * following is called:
-		 *
-		 * mkdir -p $CONFIGFS/target/iscsi
-		 */
-		ret = request_module("iscsi_target_mod");
-		if (ret < 0) {
-			pr_err("request_module() failed for"
-				" iscsi_target_mod.ko: %d\n", ret);
-			return ERR_PTR(-EINVAL);
-		}
-	} else if (!strncmp(name, "loopback", 8)) {
-		/*
-		 * Automatically load the tcm_loop fabric module when the
-		 * following is called:
-		 *
-		 * mkdir -p $CONFIGFS/target/loopback
-		 */
-		ret = request_module("tcm_loop");
-		if (ret < 0) {
-			pr_err("request_module() failed for"
-				" tcm_loop.ko: %d\n", ret);
-			return ERR_PTR(-EINVAL);
-		}
-	}
 
 	tf = target_core_get_fabric(name);
 	if (!tf) {
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index 9f99d04..9e21005 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -331,7 +331,7 @@ static int fd_do_writev(struct se_cmd *cmd, struct scatterlist *sgl,
 	return 1;
 }
 
-static void fd_emulate_sync_cache(struct se_cmd *cmd)
+static int fd_execute_sync_cache(struct se_cmd *cmd)
 {
 	struct se_device *dev = cmd->se_dev;
 	struct fd_dev *fd_dev = dev->dev_ptr;
@@ -365,7 +365,7 @@ static void fd_emulate_sync_cache(struct se_cmd *cmd)
 		pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret);
 
 	if (immed)
-		return;
+		return 0;
 
 	if (ret) {
 		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -373,11 +373,15 @@ static void fd_emulate_sync_cache(struct se_cmd *cmd)
 	} else {
 		target_complete_cmd(cmd, SAM_STAT_GOOD);
 	}
+
+	return 0;
 }
 
-static int fd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
-		u32 sgl_nents, enum dma_data_direction data_direction)
+static int fd_execute_rw(struct se_cmd *cmd)
 {
+	struct scatterlist *sgl = cmd->t_data_sg;
+	u32 sgl_nents = cmd->t_data_nents;
+	enum dma_data_direction data_direction = cmd->data_direction;
 	struct se_device *dev = cmd->se_dev;
 	int ret = 0;
 
@@ -550,6 +554,16 @@ static sector_t fd_get_blocks(struct se_device *dev)
 	return div_u64(dev_size, dev->se_sub_dev->se_dev_attrib.block_size);
 }
 
+static struct spc_ops fd_spc_ops = {
+	.execute_rw		= fd_execute_rw,
+	.execute_sync_cache	= fd_execute_sync_cache,
+};
+
+static int fd_parse_cdb(struct se_cmd *cmd)
+{
+	return sbc_parse_cdb(cmd, &fd_spc_ops);
+}
+
 static struct se_subsystem_api fileio_template = {
 	.name			= "fileio",
 	.owner			= THIS_MODULE,
@@ -561,8 +575,7 @@ static struct se_subsystem_api fileio_template = {
 	.allocate_virtdevice	= fd_allocate_virtdevice,
 	.create_virtdevice	= fd_create_virtdevice,
 	.free_device		= fd_free_device,
-	.execute_cmd		= fd_execute_cmd,
-	.do_sync_cache		= fd_emulate_sync_cache,
+	.parse_cdb		= fd_parse_cdb,
 	.check_configfs_dev_params = fd_check_configfs_dev_params,
 	.set_configfs_dev_params = fd_set_configfs_dev_params,
 	.show_configfs_dev_params = fd_show_configfs_dev_params,
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index fd47950..8a12e29 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -40,6 +40,7 @@
 #include <linux/module.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
+#include <asm/unaligned.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_backend.h>
@@ -96,6 +97,7 @@ static struct se_device *iblock_create_virtdevice(
 	struct request_queue *q;
 	struct queue_limits *limits;
 	u32 dev_flags = 0;
+	fmode_t mode;
 	int ret = -EINVAL;
 
 	if (!ib_dev) {
@@ -117,8 +119,11 @@ static struct se_device *iblock_create_virtdevice(
 	pr_debug( "IBLOCK: Claiming struct block_device: %s\n",
 			ib_dev->ibd_udev_path);
 
-	bd = blkdev_get_by_path(ib_dev->ibd_udev_path,
-				FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev);
+	mode = FMODE_READ|FMODE_EXCL;
+	if (!ib_dev->ibd_readonly)
+		mode |= FMODE_WRITE;
+
+	bd = blkdev_get_by_path(ib_dev->ibd_udev_path, mode, ib_dev);
 	if (IS_ERR(bd)) {
 		ret = PTR_ERR(bd);
 		goto failed;
@@ -292,7 +297,7 @@ static void iblock_end_io_flush(struct bio *bio, int err)
  * Implement SYCHRONIZE CACHE.  Note that we can't handle lba ranges and must
  * always flush the whole cache.
  */
-static void iblock_emulate_sync_cache(struct se_cmd *cmd)
+static int iblock_execute_sync_cache(struct se_cmd *cmd)
 {
 	struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
 	int immed = (cmd->t_task_cdb[1] & 0x2);
@@ -311,23 +316,81 @@ static void iblock_emulate_sync_cache(struct se_cmd *cmd)
 	if (!immed)
 		bio->bi_private = cmd;
 	submit_bio(WRITE_FLUSH, bio);
+	return 0;
 }
 
-static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
+static int iblock_execute_unmap(struct se_cmd *cmd)
 {
+	struct se_device *dev = cmd->se_dev;
 	struct iblock_dev *ibd = dev->dev_ptr;
-	struct block_device *bd = ibd->ibd_bd;
-	int barrier = 0;
+	unsigned char *buf, *ptr = NULL;
+	unsigned char *cdb = &cmd->t_task_cdb[0];
+	sector_t lba;
+	unsigned int size = cmd->data_length, range;
+	int ret = 0, offset;
+	unsigned short dl, bd_dl;
+
+	/* First UNMAP block descriptor starts at 8 byte offset */
+	offset = 8;
+	size -= 8;
+	dl = get_unaligned_be16(&cdb[0]);
+	bd_dl = get_unaligned_be16(&cdb[2]);
+
+	buf = transport_kmap_data_sg(cmd);
+
+	ptr = &buf[offset];
+	pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu"
+		" ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
+
+	while (size) {
+		lba = get_unaligned_be64(&ptr[0]);
+		range = get_unaligned_be32(&ptr[8]);
+		pr_debug("UNMAP: Using lba: %llu and range: %u\n",
+				 (unsigned long long)lba, range);
+
+		ret = blkdev_issue_discard(ibd->ibd_bd, lba, range,
+					   GFP_KERNEL, 0);
+		if (ret < 0) {
+			pr_err("blkdev_issue_discard() failed: %d\n",
+					ret);
+			goto err;
+		}
+
+		ptr += 16;
+		size -= 16;
+	}
 
-	return blkdev_issue_discard(bd, lba, range, GFP_KERNEL, barrier);
+err:
+	transport_kunmap_data_sg(cmd);
+	if (!ret)
+		target_complete_cmd(cmd, GOOD);
+	return ret;
+}
+
+static int iblock_execute_write_same(struct se_cmd *cmd)
+{
+	struct iblock_dev *ibd = cmd->se_dev->dev_ptr;
+	int ret;
+
+	ret = blkdev_issue_discard(ibd->ibd_bd, cmd->t_task_lba,
+				   spc_get_write_same_sectors(cmd), GFP_KERNEL,
+				   0);
+	if (ret < 0) {
+		pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n");
+		return ret;
+	}
+
+	target_complete_cmd(cmd, GOOD);
+	return 0;
 }
 
 enum {
-	Opt_udev_path, Opt_force, Opt_err
+	Opt_udev_path, Opt_readonly, Opt_force, Opt_err
 };
 
 static match_table_t tokens = {
 	{Opt_udev_path, "udev_path=%s"},
+	{Opt_readonly, "readonly=%d"},
 	{Opt_force, "force=%d"},
 	{Opt_err, NULL}
 };
@@ -340,6 +403,7 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba,
 	char *orig, *ptr, *arg_p, *opts;
 	substring_t args[MAX_OPT_ARGS];
 	int ret = 0, token;
+	unsigned long tmp_readonly;
 
 	opts = kstrdup(page, GFP_KERNEL);
 	if (!opts)
@@ -372,6 +436,22 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba,
 					ib_dev->ibd_udev_path);
 			ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH;
 			break;
+		case Opt_readonly:
+			arg_p = match_strdup(&args[0]);
+			if (!arg_p) {
+				ret = -ENOMEM;
+				break;
+			}
+			ret = strict_strtoul(arg_p, 0, &tmp_readonly);
+			kfree(arg_p);
+			if (ret < 0) {
+				pr_err("strict_strtoul() failed for"
+						" readonly=\n");
+				goto out;
+			}
+			ib_dev->ibd_readonly = tmp_readonly;
+			pr_debug("IBLOCK: readonly: %d\n", ib_dev->ibd_readonly);
+			break;
 		case Opt_force:
 			break;
 		default:
@@ -411,11 +491,10 @@ static ssize_t iblock_show_configfs_dev_params(
 	if (bd)
 		bl += sprintf(b + bl, "iBlock device: %s",
 				bdevname(bd, buf));
-	if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH) {
-		bl += sprintf(b + bl, "  UDEV PATH: %s\n",
+	if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH)
+		bl += sprintf(b + bl, "  UDEV PATH: %s",
 				ibd->ibd_udev_path);
-	} else
-		bl += sprintf(b + bl, "\n");
+	bl += sprintf(b + bl, "  readonly: %d\n", ibd->ibd_readonly);
 
 	bl += sprintf(b + bl, "        ");
 	if (bd) {
@@ -493,9 +572,11 @@ static void iblock_submit_bios(struct bio_list *list, int rw)
 	blk_finish_plug(&plug);
 }
 
-static int iblock_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
-		u32 sgl_nents, enum dma_data_direction data_direction)
+static int iblock_execute_rw(struct se_cmd *cmd)
 {
+	struct scatterlist *sgl = cmd->t_data_sg;
+	u32 sgl_nents = cmd->t_data_nents;
+	enum dma_data_direction data_direction = cmd->data_direction;
 	struct se_device *dev = cmd->se_dev;
 	struct iblock_req *ibr;
 	struct bio *bio;
@@ -642,6 +723,18 @@ static void iblock_bio_done(struct bio *bio, int err)
 	iblock_complete_cmd(cmd);
 }
 
+static struct spc_ops iblock_spc_ops = {
+	.execute_rw		= iblock_execute_rw,
+	.execute_sync_cache	= iblock_execute_sync_cache,
+	.execute_write_same	= iblock_execute_write_same,
+	.execute_unmap		= iblock_execute_unmap,
+};
+
+static int iblock_parse_cdb(struct se_cmd *cmd)
+{
+	return sbc_parse_cdb(cmd, &iblock_spc_ops);
+}
+
 static struct se_subsystem_api iblock_template = {
 	.name			= "iblock",
 	.owner			= THIS_MODULE,
@@ -653,9 +746,7 @@ static struct se_subsystem_api iblock_template = {
 	.allocate_virtdevice	= iblock_allocate_virtdevice,
 	.create_virtdevice	= iblock_create_virtdevice,
 	.free_device		= iblock_free_device,
-	.execute_cmd		= iblock_execute_cmd,
-	.do_discard		= iblock_do_discard,
-	.do_sync_cache		= iblock_emulate_sync_cache,
+	.parse_cdb		= iblock_parse_cdb,
 	.check_configfs_dev_params = iblock_check_configfs_dev_params,
 	.set_configfs_dev_params = iblock_set_configfs_dev_params,
 	.show_configfs_dev_params = iblock_show_configfs_dev_params,
diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h
index 66cf7b9..533627a 100644
--- a/drivers/target/target_core_iblock.h
+++ b/drivers/target/target_core_iblock.h
@@ -18,6 +18,7 @@ struct iblock_dev {
 	u32	ibd_flags;
 	struct bio_set	*ibd_bio_set;
 	struct block_device *ibd_bd;
+	bool ibd_readonly;
 } ____cacheline_aligned;
 
 #endif /* TARGET_CORE_IBLOCK_H */
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index 165e824..88f69e0 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -4,17 +4,6 @@
 /* target_core_alua.c */
 extern struct t10_alua_lu_gp *default_lu_gp;
 
-/* target_core_cdb.c */
-int	target_emulate_inquiry(struct se_cmd *cmd);
-int	target_emulate_readcapacity(struct se_cmd *cmd);
-int	target_emulate_readcapacity_16(struct se_cmd *cmd);
-int	target_emulate_modesense(struct se_cmd *cmd);
-int	target_emulate_request_sense(struct se_cmd *cmd);
-int	target_emulate_unmap(struct se_cmd *cmd);
-int	target_emulate_write_same(struct se_cmd *cmd);
-int	target_emulate_synchronize_cache(struct se_cmd *cmd);
-int	target_emulate_noop(struct se_cmd *cmd);
-
 /* target_core_device.c */
 struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
 int	core_free_device_list_for_node(struct se_node_acl *,
@@ -104,7 +93,6 @@ void	release_se_kmem_caches(void);
 u32	scsi_get_new_index(scsi_index_t);
 void	transport_subsystem_check_init(void);
 void	transport_cmd_finish_abort(struct se_cmd *, int);
-void	__target_remove_from_execute_list(struct se_cmd *);
 unsigned char *transport_dump_cmd_direction(struct se_cmd *);
 void	transport_dump_dev_state(struct se_device *, char *, int *);
 void	transport_dump_dev_info(struct se_device *, struct se_lun *,
@@ -116,6 +104,7 @@ int	transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int);
 bool	target_stop_cmd(struct se_cmd *cmd, unsigned long *flags);
 int	transport_clear_lun_from_sessions(struct se_lun *);
 void	transport_send_task_abort(struct se_cmd *);
+int	target_cmd_size_check(struct se_cmd *cmd, unsigned int size);
 
 /* target_core_stat.c */
 void	target_stat_setup_dev_default_groups(struct se_subsystem_dev *);
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 4ce2cf6..6e32ff6 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -35,8 +35,10 @@
 #include <linux/spinlock.h>
 #include <linux/genhd.h>
 #include <linux/cdrom.h>
-#include <linux/file.h>
+#include <linux/ratelimit.h>
 #include <linux/module.h>
+#include <asm/unaligned.h>
+
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
@@ -46,12 +48,14 @@
 #include <target/target_core_base.h>
 #include <target/target_core_backend.h>
 
+#include "target_core_alua.h"
 #include "target_core_pscsi.h"
 
 #define ISPRINT(a)  ((a >= ' ') && (a <= '~'))
 
 static struct se_subsystem_api pscsi_template;
 
+static int pscsi_execute_cmd(struct se_cmd *cmd);
 static void pscsi_req_done(struct request *, int);
 
 /*	pscsi_attach_hba():
@@ -1019,9 +1023,79 @@ fail:
 	return -ENOMEM;
 }
 
-static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
-		u32 sgl_nents, enum dma_data_direction data_direction)
+/*
+ * Clear a lun set in the cdb if the initiator talking to use spoke
+ * and old standards version, as we can't assume the underlying device
+ * won't choke up on it.
+ */
+static inline void pscsi_clear_cdb_lun(unsigned char *cdb)
+{
+	switch (cdb[0]) {
+	case READ_10: /* SBC - RDProtect */
+	case READ_12: /* SBC - RDProtect */
+	case READ_16: /* SBC - RDProtect */
+	case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
+	case VERIFY: /* SBC - VRProtect */
+	case VERIFY_16: /* SBC - VRProtect */
+	case WRITE_VERIFY: /* SBC - VRProtect */
+	case WRITE_VERIFY_12: /* SBC - VRProtect */
+	case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
+		break;
+	default:
+		cdb[1] &= 0x1f; /* clear logical unit number */
+		break;
+	}
+}
+
+static int pscsi_parse_cdb(struct se_cmd *cmd)
+{
+	unsigned char *cdb = cmd->t_task_cdb;
+	unsigned int dummy_size;
+	int ret;
+
+	if (cmd->se_cmd_flags & SCF_BIDI) {
+		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+		return -EINVAL;
+	}
+
+	pscsi_clear_cdb_lun(cdb);
+
+	/*
+	 * For REPORT LUNS we always need to emulate the response, for everything
+	 * else the default for pSCSI is to pass the command to the underlying
+	 * LLD / physical hardware.
+	 */
+	switch (cdb[0]) {
+	case REPORT_LUNS:
+		ret = spc_parse_cdb(cmd, &dummy_size);
+		if (ret)
+			return ret;
+		break;
+	case READ_6:
+	case READ_10:
+	case READ_12:
+	case READ_16:
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_12:
+	case WRITE_16:
+	case WRITE_VERIFY:
+		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+		/* FALLTHROUGH*/
+	default:
+		cmd->execute_cmd = pscsi_execute_cmd;
+		break;
+	}
+
+	return 0;
+}
+
+static int pscsi_execute_cmd(struct se_cmd *cmd)
 {
+	struct scatterlist *sgl = cmd->t_data_sg;
+	u32 sgl_nents = cmd->t_data_nents;
+	enum dma_data_direction data_direction = cmd->data_direction;
 	struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr;
 	struct pscsi_plugin_task *pt;
 	struct request *req;
@@ -1042,7 +1116,7 @@ static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
 	memcpy(pt->pscsi_cdb, cmd->t_task_cdb,
 		scsi_command_size(cmd->t_task_cdb));
 
-	if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
+	if (!sgl) {
 		req = blk_get_request(pdv->pdv_sd->request_queue,
 				(data_direction == DMA_TO_DEVICE),
 				GFP_KERNEL);
@@ -1188,7 +1262,7 @@ static struct se_subsystem_api pscsi_template = {
 	.create_virtdevice	= pscsi_create_virtdevice,
 	.free_device		= pscsi_free_device,
 	.transport_complete	= pscsi_transport_complete,
-	.execute_cmd		= pscsi_execute_cmd,
+	.parse_cdb		= pscsi_parse_cdb,
 	.check_configfs_dev_params = pscsi_check_configfs_dev_params,
 	.set_configfs_dev_params = pscsi_set_configfs_dev_params,
 	.show_configfs_dev_params = pscsi_show_configfs_dev_params,
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
index d0ceb87..d00bbe3 100644
--- a/drivers/target/target_core_rd.c
+++ b/drivers/target/target_core_rd.c
@@ -284,9 +284,11 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
 	return NULL;
 }
 
-static int rd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
-		u32 sgl_nents, enum dma_data_direction data_direction)
+static int rd_execute_rw(struct se_cmd *cmd)
 {
+	struct scatterlist *sgl = cmd->t_data_sg;
+	u32 sgl_nents = cmd->t_data_nents;
+	enum dma_data_direction data_direction = cmd->data_direction;
 	struct se_device *se_dev = cmd->se_dev;
 	struct rd_dev *dev = se_dev->dev_ptr;
 	struct rd_dev_sg_table *table;
@@ -460,6 +462,15 @@ static sector_t rd_get_blocks(struct se_device *dev)
 	return blocks_long;
 }
 
+static struct spc_ops rd_spc_ops = {
+	.execute_rw		= rd_execute_rw,
+};
+
+static int rd_parse_cdb(struct se_cmd *cmd)
+{
+	return sbc_parse_cdb(cmd, &rd_spc_ops);
+}
+
 static struct se_subsystem_api rd_mcp_template = {
 	.name			= "rd_mcp",
 	.transport_type		= TRANSPORT_PLUGIN_VHBA_VDEV,
@@ -468,7 +479,7 @@ static struct se_subsystem_api rd_mcp_template = {
 	.allocate_virtdevice	= rd_allocate_virtdevice,
 	.create_virtdevice	= rd_create_virtdevice,
 	.free_device		= rd_free_device,
-	.execute_cmd		= rd_execute_cmd,
+	.parse_cdb		= rd_parse_cdb,
 	.check_configfs_dev_params = rd_check_configfs_dev_params,
 	.set_configfs_dev_params = rd_set_configfs_dev_params,
 	.show_configfs_dev_params = rd_show_configfs_dev_params,
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
new file mode 100644
index 0000000..06e646f
--- /dev/null
+++ b/drivers/target/target_core_sbc.c
@@ -0,0 +1,581 @@
+/*
+ * SCSI Block Commands (SBC) parsing and emulation.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
+
+#include "target_core_internal.h"
+#include "target_core_ua.h"
+
+
+static int sbc_emulate_readcapacity(struct se_cmd *cmd)
+{
+	struct se_device *dev = cmd->se_dev;
+	unsigned char *buf;
+	unsigned long long blocks_long = dev->transport->get_blocks(dev);
+	u32 blocks;
+
+	if (blocks_long >= 0x00000000ffffffff)
+		blocks = 0xffffffff;
+	else
+		blocks = (u32)blocks_long;
+
+	buf = transport_kmap_data_sg(cmd);
+
+	buf[0] = (blocks >> 24) & 0xff;
+	buf[1] = (blocks >> 16) & 0xff;
+	buf[2] = (blocks >> 8) & 0xff;
+	buf[3] = blocks & 0xff;
+	buf[4] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
+	buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
+	buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
+	buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
+
+	transport_kunmap_data_sg(cmd);
+
+	target_complete_cmd(cmd, GOOD);
+	return 0;
+}
+
+static int sbc_emulate_readcapacity_16(struct se_cmd *cmd)
+{
+	struct se_device *dev = cmd->se_dev;
+	unsigned char *buf;
+	unsigned long long blocks = dev->transport->get_blocks(dev);
+
+	buf = transport_kmap_data_sg(cmd);
+
+	buf[0] = (blocks >> 56) & 0xff;
+	buf[1] = (blocks >> 48) & 0xff;
+	buf[2] = (blocks >> 40) & 0xff;
+	buf[3] = (blocks >> 32) & 0xff;
+	buf[4] = (blocks >> 24) & 0xff;
+	buf[5] = (blocks >> 16) & 0xff;
+	buf[6] = (blocks >> 8) & 0xff;
+	buf[7] = blocks & 0xff;
+	buf[8] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
+	buf[9] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
+	buf[10] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
+	buf[11] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
+	/*
+	 * Set Thin Provisioning Enable bit following sbc3r22 in section
+	 * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled.
+	 */
+	if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
+		buf[14] = 0x80;
+
+	transport_kunmap_data_sg(cmd);
+
+	target_complete_cmd(cmd, GOOD);
+	return 0;
+}
+
+int spc_get_write_same_sectors(struct se_cmd *cmd)
+{
+	u32 num_blocks;
+
+	if (cmd->t_task_cdb[0] == WRITE_SAME)
+		num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]);
+	else if (cmd->t_task_cdb[0] == WRITE_SAME_16)
+		num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
+	else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */
+		num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);
+
+	/*
+	 * Use the explicit range when non zero is supplied, otherwise calculate
+	 * the remaining range based on ->get_blocks() - starting LBA.
+	 */
+	if (num_blocks)
+		return num_blocks;
+
+	return cmd->se_dev->transport->get_blocks(cmd->se_dev) -
+		cmd->t_task_lba;
+}
+EXPORT_SYMBOL(spc_get_write_same_sectors);
+
+static int sbc_emulate_verify(struct se_cmd *cmd)
+{
+	target_complete_cmd(cmd, GOOD);
+	return 0;
+}
+
+static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors)
+{
+	return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors;
+}
+
+static int sbc_check_valid_sectors(struct se_cmd *cmd)
+{
+	struct se_device *dev = cmd->se_dev;
+	unsigned long long end_lba;
+	u32 sectors;
+
+	sectors = cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size;
+	end_lba = dev->transport->get_blocks(dev) + 1;
+
+	if (cmd->t_task_lba + sectors > end_lba) {
+		pr_err("target: lba %llu, sectors %u exceeds end lba %llu\n",
+			cmd->t_task_lba, sectors, end_lba);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline u32 transport_get_sectors_6(unsigned char *cdb)
+{
+	/*
+	 * Use 8-bit sector value.  SBC-3 says:
+	 *
+	 *   A TRANSFER LENGTH field set to zero specifies that 256
+	 *   logical blocks shall be written.  Any other value
+	 *   specifies the number of logical blocks that shall be
+	 *   written.
+	 */
+	return cdb[4] ? : 256;
+}
+
+static inline u32 transport_get_sectors_10(unsigned char *cdb)
+{
+	return (u32)(cdb[7] << 8) + cdb[8];
+}
+
+static inline u32 transport_get_sectors_12(unsigned char *cdb)
+{
+	return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9];
+}
+
+static inline u32 transport_get_sectors_16(unsigned char *cdb)
+{
+	return (u32)(cdb[10] << 24) + (cdb[11] << 16) +
+		    (cdb[12] << 8) + cdb[13];
+}
+
+/*
+ * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants
+ */
+static inline u32 transport_get_sectors_32(unsigned char *cdb)
+{
+	return (u32)(cdb[28] << 24) + (cdb[29] << 16) +
+		    (cdb[30] << 8) + cdb[31];
+
+}
+
+static inline u32 transport_lba_21(unsigned char *cdb)
+{
+	return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
+}
+
+static inline u32 transport_lba_32(unsigned char *cdb)
+{
+	return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
+}
+
+static inline unsigned long long transport_lba_64(unsigned char *cdb)
+{
+	unsigned int __v1, __v2;
+
+	__v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
+	__v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+
+	return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+}
+
+/*
+ * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs
+ */
+static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
+{
+	unsigned int __v1, __v2;
+
+	__v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15];
+	__v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19];
+
+	return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+}
+
+static int sbc_write_same_supported(struct se_device *dev,
+		unsigned char *flags)
+{
+	if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
+		pr_err("WRITE_SAME PBDATA and LBDATA"
+			" bits not supported for Block Discard"
+			" Emulation\n");
+		return -ENOSYS;
+	}
+
+	/*
+	 * Currently for the emulated case we only accept
+	 * tpws with the UNMAP=1 bit set.
+	 */
+	if (!(flags[0] & 0x08)) {
+		pr_err("WRITE_SAME w/o UNMAP bit not"
+			" supported for Block Discard Emulation\n");
+		return -ENOSYS;
+	}
+
+	return 0;
+}
+
+static void xdreadwrite_callback(struct se_cmd *cmd)
+{
+	unsigned char *buf, *addr;
+	struct scatterlist *sg;
+	unsigned int offset;
+	int i;
+	int count;
+	/*
+	 * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command
+	 *
+	 * 1) read the specified logical block(s);
+	 * 2) transfer logical blocks from the data-out buffer;
+	 * 3) XOR the logical blocks transferred from the data-out buffer with
+	 *    the logical blocks read, storing the resulting XOR data in a buffer;
+	 * 4) if the DISABLE WRITE bit is set to zero, then write the logical
+	 *    blocks transferred from the data-out buffer; and
+	 * 5) transfer the resulting XOR data to the data-in buffer.
+	 */
+	buf = kmalloc(cmd->data_length, GFP_KERNEL);
+	if (!buf) {
+		pr_err("Unable to allocate xor_callback buf\n");
+		return;
+	}
+	/*
+	 * Copy the scatterlist WRITE buffer located at cmd->t_data_sg
+	 * into the locally allocated *buf
+	 */
+	sg_copy_to_buffer(cmd->t_data_sg,
+			  cmd->t_data_nents,
+			  buf,
+			  cmd->data_length);
+
+	/*
+	 * Now perform the XOR against the BIDI read memory located at
+	 * cmd->t_mem_bidi_list
+	 */
+
+	offset = 0;
+	for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) {
+		addr = kmap_atomic(sg_page(sg));
+		if (!addr)
+			goto out;
+
+		for (i = 0; i < sg->length; i++)
+			*(addr + sg->offset + i) ^= *(buf + offset + i);
+
+		offset += sg->length;
+		kunmap_atomic(addr);
+	}
+
+out:
+	kfree(buf);
+}
+
+int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)
+{
+	struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
+	struct se_device *dev = cmd->se_dev;
+	unsigned char *cdb = cmd->t_task_cdb;
+	unsigned int size;
+	u32 sectors = 0;
+	int ret;
+
+	switch (cdb[0]) {
+	case READ_6:
+		sectors = transport_get_sectors_6(cdb);
+		cmd->t_task_lba = transport_lba_21(cdb);
+		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+		cmd->execute_cmd = ops->execute_rw;
+		break;
+	case READ_10:
+		sectors = transport_get_sectors_10(cdb);
+		cmd->t_task_lba = transport_lba_32(cdb);
+		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+		cmd->execute_cmd = ops->execute_rw;
+		break;
+	case READ_12:
+		sectors = transport_get_sectors_12(cdb);
+		cmd->t_task_lba = transport_lba_32(cdb);
+		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+		cmd->execute_cmd = ops->execute_rw;
+		break;
+	case READ_16:
+		sectors = transport_get_sectors_16(cdb);
+		cmd->t_task_lba = transport_lba_64(cdb);
+		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+		cmd->execute_cmd = ops->execute_rw;
+		break;
+	case WRITE_6:
+		sectors = transport_get_sectors_6(cdb);
+		cmd->t_task_lba = transport_lba_21(cdb);
+		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+		cmd->execute_cmd = ops->execute_rw;
+		break;
+	case WRITE_10:
+	case WRITE_VERIFY:
+		sectors = transport_get_sectors_10(cdb);
+		cmd->t_task_lba = transport_lba_32(cdb);
+		if (cdb[1] & 0x8)
+			cmd->se_cmd_flags |= SCF_FUA;
+		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+		cmd->execute_cmd = ops->execute_rw;
+		break;
+	case WRITE_12:
+		sectors = transport_get_sectors_12(cdb);
+		cmd->t_task_lba = transport_lba_32(cdb);
+		if (cdb[1] & 0x8)
+			cmd->se_cmd_flags |= SCF_FUA;
+		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+		cmd->execute_cmd = ops->execute_rw;
+		break;
+	case WRITE_16:
+		sectors = transport_get_sectors_16(cdb);
+		cmd->t_task_lba = transport_lba_64(cdb);
+		if (cdb[1] & 0x8)
+			cmd->se_cmd_flags |= SCF_FUA;
+		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+		cmd->execute_cmd = ops->execute_rw;
+		break;
+	case XDWRITEREAD_10:
+		if ((cmd->data_direction != DMA_TO_DEVICE) ||
+		    !(cmd->se_cmd_flags & SCF_BIDI))
+			goto out_invalid_cdb_field;
+		sectors = transport_get_sectors_10(cdb);
+
+		cmd->t_task_lba = transport_lba_32(cdb);
+		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+
+		/*
+		 * Setup BIDI XOR callback to be run after I/O completion.
+		 */
+		cmd->execute_cmd = ops->execute_rw;
+		cmd->transport_complete_callback = &xdreadwrite_callback;
+		if (cdb[1] & 0x8)
+			cmd->se_cmd_flags |= SCF_FUA;
+		break;
+	case VARIABLE_LENGTH_CMD:
+	{
+		u16 service_action = get_unaligned_be16(&cdb[8]);
+		switch (service_action) {
+		case XDWRITEREAD_32:
+			sectors = transport_get_sectors_32(cdb);
+
+			/*
+			 * Use WRITE_32 and READ_32 opcodes for the emulated
+			 * XDWRITE_READ_32 logic.
+			 */
+			cmd->t_task_lba = transport_lba_64_ext(cdb);
+			cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+
+			/*
+			 * Setup BIDI XOR callback to be run during after I/O
+			 * completion.
+			 */
+			cmd->execute_cmd = ops->execute_rw;
+			cmd->transport_complete_callback = &xdreadwrite_callback;
+			if (cdb[1] & 0x8)
+				cmd->se_cmd_flags |= SCF_FUA;
+			break;
+		case WRITE_SAME_32:
+			if (!ops->execute_write_same)
+				goto out_unsupported_cdb;
+
+			sectors = transport_get_sectors_32(cdb);
+			if (!sectors) {
+				pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not"
+				       " supported\n");
+				goto out_invalid_cdb_field;
+			}
+
+			size = sbc_get_size(cmd, 1);
+			cmd->t_task_lba = get_unaligned_be64(&cdb[12]);
+
+			if (sbc_write_same_supported(dev, &cdb[10]) < 0)
+				goto out_unsupported_cdb;
+			cmd->execute_cmd = ops->execute_write_same;
+			break;
+		default:
+			pr_err("VARIABLE_LENGTH_CMD service action"
+				" 0x%04x not supported\n", service_action);
+			goto out_unsupported_cdb;
+		}
+		break;
+	}
+	case READ_CAPACITY:
+		size = READ_CAP_LEN;
+		cmd->execute_cmd = sbc_emulate_readcapacity;
+		break;
+	case SERVICE_ACTION_IN:
+		switch (cmd->t_task_cdb[1] & 0x1f) {
+		case SAI_READ_CAPACITY_16:
+			cmd->execute_cmd = sbc_emulate_readcapacity_16;
+			break;
+		default:
+			pr_err("Unsupported SA: 0x%02x\n",
+				cmd->t_task_cdb[1] & 0x1f);
+			goto out_invalid_cdb_field;
+		}
+		size = (cdb[10] << 24) | (cdb[11] << 16) |
+		       (cdb[12] << 8) | cdb[13];
+		break;
+	case SYNCHRONIZE_CACHE:
+	case SYNCHRONIZE_CACHE_16:
+		if (!ops->execute_sync_cache)
+			goto out_unsupported_cdb;
+
+		/*
+		 * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE
+		 */
+		if (cdb[0] == SYNCHRONIZE_CACHE) {
+			sectors = transport_get_sectors_10(cdb);
+			cmd->t_task_lba = transport_lba_32(cdb);
+		} else {
+			sectors = transport_get_sectors_16(cdb);
+			cmd->t_task_lba = transport_lba_64(cdb);
+		}
+
+		size = sbc_get_size(cmd, sectors);
+
+		/*
+		 * Check to ensure that LBA + Range does not exceed past end of
+		 * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
+		 */
+		if (cmd->t_task_lba || sectors) {
+			if (sbc_check_valid_sectors(cmd) < 0)
+				goto out_invalid_cdb_field;
+		}
+		cmd->execute_cmd = ops->execute_sync_cache;
+		break;
+	case UNMAP:
+		if (!ops->execute_unmap)
+			goto out_unsupported_cdb;
+
+		size = get_unaligned_be16(&cdb[7]);
+		cmd->execute_cmd = ops->execute_unmap;
+		break;
+	case WRITE_SAME_16:
+		if (!ops->execute_write_same)
+			goto out_unsupported_cdb;
+
+		sectors = transport_get_sectors_16(cdb);
+		if (!sectors) {
+			pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
+			goto out_invalid_cdb_field;
+		}
+
+		size = sbc_get_size(cmd, 1);
+		cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
+
+		if (sbc_write_same_supported(dev, &cdb[1]) < 0)
+			goto out_unsupported_cdb;
+		cmd->execute_cmd = ops->execute_write_same;
+		break;
+	case WRITE_SAME:
+		if (!ops->execute_write_same)
+			goto out_unsupported_cdb;
+
+		sectors = transport_get_sectors_10(cdb);
+		if (!sectors) {
+			pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
+			goto out_invalid_cdb_field;
+		}
+
+		size = sbc_get_size(cmd, 1);
+		cmd->t_task_lba = get_unaligned_be32(&cdb[2]);
+
+		/*
+		 * Follow sbcr26 with WRITE_SAME (10) and check for the existence
+		 * of byte 1 bit 3 UNMAP instead of original reserved field
+		 */
+		if (sbc_write_same_supported(dev, &cdb[1]) < 0)
+			goto out_unsupported_cdb;
+		cmd->execute_cmd = ops->execute_write_same;
+		break;
+	case VERIFY:
+		size = 0;
+		cmd->execute_cmd = sbc_emulate_verify;
+		break;
+	default:
+		ret = spc_parse_cdb(cmd, &size);
+		if (ret)
+			return ret;
+	}
+
+	/* reject any command that we don't have a handler for */
+	if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->execute_cmd)
+		goto out_unsupported_cdb;
+
+	if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
+		unsigned long long end_lba;
+
+		if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) {
+			printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
+				" big sectors %u exceeds fabric_max_sectors:"
+				" %u\n", cdb[0], sectors,
+				su_dev->se_dev_attrib.fabric_max_sectors);
+			goto out_invalid_cdb_field;
+		}
+		if (sectors > su_dev->se_dev_attrib.hw_max_sectors) {
+			printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
+				" big sectors %u exceeds backend hw_max_sectors:"
+				" %u\n", cdb[0], sectors,
+				su_dev->se_dev_attrib.hw_max_sectors);
+			goto out_invalid_cdb_field;
+		}
+
+		end_lba = dev->transport->get_blocks(dev) + 1;
+		if (cmd->t_task_lba + sectors > end_lba) {
+			pr_err("cmd exceeds last lba %llu "
+				"(lba %llu, sectors %u)\n",
+				end_lba, cmd->t_task_lba, sectors);
+			goto out_invalid_cdb_field;
+		}
+
+		size = sbc_get_size(cmd, sectors);
+	}
+
+	ret = target_cmd_size_check(cmd, size);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+
+out_unsupported_cdb:
+	cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+	cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+	return -EINVAL;
+out_invalid_cdb_field:
+	cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+	cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+	return -EINVAL;
+}
+EXPORT_SYMBOL(sbc_parse_cdb);
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
new file mode 100644
index 0000000..4c861de
--- /dev/null
+++ b/drivers/target/target_core_spc.c
@@ -0,0 +1,1104 @@
+/*
+ * SCSI Primary Commands (SPC) parsing and emulation.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/unaligned.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
+
+#include "target_core_internal.h"
+#include "target_core_alua.h"
+#include "target_core_pr.h"
+#include "target_core_ua.h"
+
+
+static void spc_fill_alua_data(struct se_port *port, unsigned char *buf)
+{
+	struct t10_alua_tg_pt_gp *tg_pt_gp;
+	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+
+	/*
+	 * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS.
+	 */
+	buf[5]	= 0x80;
+
+	/*
+	 * Set TPGS field for explict and/or implict ALUA access type
+	 * and opteration.
+	 *
+	 * See spc4r17 section 6.4.2 Table 135
+	 */
+	if (!port)
+		return;
+	tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+	if (!tg_pt_gp_mem)
+		return;
+
+	spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+	tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+	if (tg_pt_gp)
+		buf[5] |= tg_pt_gp->tg_pt_gp_alua_access_type;
+	spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+}
+
+static int spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf)
+{
+	struct se_lun *lun = cmd->se_lun;
+	struct se_device *dev = cmd->se_dev;
+
+	/* Set RMB (removable media) for tape devices */
+	if (dev->transport->get_device_type(dev) == TYPE_TAPE)
+		buf[1] = 0x80;
+
+	buf[2] = dev->transport->get_device_rev(dev);
+
+	/*
+	 * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2
+	 *
+	 * SPC4 says:
+	 *   A RESPONSE DATA FORMAT field set to 2h indicates that the
+	 *   standard INQUIRY data is in the format defined in this
+	 *   standard. Response data format values less than 2h are
+	 *   obsolete. Response data format values greater than 2h are
+	 *   reserved.
+	 */
+	buf[3] = 2;
+
+	/*
+	 * Enable SCCS and TPGS fields for Emulated ALUA
+	 */
+	if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED)
+		spc_fill_alua_data(lun->lun_sep, buf);
+
+	buf[7] = 0x2; /* CmdQue=1 */
+
+	snprintf(&buf[8], 8, "LIO-ORG");
+	snprintf(&buf[16], 16, "%s", dev->se_sub_dev->t10_wwn.model);
+	snprintf(&buf[32], 4, "%s", dev->se_sub_dev->t10_wwn.revision);
+	buf[4] = 31; /* Set additional length to 31 */
+
+	return 0;
+}
+
+/* unit serial number */
+static int spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
+{
+	struct se_device *dev = cmd->se_dev;
+	u16 len = 0;
+
+	if (dev->se_sub_dev->su_dev_flags &
+			SDF_EMULATED_VPD_UNIT_SERIAL) {
+		u32 unit_serial_len;
+
+		unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial);
+		unit_serial_len++; /* For NULL Terminator */
+
+		len += sprintf(&buf[4], "%s",
+			dev->se_sub_dev->t10_wwn.unit_serial);
+		len++; /* Extra Byte for NULL Terminator */
+		buf[3] = len;
+	}
+	return 0;
+}
+
+static void spc_parse_naa_6h_vendor_specific(struct se_device *dev,
+		unsigned char *buf)
+{
+	unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0];
+	int cnt;
+	bool next = true;
+
+	/*
+	 * Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on
+	 * byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field
+	 * format, followed by 64 bits of VENDOR SPECIFIC IDENTIFIER EXTENSION
+	 * to complete the payload.  These are based from VPD=0x80 PRODUCT SERIAL
+	 * NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure
+	 * per device uniqeness.
+	 */
+	for (cnt = 0; *p && cnt < 13; p++) {
+		int val = hex_to_bin(*p);
+
+		if (val < 0)
+			continue;
+
+		if (next) {
+			next = false;
+			buf[cnt++] |= val;
+		} else {
+			next = true;
+			buf[cnt] = val << 4;
+		}
+	}
+}
+
+/*
+ * Device identification VPD, for a complete list of
+ * DESIGNATOR TYPEs see spc4r17 Table 459.
+ */
+static int spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
+{
+	struct se_device *dev = cmd->se_dev;
+	struct se_lun *lun = cmd->se_lun;
+	struct se_port *port = NULL;
+	struct se_portal_group *tpg = NULL;
+	struct t10_alua_lu_gp_member *lu_gp_mem;
+	struct t10_alua_tg_pt_gp *tg_pt_gp;
+	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+	unsigned char *prod = &dev->se_sub_dev->t10_wwn.model[0];
+	u32 prod_len;
+	u32 unit_serial_len, off = 0;
+	u16 len = 0, id_len;
+
+	off = 4;
+
+	/*
+	 * NAA IEEE Registered Extended Assigned designator format, see
+	 * spc4r17 section 7.7.3.6.5
+	 *
+	 * We depend upon a target_core_mod/ConfigFS provided
+	 * /sys/kernel/config/target/core/$HBA/$DEV/wwn/vpd_unit_serial
+	 * value in order to return the NAA id.
+	 */
+	if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL))
+		goto check_t10_vend_desc;
+
+	/* CODE SET == Binary */
+	buf[off++] = 0x1;
+
+	/* Set ASSOCIATION == addressed logical unit: 0)b */
+	buf[off] = 0x00;
+
+	/* Identifier/Designator type == NAA identifier */
+	buf[off++] |= 0x3;
+	off++;
+
+	/* Identifier/Designator length */
+	buf[off++] = 0x10;
+
+	/*
+	 * Start NAA IEEE Registered Extended Identifier/Designator
+	 */
+	buf[off++] = (0x6 << 4);
+
+	/*
+	 * Use OpenFabrics IEEE Company ID: 00 14 05
+	 */
+	buf[off++] = 0x01;
+	buf[off++] = 0x40;
+	buf[off] = (0x5 << 4);
+
+	/*
+	 * Return ConfigFS Unit Serial Number information for
+	 * VENDOR_SPECIFIC_IDENTIFIER and
+	 * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION
+	 */
+	spc_parse_naa_6h_vendor_specific(dev, &buf[off]);
+
+	len = 20;
+	off = (len + 4);
+
+check_t10_vend_desc:
+	/*
+	 * T10 Vendor Identifier Page, see spc4r17 section 7.7.3.4
+	 */
+	id_len = 8; /* For Vendor field */
+	prod_len = 4; /* For VPD Header */
+	prod_len += 8; /* For Vendor field */
+	prod_len += strlen(prod);
+	prod_len++; /* For : */
+
+	if (dev->se_sub_dev->su_dev_flags &
+			SDF_EMULATED_VPD_UNIT_SERIAL) {
+		unit_serial_len =
+			strlen(&dev->se_sub_dev->t10_wwn.unit_serial[0]);
+		unit_serial_len++; /* For NULL Terminator */
+
+		id_len += sprintf(&buf[off+12], "%s:%s", prod,
+				&dev->se_sub_dev->t10_wwn.unit_serial[0]);
+	}
+	buf[off] = 0x2; /* ASCII */
+	buf[off+1] = 0x1; /* T10 Vendor ID */
+	buf[off+2] = 0x0;
+	memcpy(&buf[off+4], "LIO-ORG", 8);
+	/* Extra Byte for NULL Terminator */
+	id_len++;
+	/* Identifier Length */
+	buf[off+3] = id_len;
+	/* Header size for Designation descriptor */
+	len += (id_len + 4);
+	off += (id_len + 4);
+	/*
+	 * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD
+	 */
+	port = lun->lun_sep;
+	if (port) {
+		struct t10_alua_lu_gp *lu_gp;
+		u32 padding, scsi_name_len;
+		u16 lu_gp_id = 0;
+		u16 tg_pt_gp_id = 0;
+		u16 tpgt;
+
+		tpg = port->sep_tpg;
+		/*
+		 * Relative target port identifer, see spc4r17
+		 * section 7.7.3.7
+		 *
+		 * Get the PROTOCOL IDENTIFIER as defined by spc4r17
+		 * section 7.5.1 Table 362
+		 */
+		buf[off] =
+			(tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
+		buf[off++] |= 0x1; /* CODE SET == Binary */
+		buf[off] = 0x80; /* Set PIV=1 */
+		/* Set ASSOCIATION == target port: 01b */
+		buf[off] |= 0x10;
+		/* DESIGNATOR TYPE == Relative target port identifer */
+		buf[off++] |= 0x4;
+		off++; /* Skip over Reserved */
+		buf[off++] = 4; /* DESIGNATOR LENGTH */
+		/* Skip over Obsolete field in RTPI payload
+		 * in Table 472 */
+		off += 2;
+		buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
+		buf[off++] = (port->sep_rtpi & 0xff);
+		len += 8; /* Header size + Designation descriptor */
+		/*
+		 * Target port group identifier, see spc4r17
+		 * section 7.7.3.8
+		 *
+		 * Get the PROTOCOL IDENTIFIER as defined by spc4r17
+		 * section 7.5.1 Table 362
+		 */
+		if (dev->se_sub_dev->t10_alua.alua_type !=
+				SPC3_ALUA_EMULATED)
+			goto check_scsi_name;
+
+		tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+		if (!tg_pt_gp_mem)
+			goto check_lu_gp;
+
+		spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+		tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+		if (!tg_pt_gp) {
+			spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+			goto check_lu_gp;
+		}
+		tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id;
+		spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+		buf[off] =
+			(tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
+		buf[off++] |= 0x1; /* CODE SET == Binary */
+		buf[off] = 0x80; /* Set PIV=1 */
+		/* Set ASSOCIATION == target port: 01b */
+		buf[off] |= 0x10;
+		/* DESIGNATOR TYPE == Target port group identifier */
+		buf[off++] |= 0x5;
+		off++; /* Skip over Reserved */
+		buf[off++] = 4; /* DESIGNATOR LENGTH */
+		off += 2; /* Skip over Reserved Field */
+		buf[off++] = ((tg_pt_gp_id >> 8) & 0xff);
+		buf[off++] = (tg_pt_gp_id & 0xff);
+		len += 8; /* Header size + Designation descriptor */
+		/*
+		 * Logical Unit Group identifier, see spc4r17
+		 * section 7.7.3.8
+		 */
+check_lu_gp:
+		lu_gp_mem = dev->dev_alua_lu_gp_mem;
+		if (!lu_gp_mem)
+			goto check_scsi_name;
+
+		spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+		lu_gp = lu_gp_mem->lu_gp;
+		if (!lu_gp) {
+			spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+			goto check_scsi_name;
+		}
+		lu_gp_id = lu_gp->lu_gp_id;
+		spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+		buf[off++] |= 0x1; /* CODE SET == Binary */
+		/* DESIGNATOR TYPE == Logical Unit Group identifier */
+		buf[off++] |= 0x6;
+		off++; /* Skip over Reserved */
+		buf[off++] = 4; /* DESIGNATOR LENGTH */
+		off += 2; /* Skip over Reserved Field */
+		buf[off++] = ((lu_gp_id >> 8) & 0xff);
+		buf[off++] = (lu_gp_id & 0xff);
+		len += 8; /* Header size + Designation descriptor */
+		/*
+		 * SCSI name string designator, see spc4r17
+		 * section 7.7.3.11
+		 *
+		 * Get the PROTOCOL IDENTIFIER as defined by spc4r17
+		 * section 7.5.1 Table 362
+		 */
+check_scsi_name:
+		scsi_name_len = strlen(tpg->se_tpg_tfo->tpg_get_wwn(tpg));
+		/* UTF-8 ",t,0x<16-bit TPGT>" + NULL Terminator */
+		scsi_name_len += 10;
+		/* Check for 4-byte padding */
+		padding = ((-scsi_name_len) & 3);
+		if (padding != 0)
+			scsi_name_len += padding;
+		/* Header size + Designation descriptor */
+		scsi_name_len += 4;
+
+		buf[off] =
+			(tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
+		buf[off++] |= 0x3; /* CODE SET == UTF-8 */
+		buf[off] = 0x80; /* Set PIV=1 */
+		/* Set ASSOCIATION == target port: 01b */
+		buf[off] |= 0x10;
+		/* DESIGNATOR TYPE == SCSI name string */
+		buf[off++] |= 0x8;
+		off += 2; /* Skip over Reserved and length */
+		/*
+		 * SCSI name string identifer containing, $FABRIC_MOD
+		 * dependent information.  For LIO-Target and iSCSI
+		 * Target Port, this means "<iSCSI name>,t,0x<TPGT> in
+		 * UTF-8 encoding.
+		 */
+		tpgt = tpg->se_tpg_tfo->tpg_get_tag(tpg);
+		scsi_name_len = sprintf(&buf[off], "%s,t,0x%04x",
+					tpg->se_tpg_tfo->tpg_get_wwn(tpg), tpgt);
+		scsi_name_len += 1 /* Include  NULL terminator */;
+		/*
+		 * The null-terminated, null-padded (see 4.4.2) SCSI
+		 * NAME STRING field contains a UTF-8 format string.
+		 * The number of bytes in the SCSI NAME STRING field
+		 * (i.e., the value in the DESIGNATOR LENGTH field)
+		 * shall be no larger than 256 and shall be a multiple
+		 * of four.
+		 */
+		if (padding)
+			scsi_name_len += padding;
+
+		buf[off-1] = scsi_name_len;
+		off += scsi_name_len;
+		/* Header size + Designation descriptor */
+		len += (scsi_name_len + 4);
+	}
+	buf[2] = ((len >> 8) & 0xff);
+	buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */
+	return 0;
+}
+
+/* Extended INQUIRY Data VPD Page */
+static int spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
+{
+	buf[3] = 0x3c;
+	/* Set HEADSUP, ORDSUP, SIMPSUP */
+	buf[5] = 0x07;
+
+	/* If WriteCache emulation is enabled, set V_SUP */
+	if (cmd->se_dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0)
+		buf[6] = 0x01;
+	return 0;
+}
+
+/* Block Limits VPD page */
+static int spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
+{
+	struct se_device *dev = cmd->se_dev;
+	u32 max_sectors;
+	int have_tp = 0;
+
+	/*
+	 * Following spc3r22 section 6.5.3 Block Limits VPD page, when
+	 * emulate_tpu=1 or emulate_tpws=1 we will be expect a
+	 * different page length for Thin Provisioning.
+	 */
+	if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
+		have_tp = 1;
+
+	buf[0] = dev->transport->get_device_type(dev);
+	buf[3] = have_tp ? 0x3c : 0x10;
+
+	/* Set WSNZ to 1 */
+	buf[4] = 0x01;
+
+	/*
+	 * Set OPTIMAL TRANSFER LENGTH GRANULARITY
+	 */
+	put_unaligned_be16(1, &buf[6]);
+
+	/*
+	 * Set MAXIMUM TRANSFER LENGTH
+	 */
+	max_sectors = min(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors,
+			  dev->se_sub_dev->se_dev_attrib.hw_max_sectors);
+	put_unaligned_be32(max_sectors, &buf[8]);
+
+	/*
+	 * Set OPTIMAL TRANSFER LENGTH
+	 */
+	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.optimal_sectors, &buf[12]);
+
+	/*
+	 * Exit now if we don't support TP.
+	 */
+	if (!have_tp)
+		return 0;
+
+	/*
+	 * Set MAXIMUM UNMAP LBA COUNT
+	 */
+	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count, &buf[20]);
+
+	/*
+	 * Set MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT
+	 */
+	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count,
+			   &buf[24]);
+
+	/*
+	 * Set OPTIMAL UNMAP GRANULARITY
+	 */
+	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity, &buf[28]);
+
+	/*
+	 * UNMAP GRANULARITY ALIGNMENT
+	 */
+	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment,
+			   &buf[32]);
+	if (dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment != 0)
+		buf[32] |= 0x80; /* Set the UGAVALID bit */
+
+	return 0;
+}
+
+/* Block Device Characteristics VPD page */
+static int spc_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf)
+{
+	struct se_device *dev = cmd->se_dev;
+
+	buf[0] = dev->transport->get_device_type(dev);
+	buf[3] = 0x3c;
+	buf[5] = dev->se_sub_dev->se_dev_attrib.is_nonrot ? 1 : 0;
+
+	return 0;
+}
+
+/* Thin Provisioning VPD */
+static int spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
+{
+	struct se_device *dev = cmd->se_dev;
+
+	/*
+	 * From spc3r22 section 6.5.4 Thin Provisioning VPD page:
+	 *
+	 * The PAGE LENGTH field is defined in SPC-4. If the DP bit is set to
+	 * zero, then the page length shall be set to 0004h.  If the DP bit
+	 * is set to one, then the page length shall be set to the value
+	 * defined in table 162.
+	 */
+	buf[0] = dev->transport->get_device_type(dev);
+
+	/*
+	 * Set Hardcoded length mentioned above for DP=0
+	 */
+	put_unaligned_be16(0x0004, &buf[2]);
+
+	/*
+	 * The THRESHOLD EXPONENT field indicates the threshold set size in
+	 * LBAs as a power of 2 (i.e., the threshold set size is equal to
+	 * 2(threshold exponent)).
+	 *
+	 * Note that this is currently set to 0x00 as mkp says it will be
+	 * changing again.  We can enable this once it has settled in T10
+	 * and is actually used by Linux/SCSI ML code.
+	 */
+	buf[4] = 0x00;
+
+	/*
+	 * A TPU bit set to one indicates that the device server supports
+	 * the UNMAP command (see 5.25). A TPU bit set to zero indicates
+	 * that the device server does not support the UNMAP command.
+	 */
+	if (dev->se_sub_dev->se_dev_attrib.emulate_tpu != 0)
+		buf[5] = 0x80;
+
+	/*
+	 * A TPWS bit set to one indicates that the device server supports
+	 * the use of the WRITE SAME (16) command (see 5.42) to unmap LBAs.
+	 * A TPWS bit set to zero indicates that the device server does not
+	 * support the use of the WRITE SAME (16) command to unmap LBAs.
+	 */
+	if (dev->se_sub_dev->se_dev_attrib.emulate_tpws != 0)
+		buf[5] |= 0x40;
+
+	return 0;
+}
+
+static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf);
+
+static struct {
+	uint8_t		page;
+	int		(*emulate)(struct se_cmd *, unsigned char *);
+} evpd_handlers[] = {
+	{ .page = 0x00, .emulate = spc_emulate_evpd_00 },
+	{ .page = 0x80, .emulate = spc_emulate_evpd_80 },
+	{ .page = 0x83, .emulate = spc_emulate_evpd_83 },
+	{ .page = 0x86, .emulate = spc_emulate_evpd_86 },
+	{ .page = 0xb0, .emulate = spc_emulate_evpd_b0 },
+	{ .page = 0xb1, .emulate = spc_emulate_evpd_b1 },
+	{ .page = 0xb2, .emulate = spc_emulate_evpd_b2 },
+};
+
+/* supported vital product data pages */
+static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
+{
+	int p;
+
+	/*
+	 * Only report the INQUIRY EVPD=1 pages after a valid NAA
+	 * Registered Extended LUN WWN has been set via ConfigFS
+	 * during device creation/restart.
+	 */
+	if (cmd->se_dev->se_sub_dev->su_dev_flags &
+			SDF_EMULATED_VPD_UNIT_SERIAL) {
+		buf[3] = ARRAY_SIZE(evpd_handlers);
+		for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p)
+			buf[p + 4] = evpd_handlers[p].page;
+	}
+
+	return 0;
+}
+
+static int spc_emulate_inquiry(struct se_cmd *cmd)
+{
+	struct se_device *dev = cmd->se_dev;
+	struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg;
+	unsigned char *buf, *map_buf;
+	unsigned char *cdb = cmd->t_task_cdb;
+	int p, ret;
+
+	map_buf = transport_kmap_data_sg(cmd);
+	/*
+	 * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we
+	 * know we actually allocated a full page.  Otherwise, if the
+	 * data buffer is too small, allocate a temporary buffer so we
+	 * don't have to worry about overruns in all our INQUIRY
+	 * emulation handling.
+	 */
+	if (cmd->data_length < SE_INQUIRY_BUF &&
+	    (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) {
+		buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
+		if (!buf) {
+			transport_kunmap_data_sg(cmd);
+			cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+			return -ENOMEM;
+		}
+	} else {
+		buf = map_buf;
+	}
+
+	if (dev == tpg->tpg_virt_lun0.lun_se_dev)
+		buf[0] = 0x3f; /* Not connected */
+	else
+		buf[0] = dev->transport->get_device_type(dev);
+
+	if (!(cdb[1] & 0x1)) {
+		if (cdb[2]) {
+			pr_err("INQUIRY with EVPD==0 but PAGE CODE=%02x\n",
+			       cdb[2]);
+			cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+			ret = -EINVAL;
+			goto out;
+		}
+
+		ret = spc_emulate_inquiry_std(cmd, buf);
+		goto out;
+	}
+
+	for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) {
+		if (cdb[2] == evpd_handlers[p].page) {
+			buf[1] = cdb[2];
+			ret = evpd_handlers[p].emulate(cmd, buf);
+			goto out;
+		}
+	}
+
+	pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]);
+	cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+	ret = -EINVAL;
+
+out:
+	if (buf != map_buf) {
+		memcpy(map_buf, buf, cmd->data_length);
+		kfree(buf);
+	}
+	transport_kunmap_data_sg(cmd);
+
+	if (!ret)
+		target_complete_cmd(cmd, GOOD);
+	return ret;
+}
+
+static int spc_modesense_rwrecovery(unsigned char *p)
+{
+	p[0] = 0x01;
+	p[1] = 0x0a;
+
+	return 12;
+}
+
+static int spc_modesense_control(struct se_device *dev, unsigned char *p)
+{
+	p[0] = 0x0a;
+	p[1] = 0x0a;
+	p[2] = 2;
+	/*
+	 * From spc4r23, 7.4.7 Control mode page
+	 *
+	 * The QUEUE ALGORITHM MODIFIER field (see table 368) specifies
+	 * restrictions on the algorithm used for reordering commands
+	 * having the SIMPLE task attribute (see SAM-4).
+	 *
+	 *                    Table 368 -- QUEUE ALGORITHM MODIFIER field
+	 *                         Code      Description
+	 *                          0h       Restricted reordering
+	 *                          1h       Unrestricted reordering allowed
+	 *                          2h to 7h    Reserved
+	 *                          8h to Fh    Vendor specific
+	 *
+	 * A value of zero in the QUEUE ALGORITHM MODIFIER field specifies that
+	 * the device server shall order the processing sequence of commands
+	 * having the SIMPLE task attribute such that data integrity is maintained
+	 * for that I_T nexus (i.e., if the transmission of new SCSI transport protocol
+	 * requests is halted at any time, the final value of all data observable
+	 * on the medium shall be the same as if all the commands had been processed
+	 * with the ORDERED task attribute).
+	 *
+	 * A value of one in the QUEUE ALGORITHM MODIFIER field specifies that the
+	 * device server may reorder the processing sequence of commands having the
+	 * SIMPLE task attribute in any manner. Any data integrity exposures related to
+	 * command sequence order shall be explicitly handled by the application client
+	 * through the selection of appropriate ommands and task attributes.
+	 */
+	p[3] = (dev->se_sub_dev->se_dev_attrib.emulate_rest_reord == 1) ? 0x00 : 0x10;
+	/*
+	 * From spc4r17, section 7.4.6 Control mode Page
+	 *
+	 * Unit Attention interlocks control (UN_INTLCK_CTRL) to code 00b
+	 *
+	 * 00b: The logical unit shall clear any unit attention condition
+	 * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
+	 * status and shall not establish a unit attention condition when a com-
+	 * mand is completed with BUSY, TASK SET FULL, or RESERVATION CONFLICT
+	 * status.
+	 *
+	 * 10b: The logical unit shall not clear any unit attention condition
+	 * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
+	 * status and shall not establish a unit attention condition when
+	 * a command is completed with BUSY, TASK SET FULL, or RESERVATION
+	 * CONFLICT status.
+	 *
+	 * 11b a The logical unit shall not clear any unit attention condition
+	 * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
+	 * status and shall establish a unit attention condition for the
+	 * initiator port associated with the I_T nexus on which the BUSY,
+	 * TASK SET FULL, or RESERVATION CONFLICT status is being returned.
+	 * Depending on the status, the additional sense code shall be set to
+	 * PREVIOUS BUSY STATUS, PREVIOUS TASK SET FULL STATUS, or PREVIOUS
+	 * RESERVATION CONFLICT STATUS. Until it is cleared by a REQUEST SENSE
+	 * command, a unit attention condition shall be established only once
+	 * for a BUSY, TASK SET FULL, or RESERVATION CONFLICT status regardless
+	 * to the number of commands completed with one of those status codes.
+	 */
+	p[4] = (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 2) ? 0x30 :
+	       (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 1) ? 0x20 : 0x00;
+	/*
+	 * From spc4r17, section 7.4.6 Control mode Page
+	 *
+	 * Task Aborted Status (TAS) bit set to zero.
+	 *
+	 * A task aborted status (TAS) bit set to zero specifies that aborted
+	 * tasks shall be terminated by the device server without any response
+	 * to the application client. A TAS bit set to one specifies that tasks
+	 * aborted by the actions of an I_T nexus other than the I_T nexus on
+	 * which the command was received shall be completed with TASK ABORTED
+	 * status (see SAM-4).
+	 */
+	p[5] = (dev->se_sub_dev->se_dev_attrib.emulate_tas) ? 0x40 : 0x00;
+	p[8] = 0xff;
+	p[9] = 0xff;
+	p[11] = 30;
+
+	return 12;
+}
+
+static int spc_modesense_caching(struct se_device *dev, unsigned char *p)
+{
+	p[0] = 0x08;
+	p[1] = 0x12;
+	if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0)
+		p[2] = 0x04; /* Write Cache Enable */
+	p[12] = 0x20; /* Disabled Read Ahead */
+
+	return 20;
+}
+
+static void spc_modesense_write_protect(unsigned char *buf, int type)
+{
+	/*
+	 * I believe that the WP bit (bit 7) in the mode header is the same for
+	 * all device types..
+	 */
+	switch (type) {
+	case TYPE_DISK:
+	case TYPE_TAPE:
+	default:
+		buf[0] |= 0x80; /* WP bit */
+		break;
+	}
+}
+
+static void spc_modesense_dpofua(unsigned char *buf, int type)
+{
+	switch (type) {
+	case TYPE_DISK:
+		buf[0] |= 0x10; /* DPOFUA bit */
+		break;
+	default:
+		break;
+	}
+}
+
+static int spc_emulate_modesense(struct se_cmd *cmd)
+{
+	struct se_device *dev = cmd->se_dev;
+	char *cdb = cmd->t_task_cdb;
+	unsigned char *rbuf;
+	int type = dev->transport->get_device_type(dev);
+	int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10);
+	int offset = ten ? 8 : 4;
+	int length = 0;
+	unsigned char buf[SE_MODE_PAGE_BUF];
+
+	memset(buf, 0, SE_MODE_PAGE_BUF);
+
+	switch (cdb[2] & 0x3f) {
+	case 0x01:
+		length = spc_modesense_rwrecovery(&buf[offset]);
+		break;
+	case 0x08:
+		length = spc_modesense_caching(dev, &buf[offset]);
+		break;
+	case 0x0a:
+		length = spc_modesense_control(dev, &buf[offset]);
+		break;
+	case 0x3f:
+		length = spc_modesense_rwrecovery(&buf[offset]);
+		length += spc_modesense_caching(dev, &buf[offset+length]);
+		length += spc_modesense_control(dev, &buf[offset+length]);
+		break;
+	default:
+		pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n",
+		       cdb[2] & 0x3f, cdb[3]);
+		cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE;
+		return -EINVAL;
+	}
+	offset += length;
+
+	if (ten) {
+		offset -= 2;
+		buf[0] = (offset >> 8) & 0xff;
+		buf[1] = offset & 0xff;
+
+		if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
+		    (cmd->se_deve &&
+		    (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
+			spc_modesense_write_protect(&buf[3], type);
+
+		if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) &&
+		    (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0))
+			spc_modesense_dpofua(&buf[3], type);
+
+		if ((offset + 2) > cmd->data_length)
+			offset = cmd->data_length;
+
+	} else {
+		offset -= 1;
+		buf[0] = offset & 0xff;
+
+		if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
+		    (cmd->se_deve &&
+		    (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
+			spc_modesense_write_protect(&buf[2], type);
+
+		if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) &&
+		    (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0))
+			spc_modesense_dpofua(&buf[2], type);
+
+		if ((offset + 1) > cmd->data_length)
+			offset = cmd->data_length;
+	}
+
+	rbuf = transport_kmap_data_sg(cmd);
+	memcpy(rbuf, buf, offset);
+	transport_kunmap_data_sg(cmd);
+
+	target_complete_cmd(cmd, GOOD);
+	return 0;
+}
+
+static int spc_emulate_request_sense(struct se_cmd *cmd)
+{
+	unsigned char *cdb = cmd->t_task_cdb;
+	unsigned char *buf;
+	u8 ua_asc = 0, ua_ascq = 0;
+	int err = 0;
+
+	if (cdb[1] & 0x01) {
+		pr_err("REQUEST_SENSE description emulation not"
+			" supported\n");
+		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+		return -ENOSYS;
+	}
+
+	buf = transport_kmap_data_sg(cmd);
+
+	if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) {
+		/*
+		 * CURRENT ERROR, UNIT ATTENTION
+		 */
+		buf[0] = 0x70;
+		buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
+
+		if (cmd->data_length < 18) {
+			buf[7] = 0x00;
+			err = -EINVAL;
+			goto end;
+		}
+		/*
+		 * The Additional Sense Code (ASC) from the UNIT ATTENTION
+		 */
+		buf[SPC_ASC_KEY_OFFSET] = ua_asc;
+		buf[SPC_ASCQ_KEY_OFFSET] = ua_ascq;
+		buf[7] = 0x0A;
+	} else {
+		/*
+		 * CURRENT ERROR, NO SENSE
+		 */
+		buf[0] = 0x70;
+		buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE;
+
+		if (cmd->data_length < 18) {
+			buf[7] = 0x00;
+			err = -EINVAL;
+			goto end;
+		}
+		/*
+		 * NO ADDITIONAL SENSE INFORMATION
+		 */
+		buf[SPC_ASC_KEY_OFFSET] = 0x00;
+		buf[7] = 0x0A;
+	}
+
+end:
+	transport_kunmap_data_sg(cmd);
+	target_complete_cmd(cmd, GOOD);
+	return 0;
+}
+
+static int spc_emulate_testunitready(struct se_cmd *cmd)
+{
+	target_complete_cmd(cmd, GOOD);
+	return 0;
+}
+
+int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
+{
+	struct se_device *dev = cmd->se_dev;
+	struct se_subsystem_dev *su_dev = dev->se_sub_dev;
+	unsigned char *cdb = cmd->t_task_cdb;
+
+	switch (cdb[0]) {
+	case MODE_SELECT:
+		*size = cdb[4];
+		break;
+	case MODE_SELECT_10:
+		*size = (cdb[7] << 8) + cdb[8];
+		break;
+	case MODE_SENSE:
+		*size = cdb[4];
+		cmd->execute_cmd = spc_emulate_modesense;
+		break;
+	case MODE_SENSE_10:
+		*size = (cdb[7] << 8) + cdb[8];
+		cmd->execute_cmd = spc_emulate_modesense;
+		break;
+	case LOG_SELECT:
+	case LOG_SENSE:
+		*size = (cdb[7] << 8) + cdb[8];
+		break;
+	case PERSISTENT_RESERVE_IN:
+		if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
+			cmd->execute_cmd = target_scsi3_emulate_pr_in;
+		*size = (cdb[7] << 8) + cdb[8];
+		break;
+	case PERSISTENT_RESERVE_OUT:
+		if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
+			cmd->execute_cmd = target_scsi3_emulate_pr_out;
+		*size = (cdb[7] << 8) + cdb[8];
+		break;
+	case RELEASE:
+	case RELEASE_10:
+		if (cdb[0] == RELEASE_10)
+			*size = (cdb[7] << 8) | cdb[8];
+		else
+			*size = cmd->data_length;
+
+		if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
+			cmd->execute_cmd = target_scsi2_reservation_release;
+		break;
+	case RESERVE:
+	case RESERVE_10:
+		/*
+		 * The SPC-2 RESERVE does not contain a size in the SCSI CDB.
+		 * Assume the passthrough or $FABRIC_MOD will tell us about it.
+		 */
+		if (cdb[0] == RESERVE_10)
+			*size = (cdb[7] << 8) | cdb[8];
+		else
+			*size = cmd->data_length;
+
+		/*
+		 * Setup the legacy emulated handler for SPC-2 and
+		 * >= SPC-3 compatible reservation handling (CRH=1)
+		 * Otherwise, we assume the underlying SCSI logic is
+		 * is running in SPC_PASSTHROUGH, and wants reservations
+		 * emulation disabled.
+		 */
+		if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
+			cmd->execute_cmd = target_scsi2_reservation_reserve;
+		break;
+	case REQUEST_SENSE:
+		*size = cdb[4];
+		cmd->execute_cmd = spc_emulate_request_sense;
+		break;
+	case INQUIRY:
+		*size = (cdb[3] << 8) + cdb[4];
+
+		/*
+		 * Do implict HEAD_OF_QUEUE processing for INQUIRY.
+		 * See spc4r17 section 5.3
+		 */
+		if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+			cmd->sam_task_attr = MSG_HEAD_TAG;
+		cmd->execute_cmd = spc_emulate_inquiry;
+		break;
+	case SECURITY_PROTOCOL_IN:
+	case SECURITY_PROTOCOL_OUT:
+		*size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+		break;
+	case EXTENDED_COPY:
+	case READ_ATTRIBUTE:
+	case RECEIVE_COPY_RESULTS:
+	case WRITE_ATTRIBUTE:
+		*size = (cdb[10] << 24) | (cdb[11] << 16) |
+		       (cdb[12] << 8) | cdb[13];
+		break;
+	case RECEIVE_DIAGNOSTIC:
+	case SEND_DIAGNOSTIC:
+		*size = (cdb[3] << 8) | cdb[4];
+		break;
+	case WRITE_BUFFER:
+		*size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
+		break;
+	case REPORT_LUNS:
+		cmd->execute_cmd = target_report_luns;
+		*size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+		/*
+		 * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS
+		 * See spc4r17 section 5.3
+		 */
+		if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+			cmd->sam_task_attr = MSG_HEAD_TAG;
+		break;
+	case TEST_UNIT_READY:
+		cmd->execute_cmd = spc_emulate_testunitready;
+		*size = 0;
+		break;
+	case MAINTENANCE_IN:
+		if (dev->transport->get_device_type(dev) != TYPE_ROM) {
+			/*
+			 * MAINTENANCE_IN from SCC-2
+			 * Check for emulated MI_REPORT_TARGET_PGS
+			 */
+			if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS &&
+			    su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
+				cmd->execute_cmd =
+					target_emulate_report_target_port_groups;
+			}
+			*size = get_unaligned_be32(&cdb[6]);
+		} else {
+			/*
+			 * GPCMD_SEND_KEY from multi media commands
+			 */
+			*size = get_unaligned_be16(&cdb[8]);
+		}
+		break;
+	case MAINTENANCE_OUT:
+		if (dev->transport->get_device_type(dev) != TYPE_ROM) {
+			/*
+			 * MAINTENANCE_OUT from SCC-2
+			 * Check for emulated MO_SET_TARGET_PGS.
+			 */
+			if (cdb[1] == MO_SET_TARGET_PGS &&
+			    su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
+				cmd->execute_cmd =
+					target_emulate_set_target_port_groups;
+			}
+			*size = get_unaligned_be32(&cdb[6]);
+		} else {
+			/*
+			 * GPCMD_SEND_KEY from multi media commands
+			 */
+			*size = get_unaligned_be16(&cdb[8]);
+		}
+		break;
+	default:
+		pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode"
+			" 0x%02x, sending CHECK_CONDITION.\n",
+			cmd->se_tfo->get_fabric_name(), cdb[0]);
+		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(spc_parse_cdb);
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 84caf1b..4185db1 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -295,9 +295,6 @@ static void core_tmr_drain_state_list(
 
 		list_move_tail(&cmd->state_list, &drain_task_list);
 		cmd->state_active = false;
-
-		if (!list_empty(&cmd->execute_list))
-			__target_remove_from_execute_list(cmd);
 	}
 	spin_unlock_irqrestore(&dev->execute_task_lock, flags);
 
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 634d0f3..803ac52 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -68,7 +68,6 @@ struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
 
 static int transport_generic_write_pending(struct se_cmd *);
 static int transport_processing_thread(void *param);
-static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *);
 static void transport_complete_task_attr(struct se_cmd *cmd);
 static void transport_handle_queue_full(struct se_cmd *cmd,
 		struct se_device *dev);
@@ -742,65 +741,6 @@ static void target_add_to_state_list(struct se_cmd *cmd)
 	spin_unlock_irqrestore(&dev->execute_task_lock, flags);
 }
 
-static void __target_add_to_execute_list(struct se_cmd *cmd)
-{
-	struct se_device *dev = cmd->se_dev;
-	bool head_of_queue = false;
-
-	if (!list_empty(&cmd->execute_list))
-		return;
-
-	if (dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED &&
-	    cmd->sam_task_attr == MSG_HEAD_TAG)
-		head_of_queue = true;
-
-	if (head_of_queue)
-		list_add(&cmd->execute_list, &dev->execute_list);
-	else
-		list_add_tail(&cmd->execute_list, &dev->execute_list);
-
-	atomic_inc(&dev->execute_tasks);
-
-	if (cmd->state_active)
-		return;
-
-	if (head_of_queue)
-		list_add(&cmd->state_list, &dev->state_list);
-	else
-		list_add_tail(&cmd->state_list, &dev->state_list);
-
-	cmd->state_active = true;
-}
-
-static void target_add_to_execute_list(struct se_cmd *cmd)
-{
-	unsigned long flags;
-	struct se_device *dev = cmd->se_dev;
-
-	spin_lock_irqsave(&dev->execute_task_lock, flags);
-	__target_add_to_execute_list(cmd);
-	spin_unlock_irqrestore(&dev->execute_task_lock, flags);
-}
-
-void __target_remove_from_execute_list(struct se_cmd *cmd)
-{
-	list_del_init(&cmd->execute_list);
-	atomic_dec(&cmd->se_dev->execute_tasks);
-}
-
-static void target_remove_from_execute_list(struct se_cmd *cmd)
-{
-	struct se_device *dev = cmd->se_dev;
-	unsigned long flags;
-
-	if (WARN_ON(list_empty(&cmd->execute_list)))
-		return;
-
-	spin_lock_irqsave(&dev->execute_task_lock, flags);
-	__target_remove_from_execute_list(cmd);
-	spin_unlock_irqrestore(&dev->execute_task_lock, flags);
-}
-
 /*
  * Handle QUEUE_FULL / -EAGAIN and -ENOMEM status
  */
@@ -874,8 +814,7 @@ void transport_dump_dev_state(
 		break;
 	}
 
-	*bl += sprintf(b + *bl, "  Execute/Max Queue Depth: %d/%d",
-		atomic_read(&dev->execute_tasks), dev->queue_depth);
+	*bl += sprintf(b + *bl, "  Max Queue Depth: %d", dev->queue_depth);
 	*bl += sprintf(b + *bl, "  SectorSize: %u  HwMaxSectors: %u\n",
 		dev->se_sub_dev->se_dev_attrib.block_size,
 		dev->se_sub_dev->se_dev_attrib.hw_max_sectors);
@@ -1222,7 +1161,6 @@ struct se_device *transport_add_device_to_core_hba(
 	INIT_LIST_HEAD(&dev->dev_list);
 	INIT_LIST_HEAD(&dev->dev_sep_list);
 	INIT_LIST_HEAD(&dev->dev_tmr_list);
-	INIT_LIST_HEAD(&dev->execute_list);
 	INIT_LIST_HEAD(&dev->delayed_cmd_list);
 	INIT_LIST_HEAD(&dev->state_list);
 	INIT_LIST_HEAD(&dev->qf_cmd_list);
@@ -1315,35 +1253,54 @@ out:
 }
 EXPORT_SYMBOL(transport_add_device_to_core_hba);
 
-/*	transport_generic_prepare_cdb():
- *
- *	Since the Initiator sees iSCSI devices as LUNs,  the SCSI CDB will
- *	contain the iSCSI LUN in bits 7-5 of byte 1 as per SAM-2.
- *	The point of this is since we are mapping iSCSI LUNs to
- *	SCSI Target IDs having a non-zero LUN in the CDB will throw the
- *	devices and HBAs for a loop.
- */
-static inline void transport_generic_prepare_cdb(
-	unsigned char *cdb)
+int target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
 {
-	switch (cdb[0]) {
-	case READ_10: /* SBC - RDProtect */
-	case READ_12: /* SBC - RDProtect */
-	case READ_16: /* SBC - RDProtect */
-	case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
-	case VERIFY: /* SBC - VRProtect */
-	case VERIFY_16: /* SBC - VRProtect */
-	case WRITE_VERIFY: /* SBC - VRProtect */
-	case WRITE_VERIFY_12: /* SBC - VRProtect */
-	case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
-		break;
-	default:
-		cdb[1] &= 0x1f; /* clear logical unit number */
-		break;
+	struct se_device *dev = cmd->se_dev;
+
+	if (cmd->unknown_data_length) {
+		cmd->data_length = size;
+	} else if (size != cmd->data_length) {
+		pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
+			" %u does not match SCSI CDB Length: %u for SAM Opcode:"
+			" 0x%02x\n", cmd->se_tfo->get_fabric_name(),
+				cmd->data_length, size, cmd->t_task_cdb[0]);
+
+		cmd->cmd_spdtl = size;
+
+		if (cmd->data_direction == DMA_TO_DEVICE) {
+			pr_err("Rejecting underflow/overflow"
+					" WRITE data\n");
+			goto out_invalid_cdb_field;
+		}
+		/*
+		 * Reject READ_* or WRITE_* with overflow/underflow for
+		 * type SCF_SCSI_DATA_CDB.
+		 */
+		if (dev->se_sub_dev->se_dev_attrib.block_size != 512)  {
+			pr_err("Failing OVERFLOW/UNDERFLOW for LBA op"
+				" CDB on non 512-byte sector setup subsystem"
+				" plugin: %s\n", dev->transport->name);
+			/* Returns CHECK_CONDITION + INVALID_CDB_FIELD */
+			goto out_invalid_cdb_field;
+		}
+
+		if (size > cmd->data_length) {
+			cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
+			cmd->residual_count = (size - cmd->data_length);
+		} else {
+			cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
+			cmd->residual_count = (cmd->data_length - size);
+		}
+		cmd->data_length = size;
 	}
-}
 
-static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *);
+	return 0;
+
+out_invalid_cdb_field:
+	cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+	cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+	return -EINVAL;
+}
 
 /*
  * Used by fabric modules containing a local struct se_cmd within their
@@ -1363,7 +1320,6 @@ void transport_init_se_cmd(
 	INIT_LIST_HEAD(&cmd->se_qf_node);
 	INIT_LIST_HEAD(&cmd->se_queue_node);
 	INIT_LIST_HEAD(&cmd->se_cmd_list);
-	INIT_LIST_HEAD(&cmd->execute_list);
 	INIT_LIST_HEAD(&cmd->state_list);
 	init_completion(&cmd->transport_lun_fe_stop_comp);
 	init_completion(&cmd->transport_lun_stop_comp);
@@ -1418,9 +1374,12 @@ int target_setup_cmd_from_cdb(
 	struct se_cmd *cmd,
 	unsigned char *cdb)
 {
+	struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
+	u32 pr_reg_type = 0;
+	u8 alua_ascq = 0;
+	unsigned long flags;
 	int ret;
 
-	transport_generic_prepare_cdb(cdb);
 	/*
 	 * Ensure that the received CDB is less than the max (252 + 8) bytes
 	 * for VARIABLE_LENGTH_CMD
@@ -1457,15 +1416,66 @@ int target_setup_cmd_from_cdb(
 	 * Copy the original CDB into cmd->
 	 */
 	memcpy(cmd->t_task_cdb, cdb, scsi_command_size(cdb));
+
+	/*
+	 * Check for an existing UNIT ATTENTION condition
+	 */
+	if (core_scsi3_ua_check(cmd, cdb) < 0) {
+		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+		cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION;
+		return -EINVAL;
+	}
+
+	ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq);
+	if (ret != 0) {
+		/*
+		 * Set SCSI additional sense code (ASC) to 'LUN Not Accessible';
+		 * The ALUA additional sense code qualifier (ASCQ) is determined
+		 * by the ALUA primary or secondary access state..
+		 */
+		if (ret > 0) {
+			pr_debug("[%s]: ALUA TG Port not available, "
+				"SenseKey: NOT_READY, ASC/ASCQ: "
+				"0x04/0x%02x\n",
+				cmd->se_tfo->get_fabric_name(), alua_ascq);
+
+			transport_set_sense_codes(cmd, 0x04, alua_ascq);
+			cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+			cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY;
+			return -EINVAL;
+		}
+		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+		return -EINVAL;
+	}
+
 	/*
-	 * Setup the received CDB based on SCSI defined opcodes and
-	 * perform unit attention, persistent reservations and ALUA
-	 * checks for virtual device backends.  The cmd->t_task_cdb
-	 * pointer is expected to be setup before we reach this point.
+	 * Check status for SPC-3 Persistent Reservations
 	 */
-	ret = transport_generic_cmd_sequencer(cmd, cdb);
+	if (su_dev->t10_pr.pr_ops.t10_reservation_check(cmd, &pr_reg_type)) {
+		if (su_dev->t10_pr.pr_ops.t10_seq_non_holder(
+					cmd, cdb, pr_reg_type) != 0) {
+			cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+			cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT;
+			cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
+			cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
+			return -EBUSY;
+		}
+		/*
+		 * This means the CDB is allowed for the SCSI Initiator port
+		 * when said port is *NOT* holding the legacy SPC-2 or
+		 * SPC-3 Persistent Reservation.
+		 */
+	}
+
+	ret = cmd->se_dev->transport->parse_cdb(cmd);
 	if (ret < 0)
 		return ret;
+
+	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE;
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
 	/*
 	 * Check for SAM Task Attribute Emulation
 	 */
@@ -1584,10 +1594,7 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
 		target_put_sess_cmd(se_sess, se_cmd);
 		return;
 	}
-	/*
-	 * Sanitize CDBs via transport_generic_cmd_sequencer() and
-	 * allocate the necessary tasks to complete the received CDB+data
-	 */
+
 	rc = target_setup_cmd_from_cdb(se_cmd, cdb);
 	if (rc != 0) {
 		transport_generic_request_failure(se_cmd);
@@ -1856,1193 +1863,169 @@ queue_full:
 }
 EXPORT_SYMBOL(transport_generic_request_failure);
 
-static inline u32 transport_lba_21(unsigned char *cdb)
+static void __target_execute_cmd(struct se_cmd *cmd)
 {
-	return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
-}
+	int error = 0;
 
-static inline u32 transport_lba_32(unsigned char *cdb)
-{
-	return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
-}
+	spin_lock_irq(&cmd->t_state_lock);
+	cmd->transport_state |= (CMD_T_BUSY|CMD_T_SENT);
+	spin_unlock_irq(&cmd->t_state_lock);
 
-static inline unsigned long long transport_lba_64(unsigned char *cdb)
-{
-	unsigned int __v1, __v2;
+	if (cmd->execute_cmd)
+		error = cmd->execute_cmd(cmd);
 
-	__v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
-	__v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+	if (error) {
+		spin_lock_irq(&cmd->t_state_lock);
+		cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
+		spin_unlock_irq(&cmd->t_state_lock);
 
-	return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+		transport_generic_request_failure(cmd);
+	}
 }
 
-/*
- * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs
- */
-static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
+static void target_execute_cmd(struct se_cmd *cmd)
 {
-	unsigned int __v1, __v2;
-
-	__v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15];
-	__v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19];
-
-	return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
-}
+	struct se_device *dev = cmd->se_dev;
 
-static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd)
-{
-	unsigned long flags;
+	if (transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING))
+		return;
 
-	spin_lock_irqsave(&se_cmd->t_state_lock, flags);
-	se_cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE;
-	spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
-}
+	if (dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED)
+		goto execute;
 
-/*
- * Called from Fabric Module context from transport_execute_tasks()
- *
- * The return of this function determins if the tasks from struct se_cmd
- * get added to the execution queue in transport_execute_tasks(),
- * or are added to the delayed or ordered lists here.
- */
-static inline int transport_execute_task_attr(struct se_cmd *cmd)
-{
-	if (cmd->se_dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED)
-		return 1;
 	/*
 	 * Check for the existence of HEAD_OF_QUEUE, and if true return 1
 	 * to allow the passed struct se_cmd list of tasks to the front of the list.
 	 */
-	 if (cmd->sam_task_attr == MSG_HEAD_TAG) {
-		pr_debug("Added HEAD_OF_QUEUE for CDB:"
-			" 0x%02x, se_ordered_id: %u\n",
-			cmd->t_task_cdb[0],
-			cmd->se_ordered_id);
-		return 1;
-	} else if (cmd->sam_task_attr == MSG_ORDERED_TAG) {
-		atomic_inc(&cmd->se_dev->dev_ordered_sync);
+	switch (cmd->sam_task_attr) {
+	case MSG_HEAD_TAG:
+		pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x, "
+			 "se_ordered_id: %u\n",
+			 cmd->t_task_cdb[0], cmd->se_ordered_id);
+		goto execute;
+	case MSG_ORDERED_TAG:
+		atomic_inc(&dev->dev_ordered_sync);
 		smp_mb__after_atomic_inc();
 
-		pr_debug("Added ORDERED for CDB: 0x%02x to ordered"
-				" list, se_ordered_id: %u\n",
-				cmd->t_task_cdb[0],
-				cmd->se_ordered_id);
+		pr_debug("Added ORDERED for CDB: 0x%02x to ordered list, "
+			 " se_ordered_id: %u\n",
+			 cmd->t_task_cdb[0], cmd->se_ordered_id);
+
 		/*
-		 * Add ORDERED command to tail of execution queue if
-		 * no other older commands exist that need to be
-		 * completed first.
+		 * Execute an ORDERED command if no other older commands
+		 * exist that need to be completed first.
 		 */
-		if (!atomic_read(&cmd->se_dev->simple_cmds))
-			return 1;
-	} else {
+		if (!atomic_read(&dev->simple_cmds))
+			goto execute;
+		break;
+	default:
 		/*
 		 * For SIMPLE and UNTAGGED Task Attribute commands
 		 */
-		atomic_inc(&cmd->se_dev->simple_cmds);
+		atomic_inc(&dev->simple_cmds);
 		smp_mb__after_atomic_inc();
+		break;
 	}
-	/*
-	 * Otherwise if one or more outstanding ORDERED task attribute exist,
-	 * add the dormant task(s) built for the passed struct se_cmd to the
-	 * execution queue and become in Active state for this struct se_device.
-	 */
-	if (atomic_read(&cmd->se_dev->dev_ordered_sync) != 0) {
-		/*
-		 * Otherwise, add cmd w/ tasks to delayed cmd queue that
-		 * will be drained upon completion of HEAD_OF_QUEUE task.
-		 */
-		spin_lock(&cmd->se_dev->delayed_cmd_lock);
-		cmd->se_cmd_flags |= SCF_DELAYED_CMD_FROM_SAM_ATTR;
-		list_add_tail(&cmd->se_delayed_node,
-				&cmd->se_dev->delayed_cmd_list);
-		spin_unlock(&cmd->se_dev->delayed_cmd_lock);
+
+	if (atomic_read(&dev->dev_ordered_sync) != 0) {
+		spin_lock(&dev->delayed_cmd_lock);
+		list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list);
+		spin_unlock(&dev->delayed_cmd_lock);
 
 		pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to"
 			" delayed CMD list, se_ordered_id: %u\n",
 			cmd->t_task_cdb[0], cmd->sam_task_attr,
 			cmd->se_ordered_id);
-		/*
-		 * Return zero to let transport_execute_tasks() know
-		 * not to add the delayed tasks to the execution list.
-		 */
-		return 0;
+		return;
 	}
+
+execute:
 	/*
 	 * Otherwise, no ORDERED task attributes exist..
 	 */
-	return 1;
+	__target_execute_cmd(cmd);
 }
 
 /*
- * Called from fabric module context in transport_generic_new_cmd() and
- * transport_generic_process_write()
+ * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd
  */
-static void transport_execute_tasks(struct se_cmd *cmd)
-{
-	int add_tasks;
-	struct se_device *se_dev = cmd->se_dev;
-	/*
-	 * Call transport_cmd_check_stop() to see if a fabric exception
-	 * has occurred that prevents execution.
-	 */
-	if (!transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING)) {
-		/*
-		 * Check for SAM Task Attribute emulation and HEAD_OF_QUEUE
-		 * attribute for the tasks of the received struct se_cmd CDB
-		 */
-		add_tasks = transport_execute_task_attr(cmd);
-		if (add_tasks) {
-			__transport_execute_tasks(se_dev, cmd);
-			return;
-		}
-	}
-	__transport_execute_tasks(se_dev, NULL);
-}
-
-static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *new_cmd)
+static int transport_get_sense_data(struct se_cmd *cmd)
 {
-	int error;
-	struct se_cmd *cmd = NULL;
+	unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL;
+	struct se_device *dev = cmd->se_dev;
 	unsigned long flags;
+	u32 offset = 0;
 
-check_depth:
-	spin_lock_irq(&dev->execute_task_lock);
-	if (new_cmd != NULL)
-		__target_add_to_execute_list(new_cmd);
+	WARN_ON(!cmd->se_lun);
 
-	if (list_empty(&dev->execute_list)) {
-		spin_unlock_irq(&dev->execute_task_lock);
+	if (!dev)
 		return 0;
-	}
-	cmd = list_first_entry(&dev->execute_list, struct se_cmd, execute_list);
-	__target_remove_from_execute_list(cmd);
-	spin_unlock_irq(&dev->execute_task_lock);
 
 	spin_lock_irqsave(&cmd->t_state_lock, flags);
-	cmd->transport_state |= CMD_T_BUSY;
-	cmd->transport_state |= CMD_T_SENT;
+	if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+		return 0;
+	}
 
-	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+	if (!(cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE))
+		goto out;
 
-	if (cmd->execute_cmd)
-		error = cmd->execute_cmd(cmd);
-	else {
-		error = dev->transport->execute_cmd(cmd, cmd->t_data_sg,
-				cmd->t_data_nents, cmd->data_direction);
+	if (!dev->transport->get_sense_buffer) {
+		pr_err("dev->transport->get_sense_buffer is NULL\n");
+		goto out;
 	}
 
-	if (error != 0) {
-		spin_lock_irqsave(&cmd->t_state_lock, flags);
-		cmd->transport_state &= ~CMD_T_BUSY;
-		cmd->transport_state &= ~CMD_T_SENT;
-		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
-		transport_generic_request_failure(cmd);
+	sense_buffer = dev->transport->get_sense_buffer(cmd);
+	if (!sense_buffer) {
+		pr_err("ITT 0x%08x cmd %p: Unable to locate"
+			" sense buffer for task with sense\n",
+			cmd->se_tfo->get_task_tag(cmd), cmd);
+		goto out;
 	}
 
-	new_cmd = NULL;
-	goto check_depth;
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-	return 0;
-}
+	offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER);
 
-static inline u32 transport_get_sectors_6(
-	unsigned char *cdb,
-	struct se_cmd *cmd,
-	int *ret)
-{
-	struct se_device *dev = cmd->se_dev;
+	memcpy(&buffer[offset], sense_buffer, TRANSPORT_SENSE_BUFFER);
 
-	/*
-	 * Assume TYPE_DISK for non struct se_device objects.
-	 * Use 8-bit sector value.
-	 */
-	if (!dev)
-		goto type_disk;
+	/* Automatically padded */
+	cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
 
-	/*
-	 * Use 24-bit allocation length for TYPE_TAPE.
-	 */
-	if (dev->transport->get_device_type(dev) == TYPE_TAPE)
-		return (u32)(cdb[2] << 16) + (cdb[3] << 8) + cdb[4];
+	pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x and sense\n",
+		dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status);
+	return 0;
 
-	/*
-	 * Everything else assume TYPE_DISK Sector CDB location.
-	 * Use 8-bit sector value.  SBC-3 says:
-	 *
-	 *   A TRANSFER LENGTH field set to zero specifies that 256
-	 *   logical blocks shall be written.  Any other value
-	 *   specifies the number of logical blocks that shall be
-	 *   written.
-	 */
-type_disk:
-	return cdb[4] ? : 256;
+out:
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+	return -1;
 }
 
-static inline u32 transport_get_sectors_10(
-	unsigned char *cdb,
-	struct se_cmd *cmd,
-	int *ret)
+/*
+ * Process all commands up to the last received ORDERED task attribute which
+ * requires another blocking boundary
+ */
+static void target_restart_delayed_cmds(struct se_device *dev)
 {
-	struct se_device *dev = cmd->se_dev;
-
-	/*
-	 * Assume TYPE_DISK for non struct se_device objects.
-	 * Use 16-bit sector value.
-	 */
-	if (!dev)
-		goto type_disk;
-
-	/*
-	 * XXX_10 is not defined in SSC, throw an exception
-	 */
-	if (dev->transport->get_device_type(dev) == TYPE_TAPE) {
-		*ret = -EINVAL;
-		return 0;
-	}
-
-	/*
-	 * Everything else assume TYPE_DISK Sector CDB location.
-	 * Use 16-bit sector value.
-	 */
-type_disk:
-	return (u32)(cdb[7] << 8) + cdb[8];
-}
-
-static inline u32 transport_get_sectors_12(
-	unsigned char *cdb,
-	struct se_cmd *cmd,
-	int *ret)
-{
-	struct se_device *dev = cmd->se_dev;
-
-	/*
-	 * Assume TYPE_DISK for non struct se_device objects.
-	 * Use 32-bit sector value.
-	 */
-	if (!dev)
-		goto type_disk;
-
-	/*
-	 * XXX_12 is not defined in SSC, throw an exception
-	 */
-	if (dev->transport->get_device_type(dev) == TYPE_TAPE) {
-		*ret = -EINVAL;
-		return 0;
-	}
-
-	/*
-	 * Everything else assume TYPE_DISK Sector CDB location.
-	 * Use 32-bit sector value.
-	 */
-type_disk:
-	return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9];
-}
-
-static inline u32 transport_get_sectors_16(
-	unsigned char *cdb,
-	struct se_cmd *cmd,
-	int *ret)
-{
-	struct se_device *dev = cmd->se_dev;
-
-	/*
-	 * Assume TYPE_DISK for non struct se_device objects.
-	 * Use 32-bit sector value.
-	 */
-	if (!dev)
-		goto type_disk;
-
-	/*
-	 * Use 24-bit allocation length for TYPE_TAPE.
-	 */
-	if (dev->transport->get_device_type(dev) == TYPE_TAPE)
-		return (u32)(cdb[12] << 16) + (cdb[13] << 8) + cdb[14];
-
-type_disk:
-	return (u32)(cdb[10] << 24) + (cdb[11] << 16) +
-		    (cdb[12] << 8) + cdb[13];
-}
-
-/*
- * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants
- */
-static inline u32 transport_get_sectors_32(
-	unsigned char *cdb,
-	struct se_cmd *cmd,
-	int *ret)
-{
-	/*
-	 * Assume TYPE_DISK for non struct se_device objects.
-	 * Use 32-bit sector value.
-	 */
-	return (u32)(cdb[28] << 24) + (cdb[29] << 16) +
-		    (cdb[30] << 8) + cdb[31];
-
-}
-
-static inline u32 transport_get_size(
-	u32 sectors,
-	unsigned char *cdb,
-	struct se_cmd *cmd)
-{
-	struct se_device *dev = cmd->se_dev;
-
-	if (dev->transport->get_device_type(dev) == TYPE_TAPE) {
-		if (cdb[1] & 1) { /* sectors */
-			return dev->se_sub_dev->se_dev_attrib.block_size * sectors;
-		} else /* bytes */
-			return sectors;
-	}
-
-	pr_debug("Returning block_size: %u, sectors: %u == %u for"
-		" %s object\n", dev->se_sub_dev->se_dev_attrib.block_size,
-		sectors, dev->se_sub_dev->se_dev_attrib.block_size * sectors,
-		dev->transport->name);
-
-	return dev->se_sub_dev->se_dev_attrib.block_size * sectors;
-}
-
-static void transport_xor_callback(struct se_cmd *cmd)
-{
-	unsigned char *buf, *addr;
-	struct scatterlist *sg;
-	unsigned int offset;
-	int i;
-	int count;
-	/*
-	 * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command
-	 *
-	 * 1) read the specified logical block(s);
-	 * 2) transfer logical blocks from the data-out buffer;
-	 * 3) XOR the logical blocks transferred from the data-out buffer with
-	 *    the logical blocks read, storing the resulting XOR data in a buffer;
-	 * 4) if the DISABLE WRITE bit is set to zero, then write the logical
-	 *    blocks transferred from the data-out buffer; and
-	 * 5) transfer the resulting XOR data to the data-in buffer.
-	 */
-	buf = kmalloc(cmd->data_length, GFP_KERNEL);
-	if (!buf) {
-		pr_err("Unable to allocate xor_callback buf\n");
-		return;
-	}
-	/*
-	 * Copy the scatterlist WRITE buffer located at cmd->t_data_sg
-	 * into the locally allocated *buf
-	 */
-	sg_copy_to_buffer(cmd->t_data_sg,
-			  cmd->t_data_nents,
-			  buf,
-			  cmd->data_length);
-
-	/*
-	 * Now perform the XOR against the BIDI read memory located at
-	 * cmd->t_mem_bidi_list
-	 */
-
-	offset = 0;
-	for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) {
-		addr = kmap_atomic(sg_page(sg));
-		if (!addr)
-			goto out;
-
-		for (i = 0; i < sg->length; i++)
-			*(addr + sg->offset + i) ^= *(buf + offset + i);
-
-		offset += sg->length;
-		kunmap_atomic(addr);
-	}
-
-out:
-	kfree(buf);
-}
-
-/*
- * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd
- */
-static int transport_get_sense_data(struct se_cmd *cmd)
-{
-	unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL;
-	struct se_device *dev = cmd->se_dev;
-	unsigned long flags;
-	u32 offset = 0;
-
-	WARN_ON(!cmd->se_lun);
-
-	if (!dev)
-		return 0;
-
-	spin_lock_irqsave(&cmd->t_state_lock, flags);
-	if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
-		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-		return 0;
-	}
-
-	if (!(cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE))
-		goto out;
-
-	if (!dev->transport->get_sense_buffer) {
-		pr_err("dev->transport->get_sense_buffer is NULL\n");
-		goto out;
-	}
-
-	sense_buffer = dev->transport->get_sense_buffer(cmd);
-	if (!sense_buffer) {
-		pr_err("ITT 0x%08x cmd %p: Unable to locate"
-			" sense buffer for task with sense\n",
-			cmd->se_tfo->get_task_tag(cmd), cmd);
-		goto out;
-	}
-
-	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
-	offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER);
-
-	memcpy(&buffer[offset], sense_buffer, TRANSPORT_SENSE_BUFFER);
-
-	/* Automatically padded */
-	cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
-
-	pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x and sense\n",
-		dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status);
-	return 0;
-
-out:
-	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-	return -1;
-}
-
-static inline long long transport_dev_end_lba(struct se_device *dev)
-{
-	return dev->transport->get_blocks(dev) + 1;
-}
-
-static int transport_cmd_get_valid_sectors(struct se_cmd *cmd)
-{
-	struct se_device *dev = cmd->se_dev;
-	u32 sectors;
-
-	if (dev->transport->get_device_type(dev) != TYPE_DISK)
-		return 0;
-
-	sectors = (cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size);
-
-	if ((cmd->t_task_lba + sectors) > transport_dev_end_lba(dev)) {
-		pr_err("LBA: %llu Sectors: %u exceeds"
-			" transport_dev_end_lba(): %llu\n",
-			cmd->t_task_lba, sectors,
-			transport_dev_end_lba(dev));
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int target_check_write_same_discard(unsigned char *flags, struct se_device *dev)
-{
-	/*
-	 * Determine if the received WRITE_SAME is used to for direct
-	 * passthrough into Linux/SCSI with struct request via TCM/pSCSI
-	 * or we are signaling the use of internal WRITE_SAME + UNMAP=1
-	 * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK code.
-	 */
-	int passthrough = (dev->transport->transport_type ==
-				TRANSPORT_PLUGIN_PHBA_PDEV);
-
-	if (!passthrough) {
-		if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
-			pr_err("WRITE_SAME PBDATA and LBDATA"
-				" bits not supported for Block Discard"
-				" Emulation\n");
-			return -ENOSYS;
-		}
-		/*
-		 * Currently for the emulated case we only accept
-		 * tpws with the UNMAP=1 bit set.
-		 */
-		if (!(flags[0] & 0x08)) {
-			pr_err("WRITE_SAME w/o UNMAP bit not"
-				" supported for Block Discard Emulation\n");
-			return -ENOSYS;
-		}
-	}
-
-	return 0;
-}
-
-/*	transport_generic_cmd_sequencer():
- *
- *	Generic Command Sequencer that should work for most DAS transport
- *	drivers.
- *
- *	Called from target_setup_cmd_from_cdb() in the $FABRIC_MOD
- *	RX Thread.
- *
- *	FIXME: Need to support other SCSI OPCODES where as well.
- */
-static int transport_generic_cmd_sequencer(
-	struct se_cmd *cmd,
-	unsigned char *cdb)
-{
-	struct se_device *dev = cmd->se_dev;
-	struct se_subsystem_dev *su_dev = dev->se_sub_dev;
-	int ret = 0, sector_ret = 0, passthrough;
-	u32 sectors = 0, size = 0, pr_reg_type = 0;
-	u16 service_action;
-	u8 alua_ascq = 0;
-	/*
-	 * Check for an existing UNIT ATTENTION condition
-	 */
-	if (core_scsi3_ua_check(cmd, cdb) < 0) {
-		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-		cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION;
-		return -EINVAL;
-	}
-	/*
-	 * Check status of Asymmetric Logical Unit Assignment port
-	 */
-	ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq);
-	if (ret != 0) {
-		/*
-		 * Set SCSI additional sense code (ASC) to 'LUN Not Accessible';
-		 * The ALUA additional sense code qualifier (ASCQ) is determined
-		 * by the ALUA primary or secondary access state..
-		 */
-		if (ret > 0) {
-			pr_debug("[%s]: ALUA TG Port not available,"
-				" SenseKey: NOT_READY, ASC/ASCQ: 0x04/0x%02x\n",
-				cmd->se_tfo->get_fabric_name(), alua_ascq);
-
-			transport_set_sense_codes(cmd, 0x04, alua_ascq);
-			cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-			cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY;
-			return -EINVAL;
-		}
-		goto out_invalid_cdb_field;
-	}
-	/*
-	 * Check status for SPC-3 Persistent Reservations
-	 */
-	if (su_dev->t10_pr.pr_ops.t10_reservation_check(cmd, &pr_reg_type) != 0) {
-		if (su_dev->t10_pr.pr_ops.t10_seq_non_holder(
-					cmd, cdb, pr_reg_type) != 0) {
-			cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-			cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT;
-			cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
-			cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
-			return -EBUSY;
-		}
-		/*
-		 * This means the CDB is allowed for the SCSI Initiator port
-		 * when said port is *NOT* holding the legacy SPC-2 or
-		 * SPC-3 Persistent Reservation.
-		 */
-	}
+	for (;;) {
+		struct se_cmd *cmd;
 
-	/*
-	 * If we operate in passthrough mode we skip most CDB emulation and
-	 * instead hand the commands down to the physical SCSI device.
-	 */
-	passthrough =
-		(dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV);
-
-	switch (cdb[0]) {
-	case READ_6:
-		sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
-		if (sector_ret)
-			goto out_unsupported_cdb;
-		size = transport_get_size(sectors, cdb, cmd);
-		cmd->t_task_lba = transport_lba_21(cdb);
-		cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-		break;
-	case READ_10:
-		sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
-		if (sector_ret)
-			goto out_unsupported_cdb;
-		size = transport_get_size(sectors, cdb, cmd);
-		cmd->t_task_lba = transport_lba_32(cdb);
-		cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-		break;
-	case READ_12:
-		sectors = transport_get_sectors_12(cdb, cmd, &sector_ret);
-		if (sector_ret)
-			goto out_unsupported_cdb;
-		size = transport_get_size(sectors, cdb, cmd);
-		cmd->t_task_lba = transport_lba_32(cdb);
-		cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-		break;
-	case READ_16:
-		sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
-		if (sector_ret)
-			goto out_unsupported_cdb;
-		size = transport_get_size(sectors, cdb, cmd);
-		cmd->t_task_lba = transport_lba_64(cdb);
-		cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-		break;
-	case WRITE_6:
-		sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
-		if (sector_ret)
-			goto out_unsupported_cdb;
-		size = transport_get_size(sectors, cdb, cmd);
-		cmd->t_task_lba = transport_lba_21(cdb);
-		cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-		break;
-	case WRITE_10:
-	case WRITE_VERIFY:
-		sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
-		if (sector_ret)
-			goto out_unsupported_cdb;
-		size = transport_get_size(sectors, cdb, cmd);
-		cmd->t_task_lba = transport_lba_32(cdb);
-		if (cdb[1] & 0x8)
-			cmd->se_cmd_flags |= SCF_FUA;
-		cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-		break;
-	case WRITE_12:
-		sectors = transport_get_sectors_12(cdb, cmd, &sector_ret);
-		if (sector_ret)
-			goto out_unsupported_cdb;
-		size = transport_get_size(sectors, cdb, cmd);
-		cmd->t_task_lba = transport_lba_32(cdb);
-		if (cdb[1] & 0x8)
-			cmd->se_cmd_flags |= SCF_FUA;
-		cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-		break;
-	case WRITE_16:
-		sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
-		if (sector_ret)
-			goto out_unsupported_cdb;
-		size = transport_get_size(sectors, cdb, cmd);
-		cmd->t_task_lba = transport_lba_64(cdb);
-		if (cdb[1] & 0x8)
-			cmd->se_cmd_flags |= SCF_FUA;
-		cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-		break;
-	case XDWRITEREAD_10:
-		if ((cmd->data_direction != DMA_TO_DEVICE) ||
-		    !(cmd->se_cmd_flags & SCF_BIDI))
-			goto out_invalid_cdb_field;
-		sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
-		if (sector_ret)
-			goto out_unsupported_cdb;
-		size = transport_get_size(sectors, cdb, cmd);
-		cmd->t_task_lba = transport_lba_32(cdb);
-		cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-
-		/*
-		 * Do now allow BIDI commands for passthrough mode.
-		 */
-		if (passthrough)
-			goto out_unsupported_cdb;
-
-		/*
-		 * Setup BIDI XOR callback to be run after I/O completion.
-		 */
-		cmd->transport_complete_callback = &transport_xor_callback;
-		if (cdb[1] & 0x8)
-			cmd->se_cmd_flags |= SCF_FUA;
-		break;
-	case VARIABLE_LENGTH_CMD:
-		service_action = get_unaligned_be16(&cdb[8]);
-		switch (service_action) {
-		case XDWRITEREAD_32:
-			sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
-			if (sector_ret)
-				goto out_unsupported_cdb;
-			size = transport_get_size(sectors, cdb, cmd);
-			/*
-			 * Use WRITE_32 and READ_32 opcodes for the emulated
-			 * XDWRITE_READ_32 logic.
-			 */
-			cmd->t_task_lba = transport_lba_64_ext(cdb);
-			cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-
-			/*
-			 * Do now allow BIDI commands for passthrough mode.
-			 */
-			if (passthrough)
-				goto out_unsupported_cdb;
-
-			/*
-			 * Setup BIDI XOR callback to be run during after I/O
-			 * completion.
-			 */
-			cmd->transport_complete_callback = &transport_xor_callback;
-			if (cdb[1] & 0x8)
-				cmd->se_cmd_flags |= SCF_FUA;
-			break;
-		case WRITE_SAME_32:
-			sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
-			if (sector_ret)
-				goto out_unsupported_cdb;
-
-			if (sectors)
-				size = transport_get_size(1, cdb, cmd);
-			else {
-				pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not"
-				       " supported\n");
-				goto out_invalid_cdb_field;
-			}
-
-			cmd->t_task_lba = get_unaligned_be64(&cdb[12]);
-			cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-
-			if (target_check_write_same_discard(&cdb[10], dev) < 0)
-				goto out_unsupported_cdb;
-			if (!passthrough)
-				cmd->execute_cmd = target_emulate_write_same;
-			break;
-		default:
-			pr_err("VARIABLE_LENGTH_CMD service action"
-				" 0x%04x not supported\n", service_action);
-			goto out_unsupported_cdb;
-		}
-		break;
-	case MAINTENANCE_IN:
-		if (dev->transport->get_device_type(dev) != TYPE_ROM) {
-			/* MAINTENANCE_IN from SCC-2 */
-			/*
-			 * Check for emulated MI_REPORT_TARGET_PGS.
-			 */
-			if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS &&
-			    su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
-				cmd->execute_cmd =
-					target_emulate_report_target_port_groups;
-			}
-			size = (cdb[6] << 24) | (cdb[7] << 16) |
-			       (cdb[8] << 8) | cdb[9];
-		} else {
-			/* GPCMD_SEND_KEY from multi media commands */
-			size = (cdb[8] << 8) + cdb[9];
-		}
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case MODE_SELECT:
-		size = cdb[4];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case MODE_SELECT_10:
-		size = (cdb[7] << 8) + cdb[8];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case MODE_SENSE:
-		size = cdb[4];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		if (!passthrough)
-			cmd->execute_cmd = target_emulate_modesense;
-		break;
-	case MODE_SENSE_10:
-		size = (cdb[7] << 8) + cdb[8];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		if (!passthrough)
-			cmd->execute_cmd = target_emulate_modesense;
-		break;
-	case GPCMD_READ_BUFFER_CAPACITY:
-	case GPCMD_SEND_OPC:
-	case LOG_SELECT:
-	case LOG_SENSE:
-		size = (cdb[7] << 8) + cdb[8];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case READ_BLOCK_LIMITS:
-		size = READ_BLOCK_LEN;
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case GPCMD_GET_CONFIGURATION:
-	case GPCMD_READ_FORMAT_CAPACITIES:
-	case GPCMD_READ_DISC_INFO:
-	case GPCMD_READ_TRACK_RZONE_INFO:
-		size = (cdb[7] << 8) + cdb[8];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case PERSISTENT_RESERVE_IN:
-		if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
-			cmd->execute_cmd = target_scsi3_emulate_pr_in;
-		size = (cdb[7] << 8) + cdb[8];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case PERSISTENT_RESERVE_OUT:
-		if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
-			cmd->execute_cmd = target_scsi3_emulate_pr_out;
-		size = (cdb[7] << 8) + cdb[8];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case GPCMD_MECHANISM_STATUS:
-	case GPCMD_READ_DVD_STRUCTURE:
-		size = (cdb[8] << 8) + cdb[9];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case READ_POSITION:
-		size = READ_POSITION_LEN;
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case MAINTENANCE_OUT:
-		if (dev->transport->get_device_type(dev) != TYPE_ROM) {
-			/* MAINTENANCE_OUT from SCC-2
-			 *
-			 * Check for emulated MO_SET_TARGET_PGS.
-			 */
-			if (cdb[1] == MO_SET_TARGET_PGS &&
-			    su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
-				cmd->execute_cmd =
-					target_emulate_set_target_port_groups;
-			}
-
-			size = (cdb[6] << 24) | (cdb[7] << 16) |
-			       (cdb[8] << 8) | cdb[9];
-		} else  {
-			/* GPCMD_REPORT_KEY from multi media commands */
-			size = (cdb[8] << 8) + cdb[9];
-		}
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case INQUIRY:
-		size = (cdb[3] << 8) + cdb[4];
-		/*
-		 * Do implict HEAD_OF_QUEUE processing for INQUIRY.
-		 * See spc4r17 section 5.3
-		 */
-		if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
-			cmd->sam_task_attr = MSG_HEAD_TAG;
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		if (!passthrough)
-			cmd->execute_cmd = target_emulate_inquiry;
-		break;
-	case READ_BUFFER:
-		size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case READ_CAPACITY:
-		size = READ_CAP_LEN;
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		if (!passthrough)
-			cmd->execute_cmd = target_emulate_readcapacity;
-		break;
-	case READ_MEDIA_SERIAL_NUMBER:
-	case SECURITY_PROTOCOL_IN:
-	case SECURITY_PROTOCOL_OUT:
-		size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case SERVICE_ACTION_IN:
-		switch (cmd->t_task_cdb[1] & 0x1f) {
-		case SAI_READ_CAPACITY_16:
-			if (!passthrough)
-				cmd->execute_cmd =
-					target_emulate_readcapacity_16;
+		spin_lock(&dev->delayed_cmd_lock);
+		if (list_empty(&dev->delayed_cmd_list)) {
+			spin_unlock(&dev->delayed_cmd_lock);
 			break;
-		default:
-			if (passthrough)
-				break;
-
-			pr_err("Unsupported SA: 0x%02x\n",
-				cmd->t_task_cdb[1] & 0x1f);
-			goto out_invalid_cdb_field;
 		}
-		/*FALLTHROUGH*/
-	case ACCESS_CONTROL_IN:
-	case ACCESS_CONTROL_OUT:
-	case EXTENDED_COPY:
-	case READ_ATTRIBUTE:
-	case RECEIVE_COPY_RESULTS:
-	case WRITE_ATTRIBUTE:
-		size = (cdb[10] << 24) | (cdb[11] << 16) |
-		       (cdb[12] << 8) | cdb[13];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case RECEIVE_DIAGNOSTIC:
-	case SEND_DIAGNOSTIC:
-		size = (cdb[3] << 8) | cdb[4];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-/* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */
-#if 0
-	case GPCMD_READ_CD:
-		sectors = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
-		size = (2336 * sectors);
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-#endif
-	case READ_TOC:
-		size = cdb[8];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case REQUEST_SENSE:
-		size = cdb[4];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		if (!passthrough)
-			cmd->execute_cmd = target_emulate_request_sense;
-		break;
-	case READ_ELEMENT_STATUS:
-		size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case WRITE_BUFFER:
-		size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case RESERVE:
-	case RESERVE_10:
-		/*
-		 * The SPC-2 RESERVE does not contain a size in the SCSI CDB.
-		 * Assume the passthrough or $FABRIC_MOD will tell us about it.
-		 */
-		if (cdb[0] == RESERVE_10)
-			size = (cdb[7] << 8) | cdb[8];
-		else
-			size = cmd->data_length;
 
-		/*
-		 * Setup the legacy emulated handler for SPC-2 and
-		 * >= SPC-3 compatible reservation handling (CRH=1)
-		 * Otherwise, we assume the underlying SCSI logic is
-		 * is running in SPC_PASSTHROUGH, and wants reservations
-		 * emulation disabled.
-		 */
-		if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
-			cmd->execute_cmd = target_scsi2_reservation_reserve;
-		cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
-		break;
-	case RELEASE:
-	case RELEASE_10:
-		/*
-		 * The SPC-2 RELEASE does not contain a size in the SCSI CDB.
-		 * Assume the passthrough or $FABRIC_MOD will tell us about it.
-		*/
-		if (cdb[0] == RELEASE_10)
-			size = (cdb[7] << 8) | cdb[8];
-		else
-			size = cmd->data_length;
-
-		if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
-			cmd->execute_cmd = target_scsi2_reservation_release;
-		cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
-		break;
-	case SYNCHRONIZE_CACHE:
-	case SYNCHRONIZE_CACHE_16:
-		/*
-		 * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE
-		 */
-		if (cdb[0] == SYNCHRONIZE_CACHE) {
-			sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
-			cmd->t_task_lba = transport_lba_32(cdb);
-		} else {
-			sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
-			cmd->t_task_lba = transport_lba_64(cdb);
-		}
-		if (sector_ret)
-			goto out_unsupported_cdb;
+		cmd = list_entry(dev->delayed_cmd_list.next,
+				 struct se_cmd, se_delayed_node);
+		list_del(&cmd->se_delayed_node);
+		spin_unlock(&dev->delayed_cmd_lock);
 
-		size = transport_get_size(sectors, cdb, cmd);
-		cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
+		__target_execute_cmd(cmd);
 
-		if (passthrough)
+		if (cmd->sam_task_attr == MSG_ORDERED_TAG)
 			break;
-
-		/*
-		 * Check to ensure that LBA + Range does not exceed past end of
-		 * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
-		 */
-		if ((cmd->t_task_lba != 0) || (sectors != 0)) {
-			if (transport_cmd_get_valid_sectors(cmd) < 0)
-				goto out_invalid_cdb_field;
-		}
-		cmd->execute_cmd = target_emulate_synchronize_cache;
-		break;
-	case UNMAP:
-		size = get_unaligned_be16(&cdb[7]);
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		if (!passthrough)
-			cmd->execute_cmd = target_emulate_unmap;
-		break;
-	case WRITE_SAME_16:
-		sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
-		if (sector_ret)
-			goto out_unsupported_cdb;
-
-		if (sectors)
-			size = transport_get_size(1, cdb, cmd);
-		else {
-			pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
-			goto out_invalid_cdb_field;
-		}
-
-		cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-
-		if (target_check_write_same_discard(&cdb[1], dev) < 0)
-			goto out_unsupported_cdb;
-		if (!passthrough)
-			cmd->execute_cmd = target_emulate_write_same;
-		break;
-	case WRITE_SAME:
-		sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
-		if (sector_ret)
-			goto out_unsupported_cdb;
-
-		if (sectors)
-			size = transport_get_size(1, cdb, cmd);
-		else {
-			pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
-			goto out_invalid_cdb_field;
-		}
-
-		cmd->t_task_lba = get_unaligned_be32(&cdb[2]);
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		/*
-		 * Follow sbcr26 with WRITE_SAME (10) and check for the existence
-		 * of byte 1 bit 3 UNMAP instead of original reserved field
-		 */
-		if (target_check_write_same_discard(&cdb[1], dev) < 0)
-			goto out_unsupported_cdb;
-		if (!passthrough)
-			cmd->execute_cmd = target_emulate_write_same;
-		break;
-	case ALLOW_MEDIUM_REMOVAL:
-	case ERASE:
-	case REZERO_UNIT:
-	case SEEK_10:
-	case SPACE:
-	case START_STOP:
-	case TEST_UNIT_READY:
-	case VERIFY:
-	case WRITE_FILEMARKS:
-		cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
-		if (!passthrough)
-			cmd->execute_cmd = target_emulate_noop;
-		break;
-	case GPCMD_CLOSE_TRACK:
-	case INITIALIZE_ELEMENT_STATUS:
-	case GPCMD_LOAD_UNLOAD:
-	case GPCMD_SET_SPEED:
-	case MOVE_MEDIUM:
-		cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
-		break;
-	case REPORT_LUNS:
-		cmd->execute_cmd = target_report_luns;
-		size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
-		/*
-		 * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS
-		 * See spc4r17 section 5.3
-		 */
-		if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
-			cmd->sam_task_attr = MSG_HEAD_TAG;
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case GET_EVENT_STATUS_NOTIFICATION:
-		size = (cdb[7] << 8) | cdb[8];
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	case ATA_16:
-		/* Only support ATA passthrough to pSCSI backends.. */
-		if (!passthrough)
-			goto out_unsupported_cdb;
-
-		/* T_LENGTH */
-		switch (cdb[2] & 0x3) {
-		case 0x0:
-			sectors = 0;
-			break;
-		case 0x1:
-			sectors = (((cdb[1] & 0x1) ? cdb[3] : 0) << 8) | cdb[4];
-			break;
-		case 0x2:
-			sectors = (((cdb[1] & 0x1) ? cdb[5] : 0) << 8) | cdb[6];
-			break;
-		case 0x3:
-			pr_err("T_LENGTH=0x3 not supported for ATA_16\n");
-			goto out_invalid_cdb_field;
-		}
-
-		/* BYTE_BLOCK */
-		if (cdb[2] & 0x4) {
-			/* BLOCK T_TYPE: 512 or sector */
-			size = sectors * ((cdb[2] & 0x10) ?
-				dev->se_sub_dev->se_dev_attrib.block_size : 512);
-		} else {
-			/* BYTE */
-			size = sectors;
-		}
-		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-		break;
-	default:
-		pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode"
-			" 0x%02x, sending CHECK_CONDITION.\n",
-			cmd->se_tfo->get_fabric_name(), cdb[0]);
-		goto out_unsupported_cdb;
 	}
-
-	if (cmd->unknown_data_length)
-		cmd->data_length = size;
-
-	if (size != cmd->data_length) {
-		pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
-			" %u does not match SCSI CDB Length: %u for SAM Opcode:"
-			" 0x%02x\n", cmd->se_tfo->get_fabric_name(),
-				cmd->data_length, size, cdb[0]);
-
-		cmd->cmd_spdtl = size;
-
-		if (cmd->data_direction == DMA_TO_DEVICE) {
-			pr_err("Rejecting underflow/overflow"
-					" WRITE data\n");
-			goto out_invalid_cdb_field;
-		}
-		/*
-		 * Reject READ_* or WRITE_* with overflow/underflow for
-		 * type SCF_SCSI_DATA_SG_IO_CDB.
-		 */
-		if (!ret && (dev->se_sub_dev->se_dev_attrib.block_size != 512))  {
-			pr_err("Failing OVERFLOW/UNDERFLOW for LBA op"
-				" CDB on non 512-byte sector setup subsystem"
-				" plugin: %s\n", dev->transport->name);
-			/* Returns CHECK_CONDITION + INVALID_CDB_FIELD */
-			goto out_invalid_cdb_field;
-		}
-
-		if (size > cmd->data_length) {
-			cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
-			cmd->residual_count = (size - cmd->data_length);
-		} else {
-			cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
-			cmd->residual_count = (cmd->data_length - size);
-		}
-		cmd->data_length = size;
-	}
-
-	if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
-		if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) {
-			printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
-				" big sectors %u exceeds fabric_max_sectors:"
-				" %u\n", cdb[0], sectors,
-				su_dev->se_dev_attrib.fabric_max_sectors);
-			goto out_invalid_cdb_field;
-		}
-		if (sectors > su_dev->se_dev_attrib.hw_max_sectors) {
-			printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
-				" big sectors %u exceeds backend hw_max_sectors:"
-				" %u\n", cdb[0], sectors,
-				su_dev->se_dev_attrib.hw_max_sectors);
-			goto out_invalid_cdb_field;
-		}
-	}
-
-	/* reject any command that we don't have a handler for */
-	if (!(passthrough || cmd->execute_cmd ||
-	     (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
-		goto out_unsupported_cdb;
-
-	transport_set_supported_SAM_opcode(cmd);
-	return ret;
-
-out_unsupported_cdb:
-	cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-	cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
-	return -EINVAL;
-out_invalid_cdb_field:
-	cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-	cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
-	return -EINVAL;
 }
 
 /*
@@ -3052,8 +2035,6 @@ out_invalid_cdb_field:
 static void transport_complete_task_attr(struct se_cmd *cmd)
 {
 	struct se_device *dev = cmd->se_dev;
-	struct se_cmd *cmd_p, *cmd_tmp;
-	int new_active_tasks = 0;
 
 	if (cmd->sam_task_attr == MSG_SIMPLE_TAG) {
 		atomic_dec(&dev->simple_cmds);
@@ -3075,38 +2056,8 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
 		pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED:"
 			" %u\n", dev->dev_cur_ordered_id, cmd->se_ordered_id);
 	}
-	/*
-	 * Process all commands up to the last received
-	 * ORDERED task attribute which requires another blocking
-	 * boundary
-	 */
-	spin_lock(&dev->delayed_cmd_lock);
-	list_for_each_entry_safe(cmd_p, cmd_tmp,
-			&dev->delayed_cmd_list, se_delayed_node) {
 
-		list_del(&cmd_p->se_delayed_node);
-		spin_unlock(&dev->delayed_cmd_lock);
-
-		pr_debug("Calling add_tasks() for"
-			" cmd_p: 0x%02x Task Attr: 0x%02x"
-			" Dormant -> Active, se_ordered_id: %u\n",
-			cmd_p->t_task_cdb[0],
-			cmd_p->sam_task_attr, cmd_p->se_ordered_id);
-
-		target_add_to_execute_list(cmd_p);
-		new_active_tasks++;
-
-		spin_lock(&dev->delayed_cmd_lock);
-		if (cmd_p->sam_task_attr == MSG_ORDERED_TAG)
-			break;
-	}
-	spin_unlock(&dev->delayed_cmd_lock);
-	/*
-	 * If new tasks have become active, wake up the transport thread
-	 * to do the processing of the Active tasks.
-	 */
-	if (new_active_tasks != 0)
-		wake_up_interruptible(&dev->dev_queue_obj.thread_wq);
+	target_restart_delayed_cmds(dev);
 }
 
 static void transport_complete_qf(struct se_cmd *cmd)
@@ -3365,31 +2316,27 @@ int transport_generic_map_mem_to_cmd(
 	if (!sgl || !sgl_count)
 		return 0;
 
-	if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) ||
-	    (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) {
-		/*
-		 * Reject SCSI data overflow with map_mem_to_cmd() as incoming
-		 * scatterlists already have been set to follow what the fabric
-		 * passes for the original expected data transfer length.
-		 */
-		if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
-			pr_warn("Rejecting SCSI DATA overflow for fabric using"
-				" SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC\n");
-			cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-			cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
-			return -EINVAL;
-		}
+	/*
+	 * Reject SCSI data overflow with map_mem_to_cmd() as incoming
+	 * scatterlists already have been set to follow what the fabric
+	 * passes for the original expected data transfer length.
+	 */
+	if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
+		pr_warn("Rejecting SCSI DATA overflow for fabric using"
+			" SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC\n");
+		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+		return -EINVAL;
+	}
 
-		cmd->t_data_sg = sgl;
-		cmd->t_data_nents = sgl_count;
+	cmd->t_data_sg = sgl;
+	cmd->t_data_nents = sgl_count;
 
-		if (sgl_bidi && sgl_bidi_count) {
-			cmd->t_bidi_data_sg = sgl_bidi;
-			cmd->t_bidi_data_nents = sgl_bidi_count;
-		}
-		cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
+	if (sgl_bidi && sgl_bidi_count) {
+		cmd->t_bidi_data_sg = sgl_bidi;
+		cmd->t_bidi_data_nents = sgl_bidi_count;
 	}
-
+	cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
 	return 0;
 }
 EXPORT_SYMBOL(transport_generic_map_mem_to_cmd);
@@ -3461,7 +2408,7 @@ transport_generic_get_mem(struct se_cmd *cmd)
 	cmd->t_data_nents = nents;
 	sg_init_table(cmd->t_data_sg, nents);
 
-	zero_flag = cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB ? 0 : __GFP_ZERO;
+	zero_flag = cmd->se_cmd_flags & SCF_SCSI_DATA_CDB ? 0 : __GFP_ZERO;
 
 	while (length) {
 		u32 page_len = min_t(u32, length, PAGE_SIZE);
@@ -3492,7 +2439,6 @@ out:
  */
 int transport_generic_new_cmd(struct se_cmd *cmd)
 {
-	struct se_device *dev = cmd->se_dev;
 	int ret = 0;
 
 	/*
@@ -3508,8 +2454,7 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
 	}
 
 	/* Workaround for handling zero-length control CDBs */
-	if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) &&
-	    !cmd->data_length) {
+	if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->data_length) {
 		spin_lock_irq(&cmd->t_state_lock);
 		cmd->t_state = TRANSPORT_COMPLETE;
 		cmd->transport_state |= CMD_T_ACTIVE;
@@ -3527,17 +2472,6 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
 		return 0;
 	}
 
-	if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
-		struct se_dev_attrib *attr = &dev->se_sub_dev->se_dev_attrib;
-
-		if (transport_cmd_get_valid_sectors(cmd) < 0)
-			return -EINVAL;
-
-		BUG_ON(cmd->data_length % attr->block_size);
-		BUG_ON(DIV_ROUND_UP(cmd->data_length, attr->block_size) >
-			attr->hw_max_sectors);
-	}
-
 	atomic_inc(&cmd->t_fe_count);
 
 	/*
@@ -3545,15 +2479,13 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
 	 *
 	 * The command will be added to the execution queue after its write
 	 * data has arrived.
-	 */
-	if (cmd->data_direction == DMA_TO_DEVICE) {
-		target_add_to_state_list(cmd);
-		return transport_generic_write_pending(cmd);
-	}
-	/*
+	 *
 	 * Everything else but a WRITE, add the command to the execution queue.
 	 */
-	transport_execute_tasks(cmd);
+	target_add_to_state_list(cmd);
+	if (cmd->data_direction == DMA_TO_DEVICE)
+		return transport_generic_write_pending(cmd);
+	target_execute_cmd(cmd);
 	return 0;
 
 out_fail:
@@ -3569,7 +2501,7 @@ EXPORT_SYMBOL(transport_generic_new_cmd);
  */
 void transport_generic_process_write(struct se_cmd *cmd)
 {
-	transport_execute_tasks(cmd);
+	target_execute_cmd(cmd);
 }
 EXPORT_SYMBOL(transport_generic_process_write);
 
@@ -3805,12 +2737,8 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)
 	    (cmd->transport_state & CMD_T_SENT)) {
 		if (!target_stop_cmd(cmd, &flags))
 			ret++;
-		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-	} else {
-		spin_unlock_irqrestore(&cmd->t_state_lock,
-				flags);
-		target_remove_from_execute_list(cmd);
 	}
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
 	pr_debug("ConfigFS: cmd: %p stop tasks ret:"
 			" %d\n", cmd, ret);
@@ -3967,10 +2895,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd)
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 		return false;
 	}
-	/*
-	 * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE
-	 * has been set in transport_set_supported_SAM_opcode().
-	 */
+
 	if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) &&
 	    !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index f03fb97..164b09a 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -215,7 +215,7 @@ int ft_write_pending(struct se_cmd *se_cmd)
 		 */
 		if ((ep->xid <= lport->lro_xid) &&
 		    (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) {
-			if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) &&
+			if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) &&
 			    lport->tt.ddp_target(lport, ep->xid,
 						 se_cmd->t_data_sg,
 						 se_cmd->t_data_nents))
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 514a691..3ab2bd5 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -23,6 +23,7 @@ config SPEAR_THERMAL
 	bool "SPEAr thermal sensor driver"
 	depends on THERMAL
 	depends on PLAT_SPEAR
+	depends on OF
 	help
 	  Enable this to plug the SPEAr thermal sensor driver into the Linux
 	  thermal framework
diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c
index c2e32df..5f8ee39 100644
--- a/drivers/thermal/spear_thermal.c
+++ b/drivers/thermal/spear_thermal.c
@@ -20,9 +20,9 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/platform_data/spear_thermal.h>
 #include <linux/thermal.h>
 
 #define MD_FACTOR	1000
@@ -103,21 +103,20 @@ static int spear_thermal_probe(struct platform_device *pdev)
 {
 	struct thermal_zone_device *spear_thermal = NULL;
 	struct spear_thermal_dev *stdev;
-	struct spear_thermal_pdata *pdata;
-	int ret = 0;
+	struct device_node *np = pdev->dev.of_node;
 	struct resource *stres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	int ret = 0, val;
+
+	if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) {
+		dev_err(&pdev->dev, "Failed: DT Pdata not passed\n");
+		return -EINVAL;
+	}
 
 	if (!stres) {
 		dev_err(&pdev->dev, "memory resource missing\n");
 		return -ENODEV;
 	}
 
-	pdata = dev_get_platdata(&pdev->dev);
-	if (!pdata) {
-		dev_err(&pdev->dev, "platform data is NULL\n");
-		return -EINVAL;
-	}
-
 	stdev = devm_kzalloc(&pdev->dev, sizeof(*stdev), GFP_KERNEL);
 	if (!stdev) {
 		dev_err(&pdev->dev, "kzalloc fail\n");
@@ -144,10 +143,10 @@ static int spear_thermal_probe(struct platform_device *pdev)
 		goto put_clk;
 	}
 
-	stdev->flags = pdata->thermal_flags;
+	stdev->flags = val;
 	writel_relaxed(stdev->flags, stdev->thermal_base);
 
-	spear_thermal = thermal_zone_device_register("spear_thermal", 0,
+	spear_thermal = thermal_zone_device_register("spear_thermal", 0, 0,
 				stdev, &ops, 0, 0, 0, 0);
 	if (IS_ERR(spear_thermal)) {
 		dev_err(&pdev->dev, "thermal zone device is NULL\n");
@@ -189,6 +188,12 @@ static int spear_thermal_exit(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id spear_thermal_id_table[] = {
+	{ .compatible = "st,thermal-spear1340" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, spear_thermal_id_table);
+
 static struct platform_driver spear_thermal_driver = {
 	.probe = spear_thermal_probe,
 	.remove = spear_thermal_exit,
@@ -196,6 +201,7 @@ static struct platform_driver spear_thermal_driver = {
 		.name = "spear_thermal",
 		.owner = THIS_MODULE,
 		.pm = &spear_thermal_pm_ops,
+		.of_match_table = of_match_ptr(spear_thermal_id_table),
 	},
 };
 
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 022bacb..5eb5329 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -196,6 +196,28 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
 }
 
 static ssize_t
+trip_point_temp_store(struct device *dev, struct device_attribute *attr,
+		     const char *buf, size_t count)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int trip, ret;
+	unsigned long temperature;
+
+	if (!tz->ops->set_trip_temp)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
+		return -EINVAL;
+
+	if (kstrtoul(buf, 10, &temperature))
+		return -EINVAL;
+
+	ret = tz->ops->set_trip_temp(tz, trip, temperature);
+
+	return ret ? ret : count;
+}
+
+static ssize_t
 trip_point_temp_show(struct device *dev, struct device_attribute *attr,
 		     char *buf)
 {
@@ -218,6 +240,52 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
 }
 
 static ssize_t
+trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
+		     const char *buf, size_t count)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int trip, ret;
+	unsigned long temperature;
+
+	if (!tz->ops->set_trip_hyst)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
+		return -EINVAL;
+
+	if (kstrtoul(buf, 10, &temperature))
+		return -EINVAL;
+
+	/*
+	 * We are not doing any check on the 'temperature' value
+	 * here. The driver implementing 'set_trip_hyst' has to
+	 * take care of this.
+	 */
+	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
+
+	return ret ? ret : count;
+}
+
+static ssize_t
+trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int trip, ret;
+	unsigned long temperature;
+
+	if (!tz->ops->get_trip_hyst)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
+		return -EINVAL;
+
+	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
+
+	return ret ? ret : sprintf(buf, "%ld\n", temperature);
+}
+
+static ssize_t
 passive_store(struct device *dev, struct device_attribute *attr,
 		    const char *buf, size_t count)
 {
@@ -283,33 +351,6 @@ static DEVICE_ATTR(temp, 0444, temp_show, NULL);
 static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
 static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
 
-static struct device_attribute trip_point_attrs[] = {
-	__ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL),
-	__ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL),
-	__ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL),
-	__ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL),
-	__ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL),
-	__ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL),
-	__ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL),
-	__ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL),
-	__ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL),
-	__ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL),
-	__ATTR(trip_point_10_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_10_temp, 0444, trip_point_temp_show, NULL),
-	__ATTR(trip_point_11_type, 0444, trip_point_type_show, NULL),
-	__ATTR(trip_point_11_temp, 0444, trip_point_temp_show, NULL),
-};
-
 /* sys I/F for cooling device */
 #define to_cooling_device(_dev)	\
 	container_of(_dev, struct thermal_cooling_device, device)
@@ -549,7 +590,7 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
 	temp->tz = tz;
 	hwmon->count++;
 
-	snprintf(temp->temp_input.name, THERMAL_NAME_LENGTH,
+	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
 		 "temp%d_input", hwmon->count);
 	temp->temp_input.attr.attr.name = temp->temp_input.name;
 	temp->temp_input.attr.attr.mode = 0444;
@@ -562,7 +603,8 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
 	if (tz->ops->get_crit_temp) {
 		unsigned long temperature;
 		if (!tz->ops->get_crit_temp(tz, &temperature)) {
-			snprintf(temp->temp_crit.name, THERMAL_NAME_LENGTH,
+			snprintf(temp->temp_crit.name,
+				 sizeof(temp->temp_crit.name),
 				"temp%d_crit", hwmon->count);
 			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
 			temp->temp_crit.attr.attr.mode = 0444;
@@ -1089,9 +1131,77 @@ leave:
 EXPORT_SYMBOL(thermal_zone_device_update);
 
 /**
+ * create_trip_type_attr - creates a trip point type attribute
+ * @tz:		the thermal zone device
+ * @indx:	index into the trip_type_attrs array
+ */
+static int create_trip_type_attr(struct thermal_zone_device *tz, int indx)
+{
+	char attr_name[THERMAL_NAME_LENGTH];
+
+	snprintf(attr_name, THERMAL_NAME_LENGTH, "trip_point_%d_type", indx);
+
+	sysfs_attr_init(&tz->trip_type_attrs[indx].attr);
+	tz->trip_type_attrs[indx].attr.name = attr_name;
+	tz->trip_type_attrs[indx].attr.mode = S_IRUGO;
+	tz->trip_type_attrs[indx].show = trip_point_type_show;
+
+	return device_create_file(&tz->device, &tz->trip_type_attrs[indx]);
+}
+
+/**
+ * create_trip_temp_attr - creates a trip point temp attribute
+ * @tz:		the thermal zone device
+ * @indx:	index into the trip_type_attrs array
+ * @writeable:	A flag: If 1, 'this' trip point is writeable; otherwise not
+ */
+static int create_trip_temp_attr(struct thermal_zone_device *tz,
+				int indx, int writeable)
+{
+	char attr_name[THERMAL_NAME_LENGTH];
+
+	snprintf(attr_name, THERMAL_NAME_LENGTH, "trip_point_%d_temp", indx);
+
+	sysfs_attr_init(&tz->trip_temp_attrs[indx].attr);
+	tz->trip_temp_attrs[indx].attr.name = attr_name;
+	tz->trip_temp_attrs[indx].attr.mode = S_IRUGO;
+	tz->trip_temp_attrs[indx].show = trip_point_temp_show;
+	if (writeable) {
+		tz->trip_temp_attrs[indx].attr.mode |= S_IWUSR;
+		tz->trip_temp_attrs[indx].store = trip_point_temp_store;
+	}
+
+	return device_create_file(&tz->device, &tz->trip_temp_attrs[indx]);
+}
+
+/**
+ * create_trip_hyst_attr - creates hysteresis attribute for a trip point
+ * @tz:		the thermal zone device
+ * @indx:	index into the trip_hyst_attrs array
+ */
+static int create_trip_hyst_attr(struct thermal_zone_device *tz, int indx)
+{
+	char attr_name[THERMAL_NAME_LENGTH];
+
+	snprintf(attr_name, THERMAL_NAME_LENGTH, "trip_point_%d_hyst", indx);
+
+	sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr);
+	tz->trip_hyst_attrs[indx].attr.name = attr_name;
+	tz->trip_hyst_attrs[indx].attr.mode = S_IRUGO;
+	tz->trip_hyst_attrs[indx].show = trip_point_hyst_show;
+	if (tz->ops->set_trip_hyst) {
+		tz->trip_hyst_attrs[indx].attr.mode |= S_IWUSR;
+		tz->trip_hyst_attrs[indx].store = trip_point_hyst_store;
+	}
+
+	return device_create_file(&tz->device, &tz->trip_hyst_attrs[indx]);
+}
+
+/**
  * thermal_zone_device_register - register a new thermal zone device
  * @type:	the thermal zone device type
  * @trips:	the number of trip points the thermal zone support
+ * @flag:	a bit string indicating the writeablility of trip points
  * @devdata:	private device data
  * @ops:	standard thermal zone device callbacks
  * @tc1:	thermal coefficient 1 for passive calculations
@@ -1107,7 +1217,7 @@ EXPORT_SYMBOL(thermal_zone_device_update);
  * section 11.1.5.1 of the ACPI specification 3.0.
  */
 struct thermal_zone_device *thermal_zone_device_register(char *type,
-	int trips, void *devdata,
+	int trips, int flag, void *devdata,
 	const struct thermal_zone_device_ops *ops,
 	int tc1, int tc2, int passive_delay, int polling_delay)
 {
@@ -1124,6 +1234,9 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
 	if (trips > THERMAL_MAX_TRIPS || trips < 0)
 		return ERR_PTR(-EINVAL);
 
+	if (flag >> trips)
+		return ERR_PTR(-EINVAL);
+
 	if (!ops || !ops->get_temp)
 		return ERR_PTR(-EINVAL);
 
@@ -1176,14 +1289,20 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
 	}
 
 	for (count = 0; count < trips; count++) {
-		result = device_create_file(&tz->device,
-					    &trip_point_attrs[count * 2]);
+		result = create_trip_type_attr(tz, count);
 		if (result)
-			break;
-		result = device_create_file(&tz->device,
-					    &trip_point_attrs[count * 2 + 1]);
+			goto unregister;
+		result = create_trip_temp_attr(tz, count,
+						!!(flag & (1 << count)));
 		if (result)
 			goto unregister;
+
+		if (tz->ops->get_trip_hyst) {
+			result = create_trip_hyst_attr(tz, count);
+			if (result)
+				goto unregister;
+		}
+
 		tz->ops->get_trip_type(tz, count, &trip_type);
 		if (trip_type == THERMAL_TRIP_PASSIVE)
 			passive = 1;
@@ -1261,10 +1380,11 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 		device_remove_file(&tz->device, &dev_attr_mode);
 
 	for (count = 0; count < tz->trips; count++) {
-		device_remove_file(&tz->device,
-				   &trip_point_attrs[count * 2]);
-		device_remove_file(&tz->device,
-				   &trip_point_attrs[count * 2 + 1]);
+		device_remove_file(&tz->device, &tz->trip_type_attrs[count]);
+		device_remove_file(&tz->device, &tz->trip_temp_attrs[count]);
+		if (tz->ops->get_trip_hyst)
+			device_remove_file(&tz->device,
+						&tz->trip_hyst_attrs[count]);
 	}
 	thermal_remove_hwmon_sysfs(tz);
 	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index e61cabd..cff5468 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -3289,6 +3289,7 @@ static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
 static int __init cy_detect_isa(void)
 {
 #ifdef CONFIG_ISA
+	struct cyclades_card *card;
 	unsigned short cy_isa_irq, nboard;
 	void __iomem *cy_isa_address;
 	unsigned short i, j, cy_isa_nchan;
@@ -3349,7 +3350,8 @@ static int __init cy_detect_isa(void)
 		}
 		/* fill the next cy_card structure available */
 		for (j = 0; j < NR_CARDS; j++) {
-			if (cy_card[j].base_addr == NULL)
+			card = &cy_card[j];
+			if (card->base_addr == NULL)
 				break;
 		}
 		if (j == NR_CARDS) {	/* no more cy_cards available */
@@ -3363,7 +3365,7 @@ static int __init cy_detect_isa(void)
 
 		/* allocate IRQ */
 		if (request_irq(cy_isa_irq, cyy_interrupt,
-				0, "Cyclom-Y", &cy_card[j])) {
+				0, "Cyclom-Y", card)) {
 			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
 				"could not allocate IRQ#%d.\n",
 				(unsigned long)cy_isa_address, cy_isa_irq);
@@ -3372,16 +3374,16 @@ static int __init cy_detect_isa(void)
 		}
 
 		/* set cy_card */
-		cy_card[j].base_addr = cy_isa_address;
-		cy_card[j].ctl_addr.p9050 = NULL;
-		cy_card[j].irq = (int)cy_isa_irq;
-		cy_card[j].bus_index = 0;
-		cy_card[j].first_line = cy_next_channel;
-		cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
-		cy_card[j].nports = cy_isa_nchan;
-		if (cy_init_card(&cy_card[j])) {
-			cy_card[j].base_addr = NULL;
-			free_irq(cy_isa_irq, &cy_card[j]);
+		card->base_addr = cy_isa_address;
+		card->ctl_addr.p9050 = NULL;
+		card->irq = (int)cy_isa_irq;
+		card->bus_index = 0;
+		card->first_line = cy_next_channel;
+		card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
+		card->nports = cy_isa_nchan;
+		if (cy_init_card(card)) {
+			card->base_addr = NULL;
+			free_irq(cy_isa_irq, card);
 			iounmap(cy_isa_address);
 			continue;
 		}
@@ -3695,6 +3697,7 @@ err:
 static int __devinit cy_pci_probe(struct pci_dev *pdev,
 		const struct pci_device_id *ent)
 {
+	struct cyclades_card *card;
 	void __iomem *addr0 = NULL, *addr2 = NULL;
 	char *card_name = NULL;
 	u32 uninitialized_var(mailbox);
@@ -3829,7 +3832,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 	}
 	/* fill the next cy_card structure available */
 	for (card_no = 0; card_no < NR_CARDS; card_no++) {
-		if (cy_card[card_no].base_addr == NULL)
+		card = &cy_card[card_no];
+		if (card->base_addr == NULL)
 			break;
 	}
 	if (card_no == NR_CARDS) {	/* no more cy_cards available */
@@ -3843,27 +3847,26 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
 		/* allocate IRQ */
 		retval = request_irq(irq, cyy_interrupt,
-				IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
+				IRQF_SHARED, "Cyclom-Y", card);
 		if (retval) {
 			dev_err(&pdev->dev, "could not allocate IRQ\n");
 			goto err_unmap;
 		}
-		cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
+		card->num_chips = nchan / CyPORTS_PER_CHIP;
 	} else {
 		struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
 		struct ZFW_CTRL __iomem *zfw_ctrl;
 
 		zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
 
-		cy_card[card_no].hw_ver = mailbox;
-		cy_card[card_no].num_chips = (unsigned int)-1;
-		cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
+		card->hw_ver = mailbox;
+		card->num_chips = (unsigned int)-1;
+		card->board_ctrl = &zfw_ctrl->board_ctrl;
 #ifdef CONFIG_CYZ_INTR
 		/* allocate IRQ only if board has an IRQ */
 		if (irq != 0 && irq != 255) {
 			retval = request_irq(irq, cyz_interrupt,
-					IRQF_SHARED, "Cyclades-Z",
-					&cy_card[card_no]);
+					IRQF_SHARED, "Cyclades-Z", card);
 			if (retval) {
 				dev_err(&pdev->dev, "could not allocate IRQ\n");
 				goto err_unmap;
@@ -3873,17 +3876,17 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 	}
 
 	/* set cy_card */
-	cy_card[card_no].base_addr = addr2;
-	cy_card[card_no].ctl_addr.p9050 = addr0;
-	cy_card[card_no].irq = irq;
-	cy_card[card_no].bus_index = 1;
-	cy_card[card_no].first_line = cy_next_channel;
-	cy_card[card_no].nports = nchan;
-	retval = cy_init_card(&cy_card[card_no]);
+	card->base_addr = addr2;
+	card->ctl_addr.p9050 = addr0;
+	card->irq = irq;
+	card->bus_index = 1;
+	card->first_line = cy_next_channel;
+	card->nports = nchan;
+	retval = cy_init_card(card);
 	if (retval)
 		goto err_null;
 
-	pci_set_drvdata(pdev, &cy_card[card_no]);
+	pci_set_drvdata(pdev, card);
 
 	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
 			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
@@ -3915,8 +3918,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 
 	return 0;
 err_null:
-	cy_card[card_no].base_addr = NULL;
-	free_irq(irq, &cy_card[card_no]);
+	card->base_addr = NULL;
+	free_irq(irq, card);
 err_unmap:
 	iounmap(addr0);
 	if (addr2)
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 5505ffc..b50fc1c 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -282,60 +282,98 @@ done:
 	return 0;
 }
 
-/* Traditional BSD devices */
-#ifdef CONFIG_LEGACY_PTYS
-
-static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
+		bool legacy)
 {
 	struct tty_struct *o_tty;
+	struct tty_port *ports[2];
 	int idx = tty->index;
-	int retval;
+	int retval = -ENOMEM;
 
 	o_tty = alloc_tty_struct();
-	if (!o_tty)
-		return -ENOMEM;
+	ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
+	ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
+	if (!o_tty || !ports[0] || !ports[1])
+		goto err_free_tty;
 	if (!try_module_get(driver->other->owner)) {
 		/* This cannot in fact currently happen */
-		retval = -ENOMEM;
 		goto err_free_tty;
 	}
 	initialize_tty_struct(o_tty, driver->other, idx);
 
-	/* We always use new tty termios data so we can do this
-	   the easy way .. */
-	retval = tty_init_termios(tty);
-	if (retval)
-		goto err_deinit_tty;
-
-	retval = tty_init_termios(o_tty);
-	if (retval)
-		goto err_free_termios;
+	if (legacy) {
+		/* We always use new tty termios data so we can do this
+		   the easy way .. */
+		retval = tty_init_termios(tty);
+		if (retval)
+			goto err_deinit_tty;
+
+		retval = tty_init_termios(o_tty);
+		if (retval)
+			goto err_free_termios;
+
+		driver->other->ttys[idx] = o_tty;
+		driver->ttys[idx] = tty;
+	} else {
+		tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+		if (tty->termios == NULL)
+			goto err_deinit_tty;
+		*tty->termios = driver->init_termios;
+		tty->termios_locked = tty->termios + 1;
+
+		o_tty->termios = kzalloc(sizeof(struct ktermios[2]),
+				GFP_KERNEL);
+		if (o_tty->termios == NULL)
+			goto err_free_termios;
+		*o_tty->termios = driver->other->init_termios;
+		o_tty->termios_locked = o_tty->termios + 1;
+	}
 
 	/*
 	 * Everything allocated ... set up the o_tty structure.
 	 */
-	driver->other->ttys[idx] = o_tty;
 	tty_driver_kref_get(driver->other);
 	if (driver->subtype == PTY_TYPE_MASTER)
 		o_tty->count++;
 	/* Establish the links in both directions */
 	tty->link   = o_tty;
 	o_tty->link = tty;
+	tty_port_init(ports[0]);
+	tty_port_init(ports[1]);
+	o_tty->port = ports[0];
+	tty->port = ports[1];
 
 	tty_driver_kref_get(driver);
 	tty->count++;
-	driver->ttys[idx] = tty;
 	return 0;
 err_free_termios:
-	tty_free_termios(tty);
+	if (legacy)
+		tty_free_termios(tty);
+	else
+		kfree(tty->termios);
 err_deinit_tty:
 	deinitialize_tty_struct(o_tty);
 	module_put(o_tty->driver->owner);
 err_free_tty:
+	kfree(ports[0]);
+	kfree(ports[1]);
 	free_tty_struct(o_tty);
 	return retval;
 }
 
+static void pty_cleanup(struct tty_struct *tty)
+{
+	kfree(tty->port);
+}
+
+/* Traditional BSD devices */
+#ifdef CONFIG_LEGACY_PTYS
+
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+	return pty_common_install(driver, tty, true);
+}
+
 static int pty_bsd_ioctl(struct tty_struct *tty,
 			 unsigned int cmd, unsigned long arg)
 {
@@ -366,6 +404,7 @@ static const struct tty_operations master_pty_ops_bsd = {
 	.unthrottle = pty_unthrottle,
 	.set_termios = pty_set_termios,
 	.ioctl = pty_bsd_ioctl,
+	.cleanup = pty_cleanup,
 	.resize = pty_resize
 };
 
@@ -379,6 +418,7 @@ static const struct tty_operations slave_pty_ops_bsd = {
 	.chars_in_buffer = pty_chars_in_buffer,
 	.unthrottle = pty_unthrottle,
 	.set_termios = pty_set_termios,
+	.cleanup = pty_cleanup,
 	.resize = pty_resize
 };
 
@@ -509,66 +549,17 @@ static void pty_unix98_shutdown(struct tty_struct *tty)
 
 static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
 {
-	struct tty_struct *o_tty;
-	int idx = tty->index;
-
-	o_tty = alloc_tty_struct();
-	if (!o_tty)
-		return -ENOMEM;
-	if (!try_module_get(driver->other->owner)) {
-		/* This cannot in fact currently happen */
-		goto err_free_tty;
-	}
-	initialize_tty_struct(o_tty, driver->other, idx);
-
-	tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-	if (tty->termios == NULL)
-		goto err_free_mem;
-	*tty->termios = driver->init_termios;
-	tty->termios_locked = tty->termios + 1;
-
-	o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-	if (o_tty->termios == NULL)
-		goto err_free_mem;
-	*o_tty->termios = driver->other->init_termios;
-	o_tty->termios_locked = o_tty->termios + 1;
-
-	tty_driver_kref_get(driver->other);
-	if (driver->subtype == PTY_TYPE_MASTER)
-		o_tty->count++;
-	/* Establish the links in both directions */
-	tty->link   = o_tty;
-	o_tty->link = tty;
-	/*
-	 * All structures have been allocated, so now we install them.
-	 * Failures after this point use release_tty to clean up, so
-	 * there's no need to null out the local pointers.
-	 */
-	tty_driver_kref_get(driver);
-	tty->count++;
-	return 0;
-err_free_mem:
-	deinitialize_tty_struct(o_tty);
-	kfree(o_tty->termios);
-	kfree(tty->termios);
-	module_put(o_tty->driver->owner);
-err_free_tty:
-	free_tty_struct(o_tty);
-	return -ENOMEM;
-}
-
-static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
-{
+	return pty_common_install(driver, tty, false);
 }
 
-static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
 {
 }
 
 static const struct tty_operations ptm_unix98_ops = {
 	.lookup = ptm_unix98_lookup,
 	.install = pty_unix98_install,
-	.remove = ptm_unix98_remove,
+	.remove = pty_unix98_remove,
 	.open = pty_open,
 	.close = pty_close,
 	.write = pty_write,
@@ -579,13 +570,14 @@ static const struct tty_operations ptm_unix98_ops = {
 	.set_termios = pty_set_termios,
 	.ioctl = pty_unix98_ioctl,
 	.shutdown = pty_unix98_shutdown,
+	.cleanup = pty_cleanup,
 	.resize = pty_resize
 };
 
 static const struct tty_operations pty_unix98_ops = {
 	.lookup = pts_unix98_lookup,
 	.install = pty_unix98_install,
-	.remove = pts_unix98_remove,
+	.remove = pty_unix98_remove,
 	.open = pty_open,
 	.close = pty_close,
 	.write = pty_write,
@@ -594,7 +586,8 @@ static const struct tty_operations pty_unix98_ops = {
 	.chars_in_buffer = pty_chars_in_buffer,
 	.unthrottle = pty_unthrottle,
 	.set_termios = pty_set_termios,
-	.shutdown = pty_unix98_shutdown
+	.shutdown = pty_unix98_shutdown,
+	.cleanup = pty_cleanup,
 };
 
 /**
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index 6e1958a..8123f78 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -282,6 +282,14 @@ static const struct serial8250_config uart_config[] = {
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
 		.flags		= UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
 	},
+	[PORT_LPC3220] = {
+		.name		= "LPC3220",
+		.fifo_size	= 64,
+		.tx_loadsz	= 32,
+		.fcr		= UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO |
+				  UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00,
+		.flags		= UART_CAP_FIFO,
+	},
 };
 
 /* Uart divisor latch read */
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 28e7c7c..66e5909 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1887,7 +1887,6 @@ enum pci_board_num_t {
 	pbn_panacom,
 	pbn_panacom2,
 	pbn_panacom4,
-	pbn_exsys_4055,
 	pbn_plx_romulus,
 	pbn_oxsemi,
 	pbn_oxsemi_1_4000000,
@@ -2393,13 +2392,6 @@ static struct pciserial_board pci_boards[] __devinitdata = {
 		.reg_shift	= 7,
 	},
 
-	[pbn_exsys_4055] = {
-		.flags		= FL_BASE2,
-		.num_ports	= 4,
-		.base_baud	= 115200,
-		.uart_offset	= 8,
-	},
-
 	/* I think this entry is broken - the first_offset looks wrong --rmk */
 	[pbn_plx_romulus] = {
 		.flags		= FL_BASE2,
@@ -3193,7 +3185,7 @@ static struct pci_device_id serial_pci_tbl[] = {
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 		PCI_SUBVENDOR_ID_EXSYS,
 		PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
-		pbn_exsys_4055 },
+		pbn_b2_4_115200 },
 	/*
 	 * Megawolf Romulus PCI Serial Card, from Mike Hudson
 	 * (Exoray@isys.ca)
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 070b442..0020786 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -704,6 +704,25 @@ config SERIAL_PNX8XXX_CONSOLE
 	  If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
 	  and you want to use serial console, say Y. Otherwise, say N.
 
+config SERIAL_HS_LPC32XX
+	tristate "LPC32XX high speed serial port support"
+	depends on ARCH_LPC32XX && OF
+	select SERIAL_CORE
+	help
+	  Support for the LPC32XX high speed serial ports (up to 900kbps).
+	  Those are UARTs completely different from the Standard UARTs on the
+	  LPC32XX SoC.
+	  Choose M or Y here to build this driver.
+
+config SERIAL_HS_LPC32XX_CONSOLE
+	bool "Enable LPC32XX high speed UART serial console"
+	depends on SERIAL_HS_LPC32XX
+	select SERIAL_CORE_CONSOLE
+	help
+	  If you would like to be able to use one of the high speed serial
+	  ports on the LPC32XX as the console, you can do so by answering
+	  Y to this option.
+
 config SERIAL_CORE
 	tristate
 
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 7257c5d..8a5df38 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
 obj-$(CONFIG_SERIAL_MCF) += mcf.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
+obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
 obj-$(CONFIG_SERIAL_ZS) += zs.o
 obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index c17923e..b81cc31f 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1215,14 +1215,14 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
 	return IRQ_RETVAL(handled);
 }
 
-static unsigned int pl01x_tx_empty(struct uart_port *port)
+static unsigned int pl011_tx_empty(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int status = readw(uap->port.membase + UART01x_FR);
 	return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
 }
 
-static unsigned int pl01x_get_mctrl(struct uart_port *port)
+static unsigned int pl011_get_mctrl(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int result = 0;
@@ -1285,7 +1285,7 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
-static int pl010_get_poll_char(struct uart_port *port)
+static int pl011_get_poll_char(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int status;
@@ -1297,7 +1297,7 @@ static int pl010_get_poll_char(struct uart_port *port)
 	return readw(uap->port.membase + UART01x_DR);
 }
 
-static void pl010_put_poll_char(struct uart_port *port,
+static void pl011_put_poll_char(struct uart_port *port,
 			 unsigned char ch)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1637,7 +1637,7 @@ static const char *pl011_type(struct uart_port *port)
 /*
  * Release the memory region(s) being used by 'port'
  */
-static void pl010_release_port(struct uart_port *port)
+static void pl011_release_port(struct uart_port *port)
 {
 	release_mem_region(port->mapbase, SZ_4K);
 }
@@ -1645,7 +1645,7 @@ static void pl010_release_port(struct uart_port *port)
 /*
  * Request the memory region(s) being used by 'port'
  */
-static int pl010_request_port(struct uart_port *port)
+static int pl011_request_port(struct uart_port *port)
 {
 	return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
 			!= NULL ? 0 : -EBUSY;
@@ -1654,18 +1654,18 @@ static int pl010_request_port(struct uart_port *port)
 /*
  * Configure/autoconfigure the port.
  */
-static void pl010_config_port(struct uart_port *port, int flags)
+static void pl011_config_port(struct uart_port *port, int flags)
 {
 	if (flags & UART_CONFIG_TYPE) {
 		port->type = PORT_AMBA;
-		pl010_request_port(port);
+		pl011_request_port(port);
 	}
 }
 
 /*
  * verify the new serial_struct (for TIOCSSERIAL).
  */
-static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
+static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
 {
 	int ret = 0;
 	if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
@@ -1678,9 +1678,9 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 static struct uart_ops amba_pl011_pops = {
-	.tx_empty	= pl01x_tx_empty,
+	.tx_empty	= pl011_tx_empty,
 	.set_mctrl	= pl011_set_mctrl,
-	.get_mctrl	= pl01x_get_mctrl,
+	.get_mctrl	= pl011_get_mctrl,
 	.stop_tx	= pl011_stop_tx,
 	.start_tx	= pl011_start_tx,
 	.stop_rx	= pl011_stop_rx,
@@ -1691,13 +1691,13 @@ static struct uart_ops amba_pl011_pops = {
 	.flush_buffer	= pl011_dma_flush_buffer,
 	.set_termios	= pl011_set_termios,
 	.type		= pl011_type,
-	.release_port	= pl010_release_port,
-	.request_port	= pl010_request_port,
-	.config_port	= pl010_config_port,
-	.verify_port	= pl010_verify_port,
+	.release_port	= pl011_release_port,
+	.request_port	= pl011_request_port,
+	.config_port	= pl011_config_port,
+	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_get_char = pl010_get_poll_char,
-	.poll_put_char = pl010_put_poll_char,
+	.poll_get_char = pl011_get_poll_char,
+	.poll_put_char = pl011_put_poll_char,
 #endif
 };
 
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 4ef7473..0af4eec 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -207,7 +207,7 @@ struct imx_port {
 	unsigned short		trcv_delay; /* transceiver delay */
 	struct clk		*clk_ipg;
 	struct clk		*clk_per;
-	struct imx_uart_data	*devdata;
+	const struct imx_uart_data *devdata;
 };
 
 struct imx_port_ucrs {
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
new file mode 100644
index 0000000..ba3af3b
--- /dev/null
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -0,0 +1,823 @@
+/*
+ * High Speed Serial Ports on NXP LPC32xx SoC
+ *
+ * Authors: Kevin Wells <kevin.wells@nxp.com>
+ *          Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/nmi.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <mach/platform.h>
+#include <mach/hardware.h>
+
+/*
+ * High Speed UART register offsets
+ */
+#define LPC32XX_HSUART_FIFO(x)			((x) + 0x00)
+#define LPC32XX_HSUART_LEVEL(x)			((x) + 0x04)
+#define LPC32XX_HSUART_IIR(x)			((x) + 0x08)
+#define LPC32XX_HSUART_CTRL(x)			((x) + 0x0C)
+#define LPC32XX_HSUART_RATE(x)			((x) + 0x10)
+
+#define LPC32XX_HSU_BREAK_DATA			(1 << 10)
+#define LPC32XX_HSU_ERROR_DATA			(1 << 9)
+#define LPC32XX_HSU_RX_EMPTY			(1 << 8)
+
+#define LPC32XX_HSU_TX_LEV(n)			(((n) >> 8) & 0xFF)
+#define LPC32XX_HSU_RX_LEV(n)			((n) & 0xFF)
+
+#define LPC32XX_HSU_TX_INT_SET			(1 << 6)
+#define LPC32XX_HSU_RX_OE_INT			(1 << 5)
+#define LPC32XX_HSU_BRK_INT			(1 << 4)
+#define LPC32XX_HSU_FE_INT			(1 << 3)
+#define LPC32XX_HSU_RX_TIMEOUT_INT		(1 << 2)
+#define LPC32XX_HSU_RX_TRIG_INT			(1 << 1)
+#define LPC32XX_HSU_TX_INT			(1 << 0)
+
+#define LPC32XX_HSU_HRTS_INV			(1 << 21)
+#define LPC32XX_HSU_HRTS_TRIG_8B		(0x0 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_16B		(0x1 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_32B		(0x2 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_48B		(0x3 << 19)
+#define LPC32XX_HSU_HRTS_EN			(1 << 18)
+#define LPC32XX_HSU_TMO_DISABLED		(0x0 << 16)
+#define LPC32XX_HSU_TMO_INACT_4B		(0x1 << 16)
+#define LPC32XX_HSU_TMO_INACT_8B		(0x2 << 16)
+#define LPC32XX_HSU_TMO_INACT_16B		(0x3 << 16)
+#define LPC32XX_HSU_HCTS_INV			(1 << 15)
+#define LPC32XX_HSU_HCTS_EN			(1 << 14)
+#define LPC32XX_HSU_OFFSET(n)			((n) << 9)
+#define LPC32XX_HSU_BREAK			(1 << 8)
+#define LPC32XX_HSU_ERR_INT_EN			(1 << 7)
+#define LPC32XX_HSU_RX_INT_EN			(1 << 6)
+#define LPC32XX_HSU_TX_INT_EN			(1 << 5)
+#define LPC32XX_HSU_RX_TL1B			(0x0 << 2)
+#define LPC32XX_HSU_RX_TL4B			(0x1 << 2)
+#define LPC32XX_HSU_RX_TL8B			(0x2 << 2)
+#define LPC32XX_HSU_RX_TL16B			(0x3 << 2)
+#define LPC32XX_HSU_RX_TL32B			(0x4 << 2)
+#define LPC32XX_HSU_RX_TL48B			(0x5 << 2)
+#define LPC32XX_HSU_TX_TLEMPTY			(0x0 << 0)
+#define LPC32XX_HSU_TX_TL0B			(0x0 << 0)
+#define LPC32XX_HSU_TX_TL4B			(0x1 << 0)
+#define LPC32XX_HSU_TX_TL8B			(0x2 << 0)
+#define LPC32XX_HSU_TX_TL16B			(0x3 << 0)
+
+#define MODNAME "lpc32xx_hsuart"
+
+struct lpc32xx_hsuart_port {
+	struct uart_port port;
+};
+
+#define FIFO_READ_LIMIT 128
+#define MAX_PORTS 3
+#define LPC32XX_TTY_NAME "ttyTX"
+static struct lpc32xx_hsuart_port lpc32xx_hs_ports[MAX_PORTS];
+
+#ifdef CONFIG_SERIAL_HS_LPC32XX_CONSOLE
+static void wait_for_xmit_empty(struct uart_port *port)
+{
+	unsigned int timeout = 10000;
+
+	do {
+		if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+							port->membase))) == 0)
+			break;
+		if (--timeout == 0)
+			break;
+		udelay(1);
+	} while (1);
+}
+
+static void wait_for_xmit_ready(struct uart_port *port)
+{
+	unsigned int timeout = 10000;
+
+	while (1) {
+		if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+							port->membase))) < 32)
+			break;
+		if (--timeout == 0)
+			break;
+		udelay(1);
+	}
+}
+
+static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch)
+{
+	wait_for_xmit_ready(port);
+	writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
+					 unsigned int count)
+{
+	struct lpc32xx_hsuart_port *up = &lpc32xx_hs_ports[co->index];
+	unsigned long flags;
+	int locked = 1;
+
+	touch_nmi_watchdog();
+	local_irq_save(flags);
+	if (up->port.sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock(&up->port.lock);
+	else
+		spin_lock(&up->port.lock);
+
+	uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar);
+	wait_for_xmit_empty(&up->port);
+
+	if (locked)
+		spin_unlock(&up->port.lock);
+	local_irq_restore(flags);
+}
+
+static int __init lpc32xx_hsuart_console_setup(struct console *co,
+					       char *options)
+{
+	struct uart_port *port;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index >= MAX_PORTS)
+		co->index = 0;
+
+	port = &lpc32xx_hs_ports[co->index].port;
+	if (!port->membase)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver lpc32xx_hsuart_reg;
+static struct console lpc32xx_hsuart_console = {
+	.name		= LPC32XX_TTY_NAME,
+	.write		= lpc32xx_hsuart_console_write,
+	.device		= uart_console_device,
+	.setup		= lpc32xx_hsuart_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &lpc32xx_hsuart_reg,
+};
+
+static int __init lpc32xx_hsuart_console_init(void)
+{
+	register_console(&lpc32xx_hsuart_console);
+	return 0;
+}
+console_initcall(lpc32xx_hsuart_console_init);
+
+#define LPC32XX_HSUART_CONSOLE (&lpc32xx_hsuart_console)
+#else
+#define LPC32XX_HSUART_CONSOLE NULL
+#endif
+
+static struct uart_driver lpc32xx_hs_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= MODNAME,
+	.dev_name	= LPC32XX_TTY_NAME,
+	.nr		= MAX_PORTS,
+	.cons		= LPC32XX_HSUART_CONSOLE,
+};
+static int uarts_registered;
+
+static unsigned int __serial_get_clock_div(unsigned long uartclk,
+					   unsigned long rate)
+{
+	u32 div, goodrate, hsu_rate, l_hsu_rate, comprate;
+	u32 rate_diff;
+
+	/* Find the closest divider to get the desired clock rate */
+	div = uartclk / rate;
+	goodrate = hsu_rate = (div / 14) - 1;
+	if (hsu_rate != 0)
+		hsu_rate--;
+
+	/* Tweak divider */
+	l_hsu_rate = hsu_rate + 3;
+	rate_diff = 0xFFFFFFFF;
+
+	while (hsu_rate < l_hsu_rate) {
+		comprate = uartclk / ((hsu_rate + 1) * 14);
+		if (abs(comprate - rate) < rate_diff) {
+			goodrate = hsu_rate;
+			rate_diff = abs(comprate - rate);
+		}
+
+		hsu_rate++;
+	}
+	if (hsu_rate > 0xFF)
+		hsu_rate = 0xFF;
+
+	return goodrate;
+}
+
+static void __serial_uart_flush(struct uart_port *port)
+{
+	u32 tmp;
+	int cnt = 0;
+
+	while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) &&
+	       (cnt++ < FIFO_READ_LIMIT))
+		tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void __serial_lpc32xx_rx(struct uart_port *port)
+{
+	unsigned int tmp, flag;
+	struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+	if (!tty) {
+		/* Discard data: no tty available */
+		while (!(readl(LPC32XX_HSUART_FIFO(port->membase)) &
+			 LPC32XX_HSU_RX_EMPTY))
+			;
+
+		return;
+	}
+
+	/* Read data from FIFO and push into terminal */
+	tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+	while (!(tmp & LPC32XX_HSU_RX_EMPTY)) {
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+
+		if (tmp & LPC32XX_HSU_ERROR_DATA) {
+			/* Framing error */
+			writel(LPC32XX_HSU_FE_INT,
+			       LPC32XX_HSUART_IIR(port->membase));
+			port->icount.frame++;
+			flag = TTY_FRAME;
+			tty_insert_flip_char(tty, 0, TTY_FRAME);
+		}
+
+		tty_insert_flip_char(tty, (tmp & 0xFF), flag);
+
+		tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+	}
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
+static void __serial_lpc32xx_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned int tmp;
+
+	if (port->x_char) {
+		writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase));
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+		goto exit_tx;
+
+	/* Transfer data */
+	while (LPC32XX_HSU_TX_LEV(readl(
+		LPC32XX_HSUART_LEVEL(port->membase))) < 64) {
+		writel((u32) xmit->buf[xmit->tail],
+		       LPC32XX_HSUART_FIFO(port->membase));
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+exit_tx:
+	if (uart_circ_empty(xmit)) {
+		tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+		tmp &= ~LPC32XX_HSU_TX_INT_EN;
+		writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+	}
+}
+
+static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+	u32 status;
+
+	spin_lock(&port->lock);
+
+	/* Read UART status and clear latched interrupts */
+	status = readl(LPC32XX_HSUART_IIR(port->membase));
+
+	if (status & LPC32XX_HSU_BRK_INT) {
+		/* Break received */
+		writel(LPC32XX_HSU_BRK_INT, LPC32XX_HSUART_IIR(port->membase));
+		port->icount.brk++;
+		uart_handle_break(port);
+	}
+
+	/* Framing error */
+	if (status & LPC32XX_HSU_FE_INT)
+		writel(LPC32XX_HSU_FE_INT, LPC32XX_HSUART_IIR(port->membase));
+
+	if (status & LPC32XX_HSU_RX_OE_INT) {
+		/* Receive FIFO overrun */
+		writel(LPC32XX_HSU_RX_OE_INT,
+		       LPC32XX_HSUART_IIR(port->membase));
+		port->icount.overrun++;
+		if (tty) {
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+			tty_schedule_flip(tty);
+		}
+	}
+
+	/* Data received? */
+	if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) {
+		__serial_lpc32xx_rx(port);
+		if (tty)
+			tty_flip_buffer_push(tty);
+	}
+
+	/* Transmit data request? */
+	if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) {
+		writel(LPC32XX_HSU_TX_INT, LPC32XX_HSUART_IIR(port->membase));
+		__serial_lpc32xx_tx(port);
+	}
+
+	spin_unlock(&port->lock);
+	tty_kref_put(tty);
+
+	return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int serial_lpc32xx_tx_empty(struct uart_port *port)
+{
+	unsigned int ret = 0;
+
+	if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(port->membase))) == 0)
+		ret = TIOCSER_TEMT;
+
+	return ret;
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_set_mctrl(struct uart_port *port,
+				     unsigned int mctrl)
+{
+	/* No signals are supported on HS UARTs */
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int serial_lpc32xx_get_mctrl(struct uart_port *port)
+{
+	/* No signals are supported on HS UARTs */
+	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_stop_tx(struct uart_port *port)
+{
+	u32 tmp;
+
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	tmp &= ~LPC32XX_HSU_TX_INT_EN;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_start_tx(struct uart_port *port)
+{
+	u32 tmp;
+
+	__serial_lpc32xx_tx(port);
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	tmp |= LPC32XX_HSU_TX_INT_EN;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_stop_rx(struct uart_port *port)
+{
+	u32 tmp;
+
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	writel((LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT |
+		LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_enable_ms(struct uart_port *port)
+{
+	/* Modem status is not supported */
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_break_ctl(struct uart_port *port,
+				     int break_state)
+{
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&port->lock, flags);
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	if (break_state != 0)
+		tmp |= LPC32XX_HSU_BREAK;
+	else
+		tmp &= ~LPC32XX_HSU_BREAK;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */
+static void lpc32xx_loopback_set(resource_size_t mapbase, int state)
+{
+	int bit;
+	u32 tmp;
+
+	switch (mapbase) {
+	case LPC32XX_HS_UART1_BASE:
+		bit = 0;
+		break;
+	case LPC32XX_HS_UART2_BASE:
+		bit = 1;
+		break;
+	case LPC32XX_HS_UART7_BASE:
+		bit = 6;
+		break;
+	default:
+		WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase);
+		return;
+	}
+
+	tmp = readl(LPC32XX_UARTCTL_CLOOP);
+	if (state)
+		tmp |= (1 << bit);
+	else
+		tmp &= ~(1 << bit);
+	writel(tmp, LPC32XX_UARTCTL_CLOOP);
+}
+
+/* port->lock is not held.  */
+static int serial_lpc32xx_startup(struct uart_port *port)
+{
+	int retval;
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	__serial_uart_flush(port);
+
+	writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+		LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+	       LPC32XX_HSUART_IIR(port->membase));
+
+	writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+	/*
+	 * Set receiver timeout, HSU offset of 20, no break, no interrupts,
+	 * and default FIFO trigger levels
+	 */
+	tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+		LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	retval = request_irq(port->irq, serial_lpc32xx_interrupt,
+			     0, MODNAME, port);
+	if (!retval)
+		writel((tmp | LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN),
+		       LPC32XX_HSUART_CTRL(port->membase));
+
+	return retval;
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_shutdown(struct uart_port *port)
+{
+	u32 tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+		LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	free_irq(port->irq, port);
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_set_termios(struct uart_port *port,
+				       struct ktermios *termios,
+				       struct ktermios *old)
+{
+	unsigned long flags;
+	unsigned int baud, quot;
+	u32 tmp;
+
+	/* Always 8-bit, no parity, 1 stop bit */
+	termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
+	termios->c_cflag |= CS8;
+
+	termios->c_cflag &= ~(HUPCL | CMSPAR | CLOCAL | CRTSCTS);
+
+	baud = uart_get_baud_rate(port, termios, old, 0,
+				  port->uartclk / 14);
+
+	quot = __serial_get_clock_div(port->uartclk, baud);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* Ignore characters? */
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	if ((termios->c_cflag & CREAD) == 0)
+		tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+	else
+		tmp |= LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	writel(quot, LPC32XX_HSUART_RATE(port->membase));
+
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* Don't rewrite B0 */
+	if (tty_termios_baud_rate(termios))
+		tty_termios_encode_baud_rate(termios, baud, baud);
+}
+
+static const char *serial_lpc32xx_type(struct uart_port *port)
+{
+	return MODNAME;
+}
+
+static void serial_lpc32xx_release_port(struct uart_port *port)
+{
+	if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+		if (port->flags & UPF_IOREMAP) {
+			iounmap(port->membase);
+			port->membase = NULL;
+		}
+
+		release_mem_region(port->mapbase, SZ_4K);
+	}
+}
+
+static int serial_lpc32xx_request_port(struct uart_port *port)
+{
+	int ret = -ENODEV;
+
+	if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+		ret = 0;
+
+		if (!request_mem_region(port->mapbase, SZ_4K, MODNAME))
+			ret = -EBUSY;
+		else if (port->flags & UPF_IOREMAP) {
+			port->membase = ioremap(port->mapbase, SZ_4K);
+			if (!port->membase) {
+				release_mem_region(port->mapbase, SZ_4K);
+				ret = -ENOMEM;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static void serial_lpc32xx_config_port(struct uart_port *port, int uflags)
+{
+	int ret;
+
+	ret = serial_lpc32xx_request_port(port);
+	if (ret < 0)
+		return;
+	port->type = PORT_UART00;
+	port->fifosize = 64;
+
+	__serial_uart_flush(port);
+
+	writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+		LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+	       LPC32XX_HSUART_IIR(port->membase));
+
+	writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+	/* Set receiver timeout, HSU offset of 20, no break, no interrupts,
+	   and default FIFO trigger levels */
+	writel(LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+	       LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B,
+	       LPC32XX_HSUART_CTRL(port->membase));
+}
+
+static int serial_lpc32xx_verify_port(struct uart_port *port,
+				      struct serial_struct *ser)
+{
+	int ret = 0;
+
+	if (ser->type != PORT_UART00)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static struct uart_ops serial_lpc32xx_pops = {
+	.tx_empty	= serial_lpc32xx_tx_empty,
+	.set_mctrl	= serial_lpc32xx_set_mctrl,
+	.get_mctrl	= serial_lpc32xx_get_mctrl,
+	.stop_tx	= serial_lpc32xx_stop_tx,
+	.start_tx	= serial_lpc32xx_start_tx,
+	.stop_rx	= serial_lpc32xx_stop_rx,
+	.enable_ms	= serial_lpc32xx_enable_ms,
+	.break_ctl	= serial_lpc32xx_break_ctl,
+	.startup	= serial_lpc32xx_startup,
+	.shutdown	= serial_lpc32xx_shutdown,
+	.set_termios	= serial_lpc32xx_set_termios,
+	.type		= serial_lpc32xx_type,
+	.release_port	= serial_lpc32xx_release_port,
+	.request_port	= serial_lpc32xx_request_port,
+	.config_port	= serial_lpc32xx_config_port,
+	.verify_port	= serial_lpc32xx_verify_port,
+};
+
+/*
+ * Register a set of serial devices attached to a platform device
+ */
+static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev)
+{
+	struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered];
+	int ret = 0;
+	struct resource *res;
+
+	if (uarts_registered >= MAX_PORTS) {
+		dev_err(&pdev->dev,
+			"Error: Number of possible ports exceeded (%d)!\n",
+			uarts_registered + 1);
+		return -ENXIO;
+	}
+
+	memset(p, 0, sizeof(*p));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev,
+			"Error getting mem resource for HS UART port %d\n",
+			uarts_registered);
+		return -ENXIO;
+	}
+	p->port.mapbase = res->start;
+	p->port.membase = NULL;
+
+	p->port.irq = platform_get_irq(pdev, 0);
+	if (p->port.irq < 0) {
+		dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n",
+			uarts_registered);
+		return p->port.irq;
+	}
+
+	p->port.iotype = UPIO_MEM32;
+	p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
+	p->port.regshift = 2;
+	p->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
+	p->port.dev = &pdev->dev;
+	p->port.ops = &serial_lpc32xx_pops;
+	p->port.line = uarts_registered++;
+	spin_lock_init(&p->port.lock);
+
+	/* send port to loopback mode by default */
+	lpc32xx_loopback_set(p->port.mapbase, 1);
+
+	ret = uart_add_one_port(&lpc32xx_hs_reg, &p->port);
+
+	platform_set_drvdata(pdev, p);
+
+	return ret;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev)
+{
+	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+	uart_remove_one_port(&lpc32xx_hs_reg, &p->port);
+
+	return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int serial_hs_lpc32xx_suspend(struct platform_device *pdev,
+				     pm_message_t state)
+{
+	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+	uart_suspend_port(&lpc32xx_hs_reg, &p->port);
+
+	return 0;
+}
+
+static int serial_hs_lpc32xx_resume(struct platform_device *pdev)
+{
+	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+	uart_resume_port(&lpc32xx_hs_reg, &p->port);
+
+	return 0;
+}
+#else
+#define serial_hs_lpc32xx_suspend	NULL
+#define serial_hs_lpc32xx_resume	NULL
+#endif
+
+static const struct of_device_id serial_hs_lpc32xx_dt_ids[] = {
+	{ .compatible = "nxp,lpc3220-hsuart" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids);
+
+static struct platform_driver serial_hs_lpc32xx_driver = {
+	.probe		= serial_hs_lpc32xx_probe,
+	.remove		= __devexit_p(serial_hs_lpc32xx_remove),
+	.suspend	= serial_hs_lpc32xx_suspend,
+	.resume		= serial_hs_lpc32xx_resume,
+	.driver		= {
+		.name	= MODNAME,
+		.owner	= THIS_MODULE,
+		.of_match_table	= serial_hs_lpc32xx_dt_ids,
+	},
+};
+
+static int __init lpc32xx_hsuart_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&lpc32xx_hs_reg);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&serial_hs_lpc32xx_driver);
+	if (ret)
+		uart_unregister_driver(&lpc32xx_hs_reg);
+
+	return ret;
+}
+
+static void __exit lpc32xx_hsuart_exit(void)
+{
+	platform_driver_unregister(&serial_hs_lpc32xx_driver);
+	uart_unregister_driver(&lpc32xx_hs_reg);
+}
+
+module_init(lpc32xx_hsuart_init);
+module_exit(lpc32xx_hsuart_exit);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP LPC32XX High Speed UART driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 5410c06..34e7187 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -208,6 +208,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = {
 	{ .compatible = "ns16750",  .data = (void *)PORT_16750, },
 	{ .compatible = "ns16850",  .data = (void *)PORT_16850, },
 	{ .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, },
+	{ .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, },
 #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
 	{ .compatible = "ibm,qpace-nwp-serial",
 		.data = (void *)PORT_NWPSERIAL, },
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 4fdec6a..d291518 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -253,6 +253,9 @@ struct eg20t_port {
 	dma_addr_t			rx_buf_dma;
 
 	struct dentry	*debugfs;
+
+	/* protect the eg20t_port private structure and io access to membase */
+	spinlock_t lock;
 };
 
 /**
@@ -1058,7 +1061,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
 	int next = 1;
 	u8 msr;
 
-	spin_lock_irqsave(&priv->port.lock, flags);
+	spin_lock_irqsave(&priv->lock, flags);
 	handled = 0;
 	while (next) {
 		iid = pch_uart_hal_get_iid(priv);
@@ -1116,7 +1119,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
 		handled |= (unsigned int)ret;
 	}
 
-	spin_unlock_irqrestore(&priv->port.lock, flags);
+	spin_unlock_irqrestore(&priv->lock, flags);
 	return IRQ_RETVAL(handled);
 }
 
@@ -1226,9 +1229,9 @@ static void pch_uart_break_ctl(struct uart_port *port, int ctl)
 	unsigned long flags;
 
 	priv = container_of(port, struct eg20t_port, port);
-	spin_lock_irqsave(&port->lock, flags);
+	spin_lock_irqsave(&priv->lock, flags);
 	pch_uart_hal_set_break(priv, ctl);
-	spin_unlock_irqrestore(&port->lock, flags);
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 /* Grab any interrupt resources and initialise any low level driver state. */
@@ -1376,7 +1379,8 @@ static void pch_uart_set_termios(struct uart_port *port,
 
 	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
 
-	spin_lock_irqsave(&port->lock, flags);
+	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock(&port->lock);
 
 	uart_update_timeout(port, termios->c_cflag, baud);
 	rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
@@ -1389,7 +1393,8 @@ static void pch_uart_set_termios(struct uart_port *port,
 		tty_termios_encode_baud_rate(termios, baud, baud);
 
 out:
-	spin_unlock_irqrestore(&port->lock, flags);
+	spin_unlock(&port->lock);
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 static const char *pch_uart_type(struct uart_port *port)
@@ -1538,8 +1543,9 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
 {
 	struct eg20t_port *priv;
 	unsigned long flags;
+	int priv_locked = 1;
+	int port_locked = 1;
 	u8 ier;
-	int locked = 1;
 
 	priv = pch_uart_ports[co->index];
 
@@ -1547,12 +1553,16 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
 
 	local_irq_save(flags);
 	if (priv->port.sysrq) {
-		/* serial8250_handle_port() already took the lock */
-		locked = 0;
+		spin_lock(&priv->lock);
+		/* serial8250_handle_port() already took the port lock */
+		port_locked = 0;
 	} else if (oops_in_progress) {
-		locked = spin_trylock(&priv->port.lock);
-	} else
+		priv_locked = spin_trylock(&priv->lock);
+		port_locked = spin_trylock(&priv->port.lock);
+	} else {
+		spin_lock(&priv->lock);
 		spin_lock(&priv->port.lock);
+	}
 
 	/*
 	 *	First save the IER then disable the interrupts
@@ -1570,8 +1580,10 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
 	wait_for_xmitr(priv, BOTH_EMPTY);
 	iowrite8(ier, priv->membase + UART_IER);
 
-	if (locked)
+	if (port_locked)
 		spin_unlock(&priv->port.lock);
+	if (priv_locked)
+		spin_unlock(&priv->lock);
 	local_irq_restore(flags);
 }
 
@@ -1669,6 +1681,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
 	pci_enable_msi(pdev);
 	pci_set_master(pdev);
 
+	spin_lock_init(&priv->lock);
+
 	iobase = pci_resource_start(pdev, 0);
 	mapbase = pci_resource_start(pdev, 1);
 	priv->mapbase = mapbase;
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 5847a4b..9033fc6 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -670,9 +670,19 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
 {
 	struct uart_pxa_port *up = serial_pxa_ports[co->index];
 	unsigned int ier;
+	unsigned long flags;
+	int locked = 1;
 
 	clk_prepare_enable(up->clk);
 
+	local_irq_save(flags);
+	if (up->port.sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock(&up->port.lock);
+	else
+		spin_lock(&up->port.lock);
+
 	/*
 	 *	First save the IER then disable the interrupts
 	 */
@@ -688,6 +698,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
 	wait_for_xmitr(up);
 	serial_out(up, UART_IER, ier);
 
+	if (locked)
+		spin_unlock(&up->port.lock);
+	local_irq_restore(flags);
+
 	clk_disable_unprepare(up->clk);
 }
 
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index d8b0aee..d57f165 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -529,7 +529,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
 
 	switch (level) {
 	case 3:
-		if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+		if (!IS_ERR(ourport->baudclk))
 			clk_disable(ourport->baudclk);
 
 		clk_disable(ourport->clk);
@@ -538,7 +538,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
 	case 0:
 		clk_enable(ourport->clk);
 
-		if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+		if (!IS_ERR(ourport->baudclk))
 			clk_enable(ourport->baudclk);
 
 		break;
@@ -604,7 +604,6 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
 	char clkname[MAX_CLK_NAME_LENGTH];
 	int calc_deviation, deviation = (1 << 30) - 1;
 
-	*best_clk = NULL;
 	clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel :
 			ourport->info->def_clk_sel;
 	for (cnt = 0; cnt < info->num_clks; cnt++) {
@@ -613,7 +612,7 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
 
 		sprintf(clkname, "clk_uart_baud%d", cnt);
 		clk = clk_get(ourport->port.dev, clkname);
-		if (IS_ERR_OR_NULL(clk))
+		if (IS_ERR(clk))
 			continue;
 
 		rate = clk_get_rate(clk);
@@ -684,7 +683,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
 {
 	struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
-	struct clk *clk = NULL;
+	struct clk *clk = ERR_PTR(-EINVAL);
 	unsigned long flags;
 	unsigned int baud, quot, clk_sel = 0;
 	unsigned int ulcon;
@@ -705,7 +704,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
 	quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel);
 	if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
 		quot = port->custom_divisor;
-	if (!clk)
+	if (IS_ERR(clk))
 		return;
 
 	/* check to see if we need  to change clock source */
@@ -713,9 +712,9 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
 	if (ourport->baudclk != clk) {
 		s3c24xx_serial_setsource(port, clk_sel);
 
-		if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
+		if (!IS_ERR(ourport->baudclk)) {
 			clk_disable(ourport->baudclk);
-			ourport->baudclk  = NULL;
+			ourport->baudclk = ERR_PTR(-EINVAL);
 		}
 
 		clk_enable(clk);
@@ -1014,10 +1013,10 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
 	 * a disturbance in the clock-rate over the change.
 	 */
 
-	if (IS_ERR(port->clk))
+	if (IS_ERR(port->baudclk))
 		goto exit;
 
-	if (port->baudclk_rate == clk_get_rate(port->clk))
+	if (port->baudclk_rate == clk_get_rate(port->baudclk))
 		goto exit;
 
 	if (val == CPUFREQ_PRECHANGE) {
@@ -1160,7 +1159,11 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
 	struct uart_port *port = s3c24xx_dev_to_port(dev);
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
 
-	return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->baudclk->name);
+	if (IS_ERR(ourport->baudclk))
+		return -EINVAL;
+
+	return snprintf(buf, PAGE_SIZE, "* %s\n",
+			ourport->baudclk->name ?: "(null)");
 }
 
 static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
@@ -1200,6 +1203,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
+	ourport->baudclk = ERR_PTR(-EINVAL);
 	ourport->info = ourport->drv_data->info;
 	ourport->cfg = (pdev->dev.platform_data) ?
 			(struct s3c2410_uartcfg *)pdev->dev.platform_data :
@@ -1387,7 +1391,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
 		sprintf(clk_name, "clk_uart_baud%d", clk_sel);
 
 		clk = clk_get(port->dev, clk_name);
-		if (!IS_ERR(clk) && clk != NULL)
+		if (!IS_ERR(clk))
 			rate = clk_get_rate(clk);
 		else
 			rate = 1;
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 246b823..a21dc8e 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2527,14 +2527,16 @@ void uart_insert_char(struct uart_port *port, unsigned int status,
 	struct tty_struct *tty = port->state->port.tty;
 
 	if ((status & port->ignore_status_mask & ~overrun) == 0)
-		tty_insert_flip_char(tty, ch, flag);
+		if (tty_insert_flip_char(tty, ch, flag) == 0)
+			++port->icount.buf_overrun;
 
 	/*
 	 * Overrun is special.  Since it's reported immediately,
 	 * it doesn't affect the current character.
 	 */
 	if (status & ~port->ignore_status_mask & overrun)
-		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+		if (tty_insert_flip_char(tty, 0, TTY_OVERRUN) == 0)
+			++port->icount.buf_overrun;
 }
 EXPORT_SYMBOL_GPL(uart_insert_char);
 
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index b425c79..ac96f74 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1407,6 +1407,9 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
 	if (retval < 0)
 		goto err_deinit_tty;
 
+	if (!tty->port)
+		tty->port = driver->ports[idx];
+
 	/*
 	 * Structures all installed ... call the ldisc open routines.
 	 * If we fail here just call release_tty to clean up.  No need
@@ -3094,6 +3097,7 @@ static void destruct_tty_driver(struct kref *kref)
 		kfree(p);
 		cdev_del(&driver->cdev);
 	}
+	kfree(driver->ports);
 	kfree(driver);
 }
 
@@ -3132,6 +3136,18 @@ int tty_register_driver(struct tty_driver *driver)
 		if (!p)
 			return -ENOMEM;
 	}
+	/*
+	 * There is too many lines in PTY and we won't need the array there
+	 * since it has an ->install hook where it assigns ports properly.
+	 */
+	if (driver->type != TTY_DRIVER_TYPE_PTY) {
+		driver->ports = kcalloc(driver->num, sizeof(struct tty_port *),
+				GFP_KERNEL);
+		if (!driver->ports) {
+			error = -ENOMEM;
+			goto err_free_p;
+		}
+	}
 
 	if (!driver->major) {
 		error = alloc_chrdev_region(&dev, driver->minor_start,
@@ -3144,10 +3160,8 @@ int tty_register_driver(struct tty_driver *driver)
 		dev = MKDEV(driver->major, driver->minor_start);
 		error = register_chrdev_region(dev, driver->num, driver->name);
 	}
-	if (error < 0) {
-		kfree(p);
-		return error;
-	}
+	if (error < 0)
+		goto err_free_p;
 
 	if (p) {
 		driver->ttys = (struct tty_struct **)p;
@@ -3160,13 +3174,8 @@ int tty_register_driver(struct tty_driver *driver)
 	cdev_init(&driver->cdev, &tty_fops);
 	driver->cdev.owner = driver->owner;
 	error = cdev_add(&driver->cdev, dev, driver->num);
-	if (error) {
-		unregister_chrdev_region(dev, driver->num);
-		driver->ttys = NULL;
-		driver->termios = NULL;
-		kfree(p);
-		return error;
-	}
+	if (error)
+		goto err_unreg_char;
 
 	mutex_lock(&tty_mutex);
 	list_add(&driver->tty_drivers, &tty_drivers);
@@ -3193,13 +3202,14 @@ err:
 	list_del(&driver->tty_drivers);
 	mutex_unlock(&tty_mutex);
 
+err_unreg_char:
 	unregister_chrdev_region(dev, driver->num);
 	driver->ttys = NULL;
 	driver->termios = NULL;
+err_free_p: /* destruct_tty_driver will free driver->ports */
 	kfree(p);
 	return error;
 }
-
 EXPORT_SYMBOL(tty_register_driver);
 
 /*
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index bf6e238..4e9d2b2 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -33,6 +33,15 @@ void tty_port_init(struct tty_port *port)
 }
 EXPORT_SYMBOL(tty_port_init);
 
+struct device *tty_port_register_device(struct tty_port *port,
+		struct tty_driver *driver, unsigned index,
+		struct device *device)
+{
+	driver->ports[index] = port;
+	return tty_register_device(driver, index, device);
+}
+EXPORT_SYMBOL_GPL(tty_port_register_device);
+
 int tty_port_alloc_xmit_buf(struct tty_port *port)
 {
 	/* We may sleep in get_zeroed_page() */
@@ -413,6 +422,14 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
 }
 EXPORT_SYMBOL(tty_port_close);
 
+int tty_port_install(struct tty_port *port, struct tty_driver *driver,
+		struct tty_struct *tty)
+{
+	tty->port = port;
+	return tty_standard_install(driver, tty);
+}
+EXPORT_SYMBOL_GPL(tty_port_install);
+
 int tty_port_open(struct tty_port *port, struct tty_struct *tty,
 							struct file *filp)
 {
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 48cc6f2..0b6217c 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -310,7 +310,7 @@ static void put_queue(struct vc_data *vc, int ch)
 
 	if (tty) {
 		tty_insert_flip_char(tty, ch, 0);
-		con_schedule_flip(tty);
+		tty_schedule_flip(tty);
 	}
 }
 
@@ -325,7 +325,7 @@ static void puts_queue(struct vc_data *vc, char *cp)
 		tty_insert_flip_char(tty, *cp, 0);
 		cp++;
 	}
-	con_schedule_flip(tty);
+	tty_schedule_flip(tty);
 }
 
 static void applkey(struct vc_data *vc, int key, char mode)
@@ -586,7 +586,7 @@ static void fn_send_intr(struct vc_data *vc)
 	if (!tty)
 		return;
 	tty_insert_flip_char(tty, 0, TTY_BREAK);
-	con_schedule_flip(tty);
+	tty_schedule_flip(tty);
 }
 
 static void fn_scroll_forw(struct vc_data *vc)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 84cbf29..7cb53c2 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1380,7 +1380,7 @@ static void respond_string(const char *p, struct tty_struct *tty)
 		tty_insert_flip_char(tty, *p, 0);
 		p++;
 	}
-	con_schedule_flip(tty);
+	tty_schedule_flip(tty);
 }
 
 static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
@@ -2792,41 +2792,52 @@ static void con_flush_chars(struct tty_struct *tty)
 /*
  * Allocate the console screen memory.
  */
-static int con_open(struct tty_struct *tty, struct file *filp)
+static int con_install(struct tty_driver *driver, struct tty_struct *tty)
 {
 	unsigned int currcons = tty->index;
-	int ret = 0;
+	struct vc_data *vc;
+	int ret;
 
 	console_lock();
-	if (tty->driver_data == NULL) {
-		ret = vc_allocate(currcons);
-		if (ret == 0) {
-			struct vc_data *vc = vc_cons[currcons].d;
+	ret = vc_allocate(currcons);
+	if (ret)
+		goto unlock;
 
-			/* Still being freed */
-			if (vc->port.tty) {
-				console_unlock();
-				return -ERESTARTSYS;
-			}
-			tty->driver_data = vc;
-			vc->port.tty = tty;
+	vc = vc_cons[currcons].d;
 
-			if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
-				tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
-				tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
-			}
-			if (vc->vc_utf)
-				tty->termios->c_iflag |= IUTF8;
-			else
-				tty->termios->c_iflag &= ~IUTF8;
-			console_unlock();
-			return ret;
-		}
+	/* Still being freed */
+	if (vc->port.tty) {
+		ret = -ERESTARTSYS;
+		goto unlock;
 	}
+
+	ret = tty_port_install(&vc->port, driver, tty);
+	if (ret)
+		goto unlock;
+
+	tty->driver_data = vc;
+	vc->port.tty = tty;
+
+	if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+		tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
+		tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
+	}
+	if (vc->vc_utf)
+		tty->termios->c_iflag |= IUTF8;
+	else
+		tty->termios->c_iflag &= ~IUTF8;
+unlock:
 	console_unlock();
 	return ret;
 }
 
+static int con_open(struct tty_struct *tty, struct file *filp)
+{
+	/* everything done in install */
+	return 0;
+}
+
+
 static void con_close(struct tty_struct *tty, struct file *filp)
 {
 	/* Nothing to do - we defer to shutdown */
@@ -2947,6 +2958,7 @@ static int __init con_init(void)
 console_initcall(con_init);
 
 static const struct tty_operations con_ops = {
+	.install = con_install,
 	.open = con_open,
 	.close = con_close,
 	.write = con_write,
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 6461854..b841f56 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -110,16 +110,7 @@ void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
 		wake_up_interruptible(&vt_event_waitqueue);
 }
 
-/**
- *	vt_event_wait		-	wait for an event
- *	@vw: our event
- *
- *	Waits for an event to occur which completes our vt_event_wait
- *	structure. On return the structure has wv->done set to 1 for success
- *	or 0 if some event such as a signal ended the wait.
- */
-
-static void vt_event_wait(struct vt_event_wait *vw)
+static void __vt_event_queue(struct vt_event_wait *vw)
 {
 	unsigned long flags;
 	/* Prepare the event */
@@ -129,8 +120,18 @@ static void vt_event_wait(struct vt_event_wait *vw)
 	spin_lock_irqsave(&vt_event_lock, flags);
 	list_add(&vw->list, &vt_events);
 	spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
+static void __vt_event_wait(struct vt_event_wait *vw)
+{
 	/* Wait for it to pass */
 	wait_event_interruptible(vt_event_waitqueue, vw->done);
+}
+
+static void __vt_event_dequeue(struct vt_event_wait *vw)
+{
+	unsigned long flags;
+
 	/* Dequeue it */
 	spin_lock_irqsave(&vt_event_lock, flags);
 	list_del(&vw->list);
@@ -138,6 +139,22 @@ static void vt_event_wait(struct vt_event_wait *vw)
 }
 
 /**
+ *	vt_event_wait		-	wait for an event
+ *	@vw: our event
+ *
+ *	Waits for an event to occur which completes our vt_event_wait
+ *	structure. On return the structure has wv->done set to 1 for success
+ *	or 0 if some event such as a signal ended the wait.
+ */
+
+static void vt_event_wait(struct vt_event_wait *vw)
+{
+	__vt_event_queue(vw);
+	__vt_event_wait(vw);
+	__vt_event_dequeue(vw);
+}
+
+/**
  *	vt_event_wait_ioctl	-	event ioctl handler
  *	@arg: argument to ioctl
  *
@@ -177,10 +194,14 @@ int vt_waitactive(int n)
 {
 	struct vt_event_wait vw;
 	do {
-		if (n == fg_console + 1)
-			break;
 		vw.event.event = VT_EVENT_SWITCH;
-		vt_event_wait(&vw);
+		__vt_event_queue(&vw);
+		if (n == fg_console + 1) {
+			__vt_event_dequeue(&vw);
+			break;
+		}
+		__vt_event_wait(&vw);
+		__vt_event_dequeue(&vw);
 		if (vw.done == 0)
 			return -EINTR;
 	} while (vw.event.newev != n);
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index c691eea..f5ed3d7 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -46,7 +46,7 @@ obj-$(CONFIG_USB_MICROTEK)	+= image/
 obj-$(CONFIG_USB_SERIAL)	+= serial/
 
 obj-$(CONFIG_USB)		+= misc/
-obj-$(CONFIG_USB)		+= phy/
+obj-$(CONFIG_USB_COMMON)	+= phy/
 obj-$(CONFIG_EARLY_PRINTK_DBGP)	+= early/
 
 obj-$(CONFIG_USB_ATM)		+= atm/
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 8fd398d..25e7d72 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -32,8 +32,6 @@
 #define DRIVER_AUTHOR "Oliver Neukum"
 #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
 
-#define HUAWEI_VENDOR_ID	0x12D1
-
 static const struct usb_device_id wdm_ids[] = {
 	{
 		.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
@@ -41,29 +39,6 @@ static const struct usb_device_id wdm_ids[] = {
 		.bInterfaceClass = USB_CLASS_COMM,
 		.bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
 	},
-	{
-		/* 
-		 * Huawei E392, E398 and possibly other Qualcomm based modems
-		 * embed the Qualcomm QMI protocol inside CDC on CDC ECM like
-		 * control interfaces.  Userspace access to this is required
-		 * to configure the accompanying data interface
-		 */
-		.match_flags        = USB_DEVICE_ID_MATCH_VENDOR |
-					USB_DEVICE_ID_MATCH_INT_INFO,
-		.idVendor           = HUAWEI_VENDOR_ID,
-		.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
-		.bInterfaceSubClass = 1,
-		.bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */
-	},
-	{
-		 /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */
-		.match_flags        = USB_DEVICE_ID_MATCH_VENDOR |
-				      USB_DEVICE_ID_MATCH_INT_INFO,
-		.idVendor           = HUAWEI_VENDOR_ID,
-		.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
-		.bInterfaceSubClass = 1,
-		.bInterfaceProtocol = 57, /* NOTE: CDC ECM control interface! */
-	},
 	{ }
 };
 
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index f536aeb..6978101 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -367,6 +367,7 @@ static int usb_probe_interface(struct device *dev)
 	return error;
 
  err:
+	usb_set_intfdata(intf, NULL);
 	intf->needs_remote_wakeup = 0;
 	intf->condition = USB_INTERFACE_UNBOUND;
 	usb_cancel_queued_reset(intf);
@@ -622,14 +623,15 @@ int usb_match_one_id(struct usb_interface *interface,
 	if (!usb_match_device(dev, id))
 		return 0;
 
-	/* The interface class, subclass, and protocol should never be
+	/* The interface class, subclass, protocol and number should never be
 	 * checked for a match if the device class is Vendor Specific,
 	 * unless the match record specifies the Vendor ID. */
 	if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
 			!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
 			(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
 				USB_DEVICE_ID_MATCH_INT_SUBCLASS |
-				USB_DEVICE_ID_MATCH_INT_PROTOCOL)))
+				USB_DEVICE_ID_MATCH_INT_PROTOCOL |
+				USB_DEVICE_ID_MATCH_INT_NUMBER)))
 		return 0;
 
 	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
@@ -644,6 +646,10 @@ int usb_match_one_id(struct usb_interface *interface,
 	    (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
 		return 0;
 
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
+	    (id->bInterfaceNumber != intf->desc.bInterfaceNumber))
+		return 0;
+
 	return 1;
 }
 EXPORT_SYMBOL_GPL(usb_match_one_id);
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index e673b26..e5387a4 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -92,7 +92,7 @@ static int init_usb_class(void)
 	}
 
 	kref_init(&usb_class->kref);
-	usb_class->class = class_create(THIS_MODULE, "usb");
+	usb_class->class = class_create(THIS_MODULE, "usbmisc");
 	if (IS_ERR(usb_class->class)) {
 		result = IS_ERR(usb_class->class);
 		printk(KERN_ERR "class_create failed for usb devices\n");
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index bdd1c67..8b9d669 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1559,7 +1559,7 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 	if (add_uevent_var(env,
 		   "MODALIAS=usb:"
-		   "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+		   "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02Xin%02X",
 		   le16_to_cpu(usb_dev->descriptor.idVendor),
 		   le16_to_cpu(usb_dev->descriptor.idProduct),
 		   le16_to_cpu(usb_dev->descriptor.bcdDevice),
@@ -1568,7 +1568,8 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
 		   usb_dev->descriptor.bDeviceProtocol,
 		   alt->desc.bInterfaceClass,
 		   alt->desc.bInterfaceSubClass,
-		   alt->desc.bInterfaceProtocol))
+		   alt->desc.bInterfaceProtocol,
+		   alt->desc.bInterfaceNumber))
 		return -ENOMEM;
 
 	return 0;
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 9a56e3a..777f03c 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -840,7 +840,7 @@ static ssize_t show_modalias(struct device *dev,
 	alt = intf->cur_altsetting;
 
 	return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
-			"ic%02Xisc%02Xip%02X\n",
+			"ic%02Xisc%02Xip%02Xin%02X\n",
 			le16_to_cpu(udev->descriptor.idVendor),
 			le16_to_cpu(udev->descriptor.idProduct),
 			le16_to_cpu(udev->descriptor.bcdDevice),
@@ -849,7 +849,8 @@ static ssize_t show_modalias(struct device *dev,
 			udev->descriptor.bDeviceProtocol,
 			alt->desc.bInterfaceClass,
 			alt->desc.bInterfaceSubClass,
-			alt->desc.bInterfaceProtocol);
+			alt->desc.bInterfaceProtocol,
+			alt->desc.bInterfaceNumber);
 }
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 3df1a19..ec70df7 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1091,7 +1091,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
 		if (r == req) {
 			/* wait until it is processed */
 			dwc3_stop_active_transfer(dwc, dep->number);
-			goto out0;
+			goto out1;
 		}
 		dev_err(dwc->dev, "request %p was not queued to %s\n",
 				request, ep->name);
@@ -1099,6 +1099,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
 		goto out0;
 	}
 
+out1:
 	/* giveback the request */
 	dwc3_gadget_giveback(dep, req, -ECONNRESET);
 
diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c
index 1fc8f12..ee0ebac 100644
--- a/drivers/usb/early/ehci-dbgp.c
+++ b/drivers/usb/early/ehci-dbgp.c
@@ -334,7 +334,7 @@ static int dbgp_control_msg(unsigned devnum, int requesttype,
 	int ret;
 
 	read = (requesttype & USB_DIR_IN) != 0;
-	if (size > (read ? DBGP_MAX_PACKET:0))
+	if (size > (read ? DBGP_MAX_PACKET : 0))
 		return -1;
 
 	/* Compute the control message */
diff --git a/drivers/usb/gadget/fsl_qe_udc.h b/drivers/usb/gadget/fsl_qe_udc.h
index 4c07ca9..7026919 100644
--- a/drivers/usb/gadget/fsl_qe_udc.h
+++ b/drivers/usb/gadget/fsl_qe_udc.h
@@ -153,10 +153,10 @@ struct usb_ep_para{
 #define USB_BUSMODE_DTB		0x02
 
 /* Endpoint basic handle */
-#define ep_index(EP)		((EP)->desc->bEndpointAddress & 0xF)
+#define ep_index(EP)		((EP)->ep.desc->bEndpointAddress & 0xF)
 #define ep_maxpacket(EP)	((EP)->ep.maxpacket)
 #define ep_is_in(EP)	((ep_index(EP) == 0) ? (EP->udc->ep0_dir == \
-			USB_DIR_IN) : ((EP)->desc->bEndpointAddress \
+			USB_DIR_IN) : ((EP)->ep.desc->bEndpointAddress \
 			& USB_DIR_IN) == USB_DIR_IN)
 
 /* ep0 transfer state */
diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c
index 262acfd..2ab0388 100644
--- a/drivers/usb/gadget/lpc32xx_udc.c
+++ b/drivers/usb/gadget/lpc32xx_udc.c
@@ -61,6 +61,7 @@
 #include <mach/irqs.h>
 #include <mach/board.h>
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
+#include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #endif
 
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 8981fbb..cf6bd62 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -1583,12 +1583,10 @@ static int __exit m66592_remove(struct platform_device *pdev)
 	iounmap(m66592->reg);
 	free_irq(platform_get_irq(pdev, 0), m66592);
 	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
-#ifdef CONFIG_HAVE_CLK
 	if (m66592->pdata->on_chip) {
 		clk_disable(m66592->clk);
 		clk_put(m66592->clk);
 	}
-#endif
 	kfree(m66592);
 	return 0;
 }
@@ -1602,9 +1600,7 @@ static int __init m66592_probe(struct platform_device *pdev)
 	struct resource *res, *ires;
 	void __iomem *reg = NULL;
 	struct m66592 *m66592 = NULL;
-#ifdef CONFIG_HAVE_CLK
 	char clk_name[8];
-#endif
 	int ret = 0;
 	int i;
 
@@ -1671,7 +1667,6 @@ static int __init m66592_probe(struct platform_device *pdev)
 		goto clean_up;
 	}
 
-#ifdef CONFIG_HAVE_CLK
 	if (m66592->pdata->on_chip) {
 		snprintf(clk_name, sizeof(clk_name), "usbf%d", pdev->id);
 		m66592->clk = clk_get(&pdev->dev, clk_name);
@@ -1683,7 +1678,7 @@ static int __init m66592_probe(struct platform_device *pdev)
 		}
 		clk_enable(m66592->clk);
 	}
-#endif
+
 	INIT_LIST_HEAD(&m66592->gadget.ep_list);
 	m66592->gadget.ep0 = &m66592->ep[0].ep;
 	INIT_LIST_HEAD(&m66592->gadget.ep0->ep_list);
@@ -1731,13 +1726,11 @@ err_add_udc:
 	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
 
 clean_up3:
-#ifdef CONFIG_HAVE_CLK
 	if (m66592->pdata->on_chip) {
 		clk_disable(m66592->clk);
 		clk_put(m66592->clk);
 	}
 clean_up2:
-#endif
 	free_irq(ires->start, m66592);
 clean_up:
 	if (m66592) {
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 88c85b4..16c7e14 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -13,10 +13,7 @@
 #ifndef __M66592_UDC_H__
 #define __M66592_UDC_H__
 
-#ifdef CONFIG_HAVE_CLK
 #include <linux/clk.h>
-#endif
-
 #include <linux/usb/m66592.h>
 
 #define M66592_SYSCFG		0x00
@@ -468,9 +465,7 @@ struct m66592_ep {
 struct m66592 {
 	spinlock_t		lock;
 	void __iomem		*reg;
-#ifdef CONFIG_HAVE_CLK
 	struct clk *clk;
-#endif
 	struct m66592_platdata	*pdata;
 	unsigned long		irq_trigger;
 
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index f3ac2a2..5a80751 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -1831,12 +1831,12 @@ static int __exit r8a66597_remove(struct platform_device *pdev)
 		iounmap(r8a66597->sudmac_reg);
 	free_irq(platform_get_irq(pdev, 0), r8a66597);
 	r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
-#ifdef CONFIG_HAVE_CLK
+
 	if (r8a66597->pdata->on_chip) {
 		clk_disable(r8a66597->clk);
 		clk_put(r8a66597->clk);
 	}
-#endif
+
 	device_unregister(&r8a66597->gadget.dev);
 	kfree(r8a66597);
 	return 0;
@@ -1868,9 +1868,7 @@ static int __init r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597,
 
 static int __init r8a66597_probe(struct platform_device *pdev)
 {
-#ifdef CONFIG_HAVE_CLK
 	char clk_name[8];
-#endif
 	struct resource *res, *ires;
 	int irq;
 	void __iomem *reg = NULL;
@@ -1934,7 +1932,6 @@ static int __init r8a66597_probe(struct platform_device *pdev)
 	r8a66597->timer.data = (unsigned long)r8a66597;
 	r8a66597->reg = reg;
 
-#ifdef CONFIG_HAVE_CLK
 	if (r8a66597->pdata->on_chip) {
 		snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
 		r8a66597->clk = clk_get(&pdev->dev, clk_name);
@@ -1946,7 +1943,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
 		}
 		clk_enable(r8a66597->clk);
 	}
-#endif
+
 	if (r8a66597->pdata->sudmac) {
 		ret = r8a66597_sudmac_ioremap(r8a66597, pdev);
 		if (ret < 0)
@@ -2006,13 +2003,11 @@ err_add_udc:
 clean_up3:
 	free_irq(irq, r8a66597);
 clean_up2:
-#ifdef CONFIG_HAVE_CLK
 	if (r8a66597->pdata->on_chip) {
 		clk_disable(r8a66597->clk);
 		clk_put(r8a66597->clk);
 	}
 clean_up_dev:
-#endif
 	device_unregister(&r8a66597->gadget.dev);
 clean_up:
 	if (r8a66597) {
diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h
index 99908c7..45c4b2d 100644
--- a/drivers/usb/gadget/r8a66597-udc.h
+++ b/drivers/usb/gadget/r8a66597-udc.h
@@ -13,10 +13,7 @@
 #ifndef __R8A66597_H__
 #define __R8A66597_H__
 
-#ifdef CONFIG_HAVE_CLK
 #include <linux/clk.h>
-#endif
-
 #include <linux/usb/r8a66597.h>
 
 #define R8A66597_MAX_SAMPLING	10
@@ -92,9 +89,7 @@ struct r8a66597 {
 	void __iomem		*reg;
 	void __iomem		*sudmac_reg;
 
-#ifdef CONFIG_HAVE_CLK
 	struct clk *clk;
-#endif
 	struct r8a66597_platdata	*pdata;
 
 	struct usb_gadget		gadget;
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 83e58df..18ba33d 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -652,7 +652,7 @@ config USB_HCD_BCMA
 	select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
 	select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
 	help
-	  Enbale support for the EHCI and OCHI host controller on an bcma bus.
+	  Enable support for the EHCI and OCHI host controller on an bcma bus.
 	  It converts the bcma driver into two platform device drivers
 	  for ehci and ohci.
 
@@ -664,7 +664,7 @@ config USB_HCD_SSB
 	select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
 	select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
 	help
-	  Enbale support for the EHCI and OCHI host controller on an bcma bus.
+	  Enable support for the EHCI and OCHI host controller on an bcma bus.
 	  It converts the bcma driver into two platform device drivers
 	  for ehci and ohci.
 
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 4336257..3379945 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -142,19 +142,19 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 	if (pdata->operating_mode == FSL_USB2_DR_OTG) {
 		struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
-		ehci->transceiver = usb_get_transceiver();
-		dev_dbg(&pdev->dev, "hcd=0x%p  ehci=0x%p, transceiver=0x%p\n",
-			hcd, ehci, ehci->transceiver);
+		hcd->phy = usb_get_transceiver();
+		dev_dbg(&pdev->dev, "hcd=0x%p  ehci=0x%p, phy=0x%p\n",
+			hcd, ehci, hcd->phy);
 
-		if (ehci->transceiver) {
-			retval = otg_set_host(ehci->transceiver->otg,
+		if (hcd->phy) {
+			retval = otg_set_host(hcd->phy->otg,
 					      &ehci_to_hcd(ehci)->self);
 			if (retval) {
-				usb_put_transceiver(ehci->transceiver);
+				usb_put_transceiver(hcd->phy);
 				goto err4;
 			}
 		} else {
-			dev_err(&pdev->dev, "can't find transceiver\n");
+			dev_err(&pdev->dev, "can't find phy\n");
 			retval = -ENODEV;
 			goto err4;
 		}
@@ -190,11 +190,10 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
 			       struct platform_device *pdev)
 {
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
-	if (ehci->transceiver) {
-		otg_set_host(ehci->transceiver->otg, NULL);
-		usb_put_transceiver(ehci->transceiver);
+	if (hcd->phy) {
+		otg_set_host(hcd->phy->otg, NULL);
+		usb_put_transceiver(hcd->phy);
 	}
 
 	usb_remove_hcd(hcd);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 800be38..1d9401e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1349,6 +1349,11 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER		ehci_msm_driver
 #endif
 
+#ifdef CONFIG_TILE_USB
+#include "ehci-tilegx.c"
+#define	PLATFORM_DRIVER		ehci_hcd_tilegx_driver
+#endif
+
 #ifdef CONFIG_USB_EHCI_HCD_PMC_MSP
 #include "ehci-pmcmsp.c"
 #define	PLATFORM_DRIVER		ehci_hcd_msp_driver
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index fc9e7cc..dd5eef6 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -724,7 +724,7 @@ static int ehci_hub_control (
 #ifdef CONFIG_USB_OTG
 			if ((hcd->self.otg_port == (wIndex + 1))
 			    && hcd->self.b_hnp_enable) {
-				otg_start_hnp(ehci->transceiver->otg);
+				otg_start_hnp(hcd->phy->otg);
 				break;
 			}
 #endif
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 6854823..ab8a3bf 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -46,8 +46,8 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd)
 {
 	struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
 
-	clk_enable(tegra->emc_clk);
-	clk_enable(tegra->clk);
+	clk_prepare_enable(tegra->emc_clk);
+	clk_prepare_enable(tegra->clk);
 	tegra_usb_phy_power_on(tegra->phy);
 	tegra->host_resumed = 1;
 }
@@ -58,8 +58,8 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd)
 
 	tegra->host_resumed = 0;
 	tegra_usb_phy_power_off(tegra->phy);
-	clk_disable(tegra->clk);
-	clk_disable(tegra->emc_clk);
+	clk_disable_unprepare(tegra->clk);
+	clk_disable_unprepare(tegra->emc_clk);
 }
 
 static int tegra_ehci_internal_port_reset(
@@ -671,7 +671,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 		goto fail_clk;
 	}
 
-	err = clk_enable(tegra->clk);
+	err = clk_prepare_enable(tegra->clk);
 	if (err)
 		goto fail_clken;
 
@@ -682,7 +682,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 		goto fail_emc_clk;
 	}
 
-	clk_enable(tegra->emc_clk);
+	clk_prepare_enable(tegra->emc_clk);
 	clk_set_rate(tegra->emc_clk, 400000000);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -782,10 +782,10 @@ fail:
 fail_phy:
 	iounmap(hcd->regs);
 fail_io:
-	clk_disable(tegra->emc_clk);
+	clk_disable_unprepare(tegra->emc_clk);
 	clk_put(tegra->emc_clk);
 fail_emc_clk:
-	clk_disable(tegra->clk);
+	clk_disable_unprepare(tegra->clk);
 fail_clken:
 	clk_put(tegra->clk);
 fail_clk:
@@ -820,10 +820,10 @@ static int tegra_ehci_remove(struct platform_device *pdev)
 	tegra_usb_phy_close(tegra->phy);
 	iounmap(hcd->regs);
 
-	clk_disable(tegra->clk);
+	clk_disable_unprepare(tegra->clk);
 	clk_put(tegra->clk);
 
-	clk_disable(tegra->emc_clk);
+	clk_disable_unprepare(tegra->emc_clk);
 	clk_put(tegra->emc_clk);
 
 	kfree(tegra);
diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c
new file mode 100644
index 0000000..1d215cd
--- /dev/null
+++ b/drivers/usb/host/ehci-tilegx.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/*
+ * Tilera TILE-Gx USB EHCI host controller driver.
+ */
+
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/usb/tilegx.h>
+#include <linux/usb.h>
+
+#include <asm/homecache.h>
+
+#include <gxio/iorpc_usb_host.h>
+#include <gxio/usb_host.h>
+
+static void tilegx_start_ehc(void)
+{
+}
+
+static void tilegx_stop_ehc(void)
+{
+}
+
+static int tilegx_ehci_setup(struct usb_hcd *hcd)
+{
+	int ret = ehci_init(hcd);
+
+	/*
+	 * Some drivers do:
+	 *
+	 *   struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	 *   ehci->need_io_watchdog = 0;
+	 *
+	 * here, but since this is a new driver we're going to leave the
+	 * watchdog enabled.  Later we may try to turn it off and see
+	 * whether we run into any problems.
+	 */
+
+	return ret;
+}
+
+static const struct hc_driver ehci_tilegx_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "Tile-Gx EHCI",
+	.hcd_priv_size		= sizeof(struct ehci_hcd),
+
+	/*
+	 * Generic hardware linkage.
+	 */
+	.irq			= ehci_irq,
+	.flags			= HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * Basic lifecycle operations.
+	 */
+	.reset			= tilegx_ehci_setup,
+	.start			= ehci_run,
+	.stop			= ehci_stop,
+	.shutdown		= ehci_shutdown,
+
+	/*
+	 * Managing I/O requests and associated device resources.
+	 */
+	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_dequeue		= ehci_urb_dequeue,
+	.endpoint_disable	= ehci_endpoint_disable,
+	.endpoint_reset		= ehci_endpoint_reset,
+
+	/*
+	 * Scheduling support.
+	 */
+	.get_frame_number	= ehci_get_frame,
+
+	/*
+	 * Root hub support.
+	 */
+	.hub_status_data	= ehci_hub_status_data,
+	.hub_control		= ehci_hub_control,
+	.bus_suspend		= ehci_bus_suspend,
+	.bus_resume		= ehci_bus_resume,
+	.relinquish_port	= ehci_relinquish_port,
+	.port_handed_over	= ehci_port_handed_over,
+
+	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
+};
+
+static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd;
+	struct ehci_hcd *ehci;
+	struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+	pte_t pte = { 0 };
+	int my_cpu = smp_processor_id();
+	int ret;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	/*
+	 * Try to initialize our GXIO context; if we can't, the device
+	 * doesn't exist.
+	 */
+	if (gxio_usb_host_init(&pdata->usb_ctx, pdata->dev_index, 1) != 0)
+		return -ENXIO;
+
+	hcd = usb_create_hcd(&ehci_tilegx_hc_driver, &pdev->dev,
+			     dev_name(&pdev->dev));
+	if (!hcd)
+		return -ENOMEM;
+
+	/*
+	 * We don't use rsrc_start to map in our registers, but seems like
+	 * we ought to set it to something, so we use the register VA.
+	 */
+	hcd->rsrc_start =
+		(ulong) gxio_usb_host_get_reg_start(&pdata->usb_ctx);
+	hcd->rsrc_len = gxio_usb_host_get_reg_len(&pdata->usb_ctx);
+	hcd->regs = gxio_usb_host_get_reg_start(&pdata->usb_ctx);
+
+	tilegx_start_ehc();
+
+	ehci = hcd_to_ehci(hcd);
+	ehci->caps = hcd->regs;
+	ehci->regs =
+		hcd->regs + HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
+	/* cache this readonly data; minimize chip reads */
+	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+	/* Create our IRQs and register them. */
+	pdata->irq = create_irq();
+	if (pdata->irq < 0) {
+		ret = -ENXIO;
+		goto err_no_irq;
+	}
+
+	tile_irq_activate(pdata->irq, TILE_IRQ_PERCPU);
+
+	/* Configure interrupts. */
+	ret = gxio_usb_host_cfg_interrupt(&pdata->usb_ctx,
+					  cpu_x(my_cpu), cpu_y(my_cpu),
+					  KERNEL_PL, pdata->irq);
+	if (ret) {
+		ret = -ENXIO;
+		goto err_have_irq;
+	}
+
+	/* Register all of our memory. */
+	pte = pte_set_home(pte, PAGE_HOME_HASH);
+	ret = gxio_usb_host_register_client_memory(&pdata->usb_ctx, pte, 0);
+	if (ret) {
+		ret = -ENXIO;
+		goto err_have_irq;
+	}
+
+	ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED);
+	if (ret == 0) {
+		platform_set_drvdata(pdev, hcd);
+		return ret;
+	}
+
+err_have_irq:
+	destroy_irq(pdata->irq);
+err_no_irq:
+	tilegx_stop_ehc();
+	usb_put_hcd(hcd);
+	gxio_usb_host_destroy(&pdata->usb_ctx);
+	return ret;
+}
+
+static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+
+	usb_remove_hcd(hcd);
+	usb_put_hcd(hcd);
+	tilegx_stop_ehc();
+	gxio_usb_host_destroy(&pdata->usb_ctx);
+	destroy_irq(pdata->irq);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static void ehci_hcd_tilegx_drv_shutdown(struct platform_device *pdev)
+{
+	usb_hcd_platform_shutdown(pdev);
+	ehci_hcd_tilegx_drv_remove(pdev);
+}
+
+static struct platform_driver ehci_hcd_tilegx_driver = {
+	.probe		= ehci_hcd_tilegx_drv_probe,
+	.remove		= ehci_hcd_tilegx_drv_remove,
+	.shutdown	= ehci_hcd_tilegx_drv_shutdown,
+	.driver = {
+		.name	= "tilegx-ehci",
+		.owner	= THIS_MODULE,
+	}
+};
+
+MODULE_ALIAS("platform:tilegx-ehci");
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 2694ed6..85c3572 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -175,10 +175,6 @@ struct ehci_hcd {			/* one per controller */
 #ifdef DEBUG
 	struct dentry		*debug_dir;
 #endif
-	/*
-	 * OTG controllers and transceivers need software interaction
-	 */
-	struct usb_phy	*transceiver;
 };
 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index e0adf5c..2b1e8d8 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1100,6 +1100,11 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER		ohci_octeon_driver
 #endif
 
+#ifdef CONFIG_TILE_USB
+#include "ohci-tilegx.c"
+#define PLATFORM_DRIVER		ohci_hcd_tilegx_driver
+#endif
+
 #ifdef CONFIG_USB_CNS3XXX_OHCI
 #include "ohci-cns3xxx.c"
 #define PLATFORM_DRIVER		ohci_hcd_cns3xxx_driver
diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c
index 1e364ec..a446386 100644
--- a/drivers/usb/host/ohci-nxp.c
+++ b/drivers/usb/host/ohci-nxp.c
@@ -43,16 +43,6 @@
 #define USB_HOST_NEED_CLK_EN	(1 << 21)
 #define PAD_CONTROL_LAST_DRIVEN	(1 << 19)
 
-#define USB_OTG_CLK_CTRL	IO_ADDRESS(USB_CONFIG_BASE + 0xFF4)
-#define USB_OTG_CLK_STAT	IO_ADDRESS(USB_CONFIG_BASE + 0xFF8)
-
-/* USB_OTG_CLK_CTRL bit defines */
-#define AHB_M_CLOCK_ON		(1 << 4)
-#define OTG_CLOCK_ON		(1 << 3)
-#define I2C_CLOCK_ON		(1 << 2)
-#define DEV_CLOCK_ON		(1 << 1)
-#define HOST_CLOCK_ON		(1 << 0)
-
 #define USB_OTG_STAT_CONTROL	IO_ADDRESS(USB_CONFIG_BASE + 0x110)
 
 /* USB_OTG_STAT_CONTROL bit defines */
@@ -72,7 +62,9 @@ static struct i2c_client *isp1301_i2c_client;
 
 extern int usb_disabled(void);
 
-static struct clk *usb_clk;
+static struct clk *usb_pll_clk;
+static struct clk *usb_dev_clk;
+static struct clk *usb_otg_clk;
 
 static void isp1301_configure_pnx4008(void)
 {
@@ -249,8 +241,6 @@ static const struct hc_driver ohci_nxp_hc_driver = {
 	.start_port_reset = ohci_start_port_reset,
 };
 
-#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON)
-
 static void nxp_set_usb_bits(void)
 {
 	if (machine_is_pnx4008()) {
@@ -327,41 +317,63 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
 	/* Enable AHB slave USB clock, needed for further USB clock control */
 	__raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL);
 
-	isp1301_configure();
-
 	/* Enable USB PLL */
-	usb_clk = clk_get(&pdev->dev, "ck_pll5");
-	if (IS_ERR(usb_clk)) {
+	usb_pll_clk = clk_get(&pdev->dev, "ck_pll5");
+	if (IS_ERR(usb_pll_clk)) {
 		dev_err(&pdev->dev, "failed to acquire USB PLL\n");
-		ret = PTR_ERR(usb_clk);
+		ret = PTR_ERR(usb_pll_clk);
 		goto out1;
 	}
 
-	ret = clk_enable(usb_clk);
+	ret = clk_enable(usb_pll_clk);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to start USB PLL\n");
 		goto out2;
 	}
 
-	ret = clk_set_rate(usb_clk, 48000);
+	ret = clk_set_rate(usb_pll_clk, 48000);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to set USB clock rate\n");
 		goto out3;
 	}
 
+	/* Enable USB device clock */
+	usb_dev_clk = clk_get(&pdev->dev, "ck_usbd");
+	if (IS_ERR(usb_dev_clk)) {
+		dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
+		ret = PTR_ERR(usb_dev_clk);
+		goto out4;
+	}
+
+	ret = clk_enable(usb_dev_clk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
+		goto out5;
+	}
+
+	/* Enable USB otg clocks */
+	usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
+	if (IS_ERR(usb_otg_clk)) {
+		dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
+		ret = PTR_ERR(usb_dev_clk);
+		goto out6;
+	}
+
 	__raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
 
-	/* Set to enable all needed USB clocks */
-	__raw_writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL);
+	ret = clk_enable(usb_otg_clk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
+		goto out7;
+	}
 
-	while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
-	       USB_CLOCK_MASK) ;
+	isp1301_configure();
 
 	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
 	if (!hcd) {
 		dev_err(&pdev->dev, "Failed to allocate HC buffer\n");
 		ret = -ENOMEM;
-		goto out3;
+		goto out8;
 	}
 
 	/* Set all USB bits in the Start Enable register */
@@ -371,14 +383,14 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
 	if (!res) {
 		dev_err(&pdev->dev, "Failed to get MEM resource\n");
 		ret =  -ENOMEM;
-		goto out4;
+		goto out8;
 	}
 
 	hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (!hcd->regs) {
 		dev_err(&pdev->dev, "Failed to devm_request_and_ioremap\n");
 		ret =  -ENOMEM;
-		goto out4;
+		goto out8;
 	}
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
@@ -386,7 +398,7 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
 		ret = -ENXIO;
-		goto out4;
+		goto out8;
 	}
 
 	nxp_start_hc();
@@ -400,13 +412,21 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
 		return ret;
 
 	nxp_stop_hc();
-out4:
+out8:
 	nxp_unset_usb_bits();
 	usb_put_hcd(hcd);
+out7:
+	clk_disable(usb_otg_clk);
+out6:
+	clk_put(usb_otg_clk);
+out5:
+	clk_disable(usb_dev_clk);
+out4:
+	clk_put(usb_dev_clk);
 out3:
-	clk_disable(usb_clk);
+	clk_disable(usb_pll_clk);
 out2:
-	clk_put(usb_clk);
+	clk_put(usb_pll_clk);
 out1:
 	isp1301_i2c_client = NULL;
 out:
@@ -422,8 +442,10 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev)
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 	nxp_unset_usb_bits();
-	clk_disable(usb_clk);
-	clk_put(usb_clk);
+	clk_disable(usb_pll_clk);
+	clk_put(usb_pll_clk);
+	clk_disable(usb_dev_clk);
+	clk_put(usb_dev_clk);
 	i2c_unregister_device(isp1301_i2c_client);
 	isp1301_i2c_client = NULL;
 
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 9ce35d0..eccddb4 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -167,14 +167,15 @@ static int omap_1510_local_bus_init(void)
 
 static void start_hnp(struct ohci_hcd *ohci)
 {
-	const unsigned	port = ohci_to_hcd(ohci)->self.otg_port - 1;
+	struct usb_hcd *hcd = ohci_to_hcd(ohci);
+	const unsigned	port = hcd->self.otg_port - 1;
 	unsigned long	flags;
 	u32 l;
 
-	otg_start_hnp(ohci->transceiver->otg);
+	otg_start_hnp(hcd->phy->otg);
 
 	local_irq_save(flags);
-	ohci->transceiver->state = OTG_STATE_A_SUSPEND;
+	hcd->phy->state = OTG_STATE_A_SUSPEND;
 	writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]);
 	l = omap_readl(OTG_CTRL);
 	l &= ~OTG_A_BUSREQ;
@@ -211,18 +212,18 @@ static int ohci_omap_init(struct usb_hcd *hcd)
 
 #ifdef	CONFIG_USB_OTG
 	if (need_transceiver) {
-		ohci->transceiver = usb_get_transceiver();
-		if (ohci->transceiver) {
-			int	status = otg_set_host(ohci->transceiver->otg,
+		hcd->phy = usb_get_transceiver();
+		if (hcd->phy) {
+			int	status = otg_set_host(hcd->phy->otg,
 						&ohci_to_hcd(ohci)->self);
-			dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
-					ohci->transceiver->label, status);
+			dev_dbg(hcd->self.controller, "init %s phy, status %d\n",
+					hcd->phy->label, status);
 			if (status) {
-				usb_put_transceiver(ohci->transceiver);
+				usb_put_transceiver(hcd->phy);
 				return status;
 			}
 		} else {
-			dev_err(hcd->self.controller, "can't find transceiver\n");
+			dev_err(hcd->self.controller, "can't find phy\n");
 			return -ENODEV;
 		}
 		ohci->start_hnp = start_hnp;
@@ -403,9 +404,9 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 
 	usb_remove_hcd(hcd);
-	if (ohci->transceiver) {
-		(void) otg_set_host(ohci->transceiver->otg, 0);
-		usb_put_transceiver(ohci->transceiver);
+	if (hcd->phy) {
+		(void) otg_set_host(hcd->phy->otg, 0);
+		usb_put_transceiver(hcd->phy);
 	}
 	if (machine_is_omap_osk())
 		gpio_free(9);
diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c
new file mode 100644
index 0000000..1ae7b28
--- /dev/null
+++ b/drivers/usb/host/ohci-tilegx.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/*
+ * Tilera TILE-Gx USB OHCI host controller driver.
+ */
+
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/usb/tilegx.h>
+#include <linux/usb.h>
+
+#include <asm/homecache.h>
+
+#include <gxio/iorpc_usb_host.h>
+#include <gxio/usb_host.h>
+
+static void tilegx_start_ohc(void)
+{
+}
+
+static void tilegx_stop_ohc(void)
+{
+}
+
+static int tilegx_ohci_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+	int ret;
+
+	ret = ohci_init(ohci);
+	if (ret < 0)
+		return ret;
+
+	ret = ohci_run(ohci);
+	if (ret < 0) {
+		dev_err(hcd->self.controller, "can't start %s\n",
+			hcd->self.bus_name);
+		ohci_stop(hcd);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct hc_driver ohci_tilegx_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "Tile-Gx OHCI",
+	.hcd_priv_size		= sizeof(struct ohci_hcd),
+
+	/*
+	 * Generic hardware linkage.
+	 */
+	.irq			= ohci_irq,
+	.flags			= HCD_MEMORY | HCD_LOCAL_MEM | HCD_USB11,
+
+	/*
+	 * Basic lifecycle operations.
+	 */
+	.start			= tilegx_ohci_start,
+	.stop			= ohci_stop,
+	.shutdown		= ohci_shutdown,
+
+	/*
+	 * Managing I/O requests and associated device resources.
+	 */
+	.urb_enqueue		= ohci_urb_enqueue,
+	.urb_dequeue		= ohci_urb_dequeue,
+	.endpoint_disable	= ohci_endpoint_disable,
+
+	/*
+	 * Scheduling support.
+	 */
+	.get_frame_number	= ohci_get_frame,
+
+	/*
+	 * Root hub support.
+	 */
+	.hub_status_data	= ohci_hub_status_data,
+	.hub_control		= ohci_hub_control,
+	.start_port_reset	= ohci_start_port_reset,
+};
+
+static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd;
+	struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+	pte_t pte = { 0 };
+	int my_cpu = smp_processor_id();
+	int ret;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	/*
+	 * Try to initialize our GXIO context; if we can't, the device
+	 * doesn't exist.
+	 */
+	if (gxio_usb_host_init(&pdata->usb_ctx, pdata->dev_index, 0) != 0)
+		return -ENXIO;
+
+	hcd = usb_create_hcd(&ohci_tilegx_hc_driver, &pdev->dev,
+			     dev_name(&pdev->dev));
+	if (!hcd)
+		return -ENOMEM;
+
+	/*
+	 * We don't use rsrc_start to map in our registers, but seems like
+	 * we ought to set it to something, so we use the register VA.
+	 */
+	hcd->rsrc_start =
+		(ulong) gxio_usb_host_get_reg_start(&pdata->usb_ctx);
+	hcd->rsrc_len = gxio_usb_host_get_reg_len(&pdata->usb_ctx);
+	hcd->regs = gxio_usb_host_get_reg_start(&pdata->usb_ctx);
+
+	tilegx_start_ohc();
+
+	/* Create our IRQs and register them. */
+	pdata->irq = create_irq();
+	if (pdata->irq < 0) {
+		ret = -ENXIO;
+		goto err_no_irq;
+	}
+
+	tile_irq_activate(pdata->irq, TILE_IRQ_PERCPU);
+
+	/* Configure interrupts. */
+	ret = gxio_usb_host_cfg_interrupt(&pdata->usb_ctx,
+					  cpu_x(my_cpu), cpu_y(my_cpu),
+					  KERNEL_PL, pdata->irq);
+	if (ret) {
+		ret = -ENXIO;
+		goto err_have_irq;
+	}
+
+	/* Register all of our memory. */
+	pte = pte_set_home(pte, PAGE_HOME_HASH);
+	ret = gxio_usb_host_register_client_memory(&pdata->usb_ctx, pte, 0);
+	if (ret) {
+		ret = -ENXIO;
+		goto err_have_irq;
+	}
+
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED);
+	if (ret == 0) {
+		platform_set_drvdata(pdev, hcd);
+		return ret;
+	}
+
+err_have_irq:
+	destroy_irq(pdata->irq);
+err_no_irq:
+	tilegx_stop_ohc();
+	usb_put_hcd(hcd);
+	gxio_usb_host_destroy(&pdata->usb_ctx);
+	return ret;
+}
+
+static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct tilegx_usb_platform_data* pdata = pdev->dev.platform_data;
+
+	usb_remove_hcd(hcd);
+	usb_put_hcd(hcd);
+	tilegx_stop_ohc();
+	gxio_usb_host_destroy(&pdata->usb_ctx);
+	destroy_irq(pdata->irq);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static void ohci_hcd_tilegx_drv_shutdown(struct platform_device *pdev)
+{
+	usb_hcd_platform_shutdown(pdev);
+	ohci_hcd_tilegx_drv_remove(pdev);
+}
+
+static struct platform_driver ohci_hcd_tilegx_driver = {
+	.probe		= ohci_hcd_tilegx_drv_probe,
+	.remove		= ohci_hcd_tilegx_drv_remove,
+	.shutdown	= ohci_hcd_tilegx_drv_shutdown,
+	.driver = {
+		.name	= "tilegx-ohci",
+		.owner	= THIS_MODULE,
+	}
+};
+
+MODULE_ALIAS("platform:tilegx-ohci");
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 1b19aea..d329914 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -372,11 +372,6 @@ struct ohci_hcd {
 	struct ed		*ed_controltail;	/* last in ctrl list */
 	struct ed		*periodic [NUM_INTS];	/* shadow int_table */
 
-	/*
-	 * OTG controllers and transceivers need software interaction;
-	 * other external transceivers should be software-transparent
-	 */
-	struct usb_phy	*transceiver;
 	void (*start_hnp)(struct ohci_hcd *ohci);
 
 	/*
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index c868be6..4c634eb 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -95,9 +95,7 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
 	int i = 0;
 
 	if (r8a66597->pdata->on_chip) {
-#ifdef CONFIG_HAVE_CLK
 		clk_enable(r8a66597->clk);
-#endif
 		do {
 			r8a66597_write(r8a66597, SCKE, SYSCFG0);
 			tmp = r8a66597_read(r8a66597, SYSCFG0);
@@ -141,9 +139,7 @@ static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
 	udelay(1);
 
 	if (r8a66597->pdata->on_chip) {
-#ifdef CONFIG_HAVE_CLK
 		clk_disable(r8a66597->clk);
-#endif
 	} else {
 		r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
 		r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
@@ -2406,19 +2402,15 @@ static int __devexit r8a66597_remove(struct platform_device *pdev)
 	del_timer_sync(&r8a66597->rh_timer);
 	usb_remove_hcd(hcd);
 	iounmap(r8a66597->reg);
-#ifdef CONFIG_HAVE_CLK
 	if (r8a66597->pdata->on_chip)
 		clk_put(r8a66597->clk);
-#endif
 	usb_put_hcd(hcd);
 	return 0;
 }
 
 static int __devinit r8a66597_probe(struct platform_device *pdev)
 {
-#ifdef CONFIG_HAVE_CLK
 	char clk_name[8];
-#endif
 	struct resource *res = NULL, *ires;
 	int irq = -1;
 	void __iomem *reg = NULL;
@@ -2482,7 +2474,6 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
 	r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
 
 	if (r8a66597->pdata->on_chip) {
-#ifdef CONFIG_HAVE_CLK
 		snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
 		r8a66597->clk = clk_get(&pdev->dev, clk_name);
 		if (IS_ERR(r8a66597->clk)) {
@@ -2491,7 +2482,6 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
 			ret = PTR_ERR(r8a66597->clk);
 			goto clean_up2;
 		}
-#endif
 		r8a66597->max_root_hub = 1;
 	} else
 		r8a66597->max_root_hub = 2;
@@ -2531,11 +2521,9 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
 	return 0;
 
 clean_up3:
-#ifdef CONFIG_HAVE_CLK
 	if (r8a66597->pdata->on_chip)
 		clk_put(r8a66597->clk);
 clean_up2:
-#endif
 	usb_put_hcd(hcd);
 
 clean_up:
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index f28782d..672cea3 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -26,10 +26,7 @@
 #ifndef __R8A66597_H__
 #define __R8A66597_H__
 
-#ifdef CONFIG_HAVE_CLK
 #include <linux/clk.h>
-#endif
-
 #include <linux/usb/r8a66597.h>
 
 #define R8A66597_MAX_NUM_PIPE		10
@@ -113,9 +110,7 @@ struct r8a66597_root_hub {
 struct r8a66597 {
 	spinlock_t lock;
 	void __iomem *reg;
-#ifdef CONFIG_HAVE_CLK
 	struct clk *clk;
-#endif
 	struct r8a66597_platdata	*pdata;
 	struct r8a66597_device		device0;
 	struct r8a66597_root_hub	root_hub[R8A66597_MAX_ROOT_HUB];
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index f4a40f0..f7bc23f 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -81,14 +81,6 @@ struct musb_ep;
 #define is_peripheral_active(m)		(!(m)->is_host)
 #define is_host_active(m)		((m)->is_host)
 
-#ifndef CONFIG_HAVE_CLK
-/* Dummy stub for clk framework */
-#define clk_get(dev, id)	NULL
-#define clk_put(clock)		do {} while (0)
-#define clk_enable(clock)	do {} while (0)
-#define clk_disable(clock)	do {} while (0)
-#endif
-
 #ifdef CONFIG_PROC_FS
 #include <linux/fs.h>
 #define MUSB_CONFIG_PROC_FS
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index ef8d744..e090c79 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -375,11 +375,21 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
 	 */
 	if (list_empty(&qh->hep->urb_list)) {
 		struct list_head	*head;
+		struct dma_controller	*dma = musb->dma_controller;
 
-		if (is_in)
+		if (is_in) {
 			ep->rx_reinit = 1;
-		else
+			if (ep->rx_channel) {
+				dma->channel_release(ep->rx_channel);
+				ep->rx_channel = NULL;
+			}
+		} else {
 			ep->tx_reinit = 1;
+			if (ep->tx_channel) {
+				dma->channel_release(ep->tx_channel);
+				ep->tx_channel = NULL;
+			}
+		}
 
 		/* Clobber old pointers to this qh */
 		musb_ep_set_qh(ep, is_in, NULL);
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
index d2a9a8e..0eabb04 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -305,9 +305,8 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
 
 		regulator_enable(twl->usb3v3);
 		twl->asleep = 1;
-		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, 0x1);
-		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
-								0x10);
+		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
+		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
 		status = USB_EVENT_ID;
 		otg->default_a = true;
 		twl->phy.state = OTG_STATE_A_IDLE;
@@ -316,12 +315,10 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
 		atomic_notifier_call_chain(&twl->phy.notifier, status,
 							otg->gadget);
 	} else  {
-		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR,
-								0x10);
-		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
-								0x1);
+		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
+		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
 	}
-	twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_LATCH_CLR, status);
+	twl6030_writeb(twl, TWL_MODULE_USB, status, USB_ID_INT_LATCH_CLR);
 
 	return IRQ_HANDLED;
 }
@@ -343,7 +340,7 @@ static int twl6030_enable_irq(struct usb_phy *x)
 {
 	struct twl6030_usb *twl = phy_to_twl(x);
 
-	twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, 0x1);
+	twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
 	twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C);
 	twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C);
 
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 3cfabcb..e7cf84f 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -2,11 +2,11 @@
 # Physical Layer USB driver configuration
 #
 comment "USB Physical Layer drivers"
-	depends on USB
+	depends on USB || USB_GADGET
 
 config USB_ISP1301
 	tristate "NXP ISP1301 USB transceiver support"
-	depends on USB
+	depends on USB || USB_GADGET
 	depends on I2C
 	help
 	  Say Y here to add support for the NXP ISP1301 USB transceiver driver.
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index a165490..8c9bb1a 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -19,7 +19,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
-#include "./common.h"
+#include "common.h"
 
 /*
  *		image of renesas_usbhs
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 3f3ccd3..dddf40a 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -22,8 +22,8 @@
 
 struct usbhs_priv;
 
-#include "./mod.h"
-#include "./pipe.h"
+#include "mod.h"
+#include "pipe.h"
 
 /*
  *
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 6ec7f83..0831357 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -17,8 +17,8 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/scatterlist.h>
-#include "./common.h"
-#include "./pipe.h"
+#include "common.h"
+#include "pipe.h"
 
 #define usbhsf_get_cfifo(p)	(&((p)->fifo_info.cfifo))
 #define usbhsf_get_d0fifo(p)	(&((p)->fifo_info.d0fifo))
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index 0871e81..82a628f 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -16,8 +16,8 @@
  */
 #include <linux/interrupt.h>
 
-#include "./common.h"
-#include "./mod.h"
+#include "common.h"
+#include "mod.h"
 
 #define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
 #define usbhs_mod_info_call(priv, func, param...)	\
diff --git a/drivers/usb/renesas_usbhs/mod.h b/drivers/usb/renesas_usbhs/mod.h
index 6c68755..1ef5bf6 100644
--- a/drivers/usb/renesas_usbhs/mod.h
+++ b/drivers/usb/renesas_usbhs/mod.h
@@ -19,7 +19,7 @@
 
 #include <linux/spinlock.h>
 #include <linux/usb/renesas_usbhs.h>
-#include "./common.h"
+#include "common.h"
 
 /*
  *	struct
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index feb06d6..122526c 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -16,8 +16,8 @@
  */
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include "./common.h"
-#include "./pipe.h"
+#include "common.h"
+#include "pipe.h"
 
 /*
  *		macros
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index fa18b7d..08786c0 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -17,8 +17,8 @@
 #ifndef RENESAS_USB_PIPE_H
 #define RENESAS_USB_PIPE_H
 
-#include "./common.h"
-#include "./fifo.h"
+#include "common.h"
+#include "fifo.h"
 
 /*
  *	struct
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 73d25cd..1e71079 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -93,6 +93,7 @@ static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
 	{ USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */
 	{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
+	{ USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */
 	{ USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */
 	{ USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
 	{ USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
@@ -134,7 +135,13 @@ static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */
 	{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
 	{ USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
+	{ USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */
+	{ USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */
 	{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
+	{ USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */
+	{ USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */
+	{ USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */
+	{ USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */
 	{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
 	{ USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
 	{ USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
@@ -146,7 +153,11 @@ static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
 	{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
 	{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
+	{ USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */
+	{ USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */
 	{ USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
+	{ USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */
+	{ USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */
 	{ USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
 	{ } /* Terminating Entry */
 };
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index a1b9924..9a0ca83 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1036,15 +1036,12 @@ static int keyspan_write_room(struct tty_struct *tty)
 static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
 	struct keyspan_port_private 	*p_priv;
-	struct keyspan_serial_private 	*s_priv;
-	struct usb_serial 		*serial = port->serial;
 	const struct keyspan_device_details	*d_details;
 	int				i, err;
 	int				baud_rate, device_port;
 	struct urb			*urb;
 	unsigned int			cflag = 0;
 
-	s_priv = usb_get_serial_data(serial);
 	p_priv = usb_get_serial_port_data(port);
 	d_details = p_priv->device_details;
 
@@ -1130,10 +1127,8 @@ static void keyspan_close(struct usb_serial_port *port)
 {
 	int			i;
 	struct usb_serial	*serial = port->serial;
-	struct keyspan_serial_private 	*s_priv;
 	struct keyspan_port_private 	*p_priv;
 
-	s_priv = usb_get_serial_data(serial);
 	p_priv = usb_get_serial_port_data(port);
 
 	p_priv->rts_state = 0;
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index e668a24..a0382b2 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -236,6 +236,7 @@ static void option_instat_callback(struct urb *urb);
 #define NOVATELWIRELESS_PRODUCT_G1		0xA001
 #define NOVATELWIRELESS_PRODUCT_G1_M		0xA002
 #define NOVATELWIRELESS_PRODUCT_G2		0xA010
+#define NOVATELWIRELESS_PRODUCT_MC551		0xB001
 
 /* AMOI PRODUCTS */
 #define AMOI_VENDOR_ID				0x1614
@@ -497,6 +498,10 @@ static void option_instat_callback(struct urb *urb);
 /* MediaTek products */
 #define MEDIATEK_VENDOR_ID			0x0e8d
 
+/* Cellient products */
+#define CELLIENT_VENDOR_ID			0x2692
+#define CELLIENT_PRODUCT_MEN200			0x9005
+
 /* some devices interfaces need special handling due to a number of reasons */
 enum option_blacklist_reason {
 		OPTION_BLACKLIST_NONE = 0,
@@ -734,6 +739,8 @@ static const struct usb_device_id option_ids[] = {
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1) },
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1_M) },
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) },
+	/* Novatel Ovation MC551 a.k.a. Verizon USB551L */
+	{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) },
 
 	{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) },
 	{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) },
@@ -1233,6 +1240,7 @@ static const struct usb_device_id option_ids[] = {
 	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) },        /* MediaTek MT6276M modem & app port */
+	{ USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
 	{ } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1276,6 +1284,10 @@ static struct usb_serial_driver * const serial_drivers[] = {
 
 static bool debug;
 
+struct option_private {
+	u8 bInterfaceNumber;
+};
+
 module_usb_serial_driver(serial_drivers, option_ids);
 
 static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
@@ -1306,51 +1318,78 @@ static int option_probe(struct usb_serial *serial,
 			const struct usb_device_id *id)
 {
 	struct usb_wwan_intf_private *data;
-
-	/* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */
-	if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID &&
-		serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 &&
-		serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8)
+	struct option_private *priv;
+	struct usb_interface_descriptor *iface_desc =
+				&serial->interface->cur_altsetting->desc;
+	struct usb_device_descriptor *dev_desc = &serial->dev->descriptor;
+
+	/*
+	 * D-Link DWM 652 still exposes CD-Rom emulation interface in modem
+	 * mode.
+	 */
+	if (dev_desc->idVendor == DLINK_VENDOR_ID &&
+		dev_desc->idProduct == DLINK_PRODUCT_DWM_652 &&
+		iface_desc->bInterfaceClass == 0x08)
 		return -ENODEV;
 
 	/* Bandrich modem and AT command interface is 0xff */
-	if ((serial->dev->descriptor.idVendor == BANDRICH_VENDOR_ID ||
-		serial->dev->descriptor.idVendor == PIRELLI_VENDOR_ID) &&
-		serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff)
+	if ((dev_desc->idVendor == BANDRICH_VENDOR_ID ||
+		dev_desc->idVendor == PIRELLI_VENDOR_ID) &&
+		iface_desc->bInterfaceClass != 0xff)
 		return -ENODEV;
-
-	/* Don't bind reserved interfaces (like network ones) which often have
+	/*
+	 * Don't bind reserved interfaces (like network ones) which often have
 	 * the same class/subclass/protocol as the serial interfaces.  Look at
 	 * the Windows driver .INF files for reserved interface numbers.
 	 */
 	if (is_blacklisted(
-		serial->interface->cur_altsetting->desc.bInterfaceNumber,
+		iface_desc->bInterfaceNumber,
 		OPTION_BLACKLIST_RESERVED_IF,
 		(const struct option_blacklist_info *) id->driver_info))
 		return -ENODEV;
-
-	/* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */
-	if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID &&
-		serial->dev->descriptor.idProduct == SAMSUNG_PRODUCT_GT_B3730 &&
-		serial->interface->cur_altsetting->desc.bInterfaceClass != USB_CLASS_CDC_DATA)
+	/*
+	 * Don't bind network interface on Samsung GT-B3730, it is handled by
+	 * a separate module.
+	 */
+	if (dev_desc->idVendor == SAMSUNG_VENDOR_ID &&
+		dev_desc->idProduct == SAMSUNG_PRODUCT_GT_B3730 &&
+		iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA)
 		return -ENODEV;
 
-	data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
+	data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
-	data->send_setup = option_send_setup;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		kfree(data);
+		return -ENOMEM;
+	}
+
+	priv->bInterfaceNumber = iface_desc->bInterfaceNumber;
+	data->private = priv;
+
+	if (!is_blacklisted(iface_desc->bInterfaceNumber,
+			OPTION_BLACKLIST_SENDSETUP,
+			(struct option_blacklist_info *)id->driver_info)) {
+		data->send_setup = option_send_setup;
+	}
 	spin_lock_init(&data->susp_lock);
-	data->private = (void *)id->driver_info;
+
+	usb_set_serial_data(serial, data);
+
 	return 0;
 }
 
 static void option_release(struct usb_serial *serial)
 {
-	struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
+	struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
+	struct option_private *priv = intfdata->private;
 
 	usb_wwan_release(serial);
 
 	kfree(priv);
+	kfree(intfdata);
 }
 
 static void option_instat_callback(struct urb *urb)
@@ -1417,18 +1456,11 @@ static void option_instat_callback(struct urb *urb)
 static int option_send_setup(struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
-	struct usb_wwan_intf_private *intfdata =
-		(struct usb_wwan_intf_private *) serial->private;
+	struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
+	struct option_private *priv = intfdata->private;
 	struct usb_wwan_port_private *portdata;
-	int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
 	int val = 0;
 
-	if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP,
-			(struct option_blacklist_info *) intfdata->private)) {
-		dbg("No send_setup on blacklisted interface #%d\n", ifNum);
-		return -EIO;
-	}
-
 	portdata = usb_get_serial_port_data(port);
 
 	if (portdata->dtr_state)
@@ -1436,9 +1468,9 @@ static int option_send_setup(struct usb_serial_port *port)
 	if (portdata->rts_state)
 		val |= 0x02;
 
-	return usb_control_msg(serial->dev,
-		usb_rcvctrlpipe(serial->dev, 0),
-		0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT);
+	return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+				0x22, 0x21, val, priv->bInterfaceNumber, NULL,
+				0, USB_CTRL_SET_TIMEOUT);
 }
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index 8dd88eb..151670b 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -345,7 +345,6 @@ static void qt2_set_termios(struct tty_struct *tty,
 static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
 	struct usb_serial *serial;
-	struct qt2_serial_private *serial_priv;
 	struct qt2_port_private *port_priv;
 	u8 *data;
 	u16 device_port;
@@ -357,7 +356,6 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
 	serial = port->serial;
 
 	port_priv = usb_get_serial_port_data(port);
-	serial_priv = usb_get_serial_data(serial);
 
 	/* set the port to RS232 mode */
 	status = qt2_control_msg(serial->dev, QT2_GET_SET_QMCR,
@@ -417,13 +415,11 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
 static void qt2_close(struct usb_serial_port *port)
 {
 	struct usb_serial *serial;
-	struct qt2_serial_private *serial_priv;
 	struct qt2_port_private *port_priv;
 	unsigned long flags;
 	int i;
 
 	serial = port->serial;
-	serial_priv = usb_get_serial_data(serial);
 	port_priv = usb_get_serial_port_data(port);
 
 	port_priv->is_open = false;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 27483f9..da67abb 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -207,7 +207,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
 	if (retval)
 		goto error_get_interface;
 
-	retval = tty_standard_install(driver, tty);
+	retval = tty_port_install(&port->port, driver, tty);
 	if (retval)
 		goto error_init_termios;
 
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 82dd834..5dfb4c3 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -66,7 +66,7 @@ void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us)
 	 * NOTE: This only works because a scsi_cmnd struct field contains
 	 * a unsigned char cmnd[16], so we know we have storage available
 	 */
-	for (; srb->cmd_len<12; srb->cmd_len++)
+	for (; srb->cmd_len < 12; srb->cmd_len++)
 		srb->cmnd[srb->cmd_len] = 0;
 
 	/* send the command to the transport layer */
@@ -76,14 +76,14 @@ void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us)
 void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us)
 {
 	/* fix some commands -- this is a form of mode translation
-	 * UFI devices only accept 12 byte long commands 
+	 * UFI devices only accept 12 byte long commands
 	 *
 	 * NOTE: This only works because a scsi_cmnd struct field contains
 	 * a unsigned char cmnd[16], so we know we have storage available
 	 */
 
 	/* Pad the ATAPI command with zeros */
-	for (; srb->cmd_len<12; srb->cmd_len++)
+	for (; srb->cmd_len < 12; srb->cmd_len++)
 		srb->cmnd[srb->cmd_len] = 0;
 
 	/* set command length to 12 bytes (this affects the transport layer) */
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index a324a5d..11418da 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -202,6 +202,12 @@ static int slave_configure(struct scsi_device *sdev)
 		if (us->fflags & US_FL_NO_READ_CAPACITY_16)
 			sdev->no_read_capacity_16 = 1;
 
+		/*
+		 * Many devices do not respond properly to READ_CAPACITY_16.
+		 * Tell the SCSI layer to try READ_CAPACITY_10 first.
+		 */
+		sdev->try_rc_10_first = 1;
+
 		/* assume SPC3 or latter devices support sense size > 18 */
 		if (sdev->scsi_level > SCSI_SPC_2)
 			us->fflags |= US_FL_SANE_SENSE;
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 8ec8a6e..638cd64 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -41,16 +41,17 @@ struct sense_iu_old {
 struct uas_dev_info {
 	struct usb_interface *intf;
 	struct usb_device *udev;
-	int qdepth;
+	struct usb_anchor sense_urbs;
+	struct usb_anchor data_urbs;
+	int qdepth, resetting;
+	struct response_ui response;
 	unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
 	unsigned use_streams:1;
 	unsigned uas_sense_old:1;
 	struct scsi_cmnd *cmnd;
-	struct urb *status_urb; /* used only if stream support is available */
 };
 
 enum {
-	ALLOC_STATUS_URB	= (1 << 0),
 	SUBMIT_STATUS_URB	= (1 << 1),
 	ALLOC_DATA_IN_URB	= (1 << 2),
 	SUBMIT_DATA_IN_URB	= (1 << 3),
@@ -58,18 +59,18 @@ enum {
 	SUBMIT_DATA_OUT_URB	= (1 << 5),
 	ALLOC_CMD_URB		= (1 << 6),
 	SUBMIT_CMD_URB		= (1 << 7),
-	COMPLETED_DATA_IN	= (1 << 8),
-	COMPLETED_DATA_OUT	= (1 << 9),
-	DATA_COMPLETES_CMD	= (1 << 10),
+	COMMAND_INFLIGHT        = (1 << 8),
+	DATA_IN_URB_INFLIGHT    = (1 << 9),
+	DATA_OUT_URB_INFLIGHT   = (1 << 10),
+	COMMAND_COMPLETED       = (1 << 11),
 };
 
 /* Overrides scsi_pointer */
 struct uas_cmd_info {
 	unsigned int state;
 	unsigned int stream;
+	unsigned int aborted;
 	struct urb *cmd_urb;
-	/* status_urb is used only if stream support isn't available */
-	struct urb *status_urb;
 	struct urb *data_in_urb;
 	struct urb *data_out_urb;
 	struct list_head list;
@@ -114,7 +115,6 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
 {
 	struct sense_iu *sense_iu = urb->transfer_buffer;
 	struct scsi_device *sdev = cmnd->device;
-	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 
 	if (urb->actual_length > 16) {
 		unsigned len = be16_to_cpup(&sense_iu->len);
@@ -132,15 +132,12 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
 	}
 
 	cmnd->result = sense_iu->status;
-	if (!(cmdinfo->state & DATA_COMPLETES_CMD))
-		cmnd->scsi_done(cmnd);
 }
 
 static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
 {
 	struct sense_iu_old *sense_iu = urb->transfer_buffer;
 	struct scsi_device *sdev = cmnd->device;
-	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 
 	if (urb->actual_length > 8) {
 		unsigned len = be16_to_cpup(&sense_iu->len) - 2;
@@ -158,17 +155,51 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
 	}
 
 	cmnd->result = sense_iu->status;
-	if (!(cmdinfo->state & DATA_COMPLETES_CMD))
-		cmnd->scsi_done(cmnd);
+}
+
+static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
+{
+	struct uas_cmd_info *ci = (void *)&cmnd->SCp;
+
+	scmd_printk(KERN_INFO, cmnd, "%s %p tag %d, inflight:"
+		    "%s%s%s%s%s%s%s%s%s%s%s\n",
+		    caller, cmnd, cmnd->request->tag,
+		    (ci->state & SUBMIT_STATUS_URB)     ? " s-st"  : "",
+		    (ci->state & ALLOC_DATA_IN_URB)     ? " a-in"  : "",
+		    (ci->state & SUBMIT_DATA_IN_URB)    ? " s-in"  : "",
+		    (ci->state & ALLOC_DATA_OUT_URB)    ? " a-out" : "",
+		    (ci->state & SUBMIT_DATA_OUT_URB)   ? " s-out" : "",
+		    (ci->state & ALLOC_CMD_URB)         ? " a-cmd" : "",
+		    (ci->state & SUBMIT_CMD_URB)        ? " s-cmd" : "",
+		    (ci->state & COMMAND_INFLIGHT)      ? " CMD"   : "",
+		    (ci->state & DATA_IN_URB_INFLIGHT)  ? " IN"    : "",
+		    (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT"   : "",
+		    (ci->state & COMMAND_COMPLETED)     ? " done"  : "");
+}
+
+static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
+{
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+
+	if (cmdinfo->state & (COMMAND_INFLIGHT |
+			      DATA_IN_URB_INFLIGHT |
+			      DATA_OUT_URB_INFLIGHT))
+		return -EBUSY;
+	BUG_ON(cmdinfo->state & COMMAND_COMPLETED);
+	cmdinfo->state |= COMMAND_COMPLETED;
+	usb_free_urb(cmdinfo->data_in_urb);
+	usb_free_urb(cmdinfo->data_out_urb);
+	cmnd->scsi_done(cmnd);
+	return 0;
 }
 
 static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
-							unsigned direction)
+			  unsigned direction)
 {
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 	int err;
 
-	cmdinfo->state = direction;
+	cmdinfo->state |= direction | SUBMIT_STATUS_URB;
 	err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
 	if (err) {
 		spin_lock(&uas_work_lock);
@@ -186,12 +217,15 @@ static void uas_stat_cmplt(struct urb *urb)
 	struct scsi_cmnd *cmnd;
 	struct uas_cmd_info *cmdinfo;
 	u16 tag;
-	int ret;
 
 	if (urb->status) {
 		dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
-		if (devinfo->use_streams)
-			usb_free_urb(urb);
+		usb_free_urb(urb);
+		return;
+	}
+
+	if (devinfo->resetting) {
+		usb_free_urb(urb);
 		return;
 	}
 
@@ -201,47 +235,34 @@ static void uas_stat_cmplt(struct urb *urb)
 	else
 		cmnd = scsi_host_find_tag(shost, tag - 1);
 	if (!cmnd) {
-		if (devinfo->use_streams) {
+		if (iu->iu_id != IU_ID_RESPONSE) {
 			usb_free_urb(urb);
 			return;
 		}
-		ret = usb_submit_urb(urb, GFP_ATOMIC);
-		if (ret)
-			dev_err(&urb->dev->dev, "failed submit status urb\n");
-		return;
+	} else {
+		cmdinfo = (void *)&cmnd->SCp;
 	}
-	cmdinfo = (void *)&cmnd->SCp;
 
 	switch (iu->iu_id) {
 	case IU_ID_STATUS:
 		if (devinfo->cmnd == cmnd)
 			devinfo->cmnd = NULL;
 
-		if (!(cmdinfo->state & COMPLETED_DATA_IN) &&
-				cmdinfo->data_in_urb) {
-		       if (devinfo->use_streams) {
-			       cmdinfo->state |= DATA_COMPLETES_CMD;
-			       usb_unlink_urb(cmdinfo->data_in_urb);
-		       } else {
-			       usb_free_urb(cmdinfo->data_in_urb);
-		       }
-		}
-		if (!(cmdinfo->state & COMPLETED_DATA_OUT) &&
-				cmdinfo->data_out_urb) {
-			if (devinfo->use_streams) {
-				cmdinfo->state |= DATA_COMPLETES_CMD;
-				usb_unlink_urb(cmdinfo->data_in_urb);
-			} else {
-				usb_free_urb(cmdinfo->data_out_urb);
-			}
-		}
-
 		if (urb->actual_length < 16)
 			devinfo->uas_sense_old = 1;
 		if (devinfo->uas_sense_old)
 			uas_sense_old(urb, cmnd);
 		else
 			uas_sense(urb, cmnd);
+		if (cmnd->result != 0) {
+			/* cancel data transfers on error */
+			if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
+				usb_unlink_urb(cmdinfo->data_in_urb);
+			if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
+				usb_unlink_urb(cmdinfo->data_out_urb);
+		}
+		cmdinfo->state &= ~COMMAND_INFLIGHT;
+		uas_try_complete(cmnd, __func__);
 		break;
 	case IU_ID_READ_READY:
 		uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);
@@ -249,74 +270,59 @@ static void uas_stat_cmplt(struct urb *urb)
 	case IU_ID_WRITE_READY:
 		uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
 		break;
+	case IU_ID_RESPONSE:
+		/* store results for uas_eh_task_mgmt() */
+		memcpy(&devinfo->response, iu, sizeof(devinfo->response));
+		break;
 	default:
 		scmd_printk(KERN_ERR, cmnd,
 			"Bogus IU (%d) received on status pipe\n", iu->iu_id);
 	}
-
-	if (devinfo->use_streams) {
-		usb_free_urb(urb);
-		return;
-	}
-
-	ret = usb_submit_urb(urb, GFP_ATOMIC);
-	if (ret)
-		dev_err(&urb->dev->dev, "failed submit status urb\n");
-}
-
-static void uas_data_out_cmplt(struct urb *urb)
-{
-	struct scsi_cmnd *cmnd = urb->context;
-	struct scsi_data_buffer *sdb = scsi_out(cmnd);
-	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
-
-	cmdinfo->state |= COMPLETED_DATA_OUT;
-
-	sdb->resid = sdb->length - urb->actual_length;
 	usb_free_urb(urb);
-
-	if (cmdinfo->state & DATA_COMPLETES_CMD)
-		cmnd->scsi_done(cmnd);
 }
 
-static void uas_data_in_cmplt(struct urb *urb)
+static void uas_data_cmplt(struct urb *urb)
 {
 	struct scsi_cmnd *cmnd = urb->context;
-	struct scsi_data_buffer *sdb = scsi_in(cmnd);
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct scsi_data_buffer *sdb = NULL;
 
-	cmdinfo->state |= COMPLETED_DATA_IN;
-
-	sdb->resid = sdb->length - urb->actual_length;
-	usb_free_urb(urb);
-
-	if (cmdinfo->state & DATA_COMPLETES_CMD)
-		cmnd->scsi_done(cmnd);
+	if (cmdinfo->data_in_urb == urb) {
+		sdb = scsi_in(cmnd);
+		cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
+	} else if (cmdinfo->data_out_urb == urb) {
+		sdb = scsi_out(cmnd);
+		cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
+	}
+	BUG_ON(sdb == NULL);
+	if (urb->status) {
+		/* error: no data transfered */
+		sdb->resid = sdb->length;
+	} else {
+		sdb->resid = sdb->length - urb->actual_length;
+	}
+	if (cmdinfo->aborted) {
+		return;
+	}
+	uas_try_complete(cmnd, __func__);
 }
 
 static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
-		unsigned int pipe, struct scsi_cmnd *cmnd,
-		enum dma_data_direction dir)
+				      unsigned int pipe, u16 stream_id,
+				      struct scsi_cmnd *cmnd,
+				      enum dma_data_direction dir)
 {
-	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 	struct usb_device *udev = devinfo->udev;
 	struct urb *urb = usb_alloc_urb(0, gfp);
-	struct scsi_data_buffer *sdb;
-	usb_complete_t complete_fn;
-	u16 stream_id = cmdinfo->stream;
+	struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE)
+		? scsi_in(cmnd) : scsi_out(cmnd);
 
 	if (!urb)
 		goto out;
-	if (dir == DMA_FROM_DEVICE) {
-		sdb = scsi_in(cmnd);
-		complete_fn = uas_data_in_cmplt;
-	} else {
-		sdb = scsi_out(cmnd);
-		complete_fn = uas_data_out_cmplt;
-	}
 	usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
-			complete_fn, cmnd);
-	urb->stream_id = stream_id;
+			  uas_data_cmplt, cmnd);
+	if (devinfo->use_streams)
+		urb->stream_id = stream_id;
 	urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
 	urb->sg = sdb->table.sgl;
  out:
@@ -324,7 +330,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
 }
 
 static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
-		struct Scsi_Host *shost, u16 stream_id)
+				       struct Scsi_Host *shost, u16 stream_id)
 {
 	struct usb_device *udev = devinfo->udev;
 	struct urb *urb = usb_alloc_urb(0, gfp);
@@ -388,38 +394,95 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
 	return NULL;
 }
 
+static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp,
+			       u8 function, u16 stream_id)
+{
+	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+	struct usb_device *udev = devinfo->udev;
+	struct urb *urb = usb_alloc_urb(0, gfp);
+	struct task_mgmt_iu *iu;
+	int err = -ENOMEM;
+
+	if (!urb)
+		goto err;
+
+	iu = kzalloc(sizeof(*iu), gfp);
+	if (!iu)
+		goto err;
+
+	iu->iu_id = IU_ID_TASK_MGMT;
+	iu->tag = cpu_to_be16(stream_id);
+	int_to_scsilun(cmnd->device->lun, &iu->lun);
+
+	iu->function = function;
+	switch (function) {
+	case TMF_ABORT_TASK:
+		if (blk_rq_tagged(cmnd->request))
+			iu->task_tag = cpu_to_be16(cmnd->request->tag + 2);
+		else
+			iu->task_tag = cpu_to_be16(1);
+		break;
+	}
+
+	usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu),
+			  usb_free_urb, NULL);
+	urb->transfer_flags |= URB_FREE_BUFFER;
+
+	err = usb_submit_urb(urb, gfp);
+	if (err)
+		goto err;
+
+	return 0;
+
+err:
+	usb_free_urb(urb);
+	return err;
+}
+
 /*
  * Why should I request the Status IU before sending the Command IU?  Spec
  * says to, but also says the device may receive them in any order.  Seems
  * daft to me.
  */
 
-static int uas_submit_urbs(struct scsi_cmnd *cmnd,
-					struct uas_dev_info *devinfo, gfp_t gfp)
+static int uas_submit_sense_urb(struct Scsi_Host *shost,
+				gfp_t gfp, unsigned int stream)
 {
-	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+	struct urb *urb;
 
-	if (cmdinfo->state & ALLOC_STATUS_URB) {
-		cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp,
-				cmnd->device->host, cmdinfo->stream);
-		if (!cmdinfo->status_urb)
-			return SCSI_MLQUEUE_DEVICE_BUSY;
-		cmdinfo->state &= ~ALLOC_STATUS_URB;
+	urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream);
+	if (!urb)
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+	if (usb_submit_urb(urb, gfp)) {
+		shost_printk(KERN_INFO, shost,
+			     "sense urb submission failure\n");
+		usb_free_urb(urb);
+		return SCSI_MLQUEUE_DEVICE_BUSY;
 	}
+	usb_anchor_urb(urb, &devinfo->sense_urbs);
+	return 0;
+}
+
+static int uas_submit_urbs(struct scsi_cmnd *cmnd,
+			   struct uas_dev_info *devinfo, gfp_t gfp)
+{
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	int err;
 
 	if (cmdinfo->state & SUBMIT_STATUS_URB) {
-		if (usb_submit_urb(cmdinfo->status_urb, gfp)) {
-			scmd_printk(KERN_INFO, cmnd,
-					"sense urb submission failure\n");
-			return SCSI_MLQUEUE_DEVICE_BUSY;
+		err = uas_submit_sense_urb(cmnd->device->host, gfp,
+					   cmdinfo->stream);
+		if (err) {
+			return err;
 		}
 		cmdinfo->state &= ~SUBMIT_STATUS_URB;
 	}
 
 	if (cmdinfo->state & ALLOC_DATA_IN_URB) {
 		cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
-					devinfo->data_in_pipe, cmnd,
-					DMA_FROM_DEVICE);
+					devinfo->data_in_pipe, cmdinfo->stream,
+					cmnd, DMA_FROM_DEVICE);
 		if (!cmdinfo->data_in_urb)
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		cmdinfo->state &= ~ALLOC_DATA_IN_URB;
@@ -432,12 +495,14 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		}
 		cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
+		cmdinfo->state |= DATA_IN_URB_INFLIGHT;
+		usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
 	}
 
 	if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
 		cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
-					devinfo->data_out_pipe, cmnd,
-					DMA_TO_DEVICE);
+					devinfo->data_out_pipe, cmdinfo->stream,
+					cmnd, DMA_TO_DEVICE);
 		if (!cmdinfo->data_out_urb)
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
@@ -450,6 +515,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		}
 		cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
+		cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
+		usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
 	}
 
 	if (cmdinfo->state & ALLOC_CMD_URB) {
@@ -467,6 +534,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		}
 		cmdinfo->state &= ~SUBMIT_CMD_URB;
+		cmdinfo->state |= COMMAND_INFLIGHT;
 	}
 
 	return 0;
@@ -494,8 +562,9 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
 
 	cmnd->scsi_done = done;
 
-	cmdinfo->state = ALLOC_STATUS_URB | SUBMIT_STATUS_URB |
+	cmdinfo->state = SUBMIT_STATUS_URB |
 			ALLOC_CMD_URB | SUBMIT_CMD_URB;
+	cmdinfo->aborted = 0;
 
 	switch (cmnd->sc_data_direction) {
 	case DMA_FROM_DEVICE:
@@ -510,8 +579,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
 	}
 
 	if (!devinfo->use_streams) {
-		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB |
-				ALLOC_STATUS_URB | SUBMIT_STATUS_URB);
+		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
 		cmdinfo->stream = 0;
 	}
 
@@ -519,7 +587,6 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
 	if (err) {
 		/* If we did nothing, give up now */
 		if (cmdinfo->state & SUBMIT_STATUS_URB) {
-			usb_free_urb(cmdinfo->status_urb);
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		}
 		spin_lock(&uas_work_lock);
@@ -533,36 +600,66 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
 
 static DEF_SCSI_QCMD(uas_queuecommand)
 
-static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
+static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
+			    const char *fname, u8 function)
 {
-	struct scsi_device *sdev = cmnd->device;
-	sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
-							cmnd->request->tag);
-
-/* XXX: Send ABORT TASK Task Management command */
-	return FAILED;
+	struct Scsi_Host *shost = cmnd->device->host;
+	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+	u16 tag = 9999; /* FIXME */
+
+	memset(&devinfo->response, 0, sizeof(devinfo->response));
+	if (uas_submit_sense_urb(shost, GFP_NOIO, tag)) {
+		shost_printk(KERN_INFO, shost,
+			     "%s: %s: submit sense urb failed\n",
+			     __func__, fname);
+		return FAILED;
+	}
+	if (uas_submit_task_urb(cmnd, GFP_NOIO, function, tag)) {
+		shost_printk(KERN_INFO, shost,
+			     "%s: %s: submit task mgmt urb failed\n",
+			     __func__, fname);
+		return FAILED;
+	}
+	if (0 == usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000)) {
+		shost_printk(KERN_INFO, shost,
+			     "%s: %s timed out\n", __func__, fname);
+		return FAILED;
+	}
+	if (be16_to_cpu(devinfo->response.tag) != tag) {
+		shost_printk(KERN_INFO, shost,
+			     "%s: %s failed (wrong tag %d/%d)\n", __func__,
+			     fname, be16_to_cpu(devinfo->response.tag), tag);
+		return FAILED;
+	}
+	if (devinfo->response.response_code != RC_TMF_COMPLETE) {
+		shost_printk(KERN_INFO, shost,
+			     "%s: %s failed (rc 0x%x)\n", __func__,
+			     fname, devinfo->response.response_code);
+		return FAILED;
+	}
+	return SUCCESS;
 }
 
-static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
+static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 {
-	struct scsi_device *sdev = cmnd->device;
-	sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
-							cmnd->request->tag);
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	int ret;
 
-/* XXX: Send LOGICAL UNIT RESET Task Management command */
-	return FAILED;
+	uas_log_cmd_state(cmnd, __func__);
+	cmdinfo->aborted = 1;
+	ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
+	if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
+		usb_kill_urb(cmdinfo->data_in_urb);
+	if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
+		usb_kill_urb(cmdinfo->data_out_urb);
+	return ret;
 }
 
-static int uas_eh_target_reset_handler(struct scsi_cmnd *cmnd)
+static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
 {
-	struct scsi_device *sdev = cmnd->device;
-	sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
-							cmnd->request->tag);
-
-/* XXX: Can we reset just the one USB interface?
- * Would calling usb_set_interface() have the right effect?
- */
-	return FAILED;
+	sdev_printk(KERN_INFO, cmnd->device, "%s\n", __func__);
+	return uas_eh_task_mgmt(cmnd, "LOGICAL UNIT RESET",
+				TMF_LOGICAL_UNIT_RESET);
 }
 
 static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
@@ -570,14 +667,21 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
 	struct scsi_device *sdev = cmnd->device;
 	struct uas_dev_info *devinfo = sdev->hostdata;
 	struct usb_device *udev = devinfo->udev;
+	int err;
 
-	sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
-							cmnd->request->tag);
+	devinfo->resetting = 1;
+	usb_kill_anchored_urbs(&devinfo->sense_urbs);
+	usb_kill_anchored_urbs(&devinfo->data_urbs);
+	err = usb_reset_device(udev);
+	devinfo->resetting = 0;
 
-	if (usb_reset_device(udev))
-		return SUCCESS;
+	if (err) {
+		shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__);
+		return FAILED;
+	}
 
-	return FAILED;
+	shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__);
+	return SUCCESS;
 }
 
 static int uas_slave_alloc(struct scsi_device *sdev)
@@ -602,7 +706,6 @@ static struct scsi_host_template uas_host_template = {
 	.slave_configure = uas_slave_configure,
 	.eh_abort_handler = uas_eh_abort_handler,
 	.eh_device_reset_handler = uas_eh_device_reset_handler,
-	.eh_target_reset_handler = uas_eh_target_reset_handler,
 	.eh_bus_reset_handler = uas_eh_bus_reset_handler,
 	.can_queue = 65536,	/* Is there a limit on the _host_ ? */
 	.this_id = -1,
@@ -722,29 +825,6 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
 	}
 }
 
-static int uas_alloc_status_urb(struct uas_dev_info *devinfo,
-		struct Scsi_Host *shost)
-{
-	if (devinfo->use_streams) {
-		devinfo->status_urb = NULL;
-		return 0;
-	}
-
-	devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL,
-			shost, 0);
-	if (!devinfo->status_urb)
-		goto err_s_urb;
-
-	if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL))
-		goto err_submit_urb;
-
-	return 0;
-err_submit_urb:
-	usb_free_urb(devinfo->status_urb);
-err_s_urb:
-	return -ENOMEM;
-}
-
 static void uas_free_streams(struct uas_dev_info *devinfo)
 {
 	struct usb_device *udev = devinfo->udev;
@@ -787,6 +867,9 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
 	devinfo->intf = intf;
 	devinfo->udev = udev;
+	devinfo->resetting = 0;
+	init_usb_anchor(&devinfo->sense_urbs);
+	init_usb_anchor(&devinfo->data_urbs);
 	uas_configure_endpoints(devinfo);
 
 	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
@@ -799,17 +882,10 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
 	shost->hostdata[0] = (unsigned long)devinfo;
 
-	result = uas_alloc_status_urb(devinfo, shost);
-	if (result)
-		goto err_alloc_status;
-
 	scsi_scan_host(shost);
 	usb_set_intfdata(intf, shost);
 	return result;
 
-err_alloc_status:
-	scsi_remove_host(shost);
-	shost = NULL;
 deconfig_eps:
 	uas_free_streams(devinfo);
  free:
@@ -837,8 +913,8 @@ static void uas_disconnect(struct usb_interface *intf)
 	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
 
 	scsi_remove_host(shost);
-	usb_kill_urb(devinfo->status_urb);
-	usb_free_urb(devinfo->status_urb);
+	usb_kill_anchored_urbs(&devinfo->sense_urbs);
+	usb_kill_anchored_urbs(&devinfo->data_urbs);
 	uas_free_streams(devinfo);
 	kfree(devinfo);
 }
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index caf22bf..1719886 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1107,13 +1107,6 @@ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
 		USB_SC_RBC, USB_PR_BULK, NULL,
 		0 ),
 
-/* Feiya QDI U2 DISK, reported by Hans de Goede <hdegoede@redhat.com> */
-UNUSUAL_DEV( 0x090c, 0x1000, 0x0000, 0xffff,
-		"Feiya",
-		"QDI U2 DISK",
-		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
-		US_FL_NO_READ_CAPACITY_16 ),
-
 /* aeb */
 UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
 		"Feiya",
diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
new file mode 100644
index 0000000..7cd5dec
--- /dev/null
+++ b/drivers/vfio/Kconfig
@@ -0,0 +1,16 @@
+config VFIO_IOMMU_TYPE1
+	tristate
+	depends on VFIO
+	default n
+
+menuconfig VFIO
+	tristate "VFIO Non-Privileged userspace driver framework"
+	depends on IOMMU_API
+	select VFIO_IOMMU_TYPE1 if X86
+	help
+	  VFIO provides a framework for secure userspace device drivers.
+	  See Documentation/vfio.txt for more details.
+
+	  If you don't know what to do here, say N.
+
+source "drivers/vfio/pci/Kconfig"
diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
new file mode 100644
index 0000000..2398d4a
--- /dev/null
+++ b/drivers/vfio/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_VFIO) += vfio.o
+obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
+obj-$(CONFIG_VFIO_PCI) += pci/
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig
new file mode 100644
index 0000000..cc7db62
--- /dev/null
+++ b/drivers/vfio/pci/Kconfig
@@ -0,0 +1,8 @@
+config VFIO_PCI
+	tristate "VFIO support for PCI devices"
+	depends on VFIO && PCI
+	help
+	  Support for the PCI VFIO bus driver.  This is required to make
+	  use of PCI drivers using the VFIO framework.
+
+	  If you don't know what to do here, say N.
diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile
new file mode 100644
index 0000000..1310792
--- /dev/null
+++ b/drivers/vfio/pci/Makefile
@@ -0,0 +1,4 @@
+
+vfio-pci-y := vfio_pci.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o
+
+obj-$(CONFIG_VFIO_PCI) += vfio-pci.o
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
new file mode 100644
index 0000000..82009d5
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -0,0 +1,565 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
+ *     Author: Alex Williamson <alex.williamson@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.
+ *
+ * Derived from original vfio:
+ * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
+ * Author: Tom Lyon, pugs@cisco.com
+ */
+
+#include <linux/device.h>
+#include <linux/eventfd.h>
+#include <linux/interrupt.h>
+#include <linux/iommu.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/vfio.h>
+
+#include "vfio_pci_private.h"
+
+#define DRIVER_VERSION  "0.2"
+#define DRIVER_AUTHOR   "Alex Williamson <alex.williamson@redhat.com>"
+#define DRIVER_DESC     "VFIO PCI - User Level meta-driver"
+
+static bool nointxmask;
+module_param_named(nointxmask, nointxmask, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(nointxmask,
+		  "Disable support for PCI 2.3 style INTx masking.  If this resolves problems for specific devices, report lspci -vvvxxx to linux-pci@vger.kernel.org so the device can be fixed automatically via the broken_intx_masking flag.");
+
+static int vfio_pci_enable(struct vfio_pci_device *vdev)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	int ret;
+	u16 cmd;
+	u8 msix_pos;
+
+	vdev->reset_works = (pci_reset_function(pdev) == 0);
+	pci_save_state(pdev);
+	vdev->pci_saved_state = pci_store_saved_state(pdev);
+	if (!vdev->pci_saved_state)
+		printk(KERN_DEBUG "%s: Couldn't store %s saved state\n",
+		       __func__, dev_name(&pdev->dev));
+
+	ret = vfio_config_init(vdev);
+	if (ret)
+		goto out;
+
+	if (likely(!nointxmask))
+		vdev->pci_2_3 = pci_intx_mask_supported(pdev);
+
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	if (vdev->pci_2_3 && (cmd & PCI_COMMAND_INTX_DISABLE)) {
+		cmd &= ~PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word(pdev, PCI_COMMAND, cmd);
+	}
+
+	msix_pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+	if (msix_pos) {
+		u16 flags;
+		u32 table;
+
+		pci_read_config_word(pdev, msix_pos + PCI_MSIX_FLAGS, &flags);
+		pci_read_config_dword(pdev, msix_pos + PCI_MSIX_TABLE, &table);
+
+		vdev->msix_bar = table & PCI_MSIX_FLAGS_BIRMASK;
+		vdev->msix_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
+		vdev->msix_size = ((flags & PCI_MSIX_FLAGS_QSIZE) + 1) * 16;
+	} else
+		vdev->msix_bar = 0xFF;
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		goto out;
+
+	return ret;
+
+out:
+	kfree(vdev->pci_saved_state);
+	vdev->pci_saved_state = NULL;
+	vfio_config_free(vdev);
+	return ret;
+}
+
+static void vfio_pci_disable(struct vfio_pci_device *vdev)
+{
+	int bar;
+
+	pci_disable_device(vdev->pdev);
+
+	vfio_pci_set_irqs_ioctl(vdev, VFIO_IRQ_SET_DATA_NONE |
+				VFIO_IRQ_SET_ACTION_TRIGGER,
+				vdev->irq_type, 0, 0, NULL);
+
+	vdev->virq_disabled = false;
+
+	vfio_config_free(vdev);
+
+	pci_reset_function(vdev->pdev);
+
+	if (pci_load_and_free_saved_state(vdev->pdev,
+					  &vdev->pci_saved_state) == 0)
+		pci_restore_state(vdev->pdev);
+	else
+		printk(KERN_INFO "%s: Couldn't reload %s saved state\n",
+		       __func__, dev_name(&vdev->pdev->dev));
+
+	for (bar = PCI_STD_RESOURCES; bar <= PCI_STD_RESOURCE_END; bar++) {
+		if (!vdev->barmap[bar])
+			continue;
+		pci_iounmap(vdev->pdev, vdev->barmap[bar]);
+		pci_release_selected_regions(vdev->pdev, 1 << bar);
+		vdev->barmap[bar] = NULL;
+	}
+}
+
+static void vfio_pci_release(void *device_data)
+{
+	struct vfio_pci_device *vdev = device_data;
+
+	if (atomic_dec_and_test(&vdev->refcnt))
+		vfio_pci_disable(vdev);
+
+	module_put(THIS_MODULE);
+}
+
+static int vfio_pci_open(void *device_data)
+{
+	struct vfio_pci_device *vdev = device_data;
+
+	if (!try_module_get(THIS_MODULE))
+		return -ENODEV;
+
+	if (atomic_inc_return(&vdev->refcnt) == 1) {
+		int ret = vfio_pci_enable(vdev);
+		if (ret) {
+			module_put(THIS_MODULE);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
+{
+	if (irq_type == VFIO_PCI_INTX_IRQ_INDEX) {
+		u8 pin;
+		pci_read_config_byte(vdev->pdev, PCI_INTERRUPT_PIN, &pin);
+		if (pin)
+			return 1;
+
+	} else if (irq_type == VFIO_PCI_MSI_IRQ_INDEX) {
+		u8 pos;
+		u16 flags;
+
+		pos = pci_find_capability(vdev->pdev, PCI_CAP_ID_MSI);
+		if (pos) {
+			pci_read_config_word(vdev->pdev,
+					     pos + PCI_MSI_FLAGS, &flags);
+
+			return 1 << (flags & PCI_MSI_FLAGS_QMASK);
+		}
+	} else if (irq_type == VFIO_PCI_MSIX_IRQ_INDEX) {
+		u8 pos;
+		u16 flags;
+
+		pos = pci_find_capability(vdev->pdev, PCI_CAP_ID_MSIX);
+		if (pos) {
+			pci_read_config_word(vdev->pdev,
+					     pos + PCI_MSIX_FLAGS, &flags);
+
+			return (flags & PCI_MSIX_FLAGS_QSIZE) + 1;
+		}
+	}
+
+	return 0;
+}
+
+static long vfio_pci_ioctl(void *device_data,
+			   unsigned int cmd, unsigned long arg)
+{
+	struct vfio_pci_device *vdev = device_data;
+	unsigned long minsz;
+
+	if (cmd == VFIO_DEVICE_GET_INFO) {
+		struct vfio_device_info info;
+
+		minsz = offsetofend(struct vfio_device_info, num_irqs);
+
+		if (copy_from_user(&info, (void __user *)arg, minsz))
+			return -EFAULT;
+
+		if (info.argsz < minsz)
+			return -EINVAL;
+
+		info.flags = VFIO_DEVICE_FLAGS_PCI;
+
+		if (vdev->reset_works)
+			info.flags |= VFIO_DEVICE_FLAGS_RESET;
+
+		info.num_regions = VFIO_PCI_NUM_REGIONS;
+		info.num_irqs = VFIO_PCI_NUM_IRQS;
+
+		return copy_to_user((void __user *)arg, &info, minsz);
+
+	} else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
+		struct pci_dev *pdev = vdev->pdev;
+		struct vfio_region_info info;
+
+		minsz = offsetofend(struct vfio_region_info, offset);
+
+		if (copy_from_user(&info, (void __user *)arg, minsz))
+			return -EFAULT;
+
+		if (info.argsz < minsz || info.index >= VFIO_PCI_NUM_REGIONS)
+			return -EINVAL;
+
+		info.flags = 0;
+		info.size = 0;
+		info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+
+		if (info.index == VFIO_PCI_CONFIG_REGION_INDEX) {
+			info.size = pdev->cfg_size;
+		} else if (pci_resource_start(pdev, info.index)) {
+			unsigned long flags;
+
+			flags = pci_resource_flags(pdev, info.index);
+
+			info.size = pci_resource_len(pdev, info.index);
+
+			/* If we can't read the ROM, don't report it. */
+			if (info.index == VFIO_PCI_ROM_REGION_INDEX) {
+				void __iomem *io;
+				size_t size;
+
+				io = pci_map_rom(pdev, &size);
+				if (!io || !size) {
+					info.size = 0;
+				} else {
+					info.flags = VFIO_REGION_INFO_FLAG_READ;
+					pci_unmap_rom(pdev, io);
+				}
+			} else if (flags & IORESOURCE_MEM) {
+				info.flags = (VFIO_REGION_INFO_FLAG_READ |
+					      VFIO_REGION_INFO_FLAG_WRITE |
+					      VFIO_REGION_INFO_FLAG_MMAP);
+			} else {
+				info.flags = (VFIO_REGION_INFO_FLAG_READ |
+					      VFIO_REGION_INFO_FLAG_WRITE);
+			}
+		}
+
+		return copy_to_user((void __user *)arg, &info, minsz);
+
+	} else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
+		struct vfio_irq_info info;
+
+		minsz = offsetofend(struct vfio_irq_info, count);
+
+		if (copy_from_user(&info, (void __user *)arg, minsz))
+			return -EFAULT;
+
+		if (info.argsz < minsz || info.index >= VFIO_PCI_NUM_IRQS)
+			return -EINVAL;
+
+		info.flags = VFIO_IRQ_INFO_EVENTFD;
+
+		info.count = vfio_pci_get_irq_count(vdev, info.index);
+
+		if (info.index == VFIO_PCI_INTX_IRQ_INDEX)
+			info.flags |= (VFIO_IRQ_INFO_MASKABLE |
+				       VFIO_IRQ_INFO_AUTOMASKED);
+		else
+			info.flags |= VFIO_IRQ_INFO_NORESIZE;
+
+		return copy_to_user((void __user *)arg, &info, minsz);
+
+	} else if (cmd == VFIO_DEVICE_SET_IRQS) {
+		struct vfio_irq_set hdr;
+		u8 *data = NULL;
+		int ret = 0;
+
+		minsz = offsetofend(struct vfio_irq_set, count);
+
+		if (copy_from_user(&hdr, (void __user *)arg, minsz))
+			return -EFAULT;
+
+		if (hdr.argsz < minsz || hdr.index >= VFIO_PCI_NUM_IRQS ||
+		    hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
+				  VFIO_IRQ_SET_ACTION_TYPE_MASK))
+			return -EINVAL;
+
+		if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
+			size_t size;
+
+			if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL)
+				size = sizeof(uint8_t);
+			else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD)
+				size = sizeof(int32_t);
+			else
+				return -EINVAL;
+
+			if (hdr.argsz - minsz < hdr.count * size ||
+			    hdr.count > vfio_pci_get_irq_count(vdev, hdr.index))
+				return -EINVAL;
+
+			data = kmalloc(hdr.count * size, GFP_KERNEL);
+			if (!data)
+				return -ENOMEM;
+
+			if (copy_from_user(data, (void __user *)(arg + minsz),
+					   hdr.count * size)) {
+				kfree(data);
+				return -EFAULT;
+			}
+		}
+
+		mutex_lock(&vdev->igate);
+
+		ret = vfio_pci_set_irqs_ioctl(vdev, hdr.flags, hdr.index,
+					      hdr.start, hdr.count, data);
+
+		mutex_unlock(&vdev->igate);
+		kfree(data);
+
+		return ret;
+
+	} else if (cmd == VFIO_DEVICE_RESET)
+		return vdev->reset_works ?
+			pci_reset_function(vdev->pdev) : -EINVAL;
+
+	return -ENOTTY;
+}
+
+static ssize_t vfio_pci_read(void *device_data, char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
+	struct vfio_pci_device *vdev = device_data;
+	struct pci_dev *pdev = vdev->pdev;
+
+	if (index >= VFIO_PCI_NUM_REGIONS)
+		return -EINVAL;
+
+	if (index == VFIO_PCI_CONFIG_REGION_INDEX)
+		return vfio_pci_config_readwrite(vdev, buf, count, ppos, false);
+	else if (index == VFIO_PCI_ROM_REGION_INDEX)
+		return vfio_pci_mem_readwrite(vdev, buf, count, ppos, false);
+	else if (pci_resource_flags(pdev, index) & IORESOURCE_IO)
+		return vfio_pci_io_readwrite(vdev, buf, count, ppos, false);
+	else if (pci_resource_flags(pdev, index) & IORESOURCE_MEM)
+		return vfio_pci_mem_readwrite(vdev, buf, count, ppos, false);
+
+	return -EINVAL;
+}
+
+static ssize_t vfio_pci_write(void *device_data, const char __user *buf,
+			      size_t count, loff_t *ppos)
+{
+	unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
+	struct vfio_pci_device *vdev = device_data;
+	struct pci_dev *pdev = vdev->pdev;
+
+	if (index >= VFIO_PCI_NUM_REGIONS)
+		return -EINVAL;
+
+	if (index == VFIO_PCI_CONFIG_REGION_INDEX)
+		return vfio_pci_config_readwrite(vdev, (char __user *)buf,
+						 count, ppos, true);
+	else if (index == VFIO_PCI_ROM_REGION_INDEX)
+		return -EINVAL;
+	else if (pci_resource_flags(pdev, index) & IORESOURCE_IO)
+		return vfio_pci_io_readwrite(vdev, (char __user *)buf,
+					     count, ppos, true);
+	else if (pci_resource_flags(pdev, index) & IORESOURCE_MEM) {
+		return vfio_pci_mem_readwrite(vdev, (char __user *)buf,
+					      count, ppos, true);
+	}
+
+	return -EINVAL;
+}
+
+static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
+{
+	struct vfio_pci_device *vdev = device_data;
+	struct pci_dev *pdev = vdev->pdev;
+	unsigned int index;
+	u64 phys_len, req_len, pgoff, req_start, phys;
+	int ret;
+
+	index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);
+
+	if (vma->vm_end < vma->vm_start)
+		return -EINVAL;
+	if ((vma->vm_flags & VM_SHARED) == 0)
+		return -EINVAL;
+	if (index >= VFIO_PCI_ROM_REGION_INDEX)
+		return -EINVAL;
+	if (!(pci_resource_flags(pdev, index) & IORESOURCE_MEM))
+		return -EINVAL;
+
+	phys_len = pci_resource_len(pdev, index);
+	req_len = vma->vm_end - vma->vm_start;
+	pgoff = vma->vm_pgoff &
+		((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
+	req_start = pgoff << PAGE_SHIFT;
+
+	if (phys_len < PAGE_SIZE || req_start + req_len > phys_len)
+		return -EINVAL;
+
+	if (index == vdev->msix_bar) {
+		/*
+		 * Disallow mmaps overlapping the MSI-X table; users don't
+		 * get to touch this directly.  We could find somewhere
+		 * else to map the overlap, but page granularity is only
+		 * a recommendation, not a requirement, so the user needs
+		 * to know which bits are real.  Requiring them to mmap
+		 * around the table makes that clear.
+		 */
+
+		/* If neither entirely above nor below, then it overlaps */
+		if (!(req_start >= vdev->msix_offset + vdev->msix_size ||
+		      req_start + req_len <= vdev->msix_offset))
+			return -EINVAL;
+	}
+
+	/*
+	 * Even though we don't make use of the barmap for the mmap,
+	 * we need to request the region and the barmap tracks that.
+	 */
+	if (!vdev->barmap[index]) {
+		ret = pci_request_selected_regions(pdev,
+						   1 << index, "vfio-pci");
+		if (ret)
+			return ret;
+
+		vdev->barmap[index] = pci_iomap(pdev, index, 0);
+	}
+
+	vma->vm_private_data = vdev;
+	vma->vm_flags |= (VM_IO | VM_RESERVED);
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	phys = (pci_resource_start(pdev, index) >> PAGE_SHIFT) + pgoff;
+
+	return remap_pfn_range(vma, vma->vm_start, phys,
+			       req_len, vma->vm_page_prot);
+}
+
+static const struct vfio_device_ops vfio_pci_ops = {
+	.name		= "vfio-pci",
+	.open		= vfio_pci_open,
+	.release	= vfio_pci_release,
+	.ioctl		= vfio_pci_ioctl,
+	.read		= vfio_pci_read,
+	.write		= vfio_pci_write,
+	.mmap		= vfio_pci_mmap,
+};
+
+static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	u8 type;
+	struct vfio_pci_device *vdev;
+	struct iommu_group *group;
+	int ret;
+
+	pci_read_config_byte(pdev, PCI_HEADER_TYPE, &type);
+	if ((type & PCI_HEADER_TYPE) != PCI_HEADER_TYPE_NORMAL)
+		return -EINVAL;
+
+	group = iommu_group_get(&pdev->dev);
+	if (!group)
+		return -EINVAL;
+
+	vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+	if (!vdev) {
+		iommu_group_put(group);
+		return -ENOMEM;
+	}
+
+	vdev->pdev = pdev;
+	vdev->irq_type = VFIO_PCI_NUM_IRQS;
+	mutex_init(&vdev->igate);
+	spin_lock_init(&vdev->irqlock);
+	atomic_set(&vdev->refcnt, 0);
+
+	ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev);
+	if (ret) {
+		iommu_group_put(group);
+		kfree(vdev);
+	}
+
+	return ret;
+}
+
+static void vfio_pci_remove(struct pci_dev *pdev)
+{
+	struct vfio_pci_device *vdev;
+
+	vdev = vfio_del_group_dev(&pdev->dev);
+	if (!vdev)
+		return;
+
+	iommu_group_put(pdev->dev.iommu_group);
+	kfree(vdev);
+}
+
+static struct pci_driver vfio_pci_driver = {
+	.name		= "vfio-pci",
+	.id_table	= NULL, /* only dynamic ids */
+	.probe		= vfio_pci_probe,
+	.remove		= vfio_pci_remove,
+};
+
+void __exit vfio_pci_cleanup(void)
+{
+	pci_unregister_driver(&vfio_pci_driver);
+	vfio_pci_virqfd_exit();
+	vfio_pci_uninit_perm_bits();
+}
+
+int __init vfio_pci_init(void)
+{
+	int ret;
+
+	/* Allocate shared config space permision data used by all devices */
+	ret = vfio_pci_init_perm_bits();
+	if (ret)
+		return ret;
+
+	/* Start the virqfd cleanup handler */
+	ret = vfio_pci_virqfd_init();
+	if (ret)
+		goto out_virqfd;
+
+	/* Register and scan for devices */
+	ret = pci_register_driver(&vfio_pci_driver);
+	if (ret)
+		goto out_driver;
+
+	return 0;
+
+out_virqfd:
+	vfio_pci_virqfd_exit();
+out_driver:
+	vfio_pci_uninit_perm_bits();
+	return ret;
+}
+
+module_init(vfio_pci_init);
+module_exit(vfio_pci_cleanup);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
new file mode 100644
index 0000000..a87d4f4
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -0,0 +1,1528 @@
+/*
+ * VFIO PCI config space virtualization
+ *
+ * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
+ *     Author: Alex Williamson <alex.williamson@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.
+ *
+ * Derived from original vfio:
+ * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
+ * Author: Tom Lyon, pugs@cisco.com
+ */
+
+/*
+ * This code handles reading and writing of PCI configuration registers.
+ * This is hairy because we want to allow a lot of flexibility to the
+ * user driver, but cannot trust it with all of the config fields.
+ * Tables determine which fields can be read and written, as well as
+ * which fields are 'virtualized' - special actions and translations to
+ * make it appear to the user that he has control, when in fact things
+ * must be negotiated with the underlying OS.
+ */
+
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+#include <linux/vfio.h>
+
+#include "vfio_pci_private.h"
+
+#define PCI_CFG_SPACE_SIZE	256
+
+/* Useful "pseudo" capabilities */
+#define PCI_CAP_ID_BASIC	0
+#define PCI_CAP_ID_INVALID	0xFF
+
+#define is_bar(offset)	\
+	((offset >= PCI_BASE_ADDRESS_0 && offset < PCI_BASE_ADDRESS_5 + 4) || \
+	 (offset >= PCI_ROM_ADDRESS && offset < PCI_ROM_ADDRESS + 4))
+
+/*
+ * Lengths of PCI Config Capabilities
+ *   0: Removed from the user visible capability list
+ *   FF: Variable length
+ */
+static u8 pci_cap_length[] = {
+	[PCI_CAP_ID_BASIC]	= PCI_STD_HEADER_SIZEOF, /* pci config header */
+	[PCI_CAP_ID_PM]		= PCI_PM_SIZEOF,
+	[PCI_CAP_ID_AGP]	= PCI_AGP_SIZEOF,
+	[PCI_CAP_ID_VPD]	= PCI_CAP_VPD_SIZEOF,
+	[PCI_CAP_ID_SLOTID]	= 0,		/* bridge - don't care */
+	[PCI_CAP_ID_MSI]	= 0xFF,		/* 10, 14, 20, or 24 */
+	[PCI_CAP_ID_CHSWP]	= 0,		/* cpci - not yet */
+	[PCI_CAP_ID_PCIX]	= 0xFF,		/* 8 or 24 */
+	[PCI_CAP_ID_HT]		= 0xFF,		/* hypertransport */
+	[PCI_CAP_ID_VNDR]	= 0xFF,		/* variable */
+	[PCI_CAP_ID_DBG]	= 0,		/* debug - don't care */
+	[PCI_CAP_ID_CCRC]	= 0,		/* cpci - not yet */
+	[PCI_CAP_ID_SHPC]	= 0,		/* hotswap - not yet */
+	[PCI_CAP_ID_SSVID]	= 0,		/* bridge - don't care */
+	[PCI_CAP_ID_AGP3]	= 0,		/* AGP8x - not yet */
+	[PCI_CAP_ID_SECDEV]	= 0,		/* secure device not yet */
+	[PCI_CAP_ID_EXP]	= 0xFF,		/* 20 or 44 */
+	[PCI_CAP_ID_MSIX]	= PCI_CAP_MSIX_SIZEOF,
+	[PCI_CAP_ID_SATA]	= 0xFF,
+	[PCI_CAP_ID_AF]		= PCI_CAP_AF_SIZEOF,
+};
+
+/*
+ * Lengths of PCIe/PCI-X Extended Config Capabilities
+ *   0: Removed or masked from the user visible capabilty list
+ *   FF: Variable length
+ */
+static u16 pci_ext_cap_length[] = {
+	[PCI_EXT_CAP_ID_ERR]	=	PCI_ERR_ROOT_COMMAND,
+	[PCI_EXT_CAP_ID_VC]	=	0xFF,
+	[PCI_EXT_CAP_ID_DSN]	=	PCI_EXT_CAP_DSN_SIZEOF,
+	[PCI_EXT_CAP_ID_PWR]	=	PCI_EXT_CAP_PWR_SIZEOF,
+	[PCI_EXT_CAP_ID_RCLD]	=	0,	/* root only - don't care */
+	[PCI_EXT_CAP_ID_RCILC]	=	0,	/* root only - don't care */
+	[PCI_EXT_CAP_ID_RCEC]	=	0,	/* root only - don't care */
+	[PCI_EXT_CAP_ID_MFVC]	=	0xFF,
+	[PCI_EXT_CAP_ID_VC9]	=	0xFF,	/* same as CAP_ID_VC */
+	[PCI_EXT_CAP_ID_RCRB]	=	0,	/* root only - don't care */
+	[PCI_EXT_CAP_ID_VNDR]	=	0xFF,
+	[PCI_EXT_CAP_ID_CAC]	=	0,	/* obsolete */
+	[PCI_EXT_CAP_ID_ACS]	=	0xFF,
+	[PCI_EXT_CAP_ID_ARI]	=	PCI_EXT_CAP_ARI_SIZEOF,
+	[PCI_EXT_CAP_ID_ATS]	=	PCI_EXT_CAP_ATS_SIZEOF,
+	[PCI_EXT_CAP_ID_SRIOV]	=	PCI_EXT_CAP_SRIOV_SIZEOF,
+	[PCI_EXT_CAP_ID_MRIOV]	=	0,	/* not yet */
+	[PCI_EXT_CAP_ID_MCAST]	=	PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF,
+	[PCI_EXT_CAP_ID_PRI]	=	PCI_EXT_CAP_PRI_SIZEOF,
+	[PCI_EXT_CAP_ID_AMD_XXX] =	0,	/* not yet */
+	[PCI_EXT_CAP_ID_REBAR]	=	0xFF,
+	[PCI_EXT_CAP_ID_DPA]	=	0xFF,
+	[PCI_EXT_CAP_ID_TPH]	=	0xFF,
+	[PCI_EXT_CAP_ID_LTR]	=	PCI_EXT_CAP_LTR_SIZEOF,
+	[PCI_EXT_CAP_ID_SECPCI]	=	0,	/* not yet */
+	[PCI_EXT_CAP_ID_PMUX]	=	0,	/* not yet */
+	[PCI_EXT_CAP_ID_PASID]	=	0,	/* not yet */
+};
+
+/*
+ * Read/Write Permission Bits - one bit for each bit in capability
+ * Any field can be read if it exists, but what is read depends on
+ * whether the field is 'virtualized', or just pass thru to the
+ * hardware.  Any virtualized field is also virtualized for writes.
+ * Writes are only permitted if they have a 1 bit here.
+ */
+struct perm_bits {
+	u8	*virt;		/* read/write virtual data, not hw */
+	u8	*write;		/* writeable bits */
+	int	(*readfn)(struct vfio_pci_device *vdev, int pos, int count,
+			  struct perm_bits *perm, int offset, u32 *val);
+	int	(*writefn)(struct vfio_pci_device *vdev, int pos, int count,
+			   struct perm_bits *perm, int offset, u32 val);
+};
+
+#define	NO_VIRT		0
+#define	ALL_VIRT	0xFFFFFFFFU
+#define	NO_WRITE	0
+#define	ALL_WRITE	0xFFFFFFFFU
+
+static int vfio_user_config_read(struct pci_dev *pdev, int offset,
+				 u32 *val, int count)
+{
+	int ret = -EINVAL;
+
+	switch (count) {
+	case 1:
+	{
+		u8 tmp;
+		ret = pci_user_read_config_byte(pdev, offset, &tmp);
+		*val = tmp;
+		break;
+	}
+	case 2:
+	{
+		u16 tmp;
+		ret = pci_user_read_config_word(pdev, offset, &tmp);
+		*val = tmp;
+		break;
+	}
+	case 4:
+		ret = pci_user_read_config_dword(pdev, offset, val);
+		break;
+	}
+
+	*val = cpu_to_le32(*val);
+
+	return pcibios_err_to_errno(ret);
+}
+
+static int vfio_user_config_write(struct pci_dev *pdev, int offset,
+				  u32 val, int count)
+{
+	int ret = -EINVAL;
+
+	val = le32_to_cpu(val);
+
+	switch (count) {
+	case 1:
+		ret = pci_user_write_config_byte(pdev, offset, val);
+		break;
+	case 2:
+		ret = pci_user_write_config_word(pdev, offset, val);
+		break;
+	case 4:
+		ret = pci_user_write_config_dword(pdev, offset, val);
+		break;
+	}
+
+	return pcibios_err_to_errno(ret);
+}
+
+static int vfio_default_config_read(struct vfio_pci_device *vdev, int pos,
+				    int count, struct perm_bits *perm,
+				    int offset, u32 *val)
+{
+	u32 virt = 0;
+
+	memcpy(val, vdev->vconfig + pos, count);
+
+	memcpy(&virt, perm->virt + offset, count);
+
+	/* Any non-virtualized bits? */
+	if (cpu_to_le32(~0U >> (32 - (count * 8))) != virt) {
+		struct pci_dev *pdev = vdev->pdev;
+		u32 phys_val = 0;
+		int ret;
+
+		ret = vfio_user_config_read(pdev, pos, &phys_val, count);
+		if (ret)
+			return ret;
+
+		*val = (phys_val & ~virt) | (*val & virt);
+	}
+
+	return count;
+}
+
+static int vfio_default_config_write(struct vfio_pci_device *vdev, int pos,
+				     int count, struct perm_bits *perm,
+				     int offset, u32 val)
+{
+	u32 virt = 0, write = 0;
+
+	memcpy(&write, perm->write + offset, count);
+
+	if (!write)
+		return count; /* drop, no writable bits */
+
+	memcpy(&virt, perm->virt + offset, count);
+
+	/* Virtualized and writable bits go to vconfig */
+	if (write & virt) {
+		u32 virt_val = 0;
+
+		memcpy(&virt_val, vdev->vconfig + pos, count);
+
+		virt_val &= ~(write & virt);
+		virt_val |= (val & (write & virt));
+
+		memcpy(vdev->vconfig + pos, &virt_val, count);
+	}
+
+	/* Non-virtualzed and writable bits go to hardware */
+	if (write & ~virt) {
+		struct pci_dev *pdev = vdev->pdev;
+		u32 phys_val = 0;
+		int ret;
+
+		ret = vfio_user_config_read(pdev, pos, &phys_val, count);
+		if (ret)
+			return ret;
+
+		phys_val &= ~(write & ~virt);
+		phys_val |= (val & (write & ~virt));
+
+		ret = vfio_user_config_write(pdev, pos, phys_val, count);
+		if (ret)
+			return ret;
+	}
+
+	return count;
+}
+
+/* Allow direct read from hardware, except for capability next pointer */
+static int vfio_direct_config_read(struct vfio_pci_device *vdev, int pos,
+				   int count, struct perm_bits *perm,
+				   int offset, u32 *val)
+{
+	int ret;
+
+	ret = vfio_user_config_read(vdev->pdev, pos, val, count);
+	if (ret)
+		return pcibios_err_to_errno(ret);
+
+	if (pos >= PCI_CFG_SPACE_SIZE) { /* Extended cap header mangling */
+		if (offset < 4)
+			memcpy(val, vdev->vconfig + pos, count);
+	} else if (pos >= PCI_STD_HEADER_SIZEOF) { /* Std cap mangling */
+		if (offset == PCI_CAP_LIST_ID && count > 1)
+			memcpy(val, vdev->vconfig + pos,
+			       min(PCI_CAP_FLAGS, count));
+		else if (offset == PCI_CAP_LIST_NEXT)
+			memcpy(val, vdev->vconfig + pos, 1);
+	}
+
+	return count;
+}
+
+static int vfio_direct_config_write(struct vfio_pci_device *vdev, int pos,
+				    int count, struct perm_bits *perm,
+				    int offset, u32 val)
+{
+	int ret;
+
+	ret = vfio_user_config_write(vdev->pdev, pos, val, count);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+/* Default all regions to read-only, no-virtualization */
+static struct perm_bits cap_perms[PCI_CAP_ID_MAX + 1] = {
+	[0 ... PCI_CAP_ID_MAX] = { .readfn = vfio_direct_config_read }
+};
+static struct perm_bits ecap_perms[PCI_EXT_CAP_ID_MAX + 1] = {
+	[0 ... PCI_EXT_CAP_ID_MAX] = { .readfn = vfio_direct_config_read }
+};
+
+static void free_perm_bits(struct perm_bits *perm)
+{
+	kfree(perm->virt);
+	kfree(perm->write);
+	perm->virt = NULL;
+	perm->write = NULL;
+}
+
+static int alloc_perm_bits(struct perm_bits *perm, int size)
+{
+	/*
+	 * Round up all permission bits to the next dword, this lets us
+	 * ignore whether a read/write exceeds the defined capability
+	 * structure.  We can do this because:
+	 *  - Standard config space is already dword aligned
+	 *  - Capabilities are all dword alinged (bits 0:1 of next reserved)
+	 *  - Express capabilities defined as dword aligned
+	 */
+	size = round_up(size, 4);
+
+	/*
+	 * Zero state is
+	 * - All Readable, None Writeable, None Virtualized
+	 */
+	perm->virt = kzalloc(size, GFP_KERNEL);
+	perm->write = kzalloc(size, GFP_KERNEL);
+	if (!perm->virt || !perm->write) {
+		free_perm_bits(perm);
+		return -ENOMEM;
+	}
+
+	perm->readfn = vfio_default_config_read;
+	perm->writefn = vfio_default_config_write;
+
+	return 0;
+}
+
+/*
+ * Helper functions for filling in permission tables
+ */
+static inline void p_setb(struct perm_bits *p, int off, u8 virt, u8 write)
+{
+	p->virt[off] = virt;
+	p->write[off] = write;
+}
+
+/* Handle endian-ness - pci and tables are little-endian */
+static inline void p_setw(struct perm_bits *p, int off, u16 virt, u16 write)
+{
+	*(u16 *)(&p->virt[off]) = cpu_to_le16(virt);
+	*(u16 *)(&p->write[off]) = cpu_to_le16(write);
+}
+
+/* Handle endian-ness - pci and tables are little-endian */
+static inline void p_setd(struct perm_bits *p, int off, u32 virt, u32 write)
+{
+	*(u32 *)(&p->virt[off]) = cpu_to_le32(virt);
+	*(u32 *)(&p->write[off]) = cpu_to_le32(write);
+}
+
+/*
+ * Restore the *real* BARs after we detect a FLR or backdoor reset.
+ * (backdoor = some device specific technique that we didn't catch)
+ */
+static void vfio_bar_restore(struct vfio_pci_device *vdev)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	u32 *rbar = vdev->rbar;
+	int i;
+
+	if (pdev->is_virtfn)
+		return;
+
+	printk(KERN_INFO "%s: %s reset recovery - restoring bars\n",
+	       __func__, dev_name(&pdev->dev));
+
+	for (i = PCI_BASE_ADDRESS_0; i <= PCI_BASE_ADDRESS_5; i += 4, rbar++)
+		pci_user_write_config_dword(pdev, i, *rbar);
+
+	pci_user_write_config_dword(pdev, PCI_ROM_ADDRESS, *rbar);
+}
+
+static u32 vfio_generate_bar_flags(struct pci_dev *pdev, int bar)
+{
+	unsigned long flags = pci_resource_flags(pdev, bar);
+	u32 val;
+
+	if (flags & IORESOURCE_IO)
+		return cpu_to_le32(PCI_BASE_ADDRESS_SPACE_IO);
+
+	val = PCI_BASE_ADDRESS_SPACE_MEMORY;
+
+	if (flags & IORESOURCE_PREFETCH)
+		val |= PCI_BASE_ADDRESS_MEM_PREFETCH;
+
+	if (flags & IORESOURCE_MEM_64)
+		val |= PCI_BASE_ADDRESS_MEM_TYPE_64;
+
+	return cpu_to_le32(val);
+}
+
+/*
+ * Pretend we're hardware and tweak the values of the *virtual* PCI BARs
+ * to reflect the hardware capabilities.  This implements BAR sizing.
+ */
+static void vfio_bar_fixup(struct vfio_pci_device *vdev)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	int i;
+	u32 *bar;
+	u64 mask;
+
+	bar = (u32 *)&vdev->vconfig[PCI_BASE_ADDRESS_0];
+
+	for (i = PCI_STD_RESOURCES; i <= PCI_STD_RESOURCE_END; i++, bar++) {
+		if (!pci_resource_start(pdev, i)) {
+			*bar = 0; /* Unmapped by host = unimplemented to user */
+			continue;
+		}
+
+		mask = ~(pci_resource_len(pdev, i) - 1);
+
+		*bar &= cpu_to_le32((u32)mask);
+		*bar |= vfio_generate_bar_flags(pdev, i);
+
+		if (*bar & cpu_to_le32(PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+			bar++;
+			*bar &= cpu_to_le32((u32)(mask >> 32));
+			i++;
+		}
+	}
+
+	bar = (u32 *)&vdev->vconfig[PCI_ROM_ADDRESS];
+
+	/*
+	 * NB. we expose the actual BAR size here, regardless of whether
+	 * we can read it.  When we report the REGION_INFO for the ROM
+	 * we report what PCI tells us is the actual ROM size.
+	 */
+	if (pci_resource_start(pdev, PCI_ROM_RESOURCE)) {
+		mask = ~(pci_resource_len(pdev, PCI_ROM_RESOURCE) - 1);
+		mask |= PCI_ROM_ADDRESS_ENABLE;
+		*bar &= cpu_to_le32((u32)mask);
+	} else
+		*bar = 0;
+
+	vdev->bardirty = false;
+}
+
+static int vfio_basic_config_read(struct vfio_pci_device *vdev, int pos,
+				  int count, struct perm_bits *perm,
+				  int offset, u32 *val)
+{
+	if (is_bar(offset)) /* pos == offset for basic config */
+		vfio_bar_fixup(vdev);
+
+	count = vfio_default_config_read(vdev, pos, count, perm, offset, val);
+
+	/* Mask in virtual memory enable for SR-IOV devices */
+	if (offset == PCI_COMMAND && vdev->pdev->is_virtfn) {
+		u16 cmd = le16_to_cpu(*(u16 *)&vdev->vconfig[PCI_COMMAND]);
+		*val = (le32_to_cpu(*val) | (cmd & PCI_COMMAND_MEMORY));
+		*val = cpu_to_le32(*val);
+	}
+
+	return count;
+}
+
+static int vfio_basic_config_write(struct vfio_pci_device *vdev, int pos,
+				   int count, struct perm_bits *perm,
+				   int offset, u32 val)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	u16 phys_cmd, *virt_cmd, new_cmd = 0;
+	int ret;
+
+	virt_cmd = (u16 *)&vdev->vconfig[PCI_COMMAND];
+
+	if (offset == PCI_COMMAND) {
+		bool phys_mem, virt_mem, new_mem, phys_io, virt_io, new_io;
+
+		ret = pci_user_read_config_word(pdev, PCI_COMMAND, &phys_cmd);
+		if (ret)
+			return ret;
+
+		new_cmd = le32_to_cpu(val);
+
+		phys_mem = !!(phys_cmd & PCI_COMMAND_MEMORY);
+		virt_mem = !!(le16_to_cpu(*virt_cmd) & PCI_COMMAND_MEMORY);
+		new_mem = !!(new_cmd & PCI_COMMAND_MEMORY);
+
+		phys_io = !!(phys_cmd & PCI_COMMAND_IO);
+		virt_io = !!(le16_to_cpu(*virt_cmd) & PCI_COMMAND_IO);
+		new_io = !!(new_cmd & PCI_COMMAND_IO);
+
+		/*
+		 * If the user is writing mem/io enable (new_mem/io) and we
+		 * think it's already enabled (virt_mem/io), but the hardware
+		 * shows it disabled (phys_mem/io, then the device has
+		 * undergone some kind of backdoor reset and needs to be
+		 * restored before we allow it to enable the bars.
+		 * SR-IOV devices will trigger this, but we catch them later
+		 */
+		if ((new_mem && virt_mem && !phys_mem) ||
+		    (new_io && virt_io && !phys_io))
+			vfio_bar_restore(vdev);
+	}
+
+	count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
+	if (count < 0)
+		return count;
+
+	/*
+	 * Save current memory/io enable bits in vconfig to allow for
+	 * the test above next time.
+	 */
+	if (offset == PCI_COMMAND) {
+		u16 mask = PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+
+		*virt_cmd &= cpu_to_le16(~mask);
+		*virt_cmd |= cpu_to_le16(new_cmd & mask);
+	}
+
+	/* Emulate INTx disable */
+	if (offset >= PCI_COMMAND && offset <= PCI_COMMAND + 1) {
+		bool virt_intx_disable;
+
+		virt_intx_disable = !!(le16_to_cpu(*virt_cmd) &
+				       PCI_COMMAND_INTX_DISABLE);
+
+		if (virt_intx_disable && !vdev->virq_disabled) {
+			vdev->virq_disabled = true;
+			vfio_pci_intx_mask(vdev);
+		} else if (!virt_intx_disable && vdev->virq_disabled) {
+			vdev->virq_disabled = false;
+			vfio_pci_intx_unmask(vdev);
+		}
+	}
+
+	if (is_bar(offset))
+		vdev->bardirty = true;
+
+	return count;
+}
+
+/* Permissions for the Basic PCI Header */
+static int __init init_pci_cap_basic_perm(struct perm_bits *perm)
+{
+	if (alloc_perm_bits(perm, PCI_STD_HEADER_SIZEOF))
+		return -ENOMEM;
+
+	perm->readfn = vfio_basic_config_read;
+	perm->writefn = vfio_basic_config_write;
+
+	/* Virtualized for SR-IOV functions, which just have FFFF */
+	p_setw(perm, PCI_VENDOR_ID, (u16)ALL_VIRT, NO_WRITE);
+	p_setw(perm, PCI_DEVICE_ID, (u16)ALL_VIRT, NO_WRITE);
+
+	/*
+	 * Virtualize INTx disable, we use it internally for interrupt
+	 * control and can emulate it for non-PCI 2.3 devices.
+	 */
+	p_setw(perm, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE, (u16)ALL_WRITE);
+
+	/* Virtualize capability list, we might want to skip/disable */
+	p_setw(perm, PCI_STATUS, PCI_STATUS_CAP_LIST, NO_WRITE);
+
+	/* No harm to write */
+	p_setb(perm, PCI_CACHE_LINE_SIZE, NO_VIRT, (u8)ALL_WRITE);
+	p_setb(perm, PCI_LATENCY_TIMER, NO_VIRT, (u8)ALL_WRITE);
+	p_setb(perm, PCI_BIST, NO_VIRT, (u8)ALL_WRITE);
+
+	/* Virtualize all bars, can't touch the real ones */
+	p_setd(perm, PCI_BASE_ADDRESS_0, ALL_VIRT, ALL_WRITE);
+	p_setd(perm, PCI_BASE_ADDRESS_1, ALL_VIRT, ALL_WRITE);
+	p_setd(perm, PCI_BASE_ADDRESS_2, ALL_VIRT, ALL_WRITE);
+	p_setd(perm, PCI_BASE_ADDRESS_3, ALL_VIRT, ALL_WRITE);
+	p_setd(perm, PCI_BASE_ADDRESS_4, ALL_VIRT, ALL_WRITE);
+	p_setd(perm, PCI_BASE_ADDRESS_5, ALL_VIRT, ALL_WRITE);
+	p_setd(perm, PCI_ROM_ADDRESS, ALL_VIRT, ALL_WRITE);
+
+	/* Allow us to adjust capability chain */
+	p_setb(perm, PCI_CAPABILITY_LIST, (u8)ALL_VIRT, NO_WRITE);
+
+	/* Sometimes used by sw, just virtualize */
+	p_setb(perm, PCI_INTERRUPT_LINE, (u8)ALL_VIRT, (u8)ALL_WRITE);
+	return 0;
+}
+
+/* Permissions for the Power Management capability */
+static int __init init_pci_cap_pm_perm(struct perm_bits *perm)
+{
+	if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_PM]))
+		return -ENOMEM;
+
+	/*
+	 * We always virtualize the next field so we can remove
+	 * capabilities from the chain if we want to.
+	 */
+	p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
+
+	/*
+	 * Power management is defined *per function*,
+	 * so we let the user write this
+	 */
+	p_setd(perm, PCI_PM_CTRL, NO_VIRT, ALL_WRITE);
+	return 0;
+}
+
+/* Permissions for PCI-X capability */
+static int __init init_pci_cap_pcix_perm(struct perm_bits *perm)
+{
+	/* Alloc 24, but only 8 are used in v0 */
+	if (alloc_perm_bits(perm, PCI_CAP_PCIX_SIZEOF_V2))
+		return -ENOMEM;
+
+	p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
+
+	p_setw(perm, PCI_X_CMD, NO_VIRT, (u16)ALL_WRITE);
+	p_setd(perm, PCI_X_ECC_CSR, NO_VIRT, ALL_WRITE);
+	return 0;
+}
+
+/* Permissions for PCI Express capability */
+static int __init init_pci_cap_exp_perm(struct perm_bits *perm)
+{
+	/* Alloc larger of two possible sizes */
+	if (alloc_perm_bits(perm, PCI_CAP_EXP_ENDPOINT_SIZEOF_V2))
+		return -ENOMEM;
+
+	p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
+
+	/*
+	 * Allow writes to device control fields (includes FLR!)
+	 * but not to devctl_phantom which could confuse IOMMU
+	 * or to the ARI bit in devctl2 which is set at probe time
+	 */
+	p_setw(perm, PCI_EXP_DEVCTL, NO_VIRT, ~PCI_EXP_DEVCTL_PHANTOM);
+	p_setw(perm, PCI_EXP_DEVCTL2, NO_VIRT, ~PCI_EXP_DEVCTL2_ARI);
+	return 0;
+}
+
+/* Permissions for Advanced Function capability */
+static int __init init_pci_cap_af_perm(struct perm_bits *perm)
+{
+	if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_AF]))
+		return -ENOMEM;
+
+	p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
+	p_setb(perm, PCI_AF_CTRL, NO_VIRT, PCI_AF_CTRL_FLR);
+	return 0;
+}
+
+/* Permissions for Advanced Error Reporting extended capability */
+static int __init init_pci_ext_cap_err_perm(struct perm_bits *perm)
+{
+	u32 mask;
+
+	if (alloc_perm_bits(perm, pci_ext_cap_length[PCI_EXT_CAP_ID_ERR]))
+		return -ENOMEM;
+
+	/*
+	 * Virtualize the first dword of all express capabilities
+	 * because it includes the next pointer.  This lets us later
+	 * remove capabilities from the chain if we need to.
+	 */
+	p_setd(perm, 0, ALL_VIRT, NO_WRITE);
+
+	/* Writable bits mask */
+	mask =	PCI_ERR_UNC_TRAIN |		/* Training */
+		PCI_ERR_UNC_DLP |		/* Data Link Protocol */
+		PCI_ERR_UNC_SURPDN |		/* Surprise Down */
+		PCI_ERR_UNC_POISON_TLP |	/* Poisoned TLP */
+		PCI_ERR_UNC_FCP |		/* Flow Control Protocol */
+		PCI_ERR_UNC_COMP_TIME |		/* Completion Timeout */
+		PCI_ERR_UNC_COMP_ABORT |	/* Completer Abort */
+		PCI_ERR_UNC_UNX_COMP |		/* Unexpected Completion */
+		PCI_ERR_UNC_RX_OVER |		/* Receiver Overflow */
+		PCI_ERR_UNC_MALF_TLP |		/* Malformed TLP */
+		PCI_ERR_UNC_ECRC |		/* ECRC Error Status */
+		PCI_ERR_UNC_UNSUP |		/* Unsupported Request */
+		PCI_ERR_UNC_ACSV |		/* ACS Violation */
+		PCI_ERR_UNC_INTN |		/* internal error */
+		PCI_ERR_UNC_MCBTLP |		/* MC blocked TLP */
+		PCI_ERR_UNC_ATOMEG |		/* Atomic egress blocked */
+		PCI_ERR_UNC_TLPPRE;		/* TLP prefix blocked */
+	p_setd(perm, PCI_ERR_UNCOR_STATUS, NO_VIRT, mask);
+	p_setd(perm, PCI_ERR_UNCOR_MASK, NO_VIRT, mask);
+	p_setd(perm, PCI_ERR_UNCOR_SEVER, NO_VIRT, mask);
+
+	mask =	PCI_ERR_COR_RCVR |		/* Receiver Error Status */
+		PCI_ERR_COR_BAD_TLP |		/* Bad TLP Status */
+		PCI_ERR_COR_BAD_DLLP |		/* Bad DLLP Status */
+		PCI_ERR_COR_REP_ROLL |		/* REPLAY_NUM Rollover */
+		PCI_ERR_COR_REP_TIMER |		/* Replay Timer Timeout */
+		PCI_ERR_COR_ADV_NFAT |		/* Advisory Non-Fatal */
+		PCI_ERR_COR_INTERNAL |		/* Corrected Internal */
+		PCI_ERR_COR_LOG_OVER;		/* Header Log Overflow */
+	p_setd(perm, PCI_ERR_COR_STATUS, NO_VIRT, mask);
+	p_setd(perm, PCI_ERR_COR_MASK, NO_VIRT, mask);
+
+	mask =	PCI_ERR_CAP_ECRC_GENE |		/* ECRC Generation Enable */
+		PCI_ERR_CAP_ECRC_CHKE;		/* ECRC Check Enable */
+	p_setd(perm, PCI_ERR_CAP, NO_VIRT, mask);
+	return 0;
+}
+
+/* Permissions for Power Budgeting extended capability */
+static int __init init_pci_ext_cap_pwr_perm(struct perm_bits *perm)
+{
+	if (alloc_perm_bits(perm, pci_ext_cap_length[PCI_EXT_CAP_ID_PWR]))
+		return -ENOMEM;
+
+	p_setd(perm, 0, ALL_VIRT, NO_WRITE);
+
+	/* Writing the data selector is OK, the info is still read-only */
+	p_setb(perm, PCI_PWR_DATA, NO_VIRT, (u8)ALL_WRITE);
+	return 0;
+}
+
+/*
+ * Initialize the shared permission tables
+ */
+void vfio_pci_uninit_perm_bits(void)
+{
+	free_perm_bits(&cap_perms[PCI_CAP_ID_BASIC]);
+
+	free_perm_bits(&cap_perms[PCI_CAP_ID_PM]);
+	free_perm_bits(&cap_perms[PCI_CAP_ID_PCIX]);
+	free_perm_bits(&cap_perms[PCI_CAP_ID_EXP]);
+	free_perm_bits(&cap_perms[PCI_CAP_ID_AF]);
+
+	free_perm_bits(&ecap_perms[PCI_EXT_CAP_ID_ERR]);
+	free_perm_bits(&ecap_perms[PCI_EXT_CAP_ID_PWR]);
+}
+
+int __init vfio_pci_init_perm_bits(void)
+{
+	int ret;
+
+	/* Basic config space */
+	ret = init_pci_cap_basic_perm(&cap_perms[PCI_CAP_ID_BASIC]);
+
+	/* Capabilities */
+	ret |= init_pci_cap_pm_perm(&cap_perms[PCI_CAP_ID_PM]);
+	cap_perms[PCI_CAP_ID_VPD].writefn = vfio_direct_config_write;
+	ret |= init_pci_cap_pcix_perm(&cap_perms[PCI_CAP_ID_PCIX]);
+	cap_perms[PCI_CAP_ID_VNDR].writefn = vfio_direct_config_write;
+	ret |= init_pci_cap_exp_perm(&cap_perms[PCI_CAP_ID_EXP]);
+	ret |= init_pci_cap_af_perm(&cap_perms[PCI_CAP_ID_AF]);
+
+	/* Extended capabilities */
+	ret |= init_pci_ext_cap_err_perm(&ecap_perms[PCI_EXT_CAP_ID_ERR]);
+	ret |= init_pci_ext_cap_pwr_perm(&ecap_perms[PCI_EXT_CAP_ID_PWR]);
+	ecap_perms[PCI_EXT_CAP_ID_VNDR].writefn = vfio_direct_config_write;
+
+	if (ret)
+		vfio_pci_uninit_perm_bits();
+
+	return ret;
+}
+
+static int vfio_find_cap_start(struct vfio_pci_device *vdev, int pos)
+{
+	u8 cap;
+	int base = (pos >= PCI_CFG_SPACE_SIZE) ? PCI_CFG_SPACE_SIZE :
+						 PCI_STD_HEADER_SIZEOF;
+	base /= 4;
+	pos /= 4;
+
+	cap = vdev->pci_config_map[pos];
+
+	if (cap == PCI_CAP_ID_BASIC)
+		return 0;
+
+	/* XXX Can we have to abutting capabilities of the same type? */
+	while (pos - 1 >= base && vdev->pci_config_map[pos - 1] == cap)
+		pos--;
+
+	return pos * 4;
+}
+
+static int vfio_msi_config_read(struct vfio_pci_device *vdev, int pos,
+				int count, struct perm_bits *perm,
+				int offset, u32 *val)
+{
+	/* Update max available queue size from msi_qmax */
+	if (offset <= PCI_MSI_FLAGS && offset + count >= PCI_MSI_FLAGS) {
+		u16 *flags;
+		int start;
+
+		start = vfio_find_cap_start(vdev, pos);
+
+		flags = (u16 *)&vdev->vconfig[start];
+
+		*flags &= cpu_to_le16(~PCI_MSI_FLAGS_QMASK);
+		*flags |= cpu_to_le16(vdev->msi_qmax << 1);
+	}
+
+	return vfio_default_config_read(vdev, pos, count, perm, offset, val);
+}
+
+static int vfio_msi_config_write(struct vfio_pci_device *vdev, int pos,
+				 int count, struct perm_bits *perm,
+				 int offset, u32 val)
+{
+	count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
+	if (count < 0)
+		return count;
+
+	/* Fixup and write configured queue size and enable to hardware */
+	if (offset <= PCI_MSI_FLAGS && offset + count >= PCI_MSI_FLAGS) {
+		u16 *pflags, flags;
+		int start, ret;
+
+		start = vfio_find_cap_start(vdev, pos);
+
+		pflags = (u16 *)&vdev->vconfig[start + PCI_MSI_FLAGS];
+
+		flags = le16_to_cpu(*pflags);
+
+		/* MSI is enabled via ioctl */
+		if  (!is_msi(vdev))
+			flags &= ~PCI_MSI_FLAGS_ENABLE;
+
+		/* Check queue size */
+		if ((flags & PCI_MSI_FLAGS_QSIZE) >> 4 > vdev->msi_qmax) {
+			flags &= ~PCI_MSI_FLAGS_QSIZE;
+			flags |= vdev->msi_qmax << 4;
+		}
+
+		/* Write back to virt and to hardware */
+		*pflags = cpu_to_le16(flags);
+		ret = pci_user_write_config_word(vdev->pdev,
+						 start + PCI_MSI_FLAGS,
+						 flags);
+		if (ret)
+			return pcibios_err_to_errno(ret);
+	}
+
+	return count;
+}
+
+/*
+ * MSI determination is per-device, so this routine gets used beyond
+ * initialization time. Don't add __init
+ */
+static int init_pci_cap_msi_perm(struct perm_bits *perm, int len, u16 flags)
+{
+	if (alloc_perm_bits(perm, len))
+		return -ENOMEM;
+
+	perm->readfn = vfio_msi_config_read;
+	perm->writefn = vfio_msi_config_write;
+
+	p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
+
+	/*
+	 * The upper byte of the control register is reserved,
+	 * just setup the lower byte.
+	 */
+	p_setb(perm, PCI_MSI_FLAGS, (u8)ALL_VIRT, (u8)ALL_WRITE);
+	p_setd(perm, PCI_MSI_ADDRESS_LO, ALL_VIRT, ALL_WRITE);
+	if (flags & PCI_MSI_FLAGS_64BIT) {
+		p_setd(perm, PCI_MSI_ADDRESS_HI, ALL_VIRT, ALL_WRITE);
+		p_setw(perm, PCI_MSI_DATA_64, (u16)ALL_VIRT, (u16)ALL_WRITE);
+		if (flags & PCI_MSI_FLAGS_MASKBIT) {
+			p_setd(perm, PCI_MSI_MASK_64, NO_VIRT, ALL_WRITE);
+			p_setd(perm, PCI_MSI_PENDING_64, NO_VIRT, ALL_WRITE);
+		}
+	} else {
+		p_setw(perm, PCI_MSI_DATA_32, (u16)ALL_VIRT, (u16)ALL_WRITE);
+		if (flags & PCI_MSI_FLAGS_MASKBIT) {
+			p_setd(perm, PCI_MSI_MASK_32, NO_VIRT, ALL_WRITE);
+			p_setd(perm, PCI_MSI_PENDING_32, NO_VIRT, ALL_WRITE);
+		}
+	}
+	return 0;
+}
+
+/* Determine MSI CAP field length; initialize msi_perms on 1st call per vdev */
+static int vfio_msi_cap_len(struct vfio_pci_device *vdev, u8 pos)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	int len, ret;
+	u16 flags;
+
+	ret = pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &flags);
+	if (ret)
+		return pcibios_err_to_errno(ret);
+
+	len = 10; /* Minimum size */
+	if (flags & PCI_MSI_FLAGS_64BIT)
+		len += 4;
+	if (flags & PCI_MSI_FLAGS_MASKBIT)
+		len += 10;
+
+	if (vdev->msi_perm)
+		return len;
+
+	vdev->msi_perm = kmalloc(sizeof(struct perm_bits), GFP_KERNEL);
+	if (!vdev->msi_perm)
+		return -ENOMEM;
+
+	ret = init_pci_cap_msi_perm(vdev->msi_perm, len, flags);
+	if (ret)
+		return ret;
+
+	return len;
+}
+
+/* Determine extended capability length for VC (2 & 9) and MFVC */
+static int vfio_vc_cap_len(struct vfio_pci_device *vdev, u16 pos)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	u32 tmp;
+	int ret, evcc, phases, vc_arb;
+	int len = PCI_CAP_VC_BASE_SIZEOF;
+
+	ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_REG1, &tmp);
+	if (ret)
+		return pcibios_err_to_errno(ret);
+
+	evcc = tmp & PCI_VC_REG1_EVCC; /* extended vc count */
+	ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_REG2, &tmp);
+	if (ret)
+		return pcibios_err_to_errno(ret);
+
+	if (tmp & PCI_VC_REG2_128_PHASE)
+		phases = 128;
+	else if (tmp & PCI_VC_REG2_64_PHASE)
+		phases = 64;
+	else if (tmp & PCI_VC_REG2_32_PHASE)
+		phases = 32;
+	else
+		phases = 0;
+
+	vc_arb = phases * 4;
+
+	/*
+	 * Port arbitration tables are root & switch only;
+	 * function arbitration tables are function 0 only.
+	 * In either case, we'll never let user write them so
+	 * we don't care how big they are
+	 */
+	len += (1 + evcc) * PCI_CAP_VC_PER_VC_SIZEOF;
+	if (vc_arb) {
+		len = round_up(len, 16);
+		len += vc_arb / 8;
+	}
+	return len;
+}
+
+static int vfio_cap_len(struct vfio_pci_device *vdev, u8 cap, u8 pos)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	u16 word;
+	u8 byte;
+	int ret;
+
+	switch (cap) {
+	case PCI_CAP_ID_MSI:
+		return vfio_msi_cap_len(vdev, pos);
+	case PCI_CAP_ID_PCIX:
+		ret = pci_read_config_word(pdev, pos + PCI_X_CMD, &word);
+		if (ret)
+			return pcibios_err_to_errno(ret);
+
+		if (PCI_X_CMD_VERSION(word)) {
+			vdev->extended_caps = true;
+			return PCI_CAP_PCIX_SIZEOF_V2;
+		} else
+			return PCI_CAP_PCIX_SIZEOF_V0;
+	case PCI_CAP_ID_VNDR:
+		/* length follows next field */
+		ret = pci_read_config_byte(pdev, pos + PCI_CAP_FLAGS, &byte);
+		if (ret)
+			return pcibios_err_to_errno(ret);
+
+		return byte;
+	case PCI_CAP_ID_EXP:
+		/* length based on version */
+		ret = pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &word);
+		if (ret)
+			return pcibios_err_to_errno(ret);
+
+		if ((word & PCI_EXP_FLAGS_VERS) == 1)
+			return PCI_CAP_EXP_ENDPOINT_SIZEOF_V1;
+		else {
+			vdev->extended_caps = true;
+			return PCI_CAP_EXP_ENDPOINT_SIZEOF_V2;
+		}
+	case PCI_CAP_ID_HT:
+		ret = pci_read_config_byte(pdev, pos + 3, &byte);
+		if (ret)
+			return pcibios_err_to_errno(ret);
+
+		return (byte & HT_3BIT_CAP_MASK) ?
+			HT_CAP_SIZEOF_SHORT : HT_CAP_SIZEOF_LONG;
+	case PCI_CAP_ID_SATA:
+		ret = pci_read_config_byte(pdev, pos + PCI_SATA_REGS, &byte);
+		if (ret)
+			return pcibios_err_to_errno(ret);
+
+		byte &= PCI_SATA_REGS_MASK;
+		if (byte == PCI_SATA_REGS_INLINE)
+			return PCI_SATA_SIZEOF_LONG;
+		else
+			return PCI_SATA_SIZEOF_SHORT;
+	default:
+		printk(KERN_WARNING
+		       "%s: %s unknown length for pci cap 0x%x@0x%x\n",
+		       dev_name(&pdev->dev), __func__, cap, pos);
+	}
+
+	return 0;
+}
+
+static int vfio_ext_cap_len(struct vfio_pci_device *vdev, u16 ecap, u16 epos)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	u8 byte;
+	u32 dword;
+	int ret;
+
+	switch (ecap) {
+	case PCI_EXT_CAP_ID_VNDR:
+		ret = pci_read_config_dword(pdev, epos + PCI_VSEC_HDR, &dword);
+		if (ret)
+			return pcibios_err_to_errno(ret);
+
+		return dword >> PCI_VSEC_HDR_LEN_SHIFT;
+	case PCI_EXT_CAP_ID_VC:
+	case PCI_EXT_CAP_ID_VC9:
+	case PCI_EXT_CAP_ID_MFVC:
+		return vfio_vc_cap_len(vdev, epos);
+	case PCI_EXT_CAP_ID_ACS:
+		ret = pci_read_config_byte(pdev, epos + PCI_ACS_CAP, &byte);
+		if (ret)
+			return pcibios_err_to_errno(ret);
+
+		if (byte & PCI_ACS_EC) {
+			int bits;
+
+			ret = pci_read_config_byte(pdev,
+						   epos + PCI_ACS_EGRESS_BITS,
+						   &byte);
+			if (ret)
+				return pcibios_err_to_errno(ret);
+
+			bits = byte ? round_up(byte, 32) : 256;
+			return 8 + (bits / 8);
+		}
+		return 8;
+
+	case PCI_EXT_CAP_ID_REBAR:
+		ret = pci_read_config_byte(pdev, epos + PCI_REBAR_CTRL, &byte);
+		if (ret)
+			return pcibios_err_to_errno(ret);
+
+		byte &= PCI_REBAR_CTRL_NBAR_MASK;
+		byte >>= PCI_REBAR_CTRL_NBAR_SHIFT;
+
+		return 4 + (byte * 8);
+	case PCI_EXT_CAP_ID_DPA:
+		ret = pci_read_config_byte(pdev, epos + PCI_DPA_CAP, &byte);
+		if (ret)
+			return pcibios_err_to_errno(ret);
+
+		byte &= PCI_DPA_CAP_SUBSTATE_MASK;
+		byte = round_up(byte + 1, 4);
+		return PCI_DPA_BASE_SIZEOF + byte;
+	case PCI_EXT_CAP_ID_TPH:
+		ret = pci_read_config_dword(pdev, epos + PCI_TPH_CAP, &dword);
+		if (ret)
+			return pcibios_err_to_errno(ret);
+
+		if ((dword & PCI_TPH_CAP_LOC_MASK) == PCI_TPH_LOC_CAP) {
+			int sts;
+
+			sts = byte & PCI_TPH_CAP_ST_MASK;
+			sts >>= PCI_TPH_CAP_ST_SHIFT;
+			return PCI_TPH_BASE_SIZEOF + round_up(sts * 2, 4);
+		}
+		return PCI_TPH_BASE_SIZEOF;
+	default:
+		printk(KERN_WARNING
+		       "%s: %s unknown length for pci ecap 0x%x@0x%x\n",
+		       dev_name(&pdev->dev), __func__, ecap, epos);
+	}
+
+	return 0;
+}
+
+static int vfio_fill_vconfig_bytes(struct vfio_pci_device *vdev,
+				   int offset, int size)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	int ret = 0;
+
+	/*
+	 * We try to read physical config space in the largest chunks
+	 * we can, assuming that all of the fields support dword access.
+	 * pci_save_state() makes this same assumption and seems to do ok.
+	 */
+	while (size) {
+		int filled;
+
+		if (size >= 4 && !(offset % 4)) {
+			u32 *dword = (u32 *)&vdev->vconfig[offset];
+			ret = pci_read_config_dword(pdev, offset, dword);
+			if (ret)
+				return ret;
+			*dword = cpu_to_le32(*dword);
+			filled = 4;
+		} else if (size >= 2 && !(offset % 2)) {
+			u16 *word = (u16 *)&vdev->vconfig[offset];
+			ret = pci_read_config_word(pdev, offset, word);
+			if (ret)
+				return ret;
+			*word = cpu_to_le16(*word);
+			filled = 2;
+		} else {
+			u8 *byte = &vdev->vconfig[offset];
+			ret = pci_read_config_byte(pdev, offset, byte);
+			if (ret)
+				return ret;
+			filled = 1;
+		}
+
+		offset += filled;
+		size -= filled;
+	}
+
+	return ret;
+}
+
+static int vfio_cap_init(struct vfio_pci_device *vdev)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	u8 *map = vdev->pci_config_map;
+	u16 status;
+	u8 pos, *prev, cap;
+	int loops, ret, caps = 0;
+
+	/* Any capabilities? */
+	ret = pci_read_config_word(pdev, PCI_STATUS, &status);
+	if (ret)
+		return ret;
+
+	if (!(status & PCI_STATUS_CAP_LIST))
+		return 0; /* Done */
+
+	ret = pci_read_config_byte(pdev, PCI_CAPABILITY_LIST, &pos);
+	if (ret)
+		return ret;
+
+	/* Mark the previous position in case we want to skip a capability */
+	prev = &vdev->vconfig[PCI_CAPABILITY_LIST];
+
+	/* We can bound our loop, capabilities are dword aligned */
+	loops = (PCI_CFG_SPACE_SIZE - PCI_STD_HEADER_SIZEOF) / PCI_CAP_SIZEOF;
+	while (pos && loops--) {
+		u8 next;
+		int i, len = 0;
+
+		ret = pci_read_config_byte(pdev, pos, &cap);
+		if (ret)
+			return ret;
+
+		ret = pci_read_config_byte(pdev,
+					   pos + PCI_CAP_LIST_NEXT, &next);
+		if (ret)
+			return ret;
+
+		if (cap <= PCI_CAP_ID_MAX) {
+			len = pci_cap_length[cap];
+			if (len == 0xFF) { /* Variable length */
+				len = vfio_cap_len(vdev, cap, pos);
+				if (len < 0)
+					return len;
+			}
+		}
+
+		if (!len) {
+			printk(KERN_INFO "%s: %s hiding cap 0x%x\n",
+			       __func__, dev_name(&pdev->dev), cap);
+			*prev = next;
+			pos = next;
+			continue;
+		}
+
+		/* Sanity check, do we overlap other capabilities? */
+		for (i = 0; i < len; i += 4) {
+			if (likely(map[(pos + i) / 4] == PCI_CAP_ID_INVALID))
+				continue;
+
+			printk(KERN_WARNING
+			       "%s: %s pci config conflict @0x%x, was cap 0x%x now cap 0x%x\n",
+			       __func__, dev_name(&pdev->dev), pos + i,
+			       map[pos + i], cap);
+		}
+
+		memset(map + (pos / 4), cap, len / 4);
+		ret = vfio_fill_vconfig_bytes(vdev, pos, len);
+		if (ret)
+			return ret;
+
+		prev = &vdev->vconfig[pos + PCI_CAP_LIST_NEXT];
+		pos = next;
+		caps++;
+	}
+
+	/* If we didn't fill any capabilities, clear the status flag */
+	if (!caps) {
+		u16 *vstatus = (u16 *)&vdev->vconfig[PCI_STATUS];
+		*vstatus &= ~cpu_to_le16(PCI_STATUS_CAP_LIST);
+	}
+
+	return 0;
+}
+
+static int vfio_ecap_init(struct vfio_pci_device *vdev)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	u8 *map = vdev->pci_config_map;
+	u16 epos;
+	u32 *prev = NULL;
+	int loops, ret, ecaps = 0;
+
+	if (!vdev->extended_caps)
+		return 0;
+
+	epos = PCI_CFG_SPACE_SIZE;
+
+	loops = (pdev->cfg_size - PCI_CFG_SPACE_SIZE) / PCI_CAP_SIZEOF;
+
+	while (loops-- && epos >= PCI_CFG_SPACE_SIZE) {
+		u32 header;
+		u16 ecap;
+		int i, len = 0;
+		bool hidden = false;
+
+		ret = pci_read_config_dword(pdev, epos, &header);
+		if (ret)
+			return ret;
+
+		ecap = PCI_EXT_CAP_ID(header);
+
+		if (ecap <= PCI_EXT_CAP_ID_MAX) {
+			len = pci_ext_cap_length[ecap];
+			if (len == 0xFF) {
+				len = vfio_ext_cap_len(vdev, ecap, epos);
+				if (len < 0)
+					return ret;
+			}
+		}
+
+		if (!len) {
+			printk(KERN_INFO "%s: %s hiding ecap 0x%x@0x%x\n",
+			       __func__, dev_name(&pdev->dev), ecap, epos);
+
+			/* If not the first in the chain, we can skip over it */
+			if (prev) {
+				epos = PCI_EXT_CAP_NEXT(header);
+				*prev &= cpu_to_le32(~((u32)0xffc << 20));
+				*prev |= cpu_to_le32((u32)epos << 20);
+				continue;
+			}
+
+			/*
+			 * Otherwise, fill in a placeholder, the direct
+			 * readfn will virtualize this automatically
+			 */
+			len = PCI_CAP_SIZEOF;
+			hidden = true;
+		}
+
+		for (i = 0; i < len; i += 4) {
+			if (likely(map[(epos + i) / 4] == PCI_CAP_ID_INVALID))
+				continue;
+
+			printk(KERN_WARNING
+			       "%s: %s pci config conflict @0x%x, was ecap 0x%x now ecap 0x%x\n",
+			       __func__, dev_name(&pdev->dev),
+			       epos + i, map[epos + i], ecap);
+		}
+
+		/*
+		 * Even though ecap is 2 bytes, we're currently a long way
+		 * from exceeding 1 byte capabilities.  If we ever make it
+		 * up to 0xFF we'll need to up this to a two-byte, byte map.
+		 */
+		BUILD_BUG_ON(PCI_EXT_CAP_ID_MAX >= PCI_CAP_ID_INVALID);
+
+		memset(map + (epos / 4), ecap, len / 4);
+		ret = vfio_fill_vconfig_bytes(vdev, epos, len);
+		if (ret)
+			return ret;
+
+		/*
+		 * If we're just using this capability to anchor the list,
+		 * hide the real ID.  Only count real ecaps.  XXX PCI spec
+		 * indicates to use cap id = 0, version = 0, next = 0 if
+		 * ecaps are absent, hope users check all the way to next.
+		 */
+		if (hidden)
+			*(u32 *)&vdev->vconfig[epos] &=
+				cpu_to_le32(((u32)0xffc << 20));
+		else
+			ecaps++;
+
+		prev = (u32 *)&vdev->vconfig[epos];
+		epos = PCI_EXT_CAP_NEXT(header);
+	}
+
+	if (!ecaps)
+		*(u32 *)&vdev->vconfig[PCI_CFG_SPACE_SIZE] = 0;
+
+	return 0;
+}
+
+/*
+ * For each device we allocate a pci_config_map that indicates the
+ * capability occupying each dword and thus the struct perm_bits we
+ * use for read and write.  We also allocate a virtualized config
+ * space which tracks reads and writes to bits that we emulate for
+ * the user.  Initial values filled from device.
+ *
+ * Using shared stuct perm_bits between all vfio-pci devices saves
+ * us from allocating cfg_size buffers for virt and write for every
+ * device.  We could remove vconfig and allocate individual buffers
+ * for each area requring emulated bits, but the array of pointers
+ * would be comparable in size (at least for standard config space).
+ */
+int vfio_config_init(struct vfio_pci_device *vdev)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	u8 *map, *vconfig;
+	int ret;
+
+	/*
+	 * Config space, caps and ecaps are all dword aligned, so we can
+	 * use one byte per dword to record the type.
+	 */
+	map = kmalloc(pdev->cfg_size / 4, GFP_KERNEL);
+	if (!map)
+		return -ENOMEM;
+
+	vconfig = kmalloc(pdev->cfg_size, GFP_KERNEL);
+	if (!vconfig) {
+		kfree(map);
+		return -ENOMEM;
+	}
+
+	vdev->pci_config_map = map;
+	vdev->vconfig = vconfig;
+
+	memset(map, PCI_CAP_ID_BASIC, PCI_STD_HEADER_SIZEOF / 4);
+	memset(map + (PCI_STD_HEADER_SIZEOF / 4), PCI_CAP_ID_INVALID,
+	       (pdev->cfg_size - PCI_STD_HEADER_SIZEOF) / 4);
+
+	ret = vfio_fill_vconfig_bytes(vdev, 0, PCI_STD_HEADER_SIZEOF);
+	if (ret)
+		goto out;
+
+	vdev->bardirty = true;
+
+	/*
+	 * XXX can we just pci_load_saved_state/pci_restore_state?
+	 * may need to rebuild vconfig after that
+	 */
+
+	/* For restore after reset */
+	vdev->rbar[0] = *(u32 *)&vconfig[PCI_BASE_ADDRESS_0];
+	vdev->rbar[1] = *(u32 *)&vconfig[PCI_BASE_ADDRESS_1];
+	vdev->rbar[2] = *(u32 *)&vconfig[PCI_BASE_ADDRESS_2];
+	vdev->rbar[3] = *(u32 *)&vconfig[PCI_BASE_ADDRESS_3];
+	vdev->rbar[4] = *(u32 *)&vconfig[PCI_BASE_ADDRESS_4];
+	vdev->rbar[5] = *(u32 *)&vconfig[PCI_BASE_ADDRESS_5];
+	vdev->rbar[6] = *(u32 *)&vconfig[PCI_ROM_ADDRESS];
+
+	if (pdev->is_virtfn) {
+		*(u16 *)&vconfig[PCI_VENDOR_ID] = cpu_to_le16(pdev->vendor);
+		*(u16 *)&vconfig[PCI_DEVICE_ID] = cpu_to_le16(pdev->device);
+	}
+
+	ret = vfio_cap_init(vdev);
+	if (ret)
+		goto out;
+
+	ret = vfio_ecap_init(vdev);
+	if (ret)
+		goto out;
+
+	return 0;
+
+out:
+	kfree(map);
+	vdev->pci_config_map = NULL;
+	kfree(vconfig);
+	vdev->vconfig = NULL;
+	return pcibios_err_to_errno(ret);
+}
+
+void vfio_config_free(struct vfio_pci_device *vdev)
+{
+	kfree(vdev->vconfig);
+	vdev->vconfig = NULL;
+	kfree(vdev->pci_config_map);
+	vdev->pci_config_map = NULL;
+	kfree(vdev->msi_perm);
+	vdev->msi_perm = NULL;
+}
+
+ssize_t vfio_config_do_rw(struct vfio_pci_device *vdev, char __user *buf,
+			  size_t count, loff_t *ppos, bool iswrite)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	struct perm_bits *perm;
+	u32 val = 0;
+	int cap_start = 0, offset;
+	u8 cap_id;
+
+
+	if (*ppos < 0 || *ppos + count > pdev->cfg_size)
+		return -EFAULT;
+
+	cap_id = vdev->pci_config_map[*ppos / 4];
+
+	if (cap_id == PCI_CAP_ID_INVALID) {
+		if (iswrite)
+			return count; /* drop */
+
+		/*
+		 * Per PCI spec 3.0, section 6.1, reads from reserved and
+		 * unimplemented registers return 0
+		 */
+		if (copy_to_user(buf, &val, count))
+			return -EFAULT;
+
+		return count;
+	}
+
+	/*
+	 * All capabilities are minimum 4 bytes and aligned on dword
+	 * boundaries.  Since we don't support unaligned accesses, we're
+	 * only ever accessing a single capability.
+	 */
+	if (*ppos >= PCI_CFG_SPACE_SIZE) {
+		WARN_ON(cap_id > PCI_EXT_CAP_ID_MAX);
+
+		perm = &ecap_perms[cap_id];
+		cap_start = vfio_find_cap_start(vdev, *ppos);
+
+	} else {
+		WARN_ON(cap_id > PCI_CAP_ID_MAX);
+
+		perm = &cap_perms[cap_id];
+
+		if (cap_id == PCI_CAP_ID_MSI)
+			perm = vdev->msi_perm;
+
+		if (cap_id > PCI_CAP_ID_BASIC)
+			cap_start = vfio_find_cap_start(vdev, *ppos);
+	}
+
+	WARN_ON(!cap_start && cap_id != PCI_CAP_ID_BASIC);
+	WARN_ON(cap_start > *ppos);
+
+	offset = *ppos - cap_start;
+
+	if (iswrite) {
+		if (perm->writefn) {
+			if (copy_from_user(&val, buf, count))
+				return -EFAULT;
+
+			count = perm->writefn(vdev, *ppos, count,
+					      perm, offset, val);
+		}
+	} else {
+		if (perm->readfn) {
+			count = perm->readfn(vdev, *ppos, count,
+					     perm, offset, &val);
+			if (count < 0)
+				return count;
+		}
+
+		if (copy_to_user(buf, &val, count))
+			return -EFAULT;
+	}
+
+	return count;
+}
+
+ssize_t vfio_pci_config_readwrite(struct vfio_pci_device *vdev,
+				  char __user *buf, size_t count,
+				  loff_t *ppos, bool iswrite)
+{
+	size_t done = 0;
+	int ret = 0;
+	loff_t pos = *ppos;
+
+	pos &= VFIO_PCI_OFFSET_MASK;
+
+	/*
+	 * We want to both keep the access size the caller users as well as
+	 * support reading large chunks of config space in a single call.
+	 * PCI doesn't support unaligned accesses, so we can safely break
+	 * those apart.
+	 */
+	while (count) {
+		if (count >= 4 && !(pos % 4))
+			ret = vfio_config_do_rw(vdev, buf, 4, &pos, iswrite);
+		else if (count >= 2 && !(pos % 2))
+			ret = vfio_config_do_rw(vdev, buf, 2, &pos, iswrite);
+		else
+			ret = vfio_config_do_rw(vdev, buf, 1, &pos, iswrite);
+
+		if (ret < 0)
+			return ret;
+
+		count -= ret;
+		done += ret;
+		buf += ret;
+		pos += ret;
+	}
+
+	*ppos += done;
+
+	return done;
+}
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
new file mode 100644
index 0000000..1fa653b
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -0,0 +1,727 @@
+/*
+ * VFIO PCI interrupt handling
+ *
+ * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
+ *     Author: Alex Williamson <alex.williamson@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.
+ *
+ * Derived from original vfio:
+ * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
+ * Author: Tom Lyon, pugs@cisco.com
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/eventfd.h>
+#include <linux/pci.h>
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/vfio.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include "vfio_pci_private.h"
+
+/*
+ * IRQfd - generic
+ */
+struct virqfd {
+	struct vfio_pci_device	*vdev;
+	void			*data;
+	struct eventfd_ctx	*eventfd;
+	poll_table		pt;
+	wait_queue_t		wait;
+	struct work_struct	inject;
+	struct work_struct	shutdown;
+	struct virqfd		**pvirqfd;
+};
+
+static struct workqueue_struct *vfio_irqfd_cleanup_wq;
+
+int __init vfio_pci_virqfd_init(void)
+{
+	vfio_irqfd_cleanup_wq =
+		create_singlethread_workqueue("vfio-irqfd-cleanup");
+	if (!vfio_irqfd_cleanup_wq)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void vfio_pci_virqfd_exit(void)
+{
+	destroy_workqueue(vfio_irqfd_cleanup_wq);
+}
+
+static void virqfd_deactivate(struct virqfd *virqfd)
+{
+	queue_work(vfio_irqfd_cleanup_wq, &virqfd->shutdown);
+}
+
+static int virqfd_wakeup(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+	struct virqfd *virqfd = container_of(wait, struct virqfd, wait);
+	unsigned long flags = (unsigned long)key;
+
+	if (flags & POLLIN)
+		/* An event has been signaled, inject an interrupt */
+		schedule_work(&virqfd->inject);
+
+	if (flags & POLLHUP)
+		/* The eventfd is closing, detach from VFIO */
+		virqfd_deactivate(virqfd);
+
+	return 0;
+}
+
+static void virqfd_ptable_queue_proc(struct file *file,
+				     wait_queue_head_t *wqh, poll_table *pt)
+{
+	struct virqfd *virqfd = container_of(pt, struct virqfd, pt);
+	add_wait_queue(wqh, &virqfd->wait);
+}
+
+static void virqfd_shutdown(struct work_struct *work)
+{
+	u64 cnt;
+	struct virqfd *virqfd = container_of(work, struct virqfd, shutdown);
+	struct virqfd **pvirqfd = virqfd->pvirqfd;
+
+	eventfd_ctx_remove_wait_queue(virqfd->eventfd, &virqfd->wait, &cnt);
+	flush_work(&virqfd->inject);
+	eventfd_ctx_put(virqfd->eventfd);
+
+	kfree(virqfd);
+	*pvirqfd = NULL;
+}
+
+static int virqfd_enable(struct vfio_pci_device *vdev,
+			 void (*inject)(struct work_struct *work),
+			 void *data, struct virqfd **pvirqfd, int fd)
+{
+	struct file *file = NULL;
+	struct eventfd_ctx *ctx = NULL;
+	struct virqfd *virqfd;
+	int ret = 0;
+	unsigned int events;
+
+	if (*pvirqfd)
+		return -EBUSY;
+
+	virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL);
+	if (!virqfd)
+		return -ENOMEM;
+
+	virqfd->vdev = vdev;
+	virqfd->data = data;
+	virqfd->pvirqfd = pvirqfd;
+	*pvirqfd = virqfd;
+
+	INIT_WORK(&virqfd->inject, inject);
+	INIT_WORK(&virqfd->shutdown, virqfd_shutdown);
+
+	file = eventfd_fget(fd);
+	if (IS_ERR(file)) {
+		ret = PTR_ERR(file);
+		goto fail;
+	}
+
+	ctx = eventfd_ctx_fileget(file);
+	if (IS_ERR(ctx)) {
+		ret = PTR_ERR(ctx);
+		goto fail;
+	}
+
+	virqfd->eventfd = ctx;
+
+	/*
+	 * Install our own custom wake-up handling so we are notified via
+	 * a callback whenever someone signals the underlying eventfd.
+	 */
+	init_waitqueue_func_entry(&virqfd->wait, virqfd_wakeup);
+	init_poll_funcptr(&virqfd->pt, virqfd_ptable_queue_proc);
+
+	events = file->f_op->poll(file, &virqfd->pt);
+
+	/*
+	 * Check if there was an event already pending on the eventfd
+	 * before we registered and trigger it as if we didn't miss it.
+	 */
+	if (events & POLLIN)
+		schedule_work(&virqfd->inject);
+
+	/*
+	 * Do not drop the file until the irqfd is fully initialized,
+	 * otherwise we might race against the POLLHUP.
+	 */
+	fput(file);
+
+	return 0;
+
+fail:
+	if (ctx && !IS_ERR(ctx))
+		eventfd_ctx_put(ctx);
+
+	if (!IS_ERR(file))
+		fput(file);
+
+	kfree(virqfd);
+	*pvirqfd = NULL;
+
+	return ret;
+}
+
+static void virqfd_disable(struct virqfd *virqfd)
+{
+	if (!virqfd)
+		return;
+
+	virqfd_deactivate(virqfd);
+
+	/* Block until we know all outstanding shutdown jobs have completed. */
+	flush_workqueue(vfio_irqfd_cleanup_wq);
+}
+
+/*
+ * INTx
+ */
+static inline void vfio_send_intx_eventfd(struct vfio_pci_device *vdev)
+{
+	if (likely(is_intx(vdev) && !vdev->virq_disabled))
+		eventfd_signal(vdev->ctx[0].trigger, 1);
+}
+
+void vfio_pci_intx_mask(struct vfio_pci_device *vdev)
+{
+	struct pci_dev *pdev = vdev->pdev;
+
+	spin_lock_irq(&vdev->irqlock);
+
+	/*
+	 * Masking can come from interrupt, ioctl, or config space
+	 * via INTx disable.  The latter means this can get called
+	 * even when not using intx delivery.  In this case, just
+	 * try to have the physical bit follow the virtual bit.
+	 */
+	if (unlikely(!is_intx(vdev))) {
+		if (vdev->pci_2_3)
+			pci_intx(pdev, 0);
+	} else if (!vdev->ctx[0].masked) {
+		/*
+		 * Can't use check_and_mask here because we always want to
+		 * mask, not just when something is pending.
+		 */
+		if (vdev->pci_2_3)
+			pci_intx(pdev, 0);
+		else
+			disable_irq_nosync(pdev->irq);
+
+		vdev->ctx[0].masked = true;
+	}
+
+	spin_unlock_irq(&vdev->irqlock);
+}
+
+void vfio_pci_intx_unmask(struct vfio_pci_device *vdev)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	bool signal = false;
+
+	spin_lock_irq(&vdev->irqlock);
+
+	/*
+	 * Unmasking comes from ioctl or config, so again, have the
+	 * physical bit follow the virtual even when not using INTx.
+	 */
+	if (unlikely(!is_intx(vdev))) {
+		if (vdev->pci_2_3)
+			pci_intx(pdev, 1);
+	} else if (vdev->ctx[0].masked && !vdev->virq_disabled) {
+		/*
+		 * A pending interrupt here would immediately trigger,
+		 * but we can avoid that overhead by just re-sending
+		 * the interrupt to the user.
+		 */
+		if (vdev->pci_2_3) {
+			if (!pci_check_and_unmask_intx(pdev))
+				signal = true;
+		} else
+			enable_irq(pdev->irq);
+
+		vdev->ctx[0].masked = signal;
+	}
+
+	spin_unlock_irq(&vdev->irqlock);
+
+	if (signal)
+		vfio_send_intx_eventfd(vdev);
+}
+
+static irqreturn_t vfio_intx_handler(int irq, void *dev_id)
+{
+	struct vfio_pci_device *vdev = dev_id;
+	struct pci_dev *pdev = vdev->pdev;
+	irqreturn_t ret = IRQ_NONE;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vdev->irqlock, flags);
+
+	/* Non-PCI 2.3 device don't use this hard handler */
+	if (pci_check_and_mask_intx(pdev)) {
+		ret = IRQ_WAKE_THREAD;
+		vdev->ctx[0].masked = true;
+	}
+
+	spin_unlock_irqrestore(&vdev->irqlock, flags);
+
+	return ret;
+}
+
+static irqreturn_t vfio_intx_thread(int irq, void *dev_id)
+{
+	struct vfio_pci_device *vdev = dev_id;
+	int ret = IRQ_HANDLED;
+
+	if (unlikely(!vdev->pci_2_3)) {
+		spin_lock_irq(&vdev->irqlock);
+		if (!vdev->ctx[0].masked) {
+			disable_irq_nosync(vdev->pdev->irq);
+			vdev->ctx[0].masked = true;
+		} else
+			ret = IRQ_NONE;
+		spin_unlock_irq(&vdev->irqlock);
+	}
+
+	if (ret == IRQ_HANDLED)
+		vfio_send_intx_eventfd(vdev);
+
+	return ret;
+}
+
+static int vfio_intx_enable(struct vfio_pci_device *vdev)
+{
+	if (!is_irq_none(vdev))
+		return -EINVAL;
+
+	if (!vdev->pdev->irq)
+		return -ENODEV;
+
+	vdev->ctx = kzalloc(sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
+	if (!vdev->ctx)
+		return -ENOMEM;
+
+	vdev->num_ctx = 1;
+	vdev->irq_type = VFIO_PCI_INTX_IRQ_INDEX;
+
+	return 0;
+}
+
+static int vfio_intx_set_signal(struct vfio_pci_device *vdev, int fd)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	irq_handler_t handler = vfio_intx_handler;
+	unsigned long irqflags = IRQF_SHARED;
+	struct eventfd_ctx *trigger;
+	int ret;
+
+	if (vdev->ctx[0].trigger) {
+		free_irq(pdev->irq, vdev);
+		kfree(vdev->ctx[0].name);
+		eventfd_ctx_put(vdev->ctx[0].trigger);
+		vdev->ctx[0].trigger = NULL;
+	}
+
+	if (fd < 0) /* Disable only */
+		return 0;
+
+	vdev->ctx[0].name = kasprintf(GFP_KERNEL, "vfio-intx(%s)",
+				      pci_name(pdev));
+	if (!vdev->ctx[0].name)
+		return -ENOMEM;
+
+	trigger = eventfd_ctx_fdget(fd);
+	if (IS_ERR(trigger)) {
+		kfree(vdev->ctx[0].name);
+		return PTR_ERR(trigger);
+	}
+
+	if (!vdev->pci_2_3) {
+		handler = NULL;
+		irqflags = IRQF_ONESHOT;
+	}
+
+	ret = request_threaded_irq(pdev->irq, handler, vfio_intx_thread,
+				   irqflags, vdev->ctx[0].name, vdev);
+	if (ret) {
+		kfree(vdev->ctx[0].name);
+		eventfd_ctx_put(trigger);
+		return ret;
+	}
+
+	vdev->ctx[0].trigger = trigger;
+
+	/*
+	 * INTx disable will stick across the new irq setup,
+	 * disable_irq won't.
+	 */
+	if (!vdev->pci_2_3 && (vdev->ctx[0].masked || vdev->virq_disabled))
+		disable_irq_nosync(pdev->irq);
+
+	return 0;
+}
+
+static void vfio_intx_disable(struct vfio_pci_device *vdev)
+{
+	vfio_intx_set_signal(vdev, -1);
+	virqfd_disable(vdev->ctx[0].unmask);
+	virqfd_disable(vdev->ctx[0].mask);
+	vdev->irq_type = VFIO_PCI_NUM_IRQS;
+	vdev->num_ctx = 0;
+	kfree(vdev->ctx);
+}
+
+static void vfio_intx_unmask_inject(struct work_struct *work)
+{
+	struct virqfd *virqfd = container_of(work, struct virqfd, inject);
+	vfio_pci_intx_unmask(virqfd->vdev);
+}
+
+/*
+ * MSI/MSI-X
+ */
+static irqreturn_t vfio_msihandler(int irq, void *arg)
+{
+	struct eventfd_ctx *trigger = arg;
+
+	eventfd_signal(trigger, 1);
+	return IRQ_HANDLED;
+}
+
+static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	int ret;
+
+	if (!is_irq_none(vdev))
+		return -EINVAL;
+
+	vdev->ctx = kzalloc(nvec * sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
+	if (!vdev->ctx)
+		return -ENOMEM;
+
+	if (msix) {
+		int i;
+
+		vdev->msix = kzalloc(nvec * sizeof(struct msix_entry),
+				     GFP_KERNEL);
+		if (!vdev->msix) {
+			kfree(vdev->ctx);
+			return -ENOMEM;
+		}
+
+		for (i = 0; i < nvec; i++)
+			vdev->msix[i].entry = i;
+
+		ret = pci_enable_msix(pdev, vdev->msix, nvec);
+		if (ret) {
+			kfree(vdev->msix);
+			kfree(vdev->ctx);
+			return ret;
+		}
+	} else {
+		ret = pci_enable_msi_block(pdev, nvec);
+		if (ret) {
+			kfree(vdev->ctx);
+			return ret;
+		}
+	}
+
+	vdev->num_ctx = nvec;
+	vdev->irq_type = msix ? VFIO_PCI_MSIX_IRQ_INDEX :
+				VFIO_PCI_MSI_IRQ_INDEX;
+
+	if (!msix) {
+		/*
+		 * Compute the virtual hardware field for max msi vectors -
+		 * it is the log base 2 of the number of vectors.
+		 */
+		vdev->msi_qmax = fls(nvec * 2 - 1) - 1;
+	}
+
+	return 0;
+}
+
+static int vfio_msi_set_vector_signal(struct vfio_pci_device *vdev,
+				      int vector, int fd, bool msix)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	int irq = msix ? vdev->msix[vector].vector : pdev->irq + vector;
+	char *name = msix ? "vfio-msix" : "vfio-msi";
+	struct eventfd_ctx *trigger;
+	int ret;
+
+	if (vector >= vdev->num_ctx)
+		return -EINVAL;
+
+	if (vdev->ctx[vector].trigger) {
+		free_irq(irq, vdev->ctx[vector].trigger);
+		kfree(vdev->ctx[vector].name);
+		eventfd_ctx_put(vdev->ctx[vector].trigger);
+		vdev->ctx[vector].trigger = NULL;
+	}
+
+	if (fd < 0)
+		return 0;
+
+	vdev->ctx[vector].name = kasprintf(GFP_KERNEL, "%s[%d](%s)",
+					   name, vector, pci_name(pdev));
+	if (!vdev->ctx[vector].name)
+		return -ENOMEM;
+
+	trigger = eventfd_ctx_fdget(fd);
+	if (IS_ERR(trigger)) {
+		kfree(vdev->ctx[vector].name);
+		return PTR_ERR(trigger);
+	}
+
+	ret = request_threaded_irq(irq, NULL, vfio_msihandler, IRQF_ONESHOT,
+				   vdev->ctx[vector].name, trigger);
+	if (ret) {
+		kfree(vdev->ctx[vector].name);
+		eventfd_ctx_put(trigger);
+		return ret;
+	}
+
+	vdev->ctx[vector].trigger = trigger;
+
+	return 0;
+}
+
+static int vfio_msi_set_block(struct vfio_pci_device *vdev, int start,
+			      int count, int32_t *fds, bool msix)
+{
+	int i, j, ret = 0;
+
+	if (start + count > vdev->num_ctx)
+		return -EINVAL;
+
+	for (i = 0, j = start; i < count && !ret; i++, j++) {
+		int fd = fds ? fds[i] : -1;
+		ret = vfio_msi_set_vector_signal(vdev, j, fd, msix);
+	}
+
+	if (ret) {
+		for (--j; j >= start; j--)
+			vfio_msi_set_vector_signal(vdev, j, -1, msix);
+	}
+
+	return ret;
+}
+
+static void vfio_msi_disable(struct vfio_pci_device *vdev, bool msix)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	int i;
+
+	vfio_msi_set_block(vdev, 0, vdev->num_ctx, NULL, msix);
+
+	for (i = 0; i < vdev->num_ctx; i++) {
+		virqfd_disable(vdev->ctx[i].unmask);
+		virqfd_disable(vdev->ctx[i].mask);
+	}
+
+	if (msix) {
+		pci_disable_msix(vdev->pdev);
+		kfree(vdev->msix);
+	} else
+		pci_disable_msi(pdev);
+
+	vdev->irq_type = VFIO_PCI_NUM_IRQS;
+	vdev->num_ctx = 0;
+	kfree(vdev->ctx);
+}
+
+/*
+ * IOCTL support
+ */
+static int vfio_pci_set_intx_unmask(struct vfio_pci_device *vdev,
+				    int index, int start, int count,
+				    uint32_t flags, void *data)
+{
+	if (!is_intx(vdev) || start != 0 || count != 1)
+		return -EINVAL;
+
+	if (flags & VFIO_IRQ_SET_DATA_NONE) {
+		vfio_pci_intx_unmask(vdev);
+	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
+		uint8_t unmask = *(uint8_t *)data;
+		if (unmask)
+			vfio_pci_intx_unmask(vdev);
+	} else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+		int32_t fd = *(int32_t *)data;
+		if (fd >= 0)
+			return virqfd_enable(vdev, vfio_intx_unmask_inject,
+					     NULL, &vdev->ctx[0].unmask, fd);
+
+		virqfd_disable(vdev->ctx[0].unmask);
+	}
+
+	return 0;
+}
+
+static int vfio_pci_set_intx_mask(struct vfio_pci_device *vdev,
+				  int index, int start, int count,
+				  uint32_t flags, void *data)
+{
+	if (!is_intx(vdev) || start != 0 || count != 1)
+		return -EINVAL;
+
+	if (flags & VFIO_IRQ_SET_DATA_NONE) {
+		vfio_pci_intx_mask(vdev);
+	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
+		uint8_t mask = *(uint8_t *)data;
+		if (mask)
+			vfio_pci_intx_mask(vdev);
+	} else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+		return -ENOTTY; /* XXX implement me */
+	}
+
+	return 0;
+}
+
+static int vfio_pci_set_intx_trigger(struct vfio_pci_device *vdev,
+				     int index, int start, int count,
+				     uint32_t flags, void *data)
+{
+	if (is_intx(vdev) && !count && (flags & VFIO_IRQ_SET_DATA_NONE)) {
+		vfio_intx_disable(vdev);
+		return 0;
+	}
+
+	if (!(is_intx(vdev) || is_irq_none(vdev)) || start != 0 || count != 1)
+		return -EINVAL;
+
+	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+		int32_t fd = *(int32_t *)data;
+		int ret;
+
+		if (is_intx(vdev))
+			return vfio_intx_set_signal(vdev, fd);
+
+		ret = vfio_intx_enable(vdev);
+		if (ret)
+			return ret;
+
+		ret = vfio_intx_set_signal(vdev, fd);
+		if (ret)
+			vfio_intx_disable(vdev);
+
+		return ret;
+	}
+
+	if (!is_intx(vdev))
+		return -EINVAL;
+
+	if (flags & VFIO_IRQ_SET_DATA_NONE) {
+		vfio_send_intx_eventfd(vdev);
+	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
+		uint8_t trigger = *(uint8_t *)data;
+		if (trigger)
+			vfio_send_intx_eventfd(vdev);
+	}
+	return 0;
+}
+
+static int vfio_pci_set_msi_trigger(struct vfio_pci_device *vdev,
+				    int index, int start, int count,
+				    uint32_t flags, void *data)
+{
+	int i;
+	bool msix = (index == VFIO_PCI_MSIX_IRQ_INDEX) ? true : false;
+
+	if (irq_is(vdev, index) && !count && (flags & VFIO_IRQ_SET_DATA_NONE)) {
+		vfio_msi_disable(vdev, msix);
+		return 0;
+	}
+
+	if (!(irq_is(vdev, index) || is_irq_none(vdev)))
+		return -EINVAL;
+
+	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+		int32_t *fds = data;
+		int ret;
+
+		if (vdev->irq_type == index)
+			return vfio_msi_set_block(vdev, start, count,
+						  fds, msix);
+
+		ret = vfio_msi_enable(vdev, start + count, msix);
+		if (ret)
+			return ret;
+
+		ret = vfio_msi_set_block(vdev, start, count, fds, msix);
+		if (ret)
+			vfio_msi_disable(vdev, msix);
+
+		return ret;
+	}
+
+	if (!irq_is(vdev, index) || start + count > vdev->num_ctx)
+		return -EINVAL;
+
+	for (i = start; i < start + count; i++) {
+		if (!vdev->ctx[i].trigger)
+			continue;
+		if (flags & VFIO_IRQ_SET_DATA_NONE) {
+			eventfd_signal(vdev->ctx[i].trigger, 1);
+		} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
+			uint8_t *bools = data;
+			if (bools[i - start])
+				eventfd_signal(vdev->ctx[i].trigger, 1);
+		}
+	}
+	return 0;
+}
+
+int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
+			    int index, int start, int count, void *data)
+{
+	int (*func)(struct vfio_pci_device *vdev, int index, int start,
+		    int count, uint32_t flags, void *data) = NULL;
+
+	switch (index) {
+	case VFIO_PCI_INTX_IRQ_INDEX:
+		switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
+		case VFIO_IRQ_SET_ACTION_MASK:
+			func = vfio_pci_set_intx_mask;
+			break;
+		case VFIO_IRQ_SET_ACTION_UNMASK:
+			func = vfio_pci_set_intx_unmask;
+			break;
+		case VFIO_IRQ_SET_ACTION_TRIGGER:
+			func = vfio_pci_set_intx_trigger;
+			break;
+		}
+		break;
+	case VFIO_PCI_MSI_IRQ_INDEX:
+	case VFIO_PCI_MSIX_IRQ_INDEX:
+		switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
+		case VFIO_IRQ_SET_ACTION_MASK:
+		case VFIO_IRQ_SET_ACTION_UNMASK:
+			/* XXX Need masking support exported */
+			break;
+		case VFIO_IRQ_SET_ACTION_TRIGGER:
+			func = vfio_pci_set_msi_trigger;
+			break;
+		}
+		break;
+	}
+
+	if (!func)
+		return -ENOTTY;
+
+	return func(vdev, index, start, count, flags, data);
+}
diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h
new file mode 100644
index 0000000..a4a3678
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_private.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
+ *     Author: Alex Williamson <alex.williamson@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.
+ *
+ * Derived from original vfio:
+ * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
+ * Author: Tom Lyon, pugs@cisco.com
+ */
+
+#include <linux/mutex.h>
+#include <linux/pci.h>
+
+#ifndef VFIO_PCI_PRIVATE_H
+#define VFIO_PCI_PRIVATE_H
+
+#define VFIO_PCI_OFFSET_SHIFT   40
+
+#define VFIO_PCI_OFFSET_TO_INDEX(off)	(off >> VFIO_PCI_OFFSET_SHIFT)
+#define VFIO_PCI_INDEX_TO_OFFSET(index)	((u64)(index) << VFIO_PCI_OFFSET_SHIFT)
+#define VFIO_PCI_OFFSET_MASK	(((u64)(1) << VFIO_PCI_OFFSET_SHIFT) - 1)
+
+struct vfio_pci_irq_ctx {
+	struct eventfd_ctx	*trigger;
+	struct virqfd		*unmask;
+	struct virqfd		*mask;
+	char			*name;
+	bool			masked;
+};
+
+struct vfio_pci_device {
+	struct pci_dev		*pdev;
+	void __iomem		*barmap[PCI_STD_RESOURCE_END + 1];
+	u8			*pci_config_map;
+	u8			*vconfig;
+	struct perm_bits	*msi_perm;
+	spinlock_t		irqlock;
+	struct mutex		igate;
+	struct msix_entry	*msix;
+	struct vfio_pci_irq_ctx	*ctx;
+	int			num_ctx;
+	int			irq_type;
+	u8			msi_qmax;
+	u8			msix_bar;
+	u16			msix_size;
+	u32			msix_offset;
+	u32			rbar[7];
+	bool			pci_2_3;
+	bool			virq_disabled;
+	bool			reset_works;
+	bool			extended_caps;
+	bool			bardirty;
+	struct pci_saved_state	*pci_saved_state;
+	atomic_t		refcnt;
+};
+
+#define is_intx(vdev) (vdev->irq_type == VFIO_PCI_INTX_IRQ_INDEX)
+#define is_msi(vdev) (vdev->irq_type == VFIO_PCI_MSI_IRQ_INDEX)
+#define is_msix(vdev) (vdev->irq_type == VFIO_PCI_MSIX_IRQ_INDEX)
+#define is_irq_none(vdev) (!(is_intx(vdev) || is_msi(vdev) || is_msix(vdev)))
+#define irq_is(vdev, type) (vdev->irq_type == type)
+
+extern void vfio_pci_intx_mask(struct vfio_pci_device *vdev);
+extern void vfio_pci_intx_unmask(struct vfio_pci_device *vdev);
+
+extern int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev,
+				   uint32_t flags, int index, int start,
+				   int count, void *data);
+
+extern ssize_t vfio_pci_config_readwrite(struct vfio_pci_device *vdev,
+					 char __user *buf, size_t count,
+					 loff_t *ppos, bool iswrite);
+extern ssize_t vfio_pci_mem_readwrite(struct vfio_pci_device *vdev,
+				      char __user *buf, size_t count,
+				      loff_t *ppos, bool iswrite);
+extern ssize_t vfio_pci_io_readwrite(struct vfio_pci_device *vdev,
+				     char __user *buf, size_t count,
+				     loff_t *ppos, bool iswrite);
+
+extern int vfio_pci_init_perm_bits(void);
+extern void vfio_pci_uninit_perm_bits(void);
+
+extern int vfio_pci_virqfd_init(void);
+extern void vfio_pci_virqfd_exit(void);
+
+extern int vfio_config_init(struct vfio_pci_device *vdev);
+extern void vfio_config_free(struct vfio_pci_device *vdev);
+#endif /* VFIO_PCI_PRIVATE_H */
diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
new file mode 100644
index 0000000..883cd33
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_rdwr.c
@@ -0,0 +1,269 @@
+/*
+ * VFIO PCI I/O Port & MMIO access
+ *
+ * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
+ *     Author: Alex Williamson <alex.williamson@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.
+ *
+ * Derived from original vfio:
+ * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
+ * Author: Tom Lyon, pugs@cisco.com
+ */
+
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include "vfio_pci_private.h"
+
+/* I/O Port BAR access */
+ssize_t vfio_pci_io_readwrite(struct vfio_pci_device *vdev, char __user *buf,
+			      size_t count, loff_t *ppos, bool iswrite)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
+	int bar = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
+	void __iomem *io;
+	size_t done = 0;
+
+	if (!pci_resource_start(pdev, bar))
+		return -EINVAL;
+
+	if (pos + count > pci_resource_len(pdev, bar))
+		return -EINVAL;
+
+	if (!vdev->barmap[bar]) {
+		int ret;
+
+		ret = pci_request_selected_regions(pdev, 1 << bar, "vfio");
+		if (ret)
+			return ret;
+
+		vdev->barmap[bar] = pci_iomap(pdev, bar, 0);
+
+		if (!vdev->barmap[bar]) {
+			pci_release_selected_regions(pdev, 1 << bar);
+			return -EINVAL;
+		}
+	}
+
+	io = vdev->barmap[bar];
+
+	while (count) {
+		int filled;
+
+		if (count >= 3 && !(pos % 4)) {
+			u32 val;
+
+			if (iswrite) {
+				if (copy_from_user(&val, buf, 4))
+					return -EFAULT;
+
+				iowrite32(le32_to_cpu(val), io + pos);
+			} else {
+				val = cpu_to_le32(ioread32(io + pos));
+
+				if (copy_to_user(buf, &val, 4))
+					return -EFAULT;
+			}
+
+			filled = 4;
+
+		} else if ((pos % 2) == 0 && count >= 2) {
+			u16 val;
+
+			if (iswrite) {
+				if (copy_from_user(&val, buf, 2))
+					return -EFAULT;
+
+				iowrite16(le16_to_cpu(val), io + pos);
+			} else {
+				val = cpu_to_le16(ioread16(io + pos));
+
+				if (copy_to_user(buf, &val, 2))
+					return -EFAULT;
+			}
+
+			filled = 2;
+		} else {
+			u8 val;
+
+			if (iswrite) {
+				if (copy_from_user(&val, buf, 1))
+					return -EFAULT;
+
+				iowrite8(val, io + pos);
+			} else {
+				val = ioread8(io + pos);
+
+				if (copy_to_user(buf, &val, 1))
+					return -EFAULT;
+			}
+
+			filled = 1;
+		}
+
+		count -= filled;
+		done += filled;
+		buf += filled;
+		pos += filled;
+	}
+
+	*ppos += done;
+
+	return done;
+}
+
+/*
+ * MMIO BAR access
+ * We handle two excluded ranges here as well, if the user tries to read
+ * the ROM beyond what PCI tells us is available or the MSI-X table region,
+ * we return 0xFF and writes are dropped.
+ */
+ssize_t vfio_pci_mem_readwrite(struct vfio_pci_device *vdev, char __user *buf,
+			       size_t count, loff_t *ppos, bool iswrite)
+{
+	struct pci_dev *pdev = vdev->pdev;
+	loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
+	int bar = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
+	void __iomem *io;
+	resource_size_t end;
+	size_t done = 0;
+	size_t x_start = 0, x_end = 0; /* excluded range */
+
+	if (!pci_resource_start(pdev, bar))
+		return -EINVAL;
+
+	end = pci_resource_len(pdev, bar);
+
+	if (pos > end)
+		return -EINVAL;
+
+	if (pos == end)
+		return 0;
+
+	if (pos + count > end)
+		count = end - pos;
+
+	if (bar == PCI_ROM_RESOURCE) {
+		io = pci_map_rom(pdev, &x_start);
+		x_end = end;
+	} else {
+		if (!vdev->barmap[bar]) {
+			int ret;
+
+			ret = pci_request_selected_regions(pdev, 1 << bar,
+							   "vfio");
+			if (ret)
+				return ret;
+
+			vdev->barmap[bar] = pci_iomap(pdev, bar, 0);
+
+			if (!vdev->barmap[bar]) {
+				pci_release_selected_regions(pdev, 1 << bar);
+				return -EINVAL;
+			}
+		}
+
+		io = vdev->barmap[bar];
+
+		if (bar == vdev->msix_bar) {
+			x_start = vdev->msix_offset;
+			x_end = vdev->msix_offset + vdev->msix_size;
+		}
+	}
+
+	if (!io)
+		return -EINVAL;
+
+	while (count) {
+		size_t fillable, filled;
+
+		if (pos < x_start)
+			fillable = x_start - pos;
+		else if (pos >= x_end)
+			fillable = end - pos;
+		else
+			fillable = 0;
+
+		if (fillable >= 4 && !(pos % 4) && (count >= 4)) {
+			u32 val;
+
+			if (iswrite) {
+				if (copy_from_user(&val, buf, 4))
+					goto out;
+
+				iowrite32(le32_to_cpu(val), io + pos);
+			} else {
+				val = cpu_to_le32(ioread32(io + pos));
+
+				if (copy_to_user(buf, &val, 4))
+					goto out;
+			}
+
+			filled = 4;
+		} else if (fillable >= 2 && !(pos % 2) && (count >= 2)) {
+			u16 val;
+
+			if (iswrite) {
+				if (copy_from_user(&val, buf, 2))
+					goto out;
+
+				iowrite16(le16_to_cpu(val), io + pos);
+			} else {
+				val = cpu_to_le16(ioread16(io + pos));
+
+				if (copy_to_user(buf, &val, 2))
+					goto out;
+			}
+
+			filled = 2;
+		} else if (fillable) {
+			u8 val;
+
+			if (iswrite) {
+				if (copy_from_user(&val, buf, 1))
+					goto out;
+
+				iowrite8(val, io + pos);
+			} else {
+				val = ioread8(io + pos);
+
+				if (copy_to_user(buf, &val, 1))
+					goto out;
+			}
+
+			filled = 1;
+		} else {
+			/* Drop writes, fill reads with FF */
+			if (!iswrite) {
+				char val = 0xFF;
+				size_t i;
+
+				for (i = 0; i < x_end - pos; i++) {
+					if (put_user(val, buf + i))
+						goto out;
+				}
+			}
+
+			filled = x_end - pos;
+		}
+
+		count -= filled;
+		done += filled;
+		buf += filled;
+		pos += filled;
+	}
+
+	*ppos += done;
+
+out:
+	if (bar == PCI_ROM_RESOURCE)
+		pci_unmap_rom(pdev, io);
+
+	return count ? -EFAULT : done;
+}
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
new file mode 100644
index 0000000..c66e48c
--- /dev/null
+++ b/drivers/vfio/vfio.c
@@ -0,0 +1,1420 @@
+/*
+ * VFIO core
+ *
+ * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
+ *     Author: Alex Williamson <alex.williamson@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.
+ *
+ * Derived from original vfio:
+ * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
+ * Author: Tom Lyon, pugs@cisco.com
+ */
+
+#include <linux/cdev.h>
+#include <linux/compat.h>
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/anon_inodes.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/iommu.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/vfio.h>
+#include <linux/wait.h>
+
+#define DRIVER_VERSION	"0.3"
+#define DRIVER_AUTHOR	"Alex Williamson <alex.williamson@redhat.com>"
+#define DRIVER_DESC	"VFIO - User Level meta-driver"
+
+static struct vfio {
+	struct class			*class;
+	struct list_head		iommu_drivers_list;
+	struct mutex			iommu_drivers_lock;
+	struct list_head		group_list;
+	struct idr			group_idr;
+	struct mutex			group_lock;
+	struct cdev			group_cdev;
+	struct device			*dev;
+	dev_t				devt;
+	struct cdev			cdev;
+	wait_queue_head_t		release_q;
+} vfio;
+
+struct vfio_iommu_driver {
+	const struct vfio_iommu_driver_ops	*ops;
+	struct list_head			vfio_next;
+};
+
+struct vfio_container {
+	struct kref			kref;
+	struct list_head		group_list;
+	struct mutex			group_lock;
+	struct vfio_iommu_driver	*iommu_driver;
+	void				*iommu_data;
+};
+
+struct vfio_group {
+	struct kref			kref;
+	int				minor;
+	atomic_t			container_users;
+	struct iommu_group		*iommu_group;
+	struct vfio_container		*container;
+	struct list_head		device_list;
+	struct mutex			device_lock;
+	struct device			*dev;
+	struct notifier_block		nb;
+	struct list_head		vfio_next;
+	struct list_head		container_next;
+};
+
+struct vfio_device {
+	struct kref			kref;
+	struct device			*dev;
+	const struct vfio_device_ops	*ops;
+	struct vfio_group		*group;
+	struct list_head		group_next;
+	void				*device_data;
+};
+
+/**
+ * IOMMU driver registration
+ */
+int vfio_register_iommu_driver(const struct vfio_iommu_driver_ops *ops)
+{
+	struct vfio_iommu_driver *driver, *tmp;
+
+	driver = kzalloc(sizeof(*driver), GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->ops = ops;
+
+	mutex_lock(&vfio.iommu_drivers_lock);
+
+	/* Check for duplicates */
+	list_for_each_entry(tmp, &vfio.iommu_drivers_list, vfio_next) {
+		if (tmp->ops == ops) {
+			mutex_unlock(&vfio.iommu_drivers_lock);
+			kfree(driver);
+			return -EINVAL;
+		}
+	}
+
+	list_add(&driver->vfio_next, &vfio.iommu_drivers_list);
+
+	mutex_unlock(&vfio.iommu_drivers_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vfio_register_iommu_driver);
+
+void vfio_unregister_iommu_driver(const struct vfio_iommu_driver_ops *ops)
+{
+	struct vfio_iommu_driver *driver;
+
+	mutex_lock(&vfio.iommu_drivers_lock);
+	list_for_each_entry(driver, &vfio.iommu_drivers_list, vfio_next) {
+		if (driver->ops == ops) {
+			list_del(&driver->vfio_next);
+			mutex_unlock(&vfio.iommu_drivers_lock);
+			kfree(driver);
+			return;
+		}
+	}
+	mutex_unlock(&vfio.iommu_drivers_lock);
+}
+EXPORT_SYMBOL_GPL(vfio_unregister_iommu_driver);
+
+/**
+ * Group minor allocation/free - both called with vfio.group_lock held
+ */
+static int vfio_alloc_group_minor(struct vfio_group *group)
+{
+	int ret, minor;
+
+again:
+	if (unlikely(idr_pre_get(&vfio.group_idr, GFP_KERNEL) == 0))
+		return -ENOMEM;
+
+	/* index 0 is used by /dev/vfio/vfio */
+	ret = idr_get_new_above(&vfio.group_idr, group, 1, &minor);
+	if (ret == -EAGAIN)
+		goto again;
+	if (ret || minor > MINORMASK) {
+		if (minor > MINORMASK)
+			idr_remove(&vfio.group_idr, minor);
+		return -ENOSPC;
+	}
+
+	return minor;
+}
+
+static void vfio_free_group_minor(int minor)
+{
+	idr_remove(&vfio.group_idr, minor);
+}
+
+static int vfio_iommu_group_notifier(struct notifier_block *nb,
+				     unsigned long action, void *data);
+static void vfio_group_get(struct vfio_group *group);
+
+/**
+ * Container objects - containers are created when /dev/vfio/vfio is
+ * opened, but their lifecycle extends until the last user is done, so
+ * it's freed via kref.  Must support container/group/device being
+ * closed in any order.
+ */
+static void vfio_container_get(struct vfio_container *container)
+{
+	kref_get(&container->kref);
+}
+
+static void vfio_container_release(struct kref *kref)
+{
+	struct vfio_container *container;
+	container = container_of(kref, struct vfio_container, kref);
+
+	kfree(container);
+}
+
+static void vfio_container_put(struct vfio_container *container)
+{
+	kref_put(&container->kref, vfio_container_release);
+}
+
+/**
+ * Group objects - create, release, get, put, search
+ */
+static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
+{
+	struct vfio_group *group, *tmp;
+	struct device *dev;
+	int ret, minor;
+
+	group = kzalloc(sizeof(*group), GFP_KERNEL);
+	if (!group)
+		return ERR_PTR(-ENOMEM);
+
+	kref_init(&group->kref);
+	INIT_LIST_HEAD(&group->device_list);
+	mutex_init(&group->device_lock);
+	atomic_set(&group->container_users, 0);
+	group->iommu_group = iommu_group;
+
+	group->nb.notifier_call = vfio_iommu_group_notifier;
+
+	/*
+	 * blocking notifiers acquire a rwsem around registering and hold
+	 * it around callback.  Therefore, need to register outside of
+	 * vfio.group_lock to avoid A-B/B-A contention.  Our callback won't
+	 * do anything unless it can find the group in vfio.group_list, so
+	 * no harm in registering early.
+	 */
+	ret = iommu_group_register_notifier(iommu_group, &group->nb);
+	if (ret) {
+		kfree(group);
+		return ERR_PTR(ret);
+	}
+
+	mutex_lock(&vfio.group_lock);
+
+	minor = vfio_alloc_group_minor(group);
+	if (minor < 0) {
+		mutex_unlock(&vfio.group_lock);
+		kfree(group);
+		return ERR_PTR(minor);
+	}
+
+	/* Did we race creating this group? */
+	list_for_each_entry(tmp, &vfio.group_list, vfio_next) {
+		if (tmp->iommu_group == iommu_group) {
+			vfio_group_get(tmp);
+			vfio_free_group_minor(minor);
+			mutex_unlock(&vfio.group_lock);
+			kfree(group);
+			return tmp;
+		}
+	}
+
+	dev = device_create(vfio.class, NULL, MKDEV(MAJOR(vfio.devt), minor),
+			    group, "%d", iommu_group_id(iommu_group));
+	if (IS_ERR(dev)) {
+		vfio_free_group_minor(minor);
+		mutex_unlock(&vfio.group_lock);
+		kfree(group);
+		return (struct vfio_group *)dev; /* ERR_PTR */
+	}
+
+	group->minor = minor;
+	group->dev = dev;
+
+	list_add(&group->vfio_next, &vfio.group_list);
+
+	mutex_unlock(&vfio.group_lock);
+
+	return group;
+}
+
+static void vfio_group_release(struct kref *kref)
+{
+	struct vfio_group *group = container_of(kref, struct vfio_group, kref);
+
+	WARN_ON(!list_empty(&group->device_list));
+
+	device_destroy(vfio.class, MKDEV(MAJOR(vfio.devt), group->minor));
+	list_del(&group->vfio_next);
+	vfio_free_group_minor(group->minor);
+
+	mutex_unlock(&vfio.group_lock);
+
+	/*
+	 * Unregister outside of lock.  A spurious callback is harmless now
+	 * that the group is no longer in vfio.group_list.
+	 */
+	iommu_group_unregister_notifier(group->iommu_group, &group->nb);
+
+	kfree(group);
+}
+
+static void vfio_group_put(struct vfio_group *group)
+{
+	mutex_lock(&vfio.group_lock);
+	/*
+	 * Release needs to unlock to unregister the notifier, so only
+	 * unlock if not released.
+	 */
+	if (!kref_put(&group->kref, vfio_group_release))
+		mutex_unlock(&vfio.group_lock);
+}
+
+/* Assume group_lock or group reference is held */
+static void vfio_group_get(struct vfio_group *group)
+{
+	kref_get(&group->kref);
+}
+
+/*
+ * Not really a try as we will sleep for mutex, but we need to make
+ * sure the group pointer is valid under lock and get a reference.
+ */
+static struct vfio_group *vfio_group_try_get(struct vfio_group *group)
+{
+	struct vfio_group *target = group;
+
+	mutex_lock(&vfio.group_lock);
+	list_for_each_entry(group, &vfio.group_list, vfio_next) {
+		if (group == target) {
+			vfio_group_get(group);
+			mutex_unlock(&vfio.group_lock);
+			return group;
+		}
+	}
+	mutex_unlock(&vfio.group_lock);
+
+	return NULL;
+}
+
+static
+struct vfio_group *vfio_group_get_from_iommu(struct iommu_group *iommu_group)
+{
+	struct vfio_group *group;
+
+	mutex_lock(&vfio.group_lock);
+	list_for_each_entry(group, &vfio.group_list, vfio_next) {
+		if (group->iommu_group == iommu_group) {
+			vfio_group_get(group);
+			mutex_unlock(&vfio.group_lock);
+			return group;
+		}
+	}
+	mutex_unlock(&vfio.group_lock);
+
+	return NULL;
+}
+
+static struct vfio_group *vfio_group_get_from_minor(int minor)
+{
+	struct vfio_group *group;
+
+	mutex_lock(&vfio.group_lock);
+	group = idr_find(&vfio.group_idr, minor);
+	if (!group) {
+		mutex_unlock(&vfio.group_lock);
+		return NULL;
+	}
+	vfio_group_get(group);
+	mutex_unlock(&vfio.group_lock);
+
+	return group;
+}
+
+/**
+ * Device objects - create, release, get, put, search
+ */
+static
+struct vfio_device *vfio_group_create_device(struct vfio_group *group,
+					     struct device *dev,
+					     const struct vfio_device_ops *ops,
+					     void *device_data)
+{
+	struct vfio_device *device;
+	int ret;
+
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (!device)
+		return ERR_PTR(-ENOMEM);
+
+	kref_init(&device->kref);
+	device->dev = dev;
+	device->group = group;
+	device->ops = ops;
+	device->device_data = device_data;
+
+	ret = dev_set_drvdata(dev, device);
+	if (ret) {
+		kfree(device);
+		return ERR_PTR(ret);
+	}
+
+	/* No need to get group_lock, caller has group reference */
+	vfio_group_get(group);
+
+	mutex_lock(&group->device_lock);
+	list_add(&device->group_next, &group->device_list);
+	mutex_unlock(&group->device_lock);
+
+	return device;
+}
+
+static void vfio_device_release(struct kref *kref)
+{
+	struct vfio_device *device = container_of(kref,
+						  struct vfio_device, kref);
+	struct vfio_group *group = device->group;
+
+	mutex_lock(&group->device_lock);
+	list_del(&device->group_next);
+	mutex_unlock(&group->device_lock);
+
+	dev_set_drvdata(device->dev, NULL);
+
+	kfree(device);
+
+	/* vfio_del_group_dev may be waiting for this device */
+	wake_up(&vfio.release_q);
+}
+
+/* Device reference always implies a group reference */
+static void vfio_device_put(struct vfio_device *device)
+{
+	kref_put(&device->kref, vfio_device_release);
+	vfio_group_put(device->group);
+}
+
+static void vfio_device_get(struct vfio_device *device)
+{
+	vfio_group_get(device->group);
+	kref_get(&device->kref);
+}
+
+static struct vfio_device *vfio_group_get_device(struct vfio_group *group,
+						 struct device *dev)
+{
+	struct vfio_device *device;
+
+	mutex_lock(&group->device_lock);
+	list_for_each_entry(device, &group->device_list, group_next) {
+		if (device->dev == dev) {
+			vfio_device_get(device);
+			mutex_unlock(&group->device_lock);
+			return device;
+		}
+	}
+	mutex_unlock(&group->device_lock);
+	return NULL;
+}
+
+/*
+ * Whitelist some drivers that we know are safe (no dma) or just sit on
+ * a device.  It's not always practical to leave a device within a group
+ * driverless as it could get re-bound to something unsafe.
+ */
+static const char *vfio_driver_whitelist[] = { "pci-stub" };
+
+static bool vfio_whitelisted_driver(struct device_driver* drv)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vfio_driver_whitelist); i++) {
+		if (!strcmp(drv->name, vfio_driver_whitelist[i]))
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * A vfio group is viable for use by userspace if all devices are either
+ * driver-less or bound to a vfio or whitelisted driver.  We test the
+ * latter by the existence of a struct vfio_device matching the dev.
+ */
+static int vfio_dev_viable(struct device *dev, void *data)
+{
+	struct vfio_group *group = data;
+	struct vfio_device *device;
+
+	if (!dev->driver || vfio_whitelisted_driver(dev->driver))
+		return 0;
+
+	device = vfio_group_get_device(group, dev);
+	if (device) {
+		vfio_device_put(device);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * Async device support
+ */
+static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev)
+{
+	struct vfio_device *device;
+
+	/* Do we already know about it?  We shouldn't */
+	device = vfio_group_get_device(group, dev);
+	if (WARN_ON_ONCE(device)) {
+		vfio_device_put(device);
+		return 0;
+	}
+
+	/* Nothing to do for idle groups */
+	if (!atomic_read(&group->container_users))
+		return 0;
+
+	/* TODO Prevent device auto probing */
+	WARN("Device %s added to live group %d!\n", dev_name(dev),
+	     iommu_group_id(group->iommu_group));
+
+	return 0;
+}
+
+static int vfio_group_nb_del_dev(struct vfio_group *group, struct device *dev)
+{
+	struct vfio_device *device;
+
+	/*
+	 * Expect to fall out here.  If a device was in use, it would
+	 * have been bound to a vfio sub-driver, which would have blocked
+	 * in .remove at vfio_del_group_dev.  Sanity check that we no
+	 * longer track the device, so it's safe to remove.
+	 */
+	device = vfio_group_get_device(group, dev);
+	if (likely(!device))
+		return 0;
+
+	WARN("Device %s removed from live group %d!\n", dev_name(dev),
+	     iommu_group_id(group->iommu_group));
+
+	vfio_device_put(device);
+	return 0;
+}
+
+static int vfio_group_nb_verify(struct vfio_group *group, struct device *dev)
+{
+	/* We don't care what happens when the group isn't in use */
+	if (!atomic_read(&group->container_users))
+		return 0;
+
+	return vfio_dev_viable(dev, group);
+}
+
+static int vfio_iommu_group_notifier(struct notifier_block *nb,
+				     unsigned long action, void *data)
+{
+	struct vfio_group *group = container_of(nb, struct vfio_group, nb);
+	struct device *dev = data;
+
+	/*
+	 * Need to go through a group_lock lookup to get a reference or
+	 * we risk racing a group being removed.  Leave a WARN_ON for
+	 * debuging, but if the group no longer exists, a spurious notify
+	 * is harmless.
+	 */
+	group = vfio_group_try_get(group);
+	if (WARN_ON(!group))
+		return NOTIFY_OK;
+
+	switch (action) {
+	case IOMMU_GROUP_NOTIFY_ADD_DEVICE:
+		vfio_group_nb_add_dev(group, dev);
+		break;
+	case IOMMU_GROUP_NOTIFY_DEL_DEVICE:
+		vfio_group_nb_del_dev(group, dev);
+		break;
+	case IOMMU_GROUP_NOTIFY_BIND_DRIVER:
+		printk(KERN_DEBUG
+		       "%s: Device %s, group %d binding to driver\n", __func__,
+		      dev_name(dev), iommu_group_id(group->iommu_group));
+		break;
+	case IOMMU_GROUP_NOTIFY_BOUND_DRIVER:
+		printk(KERN_DEBUG
+		       "%s: Device %s, group %d bound to driver %s\n", __func__,
+		       dev_name(dev), iommu_group_id(group->iommu_group),
+		       dev->driver->name);
+		BUG_ON(vfio_group_nb_verify(group, dev));
+		break;
+	case IOMMU_GROUP_NOTIFY_UNBIND_DRIVER:
+		printk(KERN_DEBUG
+		       "%s: Device %s, group %d unbinding from driver %s\n",
+		       __func__, dev_name(dev),
+		       iommu_group_id(group->iommu_group), dev->driver->name);
+		break;
+	case IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER:
+		printk(KERN_DEBUG
+		       "%s: Device %s, group %d unbound from driver\n",
+		       __func__, dev_name(dev),
+		       iommu_group_id(group->iommu_group));
+		/*
+		 * XXX An unbound device in a live group is ok, but we'd
+		 * really like to avoid the above BUG_ON by preventing other
+		 * drivers from binding to it.  Once that occurs, we have to
+		 * stop the system to maintain isolation.  At a minimum, we'd
+		 * want a toggle to disable driver auto probe for this device.
+		 */
+		break;
+	}
+
+	vfio_group_put(group);
+	return NOTIFY_OK;
+}
+
+/**
+ * VFIO driver API
+ */
+int vfio_add_group_dev(struct device *dev,
+		       const struct vfio_device_ops *ops, void *device_data)
+{
+	struct iommu_group *iommu_group;
+	struct vfio_group *group;
+	struct vfio_device *device;
+
+	iommu_group = iommu_group_get(dev);
+	if (!iommu_group)
+		return -EINVAL;
+
+	group = vfio_group_get_from_iommu(iommu_group);
+	if (!group) {
+		group = vfio_create_group(iommu_group);
+		if (IS_ERR(group)) {
+			iommu_group_put(iommu_group);
+			return PTR_ERR(group);
+		}
+	}
+
+	device = vfio_group_get_device(group, dev);
+	if (device) {
+		WARN(1, "Device %s already exists on group %d\n",
+		     dev_name(dev), iommu_group_id(iommu_group));
+		vfio_device_put(device);
+		vfio_group_put(group);
+		iommu_group_put(iommu_group);
+		return -EBUSY;
+	}
+
+	device = vfio_group_create_device(group, dev, ops, device_data);
+	if (IS_ERR(device)) {
+		vfio_group_put(group);
+		iommu_group_put(iommu_group);
+		return PTR_ERR(device);
+	}
+
+	/*
+	 * Added device holds reference to iommu_group and vfio_device
+	 * (which in turn holds reference to vfio_group).  Drop extra
+	 * group reference used while acquiring device.
+	 */
+	vfio_group_put(group);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vfio_add_group_dev);
+
+/* Test whether a struct device is present in our tracking */
+static bool vfio_dev_present(struct device *dev)
+{
+	struct iommu_group *iommu_group;
+	struct vfio_group *group;
+	struct vfio_device *device;
+
+	iommu_group = iommu_group_get(dev);
+	if (!iommu_group)
+		return false;
+
+	group = vfio_group_get_from_iommu(iommu_group);
+	if (!group) {
+		iommu_group_put(iommu_group);
+		return false;
+	}
+
+	device = vfio_group_get_device(group, dev);
+	if (!device) {
+		vfio_group_put(group);
+		iommu_group_put(iommu_group);
+		return false;
+	}
+
+	vfio_device_put(device);
+	vfio_group_put(group);
+	iommu_group_put(iommu_group);
+	return true;
+}
+
+/*
+ * Decrement the device reference count and wait for the device to be
+ * removed.  Open file descriptors for the device... */
+void *vfio_del_group_dev(struct device *dev)
+{
+	struct vfio_device *device = dev_get_drvdata(dev);
+	struct vfio_group *group = device->group;
+	struct iommu_group *iommu_group = group->iommu_group;
+	void *device_data = device->device_data;
+
+	vfio_device_put(device);
+
+	/* TODO send a signal to encourage this to be released */
+	wait_event(vfio.release_q, !vfio_dev_present(dev));
+
+	iommu_group_put(iommu_group);
+
+	return device_data;
+}
+EXPORT_SYMBOL_GPL(vfio_del_group_dev);
+
+/**
+ * VFIO base fd, /dev/vfio/vfio
+ */
+static long vfio_ioctl_check_extension(struct vfio_container *container,
+				       unsigned long arg)
+{
+	struct vfio_iommu_driver *driver = container->iommu_driver;
+	long ret = 0;
+
+	switch (arg) {
+		/* No base extensions yet */
+	default:
+		/*
+		 * If no driver is set, poll all registered drivers for
+		 * extensions and return the first positive result.  If
+		 * a driver is already set, further queries will be passed
+		 * only to that driver.
+		 */
+		if (!driver) {
+			mutex_lock(&vfio.iommu_drivers_lock);
+			list_for_each_entry(driver, &vfio.iommu_drivers_list,
+					    vfio_next) {
+				if (!try_module_get(driver->ops->owner))
+					continue;
+
+				ret = driver->ops->ioctl(NULL,
+							 VFIO_CHECK_EXTENSION,
+							 arg);
+				module_put(driver->ops->owner);
+				if (ret > 0)
+					break;
+			}
+			mutex_unlock(&vfio.iommu_drivers_lock);
+		} else
+			ret = driver->ops->ioctl(container->iommu_data,
+						 VFIO_CHECK_EXTENSION, arg);
+	}
+
+	return ret;
+}
+
+/* hold container->group_lock */
+static int __vfio_container_attach_groups(struct vfio_container *container,
+					  struct vfio_iommu_driver *driver,
+					  void *data)
+{
+	struct vfio_group *group;
+	int ret = -ENODEV;
+
+	list_for_each_entry(group, &container->group_list, container_next) {
+		ret = driver->ops->attach_group(data, group->iommu_group);
+		if (ret)
+			goto unwind;
+	}
+
+	return ret;
+
+unwind:
+	list_for_each_entry_continue_reverse(group, &container->group_list,
+					     container_next) {
+		driver->ops->detach_group(data, group->iommu_group);
+	}
+
+	return ret;
+}
+
+static long vfio_ioctl_set_iommu(struct vfio_container *container,
+				 unsigned long arg)
+{
+	struct vfio_iommu_driver *driver;
+	long ret = -ENODEV;
+
+	mutex_lock(&container->group_lock);
+
+	/*
+	 * The container is designed to be an unprivileged interface while
+	 * the group can be assigned to specific users.  Therefore, only by
+	 * adding a group to a container does the user get the privilege of
+	 * enabling the iommu, which may allocate finite resources.  There
+	 * is no unset_iommu, but by removing all the groups from a container,
+	 * the container is deprivileged and returns to an unset state.
+	 */
+	if (list_empty(&container->group_list) || container->iommu_driver) {
+		mutex_unlock(&container->group_lock);
+		return -EINVAL;
+	}
+
+	mutex_lock(&vfio.iommu_drivers_lock);
+	list_for_each_entry(driver, &vfio.iommu_drivers_list, vfio_next) {
+		void *data;
+
+		if (!try_module_get(driver->ops->owner))
+			continue;
+
+		/*
+		 * The arg magic for SET_IOMMU is the same as CHECK_EXTENSION,
+		 * so test which iommu driver reported support for this
+		 * extension and call open on them.  We also pass them the
+		 * magic, allowing a single driver to support multiple
+		 * interfaces if they'd like.
+		 */
+		if (driver->ops->ioctl(NULL, VFIO_CHECK_EXTENSION, arg) <= 0) {
+			module_put(driver->ops->owner);
+			continue;
+		}
+
+		/* module reference holds the driver we're working on */
+		mutex_unlock(&vfio.iommu_drivers_lock);
+
+		data = driver->ops->open(arg);
+		if (IS_ERR(data)) {
+			ret = PTR_ERR(data);
+			module_put(driver->ops->owner);
+			goto skip_drivers_unlock;
+		}
+
+		ret = __vfio_container_attach_groups(container, driver, data);
+		if (!ret) {
+			container->iommu_driver = driver;
+			container->iommu_data = data;
+		} else {
+			driver->ops->release(data);
+			module_put(driver->ops->owner);
+		}
+
+		goto skip_drivers_unlock;
+	}
+
+	mutex_unlock(&vfio.iommu_drivers_lock);
+skip_drivers_unlock:
+	mutex_unlock(&container->group_lock);
+
+	return ret;
+}
+
+static long vfio_fops_unl_ioctl(struct file *filep,
+				unsigned int cmd, unsigned long arg)
+{
+	struct vfio_container *container = filep->private_data;
+	struct vfio_iommu_driver *driver;
+	void *data;
+	long ret = -EINVAL;
+
+	if (!container)
+		return ret;
+
+	driver = container->iommu_driver;
+	data = container->iommu_data;
+
+	switch (cmd) {
+	case VFIO_GET_API_VERSION:
+		ret = VFIO_API_VERSION;
+		break;
+	case VFIO_CHECK_EXTENSION:
+		ret = vfio_ioctl_check_extension(container, arg);
+		break;
+	case VFIO_SET_IOMMU:
+		ret = vfio_ioctl_set_iommu(container, arg);
+		break;
+	default:
+		if (driver) /* passthrough all unrecognized ioctls */
+			ret = driver->ops->ioctl(data, cmd, arg);
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long vfio_fops_compat_ioctl(struct file *filep,
+				   unsigned int cmd, unsigned long arg)
+{
+	arg = (unsigned long)compat_ptr(arg);
+	return vfio_fops_unl_ioctl(filep, cmd, arg);
+}
+#endif	/* CONFIG_COMPAT */
+
+static int vfio_fops_open(struct inode *inode, struct file *filep)
+{
+	struct vfio_container *container;
+
+	container = kzalloc(sizeof(*container), GFP_KERNEL);
+	if (!container)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&container->group_list);
+	mutex_init(&container->group_lock);
+	kref_init(&container->kref);
+
+	filep->private_data = container;
+
+	return 0;
+}
+
+static int vfio_fops_release(struct inode *inode, struct file *filep)
+{
+	struct vfio_container *container = filep->private_data;
+
+	filep->private_data = NULL;
+
+	vfio_container_put(container);
+
+	return 0;
+}
+
+/*
+ * Once an iommu driver is set, we optionally pass read/write/mmap
+ * on to the driver, allowing management interfaces beyond ioctl.
+ */
+static ssize_t vfio_fops_read(struct file *filep, char __user *buf,
+			      size_t count, loff_t *ppos)
+{
+	struct vfio_container *container = filep->private_data;
+	struct vfio_iommu_driver *driver = container->iommu_driver;
+
+	if (unlikely(!driver || !driver->ops->read))
+		return -EINVAL;
+
+	return driver->ops->read(container->iommu_data, buf, count, ppos);
+}
+
+static ssize_t vfio_fops_write(struct file *filep, const char __user *buf,
+			       size_t count, loff_t *ppos)
+{
+	struct vfio_container *container = filep->private_data;
+	struct vfio_iommu_driver *driver = container->iommu_driver;
+
+	if (unlikely(!driver || !driver->ops->write))
+		return -EINVAL;
+
+	return driver->ops->write(container->iommu_data, buf, count, ppos);
+}
+
+static int vfio_fops_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+	struct vfio_container *container = filep->private_data;
+	struct vfio_iommu_driver *driver = container->iommu_driver;
+
+	if (unlikely(!driver || !driver->ops->mmap))
+		return -EINVAL;
+
+	return driver->ops->mmap(container->iommu_data, vma);
+}
+
+static const struct file_operations vfio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= vfio_fops_open,
+	.release	= vfio_fops_release,
+	.read		= vfio_fops_read,
+	.write		= vfio_fops_write,
+	.unlocked_ioctl	= vfio_fops_unl_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= vfio_fops_compat_ioctl,
+#endif
+	.mmap		= vfio_fops_mmap,
+};
+
+/**
+ * VFIO Group fd, /dev/vfio/$GROUP
+ */
+static void __vfio_group_unset_container(struct vfio_group *group)
+{
+	struct vfio_container *container = group->container;
+	struct vfio_iommu_driver *driver;
+
+	mutex_lock(&container->group_lock);
+
+	driver = container->iommu_driver;
+	if (driver)
+		driver->ops->detach_group(container->iommu_data,
+					  group->iommu_group);
+
+	group->container = NULL;
+	list_del(&group->container_next);
+
+	/* Detaching the last group deprivileges a container, remove iommu */
+	if (driver && list_empty(&container->group_list)) {
+		driver->ops->release(container->iommu_data);
+		module_put(driver->ops->owner);
+		container->iommu_driver = NULL;
+		container->iommu_data = NULL;
+	}
+
+	mutex_unlock(&container->group_lock);
+
+	vfio_container_put(container);
+}
+
+/*
+ * VFIO_GROUP_UNSET_CONTAINER should fail if there are other users or
+ * if there was no container to unset.  Since the ioctl is called on
+ * the group, we know that still exists, therefore the only valid
+ * transition here is 1->0.
+ */
+static int vfio_group_unset_container(struct vfio_group *group)
+{
+	int users = atomic_cmpxchg(&group->container_users, 1, 0);
+
+	if (!users)
+		return -EINVAL;
+	if (users != 1)
+		return -EBUSY;
+
+	__vfio_group_unset_container(group);
+
+	return 0;
+}
+
+/*
+ * When removing container users, anything that removes the last user
+ * implicitly removes the group from the container.  That is, if the
+ * group file descriptor is closed, as well as any device file descriptors,
+ * the group is free.
+ */
+static void vfio_group_try_dissolve_container(struct vfio_group *group)
+{
+	if (0 == atomic_dec_if_positive(&group->container_users))
+		__vfio_group_unset_container(group);
+}
+
+static int vfio_group_set_container(struct vfio_group *group, int container_fd)
+{
+	struct file *filep;
+	struct vfio_container *container;
+	struct vfio_iommu_driver *driver;
+	int ret = 0;
+
+	if (atomic_read(&group->container_users))
+		return -EINVAL;
+
+	filep = fget(container_fd);
+	if (!filep)
+		return -EBADF;
+
+	/* Sanity check, is this really our fd? */
+	if (filep->f_op != &vfio_fops) {
+		fput(filep);
+		return -EINVAL;
+	}
+
+	container = filep->private_data;
+	WARN_ON(!container); /* fget ensures we don't race vfio_release */
+
+	mutex_lock(&container->group_lock);
+
+	driver = container->iommu_driver;
+	if (driver) {
+		ret = driver->ops->attach_group(container->iommu_data,
+						group->iommu_group);
+		if (ret)
+			goto unlock_out;
+	}
+
+	group->container = container;
+	list_add(&group->container_next, &container->group_list);
+
+	/* Get a reference on the container and mark a user within the group */
+	vfio_container_get(container);
+	atomic_inc(&group->container_users);
+
+unlock_out:
+	mutex_unlock(&container->group_lock);
+	fput(filep);
+
+	return ret;
+}
+
+static bool vfio_group_viable(struct vfio_group *group)
+{
+	return (iommu_group_for_each_dev(group->iommu_group,
+					 group, vfio_dev_viable) == 0);
+}
+
+static const struct file_operations vfio_device_fops;
+
+static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
+{
+	struct vfio_device *device;
+	struct file *filep;
+	int ret = -ENODEV;
+
+	if (0 == atomic_read(&group->container_users) ||
+	    !group->container->iommu_driver || !vfio_group_viable(group))
+		return -EINVAL;
+
+	mutex_lock(&group->device_lock);
+	list_for_each_entry(device, &group->device_list, group_next) {
+		if (strcmp(dev_name(device->dev), buf))
+			continue;
+
+		ret = device->ops->open(device->device_data);
+		if (ret)
+			break;
+		/*
+		 * We can't use anon_inode_getfd() because we need to modify
+		 * the f_mode flags directly to allow more than just ioctls
+		 */
+		ret = get_unused_fd();
+		if (ret < 0) {
+			device->ops->release(device->device_data);
+			break;
+		}
+
+		filep = anon_inode_getfile("[vfio-device]", &vfio_device_fops,
+					   device, O_RDWR);
+		if (IS_ERR(filep)) {
+			put_unused_fd(ret);
+			ret = PTR_ERR(filep);
+			device->ops->release(device->device_data);
+			break;
+		}
+
+		/*
+		 * TODO: add an anon_inode interface to do this.
+		 * Appears to be missing by lack of need rather than
+		 * explicitly prevented.  Now there's need.
+		 */
+		filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+
+		fd_install(ret, filep);
+
+		vfio_device_get(device);
+		atomic_inc(&group->container_users);
+		break;
+	}
+	mutex_unlock(&group->device_lock);
+
+	return ret;
+}
+
+static long vfio_group_fops_unl_ioctl(struct file *filep,
+				      unsigned int cmd, unsigned long arg)
+{
+	struct vfio_group *group = filep->private_data;
+	long ret = -ENOTTY;
+
+	switch (cmd) {
+	case VFIO_GROUP_GET_STATUS:
+	{
+		struct vfio_group_status status;
+		unsigned long minsz;
+
+		minsz = offsetofend(struct vfio_group_status, flags);
+
+		if (copy_from_user(&status, (void __user *)arg, minsz))
+			return -EFAULT;
+
+		if (status.argsz < minsz)
+			return -EINVAL;
+
+		status.flags = 0;
+
+		if (vfio_group_viable(group))
+			status.flags |= VFIO_GROUP_FLAGS_VIABLE;
+
+		if (group->container)
+			status.flags |= VFIO_GROUP_FLAGS_CONTAINER_SET;
+
+		ret = copy_to_user((void __user *)arg, &status, minsz);
+
+		break;
+	}
+	case VFIO_GROUP_SET_CONTAINER:
+	{
+		int fd;
+
+		if (get_user(fd, (int __user *)arg))
+			return -EFAULT;
+
+		if (fd < 0)
+			return -EINVAL;
+
+		ret = vfio_group_set_container(group, fd);
+		break;
+	}
+	case VFIO_GROUP_UNSET_CONTAINER:
+		ret = vfio_group_unset_container(group);
+		break;
+	case VFIO_GROUP_GET_DEVICE_FD:
+	{
+		char *buf;
+
+		buf = strndup_user((const char __user *)arg, PAGE_SIZE);
+		if (IS_ERR(buf))
+			return PTR_ERR(buf);
+
+		ret = vfio_group_get_device_fd(group, buf);
+		kfree(buf);
+		break;
+	}
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long vfio_group_fops_compat_ioctl(struct file *filep,
+					 unsigned int cmd, unsigned long arg)
+{
+	arg = (unsigned long)compat_ptr(arg);
+	return vfio_group_fops_unl_ioctl(filep, cmd, arg);
+}
+#endif	/* CONFIG_COMPAT */
+
+static int vfio_group_fops_open(struct inode *inode, struct file *filep)
+{
+	struct vfio_group *group;
+
+	group = vfio_group_get_from_minor(iminor(inode));
+	if (!group)
+		return -ENODEV;
+
+	if (group->container) {
+		vfio_group_put(group);
+		return -EBUSY;
+	}
+
+	filep->private_data = group;
+
+	return 0;
+}
+
+static int vfio_group_fops_release(struct inode *inode, struct file *filep)
+{
+	struct vfio_group *group = filep->private_data;
+
+	filep->private_data = NULL;
+
+	vfio_group_try_dissolve_container(group);
+
+	vfio_group_put(group);
+
+	return 0;
+}
+
+static const struct file_operations vfio_group_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= vfio_group_fops_unl_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= vfio_group_fops_compat_ioctl,
+#endif
+	.open		= vfio_group_fops_open,
+	.release	= vfio_group_fops_release,
+};
+
+/**
+ * VFIO Device fd
+ */
+static int vfio_device_fops_release(struct inode *inode, struct file *filep)
+{
+	struct vfio_device *device = filep->private_data;
+
+	device->ops->release(device->device_data);
+
+	vfio_group_try_dissolve_container(device->group);
+
+	vfio_device_put(device);
+
+	return 0;
+}
+
+static long vfio_device_fops_unl_ioctl(struct file *filep,
+				       unsigned int cmd, unsigned long arg)
+{
+	struct vfio_device *device = filep->private_data;
+
+	if (unlikely(!device->ops->ioctl))
+		return -EINVAL;
+
+	return device->ops->ioctl(device->device_data, cmd, arg);
+}
+
+static ssize_t vfio_device_fops_read(struct file *filep, char __user *buf,
+				     size_t count, loff_t *ppos)
+{
+	struct vfio_device *device = filep->private_data;
+
+	if (unlikely(!device->ops->read))
+		return -EINVAL;
+
+	return device->ops->read(device->device_data, buf, count, ppos);
+}
+
+static ssize_t vfio_device_fops_write(struct file *filep,
+				      const char __user *buf,
+				      size_t count, loff_t *ppos)
+{
+	struct vfio_device *device = filep->private_data;
+
+	if (unlikely(!device->ops->write))
+		return -EINVAL;
+
+	return device->ops->write(device->device_data, buf, count, ppos);
+}
+
+static int vfio_device_fops_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+	struct vfio_device *device = filep->private_data;
+
+	if (unlikely(!device->ops->mmap))
+		return -EINVAL;
+
+	return device->ops->mmap(device->device_data, vma);
+}
+
+#ifdef CONFIG_COMPAT
+static long vfio_device_fops_compat_ioctl(struct file *filep,
+					  unsigned int cmd, unsigned long arg)
+{
+	arg = (unsigned long)compat_ptr(arg);
+	return vfio_device_fops_unl_ioctl(filep, cmd, arg);
+}
+#endif	/* CONFIG_COMPAT */
+
+static const struct file_operations vfio_device_fops = {
+	.owner		= THIS_MODULE,
+	.release	= vfio_device_fops_release,
+	.read		= vfio_device_fops_read,
+	.write		= vfio_device_fops_write,
+	.unlocked_ioctl	= vfio_device_fops_unl_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= vfio_device_fops_compat_ioctl,
+#endif
+	.mmap		= vfio_device_fops_mmap,
+};
+
+/**
+ * Module/class support
+ */
+static char *vfio_devnode(struct device *dev, umode_t *mode)
+{
+	return kasprintf(GFP_KERNEL, "vfio/%s", dev_name(dev));
+}
+
+static int __init vfio_init(void)
+{
+	int ret;
+
+	idr_init(&vfio.group_idr);
+	mutex_init(&vfio.group_lock);
+	mutex_init(&vfio.iommu_drivers_lock);
+	INIT_LIST_HEAD(&vfio.group_list);
+	INIT_LIST_HEAD(&vfio.iommu_drivers_list);
+	init_waitqueue_head(&vfio.release_q);
+
+	vfio.class = class_create(THIS_MODULE, "vfio");
+	if (IS_ERR(vfio.class)) {
+		ret = PTR_ERR(vfio.class);
+		goto err_class;
+	}
+
+	vfio.class->devnode = vfio_devnode;
+
+	ret = alloc_chrdev_region(&vfio.devt, 0, MINORMASK, "vfio");
+	if (ret)
+		goto err_base_chrdev;
+
+	cdev_init(&vfio.cdev, &vfio_fops);
+	ret = cdev_add(&vfio.cdev, vfio.devt, 1);
+	if (ret)
+		goto err_base_cdev;
+
+	vfio.dev = device_create(vfio.class, NULL, vfio.devt, NULL, "vfio");
+	if (IS_ERR(vfio.dev)) {
+		ret = PTR_ERR(vfio.dev);
+		goto err_base_dev;
+	}
+
+	/* /dev/vfio/$GROUP */
+	cdev_init(&vfio.group_cdev, &vfio_group_fops);
+	ret = cdev_add(&vfio.group_cdev,
+		       MKDEV(MAJOR(vfio.devt), 1), MINORMASK - 1);
+	if (ret)
+		goto err_groups_cdev;
+
+	pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	/*
+	 * Attempt to load known iommu-drivers.  This gives us a working
+	 * environment without the user needing to explicitly load iommu
+	 * drivers.
+	 */
+	request_module_nowait("vfio_iommu_type1");
+
+	return 0;
+
+err_groups_cdev:
+	device_destroy(vfio.class, vfio.devt);
+err_base_dev:
+	cdev_del(&vfio.cdev);
+err_base_cdev:
+	unregister_chrdev_region(vfio.devt, MINORMASK);
+err_base_chrdev:
+	class_destroy(vfio.class);
+	vfio.class = NULL;
+err_class:
+	return ret;
+}
+
+static void __exit vfio_cleanup(void)
+{
+	WARN_ON(!list_empty(&vfio.group_list));
+
+	idr_destroy(&vfio.group_idr);
+	cdev_del(&vfio.group_cdev);
+	device_destroy(vfio.class, vfio.devt);
+	cdev_del(&vfio.cdev);
+	unregister_chrdev_region(vfio.devt, MINORMASK);
+	class_destroy(vfio.class);
+	vfio.class = NULL;
+}
+
+module_init(vfio_init);
+module_exit(vfio_cleanup);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
new file mode 100644
index 0000000..5bb6fad
--- /dev/null
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -0,0 +1,754 @@
+/*
+ * VFIO: IOMMU DMA mapping support for Type1 IOMMU
+ *
+ * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
+ *     Author: Alex Williamson <alex.williamson@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.
+ *
+ * Derived from original vfio:
+ * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
+ * Author: Tom Lyon, pugs@cisco.com
+ *
+ * We arbitrarily define a Type1 IOMMU as one matching the below code.
+ * It could be called the x86 IOMMU as it's designed for AMD-Vi & Intel
+ * VT-d, but that makes it harder to re-use as theoretically anyone
+ * implementing a similar IOMMU could make use of this.  We expect the
+ * IOMMU to support the IOMMU API and have few to no restrictions around
+ * the IOVA range that can be mapped.  The Type1 IOMMU is currently
+ * optimized for relatively static mappings of a userspace process with
+ * userpsace pages pinned into memory.  We also assume devices and IOMMU
+ * domains are PCI based as the IOMMU API is still centered around a
+ * device/bus interface rather than a group interface.
+ */
+
+#include <linux/compat.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/iommu.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/pci.h>		/* pci_bus_type */
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/vfio.h>
+#include <linux/workqueue.h>
+
+#define DRIVER_VERSION  "0.2"
+#define DRIVER_AUTHOR   "Alex Williamson <alex.williamson@redhat.com>"
+#define DRIVER_DESC     "Type1 IOMMU driver for VFIO"
+
+static bool allow_unsafe_interrupts;
+module_param_named(allow_unsafe_interrupts,
+		   allow_unsafe_interrupts, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(allow_unsafe_interrupts,
+		 "Enable VFIO IOMMU support for on platforms without interrupt remapping support.");
+
+struct vfio_iommu {
+	struct iommu_domain	*domain;
+	struct mutex		lock;
+	struct list_head	dma_list;
+	struct list_head	group_list;
+	bool			cache;
+};
+
+struct vfio_dma {
+	struct list_head	next;
+	dma_addr_t		iova;		/* Device address */
+	unsigned long		vaddr;		/* Process virtual addr */
+	long			npage;		/* Number of pages */
+	int			prot;		/* IOMMU_READ/WRITE */
+};
+
+struct vfio_group {
+	struct iommu_group	*iommu_group;
+	struct list_head	next;
+};
+
+/*
+ * This code handles mapping and unmapping of user data buffers
+ * into DMA'ble space using the IOMMU
+ */
+
+#define NPAGE_TO_SIZE(npage)	((size_t)(npage) << PAGE_SHIFT)
+
+struct vwork {
+	struct mm_struct	*mm;
+	long			npage;
+	struct work_struct	work;
+};
+
+/* delayed decrement/increment for locked_vm */
+static void vfio_lock_acct_bg(struct work_struct *work)
+{
+	struct vwork *vwork = container_of(work, struct vwork, work);
+	struct mm_struct *mm;
+
+	mm = vwork->mm;
+	down_write(&mm->mmap_sem);
+	mm->locked_vm += vwork->npage;
+	up_write(&mm->mmap_sem);
+	mmput(mm);
+	kfree(vwork);
+}
+
+static void vfio_lock_acct(long npage)
+{
+	struct vwork *vwork;
+	struct mm_struct *mm;
+
+	if (!current->mm)
+		return; /* process exited */
+
+	if (down_write_trylock(&current->mm->mmap_sem)) {
+		current->mm->locked_vm += npage;
+		up_write(&current->mm->mmap_sem);
+		return;
+	}
+
+	/*
+	 * Couldn't get mmap_sem lock, so must setup to update
+	 * mm->locked_vm later. If locked_vm were atomic, we
+	 * wouldn't need this silliness
+	 */
+	vwork = kmalloc(sizeof(struct vwork), GFP_KERNEL);
+	if (!vwork)
+		return;
+	mm = get_task_mm(current);
+	if (!mm) {
+		kfree(vwork);
+		return;
+	}
+	INIT_WORK(&vwork->work, vfio_lock_acct_bg);
+	vwork->mm = mm;
+	vwork->npage = npage;
+	schedule_work(&vwork->work);
+}
+
+/*
+ * Some mappings aren't backed by a struct page, for example an mmap'd
+ * MMIO range for our own or another device.  These use a different
+ * pfn conversion and shouldn't be tracked as locked pages.
+ */
+static bool is_invalid_reserved_pfn(unsigned long pfn)
+{
+	if (pfn_valid(pfn)) {
+		bool reserved;
+		struct page *tail = pfn_to_page(pfn);
+		struct page *head = compound_trans_head(tail);
+		reserved = !!(PageReserved(head));
+		if (head != tail) {
+			/*
+			 * "head" is not a dangling pointer
+			 * (compound_trans_head takes care of that)
+			 * but the hugepage may have been split
+			 * from under us (and we may not hold a
+			 * reference count on the head page so it can
+			 * be reused before we run PageReferenced), so
+			 * we've to check PageTail before returning
+			 * what we just read.
+			 */
+			smp_rmb();
+			if (PageTail(tail))
+				return reserved;
+		}
+		return PageReserved(tail);
+	}
+
+	return true;
+}
+
+static int put_pfn(unsigned long pfn, int prot)
+{
+	if (!is_invalid_reserved_pfn(pfn)) {
+		struct page *page = pfn_to_page(pfn);
+		if (prot & IOMMU_WRITE)
+			SetPageDirty(page);
+		put_page(page);
+		return 1;
+	}
+	return 0;
+}
+
+/* Unmap DMA region */
+static long __vfio_dma_do_unmap(struct vfio_iommu *iommu, dma_addr_t iova,
+			     long npage, int prot)
+{
+	long i, unlocked = 0;
+
+	for (i = 0; i < npage; i++, iova += PAGE_SIZE) {
+		unsigned long pfn;
+
+		pfn = iommu_iova_to_phys(iommu->domain, iova) >> PAGE_SHIFT;
+		if (pfn) {
+			iommu_unmap(iommu->domain, iova, PAGE_SIZE);
+			unlocked += put_pfn(pfn, prot);
+		}
+	}
+	return unlocked;
+}
+
+static void vfio_dma_unmap(struct vfio_iommu *iommu, dma_addr_t iova,
+			   long npage, int prot)
+{
+	long unlocked;
+
+	unlocked = __vfio_dma_do_unmap(iommu, iova, npage, prot);
+	vfio_lock_acct(-unlocked);
+}
+
+static int vaddr_get_pfn(unsigned long vaddr, int prot, unsigned long *pfn)
+{
+	struct page *page[1];
+	struct vm_area_struct *vma;
+	int ret = -EFAULT;
+
+	if (get_user_pages_fast(vaddr, 1, !!(prot & IOMMU_WRITE), page) == 1) {
+		*pfn = page_to_pfn(page[0]);
+		return 0;
+	}
+
+	down_read(&current->mm->mmap_sem);
+
+	vma = find_vma_intersection(current->mm, vaddr, vaddr + 1);
+
+	if (vma && vma->vm_flags & VM_PFNMAP) {
+		*pfn = ((vaddr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+		if (is_invalid_reserved_pfn(*pfn))
+			ret = 0;
+	}
+
+	up_read(&current->mm->mmap_sem);
+
+	return ret;
+}
+
+/* Map DMA region */
+static int __vfio_dma_map(struct vfio_iommu *iommu, dma_addr_t iova,
+			  unsigned long vaddr, long npage, int prot)
+{
+	dma_addr_t start = iova;
+	long i, locked = 0;
+	int ret;
+
+	/* Verify that pages are not already mapped */
+	for (i = 0; i < npage; i++, iova += PAGE_SIZE)
+		if (iommu_iova_to_phys(iommu->domain, iova))
+			return -EBUSY;
+
+	iova = start;
+
+	if (iommu->cache)
+		prot |= IOMMU_CACHE;
+
+	/*
+	 * XXX We break mappings into pages and use get_user_pages_fast to
+	 * pin the pages in memory.  It's been suggested that mlock might
+	 * provide a more efficient mechanism, but nothing prevents the
+	 * user from munlocking the pages, which could then allow the user
+	 * access to random host memory.  We also have no guarantee from the
+	 * IOMMU API that the iommu driver can unmap sub-pages of previous
+	 * mappings.  This means we might lose an entire range if a single
+	 * page within it is unmapped.  Single page mappings are inefficient,
+	 * but provide the most flexibility for now.
+	 */
+	for (i = 0; i < npage; i++, iova += PAGE_SIZE, vaddr += PAGE_SIZE) {
+		unsigned long pfn = 0;
+
+		ret = vaddr_get_pfn(vaddr, prot, &pfn);
+		if (ret) {
+			__vfio_dma_do_unmap(iommu, start, i, prot);
+			return ret;
+		}
+
+		/*
+		 * Only add actual locked pages to accounting
+		 * XXX We're effectively marking a page locked for every
+		 * IOVA page even though it's possible the user could be
+		 * backing multiple IOVAs with the same vaddr.  This over-
+		 * penalizes the user process, but we currently have no
+		 * easy way to do this properly.
+		 */
+		if (!is_invalid_reserved_pfn(pfn))
+			locked++;
+
+		ret = iommu_map(iommu->domain, iova,
+				(phys_addr_t)pfn << PAGE_SHIFT,
+				PAGE_SIZE, prot);
+		if (ret) {
+			/* Back out mappings on error */
+			put_pfn(pfn, prot);
+			__vfio_dma_do_unmap(iommu, start, i, prot);
+			return ret;
+		}
+	}
+	vfio_lock_acct(locked);
+	return 0;
+}
+
+static inline bool ranges_overlap(dma_addr_t start1, size_t size1,
+				  dma_addr_t start2, size_t size2)
+{
+	if (start1 < start2)
+		return (start2 - start1 < size1);
+	else if (start2 < start1)
+		return (start1 - start2 < size2);
+	return (size1 > 0 && size2 > 0);
+}
+
+static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
+						dma_addr_t start, size_t size)
+{
+	struct vfio_dma *dma;
+
+	list_for_each_entry(dma, &iommu->dma_list, next) {
+		if (ranges_overlap(dma->iova, NPAGE_TO_SIZE(dma->npage),
+				   start, size))
+			return dma;
+	}
+	return NULL;
+}
+
+static long vfio_remove_dma_overlap(struct vfio_iommu *iommu, dma_addr_t start,
+				    size_t size, struct vfio_dma *dma)
+{
+	struct vfio_dma *split;
+	long npage_lo, npage_hi;
+
+	/* Existing dma region is completely covered, unmap all */
+	if (start <= dma->iova &&
+	    start + size >= dma->iova + NPAGE_TO_SIZE(dma->npage)) {
+		vfio_dma_unmap(iommu, dma->iova, dma->npage, dma->prot);
+		list_del(&dma->next);
+		npage_lo = dma->npage;
+		kfree(dma);
+		return npage_lo;
+	}
+
+	/* Overlap low address of existing range */
+	if (start <= dma->iova) {
+		size_t overlap;
+
+		overlap = start + size - dma->iova;
+		npage_lo = overlap >> PAGE_SHIFT;
+
+		vfio_dma_unmap(iommu, dma->iova, npage_lo, dma->prot);
+		dma->iova += overlap;
+		dma->vaddr += overlap;
+		dma->npage -= npage_lo;
+		return npage_lo;
+	}
+
+	/* Overlap high address of existing range */
+	if (start + size >= dma->iova + NPAGE_TO_SIZE(dma->npage)) {
+		size_t overlap;
+
+		overlap = dma->iova + NPAGE_TO_SIZE(dma->npage) - start;
+		npage_hi = overlap >> PAGE_SHIFT;
+
+		vfio_dma_unmap(iommu, start, npage_hi, dma->prot);
+		dma->npage -= npage_hi;
+		return npage_hi;
+	}
+
+	/* Split existing */
+	npage_lo = (start - dma->iova) >> PAGE_SHIFT;
+	npage_hi = dma->npage - (size >> PAGE_SHIFT) - npage_lo;
+
+	split = kzalloc(sizeof *split, GFP_KERNEL);
+	if (!split)
+		return -ENOMEM;
+
+	vfio_dma_unmap(iommu, start, size >> PAGE_SHIFT, dma->prot);
+
+	dma->npage = npage_lo;
+
+	split->npage = npage_hi;
+	split->iova = start + size;
+	split->vaddr = dma->vaddr + NPAGE_TO_SIZE(npage_lo) + size;
+	split->prot = dma->prot;
+	list_add(&split->next, &iommu->dma_list);
+	return size >> PAGE_SHIFT;
+}
+
+static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
+			     struct vfio_iommu_type1_dma_unmap *unmap)
+{
+	long ret = 0, npage = unmap->size >> PAGE_SHIFT;
+	struct vfio_dma *dma, *tmp;
+	uint64_t mask;
+
+	mask = ((uint64_t)1 << __ffs(iommu->domain->ops->pgsize_bitmap)) - 1;
+
+	if (unmap->iova & mask)
+		return -EINVAL;
+	if (unmap->size & mask)
+		return -EINVAL;
+
+	/* XXX We still break these down into PAGE_SIZE */
+	WARN_ON(mask & PAGE_MASK);
+
+	mutex_lock(&iommu->lock);
+
+	list_for_each_entry_safe(dma, tmp, &iommu->dma_list, next) {
+		if (ranges_overlap(dma->iova, NPAGE_TO_SIZE(dma->npage),
+				   unmap->iova, unmap->size)) {
+			ret = vfio_remove_dma_overlap(iommu, unmap->iova,
+						      unmap->size, dma);
+			if (ret > 0)
+				npage -= ret;
+			if (ret < 0 || npage == 0)
+				break;
+		}
+	}
+	mutex_unlock(&iommu->lock);
+	return ret > 0 ? 0 : (int)ret;
+}
+
+static int vfio_dma_do_map(struct vfio_iommu *iommu,
+			   struct vfio_iommu_type1_dma_map *map)
+{
+	struct vfio_dma *dma, *pdma = NULL;
+	dma_addr_t iova = map->iova;
+	unsigned long locked, lock_limit, vaddr = map->vaddr;
+	size_t size = map->size;
+	int ret = 0, prot = 0;
+	uint64_t mask;
+	long npage;
+
+	mask = ((uint64_t)1 << __ffs(iommu->domain->ops->pgsize_bitmap)) - 1;
+
+	/* READ/WRITE from device perspective */
+	if (map->flags & VFIO_DMA_MAP_FLAG_WRITE)
+		prot |= IOMMU_WRITE;
+	if (map->flags & VFIO_DMA_MAP_FLAG_READ)
+		prot |= IOMMU_READ;
+
+	if (!prot)
+		return -EINVAL; /* No READ/WRITE? */
+
+	if (vaddr & mask)
+		return -EINVAL;
+	if (iova & mask)
+		return -EINVAL;
+	if (size & mask)
+		return -EINVAL;
+
+	/* XXX We still break these down into PAGE_SIZE */
+	WARN_ON(mask & PAGE_MASK);
+
+	/* Don't allow IOVA wrap */
+	if (iova + size && iova + size < iova)
+		return -EINVAL;
+
+	/* Don't allow virtual address wrap */
+	if (vaddr + size && vaddr + size < vaddr)
+		return -EINVAL;
+
+	npage = size >> PAGE_SHIFT;
+	if (!npage)
+		return -EINVAL;
+
+	mutex_lock(&iommu->lock);
+
+	if (vfio_find_dma(iommu, iova, size)) {
+		ret = -EBUSY;
+		goto out_lock;
+	}
+
+	/* account for locked pages */
+	locked = current->mm->locked_vm + npage;
+	lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+	if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
+		printk(KERN_WARNING "%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
+			__func__, rlimit(RLIMIT_MEMLOCK));
+		ret = -ENOMEM;
+		goto out_lock;
+	}
+
+	ret = __vfio_dma_map(iommu, iova, vaddr, npage, prot);
+	if (ret)
+		goto out_lock;
+
+	/* Check if we abut a region below - nothing below 0 */
+	if (iova) {
+		dma = vfio_find_dma(iommu, iova - 1, 1);
+		if (dma && dma->prot == prot &&
+		    dma->vaddr + NPAGE_TO_SIZE(dma->npage) == vaddr) {
+
+			dma->npage += npage;
+			iova = dma->iova;
+			vaddr = dma->vaddr;
+			npage = dma->npage;
+			size = NPAGE_TO_SIZE(npage);
+
+			pdma = dma;
+		}
+	}
+
+	/* Check if we abut a region above - nothing above ~0 + 1 */
+	if (iova + size) {
+		dma = vfio_find_dma(iommu, iova + size, 1);
+		if (dma && dma->prot == prot &&
+		    dma->vaddr == vaddr + size) {
+
+			dma->npage += npage;
+			dma->iova = iova;
+			dma->vaddr = vaddr;
+
+			/*
+			 * If merged above and below, remove previously
+			 * merged entry.  New entry covers it.
+			 */
+			if (pdma) {
+				list_del(&pdma->next);
+				kfree(pdma);
+			}
+			pdma = dma;
+		}
+	}
+
+	/* Isolated, new region */
+	if (!pdma) {
+		dma = kzalloc(sizeof *dma, GFP_KERNEL);
+		if (!dma) {
+			ret = -ENOMEM;
+			vfio_dma_unmap(iommu, iova, npage, prot);
+			goto out_lock;
+		}
+
+		dma->npage = npage;
+		dma->iova = iova;
+		dma->vaddr = vaddr;
+		dma->prot = prot;
+		list_add(&dma->next, &iommu->dma_list);
+	}
+
+out_lock:
+	mutex_unlock(&iommu->lock);
+	return ret;
+}
+
+static int vfio_iommu_type1_attach_group(void *iommu_data,
+					 struct iommu_group *iommu_group)
+{
+	struct vfio_iommu *iommu = iommu_data;
+	struct vfio_group *group, *tmp;
+	int ret;
+
+	group = kzalloc(sizeof(*group), GFP_KERNEL);
+	if (!group)
+		return -ENOMEM;
+
+	mutex_lock(&iommu->lock);
+
+	list_for_each_entry(tmp, &iommu->group_list, next) {
+		if (tmp->iommu_group == iommu_group) {
+			mutex_unlock(&iommu->lock);
+			kfree(group);
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * TODO: Domain have capabilities that might change as we add
+	 * groups (see iommu->cache, currently never set).  Check for
+	 * them and potentially disallow groups to be attached when it
+	 * would change capabilities (ugh).
+	 */
+	ret = iommu_attach_group(iommu->domain, iommu_group);
+	if (ret) {
+		mutex_unlock(&iommu->lock);
+		kfree(group);
+		return ret;
+	}
+
+	group->iommu_group = iommu_group;
+	list_add(&group->next, &iommu->group_list);
+
+	mutex_unlock(&iommu->lock);
+
+	return 0;
+}
+
+static void vfio_iommu_type1_detach_group(void *iommu_data,
+					  struct iommu_group *iommu_group)
+{
+	struct vfio_iommu *iommu = iommu_data;
+	struct vfio_group *group;
+
+	mutex_lock(&iommu->lock);
+
+	list_for_each_entry(group, &iommu->group_list, next) {
+		if (group->iommu_group == iommu_group) {
+			iommu_detach_group(iommu->domain, iommu_group);
+			list_del(&group->next);
+			kfree(group);
+			break;
+		}
+	}
+
+	mutex_unlock(&iommu->lock);
+}
+
+static void *vfio_iommu_type1_open(unsigned long arg)
+{
+	struct vfio_iommu *iommu;
+
+	if (arg != VFIO_TYPE1_IOMMU)
+		return ERR_PTR(-EINVAL);
+
+	iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+	if (!iommu)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&iommu->group_list);
+	INIT_LIST_HEAD(&iommu->dma_list);
+	mutex_init(&iommu->lock);
+
+	/*
+	 * Wish we didn't have to know about bus_type here.
+	 */
+	iommu->domain = iommu_domain_alloc(&pci_bus_type);
+	if (!iommu->domain) {
+		kfree(iommu);
+		return ERR_PTR(-EIO);
+	}
+
+	/*
+	 * Wish we could specify required capabilities rather than create
+	 * a domain, see what comes out and hope it doesn't change along
+	 * the way.  Fortunately we know interrupt remapping is global for
+	 * our iommus.
+	 */
+	if (!allow_unsafe_interrupts &&
+	    !iommu_domain_has_cap(iommu->domain, IOMMU_CAP_INTR_REMAP)) {
+		printk(KERN_WARNING
+		       "%s: No interrupt remapping support.  Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n",
+		       __func__);
+		iommu_domain_free(iommu->domain);
+		kfree(iommu);
+		return ERR_PTR(-EPERM);
+	}
+
+	return iommu;
+}
+
+static void vfio_iommu_type1_release(void *iommu_data)
+{
+	struct vfio_iommu *iommu = iommu_data;
+	struct vfio_group *group, *group_tmp;
+	struct vfio_dma *dma, *dma_tmp;
+
+	list_for_each_entry_safe(group, group_tmp, &iommu->group_list, next) {
+		iommu_detach_group(iommu->domain, group->iommu_group);
+		list_del(&group->next);
+		kfree(group);
+	}
+
+	list_for_each_entry_safe(dma, dma_tmp, &iommu->dma_list, next) {
+		vfio_dma_unmap(iommu, dma->iova, dma->npage, dma->prot);
+		list_del(&dma->next);
+		kfree(dma);
+	}
+
+	iommu_domain_free(iommu->domain);
+	iommu->domain = NULL;
+	kfree(iommu);
+}
+
+static long vfio_iommu_type1_ioctl(void *iommu_data,
+				   unsigned int cmd, unsigned long arg)
+{
+	struct vfio_iommu *iommu = iommu_data;
+	unsigned long minsz;
+
+	if (cmd == VFIO_CHECK_EXTENSION) {
+		switch (arg) {
+		case VFIO_TYPE1_IOMMU:
+			return 1;
+		default:
+			return 0;
+		}
+	} else if (cmd == VFIO_IOMMU_GET_INFO) {
+		struct vfio_iommu_type1_info info;
+
+		minsz = offsetofend(struct vfio_iommu_type1_info, iova_pgsizes);
+
+		if (copy_from_user(&info, (void __user *)arg, minsz))
+			return -EFAULT;
+
+		if (info.argsz < minsz)
+			return -EINVAL;
+
+		info.flags = 0;
+
+		info.iova_pgsizes = iommu->domain->ops->pgsize_bitmap;
+
+		return copy_to_user((void __user *)arg, &info, minsz);
+
+	} else if (cmd == VFIO_IOMMU_MAP_DMA) {
+		struct vfio_iommu_type1_dma_map map;
+		uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
+				VFIO_DMA_MAP_FLAG_WRITE;
+
+		minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
+
+		if (copy_from_user(&map, (void __user *)arg, minsz))
+			return -EFAULT;
+
+		if (map.argsz < minsz || map.flags & ~mask)
+			return -EINVAL;
+
+		return vfio_dma_do_map(iommu, &map);
+
+	} else if (cmd == VFIO_IOMMU_UNMAP_DMA) {
+		struct vfio_iommu_type1_dma_unmap unmap;
+
+		minsz = offsetofend(struct vfio_iommu_type1_dma_unmap, size);
+
+		if (copy_from_user(&unmap, (void __user *)arg, minsz))
+			return -EFAULT;
+
+		if (unmap.argsz < minsz || unmap.flags)
+			return -EINVAL;
+
+		return vfio_dma_do_unmap(iommu, &unmap);
+	}
+
+	return -ENOTTY;
+}
+
+const struct vfio_iommu_driver_ops vfio_iommu_driver_ops_type1 = {
+	.name		= "vfio-iommu-type1",
+	.owner		= THIS_MODULE,
+	.open		= vfio_iommu_type1_open,
+	.release	= vfio_iommu_type1_release,
+	.ioctl		= vfio_iommu_type1_ioctl,
+	.attach_group	= vfio_iommu_type1_attach_group,
+	.detach_group	= vfio_iommu_type1_detach_group,
+};
+
+static int __init vfio_iommu_type1_init(void)
+{
+	if (!iommu_present(&pci_bus_type))
+		return -ENODEV;
+
+	return vfio_register_iommu_driver(&vfio_iommu_driver_ops_type1);
+}
+
+static void __exit vfio_iommu_type1_cleanup(void)
+{
+	vfio_unregister_iommu_driver(&vfio_iommu_driver_ops_type1);
+}
+
+module_init(vfio_iommu_type1_init);
+module_exit(vfio_iommu_type1_cleanup);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c
index 0443a4f..df1cbb7 100644
--- a/drivers/video/backlight/atmel-pwm-bl.c
+++ b/drivers/video/backlight/atmel-pwm-bl.c
@@ -127,7 +127,8 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
 	struct atmel_pwm_bl *pwmbl;
 	int retval;
 
-	pwmbl = kzalloc(sizeof(struct atmel_pwm_bl), GFP_KERNEL);
+	pwmbl = devm_kzalloc(&pdev->dev, sizeof(struct atmel_pwm_bl),
+				GFP_KERNEL);
 	if (!pwmbl)
 		return -ENOMEM;
 
@@ -154,7 +155,8 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
 		goto err_free_mem;
 
 	if (pwmbl->gpio_on != -1) {
-		retval = gpio_request(pwmbl->gpio_on, "gpio_atmel_pwm_bl");
+		retval = devm_gpio_request(&pdev->dev, pwmbl->gpio_on,
+					"gpio_atmel_pwm_bl");
 		if (retval) {
 			pwmbl->gpio_on = -1;
 			goto err_free_pwm;
@@ -164,7 +166,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
 		retval = gpio_direction_output(pwmbl->gpio_on,
 				0 ^ pdata->on_active_low);
 		if (retval)
-			goto err_free_gpio;
+			goto err_free_pwm;
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
@@ -174,7 +176,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
 					  &atmel_pwm_bl_ops, &props);
 	if (IS_ERR(bldev)) {
 		retval = PTR_ERR(bldev);
-		goto err_free_gpio;
+		goto err_free_pwm;
 	}
 
 	pwmbl->bldev = bldev;
@@ -196,13 +198,9 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
 err_free_bl_dev:
 	platform_set_drvdata(pdev, NULL);
 	backlight_device_unregister(bldev);
-err_free_gpio:
-	if (pwmbl->gpio_on != -1)
-		gpio_free(pwmbl->gpio_on);
 err_free_pwm:
 	pwm_channel_free(&pwmbl->pwmc);
 err_free_mem:
-	kfree(pwmbl);
 	return retval;
 }
 
@@ -210,15 +208,12 @@ static int __exit atmel_pwm_bl_remove(struct platform_device *pdev)
 {
 	struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev);
 
-	if (pwmbl->gpio_on != -1) {
+	if (pwmbl->gpio_on != -1)
 		gpio_set_value(pwmbl->gpio_on, 0);
-		gpio_free(pwmbl->gpio_on);
-	}
 	pwm_channel_disable(&pwmbl->pwmc);
 	pwm_channel_free(&pwmbl->pwmc);
 	backlight_device_unregister(pwmbl->bldev);
 	platform_set_drvdata(pdev, NULL);
-	kfree(pwmbl);
 
 	return 0;
 }
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
index 23d7326..c781768 100644
--- a/drivers/video/backlight/corgi_lcd.c
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -492,7 +492,8 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd,
 	lcd->gpio_backlight_cont = -1;
 
 	if (gpio_is_valid(pdata->gpio_backlight_on)) {
-		err = gpio_request(pdata->gpio_backlight_on, "BL_ON");
+		err = devm_gpio_request(&spi->dev, pdata->gpio_backlight_on,
+					"BL_ON");
 		if (err) {
 			dev_err(&spi->dev, "failed to request GPIO%d for "
 				"backlight_on\n", pdata->gpio_backlight_on);
@@ -504,11 +505,12 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd,
 	}
 
 	if (gpio_is_valid(pdata->gpio_backlight_cont)) {
-		err = gpio_request(pdata->gpio_backlight_cont, "BL_CONT");
+		err = devm_gpio_request(&spi->dev, pdata->gpio_backlight_cont,
+					"BL_CONT");
 		if (err) {
 			dev_err(&spi->dev, "failed to request GPIO%d for "
 				"backlight_cont\n", pdata->gpio_backlight_cont);
-			goto err_free_backlight_on;
+			return err;
 		}
 
 		lcd->gpio_backlight_cont = pdata->gpio_backlight_cont;
@@ -525,11 +527,6 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd,
 		}
 	}
 	return 0;
-
-err_free_backlight_on:
-	if (gpio_is_valid(lcd->gpio_backlight_on))
-		gpio_free(lcd->gpio_backlight_on);
-	return err;
 }
 
 static int __devinit corgi_lcd_probe(struct spi_device *spi)
@@ -602,12 +599,6 @@ static int __devexit corgi_lcd_remove(struct spi_device *spi)
 	backlight_update_status(lcd->bl_dev);
 	backlight_device_unregister(lcd->bl_dev);
 
-	if (gpio_is_valid(lcd->gpio_backlight_on))
-		gpio_free(lcd->gpio_backlight_on);
-
-	if (gpio_is_valid(lcd->gpio_backlight_cont))
-		gpio_free(lcd->gpio_backlight_cont);
-
 	corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
 	lcd_device_unregister(lcd->lcd_dev);
 
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c
index 40f606a..2d90c06 100644
--- a/drivers/video/backlight/l4f00242t03.c
+++ b/drivers/video/backlight/l4f00242t03.c
@@ -175,28 +175,27 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
 
 	priv->spi = spi;
 
-	ret = gpio_request_one(pdata->reset_gpio, GPIOF_OUT_INIT_HIGH,
-						"lcd l4f00242t03 reset");
+	ret = devm_gpio_request_one(&spi->dev, pdata->reset_gpio,
+			GPIOF_OUT_INIT_HIGH, "lcd l4f00242t03 reset");
 	if (ret) {
 		dev_err(&spi->dev,
 			"Unable to get the lcd l4f00242t03 reset gpio.\n");
 		return ret;
 	}
 
-	ret = gpio_request_one(pdata->data_enable_gpio, GPIOF_OUT_INIT_LOW,
-						"lcd l4f00242t03 data enable");
+	ret = devm_gpio_request_one(&spi->dev, pdata->data_enable_gpio,
+			GPIOF_OUT_INIT_LOW, "lcd l4f00242t03 data enable");
 	if (ret) {
 		dev_err(&spi->dev,
 			"Unable to get the lcd l4f00242t03 data en gpio.\n");
-		goto err;
+		return ret;
 	}
 
 	priv->io_reg = regulator_get(&spi->dev, "vdd");
 	if (IS_ERR(priv->io_reg)) {
-		ret = PTR_ERR(priv->io_reg);
 		dev_err(&spi->dev, "%s: Unable to get the IO regulator\n",
 		       __func__);
-		goto err2;
+		return PTR_ERR(priv->io_reg);
 	}
 
 	priv->core_reg = regulator_get(&spi->dev, "vcore");
@@ -204,14 +203,14 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
 		ret = PTR_ERR(priv->core_reg);
 		dev_err(&spi->dev, "%s: Unable to get the core regulator\n",
 		       __func__);
-		goto err3;
+		goto err1;
 	}
 
 	priv->ld = lcd_device_register("l4f00242t03",
 					&spi->dev, priv, &l4f_ops);
 	if (IS_ERR(priv->ld)) {
 		ret = PTR_ERR(priv->ld);
-		goto err4;
+		goto err2;
 	}
 
 	/* Init the LCD */
@@ -223,14 +222,10 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
 
 	return 0;
 
-err4:
+err2:
 	regulator_put(priv->core_reg);
-err3:
+err1:
 	regulator_put(priv->io_reg);
-err2:
-	gpio_free(pdata->data_enable_gpio);
-err:
-	gpio_free(pdata->reset_gpio);
 
 	return ret;
 }
@@ -238,16 +233,12 @@ err:
 static int __devexit l4f00242t03_remove(struct spi_device *spi)
 {
 	struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
-	struct l4f00242t03_pdata *pdata = priv->spi->dev.platform_data;
 
 	l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN);
 	lcd_device_unregister(priv->ld);
 
 	dev_set_drvdata(&spi->dev, NULL);
 
-	gpio_free(pdata->data_enable_gpio);
-	gpio_free(pdata->reset_gpio);
-
 	regulator_put(priv->io_reg);
 	regulator_put(priv->core_reg);
 
diff --git a/drivers/video/backlight/lm3533_bl.c b/drivers/video/backlight/lm3533_bl.c
index bebeb63..18dca0c 100644
--- a/drivers/video/backlight/lm3533_bl.c
+++ b/drivers/video/backlight/lm3533_bl.c
@@ -295,7 +295,7 @@ static int __devinit lm3533_bl_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	bl = kzalloc(sizeof(*bl), GFP_KERNEL);
+	bl = devm_kzalloc(&pdev->dev, sizeof(*bl), GFP_KERNEL);
 	if (!bl) {
 		dev_err(&pdev->dev,
 				"failed to allocate memory for backlight\n");
@@ -317,8 +317,7 @@ static int __devinit lm3533_bl_probe(struct platform_device *pdev)
 						&lm3533_bl_ops, &props);
 	if (IS_ERR(bd)) {
 		dev_err(&pdev->dev, "failed to register backlight device\n");
-		ret = PTR_ERR(bd);
-		goto err_free;
+		return PTR_ERR(bd);
 	}
 
 	bl->bd = bd;
@@ -348,8 +347,6 @@ err_sysfs_remove:
 	sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group);
 err_unregister:
 	backlight_device_unregister(bd);
-err_free:
-	kfree(bl);
 
 	return ret;
 }
@@ -367,7 +364,6 @@ static int __devexit lm3533_bl_remove(struct platform_device *pdev)
 	lm3533_ctrlbank_disable(&bl->cb);
 	sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group);
 	backlight_device_unregister(bd);
-	kfree(bl);
 
 	return 0;
 }
diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c
index a9f2c36..ea43f22 100644
--- a/drivers/video/backlight/lms283gf05.c
+++ b/drivers/video/backlight/lms283gf05.c
@@ -158,29 +158,27 @@ static int __devinit lms283gf05_probe(struct spi_device *spi)
 	int ret = 0;
 
 	if (pdata != NULL) {
-		ret = gpio_request(pdata->reset_gpio, "LMS285GF05 RESET");
+		ret = devm_gpio_request(&spi->dev, pdata->reset_gpio,
+					"LMS285GF05 RESET");
 		if (ret)
 			return ret;
 
 		ret = gpio_direction_output(pdata->reset_gpio,
 						!pdata->reset_inverted);
 		if (ret)
-			goto err;
+			return ret;
 	}
 
 	st = devm_kzalloc(&spi->dev, sizeof(struct lms283gf05_state),
 				GFP_KERNEL);
 	if (st == NULL) {
 		dev_err(&spi->dev, "No memory for device state\n");
-		ret = -ENOMEM;
-		goto err;
+		return -ENOMEM;
 	}
 
 	ld = lcd_device_register("lms283gf05", &spi->dev, st, &lms_ops);
-	if (IS_ERR(ld)) {
-		ret = PTR_ERR(ld);
-		goto err;
-	}
+	if (IS_ERR(ld))
+		return PTR_ERR(ld);
 
 	st->spi = spi;
 	st->ld = ld;
@@ -193,24 +191,14 @@ static int __devinit lms283gf05_probe(struct spi_device *spi)
 	lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq));
 
 	return 0;
-
-err:
-	if (pdata != NULL)
-		gpio_free(pdata->reset_gpio);
-
-	return ret;
 }
 
 static int __devexit lms283gf05_remove(struct spi_device *spi)
 {
 	struct lms283gf05_state *st = dev_get_drvdata(&spi->dev);
-	struct lms283gf05_pdata *pdata = st->spi->dev.platform_data;
 
 	lcd_device_unregister(st->ld);
 
-	if (pdata != NULL)
-		gpio_free(pdata->reset_gpio);
-
 	return 0;
 }
 
diff --git a/drivers/video/backlight/ot200_bl.c b/drivers/video/backlight/ot200_bl.c
index f519d55..469cf0f 100644
--- a/drivers/video/backlight/ot200_bl.c
+++ b/drivers/video/backlight/ot200_bl.c
@@ -84,7 +84,8 @@ static int ot200_backlight_probe(struct platform_device *pdev)
 	int retval = 0;
 
 	/* request gpio */
-	if (gpio_request(GPIO_DIMM, "ot200 backlight dimmer") < 0) {
+	if (devm_gpio_request(&pdev->dev, GPIO_DIMM,
+				"ot200 backlight dimmer") < 0) {
 		dev_err(&pdev->dev, "failed to request GPIO %d\n", GPIO_DIMM);
 		return -ENODEV;
 	}
@@ -93,14 +94,13 @@ static int ot200_backlight_probe(struct platform_device *pdev)
 	pwm_timer = cs5535_mfgpt_alloc_timer(7, MFGPT_DOMAIN_ANY);
 	if (!pwm_timer) {
 		dev_err(&pdev->dev, "MFGPT 7 not available\n");
-		retval = -ENODEV;
-		goto error_mfgpt_alloc;
+		return -ENODEV;
 	}
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 	if (!data) {
 		retval = -ENOMEM;
-		goto error_kzalloc;
+		goto error_devm_kzalloc;
 	}
 
 	/* setup gpio */
@@ -122,26 +122,21 @@ static int ot200_backlight_probe(struct platform_device *pdev)
 	if (IS_ERR(bl)) {
 		dev_err(&pdev->dev, "failed to register backlight\n");
 		retval = PTR_ERR(bl);
-		goto error_backlight_device_register;
+		goto error_devm_kzalloc;
 	}
 
 	platform_set_drvdata(pdev, bl);
 
 	return 0;
 
-error_backlight_device_register:
-	kfree(data);
-error_kzalloc:
+error_devm_kzalloc:
 	cs5535_mfgpt_free_timer(pwm_timer);
-error_mfgpt_alloc:
-	gpio_free(GPIO_DIMM);
 	return retval;
 }
 
 static int ot200_backlight_remove(struct platform_device *pdev)
 {
 	struct backlight_device *bl = platform_get_drvdata(pdev);
-	struct ot200_backlight_data *data = bl_get_data(bl);
 
 	backlight_device_unregister(bl);
 
@@ -152,9 +147,7 @@ static int ot200_backlight_remove(struct platform_device *pdev)
 		MAX_COMP2 - dim_table[100]);
 
 	cs5535_mfgpt_free_timer(pwm_timer);
-	gpio_free(GPIO_DIMM);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
index 0d54e60..49342e1 100644
--- a/drivers/video/backlight/tosa_bl.c
+++ b/drivers/video/backlight/tosa_bl.c
@@ -92,14 +92,14 @@ static int __devinit tosa_bl_probe(struct i2c_client *client,
 
 	data->comadj = sharpsl_param.comadj == -1 ? COMADJ_DEFAULT : sharpsl_param.comadj;
 
-	ret = gpio_request(TOSA_GPIO_BL_C20MA, "backlight");
+	ret = devm_gpio_request(&client->dev, TOSA_GPIO_BL_C20MA, "backlight");
 	if (ret) {
 		dev_dbg(&data->bl->dev, "Unable to request gpio!\n");
 		return ret;
 	}
 	ret = gpio_direction_output(TOSA_GPIO_BL_C20MA, 0);
 	if (ret)
-		goto err_gpio_dir;
+		return ret;
 
 	i2c_set_clientdata(client, data);
 	data->i2c = client;
@@ -123,8 +123,6 @@ static int __devinit tosa_bl_probe(struct i2c_client *client,
 
 err_reg:
 	data->bl = NULL;
-err_gpio_dir:
-	gpio_free(TOSA_GPIO_BL_C20MA);
 	return ret;
 }
 
@@ -135,8 +133,6 @@ static int __devexit tosa_bl_remove(struct i2c_client *client)
 	backlight_device_unregister(data->bl);
 	data->bl = NULL;
 
-	gpio_free(TOSA_GPIO_BL_C20MA);
-
 	return 0;
 }
 
diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c
index 47823b8..33047a66 100644
--- a/drivers/video/backlight/tosa_lcd.c
+++ b/drivers/video/backlight/tosa_lcd.c
@@ -193,7 +193,7 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi)
 	data->spi = spi;
 	dev_set_drvdata(&spi->dev, data);
 
-	ret = gpio_request(TOSA_GPIO_TG_ON, "tg #pwr");
+	ret = devm_gpio_request(&spi->dev, TOSA_GPIO_TG_ON, "tg #pwr");
 	if (ret < 0)
 		goto err_gpio_tg;
 
@@ -201,7 +201,7 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi)
 
 	ret = gpio_direction_output(TOSA_GPIO_TG_ON, 0);
 	if (ret < 0)
-		goto err_gpio_dir;
+		goto err_gpio_tg;
 
 	mdelay(60);
 	tosa_lcd_tg_init(data);
@@ -221,8 +221,6 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi)
 
 err_register:
 	tosa_lcd_tg_off(data);
-err_gpio_dir:
-	gpio_free(TOSA_GPIO_TG_ON);
 err_gpio_tg:
 	dev_set_drvdata(&spi->dev, NULL);
 	return ret;
@@ -239,7 +237,6 @@ static int __devexit tosa_lcd_remove(struct spi_device *spi)
 
 	tosa_lcd_tg_off(data);
 
-	gpio_free(TOSA_GPIO_TG_ON);
 	dev_set_drvdata(&spi->dev, NULL);
 
 	return 0;
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
index a36b2d2..9db7b9f 100644
--- a/drivers/video/exynos/exynos_dp_core.c
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -407,6 +407,9 @@ static unsigned int exynos_dp_get_lane_link_training(
 	case 3:
 		reg = exynos_dp_get_lane3_link_training(dp);
 		break;
+	default:
+		WARN_ON(1);
+		return 0;
 	}
 
 	return reg;
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h
index 1e0f998..8526e54 100644
--- a/drivers/video/exynos/exynos_dp_core.h
+++ b/drivers/video/exynos/exynos_dp_core.h
@@ -85,10 +85,6 @@ void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);
 void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);
 void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);
 void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);
-void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);
-void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);
-void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);
-void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);
 void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable);
 void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
 				 enum pattern_set pattern);
diff --git a/drivers/video/exynos/s6e8ax0.h b/drivers/video/exynos/s6e8ax0.h
deleted file mode 100644
index 1f1b270..0000000
--- a/drivers/video/exynos/s6e8ax0.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* linux/drivers/video/backlight/s6e8ax0.h
- *
- * MIPI-DSI based s6e8ax0 AMOLED LCD Panel definitions.
- *
- * Copyright (c) 2011 Samsung Electronics
- *
- * Inki Dae, <inki.dae@samsung.com>
- * Donghwa Lee <dh09.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef _S6E8AX0_H
-#define _S6E8AX0_H
-
-extern void s6e8ax0_init(void);
-
-#endif
-
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index 4c6b844..3951fda 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -127,8 +127,7 @@ static void sh_mipi_shutdown(struct platform_device *pdev)
 	sh_mipi_dsi_enable(mipi, false);
 }
 
-static int __init sh_mipi_setup(struct sh_mipi *mipi,
-				struct sh_mipi_dsi_info *pdata)
+static int sh_mipi_setup(struct sh_mipi *mipi, struct sh_mipi_dsi_info *pdata)
 {
 	void __iomem *base = mipi->base;
 	struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan;
@@ -551,7 +550,7 @@ efindslot:
 	return ret;
 }
 
-static int __exit sh_mipi_remove(struct platform_device *pdev)
+static int __devexit sh_mipi_remove(struct platform_device *pdev)
 {
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -592,7 +591,7 @@ static int __exit sh_mipi_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver sh_mipi_driver = {
-	.remove		= __exit_p(sh_mipi_remove),
+	.remove		= __devexit_p(sh_mipi_remove),
 	.shutdown	= sh_mipi_shutdown,
 	.driver = {
 		.name	= "sh-mipi-dsi",
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index e672698..98e81b3 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -12,6 +12,7 @@
 #include <linux/backlight.h>
 #include <linux/clk.h>
 #include <linux/console.h>
+#include <linux/ctype.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
@@ -32,12 +33,176 @@
 
 #include "sh_mobile_lcdcfb.h"
 
+/* ----------------------------------------------------------------------------
+ * Overlay register definitions
+ */
+
+#define LDBCR			0xb00
+#define LDBCR_UPC(n)		(1 << ((n) + 16))
+#define LDBCR_UPF(n)		(1 << ((n) + 8))
+#define LDBCR_UPD(n)		(1 << ((n) + 0))
+#define LDBnBSIFR(n)		(0xb20 + (n) * 0x20 + 0x00)
+#define LDBBSIFR_EN		(1 << 31)
+#define LDBBSIFR_VS		(1 << 29)
+#define LDBBSIFR_BRSEL		(1 << 28)
+#define LDBBSIFR_MX		(1 << 27)
+#define LDBBSIFR_MY		(1 << 26)
+#define LDBBSIFR_CV3		(3 << 24)
+#define LDBBSIFR_CV2		(2 << 24)
+#define LDBBSIFR_CV1		(1 << 24)
+#define LDBBSIFR_CV0		(0 << 24)
+#define LDBBSIFR_CV_MASK	(3 << 24)
+#define LDBBSIFR_LAY_MASK	(0xff << 16)
+#define LDBBSIFR_LAY_SHIFT	16
+#define LDBBSIFR_ROP3_MASK	(0xff << 16)
+#define LDBBSIFR_ROP3_SHIFT	16
+#define LDBBSIFR_AL_PL8		(3 << 14)
+#define LDBBSIFR_AL_PL1		(2 << 14)
+#define LDBBSIFR_AL_PK		(1 << 14)
+#define LDBBSIFR_AL_1		(0 << 14)
+#define LDBBSIFR_AL_MASK	(3 << 14)
+#define LDBBSIFR_SWPL		(1 << 10)
+#define LDBBSIFR_SWPW		(1 << 9)
+#define LDBBSIFR_SWPB		(1 << 8)
+#define LDBBSIFR_RY		(1 << 7)
+#define LDBBSIFR_CHRR_420	(2 << 0)
+#define LDBBSIFR_CHRR_422	(1 << 0)
+#define LDBBSIFR_CHRR_444	(0 << 0)
+#define LDBBSIFR_RPKF_ARGB32	(0x00 << 0)
+#define LDBBSIFR_RPKF_RGB16	(0x03 << 0)
+#define LDBBSIFR_RPKF_RGB24	(0x0b << 0)
+#define LDBBSIFR_RPKF_MASK	(0x1f << 0)
+#define LDBnBSSZR(n)		(0xb20 + (n) * 0x20 + 0x04)
+#define LDBBSSZR_BVSS_MASK	(0xfff << 16)
+#define LDBBSSZR_BVSS_SHIFT	16
+#define LDBBSSZR_BHSS_MASK	(0xfff << 0)
+#define LDBBSSZR_BHSS_SHIFT	0
+#define LDBnBLOCR(n)		(0xb20 + (n) * 0x20 + 0x08)
+#define LDBBLOCR_CVLC_MASK	(0xfff << 16)
+#define LDBBLOCR_CVLC_SHIFT	16
+#define LDBBLOCR_CHLC_MASK	(0xfff << 0)
+#define LDBBLOCR_CHLC_SHIFT	0
+#define LDBnBSMWR(n)		(0xb20 + (n) * 0x20 + 0x0c)
+#define LDBBSMWR_BSMWA_MASK	(0xffff << 16)
+#define LDBBSMWR_BSMWA_SHIFT	16
+#define LDBBSMWR_BSMW_MASK	(0xffff << 0)
+#define LDBBSMWR_BSMW_SHIFT	0
+#define LDBnBSAYR(n)		(0xb20 + (n) * 0x20 + 0x10)
+#define LDBBSAYR_FG1A_MASK	(0xff << 24)
+#define LDBBSAYR_FG1A_SHIFT	24
+#define LDBBSAYR_FG1R_MASK	(0xff << 16)
+#define LDBBSAYR_FG1R_SHIFT	16
+#define LDBBSAYR_FG1G_MASK	(0xff << 8)
+#define LDBBSAYR_FG1G_SHIFT	8
+#define LDBBSAYR_FG1B_MASK	(0xff << 0)
+#define LDBBSAYR_FG1B_SHIFT	0
+#define LDBnBSACR(n)		(0xb20 + (n) * 0x20 + 0x14)
+#define LDBBSACR_FG2A_MASK	(0xff << 24)
+#define LDBBSACR_FG2A_SHIFT	24
+#define LDBBSACR_FG2R_MASK	(0xff << 16)
+#define LDBBSACR_FG2R_SHIFT	16
+#define LDBBSACR_FG2G_MASK	(0xff << 8)
+#define LDBBSACR_FG2G_SHIFT	8
+#define LDBBSACR_FG2B_MASK	(0xff << 0)
+#define LDBBSACR_FG2B_SHIFT	0
+#define LDBnBSAAR(n)		(0xb20 + (n) * 0x20 + 0x18)
+#define LDBBSAAR_AP_MASK	(0xff << 24)
+#define LDBBSAAR_AP_SHIFT	24
+#define LDBBSAAR_R_MASK		(0xff << 16)
+#define LDBBSAAR_R_SHIFT	16
+#define LDBBSAAR_GY_MASK	(0xff << 8)
+#define LDBBSAAR_GY_SHIFT	8
+#define LDBBSAAR_B_MASK		(0xff << 0)
+#define LDBBSAAR_B_SHIFT	0
+#define LDBnBPPCR(n)		(0xb20 + (n) * 0x20 + 0x1c)
+#define LDBBPPCR_AP_MASK	(0xff << 24)
+#define LDBBPPCR_AP_SHIFT	24
+#define LDBBPPCR_R_MASK		(0xff << 16)
+#define LDBBPPCR_R_SHIFT	16
+#define LDBBPPCR_GY_MASK	(0xff << 8)
+#define LDBBPPCR_GY_SHIFT	8
+#define LDBBPPCR_B_MASK		(0xff << 0)
+#define LDBBPPCR_B_SHIFT	0
+#define LDBnBBGCL(n)		(0xb10 + (n) * 0x04)
+#define LDBBBGCL_BGA_MASK	(0xff << 24)
+#define LDBBBGCL_BGA_SHIFT	24
+#define LDBBBGCL_BGR_MASK	(0xff << 16)
+#define LDBBBGCL_BGR_SHIFT	16
+#define LDBBBGCL_BGG_MASK	(0xff << 8)
+#define LDBBBGCL_BGG_SHIFT	8
+#define LDBBBGCL_BGB_MASK	(0xff << 0)
+#define LDBBBGCL_BGB_SHIFT	0
+
 #define SIDE_B_OFFSET 0x1000
 #define MIRROR_OFFSET 0x2000
 
 #define MAX_XRES 1920
 #define MAX_YRES 1080
 
+enum sh_mobile_lcdc_overlay_mode {
+	LCDC_OVERLAY_BLEND,
+	LCDC_OVERLAY_ROP3,
+};
+
+/*
+ * struct sh_mobile_lcdc_overlay - LCDC display overlay
+ *
+ * @channel: LCDC channel this overlay belongs to
+ * @cfg: Overlay configuration
+ * @info: Frame buffer device
+ * @index: Overlay index (0-3)
+ * @base: Overlay registers base address
+ * @enabled: True if the overlay is enabled
+ * @mode: Overlay blending mode (alpha blend or ROP3)
+ * @alpha: Global alpha blending value (0-255, for alpha blending mode)
+ * @rop3: Raster operation (for ROP3 mode)
+ * @fb_mem: Frame buffer virtual memory address
+ * @fb_size: Frame buffer size in bytes
+ * @dma_handle: Frame buffer DMA address
+ * @base_addr_y: Overlay base address (RGB or luma component)
+ * @base_addr_c: Overlay base address (chroma component)
+ * @pan_offset: Current pan offset in bytes
+ * @format: Current pixelf format
+ * @xres: Horizontal visible resolution
+ * @xres_virtual: Horizontal total resolution
+ * @yres: Vertical visible resolution
+ * @yres_virtual: Vertical total resolution
+ * @pitch: Overlay line pitch
+ * @pos_x: Horizontal overlay position
+ * @pos_y: Vertical overlay position
+ */
+struct sh_mobile_lcdc_overlay {
+	struct sh_mobile_lcdc_chan *channel;
+
+	const struct sh_mobile_lcdc_overlay_cfg *cfg;
+	struct fb_info *info;
+
+	unsigned int index;
+	unsigned long base;
+
+	bool enabled;
+	enum sh_mobile_lcdc_overlay_mode mode;
+	unsigned int alpha;
+	unsigned int rop3;
+
+	void *fb_mem;
+	unsigned long fb_size;
+
+	dma_addr_t dma_handle;
+	unsigned long base_addr_y;
+	unsigned long base_addr_c;
+	unsigned long pan_offset;
+
+	const struct sh_mobile_lcdc_format_info *format;
+	unsigned int xres;
+	unsigned int xres_virtual;
+	unsigned int yres;
+	unsigned int yres_virtual;
+	unsigned int pitch;
+	int pos_x;
+	int pos_y;
+};
+
 struct sh_mobile_lcdc_priv {
 	void __iomem *base;
 	int irq;
@@ -45,7 +210,10 @@ struct sh_mobile_lcdc_priv {
 	struct device *dev;
 	struct clk *dot_clk;
 	unsigned long lddckr;
+
 	struct sh_mobile_lcdc_chan ch[2];
+	struct sh_mobile_lcdc_overlay overlays[4];
+
 	struct notifier_block notifier;
 	int started;
 	int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
@@ -141,6 +309,13 @@ static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan,
 	return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]);
 }
 
+static void lcdc_write_overlay(struct sh_mobile_lcdc_overlay *ovl,
+			       int reg, unsigned long data)
+{
+	iowrite32(data, ovl->channel->lcdc->base + reg);
+	iowrite32(data, ovl->channel->lcdc->base + reg + SIDE_B_OFFSET);
+}
+
 static void lcdc_write(struct sh_mobile_lcdc_priv *priv,
 		       unsigned long reg_offs, unsigned long data)
 {
@@ -384,8 +559,8 @@ sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,
 	return true;
 }
 
-static int sh_mobile_check_var(struct fb_var_screeninfo *var,
-			       struct fb_info *info);
+static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
+				    struct fb_info *info);
 
 static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
 					 enum sh_mobile_lcdc_entity_event event,
@@ -439,7 +614,7 @@ static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
 		fb_videomode_to_var(&var, mode);
 		var.bits_per_pixel = info->var.bits_per_pixel;
 		var.grayscale = info->var.grayscale;
-		ret = sh_mobile_check_var(&var, info);
+		ret = sh_mobile_lcdc_check_var(&var, info);
 		break;
 	}
 
@@ -585,7 +760,7 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int sh_mobile_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)
+static int sh_mobile_lcdc_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)
 {
 	unsigned long ldintr;
 	int ret;
@@ -685,8 +860,98 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
 	lcdc_write_chan(ch, LDHAJR, tmp);
 }
 
+static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl)
+{
+	u32 format = 0;
+
+	if (!ovl->enabled) {
+		lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
+		lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), 0);
+		lcdc_write(ovl->channel->lcdc, LDBCR,
+			   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
+		return;
+	}
+
+	ovl->base_addr_y = ovl->dma_handle;
+	ovl->base_addr_c = ovl->base_addr_y + ovl->xres
+			   * ovl->yres_virtual;
+
+	switch (ovl->mode) {
+	case LCDC_OVERLAY_BLEND:
+		format = LDBBSIFR_EN | (ovl->alpha << LDBBSIFR_LAY_SHIFT);
+		break;
+
+	case LCDC_OVERLAY_ROP3:
+		format = LDBBSIFR_EN | LDBBSIFR_BRSEL
+		       | (ovl->rop3 << LDBBSIFR_ROP3_SHIFT);
+		break;
+	}
+
+	switch (ovl->format->fourcc) {
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV61:
+	case V4L2_PIX_FMT_NV42:
+		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
+		break;
+	case V4L2_PIX_FMT_BGR24:
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV24:
+		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
+		break;
+	case V4L2_PIX_FMT_BGR32:
+	default:
+		format |= LDBBSIFR_SWPL;
+		break;
+	}
+
+	switch (ovl->format->fourcc) {
+	case V4L2_PIX_FMT_RGB565:
+		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
+		break;
+	case V4L2_PIX_FMT_BGR24:
+		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
+		break;
+	case V4L2_PIX_FMT_BGR32:
+		format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
+		break;
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
+		break;
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
+		break;
+	case V4L2_PIX_FMT_NV24:
+	case V4L2_PIX_FMT_NV42:
+		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
+		break;
+	}
+
+	lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
+
+	lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), format);
+
+	lcdc_write_overlay(ovl, LDBnBSSZR(ovl->index),
+		(ovl->yres << LDBBSSZR_BVSS_SHIFT) |
+		(ovl->xres << LDBBSSZR_BHSS_SHIFT));
+	lcdc_write_overlay(ovl, LDBnBLOCR(ovl->index),
+		(ovl->pos_y << LDBBLOCR_CVLC_SHIFT) |
+		(ovl->pos_x << LDBBLOCR_CHLC_SHIFT));
+	lcdc_write_overlay(ovl, LDBnBSMWR(ovl->index),
+		ovl->pitch << LDBBSMWR_BSMW_SHIFT);
+
+	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
+	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
+
+	lcdc_write(ovl->channel->lcdc, LDBCR,
+		   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
+}
+
 /*
- * __sh_mobile_lcdc_start - Configure and tart the LCDC
+ * __sh_mobile_lcdc_start - Configure and start the LCDC
  * @priv: LCDC device
  *
  * Configure all enabled channels and start the LCDC device. All external
@@ -892,6 +1157,11 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		}
 	}
 
+	for (k = 0; k < ARRAY_SIZE(priv->overlays); ++k) {
+		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[k];
+		sh_mobile_lcdc_overlay_setup(ovl);
+	}
+
 	/* Start the LCDC. */
 	__sh_mobile_lcdc_start(priv);
 
@@ -975,8 +1245,506 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
 			sh_mobile_lcdc_clk_off(priv);
 }
 
+static int __sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
+				      struct fb_info *info)
+{
+	if (var->xres > MAX_XRES || var->yres > MAX_YRES)
+		return -EINVAL;
+
+	/* Make sure the virtual resolution is at least as big as the visible
+	 * resolution.
+	 */
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	if (sh_mobile_format_is_fourcc(var)) {
+		const struct sh_mobile_lcdc_format_info *format;
+
+		format = sh_mobile_format_info(var->grayscale);
+		if (format == NULL)
+			return -EINVAL;
+		var->bits_per_pixel = format->bpp;
+
+		/* Default to RGB and JPEG color-spaces for RGB and YUV formats
+		 * respectively.
+		 */
+		if (!format->yuv)
+			var->colorspace = V4L2_COLORSPACE_SRGB;
+		else if (var->colorspace != V4L2_COLORSPACE_REC709)
+			var->colorspace = V4L2_COLORSPACE_JPEG;
+	} else {
+		if (var->bits_per_pixel <= 16) {		/* RGB 565 */
+			var->bits_per_pixel = 16;
+			var->red.offset = 11;
+			var->red.length = 5;
+			var->green.offset = 5;
+			var->green.length = 6;
+			var->blue.offset = 0;
+			var->blue.length = 5;
+			var->transp.offset = 0;
+			var->transp.length = 0;
+		} else if (var->bits_per_pixel <= 24) {		/* RGB 888 */
+			var->bits_per_pixel = 24;
+			var->red.offset = 16;
+			var->red.length = 8;
+			var->green.offset = 8;
+			var->green.length = 8;
+			var->blue.offset = 0;
+			var->blue.length = 8;
+			var->transp.offset = 0;
+			var->transp.length = 0;
+		} else if (var->bits_per_pixel <= 32) {		/* RGBA 888 */
+			var->bits_per_pixel = 32;
+			var->red.offset = 16;
+			var->red.length = 8;
+			var->green.offset = 8;
+			var->green.length = 8;
+			var->blue.offset = 0;
+			var->blue.length = 8;
+			var->transp.offset = 24;
+			var->transp.length = 8;
+		} else
+			return -EINVAL;
+
+		var->red.msb_right = 0;
+		var->green.msb_right = 0;
+		var->blue.msb_right = 0;
+		var->transp.msb_right = 0;
+	}
+
+	/* Make sure we don't exceed our allocated memory. */
+	if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
+	    info->fix.smem_len)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Frame buffer operations - Overlays
+ */
+
+static ssize_t
+overlay_alpha_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->alpha);
+}
+
+static ssize_t
+overlay_alpha_store(struct device *dev, struct device_attribute *attr,
+		    const char *buf, size_t count)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+	unsigned int alpha;
+	char *endp;
+
+	alpha = simple_strtoul(buf, &endp, 10);
+	if (isspace(*endp))
+		endp++;
+
+	if (endp - buf != count)
+		return -EINVAL;
+
+	if (alpha > 255)
+		return -EINVAL;
+
+	if (ovl->alpha != alpha) {
+		ovl->alpha = alpha;
+
+		if (ovl->mode == LCDC_OVERLAY_BLEND && ovl->enabled)
+			sh_mobile_lcdc_overlay_setup(ovl);
+	}
+
+	return count;
+}
+
+static ssize_t
+overlay_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->mode);
+}
+
+static ssize_t
+overlay_mode_store(struct device *dev, struct device_attribute *attr,
+		   const char *buf, size_t count)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+	unsigned int mode;
+	char *endp;
+
+	mode = simple_strtoul(buf, &endp, 10);
+	if (isspace(*endp))
+		endp++;
+
+	if (endp - buf != count)
+		return -EINVAL;
+
+	if (mode != LCDC_OVERLAY_BLEND && mode != LCDC_OVERLAY_ROP3)
+		return -EINVAL;
+
+	if (ovl->mode != mode) {
+		ovl->mode = mode;
+
+		if (ovl->enabled)
+			sh_mobile_lcdc_overlay_setup(ovl);
+	}
+
+	return count;
+}
+
+static ssize_t
+overlay_position_show(struct device *dev, struct device_attribute *attr,
+		      char *buf)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+	return scnprintf(buf, PAGE_SIZE, "%d,%d\n", ovl->pos_x, ovl->pos_y);
+}
+
+static ssize_t
+overlay_position_store(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+	char *endp;
+	int pos_x;
+	int pos_y;
+
+	pos_x = simple_strtol(buf, &endp, 10);
+	if (*endp != ',')
+		return -EINVAL;
+
+	pos_y = simple_strtol(endp + 1, &endp, 10);
+	if (isspace(*endp))
+		endp++;
+
+	if (endp - buf != count)
+		return -EINVAL;
+
+	if (ovl->pos_x != pos_x || ovl->pos_y != pos_y) {
+		ovl->pos_x = pos_x;
+		ovl->pos_y = pos_y;
+
+		if (ovl->enabled)
+			sh_mobile_lcdc_overlay_setup(ovl);
+	}
+
+	return count;
+}
+
+static ssize_t
+overlay_rop3_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->rop3);
+}
+
+static ssize_t
+overlay_rop3_store(struct device *dev, struct device_attribute *attr,
+		    const char *buf, size_t count)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+	unsigned int rop3;
+	char *endp;
+
+	rop3 = !!simple_strtoul(buf, &endp, 10);
+	if (isspace(*endp))
+		endp++;
+
+	if (endp - buf != count)
+		return -EINVAL;
+
+	if (rop3 > 255)
+		return -EINVAL;
+
+	if (ovl->rop3 != rop3) {
+		ovl->rop3 = rop3;
+
+		if (ovl->mode == LCDC_OVERLAY_ROP3 && ovl->enabled)
+			sh_mobile_lcdc_overlay_setup(ovl);
+	}
+
+	return count;
+}
+
+static const struct device_attribute overlay_sysfs_attrs[] = {
+	__ATTR(ovl_alpha, S_IRUGO|S_IWUSR,
+	       overlay_alpha_show, overlay_alpha_store),
+	__ATTR(ovl_mode, S_IRUGO|S_IWUSR,
+	       overlay_mode_show, overlay_mode_store),
+	__ATTR(ovl_position, S_IRUGO|S_IWUSR,
+	       overlay_position_show, overlay_position_store),
+	__ATTR(ovl_rop3, S_IRUGO|S_IWUSR,
+	       overlay_rop3_show, overlay_rop3_store),
+};
+
+static const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix  = {
+	.id =		"SH Mobile LCDC",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_TRUECOLOR,
+	.accel =	FB_ACCEL_NONE,
+	.xpanstep =	0,
+	.ypanstep =	1,
+	.ywrapstep =	0,
+	.capabilities =	FB_CAP_FOURCC,
+};
+
+static int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var,
+				    struct fb_info *info)
+{
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+	unsigned long base_addr_y;
+	unsigned long base_addr_c;
+	unsigned long pan_offset;
+	unsigned long c_offset;
+
+	if (!ovl->format->yuv)
+		pan_offset = var->yoffset * ovl->pitch
+			   + var->xoffset * (ovl->format->bpp / 8);
+	else
+		pan_offset = var->yoffset * ovl->pitch + var->xoffset;
+
+	if (pan_offset == ovl->pan_offset)
+		return 0;	/* No change, do nothing */
+
+	/* Set the source address for the next refresh */
+	base_addr_y = ovl->dma_handle + pan_offset;
+
+	ovl->base_addr_y = base_addr_y;
+	ovl->base_addr_c = base_addr_y;
+
+	if (ovl->format->yuv) {
+		/* Set Y offset */
+		c_offset = var->yoffset * ovl->pitch
+			 * (ovl->format->bpp - 8) / 8;
+		base_addr_c = ovl->dma_handle
+			    + ovl->xres * ovl->yres_virtual
+			    + c_offset;
+		/* Set X offset */
+		if (ovl->format->fourcc == V4L2_PIX_FMT_NV24)
+			base_addr_c += 2 * var->xoffset;
+		else
+			base_addr_c += var->xoffset;
+
+		ovl->base_addr_c = base_addr_c;
+	}
+
+	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
+	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
+
+	ovl->pan_offset = pan_offset;
+
+	return 0;
+}
+
+static int sh_mobile_lcdc_overlay_ioctl(struct fb_info *info, unsigned int cmd,
+				      unsigned long arg)
+{
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+	switch (cmd) {
+	case FBIO_WAITFORVSYNC:
+		return sh_mobile_lcdc_wait_for_vsync(ovl->channel);
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static int sh_mobile_lcdc_overlay_check_var(struct fb_var_screeninfo *var,
+					  struct fb_info *info)
+{
+	return __sh_mobile_lcdc_check_var(var, info);
+}
+
+static int sh_mobile_lcdc_overlay_set_par(struct fb_info *info)
+{
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+	ovl->format =
+		sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
+
+	ovl->xres = info->var.xres;
+	ovl->xres_virtual = info->var.xres_virtual;
+	ovl->yres = info->var.yres;
+	ovl->yres_virtual = info->var.yres_virtual;
+
+	if (ovl->format->yuv)
+		ovl->pitch = info->var.xres;
+	else
+		ovl->pitch = info->var.xres * ovl->format->bpp / 8;
+
+	sh_mobile_lcdc_overlay_setup(ovl);
+
+	info->fix.line_length = ovl->pitch;
+
+	if (sh_mobile_format_is_fourcc(&info->var)) {
+		info->fix.type = FB_TYPE_FOURCC;
+		info->fix.visual = FB_VISUAL_FOURCC;
+	} else {
+		info->fix.type = FB_TYPE_PACKED_PIXELS;
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+	}
+
+	return 0;
+}
+
+/* Overlay blanking. Disable the overlay when blanked. */
+static int sh_mobile_lcdc_overlay_blank(int blank, struct fb_info *info)
+{
+	struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+	ovl->enabled = !blank;
+	sh_mobile_lcdc_overlay_setup(ovl);
+
+	/* Prevent the backlight from receiving a blanking event by returning
+	 * a non-zero value.
+	 */
+	return 1;
+}
+
+static struct fb_ops sh_mobile_lcdc_overlay_ops = {
+	.owner          = THIS_MODULE,
+	.fb_read        = fb_sys_read,
+	.fb_write       = fb_sys_write,
+	.fb_fillrect	= sys_fillrect,
+	.fb_copyarea	= sys_copyarea,
+	.fb_imageblit	= sys_imageblit,
+	.fb_blank	= sh_mobile_lcdc_overlay_blank,
+	.fb_pan_display = sh_mobile_lcdc_overlay_pan,
+	.fb_ioctl       = sh_mobile_lcdc_overlay_ioctl,
+	.fb_check_var	= sh_mobile_lcdc_overlay_check_var,
+	.fb_set_par	= sh_mobile_lcdc_overlay_set_par,
+};
+
+static void
+sh_mobile_lcdc_overlay_fb_unregister(struct sh_mobile_lcdc_overlay *ovl)
+{
+	struct fb_info *info = ovl->info;
+
+	if (info == NULL || info->dev == NULL)
+		return;
+
+	unregister_framebuffer(ovl->info);
+}
+
+static int __devinit
+sh_mobile_lcdc_overlay_fb_register(struct sh_mobile_lcdc_overlay *ovl)
+{
+	struct sh_mobile_lcdc_priv *lcdc = ovl->channel->lcdc;
+	struct fb_info *info = ovl->info;
+	unsigned int i;
+	int ret;
+
+	if (info == NULL)
+		return 0;
+
+	ret = register_framebuffer(info);
+	if (ret < 0)
+		return ret;
+
+	dev_info(lcdc->dev, "registered %s/overlay %u as %dx%d %dbpp.\n",
+		 dev_name(lcdc->dev), ovl->index, info->var.xres,
+		 info->var.yres, info->var.bits_per_pixel);
+
+	for (i = 0; i < ARRAY_SIZE(overlay_sysfs_attrs); ++i) {
+		ret = device_create_file(info->dev, &overlay_sysfs_attrs[i]);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void
+sh_mobile_lcdc_overlay_fb_cleanup(struct sh_mobile_lcdc_overlay *ovl)
+{
+	struct fb_info *info = ovl->info;
+
+	if (info == NULL || info->device == NULL)
+		return;
+
+	framebuffer_release(info);
+}
+
+static int __devinit
+sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
+{
+	struct sh_mobile_lcdc_priv *priv = ovl->channel->lcdc;
+	struct fb_var_screeninfo *var;
+	struct fb_info *info;
+
+	/* Allocate and initialize the frame buffer device. */
+	info = framebuffer_alloc(0, priv->dev);
+	if (info == NULL) {
+		dev_err(priv->dev, "unable to allocate fb_info\n");
+		return -ENOMEM;
+	}
+
+	ovl->info = info;
+
+	info->flags = FBINFO_FLAG_DEFAULT;
+	info->fbops = &sh_mobile_lcdc_overlay_ops;
+	info->device = priv->dev;
+	info->screen_base = ovl->fb_mem;
+	info->par = ovl;
+
+	/* Initialize fixed screen information. Restrict pan to 2 lines steps
+	 * for NV12 and NV21.
+	 */
+	info->fix = sh_mobile_lcdc_overlay_fix;
+	snprintf(info->fix.id, sizeof(info->fix.id),
+		 "SH Mobile LCDC Overlay %u", ovl->index);
+	info->fix.smem_start = ovl->dma_handle;
+	info->fix.smem_len = ovl->fb_size;
+	info->fix.line_length = ovl->pitch;
+
+	if (ovl->format->yuv)
+		info->fix.visual = FB_VISUAL_FOURCC;
+	else
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	if (ovl->format->fourcc == V4L2_PIX_FMT_NV12 ||
+	    ovl->format->fourcc == V4L2_PIX_FMT_NV21)
+		info->fix.ypanstep = 2;
+
+	/* Initialize variable screen information. */
+	var = &info->var;
+	memset(var, 0, sizeof(*var));
+	var->xres = ovl->xres;
+	var->yres = ovl->yres;
+	var->xres_virtual = ovl->xres_virtual;
+	var->yres_virtual = ovl->yres_virtual;
+	var->activate = FB_ACTIVATE_NOW;
+
+	/* Use the legacy API by default for RGB formats, and the FOURCC API
+	 * for YUV formats.
+	 */
+	if (!ovl->format->yuv)
+		var->bits_per_pixel = ovl->format->bpp;
+	else
+		var->grayscale = ovl->format->fourcc;
+
+	return sh_mobile_lcdc_overlay_check_var(var, info);
+}
+
 /* -----------------------------------------------------------------------------
- * Frame buffer operations
+ * Frame buffer operations - main frame buffer
  */
 
 static int sh_mobile_lcdc_setcolreg(u_int regno,
@@ -1003,7 +1771,7 @@ static int sh_mobile_lcdc_setcolreg(u_int regno,
 	return 0;
 }
 
-static struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {
+static const struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {
 	.id =		"SH Mobile LCDC",
 	.type =		FB_TYPE_PACKED_PIXELS,
 	.visual =	FB_VISUAL_TRUECOLOR,
@@ -1035,8 +1803,8 @@ static void sh_mobile_lcdc_imageblit(struct fb_info *info,
 	sh_mobile_lcdc_deferred_io_touch(info);
 }
 
-static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
-				     struct fb_info *info)
+static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var,
+			      struct fb_info *info)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
 	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
@@ -1099,14 +1867,15 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
 	return 0;
 }
 
-static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
-		       unsigned long arg)
+static int sh_mobile_lcdc_ioctl(struct fb_info *info, unsigned int cmd,
+				unsigned long arg)
 {
+	struct sh_mobile_lcdc_chan *ch = info->par;
 	int retval;
 
 	switch (cmd) {
 	case FBIO_WAITFORVSYNC:
-		retval = sh_mobile_wait_for_vsync(info->par);
+		retval = sh_mobile_lcdc_wait_for_vsync(ch);
 		break;
 
 	default:
@@ -1158,7 +1927,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
  * Locking: both .fb_release() and .fb_open() are called with info->lock held if
  * user == 1, or with console sem held, if user == 0.
  */
-static int sh_mobile_release(struct fb_info *info, int user)
+static int sh_mobile_lcdc_release(struct fb_info *info, int user)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
 
@@ -1179,7 +1948,7 @@ static int sh_mobile_release(struct fb_info *info, int user)
 	return 0;
 }
 
-static int sh_mobile_open(struct fb_info *info, int user)
+static int sh_mobile_lcdc_open(struct fb_info *info, int user)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
 
@@ -1192,7 +1961,8 @@ static int sh_mobile_open(struct fb_info *info, int user)
 	return 0;
 }
 
-static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
+				    struct fb_info *info)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
 	struct sh_mobile_lcdc_priv *p = ch->lcdc;
@@ -1200,9 +1970,7 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
 	unsigned int best_xres = 0;
 	unsigned int best_yres = 0;
 	unsigned int i;
-
-	if (var->xres > MAX_XRES || var->yres > MAX_YRES)
-		return -EINVAL;
+	int ret;
 
 	/* If board code provides us with a list of available modes, make sure
 	 * we use one of them. Find the mode closest to the requested one. The
@@ -1237,73 +2005,9 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
 		var->yres = best_yres;
 	}
 
-	/* Make sure the virtual resolution is at least as big as the visible
-	 * resolution.
-	 */
-	if (var->xres_virtual < var->xres)
-		var->xres_virtual = var->xres;
-	if (var->yres_virtual < var->yres)
-		var->yres_virtual = var->yres;
-
-	if (sh_mobile_format_is_fourcc(var)) {
-		const struct sh_mobile_lcdc_format_info *format;
-
-		format = sh_mobile_format_info(var->grayscale);
-		if (format == NULL)
-			return -EINVAL;
-		var->bits_per_pixel = format->bpp;
-
-		/* Default to RGB and JPEG color-spaces for RGB and YUV formats
-		 * respectively.
-		 */
-		if (!format->yuv)
-			var->colorspace = V4L2_COLORSPACE_SRGB;
-		else if (var->colorspace != V4L2_COLORSPACE_REC709)
-			var->colorspace = V4L2_COLORSPACE_JPEG;
-	} else {
-		if (var->bits_per_pixel <= 16) {		/* RGB 565 */
-			var->bits_per_pixel = 16;
-			var->red.offset = 11;
-			var->red.length = 5;
-			var->green.offset = 5;
-			var->green.length = 6;
-			var->blue.offset = 0;
-			var->blue.length = 5;
-			var->transp.offset = 0;
-			var->transp.length = 0;
-		} else if (var->bits_per_pixel <= 24) {		/* RGB 888 */
-			var->bits_per_pixel = 24;
-			var->red.offset = 16;
-			var->red.length = 8;
-			var->green.offset = 8;
-			var->green.length = 8;
-			var->blue.offset = 0;
-			var->blue.length = 8;
-			var->transp.offset = 0;
-			var->transp.length = 0;
-		} else if (var->bits_per_pixel <= 32) {		/* RGBA 888 */
-			var->bits_per_pixel = 32;
-			var->red.offset = 16;
-			var->red.length = 8;
-			var->green.offset = 8;
-			var->green.length = 8;
-			var->blue.offset = 0;
-			var->blue.length = 8;
-			var->transp.offset = 24;
-			var->transp.length = 8;
-		} else
-			return -EINVAL;
-
-		var->red.msb_right = 0;
-		var->green.msb_right = 0;
-		var->blue.msb_right = 0;
-		var->transp.msb_right = 0;
-	}
-
-	/* Make sure we don't exceed our allocated memory. */
-	if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
-	    info->fix.smem_len)
-		return -EINVAL;
+	ret = __sh_mobile_lcdc_check_var(var, info);
+	if (ret < 0)
+		return ret;
 
 	/* only accept the forced_fourcc for dual channel configurations */
 	if (p->forced_fourcc &&
@@ -1313,7 +2017,7 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
 	return 0;
 }
 
-static int sh_mobile_set_par(struct fb_info *info)
+static int sh_mobile_lcdc_set_par(struct fb_info *info)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
 	int ret;
@@ -1383,8 +2087,8 @@ static int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
 		 * mode will reenable the clocks and update the screen in time,
 		 * so it does not need this. */
 		if (!info->fbdefio) {
-			sh_mobile_wait_for_vsync(ch);
-			sh_mobile_wait_for_vsync(ch);
+			sh_mobile_lcdc_wait_for_vsync(ch);
+			sh_mobile_lcdc_wait_for_vsync(ch);
 		}
 		sh_mobile_lcdc_clk_off(p);
 	}
@@ -1402,12 +2106,12 @@ static struct fb_ops sh_mobile_lcdc_ops = {
 	.fb_copyarea	= sh_mobile_lcdc_copyarea,
 	.fb_imageblit	= sh_mobile_lcdc_imageblit,
 	.fb_blank	= sh_mobile_lcdc_blank,
-	.fb_pan_display = sh_mobile_fb_pan_display,
-	.fb_ioctl       = sh_mobile_ioctl,
-	.fb_open	= sh_mobile_open,
-	.fb_release	= sh_mobile_release,
-	.fb_check_var	= sh_mobile_check_var,
-	.fb_set_par	= sh_mobile_set_par,
+	.fb_pan_display = sh_mobile_lcdc_pan,
+	.fb_ioctl       = sh_mobile_lcdc_ioctl,
+	.fb_open	= sh_mobile_lcdc_open,
+	.fb_release	= sh_mobile_lcdc_release,
+	.fb_check_var	= sh_mobile_lcdc_check_var,
+	.fb_set_par	= sh_mobile_lcdc_set_par,
 };
 
 static void
@@ -1537,7 +2241,7 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
 	else
 		var->grayscale = ch->format->fourcc;
 
-	ret = sh_mobile_check_var(var, info);
+	ret = sh_mobile_lcdc_check_var(var, info);
 	if (ret)
 		return ret;
 
@@ -1712,15 +2416,27 @@ static const struct fb_videomode default_720p __devinitconst = {
 static int sh_mobile_lcdc_remove(struct platform_device *pdev)
 {
 	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
-	int i;
+	unsigned int i;
 
 	fb_unregister_client(&priv->notifier);
 
+	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)
+		sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);
 	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
 		sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);
 
 	sh_mobile_lcdc_stop(priv);
 
+	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) {
+		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
+
+		sh_mobile_lcdc_overlay_fb_cleanup(ovl);
+
+		if (ovl->fb_mem)
+			dma_free_coherent(&pdev->dev, ovl->fb_size,
+					  ovl->fb_mem, ovl->dma_handle);
+	}
+
 	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
 		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
 
@@ -1796,6 +2512,61 @@ static int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *
 }
 
 static int __devinit
+sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_priv *priv,
+			  struct sh_mobile_lcdc_overlay *ovl)
+{
+	const struct sh_mobile_lcdc_format_info *format;
+	int ret;
+
+	if (ovl->cfg->fourcc == 0)
+		return 0;
+
+	/* Validate the format. */
+	format = sh_mobile_format_info(ovl->cfg->fourcc);
+	if (format == NULL) {
+		dev_err(priv->dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc);
+		return -EINVAL;
+	}
+
+	ovl->enabled = false;
+	ovl->mode = LCDC_OVERLAY_BLEND;
+	ovl->alpha = 255;
+	ovl->rop3 = 0;
+	ovl->pos_x = 0;
+	ovl->pos_y = 0;
+
+	/* The default Y virtual resolution is twice the panel size to allow for
+	 * double-buffering.
+	 */
+	ovl->format = format;
+	ovl->xres = ovl->cfg->max_xres;
+	ovl->xres_virtual = ovl->xres;
+	ovl->yres = ovl->cfg->max_yres;
+	ovl->yres_virtual = ovl->yres * 2;
+
+	if (!format->yuv)
+		ovl->pitch = ovl->xres * format->bpp / 8;
+	else
+		ovl->pitch = ovl->xres;
+
+	/* Allocate frame buffer memory. */
+	ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres
+		       * format->bpp / 8 * 2;
+	ovl->fb_mem = dma_alloc_coherent(priv->dev, ovl->fb_size,
+					   &ovl->dma_handle, GFP_KERNEL);
+	if (!ovl->fb_mem) {
+		dev_err(priv->dev, "unable to allocate buffer\n");
+		return -ENOMEM;
+	}
+
+	ret = sh_mobile_lcdc_overlay_fb_init(ovl);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int __devinit
 sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 			    struct sh_mobile_lcdc_chan *ch)
 {
@@ -2003,6 +2774,17 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 			goto err1;
 	}
 
+	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
+		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
+
+		ovl->cfg = &pdata->overlays[i];
+		ovl->channel = &priv->ch[0];
+
+		error = sh_mobile_lcdc_overlay_init(priv, ovl);
+		if (error)
+			goto err1;
+	}
+
 	error = sh_mobile_lcdc_start(priv);
 	if (error) {
 		dev_err(&pdev->dev, "unable to start hardware\n");
@@ -2017,6 +2799,14 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 			goto err1;
 	}
 
+	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
+		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
+
+		error = sh_mobile_lcdc_overlay_fb_register(ovl);
+		if (error)
+			goto err1;
+	}
+
 	/* Failure ignored */
 	priv->notifier.notifier_call = sh_mobile_lcdc_notify;
 	fb_register_client(&priv->notifier);
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
index a0c8965..530a2d3 100644
--- a/drivers/w1/masters/ds1wm.c
+++ b/drivers/w1/masters/ds1wm.c
@@ -334,7 +334,9 @@ static void ds1wm_search(void *data, struct w1_master *master_dev,
 			return;
 		}
 
+		mutex_lock(&master_dev->bus_mutex);
 		if (ds1wm_reset(ds1wm_data)) {
+			mutex_unlock(&master_dev->bus_mutex);
 			dev_dbg(&ds1wm_data->pdev->dev,
 				"pass: %d reset error (or no slaves)\n", pass);
 			break;
@@ -387,6 +389,7 @@ static void ds1wm_search(void *data, struct w1_master *master_dev,
 
 		}
 		if (ds1wm_data->read_error) {
+			mutex_unlock(&master_dev->bus_mutex);
 			dev_err(&ds1wm_data->pdev->dev,
 				"pass: %d read error, retrying\n", pass);
 			break;
@@ -400,6 +403,7 @@ static void ds1wm_search(void *data, struct w1_master *master_dev,
 		dev_dbg(&ds1wm_data->pdev->dev,
 			"pass: %d resetting bus\n", pass);
 		ds1wm_reset(ds1wm_data);
+		mutex_unlock(&master_dev->bus_mutex);
 		if ((r_prime & ((u64)1 << 63)) && (d & ((u64)1 << 63))) {
 			dev_err(&ds1wm_data->pdev->dev,
 				"pass: %d bus error, retrying\n", pass);
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index 5ef385b..848399b 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -180,6 +180,7 @@ static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
 		hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
 	if (ret == 0) {
 		dev_dbg(hdq_data->dev, "TX wait elapsed\n");
+		ret = -ETIMEDOUT;
 		goto out;
 	}
 
@@ -187,7 +188,7 @@ static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
 	/* check irqstatus */
 	if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) {
 		dev_dbg(hdq_data->dev, "timeout waiting for"
-			"TXCOMPLETE/RXCOMPLETE, %x", *status);
+			" TXCOMPLETE/RXCOMPLETE, %x", *status);
 		ret = -ETIMEDOUT;
 		goto out;
 	}
@@ -198,7 +199,7 @@ static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
 			OMAP_HDQ_FLAG_CLEAR, &tmp_status);
 	if (ret) {
 		dev_dbg(hdq_data->dev, "timeout waiting GO bit"
-			"return to zero, %x", tmp_status);
+			" return to zero, %x", tmp_status);
 	}
 
 out:
@@ -341,7 +342,7 @@ static int omap_hdq_break(struct hdq_data *hdq_data)
 			&tmp_status);
 	if (ret)
 		dev_dbg(hdq_data->dev, "timeout waiting INIT&GO bits"
-			"return to zero, %x", tmp_status);
+			" return to zero, %x", tmp_status);
 
 out:
 	mutex_unlock(&hdq_data->hdq_mutex);
@@ -353,7 +354,6 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
 {
 	int ret = 0;
 	u8 status;
-	unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT;
 
 	ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
 	if (ret < 0) {
@@ -371,22 +371,20 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
 			OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO,
 			OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
 		/*
-		 * The RX comes immediately after TX. It
-		 * triggers another interrupt before we
-		 * sleep. So we have to wait for RXCOMPLETE bit.
+		 * The RX comes immediately after TX.
 		 */
-		while (!(hdq_data->hdq_irqstatus
-			& OMAP_HDQ_INT_STATUS_RXCOMPLETE)
-			&& time_before(jiffies, timeout)) {
-			schedule_timeout_uninterruptible(1);
-		}
+		wait_event_timeout(hdq_wait_queue,
+				   (hdq_data->hdq_irqstatus
+				    & OMAP_HDQ_INT_STATUS_RXCOMPLETE),
+				   OMAP_HDQ_TIMEOUT);
+
 		hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, 0,
 			OMAP_HDQ_CTRL_STATUS_DIR);
 		status = hdq_data->hdq_irqstatus;
 		/* check irqstatus */
 		if (!(status & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
 			dev_dbg(hdq_data->dev, "timeout waiting for"
-				"RXCOMPLETE, %x", status);
+				" RXCOMPLETE, %x", status);
 			ret = -ETIMEDOUT;
 			goto out;
 		}
@@ -396,7 +394,7 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
 out:
 	mutex_unlock(&hdq_data->hdq_mutex);
 rtn:
-	return 0;
+	return ret;
 
 }
 
@@ -470,7 +468,7 @@ static int omap_hdq_put(struct hdq_data *hdq_data)
 
 	if (0 == hdq_data->hdq_usecount) {
 		dev_dbg(hdq_data->dev, "attempt to decrement use count"
-			"when it is zero");
+			" when it is zero");
 		ret = -EINVAL;
 	} else {
 		hdq_data->hdq_usecount--;
@@ -540,7 +538,7 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)
 	mutex_unlock(&hdq_data->hdq_mutex);
 
 	ret = hdq_write_byte(hdq_data, byte, &status);
-	if (ret == 0) {
+	if (ret < 0) {
 		dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status);
 		return;
 	}
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index eb9e376..6752669 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -94,6 +94,19 @@ config W1_SLAVE_DS2781
 
 	  If you are unsure, say N.
 
+config W1_SLAVE_DS28E04
+	tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)"
+	depends on W1
+	select CRC16
+	help
+	  If you enable this you will have the DS28E04-100
+	  chip support.
+
+	  Say Y here if you want to use a 1-wire
+	  4kb EEPROM with PIO family device (DS28E04).
+
+	  If you are unsure, say N.
+
 config W1_SLAVE_BQ27000
 	tristate "BQ27000 slave support"
 	depends on W1
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index c4f1859..05188f6 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_W1_SLAVE_DS2760)	+= w1_ds2760.o
 obj-$(CONFIG_W1_SLAVE_DS2780)	+= w1_ds2780.o
 obj-$(CONFIG_W1_SLAVE_DS2781)	+= w1_ds2781.o
 obj-$(CONFIG_W1_SLAVE_BQ27000)	+= w1_bq27000.o
+obj-$(CONFIG_W1_SLAVE_DS28E04)	+= w1_ds28e04.o
diff --git a/drivers/w1/slaves/w1_bq27000.c b/drivers/w1/slaves/w1_bq27000.c
index 52ad812..773dca5 100644
--- a/drivers/w1/slaves/w1_bq27000.c
+++ b/drivers/w1/slaves/w1_bq27000.c
@@ -31,10 +31,10 @@ static int w1_bq27000_read(struct device *dev, unsigned int reg)
 	u8 val;
 	struct w1_slave *sl = container_of(dev->parent, struct w1_slave, dev);
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 	w1_write_8(sl->master, HDQ_CMD_READ | reg);
 	val = w1_read_8(sl->master);
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 
 	return val;
 }
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
index 8e813ee..441ad3a 100644
--- a/drivers/w1/slaves/w1_ds2408.c
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -52,11 +52,11 @@ static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf)
 	if (!buf)
 		return -EINVAL;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 	dev_dbg(&sl->dev, "mutex locked");
 
 	if (w1_reset_select_slave(sl)) {
-		mutex_unlock(&sl->master->mutex);
+		mutex_unlock(&sl->master->bus_mutex);
 		return -EIO;
 	}
 
@@ -66,7 +66,7 @@ static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf)
 	w1_write_block(sl->master, wrbuf, 3);
 	*buf = w1_read_8(sl->master);
 
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 	dev_dbg(&sl->dev, "mutex unlocked");
 	return 1;
 }
@@ -165,7 +165,7 @@ static ssize_t w1_f29_write_output(
 		return -EFAULT;
 
 	dev_dbg(&sl->dev, "locking mutex for write_output");
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 	dev_dbg(&sl->dev, "mutex locked");
 
 	if (w1_reset_select_slave(sl))
@@ -200,14 +200,14 @@ static ssize_t w1_f29_write_output(
 		/* read the result of the READ_PIO_REGS command */
 		if (w1_read_8(sl->master) == *buf) {
 			/* success! */
-			mutex_unlock(&sl->master->mutex);
+			mutex_unlock(&sl->master->bus_mutex);
 			dev_dbg(&sl->dev,
 				"mutex unlocked, retries:%d", retries);
 			return 1;
 		}
 	}
 error:
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 	dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
 
 	return -EIO;
@@ -228,7 +228,7 @@ static ssize_t w1_f29_write_activity(
 	if (count != 1 || off != 0)
 		return -EFAULT;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 	if (w1_reset_select_slave(sl))
 		goto error;
@@ -236,7 +236,7 @@ static ssize_t w1_f29_write_activity(
 	while (retries--) {
 		w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);
 		if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {
-			mutex_unlock(&sl->master->mutex);
+			mutex_unlock(&sl->master->bus_mutex);
 			return 1;
 		}
 		if (w1_reset_resume_command(sl->master))
@@ -244,7 +244,7 @@ static ssize_t w1_f29_write_activity(
 	}
 
 error:
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 	return -EIO;
 }
 
@@ -263,7 +263,7 @@ static ssize_t w1_f29_write_status_control(
 	if (count != 1 || off != 0)
 		return -EFAULT;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 	if (w1_reset_select_slave(sl))
 		goto error;
@@ -285,12 +285,12 @@ static ssize_t w1_f29_write_status_control(
 		w1_write_block(sl->master, w1_buf, 3);
 		if (w1_read_8(sl->master) == *buf) {
 			/* success! */
-			mutex_unlock(&sl->master->mutex);
+			mutex_unlock(&sl->master->bus_mutex);
 			return 1;
 		}
 	}
 error:
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 
 	return -EIO;
 }
diff --git a/drivers/w1/slaves/w1_ds2423.c b/drivers/w1/slaves/w1_ds2423.c
index 7a7dbe5..40a10b5 100644
--- a/drivers/w1/slaves/w1_ds2423.c
+++ b/drivers/w1/slaves/w1_ds2423.c
@@ -66,7 +66,7 @@ static ssize_t w1_counter_read(struct device *device,
 	wrbuf[0]	= 0xA5;
 	wrbuf[1]	= rom_addr & 0xFF;
 	wrbuf[2]	= rom_addr >> 8;
-	mutex_lock(&dev->mutex);
+	mutex_lock(&dev->bus_mutex);
 	if (!w1_reset_select_slave(sl)) {
 		w1_write_block(dev, wrbuf, 3);
 		read_byte_count = 0;
@@ -124,7 +124,7 @@ static ssize_t w1_counter_read(struct device *device,
 	} else {
 		c -= snprintf(out_buf + PAGE_SIZE - c, c, "Connection error");
 	}
-	mutex_unlock(&dev->mutex);
+	mutex_unlock(&dev->bus_mutex);
 	return PAGE_SIZE - c;
 }
 
diff --git a/drivers/w1/slaves/w1_ds2431.c b/drivers/w1/slaves/w1_ds2431.c
index 84e2410..984b303 100644
--- a/drivers/w1/slaves/w1_ds2431.c
+++ b/drivers/w1/slaves/w1_ds2431.c
@@ -107,7 +107,7 @@ static ssize_t w1_f2d_read_bin(struct file *filp, struct kobject *kobj,
 	if (count == 0)
 		return 0;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 	/* read directly from the EEPROM in chunks of W1_F2D_READ_MAXLEN */
 	while (todo > 0) {
@@ -126,7 +126,7 @@ static ssize_t w1_f2d_read_bin(struct file *filp, struct kobject *kobj,
 		off += W1_F2D_READ_MAXLEN;
 	}
 
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 
 	return count;
 }
@@ -214,7 +214,7 @@ static ssize_t w1_f2d_write_bin(struct file *filp, struct kobject *kobj,
 	if (count == 0)
 		return 0;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 	/* Can only write data in blocks of the size of the scratchpad */
 	addr = off;
@@ -259,7 +259,7 @@ static ssize_t w1_f2d_write_bin(struct file *filp, struct kobject *kobj,
 	}
 
 out_up:
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 
 	return count;
 }
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c
index 0f7b8f9..85f2cdb 100644
--- a/drivers/w1/slaves/w1_ds2433.c
+++ b/drivers/w1/slaves/w1_ds2433.c
@@ -107,7 +107,7 @@ static ssize_t w1_f23_read_bin(struct file *filp, struct kobject *kobj,
 	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
 		return 0;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 #ifdef CONFIG_W1_SLAVE_DS2433_CRC
 
@@ -138,7 +138,7 @@ static ssize_t w1_f23_read_bin(struct file *filp, struct kobject *kobj,
 #endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
 
 out_up:
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 
 	return count;
 }
@@ -233,7 +233,7 @@ static ssize_t w1_f23_write_bin(struct file *filp, struct kobject *kobj,
 	}
 #endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 	/* Can only write data to one page at a time */
 	idx = 0;
@@ -251,7 +251,7 @@ static ssize_t w1_f23_write_bin(struct file *filp, struct kobject *kobj,
 	}
 
 out_up:
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 
 	return count;
 }
diff --git a/drivers/w1/slaves/w1_ds2760.c b/drivers/w1/slaves/w1_ds2760.c
index 5754c9a..aa7bd5f 100644
--- a/drivers/w1/slaves/w1_ds2760.c
+++ b/drivers/w1/slaves/w1_ds2760.c
@@ -31,7 +31,7 @@ static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count,
 	if (!dev)
 		return 0;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 	if (addr > DS2760_DATA_SIZE || addr < 0) {
 		count = 0;
@@ -54,7 +54,7 @@ static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count,
 	}
 
 out:
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 
 	return count;
 }
@@ -76,14 +76,14 @@ static int w1_ds2760_eeprom_cmd(struct device *dev, int addr, int cmd)
 	if (!dev)
 		return -EINVAL;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 	if (w1_reset_select_slave(sl) == 0) {
 		w1_write_8(sl->master, cmd);
 		w1_write_8(sl->master, addr);
 	}
 
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 	return 0;
 }
 
diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c
index 39f78c0..7b09307 100644
--- a/drivers/w1/slaves/w1_ds2780.c
+++ b/drivers/w1/slaves/w1_ds2780.c
@@ -60,30 +60,16 @@ int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
 	if (!dev)
 		return -ENODEV;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 	ret = w1_ds2780_do_io(dev, buf, addr, count, io);
 
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 
 	return ret;
 }
 EXPORT_SYMBOL(w1_ds2780_io);
 
-int w1_ds2780_io_nolock(struct device *dev, char *buf, int addr, size_t count,
-			int io)
-{
-	int ret;
-
-	if (!dev)
-		return -ENODEV;
-
-	ret = w1_ds2780_do_io(dev, buf, addr, count, io);
-
-	return ret;
-}
-EXPORT_SYMBOL(w1_ds2780_io_nolock);
-
 int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd)
 {
 	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
@@ -91,14 +77,14 @@ int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd)
 	if (!dev)
 		return -EINVAL;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 	if (w1_reset_select_slave(sl) == 0) {
 		w1_write_8(sl->master, cmd);
 		w1_write_8(sl->master, addr);
 	}
 
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(w1_ds2780_eeprom_cmd);
diff --git a/drivers/w1/slaves/w1_ds2780.h b/drivers/w1/slaves/w1_ds2780.h
index 7373793..a1fba79 100644
--- a/drivers/w1/slaves/w1_ds2780.h
+++ b/drivers/w1/slaves/w1_ds2780.h
@@ -124,8 +124,6 @@
 
 extern int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
 			int io);
-extern int w1_ds2780_io_nolock(struct device *dev, char *buf, int addr,
-			size_t count, int io);
 extern int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd);
 
 #endif /* !_W1_DS2780_H */
diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c
index 0d0c798..877daf7 100644
--- a/drivers/w1/slaves/w1_ds2781.c
+++ b/drivers/w1/slaves/w1_ds2781.c
@@ -58,30 +58,16 @@ int w1_ds2781_io(struct device *dev, char *buf, int addr, size_t count,
 	if (!dev)
 		return -ENODEV;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 	ret = w1_ds2781_do_io(dev, buf, addr, count, io);
 
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 
 	return ret;
 }
 EXPORT_SYMBOL(w1_ds2781_io);
 
-int w1_ds2781_io_nolock(struct device *dev, char *buf, int addr, size_t count,
-			int io)
-{
-	int ret;
-
-	if (!dev)
-		return -ENODEV;
-
-	ret = w1_ds2781_do_io(dev, buf, addr, count, io);
-
-	return ret;
-}
-EXPORT_SYMBOL(w1_ds2781_io_nolock);
-
 int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd)
 {
 	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
@@ -89,14 +75,14 @@ int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd)
 	if (!dev)
 		return -EINVAL;
 
-	mutex_lock(&sl->master->mutex);
+	mutex_lock(&sl->master->bus_mutex);
 
 	if (w1_reset_select_slave(sl) == 0) {
 		w1_write_8(sl->master, cmd);
 		w1_write_8(sl->master, addr);
 	}
 
-	mutex_unlock(&sl->master->mutex);
+	mutex_unlock(&sl->master->bus_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(w1_ds2781_eeprom_cmd);
diff --git a/drivers/w1/slaves/w1_ds2781.h b/drivers/w1/slaves/w1_ds2781.h
index 82bc664..557dfb0 100644
--- a/drivers/w1/slaves/w1_ds2781.h
+++ b/drivers/w1/slaves/w1_ds2781.h
@@ -129,8 +129,6 @@
 
 extern int w1_ds2781_io(struct device *dev, char *buf, int addr, size_t count,
 			int io);
-extern int w1_ds2781_io_nolock(struct device *dev, char *buf, int addr,
-			size_t count, int io);
 extern int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd);
 
 #endif /* !_W1_DS2781_H */
diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c
new file mode 100644
index 0000000..98117db
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds28e04.c
@@ -0,0 +1,469 @@
+/*
+ *	w1_ds28e04.c - w1 family 1C (DS28E04) driver
+ *
+ * Copyright (c) 2012 Markus Franke <franke.m@sebakmt.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/crc16.h>
+#include <linux/uaccess.h>
+
+#define CRC16_INIT		0
+#define CRC16_VALID		0xb001
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Markus Franke <franke.m@sebakmt.com>, <franm@hrz.tu-chemnitz.de>");
+MODULE_DESCRIPTION("w1 family 1C driver for DS28E04, 4kb EEPROM and PIO");
+
+/* Allow the strong pullup to be disabled, but default to enabled.
+ * If it was disabled a parasite powered device might not get the required
+ * current to copy the data from the scratchpad to EEPROM.  If it is enabled
+ * parasite powered devices have a better chance of getting the current
+ * required.
+ */
+static int w1_strong_pullup = 1;
+module_param_named(strong_pullup, w1_strong_pullup, int, 0);
+
+/* enable/disable CRC checking on DS28E04-100 memory accesses */
+static char w1_enable_crccheck = 1;
+
+#define W1_EEPROM_SIZE		512
+#define W1_PAGE_COUNT		16
+#define W1_PAGE_SIZE		32
+#define W1_PAGE_BITS		5
+#define W1_PAGE_MASK		0x1F
+
+#define W1_F1C_READ_EEPROM	0xF0
+#define W1_F1C_WRITE_SCRATCH	0x0F
+#define W1_F1C_READ_SCRATCH	0xAA
+#define W1_F1C_COPY_SCRATCH	0x55
+#define W1_F1C_ACCESS_WRITE	0x5A
+
+#define W1_1C_REG_LOGIC_STATE	0x220
+
+struct w1_f1C_data {
+	u8	memory[W1_EEPROM_SIZE];
+	u32	validcrc;
+};
+
+/**
+ * Check the file size bounds and adjusts count as needed.
+ * This would not be needed if the file size didn't reset to 0 after a write.
+ */
+static inline size_t w1_f1C_fix_count(loff_t off, size_t count, size_t size)
+{
+	if (off > size)
+		return 0;
+
+	if ((off + count) > size)
+		return size - off;
+
+	return count;
+}
+
+static int w1_f1C_refresh_block(struct w1_slave *sl, struct w1_f1C_data *data,
+				int block)
+{
+	u8	wrbuf[3];
+	int	off = block * W1_PAGE_SIZE;
+
+	if (data->validcrc & (1 << block))
+		return 0;
+
+	if (w1_reset_select_slave(sl)) {
+		data->validcrc = 0;
+		return -EIO;
+	}
+
+	wrbuf[0] = W1_F1C_READ_EEPROM;
+	wrbuf[1] = off & 0xff;
+	wrbuf[2] = off >> 8;
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);
+
+	/* cache the block if the CRC is valid */
+	if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
+		data->validcrc |= (1 << block);
+
+	return 0;
+}
+
+static int w1_f1C_read(struct w1_slave *sl, int addr, int len, char *data)
+{
+	u8 wrbuf[3];
+
+	/* read directly from the EEPROM */
+	if (w1_reset_select_slave(sl))
+		return -EIO;
+
+	wrbuf[0] = W1_F1C_READ_EEPROM;
+	wrbuf[1] = addr & 0xff;
+	wrbuf[2] = addr >> 8;
+
+	w1_write_block(sl->master, wrbuf, sizeof(wrbuf));
+	return w1_read_block(sl->master, data, len);
+}
+
+static ssize_t w1_f1C_read_bin(struct file *filp, struct kobject *kobj,
+			       struct bin_attribute *bin_attr,
+			       char *buf, loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	struct w1_f1C_data *data = sl->family_data;
+	int i, min_page, max_page;
+
+	count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE);
+	if (count == 0)
+		return 0;
+
+	mutex_lock(&sl->master->mutex);
+
+	if (w1_enable_crccheck) {
+		min_page = (off >> W1_PAGE_BITS);
+		max_page = (off + count - 1) >> W1_PAGE_BITS;
+		for (i = min_page; i <= max_page; i++) {
+			if (w1_f1C_refresh_block(sl, data, i)) {
+				count = -EIO;
+				goto out_up;
+			}
+		}
+		memcpy(buf, &data->memory[off], count);
+	} else {
+		count = w1_f1C_read(sl, off, count, buf);
+	}
+
+out_up:
+	mutex_unlock(&sl->master->mutex);
+
+	return count;
+}
+
+/**
+ * Writes to the scratchpad and reads it back for verification.
+ * Then copies the scratchpad to EEPROM.
+ * The data must be on one page.
+ * The master must be locked.
+ *
+ * @param sl	The slave structure
+ * @param addr	Address for the write
+ * @param len   length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK))
+ * @param data	The data to write
+ * @return	0=Success -1=failure
+ */
+static int w1_f1C_write(struct w1_slave *sl, int addr, int len, const u8 *data)
+{
+	u8 wrbuf[4];
+	u8 rdbuf[W1_PAGE_SIZE + 3];
+	u8 es = (addr + len - 1) & 0x1f;
+	unsigned int tm = 10;
+	int i;
+	struct w1_f1C_data *f1C = sl->family_data;
+
+	/* Write the data to the scratchpad */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F1C_WRITE_SCRATCH;
+	wrbuf[1] = addr & 0xff;
+	wrbuf[2] = addr >> 8;
+
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_write_block(sl->master, data, len);
+
+	/* Read the scratchpad and verify */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	w1_write_8(sl->master, W1_F1C_READ_SCRATCH);
+	w1_read_block(sl->master, rdbuf, len + 3);
+
+	/* Compare what was read against the data written */
+	if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
+	    (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0))
+		return -1;
+
+	/* Copy the scratchpad to EEPROM */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F1C_COPY_SCRATCH;
+	wrbuf[3] = es;
+
+	for (i = 0; i < sizeof(wrbuf); ++i) {
+		/* issue 10ms strong pullup (or delay) on the last byte
+		   for writing the data from the scratchpad to EEPROM */
+		if (w1_strong_pullup && i == sizeof(wrbuf)-1)
+			w1_next_pullup(sl->master, tm);
+
+		w1_write_8(sl->master, wrbuf[i]);
+	}
+
+	if (!w1_strong_pullup)
+		msleep(tm);
+
+	if (w1_enable_crccheck) {
+		/* invalidate cached data */
+		f1C->validcrc &= ~(1 << (addr >> W1_PAGE_BITS));
+	}
+
+	/* Reset the bus to wake up the EEPROM (this may not be needed) */
+	w1_reset_bus(sl->master);
+
+	return 0;
+}
+
+static ssize_t w1_f1C_write_bin(struct file *filp, struct kobject *kobj,
+			       struct bin_attribute *bin_attr,
+			       char *buf, loff_t off, size_t count)
+
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int addr, len, idx;
+
+	count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE);
+	if (count == 0)
+		return 0;
+
+	if (w1_enable_crccheck) {
+		/* can only write full blocks in cached mode */
+		if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
+			dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n",
+				(int)off, count);
+			return -EINVAL;
+		}
+
+		/* make sure the block CRCs are valid */
+		for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
+			if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE)
+				!= CRC16_VALID) {
+				dev_err(&sl->dev, "bad CRC at offset %d\n",
+					(int)off);
+				return -EINVAL;
+			}
+		}
+	}
+
+	mutex_lock(&sl->master->mutex);
+
+	/* Can only write data to one page at a time */
+	idx = 0;
+	while (idx < count) {
+		addr = off + idx;
+		len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK);
+		if (len > (count - idx))
+			len = count - idx;
+
+		if (w1_f1C_write(sl, addr, len, &buf[idx]) < 0) {
+			count = -EIO;
+			goto out_up;
+		}
+		idx += len;
+	}
+
+out_up:
+	mutex_unlock(&sl->master->mutex);
+
+	return count;
+}
+
+static ssize_t w1_f1C_read_pio(struct file *filp, struct kobject *kobj,
+			       struct bin_attribute *bin_attr,
+			       char *buf, loff_t off, size_t count)
+
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int ret;
+
+	/* check arguments */
+	if (off != 0 || count != 1 || buf == NULL)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->mutex);
+	ret = w1_f1C_read(sl, W1_1C_REG_LOGIC_STATE, count, buf);
+	mutex_unlock(&sl->master->mutex);
+
+	return ret;
+}
+
+static ssize_t w1_f1C_write_pio(struct file *filp, struct kobject *kobj,
+				struct bin_attribute *bin_attr,
+				char *buf, loff_t off, size_t count)
+
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	u8 wrbuf[3];
+	u8 ack;
+
+	/* check arguments */
+	if (off != 0 || count != 1 || buf == NULL)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->mutex);
+
+	/* Write the PIO data */
+	if (w1_reset_select_slave(sl)) {
+		mutex_unlock(&sl->master->mutex);
+		return -1;
+	}
+
+	/* set bit 7..2 to value '1' */
+	*buf = *buf | 0xFC;
+
+	wrbuf[0] = W1_F1C_ACCESS_WRITE;
+	wrbuf[1] = *buf;
+	wrbuf[2] = ~(*buf);
+	w1_write_block(sl->master, wrbuf, 3);
+
+	w1_read_block(sl->master, &ack, sizeof(ack));
+
+	mutex_unlock(&sl->master->mutex);
+
+	/* check for acknowledgement */
+	if (ack != 0xAA)
+		return -EIO;
+
+	return count;
+}
+
+static ssize_t w1_f1C_show_crccheck(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	if (put_user(w1_enable_crccheck + 0x30, buf))
+		return -EFAULT;
+
+	return sizeof(w1_enable_crccheck);
+}
+
+static ssize_t w1_f1C_store_crccheck(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	char val;
+
+	if (count != 1 || !buf)
+		return -EINVAL;
+
+	if (get_user(val, buf))
+		return -EFAULT;
+
+	/* convert to decimal */
+	val = val - 0x30;
+	if (val != 0 && val != 1)
+		return -EINVAL;
+
+	/* set the new value */
+	w1_enable_crccheck = val;
+
+	return sizeof(w1_enable_crccheck);
+}
+
+#define NB_SYSFS_BIN_FILES 2
+static struct bin_attribute w1_f1C_bin_attr[NB_SYSFS_BIN_FILES] = {
+	{
+		.attr = {
+			.name = "eeprom",
+			.mode = S_IRUGO | S_IWUSR,
+		},
+		.size = W1_EEPROM_SIZE,
+		.read = w1_f1C_read_bin,
+		.write = w1_f1C_write_bin,
+	},
+	{
+		.attr = {
+			.name = "pio",
+			.mode = S_IRUGO | S_IWUSR,
+		},
+		.size = 1,
+		.read = w1_f1C_read_pio,
+		.write = w1_f1C_write_pio,
+	}
+};
+
+static DEVICE_ATTR(crccheck, S_IWUSR | S_IRUGO,
+		   w1_f1C_show_crccheck, w1_f1C_store_crccheck);
+
+static int w1_f1C_add_slave(struct w1_slave *sl)
+{
+	int err = 0;
+	int i;
+	struct w1_f1C_data *data = NULL;
+
+	if (w1_enable_crccheck) {
+		data = kzalloc(sizeof(struct w1_f1C_data), GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+		sl->family_data = data;
+	}
+
+	/* create binary sysfs attributes */
+	for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
+		err = sysfs_create_bin_file(
+			&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+
+	if (!err) {
+		/* create device attributes */
+		err = device_create_file(&sl->dev, &dev_attr_crccheck);
+	}
+
+	if (err) {
+		/* remove binary sysfs attributes */
+		for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
+			sysfs_remove_bin_file(
+				&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+
+		kfree(data);
+	}
+
+	return err;
+}
+
+static void w1_f1C_remove_slave(struct w1_slave *sl)
+{
+	int i;
+
+	kfree(sl->family_data);
+	sl->family_data = NULL;
+
+	/* remove device attributes */
+	device_remove_file(&sl->dev, &dev_attr_crccheck);
+
+	/* remove binary sysfs attributes */
+	for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
+		sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
+}
+
+static struct w1_family_ops w1_f1C_fops = {
+	.add_slave      = w1_f1C_add_slave,
+	.remove_slave   = w1_f1C_remove_slave,
+};
+
+static struct w1_family w1_family_1C = {
+	.fid = W1_FAMILY_DS28E04,
+	.fops = &w1_f1C_fops,
+};
+
+static int __init w1_f1C_init(void)
+{
+	return w1_register_family(&w1_family_1C);
+}
+
+static void __exit w1_f1C_fini(void)
+{
+	w1_unregister_family(&w1_family_1C);
+}
+
+module_init(w1_f1C_init);
+module_exit(w1_f1C_fini);
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index ff29ae7..d90062b 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -179,7 +179,7 @@ static ssize_t w1_therm_read(struct device *device,
 	int i, max_trying = 10;
 	ssize_t c = PAGE_SIZE;
 
-	i = mutex_lock_interruptible(&dev->mutex);
+	i = mutex_lock_interruptible(&dev->bus_mutex);
 	if (i != 0)
 		return i;
 
@@ -207,19 +207,19 @@ static ssize_t w1_therm_read(struct device *device,
 			w1_write_8(dev, W1_CONVERT_TEMP);
 
 			if (external_power) {
-				mutex_unlock(&dev->mutex);
+				mutex_unlock(&dev->bus_mutex);
 
 				sleep_rem = msleep_interruptible(tm);
 				if (sleep_rem != 0)
 					return -EINTR;
 
-				i = mutex_lock_interruptible(&dev->mutex);
+				i = mutex_lock_interruptible(&dev->bus_mutex);
 				if (i != 0)
 					return i;
 			} else if (!w1_strong_pullup) {
 				sleep_rem = msleep_interruptible(tm);
 				if (sleep_rem != 0) {
-					mutex_unlock(&dev->mutex);
+					mutex_unlock(&dev->bus_mutex);
 					return -EINTR;
 				}
 			}
@@ -258,7 +258,7 @@ static ssize_t w1_therm_read(struct device *device,
 
 	c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n",
 		w1_convert_temp(rom, sl->family->fid));
-	mutex_unlock(&dev->mutex);
+	mutex_unlock(&dev->bus_mutex);
 
 	return PAGE_SIZE - c;
 }
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 2f2e894..1a57437 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -557,7 +557,7 @@ static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
 	struct w1_master *md = NULL;
 	struct w1_slave *sl = NULL;
 	char *event_owner, *name;
-	int err;
+	int err = 0;
 
 	if (dev->driver == &w1_master_driver) {
 		md = container_of(dev, struct w1_master, dev);
@@ -576,19 +576,17 @@ static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
 			event_owner, name, dev_name(dev));
 
 	if (dev->driver != &w1_slave_driver || !sl)
-		return 0;
+		goto end;
 
 	err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
 	if (err)
-		return err;
+		goto end;
 
 	err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
 			     (unsigned long long)sl->reg_num.id);
-	if (err)
-		return err;
-
-	return 0;
-};
+end:
+	return err;
+}
 #else
 static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
@@ -887,16 +885,21 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
 		 *
 		 * Return 0 - device(s) present, 1 - no devices present.
 		 */
+		mutex_lock(&dev->bus_mutex);
 		if (w1_reset_bus(dev)) {
+			mutex_unlock(&dev->bus_mutex);
 			dev_dbg(&dev->dev, "No devices present on the wire.\n");
 			break;
 		}
 
 		/* Do fast search on single slave bus */
 		if (dev->max_slave_count == 1) {
+			int rv;
 			w1_write_8(dev, W1_READ_ROM);
+			rv = w1_read_block(dev, (u8 *)&rn, 8);
+			mutex_unlock(&dev->bus_mutex);
 
-			if (w1_read_block(dev, (u8 *)&rn, 8) == 8 && rn)
+			if (rv == 8 && rn)
 				cb(dev, rn);
 
 			break;
@@ -929,10 +932,12 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
 			rn |= (tmp64 << i);
 
 			if (kthread_should_stop()) {
+				mutex_unlock(&dev->bus_mutex);
 				dev_dbg(&dev->dev, "Abort w1_search\n");
 				return;
 			}
 		}
+		mutex_unlock(&dev->bus_mutex);
 
 		if ( (triplet_ret & 0x03) != 0x03 ) {
 			if ( (desc_bit == last_zero) || (last_zero < 0))
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
index 4d012ca..45908e5 100644
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -180,6 +180,7 @@ struct w1_master
 
 	struct task_struct	*thread;
 	struct mutex		mutex;
+	struct mutex		bus_mutex;
 
 	struct device_driver	*driver;
 	struct device		dev;
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 874aeb0..b00ada4 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -30,6 +30,7 @@
 #define W1_FAMILY_SMEM_01	0x01
 #define W1_FAMILY_SMEM_81	0x81
 #define W1_THERM_DS18S20 	0x10
+#define W1_FAMILY_DS28E04	0x1C
 #define W1_COUNTER_DS2423	0x1D
 #define W1_THERM_DS1822  	0x22
 #define W1_EEPROM_DS2433  	0x23
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 6828835..5a98649 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -76,6 +76,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
 
 	INIT_LIST_HEAD(&dev->slist);
 	mutex_init(&dev->mutex);
+	mutex_init(&dev->bus_mutex);
 
 	memcpy(&dev->dev, device, sizeof(struct device));
 	dev_set_name(&dev->dev, "w1_bus_master%u", dev->id);
@@ -117,7 +118,7 @@ int w1_add_master_device(struct w1_bus_master *master)
 		return(-EINVAL);
         }
 	/* While it would be electrically possible to make a device that
-	 * generated a strong pullup in bit bang mode, only hardare that
+	 * generated a strong pullup in bit bang mode, only hardware that
 	 * controls 1-wire time frames are even expected to support a strong
 	 * pullup.  w1_io.c would need to support calling set_pullup before
 	 * the last write_bit operation of a w1_write_8 which it currently
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c
index 6876430..cb5da5c 100644
--- a/drivers/watchdog/coh901327_wdt.c
+++ b/drivers/watchdog/coh901327_wdt.c
@@ -263,6 +263,7 @@ static int __exit coh901327_remove(struct platform_device *pdev)
 	watchdog_unregister_device(&coh901327_wdt);
 	coh901327_disable();
 	free_irq(irq, pdev);
+	clk_unprepare(clk);
 	clk_put(clk);
 	iounmap(virtbase);
 	release_mem_region(phybase, physize);
@@ -300,9 +301,9 @@ static int __init coh901327_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "could not get clock\n");
 		goto out_no_clk;
 	}
-	ret = clk_enable(clk);
+	ret = clk_prepare_enable(clk);
 	if (ret) {
-		dev_err(&pdev->dev, "could not enable clock\n");
+		dev_err(&pdev->dev, "could not prepare and enable clock\n");
 		goto out_no_clk_enable;
 	}
 
@@ -369,7 +370,7 @@ static int __init coh901327_probe(struct platform_device *pdev)
 out_no_wdog:
 	free_irq(irq, pdev);
 out_no_irq:
-	clk_disable(clk);
+	clk_disable_unprepare(clk);
 out_no_clk_enable:
 	clk_put(clk);
 out_no_clk:
diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c
index c65b0a5..016bd93 100644
--- a/drivers/watchdog/f71808e_wdt.c
+++ b/drivers/watchdog/f71808e_wdt.c
@@ -56,6 +56,7 @@
 #define SIO_F71858_ID		0x0507	/* Chipset ID */
 #define SIO_F71862_ID		0x0601	/* Chipset ID */
 #define SIO_F71869_ID		0x0814	/* Chipset ID */
+#define SIO_F71869A_ID		0x1007	/* Chipset ID */
 #define SIO_F71882_ID		0x0541	/* Chipset ID */
 #define SIO_F71889_ID		0x0723	/* Chipset ID */
 
@@ -195,7 +196,7 @@ static inline int superio_enter(int base)
 		return -EBUSY;
 	}
 
-	/* according to the datasheet the key must be send twice! */
+	/* according to the datasheet the key must be sent twice! */
 	outb(SIO_UNLOCK_KEY, base);
 	outb(SIO_UNLOCK_KEY, base);
 
@@ -756,6 +757,7 @@ static int __init f71808e_find(int sioaddr)
 		err = f71862fg_pin_configure(0); /* validate module parameter */
 		break;
 	case SIO_F71869_ID:
+	case SIO_F71869A_ID:
 		watchdog.type = f71869;
 		break;
 	case SIO_F71882_ID:
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 2b76381..1eff743 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -146,7 +146,7 @@ struct cmn_registers {
 }  __attribute__((packed));
 
 static unsigned int hpwdt_nmi_decoding;
-static unsigned int allow_kdump;
+static unsigned int allow_kdump = 1;
 static unsigned int is_icru;
 static DEFINE_SPINLOCK(rom_lock);
 static void *cru_rom_addr;
@@ -756,6 +756,8 @@ error:
 static void hpwdt_exit_nmi_decoding(void)
 {
 	unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
+	unregister_nmi_handler(NMI_SERR, "hpwdt");
+	unregister_nmi_handler(NMI_IO_CHECK, "hpwdt");
 	if (cru_rom_addr)
 		iounmap(cru_rom_addr);
 }
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index bc47e90..ceed39f 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -47,7 +47,7 @@
 
 /* Module and version information */
 #define DRV_NAME	"iTCO_wdt"
-#define DRV_VERSION	"1.07"
+#define DRV_VERSION	"1.10"
 
 /* Includes */
 #include <linux/module.h>		/* For module specific items */
@@ -88,8 +88,6 @@
 #define TCOv2_TMR	(TCOBASE + 0x12) /* TCOv2 Timer Initial Value	*/
 
 /* internal variables */
-static unsigned long is_active;
-static char expect_release;
 static struct {		/* this is private data for the iTCO_wdt device */
 	/* TCO version/generation */
 	unsigned int iTCO_version;
@@ -106,12 +104,12 @@ static struct {		/* this is private data for the iTCO_wdt device */
 } iTCO_wdt_private;
 
 /* module parameters */
-#define WATCHDOG_HEARTBEAT 30	/* 30 sec default heartbeat */
-static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
+#define WATCHDOG_TIMEOUT 30	/* 30 sec default heartbeat */
+static int heartbeat = WATCHDOG_TIMEOUT;  /* in seconds */
 module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
 	"5..76 (TCO v1) or 3..614 (TCO v2), default="
-				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+				__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0);
@@ -178,13 +176,13 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void)
 	return ret; /* returns: 0 = OK, -EIO = Error */
 }
 
-static int iTCO_wdt_start(void)
+static int iTCO_wdt_start(struct watchdog_device *wd_dev)
 {
 	unsigned int val;
 
 	spin_lock(&iTCO_wdt_private.io_lock);
 
-	iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, heartbeat);
+	iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, wd_dev->timeout);
 
 	/* disable chipset's NO_REBOOT bit */
 	if (iTCO_wdt_unset_NO_REBOOT_bit()) {
@@ -212,7 +210,7 @@ static int iTCO_wdt_start(void)
 	return 0;
 }
 
-static int iTCO_wdt_stop(void)
+static int iTCO_wdt_stop(struct watchdog_device *wd_dev)
 {
 	unsigned int val;
 
@@ -236,11 +234,11 @@ static int iTCO_wdt_stop(void)
 	return 0;
 }
 
-static int iTCO_wdt_keepalive(void)
+static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
 {
 	spin_lock(&iTCO_wdt_private.io_lock);
 
-	iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, heartbeat);
+	iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, wd_dev->timeout);
 
 	/* Reload the timer by writing to the TCO Timer Counter register */
 	if (iTCO_wdt_private.iTCO_version == 2)
@@ -257,7 +255,7 @@ static int iTCO_wdt_keepalive(void)
 	return 0;
 }
 
-static int iTCO_wdt_set_heartbeat(int t)
+static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
 {
 	unsigned int val16;
 	unsigned char val8;
@@ -304,14 +302,15 @@ static int iTCO_wdt_set_heartbeat(int t)
 			return -EINVAL;
 	}
 
-	heartbeat = t;
+	wd_dev->timeout = t;
 	return 0;
 }
 
-static int iTCO_wdt_get_timeleft(int *time_left)
+static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev)
 {
 	unsigned int val16;
 	unsigned char val8;
+	unsigned int time_left = 0;
 
 	/* read the TCO Timer */
 	if (iTCO_wdt_private.iTCO_version == 2) {
@@ -320,7 +319,7 @@ static int iTCO_wdt_get_timeleft(int *time_left)
 		val16 &= 0x3ff;
 		spin_unlock(&iTCO_wdt_private.io_lock);
 
-		*time_left = (val16 * 6) / 10;
+		time_left = (val16 * 6) / 10;
 	} else if (iTCO_wdt_private.iTCO_version == 1) {
 		spin_lock(&iTCO_wdt_private.io_lock);
 		val8 = inb(TCO_RLD);
@@ -329,156 +328,35 @@ static int iTCO_wdt_get_timeleft(int *time_left)
 			val8 += (inb(TCOv1_TMR) & 0x3f);
 		spin_unlock(&iTCO_wdt_private.io_lock);
 
-		*time_left = (val8 * 6) / 10;
-	} else
-		return -EINVAL;
-	return 0;
-}
-
-/*
- *	/dev/watchdog handling
- */
-
-static int iTCO_wdt_open(struct inode *inode, struct file *file)
-{
-	/* /dev/watchdog can only be opened once */
-	if (test_and_set_bit(0, &is_active))
-		return -EBUSY;
-
-	/*
-	 *      Reload and activate timer
-	 */
-	iTCO_wdt_start();
-	return nonseekable_open(inode, file);
-}
-
-static int iTCO_wdt_release(struct inode *inode, struct file *file)
-{
-	/*
-	 *      Shut off the timer.
-	 */
-	if (expect_release == 42) {
-		iTCO_wdt_stop();
-	} else {
-		pr_crit("Unexpected close, not stopping watchdog!\n");
-		iTCO_wdt_keepalive();
-	}
-	clear_bit(0, &is_active);
-	expect_release = 0;
-	return 0;
-}
-
-static ssize_t iTCO_wdt_write(struct file *file, const char __user *data,
-			      size_t len, loff_t *ppos)
-{
-	/* See if we got the magic character 'V' and reload the timer */
-	if (len) {
-		if (!nowayout) {
-			size_t i;
-
-			/* note: just in case someone wrote the magic
-			   character five months ago... */
-			expect_release = 0;
-
-			/* scan to see whether or not we got the
-			   magic character */
-			for (i = 0; i != len; i++) {
-				char c;
-				if (get_user(c, data + i))
-					return -EFAULT;
-				if (c == 'V')
-					expect_release = 42;
-			}
-		}
-
-		/* someone wrote to us, we should reload the timer */
-		iTCO_wdt_keepalive();
-	}
-	return len;
-}
-
-static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
-							unsigned long arg)
-{
-	int new_options, retval = -EINVAL;
-	int new_heartbeat;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-	static const struct watchdog_info ident = {
-		.options =		WDIOF_SETTIMEOUT |
-					WDIOF_KEEPALIVEPING |
-					WDIOF_MAGICCLOSE,
-		.firmware_version =	0,
-		.identity =		DRV_NAME,
-	};
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
-	case WDIOC_GETSTATUS:
-	case WDIOC_GETBOOTSTATUS:
-		return put_user(0, p);
-
-	case WDIOC_SETOPTIONS:
-	{
-		if (get_user(new_options, p))
-			return -EFAULT;
-
-		if (new_options & WDIOS_DISABLECARD) {
-			iTCO_wdt_stop();
-			retval = 0;
-		}
-		if (new_options & WDIOS_ENABLECARD) {
-			iTCO_wdt_keepalive();
-			iTCO_wdt_start();
-			retval = 0;
-		}
-		return retval;
-	}
-	case WDIOC_KEEPALIVE:
-		iTCO_wdt_keepalive();
-		return 0;
-
-	case WDIOC_SETTIMEOUT:
-	{
-		if (get_user(new_heartbeat, p))
-			return -EFAULT;
-		if (iTCO_wdt_set_heartbeat(new_heartbeat))
-			return -EINVAL;
-		iTCO_wdt_keepalive();
-		/* Fall */
-	}
-	case WDIOC_GETTIMEOUT:
-		return put_user(heartbeat, p);
-	case WDIOC_GETTIMELEFT:
-	{
-		int time_left;
-		if (iTCO_wdt_get_timeleft(&time_left))
-			return -EINVAL;
-		return put_user(time_left, p);
-	}
-	default:
-		return -ENOTTY;
+		time_left = (val8 * 6) / 10;
 	}
+	return time_left;
 }
 
 /*
  *	Kernel Interfaces
  */
 
-static const struct file_operations iTCO_wdt_fops = {
+static const struct watchdog_info ident = {
+	.options =		WDIOF_SETTIMEOUT |
+				WDIOF_KEEPALIVEPING |
+				WDIOF_MAGICCLOSE,
+	.firmware_version =	0,
+	.identity =		DRV_NAME,
+};
+
+static const struct watchdog_ops iTCO_wdt_ops = {
 	.owner =		THIS_MODULE,
-	.llseek =		no_llseek,
-	.write =		iTCO_wdt_write,
-	.unlocked_ioctl =	iTCO_wdt_ioctl,
-	.open =			iTCO_wdt_open,
-	.release =		iTCO_wdt_release,
+	.start =		iTCO_wdt_start,
+	.stop = 		iTCO_wdt_stop,
+	.ping = 		iTCO_wdt_ping,
+	.set_timeout =		iTCO_wdt_set_timeout,
+	.get_timeleft =		iTCO_wdt_get_timeleft,
 };
 
-static struct miscdevice iTCO_wdt_miscdev = {
-	.minor =	WATCHDOG_MINOR,
-	.name =		"watchdog",
-	.fops =		&iTCO_wdt_fops,
+static struct watchdog_device iTCO_wdt_watchdog_dev = {
+	.info =		&ident,
+	.ops = 		&iTCO_wdt_ops,
 };
 
 /*
@@ -489,10 +367,10 @@ static void __devexit iTCO_wdt_cleanup(void)
 {
 	/* Stop the timer before we leave */
 	if (!nowayout)
-		iTCO_wdt_stop();
+		iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
 
 	/* Deregister */
-	misc_deregister(&iTCO_wdt_miscdev);
+	watchdog_unregister_device(&iTCO_wdt_watchdog_dev);
 
 	/* release resources */
 	release_region(iTCO_wdt_private.tco_res->start,
@@ -605,20 +483,25 @@ static int __devinit iTCO_wdt_probe(struct platform_device *dev)
 	outw(0x0002, TCO2_STS);	/* Clear SECOND_TO_STS bit */
 	outw(0x0004, TCO2_STS);	/* Clear BOOT_STS bit */
 
+	iTCO_wdt_watchdog_dev.bootstatus = 0;
+	iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT;
+	watchdog_set_nowayout(&iTCO_wdt_watchdog_dev, nowayout);
+	iTCO_wdt_watchdog_dev.parent = dev->dev.parent;
+
 	/* Make sure the watchdog is not running */
-	iTCO_wdt_stop();
+	iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
 
 	/* Check that the heartbeat value is within it's range;
 	   if not reset to the default */
-	if (iTCO_wdt_set_heartbeat(heartbeat)) {
-		iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
-		pr_info("timeout value out of range, using %d\n", heartbeat);
+	if (iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, heartbeat)) {
+		iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, WATCHDOG_TIMEOUT);
+		pr_info("timeout value out of range, using %d\n",
+			WATCHDOG_TIMEOUT);
 	}
 
-	ret = misc_register(&iTCO_wdt_miscdev);
+	ret = watchdog_register_device(&iTCO_wdt_watchdog_dev);
 	if (ret != 0) {
-		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
-		       WATCHDOG_MINOR, ret);
+		pr_err("cannot register watchdog device (err=%d)\n", ret);
 		goto unreg_tco;
 	}
 
@@ -659,7 +542,7 @@ static int __devexit iTCO_wdt_remove(struct platform_device *dev)
 
 static void iTCO_wdt_shutdown(struct platform_device *dev)
 {
-	iTCO_wdt_stop();
+	iTCO_wdt_stop(NULL);
 }
 
 static struct platform_driver iTCO_wdt_driver = {
@@ -699,3 +582,4 @@ MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
 MODULE_VERSION(DRV_VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
index 55d2f66..294fb4e 100644
--- a/drivers/watchdog/of_xilinx_wdt.c
+++ b/drivers/watchdog/of_xilinx_wdt.c
@@ -297,7 +297,7 @@ static int __devinit xwdt_probe(struct platform_device *pdev)
 
 	no_timeout = 0;
 
-	pfreq = (u32 *)of_get_property(pdev->dev.of_node->parent,
+	pfreq = (u32 *)of_get_property(pdev->dev.of_node,
 					"clock-frequency", NULL);
 
 	if (pfreq == NULL) {
diff --git a/drivers/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c
index 54984de..ccd6b29 100644
--- a/drivers/watchdog/sa1100_wdt.c
+++ b/drivers/watchdog/sa1100_wdt.c
@@ -54,10 +54,10 @@ static int sa1100dog_open(struct inode *inode, struct file *file)
 		return -EBUSY;
 
 	/* Activate SA1100 Watchdog timer */
-	OSMR3 = OSCR + pre_margin;
-	OSSR = OSSR_M3;
-	OWER = OWER_WME;
-	OIER |= OIER_E3;
+	writel_relaxed(readl_relaxed(OSCR) + pre_margin, OSMR3);
+	writel_relaxed(OSSR_M3, OSSR);
+	writel_relaxed(OWER_WME, OWER);
+	writel_relaxed(readl_relaxed(OIER) | OIER_E3, OIER);
 	return nonseekable_open(inode, file);
 }
 
@@ -80,7 +80,7 @@ static ssize_t sa1100dog_write(struct file *file, const char __user *data,
 {
 	if (len)
 		/* Refresh OSMR3 timer. */
-		OSMR3 = OSCR + pre_margin;
+		writel_relaxed(readl_relaxed(OSCR) + pre_margin, OSMR3);
 	return len;
 }
 
@@ -114,7 +114,7 @@ static long sa1100dog_ioctl(struct file *file, unsigned int cmd,
 		break;
 
 	case WDIOC_KEEPALIVE:
-		OSMR3 = OSCR + pre_margin;
+		writel_relaxed(readl_relaxed(OSCR) + pre_margin, OSMR3);
 		ret = 0;
 		break;
 
@@ -129,7 +129,7 @@ static long sa1100dog_ioctl(struct file *file, unsigned int cmd,
 		}
 
 		pre_margin = oscr_freq * time;
-		OSMR3 = OSCR + pre_margin;
+		writel_relaxed(readl_relaxed(OSCR) + pre_margin, OSMR3);
 		/*fall through*/
 
 	case WDIOC_GETTIMEOUT:
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 672d169..ef8edec 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -349,7 +349,7 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
 			sizeof(struct watchdog_info)) ? -EFAULT : 0;
 	case WDIOC_GETSTATUS:
 		err = watchdog_get_status(wdd, &val);
-		if (err)
+		if (err == -ENODEV)
 			return err;
 		return put_user(val, p);
 	case WDIOC_GETBOOTSTATUS:
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 8d2501e..d4dffcd 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -196,4 +196,12 @@ config XEN_ACPI_PROCESSOR
 	  called xen_acpi_processor  If you do not know what to choose, select
 	  M here. If the CPUFREQ drivers are built in, select Y here.
 
+config XEN_MCE_LOG
+	bool "Xen platform mcelog"
+	depends on XEN_DOM0 && X86_64 && X86_MCE
+	default n
+	help
+	  Allow kernel fetching MCE error from Xen platform and
+	  converting it into Linux mcelog format for mcelog tools
+
 endmenu
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index fc34886..d80bea5 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -17,7 +17,9 @@ obj-$(CONFIG_XEN_SYS_HYPERVISOR)	+= sys-hypervisor.o
 obj-$(CONFIG_XEN_PVHVM)			+= platform-pci.o
 obj-$(CONFIG_XEN_TMEM)			+= tmem.o
 obj-$(CONFIG_SWIOTLB_XEN)		+= swiotlb-xen.o
+obj-$(CONFIG_XEN_DOM0)			+= pcpu.o
 obj-$(CONFIG_XEN_DOM0)			+= pci.o acpi.o
+obj-$(CONFIG_XEN_MCE_LOG)		+= mcelog.o
 obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= xen-pciback/
 obj-$(CONFIG_XEN_PRIVCMD)		+= xen-privcmd.o
 obj-$(CONFIG_XEN_ACPI_PROCESSOR)	+= xen-acpi-processor.o
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 7595581..f14e7a1 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -869,7 +869,6 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
 		struct irq_info *info = info_for_irq(irq);
 		WARN_ON(info == NULL || info->type != IRQT_IPI);
 	}
-
  out:
 	mutex_unlock(&irq_mapping_update_lock);
 	return irq;
@@ -949,7 +948,6 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
 		struct irq_info *info = info_for_irq(irq);
 		WARN_ON(info == NULL || info->type != IRQT_VIRQ);
 	}
-
 out:
 	mutex_unlock(&irq_mapping_update_lock);
 
diff --git a/drivers/xen/mcelog.c b/drivers/xen/mcelog.c
new file mode 100644
index 0000000..8feee08
--- /dev/null
+++ b/drivers/xen/mcelog.c
@@ -0,0 +1,414 @@
+/******************************************************************************
+ * mcelog.c
+ * Driver for receiving and transferring machine check error infomation
+ *
+ * Copyright (c) 2012 Intel Corporation
+ * Author: Liu, Jinsong <jinsong.liu@intel.com>
+ * Author: Jiang, Yunhong <yunhong.jiang@intel.com>
+ * Author: Ke, Liping <liping.ke@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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * 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/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/capability.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+
+#include <xen/interface/xen.h>
+#include <xen/events.h>
+#include <xen/interface/vcpu.h>
+#include <xen/xen.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#define XEN_MCELOG "xen_mcelog: "
+
+static struct mc_info g_mi;
+static struct mcinfo_logical_cpu *g_physinfo;
+static uint32_t ncpus;
+
+static DEFINE_MUTEX(mcelog_lock);
+
+static struct xen_mce_log xen_mcelog = {
+	.signature	= XEN_MCE_LOG_SIGNATURE,
+	.len		= XEN_MCE_LOG_LEN,
+	.recordlen	= sizeof(struct xen_mce),
+};
+
+static DEFINE_SPINLOCK(xen_mce_chrdev_state_lock);
+static int xen_mce_chrdev_open_count;	/* #times opened */
+static int xen_mce_chrdev_open_exclu;	/* already open exclusive? */
+
+static DECLARE_WAIT_QUEUE_HEAD(xen_mce_chrdev_wait);
+
+static int xen_mce_chrdev_open(struct inode *inode, struct file *file)
+{
+	spin_lock(&xen_mce_chrdev_state_lock);
+
+	if (xen_mce_chrdev_open_exclu ||
+	    (xen_mce_chrdev_open_count && (file->f_flags & O_EXCL))) {
+		spin_unlock(&xen_mce_chrdev_state_lock);
+
+		return -EBUSY;
+	}
+
+	if (file->f_flags & O_EXCL)
+		xen_mce_chrdev_open_exclu = 1;
+	xen_mce_chrdev_open_count++;
+
+	spin_unlock(&xen_mce_chrdev_state_lock);
+
+	return nonseekable_open(inode, file);
+}
+
+static int xen_mce_chrdev_release(struct inode *inode, struct file *file)
+{
+	spin_lock(&xen_mce_chrdev_state_lock);
+
+	xen_mce_chrdev_open_count--;
+	xen_mce_chrdev_open_exclu = 0;
+
+	spin_unlock(&xen_mce_chrdev_state_lock);
+
+	return 0;
+}
+
+static ssize_t xen_mce_chrdev_read(struct file *filp, char __user *ubuf,
+				size_t usize, loff_t *off)
+{
+	char __user *buf = ubuf;
+	unsigned num;
+	int i, err;
+
+	mutex_lock(&mcelog_lock);
+
+	num = xen_mcelog.next;
+
+	/* Only supports full reads right now */
+	err = -EINVAL;
+	if (*off != 0 || usize < XEN_MCE_LOG_LEN*sizeof(struct xen_mce))
+		goto out;
+
+	err = 0;
+	for (i = 0; i < num; i++) {
+		struct xen_mce *m = &xen_mcelog.entry[i];
+
+		err |= copy_to_user(buf, m, sizeof(*m));
+		buf += sizeof(*m);
+	}
+
+	memset(xen_mcelog.entry, 0, num * sizeof(struct xen_mce));
+	xen_mcelog.next = 0;
+
+	if (err)
+		err = -EFAULT;
+
+out:
+	mutex_unlock(&mcelog_lock);
+
+	return err ? err : buf - ubuf;
+}
+
+static unsigned int xen_mce_chrdev_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &xen_mce_chrdev_wait, wait);
+
+	if (xen_mcelog.next)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+static long xen_mce_chrdev_ioctl(struct file *f, unsigned int cmd,
+				unsigned long arg)
+{
+	int __user *p = (int __user *)arg;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	switch (cmd) {
+	case MCE_GET_RECORD_LEN:
+		return put_user(sizeof(struct xen_mce), p);
+	case MCE_GET_LOG_LEN:
+		return put_user(XEN_MCE_LOG_LEN, p);
+	case MCE_GETCLEAR_FLAGS: {
+		unsigned flags;
+
+		do {
+			flags = xen_mcelog.flags;
+		} while (cmpxchg(&xen_mcelog.flags, flags, 0) != flags);
+
+		return put_user(flags, p);
+	}
+	default:
+		return -ENOTTY;
+	}
+}
+
+static const struct file_operations xen_mce_chrdev_ops = {
+	.open			= xen_mce_chrdev_open,
+	.release		= xen_mce_chrdev_release,
+	.read			= xen_mce_chrdev_read,
+	.poll			= xen_mce_chrdev_poll,
+	.unlocked_ioctl		= xen_mce_chrdev_ioctl,
+	.llseek			= no_llseek,
+};
+
+static struct miscdevice xen_mce_chrdev_device = {
+	MISC_MCELOG_MINOR,
+	"mcelog",
+	&xen_mce_chrdev_ops,
+};
+
+/*
+ * Caller should hold the mcelog_lock
+ */
+static void xen_mce_log(struct xen_mce *mce)
+{
+	unsigned entry;
+
+	entry = xen_mcelog.next;
+
+	/*
+	 * When the buffer fills up discard new entries.
+	 * Assume that the earlier errors are the more
+	 * interesting ones:
+	 */
+	if (entry >= XEN_MCE_LOG_LEN) {
+		set_bit(XEN_MCE_OVERFLOW,
+			(unsigned long *)&xen_mcelog.flags);
+		return;
+	}
+
+	memcpy(xen_mcelog.entry + entry, mce, sizeof(struct xen_mce));
+
+	xen_mcelog.next++;
+}
+
+static int convert_log(struct mc_info *mi)
+{
+	struct mcinfo_common *mic;
+	struct mcinfo_global *mc_global;
+	struct mcinfo_bank *mc_bank;
+	struct xen_mce m;
+	uint32_t i;
+
+	mic = NULL;
+	x86_mcinfo_lookup(&mic, mi, MC_TYPE_GLOBAL);
+	if (unlikely(!mic)) {
+		pr_warning(XEN_MCELOG "Failed to find global error info\n");
+		return -ENODEV;
+	}
+
+	memset(&m, 0, sizeof(struct xen_mce));
+
+	mc_global = (struct mcinfo_global *)mic;
+	m.mcgstatus = mc_global->mc_gstatus;
+	m.apicid = mc_global->mc_apicid;
+
+	for (i = 0; i < ncpus; i++)
+		if (g_physinfo[i].mc_apicid == m.apicid)
+			break;
+	if (unlikely(i == ncpus)) {
+		pr_warning(XEN_MCELOG "Failed to match cpu with apicid %d\n",
+			   m.apicid);
+		return -ENODEV;
+	}
+
+	m.socketid = g_physinfo[i].mc_chipid;
+	m.cpu = m.extcpu = g_physinfo[i].mc_cpunr;
+	m.cpuvendor = (__u8)g_physinfo[i].mc_vendor;
+	m.mcgcap = g_physinfo[i].mc_msrvalues[__MC_MSR_MCGCAP].value;
+
+	mic = NULL;
+	x86_mcinfo_lookup(&mic, mi, MC_TYPE_BANK);
+	if (unlikely(!mic)) {
+		pr_warning(XEN_MCELOG "Fail to find bank error info\n");
+		return -ENODEV;
+	}
+
+	do {
+		if ((!mic) || (mic->size == 0) ||
+		    (mic->type != MC_TYPE_GLOBAL   &&
+		     mic->type != MC_TYPE_BANK     &&
+		     mic->type != MC_TYPE_EXTENDED &&
+		     mic->type != MC_TYPE_RECOVERY))
+			break;
+
+		if (mic->type == MC_TYPE_BANK) {
+			mc_bank = (struct mcinfo_bank *)mic;
+			m.misc = mc_bank->mc_misc;
+			m.status = mc_bank->mc_status;
+			m.addr = mc_bank->mc_addr;
+			m.tsc = mc_bank->mc_tsc;
+			m.bank = mc_bank->mc_bank;
+			m.finished = 1;
+			/*log this record*/
+			xen_mce_log(&m);
+		}
+		mic = x86_mcinfo_next(mic);
+	} while (1);
+
+	return 0;
+}
+
+static int mc_queue_handle(uint32_t flags)
+{
+	struct xen_mc mc_op;
+	int ret = 0;
+
+	mc_op.cmd = XEN_MC_fetch;
+	mc_op.interface_version = XEN_MCA_INTERFACE_VERSION;
+	set_xen_guest_handle(mc_op.u.mc_fetch.data, &g_mi);
+	do {
+		mc_op.u.mc_fetch.flags = flags;
+		ret = HYPERVISOR_mca(&mc_op);
+		if (ret) {
+			pr_err(XEN_MCELOG "Failed to fetch %s error log\n",
+			       (flags == XEN_MC_URGENT) ?
+			       "urgnet" : "nonurgent");
+			break;
+		}
+
+		if (mc_op.u.mc_fetch.flags & XEN_MC_NODATA ||
+		    mc_op.u.mc_fetch.flags & XEN_MC_FETCHFAILED)
+			break;
+		else {
+			ret = convert_log(&g_mi);
+			if (ret)
+				pr_warning(XEN_MCELOG
+					   "Failed to convert this error log, "
+					   "continue acking it anyway\n");
+
+			mc_op.u.mc_fetch.flags = flags | XEN_MC_ACK;
+			ret = HYPERVISOR_mca(&mc_op);
+			if (ret) {
+				pr_err(XEN_MCELOG
+				       "Failed to ack previous error log\n");
+				break;
+			}
+		}
+	} while (1);
+
+	return ret;
+}
+
+/* virq handler for machine check error info*/
+static void xen_mce_work_fn(struct work_struct *work)
+{
+	int err;
+
+	mutex_lock(&mcelog_lock);
+
+	/* urgent mc_info */
+	err = mc_queue_handle(XEN_MC_URGENT);
+	if (err)
+		pr_err(XEN_MCELOG
+		       "Failed to handle urgent mc_info queue, "
+		       "continue handling nonurgent mc_info queue anyway.\n");
+
+	/* nonurgent mc_info */
+	err = mc_queue_handle(XEN_MC_NONURGENT);
+	if (err)
+		pr_err(XEN_MCELOG
+		       "Failed to handle nonurgent mc_info queue.\n");
+
+	/* wake processes polling /dev/mcelog */
+	wake_up_interruptible(&xen_mce_chrdev_wait);
+
+	mutex_unlock(&mcelog_lock);
+}
+static DECLARE_WORK(xen_mce_work, xen_mce_work_fn);
+
+static irqreturn_t xen_mce_interrupt(int irq, void *dev_id)
+{
+	schedule_work(&xen_mce_work);
+	return IRQ_HANDLED;
+}
+
+static int bind_virq_for_mce(void)
+{
+	int ret;
+	struct xen_mc mc_op;
+
+	memset(&mc_op, 0, sizeof(struct xen_mc));
+
+	/* Fetch physical CPU Numbers */
+	mc_op.cmd = XEN_MC_physcpuinfo;
+	mc_op.interface_version = XEN_MCA_INTERFACE_VERSION;
+	set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo);
+	ret = HYPERVISOR_mca(&mc_op);
+	if (ret) {
+		pr_err(XEN_MCELOG "Failed to get CPU numbers\n");
+		return ret;
+	}
+
+	/* Fetch each CPU Physical Info for later reference*/
+	ncpus = mc_op.u.mc_physcpuinfo.ncpus;
+	g_physinfo = kcalloc(ncpus, sizeof(struct mcinfo_logical_cpu),
+			     GFP_KERNEL);
+	if (!g_physinfo)
+		return -ENOMEM;
+	set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo);
+	ret = HYPERVISOR_mca(&mc_op);
+	if (ret) {
+		pr_err(XEN_MCELOG "Failed to get CPU info\n");
+		kfree(g_physinfo);
+		return ret;
+	}
+
+	ret  = bind_virq_to_irqhandler(VIRQ_MCA, 0,
+				       xen_mce_interrupt, 0, "mce", NULL);
+	if (ret < 0) {
+		pr_err(XEN_MCELOG "Failed to bind virq\n");
+		kfree(g_physinfo);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __init xen_late_init_mcelog(void)
+{
+	/* Only DOM0 is responsible for MCE logging */
+	if (xen_initial_domain()) {
+		/* register character device /dev/mcelog for xen mcelog */
+		if (misc_register(&xen_mce_chrdev_device))
+			return -ENODEV;
+		return bind_virq_for_mce();
+	}
+
+	return -ENODEV;
+}
+device_initcall(xen_late_init_mcelog);
diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c
new file mode 100644
index 0000000..067fcfa
--- /dev/null
+++ b/drivers/xen/pcpu.c
@@ -0,0 +1,371 @@
+/******************************************************************************
+ * pcpu.c
+ * Management physical cpu in dom0, get pcpu info and provide sys interface
+ *
+ * Copyright (c) 2012 Intel Corporation
+ * Author: Liu, Jinsong <jinsong.liu@intel.com>
+ * Author: Jiang, Yunhong <yunhong.jiang@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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * 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/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/cpu.h>
+#include <linux/stat.h>
+#include <linux/capability.h>
+
+#include <xen/xen.h>
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/interface/platform.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#define XEN_PCPU "xen_cpu: "
+
+/*
+ * @cpu_id: Xen physical cpu logic number
+ * @flags: Xen physical cpu status flag
+ * - XEN_PCPU_FLAGS_ONLINE: cpu is online
+ * - XEN_PCPU_FLAGS_INVALID: cpu is not present
+ */
+struct pcpu {
+	struct list_head list;
+	struct device dev;
+	uint32_t cpu_id;
+	uint32_t flags;
+};
+
+static struct bus_type xen_pcpu_subsys = {
+	.name = "xen_cpu",
+	.dev_name = "xen_cpu",
+};
+
+static DEFINE_MUTEX(xen_pcpu_lock);
+
+static LIST_HEAD(xen_pcpus);
+
+static int xen_pcpu_down(uint32_t cpu_id)
+{
+	struct xen_platform_op op = {
+		.cmd			= XENPF_cpu_offline,
+		.interface_version	= XENPF_INTERFACE_VERSION,
+		.u.cpu_ol.cpuid		= cpu_id,
+	};
+
+	return HYPERVISOR_dom0_op(&op);
+}
+
+static int xen_pcpu_up(uint32_t cpu_id)
+{
+	struct xen_platform_op op = {
+		.cmd			= XENPF_cpu_online,
+		.interface_version	= XENPF_INTERFACE_VERSION,
+		.u.cpu_ol.cpuid		= cpu_id,
+	};
+
+	return HYPERVISOR_dom0_op(&op);
+}
+
+static ssize_t show_online(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	struct pcpu *cpu = container_of(dev, struct pcpu, dev);
+
+	return sprintf(buf, "%u\n", !!(cpu->flags & XEN_PCPU_FLAGS_ONLINE));
+}
+
+static ssize_t __ref store_online(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct pcpu *pcpu = container_of(dev, struct pcpu, dev);
+	unsigned long long val;
+	ssize_t ret;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (kstrtoull(buf, 0, &val) < 0)
+		return -EINVAL;
+
+	switch (val) {
+	case 0:
+		ret = xen_pcpu_down(pcpu->cpu_id);
+		break;
+	case 1:
+		ret = xen_pcpu_up(pcpu->cpu_id);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret >= 0)
+		ret = count;
+	return ret;
+}
+static DEVICE_ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online);
+
+static bool xen_pcpu_online(uint32_t flags)
+{
+	return !!(flags & XEN_PCPU_FLAGS_ONLINE);
+}
+
+static void pcpu_online_status(struct xenpf_pcpuinfo *info,
+			       struct pcpu *pcpu)
+{
+	if (xen_pcpu_online(info->flags) &&
+	   !xen_pcpu_online(pcpu->flags)) {
+		/* the pcpu is onlined */
+		pcpu->flags |= XEN_PCPU_FLAGS_ONLINE;
+		kobject_uevent(&pcpu->dev.kobj, KOBJ_ONLINE);
+	} else if (!xen_pcpu_online(info->flags) &&
+		    xen_pcpu_online(pcpu->flags)) {
+		/* The pcpu is offlined */
+		pcpu->flags &= ~XEN_PCPU_FLAGS_ONLINE;
+		kobject_uevent(&pcpu->dev.kobj, KOBJ_OFFLINE);
+	}
+}
+
+static struct pcpu *get_pcpu(uint32_t cpu_id)
+{
+	struct pcpu *pcpu;
+
+	list_for_each_entry(pcpu, &xen_pcpus, list) {
+		if (pcpu->cpu_id == cpu_id)
+			return pcpu;
+	}
+
+	return NULL;
+}
+
+static void pcpu_release(struct device *dev)
+{
+	struct pcpu *pcpu = container_of(dev, struct pcpu, dev);
+
+	list_del(&pcpu->list);
+	kfree(pcpu);
+}
+
+static void unregister_and_remove_pcpu(struct pcpu *pcpu)
+{
+	struct device *dev;
+
+	if (!pcpu)
+		return;
+
+	dev = &pcpu->dev;
+	if (dev->id)
+		device_remove_file(dev, &dev_attr_online);
+
+	/* pcpu remove would be implicitly done */
+	device_unregister(dev);
+}
+
+static int register_pcpu(struct pcpu *pcpu)
+{
+	struct device *dev;
+	int err = -EINVAL;
+
+	if (!pcpu)
+		return err;
+
+	dev = &pcpu->dev;
+	dev->bus = &xen_pcpu_subsys;
+	dev->id = pcpu->cpu_id;
+	dev->release = pcpu_release;
+
+	err = device_register(dev);
+	if (err) {
+		pcpu_release(dev);
+		return err;
+	}
+
+	/*
+	 * Xen never offline cpu0 due to several restrictions
+	 * and assumptions. This basically doesn't add a sys control
+	 * to user, one cannot attempt to offline BSP.
+	 */
+	if (dev->id) {
+		err = device_create_file(dev, &dev_attr_online);
+		if (err) {
+			device_unregister(dev);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static struct pcpu *create_and_register_pcpu(struct xenpf_pcpuinfo *info)
+{
+	struct pcpu *pcpu;
+	int err;
+
+	if (info->flags & XEN_PCPU_FLAGS_INVALID)
+		return ERR_PTR(-ENODEV);
+
+	pcpu = kzalloc(sizeof(struct pcpu), GFP_KERNEL);
+	if (!pcpu)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&pcpu->list);
+	pcpu->cpu_id = info->xen_cpuid;
+	pcpu->flags = info->flags;
+
+	/* Need hold on xen_pcpu_lock before pcpu list manipulations */
+	list_add_tail(&pcpu->list, &xen_pcpus);
+
+	err = register_pcpu(pcpu);
+	if (err) {
+		pr_warning(XEN_PCPU "Failed to register pcpu%u\n",
+			   info->xen_cpuid);
+		return ERR_PTR(-ENOENT);
+	}
+
+	return pcpu;
+}
+
+/*
+ * Caller should hold the xen_pcpu_lock
+ */
+static int sync_pcpu(uint32_t cpu, uint32_t *max_cpu)
+{
+	int ret;
+	struct pcpu *pcpu = NULL;
+	struct xenpf_pcpuinfo *info;
+	struct xen_platform_op op = {
+		.cmd                   = XENPF_get_cpuinfo,
+		.interface_version     = XENPF_INTERFACE_VERSION,
+		.u.pcpu_info.xen_cpuid = cpu,
+	};
+
+	ret = HYPERVISOR_dom0_op(&op);
+	if (ret)
+		return ret;
+
+	info = &op.u.pcpu_info;
+	if (max_cpu)
+		*max_cpu = info->max_present;
+
+	pcpu = get_pcpu(cpu);
+
+	/*
+	 * Only those at cpu present map has its sys interface.
+	 */
+	if (info->flags & XEN_PCPU_FLAGS_INVALID) {
+		if (pcpu)
+			unregister_and_remove_pcpu(pcpu);
+		return 0;
+	}
+
+	if (!pcpu) {
+		pcpu = create_and_register_pcpu(info);
+		if (IS_ERR_OR_NULL(pcpu))
+			return -ENODEV;
+	} else
+		pcpu_online_status(info, pcpu);
+
+	return 0;
+}
+
+/*
+ * Sync dom0's pcpu information with xen hypervisor's
+ */
+static int xen_sync_pcpus(void)
+{
+	/*
+	 * Boot cpu always have cpu_id 0 in xen
+	 */
+	uint32_t cpu = 0, max_cpu = 0;
+	int err = 0;
+	struct pcpu *pcpu, *tmp;
+
+	mutex_lock(&xen_pcpu_lock);
+
+	while (!err && (cpu <= max_cpu)) {
+		err = sync_pcpu(cpu, &max_cpu);
+		cpu++;
+	}
+
+	if (err)
+		list_for_each_entry_safe(pcpu, tmp, &xen_pcpus, list)
+			unregister_and_remove_pcpu(pcpu);
+
+	mutex_unlock(&xen_pcpu_lock);
+
+	return err;
+}
+
+static void xen_pcpu_work_fn(struct work_struct *work)
+{
+	xen_sync_pcpus();
+}
+static DECLARE_WORK(xen_pcpu_work, xen_pcpu_work_fn);
+
+static irqreturn_t xen_pcpu_interrupt(int irq, void *dev_id)
+{
+	schedule_work(&xen_pcpu_work);
+	return IRQ_HANDLED;
+}
+
+static int __init xen_pcpu_init(void)
+{
+	int irq, ret;
+
+	if (!xen_initial_domain())
+		return -ENODEV;
+
+	irq = bind_virq_to_irqhandler(VIRQ_PCPU_STATE, 0,
+				      xen_pcpu_interrupt, 0,
+				      "xen-pcpu", NULL);
+	if (irq < 0) {
+		pr_warning(XEN_PCPU "Failed to bind pcpu virq\n");
+		return irq;
+	}
+
+	ret = subsys_system_register(&xen_pcpu_subsys, NULL);
+	if (ret) {
+		pr_warning(XEN_PCPU "Failed to register pcpu subsys\n");
+		goto err1;
+	}
+
+	ret = xen_sync_pcpus();
+	if (ret) {
+		pr_warning(XEN_PCPU "Failed to sync pcpu info\n");
+		goto err2;
+	}
+
+	return 0;
+
+err2:
+	bus_unregister(&xen_pcpu_subsys);
+err1:
+	unbind_from_irqhandler(irq, NULL);
+	return ret;
+}
+arch_initcall(xen_pcpu_init);
diff --git a/drivers/xen/xen-pciback/conf_space.c b/drivers/xen/xen-pciback/conf_space.c
index 30d7be0..46ae0f9 100644
--- a/drivers/xen/xen-pciback/conf_space.c
+++ b/drivers/xen/xen-pciback/conf_space.c
@@ -124,7 +124,7 @@ static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
 	return val;
 }
 
-static int pcibios_err_to_errno(int err)
+static int xen_pcibios_err_to_errno(int err)
 {
 	switch (err) {
 	case PCIBIOS_SUCCESSFUL:
@@ -202,7 +202,7 @@ out:
 		       pci_name(dev), size, offset, value);
 
 	*ret_val = value;
-	return pcibios_err_to_errno(err);
+	return xen_pcibios_err_to_errno(err);
 }
 
 int xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value)
@@ -290,7 +290,7 @@ int xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value)
 		}
 	}
 
-	return pcibios_err_to_errno(err);
+	return xen_pcibios_err_to_errno(err);
 }
 
 void xen_pcibk_config_free_dyn_fields(struct pci_dev *dev)
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index b85efa7..392c5da 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -560,6 +560,11 @@ static int v9fs_init_inode_cache(void)
  */
 static void v9fs_destroy_inode_cache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(v9fs_inode_cache);
 }
 
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index e78956c..34c59f1 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -144,7 +144,7 @@ extern void v9fs_session_close(struct v9fs_session_info *v9ses);
 extern void v9fs_session_cancel(struct v9fs_session_info *v9ses);
 extern void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses);
 extern struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
-			struct nameidata *nameidata);
+			unsigned int flags);
 extern int v9fs_vfs_unlink(struct inode *i, struct dentry *d);
 extern int v9fs_vfs_rmdir(struct inode *i, struct dentry *d);
 extern int v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index d529437..64600b5 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -100,13 +100,13 @@ static void v9fs_dentry_release(struct dentry *dentry)
 	}
 }
 
-static int v9fs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct p9_fid *fid;
 	struct inode *inode;
 	struct v9fs_inode *v9inode;
 
-	if (nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	inode = dentry->d_inode;
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 57ccb75..cbf9dbb 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -712,88 +712,34 @@ error:
 }
 
 /**
- * v9fs_vfs_create - VFS hook to create files
+ * v9fs_vfs_create - VFS hook to create a regular file
+ *
+ * open(.., O_CREAT) is handled in v9fs_vfs_atomic_open().  This is only called
+ * for mknod(2).
+ *
  * @dir: directory inode that is being created
  * @dentry:  dentry that is being deleted
  * @mode: create permissions
- * @nd: path information
  *
  */
 
 static int
 v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		struct nameidata *nd)
+		bool excl)
 {
-	int err;
-	u32 perm;
-	int flags;
-	struct file *filp;
-	struct v9fs_inode *v9inode;
-	struct v9fs_session_info *v9ses;
-	struct p9_fid *fid, *inode_fid;
-
-	err = 0;
-	fid = NULL;
-	v9ses = v9fs_inode2v9ses(dir);
-	perm = unixmode2p9mode(v9ses, mode);
-	if (nd)
-		flags = nd->intent.open.flags;
-	else
-		flags = O_RDWR;
+	struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
+	u32 perm = unixmode2p9mode(v9ses, mode);
+	struct p9_fid *fid;
 
-	fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
-				v9fs_uflags2omode(flags,
-						v9fs_proto_dotu(v9ses)));
-	if (IS_ERR(fid)) {
-		err = PTR_ERR(fid);
-		fid = NULL;
-		goto error;
-	}
+	/* P9_OEXCL? */
+	fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_ORDWR);
+	if (IS_ERR(fid))
+		return PTR_ERR(fid);
 
 	v9fs_invalidate_inode_attr(dir);
-	/* if we are opening a file, assign the open fid to the file */
-	if (nd) {
-		v9inode = V9FS_I(dentry->d_inode);
-		mutex_lock(&v9inode->v_mutex);
-		if (v9ses->cache && !v9inode->writeback_fid &&
-		    ((flags & O_ACCMODE) != O_RDONLY)) {
-			/*
-			 * clone a fid and add it to writeback_fid
-			 * we do it during open time instead of
-			 * page dirty time via write_begin/page_mkwrite
-			 * because we want write after unlink usecase
-			 * to work.
-			 */
-			inode_fid = v9fs_writeback_fid(dentry);
-			if (IS_ERR(inode_fid)) {
-				err = PTR_ERR(inode_fid);
-				mutex_unlock(&v9inode->v_mutex);
-				goto error;
-			}
-			v9inode->writeback_fid = (void *) inode_fid;
-		}
-		mutex_unlock(&v9inode->v_mutex);
-		filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
-		if (IS_ERR(filp)) {
-			err = PTR_ERR(filp);
-			goto error;
-		}
-
-		filp->private_data = fid;
-#ifdef CONFIG_9P_FSCACHE
-		if (v9ses->cache)
-			v9fs_cache_inode_set_cookie(dentry->d_inode, filp);
-#endif
-	} else
-		p9_client_clunk(fid);
+	p9_client_clunk(fid);
 
 	return 0;
-
-error:
-	if (fid)
-		p9_client_clunk(fid);
-
-	return err;
 }
 
 /**
@@ -839,7 +785,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
  */
 
 struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
-				      struct nameidata *nameidata)
+				      unsigned int flags)
 {
 	struct dentry *res;
 	struct super_block *sb;
@@ -849,8 +795,8 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
 	char *name;
 	int result = 0;
 
-	p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
-		 dir, dentry->d_name.name, dentry, nameidata);
+	p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p flags: %x\n",
+		 dir, dentry->d_name.name, dentry, flags);
 
 	if (dentry->d_name.len > NAME_MAX)
 		return ERR_PTR(-ENAMETOOLONG);
@@ -910,6 +856,86 @@ error:
 	return ERR_PTR(result);
 }
 
+static int
+v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
+		     struct file *file, unsigned flags, umode_t mode,
+		     int *opened)
+{
+	int err;
+	u32 perm;
+	struct v9fs_inode *v9inode;
+	struct v9fs_session_info *v9ses;
+	struct p9_fid *fid, *inode_fid;
+	struct dentry *res = NULL;
+
+	if (d_unhashed(dentry)) {
+		res = v9fs_vfs_lookup(dir, dentry, 0);
+		if (IS_ERR(res))
+			return PTR_ERR(res);
+
+		if (res)
+			dentry = res;
+	}
+
+	/* Only creates */
+	if (!(flags & O_CREAT) || dentry->d_inode)
+		return finish_no_open(file, res);
+
+	err = 0;
+	fid = NULL;
+	v9ses = v9fs_inode2v9ses(dir);
+	perm = unixmode2p9mode(v9ses, mode);
+	fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
+				v9fs_uflags2omode(flags,
+						v9fs_proto_dotu(v9ses)));
+	if (IS_ERR(fid)) {
+		err = PTR_ERR(fid);
+		fid = NULL;
+		goto error;
+	}
+
+	v9fs_invalidate_inode_attr(dir);
+	v9inode = V9FS_I(dentry->d_inode);
+	mutex_lock(&v9inode->v_mutex);
+	if (v9ses->cache && !v9inode->writeback_fid &&
+	    ((flags & O_ACCMODE) != O_RDONLY)) {
+		/*
+		 * clone a fid and add it to writeback_fid
+		 * we do it during open time instead of
+		 * page dirty time via write_begin/page_mkwrite
+		 * because we want write after unlink usecase
+		 * to work.
+		 */
+		inode_fid = v9fs_writeback_fid(dentry);
+		if (IS_ERR(inode_fid)) {
+			err = PTR_ERR(inode_fid);
+			mutex_unlock(&v9inode->v_mutex);
+			goto error;
+		}
+		v9inode->writeback_fid = (void *) inode_fid;
+	}
+	mutex_unlock(&v9inode->v_mutex);
+	err = finish_open(file, dentry, generic_file_open, opened);
+	if (err)
+		goto error;
+
+	file->private_data = fid;
+#ifdef CONFIG_9P_FSCACHE
+	if (v9ses->cache)
+		v9fs_cache_inode_set_cookie(dentry->d_inode, file);
+#endif
+
+	*opened |= FILE_CREATED;
+out:
+	dput(res);
+	return err;
+
+error:
+	if (fid)
+		p9_client_clunk(fid);
+	goto out;
+}
+
 /**
  * v9fs_vfs_unlink - VFS unlink hook to delete an inode
  * @i:  inode that is being unlinked
@@ -1488,6 +1514,7 @@ out:
 static const struct inode_operations v9fs_dir_inode_operations_dotu = {
 	.create = v9fs_vfs_create,
 	.lookup = v9fs_vfs_lookup,
+	.atomic_open = v9fs_vfs_atomic_open,
 	.symlink = v9fs_vfs_symlink,
 	.link = v9fs_vfs_link,
 	.unlink = v9fs_vfs_unlink,
@@ -1502,6 +1529,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = {
 static const struct inode_operations v9fs_dir_inode_operations = {
 	.create = v9fs_vfs_create,
 	.lookup = v9fs_vfs_lookup,
+	.atomic_open = v9fs_vfs_atomic_open,
 	.unlink = v9fs_vfs_unlink,
 	.mkdir = v9fs_vfs_mkdir,
 	.rmdir = v9fs_vfs_rmdir,
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index e3dd2a1..4089554 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -230,20 +230,25 @@ int v9fs_open_to_dotl_flags(int flags)
  * @dir: directory inode that is being created
  * @dentry:  dentry that is being deleted
  * @mode: create permissions
- * @nd: path information
  *
  */
 
 static int
 v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
-		struct nameidata *nd)
+		bool excl)
+{
+	return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
+}
+
+static int
+v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
+			  struct file *file, unsigned flags, umode_t omode,
+			  int *opened)
 {
 	int err = 0;
 	gid_t gid;
-	int flags;
 	umode_t mode;
 	char *name = NULL;
-	struct file *filp;
 	struct p9_qid qid;
 	struct inode *inode;
 	struct p9_fid *fid = NULL;
@@ -251,19 +256,23 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
 	struct p9_fid *dfid, *ofid, *inode_fid;
 	struct v9fs_session_info *v9ses;
 	struct posix_acl *pacl = NULL, *dacl = NULL;
+	struct dentry *res = NULL;
 
-	v9ses = v9fs_inode2v9ses(dir);
-	if (nd)
-		flags = nd->intent.open.flags;
-	else {
-		/*
-		 * create call without LOOKUP_OPEN is due
-		 * to mknod of regular files. So use mknod
-		 * operation.
-		 */
-		return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
+	if (d_unhashed(dentry)) {
+		res = v9fs_vfs_lookup(dir, dentry, 0);
+		if (IS_ERR(res))
+			return PTR_ERR(res);
+
+		if (res)
+			dentry = res;
 	}
 
+	/* Only creates */
+	if (!(flags & O_CREAT) || dentry->d_inode)
+		return finish_no_open(file, res);
+
+	v9ses = v9fs_inode2v9ses(dir);
+
 	name = (char *) dentry->d_name.name;
 	p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n",
 		 name, flags, omode);
@@ -272,7 +281,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
 	if (IS_ERR(dfid)) {
 		err = PTR_ERR(dfid);
 		p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
-		return err;
+		goto out;
 	}
 
 	/* clone a fid to use for creation */
@@ -280,7 +289,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
 	if (IS_ERR(ofid)) {
 		err = PTR_ERR(ofid);
 		p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
-		return err;
+		goto out;
 	}
 
 	gid = v9fs_get_fsgid_for_create(dir);
@@ -345,17 +354,18 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
 	}
 	mutex_unlock(&v9inode->v_mutex);
 	/* Since we are opening a file, assign the open fid to the file */
-	filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
-	if (IS_ERR(filp)) {
-		err = PTR_ERR(filp);
+	err = finish_open(file, dentry, generic_file_open, opened);
+	if (err)
 		goto err_clunk_old_fid;
-	}
-	filp->private_data = ofid;
+	file->private_data = ofid;
 #ifdef CONFIG_9P_FSCACHE
 	if (v9ses->cache)
-		v9fs_cache_inode_set_cookie(inode, filp);
+		v9fs_cache_inode_set_cookie(inode, file);
 #endif
-	return 0;
+	*opened |= FILE_CREATED;
+out:
+	dput(res);
+	return err;
 
 error:
 	if (fid)
@@ -364,7 +374,7 @@ err_clunk_old_fid:
 	if (ofid)
 		p9_client_clunk(ofid);
 	v9fs_set_create_acl(NULL, &dacl, &pacl);
-	return err;
+	goto out;
 }
 
 /**
@@ -982,6 +992,7 @@ out:
 
 const struct inode_operations v9fs_dir_inode_operations_dotl = {
 	.create = v9fs_vfs_create_dotl,
+	.atomic_open = v9fs_vfs_atomic_open_dotl,
 	.lookup = v9fs_vfs_lookup,
 	.link = v9fs_vfs_link_dotl,
 	.symlink = v9fs_vfs_symlink_dotl,
diff --git a/fs/Kconfig b/fs/Kconfig
index f95ae3a..c8554b5 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -255,13 +255,13 @@ config LOCKD_V4
 	default y
 
 config NFS_ACL_SUPPORT
-	tristate
+	def_tristate y
+	depends on (NFS_FS && NFS_V3_ACL) || (NFSD && (NFSD_V2_ACL || NFSD_V3_ACL))
 	select FS_POSIX_ACL
 
 config NFS_COMMON
-	bool
-	depends on NFSD || NFS_FS
-	default y
+	def_bool y
+	depends on NFS_ACL_SUPPORT
 
 source "net/sunrpc/Kconfig"
 source "fs/ceph/Kconfig"
@@ -276,4 +276,64 @@ endif # NETWORK_FILESYSTEMS
 source "fs/nls/Kconfig"
 source "fs/dlm/Kconfig"
 
+config PROTECTED_LINKS
+	bool "Evaluate vulnerable link conditions"
+	default y
+	help
+	  A long-standing class of security issues is the link-based
+	  time-of-check-time-of-use race, most commonly seen in
+	  world-writable directories like /tmp. The common method of
+	  exploitation of this flaw is to cross privilege boundaries
+	  when following a given link (i.e. a root process follows
+	  a malicious symlink belonging to another user, or a hardlink
+	  created to a root-owned file).
+
+	  Enabling this adds the logic to examine these dangerous link
+	  conditions. Whether or not the dangerous link situations are
+	  allowed is controlled by PROTECTED_HARDLINKS_ENABLED and
+	  PROTECTED_SYMLINKS_ENABLED.
+
+config PROTECTED_SYMLINKS
+	depends on PROTECTED_LINKS
+	bool "Disallow symlink following in sticky world-writable dirs"
+	default y
+	help
+	  Solve ToCToU symlink race vulnerabilities by permitting symlinks
+	  to be followed only when outside a sticky world-writable directory,
+	  or when the uid of the symlink and follower match, or when the
+	  directory and symlink owners match.
+
+	  When PROC_SYSCTL is enabled, this setting can also be controlled
+	  via /proc/sys/kernel/protected_symlinks.
+
+	  See Documentation/sysctl/fs.txt for details.
+
+config PROTECTED_SYMLINKS_SYSCTL
+	depends on PROTECTED_LINKS
+	int
+	default "1" if PROTECTED_SYMLINKS
+	default "0"
+
+config PROTECTED_HARDLINKS
+	depends on PROTECTED_LINKS
+	bool "Disallow hardlink creation to non-accessible files"
+	default y
+	help
+	  Solve ToCToU hardlink race vulnerabilities by permitting hardlinks
+	  to be created only when to a regular file that is owned by the user,
+	  or is readable and writable by the user. Also blocks users from
+	  "pinning" vulnerable setuid/setgid programs from being upgraded by
+	  the administrator.
+
+	  When PROC_SYSCTL is enabled, this setting can also be controlled
+	  via /proc/sys/kernel/protected_hardlinks.
+
+	  See Documentation/sysctl/fs.txt for details.
+
+config PROTECTED_HARDLINKS_SYSCTL
+	depends on PROTECTED_LINKS
+	int
+	default "1" if PROTECTED_HARDLINKS
+	default "0"
+
 endmenu
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 3d83075a..b3be2e7 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -266,7 +266,7 @@ const struct dentry_operations adfs_dentry_operations = {
 };
 
 static struct dentry *
-adfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+adfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	struct inode *inode = NULL;
 	struct object_info obj;
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 06fdcc9..c830c85 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -246,7 +246,6 @@ static struct inode *adfs_alloc_inode(struct super_block *sb)
 static void adfs_i_callback(struct rcu_head *head)
 {
 	struct inode *inode = container_of(head, struct inode, i_rcu);
-	INIT_LIST_HEAD(&inode->i_dentry);
 	kmem_cache_free(adfs_inode_cachep, ADFS_I(inode));
 }
 
@@ -276,6 +275,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(adfs_inode_cachep);
 }
 
diff --git a/fs/affs/affs.h b/fs/affs/affs.h
index 1fceb32..6e21641 100644
--- a/fs/affs/affs.h
+++ b/fs/affs/affs.h
@@ -3,6 +3,7 @@
 #include <linux/buffer_head.h>
 #include <linux/amigaffs.h>
 #include <linux/mutex.h>
+#include <linux/workqueue.h>
 
 /* AmigaOS allows file names with up to 30 characters length.
  * Names longer than that will be silently truncated. If you
@@ -100,6 +101,10 @@ struct affs_sb_info {
 	char *s_prefix;			/* Prefix for volumes and assigns. */
 	char s_volume[32];		/* Volume prefix for absolute symlinks. */
 	spinlock_t symlink_lock;	/* protects the previous two */
+	struct super_block *sb;		/* the VFS superblock object */
+	int work_queued;		/* non-zero delayed work is queued */
+	struct delayed_work sb_work;	/* superblock flush delayed work */
+	spinlock_t work_lock;		/* protects sb_work and work_queued */
 };
 
 #define SF_INTL		0x0001		/* International filesystem. */
@@ -120,6 +125,8 @@ static inline struct affs_sb_info *AFFS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
+void affs_mark_sb_dirty(struct super_block *sb);
+
 /* amigaffs.c */
 
 extern int	affs_insert_hash(struct inode *inode, struct buffer_head *bh);
@@ -146,9 +153,9 @@ extern void	affs_free_bitmap(struct super_block *sb);
 /* namei.c */
 
 extern int	affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len);
-extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *);
+extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int);
 extern int	affs_unlink(struct inode *dir, struct dentry *dentry);
-extern int	affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *);
+extern int	affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool);
 extern int	affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
 extern int	affs_rmdir(struct inode *dir, struct dentry *dentry);
 extern int	affs_link(struct dentry *olddentry, struct inode *dir,
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index 52a6407..eb82ee5 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -122,22 +122,16 @@ affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
 }
 
 static void
-affs_fix_dcache(struct dentry *dentry, u32 entry_ino)
+affs_fix_dcache(struct inode *inode, u32 entry_ino)
 {
-	struct inode *inode = dentry->d_inode;
-	void *data = dentry->d_fsdata;
-	struct list_head *head, *next;
-
+	struct dentry *dentry;
+	struct hlist_node *p;
 	spin_lock(&inode->i_lock);
-	head = &inode->i_dentry;
-	next = head->next;
-	while (next != head) {
-		dentry = list_entry(next, struct dentry, d_alias);
+	hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
 		if (entry_ino == (u32)(long)dentry->d_fsdata) {
-			dentry->d_fsdata = data;
+			dentry->d_fsdata = (void *)inode->i_ino;
 			break;
 		}
-		next = next->next;
 	}
 	spin_unlock(&inode->i_lock);
 }
@@ -177,7 +171,11 @@ affs_remove_link(struct dentry *dentry)
 		}
 
 		affs_lock_dir(dir);
-		affs_fix_dcache(dentry, link_ino);
+		/*
+		 * if there's a dentry for that block, make it
+		 * refer to inode itself.
+		 */
+		affs_fix_dcache(inode, link_ino);
 		retval = affs_remove_hash(dir, link_bh);
 		if (retval) {
 			affs_unlock_dir(dir);
diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c
index 3e26271..a32246b 100644
--- a/fs/affs/bitmap.c
+++ b/fs/affs/bitmap.c
@@ -10,30 +10,6 @@
 #include <linux/slab.h>
 #include "affs.h"
 
-/* This is, of course, shamelessly stolen from fs/minix */
-
-static const int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
-
-static u32
-affs_count_free_bits(u32 blocksize, const void *data)
-{
-	const u32 *map;
-	u32 free;
-	u32 tmp;
-
-	map = data;
-	free = 0;
-	for (blocksize /= 4; blocksize > 0; blocksize--) {
-		tmp = *map++;
-		while (tmp) {
-			free += nibblemap[tmp & 0xf];
-			tmp >>= 4;
-		}
-	}
-
-	return free;
-}
-
 u32
 affs_count_free_blocks(struct super_block *sb)
 {
@@ -103,7 +79,7 @@ affs_free_block(struct super_block *sb, u32 block)
 	*(__be32 *)bh->b_data = cpu_to_be32(tmp - mask);
 
 	mark_buffer_dirty(bh);
-	sb->s_dirt = 1;
+	affs_mark_sb_dirty(sb);
 	bm->bm_free++;
 
 	mutex_unlock(&sbi->s_bmlock);
@@ -248,7 +224,7 @@ find_bit:
 	*(__be32 *)bh->b_data = cpu_to_be32(tmp + mask);
 
 	mark_buffer_dirty(bh);
-	sb->s_dirt = 1;
+	affs_mark_sb_dirty(sb);
 
 	mutex_unlock(&sbi->s_bmlock);
 
@@ -317,7 +293,7 @@ int affs_init_bitmap(struct super_block *sb, int *flags)
 			goto out;
 		}
 		pr_debug("AFFS: read bitmap block %d: %d\n", blk, bm->bm_key);
-		bm->bm_free = affs_count_free_bits(sb->s_blocksize - 4, bh->b_data + 4);
+		bm->bm_free = memweight(bh->b_data + 4, sb->s_blocksize - 4);
 
 		/* Don't try read the extension if this is the last block,
 		 * but we also need the right bm pointer below
@@ -367,7 +343,7 @@ int affs_init_bitmap(struct super_block *sb, int *flags)
 
 	/* recalculate bitmap count for last block */
 	bm--;
-	bm->bm_free = affs_count_free_bits(sb->s_blocksize - 4, bh->b_data + 4);
+	bm->bm_free = memweight(bh->b_data + 4, sb->s_blocksize - 4);
 
 out:
 	affs_brelse(bh);
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 4780694..ff65884 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -211,7 +211,7 @@ affs_find_entry(struct inode *dir, struct dentry *dentry)
 }
 
 struct dentry *
-affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	struct super_block *sb = dir->i_sb;
 	struct buffer_head *bh;
@@ -255,7 +255,7 @@ affs_unlink(struct inode *dir, struct dentry *dentry)
 }
 
 int
-affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd)
+affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
 {
 	struct super_block *sb = dir->i_sb;
 	struct inode	*inode;
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 0782653..2f57053 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -17,6 +17,7 @@
 #include <linux/magic.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/writeback.h>
 #include "affs.h"
 
 extern struct timezone sys_tz;
@@ -25,15 +26,17 @@ static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
 static int affs_remount (struct super_block *sb, int *flags, char *data);
 
 static void
-affs_commit_super(struct super_block *sb, int wait, int clean)
+affs_commit_super(struct super_block *sb, int wait)
 {
 	struct affs_sb_info *sbi = AFFS_SB(sb);
 	struct buffer_head *bh = sbi->s_root_bh;
 	struct affs_root_tail *tail = AFFS_ROOT_TAIL(sb, bh);
 
-	tail->bm_flag = cpu_to_be32(clean);
+	lock_buffer(bh);
 	secs_to_datestamp(get_seconds(), &tail->disk_change);
 	affs_fix_checksum(sb, bh);
+	unlock_buffer(bh);
+
 	mark_buffer_dirty(bh);
 	if (wait)
 		sync_dirty_buffer(bh);
@@ -45,9 +48,7 @@ affs_put_super(struct super_block *sb)
 	struct affs_sb_info *sbi = AFFS_SB(sb);
 	pr_debug("AFFS: put_super()\n");
 
-	if (!(sb->s_flags & MS_RDONLY) && sb->s_dirt)
-		affs_commit_super(sb, 1, 1);
-
+	cancel_delayed_work_sync(&sbi->sb_work);
 	kfree(sbi->s_prefix);
 	affs_free_bitmap(sb);
 	affs_brelse(sbi->s_root_bh);
@@ -55,26 +56,43 @@ affs_put_super(struct super_block *sb)
 	sb->s_fs_info = NULL;
 }
 
-static void
-affs_write_super(struct super_block *sb)
+static int
+affs_sync_fs(struct super_block *sb, int wait)
 {
-	lock_super(sb);
-	if (!(sb->s_flags & MS_RDONLY))
-		affs_commit_super(sb, 1, 2);
-	sb->s_dirt = 0;
-	unlock_super(sb);
+	affs_commit_super(sb, wait);
+	return 0;
+}
+
+static void flush_superblock(struct work_struct *work)
+{
+	struct affs_sb_info *sbi;
+	struct super_block *sb;
+
+	sbi = container_of(work, struct affs_sb_info, sb_work.work);
+	sb = sbi->sb;
+
+	spin_lock(&sbi->work_lock);
+	sbi->work_queued = 0;
+	spin_unlock(&sbi->work_lock);
 
-	pr_debug("AFFS: write_super() at %lu, clean=2\n", get_seconds());
+	affs_commit_super(sb, 1);
 }
 
-static int
-affs_sync_fs(struct super_block *sb, int wait)
+void affs_mark_sb_dirty(struct super_block *sb)
 {
-	lock_super(sb);
-	affs_commit_super(sb, wait, 2);
-	sb->s_dirt = 0;
-	unlock_super(sb);
-	return 0;
+	struct affs_sb_info *sbi = AFFS_SB(sb);
+	unsigned long delay;
+
+	if (sb->s_flags & MS_RDONLY)
+	       return;
+
+	spin_lock(&sbi->work_lock);
+	if (!sbi->work_queued) {
+	       delay = msecs_to_jiffies(dirty_writeback_interval * 10);
+	       queue_delayed_work(system_long_wq, &sbi->sb_work, delay);
+	       sbi->work_queued = 1;
+	}
+	spin_unlock(&sbi->work_lock);
 }
 
 static struct kmem_cache * affs_inode_cachep;
@@ -129,6 +147,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(affs_inode_cachep);
 }
 
@@ -138,7 +161,6 @@ static const struct super_operations affs_sops = {
 	.write_inode	= affs_write_inode,
 	.evict_inode	= affs_evict_inode,
 	.put_super	= affs_put_super,
-	.write_super	= affs_write_super,
 	.sync_fs	= affs_sync_fs,
 	.statfs		= affs_statfs,
 	.remount_fs	= affs_remount,
@@ -305,8 +327,11 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
 		return -ENOMEM;
 
 	sb->s_fs_info = sbi;
+	sbi->sb = sb;
 	mutex_init(&sbi->s_bmlock);
 	spin_lock_init(&sbi->symlink_lock);
+	spin_lock_init(&sbi->work_lock);
+	INIT_DELAYED_WORK(&sbi->sb_work, flush_superblock);
 
 	if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
 				&blocksize,&sbi->s_prefix,
@@ -531,6 +556,7 @@ affs_remount(struct super_block *sb, int *flags, char *data)
 		return -EINVAL;
 	}
 
+	flush_delayed_work_sync(&sbi->sb_work);
 	replace_mount_options(sb, new_opts);
 
 	sbi->s_flags = mount_flags;
@@ -549,10 +575,9 @@ affs_remount(struct super_block *sb, int *flags, char *data)
 	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
 		return 0;
 
-	if (*flags & MS_RDONLY) {
-		affs_write_super(sb);
+	if (*flags & MS_RDONLY)
 		affs_free_bitmap(sb);
-	} else
+	else
 		res = affs_init_bitmap(sb, flags);
 
 	return res;
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index e22dc4b..db47790 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -20,16 +20,16 @@
 #include "internal.h"
 
 static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
-				 struct nameidata *nd);
+				 unsigned int flags);
 static int afs_dir_open(struct inode *inode, struct file *file);
 static int afs_readdir(struct file *file, void *dirent, filldir_t filldir);
-static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd);
+static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
 static int afs_d_delete(const struct dentry *dentry);
 static void afs_d_release(struct dentry *dentry);
 static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
 				  loff_t fpos, u64 ino, unsigned dtype);
 static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		      struct nameidata *nd);
+		      bool excl);
 static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
 static int afs_rmdir(struct inode *dir, struct dentry *dentry);
 static int afs_unlink(struct inode *dir, struct dentry *dentry);
@@ -516,7 +516,7 @@ out:
  * look up an entry in a directory
  */
 static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
-				 struct nameidata *nd)
+				 unsigned int flags)
 {
 	struct afs_vnode *vnode;
 	struct afs_fid fid;
@@ -598,7 +598,7 @@ success:
  * - NOTE! the hit can be a negative hit too, so we can't assume we have an
  *   inode
  */
-static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct afs_vnode *vnode, *dir;
 	struct afs_fid uninitialized_var(fid);
@@ -607,7 +607,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 	void *dir_version;
 	int ret;
 
-	if (nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	vnode = AFS_FS_I(dentry->d_inode);
@@ -949,7 +949,7 @@ error:
  * create a regular file on an AFS filesystem
  */
 static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		      struct nameidata *nd)
+		      bool excl)
 {
 	struct afs_file_status status;
 	struct afs_callback cb;
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 298cf89..9682c33 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -22,7 +22,7 @@
 
 static struct dentry *afs_mntpt_lookup(struct inode *dir,
 				       struct dentry *dentry,
-				       struct nameidata *nd);
+				       unsigned int flags);
 static int afs_mntpt_open(struct inode *inode, struct file *file);
 static void afs_mntpt_expiry_timed_out(struct work_struct *work);
 
@@ -104,7 +104,7 @@ out:
  */
 static struct dentry *afs_mntpt_lookup(struct inode *dir,
 				       struct dentry *dentry,
-				       struct nameidata *nd)
+				       unsigned int flags)
 {
 	_enter("%p,%p{%p{%s},%s}",
 	       dir,
diff --git a/fs/afs/super.c b/fs/afs/super.c
index f02b31e..af69050 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -123,6 +123,11 @@ void __exit afs_fs_exit(void)
 		BUG();
 	}
 
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(afs_inode_cachep);
 	_leave("");
 }
diff --git a/fs/attr.c b/fs/attr.c
index 0da9095..9645d5c 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -171,6 +171,8 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
 	struct timespec now;
 	unsigned int ia_valid = attr->ia_valid;
 
+	WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex));
+
 	if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {
 		if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 			return -EPERM;
@@ -181,6 +183,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
 			inode_inc_iversion(inode);
 	}
 
+	if ((ia_valid & ATTR_SIZE) && IS_I_VERSION(inode)) {
+		if (attr->ia_size != inode->i_size)
+			inode_inc_iversion(inode);
+	}
+
 	if ((ia_valid & ATTR_MODE)) {
 		umode_t amode = attr->ia_mode;
 		/* Flag setting protected by i_mutex */
@@ -250,5 +257,4 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
 
 	return error;
 }
-
 EXPORT_SYMBOL(notify_change);
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 75e5f1c..e7396cf 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -32,7 +32,7 @@ static long autofs4_root_ioctl(struct file *,unsigned int,unsigned long);
 static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long);
 #endif
 static int autofs4_dir_open(struct inode *inode, struct file *file);
-static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
+static struct dentry *autofs4_lookup(struct inode *,struct dentry *, unsigned int);
 static struct vfsmount *autofs4_d_automount(struct path *);
 static int autofs4_d_manage(struct dentry *, bool);
 static void autofs4_dentry_release(struct dentry *);
@@ -458,7 +458,7 @@ int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
 }
 
 /* Lookups in the root directory */
-static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	struct autofs_sb_info *sbi;
 	struct autofs_info *ino;
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 1b35d6b..b1342ff 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -173,13 +173,13 @@ static const struct file_operations bad_file_ops =
 };
 
 static int bad_inode_create (struct inode *dir, struct dentry *dentry,
-		umode_t mode, struct nameidata *nd)
+		umode_t mode, bool excl)
 {
 	return -EIO;
 }
 
 static struct dentry *bad_inode_lookup(struct inode *dir,
-			struct dentry *dentry, struct nameidata *nd)
+			struct dentry *dentry, unsigned int flags)
 {
 	return ERR_PTR(-EIO);
 }
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index e18da23..962b4f8 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -34,7 +34,7 @@ static int befs_readdir(struct file *, void *, filldir_t);
 static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 static int befs_readpage(struct file *file, struct page *page);
 static sector_t befs_bmap(struct address_space *mapping, sector_t block);
-static struct dentry *befs_lookup(struct inode *, struct dentry *, struct nameidata *);
+static struct dentry *befs_lookup(struct inode *, struct dentry *, unsigned int);
 static struct inode *befs_iget(struct super_block *, unsigned long);
 static struct inode *befs_alloc_inode(struct super_block *sb);
 static void befs_destroy_inode(struct inode *inode);
@@ -159,7 +159,7 @@ befs_get_block(struct inode *inode, sector_t block,
 }
 
 static struct dentry *
-befs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	struct inode *inode = NULL;
 	struct super_block *sb = dir->i_sb;
@@ -454,6 +454,11 @@ befs_init_inodecache(void)
 static void
 befs_destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(befs_inode_cachep);
 }
 
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index d12c796..2785ef9 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -85,7 +85,7 @@ const struct file_operations bfs_dir_operations = {
 extern void dump_imap(const char *, struct super_block *);
 
 static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-						struct nameidata *nd)
+						bool excl)
 {
 	int err;
 	struct inode *inode;
@@ -133,7 +133,7 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 }
 
 static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry,
-						struct nameidata *nd)
+						unsigned int flags)
 {
 	struct inode *inode = NULL;
 	struct buffer_head *bh;
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 9870417..d5fc598 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -280,6 +280,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(bfs_inode_cachep);
 }
 
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index fa5c45b..eaa2252 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3053,10 +3053,22 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 /* super.c */
 int btrfs_parse_options(struct btrfs_root *root, char *options);
 int btrfs_sync_fs(struct super_block *sb, int wait);
+
+#ifdef CONFIG_PRINTK
+__printf(2, 3)
 void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...);
+#else
+static inline __printf(2, 3)
+void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...)
+{
+}
+#endif
+
+__printf(5, 6)
 void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
 		     unsigned int line, int errno, const char *fmt, ...);
 
+
 void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
 			       struct btrfs_root *root, const char *function,
 			       unsigned int line, int errno);
@@ -3080,6 +3092,7 @@ do {								\
 			  (errno), fmt, ##args);		\
 } while (0)
 
+__printf(5, 6)
 void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
 		   unsigned int line, int errno, const char *fmt, ...);
 
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 7b845ff..421c68e 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1114,7 +1114,7 @@ void clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 				spin_unlock(&root->fs_info->delalloc_lock);
 				btrfs_panic(root->fs_info, -EOVERFLOW,
 					  "Can't clear %lu bytes from "
-					  " dirty_mdatadata_bytes (%lu)",
+					  " dirty_mdatadata_bytes (%llu)",
 					  buf->len,
 					  root->fs_info->dirty_metadata_bytes);
 			}
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index aaa12c1..dc3eb21 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -107,6 +107,12 @@ void extent_io_exit(void)
 		list_del(&eb->leak_list);
 		kmem_cache_free(extent_buffer_cache, eb);
 	}
+
+	/*
+	 * Make sure all delayed rcu free are flushed before we
+	 * destroy caches.
+	 */
+	rcu_barrier();
 	if (extent_state_cache)
 		kmem_cache_destroy(extent_state_cache);
 	if (extent_buffer_cache)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index d8bb0db..6a93e54 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -4247,7 +4247,7 @@ static void btrfs_dentry_release(struct dentry *dentry)
 }
 
 static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
-				   struct nameidata *nd)
+				   unsigned int flags)
 {
 	struct dentry *ret;
 
@@ -4893,7 +4893,7 @@ out_unlock:
 }
 
 static int btrfs_create(struct inode *dir, struct dentry *dentry,
-			umode_t mode, struct nameidata *nd)
+			umode_t mode, bool excl)
 {
 	struct btrfs_trans_handle *trans;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
@@ -6942,7 +6942,7 @@ void btrfs_destroy_inode(struct inode *inode)
 	struct btrfs_ordered_extent *ordered;
 	struct btrfs_root *root = BTRFS_I(inode)->root;
 
-	WARN_ON(!list_empty(&inode->i_dentry));
+	WARN_ON(!hlist_empty(&inode->i_dentry));
 	WARN_ON(inode->i_data.nrpages);
 	WARN_ON(BTRFS_I(inode)->outstanding_extents);
 	WARN_ON(BTRFS_I(inode)->reserved_extents);
@@ -7016,6 +7016,11 @@ static void init_once(void *foo)
 
 void btrfs_destroy_cachep(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	if (btrfs_inode_cachep)
 		kmem_cache_destroy(btrfs_inode_cachep);
 	if (btrfs_trans_handle_cachep)
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 646ee21..790f492 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -1242,7 +1242,7 @@ static int __must_check __add_reloc_root(struct btrfs_root *root)
 		kfree(node);
 		btrfs_panic(root->fs_info, -EEXIST, "Duplicate root found "
 			    "for start=%llu while inserting into relocation "
-			    "tree\n");
+			    "tree\n", node->bytenr);
 	}
 
 	list_add_tail(&root->root_list, &rc->reloc_roots);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 0eb9a4d..2ed29f3 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -125,6 +125,7 @@ static void btrfs_handle_error(struct btrfs_fs_info *fs_info)
 	}
 }
 
+#ifdef CONFIG_PRINTK
 /*
  * __btrfs_std_error decodes expected errors from the caller and
  * invokes the approciate error response.
@@ -167,7 +168,7 @@ void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
 	va_end(args);
 }
 
-const char *logtypes[] = {
+static const char * const logtypes[] = {
 	"emergency",
 	"alert",
 	"critical",
@@ -185,22 +186,50 @@ void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...)
 	struct va_format vaf;
 	va_list args;
 	const char *type = logtypes[4];
+	int kern_level;
 
 	va_start(args, fmt);
 
-	if (fmt[0] == '<' && isdigit(fmt[1]) && fmt[2] == '>') {
-		memcpy(lvl, fmt, 3);
-		lvl[3] = '\0';
-		fmt += 3;
-		type = logtypes[fmt[1] - '0'];
+	kern_level = printk_get_level(fmt);
+	if (kern_level) {
+		size_t size = printk_skip_level(fmt) - fmt;
+		memcpy(lvl, fmt,  size);
+		lvl[size] = '\0';
+		fmt += size;
+		type = logtypes[kern_level - '0'];
 	} else
 		*lvl = '\0';
 
 	vaf.fmt = fmt;
 	vaf.va = &args;
+
 	printk("%sBTRFS %s (device %s): %pV", lvl, type, sb->s_id, &vaf);
+
+	va_end(args);
 }
 
+#else
+
+void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
+		       unsigned int line, int errno, const char *fmt, ...)
+{
+	struct super_block *sb = fs_info->sb;
+
+	/*
+	 * Special case: if the error is EROFS, and we're already
+	 * under MS_RDONLY, then it is safe here.
+	 */
+	if (errno == -EROFS && (sb->s_flags & MS_RDONLY))
+		return;
+
+	/* Don't go through full error handling during mount */
+	if (sb->s_flags & MS_BORN) {
+		save_error_info(fs_info);
+		btrfs_handle_error(fs_info);
+	}
+}
+#endif
+
 /*
  * We only mark the transaction aborted and then set the file system read-only.
  * This will prevent new transactions from starting or trying to join this
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index 7f0771d..b0b5f7c 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -567,7 +567,7 @@ lookup_again:
 			if (ret < 0)
 				goto create_error;
 			start = jiffies;
-			ret = vfs_create(dir->d_inode, next, S_IFREG, NULL);
+			ret = vfs_create(dir->d_inode, next, S_IFREG, true);
 			cachefiles_hist(cachefiles_create_histogram, start);
 			if (ret < 0)
 				goto create_error;
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c
index 0e3c092..b4d2438 100644
--- a/fs/cachefiles/rdwr.c
+++ b/fs/cachefiles/rdwr.c
@@ -918,7 +918,7 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
 	 * own time */
 	dget(object->backer);
 	mntget(cache->mnt);
-	file = dentry_open(object->backer, cache->mnt, O_RDWR,
+	file = dentry_open(object->backer, cache->mnt, O_RDWR | O_LARGEFILE,
 			   cache->cache_cred);
 	if (IS_ERR(file)) {
 		ret = PTR_ERR(file);
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 3e8094b..00894ff 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -576,7 +576,7 @@ static int is_root_ceph_dentry(struct inode *inode, struct dentry *dentry)
  * the MDS so that it gets our 'caps wanted' value in a single op.
  */
 static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
-				  struct nameidata *nd)
+				  unsigned int flags)
 {
 	struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
 	struct ceph_mds_client *mdsc = fsc->mdsc;
@@ -594,14 +594,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
 	if (err < 0)
 		return ERR_PTR(err);
 
-	/* open (but not create!) intent? */
-	if (nd &&
-	    (nd->flags & LOOKUP_OPEN) &&
-	    !(nd->intent.open.flags & O_CREAT)) {
-		int mode = nd->intent.open.create_mode & ~current->fs->umask;
-		return ceph_lookup_open(dir, dentry, nd, mode, 1);
-	}
-
 	/* can we conclude ENOENT locally? */
 	if (dentry->d_inode == NULL) {
 		struct ceph_inode_info *ci = ceph_inode(dir);
@@ -642,13 +634,51 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
 	return dentry;
 }
 
+int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
+		     struct file *file, unsigned flags, umode_t mode,
+		     int *opened)
+{
+	int err;
+	struct dentry *res = NULL;
+
+	if (!(flags & O_CREAT)) {
+		if (dentry->d_name.len > NAME_MAX)
+			return -ENAMETOOLONG;
+
+		err = ceph_init_dentry(dentry);
+		if (err < 0)
+			return err;
+
+		return ceph_lookup_open(dir, dentry, file, flags, mode, opened);
+	}
+
+	if (d_unhashed(dentry)) {
+		res = ceph_lookup(dir, dentry, 0);
+		if (IS_ERR(res))
+			return PTR_ERR(res);
+
+		if (res)
+			dentry = res;
+	}
+
+	/* We don't deal with positive dentries here */
+	if (dentry->d_inode)
+		return finish_no_open(file, res);
+
+	*opened |= FILE_CREATED;
+	err = ceph_lookup_open(dir, dentry, file, flags, mode, opened);
+	dput(res);
+
+	return err;
+}
+
 /*
  * If we do a create but get no trace back from the MDS, follow up with
  * a lookup (the VFS expects us to link up the provided dentry).
  */
 int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry)
 {
-	struct dentry *result = ceph_lookup(dir, dentry, NULL);
+	struct dentry *result = ceph_lookup(dir, dentry, 0);
 
 	if (result && !IS_ERR(result)) {
 		/*
@@ -700,25 +730,9 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
 }
 
 static int ceph_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		       struct nameidata *nd)
+		       bool excl)
 {
-	dout("create in dir %p dentry %p name '%.*s'\n",
-	     dir, dentry, dentry->d_name.len, dentry->d_name.name);
-
-	if (ceph_snap(dir) != CEPH_NOSNAP)
-		return -EROFS;
-
-	if (nd) {
-		BUG_ON((nd->flags & LOOKUP_OPEN) == 0);
-		dentry = ceph_lookup_open(dir, dentry, nd, mode, 0);
-		/* hrm, what should i do here if we get aliased? */
-		if (IS_ERR(dentry))
-			return PTR_ERR(dentry);
-		return 0;
-	}
-
-	/* fall back to mknod */
-	return ceph_mknod(dir, dentry, (mode & ~S_IFMT) | S_IFREG, 0);
+	return ceph_mknod(dir, dentry, mode, 0);
 }
 
 static int ceph_symlink(struct inode *dir, struct dentry *dentry,
@@ -1028,12 +1042,12 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
 /*
  * Check if cached dentry can be trusted.
  */
-static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	int valid = 0;
 	struct inode *dir;
 
-	if (nd && nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
@@ -1080,7 +1094,7 @@ static void ceph_d_release(struct dentry *dentry)
 }
 
 static int ceph_snapdir_d_revalidate(struct dentry *dentry,
-					  struct nameidata *nd)
+					  unsigned int flags)
 {
 	/*
 	 * Eventually, we'll want to revalidate snapped metadata
@@ -1357,6 +1371,7 @@ const struct inode_operations ceph_dir_iops = {
 	.rmdir = ceph_unlink,
 	.rename = ceph_rename,
 	.create = ceph_create,
+	.atomic_open = ceph_atomic_open,
 };
 
 const struct dentry_operations ceph_dentry_ops = {
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 988d4f3..1b81d6c 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -213,22 +213,15 @@ out:
  * may_open() fails, the struct *file gets cleaned up (i.e.
  * ceph_release gets called).  So fear not!
  */
-/*
- * flags
- *  path_lookup_open   -> LOOKUP_OPEN
- *  path_lookup_create -> LOOKUP_OPEN|LOOKUP_CREATE
- */
-struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
-				struct nameidata *nd, int mode,
-				int locked_dir)
+int ceph_lookup_open(struct inode *dir, struct dentry *dentry,
+		     struct file *file, unsigned flags, umode_t mode,
+		     int *opened)
 {
 	struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
 	struct ceph_mds_client *mdsc = fsc->mdsc;
-	struct file *file;
 	struct ceph_mds_request *req;
 	struct dentry *ret;
 	int err;
-	int flags = nd->intent.open.flags;
 
 	dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n",
 	     dentry, dentry->d_name.len, dentry->d_name.name, flags, mode);
@@ -236,7 +229,7 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
 	/* do the open */
 	req = prepare_open_request(dir->i_sb, flags, mode);
 	if (IS_ERR(req))
-		return ERR_CAST(req);
+		return PTR_ERR(req);
 	req->r_dentry = dget(dentry);
 	req->r_num_caps = 2;
 	if (flags & O_CREAT) {
@@ -254,14 +247,17 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
 		err = ceph_handle_notrace_create(dir, dentry);
 	if (err)
 		goto out;
-	file = lookup_instantiate_filp(nd, req->r_dentry, ceph_open);
-	if (IS_ERR(file))
-		err = PTR_ERR(file);
+	err = finish_open(file, req->r_dentry, ceph_open, opened);
 out:
 	ret = ceph_finish_lookup(req, dentry, err);
 	ceph_mdsc_put_request(req);
 	dout("ceph_lookup_open result=%p\n", ret);
-	return ret;
+
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+
+	dput(ret);
+	return err;
 }
 
 int ceph_release(struct inode *inode, struct file *file)
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 200bc87..ecd7f15 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -394,11 +394,8 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
 	s->s_seq = 0;
 	mutex_init(&s->s_mutex);
 
-	ceph_con_init(mdsc->fsc->client->msgr, &s->s_con);
-	s->s_con.private = s;
-	s->s_con.ops = &mds_con_ops;
-	s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS;
-	s->s_con.peer_name.num = cpu_to_le64(mds);
+	ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr,
+		CEPH_ENTITY_TYPE_MDS, mds);
 
 	spin_lock_init(&s->s_gen_ttl_lock);
 	s->s_cap_gen = 0;
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index 1e67dd7..ecc251e 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -602,6 +602,11 @@ bad_cap:
 
 static void destroy_caches(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(ceph_inode_cachep);
 	kmem_cache_destroy(ceph_cap_cachep);
 	kmem_cache_destroy(ceph_dentry_cachep);
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index fc35036..f4d5522 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -806,9 +806,9 @@ extern int ceph_copy_from_page_vector(struct page **pages,
 				    loff_t off, size_t len);
 extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
 extern int ceph_open(struct inode *inode, struct file *file);
-extern struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
-				       struct nameidata *nd, int mode,
-				       int locked_dir);
+extern int ceph_lookup_open(struct inode *dir, struct dentry *dentry,
+			     struct file *od, unsigned flags,
+			     umode_t mode, int *opened);
 extern int ceph_release(struct inode *inode, struct file *filp);
 
 /* dir.c */
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index 4b41275..a73d7f8 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -16,4 +16,4 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
 
 cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
 
-cifs-$(CONFIG_CIFS_SMB2) += smb2ops.o
+cifs-$(CONFIG_CIFS_SMB2) += smb2ops.o smb2maperror.o smb2transport.o
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index 6873bb6..ce5cbd7 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -275,7 +275,8 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
 	struct cifs_sb_info *cifs_sb;
 	struct cifs_ses *ses;
 	char *full_path;
-	int xid, i;
+	unsigned int xid;
+	int i;
 	int rc;
 	struct vfsmount *mnt;
 	struct tcon_link *tlink;
@@ -302,11 +303,11 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
 	}
 	ses = tlink_tcon(tlink)->ses;
 
-	xid = GetXid();
+	xid = get_xid();
 	rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls,
 		&num_referrals, &referrals,
 		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-	FreeXid(xid);
+	free_xid(xid);
 
 	cifs_put_tlink(tlink);
 
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 3cc1b25..f8c8464 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -1153,15 +1153,16 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
 		__u16 fid, u32 *pacllen)
 {
 	struct cifs_ntsd *pntsd = NULL;
-	int xid, rc;
+	unsigned int xid;
+	int rc;
 	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
 
 	if (IS_ERR(tlink))
 		return ERR_CAST(tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 	rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
-	FreeXid(xid);
+	free_xid(xid);
 
 	cifs_put_tlink(tlink);
 
@@ -1176,7 +1177,8 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
 {
 	struct cifs_ntsd *pntsd = NULL;
 	int oplock = 0;
-	int xid, rc, create_options = 0;
+	unsigned int xid;
+	int rc, create_options = 0;
 	__u16 fid;
 	struct cifs_tcon *tcon;
 	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
@@ -1185,7 +1187,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
 		return ERR_CAST(tlink);
 
 	tcon = tlink_tcon(tlink);
-	xid = GetXid();
+	xid = get_xid();
 
 	if (backup_cred(cifs_sb))
 		create_options |= CREATE_OPEN_BACKUP_INTENT;
@@ -1199,7 +1201,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
 	}
 
 	cifs_put_tlink(tlink);
-	FreeXid(xid);
+	free_xid(xid);
 
 	cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
 	if (rc)
@@ -1230,7 +1232,8 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
 			struct inode *inode, const char *path, int aclflag)
 {
 	int oplock = 0;
-	int xid, rc, access_flags, create_options = 0;
+	unsigned int xid;
+	int rc, access_flags, create_options = 0;
 	__u16 fid;
 	struct cifs_tcon *tcon;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -1240,7 +1243,7 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
 		return PTR_ERR(tlink);
 
 	tcon = tlink_tcon(tlink);
-	xid = GetXid();
+	xid = get_xid();
 
 	if (backup_cred(cifs_sb))
 		create_options |= CREATE_OPEN_BACKUP_INTENT;
@@ -1263,7 +1266,7 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
 
 	CIFSSMBClose(xid, tcon, fid);
 out:
-	FreeXid(xid);
+	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
 }
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 8b6e344..dc2afa5 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -158,9 +158,9 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 	int rc = -EOPNOTSUPP;
-	int xid;
+	unsigned int xid;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	buf->f_type = CIFS_MAGIC_NUMBER;
 
@@ -197,7 +197,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	if (rc)
 		rc = SMBOldQFSInfo(xid, tcon, buf);
 
-	FreeXid(xid);
+	free_xid(xid);
 	return 0;
 }
 
@@ -257,7 +257,6 @@ cifs_alloc_inode(struct super_block *sb)
 static void cifs_i_callback(struct rcu_head *head)
 {
 	struct inode *inode = container_of(head, struct inode, i_rcu);
-	INIT_LIST_HEAD(&inode->i_dentry);
 	kmem_cache_free(cifs_inode_cachep, CIFS_I(inode));
 }
 
@@ -778,6 +777,7 @@ struct file_system_type cifs_fs_type = {
 };
 const struct inode_operations cifs_dir_inode_ops = {
 	.create = cifs_create,
+	.atomic_open = cifs_atomic_open,
 	.lookup = cifs_lookup,
 	.getattr = cifs_getattr,
 	.unlink = cifs_unlink,
@@ -975,6 +975,11 @@ cifs_init_inodecache(void)
 static void
 cifs_destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(cifs_inode_cachep);
 }
 
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 6536535..1c49c5a 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -45,9 +45,12 @@ extern const struct address_space_operations cifs_addr_ops_smallbuf;
 extern const struct inode_operations cifs_dir_inode_ops;
 extern struct inode *cifs_root_iget(struct super_block *);
 extern int cifs_create(struct inode *, struct dentry *, umode_t,
-		       struct nameidata *);
+		       bool excl);
+extern int cifs_atomic_open(struct inode *, struct dentry *,
+			    struct file *, unsigned, umode_t,
+			    int *);
 extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
-				  struct nameidata *);
+				  unsigned int);
 extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
 extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
 extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 6df0cbe..480b638 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -22,6 +22,7 @@
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/slab.h>
+#include <linux/mempool.h>
 #include <linux/workqueue.h>
 #include "cifs_fs_sb.h"
 #include "cifsacl.h"
@@ -160,6 +161,7 @@ struct mid_q_entry;
 struct TCP_Server_Info;
 struct cifsFileInfo;
 struct cifs_ses;
+struct cifs_tcon;
 
 struct smb_version_operations {
 	int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -171,9 +173,11 @@ struct smb_version_operations {
 	/* check response: verify signature, map error */
 	int (*check_receive)(struct mid_q_entry *, struct TCP_Server_Info *,
 			     bool);
-	void (*add_credits)(struct TCP_Server_Info *, const unsigned int);
+	void (*add_credits)(struct TCP_Server_Info *, const unsigned int,
+			    const int);
 	void (*set_credits)(struct TCP_Server_Info *, const int);
-	int * (*get_credits_field)(struct TCP_Server_Info *);
+	int * (*get_credits_field)(struct TCP_Server_Info *, const int);
+	unsigned int (*get_credits)(struct mid_q_entry *);
 	__u64 (*get_next_mid)(struct TCP_Server_Info *);
 	/* data offset from read response message */
 	unsigned int (*read_data_offset)(char *);
@@ -187,6 +191,23 @@ struct smb_version_operations {
 	/* verify the message */
 	int (*check_message)(char *, unsigned int);
 	bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
+	/* process transaction2 response */
+	bool (*check_trans2)(struct mid_q_entry *, struct TCP_Server_Info *,
+			     char *, int);
+	/* check if we need to negotiate */
+	bool (*need_neg)(struct TCP_Server_Info *);
+	/* negotiate to the server */
+	int (*negotiate)(const unsigned int, struct cifs_ses *);
+	/* setup smb sessionn */
+	int (*sess_setup)(const unsigned int, struct cifs_ses *,
+			  const struct nls_table *);
+	/* close smb session */
+	int (*logoff)(const unsigned int, struct cifs_ses *);
+	/* connect to a server share */
+	int (*tree_connect)(const unsigned int, struct cifs_ses *, const char *,
+			    struct cifs_tcon *, const struct nls_table *);
+	/* close tree connecion */
+	int (*tree_disconnect)(const unsigned int, struct cifs_tcon *);
 };
 
 struct smb_version_values {
@@ -198,6 +219,7 @@ struct smb_version_values {
 	size_t		header_size;
 	size_t		max_header_size;
 	size_t		read_rsp_size;
+	__le16		lock_cmd;
 };
 
 #define HEADER_SIZE(server) (server->vals->header_size)
@@ -319,8 +341,13 @@ struct TCP_Server_Info {
 	struct mutex srv_mutex;
 	struct task_struct *tsk;
 	char server_GUID[16];
-	char sec_mode;
+	__u16 sec_mode;
 	bool session_estab; /* mark when very first sess is established */
+#ifdef CONFIG_CIFS_SMB2
+	int echo_credits;  /* echo reserved slots */
+	int oplock_credits;  /* oplock break reserved slots */
+	bool echoes:1; /* enable echoes */
+#endif
 	u16 dialect; /* dialect index that server chose */
 	enum securityEnum secType;
 	bool oplocks:1; /* enable oplocks */
@@ -389,9 +416,10 @@ has_credits(struct TCP_Server_Info *server, int *credits)
 }
 
 static inline void
-add_credits(struct TCP_Server_Info *server, const unsigned int add)
+add_credits(struct TCP_Server_Info *server, const unsigned int add,
+	    const int optype)
 {
-	server->ops->add_credits(server, add);
+	server->ops->add_credits(server, add, optype);
 }
 
 static inline void
@@ -453,7 +481,7 @@ struct cifs_ses {
 	char *serverOS;		/* name of operating system underlying server */
 	char *serverNOS;	/* name of network operating system of server */
 	char *serverDomain;	/* security realm of server */
-	int Suid;		/* remote smb uid  */
+	__u64 Suid;		/* remote smb uid  */
 	uid_t linux_uid;        /* overriding owner of files on the mount */
 	uid_t cred_uid;		/* owner of credentials */
 	int capabilities;
@@ -791,6 +819,7 @@ typedef void (mid_callback_t)(struct mid_q_entry *mid);
 /* one of these for every pending CIFS request to the server */
 struct mid_q_entry {
 	struct list_head qhead;	/* mids waiting on reply from this server */
+	struct TCP_Server_Info *server;	/* server corresponding to this mid */
 	__u64 mid;		/* multiplex id */
 	__u32 pid;		/* process id */
 	__u32 sequence_number;  /* for CIFS signing */
@@ -954,6 +983,11 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
 #define   CIFS_LARGE_BUF_OP 0x020    /* large request buffer */
 #define   CIFS_NO_RESP      0x040    /* no response buffer required */
 
+/* Type of request operation */
+#define   CIFS_ECHO_OP      0x080    /* echo request */
+#define   CIFS_OBREAK_OP   0x0100    /* oplock break request */
+#define   CIFS_OP_MASK     0x0180    /* mask request type */
+
 /* Security Flags: indicate type of session setup needed */
 #define   CIFSSEC_MAY_SIGN	0x00001
 #define   CIFSSEC_MAY_NTLM	0x00002
@@ -1127,6 +1161,8 @@ void cifs_oplock_break(struct work_struct *work);
 extern const struct slow_work_ops cifs_oplock_break_ops;
 extern struct workqueue_struct *cifsiod_wq;
 
+extern mempool_t *cifs_mid_poolp;
+
 /* Operations for different SMB versions */
 #define SMB1_VERSION_STRING	"1.0"
 extern struct smb_version_operations smb1_operations;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 0a6cbfe..692d283 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -37,20 +37,20 @@ extern struct smb_hdr *cifs_small_buf_get(void);
 extern void cifs_small_buf_release(void *);
 extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *,
 			unsigned int /* length */);
-extern unsigned int _GetXid(void);
-extern void _FreeXid(unsigned int);
-#define GetXid()						\
+extern unsigned int _get_xid(void);
+extern void _free_xid(unsigned int);
+#define get_xid()						\
 ({								\
-	int __xid = (int)_GetXid();				\
-	cFYI(1, "CIFS VFS: in %s as Xid: %d with uid: %d",	\
+	unsigned int __xid = _get_xid();				\
+	cFYI(1, "CIFS VFS: in %s as Xid: %u with uid: %d",	\
 	     __func__, __xid, current_fsuid());			\
 	__xid;							\
 })
 
-#define FreeXid(curr_xid)					\
+#define free_xid(curr_xid)					\
 do {								\
-	_FreeXid(curr_xid);					\
-	cFYI(1, "CIFS VFS: leaving %s (xid = %d) rc = %d",	\
+	_free_xid(curr_xid);					\
+	cFYI(1, "CIFS VFS: leaving %s (xid = %u) rc = %d",	\
 	     __func__, curr_xid, (int)rc);			\
 } while (0)
 extern int init_cifs_idmap(void);
@@ -68,14 +68,15 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
 extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
 					struct TCP_Server_Info *server);
 extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
+extern void cifs_wake_up_task(struct mid_q_entry *mid);
 extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 			   unsigned int nvec, mid_receive_t *receive,
 			   mid_callback_t *callback, void *cbdata,
-			   bool ignore_pend);
+			   const int flags);
 extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
 			struct smb_hdr * /* input */ ,
 			struct smb_hdr * /* out */ ,
-			int * /* bytes returned */ , const int long_op);
+			int * /* bytes returned */ , const int);
 extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
 			    char *in_buf, int flags);
 extern int cifs_setup_request(struct cifs_ses *, struct kvec *, unsigned int,
@@ -90,6 +91,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
 			struct smb_hdr *in_buf ,
 			struct smb_hdr *out_buf,
 			int *bytes_returned);
+extern int cifs_reconnect(struct TCP_Server_Info *server);
 extern int checkSMB(char *buf, unsigned int length);
 extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *);
 extern bool backup_cred(struct cifs_sb_info *);
@@ -112,8 +114,8 @@ extern void header_assemble(struct smb_hdr *, char /* command */ ,
 extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
 				struct cifs_ses *ses,
 				void **request_buf);
-extern int CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses,
-			     const struct nls_table *nls_cp);
+extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
+			  const struct nls_table *nls_cp);
 extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
 extern u64 cifs_UnixTimeToNT(struct timespec);
 extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
@@ -123,10 +125,10 @@ extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
 				struct file *file, struct tcon_link *tlink,
 				__u32 oplock);
-extern int cifs_posix_open(char *full_path, struct inode **pinode,
-				struct super_block *sb,
-				int mode, unsigned int f_flags,
-				__u32 *poplock, __u16 *pnetfid, int xid);
+extern int cifs_posix_open(char *full_path, struct inode **inode,
+			   struct super_block *sb, int mode,
+			   unsigned int f_flags, __u32 *oplock, __u16 *netfid,
+			   unsigned int xid);
 void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr);
 extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
 				     FILE_UNIX_BASIC_INFO *info,
@@ -139,11 +141,12 @@ extern int cifs_get_file_info(struct file *filp);
 extern int cifs_get_inode_info(struct inode **pinode,
 			const unsigned char *search_path,
 			FILE_ALL_INFO *pfile_info,
-			struct super_block *sb, int xid, const __u16 *pfid);
+			struct super_block *sb, unsigned int xid,
+			const __u16 *pfid);
 extern int cifs_get_file_info_unix(struct file *filp);
 extern int cifs_get_inode_info_unix(struct inode **pinode,
 			const unsigned char *search_path,
-			struct super_block *sb, int xid);
+			struct super_block *sb, unsigned int xid);
 extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
 			      struct cifs_fattr *fattr, struct inode *inode,
 			      const char *path, const __u16 *pfid);
@@ -178,98 +181,100 @@ extern void cifs_dfs_release_automount_timer(void);
 void cifs_proc_init(void);
 void cifs_proc_clean(void);
 
-extern int cifs_negotiate_protocol(unsigned int xid,
-				  struct cifs_ses *ses);
-extern int cifs_setup_session(unsigned int xid, struct cifs_ses *ses,
-			struct nls_table *nls_info);
-extern int CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses);
+extern int cifs_negotiate_protocol(const unsigned int xid,
+				   struct cifs_ses *ses);
+extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
+			      struct nls_table *nls_info);
+extern int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses);
 
-extern int CIFSTCon(unsigned int xid, struct cifs_ses *ses,
-			const char *tree, struct cifs_tcon *tcon,
-			const struct nls_table *);
+extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
+		    const char *tree, struct cifs_tcon *tcon,
+		    const struct nls_table *);
 
-extern int CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
+extern int CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
 		const char *searchName, const struct nls_table *nls_codepage,
 		__u16 *searchHandle, __u16 search_flags,
 		struct cifs_search_info *psrch_inf,
 		int map, const char dirsep);
 
-extern int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
+extern int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
 		__u16 searchHandle, __u16 search_flags,
 		struct cifs_search_info *psrch_inf);
 
-extern int CIFSFindClose(const int, struct cifs_tcon *tcon,
+extern int CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
 			const __u16 search_handle);
 
-extern int CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 			u16 netfid, FILE_ALL_INFO *pFindData);
-extern int CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
 			const unsigned char *searchName,
 			FILE_ALL_INFO *findData,
 			int legacy /* whether to use old info level */,
 			const struct nls_table *nls_codepage, int remap);
-extern int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
+extern int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
 			const unsigned char *searchName,
 			FILE_ALL_INFO *findData,
 			const struct nls_table *nls_codepage, int remap);
 
-extern int CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 			u16 netfid, FILE_UNIX_BASIC_INFO *pFindData);
-extern int CIFSSMBUnixQPathInfo(const int xid,
+extern int CIFSSMBUnixQPathInfo(const unsigned int xid,
 			struct cifs_tcon *tcon,
 			const unsigned char *searchName,
 			FILE_UNIX_BASIC_INFO *pFindData,
 			const struct nls_table *nls_codepage, int remap);
 
-extern int CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
+extern int CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
 			const unsigned char *searchName,
 			struct dfs_info3_param **target_nodes,
 			unsigned int *number_of_nodes_in_array,
 			const struct nls_table *nls_codepage, int remap);
 
-extern int get_dfs_path(int xid, struct cifs_ses *pSesInfo,
+extern int get_dfs_path(unsigned int xid, struct cifs_ses *pSesInfo,
 			const char *old_path,
 			const struct nls_table *nls_codepage,
 			unsigned int *pnum_referrals,
 			struct dfs_info3_param **preferrals,
 			int remap);
-extern void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon,
+extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
 				 struct cifs_sb_info *cifs_sb,
 				 struct smb_vol *vol);
-extern int CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
 			struct kstatfs *FSData);
-extern int SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon,
+extern int SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
 			struct kstatfs *FSData);
-extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon,
 			__u64 cap);
 
-extern int CIFSSMBQFSAttributeInfo(const int xid,
+extern int CIFSSMBQFSAttributeInfo(const unsigned int xid,
 			struct cifs_tcon *tcon);
-extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon);
-extern int CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon);
-extern int CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon);
+extern int CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon);
+extern int CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
 			struct kstatfs *FSData);
 
-extern int CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *fileName, const FILE_BASIC_INFO *data,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
-extern int CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 			const FILE_BASIC_INFO *data, __u16 fid,
 			__u32 pid_of_opener);
-extern int CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
-			bool delete_file, __u16 fid, __u32 pid_of_opener);
+extern int CIFSSMBSetFileDisposition(const unsigned int xid,
+				     struct cifs_tcon *tcon,
+				     bool delete_file, __u16 fid,
+				     __u32 pid_of_opener);
 #if 0
-extern int CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon,
 			char *fileName, __u16 dos_attributes,
 			const struct nls_table *nls_codepage);
 #endif /* possibly unneeded function */
-extern int CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *fileName, __u64 size,
 			bool setAllocationSizeFlag,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
-extern int CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
 			 __u64 size, __u16 fileHandle, __u32 opener_pid,
 			bool AllocSizeFlag);
 
@@ -283,114 +288,116 @@ struct cifs_unix_set_info_args {
 	dev_t	device;
 };
 
-extern int CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBUnixSetFileInfo(const unsigned int xid,
+				  struct cifs_tcon *tcon,
 				  const struct cifs_unix_set_info_args *args,
 				  u16 fid, u32 pid_of_opener);
 
-extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *pTcon,
-			char *fileName,
-			const struct cifs_unix_set_info_args *args,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
+extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
+				  struct cifs_tcon *tcon, char *file_name,
+				  const struct cifs_unix_set_info_args *args,
+				  const struct nls_table *nls_codepage,
+				  int remap_special_chars);
 
-extern int CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *newName,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
-extern int CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *name, const struct nls_table *nls_codepage,
 			int remap_special_chars);
-extern int CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon,
+extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *name, __u16 type,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
-extern int CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *name,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
-extern int CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *fromName, const char *toName,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
-extern int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
-			int netfid, const char *target_name,
-			const struct nls_table *nls_codepage,
-			int remap_special_chars);
-extern int CIFSCreateHardLink(const int xid,
+extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
+				 int netfid, const char *target_name,
+				 const struct nls_table *nls_codepage,
+				 int remap_special_chars);
+extern int CIFSCreateHardLink(const unsigned int xid,
 			struct cifs_tcon *tcon,
 			const char *fromName, const char *toName,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
-extern int CIFSUnixCreateHardLink(const int xid,
+extern int CIFSUnixCreateHardLink(const unsigned int xid,
 			struct cifs_tcon *tcon,
 			const char *fromName, const char *toName,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
-extern int CIFSUnixCreateSymLink(const int xid,
+extern int CIFSUnixCreateSymLink(const unsigned int xid,
 			struct cifs_tcon *tcon,
 			const char *fromName, const char *toName,
 			const struct nls_table *nls_codepage);
-extern int CIFSSMBUnixQuerySymLink(const int xid,
+extern int CIFSSMBUnixQuerySymLink(const unsigned int xid,
 			struct cifs_tcon *tcon,
 			const unsigned char *searchName, char **syminfo,
 			const struct nls_table *nls_codepage);
 #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
-extern int CIFSSMBQueryReparseLinkInfo(const int xid,
+extern int CIFSSMBQueryReparseLinkInfo(const unsigned int xid,
 			struct cifs_tcon *tcon,
 			const unsigned char *searchName,
 			char *symlinkinfo, const int buflen, __u16 fid,
 			const struct nls_table *nls_codepage);
 #endif /* temporarily unused until cifs_symlink fixed */
-extern int CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *fileName, const int disposition,
 			const int access_flags, const int omode,
 			__u16 *netfid, int *pOplock, FILE_ALL_INFO *,
 			const struct nls_table *nls_codepage, int remap);
-extern int SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
+extern int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *fileName, const int disposition,
 			const int access_flags, const int omode,
 			__u16 *netfid, int *pOplock, FILE_ALL_INFO *,
 			const struct nls_table *nls_codepage, int remap);
-extern int CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon,
+extern int CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
 			u32 posix_flags, __u64 mode, __u16 *netfid,
 			FILE_UNIX_BASIC_INFO *pRetData,
 			__u32 *pOplock, const char *name,
 			const struct nls_table *nls_codepage, int remap);
-extern int CIFSSMBClose(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon,
 			const int smb_file_id);
 
-extern int CIFSSMBFlush(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon,
 			const int smb_file_id);
 
-extern int CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms,
+extern int CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
 			unsigned int *nbytes, char **buf,
 			int *return_buf_type);
-extern int CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
+extern int CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
 			unsigned int *nbytes, const char *buf,
 			const char __user *ubuf, const int long_op);
-extern int CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
+extern int CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
 			unsigned int *nbytes, struct kvec *iov, const int nvec,
 			const int long_op);
-extern int CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
+extern int CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
 			const unsigned char *searchName, __u64 *inode_number,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
 
-extern int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
-		      const __u8 lock_type, const __u32 num_unlock,
-		      const __u32 num_lock, LOCKING_ANDX_RANGE *buf);
-extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
+extern int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
+		      const __u16 netfid, const __u8 lock_type,
+		      const __u32 num_unlock, const __u32 num_lock,
+		      LOCKING_ANDX_RANGE *buf);
+extern int CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
 			const __u16 netfid, const __u32 netpid, const __u64 len,
 			const __u64 offset, const __u32 numUnlock,
 			const __u32 numLock, const __u8 lockType,
 			const bool waitFlag, const __u8 oplock_level);
-extern int CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
 			const __u16 smb_file_id, const __u32 netpid,
 			const int get_flag, const __u64 len, struct file_lock *,
 			const __u16 lock_type, const bool waitFlag);
-extern int CIFSSMBTDis(const int xid, struct cifs_tcon *tcon);
+extern int CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon);
 extern int CIFSSMBEcho(struct TCP_Server_Info *server);
-extern int CIFSSMBLogoff(const int xid, struct cifs_ses *ses);
+extern int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses);
 
 extern struct cifs_ses *sesInfoAlloc(void);
 extern void sesInfoFree(struct cifs_ses *);
@@ -416,46 +423,46 @@ extern int calc_lanman_hash(const char *password, const char *cryptkey,
 				bool encrypt, char *lnm_session_key);
 #endif /* CIFS_WEAK_PW_HASH */
 #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */
-extern int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
 			const int notify_subdirs, const __u16 netfid,
 			__u32 filter, struct file *file, int multishot,
 			const struct nls_table *nls_codepage);
 #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */
-extern int CIFSSMBCopy(int xid,
+extern int CIFSSMBCopy(unsigned int xid,
 			struct cifs_tcon *source_tcon,
 			const char *fromName,
 			const __u16 target_tid,
 			const char *toName, const int flags,
 			const struct nls_table *nls_codepage,
 			int remap_special_chars);
-extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
+extern ssize_t CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
 			const unsigned char *searchName,
 			const unsigned char *ea_name, char *EAData,
 			size_t bufsize, const struct nls_table *nls_codepage,
 			int remap_special_chars);
-extern int CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
 		const char *fileName, const char *ea_name,
 		const void *ea_value, const __u16 ea_value_len,
 		const struct nls_table *nls_codepage, int remap_special_chars);
-extern int CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon,
 			__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
-extern int CIFSSMBSetCIFSACL(const int, struct cifs_tcon *, __u16,
+extern int CIFSSMBSetCIFSACL(const unsigned int, struct cifs_tcon *, __u16,
 			struct cifs_ntsd *, __u32, int);
-extern int CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
 		const unsigned char *searchName,
 		char *acl_inf, const int buflen, const int acl_type,
 		const struct nls_table *nls_codepage, int remap_special_chars);
-extern int CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
+extern int CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
 		const unsigned char *fileName,
 		const char *local_acl, const int buflen, const int acl_type,
 		const struct nls_table *nls_codepage, int remap_special_chars);
-extern int CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
+extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
 			const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
 extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
 extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr);
 extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr,
 		const unsigned char *path,
-		struct cifs_sb_info *cifs_sb, int xid);
+		struct cifs_sb_info *cifs_sb, unsigned int xid);
 extern int mdfour(unsigned char *, unsigned char *, int);
 extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
 			const struct nls_table *codepage);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 5b40073..b24ee86 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -372,7 +372,7 @@ static inline void inc_rfc1001_len(void *pSMB, int count)
 }
 
 int
-CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
+CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
 {
 	NEGOTIATE_REQ *pSMB;
 	NEGOTIATE_RSP *pSMBr;
@@ -456,7 +456,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
 			rc = -EOPNOTSUPP;
 			goto neg_err_exit;
 		}
-		server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
+		server->sec_mode = le16_to_cpu(rsp->SecurityMode);
 		server->maxReq = min_t(unsigned int,
 				       le16_to_cpu(rsp->MaxMpxCount),
 				       cifs_max_pending);
@@ -670,7 +670,7 @@ neg_err_exit:
 }
 
 int
-CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
+CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
 {
 	struct smb_hdr *smb_buffer;
 	int rc = 0;
@@ -720,7 +720,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
 	struct TCP_Server_Info *server = mid->callback_data;
 
 	DeleteMidQEntry(mid);
-	add_credits(server, 1);
+	add_credits(server, 1, CIFS_ECHO_OP);
 }
 
 int
@@ -747,7 +747,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
 	iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 
 	rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
-			     server, true);
+			     server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
 	if (rc)
 		cFYI(1, "Echo request failed: %d", rc);
 
@@ -757,7 +757,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
 }
 
 int
-CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
+CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
 {
 	LOGOFF_ANDX_REQ *pSMB;
 	int rc = 0;
@@ -804,8 +804,9 @@ session_already_dead:
 }
 
 int
-CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
-		 __u16 type, const struct nls_table *nls_codepage, int remap)
+CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
+		 const char *fileName, __u16 type,
+		 const struct nls_table *nls_codepage, int remap)
 {
 	TRANSACTION2_SPI_REQ *pSMB = NULL;
 	TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -879,8 +880,9 @@ PsxDelete:
 }
 
 int
-CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
-	       const struct nls_table *nls_codepage, int remap)
+CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
+	       const char *fileName, const struct nls_table *nls_codepage,
+	       int remap)
 {
 	DELETE_FILE_REQ *pSMB = NULL;
 	DELETE_FILE_RSP *pSMBr = NULL;
@@ -924,8 +926,9 @@ DelFileRetry:
 }
 
 int
-CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
-	     const struct nls_table *nls_codepage, int remap)
+CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
+	     const char *dirName, const struct nls_table *nls_codepage,
+	     int remap)
 {
 	DELETE_DIRECTORY_REQ *pSMB = NULL;
 	DELETE_DIRECTORY_RSP *pSMBr = NULL;
@@ -967,7 +970,7 @@ RmDirRetry:
 }
 
 int
-CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
+CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
 	     const char *name, const struct nls_table *nls_codepage, int remap)
 {
 	int rc = 0;
@@ -1010,10 +1013,11 @@ MkDirRetry:
 }
 
 int
-CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
-		__u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
-		__u32 *pOplock, const char *name,
-		const struct nls_table *nls_codepage, int remap)
+CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
+		__u32 posix_flags, __u64 mode, __u16 *netfid,
+		FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
+		const char *name, const struct nls_table *nls_codepage,
+		int remap)
 {
 	TRANSACTION2_SPI_REQ *pSMB = NULL;
 	TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -1176,7 +1180,7 @@ access_flags_to_smbopen_mode(const int access_flags)
 }
 
 int
-SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
+SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
 	    const char *fileName, const int openDisposition,
 	    const int access_flags, const int create_options, __u16 *netfid,
 	    int *pOplock, FILE_ALL_INFO *pfile_info,
@@ -1283,7 +1287,7 @@ OldOpenRetry:
 }
 
 int
-CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
+CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
 	    const char *fileName, const int openDisposition,
 	    const int access_flags, const int create_options, __u16 *netfid,
 	    int *pOplock, FILE_ALL_INFO *pfile_info,
@@ -1563,7 +1567,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
 
 	queue_work(cifsiod_wq, &rdata->work);
 	DeleteMidQEntry(mid);
-	add_credits(server, 1);
+	add_credits(server, 1, 0);
 }
 
 /* cifs_async_readv - send an async write, and set up mid to handle result */
@@ -1619,7 +1623,7 @@ cifs_async_readv(struct cifs_readdata *rdata)
 	kref_get(&rdata->refcount);
 	rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
 			     cifs_readv_receive, cifs_readv_callback,
-			     rdata, false);
+			     rdata, 0);
 
 	if (rc == 0)
 		cifs_stats_inc(&tcon->num_reads);
@@ -1631,8 +1635,8 @@ cifs_async_readv(struct cifs_readdata *rdata)
 }
 
 int
-CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
-	    char **buf, int *pbuf_type)
+CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
+	    unsigned int *nbytes, char **buf, int *pbuf_type)
 {
 	int rc = -EACCES;
 	READ_REQ *pSMB = NULL;
@@ -1743,7 +1747,7 @@ CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
 
 
 int
-CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
+CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
 	     unsigned int *nbytes, const char *buf,
 	     const char __user *ubuf, const int long_op)
 {
@@ -2010,7 +2014,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
 
 	queue_work(cifsiod_wq, &wdata->work);
 	DeleteMidQEntry(mid);
-	add_credits(tcon->ses->server, 1);
+	add_credits(tcon->ses->server, 1, 0);
 }
 
 /* cifs_async_writev - send an async write, and set up mid to handle result */
@@ -2090,7 +2094,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
 
 	kref_get(&wdata->refcount);
 	rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
-			     NULL, cifs_writev_callback, wdata, false);
+			     NULL, cifs_writev_callback, wdata, 0);
 
 	if (rc == 0)
 		cifs_stats_inc(&tcon->num_writes);
@@ -2108,7 +2112,7 @@ async_writev_out:
 }
 
 int
-CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
+CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
 	      unsigned int *nbytes, struct kvec *iov, int n_vec,
 	      const int long_op)
 {
@@ -2216,8 +2220,8 @@ CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
 	return rc;
 }
 
-int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
-	       const __u8 lock_type, const __u32 num_unlock,
+int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
+	       const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
 	       const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
 {
 	int rc = 0;
@@ -2258,7 +2262,7 @@ int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
 }
 
 int
-CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
+CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
 	    const __u16 smb_file_id, const __u32 netpid, const __u64 len,
 	    const __u64 offset, const __u32 numUnlock,
 	    const __u32 numLock, const __u8 lockType,
@@ -2268,7 +2272,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
 	LOCK_REQ *pSMB = NULL;
 /*	LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
 	int bytes_returned;
-	int timeout = 0;
+	int flags = 0;
 	__u16 count;
 
 	cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
@@ -2278,10 +2282,11 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
 		return rc;
 
 	if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
-		timeout = CIFS_ASYNC_OP; /* no response expected */
+		/* no response expected */
+		flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
 		pSMB->Timeout = 0;
 	} else if (waitFlag) {
-		timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
+		flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
 		pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
 	} else {
 		pSMB->Timeout = 0;
@@ -2314,7 +2319,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
 			(struct smb_hdr *) pSMB, &bytes_returned);
 		cifs_small_buf_release(pSMB);
 	} else {
-		rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, timeout);
+		rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
 		/* SMB buffer freed by function above */
 	}
 	cifs_stats_inc(&tcon->num_locks);
@@ -2327,7 +2332,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
 }
 
 int
-CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
+CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
 		const __u16 smb_file_id, const __u32 netpid, const int get_flag,
 		const __u64 len, struct file_lock *pLockData,
 		const __u16 lock_type, const bool waitFlag)
@@ -2465,7 +2470,7 @@ plk_err_exit:
 
 
 int
-CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
+CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
 {
 	int rc = 0;
 	CLOSE_REQ *pSMB = NULL;
@@ -2498,7 +2503,7 @@ CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
 }
 
 int
-CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
+CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
 {
 	int rc = 0;
 	FLUSH_REQ *pSMB = NULL;
@@ -2519,7 +2524,7 @@ CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
 }
 
 int
-CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
+CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
 	      const char *fromName, const char *toName,
 	      const struct nls_table *nls_codepage, int remap)
 {
@@ -2586,7 +2591,7 @@ renameRetry:
 	return rc;
 }
 
-int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
+int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
 		int netfid, const char *target_name,
 		const struct nls_table *nls_codepage, int remap)
 {
@@ -2668,9 +2673,9 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
 }
 
 int
-CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
-	    const __u16 target_tid, const char *toName, const int flags,
-	    const struct nls_table *nls_codepage, int remap)
+CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
+	    const char *fromName, const __u16 target_tid, const char *toName,
+	    const int flags, const struct nls_table *nls_codepage, int remap)
 {
 	int rc = 0;
 	COPY_REQ *pSMB = NULL;
@@ -2736,7 +2741,7 @@ copyRetry:
 }
 
 int
-CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
+CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
 		      const char *fromName, const char *toName,
 		      const struct nls_table *nls_codepage)
 {
@@ -2825,7 +2830,7 @@ createSymLinkRetry:
 }
 
 int
-CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
+CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
 		       const char *fromName, const char *toName,
 		       const struct nls_table *nls_codepage, int remap)
 {
@@ -2910,7 +2915,7 @@ createHardLinkRetry:
 }
 
 int
-CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
+CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
 		   const char *fromName, const char *toName,
 		   const struct nls_table *nls_codepage, int remap)
 {
@@ -2982,7 +2987,7 @@ winCreateHardLinkRetry:
 }
 
 int
-CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
+CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
 			const unsigned char *searchName, char **symlinkinfo,
 			const struct nls_table *nls_codepage)
 {
@@ -3087,7 +3092,7 @@ querySymLinkRetry:
  *	it is not compiled in by default until callers fixed up and more tested.
  */
 int
-CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
+CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
 			const unsigned char *searchName,
 			char *symlinkinfo, const int buflen, __u16 fid,
 			const struct nls_table *nls_codepage)
@@ -3324,7 +3329,7 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
 }
 
 int
-CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
+CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
 		   const unsigned char *searchName,
 		   char *acl_inf, const int buflen, const int acl_type,
 		   const struct nls_table *nls_codepage, int remap)
@@ -3413,7 +3418,7 @@ queryAclRetry:
 }
 
 int
-CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
+CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
 		   const unsigned char *fileName,
 		   const char *local_acl, const int buflen,
 		   const int acl_type,
@@ -3493,7 +3498,7 @@ setACLerrorExit:
 
 /* BB fix tabs in this function FIXME BB */
 int
-CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
+CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
 	       const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
 {
 	int rc = 0;
@@ -3668,7 +3673,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
 
 /* Get Security Descriptor (by handle) from remote server for a file or dir */
 int
-CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
+CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
 		  struct cifs_ntsd **acl_inf, __u32 *pbuflen)
 {
 	int rc = 0;
@@ -3760,7 +3765,7 @@ qsec_out:
 }
 
 int
-CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
+CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
 			struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
 {
 	__u16 byte_count, param_count, data_count, param_offset, data_offset;
@@ -3824,7 +3829,7 @@ setCifsAclRetry:
 
 /* Legacy Query Path Information call for lookup to old servers such
    as Win9x/WinME */
-int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
+int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
 			const unsigned char *searchName,
 			FILE_ALL_INFO *pFinfo,
 			const struct nls_table *nls_codepage, int remap)
@@ -3893,7 +3898,7 @@ QInfRetry:
 }
 
 int
-CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
+CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 		 u16 netfid, FILE_ALL_INFO *pFindData)
 {
 	struct smb_t2_qfi_req *pSMB = NULL;
@@ -3960,7 +3965,7 @@ QFileInfoRetry:
 }
 
 int
-CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
+CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
 		 const unsigned char *searchName,
 		 FILE_ALL_INFO *pFindData,
 		 int legacy /* old style infolevel */,
@@ -4061,7 +4066,7 @@ QPathInfoRetry:
 }
 
 int
-CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
+CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 		 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
 {
 	struct smb_t2_qfi_req *pSMB = NULL;
@@ -4130,7 +4135,7 @@ UnixQFileInfoRetry:
 }
 
 int
-CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
+CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
 		     const unsigned char *searchName,
 		     FILE_UNIX_BASIC_INFO *pFindData,
 		     const struct nls_table *nls_codepage, int remap)
@@ -4216,7 +4221,7 @@ UnixQPathInfoRetry:
 
 /* xid, tcon, searchName and codepage are input parms, rest are returned */
 int
-CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
+CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
 	      const char *searchName,
 	      const struct nls_table *nls_codepage,
 	      __u16 *pnetfid, __u16 search_flags,
@@ -4361,8 +4366,9 @@ findFirstRetry:
 	return rc;
 }
 
-int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle,
-		 __u16 search_flags, struct cifs_search_info *psrch_inf)
+int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
+		 __u16 searchHandle, __u16 search_flags,
+		 struct cifs_search_info *psrch_inf)
 {
 	TRANSACTION2_FNEXT_REQ *pSMB = NULL;
 	TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
@@ -4496,7 +4502,7 @@ FNext2_err_exit:
 }
 
 int
-CIFSFindClose(const int xid, struct cifs_tcon *tcon,
+CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
 	      const __u16 searchHandle)
 {
 	int rc = 0;
@@ -4528,7 +4534,7 @@ CIFSFindClose(const int xid, struct cifs_tcon *tcon,
 }
 
 int
-CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
+CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
 		      const unsigned char *searchName,
 		      __u64 *inode_number,
 		      const struct nls_table *nls_codepage, int remap)
@@ -4735,7 +4741,7 @@ parse_DFS_referrals_exit:
 }
 
 int
-CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
+CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
 		const unsigned char *searchName,
 		struct dfs_info3_param **target_nodes,
 		unsigned int *num_of_nodes,
@@ -4850,7 +4856,8 @@ GetDFSRefExit:
 
 /* Query File System Info such as free space to old servers such as Win 9x */
 int
-SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
+SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
+	      struct kstatfs *FSData)
 {
 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -4929,7 +4936,8 @@ oldQFSInfoRetry:
 }
 
 int
-CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
+CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
+	       struct kstatfs *FSData)
 {
 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -5008,7 +5016,7 @@ QFSInfoRetry:
 }
 
 int
-CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
+CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
 {
 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -5078,7 +5086,7 @@ QFSAttributeRetry:
 }
 
 int
-CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
+CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
 {
 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -5149,7 +5157,7 @@ QFSDeviceRetry:
 }
 
 int
-CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
+CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
 {
 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -5219,7 +5227,7 @@ QFSUnixRetry:
 }
 
 int
-CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
+CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
 {
 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
 	TRANSACTION2_SETFSI_REQ *pSMB = NULL;
@@ -5293,7 +5301,7 @@ SETFSUnixRetry:
 
 
 int
-CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
+CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
 		   struct kstatfs *FSData)
 {
 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
@@ -5386,8 +5394,8 @@ QFSPosixRetry:
    in Samba which this routine can run into */
 
 int
-CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
-	      __u64 size, bool SetAllocation,
+CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
+	      const char *fileName, __u64 size, bool SetAllocation,
 	      const struct nls_table *nls_codepage, int remap)
 {
 	struct smb_com_transaction2_spi_req *pSMB = NULL;
@@ -5475,7 +5483,7 @@ SetEOFRetry:
 }
 
 int
-CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
+CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
 		   __u16 fid, __u32 pid_of_opener, bool SetAllocation)
 {
 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
@@ -5557,7 +5565,7 @@ CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
    time and resort to the original setpathinfo level which takes the ancient
    DOS time format with 2 second granularity */
 int
-CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
+CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 		    const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
 {
 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
@@ -5620,7 +5628,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
 }
 
 int
-CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
+CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
 			  bool delete_file, __u16 fid, __u32 pid_of_opener)
 {
 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
@@ -5676,7 +5684,7 @@ CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
 }
 
 int
-CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
+CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
 		   const char *fileName, const FILE_BASIC_INFO *data,
 		   const struct nls_table *nls_codepage, int remap)
 {
@@ -5760,7 +5768,7 @@ SetTimesRetry:
 	  handling it anyway and NT4 was what we thought it would be needed for
 	  Do not delete it until we prove whether needed for Win9x though */
 int
-CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
+CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
 		__u16 dos_attrs, const struct nls_table *nls_codepage)
 {
 	SETATTR_REQ *pSMB = NULL;
@@ -5848,7 +5856,7 @@ cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
 }
 
 int
-CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
+CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 		       const struct cifs_unix_set_info_args *args,
 		       u16 fid, u32 pid_of_opener)
 {
@@ -5912,7 +5920,8 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
 }
 
 int
-CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
+CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
+		       char *fileName,
 		       const struct cifs_unix_set_info_args *args,
 		       const struct nls_table *nls_codepage, int remap)
 {
@@ -5999,7 +6008,7 @@ setPermsRetry:
  * the data isn't copied to it, but the length is returned.
  */
 ssize_t
-CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
+CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
 		const unsigned char *searchName, const unsigned char *ea_name,
 		char *EAData, size_t buf_size,
 		const struct nls_table *nls_codepage, int remap)
@@ -6182,8 +6191,8 @@ QAllEAsOut:
 }
 
 int
-CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
-	     const char *ea_name, const void *ea_value,
+CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
+	     const char *fileName, const char *ea_name, const void *ea_value,
 	     const __u16 ea_value_len, const struct nls_table *nls_codepage,
 	     int remap)
 {
@@ -6309,7 +6318,7 @@ SetEARetry:
  *	incompatible for network fs clients, we could instead simply
  *	expose this config flag by adding a future cifs (and smb2) notify ioctl.
  */
-int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
+int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
 		  const int notify_subdirs, const __u16 netfid,
 		  __u32 filter, struct file *pfile, int multishot,
 		  const struct nls_table *nls_codepage)
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 78db68a..cced470 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -296,7 +296,7 @@ static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
  * reconnect tcp session
  * wake up waiters on reconnection? - (not needed currently)
  */
-static int
+int
 cifs_reconnect(struct TCP_Server_Info *server)
 {
 	int rc = 0;
@@ -394,143 +394,6 @@ cifs_reconnect(struct TCP_Server_Info *server)
 	return rc;
 }
 
-/*
-	return codes:
-		0 	not a transact2, or all data present
-		>0 	transact2 with that much data missing
-		-EINVAL = invalid transact2
-
- */
-static int check2ndT2(char *buf)
-{
-	struct smb_hdr *pSMB = (struct smb_hdr *)buf;
-	struct smb_t2_rsp *pSMBt;
-	int remaining;
-	__u16 total_data_size, data_in_this_rsp;
-
-	if (pSMB->Command != SMB_COM_TRANSACTION2)
-		return 0;
-
-	/* check for plausible wct, bcc and t2 data and parm sizes */
-	/* check for parm and data offset going beyond end of smb */
-	if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
-		cFYI(1, "invalid transact2 word count");
-		return -EINVAL;
-	}
-
-	pSMBt = (struct smb_t2_rsp *)pSMB;
-
-	total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
-	data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
-
-	if (total_data_size == data_in_this_rsp)
-		return 0;
-	else if (total_data_size < data_in_this_rsp) {
-		cFYI(1, "total data %d smaller than data in frame %d",
-			total_data_size, data_in_this_rsp);
-		return -EINVAL;
-	}
-
-	remaining = total_data_size - data_in_this_rsp;
-
-	cFYI(1, "missing %d bytes from transact2, check next response",
-		remaining);
-	if (total_data_size > CIFSMaxBufSize) {
-		cERROR(1, "TotalDataSize %d is over maximum buffer %d",
-			total_data_size, CIFSMaxBufSize);
-		return -EINVAL;
-	}
-	return remaining;
-}
-
-static int coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
-{
-	struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
-	struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)target_hdr;
-	char *data_area_of_tgt;
-	char *data_area_of_src;
-	int remaining;
-	unsigned int byte_count, total_in_tgt;
-	__u16 tgt_total_cnt, src_total_cnt, total_in_src;
-
-	src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
-	tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
-
-	if (tgt_total_cnt != src_total_cnt)
-		cFYI(1, "total data count of primary and secondary t2 differ "
-			"source=%hu target=%hu", src_total_cnt, tgt_total_cnt);
-
-	total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
-
-	remaining = tgt_total_cnt - total_in_tgt;
-
-	if (remaining < 0) {
-		cFYI(1, "Server sent too much data. tgt_total_cnt=%hu "
-			"total_in_tgt=%hu", tgt_total_cnt, total_in_tgt);
-		return -EPROTO;
-	}
-
-	if (remaining == 0) {
-		/* nothing to do, ignore */
-		cFYI(1, "no more data remains");
-		return 0;
-	}
-
-	total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
-	if (remaining < total_in_src)
-		cFYI(1, "transact2 2nd response contains too much data");
-
-	/* find end of first SMB data area */
-	data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
-				get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
-
-	/* validate target area */
-	data_area_of_src = (char *)&pSMBs->hdr.Protocol +
-				get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
-
-	data_area_of_tgt += total_in_tgt;
-
-	total_in_tgt += total_in_src;
-	/* is the result too big for the field? */
-	if (total_in_tgt > USHRT_MAX) {
-		cFYI(1, "coalesced DataCount too large (%u)", total_in_tgt);
-		return -EPROTO;
-	}
-	put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
-
-	/* fix up the BCC */
-	byte_count = get_bcc(target_hdr);
-	byte_count += total_in_src;
-	/* is the result too big for the field? */
-	if (byte_count > USHRT_MAX) {
-		cFYI(1, "coalesced BCC too large (%u)", byte_count);
-		return -EPROTO;
-	}
-	put_bcc(byte_count, target_hdr);
-
-	byte_count = be32_to_cpu(target_hdr->smb_buf_length);
-	byte_count += total_in_src;
-	/* don't allow buffer to overflow */
-	if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
-		cFYI(1, "coalesced BCC exceeds buffer size (%u)", byte_count);
-		return -ENOBUFS;
-	}
-	target_hdr->smb_buf_length = cpu_to_be32(byte_count);
-
-	/* copy second buffer into end of first buffer */
-	memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
-
-	if (remaining != total_in_src) {
-		/* more responses to go */
-		cFYI(1, "waiting for more secondary responses");
-		return 1;
-	}
-
-	/* we are done */
-	cFYI(1, "found the last secondary response");
-	return 0;
-}
-
 static void
 cifs_echo_request(struct work_struct *work)
 {
@@ -543,7 +406,7 @@ cifs_echo_request(struct work_struct *work)
 	 * done, which is indicated by maxBuf != 0. Also, no need to ping if
 	 * we got a response recently
 	 */
-	if (server->maxBuf == 0 ||
+	if (!server->ops->need_neg || server->ops->need_neg(server) ||
 	    time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
 		goto requeue_echo;
 
@@ -803,29 +666,9 @@ static void
 handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 	   char *buf, int malformed)
 {
-	if (malformed == 0 && check2ndT2(buf) > 0) {
-		mid->multiRsp = true;
-		if (mid->resp_buf) {
-			/* merge response - fix up 1st*/
-			malformed = coalesce_t2(buf, mid->resp_buf);
-			if (malformed > 0)
-				return;
-
-			/* All parts received or packet is malformed. */
-			mid->multiEnd = true;
-			return dequeue_mid(mid, malformed);
-		}
-		if (!server->large_buf) {
-			/*FIXME: switch to already allocated largebuf?*/
-			cERROR(1, "1st trans2 resp needs bigbuf");
-		} else {
-			/* Have first buffer */
-			mid->resp_buf = buf;
-			mid->large_buf = true;
-			server->bigbuf = NULL;
-		}
+	if (server->ops->check_trans2 &&
+	    server->ops->check_trans2(mid, server, buf, malformed))
 		return;
-	}
 	mid->resp_buf = buf;
 	mid->large_buf = server->large_buf;
 	/* Was previous buf put in mpx struct for multi-rsp? */
@@ -1653,24 +1496,26 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 			 * If yes, we have encountered a double deliminator
 			 * reset the NULL character to the deliminator
 			 */
-			if (tmp_end < end && tmp_end[1] == delim)
+			if (tmp_end < end && tmp_end[1] == delim) {
 				tmp_end[0] = delim;
 
-			/* Keep iterating until we get to a single deliminator
-			 * OR the end
-			 */
-			while ((tmp_end = strchr(tmp_end, delim)) != NULL &&
-			       (tmp_end[1] == delim)) {
-				tmp_end = (char *) &tmp_end[2];
-			}
+				/* Keep iterating until we get to a single
+				 * deliminator OR the end
+				 */
+				while ((tmp_end = strchr(tmp_end, delim))
+					!= NULL && (tmp_end[1] == delim)) {
+						tmp_end = (char *) &tmp_end[2];
+				}
 
-			/* Reset var options to point to next element */
-			if (tmp_end) {
-				tmp_end[0] = '\0';
-				options = (char *) &tmp_end[1];
-			} else
-				/* Reached the end of the mount option string */
-				options = end;
+				/* Reset var options to point to next element */
+				if (tmp_end) {
+					tmp_end[0] = '\0';
+					options = (char *) &tmp_end[1];
+				} else
+					/* Reached the end of the mount option
+					 * string */
+					options = end;
+			}
 
 			/* Now build new password string */
 			temp_len = strlen(value);
@@ -2407,7 +2252,7 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
 static void
 cifs_put_smb_ses(struct cifs_ses *ses)
 {
-	int xid;
+	unsigned int xid;
 	struct TCP_Server_Info *server = ses->server;
 
 	cFYI(1, "%s: ses_count=%d\n", __func__, ses->ses_count);
@@ -2420,10 +2265,10 @@ cifs_put_smb_ses(struct cifs_ses *ses)
 	list_del_init(&ses->smb_ses_list);
 	spin_unlock(&cifs_tcp_ses_lock);
 
-	if (ses->status == CifsGood) {
-		xid = GetXid();
-		CIFSSMBLogoff(xid, ses);
-		_FreeXid(xid);
+	if (ses->status == CifsGood && server->ops->logoff) {
+		xid = get_xid();
+		server->ops->logoff(xid, ses);
+		_free_xid(xid);
 	}
 	sesInfoFree(ses);
 	cifs_put_tcp_session(server);
@@ -2560,12 +2405,13 @@ static bool warned_on_ntlm;  /* globals init to false automatically */
 static struct cifs_ses *
 cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 {
-	int rc = -ENOMEM, xid;
+	int rc = -ENOMEM;
+	unsigned int xid;
 	struct cifs_ses *ses;
 	struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
 	struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	ses = cifs_find_smb_ses(server, volume_info);
 	if (ses) {
@@ -2577,7 +2423,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 			mutex_unlock(&ses->session_mutex);
 			/* problem -- put our ses reference */
 			cifs_put_smb_ses(ses);
-			FreeXid(xid);
+			free_xid(xid);
 			return ERR_PTR(rc);
 		}
 		if (ses->need_reconnect) {
@@ -2588,7 +2434,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 				mutex_unlock(&ses->session_mutex);
 				/* problem -- put our reference */
 				cifs_put_smb_ses(ses);
-				FreeXid(xid);
+				free_xid(xid);
 				return ERR_PTR(rc);
 			}
 		}
@@ -2596,7 +2442,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 
 		/* existing SMB ses has a server reference already */
 		cifs_put_tcp_session(server);
-		FreeXid(xid);
+		free_xid(xid);
 		return ses;
 	}
 
@@ -2655,12 +2501,12 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 	list_add(&ses->smb_ses_list, &server->smb_ses_list);
 	spin_unlock(&cifs_tcp_ses_lock);
 
-	FreeXid(xid);
+	free_xid(xid);
 	return ses;
 
 get_ses_fail:
 	sesInfoFree(ses);
-	FreeXid(xid);
+	free_xid(xid);
 	return ERR_PTR(rc);
 }
 
@@ -2695,7 +2541,7 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc)
 static void
 cifs_put_tcon(struct cifs_tcon *tcon)
 {
-	int xid;
+	unsigned int xid;
 	struct cifs_ses *ses = tcon->ses;
 
 	cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count);
@@ -2708,9 +2554,10 @@ cifs_put_tcon(struct cifs_tcon *tcon)
 	list_del_init(&tcon->tcon_list);
 	spin_unlock(&cifs_tcp_ses_lock);
 
-	xid = GetXid();
-	CIFSSMBTDis(xid, tcon);
-	_FreeXid(xid);
+	xid = get_xid();
+	if (ses->server->ops->tree_disconnect)
+		ses->server->ops->tree_disconnect(xid, tcon);
+	_free_xid(xid);
 
 	cifs_fscache_release_super_cookie(tcon);
 	tconInfoFree(tcon);
@@ -2734,6 +2581,11 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
 		return tcon;
 	}
 
+	if (!ses->server->ops->tree_connect) {
+		rc = -ENOSYS;
+		goto out_fail;
+	}
+
 	tcon = tconInfoAlloc();
 	if (tcon == NULL) {
 		rc = -ENOMEM;
@@ -2756,13 +2608,15 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
 		goto out_fail;
 	}
 
-	/* BB Do we need to wrap session_mutex around
-	 * this TCon call and Unix SetFS as
-	 * we do on SessSetup and reconnect? */
-	xid = GetXid();
-	rc = CIFSTCon(xid, ses, volume_info->UNC, tcon, volume_info->local_nls);
-	FreeXid(xid);
-	cFYI(1, "CIFS Tcon rc = %d", rc);
+	/*
+	 * BB Do we need to wrap session_mutex around this TCon call and Unix
+	 * SetFS as we do on SessSetup and reconnect?
+	 */
+	xid = get_xid();
+	rc = ses->server->ops->tree_connect(xid, ses, volume_info->UNC, tcon,
+					    volume_info->local_nls);
+	free_xid(xid);
+	cFYI(1, "Tcon rc = %d", rc);
 	if (rc)
 		goto out_fail;
 
@@ -2771,10 +2625,11 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
 		cFYI(1, "DFS disabled (%d)", tcon->Flags);
 	}
 	tcon->seal = volume_info->seal;
-	/* we can have only one retry value for a connection
-	   to a share so for resources mounted more than once
-	   to the same server share the last value passed in
-	   for the retry flag is used */
+	/*
+	 * We can have only one retry value for a connection to a share so for
+	 * resources mounted more than once to the same server share the last
+	 * value passed in for the retry flag is used.
+	 */
 	tcon->retry = volume_info->retry;
 	tcon->nocase = volume_info->nocase;
 	tcon->local_lease = volume_info->local_lease;
@@ -2908,37 +2763,41 @@ out:
 }
 
 int
-get_dfs_path(int xid, struct cifs_ses *pSesInfo, const char *old_path,
-	     const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
-	     struct dfs_info3_param **preferrals, int remap)
+get_dfs_path(unsigned int xid, struct cifs_ses *ses, const char *old_path,
+	     const struct nls_table *nls_codepage, unsigned int *num_referrals,
+	     struct dfs_info3_param **referrals, int remap)
 {
 	char *temp_unc;
 	int rc = 0;
 
-	*pnum_referrals = 0;
-	*preferrals = NULL;
+	if (!ses->server->ops->tree_connect)
+		return -ENOSYS;
+
+	*num_referrals = 0;
+	*referrals = NULL;
 
-	if (pSesInfo->ipc_tid == 0) {
+	if (ses->ipc_tid == 0) {
 		temp_unc = kmalloc(2 /* for slashes */ +
-			strnlen(pSesInfo->serverName,
-				SERVER_NAME_LEN_WITH_NULL * 2)
-				 + 1 + 4 /* slash IPC$ */  + 2,
-				GFP_KERNEL);
+			strnlen(ses->serverName, SERVER_NAME_LEN_WITH_NULL * 2)
+				+ 1 + 4 /* slash IPC$ */ + 2, GFP_KERNEL);
 		if (temp_unc == NULL)
 			return -ENOMEM;
 		temp_unc[0] = '\\';
 		temp_unc[1] = '\\';
-		strcpy(temp_unc + 2, pSesInfo->serverName);
-		strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
-		rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
-		cFYI(1, "CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid);
+		strcpy(temp_unc + 2, ses->serverName);
+		strcpy(temp_unc + 2 + strlen(ses->serverName), "\\IPC$");
+		rc = ses->server->ops->tree_connect(xid, ses, temp_unc, NULL,
+						    nls_codepage);
+		cFYI(1, "Tcon rc = %d ipc_tid = %d", rc, ses->ipc_tid);
 		kfree(temp_unc);
 	}
 	if (rc == 0)
-		rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
-				     pnum_referrals, nls_codepage, remap);
-	/* BB map targetUNCs to dfs_info3 structures, here or
-		in CIFSGetDFSRefer BB */
+		rc = CIFSGetDFSRefer(xid, ses, old_path, referrals,
+				     num_referrals, nls_codepage, remap);
+	/*
+	 * BB - map targetUNCs to dfs_info3 structures, here or in
+	 * CIFSGetDFSRefer.
+	 */
 
 	return rc;
 }
@@ -3207,7 +3066,7 @@ ip_connect(struct TCP_Server_Info *server)
 	return generic_ip_connect(server);
 }
 
-void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon,
+void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
 			  struct cifs_sb_info *cifs_sb, struct smb_vol *vol_info)
 {
 	/* if we are reconnecting then should we check to see if
@@ -3524,7 +3383,7 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
 }
 
 static int
-is_path_accessible(int xid, struct cifs_tcon *tcon,
+is_path_accessible(unsigned int xid, struct cifs_tcon *tcon,
 		   struct cifs_sb_info *cifs_sb, const char *full_path)
 {
 	int rc;
@@ -3610,7 +3469,7 @@ build_unc_path_to_root(const struct smb_vol *vol,
  * determine whether there were referrals.
  */
 static int
-expand_dfs_referral(int xid, struct cifs_ses *pSesInfo,
+expand_dfs_referral(unsigned int xid, struct cifs_ses *pSesInfo,
 		    struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb,
 		    int check_prefix)
 {
@@ -3720,7 +3579,7 @@ int
 cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
 {
 	int rc;
-	int xid;
+	unsigned int xid;
 	struct cifs_ses *pSesInfo;
 	struct cifs_tcon *tcon;
 	struct TCP_Server_Info *srvTcp;
@@ -3743,7 +3602,7 @@ try_mount_again:
 		else if (pSesInfo)
 			cifs_put_smb_ses(pSesInfo);
 
-		FreeXid(xid);
+		free_xid(xid);
 	}
 #endif
 	rc = 0;
@@ -3753,7 +3612,7 @@ try_mount_again:
 	full_path = NULL;
 	tlink = NULL;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	/* get a reference to a tcp session */
 	srvTcp = cifs_get_tcp_session(volume_info);
@@ -3906,7 +3765,7 @@ mount_fail_check:
 	}
 
 out:
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
@@ -3915,7 +3774,7 @@ out:
  * pointer may be NULL.
  */
 int
-CIFSTCon(unsigned int xid, struct cifs_ses *ses,
+CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
 	 const char *tree, struct cifs_tcon *tcon,
 	 const struct nls_table *nls_codepage)
 {
@@ -4099,24 +3958,22 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
 	kfree(cifs_sb);
 }
 
-int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
+int
+cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
 {
 	int rc = 0;
 	struct TCP_Server_Info *server = ses->server;
 
+	if (!server->ops->need_neg || !server->ops->negotiate)
+		return -ENOSYS;
+
 	/* only send once per connect */
-	if (server->maxBuf != 0)
+	if (!server->ops->need_neg(server))
 		return 0;
 
 	set_credits(server, 1);
-	rc = CIFSSMBNegotiate(xid, ses);
-	if (rc == -EAGAIN) {
-		/* retry only once on 1st time connection */
-		set_credits(server, 1);
-		rc = CIFSSMBNegotiate(xid, ses);
-		if (rc == -EAGAIN)
-			rc = -EHOSTDOWN;
-	}
+
+	rc = server->ops->negotiate(xid, ses);
 	if (rc == 0) {
 		spin_lock(&GlobalMid_Lock);
 		if (server->tcpStatus == CifsNeedNegotiate)
@@ -4124,17 +3981,16 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
 		else
 			rc = -EHOSTDOWN;
 		spin_unlock(&GlobalMid_Lock);
-
 	}
 
 	return rc;
 }
 
-
-int cifs_setup_session(unsigned int xid, struct cifs_ses *ses,
-			struct nls_table *nls_info)
+int
+cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
+		   struct nls_table *nls_info)
 {
-	int rc = 0;
+	int rc = -ENOSYS;
 	struct TCP_Server_Info *server = ses->server;
 
 	ses->flags = 0;
@@ -4145,7 +4001,9 @@ int cifs_setup_session(unsigned int xid, struct cifs_ses *ses,
 	cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
 		 server->sec_mode, server->capabilities, server->timeAdj);
 
-	rc = CIFS_SessSetup(xid, ses, nls_info);
+	if (server->ops->sess_setup)
+		rc = server->ops->sess_setup(xid, ses, nls_info);
+
 	if (rc) {
 		cERROR(1, "Send error in SessSetup = %d", rc);
 	} else {
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index ec4e9a2..c9971d5 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -133,108 +133,141 @@ cifs_bp_rename_retry:
 	return full_path;
 }
 
+/*
+ * Don't allow the separator character in a path component.
+ * The VFS will not allow "/", but "\" is allowed by posix.
+ */
+static int
+check_name(struct dentry *direntry)
+{
+	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
+	int i;
+
+	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
+		for (i = 0; i < direntry->d_name.len; i++) {
+			if (direntry->d_name.name[i] == '\\') {
+				cFYI(1, "Invalid file name");
+				return -EINVAL;
+			}
+		}
+	}
+	return 0;
+}
+
+
 /* Inode operations in similar order to how they appear in Linux file fs.h */
 
-int
-cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
-		struct nameidata *nd)
+static int cifs_do_create(struct inode *inode, struct dentry *direntry,
+			  unsigned int xid, struct tcon_link *tlink, unsigned oflags,
+			  umode_t mode, __u32 *oplock, __u16 *fileHandle,
+			  int *created)
 {
 	int rc = -ENOENT;
-	int xid;
 	int create_options = CREATE_NOT_DIR;
-	__u32 oplock = 0;
-	int oflags;
-	/*
-	 * BB below access is probably too much for mknod to request
-	 *    but we have to do query and setpathinfo so requesting
-	 *    less could fail (unless we want to request getatr and setatr
-	 *    permissions (only).  At least for POSIX we do not have to
-	 *    request so much.
-	 */
-	int desiredAccess = GENERIC_READ | GENERIC_WRITE;
-	__u16 fileHandle;
-	struct cifs_sb_info *cifs_sb;
-	struct tcon_link *tlink;
-	struct cifs_tcon *tcon;
+	int desiredAccess;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+	struct cifs_tcon *tcon = tlink_tcon(tlink);
 	char *full_path = NULL;
 	FILE_ALL_INFO *buf = NULL;
 	struct inode *newinode = NULL;
-	int disposition = FILE_OVERWRITE_IF;
-
-	xid = GetXid();
-
-	cifs_sb = CIFS_SB(inode->i_sb);
-	tlink = cifs_sb_tlink(cifs_sb);
-	if (IS_ERR(tlink)) {
-		FreeXid(xid);
-		return PTR_ERR(tlink);
-	}
-	tcon = tlink_tcon(tlink);
+	int disposition;
 
+	*oplock = 0;
 	if (tcon->ses->server->oplocks)
-		oplock = REQ_OPLOCK;
-
-	if (nd)
-		oflags = nd->intent.open.file->f_flags;
-	else
-		oflags = O_RDONLY | O_CREAT;
+		*oplock = REQ_OPLOCK;
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
 		rc = -ENOMEM;
-		goto cifs_create_out;
+		goto out;
 	}
 
 	if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
+	    !tcon->broken_posix_open &&
 	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
 			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 		rc = cifs_posix_open(full_path, &newinode,
-			inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
-		/* EIO could indicate that (posix open) operation is not
-		   supported, despite what server claimed in capability
-		   negotiation.  EREMOTE indicates DFS junction, which is not
-		   handled in posix open */
-
-		if (rc == 0) {
-			if (newinode == NULL) /* query inode info */
+			inode->i_sb, mode, oflags, oplock, fileHandle, xid);
+		switch (rc) {
+		case 0:
+			if (newinode == NULL) {
+				/* query inode info */
 				goto cifs_create_get_file_info;
-			else /* success, no need to query */
-				goto cifs_create_set_dentry;
-		} else if ((rc != -EIO) && (rc != -EREMOTE) &&
-			 (rc != -EOPNOTSUPP) && (rc != -EINVAL))
-			goto cifs_create_out;
-		/* else fallthrough to retry, using older open call, this is
-		   case where server does not support this SMB level, and
-		   falsely claims capability (also get here for DFS case
-		   which should be rare for path not covered on files) */
-	}
+			}
 
-	if (nd) {
-		/* if the file is going to stay open, then we
-		   need to set the desired access properly */
-		desiredAccess = 0;
-		if (OPEN_FMODE(oflags) & FMODE_READ)
-			desiredAccess |= GENERIC_READ; /* is this too little? */
-		if (OPEN_FMODE(oflags) & FMODE_WRITE)
-			desiredAccess |= GENERIC_WRITE;
-
-		if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
-			disposition = FILE_CREATE;
-		else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
-			disposition = FILE_OVERWRITE_IF;
-		else if ((oflags & O_CREAT) == O_CREAT)
-			disposition = FILE_OPEN_IF;
-		else
-			cFYI(1, "Create flag not set in create function");
+			if (!S_ISREG(newinode->i_mode)) {
+				/*
+				 * The server may allow us to open things like
+				 * FIFOs, but the client isn't set up to deal
+				 * with that. If it's not a regular file, just
+				 * close it and proceed as if it were a normal
+				 * lookup.
+				 */
+				CIFSSMBClose(xid, tcon, *fileHandle);
+				goto cifs_create_get_file_info;
+			}
+			/* success, no need to query */
+			goto cifs_create_set_dentry;
+
+		case -ENOENT:
+			goto cifs_create_get_file_info;
+
+		case -EIO:
+		case -EINVAL:
+			/*
+			 * EIO could indicate that (posix open) operation is not
+			 * supported, despite what server claimed in capability
+			 * negotiation.
+			 *
+			 * POSIX open in samba versions 3.3.1 and earlier could
+			 * incorrectly fail with invalid parameter.
+			 */
+			tcon->broken_posix_open = true;
+			break;
+
+		case -EREMOTE:
+		case -EOPNOTSUPP:
+			/*
+			 * EREMOTE indicates DFS junction, which is not handled
+			 * in posix open.  If either that or op not supported
+			 * returned, follow the normal lookup.
+			 */
+			break;
+
+		default:
+			goto out;
+		}
+		/*
+		 * fallthrough to retry, using older open call, this is case
+		 * where server does not support this SMB level, and falsely
+		 * claims capability (also get here for DFS case which should be
+		 * rare for path not covered on files)
+		 */
 	}
 
+	desiredAccess = 0;
+	if (OPEN_FMODE(oflags) & FMODE_READ)
+		desiredAccess |= GENERIC_READ; /* is this too little? */
+	if (OPEN_FMODE(oflags) & FMODE_WRITE)
+		desiredAccess |= GENERIC_WRITE;
+
+	disposition = FILE_OVERWRITE_IF;
+	if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+		disposition = FILE_CREATE;
+	else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
+		disposition = FILE_OVERWRITE_IF;
+	else if ((oflags & O_CREAT) == O_CREAT)
+		disposition = FILE_OPEN_IF;
+	else
+		cFYI(1, "Create flag not set in create function");
+
 	/* BB add processing to set equivalent of mode - e.g. via CreateX with
 	   ACLs */
 
 	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
 	if (buf == NULL) {
 		rc = -ENOMEM;
-		goto cifs_create_out;
+		goto out;
 	}
 
 	/*
@@ -250,7 +283,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
 	if (tcon->ses->capabilities & CAP_NT_SMBS)
 		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
 			 desiredAccess, create_options,
-			 &fileHandle, &oplock, buf, cifs_sb->local_nls,
+			 fileHandle, oplock, buf, cifs_sb->local_nls,
 			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	else
 		rc = -EIO; /* no NT SMB support fall into legacy open below */
@@ -259,17 +292,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
 		/* old server, retry the open legacy style */
 		rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
 			desiredAccess, create_options,
-			&fileHandle, &oplock, buf, cifs_sb->local_nls,
+			fileHandle, oplock, buf, cifs_sb->local_nls,
 			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	}
 	if (rc) {
 		cFYI(1, "cifs_create returned 0x%x", rc);
-		goto cifs_create_out;
+		goto out;
 	}
 
 	/* If Open reported that we actually created a file
 	   then we now have to set the mode if possible */
-	if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
+	if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) {
 		struct cifs_unix_set_info_args args = {
 				.mode	= mode,
 				.ctime	= NO_CHANGE_64,
@@ -278,6 +311,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
 				.device	= 0,
 		};
 
+		*created |= FILE_CREATED;
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 			args.uid = (__u64) current_fsuid();
 			if (inode->i_mode & S_ISGID)
@@ -288,7 +322,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
 			args.uid = NO_CHANGE_64;
 			args.gid = NO_CHANGE_64;
 		}
-		CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle,
+		CIFSSMBUnixSetFileInfo(xid, tcon, &args, *fileHandle,
 					current->tgid);
 	} else {
 		/* BB implement mode setting via Windows security
@@ -305,11 +339,11 @@ cifs_create_get_file_info:
 					      inode->i_sb, xid);
 	else {
 		rc = cifs_get_inode_info(&newinode, full_path, buf,
-					 inode->i_sb, xid, &fileHandle);
+					 inode->i_sb, xid, fileHandle);
 		if (newinode) {
 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
 				newinode->i_mode = mode;
-			if ((oplock & CIFS_CREATE_ACTION) &&
+			if ((*oplock & CIFS_CREATE_ACTION) &&
 			    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
 				newinode->i_uid = current_fsuid();
 				if (inode->i_mode & S_ISGID)
@@ -321,37 +355,136 @@ cifs_create_get_file_info:
 	}
 
 cifs_create_set_dentry:
-	if (rc == 0)
-		d_instantiate(direntry, newinode);
-	else
+	if (rc != 0) {
 		cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
+		goto out;
+	}
+	d_drop(direntry);
+	d_add(direntry, newinode);
 
-	if (newinode && nd) {
-		struct cifsFileInfo *pfile_info;
-		struct file *filp;
+	/* ENOENT for create?  How weird... */
+	rc = -ENOENT;
+	if (!newinode) {
+		CIFSSMBClose(xid, tcon, *fileHandle);
+		goto out;
+	}
+	rc = 0;
 
-		filp = lookup_instantiate_filp(nd, direntry, generic_file_open);
-		if (IS_ERR(filp)) {
-			rc = PTR_ERR(filp);
-			CIFSSMBClose(xid, tcon, fileHandle);
-			goto cifs_create_out;
-		}
+out:
+	kfree(buf);
+	kfree(full_path);
+	return rc;
+}
 
-		pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
-		if (pfile_info == NULL) {
-			fput(filp);
-			CIFSSMBClose(xid, tcon, fileHandle);
-			rc = -ENOMEM;
-		}
-	} else {
+int
+cifs_atomic_open(struct inode *inode, struct dentry *direntry,
+		 struct file *file, unsigned oflags, umode_t mode,
+		 int *opened)
+{
+	int rc;
+	unsigned int xid;
+	struct tcon_link *tlink;
+	struct cifs_tcon *tcon;
+	__u16 fileHandle;
+	__u32 oplock;
+	struct file *filp;
+	struct cifsFileInfo *pfile_info;
+
+	/* Posix open is only called (at lookup time) for file create now.  For
+	 * opens (rather than creates), because we do not know if it is a file
+	 * or directory yet, and current Samba no longer allows us to do posix
+	 * open on dirs, we could end up wasting an open call on what turns out
+	 * to be a dir. For file opens, we wait to call posix open till
+	 * cifs_open.  It could be added to atomic_open in the future but the
+	 * performance tradeoff of the extra network request when EISDIR or
+	 * EACCES is returned would have to be weighed against the 50% reduction
+	 * in network traffic in the other paths.
+	 */
+	if (!(oflags & O_CREAT)) {
+		struct dentry *res = cifs_lookup(inode, direntry, 0);
+		if (IS_ERR(res))
+			return PTR_ERR(res);
+
+		return finish_no_open(file, res);
+	}
+
+	rc = check_name(direntry);
+	if (rc)
+		return rc;
+
+	xid = get_xid();
+
+	cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
+	     inode, direntry->d_name.name, direntry);
+
+	tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
+	filp = ERR_CAST(tlink);
+	if (IS_ERR(tlink))
+		goto free_xid;
+
+	tcon = tlink_tcon(tlink);
+
+	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
+			    &oplock, &fileHandle, opened);
+
+	if (rc)
+		goto out;
+
+	rc = finish_open(file, direntry, generic_file_open, opened);
+	if (rc) {
 		CIFSSMBClose(xid, tcon, fileHandle);
+		goto out;
 	}
 
-cifs_create_out:
-	kfree(buf);
-	kfree(full_path);
+	pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
+	if (pfile_info == NULL) {
+		CIFSSMBClose(xid, tcon, fileHandle);
+		fput(filp);
+		rc = -ENOMEM;
+	}
+
+out:
+	cifs_put_tlink(tlink);
+free_xid:
+	free_xid(xid);
+	return rc;
+}
+
+int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
+		bool excl)
+{
+	int rc;
+	int xid = get_xid();
+	/*
+	 * BB below access is probably too much for mknod to request
+	 *    but we have to do query and setpathinfo so requesting
+	 *    less could fail (unless we want to request getatr and setatr
+	 *    permissions (only).  At least for POSIX we do not have to
+	 *    request so much.
+	 */
+	unsigned oflags = O_EXCL | O_CREAT | O_RDWR;
+	struct tcon_link *tlink;
+	__u16 fileHandle;
+	__u32 oplock;
+	int created = FILE_CREATED;
+
+	cFYI(1, "cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p",
+	     inode, direntry->d_name.name, direntry);
+
+	tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
+	rc = PTR_ERR(tlink);
+	if (IS_ERR(tlink))
+		goto free_xid;
+
+	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
+			    &oplock, &fileHandle, &created);
+	if (!rc)
+		CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle);
+
 	cifs_put_tlink(tlink);
-	FreeXid(xid);
+free_xid:
+	free_xid(xid);
+
 	return rc;
 }
 
@@ -359,7 +492,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
 		dev_t device_number)
 {
 	int rc = -EPERM;
-	int xid;
+	unsigned int xid;
 	int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
@@ -383,7 +516,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
 
 	pTcon = tlink_tcon(tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -431,7 +564,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
 	if (buf == NULL) {
 		kfree(full_path);
 		rc = -ENOMEM;
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 
@@ -481,29 +614,24 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
 mknod_out:
 	kfree(full_path);
 	kfree(buf);
-	FreeXid(xid);
+	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
 }
 
 struct dentry *
 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
-	    struct nameidata *nd)
+	    unsigned int flags)
 {
-	int xid;
+	unsigned int xid;
 	int rc = 0; /* to get around spurious gcc warning, set to zero here */
-	__u32 oplock;
-	__u16 fileHandle = 0;
-	bool posix_open = false;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
-	struct cifsFileInfo *cfile;
 	struct inode *newInode = NULL;
 	char *full_path = NULL;
-	struct file *filp;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
 	      parent_dir_inode, direntry->d_name.name, direntry);
@@ -513,36 +641,14 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 	cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink)) {
-		FreeXid(xid);
+		free_xid(xid);
 		return (struct dentry *)tlink;
 	}
 	pTcon = tlink_tcon(tlink);
 
-	oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0;
-
-	/*
-	 * Don't allow the separator character in a path component.
-	 * The VFS will not allow "/", but "\" is allowed by posix.
-	 */
-	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
-		int i;
-		for (i = 0; i < direntry->d_name.len; i++)
-			if (direntry->d_name.name[i] == '\\') {
-				cFYI(1, "Invalid file name");
-				rc = -EINVAL;
-				goto lookup_out;
-			}
-	}
-
-	/*
-	 * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
-	 * the VFS handle the create.
-	 */
-	if (nd && (nd->flags & LOOKUP_EXCL)) {
-		d_instantiate(direntry, NULL);
-		rc = 0;
+	rc = check_name(direntry);
+	if (rc)
 		goto lookup_out;
-	}
 
 	/* can not grab the rename sem here since it would
 	deadlock in the cases (beginning of sys_rename itself)
@@ -560,80 +666,16 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 	}
 	cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode);
 
-	/* Posix open is only called (at lookup time) for file create now.
-	 * For opens (rather than creates), because we do not know if it
-	 * is a file or directory yet, and current Samba no longer allows
-	 * us to do posix open on dirs, we could end up wasting an open call
-	 * on what turns out to be a dir. For file opens, we wait to call posix
-	 * open till cifs_open.  It could be added here (lookup) in the future
-	 * but the performance tradeoff of the extra network request when EISDIR
-	 * or EACCES is returned would have to be weighed against the 50%
-	 * reduction in network traffic in the other paths.
-	 */
 	if (pTcon->unix_ext) {
-		if (nd && !(nd->flags & LOOKUP_DIRECTORY) &&
-		     (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
-		     (nd->intent.open.file->f_flags & O_CREAT)) {
-			rc = cifs_posix_open(full_path, &newInode,
-					parent_dir_inode->i_sb,
-					nd->intent.open.create_mode,
-					nd->intent.open.file->f_flags, &oplock,
-					&fileHandle, xid);
-			/*
-			 * The check below works around a bug in POSIX
-			 * open in samba versions 3.3.1 and earlier where
-			 * open could incorrectly fail with invalid parameter.
-			 * If either that or op not supported returned, follow
-			 * the normal lookup.
-			 */
-			switch (rc) {
-			case 0:
-				/*
-				 * The server may allow us to open things like
-				 * FIFOs, but the client isn't set up to deal
-				 * with that. If it's not a regular file, just
-				 * close it and proceed as if it were a normal
-				 * lookup.
-				 */
-				if (newInode && !S_ISREG(newInode->i_mode)) {
-					CIFSSMBClose(xid, pTcon, fileHandle);
-					break;
-				}
-			case -ENOENT:
-				posix_open = true;
-			case -EOPNOTSUPP:
-				break;
-			default:
-				pTcon->broken_posix_open = true;
-			}
-		}
-		if (!posix_open)
-			rc = cifs_get_inode_info_unix(&newInode, full_path,
-						parent_dir_inode->i_sb, xid);
-	} else
+		rc = cifs_get_inode_info_unix(&newInode, full_path,
+					      parent_dir_inode->i_sb, xid);
+	} else {
 		rc = cifs_get_inode_info(&newInode, full_path, NULL,
 				parent_dir_inode->i_sb, xid, NULL);
+	}
 
 	if ((rc == 0) && (newInode != NULL)) {
 		d_add(direntry, newInode);
-		if (posix_open) {
-			filp = lookup_instantiate_filp(nd, direntry,
-						       generic_file_open);
-			if (IS_ERR(filp)) {
-				rc = PTR_ERR(filp);
-				CIFSSMBClose(xid, pTcon, fileHandle);
-				goto lookup_out;
-			}
-
-			cfile = cifs_new_fileinfo(fileHandle, filp, tlink,
-						  oplock);
-			if (cfile == NULL) {
-				fput(filp);
-				CIFSSMBClose(xid, pTcon, fileHandle);
-				rc = -ENOMEM;
-				goto lookup_out;
-			}
-		}
 		/* since paths are not looked up by component - the parent
 		   directories are presumed to be good here */
 		renew_parental_timestamps(direntry);
@@ -653,14 +695,14 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 lookup_out:
 	kfree(full_path);
 	cifs_put_tlink(tlink);
-	FreeXid(xid);
+	free_xid(xid);
 	return ERR_PTR(rc);
 }
 
 static int
-cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
+cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
 {
-	if (nd && (nd->flags & LOOKUP_RCU))
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	if (direntry->d_inode) {
@@ -689,7 +731,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
 	 * This may be nfsd (or something), anyway, we can't see the
 	 * intent of this. So, since this can be for creation, drop it.
 	 */
-	if (!nd)
+	if (!flags)
 		return 0;
 
 	/*
@@ -697,7 +739,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
 	 * case sensitive name which is specified by user if this is
 	 * for creation.
 	 */
-	if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
+	if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
 		return 0;
 
 	if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled)
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 513adbc..ea1bb66 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -107,7 +107,7 @@ static inline int cifs_get_disposition(unsigned int flags)
 
 int cifs_posix_open(char *full_path, struct inode **pinode,
 			struct super_block *sb, int mode, unsigned int f_flags,
-			__u32 *poplock, __u16 *pnetfid, int xid)
+			__u32 *poplock, __u16 *pnetfid, unsigned int xid)
 {
 	int rc;
 	FILE_UNIX_BASIC_INFO *presp_data;
@@ -170,7 +170,7 @@ posix_open_ret:
 static int
 cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
 	     struct cifs_tcon *tcon, unsigned int f_flags, __u32 *poplock,
-	     __u16 *pnetfid, int xid)
+	     __u16 *pnetfid, unsigned int xid)
 {
 	int rc;
 	int desiredAccess;
@@ -324,11 +324,11 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 	cancel_work_sync(&cifs_file->oplock_break);
 
 	if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
-		int xid, rc;
-
-		xid = GetXid();
+		unsigned int xid;
+		int rc;
+		xid = get_xid();
 		rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
-		FreeXid(xid);
+		free_xid(xid);
 	}
 
 	/* Delete any outstanding lock records. We'll lose them when the file
@@ -350,7 +350,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 int cifs_open(struct inode *inode, struct file *file)
 {
 	int rc = -EACCES;
-	int xid;
+	unsigned int xid;
 	__u32 oplock;
 	struct cifs_sb_info *cifs_sb;
 	struct cifs_tcon *tcon;
@@ -360,12 +360,12 @@ int cifs_open(struct inode *inode, struct file *file)
 	bool posix_open_ok = false;
 	__u16 netfid;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink)) {
-		FreeXid(xid);
+		free_xid(xid);
 		return PTR_ERR(tlink);
 	}
 	tcon = tlink_tcon(tlink);
@@ -445,7 +445,7 @@ int cifs_open(struct inode *inode, struct file *file)
 
 out:
 	kfree(full_path);
-	FreeXid(xid);
+	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
 }
@@ -464,7 +464,7 @@ static int cifs_relock_file(struct cifsFileInfo *cifsFile)
 static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
 {
 	int rc = -EACCES;
-	int xid;
+	unsigned int xid;
 	__u32 oplock;
 	struct cifs_sb_info *cifs_sb;
 	struct cifs_tcon *tcon;
@@ -476,12 +476,12 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
 	int create_options = CREATE_NOT_DIR;
 	__u16 netfid;
 
-	xid = GetXid();
+	xid = get_xid();
 	mutex_lock(&pCifsFile->fh_mutex);
 	if (!pCifsFile->invalidHandle) {
 		mutex_unlock(&pCifsFile->fh_mutex);
 		rc = 0;
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 
@@ -497,7 +497,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
 	if (full_path == NULL) {
 		rc = -ENOMEM;
 		mutex_unlock(&pCifsFile->fh_mutex);
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 
@@ -583,7 +583,7 @@ reopen_success:
 
 reopen_error_exit:
 	kfree(full_path);
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
@@ -601,13 +601,13 @@ int cifs_close(struct inode *inode, struct file *file)
 int cifs_closedir(struct inode *inode, struct file *file)
 {
 	int rc = 0;
-	int xid;
+	unsigned int xid;
 	struct cifsFileInfo *pCFileStruct = file->private_data;
 	char *ptmp;
 
 	cFYI(1, "Closedir inode = 0x%p", inode);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	if (pCFileStruct) {
 		struct cifs_tcon *pTcon = tlink_tcon(pCFileStruct->tlink);
@@ -639,7 +639,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
 		file->private_data = NULL;
 	}
 	/* BB can we lock the filestruct while this is going on? */
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
@@ -872,7 +872,8 @@ try_again:
 static int
 cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
 {
-	int xid, rc = 0, stored_rc;
+	unsigned int xid;
+	int rc = 0, stored_rc;
 	struct cifsLockInfo *li, *tmp;
 	struct cifs_tcon *tcon;
 	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
@@ -882,13 +883,13 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
 		       LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES};
 	int i;
 
-	xid = GetXid();
+	xid = get_xid();
 	tcon = tlink_tcon(cfile->tlink);
 
 	mutex_lock(&cinode->lock_mutex);
 	if (!cinode->can_cache_brlcks) {
 		mutex_unlock(&cinode->lock_mutex);
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 
@@ -899,7 +900,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
 	max_buf = tcon->ses->server->maxBuf;
 	if (!max_buf) {
 		mutex_unlock(&cinode->lock_mutex);
-		FreeXid(xid);
+		free_xid(xid);
 		return -EINVAL;
 	}
 
@@ -908,7 +909,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
 	buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
 	if (!buf) {
 		mutex_unlock(&cinode->lock_mutex);
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 
@@ -947,7 +948,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
 	mutex_unlock(&cinode->lock_mutex);
 
 	kfree(buf);
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
@@ -977,12 +978,12 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
 	struct lock_to_push *lck, *tmp;
 	__u64 length;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	mutex_lock(&cinode->lock_mutex);
 	if (!cinode->can_cache_brlcks) {
 		mutex_unlock(&cinode->lock_mutex);
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 
@@ -1056,7 +1057,7 @@ out:
 	cinode->can_cache_brlcks = false;
 	mutex_unlock(&cinode->lock_mutex);
 
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 err_out:
 	list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
@@ -1128,7 +1129,7 @@ cifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock,
 }
 
 static int
-cifs_mandatory_lock(int xid, struct cifsFileInfo *cfile, __u64 offset,
+cifs_mandatory_lock(unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
 		    __u64 length, __u32 type, int lock, int unlock, bool wait)
 {
 	return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->netfid,
@@ -1138,7 +1139,7 @@ cifs_mandatory_lock(int xid, struct cifsFileInfo *cfile, __u64 offset,
 
 static int
 cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
-	   bool wait_flag, bool posix_lck, int xid)
+	   bool wait_flag, bool posix_lck, unsigned int xid)
 {
 	int rc = 0;
 	__u64 length = 1 + flock->fl_end - flock->fl_start;
@@ -1223,7 +1224,8 @@ cifs_free_llist(struct list_head *llist)
 }
 
 static int
-cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid)
+cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
+		  unsigned int xid)
 {
 	int rc = 0, stored_rc;
 	int types[] = {LOCKING_ANDX_LARGE_FILES,
@@ -1328,7 +1330,8 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid)
 
 static int
 cifs_setlk(struct file *file,  struct file_lock *flock, __u32 type,
-	   bool wait_flag, bool posix_lck, int lock, int unlock, int xid)
+	   bool wait_flag, bool posix_lck, int lock, int unlock,
+	   unsigned int xid)
 {
 	int rc = 0;
 	__u64 length = 1 + flock->fl_end - flock->fl_start;
@@ -1402,7 +1405,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
 	__u32 type;
 
 	rc = -EACCES;
-	xid = GetXid();
+	xid = get_xid();
 
 	cFYI(1, "Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld "
 		"end: %lld", cmd, flock->fl_flags, flock->fl_type,
@@ -1428,7 +1431,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
 	 */
 	if (IS_GETLK(cmd)) {
 		rc = cifs_getlk(file, flock, type, wait_flag, posix_lck, xid);
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 
@@ -1437,13 +1440,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
 		 * if no lock or unlock then nothing to do since we do not
 		 * know what it is
 		 */
-		FreeXid(xid);
+		free_xid(xid);
 		return -EOPNOTSUPP;
 	}
 
 	rc = cifs_setlk(file, flock, type, wait_flag, posix_lck, lock, unlock,
 			xid);
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
@@ -1470,7 +1473,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
 	unsigned int total_written;
 	struct cifs_sb_info *cifs_sb;
 	struct cifs_tcon *pTcon;
-	int xid;
+	unsigned int xid;
 	struct dentry *dentry = open_file->dentry;
 	struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
 	struct cifs_io_parms io_parms;
@@ -1482,7 +1485,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
 
 	pTcon = tlink_tcon(open_file->tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	for (total_written = 0; write_size > total_written;
 	     total_written += bytes_written) {
@@ -1518,7 +1521,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
 			if (total_written)
 				break;
 			else {
-				FreeXid(xid);
+				free_xid(xid);
 				return rc;
 			}
 		} else {
@@ -1538,7 +1541,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
 		spin_unlock(&dentry->d_inode->i_lock);
 	}
 	mark_inode_dirty_sync(dentry->d_inode);
-	FreeXid(xid);
+	free_xid(xid);
 	return total_written;
 }
 
@@ -1937,9 +1940,9 @@ static int
 cifs_writepage_locked(struct page *page, struct writeback_control *wbc)
 {
 	int rc;
-	int xid;
+	unsigned int xid;
 
-	xid = GetXid();
+	xid = get_xid();
 /* BB add check for wbc flags */
 	page_cache_get(page);
 	if (!PageUptodate(page))
@@ -1968,7 +1971,7 @@ retry_write:
 		SetPageUptodate(page);
 	end_page_writeback(page);
 	page_cache_release(page);
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
@@ -2007,9 +2010,9 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
 	if (!PageUptodate(page)) {
 		char *page_data;
 		unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
-		int xid;
+		unsigned int xid;
 
-		xid = GetXid();
+		xid = get_xid();
 		/* this is probably better than directly calling
 		   partialpage_write since in this function the file handle is
 		   known which we might as well	leverage */
@@ -2020,7 +2023,7 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
 		/* if (rc < 0) should we set writebehind rc? */
 		kunmap(page);
 
-		FreeXid(xid);
+		free_xid(xid);
 	} else {
 		rc = copied;
 		pos += copied;
@@ -2043,7 +2046,7 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
 int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
 		      int datasync)
 {
-	int xid;
+	unsigned int xid;
 	int rc = 0;
 	struct cifs_tcon *tcon;
 	struct cifsFileInfo *smbfile = file->private_data;
@@ -2055,7 +2058,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
 		return rc;
 	mutex_lock(&inode->i_mutex);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	cFYI(1, "Sync file - name: %s datasync: 0x%x",
 		file->f_path.dentry->d_name.name, datasync);
@@ -2072,14 +2075,14 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
 		rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
 
-	FreeXid(xid);
+	free_xid(xid);
 	mutex_unlock(&inode->i_mutex);
 	return rc;
 }
 
 int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
-	int xid;
+	unsigned int xid;
 	int rc = 0;
 	struct cifs_tcon *tcon;
 	struct cifsFileInfo *smbfile = file->private_data;
@@ -2091,7 +2094,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 		return rc;
 	mutex_lock(&inode->i_mutex);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	cFYI(1, "Sync file - name: %s datasync: 0x%x",
 		file->f_path.dentry->d_name.name, datasync);
@@ -2100,7 +2103,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
 		rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
 
-	FreeXid(xid);
+	free_xid(xid);
 	mutex_unlock(&inode->i_mutex);
 	return rc;
 }
@@ -2745,14 +2748,14 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	unsigned int rsize;
 	struct cifs_sb_info *cifs_sb;
 	struct cifs_tcon *pTcon;
-	int xid;
+	unsigned int xid;
 	char *current_offset;
 	struct cifsFileInfo *open_file;
 	struct cifs_io_parms io_parms;
 	int buf_type = CIFS_NO_BUFFER;
 	__u32 pid;
 
-	xid = GetXid();
+	xid = get_xid();
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
 	/* FIXME: set up handlers for larger reads and/or convert to async */
@@ -2760,7 +2763,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 
 	if (file->private_data == NULL) {
 		rc = -EBADF;
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 	open_file = file->private_data;
@@ -2805,7 +2808,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 			if (total_read) {
 				break;
 			} else {
-				FreeXid(xid);
+				free_xid(xid);
 				return rc;
 			}
 		} else {
@@ -2813,7 +2816,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 			*poffset += bytes_read;
 		}
 	}
-	FreeXid(xid);
+	free_xid(xid);
 	return total_read;
 }
 
@@ -2840,7 +2843,7 @@ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
 	int rc, xid;
 	struct inode *inode = file->f_path.dentry->d_inode;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	if (!CIFS_I(inode)->clientCanCacheRead) {
 		rc = cifs_invalidate_mapping(inode);
@@ -2851,7 +2854,7 @@ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
 	rc = generic_file_mmap(file, vma);
 	if (rc == 0)
 		vma->vm_ops = &cifs_file_vm_ops;
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
@@ -2859,17 +2862,17 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	int rc, xid;
 
-	xid = GetXid();
+	xid = get_xid();
 	rc = cifs_revalidate_file(file);
 	if (rc) {
 		cFYI(1, "Validation prior to mmap failed, error=%d", rc);
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 	rc = generic_file_mmap(file, vma);
 	if (rc == 0)
 		vma->vm_ops = &cifs_file_vm_ops;
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
@@ -3159,13 +3162,13 @@ static int cifs_readpage(struct file *file, struct page *page)
 {
 	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
 	int rc = -EACCES;
-	int xid;
+	unsigned int xid;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	if (file->private_data == NULL) {
 		rc = -EBADF;
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 
@@ -3176,7 +3179,7 @@ static int cifs_readpage(struct file *file, struct page *page)
 
 	unlock_page(page);
 
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 745da3d..af90286 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -289,7 +289,7 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
 int cifs_get_file_info_unix(struct file *filp)
 {
 	int rc;
-	int xid;
+	unsigned int xid;
 	FILE_UNIX_BASIC_INFO find_data;
 	struct cifs_fattr fattr;
 	struct inode *inode = filp->f_path.dentry->d_inode;
@@ -297,7 +297,7 @@ int cifs_get_file_info_unix(struct file *filp)
 	struct cifsFileInfo *cfile = filp->private_data;
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 	rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
 	if (!rc) {
 		cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
@@ -307,13 +307,13 @@ int cifs_get_file_info_unix(struct file *filp)
 	}
 
 	cifs_fattr_to_inode(inode, &fattr);
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
 int cifs_get_inode_info_unix(struct inode **pinode,
 			     const unsigned char *full_path,
-			     struct super_block *sb, int xid)
+			     struct super_block *sb, unsigned int xid)
 {
 	int rc;
 	FILE_UNIX_BASIC_INFO find_data;
@@ -367,7 +367,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 
 static int
 cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
-	      struct cifs_sb_info *cifs_sb, int xid)
+	      struct cifs_sb_info *cifs_sb, unsigned int xid)
 {
 	int rc;
 	int oplock = 0;
@@ -466,7 +466,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
  * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
  */
 static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
-			 struct cifs_sb_info *cifs_sb, int xid)
+			 struct cifs_sb_info *cifs_sb, unsigned int xid)
 {
 #ifdef CONFIG_CIFS_XATTR
 	ssize_t rc;
@@ -557,7 +557,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
 int cifs_get_file_info(struct file *filp)
 {
 	int rc;
-	int xid;
+	unsigned int xid;
 	FILE_ALL_INFO find_data;
 	struct cifs_fattr fattr;
 	struct inode *inode = filp->f_path.dentry->d_inode;
@@ -565,7 +565,7 @@ int cifs_get_file_info(struct file *filp)
 	struct cifsFileInfo *cfile = filp->private_data;
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 	rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
 	switch (rc) {
 	case 0:
@@ -596,13 +596,13 @@ int cifs_get_file_info(struct file *filp)
 	fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
 	cifs_fattr_to_inode(inode, &fattr);
 cgfi_exit:
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
 int cifs_get_inode_info(struct inode **pinode,
 	const unsigned char *full_path, FILE_ALL_INFO *pfindData,
-	struct super_block *sb, int xid, const __u16 *pfid)
+	struct super_block *sb, unsigned int xid, const __u16 *pfid)
 {
 	int rc = 0, tmprc;
 	struct cifs_tcon *pTcon;
@@ -800,7 +800,7 @@ cifs_find_inode(struct inode *inode, void *opaque)
 		return 0;
 
 	/* if it's not a directory or has no dentries, then flag it */
-	if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry))
+	if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry))
 		fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
 
 	return 1;
@@ -825,9 +825,10 @@ static bool
 inode_has_hashed_dentries(struct inode *inode)
 {
 	struct dentry *dentry;
+	struct hlist_node *p;
 
 	spin_lock(&inode->i_lock);
-	list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+	hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
 		if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
 			spin_unlock(&inode->i_lock);
 			return true;
@@ -885,13 +886,13 @@ retry_iget5_locked:
 /* gets root inode */
 struct inode *cifs_root_iget(struct super_block *sb)
 {
-	int xid;
+	unsigned int xid;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct inode *inode = NULL;
 	long rc;
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 
-	xid = GetXid();
+	xid = get_xid();
 	if (tcon->unix_ext)
 		rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
 	else
@@ -921,15 +922,15 @@ struct inode *cifs_root_iget(struct super_block *sb)
 	}
 
 out:
-	/* can not call macro FreeXid here since in a void func
+	/* can not call macro free_xid here since in a void func
 	 * TODO: This is no longer true
 	 */
-	_FreeXid(xid);
+	_free_xid(xid);
 	return inode;
 }
 
 static int
-cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
+cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
 		    char *full_path, __u32 dosattr)
 {
 	int rc;
@@ -1050,7 +1051,8 @@ out:
  * anything else.
  */
 static int
-cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
+cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
+			   unsigned int xid)
 {
 	int oplock = 0;
 	int rc;
@@ -1170,7 +1172,7 @@ undo_setattr:
 int cifs_unlink(struct inode *dir, struct dentry *dentry)
 {
 	int rc = 0;
-	int xid;
+	unsigned int xid;
 	char *full_path = NULL;
 	struct inode *inode = dentry->d_inode;
 	struct cifsInodeInfo *cifs_inode;
@@ -1188,7 +1190,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 		return PTR_ERR(tlink);
 	tcon = tlink_tcon(tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	/* Unlink can be called from rename so we can not take the
 	 * sb->s_vfs_rename_mutex here */
@@ -1264,7 +1266,7 @@ out_reval:
 unlink_out:
 	kfree(full_path);
 	kfree(attrs);
-	FreeXid(xid);
+	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
 }
@@ -1272,7 +1274,7 @@ unlink_out:
 int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 {
 	int rc = 0, tmprc;
-	int xid;
+	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
@@ -1288,7 +1290,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 		return PTR_ERR(tlink);
 	pTcon = tlink_tcon(tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -1445,7 +1447,7 @@ mkdir_out:
 	 */
 	CIFS_I(inode)->time = 0;
 	kfree(full_path);
-	FreeXid(xid);
+	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
 }
@@ -1453,7 +1455,7 @@ mkdir_out:
 int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 {
 	int rc = 0;
-	int xid;
+	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
@@ -1462,7 +1464,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 
 	cFYI(1, "cifs_rmdir, inode = 0x%p", inode);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -1505,13 +1507,14 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 
 rmdir_exit:
 	kfree(full_path);
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
 static int
-cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
-		struct dentry *to_dentry, const char *toPath)
+cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
+	       const char *fromPath, struct dentry *to_dentry,
+	       const char *toPath)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
 	struct tcon_link *tlink;
@@ -1570,7 +1573,8 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 	struct cifs_tcon *tcon;
 	FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
 	FILE_UNIX_BASIC_INFO *info_buf_target;
-	int xid, rc, tmprc;
+	unsigned int xid;
+	int rc, tmprc;
 
 	cifs_sb = CIFS_SB(source_dir->i_sb);
 	tlink = cifs_sb_tlink(cifs_sb);
@@ -1578,7 +1582,7 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
 		return PTR_ERR(tlink);
 	tcon = tlink_tcon(tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	/*
 	 * we already have the rename sem so we do not need to
@@ -1651,7 +1655,7 @@ cifs_rename_exit:
 	kfree(info_buf_source);
 	kfree(fromName);
 	kfree(toName);
-	FreeXid(xid);
+	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
 }
@@ -1726,7 +1730,7 @@ int cifs_revalidate_file_attr(struct file *filp)
 
 int cifs_revalidate_dentry_attr(struct dentry *dentry)
 {
-	int xid;
+	unsigned int xid;
 	int rc = 0;
 	struct inode *inode = dentry->d_inode;
 	struct super_block *sb = dentry->d_sb;
@@ -1738,7 +1742,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
 	if (!cifs_inode_needs_reval(inode))
 		return rc;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	/* can not safely grab the rename sem here if rename calls revalidate
 	   since that would deadlock */
@@ -1760,7 +1764,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
 
 out:
 	kfree(full_path);
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
@@ -1868,7 +1872,7 @@ static void cifs_setsize(struct inode *inode, loff_t offset)
 
 static int
 cifs_set_file_size(struct inode *inode, struct iattr *attrs,
-		   int xid, char *full_path)
+		   unsigned int xid, char *full_path)
 {
 	int rc;
 	struct cifsFileInfo *open_file;
@@ -1970,7 +1974,7 @@ static int
 cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 {
 	int rc;
-	int xid;
+	unsigned int xid;
 	char *full_path = NULL;
 	struct inode *inode = direntry->d_inode;
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
@@ -1983,7 +1987,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 	cFYI(1, "setattr_unix on file %s attrs->ia_valid=0x%x",
 		 direntry->d_name.name, attrs->ia_valid);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
 		attrs->ia_valid |= ATTR_FORCE;
@@ -2103,14 +2107,14 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 out:
 	kfree(args);
 	kfree(full_path);
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
 static int
 cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 {
-	int xid;
+	unsigned int xid;
 	uid_t uid = NO_CHANGE_32;
 	gid_t gid = NO_CHANGE_32;
 	struct inode *inode = direntry->d_inode;
@@ -2121,7 +2125,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 	__u32 dosattr = 0;
 	__u64 mode = NO_CHANGE_64;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	cFYI(1, "setattr on file %s attrs->iavalid 0x%x",
 		 direntry->d_name.name, attrs->ia_valid);
@@ -2131,14 +2135,14 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 
 	rc = inode_change_ok(inode, attrs);
 	if (rc < 0) {
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
 		rc = -ENOMEM;
-		FreeXid(xid);
+		free_xid(xid);
 		return rc;
 	}
 
@@ -2264,7 +2268,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 
 cifs_setattr_exit:
 	kfree(full_path);
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 6d2667f..ae082a6 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -34,7 +34,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 {
 	struct inode *inode = filep->f_dentry->d_inode;
 	int rc = -ENOTTY; /* strange error - but the precedent */
-	int xid;
+	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 #ifdef CONFIG_CIFS_POSIX
 	struct cifsFileInfo *pSMBFile = filep->private_data;
@@ -44,7 +44,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 	__u64   caps;
 #endif /* CONFIG_CIFS_POSIX */
 
-	xid = GetXid();
+	xid = get_xid();
 
 	cFYI(1, "ioctl file %p  cmd %u  arg %lu", filep, command, arg);
 
@@ -105,6 +105,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 			break;
 	}
 
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 6b0e064..77d781a 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -181,7 +181,7 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
 }
 
 static int
-CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon,
+CIFSCreateMFSymLink(const unsigned int xid, struct cifs_tcon *tcon,
 		    const char *fromName, const char *toName,
 		    struct cifs_sb_info *cifs_sb)
 {
@@ -238,7 +238,7 @@ CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon,
 }
 
 static int
-CIFSQueryMFSymLink(const int xid, struct cifs_tcon *tcon,
+CIFSQueryMFSymLink(const unsigned int xid, struct cifs_tcon *tcon,
 		   const unsigned char *searchName, char **symlinkinfo,
 		   const struct nls_table *nls_codepage, int remap)
 {
@@ -307,7 +307,7 @@ CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
 int
 CIFSCheckMFSymlink(struct cifs_fattr *fattr,
 		   const unsigned char *path,
-		   struct cifs_sb_info *cifs_sb, int xid)
+		   struct cifs_sb_info *cifs_sb, unsigned int xid)
 {
 	int rc;
 	int oplock = 0;
@@ -390,7 +390,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 	      struct dentry *direntry)
 {
 	int rc = -EACCES;
-	int xid;
+	unsigned int xid;
 	char *fromName = NULL;
 	char *toName = NULL;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -403,7 +403,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 		return PTR_ERR(tlink);
 	pTcon = tlink_tcon(tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	fromName = build_path_from_dentry(old_file);
 	toName = build_path_from_dentry(direntry);
@@ -455,7 +455,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 cifs_hl_exit:
 	kfree(fromName);
 	kfree(toName);
-	FreeXid(xid);
+	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
 }
@@ -465,14 +465,14 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 {
 	struct inode *inode = direntry->d_inode;
 	int rc = -ENOMEM;
-	int xid;
+	unsigned int xid;
 	char *full_path = NULL;
 	char *target_path = NULL;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink = NULL;
 	struct cifs_tcon *tcon;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink)) {
@@ -529,7 +529,7 @@ out:
 		target_path = ERR_PTR(rc);
 	}
 
-	FreeXid(xid);
+	free_xid(xid);
 	if (tlink)
 		cifs_put_tlink(tlink);
 	nd_set_link(nd, target_path);
@@ -540,14 +540,14 @@ int
 cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
 {
 	int rc = -EOPNOTSUPP;
-	int xid;
+	unsigned int xid;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
 	char *full_path = NULL;
 	struct inode *newinode = NULL;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink)) {
@@ -594,7 +594,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
 symlink_exit:
 	kfree(full_path);
 	cifs_put_tlink(tlink);
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
 
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 557506a..6460114 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -40,7 +40,7 @@ extern mempool_t *cifs_req_poolp;
    since the cifs fs was mounted */
 
 unsigned int
-_GetXid(void)
+_get_xid(void)
 {
 	unsigned int xid;
 
@@ -58,7 +58,7 @@ _GetXid(void)
 }
 
 void
-_FreeXid(unsigned int xid)
+_free_xid(unsigned int xid)
 {
 	spin_lock(&GlobalMid_Lock);
 	/* if (GlobalTotalActiveXid == 0)
diff --git a/fs/cifs/nterr.c b/fs/cifs/nterr.c
index 819fd99..b6023c6 100644
--- a/fs/cifs/nterr.c
+++ b/fs/cifs/nterr.c
@@ -31,7 +31,7 @@ const struct nt_err_code_struct nt_errs[] = {
 	{"NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS},
 	{"NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH},
 	{"NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION},
-	{"STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW},
+	{"NT_STATUS_BUFFER_OVERFLOW", NT_STATUS_BUFFER_OVERFLOW},
 	{"NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR},
 	{"NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA},
 	{"NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE},
@@ -681,7 +681,7 @@ const struct nt_err_code_struct nt_errs[] = {
 	 NT_STATUS_QUOTA_LIST_INCONSISTENT},
 	{"NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE},
 	{"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES},
-	{"STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES},
-	{"STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED},
+	{"NT_STATUS_MORE_ENTRIES", NT_STATUS_MORE_ENTRIES},
+	{"NT_STATUS_SOME_UNMAPPED", NT_STATUS_SOME_UNMAPPED},
 	{NULL, 0}
 };
diff --git a/fs/cifs/nterr.h b/fs/cifs/nterr.h
index 25726736..7a0eae5 100644
--- a/fs/cifs/nterr.h
+++ b/fs/cifs/nterr.h
@@ -35,18 +35,20 @@ struct nt_err_code_struct {
 extern const struct nt_err_code_struct nt_errs[];
 
 /* Win32 Status codes. */
-#define STATUS_MORE_ENTRIES               0x0105
-#define ERROR_INVALID_PARAMETER		  0x0057
-#define ERROR_INSUFFICIENT_BUFFER	  0x007a
-#define STATUS_1804	                  0x070c
-#define STATUS_NOTIFY_ENUM_DIR            0x010c
+#define NT_STATUS_MORE_ENTRIES         0x0105
+#define NT_ERROR_INVALID_PARAMETER     0x0057
+#define NT_ERROR_INSUFFICIENT_BUFFER   0x007a
+#define NT_STATUS_1804                 0x070c
+#define NT_STATUS_NOTIFY_ENUM_DIR      0x010c
 
-/* Win32 Error codes extracted using a loop in smbclient then printing a
-   netmon sniff to a file. */
+/*
+ * Win32 Error codes extracted using a loop in smbclient then printing a netmon
+ * sniff to a file.
+ */
 
-#define NT_STATUS_OK 0x0000
-#define STATUS_SOME_UNMAPPED       0x0107
-#define STATUS_BUFFER_OVERFLOW     0x80000005
+#define NT_STATUS_OK                   0x0000
+#define NT_STATUS_SOME_UNMAPPED        0x0107
+#define NT_STATUS_BUFFER_OVERFLOW  0x80000005
 #define NT_STATUS_NO_MORE_ENTRIES  0x8000001a
 #define NT_STATUS_MEDIA_CHANGED    0x8000001c
 #define NT_STATUS_END_OF_MEDIA     0x8000001e
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 0a8224d..5cb2c37 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -190,7 +190,7 @@ cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
       we try to do FindFirst on (NTFS) directory symlinks */
 /*
 int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
-			     int xid)
+			     unsigned int xid)
 {
 	__u16 fid;
 	int len;
@@ -217,7 +217,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
 }
  */
 
-static int initiate_cifs_search(const int xid, struct file *file)
+static int initiate_cifs_search(const unsigned int xid, struct file *file)
 {
 	__u16 search_flags;
 	int rc = 0;
@@ -504,7 +504,7 @@ static int cifs_save_resume_key(const char *current_entry,
    assume that they are located in the findfirst return buffer.*/
 /* We start counting in the buffer with entry 2 and increment for every
    entry (do not increment for . or .. entry) */
-static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon,
+static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
 	struct file *file, char **ppCurrentEntry, int *num_to_ret)
 {
 	__u16 search_flags;
@@ -718,7 +718,8 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,
 int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 {
 	int rc = 0;
-	int xid, i;
+	unsigned int xid;
+	int i;
 	struct cifs_tcon *pTcon;
 	struct cifsFileInfo *cifsFile = NULL;
 	char *current_entry;
@@ -727,7 +728,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 	char *end_of_smb;
 	unsigned int max_len;
 
-	xid = GetXid();
+	xid = get_xid();
 
 	/*
 	 * Ensure FindFirst doesn't fail before doing filldir() for '.' and
@@ -765,7 +766,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 
 		if (file->private_data == NULL) {
 			rc = -EINVAL;
-			FreeXid(xid);
+			free_xid(xid);
 			return rc;
 		}
 		cifsFile = file->private_data;
@@ -837,6 +838,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 	} /* end switch */
 
 rddir2_exit:
-	FreeXid(xid);
+	free_xid(xid);
 	return rc;
 }
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 551d0c2..e25b312 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -556,7 +556,7 @@ setup_ntlmv2_ret:
 }
 
 int
-CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses,
+CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
 	       const struct nls_table *nls_cp)
 {
 	int rc = 0;
@@ -898,7 +898,7 @@ ssetup_ntlmssp_authenticate:
 	if (action & GUEST_LOGIN)
 		cFYI(1, "Guest login"); /* BB mark SesInfo struct? */
 	ses->Suid = smb_buf->Uid;   /* UID left in wire format (le) */
-	cFYI(1, "UID = %d ", ses->Suid);
+	cFYI(1, "UID = %llu ", ses->Suid);
 	/* response can have either 3 or 4 word count - Samba sends 3 */
 	/* and lanman response is 3 */
 	bytes_remaining = get_bcc(smb_buf);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 6dec38f..8f873863 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -101,7 +101,8 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
 }
 
 static void
-cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add)
+cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add,
+		 const int optype)
 {
 	spin_lock(&server->req_lock);
 	server->credits += add;
@@ -120,11 +121,17 @@ cifs_set_credits(struct TCP_Server_Info *server, const int val)
 }
 
 static int *
-cifs_get_credits_field(struct TCP_Server_Info *server)
+cifs_get_credits_field(struct TCP_Server_Info *server, const int optype)
 {
 	return &server->credits;
 }
 
+static unsigned int
+cifs_get_credits(struct mid_q_entry *mid)
+{
+	return 1;
+}
+
 /*
  * Find a free multiplex id (SMB mid). Otherwise there could be
  * mid collisions which might cause problems, demultiplexing the
@@ -213,6 +220,196 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
 	return mid;
 }
 
+/*
+	return codes:
+		0	not a transact2, or all data present
+		>0	transact2 with that much data missing
+		-EINVAL	invalid transact2
+ */
+static int
+check2ndT2(char *buf)
+{
+	struct smb_hdr *pSMB = (struct smb_hdr *)buf;
+	struct smb_t2_rsp *pSMBt;
+	int remaining;
+	__u16 total_data_size, data_in_this_rsp;
+
+	if (pSMB->Command != SMB_COM_TRANSACTION2)
+		return 0;
+
+	/* check for plausible wct, bcc and t2 data and parm sizes */
+	/* check for parm and data offset going beyond end of smb */
+	if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
+		cFYI(1, "invalid transact2 word count");
+		return -EINVAL;
+	}
+
+	pSMBt = (struct smb_t2_rsp *)pSMB;
+
+	total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
+	data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
+
+	if (total_data_size == data_in_this_rsp)
+		return 0;
+	else if (total_data_size < data_in_this_rsp) {
+		cFYI(1, "total data %d smaller than data in frame %d",
+			total_data_size, data_in_this_rsp);
+		return -EINVAL;
+	}
+
+	remaining = total_data_size - data_in_this_rsp;
+
+	cFYI(1, "missing %d bytes from transact2, check next response",
+		remaining);
+	if (total_data_size > CIFSMaxBufSize) {
+		cERROR(1, "TotalDataSize %d is over maximum buffer %d",
+			total_data_size, CIFSMaxBufSize);
+		return -EINVAL;
+	}
+	return remaining;
+}
+
+static int
+coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
+{
+	struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
+	struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)target_hdr;
+	char *data_area_of_tgt;
+	char *data_area_of_src;
+	int remaining;
+	unsigned int byte_count, total_in_tgt;
+	__u16 tgt_total_cnt, src_total_cnt, total_in_src;
+
+	src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
+	tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
+
+	if (tgt_total_cnt != src_total_cnt)
+		cFYI(1, "total data count of primary and secondary t2 differ "
+			"source=%hu target=%hu", src_total_cnt, tgt_total_cnt);
+
+	total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
+
+	remaining = tgt_total_cnt - total_in_tgt;
+
+	if (remaining < 0) {
+		cFYI(1, "Server sent too much data. tgt_total_cnt=%hu "
+			"total_in_tgt=%hu", tgt_total_cnt, total_in_tgt);
+		return -EPROTO;
+	}
+
+	if (remaining == 0) {
+		/* nothing to do, ignore */
+		cFYI(1, "no more data remains");
+		return 0;
+	}
+
+	total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
+	if (remaining < total_in_src)
+		cFYI(1, "transact2 2nd response contains too much data");
+
+	/* find end of first SMB data area */
+	data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
+				get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
+
+	/* validate target area */
+	data_area_of_src = (char *)&pSMBs->hdr.Protocol +
+				get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
+
+	data_area_of_tgt += total_in_tgt;
+
+	total_in_tgt += total_in_src;
+	/* is the result too big for the field? */
+	if (total_in_tgt > USHRT_MAX) {
+		cFYI(1, "coalesced DataCount too large (%u)", total_in_tgt);
+		return -EPROTO;
+	}
+	put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
+
+	/* fix up the BCC */
+	byte_count = get_bcc(target_hdr);
+	byte_count += total_in_src;
+	/* is the result too big for the field? */
+	if (byte_count > USHRT_MAX) {
+		cFYI(1, "coalesced BCC too large (%u)", byte_count);
+		return -EPROTO;
+	}
+	put_bcc(byte_count, target_hdr);
+
+	byte_count = be32_to_cpu(target_hdr->smb_buf_length);
+	byte_count += total_in_src;
+	/* don't allow buffer to overflow */
+	if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+		cFYI(1, "coalesced BCC exceeds buffer size (%u)", byte_count);
+		return -ENOBUFS;
+	}
+	target_hdr->smb_buf_length = cpu_to_be32(byte_count);
+
+	/* copy second buffer into end of first buffer */
+	memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
+
+	if (remaining != total_in_src) {
+		/* more responses to go */
+		cFYI(1, "waiting for more secondary responses");
+		return 1;
+	}
+
+	/* we are done */
+	cFYI(1, "found the last secondary response");
+	return 0;
+}
+
+static bool
+cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+		  char *buf, int malformed)
+{
+	if (malformed)
+		return false;
+	if (check2ndT2(buf) <= 0)
+		return false;
+	mid->multiRsp = true;
+	if (mid->resp_buf) {
+		/* merge response - fix up 1st*/
+		malformed = coalesce_t2(buf, mid->resp_buf);
+		if (malformed > 0)
+			return true;
+		/* All parts received or packet is malformed. */
+		mid->multiEnd = true;
+		dequeue_mid(mid, malformed);
+		return true;
+	}
+	if (!server->large_buf) {
+		/*FIXME: switch to already allocated largebuf?*/
+		cERROR(1, "1st trans2 resp needs bigbuf");
+	} else {
+		/* Have first buffer */
+		mid->resp_buf = buf;
+		mid->large_buf = true;
+		server->bigbuf = NULL;
+	}
+	return true;
+}
+
+static bool
+cifs_need_neg(struct TCP_Server_Info *server)
+{
+	return server->maxBuf == 0;
+}
+
+static int
+cifs_negotiate(const unsigned int xid, struct cifs_ses *ses)
+{
+	int rc;
+	rc = CIFSSMBNegotiate(xid, ses);
+	if (rc == -EAGAIN) {
+		/* retry only once on 1st time connection */
+		set_credits(ses->server, 1);
+		rc = CIFSSMBNegotiate(xid, ses);
+		if (rc == -EAGAIN)
+			rc = -EHOSTDOWN;
+	}
+	return rc;
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -221,6 +418,7 @@ struct smb_version_operations smb1_operations = {
 	.add_credits = cifs_add_credits,
 	.set_credits = cifs_set_credits,
 	.get_credits_field = cifs_get_credits_field,
+	.get_credits = cifs_get_credits,
 	.get_next_mid = cifs_get_next_mid,
 	.read_data_offset = cifs_read_data_offset,
 	.read_data_length = cifs_read_data_length,
@@ -229,6 +427,13 @@ struct smb_version_operations smb1_operations = {
 	.check_message = checkSMB,
 	.dump_detail = cifs_dump_detail,
 	.is_oplock_break = is_valid_oplock_break,
+	.check_trans2 = cifs_check_trans2,
+	.need_neg = cifs_need_neg,
+	.negotiate = cifs_negotiate,
+	.sess_setup = CIFS_SessSetup,
+	.logoff = CIFSSMBLogoff,
+	.tree_connect = CIFSTCon,
+	.tree_disconnect = CIFSSMBTDis,
 };
 
 struct smb_version_values smb1_values = {
@@ -240,4 +445,5 @@ struct smb_version_values smb1_values = {
 	.header_size = sizeof(struct smb_hdr),
 	.max_header_size = MAX_CIFS_HDR_SIZE,
 	.read_rsp_size = sizeof(READ_RSP),
+	.lock_cmd = cpu_to_le16(SMB_COM_LOCKING_ANDX),
 };
diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c
new file mode 100644
index 0000000..3480b80
--- /dev/null
+++ b/fs/cifs/smb2maperror.c
@@ -0,0 +1,2478 @@
+/*
+ *   fs/smb2/smb2maperror.c
+ *
+ *   Functions which do error mapping of SMB2 status codes to POSIX errors
+ *
+ *   Copyright (C) International Business Machines  Corp., 2009
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/errno.h>
+#include "cifsglob.h"
+#include "cifs_debug.h"
+#include "smb2pdu.h"
+#include "smb2proto.h"
+#include "smb2status.h"
+
+struct status_to_posix_error {
+	__u32 smb2_status;
+	int posix_error;
+	char *status_string;
+};
+
+static const struct status_to_posix_error smb2_error_map_table[] = {
+	{STATUS_SUCCESS, 0, "STATUS_SUCCESS"},
+	{STATUS_WAIT_0,  0, "STATUS_WAIT_0"},
+	{STATUS_WAIT_1, -EIO, "STATUS_WAIT_1"},
+	{STATUS_WAIT_2, -EIO, "STATUS_WAIT_2"},
+	{STATUS_WAIT_3, -EIO, "STATUS_WAIT_3"},
+	{STATUS_WAIT_63, -EIO, "STATUS_WAIT_63"},
+	{STATUS_ABANDONED, -EIO, "STATUS_ABANDONED"},
+	{STATUS_ABANDONED_WAIT_0, -EIO, "STATUS_ABANDONED_WAIT_0"},
+	{STATUS_ABANDONED_WAIT_63, -EIO, "STATUS_ABANDONED_WAIT_63"},
+	{STATUS_USER_APC, -EIO, "STATUS_USER_APC"},
+	{STATUS_KERNEL_APC, -EIO, "STATUS_KERNEL_APC"},
+	{STATUS_ALERTED, -EIO, "STATUS_ALERTED"},
+	{STATUS_TIMEOUT, -ETIMEDOUT, "STATUS_TIMEOUT"},
+	{STATUS_PENDING, -EIO, "STATUS_PENDING"},
+	{STATUS_REPARSE, -EIO, "STATUS_REPARSE"},
+	{STATUS_MORE_ENTRIES, -EIO, "STATUS_MORE_ENTRIES"},
+	{STATUS_NOT_ALL_ASSIGNED, -EIO, "STATUS_NOT_ALL_ASSIGNED"},
+	{STATUS_SOME_NOT_MAPPED, -EIO, "STATUS_SOME_NOT_MAPPED"},
+	{STATUS_OPLOCK_BREAK_IN_PROGRESS, -EIO,
+	"STATUS_OPLOCK_BREAK_IN_PROGRESS"},
+	{STATUS_VOLUME_MOUNTED, -EIO, "STATUS_VOLUME_MOUNTED"},
+	{STATUS_RXACT_COMMITTED, -EIO, "STATUS_RXACT_COMMITTED"},
+	{STATUS_NOTIFY_CLEANUP, -EIO, "STATUS_NOTIFY_CLEANUP"},
+	{STATUS_NOTIFY_ENUM_DIR, -EIO, "STATUS_NOTIFY_ENUM_DIR"},
+	{STATUS_NO_QUOTAS_FOR_ACCOUNT, -EIO, "STATUS_NO_QUOTAS_FOR_ACCOUNT"},
+	{STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED, -EIO,
+	"STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED"},
+	{STATUS_PAGE_FAULT_TRANSITION, -EIO, "STATUS_PAGE_FAULT_TRANSITION"},
+	{STATUS_PAGE_FAULT_DEMAND_ZERO, -EIO, "STATUS_PAGE_FAULT_DEMAND_ZERO"},
+	{STATUS_PAGE_FAULT_COPY_ON_WRITE, -EIO,
+	"STATUS_PAGE_FAULT_COPY_ON_WRITE"},
+	{STATUS_PAGE_FAULT_GUARD_PAGE, -EIO, "STATUS_PAGE_FAULT_GUARD_PAGE"},
+	{STATUS_PAGE_FAULT_PAGING_FILE, -EIO, "STATUS_PAGE_FAULT_PAGING_FILE"},
+	{STATUS_CACHE_PAGE_LOCKED, -EIO, "STATUS_CACHE_PAGE_LOCKED"},
+	{STATUS_CRASH_DUMP, -EIO, "STATUS_CRASH_DUMP"},
+	{STATUS_BUFFER_ALL_ZEROS, -EIO, "STATUS_BUFFER_ALL_ZEROS"},
+	{STATUS_REPARSE_OBJECT, -EIO, "STATUS_REPARSE_OBJECT"},
+	{STATUS_RESOURCE_REQUIREMENTS_CHANGED, -EIO,
+	"STATUS_RESOURCE_REQUIREMENTS_CHANGED"},
+	{STATUS_TRANSLATION_COMPLETE, -EIO, "STATUS_TRANSLATION_COMPLETE"},
+	{STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY, -EIO,
+	"STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY"},
+	{STATUS_NOTHING_TO_TERMINATE, -EIO, "STATUS_NOTHING_TO_TERMINATE"},
+	{STATUS_PROCESS_NOT_IN_JOB, -EIO, "STATUS_PROCESS_NOT_IN_JOB"},
+	{STATUS_PROCESS_IN_JOB, -EIO, "STATUS_PROCESS_IN_JOB"},
+	{STATUS_VOLSNAP_HIBERNATE_READY, -EIO,
+	"STATUS_VOLSNAP_HIBERNATE_READY"},
+	{STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY, -EIO,
+	"STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY"},
+	{STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED, -EIO,
+	"STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED"},
+	{STATUS_INTERRUPT_STILL_CONNECTED, -EIO,
+	"STATUS_INTERRUPT_STILL_CONNECTED"},
+	{STATUS_PROCESS_CLONED, -EIO, "STATUS_PROCESS_CLONED"},
+	{STATUS_FILE_LOCKED_WITH_ONLY_READERS, -EIO,
+	"STATUS_FILE_LOCKED_WITH_ONLY_READERS"},
+	{STATUS_FILE_LOCKED_WITH_WRITERS, -EIO,
+	"STATUS_FILE_LOCKED_WITH_WRITERS"},
+	{STATUS_RESOURCEMANAGER_READ_ONLY, -EROFS,
+	"STATUS_RESOURCEMANAGER_READ_ONLY"},
+	{STATUS_WAIT_FOR_OPLOCK, -EIO, "STATUS_WAIT_FOR_OPLOCK"},
+	{DBG_EXCEPTION_HANDLED, -EIO, "DBG_EXCEPTION_HANDLED"},
+	{DBG_CONTINUE, -EIO, "DBG_CONTINUE"},
+	{STATUS_FLT_IO_COMPLETE, -EIO, "STATUS_FLT_IO_COMPLETE"},
+	{STATUS_OBJECT_NAME_EXISTS, -EIO, "STATUS_OBJECT_NAME_EXISTS"},
+	{STATUS_THREAD_WAS_SUSPENDED, -EIO, "STATUS_THREAD_WAS_SUSPENDED"},
+	{STATUS_WORKING_SET_LIMIT_RANGE, -EIO,
+	"STATUS_WORKING_SET_LIMIT_RANGE"},
+	{STATUS_IMAGE_NOT_AT_BASE, -EIO, "STATUS_IMAGE_NOT_AT_BASE"},
+	{STATUS_RXACT_STATE_CREATED, -EIO, "STATUS_RXACT_STATE_CREATED"},
+	{STATUS_SEGMENT_NOTIFICATION, -EIO, "STATUS_SEGMENT_NOTIFICATION"},
+	{STATUS_LOCAL_USER_SESSION_KEY, -EIO, "STATUS_LOCAL_USER_SESSION_KEY"},
+	{STATUS_BAD_CURRENT_DIRECTORY, -EIO, "STATUS_BAD_CURRENT_DIRECTORY"},
+	{STATUS_SERIAL_MORE_WRITES, -EIO, "STATUS_SERIAL_MORE_WRITES"},
+	{STATUS_REGISTRY_RECOVERED, -EIO, "STATUS_REGISTRY_RECOVERED"},
+	{STATUS_FT_READ_RECOVERY_FROM_BACKUP, -EIO,
+	"STATUS_FT_READ_RECOVERY_FROM_BACKUP"},
+	{STATUS_FT_WRITE_RECOVERY, -EIO, "STATUS_FT_WRITE_RECOVERY"},
+	{STATUS_SERIAL_COUNTER_TIMEOUT, -ETIMEDOUT,
+	"STATUS_SERIAL_COUNTER_TIMEOUT"},
+	{STATUS_NULL_LM_PASSWORD, -EIO, "STATUS_NULL_LM_PASSWORD"},
+	{STATUS_IMAGE_MACHINE_TYPE_MISMATCH, -EIO,
+	"STATUS_IMAGE_MACHINE_TYPE_MISMATCH"},
+	{STATUS_RECEIVE_PARTIAL, -EIO, "STATUS_RECEIVE_PARTIAL"},
+	{STATUS_RECEIVE_EXPEDITED, -EIO, "STATUS_RECEIVE_EXPEDITED"},
+	{STATUS_RECEIVE_PARTIAL_EXPEDITED, -EIO,
+	"STATUS_RECEIVE_PARTIAL_EXPEDITED"},
+	{STATUS_EVENT_DONE, -EIO, "STATUS_EVENT_DONE"},
+	{STATUS_EVENT_PENDING, -EIO, "STATUS_EVENT_PENDING"},
+	{STATUS_CHECKING_FILE_SYSTEM, -EIO, "STATUS_CHECKING_FILE_SYSTEM"},
+	{STATUS_FATAL_APP_EXIT, -EIO, "STATUS_FATAL_APP_EXIT"},
+	{STATUS_PREDEFINED_HANDLE, -EIO, "STATUS_PREDEFINED_HANDLE"},
+	{STATUS_WAS_UNLOCKED, -EIO, "STATUS_WAS_UNLOCKED"},
+	{STATUS_SERVICE_NOTIFICATION, -EIO, "STATUS_SERVICE_NOTIFICATION"},
+	{STATUS_WAS_LOCKED, -EIO, "STATUS_WAS_LOCKED"},
+	{STATUS_LOG_HARD_ERROR, -EIO, "STATUS_LOG_HARD_ERROR"},
+	{STATUS_ALREADY_WIN32, -EIO, "STATUS_ALREADY_WIN32"},
+	{STATUS_WX86_UNSIMULATE, -EIO, "STATUS_WX86_UNSIMULATE"},
+	{STATUS_WX86_CONTINUE, -EIO, "STATUS_WX86_CONTINUE"},
+	{STATUS_WX86_SINGLE_STEP, -EIO, "STATUS_WX86_SINGLE_STEP"},
+	{STATUS_WX86_BREAKPOINT, -EIO, "STATUS_WX86_BREAKPOINT"},
+	{STATUS_WX86_EXCEPTION_CONTINUE, -EIO,
+	"STATUS_WX86_EXCEPTION_CONTINUE"},
+	{STATUS_WX86_EXCEPTION_LASTCHANCE, -EIO,
+	"STATUS_WX86_EXCEPTION_LASTCHANCE"},
+	{STATUS_WX86_EXCEPTION_CHAIN, -EIO, "STATUS_WX86_EXCEPTION_CHAIN"},
+	{STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE, -EIO,
+	"STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE"},
+	{STATUS_NO_YIELD_PERFORMED, -EIO, "STATUS_NO_YIELD_PERFORMED"},
+	{STATUS_TIMER_RESUME_IGNORED, -EIO, "STATUS_TIMER_RESUME_IGNORED"},
+	{STATUS_ARBITRATION_UNHANDLED, -EIO, "STATUS_ARBITRATION_UNHANDLED"},
+	{STATUS_CARDBUS_NOT_SUPPORTED, -ENOSYS, "STATUS_CARDBUS_NOT_SUPPORTED"},
+	{STATUS_WX86_CREATEWX86TIB, -EIO, "STATUS_WX86_CREATEWX86TIB"},
+	{STATUS_MP_PROCESSOR_MISMATCH, -EIO, "STATUS_MP_PROCESSOR_MISMATCH"},
+	{STATUS_HIBERNATED, -EIO, "STATUS_HIBERNATED"},
+	{STATUS_RESUME_HIBERNATION, -EIO, "STATUS_RESUME_HIBERNATION"},
+	{STATUS_FIRMWARE_UPDATED, -EIO, "STATUS_FIRMWARE_UPDATED"},
+	{STATUS_DRIVERS_LEAKING_LOCKED_PAGES, -EIO,
+	"STATUS_DRIVERS_LEAKING_LOCKED_PAGES"},
+	{STATUS_MESSAGE_RETRIEVED, -EIO, "STATUS_MESSAGE_RETRIEVED"},
+	{STATUS_SYSTEM_POWERSTATE_TRANSITION, -EIO,
+	"STATUS_SYSTEM_POWERSTATE_TRANSITION"},
+	{STATUS_ALPC_CHECK_COMPLETION_LIST, -EIO,
+	"STATUS_ALPC_CHECK_COMPLETION_LIST"},
+	{STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION, -EIO,
+	"STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION"},
+	{STATUS_ACCESS_AUDIT_BY_POLICY, -EIO, "STATUS_ACCESS_AUDIT_BY_POLICY"},
+	{STATUS_ABANDON_HIBERFILE, -EIO, "STATUS_ABANDON_HIBERFILE"},
+	{STATUS_BIZRULES_NOT_ENABLED, -EIO, "STATUS_BIZRULES_NOT_ENABLED"},
+	{STATUS_WAKE_SYSTEM, -EIO, "STATUS_WAKE_SYSTEM"},
+	{STATUS_DS_SHUTTING_DOWN, -EIO, "STATUS_DS_SHUTTING_DOWN"},
+	{DBG_REPLY_LATER, -EIO, "DBG_REPLY_LATER"},
+	{DBG_UNABLE_TO_PROVIDE_HANDLE, -EIO, "DBG_UNABLE_TO_PROVIDE_HANDLE"},
+	{DBG_TERMINATE_THREAD, -EIO, "DBG_TERMINATE_THREAD"},
+	{DBG_TERMINATE_PROCESS, -EIO, "DBG_TERMINATE_PROCESS"},
+	{DBG_CONTROL_C, -EIO, "DBG_CONTROL_C"},
+	{DBG_PRINTEXCEPTION_C, -EIO, "DBG_PRINTEXCEPTION_C"},
+	{DBG_RIPEXCEPTION, -EIO, "DBG_RIPEXCEPTION"},
+	{DBG_CONTROL_BREAK, -EIO, "DBG_CONTROL_BREAK"},
+	{DBG_COMMAND_EXCEPTION, -EIO, "DBG_COMMAND_EXCEPTION"},
+	{RPC_NT_UUID_LOCAL_ONLY, -EIO, "RPC_NT_UUID_LOCAL_ONLY"},
+	{RPC_NT_SEND_INCOMPLETE, -EIO, "RPC_NT_SEND_INCOMPLETE"},
+	{STATUS_CTX_CDM_CONNECT, -EIO, "STATUS_CTX_CDM_CONNECT"},
+	{STATUS_CTX_CDM_DISCONNECT, -EIO, "STATUS_CTX_CDM_DISCONNECT"},
+	{STATUS_SXS_RELEASE_ACTIVATION_CONTEXT, -EIO,
+	"STATUS_SXS_RELEASE_ACTIVATION_CONTEXT"},
+	{STATUS_RECOVERY_NOT_NEEDED, -EIO, "STATUS_RECOVERY_NOT_NEEDED"},
+	{STATUS_RM_ALREADY_STARTED, -EIO, "STATUS_RM_ALREADY_STARTED"},
+	{STATUS_LOG_NO_RESTART, -EIO, "STATUS_LOG_NO_RESTART"},
+	{STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST, -EIO,
+	"STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST"},
+	{STATUS_GRAPHICS_PARTIAL_DATA_POPULATED, -EIO,
+	"STATUS_GRAPHICS_PARTIAL_DATA_POPULATED"},
+	{STATUS_GRAPHICS_DRIVER_MISMATCH, -EIO,
+	"STATUS_GRAPHICS_DRIVER_MISMATCH"},
+	{STATUS_GRAPHICS_MODE_NOT_PINNED, -EIO,
+	"STATUS_GRAPHICS_MODE_NOT_PINNED"},
+	{STATUS_GRAPHICS_NO_PREFERRED_MODE, -EIO,
+	"STATUS_GRAPHICS_NO_PREFERRED_MODE"},
+	{STATUS_GRAPHICS_DATASET_IS_EMPTY, -EIO,
+	"STATUS_GRAPHICS_DATASET_IS_EMPTY"},
+	{STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET, -EIO,
+	"STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET"},
+	{STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED, -EIO,
+	"STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED"},
+	{STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS, -EIO,
+	"STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS"},
+	{STATUS_GRAPHICS_LEADLINK_START_DEFERRED, -EIO,
+	"STATUS_GRAPHICS_LEADLINK_START_DEFERRED"},
+	{STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY, -EIO,
+	"STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY"},
+	{STATUS_GRAPHICS_START_DEFERRED, -EIO,
+	"STATUS_GRAPHICS_START_DEFERRED"},
+	{STATUS_NDIS_INDICATION_REQUIRED, -EIO,
+	"STATUS_NDIS_INDICATION_REQUIRED"},
+	{STATUS_GUARD_PAGE_VIOLATION, -EIO, "STATUS_GUARD_PAGE_VIOLATION"},
+	{STATUS_DATATYPE_MISALIGNMENT, -EIO, "STATUS_DATATYPE_MISALIGNMENT"},
+	{STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
+	{STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"},
+	{STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"},
+	{STATUS_NO_MORE_FILES, -EIO, "STATUS_NO_MORE_FILES"},
+	{STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
+	{STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
+	{STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"},
+	{STATUS_GUID_SUBSTITUTION_MADE, -EIO, "STATUS_GUID_SUBSTITUTION_MADE"},
+	{STATUS_PARTIAL_COPY, -EIO, "STATUS_PARTIAL_COPY"},
+	{STATUS_DEVICE_PAPER_EMPTY, -EIO, "STATUS_DEVICE_PAPER_EMPTY"},
+	{STATUS_DEVICE_POWERED_OFF, -EIO, "STATUS_DEVICE_POWERED_OFF"},
+	{STATUS_DEVICE_OFF_LINE, -EIO, "STATUS_DEVICE_OFF_LINE"},
+	{STATUS_DEVICE_BUSY, -EBUSY, "STATUS_DEVICE_BUSY"},
+	{STATUS_NO_MORE_EAS, -EIO, "STATUS_NO_MORE_EAS"},
+	{STATUS_INVALID_EA_NAME, -EINVAL, "STATUS_INVALID_EA_NAME"},
+	{STATUS_EA_LIST_INCONSISTENT, -EIO, "STATUS_EA_LIST_INCONSISTENT"},
+	{STATUS_INVALID_EA_FLAG, -EINVAL, "STATUS_INVALID_EA_FLAG"},
+	{STATUS_VERIFY_REQUIRED, -EIO, "STATUS_VERIFY_REQUIRED"},
+	{STATUS_EXTRANEOUS_INFORMATION, -EIO, "STATUS_EXTRANEOUS_INFORMATION"},
+	{STATUS_RXACT_COMMIT_NECESSARY, -EIO, "STATUS_RXACT_COMMIT_NECESSARY"},
+	{STATUS_NO_MORE_ENTRIES, -EIO, "STATUS_NO_MORE_ENTRIES"},
+	{STATUS_FILEMARK_DETECTED, -EIO, "STATUS_FILEMARK_DETECTED"},
+	{STATUS_MEDIA_CHANGED, -EIO, "STATUS_MEDIA_CHANGED"},
+	{STATUS_BUS_RESET, -EIO, "STATUS_BUS_RESET"},
+	{STATUS_END_OF_MEDIA, -EIO, "STATUS_END_OF_MEDIA"},
+	{STATUS_BEGINNING_OF_MEDIA, -EIO, "STATUS_BEGINNING_OF_MEDIA"},
+	{STATUS_MEDIA_CHECK, -EIO, "STATUS_MEDIA_CHECK"},
+	{STATUS_SETMARK_DETECTED, -EIO, "STATUS_SETMARK_DETECTED"},
+	{STATUS_NO_DATA_DETECTED, -EIO, "STATUS_NO_DATA_DETECTED"},
+	{STATUS_REDIRECTOR_HAS_OPEN_HANDLES, -EIO,
+	"STATUS_REDIRECTOR_HAS_OPEN_HANDLES"},
+	{STATUS_SERVER_HAS_OPEN_HANDLES, -EIO,
+	"STATUS_SERVER_HAS_OPEN_HANDLES"},
+	{STATUS_ALREADY_DISCONNECTED, -EIO, "STATUS_ALREADY_DISCONNECTED"},
+	{STATUS_LONGJUMP, -EIO, "STATUS_LONGJUMP"},
+	{STATUS_CLEANER_CARTRIDGE_INSTALLED, -EIO,
+	"STATUS_CLEANER_CARTRIDGE_INSTALLED"},
+	{STATUS_PLUGPLAY_QUERY_VETOED, -EIO, "STATUS_PLUGPLAY_QUERY_VETOED"},
+	{STATUS_UNWIND_CONSOLIDATE, -EIO, "STATUS_UNWIND_CONSOLIDATE"},
+	{STATUS_REGISTRY_HIVE_RECOVERED, -EIO,
+	"STATUS_REGISTRY_HIVE_RECOVERED"},
+	{STATUS_DLL_MIGHT_BE_INSECURE, -EIO, "STATUS_DLL_MIGHT_BE_INSECURE"},
+	{STATUS_DLL_MIGHT_BE_INCOMPATIBLE, -EIO,
+	"STATUS_DLL_MIGHT_BE_INCOMPATIBLE"},
+	{STATUS_STOPPED_ON_SYMLINK, -EOPNOTSUPP, "STATUS_STOPPED_ON_SYMLINK"},
+	{STATUS_DEVICE_REQUIRES_CLEANING, -EIO,
+	"STATUS_DEVICE_REQUIRES_CLEANING"},
+	{STATUS_DEVICE_DOOR_OPEN, -EIO, "STATUS_DEVICE_DOOR_OPEN"},
+	{STATUS_DATA_LOST_REPAIR, -EIO, "STATUS_DATA_LOST_REPAIR"},
+	{DBG_EXCEPTION_NOT_HANDLED, -EIO, "DBG_EXCEPTION_NOT_HANDLED"},
+	{STATUS_CLUSTER_NODE_ALREADY_UP, -EIO,
+	"STATUS_CLUSTER_NODE_ALREADY_UP"},
+	{STATUS_CLUSTER_NODE_ALREADY_DOWN, -EIO,
+	"STATUS_CLUSTER_NODE_ALREADY_DOWN"},
+	{STATUS_CLUSTER_NETWORK_ALREADY_ONLINE, -EIO,
+	"STATUS_CLUSTER_NETWORK_ALREADY_ONLINE"},
+	{STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE, -EIO,
+	"STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE"},
+	{STATUS_CLUSTER_NODE_ALREADY_MEMBER, -EIO,
+	"STATUS_CLUSTER_NODE_ALREADY_MEMBER"},
+	{STATUS_COULD_NOT_RESIZE_LOG, -EIO, "STATUS_COULD_NOT_RESIZE_LOG"},
+	{STATUS_NO_TXF_METADATA, -EIO, "STATUS_NO_TXF_METADATA"},
+	{STATUS_CANT_RECOVER_WITH_HANDLE_OPEN, -EIO,
+	"STATUS_CANT_RECOVER_WITH_HANDLE_OPEN"},
+	{STATUS_TXF_METADATA_ALREADY_PRESENT, -EIO,
+	"STATUS_TXF_METADATA_ALREADY_PRESENT"},
+	{STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET, -EIO,
+	"STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET"},
+	{STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED, -EIO,
+	"STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED"},
+	{STATUS_FLT_BUFFER_TOO_SMALL, -ENOBUFS, "STATUS_FLT_BUFFER_TOO_SMALL"},
+	{STATUS_FVE_PARTIAL_METADATA, -EIO, "STATUS_FVE_PARTIAL_METADATA"},
+	{STATUS_UNSUCCESSFUL, -EIO, "STATUS_UNSUCCESSFUL"},
+	{STATUS_NOT_IMPLEMENTED, -ENOSYS, "STATUS_NOT_IMPLEMENTED"},
+	{STATUS_INVALID_INFO_CLASS, -EIO, "STATUS_INVALID_INFO_CLASS"},
+	{STATUS_INFO_LENGTH_MISMATCH, -EIO, "STATUS_INFO_LENGTH_MISMATCH"},
+	{STATUS_ACCESS_VIOLATION, -EACCES, "STATUS_ACCESS_VIOLATION"},
+	{STATUS_IN_PAGE_ERROR, -EFAULT, "STATUS_IN_PAGE_ERROR"},
+	{STATUS_PAGEFILE_QUOTA, -EDQUOT, "STATUS_PAGEFILE_QUOTA"},
+	{STATUS_INVALID_HANDLE, -EBADF, "STATUS_INVALID_HANDLE"},
+	{STATUS_BAD_INITIAL_STACK, -EIO, "STATUS_BAD_INITIAL_STACK"},
+	{STATUS_BAD_INITIAL_PC, -EIO, "STATUS_BAD_INITIAL_PC"},
+	{STATUS_INVALID_CID, -EIO, "STATUS_INVALID_CID"},
+	{STATUS_TIMER_NOT_CANCELED, -EIO, "STATUS_TIMER_NOT_CANCELED"},
+	{STATUS_INVALID_PARAMETER, -EINVAL, "STATUS_INVALID_PARAMETER"},
+	{STATUS_NO_SUCH_DEVICE, -ENODEV, "STATUS_NO_SUCH_DEVICE"},
+	{STATUS_NO_SUCH_FILE, -ENOENT, "STATUS_NO_SUCH_FILE"},
+	{STATUS_INVALID_DEVICE_REQUEST, -EIO, "STATUS_INVALID_DEVICE_REQUEST"},
+	{STATUS_END_OF_FILE, -ENODATA, "STATUS_END_OF_FILE"},
+	{STATUS_WRONG_VOLUME, -EIO, "STATUS_WRONG_VOLUME"},
+	{STATUS_NO_MEDIA_IN_DEVICE, -EIO, "STATUS_NO_MEDIA_IN_DEVICE"},
+	{STATUS_UNRECOGNIZED_MEDIA, -EIO, "STATUS_UNRECOGNIZED_MEDIA"},
+	{STATUS_NONEXISTENT_SECTOR, -EIO, "STATUS_NONEXISTENT_SECTOR"},
+	{STATUS_MORE_PROCESSING_REQUIRED, -EIO,
+	"STATUS_MORE_PROCESSING_REQUIRED"},
+	{STATUS_NO_MEMORY, -ENOMEM, "STATUS_NO_MEMORY"},
+	{STATUS_CONFLICTING_ADDRESSES, -EADDRINUSE,
+	"STATUS_CONFLICTING_ADDRESSES"},
+	{STATUS_NOT_MAPPED_VIEW, -EIO, "STATUS_NOT_MAPPED_VIEW"},
+	{STATUS_UNABLE_TO_FREE_VM, -EIO, "STATUS_UNABLE_TO_FREE_VM"},
+	{STATUS_UNABLE_TO_DELETE_SECTION, -EIO,
+	"STATUS_UNABLE_TO_DELETE_SECTION"},
+	{STATUS_INVALID_SYSTEM_SERVICE, -EIO, "STATUS_INVALID_SYSTEM_SERVICE"},
+	{STATUS_ILLEGAL_INSTRUCTION, -EIO, "STATUS_ILLEGAL_INSTRUCTION"},
+	{STATUS_INVALID_LOCK_SEQUENCE, -EIO, "STATUS_INVALID_LOCK_SEQUENCE"},
+	{STATUS_INVALID_VIEW_SIZE, -EIO, "STATUS_INVALID_VIEW_SIZE"},
+	{STATUS_INVALID_FILE_FOR_SECTION, -EIO,
+	"STATUS_INVALID_FILE_FOR_SECTION"},
+	{STATUS_ALREADY_COMMITTED, -EIO, "STATUS_ALREADY_COMMITTED"},
+	{STATUS_ACCESS_DENIED, -EACCES, "STATUS_ACCESS_DENIED"},
+	{STATUS_BUFFER_TOO_SMALL, -EIO, "STATUS_BUFFER_TOO_SMALL"},
+	{STATUS_OBJECT_TYPE_MISMATCH, -EIO, "STATUS_OBJECT_TYPE_MISMATCH"},
+	{STATUS_NONCONTINUABLE_EXCEPTION, -EIO,
+	"STATUS_NONCONTINUABLE_EXCEPTION"},
+	{STATUS_INVALID_DISPOSITION, -EIO, "STATUS_INVALID_DISPOSITION"},
+	{STATUS_UNWIND, -EIO, "STATUS_UNWIND"},
+	{STATUS_BAD_STACK, -EIO, "STATUS_BAD_STACK"},
+	{STATUS_INVALID_UNWIND_TARGET, -EIO, "STATUS_INVALID_UNWIND_TARGET"},
+	{STATUS_NOT_LOCKED, -EIO, "STATUS_NOT_LOCKED"},
+	{STATUS_PARITY_ERROR, -EIO, "STATUS_PARITY_ERROR"},
+	{STATUS_UNABLE_TO_DECOMMIT_VM, -EIO, "STATUS_UNABLE_TO_DECOMMIT_VM"},
+	{STATUS_NOT_COMMITTED, -EIO, "STATUS_NOT_COMMITTED"},
+	{STATUS_INVALID_PORT_ATTRIBUTES, -EIO,
+	"STATUS_INVALID_PORT_ATTRIBUTES"},
+	{STATUS_PORT_MESSAGE_TOO_LONG, -EIO, "STATUS_PORT_MESSAGE_TOO_LONG"},
+	{STATUS_INVALID_PARAMETER_MIX, -EINVAL, "STATUS_INVALID_PARAMETER_MIX"},
+	{STATUS_INVALID_QUOTA_LOWER, -EIO, "STATUS_INVALID_QUOTA_LOWER"},
+	{STATUS_DISK_CORRUPT_ERROR, -EIO, "STATUS_DISK_CORRUPT_ERROR"},
+	{STATUS_OBJECT_NAME_INVALID, -ENOENT, "STATUS_OBJECT_NAME_INVALID"},
+	{STATUS_OBJECT_NAME_NOT_FOUND, -ENOENT, "STATUS_OBJECT_NAME_NOT_FOUND"},
+	{STATUS_OBJECT_NAME_COLLISION, -EEXIST, "STATUS_OBJECT_NAME_COLLISION"},
+	{STATUS_PORT_DISCONNECTED, -EIO, "STATUS_PORT_DISCONNECTED"},
+	{STATUS_DEVICE_ALREADY_ATTACHED, -EIO,
+	"STATUS_DEVICE_ALREADY_ATTACHED"},
+	{STATUS_OBJECT_PATH_INVALID, -ENOTDIR, "STATUS_OBJECT_PATH_INVALID"},
+	{STATUS_OBJECT_PATH_NOT_FOUND, -ENOENT, "STATUS_OBJECT_PATH_NOT_FOUND"},
+	{STATUS_OBJECT_PATH_SYNTAX_BAD, -EIO, "STATUS_OBJECT_PATH_SYNTAX_BAD"},
+	{STATUS_DATA_OVERRUN, -EIO, "STATUS_DATA_OVERRUN"},
+	{STATUS_DATA_LATE_ERROR, -EIO, "STATUS_DATA_LATE_ERROR"},
+	{STATUS_DATA_ERROR, -EIO, "STATUS_DATA_ERROR"},
+	{STATUS_CRC_ERROR, -EIO, "STATUS_CRC_ERROR"},
+	{STATUS_SECTION_TOO_BIG, -EIO, "STATUS_SECTION_TOO_BIG"},
+	{STATUS_PORT_CONNECTION_REFUSED, -ECONNREFUSED,
+	"STATUS_PORT_CONNECTION_REFUSED"},
+	{STATUS_INVALID_PORT_HANDLE, -EIO, "STATUS_INVALID_PORT_HANDLE"},
+	{STATUS_SHARING_VIOLATION, -EBUSY, "STATUS_SHARING_VIOLATION"},
+	{STATUS_QUOTA_EXCEEDED, -EDQUOT, "STATUS_QUOTA_EXCEEDED"},
+	{STATUS_INVALID_PAGE_PROTECTION, -EIO,
+	"STATUS_INVALID_PAGE_PROTECTION"},
+	{STATUS_MUTANT_NOT_OWNED, -EIO, "STATUS_MUTANT_NOT_OWNED"},
+	{STATUS_SEMAPHORE_LIMIT_EXCEEDED, -EIO,
+	"STATUS_SEMAPHORE_LIMIT_EXCEEDED"},
+	{STATUS_PORT_ALREADY_SET, -EIO, "STATUS_PORT_ALREADY_SET"},
+	{STATUS_SECTION_NOT_IMAGE, -EIO, "STATUS_SECTION_NOT_IMAGE"},
+	{STATUS_SUSPEND_COUNT_EXCEEDED, -EIO, "STATUS_SUSPEND_COUNT_EXCEEDED"},
+	{STATUS_THREAD_IS_TERMINATING, -EIO, "STATUS_THREAD_IS_TERMINATING"},
+	{STATUS_BAD_WORKING_SET_LIMIT, -EIO, "STATUS_BAD_WORKING_SET_LIMIT"},
+	{STATUS_INCOMPATIBLE_FILE_MAP, -EIO, "STATUS_INCOMPATIBLE_FILE_MAP"},
+	{STATUS_SECTION_PROTECTION, -EIO, "STATUS_SECTION_PROTECTION"},
+	{STATUS_EAS_NOT_SUPPORTED, -EOPNOTSUPP, "STATUS_EAS_NOT_SUPPORTED"},
+	{STATUS_EA_TOO_LARGE, -EIO, "STATUS_EA_TOO_LARGE"},
+	{STATUS_NONEXISTENT_EA_ENTRY, -EIO, "STATUS_NONEXISTENT_EA_ENTRY"},
+	{STATUS_NO_EAS_ON_FILE, -ENODATA, "STATUS_NO_EAS_ON_FILE"},
+	{STATUS_EA_CORRUPT_ERROR, -EIO, "STATUS_EA_CORRUPT_ERROR"},
+	{STATUS_FILE_LOCK_CONFLICT, -EIO, "STATUS_FILE_LOCK_CONFLICT"},
+	{STATUS_LOCK_NOT_GRANTED, -EIO, "STATUS_LOCK_NOT_GRANTED"},
+	{STATUS_DELETE_PENDING, -ENOENT, "STATUS_DELETE_PENDING"},
+	{STATUS_CTL_FILE_NOT_SUPPORTED, -ENOSYS,
+	"STATUS_CTL_FILE_NOT_SUPPORTED"},
+	{STATUS_UNKNOWN_REVISION, -EIO, "STATUS_UNKNOWN_REVISION"},
+	{STATUS_REVISION_MISMATCH, -EIO, "STATUS_REVISION_MISMATCH"},
+	{STATUS_INVALID_OWNER, -EIO, "STATUS_INVALID_OWNER"},
+	{STATUS_INVALID_PRIMARY_GROUP, -EIO, "STATUS_INVALID_PRIMARY_GROUP"},
+	{STATUS_NO_IMPERSONATION_TOKEN, -EIO, "STATUS_NO_IMPERSONATION_TOKEN"},
+	{STATUS_CANT_DISABLE_MANDATORY, -EIO, "STATUS_CANT_DISABLE_MANDATORY"},
+	{STATUS_NO_LOGON_SERVERS, -EIO, "STATUS_NO_LOGON_SERVERS"},
+	{STATUS_NO_SUCH_LOGON_SESSION, -EIO, "STATUS_NO_SUCH_LOGON_SESSION"},
+	{STATUS_NO_SUCH_PRIVILEGE, -EIO, "STATUS_NO_SUCH_PRIVILEGE"},
+	{STATUS_PRIVILEGE_NOT_HELD, -EIO, "STATUS_PRIVILEGE_NOT_HELD"},
+	{STATUS_INVALID_ACCOUNT_NAME, -EIO, "STATUS_INVALID_ACCOUNT_NAME"},
+	{STATUS_USER_EXISTS, -EIO, "STATUS_USER_EXISTS"},
+	{STATUS_NO_SUCH_USER, -EIO, "STATUS_NO_SUCH_USER"},
+	{STATUS_GROUP_EXISTS, -EIO, "STATUS_GROUP_EXISTS"},
+	{STATUS_NO_SUCH_GROUP, -EIO, "STATUS_NO_SUCH_GROUP"},
+	{STATUS_MEMBER_IN_GROUP, -EIO, "STATUS_MEMBER_IN_GROUP"},
+	{STATUS_MEMBER_NOT_IN_GROUP, -EIO, "STATUS_MEMBER_NOT_IN_GROUP"},
+	{STATUS_LAST_ADMIN, -EIO, "STATUS_LAST_ADMIN"},
+	{STATUS_WRONG_PASSWORD, -EACCES, "STATUS_WRONG_PASSWORD"},
+	{STATUS_ILL_FORMED_PASSWORD, -EINVAL, "STATUS_ILL_FORMED_PASSWORD"},
+	{STATUS_PASSWORD_RESTRICTION, -EACCES, "STATUS_PASSWORD_RESTRICTION"},
+	{STATUS_LOGON_FAILURE, -EACCES, "STATUS_LOGON_FAILURE"},
+	{STATUS_ACCOUNT_RESTRICTION, -EACCES, "STATUS_ACCOUNT_RESTRICTION"},
+	{STATUS_INVALID_LOGON_HOURS, -EACCES, "STATUS_INVALID_LOGON_HOURS"},
+	{STATUS_INVALID_WORKSTATION, -EACCES, "STATUS_INVALID_WORKSTATION"},
+	{STATUS_PASSWORD_EXPIRED, -EKEYEXPIRED, "STATUS_PASSWORD_EXPIRED"},
+	{STATUS_ACCOUNT_DISABLED, -EKEYREVOKED, "STATUS_ACCOUNT_DISABLED"},
+	{STATUS_NONE_MAPPED, -EIO, "STATUS_NONE_MAPPED"},
+	{STATUS_TOO_MANY_LUIDS_REQUESTED, -EIO,
+	"STATUS_TOO_MANY_LUIDS_REQUESTED"},
+	{STATUS_LUIDS_EXHAUSTED, -EIO, "STATUS_LUIDS_EXHAUSTED"},
+	{STATUS_INVALID_SUB_AUTHORITY, -EIO, "STATUS_INVALID_SUB_AUTHORITY"},
+	{STATUS_INVALID_ACL, -EIO, "STATUS_INVALID_ACL"},
+	{STATUS_INVALID_SID, -EIO, "STATUS_INVALID_SID"},
+	{STATUS_INVALID_SECURITY_DESCR, -EIO, "STATUS_INVALID_SECURITY_DESCR"},
+	{STATUS_PROCEDURE_NOT_FOUND, -EIO, "STATUS_PROCEDURE_NOT_FOUND"},
+	{STATUS_INVALID_IMAGE_FORMAT, -EIO, "STATUS_INVALID_IMAGE_FORMAT"},
+	{STATUS_NO_TOKEN, -EIO, "STATUS_NO_TOKEN"},
+	{STATUS_BAD_INHERITANCE_ACL, -EIO, "STATUS_BAD_INHERITANCE_ACL"},
+	{STATUS_RANGE_NOT_LOCKED, -EIO, "STATUS_RANGE_NOT_LOCKED"},
+	{STATUS_DISK_FULL, -ENOSPC, "STATUS_DISK_FULL"},
+	{STATUS_SERVER_DISABLED, -EIO, "STATUS_SERVER_DISABLED"},
+	{STATUS_SERVER_NOT_DISABLED, -EIO, "STATUS_SERVER_NOT_DISABLED"},
+	{STATUS_TOO_MANY_GUIDS_REQUESTED, -EIO,
+	"STATUS_TOO_MANY_GUIDS_REQUESTED"},
+	{STATUS_GUIDS_EXHAUSTED, -EIO, "STATUS_GUIDS_EXHAUSTED"},
+	{STATUS_INVALID_ID_AUTHORITY, -EIO, "STATUS_INVALID_ID_AUTHORITY"},
+	{STATUS_AGENTS_EXHAUSTED, -EIO, "STATUS_AGENTS_EXHAUSTED"},
+	{STATUS_INVALID_VOLUME_LABEL, -EIO, "STATUS_INVALID_VOLUME_LABEL"},
+	{STATUS_SECTION_NOT_EXTENDED, -EIO, "STATUS_SECTION_NOT_EXTENDED"},
+	{STATUS_NOT_MAPPED_DATA, -EIO, "STATUS_NOT_MAPPED_DATA"},
+	{STATUS_RESOURCE_DATA_NOT_FOUND, -EIO,
+	"STATUS_RESOURCE_DATA_NOT_FOUND"},
+	{STATUS_RESOURCE_TYPE_NOT_FOUND, -EIO,
+	"STATUS_RESOURCE_TYPE_NOT_FOUND"},
+	{STATUS_RESOURCE_NAME_NOT_FOUND, -EIO,
+	"STATUS_RESOURCE_NAME_NOT_FOUND"},
+	{STATUS_ARRAY_BOUNDS_EXCEEDED, -EIO, "STATUS_ARRAY_BOUNDS_EXCEEDED"},
+	{STATUS_FLOAT_DENORMAL_OPERAND, -EIO, "STATUS_FLOAT_DENORMAL_OPERAND"},
+	{STATUS_FLOAT_DIVIDE_BY_ZERO, -EIO, "STATUS_FLOAT_DIVIDE_BY_ZERO"},
+	{STATUS_FLOAT_INEXACT_RESULT, -EIO, "STATUS_FLOAT_INEXACT_RESULT"},
+	{STATUS_FLOAT_INVALID_OPERATION, -EIO,
+	"STATUS_FLOAT_INVALID_OPERATION"},
+	{STATUS_FLOAT_OVERFLOW, -EIO, "STATUS_FLOAT_OVERFLOW"},
+	{STATUS_FLOAT_STACK_CHECK, -EIO, "STATUS_FLOAT_STACK_CHECK"},
+	{STATUS_FLOAT_UNDERFLOW, -EIO, "STATUS_FLOAT_UNDERFLOW"},
+	{STATUS_INTEGER_DIVIDE_BY_ZERO, -EIO, "STATUS_INTEGER_DIVIDE_BY_ZERO"},
+	{STATUS_INTEGER_OVERFLOW, -EIO, "STATUS_INTEGER_OVERFLOW"},
+	{STATUS_PRIVILEGED_INSTRUCTION, -EIO, "STATUS_PRIVILEGED_INSTRUCTION"},
+	{STATUS_TOO_MANY_PAGING_FILES, -EIO, "STATUS_TOO_MANY_PAGING_FILES"},
+	{STATUS_FILE_INVALID, -EIO, "STATUS_FILE_INVALID"},
+	{STATUS_ALLOTTED_SPACE_EXCEEDED, -EIO,
+	"STATUS_ALLOTTED_SPACE_EXCEEDED"},
+	{STATUS_INSUFFICIENT_RESOURCES, -EIO, "STATUS_INSUFFICIENT_RESOURCES"},
+	{STATUS_DFS_EXIT_PATH_FOUND, -EIO, "STATUS_DFS_EXIT_PATH_FOUND"},
+	{STATUS_DEVICE_DATA_ERROR, -EIO, "STATUS_DEVICE_DATA_ERROR"},
+	{STATUS_DEVICE_NOT_CONNECTED, -EIO, "STATUS_DEVICE_NOT_CONNECTED"},
+	{STATUS_DEVICE_POWER_FAILURE, -EIO, "STATUS_DEVICE_POWER_FAILURE"},
+	{STATUS_FREE_VM_NOT_AT_BASE, -EIO, "STATUS_FREE_VM_NOT_AT_BASE"},
+	{STATUS_MEMORY_NOT_ALLOCATED, -EFAULT, "STATUS_MEMORY_NOT_ALLOCATED"},
+	{STATUS_WORKING_SET_QUOTA, -EIO, "STATUS_WORKING_SET_QUOTA"},
+	{STATUS_MEDIA_WRITE_PROTECTED, -EROFS, "STATUS_MEDIA_WRITE_PROTECTED"},
+	{STATUS_DEVICE_NOT_READY, -EIO, "STATUS_DEVICE_NOT_READY"},
+	{STATUS_INVALID_GROUP_ATTRIBUTES, -EIO,
+	"STATUS_INVALID_GROUP_ATTRIBUTES"},
+	{STATUS_BAD_IMPERSONATION_LEVEL, -EIO,
+	"STATUS_BAD_IMPERSONATION_LEVEL"},
+	{STATUS_CANT_OPEN_ANONYMOUS, -EIO, "STATUS_CANT_OPEN_ANONYMOUS"},
+	{STATUS_BAD_VALIDATION_CLASS, -EIO, "STATUS_BAD_VALIDATION_CLASS"},
+	{STATUS_BAD_TOKEN_TYPE, -EIO, "STATUS_BAD_TOKEN_TYPE"},
+	{STATUS_BAD_MASTER_BOOT_RECORD, -EIO, "STATUS_BAD_MASTER_BOOT_RECORD"},
+	{STATUS_INSTRUCTION_MISALIGNMENT, -EIO,
+	"STATUS_INSTRUCTION_MISALIGNMENT"},
+	{STATUS_INSTANCE_NOT_AVAILABLE, -EIO, "STATUS_INSTANCE_NOT_AVAILABLE"},
+	{STATUS_PIPE_NOT_AVAILABLE, -EIO, "STATUS_PIPE_NOT_AVAILABLE"},
+	{STATUS_INVALID_PIPE_STATE, -EIO, "STATUS_INVALID_PIPE_STATE"},
+	{STATUS_PIPE_BUSY, -EBUSY, "STATUS_PIPE_BUSY"},
+	{STATUS_ILLEGAL_FUNCTION, -EIO, "STATUS_ILLEGAL_FUNCTION"},
+	{STATUS_PIPE_DISCONNECTED, -EPIPE, "STATUS_PIPE_DISCONNECTED"},
+	{STATUS_PIPE_CLOSING, -EIO, "STATUS_PIPE_CLOSING"},
+	{STATUS_PIPE_CONNECTED, -EIO, "STATUS_PIPE_CONNECTED"},
+	{STATUS_PIPE_LISTENING, -EIO, "STATUS_PIPE_LISTENING"},
+	{STATUS_INVALID_READ_MODE, -EIO, "STATUS_INVALID_READ_MODE"},
+	{STATUS_IO_TIMEOUT, -ETIMEDOUT, "STATUS_IO_TIMEOUT"},
+	{STATUS_FILE_FORCED_CLOSED, -EIO, "STATUS_FILE_FORCED_CLOSED"},
+	{STATUS_PROFILING_NOT_STARTED, -EIO, "STATUS_PROFILING_NOT_STARTED"},
+	{STATUS_PROFILING_NOT_STOPPED, -EIO, "STATUS_PROFILING_NOT_STOPPED"},
+	{STATUS_COULD_NOT_INTERPRET, -EIO, "STATUS_COULD_NOT_INTERPRET"},
+	{STATUS_FILE_IS_A_DIRECTORY, -EISDIR, "STATUS_FILE_IS_A_DIRECTORY"},
+	{STATUS_NOT_SUPPORTED, -EOPNOTSUPP, "STATUS_NOT_SUPPORTED"},
+	{STATUS_REMOTE_NOT_LISTENING, -EHOSTDOWN,
+	"STATUS_REMOTE_NOT_LISTENING"},
+	{STATUS_DUPLICATE_NAME, -ENOTUNIQ, "STATUS_DUPLICATE_NAME"},
+	{STATUS_BAD_NETWORK_PATH, -EINVAL, "STATUS_BAD_NETWORK_PATH"},
+	{STATUS_NETWORK_BUSY, -EBUSY, "STATUS_NETWORK_BUSY"},
+	{STATUS_DEVICE_DOES_NOT_EXIST, -ENODEV, "STATUS_DEVICE_DOES_NOT_EXIST"},
+	{STATUS_TOO_MANY_COMMANDS, -EIO, "STATUS_TOO_MANY_COMMANDS"},
+	{STATUS_ADAPTER_HARDWARE_ERROR, -EIO, "STATUS_ADAPTER_HARDWARE_ERROR"},
+	{STATUS_INVALID_NETWORK_RESPONSE, -EIO,
+	"STATUS_INVALID_NETWORK_RESPONSE"},
+	{STATUS_UNEXPECTED_NETWORK_ERROR, -EIO,
+	"STATUS_UNEXPECTED_NETWORK_ERROR"},
+	{STATUS_BAD_REMOTE_ADAPTER, -EIO, "STATUS_BAD_REMOTE_ADAPTER"},
+	{STATUS_PRINT_QUEUE_FULL, -EIO, "STATUS_PRINT_QUEUE_FULL"},
+	{STATUS_NO_SPOOL_SPACE, -EIO, "STATUS_NO_SPOOL_SPACE"},
+	{STATUS_PRINT_CANCELLED, -EIO, "STATUS_PRINT_CANCELLED"},
+	{STATUS_NETWORK_NAME_DELETED, -EIO, "STATUS_NETWORK_NAME_DELETED"},
+	{STATUS_NETWORK_ACCESS_DENIED, -EACCES, "STATUS_NETWORK_ACCESS_DENIED"},
+	{STATUS_BAD_DEVICE_TYPE, -EIO, "STATUS_BAD_DEVICE_TYPE"},
+	{STATUS_BAD_NETWORK_NAME, -ENOENT, "STATUS_BAD_NETWORK_NAME"},
+	{STATUS_TOO_MANY_NAMES, -EIO, "STATUS_TOO_MANY_NAMES"},
+	{STATUS_TOO_MANY_SESSIONS, -EIO, "STATUS_TOO_MANY_SESSIONS"},
+	{STATUS_SHARING_PAUSED, -EIO, "STATUS_SHARING_PAUSED"},
+	{STATUS_REQUEST_NOT_ACCEPTED, -EIO, "STATUS_REQUEST_NOT_ACCEPTED"},
+	{STATUS_REDIRECTOR_PAUSED, -EIO, "STATUS_REDIRECTOR_PAUSED"},
+	{STATUS_NET_WRITE_FAULT, -EIO, "STATUS_NET_WRITE_FAULT"},
+	{STATUS_PROFILING_AT_LIMIT, -EIO, "STATUS_PROFILING_AT_LIMIT"},
+	{STATUS_NOT_SAME_DEVICE, -EXDEV, "STATUS_NOT_SAME_DEVICE"},
+	{STATUS_FILE_RENAMED, -EIO, "STATUS_FILE_RENAMED"},
+	{STATUS_VIRTUAL_CIRCUIT_CLOSED, -EIO, "STATUS_VIRTUAL_CIRCUIT_CLOSED"},
+	{STATUS_NO_SECURITY_ON_OBJECT, -EIO, "STATUS_NO_SECURITY_ON_OBJECT"},
+	{STATUS_CANT_WAIT, -EIO, "STATUS_CANT_WAIT"},
+	{STATUS_PIPE_EMPTY, -EIO, "STATUS_PIPE_EMPTY"},
+	{STATUS_CANT_ACCESS_DOMAIN_INFO, -EIO,
+	"STATUS_CANT_ACCESS_DOMAIN_INFO"},
+	{STATUS_CANT_TERMINATE_SELF, -EIO, "STATUS_CANT_TERMINATE_SELF"},
+	{STATUS_INVALID_SERVER_STATE, -EIO, "STATUS_INVALID_SERVER_STATE"},
+	{STATUS_INVALID_DOMAIN_STATE, -EIO, "STATUS_INVALID_DOMAIN_STATE"},
+	{STATUS_INVALID_DOMAIN_ROLE, -EIO, "STATUS_INVALID_DOMAIN_ROLE"},
+	{STATUS_NO_SUCH_DOMAIN, -EIO, "STATUS_NO_SUCH_DOMAIN"},
+	{STATUS_DOMAIN_EXISTS, -EIO, "STATUS_DOMAIN_EXISTS"},
+	{STATUS_DOMAIN_LIMIT_EXCEEDED, -EIO, "STATUS_DOMAIN_LIMIT_EXCEEDED"},
+	{STATUS_OPLOCK_NOT_GRANTED, -EIO, "STATUS_OPLOCK_NOT_GRANTED"},
+	{STATUS_INVALID_OPLOCK_PROTOCOL, -EIO,
+	"STATUS_INVALID_OPLOCK_PROTOCOL"},
+	{STATUS_INTERNAL_DB_CORRUPTION, -EIO, "STATUS_INTERNAL_DB_CORRUPTION"},
+	{STATUS_INTERNAL_ERROR, -EIO, "STATUS_INTERNAL_ERROR"},
+	{STATUS_GENERIC_NOT_MAPPED, -EIO, "STATUS_GENERIC_NOT_MAPPED"},
+	{STATUS_BAD_DESCRIPTOR_FORMAT, -EIO, "STATUS_BAD_DESCRIPTOR_FORMAT"},
+	{STATUS_INVALID_USER_BUFFER, -EIO, "STATUS_INVALID_USER_BUFFER"},
+	{STATUS_UNEXPECTED_IO_ERROR, -EIO, "STATUS_UNEXPECTED_IO_ERROR"},
+	{STATUS_UNEXPECTED_MM_CREATE_ERR, -EIO,
+	"STATUS_UNEXPECTED_MM_CREATE_ERR"},
+	{STATUS_UNEXPECTED_MM_MAP_ERROR, -EIO,
+	"STATUS_UNEXPECTED_MM_MAP_ERROR"},
+	{STATUS_UNEXPECTED_MM_EXTEND_ERR, -EIO,
+	"STATUS_UNEXPECTED_MM_EXTEND_ERR"},
+	{STATUS_NOT_LOGON_PROCESS, -EIO, "STATUS_NOT_LOGON_PROCESS"},
+	{STATUS_LOGON_SESSION_EXISTS, -EIO, "STATUS_LOGON_SESSION_EXISTS"},
+	{STATUS_INVALID_PARAMETER_1, -EINVAL, "STATUS_INVALID_PARAMETER_1"},
+	{STATUS_INVALID_PARAMETER_2, -EINVAL, "STATUS_INVALID_PARAMETER_2"},
+	{STATUS_INVALID_PARAMETER_3, -EINVAL, "STATUS_INVALID_PARAMETER_3"},
+	{STATUS_INVALID_PARAMETER_4, -EINVAL, "STATUS_INVALID_PARAMETER_4"},
+	{STATUS_INVALID_PARAMETER_5, -EINVAL, "STATUS_INVALID_PARAMETER_5"},
+	{STATUS_INVALID_PARAMETER_6, -EINVAL, "STATUS_INVALID_PARAMETER_6"},
+	{STATUS_INVALID_PARAMETER_7, -EINVAL, "STATUS_INVALID_PARAMETER_7"},
+	{STATUS_INVALID_PARAMETER_8, -EINVAL, "STATUS_INVALID_PARAMETER_8"},
+	{STATUS_INVALID_PARAMETER_9, -EINVAL, "STATUS_INVALID_PARAMETER_9"},
+	{STATUS_INVALID_PARAMETER_10, -EINVAL, "STATUS_INVALID_PARAMETER_10"},
+	{STATUS_INVALID_PARAMETER_11, -EINVAL, "STATUS_INVALID_PARAMETER_11"},
+	{STATUS_INVALID_PARAMETER_12, -EINVAL, "STATUS_INVALID_PARAMETER_12"},
+	{STATUS_REDIRECTOR_NOT_STARTED, -EIO, "STATUS_REDIRECTOR_NOT_STARTED"},
+	{STATUS_REDIRECTOR_STARTED, -EIO, "STATUS_REDIRECTOR_STARTED"},
+	{STATUS_STACK_OVERFLOW, -EIO, "STATUS_STACK_OVERFLOW"},
+	{STATUS_NO_SUCH_PACKAGE, -EIO, "STATUS_NO_SUCH_PACKAGE"},
+	{STATUS_BAD_FUNCTION_TABLE, -EIO, "STATUS_BAD_FUNCTION_TABLE"},
+	{STATUS_VARIABLE_NOT_FOUND, -EIO, "STATUS_VARIABLE_NOT_FOUND"},
+	{STATUS_DIRECTORY_NOT_EMPTY, -ENOTEMPTY, "STATUS_DIRECTORY_NOT_EMPTY"},
+	{STATUS_FILE_CORRUPT_ERROR, -EIO, "STATUS_FILE_CORRUPT_ERROR"},
+	{STATUS_NOT_A_DIRECTORY, -ENOTDIR, "STATUS_NOT_A_DIRECTORY"},
+	{STATUS_BAD_LOGON_SESSION_STATE, -EIO,
+	"STATUS_BAD_LOGON_SESSION_STATE"},
+	{STATUS_LOGON_SESSION_COLLISION, -EIO,
+	"STATUS_LOGON_SESSION_COLLISION"},
+	{STATUS_NAME_TOO_LONG, -ENAMETOOLONG, "STATUS_NAME_TOO_LONG"},
+	{STATUS_FILES_OPEN, -EIO, "STATUS_FILES_OPEN"},
+	{STATUS_CONNECTION_IN_USE, -EIO, "STATUS_CONNECTION_IN_USE"},
+	{STATUS_MESSAGE_NOT_FOUND, -EIO, "STATUS_MESSAGE_NOT_FOUND"},
+	{STATUS_PROCESS_IS_TERMINATING, -EIO, "STATUS_PROCESS_IS_TERMINATING"},
+	{STATUS_INVALID_LOGON_TYPE, -EIO, "STATUS_INVALID_LOGON_TYPE"},
+	{STATUS_NO_GUID_TRANSLATION, -EIO, "STATUS_NO_GUID_TRANSLATION"},
+	{STATUS_CANNOT_IMPERSONATE, -EIO, "STATUS_CANNOT_IMPERSONATE"},
+	{STATUS_IMAGE_ALREADY_LOADED, -EIO, "STATUS_IMAGE_ALREADY_LOADED"},
+	{STATUS_ABIOS_NOT_PRESENT, -EIO, "STATUS_ABIOS_NOT_PRESENT"},
+	{STATUS_ABIOS_LID_NOT_EXIST, -EIO, "STATUS_ABIOS_LID_NOT_EXIST"},
+	{STATUS_ABIOS_LID_ALREADY_OWNED, -EIO,
+	"STATUS_ABIOS_LID_ALREADY_OWNED"},
+	{STATUS_ABIOS_NOT_LID_OWNER, -EIO, "STATUS_ABIOS_NOT_LID_OWNER"},
+	{STATUS_ABIOS_INVALID_COMMAND, -EIO, "STATUS_ABIOS_INVALID_COMMAND"},
+	{STATUS_ABIOS_INVALID_LID, -EIO, "STATUS_ABIOS_INVALID_LID"},
+	{STATUS_ABIOS_SELECTOR_NOT_AVAILABLE, -EIO,
+	"STATUS_ABIOS_SELECTOR_NOT_AVAILABLE"},
+	{STATUS_ABIOS_INVALID_SELECTOR, -EIO, "STATUS_ABIOS_INVALID_SELECTOR"},
+	{STATUS_NO_LDT, -EIO, "STATUS_NO_LDT"},
+	{STATUS_INVALID_LDT_SIZE, -EIO, "STATUS_INVALID_LDT_SIZE"},
+	{STATUS_INVALID_LDT_OFFSET, -EIO, "STATUS_INVALID_LDT_OFFSET"},
+	{STATUS_INVALID_LDT_DESCRIPTOR, -EIO, "STATUS_INVALID_LDT_DESCRIPTOR"},
+	{STATUS_INVALID_IMAGE_NE_FORMAT, -EIO,
+	"STATUS_INVALID_IMAGE_NE_FORMAT"},
+	{STATUS_RXACT_INVALID_STATE, -EIO, "STATUS_RXACT_INVALID_STATE"},
+	{STATUS_RXACT_COMMIT_FAILURE, -EIO, "STATUS_RXACT_COMMIT_FAILURE"},
+	{STATUS_MAPPED_FILE_SIZE_ZERO, -EIO, "STATUS_MAPPED_FILE_SIZE_ZERO"},
+	{STATUS_TOO_MANY_OPENED_FILES, -EMFILE, "STATUS_TOO_MANY_OPENED_FILES"},
+	{STATUS_CANCELLED, -EIO, "STATUS_CANCELLED"},
+	{STATUS_CANNOT_DELETE, -EIO, "STATUS_CANNOT_DELETE"},
+	{STATUS_INVALID_COMPUTER_NAME, -EIO, "STATUS_INVALID_COMPUTER_NAME"},
+	{STATUS_FILE_DELETED, -EIO, "STATUS_FILE_DELETED"},
+	{STATUS_SPECIAL_ACCOUNT, -EIO, "STATUS_SPECIAL_ACCOUNT"},
+	{STATUS_SPECIAL_GROUP, -EIO, "STATUS_SPECIAL_GROUP"},
+	{STATUS_SPECIAL_USER, -EIO, "STATUS_SPECIAL_USER"},
+	{STATUS_MEMBERS_PRIMARY_GROUP, -EIO, "STATUS_MEMBERS_PRIMARY_GROUP"},
+	{STATUS_FILE_CLOSED, -EBADF, "STATUS_FILE_CLOSED"},
+	{STATUS_TOO_MANY_THREADS, -EIO, "STATUS_TOO_MANY_THREADS"},
+	{STATUS_THREAD_NOT_IN_PROCESS, -EIO, "STATUS_THREAD_NOT_IN_PROCESS"},
+	{STATUS_TOKEN_ALREADY_IN_USE, -EIO, "STATUS_TOKEN_ALREADY_IN_USE"},
+	{STATUS_PAGEFILE_QUOTA_EXCEEDED, -EDQUOT,
+	"STATUS_PAGEFILE_QUOTA_EXCEEDED"},
+	{STATUS_COMMITMENT_LIMIT, -EIO, "STATUS_COMMITMENT_LIMIT"},
+	{STATUS_INVALID_IMAGE_LE_FORMAT, -EIO,
+	"STATUS_INVALID_IMAGE_LE_FORMAT"},
+	{STATUS_INVALID_IMAGE_NOT_MZ, -EIO, "STATUS_INVALID_IMAGE_NOT_MZ"},
+	{STATUS_INVALID_IMAGE_PROTECT, -EIO, "STATUS_INVALID_IMAGE_PROTECT"},
+	{STATUS_INVALID_IMAGE_WIN_16, -EIO, "STATUS_INVALID_IMAGE_WIN_16"},
+	{STATUS_LOGON_SERVER_CONFLICT, -EIO, "STATUS_LOGON_SERVER_CONFLICT"},
+	{STATUS_TIME_DIFFERENCE_AT_DC, -EIO, "STATUS_TIME_DIFFERENCE_AT_DC"},
+	{STATUS_SYNCHRONIZATION_REQUIRED, -EIO,
+	"STATUS_SYNCHRONIZATION_REQUIRED"},
+	{STATUS_DLL_NOT_FOUND, -ENOENT, "STATUS_DLL_NOT_FOUND"},
+	{STATUS_OPEN_FAILED, -EIO, "STATUS_OPEN_FAILED"},
+	{STATUS_IO_PRIVILEGE_FAILED, -EIO, "STATUS_IO_PRIVILEGE_FAILED"},
+	{STATUS_ORDINAL_NOT_FOUND, -EIO, "STATUS_ORDINAL_NOT_FOUND"},
+	{STATUS_ENTRYPOINT_NOT_FOUND, -EIO, "STATUS_ENTRYPOINT_NOT_FOUND"},
+	{STATUS_CONTROL_C_EXIT, -EIO, "STATUS_CONTROL_C_EXIT"},
+	{STATUS_LOCAL_DISCONNECT, -EIO, "STATUS_LOCAL_DISCONNECT"},
+	{STATUS_REMOTE_DISCONNECT, -ESHUTDOWN, "STATUS_REMOTE_DISCONNECT"},
+	{STATUS_REMOTE_RESOURCES, -EIO, "STATUS_REMOTE_RESOURCES"},
+	{STATUS_LINK_FAILED, -EXDEV, "STATUS_LINK_FAILED"},
+	{STATUS_LINK_TIMEOUT, -ETIMEDOUT, "STATUS_LINK_TIMEOUT"},
+	{STATUS_INVALID_CONNECTION, -EIO, "STATUS_INVALID_CONNECTION"},
+	{STATUS_INVALID_ADDRESS, -EIO, "STATUS_INVALID_ADDRESS"},
+	{STATUS_DLL_INIT_FAILED, -EIO, "STATUS_DLL_INIT_FAILED"},
+	{STATUS_MISSING_SYSTEMFILE, -EIO, "STATUS_MISSING_SYSTEMFILE"},
+	{STATUS_UNHANDLED_EXCEPTION, -EIO, "STATUS_UNHANDLED_EXCEPTION"},
+	{STATUS_APP_INIT_FAILURE, -EIO, "STATUS_APP_INIT_FAILURE"},
+	{STATUS_PAGEFILE_CREATE_FAILED, -EIO, "STATUS_PAGEFILE_CREATE_FAILED"},
+	{STATUS_NO_PAGEFILE, -EIO, "STATUS_NO_PAGEFILE"},
+	{STATUS_INVALID_LEVEL, -EIO, "STATUS_INVALID_LEVEL"},
+	{STATUS_WRONG_PASSWORD_CORE, -EIO, "STATUS_WRONG_PASSWORD_CORE"},
+	{STATUS_ILLEGAL_FLOAT_CONTEXT, -EIO, "STATUS_ILLEGAL_FLOAT_CONTEXT"},
+	{STATUS_PIPE_BROKEN, -EPIPE, "STATUS_PIPE_BROKEN"},
+	{STATUS_REGISTRY_CORRUPT, -EIO, "STATUS_REGISTRY_CORRUPT"},
+	{STATUS_REGISTRY_IO_FAILED, -EIO, "STATUS_REGISTRY_IO_FAILED"},
+	{STATUS_NO_EVENT_PAIR, -EIO, "STATUS_NO_EVENT_PAIR"},
+	{STATUS_UNRECOGNIZED_VOLUME, -EIO, "STATUS_UNRECOGNIZED_VOLUME"},
+	{STATUS_SERIAL_NO_DEVICE_INITED, -EIO,
+	"STATUS_SERIAL_NO_DEVICE_INITED"},
+	{STATUS_NO_SUCH_ALIAS, -EIO, "STATUS_NO_SUCH_ALIAS"},
+	{STATUS_MEMBER_NOT_IN_ALIAS, -EIO, "STATUS_MEMBER_NOT_IN_ALIAS"},
+	{STATUS_MEMBER_IN_ALIAS, -EIO, "STATUS_MEMBER_IN_ALIAS"},
+	{STATUS_ALIAS_EXISTS, -EIO, "STATUS_ALIAS_EXISTS"},
+	{STATUS_LOGON_NOT_GRANTED, -EIO, "STATUS_LOGON_NOT_GRANTED"},
+	{STATUS_TOO_MANY_SECRETS, -EIO, "STATUS_TOO_MANY_SECRETS"},
+	{STATUS_SECRET_TOO_LONG, -EIO, "STATUS_SECRET_TOO_LONG"},
+	{STATUS_INTERNAL_DB_ERROR, -EIO, "STATUS_INTERNAL_DB_ERROR"},
+	{STATUS_FULLSCREEN_MODE, -EIO, "STATUS_FULLSCREEN_MODE"},
+	{STATUS_TOO_MANY_CONTEXT_IDS, -EIO, "STATUS_TOO_MANY_CONTEXT_IDS"},
+	{STATUS_LOGON_TYPE_NOT_GRANTED, -EIO, "STATUS_LOGON_TYPE_NOT_GRANTED"},
+	{STATUS_NOT_REGISTRY_FILE, -EIO, "STATUS_NOT_REGISTRY_FILE"},
+	{STATUS_NT_CROSS_ENCRYPTION_REQUIRED, -EIO,
+	"STATUS_NT_CROSS_ENCRYPTION_REQUIRED"},
+	{STATUS_DOMAIN_CTRLR_CONFIG_ERROR, -EIO,
+	"STATUS_DOMAIN_CTRLR_CONFIG_ERROR"},
+	{STATUS_FT_MISSING_MEMBER, -EIO, "STATUS_FT_MISSING_MEMBER"},
+	{STATUS_ILL_FORMED_SERVICE_ENTRY, -EIO,
+	"STATUS_ILL_FORMED_SERVICE_ENTRY"},
+	{STATUS_ILLEGAL_CHARACTER, -EIO, "STATUS_ILLEGAL_CHARACTER"},
+	{STATUS_UNMAPPABLE_CHARACTER, -EIO, "STATUS_UNMAPPABLE_CHARACTER"},
+	{STATUS_UNDEFINED_CHARACTER, -EIO, "STATUS_UNDEFINED_CHARACTER"},
+	{STATUS_FLOPPY_VOLUME, -EIO, "STATUS_FLOPPY_VOLUME"},
+	{STATUS_FLOPPY_ID_MARK_NOT_FOUND, -EIO,
+	"STATUS_FLOPPY_ID_MARK_NOT_FOUND"},
+	{STATUS_FLOPPY_WRONG_CYLINDER, -EIO, "STATUS_FLOPPY_WRONG_CYLINDER"},
+	{STATUS_FLOPPY_UNKNOWN_ERROR, -EIO, "STATUS_FLOPPY_UNKNOWN_ERROR"},
+	{STATUS_FLOPPY_BAD_REGISTERS, -EIO, "STATUS_FLOPPY_BAD_REGISTERS"},
+	{STATUS_DISK_RECALIBRATE_FAILED, -EIO,
+	"STATUS_DISK_RECALIBRATE_FAILED"},
+	{STATUS_DISK_OPERATION_FAILED, -EIO, "STATUS_DISK_OPERATION_FAILED"},
+	{STATUS_DISK_RESET_FAILED, -EIO, "STATUS_DISK_RESET_FAILED"},
+	{STATUS_SHARED_IRQ_BUSY, -EBUSY, "STATUS_SHARED_IRQ_BUSY"},
+	{STATUS_FT_ORPHANING, -EIO, "STATUS_FT_ORPHANING"},
+	{STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT, -EIO,
+	"STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT"},
+	{STATUS_PARTITION_FAILURE, -EIO, "STATUS_PARTITION_FAILURE"},
+	{STATUS_INVALID_BLOCK_LENGTH, -EIO, "STATUS_INVALID_BLOCK_LENGTH"},
+	{STATUS_DEVICE_NOT_PARTITIONED, -EIO, "STATUS_DEVICE_NOT_PARTITIONED"},
+	{STATUS_UNABLE_TO_LOCK_MEDIA, -EIO, "STATUS_UNABLE_TO_LOCK_MEDIA"},
+	{STATUS_UNABLE_TO_UNLOAD_MEDIA, -EIO, "STATUS_UNABLE_TO_UNLOAD_MEDIA"},
+	{STATUS_EOM_OVERFLOW, -EIO, "STATUS_EOM_OVERFLOW"},
+	{STATUS_NO_MEDIA, -EIO, "STATUS_NO_MEDIA"},
+	{STATUS_NO_SUCH_MEMBER, -EIO, "STATUS_NO_SUCH_MEMBER"},
+	{STATUS_INVALID_MEMBER, -EIO, "STATUS_INVALID_MEMBER"},
+	{STATUS_KEY_DELETED, -EIO, "STATUS_KEY_DELETED"},
+	{STATUS_NO_LOG_SPACE, -EIO, "STATUS_NO_LOG_SPACE"},
+	{STATUS_TOO_MANY_SIDS, -EIO, "STATUS_TOO_MANY_SIDS"},
+	{STATUS_LM_CROSS_ENCRYPTION_REQUIRED, -EIO,
+	"STATUS_LM_CROSS_ENCRYPTION_REQUIRED"},
+	{STATUS_KEY_HAS_CHILDREN, -EIO, "STATUS_KEY_HAS_CHILDREN"},
+	{STATUS_CHILD_MUST_BE_VOLATILE, -EIO, "STATUS_CHILD_MUST_BE_VOLATILE"},
+	{STATUS_DEVICE_CONFIGURATION_ERROR, -EIO,
+	"STATUS_DEVICE_CONFIGURATION_ERROR"},
+	{STATUS_DRIVER_INTERNAL_ERROR, -EIO, "STATUS_DRIVER_INTERNAL_ERROR"},
+	{STATUS_INVALID_DEVICE_STATE, -EIO, "STATUS_INVALID_DEVICE_STATE"},
+	{STATUS_IO_DEVICE_ERROR, -EIO, "STATUS_IO_DEVICE_ERROR"},
+	{STATUS_DEVICE_PROTOCOL_ERROR, -EIO, "STATUS_DEVICE_PROTOCOL_ERROR"},
+	{STATUS_BACKUP_CONTROLLER, -EIO, "STATUS_BACKUP_CONTROLLER"},
+	{STATUS_LOG_FILE_FULL, -EIO, "STATUS_LOG_FILE_FULL"},
+	{STATUS_TOO_LATE, -EIO, "STATUS_TOO_LATE"},
+	{STATUS_NO_TRUST_LSA_SECRET, -EIO, "STATUS_NO_TRUST_LSA_SECRET"},
+	{STATUS_NO_TRUST_SAM_ACCOUNT, -EIO, "STATUS_NO_TRUST_SAM_ACCOUNT"},
+	{STATUS_TRUSTED_DOMAIN_FAILURE, -EIO, "STATUS_TRUSTED_DOMAIN_FAILURE"},
+	{STATUS_TRUSTED_RELATIONSHIP_FAILURE, -EIO,
+	"STATUS_TRUSTED_RELATIONSHIP_FAILURE"},
+	{STATUS_EVENTLOG_FILE_CORRUPT, -EIO, "STATUS_EVENTLOG_FILE_CORRUPT"},
+	{STATUS_EVENTLOG_CANT_START, -EIO, "STATUS_EVENTLOG_CANT_START"},
+	{STATUS_TRUST_FAILURE, -EIO, "STATUS_TRUST_FAILURE"},
+	{STATUS_MUTANT_LIMIT_EXCEEDED, -EIO, "STATUS_MUTANT_LIMIT_EXCEEDED"},
+	{STATUS_NETLOGON_NOT_STARTED, -EIO, "STATUS_NETLOGON_NOT_STARTED"},
+	{STATUS_ACCOUNT_EXPIRED, -EKEYEXPIRED, "STATUS_ACCOUNT_EXPIRED"},
+	{STATUS_POSSIBLE_DEADLOCK, -EIO, "STATUS_POSSIBLE_DEADLOCK"},
+	{STATUS_NETWORK_CREDENTIAL_CONFLICT, -EIO,
+	"STATUS_NETWORK_CREDENTIAL_CONFLICT"},
+	{STATUS_REMOTE_SESSION_LIMIT, -EIO, "STATUS_REMOTE_SESSION_LIMIT"},
+	{STATUS_EVENTLOG_FILE_CHANGED, -EIO, "STATUS_EVENTLOG_FILE_CHANGED"},
+	{STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT, -EIO,
+	"STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT"},
+	{STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, -EIO,
+	"STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT"},
+	{STATUS_NOLOGON_SERVER_TRUST_ACCOUNT, -EIO,
+	"STATUS_NOLOGON_SERVER_TRUST_ACCOUNT"},
+	{STATUS_DOMAIN_TRUST_INCONSISTENT, -EIO,
+	"STATUS_DOMAIN_TRUST_INCONSISTENT"},
+	{STATUS_FS_DRIVER_REQUIRED, -EIO, "STATUS_FS_DRIVER_REQUIRED"},
+	{STATUS_IMAGE_ALREADY_LOADED_AS_DLL, -EIO,
+	"STATUS_IMAGE_ALREADY_LOADED_AS_DLL"},
+	{STATUS_NETWORK_OPEN_RESTRICTION, -EIO,
+	"STATUS_NETWORK_OPEN_RESTRICTION"},
+	{STATUS_NO_USER_SESSION_KEY, -EIO, "STATUS_NO_USER_SESSION_KEY"},
+	{STATUS_USER_SESSION_DELETED, -EIO, "STATUS_USER_SESSION_DELETED"},
+	{STATUS_RESOURCE_LANG_NOT_FOUND, -EIO,
+	"STATUS_RESOURCE_LANG_NOT_FOUND"},
+	{STATUS_INSUFF_SERVER_RESOURCES, -EIO,
+	"STATUS_INSUFF_SERVER_RESOURCES"},
+	{STATUS_INVALID_BUFFER_SIZE, -EIO, "STATUS_INVALID_BUFFER_SIZE"},
+	{STATUS_INVALID_ADDRESS_COMPONENT, -EIO,
+	"STATUS_INVALID_ADDRESS_COMPONENT"},
+	{STATUS_INVALID_ADDRESS_WILDCARD, -EIO,
+	"STATUS_INVALID_ADDRESS_WILDCARD"},
+	{STATUS_TOO_MANY_ADDRESSES, -EIO, "STATUS_TOO_MANY_ADDRESSES"},
+	{STATUS_ADDRESS_ALREADY_EXISTS, -EADDRINUSE,
+	"STATUS_ADDRESS_ALREADY_EXISTS"},
+	{STATUS_ADDRESS_CLOSED, -EIO, "STATUS_ADDRESS_CLOSED"},
+	{STATUS_CONNECTION_DISCONNECTED, -ECONNABORTED,
+	"STATUS_CONNECTION_DISCONNECTED"},
+	{STATUS_CONNECTION_RESET, -ENETRESET, "STATUS_CONNECTION_RESET"},
+	{STATUS_TOO_MANY_NODES, -EIO, "STATUS_TOO_MANY_NODES"},
+	{STATUS_TRANSACTION_ABORTED, -EIO, "STATUS_TRANSACTION_ABORTED"},
+	{STATUS_TRANSACTION_TIMED_OUT, -EIO, "STATUS_TRANSACTION_TIMED_OUT"},
+	{STATUS_TRANSACTION_NO_RELEASE, -EIO, "STATUS_TRANSACTION_NO_RELEASE"},
+	{STATUS_TRANSACTION_NO_MATCH, -EIO, "STATUS_TRANSACTION_NO_MATCH"},
+	{STATUS_TRANSACTION_RESPONDED, -EIO, "STATUS_TRANSACTION_RESPONDED"},
+	{STATUS_TRANSACTION_INVALID_ID, -EIO, "STATUS_TRANSACTION_INVALID_ID"},
+	{STATUS_TRANSACTION_INVALID_TYPE, -EIO,
+	"STATUS_TRANSACTION_INVALID_TYPE"},
+	{STATUS_NOT_SERVER_SESSION, -EIO, "STATUS_NOT_SERVER_SESSION"},
+	{STATUS_NOT_CLIENT_SESSION, -EIO, "STATUS_NOT_CLIENT_SESSION"},
+	{STATUS_CANNOT_LOAD_REGISTRY_FILE, -EIO,
+	"STATUS_CANNOT_LOAD_REGISTRY_FILE"},
+	{STATUS_DEBUG_ATTACH_FAILED, -EIO, "STATUS_DEBUG_ATTACH_FAILED"},
+	{STATUS_SYSTEM_PROCESS_TERMINATED, -EIO,
+	"STATUS_SYSTEM_PROCESS_TERMINATED"},
+	{STATUS_DATA_NOT_ACCEPTED, -EIO, "STATUS_DATA_NOT_ACCEPTED"},
+	{STATUS_NO_BROWSER_SERVERS_FOUND, -EIO,
+	"STATUS_NO_BROWSER_SERVERS_FOUND"},
+	{STATUS_VDM_HARD_ERROR, -EIO, "STATUS_VDM_HARD_ERROR"},
+	{STATUS_DRIVER_CANCEL_TIMEOUT, -EIO, "STATUS_DRIVER_CANCEL_TIMEOUT"},
+	{STATUS_REPLY_MESSAGE_MISMATCH, -EIO, "STATUS_REPLY_MESSAGE_MISMATCH"},
+	{STATUS_MAPPED_ALIGNMENT, -EIO, "STATUS_MAPPED_ALIGNMENT"},
+	{STATUS_IMAGE_CHECKSUM_MISMATCH, -EIO,
+	"STATUS_IMAGE_CHECKSUM_MISMATCH"},
+	{STATUS_LOST_WRITEBEHIND_DATA, -EIO, "STATUS_LOST_WRITEBEHIND_DATA"},
+	{STATUS_CLIENT_SERVER_PARAMETERS_INVALID, -EIO,
+	"STATUS_CLIENT_SERVER_PARAMETERS_INVALID"},
+	{STATUS_PASSWORD_MUST_CHANGE, -EIO, "STATUS_PASSWORD_MUST_CHANGE"},
+	{STATUS_NOT_FOUND, -ENOENT, "STATUS_NOT_FOUND"},
+	{STATUS_NOT_TINY_STREAM, -EIO, "STATUS_NOT_TINY_STREAM"},
+	{STATUS_RECOVERY_FAILURE, -EIO, "STATUS_RECOVERY_FAILURE"},
+	{STATUS_STACK_OVERFLOW_READ, -EIO, "STATUS_STACK_OVERFLOW_READ"},
+	{STATUS_FAIL_CHECK, -EIO, "STATUS_FAIL_CHECK"},
+	{STATUS_DUPLICATE_OBJECTID, -EIO, "STATUS_DUPLICATE_OBJECTID"},
+	{STATUS_OBJECTID_EXISTS, -EIO, "STATUS_OBJECTID_EXISTS"},
+	{STATUS_CONVERT_TO_LARGE, -EIO, "STATUS_CONVERT_TO_LARGE"},
+	{STATUS_RETRY, -EAGAIN, "STATUS_RETRY"},
+	{STATUS_FOUND_OUT_OF_SCOPE, -EIO, "STATUS_FOUND_OUT_OF_SCOPE"},
+	{STATUS_ALLOCATE_BUCKET, -EIO, "STATUS_ALLOCATE_BUCKET"},
+	{STATUS_PROPSET_NOT_FOUND, -EIO, "STATUS_PROPSET_NOT_FOUND"},
+	{STATUS_MARSHALL_OVERFLOW, -EIO, "STATUS_MARSHALL_OVERFLOW"},
+	{STATUS_INVALID_VARIANT, -EIO, "STATUS_INVALID_VARIANT"},
+	{STATUS_DOMAIN_CONTROLLER_NOT_FOUND, -EIO,
+	"STATUS_DOMAIN_CONTROLLER_NOT_FOUND"},
+	{STATUS_ACCOUNT_LOCKED_OUT, -EIO, "STATUS_ACCOUNT_LOCKED_OUT"},
+	{STATUS_HANDLE_NOT_CLOSABLE, -EIO, "STATUS_HANDLE_NOT_CLOSABLE"},
+	{STATUS_CONNECTION_REFUSED, -EIO, "STATUS_CONNECTION_REFUSED"},
+	{STATUS_GRACEFUL_DISCONNECT, -EIO, "STATUS_GRACEFUL_DISCONNECT"},
+	{STATUS_ADDRESS_ALREADY_ASSOCIATED, -EIO,
+	"STATUS_ADDRESS_ALREADY_ASSOCIATED"},
+	{STATUS_ADDRESS_NOT_ASSOCIATED, -EIO, "STATUS_ADDRESS_NOT_ASSOCIATED"},
+	{STATUS_CONNECTION_INVALID, -EIO, "STATUS_CONNECTION_INVALID"},
+	{STATUS_CONNECTION_ACTIVE, -EIO, "STATUS_CONNECTION_ACTIVE"},
+	{STATUS_NETWORK_UNREACHABLE, -ENETUNREACH,
+	"STATUS_NETWORK_UNREACHABLE"},
+	{STATUS_HOST_UNREACHABLE, -EHOSTDOWN, "STATUS_HOST_UNREACHABLE"},
+	{STATUS_PROTOCOL_UNREACHABLE, -ENETUNREACH,
+	"STATUS_PROTOCOL_UNREACHABLE"},
+	{STATUS_PORT_UNREACHABLE, -ENETUNREACH, "STATUS_PORT_UNREACHABLE"},
+	{STATUS_REQUEST_ABORTED, -EIO, "STATUS_REQUEST_ABORTED"},
+	{STATUS_CONNECTION_ABORTED, -ECONNABORTED, "STATUS_CONNECTION_ABORTED"},
+	{STATUS_BAD_COMPRESSION_BUFFER, -EIO, "STATUS_BAD_COMPRESSION_BUFFER"},
+	{STATUS_USER_MAPPED_FILE, -EIO, "STATUS_USER_MAPPED_FILE"},
+	{STATUS_AUDIT_FAILED, -EIO, "STATUS_AUDIT_FAILED"},
+	{STATUS_TIMER_RESOLUTION_NOT_SET, -EIO,
+	"STATUS_TIMER_RESOLUTION_NOT_SET"},
+	{STATUS_CONNECTION_COUNT_LIMIT, -EIO, "STATUS_CONNECTION_COUNT_LIMIT"},
+	{STATUS_LOGIN_TIME_RESTRICTION, -EACCES,
+	"STATUS_LOGIN_TIME_RESTRICTION"},
+	{STATUS_LOGIN_WKSTA_RESTRICTION, -EACCES,
+	"STATUS_LOGIN_WKSTA_RESTRICTION"},
+	{STATUS_IMAGE_MP_UP_MISMATCH, -EIO, "STATUS_IMAGE_MP_UP_MISMATCH"},
+	{STATUS_INSUFFICIENT_LOGON_INFO, -EIO,
+	"STATUS_INSUFFICIENT_LOGON_INFO"},
+	{STATUS_BAD_DLL_ENTRYPOINT, -EIO, "STATUS_BAD_DLL_ENTRYPOINT"},
+	{STATUS_BAD_SERVICE_ENTRYPOINT, -EIO, "STATUS_BAD_SERVICE_ENTRYPOINT"},
+	{STATUS_LPC_REPLY_LOST, -EIO, "STATUS_LPC_REPLY_LOST"},
+	{STATUS_IP_ADDRESS_CONFLICT1, -EIO, "STATUS_IP_ADDRESS_CONFLICT1"},
+	{STATUS_IP_ADDRESS_CONFLICT2, -EIO, "STATUS_IP_ADDRESS_CONFLICT2"},
+	{STATUS_REGISTRY_QUOTA_LIMIT, -EDQUOT, "STATUS_REGISTRY_QUOTA_LIMIT"},
+	{STATUS_PATH_NOT_COVERED, -EREMOTE, "STATUS_PATH_NOT_COVERED"},
+	{STATUS_NO_CALLBACK_ACTIVE, -EIO, "STATUS_NO_CALLBACK_ACTIVE"},
+	{STATUS_LICENSE_QUOTA_EXCEEDED, -EACCES,
+	"STATUS_LICENSE_QUOTA_EXCEEDED"},
+	{STATUS_PWD_TOO_SHORT, -EIO, "STATUS_PWD_TOO_SHORT"},
+	{STATUS_PWD_TOO_RECENT, -EIO, "STATUS_PWD_TOO_RECENT"},
+	{STATUS_PWD_HISTORY_CONFLICT, -EIO, "STATUS_PWD_HISTORY_CONFLICT"},
+	{STATUS_PLUGPLAY_NO_DEVICE, -EIO, "STATUS_PLUGPLAY_NO_DEVICE"},
+	{STATUS_UNSUPPORTED_COMPRESSION, -EIO,
+	"STATUS_UNSUPPORTED_COMPRESSION"},
+	{STATUS_INVALID_HW_PROFILE, -EIO, "STATUS_INVALID_HW_PROFILE"},
+	{STATUS_INVALID_PLUGPLAY_DEVICE_PATH, -EIO,
+	"STATUS_INVALID_PLUGPLAY_DEVICE_PATH"},
+	{STATUS_DRIVER_ORDINAL_NOT_FOUND, -EIO,
+	"STATUS_DRIVER_ORDINAL_NOT_FOUND"},
+	{STATUS_DRIVER_ENTRYPOINT_NOT_FOUND, -EIO,
+	"STATUS_DRIVER_ENTRYPOINT_NOT_FOUND"},
+	{STATUS_RESOURCE_NOT_OWNED, -EIO, "STATUS_RESOURCE_NOT_OWNED"},
+	{STATUS_TOO_MANY_LINKS, -EMLINK, "STATUS_TOO_MANY_LINKS"},
+	{STATUS_QUOTA_LIST_INCONSISTENT, -EIO,
+	"STATUS_QUOTA_LIST_INCONSISTENT"},
+	{STATUS_FILE_IS_OFFLINE, -EIO, "STATUS_FILE_IS_OFFLINE"},
+	{STATUS_EVALUATION_EXPIRATION, -EIO, "STATUS_EVALUATION_EXPIRATION"},
+	{STATUS_ILLEGAL_DLL_RELOCATION, -EIO, "STATUS_ILLEGAL_DLL_RELOCATION"},
+	{STATUS_LICENSE_VIOLATION, -EIO, "STATUS_LICENSE_VIOLATION"},
+	{STATUS_DLL_INIT_FAILED_LOGOFF, -EIO, "STATUS_DLL_INIT_FAILED_LOGOFF"},
+	{STATUS_DRIVER_UNABLE_TO_LOAD, -EIO, "STATUS_DRIVER_UNABLE_TO_LOAD"},
+	{STATUS_DFS_UNAVAILABLE, -EIO, "STATUS_DFS_UNAVAILABLE"},
+	{STATUS_VOLUME_DISMOUNTED, -EIO, "STATUS_VOLUME_DISMOUNTED"},
+	{STATUS_WX86_INTERNAL_ERROR, -EIO, "STATUS_WX86_INTERNAL_ERROR"},
+	{STATUS_WX86_FLOAT_STACK_CHECK, -EIO, "STATUS_WX86_FLOAT_STACK_CHECK"},
+	{STATUS_VALIDATE_CONTINUE, -EIO, "STATUS_VALIDATE_CONTINUE"},
+	{STATUS_NO_MATCH, -EIO, "STATUS_NO_MATCH"},
+	{STATUS_NO_MORE_MATCHES, -EIO, "STATUS_NO_MORE_MATCHES"},
+	{STATUS_NOT_A_REPARSE_POINT, -EIO, "STATUS_NOT_A_REPARSE_POINT"},
+	{STATUS_IO_REPARSE_TAG_INVALID, -EIO, "STATUS_IO_REPARSE_TAG_INVALID"},
+	{STATUS_IO_REPARSE_TAG_MISMATCH, -EIO,
+	"STATUS_IO_REPARSE_TAG_MISMATCH"},
+	{STATUS_IO_REPARSE_DATA_INVALID, -EIO,
+	"STATUS_IO_REPARSE_DATA_INVALID"},
+	{STATUS_IO_REPARSE_TAG_NOT_HANDLED, -EIO,
+	"STATUS_IO_REPARSE_TAG_NOT_HANDLED"},
+	{STATUS_REPARSE_POINT_NOT_RESOLVED, -EIO,
+	"STATUS_REPARSE_POINT_NOT_RESOLVED"},
+	{STATUS_DIRECTORY_IS_A_REPARSE_POINT, -EIO,
+	"STATUS_DIRECTORY_IS_A_REPARSE_POINT"},
+	{STATUS_RANGE_LIST_CONFLICT, -EIO, "STATUS_RANGE_LIST_CONFLICT"},
+	{STATUS_SOURCE_ELEMENT_EMPTY, -EIO, "STATUS_SOURCE_ELEMENT_EMPTY"},
+	{STATUS_DESTINATION_ELEMENT_FULL, -EIO,
+	"STATUS_DESTINATION_ELEMENT_FULL"},
+	{STATUS_ILLEGAL_ELEMENT_ADDRESS, -EIO,
+	"STATUS_ILLEGAL_ELEMENT_ADDRESS"},
+	{STATUS_MAGAZINE_NOT_PRESENT, -EIO, "STATUS_MAGAZINE_NOT_PRESENT"},
+	{STATUS_REINITIALIZATION_NEEDED, -EIO,
+	"STATUS_REINITIALIZATION_NEEDED"},
+	{STATUS_ENCRYPTION_FAILED, -EIO, "STATUS_ENCRYPTION_FAILED"},
+	{STATUS_DECRYPTION_FAILED, -EIO, "STATUS_DECRYPTION_FAILED"},
+	{STATUS_RANGE_NOT_FOUND, -EIO, "STATUS_RANGE_NOT_FOUND"},
+	{STATUS_NO_RECOVERY_POLICY, -EIO, "STATUS_NO_RECOVERY_POLICY"},
+	{STATUS_NO_EFS, -EIO, "STATUS_NO_EFS"},
+	{STATUS_WRONG_EFS, -EIO, "STATUS_WRONG_EFS"},
+	{STATUS_NO_USER_KEYS, -EIO, "STATUS_NO_USER_KEYS"},
+	{STATUS_FILE_NOT_ENCRYPTED, -EIO, "STATUS_FILE_NOT_ENCRYPTED"},
+	{STATUS_NOT_EXPORT_FORMAT, -EIO, "STATUS_NOT_EXPORT_FORMAT"},
+	{STATUS_FILE_ENCRYPTED, -EIO, "STATUS_FILE_ENCRYPTED"},
+	{STATUS_WMI_GUID_NOT_FOUND, -EIO, "STATUS_WMI_GUID_NOT_FOUND"},
+	{STATUS_WMI_INSTANCE_NOT_FOUND, -EIO, "STATUS_WMI_INSTANCE_NOT_FOUND"},
+	{STATUS_WMI_ITEMID_NOT_FOUND, -EIO, "STATUS_WMI_ITEMID_NOT_FOUND"},
+	{STATUS_WMI_TRY_AGAIN, -EIO, "STATUS_WMI_TRY_AGAIN"},
+	{STATUS_SHARED_POLICY, -EIO, "STATUS_SHARED_POLICY"},
+	{STATUS_POLICY_OBJECT_NOT_FOUND, -EIO,
+	"STATUS_POLICY_OBJECT_NOT_FOUND"},
+	{STATUS_POLICY_ONLY_IN_DS, -EIO, "STATUS_POLICY_ONLY_IN_DS"},
+	{STATUS_VOLUME_NOT_UPGRADED, -EIO, "STATUS_VOLUME_NOT_UPGRADED"},
+	{STATUS_REMOTE_STORAGE_NOT_ACTIVE, -EIO,
+	"STATUS_REMOTE_STORAGE_NOT_ACTIVE"},
+	{STATUS_REMOTE_STORAGE_MEDIA_ERROR, -EIO,
+	"STATUS_REMOTE_STORAGE_MEDIA_ERROR"},
+	{STATUS_NO_TRACKING_SERVICE, -EIO, "STATUS_NO_TRACKING_SERVICE"},
+	{STATUS_SERVER_SID_MISMATCH, -EIO, "STATUS_SERVER_SID_MISMATCH"},
+	{STATUS_DS_NO_ATTRIBUTE_OR_VALUE, -EIO,
+	"STATUS_DS_NO_ATTRIBUTE_OR_VALUE"},
+	{STATUS_DS_INVALID_ATTRIBUTE_SYNTAX, -EIO,
+	"STATUS_DS_INVALID_ATTRIBUTE_SYNTAX"},
+	{STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED, -EIO,
+	"STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED"},
+	{STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS, -EIO,
+	"STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS"},
+	{STATUS_DS_BUSY, -EBUSY, "STATUS_DS_BUSY"},
+	{STATUS_DS_UNAVAILABLE, -EIO, "STATUS_DS_UNAVAILABLE"},
+	{STATUS_DS_NO_RIDS_ALLOCATED, -EIO, "STATUS_DS_NO_RIDS_ALLOCATED"},
+	{STATUS_DS_NO_MORE_RIDS, -EIO, "STATUS_DS_NO_MORE_RIDS"},
+	{STATUS_DS_INCORRECT_ROLE_OWNER, -EIO,
+	"STATUS_DS_INCORRECT_ROLE_OWNER"},
+	{STATUS_DS_RIDMGR_INIT_ERROR, -EIO, "STATUS_DS_RIDMGR_INIT_ERROR"},
+	{STATUS_DS_OBJ_CLASS_VIOLATION, -EIO, "STATUS_DS_OBJ_CLASS_VIOLATION"},
+	{STATUS_DS_CANT_ON_NON_LEAF, -EIO, "STATUS_DS_CANT_ON_NON_LEAF"},
+	{STATUS_DS_CANT_ON_RDN, -EIO, "STATUS_DS_CANT_ON_RDN"},
+	{STATUS_DS_CANT_MOD_OBJ_CLASS, -EIO, "STATUS_DS_CANT_MOD_OBJ_CLASS"},
+	{STATUS_DS_CROSS_DOM_MOVE_FAILED, -EIO,
+	"STATUS_DS_CROSS_DOM_MOVE_FAILED"},
+	{STATUS_DS_GC_NOT_AVAILABLE, -EIO, "STATUS_DS_GC_NOT_AVAILABLE"},
+	{STATUS_DIRECTORY_SERVICE_REQUIRED, -EIO,
+	"STATUS_DIRECTORY_SERVICE_REQUIRED"},
+	{STATUS_REPARSE_ATTRIBUTE_CONFLICT, -EIO,
+	"STATUS_REPARSE_ATTRIBUTE_CONFLICT"},
+	{STATUS_CANT_ENABLE_DENY_ONLY, -EIO, "STATUS_CANT_ENABLE_DENY_ONLY"},
+	{STATUS_FLOAT_MULTIPLE_FAULTS, -EIO, "STATUS_FLOAT_MULTIPLE_FAULTS"},
+	{STATUS_FLOAT_MULTIPLE_TRAPS, -EIO, "STATUS_FLOAT_MULTIPLE_TRAPS"},
+	{STATUS_DEVICE_REMOVED, -EIO, "STATUS_DEVICE_REMOVED"},
+	{STATUS_JOURNAL_DELETE_IN_PROGRESS, -EIO,
+	"STATUS_JOURNAL_DELETE_IN_PROGRESS"},
+	{STATUS_JOURNAL_NOT_ACTIVE, -EIO, "STATUS_JOURNAL_NOT_ACTIVE"},
+	{STATUS_NOINTERFACE, -EIO, "STATUS_NOINTERFACE"},
+	{STATUS_DS_ADMIN_LIMIT_EXCEEDED, -EIO,
+	"STATUS_DS_ADMIN_LIMIT_EXCEEDED"},
+	{STATUS_DRIVER_FAILED_SLEEP, -EIO, "STATUS_DRIVER_FAILED_SLEEP"},
+	{STATUS_MUTUAL_AUTHENTICATION_FAILED, -EIO,
+	"STATUS_MUTUAL_AUTHENTICATION_FAILED"},
+	{STATUS_CORRUPT_SYSTEM_FILE, -EIO, "STATUS_CORRUPT_SYSTEM_FILE"},
+	{STATUS_DATATYPE_MISALIGNMENT_ERROR, -EIO,
+	"STATUS_DATATYPE_MISALIGNMENT_ERROR"},
+	{STATUS_WMI_READ_ONLY, -EROFS, "STATUS_WMI_READ_ONLY"},
+	{STATUS_WMI_SET_FAILURE, -EIO, "STATUS_WMI_SET_FAILURE"},
+	{STATUS_COMMITMENT_MINIMUM, -EIO, "STATUS_COMMITMENT_MINIMUM"},
+	{STATUS_REG_NAT_CONSUMPTION, -EIO, "STATUS_REG_NAT_CONSUMPTION"},
+	{STATUS_TRANSPORT_FULL, -EIO, "STATUS_TRANSPORT_FULL"},
+	{STATUS_DS_SAM_INIT_FAILURE, -EIO, "STATUS_DS_SAM_INIT_FAILURE"},
+	{STATUS_ONLY_IF_CONNECTED, -EIO, "STATUS_ONLY_IF_CONNECTED"},
+	{STATUS_DS_SENSITIVE_GROUP_VIOLATION, -EIO,
+	"STATUS_DS_SENSITIVE_GROUP_VIOLATION"},
+	{STATUS_PNP_RESTART_ENUMERATION, -EIO,
+	"STATUS_PNP_RESTART_ENUMERATION"},
+	{STATUS_JOURNAL_ENTRY_DELETED, -EIO, "STATUS_JOURNAL_ENTRY_DELETED"},
+	{STATUS_DS_CANT_MOD_PRIMARYGROUPID, -EIO,
+	"STATUS_DS_CANT_MOD_PRIMARYGROUPID"},
+	{STATUS_SYSTEM_IMAGE_BAD_SIGNATURE, -EIO,
+	"STATUS_SYSTEM_IMAGE_BAD_SIGNATURE"},
+	{STATUS_PNP_REBOOT_REQUIRED, -EIO, "STATUS_PNP_REBOOT_REQUIRED"},
+	{STATUS_POWER_STATE_INVALID, -EIO, "STATUS_POWER_STATE_INVALID"},
+	{STATUS_DS_INVALID_GROUP_TYPE, -EIO, "STATUS_DS_INVALID_GROUP_TYPE"},
+	{STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN, -EIO,
+	"STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN"},
+	{STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN, -EIO,
+	"STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN"},
+	{STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER, -EIO,
+	"STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER"},
+	{STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER, -EIO,
+	"STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER"},
+	{STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER, -EIO,
+	"STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER"},
+	{STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER, -EIO,
+	"STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER"},
+	{STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER, -EIO,
+	"STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER"},
+	{STATUS_DS_HAVE_PRIMARY_MEMBERS, -EIO,
+	"STATUS_DS_HAVE_PRIMARY_MEMBERS"},
+	{STATUS_WMI_NOT_SUPPORTED, -EOPNOTSUPP, "STATUS_WMI_NOT_SUPPORTED"},
+	{STATUS_INSUFFICIENT_POWER, -EIO, "STATUS_INSUFFICIENT_POWER"},
+	{STATUS_SAM_NEED_BOOTKEY_PASSWORD, -EIO,
+	"STATUS_SAM_NEED_BOOTKEY_PASSWORD"},
+	{STATUS_SAM_NEED_BOOTKEY_FLOPPY, -EIO,
+	"STATUS_SAM_NEED_BOOTKEY_FLOPPY"},
+	{STATUS_DS_CANT_START, -EIO, "STATUS_DS_CANT_START"},
+	{STATUS_DS_INIT_FAILURE, -EIO, "STATUS_DS_INIT_FAILURE"},
+	{STATUS_SAM_INIT_FAILURE, -EIO, "STATUS_SAM_INIT_FAILURE"},
+	{STATUS_DS_GC_REQUIRED, -EIO, "STATUS_DS_GC_REQUIRED"},
+	{STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY, -EIO,
+	"STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY"},
+	{STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS, -EIO,
+	"STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS"},
+	{STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED, -EDQUOT,
+	"STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED"},
+	{STATUS_MULTIPLE_FAULT_VIOLATION, -EIO,
+	"STATUS_MULTIPLE_FAULT_VIOLATION"},
+	{STATUS_CURRENT_DOMAIN_NOT_ALLOWED, -EIO,
+	"STATUS_CURRENT_DOMAIN_NOT_ALLOWED"},
+	{STATUS_CANNOT_MAKE, -EIO, "STATUS_CANNOT_MAKE"},
+	{STATUS_SYSTEM_SHUTDOWN, -EIO, "STATUS_SYSTEM_SHUTDOWN"},
+	{STATUS_DS_INIT_FAILURE_CONSOLE, -EIO,
+	"STATUS_DS_INIT_FAILURE_CONSOLE"},
+	{STATUS_DS_SAM_INIT_FAILURE_CONSOLE, -EIO,
+	"STATUS_DS_SAM_INIT_FAILURE_CONSOLE"},
+	{STATUS_UNFINISHED_CONTEXT_DELETED, -EIO,
+	"STATUS_UNFINISHED_CONTEXT_DELETED"},
+	{STATUS_NO_TGT_REPLY, -EIO, "STATUS_NO_TGT_REPLY"},
+	{STATUS_OBJECTID_NOT_FOUND, -EIO, "STATUS_OBJECTID_NOT_FOUND"},
+	{STATUS_NO_IP_ADDRESSES, -EIO, "STATUS_NO_IP_ADDRESSES"},
+	{STATUS_WRONG_CREDENTIAL_HANDLE, -EIO,
+	"STATUS_WRONG_CREDENTIAL_HANDLE"},
+	{STATUS_CRYPTO_SYSTEM_INVALID, -EIO, "STATUS_CRYPTO_SYSTEM_INVALID"},
+	{STATUS_MAX_REFERRALS_EXCEEDED, -EIO, "STATUS_MAX_REFERRALS_EXCEEDED"},
+	{STATUS_MUST_BE_KDC, -EIO, "STATUS_MUST_BE_KDC"},
+	{STATUS_STRONG_CRYPTO_NOT_SUPPORTED, -EIO,
+	"STATUS_STRONG_CRYPTO_NOT_SUPPORTED"},
+	{STATUS_TOO_MANY_PRINCIPALS, -EIO, "STATUS_TOO_MANY_PRINCIPALS"},
+	{STATUS_NO_PA_DATA, -EIO, "STATUS_NO_PA_DATA"},
+	{STATUS_PKINIT_NAME_MISMATCH, -EIO, "STATUS_PKINIT_NAME_MISMATCH"},
+	{STATUS_SMARTCARD_LOGON_REQUIRED, -EIO,
+	"STATUS_SMARTCARD_LOGON_REQUIRED"},
+	{STATUS_KDC_INVALID_REQUEST, -EIO, "STATUS_KDC_INVALID_REQUEST"},
+	{STATUS_KDC_UNABLE_TO_REFER, -EIO, "STATUS_KDC_UNABLE_TO_REFER"},
+	{STATUS_KDC_UNKNOWN_ETYPE, -EIO, "STATUS_KDC_UNKNOWN_ETYPE"},
+	{STATUS_SHUTDOWN_IN_PROGRESS, -EIO, "STATUS_SHUTDOWN_IN_PROGRESS"},
+	{STATUS_SERVER_SHUTDOWN_IN_PROGRESS, -EIO,
+	"STATUS_SERVER_SHUTDOWN_IN_PROGRESS"},
+	{STATUS_NOT_SUPPORTED_ON_SBS, -EOPNOTSUPP,
+	"STATUS_NOT_SUPPORTED_ON_SBS"},
+	{STATUS_WMI_GUID_DISCONNECTED, -EIO, "STATUS_WMI_GUID_DISCONNECTED"},
+	{STATUS_WMI_ALREADY_DISABLED, -EIO, "STATUS_WMI_ALREADY_DISABLED"},
+	{STATUS_WMI_ALREADY_ENABLED, -EIO, "STATUS_WMI_ALREADY_ENABLED"},
+	{STATUS_MFT_TOO_FRAGMENTED, -EIO, "STATUS_MFT_TOO_FRAGMENTED"},
+	{STATUS_COPY_PROTECTION_FAILURE, -EIO,
+	"STATUS_COPY_PROTECTION_FAILURE"},
+	{STATUS_CSS_AUTHENTICATION_FAILURE, -EIO,
+	"STATUS_CSS_AUTHENTICATION_FAILURE"},
+	{STATUS_CSS_KEY_NOT_PRESENT, -EIO, "STATUS_CSS_KEY_NOT_PRESENT"},
+	{STATUS_CSS_KEY_NOT_ESTABLISHED, -EIO,
+	"STATUS_CSS_KEY_NOT_ESTABLISHED"},
+	{STATUS_CSS_SCRAMBLED_SECTOR, -EIO, "STATUS_CSS_SCRAMBLED_SECTOR"},
+	{STATUS_CSS_REGION_MISMATCH, -EIO, "STATUS_CSS_REGION_MISMATCH"},
+	{STATUS_CSS_RESETS_EXHAUSTED, -EIO, "STATUS_CSS_RESETS_EXHAUSTED"},
+	{STATUS_PKINIT_FAILURE, -EIO, "STATUS_PKINIT_FAILURE"},
+	{STATUS_SMARTCARD_SUBSYSTEM_FAILURE, -EIO,
+	"STATUS_SMARTCARD_SUBSYSTEM_FAILURE"},
+	{STATUS_NO_KERB_KEY, -EIO, "STATUS_NO_KERB_KEY"},
+	{STATUS_HOST_DOWN, -EIO, "STATUS_HOST_DOWN"},
+	{STATUS_UNSUPPORTED_PREAUTH, -EIO, "STATUS_UNSUPPORTED_PREAUTH"},
+	{STATUS_EFS_ALG_BLOB_TOO_BIG, -EIO, "STATUS_EFS_ALG_BLOB_TOO_BIG"},
+	{STATUS_PORT_NOT_SET, -EIO, "STATUS_PORT_NOT_SET"},
+	{STATUS_DEBUGGER_INACTIVE, -EIO, "STATUS_DEBUGGER_INACTIVE"},
+	{STATUS_DS_VERSION_CHECK_FAILURE, -EIO,
+	"STATUS_DS_VERSION_CHECK_FAILURE"},
+	{STATUS_AUDITING_DISABLED, -EIO, "STATUS_AUDITING_DISABLED"},
+	{STATUS_PRENT4_MACHINE_ACCOUNT, -EIO, "STATUS_PRENT4_MACHINE_ACCOUNT"},
+	{STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER, -EIO,
+	"STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER"},
+	{STATUS_INVALID_IMAGE_WIN_32, -EIO, "STATUS_INVALID_IMAGE_WIN_32"},
+	{STATUS_INVALID_IMAGE_WIN_64, -EIO, "STATUS_INVALID_IMAGE_WIN_64"},
+	{STATUS_BAD_BINDINGS, -EIO, "STATUS_BAD_BINDINGS"},
+	{STATUS_NETWORK_SESSION_EXPIRED, -EIO,
+	"STATUS_NETWORK_SESSION_EXPIRED"},
+	{STATUS_APPHELP_BLOCK, -EIO, "STATUS_APPHELP_BLOCK"},
+	{STATUS_ALL_SIDS_FILTERED, -EIO, "STATUS_ALL_SIDS_FILTERED"},
+	{STATUS_NOT_SAFE_MODE_DRIVER, -EIO, "STATUS_NOT_SAFE_MODE_DRIVER"},
+	{STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT, -EACCES,
+	"STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT"},
+	{STATUS_ACCESS_DISABLED_BY_POLICY_PATH, -EACCES,
+	"STATUS_ACCESS_DISABLED_BY_POLICY_PATH"},
+	{STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER, -EACCES,
+	"STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER"},
+	{STATUS_ACCESS_DISABLED_BY_POLICY_OTHER, -EACCES,
+	"STATUS_ACCESS_DISABLED_BY_POLICY_OTHER"},
+	{STATUS_FAILED_DRIVER_ENTRY, -EIO, "STATUS_FAILED_DRIVER_ENTRY"},
+	{STATUS_DEVICE_ENUMERATION_ERROR, -EIO,
+	"STATUS_DEVICE_ENUMERATION_ERROR"},
+	{STATUS_MOUNT_POINT_NOT_RESOLVED, -EIO,
+	"STATUS_MOUNT_POINT_NOT_RESOLVED"},
+	{STATUS_INVALID_DEVICE_OBJECT_PARAMETER, -EIO,
+	"STATUS_INVALID_DEVICE_OBJECT_PARAMETER"},
+	{STATUS_MCA_OCCURED, -EIO, "STATUS_MCA_OCCURED"},
+	{STATUS_DRIVER_BLOCKED_CRITICAL, -EIO,
+	"STATUS_DRIVER_BLOCKED_CRITICAL"},
+	{STATUS_DRIVER_BLOCKED, -EIO, "STATUS_DRIVER_BLOCKED"},
+	{STATUS_DRIVER_DATABASE_ERROR, -EIO, "STATUS_DRIVER_DATABASE_ERROR"},
+	{STATUS_SYSTEM_HIVE_TOO_LARGE, -EIO, "STATUS_SYSTEM_HIVE_TOO_LARGE"},
+	{STATUS_INVALID_IMPORT_OF_NON_DLL, -EIO,
+	"STATUS_INVALID_IMPORT_OF_NON_DLL"},
+	{STATUS_NO_SECRETS, -EIO, "STATUS_NO_SECRETS"},
+	{STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY, -EACCES,
+	"STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY"},
+	{STATUS_FAILED_STACK_SWITCH, -EIO, "STATUS_FAILED_STACK_SWITCH"},
+	{STATUS_HEAP_CORRUPTION, -EIO, "STATUS_HEAP_CORRUPTION"},
+	{STATUS_SMARTCARD_WRONG_PIN, -EIO, "STATUS_SMARTCARD_WRONG_PIN"},
+	{STATUS_SMARTCARD_CARD_BLOCKED, -EIO, "STATUS_SMARTCARD_CARD_BLOCKED"},
+	{STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED, -EIO,
+	"STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED"},
+	{STATUS_SMARTCARD_NO_CARD, -EIO, "STATUS_SMARTCARD_NO_CARD"},
+	{STATUS_SMARTCARD_NO_KEY_CONTAINER, -EIO,
+	"STATUS_SMARTCARD_NO_KEY_CONTAINER"},
+	{STATUS_SMARTCARD_NO_CERTIFICATE, -EIO,
+	"STATUS_SMARTCARD_NO_CERTIFICATE"},
+	{STATUS_SMARTCARD_NO_KEYSET, -EIO, "STATUS_SMARTCARD_NO_KEYSET"},
+	{STATUS_SMARTCARD_IO_ERROR, -EIO, "STATUS_SMARTCARD_IO_ERROR"},
+	{STATUS_DOWNGRADE_DETECTED, -EIO, "STATUS_DOWNGRADE_DETECTED"},
+	{STATUS_SMARTCARD_CERT_REVOKED, -EIO, "STATUS_SMARTCARD_CERT_REVOKED"},
+	{STATUS_ISSUING_CA_UNTRUSTED, -EIO, "STATUS_ISSUING_CA_UNTRUSTED"},
+	{STATUS_REVOCATION_OFFLINE_C, -EIO, "STATUS_REVOCATION_OFFLINE_C"},
+	{STATUS_PKINIT_CLIENT_FAILURE, -EIO, "STATUS_PKINIT_CLIENT_FAILURE"},
+	{STATUS_SMARTCARD_CERT_EXPIRED, -EIO, "STATUS_SMARTCARD_CERT_EXPIRED"},
+	{STATUS_DRIVER_FAILED_PRIOR_UNLOAD, -EIO,
+	"STATUS_DRIVER_FAILED_PRIOR_UNLOAD"},
+	{STATUS_SMARTCARD_SILENT_CONTEXT, -EIO,
+	"STATUS_SMARTCARD_SILENT_CONTEXT"},
+	{STATUS_PER_USER_TRUST_QUOTA_EXCEEDED, -EDQUOT,
+	"STATUS_PER_USER_TRUST_QUOTA_EXCEEDED"},
+	{STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED, -EDQUOT,
+	"STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED"},
+	{STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED, -EDQUOT,
+	"STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED"},
+	{STATUS_DS_NAME_NOT_UNIQUE, -EIO, "STATUS_DS_NAME_NOT_UNIQUE"},
+	{STATUS_DS_DUPLICATE_ID_FOUND, -EIO, "STATUS_DS_DUPLICATE_ID_FOUND"},
+	{STATUS_DS_GROUP_CONVERSION_ERROR, -EIO,
+	"STATUS_DS_GROUP_CONVERSION_ERROR"},
+	{STATUS_VOLSNAP_PREPARE_HIBERNATE, -EIO,
+	"STATUS_VOLSNAP_PREPARE_HIBERNATE"},
+	{STATUS_USER2USER_REQUIRED, -EIO, "STATUS_USER2USER_REQUIRED"},
+	{STATUS_STACK_BUFFER_OVERRUN, -EIO, "STATUS_STACK_BUFFER_OVERRUN"},
+	{STATUS_NO_S4U_PROT_SUPPORT, -EIO, "STATUS_NO_S4U_PROT_SUPPORT"},
+	{STATUS_CROSSREALM_DELEGATION_FAILURE, -EIO,
+	"STATUS_CROSSREALM_DELEGATION_FAILURE"},
+	{STATUS_REVOCATION_OFFLINE_KDC, -EIO, "STATUS_REVOCATION_OFFLINE_KDC"},
+	{STATUS_ISSUING_CA_UNTRUSTED_KDC, -EIO,
+	"STATUS_ISSUING_CA_UNTRUSTED_KDC"},
+	{STATUS_KDC_CERT_EXPIRED, -EIO, "STATUS_KDC_CERT_EXPIRED"},
+	{STATUS_KDC_CERT_REVOKED, -EIO, "STATUS_KDC_CERT_REVOKED"},
+	{STATUS_PARAMETER_QUOTA_EXCEEDED, -EDQUOT,
+	"STATUS_PARAMETER_QUOTA_EXCEEDED"},
+	{STATUS_HIBERNATION_FAILURE, -EIO, "STATUS_HIBERNATION_FAILURE"},
+	{STATUS_DELAY_LOAD_FAILED, -EIO, "STATUS_DELAY_LOAD_FAILED"},
+	{STATUS_AUTHENTICATION_FIREWALL_FAILED, -EIO,
+	"STATUS_AUTHENTICATION_FIREWALL_FAILED"},
+	{STATUS_VDM_DISALLOWED, -EIO, "STATUS_VDM_DISALLOWED"},
+	{STATUS_HUNG_DISPLAY_DRIVER_THREAD, -EIO,
+	"STATUS_HUNG_DISPLAY_DRIVER_THREAD"},
+	{STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE, -EIO,
+	"STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE"},
+	{STATUS_INVALID_CRUNTIME_PARAMETER, -EIO,
+	"STATUS_INVALID_CRUNTIME_PARAMETER"},
+	{STATUS_NTLM_BLOCKED, -EIO, "STATUS_NTLM_BLOCKED"},
+	{STATUS_ASSERTION_FAILURE, -EIO, "STATUS_ASSERTION_FAILURE"},
+	{STATUS_VERIFIER_STOP, -EIO, "STATUS_VERIFIER_STOP"},
+	{STATUS_CALLBACK_POP_STACK, -EIO, "STATUS_CALLBACK_POP_STACK"},
+	{STATUS_INCOMPATIBLE_DRIVER_BLOCKED, -EIO,
+	"STATUS_INCOMPATIBLE_DRIVER_BLOCKED"},
+	{STATUS_HIVE_UNLOADED, -EIO, "STATUS_HIVE_UNLOADED"},
+	{STATUS_COMPRESSION_DISABLED, -EIO, "STATUS_COMPRESSION_DISABLED"},
+	{STATUS_FILE_SYSTEM_LIMITATION, -EIO, "STATUS_FILE_SYSTEM_LIMITATION"},
+	{STATUS_INVALID_IMAGE_HASH, -EIO, "STATUS_INVALID_IMAGE_HASH"},
+	{STATUS_NOT_CAPABLE, -EIO, "STATUS_NOT_CAPABLE"},
+	{STATUS_REQUEST_OUT_OF_SEQUENCE, -EIO,
+	"STATUS_REQUEST_OUT_OF_SEQUENCE"},
+	{STATUS_IMPLEMENTATION_LIMIT, -EIO, "STATUS_IMPLEMENTATION_LIMIT"},
+	{STATUS_ELEVATION_REQUIRED, -EIO, "STATUS_ELEVATION_REQUIRED"},
+	{STATUS_BEYOND_VDL, -EIO, "STATUS_BEYOND_VDL"},
+	{STATUS_ENCOUNTERED_WRITE_IN_PROGRESS, -EIO,
+	"STATUS_ENCOUNTERED_WRITE_IN_PROGRESS"},
+	{STATUS_PTE_CHANGED, -EIO, "STATUS_PTE_CHANGED"},
+	{STATUS_PURGE_FAILED, -EIO, "STATUS_PURGE_FAILED"},
+	{STATUS_CRED_REQUIRES_CONFIRMATION, -EIO,
+	"STATUS_CRED_REQUIRES_CONFIRMATION"},
+	{STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE, -EIO,
+	"STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE"},
+	{STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER, -EIO,
+	"STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER"},
+	{STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE, -EIO,
+	"STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE"},
+	{STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE, -EIO,
+	"STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE"},
+	{STATUS_CS_ENCRYPTION_FILE_NOT_CSE, -EIO,
+	"STATUS_CS_ENCRYPTION_FILE_NOT_CSE"},
+	{STATUS_INVALID_LABEL, -EIO, "STATUS_INVALID_LABEL"},
+	{STATUS_DRIVER_PROCESS_TERMINATED, -EIO,
+	"STATUS_DRIVER_PROCESS_TERMINATED"},
+	{STATUS_AMBIGUOUS_SYSTEM_DEVICE, -EIO,
+	"STATUS_AMBIGUOUS_SYSTEM_DEVICE"},
+	{STATUS_SYSTEM_DEVICE_NOT_FOUND, -EIO,
+	"STATUS_SYSTEM_DEVICE_NOT_FOUND"},
+	{STATUS_RESTART_BOOT_APPLICATION, -EIO,
+	"STATUS_RESTART_BOOT_APPLICATION"},
+	{STATUS_INVALID_TASK_NAME, -EIO, "STATUS_INVALID_TASK_NAME"},
+	{STATUS_INVALID_TASK_INDEX, -EIO, "STATUS_INVALID_TASK_INDEX"},
+	{STATUS_THREAD_ALREADY_IN_TASK, -EIO, "STATUS_THREAD_ALREADY_IN_TASK"},
+	{STATUS_CALLBACK_BYPASS, -EIO, "STATUS_CALLBACK_BYPASS"},
+	{STATUS_PORT_CLOSED, -EIO, "STATUS_PORT_CLOSED"},
+	{STATUS_MESSAGE_LOST, -EIO, "STATUS_MESSAGE_LOST"},
+	{STATUS_INVALID_MESSAGE, -EIO, "STATUS_INVALID_MESSAGE"},
+	{STATUS_REQUEST_CANCELED, -EIO, "STATUS_REQUEST_CANCELED"},
+	{STATUS_RECURSIVE_DISPATCH, -EIO, "STATUS_RECURSIVE_DISPATCH"},
+	{STATUS_LPC_RECEIVE_BUFFER_EXPECTED, -EIO,
+	"STATUS_LPC_RECEIVE_BUFFER_EXPECTED"},
+	{STATUS_LPC_INVALID_CONNECTION_USAGE, -EIO,
+	"STATUS_LPC_INVALID_CONNECTION_USAGE"},
+	{STATUS_LPC_REQUESTS_NOT_ALLOWED, -EIO,
+	"STATUS_LPC_REQUESTS_NOT_ALLOWED"},
+	{STATUS_RESOURCE_IN_USE, -EIO, "STATUS_RESOURCE_IN_USE"},
+	{STATUS_HARDWARE_MEMORY_ERROR, -EIO, "STATUS_HARDWARE_MEMORY_ERROR"},
+	{STATUS_THREADPOOL_HANDLE_EXCEPTION, -EIO,
+	"STATUS_THREADPOOL_HANDLE_EXCEPTION"},
+	{STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED, -EIO,
+	"STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED"},
+	{STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED, -EIO,
+	"STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED"},
+	{STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED, -EIO,
+	"STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED"},
+	{STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED, -EIO,
+	"STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED"},
+	{STATUS_THREADPOOL_RELEASED_DURING_OPERATION, -EIO,
+	"STATUS_THREADPOOL_RELEASED_DURING_OPERATION"},
+	{STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING, -EIO,
+	"STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING"},
+	{STATUS_APC_RETURNED_WHILE_IMPERSONATING, -EIO,
+	"STATUS_APC_RETURNED_WHILE_IMPERSONATING"},
+	{STATUS_PROCESS_IS_PROTECTED, -EIO, "STATUS_PROCESS_IS_PROTECTED"},
+	{STATUS_MCA_EXCEPTION, -EIO, "STATUS_MCA_EXCEPTION"},
+	{STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE, -EIO,
+	"STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE"},
+	{STATUS_SYMLINK_CLASS_DISABLED, -EIO, "STATUS_SYMLINK_CLASS_DISABLED"},
+	{STATUS_INVALID_IDN_NORMALIZATION, -EIO,
+	"STATUS_INVALID_IDN_NORMALIZATION"},
+	{STATUS_NO_UNICODE_TRANSLATION, -EIO, "STATUS_NO_UNICODE_TRANSLATION"},
+	{STATUS_ALREADY_REGISTERED, -EIO, "STATUS_ALREADY_REGISTERED"},
+	{STATUS_CONTEXT_MISMATCH, -EIO, "STATUS_CONTEXT_MISMATCH"},
+	{STATUS_PORT_ALREADY_HAS_COMPLETION_LIST, -EIO,
+	"STATUS_PORT_ALREADY_HAS_COMPLETION_LIST"},
+	{STATUS_CALLBACK_RETURNED_THREAD_PRIORITY, -EIO,
+	"STATUS_CALLBACK_RETURNED_THREAD_PRIORITY"},
+	{STATUS_INVALID_THREAD, -EIO, "STATUS_INVALID_THREAD"},
+	{STATUS_CALLBACK_RETURNED_TRANSACTION, -EIO,
+	"STATUS_CALLBACK_RETURNED_TRANSACTION"},
+	{STATUS_CALLBACK_RETURNED_LDR_LOCK, -EIO,
+	"STATUS_CALLBACK_RETURNED_LDR_LOCK"},
+	{STATUS_CALLBACK_RETURNED_LANG, -EIO, "STATUS_CALLBACK_RETURNED_LANG"},
+	{STATUS_CALLBACK_RETURNED_PRI_BACK, -EIO,
+	"STATUS_CALLBACK_RETURNED_PRI_BACK"},
+	{STATUS_CALLBACK_RETURNED_THREAD_AFFINITY, -EIO,
+	"STATUS_CALLBACK_RETURNED_THREAD_AFFINITY"},
+	{STATUS_DISK_REPAIR_DISABLED, -EIO, "STATUS_DISK_REPAIR_DISABLED"},
+	{STATUS_DS_DOMAIN_RENAME_IN_PROGRESS, -EIO,
+	"STATUS_DS_DOMAIN_RENAME_IN_PROGRESS"},
+	{STATUS_DISK_QUOTA_EXCEEDED, -EDQUOT, "STATUS_DISK_QUOTA_EXCEEDED"},
+	{STATUS_CONTENT_BLOCKED, -EIO, "STATUS_CONTENT_BLOCKED"},
+	{STATUS_BAD_CLUSTERS, -EIO, "STATUS_BAD_CLUSTERS"},
+	{STATUS_VOLUME_DIRTY, -EIO, "STATUS_VOLUME_DIRTY"},
+	{STATUS_FILE_CHECKED_OUT, -EIO, "STATUS_FILE_CHECKED_OUT"},
+	{STATUS_CHECKOUT_REQUIRED, -EIO, "STATUS_CHECKOUT_REQUIRED"},
+	{STATUS_BAD_FILE_TYPE, -EIO, "STATUS_BAD_FILE_TYPE"},
+	{STATUS_FILE_TOO_LARGE, -EIO, "STATUS_FILE_TOO_LARGE"},
+	{STATUS_FORMS_AUTH_REQUIRED, -EIO, "STATUS_FORMS_AUTH_REQUIRED"},
+	{STATUS_VIRUS_INFECTED, -EIO, "STATUS_VIRUS_INFECTED"},
+	{STATUS_VIRUS_DELETED, -EIO, "STATUS_VIRUS_DELETED"},
+	{STATUS_BAD_MCFG_TABLE, -EIO, "STATUS_BAD_MCFG_TABLE"},
+	{STATUS_WOW_ASSERTION, -EIO, "STATUS_WOW_ASSERTION"},
+	{STATUS_INVALID_SIGNATURE, -EIO, "STATUS_INVALID_SIGNATURE"},
+	{STATUS_HMAC_NOT_SUPPORTED, -EIO, "STATUS_HMAC_NOT_SUPPORTED"},
+	{STATUS_IPSEC_QUEUE_OVERFLOW, -EIO, "STATUS_IPSEC_QUEUE_OVERFLOW"},
+	{STATUS_ND_QUEUE_OVERFLOW, -EIO, "STATUS_ND_QUEUE_OVERFLOW"},
+	{STATUS_HOPLIMIT_EXCEEDED, -EIO, "STATUS_HOPLIMIT_EXCEEDED"},
+	{STATUS_PROTOCOL_NOT_SUPPORTED, -EOPNOTSUPP,
+	"STATUS_PROTOCOL_NOT_SUPPORTED"},
+	{STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED, -EIO,
+	"STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED"},
+	{STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR, -EIO,
+	"STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR"},
+	{STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR, -EIO,
+	"STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR"},
+	{STATUS_XML_PARSE_ERROR, -EIO, "STATUS_XML_PARSE_ERROR"},
+	{STATUS_XMLDSIG_ERROR, -EIO, "STATUS_XMLDSIG_ERROR"},
+	{STATUS_WRONG_COMPARTMENT, -EIO, "STATUS_WRONG_COMPARTMENT"},
+	{STATUS_AUTHIP_FAILURE, -EIO, "STATUS_AUTHIP_FAILURE"},
+	{DBG_NO_STATE_CHANGE, -EIO, "DBG_NO_STATE_CHANGE"},
+	{DBG_APP_NOT_IDLE, -EIO, "DBG_APP_NOT_IDLE"},
+	{RPC_NT_INVALID_STRING_BINDING, -EIO, "RPC_NT_INVALID_STRING_BINDING"},
+	{RPC_NT_WRONG_KIND_OF_BINDING, -EIO, "RPC_NT_WRONG_KIND_OF_BINDING"},
+	{RPC_NT_INVALID_BINDING, -EIO, "RPC_NT_INVALID_BINDING"},
+	{RPC_NT_PROTSEQ_NOT_SUPPORTED, -EOPNOTSUPP,
+	"RPC_NT_PROTSEQ_NOT_SUPPORTED"},
+	{RPC_NT_INVALID_RPC_PROTSEQ, -EIO, "RPC_NT_INVALID_RPC_PROTSEQ"},
+	{RPC_NT_INVALID_STRING_UUID, -EIO, "RPC_NT_INVALID_STRING_UUID"},
+	{RPC_NT_INVALID_ENDPOINT_FORMAT, -EIO,
+	"RPC_NT_INVALID_ENDPOINT_FORMAT"},
+	{RPC_NT_INVALID_NET_ADDR, -EIO, "RPC_NT_INVALID_NET_ADDR"},
+	{RPC_NT_NO_ENDPOINT_FOUND, -EIO, "RPC_NT_NO_ENDPOINT_FOUND"},
+	{RPC_NT_INVALID_TIMEOUT, -EINVAL, "RPC_NT_INVALID_TIMEOUT"},
+	{RPC_NT_OBJECT_NOT_FOUND, -ENOENT, "RPC_NT_OBJECT_NOT_FOUND"},
+	{RPC_NT_ALREADY_REGISTERED, -EIO, "RPC_NT_ALREADY_REGISTERED"},
+	{RPC_NT_TYPE_ALREADY_REGISTERED, -EIO,
+	"RPC_NT_TYPE_ALREADY_REGISTERED"},
+	{RPC_NT_ALREADY_LISTENING, -EIO, "RPC_NT_ALREADY_LISTENING"},
+	{RPC_NT_NO_PROTSEQS_REGISTERED, -EIO, "RPC_NT_NO_PROTSEQS_REGISTERED"},
+	{RPC_NT_NOT_LISTENING, -EIO, "RPC_NT_NOT_LISTENING"},
+	{RPC_NT_UNKNOWN_MGR_TYPE, -EIO, "RPC_NT_UNKNOWN_MGR_TYPE"},
+	{RPC_NT_UNKNOWN_IF, -EIO, "RPC_NT_UNKNOWN_IF"},
+	{RPC_NT_NO_BINDINGS, -EIO, "RPC_NT_NO_BINDINGS"},
+	{RPC_NT_NO_PROTSEQS, -EIO, "RPC_NT_NO_PROTSEQS"},
+	{RPC_NT_CANT_CREATE_ENDPOINT, -EIO, "RPC_NT_CANT_CREATE_ENDPOINT"},
+	{RPC_NT_OUT_OF_RESOURCES, -EIO, "RPC_NT_OUT_OF_RESOURCES"},
+	{RPC_NT_SERVER_UNAVAILABLE, -EIO, "RPC_NT_SERVER_UNAVAILABLE"},
+	{RPC_NT_SERVER_TOO_BUSY, -EBUSY, "RPC_NT_SERVER_TOO_BUSY"},
+	{RPC_NT_INVALID_NETWORK_OPTIONS, -EIO,
+	"RPC_NT_INVALID_NETWORK_OPTIONS"},
+	{RPC_NT_NO_CALL_ACTIVE, -EIO, "RPC_NT_NO_CALL_ACTIVE"},
+	{RPC_NT_CALL_FAILED, -EIO, "RPC_NT_CALL_FAILED"},
+	{RPC_NT_CALL_FAILED_DNE, -EIO, "RPC_NT_CALL_FAILED_DNE"},
+	{RPC_NT_PROTOCOL_ERROR, -EIO, "RPC_NT_PROTOCOL_ERROR"},
+	{RPC_NT_UNSUPPORTED_TRANS_SYN, -EIO, "RPC_NT_UNSUPPORTED_TRANS_SYN"},
+	{RPC_NT_UNSUPPORTED_TYPE, -EIO, "RPC_NT_UNSUPPORTED_TYPE"},
+	{RPC_NT_INVALID_TAG, -EIO, "RPC_NT_INVALID_TAG"},
+	{RPC_NT_INVALID_BOUND, -EIO, "RPC_NT_INVALID_BOUND"},
+	{RPC_NT_NO_ENTRY_NAME, -EIO, "RPC_NT_NO_ENTRY_NAME"},
+	{RPC_NT_INVALID_NAME_SYNTAX, -EIO, "RPC_NT_INVALID_NAME_SYNTAX"},
+	{RPC_NT_UNSUPPORTED_NAME_SYNTAX, -EIO,
+	"RPC_NT_UNSUPPORTED_NAME_SYNTAX"},
+	{RPC_NT_UUID_NO_ADDRESS, -EIO, "RPC_NT_UUID_NO_ADDRESS"},
+	{RPC_NT_DUPLICATE_ENDPOINT, -ENOTUNIQ, "RPC_NT_DUPLICATE_ENDPOINT"},
+	{RPC_NT_UNKNOWN_AUTHN_TYPE, -EIO, "RPC_NT_UNKNOWN_AUTHN_TYPE"},
+	{RPC_NT_MAX_CALLS_TOO_SMALL, -EIO, "RPC_NT_MAX_CALLS_TOO_SMALL"},
+	{RPC_NT_STRING_TOO_LONG, -EIO, "RPC_NT_STRING_TOO_LONG"},
+	{RPC_NT_PROTSEQ_NOT_FOUND, -EIO, "RPC_NT_PROTSEQ_NOT_FOUND"},
+	{RPC_NT_PROCNUM_OUT_OF_RANGE, -EIO, "RPC_NT_PROCNUM_OUT_OF_RANGE"},
+	{RPC_NT_BINDING_HAS_NO_AUTH, -EIO, "RPC_NT_BINDING_HAS_NO_AUTH"},
+	{RPC_NT_UNKNOWN_AUTHN_SERVICE, -EIO, "RPC_NT_UNKNOWN_AUTHN_SERVICE"},
+	{RPC_NT_UNKNOWN_AUTHN_LEVEL, -EIO, "RPC_NT_UNKNOWN_AUTHN_LEVEL"},
+	{RPC_NT_INVALID_AUTH_IDENTITY, -EIO, "RPC_NT_INVALID_AUTH_IDENTITY"},
+	{RPC_NT_UNKNOWN_AUTHZ_SERVICE, -EIO, "RPC_NT_UNKNOWN_AUTHZ_SERVICE"},
+	{EPT_NT_INVALID_ENTRY, -EIO, "EPT_NT_INVALID_ENTRY"},
+	{EPT_NT_CANT_PERFORM_OP, -EIO, "EPT_NT_CANT_PERFORM_OP"},
+	{EPT_NT_NOT_REGISTERED, -EIO, "EPT_NT_NOT_REGISTERED"},
+	{RPC_NT_NOTHING_TO_EXPORT, -EIO, "RPC_NT_NOTHING_TO_EXPORT"},
+	{RPC_NT_INCOMPLETE_NAME, -EIO, "RPC_NT_INCOMPLETE_NAME"},
+	{RPC_NT_INVALID_VERS_OPTION, -EIO, "RPC_NT_INVALID_VERS_OPTION"},
+	{RPC_NT_NO_MORE_MEMBERS, -EIO, "RPC_NT_NO_MORE_MEMBERS"},
+	{RPC_NT_NOT_ALL_OBJS_UNEXPORTED, -EIO,
+	"RPC_NT_NOT_ALL_OBJS_UNEXPORTED"},
+	{RPC_NT_INTERFACE_NOT_FOUND, -EIO, "RPC_NT_INTERFACE_NOT_FOUND"},
+	{RPC_NT_ENTRY_ALREADY_EXISTS, -EIO, "RPC_NT_ENTRY_ALREADY_EXISTS"},
+	{RPC_NT_ENTRY_NOT_FOUND, -EIO, "RPC_NT_ENTRY_NOT_FOUND"},
+	{RPC_NT_NAME_SERVICE_UNAVAILABLE, -EIO,
+	"RPC_NT_NAME_SERVICE_UNAVAILABLE"},
+	{RPC_NT_INVALID_NAF_ID, -EIO, "RPC_NT_INVALID_NAF_ID"},
+	{RPC_NT_CANNOT_SUPPORT, -EOPNOTSUPP, "RPC_NT_CANNOT_SUPPORT"},
+	{RPC_NT_NO_CONTEXT_AVAILABLE, -EIO, "RPC_NT_NO_CONTEXT_AVAILABLE"},
+	{RPC_NT_INTERNAL_ERROR, -EIO, "RPC_NT_INTERNAL_ERROR"},
+	{RPC_NT_ZERO_DIVIDE, -EIO, "RPC_NT_ZERO_DIVIDE"},
+	{RPC_NT_ADDRESS_ERROR, -EIO, "RPC_NT_ADDRESS_ERROR"},
+	{RPC_NT_FP_DIV_ZERO, -EIO, "RPC_NT_FP_DIV_ZERO"},
+	{RPC_NT_FP_UNDERFLOW, -EIO, "RPC_NT_FP_UNDERFLOW"},
+	{RPC_NT_FP_OVERFLOW, -EIO, "RPC_NT_FP_OVERFLOW"},
+	{RPC_NT_CALL_IN_PROGRESS, -EIO, "RPC_NT_CALL_IN_PROGRESS"},
+	{RPC_NT_NO_MORE_BINDINGS, -EIO, "RPC_NT_NO_MORE_BINDINGS"},
+	{RPC_NT_GROUP_MEMBER_NOT_FOUND, -EIO, "RPC_NT_GROUP_MEMBER_NOT_FOUND"},
+	{EPT_NT_CANT_CREATE, -EIO, "EPT_NT_CANT_CREATE"},
+	{RPC_NT_INVALID_OBJECT, -EIO, "RPC_NT_INVALID_OBJECT"},
+	{RPC_NT_NO_INTERFACES, -EIO, "RPC_NT_NO_INTERFACES"},
+	{RPC_NT_CALL_CANCELLED, -EIO, "RPC_NT_CALL_CANCELLED"},
+	{RPC_NT_BINDING_INCOMPLETE, -EIO, "RPC_NT_BINDING_INCOMPLETE"},
+	{RPC_NT_COMM_FAILURE, -EIO, "RPC_NT_COMM_FAILURE"},
+	{RPC_NT_UNSUPPORTED_AUTHN_LEVEL, -EIO,
+	"RPC_NT_UNSUPPORTED_AUTHN_LEVEL"},
+	{RPC_NT_NO_PRINC_NAME, -EIO, "RPC_NT_NO_PRINC_NAME"},
+	{RPC_NT_NOT_RPC_ERROR, -EIO, "RPC_NT_NOT_RPC_ERROR"},
+	{RPC_NT_SEC_PKG_ERROR, -EIO, "RPC_NT_SEC_PKG_ERROR"},
+	{RPC_NT_NOT_CANCELLED, -EIO, "RPC_NT_NOT_CANCELLED"},
+	{RPC_NT_INVALID_ASYNC_HANDLE, -EIO, "RPC_NT_INVALID_ASYNC_HANDLE"},
+	{RPC_NT_INVALID_ASYNC_CALL, -EIO, "RPC_NT_INVALID_ASYNC_CALL"},
+	{RPC_NT_PROXY_ACCESS_DENIED, -EACCES, "RPC_NT_PROXY_ACCESS_DENIED"},
+	{RPC_NT_NO_MORE_ENTRIES, -EIO, "RPC_NT_NO_MORE_ENTRIES"},
+	{RPC_NT_SS_CHAR_TRANS_OPEN_FAIL, -EIO,
+	"RPC_NT_SS_CHAR_TRANS_OPEN_FAIL"},
+	{RPC_NT_SS_CHAR_TRANS_SHORT_FILE, -EIO,
+	"RPC_NT_SS_CHAR_TRANS_SHORT_FILE"},
+	{RPC_NT_SS_IN_NULL_CONTEXT, -EIO, "RPC_NT_SS_IN_NULL_CONTEXT"},
+	{RPC_NT_SS_CONTEXT_MISMATCH, -EIO, "RPC_NT_SS_CONTEXT_MISMATCH"},
+	{RPC_NT_SS_CONTEXT_DAMAGED, -EIO, "RPC_NT_SS_CONTEXT_DAMAGED"},
+	{RPC_NT_SS_HANDLES_MISMATCH, -EIO, "RPC_NT_SS_HANDLES_MISMATCH"},
+	{RPC_NT_SS_CANNOT_GET_CALL_HANDLE, -EIO,
+	"RPC_NT_SS_CANNOT_GET_CALL_HANDLE"},
+	{RPC_NT_NULL_REF_POINTER, -EIO, "RPC_NT_NULL_REF_POINTER"},
+	{RPC_NT_ENUM_VALUE_OUT_OF_RANGE, -EIO,
+	"RPC_NT_ENUM_VALUE_OUT_OF_RANGE"},
+	{RPC_NT_BYTE_COUNT_TOO_SMALL, -EIO, "RPC_NT_BYTE_COUNT_TOO_SMALL"},
+	{RPC_NT_BAD_STUB_DATA, -EIO, "RPC_NT_BAD_STUB_DATA"},
+	{RPC_NT_INVALID_ES_ACTION, -EIO, "RPC_NT_INVALID_ES_ACTION"},
+	{RPC_NT_WRONG_ES_VERSION, -EIO, "RPC_NT_WRONG_ES_VERSION"},
+	{RPC_NT_WRONG_STUB_VERSION, -EIO, "RPC_NT_WRONG_STUB_VERSION"},
+	{RPC_NT_INVALID_PIPE_OBJECT, -EIO, "RPC_NT_INVALID_PIPE_OBJECT"},
+	{RPC_NT_INVALID_PIPE_OPERATION, -EIO, "RPC_NT_INVALID_PIPE_OPERATION"},
+	{RPC_NT_WRONG_PIPE_VERSION, -EIO, "RPC_NT_WRONG_PIPE_VERSION"},
+	{RPC_NT_PIPE_CLOSED, -EIO, "RPC_NT_PIPE_CLOSED"},
+	{RPC_NT_PIPE_DISCIPLINE_ERROR, -EIO, "RPC_NT_PIPE_DISCIPLINE_ERROR"},
+	{RPC_NT_PIPE_EMPTY, -EIO, "RPC_NT_PIPE_EMPTY"},
+	{STATUS_PNP_BAD_MPS_TABLE, -EIO, "STATUS_PNP_BAD_MPS_TABLE"},
+	{STATUS_PNP_TRANSLATION_FAILED, -EIO, "STATUS_PNP_TRANSLATION_FAILED"},
+	{STATUS_PNP_IRQ_TRANSLATION_FAILED, -EIO,
+	"STATUS_PNP_IRQ_TRANSLATION_FAILED"},
+	{STATUS_PNP_INVALID_ID, -EIO, "STATUS_PNP_INVALID_ID"},
+	{STATUS_IO_REISSUE_AS_CACHED, -EIO, "STATUS_IO_REISSUE_AS_CACHED"},
+	{STATUS_CTX_WINSTATION_NAME_INVALID, -EIO,
+	"STATUS_CTX_WINSTATION_NAME_INVALID"},
+	{STATUS_CTX_INVALID_PD, -EIO, "STATUS_CTX_INVALID_PD"},
+	{STATUS_CTX_PD_NOT_FOUND, -EIO, "STATUS_CTX_PD_NOT_FOUND"},
+	{STATUS_CTX_CLOSE_PENDING, -EIO, "STATUS_CTX_CLOSE_PENDING"},
+	{STATUS_CTX_NO_OUTBUF, -EIO, "STATUS_CTX_NO_OUTBUF"},
+	{STATUS_CTX_MODEM_INF_NOT_FOUND, -EIO,
+	"STATUS_CTX_MODEM_INF_NOT_FOUND"},
+	{STATUS_CTX_INVALID_MODEMNAME, -EIO, "STATUS_CTX_INVALID_MODEMNAME"},
+	{STATUS_CTX_RESPONSE_ERROR, -EIO, "STATUS_CTX_RESPONSE_ERROR"},
+	{STATUS_CTX_MODEM_RESPONSE_TIMEOUT, -ETIMEDOUT,
+	"STATUS_CTX_MODEM_RESPONSE_TIMEOUT"},
+	{STATUS_CTX_MODEM_RESPONSE_NO_CARRIER, -EIO,
+	"STATUS_CTX_MODEM_RESPONSE_NO_CARRIER"},
+	{STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE, -EIO,
+	"STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE"},
+	{STATUS_CTX_MODEM_RESPONSE_BUSY, -EBUSY,
+	"STATUS_CTX_MODEM_RESPONSE_BUSY"},
+	{STATUS_CTX_MODEM_RESPONSE_VOICE, -EIO,
+	"STATUS_CTX_MODEM_RESPONSE_VOICE"},
+	{STATUS_CTX_TD_ERROR, -EIO, "STATUS_CTX_TD_ERROR"},
+	{STATUS_CTX_LICENSE_CLIENT_INVALID, -EIO,
+	"STATUS_CTX_LICENSE_CLIENT_INVALID"},
+	{STATUS_CTX_LICENSE_NOT_AVAILABLE, -EIO,
+	"STATUS_CTX_LICENSE_NOT_AVAILABLE"},
+	{STATUS_CTX_LICENSE_EXPIRED, -EIO, "STATUS_CTX_LICENSE_EXPIRED"},
+	{STATUS_CTX_WINSTATION_NOT_FOUND, -EIO,
+	"STATUS_CTX_WINSTATION_NOT_FOUND"},
+	{STATUS_CTX_WINSTATION_NAME_COLLISION, -EIO,
+	"STATUS_CTX_WINSTATION_NAME_COLLISION"},
+	{STATUS_CTX_WINSTATION_BUSY, -EBUSY, "STATUS_CTX_WINSTATION_BUSY"},
+	{STATUS_CTX_BAD_VIDEO_MODE, -EIO, "STATUS_CTX_BAD_VIDEO_MODE"},
+	{STATUS_CTX_GRAPHICS_INVALID, -EIO, "STATUS_CTX_GRAPHICS_INVALID"},
+	{STATUS_CTX_NOT_CONSOLE, -EIO, "STATUS_CTX_NOT_CONSOLE"},
+	{STATUS_CTX_CLIENT_QUERY_TIMEOUT, -EIO,
+	"STATUS_CTX_CLIENT_QUERY_TIMEOUT"},
+	{STATUS_CTX_CONSOLE_DISCONNECT, -EIO, "STATUS_CTX_CONSOLE_DISCONNECT"},
+	{STATUS_CTX_CONSOLE_CONNECT, -EIO, "STATUS_CTX_CONSOLE_CONNECT"},
+	{STATUS_CTX_SHADOW_DENIED, -EIO, "STATUS_CTX_SHADOW_DENIED"},
+	{STATUS_CTX_WINSTATION_ACCESS_DENIED, -EACCES,
+	"STATUS_CTX_WINSTATION_ACCESS_DENIED"},
+	{STATUS_CTX_INVALID_WD, -EIO, "STATUS_CTX_INVALID_WD"},
+	{STATUS_CTX_WD_NOT_FOUND, -EIO, "STATUS_CTX_WD_NOT_FOUND"},
+	{STATUS_CTX_SHADOW_INVALID, -EIO, "STATUS_CTX_SHADOW_INVALID"},
+	{STATUS_CTX_SHADOW_DISABLED, -EIO, "STATUS_CTX_SHADOW_DISABLED"},
+	{STATUS_RDP_PROTOCOL_ERROR, -EIO, "STATUS_RDP_PROTOCOL_ERROR"},
+	{STATUS_CTX_CLIENT_LICENSE_NOT_SET, -EIO,
+	"STATUS_CTX_CLIENT_LICENSE_NOT_SET"},
+	{STATUS_CTX_CLIENT_LICENSE_IN_USE, -EIO,
+	"STATUS_CTX_CLIENT_LICENSE_IN_USE"},
+	{STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE, -EIO,
+	"STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE"},
+	{STATUS_CTX_SHADOW_NOT_RUNNING, -EIO, "STATUS_CTX_SHADOW_NOT_RUNNING"},
+	{STATUS_CTX_LOGON_DISABLED, -EIO, "STATUS_CTX_LOGON_DISABLED"},
+	{STATUS_CTX_SECURITY_LAYER_ERROR, -EIO,
+	"STATUS_CTX_SECURITY_LAYER_ERROR"},
+	{STATUS_TS_INCOMPATIBLE_SESSIONS, -EIO,
+	"STATUS_TS_INCOMPATIBLE_SESSIONS"},
+	{STATUS_MUI_FILE_NOT_FOUND, -EIO, "STATUS_MUI_FILE_NOT_FOUND"},
+	{STATUS_MUI_INVALID_FILE, -EIO, "STATUS_MUI_INVALID_FILE"},
+	{STATUS_MUI_INVALID_RC_CONFIG, -EIO, "STATUS_MUI_INVALID_RC_CONFIG"},
+	{STATUS_MUI_INVALID_LOCALE_NAME, -EIO,
+	"STATUS_MUI_INVALID_LOCALE_NAME"},
+	{STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME, -EIO,
+	"STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME"},
+	{STATUS_MUI_FILE_NOT_LOADED, -EIO, "STATUS_MUI_FILE_NOT_LOADED"},
+	{STATUS_RESOURCE_ENUM_USER_STOP, -EIO,
+	"STATUS_RESOURCE_ENUM_USER_STOP"},
+	{STATUS_CLUSTER_INVALID_NODE, -EIO, "STATUS_CLUSTER_INVALID_NODE"},
+	{STATUS_CLUSTER_NODE_EXISTS, -EIO, "STATUS_CLUSTER_NODE_EXISTS"},
+	{STATUS_CLUSTER_JOIN_IN_PROGRESS, -EIO,
+	"STATUS_CLUSTER_JOIN_IN_PROGRESS"},
+	{STATUS_CLUSTER_NODE_NOT_FOUND, -EIO, "STATUS_CLUSTER_NODE_NOT_FOUND"},
+	{STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND, -EIO,
+	"STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND"},
+	{STATUS_CLUSTER_NETWORK_EXISTS, -EIO, "STATUS_CLUSTER_NETWORK_EXISTS"},
+	{STATUS_CLUSTER_NETWORK_NOT_FOUND, -EIO,
+	"STATUS_CLUSTER_NETWORK_NOT_FOUND"},
+	{STATUS_CLUSTER_NETINTERFACE_EXISTS, -EIO,
+	"STATUS_CLUSTER_NETINTERFACE_EXISTS"},
+	{STATUS_CLUSTER_NETINTERFACE_NOT_FOUND, -EIO,
+	"STATUS_CLUSTER_NETINTERFACE_NOT_FOUND"},
+	{STATUS_CLUSTER_INVALID_REQUEST, -EIO,
+	"STATUS_CLUSTER_INVALID_REQUEST"},
+	{STATUS_CLUSTER_INVALID_NETWORK_PROVIDER, -EIO,
+	"STATUS_CLUSTER_INVALID_NETWORK_PROVIDER"},
+	{STATUS_CLUSTER_NODE_DOWN, -EIO, "STATUS_CLUSTER_NODE_DOWN"},
+	{STATUS_CLUSTER_NODE_UNREACHABLE, -EIO,
+	"STATUS_CLUSTER_NODE_UNREACHABLE"},
+	{STATUS_CLUSTER_NODE_NOT_MEMBER, -EIO,
+	"STATUS_CLUSTER_NODE_NOT_MEMBER"},
+	{STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS, -EIO,
+	"STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS"},
+	{STATUS_CLUSTER_INVALID_NETWORK, -EIO,
+	"STATUS_CLUSTER_INVALID_NETWORK"},
+	{STATUS_CLUSTER_NO_NET_ADAPTERS, -EIO,
+	"STATUS_CLUSTER_NO_NET_ADAPTERS"},
+	{STATUS_CLUSTER_NODE_UP, -EIO, "STATUS_CLUSTER_NODE_UP"},
+	{STATUS_CLUSTER_NODE_PAUSED, -EIO, "STATUS_CLUSTER_NODE_PAUSED"},
+	{STATUS_CLUSTER_NODE_NOT_PAUSED, -EIO,
+	"STATUS_CLUSTER_NODE_NOT_PAUSED"},
+	{STATUS_CLUSTER_NO_SECURITY_CONTEXT, -EIO,
+	"STATUS_CLUSTER_NO_SECURITY_CONTEXT"},
+	{STATUS_CLUSTER_NETWORK_NOT_INTERNAL, -EIO,
+	"STATUS_CLUSTER_NETWORK_NOT_INTERNAL"},
+	{STATUS_CLUSTER_POISONED, -EIO, "STATUS_CLUSTER_POISONED"},
+	{STATUS_ACPI_INVALID_OPCODE, -EIO, "STATUS_ACPI_INVALID_OPCODE"},
+	{STATUS_ACPI_STACK_OVERFLOW, -EIO, "STATUS_ACPI_STACK_OVERFLOW"},
+	{STATUS_ACPI_ASSERT_FAILED, -EIO, "STATUS_ACPI_ASSERT_FAILED"},
+	{STATUS_ACPI_INVALID_INDEX, -EIO, "STATUS_ACPI_INVALID_INDEX"},
+	{STATUS_ACPI_INVALID_ARGUMENT, -EIO, "STATUS_ACPI_INVALID_ARGUMENT"},
+	{STATUS_ACPI_FATAL, -EIO, "STATUS_ACPI_FATAL"},
+	{STATUS_ACPI_INVALID_SUPERNAME, -EIO, "STATUS_ACPI_INVALID_SUPERNAME"},
+	{STATUS_ACPI_INVALID_ARGTYPE, -EIO, "STATUS_ACPI_INVALID_ARGTYPE"},
+	{STATUS_ACPI_INVALID_OBJTYPE, -EIO, "STATUS_ACPI_INVALID_OBJTYPE"},
+	{STATUS_ACPI_INVALID_TARGETTYPE, -EIO,
+	"STATUS_ACPI_INVALID_TARGETTYPE"},
+	{STATUS_ACPI_INCORRECT_ARGUMENT_COUNT, -EIO,
+	"STATUS_ACPI_INCORRECT_ARGUMENT_COUNT"},
+	{STATUS_ACPI_ADDRESS_NOT_MAPPED, -EIO,
+	"STATUS_ACPI_ADDRESS_NOT_MAPPED"},
+	{STATUS_ACPI_INVALID_EVENTTYPE, -EIO, "STATUS_ACPI_INVALID_EVENTTYPE"},
+	{STATUS_ACPI_HANDLER_COLLISION, -EIO, "STATUS_ACPI_HANDLER_COLLISION"},
+	{STATUS_ACPI_INVALID_DATA, -EIO, "STATUS_ACPI_INVALID_DATA"},
+	{STATUS_ACPI_INVALID_REGION, -EIO, "STATUS_ACPI_INVALID_REGION"},
+	{STATUS_ACPI_INVALID_ACCESS_SIZE, -EIO,
+	"STATUS_ACPI_INVALID_ACCESS_SIZE"},
+	{STATUS_ACPI_ACQUIRE_GLOBAL_LOCK, -EIO,
+	"STATUS_ACPI_ACQUIRE_GLOBAL_LOCK"},
+	{STATUS_ACPI_ALREADY_INITIALIZED, -EIO,
+	"STATUS_ACPI_ALREADY_INITIALIZED"},
+	{STATUS_ACPI_NOT_INITIALIZED, -EIO, "STATUS_ACPI_NOT_INITIALIZED"},
+	{STATUS_ACPI_INVALID_MUTEX_LEVEL, -EIO,
+	"STATUS_ACPI_INVALID_MUTEX_LEVEL"},
+	{STATUS_ACPI_MUTEX_NOT_OWNED, -EIO, "STATUS_ACPI_MUTEX_NOT_OWNED"},
+	{STATUS_ACPI_MUTEX_NOT_OWNER, -EIO, "STATUS_ACPI_MUTEX_NOT_OWNER"},
+	{STATUS_ACPI_RS_ACCESS, -EIO, "STATUS_ACPI_RS_ACCESS"},
+	{STATUS_ACPI_INVALID_TABLE, -EIO, "STATUS_ACPI_INVALID_TABLE"},
+	{STATUS_ACPI_REG_HANDLER_FAILED, -EIO,
+	"STATUS_ACPI_REG_HANDLER_FAILED"},
+	{STATUS_ACPI_POWER_REQUEST_FAILED, -EIO,
+	"STATUS_ACPI_POWER_REQUEST_FAILED"},
+	{STATUS_SXS_SECTION_NOT_FOUND, -EIO, "STATUS_SXS_SECTION_NOT_FOUND"},
+	{STATUS_SXS_CANT_GEN_ACTCTX, -EIO, "STATUS_SXS_CANT_GEN_ACTCTX"},
+	{STATUS_SXS_INVALID_ACTCTXDATA_FORMAT, -EIO,
+	"STATUS_SXS_INVALID_ACTCTXDATA_FORMAT"},
+	{STATUS_SXS_ASSEMBLY_NOT_FOUND, -EIO, "STATUS_SXS_ASSEMBLY_NOT_FOUND"},
+	{STATUS_SXS_MANIFEST_FORMAT_ERROR, -EIO,
+	"STATUS_SXS_MANIFEST_FORMAT_ERROR"},
+	{STATUS_SXS_MANIFEST_PARSE_ERROR, -EIO,
+	"STATUS_SXS_MANIFEST_PARSE_ERROR"},
+	{STATUS_SXS_ACTIVATION_CONTEXT_DISABLED, -EIO,
+	"STATUS_SXS_ACTIVATION_CONTEXT_DISABLED"},
+	{STATUS_SXS_KEY_NOT_FOUND, -EIO, "STATUS_SXS_KEY_NOT_FOUND"},
+	{STATUS_SXS_VERSION_CONFLICT, -EIO, "STATUS_SXS_VERSION_CONFLICT"},
+	{STATUS_SXS_WRONG_SECTION_TYPE, -EIO, "STATUS_SXS_WRONG_SECTION_TYPE"},
+	{STATUS_SXS_THREAD_QUERIES_DISABLED, -EIO,
+	"STATUS_SXS_THREAD_QUERIES_DISABLED"},
+	{STATUS_SXS_ASSEMBLY_MISSING, -EIO, "STATUS_SXS_ASSEMBLY_MISSING"},
+	{STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET, -EIO,
+	"STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET"},
+	{STATUS_SXS_EARLY_DEACTIVATION, -EIO, "STATUS_SXS_EARLY_DEACTIVATION"},
+	{STATUS_SXS_INVALID_DEACTIVATION, -EIO,
+	"STATUS_SXS_INVALID_DEACTIVATION"},
+	{STATUS_SXS_MULTIPLE_DEACTIVATION, -EIO,
+	"STATUS_SXS_MULTIPLE_DEACTIVATION"},
+	{STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY, -EIO,
+	"STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY"},
+	{STATUS_SXS_PROCESS_TERMINATION_REQUESTED, -EIO,
+	"STATUS_SXS_PROCESS_TERMINATION_REQUESTED"},
+	{STATUS_SXS_CORRUPT_ACTIVATION_STACK, -EIO,
+	"STATUS_SXS_CORRUPT_ACTIVATION_STACK"},
+	{STATUS_SXS_CORRUPTION, -EIO, "STATUS_SXS_CORRUPTION"},
+	{STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE, -EIO,
+	"STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE"},
+	{STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME, -EIO,
+	"STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME"},
+	{STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE, -EIO,
+	"STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE"},
+	{STATUS_SXS_IDENTITY_PARSE_ERROR, -EIO,
+	"STATUS_SXS_IDENTITY_PARSE_ERROR"},
+	{STATUS_SXS_COMPONENT_STORE_CORRUPT, -EIO,
+	"STATUS_SXS_COMPONENT_STORE_CORRUPT"},
+	{STATUS_SXS_FILE_HASH_MISMATCH, -EIO, "STATUS_SXS_FILE_HASH_MISMATCH"},
+	{STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT, -EIO,
+	"STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT"},
+	{STATUS_SXS_IDENTITIES_DIFFERENT, -EIO,
+	"STATUS_SXS_IDENTITIES_DIFFERENT"},
+	{STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT, -EIO,
+	"STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT"},
+	{STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY, -EIO,
+	"STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY"},
+	{STATUS_ADVANCED_INSTALLER_FAILED, -EIO,
+	"STATUS_ADVANCED_INSTALLER_FAILED"},
+	{STATUS_XML_ENCODING_MISMATCH, -EIO, "STATUS_XML_ENCODING_MISMATCH"},
+	{STATUS_SXS_MANIFEST_TOO_BIG, -EIO, "STATUS_SXS_MANIFEST_TOO_BIG"},
+	{STATUS_SXS_SETTING_NOT_REGISTERED, -EIO,
+	"STATUS_SXS_SETTING_NOT_REGISTERED"},
+	{STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE, -EIO,
+	"STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE"},
+	{STATUS_SMI_PRIMITIVE_INSTALLER_FAILED, -EIO,
+	"STATUS_SMI_PRIMITIVE_INSTALLER_FAILED"},
+	{STATUS_GENERIC_COMMAND_FAILED, -EIO, "STATUS_GENERIC_COMMAND_FAILED"},
+	{STATUS_SXS_FILE_HASH_MISSING, -EIO, "STATUS_SXS_FILE_HASH_MISSING"},
+	{STATUS_TRANSACTIONAL_CONFLICT, -EIO, "STATUS_TRANSACTIONAL_CONFLICT"},
+	{STATUS_INVALID_TRANSACTION, -EIO, "STATUS_INVALID_TRANSACTION"},
+	{STATUS_TRANSACTION_NOT_ACTIVE, -EIO, "STATUS_TRANSACTION_NOT_ACTIVE"},
+	{STATUS_TM_INITIALIZATION_FAILED, -EIO,
+	"STATUS_TM_INITIALIZATION_FAILED"},
+	{STATUS_RM_NOT_ACTIVE, -EIO, "STATUS_RM_NOT_ACTIVE"},
+	{STATUS_RM_METADATA_CORRUPT, -EIO, "STATUS_RM_METADATA_CORRUPT"},
+	{STATUS_TRANSACTION_NOT_JOINED, -EIO, "STATUS_TRANSACTION_NOT_JOINED"},
+	{STATUS_DIRECTORY_NOT_RM, -EIO, "STATUS_DIRECTORY_NOT_RM"},
+	{STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE, -EIO,
+	"STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE"},
+	{STATUS_LOG_RESIZE_INVALID_SIZE, -EIO,
+	"STATUS_LOG_RESIZE_INVALID_SIZE"},
+	{STATUS_REMOTE_FILE_VERSION_MISMATCH, -EIO,
+	"STATUS_REMOTE_FILE_VERSION_MISMATCH"},
+	{STATUS_CRM_PROTOCOL_ALREADY_EXISTS, -EIO,
+	"STATUS_CRM_PROTOCOL_ALREADY_EXISTS"},
+	{STATUS_TRANSACTION_PROPAGATION_FAILED, -EIO,
+	"STATUS_TRANSACTION_PROPAGATION_FAILED"},
+	{STATUS_CRM_PROTOCOL_NOT_FOUND, -EIO, "STATUS_CRM_PROTOCOL_NOT_FOUND"},
+	{STATUS_TRANSACTION_SUPERIOR_EXISTS, -EIO,
+	"STATUS_TRANSACTION_SUPERIOR_EXISTS"},
+	{STATUS_TRANSACTION_REQUEST_NOT_VALID, -EIO,
+	"STATUS_TRANSACTION_REQUEST_NOT_VALID"},
+	{STATUS_TRANSACTION_NOT_REQUESTED, -EIO,
+	"STATUS_TRANSACTION_NOT_REQUESTED"},
+	{STATUS_TRANSACTION_ALREADY_ABORTED, -EIO,
+	"STATUS_TRANSACTION_ALREADY_ABORTED"},
+	{STATUS_TRANSACTION_ALREADY_COMMITTED, -EIO,
+	"STATUS_TRANSACTION_ALREADY_COMMITTED"},
+	{STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER, -EIO,
+	"STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER"},
+	{STATUS_CURRENT_TRANSACTION_NOT_VALID, -EIO,
+	"STATUS_CURRENT_TRANSACTION_NOT_VALID"},
+	{STATUS_LOG_GROWTH_FAILED, -EIO, "STATUS_LOG_GROWTH_FAILED"},
+	{STATUS_OBJECT_NO_LONGER_EXISTS, -EIO,
+	"STATUS_OBJECT_NO_LONGER_EXISTS"},
+	{STATUS_STREAM_MINIVERSION_NOT_FOUND, -EIO,
+	"STATUS_STREAM_MINIVERSION_NOT_FOUND"},
+	{STATUS_STREAM_MINIVERSION_NOT_VALID, -EIO,
+	"STATUS_STREAM_MINIVERSION_NOT_VALID"},
+	{STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION, -EIO,
+	"STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION"},
+	{STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT, -EIO,
+	"STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT"},
+	{STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS, -EIO,
+	"STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS"},
+	{STATUS_HANDLE_NO_LONGER_VALID, -EIO, "STATUS_HANDLE_NO_LONGER_VALID"},
+	{STATUS_LOG_CORRUPTION_DETECTED, -EIO,
+	"STATUS_LOG_CORRUPTION_DETECTED"},
+	{STATUS_RM_DISCONNECTED, -EIO, "STATUS_RM_DISCONNECTED"},
+	{STATUS_ENLISTMENT_NOT_SUPERIOR, -EIO,
+	"STATUS_ENLISTMENT_NOT_SUPERIOR"},
+	{STATUS_FILE_IDENTITY_NOT_PERSISTENT, -EIO,
+	"STATUS_FILE_IDENTITY_NOT_PERSISTENT"},
+	{STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY, -EIO,
+	"STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY"},
+	{STATUS_CANT_CROSS_RM_BOUNDARY, -EIO, "STATUS_CANT_CROSS_RM_BOUNDARY"},
+	{STATUS_TXF_DIR_NOT_EMPTY, -EIO, "STATUS_TXF_DIR_NOT_EMPTY"},
+	{STATUS_INDOUBT_TRANSACTIONS_EXIST, -EIO,
+	"STATUS_INDOUBT_TRANSACTIONS_EXIST"},
+	{STATUS_TM_VOLATILE, -EIO, "STATUS_TM_VOLATILE"},
+	{STATUS_ROLLBACK_TIMER_EXPIRED, -EIO, "STATUS_ROLLBACK_TIMER_EXPIRED"},
+	{STATUS_TXF_ATTRIBUTE_CORRUPT, -EIO, "STATUS_TXF_ATTRIBUTE_CORRUPT"},
+	{STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION, -EIO,
+	"STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION"},
+	{STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED, -EIO,
+	"STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED"},
+	{STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE, -EIO,
+	"STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE"},
+	{STATUS_TRANSACTION_REQUIRED_PROMOTION, -EIO,
+	"STATUS_TRANSACTION_REQUIRED_PROMOTION"},
+	{STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION, -EIO,
+	"STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION"},
+	{STATUS_TRANSACTIONS_NOT_FROZEN, -EIO,
+	"STATUS_TRANSACTIONS_NOT_FROZEN"},
+	{STATUS_TRANSACTION_FREEZE_IN_PROGRESS, -EIO,
+	"STATUS_TRANSACTION_FREEZE_IN_PROGRESS"},
+	{STATUS_NOT_SNAPSHOT_VOLUME, -EIO, "STATUS_NOT_SNAPSHOT_VOLUME"},
+	{STATUS_NO_SAVEPOINT_WITH_OPEN_FILES, -EIO,
+	"STATUS_NO_SAVEPOINT_WITH_OPEN_FILES"},
+	{STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION, -EIO,
+	"STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION"},
+	{STATUS_TM_IDENTITY_MISMATCH, -EIO, "STATUS_TM_IDENTITY_MISMATCH"},
+	{STATUS_FLOATED_SECTION, -EIO, "STATUS_FLOATED_SECTION"},
+	{STATUS_CANNOT_ACCEPT_TRANSACTED_WORK, -EIO,
+	"STATUS_CANNOT_ACCEPT_TRANSACTED_WORK"},
+	{STATUS_CANNOT_ABORT_TRANSACTIONS, -EIO,
+	"STATUS_CANNOT_ABORT_TRANSACTIONS"},
+	{STATUS_TRANSACTION_NOT_FOUND, -EIO, "STATUS_TRANSACTION_NOT_FOUND"},
+	{STATUS_RESOURCEMANAGER_NOT_FOUND, -EIO,
+	"STATUS_RESOURCEMANAGER_NOT_FOUND"},
+	{STATUS_ENLISTMENT_NOT_FOUND, -EIO, "STATUS_ENLISTMENT_NOT_FOUND"},
+	{STATUS_TRANSACTIONMANAGER_NOT_FOUND, -EIO,
+	"STATUS_TRANSACTIONMANAGER_NOT_FOUND"},
+	{STATUS_TRANSACTIONMANAGER_NOT_ONLINE, -EIO,
+	"STATUS_TRANSACTIONMANAGER_NOT_ONLINE"},
+	{STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION, -EIO,
+	"STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION"},
+	{STATUS_TRANSACTION_NOT_ROOT, -EIO, "STATUS_TRANSACTION_NOT_ROOT"},
+	{STATUS_TRANSACTION_OBJECT_EXPIRED, -EIO,
+	"STATUS_TRANSACTION_OBJECT_EXPIRED"},
+	{STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION, -EIO,
+	"STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION"},
+	{STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED, -EIO,
+	"STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED"},
+	{STATUS_TRANSACTION_RECORD_TOO_LONG, -EIO,
+	"STATUS_TRANSACTION_RECORD_TOO_LONG"},
+	{STATUS_NO_LINK_TRACKING_IN_TRANSACTION, -EIO,
+	"STATUS_NO_LINK_TRACKING_IN_TRANSACTION"},
+	{STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION, -EOPNOTSUPP,
+	"STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION"},
+	{STATUS_TRANSACTION_INTEGRITY_VIOLATED, -EIO,
+	"STATUS_TRANSACTION_INTEGRITY_VIOLATED"},
+	{STATUS_LOG_SECTOR_INVALID, -EIO, "STATUS_LOG_SECTOR_INVALID"},
+	{STATUS_LOG_SECTOR_PARITY_INVALID, -EIO,
+	"STATUS_LOG_SECTOR_PARITY_INVALID"},
+	{STATUS_LOG_SECTOR_REMAPPED, -EIO, "STATUS_LOG_SECTOR_REMAPPED"},
+	{STATUS_LOG_BLOCK_INCOMPLETE, -EIO, "STATUS_LOG_BLOCK_INCOMPLETE"},
+	{STATUS_LOG_INVALID_RANGE, -EIO, "STATUS_LOG_INVALID_RANGE"},
+	{STATUS_LOG_BLOCKS_EXHAUSTED, -EIO, "STATUS_LOG_BLOCKS_EXHAUSTED"},
+	{STATUS_LOG_READ_CONTEXT_INVALID, -EIO,
+	"STATUS_LOG_READ_CONTEXT_INVALID"},
+	{STATUS_LOG_RESTART_INVALID, -EIO, "STATUS_LOG_RESTART_INVALID"},
+	{STATUS_LOG_BLOCK_VERSION, -EIO, "STATUS_LOG_BLOCK_VERSION"},
+	{STATUS_LOG_BLOCK_INVALID, -EIO, "STATUS_LOG_BLOCK_INVALID"},
+	{STATUS_LOG_READ_MODE_INVALID, -EIO, "STATUS_LOG_READ_MODE_INVALID"},
+	{STATUS_LOG_METADATA_CORRUPT, -EIO, "STATUS_LOG_METADATA_CORRUPT"},
+	{STATUS_LOG_METADATA_INVALID, -EIO, "STATUS_LOG_METADATA_INVALID"},
+	{STATUS_LOG_METADATA_INCONSISTENT, -EIO,
+	"STATUS_LOG_METADATA_INCONSISTENT"},
+	{STATUS_LOG_RESERVATION_INVALID, -EIO,
+	"STATUS_LOG_RESERVATION_INVALID"},
+	{STATUS_LOG_CANT_DELETE, -EIO, "STATUS_LOG_CANT_DELETE"},
+	{STATUS_LOG_CONTAINER_LIMIT_EXCEEDED, -EIO,
+	"STATUS_LOG_CONTAINER_LIMIT_EXCEEDED"},
+	{STATUS_LOG_START_OF_LOG, -EIO, "STATUS_LOG_START_OF_LOG"},
+	{STATUS_LOG_POLICY_ALREADY_INSTALLED, -EIO,
+	"STATUS_LOG_POLICY_ALREADY_INSTALLED"},
+	{STATUS_LOG_POLICY_NOT_INSTALLED, -EIO,
+	"STATUS_LOG_POLICY_NOT_INSTALLED"},
+	{STATUS_LOG_POLICY_INVALID, -EIO, "STATUS_LOG_POLICY_INVALID"},
+	{STATUS_LOG_POLICY_CONFLICT, -EIO, "STATUS_LOG_POLICY_CONFLICT"},
+	{STATUS_LOG_PINNED_ARCHIVE_TAIL, -EIO,
+	"STATUS_LOG_PINNED_ARCHIVE_TAIL"},
+	{STATUS_LOG_RECORD_NONEXISTENT, -EIO, "STATUS_LOG_RECORD_NONEXISTENT"},
+	{STATUS_LOG_RECORDS_RESERVED_INVALID, -EIO,
+	"STATUS_LOG_RECORDS_RESERVED_INVALID"},
+	{STATUS_LOG_SPACE_RESERVED_INVALID, -EIO,
+	"STATUS_LOG_SPACE_RESERVED_INVALID"},
+	{STATUS_LOG_TAIL_INVALID, -EIO, "STATUS_LOG_TAIL_INVALID"},
+	{STATUS_LOG_FULL, -EIO, "STATUS_LOG_FULL"},
+	{STATUS_LOG_MULTIPLEXED, -EIO, "STATUS_LOG_MULTIPLEXED"},
+	{STATUS_LOG_DEDICATED, -EIO, "STATUS_LOG_DEDICATED"},
+	{STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS, -EIO,
+	"STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS"},
+	{STATUS_LOG_ARCHIVE_IN_PROGRESS, -EIO,
+	"STATUS_LOG_ARCHIVE_IN_PROGRESS"},
+	{STATUS_LOG_EPHEMERAL, -EIO, "STATUS_LOG_EPHEMERAL"},
+	{STATUS_LOG_NOT_ENOUGH_CONTAINERS, -EIO,
+	"STATUS_LOG_NOT_ENOUGH_CONTAINERS"},
+	{STATUS_LOG_CLIENT_ALREADY_REGISTERED, -EIO,
+	"STATUS_LOG_CLIENT_ALREADY_REGISTERED"},
+	{STATUS_LOG_CLIENT_NOT_REGISTERED, -EIO,
+	"STATUS_LOG_CLIENT_NOT_REGISTERED"},
+	{STATUS_LOG_FULL_HANDLER_IN_PROGRESS, -EIO,
+	"STATUS_LOG_FULL_HANDLER_IN_PROGRESS"},
+	{STATUS_LOG_CONTAINER_READ_FAILED, -EIO,
+	"STATUS_LOG_CONTAINER_READ_FAILED"},
+	{STATUS_LOG_CONTAINER_WRITE_FAILED, -EIO,
+	"STATUS_LOG_CONTAINER_WRITE_FAILED"},
+	{STATUS_LOG_CONTAINER_OPEN_FAILED, -EIO,
+	"STATUS_LOG_CONTAINER_OPEN_FAILED"},
+	{STATUS_LOG_CONTAINER_STATE_INVALID, -EIO,
+	"STATUS_LOG_CONTAINER_STATE_INVALID"},
+	{STATUS_LOG_STATE_INVALID, -EIO, "STATUS_LOG_STATE_INVALID"},
+	{STATUS_LOG_PINNED, -EIO, "STATUS_LOG_PINNED"},
+	{STATUS_LOG_METADATA_FLUSH_FAILED, -EIO,
+	"STATUS_LOG_METADATA_FLUSH_FAILED"},
+	{STATUS_LOG_INCONSISTENT_SECURITY, -EIO,
+	"STATUS_LOG_INCONSISTENT_SECURITY"},
+	{STATUS_LOG_APPENDED_FLUSH_FAILED, -EIO,
+	"STATUS_LOG_APPENDED_FLUSH_FAILED"},
+	{STATUS_LOG_PINNED_RESERVATION, -EIO, "STATUS_LOG_PINNED_RESERVATION"},
+	{STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD, -EIO,
+	"STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD"},
+	{STATUS_FLT_NO_HANDLER_DEFINED, -EIO, "STATUS_FLT_NO_HANDLER_DEFINED"},
+	{STATUS_FLT_CONTEXT_ALREADY_DEFINED, -EIO,
+	"STATUS_FLT_CONTEXT_ALREADY_DEFINED"},
+	{STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST, -EIO,
+	"STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST"},
+	{STATUS_FLT_DISALLOW_FAST_IO, -EIO, "STATUS_FLT_DISALLOW_FAST_IO"},
+	{STATUS_FLT_INVALID_NAME_REQUEST, -EIO,
+	"STATUS_FLT_INVALID_NAME_REQUEST"},
+	{STATUS_FLT_NOT_SAFE_TO_POST_OPERATION, -EIO,
+	"STATUS_FLT_NOT_SAFE_TO_POST_OPERATION"},
+	{STATUS_FLT_NOT_INITIALIZED, -EIO, "STATUS_FLT_NOT_INITIALIZED"},
+	{STATUS_FLT_FILTER_NOT_READY, -EIO, "STATUS_FLT_FILTER_NOT_READY"},
+	{STATUS_FLT_POST_OPERATION_CLEANUP, -EIO,
+	"STATUS_FLT_POST_OPERATION_CLEANUP"},
+	{STATUS_FLT_INTERNAL_ERROR, -EIO, "STATUS_FLT_INTERNAL_ERROR"},
+	{STATUS_FLT_DELETING_OBJECT, -EIO, "STATUS_FLT_DELETING_OBJECT"},
+	{STATUS_FLT_MUST_BE_NONPAGED_POOL, -EIO,
+	"STATUS_FLT_MUST_BE_NONPAGED_POOL"},
+	{STATUS_FLT_DUPLICATE_ENTRY, -EIO, "STATUS_FLT_DUPLICATE_ENTRY"},
+	{STATUS_FLT_CBDQ_DISABLED, -EIO, "STATUS_FLT_CBDQ_DISABLED"},
+	{STATUS_FLT_DO_NOT_ATTACH, -EIO, "STATUS_FLT_DO_NOT_ATTACH"},
+	{STATUS_FLT_DO_NOT_DETACH, -EIO, "STATUS_FLT_DO_NOT_DETACH"},
+	{STATUS_FLT_INSTANCE_ALTITUDE_COLLISION, -EIO,
+	"STATUS_FLT_INSTANCE_ALTITUDE_COLLISION"},
+	{STATUS_FLT_INSTANCE_NAME_COLLISION, -EIO,
+	"STATUS_FLT_INSTANCE_NAME_COLLISION"},
+	{STATUS_FLT_FILTER_NOT_FOUND, -EIO, "STATUS_FLT_FILTER_NOT_FOUND"},
+	{STATUS_FLT_VOLUME_NOT_FOUND, -EIO, "STATUS_FLT_VOLUME_NOT_FOUND"},
+	{STATUS_FLT_INSTANCE_NOT_FOUND, -EIO, "STATUS_FLT_INSTANCE_NOT_FOUND"},
+	{STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND, -EIO,
+	"STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND"},
+	{STATUS_FLT_INVALID_CONTEXT_REGISTRATION, -EIO,
+	"STATUS_FLT_INVALID_CONTEXT_REGISTRATION"},
+	{STATUS_FLT_NAME_CACHE_MISS, -EIO, "STATUS_FLT_NAME_CACHE_MISS"},
+	{STATUS_FLT_NO_DEVICE_OBJECT, -EIO, "STATUS_FLT_NO_DEVICE_OBJECT"},
+	{STATUS_FLT_VOLUME_ALREADY_MOUNTED, -EIO,
+	"STATUS_FLT_VOLUME_ALREADY_MOUNTED"},
+	{STATUS_FLT_ALREADY_ENLISTED, -EIO, "STATUS_FLT_ALREADY_ENLISTED"},
+	{STATUS_FLT_CONTEXT_ALREADY_LINKED, -EIO,
+	"STATUS_FLT_CONTEXT_ALREADY_LINKED"},
+	{STATUS_FLT_NO_WAITER_FOR_REPLY, -EIO,
+	"STATUS_FLT_NO_WAITER_FOR_REPLY"},
+	{STATUS_MONITOR_NO_DESCRIPTOR, -EIO, "STATUS_MONITOR_NO_DESCRIPTOR"},
+	{STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT, -EIO,
+	"STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT"},
+	{STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM, -EIO,
+	"STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM"},
+	{STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK, -EIO,
+	"STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK"},
+	{STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED, -EIO,
+	"STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED"},
+	{STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK, -EIO,
+	"STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK"},
+	{STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK, -EIO,
+	"STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK"},
+	{STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA, -EIO,
+	"STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA"},
+	{STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK, -EIO,
+	"STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK"},
+	{STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER, -EIO,
+	"STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER"},
+	{STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER, -EIO,
+	"STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER"},
+	{STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER, -EIO,
+	"STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER"},
+	{STATUS_GRAPHICS_ADAPTER_WAS_RESET, -EIO,
+	"STATUS_GRAPHICS_ADAPTER_WAS_RESET"},
+	{STATUS_GRAPHICS_INVALID_DRIVER_MODEL, -EIO,
+	"STATUS_GRAPHICS_INVALID_DRIVER_MODEL"},
+	{STATUS_GRAPHICS_PRESENT_MODE_CHANGED, -EIO,
+	"STATUS_GRAPHICS_PRESENT_MODE_CHANGED"},
+	{STATUS_GRAPHICS_PRESENT_OCCLUDED, -EIO,
+	"STATUS_GRAPHICS_PRESENT_OCCLUDED"},
+	{STATUS_GRAPHICS_PRESENT_DENIED, -EIO,
+	"STATUS_GRAPHICS_PRESENT_DENIED"},
+	{STATUS_GRAPHICS_CANNOTCOLORCONVERT, -EIO,
+	"STATUS_GRAPHICS_CANNOTCOLORCONVERT"},
+	{STATUS_GRAPHICS_NO_VIDEO_MEMORY, -EIO,
+	"STATUS_GRAPHICS_NO_VIDEO_MEMORY"},
+	{STATUS_GRAPHICS_CANT_LOCK_MEMORY, -EIO,
+	"STATUS_GRAPHICS_CANT_LOCK_MEMORY"},
+	{STATUS_GRAPHICS_ALLOCATION_BUSY, -EBUSY,
+	"STATUS_GRAPHICS_ALLOCATION_BUSY"},
+	{STATUS_GRAPHICS_TOO_MANY_REFERENCES, -EIO,
+	"STATUS_GRAPHICS_TOO_MANY_REFERENCES"},
+	{STATUS_GRAPHICS_TRY_AGAIN_LATER, -EIO,
+	"STATUS_GRAPHICS_TRY_AGAIN_LATER"},
+	{STATUS_GRAPHICS_TRY_AGAIN_NOW, -EIO, "STATUS_GRAPHICS_TRY_AGAIN_NOW"},
+	{STATUS_GRAPHICS_ALLOCATION_INVALID, -EIO,
+	"STATUS_GRAPHICS_ALLOCATION_INVALID"},
+	{STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE, -EIO,
+	"STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE"},
+	{STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED, -EIO,
+	"STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED"},
+	{STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION, -EIO,
+	"STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION"},
+	{STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE, -EIO,
+	"STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE"},
+	{STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION, -EIO,
+	"STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION"},
+	{STATUS_GRAPHICS_ALLOCATION_CLOSED, -EIO,
+	"STATUS_GRAPHICS_ALLOCATION_CLOSED"},
+	{STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE, -EIO,
+	"STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE"},
+	{STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE, -EIO,
+	"STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE"},
+	{STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE, -EIO,
+	"STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE"},
+	{STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST, -EIO,
+	"STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST"},
+	{STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE, -EIO,
+	"STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE"},
+	{STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY"},
+	{STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_INVALID_VIDPN, -EIO, "STATUS_GRAPHICS_INVALID_VIDPN"},
+	{STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE"},
+	{STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET"},
+	{STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET"},
+	{STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET"},
+	{STATUS_GRAPHICS_INVALID_FREQUENCY, -EIO,
+	"STATUS_GRAPHICS_INVALID_FREQUENCY"},
+	{STATUS_GRAPHICS_INVALID_ACTIVE_REGION, -EIO,
+	"STATUS_GRAPHICS_INVALID_ACTIVE_REGION"},
+	{STATUS_GRAPHICS_INVALID_TOTAL_REGION, -EIO,
+	"STATUS_GRAPHICS_INVALID_TOTAL_REGION"},
+	{STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE"},
+	{STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE"},
+	{STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET, -EIO,
+	"STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET"},
+	{STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY, -EIO,
+	"STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY"},
+	{STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET, -EIO,
+	"STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET"},
+	{STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET"},
+	{STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET"},
+	{STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET, -EIO,
+	"STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET"},
+	{STATUS_GRAPHICS_TARGET_ALREADY_IN_SET, -EIO,
+	"STATUS_GRAPHICS_TARGET_ALREADY_IN_SET"},
+	{STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH"},
+	{STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY, -EIO,
+	"STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY"},
+	{STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET, -EIO,
+	"STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET"},
+	{STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE, -EIO,
+	"STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE"},
+	{STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET, -EIO,
+	"STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET"},
+	{STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET, -EIO,
+	"STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET"},
+	{STATUS_GRAPHICS_STALE_MODESET, -EIO, "STATUS_GRAPHICS_STALE_MODESET"},
+	{STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET, -EIO,
+	"STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET"},
+	{STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE, -EIO,
+	"STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE"},
+	{STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN, -EIO,
+	"STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN"},
+	{STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE, -EIO,
+	"STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE"},
+	{STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION, -EIO,
+	"STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION"},
+	{STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES, -EIO,
+	"STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES"},
+	{STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY, -EIO,
+	"STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY"},
+	{STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE, -EIO,
+	"STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE"},
+	{STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET, -EIO,
+	"STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET"},
+	{STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET, -EIO,
+	"STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET"},
+	{STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR, -EIO,
+	"STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR"},
+	{STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET, -EIO,
+	"STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET"},
+	{STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET, -EIO,
+	"STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET"},
+	{STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE, -EIO,
+	"STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE"},
+	{STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE"},
+	{STATUS_GRAPHICS_RESOURCES_NOT_RELATED, -EIO,
+	"STATUS_GRAPHICS_RESOURCES_NOT_RELATED"},
+	{STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE, -EIO,
+	"STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE"},
+	{STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE, -EIO,
+	"STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE"},
+	{STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET, -EIO,
+	"STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET"},
+	{STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER, -EIO,
+	"STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER"},
+	{STATUS_GRAPHICS_NO_VIDPNMGR, -EIO, "STATUS_GRAPHICS_NO_VIDPNMGR"},
+	{STATUS_GRAPHICS_NO_ACTIVE_VIDPN, -EIO,
+	"STATUS_GRAPHICS_NO_ACTIVE_VIDPN"},
+	{STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY, -EIO,
+	"STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY"},
+	{STATUS_GRAPHICS_MONITOR_NOT_CONNECTED, -EIO,
+	"STATUS_GRAPHICS_MONITOR_NOT_CONNECTED"},
+	{STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY, -EIO,
+	"STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY"},
+	{STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE, -EIO,
+	"STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE"},
+	{STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE, -EIO,
+	"STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE"},
+	{STATUS_GRAPHICS_INVALID_STRIDE, -EIO,
+	"STATUS_GRAPHICS_INVALID_STRIDE"},
+	{STATUS_GRAPHICS_INVALID_PIXELFORMAT, -EIO,
+	"STATUS_GRAPHICS_INVALID_PIXELFORMAT"},
+	{STATUS_GRAPHICS_INVALID_COLORBASIS, -EIO,
+	"STATUS_GRAPHICS_INVALID_COLORBASIS"},
+	{STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE, -EIO,
+	"STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE"},
+	{STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY, -EIO,
+	"STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY"},
+	{STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT, -EIO,
+	"STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT"},
+	{STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, -EIO,
+	"STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE"},
+	{STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN, -EIO,
+	"STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN"},
+	{STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL, -EIO,
+	"STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL"},
+	{STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION, -EIO,
+	"STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION"},
+	{STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED,
+	-EIO,
+	"STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_INVALID_GAMMA_RAMP, -EIO,
+	"STATUS_GRAPHICS_INVALID_GAMMA_RAMP"},
+	{STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_MODE_NOT_IN_MODESET, -EIO,
+	"STATUS_GRAPHICS_MODE_NOT_IN_MODESET"},
+	{STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON, -EIO,
+	"STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON"},
+	{STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE, -EIO,
+	"STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE"},
+	{STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE, -EIO,
+	"STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE"},
+	{STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS, -EIO,
+	"STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS"},
+	{STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING, -EIO,
+	"STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING"},
+	{STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED, -EIO,
+	"STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED"},
+	{STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS, -EIO,
+	"STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS"},
+	{STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT, -EIO,
+	"STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT"},
+	{STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM, -EIO,
+	"STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM"},
+	{STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN, -EIO,
+	"STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN"},
+	{STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT, -EIO,
+	"STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT"},
+	{STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED, -EIO,
+	"STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED"},
+	{STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION, -EIO,
+	"STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION"},
+	{STATUS_GRAPHICS_INVALID_CLIENT_TYPE, -EIO,
+	"STATUS_GRAPHICS_INVALID_CLIENT_TYPE"},
+	{STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET, -EIO,
+	"STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET"},
+	{STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED, -EIO,
+	"STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED"},
+	{STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER, -EIO,
+	"STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER"},
+	{STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED, -EIO,
+	"STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED"},
+	{STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED, -EIO,
+	"STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED"},
+	{STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY, -EIO,
+	"STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY"},
+	{STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED, -EIO,
+	"STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED"},
+	{STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON, -EIO,
+	"STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON"},
+	{STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE, -EIO,
+	"STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE"},
+	{STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER, -EIO,
+	"STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER"},
+	{STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED, -EIO,
+	"STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED"},
+	{STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS,
+	-EIO,
+	"STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS"},
+	{STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST, -EIO,
+	"STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST"},
+	{STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR, -EIO,
+	"STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR"},
+	{STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS, -EIO,
+	"STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS"},
+	{STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST, -EIO,
+	"STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST"},
+	{STATUS_GRAPHICS_OPM_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_OPM_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_COPP_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_COPP_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_UAB_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_UAB_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS, -EIO,
+	"STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS"},
+	{STATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL, -EIO,
+	"STATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL"},
+	{STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST, -EIO,
+	"STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST"},
+	{STATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME, -EIO,
+	"STATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME"},
+	{STATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP, -EIO,
+	"STATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP"},
+	{STATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_OPM_INVALID_POINTER, -EIO,
+	"STATUS_GRAPHICS_OPM_INVALID_POINTER"},
+	{STATUS_GRAPHICS_OPM_INTERNAL_ERROR, -EIO,
+	"STATUS_GRAPHICS_OPM_INTERNAL_ERROR"},
+	{STATUS_GRAPHICS_OPM_INVALID_HANDLE, -EIO,
+	"STATUS_GRAPHICS_OPM_INVALID_HANDLE"},
+	{STATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE, -EIO,
+	"STATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE"},
+	{STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH, -EIO,
+	"STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH"},
+	{STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED, -EIO,
+	"STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED"},
+	{STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED, -EIO,
+	"STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED"},
+	{STATUS_GRAPHICS_PVP_HFS_FAILED, -EIO,
+	"STATUS_GRAPHICS_PVP_HFS_FAILED"},
+	{STATUS_GRAPHICS_OPM_INVALID_SRM, -EIO,
+	"STATUS_GRAPHICS_OPM_INVALID_SRM"},
+	{STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP, -EIO,
+	"STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP"},
+	{STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP, -EIO,
+	"STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP"},
+	{STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA, -EIO,
+	"STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA"},
+	{STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET, -EIO,
+	"STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET"},
+	{STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH, -EIO,
+	"STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH"},
+	{STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE, -EIO,
+	"STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE"},
+	{STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS, -EIO,
+	"STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS"},
+	{STATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS, -EIO,
+	"STATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS"},
+	{STATUS_GRAPHICS_I2C_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_I2C_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST, -EIO,
+	"STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST"},
+	{STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA, -EIO,
+	"STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA"},
+	{STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA, -EIO,
+	"STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA"},
+	{STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_DDCCI_INVALID_DATA, -EIO,
+	"STATUS_GRAPHICS_DDCCI_INVALID_DATA"},
+	{STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE,
+	-EIO,
+	"STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE"},
+	{STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING, -EIO,
+	"STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING"},
+	{STATUS_GRAPHICS_MCA_INTERNAL_ERROR, -EIO,
+	"STATUS_GRAPHICS_MCA_INTERNAL_ERROR"},
+	{STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND, -EIO,
+	"STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND"},
+	{STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH, -EIO,
+	"STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH"},
+	{STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM, -EIO,
+	"STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM"},
+	{STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE, -EIO,
+	"STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE"},
+	{STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS, -EIO,
+	"STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS"},
+	{STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED"},
+	{STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME, -EIO,
+	"STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME"},
+	{STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP, -EIO,
+	"STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP"},
+	{STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED, -EIO,
+	"STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED"},
+	{STATUS_GRAPHICS_INVALID_POINTER, -EIO,
+	"STATUS_GRAPHICS_INVALID_POINTER"},
+	{STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE, -EIO,
+	"STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE"},
+	{STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL, -EIO,
+	"STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL"},
+	{STATUS_GRAPHICS_INTERNAL_ERROR, -EIO,
+	"STATUS_GRAPHICS_INTERNAL_ERROR"},
+	{STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS, -EIO,
+	"STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS"},
+	{STATUS_FVE_LOCKED_VOLUME, -EIO, "STATUS_FVE_LOCKED_VOLUME"},
+	{STATUS_FVE_NOT_ENCRYPTED, -EIO, "STATUS_FVE_NOT_ENCRYPTED"},
+	{STATUS_FVE_BAD_INFORMATION, -EIO, "STATUS_FVE_BAD_INFORMATION"},
+	{STATUS_FVE_TOO_SMALL, -EIO, "STATUS_FVE_TOO_SMALL"},
+	{STATUS_FVE_FAILED_WRONG_FS, -EIO, "STATUS_FVE_FAILED_WRONG_FS"},
+	{STATUS_FVE_FAILED_BAD_FS, -EIO, "STATUS_FVE_FAILED_BAD_FS"},
+	{STATUS_FVE_FS_NOT_EXTENDED, -EIO, "STATUS_FVE_FS_NOT_EXTENDED"},
+	{STATUS_FVE_FS_MOUNTED, -EIO, "STATUS_FVE_FS_MOUNTED"},
+	{STATUS_FVE_NO_LICENSE, -EIO, "STATUS_FVE_NO_LICENSE"},
+	{STATUS_FVE_ACTION_NOT_ALLOWED, -EIO, "STATUS_FVE_ACTION_NOT_ALLOWED"},
+	{STATUS_FVE_BAD_DATA, -EIO, "STATUS_FVE_BAD_DATA"},
+	{STATUS_FVE_VOLUME_NOT_BOUND, -EIO, "STATUS_FVE_VOLUME_NOT_BOUND"},
+	{STATUS_FVE_NOT_DATA_VOLUME, -EIO, "STATUS_FVE_NOT_DATA_VOLUME"},
+	{STATUS_FVE_CONV_READ_ERROR, -EIO, "STATUS_FVE_CONV_READ_ERROR"},
+	{STATUS_FVE_CONV_WRITE_ERROR, -EIO, "STATUS_FVE_CONV_WRITE_ERROR"},
+	{STATUS_FVE_OVERLAPPED_UPDATE, -EIO, "STATUS_FVE_OVERLAPPED_UPDATE"},
+	{STATUS_FVE_FAILED_SECTOR_SIZE, -EIO, "STATUS_FVE_FAILED_SECTOR_SIZE"},
+	{STATUS_FVE_FAILED_AUTHENTICATION, -EIO,
+	"STATUS_FVE_FAILED_AUTHENTICATION"},
+	{STATUS_FVE_NOT_OS_VOLUME, -EIO, "STATUS_FVE_NOT_OS_VOLUME"},
+	{STATUS_FVE_KEYFILE_NOT_FOUND, -EIO, "STATUS_FVE_KEYFILE_NOT_FOUND"},
+	{STATUS_FVE_KEYFILE_INVALID, -EIO, "STATUS_FVE_KEYFILE_INVALID"},
+	{STATUS_FVE_KEYFILE_NO_VMK, -EIO, "STATUS_FVE_KEYFILE_NO_VMK"},
+	{STATUS_FVE_TPM_DISABLED, -EIO, "STATUS_FVE_TPM_DISABLED"},
+	{STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO, -EIO,
+	"STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO"},
+	{STATUS_FVE_TPM_INVALID_PCR, -EIO, "STATUS_FVE_TPM_INVALID_PCR"},
+	{STATUS_FVE_TPM_NO_VMK, -EIO, "STATUS_FVE_TPM_NO_VMK"},
+	{STATUS_FVE_PIN_INVALID, -EIO, "STATUS_FVE_PIN_INVALID"},
+	{STATUS_FVE_AUTH_INVALID_APPLICATION, -EIO,
+	"STATUS_FVE_AUTH_INVALID_APPLICATION"},
+	{STATUS_FVE_AUTH_INVALID_CONFIG, -EIO,
+	"STATUS_FVE_AUTH_INVALID_CONFIG"},
+	{STATUS_FVE_DEBUGGER_ENABLED, -EIO, "STATUS_FVE_DEBUGGER_ENABLED"},
+	{STATUS_FVE_DRY_RUN_FAILED, -EIO, "STATUS_FVE_DRY_RUN_FAILED"},
+	{STATUS_FVE_BAD_METADATA_POINTER, -EIO,
+	"STATUS_FVE_BAD_METADATA_POINTER"},
+	{STATUS_FVE_OLD_METADATA_COPY, -EIO, "STATUS_FVE_OLD_METADATA_COPY"},
+	{STATUS_FVE_REBOOT_REQUIRED, -EIO, "STATUS_FVE_REBOOT_REQUIRED"},
+	{STATUS_FVE_RAW_ACCESS, -EIO, "STATUS_FVE_RAW_ACCESS"},
+	{STATUS_FVE_RAW_BLOCKED, -EIO, "STATUS_FVE_RAW_BLOCKED"},
+	{STATUS_FWP_CALLOUT_NOT_FOUND, -EIO, "STATUS_FWP_CALLOUT_NOT_FOUND"},
+	{STATUS_FWP_CONDITION_NOT_FOUND, -EIO,
+	"STATUS_FWP_CONDITION_NOT_FOUND"},
+	{STATUS_FWP_FILTER_NOT_FOUND, -EIO, "STATUS_FWP_FILTER_NOT_FOUND"},
+	{STATUS_FWP_LAYER_NOT_FOUND, -EIO, "STATUS_FWP_LAYER_NOT_FOUND"},
+	{STATUS_FWP_PROVIDER_NOT_FOUND, -EIO, "STATUS_FWP_PROVIDER_NOT_FOUND"},
+	{STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND, -EIO,
+	"STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND"},
+	{STATUS_FWP_SUBLAYER_NOT_FOUND, -EIO, "STATUS_FWP_SUBLAYER_NOT_FOUND"},
+	{STATUS_FWP_NOT_FOUND, -EIO, "STATUS_FWP_NOT_FOUND"},
+	{STATUS_FWP_ALREADY_EXISTS, -EIO, "STATUS_FWP_ALREADY_EXISTS"},
+	{STATUS_FWP_IN_USE, -EIO, "STATUS_FWP_IN_USE"},
+	{STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS, -EIO,
+	"STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS"},
+	{STATUS_FWP_WRONG_SESSION, -EIO, "STATUS_FWP_WRONG_SESSION"},
+	{STATUS_FWP_NO_TXN_IN_PROGRESS, -EIO, "STATUS_FWP_NO_TXN_IN_PROGRESS"},
+	{STATUS_FWP_TXN_IN_PROGRESS, -EIO, "STATUS_FWP_TXN_IN_PROGRESS"},
+	{STATUS_FWP_TXN_ABORTED, -EIO, "STATUS_FWP_TXN_ABORTED"},
+	{STATUS_FWP_SESSION_ABORTED, -EIO, "STATUS_FWP_SESSION_ABORTED"},
+	{STATUS_FWP_INCOMPATIBLE_TXN, -EIO, "STATUS_FWP_INCOMPATIBLE_TXN"},
+	{STATUS_FWP_TIMEOUT, -ETIMEDOUT, "STATUS_FWP_TIMEOUT"},
+	{STATUS_FWP_NET_EVENTS_DISABLED, -EIO,
+	"STATUS_FWP_NET_EVENTS_DISABLED"},
+	{STATUS_FWP_INCOMPATIBLE_LAYER, -EIO, "STATUS_FWP_INCOMPATIBLE_LAYER"},
+	{STATUS_FWP_KM_CLIENTS_ONLY, -EIO, "STATUS_FWP_KM_CLIENTS_ONLY"},
+	{STATUS_FWP_LIFETIME_MISMATCH, -EIO, "STATUS_FWP_LIFETIME_MISMATCH"},
+	{STATUS_FWP_BUILTIN_OBJECT, -EIO, "STATUS_FWP_BUILTIN_OBJECT"},
+	{STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS, -EIO,
+	"STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS"},
+	{STATUS_FWP_TOO_MANY_CALLOUTS, -EIO, "STATUS_FWP_TOO_MANY_CALLOUTS"},
+	{STATUS_FWP_NOTIFICATION_DROPPED, -EIO,
+	"STATUS_FWP_NOTIFICATION_DROPPED"},
+	{STATUS_FWP_TRAFFIC_MISMATCH, -EIO, "STATUS_FWP_TRAFFIC_MISMATCH"},
+	{STATUS_FWP_INCOMPATIBLE_SA_STATE, -EIO,
+	"STATUS_FWP_INCOMPATIBLE_SA_STATE"},
+	{STATUS_FWP_NULL_POINTER, -EIO, "STATUS_FWP_NULL_POINTER"},
+	{STATUS_FWP_INVALID_ENUMERATOR, -EIO, "STATUS_FWP_INVALID_ENUMERATOR"},
+	{STATUS_FWP_INVALID_FLAGS, -EIO, "STATUS_FWP_INVALID_FLAGS"},
+	{STATUS_FWP_INVALID_NET_MASK, -EIO, "STATUS_FWP_INVALID_NET_MASK"},
+	{STATUS_FWP_INVALID_RANGE, -EIO, "STATUS_FWP_INVALID_RANGE"},
+	{STATUS_FWP_INVALID_INTERVAL, -EIO, "STATUS_FWP_INVALID_INTERVAL"},
+	{STATUS_FWP_ZERO_LENGTH_ARRAY, -EIO, "STATUS_FWP_ZERO_LENGTH_ARRAY"},
+	{STATUS_FWP_NULL_DISPLAY_NAME, -EIO, "STATUS_FWP_NULL_DISPLAY_NAME"},
+	{STATUS_FWP_INVALID_ACTION_TYPE, -EIO,
+	"STATUS_FWP_INVALID_ACTION_TYPE"},
+	{STATUS_FWP_INVALID_WEIGHT, -EIO, "STATUS_FWP_INVALID_WEIGHT"},
+	{STATUS_FWP_MATCH_TYPE_MISMATCH, -EIO,
+	"STATUS_FWP_MATCH_TYPE_MISMATCH"},
+	{STATUS_FWP_TYPE_MISMATCH, -EIO, "STATUS_FWP_TYPE_MISMATCH"},
+	{STATUS_FWP_OUT_OF_BOUNDS, -EIO, "STATUS_FWP_OUT_OF_BOUNDS"},
+	{STATUS_FWP_RESERVED, -EIO, "STATUS_FWP_RESERVED"},
+	{STATUS_FWP_DUPLICATE_CONDITION, -EIO,
+	"STATUS_FWP_DUPLICATE_CONDITION"},
+	{STATUS_FWP_DUPLICATE_KEYMOD, -EIO, "STATUS_FWP_DUPLICATE_KEYMOD"},
+	{STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER, -EIO,
+	"STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER"},
+	{STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER, -EIO,
+	"STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER"},
+	{STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER, -EIO,
+	"STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER"},
+	{STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT, -EIO,
+	"STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT"},
+	{STATUS_FWP_INCOMPATIBLE_AUTH_METHOD, -EIO,
+	"STATUS_FWP_INCOMPATIBLE_AUTH_METHOD"},
+	{STATUS_FWP_INCOMPATIBLE_DH_GROUP, -EIO,
+	"STATUS_FWP_INCOMPATIBLE_DH_GROUP"},
+	{STATUS_FWP_EM_NOT_SUPPORTED, -EOPNOTSUPP,
+	"STATUS_FWP_EM_NOT_SUPPORTED"},
+	{STATUS_FWP_NEVER_MATCH, -EIO, "STATUS_FWP_NEVER_MATCH"},
+	{STATUS_FWP_PROVIDER_CONTEXT_MISMATCH, -EIO,
+	"STATUS_FWP_PROVIDER_CONTEXT_MISMATCH"},
+	{STATUS_FWP_INVALID_PARAMETER, -EIO, "STATUS_FWP_INVALID_PARAMETER"},
+	{STATUS_FWP_TOO_MANY_SUBLAYERS, -EIO, "STATUS_FWP_TOO_MANY_SUBLAYERS"},
+	{STATUS_FWP_CALLOUT_NOTIFICATION_FAILED, -EIO,
+	"STATUS_FWP_CALLOUT_NOTIFICATION_FAILED"},
+	{STATUS_FWP_INCOMPATIBLE_AUTH_CONFIG, -EIO,
+	"STATUS_FWP_INCOMPATIBLE_AUTH_CONFIG"},
+	{STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG, -EIO,
+	"STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG"},
+	{STATUS_FWP_TCPIP_NOT_READY, -EIO, "STATUS_FWP_TCPIP_NOT_READY"},
+	{STATUS_FWP_INJECT_HANDLE_CLOSING, -EIO,
+	"STATUS_FWP_INJECT_HANDLE_CLOSING"},
+	{STATUS_FWP_INJECT_HANDLE_STALE, -EIO,
+	"STATUS_FWP_INJECT_HANDLE_STALE"},
+	{STATUS_FWP_CANNOT_PEND, -EIO, "STATUS_FWP_CANNOT_PEND"},
+	{STATUS_NDIS_CLOSING, -EIO, "STATUS_NDIS_CLOSING"},
+	{STATUS_NDIS_BAD_VERSION, -EIO, "STATUS_NDIS_BAD_VERSION"},
+	{STATUS_NDIS_BAD_CHARACTERISTICS, -EIO,
+	"STATUS_NDIS_BAD_CHARACTERISTICS"},
+	{STATUS_NDIS_ADAPTER_NOT_FOUND, -EIO, "STATUS_NDIS_ADAPTER_NOT_FOUND"},
+	{STATUS_NDIS_OPEN_FAILED, -EIO, "STATUS_NDIS_OPEN_FAILED"},
+	{STATUS_NDIS_DEVICE_FAILED, -EIO, "STATUS_NDIS_DEVICE_FAILED"},
+	{STATUS_NDIS_MULTICAST_FULL, -EIO, "STATUS_NDIS_MULTICAST_FULL"},
+	{STATUS_NDIS_MULTICAST_EXISTS, -EIO, "STATUS_NDIS_MULTICAST_EXISTS"},
+	{STATUS_NDIS_MULTICAST_NOT_FOUND, -EIO,
+	"STATUS_NDIS_MULTICAST_NOT_FOUND"},
+	{STATUS_NDIS_REQUEST_ABORTED, -EIO, "STATUS_NDIS_REQUEST_ABORTED"},
+	{STATUS_NDIS_RESET_IN_PROGRESS, -EIO, "STATUS_NDIS_RESET_IN_PROGRESS"},
+	{STATUS_NDIS_INVALID_PACKET, -EIO, "STATUS_NDIS_INVALID_PACKET"},
+	{STATUS_NDIS_INVALID_DEVICE_REQUEST, -EIO,
+	"STATUS_NDIS_INVALID_DEVICE_REQUEST"},
+	{STATUS_NDIS_ADAPTER_NOT_READY, -EIO, "STATUS_NDIS_ADAPTER_NOT_READY"},
+	{STATUS_NDIS_INVALID_LENGTH, -EIO, "STATUS_NDIS_INVALID_LENGTH"},
+	{STATUS_NDIS_INVALID_DATA, -EIO, "STATUS_NDIS_INVALID_DATA"},
+	{STATUS_NDIS_BUFFER_TOO_SHORT, -ENOBUFS,
+	"STATUS_NDIS_BUFFER_TOO_SHORT"},
+	{STATUS_NDIS_INVALID_OID, -EIO, "STATUS_NDIS_INVALID_OID"},
+	{STATUS_NDIS_ADAPTER_REMOVED, -EIO, "STATUS_NDIS_ADAPTER_REMOVED"},
+	{STATUS_NDIS_UNSUPPORTED_MEDIA, -EIO, "STATUS_NDIS_UNSUPPORTED_MEDIA"},
+	{STATUS_NDIS_GROUP_ADDRESS_IN_USE, -EIO,
+	"STATUS_NDIS_GROUP_ADDRESS_IN_USE"},
+	{STATUS_NDIS_FILE_NOT_FOUND, -EIO, "STATUS_NDIS_FILE_NOT_FOUND"},
+	{STATUS_NDIS_ERROR_READING_FILE, -EIO,
+	"STATUS_NDIS_ERROR_READING_FILE"},
+	{STATUS_NDIS_ALREADY_MAPPED, -EIO, "STATUS_NDIS_ALREADY_MAPPED"},
+	{STATUS_NDIS_RESOURCE_CONFLICT, -EIO, "STATUS_NDIS_RESOURCE_CONFLICT"},
+	{STATUS_NDIS_MEDIA_DISCONNECTED, -EIO,
+	"STATUS_NDIS_MEDIA_DISCONNECTED"},
+	{STATUS_NDIS_INVALID_ADDRESS, -EIO, "STATUS_NDIS_INVALID_ADDRESS"},
+	{STATUS_NDIS_PAUSED, -EIO, "STATUS_NDIS_PAUSED"},
+	{STATUS_NDIS_INTERFACE_NOT_FOUND, -EIO,
+	"STATUS_NDIS_INTERFACE_NOT_FOUND"},
+	{STATUS_NDIS_UNSUPPORTED_REVISION, -EIO,
+	"STATUS_NDIS_UNSUPPORTED_REVISION"},
+	{STATUS_NDIS_INVALID_PORT, -EIO, "STATUS_NDIS_INVALID_PORT"},
+	{STATUS_NDIS_INVALID_PORT_STATE, -EIO,
+	"STATUS_NDIS_INVALID_PORT_STATE"},
+	{STATUS_NDIS_LOW_POWER_STATE, -EIO, "STATUS_NDIS_LOW_POWER_STATE"},
+	{STATUS_NDIS_NOT_SUPPORTED, -ENOSYS, "STATUS_NDIS_NOT_SUPPORTED"},
+	{STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED, -EIO,
+	"STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED"},
+	{STATUS_NDIS_DOT11_MEDIA_IN_USE, -EIO,
+	"STATUS_NDIS_DOT11_MEDIA_IN_USE"},
+	{STATUS_NDIS_DOT11_POWER_STATE_INVALID, -EIO,
+	"STATUS_NDIS_DOT11_POWER_STATE_INVALID"},
+	{STATUS_IPSEC_BAD_SPI, -EIO, "STATUS_IPSEC_BAD_SPI"},
+	{STATUS_IPSEC_SA_LIFETIME_EXPIRED, -EIO,
+	"STATUS_IPSEC_SA_LIFETIME_EXPIRED"},
+	{STATUS_IPSEC_WRONG_SA, -EIO, "STATUS_IPSEC_WRONG_SA"},
+	{STATUS_IPSEC_REPLAY_CHECK_FAILED, -EIO,
+	"STATUS_IPSEC_REPLAY_CHECK_FAILED"},
+	{STATUS_IPSEC_INVALID_PACKET, -EIO, "STATUS_IPSEC_INVALID_PACKET"},
+	{STATUS_IPSEC_INTEGRITY_CHECK_FAILED, -EIO,
+	"STATUS_IPSEC_INTEGRITY_CHECK_FAILED"},
+	{STATUS_IPSEC_CLEAR_TEXT_DROP, -EIO, "STATUS_IPSEC_CLEAR_TEXT_DROP"},
+	{0, 0, NULL}
+};
+
+/*****************************************************************************
+ Print an error message from the status code
+ *****************************************************************************/
+static void
+smb2_print_status(__u32 status)
+{
+	int idx = 0;
+
+	while (smb2_error_map_table[idx].status_string != NULL) {
+		if ((smb2_error_map_table[idx].smb2_status) == status) {
+			pr_notice("Status code returned 0x%08x %s\n", status,
+				  smb2_error_map_table[idx].status_string);
+		}
+		idx++;
+	}
+	return;
+}
+
+int
+map_smb2_to_linux_error(char *buf, bool log_err)
+{
+	struct smb2_hdr *smb = (struct smb2_hdr *)buf;
+	unsigned int i;
+	int rc = -EIO;
+	__u32 smb2err;
+
+	if (smb->Status == 0)
+		return 0;
+
+	smb2err = le32_to_cpu(smb->Status);
+	/* mask facility */
+	if (log_err && (smb2err != (STATUS_MORE_PROCESSING_REQUIRED)))
+		smb2_print_status(smb2err);
+	else if (cifsFYI & CIFS_RC)
+		smb2_print_status(smb2err);
+
+	for (i = 0; i < sizeof(smb2_error_map_table) /
+			sizeof(struct status_to_posix_error); i++) {
+		if (smb2_error_map_table[i].smb2_status == smb2err) {
+			rc = smb2_error_map_table[i].posix_error;
+			break;
+		}
+	}
+
+	/* on error mapping not found  - return EIO */
+
+	cFYI(1, "Mapping SMB2 status code %d to POSIX err %d",
+		 smb2err, rc);
+
+	return rc;
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index f065e89..fa1ce55 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -18,10 +18,104 @@
  */
 
 #include "cifsglob.h"
+#include "smb2pdu.h"
+#include "smb2proto.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+
+static void
+change_conf(struct TCP_Server_Info *server)
+{
+	server->credits += server->echo_credits + server->oplock_credits;
+	server->oplock_credits = server->echo_credits = 0;
+	switch (server->credits) {
+	case 0:
+		cifs_reconnect(server);
+		return;
+	case 1:
+		server->echoes = false;
+		server->oplocks = false;
+		cERROR(1, "disabling echoes and oplocks");
+		break;
+	case 2:
+		server->echoes = true;
+		server->oplocks = false;
+		server->echo_credits = 1;
+		cFYI(1, "disabling oplocks");
+		break;
+	default:
+		server->echoes = true;
+		server->oplocks = true;
+		server->echo_credits = 1;
+		server->oplock_credits = 1;
+	}
+	server->credits -= server->echo_credits + server->oplock_credits;
+}
+
+static void
+smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
+		 const int optype)
+{
+	int *val;
+	spin_lock(&server->req_lock);
+	val = server->ops->get_credits_field(server, optype);
+	*val += add;
+	server->in_flight--;
+	if (server->in_flight == 0)
+		change_conf(server);
+	spin_unlock(&server->req_lock);
+	wake_up(&server->request_q);
+}
+
+static void
+smb2_set_credits(struct TCP_Server_Info *server, const int val)
+{
+	spin_lock(&server->req_lock);
+	server->credits = val;
+	spin_unlock(&server->req_lock);
+}
+
+static int *
+smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
+{
+	switch (optype) {
+	case CIFS_ECHO_OP:
+		return &server->echo_credits;
+	case CIFS_OBREAK_OP:
+		return &server->oplock_credits;
+	default:
+		return &server->credits;
+	}
+}
+
+static unsigned int
+smb2_get_credits(struct mid_q_entry *mid)
+{
+	return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest);
+}
+
+static __u64
+smb2_get_next_mid(struct TCP_Server_Info *server)
+{
+	__u64 mid;
+	/* for SMB2 we need the current value */
+	spin_lock(&GlobalMid_Lock);
+	mid = server->CurrentMid++;
+	spin_unlock(&GlobalMid_Lock);
+	return mid;
+}
 
 struct smb_version_operations smb21_operations = {
+	.setup_request = smb2_setup_request,
+	.check_receive = smb2_check_receive,
+	.add_credits = smb2_add_credits,
+	.set_credits = smb2_set_credits,
+	.get_credits_field = smb2_get_credits_field,
+	.get_credits = smb2_get_credits,
+	.get_next_mid = smb2_get_next_mid,
 };
 
 struct smb_version_values smb21_values = {
 	.version_string = SMB21_VERSION_STRING,
+	.lock_cmd = SMB2_LOCK,
 };
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
new file mode 100644
index 0000000..c7f52e3
--- /dev/null
+++ b/fs/cifs/smb2pdu.h
@@ -0,0 +1,115 @@
+/*
+ *   fs/cifs/smb2pdu.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2009, 2010
+ *                 Etersoft, 2012
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *              Pavel Shilovsky (pshilovsky@samba.org) 2012
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _SMB2PDU_H
+#define _SMB2PDU_H
+
+#include <net/sock.h>
+
+/*
+ * Note that, due to trying to use names similar to the protocol specifications,
+ * there are many mixed case field names in the structures below.  Although
+ * this does not match typical Linux kernel style, it is necessary to be
+ * be able to match against the protocol specfication.
+ *
+ * SMB2 commands
+ * Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
+ * (ie no useful data other than the SMB error code itself) and are marked such.
+ * Knowing this helps avoid response buffer allocations and copy in some cases.
+ */
+
+/* List of commands in host endian */
+#define SMB2_NEGOTIATE_HE	0x0000
+#define SMB2_SESSION_SETUP_HE	0x0001
+#define SMB2_LOGOFF_HE		0x0002 /* trivial request/resp */
+#define SMB2_TREE_CONNECT_HE	0x0003
+#define SMB2_TREE_DISCONNECT_HE	0x0004 /* trivial req/resp */
+#define SMB2_CREATE_HE		0x0005
+#define SMB2_CLOSE_HE		0x0006
+#define SMB2_FLUSH_HE		0x0007 /* trivial resp */
+#define SMB2_READ_HE		0x0008
+#define SMB2_WRITE_HE		0x0009
+#define SMB2_LOCK_HE		0x000A
+#define SMB2_IOCTL_HE		0x000B
+#define SMB2_CANCEL_HE		0x000C
+#define SMB2_ECHO_HE		0x000D
+#define SMB2_QUERY_DIRECTORY_HE	0x000E
+#define SMB2_CHANGE_NOTIFY_HE	0x000F
+#define SMB2_QUERY_INFO_HE	0x0010
+#define SMB2_SET_INFO_HE	0x0011
+#define SMB2_OPLOCK_BREAK_HE	0x0012
+
+/* The same list in little endian */
+#define SMB2_NEGOTIATE		cpu_to_le16(SMB2_NEGOTIATE_HE)
+#define SMB2_SESSION_SETUP	cpu_to_le16(SMB2_SESSION_SETUP_HE)
+#define SMB2_LOGOFF		cpu_to_le16(SMB2_LOGOFF_HE)
+#define SMB2_TREE_CONNECT	cpu_to_le16(SMB2_TREE_CONNECT_HE)
+#define SMB2_TREE_DISCONNECT	cpu_to_le16(SMB2_TREE_DISCONNECT_HE)
+#define SMB2_CREATE		cpu_to_le16(SMB2_CREATE_HE)
+#define SMB2_CLOSE		cpu_to_le16(SMB2_CLOSE_HE)
+#define SMB2_FLUSH		cpu_to_le16(SMB2_FLUSH_HE)
+#define SMB2_READ		cpu_to_le16(SMB2_READ_HE)
+#define SMB2_WRITE		cpu_to_le16(SMB2_WRITE_HE)
+#define SMB2_LOCK		cpu_to_le16(SMB2_LOCK_HE)
+#define SMB2_IOCTL		cpu_to_le16(SMB2_IOCTL_HE)
+#define SMB2_CANCEL		cpu_to_le16(SMB2_CANCEL_HE)
+#define SMB2_ECHO		cpu_to_le16(SMB2_ECHO_HE)
+#define SMB2_QUERY_DIRECTORY	cpu_to_le16(SMB2_QUERY_DIRECTORY_HE)
+#define SMB2_CHANGE_NOTIFY	cpu_to_le16(SMB2_CHANGE_NOTIFY_HE)
+#define SMB2_QUERY_INFO		cpu_to_le16(SMB2_QUERY_INFO_HE)
+#define SMB2_SET_INFO		cpu_to_le16(SMB2_SET_INFO_HE)
+#define SMB2_OPLOCK_BREAK	cpu_to_le16(SMB2_OPLOCK_BREAK_HE)
+
+#define NUMBER_OF_SMB2_COMMANDS	0x0013
+
+/* BB FIXME - analyze following length BB */
+#define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */
+
+/*
+ * SMB2 Header Definition
+ *
+ * "MBZ" :  Must be Zero
+ * "BB"  :  BugBug, Something to check/review/analyze later
+ * "PDU" :  "Protocol Data Unit" (ie a network "frame")
+ *
+ */
+struct smb2_hdr {
+	__be32 smb2_buf_length;	/* big endian on wire */
+				/* length is only two or three bytes - with
+				 one or two byte type preceding it that MBZ */
+	__u8   ProtocolId[4];	/* 0xFE 'S' 'M' 'B' */
+	__le16 StructureSize;	/* 64 */
+	__le16 CreditCharge;	/* MBZ */
+	__le32 Status;		/* Error from server */
+	__le16 Command;
+	__le16 CreditRequest;  /* CreditResponse */
+	__le32 Flags;
+	__le32 NextCommand;
+	__u64  MessageId;	/* opaque - so can stay little endian */
+	__le32 ProcessId;
+	__u32  TreeId;		/* opaque - so do not make little endian */
+	__u64  SessionId;	/* opaque - so do not make little endian */
+	__u8   Signature[16];
+} __packed;
+
+#endif				/* _SMB2PDU_H */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
new file mode 100644
index 0000000..0e59afb
--- /dev/null
+++ b/fs/cifs/smb2proto.h
@@ -0,0 +1,42 @@
+/*
+ *   fs/cifs/smb2proto.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002, 2011
+ *                 Etersoft, 2012
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *              Pavel Shilovsky (pshilovsky@samba.org) 2012
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _SMB2PROTO_H
+#define _SMB2PROTO_H
+#include <linux/nls.h>
+#include <linux/key-type.h>
+
+struct statfs;
+
+/*
+ *****************************************************************
+ * All Prototypes
+ *****************************************************************
+ */
+extern int map_smb2_to_linux_error(char *buf, bool log_err);
+
+extern int smb2_check_receive(struct mid_q_entry *mid,
+			      struct TCP_Server_Info *server, bool log_error);
+extern int smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
+			      unsigned int nvec, struct mid_q_entry **ret_mid);
+
+#endif			/* _SMB2PROTO_H */
diff --git a/fs/cifs/smb2status.h b/fs/cifs/smb2status.h
new file mode 100644
index 0000000..3e98714
--- /dev/null
+++ b/fs/cifs/smb2status.h
@@ -0,0 +1,1782 @@
+/*
+ *   fs/cifs/smb2status.h
+ *
+ *   SMB2 Status code (network error) definitions
+ *   Definitions are from MS-ERREF
+ *
+ *   Copyright (c) International Business Machines  Corp., 2009,2011
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ *  0 1 2 3 4 5 6 7 8 9 0 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ *  SEV C N <-------Facility--------> <------Error Status Code------>
+ *
+ *  C is set if "customer defined" error, N bit is reserved and MBZ
+ */
+
+#define STATUS_SEVERITY_SUCCESS       cpu_to_le32 0x0000
+#define STATUS_SEVERITY_INFORMATIONAL cpu_to_le32 0x0001
+#define STATUS_SEVERITY_WARNING       cpu_to_le32 0x0002
+#define STATUS_SEVERITY_ERROR         cpu_to_le32 0x0003
+
+struct ntstatus {
+	/* Facility is the high 12 bits of the following field */
+	__le32 Facility; /* low 2 bits Severity, next is Customer, then rsrvd */
+	__le32 Code;
+};
+
+#define STATUS_SUCCESS 0x00000000
+#define STATUS_WAIT_0 0x00000000
+#define STATUS_WAIT_1 0x00000001
+#define STATUS_WAIT_2 0x00000002
+#define STATUS_WAIT_3 0x00000003
+#define STATUS_WAIT_63 0x0000003F
+#define STATUS_ABANDONED 0x00000080
+#define STATUS_ABANDONED_WAIT_0 0x00000080
+#define STATUS_ABANDONED_WAIT_63 0x000000BF
+#define STATUS_USER_APC 0x000000C0
+#define STATUS_KERNEL_APC 0x00000100
+#define STATUS_ALERTED 0x00000101
+#define STATUS_TIMEOUT 0x00000102
+#define STATUS_PENDING 0x00000103
+#define STATUS_REPARSE 0x00000104
+#define STATUS_MORE_ENTRIES 0x00000105
+#define STATUS_NOT_ALL_ASSIGNED 0x00000106
+#define STATUS_SOME_NOT_MAPPED 0x00000107
+#define STATUS_OPLOCK_BREAK_IN_PROGRESS 0x00000108
+#define STATUS_VOLUME_MOUNTED 0x00000109
+#define STATUS_RXACT_COMMITTED 0x0000010A
+#define STATUS_NOTIFY_CLEANUP 0x0000010B
+#define STATUS_NOTIFY_ENUM_DIR 0x0000010C
+#define STATUS_NO_QUOTAS_FOR_ACCOUNT 0x0000010D
+#define STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED 0x0000010E
+#define STATUS_PAGE_FAULT_TRANSITION 0x00000110
+#define STATUS_PAGE_FAULT_DEMAND_ZERO 0x00000111
+#define STATUS_PAGE_FAULT_COPY_ON_WRITE 0x00000112
+#define STATUS_PAGE_FAULT_GUARD_PAGE 0x00000113
+#define STATUS_PAGE_FAULT_PAGING_FILE 0x00000114
+#define STATUS_CACHE_PAGE_LOCKED 0x00000115
+#define STATUS_CRASH_DUMP 0x00000116
+#define STATUS_BUFFER_ALL_ZEROS 0x00000117
+#define STATUS_REPARSE_OBJECT 0x00000118
+#define STATUS_RESOURCE_REQUIREMENTS_CHANGED 0x00000119
+#define STATUS_TRANSLATION_COMPLETE 0x00000120
+#define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY 0x00000121
+#define STATUS_NOTHING_TO_TERMINATE 0x00000122
+#define STATUS_PROCESS_NOT_IN_JOB 0x00000123
+#define STATUS_PROCESS_IN_JOB 0x00000124
+#define STATUS_VOLSNAP_HIBERNATE_READY 0x00000125
+#define STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY 0x00000126
+#define STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED 0x00000127
+#define STATUS_INTERRUPT_STILL_CONNECTED 0x00000128
+#define STATUS_PROCESS_CLONED 0x00000129
+#define STATUS_FILE_LOCKED_WITH_ONLY_READERS 0x0000012A
+#define STATUS_FILE_LOCKED_WITH_WRITERS 0x0000012B
+#define STATUS_RESOURCEMANAGER_READ_ONLY 0x00000202
+#define STATUS_WAIT_FOR_OPLOCK 0x00000367
+#define DBG_EXCEPTION_HANDLED 0x00010001
+#define DBG_CONTINUE 0x00010002
+#define STATUS_FLT_IO_COMPLETE 0x001C0001
+#define STATUS_OBJECT_NAME_EXISTS 0x40000000
+#define STATUS_THREAD_WAS_SUSPENDED 0x40000001
+#define STATUS_WORKING_SET_LIMIT_RANGE 0x40000002
+#define STATUS_IMAGE_NOT_AT_BASE 0x40000003
+#define STATUS_RXACT_STATE_CREATED 0x40000004
+#define STATUS_SEGMENT_NOTIFICATION 0x40000005
+#define STATUS_LOCAL_USER_SESSION_KEY 0x40000006
+#define STATUS_BAD_CURRENT_DIRECTORY 0x40000007
+#define STATUS_SERIAL_MORE_WRITES 0x40000008
+#define STATUS_REGISTRY_RECOVERED 0x40000009
+#define STATUS_FT_READ_RECOVERY_FROM_BACKUP 0x4000000A
+#define STATUS_FT_WRITE_RECOVERY 0x4000000B
+#define STATUS_SERIAL_COUNTER_TIMEOUT 0x4000000C
+#define STATUS_NULL_LM_PASSWORD 0x4000000D
+#define STATUS_IMAGE_MACHINE_TYPE_MISMATCH 0x4000000E
+#define STATUS_RECEIVE_PARTIAL 0x4000000F
+#define STATUS_RECEIVE_EXPEDITED 0x40000010
+#define STATUS_RECEIVE_PARTIAL_EXPEDITED 0x40000011
+#define STATUS_EVENT_DONE 0x40000012
+#define STATUS_EVENT_PENDING 0x40000013
+#define STATUS_CHECKING_FILE_SYSTEM 0x40000014
+#define STATUS_FATAL_APP_EXIT 0x40000015
+#define STATUS_PREDEFINED_HANDLE 0x40000016
+#define STATUS_WAS_UNLOCKED 0x40000017
+#define STATUS_SERVICE_NOTIFICATION 0x40000018
+#define STATUS_WAS_LOCKED 0x40000019
+#define STATUS_LOG_HARD_ERROR 0x4000001A
+#define STATUS_ALREADY_WIN32 0x4000001B
+#define STATUS_WX86_UNSIMULATE 0x4000001C
+#define STATUS_WX86_CONTINUE 0x4000001D
+#define STATUS_WX86_SINGLE_STEP 0x4000001E
+#define STATUS_WX86_BREAKPOINT 0x4000001F
+#define STATUS_WX86_EXCEPTION_CONTINUE 0x40000020
+#define STATUS_WX86_EXCEPTION_LASTCHANCE 0x40000021
+#define STATUS_WX86_EXCEPTION_CHAIN 0x40000022
+#define STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE 0x40000023
+#define STATUS_NO_YIELD_PERFORMED 0x40000024
+#define STATUS_TIMER_RESUME_IGNORED 0x40000025
+#define STATUS_ARBITRATION_UNHANDLED 0x40000026
+#define STATUS_CARDBUS_NOT_SUPPORTED 0x40000027
+#define STATUS_WX86_CREATEWX86TIB 0x40000028
+#define STATUS_MP_PROCESSOR_MISMATCH 0x40000029
+#define STATUS_HIBERNATED 0x4000002A
+#define STATUS_RESUME_HIBERNATION 0x4000002B
+#define STATUS_FIRMWARE_UPDATED 0x4000002C
+#define STATUS_DRIVERS_LEAKING_LOCKED_PAGES 0x4000002D
+#define STATUS_MESSAGE_RETRIEVED 0x4000002E
+#define STATUS_SYSTEM_POWERSTATE_TRANSITION 0x4000002F
+#define STATUS_ALPC_CHECK_COMPLETION_LIST 0x40000030
+#define STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION 0x40000031
+#define STATUS_ACCESS_AUDIT_BY_POLICY 0x40000032
+#define STATUS_ABANDON_HIBERFILE 0x40000033
+#define STATUS_BIZRULES_NOT_ENABLED 0x40000034
+#define STATUS_WAKE_SYSTEM 0x40000294
+#define STATUS_DS_SHUTTING_DOWN 0x40000370
+#define DBG_REPLY_LATER 0x40010001
+#define DBG_UNABLE_TO_PROVIDE_HANDLE 0x40010002
+#define DBG_TERMINATE_THREAD 0x40010003
+#define DBG_TERMINATE_PROCESS 0x40010004
+#define DBG_CONTROL_C 0x40010005
+#define DBG_PRINTEXCEPTION_C 0x40010006
+#define DBG_RIPEXCEPTION 0x40010007
+#define DBG_CONTROL_BREAK 0x40010008
+#define DBG_COMMAND_EXCEPTION 0x40010009
+#define RPC_NT_UUID_LOCAL_ONLY 0x40020056
+#define RPC_NT_SEND_INCOMPLETE 0x400200AF
+#define STATUS_CTX_CDM_CONNECT 0x400A0004
+#define STATUS_CTX_CDM_DISCONNECT 0x400A0005
+#define STATUS_SXS_RELEASE_ACTIVATION_CONTEXT 0x4015000D
+#define STATUS_RECOVERY_NOT_NEEDED 0x40190034
+#define STATUS_RM_ALREADY_STARTED 0x40190035
+#define STATUS_LOG_NO_RESTART 0x401A000C
+#define STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST 0x401B00EC
+#define STATUS_GRAPHICS_PARTIAL_DATA_POPULATED 0x401E000A
+#define STATUS_GRAPHICS_DRIVER_MISMATCH 0x401E0117
+#define STATUS_GRAPHICS_MODE_NOT_PINNED 0x401E0307
+#define STATUS_GRAPHICS_NO_PREFERRED_MODE 0x401E031E
+#define STATUS_GRAPHICS_DATASET_IS_EMPTY 0x401E034B
+#define STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET 0x401E034C
+#define STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED 0x401E0351
+#define STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS 0x401E042F
+#define STATUS_GRAPHICS_LEADLINK_START_DEFERRED 0x401E0437
+#define STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY 0x401E0439
+#define STATUS_GRAPHICS_START_DEFERRED 0x401E043A
+#define STATUS_NDIS_INDICATION_REQUIRED 0x40230001
+#define STATUS_GUARD_PAGE_VIOLATION 0x80000001
+#define STATUS_DATATYPE_MISALIGNMENT 0x80000002
+#define STATUS_BREAKPOINT 0x80000003
+#define STATUS_SINGLE_STEP 0x80000004
+#define STATUS_BUFFER_OVERFLOW 0x80000005
+#define STATUS_NO_MORE_FILES 0x80000006
+#define STATUS_WAKE_SYSTEM_DEBUGGER 0x80000007
+#define STATUS_HANDLES_CLOSED 0x8000000A
+#define STATUS_NO_INHERITANCE 0x8000000B
+#define STATUS_GUID_SUBSTITUTION_MADE 0x8000000C
+#define STATUS_PARTIAL_COPY 0x8000000D
+#define STATUS_DEVICE_PAPER_EMPTY 0x8000000E
+#define STATUS_DEVICE_POWERED_OFF 0x8000000F
+#define STATUS_DEVICE_OFF_LINE 0x80000010
+#define STATUS_DEVICE_BUSY 0x80000011
+#define STATUS_NO_MORE_EAS 0x80000012
+#define STATUS_INVALID_EA_NAME 0x80000013
+#define STATUS_EA_LIST_INCONSISTENT 0x80000014
+#define STATUS_INVALID_EA_FLAG 0x80000015
+#define STATUS_VERIFY_REQUIRED 0x80000016
+#define STATUS_EXTRANEOUS_INFORMATION 0x80000017
+#define STATUS_RXACT_COMMIT_NECESSARY 0x80000018
+#define STATUS_NO_MORE_ENTRIES 0x8000001A
+#define STATUS_FILEMARK_DETECTED 0x8000001B
+#define STATUS_MEDIA_CHANGED 0x8000001C
+#define STATUS_BUS_RESET 0x8000001D
+#define STATUS_END_OF_MEDIA 0x8000001E
+#define STATUS_BEGINNING_OF_MEDIA 0x8000001F
+#define STATUS_MEDIA_CHECK 0x80000020
+#define STATUS_SETMARK_DETECTED 0x80000021
+#define STATUS_NO_DATA_DETECTED 0x80000022
+#define STATUS_REDIRECTOR_HAS_OPEN_HANDLES 0x80000023
+#define STATUS_SERVER_HAS_OPEN_HANDLES 0x80000024
+#define STATUS_ALREADY_DISCONNECTED 0x80000025
+#define STATUS_LONGJUMP 0x80000026
+#define STATUS_CLEANER_CARTRIDGE_INSTALLED 0x80000027
+#define STATUS_PLUGPLAY_QUERY_VETOED 0x80000028
+#define STATUS_UNWIND_CONSOLIDATE 0x80000029
+#define STATUS_REGISTRY_HIVE_RECOVERED 0x8000002A
+#define STATUS_DLL_MIGHT_BE_INSECURE 0x8000002B
+#define STATUS_DLL_MIGHT_BE_INCOMPATIBLE 0x8000002C
+#define STATUS_STOPPED_ON_SYMLINK 0x8000002D
+#define STATUS_DEVICE_REQUIRES_CLEANING 0x80000288
+#define STATUS_DEVICE_DOOR_OPEN 0x80000289
+#define STATUS_DATA_LOST_REPAIR 0x80000803
+#define DBG_EXCEPTION_NOT_HANDLED 0x80010001
+#define STATUS_CLUSTER_NODE_ALREADY_UP 0x80130001
+#define STATUS_CLUSTER_NODE_ALREADY_DOWN 0x80130002
+#define STATUS_CLUSTER_NETWORK_ALREADY_ONLINE 0x80130003
+#define STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE 0x80130004
+#define STATUS_CLUSTER_NODE_ALREADY_MEMBER 0x80130005
+#define STATUS_COULD_NOT_RESIZE_LOG 0x80190009
+#define STATUS_NO_TXF_METADATA 0x80190029
+#define STATUS_CANT_RECOVER_WITH_HANDLE_OPEN 0x80190031
+#define STATUS_TXF_METADATA_ALREADY_PRESENT 0x80190041
+#define STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET 0x80190042
+#define STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED 0x801B00EB
+#define STATUS_FLT_BUFFER_TOO_SMALL 0x801C0001
+#define STATUS_FVE_PARTIAL_METADATA 0x80210001
+#define STATUS_UNSUCCESSFUL 0xC0000001
+#define STATUS_NOT_IMPLEMENTED 0xC0000002
+#define STATUS_INVALID_INFO_CLASS 0xC0000003
+#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
+#define STATUS_ACCESS_VIOLATION 0xC0000005
+#define STATUS_IN_PAGE_ERROR 0xC0000006
+#define STATUS_PAGEFILE_QUOTA 0xC0000007
+#define STATUS_INVALID_HANDLE 0xC0000008
+#define STATUS_BAD_INITIAL_STACK 0xC0000009
+#define STATUS_BAD_INITIAL_PC 0xC000000A
+#define STATUS_INVALID_CID 0xC000000B
+#define STATUS_TIMER_NOT_CANCELED 0xC000000C
+#define STATUS_INVALID_PARAMETER 0xC000000D
+#define STATUS_NO_SUCH_DEVICE 0xC000000E
+#define STATUS_NO_SUCH_FILE 0xC000000F
+#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010
+#define STATUS_END_OF_FILE 0xC0000011
+#define STATUS_WRONG_VOLUME 0xC0000012
+#define STATUS_NO_MEDIA_IN_DEVICE 0xC0000013
+#define STATUS_UNRECOGNIZED_MEDIA 0xC0000014
+#define STATUS_NONEXISTENT_SECTOR 0xC0000015
+#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016
+#define STATUS_NO_MEMORY 0xC0000017
+#define STATUS_CONFLICTING_ADDRESSES 0xC0000018
+#define STATUS_NOT_MAPPED_VIEW 0xC0000019
+#define STATUS_UNABLE_TO_FREE_VM 0xC000001A
+#define STATUS_UNABLE_TO_DELETE_SECTION 0xC000001B
+#define STATUS_INVALID_SYSTEM_SERVICE 0xC000001C
+#define STATUS_ILLEGAL_INSTRUCTION 0xC000001D
+#define STATUS_INVALID_LOCK_SEQUENCE 0xC000001E
+#define STATUS_INVALID_VIEW_SIZE 0xC000001F
+#define STATUS_INVALID_FILE_FOR_SECTION 0xC0000020
+#define STATUS_ALREADY_COMMITTED 0xC0000021
+#define STATUS_ACCESS_DENIED 0xC0000022
+#define STATUS_BUFFER_TOO_SMALL 0xC0000023
+#define STATUS_OBJECT_TYPE_MISMATCH 0xC0000024
+#define STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025
+#define STATUS_INVALID_DISPOSITION 0xC0000026
+#define STATUS_UNWIND 0xC0000027
+#define STATUS_BAD_STACK 0xC0000028
+#define STATUS_INVALID_UNWIND_TARGET 0xC0000029
+#define STATUS_NOT_LOCKED 0xC000002A
+#define STATUS_PARITY_ERROR 0xC000002B
+#define STATUS_UNABLE_TO_DECOMMIT_VM 0xC000002C
+#define STATUS_NOT_COMMITTED 0xC000002D
+#define STATUS_INVALID_PORT_ATTRIBUTES 0xC000002E
+#define STATUS_PORT_MESSAGE_TOO_LONG 0xC000002F
+#define STATUS_INVALID_PARAMETER_MIX 0xC0000030
+#define STATUS_INVALID_QUOTA_LOWER 0xC0000031
+#define STATUS_DISK_CORRUPT_ERROR 0xC0000032
+#define STATUS_OBJECT_NAME_INVALID 0xC0000033
+#define STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034
+#define STATUS_OBJECT_NAME_COLLISION 0xC0000035
+#define STATUS_PORT_DISCONNECTED 0xC0000037
+#define STATUS_DEVICE_ALREADY_ATTACHED 0xC0000038
+#define STATUS_OBJECT_PATH_INVALID 0xC0000039
+#define STATUS_OBJECT_PATH_NOT_FOUND 0xC000003A
+#define STATUS_OBJECT_PATH_SYNTAX_BAD 0xC000003B
+#define STATUS_DATA_OVERRUN 0xC000003C
+#define STATUS_DATA_LATE_ERROR 0xC000003D
+#define STATUS_DATA_ERROR 0xC000003E
+#define STATUS_CRC_ERROR 0xC000003F
+#define STATUS_SECTION_TOO_BIG 0xC0000040
+#define STATUS_PORT_CONNECTION_REFUSED 0xC0000041
+#define STATUS_INVALID_PORT_HANDLE 0xC0000042
+#define STATUS_SHARING_VIOLATION 0xC0000043
+#define STATUS_QUOTA_EXCEEDED 0xC0000044
+#define STATUS_INVALID_PAGE_PROTECTION 0xC0000045
+#define STATUS_MUTANT_NOT_OWNED 0xC0000046
+#define STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000047
+#define STATUS_PORT_ALREADY_SET 0xC0000048
+#define STATUS_SECTION_NOT_IMAGE 0xC0000049
+#define STATUS_SUSPEND_COUNT_EXCEEDED 0xC000004A
+#define STATUS_THREAD_IS_TERMINATING 0xC000004B
+#define STATUS_BAD_WORKING_SET_LIMIT 0xC000004C
+#define STATUS_INCOMPATIBLE_FILE_MAP 0xC000004D
+#define STATUS_SECTION_PROTECTION 0xC000004E
+#define STATUS_EAS_NOT_SUPPORTED 0xC000004F
+#define STATUS_EA_TOO_LARGE 0xC0000050
+#define STATUS_NONEXISTENT_EA_ENTRY 0xC0000051
+#define STATUS_NO_EAS_ON_FILE 0xC0000052
+#define STATUS_EA_CORRUPT_ERROR 0xC0000053
+#define STATUS_FILE_LOCK_CONFLICT 0xC0000054
+#define STATUS_LOCK_NOT_GRANTED 0xC0000055
+#define STATUS_DELETE_PENDING 0xC0000056
+#define STATUS_CTL_FILE_NOT_SUPPORTED 0xC0000057
+#define STATUS_UNKNOWN_REVISION 0xC0000058
+#define STATUS_REVISION_MISMATCH 0xC0000059
+#define STATUS_INVALID_OWNER 0xC000005A
+#define STATUS_INVALID_PRIMARY_GROUP 0xC000005B
+#define STATUS_NO_IMPERSONATION_TOKEN 0xC000005C
+#define STATUS_CANT_DISABLE_MANDATORY 0xC000005D
+#define STATUS_NO_LOGON_SERVERS 0xC000005E
+#define STATUS_NO_SUCH_LOGON_SESSION 0xC000005F
+#define STATUS_NO_SUCH_PRIVILEGE 0xC0000060
+#define STATUS_PRIVILEGE_NOT_HELD 0xC0000061
+#define STATUS_INVALID_ACCOUNT_NAME 0xC0000062
+#define STATUS_USER_EXISTS 0xC0000063
+#define STATUS_NO_SUCH_USER 0xC0000064
+#define STATUS_GROUP_EXISTS 0xC0000065
+#define STATUS_NO_SUCH_GROUP 0xC0000066
+#define STATUS_MEMBER_IN_GROUP 0xC0000067
+#define STATUS_MEMBER_NOT_IN_GROUP 0xC0000068
+#define STATUS_LAST_ADMIN 0xC0000069
+#define STATUS_WRONG_PASSWORD 0xC000006A
+#define STATUS_ILL_FORMED_PASSWORD 0xC000006B
+#define STATUS_PASSWORD_RESTRICTION 0xC000006C
+#define STATUS_LOGON_FAILURE 0xC000006D
+#define STATUS_ACCOUNT_RESTRICTION 0xC000006E
+#define STATUS_INVALID_LOGON_HOURS 0xC000006F
+#define STATUS_INVALID_WORKSTATION 0xC0000070
+#define STATUS_PASSWORD_EXPIRED 0xC0000071
+#define STATUS_ACCOUNT_DISABLED 0xC0000072
+#define STATUS_NONE_MAPPED 0xC0000073
+#define STATUS_TOO_MANY_LUIDS_REQUESTED 0xC0000074
+#define STATUS_LUIDS_EXHAUSTED 0xC0000075
+#define STATUS_INVALID_SUB_AUTHORITY 0xC0000076
+#define STATUS_INVALID_ACL 0xC0000077
+#define STATUS_INVALID_SID 0xC0000078
+#define STATUS_INVALID_SECURITY_DESCR 0xC0000079
+#define STATUS_PROCEDURE_NOT_FOUND 0xC000007A
+#define STATUS_INVALID_IMAGE_FORMAT 0xC000007B
+#define STATUS_NO_TOKEN 0xC000007C
+#define STATUS_BAD_INHERITANCE_ACL 0xC000007D
+#define STATUS_RANGE_NOT_LOCKED 0xC000007E
+#define STATUS_DISK_FULL 0xC000007F
+#define STATUS_SERVER_DISABLED 0xC0000080
+#define STATUS_SERVER_NOT_DISABLED 0xC0000081
+#define STATUS_TOO_MANY_GUIDS_REQUESTED 0xC0000082
+#define STATUS_GUIDS_EXHAUSTED 0xC0000083
+#define STATUS_INVALID_ID_AUTHORITY 0xC0000084
+#define STATUS_AGENTS_EXHAUSTED 0xC0000085
+#define STATUS_INVALID_VOLUME_LABEL 0xC0000086
+#define STATUS_SECTION_NOT_EXTENDED 0xC0000087
+#define STATUS_NOT_MAPPED_DATA 0xC0000088
+#define STATUS_RESOURCE_DATA_NOT_FOUND 0xC0000089
+#define STATUS_RESOURCE_TYPE_NOT_FOUND 0xC000008A
+#define STATUS_RESOURCE_NAME_NOT_FOUND 0xC000008B
+#define STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008C
+#define STATUS_FLOAT_DENORMAL_OPERAND 0xC000008D
+#define STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008E
+#define STATUS_FLOAT_INEXACT_RESULT 0xC000008F
+#define STATUS_FLOAT_INVALID_OPERATION 0xC0000090
+#define STATUS_FLOAT_OVERFLOW 0xC0000091
+#define STATUS_FLOAT_STACK_CHECK 0xC0000092
+#define STATUS_FLOAT_UNDERFLOW 0xC0000093
+#define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094
+#define STATUS_INTEGER_OVERFLOW 0xC0000095
+#define STATUS_PRIVILEGED_INSTRUCTION 0xC0000096
+#define STATUS_TOO_MANY_PAGING_FILES 0xC0000097
+#define STATUS_FILE_INVALID 0xC0000098
+#define STATUS_ALLOTTED_SPACE_EXCEEDED 0xC0000099
+#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A
+#define STATUS_DFS_EXIT_PATH_FOUND 0xC000009B
+#define STATUS_DEVICE_DATA_ERROR 0xC000009C
+#define STATUS_DEVICE_NOT_CONNECTED 0xC000009D
+#define STATUS_DEVICE_POWER_FAILURE 0xC000009E
+#define STATUS_FREE_VM_NOT_AT_BASE 0xC000009F
+#define STATUS_MEMORY_NOT_ALLOCATED 0xC00000A0
+#define STATUS_WORKING_SET_QUOTA 0xC00000A1
+#define STATUS_MEDIA_WRITE_PROTECTED 0xC00000A2
+#define STATUS_DEVICE_NOT_READY 0xC00000A3
+#define STATUS_INVALID_GROUP_ATTRIBUTES 0xC00000A4
+#define STATUS_BAD_IMPERSONATION_LEVEL 0xC00000A5
+#define STATUS_CANT_OPEN_ANONYMOUS 0xC00000A6
+#define STATUS_BAD_VALIDATION_CLASS 0xC00000A7
+#define STATUS_BAD_TOKEN_TYPE 0xC00000A8
+#define STATUS_BAD_MASTER_BOOT_RECORD 0xC00000A9
+#define STATUS_INSTRUCTION_MISALIGNMENT 0xC00000AA
+#define STATUS_INSTANCE_NOT_AVAILABLE 0xC00000AB
+#define STATUS_PIPE_NOT_AVAILABLE 0xC00000AC
+#define STATUS_INVALID_PIPE_STATE 0xC00000AD
+#define STATUS_PIPE_BUSY 0xC00000AE
+#define STATUS_ILLEGAL_FUNCTION 0xC00000AF
+#define STATUS_PIPE_DISCONNECTED 0xC00000B0
+#define STATUS_PIPE_CLOSING 0xC00000B1
+#define STATUS_PIPE_CONNECTED 0xC00000B2
+#define STATUS_PIPE_LISTENING 0xC00000B3
+#define STATUS_INVALID_READ_MODE 0xC00000B4
+#define STATUS_IO_TIMEOUT 0xC00000B5
+#define STATUS_FILE_FORCED_CLOSED 0xC00000B6
+#define STATUS_PROFILING_NOT_STARTED 0xC00000B7
+#define STATUS_PROFILING_NOT_STOPPED 0xC00000B8
+#define STATUS_COULD_NOT_INTERPRET 0xC00000B9
+#define STATUS_FILE_IS_A_DIRECTORY 0xC00000BA
+#define STATUS_NOT_SUPPORTED 0xC00000BB
+#define STATUS_REMOTE_NOT_LISTENING 0xC00000BC
+#define STATUS_DUPLICATE_NAME 0xC00000BD
+#define STATUS_BAD_NETWORK_PATH 0xC00000BE
+#define STATUS_NETWORK_BUSY 0xC00000BF
+#define STATUS_DEVICE_DOES_NOT_EXIST 0xC00000C0
+#define STATUS_TOO_MANY_COMMANDS 0xC00000C1
+#define STATUS_ADAPTER_HARDWARE_ERROR 0xC00000C2
+#define STATUS_INVALID_NETWORK_RESPONSE 0xC00000C3
+#define STATUS_UNEXPECTED_NETWORK_ERROR 0xC00000C4
+#define STATUS_BAD_REMOTE_ADAPTER 0xC00000C5
+#define STATUS_PRINT_QUEUE_FULL 0xC00000C6
+#define STATUS_NO_SPOOL_SPACE 0xC00000C7
+#define STATUS_PRINT_CANCELLED 0xC00000C8
+#define STATUS_NETWORK_NAME_DELETED 0xC00000C9
+#define STATUS_NETWORK_ACCESS_DENIED 0xC00000CA
+#define STATUS_BAD_DEVICE_TYPE 0xC00000CB
+#define STATUS_BAD_NETWORK_NAME 0xC00000CC
+#define STATUS_TOO_MANY_NAMES 0xC00000CD
+#define STATUS_TOO_MANY_SESSIONS 0xC00000CE
+#define STATUS_SHARING_PAUSED 0xC00000CF
+#define STATUS_REQUEST_NOT_ACCEPTED 0xC00000D0
+#define STATUS_REDIRECTOR_PAUSED 0xC00000D1
+#define STATUS_NET_WRITE_FAULT 0xC00000D2
+#define STATUS_PROFILING_AT_LIMIT 0xC00000D3
+#define STATUS_NOT_SAME_DEVICE 0xC00000D4
+#define STATUS_FILE_RENAMED 0xC00000D5
+#define STATUS_VIRTUAL_CIRCUIT_CLOSED 0xC00000D6
+#define STATUS_NO_SECURITY_ON_OBJECT 0xC00000D7
+#define STATUS_CANT_WAIT 0xC00000D8
+#define STATUS_PIPE_EMPTY 0xC00000D9
+#define STATUS_CANT_ACCESS_DOMAIN_INFO 0xC00000DA
+#define STATUS_CANT_TERMINATE_SELF 0xC00000DB
+#define STATUS_INVALID_SERVER_STATE 0xC00000DC
+#define STATUS_INVALID_DOMAIN_STATE 0xC00000DD
+#define STATUS_INVALID_DOMAIN_ROLE 0xC00000DE
+#define STATUS_NO_SUCH_DOMAIN 0xC00000DF
+#define STATUS_DOMAIN_EXISTS 0xC00000E0
+#define STATUS_DOMAIN_LIMIT_EXCEEDED 0xC00000E1
+#define STATUS_OPLOCK_NOT_GRANTED 0xC00000E2
+#define STATUS_INVALID_OPLOCK_PROTOCOL 0xC00000E3
+#define STATUS_INTERNAL_DB_CORRUPTION 0xC00000E4
+#define STATUS_INTERNAL_ERROR 0xC00000E5
+#define STATUS_GENERIC_NOT_MAPPED 0xC00000E6
+#define STATUS_BAD_DESCRIPTOR_FORMAT 0xC00000E7
+#define STATUS_INVALID_USER_BUFFER 0xC00000E8
+#define STATUS_UNEXPECTED_IO_ERROR 0xC00000E9
+#define STATUS_UNEXPECTED_MM_CREATE_ERR 0xC00000EA
+#define STATUS_UNEXPECTED_MM_MAP_ERROR 0xC00000EB
+#define STATUS_UNEXPECTED_MM_EXTEND_ERR 0xC00000EC
+#define STATUS_NOT_LOGON_PROCESS 0xC00000ED
+#define STATUS_LOGON_SESSION_EXISTS 0xC00000EE
+#define STATUS_INVALID_PARAMETER_1 0xC00000EF
+#define STATUS_INVALID_PARAMETER_2 0xC00000F0
+#define STATUS_INVALID_PARAMETER_3 0xC00000F1
+#define STATUS_INVALID_PARAMETER_4 0xC00000F2
+#define STATUS_INVALID_PARAMETER_5 0xC00000F3
+#define STATUS_INVALID_PARAMETER_6 0xC00000F4
+#define STATUS_INVALID_PARAMETER_7 0xC00000F5
+#define STATUS_INVALID_PARAMETER_8 0xC00000F6
+#define STATUS_INVALID_PARAMETER_9 0xC00000F7
+#define STATUS_INVALID_PARAMETER_10 0xC00000F8
+#define STATUS_INVALID_PARAMETER_11 0xC00000F9
+#define STATUS_INVALID_PARAMETER_12 0xC00000FA
+#define STATUS_REDIRECTOR_NOT_STARTED 0xC00000FB
+#define STATUS_REDIRECTOR_STARTED 0xC00000FC
+#define STATUS_STACK_OVERFLOW 0xC00000FD
+#define STATUS_NO_SUCH_PACKAGE 0xC00000FE
+#define STATUS_BAD_FUNCTION_TABLE 0xC00000FF
+#define STATUS_VARIABLE_NOT_FOUND 0xC0000100
+#define STATUS_DIRECTORY_NOT_EMPTY 0xC0000101
+#define STATUS_FILE_CORRUPT_ERROR 0xC0000102
+#define STATUS_NOT_A_DIRECTORY 0xC0000103
+#define STATUS_BAD_LOGON_SESSION_STATE 0xC0000104
+#define STATUS_LOGON_SESSION_COLLISION 0xC0000105
+#define STATUS_NAME_TOO_LONG 0xC0000106
+#define STATUS_FILES_OPEN 0xC0000107
+#define STATUS_CONNECTION_IN_USE 0xC0000108
+#define STATUS_MESSAGE_NOT_FOUND 0xC0000109
+#define STATUS_PROCESS_IS_TERMINATING 0xC000010A
+#define STATUS_INVALID_LOGON_TYPE 0xC000010B
+#define STATUS_NO_GUID_TRANSLATION 0xC000010C
+#define STATUS_CANNOT_IMPERSONATE 0xC000010D
+#define STATUS_IMAGE_ALREADY_LOADED 0xC000010E
+#define STATUS_ABIOS_NOT_PRESENT 0xC000010F
+#define STATUS_ABIOS_LID_NOT_EXIST 0xC0000110
+#define STATUS_ABIOS_LID_ALREADY_OWNED 0xC0000111
+#define STATUS_ABIOS_NOT_LID_OWNER 0xC0000112
+#define STATUS_ABIOS_INVALID_COMMAND 0xC0000113
+#define STATUS_ABIOS_INVALID_LID 0xC0000114
+#define STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0xC0000115
+#define STATUS_ABIOS_INVALID_SELECTOR 0xC0000116
+#define STATUS_NO_LDT 0xC0000117
+#define STATUS_INVALID_LDT_SIZE 0xC0000118
+#define STATUS_INVALID_LDT_OFFSET 0xC0000119
+#define STATUS_INVALID_LDT_DESCRIPTOR 0xC000011A
+#define STATUS_INVALID_IMAGE_NE_FORMAT 0xC000011B
+#define STATUS_RXACT_INVALID_STATE 0xC000011C
+#define STATUS_RXACT_COMMIT_FAILURE 0xC000011D
+#define STATUS_MAPPED_FILE_SIZE_ZERO 0xC000011E
+#define STATUS_TOO_MANY_OPENED_FILES 0xC000011F
+#define STATUS_CANCELLED 0xC0000120
+#define STATUS_CANNOT_DELETE 0xC0000121
+#define STATUS_INVALID_COMPUTER_NAME 0xC0000122
+#define STATUS_FILE_DELETED 0xC0000123
+#define STATUS_SPECIAL_ACCOUNT 0xC0000124
+#define STATUS_SPECIAL_GROUP 0xC0000125
+#define STATUS_SPECIAL_USER 0xC0000126
+#define STATUS_MEMBERS_PRIMARY_GROUP 0xC0000127
+#define STATUS_FILE_CLOSED 0xC0000128
+#define STATUS_TOO_MANY_THREADS 0xC0000129
+#define STATUS_THREAD_NOT_IN_PROCESS 0xC000012A
+#define STATUS_TOKEN_ALREADY_IN_USE 0xC000012B
+#define STATUS_PAGEFILE_QUOTA_EXCEEDED 0xC000012C
+#define STATUS_COMMITMENT_LIMIT 0xC000012D
+#define STATUS_INVALID_IMAGE_LE_FORMAT 0xC000012E
+#define STATUS_INVALID_IMAGE_NOT_MZ 0xC000012F
+#define STATUS_INVALID_IMAGE_PROTECT 0xC0000130
+#define STATUS_INVALID_IMAGE_WIN_16 0xC0000131
+#define STATUS_LOGON_SERVER_CONFLICT 0xC0000132
+#define STATUS_TIME_DIFFERENCE_AT_DC 0xC0000133
+#define STATUS_SYNCHRONIZATION_REQUIRED 0xC0000134
+#define STATUS_DLL_NOT_FOUND 0xC0000135
+#define STATUS_OPEN_FAILED 0xC0000136
+#define STATUS_IO_PRIVILEGE_FAILED 0xC0000137
+#define STATUS_ORDINAL_NOT_FOUND 0xC0000138
+#define STATUS_ENTRYPOINT_NOT_FOUND 0xC0000139
+#define STATUS_CONTROL_C_EXIT 0xC000013A
+#define STATUS_LOCAL_DISCONNECT 0xC000013B
+#define STATUS_REMOTE_DISCONNECT 0xC000013C
+#define STATUS_REMOTE_RESOURCES 0xC000013D
+#define STATUS_LINK_FAILED 0xC000013E
+#define STATUS_LINK_TIMEOUT 0xC000013F
+#define STATUS_INVALID_CONNECTION 0xC0000140
+#define STATUS_INVALID_ADDRESS 0xC0000141
+#define STATUS_DLL_INIT_FAILED 0xC0000142
+#define STATUS_MISSING_SYSTEMFILE 0xC0000143
+#define STATUS_UNHANDLED_EXCEPTION 0xC0000144
+#define STATUS_APP_INIT_FAILURE 0xC0000145
+#define STATUS_PAGEFILE_CREATE_FAILED 0xC0000146
+#define STATUS_NO_PAGEFILE 0xC0000147
+#define STATUS_INVALID_LEVEL 0xC0000148
+#define STATUS_WRONG_PASSWORD_CORE 0xC0000149
+#define STATUS_ILLEGAL_FLOAT_CONTEXT 0xC000014A
+#define STATUS_PIPE_BROKEN 0xC000014B
+#define STATUS_REGISTRY_CORRUPT 0xC000014C
+#define STATUS_REGISTRY_IO_FAILED 0xC000014D
+#define STATUS_NO_EVENT_PAIR 0xC000014E
+#define STATUS_UNRECOGNIZED_VOLUME 0xC000014F
+#define STATUS_SERIAL_NO_DEVICE_INITED 0xC0000150
+#define STATUS_NO_SUCH_ALIAS 0xC0000151
+#define STATUS_MEMBER_NOT_IN_ALIAS 0xC0000152
+#define STATUS_MEMBER_IN_ALIAS 0xC0000153
+#define STATUS_ALIAS_EXISTS 0xC0000154
+#define STATUS_LOGON_NOT_GRANTED 0xC0000155
+#define STATUS_TOO_MANY_SECRETS 0xC0000156
+#define STATUS_SECRET_TOO_LONG 0xC0000157
+#define STATUS_INTERNAL_DB_ERROR 0xC0000158
+#define STATUS_FULLSCREEN_MODE 0xC0000159
+#define STATUS_TOO_MANY_CONTEXT_IDS 0xC000015A
+#define STATUS_LOGON_TYPE_NOT_GRANTED 0xC000015B
+#define STATUS_NOT_REGISTRY_FILE 0xC000015C
+#define STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0xC000015D
+#define STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0xC000015E
+#define STATUS_FT_MISSING_MEMBER 0xC000015F
+#define STATUS_ILL_FORMED_SERVICE_ENTRY 0xC0000160
+#define STATUS_ILLEGAL_CHARACTER 0xC0000161
+#define STATUS_UNMAPPABLE_CHARACTER 0xC0000162
+#define STATUS_UNDEFINED_CHARACTER 0xC0000163
+#define STATUS_FLOPPY_VOLUME 0xC0000164
+#define STATUS_FLOPPY_ID_MARK_NOT_FOUND 0xC0000165
+#define STATUS_FLOPPY_WRONG_CYLINDER 0xC0000166
+#define STATUS_FLOPPY_UNKNOWN_ERROR 0xC0000167
+#define STATUS_FLOPPY_BAD_REGISTERS 0xC0000168
+#define STATUS_DISK_RECALIBRATE_FAILED 0xC0000169
+#define STATUS_DISK_OPERATION_FAILED 0xC000016A
+#define STATUS_DISK_RESET_FAILED 0xC000016B
+#define STATUS_SHARED_IRQ_BUSY 0xC000016C
+#define STATUS_FT_ORPHANING 0xC000016D
+#define STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT 0xC000016E
+#define STATUS_PARTITION_FAILURE 0xC0000172
+#define STATUS_INVALID_BLOCK_LENGTH 0xC0000173
+#define STATUS_DEVICE_NOT_PARTITIONED 0xC0000174
+#define STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000175
+#define STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000176
+#define STATUS_EOM_OVERFLOW 0xC0000177
+#define STATUS_NO_MEDIA 0xC0000178
+#define STATUS_NO_SUCH_MEMBER 0xC000017A
+#define STATUS_INVALID_MEMBER 0xC000017B
+#define STATUS_KEY_DELETED 0xC000017C
+#define STATUS_NO_LOG_SPACE 0xC000017D
+#define STATUS_TOO_MANY_SIDS 0xC000017E
+#define STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC000017F
+#define STATUS_KEY_HAS_CHILDREN 0xC0000180
+#define STATUS_CHILD_MUST_BE_VOLATILE 0xC0000181
+#define STATUS_DEVICE_CONFIGURATION_ERROR 0xC0000182
+#define STATUS_DRIVER_INTERNAL_ERROR 0xC0000183
+#define STATUS_INVALID_DEVICE_STATE 0xC0000184
+#define STATUS_IO_DEVICE_ERROR 0xC0000185
+#define STATUS_DEVICE_PROTOCOL_ERROR 0xC0000186
+#define STATUS_BACKUP_CONTROLLER 0xC0000187
+#define STATUS_LOG_FILE_FULL 0xC0000188
+#define STATUS_TOO_LATE 0xC0000189
+#define STATUS_NO_TRUST_LSA_SECRET 0xC000018A
+#define STATUS_NO_TRUST_SAM_ACCOUNT 0xC000018B
+#define STATUS_TRUSTED_DOMAIN_FAILURE 0xC000018C
+#define STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC000018D
+#define STATUS_EVENTLOG_FILE_CORRUPT 0xC000018E
+#define STATUS_EVENTLOG_CANT_START 0xC000018F
+#define STATUS_TRUST_FAILURE 0xC0000190
+#define STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000191
+#define STATUS_NETLOGON_NOT_STARTED 0xC0000192
+#define STATUS_ACCOUNT_EXPIRED 0xC0000193
+#define STATUS_POSSIBLE_DEADLOCK 0xC0000194
+#define STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000195
+#define STATUS_REMOTE_SESSION_LIMIT 0xC0000196
+#define STATUS_EVENTLOG_FILE_CHANGED 0xC0000197
+#define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000198
+#define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000199
+#define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC000019A
+#define STATUS_DOMAIN_TRUST_INCONSISTENT 0xC000019B
+#define STATUS_FS_DRIVER_REQUIRED 0xC000019C
+#define STATUS_IMAGE_ALREADY_LOADED_AS_DLL 0xC000019D
+#define STATUS_NETWORK_OPEN_RESTRICTION 0xC0000201
+#define STATUS_NO_USER_SESSION_KEY 0xC0000202
+#define STATUS_USER_SESSION_DELETED 0xC0000203
+#define STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000204
+#define STATUS_INSUFF_SERVER_RESOURCES 0xC0000205
+#define STATUS_INVALID_BUFFER_SIZE 0xC0000206
+#define STATUS_INVALID_ADDRESS_COMPONENT 0xC0000207
+#define STATUS_INVALID_ADDRESS_WILDCARD 0xC0000208
+#define STATUS_TOO_MANY_ADDRESSES 0xC0000209
+#define STATUS_ADDRESS_ALREADY_EXISTS 0xC000020A
+#define STATUS_ADDRESS_CLOSED 0xC000020B
+#define STATUS_CONNECTION_DISCONNECTED 0xC000020C
+#define STATUS_CONNECTION_RESET 0xC000020D
+#define STATUS_TOO_MANY_NODES 0xC000020E
+#define STATUS_TRANSACTION_ABORTED 0xC000020F
+#define STATUS_TRANSACTION_TIMED_OUT 0xC0000210
+#define STATUS_TRANSACTION_NO_RELEASE 0xC0000211
+#define STATUS_TRANSACTION_NO_MATCH 0xC0000212
+#define STATUS_TRANSACTION_RESPONDED 0xC0000213
+#define STATUS_TRANSACTION_INVALID_ID 0xC0000214
+#define STATUS_TRANSACTION_INVALID_TYPE 0xC0000215
+#define STATUS_NOT_SERVER_SESSION 0xC0000216
+#define STATUS_NOT_CLIENT_SESSION 0xC0000217
+#define STATUS_CANNOT_LOAD_REGISTRY_FILE 0xC0000218
+#define STATUS_DEBUG_ATTACH_FAILED 0xC0000219
+#define STATUS_SYSTEM_PROCESS_TERMINATED 0xC000021A
+#define STATUS_DATA_NOT_ACCEPTED 0xC000021B
+#define STATUS_NO_BROWSER_SERVERS_FOUND 0xC000021C
+#define STATUS_VDM_HARD_ERROR 0xC000021D
+#define STATUS_DRIVER_CANCEL_TIMEOUT 0xC000021E
+#define STATUS_REPLY_MESSAGE_MISMATCH 0xC000021F
+#define STATUS_MAPPED_ALIGNMENT 0xC0000220
+#define STATUS_IMAGE_CHECKSUM_MISMATCH 0xC0000221
+#define STATUS_LOST_WRITEBEHIND_DATA 0xC0000222
+#define STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0xC0000223
+#define STATUS_PASSWORD_MUST_CHANGE 0xC0000224
+#define STATUS_NOT_FOUND 0xC0000225
+#define STATUS_NOT_TINY_STREAM 0xC0000226
+#define STATUS_RECOVERY_FAILURE 0xC0000227
+#define STATUS_STACK_OVERFLOW_READ 0xC0000228
+#define STATUS_FAIL_CHECK 0xC0000229
+#define STATUS_DUPLICATE_OBJECTID 0xC000022A
+#define STATUS_OBJECTID_EXISTS 0xC000022B
+#define STATUS_CONVERT_TO_LARGE 0xC000022C
+#define STATUS_RETRY 0xC000022D
+#define STATUS_FOUND_OUT_OF_SCOPE 0xC000022E
+#define STATUS_ALLOCATE_BUCKET 0xC000022F
+#define STATUS_PROPSET_NOT_FOUND 0xC0000230
+#define STATUS_MARSHALL_OVERFLOW 0xC0000231
+#define STATUS_INVALID_VARIANT 0xC0000232
+#define STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0xC0000233
+#define STATUS_ACCOUNT_LOCKED_OUT 0xC0000234
+#define STATUS_HANDLE_NOT_CLOSABLE 0xC0000235
+#define STATUS_CONNECTION_REFUSED 0xC0000236
+#define STATUS_GRACEFUL_DISCONNECT 0xC0000237
+#define STATUS_ADDRESS_ALREADY_ASSOCIATED 0xC0000238
+#define STATUS_ADDRESS_NOT_ASSOCIATED 0xC0000239
+#define STATUS_CONNECTION_INVALID 0xC000023A
+#define STATUS_CONNECTION_ACTIVE 0xC000023B
+#define STATUS_NETWORK_UNREACHABLE 0xC000023C
+#define STATUS_HOST_UNREACHABLE 0xC000023D
+#define STATUS_PROTOCOL_UNREACHABLE 0xC000023E
+#define STATUS_PORT_UNREACHABLE 0xC000023F
+#define STATUS_REQUEST_ABORTED 0xC0000240
+#define STATUS_CONNECTION_ABORTED 0xC0000241
+#define STATUS_BAD_COMPRESSION_BUFFER 0xC0000242
+#define STATUS_USER_MAPPED_FILE 0xC0000243
+#define STATUS_AUDIT_FAILED 0xC0000244
+#define STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000245
+#define STATUS_CONNECTION_COUNT_LIMIT 0xC0000246
+#define STATUS_LOGIN_TIME_RESTRICTION 0xC0000247
+#define STATUS_LOGIN_WKSTA_RESTRICTION 0xC0000248
+#define STATUS_IMAGE_MP_UP_MISMATCH 0xC0000249
+#define STATUS_INSUFFICIENT_LOGON_INFO 0xC0000250
+#define STATUS_BAD_DLL_ENTRYPOINT 0xC0000251
+#define STATUS_BAD_SERVICE_ENTRYPOINT 0xC0000252
+#define STATUS_LPC_REPLY_LOST 0xC0000253
+#define STATUS_IP_ADDRESS_CONFLICT1 0xC0000254
+#define STATUS_IP_ADDRESS_CONFLICT2 0xC0000255
+#define STATUS_REGISTRY_QUOTA_LIMIT 0xC0000256
+#define STATUS_PATH_NOT_COVERED 0xC0000257
+#define STATUS_NO_CALLBACK_ACTIVE 0xC0000258
+#define STATUS_LICENSE_QUOTA_EXCEEDED 0xC0000259
+#define STATUS_PWD_TOO_SHORT 0xC000025A
+#define STATUS_PWD_TOO_RECENT 0xC000025B
+#define STATUS_PWD_HISTORY_CONFLICT 0xC000025C
+#define STATUS_PLUGPLAY_NO_DEVICE 0xC000025E
+#define STATUS_UNSUPPORTED_COMPRESSION 0xC000025F
+#define STATUS_INVALID_HW_PROFILE 0xC0000260
+#define STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0xC0000261
+#define STATUS_DRIVER_ORDINAL_NOT_FOUND 0xC0000262
+#define STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0xC0000263
+#define STATUS_RESOURCE_NOT_OWNED 0xC0000264
+#define STATUS_TOO_MANY_LINKS 0xC0000265
+#define STATUS_QUOTA_LIST_INCONSISTENT 0xC0000266
+#define STATUS_FILE_IS_OFFLINE 0xC0000267
+#define STATUS_EVALUATION_EXPIRATION 0xC0000268
+#define STATUS_ILLEGAL_DLL_RELOCATION 0xC0000269
+#define STATUS_LICENSE_VIOLATION 0xC000026A
+#define STATUS_DLL_INIT_FAILED_LOGOFF 0xC000026B
+#define STATUS_DRIVER_UNABLE_TO_LOAD 0xC000026C
+#define STATUS_DFS_UNAVAILABLE 0xC000026D
+#define STATUS_VOLUME_DISMOUNTED 0xC000026E
+#define STATUS_WX86_INTERNAL_ERROR 0xC000026F
+#define STATUS_WX86_FLOAT_STACK_CHECK 0xC0000270
+#define STATUS_VALIDATE_CONTINUE 0xC0000271
+#define STATUS_NO_MATCH 0xC0000272
+#define STATUS_NO_MORE_MATCHES 0xC0000273
+#define STATUS_NOT_A_REPARSE_POINT 0xC0000275
+#define STATUS_IO_REPARSE_TAG_INVALID 0xC0000276
+#define STATUS_IO_REPARSE_TAG_MISMATCH 0xC0000277
+#define STATUS_IO_REPARSE_DATA_INVALID 0xC0000278
+#define STATUS_IO_REPARSE_TAG_NOT_HANDLED 0xC0000279
+#define STATUS_REPARSE_POINT_NOT_RESOLVED 0xC0000280
+#define STATUS_DIRECTORY_IS_A_REPARSE_POINT 0xC0000281
+#define STATUS_RANGE_LIST_CONFLICT 0xC0000282
+#define STATUS_SOURCE_ELEMENT_EMPTY 0xC0000283
+#define STATUS_DESTINATION_ELEMENT_FULL 0xC0000284
+#define STATUS_ILLEGAL_ELEMENT_ADDRESS 0xC0000285
+#define STATUS_MAGAZINE_NOT_PRESENT 0xC0000286
+#define STATUS_REINITIALIZATION_NEEDED 0xC0000287
+#define STATUS_ENCRYPTION_FAILED 0xC000028A
+#define STATUS_DECRYPTION_FAILED 0xC000028B
+#define STATUS_RANGE_NOT_FOUND 0xC000028C
+#define STATUS_NO_RECOVERY_POLICY 0xC000028D
+#define STATUS_NO_EFS 0xC000028E
+#define STATUS_WRONG_EFS 0xC000028F
+#define STATUS_NO_USER_KEYS 0xC0000290
+#define STATUS_FILE_NOT_ENCRYPTED 0xC0000291
+#define STATUS_NOT_EXPORT_FORMAT 0xC0000292
+#define STATUS_FILE_ENCRYPTED 0xC0000293
+#define STATUS_WMI_GUID_NOT_FOUND 0xC0000295
+#define STATUS_WMI_INSTANCE_NOT_FOUND 0xC0000296
+#define STATUS_WMI_ITEMID_NOT_FOUND 0xC0000297
+#define STATUS_WMI_TRY_AGAIN 0xC0000298
+#define STATUS_SHARED_POLICY 0xC0000299
+#define STATUS_POLICY_OBJECT_NOT_FOUND 0xC000029A
+#define STATUS_POLICY_ONLY_IN_DS 0xC000029B
+#define STATUS_VOLUME_NOT_UPGRADED 0xC000029C
+#define STATUS_REMOTE_STORAGE_NOT_ACTIVE 0xC000029D
+#define STATUS_REMOTE_STORAGE_MEDIA_ERROR 0xC000029E
+#define STATUS_NO_TRACKING_SERVICE 0xC000029F
+#define STATUS_SERVER_SID_MISMATCH 0xC00002A0
+#define STATUS_DS_NO_ATTRIBUTE_OR_VALUE 0xC00002A1
+#define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX 0xC00002A2
+#define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED 0xC00002A3
+#define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS 0xC00002A4
+#define STATUS_DS_BUSY 0xC00002A5
+#define STATUS_DS_UNAVAILABLE 0xC00002A6
+#define STATUS_DS_NO_RIDS_ALLOCATED 0xC00002A7
+#define STATUS_DS_NO_MORE_RIDS 0xC00002A8
+#define STATUS_DS_INCORRECT_ROLE_OWNER 0xC00002A9
+#define STATUS_DS_RIDMGR_INIT_ERROR 0xC00002AA
+#define STATUS_DS_OBJ_CLASS_VIOLATION 0xC00002AB
+#define STATUS_DS_CANT_ON_NON_LEAF 0xC00002AC
+#define STATUS_DS_CANT_ON_RDN 0xC00002AD
+#define STATUS_DS_CANT_MOD_OBJ_CLASS 0xC00002AE
+#define STATUS_DS_CROSS_DOM_MOVE_FAILED 0xC00002AF
+#define STATUS_DS_GC_NOT_AVAILABLE 0xC00002B0
+#define STATUS_DIRECTORY_SERVICE_REQUIRED 0xC00002B1
+#define STATUS_REPARSE_ATTRIBUTE_CONFLICT 0xC00002B2
+#define STATUS_CANT_ENABLE_DENY_ONLY 0xC00002B3
+#define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4
+#define STATUS_FLOAT_MULTIPLE_TRAPS 0xC00002B5
+#define STATUS_DEVICE_REMOVED 0xC00002B6
+#define STATUS_JOURNAL_DELETE_IN_PROGRESS 0xC00002B7
+#define STATUS_JOURNAL_NOT_ACTIVE 0xC00002B8
+#define STATUS_NOINTERFACE 0xC00002B9
+#define STATUS_DS_ADMIN_LIMIT_EXCEEDED 0xC00002C1
+#define STATUS_DRIVER_FAILED_SLEEP 0xC00002C2
+#define STATUS_MUTUAL_AUTHENTICATION_FAILED 0xC00002C3
+#define STATUS_CORRUPT_SYSTEM_FILE 0xC00002C4
+#define STATUS_DATATYPE_MISALIGNMENT_ERROR 0xC00002C5
+#define STATUS_WMI_READ_ONLY 0xC00002C6
+#define STATUS_WMI_SET_FAILURE 0xC00002C7
+#define STATUS_COMMITMENT_MINIMUM 0xC00002C8
+#define STATUS_REG_NAT_CONSUMPTION 0xC00002C9
+#define STATUS_TRANSPORT_FULL 0xC00002CA
+#define STATUS_DS_SAM_INIT_FAILURE 0xC00002CB
+#define STATUS_ONLY_IF_CONNECTED 0xC00002CC
+#define STATUS_DS_SENSITIVE_GROUP_VIOLATION 0xC00002CD
+#define STATUS_PNP_RESTART_ENUMERATION 0xC00002CE
+#define STATUS_JOURNAL_ENTRY_DELETED 0xC00002CF
+#define STATUS_DS_CANT_MOD_PRIMARYGROUPID 0xC00002D0
+#define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE 0xC00002D1
+#define STATUS_PNP_REBOOT_REQUIRED 0xC00002D2
+#define STATUS_POWER_STATE_INVALID 0xC00002D3
+#define STATUS_DS_INVALID_GROUP_TYPE 0xC00002D4
+#define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN 0xC00002D5
+#define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN 0xC00002D6
+#define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER 0xC00002D7
+#define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER 0xC00002D8
+#define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER 0xC00002D9
+#define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER 0xC00002DA
+#define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER 0xC00002DB
+#define STATUS_DS_HAVE_PRIMARY_MEMBERS 0xC00002DC
+#define STATUS_WMI_NOT_SUPPORTED 0xC00002DD
+#define STATUS_INSUFFICIENT_POWER 0xC00002DE
+#define STATUS_SAM_NEED_BOOTKEY_PASSWORD 0xC00002DF
+#define STATUS_SAM_NEED_BOOTKEY_FLOPPY 0xC00002E0
+#define STATUS_DS_CANT_START 0xC00002E1
+#define STATUS_DS_INIT_FAILURE 0xC00002E2
+#define STATUS_SAM_INIT_FAILURE 0xC00002E3
+#define STATUS_DS_GC_REQUIRED 0xC00002E4
+#define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY 0xC00002E5
+#define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS 0xC00002E6
+#define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED 0xC00002E7
+#define STATUS_MULTIPLE_FAULT_VIOLATION 0xC00002E8
+#define STATUS_CURRENT_DOMAIN_NOT_ALLOWED 0xC00002E9
+#define STATUS_CANNOT_MAKE 0xC00002EA
+#define STATUS_SYSTEM_SHUTDOWN 0xC00002EB
+#define STATUS_DS_INIT_FAILURE_CONSOLE 0xC00002EC
+#define STATUS_DS_SAM_INIT_FAILURE_CONSOLE 0xC00002ED
+#define STATUS_UNFINISHED_CONTEXT_DELETED 0xC00002EE
+#define STATUS_NO_TGT_REPLY 0xC00002EF
+#define STATUS_OBJECTID_NOT_FOUND 0xC00002F0
+#define STATUS_NO_IP_ADDRESSES 0xC00002F1
+#define STATUS_WRONG_CREDENTIAL_HANDLE 0xC00002F2
+#define STATUS_CRYPTO_SYSTEM_INVALID 0xC00002F3
+#define STATUS_MAX_REFERRALS_EXCEEDED 0xC00002F4
+#define STATUS_MUST_BE_KDC 0xC00002F5
+#define STATUS_STRONG_CRYPTO_NOT_SUPPORTED 0xC00002F6
+#define STATUS_TOO_MANY_PRINCIPALS 0xC00002F7
+#define STATUS_NO_PA_DATA 0xC00002F8
+#define STATUS_PKINIT_NAME_MISMATCH 0xC00002F9
+#define STATUS_SMARTCARD_LOGON_REQUIRED 0xC00002FA
+#define STATUS_KDC_INVALID_REQUEST 0xC00002FB
+#define STATUS_KDC_UNABLE_TO_REFER 0xC00002FC
+#define STATUS_KDC_UNKNOWN_ETYPE 0xC00002FD
+#define STATUS_SHUTDOWN_IN_PROGRESS 0xC00002FE
+#define STATUS_SERVER_SHUTDOWN_IN_PROGRESS 0xC00002FF
+#define STATUS_NOT_SUPPORTED_ON_SBS 0xC0000300
+#define STATUS_WMI_GUID_DISCONNECTED 0xC0000301
+#define STATUS_WMI_ALREADY_DISABLED 0xC0000302
+#define STATUS_WMI_ALREADY_ENABLED 0xC0000303
+#define STATUS_MFT_TOO_FRAGMENTED 0xC0000304
+#define STATUS_COPY_PROTECTION_FAILURE 0xC0000305
+#define STATUS_CSS_AUTHENTICATION_FAILURE 0xC0000306
+#define STATUS_CSS_KEY_NOT_PRESENT 0xC0000307
+#define STATUS_CSS_KEY_NOT_ESTABLISHED 0xC0000308
+#define STATUS_CSS_SCRAMBLED_SECTOR 0xC0000309
+#define STATUS_CSS_REGION_MISMATCH 0xC000030A
+#define STATUS_CSS_RESETS_EXHAUSTED 0xC000030B
+#define STATUS_PKINIT_FAILURE 0xC0000320
+#define STATUS_SMARTCARD_SUBSYSTEM_FAILURE 0xC0000321
+#define STATUS_NO_KERB_KEY 0xC0000322
+#define STATUS_HOST_DOWN 0xC0000350
+#define STATUS_UNSUPPORTED_PREAUTH 0xC0000351
+#define STATUS_EFS_ALG_BLOB_TOO_BIG 0xC0000352
+#define STATUS_PORT_NOT_SET 0xC0000353
+#define STATUS_DEBUGGER_INACTIVE 0xC0000354
+#define STATUS_DS_VERSION_CHECK_FAILURE 0xC0000355
+#define STATUS_AUDITING_DISABLED 0xC0000356
+#define STATUS_PRENT4_MACHINE_ACCOUNT 0xC0000357
+#define STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER 0xC0000358
+#define STATUS_INVALID_IMAGE_WIN_32 0xC0000359
+#define STATUS_INVALID_IMAGE_WIN_64 0xC000035A
+#define STATUS_BAD_BINDINGS 0xC000035B
+#define STATUS_NETWORK_SESSION_EXPIRED 0xC000035C
+#define STATUS_APPHELP_BLOCK 0xC000035D
+#define STATUS_ALL_SIDS_FILTERED 0xC000035E
+#define STATUS_NOT_SAFE_MODE_DRIVER 0xC000035F
+#define STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT 0xC0000361
+#define STATUS_ACCESS_DISABLED_BY_POLICY_PATH 0xC0000362
+#define STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER 0xC0000363
+#define STATUS_ACCESS_DISABLED_BY_POLICY_OTHER 0xC0000364
+#define STATUS_FAILED_DRIVER_ENTRY 0xC0000365
+#define STATUS_DEVICE_ENUMERATION_ERROR 0xC0000366
+#define STATUS_MOUNT_POINT_NOT_RESOLVED 0xC0000368
+#define STATUS_INVALID_DEVICE_OBJECT_PARAMETER 0xC0000369
+#define STATUS_MCA_OCCURED 0xC000036A
+#define STATUS_DRIVER_BLOCKED_CRITICAL 0xC000036B
+#define STATUS_DRIVER_BLOCKED 0xC000036C
+#define STATUS_DRIVER_DATABASE_ERROR 0xC000036D
+#define STATUS_SYSTEM_HIVE_TOO_LARGE 0xC000036E
+#define STATUS_INVALID_IMPORT_OF_NON_DLL 0xC000036F
+#define STATUS_NO_SECRETS 0xC0000371
+#define STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY 0xC0000372
+#define STATUS_FAILED_STACK_SWITCH 0xC0000373
+#define STATUS_HEAP_CORRUPTION 0xC0000374
+#define STATUS_SMARTCARD_WRONG_PIN 0xC0000380
+#define STATUS_SMARTCARD_CARD_BLOCKED 0xC0000381
+#define STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED 0xC0000382
+#define STATUS_SMARTCARD_NO_CARD 0xC0000383
+#define STATUS_SMARTCARD_NO_KEY_CONTAINER 0xC0000384
+#define STATUS_SMARTCARD_NO_CERTIFICATE 0xC0000385
+#define STATUS_SMARTCARD_NO_KEYSET 0xC0000386
+#define STATUS_SMARTCARD_IO_ERROR 0xC0000387
+#define STATUS_DOWNGRADE_DETECTED 0xC0000388
+#define STATUS_SMARTCARD_CERT_REVOKED 0xC0000389
+#define STATUS_ISSUING_CA_UNTRUSTED 0xC000038A
+#define STATUS_REVOCATION_OFFLINE_C 0xC000038B
+#define STATUS_PKINIT_CLIENT_FAILURE 0xC000038C
+#define STATUS_SMARTCARD_CERT_EXPIRED 0xC000038D
+#define STATUS_DRIVER_FAILED_PRIOR_UNLOAD 0xC000038E
+#define STATUS_SMARTCARD_SILENT_CONTEXT 0xC000038F
+#define STATUS_PER_USER_TRUST_QUOTA_EXCEEDED 0xC0000401
+#define STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED 0xC0000402
+#define STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED 0xC0000403
+#define STATUS_DS_NAME_NOT_UNIQUE 0xC0000404
+#define STATUS_DS_DUPLICATE_ID_FOUND 0xC0000405
+#define STATUS_DS_GROUP_CONVERSION_ERROR 0xC0000406
+#define STATUS_VOLSNAP_PREPARE_HIBERNATE 0xC0000407
+#define STATUS_USER2USER_REQUIRED 0xC0000408
+#define STATUS_STACK_BUFFER_OVERRUN 0xC0000409
+#define STATUS_NO_S4U_PROT_SUPPORT 0xC000040A
+#define STATUS_CROSSREALM_DELEGATION_FAILURE 0xC000040B
+#define STATUS_REVOCATION_OFFLINE_KDC 0xC000040C
+#define STATUS_ISSUING_CA_UNTRUSTED_KDC 0xC000040D
+#define STATUS_KDC_CERT_EXPIRED 0xC000040E
+#define STATUS_KDC_CERT_REVOKED 0xC000040F
+#define STATUS_PARAMETER_QUOTA_EXCEEDED 0xC0000410
+#define STATUS_HIBERNATION_FAILURE 0xC0000411
+#define STATUS_DELAY_LOAD_FAILED 0xC0000412
+#define STATUS_AUTHENTICATION_FIREWALL_FAILED 0xC0000413
+#define STATUS_VDM_DISALLOWED 0xC0000414
+#define STATUS_HUNG_DISPLAY_DRIVER_THREAD 0xC0000415
+#define STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE 0xC0000416
+#define STATUS_INVALID_CRUNTIME_PARAMETER 0xC0000417
+#define STATUS_NTLM_BLOCKED 0xC0000418
+#define STATUS_ASSERTION_FAILURE 0xC0000420
+#define STATUS_VERIFIER_STOP 0xC0000421
+#define STATUS_CALLBACK_POP_STACK 0xC0000423
+#define STATUS_INCOMPATIBLE_DRIVER_BLOCKED 0xC0000424
+#define STATUS_HIVE_UNLOADED 0xC0000425
+#define STATUS_COMPRESSION_DISABLED 0xC0000426
+#define STATUS_FILE_SYSTEM_LIMITATION 0xC0000427
+#define STATUS_INVALID_IMAGE_HASH 0xC0000428
+#define STATUS_NOT_CAPABLE 0xC0000429
+#define STATUS_REQUEST_OUT_OF_SEQUENCE 0xC000042A
+#define STATUS_IMPLEMENTATION_LIMIT 0xC000042B
+#define STATUS_ELEVATION_REQUIRED 0xC000042C
+#define STATUS_BEYOND_VDL 0xC0000432
+#define STATUS_ENCOUNTERED_WRITE_IN_PROGRESS 0xC0000433
+#define STATUS_PTE_CHANGED 0xC0000434
+#define STATUS_PURGE_FAILED 0xC0000435
+#define STATUS_CRED_REQUIRES_CONFIRMATION 0xC0000440
+#define STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE 0xC0000441
+#define STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER 0xC0000442
+#define STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE 0xC0000443
+#define STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE 0xC0000444
+#define STATUS_CS_ENCRYPTION_FILE_NOT_CSE 0xC0000445
+#define STATUS_INVALID_LABEL 0xC0000446
+#define STATUS_DRIVER_PROCESS_TERMINATED 0xC0000450
+#define STATUS_AMBIGUOUS_SYSTEM_DEVICE 0xC0000451
+#define STATUS_SYSTEM_DEVICE_NOT_FOUND 0xC0000452
+#define STATUS_RESTART_BOOT_APPLICATION 0xC0000453
+#define STATUS_INVALID_TASK_NAME 0xC0000500
+#define STATUS_INVALID_TASK_INDEX 0xC0000501
+#define STATUS_THREAD_ALREADY_IN_TASK 0xC0000502
+#define STATUS_CALLBACK_BYPASS 0xC0000503
+#define STATUS_PORT_CLOSED 0xC0000700
+#define STATUS_MESSAGE_LOST 0xC0000701
+#define STATUS_INVALID_MESSAGE 0xC0000702
+#define STATUS_REQUEST_CANCELED 0xC0000703
+#define STATUS_RECURSIVE_DISPATCH 0xC0000704
+#define STATUS_LPC_RECEIVE_BUFFER_EXPECTED 0xC0000705
+#define STATUS_LPC_INVALID_CONNECTION_USAGE 0xC0000706
+#define STATUS_LPC_REQUESTS_NOT_ALLOWED 0xC0000707
+#define STATUS_RESOURCE_IN_USE 0xC0000708
+#define STATUS_HARDWARE_MEMORY_ERROR 0xC0000709
+#define STATUS_THREADPOOL_HANDLE_EXCEPTION 0xC000070A
+#define STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED 0xC000070B
+#define STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED 0xC000070C
+#define STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED 0xC000070D
+#define STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED 0xC000070E
+#define STATUS_THREADPOOL_RELEASED_DURING_OPERATION 0xC000070F
+#define STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING 0xC0000710
+#define STATUS_APC_RETURNED_WHILE_IMPERSONATING 0xC0000711
+#define STATUS_PROCESS_IS_PROTECTED 0xC0000712
+#define STATUS_MCA_EXCEPTION 0xC0000713
+#define STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE 0xC0000714
+#define STATUS_SYMLINK_CLASS_DISABLED 0xC0000715
+#define STATUS_INVALID_IDN_NORMALIZATION 0xC0000716
+#define STATUS_NO_UNICODE_TRANSLATION 0xC0000717
+#define STATUS_ALREADY_REGISTERED 0xC0000718
+#define STATUS_CONTEXT_MISMATCH 0xC0000719
+#define STATUS_PORT_ALREADY_HAS_COMPLETION_LIST 0xC000071A
+#define STATUS_CALLBACK_RETURNED_THREAD_PRIORITY 0xC000071B
+#define STATUS_INVALID_THREAD 0xC000071C
+#define STATUS_CALLBACK_RETURNED_TRANSACTION 0xC000071D
+#define STATUS_CALLBACK_RETURNED_LDR_LOCK 0xC000071E
+#define STATUS_CALLBACK_RETURNED_LANG 0xC000071F
+#define STATUS_CALLBACK_RETURNED_PRI_BACK 0xC0000720
+#define STATUS_CALLBACK_RETURNED_THREAD_AFFINITY 0xC0000721
+#define STATUS_DISK_REPAIR_DISABLED 0xC0000800
+#define STATUS_DS_DOMAIN_RENAME_IN_PROGRESS 0xC0000801
+#define STATUS_DISK_QUOTA_EXCEEDED 0xC0000802
+#define STATUS_CONTENT_BLOCKED 0xC0000804
+#define STATUS_BAD_CLUSTERS 0xC0000805
+#define STATUS_VOLUME_DIRTY 0xC0000806
+#define STATUS_FILE_CHECKED_OUT 0xC0000901
+#define STATUS_CHECKOUT_REQUIRED 0xC0000902
+#define STATUS_BAD_FILE_TYPE 0xC0000903
+#define STATUS_FILE_TOO_LARGE 0xC0000904
+#define STATUS_FORMS_AUTH_REQUIRED 0xC0000905
+#define STATUS_VIRUS_INFECTED 0xC0000906
+#define STATUS_VIRUS_DELETED 0xC0000907
+#define STATUS_BAD_MCFG_TABLE 0xC0000908
+#define STATUS_WOW_ASSERTION 0xC0009898
+#define STATUS_INVALID_SIGNATURE 0xC000A000
+#define STATUS_HMAC_NOT_SUPPORTED 0xC000A001
+#define STATUS_IPSEC_QUEUE_OVERFLOW 0xC000A010
+#define STATUS_ND_QUEUE_OVERFLOW 0xC000A011
+#define STATUS_HOPLIMIT_EXCEEDED 0xC000A012
+#define STATUS_PROTOCOL_NOT_SUPPORTED 0xC000A013
+#define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED 0xC000A080
+#define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR 0xC000A081
+#define STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR 0xC000A082
+#define STATUS_XML_PARSE_ERROR 0xC000A083
+#define STATUS_XMLDSIG_ERROR 0xC000A084
+#define STATUS_WRONG_COMPARTMENT 0xC000A085
+#define STATUS_AUTHIP_FAILURE 0xC000A086
+#define DBG_NO_STATE_CHANGE 0xC0010001
+#define DBG_APP_NOT_IDLE 0xC0010002
+#define RPC_NT_INVALID_STRING_BINDING 0xC0020001
+#define RPC_NT_WRONG_KIND_OF_BINDING 0xC0020002
+#define RPC_NT_INVALID_BINDING 0xC0020003
+#define RPC_NT_PROTSEQ_NOT_SUPPORTED 0xC0020004
+#define RPC_NT_INVALID_RPC_PROTSEQ 0xC0020005
+#define RPC_NT_INVALID_STRING_UUID 0xC0020006
+#define RPC_NT_INVALID_ENDPOINT_FORMAT 0xC0020007
+#define RPC_NT_INVALID_NET_ADDR 0xC0020008
+#define RPC_NT_NO_ENDPOINT_FOUND 0xC0020009
+#define RPC_NT_INVALID_TIMEOUT 0xC002000A
+#define RPC_NT_OBJECT_NOT_FOUND 0xC002000B
+#define RPC_NT_ALREADY_REGISTERED 0xC002000C
+#define RPC_NT_TYPE_ALREADY_REGISTERED 0xC002000D
+#define RPC_NT_ALREADY_LISTENING 0xC002000E
+#define RPC_NT_NO_PROTSEQS_REGISTERED 0xC002000F
+#define RPC_NT_NOT_LISTENING 0xC0020010
+#define RPC_NT_UNKNOWN_MGR_TYPE 0xC0020011
+#define RPC_NT_UNKNOWN_IF 0xC0020012
+#define RPC_NT_NO_BINDINGS 0xC0020013
+#define RPC_NT_NO_PROTSEQS 0xC0020014
+#define RPC_NT_CANT_CREATE_ENDPOINT 0xC0020015
+#define RPC_NT_OUT_OF_RESOURCES 0xC0020016
+#define RPC_NT_SERVER_UNAVAILABLE 0xC0020017
+#define RPC_NT_SERVER_TOO_BUSY 0xC0020018
+#define RPC_NT_INVALID_NETWORK_OPTIONS 0xC0020019
+#define RPC_NT_NO_CALL_ACTIVE 0xC002001A
+#define RPC_NT_CALL_FAILED 0xC002001B
+#define RPC_NT_CALL_FAILED_DNE 0xC002001C
+#define RPC_NT_PROTOCOL_ERROR 0xC002001D
+#define RPC_NT_UNSUPPORTED_TRANS_SYN 0xC002001F
+#define RPC_NT_UNSUPPORTED_TYPE 0xC0020021
+#define RPC_NT_INVALID_TAG 0xC0020022
+#define RPC_NT_INVALID_BOUND 0xC0020023
+#define RPC_NT_NO_ENTRY_NAME 0xC0020024
+#define RPC_NT_INVALID_NAME_SYNTAX 0xC0020025
+#define RPC_NT_UNSUPPORTED_NAME_SYNTAX 0xC0020026
+#define RPC_NT_UUID_NO_ADDRESS 0xC0020028
+#define RPC_NT_DUPLICATE_ENDPOINT 0xC0020029
+#define RPC_NT_UNKNOWN_AUTHN_TYPE 0xC002002A
+#define RPC_NT_MAX_CALLS_TOO_SMALL 0xC002002B
+#define RPC_NT_STRING_TOO_LONG 0xC002002C
+#define RPC_NT_PROTSEQ_NOT_FOUND 0xC002002D
+#define RPC_NT_PROCNUM_OUT_OF_RANGE 0xC002002E
+#define RPC_NT_BINDING_HAS_NO_AUTH 0xC002002F
+#define RPC_NT_UNKNOWN_AUTHN_SERVICE 0xC0020030
+#define RPC_NT_UNKNOWN_AUTHN_LEVEL 0xC0020031
+#define RPC_NT_INVALID_AUTH_IDENTITY 0xC0020032
+#define RPC_NT_UNKNOWN_AUTHZ_SERVICE 0xC0020033
+#define EPT_NT_INVALID_ENTRY 0xC0020034
+#define EPT_NT_CANT_PERFORM_OP 0xC0020035
+#define EPT_NT_NOT_REGISTERED 0xC0020036
+#define RPC_NT_NOTHING_TO_EXPORT 0xC0020037
+#define RPC_NT_INCOMPLETE_NAME 0xC0020038
+#define RPC_NT_INVALID_VERS_OPTION 0xC0020039
+#define RPC_NT_NO_MORE_MEMBERS 0xC002003A
+#define RPC_NT_NOT_ALL_OBJS_UNEXPORTED 0xC002003B
+#define RPC_NT_INTERFACE_NOT_FOUND 0xC002003C
+#define RPC_NT_ENTRY_ALREADY_EXISTS 0xC002003D
+#define RPC_NT_ENTRY_NOT_FOUND 0xC002003E
+#define RPC_NT_NAME_SERVICE_UNAVAILABLE 0xC002003F
+#define RPC_NT_INVALID_NAF_ID 0xC0020040
+#define RPC_NT_CANNOT_SUPPORT 0xC0020041
+#define RPC_NT_NO_CONTEXT_AVAILABLE 0xC0020042
+#define RPC_NT_INTERNAL_ERROR 0xC0020043
+#define RPC_NT_ZERO_DIVIDE 0xC0020044
+#define RPC_NT_ADDRESS_ERROR 0xC0020045
+#define RPC_NT_FP_DIV_ZERO 0xC0020046
+#define RPC_NT_FP_UNDERFLOW 0xC0020047
+#define RPC_NT_FP_OVERFLOW 0xC0020048
+#define RPC_NT_CALL_IN_PROGRESS 0xC0020049
+#define RPC_NT_NO_MORE_BINDINGS 0xC002004A
+#define RPC_NT_GROUP_MEMBER_NOT_FOUND 0xC002004B
+#define EPT_NT_CANT_CREATE 0xC002004C
+#define RPC_NT_INVALID_OBJECT 0xC002004D
+#define RPC_NT_NO_INTERFACES 0xC002004F
+#define RPC_NT_CALL_CANCELLED 0xC0020050
+#define RPC_NT_BINDING_INCOMPLETE 0xC0020051
+#define RPC_NT_COMM_FAILURE 0xC0020052
+#define RPC_NT_UNSUPPORTED_AUTHN_LEVEL 0xC0020053
+#define RPC_NT_NO_PRINC_NAME 0xC0020054
+#define RPC_NT_NOT_RPC_ERROR 0xC0020055
+#define RPC_NT_SEC_PKG_ERROR 0xC0020057
+#define RPC_NT_NOT_CANCELLED 0xC0020058
+#define RPC_NT_INVALID_ASYNC_HANDLE 0xC0020062
+#define RPC_NT_INVALID_ASYNC_CALL 0xC0020063
+#define RPC_NT_PROXY_ACCESS_DENIED 0xC0020064
+#define RPC_NT_NO_MORE_ENTRIES 0xC0030001
+#define RPC_NT_SS_CHAR_TRANS_OPEN_FAIL 0xC0030002
+#define RPC_NT_SS_CHAR_TRANS_SHORT_FILE 0xC0030003
+#define RPC_NT_SS_IN_NULL_CONTEXT 0xC0030004
+#define RPC_NT_SS_CONTEXT_MISMATCH 0xC0030005
+#define RPC_NT_SS_CONTEXT_DAMAGED 0xC0030006
+#define RPC_NT_SS_HANDLES_MISMATCH 0xC0030007
+#define RPC_NT_SS_CANNOT_GET_CALL_HANDLE 0xC0030008
+#define RPC_NT_NULL_REF_POINTER 0xC0030009
+#define RPC_NT_ENUM_VALUE_OUT_OF_RANGE 0xC003000A
+#define RPC_NT_BYTE_COUNT_TOO_SMALL 0xC003000B
+#define RPC_NT_BAD_STUB_DATA 0xC003000C
+#define RPC_NT_INVALID_ES_ACTION 0xC0030059
+#define RPC_NT_WRONG_ES_VERSION 0xC003005A
+#define RPC_NT_WRONG_STUB_VERSION 0xC003005B
+#define RPC_NT_INVALID_PIPE_OBJECT 0xC003005C
+#define RPC_NT_INVALID_PIPE_OPERATION 0xC003005D
+#define RPC_NT_WRONG_PIPE_VERSION 0xC003005E
+#define RPC_NT_PIPE_CLOSED 0xC003005F
+#define RPC_NT_PIPE_DISCIPLINE_ERROR 0xC0030060
+#define RPC_NT_PIPE_EMPTY 0xC0030061
+#define STATUS_PNP_BAD_MPS_TABLE 0xC0040035
+#define STATUS_PNP_TRANSLATION_FAILED 0xC0040036
+#define STATUS_PNP_IRQ_TRANSLATION_FAILED 0xC0040037
+#define STATUS_PNP_INVALID_ID 0xC0040038
+#define STATUS_IO_REISSUE_AS_CACHED 0xC0040039
+#define STATUS_CTX_WINSTATION_NAME_INVALID 0xC00A0001
+#define STATUS_CTX_INVALID_PD 0xC00A0002
+#define STATUS_CTX_PD_NOT_FOUND 0xC00A0003
+#define STATUS_CTX_CLOSE_PENDING 0xC00A0006
+#define STATUS_CTX_NO_OUTBUF 0xC00A0007
+#define STATUS_CTX_MODEM_INF_NOT_FOUND 0xC00A0008
+#define STATUS_CTX_INVALID_MODEMNAME 0xC00A0009
+#define STATUS_CTX_RESPONSE_ERROR 0xC00A000A
+#define STATUS_CTX_MODEM_RESPONSE_TIMEOUT 0xC00A000B
+#define STATUS_CTX_MODEM_RESPONSE_NO_CARRIER 0xC00A000C
+#define STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE 0xC00A000D
+#define STATUS_CTX_MODEM_RESPONSE_BUSY 0xC00A000E
+#define STATUS_CTX_MODEM_RESPONSE_VOICE 0xC00A000F
+#define STATUS_CTX_TD_ERROR 0xC00A0010
+#define STATUS_CTX_LICENSE_CLIENT_INVALID 0xC00A0012
+#define STATUS_CTX_LICENSE_NOT_AVAILABLE 0xC00A0013
+#define STATUS_CTX_LICENSE_EXPIRED 0xC00A0014
+#define STATUS_CTX_WINSTATION_NOT_FOUND 0xC00A0015
+#define STATUS_CTX_WINSTATION_NAME_COLLISION 0xC00A0016
+#define STATUS_CTX_WINSTATION_BUSY 0xC00A0017
+#define STATUS_CTX_BAD_VIDEO_MODE 0xC00A0018
+#define STATUS_CTX_GRAPHICS_INVALID 0xC00A0022
+#define STATUS_CTX_NOT_CONSOLE 0xC00A0024
+#define STATUS_CTX_CLIENT_QUERY_TIMEOUT 0xC00A0026
+#define STATUS_CTX_CONSOLE_DISCONNECT 0xC00A0027
+#define STATUS_CTX_CONSOLE_CONNECT 0xC00A0028
+#define STATUS_CTX_SHADOW_DENIED 0xC00A002A
+#define STATUS_CTX_WINSTATION_ACCESS_DENIED 0xC00A002B
+#define STATUS_CTX_INVALID_WD 0xC00A002E
+#define STATUS_CTX_WD_NOT_FOUND 0xC00A002F
+#define STATUS_CTX_SHADOW_INVALID 0xC00A0030
+#define STATUS_CTX_SHADOW_DISABLED 0xC00A0031
+#define STATUS_RDP_PROTOCOL_ERROR 0xC00A0032
+#define STATUS_CTX_CLIENT_LICENSE_NOT_SET 0xC00A0033
+#define STATUS_CTX_CLIENT_LICENSE_IN_USE 0xC00A0034
+#define STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE 0xC00A0035
+#define STATUS_CTX_SHADOW_NOT_RUNNING 0xC00A0036
+#define STATUS_CTX_LOGON_DISABLED 0xC00A0037
+#define STATUS_CTX_SECURITY_LAYER_ERROR 0xC00A0038
+#define STATUS_TS_INCOMPATIBLE_SESSIONS 0xC00A0039
+#define STATUS_MUI_FILE_NOT_FOUND 0xC00B0001
+#define STATUS_MUI_INVALID_FILE 0xC00B0002
+#define STATUS_MUI_INVALID_RC_CONFIG 0xC00B0003
+#define STATUS_MUI_INVALID_LOCALE_NAME 0xC00B0004
+#define STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME 0xC00B0005
+#define STATUS_MUI_FILE_NOT_LOADED 0xC00B0006
+#define STATUS_RESOURCE_ENUM_USER_STOP 0xC00B0007
+#define STATUS_CLUSTER_INVALID_NODE 0xC0130001
+#define STATUS_CLUSTER_NODE_EXISTS 0xC0130002
+#define STATUS_CLUSTER_JOIN_IN_PROGRESS 0xC0130003
+#define STATUS_CLUSTER_NODE_NOT_FOUND 0xC0130004
+#define STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND 0xC0130005
+#define STATUS_CLUSTER_NETWORK_EXISTS 0xC0130006
+#define STATUS_CLUSTER_NETWORK_NOT_FOUND 0xC0130007
+#define STATUS_CLUSTER_NETINTERFACE_EXISTS 0xC0130008
+#define STATUS_CLUSTER_NETINTERFACE_NOT_FOUND 0xC0130009
+#define STATUS_CLUSTER_INVALID_REQUEST 0xC013000A
+#define STATUS_CLUSTER_INVALID_NETWORK_PROVIDER 0xC013000B
+#define STATUS_CLUSTER_NODE_DOWN 0xC013000C
+#define STATUS_CLUSTER_NODE_UNREACHABLE 0xC013000D
+#define STATUS_CLUSTER_NODE_NOT_MEMBER 0xC013000E
+#define STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS 0xC013000F
+#define STATUS_CLUSTER_INVALID_NETWORK 0xC0130010
+#define STATUS_CLUSTER_NO_NET_ADAPTERS 0xC0130011
+#define STATUS_CLUSTER_NODE_UP 0xC0130012
+#define STATUS_CLUSTER_NODE_PAUSED 0xC0130013
+#define STATUS_CLUSTER_NODE_NOT_PAUSED 0xC0130014
+#define STATUS_CLUSTER_NO_SECURITY_CONTEXT 0xC0130015
+#define STATUS_CLUSTER_NETWORK_NOT_INTERNAL 0xC0130016
+#define STATUS_CLUSTER_POISONED 0xC0130017
+#define STATUS_ACPI_INVALID_OPCODE 0xC0140001
+#define STATUS_ACPI_STACK_OVERFLOW 0xC0140002
+#define STATUS_ACPI_ASSERT_FAILED 0xC0140003
+#define STATUS_ACPI_INVALID_INDEX 0xC0140004
+#define STATUS_ACPI_INVALID_ARGUMENT 0xC0140005
+#define STATUS_ACPI_FATAL 0xC0140006
+#define STATUS_ACPI_INVALID_SUPERNAME 0xC0140007
+#define STATUS_ACPI_INVALID_ARGTYPE 0xC0140008
+#define STATUS_ACPI_INVALID_OBJTYPE 0xC0140009
+#define STATUS_ACPI_INVALID_TARGETTYPE 0xC014000A
+#define STATUS_ACPI_INCORRECT_ARGUMENT_COUNT 0xC014000B
+#define STATUS_ACPI_ADDRESS_NOT_MAPPED 0xC014000C
+#define STATUS_ACPI_INVALID_EVENTTYPE 0xC014000D
+#define STATUS_ACPI_HANDLER_COLLISION 0xC014000E
+#define STATUS_ACPI_INVALID_DATA 0xC014000F
+#define STATUS_ACPI_INVALID_REGION 0xC0140010
+#define STATUS_ACPI_INVALID_ACCESS_SIZE 0xC0140011
+#define STATUS_ACPI_ACQUIRE_GLOBAL_LOCK 0xC0140012
+#define STATUS_ACPI_ALREADY_INITIALIZED 0xC0140013
+#define STATUS_ACPI_NOT_INITIALIZED 0xC0140014
+#define STATUS_ACPI_INVALID_MUTEX_LEVEL 0xC0140015
+#define STATUS_ACPI_MUTEX_NOT_OWNED 0xC0140016
+#define STATUS_ACPI_MUTEX_NOT_OWNER 0xC0140017
+#define STATUS_ACPI_RS_ACCESS 0xC0140018
+#define STATUS_ACPI_INVALID_TABLE 0xC0140019
+#define STATUS_ACPI_REG_HANDLER_FAILED 0xC0140020
+#define STATUS_ACPI_POWER_REQUEST_FAILED 0xC0140021
+#define STATUS_SXS_SECTION_NOT_FOUND 0xC0150001
+#define STATUS_SXS_CANT_GEN_ACTCTX 0xC0150002
+#define STATUS_SXS_INVALID_ACTCTXDATA_FORMAT 0xC0150003
+#define STATUS_SXS_ASSEMBLY_NOT_FOUND 0xC0150004
+#define STATUS_SXS_MANIFEST_FORMAT_ERROR 0xC0150005
+#define STATUS_SXS_MANIFEST_PARSE_ERROR 0xC0150006
+#define STATUS_SXS_ACTIVATION_CONTEXT_DISABLED 0xC0150007
+#define STATUS_SXS_KEY_NOT_FOUND 0xC0150008
+#define STATUS_SXS_VERSION_CONFLICT 0xC0150009
+#define STATUS_SXS_WRONG_SECTION_TYPE 0xC015000A
+#define STATUS_SXS_THREAD_QUERIES_DISABLED 0xC015000B
+#define STATUS_SXS_ASSEMBLY_MISSING 0xC015000C
+#define STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET 0xC015000E
+#define STATUS_SXS_EARLY_DEACTIVATION 0xC015000F
+#define STATUS_SXS_INVALID_DEACTIVATION 0xC0150010
+#define STATUS_SXS_MULTIPLE_DEACTIVATION 0xC0150011
+#define STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY 0xC0150012
+#define STATUS_SXS_PROCESS_TERMINATION_REQUESTED 0xC0150013
+#define STATUS_SXS_CORRUPT_ACTIVATION_STACK 0xC0150014
+#define STATUS_SXS_CORRUPTION 0xC0150015
+#define STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE 0xC0150016
+#define STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME 0xC0150017
+#define STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE 0xC0150018
+#define STATUS_SXS_IDENTITY_PARSE_ERROR 0xC0150019
+#define STATUS_SXS_COMPONENT_STORE_CORRUPT 0xC015001A
+#define STATUS_SXS_FILE_HASH_MISMATCH 0xC015001B
+#define STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT 0xC015001C
+#define STATUS_SXS_IDENTITIES_DIFFERENT 0xC015001D
+#define STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT 0xC015001E
+#define STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY 0xC015001F
+#define STATUS_ADVANCED_INSTALLER_FAILED 0xC0150020
+#define STATUS_XML_ENCODING_MISMATCH 0xC0150021
+#define STATUS_SXS_MANIFEST_TOO_BIG 0xC0150022
+#define STATUS_SXS_SETTING_NOT_REGISTERED 0xC0150023
+#define STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE 0xC0150024
+#define STATUS_SMI_PRIMITIVE_INSTALLER_FAILED 0xC0150025
+#define STATUS_GENERIC_COMMAND_FAILED 0xC0150026
+#define STATUS_SXS_FILE_HASH_MISSING 0xC0150027
+#define STATUS_TRANSACTIONAL_CONFLICT 0xC0190001
+#define STATUS_INVALID_TRANSACTION 0xC0190002
+#define STATUS_TRANSACTION_NOT_ACTIVE 0xC0190003
+#define STATUS_TM_INITIALIZATION_FAILED 0xC0190004
+#define STATUS_RM_NOT_ACTIVE 0xC0190005
+#define STATUS_RM_METADATA_CORRUPT 0xC0190006
+#define STATUS_TRANSACTION_NOT_JOINED 0xC0190007
+#define STATUS_DIRECTORY_NOT_RM 0xC0190008
+#define STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE 0xC019000A
+#define STATUS_LOG_RESIZE_INVALID_SIZE 0xC019000B
+#define STATUS_REMOTE_FILE_VERSION_MISMATCH 0xC019000C
+#define STATUS_CRM_PROTOCOL_ALREADY_EXISTS 0xC019000F
+#define STATUS_TRANSACTION_PROPAGATION_FAILED 0xC0190010
+#define STATUS_CRM_PROTOCOL_NOT_FOUND 0xC0190011
+#define STATUS_TRANSACTION_SUPERIOR_EXISTS 0xC0190012
+#define STATUS_TRANSACTION_REQUEST_NOT_VALID 0xC0190013
+#define STATUS_TRANSACTION_NOT_REQUESTED 0xC0190014
+#define STATUS_TRANSACTION_ALREADY_ABORTED 0xC0190015
+#define STATUS_TRANSACTION_ALREADY_COMMITTED 0xC0190016
+#define STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER 0xC0190017
+#define STATUS_CURRENT_TRANSACTION_NOT_VALID 0xC0190018
+#define STATUS_LOG_GROWTH_FAILED 0xC0190019
+#define STATUS_OBJECT_NO_LONGER_EXISTS 0xC0190021
+#define STATUS_STREAM_MINIVERSION_NOT_FOUND 0xC0190022
+#define STATUS_STREAM_MINIVERSION_NOT_VALID 0xC0190023
+#define STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION 0xC0190024
+#define STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT 0xC0190025
+#define STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS 0xC0190026
+#define STATUS_HANDLE_NO_LONGER_VALID 0xC0190028
+#define STATUS_LOG_CORRUPTION_DETECTED 0xC0190030
+#define STATUS_RM_DISCONNECTED 0xC0190032
+#define STATUS_ENLISTMENT_NOT_SUPERIOR 0xC0190033
+#define STATUS_FILE_IDENTITY_NOT_PERSISTENT 0xC0190036
+#define STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY 0xC0190037
+#define STATUS_CANT_CROSS_RM_BOUNDARY 0xC0190038
+#define STATUS_TXF_DIR_NOT_EMPTY 0xC0190039
+#define STATUS_INDOUBT_TRANSACTIONS_EXIST 0xC019003A
+#define STATUS_TM_VOLATILE 0xC019003B
+#define STATUS_ROLLBACK_TIMER_EXPIRED 0xC019003C
+#define STATUS_TXF_ATTRIBUTE_CORRUPT 0xC019003D
+#define STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION 0xC019003E
+#define STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED 0xC019003F
+#define STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE 0xC0190040
+#define STATUS_TRANSACTION_REQUIRED_PROMOTION 0xC0190043
+#define STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION 0xC0190044
+#define STATUS_TRANSACTIONS_NOT_FROZEN 0xC0190045
+#define STATUS_TRANSACTION_FREEZE_IN_PROGRESS 0xC0190046
+#define STATUS_NOT_SNAPSHOT_VOLUME 0xC0190047
+#define STATUS_NO_SAVEPOINT_WITH_OPEN_FILES 0xC0190048
+#define STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION 0xC0190049
+#define STATUS_TM_IDENTITY_MISMATCH 0xC019004A
+#define STATUS_FLOATED_SECTION 0xC019004B
+#define STATUS_CANNOT_ACCEPT_TRANSACTED_WORK 0xC019004C
+#define STATUS_CANNOT_ABORT_TRANSACTIONS 0xC019004D
+#define STATUS_TRANSACTION_NOT_FOUND 0xC019004E
+#define STATUS_RESOURCEMANAGER_NOT_FOUND 0xC019004F
+#define STATUS_ENLISTMENT_NOT_FOUND 0xC0190050
+#define STATUS_TRANSACTIONMANAGER_NOT_FOUND 0xC0190051
+#define STATUS_TRANSACTIONMANAGER_NOT_ONLINE 0xC0190052
+#define STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION 0xC0190053
+#define STATUS_TRANSACTION_NOT_ROOT 0xC0190054
+#define STATUS_TRANSACTION_OBJECT_EXPIRED 0xC0190055
+#define STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION 0xC0190056
+#define STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED 0xC0190057
+#define STATUS_TRANSACTION_RECORD_TOO_LONG 0xC0190058
+#define STATUS_NO_LINK_TRACKING_IN_TRANSACTION 0xC0190059
+#define STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION 0xC019005A
+#define STATUS_TRANSACTION_INTEGRITY_VIOLATED 0xC019005B
+#define STATUS_LOG_SECTOR_INVALID 0xC01A0001
+#define STATUS_LOG_SECTOR_PARITY_INVALID 0xC01A0002
+#define STATUS_LOG_SECTOR_REMAPPED 0xC01A0003
+#define STATUS_LOG_BLOCK_INCOMPLETE 0xC01A0004
+#define STATUS_LOG_INVALID_RANGE 0xC01A0005
+#define STATUS_LOG_BLOCKS_EXHAUSTED 0xC01A0006
+#define STATUS_LOG_READ_CONTEXT_INVALID 0xC01A0007
+#define STATUS_LOG_RESTART_INVALID 0xC01A0008
+#define STATUS_LOG_BLOCK_VERSION 0xC01A0009
+#define STATUS_LOG_BLOCK_INVALID 0xC01A000A
+#define STATUS_LOG_READ_MODE_INVALID 0xC01A000B
+#define STATUS_LOG_METADATA_CORRUPT 0xC01A000D
+#define STATUS_LOG_METADATA_INVALID 0xC01A000E
+#define STATUS_LOG_METADATA_INCONSISTENT 0xC01A000F
+#define STATUS_LOG_RESERVATION_INVALID 0xC01A0010
+#define STATUS_LOG_CANT_DELETE 0xC01A0011
+#define STATUS_LOG_CONTAINER_LIMIT_EXCEEDED 0xC01A0012
+#define STATUS_LOG_START_OF_LOG 0xC01A0013
+#define STATUS_LOG_POLICY_ALREADY_INSTALLED 0xC01A0014
+#define STATUS_LOG_POLICY_NOT_INSTALLED 0xC01A0015
+#define STATUS_LOG_POLICY_INVALID 0xC01A0016
+#define STATUS_LOG_POLICY_CONFLICT 0xC01A0017
+#define STATUS_LOG_PINNED_ARCHIVE_TAIL 0xC01A0018
+#define STATUS_LOG_RECORD_NONEXISTENT 0xC01A0019
+#define STATUS_LOG_RECORDS_RESERVED_INVALID 0xC01A001A
+#define STATUS_LOG_SPACE_RESERVED_INVALID 0xC01A001B
+#define STATUS_LOG_TAIL_INVALID 0xC01A001C
+#define STATUS_LOG_FULL 0xC01A001D
+#define STATUS_LOG_MULTIPLEXED 0xC01A001E
+#define STATUS_LOG_DEDICATED 0xC01A001F
+#define STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS 0xC01A0020
+#define STATUS_LOG_ARCHIVE_IN_PROGRESS 0xC01A0021
+#define STATUS_LOG_EPHEMERAL 0xC01A0022
+#define STATUS_LOG_NOT_ENOUGH_CONTAINERS 0xC01A0023
+#define STATUS_LOG_CLIENT_ALREADY_REGISTERED 0xC01A0024
+#define STATUS_LOG_CLIENT_NOT_REGISTERED 0xC01A0025
+#define STATUS_LOG_FULL_HANDLER_IN_PROGRESS 0xC01A0026
+#define STATUS_LOG_CONTAINER_READ_FAILED 0xC01A0027
+#define STATUS_LOG_CONTAINER_WRITE_FAILED 0xC01A0028
+#define STATUS_LOG_CONTAINER_OPEN_FAILED 0xC01A0029
+#define STATUS_LOG_CONTAINER_STATE_INVALID 0xC01A002A
+#define STATUS_LOG_STATE_INVALID 0xC01A002B
+#define STATUS_LOG_PINNED 0xC01A002C
+#define STATUS_LOG_METADATA_FLUSH_FAILED 0xC01A002D
+#define STATUS_LOG_INCONSISTENT_SECURITY 0xC01A002E
+#define STATUS_LOG_APPENDED_FLUSH_FAILED 0xC01A002F
+#define STATUS_LOG_PINNED_RESERVATION 0xC01A0030
+#define STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD 0xC01B00EA
+#define STATUS_FLT_NO_HANDLER_DEFINED 0xC01C0001
+#define STATUS_FLT_CONTEXT_ALREADY_DEFINED 0xC01C0002
+#define STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST 0xC01C0003
+#define STATUS_FLT_DISALLOW_FAST_IO 0xC01C0004
+#define STATUS_FLT_INVALID_NAME_REQUEST 0xC01C0005
+#define STATUS_FLT_NOT_SAFE_TO_POST_OPERATION 0xC01C0006
+#define STATUS_FLT_NOT_INITIALIZED 0xC01C0007
+#define STATUS_FLT_FILTER_NOT_READY 0xC01C0008
+#define STATUS_FLT_POST_OPERATION_CLEANUP 0xC01C0009
+#define STATUS_FLT_INTERNAL_ERROR 0xC01C000A
+#define STATUS_FLT_DELETING_OBJECT 0xC01C000B
+#define STATUS_FLT_MUST_BE_NONPAGED_POOL 0xC01C000C
+#define STATUS_FLT_DUPLICATE_ENTRY 0xC01C000D
+#define STATUS_FLT_CBDQ_DISABLED 0xC01C000E
+#define STATUS_FLT_DO_NOT_ATTACH 0xC01C000F
+#define STATUS_FLT_DO_NOT_DETACH 0xC01C0010
+#define STATUS_FLT_INSTANCE_ALTITUDE_COLLISION 0xC01C0011
+#define STATUS_FLT_INSTANCE_NAME_COLLISION 0xC01C0012
+#define STATUS_FLT_FILTER_NOT_FOUND 0xC01C0013
+#define STATUS_FLT_VOLUME_NOT_FOUND 0xC01C0014
+#define STATUS_FLT_INSTANCE_NOT_FOUND 0xC01C0015
+#define STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND 0xC01C0016
+#define STATUS_FLT_INVALID_CONTEXT_REGISTRATION 0xC01C0017
+#define STATUS_FLT_NAME_CACHE_MISS 0xC01C0018
+#define STATUS_FLT_NO_DEVICE_OBJECT 0xC01C0019
+#define STATUS_FLT_VOLUME_ALREADY_MOUNTED 0xC01C001A
+#define STATUS_FLT_ALREADY_ENLISTED 0xC01C001B
+#define STATUS_FLT_CONTEXT_ALREADY_LINKED 0xC01C001C
+#define STATUS_FLT_NO_WAITER_FOR_REPLY 0xC01C0020
+#define STATUS_MONITOR_NO_DESCRIPTOR 0xC01D0001
+#define STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT 0xC01D0002
+#define STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM 0xC01D0003
+#define STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK 0xC01D0004
+#define STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED 0xC01D0005
+#define STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK 0xC01D0006
+#define STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK 0xC01D0007
+#define STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA 0xC01D0008
+#define STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK 0xC01D0009
+#define STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER 0xC01E0000
+#define STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER 0xC01E0001
+#define STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER 0xC01E0002
+#define STATUS_GRAPHICS_ADAPTER_WAS_RESET 0xC01E0003
+#define STATUS_GRAPHICS_INVALID_DRIVER_MODEL 0xC01E0004
+#define STATUS_GRAPHICS_PRESENT_MODE_CHANGED 0xC01E0005
+#define STATUS_GRAPHICS_PRESENT_OCCLUDED 0xC01E0006
+#define STATUS_GRAPHICS_PRESENT_DENIED 0xC01E0007
+#define STATUS_GRAPHICS_CANNOTCOLORCONVERT 0xC01E0008
+#define STATUS_GRAPHICS_NO_VIDEO_MEMORY 0xC01E0100
+#define STATUS_GRAPHICS_CANT_LOCK_MEMORY 0xC01E0101
+#define STATUS_GRAPHICS_ALLOCATION_BUSY 0xC01E0102
+#define STATUS_GRAPHICS_TOO_MANY_REFERENCES 0xC01E0103
+#define STATUS_GRAPHICS_TRY_AGAIN_LATER 0xC01E0104
+#define STATUS_GRAPHICS_TRY_AGAIN_NOW 0xC01E0105
+#define STATUS_GRAPHICS_ALLOCATION_INVALID 0xC01E0106
+#define STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE 0xC01E0107
+#define STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED 0xC01E0108
+#define STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION 0xC01E0109
+#define STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE 0xC01E0110
+#define STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION 0xC01E0111
+#define STATUS_GRAPHICS_ALLOCATION_CLOSED 0xC01E0112
+#define STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE 0xC01E0113
+#define STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE 0xC01E0114
+#define STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE 0xC01E0115
+#define STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST 0xC01E0116
+#define STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE 0xC01E0200
+#define STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY 0xC01E0300
+#define STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED 0xC01E0301
+#define STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED 0xC01E0302
+#define STATUS_GRAPHICS_INVALID_VIDPN 0xC01E0303
+#define STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE 0xC01E0304
+#define STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET 0xC01E0305
+#define STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED 0xC01E0306
+#define STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET 0xC01E0308
+#define STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET 0xC01E0309
+#define STATUS_GRAPHICS_INVALID_FREQUENCY 0xC01E030A
+#define STATUS_GRAPHICS_INVALID_ACTIVE_REGION 0xC01E030B
+#define STATUS_GRAPHICS_INVALID_TOTAL_REGION 0xC01E030C
+#define STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE 0xC01E0310
+#define STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE 0xC01E0311
+#define STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET 0xC01E0312
+#define STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY 0xC01E0313
+#define STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET 0xC01E0314
+#define STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET 0xC01E0315
+#define STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET 0xC01E0316
+#define STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET 0xC01E0317
+#define STATUS_GRAPHICS_TARGET_ALREADY_IN_SET 0xC01E0318
+#define STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH 0xC01E0319
+#define STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY 0xC01E031A
+#define STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET 0xC01E031B
+#define STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE 0xC01E031C
+#define STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET 0xC01E031D
+#define STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET 0xC01E031F
+#define STATUS_GRAPHICS_STALE_MODESET 0xC01E0320
+#define STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET 0xC01E0321
+#define STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE 0xC01E0322
+#define STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN 0xC01E0323
+#define STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE 0xC01E0324
+#define STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION 0xC01E0325
+#define STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES 0xC01E0326
+#define STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY 0xC01E0327
+#define STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE 0xC01E0328
+#define STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET 0xC01E0329
+#define STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET 0xC01E032A
+#define STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR 0xC01E032B
+#define STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET 0xC01E032C
+#define STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET 0xC01E032D
+#define STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE 0xC01E032E
+#define STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE 0xC01E032F
+#define STATUS_GRAPHICS_RESOURCES_NOT_RELATED 0xC01E0330
+#define STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE 0xC01E0331
+#define STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE 0xC01E0332
+#define STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET 0xC01E0333
+#define STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER 0xC01E0334
+#define STATUS_GRAPHICS_NO_VIDPNMGR 0xC01E0335
+#define STATUS_GRAPHICS_NO_ACTIVE_VIDPN 0xC01E0336
+#define STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY 0xC01E0337
+#define STATUS_GRAPHICS_MONITOR_NOT_CONNECTED 0xC01E0338
+#define STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY 0xC01E0339
+#define STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE 0xC01E033A
+#define STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE 0xC01E033B
+#define STATUS_GRAPHICS_INVALID_STRIDE 0xC01E033C
+#define STATUS_GRAPHICS_INVALID_PIXELFORMAT 0xC01E033D
+#define STATUS_GRAPHICS_INVALID_COLORBASIS 0xC01E033E
+#define STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE 0xC01E033F
+#define STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY 0xC01E0340
+#define STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT 0xC01E0341
+#define STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE 0xC01E0342
+#define STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN 0xC01E0343
+#define STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL 0xC01E0344
+#define STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION 0xC01E0345
+#define STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED 0xC01E0346
+#define STATUS_GRAPHICS_INVALID_GAMMA_RAMP 0xC01E0347
+#define STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED 0xC01E0348
+#define STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED 0xC01E0349
+#define STATUS_GRAPHICS_MODE_NOT_IN_MODESET 0xC01E034A
+#define STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON 0xC01E034D
+#define STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE 0xC01E034E
+#define STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE 0xC01E034F
+#define STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS 0xC01E0350
+#define STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING 0xC01E0352
+#define STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED 0xC01E0353
+#define STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS 0xC01E0354
+#define STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT 0xC01E0355
+#define STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM 0xC01E0356
+#define STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN 0xC01E0357
+#define STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT 0xC01E0358
+#define STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED 0xC01E0359
+#define STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION 0xC01E035A
+#define STATUS_GRAPHICS_INVALID_CLIENT_TYPE 0xC01E035B
+#define STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET 0xC01E035C
+#define STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED 0xC01E0400
+#define STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED 0xC01E0401
+#define STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER 0xC01E0430
+#define STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED 0xC01E0431
+#define STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED 0xC01E0432
+#define STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY 0xC01E0433
+#define STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED 0xC01E0434
+#define STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON 0xC01E0435
+#define STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE 0xC01E0436
+#define STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER 0xC01E0438
+#define STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED 0xC01E043B
+#define STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS 0xC01E051C
+#define STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST 0xC01E051D
+#define STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR 0xC01E051E
+#define STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS 0xC01E051F
+#define STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED 0xC01E0520
+#define STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST 0xC01E0521
+#define STATUS_GRAPHICS_OPM_NOT_SUPPORTED 0xC01E0500
+#define STATUS_GRAPHICS_COPP_NOT_SUPPORTED 0xC01E0501
+#define STATUS_GRAPHICS_UAB_NOT_SUPPORTED 0xC01E0502
+#define STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS 0xC01E0503
+#define STATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL 0xC01E0504
+#define STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST 0xC01E0505
+#define STATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME 0xC01E0506
+#define STATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP 0xC01E0507
+#define STATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED 0xC01E0508
+#define STATUS_GRAPHICS_OPM_INVALID_POINTER 0xC01E050A
+#define STATUS_GRAPHICS_OPM_INTERNAL_ERROR 0xC01E050B
+#define STATUS_GRAPHICS_OPM_INVALID_HANDLE 0xC01E050C
+#define STATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE 0xC01E050D
+#define STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH 0xC01E050E
+#define STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED 0xC01E050F
+#define STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED 0xC01E0510
+#define STATUS_GRAPHICS_PVP_HFS_FAILED 0xC01E0511
+#define STATUS_GRAPHICS_OPM_INVALID_SRM 0xC01E0512
+#define STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP 0xC01E0513
+#define STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP 0xC01E0514
+#define STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA 0xC01E0515
+#define STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET 0xC01E0516
+#define STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH 0xC01E0517
+#define STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE 0xC01E0518
+#define STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS 0xC01E051A
+#define STATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS 0xC01E051B
+#define STATUS_GRAPHICS_I2C_NOT_SUPPORTED 0xC01E0580
+#define STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST 0xC01E0581
+#define STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA 0xC01E0582
+#define STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA 0xC01E0583
+#define STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED 0xC01E0584
+#define STATUS_GRAPHICS_DDCCI_INVALID_DATA 0xC01E0585
+#define STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE 0xC01E0586
+#define STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING 0xC01E0587
+#define STATUS_GRAPHICS_MCA_INTERNAL_ERROR 0xC01E0588
+#define STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND 0xC01E0589
+#define STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH 0xC01E058A
+#define STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM 0xC01E058B
+#define STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE 0xC01E058C
+#define STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS 0xC01E058D
+#define STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED 0xC01E05E0
+#define STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME 0xC01E05E1
+#define STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP 0xC01E05E2
+#define STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED 0xC01E05E3
+#define STATUS_GRAPHICS_INVALID_POINTER 0xC01E05E4
+#define STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE 0xC01E05E5
+#define STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL 0xC01E05E6
+#define STATUS_GRAPHICS_INTERNAL_ERROR 0xC01E05E7
+#define STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS 0xC01E05E8
+#define STATUS_FVE_LOCKED_VOLUME 0xC0210000
+#define STATUS_FVE_NOT_ENCRYPTED 0xC0210001
+#define STATUS_FVE_BAD_INFORMATION 0xC0210002
+#define STATUS_FVE_TOO_SMALL 0xC0210003
+#define STATUS_FVE_FAILED_WRONG_FS 0xC0210004
+#define STATUS_FVE_FAILED_BAD_FS 0xC0210005
+#define STATUS_FVE_FS_NOT_EXTENDED 0xC0210006
+#define STATUS_FVE_FS_MOUNTED 0xC0210007
+#define STATUS_FVE_NO_LICENSE 0xC0210008
+#define STATUS_FVE_ACTION_NOT_ALLOWED 0xC0210009
+#define STATUS_FVE_BAD_DATA 0xC021000A
+#define STATUS_FVE_VOLUME_NOT_BOUND 0xC021000B
+#define STATUS_FVE_NOT_DATA_VOLUME 0xC021000C
+#define STATUS_FVE_CONV_READ_ERROR 0xC021000D
+#define STATUS_FVE_CONV_WRITE_ERROR 0xC021000E
+#define STATUS_FVE_OVERLAPPED_UPDATE 0xC021000F
+#define STATUS_FVE_FAILED_SECTOR_SIZE 0xC0210010
+#define STATUS_FVE_FAILED_AUTHENTICATION 0xC0210011
+#define STATUS_FVE_NOT_OS_VOLUME 0xC0210012
+#define STATUS_FVE_KEYFILE_NOT_FOUND 0xC0210013
+#define STATUS_FVE_KEYFILE_INVALID 0xC0210014
+#define STATUS_FVE_KEYFILE_NO_VMK 0xC0210015
+#define STATUS_FVE_TPM_DISABLED 0xC0210016
+#define STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO 0xC0210017
+#define STATUS_FVE_TPM_INVALID_PCR 0xC0210018
+#define STATUS_FVE_TPM_NO_VMK 0xC0210019
+#define STATUS_FVE_PIN_INVALID 0xC021001A
+#define STATUS_FVE_AUTH_INVALID_APPLICATION 0xC021001B
+#define STATUS_FVE_AUTH_INVALID_CONFIG 0xC021001C
+#define STATUS_FVE_DEBUGGER_ENABLED 0xC021001D
+#define STATUS_FVE_DRY_RUN_FAILED 0xC021001E
+#define STATUS_FVE_BAD_METADATA_POINTER 0xC021001F
+#define STATUS_FVE_OLD_METADATA_COPY 0xC0210020
+#define STATUS_FVE_REBOOT_REQUIRED 0xC0210021
+#define STATUS_FVE_RAW_ACCESS 0xC0210022
+#define STATUS_FVE_RAW_BLOCKED 0xC0210023
+#define STATUS_FWP_CALLOUT_NOT_FOUND 0xC0220001
+#define STATUS_FWP_CONDITION_NOT_FOUND 0xC0220002
+#define STATUS_FWP_FILTER_NOT_FOUND 0xC0220003
+#define STATUS_FWP_LAYER_NOT_FOUND 0xC0220004
+#define STATUS_FWP_PROVIDER_NOT_FOUND 0xC0220005
+#define STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND 0xC0220006
+#define STATUS_FWP_SUBLAYER_NOT_FOUND 0xC0220007
+#define STATUS_FWP_NOT_FOUND 0xC0220008
+#define STATUS_FWP_ALREADY_EXISTS 0xC0220009
+#define STATUS_FWP_IN_USE 0xC022000A
+#define STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS 0xC022000B
+#define STATUS_FWP_WRONG_SESSION 0xC022000C
+#define STATUS_FWP_NO_TXN_IN_PROGRESS 0xC022000D
+#define STATUS_FWP_TXN_IN_PROGRESS 0xC022000E
+#define STATUS_FWP_TXN_ABORTED 0xC022000F
+#define STATUS_FWP_SESSION_ABORTED 0xC0220010
+#define STATUS_FWP_INCOMPATIBLE_TXN 0xC0220011
+#define STATUS_FWP_TIMEOUT 0xC0220012
+#define STATUS_FWP_NET_EVENTS_DISABLED 0xC0220013
+#define STATUS_FWP_INCOMPATIBLE_LAYER 0xC0220014
+#define STATUS_FWP_KM_CLIENTS_ONLY 0xC0220015
+#define STATUS_FWP_LIFETIME_MISMATCH 0xC0220016
+#define STATUS_FWP_BUILTIN_OBJECT 0xC0220017
+#define STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS 0xC0220018
+#define STATUS_FWP_TOO_MANY_CALLOUTS 0xC0220018
+#define STATUS_FWP_NOTIFICATION_DROPPED 0xC0220019
+#define STATUS_FWP_TRAFFIC_MISMATCH 0xC022001A
+#define STATUS_FWP_INCOMPATIBLE_SA_STATE 0xC022001B
+#define STATUS_FWP_NULL_POINTER 0xC022001C
+#define STATUS_FWP_INVALID_ENUMERATOR 0xC022001D
+#define STATUS_FWP_INVALID_FLAGS 0xC022001E
+#define STATUS_FWP_INVALID_NET_MASK 0xC022001F
+#define STATUS_FWP_INVALID_RANGE 0xC0220020
+#define STATUS_FWP_INVALID_INTERVAL 0xC0220021
+#define STATUS_FWP_ZERO_LENGTH_ARRAY 0xC0220022
+#define STATUS_FWP_NULL_DISPLAY_NAME 0xC0220023
+#define STATUS_FWP_INVALID_ACTION_TYPE 0xC0220024
+#define STATUS_FWP_INVALID_WEIGHT 0xC0220025
+#define STATUS_FWP_MATCH_TYPE_MISMATCH 0xC0220026
+#define STATUS_FWP_TYPE_MISMATCH 0xC0220027
+#define STATUS_FWP_OUT_OF_BOUNDS 0xC0220028
+#define STATUS_FWP_RESERVED 0xC0220029
+#define STATUS_FWP_DUPLICATE_CONDITION 0xC022002A
+#define STATUS_FWP_DUPLICATE_KEYMOD 0xC022002B
+#define STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER 0xC022002C
+#define STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER 0xC022002D
+#define STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER 0xC022002E
+#define STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT 0xC022002F
+#define STATUS_FWP_INCOMPATIBLE_AUTH_METHOD 0xC0220030
+#define STATUS_FWP_INCOMPATIBLE_DH_GROUP 0xC0220031
+#define STATUS_FWP_EM_NOT_SUPPORTED 0xC0220032
+#define STATUS_FWP_NEVER_MATCH 0xC0220033
+#define STATUS_FWP_PROVIDER_CONTEXT_MISMATCH 0xC0220034
+#define STATUS_FWP_INVALID_PARAMETER 0xC0220035
+#define STATUS_FWP_TOO_MANY_SUBLAYERS 0xC0220036
+#define STATUS_FWP_CALLOUT_NOTIFICATION_FAILED 0xC0220037
+#define STATUS_FWP_INCOMPATIBLE_AUTH_CONFIG 0xC0220038
+#define STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG 0xC0220039
+#define STATUS_FWP_TCPIP_NOT_READY 0xC0220100
+#define STATUS_FWP_INJECT_HANDLE_CLOSING 0xC0220101
+#define STATUS_FWP_INJECT_HANDLE_STALE 0xC0220102
+#define STATUS_FWP_CANNOT_PEND 0xC0220103
+#define STATUS_NDIS_CLOSING 0xC0230002
+#define STATUS_NDIS_BAD_VERSION 0xC0230004
+#define STATUS_NDIS_BAD_CHARACTERISTICS 0xC0230005
+#define STATUS_NDIS_ADAPTER_NOT_FOUND 0xC0230006
+#define STATUS_NDIS_OPEN_FAILED 0xC0230007
+#define STATUS_NDIS_DEVICE_FAILED 0xC0230008
+#define STATUS_NDIS_MULTICAST_FULL 0xC0230009
+#define STATUS_NDIS_MULTICAST_EXISTS 0xC023000A
+#define STATUS_NDIS_MULTICAST_NOT_FOUND 0xC023000B
+#define STATUS_NDIS_REQUEST_ABORTED 0xC023000C
+#define STATUS_NDIS_RESET_IN_PROGRESS 0xC023000D
+#define STATUS_NDIS_INVALID_PACKET 0xC023000F
+#define STATUS_NDIS_INVALID_DEVICE_REQUEST 0xC0230010
+#define STATUS_NDIS_ADAPTER_NOT_READY 0xC0230011
+#define STATUS_NDIS_INVALID_LENGTH 0xC0230014
+#define STATUS_NDIS_INVALID_DATA 0xC0230015
+#define STATUS_NDIS_BUFFER_TOO_SHORT 0xC0230016
+#define STATUS_NDIS_INVALID_OID 0xC0230017
+#define STATUS_NDIS_ADAPTER_REMOVED 0xC0230018
+#define STATUS_NDIS_UNSUPPORTED_MEDIA 0xC0230019
+#define STATUS_NDIS_GROUP_ADDRESS_IN_USE 0xC023001A
+#define STATUS_NDIS_FILE_NOT_FOUND 0xC023001B
+#define STATUS_NDIS_ERROR_READING_FILE 0xC023001C
+#define STATUS_NDIS_ALREADY_MAPPED 0xC023001D
+#define STATUS_NDIS_RESOURCE_CONFLICT 0xC023001E
+#define STATUS_NDIS_MEDIA_DISCONNECTED 0xC023001F
+#define STATUS_NDIS_INVALID_ADDRESS 0xC0230022
+#define STATUS_NDIS_PAUSED 0xC023002A
+#define STATUS_NDIS_INTERFACE_NOT_FOUND 0xC023002B
+#define STATUS_NDIS_UNSUPPORTED_REVISION 0xC023002C
+#define STATUS_NDIS_INVALID_PORT 0xC023002D
+#define STATUS_NDIS_INVALID_PORT_STATE 0xC023002E
+#define STATUS_NDIS_LOW_POWER_STATE 0xC023002F
+#define STATUS_NDIS_NOT_SUPPORTED 0xC02300BB
+#define STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED 0xC0232000
+#define STATUS_NDIS_DOT11_MEDIA_IN_USE 0xC0232001
+#define STATUS_NDIS_DOT11_POWER_STATE_INVALID 0xC0232002
+#define STATUS_IPSEC_BAD_SPI 0xC0360001
+#define STATUS_IPSEC_SA_LIFETIME_EXPIRED 0xC0360002
+#define STATUS_IPSEC_WRONG_SA 0xC0360003
+#define STATUS_IPSEC_REPLAY_CHECK_FAILED 0xC0360004
+#define STATUS_IPSEC_INVALID_PACKET 0xC0360005
+#define STATUS_IPSEC_INTEGRITY_CHECK_FAILED 0xC0360006
+#define STATUS_IPSEC_CLEAR_TEXT_DROP 0xC0360007
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
new file mode 100644
index 0000000..b4b6b9a
--- /dev/null
+++ b/fs/cifs/smb2transport.c
@@ -0,0 +1,151 @@
+/*
+ *   fs/cifs/smb2transport.c
+ *
+ *   Copyright (C) International Business Machines  Corp., 2002, 2011
+ *                 Etersoft, 2012
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *              Jeremy Allison (jra@samba.org) 2006
+ *              Pavel Shilovsky (pshilovsky@samba.org) 2012
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/net.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <asm/processor.h>
+#include <linux/mempool.h>
+#include "smb2pdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "smb2proto.h"
+#include "cifs_debug.h"
+#include "smb2status.h"
+
+/*
+ * Set message id for the request. Should be called after wait_for_free_request
+ * and when srv_mutex is held.
+ */
+static inline void
+smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr)
+{
+	hdr->MessageId = get_next_mid(server);
+}
+
+static struct mid_q_entry *
+smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
+		     struct TCP_Server_Info *server)
+{
+	struct mid_q_entry *temp;
+
+	if (server == NULL) {
+		cERROR(1, "Null TCP session in smb2_mid_entry_alloc");
+		return NULL;
+	}
+
+	temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
+	if (temp == NULL)
+		return temp;
+	else {
+		memset(temp, 0, sizeof(struct mid_q_entry));
+		temp->mid = smb_buffer->MessageId;	/* always LE */
+		temp->pid = current->pid;
+		temp->command = smb_buffer->Command;	/* Always LE */
+		temp->when_alloc = jiffies;
+		temp->server = server;
+
+		/*
+		 * The default is for the mid to be synchronous, so the
+		 * default callback just wakes up the current task.
+		 */
+		temp->callback = cifs_wake_up_task;
+		temp->callback_data = current;
+	}
+
+	atomic_inc(&midCount);
+	temp->mid_state = MID_REQUEST_ALLOCATED;
+	return temp;
+}
+
+static int
+smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
+		   struct mid_q_entry **mid)
+{
+	if (ses->server->tcpStatus == CifsExiting)
+		return -ENOENT;
+
+	if (ses->server->tcpStatus == CifsNeedReconnect) {
+		cFYI(1, "tcp session dead - return to caller to retry");
+		return -EAGAIN;
+	}
+
+	if (ses->status != CifsGood) {
+		/* check if SMB2 session is bad because we are setting it up */
+		if ((buf->Command != SMB2_SESSION_SETUP) &&
+		    (buf->Command != SMB2_NEGOTIATE))
+			return -EAGAIN;
+		/* else ok - we are setting up session */
+	}
+	*mid = smb2_mid_entry_alloc(buf, ses->server);
+	if (*mid == NULL)
+		return -ENOMEM;
+	spin_lock(&GlobalMid_Lock);
+	list_add_tail(&(*mid)->qhead, &ses->server->pending_mid_q);
+	spin_unlock(&GlobalMid_Lock);
+	return 0;
+}
+
+int
+smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+		   bool log_error)
+{
+	unsigned int len = get_rfc1002_length(mid->resp_buf);
+
+	dump_smb(mid->resp_buf, min_t(u32, 80, len));
+	/* convert the length into a more usable form */
+	/* BB - uncomment with SMB2 signing implementation */
+	/* if ((len > 24) &&
+	    (server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) {
+		if (smb2_verify_signature(mid->resp_buf, server))
+			cERROR(1, "Unexpected SMB signature");
+	} */
+
+	return map_smb2_to_linux_error(mid->resp_buf, log_error);
+}
+
+int
+smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
+		   unsigned int nvec, struct mid_q_entry **ret_mid)
+{
+	int rc;
+	struct smb2_hdr *hdr = (struct smb2_hdr *)iov[0].iov_base;
+	struct mid_q_entry *mid;
+
+	smb2_seq_num_into_buf(ses->server, hdr);
+
+	rc = smb2_get_mid_entry(ses, hdr, &mid);
+	if (rc)
+		return rc;
+	/* rc = smb2_sign_smb2(iov, nvec, ses->server);
+	if (rc)
+		delete_mid(mid); */
+	*ret_mid = mid;
+	return rc;
+}
+
+/* BB add missing functions here */
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 3097ee5..bd51339 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -35,10 +35,8 @@
 #include "cifsproto.h"
 #include "cifs_debug.h"
 
-extern mempool_t *cifs_mid_poolp;
-
-static void
-wake_up_task(struct mid_q_entry *mid)
+void
+cifs_wake_up_task(struct mid_q_entry *mid)
 {
 	wake_up_process(mid->callback_data);
 }
@@ -65,12 +63,13 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 	/*	do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
 		/* when mid allocated can be before when sent */
 		temp->when_alloc = jiffies;
+		temp->server = server;
 
 		/*
 		 * The default is for the mid to be synchronous, so the
 		 * default callback just wakes up the current task.
 		 */
-		temp->callback = wake_up_task;
+		temp->callback = cifs_wake_up_task;
 		temp->callback_data = current;
 	}
 
@@ -83,6 +82,7 @@ void
 DeleteMidQEntry(struct mid_q_entry *midEntry)
 {
 #ifdef CONFIG_CIFS_STATS2
+	__le16 command = midEntry->server->vals->lock_cmd;
 	unsigned long now;
 #endif
 	midEntry->mid_state = MID_FREE;
@@ -96,8 +96,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
 	/* commands taking longer than one second are indications that
 	   something is wrong, unless it is quite a slow link or server */
 	if ((now - midEntry->when_alloc) > HZ) {
-		if ((cifsFYI & CIFS_TIMER) &&
-		    (midEntry->command != cpu_to_le16(SMB_COM_LOCKING_ANDX))) {
+		if ((cifsFYI & CIFS_TIMER) && (midEntry->command != command)) {
 			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %llu",
 			       midEntry->command, midEntry->mid);
 			printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
@@ -254,13 +253,13 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
 }
 
 static int
-wait_for_free_credits(struct TCP_Server_Info *server, const int optype,
+wait_for_free_credits(struct TCP_Server_Info *server, const int timeout,
 		      int *credits)
 {
 	int rc;
 
 	spin_lock(&server->req_lock);
-	if (optype == CIFS_ASYNC_OP) {
+	if (timeout == CIFS_ASYNC_OP) {
 		/* oplock breaks must not be held up */
 		server->in_flight++;
 		*credits -= 1;
@@ -290,7 +289,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int optype,
 			 */
 
 			/* update # of requests on the wire to server */
-			if (optype != CIFS_BLOCKING_OP) {
+			if (timeout != CIFS_BLOCKING_OP) {
 				*credits -= 1;
 				server->in_flight++;
 			}
@@ -302,10 +301,11 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int optype,
 }
 
 static int
-wait_for_free_request(struct TCP_Server_Info *server, const int optype)
+wait_for_free_request(struct TCP_Server_Info *server, const int timeout,
+		      const int optype)
 {
-	return wait_for_free_credits(server, optype,
-				     server->ops->get_credits_field(server));
+	return wait_for_free_credits(server, timeout,
+				server->ops->get_credits_field(server, optype));
 }
 
 static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
@@ -384,12 +384,15 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
 int
 cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 		unsigned int nvec, mid_receive_t *receive,
-		mid_callback_t *callback, void *cbdata, bool ignore_pend)
+		mid_callback_t *callback, void *cbdata, const int flags)
 {
-	int rc;
+	int rc, timeout, optype;
 	struct mid_q_entry *mid;
 
-	rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0);
+	timeout = flags & CIFS_TIMEOUT_MASK;
+	optype = flags & CIFS_OP_MASK;
+
+	rc = wait_for_free_request(server, timeout, optype);
 	if (rc)
 		return rc;
 
@@ -397,7 +400,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 	rc = cifs_setup_async_request(server, iov, nvec, &mid);
 	if (rc) {
 		mutex_unlock(&server->srv_mutex);
-		add_credits(server, 1);
+		add_credits(server, 1, optype);
 		wake_up(&server->request_q);
 		return rc;
 	}
@@ -419,7 +422,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 	return rc;
 out_err:
 	delete_mid(mid);
-	add_credits(server, 1);
+	add_credits(server, 1, optype);
 	wake_up(&server->request_q);
 	return rc;
 }
@@ -535,17 +538,19 @@ cifs_setup_request(struct cifs_ses *ses, struct kvec *iov,
 
 int
 SendReceive2(const unsigned int xid, struct cifs_ses *ses,
-	     struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
+	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
 	     const int flags)
 {
 	int rc = 0;
-	int long_op;
+	int timeout, optype;
 	struct mid_q_entry *midQ;
 	char *buf = iov[0].iov_base;
+	unsigned int credits = 1;
 
-	long_op = flags & CIFS_TIMEOUT_MASK;
+	timeout = flags & CIFS_TIMEOUT_MASK;
+	optype = flags & CIFS_OP_MASK;
 
-	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
+	*resp_buf_type = CIFS_NO_BUFFER;  /* no response buf yet */
 
 	if ((ses == NULL) || (ses->server == NULL)) {
 		cifs_small_buf_release(buf);
@@ -564,7 +569,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	 * use ses->maxReq.
 	 */
 
-	rc = wait_for_free_request(ses->server, long_op);
+	rc = wait_for_free_request(ses->server, optype, timeout);
 	if (rc) {
 		cifs_small_buf_release(buf);
 		return rc;
@@ -583,7 +588,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		mutex_unlock(&ses->server->srv_mutex);
 		cifs_small_buf_release(buf);
 		/* Update # of requests on wire to server */
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, optype);
 		return rc;
 	}
 
@@ -600,7 +605,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		goto out;
 	}
 
-	if (long_op == CIFS_ASYNC_OP) {
+	if (timeout == CIFS_ASYNC_OP) {
 		cifs_small_buf_release(buf);
 		goto out;
 	}
@@ -613,7 +618,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
 			cifs_small_buf_release(buf);
-			add_credits(ses->server, 1);
+			add_credits(ses->server, 1, optype);
 			return rc;
 		}
 		spin_unlock(&GlobalMid_Lock);
@@ -623,7 +628,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, optype);
 		return rc;
 	}
 
@@ -637,9 +642,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	iov[0].iov_base = buf;
 	iov[0].iov_len = get_rfc1002_length(buf) + 4;
 	if (midQ->large_buf)
-		*pRespBufType = CIFS_LARGE_BUFFER;
+		*resp_buf_type = CIFS_LARGE_BUFFER;
 	else
-		*pRespBufType = CIFS_SMALL_BUFFER;
+		*resp_buf_type = CIFS_SMALL_BUFFER;
+
+	credits = ses->server->ops->get_credits(midQ);
 
 	rc = ses->server->ops->check_receive(midQ, ses->server,
 					     flags & CIFS_LOG_ERROR);
@@ -649,7 +656,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		midQ->resp_buf = NULL;
 out:
 	delete_mid(midQ);
-	add_credits(ses->server, 1);
+	add_credits(ses->server, credits, optype);
 
 	return rc;
 }
@@ -657,7 +664,7 @@ out:
 int
 SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
-	    int *pbytes_returned, const int long_op)
+	    int *pbytes_returned, const int timeout)
 {
 	int rc = 0;
 	struct mid_q_entry *midQ;
@@ -685,7 +692,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 		return -EIO;
 	}
 
-	rc = wait_for_free_request(ses->server, long_op);
+	rc = wait_for_free_request(ses->server, 0, timeout);
 	if (rc)
 		return rc;
 
@@ -699,7 +706,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	if (rc) {
 		mutex_unlock(&ses->server->srv_mutex);
 		/* Update # of requests on wire to server */
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, 0);
 		return rc;
 	}
 
@@ -720,7 +727,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	if (rc < 0)
 		goto out;
 
-	if (long_op == CIFS_ASYNC_OP)
+	if (timeout == CIFS_ASYNC_OP)
 		goto out;
 
 	rc = wait_for_response(ses->server, midQ);
@@ -731,7 +738,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 			/* no longer considered to be "in-flight" */
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
-			add_credits(ses->server, 1);
+			add_credits(ses->server, 1, 0);
 			return rc;
 		}
 		spin_unlock(&GlobalMid_Lock);
@@ -739,7 +746,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, 0);
 		return rc;
 	}
 
@@ -755,7 +762,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
 	delete_mid(midQ);
-	add_credits(ses->server, 1);
+	add_credits(ses->server, 1, 0);
 
 	return rc;
 }
@@ -820,7 +827,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 		return -EIO;
 	}
 
-	rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP);
+	rc = wait_for_free_request(ses->server, 0, CIFS_BLOCKING_OP);
 	if (rc)
 		return rc;
 
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 10d92cf..5142f2c 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -39,7 +39,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
 {
 	int rc = -EOPNOTSUPP;
 #ifdef CONFIG_CIFS_XATTR
-	int xid;
+	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
@@ -60,7 +60,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
 		return PTR_ERR(tlink);
 	pTcon = tlink_tcon(tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -88,7 +88,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
 	}
 remove_ea_exit:
 	kfree(full_path);
-	FreeXid(xid);
+	free_xid(xid);
 	cifs_put_tlink(tlink);
 #endif
 	return rc;
@@ -99,7 +99,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
 {
 	int rc = -EOPNOTSUPP;
 #ifdef CONFIG_CIFS_XATTR
-	int xid;
+	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
@@ -120,7 +120,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
 		return PTR_ERR(tlink);
 	pTcon = tlink_tcon(tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -221,7 +221,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
 
 set_ea_exit:
 	kfree(full_path);
-	FreeXid(xid);
+	free_xid(xid);
 	cifs_put_tlink(tlink);
 #endif
 	return rc;
@@ -232,7 +232,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
 {
 	ssize_t rc = -EOPNOTSUPP;
 #ifdef CONFIG_CIFS_XATTR
-	int xid;
+	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
@@ -253,7 +253,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
 		return PTR_ERR(tlink);
 	pTcon = tlink_tcon(tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -355,7 +355,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
 
 get_ea_exit:
 	kfree(full_path);
-	FreeXid(xid);
+	free_xid(xid);
 	cifs_put_tlink(tlink);
 #endif
 	return rc;
@@ -365,7 +365,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 {
 	ssize_t rc = -EOPNOTSUPP;
 #ifdef CONFIG_CIFS_XATTR
-	int xid;
+	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
@@ -389,7 +389,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 		return PTR_ERR(tlink);
 	pTcon = tlink_tcon(tlink);
 
-	xid = GetXid();
+	xid = get_xid();
 
 	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
@@ -409,7 +409,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 
 list_ea_exit:
 	kfree(full_path);
-	FreeXid(xid);
+	free_xid(xid);
 	cifs_put_tlink(tlink);
 #endif
 	return rc;
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 6901578..958ae0e 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -89,17 +89,13 @@ int coda_cache_check(struct inode *inode, int mask)
 /* this won't do any harm: just flag all children */
 static void coda_flag_children(struct dentry *parent, int flag)
 {
-	struct list_head *child;
 	struct dentry *de;
 
 	spin_lock(&parent->d_lock);
-	list_for_each(child, &parent->d_subdirs)
-	{
-		de = list_entry(child, struct dentry, d_u.d_child);
+	list_for_each_entry(de, &parent->d_subdirs, d_u.d_child) {
 		/* don't know what to do with negative dentries */
-		if ( ! de->d_inode ) 
-			continue;
-		coda_flag_inode(de->d_inode, flag);
+		if (de->d_inode ) 
+			coda_flag_inode(de->d_inode, flag);
 	}
 	spin_unlock(&parent->d_lock);
 	return; 
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 1775158..49fe52d 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -30,8 +30,8 @@
 #include "coda_int.h"
 
 /* dir inode-ops */
-static int coda_create(struct inode *dir, struct dentry *new, umode_t mode, struct nameidata *nd);
-static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, struct nameidata *nd);
+static int coda_create(struct inode *dir, struct dentry *new, umode_t mode, bool excl);
+static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, unsigned int flags);
 static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, 
 		     struct dentry *entry);
 static int coda_unlink(struct inode *dir_inode, struct dentry *entry);
@@ -46,7 +46,7 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
 static int coda_readdir(struct file *file, void *buf, filldir_t filldir);
 
 /* dentry ops */
-static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd);
+static int coda_dentry_revalidate(struct dentry *de, unsigned int flags);
 static int coda_dentry_delete(const struct dentry *);
 
 /* support routines */
@@ -94,7 +94,7 @@ const struct file_operations coda_dir_operations = {
 
 /* inode operations for directories */
 /* access routines: lookup, readlink, permission */
-static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd)
+static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsigned int flags)
 {
 	struct super_block *sb = dir->i_sb;
 	const char *name = entry->d_name.name;
@@ -188,7 +188,7 @@ static inline void coda_dir_drop_nlink(struct inode *dir)
 }
 
 /* creation routines: create, mknod, mkdir, link, symlink */
-static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, struct nameidata *nd)
+static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, bool excl)
 {
 	int error;
 	const char *name=de->d_name.name;
@@ -536,12 +536,12 @@ out:
 }
 
 /* called when a cache lookup succeeds */
-static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
+static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
 {
 	struct inode *inode;
 	struct coda_inode_info *cii;
 
-	if (nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	inode = de->d_inode;
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index f181312..0c70460 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -85,6 +85,11 @@ int coda_init_inodecache(void)
 
 void coda_destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(coda_inode_cachep);
 }
 
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 7e6c52d..7414ae2 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -442,7 +442,7 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den
 
 static struct dentry * configfs_lookup(struct inode *dir,
 				       struct dentry *dentry,
-				       struct nameidata *nd)
+				       unsigned int flags)
 {
 	struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
 	struct configfs_dirent * sd;
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index d013c46..28cca01 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -417,7 +417,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 /*
  * Lookup and fill in the inode data..
  */
-static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	unsigned int offset = 0;
 	struct inode *inode = NULL;
diff --git a/fs/dcache.c b/fs/dcache.c
index 4046904..8086636 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -218,7 +218,7 @@ static void __d_free(struct rcu_head *head)
 {
 	struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
 
-	WARN_ON(!list_empty(&dentry->d_alias));
+	WARN_ON(!hlist_unhashed(&dentry->d_alias));
 	if (dname_external(dentry))
 		kfree(dentry->d_name.name);
 	kmem_cache_free(dentry_cache, dentry); 
@@ -267,7 +267,7 @@ static void dentry_iput(struct dentry * dentry)
 	struct inode *inode = dentry->d_inode;
 	if (inode) {
 		dentry->d_inode = NULL;
-		list_del_init(&dentry->d_alias);
+		hlist_del_init(&dentry->d_alias);
 		spin_unlock(&dentry->d_lock);
 		spin_unlock(&inode->i_lock);
 		if (!inode->i_nlink)
@@ -291,7 +291,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
 {
 	struct inode *inode = dentry->d_inode;
 	dentry->d_inode = NULL;
-	list_del_init(&dentry->d_alias);
+	hlist_del_init(&dentry->d_alias);
 	dentry_rcuwalk_barrier(dentry);
 	spin_unlock(&dentry->d_lock);
 	spin_unlock(&inode->i_lock);
@@ -699,10 +699,11 @@ EXPORT_SYMBOL(dget_parent);
 static struct dentry *__d_find_alias(struct inode *inode, int want_discon)
 {
 	struct dentry *alias, *discon_alias;
+	struct hlist_node *p;
 
 again:
 	discon_alias = NULL;
-	list_for_each_entry(alias, &inode->i_dentry, d_alias) {
+	hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
 		spin_lock(&alias->d_lock);
  		if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
 			if (IS_ROOT(alias) &&
@@ -737,7 +738,7 @@ struct dentry *d_find_alias(struct inode *inode)
 {
 	struct dentry *de = NULL;
 
-	if (!list_empty(&inode->i_dentry)) {
+	if (!hlist_empty(&inode->i_dentry)) {
 		spin_lock(&inode->i_lock);
 		de = __d_find_alias(inode, 0);
 		spin_unlock(&inode->i_lock);
@@ -753,9 +754,10 @@ EXPORT_SYMBOL(d_find_alias);
 void d_prune_aliases(struct inode *inode)
 {
 	struct dentry *dentry;
+	struct hlist_node *p;
 restart:
 	spin_lock(&inode->i_lock);
-	list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+	hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
 		spin_lock(&dentry->d_lock);
 		if (!dentry->d_count) {
 			__dget_dlock(dentry);
@@ -977,7 +979,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
 			inode = dentry->d_inode;
 			if (inode) {
 				dentry->d_inode = NULL;
-				list_del_init(&dentry->d_alias);
+				hlist_del_init(&dentry->d_alias);
 				if (dentry->d_op && dentry->d_op->d_iput)
 					dentry->d_op->d_iput(dentry, inode);
 				else
@@ -1312,7 +1314,7 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
 	INIT_HLIST_BL_NODE(&dentry->d_hash);
 	INIT_LIST_HEAD(&dentry->d_lru);
 	INIT_LIST_HEAD(&dentry->d_subdirs);
-	INIT_LIST_HEAD(&dentry->d_alias);
+	INIT_HLIST_NODE(&dentry->d_alias);
 	INIT_LIST_HEAD(&dentry->d_u.d_child);
 	d_set_d_op(dentry, dentry->d_sb->s_d_op);
 
@@ -1400,7 +1402,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
 	if (inode) {
 		if (unlikely(IS_AUTOMOUNT(inode)))
 			dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
-		list_add(&dentry->d_alias, &inode->i_dentry);
+		hlist_add_head(&dentry->d_alias, &inode->i_dentry);
 	}
 	dentry->d_inode = inode;
 	dentry_rcuwalk_barrier(dentry);
@@ -1425,7 +1427,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
  
 void d_instantiate(struct dentry *entry, struct inode * inode)
 {
-	BUG_ON(!list_empty(&entry->d_alias));
+	BUG_ON(!hlist_unhashed(&entry->d_alias));
 	if (inode)
 		spin_lock(&inode->i_lock);
 	__d_instantiate(entry, inode);
@@ -1458,13 +1460,14 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
 	int len = entry->d_name.len;
 	const char *name = entry->d_name.name;
 	unsigned int hash = entry->d_name.hash;
+	struct hlist_node *p;
 
 	if (!inode) {
 		__d_instantiate(entry, NULL);
 		return NULL;
 	}
 
-	list_for_each_entry(alias, &inode->i_dentry, d_alias) {
+	hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
 		/*
 		 * Don't need alias->d_lock here, because aliases with
 		 * d_parent == entry->d_parent are not subject to name or
@@ -1490,7 +1493,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
 {
 	struct dentry *result;
 
-	BUG_ON(!list_empty(&entry->d_alias));
+	BUG_ON(!hlist_unhashed(&entry->d_alias));
 
 	if (inode)
 		spin_lock(&inode->i_lock);
@@ -1531,9 +1534,9 @@ static struct dentry * __d_find_any_alias(struct inode *inode)
 {
 	struct dentry *alias;
 
-	if (list_empty(&inode->i_dentry))
+	if (hlist_empty(&inode->i_dentry))
 		return NULL;
-	alias = list_first_entry(&inode->i_dentry, struct dentry, d_alias);
+	alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
 	__dget(alias);
 	return alias;
 }
@@ -1607,7 +1610,7 @@ struct dentry *d_obtain_alias(struct inode *inode)
 	spin_lock(&tmp->d_lock);
 	tmp->d_inode = inode;
 	tmp->d_flags |= DCACHE_DISCONNECTED;
-	list_add(&tmp->d_alias, &inode->i_dentry);
+	hlist_add_head(&tmp->d_alias, &inode->i_dentry);
 	hlist_bl_lock(&tmp->d_sb->s_anon);
 	hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
 	hlist_bl_unlock(&tmp->d_sb->s_anon);
@@ -2384,14 +2387,13 @@ static struct dentry *__d_unalias(struct inode *inode,
 		struct dentry *dentry, struct dentry *alias)
 {
 	struct mutex *m1 = NULL, *m2 = NULL;
-	struct dentry *ret;
+	struct dentry *ret = ERR_PTR(-EBUSY);
 
 	/* If alias and dentry share a parent, then no extra locks required */
 	if (alias->d_parent == dentry->d_parent)
 		goto out_unalias;
 
 	/* See lock_rename() */
-	ret = ERR_PTR(-EBUSY);
 	if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex))
 		goto out_err;
 	m1 = &dentry->d_sb->s_vfs_rename_mutex;
@@ -2399,8 +2401,10 @@ static struct dentry *__d_unalias(struct inode *inode,
 		goto out_err;
 	m2 = &alias->d_parent->d_inode->i_mutex;
 out_unalias:
-	__d_move(alias, dentry);
-	ret = alias;
+	if (likely(!d_mountpoint(alias))) {
+		__d_move(alias, dentry);
+		ret = alias;
+	}
 out_err:
 	spin_unlock(&inode->i_lock);
 	if (m2)
@@ -2622,7 +2626,7 @@ global_root:
 	if (!slash)
 		error = prepend(buffer, buflen, "/", 1);
 	if (!error)
-		error = real_mount(vfsmnt)->mnt_ns ? 1 : 2;
+		error = is_mounted(vfsmnt) ? 1 : 2;
 	goto out;
 }
 
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index b80bc84..4733eab 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -54,13 +54,12 @@ static struct inode *debugfs_get_inode(struct super_block *sb, umode_t mode, dev
 			break;
 		case S_IFLNK:
 			inode->i_op = &debugfs_link_operations;
-			inode->i_fop = fops;
 			inode->i_private = data;
 			break;
 		case S_IFDIR:
 			inode->i_op = &simple_dir_inode_operations;
-			inode->i_fop = fops ? fops : &simple_dir_operations;
-			inode->i_private = data;
+			inode->i_fop = &simple_dir_operations;
+			inode->i_private = NULL;
 
 			/* directory inodes start off with i_nlink == 2
 			 * (for "." entry) */
@@ -91,13 +90,12 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry,
 	return error;
 }
 
-static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode,
-			 void *data, const struct file_operations *fops)
+static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
 	int res;
 
 	mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
-	res = debugfs_mknod(dir, dentry, mode, 0, data, fops);
+	res = debugfs_mknod(dir, dentry, mode, 0, NULL, NULL);
 	if (!res) {
 		inc_nlink(dir);
 		fsnotify_mkdir(dir, dentry);
@@ -106,10 +104,10 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode,
 }
 
 static int debugfs_link(struct inode *dir, struct dentry *dentry, umode_t mode,
-			void *data, const struct file_operations *fops)
+			void *data)
 {
 	mode = (mode & S_IALLUGO) | S_IFLNK;
-	return debugfs_mknod(dir, dentry, mode, 0, data, fops);
+	return debugfs_mknod(dir, dentry, mode, 0, data, NULL);
 }
 
 static int debugfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
@@ -293,13 +291,19 @@ static struct file_system_type debug_fs_type = {
 	.kill_sb =	kill_litter_super,
 };
 
-static int debugfs_create_by_name(const char *name, umode_t mode,
-				  struct dentry *parent,
-				  struct dentry **dentry,
-				  void *data,
-				  const struct file_operations *fops)
+struct dentry *__create_file(const char *name, umode_t mode,
+				   struct dentry *parent, void *data,
+				   const struct file_operations *fops)
 {
-	int error = 0;
+	struct dentry *dentry = NULL;
+	int error;
+
+	pr_debug("debugfs: creating file '%s'\n",name);
+
+	error = simple_pin_fs(&debug_fs_type, &debugfs_mount,
+			      &debugfs_mount_count);
+	if (error)
+		goto exit;
 
 	/* If the parent is not specified, we create it in the root.
 	 * We need the root dentry to do this, which is in the super 
@@ -309,30 +313,35 @@ static int debugfs_create_by_name(const char *name, umode_t mode,
 	if (!parent)
 		parent = debugfs_mount->mnt_root;
 
-	*dentry = NULL;
+	dentry = NULL;
 	mutex_lock(&parent->d_inode->i_mutex);
-	*dentry = lookup_one_len(name, parent, strlen(name));
-	if (!IS_ERR(*dentry)) {
+	dentry = lookup_one_len(name, parent, strlen(name));
+	if (!IS_ERR(dentry)) {
 		switch (mode & S_IFMT) {
 		case S_IFDIR:
-			error = debugfs_mkdir(parent->d_inode, *dentry, mode,
-					      data, fops);
+			error = debugfs_mkdir(parent->d_inode, dentry, mode);
+					      
 			break;
 		case S_IFLNK:
-			error = debugfs_link(parent->d_inode, *dentry, mode,
-					     data, fops);
+			error = debugfs_link(parent->d_inode, dentry, mode,
+					     data);
 			break;
 		default:
-			error = debugfs_create(parent->d_inode, *dentry, mode,
+			error = debugfs_create(parent->d_inode, dentry, mode,
 					       data, fops);
 			break;
 		}
-		dput(*dentry);
+		dput(dentry);
 	} else
-		error = PTR_ERR(*dentry);
+		error = PTR_ERR(dentry);
 	mutex_unlock(&parent->d_inode->i_mutex);
 
-	return error;
+	if (error) {
+		dentry = NULL;
+		simple_release_fs(&debugfs_mount, &debugfs_mount_count);
+	}
+exit:
+	return dentry;
 }
 
 /**
@@ -365,25 +374,15 @@ struct dentry *debugfs_create_file(const char *name, umode_t mode,
 				   struct dentry *parent, void *data,
 				   const struct file_operations *fops)
 {
-	struct dentry *dentry = NULL;
-	int error;
-
-	pr_debug("debugfs: creating file '%s'\n",name);
-
-	error = simple_pin_fs(&debug_fs_type, &debugfs_mount,
-			      &debugfs_mount_count);
-	if (error)
-		goto exit;
-
-	error = debugfs_create_by_name(name, mode, parent, &dentry,
-				       data, fops);
-	if (error) {
-		dentry = NULL;
-		simple_release_fs(&debugfs_mount, &debugfs_mount_count);
-		goto exit;
+	switch (mode & S_IFMT) {
+	case S_IFREG:
+	case 0:
+		break;
+	default:
+		BUG();
 	}
-exit:
-	return dentry;
+
+	return __create_file(name, mode, parent, data, fops);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_file);
 
@@ -407,8 +406,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_file);
  */
 struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
 {
-	return debugfs_create_file(name, 
-				   S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
+	return __create_file(name, S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
 				   parent, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_dir);
@@ -446,8 +444,7 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
 	if (!link)
 		return NULL;
 
-	result = debugfs_create_file(name, S_IFLNK | S_IRWXUGO, parent, link,
-				     NULL);
+	result = __create_file(name, S_IFLNK | S_IRWXUGO, parent, link, NULL);
 	if (!result)
 		kfree(link);
 	return result;
@@ -498,7 +495,7 @@ void debugfs_remove(struct dentry *dentry)
 	struct dentry *parent;
 	int ret;
 
-	if (!dentry)
+	if (IS_ERR_OR_NULL(dentry))
 		return;
 
 	parent = dentry->d_parent;
@@ -530,7 +527,7 @@ void debugfs_remove_recursive(struct dentry *dentry)
 	struct dentry *child;
 	struct dentry *parent;
 
-	if (!dentry)
+	if (IS_ERR_OR_NULL(dentry))
 		return;
 
 	parent = dentry->d_parent;
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 0c85fae..1faf4cb 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -1258,7 +1258,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
 	 */
 	BUG_ON(retval == -EIOCBQUEUED);
 	if (dio->is_async && retval == 0 && dio->result &&
-	    ((rw & READ) || (dio->result == sdio.size)))
+	    ((rw == READ) || (dio->result == sdio.size)))
 		retval = -EIOCBQUEUED;
 
 	if (retval != -EIOCBQUEUED)
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index e7e327d..9ccf734 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -96,7 +96,6 @@ struct dlm_cluster {
 	unsigned int cl_tcp_port;
 	unsigned int cl_buffer_size;
 	unsigned int cl_rsbtbl_size;
-	unsigned int cl_dirtbl_size;
 	unsigned int cl_recover_timer;
 	unsigned int cl_toss_secs;
 	unsigned int cl_scan_secs;
@@ -113,7 +112,6 @@ enum {
 	CLUSTER_ATTR_TCP_PORT = 0,
 	CLUSTER_ATTR_BUFFER_SIZE,
 	CLUSTER_ATTR_RSBTBL_SIZE,
-	CLUSTER_ATTR_DIRTBL_SIZE,
 	CLUSTER_ATTR_RECOVER_TIMER,
 	CLUSTER_ATTR_TOSS_SECS,
 	CLUSTER_ATTR_SCAN_SECS,
@@ -189,7 +187,6 @@ __CONFIGFS_ATTR(name, 0644, name##_read, name##_write)
 CLUSTER_ATTR(tcp_port, 1);
 CLUSTER_ATTR(buffer_size, 1);
 CLUSTER_ATTR(rsbtbl_size, 1);
-CLUSTER_ATTR(dirtbl_size, 1);
 CLUSTER_ATTR(recover_timer, 1);
 CLUSTER_ATTR(toss_secs, 1);
 CLUSTER_ATTR(scan_secs, 1);
@@ -204,7 +201,6 @@ static struct configfs_attribute *cluster_attrs[] = {
 	[CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
 	[CLUSTER_ATTR_BUFFER_SIZE] = &cluster_attr_buffer_size.attr,
 	[CLUSTER_ATTR_RSBTBL_SIZE] = &cluster_attr_rsbtbl_size.attr,
-	[CLUSTER_ATTR_DIRTBL_SIZE] = &cluster_attr_dirtbl_size.attr,
 	[CLUSTER_ATTR_RECOVER_TIMER] = &cluster_attr_recover_timer.attr,
 	[CLUSTER_ATTR_TOSS_SECS] = &cluster_attr_toss_secs.attr,
 	[CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr,
@@ -478,7 +474,6 @@ static struct config_group *make_cluster(struct config_group *g,
 	cl->cl_tcp_port = dlm_config.ci_tcp_port;
 	cl->cl_buffer_size = dlm_config.ci_buffer_size;
 	cl->cl_rsbtbl_size = dlm_config.ci_rsbtbl_size;
-	cl->cl_dirtbl_size = dlm_config.ci_dirtbl_size;
 	cl->cl_recover_timer = dlm_config.ci_recover_timer;
 	cl->cl_toss_secs = dlm_config.ci_toss_secs;
 	cl->cl_scan_secs = dlm_config.ci_scan_secs;
@@ -1050,7 +1045,6 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
 #define DEFAULT_TCP_PORT       21064
 #define DEFAULT_BUFFER_SIZE     4096
 #define DEFAULT_RSBTBL_SIZE     1024
-#define DEFAULT_DIRTBL_SIZE     1024
 #define DEFAULT_RECOVER_TIMER      5
 #define DEFAULT_TOSS_SECS         10
 #define DEFAULT_SCAN_SECS          5
@@ -1066,7 +1060,6 @@ struct dlm_config_info dlm_config = {
 	.ci_tcp_port = DEFAULT_TCP_PORT,
 	.ci_buffer_size = DEFAULT_BUFFER_SIZE,
 	.ci_rsbtbl_size = DEFAULT_RSBTBL_SIZE,
-	.ci_dirtbl_size = DEFAULT_DIRTBL_SIZE,
 	.ci_recover_timer = DEFAULT_RECOVER_TIMER,
 	.ci_toss_secs = DEFAULT_TOSS_SECS,
 	.ci_scan_secs = DEFAULT_SCAN_SECS,
diff --git a/fs/dlm/config.h b/fs/dlm/config.h
index 9f5e366..dbd35a0 100644
--- a/fs/dlm/config.h
+++ b/fs/dlm/config.h
@@ -27,7 +27,6 @@ struct dlm_config_info {
 	int ci_tcp_port;
 	int ci_buffer_size;
 	int ci_rsbtbl_size;
-	int ci_dirtbl_size;
 	int ci_recover_timer;
 	int ci_toss_secs;
 	int ci_scan_secs;
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c
index 1c9b080..b969dee 100644
--- a/fs/dlm/debug_fs.c
+++ b/fs/dlm/debug_fs.c
@@ -344,6 +344,45 @@ static int print_format3(struct dlm_rsb *r, struct seq_file *s)
 	return rv;
 }
 
+static int print_format4(struct dlm_rsb *r, struct seq_file *s)
+{
+	int our_nodeid = dlm_our_nodeid();
+	int print_name = 1;
+	int i, rv;
+
+	lock_rsb(r);
+
+	rv = seq_printf(s, "rsb %p %d %d %d %d %lu %lx %d ",
+			r,
+			r->res_nodeid,
+			r->res_master_nodeid,
+			r->res_dir_nodeid,
+			our_nodeid,
+			r->res_toss_time,
+			r->res_flags,
+			r->res_length);
+	if (rv)
+		goto out;
+
+	for (i = 0; i < r->res_length; i++) {
+		if (!isascii(r->res_name[i]) || !isprint(r->res_name[i]))
+			print_name = 0;
+	}
+
+	seq_printf(s, "%s", print_name ? "str " : "hex");
+
+	for (i = 0; i < r->res_length; i++) {
+		if (print_name)
+			seq_printf(s, "%c", r->res_name[i]);
+		else
+			seq_printf(s, " %02x", (unsigned char)r->res_name[i]);
+	}
+	rv = seq_printf(s, "\n");
+ out:
+	unlock_rsb(r);
+	return rv;
+}
+
 struct rsbtbl_iter {
 	struct dlm_rsb *rsb;
 	unsigned bucket;
@@ -382,6 +421,13 @@ static int table_seq_show(struct seq_file *seq, void *iter_ptr)
 		}
 		rv = print_format3(ri->rsb, seq);
 		break;
+	case 4:
+		if (ri->header) {
+			seq_printf(seq, "version 4 rsb 2\n");
+			ri->header = 0;
+		}
+		rv = print_format4(ri->rsb, seq);
+		break;
 	}
 
 	return rv;
@@ -390,15 +436,18 @@ static int table_seq_show(struct seq_file *seq, void *iter_ptr)
 static const struct seq_operations format1_seq_ops;
 static const struct seq_operations format2_seq_ops;
 static const struct seq_operations format3_seq_ops;
+static const struct seq_operations format4_seq_ops;
 
 static void *table_seq_start(struct seq_file *seq, loff_t *pos)
 {
+	struct rb_root *tree;
 	struct rb_node *node;
 	struct dlm_ls *ls = seq->private;
 	struct rsbtbl_iter *ri;
 	struct dlm_rsb *r;
 	loff_t n = *pos;
 	unsigned bucket, entry;
+	int toss = (seq->op == &format4_seq_ops);
 
 	bucket = n >> 32;
 	entry = n & ((1LL << 32) - 1);
@@ -417,11 +466,14 @@ static void *table_seq_start(struct seq_file *seq, loff_t *pos)
 		ri->format = 2;
 	if (seq->op == &format3_seq_ops)
 		ri->format = 3;
+	if (seq->op == &format4_seq_ops)
+		ri->format = 4;
+
+	tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;
 
 	spin_lock(&ls->ls_rsbtbl[bucket].lock);
-	if (!RB_EMPTY_ROOT(&ls->ls_rsbtbl[bucket].keep)) {
-		for (node = rb_first(&ls->ls_rsbtbl[bucket].keep); node;
-		     node = rb_next(node)) {
+	if (!RB_EMPTY_ROOT(tree)) {
+		for (node = rb_first(tree); node; node = rb_next(node)) {
 			r = rb_entry(node, struct dlm_rsb, res_hashnode);
 			if (!entry--) {
 				dlm_hold_rsb(r);
@@ -449,10 +501,11 @@ static void *table_seq_start(struct seq_file *seq, loff_t *pos)
 			kfree(ri);
 			return NULL;
 		}
+		tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;
 
 		spin_lock(&ls->ls_rsbtbl[bucket].lock);
-		if (!RB_EMPTY_ROOT(&ls->ls_rsbtbl[bucket].keep)) {
-			node = rb_first(&ls->ls_rsbtbl[bucket].keep);
+		if (!RB_EMPTY_ROOT(tree)) {
+			node = rb_first(tree);
 			r = rb_entry(node, struct dlm_rsb, res_hashnode);
 			dlm_hold_rsb(r);
 			ri->rsb = r;
@@ -469,10 +522,12 @@ static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos)
 {
 	struct dlm_ls *ls = seq->private;
 	struct rsbtbl_iter *ri = iter_ptr;
+	struct rb_root *tree;
 	struct rb_node *next;
 	struct dlm_rsb *r, *rp;
 	loff_t n = *pos;
 	unsigned bucket;
+	int toss = (seq->op == &format4_seq_ops);
 
 	bucket = n >> 32;
 
@@ -511,10 +566,11 @@ static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos)
 			kfree(ri);
 			return NULL;
 		}
+		tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;
 
 		spin_lock(&ls->ls_rsbtbl[bucket].lock);
-		if (!RB_EMPTY_ROOT(&ls->ls_rsbtbl[bucket].keep)) {
-			next = rb_first(&ls->ls_rsbtbl[bucket].keep);
+		if (!RB_EMPTY_ROOT(tree)) {
+			next = rb_first(tree);
 			r = rb_entry(next, struct dlm_rsb, res_hashnode);
 			dlm_hold_rsb(r);
 			ri->rsb = r;
@@ -558,9 +614,17 @@ static const struct seq_operations format3_seq_ops = {
 	.show  = table_seq_show,
 };
 
+static const struct seq_operations format4_seq_ops = {
+	.start = table_seq_start,
+	.next  = table_seq_next,
+	.stop  = table_seq_stop,
+	.show  = table_seq_show,
+};
+
 static const struct file_operations format1_fops;
 static const struct file_operations format2_fops;
 static const struct file_operations format3_fops;
+static const struct file_operations format4_fops;
 
 static int table_open(struct inode *inode, struct file *file)
 {
@@ -573,6 +637,8 @@ static int table_open(struct inode *inode, struct file *file)
 		ret = seq_open(file, &format2_seq_ops);
 	else if (file->f_op == &format3_fops)
 		ret = seq_open(file, &format3_seq_ops);
+	else if (file->f_op == &format4_fops)
+		ret = seq_open(file, &format4_seq_ops);
 
 	if (ret)
 		return ret;
@@ -606,6 +672,14 @@ static const struct file_operations format3_fops = {
 	.release = seq_release
 };
 
+static const struct file_operations format4_fops = {
+	.owner   = THIS_MODULE,
+	.open    = table_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release
+};
+
 /*
  * dump lkb's on the ls_waiters list
  */
@@ -652,6 +726,8 @@ void dlm_delete_debug_file(struct dlm_ls *ls)
 		debugfs_remove(ls->ls_debug_locks_dentry);
 	if (ls->ls_debug_all_dentry)
 		debugfs_remove(ls->ls_debug_all_dentry);
+	if (ls->ls_debug_toss_dentry)
+		debugfs_remove(ls->ls_debug_toss_dentry);
 }
 
 int dlm_create_debug_file(struct dlm_ls *ls)
@@ -694,6 +770,19 @@ int dlm_create_debug_file(struct dlm_ls *ls)
 	if (!ls->ls_debug_all_dentry)
 		goto fail;
 
+	/* format 4 */
+
+	memset(name, 0, sizeof(name));
+	snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_toss", ls->ls_name);
+
+	ls->ls_debug_toss_dentry = debugfs_create_file(name,
+						       S_IFREG | S_IRUGO,
+						       dlm_root,
+						       ls,
+						       &format4_fops);
+	if (!ls->ls_debug_toss_dentry)
+		goto fail;
+
 	memset(name, 0, sizeof(name));
 	snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name);
 
diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c
index dc5eb59..278a75c 100644
--- a/fs/dlm/dir.c
+++ b/fs/dlm/dir.c
@@ -23,50 +23,6 @@
 #include "lock.h"
 #include "dir.h"
 
-
-static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de)
-{
-	spin_lock(&ls->ls_recover_list_lock);
-	list_add(&de->list, &ls->ls_recover_list);
-	spin_unlock(&ls->ls_recover_list_lock);
-}
-
-static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len)
-{
-	int found = 0;
-	struct dlm_direntry *de;
-
-	spin_lock(&ls->ls_recover_list_lock);
-	list_for_each_entry(de, &ls->ls_recover_list, list) {
-		if (de->length == len) {
-			list_del(&de->list);
-			de->master_nodeid = 0;
-			memset(de->name, 0, len);
-			found = 1;
-			break;
-		}
-	}
-	spin_unlock(&ls->ls_recover_list_lock);
-
-	if (!found)
-		de = kzalloc(sizeof(struct dlm_direntry) + len, GFP_NOFS);
-	return de;
-}
-
-void dlm_clear_free_entries(struct dlm_ls *ls)
-{
-	struct dlm_direntry *de;
-
-	spin_lock(&ls->ls_recover_list_lock);
-	while (!list_empty(&ls->ls_recover_list)) {
-		de = list_entry(ls->ls_recover_list.next, struct dlm_direntry,
-				list);
-		list_del(&de->list);
-		kfree(de);
-	}
-	spin_unlock(&ls->ls_recover_list_lock);
-}
-
 /*
  * We use the upper 16 bits of the hash value to select the directory node.
  * Low bits are used for distribution of rsb's among hash buckets on each node.
@@ -78,144 +34,53 @@ void dlm_clear_free_entries(struct dlm_ls *ls)
 
 int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash)
 {
-	struct list_head *tmp;
-	struct dlm_member *memb = NULL;
-	uint32_t node, n = 0;
-	int nodeid;
-
-	if (ls->ls_num_nodes == 1) {
-		nodeid = dlm_our_nodeid();
-		goto out;
-	}
+	uint32_t node;
 
-	if (ls->ls_node_array) {
+	if (ls->ls_num_nodes == 1)
+		return dlm_our_nodeid();
+	else {
 		node = (hash >> 16) % ls->ls_total_weight;
-		nodeid = ls->ls_node_array[node];
-		goto out;
-	}
-
-	/* make_member_array() failed to kmalloc ls_node_array... */
-
-	node = (hash >> 16) % ls->ls_num_nodes;
-
-	list_for_each(tmp, &ls->ls_nodes) {
-		if (n++ != node)
-			continue;
-		memb = list_entry(tmp, struct dlm_member, list);
-		break;
+		return ls->ls_node_array[node];
 	}
-
-	DLM_ASSERT(memb , printk("num_nodes=%u n=%u node=%u\n",
-				 ls->ls_num_nodes, n, node););
-	nodeid = memb->nodeid;
- out:
-	return nodeid;
 }
 
 int dlm_dir_nodeid(struct dlm_rsb *r)
 {
-	return dlm_hash2nodeid(r->res_ls, r->res_hash);
-}
-
-static inline uint32_t dir_hash(struct dlm_ls *ls, char *name, int len)
-{
-	uint32_t val;
-
-	val = jhash(name, len, 0);
-	val &= (ls->ls_dirtbl_size - 1);
-
-	return val;
-}
-
-static void add_entry_to_hash(struct dlm_ls *ls, struct dlm_direntry *de)
-{
-	uint32_t bucket;
-
-	bucket = dir_hash(ls, de->name, de->length);
-	list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
+	return r->res_dir_nodeid;
 }
 
-static struct dlm_direntry *search_bucket(struct dlm_ls *ls, char *name,
-					  int namelen, uint32_t bucket)
+void dlm_recover_dir_nodeid(struct dlm_ls *ls)
 {
-	struct dlm_direntry *de;
-
-	list_for_each_entry(de, &ls->ls_dirtbl[bucket].list, list) {
-		if (de->length == namelen && !memcmp(name, de->name, namelen))
-			goto out;
-	}
-	de = NULL;
- out:
-	return de;
-}
-
-void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen)
-{
-	struct dlm_direntry *de;
-	uint32_t bucket;
-
-	bucket = dir_hash(ls, name, namelen);
-
-	spin_lock(&ls->ls_dirtbl[bucket].lock);
-
-	de = search_bucket(ls, name, namelen, bucket);
-
-	if (!de) {
-		log_error(ls, "remove fr %u none", nodeid);
-		goto out;
-	}
-
-	if (de->master_nodeid != nodeid) {
-		log_error(ls, "remove fr %u ID %u", nodeid, de->master_nodeid);
-		goto out;
-	}
-
-	list_del(&de->list);
-	kfree(de);
- out:
-	spin_unlock(&ls->ls_dirtbl[bucket].lock);
-}
+	struct dlm_rsb *r;
 
-void dlm_dir_clear(struct dlm_ls *ls)
-{
-	struct list_head *head;
-	struct dlm_direntry *de;
-	int i;
-
-	DLM_ASSERT(list_empty(&ls->ls_recover_list), );
-
-	for (i = 0; i < ls->ls_dirtbl_size; i++) {
-		spin_lock(&ls->ls_dirtbl[i].lock);
-		head = &ls->ls_dirtbl[i].list;
-		while (!list_empty(head)) {
-			de = list_entry(head->next, struct dlm_direntry, list);
-			list_del(&de->list);
-			put_free_de(ls, de);
-		}
-		spin_unlock(&ls->ls_dirtbl[i].lock);
+	down_read(&ls->ls_root_sem);
+	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+		r->res_dir_nodeid = dlm_hash2nodeid(ls, r->res_hash);
 	}
+	up_read(&ls->ls_root_sem);
 }
 
 int dlm_recover_directory(struct dlm_ls *ls)
 {
 	struct dlm_member *memb;
-	struct dlm_direntry *de;
 	char *b, *last_name = NULL;
-	int error = -ENOMEM, last_len, count = 0;
+	int error = -ENOMEM, last_len, nodeid, result;
 	uint16_t namelen;
+	unsigned int count = 0, count_match = 0, count_bad = 0, count_add = 0;
 
 	log_debug(ls, "dlm_recover_directory");
 
 	if (dlm_no_directory(ls))
 		goto out_status;
 
-	dlm_dir_clear(ls);
-
 	last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_NOFS);
 	if (!last_name)
 		goto out;
 
 	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		if (memb->nodeid == dlm_our_nodeid())
+			continue;
+
 		memset(last_name, 0, DLM_RESNAME_MAXLEN);
 		last_len = 0;
 
@@ -230,7 +95,7 @@ int dlm_recover_directory(struct dlm_ls *ls)
 			if (error)
 				goto out_free;
 
-			schedule();
+			cond_resched();
 
 			/*
 			 * pick namelen/name pairs out of received buffer
@@ -267,87 +132,71 @@ int dlm_recover_directory(struct dlm_ls *ls)
 				if (namelen > DLM_RESNAME_MAXLEN)
 					goto out_free;
 
-				error = -ENOMEM;
-				de = get_free_de(ls, namelen);
-				if (!de)
+				error = dlm_master_lookup(ls, memb->nodeid,
+							  b, namelen,
+							  DLM_LU_RECOVER_DIR,
+							  &nodeid, &result);
+				if (error) {
+					log_error(ls, "recover_dir lookup %d",
+						  error);
 					goto out_free;
+				}
+
+				/* The name was found in rsbtbl, but the
+				 * master nodeid is different from
+				 * memb->nodeid which says it is the master.
+				 * This should not happen. */
+
+				if (result == DLM_LU_MATCH &&
+				    nodeid != memb->nodeid) {
+					count_bad++;
+					log_error(ls, "recover_dir lookup %d "
+						  "nodeid %d memb %d bad %u",
+						  result, nodeid, memb->nodeid,
+						  count_bad);
+					print_hex_dump_bytes("dlm_recover_dir ",
+							     DUMP_PREFIX_NONE,
+							     b, namelen);
+				}
+
+				/* The name was found in rsbtbl, and the
+				 * master nodeid matches memb->nodeid. */
+
+				if (result == DLM_LU_MATCH &&
+				    nodeid == memb->nodeid) {
+					count_match++;
+				}
+
+				/* The name was not found in rsbtbl and was
+				 * added with memb->nodeid as the master. */
+
+				if (result == DLM_LU_ADD) {
+					count_add++;
+				}
 
-				de->master_nodeid = memb->nodeid;
-				de->length = namelen;
 				last_len = namelen;
-				memcpy(de->name, b, namelen);
 				memcpy(last_name, b, namelen);
 				b += namelen;
 				left -= namelen;
-
-				add_entry_to_hash(ls, de);
 				count++;
 			}
 		}
-         done:
+	 done:
 		;
 	}
 
  out_status:
 	error = 0;
-	log_debug(ls, "dlm_recover_directory %d entries", count);
+	dlm_set_recover_status(ls, DLM_RS_DIR);
+
+	log_debug(ls, "dlm_recover_directory %u in %u new",
+		  count, count_add);
  out_free:
 	kfree(last_name);
  out:
-	dlm_clear_free_entries(ls);
 	return error;
 }
 
-static int get_entry(struct dlm_ls *ls, int nodeid, char *name,
-		     int namelen, int *r_nodeid)
-{
-	struct dlm_direntry *de, *tmp;
-	uint32_t bucket;
-
-	bucket = dir_hash(ls, name, namelen);
-
-	spin_lock(&ls->ls_dirtbl[bucket].lock);
-	de = search_bucket(ls, name, namelen, bucket);
-	if (de) {
-		*r_nodeid = de->master_nodeid;
-		spin_unlock(&ls->ls_dirtbl[bucket].lock);
-		if (*r_nodeid == nodeid)
-			return -EEXIST;
-		return 0;
-	}
-
-	spin_unlock(&ls->ls_dirtbl[bucket].lock);
-
-	if (namelen > DLM_RESNAME_MAXLEN)
-		return -EINVAL;
-
-	de = kzalloc(sizeof(struct dlm_direntry) + namelen, GFP_NOFS);
-	if (!de)
-		return -ENOMEM;
-
-	de->master_nodeid = nodeid;
-	de->length = namelen;
-	memcpy(de->name, name, namelen);
-
-	spin_lock(&ls->ls_dirtbl[bucket].lock);
-	tmp = search_bucket(ls, name, namelen, bucket);
-	if (tmp) {
-		kfree(de);
-		de = tmp;
-	} else {
-		list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
-	}
-	*r_nodeid = de->master_nodeid;
-	spin_unlock(&ls->ls_dirtbl[bucket].lock);
-	return 0;
-}
-
-int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
-		   int *r_nodeid)
-{
-	return get_entry(ls, nodeid, name, namelen, r_nodeid);
-}
-
 static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len)
 {
 	struct dlm_rsb *r;
@@ -358,10 +207,10 @@ static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len)
 	bucket = hash & (ls->ls_rsbtbl_size - 1);
 
 	spin_lock(&ls->ls_rsbtbl[bucket].lock);
-	rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].keep, name, len, 0, &r);
+	rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].keep, name, len, &r);
 	if (rv)
 		rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].toss,
-					 name, len, 0, &r);
+					 name, len, &r);
 	spin_unlock(&ls->ls_rsbtbl[bucket].lock);
 
 	if (!rv)
@@ -371,7 +220,7 @@ static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len)
 	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
 		if (len == r->res_length && !memcmp(name, r->res_name, len)) {
 			up_read(&ls->ls_root_sem);
-			log_error(ls, "find_rsb_root revert to root_list %s",
+			log_debug(ls, "find_rsb_root revert to root_list %s",
 				  r->res_name);
 			return r;
 		}
@@ -429,6 +278,7 @@ void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
 			be_namelen = cpu_to_be16(0);
 			memcpy(outbuf + offset, &be_namelen, sizeof(__be16));
 			offset += sizeof(__be16);
+			ls->ls_recover_dir_sent_msg++;
 			goto out;
 		}
 
@@ -437,6 +287,7 @@ void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
 		offset += sizeof(__be16);
 		memcpy(outbuf + offset, r->res_name, r->res_length);
 		offset += r->res_length;
+		ls->ls_recover_dir_sent_res++;
 	}
 
 	/*
@@ -449,8 +300,8 @@ void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
 		be_namelen = cpu_to_be16(0xFFFF);
 		memcpy(outbuf + offset, &be_namelen, sizeof(__be16));
 		offset += sizeof(__be16);
+		ls->ls_recover_dir_sent_msg++;
 	}
-
  out:
 	up_read(&ls->ls_root_sem);
 }
diff --git a/fs/dlm/dir.h b/fs/dlm/dir.h
index 0b0eb12..4175063 100644
--- a/fs/dlm/dir.h
+++ b/fs/dlm/dir.h
@@ -14,15 +14,10 @@
 #ifndef __DIR_DOT_H__
 #define __DIR_DOT_H__
 
-
 int dlm_dir_nodeid(struct dlm_rsb *rsb);
 int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash);
-void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int len);
-void dlm_dir_clear(struct dlm_ls *ls);
-void dlm_clear_free_entries(struct dlm_ls *ls);
+void dlm_recover_dir_nodeid(struct dlm_ls *ls);
 int dlm_recover_directory(struct dlm_ls *ls);
-int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
-	int *r_nodeid);
 void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
 	char *outbuf, int outlen, int nodeid);
 
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index bc342f7..9d3e485 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -55,8 +55,6 @@ struct dlm_lkb;
 struct dlm_rsb;
 struct dlm_member;
 struct dlm_rsbtable;
-struct dlm_dirtable;
-struct dlm_direntry;
 struct dlm_recover;
 struct dlm_header;
 struct dlm_message;
@@ -98,18 +96,6 @@ do { \
 }
 
 
-struct dlm_direntry {
-	struct list_head	list;
-	uint32_t		master_nodeid;
-	uint16_t		length;
-	char			name[1];
-};
-
-struct dlm_dirtable {
-	struct list_head	list;
-	spinlock_t		lock;
-};
-
 struct dlm_rsbtable {
 	struct rb_root		keep;
 	struct rb_root		toss;
@@ -283,6 +269,15 @@ struct dlm_lkb {
 	};
 };
 
+/*
+ * res_master_nodeid is "normal": 0 is unset/invalid, non-zero is the real
+ * nodeid, even when nodeid is our_nodeid.
+ *
+ * res_nodeid is "odd": -1 is unset/invalid, zero means our_nodeid,
+ * greater than zero when another nodeid.
+ *
+ * (TODO: remove res_nodeid and only use res_master_nodeid)
+ */
 
 struct dlm_rsb {
 	struct dlm_ls		*res_ls;	/* the lockspace */
@@ -291,6 +286,9 @@ struct dlm_rsb {
 	unsigned long		res_flags;
 	int			res_length;	/* length of rsb name */
 	int			res_nodeid;
+	int			res_master_nodeid;
+	int			res_dir_nodeid;
+	int			res_id;		/* for ls_recover_idr */
 	uint32_t                res_lvbseq;
 	uint32_t		res_hash;
 	uint32_t		res_bucket;	/* rsbtbl */
@@ -313,10 +311,21 @@ struct dlm_rsb {
 	char			res_name[DLM_RESNAME_MAXLEN+1];
 };
 
+/* dlm_master_lookup() flags */
+
+#define DLM_LU_RECOVER_DIR	1
+#define DLM_LU_RECOVER_MASTER	2
+
+/* dlm_master_lookup() results */
+
+#define DLM_LU_MATCH		1
+#define DLM_LU_ADD		2
+
 /* find_rsb() flags */
 
-#define R_MASTER		1	/* only return rsb if it's a master */
-#define R_CREATE		2	/* create/add rsb if not found */
+#define R_REQUEST		0x00000001
+#define R_RECEIVE_REQUEST	0x00000002
+#define R_RECEIVE_RECOVER	0x00000004
 
 /* rsb_flags */
 
@@ -489,6 +498,13 @@ struct rcom_lock {
 	char			rl_lvb[0];
 };
 
+/*
+ * The max number of resources per rsbtbl bucket that shrink will attempt
+ * to remove in each iteration.
+ */
+
+#define DLM_REMOVE_NAMES_MAX 8
+
 struct dlm_ls {
 	struct list_head	ls_list;	/* list of lockspaces */
 	dlm_lockspace_t		*ls_local_handle;
@@ -509,9 +525,6 @@ struct dlm_ls {
 	struct dlm_rsbtable	*ls_rsbtbl;
 	uint32_t		ls_rsbtbl_size;
 
-	struct dlm_dirtable	*ls_dirtbl;
-	uint32_t		ls_dirtbl_size;
-
 	struct mutex		ls_waiters_mutex;
 	struct list_head	ls_waiters;	/* lkbs needing a reply */
 
@@ -525,6 +538,12 @@ struct dlm_ls {
 	int			ls_new_rsb_count;
 	struct list_head	ls_new_rsb;	/* new rsb structs */
 
+	spinlock_t		ls_remove_spin;
+	char			ls_remove_name[DLM_RESNAME_MAXLEN+1];
+	char			*ls_remove_names[DLM_REMOVE_NAMES_MAX];
+	int			ls_remove_len;
+	int			ls_remove_lens[DLM_REMOVE_NAMES_MAX];
+
 	struct list_head	ls_nodes;	/* current nodes in ls */
 	struct list_head	ls_nodes_gone;	/* dead node list, recovery */
 	int			ls_num_nodes;	/* number of nodes in ls */
@@ -545,6 +564,7 @@ struct dlm_ls {
 	struct dentry		*ls_debug_waiters_dentry; /* debugfs */
 	struct dentry		*ls_debug_locks_dentry; /* debugfs */
 	struct dentry		*ls_debug_all_dentry; /* debugfs */
+	struct dentry		*ls_debug_toss_dentry; /* debugfs */
 
 	wait_queue_head_t	ls_uevent_wait;	/* user part of join/leave */
 	int			ls_uevent_result;
@@ -573,12 +593,16 @@ struct dlm_ls {
 	struct mutex		ls_requestqueue_mutex;
 	struct dlm_rcom		*ls_recover_buf;
 	int			ls_recover_nodeid; /* for debugging */
+	unsigned int		ls_recover_dir_sent_res; /* for log info */
+	unsigned int		ls_recover_dir_sent_msg; /* for log info */
 	unsigned int		ls_recover_locks_in; /* for log info */
 	uint64_t		ls_rcom_seq;
 	spinlock_t		ls_rcom_spin;
 	struct list_head	ls_recover_list;
 	spinlock_t		ls_recover_list_lock;
 	int			ls_recover_list_count;
+	struct idr		ls_recover_idr;
+	spinlock_t		ls_recover_idr_lock;
 	wait_queue_head_t	ls_wait_general;
 	struct mutex		ls_clear_proc_locks;
 
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index bdafb65..f061dd3 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -170,9 +170,11 @@ void dlm_print_lkb(struct dlm_lkb *lkb)
 
 static void dlm_print_rsb(struct dlm_rsb *r)
 {
-	printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n",
-	       r->res_nodeid, r->res_flags, r->res_first_lkid,
-	       r->res_recover_locks_count, r->res_name);
+	printk(KERN_ERR "rsb: nodeid %d master %d dir %d flags %lx first %x "
+	       "rlc %d name %s\n",
+	       r->res_nodeid, r->res_master_nodeid, r->res_dir_nodeid,
+	       r->res_flags, r->res_first_lkid, r->res_recover_locks_count,
+	       r->res_name);
 }
 
 void dlm_dump_rsb(struct dlm_rsb *r)
@@ -411,11 +413,10 @@ static int rsb_cmp(struct dlm_rsb *r, const char *name, int nlen)
 }
 
 int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len,
-			unsigned int flags, struct dlm_rsb **r_ret)
+			struct dlm_rsb **r_ret)
 {
 	struct rb_node *node = tree->rb_node;
 	struct dlm_rsb *r;
-	int error = 0;
 	int rc;
 
 	while (node) {
@@ -432,10 +433,8 @@ int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len,
 	return -EBADR;
 
  found:
-	if (r->res_nodeid && (flags & R_MASTER))
-		error = -ENOTBLK;
 	*r_ret = r;
-	return error;
+	return 0;
 }
 
 static int rsb_insert(struct dlm_rsb *rsb, struct rb_root *tree)
@@ -467,124 +466,568 @@ static int rsb_insert(struct dlm_rsb *rsb, struct rb_root *tree)
 	return 0;
 }
 
-static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b,
-		       unsigned int flags, struct dlm_rsb **r_ret)
+/*
+ * Find rsb in rsbtbl and potentially create/add one
+ *
+ * Delaying the release of rsb's has a similar benefit to applications keeping
+ * NL locks on an rsb, but without the guarantee that the cached master value
+ * will still be valid when the rsb is reused.  Apps aren't always smart enough
+ * to keep NL locks on an rsb that they may lock again shortly; this can lead
+ * to excessive master lookups and removals if we don't delay the release.
+ *
+ * Searching for an rsb means looking through both the normal list and toss
+ * list.  When found on the toss list the rsb is moved to the normal list with
+ * ref count of 1; when found on normal list the ref count is incremented.
+ *
+ * rsb's on the keep list are being used locally and refcounted.
+ * rsb's on the toss list are not being used locally, and are not refcounted.
+ *
+ * The toss list rsb's were either
+ * - previously used locally but not any more (were on keep list, then
+ *   moved to toss list when last refcount dropped)
+ * - created and put on toss list as a directory record for a lookup
+ *   (we are the dir node for the res, but are not using the res right now,
+ *   but some other node is)
+ *
+ * The purpose of find_rsb() is to return a refcounted rsb for local use.
+ * So, if the given rsb is on the toss list, it is moved to the keep list
+ * before being returned.
+ *
+ * toss_rsb() happens when all local usage of the rsb is done, i.e. no
+ * more refcounts exist, so the rsb is moved from the keep list to the
+ * toss list.
+ *
+ * rsb's on both keep and toss lists are used for doing a name to master
+ * lookups.  rsb's that are in use locally (and being refcounted) are on
+ * the keep list, rsb's that are not in use locally (not refcounted) and
+ * only exist for name/master lookups are on the toss list.
+ *
+ * rsb's on the toss list who's dir_nodeid is not local can have stale
+ * name/master mappings.  So, remote requests on such rsb's can potentially
+ * return with an error, which means the mapping is stale and needs to
+ * be updated with a new lookup.  (The idea behind MASTER UNCERTAIN and
+ * first_lkid is to keep only a single outstanding request on an rsb
+ * while that rsb has a potentially stale master.)
+ */
+
+static int find_rsb_dir(struct dlm_ls *ls, char *name, int len,
+			uint32_t hash, uint32_t b,
+			int dir_nodeid, int from_nodeid,
+			unsigned int flags, struct dlm_rsb **r_ret)
 {
-	struct dlm_rsb *r;
+	struct dlm_rsb *r = NULL;
+	int our_nodeid = dlm_our_nodeid();
+	int from_local = 0;
+	int from_other = 0;
+	int from_dir = 0;
+	int create = 0;
 	int error;
 
-	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, flags, &r);
-	if (!error) {
-		kref_get(&r->res_ref);
-		goto out;
+	if (flags & R_RECEIVE_REQUEST) {
+		if (from_nodeid == dir_nodeid)
+			from_dir = 1;
+		else
+			from_other = 1;
+	} else if (flags & R_REQUEST) {
+		from_local = 1;
 	}
-	if (error == -ENOTBLK)
-		goto out;
 
-	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
+	/*
+	 * flags & R_RECEIVE_RECOVER is from dlm_recover_master_copy, so
+	 * from_nodeid has sent us a lock in dlm_recover_locks, believing
+	 * we're the new master.  Our local recovery may not have set
+	 * res_master_nodeid to our_nodeid yet, so allow either.  Don't
+	 * create the rsb; dlm_recover_process_copy() will handle EBADR
+	 * by resending.
+	 *
+	 * If someone sends us a request, we are the dir node, and we do
+	 * not find the rsb anywhere, then recreate it.  This happens if
+	 * someone sends us a request after we have removed/freed an rsb
+	 * from our toss list.  (They sent a request instead of lookup
+	 * because they are using an rsb from their toss list.)
+	 */
+
+	if (from_local || from_dir ||
+	    (from_other && (dir_nodeid == our_nodeid))) {
+		create = 1;
+	}
+
+ retry:
+	if (create) {
+		error = pre_rsb_struct(ls);
+		if (error < 0)
+			goto out;
+	}
+
+	spin_lock(&ls->ls_rsbtbl[b].lock);
+
+	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, &r);
 	if (error)
-		goto out;
+		goto do_toss;
 
-	rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
-	error = rsb_insert(r, &ls->ls_rsbtbl[b].keep);
+	/*
+	 * rsb found in use
+	 */
+
+	if ((r->res_master_nodeid != our_nodeid) && from_other) {
+		/* our rsb is not master, and another node (not the dir node)
+		   has sent us a request.  this is much more common when
+		   our master_nodeid is zero, so limit debug to non-zero. */
+		if (r->res_master_nodeid) {
+			log_debug(ls, "find_rsb keep from_other %d master %d "
+				  "dir %d first %x %s", from_nodeid,
+				  r->res_master_nodeid, dir_nodeid,
+				  r->res_first_lkid, r->res_name);
+		}
+		error = -ENOTBLK;
+		goto out_unlock;
+	}
+
+	if ((r->res_master_nodeid != our_nodeid) && from_dir) {
+		/* our rsb is not master, but the dir nodeid has sent us a
+		   request; this could happen with master 0 / res_nodeid -1 */
+
+		if (r->res_master_nodeid) {
+			log_error(ls, "find_rsb keep from_dir %d master %d "
+				  "first %x %s",
+				  from_nodeid, r->res_master_nodeid,
+				  r->res_first_lkid, r->res_name);
+		}
+
+		r->res_master_nodeid = our_nodeid;
+		r->res_nodeid = 0;
+		/* fall through to kref_get */
+	}
+
+	kref_get(&r->res_ref);
+	error = 0;
+	goto out_unlock;
+
+
+ do_toss:
+	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
 	if (error)
-		return error;
+		goto do_new;
 
-	if (dlm_no_directory(ls))
-		goto out;
+	/*
+	 * rsb found unused (master_nodeid may be out of date unless
+	 * we are the dir_nodeid or were the master)
+	 */
 
-	if (r->res_nodeid == -1) {
+	if ((r->res_master_nodeid != our_nodeid) && from_other) {
+		/* our rsb was not master, and another node (not the dir node)
+		   has sent us a request */
+		log_debug(ls, "find_rsb toss from_other %d master %d dir %d %s",
+			  from_nodeid, r->res_master_nodeid, dir_nodeid,
+			  r->res_name);
+		error = -ENOTBLK;
+		goto out_unlock;
+	}
+
+	if ((r->res_master_nodeid != our_nodeid) && from_dir) {
+		/* don't think this should ever happen */
+		log_error(ls, "find_rsb toss from_dir %d master %d",
+			  from_nodeid, r->res_master_nodeid);
+		dlm_print_rsb(r);
+		/* fix it and go on */
+		r->res_master_nodeid = our_nodeid;
+		r->res_nodeid = 0;
 		rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
 		r->res_first_lkid = 0;
-	} else if (r->res_nodeid > 0) {
+	}
+
+	if (from_local && (r->res_master_nodeid != our_nodeid)) {
+		/* Because we have held no locks on this rsb,
+		   res_master_nodeid could have become stale. */
 		rsb_set_flag(r, RSB_MASTER_UNCERTAIN);
 		r->res_first_lkid = 0;
+	}
+
+	rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
+	error = rsb_insert(r, &ls->ls_rsbtbl[b].keep);
+	goto out_unlock;
+
+
+ do_new:
+	/*
+	 * rsb not found
+	 */
+
+	if (error == -EBADR && !create)
+		goto out_unlock;
+
+	error = get_rsb_struct(ls, name, len, &r);
+	if (error == -EAGAIN) {
+		spin_unlock(&ls->ls_rsbtbl[b].lock);
+		goto retry;
+	}
+	if (error)
+		goto out_unlock;
+
+	r->res_hash = hash;
+	r->res_bucket = b;
+	r->res_dir_nodeid = dir_nodeid;
+	kref_init(&r->res_ref);
+
+	if (from_dir) {
+		/* want to see how often this happens */
+		log_debug(ls, "find_rsb new from_dir %d recreate %s",
+			  from_nodeid, r->res_name);
+		r->res_master_nodeid = our_nodeid;
+		r->res_nodeid = 0;
+		goto out_add;
+	}
+
+	if (from_other && (dir_nodeid != our_nodeid)) {
+		/* should never happen */
+		log_error(ls, "find_rsb new from_other %d dir %d our %d %s",
+			  from_nodeid, dir_nodeid, our_nodeid, r->res_name);
+		dlm_free_rsb(r);
+		error = -ENOTBLK;
+		goto out_unlock;
+	}
+
+	if (from_other) {
+		log_debug(ls, "find_rsb new from_other %d dir %d %s",
+			  from_nodeid, dir_nodeid, r->res_name);
+	}
+
+	if (dir_nodeid == our_nodeid) {
+		/* When we are the dir nodeid, we can set the master
+		   node immediately */
+		r->res_master_nodeid = our_nodeid;
+		r->res_nodeid = 0;
 	} else {
-		DLM_ASSERT(r->res_nodeid == 0, dlm_print_rsb(r););
-		DLM_ASSERT(!rsb_flag(r, RSB_MASTER_UNCERTAIN),);
+		/* set_master will send_lookup to dir_nodeid */
+		r->res_master_nodeid = 0;
+		r->res_nodeid = -1;
 	}
+
+ out_add:
+	error = rsb_insert(r, &ls->ls_rsbtbl[b].keep);
+ out_unlock:
+	spin_unlock(&ls->ls_rsbtbl[b].lock);
  out:
 	*r_ret = r;
 	return error;
 }
 
+/* During recovery, other nodes can send us new MSTCPY locks (from
+   dlm_recover_locks) before we've made ourself master (in
+   dlm_recover_masters). */
+
+static int find_rsb_nodir(struct dlm_ls *ls, char *name, int len,
+			  uint32_t hash, uint32_t b,
+			  int dir_nodeid, int from_nodeid,
+			  unsigned int flags, struct dlm_rsb **r_ret)
+{
+	struct dlm_rsb *r = NULL;
+	int our_nodeid = dlm_our_nodeid();
+	int recover = (flags & R_RECEIVE_RECOVER);
+	int error;
+
+ retry:
+	error = pre_rsb_struct(ls);
+	if (error < 0)
+		goto out;
+
+	spin_lock(&ls->ls_rsbtbl[b].lock);
+
+	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, &r);
+	if (error)
+		goto do_toss;
+
+	/*
+	 * rsb found in use
+	 */
+
+	if (!recover && (r->res_master_nodeid != our_nodeid) && from_nodeid) {
+		/* our rsb is not master, and another node has sent us a
+		   request; this should never happen */
+		log_error(ls, "find_rsb keep from_nodeid %d master %d dir %d",
+			  from_nodeid, r->res_master_nodeid, dir_nodeid);
+		dlm_print_rsb(r);
+		error = -ENOTBLK;
+		goto out_unlock;
+	}
+
+	if (!recover && (r->res_master_nodeid != our_nodeid) &&
+	    (dir_nodeid == our_nodeid)) {
+		/* our rsb is not master, and we are dir; just fix it up;
+		   this should never happen */
+		log_error(ls, "find_rsb keep our %d master %d dir %d",
+			  our_nodeid, r->res_master_nodeid, dir_nodeid);
+		dlm_print_rsb(r);
+		r->res_master_nodeid = our_nodeid;
+		r->res_nodeid = 0;
+		error = 0;
+		goto out_unlock;
+	}
+
+	kref_get(&r->res_ref);
+	goto out_unlock;
+
+
+ do_toss:
+	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
+	if (error)
+		goto do_new;
+
+	/*
+	 * rsb found on toss list; may be unused or dir record
+	 */
+
+	if (!recover && (r->res_master_nodeid != our_nodeid) && from_nodeid) {
+		/* our rsb is not master, and another node has sent us a
+		   request; this should never happen */
+		log_error(ls, "find_rsb toss from_nodeid %d master %d dir %d",
+			  from_nodeid, r->res_master_nodeid, dir_nodeid);
+		dlm_print_rsb(r);
+		error = -ENOTBLK;
+		goto out_unlock;
+	}
+
+	if (!recover && (r->res_master_nodeid != our_nodeid) &&
+	    (dir_nodeid == our_nodeid)) {
+		/* our rsb is not master, and we are dir; may as well fix it;
+		   this should never happen */
+		log_error(ls, "find_rsb toss our %d master %d dir %d",
+			  our_nodeid, r->res_master_nodeid, dir_nodeid);
+		dlm_print_rsb(r);
+		r->res_master_nodeid = our_nodeid;
+		r->res_nodeid = 0;
+	}
+
+	rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
+	error = rsb_insert(r, &ls->ls_rsbtbl[b].keep);
+	goto out_unlock;
+
+
+ do_new:
+	/*
+	 * rsb not found
+	 */
+
+	error = get_rsb_struct(ls, name, len, &r);
+	if (error == -EAGAIN) {
+		spin_unlock(&ls->ls_rsbtbl[b].lock);
+		goto retry;
+	}
+	if (error)
+		goto out_unlock;
+
+	r->res_hash = hash;
+	r->res_bucket = b;
+	r->res_dir_nodeid = dir_nodeid;
+	r->res_master_nodeid = dir_nodeid;
+	r->res_nodeid = (dir_nodeid == our_nodeid) ? 0 : dir_nodeid;
+	kref_init(&r->res_ref);
+
+	error = rsb_insert(r, &ls->ls_rsbtbl[b].keep);
+ out_unlock:
+	spin_unlock(&ls->ls_rsbtbl[b].lock);
+ out:
+	*r_ret = r;
+	return error;
+}
+
+static int find_rsb(struct dlm_ls *ls, char *name, int len, int from_nodeid,
+		    unsigned int flags, struct dlm_rsb **r_ret)
+{
+	uint32_t hash, b;
+	int dir_nodeid;
+
+	if (len > DLM_RESNAME_MAXLEN)
+		return -EINVAL;
+
+	hash = jhash(name, len, 0);
+	b = hash & (ls->ls_rsbtbl_size - 1);
+
+	dir_nodeid = dlm_hash2nodeid(ls, hash);
+
+	if (dlm_no_directory(ls))
+		return find_rsb_nodir(ls, name, len, hash, b, dir_nodeid,
+				      from_nodeid, flags, r_ret);
+	else
+		return find_rsb_dir(ls, name, len, hash, b, dir_nodeid,
+				      from_nodeid, flags, r_ret);
+}
+
 /*
- * Find rsb in rsbtbl and potentially create/add one
+ * We're the dir node for this res and another node wants to know the
+ * master nodeid.  During normal operation (non recovery) this is only
+ * called from receive_lookup(); master lookups when the local node is
+ * the dir node are done by find_rsb().
  *
- * Delaying the release of rsb's has a similar benefit to applications keeping
- * NL locks on an rsb, but without the guarantee that the cached master value
- * will still be valid when the rsb is reused.  Apps aren't always smart enough
- * to keep NL locks on an rsb that they may lock again shortly; this can lead
- * to excessive master lookups and removals if we don't delay the release.
+ * normal operation, we are the dir node for a resource
+ * . _request_lock
+ * . set_master
+ * . send_lookup
+ * . receive_lookup
+ * . dlm_master_lookup flags 0
  *
- * Searching for an rsb means looking through both the normal list and toss
- * list.  When found on the toss list the rsb is moved to the normal list with
- * ref count of 1; when found on normal list the ref count is incremented.
+ * recover directory, we are rebuilding dir for all resources
+ * . dlm_recover_directory
+ * . dlm_rcom_names
+ *   remote node sends back the rsb names it is master of and we are dir of
+ * . dlm_master_lookup RECOVER_DIR (fix_master 0, from_master 1)
+ *   we either create new rsb setting remote node as master, or find existing
+ *   rsb and set master to be the remote node.
+ *
+ * recover masters, we are finding the new master for resources
+ * . dlm_recover_masters
+ * . recover_master
+ * . dlm_send_rcom_lookup
+ * . receive_rcom_lookup
+ * . dlm_master_lookup RECOVER_MASTER (fix_master 1, from_master 0)
  */
 
-static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
-		    unsigned int flags, struct dlm_rsb **r_ret)
+int dlm_master_lookup(struct dlm_ls *ls, int from_nodeid, char *name, int len,
+		      unsigned int flags, int *r_nodeid, int *result)
 {
 	struct dlm_rsb *r = NULL;
-	uint32_t hash, bucket;
-	int error;
+	uint32_t hash, b;
+	int from_master = (flags & DLM_LU_RECOVER_DIR);
+	int fix_master = (flags & DLM_LU_RECOVER_MASTER);
+	int our_nodeid = dlm_our_nodeid();
+	int dir_nodeid, error, toss_list = 0;
 
-	if (namelen > DLM_RESNAME_MAXLEN) {
-		error = -EINVAL;
-		goto out;
+	if (len > DLM_RESNAME_MAXLEN)
+		return -EINVAL;
+
+	if (from_nodeid == our_nodeid) {
+		log_error(ls, "dlm_master_lookup from our_nodeid %d flags %x",
+			  our_nodeid, flags);
+		return -EINVAL;
 	}
 
-	if (dlm_no_directory(ls))
-		flags |= R_CREATE;
+	hash = jhash(name, len, 0);
+	b = hash & (ls->ls_rsbtbl_size - 1);
 
-	hash = jhash(name, namelen, 0);
-	bucket = hash & (ls->ls_rsbtbl_size - 1);
+	dir_nodeid = dlm_hash2nodeid(ls, hash);
+	if (dir_nodeid != our_nodeid) {
+		log_error(ls, "dlm_master_lookup from %d dir %d our %d h %x %d",
+			  from_nodeid, dir_nodeid, our_nodeid, hash,
+			  ls->ls_num_nodes);
+		*r_nodeid = -1;
+		return -EINVAL;
+	}
 
  retry:
-	if (flags & R_CREATE) {
-		error = pre_rsb_struct(ls);
-		if (error < 0)
-			goto out;
+	error = pre_rsb_struct(ls);
+	if (error < 0)
+		return error;
+
+	spin_lock(&ls->ls_rsbtbl[b].lock);
+	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, &r);
+	if (!error)
+		goto found;
+
+	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
+	if (error)
+		goto not_found;
+
+	toss_list = 1;
+ found:
+	if (r->res_dir_nodeid != our_nodeid) {
+		/* should not happen, but may as well fix it and carry on */
+		log_error(ls, "dlm_master_lookup res_dir %d our %d %s",
+			  r->res_dir_nodeid, our_nodeid, r->res_name);
+		r->res_dir_nodeid = our_nodeid;
+	}
+
+	if (fix_master && dlm_is_removed(ls, r->res_master_nodeid)) {
+		/* Recovery uses this function to set a new master when
+		   the previous master failed.  Setting NEW_MASTER will
+		   force dlm_recover_masters to call recover_master on this
+		   rsb even though the res_nodeid is no longer removed. */
+
+		r->res_master_nodeid = from_nodeid;
+		r->res_nodeid = from_nodeid;
+		rsb_set_flag(r, RSB_NEW_MASTER);
+
+		if (toss_list) {
+			/* I don't think we should ever find it on toss list. */
+			log_error(ls, "dlm_master_lookup fix_master on toss");
+			dlm_dump_rsb(r);
+		}
 	}
 
-	spin_lock(&ls->ls_rsbtbl[bucket].lock);
+	if (from_master && (r->res_master_nodeid != from_nodeid)) {
+		/* this will happen if from_nodeid became master during
+		   a previous recovery cycle, and we aborted the previous
+		   cycle before recovering this master value */
 
-	error = _search_rsb(ls, name, namelen, bucket, flags, &r);
-	if (!error)
-		goto out_unlock;
+		log_limit(ls, "dlm_master_lookup from_master %d "
+			  "master_nodeid %d res_nodeid %d first %x %s",
+			  from_nodeid, r->res_master_nodeid, r->res_nodeid,
+			  r->res_first_lkid, r->res_name);
+		r->res_master_nodeid = from_nodeid;
+		r->res_nodeid = from_nodeid;
+		rsb_set_flag(r, RSB_NEW_MASTER);
+	}
 
-	if (error == -EBADR && !(flags & R_CREATE))
-		goto out_unlock;
+	if (!r->res_master_nodeid) {
+		/* this will happen if recovery happens while we're looking
+		   up the master for this rsb */
 
-	/* the rsb was found but wasn't a master copy */
-	if (error == -ENOTBLK)
-		goto out_unlock;
+		log_debug(ls, "dlm_master_lookup master 0 to %d first %x %s",
+			  from_nodeid, r->res_first_lkid, r->res_name);
+		r->res_master_nodeid = from_nodeid;
+		r->res_nodeid = from_nodeid;
+	}
+
+	if (!from_master && !fix_master &&
+	    (r->res_master_nodeid == from_nodeid)) {
+		/* this can happen when the master sends remove, the dir node
+		   finds the rsb on the keep list and ignores the remove,
+		   and the former master sends a lookup */
+
+		log_limit(ls, "dlm_master_lookup from master %d flags %x "
+			  "first %x %s", from_nodeid, flags,
+			  r->res_first_lkid, r->res_name);
+	}
+
+	if (toss_list)
+		r->res_toss_time = jiffies;
+
+	*r_nodeid = r->res_master_nodeid;
+	if (result)
+		*result = DLM_LU_MATCH;
+	spin_unlock(&ls->ls_rsbtbl[b].lock);
+	return 0;
 
-	error = get_rsb_struct(ls, name, namelen, &r);
+ not_found:
+	error = get_rsb_struct(ls, name, len, &r);
 	if (error == -EAGAIN) {
-		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+		spin_unlock(&ls->ls_rsbtbl[b].lock);
 		goto retry;
 	}
 	if (error)
 		goto out_unlock;
 
 	r->res_hash = hash;
-	r->res_bucket = bucket;
-	r->res_nodeid = -1;
+	r->res_bucket = b;
+	r->res_dir_nodeid = our_nodeid;
+	r->res_master_nodeid = from_nodeid;
+	r->res_nodeid = from_nodeid;
 	kref_init(&r->res_ref);
+	r->res_toss_time = jiffies;
 
-	/* With no directory, the master can be set immediately */
-	if (dlm_no_directory(ls)) {
-		int nodeid = dlm_dir_nodeid(r);
-		if (nodeid == dlm_our_nodeid())
-			nodeid = 0;
-		r->res_nodeid = nodeid;
+	error = rsb_insert(r, &ls->ls_rsbtbl[b].toss);
+	if (error) {
+		/* should never happen */
+		dlm_free_rsb(r);
+		spin_unlock(&ls->ls_rsbtbl[b].lock);
+		goto retry;
 	}
-	error = rsb_insert(r, &ls->ls_rsbtbl[bucket].keep);
+
+	if (result)
+		*result = DLM_LU_ADD;
+	*r_nodeid = from_nodeid;
+	error = 0;
  out_unlock:
-	spin_unlock(&ls->ls_rsbtbl[bucket].lock);
- out:
-	*r_ret = r;
+	spin_unlock(&ls->ls_rsbtbl[b].lock);
 	return error;
 }
 
@@ -1138,61 +1581,170 @@ static int remove_from_waiters_ms(struct dlm_lkb *lkb, struct dlm_message *ms)
 	return error;
 }
 
-static void dir_remove(struct dlm_rsb *r)
-{
-	int to_nodeid;
+/* If there's an rsb for the same resource being removed, ensure
+   that the remove message is sent before the new lookup message.
+   It should be rare to need a delay here, but if not, then it may
+   be worthwhile to add a proper wait mechanism rather than a delay. */
 
-	if (dlm_no_directory(r->res_ls))
-		return;
-
-	to_nodeid = dlm_dir_nodeid(r);
-	if (to_nodeid != dlm_our_nodeid())
-		send_remove(r);
-	else
-		dlm_dir_remove_entry(r->res_ls, to_nodeid,
-				     r->res_name, r->res_length);
+static void wait_pending_remove(struct dlm_rsb *r)
+{
+	struct dlm_ls *ls = r->res_ls;
+ restart:
+	spin_lock(&ls->ls_remove_spin);
+	if (ls->ls_remove_len &&
+	    !rsb_cmp(r, ls->ls_remove_name, ls->ls_remove_len)) {
+		log_debug(ls, "delay lookup for remove dir %d %s",
+		  	  r->res_dir_nodeid, r->res_name);
+		spin_unlock(&ls->ls_remove_spin);
+		msleep(1);
+		goto restart;
+	}
+	spin_unlock(&ls->ls_remove_spin);
 }
 
-/* FIXME: make this more efficient */
+/*
+ * ls_remove_spin protects ls_remove_name and ls_remove_len which are
+ * read by other threads in wait_pending_remove.  ls_remove_names
+ * and ls_remove_lens are only used by the scan thread, so they do
+ * not need protection.
+ */
 
-static int shrink_bucket(struct dlm_ls *ls, int b)
+static void shrink_bucket(struct dlm_ls *ls, int b)
 {
-	struct rb_node *n;
+	struct rb_node *n, *next;
 	struct dlm_rsb *r;
-	int count = 0, found;
+	char *name;
+	int our_nodeid = dlm_our_nodeid();
+	int remote_count = 0;
+	int i, len, rv;
+
+	memset(&ls->ls_remove_lens, 0, sizeof(int) * DLM_REMOVE_NAMES_MAX);
+
+	spin_lock(&ls->ls_rsbtbl[b].lock);
+	for (n = rb_first(&ls->ls_rsbtbl[b].toss); n; n = next) {
+		next = rb_next(n);
+		r = rb_entry(n, struct dlm_rsb, res_hashnode);
+
+		/* If we're the directory record for this rsb, and
+		   we're not the master of it, then we need to wait
+		   for the master node to send us a dir remove for
+		   before removing the dir record. */
+
+		if (!dlm_no_directory(ls) &&
+		    (r->res_master_nodeid != our_nodeid) &&
+		    (dlm_dir_nodeid(r) == our_nodeid)) {
+			continue;
+		}
+
+		if (!time_after_eq(jiffies, r->res_toss_time +
+				   dlm_config.ci_toss_secs * HZ)) {
+			continue;
+		}
+
+		if (!dlm_no_directory(ls) &&
+		    (r->res_master_nodeid == our_nodeid) &&
+		    (dlm_dir_nodeid(r) != our_nodeid)) {
+
+			/* We're the master of this rsb but we're not
+			   the directory record, so we need to tell the
+			   dir node to remove the dir record. */
+
+			ls->ls_remove_lens[remote_count] = r->res_length;
+			memcpy(ls->ls_remove_names[remote_count], r->res_name,
+			       DLM_RESNAME_MAXLEN);
+			remote_count++;
+
+			if (remote_count >= DLM_REMOVE_NAMES_MAX)
+				break;
+			continue;
+		}
+
+		if (!kref_put(&r->res_ref, kill_rsb)) {
+			log_error(ls, "tossed rsb in use %s", r->res_name);
+			continue;
+		}
+
+		rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
+		dlm_free_rsb(r);
+	}
+	spin_unlock(&ls->ls_rsbtbl[b].lock);
+
+	/*
+	 * While searching for rsb's to free, we found some that require
+	 * remote removal.  We leave them in place and find them again here
+	 * so there is a very small gap between removing them from the toss
+	 * list and sending the removal.  Keeping this gap small is
+	 * important to keep us (the master node) from being out of sync
+	 * with the remote dir node for very long.
+	 *
+	 * From the time the rsb is removed from toss until just after
+	 * send_remove, the rsb name is saved in ls_remove_name.  A new
+	 * lookup checks this to ensure that a new lookup message for the
+	 * same resource name is not sent just before the remove message.
+	 */
+
+	for (i = 0; i < remote_count; i++) {
+		name = ls->ls_remove_names[i];
+		len = ls->ls_remove_lens[i];
 
-	for (;;) {
-		found = 0;
 		spin_lock(&ls->ls_rsbtbl[b].lock);
-		for (n = rb_first(&ls->ls_rsbtbl[b].toss); n; n = rb_next(n)) {
-			r = rb_entry(n, struct dlm_rsb, res_hashnode);
-			if (!time_after_eq(jiffies, r->res_toss_time +
-					   dlm_config.ci_toss_secs * HZ))
-				continue;
-			found = 1;
-			break;
+		rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
+		if (rv) {
+			spin_unlock(&ls->ls_rsbtbl[b].lock);
+			log_debug(ls, "remove_name not toss %s", name);
+			continue;
 		}
 
-		if (!found) {
+		if (r->res_master_nodeid != our_nodeid) {
 			spin_unlock(&ls->ls_rsbtbl[b].lock);
-			break;
+			log_debug(ls, "remove_name master %d dir %d our %d %s",
+				  r->res_master_nodeid, r->res_dir_nodeid,
+				  our_nodeid, name);
+			continue;
 		}
 
-		if (kref_put(&r->res_ref, kill_rsb)) {
-			rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
+		if (r->res_dir_nodeid == our_nodeid) {
+			/* should never happen */
 			spin_unlock(&ls->ls_rsbtbl[b].lock);
+			log_error(ls, "remove_name dir %d master %d our %d %s",
+				  r->res_dir_nodeid, r->res_master_nodeid,
+				  our_nodeid, name);
+			continue;
+		}
 
-			if (is_master(r))
-				dir_remove(r);
-			dlm_free_rsb(r);
-			count++;
-		} else {
+		if (!time_after_eq(jiffies, r->res_toss_time +
+				   dlm_config.ci_toss_secs * HZ)) {
 			spin_unlock(&ls->ls_rsbtbl[b].lock);
-			log_error(ls, "tossed rsb in use %s", r->res_name);
+			log_debug(ls, "remove_name toss_time %lu now %lu %s",
+				  r->res_toss_time, jiffies, name);
+			continue;
 		}
-	}
 
-	return count;
+		if (!kref_put(&r->res_ref, kill_rsb)) {
+			spin_unlock(&ls->ls_rsbtbl[b].lock);
+			log_error(ls, "remove_name in use %s", name);
+			continue;
+		}
+
+		rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
+
+		/* block lookup of same name until we've sent remove */
+		spin_lock(&ls->ls_remove_spin);
+		ls->ls_remove_len = len;
+		memcpy(ls->ls_remove_name, name, DLM_RESNAME_MAXLEN);
+		spin_unlock(&ls->ls_remove_spin);
+		spin_unlock(&ls->ls_rsbtbl[b].lock);
+
+		send_remove(r);
+
+		/* allow lookup of name again */
+		spin_lock(&ls->ls_remove_spin);
+		ls->ls_remove_len = 0;
+		memset(ls->ls_remove_name, 0, DLM_RESNAME_MAXLEN);
+		spin_unlock(&ls->ls_remove_spin);
+
+		dlm_free_rsb(r);
+	}
 }
 
 void dlm_scan_rsbs(struct dlm_ls *ls)
@@ -1684,10 +2236,14 @@ static int conversion_deadlock_detect(struct dlm_rsb *r, struct dlm_lkb *lkb2)
  * immediate request, it is 0 if called later, after the lock has been
  * queued.
  *
+ * recover is 1 if dlm_recover_grant() is trying to grant conversions
+ * after recovery.
+ *
  * References are from chapter 6 of "VAXcluster Principles" by Roy Davis
  */
 
-static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
+static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
+			   int recover)
 {
 	int8_t conv = (lkb->lkb_grmode != DLM_LOCK_IV);
 
@@ -1719,7 +2275,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
 	 */
 
 	if (queue_conflict(&r->res_grantqueue, lkb))
-		goto out;
+		return 0;
 
 	/*
 	 * 6-3: By default, a conversion request is immediately granted if the
@@ -1728,7 +2284,24 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
 	 */
 
 	if (queue_conflict(&r->res_convertqueue, lkb))
-		goto out;
+		return 0;
+
+	/*
+	 * The RECOVER_GRANT flag means dlm_recover_grant() is granting
+	 * locks for a recovered rsb, on which lkb's have been rebuilt.
+	 * The lkb's may have been rebuilt on the queues in a different
+	 * order than they were in on the previous master.  So, granting
+	 * queued conversions in order after recovery doesn't make sense
+	 * since the order hasn't been preserved anyway.  The new order
+	 * could also have created a new "in place" conversion deadlock.
+	 * (e.g. old, failed master held granted EX, with PR->EX, NL->EX.
+	 * After recovery, there would be no granted locks, and possibly
+	 * NL->EX, PR->EX, an in-place conversion deadlock.)  So, after
+	 * recovery, grant conversions without considering order.
+	 */
+
+	if (conv && recover)
+		return 1;
 
 	/*
 	 * 6-5: But the default algorithm for deciding whether to grant or
@@ -1765,7 +2338,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
 		if (list_empty(&r->res_convertqueue))
 			return 1;
 		else
-			goto out;
+			return 0;
 	}
 
 	/*
@@ -1811,12 +2384,12 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
 	if (!now && !conv && list_empty(&r->res_convertqueue) &&
 	    first_in_list(lkb, &r->res_waitqueue))
 		return 1;
- out:
+
 	return 0;
 }
 
 static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
-			  int *err)
+			  int recover, int *err)
 {
 	int rv;
 	int8_t alt = 0, rqmode = lkb->lkb_rqmode;
@@ -1825,7 +2398,7 @@ static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
 	if (err)
 		*err = 0;
 
-	rv = _can_be_granted(r, lkb, now);
+	rv = _can_be_granted(r, lkb, now, recover);
 	if (rv)
 		goto out;
 
@@ -1866,7 +2439,7 @@ static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
 
 	if (alt) {
 		lkb->lkb_rqmode = alt;
-		rv = _can_be_granted(r, lkb, now);
+		rv = _can_be_granted(r, lkb, now, 0);
 		if (rv)
 			lkb->lkb_sbflags |= DLM_SBF_ALTMODE;
 		else
@@ -1890,6 +2463,7 @@ static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw,
 				 unsigned int *count)
 {
 	struct dlm_lkb *lkb, *s;
+	int recover = rsb_flag(r, RSB_RECOVER_GRANT);
 	int hi, demoted, quit, grant_restart, demote_restart;
 	int deadlk;
 
@@ -1903,7 +2477,7 @@ static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw,
 		demoted = is_demoted(lkb);
 		deadlk = 0;
 
-		if (can_be_granted(r, lkb, 0, &deadlk)) {
+		if (can_be_granted(r, lkb, 0, recover, &deadlk)) {
 			grant_lock_pending(r, lkb);
 			grant_restart = 1;
 			if (count)
@@ -1947,7 +2521,7 @@ static int grant_pending_wait(struct dlm_rsb *r, int high, int *cw,
 	struct dlm_lkb *lkb, *s;
 
 	list_for_each_entry_safe(lkb, s, &r->res_waitqueue, lkb_statequeue) {
-		if (can_be_granted(r, lkb, 0, NULL)) {
+		if (can_be_granted(r, lkb, 0, 0, NULL)) {
 			grant_lock_pending(r, lkb);
 			if (count)
 				(*count)++;
@@ -2078,8 +2652,7 @@ static void send_blocking_asts_all(struct dlm_rsb *r, struct dlm_lkb *lkb)
 
 static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
-	struct dlm_ls *ls = r->res_ls;
-	int i, error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
+	int our_nodeid = dlm_our_nodeid();
 
 	if (rsb_flag(r, RSB_MASTER_UNCERTAIN)) {
 		rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
@@ -2093,53 +2666,37 @@ static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)
 		return 1;
 	}
 
-	if (r->res_nodeid == 0) {
+	if (r->res_master_nodeid == our_nodeid) {
 		lkb->lkb_nodeid = 0;
 		return 0;
 	}
 
-	if (r->res_nodeid > 0) {
-		lkb->lkb_nodeid = r->res_nodeid;
+	if (r->res_master_nodeid) {
+		lkb->lkb_nodeid = r->res_master_nodeid;
 		return 0;
 	}
 
-	DLM_ASSERT(r->res_nodeid == -1, dlm_dump_rsb(r););
-
-	dir_nodeid = dlm_dir_nodeid(r);
-
-	if (dir_nodeid != our_nodeid) {
-		r->res_first_lkid = lkb->lkb_id;
-		send_lookup(r, lkb);
-		return 1;
-	}
-
-	for (i = 0; i < 2; i++) {
-		/* It's possible for dlm_scand to remove an old rsb for
-		   this same resource from the toss list, us to create
-		   a new one, look up the master locally, and find it
-		   already exists just before dlm_scand does the
-		   dir_remove() on the previous rsb. */
-
-		error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
-				       r->res_length, &ret_nodeid);
-		if (!error)
-			break;
-		log_debug(ls, "dir_lookup error %d %s", error, r->res_name);
-		schedule();
-	}
-	if (error && error != -EEXIST)
-		return error;
-
-	if (ret_nodeid == our_nodeid) {
-		r->res_first_lkid = 0;
+	if (dlm_dir_nodeid(r) == our_nodeid) {
+		/* This is a somewhat unusual case; find_rsb will usually
+		   have set res_master_nodeid when dir nodeid is local, but
+		   there are cases where we become the dir node after we've
+		   past find_rsb and go through _request_lock again.
+		   confirm_master() or process_lookup_list() needs to be
+		   called after this. */
+		log_debug(r->res_ls, "set_master %x self master %d dir %d %s",
+			  lkb->lkb_id, r->res_master_nodeid, r->res_dir_nodeid,
+			  r->res_name);
+		r->res_master_nodeid = our_nodeid;
 		r->res_nodeid = 0;
 		lkb->lkb_nodeid = 0;
-	} else {
-		r->res_first_lkid = lkb->lkb_id;
-		r->res_nodeid = ret_nodeid;
-		lkb->lkb_nodeid = ret_nodeid;
+		return 0;
 	}
-	return 0;
+
+	wait_pending_remove(r);
+
+	r->res_first_lkid = lkb->lkb_id;
+	send_lookup(r, lkb);
+	return 1;
 }
 
 static void process_lookup_list(struct dlm_rsb *r)
@@ -2464,7 +3021,7 @@ static int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
 	int error = 0;
 
-	if (can_be_granted(r, lkb, 1, NULL)) {
+	if (can_be_granted(r, lkb, 1, 0, NULL)) {
 		grant_lock(r, lkb);
 		queue_cast(r, lkb, 0);
 		goto out;
@@ -2504,7 +3061,7 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
 
 	/* changing an existing lock may allow others to be granted */
 
-	if (can_be_granted(r, lkb, 1, &deadlk)) {
+	if (can_be_granted(r, lkb, 1, 0, &deadlk)) {
 		grant_lock(r, lkb);
 		queue_cast(r, lkb, 0);
 		goto out;
@@ -2530,7 +3087,7 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
 
 	if (is_demoted(lkb)) {
 		grant_pending_convert(r, DLM_LOCK_IV, NULL, NULL);
-		if (_can_be_granted(r, lkb, 1)) {
+		if (_can_be_granted(r, lkb, 1, 0)) {
 			grant_lock(r, lkb);
 			queue_cast(r, lkb, 0);
 			goto out;
@@ -2584,7 +3141,7 @@ static void do_unlock_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
 }
 
 /* returns: 0 did nothing, -DLM_ECANCEL canceled lock */
- 
+
 static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
 	int error;
@@ -2710,7 +3267,7 @@ static int request_lock(struct dlm_ls *ls, struct dlm_lkb *lkb, char *name,
 	if (error)
 		goto out;
 
-	error = find_rsb(ls, name, len, R_CREATE, &r);
+	error = find_rsb(ls, name, len, 0, R_REQUEST, &r);
 	if (error)
 		goto out;
 
@@ -3402,11 +3959,67 @@ static int validate_message(struct dlm_lkb *lkb, struct dlm_message *ms)
 	return error;
 }
 
+static void send_repeat_remove(struct dlm_ls *ls, char *ms_name, int len)
+{
+	char name[DLM_RESNAME_MAXLEN + 1];
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	struct dlm_rsb *r;
+	uint32_t hash, b;
+	int rv, dir_nodeid;
+
+	memset(name, 0, sizeof(name));
+	memcpy(name, ms_name, len);
+
+	hash = jhash(name, len, 0);
+	b = hash & (ls->ls_rsbtbl_size - 1);
+
+	dir_nodeid = dlm_hash2nodeid(ls, hash);
+
+	log_error(ls, "send_repeat_remove dir %d %s", dir_nodeid, name);
+
+	spin_lock(&ls->ls_rsbtbl[b].lock);
+	rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, &r);
+	if (!rv) {
+		spin_unlock(&ls->ls_rsbtbl[b].lock);
+		log_error(ls, "repeat_remove on keep %s", name);
+		return;
+	}
+
+	rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
+	if (!rv) {
+		spin_unlock(&ls->ls_rsbtbl[b].lock);
+		log_error(ls, "repeat_remove on toss %s", name);
+		return;
+	}
+
+	/* use ls->remove_name2 to avoid conflict with shrink? */
+
+	spin_lock(&ls->ls_remove_spin);
+	ls->ls_remove_len = len;
+	memcpy(ls->ls_remove_name, name, DLM_RESNAME_MAXLEN);
+	spin_unlock(&ls->ls_remove_spin);
+	spin_unlock(&ls->ls_rsbtbl[b].lock);
+
+	rv = _create_message(ls, sizeof(struct dlm_message) + len,
+			     dir_nodeid, DLM_MSG_REMOVE, &ms, &mh);
+	if (rv)
+		return;
+
+	memcpy(ms->m_extra, name, len);
+	ms->m_hash = hash;
+
+	send_message(mh, ms);
+}
+
 static int receive_request(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
-	int error, namelen;
+	int from_nodeid;
+	int error, namelen = 0;
+
+	from_nodeid = ms->m_header.h_nodeid;
 
 	error = create_lkb(ls, &lkb);
 	if (error)
@@ -3420,9 +4033,16 @@ static int receive_request(struct dlm_ls *ls, struct dlm_message *ms)
 		goto fail;
 	}
 
+	/* The dir node is the authority on whether we are the master
+	   for this rsb or not, so if the master sends us a request, we should
+	   recreate the rsb if we've destroyed it.   This race happens when we
+	   send a remove message to the dir node at the same time that the dir
+	   node sends us a request for the rsb. */
+
 	namelen = receive_extralen(ms);
 
-	error = find_rsb(ls, ms->m_extra, namelen, R_MASTER, &r);
+	error = find_rsb(ls, ms->m_extra, namelen, from_nodeid,
+			 R_RECEIVE_REQUEST, &r);
 	if (error) {
 		__put_lkb(ls, lkb);
 		goto fail;
@@ -3445,6 +4065,31 @@ static int receive_request(struct dlm_ls *ls, struct dlm_message *ms)
 	return 0;
 
  fail:
+	/* TODO: instead of returning ENOTBLK, add the lkb to res_lookup
+	   and do this receive_request again from process_lookup_list once
+	   we get the lookup reply.  This would avoid a many repeated
+	   ENOTBLK request failures when the lookup reply designating us
+	   as master is delayed. */
+
+	/* We could repeatedly return -EBADR here if our send_remove() is
+	   delayed in being sent/arriving/being processed on the dir node.
+	   Another node would repeatedly lookup up the master, and the dir
+	   node would continue returning our nodeid until our send_remove
+	   took effect.
+
+	   We send another remove message in case our previous send_remove
+	   was lost/ignored/missed somehow. */
+
+	if (error != -ENOTBLK) {
+		log_limit(ls, "receive_request %x from %d %d",
+			  ms->m_lkid, from_nodeid, error);
+	}
+
+	if (namelen && error == -EBADR) {
+		send_repeat_remove(ls, ms->m_extra, namelen);
+		msleep(1000);
+	}
+
 	setup_stub_lkb(ls, ms);
 	send_request_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
 	return error;
@@ -3651,49 +4296,110 @@ static int receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
 
 static void receive_lookup(struct dlm_ls *ls, struct dlm_message *ms)
 {
-	int len, error, ret_nodeid, dir_nodeid, from_nodeid, our_nodeid;
+	int len, error, ret_nodeid, from_nodeid, our_nodeid;
 
 	from_nodeid = ms->m_header.h_nodeid;
 	our_nodeid = dlm_our_nodeid();
 
 	len = receive_extralen(ms);
 
-	dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);
-	if (dir_nodeid != our_nodeid) {
-		log_error(ls, "lookup dir_nodeid %d from %d",
-			  dir_nodeid, from_nodeid);
-		error = -EINVAL;
-		ret_nodeid = -1;
-		goto out;
-	}
-
-	error = dlm_dir_lookup(ls, from_nodeid, ms->m_extra, len, &ret_nodeid);
+	error = dlm_master_lookup(ls, from_nodeid, ms->m_extra, len, 0,
+				  &ret_nodeid, NULL);
 
 	/* Optimization: we're master so treat lookup as a request */
 	if (!error && ret_nodeid == our_nodeid) {
 		receive_request(ls, ms);
 		return;
 	}
- out:
 	send_lookup_reply(ls, ms, ret_nodeid, error);
 }
 
 static void receive_remove(struct dlm_ls *ls, struct dlm_message *ms)
 {
-	int len, dir_nodeid, from_nodeid;
+	char name[DLM_RESNAME_MAXLEN+1];
+	struct dlm_rsb *r;
+	uint32_t hash, b;
+	int rv, len, dir_nodeid, from_nodeid;
 
 	from_nodeid = ms->m_header.h_nodeid;
 
 	len = receive_extralen(ms);
 
+	if (len > DLM_RESNAME_MAXLEN) {
+		log_error(ls, "receive_remove from %d bad len %d",
+			  from_nodeid, len);
+		return;
+	}
+
 	dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);
 	if (dir_nodeid != dlm_our_nodeid()) {
-		log_error(ls, "remove dir entry dir_nodeid %d from %d",
-			  dir_nodeid, from_nodeid);
+		log_error(ls, "receive_remove from %d bad nodeid %d",
+			  from_nodeid, dir_nodeid);
+		return;
+	}
+
+	/* Look for name on rsbtbl.toss, if it's there, kill it.
+	   If it's on rsbtbl.keep, it's being used, and we should ignore this
+	   message.  This is an expected race between the dir node sending a
+	   request to the master node at the same time as the master node sends
+	   a remove to the dir node.  The resolution to that race is for the
+	   dir node to ignore the remove message, and the master node to
+	   recreate the master rsb when it gets a request from the dir node for
+	   an rsb it doesn't have. */
+
+	memset(name, 0, sizeof(name));
+	memcpy(name, ms->m_extra, len);
+
+	hash = jhash(name, len, 0);
+	b = hash & (ls->ls_rsbtbl_size - 1);
+
+	spin_lock(&ls->ls_rsbtbl[b].lock);
+
+	rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
+	if (rv) {
+		/* verify the rsb is on keep list per comment above */
+		rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, &r);
+		if (rv) {
+			/* should not happen */
+			log_error(ls, "receive_remove from %d not found %s",
+				  from_nodeid, name);
+			spin_unlock(&ls->ls_rsbtbl[b].lock);
+			return;
+		}
+		if (r->res_master_nodeid != from_nodeid) {
+			/* should not happen */
+			log_error(ls, "receive_remove keep from %d master %d",
+				  from_nodeid, r->res_master_nodeid);
+			dlm_print_rsb(r);
+			spin_unlock(&ls->ls_rsbtbl[b].lock);
+			return;
+		}
+
+		log_debug(ls, "receive_remove from %d master %d first %x %s",
+			  from_nodeid, r->res_master_nodeid, r->res_first_lkid,
+			  name);
+		spin_unlock(&ls->ls_rsbtbl[b].lock);
+		return;
+	}
+
+	if (r->res_master_nodeid != from_nodeid) {
+		log_error(ls, "receive_remove toss from %d master %d",
+			  from_nodeid, r->res_master_nodeid);
+		dlm_print_rsb(r);
+		spin_unlock(&ls->ls_rsbtbl[b].lock);
 		return;
 	}
 
-	dlm_dir_remove_entry(ls, from_nodeid, ms->m_extra, len);
+	if (kref_put(&r->res_ref, kill_rsb)) {
+		rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
+		spin_unlock(&ls->ls_rsbtbl[b].lock);
+		dlm_free_rsb(r);
+	} else {
+		log_error(ls, "receive_remove from %d rsb ref error",
+			  from_nodeid);
+		dlm_print_rsb(r);
+		spin_unlock(&ls->ls_rsbtbl[b].lock);
+	}
 }
 
 static void receive_purge(struct dlm_ls *ls, struct dlm_message *ms)
@@ -3706,6 +4412,7 @@ static int receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
 	int error, mstype, result;
+	int from_nodeid = ms->m_header.h_nodeid;
 
 	error = find_lkb(ls, ms->m_remid, &lkb);
 	if (error)
@@ -3723,8 +4430,7 @@ static int receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
 	error = remove_from_waiters(lkb, DLM_MSG_REQUEST_REPLY);
 	if (error) {
 		log_error(ls, "receive_request_reply %x remote %d %x result %d",
-			  lkb->lkb_id, ms->m_header.h_nodeid, ms->m_lkid,
-			  ms->m_result);
+			  lkb->lkb_id, from_nodeid, ms->m_lkid, ms->m_result);
 		dlm_dump_rsb(r);
 		goto out;
 	}
@@ -3732,8 +4438,9 @@ static int receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
 	/* Optimization: the dir node was also the master, so it took our
 	   lookup as a request and sent request reply instead of lookup reply */
 	if (mstype == DLM_MSG_LOOKUP) {
-		r->res_nodeid = ms->m_header.h_nodeid;
-		lkb->lkb_nodeid = r->res_nodeid;
+		r->res_master_nodeid = from_nodeid;
+		r->res_nodeid = from_nodeid;
+		lkb->lkb_nodeid = from_nodeid;
 	}
 
 	/* this is the value returned from do_request() on the master */
@@ -3767,18 +4474,30 @@ static int receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
 	case -EBADR:
 	case -ENOTBLK:
 		/* find_rsb failed to find rsb or rsb wasn't master */
-		log_debug(ls, "receive_request_reply %x %x master diff %d %d",
-			  lkb->lkb_id, lkb->lkb_flags, r->res_nodeid, result);
-		r->res_nodeid = -1;
-		lkb->lkb_nodeid = -1;
+		log_limit(ls, "receive_request_reply %x from %d %d "
+			  "master %d dir %d first %x %s", lkb->lkb_id,
+			  from_nodeid, result, r->res_master_nodeid,
+			  r->res_dir_nodeid, r->res_first_lkid, r->res_name);
+
+		if (r->res_dir_nodeid != dlm_our_nodeid() &&
+		    r->res_master_nodeid != dlm_our_nodeid()) {
+			/* cause _request_lock->set_master->send_lookup */
+			r->res_master_nodeid = 0;
+			r->res_nodeid = -1;
+			lkb->lkb_nodeid = -1;
+		}
 
 		if (is_overlap(lkb)) {
 			/* we'll ignore error in cancel/unlock reply */
 			queue_cast_overlap(r, lkb);
 			confirm_master(r, result);
 			unhold_lkb(lkb); /* undoes create_lkb() */
-		} else
+		} else {
 			_request_lock(r, lkb);
+
+			if (r->res_master_nodeid == dlm_our_nodeid())
+				confirm_master(r, 0);
+		}
 		break;
 
 	default:
@@ -3994,6 +4713,7 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
 	int error, ret_nodeid;
+	int do_lookup_list = 0;
 
 	error = find_lkb(ls, ms->m_lkid, &lkb);
 	if (error) {
@@ -4001,7 +4721,7 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
 		return;
 	}
 
-	/* ms->m_result is the value returned by dlm_dir_lookup on dir node
+	/* ms->m_result is the value returned by dlm_master_lookup on dir node
 	   FIXME: will a non-zero error ever be returned? */
 
 	r = lkb->lkb_resource;
@@ -4013,12 +4733,37 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
 		goto out;
 
 	ret_nodeid = ms->m_nodeid;
+
+	/* We sometimes receive a request from the dir node for this
+	   rsb before we've received the dir node's loookup_reply for it.
+	   The request from the dir node implies we're the master, so we set
+	   ourself as master in receive_request_reply, and verify here that
+	   we are indeed the master. */
+
+	if (r->res_master_nodeid && (r->res_master_nodeid != ret_nodeid)) {
+		/* This should never happen */
+		log_error(ls, "receive_lookup_reply %x from %d ret %d "
+			  "master %d dir %d our %d first %x %s",
+			  lkb->lkb_id, ms->m_header.h_nodeid, ret_nodeid,
+			  r->res_master_nodeid, r->res_dir_nodeid,
+			  dlm_our_nodeid(), r->res_first_lkid, r->res_name);
+	}
+
 	if (ret_nodeid == dlm_our_nodeid()) {
+		r->res_master_nodeid = ret_nodeid;
 		r->res_nodeid = 0;
-		ret_nodeid = 0;
+		do_lookup_list = 1;
 		r->res_first_lkid = 0;
+	} else if (ret_nodeid == -1) {
+		/* the remote node doesn't believe it's the dir node */
+		log_error(ls, "receive_lookup_reply %x from %d bad ret_nodeid",
+			  lkb->lkb_id, ms->m_header.h_nodeid);
+		r->res_master_nodeid = 0;
+		r->res_nodeid = -1;
+		lkb->lkb_nodeid = -1;
 	} else {
-		/* set_master() will copy res_nodeid to lkb_nodeid */
+		/* set_master() will set lkb_nodeid from r */
+		r->res_master_nodeid = ret_nodeid;
 		r->res_nodeid = ret_nodeid;
 	}
 
@@ -4033,7 +4778,7 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
 	_request_lock(r, lkb);
 
  out_list:
-	if (!ret_nodeid)
+	if (do_lookup_list)
 		process_lookup_list(r);
  out:
 	unlock_rsb(r);
@@ -4047,7 +4792,7 @@ static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms,
 	int error = 0, noent = 0;
 
 	if (!dlm_is_member(ls, ms->m_header.h_nodeid)) {
-		log_debug(ls, "ignore non-member message %d from %d %x %x %d",
+		log_limit(ls, "receive %d from non-member %d %x %x %d",
 			  ms->m_type, ms->m_header.h_nodeid, ms->m_lkid,
 			  ms->m_remid, ms->m_result);
 		return;
@@ -4174,6 +4919,15 @@ static void dlm_receive_message(struct dlm_ls *ls, struct dlm_message *ms,
 				int nodeid)
 {
 	if (dlm_locking_stopped(ls)) {
+		/* If we were a member of this lockspace, left, and rejoined,
+		   other nodes may still be sending us messages from the
+		   lockspace generation before we left. */
+		if (!ls->ls_generation) {
+			log_limit(ls, "receive %d from %d ignore old gen",
+				  ms->m_type, nodeid);
+			return;
+		}
+
 		dlm_add_requestqueue(ls, nodeid, ms);
 	} else {
 		dlm_wait_requestqueue(ls);
@@ -4651,9 +5405,10 @@ static struct dlm_rsb *find_grant_rsb(struct dlm_ls *ls, int bucket)
 
 		if (!rsb_flag(r, RSB_RECOVER_GRANT))
 			continue;
-		rsb_clear_flag(r, RSB_RECOVER_GRANT);
-		if (!is_master(r))
+		if (!is_master(r)) {
+			rsb_clear_flag(r, RSB_RECOVER_GRANT);
 			continue;
+		}
 		hold_rsb(r);
 		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
 		return r;
@@ -4698,7 +5453,9 @@ void dlm_recover_grant(struct dlm_ls *ls)
 		rsb_count++;
 		count = 0;
 		lock_rsb(r);
+		/* the RECOVER_GRANT flag is checked in the grant path */
 		grant_pending_locks(r, &count);
+		rsb_clear_flag(r, RSB_RECOVER_GRANT);
 		lkb_count += count;
 		confirm_master(r, 0);
 		unlock_rsb(r);
@@ -4798,6 +5555,7 @@ int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
 	struct dlm_rsb *r;
 	struct dlm_lkb *lkb;
 	uint32_t remid = 0;
+	int from_nodeid = rc->rc_header.h_nodeid;
 	int error;
 
 	if (rl->rl_parent_lkid) {
@@ -4815,13 +5573,14 @@ int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
 	   we make ourselves master, dlm_recover_masters() won't touch the
 	   MSTCPY locks we've received early. */
 
-	error = find_rsb(ls, rl->rl_name, le16_to_cpu(rl->rl_namelen), 0, &r);
+	error = find_rsb(ls, rl->rl_name, le16_to_cpu(rl->rl_namelen),
+			 from_nodeid, R_RECEIVE_RECOVER, &r);
 	if (error)
 		goto out;
 
 	if (dlm_no_directory(ls) && (dlm_dir_nodeid(r) != dlm_our_nodeid())) {
 		log_error(ls, "dlm_recover_master_copy remote %d %x not dir",
-			  rc->rc_header.h_nodeid, remid);
+			  from_nodeid, remid);
 		error = -EBADR;
 		put_rsb(r);
 		goto out;
@@ -4829,7 +5588,7 @@ int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
 
 	lock_rsb(r);
 
-	lkb = search_remid(r, rc->rc_header.h_nodeid, remid);
+	lkb = search_remid(r, from_nodeid, remid);
 	if (lkb) {
 		error = -EEXIST;
 		goto out_remid;
@@ -4866,7 +5625,7 @@ int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
  out:
 	if (error && error != -EEXIST)
 		log_debug(ls, "dlm_recover_master_copy remote %d %x error %d",
-			  rc->rc_header.h_nodeid, remid, error);
+			  from_nodeid, remid, error);
 	rl->rl_result = cpu_to_le32(error);
 	return error;
 }
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index c8b226c..c67bd36 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -28,9 +28,11 @@ void dlm_unlock_recovery(struct dlm_ls *ls);
 void dlm_scan_waiters(struct dlm_ls *ls);
 void dlm_scan_timeout(struct dlm_ls *ls);
 void dlm_adjust_timeouts(struct dlm_ls *ls);
+int dlm_master_lookup(struct dlm_ls *ls, int nodeid, char *name, int len,
+		      unsigned int flags, int *r_nodeid, int *result);
 
 int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len,
-			unsigned int flags, struct dlm_rsb **r_ret);
+			struct dlm_rsb **r_ret);
 
 void dlm_recover_purge(struct dlm_ls *ls);
 void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index ca506ab..952557d 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -506,20 +506,18 @@ static int new_lockspace(const char *name, const char *cluster,
 		spin_lock_init(&ls->ls_rsbtbl[i].lock);
 	}
 
-	idr_init(&ls->ls_lkbidr);
-	spin_lock_init(&ls->ls_lkbidr_spin);
+	spin_lock_init(&ls->ls_remove_spin);
 
-	size = dlm_config.ci_dirtbl_size;
-	ls->ls_dirtbl_size = size;
-
-	ls->ls_dirtbl = vmalloc(sizeof(struct dlm_dirtable) * size);
-	if (!ls->ls_dirtbl)
-		goto out_lkbfree;
-	for (i = 0; i < size; i++) {
-		INIT_LIST_HEAD(&ls->ls_dirtbl[i].list);
-		spin_lock_init(&ls->ls_dirtbl[i].lock);
+	for (i = 0; i < DLM_REMOVE_NAMES_MAX; i++) {
+		ls->ls_remove_names[i] = kzalloc(DLM_RESNAME_MAXLEN+1,
+						 GFP_KERNEL);
+		if (!ls->ls_remove_names[i])
+			goto out_rsbtbl;
 	}
 
+	idr_init(&ls->ls_lkbidr);
+	spin_lock_init(&ls->ls_lkbidr_spin);
+
 	INIT_LIST_HEAD(&ls->ls_waiters);
 	mutex_init(&ls->ls_waiters_mutex);
 	INIT_LIST_HEAD(&ls->ls_orphans);
@@ -567,7 +565,7 @@ static int new_lockspace(const char *name, const char *cluster,
 
 	ls->ls_recover_buf = kmalloc(dlm_config.ci_buffer_size, GFP_NOFS);
 	if (!ls->ls_recover_buf)
-		goto out_dirfree;
+		goto out_lkbidr;
 
 	ls->ls_slot = 0;
 	ls->ls_num_slots = 0;
@@ -576,6 +574,8 @@ static int new_lockspace(const char *name, const char *cluster,
 
 	INIT_LIST_HEAD(&ls->ls_recover_list);
 	spin_lock_init(&ls->ls_recover_list_lock);
+	idr_init(&ls->ls_recover_idr);
+	spin_lock_init(&ls->ls_recover_idr_lock);
 	ls->ls_recover_list_count = 0;
 	ls->ls_local_handle = ls;
 	init_waitqueue_head(&ls->ls_wait_general);
@@ -647,11 +647,15 @@ static int new_lockspace(const char *name, const char *cluster,
 	spin_lock(&lslist_lock);
 	list_del(&ls->ls_list);
 	spin_unlock(&lslist_lock);
+	idr_destroy(&ls->ls_recover_idr);
 	kfree(ls->ls_recover_buf);
- out_dirfree:
-	vfree(ls->ls_dirtbl);
- out_lkbfree:
+ out_lkbidr:
 	idr_destroy(&ls->ls_lkbidr);
+	for (i = 0; i < DLM_REMOVE_NAMES_MAX; i++) {
+		if (ls->ls_remove_names[i])
+			kfree(ls->ls_remove_names[i]);
+	}
+ out_rsbtbl:
 	vfree(ls->ls_rsbtbl);
  out_lsfree:
 	if (do_unreg)
@@ -779,13 +783,6 @@ static int release_lockspace(struct dlm_ls *ls, int force)
 	kfree(ls->ls_recover_buf);
 
 	/*
-	 * Free direntry structs.
-	 */
-
-	dlm_dir_clear(ls);
-	vfree(ls->ls_dirtbl);
-
-	/*
 	 * Free all lkb's in idr
 	 */
 
@@ -813,6 +810,9 @@ static int release_lockspace(struct dlm_ls *ls, int force)
 
 	vfree(ls->ls_rsbtbl);
 
+	for (i = 0; i < DLM_REMOVE_NAMES_MAX; i++)
+		kfree(ls->ls_remove_names[i]);
+
 	while (!list_empty(&ls->ls_new_rsb)) {
 		rsb = list_first_entry(&ls->ls_new_rsb, struct dlm_rsb,
 				       res_hashchain);
@@ -826,7 +826,6 @@ static int release_lockspace(struct dlm_ls *ls, int force)
 
 	dlm_purge_requestqueue(ls);
 	kfree(ls->ls_recover_args);
-	dlm_clear_free_entries(ls);
 	dlm_clear_members(ls);
 	dlm_clear_members_gone(ls);
 	kfree(ls->ls_node_array);
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
index 64d3e2b..2847d32 100644
--- a/fs/dlm/rcom.c
+++ b/fs/dlm/rcom.c
@@ -23,8 +23,6 @@
 #include "memory.h"
 #include "lock.h"
 #include "util.h"
-#include "member.h"
-
 
 static int rcom_response(struct dlm_ls *ls)
 {
@@ -275,19 +273,9 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len)
 	struct dlm_rcom *rc;
 	struct dlm_mhandle *mh;
 	int error = 0;
-	int max_size = dlm_config.ci_buffer_size - sizeof(struct dlm_rcom);
 
 	ls->ls_recover_nodeid = nodeid;
 
-	if (nodeid == dlm_our_nodeid()) {
-		ls->ls_recover_buf->rc_header.h_length =
-			dlm_config.ci_buffer_size;
-		dlm_copy_master_names(ls, last_name, last_len,
-		                      ls->ls_recover_buf->rc_buf,
-		                      max_size, nodeid);
-		goto out;
-	}
-
 	error = create_rcom(ls, nodeid, DLM_RCOM_NAMES, last_len, &rc, &mh);
 	if (error)
 		goto out;
@@ -337,7 +325,7 @@ int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid)
 	if (error)
 		goto out;
 	memcpy(rc->rc_buf, r->res_name, r->res_length);
-	rc->rc_id = (unsigned long) r;
+	rc->rc_id = (unsigned long) r->res_id;
 
 	send_rcom(ls, mh, rc);
  out:
@@ -355,7 +343,8 @@ static void receive_rcom_lookup(struct dlm_ls *ls, struct dlm_rcom *rc_in)
 	if (error)
 		return;
 
-	error = dlm_dir_lookup(ls, nodeid, rc_in->rc_buf, len, &ret_nodeid);
+	error = dlm_master_lookup(ls, nodeid, rc_in->rc_buf, len,
+				  DLM_LU_RECOVER_MASTER, &ret_nodeid, NULL);
 	if (error)
 		ret_nodeid = error;
 	rc->rc_result = ret_nodeid;
@@ -486,17 +475,76 @@ int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
 	return 0;
 }
 
+/*
+ * Ignore messages for stage Y before we set
+ * recover_status bit for stage X:
+ *
+ * recover_status = 0
+ *
+ * dlm_recover_members()
+ * - send nothing
+ * - recv nothing
+ * - ignore NAMES, NAMES_REPLY
+ * - ignore LOOKUP, LOOKUP_REPLY
+ * - ignore LOCK, LOCK_REPLY
+ *
+ * recover_status |= NODES
+ *
+ * dlm_recover_members_wait()
+ *
+ * dlm_recover_directory()
+ * - send NAMES
+ * - recv NAMES_REPLY
+ * - ignore LOOKUP, LOOKUP_REPLY
+ * - ignore LOCK, LOCK_REPLY
+ *
+ * recover_status |= DIR
+ *
+ * dlm_recover_directory_wait()
+ *
+ * dlm_recover_masters()
+ * - send LOOKUP
+ * - recv LOOKUP_REPLY
+ *
+ * dlm_recover_locks()
+ * - send LOCKS
+ * - recv LOCKS_REPLY
+ *
+ * recover_status |= LOCKS
+ *
+ * dlm_recover_locks_wait()
+ *
+ * recover_status |= DONE
+ */
+
 /* Called by dlm_recv; corresponds to dlm_receive_message() but special
    recovery-only comms are sent through here. */
 
 void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
 {
 	int lock_size = sizeof(struct dlm_rcom) + sizeof(struct rcom_lock);
-	int stop, reply = 0, lock = 0;
+	int stop, reply = 0, names = 0, lookup = 0, lock = 0;
 	uint32_t status;
 	uint64_t seq;
 
 	switch (rc->rc_type) {
+	case DLM_RCOM_STATUS_REPLY:
+		reply = 1;
+		break;
+	case DLM_RCOM_NAMES:
+		names = 1;
+		break;
+	case DLM_RCOM_NAMES_REPLY:
+		names = 1;
+		reply = 1;
+		break;
+	case DLM_RCOM_LOOKUP:
+		lookup = 1;
+		break;
+	case DLM_RCOM_LOOKUP_REPLY:
+		lookup = 1;
+		reply = 1;
+		break;
 	case DLM_RCOM_LOCK:
 		lock = 1;
 		break;
@@ -504,10 +552,6 @@ void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
 		lock = 1;
 		reply = 1;
 		break;
-	case DLM_RCOM_STATUS_REPLY:
-	case DLM_RCOM_NAMES_REPLY:
-	case DLM_RCOM_LOOKUP_REPLY:
-		reply = 1;
 	};
 
 	spin_lock(&ls->ls_recover_lock);
@@ -516,19 +560,17 @@ void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
 	seq = ls->ls_recover_seq;
 	spin_unlock(&ls->ls_recover_lock);
 
-	if ((stop && (rc->rc_type != DLM_RCOM_STATUS)) ||
-	    (reply && (rc->rc_seq_reply != seq)) ||
-	    (lock && !(status & DLM_RS_DIR))) {
-		log_limit(ls, "dlm_receive_rcom ignore msg %d "
-			  "from %d %llu %llu recover seq %llu sts %x gen %u",
-			   rc->rc_type,
-			   nodeid,
-			   (unsigned long long)rc->rc_seq,
-			   (unsigned long long)rc->rc_seq_reply,
-			   (unsigned long long)seq,
-			   status, ls->ls_generation);
-		goto out;
-	}
+	if (stop && (rc->rc_type != DLM_RCOM_STATUS))
+		goto ignore;
+
+	if (reply && (rc->rc_seq_reply != seq))
+		goto ignore;
+
+	if (!(status & DLM_RS_NODES) && (names || lookup || lock))
+		goto ignore;
+
+	if (!(status & DLM_RS_DIR) && (lookup || lock))
+		goto ignore;
 
 	switch (rc->rc_type) {
 	case DLM_RCOM_STATUS:
@@ -570,10 +612,20 @@ void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
 	default:
 		log_error(ls, "receive_rcom bad type %d", rc->rc_type);
 	}
-out:
+	return;
+
+ignore:
+	log_limit(ls, "dlm_receive_rcom ignore msg %d "
+		  "from %d %llu %llu recover seq %llu sts %x gen %u",
+		   rc->rc_type,
+		   nodeid,
+		   (unsigned long long)rc->rc_seq,
+		   (unsigned long long)rc->rc_seq_reply,
+		   (unsigned long long)seq,
+		   status, ls->ls_generation);
 	return;
 Eshort:
-	log_error(ls, "recovery message %x from %d is too short",
-			  rc->rc_type, nodeid);
+	log_error(ls, "recovery message %d from %d is too short",
+		  rc->rc_type, nodeid);
 }
 
diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c
index 7554e4d..4a7a76e 100644
--- a/fs/dlm/recover.c
+++ b/fs/dlm/recover.c
@@ -36,30 +36,23 @@
  * (LS_RECOVERY_STOP set due to failure of a node in ls_nodes).  When another
  * function thinks it could have completed the waited-on task, they should wake
  * up ls_wait_general to get an immediate response rather than waiting for the
- * timer to detect the result.  A timer wakes us up periodically while waiting
- * to see if we should abort due to a node failure.  This should only be called
- * by the dlm_recoverd thread.
+ * timeout.  This uses a timeout so it can check periodically if the wait
+ * should abort due to node failure (which doesn't cause a wake_up).
+ * This should only be called by the dlm_recoverd thread.
  */
 
-static void dlm_wait_timer_fn(unsigned long data)
-{
-	struct dlm_ls *ls = (struct dlm_ls *) data;
-	mod_timer(&ls->ls_timer, jiffies + (dlm_config.ci_recover_timer * HZ));
-	wake_up(&ls->ls_wait_general);
-}
-
 int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls))
 {
 	int error = 0;
+	int rv;
 
-	init_timer(&ls->ls_timer);
-	ls->ls_timer.function = dlm_wait_timer_fn;
-	ls->ls_timer.data = (long) ls;
-	ls->ls_timer.expires = jiffies + (dlm_config.ci_recover_timer * HZ);
-	add_timer(&ls->ls_timer);
-
-	wait_event(ls->ls_wait_general, testfn(ls) || dlm_recovery_stopped(ls));
-	del_timer_sync(&ls->ls_timer);
+	while (1) {
+		rv = wait_event_timeout(ls->ls_wait_general,
+					testfn(ls) || dlm_recovery_stopped(ls),
+					dlm_config.ci_recover_timer * HZ);
+		if (rv)
+			break;
+	}
 
 	if (dlm_recovery_stopped(ls)) {
 		log_debug(ls, "dlm_wait_function aborted");
@@ -277,22 +270,6 @@ static void recover_list_del(struct dlm_rsb *r)
 	dlm_put_rsb(r);
 }
 
-static struct dlm_rsb *recover_list_find(struct dlm_ls *ls, uint64_t id)
-{
-	struct dlm_rsb *r = NULL;
-
-	spin_lock(&ls->ls_recover_list_lock);
-
-	list_for_each_entry(r, &ls->ls_recover_list, res_recover_list) {
-		if (id == (unsigned long) r)
-			goto out;
-	}
-	r = NULL;
- out:
-	spin_unlock(&ls->ls_recover_list_lock);
-	return r;
-}
-
 static void recover_list_clear(struct dlm_ls *ls)
 {
 	struct dlm_rsb *r, *s;
@@ -313,6 +290,94 @@ static void recover_list_clear(struct dlm_ls *ls)
 	spin_unlock(&ls->ls_recover_list_lock);
 }
 
+static int recover_idr_empty(struct dlm_ls *ls)
+{
+	int empty = 1;
+
+	spin_lock(&ls->ls_recover_idr_lock);
+	if (ls->ls_recover_list_count)
+		empty = 0;
+	spin_unlock(&ls->ls_recover_idr_lock);
+
+	return empty;
+}
+
+static int recover_idr_add(struct dlm_rsb *r)
+{
+	struct dlm_ls *ls = r->res_ls;
+	int rv, id;
+
+	rv = idr_pre_get(&ls->ls_recover_idr, GFP_NOFS);
+	if (!rv)
+		return -ENOMEM;
+
+	spin_lock(&ls->ls_recover_idr_lock);
+	if (r->res_id) {
+		spin_unlock(&ls->ls_recover_idr_lock);
+		return -1;
+	}
+	rv = idr_get_new_above(&ls->ls_recover_idr, r, 1, &id);
+	if (rv) {
+		spin_unlock(&ls->ls_recover_idr_lock);
+		return rv;
+	}
+	r->res_id = id;
+	ls->ls_recover_list_count++;
+	dlm_hold_rsb(r);
+	spin_unlock(&ls->ls_recover_idr_lock);
+	return 0;
+}
+
+static void recover_idr_del(struct dlm_rsb *r)
+{
+	struct dlm_ls *ls = r->res_ls;
+
+	spin_lock(&ls->ls_recover_idr_lock);
+	idr_remove(&ls->ls_recover_idr, r->res_id);
+	r->res_id = 0;
+	ls->ls_recover_list_count--;
+	spin_unlock(&ls->ls_recover_idr_lock);
+
+	dlm_put_rsb(r);
+}
+
+static struct dlm_rsb *recover_idr_find(struct dlm_ls *ls, uint64_t id)
+{
+	struct dlm_rsb *r;
+
+	spin_lock(&ls->ls_recover_idr_lock);
+	r = idr_find(&ls->ls_recover_idr, (int)id);
+	spin_unlock(&ls->ls_recover_idr_lock);
+	return r;
+}
+
+static int recover_idr_clear_rsb(int id, void *p, void *data)
+{
+	struct dlm_ls *ls = data;
+	struct dlm_rsb *r = p;
+
+	r->res_id = 0;
+	r->res_recover_locks_count = 0;
+	ls->ls_recover_list_count--;
+
+	dlm_put_rsb(r);
+	return 0;
+}
+
+static void recover_idr_clear(struct dlm_ls *ls)
+{
+	spin_lock(&ls->ls_recover_idr_lock);
+	idr_for_each(&ls->ls_recover_idr, recover_idr_clear_rsb, ls);
+	idr_remove_all(&ls->ls_recover_idr);
+
+	if (ls->ls_recover_list_count != 0) {
+		log_error(ls, "warning: recover_list_count %d",
+			  ls->ls_recover_list_count);
+		ls->ls_recover_list_count = 0;
+	}
+	spin_unlock(&ls->ls_recover_idr_lock);
+}
+
 
 /* Master recovery: find new master node for rsb's that were
    mastered on nodes that have been removed.
@@ -361,9 +426,8 @@ static void set_master_lkbs(struct dlm_rsb *r)
  * rsb's to consider.
  */
 
-static void set_new_master(struct dlm_rsb *r, int nodeid)
+static void set_new_master(struct dlm_rsb *r)
 {
-	r->res_nodeid = nodeid;
 	set_master_lkbs(r);
 	rsb_set_flag(r, RSB_NEW_MASTER);
 	rsb_set_flag(r, RSB_NEW_MASTER2);
@@ -372,31 +436,48 @@ static void set_new_master(struct dlm_rsb *r, int nodeid)
 /*
  * We do async lookups on rsb's that need new masters.  The rsb's
  * waiting for a lookup reply are kept on the recover_list.
+ *
+ * Another node recovering the master may have sent us a rcom lookup,
+ * and our dlm_master_lookup() set it as the new master, along with
+ * NEW_MASTER so that we'll recover it here (this implies dir_nodeid
+ * equals our_nodeid below).
  */
 
-static int recover_master(struct dlm_rsb *r)
+static int recover_master(struct dlm_rsb *r, unsigned int *count)
 {
 	struct dlm_ls *ls = r->res_ls;
-	int error, ret_nodeid;
-	int our_nodeid = dlm_our_nodeid();
-	int dir_nodeid = dlm_dir_nodeid(r);
+	int our_nodeid, dir_nodeid;
+	int is_removed = 0;
+	int error;
+
+	if (is_master(r))
+		return 0;
+
+	is_removed = dlm_is_removed(ls, r->res_nodeid);
+
+	if (!is_removed && !rsb_flag(r, RSB_NEW_MASTER))
+		return 0;
+
+	our_nodeid = dlm_our_nodeid();
+	dir_nodeid = dlm_dir_nodeid(r);
 
 	if (dir_nodeid == our_nodeid) {
-		error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
-				       r->res_length, &ret_nodeid);
-		if (error)
-			log_error(ls, "recover dir lookup error %d", error);
+		if (is_removed) {
+			r->res_master_nodeid = our_nodeid;
+			r->res_nodeid = 0;
+		}
 
-		if (ret_nodeid == our_nodeid)
-			ret_nodeid = 0;
-		lock_rsb(r);
-		set_new_master(r, ret_nodeid);
-		unlock_rsb(r);
+		/* set master of lkbs to ourself when is_removed, or to
+		   another new master which we set along with NEW_MASTER
+		   in dlm_master_lookup */
+		set_new_master(r);
+		error = 0;
 	} else {
-		recover_list_add(r);
+		recover_idr_add(r);
 		error = dlm_send_rcom_lookup(r, dir_nodeid);
 	}
 
+	(*count)++;
 	return error;
 }
 
@@ -415,7 +496,7 @@ static int recover_master(struct dlm_rsb *r)
  * resent.
  */
 
-static int recover_master_static(struct dlm_rsb *r)
+static int recover_master_static(struct dlm_rsb *r, unsigned int *count)
 {
 	int dir_nodeid = dlm_dir_nodeid(r);
 	int new_master = dir_nodeid;
@@ -423,11 +504,12 @@ static int recover_master_static(struct dlm_rsb *r)
 	if (dir_nodeid == dlm_our_nodeid())
 		new_master = 0;
 
-	lock_rsb(r);
 	dlm_purge_mstcpy_locks(r);
-	set_new_master(r, new_master);
-	unlock_rsb(r);
-	return 1;
+	r->res_master_nodeid = dir_nodeid;
+	r->res_nodeid = new_master;
+	set_new_master(r);
+	(*count)++;
+	return 0;
 }
 
 /*
@@ -443,7 +525,10 @@ static int recover_master_static(struct dlm_rsb *r)
 int dlm_recover_masters(struct dlm_ls *ls)
 {
 	struct dlm_rsb *r;
-	int error = 0, count = 0;
+	unsigned int total = 0;
+	unsigned int count = 0;
+	int nodir = dlm_no_directory(ls);
+	int error;
 
 	log_debug(ls, "dlm_recover_masters");
 
@@ -455,50 +540,58 @@ int dlm_recover_masters(struct dlm_ls *ls)
 			goto out;
 		}
 
-		if (dlm_no_directory(ls))
-			count += recover_master_static(r);
-		else if (!is_master(r) &&
-			 (dlm_is_removed(ls, r->res_nodeid) ||
-			  rsb_flag(r, RSB_NEW_MASTER))) {
-			recover_master(r);
-			count++;
-		}
+		lock_rsb(r);
+		if (nodir)
+			error = recover_master_static(r, &count);
+		else
+			error = recover_master(r, &count);
+		unlock_rsb(r);
+		cond_resched();
+		total++;
 
-		schedule();
+		if (error) {
+			up_read(&ls->ls_root_sem);
+			goto out;
+		}
 	}
 	up_read(&ls->ls_root_sem);
 
-	log_debug(ls, "dlm_recover_masters %d resources", count);
+	log_debug(ls, "dlm_recover_masters %u of %u", count, total);
 
-	error = dlm_wait_function(ls, &recover_list_empty);
+	error = dlm_wait_function(ls, &recover_idr_empty);
  out:
 	if (error)
-		recover_list_clear(ls);
+		recover_idr_clear(ls);
 	return error;
 }
 
 int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
 {
 	struct dlm_rsb *r;
-	int nodeid;
+	int ret_nodeid, new_master;
 
-	r = recover_list_find(ls, rc->rc_id);
+	r = recover_idr_find(ls, rc->rc_id);
 	if (!r) {
 		log_error(ls, "dlm_recover_master_reply no id %llx",
 			  (unsigned long long)rc->rc_id);
 		goto out;
 	}
 
-	nodeid = rc->rc_result;
-	if (nodeid == dlm_our_nodeid())
-		nodeid = 0;
+	ret_nodeid = rc->rc_result;
+
+	if (ret_nodeid == dlm_our_nodeid())
+		new_master = 0;
+	else
+		new_master = ret_nodeid;
 
 	lock_rsb(r);
-	set_new_master(r, nodeid);
+	r->res_master_nodeid = ret_nodeid;
+	r->res_nodeid = new_master;
+	set_new_master(r);
 	unlock_rsb(r);
-	recover_list_del(r);
+	recover_idr_del(r);
 
-	if (recover_list_empty(ls))
+	if (recover_idr_empty(ls))
 		wake_up(&ls->ls_wait_general);
  out:
 	return 0;
@@ -711,6 +804,7 @@ static void recover_lvb(struct dlm_rsb *r)
 
 static void recover_conversion(struct dlm_rsb *r)
 {
+	struct dlm_ls *ls = r->res_ls;
 	struct dlm_lkb *lkb;
 	int grmode = -1;
 
@@ -725,10 +819,15 @@ static void recover_conversion(struct dlm_rsb *r)
 	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
 		if (lkb->lkb_grmode != DLM_LOCK_IV)
 			continue;
-		if (grmode == -1)
+		if (grmode == -1) {
+			log_debug(ls, "recover_conversion %x set gr to rq %d",
+				  lkb->lkb_id, lkb->lkb_rqmode);
 			lkb->lkb_grmode = lkb->lkb_rqmode;
-		else
+		} else {
+			log_debug(ls, "recover_conversion %x set gr %d",
+				  lkb->lkb_id, grmode);
 			lkb->lkb_grmode = grmode;
+		}
 	}
 }
 
@@ -791,20 +890,8 @@ int dlm_create_root_list(struct dlm_ls *ls)
 			dlm_hold_rsb(r);
 		}
 
-		/* If we're using a directory, add tossed rsbs to the root
-		   list; they'll have entries created in the new directory,
-		   but no other recovery steps should do anything with them. */
-
-		if (dlm_no_directory(ls)) {
-			spin_unlock(&ls->ls_rsbtbl[i].lock);
-			continue;
-		}
-
-		for (n = rb_first(&ls->ls_rsbtbl[i].toss); n; n = rb_next(n)) {
-			r = rb_entry(n, struct dlm_rsb, res_hashnode);
-			list_add(&r->res_root_list, &ls->ls_root_list);
-			dlm_hold_rsb(r);
-		}
+		if (!RB_EMPTY_ROOT(&ls->ls_rsbtbl[i].toss))
+			log_error(ls, "dlm_create_root_list toss not empty");
 		spin_unlock(&ls->ls_rsbtbl[i].lock);
 	}
  out:
@@ -824,28 +911,26 @@ void dlm_release_root_list(struct dlm_ls *ls)
 	up_write(&ls->ls_root_sem);
 }
 
-/* If not using a directory, clear the entire toss list, there's no benefit to
-   caching the master value since it's fixed.  If we are using a dir, keep the
-   rsb's we're the master of.  Recovery will add them to the root list and from
-   there they'll be entered in the rebuilt directory. */
-
-void dlm_clear_toss_list(struct dlm_ls *ls)
+void dlm_clear_toss(struct dlm_ls *ls)
 {
 	struct rb_node *n, *next;
-	struct dlm_rsb *rsb;
+	struct dlm_rsb *r;
+	unsigned int count = 0;
 	int i;
 
 	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
 		spin_lock(&ls->ls_rsbtbl[i].lock);
 		for (n = rb_first(&ls->ls_rsbtbl[i].toss); n; n = next) {
-			next = rb_next(n);;
-			rsb = rb_entry(n, struct dlm_rsb, res_hashnode);
-			if (dlm_no_directory(ls) || !is_master(rsb)) {
-				rb_erase(n, &ls->ls_rsbtbl[i].toss);
-				dlm_free_rsb(rsb);
-			}
+			next = rb_next(n);
+			r = rb_entry(n, struct dlm_rsb, res_hashnode);
+			rb_erase(n, &ls->ls_rsbtbl[i].toss);
+			dlm_free_rsb(r);
+			count++;
 		}
 		spin_unlock(&ls->ls_rsbtbl[i].lock);
 	}
+
+	if (count)
+		log_debug(ls, "dlm_clear_toss %u done", count);
 }
 
diff --git a/fs/dlm/recover.h b/fs/dlm/recover.h
index ebd0363..d8c8738 100644
--- a/fs/dlm/recover.h
+++ b/fs/dlm/recover.h
@@ -27,7 +27,7 @@ int dlm_recover_locks(struct dlm_ls *ls);
 void dlm_recovered_lock(struct dlm_rsb *r);
 int dlm_create_root_list(struct dlm_ls *ls);
 void dlm_release_root_list(struct dlm_ls *ls);
-void dlm_clear_toss_list(struct dlm_ls *ls);
+void dlm_clear_toss(struct dlm_ls *ls);
 void dlm_recover_rsbs(struct dlm_ls *ls);
 
 #endif				/* __RECOVER_DOT_H__ */
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
index f1a9073..88ce65f 100644
--- a/fs/dlm/recoverd.c
+++ b/fs/dlm/recoverd.c
@@ -60,12 +60,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
 	dlm_callback_suspend(ls);
 
-	/*
-	 * Free non-master tossed rsb's.  Master rsb's are kept on toss
-	 * list and put on root list to be included in resdir recovery.
-	 */
-
-	dlm_clear_toss_list(ls);
+	dlm_clear_toss(ls);
 
 	/*
 	 * This list of root rsb's will be the basis of most of the recovery
@@ -84,6 +79,10 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 		goto fail;
 	}
 
+	dlm_recover_dir_nodeid(ls);
+
+	ls->ls_recover_dir_sent_res = 0;
+	ls->ls_recover_dir_sent_msg = 0;
 	ls->ls_recover_locks_in = 0;
 
 	dlm_set_recover_status(ls, DLM_RS_NODES);
@@ -115,6 +114,9 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 		goto fail;
 	}
 
+	log_debug(ls, "dlm_recover_directory %u out %u messages",
+		  ls->ls_recover_dir_sent_res, ls->ls_recover_dir_sent_msg);
+
 	/*
 	 * We may have outstanding operations that are waiting for a reply from
 	 * a failed node.  Mark these to be resent after recovery.  Unlock and
diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c
index 534c1d4..1b5d9af 100644
--- a/fs/ecryptfs/dentry.c
+++ b/fs/ecryptfs/dentry.c
@@ -32,7 +32,7 @@
 /**
  * ecryptfs_d_revalidate - revalidate an ecryptfs dentry
  * @dentry: The ecryptfs dentry
- * @nd: The associated nameidata
+ * @flags: lookup flags
  *
  * Called when the VFS needs to revalidate a dentry. This
  * is called whenever a name lookup finds a dentry in the
@@ -42,32 +42,20 @@
  * Returns 1 if valid, 0 otherwise.
  *
  */
-static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct dentry *lower_dentry;
 	struct vfsmount *lower_mnt;
-	struct dentry *dentry_save = NULL;
-	struct vfsmount *vfsmount_save = NULL;
 	int rc = 1;
 
-	if (nd && nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	lower_dentry = ecryptfs_dentry_to_lower(dentry);
 	lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
 	if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
 		goto out;
-	if (nd) {
-		dentry_save = nd->path.dentry;
-		vfsmount_save = nd->path.mnt;
-		nd->path.dentry = lower_dentry;
-		nd->path.mnt = lower_mnt;
-	}
-	rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
-	if (nd) {
-		nd->path.dentry = dentry_save;
-		nd->path.mnt = vfsmount_save;
-	}
+	rc = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
 	if (dentry->d_inode) {
 		struct inode *lower_inode =
 			ecryptfs_inode_to_lower(dentry->d_inode);
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 867b64c..9f77ff8 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -385,8 +385,6 @@ struct ecryptfs_msg_ctx {
 	struct mutex mux;
 };
 
-struct ecryptfs_daemon;
-
 struct ecryptfs_daemon {
 #define ECRYPTFS_DAEMON_IN_READ      0x00000001
 #define ECRYPTFS_DAEMON_IN_POLL      0x00000002
@@ -394,10 +392,7 @@ struct ecryptfs_daemon {
 #define ECRYPTFS_DAEMON_MISCDEV_OPEN 0x00000008
 	u32 flags;
 	u32 num_queued_msg_ctx;
-	struct pid *pid;
-	uid_t euid;
-	struct user_namespace *user_ns;
-	struct task_struct *task;
+	struct file *file;
 	struct mutex mux;
 	struct list_head msg_ctx_out_queue;
 	wait_queue_head_t wait;
@@ -568,6 +563,8 @@ struct ecryptfs_open_req {
 struct inode *ecryptfs_get_inode(struct inode *lower_inode,
 				 struct super_block *sb);
 void ecryptfs_i_size_init(const char *page_virt, struct inode *inode);
+int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
+			     struct inode *ecryptfs_inode);
 int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,
 					 size_t *decrypted_name_size,
 					 struct dentry *ecryptfs_dentry,
@@ -621,13 +618,8 @@ int
 ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
 		  size_t size, int flags);
 int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode);
-int ecryptfs_process_helo(uid_t euid, struct user_namespace *user_ns,
-			  struct pid *pid);
-int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,
-			  struct pid *pid);
-int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
-			      struct user_namespace *user_ns, struct pid *pid,
-			      u32 seq);
+int ecryptfs_process_response(struct ecryptfs_daemon *daemon,
+			      struct ecryptfs_message *msg, u32 seq);
 int ecryptfs_send_message(char *data, int data_len,
 			  struct ecryptfs_msg_ctx **msg_ctx);
 int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
@@ -672,8 +664,7 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
 				     struct inode *ecryptfs_inode);
 struct page *ecryptfs_get_locked_page(struct inode *inode, loff_t index);
 int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon);
-int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid,
-				 struct user_namespace *user_ns);
+int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon);
 int ecryptfs_parse_packet_length(unsigned char *data, size_t *size,
 				 size_t *length_size);
 int ecryptfs_write_packet_length(char *dest, size_t size,
@@ -685,8 +676,7 @@ int ecryptfs_send_miscdev(char *data, size_t data_size,
 			  u16 msg_flags, struct ecryptfs_daemon *daemon);
 void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx);
 int
-ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,
-		      struct user_namespace *user_ns, struct pid *pid);
+ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, struct file *file);
 int ecryptfs_init_kthread(void);
 void ecryptfs_destroy_kthread(void);
 int ecryptfs_privileged_open(struct file **lower_file,
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 2b17f2f..baf8b05 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -161,6 +161,48 @@ static int ecryptfs_file_mmap(struct file *file, struct vm_area_struct *vma)
 
 struct kmem_cache *ecryptfs_file_info_cache;
 
+static int read_or_initialize_metadata(struct dentry *dentry)
+{
+	struct inode *inode = dentry->d_inode;
+	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+	struct ecryptfs_crypt_stat *crypt_stat;
+	int rc;
+
+	crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+	mount_crypt_stat = &ecryptfs_superblock_to_private(
+						inode->i_sb)->mount_crypt_stat;
+	mutex_lock(&crypt_stat->cs_mutex);
+
+	if (crypt_stat->flags & ECRYPTFS_POLICY_APPLIED &&
+	    crypt_stat->flags & ECRYPTFS_KEY_VALID) {
+		rc = 0;
+		goto out;
+	}
+
+	rc = ecryptfs_read_metadata(dentry);
+	if (!rc)
+		goto out;
+
+	if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED) {
+		crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
+				       | ECRYPTFS_ENCRYPTED);
+		rc = 0;
+		goto out;
+	}
+
+	if (!(mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) &&
+	    !i_size_read(ecryptfs_inode_to_lower(inode))) {
+		rc = ecryptfs_initialize_file(dentry, inode);
+		if (!rc)
+			goto out;
+	}
+
+	rc = -EIO;
+out:
+	mutex_unlock(&crypt_stat->cs_mutex);
+	return rc;
+}
+
 /**
  * ecryptfs_open
  * @inode: inode speciying file to open
@@ -236,32 +278,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
 		rc = 0;
 		goto out;
 	}
-	mutex_lock(&crypt_stat->cs_mutex);
-	if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
-	    || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) {
-		rc = ecryptfs_read_metadata(ecryptfs_dentry);
-		if (rc) {
-			ecryptfs_printk(KERN_DEBUG,
-					"Valid headers not found\n");
-			if (!(mount_crypt_stat->flags
-			      & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
-				rc = -EIO;
-				printk(KERN_WARNING "Either the lower file "
-				       "is not in a valid eCryptfs format, "
-				       "or the key could not be retrieved. "
-				       "Plaintext passthrough mode is not "
-				       "enabled; returning -EIO\n");
-				mutex_unlock(&crypt_stat->cs_mutex);
-				goto out_put;
-			}
-			rc = 0;
-			crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
-					       | ECRYPTFS_ENCRYPTED);
-			mutex_unlock(&crypt_stat->cs_mutex);
-			goto out;
-		}
-	}
-	mutex_unlock(&crypt_stat->cs_mutex);
+	rc = read_or_initialize_metadata(ecryptfs_dentry);
+	if (rc)
+		goto out_put;
 	ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = "
 			"[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino,
 			(unsigned long long)i_size_read(inode));
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index a07441a..908ade7 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -143,6 +143,31 @@ static int ecryptfs_interpose(struct dentry *lower_dentry,
 	return 0;
 }
 
+static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry,
+			      struct inode *inode)
+{
+	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
+	struct dentry *lower_dir_dentry;
+	int rc;
+
+	dget(lower_dentry);
+	lower_dir_dentry = lock_parent(lower_dentry);
+	rc = vfs_unlink(lower_dir_inode, lower_dentry);
+	if (rc) {
+		printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
+		goto out_unlock;
+	}
+	fsstack_copy_attr_times(dir, lower_dir_inode);
+	set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink);
+	inode->i_ctime = dir->i_ctime;
+	d_drop(dentry);
+out_unlock:
+	unlock_dir(lower_dir_dentry);
+	dput(lower_dentry);
+	return rc;
+}
+
 /**
  * ecryptfs_do_create
  * @directory_inode: inode of the new file's dentry's parent in ecryptfs
@@ -173,7 +198,7 @@ ecryptfs_do_create(struct inode *directory_inode,
 		inode = ERR_CAST(lower_dir_dentry);
 		goto out;
 	}
-	rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, NULL);
+	rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, true);
 	if (rc) {
 		printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
 		       "rc = [%d]\n", __func__, rc);
@@ -182,8 +207,10 @@ ecryptfs_do_create(struct inode *directory_inode,
 	}
 	inode = __ecryptfs_get_inode(lower_dentry->d_inode,
 				     directory_inode->i_sb);
-	if (IS_ERR(inode))
+	if (IS_ERR(inode)) {
+		vfs_unlink(lower_dir_dentry->d_inode, lower_dentry);
 		goto out_lock;
+	}
 	fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode);
 	fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode);
 out_lock:
@@ -200,8 +227,8 @@ out:
  *
  * Returns zero on success
  */
-static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
-				    struct inode *ecryptfs_inode)
+int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
+			     struct inode *ecryptfs_inode)
 {
 	struct ecryptfs_crypt_stat *crypt_stat =
 		&ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
@@ -240,7 +267,6 @@ out:
  * @dir: The inode of the directory in which to create the file.
  * @dentry: The eCryptfs dentry
  * @mode: The mode of the new file.
- * @nd: nameidata
  *
  * Creates a new file.
  *
@@ -248,7 +274,7 @@ out:
  */
 static int
 ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
-		umode_t mode, struct nameidata *nd)
+		umode_t mode, bool excl)
 {
 	struct inode *ecryptfs_inode;
 	int rc;
@@ -265,7 +291,9 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
 	 * that this on disk file is prepared to be an ecryptfs file */
 	rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode);
 	if (rc) {
-		drop_nlink(ecryptfs_inode);
+		ecryptfs_do_unlink(directory_inode, ecryptfs_dentry,
+				   ecryptfs_inode);
+		make_bad_inode(ecryptfs_inode);
 		unlock_new_inode(ecryptfs_inode);
 		iput(ecryptfs_inode);
 		goto out;
@@ -374,7 +402,7 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry,
  */
 static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
 				      struct dentry *ecryptfs_dentry,
-				      struct nameidata *ecryptfs_nd)
+				      unsigned int flags)
 {
 	char *encrypted_and_encoded_name = NULL;
 	size_t encrypted_and_encoded_name_size;
@@ -477,27 +505,7 @@ out_lock:
 
 static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
 {
-	int rc = 0;
-	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
-	struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
-	struct dentry *lower_dir_dentry;
-
-	dget(lower_dentry);
-	lower_dir_dentry = lock_parent(lower_dentry);
-	rc = vfs_unlink(lower_dir_inode, lower_dentry);
-	if (rc) {
-		printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
-		goto out_unlock;
-	}
-	fsstack_copy_attr_times(dir, lower_dir_inode);
-	set_nlink(dentry->d_inode,
-		  ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink);
-	dentry->d_inode->i_ctime = dir->i_ctime;
-	d_drop(dentry);
-out_unlock:
-	unlock_dir(lower_dir_dentry);
-	dput(lower_dentry);
-	return rc;
+	return ecryptfs_do_unlink(dir, dentry, dentry->d_inode);
 }
 
 static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c
index 69f994a..0dbe58a 100644
--- a/fs/ecryptfs/kthread.c
+++ b/fs/ecryptfs/kthread.c
@@ -149,7 +149,7 @@ int ecryptfs_privileged_open(struct file **lower_file,
 	(*lower_file) = dentry_open(lower_dentry, lower_mnt, flags, cred);
 	if (!IS_ERR(*lower_file))
 		goto out;
-	if (flags & O_RDONLY) {
+	if ((flags & O_ACCMODE) == O_RDONLY) {
 		rc = PTR_ERR((*lower_file));
 		goto out;
 	}
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 6895493..06abfa0 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -505,7 +505,6 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
 		goto out;
 	}
 
-	s->s_flags = flags;
 	rc = bdi_setup_and_register(&sbi->bdi, "ecryptfs", BDI_CAP_MAP_COPY);
 	if (rc)
 		goto out1;
@@ -541,6 +540,15 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
 	}
 
 	ecryptfs_set_superblock_lower(s, path.dentry->d_sb);
+
+	/**
+	 * Set the POSIX ACL flag based on whether they're enabled in the lower
+	 * mount. Force a read-only eCryptfs mount if the lower mount is ro.
+	 * Allow a ro eCryptfs mount even when the lower mount is rw.
+	 */
+	s->s_flags = flags & ~MS_POSIXACL;
+	s->s_flags |= path.dentry->d_sb->s_flags & (MS_RDONLY | MS_POSIXACL);
+
 	s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
 	s->s_blocksize = path.dentry->d_sb->s_blocksize;
 	s->s_magic = ECRYPTFS_SUPER_MAGIC;
@@ -693,6 +701,12 @@ static void ecryptfs_free_kmem_caches(void)
 {
 	int i;
 
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
+
 	for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {
 		struct ecryptfs_cache_info *info;
 
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c
index a750f95..b29bb8b 100644
--- a/fs/ecryptfs/messaging.c
+++ b/fs/ecryptfs/messaging.c
@@ -32,8 +32,8 @@ static struct mutex ecryptfs_msg_ctx_lists_mux;
 static struct hlist_head *ecryptfs_daemon_hash;
 struct mutex ecryptfs_daemon_hash_mux;
 static int ecryptfs_hash_bits;
-#define ecryptfs_uid_hash(uid) \
-        hash_long((unsigned long)uid, ecryptfs_hash_bits)
+#define ecryptfs_current_euid_hash(uid) \
+		hash_long((unsigned long)current_euid(), ecryptfs_hash_bits)
 
 static u32 ecryptfs_msg_counter;
 static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
@@ -105,26 +105,24 @@ void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
 
 /**
  * ecryptfs_find_daemon_by_euid
- * @euid: The effective user id which maps to the desired daemon id
- * @user_ns: The namespace in which @euid applies
  * @daemon: If return value is zero, points to the desired daemon pointer
  *
  * Must be called with ecryptfs_daemon_hash_mux held.
  *
- * Search the hash list for the given user id.
+ * Search the hash list for the current effective user id.
  *
  * Returns zero if the user id exists in the list; non-zero otherwise.
  */
-int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid,
-				 struct user_namespace *user_ns)
+int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon)
 {
 	struct hlist_node *elem;
 	int rc;
 
 	hlist_for_each_entry(*daemon, elem,
-			     &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)],
-			     euid_chain) {
-		if ((*daemon)->euid == euid && (*daemon)->user_ns == user_ns) {
+			    &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()],
+			    euid_chain) {
+		if ((*daemon)->file->f_cred->euid == current_euid() &&
+		    (*daemon)->file->f_cred->user_ns == current_user_ns()) {
 			rc = 0;
 			goto out;
 		}
@@ -137,9 +135,7 @@ out:
 /**
  * ecryptfs_spawn_daemon - Create and initialize a new daemon struct
  * @daemon: Pointer to set to newly allocated daemon struct
- * @euid: Effective user id for the daemon
- * @user_ns: The namespace in which @euid applies
- * @pid: Process id for the daemon
+ * @file: File used when opening /dev/ecryptfs
  *
  * Must be called ceremoniously while in possession of
  * ecryptfs_sacred_daemon_hash_mux
@@ -147,8 +143,7 @@ out:
  * Returns zero on success; non-zero otherwise
  */
 int
-ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,
-		      struct user_namespace *user_ns, struct pid *pid)
+ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, struct file *file)
 {
 	int rc = 0;
 
@@ -159,16 +154,13 @@ ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,
 		       "GFP_KERNEL memory\n", __func__, sizeof(**daemon));
 		goto out;
 	}
-	(*daemon)->euid = euid;
-	(*daemon)->user_ns = get_user_ns(user_ns);
-	(*daemon)->pid = get_pid(pid);
-	(*daemon)->task = current;
+	(*daemon)->file = file;
 	mutex_init(&(*daemon)->mux);
 	INIT_LIST_HEAD(&(*daemon)->msg_ctx_out_queue);
 	init_waitqueue_head(&(*daemon)->wait);
 	(*daemon)->num_queued_msg_ctx = 0;
 	hlist_add_head(&(*daemon)->euid_chain,
-		       &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)]);
+		       &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()]);
 out:
 	return rc;
 }
@@ -188,9 +180,6 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
 	if ((daemon->flags & ECRYPTFS_DAEMON_IN_READ)
 	    || (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)) {
 		rc = -EBUSY;
-		printk(KERN_WARNING "%s: Attempt to destroy daemon with pid "
-		       "[0x%p], but it is in the midst of a read or a poll\n",
-		       __func__, daemon->pid);
 		mutex_unlock(&daemon->mux);
 		goto out;
 	}
@@ -203,12 +192,6 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
 		ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
 	}
 	hlist_del(&daemon->euid_chain);
-	if (daemon->task)
-		wake_up_process(daemon->task);
-	if (daemon->pid)
-		put_pid(daemon->pid);
-	if (daemon->user_ns)
-		put_user_ns(daemon->user_ns);
 	mutex_unlock(&daemon->mux);
 	kzfree(daemon);
 out:
@@ -216,42 +199,9 @@ out:
 }
 
 /**
- * ecryptfs_process_quit
- * @euid: The user ID owner of the message
- * @user_ns: The namespace in which @euid applies
- * @pid: The process ID for the userspace program that sent the
- *       message
- *
- * Deletes the corresponding daemon for the given euid and pid, if
- * it is the registered that is requesting the deletion. Returns zero
- * after deleting the desired daemon; non-zero otherwise.
- */
-int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,
-			  struct pid *pid)
-{
-	struct ecryptfs_daemon *daemon;
-	int rc;
-
-	mutex_lock(&ecryptfs_daemon_hash_mux);
-	rc = ecryptfs_find_daemon_by_euid(&daemon, euid, user_ns);
-	if (rc || !daemon) {
-		rc = -EINVAL;
-		printk(KERN_ERR "Received request from user [%d] to "
-		       "unregister unrecognized daemon [0x%p]\n", euid, pid);
-		goto out_unlock;
-	}
-	rc = ecryptfs_exorcise_daemon(daemon);
-out_unlock:
-	mutex_unlock(&ecryptfs_daemon_hash_mux);
-	return rc;
-}
-
-/**
  * ecryptfs_process_reponse
  * @msg: The ecryptfs message received; the caller should sanity check
  *       msg->data_len and free the memory
- * @pid: The process ID of the userspace application that sent the
- *       message
  * @seq: The sequence number of the message; must match the sequence
  *       number for the existing message context waiting for this
  *       response
@@ -270,16 +220,11 @@ out_unlock:
  *
  * Returns zero on success; non-zero otherwise
  */
-int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
-			      struct user_namespace *user_ns, struct pid *pid,
-			      u32 seq)
+int ecryptfs_process_response(struct ecryptfs_daemon *daemon,
+			      struct ecryptfs_message *msg, u32 seq)
 {
-	struct ecryptfs_daemon *uninitialized_var(daemon);
 	struct ecryptfs_msg_ctx *msg_ctx;
 	size_t msg_size;
-	struct nsproxy *nsproxy;
-	struct user_namespace *tsk_user_ns;
-	uid_t ctx_euid;
 	int rc;
 
 	if (msg->index >= ecryptfs_message_buf_len) {
@@ -292,51 +237,6 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
 	}
 	msg_ctx = &ecryptfs_msg_ctx_arr[msg->index];
 	mutex_lock(&msg_ctx->mux);
-	mutex_lock(&ecryptfs_daemon_hash_mux);
-	rcu_read_lock();
-	nsproxy = task_nsproxy(msg_ctx->task);
-	if (nsproxy == NULL) {
-		rc = -EBADMSG;
-		printk(KERN_ERR "%s: Receiving process is a zombie. Dropping "
-		       "message.\n", __func__);
-		rcu_read_unlock();
-		mutex_unlock(&ecryptfs_daemon_hash_mux);
-		goto wake_up;
-	}
-	tsk_user_ns = __task_cred(msg_ctx->task)->user_ns;
-	ctx_euid = task_euid(msg_ctx->task);
-	rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns);
-	rcu_read_unlock();
-	mutex_unlock(&ecryptfs_daemon_hash_mux);
-	if (rc) {
-		rc = -EBADMSG;
-		printk(KERN_WARNING "%s: User [%d] received a "
-		       "message response from process [0x%p] but does "
-		       "not have a registered daemon\n", __func__,
-		       ctx_euid, pid);
-		goto wake_up;
-	}
-	if (ctx_euid != euid) {
-		rc = -EBADMSG;
-		printk(KERN_WARNING "%s: Received message from user "
-		       "[%d]; expected message from user [%d]\n", __func__,
-		       euid, ctx_euid);
-		goto unlock;
-	}
-	if (tsk_user_ns != user_ns) {
-		rc = -EBADMSG;
-		printk(KERN_WARNING "%s: Received message from user_ns "
-		       "[0x%p]; expected message from user_ns [0x%p]\n",
-		       __func__, user_ns, tsk_user_ns);
-		goto unlock;
-	}
-	if (daemon->pid != pid) {
-		rc = -EBADMSG;
-		printk(KERN_ERR "%s: User [%d] sent a message response "
-		       "from an unrecognized process [0x%p]\n",
-		       __func__, ctx_euid, pid);
-		goto unlock;
-	}
 	if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
 		rc = -EINVAL;
 		printk(KERN_WARNING "%s: Desired context element is not "
@@ -359,9 +259,8 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
 	}
 	memcpy(msg_ctx->msg, msg, msg_size);
 	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE;
-	rc = 0;
-wake_up:
 	wake_up_process(msg_ctx->task);
+	rc = 0;
 unlock:
 	mutex_unlock(&msg_ctx->mux);
 out:
@@ -383,14 +282,11 @@ ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,
 			     struct ecryptfs_msg_ctx **msg_ctx)
 {
 	struct ecryptfs_daemon *daemon;
-	uid_t euid = current_euid();
 	int rc;
 
-	rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
+	rc = ecryptfs_find_daemon_by_euid(&daemon);
 	if (rc || !daemon) {
 		rc = -ENOTCONN;
-		printk(KERN_ERR "%s: User [%d] does not have a daemon "
-		       "registered\n", __func__, euid);
 		goto out;
 	}
 	mutex_lock(&ecryptfs_msg_ctx_lists_mux);
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c
index 3a06f40..412e6ed 100644
--- a/fs/ecryptfs/miscdev.c
+++ b/fs/ecryptfs/miscdev.c
@@ -33,7 +33,7 @@ static atomic_t ecryptfs_num_miscdev_opens;
 
 /**
  * ecryptfs_miscdev_poll
- * @file: dev file (ignored)
+ * @file: dev file
  * @pt: dev poll table (ignored)
  *
  * Returns the poll mask
@@ -41,17 +41,10 @@ static atomic_t ecryptfs_num_miscdev_opens;
 static unsigned int
 ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
 {
-	struct ecryptfs_daemon *daemon;
+	struct ecryptfs_daemon *daemon = file->private_data;
 	unsigned int mask = 0;
-	uid_t euid = current_euid();
-	int rc;
 
-	mutex_lock(&ecryptfs_daemon_hash_mux);
-	/* TODO: Just use file->private_data? */
-	rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
-	BUG_ON(rc || !daemon);
 	mutex_lock(&daemon->mux);
-	mutex_unlock(&ecryptfs_daemon_hash_mux);
 	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
 		printk(KERN_WARNING "%s: Attempt to poll on zombified "
 		       "daemon\n", __func__);
@@ -76,7 +69,7 @@ out_unlock_daemon:
 /**
  * ecryptfs_miscdev_open
  * @inode: inode of miscdev handle (ignored)
- * @file: file for miscdev handle (ignored)
+ * @file: file for miscdev handle
  *
  * Returns zero on success; non-zero otherwise
  */
@@ -84,7 +77,6 @@ static int
 ecryptfs_miscdev_open(struct inode *inode, struct file *file)
 {
 	struct ecryptfs_daemon *daemon = NULL;
-	uid_t euid = current_euid();
 	int rc;
 
 	mutex_lock(&ecryptfs_daemon_hash_mux);
@@ -95,33 +87,24 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file)
 		       "count; rc = [%d]\n", __func__, rc);
 		goto out_unlock_daemon_list;
 	}
-	rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
-	if (rc || !daemon) {
-		rc = ecryptfs_spawn_daemon(&daemon, euid, current_user_ns(),
-					   task_pid(current));
-		if (rc) {
-			printk(KERN_ERR "%s: Error attempting to spawn daemon; "
-			       "rc = [%d]\n", __func__, rc);
-			goto out_module_put_unlock_daemon_list;
-		}
-	}
-	mutex_lock(&daemon->mux);
-	if (daemon->pid != task_pid(current)) {
+	rc = ecryptfs_find_daemon_by_euid(&daemon);
+	if (!rc) {
 		rc = -EINVAL;
-		printk(KERN_ERR "%s: pid [0x%p] has registered with euid [%d], "
-		       "but pid [0x%p] has attempted to open the handle "
-		       "instead\n", __func__, daemon->pid, daemon->euid,
-		       task_pid(current));
-		goto out_unlock_daemon;
+		goto out_unlock_daemon_list;
+	}
+	rc = ecryptfs_spawn_daemon(&daemon, file);
+	if (rc) {
+		printk(KERN_ERR "%s: Error attempting to spawn daemon; "
+		       "rc = [%d]\n", __func__, rc);
+		goto out_module_put_unlock_daemon_list;
 	}
+	mutex_lock(&daemon->mux);
 	if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
 		rc = -EBUSY;
-		printk(KERN_ERR "%s: Miscellaneous device handle may only be "
-		       "opened once per daemon; pid [0x%p] already has this "
-		       "handle open\n", __func__, daemon->pid);
 		goto out_unlock_daemon;
 	}
 	daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
+	file->private_data = daemon;
 	atomic_inc(&ecryptfs_num_miscdev_opens);
 out_unlock_daemon:
 	mutex_unlock(&daemon->mux);
@@ -136,7 +119,7 @@ out_unlock_daemon_list:
 /**
  * ecryptfs_miscdev_release
  * @inode: inode of fs/ecryptfs/euid handle (ignored)
- * @file: file for fs/ecryptfs/euid handle (ignored)
+ * @file: file for fs/ecryptfs/euid handle
  *
  * This keeps the daemon registered until the daemon sends another
  * ioctl to fs/ecryptfs/ctl or until the kernel module unregisters.
@@ -146,20 +129,18 @@ out_unlock_daemon_list:
 static int
 ecryptfs_miscdev_release(struct inode *inode, struct file *file)
 {
-	struct ecryptfs_daemon *daemon = NULL;
-	uid_t euid = current_euid();
+	struct ecryptfs_daemon *daemon = file->private_data;
 	int rc;
 
-	mutex_lock(&ecryptfs_daemon_hash_mux);
-	rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
-	BUG_ON(rc || !daemon);
 	mutex_lock(&daemon->mux);
-	BUG_ON(daemon->pid != task_pid(current));
 	BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
 	daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
 	atomic_dec(&ecryptfs_num_miscdev_opens);
 	mutex_unlock(&daemon->mux);
+
+	mutex_lock(&ecryptfs_daemon_hash_mux);
 	rc = ecryptfs_exorcise_daemon(daemon);
+	mutex_unlock(&ecryptfs_daemon_hash_mux);
 	if (rc) {
 		printk(KERN_CRIT "%s: Fatal error whilst attempting to "
 		       "shut down daemon; rc = [%d]. Please report this "
@@ -167,7 +148,6 @@ ecryptfs_miscdev_release(struct inode *inode, struct file *file)
 		BUG();
 	}
 	module_put(THIS_MODULE);
-	mutex_unlock(&ecryptfs_daemon_hash_mux);
 	return rc;
 }
 
@@ -191,31 +171,32 @@ int ecryptfs_send_miscdev(char *data, size_t data_size,
 			  struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
 			  u16 msg_flags, struct ecryptfs_daemon *daemon)
 {
-	int rc = 0;
+	struct ecryptfs_message *msg;
 
-	mutex_lock(&msg_ctx->mux);
-	msg_ctx->msg = kmalloc((sizeof(*msg_ctx->msg) + data_size),
-			       GFP_KERNEL);
-	if (!msg_ctx->msg) {
-		rc = -ENOMEM;
+	msg = kmalloc((sizeof(*msg) + data_size), GFP_KERNEL);
+	if (!msg) {
 		printk(KERN_ERR "%s: Out of memory whilst attempting "
 		       "to kmalloc(%zd, GFP_KERNEL)\n", __func__,
-		       (sizeof(*msg_ctx->msg) + data_size));
-		goto out_unlock;
+		       (sizeof(*msg) + data_size));
+		return -ENOMEM;
 	}
+
+	mutex_lock(&msg_ctx->mux);
+	msg_ctx->msg = msg;
 	msg_ctx->msg->index = msg_ctx->index;
 	msg_ctx->msg->data_len = data_size;
 	msg_ctx->type = msg_type;
 	memcpy(msg_ctx->msg->data, data, data_size);
 	msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);
-	mutex_lock(&daemon->mux);
 	list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue);
+	mutex_unlock(&msg_ctx->mux);
+
+	mutex_lock(&daemon->mux);
 	daemon->num_queued_msg_ctx++;
 	wake_up_interruptible(&daemon->wait);
 	mutex_unlock(&daemon->mux);
-out_unlock:
-	mutex_unlock(&msg_ctx->mux);
-	return rc;
+
+	return 0;
 }
 
 /*
@@ -243,7 +224,7 @@ out_unlock:
 
 /**
  * ecryptfs_miscdev_read - format and send message from queue
- * @file: fs/ecryptfs/euid miscdevfs handle (ignored)
+ * @file: miscdevfs handle
  * @buf: User buffer into which to copy the next message on the daemon queue
  * @count: Amount of space available in @buf
  * @ppos: Offset in file (ignored)
@@ -257,35 +238,27 @@ static ssize_t
 ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
 		      loff_t *ppos)
 {
-	struct ecryptfs_daemon *daemon;
+	struct ecryptfs_daemon *daemon = file->private_data;
 	struct ecryptfs_msg_ctx *msg_ctx;
 	size_t packet_length_size;
 	char packet_length[ECRYPTFS_MAX_PKT_LEN_SIZE];
 	size_t i;
 	size_t total_length;
-	uid_t euid = current_euid();
 	int rc;
 
-	mutex_lock(&ecryptfs_daemon_hash_mux);
-	/* TODO: Just use file->private_data? */
-	rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
-	BUG_ON(rc || !daemon);
 	mutex_lock(&daemon->mux);
 	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
 		rc = 0;
-		mutex_unlock(&ecryptfs_daemon_hash_mux);
 		printk(KERN_WARNING "%s: Attempt to read from zombified "
 		       "daemon\n", __func__);
 		goto out_unlock_daemon;
 	}
 	if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) {
 		rc = 0;
-		mutex_unlock(&ecryptfs_daemon_hash_mux);
 		goto out_unlock_daemon;
 	}
 	/* This daemon will not go away so long as this flag is set */
 	daemon->flags |= ECRYPTFS_DAEMON_IN_READ;
-	mutex_unlock(&ecryptfs_daemon_hash_mux);
 check_list:
 	if (list_empty(&daemon->msg_ctx_out_queue)) {
 		mutex_unlock(&daemon->mux);
@@ -307,9 +280,6 @@ check_list:
 		 * message from the queue; try again */
 		goto check_list;
 	}
-	BUG_ON(euid != daemon->euid);
-	BUG_ON(current_user_ns() != daemon->user_ns);
-	BUG_ON(task_pid(current) != daemon->pid);
 	msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
 				   struct ecryptfs_msg_ctx, daemon_out_list);
 	BUG_ON(!msg_ctx);
@@ -372,16 +342,12 @@ out_unlock_daemon:
  * ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon
  * @data: Bytes comprising struct ecryptfs_message
  * @data_size: sizeof(struct ecryptfs_message) + data len
- * @euid: Effective user id of miscdevess sending the miscdev response
- * @user_ns: The namespace in which @euid applies
- * @pid: Miscdevess id of miscdevess sending the miscdev response
  * @seq: Sequence number for miscdev response packet
  *
  * Returns zero on success; non-zero otherwise
  */
-static int ecryptfs_miscdev_response(char *data, size_t data_size,
-				     uid_t euid, struct user_namespace *user_ns,
-				     struct pid *pid, u32 seq)
+static int ecryptfs_miscdev_response(struct ecryptfs_daemon *daemon, char *data,
+				     size_t data_size, u32 seq)
 {
 	struct ecryptfs_message *msg = (struct ecryptfs_message *)data;
 	int rc;
@@ -393,7 +359,7 @@ static int ecryptfs_miscdev_response(char *data, size_t data_size,
 		rc = -EINVAL;
 		goto out;
 	}
-	rc = ecryptfs_process_response(msg, euid, user_ns, pid, seq);
+	rc = ecryptfs_process_response(daemon, msg, seq);
 	if (rc)
 		printk(KERN_ERR
 		       "Error processing response message; rc = [%d]\n", rc);
@@ -403,7 +369,7 @@ out:
 
 /**
  * ecryptfs_miscdev_write - handle write to daemon miscdev handle
- * @file: File for misc dev handle (ignored)
+ * @file: File for misc dev handle
  * @buf: Buffer containing user data
  * @count: Amount of data in @buf
  * @ppos: Pointer to offset in file (ignored)
@@ -418,7 +384,6 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf,
 	u32 seq;
 	size_t packet_size, packet_size_length;
 	char *data;
-	uid_t euid = current_euid();
 	unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE];
 	ssize_t rc;
 
@@ -478,10 +443,9 @@ memdup:
 		}
 		memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE);
 		seq = be32_to_cpu(counter_nbo);
-		rc = ecryptfs_miscdev_response(
+		rc = ecryptfs_miscdev_response(file->private_data,
 				&data[PKT_LEN_OFFSET + packet_size_length],
-				packet_size, euid, current_user_ns(),
-				task_pid(current), seq);
+				packet_size, seq);
 		if (rc) {
 			printk(KERN_WARNING "%s: Failed to deliver miscdev "
 			       "response to requesting operation; rc = [%zd]\n",
diff --git a/fs/efs/efs.h b/fs/efs/efs.h
index d8305b5..5528926 100644
--- a/fs/efs/efs.h
+++ b/fs/efs/efs.h
@@ -129,7 +129,7 @@ extern struct inode *efs_iget(struct super_block *, unsigned long);
 extern efs_block_t efs_map_block(struct inode *, efs_block_t);
 extern int efs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
-extern struct dentry *efs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct dentry *efs_lookup(struct inode *, struct dentry *, unsigned int);
 extern struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid,
 		int fh_len, int fh_type);
 extern struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid,
diff --git a/fs/efs/namei.c b/fs/efs/namei.c
index 832b10d..96f66d2 100644
--- a/fs/efs/namei.c
+++ b/fs/efs/namei.c
@@ -58,7 +58,8 @@ static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len)
 	return(0);
 }
 
-struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) {
+struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
 	efs_ino_t inodenum;
 	struct inode *inode = NULL;
 
diff --git a/fs/efs/super.c b/fs/efs/super.c
index e755ec7..2002431 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -96,6 +96,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(efs_inode_cachep);
 }
 
diff --git a/fs/exec.c b/fs/exec.c
index da27b91..9eda173 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1515,8 +1515,6 @@ static int do_execve_common(const char *filename,
 	if (IS_ERR(file))
 		goto out_unmark;
 
-	sched_exec();
-
 	bprm->file = file;
 	bprm->filename = filename;
 	bprm->interp = filename;
@@ -1525,6 +1523,8 @@ static int do_execve_common(const char *filename,
 	if (retval)
 		goto out_file;
 
+	sched_exec(bprm->mm);
+
 	bprm->argc = count(argv, MAX_ARG_STRINGS);
 	if ((retval = bprm->argc) < 0)
 		goto out;
diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c
index fc7161d..4731fd9 100644
--- a/fs/exofs/namei.c
+++ b/fs/exofs/namei.c
@@ -46,7 +46,7 @@ static inline int exofs_add_nondir(struct dentry *dentry, struct inode *inode)
 }
 
 static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
-				   struct nameidata *nd)
+				   unsigned int flags)
 {
 	struct inode *inode;
 	ino_t ino;
@@ -60,7 +60,7 @@ static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
 }
 
 static int exofs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-			 struct nameidata *nd)
+			 bool excl)
 {
 	struct inode *inode = exofs_new_inode(dir, mode);
 	int err = PTR_ERR(inode);
diff --git a/fs/exofs/super.c b/fs/exofs/super.c
index 4337836..d271f96 100644
--- a/fs/exofs/super.c
+++ b/fs/exofs/super.c
@@ -206,6 +206,11 @@ static int init_inodecache(void)
  */
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(exofs_inode_cachep);
 }
 
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index b0201ca..b42063c 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -44,13 +44,14 @@ find_acceptable_alias(struct dentry *result,
 {
 	struct dentry *dentry, *toput = NULL;
 	struct inode *inode;
+	struct hlist_node *p;
 
 	if (acceptable(context, result))
 		return result;
 
 	inode = result->d_inode;
 	spin_lock(&inode->i_lock);
-	list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+	hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
 		dget(dentry);
 		spin_unlock(&inode->i_lock);
 		if (toput)
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 1c36139..376aa77 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -1444,19 +1444,9 @@ ext2_fsblk_t ext2_new_block(struct inode *inode, unsigned long goal, int *errp)
 
 #ifdef EXT2FS_DEBUG
 
-static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
-
-unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars)
+unsigned long ext2_count_free(struct buffer_head *map, unsigned int numchars)
 {
-	unsigned int i;
-	unsigned long sum = 0;
-
-	if (!map)
-		return (0);
-	for (i = 0; i < numchars; i++)
-		sum += nibblemap[map->b_data[i] & 0xf] +
-			nibblemap[(map->b_data[i] >> 4) & 0xf];
-	return (sum);
+	return numchars * BITS_PER_BYTE - memweight(map->b_data, numchars);
 }
 
 #endif  /*  EXT2FS_DEBUG  */
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index c13eb7b..8f370e01 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -644,6 +644,7 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
 	}
 	brelse(bitmap_bh);
 	printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
+		(unsigned long)
 		percpu_counter_read(&EXT2_SB(sb)->s_freeinodes_counter),
 		desc_count, bitmap_count);
 	return desc_count;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index f663a67..9ba7de0 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -55,7 +55,7 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
  * Methods themselves.
  */
 
-static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
 {
 	struct inode * inode;
 	ino_t ino;
@@ -94,7 +94,7 @@ struct dentry *ext2_get_parent(struct dentry *child)
  * If the create succeeds, we fill in the inode information
  * with d_instantiate(). 
  */
-static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, struct nameidata *nd)
+static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, bool excl)
 {
 	struct inode *inode;
 
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index b3621cb..de2051c 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -204,6 +204,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(ext2_inode_cachep);
 }
 
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 25cd608..90d901f 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -1813,7 +1813,7 @@ ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb)
 	brelse(bitmap_bh);
 	printk("ext3_count_free_blocks: stored = "E3FSBLK
 		", computed = "E3FSBLK", "E3FSBLK"\n",
-	       le32_to_cpu(es->s_free_blocks_count),
+	       (ext3_fsblk_t)le32_to_cpu(es->s_free_blocks_count),
 		desc_count, bitmap_count);
 	return bitmap_count;
 #else
diff --git a/fs/ext3/bitmap.c b/fs/ext3/bitmap.c
index 909d13e..ef9c643 100644
--- a/fs/ext3/bitmap.c
+++ b/fs/ext3/bitmap.c
@@ -11,19 +11,9 @@
 
 #ifdef EXT3FS_DEBUG
 
-static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
-
 unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars)
 {
-	unsigned int i;
-	unsigned long sum = 0;
-
-	if (!map)
-		return (0);
-	for (i = 0; i < numchars; i++)
-		sum += nibblemap[map->b_data[i] & 0xf] +
-			nibblemap[(map->b_data[i] >> 4) & 0xf];
-	return (sum);
+	return numchars * BITS_PER_BYTE - memweight(map->b_data, numchars);
 }
 
 #endif  /*  EXT3FS_DEBUG  */
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index eeb63df..85286db 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1011,7 +1011,7 @@ errout:
 	return NULL;
 }
 
-static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
 {
 	struct inode * inode;
 	struct ext3_dir_entry_2 * de;
@@ -1690,7 +1690,7 @@ static int ext3_add_nondir(handle_t *handle,
  * with d_instantiate().
  */
 static int ext3_create (struct inode * dir, struct dentry * dentry, umode_t mode,
-		struct nameidata *nd)
+		bool excl)
 {
 	handle_t *handle;
 	struct inode * inode;
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 8c3a44b..bd60e08 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -543,6 +543,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(ext3_inode_cachep);
 }
 
diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c
index b319721..ff53d5d 100644
--- a/fs/ext4/bitmap.c
+++ b/fs/ext4/bitmap.c
@@ -13,18 +13,9 @@
 
 #ifdef EXT4FS_DEBUG
 
-static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
-
 unsigned int ext4_count_free(struct buffer_head *map, unsigned int numchars)
 {
-	unsigned int i, sum = 0;
-
-	if (!map)
-		return 0;
-	for (i = 0; i < numchars; i++)
-		sum += nibblemap[map->b_data[i] & 0xf] +
-			nibblemap[(map->b_data[i] >> 4) & 0xf];
-	return sum;
+	return numchars * BITS_PER_BYTE - memweight(map->b_data, numchars);
 }
 
 #endif  /*  EXT4FS_DEBUG  */
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index bb6c7d8..2a1dcea 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -135,14 +135,7 @@ static int ext4_sync_parent(struct inode *inode)
 	inode = igrab(inode);
 	while (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) {
 		ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY);
-		dentry = NULL;
-		spin_lock(&inode->i_lock);
-		if (!list_empty(&inode->i_dentry)) {
-			dentry = list_first_entry(&inode->i_dentry,
-						  struct dentry, d_alias);
-			dget(dentry);
-		}
-		spin_unlock(&inode->i_lock);
+		dentry = d_find_any_alias(inode);
 		if (!dentry)
 			break;
 		next = igrab(dentry->d_parent->d_inode);
@@ -232,7 +225,7 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 
 	if (!journal) {
 		ret = __sync_inode(inode, datasync);
-		if (!ret && !list_empty(&inode->i_dentry))
+		if (!ret && !hlist_empty(&inode->i_dentry))
 			ret = ext4_sync_parent(inode);
 		goto out;
 	}
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 5845cd9..eca3e48 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1312,7 +1312,7 @@ errout:
 	return NULL;
 }
 
-static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	struct inode *inode;
 	struct ext4_dir_entry_2 *de;
@@ -2091,7 +2091,7 @@ static int ext4_add_nondir(handle_t *handle,
  * with d_instantiate().
  */
 static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		       struct nameidata *nd)
+		       bool excl)
 {
 	handle_t *handle;
 	struct inode *inode;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index eb7aa3e..4e2aacb 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1046,6 +1046,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(ext4_inode_cachep);
 }
 
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index a3d81eb..35113bc 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -526,6 +526,11 @@ static int __init fat_init_inodecache(void)
 
 static void __exit fat_destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(fat_inode_cachep);
 }
 
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index c5938c9..70d993a 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -201,7 +201,7 @@ static const struct dentry_operations msdos_dentry_operations = {
 
 /***** Get inode using directory and name */
 static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
-				   struct nameidata *nd)
+				   unsigned int flags)
 {
 	struct super_block *sb = dir->i_sb;
 	struct fat_slot_info sinfo;
@@ -265,7 +265,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name,
 
 /***** Create a file */
 static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-			struct nameidata *nd)
+			bool excl)
 {
 	struct super_block *sb = dir->i_sb;
 	struct inode *inode = NULL;
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index 98ae804..6cc4806 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -41,9 +41,9 @@ static int vfat_revalidate_shortname(struct dentry *dentry)
 	return ret;
 }
 
-static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int vfat_revalidate(struct dentry *dentry, unsigned int flags)
 {
-	if (nd && nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	/* This is not negative dentry. Always valid. */
@@ -52,9 +52,9 @@ static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
 	return vfat_revalidate_shortname(dentry);
 }
 
-static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
+static int vfat_revalidate_ci(struct dentry *dentry, unsigned int flags)
 {
-	if (nd && nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	/*
@@ -74,7 +74,7 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
 	 * This may be nfsd (or something), anyway, we can't see the
 	 * intent of this. So, since this can be for creation, drop it.
 	 */
-	if (!nd)
+	if (!flags)
 		return 0;
 
 	/*
@@ -82,7 +82,7 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
 	 * case sensitive name which is specified by user if this is
 	 * for creation.
 	 */
-	if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
+	if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
 		return 0;
 
 	return vfat_revalidate_shortname(dentry);
@@ -714,7 +714,7 @@ static int vfat_d_anon_disconn(struct dentry *dentry)
 }
 
 static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
-				  struct nameidata *nd)
+				  unsigned int flags)
 {
 	struct super_block *sb = dir->i_sb;
 	struct fat_slot_info sinfo;
@@ -772,7 +772,7 @@ error:
 }
 
 static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		       struct nameidata *nd)
+		       bool excl)
 {
 	struct super_block *sb = dir->i_sb;
 	struct inode *inode;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 81b70e6..887b5ba 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -20,6 +20,7 @@
 #include <linux/signal.h>
 #include <linux/rcupdate.h>
 #include <linux/pid_namespace.h>
+#include <linux/user_namespace.h>
 
 #include <asm/poll.h>
 #include <asm/siginfo.h>
@@ -340,6 +341,31 @@ static int f_getown_ex(struct file *filp, unsigned long arg)
 	return ret;
 }
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+static int f_getowner_uids(struct file *filp, unsigned long arg)
+{
+	struct user_namespace *user_ns = current_user_ns();
+	uid_t * __user dst = (void * __user)arg;
+	uid_t src[2];
+	int err;
+
+	read_lock(&filp->f_owner.lock);
+	src[0] = from_kuid(user_ns, filp->f_owner.uid);
+	src[1] = from_kuid(user_ns, filp->f_owner.euid);
+	read_unlock(&filp->f_owner.lock);
+
+	err  = put_user(src[0], &dst[0]);
+	err |= put_user(src[1], &dst[1]);
+
+	return err;
+}
+#else
+static int f_getowner_uids(struct file *filp, unsigned long arg)
+{
+	return -EINVAL;
+}
+#endif
+
 static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
 		struct file *filp)
 {
@@ -396,6 +422,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
 	case F_SETOWN_EX:
 		err = f_setown_ex(filp, arg);
 		break;
+	case F_GETOWNER_UIDS:
+		err = f_getowner_uids(filp, arg);
+		break;
 	case F_GETSIG:
 		err = filp->f_owner.signum;
 		break;
diff --git a/fs/file_table.c b/fs/file_table.c
index a305d9e..9ace278 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -483,10 +483,8 @@ void mark_files_ro(struct super_block *sb)
 {
 	struct file *f;
 
-retry:
 	lg_global_lock(&files_lglock);
 	do_file_list_for_each_entry(sb, f) {
-		struct vfsmount *mnt;
 		if (!S_ISREG(f->f_path.dentry->d_inode->i_mode))
 		       continue;
 		if (!file_count(f))
@@ -499,12 +497,7 @@ retry:
 		if (file_check_writeable(f) != 0)
 			continue;
 		file_release_write(f);
-		mnt = mntget(f->f_path.mnt);
-		/* This can sleep, so we can't hold the spinlock. */
-		lg_global_unlock(&files_lglock);
-		mnt_drop_write(mnt);
-		mntput(mnt);
-		goto retry;
+		mnt_drop_write_file(f);
 	} while_file_list_for_each_entry;
 	lg_global_unlock(&files_lglock);
 }
diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c
index 3360f1e..bd447e8 100644
--- a/fs/freevxfs/vxfs_lookup.c
+++ b/fs/freevxfs/vxfs_lookup.c
@@ -48,7 +48,7 @@
 #define VXFS_BLOCK_PER_PAGE(sbp)  ((PAGE_CACHE_SIZE / (sbp)->s_blocksize))
 
 
-static struct dentry *	vxfs_lookup(struct inode *, struct dentry *, struct nameidata *);
+static struct dentry *	vxfs_lookup(struct inode *, struct dentry *, unsigned int);
 static int		vxfs_readdir(struct file *, void *, filldir_t);
 
 const struct inode_operations vxfs_dir_inode_ops = {
@@ -203,7 +203,7 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
  *   in the return pointer.
  */
 static struct dentry *
-vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd)
+vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
 {
 	struct inode		*ip = NULL;
 	ino_t			ino;
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index d4fabd2..fed2c8a 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -279,6 +279,11 @@ static void __exit
 vxfs_cleanup(void)
 {
 	unregister_filesystem(&vxfs_fs_type);
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(vxfs_inode_cachep);
 }
 
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 41a3ccf..f2c03ac 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -52,11 +52,6 @@ struct wb_writeback_work {
 	struct completion *done;	/* set if the caller waits */
 };
 
-/*
- * We don't actually have pdflush, but this one is exported though /proc...
- */
-int nr_pdflush_threads;
-
 /**
  * writeback_in_progress - determine whether there is writeback in progress
  * @bdi: the device's backing_dev_info structure.
@@ -628,8 +623,8 @@ static long writeback_sb_inodes(struct super_block *sb,
 		}
 
 		/*
-		 * Don't bother with new inodes or inodes beeing freed, first
-		 * kind does not need peridic writeout yet, and for the latter
+		 * Don't bother with new inodes or inodes being freed, first
+		 * kind does not need periodic writeout yet, and for the latter
 		 * kind writeout is handled by the freer.
 		 */
 		spin_lock(&inode->i_lock);
diff --git a/fs/fs_struct.c b/fs/fs_struct.c
index e159e68..5df4775 100644
--- a/fs/fs_struct.c
+++ b/fs/fs_struct.c
@@ -6,18 +6,6 @@
 #include <linux/fs_struct.h>
 #include "internal.h"
 
-static inline void path_get_longterm(struct path *path)
-{
-	path_get(path);
-	mnt_make_longterm(path->mnt);
-}
-
-static inline void path_put_longterm(struct path *path)
-{
-	mnt_make_shortterm(path->mnt);
-	path_put(path);
-}
-
 /*
  * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
  * It can block.
@@ -26,7 +14,7 @@ void set_fs_root(struct fs_struct *fs, struct path *path)
 {
 	struct path old_root;
 
-	path_get_longterm(path);
+	path_get(path);
 	spin_lock(&fs->lock);
 	write_seqcount_begin(&fs->seq);
 	old_root = fs->root;
@@ -34,7 +22,7 @@ void set_fs_root(struct fs_struct *fs, struct path *path)
 	write_seqcount_end(&fs->seq);
 	spin_unlock(&fs->lock);
 	if (old_root.dentry)
-		path_put_longterm(&old_root);
+		path_put(&old_root);
 }
 
 /*
@@ -45,7 +33,7 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path)
 {
 	struct path old_pwd;
 
-	path_get_longterm(path);
+	path_get(path);
 	spin_lock(&fs->lock);
 	write_seqcount_begin(&fs->seq);
 	old_pwd = fs->pwd;
@@ -54,7 +42,7 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path)
 	spin_unlock(&fs->lock);
 
 	if (old_pwd.dentry)
-		path_put_longterm(&old_pwd);
+		path_put(&old_pwd);
 }
 
 static inline int replace_path(struct path *p, const struct path *old, const struct path *new)
@@ -84,7 +72,7 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root)
 			write_seqcount_end(&fs->seq);
 			while (hits--) {
 				count++;
-				path_get_longterm(new_root);
+				path_get(new_root);
 			}
 			spin_unlock(&fs->lock);
 		}
@@ -92,13 +80,13 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root)
 	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 	while (count--)
-		path_put_longterm(old_root);
+		path_put(old_root);
 }
 
 void free_fs_struct(struct fs_struct *fs)
 {
-	path_put_longterm(&fs->root);
-	path_put_longterm(&fs->pwd);
+	path_put(&fs->root);
+	path_put(&fs->pwd);
 	kmem_cache_free(fs_cachep, fs);
 }
 
@@ -132,9 +120,9 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
 
 		spin_lock(&old->lock);
 		fs->root = old->root;
-		path_get_longterm(&fs->root);
+		path_get(&fs->root);
 		fs->pwd = old->pwd;
-		path_get_longterm(&fs->pwd);
+		path_get(&fs->pwd);
 		spin_unlock(&old->lock);
 	}
 	return fs;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 334e0b1..8964cf3 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -154,7 +154,7 @@ u64 fuse_get_attr_version(struct fuse_conn *fc)
  * the lookup once more.  If the lookup results in the same inode,
  * then refresh the attributes, timeouts and mark the dentry valid.
  */
-static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
+static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
 {
 	struct inode *inode;
 
@@ -174,7 +174,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
 		if (!inode)
 			return 0;
 
-		if (nd && (nd->flags & LOOKUP_RCU))
+		if (flags & LOOKUP_RCU)
 			return -ECHILD;
 
 		fc = get_fuse_conn(inode);
@@ -249,7 +249,7 @@ static struct dentry *fuse_d_add_directory(struct dentry *entry,
 		/* This tries to shrink the subtree below alias */
 		fuse_invalidate_entry(alias);
 		dput(alias);
-		if (!list_empty(&inode->i_dentry))
+		if (!hlist_empty(&inode->i_dentry))
 			return ERR_PTR(-EBUSY);
 	} else {
 		dput(alias);
@@ -316,7 +316,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
 }
 
 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
-				  struct nameidata *nd)
+				  unsigned int flags)
 {
 	int err;
 	struct fuse_entry_out outarg;
@@ -370,7 +370,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
  * 'mknod' + 'open' requests.
  */
 static int fuse_create_open(struct inode *dir, struct dentry *entry,
-			    umode_t mode, struct nameidata *nd)
+			    struct file *file, unsigned flags,
+			    umode_t mode, int *opened)
 {
 	int err;
 	struct inode *inode;
@@ -381,15 +382,11 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
 	struct fuse_open_out outopen;
 	struct fuse_entry_out outentry;
 	struct fuse_file *ff;
-	struct file *file;
-	int flags = nd->intent.open.flags;
-
-	if (fc->no_create)
-		return -ENOSYS;
 
 	forget = fuse_alloc_forget();
+	err = -ENOMEM;
 	if (!forget)
-		return -ENOMEM;
+		goto out_err;
 
 	req = fuse_get_req(fc);
 	err = PTR_ERR(req);
@@ -428,11 +425,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
 	req->out.args[1].value = &outopen;
 	fuse_request_send(fc, req);
 	err = req->out.h.error;
-	if (err) {
-		if (err == -ENOSYS)
-			fc->no_create = 1;
+	if (err)
 		goto out_free_ff;
-	}
 
 	err = -EIO;
 	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
@@ -448,28 +442,74 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
 		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
 		fuse_sync_release(ff, flags);
 		fuse_queue_forget(fc, forget, outentry.nodeid, 1);
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto out_err;
 	}
 	kfree(forget);
 	d_instantiate(entry, inode);
 	fuse_change_entry_timeout(entry, &outentry);
 	fuse_invalidate_attr(dir);
-	file = lookup_instantiate_filp(nd, entry, generic_file_open);
-	if (IS_ERR(file)) {
+	err = finish_open(file, entry, generic_file_open, opened);
+	if (err) {
 		fuse_sync_release(ff, flags);
-		return PTR_ERR(file);
+	} else {
+		file->private_data = fuse_file_get(ff);
+		fuse_finish_open(inode, file);
 	}
-	file->private_data = fuse_file_get(ff);
-	fuse_finish_open(inode, file);
-	return 0;
+	return err;
 
- out_free_ff:
+out_free_ff:
 	fuse_file_free(ff);
- out_put_request:
+out_put_request:
 	fuse_put_request(fc, req);
- out_put_forget_req:
+out_put_forget_req:
 	kfree(forget);
+out_err:
+	return err;
+}
+
+static int fuse_mknod(struct inode *, struct dentry *, umode_t, dev_t);
+static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
+			    struct file *file, unsigned flags,
+			    umode_t mode, int *opened)
+{
+	int err;
+	struct fuse_conn *fc = get_fuse_conn(dir);
+	struct dentry *res = NULL;
+
+	if (d_unhashed(entry)) {
+		res = fuse_lookup(dir, entry, 0);
+		if (IS_ERR(res))
+			return PTR_ERR(res);
+
+		if (res)
+			entry = res;
+	}
+
+	if (!(flags & O_CREAT) || entry->d_inode)
+		goto no_open;
+
+	/* Only creates */
+	*opened |= FILE_CREATED;
+
+	if (fc->no_create)
+		goto mknod;
+
+	err = fuse_create_open(dir, entry, file, flags, mode, opened);
+	if (err == -ENOSYS) {
+		fc->no_create = 1;
+		goto mknod;
+	}
+out_dput:
+	dput(res);
 	return err;
+
+mknod:
+	err = fuse_mknod(dir, entry, mode, 0);
+	if (err)
+		goto out_dput;
+no_open:
+	return finish_no_open(file, res);
 }
 
 /*
@@ -571,14 +611,8 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode,
 }
 
 static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode,
-		       struct nameidata *nd)
+		       bool excl)
 {
-	if (nd) {
-		int err = fuse_create_open(dir, entry, mode, nd);
-		if (err != -ENOSYS)
-			return err;
-		/* Fall back on mknod */
-	}
 	return fuse_mknod(dir, entry, mode, 0);
 }
 
@@ -1646,6 +1680,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
 	.link		= fuse_link,
 	.setattr	= fuse_setattr,
 	.create		= fuse_create,
+	.atomic_open	= fuse_atomic_open,
 	.mknod		= fuse_mknod,
 	.permission	= fuse_permission,
 	.getattr	= fuse_getattr,
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 1cd6165..9078173 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1171,6 +1171,12 @@ static void fuse_fs_cleanup(void)
 {
 	unregister_filesystem(&fuse_fs_type);
 	unregister_fuseblk();
+
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(fuse_inode_cachep);
 }
 
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index e80a464..d652634 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -614,7 +614,6 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
 	unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
 	int alloc_required;
 	int error = 0;
-	struct gfs2_qadata *qa = NULL;
 	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
 	unsigned from = pos & (PAGE_CACHE_SIZE - 1);
 	struct page *page;
@@ -638,15 +637,9 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
 		gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks);
 
 	if (alloc_required) {
-		qa = gfs2_qadata_get(ip);
-		if (!qa) {
-			error = -ENOMEM;
-			goto out_unlock;
-		}
-
 		error = gfs2_quota_lock_check(ip);
 		if (error)
-			goto out_alloc_put;
+			goto out_unlock;
 
 		error = gfs2_inplace_reserve(ip, data_blocks + ind_blocks);
 		if (error)
@@ -708,8 +701,6 @@ out_trans_fail:
 		gfs2_inplace_release(ip);
 out_qunlock:
 		gfs2_quota_unlock(ip);
-out_alloc_put:
-		gfs2_qadata_put(ip);
 	}
 out_unlock:
 	if (&ip->i_inode == sdp->sd_rindex) {
@@ -846,7 +837,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
 	struct gfs2_sbd *sdp = GFS2_SB(inode);
 	struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
 	struct buffer_head *dibh;
-	struct gfs2_qadata *qa = ip->i_qadata;
 	unsigned int from = pos & (PAGE_CACHE_SIZE - 1);
 	unsigned int to = from + len;
 	int ret;
@@ -878,12 +868,10 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
 	brelse(dibh);
 failed:
 	gfs2_trans_end(sdp);
-	if (ip->i_res)
+	if (gfs2_mb_reserved(ip))
 		gfs2_inplace_release(ip);
-	if (qa) {
+	if (ip->i_res->rs_qa_qd_num)
 		gfs2_quota_unlock(ip);
-		gfs2_qadata_put(ip);
-	}
 	if (inode == sdp->sd_rindex) {
 		gfs2_glock_dq(&m_ip->i_gh);
 		gfs2_holder_uninit(&m_ip->i_gh);
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index dab5409..6d957a8 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -1045,12 +1045,13 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
 		lblock = (size - 1) >> sdp->sd_sb.sb_bsize_shift;
 
 	find_metapath(sdp, lblock, &mp, ip->i_height);
-	if (!gfs2_qadata_get(ip))
-		return -ENOMEM;
+	error = gfs2_rindex_update(sdp);
+	if (error)
+		return error;
 
 	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
 	if (error)
-		goto out;
+		return error;
 
 	while (height--) {
 		struct strip_mine sm;
@@ -1064,8 +1065,6 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
 
 	gfs2_quota_unhold(ip);
 
-out:
-	gfs2_qadata_put(ip);
 	return error;
 }
 
@@ -1167,19 +1166,14 @@ static int do_grow(struct inode *inode, u64 size)
 	struct gfs2_inode *ip = GFS2_I(inode);
 	struct gfs2_sbd *sdp = GFS2_SB(inode);
 	struct buffer_head *dibh;
-	struct gfs2_qadata *qa = NULL;
 	int error;
 	int unstuff = 0;
 
 	if (gfs2_is_stuffed(ip) &&
 	    (size > (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)))) {
-		qa = gfs2_qadata_get(ip);
-		if (qa == NULL)
-			return -ENOMEM;
-
 		error = gfs2_quota_lock_check(ip);
 		if (error)
-			goto do_grow_alloc_put;
+			return error;
 
 		error = gfs2_inplace_reserve(ip, 1);
 		if (error)
@@ -1214,8 +1208,6 @@ do_grow_release:
 		gfs2_inplace_release(ip);
 do_grow_qunlock:
 		gfs2_quota_unlock(ip);
-do_grow_alloc_put:
-		gfs2_qadata_put(ip);
 	}
 	return error;
 }
diff --git a/fs/gfs2/dentry.c b/fs/gfs2/dentry.c
index 0da8da2..4fddb3c 100644
--- a/fs/gfs2/dentry.c
+++ b/fs/gfs2/dentry.c
@@ -25,7 +25,7 @@
 /**
  * gfs2_drevalidate - Check directory lookup consistency
  * @dentry: the mapping to check
- * @nd:
+ * @flags: lookup flags
  *
  * Check to make sure the lookup necessary to arrive at this inode from its
  * parent is still good.
@@ -33,7 +33,7 @@
  * Returns: 1 if the dentry is ok, 0 if it isn't
  */
 
-static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
+static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct dentry *parent;
 	struct gfs2_sbd *sdp;
@@ -44,7 +44,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
 	int error;
 	int had_lock = 0;
 
-	if (nd && nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	parent = dget_parent(dentry);
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 8aaeb07..259b088 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -1854,14 +1854,9 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
 	if (!ht)
 		return -ENOMEM;
 
-	if (!gfs2_qadata_get(dip)) {
-		error = -ENOMEM;
-		goto out;
-	}
-
 	error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
 	if (error)
-		goto out_put;
+		goto out;
 
 	/*  Count the number of leaves  */
 	bh = leaf_bh;
@@ -1942,8 +1937,6 @@ out_rg_gunlock:
 out_rlist:
 	gfs2_rlist_free(&rlist);
 	gfs2_quota_unhold(dip);
-out_put:
-	gfs2_qadata_put(dip);
 out:
 	kfree(ht);
 	return error;
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 31b199f..6fbf3cb 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -142,6 +142,7 @@ static const u32 fsflags_to_gfs2[32] = {
 	[7] = GFS2_DIF_NOATIME,
 	[12] = GFS2_DIF_EXHASH,
 	[14] = GFS2_DIF_INHERIT_JDATA,
+	[17] = GFS2_DIF_TOPDIR,
 };
 
 static const u32 gfs2_to_fsflags[32] = {
@@ -150,6 +151,7 @@ static const u32 gfs2_to_fsflags[32] = {
 	[gfs2fl_AppendOnly] = FS_APPEND_FL,
 	[gfs2fl_NoAtime] = FS_NOATIME_FL,
 	[gfs2fl_ExHash] = FS_INDEX_FL,
+	[gfs2fl_TopLevel] = FS_TOPDIR_FL,
 	[gfs2fl_InheritJdata] = FS_JOURNAL_DATA_FL,
 };
 
@@ -203,6 +205,7 @@ void gfs2_set_inode_flags(struct inode *inode)
 			     GFS2_DIF_NOATIME|			\
 			     GFS2_DIF_SYNC|			\
 			     GFS2_DIF_SYSTEM|			\
+			     GFS2_DIF_TOPDIR|			\
 			     GFS2_DIF_INHERIT_JDATA)
 
 /**
@@ -298,6 +301,7 @@ static int gfs2_set_flags(struct file *filp, u32 __user *ptr)
 
 	gfsflags = fsflags_cvt(fsflags_to_gfs2, fsflags);
 	if (!S_ISDIR(inode->i_mode)) {
+		gfsflags &= ~GFS2_DIF_TOPDIR;
 		if (gfsflags & GFS2_DIF_INHERIT_JDATA)
 			gfsflags ^= (GFS2_DIF_JDATA | GFS2_DIF_INHERIT_JDATA);
 		return do_gfs2_set_flags(filp, gfsflags, ~0);
@@ -366,7 +370,6 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 	u64 pos = page->index << PAGE_CACHE_SHIFT;
 	unsigned int data_blocks, ind_blocks, rblocks;
 	struct gfs2_holder gh;
-	struct gfs2_qadata *qa;
 	loff_t size;
 	int ret;
 
@@ -376,6 +379,10 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 	 */
 	vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
 
+	ret = gfs2_rs_alloc(ip);
+	if (ret)
+		return ret;
+
 	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
 	ret = gfs2_glock_nq(&gh);
 	if (ret)
@@ -393,14 +400,13 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 		goto out_unlock;
 	}
 
-	ret = -ENOMEM;
-	qa = gfs2_qadata_get(ip);
-	if (qa == NULL)
+	ret = gfs2_rindex_update(sdp);
+	if (ret)
 		goto out_unlock;
 
 	ret = gfs2_quota_lock_check(ip);
 	if (ret)
-		goto out_alloc_put;
+		goto out_unlock;
 	gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
 	ret = gfs2_inplace_reserve(ip, data_blocks + ind_blocks);
 	if (ret)
@@ -447,8 +453,6 @@ out_trans_fail:
 	gfs2_inplace_release(ip);
 out_quota_unlock:
 	gfs2_quota_unlock(ip);
-out_alloc_put:
-	gfs2_qadata_put(ip);
 out_unlock:
 	gfs2_glock_dq(&gh);
 out:
@@ -569,10 +573,15 @@ static int gfs2_release(struct inode *inode, struct file *file)
 {
 	struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
 	struct gfs2_file *fp;
+	struct gfs2_inode *ip = GFS2_I(inode);
 
 	fp = file->private_data;
 	file->private_data = NULL;
 
+	if ((file->f_mode & FMODE_WRITE) && ip->i_res &&
+	    (atomic_read(&inode->i_writecount) == 1))
+		gfs2_rs_delete(ip);
+
 	if (gfs2_assert_warn(sdp, fp))
 		return -EIO;
 
@@ -653,12 +662,16 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
 				   unsigned long nr_segs, loff_t pos)
 {
 	struct file *file = iocb->ki_filp;
+	struct dentry *dentry = file->f_dentry;
+	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+	int ret;
+
+	ret = gfs2_rs_alloc(ip);
+	if (ret)
+		return ret;
 
 	if (file->f_flags & O_APPEND) {
-		struct dentry *dentry = file->f_dentry;
-		struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
 		struct gfs2_holder gh;
-		int ret;
 
 		ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
 		if (ret)
@@ -751,7 +764,6 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
 	struct gfs2_inode *ip = GFS2_I(inode);
 	unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
 	loff_t bytes, max_bytes;
-	struct gfs2_qadata *qa;
 	int error;
 	const loff_t pos = offset;
 	const loff_t count = len;
@@ -774,6 +786,10 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
 	if (bytes == 0)
 		bytes = sdp->sd_sb.sb_bsize;
 
+	error = gfs2_rs_alloc(ip);
+	if (error)
+		return error;
+
 	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);
 	error = gfs2_glock_nq(&ip->i_gh);
 	if (unlikely(error))
@@ -787,15 +803,13 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
 			offset += bytes;
 			continue;
 		}
-		qa = gfs2_qadata_get(ip);
-		if (!qa) {
-			error = -ENOMEM;
+		error = gfs2_rindex_update(sdp);
+		if (error)
 			goto out_unlock;
-		}
 
 		error = gfs2_quota_lock_check(ip);
 		if (error)
-			goto out_alloc_put;
+			goto out_unlock;
 
 retry:
 		gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks);
@@ -835,7 +849,6 @@ retry:
 		offset += max_bytes;
 		gfs2_inplace_release(ip);
 		gfs2_quota_unlock(ip);
-		gfs2_qadata_put(ip);
 	}
 
 	if (error == 0)
@@ -846,8 +859,6 @@ out_trans_fail:
 	gfs2_inplace_release(ip);
 out_qunlock:
 	gfs2_quota_unlock(ip);
-out_alloc_put:
-	gfs2_qadata_put(ip);
 out_unlock:
 	gfs2_glock_dq(&ip->i_gh);
 out_uninit:
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index dab2526..1ed81f4 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -46,10 +46,11 @@
 #include "trace_gfs2.h"
 
 struct gfs2_glock_iter {
-	int hash;			/* hash bucket index         */
-	struct gfs2_sbd *sdp;		/* incore superblock         */
-	struct gfs2_glock *gl;		/* current glock struct      */
-	char string[512];		/* scratch space             */
+	int hash;			/* hash bucket index           */
+	unsigned nhash;			/* Index within current bucket */
+	struct gfs2_sbd *sdp;		/* incore superblock           */
+	struct gfs2_glock *gl;		/* current glock struct        */
+	loff_t last_pos;		/* last position               */
 };
 
 typedef void (*glock_examiner) (struct gfs2_glock * gl);
@@ -767,6 +768,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
 	gl->gl_stats.stats[GFS2_LKS_DCOUNT] = 0;
 	gl->gl_stats.stats[GFS2_LKS_QCOUNT] = 0;
 	memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb));
+	memset(gl->gl_lvb, 0, 32 * sizeof(char));
 	gl->gl_lksb.sb_lvbptr = gl->gl_lvb;
 	gl->gl_tchange = jiffies;
 	gl->gl_object = NULL;
@@ -948,9 +950,7 @@ void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...)
 	va_start(args, fmt);
 
 	if (seq) {
-		struct gfs2_glock_iter *gi = seq->private;
-		vsprintf(gi->string, fmt, args);
-		seq_printf(seq, gi->string);
+		seq_vprintf(seq, fmt, args);
 	} else {
 		vaf.fmt = fmt;
 		vaf.va = &args;
@@ -1854,8 +1854,14 @@ static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi)
 		gl = gi->gl;
 		if (gl) {
 			gi->gl = glock_hash_next(gl);
+			gi->nhash++;
 		} else {
+			if (gi->hash >= GFS2_GL_HASH_SIZE) {
+				rcu_read_unlock();
+				return 1;
+			}
 			gi->gl = glock_hash_chain(gi->hash);
+			gi->nhash = 0;
 		}
 		while (gi->gl == NULL) {
 			gi->hash++;
@@ -1864,6 +1870,7 @@ static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi)
 				return 1;
 			}
 			gi->gl = glock_hash_chain(gi->hash);
+			gi->nhash = 0;
 		}
 	/* Skip entries for other sb and dead entries */
 	} while (gi->sdp != gi->gl->gl_sbd || atomic_read(&gi->gl->gl_ref) == 0);
@@ -1876,7 +1883,12 @@ static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
 	struct gfs2_glock_iter *gi = seq->private;
 	loff_t n = *pos;
 
-	gi->hash = 0;
+	if (gi->last_pos <= *pos)
+		n = gi->nhash + (*pos - gi->last_pos);
+	else
+		gi->hash = 0;
+
+	gi->nhash = 0;
 	rcu_read_lock();
 
 	do {
@@ -1884,6 +1896,7 @@ static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
 			return NULL;
 	} while (n--);
 
+	gi->last_pos = *pos;
 	return gi->gl;
 }
 
@@ -1893,7 +1906,7 @@ static void *gfs2_glock_seq_next(struct seq_file *seq, void *iter_ptr,
 	struct gfs2_glock_iter *gi = seq->private;
 
 	(*pos)++;
-
+	gi->last_pos = *pos;
 	if (gfs2_glock_iter_next(gi))
 		return NULL;
 
@@ -1964,6 +1977,8 @@ static const struct seq_operations gfs2_sbstats_seq_ops = {
 	.show  = gfs2_sbstats_seq_show,
 };
 
+#define GFS2_SEQ_GOODSIZE min(PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER, 65536UL)
+
 static int gfs2_glocks_open(struct inode *inode, struct file *file)
 {
 	int ret = seq_open_private(file, &gfs2_glock_seq_ops,
@@ -1972,6 +1987,9 @@ static int gfs2_glocks_open(struct inode *inode, struct file *file)
 		struct seq_file *seq = file->private_data;
 		struct gfs2_glock_iter *gi = seq->private;
 		gi->sdp = inode->i_private;
+		seq->buf = kmalloc(GFS2_SEQ_GOODSIZE, GFP_KERNEL | __GFP_NOWARN);
+		if (seq->buf)
+			seq->size = GFS2_SEQ_GOODSIZE;
 	}
 	return ret;
 }
@@ -1984,6 +2002,9 @@ static int gfs2_glstats_open(struct inode *inode, struct file *file)
 		struct seq_file *seq = file->private_data;
 		struct gfs2_glock_iter *gi = seq->private;
 		gi->sdp = inode->i_private;
+		seq->buf = kmalloc(GFS2_SEQ_GOODSIZE, GFP_KERNEL | __GFP_NOWARN);
+		if (seq->buf)
+			seq->size = GFS2_SEQ_GOODSIZE;
 	}
 	return ret;
 }
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 67fd6be..dc73070 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -89,6 +89,7 @@ struct gfs2_rgrpd {
 	u64 rd_igeneration;
 	struct gfs2_bitmap *rd_bits;
 	struct gfs2_sbd *rd_sbd;
+	struct gfs2_rgrp_lvb *rd_rgl;
 	u32 rd_last_alloc;
 	u32 rd_flags;
 #define GFS2_RDF_CHECK		0x10000000 /* check for unlinked inodes */
@@ -289,16 +290,14 @@ struct gfs2_glock {
 
 #define GFS2_MIN_LVB_SIZE 32	/* Min size of LVB that gfs2 supports */
 
-struct gfs2_qadata { /* quota allocation data */
-	/* Quota stuff */
-	struct gfs2_quota_data *qa_qd[2*MAXQUOTAS];
-	struct gfs2_holder qa_qd_ghs[2*MAXQUOTAS];
-	unsigned int qa_qd_num;
-};
-
 struct gfs2_blkreserv {
 	u32 rs_requested; /* Filled in by caller of gfs2_inplace_reserve() */
 	struct gfs2_holder rs_rgd_gh; /* Filled in by gfs2_inplace_reserve() */
+
+	/* ancillary quota stuff */
+	struct gfs2_quota_data *rs_qa_qd[2 * MAXQUOTAS];
+	struct gfs2_holder rs_qa_qd_ghs[2 * MAXQUOTAS];
+	unsigned int rs_qa_qd_num;
 };
 
 enum {
@@ -319,7 +318,6 @@ struct gfs2_inode {
 	struct gfs2_glock *i_gl; /* Move into i_gh? */
 	struct gfs2_holder i_iopen_gh;
 	struct gfs2_holder i_gh; /* for prepare/commit_write only */
-	struct gfs2_qadata *i_qadata; /* quota allocation data */
 	struct gfs2_blkreserv *i_res; /* resource group block reservation */
 	struct gfs2_rgrpd *i_rgd;
 	u64 i_goal;	/* goal block for allocations */
@@ -473,6 +471,7 @@ struct gfs2_args {
 	unsigned int ar_discard:1;		/* discard requests */
 	unsigned int ar_errors:2;               /* errors=withdraw | panic */
 	unsigned int ar_nobarrier:1;            /* do not send barriers */
+	unsigned int ar_rgrplvb:1;		/* use lvbs for rgrp info */
 	int ar_commit;				/* Commit interval */
 	int ar_statfs_quantum;			/* The fast statfs interval */
 	int ar_quota_quantum;			/* The quota interval */
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index a9ba244..b514b4b 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -521,12 +521,10 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
 	int error;
 
 	munge_mode_uid_gid(dip, &mode, &uid, &gid);
-	if (!gfs2_qadata_get(dip))
-		return -ENOMEM;
 
 	error = gfs2_quota_lock(dip, uid, gid);
 	if (error)
-		goto out;
+		return error;
 
 	error = gfs2_quota_check(dip, uid, gid);
 	if (error)
@@ -542,8 +540,6 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
 
 out_quota:
 	gfs2_quota_unlock(dip);
-out:
-	gfs2_qadata_put(dip);
 	return error;
 }
 
@@ -551,15 +547,10 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
 		       struct gfs2_inode *ip)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
-	struct gfs2_qadata *qa;
 	int alloc_required;
 	struct buffer_head *dibh;
 	int error;
 
-	qa = gfs2_qadata_get(dip);
-	if (!qa)
-		return -ENOMEM;
-
 	error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
 	if (error)
 		goto fail;
@@ -611,7 +602,6 @@ fail_quota_locks:
 	gfs2_quota_unlock(dip);
 
 fail:
-	gfs2_qadata_put(dip);
 	return error;
 }
 
@@ -667,6 +657,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 	if (!name->len || name->len > GFS2_FNAMESIZE)
 		return -ENAMETOOLONG;
 
+	error = gfs2_rs_alloc(dip);
+	if (error)
+		return error;
+
 	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
 	if (error)
 		goto fail;
@@ -704,6 +698,11 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 	if (error)
 		goto fail_gunlock2;
 
+	/* the new inode needs a reservation so it can allocate xattrs. */
+	error = gfs2_rs_alloc(GFS2_I(inode));
+	if (error)
+		goto fail_gunlock2;
+
 	error = gfs2_acl_create(dip, inode);
 	if (error)
 		goto fail_gunlock2;
@@ -722,10 +721,9 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 	gfs2_trans_end(sdp);
 	/* Check if we reserved space in the rgrp. Function link_dinode may
 	   not, depending on whether alloc is required. */
-	if (dip->i_res)
+	if (gfs2_mb_reserved(dip))
 		gfs2_inplace_release(dip);
 	gfs2_quota_unlock(dip);
-	gfs2_qadata_put(dip);
 	mark_inode_dirty(inode);
 	gfs2_glock_dq_uninit_m(2, ghs);
 	d_instantiate(dentry, inode);
@@ -755,11 +753,8 @@ fail:
  */
 
 static int gfs2_create(struct inode *dir, struct dentry *dentry,
-		       umode_t mode, struct nameidata *nd)
+		       umode_t mode, bool excl)
 {
-	int excl = 0;
-	if (nd && (nd->flags & LOOKUP_EXCL))
-		excl = 1;
 	return gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0, excl);
 }
 
@@ -775,7 +770,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
  */
 
 static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
-				  struct nameidata *nd)
+				  unsigned int flags)
 {
 	struct inode *inode = gfs2_lookupi(dir, &dentry->d_name, 0);
 	if (inode && !IS_ERR(inode)) {
@@ -819,6 +814,10 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
 	if (S_ISDIR(inode->i_mode))
 		return -EPERM;
 
+	error = gfs2_rs_alloc(dip);
+	if (error)
+		return error;
+
 	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
 	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
 
@@ -870,16 +869,9 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
 	error = 0;
 
 	if (alloc_required) {
-		struct gfs2_qadata *qa = gfs2_qadata_get(dip);
-
-		if (!qa) {
-			error = -ENOMEM;
-			goto out_gunlock;
-		}
-
 		error = gfs2_quota_lock_check(dip);
 		if (error)
-			goto out_alloc;
+			goto out_gunlock;
 
 		error = gfs2_inplace_reserve(dip, sdp->sd_max_dirres);
 		if (error)
@@ -922,9 +914,6 @@ out_ipres:
 out_gunlock_q:
 	if (alloc_required)
 		gfs2_quota_unlock(dip);
-out_alloc:
-	if (alloc_required)
-		gfs2_qadata_put(dip);
 out_gunlock:
 	gfs2_glock_dq(ghs + 1);
 out_child:
@@ -1234,6 +1223,10 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
 	if (error)
 		return error;
 
+	error = gfs2_rs_alloc(ndip);
+	if (error)
+		return error;
+
 	if (odip != ndip) {
 		error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE,
 					   0, &r_gh);
@@ -1357,16 +1350,9 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
 		goto out_gunlock;
 
 	if (alloc_required) {
-		struct gfs2_qadata *qa = gfs2_qadata_get(ndip);
-
-		if (!qa) {
-			error = -ENOMEM;
-			goto out_gunlock;
-		}
-
 		error = gfs2_quota_lock_check(ndip);
 		if (error)
-			goto out_alloc;
+			goto out_gunlock;
 
 		error = gfs2_inplace_reserve(ndip, sdp->sd_max_dirres);
 		if (error)
@@ -1427,9 +1413,6 @@ out_ipreserv:
 out_gunlock_q:
 	if (alloc_required)
 		gfs2_quota_unlock(ndip);
-out_alloc:
-	if (alloc_required)
-		gfs2_qadata_put(ndip);
 out_gunlock:
 	while (x--) {
 		gfs2_glock_dq(ghs + x);
@@ -1590,12 +1573,9 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
 	if (!(attr->ia_valid & ATTR_GID) || ogid == ngid)
 		ogid = ngid = NO_QUOTA_CHANGE;
 
-	if (!gfs2_qadata_get(ip))
-		return -ENOMEM;
-
 	error = gfs2_quota_lock(ip, nuid, ngid);
 	if (error)
-		goto out_alloc;
+		return error;
 
 	if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {
 		error = gfs2_quota_check(ip, nuid, ngid);
@@ -1621,8 +1601,6 @@ out_end_trans:
 	gfs2_trans_end(sdp);
 out_gunlock_q:
 	gfs2_quota_unlock(ip);
-out_alloc:
-	gfs2_qadata_put(ip);
 	return error;
 }
 
@@ -1644,6 +1622,10 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
 	struct gfs2_holder i_gh;
 	int error;
 
+	error = gfs2_rs_alloc(ip);
+	if (error)
+		return error;
+
 	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
 	if (error)
 		return error;
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 852c1be..8ff95a2 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -401,9 +401,14 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
 		goto out;
 	set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
 	set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
-	gfs2_meta_check(sdp, bd->bd_bh);
-	gfs2_pin(sdp, bd->bd_bh);
 	mh = (struct gfs2_meta_header *)bd->bd_bh->b_data;
+	if (unlikely(mh->mh_magic != cpu_to_be32(GFS2_MAGIC))) {
+		printk(KERN_ERR
+		       "Attempting to add uninitialised block to journal (inplace block=%lld)\n",
+		       (unsigned long long)bd->bd_bh->b_blocknr);
+		BUG();
+	}
+	gfs2_pin(sdp, bd->bd_bh);
 	mh->__pad0 = cpu_to_be64(0);
 	mh->mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);
 	sdp->sd_log_num_buf++;
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index 6cdb0f2..e04d0e0 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -43,7 +43,6 @@ static void gfs2_init_inode_once(void *foo)
 	inode_init_once(&ip->i_inode);
 	init_rwsem(&ip->i_rw_mutex);
 	INIT_LIST_HEAD(&ip->i_trunc_list);
-	ip->i_qadata = NULL;
 	ip->i_res = NULL;
 	ip->i_hash_cache = NULL;
 }
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index b8c250f..9b23897 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1118,20 +1118,33 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
 	}
 
 	error = init_names(sdp, silent);
-	if (error)
-		goto fail;
+	if (error) {
+		/* In this case, we haven't initialized sysfs, so we have to
+		   manually free the sdp. */
+		free_percpu(sdp->sd_lkstats);
+		kfree(sdp);
+		sb->s_fs_info = NULL;
+		return error;
+	}
 
 	snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s", sdp->sd_table_name);
 
-	gfs2_create_debugfs_file(sdp);
-
 	error = gfs2_sys_fs_add(sdp);
+	/*
+	 * If we hit an error here, gfs2_sys_fs_add will have called function
+	 * kobject_put which causes the sysfs usage count to go to zero, which
+	 * causes sysfs to call function gfs2_sbd_release, which frees sdp.
+	 * Subsequent error paths here will call gfs2_sys_fs_del, which also
+	 * kobject_put to free sdp.
+	 */
 	if (error)
-		goto fail;
+		return error;
+
+	gfs2_create_debugfs_file(sdp);
 
 	error = gfs2_lm_mount(sdp, silent);
 	if (error)
-		goto fail_sys;
+		goto fail_debug;
 
 	error = init_locking(sdp, &mount_gh, DO);
 	if (error)
@@ -1215,12 +1228,12 @@ fail_locking:
 fail_lm:
 	gfs2_gl_hash_clear(sdp);
 	gfs2_lm_unmount(sdp);
-fail_sys:
-	gfs2_sys_fs_del(sdp);
-fail:
+fail_debug:
 	gfs2_delete_debugfs_file(sdp);
 	free_percpu(sdp->sd_lkstats);
-	kfree(sdp);
+	/* gfs2_sys_fs_del must be the last thing we do, since it causes
+	 * sysfs to call function gfs2_sbd_release, which frees sdp. */
+	gfs2_sys_fs_del(sdp);
 	sb->s_fs_info = NULL;
 	return error;
 }
@@ -1390,10 +1403,9 @@ static void gfs2_kill_sb(struct super_block *sb)
 	sdp->sd_root_dir = NULL;
 	sdp->sd_master_dir = NULL;
 	shrink_dcache_sb(sb);
-	kill_block_super(sb);
 	gfs2_delete_debugfs_file(sdp);
 	free_percpu(sdp->sd_lkstats);
-	kfree(sdp);
+	kill_block_super(sb);
 }
 
 struct file_system_type gfs2_fs_type = {
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index b97178e..7d1ede7 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -494,11 +494,15 @@ static void qdsb_put(struct gfs2_quota_data *qd)
 int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-	struct gfs2_qadata *qa = ip->i_qadata;
-	struct gfs2_quota_data **qd = qa->qa_qd;
+	struct gfs2_quota_data **qd;
 	int error;
 
-	if (gfs2_assert_warn(sdp, !qa->qa_qd_num) ||
+	if (ip->i_res == NULL)
+		gfs2_rs_alloc(ip);
+
+	qd = ip->i_res->rs_qa_qd;
+
+	if (gfs2_assert_warn(sdp, !ip->i_res->rs_qa_qd_num) ||
 	    gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)))
 		return -EIO;
 
@@ -508,20 +512,20 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
 	error = qdsb_get(sdp, QUOTA_USER, ip->i_inode.i_uid, qd);
 	if (error)
 		goto out;
-	qa->qa_qd_num++;
+	ip->i_res->rs_qa_qd_num++;
 	qd++;
 
 	error = qdsb_get(sdp, QUOTA_GROUP, ip->i_inode.i_gid, qd);
 	if (error)
 		goto out;
-	qa->qa_qd_num++;
+	ip->i_res->rs_qa_qd_num++;
 	qd++;
 
 	if (uid != NO_QUOTA_CHANGE && uid != ip->i_inode.i_uid) {
 		error = qdsb_get(sdp, QUOTA_USER, uid, qd);
 		if (error)
 			goto out;
-		qa->qa_qd_num++;
+		ip->i_res->rs_qa_qd_num++;
 		qd++;
 	}
 
@@ -529,7 +533,7 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
 		error = qdsb_get(sdp, QUOTA_GROUP, gid, qd);
 		if (error)
 			goto out;
-		qa->qa_qd_num++;
+		ip->i_res->rs_qa_qd_num++;
 		qd++;
 	}
 
@@ -542,16 +546,17 @@ out:
 void gfs2_quota_unhold(struct gfs2_inode *ip)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-	struct gfs2_qadata *qa = ip->i_qadata;
 	unsigned int x;
 
+	if (ip->i_res == NULL)
+		return;
 	gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags));
 
-	for (x = 0; x < qa->qa_qd_num; x++) {
-		qdsb_put(qa->qa_qd[x]);
-		qa->qa_qd[x] = NULL;
+	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
+		qdsb_put(ip->i_res->rs_qa_qd[x]);
+		ip->i_res->rs_qa_qd[x] = NULL;
 	}
-	qa->qa_qd_num = 0;
+	ip->i_res->rs_qa_qd_num = 0;
 }
 
 static int sort_qd(const void *a, const void *b)
@@ -764,6 +769,10 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
 	unsigned int nalloc = 0, blocks;
 	int error;
 
+	error = gfs2_rs_alloc(ip);
+	if (error)
+		return error;
+
 	gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota),
 			      &data_blocks, &ind_blocks);
 
@@ -915,7 +924,6 @@ fail:
 int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-	struct gfs2_qadata *qa = ip->i_qadata;
 	struct gfs2_quota_data *qd;
 	unsigned int x;
 	int error = 0;
@@ -928,15 +936,15 @@ int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
 	    sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
 		return 0;
 
-	sort(qa->qa_qd, qa->qa_qd_num, sizeof(struct gfs2_quota_data *),
-	     sort_qd, NULL);
+	sort(ip->i_res->rs_qa_qd, ip->i_res->rs_qa_qd_num,
+	     sizeof(struct gfs2_quota_data *), sort_qd, NULL);
 
-	for (x = 0; x < qa->qa_qd_num; x++) {
+	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
 		int force = NO_FORCE;
-		qd = qa->qa_qd[x];
+		qd = ip->i_res->rs_qa_qd[x];
 		if (test_and_clear_bit(QDF_REFRESH, &qd->qd_flags))
 			force = FORCE;
-		error = do_glock(qd, force, &qa->qa_qd_ghs[x]);
+		error = do_glock(qd, force, &ip->i_res->rs_qa_qd_ghs[x]);
 		if (error)
 			break;
 	}
@@ -945,7 +953,7 @@ int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
 		set_bit(GIF_QD_LOCKED, &ip->i_flags);
 	else {
 		while (x--)
-			gfs2_glock_dq_uninit(&qa->qa_qd_ghs[x]);
+			gfs2_glock_dq_uninit(&ip->i_res->rs_qa_qd_ghs[x]);
 		gfs2_quota_unhold(ip);
 	}
 
@@ -990,7 +998,6 @@ static int need_sync(struct gfs2_quota_data *qd)
 
 void gfs2_quota_unlock(struct gfs2_inode *ip)
 {
-	struct gfs2_qadata *qa = ip->i_qadata;
 	struct gfs2_quota_data *qda[4];
 	unsigned int count = 0;
 	unsigned int x;
@@ -998,14 +1005,14 @@ void gfs2_quota_unlock(struct gfs2_inode *ip)
 	if (!test_and_clear_bit(GIF_QD_LOCKED, &ip->i_flags))
 		goto out;
 
-	for (x = 0; x < qa->qa_qd_num; x++) {
+	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
 		struct gfs2_quota_data *qd;
 		int sync;
 
-		qd = qa->qa_qd[x];
+		qd = ip->i_res->rs_qa_qd[x];
 		sync = need_sync(qd);
 
-		gfs2_glock_dq_uninit(&qa->qa_qd_ghs[x]);
+		gfs2_glock_dq_uninit(&ip->i_res->rs_qa_qd_ghs[x]);
 
 		if (sync && qd_trylock(qd))
 			qda[count++] = qd;
@@ -1038,7 +1045,6 @@ static int print_message(struct gfs2_quota_data *qd, char *type)
 int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-	struct gfs2_qadata *qa = ip->i_qadata;
 	struct gfs2_quota_data *qd;
 	s64 value;
 	unsigned int x;
@@ -1050,8 +1056,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
         if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
                 return 0;
 
-	for (x = 0; x < qa->qa_qd_num; x++) {
-		qd = qa->qa_qd[x];
+	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
+		qd = ip->i_res->rs_qa_qd[x];
 
 		if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
 		      (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))))
@@ -1089,7 +1095,6 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
 void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
 		       u32 uid, u32 gid)
 {
-	struct gfs2_qadata *qa = ip->i_qadata;
 	struct gfs2_quota_data *qd;
 	unsigned int x;
 
@@ -1098,8 +1103,8 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
 	if (ip->i_diskflags & GFS2_DIF_SYSTEM)
 		return;
 
-	for (x = 0; x < qa->qa_qd_num; x++) {
-		qd = qa->qa_qd[x];
+	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
+		qd = ip->i_res->rs_qa_qd[x];
 
 		if ((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
 		    (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))) {
@@ -1549,10 +1554,14 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
 	if (error)
 		return error;
 
+	error = gfs2_rs_alloc(ip);
+	if (error)
+		goto out_put;
+
 	mutex_lock(&ip->i_inode.i_mutex);
 	error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_EXCLUSIVE, 0, &q_gh);
 	if (error)
-		goto out_put;
+		goto out_unlockput;
 	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
 	if (error)
 		goto out_q;
@@ -1609,8 +1618,9 @@ out_i:
 	gfs2_glock_dq_uninit(&i_gh);
 out_q:
 	gfs2_glock_dq_uninit(&q_gh);
-out_put:
+out_unlockput:
 	mutex_unlock(&ip->i_inode.i_mutex);
+out_put:
 	qd_put(qd);
 	return error;
 }
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index f74fb9b..e53d0a1 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -417,6 +417,39 @@ void gfs2_free_clones(struct gfs2_rgrpd *rgd)
 	}
 }
 
+/**
+ * gfs2_rs_alloc - make sure we have a reservation assigned to the inode
+ * @ip: the inode for this reservation
+ */
+int gfs2_rs_alloc(struct gfs2_inode *ip)
+{
+	int error = 0;
+
+	down_write(&ip->i_rw_mutex);
+	if (!ip->i_res) {
+		ip->i_res = kmem_cache_zalloc(gfs2_rsrv_cachep, GFP_NOFS);
+		if (!ip->i_res)
+			error = -ENOMEM;
+	}
+	up_write(&ip->i_rw_mutex);
+	return error;
+}
+
+/**
+ * gfs2_rs_delete - delete a reservation
+ * @ip: The inode for this reservation
+ *
+ */
+void gfs2_rs_delete(struct gfs2_inode *ip)
+{
+	down_write(&ip->i_rw_mutex);
+	if (ip->i_res) {
+		kmem_cache_free(gfs2_rsrv_cachep, ip->i_res);
+		ip->i_res = NULL;
+	}
+	up_write(&ip->i_rw_mutex);
+}
+
 void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)
 {
 	struct rb_node *n;
@@ -627,6 +660,7 @@ static int read_rindex_entry(struct gfs2_inode *ip)
 		goto fail;
 
 	rgd->rd_gl->gl_object = rgd;
+	rgd->rd_rgl = (struct gfs2_rgrp_lvb *)rgd->rd_gl->gl_lvb;
 	rgd->rd_flags &= ~GFS2_RDF_UPTODATE;
 	if (rgd->rd_data > sdp->sd_max_rg_data)
 		sdp->sd_max_rg_data = rgd->rd_data;
@@ -736,9 +770,65 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf)
 	memset(&str->rg_reserved, 0, sizeof(str->rg_reserved));
 }
 
+static int gfs2_rgrp_lvb_valid(struct gfs2_rgrpd *rgd)
+{
+	struct gfs2_rgrp_lvb *rgl = rgd->rd_rgl;
+	struct gfs2_rgrp *str = (struct gfs2_rgrp *)rgd->rd_bits[0].bi_bh->b_data;
+
+	if (rgl->rl_flags != str->rg_flags || rgl->rl_free != str->rg_free ||
+	    rgl->rl_dinodes != str->rg_dinodes ||
+	    rgl->rl_igeneration != str->rg_igeneration)
+		return 0;
+	return 1;
+}
+
+static void gfs2_rgrp_ondisk2lvb(struct gfs2_rgrp_lvb *rgl, const void *buf)
+{
+	const struct gfs2_rgrp *str = buf;
+
+	rgl->rl_magic = cpu_to_be32(GFS2_MAGIC);
+	rgl->rl_flags = str->rg_flags;
+	rgl->rl_free = str->rg_free;
+	rgl->rl_dinodes = str->rg_dinodes;
+	rgl->rl_igeneration = str->rg_igeneration;
+	rgl->__pad = 0UL;
+}
+
+static void update_rgrp_lvb_unlinked(struct gfs2_rgrpd *rgd, u32 change)
+{
+	struct gfs2_rgrp_lvb *rgl = rgd->rd_rgl;
+	u32 unlinked = be32_to_cpu(rgl->rl_unlinked) + change;
+	rgl->rl_unlinked = cpu_to_be32(unlinked);
+}
+
+static u32 count_unlinked(struct gfs2_rgrpd *rgd)
+{
+	struct gfs2_bitmap *bi;
+	const u32 length = rgd->rd_length;
+	const u8 *buffer = NULL;
+	u32 i, goal, count = 0;
+
+	for (i = 0, bi = rgd->rd_bits; i < length; i++, bi++) {
+		goal = 0;
+		buffer = bi->bi_bh->b_data + bi->bi_offset;
+		WARN_ON(!buffer_uptodate(bi->bi_bh));
+		while (goal < bi->bi_len * GFS2_NBBY) {
+			goal = gfs2_bitfit(buffer, bi->bi_len, goal,
+					   GFS2_BLKST_UNLINKED);
+			if (goal == BFITNOENT)
+				break;
+			count++;
+			goal++;
+		}
+	}
+
+	return count;
+}
+
+
 /**
- * gfs2_rgrp_go_lock - Read in a RG's header and bitmaps
- * @gh: The glock holder for the resource group
+ * gfs2_rgrp_bh_get - Read in a RG's header and bitmaps
+ * @rgd: the struct gfs2_rgrpd describing the RG to read in
  *
  * Read in all of a Resource Group's header and bitmap blocks.
  * Caller must eventually call gfs2_rgrp_relse() to free the bitmaps.
@@ -746,9 +836,8 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf)
  * Returns: errno
  */
 
-int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
+int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
 {
-	struct gfs2_rgrpd *rgd = gh->gh_gl->gl_object;
 	struct gfs2_sbd *sdp = rgd->rd_sbd;
 	struct gfs2_glock *gl = rgd->rd_gl;
 	unsigned int length = rgd->rd_length;
@@ -756,6 +845,9 @@ int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
 	unsigned int x, y;
 	int error;
 
+	if (rgd->rd_bits[0].bi_bh != NULL)
+		return 0;
+
 	for (x = 0; x < length; x++) {
 		bi = rgd->rd_bits + x;
 		error = gfs2_meta_read(gl, rgd->rd_addr + x, 0, &bi->bi_bh);
@@ -782,7 +874,20 @@ int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
 		rgd->rd_flags |= (GFS2_RDF_UPTODATE | GFS2_RDF_CHECK);
 		rgd->rd_free_clone = rgd->rd_free;
 	}
-
+	if (be32_to_cpu(GFS2_MAGIC) != rgd->rd_rgl->rl_magic) {
+		rgd->rd_rgl->rl_unlinked = cpu_to_be32(count_unlinked(rgd));
+		gfs2_rgrp_ondisk2lvb(rgd->rd_rgl,
+				     rgd->rd_bits[0].bi_bh->b_data);
+	}
+	else if (sdp->sd_args.ar_rgrplvb) {
+		if (!gfs2_rgrp_lvb_valid(rgd)){
+			gfs2_consist_rgrpd(rgd);
+			error = -EIO;
+			goto fail;
+		}
+		if (rgd->rd_rgl->rl_unlinked == 0)
+			rgd->rd_flags &= ~GFS2_RDF_CHECK;
+	}
 	return 0;
 
 fail:
@@ -796,6 +901,39 @@ fail:
 	return error;
 }
 
+int update_rgrp_lvb(struct gfs2_rgrpd *rgd)
+{
+	u32 rl_flags;
+
+	if (rgd->rd_flags & GFS2_RDF_UPTODATE)
+		return 0;
+
+	if (be32_to_cpu(GFS2_MAGIC) != rgd->rd_rgl->rl_magic)
+		return gfs2_rgrp_bh_get(rgd);
+
+	rl_flags = be32_to_cpu(rgd->rd_rgl->rl_flags);
+	rl_flags &= ~GFS2_RDF_MASK;
+	rgd->rd_flags &= GFS2_RDF_MASK;
+	rgd->rd_flags |= (rl_flags | GFS2_RDF_UPTODATE | GFS2_RDF_CHECK);
+	if (rgd->rd_rgl->rl_unlinked == 0)
+		rgd->rd_flags &= ~GFS2_RDF_CHECK;
+	rgd->rd_free = be32_to_cpu(rgd->rd_rgl->rl_free);
+	rgd->rd_free_clone = rgd->rd_free;
+	rgd->rd_dinodes = be32_to_cpu(rgd->rd_rgl->rl_dinodes);
+	rgd->rd_igeneration = be64_to_cpu(rgd->rd_rgl->rl_igeneration);
+	return 0;
+}
+
+int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
+{
+	struct gfs2_rgrpd *rgd = gh->gh_gl->gl_object;
+	struct gfs2_sbd *sdp = rgd->rd_sbd;
+
+	if (gh->gh_flags & GL_SKIP && sdp->sd_args.ar_rgrplvb)
+		return 0;
+	return gfs2_rgrp_bh_get((struct gfs2_rgrpd *)gh->gh_gl->gl_object);
+}
+
 /**
  * gfs2_rgrp_go_unlock - Release RG bitmaps read in with gfs2_rgrp_bh_get()
  * @gh: The glock holder for the resource group
@@ -809,8 +947,10 @@ void gfs2_rgrp_go_unlock(struct gfs2_holder *gh)
 
 	for (x = 0; x < length; x++) {
 		struct gfs2_bitmap *bi = rgd->rd_bits + x;
-		brelse(bi->bi_bh);
-		bi->bi_bh = NULL;
+		if (bi->bi_bh) {
+			brelse(bi->bi_bh);
+			bi->bi_bh = NULL;
+		}
 	}
 
 }
@@ -954,6 +1094,7 @@ int gfs2_fitrim(struct file *filp, void __user *argp)
 				rgd->rd_flags |= GFS2_RGF_TRIMMED;
 				gfs2_trans_add_bh(rgd->rd_gl, bh, 1);
 				gfs2_rgrp_out(rgd, bh->b_data);
+				gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, bh->b_data);
 				gfs2_trans_end(sdp);
 			}
 		}
@@ -974,41 +1115,6 @@ out:
 }
 
 /**
- * gfs2_qadata_get - get the struct gfs2_qadata structure for an inode
- * @ip: the incore GFS2 inode structure
- *
- * Returns: the struct gfs2_qadata
- */
-
-struct gfs2_qadata *gfs2_qadata_get(struct gfs2_inode *ip)
-{
-	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-	int error;
-	BUG_ON(ip->i_qadata != NULL);
-	ip->i_qadata = kzalloc(sizeof(struct gfs2_qadata), GFP_NOFS);
-	error = gfs2_rindex_update(sdp);
-	if (error)
-		fs_warn(sdp, "rindex update returns %d\n", error);
-	return ip->i_qadata;
-}
-
-/**
- * gfs2_blkrsv_get - get the struct gfs2_blkreserv structure for an inode
- * @ip: the incore GFS2 inode structure
- *
- * Returns: the struct gfs2_qadata
- */
-
-static int gfs2_blkrsv_get(struct gfs2_inode *ip)
-{
-	BUG_ON(ip->i_res != NULL);
-	ip->i_res = kmem_cache_zalloc(gfs2_rsrv_cachep, GFP_NOFS);
-	if (!ip->i_res)
-		return -ENOMEM;
-	return 0;
-}
-
-/**
  * try_rgrp_fit - See if a given reservation will fit in a given RG
  * @rgd: the RG data
  * @ip: the inode
@@ -1101,23 +1207,31 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip
 }
 
 /**
- * get_local_rgrp - Choose and lock a rgrp for allocation
+ * gfs2_inplace_reserve - Reserve space in the filesystem
  * @ip: the inode to reserve space for
- * @last_unlinked: the last unlinked block
- *
- * Try to acquire rgrp in way which avoids contending with others.
+ * @requested: the number of blocks to be reserved
  *
  * Returns: errno
  */
 
-static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
+int gfs2_inplace_reserve(struct gfs2_inode *ip, u32 requested)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
 	struct gfs2_rgrpd *rgd, *begin = NULL;
 	struct gfs2_blkreserv *rs = ip->i_res;
-	int error, rg_locked, flags = LM_FLAG_TRY;
+	int error = 0, rg_locked, flags = LM_FLAG_TRY;
+	u64 last_unlinked = NO_BLOCK;
 	int loops = 0;
 
+	if (sdp->sd_args.ar_rgrplvb)
+		flags |= GL_SKIP;
+	rs = ip->i_res;
+	rs->rs_requested = requested;
+	if (gfs2_assert_warn(sdp, requested)) {
+		error = -EINVAL;
+		goto out;
+	}
+
 	if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal))
 		rgd = begin = ip->i_rgd;
 	else
@@ -1135,85 +1249,57 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
 		} else {
 			error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
 						   flags, &rs->rs_rgd_gh);
+			if (!error && sdp->sd_args.ar_rgrplvb) {
+				error = update_rgrp_lvb(rgd);
+				if (error) {
+					gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
+					return error;
+				}
+			}
 		}
 		switch (error) {
 		case 0:
 			if (try_rgrp_fit(rgd, ip)) {
+				if (sdp->sd_args.ar_rgrplvb)
+					gfs2_rgrp_bh_get(rgd);
 				ip->i_rgd = rgd;
 				return 0;
 			}
-			if (rgd->rd_flags & GFS2_RDF_CHECK)
-				try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
+			if (rgd->rd_flags & GFS2_RDF_CHECK) {
+				if (sdp->sd_args.ar_rgrplvb)
+					gfs2_rgrp_bh_get(rgd);
+				try_rgrp_unlink(rgd, &last_unlinked,
+						ip->i_no_addr);
+			}
 			if (!rg_locked)
 				gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
 			/* fall through */
 		case GLR_TRYFAILED:
 			rgd = gfs2_rgrpd_get_next(rgd);
-			if (rgd == begin) {
-				flags = 0;
-				loops++;
-			}
+			if (rgd != begin) /* If we didn't wrap */
+				break;
+
+			flags &= ~LM_FLAG_TRY;
+			loops++;
+			/* Check that fs hasn't grown if writing to rindex */
+			if (ip == GFS2_I(sdp->sd_rindex) &&
+			    !sdp->sd_rindex_uptodate) {
+				error = gfs2_ri_update(ip);
+				if (error)
+					goto out;
+			} else if (loops == 2)
+				/* Flushing the log may release space */
+				gfs2_log_flush(sdp, NULL);
 			break;
 		default:
-			return error;
+			goto out;
 		}
 	}
-
-	return -ENOSPC;
-}
-
-static void gfs2_blkrsv_put(struct gfs2_inode *ip)
-{
-	BUG_ON(ip->i_res == NULL);
-	kmem_cache_free(gfs2_rsrv_cachep, ip->i_res);
-	ip->i_res = NULL;
-}
-
-/**
- * gfs2_inplace_reserve - Reserve space in the filesystem
- * @ip: the inode to reserve space for
- * @requested: the number of blocks to be reserved
- *
- * Returns: errno
- */
-
-int gfs2_inplace_reserve(struct gfs2_inode *ip, u32 requested)
-{
-	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-	struct gfs2_blkreserv *rs;
-	int error;
-	u64 last_unlinked = NO_BLOCK;
-	int tries = 0;
-
-	error = gfs2_blkrsv_get(ip);
-	if (error)
-		return error;
-
-	rs = ip->i_res;
-	rs->rs_requested = requested;
-	if (gfs2_assert_warn(sdp, requested)) {
-		error = -EINVAL;
-		goto out;
-	}
-
-	do {
-		error = get_local_rgrp(ip, &last_unlinked);
-		if (error != -ENOSPC)
-			break;
-		/* Check that fs hasn't grown if writing to rindex */
-		if (ip == GFS2_I(sdp->sd_rindex) && !sdp->sd_rindex_uptodate) {
-			error = gfs2_ri_update(ip);
-			if (error)
-				break;
-			continue;
-		}
-		/* Flushing the log may release space */
-		gfs2_log_flush(sdp, NULL);
-	} while (tries++ < 3);
+	error = -ENOSPC;
 
 out:
 	if (error)
-		gfs2_blkrsv_put(ip);
+		rs->rs_requested = 0;
 	return error;
 }
 
@@ -1230,7 +1316,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
 
 	if (rs->rs_rgd_gh.gh_gl)
 		gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
-	gfs2_blkrsv_put(ip);
+	rs->rs_requested = 0;
 }
 
 /**
@@ -1496,7 +1582,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
 	/* Only happens if there is a bug in gfs2, return something distinctive
 	 * to ensure that it is noticed.
 	 */
-	if (ip->i_res == NULL)
+	if (ip->i_res->rs_requested == 0)
 		return -ECANCELED;
 
 	rgd = ip->i_rgd;
@@ -1542,6 +1628,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
 
 	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
 	gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
+	gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, rgd->rd_bits[0].bi_bh->b_data);
 
 	gfs2_statfs_change(sdp, 0, -(s64)*nblocks, dinode ? 1 : 0);
 	if (dinode)
@@ -1588,6 +1675,7 @@ void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta)
 	rgd->rd_flags &= ~GFS2_RGF_TRIMMED;
 	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
 	gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
+	gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, rgd->rd_bits[0].bi_bh->b_data);
 
 	/* Directories keep their data in the metadata address space */
 	if (meta || ip->i_depth)
@@ -1624,6 +1712,8 @@ void gfs2_unlink_di(struct inode *inode)
 	trace_gfs2_block_alloc(ip, rgd, blkno, 1, GFS2_BLKST_UNLINKED);
 	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
 	gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
+	gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, rgd->rd_bits[0].bi_bh->b_data);
+	update_rgrp_lvb_unlinked(rgd, 1);
 }
 
 static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
@@ -1643,6 +1733,8 @@ static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
 
 	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
 	gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
+	gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, rgd->rd_bits[0].bi_bh->b_data);
+	update_rgrp_lvb_unlinked(rgd, -1);
 
 	gfs2_statfs_change(sdp, 0, +1, -1);
 }
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
index b4b10f4..5d8314d 100644
--- a/fs/gfs2/rgrp.h
+++ b/fs/gfs2/rgrp.h
@@ -29,20 +29,14 @@ extern void gfs2_free_clones(struct gfs2_rgrpd *rgd);
 extern int gfs2_rgrp_go_lock(struct gfs2_holder *gh);
 extern void gfs2_rgrp_go_unlock(struct gfs2_holder *gh);
 
-extern struct gfs2_qadata *gfs2_qadata_get(struct gfs2_inode *ip);
-static inline void gfs2_qadata_put(struct gfs2_inode *ip)
-{
-	BUG_ON(ip->i_qadata == NULL);
-	kfree(ip->i_qadata);
-	ip->i_qadata = NULL;
-}
-
 extern int gfs2_inplace_reserve(struct gfs2_inode *ip, u32 requested);
 extern void gfs2_inplace_release(struct gfs2_inode *ip);
 
 extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n,
 			     bool dinode, u64 *generation);
 
+extern int gfs2_rs_alloc(struct gfs2_inode *ip);
+extern void gfs2_rs_delete(struct gfs2_inode *ip);
 extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta);
 extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
 extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip);
@@ -68,4 +62,12 @@ extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
 				   const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed);
 extern int gfs2_fitrim(struct file *filp, void __user *argp);
 
+/* This is how to tell if a reservation is "inplace" reserved: */
+static inline int gfs2_mb_reserved(struct gfs2_inode *ip)
+{
+	if (ip->i_res && ip->i_res->rs_requested)
+		return 1;
+	return 0;
+}
+
 #endif /* __RGRP_DOT_H__ */
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 713e621..7880687 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -78,6 +78,8 @@ enum {
 	Opt_quota_quantum,
 	Opt_barrier,
 	Opt_nobarrier,
+	Opt_rgrplvb,
+	Opt_norgrplvb,
 	Opt_error,
 };
 
@@ -115,6 +117,8 @@ static const match_table_t tokens = {
 	{Opt_quota_quantum, "quota_quantum=%d"},
 	{Opt_barrier, "barrier"},
 	{Opt_nobarrier, "nobarrier"},
+	{Opt_rgrplvb, "rgrplvb"},
+	{Opt_norgrplvb, "norgrplvb"},
 	{Opt_error, NULL}
 };
 
@@ -267,6 +271,12 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
 		case Opt_nobarrier:
 			args->ar_nobarrier = 1;
 			break;
+		case Opt_rgrplvb:
+			args->ar_rgrplvb = 1;
+			break;
+		case Opt_norgrplvb:
+			args->ar_rgrplvb = 0;
+			break;
 		case Opt_error:
 		default:
 			printk(KERN_WARNING "GFS2: invalid mount option: %s\n", o);
@@ -1379,6 +1389,8 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
 		seq_printf(s, ",nobarrier");
 	if (test_bit(SDF_DEMOTE, &sdp->sd_flags))
 		seq_printf(s, ",demote_interface_used");
+	if (args->ar_rgrplvb)
+		seq_printf(s, ",rgrplvb");
 	return 0;
 }
 
@@ -1399,7 +1411,6 @@ static void gfs2_final_release_pages(struct gfs2_inode *ip)
 static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-	struct gfs2_qadata *qa;
 	struct gfs2_rgrpd *rgd;
 	struct gfs2_holder gh;
 	int error;
@@ -1409,13 +1420,9 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
 		return -EIO;
 	}
 
-	qa = gfs2_qadata_get(ip);
-	if (!qa)
-		return -ENOMEM;
-
 	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
 	if (error)
-		goto out;
+		return error;
 
 	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr, 1);
 	if (!rgd) {
@@ -1443,8 +1450,6 @@ out_rg_gunlock:
 	gfs2_glock_dq_uninit(&gh);
 out_qs:
 	gfs2_quota_unhold(ip);
-out:
-	gfs2_qadata_put(ip);
 	return error;
 }
 
@@ -1554,6 +1559,7 @@ out_unlock:
 out:
 	/* Case 3 starts here */
 	truncate_inode_pages(&inode->i_data, 0);
+	gfs2_rs_delete(ip);
 	clear_inode(inode);
 	gfs2_dir_hash_inval(ip);
 	ip->i_gl->gl_object = NULL;
@@ -1576,6 +1582,7 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb)
 		ip->i_flags = 0;
 		ip->i_gl = NULL;
 		ip->i_rgd = NULL;
+		ip->i_res = NULL;
 	}
 	return &ip->i_inode;
 }
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index 9c2592b..e4bee4b 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -276,7 +276,15 @@ static struct attribute *gfs2_attrs[] = {
 	NULL,
 };
 
+static void gfs2_sbd_release(struct kobject *kobj)
+{
+	struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
+
+	kfree(sdp);
+}
+
 static struct kobj_type gfs2_ktype = {
+	.release = gfs2_sbd_release,
 	.default_attrs = gfs2_attrs,
 	.sysfs_ops     = &gfs2_attr_ops,
 };
@@ -583,6 +591,7 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
 	char ro[20];
 	char spectator[20];
 	char *envp[] = { ro, spectator, NULL };
+	int sysfs_frees_sdp = 0;
 
 	sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0);
 	sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0);
@@ -591,8 +600,10 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
 	error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL,
 				     "%s", sdp->sd_table_name);
 	if (error)
-		goto fail;
+		goto fail_reg;
 
+	sysfs_frees_sdp = 1; /* Freeing sdp is now done by sysfs calling
+				function gfs2_sbd_release. */
 	error = sysfs_create_group(&sdp->sd_kobj, &tune_group);
 	if (error)
 		goto fail_reg;
@@ -615,9 +626,13 @@ fail_lock_module:
 fail_tune:
 	sysfs_remove_group(&sdp->sd_kobj, &tune_group);
 fail_reg:
-	kobject_put(&sdp->sd_kobj);
-fail:
+	free_percpu(sdp->sd_lkstats);
 	fs_err(sdp, "error %d adding sysfs files", error);
+	if (sysfs_frees_sdp)
+		kobject_put(&sdp->sd_kobj);
+	else
+		kfree(sdp);
+	sb->s_fs_info = NULL;
 	return error;
 }
 
diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h
index 125d457..41f42cd 100644
--- a/fs/gfs2/trans.h
+++ b/fs/gfs2/trans.h
@@ -31,7 +31,7 @@ struct gfs2_glock;
 static inline unsigned int gfs2_rg_blocks(const struct gfs2_inode *ip)
 {
 	const struct gfs2_blkreserv *rs = ip->i_res;
-	if (rs->rs_requested < ip->i_rgd->rd_length)
+	if (rs && rs->rs_requested < ip->i_rgd->rd_length)
 		return rs->rs_requested + 1;
 	return ip->i_rgd->rd_length;
 }
diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h
index 3586b0d..8053573 100644
--- a/fs/gfs2/util.h
+++ b/fs/gfs2/util.h
@@ -79,23 +79,19 @@ int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
 		       const char *type, const char *function,
 		       char *file, unsigned int line);
 
-static inline int gfs2_meta_check_i(struct gfs2_sbd *sdp,
-				    struct buffer_head *bh,
-				    const char *function,
-				    char *file, unsigned int line)
+static inline int gfs2_meta_check(struct gfs2_sbd *sdp,
+				    struct buffer_head *bh)
 {
 	struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data;
 	u32 magic = be32_to_cpu(mh->mh_magic);
-	if (unlikely(magic != GFS2_MAGIC))
-		return gfs2_meta_check_ii(sdp, bh, "magic number", function,
-					  file, line);
+	if (unlikely(magic != GFS2_MAGIC)) {
+		printk(KERN_ERR "GFS2: Magic number missing at %llu\n",
+		       (unsigned long long)bh->b_blocknr);
+		return -EIO;
+	}
 	return 0;
 }
 
-#define gfs2_meta_check(sdp, bh) \
-gfs2_meta_check_i((sdp), (bh), __func__, __FILE__, __LINE__)
-
-
 int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
 			   u16 type, u16 t,
 			   const char *function,
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c
index 927f4df..523c0de 100644
--- a/fs/gfs2/xattr.c
+++ b/fs/gfs2/xattr.c
@@ -325,13 +325,8 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
 			       struct gfs2_ea_header *ea,
 			       struct gfs2_ea_header *prev, int leave)
 {
-	struct gfs2_qadata *qa;
 	int error;
 
-	qa = gfs2_qadata_get(ip);
-	if (!qa)
-		return -ENOMEM;
-
 	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
 	if (error)
 		goto out_alloc;
@@ -340,7 +335,6 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
 
 	gfs2_quota_unhold(ip);
 out_alloc:
-	gfs2_qadata_put(ip);
 	return error;
 }
 
@@ -713,17 +707,12 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
 			     unsigned int blks,
 			     ea_skeleton_call_t skeleton_call, void *private)
 {
-	struct gfs2_qadata *qa;
 	struct buffer_head *dibh;
 	int error;
 
-	qa = gfs2_qadata_get(ip);
-	if (!qa)
-		return -ENOMEM;
-
 	error = gfs2_quota_lock_check(ip);
 	if (error)
-		goto out;
+		return error;
 
 	error = gfs2_inplace_reserve(ip, blks);
 	if (error)
@@ -753,8 +742,6 @@ out_ipres:
 	gfs2_inplace_release(ip);
 out_gunlock_q:
 	gfs2_quota_unlock(ip);
-out:
-	gfs2_qadata_put(ip);
 	return error;
 }
 
@@ -1494,16 +1481,11 @@ out_gunlock:
 
 int gfs2_ea_dealloc(struct gfs2_inode *ip)
 {
-	struct gfs2_qadata *qa;
 	int error;
 
-	qa = gfs2_qadata_get(ip);
-	if (!qa)
-		return -ENOMEM;
-
 	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
 	if (error)
-		goto out_alloc;
+		return error;
 
 	error = ea_foreach(ip, ea_dealloc_unstuffed, NULL);
 	if (error)
@@ -1519,8 +1501,6 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip)
 
 out_quota:
 	gfs2_quota_unhold(ip);
-out_alloc:
-	gfs2_qadata_put(ip);
 	return error;
 }
 
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 62fc14e..422dde2 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -18,7 +18,7 @@
  * hfs_lookup()
  */
 static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
-				 struct nameidata *nd)
+				 unsigned int flags)
 {
 	hfs_cat_rec rec;
 	struct hfs_find_data fd;
@@ -187,7 +187,7 @@ static int hfs_dir_release(struct inode *inode, struct file *file)
  * the directory and the name (and its length) of the new file.
  */
 static int hfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		      struct nameidata *nd)
+		      bool excl)
 {
 	struct inode *inode;
 	int res;
diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c
index 2c16316..a67955a 100644
--- a/fs/hfs/extent.c
+++ b/fs/hfs/extent.c
@@ -432,7 +432,7 @@ out:
 		if (inode->i_ino < HFS_FIRSTUSER_CNID)
 			set_bit(HFS_FLG_ALT_MDB_DIRTY, &HFS_SB(sb)->flags);
 		set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
-		sb->s_dirt = 1;
+		hfs_mark_mdb_dirty(sb);
 	}
 	return res;
 
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index 1bf967c..8275175 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -14,6 +14,7 @@
 #include <linux/mutex.h>
 #include <linux/buffer_head.h>
 #include <linux/fs.h>
+#include <linux/workqueue.h>
 
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
@@ -137,16 +138,15 @@ struct hfs_sb_info {
 	gid_t s_gid;				/* The gid of all files */
 
 	int session, part;
-
 	struct nls_table *nls_io, *nls_disk;
-
 	struct mutex bitmap_lock;
-
 	unsigned long flags;
-
 	u16 blockoffset;
-
 	int fs_div;
+	struct super_block *sb;
+	int work_queued;		/* non-zero delayed work is queued */
+	struct delayed_work mdb_work;	/* MDB flush delayed work */
+	spinlock_t work_lock;		/* protects mdb_work and work_queued */
 };
 
 #define HFS_FLG_BITMAP_DIRTY	0
@@ -226,6 +226,9 @@ extern int hfs_compare_dentry(const struct dentry *parent,
 extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *);
 extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *);
 
+/* super.c */
+extern void hfs_mark_mdb_dirty(struct super_block *sb);
+
 extern struct timezone sys_tz;
 
 /*
@@ -253,7 +256,7 @@ static inline const char *hfs_mdb_name(struct super_block *sb)
 static inline void hfs_bitmap_dirty(struct super_block *sb)
 {
 	set_bit(HFS_FLG_BITMAP_DIRTY, &HFS_SB(sb)->flags);
-	sb->s_dirt = 1;
+	hfs_mark_mdb_dirty(sb);
 }
 
 #define sb_bread512(sb, sec, data) ({			\
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 761ec06..ee1bc55 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -220,7 +220,7 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, umode_t mode)
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
 	set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
-	sb->s_dirt = 1;
+	hfs_mark_mdb_dirty(sb);
 
 	return inode;
 }
@@ -235,7 +235,7 @@ void hfs_delete_inode(struct inode *inode)
 		if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID))
 			HFS_SB(sb)->root_dirs--;
 		set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
-		sb->s_dirt = 1;
+		hfs_mark_mdb_dirty(sb);
 		return;
 	}
 	HFS_SB(sb)->file_count--;
@@ -248,7 +248,7 @@ void hfs_delete_inode(struct inode *inode)
 		}
 	}
 	set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
-	sb->s_dirt = 1;
+	hfs_mark_mdb_dirty(sb);
 }
 
 void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext,
@@ -489,7 +489,7 @@ out:
 }
 
 static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
-				      struct nameidata *nd)
+				      unsigned int flags)
 {
 	struct inode *inode = NULL;
 	hfs_cat_rec rec;
@@ -644,13 +644,7 @@ static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end,
 
 	/* sync the superblock to buffers */
 	sb = inode->i_sb;
-	if (sb->s_dirt) {
-		lock_super(sb);
-		sb->s_dirt = 0;
-		if (!(sb->s_flags & MS_RDONLY))
-			hfs_mdb_commit(sb);
-		unlock_super(sb);
-	}
+	flush_delayed_work_sync(&HFS_SB(sb)->mdb_work);
 	/* .. finally sync the buffers to disk */
 	err = sync_blockdev(sb->s_bdev);
 	if (!ret)
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c
index 1563d5c..a5cd355 100644
--- a/fs/hfs/mdb.c
+++ b/fs/hfs/mdb.c
@@ -260,6 +260,12 @@ void hfs_mdb_commit(struct super_block *sb)
 {
 	struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
 
+	if (sb->s_flags & MS_RDONLY)
+		return;
+
+	cancel_delayed_work(&HFS_SB(sb)->mdb_work);
+
+	lock_buffer(HFS_SB(sb)->mdb_bh);
 	if (test_and_clear_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags)) {
 		/* These parameters may have been modified, so write them back */
 		mdb->drLsMod = hfs_mtime();
@@ -283,9 +289,13 @@ void hfs_mdb_commit(struct super_block *sb)
 				     &mdb->drXTFlSize, NULL);
 		hfs_inode_write_fork(HFS_SB(sb)->cat_tree->inode, mdb->drCTExtRec,
 				     &mdb->drCTFlSize, NULL);
+
+		lock_buffer(HFS_SB(sb)->alt_mdb_bh);
 		memcpy(HFS_SB(sb)->alt_mdb, HFS_SB(sb)->mdb, HFS_SECTOR_SIZE);
 		HFS_SB(sb)->alt_mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
 		HFS_SB(sb)->alt_mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
+		unlock_buffer(HFS_SB(sb)->alt_mdb_bh);
+
 		mark_buffer_dirty(HFS_SB(sb)->alt_mdb_bh);
 		sync_dirty_buffer(HFS_SB(sb)->alt_mdb_bh);
 	}
@@ -308,7 +318,11 @@ void hfs_mdb_commit(struct super_block *sb)
 				break;
 			}
 			len = min((int)sb->s_blocksize - off, size);
+
+			lock_buffer(bh);
 			memcpy(bh->b_data + off, ptr, len);
+			unlock_buffer(bh);
+
 			mark_buffer_dirty(bh);
 			brelse(bh);
 			block++;
@@ -317,6 +331,7 @@ void hfs_mdb_commit(struct super_block *sb)
 			size -= len;
 		}
 	}
+	unlock_buffer(HFS_SB(sb)->mdb_bh);
 }
 
 void hfs_mdb_close(struct super_block *sb)
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 7b4c537..941d7a8 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -29,43 +29,9 @@ static struct kmem_cache *hfs_inode_cachep;
 
 MODULE_LICENSE("GPL");
 
-/*
- * hfs_write_super()
- *
- * Description:
- *   This function is called by the VFS only. When the filesystem
- *   is mounted r/w it updates the MDB on disk.
- * Input Variable(s):
- *   struct super_block *sb: Pointer to the hfs superblock
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'sb' points to a "valid" (struct super_block).
- * Postconditions:
- *   The MDB is marked 'unsuccessfully unmounted' by clearing bit 8 of drAtrb
- *   (hfs_put_super() must set this flag!). Some MDB fields are updated
- *   and the MDB buffer is written to disk by calling hfs_mdb_commit().
- */
-static void hfs_write_super(struct super_block *sb)
-{
-	lock_super(sb);
-	sb->s_dirt = 0;
-
-	/* sync everything to the buffers */
-	if (!(sb->s_flags & MS_RDONLY))
-		hfs_mdb_commit(sb);
-	unlock_super(sb);
-}
-
 static int hfs_sync_fs(struct super_block *sb, int wait)
 {
-	lock_super(sb);
 	hfs_mdb_commit(sb);
-	sb->s_dirt = 0;
-	unlock_super(sb);
-
 	return 0;
 }
 
@@ -78,13 +44,44 @@ static int hfs_sync_fs(struct super_block *sb, int wait)
  */
 static void hfs_put_super(struct super_block *sb)
 {
-	if (sb->s_dirt)
-		hfs_write_super(sb);
+	cancel_delayed_work_sync(&HFS_SB(sb)->mdb_work);
 	hfs_mdb_close(sb);
 	/* release the MDB's resources */
 	hfs_mdb_put(sb);
 }
 
+static void flush_mdb(struct work_struct *work)
+{
+	struct hfs_sb_info *sbi;
+	struct super_block *sb;
+
+	sbi = container_of(work, struct hfs_sb_info, mdb_work.work);
+	sb = sbi->sb;
+
+	spin_lock(&sbi->work_lock);
+	sbi->work_queued = 0;
+	spin_unlock(&sbi->work_lock);
+
+	hfs_mdb_commit(sb);
+}
+
+void hfs_mark_mdb_dirty(struct super_block *sb)
+{
+	struct hfs_sb_info *sbi = HFS_SB(sb);
+	unsigned long delay;
+
+	if (sb->s_flags & MS_RDONLY)
+		return;
+
+	spin_lock(&sbi->work_lock);
+	if (!sbi->work_queued) {
+		delay = msecs_to_jiffies(dirty_writeback_interval * 10);
+		queue_delayed_work(system_long_wq, &sbi->mdb_work, delay);
+		sbi->work_queued = 1;
+	}
+	spin_unlock(&sbi->work_lock);
+}
+
 /*
  * hfs_statfs()
  *
@@ -184,7 +181,6 @@ static const struct super_operations hfs_super_operations = {
 	.write_inode	= hfs_write_inode,
 	.evict_inode	= hfs_evict_inode,
 	.put_super	= hfs_put_super,
-	.write_super	= hfs_write_super,
 	.sync_fs	= hfs_sync_fs,
 	.statfs		= hfs_statfs,
 	.remount_fs     = hfs_remount,
@@ -387,7 +383,10 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
 	if (!sbi)
 		return -ENOMEM;
 
+	sbi->sb = sb;
 	sb->s_fs_info = sbi;
+	spin_lock_init(&sbi->work_lock);
+	INIT_DELAYED_WORK(&sbi->mdb_work, flush_mdb);
 
 	res = -EINVAL;
 	if (!parse_options((char *)data, sbi)) {
@@ -483,6 +482,12 @@ static int __init init_hfs_fs(void)
 static void __exit exit_hfs_fs(void)
 {
 	unregister_filesystem(&hfs_fs_type);
+
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(hfs_inode_cachep);
 }
 
diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c
index 19cf291..91b91fd 100644
--- a/fs/hfs/sysdep.c
+++ b/fs/hfs/sysdep.c
@@ -13,12 +13,12 @@
 
 /* dentry case-handling: just lowercase everything */
 
-static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd)
+static int hfs_revalidate_dentry(struct dentry *dentry, unsigned int flags)
 {
 	struct inode *inode;
 	int diff;
 
-	if (nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	inode = dentry->d_inode;
diff --git a/fs/hfsplus/bitmap.c b/fs/hfsplus/bitmap.c
index 1cad80c..4cfbe2e 100644
--- a/fs/hfsplus/bitmap.c
+++ b/fs/hfsplus/bitmap.c
@@ -153,7 +153,7 @@ done:
 	kunmap(page);
 	*max = offset + (curr - pptr) * 32 + i - start;
 	sbi->free_blocks -= *max;
-	sb->s_dirt = 1;
+	hfsplus_mark_mdb_dirty(sb);
 	dprint(DBG_BITMAP, "-> %u,%u\n", start, *max);
 out:
 	mutex_unlock(&sbi->alloc_mutex);
@@ -228,7 +228,7 @@ out:
 	set_page_dirty(page);
 	kunmap(page);
 	sbi->free_blocks += len;
-	sb->s_dirt = 1;
+	hfsplus_mark_mdb_dirty(sb);
 	mutex_unlock(&sbi->alloc_mutex);
 
 	return 0;
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 26b53fb..6b9f921 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -25,7 +25,7 @@ static inline void hfsplus_instantiate(struct dentry *dentry,
 
 /* Find the entry inside dir named dentry->d_name */
 static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
-				     struct nameidata *nd)
+				     unsigned int flags)
 {
 	struct inode *inode = NULL;
 	struct hfs_find_data fd;
@@ -316,7 +316,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
 	inode->i_ctime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
 	sbi->file_count++;
-	dst_dir->i_sb->s_dirt = 1;
+	hfsplus_mark_mdb_dirty(dst_dir->i_sb);
 out:
 	mutex_unlock(&sbi->vh_mutex);
 	return res;
@@ -465,7 +465,7 @@ out:
 }
 
 static int hfsplus_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-			  struct nameidata *nd)
+			  bool excl)
 {
 	return hfsplus_mknod(dir, dentry, mode, 0);
 }
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 4e75ac6..558dbb4 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -153,8 +153,11 @@ struct hfsplus_sb_info {
 	gid_t gid;
 
 	int part, session;
-
 	unsigned long flags;
+
+	int work_queued;               /* non-zero delayed work is queued */
+	struct delayed_work sync_work; /* FS sync delayed work */
+	spinlock_t work_lock;          /* protects sync_work and work_queued */
 };
 
 #define HFSPLUS_SB_WRITEBACKUP	0
@@ -428,7 +431,7 @@ int hfsplus_show_options(struct seq_file *, struct dentry *);
 
 /* super.c */
 struct inode *hfsplus_iget(struct super_block *, unsigned long);
-int hfsplus_sync_fs(struct super_block *sb, int wait);
+void hfsplus_mark_mdb_dirty(struct super_block *sb);
 
 /* tables.c */
 extern u16 hfsplus_case_fold_table[];
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 82b69ee..3d8b4a6 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -168,7 +168,7 @@ const struct dentry_operations hfsplus_dentry_operations = {
 };
 
 static struct dentry *hfsplus_file_lookup(struct inode *dir,
-		struct dentry *dentry, struct nameidata *nd)
+		struct dentry *dentry, unsigned int flags)
 {
 	struct hfs_find_data fd;
 	struct super_block *sb = dir->i_sb;
@@ -431,7 +431,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
 		sbi->file_count++;
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
-	sb->s_dirt = 1;
+	hfsplus_mark_mdb_dirty(sb);
 
 	return inode;
 }
@@ -442,7 +442,7 @@ void hfsplus_delete_inode(struct inode *inode)
 
 	if (S_ISDIR(inode->i_mode)) {
 		HFSPLUS_SB(sb)->folder_count--;
-		sb->s_dirt = 1;
+		hfsplus_mark_mdb_dirty(sb);
 		return;
 	}
 	HFSPLUS_SB(sb)->file_count--;
@@ -455,7 +455,7 @@ void hfsplus_delete_inode(struct inode *inode)
 		inode->i_size = 0;
 		hfsplus_file_truncate(inode);
 	}
-	sb->s_dirt = 1;
+	hfsplus_mark_mdb_dirty(sb);
 }
 
 void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index a9bca4b..86fcbf5 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -124,7 +124,7 @@ static int hfsplus_system_write_inode(struct inode *inode)
 
 	if (fork->total_size != cpu_to_be64(inode->i_size)) {
 		set_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags);
-		inode->i_sb->s_dirt = 1;
+		hfsplus_mark_mdb_dirty(inode->i_sb);
 	}
 	hfsplus_inode_write_fork(inode, fork);
 	if (tree)
@@ -161,7 +161,7 @@ static void hfsplus_evict_inode(struct inode *inode)
 	}
 }
 
-int hfsplus_sync_fs(struct super_block *sb, int wait)
+static int hfsplus_sync_fs(struct super_block *sb, int wait)
 {
 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
 	struct hfsplus_vh *vhdr = sbi->s_vhdr;
@@ -171,9 +171,9 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
 	if (!wait)
 		return 0;
 
-	dprint(DBG_SUPER, "hfsplus_write_super\n");
+	dprint(DBG_SUPER, "hfsplus_sync_fs\n");
 
-	sb->s_dirt = 0;
+	cancel_delayed_work(&sbi->sync_work);
 
 	/*
 	 * Explicitly write out the special metadata inodes.
@@ -226,12 +226,34 @@ out:
 	return error;
 }
 
-static void hfsplus_write_super(struct super_block *sb)
+static void delayed_sync_fs(struct work_struct *work)
 {
-	if (!(sb->s_flags & MS_RDONLY))
-		hfsplus_sync_fs(sb, 1);
-	else
-		sb->s_dirt = 0;
+	struct hfsplus_sb_info *sbi;
+
+	sbi = container_of(work, struct hfsplus_sb_info, sync_work.work);
+
+	spin_lock(&sbi->work_lock);
+	sbi->work_queued = 0;
+	spin_unlock(&sbi->work_lock);
+
+	hfsplus_sync_fs(sbi->alloc_file->i_sb, 1);
+}
+
+void hfsplus_mark_mdb_dirty(struct super_block *sb)
+{
+	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
+	unsigned long delay;
+
+	if (sb->s_flags & MS_RDONLY)
+		return;
+
+	spin_lock(&sbi->work_lock);
+	if (!sbi->work_queued) {
+		delay = msecs_to_jiffies(dirty_writeback_interval * 10);
+		queue_delayed_work(system_long_wq, &sbi->sync_work, delay);
+		sbi->work_queued = 1;
+	}
+	spin_unlock(&sbi->work_lock);
 }
 
 static void hfsplus_put_super(struct super_block *sb)
@@ -240,8 +262,7 @@ static void hfsplus_put_super(struct super_block *sb)
 
 	dprint(DBG_SUPER, "hfsplus_put_super\n");
 
-	if (!sb->s_fs_info)
-		return;
+	cancel_delayed_work_sync(&sbi->sync_work);
 
 	if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
 		struct hfsplus_vh *vhdr = sbi->s_vhdr;
@@ -328,7 +349,6 @@ static const struct super_operations hfsplus_sops = {
 	.write_inode	= hfsplus_write_inode,
 	.evict_inode	= hfsplus_evict_inode,
 	.put_super	= hfsplus_put_super,
-	.write_super	= hfsplus_write_super,
 	.sync_fs	= hfsplus_sync_fs,
 	.statfs		= hfsplus_statfs,
 	.remount_fs	= hfsplus_remount,
@@ -347,7 +367,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
 	u64 last_fs_block, last_fs_page;
 	int err;
 
-	err = -EINVAL;
+	err = -ENOMEM;
 	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
 	if (!sbi)
 		goto out;
@@ -355,6 +375,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_fs_info = sbi;
 	mutex_init(&sbi->alloc_mutex);
 	mutex_init(&sbi->vh_mutex);
+	spin_lock_init(&sbi->work_lock);
+	INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs);
 	hfsplus_fill_defaults(sbi);
 
 	err = -EINVAL;
@@ -615,6 +637,12 @@ static int __init init_hfsplus_fs(void)
 static void __exit exit_hfsplus_fs(void)
 {
 	unregister_filesystem(&hfsplus_fs_type);
+
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(hfsplus_inode_cachep);
 }
 
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 2afa5bb..1241465 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -553,7 +553,7 @@ static int read_name(struct inode *ino, char *name)
 }
 
 int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		  struct nameidata *nd)
+		  bool excl)
 {
 	struct inode *inode;
 	char *name;
@@ -595,7 +595,7 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 }
 
 struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
-			     struct nameidata *nd)
+			     unsigned int flags)
 {
 	struct inode *inode;
 	char *name;
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index b8472f8..78e12b2 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -189,7 +189,7 @@ out:
  *	      to tell read_inode to read fnode or not.
  */
 
-struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	const unsigned char *name = dentry->d_name.name;
 	unsigned len = dentry->d_name.len;
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index c07ef1f..ac1ead1 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -220,7 +220,7 @@ extern const struct dentry_operations hpfs_dentry_operations;
 
 /* dir.c */
 
-struct dentry *hpfs_lookup(struct inode *, struct dentry *, struct nameidata *);
+struct dentry *hpfs_lookup(struct inode *, struct dentry *, unsigned int);
 extern const struct file_operations hpfs_dir_ops;
 
 /* dnode.c */
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 9083ef8..bc90824 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -115,7 +115,7 @@ bail:
 	return err;
 }
 
-static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd)
+static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
 {
 	const unsigned char *name = dentry->d_name.name;
 	unsigned len = dentry->d_name.len;
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 706a12c..3cb1da5 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -210,6 +210,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(hpfs_inode_cachep);
 }
 
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index d4f93b5..e5c0653 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -138,7 +138,7 @@ static int file_removed(struct dentry *dentry, const char *file)
 }
 
 static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
-				   struct nameidata *nd)
+				   unsigned int flags)
 {
 	struct dentry *proc_dentry, *parent;
 	struct qstr *name = &dentry->d_name;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index cc9281b..c4b85d0 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -416,8 +416,8 @@ hugetlb_vmtruncate_list(struct prio_tree_root *root, pgoff_t pgoff)
 		else
 			v_offset = 0;
 
-		__unmap_hugepage_range(vma,
-				vma->vm_start + v_offset, vma->vm_end, NULL);
+		unmap_hugepage_range(vma, vma->vm_start + v_offset,
+				     vma->vm_end, NULL);
 	}
 }
 
@@ -565,7 +565,7 @@ static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mod
 	return retval;
 }
 
-static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd)
+static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
 {
 	return hugetlbfs_mknod(dir, dentry, mode | S_IFREG, 0);
 }
@@ -1042,6 +1042,11 @@ static int __init init_hugetlbfs_fs(void)
 
 static void __exit exit_hugetlbfs_fs(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(hugetlbfs_inode_cachep);
 	kern_unmount(hugetlbfs_vfsmount);
 	unregister_filesystem(&hugetlbfs_fs_type);
diff --git a/fs/inode.c b/fs/inode.c
index c99163b..775cbab 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -182,7 +182,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
 	}
 	inode->i_private = NULL;
 	inode->i_mapping = mapping;
-	INIT_LIST_HEAD(&inode->i_dentry);	/* buggered by rcu freeing */
+	INIT_HLIST_HEAD(&inode->i_dentry);	/* buggered by rcu freeing */
 #ifdef CONFIG_FS_POSIX_ACL
 	inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED;
 #endif
diff --git a/fs/internal.h b/fs/internal.h
index 18bc216..8a9f5fa 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -50,8 +50,6 @@ extern int copy_mount_string(const void __user *, char **);
 extern struct vfsmount *lookup_mnt(struct path *);
 extern int finish_automount(struct vfsmount *, struct path *);
 
-extern void mnt_make_longterm(struct vfsmount *);
-extern void mnt_make_shortterm(struct vfsmount *);
 extern int sb_prepare_remount_readonly(struct super_block *);
 
 extern void __init mnt_init(void);
@@ -84,9 +82,6 @@ extern struct super_block *user_get_super(dev_t);
 /*
  * open.c
  */
-struct nameidata;
-extern struct file *nameidata_to_filp(struct nameidata *);
-extern void release_open_intent(struct nameidata *);
 struct open_flags {
 	int open_flag;
 	umode_t mode;
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 29037c3..f94cde4 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -114,6 +114,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(isofs_inode_cachep);
 }
 
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h
index 0e73f63..3620ad1 100644
--- a/fs/isofs/isofs.h
+++ b/fs/isofs/isofs.h
@@ -114,7 +114,7 @@ extern int isofs_name_translate(struct iso_directory_record *, char *, struct in
 int get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *);
 int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
 
-extern struct dentry *isofs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct dentry *isofs_lookup(struct inode *, struct dentry *, unsigned int flags);
 extern struct buffer_head *isofs_bread(struct inode *, sector_t);
 extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
 
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 1e2946f..c167028 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -163,7 +163,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
 	return 0;
 }
 
-struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	int found;
 	unsigned long uninitialized_var(block);
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 216f429..af5280f 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -349,12 +349,12 @@ static void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag,
 		return;
 
 	sequence = cpu_to_be32(sequence);
-	addr = kmap_atomic(page, KM_USER0);
+	addr = kmap_atomic(page);
 	csum = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence,
 			  sizeof(sequence));
 	csum = jbd2_chksum(j, csum, addr + offset_in_page(bh->b_data),
 			  bh->b_size);
-	kunmap_atomic(addr, KM_USER0);
+	kunmap_atomic(addr);
 
 	tag->t_checksum = cpu_to_be32(csum);
 }
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index b560188..2324519 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -25,9 +25,9 @@
 static int jffs2_readdir (struct file *, void *, filldir_t);
 
 static int jffs2_create (struct inode *,struct dentry *,umode_t,
-			 struct nameidata *);
+			 bool);
 static struct dentry *jffs2_lookup (struct inode *,struct dentry *,
-				    struct nameidata *);
+				    unsigned int);
 static int jffs2_link (struct dentry *,struct inode *,struct dentry *);
 static int jffs2_unlink (struct inode *,struct dentry *);
 static int jffs2_symlink (struct inode *,struct dentry *,const char *);
@@ -74,7 +74,7 @@ const struct inode_operations jffs2_dir_inode_operations =
    nice and simple
 */
 static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
-				   struct nameidata *nd)
+				   unsigned int flags)
 {
 	struct jffs2_inode_info *dir_f;
 	struct jffs2_full_dirent *fd = NULL, *fd_list;
@@ -175,7 +175,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
 
 static int jffs2_create(struct inode *dir_i, struct dentry *dentry,
-			umode_t mode, struct nameidata *nd)
+			umode_t mode, bool excl)
 {
 	struct jffs2_raw_inode *ri;
 	struct jffs2_inode_info *f, *dir_f;
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 61ea413..ff48795 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -418,6 +418,12 @@ static void __exit exit_jffs2_fs(void)
 	unregister_filesystem(&jffs2_fs_type);
 	jffs2_destroy_slab_caches();
 	jffs2_compressors_exit();
+
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(jffs2_inode_cachep);
 }
 
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 07c91ca..c426293 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -73,7 +73,7 @@ static inline void free_ea_wmap(struct inode *inode)
  *
  */
 static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,
-		struct nameidata *nd)
+		bool excl)
 {
 	int rc = 0;
 	tid_t tid;		/* transaction id */
@@ -1436,7 +1436,7 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
 	return rc;
 }
 
-static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags)
 {
 	struct btstack btstack;
 	ino_t inum;
@@ -1570,7 +1570,7 @@ out:
 	return result;
 }
 
-static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int jfs_ci_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	/*
 	 * This is not negative dentry. Always valid.
@@ -1589,7 +1589,7 @@ static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd)
 	 * This may be nfsd (or something), anyway, we can't see the
 	 * intent of this. So, since this can be for creation, drop it.
 	 */
-	if (!nd)
+	if (!flags)
 		return 0;
 
 	/*
@@ -1597,7 +1597,7 @@ static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd)
 	 * case sensitive name which is specified by user if this is
 	 * for creation.
 	 */
-	if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
+	if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
 		return 0;
 	return 1;
 }
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 4a82950..2fc7602 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -898,6 +898,12 @@ static void __exit exit_jfs_fs(void)
 	jfs_proc_clean();
 #endif
 	unregister_filesystem(&jfs_fs_type);
+
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(jfs_inode_cachep);
 }
 
diff --git a/fs/libfs.c b/fs/libfs.c
index f86ec27..ebd03f6 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -53,7 +53,7 @@ static int simple_delete_dentry(const struct dentry *dentry)
  * Lookup the data. This is trivial - if the dentry didn't already
  * exist, we know it is negative.  Set d_op to delete negative dentries.
  */
-struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	static const struct dentry_operations simple_dentry_operations = {
 		.d_delete = simple_delete_dentry,
diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c
index df0de27..ea29df3 100644
--- a/fs/logfs/dev_bdev.c
+++ b/fs/logfs/dev_bdev.c
@@ -26,6 +26,7 @@ static int sync_request(struct page *page, struct block_device *bdev, int rw)
 	struct completion complete;
 
 	bio_init(&bio);
+	bio.bi_max_vecs = 1;
 	bio.bi_io_vec = &bio_vec;
 	bio_vec.bv_page = page;
 	bio_vec.bv_len = PAGE_SIZE;
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c
index bea5d1b..26e4a94 100644
--- a/fs/logfs/dir.c
+++ b/fs/logfs/dir.c
@@ -349,7 +349,7 @@ static void logfs_set_name(struct logfs_disk_dentry *dd, struct qstr *name)
 }
 
 static struct dentry *logfs_lookup(struct inode *dir, struct dentry *dentry,
-		struct nameidata *nd)
+		unsigned int flags)
 {
 	struct page *page;
 	struct logfs_disk_dentry *dd;
@@ -502,7 +502,7 @@ static int logfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 }
 
 static int logfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		struct nameidata *nd)
+		bool excl)
 {
 	struct inode *inode;
 
diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c
index a422f42..513c892 100644
--- a/fs/logfs/inode.c
+++ b/fs/logfs/inode.c
@@ -156,10 +156,26 @@ static void __logfs_destroy_inode(struct inode *inode)
 	call_rcu(&inode->i_rcu, logfs_i_callback);
 }
 
+static void __logfs_destroy_meta_inode(struct inode *inode)
+{
+	struct logfs_inode *li = logfs_inode(inode);
+	BUG_ON(li->li_block);
+	call_rcu(&inode->i_rcu, logfs_i_callback);
+}
+
 static void logfs_destroy_inode(struct inode *inode)
 {
 	struct logfs_inode *li = logfs_inode(inode);
 
+	if (inode->i_ino < LOGFS_RESERVED_INOS) {
+		/*
+		 * The reserved inodes are never destroyed unless we are in
+		 * unmont path.
+		 */
+		__logfs_destroy_meta_inode(inode);
+		return;
+	}
+
 	BUG_ON(list_empty(&li->li_freeing_list));
 	spin_lock(&logfs_inode_lock);
 	li->li_refcount--;
@@ -401,5 +417,10 @@ int logfs_init_inode_cache(void)
 
 void logfs_destroy_inode_cache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(logfs_inode_cache);
 }
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c
index f1cb512..5be0abe 100644
--- a/fs/logfs/readwrite.c
+++ b/fs/logfs/readwrite.c
@@ -2189,7 +2189,6 @@ void logfs_evict_inode(struct inode *inode)
 		return;
 	}
 
-	BUG_ON(inode->i_ino < LOGFS_RESERVED_INOS);
 	page = inode_to_page(inode);
 	BUG_ON(!page); /* FIXME: Use emergency page */
 	logfs_put_write_page(page);
diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c
index e28d090..038da09 100644
--- a/fs/logfs/segment.c
+++ b/fs/logfs/segment.c
@@ -886,7 +886,7 @@ static struct logfs_area *alloc_area(struct super_block *sb)
 
 static void map_invalidatepage(struct page *page, unsigned long l)
 {
-	BUG();
+	return;
 }
 
 static int map_releasepage(struct page *page, gfp_t g)
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 2a503ad..dc8d362 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -100,6 +100,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(minix_inode_cachep);
 }
 
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 2d0ee17..0db73d9 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -18,7 +18,7 @@ static int add_nondir(struct dentry *dentry, struct inode *inode)
 	return err;
 }
 
-static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
 {
 	struct inode * inode = NULL;
 	ino_t ino;
@@ -55,7 +55,7 @@ static int minix_mknod(struct inode * dir, struct dentry *dentry, umode_t mode,
 }
 
 static int minix_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		struct nameidata *nd)
+		bool excl)
 {
 	return minix_mknod(dir, dentry, mode, 0);
 }
diff --git a/fs/mount.h b/fs/mount.h
index 4ef36d9..4f291f9 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -22,7 +22,6 @@ struct mount {
 	struct vfsmount mnt;
 #ifdef CONFIG_SMP
 	struct mnt_pcp __percpu *mnt_pcp;
-	atomic_t mnt_longterm;		/* how many of the refs are longterm */
 #else
 	int mnt_count;
 	int mnt_writers;
@@ -49,6 +48,8 @@ struct mount {
 	int mnt_ghosts;
 };
 
+#define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */
+
 static inline struct mount *real_mount(struct vfsmount *mnt)
 {
 	return container_of(mnt, struct mount, mnt);
@@ -59,6 +60,12 @@ static inline int mnt_has_parent(struct mount *mnt)
 	return mnt != mnt->mnt_parent;
 }
 
+static inline int is_mounted(struct vfsmount *mnt)
+{
+	/* neither detached nor internal? */
+	return !IS_ERR_OR_NULL(real_mount(mnt));
+}
+
 extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *, int);
 
 static inline void get_mnt_ns(struct mnt_namespace *ns)
@@ -67,10 +74,12 @@ static inline void get_mnt_ns(struct mnt_namespace *ns)
 }
 
 struct proc_mounts {
-	struct seq_file m; /* must be the first element */
+	struct seq_file m;
 	struct mnt_namespace *ns;
 	struct path root;
 	int (*show)(struct seq_file *, struct vfsmount *);
 };
 
+#define proc_mounts(p) (container_of((p), struct proc_mounts, m))
+
 extern const struct seq_operations mounts_op;
diff --git a/fs/namei.c b/fs/namei.c
index 7d69419..100d589 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -463,25 +463,9 @@ err_root:
 	return -ECHILD;
 }
 
-/**
- * release_open_intent - free up open intent resources
- * @nd: pointer to nameidata
- */
-void release_open_intent(struct nameidata *nd)
+static inline int d_revalidate(struct dentry *dentry, unsigned int flags)
 {
-	struct file *file = nd->intent.open.file;
-
-	if (file && !IS_ERR(file)) {
-		if (file->f_path.dentry == NULL)
-			put_filp(file);
-		else
-			fput(file);
-	}
-}
-
-static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd)
-{
-	return dentry->d_op->d_revalidate(dentry, nd);
+	return dentry->d_op->d_revalidate(dentry, flags);
 }
 
 /**
@@ -527,7 +511,7 @@ static int complete_walk(struct nameidata *nd)
 		return 0;
 
 	/* Note: we do not d_invalidate() */
-	status = d_revalidate(dentry, nd);
+	status = d_revalidate(dentry, nd->flags);
 	if (status > 0)
 		return 0;
 
@@ -602,30 +586,179 @@ static inline void path_to_nameidata(const struct path *path,
 	nd->path.dentry = path->dentry;
 }
 
+/*
+ * Helper to directly jump to a known parsed path from ->follow_link,
+ * caller must have taken a reference to path beforehand.
+ */
+void nd_jump_link(struct nameidata *nd, struct path *path)
+{
+	path_put(&nd->path);
+
+	nd->path = *path;
+	nd->inode = nd->path.dentry->d_inode;
+	nd->flags |= LOOKUP_JUMPED;
+
+	BUG_ON(nd->inode->i_op->follow_link);
+}
+
 static inline void put_link(struct nameidata *nd, struct path *link, void *cookie)
 {
 	struct inode *inode = link->dentry->d_inode;
-	if (!IS_ERR(cookie) && inode->i_op->put_link)
+	if (inode->i_op->put_link)
 		inode->i_op->put_link(link->dentry, nd, cookie);
 	path_put(link);
 }
 
+#ifdef CONFIG_PROTECTED_LINKS
+int sysctl_protected_symlinks __read_mostly =
+	CONFIG_PROTECTED_SYMLINKS_SYSCTL;
+int sysctl_protected_hardlinks __read_mostly =
+	CONFIG_PROTECTED_HARDLINKS_SYSCTL;
+
+/**
+ * may_follow_link - Check symlink following for unsafe situations
+ * @link: The path of the symlink
+ *
+ * In the case of the sysctl_protected_symlinks sysctl being enabled,
+ * CAP_DAC_OVERRIDE needs to be specifically ignored if the symlink is
+ * in a sticky world-writable directory. This is to protect privileged
+ * processes from failing races against path names that may change out
+ * from under them by way of other users creating malicious symlinks.
+ * It will permit symlinks to be followed only when outside a sticky
+ * world-writable directory, or when the uid of the symlink and follower
+ * match, or when the directory owner matches the symlink's owner.
+ *
+ * Returns 0 if following the symlink is allowed, -ve on error.
+ */
+static inline int may_follow_link(struct path *link)
+{
+	int error = 0;
+	const struct inode *parent;
+	const struct inode *inode;
+	const struct cred *cred;
+	struct dentry *dentry;
+
+	if (!sysctl_protected_symlinks)
+		return 0;
+
+	/* Allowed if owner and follower match. */
+	cred = current_cred();
+	dentry = link->dentry;
+	inode = dentry->d_inode;
+	if (cred->fsuid == inode->i_uid)
+		return 0;
+
+	/* Check parent directory mode and owner. */
+	spin_lock(&dentry->d_lock);
+	parent = dentry->d_parent->d_inode;
+	if ((parent->i_mode & (S_ISVTX|S_IWOTH)) == (S_ISVTX|S_IWOTH) &&
+	    parent->i_uid != inode->i_uid) {
+		error = -EACCES;
+	}
+	spin_unlock(&dentry->d_lock);
+
+	if (error)
+		audit_log_link_denied("follow_link", link);
+
+	return error;
+}
+
+/**
+ * safe_hardlink_source - Check for safe hardlink conditions
+ * @inode: the source inode to hardlink from
+ *
+ * Return false if at least one of the following conditions:
+ *    - inode is not a regular file
+ *    - inode is setuid
+ *    - inode is setgid and group-exec
+ *    - access failure for read and write
+ *
+ * Otherwise returns true.
+ */
+static bool safe_hardlink_source(struct inode *inode)
+{
+	mode_t mode = inode->i_mode;
+
+	/* Special files should not get pinned to the filesystem. */
+	if (!S_ISREG(mode))
+		return false;
+
+	/* Setuid files should not get pinned to the filesystem. */
+	if (mode & S_ISUID)
+		return false;
+
+	/* Executable setgid files should not get pinned to the filesystem. */
+	if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
+		return false;
+
+	/* Hardlinking to unreadable or unwritable sources is dangerous. */
+	if (inode_permission(inode, MAY_READ | MAY_WRITE))
+		return false;
+
+	return true;
+}
+
+/**
+ * may_linkat - Check permissions for creating a hardlink
+ * @link: the source to hardlink from
+ *
+ * Block hardlink when all of:
+ *  - sysctl_protected_hardlinks enabled
+ *  - fsuid does not match inode
+ *  - hardlink source is unsafe (see safe_hardlink_source() above)
+ *  - not CAP_FOWNER
+ *
+ * Returns 0 if successful, -ve on error.
+ */
+static int may_linkat(struct path *link)
+{
+	const struct cred *cred;
+	struct inode *inode;
+
+	if (!sysctl_protected_hardlinks)
+		return 0;
+
+	cred = current_cred();
+	inode = link->dentry->d_inode;
+
+	/* Source inode owner (or CAP_FOWNER) can hardlink all they like,
+	 * otherwise, it must be a safe source.
+	 */
+	if (cred->fsuid == inode->i_uid || safe_hardlink_source(inode) ||
+	    capable(CAP_FOWNER))
+		return 0;
+
+	audit_log_link_denied("linkat", link);
+	return -EPERM;
+}
+#else
+static inline int may_follow_link(struct path *link)
+{
+	return 0;
+}
+
+static inline int may_linkat(struct path *link)
+{
+	return 0;
+}
+#endif
+
 static __always_inline int
 follow_link(struct path *link, struct nameidata *nd, void **p)
 {
-	int error;
 	struct dentry *dentry = link->dentry;
+	int error;
+	char *s;
 
 	BUG_ON(nd->flags & LOOKUP_RCU);
 
 	if (link->mnt == nd->path.mnt)
 		mntget(link->mnt);
 
-	if (unlikely(current->total_link_count >= 40)) {
-		*p = ERR_PTR(-ELOOP); /* no ->put_link(), please */
-		path_put(&nd->path);
-		return -ELOOP;
-	}
+	error = -ELOOP;
+	if (unlikely(current->total_link_count >= 40))
+		goto out_put_nd_path;
+
 	cond_resched();
 	current->total_link_count++;
 
@@ -633,30 +766,28 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
 	nd_set_link(nd, NULL);
 
 	error = security_inode_follow_link(link->dentry, nd);
-	if (error) {
-		*p = ERR_PTR(error); /* no ->put_link(), please */
-		path_put(&nd->path);
-		return error;
-	}
+	if (error)
+		goto out_put_nd_path;
 
 	nd->last_type = LAST_BIND;
 	*p = dentry->d_inode->i_op->follow_link(dentry, nd);
 	error = PTR_ERR(*p);
-	if (!IS_ERR(*p)) {
-		char *s = nd_get_link(nd);
-		error = 0;
-		if (s)
-			error = __vfs_follow_link(nd, s);
-		else if (nd->last_type == LAST_BIND) {
-			nd->flags |= LOOKUP_JUMPED;
-			nd->inode = nd->path.dentry->d_inode;
-			if (nd->inode->i_op->follow_link) {
-				/* stepped on a _really_ weird one */
-				path_put(&nd->path);
-				error = -ELOOP;
-			}
-		}
+	if (IS_ERR(*p))
+		goto out_put_nd_path;
+
+	error = 0;
+	s = nd_get_link(nd);
+	if (s) {
+		error = __vfs_follow_link(nd, s);
+		if (unlikely(error))
+			put_link(nd, link, *p);
 	}
+
+	return error;
+
+out_put_nd_path:
+	path_put(&nd->path);
+	path_put(link);
 	return error;
 }
 
@@ -1048,7 +1179,7 @@ static void follow_dotdot(struct nameidata *nd)
  * dir->d_inode->i_mutex must be held
  */
 static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
-				    struct nameidata *nd, bool *need_lookup)
+				    unsigned int flags, bool *need_lookup)
 {
 	struct dentry *dentry;
 	int error;
@@ -1059,7 +1190,7 @@ static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
 		if (d_need_lookup(dentry)) {
 			*need_lookup = true;
 		} else if (dentry->d_flags & DCACHE_OP_REVALIDATE) {
-			error = d_revalidate(dentry, nd);
+			error = d_revalidate(dentry, flags);
 			if (unlikely(error <= 0)) {
 				if (error < 0) {
 					dput(dentry);
@@ -1089,7 +1220,7 @@ static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
  * dir->d_inode->i_mutex must be held
  */
 static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
-				  struct nameidata *nd)
+				  unsigned int flags)
 {
 	struct dentry *old;
 
@@ -1099,7 +1230,7 @@ static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
 		return ERR_PTR(-ENOENT);
 	}
 
-	old = dir->i_op->lookup(dir, dentry, nd);
+	old = dir->i_op->lookup(dir, dentry, flags);
 	if (unlikely(old)) {
 		dput(dentry);
 		dentry = old;
@@ -1108,16 +1239,16 @@ static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
 }
 
 static struct dentry *__lookup_hash(struct qstr *name,
-		struct dentry *base, struct nameidata *nd)
+		struct dentry *base, unsigned int flags)
 {
 	bool need_lookup;
 	struct dentry *dentry;
 
-	dentry = lookup_dcache(name, base, nd, &need_lookup);
+	dentry = lookup_dcache(name, base, flags, &need_lookup);
 	if (!need_lookup)
 		return dentry;
 
-	return lookup_real(base->d_inode, dentry, nd);
+	return lookup_real(base->d_inode, dentry, flags);
 }
 
 /*
@@ -1167,7 +1298,7 @@ static int lookup_fast(struct nameidata *nd, struct qstr *name,
 		if (unlikely(d_need_lookup(dentry)))
 			goto unlazy;
 		if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
-			status = d_revalidate(dentry, nd);
+			status = d_revalidate(dentry, nd->flags);
 			if (unlikely(status <= 0)) {
 				if (status != -ECHILD)
 					need_reval = 0;
@@ -1197,7 +1328,7 @@ unlazy:
 	}
 
 	if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval)
-		status = d_revalidate(dentry, nd);
+		status = d_revalidate(dentry, nd->flags);
 	if (unlikely(status <= 0)) {
 		if (status < 0) {
 			dput(dentry);
@@ -1236,7 +1367,7 @@ static int lookup_slow(struct nameidata *nd, struct qstr *name,
 	BUG_ON(nd->inode != parent->d_inode);
 
 	mutex_lock(&parent->d_inode->i_mutex);
-	dentry = __lookup_hash(name, parent, nd);
+	dentry = __lookup_hash(name, parent, nd->flags);
 	mutex_unlock(&parent->d_inode->i_mutex);
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
@@ -1383,9 +1514,10 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
 		void *cookie;
 
 		res = follow_link(&link, nd, &cookie);
-		if (!res)
-			res = walk_component(nd, path, &nd->last,
-					     nd->last_type, LOOKUP_FOLLOW);
+		if (res)
+			break;
+		res = walk_component(nd, path, &nd->last,
+				     nd->last_type, LOOKUP_FOLLOW);
 		put_link(nd, &link, cookie);
 	} while (res > 0);
 
@@ -1775,10 +1907,14 @@ static int path_lookupat(int dfd, const char *name,
 		while (err > 0) {
 			void *cookie;
 			struct path link = path;
+			err = may_follow_link(&link);
+			if (unlikely(err))
+				break;
 			nd->flags |= LOOKUP_PARENT;
 			err = follow_link(&link, nd, &cookie);
-			if (!err)
-				err = lookup_last(nd, &path);
+			if (err)
+				break;
+			err = lookup_last(nd, &path);
 			put_link(nd, &link, cookie);
 		}
 	}
@@ -1821,9 +1957,27 @@ static int do_path_lookup(int dfd, const char *name,
 	return retval;
 }
 
-int kern_path_parent(const char *name, struct nameidata *nd)
+/* does lookup, returns the object with parent locked */
+struct dentry *kern_path_locked(const char *name, struct path *path)
 {
-	return do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, nd);
+	struct nameidata nd;
+	struct dentry *d;
+	int err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd);
+	if (err)
+		return ERR_PTR(err);
+	if (nd.last_type != LAST_NORM) {
+		path_put(&nd.path);
+		return ERR_PTR(-EINVAL);
+	}
+	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+	d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
+	if (IS_ERR(d)) {
+		mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+		path_put(&nd.path);
+		return d;
+	}
+	*path = nd.path;
+	return d;
 }
 
 int kern_path(const char *name, unsigned int flags, struct path *path)
@@ -1866,7 +2020,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
  */
 static struct dentry *lookup_hash(struct nameidata *nd)
 {
-	return __lookup_hash(&nd->last, nd->path.dentry, nd);
+	return __lookup_hash(&nd->last, nd->path.dentry, nd->flags);
 }
 
 /**
@@ -1913,7 +2067,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
 	if (err)
 		return ERR_PTR(err);
 
-	return __lookup_hash(&this, base, NULL);
+	return __lookup_hash(&this, base, 0);
 }
 
 int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
@@ -2086,10 +2240,9 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
 }
 
 int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		struct nameidata *nd)
+		bool want_excl)
 {
 	int error = may_create(dir, dentry);
-
 	if (error)
 		return error;
 
@@ -2100,7 +2253,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 	error = security_inode_create(dir, dentry, mode);
 	if (error)
 		return error;
-	error = dir->i_op->create(dir, dentry, mode, nd);
+	error = dir->i_op->create(dir, dentry, mode, want_excl);
 	if (!error)
 		fsnotify_create(dir, dentry);
 	return error;
@@ -2187,21 +2340,275 @@ static inline int open_to_namei_flags(int flag)
 	return flag;
 }
 
+static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
+{
+	int error = security_path_mknod(dir, dentry, mode, 0);
+	if (error)
+		return error;
+
+	error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
+	if (error)
+		return error;
+
+	return security_inode_create(dir->dentry->d_inode, dentry, mode);
+}
+
 /*
- * Handle the last step of open()
+ * Attempt to atomically look up, create and open a file from a negative
+ * dentry.
+ *
+ * Returns 0 if successful.  The file will have been created and attached to
+ * @file by the filesystem calling finish_open().
+ *
+ * Returns 1 if the file was looked up only or didn't need creating.  The
+ * caller will need to perform the open themselves.  @path will have been
+ * updated to point to the new dentry.  This may be negative.
+ *
+ * Returns an error code otherwise.
+ */
+static int atomic_open(struct nameidata *nd, struct dentry *dentry,
+			struct path *path, struct file *file,
+			const struct open_flags *op,
+			bool *want_write, bool need_lookup,
+			int *opened)
+{
+	struct inode *dir =  nd->path.dentry->d_inode;
+	unsigned open_flag = open_to_namei_flags(op->open_flag);
+	umode_t mode;
+	int error;
+	int acc_mode;
+	int create_error = 0;
+	struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
+
+	BUG_ON(dentry->d_inode);
+
+	/* Don't create child dentry for a dead directory. */
+	if (unlikely(IS_DEADDIR(dir))) {
+		error = -ENOENT;
+		goto out;
+	}
+
+	mode = op->mode & S_IALLUGO;
+	if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
+		mode &= ~current_umask();
+
+	if (open_flag & O_EXCL) {
+		open_flag &= ~O_TRUNC;
+		*opened |= FILE_CREATED;
+	}
+
+	/*
+	 * Checking write permission is tricky, bacuse we don't know if we are
+	 * going to actually need it: O_CREAT opens should work as long as the
+	 * file exists.  But checking existence breaks atomicity.  The trick is
+	 * to check access and if not granted clear O_CREAT from the flags.
+	 *
+	 * Another problem is returing the "right" error value (e.g. for an
+	 * O_EXCL open we want to return EEXIST not EROFS).
+	 */
+	if ((open_flag & (O_CREAT | O_TRUNC)) ||
+	    (open_flag & O_ACCMODE) != O_RDONLY) {
+		error = mnt_want_write(nd->path.mnt);
+		if (!error) {
+			*want_write = true;
+		} else if (!(open_flag & O_CREAT)) {
+			/*
+			 * No O_CREATE -> atomicity not a requirement -> fall
+			 * back to lookup + open
+			 */
+			goto no_open;
+		} else if (open_flag & (O_EXCL | O_TRUNC)) {
+			/* Fall back and fail with the right error */
+			create_error = error;
+			goto no_open;
+		} else {
+			/* No side effects, safe to clear O_CREAT */
+			create_error = error;
+			open_flag &= ~O_CREAT;
+		}
+	}
+
+	if (open_flag & O_CREAT) {
+		error = may_o_create(&nd->path, dentry, op->mode);
+		if (error) {
+			create_error = error;
+			if (open_flag & O_EXCL)
+				goto no_open;
+			open_flag &= ~O_CREAT;
+		}
+	}
+
+	if (nd->flags & LOOKUP_DIRECTORY)
+		open_flag |= O_DIRECTORY;
+
+	file->f_path.dentry = DENTRY_NOT_SET;
+	file->f_path.mnt = nd->path.mnt;
+	error = dir->i_op->atomic_open(dir, dentry, file, open_flag, mode,
+				      opened);
+	if (error < 0) {
+		if (create_error && error == -ENOENT)
+			error = create_error;
+		goto out;
+	}
+
+	acc_mode = op->acc_mode;
+	if (*opened & FILE_CREATED) {
+		fsnotify_create(dir, dentry);
+		acc_mode = MAY_OPEN;
+	}
+
+	if (error) {	/* returned 1, that is */
+		if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) {
+			error = -EIO;
+			goto out;
+		}
+		if (file->f_path.dentry) {
+			dput(dentry);
+			dentry = file->f_path.dentry;
+		}
+		goto looked_up;
+	}
+
+	/*
+	 * We didn't have the inode before the open, so check open permission
+	 * here.
+	 */
+	error = may_open(&file->f_path, acc_mode, open_flag);
+	if (error)
+		fput(file);
+
+out:
+	dput(dentry);
+	return error;
+
+no_open:
+	if (need_lookup) {
+		dentry = lookup_real(dir, dentry, nd->flags);
+		if (IS_ERR(dentry))
+			return PTR_ERR(dentry);
+
+		if (create_error) {
+			int open_flag = op->open_flag;
+
+			error = create_error;
+			if ((open_flag & O_EXCL)) {
+				if (!dentry->d_inode)
+					goto out;
+			} else if (!dentry->d_inode) {
+				goto out;
+			} else if ((open_flag & O_TRUNC) &&
+				   S_ISREG(dentry->d_inode->i_mode)) {
+				goto out;
+			}
+			/* will fail later, go on to get the right error */
+		}
+	}
+looked_up:
+	path->dentry = dentry;
+	path->mnt = nd->path.mnt;
+	return 1;
+}
+
+/*
+ * Look up and maybe create and open the last component.
+ *
+ * Must be called with i_mutex held on parent.
+ *
+ * Returns 0 if the file was successfully atomically created (if necessary) and
+ * opened.  In this case the file will be returned attached to @file.
+ *
+ * Returns 1 if the file was not completely opened at this time, though lookups
+ * and creations will have been performed and the dentry returned in @path will
+ * be positive upon return if O_CREAT was specified.  If O_CREAT wasn't
+ * specified then a negative dentry may be returned.
+ *
+ * An error code is returned otherwise.
+ *
+ * FILE_CREATE will be set in @*opened if the dentry was created and will be
+ * cleared otherwise prior to returning.
  */
-static struct file *do_last(struct nameidata *nd, struct path *path,
-			    const struct open_flags *op, const char *pathname)
+static int lookup_open(struct nameidata *nd, struct path *path,
+			struct file *file,
+			const struct open_flags *op,
+			bool *want_write, int *opened)
 {
 	struct dentry *dir = nd->path.dentry;
+	struct inode *dir_inode = dir->d_inode;
 	struct dentry *dentry;
+	int error;
+	bool need_lookup;
+
+	*opened &= ~FILE_CREATED;
+	dentry = lookup_dcache(&nd->last, dir, nd->flags, &need_lookup);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+
+	/* Cached positive dentry: will open in f_op->open */
+	if (!need_lookup && dentry->d_inode)
+		goto out_no_open;
+
+	if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) {
+		return atomic_open(nd, dentry, path, file, op, want_write,
+				   need_lookup, opened);
+	}
+
+	if (need_lookup) {
+		BUG_ON(dentry->d_inode);
+
+		dentry = lookup_real(dir_inode, dentry, nd->flags);
+		if (IS_ERR(dentry))
+			return PTR_ERR(dentry);
+	}
+
+	/* Negative dentry, just create the file */
+	if (!dentry->d_inode && (op->open_flag & O_CREAT)) {
+		umode_t mode = op->mode;
+		if (!IS_POSIXACL(dir->d_inode))
+			mode &= ~current_umask();
+		/*
+		 * This write is needed to ensure that a
+		 * rw->ro transition does not occur between
+		 * the time when the file is created and when
+		 * a permanent write count is taken through
+		 * the 'struct file' in finish_open().
+		 */
+		error = mnt_want_write(nd->path.mnt);
+		if (error)
+			goto out_dput;
+		*want_write = true;
+		*opened |= FILE_CREATED;
+		error = security_path_mknod(&nd->path, dentry, mode, 0);
+		if (error)
+			goto out_dput;
+		error = vfs_create(dir->d_inode, dentry, mode,
+				   nd->flags & LOOKUP_EXCL);
+		if (error)
+			goto out_dput;
+	}
+out_no_open:
+	path->dentry = dentry;
+	path->mnt = nd->path.mnt;
+	return 1;
+
+out_dput:
+	dput(dentry);
+	return error;
+}
+
+/*
+ * Handle the last step of open()
+ */
+static int do_last(struct nameidata *nd, struct path *path,
+		   struct file *file, const struct open_flags *op,
+		   int *opened, const char *pathname)
+{
+	struct dentry *dir = nd->path.dentry;
 	int open_flag = op->open_flag;
-	int will_truncate = open_flag & O_TRUNC;
-	int want_write = 0;
+	bool will_truncate = (open_flag & O_TRUNC) != 0;
+	bool want_write = false;
 	int acc_mode = op->acc_mode;
-	struct file *filp;
 	struct inode *inode;
-	int symlink_ok = 0;
+	bool symlink_ok = false;
 	struct path save_parent = { .dentry = NULL, .mnt = NULL };
 	bool retried = false;
 	int error;
@@ -2214,112 +2621,99 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
 	case LAST_DOT:
 		error = handle_dots(nd, nd->last_type);
 		if (error)
-			return ERR_PTR(error);
+			return error;
 		/* fallthrough */
 	case LAST_ROOT:
 		error = complete_walk(nd);
 		if (error)
-			return ERR_PTR(error);
+			return error;
 		audit_inode(pathname, nd->path.dentry);
 		if (open_flag & O_CREAT) {
 			error = -EISDIR;
-			goto exit;
+			goto out;
 		}
-		goto ok;
+		goto finish_open;
 	case LAST_BIND:
 		error = complete_walk(nd);
 		if (error)
-			return ERR_PTR(error);
+			return error;
 		audit_inode(pathname, dir);
-		goto ok;
+		goto finish_open;
 	}
 
 	if (!(open_flag & O_CREAT)) {
 		if (nd->last.name[nd->last.len])
 			nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
 		if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
-			symlink_ok = 1;
+			symlink_ok = true;
 		/* we _can_ be in RCU mode here */
 		error = lookup_fast(nd, &nd->last, path, &inode);
-		if (unlikely(error)) {
-			if (error < 0)
-				goto exit;
-
-			error = lookup_slow(nd, &nd->last, path);
-			if (error < 0)
-				goto exit;
+		if (likely(!error))
+			goto finish_lookup;
 
-			inode = path->dentry->d_inode;
-		}
-		goto finish_lookup;
-	}
+		if (error < 0)
+			goto out;
 
-	/* create side of things */
-	/*
-	 * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED has been
-	 * cleared when we got to the last component we are about to look up
-	 */
-	error = complete_walk(nd);
-	if (error)
-		return ERR_PTR(error);
+		BUG_ON(nd->inode != dir->d_inode);
+	} else {
+		/* create side of things */
+		/*
+		 * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED
+		 * has been cleared when we got to the last component we are
+		 * about to look up
+		 */
+		error = complete_walk(nd);
+		if (error)
+			return error;
 
-	audit_inode(pathname, dir);
-	error = -EISDIR;
-	/* trailing slashes? */
-	if (nd->last.name[nd->last.len])
-		goto exit;
+		audit_inode(pathname, dir);
+		error = -EISDIR;
+		/* trailing slashes? */
+		if (nd->last.name[nd->last.len])
+			goto out;
+	}
 
 retry_lookup:
 	mutex_lock(&dir->d_inode->i_mutex);
+	error = lookup_open(nd, path, file, op, &want_write, opened);
+	mutex_unlock(&dir->d_inode->i_mutex);
 
-	dentry = lookup_hash(nd);
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry)) {
-		mutex_unlock(&dir->d_inode->i_mutex);
-		goto exit;
-	}
+	if (error <= 0) {
+		if (error)
+			goto out;
 
-	path->dentry = dentry;
-	path->mnt = nd->path.mnt;
+		if ((*opened & FILE_CREATED) ||
+		    !S_ISREG(file->f_path.dentry->d_inode->i_mode))
+			will_truncate = false;
 
-	/* Negative dentry, just create the file */
-	if (!dentry->d_inode) {
-		umode_t mode = op->mode;
-		if (!IS_POSIXACL(dir->d_inode))
-			mode &= ~current_umask();
-		/*
-		 * This write is needed to ensure that a
-		 * rw->ro transition does not occur between
-		 * the time when the file is created and when
-		 * a permanent write count is taken through
-		 * the 'struct file' in nameidata_to_filp().
-		 */
-		error = mnt_want_write(nd->path.mnt);
-		if (error)
-			goto exit_mutex_unlock;
-		want_write = 1;
+		audit_inode(pathname, file->f_path.dentry);
+		goto opened;
+	}
+
+	if (*opened & FILE_CREATED) {
 		/* Don't check for write permission, don't truncate */
 		open_flag &= ~O_TRUNC;
-		will_truncate = 0;
+		will_truncate = false;
 		acc_mode = MAY_OPEN;
-		error = security_path_mknod(&nd->path, dentry, mode, 0);
-		if (error)
-			goto exit_mutex_unlock;
-		error = vfs_create(dir->d_inode, dentry, mode, nd);
-		if (error)
-			goto exit_mutex_unlock;
-		mutex_unlock(&dir->d_inode->i_mutex);
-		dput(nd->path.dentry);
-		nd->path.dentry = dentry;
-		goto common;
+		path_to_nameidata(path, nd);
+		goto finish_open_created;
 	}
 
 	/*
 	 * It already exists.
 	 */
-	mutex_unlock(&dir->d_inode->i_mutex);
 	audit_inode(pathname, path->dentry);
 
+	/*
+	 * If atomic_open() acquired write access it is dropped now due to
+	 * possible mount and symlink following (this might be optimized away if
+	 * necessary...)
+	 */
+	if (want_write) {
+		mnt_drop_write(nd->path.mnt);
+		want_write = false;
+	}
+
 	error = -EEXIST;
 	if (open_flag & O_EXCL)
 		goto exit_dput;
@@ -2338,18 +2732,18 @@ finish_lookup:
 	error = -ENOENT;
 	if (!inode) {
 		path_to_nameidata(path, nd);
-		goto exit;
+		goto out;
 	}
 
 	if (should_follow_link(inode, !symlink_ok)) {
 		if (nd->flags & LOOKUP_RCU) {
 			if (unlikely(unlazy_walk(nd, path->dentry))) {
 				error = -ECHILD;
-				goto exit;
+				goto out;
 			}
 		}
 		BUG_ON(inode != path->dentry->d_inode);
-		return NULL;
+		return 1;
 	}
 
 	if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path->mnt) {
@@ -2365,119 +2759,125 @@ finish_lookup:
 	error = complete_walk(nd);
 	if (error) {
 		path_put(&save_parent);
-		return ERR_PTR(error);
+		return error;
 	}
 	error = -EISDIR;
 	if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode))
-		goto exit;
+		goto out;
 	error = -ENOTDIR;
 	if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)
-		goto exit;
+		goto out;
 	audit_inode(pathname, nd->path.dentry);
-ok:
+finish_open:
 	if (!S_ISREG(nd->inode->i_mode))
-		will_truncate = 0;
+		will_truncate = false;
 
 	if (will_truncate) {
 		error = mnt_want_write(nd->path.mnt);
 		if (error)
-			goto exit;
-		want_write = 1;
+			goto out;
+		want_write = true;
 	}
-common:
+finish_open_created:
 	error = may_open(&nd->path, acc_mode, open_flag);
 	if (error)
-		goto exit;
-	filp = nameidata_to_filp(nd);
-	if (filp == ERR_PTR(-EOPENSTALE) && save_parent.dentry && !retried) {
-		BUG_ON(save_parent.dentry != dir);
-		path_put(&nd->path);
-		nd->path = save_parent;
-		nd->inode = dir->d_inode;
-		save_parent.mnt = NULL;
-		save_parent.dentry = NULL;
-		if (want_write) {
-			mnt_drop_write(nd->path.mnt);
-			want_write = 0;
-		}
-		retried = true;
-		goto retry_lookup;
-	}
-	if (!IS_ERR(filp)) {
-		error = ima_file_check(filp, op->acc_mode);
-		if (error) {
-			fput(filp);
-			filp = ERR_PTR(error);
-		}
+		goto out;
+	file->f_path.mnt = nd->path.mnt;
+	error = finish_open(file, nd->path.dentry, NULL, opened);
+	if (error) {
+		if (error == -EOPENSTALE)
+			goto stale_open;
+		goto out;
 	}
-	if (!IS_ERR(filp)) {
-		if (will_truncate) {
-			error = handle_truncate(filp);
-			if (error) {
-				fput(filp);
-				filp = ERR_PTR(error);
-			}
-		}
+opened:
+	error = open_check_o_direct(file);
+	if (error)
+		goto exit_fput;
+	error = ima_file_check(file, op->acc_mode);
+	if (error)
+		goto exit_fput;
+
+	if (will_truncate) {
+		error = handle_truncate(file);
+		if (error)
+			goto exit_fput;
 	}
 out:
 	if (want_write)
 		mnt_drop_write(nd->path.mnt);
 	path_put(&save_parent);
 	terminate_walk(nd);
-	return filp;
+	return error;
 
-exit_mutex_unlock:
-	mutex_unlock(&dir->d_inode->i_mutex);
 exit_dput:
 	path_put_conditional(path, nd);
-exit:
-	filp = ERR_PTR(error);
 	goto out;
+exit_fput:
+	fput(file);
+	goto out;
+
+stale_open:
+	/* If no saved parent or already retried then can't retry */
+	if (!save_parent.dentry || retried)
+		goto out;
+
+	BUG_ON(save_parent.dentry != dir);
+	path_put(&nd->path);
+	nd->path = save_parent;
+	nd->inode = dir->d_inode;
+	save_parent.mnt = NULL;
+	save_parent.dentry = NULL;
+	if (want_write) {
+		mnt_drop_write(nd->path.mnt);
+		want_write = false;
+	}
+	retried = true;
+	goto retry_lookup;
 }
 
 static struct file *path_openat(int dfd, const char *pathname,
 		struct nameidata *nd, const struct open_flags *op, int flags)
 {
 	struct file *base = NULL;
-	struct file *filp;
+	struct file *file;
 	struct path path;
+	int opened = 0;
 	int error;
 
-	filp = get_empty_filp();
-	if (!filp)
+	file = get_empty_filp();
+	if (!file)
 		return ERR_PTR(-ENFILE);
 
-	filp->f_flags = op->open_flag;
-	nd->intent.open.file = filp;
-	nd->intent.open.flags = open_to_namei_flags(op->open_flag);
-	nd->intent.open.create_mode = op->mode;
+	file->f_flags = op->open_flag;
 
 	error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base);
 	if (unlikely(error))
-		goto out_filp;
+		goto out;
 
 	current->total_link_count = 0;
 	error = link_path_walk(pathname, nd);
 	if (unlikely(error))
-		goto out_filp;
+		goto out;
 
-	filp = do_last(nd, &path, op, pathname);
-	while (unlikely(!filp)) { /* trailing symlink */
+	error = do_last(nd, &path, file, op, &opened, pathname);
+	while (unlikely(error > 0)) { /* trailing symlink */
 		struct path link = path;
 		void *cookie;
 		if (!(nd->flags & LOOKUP_FOLLOW)) {
 			path_put_conditional(&path, nd);
 			path_put(&nd->path);
-			filp = ERR_PTR(-ELOOP);
+			error = -ELOOP;
 			break;
 		}
+		error = may_follow_link(&link);
+		if (unlikely(error))
+			break;
 		nd->flags |= LOOKUP_PARENT;
 		nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
 		error = follow_link(&link, nd, &cookie);
 		if (unlikely(error))
-			filp = ERR_PTR(error);
-		else
-			filp = do_last(nd, &path, op, pathname);
+			break;
+		error = do_last(nd, &path, file, op, &opened, pathname);
 		put_link(nd, &link, cookie);
 	}
 out:
@@ -2485,18 +2885,20 @@ out:
 		path_put(&nd->root);
 	if (base)
 		fput(base);
-	release_open_intent(nd);
-	if (filp == ERR_PTR(-EOPENSTALE)) {
-		if (flags & LOOKUP_RCU)
-			filp = ERR_PTR(-ECHILD);
-		else
-			filp = ERR_PTR(-ESTALE);
+	if (!(opened & FILE_OPENED)) {
+		BUG_ON(!error);
+		put_filp(file);
 	}
-	return filp;
-
-out_filp:
-	filp = ERR_PTR(error);
-	goto out;
+	if (unlikely(error)) {
+		if (error == -EOPENSTALE) {
+			if (flags & LOOKUP_RCU)
+				error = -ECHILD;
+			else
+				error = -ESTALE;
+		}
+		file = ERR_PTR(error);
+	}
+	return file;
 }
 
 struct file *do_filp_open(int dfd, const char *pathname,
@@ -2551,7 +2953,6 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path
 		goto out;
 	nd.flags &= ~LOOKUP_PARENT;
 	nd.flags |= LOOKUP_CREATE | LOOKUP_EXCL;
-	nd.intent.open.flags = O_EXCL;
 
 	/*
 	 * Do the final lookup.
@@ -2670,7 +3071,7 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
 		goto out_drop_write;
 	switch (mode & S_IFMT) {
 		case 0: case S_IFREG:
-			error = vfs_create(path.dentry->d_inode,dentry,mode,NULL);
+			error = vfs_create(path.dentry->d_inode,dentry,mode,true);
 			break;
 		case S_IFCHR: case S_IFBLK:
 			error = vfs_mknod(path.dentry->d_inode,dentry,mode,
@@ -3130,6 +3531,9 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
 	error = -EXDEV;
 	if (old_path.mnt != new_path.mnt)
 		goto out_dput;
+	error = may_linkat(&old_path);
+	if (unlikely(error))
+		goto out_dput;
 	error = mnt_want_write(new_path.mnt);
 	if (error)
 		goto out_dput;
diff --git a/fs/namespace.c b/fs/namespace.c
index 1e4a5fe..8f412ab 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -621,21 +621,6 @@ static void attach_mnt(struct mount *mnt, struct path *path)
 	list_add_tail(&mnt->mnt_child, &real_mount(path->mnt)->mnt_mounts);
 }
 
-static inline void __mnt_make_longterm(struct mount *mnt)
-{
-#ifdef CONFIG_SMP
-	atomic_inc(&mnt->mnt_longterm);
-#endif
-}
-
-/* needs vfsmount lock for write */
-static inline void __mnt_make_shortterm(struct mount *mnt)
-{
-#ifdef CONFIG_SMP
-	atomic_dec(&mnt->mnt_longterm);
-#endif
-}
-
 /*
  * vfsmount lock must be held for write
  */
@@ -649,10 +634,8 @@ static void commit_tree(struct mount *mnt)
 	BUG_ON(parent == mnt);
 
 	list_add_tail(&head, &mnt->mnt_list);
-	list_for_each_entry(m, &head, mnt_list) {
+	list_for_each_entry(m, &head, mnt_list)
 		m->mnt_ns = n;
-		__mnt_make_longterm(m);
-	}
 
 	list_splice(&head, n->list.prev);
 
@@ -804,7 +787,8 @@ static void mntput_no_expire(struct mount *mnt)
 put_again:
 #ifdef CONFIG_SMP
 	br_read_lock(&vfsmount_lock);
-	if (likely(atomic_read(&mnt->mnt_longterm))) {
+	if (likely(mnt->mnt_ns)) {
+		/* shouldn't be the last one */
 		mnt_add_count(mnt, -1);
 		br_read_unlock(&vfsmount_lock);
 		return;
@@ -939,7 +923,7 @@ EXPORT_SYMBOL(replace_mount_options);
 /* iterator; we want it to have access to namespace_sem, thus here... */
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
-	struct proc_mounts *p = container_of(m, struct proc_mounts, m);
+	struct proc_mounts *p = proc_mounts(m);
 
 	down_read(&namespace_sem);
 	return seq_list_start(&p->ns->list, *pos);
@@ -947,7 +931,7 @@ static void *m_start(struct seq_file *m, loff_t *pos)
 
 static void *m_next(struct seq_file *m, void *v, loff_t *pos)
 {
-	struct proc_mounts *p = container_of(m, struct proc_mounts, m);
+	struct proc_mounts *p = proc_mounts(m);
 
 	return seq_list_next(v, &p->ns->list, pos);
 }
@@ -959,7 +943,7 @@ static void m_stop(struct seq_file *m, void *v)
 
 static int m_show(struct seq_file *m, void *v)
 {
-	struct proc_mounts *p = container_of(m, struct proc_mounts, m);
+	struct proc_mounts *p = proc_mounts(m);
 	struct mount *r = list_entry(v, struct mount, mnt_list);
 	return p->show(m, &r->mnt);
 }
@@ -1074,8 +1058,6 @@ void umount_tree(struct mount *mnt, int propagate, struct list_head *kill)
 		list_del_init(&p->mnt_expire);
 		list_del_init(&p->mnt_list);
 		__touch_mnt_namespace(p->mnt_ns);
-		if (p->mnt_ns)
-			__mnt_make_shortterm(p);
 		p->mnt_ns = NULL;
 		list_del_init(&p->mnt_child);
 		if (mnt_has_parent(p)) {
@@ -2209,23 +2191,6 @@ static struct mnt_namespace *alloc_mnt_ns(void)
 	return new_ns;
 }
 
-void mnt_make_longterm(struct vfsmount *mnt)
-{
-	__mnt_make_longterm(real_mount(mnt));
-}
-
-void mnt_make_shortterm(struct vfsmount *m)
-{
-#ifdef CONFIG_SMP
-	struct mount *mnt = real_mount(m);
-	if (atomic_add_unless(&mnt->mnt_longterm, -1, 1))
-		return;
-	br_write_lock(&vfsmount_lock);
-	atomic_dec(&mnt->mnt_longterm);
-	br_write_unlock(&vfsmount_lock);
-#endif
-}
-
 /*
  * Allocate a new namespace structure and populate it with contents
  * copied from the namespace of the passed in task structure.
@@ -2265,18 +2230,13 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
 	q = new;
 	while (p) {
 		q->mnt_ns = new_ns;
-		__mnt_make_longterm(q);
 		if (fs) {
 			if (&p->mnt == fs->root.mnt) {
 				fs->root.mnt = mntget(&q->mnt);
-				__mnt_make_longterm(q);
-				mnt_make_shortterm(&p->mnt);
 				rootmnt = &p->mnt;
 			}
 			if (&p->mnt == fs->pwd.mnt) {
 				fs->pwd.mnt = mntget(&q->mnt);
-				__mnt_make_longterm(q);
-				mnt_make_shortterm(&p->mnt);
 				pwdmnt = &p->mnt;
 			}
 		}
@@ -2320,7 +2280,6 @@ static struct mnt_namespace *create_mnt_ns(struct vfsmount *m)
 	if (!IS_ERR(new_ns)) {
 		struct mount *mnt = real_mount(m);
 		mnt->mnt_ns = new_ns;
-		__mnt_make_longterm(mnt);
 		new_ns->root = mnt;
 		list_add(&new_ns->list, &mnt->mnt_list);
 	} else {
@@ -2615,7 +2574,7 @@ struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
 		 * it is a longterm mount, don't release mnt until
 		 * we unmount before file sys is unregistered
 		*/
-		mnt_make_longterm(mnt);
+		real_mount(mnt)->mnt_ns = MNT_NS_INTERNAL;
 	}
 	return mnt;
 }
@@ -2625,7 +2584,9 @@ void kern_unmount(struct vfsmount *mnt)
 {
 	/* release long term mount so mount point can be released */
 	if (!IS_ERR_OR_NULL(mnt)) {
-		mnt_make_shortterm(mnt);
+		br_write_lock(&vfsmount_lock);
+		real_mount(mnt)->mnt_ns = NULL;
+		br_write_unlock(&vfsmount_lock);
 		mntput(mnt);
 	}
 }
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index aeed93a..4117e7b 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -30,8 +30,8 @@ static void ncp_do_readdir(struct file *, void *, filldir_t,
 
 static int ncp_readdir(struct file *, void *, filldir_t);
 
-static int ncp_create(struct inode *, struct dentry *, umode_t, struct nameidata *);
-static struct dentry *ncp_lookup(struct inode *, struct dentry *, struct nameidata *);
+static int ncp_create(struct inode *, struct dentry *, umode_t, bool);
+static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int);
 static int ncp_unlink(struct inode *, struct dentry *);
 static int ncp_mkdir(struct inode *, struct dentry *, umode_t);
 static int ncp_rmdir(struct inode *, struct dentry *);
@@ -72,7 +72,7 @@ const struct inode_operations ncp_dir_inode_operations =
 /*
  * Dentry operations routines
  */
-static int ncp_lookup_validate(struct dentry *, struct nameidata *);
+static int ncp_lookup_validate(struct dentry *, unsigned int);
 static int ncp_hash_dentry(const struct dentry *, const struct inode *,
 		struct qstr *);
 static int ncp_compare_dentry(const struct dentry *, const struct inode *,
@@ -290,7 +290,7 @@ leave_me:;
 
 
 static int
-ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd)
+ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
 {
 	struct ncp_server *server;
 	struct dentry *parent;
@@ -302,7 +302,7 @@ ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd)
 	if (dentry == dentry->d_sb->s_root)
 		return 1;
 
-	if (nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	parent = dget_parent(dentry);
@@ -836,7 +836,7 @@ out:
 	return result;
 }
 
-static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	struct ncp_server *server = NCP_SERVER(dir);
 	struct inode *inode = NULL;
@@ -980,7 +980,7 @@ out:
 }
 
 static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		struct nameidata *nd)
+		bool excl)
 {
 	return ncp_create_new(dir, dentry, mode, 0, 0);
 }
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 333df07..0c62c55 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -89,6 +89,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(ncp_inode_cachep);
 }
 
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index f90f4f5..b47452f 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -3,7 +3,6 @@ config NFS_FS
 	depends on INET && FILE_LOCKING
 	select LOCKD
 	select SUNRPC
-	select NFS_ACL_SUPPORT if NFS_V3_ACL
 	help
 	  Choose Y here if you want to access files residing on other
 	  computers using Sun's Network File System protocol.  To compile
@@ -88,9 +87,8 @@ config NFS_V4
 
 config NFS_V4_1
 	bool "NFS client support for NFSv4.1 (EXPERIMENTAL)"
-	depends on NFS_FS && NFS_V4 && EXPERIMENTAL
+	depends on NFS_V4 && EXPERIMENTAL
 	select SUNRPC_BACKCHANNEL
-	select PNFS_FILE_LAYOUT
 	help
 	  This option enables support for minor version 1 of the NFSv4 protocol
 	  (RFC 5661) in the kernel's NFS client.
@@ -99,15 +97,17 @@ config NFS_V4_1
 
 config PNFS_FILE_LAYOUT
 	tristate
+	depends on NFS_V4_1
+	default m
 
 config PNFS_BLOCK
 	tristate
-	depends on NFS_FS && NFS_V4_1 && BLK_DEV_DM
+	depends on NFS_V4_1 && BLK_DEV_DM
 	default m
 
 config PNFS_OBJLAYOUT
 	tristate
-	depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD
+	depends on NFS_V4_1 && SCSI_OSD_ULD
 	default m
 
 config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f430057..a6b1c7f 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -46,8 +46,8 @@
 static int nfs_opendir(struct inode *, struct file *);
 static int nfs_closedir(struct inode *, struct file *);
 static int nfs_readdir(struct file *, void *, filldir_t);
-static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *);
-static int nfs_create(struct inode *, struct dentry *, umode_t, struct nameidata *);
+static struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int);
+static int nfs_create(struct inode *, struct dentry *, umode_t, bool);
 static int nfs_mkdir(struct inode *, struct dentry *, umode_t);
 static int nfs_rmdir(struct inode *, struct dentry *);
 static int nfs_unlink(struct inode *, struct dentry *);
@@ -111,11 +111,13 @@ const struct inode_operations nfs3_dir_inode_operations = {
 
 #ifdef CONFIG_NFS_V4
 
-static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
-static int nfs_open_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd);
+static int nfs_atomic_open(struct inode *, struct dentry *,
+			   struct file *, unsigned, umode_t,
+			   int *);
 const struct inode_operations nfs4_dir_inode_operations = {
-	.create		= nfs_open_create,
-	.lookup		= nfs_atomic_lookup,
+	.create		= nfs_create,
+	.lookup		= nfs_lookup,
+	.atomic_open	= nfs_atomic_open,
 	.link		= nfs_link,
 	.unlink		= nfs_unlink,
 	.symlink	= nfs_symlink,
@@ -1029,27 +1031,14 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
 }
 
 /*
- * Return the intent data that applies to this particular path component
- *
- * Note that the current set of intents only apply to the very last
- * component of the path and none of them is set before that last
- * component.
- */
-static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd,
-						unsigned int mask)
-{
-	return nd->flags & mask;
-}
-
-/*
  * Use intent information to check whether or not we're going to do
  * an O_EXCL create using this path component.
  */
-static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
+static int nfs_is_exclusive_create(struct inode *dir, unsigned int flags)
 {
 	if (NFS_PROTO(dir)->version == 2)
 		return 0;
-	return nd && nfs_lookup_check_intent(nd, LOOKUP_EXCL);
+	return flags & LOOKUP_EXCL;
 }
 
 /*
@@ -1061,25 +1050,20 @@ static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
  *
  */
 static inline
-int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
+int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags)
 {
 	struct nfs_server *server = NFS_SERVER(inode);
 
 	if (IS_AUTOMOUNT(inode))
 		return 0;
-	if (nd != NULL) {
-		/* VFS wants an on-the-wire revalidation */
-		if (nd->flags & LOOKUP_REVAL)
-			goto out_force;
-		/* This is an open(2) */
-		if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
-				!(server->flags & NFS_MOUNT_NOCTO) &&
-				(S_ISREG(inode->i_mode) ||
-				 S_ISDIR(inode->i_mode)))
-			goto out_force;
-		return 0;
-	}
-	return nfs_revalidate_inode(server, inode);
+	/* VFS wants an on-the-wire revalidation */
+	if (flags & LOOKUP_REVAL)
+		goto out_force;
+	/* This is an open(2) */
+	if ((flags & LOOKUP_OPEN) && !(server->flags & NFS_MOUNT_NOCTO) &&
+	    (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
+		goto out_force;
+	return 0;
 out_force:
 	return __nfs_revalidate_inode(server, inode);
 }
@@ -1093,10 +1077,10 @@ out_force:
  */
 static inline
 int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
-		       struct nameidata *nd)
+		       unsigned int flags)
 {
 	/* Don't revalidate a negative dentry if we're creating a new file */
-	if (nd != NULL && nfs_lookup_check_intent(nd, LOOKUP_CREATE) != 0)
+	if (flags & LOOKUP_CREATE)
 		return 0;
 	if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG)
 		return 1;
@@ -1114,7 +1098,7 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
  * If the parent directory is seen to have changed, we throw out the
  * cached dentry and do a new lookup.
  */
-static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct inode *dir;
 	struct inode *inode;
@@ -1123,7 +1107,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
 	struct nfs_fattr *fattr = NULL;
 	int error;
 
-	if (nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	parent = dget_parent(dentry);
@@ -1132,7 +1116,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
 	inode = dentry->d_inode;
 
 	if (!inode) {
-		if (nfs_neg_need_reval(dir, dentry, nd))
+		if (nfs_neg_need_reval(dir, dentry, flags))
 			goto out_bad;
 		goto out_valid_noent;
 	}
@@ -1148,8 +1132,8 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
 		goto out_set_verifier;
 
 	/* Force a full look up iff the parent directory has changed */
-	if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) {
-		if (nfs_lookup_verify_inode(inode, nd))
+	if (!nfs_is_exclusive_create(dir, flags) && nfs_check_verifier(dir, dentry)) {
+		if (nfs_lookup_verify_inode(inode, flags))
 			goto out_zap_parent;
 		goto out_valid;
 	}
@@ -1286,7 +1270,7 @@ const struct dentry_operations nfs_dentry_operations = {
 	.d_release	= nfs_d_release,
 };
 
-static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
 	struct dentry *res;
 	struct dentry *parent;
@@ -1307,7 +1291,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
 	 * If we're doing an exclusive create, optimize away the lookup
 	 * but don't hash the dentry.
 	 */
-	if (nfs_is_exclusive_create(dir, nd)) {
+	if (nfs_is_exclusive_create(dir, flags)) {
 		d_instantiate(dentry, NULL);
 		res = NULL;
 		goto out;
@@ -1354,7 +1338,7 @@ out:
 }
 
 #ifdef CONFIG_NFS_V4
-static int nfs4_lookup_revalidate(struct dentry *, struct nameidata *);
+static int nfs4_lookup_revalidate(struct dentry *, unsigned int);
 
 const struct dentry_operations nfs4_dentry_operations = {
 	.d_revalidate	= nfs4_lookup_revalidate,
@@ -1364,24 +1348,6 @@ const struct dentry_operations nfs4_dentry_operations = {
 	.d_release	= nfs_d_release,
 };
 
-/*
- * Use intent information to determine whether we need to substitute
- * the NFSv4-style stateful OPEN for the LOOKUP call
- */
-static int is_atomic_open(struct nameidata *nd)
-{
-	if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0)
-		return 0;
-	/* NFS does not (yet) have a stateful open for directories */
-	if (nd->flags & LOOKUP_DIRECTORY)
-		return 0;
-	/* Are we trying to write to a read only partition? */
-	if (__mnt_is_readonly(nd->path.mnt) &&
-	    (nd->intent.open.flags & (O_CREAT|O_TRUNC|O_ACCMODE)))
-		return 0;
-	return 1;
-}
-
 static fmode_t flags_to_mode(int flags)
 {
 	fmode_t res = (__force fmode_t)flags & FMODE_EXEC;
@@ -1403,136 +1369,143 @@ static int do_open(struct inode *inode, struct file *filp)
 	return 0;
 }
 
-static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx)
+static int nfs_finish_open(struct nfs_open_context *ctx,
+			   struct dentry *dentry,
+			   struct file *file, unsigned open_flags,
+			   int *opened)
 {
-	struct file *filp;
-	int ret = 0;
+	int err;
+
+	if (ctx->dentry != dentry) {
+		dput(ctx->dentry);
+		ctx->dentry = dget(dentry);
+	}
 
 	/* If the open_intent is for execute, we have an extra check to make */
 	if (ctx->mode & FMODE_EXEC) {
-		ret = nfs_may_open(ctx->dentry->d_inode,
-				ctx->cred,
-				nd->intent.open.flags);
-		if (ret < 0)
+		err = nfs_may_open(dentry->d_inode, ctx->cred, open_flags);
+		if (err < 0)
 			goto out;
 	}
-	filp = lookup_instantiate_filp(nd, ctx->dentry, do_open);
-	if (IS_ERR(filp))
-		ret = PTR_ERR(filp);
-	else
-		nfs_file_set_open_context(filp, ctx);
+
+	err = finish_open(file, dentry, do_open, opened);
+	if (err)
+		goto out;
+	nfs_file_set_open_context(file, ctx);
+
 out:
 	put_nfs_open_context(ctx);
-	return ret;
+	return err;
 }
 
-static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
+			    struct file *file, unsigned open_flags,
+			    umode_t mode, int *opened)
 {
 	struct nfs_open_context *ctx;
-	struct iattr attr;
-	struct dentry *res = NULL;
+	struct dentry *res;
+	struct iattr attr = { .ia_valid = ATTR_OPEN };
 	struct inode *inode;
-	int open_flags;
 	int err;
 
-	dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n",
+	/* Expect a negative dentry */
+	BUG_ON(dentry->d_inode);
+
+	dfprintk(VFS, "NFS: atomic_open(%s/%ld), %s\n",
 			dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
 
-	/* Check that we are indeed trying to open this file */
-	if (!is_atomic_open(nd))
+	/* NFS only supports OPEN on regular files */
+	if ((open_flags & O_DIRECTORY)) {
+		if (!d_unhashed(dentry)) {
+			/*
+			 * Hashed negative dentry with O_DIRECTORY: dentry was
+			 * revalidated and is fine, no need to perform lookup
+			 * again
+			 */
+			return -ENOENT;
+		}
 		goto no_open;
-
-	if (dentry->d_name.len > NFS_SERVER(dir)->namelen) {
-		res = ERR_PTR(-ENAMETOOLONG);
-		goto out;
-	}
-
-	/* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash
-	 * the dentry. */
-	if (nd->flags & LOOKUP_EXCL) {
-		d_instantiate(dentry, NULL);
-		goto out;
 	}
 
-	open_flags = nd->intent.open.flags;
-	attr.ia_valid = ATTR_OPEN;
-
-	ctx = create_nfs_open_context(dentry, open_flags);
-	res = ERR_CAST(ctx);
-	if (IS_ERR(ctx))
-		goto out;
+	if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
+		return -ENAMETOOLONG;
 
-	if (nd->flags & LOOKUP_CREATE) {
-		attr.ia_mode = nd->intent.open.create_mode;
+	if (open_flags & O_CREAT) {
 		attr.ia_valid |= ATTR_MODE;
-		attr.ia_mode &= ~current_umask();
-	} else
-		open_flags &= ~(O_EXCL | O_CREAT);
-
+		attr.ia_mode = mode & ~current_umask();
+	}
 	if (open_flags & O_TRUNC) {
 		attr.ia_valid |= ATTR_SIZE;
 		attr.ia_size = 0;
 	}
 
-	/* Open the file on the server */
+	ctx = create_nfs_open_context(dentry, open_flags);
+	err = PTR_ERR(ctx);
+	if (IS_ERR(ctx))
+		goto out;
+
 	nfs_block_sillyrename(dentry->d_parent);
 	inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr);
+	d_drop(dentry);
 	if (IS_ERR(inode)) {
 		nfs_unblock_sillyrename(dentry->d_parent);
 		put_nfs_open_context(ctx);
-		switch (PTR_ERR(inode)) {
-			/* Make a negative dentry */
-			case -ENOENT:
-				d_add(dentry, NULL);
-				res = NULL;
-				goto out;
-			/* This turned out not to be a regular file */
-			case -EISDIR:
-			case -ENOTDIR:
+		err = PTR_ERR(inode);
+		switch (err) {
+		case -ENOENT:
+			d_add(dentry, NULL);
+			break;
+		case -EISDIR:
+		case -ENOTDIR:
+			goto no_open;
+		case -ELOOP:
+			if (!(open_flags & O_NOFOLLOW))
 				goto no_open;
-			case -ELOOP:
-				if (!(nd->intent.open.flags & O_NOFOLLOW))
-					goto no_open;
+			break;
 			/* case -EINVAL: */
-			default:
-				res = ERR_CAST(inode);
-				goto out;
+		default:
+			break;
 		}
+		goto out;
 	}
 	res = d_add_unique(dentry, inode);
-	nfs_unblock_sillyrename(dentry->d_parent);
-	if (res != NULL) {
-		dput(ctx->dentry);
-		ctx->dentry = dget(res);
+	if (res != NULL)
 		dentry = res;
-	}
-	err = nfs_intent_set_file(nd, ctx);
-	if (err < 0) {
-		if (res != NULL)
-			dput(res);
-		return ERR_PTR(err);
-	}
-out:
+
+	nfs_unblock_sillyrename(dentry->d_parent);
 	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-	return res;
+
+	err = nfs_finish_open(ctx, dentry, file, open_flags, opened);
+
+	dput(res);
+out:
+	return err;
+
 no_open:
-	return nfs_lookup(dir, dentry, nd);
+	res = nfs_lookup(dir, dentry, 0);
+	err = PTR_ERR(res);
+	if (IS_ERR(res))
+		goto out;
+
+	return finish_no_open(file, res);
 }
 
-static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct dentry *parent = NULL;
 	struct inode *inode;
 	struct inode *dir;
-	int openflags, ret = 0;
+	int ret = 0;
 
-	if (nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
-	inode = dentry->d_inode;
-	if (!is_atomic_open(nd) || d_mountpoint(dentry))
+	if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY))
+		goto no_open;
+	if (d_mountpoint(dentry))
 		goto no_open;
 
+	inode = dentry->d_inode;
 	parent = dget_parent(dentry);
 	dir = parent->d_inode;
 
@@ -1540,7 +1513,7 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
 	 * optimize away revalidation of negative dentries.
 	 */
 	if (inode == NULL) {
-		if (!nfs_neg_need_reval(dir, dentry, nd))
+		if (!nfs_neg_need_reval(dir, dentry, flags))
 			ret = 1;
 		goto out;
 	}
@@ -1548,9 +1521,8 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
 	/* NFS only supports OPEN on regular files */
 	if (!S_ISREG(inode->i_mode))
 		goto no_open_dput;
-	openflags = nd->intent.open.flags;
 	/* We cannot do exclusive creation on a positive dentry */
-	if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
+	if (flags & LOOKUP_EXCL)
 		goto no_open_dput;
 
 	/* Let f_op->open() actually open (and revalidate) the file */
@@ -1563,48 +1535,7 @@ out:
 no_open_dput:
 	dput(parent);
 no_open:
-	return nfs_lookup_revalidate(dentry, nd);
-}
-
-static int nfs_open_create(struct inode *dir, struct dentry *dentry,
-		umode_t mode, struct nameidata *nd)
-{
-	struct nfs_open_context *ctx = NULL;
-	struct iattr attr;
-	int error;
-	int open_flags = O_CREAT|O_EXCL;
-
-	dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
-			dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
-
-	attr.ia_mode = mode;
-	attr.ia_valid = ATTR_MODE;
-
-	if (nd)
-		open_flags = nd->intent.open.flags;
-
-	ctx = create_nfs_open_context(dentry, open_flags);
-	error = PTR_ERR(ctx);
-	if (IS_ERR(ctx))
-		goto out_err_drop;
-
-	error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx);
-	if (error != 0)
-		goto out_put_ctx;
-	if (nd) {
-		error = nfs_intent_set_file(nd, ctx);
-		if (error < 0)
-			goto out_err;
-	} else {
-		put_nfs_open_context(ctx);
-	}
-	return 0;
-out_put_ctx:
-	put_nfs_open_context(ctx);
-out_err_drop:
-	d_drop(dentry);
-out_err:
-	return error;
+	return nfs_lookup_revalidate(dentry, flags);
 }
 
 #endif /* CONFIG_NFSV4 */
@@ -1658,11 +1589,11 @@ out_error:
  * reply path made it appear to have failed.
  */
 static int nfs_create(struct inode *dir, struct dentry *dentry,
-		umode_t mode, struct nameidata *nd)
+		umode_t mode, bool excl)
 {
 	struct iattr attr;
+	int open_flags = excl ? O_CREAT | O_EXCL : O_CREAT;
 	int error;
-	int open_flags = O_CREAT|O_EXCL;
 
 	dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
 			dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
@@ -1670,10 +1601,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry,
 	attr.ia_mode = mode;
 	attr.ia_valid = ATTR_MODE;
 
-	if (nd)
-		open_flags = nd->intent.open.flags;
-
-	error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, NULL);
+	error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags);
 	if (error != 0)
 		goto out_err;
 	return 0;
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 8abfb19..a67990f 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -62,7 +62,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
 		 */
 		spin_lock(&sb->s_root->d_inode->i_lock);
 		spin_lock(&sb->s_root->d_lock);
-		list_del_init(&sb->s_root->d_alias);
+		hlist_del_init(&sb->s_root->d_alias);
 		spin_unlock(&sb->s_root->d_lock);
 		spin_unlock(&sb->s_root->d_inode->i_lock);
 	}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index f729698..edecd05 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1566,6 +1566,11 @@ static int __init nfs_init_inodecache(void)
 
 static void nfs_destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(nfs_inode_cachep);
 }
 
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index baf759b..d04f0df 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -106,19 +106,16 @@ static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
 static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result)
 {
 	u32 recvd, count;
-	size_t hdrlen;
 	__be32 *p;
 
 	p = xdr_inline_decode(xdr, 4);
 	if (unlikely(p == NULL))
 		goto out_overflow;
 	count = be32_to_cpup(p);
-	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-	recvd = xdr->buf->len - hdrlen;
+	recvd = xdr_read_pages(xdr, count);
 	if (unlikely(count > recvd))
 		goto out_cheating;
 out:
-	xdr_read_pages(xdr, count);
 	result->eof = 0;	/* NFSv2 does not pass EOF flag on the wire. */
 	result->count = count;
 	return count;
@@ -440,7 +437,6 @@ static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
 static int decode_path(struct xdr_stream *xdr)
 {
 	u32 length, recvd;
-	size_t hdrlen;
 	__be32 *p;
 
 	p = xdr_inline_decode(xdr, 4);
@@ -449,12 +445,9 @@ static int decode_path(struct xdr_stream *xdr)
 	length = be32_to_cpup(p);
 	if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
 		goto out_size;
-	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-	recvd = xdr->buf->len - hdrlen;
+	recvd = xdr_read_pages(xdr, length);
 	if (unlikely(length > recvd))
 		goto out_cheating;
-
-	xdr_read_pages(xdr, length);
 	xdr_terminate_string(xdr->buf, length);
 	return 0;
 out_size:
@@ -972,22 +965,7 @@ out_overflow:
  */
 static int decode_readdirok(struct xdr_stream *xdr)
 {
-	u32 recvd, pglen;
-	size_t hdrlen;
-
-	pglen = xdr->buf->page_len;
-	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-	recvd = xdr->buf->len - hdrlen;
-	if (unlikely(pglen > recvd))
-		goto out_cheating;
-out:
-	xdr_read_pages(xdr, pglen);
-	return pglen;
-out_cheating:
-	dprintk("NFS: server cheating in readdir result: "
-		"pglen %u > recvd %u\n", pglen, recvd);
-	pglen = recvd;
-	goto out;
+	return xdr_read_pages(xdr, xdr->buf->page_len);
 }
 
 static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req,
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 2292a0f..3187e24 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -314,7 +314,7 @@ static void nfs3_free_createdata(struct nfs3_createdata *data)
  */
 static int
 nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-		 int flags, struct nfs_open_context *ctx)
+		 int flags)
 {
 	struct nfs3_createdata *data;
 	umode_t mode = sattr->ia_mode;
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 902de48..6cbe894 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -246,7 +246,6 @@ static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
 static int decode_nfspath3(struct xdr_stream *xdr)
 {
 	u32 recvd, count;
-	size_t hdrlen;
 	__be32 *p;
 
 	p = xdr_inline_decode(xdr, 4);
@@ -255,12 +254,9 @@ static int decode_nfspath3(struct xdr_stream *xdr)
 	count = be32_to_cpup(p);
 	if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN))
 		goto out_nametoolong;
-	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-	recvd = xdr->buf->len - hdrlen;
+	recvd = xdr_read_pages(xdr, count);
 	if (unlikely(count > recvd))
 		goto out_cheating;
-
-	xdr_read_pages(xdr, count);
 	xdr_terminate_string(xdr->buf, count);
 	return 0;
 
@@ -329,14 +325,14 @@ static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
 	memcpy(p, verifier, NFS3_CREATEVERFSIZE);
 }
 
-static int decode_writeverf3(struct xdr_stream *xdr, __be32 *verifier)
+static int decode_writeverf3(struct xdr_stream *xdr, struct nfs_write_verifier *verifier)
 {
 	__be32 *p;
 
 	p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE);
 	if (unlikely(p == NULL))
 		goto out_overflow;
-	memcpy(verifier, p, NFS3_WRITEVERFSIZE);
+	memcpy(verifier->data, p, NFS3_WRITEVERFSIZE);
 	return 0;
 out_overflow:
 	print_overflow_msg(__func__, xdr);
@@ -1587,7 +1583,6 @@ static int decode_read3resok(struct xdr_stream *xdr,
 			     struct nfs_readres *result)
 {
 	u32 eof, count, ocount, recvd;
-	size_t hdrlen;
 	__be32 *p;
 
 	p = xdr_inline_decode(xdr, 4 + 4 + 4);
@@ -1598,13 +1593,10 @@ static int decode_read3resok(struct xdr_stream *xdr,
 	ocount = be32_to_cpup(p++);
 	if (unlikely(ocount != count))
 		goto out_mismatch;
-	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-	recvd = xdr->buf->len - hdrlen;
+	recvd = xdr_read_pages(xdr, count);
 	if (unlikely(count > recvd))
 		goto out_cheating;
-
 out:
-	xdr_read_pages(xdr, count);
 	result->eof = eof;
 	result->count = count;
 	return count;
@@ -1676,20 +1668,22 @@ static int decode_write3resok(struct xdr_stream *xdr,
 {
 	__be32 *p;
 
-	p = xdr_inline_decode(xdr, 4 + 4 + NFS3_WRITEVERFSIZE);
+	p = xdr_inline_decode(xdr, 4 + 4);
 	if (unlikely(p == NULL))
 		goto out_overflow;
 	result->count = be32_to_cpup(p++);
 	result->verf->committed = be32_to_cpup(p++);
 	if (unlikely(result->verf->committed > NFS_FILE_SYNC))
 		goto out_badvalue;
-	memcpy(result->verf->verifier, p, NFS3_WRITEVERFSIZE);
+	if (decode_writeverf3(xdr, &result->verf->verifier))
+		goto out_eio;
 	return result->count;
 out_badvalue:
 	dprintk("NFS: bad stable_how value: %u\n", result->verf->committed);
 	return -EIO;
 out_overflow:
 	print_overflow_msg(__func__, xdr);
+out_eio:
 	return -EIO;
 }
 
@@ -2039,22 +2033,7 @@ out_truncated:
  */
 static int decode_dirlist3(struct xdr_stream *xdr)
 {
-	u32 recvd, pglen;
-	size_t hdrlen;
-
-	pglen = xdr->buf->page_len;
-	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-	recvd = xdr->buf->len - hdrlen;
-	if (unlikely(pglen > recvd))
-		goto out_cheating;
-out:
-	xdr_read_pages(xdr, pglen);
-	return pglen;
-out_cheating:
-	dprintk("NFS: server cheating in readdir result: "
-		"pglen %u > recvd %u\n", pglen, recvd);
-	pglen = recvd;
-	goto out;
+	return xdr_read_pages(xdr, xdr->buf->page_len);
 }
 
 static int decode_readdir3resok(struct xdr_stream *xdr,
@@ -2337,7 +2316,7 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
 		goto out;
 	if (status != NFS3_OK)
 		goto out_status;
-	error = decode_writeverf3(xdr, result->verf->verifier);
+	error = decode_writeverf3(xdr, &result->verf->verifier);
 out:
 	return error;
 out_status:
@@ -2364,7 +2343,7 @@ static inline int decode_getacl3resok(struct xdr_stream *xdr,
 	if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
 		goto out;
 
-	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
+	hdrlen = xdr_stream_pos(xdr);
 
 	acl = NULL;
 	if (result->mask & NFS_ACL)
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index e134029..85b7063 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -351,9 +351,9 @@ static void prepare_to_resend_writes(struct nfs_commit_data *data)
 	struct nfs_page *first = nfs_list_entry(data->pages.next);
 
 	data->task.tk_status = 0;
-	memcpy(data->verf.verifier, first->wb_verf.verifier,
-	       sizeof(first->wb_verf.verifier));
-	data->verf.verifier[0]++; /* ensure verifier mismatch */
+	memcpy(&data->verf.verifier, &first->wb_verf,
+	       sizeof(data->verf.verifier));
+	data->verf.verifier.data[0]++; /* ensure verifier mismatch */
 }
 
 static int filelayout_commit_done_cb(struct rpc_task *task,
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c
index a1fab8d..f81231f 100644
--- a/fs/nfs/nfs4filelayoutdev.c
+++ b/fs/nfs/nfs4filelayoutdev.c
@@ -728,7 +728,7 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_fla
 	pdev->layout_type = LAYOUT_NFSV4_1_FILES;
 	pdev->pages = pages;
 	pdev->pgbase = 0;
-	pdev->pglen = PAGE_SIZE * max_pages;
+	pdev->pglen = max_resp_sz;
 	pdev->mincount = 0;
 
 	rc = nfs4_proc_getdeviceinfo(server, pdev);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 15fc7e4..19cfc8a 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2766,9 +2766,7 @@ static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
  *
  * In the case of WRITE, we also want to put the GETATTR after
  * the operation -- in this case because we want to make sure
- * we get the post-operation mtime and size.  This means that
- * we can't use xdr_encode_pages() as written: we need a variant
- * of it which would leave room in the 'tail' iovec.
+ * we get the post-operation mtime and size.
  *
  * Both of these changes to the XDR layer would in fact be quite
  * minor, but I decided to leave them for a subsequent patch.
@@ -2806,37 +2804,22 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page,
 }
 
 /*
- * Got race?
- * We will need to arrange for the VFS layer to provide an atomic open.
- * Until then, this create/open method is prone to inefficiency and race
- * conditions due to the lookup, create, and open VFS calls from sys_open()
- * placed on the wire.
- *
- * Given the above sorry state of affairs, I'm simply sending an OPEN.
- * The file will be opened again in the subsequent VFS open call
- * (nfs4_proc_file_open).
- *
- * The open for read will just hang around to be used by any process that
- * opens the file O_RDONLY. This will all be resolved with the VFS changes.
+ * This is just for mknod.  open(O_CREAT) will always do ->open_context().
  */
-
 static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-                 int flags, struct nfs_open_context *ctx)
+		 int flags)
 {
-	struct dentry *de = dentry;
+	struct nfs_open_context *ctx;
 	struct nfs4_state *state;
-	struct rpc_cred *cred = NULL;
-	fmode_t fmode = 0;
 	int status = 0;
 
-	if (ctx != NULL) {
-		cred = ctx->cred;
-		de = ctx->dentry;
-		fmode = ctx->mode;
-	}
+	ctx = alloc_nfs_open_context(dentry, FMODE_READ);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
 	sattr->ia_mode &= ~current_umask();
-	state = nfs4_do_open(dir, de, fmode, flags, sattr, cred, NULL);
+	state = nfs4_do_open(dir, dentry, ctx->mode, flags, sattr, ctx->cred, NULL);
 	d_drop(dentry);
 	if (IS_ERR(state)) {
 		status = PTR_ERR(state);
@@ -2844,11 +2827,9 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	}
 	d_add(dentry, igrab(state->inode));
 	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-	if (ctx != NULL)
-		ctx->state = state;
-	else
-		nfs4_close_sync(state, fmode);
+	ctx->state = state;
 out:
+	put_nfs_open_context(ctx);
 	return status;
 }
 
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index f38300e..1cfc460 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1642,7 +1642,7 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
 	return 0;
 }
 
-static int nfs4_reclaim_lease(struct nfs_client *clp)
+static int nfs4_establish_lease(struct nfs_client *clp)
 {
 	struct rpc_cred *cred;
 	const struct nfs4_state_recovery_ops *ops =
@@ -1655,7 +1655,37 @@ static int nfs4_reclaim_lease(struct nfs_client *clp)
 	status = ops->establish_clid(clp, cred);
 	put_rpccred(cred);
 	if (status != 0)
+		return status;
+	pnfs_destroy_all_layouts(clp);
+	return 0;
+}
+
+static int nfs4_reclaim_lease(struct nfs_client *clp)
+{
+	int status;
+
+	status = nfs4_establish_lease(clp);
+	if (status < 0)
+		return nfs4_handle_reclaim_lease_error(clp, status);
+	if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state))
+		nfs4_state_start_reclaim_nograce(clp);
+	if (!test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state))
+		set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
+	clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
+	clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+	return 0;
+}
+
+static int nfs4_purge_lease(struct nfs_client *clp)
+{
+	int status;
+
+	status = nfs4_establish_lease(clp);
+	if (status < 0)
 		return nfs4_handle_reclaim_lease_error(clp, status);
+	clear_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
+	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+	nfs4_state_start_reclaim_nograce(clp);
 	return 0;
 }
 
@@ -1764,6 +1794,8 @@ static int nfs4_reset_session(struct nfs_client *clp)
 	struct rpc_cred *cred;
 	int status;
 
+	if (!nfs4_has_session(clp))
+		return 0;
 	nfs4_begin_drain_session(clp);
 	cred = nfs4_get_exchange_id_cred(clp);
 	status = nfs4_proc_destroy_session(clp->cl_session, cred);
@@ -1792,12 +1824,14 @@ out:
 
 static int nfs4_recall_slot(struct nfs_client *clp)
 {
-	struct nfs4_slot_table *fc_tbl = &clp->cl_session->fc_slot_table;
-	struct nfs4_channel_attrs *fc_attrs = &clp->cl_session->fc_attrs;
+	struct nfs4_slot_table *fc_tbl;
 	struct nfs4_slot *new, *old;
 	int i;
 
+	if (!nfs4_has_session(clp))
+		return 0;
 	nfs4_begin_drain_session(clp);
+	fc_tbl = &clp->cl_session->fc_slot_table;
 	new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot),
 		      GFP_NOFS);
         if (!new)
@@ -1810,11 +1844,10 @@ static int nfs4_recall_slot(struct nfs_client *clp)
 	fc_tbl->slots = new;
 	fc_tbl->max_slots = fc_tbl->target_max_slots;
 	fc_tbl->target_max_slots = 0;
-	fc_attrs->max_reqs = fc_tbl->max_slots;
+	clp->cl_session->fc_attrs.max_reqs = fc_tbl->max_slots;
 	spin_unlock(&fc_tbl->slot_tbl_lock);
 
 	kfree(old);
-	nfs4_end_drain_session(clp);
 	return 0;
 }
 
@@ -1823,6 +1856,8 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 	struct rpc_cred *cred;
 	int ret;
 
+	if (!nfs4_has_session(clp))
+		return 0;
 	nfs4_begin_drain_session(clp);
 	cred = nfs4_get_exchange_id_cred(clp);
 	ret = nfs4_proc_bind_conn_to_session(clp, cred);
@@ -1857,37 +1892,29 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 static void nfs4_state_manager(struct nfs_client *clp)
 {
 	int status = 0;
+	const char *section = "", *section_sep = "";
 
 	/* Ensure exclusive access to NFSv4 state */
 	do {
 		if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
-			status = nfs4_reclaim_lease(clp);
+			section = "purge state";
+			status = nfs4_purge_lease(clp);
 			if (status < 0)
 				goto out_error;
-			clear_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
-			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+			continue;
 		}
 
-		if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
+		if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
+			section = "lease expired";
 			/* We're going to have to re-establish a clientid */
 			status = nfs4_reclaim_lease(clp);
 			if (status < 0)
 				goto out_error;
-			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
-				continue;
-			clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
-
-			if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH,
-					       &clp->cl_state))
-				nfs4_state_start_reclaim_nograce(clp);
-			else
-				set_bit(NFS4CLNT_RECLAIM_REBOOT,
-					&clp->cl_state);
-
-			pnfs_destroy_all_layouts(clp);
+			continue;
 		}
 
 		if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
+			section = "check lease";
 			status = nfs4_check_lease(clp);
 			if (status < 0)
 				goto out_error;
@@ -1896,8 +1923,8 @@ static void nfs4_state_manager(struct nfs_client *clp)
 		}
 
 		/* Initialize or reset the session */
-		if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)
-		   && nfs4_has_session(clp)) {
+		if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) {
+			section = "reset session";
 			status = nfs4_reset_session(clp);
 			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
 				continue;
@@ -1907,15 +1934,26 @@ static void nfs4_state_manager(struct nfs_client *clp)
 
 		/* Send BIND_CONN_TO_SESSION */
 		if (test_and_clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION,
-				&clp->cl_state) && nfs4_has_session(clp)) {
+				&clp->cl_state)) {
+			section = "bind conn to session";
 			status = nfs4_bind_conn_to_session(clp);
 			if (status < 0)
 				goto out_error;
 			continue;
 		}
 
+		/* Recall session slots */
+		if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)) {
+			section = "recall slot";
+			status = nfs4_recall_slot(clp);
+			if (status < 0)
+				goto out_error;
+			continue;
+		}
+
 		/* First recover reboot state... */
 		if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
+			section = "reclaim reboot";
 			status = nfs4_do_reclaim(clp,
 				clp->cl_mvops->reboot_recovery_ops);
 			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
@@ -1930,6 +1968,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
 
 		/* Now recover expired state... */
 		if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
+			section = "reclaim nograce";
 			status = nfs4_do_reclaim(clp,
 				clp->cl_mvops->nograce_recovery_ops);
 			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
@@ -1945,15 +1984,6 @@ static void nfs4_state_manager(struct nfs_client *clp)
 			nfs_client_return_marked_delegations(clp);
 			continue;
 		}
-		/* Recall session slots */
-		if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)
-		   && nfs4_has_session(clp)) {
-			status = nfs4_recall_slot(clp);
-			if (status < 0)
-				goto out_error;
-			continue;
-		}
-
 
 		nfs4_clear_state_manager_bit(clp);
 		/* Did we race with an attempt to give us more work? */
@@ -1964,8 +1994,11 @@ static void nfs4_state_manager(struct nfs_client *clp)
 	} while (atomic_read(&clp->cl_count) > 1);
 	return;
 out_error:
-	pr_warn_ratelimited("NFS: state manager failed on NFSv4 server %s"
-			" with error %d\n", clp->cl_hostname, -status);
+	if (strlen(section))
+		section_sep = ": ";
+	pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s"
+			" with error %d\n", section_sep, section,
+			clp->cl_hostname, -status);
 	nfs4_end_drain_session(clp);
 	nfs4_clear_state_manager_bit(clp);
 }
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 18fae29..610ebcc 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -3078,7 +3078,7 @@ out_overflow:
 	return -EIO;
 }
 
-static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
+static int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, unsigned int *savep)
 {
 	__be32 *p;
 
@@ -3086,7 +3086,7 @@ static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen,
 	if (unlikely(!p))
 		goto out_overflow;
 	*attrlen = be32_to_cpup(p);
-	*savep = xdr->p;
+	*savep = xdr_stream_pos(xdr);
 	return 0;
 out_overflow:
 	print_overflow_msg(__func__, xdr);
@@ -4068,10 +4068,10 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
 	return status;
 }
 
-static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
+static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen)
 {
 	unsigned int attrwords = XDR_QUADLEN(attrlen);
-	unsigned int nwords = xdr->p - savep;
+	unsigned int nwords = (xdr_stream_pos(xdr) - savep) >> 2;
 
 	if (unlikely(attrwords != nwords)) {
 		dprintk("%s: server returned incorrect attribute length: "
@@ -4158,13 +4158,18 @@ static int decode_verifier(struct xdr_stream *xdr, void *verifier)
 	return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE);
 }
 
+static int decode_write_verifier(struct xdr_stream *xdr, struct nfs_write_verifier *verifier)
+{
+	return decode_opaque_fixed(xdr, verifier->data, NFS4_VERIFIER_SIZE);
+}
+
 static int decode_commit(struct xdr_stream *xdr, struct nfs_commitres *res)
 {
 	int status;
 
 	status = decode_op_hdr(xdr, OP_COMMIT);
 	if (!status)
-		status = decode_verifier(xdr, res->verf->verifier);
+		status = decode_write_verifier(xdr, &res->verf->verifier);
 	return status;
 }
 
@@ -4193,7 +4198,7 @@ out_overflow:
 
 static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
 {
-	__be32 *savep;
+	unsigned int savep;
 	uint32_t attrlen, bitmap[3] = {0};
 	int status;
 
@@ -4222,7 +4227,7 @@ xdr_error:
 
 static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
 {
-	__be32 *savep;
+	unsigned int savep;
 	uint32_t attrlen, bitmap[3] = {0};
 	int status;
 
@@ -4254,7 +4259,7 @@ xdr_error:
 
 static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
 {
-	__be32 *savep;
+	unsigned int savep;
 	uint32_t attrlen, bitmap[3] = {0};
 	int status;
 
@@ -4299,7 +4304,8 @@ out_overflow:
 static int decode_first_threshold_item4(struct xdr_stream *xdr,
 					struct nfs4_threshold *res)
 {
-	__be32 *p, *savep;
+	__be32 *p;
+	unsigned int savep;
 	uint32_t bitmap[3] = {0,}, attrlen;
 	int status;
 
@@ -4503,7 +4509,7 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
 		struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc,
 		const struct nfs_server *server)
 {
-	__be32 *savep;
+	unsigned int savep;
 	uint32_t attrlen,
 		 bitmap[3] = {0};
 	int status;
@@ -4615,7 +4621,7 @@ static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap,
 
 static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
 {
-	__be32 *savep;
+	unsigned int savep;
 	uint32_t attrlen, bitmap[3];
 	int status;
 
@@ -4920,9 +4926,8 @@ static int decode_putrootfh(struct xdr_stream *xdr)
 
 static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
 {
-	struct kvec *iov = req->rq_rcv_buf.head;
 	__be32 *p;
-	uint32_t count, eof, recvd, hdrlen;
+	uint32_t count, eof, recvd;
 	int status;
 
 	status = decode_op_hdr(xdr, OP_READ);
@@ -4933,15 +4938,13 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_
 		goto out_overflow;
 	eof = be32_to_cpup(p++);
 	count = be32_to_cpup(p);
-	hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base;
-	recvd = req->rq_rcv_buf.len - hdrlen;
+	recvd = xdr_read_pages(xdr, count);
 	if (count > recvd) {
 		dprintk("NFS: server cheating in read reply: "
 				"count %u > recvd %u\n", count, recvd);
 		count = recvd;
 		eof = 0;
 	}
-	xdr_read_pages(xdr, count);
 	res->eof = eof;
 	res->count = count;
 	return 0;
@@ -4952,10 +4955,6 @@ out_overflow:
 
 static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
 {
-	struct xdr_buf	*rcvbuf = &req->rq_rcv_buf;
-	struct kvec	*iov = rcvbuf->head;
-	size_t		hdrlen;
-	u32		recvd, pglen = rcvbuf->page_len;
 	int		status;
 	__be32		verf[2];
 
@@ -4967,22 +4966,12 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
 	memcpy(verf, readdir->verifier.data, sizeof(verf));
 	dprintk("%s: verifier = %08x:%08x\n",
 			__func__, verf[0], verf[1]);
-
-	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
-	recvd = rcvbuf->len - hdrlen;
-	if (pglen > recvd)
-		pglen = recvd;
-	xdr_read_pages(xdr, pglen);
-
-
-	return pglen;
+	return xdr_read_pages(xdr, xdr->buf->page_len);
 }
 
 static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
 {
 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
-	struct kvec *iov = rcvbuf->head;
-	size_t hdrlen;
 	u32 len, recvd;
 	__be32 *p;
 	int status;
@@ -5000,14 +4989,12 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
 		dprintk("nfs: server returned giant symlink!\n");
 		return -ENAMETOOLONG;
 	}
-	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
-	recvd = req->rq_rcv_buf.len - hdrlen;
+	recvd = xdr_read_pages(xdr, len);
 	if (recvd < len) {
 		dprintk("NFS: server cheating in readlink reply: "
 				"count %u > recvd %u\n", len, recvd);
 		return -EIO;
 	}
-	xdr_read_pages(xdr, len);
 	/*
 	 * The XDR encode routine has set things up so that
 	 * the link text will be copied directly into the
@@ -5063,10 +5050,10 @@ decode_restorefh(struct xdr_stream *xdr)
 static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
 			 struct nfs_getaclres *res)
 {
-	__be32 *savep, *bm_p;
+	unsigned int savep;
+	__be32 *bm_p;
 	uint32_t attrlen,
 		 bitmap[3] = {0};
-	struct kvec *iov = req->rq_rcv_buf.head;
 	int status;
 	size_t page_len = xdr->buf->page_len;
 
@@ -5089,7 +5076,6 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
 	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
 		return -EIO;
 	if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
-		size_t hdrlen;
 
 		/* The bitmap (xdr len + bitmaps) and the attr xdr len words
 		 * are stored with the acl data to handle the problem of
@@ -5098,7 +5084,6 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
 
 		/* We ignore &savep and don't do consistency checks on
 		 * the attr length.  Let userspace figure it out.... */
-		hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
 		attrlen += res->acl_data_offset;
 		if (attrlen > page_len) {
 			if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
@@ -5212,13 +5197,12 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
 	if (status)
 		return status;
 
-	p = xdr_inline_decode(xdr, 16);
+	p = xdr_inline_decode(xdr, 8);
 	if (unlikely(!p))
 		goto out_overflow;
 	res->count = be32_to_cpup(p++);
 	res->verf->committed = be32_to_cpup(p++);
-	memcpy(res->verf->verifier, p, NFS4_VERIFIER_SIZE);
-	return 0;
+	return decode_write_verifier(xdr, &res->verf->verifier);
 out_overflow:
 	print_overflow_msg(__func__, xdr);
 	return -EIO;
@@ -5599,7 +5583,7 @@ static int decode_getdevicelist(struct xdr_stream *xdr,
 {
 	__be32 *p;
 	int status, i;
-	struct nfs_writeverf verftemp;
+	nfs4_verifier verftemp;
 
 	status = decode_op_hdr(xdr, OP_GETDEVICELIST);
 	if (status)
@@ -5613,7 +5597,7 @@ static int decode_getdevicelist(struct xdr_stream *xdr,
 	p += 2;
 
 	/* Read verifier */
-	p = xdr_decode_opaque_fixed(p, verftemp.verifier, NFS4_VERIFIER_SIZE);
+	p = xdr_decode_opaque_fixed(p, verftemp.data, NFS4_VERIFIER_SIZE);
 
 	res->num_devs = be32_to_cpup(p);
 
@@ -5707,9 +5691,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
 	__be32 *p;
 	int status;
 	u32 layout_count;
-	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
-	struct kvec *iov = rcvbuf->head;
-	u32 hdrlen, recvd;
+	u32 recvd;
 
 	status = decode_op_hdr(xdr, OP_LAYOUTGET);
 	if (status)
@@ -5746,8 +5728,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
 		res->type,
 		res->layoutp->len);
 
-	hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base;
-	recvd = req->rq_rcv_buf.len - hdrlen;
+	recvd = xdr_read_pages(xdr, res->layoutp->len);
 	if (res->layoutp->len > recvd) {
 		dprintk("NFS: server cheating in layoutget reply: "
 				"layout len %u > recvd %u\n",
@@ -5755,8 +5736,6 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
 		return -EINVAL;
 	}
 
-	xdr_read_pages(xdr, res->layoutp->len);
-
 	if (layout_count > 1) {
 		/* We only handle a length one array at the moment.  Any
 		 * further entries are just ignored.  Note that this means
@@ -7103,6 +7082,7 @@ out:
 int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 		       int plus)
 {
+	unsigned int savep;
 	uint32_t bitmap[3] = {0};
 	uint32_t len;
 	__be32 *p = xdr_inline_decode(xdr, 4);
@@ -7141,7 +7121,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 	if (decode_attr_bitmap(xdr, bitmap) < 0)
 		goto out_overflow;
 
-	if (decode_attr_length(xdr, &len, &p) < 0)
+	if (decode_attr_length(xdr, &len, &savep) < 0)
 		goto out_overflow;
 
 	if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 617c741..4433806 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -259,7 +259,7 @@ static void nfs_free_createdata(const struct nfs_createdata *data)
 
 static int
 nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-		int flags, struct nfs_open_context *ctx)
+		int flags)
 {
 	struct nfs_createdata *data;
 	struct rpc_message msg = {
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 4d6861c..ee929e5 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -620,7 +620,7 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr)
 			goto next;
 		}
 		if (test_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags)) {
-			memcpy(&req->wb_verf, hdr->verf, sizeof(req->wb_verf));
+			memcpy(&req->wb_verf, &hdr->verf->verifier, sizeof(req->wb_verf));
 			nfs_mark_request_commit(req, hdr->lseg, &cinfo);
 			goto next;
 		}
@@ -1547,7 +1547,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
 
 		/* Okay, COMMIT succeeded, apparently. Check the verifier
 		 * returned by the server against all stored verfs. */
-		if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) {
+		if (!memcmp(&req->wb_verf, &data->verf.verifier, sizeof(req->wb_verf))) {
 			/* We have a match */
 			nfs_inode_remove_request(req);
 			dprintk(" OK\n");
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 8df1ea4..d202bd5 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -5,7 +5,6 @@ config NFSD
 	select LOCKD
 	select SUNRPC
 	select EXPORTFS
-	select NFS_ACL_SUPPORT if NFSD_V2_ACL
 	help
 	  Choose Y here if you want to allow other computers to access
 	  files residing on this system using Sun's Network File System
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 94effd5..59b9efc 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -38,6 +38,7 @@
 #include <linux/namei.h>
 #include <linux/swap.h>
 #include <linux/pagemap.h>
+#include <linux/ratelimit.h>
 #include <linux/sunrpc/svcauth_gss.h>
 #include <linux/sunrpc/clnt.h>
 #include "xdr4.h"
@@ -862,6 +863,11 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses,
 	if (ret)
 		/* oops; xprt is already down: */
 		nfsd4_conn_lost(&conn->cn_xpt_user);
+	if (ses->se_client->cl_cb_state == NFSD4_CB_DOWN &&
+		dir & NFS4_CDFC4_BACK) {
+		/* callback channel may be back up */
+		nfsd4_probe_callback(ses->se_client);
+	}
 	return nfs_ok;
 }
 
@@ -3333,18 +3339,26 @@ static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_s
 	return nfserr_old_stateid;
 }
 
-__be32 nfs4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
+static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 {
 	struct nfs4_stid *s;
 	struct nfs4_ol_stateid *ols;
 	__be32 status;
 
-	if (STALE_STATEID(stateid))
-		return nfserr_stale_stateid;
-
+	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+		return nfserr_bad_stateid;
+	/* Client debugging aid. */
+	if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
+		char addr_str[INET6_ADDRSTRLEN];
+		rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str,
+				 sizeof(addr_str));
+		pr_warn_ratelimited("NFSD: client %s testing state ID "
+					"with incorrect client ID\n", addr_str);
+		return nfserr_bad_stateid;
+	}
 	s = find_stateid(cl, stateid);
 	if (!s)
-		 return nfserr_stale_stateid;
+		return nfserr_bad_stateid;
 	status = check_stateid_generation(stateid, &s->sc_stateid, 1);
 	if (status)
 		return status;
@@ -3463,7 +3477,8 @@ nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 	nfs4_lock_state();
 	list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
-		stateid->ts_id_status = nfs4_validate_stateid(cl, &stateid->ts_id_stateid);
+		stateid->ts_id_status =
+			nfsd4_validate_stateid(cl, &stateid->ts_id_stateid);
 	nfs4_unlock_state();
 
 	return nfs_ok;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 849091e..495df4e 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -475,7 +475,6 @@ extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
 extern int nfs4_client_to_reclaim(const char *name);
 extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
 extern void release_session_client(struct nfsd4_session *);
-extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
 extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
 
 /* nfs4recover operations */
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index c8bd9c3..05d9eee 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1329,7 +1329,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	err = 0;
 	switch (type) {
 	case S_IFREG:
-		host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+		host_err = vfs_create(dirp, dchild, iap->ia_mode, true);
 		if (!host_err)
 			nfsd_check_ignore_resizing(iap);
 		break;
@@ -1492,7 +1492,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		goto out;
 	}
 
-	host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+	host_err = vfs_create(dirp, dchild, iap->ia_mode, true);
 	if (host_err < 0) {
 		fh_drop_write(fhp);
 		goto out_nfserr;
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index b728479..1d0c0b8 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -63,7 +63,7 @@ static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode)
  */
 
 static struct dentry *
-nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+nilfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	struct inode *inode;
 	ino_t ino;
@@ -85,7 +85,7 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
  * with d_instantiate().
  */
 static int nilfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-			struct nameidata *nd)
+			bool excl)
 {
 	struct inode *inode;
 	struct nilfs_transaction_info ti;
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 1099a76..956e5a4 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -1386,6 +1386,12 @@ static void nilfs_segbuf_init_once(void *obj)
 
 static void nilfs_destroy_cachep(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
+
 	if (nilfs_inode_cachep)
 		kmem_cache_destroy(nilfs_inode_cachep);
 	if (nilfs_transaction_cachep)
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index 3344bdd..08b886f 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -201,7 +201,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id)
 
 	/* nothing else could have found us thanks to the dnotify_mark_mutex */
 	if (dn_mark->dn == NULL)
-		fsnotify_destroy_mark(fsn_mark);
+		fsnotify_destroy_mark(fsn_mark, dnotify_group);
 
 	mutex_unlock(&dnotify_mark_mutex);
 
@@ -385,7 +385,7 @@ out:
 	spin_unlock(&fsn_mark->lock);
 
 	if (destroy)
-		fsnotify_destroy_mark(fsn_mark);
+		fsnotify_destroy_mark(fsn_mark, dnotify_group);
 
 	mutex_unlock(&dnotify_mark_mutex);
 	fsnotify_put_mark(fsn_mark);
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index f35794b..aeb5b5a 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -18,6 +18,12 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
 	    old->tgid == new->tgid) {
 		switch (old->data_type) {
 		case (FSNOTIFY_EVENT_PATH):
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+			/* dont merge two permission events */
+			if ((old->mask & FAN_ALL_PERM_EVENTS) &&
+			    (new->mask & FAN_ALL_PERM_EVENTS))
+				return false;
+#endif
 			if ((old->path.mnt == new->path.mnt) &&
 			    (old->path.dentry == new->path.dentry))
 				return true;
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 3568c8a..5d01b63 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -418,8 +418,12 @@ static int fanotify_release(struct inode *ignored, struct file *file)
 
 	wake_up(&group->fanotify_data.access_waitq);
 #endif
+
+	if (file->f_flags & FASYNC)
+		fsnotify_fasync(-1, file, 0);
+
 	/* matches the fanotify_init->fsnotify_alloc_group */
-	fsnotify_put_group(group);
+	fsnotify_destroy_group(group);
 
 	return 0;
 }
@@ -515,7 +519,8 @@ out:
 
 static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
 					    __u32 mask,
-					    unsigned int flags)
+					    unsigned int flags,
+					    int *destroy)
 {
 	__u32 oldmask;
 
@@ -529,8 +534,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
 	}
 	spin_unlock(&fsn_mark->lock);
 
-	if (!(oldmask & ~mask))
-		fsnotify_destroy_mark(fsn_mark);
+	*destroy = !(oldmask & ~mask);
 
 	return mask & oldmask;
 }
@@ -541,12 +545,17 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
 {
 	struct fsnotify_mark *fsn_mark = NULL;
 	__u32 removed;
+	int destroy_mark;
 
 	fsn_mark = fsnotify_find_vfsmount_mark(group, mnt);
 	if (!fsn_mark)
 		return -ENOENT;
 
-	removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags);
+	removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags,
+						 &destroy_mark);
+	if (destroy_mark)
+		fsnotify_destroy_mark(fsn_mark, group);
+
 	fsnotify_put_mark(fsn_mark);
 	if (removed & real_mount(mnt)->mnt_fsnotify_mask)
 		fsnotify_recalc_vfsmount_mask(mnt);
@@ -560,12 +569,16 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,
 {
 	struct fsnotify_mark *fsn_mark = NULL;
 	__u32 removed;
+	int destroy_mark;
 
 	fsn_mark = fsnotify_find_inode_mark(group, inode);
 	if (!fsn_mark)
 		return -ENOENT;
 
-	removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags);
+	removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags,
+						 &destroy_mark);
+	if (destroy_mark)
+		fsnotify_destroy_mark(fsn_mark, group);
 	/* matches the fsnotify_find_inode_mark() */
 	fsnotify_put_mark(fsn_mark);
 	if (removed & inode->i_fsnotify_mask)
@@ -732,13 +745,13 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 		break;
 	default:
 		fd = -EINVAL;
-		goto out_put_group;
+		goto out_destroy_group;
 	}
 
 	if (flags & FAN_UNLIMITED_QUEUE) {
 		fd = -EPERM;
 		if (!capable(CAP_SYS_ADMIN))
-			goto out_put_group;
+			goto out_destroy_group;
 		group->max_events = UINT_MAX;
 	} else {
 		group->max_events = FANOTIFY_DEFAULT_MAX_EVENTS;
@@ -747,7 +760,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 	if (flags & FAN_UNLIMITED_MARKS) {
 		fd = -EPERM;
 		if (!capable(CAP_SYS_ADMIN))
-			goto out_put_group;
+			goto out_destroy_group;
 		group->fanotify_data.max_marks = UINT_MAX;
 	} else {
 		group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS;
@@ -755,12 +768,12 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 
 	fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
 	if (fd < 0)
-		goto out_put_group;
+		goto out_destroy_group;
 
 	return fd;
 
-out_put_group:
-	fsnotify_put_group(group);
+out_destroy_group:
+	fsnotify_destroy_group(group);
 	return fd;
 }
 
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index b39c5c1..6baadb5 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -52,6 +52,7 @@ void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
 void __fsnotify_update_child_dentry_flags(struct inode *inode)
 {
 	struct dentry *alias;
+	struct hlist_node *p;
 	int watched;
 
 	if (!S_ISDIR(inode->i_mode))
@@ -63,7 +64,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
 	spin_lock(&inode->i_lock);
 	/* run all of the dentries associated with this inode.  Since this is a
 	 * directory, there damn well better only be one item on this list */
-	list_for_each_entry(alias, &inode->i_dentry, d_alias) {
+	hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
 		struct dentry *child;
 
 		/* run all of the children of the original inode and fix their
diff --git a/fs/notify/group.c b/fs/notify/group.c
index 63fc294..bd2625b 100644
--- a/fs/notify/group.c
+++ b/fs/notify/group.c
@@ -33,9 +33,6 @@
  */
 void fsnotify_final_destroy_group(struct fsnotify_group *group)
 {
-	/* clear the notification queue of all events */
-	fsnotify_flush_notify(group);
-
 	if (group->ops->free_group_priv)
 		group->ops->free_group_priv(group);
 
@@ -43,23 +40,30 @@ void fsnotify_final_destroy_group(struct fsnotify_group *group)
 }
 
 /*
- * Trying to get rid of a group.  We need to first get rid of any outstanding
- * allocations and then free the group.  Remember that fsnotify_clear_marks_by_group
- * could miss marks that are being freed by inode and those marks could still
- * hold a reference to this group (via group->num_marks)  If we get into that
- * situtation, the fsnotify_final_destroy_group will get called when that final
- * mark is freed.
+ * Trying to get rid of a group. Remove all marks, flush all events and release
+ * the group reference.
+ * Note that another thread calling fsnotify_clear_marks_by_group() may still
+ * hold a ref to the group.
  */
-static void fsnotify_destroy_group(struct fsnotify_group *group)
+void fsnotify_destroy_group(struct fsnotify_group *group)
 {
 	/* clear all inode marks for this group */
 	fsnotify_clear_marks_by_group(group);
 
 	synchronize_srcu(&fsnotify_mark_srcu);
 
-	/* past the point of no return, matches the initial value of 1 */
-	if (atomic_dec_and_test(&group->num_marks))
-		fsnotify_final_destroy_group(group);
+	/* clear the notification queue of all events */
+	fsnotify_flush_notify(group);
+
+	fsnotify_put_group(group);
+}
+
+/*
+ * Get reference to a group.
+ */
+void fsnotify_get_group(struct fsnotify_group *group)
+{
+	atomic_inc(&group->refcnt);
 }
 
 /*
@@ -68,7 +72,7 @@ static void fsnotify_destroy_group(struct fsnotify_group *group)
 void fsnotify_put_group(struct fsnotify_group *group)
 {
 	if (atomic_dec_and_test(&group->refcnt))
-		fsnotify_destroy_group(group);
+		fsnotify_final_destroy_group(group);
 }
 
 /*
@@ -84,21 +88,24 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
 
 	/* set to 0 when there a no external references to this group */
 	atomic_set(&group->refcnt, 1);
-	/*
-	 * hits 0 when there are no external references AND no marks for
-	 * this group
-	 */
-	atomic_set(&group->num_marks, 1);
+	atomic_set(&group->num_marks, 0);
 
 	mutex_init(&group->notification_mutex);
 	INIT_LIST_HEAD(&group->notification_list);
 	init_waitqueue_head(&group->notification_waitq);
 	group->max_events = UINT_MAX;
 
-	spin_lock_init(&group->mark_lock);
+	mutex_init(&group->mark_mutex);
 	INIT_LIST_HEAD(&group->marks_list);
 
 	group->ops = ops;
 
 	return group;
 }
+
+int fsnotify_fasync(int fd, struct file *file, int on)
+{
+	struct fsnotify_group *group = file->private_data;
+
+	return fasync_helper(fd, file, on, &group->fsn_fa) >= 0 ? 0 : -EIO;
+}
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index b13c00a..2123020 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -63,8 +63,8 @@ void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark)
 {
 	struct inode *inode = mark->i.inode;
 
+	BUG_ON(!mutex_is_locked(&mark->group->mark_mutex));
 	assert_spin_locked(&mark->lock);
-	assert_spin_locked(&mark->group->mark_lock);
 
 	spin_lock(&inode->i_lock);
 
@@ -99,8 +99,16 @@ void fsnotify_clear_marks_by_inode(struct inode *inode)
 	spin_unlock(&inode->i_lock);
 
 	list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) {
-		fsnotify_destroy_mark(mark);
+		struct fsnotify_group *group;
+
+		spin_lock(&mark->lock);
+		fsnotify_get_group(mark->group);
+		group = mark->group;
+		spin_unlock(&mark->lock);
+
+		fsnotify_destroy_mark(mark, group);
 		fsnotify_put_mark(mark);
+		fsnotify_put_group(group);
 	}
 }
 
@@ -191,8 +199,8 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
 
 	mark->flags |= FSNOTIFY_MARK_FLAG_INODE;
 
+	BUG_ON(!mutex_is_locked(&group->mark_mutex));
 	assert_spin_locked(&mark->lock);
-	assert_spin_locked(&group->mark_lock);
 
 	spin_lock(&inode->i_lock);
 
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index e3cbd74..871569c 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -118,6 +118,7 @@ static int inotify_handle_event(struct fsnotify_group *group,
 
 	fsn_event_priv = &event_priv->fsnotify_event_priv_data;
 
+	fsnotify_get_group(group);
 	fsn_event_priv->group = group;
 	event_priv->wd = wd;
 
@@ -131,7 +132,7 @@ static int inotify_handle_event(struct fsnotify_group *group,
 	}
 
 	if (inode_mark->mask & IN_ONESHOT)
-		fsnotify_destroy_mark(inode_mark);
+		fsnotify_destroy_mark(inode_mark, group);
 
 	return ret;
 }
@@ -210,6 +211,7 @@ void inotify_free_event_priv(struct fsnotify_event_private_data *fsn_event_priv)
 	event_priv = container_of(fsn_event_priv, struct inotify_event_private_data,
 				  fsnotify_event_priv_data);
 
+	fsnotify_put_group(fsn_event_priv->group);
 	kmem_cache_free(event_priv_cachep, event_priv);
 }
 
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 8445fbc..463e828 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -264,7 +264,7 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
 		ret = -EAGAIN;
 		if (file->f_flags & O_NONBLOCK)
 			break;
-		ret = -EINTR;
+		ret = -ERESTARTSYS;
 		if (signal_pending(current))
 			break;
 
@@ -280,23 +280,17 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
 	return ret;
 }
 
-static int inotify_fasync(int fd, struct file *file, int on)
-{
-	struct fsnotify_group *group = file->private_data;
-
-	return fasync_helper(fd, file, on, &group->inotify_data.fa) >= 0 ? 0 : -EIO;
-}
-
 static int inotify_release(struct inode *ignored, struct file *file)
 {
 	struct fsnotify_group *group = file->private_data;
 
 	pr_debug("%s: group=%p\n", __func__, group);
 
-	fsnotify_clear_marks_by_group(group);
+	if (file->f_flags & FASYNC)
+		fsnotify_fasync(-1, file, 0);
 
 	/* free this group, matching get was inotify_init->fsnotify_obtain_group */
-	fsnotify_put_group(group);
+	fsnotify_destroy_group(group);
 
 	return 0;
 }
@@ -337,7 +331,7 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
 static const struct file_operations inotify_fops = {
 	.poll		= inotify_poll,
 	.read		= inotify_read,
-	.fasync		= inotify_fasync,
+	.fasync		= fsnotify_fasync,
 	.release	= inotify_release,
 	.unlocked_ioctl	= inotify_ioctl,
 	.compat_ioctl	= inotify_ioctl,
@@ -519,13 +513,13 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
 	struct fsnotify_event_private_data *fsn_event_priv;
 	int ret;
 
+	i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
+
 	ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL,
 					      FSNOTIFY_EVENT_NONE, NULL, 0,
 					      GFP_NOFS);
 	if (!ignored_event)
-		return;
-
-	i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
+		goto skip_send_ignore;
 
 	event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS);
 	if (unlikely(!event_priv))
@@ -533,6 +527,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
 
 	fsn_event_priv = &event_priv->fsnotify_event_priv_data;
 
+	fsnotify_get_group(group);
 	fsn_event_priv->group = group;
 	event_priv->wd = i_mark->wd;
 
@@ -546,9 +541,9 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
 	}
 
 skip_send_ignore:
-
 	/* matches the reference taken when the event was created */
-	fsnotify_put_event(ignored_event);
+	if (ignored_event)
+		fsnotify_put_event(ignored_event);
 
 	/* remove this mark from the idr */
 	inotify_remove_from_idr(group, i_mark);
@@ -707,12 +702,11 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events)
 	spin_lock_init(&group->inotify_data.idr_lock);
 	idr_init(&group->inotify_data.idr);
 	group->inotify_data.last_wd = 0;
-	group->inotify_data.fa = NULL;
 	group->inotify_data.user = get_current_user();
 
 	if (atomic_inc_return(&group->inotify_data.user->inotify_devs) >
 	    inotify_max_user_instances) {
-		fsnotify_put_group(group);
+		fsnotify_destroy_group(group);
 		return ERR_PTR(-EMFILE);
 	}
 
@@ -741,7 +735,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
 	ret = anon_inode_getfd("inotify", &inotify_fops, group,
 				  O_RDONLY | flags);
 	if (ret < 0)
-		fsnotify_put_group(group);
+		fsnotify_destroy_group(group);
 
 	return ret;
 }
@@ -817,7 +811,7 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd)
 
 	ret = 0;
 
-	fsnotify_destroy_mark(&i_mark->fsn_mark);
+	fsnotify_destroy_mark(&i_mark->fsn_mark, group);
 
 	/* match ref taken by inotify_idr_find */
 	fsnotify_put_mark(&i_mark->fsn_mark);
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index f104d56..fc6b49b 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -109,8 +109,11 @@ void fsnotify_get_mark(struct fsnotify_mark *mark)
 
 void fsnotify_put_mark(struct fsnotify_mark *mark)
 {
-	if (atomic_dec_and_test(&mark->refcnt))
+	if (atomic_dec_and_test(&mark->refcnt)) {
+		if (mark->group)
+			fsnotify_put_group(mark->group);
 		mark->free_mark(mark);
+	}
 }
 
 /*
@@ -118,14 +121,14 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
  * The caller had better be holding a reference to this mark so we don't actually
  * do the final put under the mark->lock
  */
-void fsnotify_destroy_mark(struct fsnotify_mark *mark)
+void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark,
+				  struct fsnotify_group *group)
 {
-	struct fsnotify_group *group;
 	struct inode *inode = NULL;
 
-	spin_lock(&mark->lock);
+	BUG_ON(!mutex_is_locked(&group->mark_mutex));
 
-	group = mark->group;
+	spin_lock(&mark->lock);
 
 	/* something else already called this function on this mark */
 	if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) {
@@ -135,8 +138,6 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)
 
 	mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
 
-	spin_lock(&group->mark_lock);
-
 	if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
 		inode = mark->i.inode;
 		fsnotify_destroy_inode_mark(mark);
@@ -147,13 +148,22 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)
 
 	list_del_init(&mark->g_list);
 
-	spin_unlock(&group->mark_lock);
 	spin_unlock(&mark->lock);
 
+	if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED))
+		iput(inode);
+	/* release lock temporarily */
+	mutex_unlock(&group->mark_mutex);
+
 	spin_lock(&destroy_lock);
 	list_add(&mark->destroy_list, &destroy_list);
 	spin_unlock(&destroy_lock);
 	wake_up(&destroy_waitq);
+	/*
+	 * We don't necessarily have a ref on mark from caller so the above destroy
+	 * may have actually freed it, unless this group provides a 'freeing_mark'
+	 * function which must be holding a reference.
+	 */
 
 	/*
 	 * Some groups like to know that marks are being freed.  This is a
@@ -175,21 +185,17 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)
 	 * is just a lazy update (and could be a perf win...)
 	 */
 
-	if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED))
-		iput(inode);
+	atomic_dec(&group->num_marks);
 
-	/*
-	 * We don't necessarily have a ref on mark from caller so the above iput
-	 * may have already destroyed it.  Don't touch from now on.
-	 */
+	mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
+}
 
-	/*
-	 * it's possible that this group tried to destroy itself, but this
-	 * this mark was simultaneously being freed by inode.  If that's the
-	 * case, we finish freeing the group here.
-	 */
-	if (unlikely(atomic_dec_and_test(&group->num_marks)))
-		fsnotify_final_destroy_group(group);
+void fsnotify_destroy_mark(struct fsnotify_mark *mark,
+			   struct fsnotify_group *group)
+{
+	mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
+	fsnotify_destroy_mark_locked(mark, group);
+	mutex_unlock(&group->mark_mutex);
 }
 
 void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask)
@@ -214,26 +220,26 @@ void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mas
  * These marks may be used for the fsnotify backend to determine which
  * event types should be delivered to which group.
  */
-int fsnotify_add_mark(struct fsnotify_mark *mark,
-		      struct fsnotify_group *group, struct inode *inode,
-		      struct vfsmount *mnt, int allow_dups)
+int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
+			     struct fsnotify_group *group, struct inode *inode,
+			     struct vfsmount *mnt, int allow_dups)
 {
 	int ret = 0;
 
 	BUG_ON(inode && mnt);
 	BUG_ON(!inode && !mnt);
+	BUG_ON(!mutex_is_locked(&group->mark_mutex));
 
 	/*
 	 * LOCKING ORDER!!!!
+	 * group->mark_mutex
 	 * mark->lock
-	 * group->mark_lock
 	 * inode->i_lock
 	 */
 	spin_lock(&mark->lock);
-	spin_lock(&group->mark_lock);
-
 	mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE;
 
+	fsnotify_get_group(group);
 	mark->group = group;
 	list_add(&mark->g_list, &group->marks_list);
 	atomic_inc(&group->num_marks);
@@ -251,11 +257,8 @@ int fsnotify_add_mark(struct fsnotify_mark *mark,
 		BUG();
 	}
 
-	spin_unlock(&group->mark_lock);
-
 	/* this will pin the object if appropriate */
 	fsnotify_set_mark_mask_locked(mark, mark->mask);
-
 	spin_unlock(&mark->lock);
 
 	if (inode)
@@ -265,10 +268,10 @@ int fsnotify_add_mark(struct fsnotify_mark *mark,
 err:
 	mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
 	list_del_init(&mark->g_list);
+	fsnotify_put_group(group);
 	mark->group = NULL;
 	atomic_dec(&group->num_marks);
 
-	spin_unlock(&group->mark_lock);
 	spin_unlock(&mark->lock);
 
 	spin_lock(&destroy_lock);
@@ -279,6 +282,16 @@ err:
 	return ret;
 }
 
+int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group,
+		      struct inode *inode, struct vfsmount *mnt, int allow_dups)
+{
+	int ret;
+	mutex_lock(&group->mark_mutex);
+	ret = fsnotify_add_mark_locked(mark, group, inode, mnt, allow_dups);
+	mutex_unlock(&group->mark_mutex);
+	return ret;
+}
+
 /*
  * clear any marks in a group in which mark->flags & flags is true
  */
@@ -286,22 +299,16 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
 					 unsigned int flags)
 {
 	struct fsnotify_mark *lmark, *mark;
-	LIST_HEAD(free_list);
 
-	spin_lock(&group->mark_lock);
+	mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
 	list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
 		if (mark->flags & flags) {
-			list_add(&mark->free_g_list, &free_list);
-			list_del_init(&mark->g_list);
 			fsnotify_get_mark(mark);
+			fsnotify_destroy_mark_locked(mark, group);
+			fsnotify_put_mark(mark);
 		}
 	}
-	spin_unlock(&group->mark_lock);
-
-	list_for_each_entry_safe(mark, lmark, &free_list, free_g_list) {
-		fsnotify_destroy_mark(mark);
-		fsnotify_put_mark(mark);
-	}
+	mutex_unlock(&group->mark_mutex);
 }
 
 /*
@@ -317,6 +324,8 @@ void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *ol
 	assert_spin_locked(&old->lock);
 	new->i.inode = old->i.inode;
 	new->m.mnt = old->m.mnt;
+	if (old->group)
+		fsnotify_get_group(old->group);
 	new->group = old->group;
 	new->mask = old->mask;
 	new->free_mark = old->free_mark;
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index c887b13..b3963d8 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -225,6 +225,7 @@ alloc_holder:
 	mutex_unlock(&group->notification_mutex);
 
 	wake_up(&group->notification_waitq);
+	kill_fasync(&group->fsn_fa, SIGIO, POLL_IN);
 	return return_event;
 }
 
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c
index b7b4b0e..4df58b8 100644
--- a/fs/notify/vfsmount_mark.c
+++ b/fs/notify/vfsmount_mark.c
@@ -46,8 +46,16 @@ void fsnotify_clear_marks_by_mount(struct vfsmount *mnt)
 	spin_unlock(&mnt->mnt_root->d_lock);
 
 	list_for_each_entry_safe(mark, lmark, &free_list, m.free_m_list) {
-		fsnotify_destroy_mark(mark);
+		struct fsnotify_group *group;
+
+		spin_lock(&mark->lock);
+		fsnotify_get_group(mark->group);
+		group = mark->group;
+		spin_unlock(&mark->lock);
+
+		fsnotify_destroy_mark(mark, group);
 		fsnotify_put_mark(mark);
+		fsnotify_put_group(group);
 	}
 }
 
@@ -88,8 +96,8 @@ void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark)
 {
 	struct vfsmount *mnt = mark->m.mnt;
 
+	BUG_ON(!mutex_is_locked(&mark->group->mark_mutex));
 	assert_spin_locked(&mark->lock);
-	assert_spin_locked(&mark->group->mark_lock);
 
 	spin_lock(&mnt->mnt_root->d_lock);
 
@@ -151,8 +159,8 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
 
 	mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT;
 
+	BUG_ON(!mutex_is_locked(&group->mark_mutex));
 	assert_spin_locked(&mark->lock);
-	assert_spin_locked(&group->mark_lock);
 
 	spin_lock(&mnt->mnt_root->d_lock);
 
diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c
index 358273e..436f360 100644
--- a/fs/ntfs/namei.c
+++ b/fs/ntfs/namei.c
@@ -101,7 +101,7 @@
  * Locking: Caller must hold i_mutex on the directory.
  */
 static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
-		struct nameidata *nd)
+		unsigned int flags)
 {
 	ntfs_volume *vol = NTFS_SB(dir_ino->i_sb);
 	struct inode *dent_inode;
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index b341492..ecc8625 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -3185,6 +3185,12 @@ static void __exit exit_ntfs_fs(void)
 	ntfs_debug("Unregistering NTFS driver.");
 
 	unregister_filesystem(&ntfs_fs_type);
+
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(ntfs_big_inode_cache);
 	kmem_cache_destroy(ntfs_inode_cache);
 	kmem_cache_destroy(ntfs_name_cache);
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index a4e855e..f3f2d95 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -35,6 +35,7 @@
 #include <linux/time.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
+#include <linux/bitmap.h>
 
 #include "heartbeat.h"
 #include "tcp.h"
@@ -282,15 +283,6 @@ struct o2hb_bio_wait_ctxt {
 	int               wc_error;
 };
 
-static int o2hb_pop_count(void *map, int count)
-{
-	int i = -1, pop = 0;
-
-	while ((i = find_next_bit(map, count, i + 1)) < count)
-		pop++;
-	return pop;
-}
-
 static void o2hb_write_timeout(struct work_struct *work)
 {
 	int failed, quorum;
@@ -307,9 +299,9 @@ static void o2hb_write_timeout(struct work_struct *work)
 		spin_lock_irqsave(&o2hb_live_lock, flags);
 		if (test_bit(reg->hr_region_num, o2hb_quorum_region_bitmap))
 			set_bit(reg->hr_region_num, o2hb_failed_region_bitmap);
-		failed = o2hb_pop_count(&o2hb_failed_region_bitmap,
+		failed = bitmap_weight(o2hb_failed_region_bitmap,
 					O2NM_MAX_REGIONS);
-		quorum = o2hb_pop_count(&o2hb_quorum_region_bitmap,
+		quorum = bitmap_weight(o2hb_quorum_region_bitmap,
 					O2NM_MAX_REGIONS);
 		spin_unlock_irqrestore(&o2hb_live_lock, flags);
 
@@ -771,7 +763,7 @@ static void o2hb_set_quorum_device(struct o2hb_region *reg)
 	 * If global heartbeat active, unpin all regions if the
 	 * region count > CUT_OFF
 	 */
-	if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
+	if (bitmap_weight(o2hb_quorum_region_bitmap,
 			   O2NM_MAX_REGIONS) > O2HB_PIN_CUT_OFF)
 		o2hb_region_unpin(NULL);
 unlock:
@@ -956,23 +948,9 @@ out:
 	return changed;
 }
 
-/* This could be faster if we just implmented a find_last_bit, but I
- * don't think the circumstances warrant it. */
-static int o2hb_highest_node(unsigned long *nodes,
-			     int numbits)
+static int o2hb_highest_node(unsigned long *nodes, int numbits)
 {
-	int highest, node;
-
-	highest = numbits;
-	node = -1;
-	while ((node = find_next_bit(nodes, numbits, node + 1)) != -1) {
-		if (node >= numbits)
-			break;
-
-		highest = node;
-	}
-
-	return highest;
+	return find_last_bit(nodes, numbits);
 }
 
 static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
@@ -1833,7 +1811,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
 	live_threshold = O2HB_LIVE_THRESHOLD;
 	if (o2hb_global_heartbeat_active()) {
 		spin_lock(&o2hb_live_lock);
-		if (o2hb_pop_count(&o2hb_region_bitmap, O2NM_MAX_REGIONS) == 1)
+		if (bitmap_weight(o2hb_region_bitmap, O2NM_MAX_REGIONS) == 1)
 			live_threshold <<= 1;
 		spin_unlock(&o2hb_live_lock);
 	}
@@ -2184,7 +2162,7 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
 	if (!o2hb_dependent_users)
 		goto unlock;
 
-	if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
+	if (bitmap_weight(o2hb_quorum_region_bitmap,
 			   O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF)
 		o2hb_region_pin(NULL);
 
@@ -2478,7 +2456,7 @@ static int o2hb_region_inc_user(const char *region_uuid)
 	if (o2hb_dependent_users > 1)
 		goto unlock;
 
-	if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
+	if (bitmap_weight(o2hb_quorum_region_bitmap,
 			   O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF)
 		ret = o2hb_region_pin(NULL);
 
diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c
index e5ba348..8db4b58 100644
--- a/fs/ocfs2/dcache.c
+++ b/fs/ocfs2/dcache.c
@@ -49,14 +49,13 @@ void ocfs2_dentry_attach_gen(struct dentry *dentry)
 }
 
 
-static int ocfs2_dentry_revalidate(struct dentry *dentry,
-				   struct nameidata *nd)
+static int ocfs2_dentry_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct inode *inode;
 	int ret = 0;    /* if all else fails, just return false */
 	struct ocfs2_super *osb;
 
-	if (nd && nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	inode = dentry->d_inode;
@@ -170,13 +169,11 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode,
 				      u64 parent_blkno,
 				      int skip_unhashed)
 {
-	struct list_head *p;
-	struct dentry *dentry = NULL;
+	struct hlist_node *p;
+	struct dentry *dentry;
 
 	spin_lock(&inode->i_lock);
-	list_for_each(p, &inode->i_dentry) {
-		dentry = list_entry(p, struct dentry, d_alias);
-
+	hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
 		spin_lock(&dentry->d_lock);
 		if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
 			trace_ocfs2_find_local_alias(dentry->d_name.len,
@@ -184,16 +181,13 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode,
 
 			dget_dlock(dentry);
 			spin_unlock(&dentry->d_lock);
-			break;
+			spin_unlock(&inode->i_lock);
+			return dentry;
 		}
 		spin_unlock(&dentry->d_lock);
-
-		dentry = NULL;
 	}
-
 	spin_unlock(&inode->i_lock);
-
-	return dentry;
+	return NULL;
 }
 
 DEFINE_SPINLOCK(dentry_attach_lock);
diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
index e31d6ae..16b712d 100644
--- a/fs/ocfs2/dlmfs/dlmfs.c
+++ b/fs/ocfs2/dlmfs/dlmfs.c
@@ -526,7 +526,7 @@ bail:
 static int dlmfs_create(struct inode *dir,
 			struct dentry *dentry,
 			umode_t mode,
-			struct nameidata *nd)
+			bool excl)
 {
 	int status = 0;
 	struct inode *inode;
@@ -691,6 +691,11 @@ static void __exit exit_dlmfs_fs(void)
 	flush_workqueue(user_dlm_worker);
 	destroy_workqueue(user_dlm_worker);
 
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(dlmfs_inode_cache);
 
 	bdi_destroy(&dlmfs_backing_dev_info);
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 061591a..48d2989 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1950,7 +1950,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
 	if (ret < 0)
 		mlog_errno(ret);
 
-	if (file->f_flags & O_SYNC)
+	if (file && (file->f_flags & O_SYNC))
 		handle->h_sync = 1;
 
 	ocfs2_commit_trans(osb, handle);
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
index 210c352..a9f78c7 100644
--- a/fs/ocfs2/localalloc.c
+++ b/fs/ocfs2/localalloc.c
@@ -784,14 +784,10 @@ bail:
 
 static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc)
 {
-	int i;
-	u8 *buffer;
-	u32 count = 0;
+	u32 count;
 	struct ocfs2_local_alloc *la = OCFS2_LOCAL_ALLOC(alloc);
 
-	buffer = la->la_bitmap;
-	for (i = 0; i < le16_to_cpu(la->la_size); i++)
-		count += hweight8(buffer[i]);
+	count = memweight(la->la_bitmap, le16_to_cpu(la->la_size));
 
 	trace_ocfs2_local_alloc_count_bits(count);
 	return count;
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 9f39c64..f1fd074 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -98,7 +98,7 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
 #define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))
 
 static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
-				   struct nameidata *nd)
+				   unsigned int flags)
 {
 	int status;
 	u64 blkno;
@@ -618,7 +618,7 @@ static int ocfs2_mkdir(struct inode *dir,
 static int ocfs2_create(struct inode *dir,
 			struct dentry *dentry,
 			umode_t mode,
-			struct nameidata *nd)
+			bool excl)
 {
 	int ret;
 
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 68f4541..0e91ec2 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1818,6 +1818,11 @@ static int ocfs2_initialize_mem_caches(void)
 
 static void ocfs2_free_mem_caches(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	if (ocfs2_inode_cachep)
 		kmem_cache_destroy(ocfs2_inode_cachep);
 	ocfs2_inode_cachep = NULL;
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c
index f00576e..fb5b3ff 100644
--- a/fs/omfs/dir.c
+++ b/fs/omfs/dir.c
@@ -285,13 +285,13 @@ static int omfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 }
 
 static int omfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		struct nameidata *nd)
+		bool excl)
 {
 	return omfs_add_node(dir, dentry, mode | S_IFREG);
 }
 
 static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry,
-				  struct nameidata *nd)
+				  unsigned int flags)
 {
 	struct buffer_head *bh;
 	struct inode *inode = NULL;
diff --git a/fs/open.c b/fs/open.c
index d6c79a0..ecea9f4 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -667,10 +667,9 @@ int open_check_o_direct(struct file *f)
 	return 0;
 }
 
-static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
-				   struct file *f,
-				   int (*open)(struct inode *, struct file *),
-				   const struct cred *cred)
+static int do_dentry_open(struct file *f,
+			  int (*open)(struct inode *, struct file *),
+			  const struct cred *cred)
 {
 	static const struct file_operations empty_fops = {};
 	struct inode *inode;
@@ -682,9 +681,9 @@ static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 	if (unlikely(f->f_flags & O_PATH))
 		f->f_mode = FMODE_PATH;
 
-	inode = dentry->d_inode;
+	inode = f->f_path.dentry->d_inode;
 	if (f->f_mode & FMODE_WRITE) {
-		error = __get_file_write_access(inode, mnt);
+		error = __get_file_write_access(inode, f->f_path.mnt);
 		if (error)
 			goto cleanup_file;
 		if (!special_file(inode->i_mode))
@@ -692,14 +691,12 @@ static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 	}
 
 	f->f_mapping = inode->i_mapping;
-	f->f_path.dentry = dentry;
-	f->f_path.mnt = mnt;
 	f->f_pos = 0;
 	file_sb_list_add(f, inode->i_sb);
 
 	if (unlikely(f->f_mode & FMODE_PATH)) {
 		f->f_op = &empty_fops;
-		return f;
+		return 0;
 	}
 
 	f->f_op = fops_get(inode->i_fop);
@@ -726,10 +723,11 @@ static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 
 	file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
 
-	return f;
+	return 0;
 
 cleanup_all:
 	fops_put(f->f_op);
+	file_sb_list_del(f);
 	if (f->f_mode & FMODE_WRITE) {
 		put_write_access(inode);
 		if (!special_file(inode->i_mode)) {
@@ -740,118 +738,60 @@ cleanup_all:
 			 * here, so just reset the state.
 			 */
 			file_reset_write(f);
-			mnt_drop_write(mnt);
+			mnt_drop_write(f->f_path.mnt);
 		}
 	}
-	file_sb_list_del(f);
-	f->f_path.dentry = NULL;
-	f->f_path.mnt = NULL;
 cleanup_file:
-	dput(dentry);
-	mntput(mnt);
-	return ERR_PTR(error);
-}
-
-static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
-				struct file *f,
-				int (*open)(struct inode *, struct file *),
-				const struct cred *cred)
-{
-	struct file *res = do_dentry_open(dentry, mnt, f, open, cred);
-	if (!IS_ERR(res)) {
-		int error = open_check_o_direct(f);
-		if (error) {
-			fput(res);
-			res = ERR_PTR(error);
-		}
-	} else {
-		put_filp(f);
-	}
-	return res;
+	path_put(&f->f_path);
+	f->f_path.mnt = NULL;
+	f->f_path.dentry = NULL;
+	return error;
 }
 
 /**
- * lookup_instantiate_filp - instantiates the open intent filp
- * @nd: pointer to nameidata
+ * finish_open - finish opening a file
+ * @od: opaque open data
  * @dentry: pointer to dentry
  * @open: open callback
  *
- * Helper for filesystems that want to use lookup open intents and pass back
- * a fully instantiated struct file to the caller.
- * This function is meant to be called from within a filesystem's
- * lookup method.
- * Beware of calling it for non-regular files! Those ->open methods might block
- * (e.g. in fifo_open), leaving you with parent locked (and in case of fifo,
- * leading to a deadlock, as nobody can open that fifo anymore, because
- * another process to open fifo will block on locked parent when doing lookup).
- * Note that in case of error, nd->intent.open.file is destroyed, but the
- * path information remains valid.
+ * This can be used to finish opening a file passed to i_op->atomic_open().
+ *
  * If the open callback is set to NULL, then the standard f_op->open()
  * filesystem callback is substituted.
  */
-struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
-		int (*open)(struct inode *, struct file *))
+int finish_open(struct file *file, struct dentry *dentry,
+		int (*open)(struct inode *, struct file *),
+		int *opened)
 {
-	const struct cred *cred = current_cred();
+	int error;
+	BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
 
-	if (IS_ERR(nd->intent.open.file))
-		goto out;
-	if (IS_ERR(dentry))
-		goto out_err;
-	nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
-					     nd->intent.open.file,
-					     open, cred);
-out:
-	return nd->intent.open.file;
-out_err:
-	release_open_intent(nd);
-	nd->intent.open.file = ERR_CAST(dentry);
-	goto out;
+	mntget(file->f_path.mnt);
+	file->f_path.dentry = dget(dentry);
+
+	error = do_dentry_open(file, open, current_cred());
+	if (!error)
+		*opened |= FILE_OPENED;
+
+	return error;
 }
-EXPORT_SYMBOL_GPL(lookup_instantiate_filp);
+EXPORT_SYMBOL(finish_open);
 
 /**
- * nameidata_to_filp - convert a nameidata to an open filp.
- * @nd: pointer to nameidata
- * @flags: open flags
+ * finish_no_open - finish ->atomic_open() without opening the file
  *
- * Note that this function destroys the original nameidata
+ * @od: opaque open data
+ * @dentry: dentry or NULL (as returned from ->lookup())
+ *
+ * This can be used to set the result of a successful lookup in ->atomic_open().
+ * The filesystem's atomic_open() method shall return NULL after calling this.
  */
-struct file *nameidata_to_filp(struct nameidata *nd)
+int finish_no_open(struct file *file, struct dentry *dentry)
 {
-	const struct cred *cred = current_cred();
-	struct file *filp;
-
-	/* Pick up the filp from the open intent */
-	filp = nd->intent.open.file;
-
-	/* Has the filesystem initialised the file for us? */
-	if (filp->f_path.dentry != NULL) {
-		nd->intent.open.file = NULL;
-	} else {
-		struct file *res;
-
-		path_get(&nd->path);
-		res = do_dentry_open(nd->path.dentry, nd->path.mnt,
-				     filp, NULL, cred);
-		if (!IS_ERR(res)) {
-			int error;
-
-			nd->intent.open.file = NULL;
-			BUG_ON(res != filp);
-
-			error = open_check_o_direct(filp);
-			if (error) {
-				fput(filp);
-				filp = ERR_PTR(error);
-			}
-		} else {
-			/* Allow nd->intent.open.file to be recycled */
-			filp = res;
-		}
-	}
-	return filp;
+	file->f_path.dentry = dentry;
+	return 1;
 }
+EXPORT_SYMBOL(finish_no_open);
 
 /*
  * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an
@@ -877,7 +817,20 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
 	}
 
 	f->f_flags = flags;
-	return __dentry_open(dentry, mnt, f, NULL, cred);
+	f->f_path.mnt = mnt;
+	f->f_path.dentry = dentry;
+	error = do_dentry_open(f, NULL, cred);
+	if (!error) {
+		error = open_check_o_direct(f);
+		if (error) {
+			fput(f);
+			f = ERR_PTR(error);
+		}
+	} else { 
+		put_filp(f);
+		f = ERR_PTR(error);
+	}
+	return f;
 }
 EXPORT_SYMBOL(dentry_open);
 
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index bc49c97..2ad080f 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -170,13 +170,13 @@ static const struct file_operations openprom_operations = {
 	.llseek		= generic_file_llseek,
 };
 
-static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, struct nameidata *);
+static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int);
 
 static const struct inode_operations openprom_inode_operations = {
 	.lookup		= openpromfs_lookup,
 };
 
-static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	struct op_inode_info *ent_oi, *oi = OP_I(dir);
 	struct device_node *dp, *child;
@@ -463,6 +463,11 @@ static int __init init_openprom_fs(void)
 static void __exit exit_openprom_fs(void)
 {
 	unregister_filesystem(&openprom_fs_type);
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(op_inode_cachep);
 }
 
diff --git a/fs/pipe.c b/fs/pipe.c
index 49c1065..95cbd6b 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -224,7 +224,7 @@ static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
  *	and the caller has to be careful not to fault before calling
  *	the unmap function.
  *
- *	Note that this function occupies KM_USER0 if @atomic != 0.
+ *	Note that this function calls kmap_atomic() if @atomic != 0.
  */
 void *generic_pipe_buf_map(struct pipe_inode_info *pipe,
 			   struct pipe_buffer *buf, int atomic)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 437195f..2772208 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1427,16 +1427,19 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
 static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct inode *inode = dentry->d_inode;
+	struct path path;
 	int error = -EACCES;
 
-	/* We don't need a base pointer in the /proc filesystem */
-	path_put(&nd->path);
-
 	/* Are we allowed to snoop on the tasks file descriptors? */
 	if (!proc_fd_access_allowed(inode))
 		goto out;
 
-	error = PROC_I(inode)->op.proc_get_link(dentry, &nd->path);
+	error = PROC_I(inode)->op.proc_get_link(dentry, &path);
+	if (error)
+		goto out;
+
+	nd_jump_link(nd, &path);
+	return NULL;
 out:
 	return ERR_PTR(error);
 }
@@ -1601,13 +1604,13 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
  * made this apply to all per process world readable and executable
  * directories.
  */
-int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
+int pid_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct inode *inode;
 	struct task_struct *task;
 	const struct cred *cred;
 
-	if (nd && nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	inode = dentry->d_inode;
@@ -1781,7 +1784,7 @@ static int proc_fd_link(struct dentry *dentry, struct path *path)
 	return proc_fd_info(dentry->d_inode, path, NULL);
 }
 
-static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct inode *inode;
 	struct task_struct *task;
@@ -1789,7 +1792,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
 	struct files_struct *files;
 	const struct cred *cred;
 
-	if (nd && nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	inode = dentry->d_inode;
@@ -1868,7 +1871,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir,
 	d_set_d_op(dentry, &tid_fd_dentry_operations);
 	d_add(dentry, inode);
 	/* Close the race of the process dying before we return the dentry */
-	if (tid_fd_revalidate(dentry, NULL))
+	if (tid_fd_revalidate(dentry, 0))
 		error = NULL;
 
  out:
@@ -1956,7 +1959,7 @@ out_no_task:
 }
 
 static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
-				    struct nameidata *nd)
+				    unsigned int flags)
 {
 	return proc_lookupfd_common(dir, dentry, proc_fd_instantiate);
 }
@@ -2003,7 +2006,7 @@ static int dname_to_vma_addr(struct dentry *dentry,
 	return 0;
 }
 
-static int map_files_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	unsigned long vm_start, vm_end;
 	bool exact_vma_exists = false;
@@ -2013,7 +2016,7 @@ static int map_files_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 	struct inode *inode;
 	int status = 0;
 
-	if (nd && nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	if (!capable(CAP_SYS_ADMIN)) {
@@ -2145,7 +2148,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
 }
 
 static struct dentry *proc_map_files_lookup(struct inode *dir,
-		struct dentry *dentry, struct nameidata *nd)
+		struct dentry *dentry, unsigned int flags)
 {
 	unsigned long vm_start, vm_end;
 	struct vm_area_struct *vma;
@@ -2371,7 +2374,7 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
 	d_set_d_op(dentry, &tid_fd_dentry_operations);
 	d_add(dentry, inode);
 	/* Close the race of the process dying before we return the dentry */
-	if (tid_fd_revalidate(dentry, NULL))
+	if (tid_fd_revalidate(dentry, 0))
 		error = NULL;
 
  out:
@@ -2380,7 +2383,7 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
 
 static struct dentry *proc_lookupfdinfo(struct inode *dir,
 					struct dentry *dentry,
-					struct nameidata *nd)
+					unsigned int flags)
 {
 	return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);
 }
@@ -2430,7 +2433,7 @@ static struct dentry *proc_pident_instantiate(struct inode *dir,
 	d_set_d_op(dentry, &pid_dentry_operations);
 	d_add(dentry, inode);
 	/* Close the race of the process dying before we return the dentry */
-	if (pid_revalidate(dentry, NULL))
+	if (pid_revalidate(dentry, 0))
 		error = NULL;
 out:
 	return error;
@@ -2630,7 +2633,7 @@ static const struct file_operations proc_attr_dir_operations = {
 };
 
 static struct dentry *proc_attr_dir_lookup(struct inode *dir,
-				struct dentry *dentry, struct nameidata *nd)
+				struct dentry *dentry, unsigned int flags)
 {
 	return proc_pident_lookup(dir, dentry,
 				  attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
@@ -3114,7 +3117,8 @@ static const struct file_operations proc_tgid_base_operations = {
 	.llseek		= default_llseek,
 };
 
-static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
+static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
 	return proc_pident_lookup(dir, dentry,
 				  tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
 }
@@ -3237,13 +3241,13 @@ static struct dentry *proc_pid_instantiate(struct inode *dir,
 
 	d_add(dentry, inode);
 	/* Close the race of the process dying before we return the dentry */
-	if (pid_revalidate(dentry, NULL))
+	if (pid_revalidate(dentry, 0))
 		error = NULL;
 out:
 	return error;
 }
 
-struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
 	struct dentry *result;
 	struct task_struct *task;
@@ -3470,7 +3474,8 @@ static int proc_tid_base_readdir(struct file * filp,
 				   tid_base_stuff,ARRAY_SIZE(tid_base_stuff));
 }
 
-static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
+static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
 	return proc_pident_lookup(dir, dentry,
 				  tid_base_stuff, ARRAY_SIZE(tid_base_stuff));
 }
@@ -3508,13 +3513,13 @@ static struct dentry *proc_task_instantiate(struct inode *dir,
 
 	d_add(dentry, inode);
 	/* Close the race of the process dying before we return the dentry */
-	if (pid_revalidate(dentry, NULL))
+	if (pid_revalidate(dentry, 0))
 		error = NULL;
 out:
 	return error;
 }
 
-static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
 	struct dentry *result = ERR_PTR(-ENOENT);
 	struct task_struct *task;
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 2edf34f..b3647fe 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -446,7 +446,7 @@ out_unlock:
 }
 
 struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry,
-		struct nameidata *nd)
+		unsigned int flags)
 {
 	return proc_lookup_de(PDE(dir), dir, dentry);
 }
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index eca4aca..e1167a1 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -106,7 +106,7 @@ void pde_users_dec(struct proc_dir_entry *pde);
 
 extern spinlock_t proc_subdir_lock;
 
-struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *);
+struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int);
 int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir);
 unsigned long task_vsize(struct mm_struct *);
 unsigned long task_statm(struct mm_struct *,
@@ -132,7 +132,7 @@ int proc_remount(struct super_block *sb, int *flags, char *data);
  * of the /proc/<pid> subdirectories.
  */
 int proc_readdir(struct file *, void *, filldir_t);
-struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *);
+struct dentry *proc_lookup(struct inode *, struct dentry *, unsigned int);
 
 
 
@@ -142,7 +142,7 @@ typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
 int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
 	const char *name, int len,
 	instantiate_t instantiate, struct task_struct *task, const void *ptr);
-int pid_revalidate(struct dentry *dentry, struct nameidata *nd);
+int pid_revalidate(struct dentry *dentry, unsigned int flags);
 struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task);
 extern const struct dentry_operations pid_dentry_operations;
 int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index 0d9e23a..b178ed7 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -56,7 +56,7 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
 	d_set_d_op(dentry, &pid_dentry_operations);
 	d_add(dentry, inode);
 	/* Close the race of the process dying before we return the dentry */
-	if (pid_revalidate(dentry, NULL))
+	if (pid_revalidate(dentry, 0))
 		error = NULL;
 out:
 	return error;
@@ -140,7 +140,7 @@ const struct file_operations proc_ns_dir_operations = {
 };
 
 static struct dentry *proc_ns_dir_lookup(struct inode *dir,
-				struct dentry *dentry, struct nameidata *nd)
+				struct dentry *dentry, unsigned int flags)
 {
 	struct dentry *error;
 	struct task_struct *task = get_proc_task(dir);
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
index 06e1cc1..fe72cd0 100644
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -119,7 +119,7 @@ static struct net *get_proc_task_net(struct inode *dir)
 }
 
 static struct dentry *proc_tgid_net_lookup(struct inode *dir,
-		struct dentry *dentry, struct nameidata *nd)
+		struct dentry *dentry, unsigned int flags)
 {
 	struct dentry *de;
 	struct net *net;
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 3476bca..dfafeb2 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -433,7 +433,7 @@ static struct ctl_table_header *grab_header(struct inode *inode)
 }
 
 static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
-					struct nameidata *nd)
+					unsigned int flags)
 {
 	struct ctl_table_header *head = grab_header(dir);
 	struct ctl_table_header *h = NULL;
@@ -794,9 +794,9 @@ static const struct inode_operations proc_sys_dir_operations = {
 	.getattr	= proc_sys_getattr,
 };
 
-static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int proc_sys_revalidate(struct dentry *dentry, unsigned int flags)
 {
-	if (nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 	return !PROC_I(dentry->d_inode)->sysctl->unregistering;
 }
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 7c30fce..568b202 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -200,13 +200,12 @@ static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct
 	return 0;
 }
 
-static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags)
 {
-	if (!proc_lookup(dir, dentry, nd)) {
+	if (!proc_lookup(dir, dentry, flags))
 		return NULL;
-	}
 	
-	return proc_pid_lookup(dir, dentry, nd);
+	return proc_pid_lookup(dir, dentry, flags);
 }
 
 static int proc_root_readdir(struct file * filp,
diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c
index 5e289a7..5fe34c3 100644
--- a/fs/proc_namespace.c
+++ b/fs/proc_namespace.c
@@ -17,7 +17,7 @@
 
 static unsigned mounts_poll(struct file *file, poll_table *wait)
 {
-	struct proc_mounts *p = file->private_data;
+	struct proc_mounts *p = proc_mounts(file->private_data);
 	struct mnt_namespace *ns = p->ns;
 	unsigned res = POLLIN | POLLRDNORM;
 
@@ -121,7 +121,7 @@ out:
 
 static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
 {
-	struct proc_mounts *p = m->private;
+	struct proc_mounts *p = proc_mounts(m);
 	struct mount *r = real_mount(mnt);
 	struct super_block *sb = mnt->mnt_sb;
 	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
@@ -268,7 +268,6 @@ static int mounts_open_common(struct inode *inode, struct file *file,
 	if (ret)
 		goto err_free;
 
-	p->m.private = p;
 	p->ns = ns;
 	p->root = root;
 	p->m.poll_event = ns->event;
@@ -288,7 +287,7 @@ static int mounts_open_common(struct inode *inode, struct file *file,
 
 static int mounts_release(struct inode *inode, struct file *file)
 {
-	struct proc_mounts *p = file->private_data;
+	struct proc_mounts *p = proc_mounts(file->private_data);
 	path_put(&p->root);
 	put_mnt_ns(p->ns);
 	return seq_release(inode, file);
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 23ade26..d044de6 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -12,6 +12,13 @@ config PSTORE
 	   If you don't have a platform persistent store driver,
 	   say N.
 
+config PSTORE_CONSOLE
+	bool "Log kernel console messages"
+	depends on PSTORE
+	help
+	  When the option is enabled, pstore will log all kernel
+	  messages, even if no oops or panic happened.
+
 config PSTORE_RAM
 	tristate "Log panic/oops to a RAM buffer"
 	depends on PSTORE
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 11a2aa2..45bff54 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -212,6 +212,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
 	case PSTORE_TYPE_DMESG:
 		sprintf(name, "dmesg-%s-%lld", psname, id);
 		break;
+	case PSTORE_TYPE_CONSOLE:
+		sprintf(name, "console-%s", psname);
+		break;
 	case PSTORE_TYPE_MCE:
 		sprintf(name, "mce-%s-%lld", psname, id);
 		break;
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 03ce7a9..6b3ff04 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -1,6 +1,7 @@
 /*
  * Persistent Storage - platform driver interface parts.
  *
+ * Copyright (C) 2007-2008 Google, Inc.
  * Copyright (C) 2010 Intel Corporation <tony.luck@intel.com>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -22,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/kmsg_dump.h>
+#include <linux/console.h>
 #include <linux/module.h>
 #include <linux/pstore.h>
 #include <linux/string.h>
@@ -29,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
+#include <linux/jiffies.h>
 #include <linux/workqueue.h>
 
 #include "internal.h"
@@ -38,7 +41,12 @@
  * whether the system is actually still running well enough
  * to let someone see the entry
  */
-#define	PSTORE_INTERVAL	(60 * HZ)
+static int pstore_update_ms = -1;
+module_param_named(update_ms, pstore_update_ms, int, 0600);
+MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content "
+		 "(default is -1, which means runtime updates are disabled; "
+		 "enabling this option is not safe, it may lead to further "
+		 "corruption on Oopses)");
 
 static int pstore_new_entry;
 
@@ -146,6 +154,40 @@ static struct kmsg_dumper pstore_dumper = {
 	.dump = pstore_dump,
 };
 
+#ifdef CONFIG_PSTORE_CONSOLE
+static void pstore_console_write(struct console *con, const char *s, unsigned c)
+{
+	const char *e = s + c;
+
+	while (s < e) {
+		unsigned long flags;
+
+		if (c > psinfo->bufsize)
+			c = psinfo->bufsize;
+		spin_lock_irqsave(&psinfo->buf_lock, flags);
+		memcpy(psinfo->buf, s, c);
+		psinfo->write(PSTORE_TYPE_CONSOLE, 0, NULL, 0, c, psinfo);
+		spin_unlock_irqrestore(&psinfo->buf_lock, flags);
+		s += c;
+		c = e - s;
+	}
+}
+
+static struct console pstore_console = {
+	.name	= "pstore",
+	.write	= pstore_console_write,
+	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
+	.index	= -1,
+};
+
+static void pstore_register_console(void)
+{
+	register_console(&pstore_console);
+}
+#else
+static void pstore_register_console(void) {}
+#endif
+
 /*
  * platform specific persistent storage driver registers with
  * us here. If pstore is already mounted, call the platform
@@ -183,9 +225,13 @@ int pstore_register(struct pstore_info *psi)
 		pstore_get_records(0);
 
 	kmsg_dump_register(&pstore_dumper);
+	pstore_register_console();
 
-	pstore_timer.expires = jiffies + PSTORE_INTERVAL;
-	add_timer(&pstore_timer);
+	if (pstore_update_ms >= 0) {
+		pstore_timer.expires = jiffies +
+			msecs_to_jiffies(pstore_update_ms);
+		add_timer(&pstore_timer);
+	}
 
 	return 0;
 }
@@ -244,7 +290,7 @@ static void pstore_timefunc(unsigned long dummy)
 		schedule_work(&pstore_work);
 	}
 
-	mod_timer(&pstore_timer, jiffies + PSTORE_INTERVAL);
+	mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms));
 }
 
 module_param(backend, charp, 0444);
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 453030f..58b93fb 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -41,6 +41,10 @@ module_param(record_size, ulong, 0400);
 MODULE_PARM_DESC(record_size,
 		"size of each dump done on oops/panic");
 
+static ulong ramoops_console_size = MIN_MEM_SIZE;
+module_param_named(console_size, ramoops_console_size, ulong, 0400);
+MODULE_PARM_DESC(console_size, "size of kernel console log");
+
 static ulong mem_address;
 module_param(mem_address, ulong, 0400);
 MODULE_PARM_DESC(mem_address,
@@ -63,14 +67,17 @@ MODULE_PARM_DESC(ramoops_ecc,
 
 struct ramoops_context {
 	struct persistent_ram_zone **przs;
+	struct persistent_ram_zone *cprz;
 	phys_addr_t phys_addr;
 	unsigned long size;
 	size_t record_size;
+	size_t console_size;
 	int dump_oops;
 	bool ecc;
-	unsigned int count;
-	unsigned int max_count;
-	unsigned int read_count;
+	unsigned int max_dump_cnt;
+	unsigned int dump_write_cnt;
+	unsigned int dump_read_cnt;
+	unsigned int console_read_cnt;
 	struct pstore_info pstore;
 };
 
@@ -81,10 +88,38 @@ static int ramoops_pstore_open(struct pstore_info *psi)
 {
 	struct ramoops_context *cxt = psi->data;
 
-	cxt->read_count = 0;
+	cxt->dump_read_cnt = 0;
+	cxt->console_read_cnt = 0;
 	return 0;
 }
 
+static struct persistent_ram_zone *
+ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
+		     u64 *id,
+		     enum pstore_type_id *typep, enum pstore_type_id type,
+		     bool update)
+{
+	struct persistent_ram_zone *prz;
+	int i = (*c)++;
+
+	if (i >= max)
+		return NULL;
+
+	prz = przs[i];
+
+	if (update) {
+		/* Update old/shadowed buffer. */
+		persistent_ram_save_old(prz);
+		if (!persistent_ram_old_size(prz))
+			return NULL;
+	}
+
+	*typep = type;
+	*id = i;
+
+	return prz;
+}
+
 static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
 				   struct timespec *time,
 				   char **buf,
@@ -94,20 +129,19 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
 	struct ramoops_context *cxt = psi->data;
 	struct persistent_ram_zone *prz;
 
-	if (cxt->read_count >= cxt->max_count)
-		return -EINVAL;
+	prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
+				   cxt->max_dump_cnt, id, type,
+				   PSTORE_TYPE_DMESG, 1);
+	if (!prz)
+		prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
+					   1, id, type, PSTORE_TYPE_CONSOLE, 0);
+	if (!prz)
+		return 0;
 
-	*id = cxt->read_count++;
-	prz = cxt->przs[*id];
-
-	/* Only supports dmesg output so far. */
-	*type = PSTORE_TYPE_DMESG;
 	/* TODO(kees): Bogus time for the moment. */
 	time->tv_sec = 0;
 	time->tv_nsec = 0;
 
-	/* Update old/shadowed buffer. */
-	persistent_ram_save_old(prz);
 	size = persistent_ram_old_size(prz);
 	*buf = kmalloc(size, GFP_KERNEL);
 	if (*buf == NULL)
@@ -141,10 +175,16 @@ static int ramoops_pstore_write(enum pstore_type_id type,
 				size_t size, struct pstore_info *psi)
 {
 	struct ramoops_context *cxt = psi->data;
-	struct persistent_ram_zone *prz = cxt->przs[cxt->count];
+	struct persistent_ram_zone *prz = cxt->przs[cxt->dump_write_cnt];
 	size_t hlen;
 
-	/* Currently ramoops is designed to only store dmesg dumps. */
+	if (type == PSTORE_TYPE_CONSOLE) {
+		if (!cxt->cprz)
+			return -ENOMEM;
+		persistent_ram_write(cxt->cprz, cxt->pstore.buf, size);
+		return 0;
+	}
+
 	if (type != PSTORE_TYPE_DMESG)
 		return -EINVAL;
 
@@ -172,7 +212,7 @@ static int ramoops_pstore_write(enum pstore_type_id type,
 		size = prz->buffer_size - hlen;
 	persistent_ram_write(prz, cxt->pstore.buf, size);
 
-	cxt->count = (cxt->count + 1) % cxt->max_count;
+	cxt->dump_write_cnt = (cxt->dump_write_cnt + 1) % cxt->max_dump_cnt;
 
 	return 0;
 }
@@ -181,12 +221,23 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id,
 				struct pstore_info *psi)
 {
 	struct ramoops_context *cxt = psi->data;
+	struct persistent_ram_zone *prz;
 
-	if (id >= cxt->max_count)
+	switch (type) {
+	case PSTORE_TYPE_DMESG:
+		if (id >= cxt->max_dump_cnt)
+			return -EINVAL;
+		prz = cxt->przs[id];
+		break;
+	case PSTORE_TYPE_CONSOLE:
+		prz = cxt->cprz;
+		break;
+	default:
 		return -EINVAL;
+	}
 
-	persistent_ram_free_old(cxt->przs[id]);
-	persistent_ram_zap(cxt->przs[id]);
+	persistent_ram_free_old(prz);
+	persistent_ram_zap(prz);
 
 	return 0;
 }
@@ -202,73 +253,142 @@ static struct ramoops_context oops_cxt = {
 	},
 };
 
-static int __init ramoops_probe(struct platform_device *pdev)
+static void ramoops_free_przs(struct ramoops_context *cxt)
+{
+	int i;
+
+	if (!cxt->przs)
+		return;
+
+	for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++)
+		persistent_ram_free(cxt->przs[i]);
+	kfree(cxt->przs);
+}
+
+static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
+			      phys_addr_t *paddr, size_t dump_mem_sz)
+{
+	int err = -ENOMEM;
+	int i;
+
+	if (!cxt->record_size)
+		return 0;
+
+	cxt->max_dump_cnt = dump_mem_sz / cxt->record_size;
+	if (!cxt->max_dump_cnt)
+		return -ENOMEM;
+
+	cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt,
+			     GFP_KERNEL);
+	if (!cxt->przs) {
+		dev_err(dev, "failed to initialize a prz array for dumps\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < cxt->max_dump_cnt; i++) {
+		size_t sz = cxt->record_size;
+
+		cxt->przs[i] = persistent_ram_new(*paddr, sz, cxt->ecc);
+		if (IS_ERR(cxt->przs[i])) {
+			err = PTR_ERR(cxt->przs[i]);
+			dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
+				sz, (unsigned long long)*paddr, err);
+			goto fail_prz;
+		}
+		*paddr += sz;
+	}
+
+	return 0;
+fail_prz:
+	ramoops_free_przs(cxt);
+	return err;
+}
+
+static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
+			    struct persistent_ram_zone **prz,
+			    phys_addr_t *paddr, size_t sz)
+{
+	if (!sz)
+		return 0;
+
+	if (*paddr + sz > *paddr + cxt->size)
+		return -ENOMEM;
+
+	*prz = persistent_ram_new(*paddr, sz, cxt->ecc);
+	if (IS_ERR(*prz)) {
+		int err = PTR_ERR(*prz);
+
+		dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
+			sz, (unsigned long long)*paddr, err);
+		return err;
+	}
+
+	persistent_ram_zap(*prz);
+
+	*paddr += sz;
+
+	return 0;
+}
+
+static int __devinit ramoops_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct ramoops_platform_data *pdata = pdev->dev.platform_data;
 	struct ramoops_context *cxt = &oops_cxt;
+	size_t dump_mem_sz;
+	phys_addr_t paddr;
 	int err = -EINVAL;
-	int i;
 
 	/* Only a single ramoops area allowed at a time, so fail extra
 	 * probes.
 	 */
-	if (cxt->max_count)
+	if (cxt->max_dump_cnt)
 		goto fail_out;
 
-	if (!pdata->mem_size || !pdata->record_size) {
-		pr_err("The memory size and the record size must be "
+	if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size)) {
+		pr_err("The memory size and the record/console size must be "
 			"non-zero\n");
 		goto fail_out;
 	}
 
 	pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
 	pdata->record_size = rounddown_pow_of_two(pdata->record_size);
+	pdata->console_size = rounddown_pow_of_two(pdata->console_size);
 
-	/* Check for the minimum memory size */
-	if (pdata->mem_size < MIN_MEM_SIZE &&
-			pdata->record_size < MIN_MEM_SIZE) {
-		pr_err("memory size too small, minimum is %lu\n",
-			MIN_MEM_SIZE);
-		goto fail_out;
-	}
-
-	if (pdata->mem_size < pdata->record_size) {
-		pr_err("The memory size must be larger than the "
-			"records size\n");
-		goto fail_out;
-	}
-
-	cxt->max_count = pdata->mem_size / pdata->record_size;
-	cxt->count = 0;
+	cxt->dump_read_cnt = 0;
 	cxt->size = pdata->mem_size;
 	cxt->phys_addr = pdata->mem_address;
 	cxt->record_size = pdata->record_size;
+	cxt->console_size = pdata->console_size;
 	cxt->dump_oops = pdata->dump_oops;
 	cxt->ecc = pdata->ecc;
 
-	cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_count, GFP_KERNEL);
-	if (!cxt->przs) {
-		err = -ENOMEM;
-		dev_err(dev, "failed to initialize a prz array\n");
+	paddr = cxt->phys_addr;
+
+	dump_mem_sz = cxt->size - cxt->console_size;
+	err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz);
+	if (err)
 		goto fail_out;
-	}
 
-	for (i = 0; i < cxt->max_count; i++) {
-		size_t sz = cxt->record_size;
-		phys_addr_t start = cxt->phys_addr + sz * i;
+	err = ramoops_init_prz(dev, cxt, &cxt->cprz, &paddr, cxt->console_size);
+	if (err)
+		goto fail_init_cprz;
 
-		cxt->przs[i] = persistent_ram_new(start, sz, cxt->ecc);
-		if (IS_ERR(cxt->przs[i])) {
-			err = PTR_ERR(cxt->przs[i]);
-			dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
-				sz, (unsigned long long)start, err);
-			goto fail_przs;
-		}
+	if (!cxt->przs && !cxt->cprz) {
+		pr_err("memory size too small, minimum is %lu\n",
+			cxt->console_size + cxt->record_size);
+		goto fail_cnt;
 	}
 
 	cxt->pstore.data = cxt;
-	cxt->pstore.bufsize = cxt->przs[0]->buffer_size;
+	/*
+	 * Console can handle any buffer size, so prefer dumps buffer
+	 * size since usually it is smaller.
+	 */
+	if (cxt->przs)
+		cxt->pstore.bufsize = cxt->przs[0]->buffer_size;
+	else
+		cxt->pstore.bufsize = cxt->cprz->buffer_size;
 	cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
 	spin_lock_init(&cxt->pstore.buf_lock);
 	if (!cxt->pstore.buf) {
@@ -291,9 +411,8 @@ static int __init ramoops_probe(struct platform_device *pdev)
 	record_size = pdata->record_size;
 	dump_oops = pdata->dump_oops;
 
-	pr_info("attached 0x%lx@0x%llx (%ux0x%zx), ecc: %s\n",
+	pr_info("attached 0x%lx@0x%llx, ecc: %s\n",
 		cxt->size, (unsigned long long)cxt->phys_addr,
-		cxt->max_count, cxt->record_size,
 		ramoops_ecc ? "on" : "off");
 
 	return 0;
@@ -302,11 +421,11 @@ fail_buf:
 	kfree(cxt->pstore.buf);
 fail_clear:
 	cxt->pstore.bufsize = 0;
-	cxt->max_count = 0;
-fail_przs:
-	for (i = 0; cxt->przs[i]; i++)
-		persistent_ram_free(cxt->przs[i]);
-	kfree(cxt->przs);
+	cxt->max_dump_cnt = 0;
+fail_cnt:
+	kfree(cxt->cprz);
+fail_init_cprz:
+	ramoops_free_przs(cxt);
 fail_out:
 	return err;
 }
@@ -321,7 +440,7 @@ static int __exit ramoops_remove(struct platform_device *pdev)
 
 	iounmap(cxt->virt_addr);
 	release_mem_region(cxt->phys_addr, cxt->size);
-	cxt->max_count = 0;
+	cxt->max_dump_cnt = 0;
 
 	/* TODO(kees): When pstore supports unregistering, call it here. */
 	kfree(cxt->pstore.buf);
@@ -333,6 +452,7 @@ static int __exit ramoops_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver ramoops_driver = {
+	.probe		= ramoops_probe,
 	.remove		= __exit_p(ramoops_remove),
 	.driver		= {
 		.name	= "ramoops",
@@ -340,45 +460,46 @@ static struct platform_driver ramoops_driver = {
 	},
 };
 
-static int __init ramoops_init(void)
+static void ramoops_register_dummy(void)
 {
-	int ret;
-	ret = platform_driver_probe(&ramoops_driver, ramoops_probe);
-	if (ret == -ENODEV) {
-		/*
-		 * If we didn't find a platform device, we use module parameters
-		 * building platform data on the fly.
-		 */
-		pr_info("platform device not found, using module parameters\n");
-		dummy_data = kzalloc(sizeof(struct ramoops_platform_data),
-				     GFP_KERNEL);
-		if (!dummy_data)
-			return -ENOMEM;
-		dummy_data->mem_size = mem_size;
-		dummy_data->mem_address = mem_address;
-		dummy_data->record_size = record_size;
-		dummy_data->dump_oops = dump_oops;
-		dummy_data->ecc = ramoops_ecc;
-		dummy = platform_create_bundle(&ramoops_driver, ramoops_probe,
-			NULL, 0, dummy_data,
-			sizeof(struct ramoops_platform_data));
-
-		if (IS_ERR(dummy))
-			ret = PTR_ERR(dummy);
-		else
-			ret = 0;
+	if (!mem_size)
+		return;
+
+	pr_info("using module parameters\n");
+
+	dummy_data = kzalloc(sizeof(*dummy_data), GFP_KERNEL);
+	if (!dummy_data) {
+		pr_info("could not allocate pdata\n");
+		return;
 	}
 
-	return ret;
+	dummy_data->mem_size = mem_size;
+	dummy_data->mem_address = mem_address;
+	dummy_data->record_size = record_size;
+	dummy_data->console_size = ramoops_console_size;
+	dummy_data->dump_oops = dump_oops;
+	dummy_data->ecc = ramoops_ecc;
+
+	dummy = platform_device_register_data(NULL, "ramoops", -1,
+			dummy_data, sizeof(struct ramoops_platform_data));
+	if (IS_ERR(dummy)) {
+		pr_info("could not create platform device: %ld\n",
+			PTR_ERR(dummy));
+	}
 }
 
+static int __init ramoops_init(void)
+{
+	ramoops_register_dummy();
+	return platform_driver_register(&ramoops_driver);
+}
+postcore_initcall(ramoops_init);
+
 static void __exit ramoops_exit(void)
 {
 	platform_driver_unregister(&ramoops_driver);
 	kfree(dummy_data);
 }
-
-module_init(ramoops_init);
 module_exit(ramoops_exit);
 
 MODULE_LICENSE("GPL");
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
index c5fbdbb..a5a7b13 100644
--- a/fs/pstore/ram_core.c
+++ b/fs/pstore/ram_core.c
@@ -35,8 +35,6 @@ struct persistent_ram_buffer {
 
 #define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
 
-static __initdata LIST_HEAD(persistent_ram_list);
-
 static inline size_t buffer_size(struct persistent_ram_zone *prz)
 {
 	return atomic_read(&prz->buffer->size);
@@ -173,12 +171,12 @@ static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
 	}
 }
 
-static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
-	size_t buffer_size)
+static int persistent_ram_init_ecc(struct persistent_ram_zone *prz)
 {
 	int numerr;
 	struct persistent_ram_buffer *buffer = prz->buffer;
 	int ecc_blocks;
+	size_t ecc_total;
 
 	if (!prz->ecc)
 		return 0;
@@ -189,14 +187,14 @@ static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
 	prz->ecc_poly = 0x11d;
 
 	ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
-	prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
-
-	if (prz->buffer_size > buffer_size) {
-		pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
-		       buffer_size, prz->buffer_size);
+	ecc_total = (ecc_blocks + 1) * prz->ecc_size;
+	if (ecc_total >= prz->buffer_size) {
+		pr_err("%s: invalid ecc_size %u (total %zu, buffer size %zu)\n",
+		       __func__, prz->ecc_size, ecc_total, prz->buffer_size);
 		return -EINVAL;
 	}
 
+	prz->buffer_size -= ecc_total;
 	prz->par_buffer = buffer->data + prz->buffer_size;
 	prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
 
@@ -392,13 +390,14 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
 	return 0;
 }
 
-static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool ecc)
+static int __devinit persistent_ram_post_init(struct persistent_ram_zone *prz,
+					      bool ecc)
 {
 	int ret;
 
 	prz->ecc = ecc;
 
-	ret = persistent_ram_init_ecc(prz, prz->buffer_size);
+	ret = persistent_ram_init_ecc(prz);
 	if (ret)
 		return ret;
 
@@ -409,14 +408,14 @@ static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool
 				" size %zu, start %zu\n",
 			       buffer_size(prz), buffer_start(prz));
 		else {
-			pr_info("persistent_ram: found existing buffer,"
+			pr_debug("persistent_ram: found existing buffer,"
 				" size %zu, start %zu\n",
 			       buffer_size(prz), buffer_start(prz));
 			persistent_ram_save_old(prz);
 			return 0;
 		}
 	} else {
-		pr_info("persistent_ram: no valid data in buffer"
+		pr_debug("persistent_ram: no valid data in buffer"
 			" (sig = 0x%08x)\n", prz->buffer->sig);
 	}
 
@@ -428,19 +427,25 @@ static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool
 
 void persistent_ram_free(struct persistent_ram_zone *prz)
 {
-	if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
-		vunmap(prz->vaddr);
-	} else {
-		iounmap(prz->vaddr);
-		release_mem_region(prz->paddr, prz->size);
+	if (!prz)
+		return;
+
+	if (prz->vaddr) {
+		if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
+			vunmap(prz->vaddr);
+		} else {
+			iounmap(prz->vaddr);
+			release_mem_region(prz->paddr, prz->size);
+		}
+		prz->vaddr = NULL;
 	}
 	persistent_ram_free_old(prz);
 	kfree(prz);
 }
 
-struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
-						       size_t size,
-						       bool ecc)
+struct persistent_ram_zone * __devinit persistent_ram_new(phys_addr_t start,
+							  size_t size,
+							  bool ecc)
 {
 	struct persistent_ram_zone *prz;
 	int ret = -ENOMEM;
@@ -455,85 +460,12 @@ struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
 	if (ret)
 		goto err;
 
-	persistent_ram_post_init(prz, ecc);
-
-	return prz;
-err:
-	kfree(prz);
-	return ERR_PTR(ret);
-}
-
-#ifndef MODULE
-static int __init persistent_ram_buffer_init(const char *name,
-		struct persistent_ram_zone *prz)
-{
-	int i;
-	struct persistent_ram *ram;
-	struct persistent_ram_descriptor *desc;
-	phys_addr_t start;
-
-	list_for_each_entry(ram, &persistent_ram_list, node) {
-		start = ram->start;
-		for (i = 0; i < ram->num_descs; i++) {
-			desc = &ram->descs[i];
-			if (!strcmp(desc->name, name))
-				return persistent_ram_buffer_map(start,
-						desc->size, prz);
-			start += desc->size;
-		}
-	}
-
-	return -EINVAL;
-}
-
-static  __init
-struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
-{
-	struct persistent_ram_zone *prz;
-	int ret = -ENOMEM;
-
-	prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
-	if (!prz) {
-		pr_err("persistent_ram: failed to allocate persistent ram zone\n");
-		goto err;
-	}
-
-	ret = persistent_ram_buffer_init(dev_name(dev), prz);
-	if (ret) {
-		pr_err("persistent_ram: failed to initialize buffer\n");
+	ret = persistent_ram_post_init(prz, ecc);
+	if (ret)
 		goto err;
-	}
-
-	persistent_ram_post_init(prz, ecc);
 
 	return prz;
 err:
-	kfree(prz);
+	persistent_ram_free(prz);
 	return ERR_PTR(ret);
 }
-
-struct persistent_ram_zone * __init
-persistent_ram_init_ringbuffer(struct device *dev, bool ecc)
-{
-	return __persistent_ram_init(dev, ecc);
-}
-
-int __init persistent_ram_early_init(struct persistent_ram *ram)
-{
-	int ret;
-
-	ret = memblock_reserve(ram->start, ram->size);
-	if (ret) {
-		pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
-			(long)ram->start, (long)(ram->start + ram->size - 1));
-		return ret;
-	}
-
-	list_add_tail(&ram->node, &persistent_ram_list);
-
-	pr_info("Initialized persistent memory from %08lx-%08lx\n",
-		(long)ram->start, (long)(ram->start + ram->size - 1));
-
-	return 0;
-}
-#endif
diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c
index 22e0d60..76a7a69 100644
--- a/fs/qnx4/bitmap.c
+++ b/fs/qnx4/bitmap.c
@@ -17,23 +17,6 @@
 #include <linux/bitops.h>
 #include "qnx4.h"
 
-static void count_bits(register const char *bmPart, register int size,
-		       int *const tf)
-{
-	char b;
-	int tot = *tf;
-
-	if (size > QNX4_BLOCK_SIZE) {
-		size = QNX4_BLOCK_SIZE;
-	}
-	do {
-		b = *bmPart++;
-		tot += 8 - hweight8(b);
-		size--;
-	} while (size != 0);
-	*tf = tot;
-}
-
 unsigned long qnx4_count_free_blocks(struct super_block *sb)
 {
 	int start = le32_to_cpu(qnx4_sb(sb)->BitMap->di_first_xtnt.xtnt_blk) - 1;
@@ -44,13 +27,16 @@ unsigned long qnx4_count_free_blocks(struct super_block *sb)
 	struct buffer_head *bh;
 
 	while (total < size) {
+		int bytes = min(size - total, QNX4_BLOCK_SIZE);
+
 		if ((bh = sb_bread(sb, start + offset)) == NULL) {
 			printk(KERN_ERR "qnx4: I/O error in counting free blocks\n");
 			break;
 		}
-		count_bits(bh->b_data, size - total, &total_free);
+		total_free += bytes * BITS_PER_BYTE -
+				memweight(bh->b_data, bytes);
 		brelse(bh);
-		total += QNX4_BLOCK_SIZE;
+		total += bytes;
 		offset++;
 	}
 
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 552e994..9534b4f 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -391,6 +391,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(qnx4_inode_cachep);
 }
 
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
index a512c0b..d024505 100644
--- a/fs/qnx4/namei.c
+++ b/fs/qnx4/namei.c
@@ -95,7 +95,7 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
 	return NULL;
 }
 
-struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	int ino;
 	struct qnx4_inode_entry *de;
diff --git a/fs/qnx4/qnx4.h b/fs/qnx4/qnx4.h
index 244d462..34e2d32 100644
--- a/fs/qnx4/qnx4.h
+++ b/fs/qnx4/qnx4.h
@@ -23,7 +23,7 @@ struct qnx4_inode_info {
 };
 
 extern struct inode *qnx4_iget(struct super_block *, unsigned long);
-extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd);
+extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags);
 extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
 extern unsigned long qnx4_block_map(struct inode *inode, long iblock);
 
diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c
index e44012d..1b37fff 100644
--- a/fs/qnx6/inode.c
+++ b/fs/qnx6/inode.c
@@ -622,7 +622,6 @@ static struct inode *qnx6_alloc_inode(struct super_block *sb)
 static void qnx6_i_callback(struct rcu_head *head)
 {
 	struct inode *inode = container_of(head, struct inode, i_rcu);
-	INIT_LIST_HEAD(&inode->i_dentry);
 	kmem_cache_free(qnx6_inode_cachep, QNX6_I(inode));
 }
 
@@ -652,6 +651,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(qnx6_inode_cachep);
 }
 
diff --git a/fs/qnx6/namei.c b/fs/qnx6/namei.c
index 8a97289..0561326 100644
--- a/fs/qnx6/namei.c
+++ b/fs/qnx6/namei.c
@@ -13,7 +13,7 @@
 #include "qnx6.h"
 
 struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry,
-				struct nameidata *nd)
+				unsigned int flags)
 {
 	unsigned ino;
 	struct page *page;
diff --git a/fs/qnx6/qnx6.h b/fs/qnx6/qnx6.h
index 6c5e02a..b00fcc9 100644
--- a/fs/qnx6/qnx6.h
+++ b/fs/qnx6/qnx6.h
@@ -45,7 +45,7 @@ struct qnx6_inode_info {
 
 extern struct inode *qnx6_iget(struct super_block *sb, unsigned ino);
 extern struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry,
-					struct nameidata *nd);
+					unsigned int flags);
 
 #ifdef CONFIG_QNX6FS_DEBUG
 extern void qnx6_superblock_debug(struct qnx6_super_block *,
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 10cbe84..0c541dc 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -78,7 +78,7 @@
 #include <linux/quotaops.h>
 #include "../internal.h" /* ugh */
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 /*
  * There are three quota SMP locks. dq_list_lock protects all lists with quotas
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 9a39120..639782d 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -9,7 +9,7 @@
 #include <linux/namei.h>
 #include <linux/slab.h>
 #include <asm/current.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/kernel.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index a1fdabe..eab8c09 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -114,7 +114,7 @@ static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
 	return retval;
 }
 
-static int ramfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd)
+static int ramfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
 {
 	return ramfs_mknod(dir, dentry, mode | S_IFREG, 0);
 }
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 84e8a69..3916be1 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -322,7 +322,7 @@ static int reiserfs_find_entry(struct inode *dir, const char *name, int namelen,
 }
 
 static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
-				      struct nameidata *nd)
+				      unsigned int flags)
 {
 	int retval;
 	int lock_depth;
@@ -573,7 +573,7 @@ static int new_inode_init(struct inode *inode, struct inode *dir, umode_t mode)
 }
 
 static int reiserfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-			   struct nameidata *nd)
+			   bool excl)
 {
 	int retval;
 	struct inode *inode;
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 651ce76..ad39139 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -603,6 +603,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(reiserfs_inode_cachep);
 }
 
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 46fc1c2..d319963 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -62,7 +62,7 @@
 static int xattr_create(struct inode *dir, struct dentry *dentry, int mode)
 {
 	BUG_ON(!mutex_is_locked(&dir->i_mutex));
-	return dir->i_op->create(dir, dentry, mode, NULL);
+	return dir->i_op->create(dir, dentry, mode, true);
 }
 #endif
 
@@ -942,7 +942,7 @@ int reiserfs_permission(struct inode *inode, int mask)
 	return generic_permission(inode, mask);
 }
 
-static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int xattr_hide_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	return -EPERM;
 }
diff --git a/fs/romfs/super.c b/fs/romfs/super.c
index e64f6b5..fd7c5f6 100644
--- a/fs/romfs/super.c
+++ b/fs/romfs/super.c
@@ -210,7 +210,7 @@ out:
  * look up an entry in a directory
  */
 static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry,
-				   struct nameidata *nd)
+				   unsigned int flags)
 {
 	unsigned long offset, maxoff;
 	struct inode *inode;
@@ -648,6 +648,11 @@ error_register:
 static void __exit exit_romfs_fs(void)
 {
 	unregister_filesystem(&romfs_fs_type);
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(romfs_inode_cachep);
 }
 
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 0cbd049..14cf9de 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -385,15 +385,12 @@ int seq_escape(struct seq_file *m, const char *s, const char *esc)
 }
 EXPORT_SYMBOL(seq_escape);
 
-int seq_printf(struct seq_file *m, const char *f, ...)
+int seq_vprintf(struct seq_file *m, const char *f, va_list args)
 {
-	va_list args;
 	int len;
 
 	if (m->count < m->size) {
-		va_start(args, f);
 		len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
-		va_end(args);
 		if (m->count + len < m->size) {
 			m->count += len;
 			return 0;
@@ -402,6 +399,19 @@ int seq_printf(struct seq_file *m, const char *f, ...)
 	seq_set_overflow(m);
 	return -1;
 }
+EXPORT_SYMBOL(seq_vprintf);
+
+int seq_printf(struct seq_file *m, const char *f, ...)
+{
+	int ret;
+	va_list args;
+
+	va_start(args, f);
+	ret = seq_vprintf(m, f, args);
+	va_end(args);
+
+	return ret;
+}
 EXPORT_SYMBOL(seq_printf);
 
 /**
diff --git a/fs/splice.c b/fs/splice.c
index c9f1318..7bf08fa 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -273,13 +273,16 @@ void spd_release_page(struct splice_pipe_desc *spd, unsigned int i)
  * Check if we need to grow the arrays holding pages and partial page
  * descriptions.
  */
-int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
+int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
 {
-	if (pipe->buffers <= PIPE_DEF_BUFFERS)
+	unsigned int buffers = ACCESS_ONCE(pipe->buffers);
+
+	spd->nr_pages_max = buffers;
+	if (buffers <= PIPE_DEF_BUFFERS)
 		return 0;
 
-	spd->pages = kmalloc(pipe->buffers * sizeof(struct page *), GFP_KERNEL);
-	spd->partial = kmalloc(pipe->buffers * sizeof(struct partial_page), GFP_KERNEL);
+	spd->pages = kmalloc(buffers * sizeof(struct page *), GFP_KERNEL);
+	spd->partial = kmalloc(buffers * sizeof(struct partial_page), GFP_KERNEL);
 
 	if (spd->pages && spd->partial)
 		return 0;
@@ -289,10 +292,9 @@ int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
 	return -ENOMEM;
 }
 
-void splice_shrink_spd(struct pipe_inode_info *pipe,
-		       struct splice_pipe_desc *spd)
+void splice_shrink_spd(struct splice_pipe_desc *spd)
 {
-	if (pipe->buffers <= PIPE_DEF_BUFFERS)
+	if (spd->nr_pages_max <= PIPE_DEF_BUFFERS)
 		return;
 
 	kfree(spd->pages);
@@ -315,6 +317,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
 	struct splice_pipe_desc spd = {
 		.pages = pages,
 		.partial = partial,
+		.nr_pages_max = PIPE_DEF_BUFFERS,
 		.flags = flags,
 		.ops = &page_cache_pipe_buf_ops,
 		.spd_release = spd_release_page,
@@ -326,7 +329,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
 	index = *ppos >> PAGE_CACHE_SHIFT;
 	loff = *ppos & ~PAGE_CACHE_MASK;
 	req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-	nr_pages = min(req_pages, pipe->buffers);
+	nr_pages = min(req_pages, spd.nr_pages_max);
 
 	/*
 	 * Lookup the (hopefully) full range of pages we need.
@@ -497,7 +500,7 @@ fill_it:
 	if (spd.nr_pages)
 		error = splice_to_pipe(pipe, &spd);
 
-	splice_shrink_spd(pipe, &spd);
+	splice_shrink_spd(&spd);
 	return error;
 }
 
@@ -598,6 +601,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
 	struct splice_pipe_desc spd = {
 		.pages = pages,
 		.partial = partial,
+		.nr_pages_max = PIPE_DEF_BUFFERS,
 		.flags = flags,
 		.ops = &default_pipe_buf_ops,
 		.spd_release = spd_release_page,
@@ -608,8 +612,8 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
 
 	res = -ENOMEM;
 	vec = __vec;
-	if (pipe->buffers > PIPE_DEF_BUFFERS) {
-		vec = kmalloc(pipe->buffers * sizeof(struct iovec), GFP_KERNEL);
+	if (spd.nr_pages_max > PIPE_DEF_BUFFERS) {
+		vec = kmalloc(spd.nr_pages_max * sizeof(struct iovec), GFP_KERNEL);
 		if (!vec)
 			goto shrink_ret;
 	}
@@ -617,7 +621,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
 	offset = *ppos & ~PAGE_CACHE_MASK;
 	nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 
-	for (i = 0; i < nr_pages && i < pipe->buffers && len; i++) {
+	for (i = 0; i < nr_pages && i < spd.nr_pages_max && len; i++) {
 		struct page *page;
 
 		page = alloc_page(GFP_USER);
@@ -665,7 +669,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
 shrink_ret:
 	if (vec != __vec)
 		kfree(vec);
-	splice_shrink_spd(pipe, &spd);
+	splice_shrink_spd(&spd);
 	return res;
 
 err:
@@ -1614,6 +1618,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
 	struct splice_pipe_desc spd = {
 		.pages = pages,
 		.partial = partial,
+		.nr_pages_max = PIPE_DEF_BUFFERS,
 		.flags = flags,
 		.ops = &user_page_pipe_buf_ops,
 		.spd_release = spd_release_page,
@@ -1629,13 +1634,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
 
 	spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages,
 					    spd.partial, false,
-					    pipe->buffers);
+					    spd.nr_pages_max);
 	if (spd.nr_pages <= 0)
 		ret = spd.nr_pages;
 	else
 		ret = splice_to_pipe(pipe, &spd);
 
-	splice_shrink_spd(pipe, &spd);
+	splice_shrink_spd(&spd);
 	return ret;
 }
 
diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c
index abcc58f..7834a51 100644
--- a/fs/squashfs/namei.c
+++ b/fs/squashfs/namei.c
@@ -134,7 +134,7 @@ out:
 
 
 static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
-				 struct nameidata *nd)
+				 unsigned int flags)
 {
 	const unsigned char *name = dentry->d_name.name;
 	int len = dentry->d_name.len;
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index 29cd014..260e392 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -425,6 +425,11 @@ static int __init init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(squashfs_inode_cachep);
 }
 
diff --git a/fs/super.c b/fs/super.c
index cf00177..c2f3a1f 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -256,12 +256,6 @@ void deactivate_locked_super(struct super_block *s)
 
 		/* caches are now gone, we can safely kill the shrinker now */
 		unregister_shrinker(&s->s_shrink);
-
-		/*
-		 * We need to call rcu_barrier so all the delayed rcu free
-		 * inodes are flushed before we release the fs module.
-		 */
-		rcu_barrier();
 		put_filesystem(fs);
 		put_super(s);
 	} else {
@@ -318,7 +312,7 @@ static int grab_super(struct super_block *s) __releases(sb_lock)
 
 /*
  *	grab_super_passive - acquire a passive reference
- *	@s: reference we are trying to grab
+ *	@sb: reference we are trying to grab
  *
  *	Tries to acquire a passive reference. This is used in places where we
  *	cannot take an active reference but we need to ensure that the
diff --git a/fs/sync.c b/fs/sync.c
index 11e3d1c..1830704 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -92,7 +92,7 @@ static void sync_filesystems(int wait)
 }
 
 /*
- * sync everything.  Start out by waking pdflush, because that writes back
+ * sync everything.  Start out by waking flusher, because that writes back
  * all queues in parallel.
  */
 SYSCALL_DEFINE0(sync)
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index e6bb9b2..a5cf784 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -300,15 +300,15 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)
 static int sysfs_dentry_delete(const struct dentry *dentry)
 {
 	struct sysfs_dirent *sd = dentry->d_fsdata;
-	return !!(sd->s_flags & SYSFS_FLAG_REMOVED);
+	return !(sd && !(sd->s_flags & SYSFS_FLAG_REMOVED));
 }
 
-static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	struct sysfs_dirent *sd;
 	int is_dir;
 
-	if (nd->flags & LOOKUP_RCU)
+	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	sd = dentry->d_fsdata;
@@ -355,18 +355,15 @@ out_bad:
 	return 0;
 }
 
-static void sysfs_dentry_iput(struct dentry *dentry, struct inode *inode)
+static void sysfs_dentry_release(struct dentry *dentry)
 {
-	struct sysfs_dirent * sd = dentry->d_fsdata;
-
-	sysfs_put(sd);
-	iput(inode);
+	sysfs_put(dentry->d_fsdata);
 }
 
-static const struct dentry_operations sysfs_dentry_ops = {
+const struct dentry_operations sysfs_dentry_ops = {
 	.d_revalidate	= sysfs_dentry_revalidate,
 	.d_delete	= sysfs_dentry_delete,
-	.d_iput		= sysfs_dentry_iput,
+	.d_release	= sysfs_dentry_release,
 };
 
 struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
@@ -764,7 +761,7 @@ int sysfs_create_dir(struct kobject * kobj)
 }
 
 static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
-				struct nameidata *nd)
+				unsigned int flags)
 {
 	struct dentry *ret = NULL;
 	struct dentry *parent = dentry->d_parent;
@@ -786,6 +783,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 		ret = ERR_PTR(-ENOENT);
 		goto out_unlock;
 	}
+	dentry->d_fsdata = sysfs_get(sd);
 
 	/* attach dentry and inode */
 	inode = sysfs_get_inode(dir->i_sb, sd);
@@ -795,16 +793,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 	}
 
 	/* instantiate and hash dentry */
-	ret = d_find_alias(inode);
-	if (!ret) {
-		d_set_d_op(dentry, &sysfs_dentry_ops);
-		dentry->d_fsdata = sysfs_get(sd);
-		d_add(dentry, inode);
-	} else {
-		d_move(ret, dentry);
-		iput(inode);
-	}
-
+	ret = d_materialise_unique(dentry, inode);
  out_unlock:
 	mutex_unlock(&sysfs_mutex);
 	return ret;
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 52c3bdb..c15a7a3 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -68,6 +68,7 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
 	}
 	root->d_fsdata = &sysfs_root;
 	sb->s_root = root;
+	sb->s_d_op = &sysfs_dentry_ops;
 	return 0;
 }
 
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 661a963..d73c093 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -157,6 +157,7 @@ extern struct kmem_cache *sysfs_dir_cachep;
  */
 extern struct mutex sysfs_mutex;
 extern spinlock_t sysfs_assoc_lock;
+extern const struct dentry_operations sysfs_dentry_ops;
 
 extern const struct file_operations sysfs_dir_operations;
 extern const struct inode_operations sysfs_dir_inode_operations;
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 08d0b25..a08341c 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -376,5 +376,10 @@ int __init sysv_init_icache(void)
 
 void sysv_destroy_icache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(sysv_inode_cachep);
 }
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index d7466e2..1c0d5f2 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -43,7 +43,7 @@ const struct dentry_operations sysv_dentry_operations = {
 	.d_hash		= sysv_hash,
 };
 
-static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags)
 {
 	struct inode * inode = NULL;
 	ino_t ino;
@@ -80,7 +80,7 @@ static int sysv_mknod(struct inode * dir, struct dentry * dentry, umode_t mode,
 	return err;
 }
 
-static int sysv_create(struct inode * dir, struct dentry * dentry, umode_t mode, struct nameidata *nd)
+static int sysv_create(struct inode * dir, struct dentry * dentry, umode_t mode, bool excl)
 {
 	return sysv_mknod(dir, dentry, mode, 0);
 }
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index a6d42ef..b1cca89 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -184,7 +184,7 @@ static int dbg_check_name(const struct ubifs_info *c,
 }
 
 static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
-				   struct nameidata *nd)
+				   unsigned int flags)
 {
 	int err;
 	union ubifs_key key;
@@ -246,7 +246,7 @@ out:
 }
 
 static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-			struct nameidata *nd)
+			bool excl)
 {
 	struct inode *inode;
 	struct ubifs_info *c = dir->i_sb->s_fs_info;
diff --git a/fs/ubifs/find.c b/fs/ubifs/find.c
index 2559d17..28ec13a 100644
--- a/fs/ubifs/find.c
+++ b/fs/ubifs/find.c
@@ -939,8 +939,8 @@ static int find_dirtiest_idx_leb(struct ubifs_info *c)
 	}
 	dbg_find("LEB %d, dirty %d and free %d flags %#x", lp->lnum, lp->dirty,
 		 lp->free, lp->flags);
-	ubifs_assert(lp->flags | LPROPS_TAKEN);
-	ubifs_assert(lp->flags | LPROPS_INDEX);
+	ubifs_assert(lp->flags & LPROPS_TAKEN);
+	ubifs_assert(lp->flags & LPROPS_INDEX);
 	return lnum;
 }
 
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 5862dd9..e8ae748 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -2302,6 +2302,12 @@ static void __exit ubifs_exit(void)
 	dbg_debugfs_exit();
 	ubifs_compressors_exit();
 	unregister_shrinker(&ubifs_shrinker_info);
+
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(ubifs_inode_slab);
 	unregister_filesystem(&ubifs_fs_type);
 }
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 1802417..544b279 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -251,7 +251,7 @@ out_ok:
 }
 
 static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
-				 struct nameidata *nd)
+				 unsigned int flags)
 {
 	struct inode *inode = NULL;
 	struct fileIdentDesc cfi;
@@ -551,7 +551,7 @@ static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
 }
 
 static int udf_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		      struct nameidata *nd)
+		      bool excl)
 {
 	struct udf_fileident_bh fibh;
 	struct inode *inode;
diff --git a/fs/udf/super.c b/fs/udf/super.c
index ac8a348..ebe9f52 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -170,6 +170,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(udf_inode_cachep);
 }
 
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index a2281ca..90d74b8 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -46,7 +46,7 @@ static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode)
 	return err;
 }
 
-static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
 {
 	struct inode * inode = NULL;
 	ino_t ino;
@@ -71,7 +71,7 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru
  * with d_instantiate(). 
  */
 static int ufs_create (struct inode * dir, struct dentry * dentry, umode_t mode,
-		struct nameidata *nd)
+		bool excl)
 {
 	struct inode *inode;
 	int err;
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 302f340..f655c1d 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -1449,6 +1449,11 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+	rcu_barrier();
 	kmem_cache_destroy(ufs_inode_cachep);
 }
 
diff --git a/fs/xattr.c b/fs/xattr.c
index 1d7ac37..4d45b71 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -427,6 +427,7 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
 {
 	ssize_t error;
 	void *kvalue = NULL;
+	void *vvalue = NULL;
 	char kname[XATTR_NAME_MAX + 1];
 
 	error = strncpy_from_user(kname, name, sizeof(kname));
@@ -438,9 +439,13 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
 	if (size) {
 		if (size > XATTR_SIZE_MAX)
 			size = XATTR_SIZE_MAX;
-		kvalue = kzalloc(size, GFP_KERNEL);
-		if (!kvalue)
-			return -ENOMEM;
+		kvalue = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+		if (!kvalue) {
+			vvalue = vmalloc(size);
+			if (!vvalue)
+				return -ENOMEM;
+			kvalue = vvalue;
+		}
 	}
 
 	error = vfs_getxattr(d, kname, kvalue, size);
@@ -452,7 +457,10 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
 		   than XATTR_SIZE_MAX bytes. Not possible. */
 		error = -E2BIG;
 	}
-	kfree(kvalue);
+	if (vvalue)
+		vfree(vvalue);
+	else
+		kfree(kvalue);
 	return error;
 }
 
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 8dad722..84e3725 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -323,10 +323,10 @@ xfs_map_blocks(
 
 	ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
 	       (ip->i_df.if_flags & XFS_IFEXTENTS));
-	ASSERT(offset <= mp->m_maxioffset);
+	ASSERT(offset <= mp->m_super->s_maxbytes);
 
-	if (offset + count > mp->m_maxioffset)
-		count = mp->m_maxioffset - offset;
+	if (offset + count > mp->m_super->s_maxbytes)
+		count = mp->m_super->s_maxbytes - offset;
 	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
 	offset_fsb = XFS_B_TO_FSBT(mp, offset);
 	error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
@@ -1162,9 +1162,9 @@ __xfs_get_blocks(
 		lockmode = xfs_ilock_map_shared(ip);
 	}
 
-	ASSERT(offset <= mp->m_maxioffset);
-	if (offset + size > mp->m_maxioffset)
-		size = mp->m_maxioffset - offset;
+	ASSERT(offset <= mp->m_super->s_maxbytes);
+	if (offset + size > mp->m_super->s_maxbytes)
+		size = mp->m_super->s_maxbytes - offset;
 	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
 	offset_fsb = XFS_B_TO_FSBT(mp, offset);
 
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 58b815e..848ffa7 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -5517,7 +5517,7 @@ xfs_getbmap(
 		if (xfs_get_extsz_hint(ip) ||
 		    ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){
 			prealloced = 1;
-			fixlen = XFS_MAXIOFFSET(mp);
+			fixlen = mp->m_super->s_maxbytes;
 		} else {
 			prealloced = 0;
 			fixlen = XFS_ISIZE(ip);
diff --git a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h
index a372163..1d9643b 100644
--- a/fs/xfs/xfs_dinode.h
+++ b/fs/xfs/xfs_dinode.h
@@ -33,7 +33,7 @@ typedef struct xfs_timestamp {
  * variable size the leftover area split into a data and an attribute fork.
  * The format of the data and attribute fork depends on the format of the
  * inode as indicated by di_format and di_aformat.  To access the data and
- * attribute use the XFS_DFORK_PTR, XFS_DFORK_DPTR, and XFS_DFORK_PTR macros
+ * attribute use the XFS_DFORK_DPTR, XFS_DFORK_APTR, and XFS_DFORK_PTR macros
  * below.
  *
  * There is a very similar struct icdinode in xfs_inode which matches the
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 9f7ec15..c4559c6 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -236,7 +236,6 @@ xfs_file_aio_read(
 	ssize_t			ret = 0;
 	int			ioflags = 0;
 	xfs_fsize_t		n;
-	unsigned long		seg;
 
 	XFS_STATS_INC(xs_read_calls);
 
@@ -247,19 +246,9 @@ xfs_file_aio_read(
 	if (file->f_mode & FMODE_NOCMTIME)
 		ioflags |= IO_INVIS;
 
-	/* START copy & waste from filemap.c */
-	for (seg = 0; seg < nr_segs; seg++) {
-		const struct iovec *iv = &iovp[seg];
-
-		/*
-		 * If any segment has a negative length, or the cumulative
-		 * length ever wraps negative then return -EINVAL.
-		 */
-		size += iv->iov_len;
-		if (unlikely((ssize_t)(size|iv->iov_len) < 0))
-			return XFS_ERROR(-EINVAL);
-	}
-	/* END copy & waste from filemap.c */
+	ret = generic_segment_checks(iovp, &nr_segs, &size, VERIFY_WRITE);
+	if (ret < 0)
+		return ret;
 
 	if (unlikely(ioflags & IO_ISDIRECT)) {
 		xfs_buftarg_t	*target =
@@ -273,7 +262,7 @@ xfs_file_aio_read(
 		}
 	}
 
-	n = XFS_MAXIOFFSET(mp) - iocb->ki_pos;
+	n = mp->m_super->s_maxbytes - iocb->ki_pos;
 	if (n <= 0 || size == 0)
 		return 0;
 
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index a59eea0..257f3c4 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1226,7 +1226,7 @@ xfs_itruncate_extents(
 	 * then there is nothing to do.
 	 */
 	first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size);
-	last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
+	last_block = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
 	if (first_unmap_block == last_block)
 		return 0;
 
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index aadfce6..915edf6 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -285,7 +285,7 @@ xfs_iomap_eof_want_preallocate(
 	 * do any speculative allocation.
 	 */
 	start_fsb = XFS_B_TO_FSBT(mp, ((xfs_ufsize_t)(offset + count - 1)));
-	count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
+	count_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
 	while (count_fsb > 0) {
 		imaps = nimaps;
 		firstblock = NULLFSBLOCK;
@@ -416,8 +416,8 @@ retry:
 	 * Make sure preallocation does not create extents beyond the range we
 	 * actually support in this filesystem.
 	 */
-	if (last_fsb > XFS_B_TO_FSB(mp, mp->m_maxioffset))
-		last_fsb = XFS_B_TO_FSB(mp, mp->m_maxioffset);
+	if (last_fsb > XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes))
+		last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
 
 	ASSERT(last_fsb > offset_fsb);
 
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 1a25fd8..9c4340f 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -179,7 +179,7 @@ xfs_vn_create(
 	struct inode	*dir,
 	struct dentry	*dentry,
 	umode_t		mode,
-	struct nameidata *nd)
+	bool		flags)
 {
 	return xfs_vn_mknod(dir, dentry, mode, 0);
 }
@@ -197,7 +197,7 @@ STATIC struct dentry *
 xfs_vn_lookup(
 	struct inode	*dir,
 	struct dentry	*dentry,
-	struct nameidata *nd)
+	unsigned int flags)
 {
 	struct xfs_inode *cip;
 	struct xfs_name	name;
@@ -222,7 +222,7 @@ STATIC struct dentry *
 xfs_vn_ci_lookup(
 	struct inode	*dir,
 	struct dentry	*dentry,
-	struct nameidata *nd)
+	unsigned int flags)
 {
 	struct xfs_inode *ip;
 	struct xfs_name	xname;
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index d90d4a3..7f4f937 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -45,51 +45,85 @@ xlog_commit_record(
 	struct xlog_in_core	**iclog,
 	xfs_lsn_t		*commitlsnp);
 
-STATIC xlog_t *  xlog_alloc_log(xfs_mount_t	*mp,
-				xfs_buftarg_t	*log_target,
-				xfs_daddr_t	blk_offset,
-				int		num_bblks);
+STATIC struct xlog *
+xlog_alloc_log(
+	struct xfs_mount	*mp,
+	struct xfs_buftarg	*log_target,
+	xfs_daddr_t		blk_offset,
+	int			num_bblks);
 STATIC int
 xlog_space_left(
 	struct xlog		*log,
 	atomic64_t		*head);
-STATIC int	 xlog_sync(xlog_t *log, xlog_in_core_t *iclog);
-STATIC void	 xlog_dealloc_log(xlog_t *log);
+STATIC int
+xlog_sync(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog);
+STATIC void
+xlog_dealloc_log(
+	struct xlog		*log);
 
 /* local state machine functions */
 STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int);
-STATIC void xlog_state_do_callback(xlog_t *log,int aborted, xlog_in_core_t *iclog);
-STATIC int  xlog_state_get_iclog_space(xlog_t		*log,
-				       int		len,
-				       xlog_in_core_t	**iclog,
-				       xlog_ticket_t	*ticket,
-				       int		*continued_write,
-				       int		*logoffsetp);
-STATIC int  xlog_state_release_iclog(xlog_t		*log,
-				     xlog_in_core_t	*iclog);
-STATIC void xlog_state_switch_iclogs(xlog_t		*log,
-				     xlog_in_core_t *iclog,
-				     int		eventual_size);
-STATIC void xlog_state_want_sync(xlog_t	*log, xlog_in_core_t *iclog);
+STATIC void
+xlog_state_do_callback(
+	struct xlog		*log,
+	int			aborted,
+	struct xlog_in_core	*iclog);
+STATIC int
+xlog_state_get_iclog_space(
+	struct xlog		*log,
+	int			len,
+	struct xlog_in_core	**iclog,
+	struct xlog_ticket	*ticket,
+	int			*continued_write,
+	int			*logoffsetp);
+STATIC int
+xlog_state_release_iclog(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog);
+STATIC void
+xlog_state_switch_iclogs(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog,
+	int			eventual_size);
+STATIC void
+xlog_state_want_sync(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog);
 
 STATIC void
 xlog_grant_push_ail(
-	struct xlog	*log,
-	int		need_bytes);
-STATIC void xlog_regrant_reserve_log_space(xlog_t	 *log,
-					   xlog_ticket_t *ticket);
-STATIC void xlog_ungrant_log_space(xlog_t	 *log,
-				   xlog_ticket_t *ticket);
+	struct xlog		*log,
+	int			need_bytes);
+STATIC void
+xlog_regrant_reserve_log_space(
+	struct xlog		*log,
+	struct xlog_ticket	*ticket);
+STATIC void
+xlog_ungrant_log_space(
+	struct xlog		*log,
+	struct xlog_ticket	*ticket);
 
 #if defined(DEBUG)
-STATIC void	xlog_verify_dest_ptr(xlog_t *log, char *ptr);
+STATIC void
+xlog_verify_dest_ptr(
+	struct xlog		*log,
+	char			*ptr);
 STATIC void
 xlog_verify_grant_tail(
-	struct xlog	*log);
-STATIC void	xlog_verify_iclog(xlog_t *log, xlog_in_core_t *iclog,
-				  int count, boolean_t syncing);
-STATIC void	xlog_verify_tail_lsn(xlog_t *log, xlog_in_core_t *iclog,
-				     xfs_lsn_t tail_lsn);
+	struct xlog *log);
+STATIC void
+xlog_verify_iclog(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog,
+	int			count,
+	boolean_t		syncing);
+STATIC void
+xlog_verify_tail_lsn(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog,
+	xfs_lsn_t		tail_lsn);
 #else
 #define xlog_verify_dest_ptr(a,b)
 #define xlog_verify_grant_tail(a)
@@ -97,7 +131,9 @@ STATIC void	xlog_verify_tail_lsn(xlog_t *log, xlog_in_core_t *iclog,
 #define xlog_verify_tail_lsn(a,b,c)
 #endif
 
-STATIC int	xlog_iclogs_empty(xlog_t *log);
+STATIC int
+xlog_iclogs_empty(
+	struct xlog		*log);
 
 static void
 xlog_grant_sub_space(
@@ -684,7 +720,7 @@ xfs_log_mount_finish(xfs_mount_t *mp)
 int
 xfs_log_unmount_write(xfs_mount_t *mp)
 {
-	xlog_t		 *log = mp->m_log;
+	struct xlog	 *log = mp->m_log;
 	xlog_in_core_t	 *iclog;
 #ifdef DEBUG
 	xlog_in_core_t	 *first_iclog;
@@ -893,7 +929,7 @@ int
 xfs_log_need_covered(xfs_mount_t *mp)
 {
 	int		needed = 0;
-	xlog_t		*log = mp->m_log;
+	struct xlog	*log = mp->m_log;
 
 	if (!xfs_fs_writable(mp))
 		return 0;
@@ -1024,9 +1060,9 @@ xlog_space_left(
 void
 xlog_iodone(xfs_buf_t *bp)
 {
-	xlog_in_core_t	*iclog = bp->b_fspriv;
-	xlog_t		*l = iclog->ic_log;
-	int		aborted = 0;
+	struct xlog_in_core	*iclog = bp->b_fspriv;
+	struct xlog		*l = iclog->ic_log;
+	int			aborted = 0;
 
 	/*
 	 * Race to shutdown the filesystem if we see an error.
@@ -1067,8 +1103,9 @@ xlog_iodone(xfs_buf_t *bp)
  */
 
 STATIC void
-xlog_get_iclog_buffer_size(xfs_mount_t	*mp,
-			   xlog_t	*log)
+xlog_get_iclog_buffer_size(
+	struct xfs_mount	*mp,
+	struct xlog		*log)
 {
 	int size;
 	int xhdrs;
@@ -1129,13 +1166,14 @@ done:
  * Its primary purpose is to fill in enough, so recovery can occur.  However,
  * some other stuff may be filled in too.
  */
-STATIC xlog_t *
-xlog_alloc_log(xfs_mount_t	*mp,
-	       xfs_buftarg_t	*log_target,
-	       xfs_daddr_t	blk_offset,
-	       int		num_bblks)
+STATIC struct xlog *
+xlog_alloc_log(
+	struct xfs_mount	*mp,
+	struct xfs_buftarg	*log_target,
+	xfs_daddr_t		blk_offset,
+	int			num_bblks)
 {
-	xlog_t			*log;
+	struct xlog		*log;
 	xlog_rec_header_t	*head;
 	xlog_in_core_t		**iclogp;
 	xlog_in_core_t		*iclog, *prev_iclog=NULL;
@@ -1144,7 +1182,7 @@ xlog_alloc_log(xfs_mount_t	*mp,
 	int			error = ENOMEM;
 	uint			log2_size = 0;
 
-	log = kmem_zalloc(sizeof(xlog_t), KM_MAYFAIL);
+	log = kmem_zalloc(sizeof(struct xlog), KM_MAYFAIL);
 	if (!log) {
 		xfs_warn(mp, "Log allocation failed: No memory!");
 		goto out;
@@ -1434,8 +1472,9 @@ xlog_bdstrat(
  */
 
 STATIC int
-xlog_sync(xlog_t		*log,
-	  xlog_in_core_t	*iclog)
+xlog_sync(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog)
 {
 	xfs_caddr_t	dptr;		/* pointer to byte sized element */
 	xfs_buf_t	*bp;
@@ -1584,7 +1623,8 @@ xlog_sync(xlog_t		*log,
  * Deallocate a log structure
  */
 STATIC void
-xlog_dealloc_log(xlog_t *log)
+xlog_dealloc_log(
+	struct xlog	*log)
 {
 	xlog_in_core_t	*iclog, *next_iclog;
 	int		i;
@@ -1616,10 +1656,11 @@ xlog_dealloc_log(xlog_t *log)
  */
 /* ARGSUSED */
 static inline void
-xlog_state_finish_copy(xlog_t		*log,
-		       xlog_in_core_t	*iclog,
-		       int		record_cnt,
-		       int		copy_bytes)
+xlog_state_finish_copy(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog,
+	int			record_cnt,
+	int			copy_bytes)
 {
 	spin_lock(&log->l_icloglock);
 
@@ -2142,7 +2183,8 @@ xlog_write(
  * State Change: DIRTY -> ACTIVE
  */
 STATIC void
-xlog_state_clean_log(xlog_t *log)
+xlog_state_clean_log(
+	struct xlog *log)
 {
 	xlog_in_core_t	*iclog;
 	int changed = 0;
@@ -2222,7 +2264,7 @@ xlog_state_clean_log(xlog_t *log)
 
 STATIC xfs_lsn_t
 xlog_get_lowest_lsn(
-	xlog_t		*log)
+	struct xlog	*log)
 {
 	xlog_in_core_t  *lsn_log;
 	xfs_lsn_t	lowest_lsn, lsn;
@@ -2245,9 +2287,9 @@ xlog_get_lowest_lsn(
 
 STATIC void
 xlog_state_do_callback(
-	xlog_t		*log,
-	int		aborted,
-	xlog_in_core_t	*ciclog)
+	struct xlog		*log,
+	int			aborted,
+	struct xlog_in_core	*ciclog)
 {
 	xlog_in_core_t	   *iclog;
 	xlog_in_core_t	   *first_iclog;	/* used to know when we've
@@ -2467,7 +2509,7 @@ xlog_state_done_syncing(
 	xlog_in_core_t	*iclog,
 	int		aborted)
 {
-	xlog_t		   *log = iclog->ic_log;
+	struct xlog	   *log = iclog->ic_log;
 
 	spin_lock(&log->l_icloglock);
 
@@ -2521,12 +2563,13 @@ xlog_state_done_syncing(
  *		is copied.
  */
 STATIC int
-xlog_state_get_iclog_space(xlog_t	  *log,
-			   int		  len,
-			   xlog_in_core_t **iclogp,
-			   xlog_ticket_t  *ticket,
-			   int		  *continued_write,
-			   int		  *logoffsetp)
+xlog_state_get_iclog_space(
+	struct xlog		*log,
+	int			len,
+	struct xlog_in_core	**iclogp,
+	struct xlog_ticket	*ticket,
+	int			*continued_write,
+	int			*logoffsetp)
 {
 	int		  log_offset;
 	xlog_rec_header_t *head;
@@ -2631,8 +2674,9 @@ restart:
  * move grant reservation head forward.
  */
 STATIC void
-xlog_regrant_reserve_log_space(xlog_t	     *log,
-			       xlog_ticket_t *ticket)
+xlog_regrant_reserve_log_space(
+	struct xlog		*log,
+	struct xlog_ticket	*ticket)
 {
 	trace_xfs_log_regrant_reserve_enter(log, ticket);
 
@@ -2677,8 +2721,9 @@ xlog_regrant_reserve_log_space(xlog_t	     *log,
  * in the current reservation field.
  */
 STATIC void
-xlog_ungrant_log_space(xlog_t	     *log,
-		       xlog_ticket_t *ticket)
+xlog_ungrant_log_space(
+	struct xlog		*log,
+	struct xlog_ticket	*ticket)
 {
 	int	bytes;
 
@@ -2717,8 +2762,8 @@ xlog_ungrant_log_space(xlog_t	     *log,
  */
 STATIC int
 xlog_state_release_iclog(
-	xlog_t		*log,
-	xlog_in_core_t	*iclog)
+	struct xlog		*log,
+	struct xlog_in_core	*iclog)
 {
 	int		sync = 0;	/* do we sync? */
 
@@ -2768,9 +2813,10 @@ xlog_state_release_iclog(
  * that every data block.  We have run out of space in this log record.
  */
 STATIC void
-xlog_state_switch_iclogs(xlog_t		*log,
-			 xlog_in_core_t *iclog,
-			 int		eventual_size)
+xlog_state_switch_iclogs(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog,
+	int			eventual_size)
 {
 	ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE);
 	if (!eventual_size)
@@ -3114,7 +3160,9 @@ xfs_log_force_lsn(
  * disk.
  */
 STATIC void
-xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog)
+xlog_state_want_sync(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog)
 {
 	assert_spin_locked(&log->l_icloglock);
 
@@ -3158,7 +3206,7 @@ xfs_log_ticket_get(
 /*
  * Allocate and initialise a new log ticket.
  */
-xlog_ticket_t *
+struct xlog_ticket *
 xlog_ticket_alloc(
 	struct xlog	*log,
 	int		unit_bytes,
@@ -3346,9 +3394,10 @@ xlog_verify_grant_tail(
 
 /* check if it will fit */
 STATIC void
-xlog_verify_tail_lsn(xlog_t	    *log,
-		     xlog_in_core_t *iclog,
-		     xfs_lsn_t	    tail_lsn)
+xlog_verify_tail_lsn(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog,
+	xfs_lsn_t		tail_lsn)
 {
     int blocks;
 
@@ -3385,10 +3434,11 @@ xlog_verify_tail_lsn(xlog_t	    *log,
  *	the cycle numbers agree with the current cycle number.
  */
 STATIC void
-xlog_verify_iclog(xlog_t	 *log,
-		  xlog_in_core_t *iclog,
-		  int		 count,
-		  boolean_t	 syncing)
+xlog_verify_iclog(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog,
+	int			count,
+	boolean_t		syncing)
 {
 	xlog_op_header_t	*ophead;
 	xlog_in_core_t		*icptr;
@@ -3482,7 +3532,7 @@ xlog_verify_iclog(xlog_t	 *log,
  */
 STATIC int
 xlog_state_ioerror(
-	xlog_t	*log)
+	struct xlog	*log)
 {
 	xlog_in_core_t	*iclog, *ic;
 
@@ -3527,7 +3577,7 @@ xfs_log_force_umount(
 	struct xfs_mount	*mp,
 	int			logerror)
 {
-	xlog_t		*log;
+	struct xlog	*log;
 	int		retval;
 
 	log = mp->m_log;
@@ -3634,7 +3684,8 @@ xfs_log_force_umount(
 }
 
 STATIC int
-xlog_iclogs_empty(xlog_t *log)
+xlog_iclogs_empty(
+	struct xlog	*log)
 {
 	xlog_in_core_t	*iclog;
 
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
index 72eba22..18a801d 100644
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -487,7 +487,7 @@ struct xlog_grant_head {
  * overflow 31 bits worth of byte offset, so using a byte number will mean
  * that round off problems won't occur when releasing partial reservations.
  */
-typedef struct xlog {
+struct xlog {
 	/* The following fields don't need locking */
 	struct xfs_mount	*l_mp;	        /* mount point */
 	struct xfs_ail		*l_ailp;	/* AIL log is working with */
@@ -540,7 +540,7 @@ typedef struct xlog {
 	char			*l_iclog_bak[XLOG_MAX_ICLOGS];
 #endif
 
-} xlog_t;
+};
 
 #define XLOG_BUF_CANCEL_BUCKET(log, blkno) \
 	((log)->l_buf_cancel_table + ((__uint64_t)blkno % XLOG_BC_TABLE_SIZE))
@@ -548,9 +548,17 @@ typedef struct xlog {
 #define XLOG_FORCED_SHUTDOWN(log)	((log)->l_flags & XLOG_IO_ERROR)
 
 /* common routines */
-extern int	 xlog_recover(xlog_t *log);
-extern int	 xlog_recover_finish(xlog_t *log);
-extern void	 xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int);
+extern int
+xlog_recover(
+	struct xlog		*log);
+extern int
+xlog_recover_finish(
+	struct xlog		*log);
+extern void
+xlog_pack_data(
+	struct xlog		*log,
+	struct xlog_in_core	*iclog,
+	int);
 
 extern kmem_zone_t *xfs_log_ticket_zone;
 struct xlog_ticket *
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index a7be98a..a76ba88 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -43,10 +43,18 @@
 #include "xfs_utils.h"
 #include "xfs_trace.h"
 
-STATIC int	xlog_find_zeroed(xlog_t *, xfs_daddr_t *);
-STATIC int	xlog_clear_stale_blocks(xlog_t *, xfs_lsn_t);
+STATIC int
+xlog_find_zeroed(
+	struct xlog	*,
+	xfs_daddr_t	*);
+STATIC int
+xlog_clear_stale_blocks(
+	struct xlog	*,
+	xfs_lsn_t);
 #if defined(DEBUG)
-STATIC void	xlog_recover_check_summary(xlog_t *);
+STATIC void
+xlog_recover_check_summary(
+	struct xlog *);
 #else
 #define	xlog_recover_check_summary(log)
 #endif
@@ -74,7 +82,7 @@ struct xfs_buf_cancel {
 
 static inline int
 xlog_buf_bbcount_valid(
-	xlog_t		*log,
+	struct xlog	*log,
 	int		bbcount)
 {
 	return bbcount > 0 && bbcount <= log->l_logBBsize;
@@ -87,7 +95,7 @@ xlog_buf_bbcount_valid(
  */
 STATIC xfs_buf_t *
 xlog_get_bp(
-	xlog_t		*log,
+	struct xlog	*log,
 	int		nbblks)
 {
 	struct xfs_buf	*bp;
@@ -138,10 +146,10 @@ xlog_put_bp(
  */
 STATIC xfs_caddr_t
 xlog_align(
-	xlog_t		*log,
+	struct xlog	*log,
 	xfs_daddr_t	blk_no,
 	int		nbblks,
-	xfs_buf_t	*bp)
+	struct xfs_buf	*bp)
 {
 	xfs_daddr_t	offset = blk_no & ((xfs_daddr_t)log->l_sectBBsize - 1);
 
@@ -155,10 +163,10 @@ xlog_align(
  */
 STATIC int
 xlog_bread_noalign(
-	xlog_t		*log,
+	struct xlog	*log,
 	xfs_daddr_t	blk_no,
 	int		nbblks,
-	xfs_buf_t	*bp)
+	struct xfs_buf	*bp)
 {
 	int		error;
 
@@ -189,10 +197,10 @@ xlog_bread_noalign(
 
 STATIC int
 xlog_bread(
-	xlog_t		*log,
+	struct xlog	*log,
 	xfs_daddr_t	blk_no,
 	int		nbblks,
-	xfs_buf_t	*bp,
+	struct xfs_buf	*bp,
 	xfs_caddr_t	*offset)
 {
 	int		error;
@@ -211,10 +219,10 @@ xlog_bread(
  */
 STATIC int
 xlog_bread_offset(
-	xlog_t		*log,
+	struct xlog	*log,
 	xfs_daddr_t	blk_no,		/* block to read from */
 	int		nbblks,		/* blocks to read */
-	xfs_buf_t	*bp,
+	struct xfs_buf	*bp,
 	xfs_caddr_t	offset)
 {
 	xfs_caddr_t	orig_offset = bp->b_addr;
@@ -241,10 +249,10 @@ xlog_bread_offset(
  */
 STATIC int
 xlog_bwrite(
-	xlog_t		*log,
+	struct xlog	*log,
 	xfs_daddr_t	blk_no,
 	int		nbblks,
-	xfs_buf_t	*bp)
+	struct xfs_buf	*bp)
 {
 	int		error;
 
@@ -378,8 +386,8 @@ xlog_recover_iodone(
  */
 STATIC int
 xlog_find_cycle_start(
-	xlog_t		*log,
-	xfs_buf_t	*bp,
+	struct xlog	*log,
+	struct xfs_buf	*bp,
 	xfs_daddr_t	first_blk,
 	xfs_daddr_t	*last_blk,
 	uint		cycle)
@@ -421,7 +429,7 @@ xlog_find_cycle_start(
  */
 STATIC int
 xlog_find_verify_cycle(
-	xlog_t		*log,
+	struct xlog	*log,
 	xfs_daddr_t	start_blk,
 	int		nbblks,
 	uint		stop_on_cycle_no,
@@ -490,7 +498,7 @@ out:
  */
 STATIC int
 xlog_find_verify_log_record(
-	xlog_t			*log,
+	struct xlog		*log,
 	xfs_daddr_t		start_blk,
 	xfs_daddr_t		*last_blk,
 	int			extra_bblks)
@@ -600,7 +608,7 @@ out:
  */
 STATIC int
 xlog_find_head(
-	xlog_t 		*log,
+	struct xlog	*log,
 	xfs_daddr_t	*return_head_blk)
 {
 	xfs_buf_t	*bp;
@@ -871,7 +879,7 @@ validate_head:
  */
 STATIC int
 xlog_find_tail(
-	xlog_t			*log,
+	struct xlog		*log,
 	xfs_daddr_t		*head_blk,
 	xfs_daddr_t		*tail_blk)
 {
@@ -1080,7 +1088,7 @@ done:
  */
 STATIC int
 xlog_find_zeroed(
-	xlog_t		*log,
+	struct xlog	*log,
 	xfs_daddr_t	*blk_no)
 {
 	xfs_buf_t	*bp;
@@ -1183,7 +1191,7 @@ bp_err:
  */
 STATIC void
 xlog_add_record(
-	xlog_t			*log,
+	struct xlog		*log,
 	xfs_caddr_t		buf,
 	int			cycle,
 	int			block,
@@ -1205,7 +1213,7 @@ xlog_add_record(
 
 STATIC int
 xlog_write_log_records(
-	xlog_t		*log,
+	struct xlog	*log,
 	int		cycle,
 	int		start_block,
 	int		blocks,
@@ -1305,7 +1313,7 @@ xlog_write_log_records(
  */
 STATIC int
 xlog_clear_stale_blocks(
-	xlog_t		*log,
+	struct xlog	*log,
 	xfs_lsn_t	tail_lsn)
 {
 	int		tail_cycle, head_cycle;
@@ -2050,11 +2058,11 @@ xfs_qm_dqcheck(
  */
 STATIC void
 xlog_recover_do_dquot_buffer(
-	xfs_mount_t		*mp,
-	xlog_t			*log,
-	xlog_recover_item_t	*item,
-	xfs_buf_t		*bp,
-	xfs_buf_log_format_t	*buf_f)
+	struct xfs_mount		*mp,
+	struct xlog			*log,
+	struct xlog_recover_item	*item,
+	struct xfs_buf			*bp,
+	struct xfs_buf_log_format	*buf_f)
 {
 	uint			type;
 
@@ -2108,9 +2116,9 @@ xlog_recover_do_dquot_buffer(
  */
 STATIC int
 xlog_recover_buffer_pass2(
-	xlog_t			*log,
-	struct list_head	*buffer_list,
-	xlog_recover_item_t	*item)
+	struct xlog			*log,
+	struct list_head		*buffer_list,
+	struct xlog_recover_item	*item)
 {
 	xfs_buf_log_format_t	*buf_f = item->ri_buf[0].i_addr;
 	xfs_mount_t		*mp = log->l_mp;
@@ -2189,9 +2197,9 @@ xlog_recover_buffer_pass2(
 
 STATIC int
 xlog_recover_inode_pass2(
-	xlog_t			*log,
-	struct list_head	*buffer_list,
-	xlog_recover_item_t	*item)
+	struct xlog			*log,
+	struct list_head		*buffer_list,
+	struct xlog_recover_item	*item)
 {
 	xfs_inode_log_format_t	*in_f;
 	xfs_mount_t		*mp = log->l_mp;
@@ -2452,14 +2460,14 @@ error:
 }
 
 /*
- * Recover QUOTAOFF records. We simply make a note of it in the xlog_t
+ * Recover QUOTAOFF records. We simply make a note of it in the xlog
  * structure, so that we know not to do any dquot item or dquot buffer recovery,
  * of that type.
  */
 STATIC int
 xlog_recover_quotaoff_pass1(
-	xlog_t			*log,
-	xlog_recover_item_t	*item)
+	struct xlog			*log,
+	struct xlog_recover_item	*item)
 {
 	xfs_qoff_logformat_t	*qoff_f = item->ri_buf[0].i_addr;
 	ASSERT(qoff_f);
@@ -2483,9 +2491,9 @@ xlog_recover_quotaoff_pass1(
  */
 STATIC int
 xlog_recover_dquot_pass2(
-	xlog_t			*log,
-	struct list_head	*buffer_list,
-	xlog_recover_item_t	*item)
+	struct xlog			*log,
+	struct list_head		*buffer_list,
+	struct xlog_recover_item	*item)
 {
 	xfs_mount_t		*mp = log->l_mp;
 	xfs_buf_t		*bp;
@@ -2578,9 +2586,9 @@ xlog_recover_dquot_pass2(
  */
 STATIC int
 xlog_recover_efi_pass2(
-	xlog_t			*log,
-	xlog_recover_item_t	*item,
-	xfs_lsn_t		lsn)
+	struct xlog			*log,
+	struct xlog_recover_item	*item,
+	xfs_lsn_t			lsn)
 {
 	int			error;
 	xfs_mount_t		*mp = log->l_mp;
@@ -2616,8 +2624,8 @@ xlog_recover_efi_pass2(
  */
 STATIC int
 xlog_recover_efd_pass2(
-	xlog_t			*log,
-	xlog_recover_item_t	*item)
+	struct xlog			*log,
+	struct xlog_recover_item	*item)
 {
 	xfs_efd_log_format_t	*efd_formatp;
 	xfs_efi_log_item_t	*efip = NULL;
@@ -2812,9 +2820,9 @@ xlog_recover_unmount_trans(
  */
 STATIC int
 xlog_recover_process_data(
-	xlog_t			*log,
+	struct xlog		*log,
 	struct hlist_head	rhash[],
-	xlog_rec_header_t	*rhead,
+	struct xlog_rec_header	*rhead,
 	xfs_caddr_t		dp,
 	int			pass)
 {
@@ -2986,7 +2994,7 @@ abort_error:
  */
 STATIC int
 xlog_recover_process_efis(
-	xlog_t			*log)
+	struct xlog	*log)
 {
 	xfs_log_item_t		*lip;
 	xfs_efi_log_item_t	*efip;
@@ -3147,7 +3155,7 @@ xlog_recover_process_one_iunlink(
  */
 STATIC void
 xlog_recover_process_iunlinks(
-	xlog_t		*log)
+	struct xlog	*log)
 {
 	xfs_mount_t	*mp;
 	xfs_agnumber_t	agno;
@@ -3209,9 +3217,9 @@ xlog_recover_process_iunlinks(
 #ifdef DEBUG
 STATIC void
 xlog_pack_data_checksum(
-	xlog_t		*log,
-	xlog_in_core_t	*iclog,
-	int		size)
+	struct xlog		*log,
+	struct xlog_in_core	*iclog,
+	int			size)
 {
 	int		i;
 	__be32		*up;
@@ -3234,8 +3242,8 @@ xlog_pack_data_checksum(
  */
 void
 xlog_pack_data(
-	xlog_t			*log,
-	xlog_in_core_t		*iclog,
+	struct xlog		*log,
+	struct xlog_in_core	*iclog,
 	int			roundoff)
 {
 	int			i, j, k;
@@ -3274,9 +3282,9 @@ xlog_pack_data(
 
 STATIC void
 xlog_unpack_data(
-	xlog_rec_header_t	*rhead,
+	struct xlog_rec_header	*rhead,
 	xfs_caddr_t		dp,
-	xlog_t			*log)
+	struct xlog		*log)
 {
 	int			i, j, k;
 
@@ -3299,8 +3307,8 @@ xlog_unpack_data(
 
 STATIC int
 xlog_valid_rec_header(
-	xlog_t			*log,
-	xlog_rec_header_t	*rhead,
+	struct xlog		*log,
+	struct xlog_rec_header	*rhead,
 	xfs_daddr_t		blkno)
 {
 	int			hlen;
@@ -3343,7 +3351,7 @@ xlog_valid_rec_header(
  */
 STATIC int
 xlog_do_recovery_pass(
-	xlog_t			*log,
+	struct xlog		*log,
 	xfs_daddr_t		head_blk,
 	xfs_daddr_t		tail_blk,
 	int			pass)
@@ -3595,7 +3603,7 @@ xlog_do_recovery_pass(
  */
 STATIC int
 xlog_do_log_recovery(
-	xlog_t		*log,
+	struct xlog	*log,
 	xfs_daddr_t	head_blk,
 	xfs_daddr_t	tail_blk)
 {
@@ -3646,7 +3654,7 @@ xlog_do_log_recovery(
  */
 STATIC int
 xlog_do_recover(
-	xlog_t		*log,
+	struct xlog	*log,
 	xfs_daddr_t	head_blk,
 	xfs_daddr_t	tail_blk)
 {
@@ -3721,7 +3729,7 @@ xlog_do_recover(
  */
 int
 xlog_recover(
-	xlog_t		*log)
+	struct xlog	*log)
 {
 	xfs_daddr_t	head_blk, tail_blk;
 	int		error;
@@ -3767,7 +3775,7 @@ xlog_recover(
  */
 int
 xlog_recover_finish(
-	xlog_t		*log)
+	struct xlog	*log)
 {
 	/*
 	 * Now we're ready to do the transactions needed for the
@@ -3814,7 +3822,7 @@ xlog_recover_finish(
  */
 void
 xlog_recover_check_summary(
-	xlog_t		*log)
+	struct xlog	*log)
 {
 	xfs_mount_t	*mp;
 	xfs_agf_t	*agfp;
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 536021f..9536fd1 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1200,8 +1200,6 @@ xfs_mountfs(
 
 	xfs_set_maxicount(mp);
 
-	mp->m_maxioffset = xfs_max_file_offset(sbp->sb_blocklog);
-
 	error = xfs_uuid_mount(mp);
 	if (error)
 		goto out;
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 90c1fc9..8724336 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -176,7 +176,6 @@ typedef struct xfs_mount {
 	uint			m_qflags;	/* quota status flags */
 	xfs_trans_reservations_t m_reservations;/* precomputed res values */
 	__uint64_t		m_maxicount;	/* maximum inode count */
-	__uint64_t		m_maxioffset;	/* maximum inode offset */
 	__uint64_t		m_resblks;	/* total reserved blocks */
 	__uint64_t		m_resblks_avail;/* available reserved blocks */
 	__uint64_t		m_resblks_save;	/* reserved blks @ remount,ro */
@@ -297,8 +296,6 @@ xfs_preferred_iosize(xfs_mount_t *mp)
 			PAGE_CACHE_SIZE));
 }
 
-#define XFS_MAXIOFFSET(mp)	((mp)->m_maxioffset)
-
 #define XFS_LAST_UNMOUNT_WAS_CLEAN(mp)	\
 				((mp)->m_flags & XFS_MOUNT_WAS_CLEAN)
 #define XFS_FORCED_SHUTDOWN(mp)	((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN)
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 249db19..2e86fa0 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -940,7 +940,7 @@ xfs_qm_dqiterate(
 	map = kmem_alloc(XFS_DQITER_MAP_SIZE * sizeof(*map), KM_SLEEP);
 
 	lblkno = 0;
-	maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
+	maxlblkcnt = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
 	do {
 		nmaps = XFS_DQITER_MAP_SIZE;
 		/*
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 0d9de41..bbcbf2a 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1582,6 +1582,11 @@ xfs_init_zones(void)
 STATIC void
 xfs_destroy_zones(void)
 {
+	/*
+	 * Make sure all delayed rcu free are flushed before we
+	 * destroy caches.
+	 */
+	rcu_barrier();
 	kmem_zone_destroy(xfs_ili_zone);
 	kmem_zone_destroy(xfs_inode_zone);
 	kmem_zone_destroy(xfs_efi_zone);
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index b6a82d8..c22f4e0 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -174,7 +174,7 @@ xfs_free_eofblocks(
 	 * of the file.  If not, then there is nothing to do.
 	 */
 	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
-	last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
+	last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
 	if (last_fsb <= end_fsb)
 		return 0;
 	map_len = last_fsb - end_fsb;
@@ -2262,10 +2262,10 @@ xfs_change_file_space(
 
 	llen = bf->l_len > 0 ? bf->l_len - 1 : bf->l_len;
 
-	if (   (bf->l_start < 0)
-	    || (bf->l_start > XFS_MAXIOFFSET(mp))
-	    || (bf->l_start + llen < 0)
-	    || (bf->l_start + llen > XFS_MAXIOFFSET(mp)))
+	if (bf->l_start < 0 ||
+	    bf->l_start > mp->m_super->s_maxbytes ||
+	    bf->l_start + llen < 0 ||
+	    bf->l_start + llen > mp->m_super->s_maxbytes)
 		return XFS_ERROR(EINVAL);
 
 	bf->l_whence = 0;
diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h
index 38f5088..b177f97 100644
--- a/include/acpi/acnames.h
+++ b/include/acpi/acnames.h
@@ -62,6 +62,7 @@
 #define METHOD_NAME__AEI        "_AEI"
 #define METHOD_NAME__PRW        "_PRW"
 #define METHOD_NAME__SRS        "_SRS"
+#define METHOD_NAME__CBA        "_CBA"
 
 /* Method names - these methods must appear at the namespace root */
 
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 9e6e1c6..7ff5c16 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -50,6 +50,9 @@ acpi_evaluate_reference(acpi_handle handle,
 			acpi_string pathname,
 			struct acpi_object_list *arguments,
 			struct acpi_handle_list *list);
+acpi_status
+acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
+			u32 status_code, struct acpi_buffer *status_buf);
 
 struct acpi_pld {
 	unsigned int revision:7; /* 0 */
@@ -179,7 +182,8 @@ struct acpi_device_flags {
 	u32 suprise_removal_ok:1;
 	u32 power_manageable:1;
 	u32 performance_manageable:1;
-	u32 reserved:24;
+	u32 eject_pending:1;
+	u32 reserved:23;
 };
 
 /* File System */
@@ -331,6 +335,11 @@ struct acpi_bus_event {
 	u32 data;
 };
 
+struct acpi_eject_event {
+	acpi_handle	handle;
+	u32		event;
+};
+
 extern struct kobject *acpi_kobj;
 extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
 void acpi_bus_private_data_handler(acpi_handle, void *);
@@ -368,6 +377,7 @@ int acpi_bus_register_driver(struct acpi_driver *driver);
 void acpi_bus_unregister_driver(struct acpi_driver *driver);
 int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent,
 		 acpi_handle handle, int type);
+void acpi_bus_hot_remove_device(void *context);
 int acpi_bus_trim(struct acpi_device *start, int rmdevice);
 int acpi_bus_start(struct acpi_device *device);
 acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd);
@@ -401,6 +411,7 @@ struct acpi_pci_root {
 
 	u32 osc_support_set;	/* _OSC state of support bits */
 	u32 osc_control_set;	/* _OSC state of control bits */
+	phys_addr_t mcfg_addr;
 };
 
 /* helper */
@@ -414,13 +425,13 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state);
 int acpi_disable_wakeup_device_power(struct acpi_device *dev);
 
 #ifdef CONFIG_PM
-int acpi_pm_device_sleep_state(struct device *, int *);
+int acpi_pm_device_sleep_state(struct device *, int *, int);
 #else
-static inline int acpi_pm_device_sleep_state(struct device *d, int *p)
+static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m)
 {
 	if (p)
 		*p = ACPI_STATE_D0;
-	return ACPI_STATE_D3;
+	return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3) ? m : ACPI_STATE_D0;
 }
 #endif
 
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 21a5548..f3746f7 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -205,7 +205,7 @@ acpi_os_execute(acpi_execute_type type,
 acpi_status
 acpi_os_hotplug_execute(acpi_osd_exec_callback function, void *context);
 
-void acpi_os_wait_events_complete(void *context);
+void acpi_os_wait_events_complete(void);
 
 void acpi_os_sleep(u64 milliseconds);
 
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 9821101..381c940 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -47,7 +47,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20120320
+#define ACPI_CA_VERSION                 0x20120518
 
 #include "acconfig.h"
 #include "actypes.h"
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index e8bcc47..376c9ed 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -706,10 +706,14 @@ typedef u32 acpi_event_status;
 #define ACPI_DEVICE_NOTIFY              0x2
 #define ACPI_ALL_NOTIFY                 (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY)
 #define ACPI_MAX_NOTIFY_HANDLER_TYPE    0x3
+#define ACPI_NUM_NOTIFY_TYPES           2
 
 #define ACPI_MAX_SYS_NOTIFY             0x7F
 #define ACPI_MAX_DEVICE_SPECIFIC_NOTIFY 0xBF
 
+#define ACPI_SYSTEM_HANDLER_LIST        0	/* Used as index, must be SYSTEM_NOTIFY -1 */
+#define ACPI_DEVICE_HANDLER_LIST        1	/* Used as index, must be DEVICE_NOTIFY -1 */
+
 /* Address Space (Operation Region) Types */
 
 typedef u8 acpi_adr_space_type;
@@ -724,8 +728,9 @@ typedef u8 acpi_adr_space_type;
 #define ACPI_ADR_SPACE_IPMI             (acpi_adr_space_type) 7
 #define ACPI_ADR_SPACE_GPIO             (acpi_adr_space_type) 8
 #define ACPI_ADR_SPACE_GSBUS            (acpi_adr_space_type) 9
+#define ACPI_ADR_SPACE_PLATFORM_COMM    (acpi_adr_space_type) 10
 
-#define ACPI_NUM_PREDEFINED_REGIONS     10
+#define ACPI_NUM_PREDEFINED_REGIONS     11
 
 /*
  * Special Address Spaces
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 506ec19..7d10f96 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -3,10 +3,18 @@
 
 #include <linux/compiler.h>
 
+#ifdef CONFIG_GENERIC_BUG
+#define BUGFLAG_WARNING		(1 << 0)
+#define BUGFLAG_TAINT(taint)	(BUGFLAG_WARNING | ((taint) << 8))
+#define BUG_GET_TAINT(bug)	((bug)->flags >> 8)
+#endif
+
+#ifndef __ASSEMBLY__
+#include <linux/kernel.h>
+
 #ifdef CONFIG_BUG
 
 #ifdef CONFIG_GENERIC_BUG
-#ifndef __ASSEMBLY__
 struct bug_entry {
 #ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
 	unsigned long	bug_addr;
@@ -23,17 +31,8 @@ struct bug_entry {
 #endif
 	unsigned short	flags;
 };
-#endif		/* __ASSEMBLY__ */
-
-#define BUGFLAG_WARNING		(1 << 0)
-#define BUGFLAG_TAINT(taint)	(BUGFLAG_WARNING | ((taint) << 8))
-#define BUG_GET_TAINT(bug)	((bug)->flags >> 8)
-
 #endif	/* CONFIG_GENERIC_BUG */
 
-#ifndef __ASSEMBLY__
-#include <linux/kernel.h>
-
 /*
  * Don't use BUG() or BUG_ON() unless there's really no way out; one
  * example might be detecting data structure corruption in the middle
diff --git a/include/asm-generic/dma-coherent.h b/include/asm-generic/dma-coherent.h
index abfb268..2be8a2d 100644
--- a/include/asm-generic/dma-coherent.h
+++ b/include/asm-generic/dma-coherent.h
@@ -29,6 +29,7 @@ dma_mark_declared_memory_occupied(struct device *dev,
 #else
 #define dma_alloc_from_coherent(dev, size, handle, ret) (0)
 #define dma_release_from_coherent(dev, order, vaddr) (0)
+#define dma_mmap_from_coherent(dev, vma, vaddr, order, ret) (0)
 #endif
 
 #endif
diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h
index 2e248d8..de8bf89 100644
--- a/include/asm-generic/dma-mapping-common.h
+++ b/include/asm-generic/dma-mapping-common.h
@@ -176,4 +176,59 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
 #define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL)
 #define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL)
 
+extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+			   void *cpu_addr, dma_addr_t dma_addr, size_t size);
+
+/**
+ * dma_mmap_attrs - map a coherent DMA allocation into user space
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @vma: vm_area_struct describing requested user mapping
+ * @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs
+ * @handle: device-view address returned from dma_alloc_attrs
+ * @size: size of memory originally requested in dma_alloc_attrs
+ * @attrs: attributes of mapping properties requested in dma_alloc_attrs
+ *
+ * Map a coherent DMA buffer previously allocated by dma_alloc_attrs
+ * into user space.  The coherent DMA buffer must not be freed by the
+ * driver until the user space mapping has been released.
+ */
+static inline int
+dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
+	       dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+{
+	struct dma_map_ops *ops = get_dma_ops(dev);
+	BUG_ON(!ops);
+	if (ops->mmap)
+		return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
+	return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+
+#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
+
+static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+	DEFINE_DMA_ATTRS(attrs);
+	dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+	return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
+}
+
+int
+dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
+		       void *cpu_addr, dma_addr_t dma_addr, size_t size);
+
+static inline int
+dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr,
+		      dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+{
+	struct dma_map_ops *ops = get_dma_ops(dev);
+	BUG_ON(!ops);
+	if (ops->get_sgtable)
+		return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size,
+					attrs);
+	return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size);
+}
+
+#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL)
+
 #endif
diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h
index a1331ce..5d012c1 100644
--- a/include/asm-generic/errno.h
+++ b/include/asm-generic/errno.h
@@ -109,5 +109,8 @@
 #define ERFKILL		132	/* Operation not possible due to RF-kill */
 
 #define EHWPOISON	133	/* Memory page has hardware error */
+#define	ENOAUTHSERVICE	134	/* Authentication service not available */
+#define	ENONAMESERVICE	135	/* Network name service unavailable */
+#define	ENAMEUNKNOWN	136	/* Network name unknown */
 
 #endif
diff --git a/include/asm-generic/fcntl.h b/include/asm-generic/fcntl.h
index 9e5b035..a48937d 100644
--- a/include/asm-generic/fcntl.h
+++ b/include/asm-generic/fcntl.h
@@ -120,6 +120,10 @@
 #define F_GETOWN_EX	16
 #endif
 
+#ifndef F_GETOWNER_UIDS
+#define F_GETOWNER_UIDS	17
+#endif
+
 #define F_OWNER_TID	0
 #define F_OWNER_PID	1
 #define F_OWNER_PGRP	2
diff --git a/include/asm-generic/kmap_types.h b/include/asm-generic/kmap_types.h
index 0232ccb..90f99c7 100644
--- a/include/asm-generic/kmap_types.h
+++ b/include/asm-generic/kmap_types.h
@@ -2,39 +2,9 @@
 #define _ASM_GENERIC_KMAP_TYPES_H
 
 #ifdef __WITH_KM_FENCE
-# define KMAP_D(n) __KM_FENCE_##n ,
+# define KM_TYPE_NR 41
 #else
-# define KMAP_D(n)
+# define KM_TYPE_NR 20
 #endif
 
-enum km_type {
-KMAP_D(0)	KM_BOUNCE_READ,
-KMAP_D(1)	KM_SKB_SUNRPC_DATA,
-KMAP_D(2)	KM_SKB_DATA_SOFTIRQ,
-KMAP_D(3)	KM_USER0,
-KMAP_D(4)	KM_USER1,
-KMAP_D(5)	KM_BIO_SRC_IRQ,
-KMAP_D(6)	KM_BIO_DST_IRQ,
-KMAP_D(7)	KM_PTE0,
-KMAP_D(8)	KM_PTE1,
-KMAP_D(9)	KM_IRQ0,
-KMAP_D(10)	KM_IRQ1,
-KMAP_D(11)	KM_SOFTIRQ0,
-KMAP_D(12)	KM_SOFTIRQ1,
-KMAP_D(13)	KM_SYNC_ICACHE,
-KMAP_D(14)	KM_SYNC_DCACHE,
-/* UML specific, for copy_*_user - used in do_op_one_page */
-KMAP_D(15)	KM_UML_USERCOPY,
-KMAP_D(16)	KM_IRQ_PTE,
-KMAP_D(17)	KM_NMI,
-KMAP_D(18)	KM_NMI_PTE,
-KMAP_D(19)	KM_KDB,
-/*
- * Remember to update debug_kmap_atomic() when adding new kmap types!
- */
-KMAP_D(20)	KM_TYPE_NR
-};
-
-#undef KMAP_D
-
 #endif
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index f3f8224..bab1743 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -200,6 +200,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_GEM_EXECBUFFER2	0x29
 #define DRM_I915_GET_SPRITE_COLORKEY	0x2a
 #define DRM_I915_SET_SPRITE_COLORKEY	0x2b
+#define DRM_I915_GEM_WAIT	0x2c
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -243,6 +244,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_OVERLAY_ATTRS	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
 #define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
 #define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
+#define DRM_IOCTL_I915_GEM_WAIT		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -886,4 +888,12 @@ struct drm_intel_sprite_colorkey {
 	__u32 flags;
 };
 
+struct drm_i915_gem_wait {
+	/** Handle of BO we shall wait on */
+	__u32 bo_handle;
+	__u32 flags;
+	/** Number of nanoseconds to wait, Returns time remaining. */
+	__u64 timeout_ns;
+};
+
 #endif				/* _I915_DRM_H_ */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 8760be3..b20e578 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -84,7 +84,6 @@ header-y += capability.h
 header-y += capi.h
 header-y += cciss_defs.h
 header-y += cciss_ioctl.h
-header-y += cdk.h
 header-y += cdrom.h
 header-y += cgroupstats.h
 header-y += chio.h
@@ -93,7 +92,6 @@ header-y += cn_proc.h
 header-y += coda.h
 header-y += coda_psdev.h
 header-y += coff.h
-header-y += comstats.h
 header-y += connector.h
 header-y += const.h
 header-y += cramfs_fs.h
@@ -140,7 +138,6 @@ header-y += fuse.h
 header-y += futex.h
 header-y += gameport.h
 header-y += gen_stats.h
-header-y += generic_serial.h
 header-y += genetlink.h
 header-y += gfs2_ondisk.h
 header-y += gigaset_dev.h
@@ -183,7 +180,6 @@ header-y += if_ppp.h
 header-y += if_pppol2tp.h
 header-y += if_pppox.h
 header-y += if_slip.h
-header-y += if_strip.h
 header-y += if_team.h
 header-y += if_tun.h
 header-y += if_tunnel.h
@@ -376,6 +372,7 @@ header-y += tty.h
 header-y += types.h
 header-y += udf_fs_i.h
 header-y += udp.h
+header-y += uhid.h
 header-y += uinput.h
 header-y += uio.h
 header-y += ultrasound.h
diff --git a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h
deleted file mode 100644
index 0260c3e..0000000
--- a/include/linux/ac97_codec.h
+++ /dev/null
@@ -1,362 +0,0 @@
-#ifndef _AC97_CODEC_H_
-#define _AC97_CODEC_H_
-
-#include <linux/types.h>
-#include <linux/soundcard.h>
-
-/* AC97 1.0 */
-#define  AC97_RESET               0x0000      //
-#define  AC97_MASTER_VOL_STEREO   0x0002      // Line Out
-#define  AC97_HEADPHONE_VOL       0x0004      // 
-#define  AC97_MASTER_VOL_MONO     0x0006      // TAD Output
-#define  AC97_MASTER_TONE         0x0008      //
-#define  AC97_PCBEEP_VOL          0x000a      // none
-#define  AC97_PHONE_VOL           0x000c      // TAD Input (mono)
-#define  AC97_MIC_VOL             0x000e      // MIC Input (mono)
-#define  AC97_LINEIN_VOL          0x0010      // Line Input (stereo)
-#define  AC97_CD_VOL              0x0012      // CD Input (stereo)
-#define  AC97_VIDEO_VOL           0x0014      // none
-#define  AC97_AUX_VOL             0x0016      // Aux Input (stereo)
-#define  AC97_PCMOUT_VOL          0x0018      // Wave Output (stereo)
-#define  AC97_RECORD_SELECT       0x001a      //
-#define  AC97_RECORD_GAIN         0x001c
-#define  AC97_RECORD_GAIN_MIC     0x001e
-#define  AC97_GENERAL_PURPOSE     0x0020
-#define  AC97_3D_CONTROL          0x0022
-#define  AC97_MODEM_RATE          0x0024
-#define  AC97_POWER_CONTROL       0x0026
-
-/* AC'97 2.0 */
-#define AC97_EXTENDED_ID          0x0028       /* Extended Audio ID */
-#define AC97_EXTENDED_STATUS      0x002A       /* Extended Audio Status */
-#define AC97_PCM_FRONT_DAC_RATE   0x002C       /* PCM Front DAC Rate */
-#define AC97_PCM_SURR_DAC_RATE    0x002E       /* PCM Surround DAC Rate */
-#define AC97_PCM_LFE_DAC_RATE     0x0030       /* PCM LFE DAC Rate */
-#define AC97_PCM_LR_ADC_RATE      0x0032       /* PCM LR ADC Rate */
-#define AC97_PCM_MIC_ADC_RATE     0x0034       /* PCM MIC ADC Rate */
-#define AC97_CENTER_LFE_MASTER    0x0036       /* Center + LFE Master Volume */
-#define AC97_SURROUND_MASTER      0x0038       /* Surround (Rear) Master Volume */
-#define AC97_RESERVED_3A          0x003A       /* Reserved in AC '97 < 2.2 */
-
-/* AC'97 2.2 */
-#define AC97_SPDIF_CONTROL        0x003A       /* S/PDIF Control */
-
-/* range 0x3c-0x58 - MODEM */
-#define AC97_EXTENDED_MODEM_ID    0x003C
-#define AC97_EXTEND_MODEM_STAT    0x003E
-#define AC97_LINE1_RATE           0x0040
-#define AC97_LINE2_RATE           0x0042
-#define AC97_HANDSET_RATE         0x0044
-#define AC97_LINE1_LEVEL          0x0046
-#define AC97_LINE2_LEVEL          0x0048
-#define AC97_HANDSET_LEVEL        0x004A
-#define AC97_GPIO_CONFIG          0x004C
-#define AC97_GPIO_POLARITY        0x004E
-#define AC97_GPIO_STICKY          0x0050
-#define AC97_GPIO_WAKE_UP         0x0052
-#define AC97_GPIO_STATUS          0x0054
-#define AC97_MISC_MODEM_STAT      0x0056
-#define AC97_RESERVED_58          0x0058
-
-/* registers 0x005a - 0x007a are vendor reserved */
-
-#define AC97_VENDOR_ID1           0x007c
-#define AC97_VENDOR_ID2           0x007e
-
-/* volume control bit defines */
-#define AC97_MUTE                 0x8000
-#define AC97_MICBOOST             0x0040
-#define AC97_LEFTVOL              0x3f00
-#define AC97_RIGHTVOL             0x003f
-
-/* record mux defines */
-#define AC97_RECMUX_MIC           0x0000
-#define AC97_RECMUX_CD            0x0101
-#define AC97_RECMUX_VIDEO         0x0202
-#define AC97_RECMUX_AUX           0x0303
-#define AC97_RECMUX_LINE          0x0404
-#define AC97_RECMUX_STEREO_MIX    0x0505
-#define AC97_RECMUX_MONO_MIX      0x0606
-#define AC97_RECMUX_PHONE         0x0707
-
-/* general purpose register bit defines */
-#define AC97_GP_LPBK              0x0080       /* Loopback mode */
-#define AC97_GP_MS                0x0100       /* Mic Select 0=Mic1, 1=Mic2 */
-#define AC97_GP_MIX               0x0200       /* Mono output select 0=Mix, 1=Mic */
-#define AC97_GP_RLBK              0x0400       /* Remote Loopback - Modem line codec */
-#define AC97_GP_LLBK              0x0800       /* Local Loopback - Modem Line codec */
-#define AC97_GP_LD                0x1000       /* Loudness 1=on */
-#define AC97_GP_3D                0x2000       /* 3D Enhancement 1=on */
-#define AC97_GP_ST                0x4000       /* Stereo Enhancement 1=on */
-#define AC97_GP_POP               0x8000       /* Pcm Out Path, 0=pre 3D, 1=post 3D */
-
-/* extended audio status and control bit defines */
-#define AC97_EA_VRA               0x0001       /* Variable bit rate enable bit */
-#define AC97_EA_DRA               0x0002       /* Double-rate audio enable bit */
-#define AC97_EA_SPDIF             0x0004       /* S/PDIF Enable bit */
-#define AC97_EA_VRM               0x0008       /* Variable bit rate for MIC enable bit */
-#define AC97_EA_CDAC              0x0040       /* PCM Center DAC is ready (Read only) */
-#define AC97_EA_SDAC              0x0040       /* PCM Surround DACs are ready (Read only) */
-#define AC97_EA_LDAC              0x0080       /* PCM LFE DAC is ready (Read only) */
-#define AC97_EA_MDAC              0x0100       /* MIC ADC is ready (Read only) */
-#define AC97_EA_SPCV              0x0400       /* S/PDIF configuration valid (Read only) */
-#define AC97_EA_PRI               0x0800       /* Turns the PCM Center DAC off */
-#define AC97_EA_PRJ               0x1000       /* Turns the PCM Surround DACs off */
-#define AC97_EA_PRK               0x2000       /* Turns the PCM LFE DAC off */
-#define AC97_EA_PRL               0x4000       /* Turns the MIC ADC off */
-#define AC97_EA_SLOT_MASK         0xffcf       /* Mask for slot assignment bits */
-#define AC97_EA_SPSA_3_4          0x0000       /* Slot assigned to 3 & 4 */
-#define AC97_EA_SPSA_7_8          0x0010       /* Slot assigned to 7 & 8 */
-#define AC97_EA_SPSA_6_9          0x0020       /* Slot assigned to 6 & 9 */
-#define AC97_EA_SPSA_10_11        0x0030       /* Slot assigned to 10 & 11 */
-
-/* S/PDIF control bit defines */
-#define AC97_SC_PRO               0x0001       /* Professional status */
-#define AC97_SC_NAUDIO            0x0002       /* Non audio stream */
-#define AC97_SC_COPY              0x0004       /* Copyright status */
-#define AC97_SC_PRE               0x0008       /* Preemphasis status */
-#define AC97_SC_CC_MASK           0x07f0       /* Category Code mask */
-#define AC97_SC_L                 0x0800       /* Generation Level status */
-#define AC97_SC_SPSR_MASK         0xcfff       /* S/PDIF Sample Rate bits */
-#define AC97_SC_SPSR_44K          0x0000       /* Use 44.1kHz Sample rate */
-#define AC97_SC_SPSR_48K          0x2000       /* Use 48kHz Sample rate */
-#define AC97_SC_SPSR_32K          0x3000       /* Use 32kHz Sample rate */
-#define AC97_SC_DRS               0x4000       /* Double Rate S/PDIF */
-#define AC97_SC_V                 0x8000       /* Validity status */
-
-/* powerdown control and status bit defines */
-
-/* status */
-#define AC97_PWR_MDM              0x0010       /* Modem section ready */
-#define AC97_PWR_REF              0x0008       /* Vref nominal */
-#define AC97_PWR_ANL              0x0004       /* Analog section ready */
-#define AC97_PWR_DAC              0x0002       /* DAC section ready */
-#define AC97_PWR_ADC              0x0001       /* ADC section ready */
-
-/* control */
-#define AC97_PWR_PR0              0x0100       /* ADC and Mux powerdown */
-#define AC97_PWR_PR1              0x0200       /* DAC powerdown */
-#define AC97_PWR_PR2              0x0400       /* Output mixer powerdown (Vref on) */
-#define AC97_PWR_PR3              0x0800       /* Output mixer powerdown (Vref off) */
-#define AC97_PWR_PR4              0x1000       /* AC-link powerdown */
-#define AC97_PWR_PR5              0x2000       /* Internal Clk disable */
-#define AC97_PWR_PR6              0x4000       /* HP amp powerdown */
-#define AC97_PWR_PR7              0x8000       /* Modem off - if supported */
-
-/* extended audio ID register bit defines */
-#define AC97_EXTID_VRA            0x0001
-#define AC97_EXTID_DRA            0x0002
-#define AC97_EXTID_SPDIF          0x0004
-#define AC97_EXTID_VRM            0x0008
-#define AC97_EXTID_DSA0           0x0010
-#define AC97_EXTID_DSA1           0x0020
-#define AC97_EXTID_CDAC           0x0040
-#define AC97_EXTID_SDAC           0x0080
-#define AC97_EXTID_LDAC           0x0100
-#define AC97_EXTID_AMAP           0x0200
-#define AC97_EXTID_REV0           0x0400
-#define AC97_EXTID_REV1           0x0800
-#define AC97_EXTID_ID0            0x4000
-#define AC97_EXTID_ID1            0x8000
-
-/* extended status register bit defines */
-#define AC97_EXTSTAT_VRA          0x0001
-#define AC97_EXTSTAT_DRA          0x0002
-#define AC97_EXTSTAT_SPDIF        0x0004
-#define AC97_EXTSTAT_VRM          0x0008
-#define AC97_EXTSTAT_SPSA0        0x0010
-#define AC97_EXTSTAT_SPSA1        0x0020
-#define AC97_EXTSTAT_CDAC         0x0040
-#define AC97_EXTSTAT_SDAC         0x0080
-#define AC97_EXTSTAT_LDAC         0x0100
-#define AC97_EXTSTAT_MADC         0x0200
-#define AC97_EXTSTAT_SPCV         0x0400
-#define AC97_EXTSTAT_PRI          0x0800
-#define AC97_EXTSTAT_PRJ          0x1000
-#define AC97_EXTSTAT_PRK          0x2000
-#define AC97_EXTSTAT_PRL          0x4000
-
-/* extended audio ID register bit defines */
-#define AC97_EXTID_VRA            0x0001
-#define AC97_EXTID_DRA            0x0002
-#define AC97_EXTID_SPDIF          0x0004
-#define AC97_EXTID_VRM            0x0008
-#define AC97_EXTID_DSA0           0x0010
-#define AC97_EXTID_DSA1           0x0020
-#define AC97_EXTID_CDAC           0x0040
-#define AC97_EXTID_SDAC           0x0080
-#define AC97_EXTID_LDAC           0x0100
-#define AC97_EXTID_AMAP           0x0200
-#define AC97_EXTID_REV0           0x0400
-#define AC97_EXTID_REV1           0x0800
-#define AC97_EXTID_ID0            0x4000
-#define AC97_EXTID_ID1            0x8000
-
-/* extended status register bit defines */
-#define AC97_EXTSTAT_VRA          0x0001
-#define AC97_EXTSTAT_DRA          0x0002
-#define AC97_EXTSTAT_SPDIF        0x0004
-#define AC97_EXTSTAT_VRM          0x0008
-#define AC97_EXTSTAT_SPSA0        0x0010
-#define AC97_EXTSTAT_SPSA1        0x0020
-#define AC97_EXTSTAT_CDAC         0x0040
-#define AC97_EXTSTAT_SDAC         0x0080
-#define AC97_EXTSTAT_LDAC         0x0100
-#define AC97_EXTSTAT_MADC         0x0200
-#define AC97_EXTSTAT_SPCV         0x0400
-#define AC97_EXTSTAT_PRI          0x0800
-#define AC97_EXTSTAT_PRJ          0x1000
-#define AC97_EXTSTAT_PRK          0x2000
-#define AC97_EXTSTAT_PRL          0x4000
-
-/* useful power states */
-#define AC97_PWR_D0               0x0000      /* everything on */
-#define AC97_PWR_D1              AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR4
-#define AC97_PWR_D2              AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
-#define AC97_PWR_D3              AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
-#define AC97_PWR_ANLOFF          AC97_PWR_PR2|AC97_PWR_PR3  /* analog section off */
-
-/* Total number of defined registers.  */
-#define AC97_REG_CNT 64
-
-
-/* OSS interface to the ac97s.. */
-#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_PCM|\
-	SOUND_MASK_LINE|SOUND_MASK_CD|\
-	SOUND_MASK_ALTPCM|SOUND_MASK_IGAIN|\
-	SOUND_MASK_LINE1|SOUND_MASK_VIDEO)
-
-#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
-	SOUND_MASK_BASS|SOUND_MASK_TREBLE|\
-	SOUND_MASK_SPEAKER|SOUND_MASK_MIC|\
-	SOUND_MASK_PHONEIN|SOUND_MASK_PHONEOUT)
-
-#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
-	SOUND_MASK_CD|SOUND_MASK_IGAIN|SOUND_MASK_VIDEO|\
-	SOUND_MASK_LINE1| SOUND_MASK_LINE|\
-	SOUND_MASK_PHONEIN)
-
-/* original check is not good enough in case FOO is greater than
- * SOUND_MIXER_NRDEVICES because the supported_mixers has exactly
- * SOUND_MIXER_NRDEVICES elements.
- * before matching the given mixer against the bitmask in supported_mixers we
- * check if mixer number exceeds maximum allowed size which is as mentioned
- * above SOUND_MIXER_NRDEVICES */
-#define supported_mixer(CODEC,FOO) ((FOO >= 0) && \
-                                    (FOO < SOUND_MIXER_NRDEVICES) && \
-                                    (CODEC)->supported_mixers & (1<<FOO) )
-
-struct ac97_codec {
-	/* Linked list of codecs */
-	struct list_head list;
-
-	/* AC97 controller connected with */
-	void *private_data;
-
-	char *name;
-	int id;
-	int dev_mixer; 
-	int type;
-	u32 model;
-
-	unsigned int modem:1;
-
-	struct ac97_ops *codec_ops;
-
-	/* controller specific lower leverl ac97 accessing routines.
-	   must be re-entrant safe */
-	u16  (*codec_read)  (struct ac97_codec *codec, u8 reg);
-	void (*codec_write) (struct ac97_codec *codec, u8 reg, u16 val);
-
-	/* Wait for codec-ready.  Ok to sleep here.  */
-	void  (*codec_wait)  (struct ac97_codec *codec);
-
-	/* callback used by helper drivers for interesting ac97 setups */
-	void  (*codec_unregister) (struct ac97_codec *codec);
-	
-	struct ac97_driver *driver;
-	void *driver_private;	/* Private data for the driver */
-	
-	spinlock_t lock;
-	
-	/* OSS mixer masks */
-	int modcnt;
-	int supported_mixers;
-	int stereo_mixers;
-	int record_sources;
-
-	/* Property flags */
-	int flags;
-
-	int bit_resolution;
-
-	/* OSS mixer interface */
-	int  (*read_mixer) (struct ac97_codec *codec, int oss_channel);
-	void (*write_mixer)(struct ac97_codec *codec, int oss_channel,
-			    unsigned int left, unsigned int right);
-	int  (*recmask_io) (struct ac97_codec *codec, int rw, int mask);
-	int  (*mixer_ioctl)(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
-
-	/* saved OSS mixer states */
-	unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
-
-	/* Software Modem interface */
-	int  (*modem_ioctl)(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
-};
-
-/*
- *	Operation structures for each known AC97 chip
- */
- 
-struct ac97_ops
-{
-	/* Initialise */
-	int (*init)(struct ac97_codec *c);
-	/* Amplifier control */
-	int (*amplifier)(struct ac97_codec *codec, int on);
-	/* Digital mode control */
-	int (*digital)(struct ac97_codec *codec, int slots, int rate, int mode);
-#define AUDIO_DIGITAL		0x8000
-#define AUDIO_PRO		0x4000
-#define AUDIO_DRS		0x2000
-#define AUDIO_CCMASK		0x003F
-	
-#define AC97_DELUDED_MODEM	1	/* Audio codec reports its a modem */
-#define AC97_NO_PCM_VOLUME	2	/* Volume control is missing 	   */
-#define AC97_DEFAULT_POWER_OFF 4 /* Needs warm reset to power up */
-};
-
-extern int ac97_probe_codec(struct ac97_codec *);
-
-extern struct ac97_codec *ac97_alloc_codec(void);
-extern void ac97_release_codec(struct ac97_codec *codec);
-
-struct ac97_driver {
-	struct list_head list;
-	char *name;
-	u32 codec_id;
-	u32 codec_mask;
-	int (*probe) (struct ac97_codec *codec, struct ac97_driver *driver);
-	void (*remove) (struct ac97_codec *codec, struct ac97_driver *driver);
-};
-
-/* quirk types */
-enum {
-	AC97_TUNE_DEFAULT = -1, /* use default from quirk list (not valid in list) */
-	AC97_TUNE_NONE = 0,     /* nothing extra to do */
-	AC97_TUNE_HP_ONLY,      /* headphone (true line-out) control as master only */
-	AC97_TUNE_SWAP_HP,      /* swap headphone and master controls */
-	AC97_TUNE_SWAP_SURROUND, /* swap master and surround controls */
-	AC97_TUNE_AD_SHARING,   /* for AD1985, turn on OMS bit and use headphone */
-	AC97_TUNE_ALC_JACK,     /* for Realtek, enable JACK detection */
-};
-
-struct ac97_quirk {
-	unsigned short vendor;  /* PCI vendor id */
-	unsigned short device;  /* PCI device id */
-	unsigned short mask;    /* device id bit mask, 0 = accept all */
-	const char *name;       /* name shown as info */
-	int type;               /* quirk type above */
-};
-
-#endif /* _AC97_CODEC_H_ */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index f421dd8..b2b4d2a 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -277,7 +277,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 #define OSC_SB_PAD_SUPPORT		1
 #define OSC_SB_PPC_OST_SUPPORT		2
 #define OSC_SB_PR3_SUPPORT		4
-#define OSC_SB_CPUHP_OST_SUPPORT	8
+#define OSC_SB_HOTPLUG_OST_SUPPORT	8
 #define OSC_SB_APEI_SUPPORT		16
 
 extern bool osc_sb_apei_support_acked;
@@ -309,6 +309,44 @@ extern bool osc_sb_apei_support_acked;
 
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
 					     u32 *mask, u32 req);
+
+/* Enable _OST when all relevant hotplug operations are enabled */
+#if defined(CONFIG_ACPI_HOTPLUG_CPU) &&			\
+	(defined(CONFIG_ACPI_HOTPLUG_MEMORY) ||		\
+	 defined(CONFIG_ACPI_HOTPLUG_MEMORY_MODULE)) &&	\
+	(defined(CONFIG_ACPI_CONTAINER) ||		\
+	 defined(CONFIG_ACPI_CONTAINER_MODULE))
+#define ACPI_HOTPLUG_OST
+#endif
+
+/* _OST Source Event Code (OSPM Action) */
+#define ACPI_OST_EC_OSPM_SHUTDOWN		0x100
+#define ACPI_OST_EC_OSPM_EJECT			0x103
+#define ACPI_OST_EC_OSPM_INSERTION		0x200
+
+/* _OST General Processing Status Code */
+#define ACPI_OST_SC_SUCCESS			0x0
+#define ACPI_OST_SC_NON_SPECIFIC_FAILURE	0x1
+#define ACPI_OST_SC_UNRECOGNIZED_NOTIFY		0x2
+
+/* _OST OS Shutdown Processing (0x100) Status Code */
+#define ACPI_OST_SC_OS_SHUTDOWN_DENIED		0x80
+#define ACPI_OST_SC_OS_SHUTDOWN_IN_PROGRESS	0x81
+#define ACPI_OST_SC_OS_SHUTDOWN_COMPLETED	0x82
+#define ACPI_OST_SC_OS_SHUTDOWN_NOT_SUPPORTED	0x83
+
+/* _OST Ejection Request (0x3, 0x103) Status Code */
+#define ACPI_OST_SC_EJECT_NOT_SUPPORTED		0x80
+#define ACPI_OST_SC_DEVICE_IN_USE		0x81
+#define ACPI_OST_SC_DEVICE_BUSY			0x82
+#define ACPI_OST_SC_EJECT_DEPENDENCY_BUSY	0x83
+#define ACPI_OST_SC_EJECT_IN_PROGRESS		0x84
+
+/* _OST Insertion Request (0x200) Status Code */
+#define ACPI_OST_SC_INSERT_IN_PROGRESS		0x80
+#define ACPI_OST_SC_DRIVER_LOAD_FAILURE		0x81
+#define ACPI_OST_SC_INSERT_NOT_SUPPORTED	0x82
+
 extern void acpi_early_init(void);
 
 extern int acpi_nvs_register(__u64 start, __u64 size);
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 22f292a..4d10e5f 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -687,6 +687,8 @@ extern void		    audit_log_d_path(struct audit_buffer *ab,
 					     const struct path *path);
 extern void		    audit_log_key(struct audit_buffer *ab,
 					  char *key);
+extern void		    audit_log_link_denied(const char *operation,
+						  struct path *link);
 extern void		    audit_log_lost(const char *message);
 #ifdef CONFIG_SECURITY
 extern void 		    audit_log_secctx(struct audit_buffer *ab, u32 secid);
@@ -716,6 +718,7 @@ extern int audit_enabled;
 #define audit_log_untrustedstring(a,s) do { ; } while (0)
 #define audit_log_d_path(b, p, d) do { ; } while (0)
 #define audit_log_key(b, k) do { ; } while (0)
+#define audit_log_link_denied(o, l) do { ; } while (0)
 #define audit_log_secctx(b,s) do { ; } while (0)
 #define audit_enabled 0
 #endif
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index b1038bd..c97c6b9 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -10,13 +10,14 @@
 
 #include <linux/percpu_counter.h>
 #include <linux/log2.h>
-#include <linux/proportions.h>
+#include <linux/flex_proportions.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/writeback.h>
 #include <linux/atomic.h>
+#include <linux/sysctl.h>
 
 struct page;
 struct device;
@@ -89,7 +90,7 @@ struct backing_dev_info {
 	unsigned long dirty_ratelimit;
 	unsigned long balanced_dirty_ratelimit;
 
-	struct prop_local_percpu completions;
+	struct fprop_local_percpu completions;
 	int dirty_exceeded;
 
 	unsigned int min_ratio;
@@ -304,6 +305,8 @@ void clear_bdi_congested(struct backing_dev_info *bdi, int sync);
 void set_bdi_congested(struct backing_dev_info *bdi, int sync);
 long congestion_wait(int sync, long timeout);
 long wait_iff_congested(struct zone *zone, int sync, long timeout);
+int pdflush_proc_obsolete(struct ctl_table *table, int write,
+		void __user *buffer, size_t *lenp, loff_t *ppos);
 
 static inline bool bdi_cap_writeback_dirty(struct backing_dev_info *bdi)
 {
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index ba43f40..07954b0 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -827,7 +827,6 @@ extern bool __blk_end_request_err(struct request *rq, int error);
 extern void blk_complete_request(struct request *);
 extern void __blk_complete_request(struct request *);
 extern void blk_abort_request(struct request *);
-extern void blk_abort_queue(struct request_queue *);
 extern void blk_unprep_request(struct request *);
 
 /*
diff --git a/include/linux/can.h b/include/linux/can.h
index 9a19bcb..1a66cf61 100644
--- a/include/linux/can.h
+++ b/include/linux/can.h
@@ -21,7 +21,7 @@
 /* special address description flags for the CAN_ID */
 #define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
 #define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
-#define CAN_ERR_FLAG 0x20000000U /* error frame */
+#define CAN_ERR_FLAG 0x20000000U /* error message frame */
 
 /* valid bits in CAN ID for frame formats */
 #define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
@@ -32,32 +32,81 @@
  * Controller Area Network Identifier structure
  *
  * bit 0-28	: CAN identifier (11/29 bit)
- * bit 29	: error frame flag (0 = data frame, 1 = error frame)
+ * bit 29	: error message frame flag (0 = data frame, 1 = error message)
  * bit 30	: remote transmission request flag (1 = rtr frame)
  * bit 31	: frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
  */
 typedef __u32 canid_t;
 
 /*
- * Controller Area Network Error Frame Mask structure
+ * Controller Area Network Error Message Frame Mask structure
  *
  * bit 0-28	: error class mask (see include/linux/can/error.h)
  * bit 29-31	: set to zero
  */
 typedef __u32 can_err_mask_t;
 
+/* CAN payload length and DLC definitions according to ISO 11898-1 */
+#define CAN_MAX_DLC 8
+#define CAN_MAX_DLEN 8
+
+/* CAN FD payload length and DLC definitions according to ISO 11898-7 */
+#define CANFD_MAX_DLC 15
+#define CANFD_MAX_DLEN 64
+
 /**
  * struct can_frame - basic CAN frame structure
- * @can_id:  the CAN ID of the frame and CAN_*_FLAG flags, see above.
- * @can_dlc: the data length field of the CAN frame
- * @data:    the CAN frame payload.
+ * @can_id:  CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
+ * @can_dlc: frame payload length in byte (0 .. 8) aka data length code
+ *           N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
+ *           mapping of the 'data length code' to the real payload length
+ * @data:    CAN frame payload (up to 8 byte)
  */
 struct can_frame {
 	canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
-	__u8    can_dlc; /* data length code: 0 .. 8 */
-	__u8    data[8] __attribute__((aligned(8)));
+	__u8    can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
+	__u8    data[CAN_MAX_DLEN] __attribute__((aligned(8)));
 };
 
+/*
+ * defined bits for canfd_frame.flags
+ *
+ * As the default for CAN FD should be to support the high data rate in the
+ * payload section of the frame (HDR) and to support up to 64 byte in the
+ * data section (EDL) the bits are only set in the non-default case.
+ * Btw. as long as there's no real implementation for CAN FD network driver
+ * these bits are only preliminary.
+ *
+ * RX: NOHDR/NOEDL - info about received CAN FD frame
+ *     ESI         - bit from originating CAN controller
+ * TX: NOHDR/NOEDL - control per-frame settings if supported by CAN controller
+ *     ESI         - bit is set by local CAN controller
+ */
+#define CANFD_NOHDR 0x01 /* frame without high data rate */
+#define CANFD_NOEDL 0x02 /* frame without extended data length */
+#define CANFD_ESI   0x04 /* error state indicator */
+
+/**
+ * struct canfd_frame - CAN flexible data rate frame structure
+ * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
+ * @len:    frame payload length in byte (0 .. CANFD_MAX_DLEN)
+ * @flags:  additional flags for CAN FD
+ * @__res0: reserved / padding
+ * @__res1: reserved / padding
+ * @data:   CAN FD frame payload (up to CANFD_MAX_DLEN byte)
+ */
+struct canfd_frame {
+	canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+	__u8    len;     /* frame payload length in byte */
+	__u8    flags;   /* additional flags for CAN FD */
+	__u8    __res0;  /* reserved / padding */
+	__u8    __res1;  /* reserved / padding */
+	__u8    data[CANFD_MAX_DLEN] __attribute__((aligned(8)));
+};
+
+#define CAN_MTU		(sizeof(struct can_frame))
+#define CANFD_MTU	(sizeof(struct canfd_frame))
+
 /* particular protocols of the protocol family PF_CAN */
 #define CAN_RAW		1 /* RAW sockets */
 #define CAN_BCM		2 /* Broadcast Manager */
@@ -97,7 +146,7 @@ struct sockaddr_can {
  *          <received_can_id> & mask == can_id & mask
  *
  * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
- * filter for error frames (CAN_ERR_FLAG bit set in mask).
+ * filter for error message frames (CAN_ERR_FLAG bit set in mask).
  */
 struct can_filter {
 	canid_t can_id;
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index 0ccc1cd..78c6c52 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -17,10 +17,10 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 
-#define CAN_VERSION "20090105"
+#define CAN_VERSION "20120528"
 
 /* increment this number each time you change some user-space interface */
-#define CAN_ABI_VERSION "8"
+#define CAN_ABI_VERSION "9"
 
 #define CAN_VERSION_STRING "rev " CAN_VERSION " abi " CAN_ABI_VERSION
 
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
index 5d2efe7..ee5a771 100644
--- a/include/linux/can/dev.h
+++ b/include/linux/can/dev.h
@@ -61,23 +61,40 @@ struct can_priv {
  * To be used in the CAN netdriver receive path to ensure conformance with
  * ISO 11898-1 Chapter 8.4.2.3 (DLC field)
  */
-#define get_can_dlc(i)	(min_t(__u8, (i), 8))
+#define get_can_dlc(i)		(min_t(__u8, (i), CAN_MAX_DLC))
+#define get_canfd_dlc(i)	(min_t(__u8, (i), CANFD_MAX_DLC))
 
 /* Drop a given socketbuffer if it does not contain a valid CAN frame. */
 static inline int can_dropped_invalid_skb(struct net_device *dev,
 					  struct sk_buff *skb)
 {
-	const struct can_frame *cf = (struct can_frame *)skb->data;
-
-	if (unlikely(skb->len != sizeof(*cf) || cf->can_dlc > 8)) {
-		kfree_skb(skb);
-		dev->stats.tx_dropped++;
-		return 1;
-	}
+	const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+
+	if (skb->protocol == htons(ETH_P_CAN)) {
+		if (unlikely(skb->len != CAN_MTU ||
+			     cfd->len > CAN_MAX_DLEN))
+			goto inval_skb;
+	} else if (skb->protocol == htons(ETH_P_CANFD)) {
+		if (unlikely(skb->len != CANFD_MTU ||
+			     cfd->len > CANFD_MAX_DLEN))
+			goto inval_skb;
+	} else
+		goto inval_skb;
 
 	return 0;
+
+inval_skb:
+	kfree_skb(skb);
+	dev->stats.tx_dropped++;
+	return 1;
 }
 
+/* get data length from can_dlc with sanitized can_dlc */
+u8 can_dlc2len(u8 can_dlc);
+
+/* map the sanitized data length to an appropriate data length code */
+u8 can_len2dlc(u8 len);
+
 struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
 void free_candev(struct net_device *dev);
 
diff --git a/include/linux/can/error.h b/include/linux/can/error.h
index 63e855e..7b7148b 100644
--- a/include/linux/can/error.h
+++ b/include/linux/can/error.h
@@ -1,7 +1,7 @@
 /*
  * linux/can/error.h
  *
- * Definitions of the CAN error frame to be filtered and passed to the user.
+ * Definitions of the CAN error messages to be filtered and passed to the user.
  *
  * Author: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
  * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
@@ -12,7 +12,7 @@
 #ifndef CAN_ERROR_H
 #define CAN_ERROR_H
 
-#define CAN_ERR_DLC 8 /* dlc for error frames */
+#define CAN_ERR_DLC 8 /* dlc for error message frames */
 
 /* error class (mask) in can_id */
 #define CAN_ERR_TX_TIMEOUT   0x00000001U /* TX timeout (by netdevice driver) */
diff --git a/include/linux/can/raw.h b/include/linux/can/raw.h
index 781f3a3..a814062 100644
--- a/include/linux/can/raw.h
+++ b/include/linux/can/raw.h
@@ -23,7 +23,8 @@ enum {
 	CAN_RAW_FILTER = 1,	/* set 0 .. n can_filter(s)          */
 	CAN_RAW_ERR_FILTER,	/* set filter for error frames       */
 	CAN_RAW_LOOPBACK,	/* local loopback (default:on)       */
-	CAN_RAW_RECV_OWN_MSGS	/* receive my own msgs (default:off) */
+	CAN_RAW_RECV_OWN_MSGS,	/* receive my own msgs (default:off) */
+	CAN_RAW_FD_FRAMES,	/* allow CAN FD frames (default:off) */
 };
 
 #endif
diff --git a/include/linux/cd1400.h b/include/linux/cd1400.h
deleted file mode 100644
index 1dc3ab0..0000000
--- a/include/linux/cd1400.h
+++ /dev/null
@@ -1,292 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	cd1400.h  -- cd1400 UART hardware info.
- *
- *	Copyright (C) 1996-1998  Stallion Technologies
- *	Copyright (C) 1994-1996  Greg Ungerer.
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You 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	_CD1400_H
-#define	_CD1400_H
-/*****************************************************************************/
-
-/*
- *	Define the number of async ports per cd1400 uart chip.
- */
-#define	CD1400_PORTS		4
-
-/*
- *	Define the cd1400 uarts internal FIFO sizes.
- */
-#define	CD1400_TXFIFOSIZE	12
-#define	CD1400_RXFIFOSIZE	12
-
-/*
- *	Local RX FIFO thresh hold level. Also define the RTS thresh hold
- *	based on the RX thresh hold.
- */
-#define	FIFO_RXTHRESHOLD	6
-#define	FIFO_RTSTHRESHOLD	7
-
-/*****************************************************************************/
-
-/*
- *	Define the cd1400 register addresses. These are all the valid
- *	registers with the cd1400. Some are global, some virtual, some
- *	per port.
- */
-#define	GFRCR		0x40
-#define	CAR		0x68
-#define	GCR		0x4b
-#define	SVRR		0x67
-#define	RICR		0x44
-#define	TICR		0x45
-#define	MICR		0x46
-#define	RIR		0x6b
-#define	TIR		0x6a
-#define	MIR		0x69
-#define	PPR		0x7e
-
-#define	RIVR		0x43
-#define	TIVR		0x42
-#define	MIVR		0x41
-#define	TDR		0x63
-#define	RDSR		0x62
-#define	MISR		0x4c
-#define	EOSRR		0x60
-
-#define	LIVR		0x18
-#define	CCR		0x05
-#define	SRER		0x06
-#define	COR1		0x08
-#define	COR2		0x09
-#define	COR3		0x0a
-#define	COR4		0x1e
-#define	COR5		0x1f
-#define	CCSR		0x0b
-#define	RDCR		0x0e
-#define	SCHR1		0x1a
-#define	SCHR2		0x1b
-#define	SCHR3		0x1c
-#define	SCHR4		0x1d
-#define	SCRL		0x22
-#define	SCRH		0x23
-#define	LNC		0x24
-#define	MCOR1		0x15
-#define	MCOR2		0x16
-#define	RTPR		0x21
-#define	MSVR1		0x6c
-#define	MSVR2		0x6d
-#define	PSVR		0x6f
-#define	RBPR		0x78
-#define	RCOR		0x7c
-#define	TBPR		0x72
-#define	TCOR		0x76
-
-/*****************************************************************************/
-
-/*
- *	Define the set of baud rate clock divisors.
- */
-#define	CD1400_CLK0	8
-#define	CD1400_CLK1	32
-#define	CD1400_CLK2	128
-#define	CD1400_CLK3	512
-#define	CD1400_CLK4	2048
-
-#define	CD1400_NUMCLKS	5
-
-/*****************************************************************************/
-
-/*
- *	Define the clock pre-scalar value to be a 5 ms clock. This should be
- *	OK for now. It would probably be better to make it 10 ms, but we
- *	can't fit that divisor into 8 bits!
- */
-#define	PPR_SCALAR	244
-
-/*****************************************************************************/
-
-/*
- *	Define values used to set character size options.
- */
-#define	COR1_CHL5	0x00
-#define	COR1_CHL6	0x01
-#define	COR1_CHL7	0x02
-#define	COR1_CHL8	0x03
-
-/*
- *	Define values used to set the number of stop bits.
- */
-#define	COR1_STOP1	0x00
-#define	COR1_STOP15	0x04
-#define	COR1_STOP2	0x08
-
-/*
- *	Define values used to set the parity scheme in use.
- */
-#define	COR1_PARNONE	0x00
-#define	COR1_PARFORCE	0x20
-#define	COR1_PARENB	0x40
-#define	COR1_PARIGNORE	0x10
-
-#define	COR1_PARODD	0x80
-#define	COR1_PAREVEN	0x00
-
-#define	COR2_IXM	0x80
-#define	COR2_TXIBE	0x40
-#define	COR2_ETC	0x20
-#define	COR2_LLM	0x10
-#define	COR2_RLM	0x08
-#define	COR2_RTSAO	0x04
-#define	COR2_CTSAE	0x02
-
-#define	COR3_SCDRNG	0x80
-#define	COR3_SCD34	0x40
-#define	COR3_FCT	0x20
-#define	COR3_SCD12	0x10
-
-/*
- *	Define values used by COR4.
- */
-#define	COR4_BRKINT	0x08
-#define	COR4_IGNBRK	0x18
-
-/*****************************************************************************/
-
-/*
- *	Define the modem control register values.
- *	Note that the actual hardware is a little different to the conventional
- *	pin names on the cd1400.
- */
-#define	MSVR1_DTR	0x01
-#define	MSVR1_DSR	0x10
-#define	MSVR1_RI	0x20
-#define	MSVR1_CTS	0x40
-#define	MSVR1_DCD	0x80
-
-#define	MSVR2_RTS	0x02
-#define	MSVR2_DSR	0x10
-#define	MSVR2_RI	0x20
-#define	MSVR2_CTS	0x40
-#define	MSVR2_DCD	0x80
-
-#define	MCOR1_DCD	0x80
-#define	MCOR1_CTS	0x40
-#define	MCOR1_RI	0x20
-#define	MCOR1_DSR	0x10
-
-#define	MCOR2_DCD	0x80
-#define	MCOR2_CTS	0x40
-#define	MCOR2_RI	0x20
-#define	MCOR2_DSR	0x10
-
-/*****************************************************************************/
-
-/*
- *	Define the bits used with the service (interrupt) enable register.
- */
-#define	SRER_NNDT	0x01
-#define	SRER_TXEMPTY	0x02
-#define	SRER_TXDATA	0x04
-#define	SRER_RXDATA	0x10
-#define	SRER_MODEM	0x80
-
-/*****************************************************************************/
-
-/*
- *	Define operational commands for the command register.
- */
-#define	CCR_RESET	0x80
-#define	CCR_CORCHANGE	0x4e
-#define	CCR_SENDCH	0x20
-#define	CCR_CHANCTRL	0x10
-
-#define	CCR_TXENABLE	(CCR_CHANCTRL | 0x08)
-#define	CCR_TXDISABLE	(CCR_CHANCTRL | 0x04)
-#define	CCR_RXENABLE	(CCR_CHANCTRL | 0x02)
-#define	CCR_RXDISABLE	(CCR_CHANCTRL | 0x01)
-
-#define	CCR_SENDSCHR1	(CCR_SENDCH | 0x01)
-#define	CCR_SENDSCHR2	(CCR_SENDCH | 0x02)
-#define	CCR_SENDSCHR3	(CCR_SENDCH | 0x03)
-#define	CCR_SENDSCHR4	(CCR_SENDCH | 0x04)
-
-#define	CCR_RESETCHAN	(CCR_RESET | 0x00)
-#define	CCR_RESETFULL	(CCR_RESET | 0x01)
-#define	CCR_TXFLUSHFIFO	(CCR_RESET | 0x02)
-
-#define	CCR_MAXWAIT	10000
-
-/*****************************************************************************/
-
-/*
- *	Define the valid acknowledgement types (for hw ack cycle).
- */
-#define	ACK_TYPMASK	0x07
-#define	ACK_TYPTX	0x02
-#define	ACK_TYPMDM	0x01
-#define	ACK_TYPRXGOOD	0x03
-#define	ACK_TYPRXBAD	0x07
-
-#define	SVRR_RX		0x01
-#define	SVRR_TX		0x02
-#define	SVRR_MDM	0x04
-
-#define	ST_OVERRUN	0x01
-#define	ST_FRAMING	0x02
-#define	ST_PARITY	0x04
-#define	ST_BREAK	0x08
-#define	ST_SCHAR1	0x10
-#define	ST_SCHAR2	0x20
-#define	ST_SCHAR3	0x30
-#define	ST_SCHAR4	0x40
-#define	ST_RANGE	0x70
-#define	ST_SCHARMASK	0x70
-#define	ST_TIMEOUT	0x80
-
-#define	MISR_DCD	0x80
-#define	MISR_CTS	0x40
-#define	MISR_RI		0x20
-#define	MISR_DSR	0x10
-
-/*****************************************************************************/
-
-/*
- *	Defines for the CCSR status register.
- */
-#define	CCSR_RXENABLED	0x80
-#define	CCSR_RXFLOWON	0x40
-#define	CCSR_RXFLOWOFF	0x20
-#define	CCSR_TXENABLED	0x08
-#define	CCSR_TXFLOWON	0x04
-#define	CCSR_TXFLOWOFF	0x02
-
-/*****************************************************************************/
-
-/*
- *	Define the embedded commands.
- */
-#define	ETC_CMD		0x00
-#define	ETC_STARTBREAK	0x81
-#define	ETC_DELAY	0x82
-#define	ETC_STOPBREAK	0x83
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/cdk.h b/include/linux/cdk.h
deleted file mode 100644
index 80093a8..0000000
--- a/include/linux/cdk.h
+++ /dev/null
@@ -1,486 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	cdk.h  -- CDK interface definitions.
- *
- *	Copyright (C) 1996-1998  Stallion Technologies
- *	Copyright (C) 1994-1996  Greg Ungerer.
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You 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	_CDK_H
-#define	_CDK_H
-/*****************************************************************************/
-
-#pragma	pack(2)
-
-/*
- *	The following set of definitions is used to communicate with the
- *	shared memory interface of the Stallion intelligent multiport serial
- *	boards. The definitions in this file are taken directly from the
- *	document titled "Generic Stackable Interface, Downloader and
- *	Communications Development Kit".
- */
-
-/*
- *	Define the set of important shared memory addresses. These are
- *	required to initialize the board and get things started. All of these
- *	addresses are relative to the start of the shared memory.
- */
-#define	CDK_SIGADDR	0x200
-#define	CDK_FEATADDR	0x280
-#define	CDK_CDKADDR	0x300
-#define	CDK_RDYADDR	0x262
-
-#define	CDK_ALIVEMARKER	13
-
-/*
- *	On hardware power up the ROMs located on the EasyConnection 8/64 will
- *	fill out the following signature information into shared memory. This
- *	way the host system can quickly determine that the board is present
- *	and is operational.
- */
-typedef struct cdkecpsig {
-	unsigned long	magic;
-	unsigned short	romver;
-	unsigned short	cputype;
-	unsigned char	panelid[8];
-} cdkecpsig_t;
-
-#define	ECP_MAGIC	0x21504345
-
-/*
- *	On hardware power up the ROMs located on the ONboard, Stallion and
- *	Brumbys will fill out the following signature information into shared
- *	memory. This way the host system can quickly determine that the board
- *	is present and is operational.
- */
-typedef struct cdkonbsig {
-	unsigned short	magic0;
-	unsigned short	magic1;
-	unsigned short	magic2;
-	unsigned short	magic3;
-	unsigned short	romver;
-	unsigned short	memoff;
-	unsigned short	memseg;
-	unsigned short	amask0;
-	unsigned short	pic;
-	unsigned short	status;
-	unsigned short	btype;
-	unsigned short	clkticks;
-	unsigned short	clkspeed;
-	unsigned short	amask1;
-	unsigned short	amask2;
-} cdkonbsig_t;
-
-#define	ONB_MAGIC0	0xf2a7
-#define	ONB_MAGIC1	0xa149
-#define	ONB_MAGIC2	0x6352
-#define	ONB_MAGIC3	0xf121
-
-/*
- *	Define the feature area structure. The feature area is the set of
- *	startup parameters used by the slave image when it starts executing.
- *	They allow for the specification of buffer sizes, debug trace, etc.
- */
-typedef struct cdkfeature {
-	unsigned long	debug;
-	unsigned long	banner;
-	unsigned long	etype;
-	unsigned long	nrdevs;
-	unsigned long	brdspec;
-	unsigned long	txrqsize;
-	unsigned long	rxrqsize;
-	unsigned long	flags;
-} cdkfeature_t;
-
-#define	ETYP_DDK	0
-#define	ETYP_CDK	1
-
-/*
- *	Define the CDK header structure. This is the info that the slave
- *	environment sets up after it has been downloaded and started. It
- *	essentially provides a memory map for the shared memory interface.
- */
-typedef struct cdkhdr {
-	unsigned short	command;
-	unsigned short	status;
-	unsigned short	port;
-	unsigned short	mode;
-	unsigned long	cmd_buf[14];
-	unsigned short	alive_cnt;
-	unsigned short	intrpt_mode;
-	unsigned char	intrpt_id[8];
-	unsigned char	ver_release;
-	unsigned char	ver_modification;
-	unsigned char	ver_fix;
-	unsigned char	deadman_restart;
-	unsigned short	deadman;
-	unsigned short	nrdevs;
-	unsigned long	memp;
-	unsigned long	hostp;
-	unsigned long	slavep;
-	unsigned char	hostreq;
-	unsigned char	slavereq;
-	unsigned char	cmd_reserved[30];
-} cdkhdr_t;
-
-#define	MODE_DDK	0
-#define	MODE_CDK	1
-
-#define	IMD_INTR	0x0
-#define	IMD_PPINTR	0x1
-#define	IMD_POLL	0xff
-
-/*
- *	Define the memory mapping structure. This structure is pointed to by
- *	the memp field in the stlcdkhdr struct. As many as these structures
- *	as required are laid out in shared memory to define how the rest of
- *	shared memory is divided up. There will be one for each port.
- */
-typedef struct cdkmem {
-	unsigned short	dtype;
-	unsigned long	offset;
-} cdkmem_t;
-
-#define	TYP_UNDEFINED	0x0
-#define	TYP_ASYNCTRL	0x1
-#define	TYP_ASYNC	0x20
-#define	TYP_PARALLEL	0x40
-#define	TYP_SYNCX21	0x60
-
-/*****************************************************************************/
-
-/*
- *	Following is a set of defines and structures used to actually deal
- *	with the serial ports on the board. Firstly is the set of commands
- *	that can be applied to ports.
- */
-#define	ASYCMD		(((unsigned long) 'a') << 8)
-
-#define	A_NULL		(ASYCMD | 0)
-#define	A_FLUSH		(ASYCMD | 1)
-#define	A_BREAK		(ASYCMD | 2)
-#define	A_GETPORT	(ASYCMD | 3)
-#define	A_SETPORT	(ASYCMD | 4)
-#define	A_SETPORTF	(ASYCMD | 5)
-#define	A_SETPORTFTX	(ASYCMD | 6)
-#define	A_SETPORTFRX	(ASYCMD | 7)
-#define	A_GETSIGNALS	(ASYCMD | 8)
-#define	A_SETSIGNALS	(ASYCMD | 9)
-#define	A_SETSIGNALSF	(ASYCMD | 10)
-#define	A_SETSIGNALSFTX	(ASYCMD | 11)
-#define	A_SETSIGNALSFRX	(ASYCMD | 12)
-#define	A_GETNOTIFY	(ASYCMD | 13)
-#define	A_SETNOTIFY	(ASYCMD | 14)
-#define	A_NOTIFY	(ASYCMD | 15)
-#define	A_PORTCTRL	(ASYCMD | 16)
-#define	A_GETSTATS	(ASYCMD | 17)
-#define	A_RQSTATE	(ASYCMD | 18)
-#define	A_FLOWSTATE	(ASYCMD | 19)
-#define	A_CLEARSTATS	(ASYCMD | 20)
-
-/*
- *	Define those arguments used for simple commands.
- */
-#define	FLUSHRX		0x1
-#define	FLUSHTX		0x2
-
-#define	BREAKON		-1
-#define	BREAKOFF	-2
-
-/*
- *	Define the port setting structure, and all those defines that go along
- *	with it. Basically this structure defines the characteristics of this
- *	port: baud rate, chars, parity, input/output char cooking etc.
- */
-typedef struct asyport {
-	unsigned long	baudout;
-	unsigned long	baudin;
-	unsigned long	iflag;
-	unsigned long	oflag;
-	unsigned long	lflag;
-	unsigned long	pflag;
-	unsigned long	flow;
-	unsigned long	spare1;
-	unsigned short	vtime;
-	unsigned short	vmin;
-	unsigned short	txlo;
-	unsigned short	txhi;
-	unsigned short	rxlo;
-	unsigned short	rxhi;
-	unsigned short	rxhog;
-	unsigned short	spare2;
-	unsigned char	csize;
-	unsigned char	stopbs;
-	unsigned char	parity;
-	unsigned char	stopin;
-	unsigned char	startin;
-	unsigned char	stopout;
-	unsigned char	startout;
-	unsigned char	parmark;
-	unsigned char	brkmark;
-	unsigned char	cc[11];
-} asyport_t;
-
-#define	PT_STOP1	0x0
-#define	PT_STOP15	0x1
-#define	PT_STOP2	0x2
-
-#define	PT_NOPARITY	0x0
-#define	PT_ODDPARITY	0x1
-#define	PT_EVENPARITY	0x2
-#define	PT_MARKPARITY	0x3
-#define	PT_SPACEPARITY	0x4
-
-#define	F_NONE		0x0
-#define	F_IXON		0x1
-#define	F_IXOFF		0x2
-#define	F_IXANY		0x4
-#define	F_IOXANY	0x8
-#define	F_RTSFLOW	0x10
-#define	F_CTSFLOW	0x20
-#define	F_DTRFLOW	0x40
-#define	F_DCDFLOW	0x80
-#define	F_DSROFLOW	0x100
-#define	F_DSRIFLOW	0x200
-
-#define	FI_NORX		0x1
-#define	FI_RAW		0x2
-#define	FI_ISTRIP	0x4
-#define	FI_UCLC		0x8
-#define	FI_INLCR	0x10
-#define	FI_ICRNL	0x20
-#define	FI_IGNCR	0x40
-#define	FI_IGNBREAK	0x80
-#define	FI_DSCRDBREAK	0x100
-#define	FI_1MARKBREAK	0x200
-#define	FI_2MARKBREAK	0x400
-#define	FI_XCHNGBREAK	0x800
-#define	FI_IGNRXERRS	0x1000
-#define	FI_DSCDRXERRS	0x2000
-#define	FI_1MARKRXERRS	0x4000
-#define	FI_2MARKRXERRS	0x8000
-#define	FI_XCHNGRXERRS	0x10000
-#define	FI_DSCRDNULL	0x20000
-
-#define	FO_OLCUC	0x1
-#define	FO_ONLCR	0x2
-#define	FO_OOCRNL	0x4
-#define	FO_ONOCR	0x8
-#define	FO_ONLRET	0x10
-#define	FO_ONL		0x20
-#define	FO_OBS		0x40
-#define	FO_OVT		0x80
-#define	FO_OFF		0x100
-#define	FO_OTAB1	0x200
-#define	FO_OTAB2	0x400
-#define	FO_OTAB3	0x800
-#define	FO_OCR1		0x1000
-#define	FO_OCR2		0x2000
-#define	FO_OCR3		0x4000
-#define	FO_OFILL	0x8000
-#define	FO_ODELL	0x10000
-
-#define	P_RTSLOCK	0x1
-#define	P_CTSLOCK	0x2
-#define	P_MAPRTS	0x4
-#define	P_MAPCTS	0x8
-#define	P_LOOPBACK	0x10
-#define	P_DTRFOLLOW	0x20
-#define	P_FAKEDCD	0x40
-
-#define	P_RXIMIN	0x10000
-#define	P_RXITIME	0x20000
-#define	P_RXTHOLD	0x40000
-
-/*
- *	Define a structure to communicate serial port signal and data state
- *	information.
- */
-typedef struct asysigs {
-	unsigned long	data;
-	unsigned long	signal;
-	unsigned long	sigvalue;
-} asysigs_t;
-
-#define	DT_TXBUSY	0x1
-#define	DT_TXEMPTY	0x2
-#define	DT_TXLOW	0x4
-#define	DT_TXHIGH	0x8
-#define	DT_TXFULL	0x10
-#define	DT_TXHOG	0x20
-#define	DT_TXFLOWED	0x40
-#define	DT_TXBREAK	0x80
-
-#define	DT_RXBUSY	0x100
-#define	DT_RXEMPTY	0x200
-#define	DT_RXLOW	0x400
-#define	DT_RXHIGH	0x800
-#define	DT_RXFULL	0x1000
-#define	DT_RXHOG	0x2000
-#define	DT_RXFLOWED	0x4000
-#define	DT_RXBREAK	0x8000
-
-#define	SG_DTR		0x1
-#define	SG_DCD		0x2
-#define	SG_RTS		0x4
-#define	SG_CTS		0x8
-#define	SG_DSR		0x10
-#define	SG_RI		0x20
-
-/*
- *	Define the notification setting structure. This is used to tell the
- *	port what events we want to be informed about. Fields here use the
- *	same defines as for the asysigs structure above.
- */
-typedef struct asynotify {
-	unsigned long	ctrl;
-	unsigned long	data;
-	unsigned long	signal;
-	unsigned long	sigvalue;
-} asynotify_t;
-
-/*
- *	Define the port control structure. It is used to do fine grain
- *	control operations on the port.
- */
-typedef struct {
-	unsigned long	rxctrl;
-	unsigned long	txctrl;
-	char		rximdch;
-	char		tximdch;
-	char		spare1;
-	char		spare2;
-} asyctrl_t;
-
-#define	CT_ENABLE	0x1
-#define	CT_DISABLE	0x2
-#define	CT_STOP		0x4
-#define	CT_START	0x8
-#define	CT_STARTFLOW	0x10
-#define	CT_STOPFLOW	0x20
-#define	CT_SENDCHR	0x40
-
-/*
- *	Define the stats structure kept for each port. This is a useful set
- *	of data collected for each port on the slave. The A_GETSTATS command
- *	is used to retrieve this data from the slave.
- */
-typedef struct asystats {
-	unsigned long	opens;
-	unsigned long	txchars;
-	unsigned long	rxchars;
-	unsigned long	txringq;
-	unsigned long	rxringq;
-	unsigned long	txmsgs;
-	unsigned long	rxmsgs;
-	unsigned long	txflushes;
-	unsigned long	rxflushes;
-	unsigned long	overruns;
-	unsigned long	framing;
-	unsigned long	parity;
-	unsigned long	ringover;
-	unsigned long	lost;
-	unsigned long	rxstart;
-	unsigned long	rxstop;
-	unsigned long	txstart;
-	unsigned long	txstop;
-	unsigned long	dcdcnt;
-	unsigned long	dtrcnt;
-	unsigned long	ctscnt;
-	unsigned long	rtscnt;
-	unsigned long	dsrcnt;
-	unsigned long	ricnt;
-	unsigned long	txbreaks;
-	unsigned long	rxbreaks;
-	unsigned long	signals;
-	unsigned long	state;
-	unsigned long	hwid;
-} asystats_t;
-
-/*****************************************************************************/
-
-/*
- *	All command and control communication with a device on the slave is
- *	via a control block in shared memory. Each device has its own control
- *	block, defined by the following structure. The control block allows
- *	the host to open, close and control the device on the slave.
- */
-typedef struct cdkctrl {
-	unsigned char	open;
-	unsigned char	close;
-	unsigned long	openarg;
-	unsigned long	closearg;
-	unsigned long	cmd;
-	unsigned long	status;
-	unsigned long	args[32];
-} cdkctrl_t;
-
-/*
- *	Each device on the slave passes data to and from the host via a ring
- *	queue in shared memory. Define a ring queue structure to hold the
- *	vital information about each ring queue. Two ring queues will be
- *	allocated for each port, one for receive data and one for transmit
- *	data.
- */
-typedef struct cdkasyrq {
-	unsigned long	offset;
-	unsigned short	size;
-	unsigned short	head;
-	unsigned short	tail;
-} cdkasyrq_t;
-
-/*
- *	Each asynchronous port is defined in shared memory by the following
- *	structure. It contains a control block to command a device, and also
- *	the necessary data channel information as well.
- */
-typedef struct cdkasy {
-	cdkctrl_t	ctrl;
-	unsigned short	notify;
-	asynotify_t	changed;
-	unsigned short	receive;
-	cdkasyrq_t	rxq;
-	unsigned short	transmit;
-	cdkasyrq_t	txq;
-} cdkasy_t;
-
-#pragma	pack()
-
-/*****************************************************************************/
-
-/*
- *	Define the set of ioctls used by the driver to do special things
- *	to the board. These include interrupting it, and initializing
- *	the driver after board startup and shutdown.
- */
-#include <linux/ioctl.h>
-
-#define	STL_BINTR	_IO('s',20)
-#define	STL_BSTART	_IO('s',21)
-#define	STL_BSTOP	_IO('s',22)
-#define	STL_BRESET	_IO('s',23)
-
-/*
- *	Define a set of ioctl extensions, used to get at special stuff.
- */
-#define	STL_GETPFLAG	_IO('s',80)
-#define	STL_SETPFLAG	_IO('s',81)
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h
index e71d683..98ec36a 100644
--- a/include/linux/ceph/libceph.h
+++ b/include/linux/ceph/libceph.h
@@ -132,7 +132,7 @@ struct ceph_client {
 	u32 supported_features;
 	u32 required_features;
 
-	struct ceph_messenger *msgr;   /* messenger instance */
+	struct ceph_messenger msgr;   /* messenger instance */
 	struct ceph_mon_client monc;
 	struct ceph_osd_client osdc;
 
diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h
index 2521a95..a334dbd 100644
--- a/include/linux/ceph/messenger.h
+++ b/include/linux/ceph/messenger.h
@@ -31,9 +31,6 @@ struct ceph_connection_operations {
 	int (*verify_authorizer_reply) (struct ceph_connection *con, int len);
 	int (*invalidate_authorizer)(struct ceph_connection *con);
 
-	/* protocol version mismatch */
-	void (*bad_proto) (struct ceph_connection *con);
-
 	/* there was some error on the socket (disconnect, whatever) */
 	void (*fault) (struct ceph_connection *con);
 
@@ -80,7 +77,10 @@ struct ceph_msg {
 	unsigned nr_pages;              /* size of page array */
 	unsigned page_alignment;        /* io offset in first page */
 	struct ceph_pagelist *pagelist; /* instead of pages */
+
+	struct ceph_connection *con;
 	struct list_head list_head;
+
 	struct kref kref;
 	struct bio  *bio;		/* instead of pages/pagelist */
 	struct bio  *bio_iter;		/* bio iterator */
@@ -106,21 +106,25 @@ struct ceph_msg_pos {
 #define MAX_DELAY_INTERVAL	(5 * 60 * HZ)
 
 /*
- * ceph_connection state bit flags
+ * ceph_connection flag bits
  */
+
 #define LOSSYTX         0  /* we can close channel or drop messages on errors */
-#define CONNECTING	1
-#define NEGOTIATING	2
 #define KEEPALIVE_PENDING      3
 #define WRITE_PENDING	4  /* we have data ready to send */
+#define SOCK_CLOSED	11 /* socket state changed to closed */
+#define BACKOFF         15
+
+/*
+ * ceph_connection states
+ */
+#define CONNECTING	1
+#define NEGOTIATING	2
 #define STANDBY		8  /* no outgoing messages, socket closed.  we keep
 			    * the ceph_connection around to maintain shared
 			    * state with the peer. */
 #define CLOSED		10 /* we've closed the connection */
-#define SOCK_CLOSED	11 /* socket state changed to closed */
 #define OPENING         13 /* open connection w/ (possibly new) peer */
-#define DEAD            14 /* dead, about to kfree */
-#define BACKOFF         15
 
 /*
  * A single connection with another host.
@@ -136,13 +140,18 @@ struct ceph_connection {
 	const struct ceph_connection_operations *ops;
 
 	struct ceph_messenger *msgr;
+
+	atomic_t sock_state;
 	struct socket *sock;
-	unsigned long state;	/* connection state (see flags above) */
+	struct ceph_entity_addr peer_addr; /* peer address */
+	struct ceph_entity_addr peer_addr_for_me;
+
+	unsigned long flags;
+	unsigned long state;
 	const char *error_msg;  /* error message, if any */
 
-	struct ceph_entity_addr peer_addr; /* peer address */
 	struct ceph_entity_name peer_name; /* peer name */
-	struct ceph_entity_addr peer_addr_for_me;
+
 	unsigned peer_features;
 	u32 connect_seq;      /* identify the most recent connection
 				 attempt for this connection, client */
@@ -215,21 +224,25 @@ extern int ceph_msgr_init(void);
 extern void ceph_msgr_exit(void);
 extern void ceph_msgr_flush(void);
 
-extern struct ceph_messenger *ceph_messenger_create(
-	struct ceph_entity_addr *myaddr,
-	u32 features, u32 required);
-extern void ceph_messenger_destroy(struct ceph_messenger *);
+extern void ceph_messenger_init(struct ceph_messenger *msgr,
+			struct ceph_entity_addr *myaddr,
+			u32 supported_features,
+			u32 required_features,
+			bool nocrc);
 
-extern void ceph_con_init(struct ceph_messenger *msgr,
-			  struct ceph_connection *con);
+extern void ceph_con_init(struct ceph_connection *con, void *private,
+			const struct ceph_connection_operations *ops,
+			struct ceph_messenger *msgr, __u8 entity_type,
+			__u64 entity_num);
 extern void ceph_con_open(struct ceph_connection *con,
 			  struct ceph_entity_addr *addr);
 extern bool ceph_con_opened(struct ceph_connection *con);
 extern void ceph_con_close(struct ceph_connection *con);
 extern void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg);
-extern void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg);
-extern void ceph_con_revoke_message(struct ceph_connection *con,
-				  struct ceph_msg *msg);
+
+extern void ceph_msg_revoke(struct ceph_msg *msg);
+extern void ceph_msg_revoke_incoming(struct ceph_msg *msg);
+
 extern void ceph_con_keepalive(struct ceph_connection *con);
 extern struct ceph_connection *ceph_con_get(struct ceph_connection *con);
 extern void ceph_con_put(struct ceph_connection *con);
diff --git a/include/linux/ceph/mon_client.h b/include/linux/ceph/mon_client.h
index 545f859..2113e38 100644
--- a/include/linux/ceph/mon_client.h
+++ b/include/linux/ceph/mon_client.h
@@ -70,7 +70,7 @@ struct ceph_mon_client {
 	bool hunting;
 	int cur_mon;                       /* last monitor i contacted */
 	unsigned long sub_sent, sub_renew_after;
-	struct ceph_connection *con;
+	struct ceph_connection con;
 	bool have_fsid;
 
 	/* pending generic requests */
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index d3f5fba..c90eaa8 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -500,21 +500,8 @@ struct cgroup_subsys {
 	const char *name;
 
 	/*
-	 * Protects sibling/children links of cgroups in this
-	 * hierarchy, plus protects which hierarchy (or none) the
-	 * subsystem is a part of (i.e. root/sibling).  To avoid
-	 * potential deadlocks, the following operations should not be
-	 * undertaken while holding any hierarchy_mutex:
-	 *
-	 * - allocating memory
-	 * - initiating hotplug events
-	 */
-	struct mutex hierarchy_mutex;
-	struct lock_class_key subsys_key;
-
-	/*
 	 * Link to parent, and list entry in parent's children.
-	 * Protected by this->hierarchy_mutex and cgroup_lock()
+	 * Protected by cgroup_lock()
 	 */
 	struct cgroupfs_root *root;
 	struct list_head sibling;
@@ -602,7 +589,7 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
  * the lifetime of cgroup_subsys_state is subsys's matter.
  *
  * Looking up and scanning function should be called under rcu_read_lock().
- * Taking cgroup_mutex()/hierarchy_mutex() is not necessary for following calls.
+ * Taking cgroup_mutex is not necessary for following calls.
  * But the css returned by this routine can be "not populated yet" or "being
  * destroyed". The caller should check css and cgroup's status.
  */
diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h
index 0bd390c..895923a 100644
--- a/include/linux/cgroup_subsys.h
+++ b/include/linux/cgroup_subsys.h
@@ -72,3 +72,9 @@ SUBSYS(net_prio)
 #endif
 
 /* */
+
+#ifdef CONFIG_CGROUP_HUGETLB_RES_CTLR
+SUBSYS(hugetlb)
+#endif
+
+/* */
diff --git a/include/linux/clk.h b/include/linux/clk.h
index ad5c43e..f7bd858 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -84,6 +84,43 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
 #endif
 
 /**
+ * clk_prepare - prepare a clock source
+ * @clk: clock source
+ *
+ * This prepares the clock source for use.
+ *
+ * Must not be called from within atomic context.
+ */
+#ifdef CONFIG_HAVE_CLK_PREPARE
+int clk_prepare(struct clk *clk);
+#else
+static inline int clk_prepare(struct clk *clk)
+{
+	might_sleep();
+	return 0;
+}
+#endif
+
+/**
+ * clk_unprepare - undo preparation of a clock source
+ * @clk: clock source
+ *
+ * This undoes a previously prepared clock.  The caller must balance
+ * the number of prepare and unprepare calls.
+ *
+ * Must not be called from within atomic context.
+ */
+#ifdef CONFIG_HAVE_CLK_PREPARE
+void clk_unprepare(struct clk *clk);
+#else
+static inline void clk_unprepare(struct clk *clk)
+{
+	might_sleep();
+}
+#endif
+
+#ifdef CONFIG_HAVE_CLK
+/**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
  * @id: clock comsumer ID
@@ -121,24 +158,6 @@ struct clk *clk_get(struct device *dev, const char *id);
 struct clk *devm_clk_get(struct device *dev, const char *id);
 
 /**
- * clk_prepare - prepare a clock source
- * @clk: clock source
- *
- * This prepares the clock source for use.
- *
- * Must not be called from within atomic context.
- */
-#ifdef CONFIG_HAVE_CLK_PREPARE
-int clk_prepare(struct clk *clk);
-#else
-static inline int clk_prepare(struct clk *clk)
-{
-	might_sleep();
-	return 0;
-}
-#endif
-
-/**
  * clk_enable - inform the system when the clock source should be running.
  * @clk: clock source
  *
@@ -166,47 +185,6 @@ int clk_enable(struct clk *clk);
  */
 void clk_disable(struct clk *clk);
 
-
-/**
- * clk_unprepare - undo preparation of a clock source
- * @clk: clock source
- *
- * This undoes a previously prepared clock.  The caller must balance
- * the number of prepare and unprepare calls.
- *
- * Must not be called from within atomic context.
- */
-#ifdef CONFIG_HAVE_CLK_PREPARE
-void clk_unprepare(struct clk *clk);
-#else
-static inline void clk_unprepare(struct clk *clk)
-{
-	might_sleep();
-}
-#endif
-
-/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
-static inline int clk_prepare_enable(struct clk *clk)
-{
-	int ret;
-
-	ret = clk_prepare(clk);
-	if (ret)
-		return ret;
-	ret = clk_enable(clk);
-	if (ret)
-		clk_unprepare(clk);
-
-	return ret;
-}
-
-/* clk_disable_unprepare helps cases using clk_disable in non-atomic context. */
-static inline void clk_disable_unprepare(struct clk *clk)
-{
-	clk_disable(clk);
-	clk_unprepare(clk);
-}
-
 /**
  * clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
  *		  This is only valid once the clock source has been enabled.
@@ -297,6 +275,78 @@ struct clk *clk_get_parent(struct clk *clk);
  */
 struct clk *clk_get_sys(const char *dev_id, const char *con_id);
 
+#else /* !CONFIG_HAVE_CLK */
+
+static inline struct clk *clk_get(struct device *dev, const char *id)
+{
+	return NULL;
+}
+
+static inline struct clk *devm_clk_get(struct device *dev, const char *id)
+{
+	return NULL;
+}
+
+static inline void clk_put(struct clk *clk) {}
+
+static inline void devm_clk_put(struct device *dev, struct clk *clk) {}
+
+static inline int clk_enable(struct clk *clk)
+{
+	return 0;
+}
+
+static inline void clk_disable(struct clk *clk) {}
+
+static inline unsigned long clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+
+static inline int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	return 0;
+}
+
+static inline long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	return 0;
+}
+
+static inline int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return 0;
+}
+
+static inline struct clk *clk_get_parent(struct clk *clk)
+{
+	return NULL;
+}
+
+#endif
+
+/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
+static inline int clk_prepare_enable(struct clk *clk)
+{
+	int ret;
+
+	ret = clk_prepare(clk);
+	if (ret)
+		return ret;
+	ret = clk_enable(clk);
+	if (ret)
+		clk_unprepare(clk);
+
+	return ret;
+}
+
+/* clk_disable_unprepare helps cases using clk_disable in non-atomic context. */
+static inline void clk_disable_unprepare(struct clk *clk)
+{
+	clk_disable(clk);
+	clk_unprepare(clk);
+}
+
 /**
  * clk_add_alias - add a new clock alias
  * @alias: name for clock alias
diff --git a/include/linux/compaction.h b/include/linux/compaction.h
index 51a90b7..bec4d67 100644
--- a/include/linux/compaction.h
+++ b/include/linux/compaction.h
@@ -1,6 +1,8 @@
 #ifndef _LINUX_COMPACTION_H
 #define _LINUX_COMPACTION_H
 
+#include <linux/node.h>
+
 /* Return values for compact_zone() and try_to_compact_pages() */
 /* compaction didn't start as it was not possible or direct reclaim was more suitable */
 #define COMPACT_SKIPPED		0
@@ -11,6 +13,23 @@
 /* The full zone was compacted */
 #define COMPACT_COMPLETE	3
 
+/*
+ * compaction supports three modes
+ *
+ * COMPACT_ASYNC_MOVABLE uses asynchronous migration and only scans
+ *    MIGRATE_MOVABLE pageblocks as migration sources and targets.
+ * COMPACT_ASYNC_UNMOVABLE uses asynchronous migration and only scans
+ *    MIGRATE_MOVABLE pageblocks as migration sources.
+ *    MIGRATE_UNMOVABLE pageblocks are scanned as potential migration
+ *    targets and convers them to MIGRATE_MOVABLE if possible
+ * COMPACT_SYNC uses synchronous migration and scans all pageblocks
+ */
+enum compact_mode {
+	COMPACT_ASYNC_MOVABLE,
+	COMPACT_ASYNC_UNMOVABLE,
+	COMPACT_SYNC,
+};
+
 #ifdef CONFIG_COMPACTION
 extern int sysctl_compact_memory;
 extern int sysctl_compaction_handler(struct ctl_table *table, int write,
@@ -58,7 +77,7 @@ static inline bool compaction_deferred(struct zone *zone, int order)
 	if (++zone->compact_considered > defer_limit)
 		zone->compact_considered = defer_limit;
 
-	return zone->compact_considered < (1UL << zone->compact_defer_shift);
+	return zone->compact_considered < defer_limit;
 }
 
 #else
@@ -85,7 +104,7 @@ static inline void defer_compaction(struct zone *zone, int order)
 
 static inline bool compaction_deferred(struct zone *zone, int order)
 {
-	return 1;
+	return true;
 }
 
 #endif /* CONFIG_COMPACTION */
diff --git a/include/linux/comstats.h b/include/linux/comstats.h
deleted file mode 100644
index 3f5ea8e..0000000
--- a/include/linux/comstats.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	comstats.h  -- Serial Port Stats.
- *
- *	Copyright (C) 1996-1998  Stallion Technologies
- *	Copyright (C) 1994-1996  Greg Ungerer.
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You 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	_COMSTATS_H
-#define	_COMSTATS_H
-/*****************************************************************************/
-
-/*
- *	Serial port stats structure. The structure itself is UART
- *	independent, but some fields may be UART/driver specific (for
- *	example state).
- */
-
-typedef struct {
-	unsigned long	brd;
-	unsigned long	panel;
-	unsigned long	port;
-	unsigned long	hwid;
-	unsigned long	type;
-	unsigned long	txtotal;
-	unsigned long	rxtotal;
-	unsigned long	txbuffered;
-	unsigned long	rxbuffered;
-	unsigned long	rxoverrun;
-	unsigned long	rxparity;
-	unsigned long	rxframing;
-	unsigned long	rxlost;
-	unsigned long	txbreaks;
-	unsigned long	rxbreaks;
-	unsigned long	txxon;
-	unsigned long	txxoff;
-	unsigned long	rxxon;
-	unsigned long	rxxoff;
-	unsigned long	txctson;
-	unsigned long	txctsoff;
-	unsigned long	rxrtson;
-	unsigned long	rxrtsoff;
-	unsigned long	modem;
-	unsigned long	state;
-	unsigned long	flags;
-	unsigned long	ttystate;
-	unsigned long	cflags;
-	unsigned long	iflags;
-	unsigned long	oflags;
-	unsigned long	lflags;
-	unsigned long	signals;
-} comstats_t;
-
-
-/*
- *	Board stats structure. Returns useful info about the board.
- */
-
-#define	COM_MAXPANELS	8
-
-typedef struct {
-	unsigned long	panel;
-	unsigned long	type;
-	unsigned long	hwid;
-	unsigned long	nrports;
-} companel_t;
-
-typedef struct {
-	unsigned long	brd;
-	unsigned long	type;
-	unsigned long	hwid;
-	unsigned long	state;
-	unsigned long	ioaddr;
-	unsigned long	ioaddr2;
-	unsigned long	memaddr;
-	unsigned long	irq;
-	unsigned long	nrpanels;
-	unsigned long	nrports;
-	companel_t	panels[COM_MAXPANELS];
-} combrd_t;
-
-
-/*
- *	Define the ioctl operations for stats stuff.
- */
-#include <linux/ioctl.h>
-
-#define	COM_GETPORTSTATS	_IO('c',30)
-#define	COM_CLRPORTSTATS	_IO('c',31)
-#define	COM_GETBRDSTATS		_IO('c',32)
-
-
-/*
- *	Define the set of ioctls that give user level access to the
- *	private port, panel and board structures. The argument required
- *	will be driver dependent!  
- */
-#define	COM_READPORT		_IO('c',40)
-#define	COM_READBOARD		_IO('c',41)
-#define	COM_READPANEL		_IO('c',42)
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 6c26a3d..322da35 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -57,6 +57,7 @@ struct cpuidle_state {
 
 /* Idle State Flags */
 #define CPUIDLE_FLAG_TIME_VALID	(0x01) /* is residency time measurable? */
+#define CPUIDLE_FLAG_COUPLED	(0x02) /* state applies to multiple cpus */
 
 #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
 
@@ -100,6 +101,12 @@ struct cpuidle_device {
 	struct list_head 	device_list;
 	struct kobject		kobj;
 	struct completion	kobj_unregister;
+
+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
+	int			safe_state_index;
+	cpumask_t		coupled_cpus;
+	struct cpuidle_coupled	*coupled;
+#endif
 };
 
 DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
@@ -136,7 +143,9 @@ struct cpuidle_driver {
 extern void disable_cpuidle(void);
 extern int cpuidle_idle_call(void);
 extern int cpuidle_register_driver(struct cpuidle_driver *drv);
-struct cpuidle_driver *cpuidle_get_driver(void);
+extern struct cpuidle_driver *cpuidle_get_driver(void);
+extern struct cpuidle_driver *cpuidle_driver_ref(void);
+extern void cpuidle_driver_unref(void);
 extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
 extern int cpuidle_register_device(struct cpuidle_device *dev);
 extern void cpuidle_unregister_device(struct cpuidle_device *dev);
@@ -157,6 +166,8 @@ static inline int cpuidle_idle_call(void) { return -ENODEV; }
 static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
 {return -ENODEV; }
 static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
+static inline struct cpuidle_driver *cpuidle_driver_ref(void) {return NULL; }
+static inline void cpuidle_driver_unref(void) {}
 static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
 static inline int cpuidle_register_device(struct cpuidle_device *dev)
 {return -ENODEV; }
@@ -176,6 +187,10 @@ static inline int cpuidle_play_dead(void) {return -ENODEV; }
 
 #endif
 
+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
+void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a);
+#endif
+
 /******************************
  * CPUIDLE GOVERNOR INTERFACE *
  ******************************/
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index a2c819d..170c5af 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -271,6 +271,7 @@ static inline void cpumask_clear_cpu(int cpu, struct cpumask *dstp)
  * cpumask_test_cpu - test for a cpu in a cpumask
  * @cpu: cpu number (< nr_cpu_ids)
  * @cpumask: the cpumask pointer
+ * Returns 1 if 'cpu' is set in 'cpumask', else returns 0
  *
  * No static inline type checking - see Subtlety (1) above.
  */
@@ -281,6 +282,7 @@ static inline void cpumask_clear_cpu(int cpu, struct cpumask *dstp)
  * cpumask_test_and_set_cpu - atomically test and set a cpu in a cpumask
  * @cpu: cpu number (< nr_cpu_ids)
  * @cpumask: the cpumask pointer
+ * Returns 1 if 'cpu' is set in old bitmap of 'cpumask', else returns 0
  *
  * test_and_set_bit wrapper for cpumasks.
  */
@@ -293,6 +295,7 @@ static inline int cpumask_test_and_set_cpu(int cpu, struct cpumask *cpumask)
  * cpumask_test_and_clear_cpu - atomically test and clear a cpu in a cpumask
  * @cpu: cpu number (< nr_cpu_ids)
  * @cpumask: the cpumask pointer
+ * Returns 1 if 'cpu' is set in old bitmap of 'cpumask', else returns 0
  *
  * test_and_clear_bit wrapper for cpumasks.
  */
@@ -324,6 +327,7 @@ static inline void cpumask_clear(struct cpumask *dstp)
  * @dstp: the cpumask result
  * @src1p: the first input
  * @src2p: the second input
+ * If *dstp is empty, returns 0, else returns 1
  */
 static inline int cpumask_and(struct cpumask *dstp,
 			       const struct cpumask *src1p,
@@ -365,6 +369,7 @@ static inline void cpumask_xor(struct cpumask *dstp,
  * @dstp: the cpumask result
  * @src1p: the first input
  * @src2p: the second input
+ * If *dstp is empty, returns 0, else returns 1
  */
 static inline int cpumask_andnot(struct cpumask *dstp,
 				  const struct cpumask *src1p,
@@ -414,6 +419,7 @@ static inline bool cpumask_intersects(const struct cpumask *src1p,
  * cpumask_subset - (*src1p & ~*src2p) == 0
  * @src1p: the first input
  * @src2p: the second input
+ * Returns 1 if *src1p is a subset of *src2p, else returns 0
  */
 static inline int cpumask_subset(const struct cpumask *src1p,
 				 const struct cpumask *src2p)
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index 668f66b..119be3a 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -20,7 +20,7 @@ extern int number_of_cpusets;	/* How many cpusets are defined in system? */
 
 extern int cpuset_init(void);
 extern void cpuset_init_smp(void);
-extern void cpuset_update_active_cpus(void);
+extern void cpuset_update_active_cpus(bool cpu_online);
 extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask);
 extern void cpuset_cpus_allowed_fallback(struct task_struct *p);
 extern nodemask_t cpuset_mems_allowed(struct task_struct *p);
@@ -89,25 +89,26 @@ extern void rebuild_sched_domains(void);
 extern void cpuset_print_task_mems_allowed(struct task_struct *p);
 
 /*
- * get_mems_allowed is required when making decisions involving mems_allowed
- * such as during page allocation. mems_allowed can be updated in parallel
- * and depending on the new value an operation can fail potentially causing
- * process failure. A retry loop with get_mems_allowed and put_mems_allowed
- * prevents these artificial failures.
+ * read_mems_allowed_begin is required when making decisions involving
+ * mems_allowed such as during page allocation. mems_allowed can be updated in
+ * parallel and depending on the new value an operation can fail potentially
+ * causing process failure. A retry loop with read_mems_allowed_begin and
+ * read_mems_allowed_retry prevents these artificial failures.
  */
-static inline unsigned int get_mems_allowed(void)
+static inline unsigned int read_mems_allowed_begin(void)
 {
 	return read_seqcount_begin(&current->mems_allowed_seq);
 }
 
 /*
- * If this returns false, the operation that took place after get_mems_allowed
- * may have failed. It is up to the caller to retry the operation if
+ * If this returns true, the operation that took place after
+ * read_mems_allowed_begin may have failed artificially due to a concurrent
+ * update of mems_allowed. It is up to the caller to retry the operation if
  * appropriate.
  */
-static inline bool put_mems_allowed(unsigned int seq)
+static inline bool read_mems_allowed_retry(unsigned int seq)
 {
-	return !read_seqcount_retry(&current->mems_allowed_seq, seq);
+	return read_seqcount_retry(&current->mems_allowed_seq, seq);
 }
 
 static inline void set_mems_allowed(nodemask_t nodemask)
@@ -124,7 +125,7 @@ static inline void set_mems_allowed(nodemask_t nodemask)
 static inline int cpuset_init(void) { return 0; }
 static inline void cpuset_init_smp(void) {}
 
-static inline void cpuset_update_active_cpus(void)
+static inline void cpuset_update_active_cpus(bool cpu_online)
 {
 	partition_sched_domains(1, NULL, NULL);
 }
@@ -223,14 +224,14 @@ static inline void set_mems_allowed(nodemask_t nodemask)
 {
 }
 
-static inline unsigned int get_mems_allowed(void)
+static inline unsigned int read_mems_allowed_begin(void)
 {
 	return 0;
 }
 
-static inline bool put_mems_allowed(unsigned int seq)
+static inline bool read_mems_allowed_retry(unsigned int seq)
 {
-	return true;
+	return false;
 }
 
 #endif /* !CONFIG_CPUSETS */
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 094789f..caa34e5 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -128,7 +128,7 @@ struct dentry {
 	 	struct rcu_head d_rcu;
 	} d_u;
 	struct list_head d_subdirs;	/* our children */
-	struct list_head d_alias;	/* inode alias list */
+	struct hlist_node d_alias;	/* inode alias list */
 };
 
 /*
@@ -144,7 +144,7 @@ enum dentry_d_lock_class
 };
 
 struct dentry_operations {
-	int (*d_revalidate)(struct dentry *, struct nameidata *);
+	int (*d_revalidate)(struct dentry *, unsigned int);
 	int (*d_hash)(const struct dentry *, const struct inode *,
 			struct qstr *);
 	int (*d_compare)(const struct dentry *, const struct inode *,
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 98f34b8..00292a0 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -188,8 +188,8 @@ struct dm_target {
 	sector_t begin;
 	sector_t len;
 
-	/* Always a power of 2 */
-	sector_t split_io;
+	/* If non-zero, maximum size of I/O submitted to a target. */
+	uint32_t max_io_len;
 
 	/*
 	 * A number of zero-length barrier requests that will be submitted
@@ -360,6 +360,11 @@ void dm_table_add_target_callbacks(struct dm_table *t, struct dm_target_callback
 int dm_table_complete(struct dm_table *t);
 
 /*
+ * Target may require that it is never sent I/O larger than len.
+ */
+int __must_check dm_set_target_max_io_len(struct dm_target *ti, sector_t len);
+
+/*
  * Table reference counting.
  */
 struct dm_table *dm_get_live_table(struct mapped_device *md);
diff --git a/include/linux/device.h b/include/linux/device.h
index 161d962..d0e4d99 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -36,6 +36,7 @@ struct subsys_private;
 struct bus_type;
 struct device_node;
 struct iommu_ops;
+struct iommu_group;
 
 struct bus_attribute {
 	struct attribute	attr;
@@ -687,6 +688,7 @@ struct device {
 	const struct attribute_group **groups;	/* optional groups */
 
 	void	(*release)(struct device *dev);
+	struct iommu_group	*iommu_group;
 };
 
 /* Get the wakeup routines, which depend on struct device */
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h
index 75fd557..3ece4ee 100644
--- a/include/linux/dm-ioctl.h
+++ b/include/linux/dm-ioctl.h
@@ -268,8 +268,8 @@ enum {
 
 #define DM_VERSION_MAJOR	4
 #define DM_VERSION_MINOR	22
-#define DM_VERSION_PATCHLEVEL	0
-#define DM_VERSION_EXTRA	"-ioctl (2011-10-19)"
+#define DM_VERSION_PATCHLEVEL	1
+#define DM_VERSION_EXTRA	"-ioctl (2012-06-01)"
 
 /* Status bits */
 #define DM_READONLY_FLAG	(1 << 0) /* In/Out */
diff --git a/include/linux/dma-attrs.h b/include/linux/dma-attrs.h
index 547ab56..f83f793 100644
--- a/include/linux/dma-attrs.h
+++ b/include/linux/dma-attrs.h
@@ -15,6 +15,8 @@ enum dma_attr {
 	DMA_ATTR_WEAK_ORDERING,
 	DMA_ATTR_WRITE_COMBINE,
 	DMA_ATTR_NON_CONSISTENT,
+	DMA_ATTR_NO_KERNEL_MAPPING,
+	DMA_ATTR_SKIP_CPU_SYNC,
 	DMA_ATTR_MAX,
 };
 
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index dfc099e..94af418 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -18,6 +18,9 @@ struct dma_map_ops {
 	int (*mmap)(struct device *, struct vm_area_struct *,
 			  void *, dma_addr_t, size_t, struct dma_attrs *attrs);
 
+	int (*get_sgtable)(struct device *dev, struct sg_table *sgt, void *,
+			   dma_addr_t, size_t, struct dma_attrs *attrs);
+
 	dma_addr_t (*map_page)(struct device *dev, struct page *page,
 			       unsigned long offset, size_t size,
 			       enum dma_data_direction dir,
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 56377df..9c02a45 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -338,6 +338,9 @@ enum dma_slave_buswidth {
  * @device_fc: Flow Controller Settings. Only valid for slave channels. Fill
  * with 'true' if peripheral should be flow controller. Direction will be
  * selected at Runtime.
+ * @slave_id: Slave requester id. Only valid for slave channels. The dma
+ * slave peripheral will have unique id as dma requester which need to be
+ * pass as slave config.
  *
  * This struct is passed in as configuration data to a DMA engine
  * in order to set up a certain channel for DMA transport at runtime.
@@ -365,6 +368,7 @@ struct dma_slave_config {
 	u32 src_maxburst;
 	u32 dst_maxburst;
 	bool device_fc;
+	unsigned int slave_id;
 };
 
 static inline const char *dma_chan_name(struct dma_chan *chan)
@@ -670,6 +674,12 @@ static inline int dmaengine_resume(struct dma_chan *chan)
 	return dmaengine_device_control(chan, DMA_RESUME, 0);
 }
 
+static inline enum dma_status dmaengine_tx_status(struct dma_chan *chan,
+	dma_cookie_t cookie, struct dma_tx_state *state)
+{
+	return chan->device->device_tx_status(chan, cookie, state);
+}
+
 static inline dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
 {
 	return desc->tx_submit(desc);
diff --git a/include/linux/edac.h b/include/linux/edac.h
index 91ba3ba..bab9f84 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
@@ -13,9 +13,11 @@
 #define _LINUX_EDAC_H_
 
 #include <linux/atomic.h>
+#include <linux/device.h>
 #include <linux/kobject.h>
 #include <linux/completion.h>
 #include <linux/workqueue.h>
+#include <linux/debugfs.h>
 
 struct device;
 
@@ -49,7 +51,19 @@ static inline void opstate_init(void)
 #define EDAC_MC_LABEL_LEN	31
 #define MC_PROC_NAME_MAX_LEN	7
 
-/* memory devices */
+/**
+ * enum dev_type - describe the type of memory DRAM chips used at the stick
+ * @DEV_UNKNOWN:	Can't be determined, or MC doesn't support detect it
+ * @DEV_X1:		1 bit for data
+ * @DEV_X2:		2 bits for data
+ * @DEV_X4:		4 bits for data
+ * @DEV_X8:		8 bits for data
+ * @DEV_X16:		16 bits for data
+ * @DEV_X32:		32 bits for data
+ * @DEV_X64:		64 bits for data
+ *
+ * Typical values are x4 and x8.
+ */
 enum dev_type {
 	DEV_UNKNOWN = 0,
 	DEV_X1,
@@ -167,18 +181,30 @@ enum mem_type {
 #define MEM_FLAG_DDR3		 BIT(MEM_DDR3)
 #define MEM_FLAG_RDDR3		 BIT(MEM_RDDR3)
 
-/* chipset Error Detection and Correction capabilities and mode */
+/**
+ * enum edac-type - Error Detection and Correction capabilities and mode
+ * @EDAC_UNKNOWN:	Unknown if ECC is available
+ * @EDAC_NONE:		Doesn't support ECC
+ * @EDAC_RESERVED:	Reserved ECC type
+ * @EDAC_PARITY:	Detects parity errors
+ * @EDAC_EC:		Error Checking - no correction
+ * @EDAC_SECDED:	Single bit error correction, Double detection
+ * @EDAC_S2ECD2ED:	Chipkill x2 devices - do these exist?
+ * @EDAC_S4ECD4ED:	Chipkill x4 devices
+ * @EDAC_S8ECD8ED:	Chipkill x8 devices
+ * @EDAC_S16ECD16ED:	Chipkill x16 devices
+ */
 enum edac_type {
-	EDAC_UNKNOWN = 0,	/* Unknown if ECC is available */
-	EDAC_NONE,		/* Doesn't support ECC */
-	EDAC_RESERVED,		/* Reserved ECC type */
-	EDAC_PARITY,		/* Detects parity errors */
-	EDAC_EC,		/* Error Checking - no correction */
-	EDAC_SECDED,		/* Single bit error correction, Double detection */
-	EDAC_S2ECD2ED,		/* Chipkill x2 devices - do these exist? */
-	EDAC_S4ECD4ED,		/* Chipkill x4 devices */
-	EDAC_S8ECD8ED,		/* Chipkill x8 devices */
-	EDAC_S16ECD16ED,	/* Chipkill x16 devices */
+	EDAC_UNKNOWN =	0,
+	EDAC_NONE,
+	EDAC_RESERVED,
+	EDAC_PARITY,
+	EDAC_EC,
+	EDAC_SECDED,
+	EDAC_S2ECD2ED,
+	EDAC_S4ECD4ED,
+	EDAC_S8ECD8ED,
+	EDAC_S16ECD16ED,
 };
 
 #define EDAC_FLAG_UNKNOWN	BIT(EDAC_UNKNOWN)
@@ -191,18 +217,30 @@ enum edac_type {
 #define EDAC_FLAG_S8ECD8ED	BIT(EDAC_S8ECD8ED)
 #define EDAC_FLAG_S16ECD16ED	BIT(EDAC_S16ECD16ED)
 
-/* scrubbing capabilities */
+/**
+ * enum scrub_type - scrubbing capabilities
+ * @SCRUB_UNKNOWN		Unknown if scrubber is available
+ * @SCRUB_NONE:			No scrubber
+ * @SCRUB_SW_PROG:		SW progressive (sequential) scrubbing
+ * @SCRUB_SW_SRC:		Software scrub only errors
+ * @SCRUB_SW_PROG_SRC:		Progressive software scrub from an error
+ * @SCRUB_SW_TUNABLE:		Software scrub frequency is tunable
+ * @SCRUB_HW_PROG:		HW progressive (sequential) scrubbing
+ * @SCRUB_HW_SRC:		Hardware scrub only errors
+ * @SCRUB_HW_PROG_SRC:		Progressive hardware scrub from an error
+ * SCRUB_HW_TUNABLE:		Hardware scrub frequency is tunable
+ */
 enum scrub_type {
-	SCRUB_UNKNOWN = 0,	/* Unknown if scrubber is available */
-	SCRUB_NONE,		/* No scrubber */
-	SCRUB_SW_PROG,		/* SW progressive (sequential) scrubbing */
-	SCRUB_SW_SRC,		/* Software scrub only errors */
-	SCRUB_SW_PROG_SRC,	/* Progressive software scrub from an error */
-	SCRUB_SW_TUNABLE,	/* Software scrub frequency is tunable */
-	SCRUB_HW_PROG,		/* HW progressive (sequential) scrubbing */
-	SCRUB_HW_SRC,		/* Hardware scrub only errors */
-	SCRUB_HW_PROG_SRC,	/* Progressive hardware scrub from an error */
-	SCRUB_HW_TUNABLE	/* Hardware scrub frequency is tunable */
+	SCRUB_UNKNOWN =	0,
+	SCRUB_NONE,
+	SCRUB_SW_PROG,
+	SCRUB_SW_SRC,
+	SCRUB_SW_PROG_SRC,
+	SCRUB_SW_TUNABLE,
+	SCRUB_HW_PROG,
+	SCRUB_HW_SRC,
+	SCRUB_HW_PROG_SRC,
+	SCRUB_HW_TUNABLE
 };
 
 #define SCRUB_FLAG_SW_PROG	BIT(SCRUB_SW_PROG)
@@ -374,23 +412,21 @@ struct edac_mc_layer {
 #define EDAC_MAX_LAYERS		3
 
 /**
- * EDAC_DIMM_PTR - Macro responsible to find a pointer inside a pointer array
+ * EDAC_DIMM_OFF - Macro responsible to get a pointer offset inside a pointer array
  *		   for the element given by [layer0,layer1,layer2] position
  *
  * @layers:	a struct edac_mc_layer array, describing how many elements
  *		were allocated for each layer
- * @var:	name of the var where we want to get the pointer
- *		(like mci->dimms)
  * @n_layers:	Number of layers at the @layers array
  * @layer0:	layer0 position
  * @layer1:	layer1 position. Unused if n_layers < 2
  * @layer2:	layer2 position. Unused if n_layers < 3
  *
- * For 1 layer, this macro returns &var[layer0]
+ * For 1 layer, this macro returns &var[layer0] - &var
  * For 2 layers, this macro is similar to allocate a bi-dimensional array
- *		and to return "&var[layer0][layer1]"
+ *		and to return "&var[layer0][layer1] - &var"
  * For 3 layers, this macro is similar to allocate a tri-dimensional array
- *		and to return "&var[layer0][layer1][layer2]"
+ *		and to return "&var[layer0][layer1][layer2] - &var"
  *
  * A loop could be used here to make it more generic, but, as we only have
  * 3 layers, this is a little faster.
@@ -398,23 +434,52 @@ struct edac_mc_layer {
  * a NULL is returned, causing an OOPS during the memory allocation routine,
  * with would point to the developer that he's doing something wrong.
  */
-#define EDAC_DIMM_PTR(layers, var, nlayers, layer0, layer1, layer2) ({	\
-	typeof(var) __p;						\
+#define EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2) ({		\
+	int __i;							\
 	if ((nlayers) == 1)						\
-		__p = &var[layer0];					\
+		__i = layer0;						\
 	else if ((nlayers) == 2)					\
-		__p = &var[(layer1) + ((layers[1]).size * (layer0))];	\
+		__i = (layer1) + ((layers[1]).size * (layer0));		\
 	else if ((nlayers) == 3)					\
-		__p = &var[(layer2) + ((layers[2]).size * ((layer1) +	\
-			    ((layers[1]).size * (layer0))))];		\
+		__i = (layer2) + ((layers[2]).size * ((layer1) +	\
+			    ((layers[1]).size * (layer0))));		\
 	else								\
+		__i = -EINVAL;						\
+	__i;								\
+})
+
+/**
+ * EDAC_DIMM_PTR - Macro responsible to get a pointer inside a pointer array
+ *		   for the element given by [layer0,layer1,layer2] position
+ *
+ * @layers:	a struct edac_mc_layer array, describing how many elements
+ *		were allocated for each layer
+ * @var:	name of the var where we want to get the pointer
+ *		(like mci->dimms)
+ * @n_layers:	Number of layers at the @layers array
+ * @layer0:	layer0 position
+ * @layer1:	layer1 position. Unused if n_layers < 2
+ * @layer2:	layer2 position. Unused if n_layers < 3
+ *
+ * For 1 layer, this macro returns &var[layer0]
+ * For 2 layers, this macro is similar to allocate a bi-dimensional array
+ *		and to return "&var[layer0][layer1]"
+ * For 3 layers, this macro is similar to allocate a tri-dimensional array
+ *		and to return "&var[layer0][layer1][layer2]"
+ */
+#define EDAC_DIMM_PTR(layers, var, nlayers, layer0, layer1, layer2) ({	\
+	typeof(*var) __p;						\
+	int ___i = EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2);	\
+	if (___i < 0)							\
 		__p = NULL;						\
+	else								\
+		__p = (var)[___i];					\
 	__p;								\
 })
 
-
-/* FIXME: add the proper per-location error counts */
 struct dimm_info {
+	struct device dev;
+
 	char label[EDAC_MC_LABEL_LEN + 1];	/* DIMM label on motherboard */
 
 	/* Memory location data */
@@ -456,6 +521,8 @@ struct rank_info {
 };
 
 struct csrow_info {
+	struct device dev;
+
 	/* Used only by edac_mc_find_csrow_by_page() */
 	unsigned long first_page;	/* first page number in csrow */
 	unsigned long last_page;	/* last page number in csrow */
@@ -469,44 +536,26 @@ struct csrow_info {
 
 	struct mem_ctl_info *mci;	/* the parent */
 
-	struct kobject kobj;	/* sysfs kobject for this csrow */
-
 	/* channel information for this csrow */
 	u32 nr_channels;
-	struct rank_info *channels;
+	struct rank_info **channels;
 };
 
-struct mcidev_sysfs_group {
-	const char *name;				/* group name */
-	const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
-};
-
-struct mcidev_sysfs_group_kobj {
-	struct list_head list;		/* list for all instances within a mc */
-
-	struct kobject kobj;		/* kobj for the group */
-
-	const struct mcidev_sysfs_group *grp;	/* group description table */
-	struct mem_ctl_info *mci;	/* the parent */
-};
-
-/* mcidev_sysfs_attribute structure
- *	used for driver sysfs attributes and in mem_ctl_info
- * 	sysfs top level entries
+/*
+ * struct errcount_attribute - used to store the several error counts
  */
-struct mcidev_sysfs_attribute {
-	/* It should use either attr or grp */
-	struct attribute attr;
-	const struct mcidev_sysfs_group *grp;	/* Points to a group of attributes */
-
-	/* Ops for show/store values at the attribute - not used on group */
-        ssize_t (*show)(struct mem_ctl_info *,char *);
-        ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
+struct errcount_attribute_data {
+	int n_layers;
+	int pos[EDAC_MAX_LAYERS];
+	int layer0, layer1, layer2;
 };
 
 /* MEMORY controller information structure
  */
 struct mem_ctl_info {
+	struct device			dev;
+	struct bus_type			bus;
+
 	struct list_head link;	/* for global list of mem_ctl_info structs */
 
 	struct module *owner;	/* Module owner of this control struct */
@@ -548,10 +597,18 @@ struct mem_ctl_info {
 	unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
 					   unsigned long page);
 	int mc_idx;
-	struct csrow_info *csrows;
+	struct csrow_info **csrows;
 	unsigned nr_csrows, num_cschannel;
 
-	/* Memory Controller hierarchy */
+	/*
+	 * Memory Controller hierarchy
+	 *
+	 * There are basically two types of memory controller: the ones that
+	 * sees memory sticks ("dimms"), and the ones that sees memory ranks.
+	 * All old memory controllers enumerate memories per rank, but most
+	 * of the recent drivers enumerate memories per DIMM, instead.
+	 * When the memory controller is per rank, mem_is_per_rank is true.
+	 */
 	unsigned n_layers;
 	struct edac_mc_layer *layers;
 	bool mem_is_per_rank;
@@ -560,14 +617,14 @@ struct mem_ctl_info {
 	 * DIMM info. Will eventually remove the entire csrows_info some day
 	 */
 	unsigned tot_dimms;
-	struct dimm_info *dimms;
+	struct dimm_info **dimms;
 
 	/*
 	 * FIXME - what about controllers on other busses? - IDs must be
 	 * unique.  dev pointer should be sufficiently unique, but
 	 * BUS:SLOT.FUNC numbers may not be unique.
 	 */
-	struct device *dev;
+	struct device *pdev;
 	const char *mod_name;
 	const char *mod_ver;
 	const char *ctl_name;
@@ -586,12 +643,6 @@ struct mem_ctl_info {
 
 	struct completion complete;
 
-	/* edac sysfs device control */
-	struct kobject edac_mci_kobj;
-
-	/* list for all grp instances within a mc */
-	struct list_head grp_kobj_list;
-
 	/* Additional top controller level attributes, but specified
 	 * by the low level driver.
 	 *
@@ -609,6 +660,13 @@ struct mem_ctl_info {
 
 	/* the internal state of this controller instance */
 	int op_state;
+
+#ifdef CONFIG_EDAC_DEBUG
+	struct dentry *debugfs;
+	u8 fake_inject_layer[EDAC_MAX_LAYERS];
+	u32 fake_inject_ue;
+	u16 fake_inject_count;
+#endif
 };
 
 #endif
diff --git a/include/linux/efi.h b/include/linux/efi.h
index ec45ccd..103adc6 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -503,8 +503,6 @@ extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size);
 extern int __init efi_uart_console_only (void);
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
 		struct resource *data_resource, struct resource *bss_resource);
-extern unsigned long efi_get_time(void);
-extern int efi_set_rtc_mmss(unsigned long nowtime);
 extern void efi_reserve_boot_services(void);
 extern struct efi_memory_map memmap;
 
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index e17fa71..297370a 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -137,6 +137,35 @@ struct ethtool_eeprom {
 };
 
 /**
+ * struct ethtool_eee - Energy Efficient Ethernet information
+ * @cmd: ETHTOOL_{G,S}EEE
+ * @supported: Mask of %SUPPORTED_* flags for the speed/duplex combinations
+ *	for which there is EEE support.
+ * @advertised: Mask of %ADVERTISED_* flags for the speed/duplex combinations
+ *	advertised as eee capable.
+ * @lp_advertised: Mask of %ADVERTISED_* flags for the speed/duplex
+ *	combinations advertised by the link partner as eee capable.
+ * @eee_active: Result of the eee auto negotiation.
+ * @eee_enabled: EEE configured mode (enabled/disabled).
+ * @tx_lpi_enabled: Whether the interface should assert its tx lpi, given
+ *	that eee was negotiated.
+ * @tx_lpi_timer: Time in microseconds the interface delays prior to asserting
+ *	its tx lpi (after reaching 'idle' state). Effective only when eee
+ *	was negotiated and tx_lpi_enabled was set.
+ */
+struct ethtool_eee {
+	__u32	cmd;
+	__u32	supported;
+	__u32	advertised;
+	__u32	lp_advertised;
+	__u32	eee_active;
+	__u32	eee_enabled;
+	__u32	tx_lpi_enabled;
+	__u32	tx_lpi_timer;
+	__u32	reserved[2];
+};
+
+/**
  * struct ethtool_modinfo - plugin module eeprom information
  * @cmd: %ETHTOOL_GMODULEINFO
  * @type: Standard the module information conforms to %ETH_MODULE_SFF_xxxx
@@ -945,6 +974,8 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings)
  * @get_module_info: Get the size and type of the eeprom contained within
  *	a plug-in module.
  * @get_module_eeprom: Get the eeprom information from the plug-in module
+ * @get_eee: Get Energy-Efficient (EEE) supported and status.
+ * @set_eee: Set EEE status (enable/disable) as well as LPI timers.
  *
  * All operations are optional (i.e. the function pointer may be set
  * to %NULL) and callers must take this into account.  Callers must
@@ -1011,6 +1042,8 @@ struct ethtool_ops {
 				   struct ethtool_modinfo *);
 	int     (*get_module_eeprom)(struct net_device *,
 				     struct ethtool_eeprom *, u8 *);
+	int	(*get_eee)(struct net_device *, struct ethtool_eee *);
+	int	(*set_eee)(struct net_device *, struct ethtool_eee *);
 
 
 };
@@ -1089,6 +1122,8 @@ struct ethtool_ops {
 #define ETHTOOL_GET_TS_INFO	0x00000041 /* Get time stamping and PHC info */
 #define ETHTOOL_GMODULEINFO	0x00000042 /* Get plug-in module information */
 #define ETHTOOL_GMODULEEEPROM	0x00000043 /* Get plug-in module eeprom */
+#define ETHTOOL_GEEE		0x00000044 /* Get EEE settings */
+#define ETHTOOL_SEEE		0x00000045 /* Set EEE settings */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET		ETHTOOL_GSET
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 7edcf10..d1f573d 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -321,7 +321,7 @@ struct fw_transaction {
 
 struct fw_address_handler {
 	u64 offset;
-	size_t length;
+	u64 length;
 	fw_address_callback_t address_callback;
 	void *callback_data;
 	struct list_head link;
diff --git a/include/linux/flex_proportions.h b/include/linux/flex_proportions.h
new file mode 100644
index 0000000..4ebc49f
--- /dev/null
+++ b/include/linux/flex_proportions.h
@@ -0,0 +1,101 @@
+/*
+ * Floating proportions with flexible aging period
+ *
+ *  Copyright (C) 2011, SUSE, Jan Kara <jack@suse.cz>
+ */
+
+#ifndef _LINUX_FLEX_PROPORTIONS_H
+#define _LINUX_FLEX_PROPORTIONS_H
+
+#include <linux/percpu_counter.h>
+#include <linux/spinlock.h>
+#include <linux/seqlock.h>
+
+/*
+ * When maximum proportion of some event type is specified, this is the
+ * precision with which we allow limitting. Note that this creates an upper
+ * bound on the number of events per period like
+ *   ULLONG_MAX >> FPROP_FRAC_SHIFT.
+ */
+#define FPROP_FRAC_SHIFT 10
+#define FPROP_FRAC_BASE (1UL << FPROP_FRAC_SHIFT)
+
+/*
+ * ---- Global proportion definitions ----
+ */
+struct fprop_global {
+	/* Number of events in the current period */
+	struct percpu_counter events;
+	/* Current period */
+	unsigned int period;
+	/* Synchronization with period transitions */
+	seqcount_t sequence;
+};
+
+int fprop_global_init(struct fprop_global *p);
+void fprop_global_destroy(struct fprop_global *p);
+bool fprop_new_period(struct fprop_global *p, int periods);
+
+/*
+ *  ---- SINGLE ----
+ */
+struct fprop_local_single {
+	/* the local events counter */
+	unsigned long events;
+	/* Period in which we last updated events */
+	unsigned int period;
+	raw_spinlock_t lock;	/* Protect period and numerator */
+};
+
+#define INIT_FPROP_LOCAL_SINGLE(name)			\
+{	.lock = __RAW_SPIN_LOCK_UNLOCKED(name.lock),	\
+}
+
+int fprop_local_init_single(struct fprop_local_single *pl);
+void fprop_local_destroy_single(struct fprop_local_single *pl);
+void __fprop_inc_single(struct fprop_global *p, struct fprop_local_single *pl);
+void fprop_fraction_single(struct fprop_global *p,
+	struct fprop_local_single *pl, unsigned long *numerator,
+	unsigned long *denominator);
+
+static inline
+void fprop_inc_single(struct fprop_global *p, struct fprop_local_single *pl)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	__fprop_inc_single(p, pl);
+	local_irq_restore(flags);
+}
+
+/*
+ * ---- PERCPU ----
+ */
+struct fprop_local_percpu {
+	/* the local events counter */
+	struct percpu_counter events;
+	/* Period in which we last updated events */
+	unsigned int period;
+	raw_spinlock_t lock;	/* Protect period and numerator */
+};
+
+int fprop_local_init_percpu(struct fprop_local_percpu *pl);
+void fprop_local_destroy_percpu(struct fprop_local_percpu *pl);
+void __fprop_inc_percpu(struct fprop_global *p, struct fprop_local_percpu *pl);
+void __fprop_inc_percpu_max(struct fprop_global *p, struct fprop_local_percpu *pl,
+			    int max_frac);
+void fprop_fraction_percpu(struct fprop_global *p,
+	struct fprop_local_percpu *pl, unsigned long *numerator,
+	unsigned long *denominator);
+
+static inline
+void fprop_inc_percpu(struct fprop_global *p, struct fprop_local_percpu *pl)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	__fprop_inc_percpu(p, pl);
+	local_irq_restore(flags);
+}
+
+#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 17fd887..3e035f4 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -437,6 +437,8 @@ extern unsigned long get_max_files(void);
 extern int sysctl_nr_open;
 extern struct inodes_stat_t inodes_stat;
 extern int leases_enable, lease_break_time;
+extern int sysctl_protected_symlinks;
+extern int sysctl_protected_hardlinks;
 
 struct buffer_head;
 typedef int (get_block_t)(struct inode *inode, sector_t iblock,
@@ -826,7 +828,7 @@ struct inode {
 	struct list_head	i_lru;		/* inode LRU list */
 	struct list_head	i_sb_list;
 	union {
-		struct list_head	i_dentry;
+		struct hlist_head	i_dentry;
 		struct rcu_head		i_rcu;
 	};
 	u64			i_version;
@@ -1571,7 +1573,7 @@ extern void unlock_super(struct super_block *);
 /*
  * VFS helper functions..
  */
-extern int vfs_create(struct inode *, struct dentry *, umode_t, struct nameidata *);
+extern int vfs_create(struct inode *, struct dentry *, umode_t, bool);
 extern int vfs_mkdir(struct inode *, struct dentry *, umode_t);
 extern int vfs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
 extern int vfs_symlink(struct inode *, struct dentry *, const char *);
@@ -1666,7 +1668,7 @@ struct file_operations {
 };
 
 struct inode_operations {
-	struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
+	struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
 	void * (*follow_link) (struct dentry *, struct nameidata *);
 	int (*permission) (struct inode *, int);
 	struct posix_acl * (*get_acl)(struct inode *, int);
@@ -1674,7 +1676,7 @@ struct inode_operations {
 	int (*readlink) (struct dentry *, char __user *,int);
 	void (*put_link) (struct dentry *, struct nameidata *, void *);
 
-	int (*create) (struct inode *,struct dentry *,umode_t,struct nameidata *);
+	int (*create) (struct inode *,struct dentry *, umode_t, bool);
 	int (*link) (struct dentry *,struct inode *,struct dentry *);
 	int (*unlink) (struct inode *,struct dentry *);
 	int (*symlink) (struct inode *,struct dentry *,const char *);
@@ -1693,6 +1695,9 @@ struct inode_operations {
 	int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
 		      u64 len);
 	int (*update_time)(struct inode *, struct timespec *, int);
+	int (*atomic_open)(struct inode *, struct dentry *,
+			   struct file *, unsigned open_flag,
+			   umode_t create_mode, int *opened);
 } ____cacheline_aligned;
 
 struct seq_file;
@@ -2061,6 +2066,14 @@ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
 				 const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
 extern char * getname(const char __user *);
+enum {
+	FILE_CREATED = 1,
+	FILE_OPENED = 2
+};
+extern int finish_open(struct file *file, struct dentry *dentry,
+			int (*open)(struct inode *, struct file *),
+			int *opened);
+extern int finish_no_open(struct file *file, struct dentry *dentry);
 
 /* fs/ioctl.c */
 
@@ -2560,7 +2573,7 @@ extern int simple_write_end(struct file *file, struct address_space *mapping,
 			loff_t pos, unsigned len, unsigned copied,
 			struct page *page, void *fsdata);
 
-extern struct dentry *simple_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);
 extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
 extern const struct file_operations simple_dir_operations;
 extern const struct inode_operations simple_dir_inode_operations;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 63d966d..d5b0910 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -88,9 +88,10 @@ struct fsnotify_event_private_data;
  *		if the group is interested in this event.
  * handle_event - main call for a group to handle an fs event
  * free_group_priv - called when a group refcnt hits 0 to clean up the private union
- * freeing-mark - this means that a mark has been flagged to die when everything
- *		finishes using it.  The function is supplied with what must be a
- *		valid group and inode to use to clean up.
+ * freeing_mark - called when a mark is being destroyed for some reason.  The group
+ * 		MUST be holding a reference on each mark and that reference must be
+ * 		dropped in this function.  inotify uses this function to send
+ * 		userspace messages that marks have been removed.
  */
 struct fsnotify_ops {
 	bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode,
@@ -141,12 +142,14 @@ struct fsnotify_group {
 	unsigned int priority;
 
 	/* stores all fastpath marks assoc with this group so they can be cleaned on unregister */
-	spinlock_t mark_lock;		/* protect marks_list */
+	struct mutex mark_mutex;	/* protect marks_list */
 	atomic_t num_marks;		/* 1 for each mark and 1 for not being
 					 * past the point of no return when freeing
 					 * a group */
 	struct list_head marks_list;	/* all inode marks for this group */
 
+	struct fasync_struct    *fsn_fa;    /* async notification */
+
 	/* groups can define private fields here or use the void *private */
 	union {
 		void *private;
@@ -155,7 +158,6 @@ struct fsnotify_group {
 			spinlock_t	idr_lock;
 			struct idr      idr;
 			u32             last_wd;
-			struct fasync_struct    *fa;    /* async notification */
 			struct user_struct      *user;
 		} inotify_data;
 #endif
@@ -287,7 +289,6 @@ struct fsnotify_mark {
 		struct fsnotify_inode_mark i;
 		struct fsnotify_vfsmount_mark m;
 	};
-	struct list_head free_g_list;	/* tmp list used when freeing this mark */
 	__u32 ignored_mask;		/* events types to ignore */
 #define FSNOTIFY_MARK_FLAG_INODE		0x01
 #define FSNOTIFY_MARK_FLAG_VFSMOUNT		0x02
@@ -360,11 +361,16 @@ static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode
 
 /* called from fsnotify listeners, such as fanotify or dnotify */
 
-/* get a reference to an existing or create a new group */
+/* create a new group */
 extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops);
+/* get reference to a group */
+extern void fsnotify_get_group(struct fsnotify_group *group);
 /* drop reference on a group from fsnotify_alloc_group */
 extern void fsnotify_put_group(struct fsnotify_group *group);
-
+/* destroy group */
+extern void fsnotify_destroy_group(struct fsnotify_group *group);
+/* fasync handler function */
+extern int fsnotify_fasync(int fd, struct file *file, int on);
 /* take a reference to an event */
 extern void fsnotify_get_event(struct fsnotify_event *event);
 extern void fsnotify_put_event(struct fsnotify_event *event);
@@ -405,8 +411,13 @@ extern void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask
 /* attach the mark to both the group and the inode */
 extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group,
 			     struct inode *inode, struct vfsmount *mnt, int allow_dups);
-/* given a mark, flag it to be freed when all references are dropped */
-extern void fsnotify_destroy_mark(struct fsnotify_mark *mark);
+extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct fsnotify_group *group,
+				    struct inode *inode, struct vfsmount *mnt, int allow_dups);
+/* given a group and a mark, flag mark to be freed when all references are dropped */
+extern void fsnotify_destroy_mark(struct fsnotify_mark *mark,
+				  struct fsnotify_group *group);
+extern void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark,
+					 struct fsnotify_group *group);
 /* run all the marks in a group, and clear all of the vfsmount marks */
 extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group);
 /* run all the marks in a group, and clear all of the inode marks */
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 176a939..1aff183 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -207,6 +207,9 @@ struct ftrace_event_call {
 	 *   bit 1:		enabled
 	 *   bit 2:		filter_active
 	 *   bit 3:		enabled cmd record
+	 *   bit 4:		allow trace by non root (cap any)
+	 *   bit 5:		failed to apply filter
+	 *   bit 6:		ftrace internal event (do not enable)
 	 *
 	 * Changes to flags must hold the event_mutex.
 	 *
diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h
deleted file mode 100644
index 79b3eb3..0000000
--- a/include/linux/generic_serial.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *  generic_serial.h
- *
- *  Copyright (C) 1998 R.E.Wolff@BitWizard.nl
- *
- *  written for the SX serial driver.
- *
- *  Version 0.1 -- December, 1998.
- */
-
-#ifndef GENERIC_SERIAL_H
-#define GENERIC_SERIAL_H
-
-#warning Use of this header is deprecated.
-#warning Since nobody sets the constants defined here for you, you should not, in any case, use them. Including the header is thus pointless.
-
-/* Flags */
-/* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
-   used in serial.c, but they are also used in all other serial drivers. 
-   Make sure they don't clash with these here... */
-#define GS_TX_INTEN      0x00800000
-#define GS_RX_INTEN      0x00400000
-#define GS_ACTIVE        0x00200000
-
-#define GS_TYPE_NORMAL   1
-
-#define GS_DEBUG_FLUSH   0x00000001
-#define GS_DEBUG_BTR     0x00000002
-#define GS_DEBUG_TERMIOS 0x00000004
-#define GS_DEBUG_STUFF   0x00000008
-#define GS_DEBUG_CLOSE   0x00000010
-#define GS_DEBUG_FLOW    0x00000020
-#define GS_DEBUG_WRITE   0x00000040
-
-#endif
diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h
index fa98bdb..b2de1f9 100644
--- a/include/linux/gfs2_ondisk.h
+++ b/include/linux/gfs2_ondisk.h
@@ -170,6 +170,16 @@ struct gfs2_rindex {
 #define GFS2_RGF_NOALLOC	0x00000008
 #define GFS2_RGF_TRIMMED	0x00000010
 
+struct gfs2_rgrp_lvb {
+	__be32 rl_magic;
+	__be32 rl_flags;
+	__be32 rl_free;
+	__be32 rl_dinodes;
+	__be64 rl_igeneration;
+	__be32 rl_unlinked;
+	__be32 __pad;
+};
+
 struct gfs2_rgrp {
 	struct gfs2_meta_header rg_header;
 
@@ -214,6 +224,7 @@ enum {
 	gfs2fl_NoAtime		= 7,
 	gfs2fl_Sync		= 8,
 	gfs2fl_System		= 9,
+	gfs2fl_TopLevel		= 10,
 	gfs2fl_TruncInProg	= 29,
 	gfs2fl_InheritDirectio	= 30,
 	gfs2fl_InheritJdata	= 31,
@@ -230,8 +241,9 @@ enum {
 #define GFS2_DIF_NOATIME		0x00000080
 #define GFS2_DIF_SYNC			0x00000100
 #define GFS2_DIF_SYSTEM			0x00000200 /* New in gfs2 */
+#define GFS2_DIF_TOPDIR			0x00000400 /* New in gfs2 */
 #define GFS2_DIF_TRUNC_IN_PROG		0x20000000 /* New in gfs2 */
-#define GFS2_DIF_INHERIT_DIRECTIO	0x40000000
+#define GFS2_DIF_INHERIT_DIRECTIO	0x40000000 /* only in gfs1 */
 #define GFS2_DIF_INHERIT_JDATA		0x80000000
 
 struct gfs2_dinode {
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index d3999b4..774fa47 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -110,54 +110,15 @@ static inline void kmap_atomic_idx_pop(void)
 #endif
 
 /*
- * NOTE:
- * kmap_atomic() and kunmap_atomic() with two arguments are deprecated.
- * We only keep them for backward compatibility, any usage of them
- * are now warned.
- */
-
-#define PASTE(a, b) a ## b
-#define PASTE2(a, b) PASTE(a, b)
-
-#define NARG_(_2, _1, n, ...) n
-#define NARG(...) NARG_(__VA_ARGS__, 2, 1, :)
-
-static inline void __deprecated *kmap_atomic_deprecated(struct page *page,
-							enum km_type km)
-{
-	return kmap_atomic(page);
-}
-
-#define kmap_atomic1(...) kmap_atomic(__VA_ARGS__)
-#define kmap_atomic2(...) kmap_atomic_deprecated(__VA_ARGS__)
-#define kmap_atomic(...) PASTE2(kmap_atomic, NARG(__VA_ARGS__)(__VA_ARGS__))
-
-static inline void __deprecated __kunmap_atomic_deprecated(void *addr,
-							enum km_type km)
-{
-	__kunmap_atomic(addr);
-}
-
-/*
  * Prevent people trying to call kunmap_atomic() as if it were kunmap()
  * kunmap_atomic() should get the return value of kmap_atomic, not the page.
  */
-#define kunmap_atomic_deprecated(addr, km)                      \
-do {                                                            \
-	BUILD_BUG_ON(__same_type((addr), struct page *));       \
-	__kunmap_atomic_deprecated(addr, km);                   \
-} while (0)
-
-#define kunmap_atomic_withcheck(addr)                           \
+#define kunmap_atomic(addr)                                     \
 do {                                                            \
 	BUILD_BUG_ON(__same_type((addr), struct page *));       \
 	__kunmap_atomic(addr);                                  \
 } while (0)
 
-#define kunmap_atomic1(...) kunmap_atomic_withcheck(__VA_ARGS__)
-#define kunmap_atomic2(...) kunmap_atomic_deprecated(__VA_ARGS__)
-#define kunmap_atomic(...) PASTE2(kunmap_atomic, NARG(__VA_ARGS__)(__VA_ARGS__))
-/**** End of C pre-processor tricks for deprecated macros ****/
 
 /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */
 #ifndef clear_user_highpage
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index d5d6bbe..0f0877e 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -4,9 +4,11 @@
 #include <linux/mm_types.h>
 #include <linux/fs.h>
 #include <linux/hugetlb_inline.h>
+#include <linux/cgroup.h>
 
 struct ctl_table;
 struct user_struct;
+struct mmu_gather;
 
 #ifdef CONFIG_HUGETLB_PAGE
 
@@ -20,6 +22,11 @@ struct hugepage_subpool {
 	long max_hpages, used_hpages;
 };
 
+extern spinlock_t hugetlb_lock;
+extern int hugetlb_max_hstate __read_mostly;
+#define for_each_hstate(h) \
+	for ((h) = hstates; (h) < &hstates[hugetlb_max_hstate]; (h)++)
+
 struct hugepage_subpool *hugepage_new_subpool(long nr_blocks);
 void hugepage_put_subpool(struct hugepage_subpool *spool);
 
@@ -40,9 +47,10 @@ int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *,
 			struct page **, struct vm_area_struct **,
 			unsigned long *, int *, int, unsigned int flags);
 void unmap_hugepage_range(struct vm_area_struct *,
-			unsigned long, unsigned long, struct page *);
-void __unmap_hugepage_range(struct vm_area_struct *,
-			unsigned long, unsigned long, struct page *);
+			  unsigned long, unsigned long, struct page *);
+void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+				unsigned long start, unsigned long end,
+				struct page *ref_page);
 int hugetlb_prefault(struct address_space *, struct vm_area_struct *);
 void hugetlb_report_meminfo(struct seq_file *);
 int hugetlb_report_node_meminfo(int, char *);
@@ -98,7 +106,6 @@ static inline unsigned long hugetlb_total_pages(void)
 #define follow_huge_addr(mm, addr, write)	ERR_PTR(-EINVAL)
 #define copy_hugetlb_page_range(src, dst, vma)	({ BUG(); 0; })
 #define hugetlb_prefault(mapping, vma)		({ BUG(); 0; })
-#define unmap_hugepage_range(vma, start, end, page)	BUG()
 static inline void hugetlb_report_meminfo(struct seq_file *m)
 {
 }
@@ -112,13 +119,24 @@ static inline void hugetlb_report_meminfo(struct seq_file *m)
 #define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; })
 #define hugetlb_fault(mm, vma, addr, flags)	({ BUG(); 0; })
 #define huge_pte_offset(mm, address)	0
-#define dequeue_hwpoisoned_huge_page(page)	0
+static inline int dequeue_hwpoisoned_huge_page(struct page *page)
+{
+	return 0;
+}
+
 static inline void copy_huge_page(struct page *dst, struct page *src)
 {
 }
 
 #define hugetlb_change_protection(vma, address, end, newprot)
 
+static inline void __unmap_hugepage_range(struct mmu_gather *tlb,
+			struct vm_area_struct *vma, unsigned long start,
+			unsigned long end, struct page *ref_page)
+{
+	BUG();
+}
+
 #endif /* !CONFIG_HUGETLB_PAGE */
 
 #define HUGETLB_ANON_FILE "anon_hugepage"
@@ -199,10 +217,15 @@ struct hstate {
 	unsigned long resv_huge_pages;
 	unsigned long surplus_huge_pages;
 	unsigned long nr_overcommit_huge_pages;
+	struct list_head hugepage_activelist;
 	struct list_head hugepage_freelists[MAX_NUMNODES];
 	unsigned int nr_huge_pages_node[MAX_NUMNODES];
 	unsigned int free_huge_pages_node[MAX_NUMNODES];
 	unsigned int surplus_huge_pages_node[MAX_NUMNODES];
+#ifdef CONFIG_CGROUP_HUGETLB_RES_CTLR
+	/* cgroup control files */
+	struct cftype cgroup_files[5];
+#endif
 	char name[HSTATE_NAME_LEN];
 };
 
@@ -302,6 +325,11 @@ static inline unsigned hstate_index_to_shift(unsigned index)
 	return hstates[index].order + PAGE_SHIFT;
 }
 
+static inline int hstate_index(struct hstate *h)
+{
+	return h - hstates;
+}
+
 #else
 struct hstate {};
 #define alloc_huge_page_node(h, nid) NULL
@@ -320,6 +348,7 @@ static inline unsigned int pages_per_huge_page(struct hstate *h)
 	return 1;
 }
 #define hstate_index_to_shift(index) 0
+#define hstate_index(h) 0
 #endif
 
 #endif /* _LINUX_HUGETLB_H */
diff --git a/include/linux/hugetlb_cgroup.h b/include/linux/hugetlb_cgroup.h
new file mode 100644
index 0000000..bc30413
--- /dev/null
+++ b/include/linux/hugetlb_cgroup.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright IBM Corporation, 2012
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef _LINUX_HUGETLB_CGROUP_H
+#define _LINUX_HUGETLB_CGROUP_H
+
+#include <linux/res_counter.h>
+
+struct hugetlb_cgroup;
+/*
+ * Minimum page order trackable by hugetlb cgroup.
+ * At least 3 pages are necessary for all the tracking information.
+ */
+#define HUGETLB_CGROUP_MIN_ORDER	2
+
+#ifdef CONFIG_CGROUP_HUGETLB_RES_CTLR
+
+static inline struct hugetlb_cgroup *hugetlb_cgroup_from_page(struct page *page)
+{
+	VM_BUG_ON(!PageHuge(page));
+
+	if (compound_order(page) < HUGETLB_CGROUP_MIN_ORDER)
+		return NULL;
+	return (struct hugetlb_cgroup *)page[2].lru.next;
+}
+
+static inline
+int set_hugetlb_cgroup(struct page *page, struct hugetlb_cgroup *h_cg)
+{
+	VM_BUG_ON(!PageHuge(page));
+
+	if (compound_order(page) < HUGETLB_CGROUP_MIN_ORDER)
+		return -1;
+	page[2].lru.next = (void *)h_cg;
+	return 0;
+}
+
+static inline bool hugetlb_cgroup_disabled(void)
+{
+	if (hugetlb_subsys.disabled)
+		return true;
+	return false;
+}
+
+extern int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
+					struct hugetlb_cgroup **ptr);
+extern void hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages,
+					 struct hugetlb_cgroup *h_cg,
+					 struct page *page);
+extern void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages,
+					 struct page *page);
+extern void hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages,
+					   struct hugetlb_cgroup *h_cg);
+extern int hugetlb_cgroup_file_init(int idx) __init;
+extern void hugetlb_cgroup_migrate(struct page *oldhpage,
+				   struct page *newhpage);
+
+#else
+static inline struct hugetlb_cgroup *hugetlb_cgroup_from_page(struct page *page)
+{
+	return NULL;
+}
+
+static inline
+int set_hugetlb_cgroup(struct page *page, struct hugetlb_cgroup *h_cg)
+{
+	return 0;
+}
+
+static inline bool hugetlb_cgroup_disabled(void)
+{
+	return true;
+}
+
+static inline int
+hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
+			     struct hugetlb_cgroup **ptr)
+{
+	return 0;
+}
+
+static inline void
+hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages,
+			     struct hugetlb_cgroup *h_cg,
+			     struct page *page)
+{
+	return;
+}
+
+static inline void
+hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages, struct page *page)
+{
+	return;
+}
+
+static inline void
+hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages,
+			       struct hugetlb_cgroup *h_cg)
+{
+	return;
+}
+
+static inline int __init hugetlb_cgroup_file_init(int idx)
+{
+	return 0;
+}
+
+static inline void hugetlb_cgroup_migrate(struct page *oldhpage,
+					  struct page *newhpage)
+{
+	return;
+}
+
+#endif  /* CONFIG_MEM_RES_CTLR_HUGETLB */
+#endif
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index 3993477..8eec440 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -555,6 +555,8 @@ struct twl4030_clock_init_data {
 struct twl4030_bci_platform_data {
 	int *battery_tmp_tbl;
 	unsigned int tblsize;
+	int	bb_uvolt;	/* voltage to charge backup battery */
+	int	bb_uamp;	/* current for backup battery charging */
 };
 
 /* TWL4030_GPIO_MAX (18) GPIOs, with interrupts */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index ce9af89..318fc1f 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -568,6 +568,26 @@ struct ieee80211s_hdr {
 #define MESH_FLAGS_PS_DEEP	0x4
 
 /**
+ * enum ieee80211_preq_flags - mesh PREQ element flags
+ *
+ * @IEEE80211_PREQ_PROACTIVE_PREP_FLAG: proactive PREP subfield
+ */
+enum ieee80211_preq_flags {
+	IEEE80211_PREQ_PROACTIVE_PREP_FLAG	= 1<<2,
+};
+
+/**
+ * enum ieee80211_preq_target_flags - mesh PREQ element per target flags
+ *
+ * @IEEE80211_PREQ_TO_FLAG: target only subfield
+ * @IEEE80211_PREQ_USN_FLAG: unknown target HWMP sequence number subfield
+ */
+enum ieee80211_preq_target_flags {
+	IEEE80211_PREQ_TO_FLAG	= 1<<0,
+	IEEE80211_PREQ_USN_FLAG	= 1<<2,
+};
+
+/**
  * struct ieee80211_quiet_ie
  *
  * This structure refers to "Quiet information element"
@@ -1443,7 +1463,7 @@ enum ieee80211_tdls_actioncode {
  *
  * @IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET: the default synchronization method
  * @IEEE80211_SYNC_METHOD_VENDOR: a vendor specific synchronization method
- * that will be specified in a vendor specific information element
+ *	that will be specified in a vendor specific information element
  */
 enum {
 	IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET = 1,
@@ -1455,7 +1475,7 @@ enum {
  *
  * @IEEE80211_PATH_PROTOCOL_HWMP: the default path selection protocol
  * @IEEE80211_PATH_PROTOCOL_VENDOR: a vendor specific protocol that will
- * be specified in a vendor specific information element
+ *	be specified in a vendor specific information element
  */
 enum {
 	IEEE80211_PATH_PROTOCOL_HWMP = 1,
@@ -1467,13 +1487,35 @@ enum {
  *
  * @IEEE80211_PATH_METRIC_AIRTIME: the default path selection metric
  * @IEEE80211_PATH_METRIC_VENDOR: a vendor specific metric that will be
- * specified in a vendor specific information element
+ *	specified in a vendor specific information element
  */
 enum {
 	IEEE80211_PATH_METRIC_AIRTIME = 1,
 	IEEE80211_PATH_METRIC_VENDOR = 255,
 };
 
+/**
+ * enum ieee80211_root_mode_identifier - root mesh STA mode identifier
+ *
+ * These attribute are used by dot11MeshHWMPRootMode to set root mesh STA mode
+ *
+ * @IEEE80211_ROOTMODE_NO_ROOT: the mesh STA is not a root mesh STA (default)
+ * @IEEE80211_ROOTMODE_ROOT: the mesh STA is a root mesh STA if greater than
+ *	this value
+ * @IEEE80211_PROACTIVE_PREQ_NO_PREP: the mesh STA is a root mesh STA supports
+ *	the proactive PREQ with proactive PREP subfield set to 0
+ * @IEEE80211_PROACTIVE_PREQ_WITH_PREP: the mesh STA is a root mesh STA
+ *	supports the proactive PREQ with proactive PREP subfield set to 1
+ * @IEEE80211_PROACTIVE_RANN: the mesh STA is a root mesh STA supports
+ *	the proactive RANN
+ */
+enum ieee80211_root_mode_identifier {
+	IEEE80211_ROOTMODE_NO_ROOT = 0,
+	IEEE80211_ROOTMODE_ROOT = 1,
+	IEEE80211_PROACTIVE_PREQ_NO_PREP = 2,
+	IEEE80211_PROACTIVE_PREQ_WITH_PREP = 3,
+	IEEE80211_PROACTIVE_RANN = 4,
+};
 
 /*
  * IEEE 802.11-2007 7.3.2.9 Country information element
@@ -1589,6 +1631,10 @@ enum ieee80211_sa_query_action {
 
 #define WLAN_OUI_WFA			0x506f9a
 #define WLAN_OUI_TYPE_WFA_P2P		9
+#define WLAN_OUI_MICROSOFT		0x0050f2
+#define WLAN_OUI_TYPE_MICROSOFT_WPA	1
+#define WLAN_OUI_TYPE_MICROSOFT_WMM	2
+#define WLAN_OUI_TYPE_MICROSOFT_WPS	4
 
 /*
  * WMM/802.11e Tspec Element
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 56d907a..167ce5b 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -105,7 +105,8 @@
 #define ETH_P_WAN_PPP   0x0007          /* Dummy type for WAN PPP frames*/
 #define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
 #define ETH_P_LOCALTALK 0x0009		/* Localtalk pseudo type 	*/
-#define ETH_P_CAN	0x000C		/* Controller Area Network      */
+#define ETH_P_CAN	0x000C		/* CAN: Controller Area Network */
+#define ETH_P_CANFD	0x000D		/* CANFD: CAN flexible data rate*/
 #define ETH_P_PPPTALK	0x0010		/* Dummy type for Atalk over PPP*/
 #define ETH_P_TR_802_2	0x0011		/* 802.2 frames 		*/
 #define ETH_P_MOBITEX	0x0015		/* Mobitex (kaz@cafe.net)	*/
diff --git a/include/linux/if_strip.h b/include/linux/if_strip.h
deleted file mode 100644
index 6526a62..0000000
--- a/include/linux/if_strip.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * if_strip.h --
- *
- *      Definitions for the STRIP interface
- *
- * Copyright 1996 The Board of Trustees of The Leland Stanford
- * Junior University. All Rights Reserved.
- *
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies.  Stanford University
- * makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without
- * express or implied warranty.
- */
-
-#ifndef __LINUX_STRIP_H
-#define __LINUX_STRIP_H
-
-#include <linux/types.h>
-
-typedef struct {
-    __u8 c[6];
-} MetricomAddress;
-
-#endif
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index 8185f57..c193886 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -61,6 +61,7 @@ struct team_port {
 	} orig;
 
 	struct rcu_head rcu;
+	long mode_priv[0];
 };
 
 struct team_mode_ops {
@@ -73,6 +74,8 @@ struct team_mode_ops {
 	int (*port_enter)(struct team *team, struct team_port *port);
 	void (*port_leave)(struct team *team, struct team_port *port);
 	void (*port_change_mac)(struct team *team, struct team_port *port);
+	void (*port_enabled)(struct team *team, struct team_port *port);
+	void (*port_disabled)(struct team *team, struct team_port *port);
 };
 
 enum team_option_type {
@@ -82,6 +85,11 @@ enum team_option_type {
 	TEAM_OPTION_TYPE_BOOL,
 };
 
+struct team_option_inst_info {
+	u32 array_index;
+	struct team_port *port; /* != NULL if per-port */
+};
+
 struct team_gsetter_ctx {
 	union {
 		u32 u32_val;
@@ -92,23 +100,28 @@ struct team_gsetter_ctx {
 		} bin_val;
 		bool bool_val;
 	} data;
-	struct team_port *port;
+	struct team_option_inst_info *info;
 };
 
 struct team_option {
 	struct list_head list;
 	const char *name;
 	bool per_port;
+	unsigned int array_size; /* != 0 means the option is array */
 	enum team_option_type type;
+	int (*init)(struct team *team, struct team_option_inst_info *info);
 	int (*getter)(struct team *team, struct team_gsetter_ctx *ctx);
 	int (*setter)(struct team *team, struct team_gsetter_ctx *ctx);
 };
 
+extern void team_option_inst_set_change(struct team_option_inst_info *opt_inst_info);
+extern void team_options_change_check(struct team *team);
+
 struct team_mode {
-	struct list_head list;
 	const char *kind;
 	struct module *owner;
 	size_t priv_size;
+	size_t port_priv_size;
 	const struct team_mode_ops *ops;
 };
 
@@ -178,8 +191,8 @@ extern int team_options_register(struct team *team,
 extern void team_options_unregister(struct team *team,
 				    const struct team_option *option,
 				    size_t option_count);
-extern int team_mode_register(struct team_mode *mode);
-extern int team_mode_unregister(struct team_mode *mode);
+extern int team_mode_register(const struct team_mode *mode);
+extern void team_mode_unregister(const struct team_mode *mode);
 
 #endif /* __KERNEL__ */
 
@@ -241,6 +254,7 @@ enum {
 	TEAM_ATTR_OPTION_DATA,		/* dynamic */
 	TEAM_ATTR_OPTION_REMOVED,	/* flag */
 	TEAM_ATTR_OPTION_PORT_IFINDEX,	/* u32 */ /* for per-port options */
+	TEAM_ATTR_OPTION_ARRAY_INDEX,	/* u32 */ /* for array options */
 
 	__TEAM_ATTR_OPTION_MAX,
 	TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1,
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index fb0fe46..ad4fb1a 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -184,7 +184,7 @@ static inline int iio_buffer_register(struct iio_dev *indio_dev,
 }
 
 static inline void iio_buffer_unregister(struct iio_dev *indio_dev)
-{};
+{}
 
 #endif /* CONFIG_IIO_BUFFER */
 
diff --git a/include/linux/iio/dac/ad5421.h b/include/linux/iio/dac/ad5421.h
new file mode 100644
index 0000000..8fd8f05
--- /dev/null
+++ b/include/linux/iio/dac/ad5421.h
@@ -0,0 +1,28 @@
+#ifndef __IIO_DAC_AD5421_H__
+#define __IIO_DAC_AD5421_H__
+
+/**
+ * enum ad5421_current_range - Current range the AD5421 is configured for.
+ * @AD5421_CURRENT_RANGE_4mA_20mA: 4 mA to 20 mA (RANGE1,0 pins = 00)
+ * @AD5421_CURRENT_RANGE_3mA8_21mA: 3.8 mA to 21 mA (RANGE1,0 pins = x1)
+ * @AD5421_CURRENT_RANGE_3mA2_24mA: 3.2 mA to 24 mA (RANGE1,0 pins = 10)
+ */
+
+enum ad5421_current_range {
+	AD5421_CURRENT_RANGE_4mA_20mA,
+	AD5421_CURRENT_RANGE_3mA8_21mA,
+	AD5421_CURRENT_RANGE_3mA2_24mA,
+};
+
+/**
+ * struct ad5421_platform_data - AD5421 DAC driver platform data
+ * @external_vref: whether an external reference voltage is used or not
+ * @current_range: Current range the AD5421 is configured for
+ */
+
+struct ad5421_platform_data {
+	bool external_vref;
+	enum ad5421_current_range current_range;
+};
+
+#endif
diff --git a/include/linux/iio/dac/ad5504.h b/include/linux/iio/dac/ad5504.h
new file mode 100644
index 0000000..4389537
--- /dev/null
+++ b/include/linux/iio/dac/ad5504.h
@@ -0,0 +1,16 @@
+/*
+ * AD5504 SPI DAC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef SPI_AD5504_H_
+#define SPI_AD5504_H_
+
+struct ad5504_platform_data {
+	u16				vref_mv;
+};
+
+#endif /* SPI_AD5504_H_ */
diff --git a/include/linux/iio/dac/ad5791.h b/include/linux/iio/dac/ad5791.h
new file mode 100644
index 0000000..45ee281
--- /dev/null
+++ b/include/linux/iio/dac/ad5791.h
@@ -0,0 +1,25 @@
+/*
+ * AD5791 SPI DAC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef SPI_AD5791_H_
+#define SPI_AD5791_H_
+
+/**
+ * struct ad5791_platform_data - platform specific information
+ * @vref_pos_mv:	Vdd Positive Analog Supply Volatge (mV)
+ * @vref_neg_mv:	Vdd Negative Analog Supply Volatge (mV)
+ * @use_rbuf_gain2:	ext. amplifier connected in gain of two configuration
+ */
+
+struct ad5791_platform_data {
+	u16				vref_pos_mv;
+	u16				vref_neg_mv;
+	bool				use_rbuf_gain2;
+};
+
+#endif /* SPI_AD5791_H_ */
diff --git a/include/linux/iio/dac/max517.h b/include/linux/iio/dac/max517.h
new file mode 100644
index 0000000..f6d1d25
--- /dev/null
+++ b/include/linux/iio/dac/max517.h
@@ -0,0 +1,15 @@
+/*
+ * MAX517 DAC driver
+ *
+ * Copyright 2011 Roland Stigge <stigge@antcom.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef IIO_DAC_MAX517_H_
+#define IIO_DAC_MAX517_H_
+
+struct max517_platform_data {
+	u16				vref_mv[2];
+};
+
+#endif /* IIO_DAC_MAX517_H_ */
diff --git a/include/linux/iio/dac/mcp4725.h b/include/linux/iio/dac/mcp4725.h
new file mode 100644
index 0000000..91530e6
--- /dev/null
+++ b/include/linux/iio/dac/mcp4725.h
@@ -0,0 +1,16 @@
+/*
+ * MCP4725 DAC driver
+ *
+ * Copyright (C) 2012 Peter Meerwald <pmeerw@pmeerw.net>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef IIO_DAC_MCP4725_H_
+#define IIO_DAC_MCP4725_H_
+
+struct mcp4725_platform_data {
+	u16 vref_mv;
+};
+
+#endif /* IIO_DAC_MCP4725_H_ */
diff --git a/include/linux/iio/events.h b/include/linux/iio/events.h
index b5acbf9..13ce220 100644
--- a/include/linux/iio/events.h
+++ b/include/linux/iio/events.h
@@ -46,7 +46,7 @@ enum iio_event_direction {
  * @diff:	Whether the event is for an differential channel or not.
  * @modifier:	Modifier for the channel. Should be one of enum iio_modifier.
  * @direction:	Direction of the event. One of enum iio_event_direction.
- * @type:	Type of the event. Should be one enum iio_event_type.
+ * @type:	Type of the event. Should be one of enum iio_event_type.
  * @chan:	Channel number for non-differential channels.
  * @chan1:	First channel number for differential channels.
  * @chan2:	Second channel number for differential channels.
@@ -69,7 +69,7 @@ enum iio_event_direction {
  * @chan_type:	Type of the channel. Should be one of enum iio_chan_type.
  * @number:	Channel number.
  * @modifier:	Modifier for the channel. Should be one of enum iio_modifier.
- * @type:	Type of the event. Should be one enum iio_event_type.
+ * @type:	Type of the event. Should be one of enum iio_event_type.
  * @direction:	Direction of the event. One of enum iio_event_direction.
  */
 
@@ -81,7 +81,7 @@ enum iio_event_direction {
  * IIO_UNMOD_EVENT_CODE() - create event identifier for unmodified channels
  * @chan_type:	Type of the channel. Should be one of enum iio_chan_type.
  * @number:	Channel number.
- * @type:	Type of the event. Should be one enum iio_event_type.
+ * @type:	Type of the event. Should be one of enum iio_event_type.
  * @direction:	Direction of the event. One of enum iio_event_direction.
  */
 
diff --git a/include/linux/iio/frequency/ad9523.h b/include/linux/iio/frequency/ad9523.h
new file mode 100644
index 0000000..12ce3ee
--- /dev/null
+++ b/include/linux/iio/frequency/ad9523.h
@@ -0,0 +1,195 @@
+/*
+ * AD9523 SPI Low Jitter Clock Generator
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef IIO_FREQUENCY_AD9523_H_
+#define IIO_FREQUENCY_AD9523_H_
+
+enum outp_drv_mode {
+	TRISTATE,
+	LVPECL_8mA,
+	LVDS_4mA,
+	LVDS_7mA,
+	HSTL0_16mA,
+	HSTL1_8mA,
+	CMOS_CONF1,
+	CMOS_CONF2,
+	CMOS_CONF3,
+	CMOS_CONF4,
+	CMOS_CONF5,
+	CMOS_CONF6,
+	CMOS_CONF7,
+	CMOS_CONF8,
+	CMOS_CONF9
+};
+
+enum ref_sel_mode {
+	NONEREVERTIVE_STAY_ON_REFB,
+	REVERT_TO_REFA,
+	SELECT_REFA,
+	SELECT_REFB,
+	EXT_REF_SEL
+};
+
+/**
+ * struct ad9523_channel_spec - Output channel configuration
+ *
+ * @channel_num: Output channel number.
+ * @divider_output_invert_en: Invert the polarity of the output clock.
+ * @sync_ignore_en: Ignore chip-level SYNC signal.
+ * @low_power_mode_en: Reduce power used in the differential output modes.
+ * @use_alt_clock_src: Channel divider uses alternative clk source.
+ * @output_dis: Disables, powers down the entire channel.
+ * @driver_mode: Output driver mode (logic level family).
+ * @divider_phase: Divider initial phase after a SYNC. Range 0..63
+		   LSB = 1/2 of a period of the divider input clock.
+ * @channel_divider: 10-bit channel divider.
+ * @extended_name: Optional descriptive channel name.
+ */
+
+struct ad9523_channel_spec {
+	unsigned		channel_num;
+	bool			divider_output_invert_en;
+	bool			sync_ignore_en;
+	bool			low_power_mode_en;
+				 /* CH0..CH3 VCXO, CH4..CH9 VCO2 */
+	bool			use_alt_clock_src;
+	bool			output_dis;
+	enum outp_drv_mode	driver_mode;
+	unsigned char		divider_phase;
+	unsigned short		channel_divider;
+	char			extended_name[16];
+};
+
+enum pll1_rzero_resistor {
+	RZERO_883_OHM,
+	RZERO_677_OHM,
+	RZERO_341_OHM,
+	RZERO_135_OHM,
+	RZERO_10_OHM,
+	RZERO_USE_EXT_RES = 8,
+};
+
+enum rpole2_resistor {
+	RPOLE2_900_OHM,
+	RPOLE2_450_OHM,
+	RPOLE2_300_OHM,
+	RPOLE2_225_OHM,
+};
+
+enum rzero_resistor {
+	RZERO_3250_OHM,
+	RZERO_2750_OHM,
+	RZERO_2250_OHM,
+	RZERO_2100_OHM,
+	RZERO_3000_OHM,
+	RZERO_2500_OHM,
+	RZERO_2000_OHM,
+	RZERO_1850_OHM,
+};
+
+enum cpole1_capacitor {
+	CPOLE1_0_PF,
+	CPOLE1_8_PF,
+	CPOLE1_16_PF,
+	CPOLE1_24_PF,
+	_CPOLE1_24_PF, /* place holder */
+	CPOLE1_32_PF,
+	CPOLE1_40_PF,
+	CPOLE1_48_PF,
+};
+
+/**
+ * struct ad9523_platform_data - platform specific information
+ *
+ * @vcxo_freq: External VCXO frequency in Hz
+ * @refa_diff_rcv_en: REFA differential/single-ended input selection.
+ * @refb_diff_rcv_en: REFB differential/single-ended input selection.
+ * @zd_in_diff_en: Zero Delay differential/single-ended input selection.
+ * @osc_in_diff_en: OSC differential/ single-ended input selection.
+ * @refa_cmos_neg_inp_en: REFA single-ended neg./pos. input enable.
+ * @refb_cmos_neg_inp_en: REFB single-ended neg./pos. input enable.
+ * @zd_in_cmos_neg_inp_en: Zero Delay single-ended neg./pos. input enable.
+ * @osc_in_cmos_neg_inp_en: OSC single-ended neg./pos. input enable.
+ * @refa_r_div: PLL1 10-bit REFA R divider.
+ * @refb_r_div: PLL1 10-bit REFB R divider.
+ * @pll1_feedback_div: PLL1 10-bit Feedback N divider.
+ * @pll1_charge_pump_current_nA: Magnitude of PLL1 charge pump current (nA).
+ * @zero_delay_mode_internal_en: Internal, external Zero Delay mode selection.
+ * @osc_in_feedback_en: PLL1 feedback path, local feedback from
+ *			the OSC_IN receiver or zero delay mode
+ * @pll1_loop_filter_rzero: PLL1 Loop Filter Zero Resistor selection.
+ * @ref_mode: Reference selection mode.
+ * @pll2_charge_pump_current_nA: Magnitude of PLL2 charge pump current (nA).
+ * @pll2_ndiv_a_cnt: PLL2 Feedback N-divider, A Counter, range 0..4.
+ * @pll2_ndiv_b_cnt: PLL2 Feedback N-divider, B Counter, range 0..63.
+ * @pll2_freq_doubler_en: PLL2 frequency doubler enable.
+ * @pll2_r2_div: PLL2 R2 divider, range 0..31.
+ * @pll2_vco_diff_m1: VCO1 divider, range 3..5.
+ * @pll2_vco_diff_m2: VCO2 divider, range 3..5.
+ * @rpole2: PLL2 loop filter Rpole resistor value.
+ * @rzero: PLL2 loop filter Rzero resistor value.
+ * @cpole1: PLL2 loop filter Cpole capacitor value.
+ * @rzero_bypass_en: PLL2 loop filter Rzero bypass enable.
+ * @num_channels: Array size of struct ad9523_channel_spec.
+ * @channels: Pointer to channel array.
+ * @name: Optional alternative iio device name.
+ */
+
+struct ad9523_platform_data {
+	unsigned long vcxo_freq;
+
+	/* Differential/ Single-Ended Input Configuration */
+	bool				refa_diff_rcv_en;
+	bool				refb_diff_rcv_en;
+	bool				zd_in_diff_en;
+	bool				osc_in_diff_en;
+
+	/*
+	 * Valid if differential input disabled
+	 * if false defaults to pos input
+	 */
+	bool				refa_cmos_neg_inp_en;
+	bool				refb_cmos_neg_inp_en;
+	bool				zd_in_cmos_neg_inp_en;
+	bool				osc_in_cmos_neg_inp_en;
+
+	/* PLL1 Setting */
+	unsigned short			refa_r_div;
+	unsigned short			refb_r_div;
+	unsigned short			pll1_feedback_div;
+	unsigned short			pll1_charge_pump_current_nA;
+	bool				zero_delay_mode_internal_en;
+	bool				osc_in_feedback_en;
+	enum pll1_rzero_resistor	pll1_loop_filter_rzero;
+
+	/* Reference */
+	enum ref_sel_mode		ref_mode;
+
+	/* PLL2 Setting */
+	unsigned int			pll2_charge_pump_current_nA;
+	unsigned char			pll2_ndiv_a_cnt;
+	unsigned char			pll2_ndiv_b_cnt;
+	bool				pll2_freq_doubler_en;
+	unsigned char			pll2_r2_div;
+	unsigned char			pll2_vco_diff_m1; /* 3..5 */
+	unsigned char			pll2_vco_diff_m2; /* 3..5 */
+
+	/* Loop Filter PLL2 */
+	enum rpole2_resistor		rpole2;
+	enum rzero_resistor		rzero;
+	enum cpole1_capacitor		cpole1;
+	bool				rzero_bypass_en;
+
+	/* Output Channel Configuration */
+	int				num_channels;
+	struct ad9523_channel_spec	*channels;
+
+	char				name[SPI_NAME_SIZE];
+};
+
+#endif /* IIO_FREQUENCY_AD9523_H_ */
diff --git a/include/linux/iio/frequency/adf4350.h b/include/linux/iio/frequency/adf4350.h
new file mode 100644
index 0000000..b76b4a8
--- /dev/null
+++ b/include/linux/iio/frequency/adf4350.h
@@ -0,0 +1,126 @@
+/*
+ * ADF4350/ADF4351 SPI PLL driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef IIO_PLL_ADF4350_H_
+#define IIO_PLL_ADF4350_H_
+
+/* Registers */
+#define ADF4350_REG0	0
+#define ADF4350_REG1	1
+#define ADF4350_REG2	2
+#define ADF4350_REG3	3
+#define ADF4350_REG4	4
+#define ADF4350_REG5	5
+
+/* REG0 Bit Definitions */
+#define ADF4350_REG0_FRACT(x)			(((x) & 0xFFF) << 3)
+#define ADF4350_REG0_INT(x)			(((x) & 0xFFFF) << 15)
+
+/* REG1 Bit Definitions */
+#define ADF4350_REG1_MOD(x)			(((x) & 0xFFF) << 3)
+#define ADF4350_REG1_PHASE(x)			(((x) & 0xFFF) << 15)
+#define ADF4350_REG1_PRESCALER			(1 << 27)
+
+/* REG2 Bit Definitions */
+#define ADF4350_REG2_COUNTER_RESET_EN		(1 << 3)
+#define ADF4350_REG2_CP_THREESTATE_EN		(1 << 4)
+#define ADF4350_REG2_POWER_DOWN_EN		(1 << 5)
+#define ADF4350_REG2_PD_POLARITY_POS		(1 << 6)
+#define ADF4350_REG2_LDP_6ns			(1 << 7)
+#define ADF4350_REG2_LDP_10ns			(0 << 7)
+#define ADF4350_REG2_LDF_FRACT_N		(0 << 8)
+#define ADF4350_REG2_LDF_INT_N			(1 << 8)
+#define ADF4350_REG2_CHARGE_PUMP_CURR_uA(x)	(((((x)-312) / 312) & 0xF) << 9)
+#define ADF4350_REG2_DOUBLE_BUFF_EN		(1 << 13)
+#define ADF4350_REG2_10BIT_R_CNT(x)		((x) << 14)
+#define ADF4350_REG2_RDIV2_EN			(1 << 24)
+#define ADF4350_REG2_RMULT2_EN			(1 << 25)
+#define ADF4350_REG2_MUXOUT(x)			((x) << 26)
+#define ADF4350_REG2_NOISE_MODE(x)		((x) << 29)
+#define ADF4350_MUXOUT_THREESTATE		0
+#define ADF4350_MUXOUT_DVDD			1
+#define ADF4350_MUXOUT_GND			2
+#define ADF4350_MUXOUT_R_DIV_OUT		3
+#define ADF4350_MUXOUT_N_DIV_OUT		4
+#define ADF4350_MUXOUT_ANALOG_LOCK_DETECT	5
+#define ADF4350_MUXOUT_DIGITAL_LOCK_DETECT	6
+
+/* REG3 Bit Definitions */
+#define ADF4350_REG3_12BIT_CLKDIV(x)		((x) << 3)
+#define ADF4350_REG3_12BIT_CLKDIV_MODE(x)	((x) << 16)
+#define ADF4350_REG3_12BIT_CSR_EN		(1 << 18)
+#define ADF4351_REG3_CHARGE_CANCELLATION_EN	(1 << 21)
+#define ADF4351_REG3_ANTI_BACKLASH_3ns_EN	(1 << 22)
+#define ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH	(1 << 23)
+
+/* REG4 Bit Definitions */
+#define ADF4350_REG4_OUTPUT_PWR(x)		((x) << 3)
+#define ADF4350_REG4_RF_OUT_EN			(1 << 5)
+#define ADF4350_REG4_AUX_OUTPUT_PWR(x)		((x) << 6)
+#define ADF4350_REG4_AUX_OUTPUT_EN		(1 << 8)
+#define ADF4350_REG4_AUX_OUTPUT_FUND		(1 << 9)
+#define ADF4350_REG4_AUX_OUTPUT_DIV		(0 << 9)
+#define ADF4350_REG4_MUTE_TILL_LOCK_EN		(1 << 10)
+#define ADF4350_REG4_VCO_PWRDOWN_EN		(1 << 11)
+#define ADF4350_REG4_8BIT_BAND_SEL_CLKDIV(x)	((x) << 12)
+#define ADF4350_REG4_RF_DIV_SEL(x)		((x) << 20)
+#define ADF4350_REG4_FEEDBACK_DIVIDED		(0 << 23)
+#define ADF4350_REG4_FEEDBACK_FUND		(1 << 23)
+
+/* REG5 Bit Definitions */
+#define ADF4350_REG5_LD_PIN_MODE_LOW		(0 << 22)
+#define ADF4350_REG5_LD_PIN_MODE_DIGITAL	(1 << 22)
+#define ADF4350_REG5_LD_PIN_MODE_HIGH		(3 << 22)
+
+/* Specifications */
+#define ADF4350_MAX_OUT_FREQ		4400000000ULL /* Hz */
+#define ADF4350_MIN_OUT_FREQ		137500000 /* Hz */
+#define ADF4351_MIN_OUT_FREQ		34375000 /* Hz */
+#define ADF4350_MIN_VCO_FREQ		2200000000ULL /* Hz */
+#define ADF4350_MAX_FREQ_45_PRESC	3000000000ULL /* Hz */
+#define ADF4350_MAX_FREQ_PFD		32000000 /* Hz */
+#define ADF4350_MAX_BANDSEL_CLK		125000 /* Hz */
+#define ADF4350_MAX_FREQ_REFIN		250000000 /* Hz */
+#define ADF4350_MAX_MODULUS		4095
+
+/**
+ * struct adf4350_platform_data - platform specific information
+ * @name:		Optional device name.
+ * @clkin:		REFin frequency in Hz.
+ * @channel_spacing:	Channel spacing in Hz (influences MODULUS).
+ * @power_up_frequency:	Optional, If set in Hz the PLL tunes to the desired
+ *			frequency on probe.
+ * @ref_div_factor:	Optional, if set the driver skips dynamic calculation
+ *			and uses this default value instead.
+ * @ref_doubler_en:	Enables reference doubler.
+ * @ref_div2_en:	Enables reference divider.
+ * @r2_user_settings:	User defined settings for ADF4350/1 REGISTER_2.
+ * @r3_user_settings:	User defined settings for ADF4350/1 REGISTER_3.
+ * @r4_user_settings:	User defined settings for ADF4350/1 REGISTER_4.
+ * @gpio_lock_detect:	Optional, if set with a valid GPIO number,
+ *			pll lock state is tested upon read.
+ *			If not used - set to -1.
+ */
+
+struct adf4350_platform_data {
+	char			name[32];
+	unsigned long		clkin;
+	unsigned long		channel_spacing;
+	unsigned long long	power_up_frequency;
+
+	unsigned short		ref_div_factor; /* 10-bit R counter */
+	bool			ref_doubler_en;
+	bool			ref_div2_en;
+
+	unsigned		r2_user_settings;
+	unsigned		r3_user_settings;
+	unsigned		r4_user_settings;
+	int			gpio_lock_detect;
+};
+
+#endif /* IIO_PLL_ADF4350_H_ */
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 3a4f6a3..2afbb6f 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -130,14 +130,78 @@ struct iio_chan_spec_ext_info {
 };
 
 /**
+ * struct iio_enum - Enum channel info attribute
+ * @items:	An array of strings.
+ * @num_items:	Length of the item array.
+ * @set:	Set callback function, may be NULL.
+ * @get:	Get callback function, may be NULL.
+ *
+ * The iio_enum struct can be used to implement enum style channel attributes.
+ * Enum style attributes are those which have a set of strings which map to
+ * unsigned integer values. The IIO enum helper code takes care of mapping
+ * between value and string as well as generating a "_available" file which
+ * contains a list of all available items. The set callback will be called when
+ * the attribute is updated. The last parameter is the index to the newly
+ * activated item. The get callback will be used to query the currently active
+ * item and is supposed to return the index for it.
+ */
+struct iio_enum {
+	const char * const *items;
+	unsigned int num_items;
+	int (*set)(struct iio_dev *, const struct iio_chan_spec *, unsigned int);
+	int (*get)(struct iio_dev *, const struct iio_chan_spec *);
+};
+
+ssize_t iio_enum_available_read(struct iio_dev *indio_dev,
+	uintptr_t priv, const struct iio_chan_spec *chan, char *buf);
+ssize_t iio_enum_read(struct iio_dev *indio_dev,
+	uintptr_t priv, const struct iio_chan_spec *chan, char *buf);
+ssize_t iio_enum_write(struct iio_dev *indio_dev,
+	uintptr_t priv, const struct iio_chan_spec *chan, const char *buf,
+	size_t len);
+
+/**
+ * IIO_ENUM() - Initialize enum extended channel attribute
+ * @_name:	Attribute name
+ * @_shared:	Whether the attribute is shared between all channels
+ * @_e:		Pointer to a iio_enum struct
+ *
+ * This should usually be used together with IIO_ENUM_AVAILABLE()
+ */
+#define IIO_ENUM(_name, _shared, _e) \
+{ \
+	.name = (_name), \
+	.shared = (_shared), \
+	.read = iio_enum_read, \
+	.write = iio_enum_write, \
+	.private = (uintptr_t)(_e), \
+}
+
+/**
+ * IIO_ENUM_AVAILABLE() - Initialize enum available extended channel attribute
+ * @_name:	Attribute name ("_available" will be appended to the name)
+ * @_e:		Pointer to a iio_enum struct
+ *
+ * Creates a read only attribute which list all the available enum items in a
+ * space separated list. This should usually be used together with IIO_ENUM()
+ */
+#define IIO_ENUM_AVAILABLE(_name, _e) \
+{ \
+	.name = (_name "_available"), \
+	.shared = true, \
+	.read = iio_enum_available_read, \
+	.private = (uintptr_t)(_e), \
+}
+
+/**
  * struct iio_chan_spec - specification of a single channel
  * @type:		What type of measurement is the channel making.
- * @channel:		What number or name do we wish to assign the channel.
+ * @channel:		What number do we wish to assign the channel.
  * @channel2:		If there is a second number for a differential
  *			channel then this is it. If modified is set then the
  *			value here specifies the modifier.
  * @address:		Driver specific identifier.
- * @scan_index:	Monotonic index to give ordering in scans when read
+ * @scan_index:		Monotonic index to give ordering in scans when read
  *			from a buffer.
  * @scan_type:		Sign:		's' or 'u' to specify signed or unsigned
  *			realbits:	Number of valid bits of data
@@ -147,14 +211,14 @@ struct iio_chan_spec_ext_info {
  *			endianness:	little or big endian
  * @info_mask:		What information is to be exported about this channel.
  *			This includes calibbias, scale etc.
- * @event_mask:	What events can this channel produce.
+ * @event_mask:		What events can this channel produce.
  * @ext_info:		Array of extended info attributes for this channel.
  *			The array is NULL terminated, the last element should
- *			have it's name field set to NULL.
+ *			have its name field set to NULL.
  * @extend_name:	Allows labeling of channel attributes with an
  *			informative name. Note this has no effect codes etc,
  *			unlike modifiers.
- * @datasheet_name:	A name used in in kernel mapping of channels. It should
+ * @datasheet_name:	A name used in in-kernel mapping of channels. It should
  *			correspond to the first name that the channel is referred
  *			to by in the datasheet (e.g. IND), or the nearest
  *			possible compound name (e.g. IND-INC).
@@ -163,9 +227,8 @@ struct iio_chan_spec_ext_info {
  *			channel2. Examples are IIO_MOD_X for axial sensors about
  *			the 'x' axis.
  * @indexed:		Specify the channel has a numerical index. If not,
- *			the value in channel will be suppressed for attribute
- *			but not for event codes. Typically set it to 0 when
- *			the index is false.
+ *			the channel index number will be suppressed for sysfs
+ *			attributes but not for event codes.
  * @differential:	Channel is differential.
  */
 struct iio_chan_spec {
@@ -329,7 +392,7 @@ struct iio_buffer_setup_ops {
  * @trig:		[INTERN] current device trigger (buffer modes)
  * @pollfunc:		[DRIVER] function run on trigger being received
  * @channels:		[DRIVER] channel specification structure table
- * @num_channels:	[DRIVER] number of chanels specified in @channels.
+ * @num_channels:	[DRIVER] number of channels specified in @channels.
  * @channel_attr_list:	[INTERN] keep track of automatically created channel
  *			attributes
  * @chan_attr_group:	[INTERN] group for all attrs in base directory
@@ -419,7 +482,7 @@ extern struct bus_type iio_bus_type;
 
 /**
  * iio_device_put() - reference counted deallocation of struct device
- * @dev: the iio_device containing the device
+ * @indio_dev: 		IIO device structure containing the device
  **/
 static inline void iio_device_put(struct iio_dev *indio_dev)
 {
@@ -429,7 +492,7 @@ static inline void iio_device_put(struct iio_dev *indio_dev)
 
 /**
  * dev_to_iio_dev() - Get IIO device struct from a device struct
- * @dev: The device embedded in the IIO device
+ * @dev: 		The device embedded in the IIO device
  *
  * Note: The device must be a IIO device, otherwise the result is undefined.
  */
@@ -438,11 +501,22 @@ static inline struct iio_dev *dev_to_iio_dev(struct device *dev)
 	return container_of(dev, struct iio_dev, dev);
 }
 
+/**
+ * iio_device_get() - increment reference count for the device
+ * @indio_dev: 		IIO device structure
+ *
+ * Returns: The passed IIO device
+ **/
+static inline struct iio_dev *iio_device_get(struct iio_dev *indio_dev)
+{
+	return indio_dev ? dev_to_iio_dev(get_device(&indio_dev->dev)) : NULL;
+}
+
 /* Can we make this smaller? */
 #define IIO_ALIGN L1_CACHE_BYTES
 /**
  * iio_device_alloc() - allocate an iio_dev from a driver
- * @sizeof_priv: Space to allocate for private structure.
+ * @sizeof_priv: 	Space to allocate for private structure.
  **/
 struct iio_dev *iio_device_alloc(int sizeof_priv);
 
@@ -459,13 +533,13 @@ static inline struct iio_dev *iio_priv_to_dev(void *priv)
 
 /**
  * iio_device_free() - free an iio_dev from a driver
- * @dev: the iio_dev associated with the device
+ * @indio_dev: 		the iio_dev associated with the device
  **/
 void iio_device_free(struct iio_dev *indio_dev);
 
 /**
  * iio_buffer_enabled() - helper function to test if the buffer is enabled
- * @indio_dev:		IIO device info structure for device
+ * @indio_dev:		IIO device structure for device
  **/
 static inline bool iio_buffer_enabled(struct iio_dev *indio_dev)
 {
@@ -475,7 +549,7 @@ static inline bool iio_buffer_enabled(struct iio_dev *indio_dev)
 
 /**
  * iio_get_debugfs_dentry() - helper function to get the debugfs_dentry
- * @indio_dev:		IIO device info structure for device
+ * @indio_dev:		IIO device structure for device
  **/
 #if defined(CONFIG_DEBUG_FS)
 static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
diff --git a/include/linux/iio/machine.h b/include/linux/iio/machine.h
index 0b1f19b..400a453 100644
--- a/include/linux/iio/machine.h
+++ b/include/linux/iio/machine.h
@@ -14,7 +14,7 @@
  *			This is matched against the datasheet_name element
  *			of struct iio_chan_spec.
  * @consumer_dev_name:	Name to uniquely identify the consumer device.
- * @consumer_channel:	Unique name used to idenitify the channel on the
+ * @consumer_channel:	Unique name used to identify the channel on the
  *			consumer side.
  */
 struct iio_map {
diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h
index bfedb73..b7a934b 100644
--- a/include/linux/iio/sysfs.h
+++ b/include/linux/iio/sysfs.h
@@ -97,7 +97,7 @@ struct iio_const_attr {
 #define IIO_DEV_ATTR_SAMP_FREQ_AVAIL(_show)				\
 	IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO, _show, NULL, 0)
 /**
- * IIO_CONST_ATTR_AVAIL_SAMP_FREQ - list available sampling frequencies
+ * IIO_CONST_ATTR_SAMP_FREQ_AVAIL - list available sampling frequencies
  * @_string: frequency string for the attribute
  *
  * Constant version
diff --git a/include/linux/iio/triggered_buffer.h b/include/linux/iio/triggered_buffer.h
new file mode 100644
index 0000000..c378ebe
--- /dev/null
+++ b/include/linux/iio/triggered_buffer.h
@@ -0,0 +1,15 @@
+#ifndef _LINUX_IIO_TRIGGERED_BUFFER_H_
+#define _LINUX_IIO_TRIGGERED_BUFFER_H_
+
+#include <linux/interrupt.h>
+
+struct iio_dev;
+struct iio_buffer_setup_ops;
+
+int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
+	irqreturn_t (*pollfunc_bh)(int irq, void *p),
+	irqreturn_t (*pollfunc_th)(int irq, void *p),
+	const struct iio_buffer_setup_ops *setup_ops);
+void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev);
+
+#endif
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
index 1b073b1..d086736 100644
--- a/include/linux/iio/types.h
+++ b/include/linux/iio/types.h
@@ -11,7 +11,6 @@
 #define _IIO_TYPES_H_
 
 enum iio_chan_type {
-	/* real channel types */
 	IIO_VOLTAGE,
 	IIO_CURRENT,
 	IIO_POWER,
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index 597f4a9..67f9dda 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -38,6 +38,7 @@ enum
 	IPV4_DEVCONF_ACCEPT_LOCAL,
 	IPV4_DEVCONF_SRC_VMARK,
 	IPV4_DEVCONF_PROXY_ARP_PVLAN,
+	IPV4_DEVCONF_ROUTE_LOCALNET,
 	__IPV4_DEVCONF_MAX
 };
 
@@ -131,6 +132,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
 #define IN_DEV_PROMOTE_SECONDARIES(in_dev) \
 					IN_DEV_ORCONF((in_dev), \
 						      PROMOTE_SECONDARIES)
+#define IN_DEV_ROUTE_LOCALNET(in_dev)	IN_DEV_ORCONF(in_dev, ROUTE_LOCALNET)
 
 #define IN_DEV_RX_REDIRECTS(in_dev) \
 	((IN_DEV_FORWARD(in_dev) && \
diff --git a/include/linux/init.h b/include/linux/init.h
index 6b95109..5e664f6 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -191,6 +191,7 @@ extern bool initcall_debug;
  * initializes variables that couldn't be statically initialized.
  *
  * This only exists for built-in code, not for modules.
+ * Keep main.c:initcall_level_names[] in sync.
  */
 #define pure_initcall(fn)		__define_initcall("0",fn,0)
 
@@ -280,7 +281,7 @@ void __init parse_early_options(char *cmdline);
 
 #else /* MODULE */
 
-/* Don't use these in modules, but some people do... */
+/* Don't use these in loadable modules, but some people do... */
 #define early_initcall(fn)		module_init(fn)
 #define core_initcall(fn)		module_init(fn)
 #define postcore_initcall(fn)		module_init(fn)
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 9e65eff..8bfae30 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -134,6 +134,13 @@ extern struct cred init_cred;
 
 #define INIT_TASK_COMM "swapper"
 
+#ifdef CONFIG_NUMA
+# define INIT_TASK_NUMA(tsk)						\
+	.node = -1,
+#else
+# define INIT_TASK_NUMA(tsk)
+#endif
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -168,8 +175,8 @@ extern struct cred init_cred;
 	.children	= LIST_HEAD_INIT(tsk.children),			\
 	.sibling	= LIST_HEAD_INIT(tsk.sibling),			\
 	.group_leader	= &tsk,						\
-	RCU_INIT_POINTER(.real_cred, &init_cred),			\
-	RCU_INIT_POINTER(.cred, &init_cred),				\
+	RCU_POINTER_INITIALIZER(real_cred, &init_cred),			\
+	RCU_POINTER_INITIALIZER(cred, &init_cred),			\
 	.comm		= INIT_TASK_COMM,				\
 	.thread		= INIT_THREAD,					\
 	.fs		= &init_fs,					\
@@ -200,6 +207,7 @@ extern struct cred init_cred;
 	INIT_TRACE_RECURSION						\
 	INIT_TASK_RCU_PREEMPT(tsk)					\
 	INIT_CPUSET_SEQ							\
+	INIT_TASK_NUMA(tsk)						\
 }
 
 
diff --git a/include/linux/input.h b/include/linux/input.h
index a816714..2740d08 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -116,6 +116,7 @@ struct input_keymap_entry {
 
 /**
  * EVIOCGMTSLOTS(len) - get MT slot values
+ * @len: size of the data buffer in bytes
  *
  * The ioctl buffer argument should be binary equivalent to
  *
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index e6ca56d..78e2ada 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -308,6 +308,8 @@ enum {
 
 struct intel_iommu {
 	void __iomem	*reg; /* Pointer to hardware regs, virtual addr */
+	u64 		reg_phys; /* physical address of hw register set */
+	u64		reg_size; /* size of hw register set */
 	u64		cap;
 	u64		ecap;
 	u32		gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 450293f..a71df92 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -26,6 +26,7 @@
 #define IOMMU_CACHE	(4) /* DMA cache coherency */
 
 struct iommu_ops;
+struct iommu_group;
 struct bus_type;
 struct device;
 struct iommu_domain;
@@ -60,6 +61,8 @@ struct iommu_domain {
  * @iova_to_phys: translate iova to physical address
  * @domain_has_cap: domain capabilities query
  * @commit: commit iommu domain
+ * @add_device: add device to iommu grouping
+ * @remove_device: remove device from iommu grouping
  * @pgsize_bitmap: bitmap of supported page sizes
  */
 struct iommu_ops {
@@ -75,10 +78,18 @@ struct iommu_ops {
 				    unsigned long iova);
 	int (*domain_has_cap)(struct iommu_domain *domain,
 			      unsigned long cap);
-	int (*device_group)(struct device *dev, unsigned int *groupid);
+	int (*add_device)(struct device *dev);
+	void (*remove_device)(struct device *dev);
 	unsigned long pgsize_bitmap;
 };
 
+#define IOMMU_GROUP_NOTIFY_ADD_DEVICE		1 /* Device added */
+#define IOMMU_GROUP_NOTIFY_DEL_DEVICE		2 /* Pre Device removed */
+#define IOMMU_GROUP_NOTIFY_BIND_DRIVER		3 /* Pre Driver bind */
+#define IOMMU_GROUP_NOTIFY_BOUND_DRIVER		4 /* Post Driver bind */
+#define IOMMU_GROUP_NOTIFY_UNBIND_DRIVER	5 /* Pre Driver unbind */
+#define IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER	6 /* Post Driver unbind */
+
 extern int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops);
 extern bool iommu_present(struct bus_type *bus);
 extern struct iommu_domain *iommu_domain_alloc(struct bus_type *bus);
@@ -97,7 +108,29 @@ extern int iommu_domain_has_cap(struct iommu_domain *domain,
 				unsigned long cap);
 extern void iommu_set_fault_handler(struct iommu_domain *domain,
 			iommu_fault_handler_t handler, void *token);
-extern int iommu_device_group(struct device *dev, unsigned int *groupid);
+
+extern int iommu_attach_group(struct iommu_domain *domain,
+			      struct iommu_group *group);
+extern void iommu_detach_group(struct iommu_domain *domain,
+			       struct iommu_group *group);
+extern struct iommu_group *iommu_group_alloc(void);
+extern void *iommu_group_get_iommudata(struct iommu_group *group);
+extern void iommu_group_set_iommudata(struct iommu_group *group,
+				      void *iommu_data,
+				      void (*release)(void *iommu_data));
+extern int iommu_group_set_name(struct iommu_group *group, const char *name);
+extern int iommu_group_add_device(struct iommu_group *group,
+				  struct device *dev);
+extern void iommu_group_remove_device(struct device *dev);
+extern int iommu_group_for_each_dev(struct iommu_group *group, void *data,
+				    int (*fn)(struct device *, void *));
+extern struct iommu_group *iommu_group_get(struct device *dev);
+extern void iommu_group_put(struct iommu_group *group);
+extern int iommu_group_register_notifier(struct iommu_group *group,
+					 struct notifier_block *nb);
+extern int iommu_group_unregister_notifier(struct iommu_group *group,
+					   struct notifier_block *nb);
+extern int iommu_group_id(struct iommu_group *group);
 
 /**
  * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework
@@ -142,6 +175,7 @@ static inline int report_iommu_fault(struct iommu_domain *domain,
 #else /* CONFIG_IOMMU_API */
 
 struct iommu_ops {};
+struct iommu_group {};
 
 static inline bool iommu_present(struct bus_type *bus)
 {
@@ -197,11 +231,75 @@ static inline void iommu_set_fault_handler(struct iommu_domain *domain,
 {
 }
 
-static inline int iommu_device_group(struct device *dev, unsigned int *groupid)
+int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group)
+{
+	return -ENODEV;
+}
+
+void iommu_detach_group(struct iommu_domain *domain, struct iommu_group *group)
+{
+}
+
+struct iommu_group *iommu_group_alloc(void)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+void *iommu_group_get_iommudata(struct iommu_group *group)
+{
+	return NULL;
+}
+
+void iommu_group_set_iommudata(struct iommu_group *group, void *iommu_data,
+			       void (*release)(void *iommu_data))
+{
+}
+
+int iommu_group_set_name(struct iommu_group *group, const char *name)
+{
+	return -ENODEV;
+}
+
+int iommu_group_add_device(struct iommu_group *group, struct device *dev)
+{
+	return -ENODEV;
+}
+
+void iommu_group_remove_device(struct device *dev)
+{
+}
+
+int iommu_group_for_each_dev(struct iommu_group *group, void *data,
+			     int (*fn)(struct device *, void *))
+{
+	return -ENODEV;
+}
+
+struct iommu_group *iommu_group_get(struct device *dev)
+{
+	return NULL;
+}
+
+void iommu_group_put(struct iommu_group *group)
+{
+}
+
+int iommu_group_register_notifier(struct iommu_group *group,
+				  struct notifier_block *nb)
 {
 	return -ENODEV;
 }
 
+int iommu_group_unregister_notifier(struct iommu_group *group,
+				    struct notifier_block *nb)
+{
+	return 0;
+}
+
+int iommu_group_id(struct iommu_group *group)
+{
+	return -ENODEV;
+}
 #endif /* CONFIG_IOMMU_API */
 
 #endif /* __LINUX_IOMMU_H */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 61f5cec..47a937c 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -150,9 +150,7 @@ struct irq_data {
 	void			*handler_data;
 	void			*chip_data;
 	struct msi_desc		*msi_desc;
-#ifdef CONFIG_SMP
 	cpumask_var_t		affinity;
-#endif
 };
 
 /*
diff --git a/include/linux/istallion.h b/include/linux/istallion.h
deleted file mode 100644
index ad700a6..0000000
--- a/include/linux/istallion.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	istallion.h  -- stallion intelligent multiport serial driver.
- *
- *	Copyright (C) 1996-1998  Stallion Technologies
- *	Copyright (C) 1994-1996  Greg Ungerer.
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You 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	_ISTALLION_H
-#define	_ISTALLION_H
-/*****************************************************************************/
-
-/*
- *	Define important driver constants here.
- */
-#define	STL_MAXBRDS		4
-#define	STL_MAXPANELS		4
-#define	STL_MAXPORTS		64
-#define	STL_MAXCHANS		(STL_MAXPORTS + 1)
-#define	STL_MAXDEVS		(STL_MAXBRDS * STL_MAXPORTS)
-
-
-/*
- *	Define a set of structures to hold all the board/panel/port info
- *	for our ports. These will be dynamically allocated as required at
- *	driver initialization time.
- */
-
-/*
- *	Port and board structures to hold status info about each object.
- *	The board structure contains pointers to structures for each port
- *	connected to it. Panels are not distinguished here, since
- *	communication with the slave board will always be on a per port
- *	basis.
- */
-struct stliport {
-	unsigned long		magic;
-	struct tty_port		port;
-	unsigned int		portnr;
-	unsigned int		panelnr;
-	unsigned int		brdnr;
-	unsigned long		state;
-	unsigned int		devnr;
-	int			baud_base;
-	int			custom_divisor;
-	int			closing_wait;
-	int			rc;
-	int			argsize;
-	void			*argp;
-	unsigned int		rxmarkmsk;
-	wait_queue_head_t	raw_wait;
-	struct asysigs		asig;
-	unsigned long		addr;
-	unsigned long		rxoffset;
-	unsigned long		txoffset;
-	unsigned long		sigs;
-	unsigned long		pflag;
-	unsigned int		rxsize;
-	unsigned int		txsize;
-	unsigned char		reqbit;
-	unsigned char		portidx;
-	unsigned char		portbit;
-};
-
-/*
- *	Use a structure of function pointers to do board level operations.
- *	These include, enable/disable, paging shared memory, interrupting, etc.
- */
-struct stlibrd {
-	unsigned long	magic;
-	unsigned int	brdnr;
-	unsigned int	brdtype;
-	unsigned long	state;
-	unsigned int	nrpanels;
-	unsigned int	nrports;
-	unsigned int	nrdevs;
-	unsigned int	iobase;
-	int		iosize;
-	unsigned long	memaddr;
-	void		__iomem *membase;
-	unsigned long	memsize;
-	int		pagesize;
-	int		hostoffset;
-	int		slaveoffset;
-	int		bitsize;
-	int		enabval;
-	unsigned int	panels[STL_MAXPANELS];
-	int		panelids[STL_MAXPANELS];
-	void		(*init)(struct stlibrd *brdp);
-	void		(*enable)(struct stlibrd *brdp);
-	void		(*reenable)(struct stlibrd *brdp);
-	void		(*disable)(struct stlibrd *brdp);
-	void		__iomem *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line);
-	void		(*intr)(struct stlibrd *brdp);
-	void		(*reset)(struct stlibrd *brdp);
-	struct stliport	*ports[STL_MAXPORTS];
-};
-
-
-/*
- *	Define MAGIC numbers used for above structures.
- */
-#define	STLI_PORTMAGIC	0xe671c7a1
-#define	STLI_BOARDMAGIC	0x4bc6c825
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h
index daf4a3a..af9137d 100644
--- a/include/linux/kbd_kern.h
+++ b/include/linux/kbd_kern.h
@@ -145,16 +145,4 @@ void compute_shiftstate(void);
 
 extern unsigned int keymap_count;
 
-/* console.c */
-
-static inline void con_schedule_flip(struct tty_struct *t)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&t->buf.lock, flags);
-	if (t->buf.tail != NULL)
-		t->buf.tail->commit = t->buf.tail->used;
-	spin_unlock_irqrestore(&t->buf.lock, flags);
-	schedule_work(&t->buf.work);
-}
-
 #endif
diff --git a/include/linux/kern_levels.h b/include/linux/kern_levels.h
new file mode 100644
index 0000000..866caaa
--- /dev/null
+++ b/include/linux/kern_levels.h
@@ -0,0 +1,25 @@
+#ifndef __KERN_LEVELS_H__
+#define __KERN_LEVELS_H__
+
+#define KERN_SOH	"\001"		/* ASCII Start Of Header */
+#define KERN_SOH_ASCII	'\001'
+
+#define KERN_EMERG	KERN_SOH "0"	/* system is unusable */
+#define KERN_ALERT	KERN_SOH "1"	/* action must be taken immediately */
+#define KERN_CRIT	KERN_SOH "2"	/* critical conditions */
+#define KERN_ERR	KERN_SOH "3"	/* error conditions */
+#define KERN_WARNING	KERN_SOH "4"	/* warning conditions */
+#define KERN_NOTICE	KERN_SOH "5"	/* normal but significant condition */
+#define KERN_INFO	KERN_SOH "6"	/* informational */
+#define KERN_DEBUG	KERN_SOH "7"	/* debug-level messages */
+
+#define KERN_DEFAULT	KERN_SOH "d"	/* the default kernel loglevel */
+
+/*
+ * Annotation for a "continued" line of log printout (only done after a
+ * line that had no enclosing \n). Only to be used by core/arch code
+ * during early bootup (a continued line is not SMP-safe otherwise).
+ */
+#define KERN_CONT	""
+
+#endif
diff --git a/include/linux/key.h b/include/linux/key.h
index 4cd22ed..cef3b31 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -303,7 +303,9 @@ static inline bool key_is_instantiated(const struct key *key)
 				   rwsem_is_locked(&((struct key *)(KEY))->sem)))
 
 #define rcu_assign_keypointer(KEY, PAYLOAD)				\
-	(rcu_assign_pointer((KEY)->payload.rcudata, PAYLOAD))
+do {									\
+	rcu_assign_pointer((KEY)->payload.rcudata, (PAYLOAD));		\
+} while (0)
 
 #ifdef CONFIG_SYSCTL
 extern ctl_table key_sysctls[];
diff --git a/include/linux/ks8851_mll.h b/include/linux/ks8851_mll.h
new file mode 100644
index 0000000..e9ccfb5
--- /dev/null
+++ b/include/linux/ks8851_mll.h
@@ -0,0 +1,33 @@
+/*
+ * ks8861_mll platform data struct definition
+ * Copyright (c) 2012 BTicino S.p.A.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LINUX_KS8851_MLL_H
+#define _LINUX_KS8851_MLL_H
+
+#include <linux/if_ether.h>
+
+/**
+ * struct ks8851_mll_platform_data - Platform data of the KS8851_MLL network driver
+ * @macaddr:	The MAC address of the device, set to all 0:s to use the on in
+ *		the chip.
+ */
+struct ks8851_mll_platform_data {
+	u8 mac_addr[ETH_ALEN];
+};
+
+#endif
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 09f2b3a..2ce09aa 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -617,6 +617,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_SIGNAL_MSI 77
 #define KVM_CAP_PPC_GET_SMMU_INFO 78
 #define KVM_CAP_S390_COW 79
+#define KVM_CAP_PPC_ALLOC_HTAB 80
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -828,6 +829,8 @@ struct kvm_s390_ucas_mapping {
 #define KVM_SIGNAL_MSI            _IOW(KVMIO,  0xa5, struct kvm_msi)
 /* Available with KVM_CAP_PPC_GET_SMMU_INFO */
 #define KVM_PPC_GET_SMMU_INFO	  _IOR(KVMIO,  0xa6, struct kvm_ppc_smmu_info)
+/* Available with KVM_CAP_PPC_ALLOC_HTAB */
+#define KVM_PPC_ALLOCATE_HTAB	  _IOWR(KVMIO, 0xa7, __u32)
 
 /*
  * ioctls for vcpu fds
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index c446435..27ac8a4 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -314,13 +314,19 @@ struct kvm {
 	long tlbs_dirty;
 };
 
-/* The guest did something we don't support. */
-#define pr_unimpl(vcpu, fmt, ...)					\
-	pr_err_ratelimited("kvm: %i: cpu%i " fmt,			\
-			   current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__)
+#define kvm_err(fmt, ...) \
+	pr_err("kvm [%i]: " fmt, task_pid_nr(current), ## __VA_ARGS__)
+#define kvm_info(fmt, ...) \
+	pr_info("kvm [%i]: " fmt, task_pid_nr(current), ## __VA_ARGS__)
+#define kvm_debug(fmt, ...) \
+	pr_debug("kvm [%i]: " fmt, task_pid_nr(current), ## __VA_ARGS__)
+#define kvm_pr_unimpl(fmt, ...) \
+	pr_err_ratelimited("kvm [%i]: " fmt, \
+			   task_tgid_nr(current), ## __VA_ARGS__)
 
-#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
-#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
+/* The guest did something we don't support. */
+#define vcpu_unimpl(vcpu, fmt, ...)					\
+	kvm_pr_unimpl("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__)
 
 static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
 {
@@ -535,6 +541,9 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu);
 
 void kvm_free_physmem(struct kvm *kvm);
 
+void *kvm_kvzalloc(unsigned long size);
+void kvm_kvfree(const void *addr);
+
 #ifndef __KVM_HAVE_ARCH_VM_ALLOC
 static inline struct kvm *kvm_arch_alloc_vm(void)
 {
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 39eee41..d503234 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -38,6 +38,9 @@ struct led_classdev {
 #define LED_SUSPENDED		(1 << 0)
 	/* Upper 16 bits reflect control information */
 #define LED_CORE_SUSPENDRESUME	(1 << 16)
+#define LED_BLINK_ONESHOT	(1 << 17)
+#define LED_BLINK_ONESHOT_STOP	(1 << 18)
+#define LED_BLINK_INVERT	(1 << 19)
 
 	/* Set LED brightness level */
 	/* Must not sleep, use a workqueue if needed */
@@ -103,7 +106,25 @@ extern void led_blink_set(struct led_classdev *led_cdev,
 			  unsigned long *delay_on,
 			  unsigned long *delay_off);
 /**
- * led_brightness_set - set LED brightness
+ * led_blink_set_oneshot - do a oneshot software blink
+ * @led_cdev: the LED to start blinking
+ * @delay_on: the time it should be on (in ms)
+ * @delay_off: the time it should ble off (in ms)
+ * @invert: blink off, then on, leaving the led on
+ *
+ * This function makes the LED blink one time for delay_on +
+ * delay_off time, ignoring the request if another one-shot
+ * blink is already in progress.
+ *
+ * If invert is set, led blinks for delay_off first, then for
+ * delay_on and leave the led on after the on-off cycle.
+ */
+extern void led_blink_set_oneshot(struct led_classdev *led_cdev,
+				  unsigned long *delay_on,
+				  unsigned long *delay_off,
+				  int invert);
+/**
+ * led_set_brightness - set LED brightness
  * @led_cdev: the LED to set
  * @brightness: the brightness to set it to
  *
@@ -111,7 +132,7 @@ extern void led_blink_set(struct led_classdev *led_cdev,
  * software blink timer that implements blinking when the
  * hardware doesn't.
  */
-extern void led_brightness_set(struct led_classdev *led_cdev,
+extern void led_set_brightness(struct led_classdev *led_cdev,
 			       enum led_brightness brightness);
 
 /*
@@ -150,6 +171,10 @@ extern void led_trigger_event(struct led_trigger *trigger,
 extern void led_trigger_blink(struct led_trigger *trigger,
 			      unsigned long *delay_on,
 			      unsigned long *delay_off);
+extern void led_trigger_blink_oneshot(struct led_trigger *trigger,
+				      unsigned long *delay_on,
+				      unsigned long *delay_off,
+				      int invert);
 
 #else
 
@@ -212,4 +237,20 @@ struct gpio_led_platform_data {
 struct platform_device *gpio_led_register_device(
 		int id, const struct gpio_led_platform_data *pdata);
 
+enum cpu_led_event {
+	CPU_LED_IDLE_START,	/* CPU enters idle */
+	CPU_LED_IDLE_END,	/* CPU idle ends */
+	CPU_LED_START,		/* Machine starts, especially resume */
+	CPU_LED_STOP,		/* Machine stops, especially suspend */
+	CPU_LED_HALTED,		/* Machine shutdown */
+};
+#if defined(CONFIG_LEDS_TRIGGER_CPU) || defined(CONFIG_LEDS_TRIGGER_CPU_MODULE)
+extern void ledtrig_cpu(enum cpu_led_event evt);
+#else
+static inline void ledtrig_cpu(enum cpu_led_event evt)
+{
+	return;
+}
+#endif
+
 #endif		/* __LINUX_LEDS_H_INCLUDED */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 6e887c7..af467d3 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -182,6 +182,7 @@ enum {
 	ATA_LFLAG_DISABLED	= (1 << 6), /* link is disabled */
 	ATA_LFLAG_SW_ACTIVITY	= (1 << 7), /* keep activity stats */
 	ATA_LFLAG_NO_LPM	= (1 << 8), /* disable LPM on this link */
+	ATA_LFLAG_RST_ONCE	= (1 << 9), /* limit recovery to one reset */
 
 	/* struct ata_port flags */
 	ATA_FLAG_SLAVE_POSS	= (1 << 0), /* host supports slave dev */
@@ -846,6 +847,8 @@ struct ata_port_operations {
 	void (*error_handler)(struct ata_port *ap);
 	void (*lost_interrupt)(struct ata_port *ap);
 	void (*post_internal_cmd)(struct ata_queued_cmd *qc);
+	void (*sched_eh)(struct ata_port *ap);
+	void (*end_eh)(struct ata_port *ap);
 
 	/*
 	 * Optional features
@@ -1013,6 +1016,17 @@ extern bool ata_link_offline(struct ata_link *link);
 #ifdef CONFIG_PM
 extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
 extern void ata_host_resume(struct ata_host *host);
+extern int ata_sas_port_async_suspend(struct ata_port *ap, int *async);
+extern int ata_sas_port_async_resume(struct ata_port *ap, int *async);
+#else
+static inline int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+{
+	return 0;
+}
+static inline int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+{
+	return 0;
+}
 #endif
 extern int ata_ratelimit(void);
 extern void ata_msleep(struct ata_port *ap, unsigned int msecs);
@@ -1167,6 +1181,8 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
 		      ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 		      ata_postreset_fn_t postreset);
 extern void ata_std_error_handler(struct ata_port *ap);
+extern void ata_std_sched_eh(struct ata_port *ap);
+extern void ata_std_end_eh(struct ata_port *ap);
 extern int ata_link_nr_enabled(struct ata_link *link);
 
 /*
diff --git a/include/linux/libfdt.h b/include/linux/libfdt.h
new file mode 100644
index 0000000..4c0306c
--- /dev/null
+++ b/include/linux/libfdt.h
@@ -0,0 +1,8 @@
+#ifndef _INCLUDE_LIBFDT_H_
+#define _INCLUDE_LIBFDT_H_
+
+#include <linux/libfdt_env.h>
+#include "../../scripts/dtc/libfdt/fdt.h"
+#include "../../scripts/dtc/libfdt/libfdt.h"
+
+#endif /* _INCLUDE_LIBFDT_H_ */
diff --git a/include/linux/libfdt_env.h b/include/linux/libfdt_env.h
new file mode 100644
index 0000000..01508c7
--- /dev/null
+++ b/include/linux/libfdt_env.h
@@ -0,0 +1,13 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include <linux/string.h>
+
+#include <asm/byteorder.h>
+
+#define fdt32_to_cpu(x) be32_to_cpu(x)
+#define cpu_to_fdt32(x) cpu_to_be32(x)
+#define fdt64_to_cpu(x) be64_to_cpu(x)
+#define cpu_to_fdt64(x) cpu_to_be64(x)
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index 4aa4273..e407ed1 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -20,6 +20,8 @@ enum {
 	MPOL_PREFERRED,
 	MPOL_BIND,
 	MPOL_INTERLEAVE,
+	MPOL_LOCAL,
+	MPOL_NOOP,		/* retain existing policy for range */
 	MPOL_MAX,	/* always last member of enum */
 };
 
@@ -47,9 +49,16 @@ enum mpol_rebind_step {
 
 /* Flags for mbind */
 #define MPOL_MF_STRICT	(1<<0)	/* Verify existing pages in the mapping */
-#define MPOL_MF_MOVE	(1<<1)	/* Move pages owned by this process to conform to mapping */
-#define MPOL_MF_MOVE_ALL (1<<2)	/* Move every page to conform to mapping */
-#define MPOL_MF_INTERNAL (1<<3)	/* Internal flags start here */
+#define MPOL_MF_MOVE	 (1<<1)	/* Move pages owned by this process to conform
+				   to policy */
+#define MPOL_MF_MOVE_ALL (1<<2)	/* Move every page to conform to policy */
+#define MPOL_MF_LAZY	 (1<<3)	/* Modifies '_MOVE:  lazy migrate on fault */
+#define MPOL_MF_INTERNAL (1<<4)	/* Internal flags start here */
+
+#define MPOL_MF_VALID	(MPOL_MF_STRICT   | 	\
+			 MPOL_MF_MOVE     | 	\
+			 MPOL_MF_MOVE_ALL |	\
+			 MPOL_MF_LAZY)
 
 /*
  * Internal flags that share the struct mempolicy flags word with
@@ -59,6 +68,7 @@ enum mpol_rebind_step {
 #define MPOL_F_SHARED  (1 << 0)	/* identify shared policies */
 #define MPOL_F_LOCAL   (1 << 1)	/* preferred local allocation */
 #define MPOL_F_REBINDING (1 << 2)	/* identify policies in rebinding */
+#define MPOL_F_MOF	(1 << 3) /* this policy wants migrate on fault */
 
 #ifdef __KERNEL__
 
@@ -68,6 +78,7 @@ enum mpol_rebind_step {
 #include <linux/spinlock.h>
 #include <linux/nodemask.h>
 #include <linux/pagemap.h>
+#include <linux/migrate.h>
 
 struct mm_struct;
 
@@ -158,6 +169,9 @@ static inline struct mempolicy *mpol_dup(struct mempolicy *pol)
 #define vma_policy(vma) ((vma)->vm_policy)
 #define vma_set_policy(vma, pol) ((vma)->vm_policy = (pol))
 
+extern int vma_dup_policy(struct vm_area_struct *new, struct vm_area_struct *old);
+extern void vma_put_policy(struct vm_area_struct *vma);
+
 static inline void mpol_get(struct mempolicy *pol)
 {
 	if (pol)
@@ -191,6 +205,12 @@ struct shared_policy {
 	spinlock_t lock;
 };
 
+extern struct mempolicy *mpol_new(unsigned short mode, unsigned short flags,
+				  nodemask_t *nodes);
+extern long mpol_do_mbind(unsigned long start, unsigned long len,
+				struct mempolicy *policy, unsigned long mode,
+				nodemask_t *nmask, unsigned long flags);
+
 void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol);
 int mpol_set_shared_policy(struct shared_policy *info,
 				struct vm_area_struct *vma,
@@ -204,6 +224,8 @@ struct mempolicy *get_vma_policy(struct task_struct *tsk,
 
 extern void numa_default_policy(void);
 extern void numa_policy_init(void);
+extern void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *new,
+				enum mpol_rebind_step step);
 extern void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new,
 				enum mpol_rebind_step step);
 extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
@@ -215,7 +237,7 @@ extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
 extern bool init_nodemask_of_mempolicy(nodemask_t *mask);
 extern bool mempolicy_nodemask_intersects(struct task_struct *tsk,
 				const nodemask_t *mask);
-extern unsigned slab_node(struct mempolicy *policy);
+extern unsigned slab_node(void);
 
 extern enum zone_type policy_zone;
 
@@ -236,22 +258,12 @@ extern int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context);
 extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol,
 			int no_context);
 
-/* Check if a vma is migratable */
-static inline int vma_migratable(struct vm_area_struct *vma)
-{
-	if (vma->vm_flags & (VM_IO|VM_HUGETLB|VM_PFNMAP|VM_RESERVED))
-		return 0;
-	/*
-	 * Migration allocates pages in the highest zone. If we cannot
-	 * do so then migration (at least from node to node) is not
-	 * possible.
-	 */
-	if (vma->vm_file &&
-		gfp_zone(mapping_gfp_mask(vma->vm_file->f_mapping))
-								< policy_zone)
-			return 0;
-	return 1;
-}
+extern int vma_migratable(struct vm_area_struct *);
+
+extern int mpol_misplaced(struct page *, struct vm_area_struct *, unsigned long);
+
+extern void lazy_migrate_vma(struct vm_area_struct *vma, int node);
+extern void lazy_migrate_process(struct mm_struct *mm, int node);
 
 #else
 
@@ -311,6 +323,11 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx)
 
 #define vma_policy(vma) NULL
 #define vma_set_policy(vma, pol) do {} while(0)
+#define vma_dup_policy(new, old) (0)
+
+static inline void vma_put_policy(struct vm_area_struct *vma)
+{
+}
 
 static inline void numa_policy_init(void)
 {
diff --git a/include/linux/mfd/abx500/ab8500-codec.h b/include/linux/mfd/abx500/ab8500-codec.h
new file mode 100644
index 0000000..dc65292
--- /dev/null
+++ b/include/linux/mfd/abx500/ab8500-codec.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can 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 AB8500_CORE_CODEC_H
+#define AB8500_CORE_CODEC_H
+
+/* Mic-types */
+enum amic_type {
+	AMIC_TYPE_SINGLE_ENDED,
+	AMIC_TYPE_DIFFERENTIAL
+};
+
+/* Mic-biases */
+enum amic_micbias {
+	AMIC_MICBIAS_VAMIC1,
+	AMIC_MICBIAS_VAMIC2
+};
+
+/* Bias-voltage */
+enum ear_cm_voltage {
+	EAR_CMV_0_95V,
+	EAR_CMV_1_10V,
+	EAR_CMV_1_27V,
+	EAR_CMV_1_58V
+};
+
+/* Analog microphone settings */
+struct amic_settings {
+	enum amic_type mic1_type;
+	enum amic_type mic2_type;
+	enum amic_micbias mic1a_micbias;
+	enum amic_micbias mic1b_micbias;
+	enum amic_micbias mic2_micbias;
+};
+
+/* Platform data structure for the audio-parts of the AB8500 */
+struct ab8500_codec_platform_data {
+	struct amic_settings amics;
+	enum ear_cm_voltage ear_cmv;
+};
+
+#endif
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 91dd3ef..bc9b84b 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -266,6 +266,7 @@ struct ab8500 {
 struct regulator_reg_init;
 struct regulator_init_data;
 struct ab8500_gpio_platform_data;
+struct ab8500_codec_platform_data;
 
 /**
  * struct ab8500_platform_data - AB8500 platform data
@@ -284,6 +285,7 @@ struct ab8500_platform_data {
 	int num_regulator;
 	struct regulator_init_data *regulator;
 	struct ab8500_gpio_platform_data *gpio;
+	struct ab8500_codec_platform_data *codec;
 };
 
 extern int __devinit ab8500_init(struct ab8500 *ab8500,
diff --git a/include/linux/mfd/max77686-private.h b/include/linux/mfd/max77686-private.h
new file mode 100644
index 0000000..962f65e
--- /dev/null
+++ b/include/linux/mfd/max77686-private.h
@@ -0,0 +1,247 @@
+/*
+ * max77686.h - Voltage regulator driver for the Maxim 77686
+ *
+ *  Copyright (C) 2012 Samsung Electrnoics
+ *  Chiwoong Byun <woong.byun@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LINUX_MFD_MAX77686_PRIV_H
+#define __LINUX_MFD_MAX77686_PRIV_H
+
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+
+#define MAX77686_REG_INVALID		(0xff)
+
+enum max77686_pmic_reg {
+	MAX77686_REG_DEVICE_ID		= 0x00,
+	MAX77686_REG_INTSRC		= 0x01,
+	MAX77686_REG_INT1		= 0x02,
+	MAX77686_REG_INT2		= 0x03,
+
+	MAX77686_REG_INT1MSK		= 0x04,
+	MAX77686_REG_INT2MSK		= 0x05,
+
+	MAX77686_REG_STATUS1		= 0x06,
+	MAX77686_REG_STATUS2		= 0x07,
+
+	MAX77686_REG_PWRON		= 0x08,
+	MAX77686_REG_ONOFF_DELAY	= 0x09,
+	MAX77686_REG_MRSTB		= 0x0A,
+	/* Reserved: 0x0B-0x0F */
+
+	MAX77686_REG_BUCK1CTRL		= 0x10,
+	MAX77686_REG_BUCK1OUT		= 0x11,
+	MAX77686_REG_BUCK2CTRL1		= 0x12,
+	MAX77686_REG_BUCK234FREQ	= 0x13,
+	MAX77686_REG_BUCK2DVS1		= 0x14,
+	MAX77686_REG_BUCK2DVS2		= 0x15,
+	MAX77686_REG_BUCK2DVS3		= 0x16,
+	MAX77686_REG_BUCK2DVS4		= 0x17,
+	MAX77686_REG_BUCK2DVS5		= 0x18,
+	MAX77686_REG_BUCK2DVS6		= 0x19,
+	MAX77686_REG_BUCK2DVS7		= 0x1A,
+	MAX77686_REG_BUCK2DVS8		= 0x1B,
+	MAX77686_REG_BUCK3CTRL1		= 0x1C,
+	/* Reserved: 0x1D */
+	MAX77686_REG_BUCK3DVS1		= 0x1E,
+	MAX77686_REG_BUCK3DVS2		= 0x1F,
+	MAX77686_REG_BUCK3DVS3		= 0x20,
+	MAX77686_REG_BUCK3DVS4		= 0x21,
+	MAX77686_REG_BUCK3DVS5		= 0x22,
+	MAX77686_REG_BUCK3DVS6		= 0x23,
+	MAX77686_REG_BUCK3DVS7		= 0x24,
+	MAX77686_REG_BUCK3DVS8		= 0x25,
+	MAX77686_REG_BUCK4CTRL1		= 0x26,
+	/* Reserved: 0x27 */
+	MAX77686_REG_BUCK4DVS1		= 0x28,
+	MAX77686_REG_BUCK4DVS2		= 0x29,
+	MAX77686_REG_BUCK4DVS3		= 0x2A,
+	MAX77686_REG_BUCK4DVS4		= 0x2B,
+	MAX77686_REG_BUCK4DVS5		= 0x2C,
+	MAX77686_REG_BUCK4DVS6		= 0x2D,
+	MAX77686_REG_BUCK4DVS7		= 0x2E,
+	MAX77686_REG_BUCK4DVS8		= 0x2F,
+	MAX77686_REG_BUCK5CTRL		= 0x30,
+	MAX77686_REG_BUCK5OUT		= 0x31,
+	MAX77686_REG_BUCK6CTRL		= 0x32,
+	MAX77686_REG_BUCK6OUT		= 0x33,
+	MAX77686_REG_BUCK7CTRL		= 0x34,
+	MAX77686_REG_BUCK7OUT		= 0x35,
+	MAX77686_REG_BUCK8CTRL		= 0x36,
+	MAX77686_REG_BUCK8OUT		= 0x37,
+	MAX77686_REG_BUCK9CTRL		= 0x38,
+	MAX77686_REG_BUCK9OUT		= 0x39,
+	/* Reserved: 0x3A-0x3F */
+
+	MAX77686_REG_LDO1CTRL1		= 0x40,
+	MAX77686_REG_LDO2CTRL1		= 0x41,
+	MAX77686_REG_LDO3CTRL1		= 0x42,
+	MAX77686_REG_LDO4CTRL1		= 0x43,
+	MAX77686_REG_LDO5CTRL1		= 0x44,
+	MAX77686_REG_LDO6CTRL1		= 0x45,
+	MAX77686_REG_LDO7CTRL1		= 0x46,
+	MAX77686_REG_LDO8CTRL1		= 0x47,
+	MAX77686_REG_LDO9CTRL1		= 0x48,
+	MAX77686_REG_LDO10CTRL1		= 0x49,
+	MAX77686_REG_LDO11CTRL1		= 0x4A,
+	MAX77686_REG_LDO12CTRL1		= 0x4B,
+	MAX77686_REG_LDO13CTRL1		= 0x4C,
+	MAX77686_REG_LDO14CTRL1		= 0x4D,
+	MAX77686_REG_LDO15CTRL1		= 0x4E,
+	MAX77686_REG_LDO16CTRL1		= 0x4F,
+	MAX77686_REG_LDO17CTRL1		= 0x50,
+	MAX77686_REG_LDO18CTRL1		= 0x51,
+	MAX77686_REG_LDO19CTRL1		= 0x52,
+	MAX77686_REG_LDO20CTRL1		= 0x53,
+	MAX77686_REG_LDO21CTRL1		= 0x54,
+	MAX77686_REG_LDO22CTRL1		= 0x55,
+	MAX77686_REG_LDO23CTRL1		= 0x56,
+	MAX77686_REG_LDO24CTRL1		= 0x57,
+	MAX77686_REG_LDO25CTRL1		= 0x58,
+	MAX77686_REG_LDO26CTRL1		= 0x59,
+	/* Reserved: 0x5A-0x5F */
+	MAX77686_REG_LDO1CTRL2		= 0x60,
+	MAX77686_REG_LDO2CTRL2		= 0x61,
+	MAX77686_REG_LDO3CTRL2		= 0x62,
+	MAX77686_REG_LDO4CTRL2		= 0x63,
+	MAX77686_REG_LDO5CTRL2		= 0x64,
+	MAX77686_REG_LDO6CTRL2		= 0x65,
+	MAX77686_REG_LDO7CTRL2		= 0x66,
+	MAX77686_REG_LDO8CTRL2		= 0x67,
+	MAX77686_REG_LDO9CTRL2		= 0x68,
+	MAX77686_REG_LDO10CTRL2		= 0x69,
+	MAX77686_REG_LDO11CTRL2		= 0x6A,
+	MAX77686_REG_LDO12CTRL2		= 0x6B,
+	MAX77686_REG_LDO13CTRL2		= 0x6C,
+	MAX77686_REG_LDO14CTRL2		= 0x6D,
+	MAX77686_REG_LDO15CTRL2		= 0x6E,
+	MAX77686_REG_LDO16CTRL2		= 0x6F,
+	MAX77686_REG_LDO17CTRL2		= 0x70,
+	MAX77686_REG_LDO18CTRL2		= 0x71,
+	MAX77686_REG_LDO19CTRL2		= 0x72,
+	MAX77686_REG_LDO20CTRL2		= 0x73,
+	MAX77686_REG_LDO21CTRL2		= 0x74,
+	MAX77686_REG_LDO22CTRL2		= 0x75,
+	MAX77686_REG_LDO23CTRL2		= 0x76,
+	MAX77686_REG_LDO24CTRL2		= 0x77,
+	MAX77686_REG_LDO25CTRL2		= 0x78,
+	MAX77686_REG_LDO26CTRL2		= 0x79,
+	/* Reserved: 0x7A-0x7D */
+
+	MAX77686_REG_BBAT_CHG		= 0x7E,
+	MAX77686_REG_32KHZ			= 0x7F,
+
+	MAX77686_REG_PMIC_END		= 0x80,
+};
+
+enum max77686_rtc_reg {
+	MAX77686_RTC_INT			= 0x00,
+	MAX77686_RTC_INTM			= 0x01,
+	MAX77686_RTC_CONTROLM		= 0x02,
+	MAX77686_RTC_CONTROL		= 0x03,
+	MAX77686_RTC_UPDATE0		= 0x04,
+	/* Reserved: 0x5 */
+	MAX77686_WTSR_SMPL_CNTL		= 0x06,
+	MAX77686_RTC_SEC			= 0x07,
+	MAX77686_RTC_MIN			= 0x08,
+	MAX77686_RTC_HOUR			= 0x09,
+	MAX77686_RTC_WEEKDAY		= 0x0A,
+	MAX77686_RTC_MONTH			= 0x0B,
+	MAX77686_RTC_YEAR			= 0x0C,
+	MAX77686_RTC_DATE			= 0x0D,
+	MAX77686_ALARM1_SEC			= 0x0E,
+	MAX77686_ALARM1_MIN			= 0x0F,
+	MAX77686_ALARM1_HOUR		= 0x10,
+	MAX77686_ALARM1_WEEKDAY		= 0x11,
+	MAX77686_ALARM1_MONTH		= 0x12,
+	MAX77686_ALARM1_YEAR		= 0x13,
+	MAX77686_ALARM1_DATE		= 0x14,
+	MAX77686_ALARM2_SEC			= 0x15,
+	MAX77686_ALARM2_MIN			= 0x16,
+	MAX77686_ALARM2_HOUR		= 0x17,
+	MAX77686_ALARM2_WEEKDAY		= 0x18,
+	MAX77686_ALARM2_MONTH		= 0x19,
+	MAX77686_ALARM2_YEAR		= 0x1A,
+	MAX77686_ALARM2_DATE		= 0x1B,
+};
+
+#define MAX77686_IRQSRC_PMIC	(0)
+#define MAX77686_IRQSRC_RTC		(1 << 0)
+
+enum max77686_irq_source {
+	PMIC_INT1 = 0,
+	PMIC_INT2,
+	RTC_INT,
+
+	MAX77686_IRQ_GROUP_NR,
+};
+
+enum max77686_irq {
+	MAX77686_PMICIRQ_PWRONF,
+	MAX77686_PMICIRQ_PWRONR,
+	MAX77686_PMICIRQ_JIGONBF,
+	MAX77686_PMICIRQ_JIGONBR,
+	MAX77686_PMICIRQ_ACOKBF,
+	MAX77686_PMICIRQ_ACOKBR,
+	MAX77686_PMICIRQ_ONKEY1S,
+	MAX77686_PMICIRQ_MRSTB,
+
+	MAX77686_PMICIRQ_140C,
+	MAX77686_PMICIRQ_120C,
+
+	MAX77686_RTCIRQ_RTC60S,
+	MAX77686_RTCIRQ_RTCA1,
+	MAX77686_RTCIRQ_RTCA2,
+	MAX77686_RTCIRQ_SMPL,
+	MAX77686_RTCIRQ_RTC1S,
+	MAX77686_RTCIRQ_WTSR,
+
+	MAX77686_IRQ_NR,
+};
+
+struct max77686_dev {
+	struct device *dev;
+	struct i2c_client *i2c; /* 0xcc / PMIC, Battery Control, and FLASH */
+	struct i2c_client *rtc; /* slave addr 0x0c */
+	struct mutex iolock;
+
+	int type;
+
+	struct regmap *regmap;		/* regmap for mfd */
+	struct regmap *rtc_regmap;	/* regmap for rtc */
+
+	struct irq_domain *irq_domain;
+
+	int irq;
+	int irq_gpio;
+	bool wakeup;
+	struct mutex irqlock;
+	int irq_masks_cur[MAX77686_IRQ_GROUP_NR];
+	int irq_masks_cache[MAX77686_IRQ_GROUP_NR];
+};
+
+enum max77686_types {
+	TYPE_MAX77686,
+};
+
+extern int max77686_irq_init(struct max77686_dev *max77686);
+extern void max77686_irq_exit(struct max77686_dev *max77686);
+extern int max77686_irq_resume(struct max77686_dev *max77686);
+
+#endif /*  __LINUX_MFD_MAX77686_PRIV_H */
diff --git a/include/linux/mfd/max77686.h b/include/linux/mfd/max77686.h
new file mode 100644
index 0000000..fcf3126
--- /dev/null
+++ b/include/linux/mfd/max77686.h
@@ -0,0 +1,117 @@
+/*
+ * max77686.h - Driver for the Maxim 77686
+ *
+ *  Copyright (C) 2012 Samsung Electrnoics
+ *  Chiwoong Byun <woong.byun@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8997.h
+ *
+ * MAX77686 has PMIC, RTC devices.
+ * The devices share the same I2C bus and included in
+ * this mfd driver.
+ */
+
+#ifndef __LINUX_MFD_MAX77686_H
+#define __LINUX_MFD_MAX77686_H
+
+#include <linux/regulator/consumer.h>
+
+/* MAX77686 regulator IDs */
+enum max77686_regulators {
+	MAX77686_LDO1 = 0,
+	MAX77686_LDO2,
+	MAX77686_LDO3,
+	MAX77686_LDO4,
+	MAX77686_LDO5,
+	MAX77686_LDO6,
+	MAX77686_LDO7,
+	MAX77686_LDO8,
+	MAX77686_LDO9,
+	MAX77686_LDO10,
+	MAX77686_LDO11,
+	MAX77686_LDO12,
+	MAX77686_LDO13,
+	MAX77686_LDO14,
+	MAX77686_LDO15,
+	MAX77686_LDO16,
+	MAX77686_LDO17,
+	MAX77686_LDO18,
+	MAX77686_LDO19,
+	MAX77686_LDO20,
+	MAX77686_LDO21,
+	MAX77686_LDO22,
+	MAX77686_LDO23,
+	MAX77686_LDO24,
+	MAX77686_LDO25,
+	MAX77686_LDO26,
+	MAX77686_BUCK1,
+	MAX77686_BUCK2,
+	MAX77686_BUCK3,
+	MAX77686_BUCK4,
+	MAX77686_BUCK5,
+	MAX77686_BUCK6,
+	MAX77686_BUCK7,
+	MAX77686_BUCK8,
+	MAX77686_BUCK9,
+	MAX77686_EN32KHZ_AP,
+	MAX77686_EN32KHZ_CP,
+	MAX77686_P32KH,
+
+	MAX77686_REG_MAX,
+};
+
+struct max77686_regulator_data {
+	int id;
+	struct regulator_init_data *initdata;
+};
+
+enum max77686_opmode {
+	MAX77686_OPMODE_NORMAL,
+	MAX77686_OPMODE_LP,
+	MAX77686_OPMODE_STANDBY,
+};
+
+struct max77686_opmode_data {
+	int id;
+	int mode;
+};
+
+struct max77686_platform_data {
+	/* IRQ */
+	int irq_gpio;
+	int ono;
+	int wakeup;
+
+	/* ---- PMIC ---- */
+	struct max77686_regulator_data *regulators;
+	int num_regulators;
+
+	struct max77686_opmode_data *opmode_data;
+
+	/*
+	 * GPIO-DVS feature is not enabled with the current version of
+	 * MAX77686 driver. Buck2/3/4_voltages[0] is used as the default
+	 * voltage at probe. DVS/SELB gpios are set as OUTPUT-LOW.
+	 */
+	int buck234_gpio_dvs[3]; /* GPIO of [0]DVS1, [1]DVS2, [2]DVS3 */
+	int buck234_gpio_selb[3]; /* [0]SELB2, [1]SELB3, [2]SELB4 */
+	unsigned int buck2_voltage[8]; /* buckx_voltage in uV */
+	unsigned int buck3_voltage[8];
+	unsigned int buck4_voltage[8];
+};
+
+#endif /* __LINUX_MFD_MAX77686_H */
diff --git a/include/linux/mfd/s5m87xx/s5m-core.h b/include/linux/mfd/s5m87xx/s5m-core.h
index 21603b4..0b2e0ed 100644
--- a/include/linux/mfd/s5m87xx/s5m-core.h
+++ b/include/linux/mfd/s5m87xx/s5m-core.h
@@ -347,6 +347,7 @@ struct s5m_platform_data {
 	bool				buck_voltage_lock;
 
 	int				buck_gpios[3];
+	int				buck_ds[3];
 	int				buck2_voltage[8];
 	bool				buck2_gpiodvs;
 	int				buck3_voltage[8];
@@ -369,6 +370,10 @@ struct s5m_platform_data {
 	bool                            buck2_ramp_enable;
 	bool                            buck3_ramp_enable;
 	bool                            buck4_ramp_enable;
+
+	int				buck2_init;
+	int				buck3_init;
+	int				buck4_init;
 };
 
 #endif /*  __LINUX_MFD_S5M_CORE_H */
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
index f5171db..b332c4c 100644
--- a/include/linux/mfd/tmio.h
+++ b/include/linux/mfd/tmio.h
@@ -110,6 +110,9 @@ struct tmio_mmc_data {
 	void (*set_clk_div)(struct platform_device *host, int state);
 	int (*get_cd)(struct platform_device *host);
 	int (*write16_hook)(struct tmio_mmc_host *host, int addr);
+	/* clock management callbacks */
+	int (*clk_enable)(struct platform_device *pdev, unsigned int *f);
+	void (*clk_disable)(struct platform_device *pdev);
 };
 
 /*
diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
index e030ef9..4e035a4 100644
--- a/include/linux/mfd/tps65217.h
+++ b/include/linux/mfd/tps65217.h
@@ -229,9 +229,6 @@ struct tps65217_board {
  * @uv_to_vsel:		Function pointer to get selector from voltage
  * @table:		Table for non-uniform voltage step-size
  * @table_len:		Length of the voltage table
- * @enable_mask:	Regulator enable mask bits
- * @set_vout_reg:	Regulator output voltage set register
- * @set_vout_mask:	Regulator output voltage set mask
  *
  * This data is used to check the regualtor voltage limits while setting.
  */
@@ -243,9 +240,6 @@ struct tps_info {
 	int (*uv_to_vsel)(int uV, unsigned int *vsel);
 	const int *table;
 	unsigned int table_len;
-	unsigned int enable_mask;
-	unsigned int set_vout_reg;
-	unsigned int set_vout_mask;
 };
 
 /**
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 855c337..027d552 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -15,7 +15,7 @@ extern int migrate_page(struct address_space *,
 extern int migrate_pages(struct list_head *l, new_page_t x,
 			unsigned long private, bool offlining,
 			enum migrate_mode mode);
-extern int migrate_huge_pages(struct list_head *l, new_page_t x,
+extern int migrate_huge_page(struct page *, new_page_t x,
 			unsigned long private, bool offlining,
 			enum migrate_mode mode);
 
@@ -30,13 +30,17 @@ extern int migrate_vmas(struct mm_struct *mm,
 extern void migrate_page_copy(struct page *newpage, struct page *page);
 extern int migrate_huge_page_move_mapping(struct address_space *mapping,
 				  struct page *newpage, struct page *page);
+
+extern int migrate_pages_unmap_only(struct list_head *);
+extern struct page *migrate_misplaced_page(struct page *,
+			struct mm_struct *, int);
 #else
 
 static inline void putback_lru_pages(struct list_head *l) {}
 static inline int migrate_pages(struct list_head *l, new_page_t x,
 		unsigned long private, bool offlining,
 		enum migrate_mode mode) { return -ENOSYS; }
-static inline int migrate_huge_pages(struct list_head *l, new_page_t x,
+static inline int migrate_huge_page(struct page *page, new_page_t x,
 		unsigned long private, bool offlining,
 		enum migrate_mode mode) { return -ENOSYS; }
 
@@ -59,9 +63,26 @@ static inline int migrate_huge_page_move_mapping(struct address_space *mapping,
 	return -ENOSYS;
 }
 
+static inline int migrate_pages_unmap_only(struct list_head *l)
+{
+	return -ENOSYS;
+}
+
 /* Possible settings for the migrate_page() method in address_operations */
 #define migrate_page NULL
 #define fail_migrate_page NULL
 
 #endif /* CONFIG_MIGRATION */
+
+#if defined(CONFIG_MIGRATION) && defined(CONFIG_NUMA)
+extern struct page *check_migrate_misplaced_page(struct page *,
+			struct vm_area_struct *, unsigned long);
+#else
+static inline struct page *check_migrate_misplaced_page(struct page *page,
+			struct vm_area_struct *vma, unsigned long addr)
+{
+	return page;
+}
+#endif
+
 #endif /* _LINUX_MIGRATE_H */
diff --git a/include/linux/migrate_mode.h b/include/linux/migrate_mode.h
index ebf3d89..9694347 100644
--- a/include/linux/migrate_mode.h
+++ b/include/linux/migrate_mode.h
@@ -6,11 +6,14 @@
  *	on most operations but not ->writepage as the potential stall time
  *	is too significant
  * MIGRATE_SYNC will block when migrating pages
+ * MIGRATE_FAULT called from the fault path to migrate-on-fault for mempolicy
+ * 	this path has an extra reference count
  */
 enum migrate_mode {
 	MIGRATE_ASYNC,
 	MIGRATE_SYNC_LIGHT,
 	MIGRATE_SYNC,
+	MIGRATE_FAULT,
 };
 
 #endif		/* MIGRATE_MODE_H_INCLUDED */
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index 0549d211..e0deeb2 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -35,6 +35,7 @@
 #define MPT_MINOR		220
 #define MPT2SAS_MINOR		221
 #define UINPUT_MINOR		223
+#define MISC_MCELOG_MINOR	227
 #define HPET_MINOR		228
 #define FUSE_MINOR		229
 #define KVM_MINOR		232
diff --git a/include/linux/mm.h b/include/linux/mm.h
index b36d08c..a4549c6 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1528,6 +1528,7 @@ void vm_stat_account(struct mm_struct *, unsigned long, struct file *, long);
 static inline void vm_stat_account(struct mm_struct *mm,
 			unsigned long flags, struct file *file, long pages)
 {
+	mm->total_vm += pages;
 }
 #endif /* CONFIG_PROC_FS */
 
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 704a626..27c741c 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -53,7 +53,7 @@ struct page {
 	struct {
 		union {
 			pgoff_t index;		/* Our offset within mapping. */
-			void *freelist;		/* slub first free object */
+			void *freelist;		/* slub/slob first free object */
 		};
 
 		union {
@@ -91,11 +91,12 @@ struct page {
 					 */
 					atomic_t _mapcount;
 
-					struct {
+					struct { /* SLUB */
 						unsigned inuse:16;
 						unsigned objects:15;
 						unsigned frozen:1;
 					};
+					int units;	/* SLOB */
 				};
 				atomic_t _count;		/* Usage count, see below. */
 			};
@@ -117,6 +118,12 @@ struct page {
 			short int pobjects;
 #endif
 		};
+
+		struct list_head list;	/* slobs list of pages */
+		struct {		/* slab fields */
+			struct kmem_cache *slab_cache;
+			struct slab *slab_page;
+		};
 	};
 
 	/* Remainder is not double word aligned */
@@ -296,6 +303,14 @@ struct mm_rss_stat {
 	atomic_long_t count[NR_MM_COUNTERS];
 };
 
+struct numa_entity {
+#ifdef CONFIG_NUMA
+	int			node;		/* home node */
+	struct list_head	numa_entry;	/* balance list */
+	const struct numa_ops	*nops;
+#endif
+};
+
 struct mm_struct {
 	struct vm_area_struct * mmap;		/* list of VMAs */
 	struct rb_root mm_rb;
@@ -389,6 +404,7 @@ struct mm_struct {
 	struct cpumask cpumask_allocation;
 #endif
 	struct uprobes_state uprobes_state;
+	struct numa_entity numa;
 };
 
 static inline void mm_init_cpumask(struct mm_struct *mm)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 0707d22..9deb725 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -155,6 +155,13 @@ struct mmc_hotplug {
 	void *handler_priv;
 };
 
+struct regulator;
+
+struct mmc_supply {
+	struct regulator *vmmc;		/* Card power supply */
+	struct regulator *vqmmc;	/* Optional Vccq supply */
+};
+
 struct mmc_host {
 	struct device		*parent;
 	struct device		class_dev;
@@ -309,6 +316,7 @@ struct mmc_host {
 #ifdef CONFIG_REGULATOR
 	bool			regulator_enabled; /* regulator state */
 #endif
+	struct mmc_supply	supply;
 
 	struct dentry		*debugfs_root;
 
@@ -357,13 +365,12 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 	wake_up_process(host->sdio_irq_thread);
 }
 
-struct regulator;
-
 #ifdef CONFIG_REGULATOR
 int mmc_regulator_get_ocrmask(struct regulator *supply);
 int mmc_regulator_set_ocr(struct mmc_host *mmc,
 			struct regulator *supply,
 			unsigned short vdd_bit);
+int mmc_regulator_get_supply(struct mmc_host *mmc);
 #else
 static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
 {
@@ -376,6 +383,11 @@ static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
 {
 	return 0;
 }
+
+static inline int mmc_regulator_get_supply(struct mmc_host *mmc)
+{
+	return 0;
+}
 #endif
 
 int mmc_card_awake(struct mmc_host *host);
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 2427706..dbc876e 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -137,7 +137,6 @@ enum zone_stat_item {
 	NUMA_HIT,		/* allocated in intended node */
 	NUMA_MISS,		/* allocated in non intended node */
 	NUMA_FOREIGN,		/* was intended here, hit elsewhere */
-	NUMA_INTERLEAVE_HIT,	/* interleaver preferred this zone */
 	NUMA_LOCAL,		/* allocation from local node */
 	NUMA_OTHER,		/* allocation from other node */
 #endif
@@ -694,7 +693,7 @@ typedef struct pglist_data {
 					     range, including holes */
 	int node_id;
 	wait_queue_head_t kswapd_wait;
-	struct task_struct *kswapd;
+	struct task_struct *kswapd;	/* Protected by lock_memory_hotplug() */
 	int kswapd_max_order;
 	enum zone_type classzone_idx;
 } pg_data_t;
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 5db9382..6955045 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -78,6 +78,9 @@ struct ieee1394_device_id {
  *	of a given interface; other interfaces may support other classes.
  * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
  * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
+ * @bInterfaceNumber: Number of interface; composite devices may use
+ *	fixed interface numbers to differentiate between vendor-specific
+ *	interfaces.
  * @driver_info: Holds information used by the driver.  Usually it holds
  *	a pointer to a descriptor understood by the driver, or perhaps
  *	device flags.
@@ -115,8 +118,12 @@ struct usb_device_id {
 	__u8		bInterfaceSubClass;
 	__u8		bInterfaceProtocol;
 
+	/* Used for vendor-specific interface matches */
+	__u8		bInterfaceNumber;
+
 	/* not matched against */
-	kernel_ulong_t	driver_info;
+	kernel_ulong_t	driver_info
+		__attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
 /* Some useful macros to use to create struct usb_device_id */
@@ -130,6 +137,7 @@ struct usb_device_id {
 #define USB_DEVICE_ID_MATCH_INT_CLASS		0x0080
 #define USB_DEVICE_ID_MATCH_INT_SUBCLASS	0x0100
 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL	0x0200
+#define USB_DEVICE_ID_MATCH_INT_NUMBER		0x0400
 
 #define HID_ANY_ID				(~0)
 #define HID_BUS_ANY				0xffff
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index 650ef35..5d9fcb7 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -78,8 +78,6 @@ struct nand_bbt_descr {
 #define NAND_BBT_LASTBLOCK	0x00000010
 /* The bbt is at the given page, else we must scan for the bbt */
 #define NAND_BBT_ABSPAGE	0x00000020
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_SEARCH		0x00000040
 /* bbt is stored per chip on multichip devices */
 #define NAND_BBT_PERCHIP	0x00000080
 /* bbt has a version counter at offset veroffs */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 57977c6..a81ac89 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -185,12 +185,6 @@ typedef enum {
  * This happens with the Renesas AG-AND chips, possibly others.
  */
 #define BBT_AUTO_REFRESH	0x00000080
-/*
- * Chip does not require ready check on read. True
- * for all large page devices, as they do not support
- * autoincrement.
- */
-#define NAND_NO_READRDY		0x00000100
 /* Chip does not allow subpage writes */
 #define NAND_NO_SUBPAGE_WRITE	0x00000200
 
@@ -559,6 +553,7 @@ struct nand_chip {
 #define NAND_MFR_MICRON		0x2c
 #define NAND_MFR_AMD		0x01
 #define NAND_MFR_MACRONIX	0xc2
+#define NAND_MFR_EON		0x92
 
 /**
  * struct nand_flash_dev - NAND Flash Device ID Structure
diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h
index a38e1fa..01e4b15 100644
--- a/include/linux/mtd/sh_flctl.h
+++ b/include/linux/mtd/sh_flctl.h
@@ -49,7 +49,6 @@
 #define	FLERRADR(f)		(f->reg + 0x98)
 
 /* FLCMNCR control bits */
-#define ECCPOS2		(0x1 << 25)
 #define _4ECCCNTEN	(0x1 << 24)
 #define _4ECCEN		(0x1 << 23)
 #define _4ECCCORRECT	(0x1 << 22)
@@ -59,9 +58,6 @@
 #define QTSEL_E		(0x1 << 17)
 #define ENDIAN		(0x1 << 16)	/* 1 = little endian */
 #define FCKSEL_E	(0x1 << 15)
-#define ECCPOS_00	(0x00 << 12)
-#define ECCPOS_01	(0x01 << 12)
-#define ECCPOS_02	(0x02 << 12)
 #define ACM_SACCES_MODE	(0x01 << 10)
 #define NANWF_E		(0x1 << 9)
 #define SE_D		(0x1 << 8)	/* Spare area disable */
@@ -107,6 +103,14 @@
 #define DOCMD2_E	(0x1 << 17)	/* 2nd cmd stage execute */
 #define DOCMD1_E	(0x1 << 16)	/* 1st cmd stage execute */
 
+/* FLINTDMACR control bits */
+#define ESTERINTE	(0x1 << 24)	/* ECC error interrupt enable */
+#define AC1CLR		(0x1 << 19)	/* ECC FIFO clear */
+#define AC0CLR		(0x1 << 18)	/* Data FIFO clear */
+#define ECERB		(0x1 << 9)	/* ECC error */
+#define STERB		(0x1 << 8)	/* Status error */
+#define STERINTE	(0x1 << 4)	/* Status error enable */
+
 /* FLTRCR control bits */
 #define TRSTRT		(0x1 << 0)	/* translation start */
 #define TREND		(0x1 << 1)	/* translation end */
@@ -125,9 +129,15 @@
 #define	_4ECCEND	(0x1 << 1)	/* 4 symbols end */
 #define	_4ECCEXST	(0x1 << 0)	/* 4 symbols exist */
 
-#define INIT_FL4ECCRESULT_VAL	0x03FF03FF
 #define LOOP_TIMEOUT_MAX	0x00010000
 
+enum flctl_ecc_res_t {
+	FL_SUCCESS,
+	FL_REPAIRABLE,
+	FL_ERROR,
+	FL_TIMEOUT
+};
+
 struct sh_flctl {
 	struct mtd_info		mtd;
 	struct nand_chip	chip;
@@ -145,8 +155,7 @@ struct sh_flctl {
 	uint32_t erase_ADRCNT;		/* bits of FLCMDCR in ERASE1 cmd */
 	uint32_t rw_ADRCNT;	/* bits of FLCMDCR in READ WRITE cmd */
 	uint32_t flcmncr_base;	/* base value of FLCMNCR */
-
-	int	hwecc_cant_correct[4];
+	uint32_t flintdmacr_base;	/* irq enable bits */
 
 	unsigned page_size:1;	/* NAND page size (0 = 512, 1 = 2048) */
 	unsigned hwecc:1;	/* Hardware ECC (0 = disabled, 1 = enabled) */
diff --git a/include/linux/namei.h b/include/linux/namei.h
index ffc0213..d2ef8b3 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -7,12 +7,6 @@
 
 struct vfsmount;
 
-struct open_intent {
-	int	flags;
-	int	create_mode;
-	struct file *file;
-};
-
 enum { MAX_NESTED_LINKS = 8 };
 
 struct nameidata {
@@ -25,11 +19,6 @@ struct nameidata {
 	int		last_type;
 	unsigned	depth;
 	char *saved_names[MAX_NESTED_LINKS + 1];
-
-	/* Intent data */
-	union {
-		struct open_intent open;
-	} intent;
 };
 
 /*
@@ -78,13 +67,10 @@ extern int kern_path(const char *, unsigned, struct path *);
 
 extern struct dentry *kern_path_create(int, const char *, struct path *, int);
 extern struct dentry *user_path_create(int, const char __user *, struct path *, int);
-extern int kern_path_parent(const char *, struct nameidata *);
+extern struct dentry *kern_path_locked(const char *, struct path *);
 extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
 			   const char *, unsigned int, struct path *);
 
-extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
-		int (*open)(struct inode *, struct file *));
-
 extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
 
 extern int follow_down_one(struct path *);
@@ -94,6 +80,8 @@ extern int follow_up(struct path *);
 extern struct dentry *lock_rename(struct dentry *, struct dentry *);
 extern void unlock_rename(struct dentry *, struct dentry *);
 
+extern void nd_jump_link(struct nameidata *nd, struct path *path);
+
 static inline void nd_set_link(struct nameidata *nd, char *path)
 {
 	nd->saved_names[nd->depth] = path;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d94cb14..2c2ecea 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1046,10 +1046,9 @@ struct net_device {
 	 */
 	char			name[IFNAMSIZ];
 
-	struct pm_qos_request	pm_qos_req;
-
-	/* device name hash chain */
+	/* device name hash chain, please keep it close to name[] */
 	struct hlist_node	name_hlist;
+
 	/* snmp alias */
 	char 			*ifalias;
 
@@ -1322,6 +1321,8 @@ struct net_device {
 
 	/* group the device belongs to */
 	int group;
+
+	struct pm_qos_request	pm_qos_req;
 };
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
@@ -1626,6 +1627,7 @@ extern int		dev_alloc_name(struct net_device *dev, const char *name);
 extern int		dev_open(struct net_device *dev);
 extern int		dev_close(struct net_device *dev);
 extern void		dev_disable_lro(struct net_device *dev);
+extern int		dev_loopback_xmit(struct sk_buff *newskb);
 extern int		dev_queue_xmit(struct sk_buff *skb);
 extern int		register_netdevice(struct net_device *dev);
 extern void		unregister_netdevice_queue(struct net_device *dev,
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index ff9c84c..c613cf0 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -94,6 +94,16 @@ static inline int nf_inet_addr_cmp(const union nf_inet_addr *a1,
 	       a1->all[3] == a2->all[3];
 }
 
+static inline void nf_inet_addr_mask(const union nf_inet_addr *a1,
+				     union nf_inet_addr *result,
+				     const union nf_inet_addr *mask)
+{
+	result->all[0] = a1->all[0] & mask->all[0];
+	result->all[1] = a1->all[1] & mask->all[1];
+	result->all[2] = a1->all[2] & mask->all[2];
+	result->all[3] = a1->all[3] & mask->all[3];
+}
+
 extern void netfilter_init(void);
 
 /* Largest hook number + 1 */
@@ -383,6 +393,22 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
 extern void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *) __rcu;
 extern void nf_ct_attach(struct sk_buff *, struct sk_buff *);
 extern void (*nf_ct_destroy)(struct nf_conntrack *) __rcu;
+
+struct nf_conn;
+struct nlattr;
+
+struct nfq_ct_hook {
+	size_t (*build_size)(const struct nf_conn *ct);
+	int (*build)(struct sk_buff *skb, struct nf_conn *ct);
+	int (*parse)(const struct nlattr *attr, struct nf_conn *ct);
+};
+extern struct nfq_ct_hook __rcu *nfq_ct_hook;
+
+struct nfq_ct_nat_hook {
+	void (*seq_adjust)(struct sk_buff *skb, struct nf_conn *ct,
+			   u32 ctinfo, int off);
+};
+extern struct nfq_ct_nat_hook __rcu *nfq_ct_nat_hook;
 #else
 static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
 #endif
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild
index 1697036..874ae8f 100644
--- a/include/linux/netfilter/Kbuild
+++ b/include/linux/netfilter/Kbuild
@@ -10,6 +10,7 @@ header-y += nfnetlink.h
 header-y += nfnetlink_acct.h
 header-y += nfnetlink_compat.h
 header-y += nfnetlink_conntrack.h
+header-y += nfnetlink_cthelper.h
 header-y += nfnetlink_cttimeout.h
 header-y += nfnetlink_log.h
 header-y += nfnetlink_queue.h
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 0ce91d5..0dfc8b7 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -2,6 +2,8 @@
 #define __NF_CONNTRACK_SIP_H__
 #ifdef __KERNEL__
 
+#include <net/netfilter/nf_conntrack_expect.h>
+
 #define SIP_PORT	5060
 #define SIP_TIMEOUT	3600
 
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index a1048c1..18341cd 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -50,7 +50,8 @@ struct nfgenmsg {
 #define NFNL_SUBSYS_IPSET		6
 #define NFNL_SUBSYS_ACCT		7
 #define NFNL_SUBSYS_CTNETLINK_TIMEOUT	8
-#define NFNL_SUBSYS_COUNT		9
+#define NFNL_SUBSYS_CTHELPER		9
+#define NFNL_SUBSYS_COUNT		10
 
 #ifdef __KERNEL__
 
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
index e58e4b9..7688833 100644
--- a/include/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/linux/netfilter/nfnetlink_conntrack.h
@@ -191,6 +191,7 @@ enum ctattr_expect_nat {
 enum ctattr_help {
 	CTA_HELP_UNSPEC,
 	CTA_HELP_NAME,
+	CTA_HELP_INFO,
 	__CTA_HELP_MAX
 };
 #define CTA_HELP_MAX (__CTA_HELP_MAX - 1)
diff --git a/include/linux/netfilter/nfnetlink_cthelper.h b/include/linux/netfilter/nfnetlink_cthelper.h
new file mode 100644
index 0000000..33659f6
--- /dev/null
+++ b/include/linux/netfilter/nfnetlink_cthelper.h
@@ -0,0 +1,55 @@
+#ifndef _NFNL_CTHELPER_H_
+#define _NFNL_CTHELPER_H_
+
+#define NFCT_HELPER_STATUS_DISABLED	0
+#define NFCT_HELPER_STATUS_ENABLED	1
+
+enum nfnl_acct_msg_types {
+	NFNL_MSG_CTHELPER_NEW,
+	NFNL_MSG_CTHELPER_GET,
+	NFNL_MSG_CTHELPER_DEL,
+	NFNL_MSG_CTHELPER_MAX
+};
+
+enum nfnl_cthelper_type {
+	NFCTH_UNSPEC,
+	NFCTH_NAME,
+	NFCTH_TUPLE,
+	NFCTH_QUEUE_NUM,
+	NFCTH_POLICY,
+	NFCTH_PRIV_DATA_LEN,
+	NFCTH_STATUS,
+	__NFCTH_MAX
+};
+#define NFCTH_MAX (__NFCTH_MAX - 1)
+
+enum nfnl_cthelper_policy_type {
+	NFCTH_POLICY_SET_UNSPEC,
+	NFCTH_POLICY_SET_NUM,
+	NFCTH_POLICY_SET,
+	NFCTH_POLICY_SET1	= NFCTH_POLICY_SET,
+	NFCTH_POLICY_SET2,
+	NFCTH_POLICY_SET3,
+	NFCTH_POLICY_SET4,
+	__NFCTH_POLICY_SET_MAX
+};
+#define NFCTH_POLICY_SET_MAX (__NFCTH_POLICY_SET_MAX - 1)
+
+enum nfnl_cthelper_pol_type {
+	NFCTH_POLICY_UNSPEC,
+	NFCTH_POLICY_NAME,
+	NFCTH_POLICY_EXPECT_MAX,
+	NFCTH_POLICY_EXPECT_TIMEOUT,
+	__NFCTH_POLICY_MAX
+};
+#define NFCTH_POLICY_MAX (__NFCTH_POLICY_MAX - 1)
+
+enum nfnl_cthelper_tuple_type {
+	NFCTH_TUPLE_UNSPEC,
+	NFCTH_TUPLE_L3PROTONUM,
+	NFCTH_TUPLE_L4PROTONUM,
+	__NFCTH_TUPLE_MAX,
+};
+#define NFCTH_TUPLE_MAX (__NFCTH_TUPLE_MAX - 1)
+
+#endif /* _NFNL_CTHELPER_H */
diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h
index 24b32e6..e0d8fd8 100644
--- a/include/linux/netfilter/nfnetlink_queue.h
+++ b/include/linux/netfilter/nfnetlink_queue.h
@@ -42,6 +42,8 @@ enum nfqnl_attr_type {
 	NFQA_IFINDEX_PHYSOUTDEV,	/* __u32 ifindex */
 	NFQA_HWADDR,			/* nfqnl_msg_packet_hw */
 	NFQA_PAYLOAD,			/* opaque data payload */
+	NFQA_CT,			/* nf_conntrack_netlink.h */
+	NFQA_CT_INFO,			/* enum ip_conntrack_info */
 
 	__NFQA_MAX
 };
@@ -84,8 +86,14 @@ enum nfqnl_attr_config {
 	NFQA_CFG_CMD,			/* nfqnl_msg_config_cmd */
 	NFQA_CFG_PARAMS,		/* nfqnl_msg_config_params */
 	NFQA_CFG_QUEUE_MAXLEN,		/* __u32 */
+	NFQA_CFG_MASK,			/* identify which flags to change */
+	NFQA_CFG_FLAGS,			/* value of these flags (__u32) */
 	__NFQA_CFG_MAX
 };
 #define NFQA_CFG_MAX (__NFQA_CFG_MAX-1)
 
+/* Flags for NFQA_CFG_FLAGS */
+#define NFQA_CFG_F_FAIL_OPEN			(1 << 0)
+#define NFQA_CFG_F_CONNTRACK			(1 << 1)
+
 #endif /* _NFNETLINK_QUEUE_H */
diff --git a/include/linux/netfilter/xt_connlimit.h b/include/linux/netfilter/xt_connlimit.h
index d1366f0..f165609 100644
--- a/include/linux/netfilter/xt_connlimit.h
+++ b/include/linux/netfilter/xt_connlimit.h
@@ -22,13 +22,8 @@ struct xt_connlimit_info {
 #endif
 	};
 	unsigned int limit;
-	union {
-		/* revision 0 */
-		unsigned int inverse;
-
-		/* revision 1 */
-		__u32 flags;
-	};
+	/* revision 1 */
+	__u32 flags;
 
 	/* Used internally by the kernel */
 	struct xt_connlimit_data *data __attribute__((aligned(8)));
diff --git a/include/linux/netfilter/xt_recent.h b/include/linux/netfilter/xt_recent.h
index 83318e0..6ef36c1 100644
--- a/include/linux/netfilter/xt_recent.h
+++ b/include/linux/netfilter/xt_recent.h
@@ -32,4 +32,14 @@ struct xt_recent_mtinfo {
 	__u8 side;
 };
 
+struct xt_recent_mtinfo_v1 {
+	__u32 seconds;
+	__u32 hit_count;
+	__u8 check_set;
+	__u8 invert;
+	char name[XT_RECENT_NAME_LEN];
+	__u8 side;
+	union nf_inet_addr mask;
+};
+
 #endif /* _LINUX_NETFILTER_XT_RECENT_H */
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index fa0946c..e2b1280 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -66,6 +66,7 @@ enum nf_ip_hook_priorities {
 	NF_IP_PRI_SECURITY = 50,
 	NF_IP_PRI_NAT_SRC = 100,
 	NF_IP_PRI_SELINUX_LAST = 225,
+	NF_IP_PRI_CONNTRACK_HELPER = 300,
 	NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
 	NF_IP_PRI_LAST = INT_MAX,
 };
diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild
index c61b8fb..8ba0c5b 100644
--- a/include/linux/netfilter_ipv4/Kbuild
+++ b/include/linux/netfilter_ipv4/Kbuild
@@ -5,7 +5,6 @@ header-y += ipt_LOG.h
 header-y += ipt_REJECT.h
 header-y += ipt_TTL.h
 header-y += ipt_ULOG.h
-header-y += ipt_addrtype.h
 header-y += ipt_ah.h
 header-y += ipt_ecn.h
 header-y += ipt_ttl.h
diff --git a/include/linux/netfilter_ipv4/ipt_addrtype.h b/include/linux/netfilter_ipv4/ipt_addrtype.h
deleted file mode 100644
index 0da4223..0000000
--- a/include/linux/netfilter_ipv4/ipt_addrtype.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _IPT_ADDRTYPE_H
-#define _IPT_ADDRTYPE_H
-
-#include <linux/types.h>
-
-enum {
-	IPT_ADDRTYPE_INVERT_SOURCE	= 0x0001,
-	IPT_ADDRTYPE_INVERT_DEST	= 0x0002,
-	IPT_ADDRTYPE_LIMIT_IFACE_IN	= 0x0004,
-	IPT_ADDRTYPE_LIMIT_IFACE_OUT	= 0x0008,
-};
-
-struct ipt_addrtype_info_v1 {
-	__u16	source;		/* source-type mask */
-	__u16	dest;		/* dest-type mask */
-	__u32	flags;
-};
-
-/* revision 0 */
-struct ipt_addrtype_info {
-	__u16	source;		/* source-type mask */
-	__u16	dest;		/* dest-type mask */
-	__u32	invert_source;
-	__u32	invert_dest;
-};
-
-#endif
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h
index 57c0251..7c8a513 100644
--- a/include/linux/netfilter_ipv6.h
+++ b/include/linux/netfilter_ipv6.h
@@ -71,6 +71,7 @@ enum nf_ip6_hook_priorities {
 	NF_IP6_PRI_SECURITY = 50,
 	NF_IP6_PRI_NAT_SRC = 100,
 	NF_IP6_PRI_SELINUX_LAST = 225,
+	NF_IP6_PRI_CONNTRACK_HELPER = 300,
 	NF_IP6_PRI_LAST = INT_MAX,
 };
 
diff --git a/include/linux/nfc.h b/include/linux/nfc.h
index 0ae9b58..f4e6dd9 100644
--- a/include/linux/nfc.h
+++ b/include/linux/nfc.h
@@ -56,6 +56,10 @@
  *	%NFC_ATTR_PROTOCOLS)
  * @NFC_EVENT_DEVICE_REMOVED: event emitted when a device is removed
  *	(it sends %NFC_ATTR_DEVICE_INDEX)
+ * @NFC_EVENT_TM_ACTIVATED: event emitted when the adapter is activated in
+ *      target mode.
+ * @NFC_EVENT_DEVICE_DEACTIVATED: event emitted when the adapter is deactivated
+ *      from target mode.
  */
 enum nfc_commands {
 	NFC_CMD_UNSPEC,
@@ -71,6 +75,8 @@ enum nfc_commands {
 	NFC_EVENT_DEVICE_ADDED,
 	NFC_EVENT_DEVICE_REMOVED,
 	NFC_EVENT_TARGET_LOST,
+	NFC_EVENT_TM_ACTIVATED,
+	NFC_EVENT_TM_DEACTIVATED,
 /* private: internal use only */
 	__NFC_CMD_AFTER_LAST
 };
@@ -94,6 +100,8 @@ enum nfc_commands {
  * @NFC_ATTR_TARGET_SENSF_RES: NFC-F targets extra information, max 18 bytes
  * @NFC_ATTR_COMM_MODE: Passive or active mode
  * @NFC_ATTR_RF_MODE: Initiator or target
+ * @NFC_ATTR_IM_PROTOCOLS: Initiator mode protocols to poll for
+ * @NFC_ATTR_TM_PROTOCOLS: Target mode protocols to listen for
  */
 enum nfc_attrs {
 	NFC_ATTR_UNSPEC,
@@ -109,6 +117,8 @@ enum nfc_attrs {
 	NFC_ATTR_COMM_MODE,
 	NFC_ATTR_RF_MODE,
 	NFC_ATTR_DEVICE_POWERED,
+	NFC_ATTR_IM_PROTOCOLS,
+	NFC_ATTR_TM_PROTOCOLS,
 /* private: internal use only */
 	__NFC_ATTR_AFTER_LAST
 };
@@ -118,6 +128,7 @@ enum nfc_attrs {
 #define NFC_NFCID1_MAXSIZE 10
 #define NFC_SENSB_RES_MAXSIZE 12
 #define NFC_SENSF_RES_MAXSIZE 18
+#define NFC_GB_MAXSIZE        48
 
 /* NFC protocols */
 #define NFC_PROTO_JEWEL		1
@@ -135,6 +146,7 @@ enum nfc_attrs {
 /* NFC RF modes */
 #define NFC_RF_INITIATOR 0
 #define NFC_RF_TARGET    1
+#define NFC_RF_NONE      2
 
 /* NFC protocols masks used in bitsets */
 #define NFC_PROTO_JEWEL_MASK	(1 << NFC_PROTO_JEWEL)
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 88d166b..8808057 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -42,7 +42,7 @@ struct nfs_page {
 				wb_bytes;	/* Length of request */
 	struct kref		wb_kref;	/* reference count */
 	unsigned long		wb_flags;
-	struct nfs_writeverf	wb_verf;	/* Commit cookie */
+	struct nfs_write_verifier	wb_verf;	/* Commit cookie */
 };
 
 struct nfs_pageio_descriptor;
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 8aadd90..1b77280 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -514,9 +514,13 @@ struct nfs_writeargs {
 	struct nfs4_sequence_args	seq_args;
 };
 
+struct nfs_write_verifier {
+	char			data[8];
+};
+
 struct nfs_writeverf {
+	struct nfs_write_verifier verifier;
 	enum nfs3_stable_how	committed;
-	__be32			verifier[2];
 };
 
 struct nfs_writeres {
@@ -1374,7 +1378,7 @@ struct nfs_rpc_ops {
 	int	(*readlink)(struct inode *, struct page *, unsigned int,
 			    unsigned int);
 	int	(*create)  (struct inode *, struct dentry *,
-			    struct iattr *, int, struct nfs_open_context *);
+			    struct iattr *, int);
 	int	(*remove)  (struct inode *, struct qstr *);
 	void	(*unlink_setup)  (struct rpc_message *, struct inode *dir);
 	void	(*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *);
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index a6959f7..c0fc5d2 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -170,6 +170,8 @@
  *	%NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
  *	%NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
  *	%NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
+ *	The channel to use can be set on the interface or be given using the
+ *	%NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs.
  * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
  * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
  * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
@@ -275,6 +277,12 @@
  * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
  *	NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
  *
+ * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC
+ *	(for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC
+ *	(for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries.
+ *
  * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
  * 	has been changed and provides details of the request information
  * 	that caused the change such as who initiated the regulatory request
@@ -454,6 +462,10 @@
  *	the frame.
  * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
  *	backward compatibility.
+ *
+ * @NL80211_CMD_SET_POWER_SAVE: Set powersave, using %NL80211_ATTR_PS_STATE
+ * @NL80211_CMD_GET_POWER_SAVE: Get powersave status in %NL80211_ATTR_PS_STATE
+ *
  * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
  *	is used to configure connection quality monitoring notification trigger
  *	levels.
@@ -769,6 +781,13 @@ enum nl80211_commands {
  *	section 7.3.2.25.1, e.g. 0x000FAC04)
  * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
  *	CCMP keys, each six bytes in little endian
+ * @NL80211_ATTR_KEY_DEFAULT: Flag attribute indicating the key is default key
+ * @NL80211_ATTR_KEY_DEFAULT_MGMT: Flag attribute indicating the key is the
+ *	default management key
+ * @NL80211_ATTR_CIPHER_SUITES_PAIRWISE: For crypto settings for connect or
+ *	other commands, indicates which pairwise cipher suites are used
+ * @NL80211_ATTR_CIPHER_SUITE_GROUP: For crypto settings for connect or
+ *	other commands, indicates which group cipher suite is used
  *
  * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
  * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
@@ -1004,6 +1023,8 @@ enum nl80211_commands {
  * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
  *	acknowledged by the recipient.
  *
+ * @NL80211_ATTR_PS_STATE: powersave state, using &enum nl80211_ps_state values.
+ *
  * @NL80211_ATTR_CQM: connection quality monitor configuration in a
  *	nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
  *
@@ -1061,7 +1082,7 @@ enum nl80211_commands {
  *	flag isn't set, the frame will be rejected. This is also used as an
  *	nl80211 capability flag.
  *
- * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16)
+ * @NL80211_ATTR_BSS_HT_OPMODE: HT operation mode (u16)
  *
  * @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags
  *	attributes, specifying what a key should be set as default as.
@@ -1085,10 +1106,10 @@ enum nl80211_commands {
  *	indicate which WoW triggers should be enabled. This is also
  *	used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN
  *	triggers.
-
+ *
  * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
  *	cycles, in msecs.
-
+ *
  * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
  *	sets of attributes to match during scheduled scans.  Only BSSs
  *	that match any of the sets will be reported.  These are
@@ -1115,7 +1136,7 @@ enum nl80211_commands {
  *	are managed in software: interfaces of these types aren't subject to
  *	any restrictions in their number or combinations.
  *
- * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ * @NL80211_ATTR_REKEY_DATA: nested attribute containing the information
  *	necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
  *
  * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan,
@@ -1182,7 +1203,6 @@ enum nl80211_commands {
  * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
  *	&enum nl80211_feature_flags and is advertised in wiphy information.
  * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
- *
  *	requests while operating in AP-mode.
  *	This attribute holds a bitmap of the supported protocols for
  *	offloading (see &enum nl80211_probe_resp_offload_support_attr).
@@ -1520,6 +1540,11 @@ enum nl80211_attrs {
 #define NL80211_MAX_NR_CIPHER_SUITES		5
 #define NL80211_MAX_NR_AKM_SUITES		2
 
+#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME	10
+
+/* default RSSI threshold for scan results if none specified. */
+#define NL80211_SCAN_RSSI_THOLD_OFF		-300
+
 /**
  * enum nl80211_iftype - (virtual) interface types
  *
@@ -1952,6 +1977,8 @@ enum nl80211_reg_rule_attr {
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
  * only report BSS with matching SSID.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
+ *	BSS in scan results. Filtering is turned off if not specified.
  * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
  *	attribute number currently defined
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -1959,7 +1986,8 @@ enum nl80211_reg_rule_attr {
 enum nl80211_sched_scan_match_attr {
 	__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
 
-	NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+	NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
+	NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
 
 	/* keep last */
 	__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -1967,6 +1995,9 @@ enum nl80211_sched_scan_match_attr {
 		__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
 };
 
+/* only for backward compatibility */
+#define NL80211_ATTR_SCHED_SCAN_MATCH_SSID NL80211_SCHED_SCAN_MATCH_ATTR_SSID
+
 /**
  * enum nl80211_reg_rule_flags - regulatory rule flags
  *
@@ -2086,78 +2117,91 @@ enum nl80211_mntr_flags {
  * @__NL80211_MESHCONF_INVALID: internal use
  *
  * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
- * millisecond units, used by the Peer Link Open message
+ *	millisecond units, used by the Peer Link Open message
  *
  * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in
- * millisecond units, used by the peer link management to close a peer link
+ *	millisecond units, used by the peer link management to close a peer link
  *
  * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
- * millisecond units
+ *	millisecond units
  *
  * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
- * on this mesh interface
+ *	on this mesh interface
  *
  * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
- * open retries that can be sent to establish a new peer link instance in a
- * mesh
+ *	open retries that can be sent to establish a new peer link instance in a
+ *	mesh
  *
  * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
- * point.
+ *	point.
  *
  * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
- * open peer links when we detect compatible mesh peers.
+ *	open peer links when we detect compatible mesh peers.
  *
  * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
- * containing a PREQ that an MP can send to a particular destination (path
- * target)
+ *	containing a PREQ that an MP can send to a particular destination (path
+ *	target)
  *
  * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
- * (in milliseconds)
+ *	(in milliseconds)
  *
  * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
- * until giving up on a path discovery (in milliseconds)
+ *	until giving up on a path discovery (in milliseconds)
  *
  * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
- * points receiving a PREQ shall consider the forwarding information from the
- * root to be valid. (TU = time unit)
+ *	points receiving a PREQ shall consider the forwarding information from
+ *	the root to be valid. (TU = time unit)
  *
  * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
- * TUs) during which an MP can send only one action frame containing a PREQ
- * reference element
+ *	TUs) during which an MP can send only one action frame containing a PREQ
+ *	reference element
  *
  * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
- * that it takes for an HWMP information element to propagate across the mesh
+ *	that it takes for an HWMP information element to propagate across the
+ *	mesh
  *
  * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not
  *
  * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
- * source mesh point for path selection elements.
+ *	source mesh point for path selection elements.
  *
  * @NL80211_MESHCONF_HWMP_RANN_INTERVAL:  The interval of time (in TUs) between
- * root announcements are transmitted.
+ *	root announcements are transmitted.
  *
  * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
- * access to a broader network beyond the MBSS.  This is done via Root
- * Announcement frames.
+ *	access to a broader network beyond the MBSS.  This is done via Root
+ *	Announcement frames.
  *
  * @NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL: The minimum interval of time (in
- * TUs) during which a mesh STA can send only one Action frame containing a
- * PERR element.
+ *	TUs) during which a mesh STA can send only one Action frame containing a
+ *	PERR element.
  *
  * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding
- * or forwarding entity (default is TRUE - forwarding entity)
+ *	or forwarding entity (default is TRUE - forwarding entity)
  *
  * @NL80211_MESHCONF_RSSI_THRESHOLD: RSSI threshold in dBm. This specifies the
- * threshold for average signal strength of candidate station to establish
- * a peer link.
- *
- * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
+ *	threshold for average signal strength of candidate station to establish
+ *	a peer link.
  *
  * @NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR: maximum number of neighbors
- * to synchronize to for 11s default synchronization method (see 11C.12.2.2)
+ *	to synchronize to for 11s default synchronization method
+ *	(see 11C.12.2.2)
  *
  * @NL80211_MESHCONF_HT_OPMODE: set mesh HT protection mode.
  *
+ * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
+ *
+ * @NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT: The time (in TUs) for
+ *	which mesh STAs receiving a proactive PREQ shall consider the forwarding
+ *	information to the root mesh STA to be valid.
+ *
+ * @NL80211_MESHCONF_HWMP_ROOT_INTERVAL: The interval of time (in TUs) between
+ *	proactive PREQs are transmitted.
+ *
+ * @NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL: The minimum interval of time
+ *	(in TUs) during which a mesh STA can send only one Action frame
+ *	containing a PREQ element for root path confirmation.
+ *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_meshconf_params {
@@ -2184,6 +2228,9 @@ enum nl80211_meshconf_params {
 	NL80211_MESHCONF_RSSI_THRESHOLD,
 	NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
 	NL80211_MESHCONF_HT_OPMODE,
+	NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
+	NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
+	NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
 
 	/* keep last */
 	__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2199,34 +2246,36 @@ enum nl80211_meshconf_params {
  * @__NL80211_MESH_SETUP_INVALID: Internal use
  *
  * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a
- * vendor specific path selection algorithm or disable it to use the default
- * HWMP.
+ *	vendor specific path selection algorithm or disable it to use the
+ *	default HWMP.
  *
  * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a
- * vendor specific path metric or disable it to use the default Airtime
- * metric.
+ *	vendor specific path metric or disable it to use the default Airtime
+ *	metric.
  *
  * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
- * robust security network ie, or a vendor specific information element that
- * vendors will use to identify the path selection methods and metrics in use.
+ *	robust security network ie, or a vendor specific information element
+ *	that vendors will use to identify the path selection methods and
+ *	metrics in use.
  *
  * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication
- * daemon will be authenticating mesh candidates.
+ *	daemon will be authenticating mesh candidates.
  *
  * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication
- * daemon will be securing peer link frames.  AMPE is a secured version of Mesh
- * Peering Management (MPM) and is implemented with the assistance of a
- * userspace daemon.  When this flag is set, the kernel will send peer
- * management frames to a userspace daemon that will implement AMPE
- * functionality (security capabilities selection, key confirmation, and key
- * management).  When the flag is unset (default), the kernel can autonomously
- * complete (unsecured) mesh peering without the need of a userspace daemon.
- *
- * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
+ *	daemon will be securing peer link frames.  AMPE is a secured version of
+ *	Mesh Peering Management (MPM) and is implemented with the assistance of
+ *	a userspace daemon.  When this flag is set, the kernel will send peer
+ *	management frames to a userspace daemon that will implement AMPE
+ *	functionality (security capabilities selection, key confirmation, and
+ *	key management).  When the flag is unset (default), the kernel can
+ *	autonomously complete (unsecured) mesh peering without the need of a
+ *	userspace daemon.
  *
  * @NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC: Enable this option to use a
- * vendor specific synchronization method or disable it to use the default
- * neighbor offset synchronization
+ *	vendor specific synchronization method or disable it to use the default
+ *	neighbor offset synchronization
+ *
+ * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
  *
  * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
  */
@@ -2496,6 +2545,11 @@ enum nl80211_band {
 	NL80211_BAND_5GHZ,
 };
 
+/**
+ * enum nl80211_ps_state - powersave state
+ * @NL80211_PS_DISABLED: powersave is disabled
+ * @NL80211_PS_ENABLED: powersave is enabled
+ */
 enum nl80211_ps_state {
 	NL80211_PS_DISABLED,
 	NL80211_PS_ENABLED,
@@ -2534,10 +2588,14 @@ enum nl80211_attr_cqm {
  *      configured threshold
  * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
  *      configured threshold
+ * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
+ *	(Note that deauth/disassoc will still follow if the AP is not
+ *	available. This event might get used as roaming event, etc.)
  */
 enum nl80211_cqm_rssi_threshold_event {
 	NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
 	NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+	NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
 };
 
 
diff --git a/include/linux/of.h b/include/linux/of.h
index 2ec1083..76930ee 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -21,6 +21,7 @@
 #include <linux/kref.h>
 #include <linux/mod_devicetable.h>
 #include <linux/spinlock.h>
+#include <linux/topology.h>
 
 #include <asm/byteorder.h>
 #include <asm/errno.h>
@@ -158,10 +159,10 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size)
 
 #define OF_BAD_ADDR	((u64)-1)
 
-#ifndef of_node_to_nid
-static inline int of_node_to_nid(struct device_node *np) { return -1; }
-#define of_node_to_nid of_node_to_nid
-#endif
+static inline const char* of_node_full_name(struct device_node *np)
+{
+	return np ? np->full_name : "<no-node>";
+}
 
 extern struct device_node *of_find_node_by_name(struct device_node *from,
 	const char *name);
@@ -303,6 +304,11 @@ const char *of_prop_next_string(struct property *prop, const char *cur);
 
 #else /* CONFIG_OF */
 
+static inline const char* of_node_full_name(struct device_node *np)
+{
+	return "<no-node>";
+}
+
 static inline bool of_have_populated_dt(void)
 {
 	return false;
@@ -402,6 +408,15 @@ static inline int of_machine_is_compatible(const char *compat)
 	while (0)
 #endif /* CONFIG_OF */
 
+#ifndef of_node_to_nid
+static inline int of_node_to_nid(struct device_node *np)
+{
+	return numa_node_id();
+}
+
+#define of_node_to_nid of_node_to_nid
+#endif
+
 /**
  * of_property_read_bool - Findfrom a property
  * @np:		device node from which the property value is to be read.
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
new file mode 100644
index 0000000..51a560f
--- /dev/null
+++ b/include/linux/of_iommu.h
@@ -0,0 +1,21 @@
+#ifndef __OF_IOMMU_H
+#define __OF_IOMMU_H
+
+#ifdef CONFIG_OF_IOMMU
+
+extern int of_get_dma_window(struct device_node *dn, const char *prefix,
+			     int index, unsigned long *busno, dma_addr_t *addr,
+			     size_t *size);
+
+#else
+
+static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
+			    int index, unsigned long *busno, dma_addr_t *addr,
+			    size_t *size)
+{
+	return -EINVAL;
+}
+
+#endif	/* CONFIG_OF_IOMMU */
+
+#endif /* __OF_IOMMU_H */
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 4462350..248fba2 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -17,6 +17,7 @@ extern acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev);
 extern acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
 					     struct pci_dev *pci_dev);
 extern acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev);
+extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
 
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
 {
diff --git a/include/linux/pci.h b/include/linux/pci.h
index fefb4e1..b26b314 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -132,9 +132,10 @@ static inline const char *pci_power_name(pci_power_t state)
 	return pci_power_names[1 + (int) state];
 }
 
-#define PCI_PM_D2_DELAY	200
-#define PCI_PM_D3_WAIT	10
-#define PCI_PM_BUS_WAIT	50
+#define PCI_PM_D2_DELAY		200
+#define PCI_PM_D3_WAIT		10
+#define PCI_PM_D3COLD_WAIT	100
+#define PCI_PM_BUS_WAIT		50
 
 /** The pci_channel state describes connectivity between the CPU and
  *  the pci device.  If some PCI bus between here and the pci device
@@ -280,11 +281,18 @@ struct pci_dev {
 	unsigned int	pme_poll:1;	/* Poll device's PME status bit */
 	unsigned int	d1_support:1;	/* Low power state D1 is supported */
 	unsigned int	d2_support:1;	/* Low power state D2 is supported */
-	unsigned int	no_d1d2:1;	/* Only allow D0 and D3 */
+	unsigned int	no_d1d2:1;	/* D1 and D2 are forbidden */
+	unsigned int	no_d3cold:1;	/* D3cold is forbidden */
+	unsigned int	d3cold_allowed:1;	/* D3cold is allowed by user */
 	unsigned int	mmio_always_on:1;	/* disallow turning off io/mem
 						   decoding during bar sizing */
 	unsigned int	wakeup_prepared:1;
+	unsigned int	runtime_d3cold:1;	/* whether go through runtime
+						   D3cold, not set for devices
+						   powered on/off by the
+						   corresponding bridge */
 	unsigned int	d3_delay;	/* D3->D0 transition time in ms */
+	unsigned int	d3cold_delay;	/* D3cold->D0 transition time in ms */
 
 #ifdef CONFIG_PCIEASPM
 	struct pcie_link_state	*link_state;	/* ASPM link state. */
@@ -326,6 +334,7 @@ struct pci_dev {
 	unsigned int    is_hotplug_bridge:1;
 	unsigned int    __aer_firmware_first_valid:1;
 	unsigned int	__aer_firmware_first:1;
+	unsigned int	broken_intx_masking:1;
 	pci_dev_flags_t dev_flags;
 	atomic_t	enable_cnt;	/* pci_enable_device has been called */
 
@@ -370,6 +379,8 @@ static inline int pci_channel_offline(struct pci_dev *pdev)
 	return (pdev->error_state != pci_channel_io_normal);
 }
 
+extern struct resource busn_resource;
+
 struct pci_host_bridge_window {
 	struct list_head list;
 	struct resource *res;		/* host bridge aperture (CPU address) */
@@ -421,6 +432,7 @@ struct pci_bus {
 	struct list_head slots;		/* list of slots on this bus */
 	struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];
 	struct list_head resources;	/* address space routed to this bus */
+	struct resource busn_res;	/* bus numbers routed to this bus */
 
 	struct pci_ops	*ops;		/* configuration access functions */
 	void		*sysdata;	/* hook for sys-specific extension */
@@ -428,8 +440,6 @@ struct pci_bus {
 
 	unsigned char	number;		/* bus number */
 	unsigned char	primary;	/* number of primary bridge */
-	unsigned char	secondary;	/* number of secondary bridge */
-	unsigned char	subordinate;	/* max number of subordinate buses */
 	unsigned char	max_bus_speed;	/* enum pci_bus_speed */
 	unsigned char	cur_bus_speed;	/* enum pci_bus_speed */
 
@@ -476,6 +486,32 @@ static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev) { return false;
 #define PCIBIOS_SET_FAILED		0x88
 #define PCIBIOS_BUFFER_TOO_SMALL	0x89
 
+/*
+ * Translate above to generic errno for passing back through non-pci.
+ */
+static inline int pcibios_err_to_errno(int err)
+{
+	if (err <= PCIBIOS_SUCCESSFUL)
+		return err; /* Assume already errno */
+
+	switch (err) {
+	case PCIBIOS_FUNC_NOT_SUPPORTED:
+		return -ENOENT;
+	case PCIBIOS_BAD_VENDOR_ID:
+		return -EINVAL;
+	case PCIBIOS_DEVICE_NOT_FOUND:
+		return -ENODEV;
+	case PCIBIOS_BAD_REGISTER_NUMBER:
+		return -EFAULT;
+	case PCIBIOS_SET_FAILED:
+		return -EIO;
+	case PCIBIOS_BUFFER_TOO_SMALL:
+		return -ENOSPC;
+	}
+
+	return -ENOTTY;
+}
+
 /* Low-level architecture-dependent routines */
 
 struct pci_ops {
@@ -670,6 +706,9 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
 struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 				    struct pci_ops *ops, void *sysdata,
 				    struct list_head *resources);
+int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
+int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
+void pci_bus_release_busn_res(struct pci_bus *b);
 struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
 					     struct pci_ops *ops, void *sysdata,
 					     struct list_head *resources);
@@ -716,8 +755,6 @@ enum pci_lost_interrupt_reason pci_lost_interrupt(struct pci_dev *dev);
 int pci_find_capability(struct pci_dev *dev, int cap);
 int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap);
 int pci_find_ext_capability(struct pci_dev *dev, int cap);
-int pci_bus_find_ext_capability(struct pci_bus *bus, unsigned int devfn,
-				int cap);
 int pci_find_ht_capability(struct pci_dev *dev, int ht_cap);
 int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap);
 struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
@@ -779,6 +816,14 @@ static inline int pci_write_config_dword(const struct pci_dev *dev, int where,
 	return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val);
 }
 
+/* user-space driven config access */
+int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
+int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
+int pci_user_read_config_dword(struct pci_dev *dev, int where, u32 *val);
+int pci_user_write_config_byte(struct pci_dev *dev, int where, u8 val);
+int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val);
+int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val);
+
 int __must_check pci_enable_device(struct pci_dev *dev);
 int __must_check pci_enable_device_io(struct pci_dev *dev);
 int __must_check pci_enable_device_mem(struct pci_dev *dev);
@@ -877,7 +922,6 @@ enum pci_obff_signal_type {
 int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type);
 void pci_disable_obff(struct pci_dev *dev);
 
-bool pci_ltr_supported(struct pci_dev *dev);
 int pci_enable_ltr(struct pci_dev *dev);
 void pci_disable_ltr(struct pci_dev *dev);
 int pci_set_ltr(struct pci_dev *dev, int snoop_lat_ns, int nosnoop_lat_ns);
@@ -1334,6 +1378,9 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
 static inline int pci_domain_nr(struct pci_bus *bus)
 { return 0; }
 
+static inline struct pci_dev *pci_dev_get(struct pci_dev *dev)
+{ return NULL; }
+
 #define dev_is_pci(d) (false)
 #define dev_is_pf(d) (false)
 #define dev_num_vf(d) (0)
@@ -1488,9 +1535,20 @@ enum pci_fixup_pass {
 
 #ifdef CONFIG_PCI_QUIRKS
 void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
+struct pci_dev *pci_get_dma_source(struct pci_dev *dev);
+int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
 #else
 static inline void pci_fixup_device(enum pci_fixup_pass pass,
 				    struct pci_dev *dev) {}
+static inline struct pci_dev *pci_get_dma_source(struct pci_dev *dev)
+{
+	return pci_dev_get(dev);
+}
+static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev,
+					       u16 acs_flags)
+{
+	return -ENOTTY;
+}
 #endif
 
 void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
@@ -1593,7 +1651,9 @@ static inline bool pci_is_pcie(struct pci_dev *dev)
 }
 
 void pci_request_acs(void);
-
+bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags);
+bool pci_acs_path_enabled(struct pci_dev *start,
+			  struct pci_dev *end, u16 acs_flags);
 
 #define PCI_VPD_LRDT			0x80	/* Large Resource Data Type */
 #define PCI_VPD_LRDT_ID(x)		(x | PCI_VPD_LRDT)
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index ab741b0..fc35260 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -517,6 +517,7 @@
 #define PCI_DEVICE_ID_AMD_11H_NB_DRAM	0x1302
 #define PCI_DEVICE_ID_AMD_11H_NB_MISC	0x1303
 #define PCI_DEVICE_ID_AMD_11H_NB_LINK	0x1304
+#define PCI_DEVICE_ID_AMD_15H_M10H_F3	0x1403
 #define PCI_DEVICE_ID_AMD_15H_NB_F0	0x1600
 #define PCI_DEVICE_ID_AMD_15H_NB_F1	0x1601
 #define PCI_DEVICE_ID_AMD_15H_NB_F2	0x1602
@@ -2755,6 +2756,17 @@
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB7	0x3c27
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB8	0x3c2e
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB9	0x3c2f
+#define PCI_DEVICE_ID_INTEL_UNC_HA	0x3c46
+#define PCI_DEVICE_ID_INTEL_UNC_IMC0	0x3cb0
+#define PCI_DEVICE_ID_INTEL_UNC_IMC1	0x3cb1
+#define PCI_DEVICE_ID_INTEL_UNC_IMC2	0x3cb4
+#define PCI_DEVICE_ID_INTEL_UNC_IMC3	0x3cb5
+#define PCI_DEVICE_ID_INTEL_UNC_QPI0	0x3c41
+#define PCI_DEVICE_ID_INTEL_UNC_QPI1	0x3c42
+#define PCI_DEVICE_ID_INTEL_UNC_R2PCIE	0x3c43
+#define PCI_DEVICE_ID_INTEL_UNC_R3QPI0	0x3c44
+#define PCI_DEVICE_ID_INTEL_UNC_R3QPI1	0x3c45
+#define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX	0x3ce0
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB	0x402f
 #define PCI_DEVICE_ID_INTEL_5100_16	0x65f0
 #define PCI_DEVICE_ID_INTEL_5100_21	0x65f5
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index 4b608f5..80e8605 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -26,6 +26,7 @@
  * Under PCI, each device has 256 bytes of configuration address space,
  * of which the first 64 bytes are standardized as follows:
  */
+#define PCI_STD_HEADER_SIZEOF	64
 #define PCI_VENDOR_ID		0x00	/* 16 bits */
 #define PCI_DEVICE_ID		0x02	/* 16 bits */
 #define PCI_COMMAND		0x04	/* 16 bits */
@@ -209,9 +210,12 @@
 #define  PCI_CAP_ID_SHPC 	0x0C	/* PCI Standard Hot-Plug Controller */
 #define  PCI_CAP_ID_SSVID	0x0D	/* Bridge subsystem vendor/device ID */
 #define  PCI_CAP_ID_AGP3	0x0E	/* AGP Target PCI-PCI bridge */
+#define  PCI_CAP_ID_SECDEV	0x0F	/* Secure Device */
 #define  PCI_CAP_ID_EXP 	0x10	/* PCI Express */
 #define  PCI_CAP_ID_MSIX	0x11	/* MSI-X */
+#define  PCI_CAP_ID_SATA	0x12	/* SATA Data/Index Conf. */
 #define  PCI_CAP_ID_AF		0x13	/* PCI Advanced Features */
+#define  PCI_CAP_ID_MAX		PCI_CAP_ID_AF
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
 #define PCI_CAP_SIZEOF		4
@@ -276,6 +280,7 @@
 #define  PCI_VPD_ADDR_MASK	0x7fff	/* Address mask */
 #define  PCI_VPD_ADDR_F		0x8000	/* Write 0, 1 indicates completion */
 #define PCI_VPD_DATA		4	/* 32-bits of data returned here */
+#define PCI_CAP_VPD_SIZEOF	8
 
 /* Slot Identification */
 
@@ -297,8 +302,10 @@
 #define PCI_MSI_ADDRESS_HI	8	/* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
 #define PCI_MSI_DATA_32		8	/* 16 bits of data for 32-bit devices */
 #define PCI_MSI_MASK_32		12	/* Mask bits register for 32-bit devices */
+#define PCI_MSI_PENDING_32	16	/* Pending intrs for 32-bit devices */
 #define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
 #define PCI_MSI_MASK_64		16	/* Mask bits register for 64-bit devices */
+#define PCI_MSI_PENDING_64	20	/* Pending intrs for 64-bit devices */
 
 /* MSI-X registers */
 #define PCI_MSIX_FLAGS		2
@@ -308,6 +315,7 @@
 #define PCI_MSIX_TABLE		4
 #define PCI_MSIX_PBA		8
 #define  PCI_MSIX_FLAGS_BIRMASK	(7 << 0)
+#define PCI_CAP_MSIX_SIZEOF	12	/* size of MSIX registers */
 
 /* MSI-X entry's format */
 #define PCI_MSIX_ENTRY_SIZE		16
@@ -338,6 +346,7 @@
 #define  PCI_AF_CTRL_FLR	0x01
 #define PCI_AF_STATUS		5
 #define  PCI_AF_STATUS_TP	0x01
+#define PCI_CAP_AF_SIZEOF	6	/* size of AF registers */
 
 /* PCI-X registers */
 
@@ -374,6 +383,10 @@
 #define  PCI_X_STATUS_SPL_ERR	0x20000000	/* Rcvd Split Completion Error Msg */
 #define  PCI_X_STATUS_266MHZ	0x40000000	/* 266 MHz capable */
 #define  PCI_X_STATUS_533MHZ	0x80000000	/* 533 MHz capable */
+#define PCI_X_ECC_CSR		8	/* ECC control and status */
+#define PCI_CAP_PCIX_SIZEOF_V0	8	/* size of registers for Version 0 */
+#define PCI_CAP_PCIX_SIZEOF_V1	24	/* size for Version 1 */
+#define PCI_CAP_PCIX_SIZEOF_V2	PCI_CAP_PCIX_SIZEOF_V1	/* Same for v2 */
 
 /* PCI Bridge Subsystem ID registers */
 
@@ -462,6 +475,7 @@
 #define  PCI_EXP_LNKSTA_DLLLA	0x2000	/* Data Link Layer Link Active */
 #define  PCI_EXP_LNKSTA_LBMS	0x4000	/* Link Bandwidth Management Status */
 #define  PCI_EXP_LNKSTA_LABS	0x8000	/* Link Autonomous Bandwidth Status */
+#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V1	20	/* v1 endpoints end here */
 #define PCI_EXP_SLTCAP		20	/* Slot Capabilities */
 #define  PCI_EXP_SLTCAP_ABP	0x00000001 /* Attention Button Present */
 #define  PCI_EXP_SLTCAP_PCP	0x00000002 /* Power Controller Present */
@@ -507,6 +521,12 @@
 #define PCI_EXP_RTSTA		32	/* Root Status */
 #define PCI_EXP_RTSTA_PME	0x10000 /* PME status */
 #define PCI_EXP_RTSTA_PENDING	0x20000 /* PME pending */
+/*
+ * Note that the following PCI Express 'Capability Structure' registers
+ * were introduced with 'Capability Version' 0x2 (v2).  These registers
+ * do not exist on devices with Capability Version 1.  Use pci_pcie_cap2()
+ * to use these fields safely.
+ */
 #define PCI_EXP_DEVCAP2		36	/* Device Capabilities 2 */
 #define  PCI_EXP_DEVCAP2_ARI	0x20	/* Alternative Routing-ID */
 #define  PCI_EXP_DEVCAP2_LTR	0x800	/* Latency tolerance reporting */
@@ -521,6 +541,7 @@
 #define  PCI_EXP_OBFF_MSGA_EN	0x2000	/* OBFF enable with Message type A */
 #define  PCI_EXP_OBFF_MSGB_EN	0x4000	/* OBFF enable with Message type B */
 #define  PCI_EXP_OBFF_WAKE_EN	0x6000	/* OBFF using WAKE# signaling */
+#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2	44	/* v2 endpoints end here */
 #define PCI_EXP_LNKCTL2		48	/* Link Control 2 */
 #define PCI_EXP_SLTCTL2		56	/* Slot Control 2 */
 
@@ -529,23 +550,43 @@
 #define PCI_EXT_CAP_VER(header)		((header >> 16) & 0xf)
 #define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
 
-#define PCI_EXT_CAP_ID_ERR	1
-#define PCI_EXT_CAP_ID_VC	2
-#define PCI_EXT_CAP_ID_DSN	3
-#define PCI_EXT_CAP_ID_PWR	4
-#define PCI_EXT_CAP_ID_VNDR	11
-#define PCI_EXT_CAP_ID_ACS	13
-#define PCI_EXT_CAP_ID_ARI	14
-#define PCI_EXT_CAP_ID_ATS	15
-#define PCI_EXT_CAP_ID_SRIOV	16
-#define PCI_EXT_CAP_ID_PRI	19
-#define PCI_EXT_CAP_ID_LTR	24
-#define PCI_EXT_CAP_ID_PASID	27
+#define PCI_EXT_CAP_ID_ERR	0x01	/* Advanced Error Reporting */
+#define PCI_EXT_CAP_ID_VC	0x02	/* Virtual Channel Capability */
+#define PCI_EXT_CAP_ID_DSN	0x03	/* Device Serial Number */
+#define PCI_EXT_CAP_ID_PWR	0x04	/* Power Budgeting */
+#define PCI_EXT_CAP_ID_RCLD	0x05	/* Root Complex Link Declaration */
+#define PCI_EXT_CAP_ID_RCILC	0x06	/* Root Complex Internal Link Control */
+#define PCI_EXT_CAP_ID_RCEC	0x07	/* Root Complex Event Collector */
+#define PCI_EXT_CAP_ID_MFVC	0x08	/* Multi-Function VC Capability */
+#define PCI_EXT_CAP_ID_VC9	0x09	/* same as _VC */
+#define PCI_EXT_CAP_ID_RCRB	0x0A	/* Root Complex RB? */
+#define PCI_EXT_CAP_ID_VNDR	0x0B	/* Vendor Specific */
+#define PCI_EXT_CAP_ID_CAC	0x0C	/* Config Access - obsolete */
+#define PCI_EXT_CAP_ID_ACS	0x0D	/* Access Control Services */
+#define PCI_EXT_CAP_ID_ARI	0x0E	/* Alternate Routing ID */
+#define PCI_EXT_CAP_ID_ATS	0x0F	/* Address Translation Services */
+#define PCI_EXT_CAP_ID_SRIOV	0x10	/* Single Root I/O Virtualization */
+#define PCI_EXT_CAP_ID_MRIOV	0x11	/* Multi Root I/O Virtualization */
+#define PCI_EXT_CAP_ID_MCAST	0x12	/* Multicast */
+#define PCI_EXT_CAP_ID_PRI	0x13	/* Page Request Interface */
+#define PCI_EXT_CAP_ID_AMD_XXX	0x14	/* reserved for AMD */
+#define PCI_EXT_CAP_ID_REBAR	0x15	/* resizable BAR */
+#define PCI_EXT_CAP_ID_DPA	0x16	/* dynamic power alloc */
+#define PCI_EXT_CAP_ID_TPH	0x17	/* TPH request */
+#define PCI_EXT_CAP_ID_LTR	0x18	/* latency tolerance reporting */
+#define PCI_EXT_CAP_ID_SECPCI	0x19	/* Secondary PCIe */
+#define PCI_EXT_CAP_ID_PMUX	0x1A	/* Protocol Multiplexing */
+#define PCI_EXT_CAP_ID_PASID	0x1B	/* Process Address Space ID */
+#define PCI_EXT_CAP_ID_MAX	PCI_EXT_CAP_ID_PASID
+
+#define PCI_EXT_CAP_DSN_SIZEOF	12
+#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
 
 /* Advanced Error Reporting */
 #define PCI_ERR_UNCOR_STATUS	4	/* Uncorrectable Error Status */
 #define  PCI_ERR_UNC_TRAIN	0x00000001	/* Training */
 #define  PCI_ERR_UNC_DLP	0x00000010	/* Data Link Protocol */
+#define  PCI_ERR_UNC_SURPDN	0x00000020	/* Surprise Down */
 #define  PCI_ERR_UNC_POISON_TLP	0x00001000	/* Poisoned TLP */
 #define  PCI_ERR_UNC_FCP	0x00002000	/* Flow Control Protocol */
 #define  PCI_ERR_UNC_COMP_TIME	0x00004000	/* Completion Timeout */
@@ -555,6 +596,11 @@
 #define  PCI_ERR_UNC_MALF_TLP	0x00040000	/* Malformed TLP */
 #define  PCI_ERR_UNC_ECRC	0x00080000	/* ECRC Error Status */
 #define  PCI_ERR_UNC_UNSUP	0x00100000	/* Unsupported Request */
+#define  PCI_ERR_UNC_ACSV	0x00200000	/* ACS Violation */
+#define  PCI_ERR_UNC_INTN	0x00400000	/* internal error */
+#define  PCI_ERR_UNC_MCBTLP	0x00800000	/* MC blocked TLP */
+#define  PCI_ERR_UNC_ATOMEG	0x01000000	/* Atomic egress blocked */
+#define  PCI_ERR_UNC_TLPPRE	0x02000000	/* TLP prefix blocked */
 #define PCI_ERR_UNCOR_MASK	8	/* Uncorrectable Error Mask */
 	/* Same bits as above */
 #define PCI_ERR_UNCOR_SEVER	12	/* Uncorrectable Error Severity */
@@ -565,6 +611,9 @@
 #define  PCI_ERR_COR_BAD_DLLP	0x00000080	/* Bad DLLP Status */
 #define  PCI_ERR_COR_REP_ROLL	0x00000100	/* REPLAY_NUM Rollover */
 #define  PCI_ERR_COR_REP_TIMER	0x00001000	/* Replay Timer Timeout */
+#define  PCI_ERR_COR_ADV_NFAT	0x00002000	/* Advisory Non-Fatal */
+#define  PCI_ERR_COR_INTERNAL	0x00004000	/* Corrected Internal */
+#define  PCI_ERR_COR_LOG_OVER	0x00008000	/* Header Log Overflow */
 #define PCI_ERR_COR_MASK	20	/* Correctable Error Mask */
 	/* Same bits as above */
 #define PCI_ERR_CAP		24	/* Advanced Error Capabilities */
@@ -596,12 +645,18 @@
 
 /* Virtual Channel */
 #define PCI_VC_PORT_REG1	4
+#define  PCI_VC_REG1_EVCC	0x7	/* extended vc count */
 #define PCI_VC_PORT_REG2	8
+#define  PCI_VC_REG2_32_PHASE	0x2
+#define  PCI_VC_REG2_64_PHASE	0x4
+#define  PCI_VC_REG2_128_PHASE	0x8
 #define PCI_VC_PORT_CTRL	12
 #define PCI_VC_PORT_STATUS	14
 #define PCI_VC_RES_CAP		16
 #define PCI_VC_RES_CTRL		20
 #define PCI_VC_RES_STATUS	26
+#define PCI_CAP_VC_BASE_SIZEOF		0x10
+#define PCI_CAP_VC_PER_VC_SIZEOF	0x0C
 
 /* Power Budgeting */
 #define PCI_PWR_DSR		4	/* Data Select Register */
@@ -614,6 +669,7 @@
 #define  PCI_PWR_DATA_RAIL(x)	(((x) >> 18) & 7)   /* Power Rail */
 #define PCI_PWR_CAP		12	/* Capability */
 #define  PCI_PWR_CAP_BUDGET(x)	((x) & 1)	/* Included in system budget */
+#define PCI_EXT_CAP_PWR_SIZEOF	16
 
 /*
  * Hypertransport sub capability types
@@ -646,6 +702,8 @@
 #define HT_CAPTYPE_ERROR_RETRY	0xC0	/* Retry on error configuration */
 #define HT_CAPTYPE_GEN3		0xD0	/* Generation 3 hypertransport configuration */
 #define HT_CAPTYPE_PM		0xE0	/* Hypertransport powermanagement configuration */
+#define HT_CAP_SIZEOF_LONG	28	/* slave & primary */
+#define HT_CAP_SIZEOF_SHORT	24	/* host & secondary */
 
 /* Alternative Routing-ID Interpretation */
 #define PCI_ARI_CAP		0x04	/* ARI Capability Register */
@@ -656,6 +714,7 @@
 #define  PCI_ARI_CTRL_MFVC	0x0001	/* MFVC Function Groups Enable */
 #define  PCI_ARI_CTRL_ACS	0x0002	/* ACS Function Groups Enable */
 #define  PCI_ARI_CTRL_FG(x)	(((x) >> 4) & 7) /* Function Group */
+#define PCI_EXT_CAP_ARI_SIZEOF	8
 
 /* Address Translation Service */
 #define PCI_ATS_CAP		0x04	/* ATS Capability Register */
@@ -665,6 +724,7 @@
 #define  PCI_ATS_CTRL_ENABLE	0x8000	/* ATS Enable */
 #define  PCI_ATS_CTRL_STU(x)	((x) & 0x1f)	/* Smallest Translation Unit */
 #define  PCI_ATS_MIN_STU	12	/* shift of minimum STU block */
+#define PCI_EXT_CAP_ATS_SIZEOF	8
 
 /* Page Request Interface */
 #define PCI_PRI_CTRL		0x04	/* PRI control register */
@@ -676,6 +736,7 @@
 #define  PCI_PRI_STATUS_STOPPED	0x100	/* PRI Stopped */
 #define PCI_PRI_MAX_REQ		0x08	/* PRI max reqs supported */
 #define PCI_PRI_ALLOC_REQ	0x0c	/* PRI max reqs allowed */
+#define PCI_EXT_CAP_PRI_SIZEOF	16
 
 /* PASID capability */
 #define PCI_PASID_CAP		0x04    /* PASID feature register */
@@ -685,6 +746,7 @@
 #define  PCI_PASID_CTRL_ENABLE	0x01	/* Enable bit */
 #define  PCI_PASID_CTRL_EXEC	0x02	/* Exec permissions Enable */
 #define  PCI_PASID_CTRL_PRIV	0x04	/* Priviledge Mode Enable */
+#define PCI_EXT_CAP_PASID_SIZEOF	8
 
 /* Single Root I/O Virtualization */
 #define PCI_SRIOV_CAP		0x04	/* SR-IOV Capabilities */
@@ -716,12 +778,14 @@
 #define  PCI_SRIOV_VFM_MI	0x1	/* Dormant.MigrateIn */
 #define  PCI_SRIOV_VFM_MO	0x2	/* Active.MigrateOut */
 #define  PCI_SRIOV_VFM_AV	0x3	/* Active.Available */
+#define PCI_EXT_CAP_SRIOV_SIZEOF 64
 
 #define PCI_LTR_MAX_SNOOP_LAT	0x4
 #define PCI_LTR_MAX_NOSNOOP_LAT	0x6
 #define  PCI_LTR_VALUE_MASK	0x000003ff
 #define  PCI_LTR_SCALE_MASK	0x00001c00
 #define  PCI_LTR_SCALE_SHIFT	10
+#define PCI_EXT_CAP_LTR_SIZEOF	8
 
 /* Access Control Service */
 #define PCI_ACS_CAP		0x04	/* ACS Capability Register */
@@ -732,7 +796,38 @@
 #define  PCI_ACS_UF		0x10	/* Upstream Forwarding */
 #define  PCI_ACS_EC		0x20	/* P2P Egress Control */
 #define  PCI_ACS_DT		0x40	/* Direct Translated P2P */
+#define PCI_ACS_EGRESS_BITS	0x05	/* ACS Egress Control Vector Size */
 #define PCI_ACS_CTRL		0x06	/* ACS Control Register */
 #define PCI_ACS_EGRESS_CTL_V	0x08	/* ACS Egress Control Vector */
 
+#define PCI_VSEC_HDR		4	/* extended cap - vendor specific */
+#define  PCI_VSEC_HDR_LEN_SHIFT	20	/* shift for length field */
+
+/* sata capability */
+#define PCI_SATA_REGS		4	/* SATA REGs specifier */
+#define  PCI_SATA_REGS_MASK	0xF	/* location - BAR#/inline */
+#define  PCI_SATA_REGS_INLINE	0xF	/* REGS in config space */
+#define PCI_SATA_SIZEOF_SHORT	8
+#define PCI_SATA_SIZEOF_LONG	16
+
+/* resizable BARs */
+#define PCI_REBAR_CTRL		8	/* control register */
+#define  PCI_REBAR_CTRL_NBAR_MASK	(7 << 5)	/* mask for # bars */
+#define  PCI_REBAR_CTRL_NBAR_SHIFT	5	/* shift for # bars */
+
+/* dynamic power allocation */
+#define PCI_DPA_CAP		4	/* capability register */
+#define  PCI_DPA_CAP_SUBSTATE_MASK	0x1F	/* # substates - 1 */
+#define PCI_DPA_BASE_SIZEOF	16	/* size with 0 substates */
+
+/* TPH Requester */
+#define PCI_TPH_CAP		4	/* capability register */
+#define  PCI_TPH_CAP_LOC_MASK	0x600	/* location mask */
+#define   PCI_TPH_LOC_NONE	0x000	/* no location */
+#define   PCI_TPH_LOC_CAP	0x200	/* in capability */
+#define   PCI_TPH_LOC_MSIX	0x400	/* in MSI-X */
+#define PCI_TPH_CAP_ST_MASK	0x07FF0000	/* st table mask */
+#define PCI_TPH_CAP_ST_SHIFT	16	/* st table shift */
+#define PCI_TPH_BASE_SIZEOF	12	/* size with no st table */
+
 #endif /* LINUX_PCI_REGS_H */
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 45db49f..76c5c8b 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -677,6 +677,7 @@ struct hw_perf_event {
 			u64		last_tag;
 			unsigned long	config_base;
 			unsigned long	event_base;
+			int		event_base_rdpmc;
 			int		idx;
 			int		last_cpu;
 
@@ -1106,6 +1107,8 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr,
 				struct task_struct *task,
 				perf_overflow_handler_t callback,
 				void *context);
+extern void perf_pmu_migrate_context(struct pmu *pmu,
+				int src_cpu, int dst_cpu);
 extern u64 perf_event_read_value(struct perf_event *event,
 				 u64 *enabled, u64 *running);
 
diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
index 3b894a6..69393a6 100644
--- a/include/linux/pinctrl/pinctrl.h
+++ b/include/linux/pinctrl/pinctrl.h
@@ -131,8 +131,9 @@ extern void pinctrl_unregister(struct pinctrl_dev *pctldev);
 extern bool pin_is_valid(struct pinctrl_dev *pctldev, int pin);
 extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
 				struct pinctrl_gpio_range *range);
-extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
-				struct pinctrl_gpio_range *range);
+extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
+				struct pinctrl_gpio_range *ranges,
+				unsigned nranges);
 extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
 extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
 #else
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index e1ac1ce..e11d1c0 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -86,11 +86,9 @@ struct pipe_buf_operations {
 	 * mapping or not. The atomic map is faster, however you can't take
 	 * page faults before calling ->unmap() again. So if you need to eg
 	 * access user data through copy_to/from_user(), then you must get
-	 * a non-atomic map. ->map() uses the KM_USER0 atomic slot for
-	 * atomic maps, so you can't map more than one pipe_buffer at once
-	 * and you have to be careful if mapping another page as source
-	 * or destination for a copy (IOW, it has to use something else
-	 * than KM_USER0).
+	 * a non-atomic map. ->map() uses the kmap_atomic slot for
+	 * atomic maps, you have to be careful if mapping another page as
+	 * source or destination for a copy.
 	 */
 	void * (*map)(struct pipe_inode_info *, struct pipe_buffer *, int);
 
diff --git a/include/linux/platform_data/clk-nomadik.h b/include/linux/platform_data/clk-nomadik.h
new file mode 100644
index 0000000..5713c87
--- /dev/null
+++ b/include/linux/platform_data/clk-nomadik.h
@@ -0,0 +1,2 @@
+/* Minimal platform data header */
+void nomadik_clk_init(void);
diff --git a/include/linux/platform_data/leds-lm3556.h b/include/linux/platform_data/leds-lm3556.h
new file mode 100644
index 0000000..4b4e7d6
--- /dev/null
+++ b/include/linux/platform_data/leds-lm3556.h
@@ -0,0 +1,50 @@
+/*
+ * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __LINUX_LM3556_H
+#define __LINUX_LM3556_H
+
+#define LM3556_NAME "leds-lm3556"
+
+enum lm3556_pin_polarity {
+	PIN_LOW_ACTIVE = 0,
+	PIN_HIGH_ACTIVE,
+};
+
+enum lm3556_pin_enable {
+	PIN_DISABLED = 0,
+	PIN_ENABLED,
+};
+
+enum lm3556_strobe_usuage {
+	STROBE_EDGE_DETECT = 0,
+	STROBE_LEVEL_DETECT,
+};
+
+enum lm3556_indic_mode {
+	INDIC_MODE_INTERNAL = 0,
+	INDIC_MODE_EXTERNAL,
+};
+
+struct lm3556_platform_data {
+	enum lm3556_pin_enable torch_pin_en;
+	enum lm3556_pin_polarity torch_pin_polarity;
+
+	enum lm3556_strobe_usuage strobe_usuage;
+	enum lm3556_pin_enable strobe_pin_en;
+	enum lm3556_pin_polarity strobe_pin_polarity;
+
+	enum lm3556_pin_enable tx_pin_en;
+	enum lm3556_pin_polarity tx_pin_polarity;
+
+	enum lm3556_indic_mode indicator_mode;
+};
+
+#endif /* __LINUX_LM3556_H */
diff --git a/include/linux/platform_data/mmp_audio.h b/include/linux/platform_data/mmp_audio.h
new file mode 100644
index 0000000..0f25d16
--- /dev/null
+++ b/include/linux/platform_data/mmp_audio.h
@@ -0,0 +1,22 @@
+/*
+ *  MMP Platform AUDIO Management
+ *
+ *  Copyright (c) 2011 Marvell Semiconductors Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#ifndef MMP_AUDIO_H
+#define MMP_AUDIO_H
+
+struct mmp_audio_platdata {
+	u32 period_max_capture;
+	u32 buffer_max_capture;
+	u32 period_max_playback;
+	u32 buffer_max_playback;
+};
+
+#endif /* MMP_AUDIO_H */
diff --git a/include/linux/platform_data/mv_usb.h b/include/linux/platform_data/mv_usb.h
index d94804a..944b01d 100644
--- a/include/linux/platform_data/mv_usb.h
+++ b/include/linux/platform_data/mv_usb.h
@@ -52,13 +52,4 @@ struct mv_usb_platform_data {
 	int	(*set_vbus)(unsigned int vbus);
 	int     (*private_init)(void __iomem *opregs, void __iomem *phyregs);
 };
-
-#ifndef CONFIG_HAVE_CLK
-/* Dummy stub for clk framework */
-#define clk_get(dev, id)       NULL
-#define clk_put(clock)         do {} while (0)
-#define clk_enable(clock)      do {} while (0)
-#define clk_disable(clock)     do {} while (0)
-#endif
-
 #endif
diff --git a/include/linux/platform_data/spear_thermal.h b/include/linux/platform_data/spear_thermal.h
deleted file mode 100644
index 724f2e1..0000000
--- a/include/linux/platform_data/spear_thermal.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SPEAr thermal driver platform data.
- *
- * Copyright (C) 2011-2012 ST Microelectronics
- * Author: Vincenzo Frascino <vincenzo.frascino@st.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-#ifndef SPEAR_THERMAL_H
-#define SPEAR_THERMAL_H
-
-/* SPEAr Thermal Sensor Platform Data */
-struct spear_thermal_pdata {
-	/* flags used to enable thermal sensor */
-	unsigned int thermal_flags;
-};
-
-#endif /* SPEAR_THERMAL_H */
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 30f794e..2febe31 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -15,6 +15,7 @@
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/notifier.h>
+#include <linux/cpuidle.h>
 
 enum gpd_status {
 	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
@@ -45,6 +46,11 @@ struct gpd_dev_ops {
 	bool (*active_wakeup)(struct device *dev);
 };
 
+struct gpd_cpu_data {
+	unsigned int saved_exit_latency;
+	struct cpuidle_state *idle_state;
+};
+
 struct generic_pm_domain {
 	struct dev_pm_domain domain;	/* PM domain operations */
 	struct list_head gpd_list_node;	/* Node in the global PM domains list */
@@ -75,6 +81,7 @@ struct generic_pm_domain {
 	bool max_off_time_changed;
 	bool cached_power_down_ok;
 	struct device_node *of_node; /* Node in device tree */
+	struct gpd_cpu_data *cpu_data;
 };
 
 static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
@@ -155,6 +162,8 @@ extern int pm_genpd_add_callbacks(struct device *dev,
 				  struct gpd_dev_ops *ops,
 				  struct gpd_timing_data *td);
 extern int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td);
+extern int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state);
+extern int genpd_detach_cpuidle(struct generic_pm_domain *genpd);
 extern void pm_genpd_init(struct generic_pm_domain *genpd,
 			  struct dev_power_governor *gov, bool is_off);
 
@@ -211,6 +220,14 @@ static inline int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
 {
 	return -ENOSYS;
 }
+static inline int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int st)
+{
+	return -ENOSYS;
+}
+static inline int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
+{
+	return -ENOSYS;
+}
 static inline void pm_genpd_init(struct generic_pm_domain *genpd,
 				 struct dev_power_governor *gov, bool is_off)
 {
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 3b912be..53f177d 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -109,6 +109,8 @@ enum power_supply_property {
 	POWER_SUPPLY_PROP_CHARGE_NOW,
 	POWER_SUPPLY_PROP_CHARGE_AVG,
 	POWER_SUPPLY_PROP_CHARGE_COUNTER,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
 	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
 	POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
 	POWER_SUPPLY_PROP_ENERGY_FULL,
@@ -173,6 +175,9 @@ struct power_supply {
 	/* private */
 	struct device *dev;
 	struct work_struct changed_work;
+#ifdef CONFIG_THERMAL
+	struct thermal_zone_device *tzd;
+#endif
 
 #ifdef CONFIG_LEDS_TRIGGERS
 	struct led_trigger *charging_full_trig;
@@ -236,6 +241,7 @@ static inline bool power_supply_is_amp_property(enum power_supply_property psp)
 	case POWER_SUPPLY_PROP_CHARGE_NOW:
 	case POWER_SUPPLY_PROP_CHARGE_AVG:
 	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
 	case POWER_SUPPLY_PROP_CURRENT_MAX:
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
 	case POWER_SUPPLY_PROP_CURRENT_AVG:
@@ -263,6 +269,7 @@ static inline bool power_supply_is_watt_property(enum power_supply_property psp)
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
 	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
 	case POWER_SUPPLY_PROP_POWER_NOW:
 		return 1;
 	default:
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 1bec2f7..9afc01e 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -2,27 +2,34 @@
 #define __KERNEL_PRINTK__
 
 #include <linux/init.h>
+#include <linux/kern_levels.h>
 
 extern const char linux_banner[];
 extern const char linux_proc_banner[];
 
-#define KERN_EMERG	"<0>"	/* system is unusable			*/
-#define KERN_ALERT	"<1>"	/* action must be taken immediately	*/
-#define KERN_CRIT	"<2>"	/* critical conditions			*/
-#define KERN_ERR	"<3>"	/* error conditions			*/
-#define KERN_WARNING	"<4>"	/* warning conditions			*/
-#define KERN_NOTICE	"<5>"	/* normal but significant condition	*/
-#define KERN_INFO	"<6>"	/* informational			*/
-#define KERN_DEBUG	"<7>"	/* debug-level messages			*/
-
-/* Use the default kernel loglevel */
-#define KERN_DEFAULT	"<d>"
-/*
- * Annotation for a "continued" line of log printout (only done after a
- * line that had no enclosing \n). Only to be used by core/arch code
- * during early bootup (a continued line is not SMP-safe otherwise).
- */
-#define KERN_CONT	"<c>"
+static inline int printk_get_level(const char *buffer)
+{
+	if (buffer[0] == KERN_SOH_ASCII && buffer[1]) {
+		switch (buffer[1]) {
+		case '0' ... '7':
+		case 'd':	/* KERN_DEFAULT */
+			return buffer[1];
+		}
+	}
+	return 0;
+}
+
+static inline const char *printk_skip_level(const char *buffer)
+{
+	if (printk_get_level(buffer)) {
+		switch (buffer[1]) {
+		case '0' ... '7':
+		case 'd':	/* KERN_DEFAULT */
+			return buffer + 2;
+		}
+	}
+	return buffer;
+}
 
 extern int console_printk[];
 
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index e1461e1..1bd014b 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -29,6 +29,7 @@
 enum pstore_type_id {
 	PSTORE_TYPE_DMESG	= 0,
 	PSTORE_TYPE_MCE		= 1,
+	PSTORE_TYPE_CONSOLE	= 2,
 	PSTORE_TYPE_UNKNOWN	= 255
 };
 
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
index 3b823d4..e681af9 100644
--- a/include/linux/pstore_ram.h
+++ b/include/linux/pstore_ram.h
@@ -25,21 +25,6 @@
 
 struct persistent_ram_buffer;
 
-struct persistent_ram_descriptor {
-	const char	*name;
-	phys_addr_t	size;
-};
-
-struct persistent_ram {
-	phys_addr_t	start;
-	phys_addr_t	size;
-
-	int					num_descs;
-	struct persistent_ram_descriptor	*descs;
-
-	struct list_head node;
-};
-
 struct persistent_ram_zone {
 	phys_addr_t paddr;
 	size_t size;
@@ -63,15 +48,11 @@ struct persistent_ram_zone {
 	size_t old_log_size;
 };
 
-int persistent_ram_early_init(struct persistent_ram *ram);
-
-struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
-						       size_t size,
-						       bool ecc);
+struct persistent_ram_zone * __devinit persistent_ram_new(phys_addr_t start,
+							  size_t size,
+							  bool ecc);
 void persistent_ram_free(struct persistent_ram_zone *prz);
 void persistent_ram_zap(struct persistent_ram_zone *prz);
-struct persistent_ram_zone *persistent_ram_init_ringbuffer(struct device *dev,
-		bool ecc);
 
 int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
 	unsigned int count);
@@ -93,6 +74,7 @@ struct ramoops_platform_data {
 	unsigned long	mem_size;
 	unsigned long	mem_address;
 	unsigned long	record_size;
+	unsigned long	console_size;
 	int		dump_oops;
 	bool		ecc;
 };
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 26d1a47..817a2f2 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -147,6 +147,7 @@ extern void synchronize_sched(void);
 
 extern void __rcu_read_lock(void);
 extern void __rcu_read_unlock(void);
+extern void rcu_read_unlock_special(struct task_struct *t);
 void synchronize_rcu(void);
 
 /*
@@ -256,6 +257,10 @@ static inline void destroy_rcu_head_on_stack(struct rcu_head *head)
 }
 #endif	/* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 
+#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SMP)
+extern int rcu_is_cpu_idle(void);
+#endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SMP) */
+
 #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU)
 bool rcu_lockdep_current_cpu_online(void);
 #else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
@@ -267,15 +272,6 @@ static inline bool rcu_lockdep_current_cpu_online(void)
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 
-#ifdef CONFIG_PROVE_RCU
-extern int rcu_is_cpu_idle(void);
-#else /* !CONFIG_PROVE_RCU */
-static inline int rcu_is_cpu_idle(void)
-{
-	return 0;
-}
-#endif /* else !CONFIG_PROVE_RCU */
-
 static inline void rcu_lock_acquire(struct lockdep_map *map)
 {
 	lock_acquire(map, 0, 0, 2, 1, NULL, _THIS_IP_);
@@ -514,10 +510,10 @@ static inline void rcu_preempt_sleep_check(void)
 		(_________p1); \
 	})
 #define __rcu_assign_pointer(p, v, space) \
-	({ \
+	do { \
 		smp_wmb(); \
 		(p) = (typeof(*v) __force space *)(v); \
-	})
+	} while (0)
 
 
 /**
@@ -852,7 +848,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
  *
  * Assigns the specified value to the specified RCU-protected
  * pointer, ensuring that any concurrent RCU readers will see
- * any prior initialization.  Returns the value assigned.
+ * any prior initialization.
  *
  * Inserts memory barriers on architectures that require them
  * (which is most of them), and also prevents the compiler from
@@ -904,25 +900,17 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
  * the reader-accessible portions of the linked structure.
  */
 #define RCU_INIT_POINTER(p, v) \
-		p = (typeof(*v) __force __rcu *)(v)
-
-static __always_inline bool __is_kfree_rcu_offset(unsigned long offset)
-{
-	return offset < 4096;
-}
-
-static __always_inline
-void __kfree_rcu(struct rcu_head *head, unsigned long offset)
-{
-	typedef void (*rcu_callback)(struct rcu_head *);
-
-	BUILD_BUG_ON(!__builtin_constant_p(offset));
-
-	/* See the kfree_rcu() header comment. */
-	BUILD_BUG_ON(!__is_kfree_rcu_offset(offset));
+	do { \
+		p = (typeof(*v) __force __rcu *)(v); \
+	} while (0)
 
-	kfree_call_rcu(head, (rcu_callback)offset);
-}
+/**
+ * RCU_POINTER_INITIALIZER() - statically initialize an RCU protected pointer
+ *
+ * GCC-style initialization for an RCU-protected pointer in a structure field.
+ */
+#define RCU_POINTER_INITIALIZER(p, v) \
+		.p = (typeof(*v) __force __rcu *)(v)
 
 /*
  * Does the specified offset indicate that the corresponding rcu_head
@@ -936,7 +924,7 @@ void __kfree_rcu(struct rcu_head *head, unsigned long offset)
 #define __kfree_rcu(head, offset) \
 	do { \
 		BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); \
-		call_rcu(head, (void (*)(struct rcu_head *))(unsigned long)(offset)); \
+		kfree_call_rcu(head, (void (*)(struct rcu_head *))(unsigned long)(offset)); \
 	} while (0)
 
 /**
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 56af22e..7f7e00d 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -14,12 +14,14 @@
  */
 
 #include <linux/list.h>
+#include <linux/rbtree.h>
 
 struct module;
 struct device;
 struct i2c_client;
 struct spi_device;
 struct regmap;
+struct regmap_range_cfg;
 
 /* An enum of all the supported cache types */
 enum regcache_type {
@@ -43,6 +45,14 @@ struct reg_default {
 
 #ifdef CONFIG_REGMAP
 
+enum regmap_endian {
+	/* Unspecified -> 0 -> Backwards compatible default */
+	REGMAP_ENDIAN_DEFAULT = 0,
+	REGMAP_ENDIAN_BIG,
+	REGMAP_ENDIAN_LITTLE,
+	REGMAP_ENDIAN_NATIVE,
+};
+
 /**
  * Configuration for the register map of a device.
  *
@@ -84,6 +94,15 @@ struct reg_default {
  * @reg_defaults_raw: Power on reset values for registers (for use with
  *                    register cache support).
  * @num_reg_defaults_raw: Number of elements in reg_defaults_raw.
+ * @reg_format_endian: Endianness for formatted register addresses. If this is
+ *                     DEFAULT, the @reg_format_endian_default value from the
+ *                     regmap bus is used.
+ * @val_format_endian: Endianness for formatted register values. If this is
+ *                     DEFAULT, the @reg_format_endian_default value from the
+ *                     regmap bus is used.
+ *
+ * @ranges: Array of configuration entries for virtual address ranges.
+ * @num_ranges: Number of range configuration entries.
  */
 struct regmap_config {
 	const char *name;
@@ -109,6 +128,43 @@ struct regmap_config {
 	u8 write_flag_mask;
 
 	bool use_single_rw;
+
+	enum regmap_endian reg_format_endian;
+	enum regmap_endian val_format_endian;
+
+	const struct regmap_range_cfg *ranges;
+	unsigned int n_ranges;
+};
+
+/**
+ * Configuration for indirectly accessed or paged registers.
+ * Registers, mapped to this virtual range, are accessed in two steps:
+ *     1. page selector register update;
+ *     2. access through data window registers.
+ *
+ * @range_min: Address of the lowest register address in virtual range.
+ * @range_max: Address of the highest register in virtual range.
+ *
+ * @page_sel_reg: Register with selector field.
+ * @page_sel_mask: Bit shift for selector value.
+ * @page_sel_shift: Bit mask for selector value.
+ *
+ * @window_start: Address of first (lowest) register in data window.
+ * @window_len: Number of registers in data window.
+ */
+struct regmap_range_cfg {
+	/* Registers of virtual address range */
+	unsigned int range_min;
+	unsigned int range_max;
+
+	/* Page selector for indirect addressing */
+	unsigned int selector_reg;
+	unsigned int selector_mask;
+	int selector_shift;
+
+	/* Data window (per each page) */
+	unsigned int window_start;
+	unsigned int window_len;
 };
 
 typedef int (*regmap_hw_write)(void *context, const void *data,
@@ -133,6 +189,12 @@ typedef void (*regmap_hw_free_context)(void *context);
  *         data.
  * @read_flag_mask: Mask to be set in the top byte of the register when doing
  *                  a read.
+ * @reg_format_endian_default: Default endianness for formatted register
+ *     addresses. Used when the regmap_config specifies DEFAULT. If this is
+ *     DEFAULT, BIG is assumed.
+ * @val_format_endian_default: Default endianness for formatted register
+ *     values. Used when the regmap_config specifies DEFAULT. If this is
+ *     DEFAULT, BIG is assumed.
  */
 struct regmap_bus {
 	bool fast_io;
@@ -141,6 +203,8 @@ struct regmap_bus {
 	regmap_hw_read read;
 	regmap_hw_free_context free_context;
 	u8 read_flag_mask;
+	enum regmap_endian reg_format_endian_default;
+	enum regmap_endian val_format_endian_default;
 };
 
 struct regmap *regmap_init(struct device *dev,
@@ -219,6 +283,7 @@ struct regmap_irq {
  * @status_base: Base status register address.
  * @mask_base:   Base mask register address.
  * @ack_base:    Base ack address.  If zero then the chip is clear on read.
+ * @wake_base:   Base address for wake enables.  If zero unsupported.
  * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
  *
  * @num_regs:    Number of registers in each control bank.
@@ -232,6 +297,7 @@ struct regmap_irq_chip {
 	unsigned int status_base;
 	unsigned int mask_base;
 	unsigned int ack_base;
+	unsigned int wake_base;
 	unsigned int irq_reg_stride;
 
 	int num_regs;
@@ -243,7 +309,7 @@ struct regmap_irq_chip {
 struct regmap_irq_chip_data;
 
 int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
-			int irq_base, struct regmap_irq_chip *chip,
+			int irq_base, const struct regmap_irq_chip *chip,
 			struct regmap_irq_chip_data **data);
 void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
 int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
@@ -361,7 +427,6 @@ static inline int regmap_register_patch(struct regmap *map,
 static inline struct regmap *dev_get_regmap(struct device *dev,
 					    const char *name)
 {
-	WARN_ONCE(1, "regmap API is disabled");
 	return NULL;
 }
 
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index 4ed1b30..9ff29ef 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -291,7 +291,7 @@ static inline int regulator_set_voltage(struct regulator *regulator,
 
 static inline int regulator_get_voltage(struct regulator *regulator)
 {
-	return 0;
+	return -EINVAL;
 }
 
 static inline int regulator_set_current_limit(struct regulator *regulator,
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index b0432cc..84f999ed 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -67,6 +67,8 @@ enum regulator_status {
  *
  * @enable_time: Time taken for the regulator voltage output voltage to
  *               stabilise after being enabled, in microseconds.
+ * @set_ramp_delay: Set the ramp delay for the regulator. The driver should
+ *		select ramp delay equal to or less than(closest) ramp_delay.
  * @set_voltage_time_sel: Time taken for the regulator voltage output voltage
  *               to stabilise after being set to a new value, in microseconds.
  *               The function provides the from and to voltage selector, the
@@ -113,6 +115,7 @@ struct regulator_ops {
 
 	/* Time taken to enable or set voltage on the regulator */
 	int (*enable_time) (struct regulator_dev *);
+	int (*set_ramp_delay) (struct regulator_dev *, int ramp_delay);
 	int (*set_voltage_time_sel) (struct regulator_dev *,
 				     unsigned int old_selector,
 				     unsigned int new_selector);
@@ -170,6 +173,8 @@ enum regulator_type {
  *
  * @min_uV: Voltage given by the lowest selector (if linear mapping)
  * @uV_step: Voltage increase with each selector (if linear mapping)
+ * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
+ * @volt_table: Voltage mapping table (if table based mapping)
  *
  * @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
  * @vsel_mask: Mask for register bitfield used for selector
@@ -188,6 +193,9 @@ struct regulator_desc {
 
 	unsigned int min_uV;
 	unsigned int uV_step;
+	unsigned int ramp_delay;
+
+	const unsigned int *volt_table;
 
 	unsigned int vsel_reg;
 	unsigned int vsel_mask;
@@ -271,6 +279,8 @@ int regulator_mode_to_status(unsigned int);
 
 int regulator_list_voltage_linear(struct regulator_dev *rdev,
 				  unsigned int selector);
+int regulator_list_voltage_table(struct regulator_dev *rdev,
+				  unsigned int selector);
 int regulator_map_voltage_linear(struct regulator_dev *rdev,
 				  int min_uV, int max_uV);
 int regulator_map_voltage_iterate(struct regulator_dev *rdev,
@@ -280,6 +290,9 @@ int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel);
 int regulator_is_enabled_regmap(struct regulator_dev *rdev);
 int regulator_enable_regmap(struct regulator_dev *rdev);
 int regulator_disable_regmap(struct regulator_dev *rdev);
+int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+				   unsigned int old_selector,
+				   unsigned int new_selector);
 
 void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
 
diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h
index f83f744..680f24e 100644
--- a/include/linux/regulator/fixed.h
+++ b/include/linux/regulator/fixed.h
@@ -58,14 +58,17 @@ struct fixed_voltage_config {
 struct regulator_consumer_supply;
 
 #if IS_ENABLED(CONFIG_REGULATOR)
-struct platform_device *regulator_register_fixed(int id,
-		struct regulator_consumer_supply *supplies, int num_supplies);
+struct platform_device *regulator_register_always_on(int id, const char *name,
+		struct regulator_consumer_supply *supplies, int num_supplies, int uv);
 #else
-static inline struct platform_device *regulator_register_fixed(int id,
-		struct regulator_consumer_supply *supplies, int num_supplies)
+static inline struct platform_device *regulator_register_always_on(int id, const char *name,
+		struct regulator_consumer_supply *supplies, int num_supplies, int uv)
 {
 	return NULL;
 }
 #endif
 
+#define regulator_register_fixed(id, s, ns) regulator_register_always_on(id, \
+						"fixed-dummy", s, ns, 0)
+
 #endif
diff --git a/include/linux/regulator/lp872x.h b/include/linux/regulator/lp872x.h
new file mode 100644
index 0000000..132e05c
--- /dev/null
+++ b/include/linux/regulator/lp872x.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __LP872X_REGULATOR_H__
+#define __LP872X_REGULATOR_H__
+
+#include <linux/regulator/machine.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#define LP872X_MAX_REGULATORS		9
+
+enum lp872x_regulator_id {
+	LP8720_ID_BASE,
+	LP8720_ID_LDO1 = LP8720_ID_BASE,
+	LP8720_ID_LDO2,
+	LP8720_ID_LDO3,
+	LP8720_ID_LDO4,
+	LP8720_ID_LDO5,
+	LP8720_ID_BUCK,
+
+	LP8725_ID_BASE,
+	LP8725_ID_LDO1 = LP8725_ID_BASE,
+	LP8725_ID_LDO2,
+	LP8725_ID_LDO3,
+	LP8725_ID_LDO4,
+	LP8725_ID_LDO5,
+	LP8725_ID_LILO1,
+	LP8725_ID_LILO2,
+	LP8725_ID_BUCK1,
+	LP8725_ID_BUCK2,
+
+	LP872X_ID_MAX,
+};
+
+enum lp872x_dvs_state {
+	DVS_LOW  = GPIOF_OUT_INIT_LOW,
+	DVS_HIGH = GPIOF_OUT_INIT_HIGH,
+};
+
+enum lp872x_dvs_sel {
+	SEL_V1,
+	SEL_V2,
+};
+
+/**
+ * lp872x_dvs
+ * @gpio       : gpio pin number for dvs control
+ * @vsel       : dvs selector for buck v1 or buck v2 register
+ * @init_state : initial dvs pin state
+ */
+struct lp872x_dvs {
+	int gpio;
+	enum lp872x_dvs_sel vsel;
+	enum lp872x_dvs_state init_state;
+};
+
+/**
+ * lp872x_regdata
+ * @id        : regulator id
+ * @init_data : init data for each regulator
+ */
+struct lp872x_regulator_data {
+	enum lp872x_regulator_id id;
+	struct regulator_init_data *init_data;
+};
+
+/**
+ * lp872x_platform_data
+ * @general_config    : the value of LP872X_GENERAL_CFG register
+ * @update_config     : if LP872X_GENERAL_CFG register is updated, set true
+ * @regulator_data    : platform regulator id and init data
+ * @dvs               : dvs data for buck voltage control
+ */
+struct lp872x_platform_data {
+	u8 general_config;
+	bool update_config;
+	struct lp872x_regulator_data regulator_data[LP872X_MAX_REGULATORS];
+	struct lp872x_dvs *dvs;
+};
+
+#endif
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index b021084..40dd0a3 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -92,6 +92,7 @@ struct regulator_state {
  *                 mode.
  * @initial_state: Suspend state to set by default.
  * @initial_mode: Mode to set at startup.
+ * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
  */
 struct regulation_constraints {
 
@@ -125,6 +126,8 @@ struct regulation_constraints {
 	/* mode to set on startup */
 	unsigned int initial_mode;
 
+	unsigned int ramp_delay;
+
 	/* constraint flags */
 	unsigned always_on:1;	/* regulator never off when system is on */
 	unsigned boot_on:1;	/* bootloader/firmware enabled regulator */
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index f1ffabb..c20d8f5 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -42,6 +42,7 @@
 #include <linux/virtio.h>
 #include <linux/completion.h>
 #include <linux/idr.h>
+#include <linux/firmware.h>
 
 /**
  * struct resource_table - firmware resource table header
@@ -339,6 +340,23 @@ struct rproc_ops {
 };
 
 /**
+ * struct rproc_fw_ops - firmware format specific operations.
+ * @find_rsc_table:	finds the resource table inside the firmware image
+ * @load:		load firmeware to memory, where the remote processor
+ *			expects to find it
+ * @sanity_check:	sanity check the fw image
+ * @get_boot_addr:	get boot address to entry point specified in firmware
+ */
+struct rproc_fw_ops {
+	struct resource_table *(*find_rsc_table) (struct rproc *rproc,
+						const struct firmware *fw,
+						int *tablesz);
+	int (*load)(struct rproc *rproc, const struct firmware *fw);
+	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
+	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
+};
+
+/**
  * enum rproc_state - remote processor states
  * @RPROC_OFFLINE:	device is powered off
  * @RPROC_SUSPENDED:	device is suspended; needs to be woken up to receive
@@ -369,6 +387,7 @@ enum rproc_state {
  * @firmware: name of firmware file to be loaded
  * @priv: private data which belongs to the platform-specific rproc module
  * @ops: platform-specific start/stop rproc handlers
+ * @fw_ops: firmware-specific handlers
  * @dev: underlying device
  * @refcount: refcount of users that have a valid pointer to this rproc
  * @power: refcount of users who need this rproc powered up
@@ -391,6 +410,7 @@ struct rproc {
 	const char *firmware;
 	void *priv;
 	const struct rproc_ops *ops;
+	const struct rproc_fw_ops *fw_ops;
 	struct device *dev;
 	struct kref refcount;
 	atomic_t power;
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 3fce545..3c7bd4b 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -163,8 +163,9 @@ int page_referenced_one(struct page *, struct vm_area_struct *,
 
 enum ttu_flags {
 	TTU_UNMAP = 0,			/* unmap mode */
-	TTU_MIGRATION = 1,		/* migration mode */
-	TTU_MUNLOCK = 2,		/* munlock mode */
+	TTU_MIGRATE_DIRECT = 1,		/* direct migration mode */
+	TTU_MIGRATE_DEFERRED = 2,	/* deferred [lazy] migration mode */
+	TTU_MUNLOCK = 4,		/* munlock mode */
 	TTU_ACTION_MASK = 0xff,
 
 	TTU_IGNORE_MLOCK = (1 << 8),	/* ignore mlock */
diff --git a/include/linux/sc26198.h b/include/linux/sc26198.h
deleted file mode 100644
index 7ca35ab..0000000
--- a/include/linux/sc26198.h
+++ /dev/null
@@ -1,533 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	sc26198.h  -- SC26198 UART hardware info.
- *
- *	Copyright (C) 1995-1998  Stallion Technologies
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You 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	_SC26198_H
-#define	_SC26198_H
-/*****************************************************************************/
-
-/*
- *	Define the number of async ports per sc26198 uart device.
- */
-#define	SC26198_PORTS		8
-
-/*
- *	Baud rate timing clocks. All derived from a master 14.7456 MHz clock.
- */
-#define	SC26198_MASTERCLOCK	14745600L
-#define	SC26198_DCLK		(SC26198_MASTERCLOCK)
-#define	SC26198_CCLK		(SC26198_MASTERCLOCK / 2)
-#define	SC26198_BCLK		(SC26198_MASTERCLOCK / 4)
-
-/*
- *	Define internal FIFO sizes for the 26198 ports.
- */
-#define	SC26198_TXFIFOSIZE	16
-#define	SC26198_RXFIFOSIZE	16
-
-/*****************************************************************************/
-
-/*
- *	Global register definitions. These registers are global to each 26198
- *	device, not specific ports on it.
- */
-#define	TSTR		0x0d
-#define	GCCR		0x0f
-#define	ICR		0x1b
-#define	WDTRCR		0x1d
-#define	IVR		0x1f
-#define	BRGTRUA		0x84
-#define	GPOSR		0x87
-#define	GPOC		0x8b
-#define	UCIR		0x8c
-#define	CIR		0x8c
-#define	BRGTRUB		0x8d
-#define	GRXFIFO		0x8e
-#define	GTXFIFO		0x8e
-#define	GCCR2		0x8f
-#define	BRGTRLA		0x94
-#define	GPOR		0x97
-#define	GPOD		0x9b
-#define	BRGTCR		0x9c
-#define	GICR		0x9c
-#define	BRGTRLB		0x9d
-#define	GIBCR		0x9d
-#define	GITR		0x9f
-
-/*
- *	Per port channel registers. These are the register offsets within
- *	the port address space, so need to have the port address (0 to 7)
- *	inserted in bit positions 4:6.
- */
-#define	MR0		0x00
-#define	MR1		0x01
-#define	IOPCR		0x02
-#define	BCRBRK		0x03
-#define	BCRCOS		0x04
-#define	BCRX		0x06
-#define	BCRA		0x07
-#define	XONCR		0x08
-#define	XOFFCR		0x09
-#define	ARCR		0x0a
-#define	RXCSR		0x0c
-#define	TXCSR		0x0e
-#define	MR2		0x80
-#define	SR		0x81
-#define SCCR		0x81
-#define	ISR		0x82
-#define	IMR		0x82
-#define	TXFIFO		0x83
-#define	RXFIFO		0x83
-#define	IPR		0x84
-#define	IOPIOR		0x85
-#define	XISR		0x86
-
-/*
- *	For any given port calculate the address to use to access a specified
- *	register. This is only used for unusual access, mostly this is done
- *	through the assembler access routines.
- */
-#define	SC26198_PORTREG(port,reg)	((((port) & 0x07) << 4) | (reg))
-
-/*****************************************************************************/
-
-/*
- *	Global configuration control register bit definitions.
- */
-#define	GCCR_NOACK		0x00
-#define	GCCR_IVRACK		0x02
-#define	GCCR_IVRCHANACK		0x04
-#define	GCCR_IVRTYPCHANACK	0x06
-#define	GCCR_ASYNCCYCLE		0x00
-#define	GCCR_SYNCCYCLE		0x40
-
-/*****************************************************************************/
-
-/*
- *	Mode register 0 bit definitions.
- */
-#define	MR0_ADDRNONE		0x00
-#define	MR0_AUTOWAKE		0x01
-#define	MR0_AUTODOZE		0x02
-#define	MR0_AUTOWAKEDOZE	0x03
-#define	MR0_SWFNONE		0x00
-#define	MR0_SWFTX		0x04
-#define	MR0_SWFRX		0x08
-#define	MR0_SWFRXTX		0x0c
-#define	MR0_TXMASK		0x30
-#define	MR0_TXEMPTY		0x00
-#define	MR0_TXHIGH		0x10
-#define	MR0_TXHALF		0x20
-#define	MR0_TXRDY		0x00
-#define	MR0_ADDRNT		0x00
-#define	MR0_ADDRT		0x40
-#define	MR0_SWFNT		0x00
-#define	MR0_SWFT		0x80
-
-/*
- *	Mode register 1 bit definitions.
- */
-#define	MR1_CS5			0x00
-#define	MR1_CS6			0x01
-#define	MR1_CS7			0x02
-#define	MR1_CS8			0x03
-#define	MR1_PAREVEN		0x00
-#define	MR1_PARODD		0x04
-#define	MR1_PARENB		0x00
-#define	MR1_PARFORCE		0x08
-#define	MR1_PARNONE		0x10
-#define	MR1_PARSPECIAL		0x18
-#define	MR1_ERRCHAR		0x00
-#define	MR1_ERRBLOCK		0x20
-#define	MR1_ISRUNMASKED		0x00
-#define	MR1_ISRMASKED		0x40
-#define	MR1_AUTORTS		0x80
-
-/*
- *	Mode register 2 bit definitions.
- */
-#define	MR2_STOP1		0x00
-#define	MR2_STOP15		0x01
-#define	MR2_STOP2		0x02
-#define	MR2_STOP916		0x03
-#define	MR2_RXFIFORDY		0x00
-#define	MR2_RXFIFOHALF		0x04
-#define	MR2_RXFIFOHIGH		0x08
-#define	MR2_RXFIFOFULL		0x0c
-#define	MR2_AUTOCTS		0x10
-#define	MR2_TXRTS		0x20
-#define	MR2_MODENORM		0x00
-#define	MR2_MODEAUTOECHO	0x40
-#define	MR2_MODELOOP		0x80
-#define	MR2_MODEREMECHO		0xc0
-
-/*****************************************************************************/
-
-/*
- *	Baud Rate Generator (BRG) selector values.
- */
-#define	BRG_50			0x00
-#define	BRG_75			0x01
-#define	BRG_150			0x02
-#define	BRG_200			0x03
-#define	BRG_300			0x04
-#define	BRG_450			0x05
-#define	BRG_600			0x06
-#define	BRG_900			0x07
-#define	BRG_1200		0x08
-#define	BRG_1800		0x09
-#define	BRG_2400		0x0a
-#define	BRG_3600		0x0b
-#define	BRG_4800		0x0c
-#define	BRG_7200		0x0d
-#define	BRG_9600		0x0e
-#define	BRG_14400		0x0f
-#define	BRG_19200		0x10
-#define	BRG_28200		0x11
-#define	BRG_38400		0x12
-#define	BRG_57600		0x13
-#define	BRG_115200		0x14
-#define	BRG_230400		0x15
-#define	BRG_GIN0		0x16
-#define	BRG_GIN1		0x17
-#define	BRG_CT0			0x18
-#define	BRG_CT1			0x19
-#define	BRG_RX2TX316		0x1b
-#define	BRG_RX2TX31		0x1c
-
-#define	SC26198_MAXBAUD		921600
-
-/*****************************************************************************/
-
-/*
- *	Command register command definitions.
- */
-#define	CR_NULL			0x04
-#define	CR_ADDRNORMAL		0x0c
-#define	CR_RXRESET		0x14
-#define	CR_TXRESET		0x1c
-#define	CR_CLEARRXERR		0x24
-#define	CR_BREAKRESET		0x2c
-#define	CR_TXSTARTBREAK		0x34
-#define	CR_TXSTOPBREAK		0x3c
-#define	CR_RTSON		0x44
-#define	CR_RTSOFF		0x4c
-#define	CR_ADDRINIT		0x5c
-#define	CR_RXERRBLOCK		0x6c
-#define	CR_TXSENDXON		0x84
-#define	CR_TXSENDXOFF		0x8c
-#define	CR_GANGXONSET		0x94
-#define	CR_GANGXOFFSET		0x9c
-#define	CR_GANGXONINIT		0xa4
-#define	CR_GANGXOFFINIT		0xac
-#define	CR_HOSTXON		0xb4
-#define	CR_HOSTXOFF		0xbc
-#define	CR_CANCELXOFF		0xc4
-#define	CR_ADDRRESET		0xdc
-#define	CR_RESETALLPORTS	0xf4
-#define	CR_RESETALL		0xfc
-
-#define	CR_RXENABLE		0x01
-#define	CR_TXENABLE		0x02
-
-/*****************************************************************************/
-
-/*
- *	Channel status register.
- */
-#define	SR_RXRDY		0x01
-#define	SR_RXFULL		0x02
-#define	SR_TXRDY		0x04
-#define	SR_TXEMPTY		0x08
-#define	SR_RXOVERRUN		0x10
-#define	SR_RXPARITY		0x20
-#define	SR_RXFRAMING		0x40
-#define	SR_RXBREAK		0x80
-
-#define	SR_RXERRS		(SR_RXPARITY | SR_RXFRAMING | SR_RXOVERRUN)
-
-/*****************************************************************************/
-
-/*
- *	Interrupt status register and interrupt mask register bit definitions.
- */
-#define	IR_TXRDY		0x01
-#define	IR_RXRDY		0x02
-#define	IR_RXBREAK		0x04
-#define	IR_XONXOFF		0x10
-#define	IR_ADDRRECOG		0x20
-#define	IR_RXWATCHDOG		0x40
-#define	IR_IOPORT		0x80
-
-/*****************************************************************************/
-
-/*
- *	Interrupt vector register field definitions.
- */
-#define	IVR_CHANMASK		0x07
-#define	IVR_TYPEMASK		0x18
-#define	IVR_CONSTMASK		0xc0
-
-#define	IVR_RXDATA		0x10
-#define	IVR_RXBADDATA		0x18
-#define	IVR_TXDATA		0x08
-#define	IVR_OTHER		0x00
-
-/*****************************************************************************/
-
-/*
- *	BRG timer control register bit definitions.
- */
-#define	BRGCTCR_DISABCLK0	0x00
-#define	BRGCTCR_ENABCLK0	0x08
-#define	BRGCTCR_DISABCLK1	0x00
-#define	BRGCTCR_ENABCLK1	0x80
-
-#define	BRGCTCR_0SCLK16		0x00
-#define	BRGCTCR_0SCLK32		0x01
-#define	BRGCTCR_0SCLK64		0x02
-#define	BRGCTCR_0SCLK128	0x03
-#define	BRGCTCR_0X1		0x04
-#define	BRGCTCR_0X12		0x05
-#define	BRGCTCR_0IO1A		0x06
-#define	BRGCTCR_0GIN0		0x07
-
-#define	BRGCTCR_1SCLK16		0x00
-#define	BRGCTCR_1SCLK32		0x10
-#define	BRGCTCR_1SCLK64		0x20
-#define	BRGCTCR_1SCLK128	0x30
-#define	BRGCTCR_1X1		0x40
-#define	BRGCTCR_1X12		0x50
-#define	BRGCTCR_1IO1B		0x60
-#define	BRGCTCR_1GIN1		0x70
-
-/*****************************************************************************/
-
-/*
- *	Watch dog timer enable register.
- */
-#define	WDTRCR_ENABALL		0xff
-
-/*****************************************************************************/
-
-/*
- *	XON/XOFF interrupt status register.
- */
-#define	XISR_TXCHARMASK		0x03
-#define	XISR_TXCHARNORMAL	0x00
-#define	XISR_TXWAIT		0x01
-#define	XISR_TXXOFFPEND		0x02
-#define	XISR_TXXONPEND		0x03
-
-#define	XISR_TXFLOWMASK		0x0c
-#define	XISR_TXNORMAL		0x00
-#define	XISR_TXSTOPPEND		0x04
-#define	XISR_TXSTARTED		0x08
-#define	XISR_TXSTOPPED		0x0c
-
-#define	XISR_RXFLOWMASK		0x30
-#define	XISR_RXFLOWNONE		0x00
-#define	XISR_RXXONSENT		0x10
-#define	XISR_RXXOFFSENT		0x20
-
-#define	XISR_RXXONGOT		0x40
-#define	XISR_RXXOFFGOT		0x80
-
-/*****************************************************************************/
-
-/*
- *	Current interrupt register.
- */
-#define	CIR_TYPEMASK		0xc0
-#define	CIR_TYPEOTHER		0x00
-#define	CIR_TYPETX		0x40
-#define	CIR_TYPERXGOOD		0x80
-#define	CIR_TYPERXBAD		0xc0
-
-#define	CIR_RXDATA		0x80
-#define	CIR_RXBADDATA		0x40
-#define	CIR_TXDATA		0x40
-
-#define	CIR_CHANMASK		0x07
-#define	CIR_CNTMASK		0x38
-
-#define	CIR_SUBTYPEMASK		0x38
-#define	CIR_SUBNONE		0x00
-#define	CIR_SUBCOS		0x08
-#define	CIR_SUBADDR		0x10
-#define	CIR_SUBXONXOFF		0x18
-#define	CIR_SUBBREAK		0x28
-
-/*****************************************************************************/
-
-/*
- *	Global interrupting channel register.
- */
-#define	GICR_CHANMASK		0x07
-
-/*****************************************************************************/
-
-/*
- *	Global interrupting byte count register.
- */
-#define	GICR_COUNTMASK		0x0f
-
-/*****************************************************************************/
-
-/*
- *	Global interrupting type register.
- */
-#define	GITR_RXMASK		0xc0
-#define	GITR_RXNONE		0x00
-#define	GITR_RXBADDATA		0x80
-#define	GITR_RXGOODDATA		0xc0
-#define	GITR_TXDATA		0x20
-
-#define	GITR_SUBTYPEMASK	0x07
-#define	GITR_SUBNONE		0x00
-#define	GITR_SUBCOS		0x01
-#define	GITR_SUBADDR		0x02
-#define	GITR_SUBXONXOFF		0x03
-#define	GITR_SUBBREAK		0x05
-
-/*****************************************************************************/
-
-/*
- *	Input port change register.
- */
-#define	IPR_CTS			0x01
-#define	IPR_DTR			0x02
-#define	IPR_RTS			0x04
-#define	IPR_DCD			0x08
-#define	IPR_CTSCHANGE		0x10
-#define	IPR_DTRCHANGE		0x20
-#define	IPR_RTSCHANGE		0x40
-#define	IPR_DCDCHANGE		0x80
-
-#define	IPR_CHANGEMASK		0xf0
-
-/*****************************************************************************/
-
-/*
- *	IO port interrupt and output register.
- */
-#define	IOPR_CTS		0x01
-#define	IOPR_DTR		0x02
-#define	IOPR_RTS		0x04
-#define	IOPR_DCD		0x08
-#define	IOPR_CTSCOS		0x10
-#define	IOPR_DTRCOS		0x20
-#define	IOPR_RTSCOS		0x40
-#define	IOPR_DCDCOS		0x80
-
-/*****************************************************************************/
-
-/*
- *	IO port configuration register.
- */
-#define	IOPCR_SETCTS		0x00
-#define	IOPCR_SETDTR		0x04
-#define	IOPCR_SETRTS		0x10
-#define	IOPCR_SETDCD		0x00
-
-#define	IOPCR_SETSIGS		(IOPCR_SETRTS | IOPCR_SETRTS | IOPCR_SETDTR | IOPCR_SETDCD)
-
-/*****************************************************************************/
-
-/*
- *	General purpose output select register.
- */
-#define	GPORS_TXC1XA		0x08
-#define	GPORS_TXC16XA		0x09
-#define	GPORS_RXC16XA		0x0a
-#define	GPORS_TXC16XB		0x0b
-#define	GPORS_GPOR3		0x0c
-#define	GPORS_GPOR2		0x0d
-#define	GPORS_GPOR1		0x0e
-#define	GPORS_GPOR0		0x0f
-
-/*****************************************************************************/
-
-/*
- *	General purpose output register.
- */
-#define	GPOR_0			0x01
-#define	GPOR_1			0x02
-#define	GPOR_2			0x04
-#define	GPOR_3			0x08
-
-/*****************************************************************************/
-
-/*
- *	General purpose output clock register.
- */
-#define	GPORC_0NONE		0x00
-#define	GPORC_0GIN0		0x01
-#define	GPORC_0GIN1		0x02
-#define	GPORC_0IO3A		0x02
-
-#define	GPORC_1NONE		0x00
-#define	GPORC_1GIN0		0x04
-#define	GPORC_1GIN1		0x08
-#define	GPORC_1IO3C		0x0c
-
-#define	GPORC_2NONE		0x00
-#define	GPORC_2GIN0		0x10
-#define	GPORC_2GIN1		0x20
-#define	GPORC_2IO3E		0x20
-
-#define	GPORC_3NONE		0x00
-#define	GPORC_3GIN0		0x40
-#define	GPORC_3GIN1		0x80
-#define	GPORC_3IO3G		0xc0
-
-/*****************************************************************************/
-
-/*
- *	General purpose output data register.
- */
-#define	GPOD_0MASK		0x03
-#define	GPOD_0SET1		0x00
-#define	GPOD_0SET0		0x01
-#define	GPOD_0SETR0		0x02
-#define	GPOD_0SETIO3B		0x03
-
-#define	GPOD_1MASK		0x0c
-#define	GPOD_1SET1		0x00
-#define	GPOD_1SET0		0x04
-#define	GPOD_1SETR0		0x08
-#define	GPOD_1SETIO3D		0x0c
-
-#define	GPOD_2MASK		0x30
-#define	GPOD_2SET1		0x00
-#define	GPOD_2SET0		0x10
-#define	GPOD_2SETR0		0x20
-#define	GPOD_2SETIO3F		0x30
-
-#define	GPOD_3MASK		0xc0
-#define	GPOD_3SET1		0x00
-#define	GPOD_3SET0		0x40
-#define	GPOD_3SETR0		0x80
-#define	GPOD_3SETIO3H		0xc0
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index ac9586d..7b600da 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -214,6 +214,10 @@ void sg_free_table(struct sg_table *);
 int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int, gfp_t,
 		     sg_alloc_fn *);
 int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
+int sg_alloc_table_from_pages(struct sg_table *sgt,
+	struct page **pages, unsigned int n_pages,
+	unsigned long offset, unsigned long size,
+	gfp_t gfp_mask);
 
 size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
 			   void *buf, size_t buflen);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4059c0f..08384db 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -144,7 +144,7 @@ extern unsigned long nr_iowait_cpu(int cpu);
 extern unsigned long this_cpu_load(void);
 
 
-extern void calc_global_load(unsigned long ticks);
+extern void calc_global_load(void);
 extern void update_cpu_load_nohz(void);
 
 extern unsigned long get_parent_ip(unsigned long addr);
@@ -334,6 +334,14 @@ static inline void lockup_detector_init(void)
 }
 #endif
 
+#if defined(CONFIG_LOCKUP_DETECTOR) && defined(CONFIG_SUSPEND)
+void lockup_detector_bootcpu_resume(void);
+#else
+static inline void lockup_detector_bootcpu_resume(void)
+{
+}
+#endif
+
 #ifdef CONFIG_DETECT_HUNG_TASK
 extern unsigned int  sysctl_hung_task_panic;
 extern unsigned long sysctl_hung_task_check_count;
@@ -862,6 +870,7 @@ enum cpu_idle_type {
 #define SD_ASYM_PACKING		0x0800  /* Place busy groups earlier in the domain */
 #define SD_PREFER_SIBLING	0x1000	/* Prefer to place tasks in a sibling domain */
 #define SD_OVERLAP		0x2000	/* sched_domains of this level overlap */
+#define SD_NUMA			0x4000	/* cross-node balancing */
 
 extern int __weak arch_sd_sibiling_asym_packing(void);
 
@@ -949,6 +958,7 @@ struct sched_domain {
 	unsigned int smt_gain;
 	int flags;			/* See SD_* */
 	int level;
+	int idle_buddy;			/* cpu assigned to select_idle_sibling() */
 
 	/* Runtime fields. */
 	unsigned long last_balance;	/* init to jiffies. units in jiffies */
@@ -1245,6 +1255,11 @@ struct task_struct {
 	struct sched_entity se;
 	struct sched_rt_entity rt;
 
+#ifdef CONFIG_NUMA
+	unsigned long	 numa_contrib;
+	int		 numa_remote;
+#endif
+
 #ifdef CONFIG_PREEMPT_NOTIFIERS
 	/* list of struct preempt_notifier: */
 	struct hlist_head preempt_notifiers;
@@ -1514,6 +1529,7 @@ struct task_struct {
 	struct mempolicy *mempolicy;	/* Protected by alloc_lock */
 	short il_next;
 	short pref_node_fork;
+	int node;
 #endif
 	struct rcu_head rcu;
 
@@ -1581,13 +1597,21 @@ struct task_struct {
 #endif
 #ifdef CONFIG_UPROBES
 	struct uprobe_task *utask;
-	int uprobe_srcu_id;
 #endif
 };
 
 /* Future-safe accessor for struct task_struct's cpus_allowed. */
 #define tsk_cpus_allowed(tsk) (&(tsk)->cpus_allowed)
 
+static inline int tsk_home_node(struct task_struct *p)
+{
+#ifdef CONFIG_NUMA
+	return p->node;
+#else
+	return -1;
+#endif
+}
+
 /*
  * Priority of a process goes from 0..MAX_PRIO-1, valid RT
  * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
@@ -1979,9 +2003,9 @@ task_sched_runtime(struct task_struct *task);
 
 /* sched_exec is called by processes performing an exec */
 #ifdef CONFIG_SMP
-extern void sched_exec(void);
+extern void sched_exec(struct mm_struct *mm);
 #else
-#define sched_exec()   {}
+#define sched_exec(mm)   {}
 #endif
 
 extern void sched_clock_idle_sleep_event(void);
@@ -2807,6 +2831,14 @@ static inline unsigned long rlimit_max(unsigned int limit)
 	return task_rlimit_max(current, limit);
 }
 
+#ifdef CONFIG_NUMA
+void mm_init_numa(struct mm_struct *mm);
+void exit_numa(struct mm_struct *mm);
+#else
+static inline void mm_init_numa(struct mm_struct *mm) { }
+static inline void exit_numa(struct mm_struct *mm) { }
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index fc61854..83c44ee 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -86,6 +86,7 @@ int seq_puts(struct seq_file *m, const char *s);
 int seq_write(struct seq_file *seq, const void *data, size_t len);
 
 __printf(2, 3) int seq_printf(struct seq_file *, const char *, ...);
+__printf(2, 0) int seq_vprintf(struct seq_file *, const char *, va_list args);
 
 int seq_path(struct seq_file *, const struct path *, const char *);
 int seq_dentry(struct seq_file *, struct dentry *, const char *);
diff --git a/include/linux/serial167.h b/include/linux/serial167.h
deleted file mode 100644
index 59c81b7..0000000
--- a/include/linux/serial167.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * serial167.h
- *
- * Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * Based on cyclades.h
- */
-
-struct cyclades_monitor {
-        unsigned long           int_count;
-        unsigned long           char_count;
-        unsigned long           char_max;
-        unsigned long           char_last;
-};
-
-/*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct cyclades_port {
-	int                     magic;
-	int                     type;
-	int			card;
-	int			line;
-	int			flags; 		/* defined in tty.h */
-	struct tty_struct 	*tty;
-	int			read_status_mask;
-	int			timeout;
-	int			xmit_fifo_size;
-	int                     cor1,cor2,cor3,cor4,cor5,cor6,cor7;
-	int                     tbpr,tco,rbpr,rco;
-	int			ignore_status_mask;
-	int			close_delay;
-	int			IER; 	/* Interrupt Enable Register */
-	unsigned long		last_active;
-	int			count;	/* # of fd on device */
-	int                     x_char; /* to be pushed out ASAP */
-	int                     x_break;
-	int			blocked_open; /* # of blocked opens */
-	unsigned char 		*xmit_buf;
-	int			xmit_head;
-	int			xmit_tail;
-	int			xmit_cnt;
-        int                     default_threshold;
-        int                     default_timeout;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-        struct cyclades_monitor mon;
-};
-
-#define CYCLADES_MAGIC  0x4359
-
-#define CYGETMON                0x435901
-#define CYGETTHRESH             0x435902
-#define CYSETTHRESH             0x435903
-#define CYGETDEFTHRESH          0x435904
-#define CYSETDEFTHRESH          0x435905
-#define CYGETTIMEOUT            0x435906
-#define CYSETTIMEOUT            0x435907
-#define CYGETDEFTIMEOUT         0x435908
-#define CYSETDEFTIMEOUT         0x435909
-
-#define CyMaxChipsPerCard 1
-
-/**** cd2401 registers ****/
-
-#define CyGFRCR         (0x81)
-#define CyCCR		(0x13)
-#define      CyCLR_CHAN		(0x40)
-#define      CyINIT_CHAN	(0x20)
-#define      CyCHIP_RESET	(0x10)
-#define      CyENB_XMTR		(0x08)
-#define      CyDIS_XMTR		(0x04)
-#define      CyENB_RCVR		(0x02)
-#define      CyDIS_RCVR		(0x01)
-#define CyCAR		(0xee)
-#define CyIER		(0x11)
-#define      CyMdmCh		(0x80)
-#define      CyRxExc		(0x20)
-#define      CyRxData		(0x08)
-#define      CyTxMpty		(0x02)
-#define      CyTxRdy		(0x01)
-#define CyLICR		(0x26)
-#define CyRISR		(0x89)
-#define      CyTIMEOUT		(0x80)
-#define      CySPECHAR		(0x70)
-#define      CyOVERRUN		(0x08)
-#define      CyPARITY		(0x04)
-#define      CyFRAME		(0x02)
-#define      CyBREAK		(0x01)
-#define CyREOIR		(0x84)
-#define CyTEOIR		(0x85)
-#define CyMEOIR		(0x86)
-#define      CyNOTRANS		(0x08)
-#define CyRFOC		(0x30)
-#define CyRDR		(0xf8)
-#define CyTDR		(0xf8)
-#define CyMISR		(0x8b)
-#define CyRISR		(0x89)
-#define CyTISR		(0x8a)
-#define CyMSVR1		(0xde)
-#define CyMSVR2		(0xdf)
-#define      CyDSR		(0x80)
-#define      CyDCD		(0x40)
-#define      CyCTS		(0x20)
-#define      CyDTR		(0x02)
-#define      CyRTS		(0x01)
-#define CyRTPRL		(0x25)
-#define CyRTPRH		(0x24)
-#define CyCOR1		(0x10)
-#define      CyPARITY_NONE	(0x00)
-#define      CyPARITY_E		(0x40)
-#define      CyPARITY_O		(0xC0)
-#define      Cy_5_BITS		(0x04)
-#define      Cy_6_BITS		(0x05)
-#define      Cy_7_BITS		(0x06)
-#define      Cy_8_BITS		(0x07)
-#define CyCOR2		(0x17)
-#define      CyETC		(0x20)
-#define      CyCtsAE		(0x02)
-#define CyCOR3		(0x16)
-#define      Cy_1_STOP		(0x02)
-#define      Cy_2_STOP		(0x04)
-#define CyCOR4		(0x15)
-#define      CyREC_FIFO		(0x0F)  /* Receive FIFO threshold */
-#define CyCOR5		(0x14)
-#define CyCOR6		(0x18)
-#define CyCOR7		(0x07)
-#define CyRBPR		(0xcb)
-#define CyRCOR		(0xc8)
-#define CyTBPR		(0xc3)
-#define CyTCOR		(0xc0)
-#define CySCHR1		(0x1f)
-#define CySCHR2 	(0x1e)
-#define CyTPR		(0xda)
-#define CyPILR1		(0xe3)
-#define CyPILR2		(0xe0)
-#define CyPILR3		(0xe1)
-#define CyCMR		(0x1b)
-#define      CyASYNC		(0x02)
-#define CyLICR          (0x26)
-#define CyLIVR          (0x09)
-#define CySCRL		(0x23)
-#define CySCRH		(0x22)
-#define CyTFTC		(0x80)
-
-
-/* max number of chars in the FIFO */
-
-#define CyMAX_CHAR_FIFO	12
-
-/***************************************************************************/
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 65db992..0253c20 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -47,7 +47,8 @@
 #define PORT_U6_16550A	19	/* ST-Ericsson U6xxx internal UART */
 #define PORT_TEGRA	20	/* NVIDIA Tegra internal UART */
 #define PORT_XR17D15X	21	/* Exar XR17D15x UART */
-#define PORT_MAX_8250	21	/* max port ID */
+#define PORT_LPC3220	22	/* NXP LPC32xx SoC "Standard" UART */
+#define PORT_MAX_8250	22	/* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed
diff --git a/include/linux/sfi_acpi.h b/include/linux/sfi_acpi.h
index c4a5a8c..631af63 100644
--- a/include/linux/sfi_acpi.h
+++ b/include/linux/sfi_acpi.h
@@ -66,7 +66,7 @@ extern int sfi_acpi_table_parse(char *signature, char *oem_id,
 				char *oem_table_id,
 				int (*handler)(struct acpi_table_header *));
 
-static inline int acpi_sfi_table_parse(char *signature,
+static inline int __init acpi_sfi_table_parse(char *signature,
 				int (*handler)(struct acpi_table_header *))
 {
 	if (!acpi_table_parse(signature, handler))
@@ -83,7 +83,7 @@ static inline int sfi_acpi_table_parse(char *signature, char *oem_id,
 	return -1;
 }
 
-static inline int acpi_sfi_table_parse(char *signature,
+static inline int __init acpi_sfi_table_parse(char *signature,
 				int (*handler)(struct acpi_table_header *))
 {
 	return acpi_table_parse(signature, handler);
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h
index c513b73..5091091 100644
--- a/include/linux/sh_clk.h
+++ b/include/linux/sh_clk.h
@@ -18,7 +18,6 @@ struct clk_mapping {
 	struct kref		ref;
 };
 
-
 struct sh_clk_ops {
 #ifdef CONFIG_SH_CLK_CPG_LEGACY
 	void (*init)(struct clk *clk);
@@ -31,6 +30,10 @@ struct sh_clk_ops {
 	long (*round_rate)(struct clk *clk, unsigned long rate);
 };
 
+#define SH_CLK_DIV_MSK(div)	((1 << (div)) - 1)
+#define SH_CLK_DIV4_MSK		SH_CLK_DIV_MSK(4)
+#define SH_CLK_DIV6_MSK		SH_CLK_DIV_MSK(6)
+
 struct clk {
 	struct list_head	node;
 	struct clk		*parent;
@@ -52,6 +55,7 @@ struct clk {
 	unsigned int		enable_bit;
 	void __iomem		*mapped_reg;
 
+	unsigned int		div_mask;
 	unsigned long		arch_flags;
 	void			*priv;
 	struct clk_mapping	*mapping;
@@ -65,6 +69,8 @@ struct clk {
 #define CLK_ENABLE_REG_16BIT	BIT(2)
 #define CLK_ENABLE_REG_8BIT	BIT(3)
 
+#define CLK_MASK_DIV_ON_DISABLE	BIT(4)
+
 #define CLK_ENABLE_REG_MASK	(CLK_ENABLE_REG_32BIT | \
 				 CLK_ENABLE_REG_16BIT | \
 				 CLK_ENABLE_REG_8BIT)
@@ -146,14 +152,17 @@ static inline int __deprecated sh_clk_mstp32_register(struct clk *clks, int nr)
 	.enable_reg = (void __iomem *)_reg,			\
 	.enable_bit = _shift,					\
 	.arch_flags = _div_bitmap,				\
+	.div_mask = SH_CLK_DIV4_MSK,				\
 	.flags = _flags,					\
 }
 
-struct clk_div4_table {
+struct clk_div_table {
 	struct clk_div_mult_table *div_mult_table;
 	void (*kick)(struct clk *clk);
 };
 
+#define clk_div4_table clk_div_table
+
 int sh_clk_div4_register(struct clk *clks, int nr,
 			 struct clk_div4_table *table);
 int sh_clk_div4_enable_register(struct clk *clks, int nr,
@@ -165,7 +174,9 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr,
 			_num_parents, _src_shift, _src_width)	\
 {								\
 	.enable_reg = (void __iomem *)_reg,			\
-	.flags = _flags,					\
+	.enable_bit = 0, /* unused */				\
+	.flags = _flags | CLK_MASK_DIV_ON_DISABLE,		\
+	.div_mask = SH_CLK_DIV6_MSK,				\
 	.parent_table = _parents,				\
 	.parent_num = _num_parents,				\
 	.src_shift = _src_shift,				\
@@ -176,7 +187,9 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr,
 {								\
 	.parent		= _parent,				\
 	.enable_reg	= (void __iomem *)_reg,			\
-	.flags		= _flags,				\
+	.enable_bit	= 0,	/* unused */			\
+	.div_mask	= SH_CLK_DIV6_MSK,			\
+	.flags		= _flags | CLK_MASK_DIV_ON_DISABLE,	\
 }
 
 int sh_clk_div6_register(struct clk *clks, int nr);
diff --git a/include/linux/sh_pfc.h b/include/linux/sh_pfc.h
index 5c15aed..ed1d823 100644
--- a/include/linux/sh_pfc.h
+++ b/include/linux/sh_pfc.h
@@ -16,17 +16,18 @@
 typedef unsigned short pinmux_enum_t;
 typedef unsigned short pinmux_flag_t;
 
-#define PINMUX_TYPE_NONE            0
-#define PINMUX_TYPE_FUNCTION        1
-#define PINMUX_TYPE_GPIO            2
-#define PINMUX_TYPE_OUTPUT          3
-#define PINMUX_TYPE_INPUT           4
-#define PINMUX_TYPE_INPUT_PULLUP    5
-#define PINMUX_TYPE_INPUT_PULLDOWN  6
-
-#define PINMUX_FLAG_TYPE            (0x7)
-#define PINMUX_FLAG_WANT_PULLUP     (1 << 3)
-#define PINMUX_FLAG_WANT_PULLDOWN   (1 << 4)
+enum {
+	PINMUX_TYPE_NONE,
+
+	PINMUX_TYPE_FUNCTION,
+	PINMUX_TYPE_GPIO,
+	PINMUX_TYPE_OUTPUT,
+	PINMUX_TYPE_INPUT,
+	PINMUX_TYPE_INPUT_PULLUP,
+	PINMUX_TYPE_INPUT_PULLDOWN,
+
+	PINMUX_FLAG_TYPE,	/* must be last */
+};
 
 #define PINMUX_FLAG_DBIT_SHIFT      5
 #define PINMUX_FLAG_DBIT            (0x1f << PINMUX_FLAG_DBIT_SHIFT)
@@ -38,7 +39,9 @@ struct pinmux_gpio {
 	pinmux_flag_t flags;
 };
 
-#define PINMUX_GPIO(gpio, data_or_mark) [gpio] = { data_or_mark }
+#define PINMUX_GPIO(gpio, data_or_mark) \
+	[gpio] = { .enum_id = data_or_mark, .flags = PINMUX_TYPE_NONE }
+
 #define PINMUX_DATA(data_or_mark, ids...) data_or_mark, ids, 0
 
 struct pinmux_cfg_reg {
@@ -89,7 +92,7 @@ struct pfc_window {
 	unsigned long size;
 };
 
-struct pinmux_info {
+struct sh_pfc {
 	char *name;
 	pinmux_enum_t reserved_id;
 	struct pinmux_range data;
@@ -112,17 +115,44 @@ struct pinmux_info {
 	struct pinmux_irq *gpio_irq;
 	unsigned int gpio_irq_size;
 
+	spinlock_t lock;
+
 	struct resource *resource;
 	unsigned int num_resources;
 	struct pfc_window *window;
 
 	unsigned long unlock_reg;
-
-	struct gpio_chip chip;
 };
 
-int register_pinmux(struct pinmux_info *pip);
-int unregister_pinmux(struct pinmux_info *pip);
+/* XXX compat for now */
+#define pinmux_info sh_pfc
+
+/* drivers/sh/pfc-gpio.c */
+int sh_pfc_register_gpiochip(struct sh_pfc *pfc);
+
+/* drivers/sh/pfc.c */
+int register_sh_pfc(struct sh_pfc *pfc);
+
+int sh_pfc_read_bit(struct pinmux_data_reg *dr, unsigned long in_pos);
+void sh_pfc_write_bit(struct pinmux_data_reg *dr, unsigned long in_pos,
+		      unsigned long value);
+int sh_pfc_get_data_reg(struct sh_pfc *pfc, unsigned gpio,
+			struct pinmux_data_reg **drp, int *bitp);
+int sh_pfc_gpio_to_enum(struct sh_pfc *pfc, unsigned gpio, int pos,
+			pinmux_enum_t *enum_idp);
+int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
+		       int cfg_mode);
+int sh_pfc_set_direction(struct sh_pfc *pfc, unsigned gpio,
+			 int new_pinmux_type);
+
+/* xxx */
+static inline int register_pinmux(struct pinmux_info *pip)
+{
+	struct sh_pfc *pfc = pip;
+	return register_sh_pfc(pfc);
+}
+
+enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE };
 
 /* helper macro for port */
 #define PORT_1(fn, pfx, sfx) fn(pfx, sfx)
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index bef2cf0..cfe8a34 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -17,6 +17,7 @@ struct shmem_inode_info {
 		char		*symlink;	/* unswappable short symlink */
 	};
 	struct shared_policy	policy;		/* NUMA memory alloc policy */
+	unsigned long           node_offset;	/* bias for interleaved nodes */
 	struct list_head	swaplist;	/* chain of maybes on swap */
 	struct list_head	xattr_list;	/* list of shmem_xattr */
 	struct inode		vfs_inode;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index b534a1b..d205c4b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -225,14 +225,11 @@ enum {
 	/* device driver is going to provide hardware time stamp */
 	SKBTX_IN_PROGRESS = 1 << 2,
 
-	/* ensure the originating sk reference is available on driver level */
-	SKBTX_DRV_NEEDS_SK_REF = 1 << 3,
-
 	/* device driver supports TX zero-copy buffers */
-	SKBTX_DEV_ZEROCOPY = 1 << 4,
+	SKBTX_DEV_ZEROCOPY = 1 << 3,
 
 	/* generate wifi status information (where possible) */
-	SKBTX_WIFI_STATUS = 1 << 5,
+	SKBTX_WIFI_STATUS = 1 << 4,
 };
 
 /*
@@ -1670,6 +1667,22 @@ static inline void skb_orphan(struct sk_buff *skb)
 }
 
 /**
+ *	skb_orphan_frags - orphan the frags contained in a buffer
+ *	@skb: buffer to orphan frags from
+ *	@gfp_mask: allocation mask for replacement pages
+ *
+ *	For each frag in the SKB which needs a destructor (i.e. has an
+ *	owner) create a copy of that frag and release the original
+ *	page by calling the destructor.
+ */
+static inline int skb_orphan_frags(struct sk_buff *skb, gfp_t gfp_mask)
+{
+	if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY)))
+		return 0;
+	return skb_copy_ubufs(skb, gfp_mask);
+}
+
+/**
  *	__skb_queue_purge - empty a list
  *	@list: list to empty
  *
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 67d5d94..0dd2dfa 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -93,6 +93,30 @@
 				(unsigned long)ZERO_SIZE_PTR)
 
 /*
+ * Common fields provided in kmem_cache by all slab allocators
+ * This struct is either used directly by the allocator (SLOB)
+ * or the allocator must include definitions for all fields
+ * provided in kmem_cache_common in their definition of kmem_cache.
+ *
+ * Once we can do anonymous structs (C11 standard) we could put a
+ * anonymous struct definition in these allocators so that the
+ * separate allocations in the kmem_cache structure of SLAB and
+ * SLUB is no longer needed.
+ */
+#ifdef CONFIG_SLOB
+struct kmem_cache {
+	unsigned int object_size;/* The original size of the object */
+	unsigned int size;	/* The aligned/padded/added on size  */
+	unsigned int align;	/* Alignment as calculated */
+	unsigned long flags;	/* Active flags on the slab */
+	const char *name;	/* Slab name for sysfs */
+	int refcount;		/* Use counter */
+	void (*ctor)(void *);	/* Called on object slot creation */
+	struct list_head list;	/* List of all slab caches on the system */
+};
+#endif
+
+/*
  * struct kmem_cache related prototypes
  */
 void __init kmem_cache_init(void);
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h
index fbd1117..1d93f27 100644
--- a/include/linux/slab_def.h
+++ b/include/linux/slab_def.h
@@ -27,7 +27,7 @@ struct kmem_cache {
 	unsigned int limit;
 	unsigned int shared;
 
-	unsigned int buffer_size;
+	unsigned int size;
 	u32 reciprocal_buffer_size;
 /* 2) touched by every alloc & free from the backend */
 
@@ -52,7 +52,10 @@ struct kmem_cache {
 
 /* 4) cache creation/removal */
 	const char *name;
-	struct list_head next;
+	struct list_head list;
+	int refcount;
+	int object_size;
+	int align;
 
 /* 5) statistics */
 #ifdef CONFIG_DEBUG_SLAB
@@ -73,12 +76,11 @@ struct kmem_cache {
 
 	/*
 	 * If debugging is enabled, then the allocator can add additional
-	 * fields and/or padding to every object. buffer_size contains the total
+	 * fields and/or padding to every object. size contains the total
 	 * object size including these internal fields, the following two
 	 * variables contain the offset to the user object and its size.
 	 */
 	int obj_offset;
-	int obj_size;
 #endif /* CONFIG_DEBUG_SLAB */
 
 /* 6) per-cpu/per-node data, touched during every alloc/free */
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index c2f8c8b..df448ad 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -48,7 +48,6 @@ struct kmem_cache_cpu {
 	unsigned long tid;	/* Globally unique transaction id */
 	struct page *page;	/* The slab from which we are allocating */
 	struct page *partial;	/* Partially allocated frozen slabs */
-	int node;		/* The node of the page (or -1 for debug) */
 #ifdef CONFIG_SLUB_STATS
 	unsigned stat[NR_SLUB_STAT_ITEMS];
 #endif
@@ -83,7 +82,7 @@ struct kmem_cache {
 	unsigned long flags;
 	unsigned long min_partial;
 	int size;		/* The size of an object including meta data */
-	int objsize;		/* The size of an object without meta data */
+	int object_size;	/* The size of an object without meta data */
 	int offset;		/* Free pointer offset. */
 	int cpu_partial;	/* Number of per cpu partial objects to keep around */
 	struct kmem_cache_order_objects oo;
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 717fb74..dd6f06b 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -90,10 +90,6 @@ void kick_all_cpus_sync(void);
 void __init call_function_init(void);
 void generic_smp_call_function_single_interrupt(void);
 void generic_smp_call_function_interrupt(void);
-void ipi_call_lock(void);
-void ipi_call_unlock(void);
-void ipi_call_lock_irq(void);
-void ipi_call_unlock_irq(void);
 #else
 static inline void call_function_init(void) { }
 #endif
@@ -181,7 +177,6 @@ static inline int up_smp_call_function(smp_call_func_t func, void *info)
 	} while (0)
 
 static inline void smp_send_reschedule(int cpu) { }
-#define num_booting_cpus()			1
 #define smp_prepare_boot_cpu()			do {} while (0)
 #define smp_call_function_many(mask, func, info, wait) \
 			(up_smp_call_function(func, info))
diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h
index db4bae7..6793fac 100644
--- a/include/linux/sock_diag.h
+++ b/include/linux/sock_diag.h
@@ -18,6 +18,7 @@ enum {
 	SK_MEMINFO_FWD_ALLOC,
 	SK_MEMINFO_WMEM_QUEUED,
 	SK_MEMINFO_OPTMEM,
+	SK_MEMINFO_BACKLOG,
 
 	SK_MEMINFO_VARS,
 };
diff --git a/include/linux/splice.h b/include/linux/splice.h
index 26e5b61..09a545a 100644
--- a/include/linux/splice.h
+++ b/include/linux/splice.h
@@ -51,7 +51,8 @@ struct partial_page {
 struct splice_pipe_desc {
 	struct page **pages;		/* page map */
 	struct partial_page *partial;	/* pages[] may not be contig */
-	int nr_pages;			/* number of pages in map */
+	int nr_pages;			/* number of populated pages in map */
+	unsigned int nr_pages_max;	/* pages[] & partial[] arrays size */
 	unsigned int flags;		/* splice flags */
 	const struct pipe_buf_operations *ops;/* ops associated with output pipe */
 	void (*spd_release)(struct splice_pipe_desc *, unsigned int);
@@ -85,9 +86,8 @@ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
 /*
  * for dynamic pipe sizing
  */
-extern int splice_grow_spd(struct pipe_inode_info *, struct splice_pipe_desc *);
-extern void splice_shrink_spd(struct pipe_inode_info *,
-				struct splice_pipe_desc *);
+extern int splice_grow_spd(const struct pipe_inode_info *, struct splice_pipe_desc *);
+extern void splice_shrink_spd(struct splice_pipe_desc *);
 extern void spd_release_page(struct splice_pipe_desc *, unsigned int);
 
 extern const struct pipe_buf_operations page_cache_pipe_buf_ops;
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index bc14bd7..bb674c0 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -243,6 +243,7 @@ struct ssb_bus_ops {
 #define SSB_DEV_MINI_MACPHY	0x823
 #define SSB_DEV_ARM_1176	0x824
 #define SSB_DEV_ARM_7TDMI	0x825
+#define SSB_DEV_ARM_CM3		0x82A
 
 /* Vendor-ID values */
 #define SSB_VENDOR_BROADCOM	0x4243
diff --git a/include/linux/stallion.h b/include/linux/stallion.h
deleted file mode 100644
index 336af33c..0000000
--- a/include/linux/stallion.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	stallion.h  -- stallion multiport serial driver.
- *
- *	Copyright (C) 1996-1998  Stallion Technologies
- *	Copyright (C) 1994-1996  Greg Ungerer.
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You 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	_STALLION_H
-#define	_STALLION_H
-/*****************************************************************************/
-
-/*
- *	Define important driver constants here.
- */
-#define	STL_MAXBRDS		4
-#define	STL_MAXPANELS		4
-#define	STL_MAXBANKS		8
-#define	STL_PORTSPERPANEL	16
-#define	STL_MAXPORTS		64
-#define	STL_MAXDEVS		(STL_MAXBRDS * STL_MAXPORTS)
-
-
-/*
- *	Define a set of structures to hold all the board/panel/port info
- *	for our ports. These will be dynamically allocated as required.
- */
-
-/*
- *	Define a ring queue structure for each port. This will hold the
- *	TX data waiting to be output. Characters are fed into this buffer
- *	from the line discipline (or even direct from user space!) and
- *	then fed into the UARTs during interrupts. Will use a classic ring
- *	queue here for this. The good thing about this type of ring queue
- *	is that the head and tail pointers can be updated without interrupt
- *	protection - since "write" code only needs to change the head, and
- *	interrupt code only needs to change the tail.
- */
-struct stlrq {
-	char	*buf;
-	char	*head;
-	char	*tail;
-};
-
-/*
- *	Port, panel and board structures to hold status info about each.
- *	The board structure contains pointers to structures for each panel
- *	connected to it, and in turn each panel structure contains pointers
- *	for each port structure for each port on that panel. Note that
- *	the port structure also contains the board and panel number that it
- *	is associated with, this makes it (fairly) easy to get back to the
- *	board/panel info for a port.
- */
-struct stlport {
-	unsigned long		magic;
-	struct tty_port		port;
-	unsigned int		portnr;
-	unsigned int		panelnr;
-	unsigned int		brdnr;
-	int			ioaddr;
-	int			uartaddr;
-	unsigned int		pagenr;
-	unsigned long		istate;
-	int			baud_base;
-	int			custom_divisor;
-	int			close_delay;
-	int			closing_wait;
-	int			openwaitcnt;
-	int			brklen;
-	unsigned int		sigs;
-	unsigned int		rxignoremsk;
-	unsigned int		rxmarkmsk;
-	unsigned int		imr;
-	unsigned int		crenable;
-	unsigned long		clk;
-	unsigned long		hwid;
-	void			*uartp;
-	comstats_t		stats;
-	struct stlrq		tx;
-};
-
-struct stlpanel {
-	unsigned long	magic;
-	unsigned int	panelnr;
-	unsigned int	brdnr;
-	unsigned int	pagenr;
-	unsigned int	nrports;
-	int		iobase;
-	void		*uartp;
-	void		(*isr)(struct stlpanel *panelp, unsigned int iobase);
-	unsigned int	hwid;
-	unsigned int	ackmask;
-	struct stlport	*ports[STL_PORTSPERPANEL];
-};
-
-struct stlbrd {
-	unsigned long	magic;
-	unsigned int	brdnr;
-	unsigned int	brdtype;
-	unsigned int	state;
-	unsigned int	nrpanels;
-	unsigned int	nrports;
-	unsigned int	nrbnks;
-	int		irq;
-	int		irqtype;
-	int		(*isr)(struct stlbrd *brdp);
-	unsigned int	ioaddr1;
-	unsigned int	ioaddr2;
-	unsigned int	iosize1;
-	unsigned int	iosize2;
-	unsigned int	iostatus;
-	unsigned int	ioctrl;
-	unsigned int	ioctrlval;
-	unsigned int	hwid;
-	unsigned long	clk;
-	unsigned int	bnkpageaddr[STL_MAXBANKS];
-	unsigned int	bnkstataddr[STL_MAXBANKS];
-	struct stlpanel	*bnk2panel[STL_MAXBANKS];
-	struct stlpanel	*panels[STL_MAXPANELS];
-};
-
-
-/*
- *	Define MAGIC numbers used for above structures.
- */
-#define	STL_PORTMAGIC	0x5a7182c9
-#define	STL_PANELMAGIC	0x7ef621a1
-#define	STL_BOARDMAGIC	0xa2267f52
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/string.h b/include/linux/string.h
index e033564..ffe0442 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -145,4 +145,7 @@ static inline bool strstarts(const char *str, const char *prefix)
 	return strncmp(str, prefix, strlen(prefix)) == 0;
 }
 #endif
+
+extern size_t memweight(const void *ptr, size_t bytes);
+
 #endif /* _LINUX_STRING_H_ */
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index af70af3..6398899 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -104,8 +104,6 @@ __be32 *xdr_decode_string_inplace(__be32 *p, char **sp, unsigned int *lenp,
 __be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *);
 __be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *);
 
-void	xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int,
-			 unsigned int);
 void	xdr_inline_pages(struct xdr_buf *, unsigned int,
 			 struct page **, unsigned int, unsigned int);
 void	xdr_terminate_string(struct xdr_buf *, const u32);
@@ -205,6 +203,7 @@ struct xdr_stream {
 	struct kvec *iov;	/* pointer to the current kvec */
 	struct kvec scratch;	/* Scratch buffer */
 	struct page **page_ptr;	/* pointer to the current page */
+	unsigned int nwords;	/* Remaining decode buffer length */
 };
 
 /*
@@ -217,12 +216,13 @@ extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32
 extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
 extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
 		unsigned int base, unsigned int len);
+extern unsigned int xdr_stream_pos(const struct xdr_stream *xdr);
 extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
 extern void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
 		struct page **pages, unsigned int len);
 extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen);
 extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
-extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
+extern unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
 extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
 extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data);
 
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index cd83059..0c808d7 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -408,6 +408,12 @@ static inline void unlock_system_sleep(void) {}
 
 #endif /* !CONFIG_PM_SLEEP */
 
+#ifdef CONFIG_PM_SLEEP_DEBUG
+extern bool pm_print_times_enabled;
+#else
+#define pm_print_times_enabled	(false)
+#endif
+
 #ifdef CONFIG_PM_AUTOSLEEP
 
 /* kernel/power/autosleep.c */
diff --git a/include/linux/swap.h b/include/linux/swap.h
index c84ec68..b967eda 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -357,6 +357,7 @@ extern sector_t map_swap_page(struct page *, struct block_device **);
 extern sector_t swapdev_block(int, pgoff_t);
 extern int page_swapcount(struct page *);
 extern int reuse_swap_page(struct page *);
+extern int can_reuse_swap_page(struct page *);
 extern int try_to_free_swap(struct page *);
 struct backing_dev_info;
 
@@ -454,7 +455,8 @@ static inline int page_swapcount(struct page *page)
 	return 0;
 }
 
-#define reuse_swap_page(page)	(page_mapcount(page) == 1)
+#define reuse_swap_page(page)		(page_mapcount(page) == 1)
+#define can_reuse_swap_page(page)	(page_mapcount(page) == 1)
 
 static inline int try_to_free_swap(struct page *page)
 {
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 5f359db..7d3bced 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -506,8 +506,9 @@ struct tcp_timewait_sock {
 	u32			  tw_rcv_wnd;
 	u32			  tw_ts_recent;
 	long			  tw_ts_recent_stamp;
+	struct inet_peer	  *tw_peer;
 #ifdef CONFIG_TCP_MD5SIG
-	struct tcp_md5sig_key	*tw_md5_key;
+	struct tcp_md5sig_key	  *tw_md5_key;
 #endif
 	/* Few sockets in timewait have cookies; in that case, then this
 	 * object holds a reference to them (tw_cookie_values->kref).
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 796f1ff..c1e1883 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -58,6 +58,12 @@ struct thermal_zone_device_ops {
 		enum thermal_trip_type *);
 	int (*get_trip_temp) (struct thermal_zone_device *, int,
 			      unsigned long *);
+	int (*set_trip_temp) (struct thermal_zone_device *, int,
+			      unsigned long);
+	int (*get_trip_hyst) (struct thermal_zone_device *, int,
+			      unsigned long *);
+	int (*set_trip_hyst) (struct thermal_zone_device *, int,
+			      unsigned long);
 	int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
 	int (*notify) (struct thermal_zone_device *, int,
 		       enum thermal_trip_type);
@@ -89,6 +95,9 @@ struct thermal_zone_device {
 	int id;
 	char type[THERMAL_NAME_LENGTH];
 	struct device device;
+	struct device_attribute trip_temp_attrs[THERMAL_MAX_TRIPS];
+	struct device_attribute trip_type_attrs[THERMAL_MAX_TRIPS];
+	struct device_attribute trip_hyst_attrs[THERMAL_MAX_TRIPS];
 	void *devdata;
 	int trips;
 	int tc1;
@@ -137,9 +146,9 @@ enum {
 };
 #define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)
 
-struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
-		const struct thermal_zone_device_ops *, int tc1, int tc2,
-		int passive_freq, int polling_freq);
+struct thermal_zone_device *thermal_zone_device_register(char *, int, int,
+		void *, const struct thermal_zone_device_ops *, int tc1,
+		int tc2, int passive_freq, int polling_freq);
 void thermal_zone_device_unregister(struct thermal_zone_device *);
 
 int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
diff --git a/include/linux/tick.h b/include/linux/tick.h
index ab8be90..f37fceb 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -31,10 +31,10 @@ enum tick_nohz_mode {
  * struct tick_sched - sched tick emulation and no idle tick control/stats
  * @sched_timer:	hrtimer to schedule the periodic tick in high
  *			resolution mode
- * @idle_tick:		Store the last idle tick expiry time when the tick
- *			timer is modified for idle sleeps. This is necessary
+ * @last_tick:		Store the last tick expiry time when the tick
+ *			timer is modified for nohz sleeps. This is necessary
  *			to resume the tick timer operation in the timeline
- *			when the CPU returns from idle
+ *			when the CPU returns from nohz sleep.
  * @tick_stopped:	Indicator that the idle tick has been stopped
  * @idle_jiffies:	jiffies at the entry to idle for idle time accounting
  * @idle_calls:		Total number of idle calls
@@ -51,7 +51,7 @@ struct tick_sched {
 	struct hrtimer			sched_timer;
 	unsigned long			check_clocks;
 	enum tick_nohz_mode		nohz_mode;
-	ktime_t				idle_tick;
+	ktime_t				last_tick;
 	int				inidle;
 	int				tick_stopped;
 	unsigned long			idle_jiffies;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 9f47ab5..40b18d7 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -497,6 +497,9 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
 #define tty_is_writelocked(tty)  (mutex_is_locked(&tty->atomic_write_lock))
 
 extern void tty_port_init(struct tty_port *port);
+extern struct device *tty_port_register_device(struct tty_port *port,
+		struct tty_driver *driver, unsigned index,
+		struct device *device);
 extern int tty_port_alloc_xmit_buf(struct tty_port *port);
 extern void tty_port_free_xmit_buf(struct tty_port *port);
 extern void tty_port_put(struct tty_port *port);
@@ -521,6 +524,8 @@ extern int tty_port_close_start(struct tty_port *port,
 extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
 extern void tty_port_close(struct tty_port *port,
 				struct tty_struct *tty, struct file *filp);
+extern int tty_port_install(struct tty_port *port, struct tty_driver *driver,
+				struct tty_struct *tty);
 extern int tty_port_open(struct tty_port *port,
 				struct tty_struct *tty, struct file *filp);
 static inline int tty_port_users(struct tty_port *port)
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 6e6dbb7..04419c1 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -313,6 +313,7 @@ struct tty_driver {
 	 * Pointer to the tty data structures
 	 */
 	struct tty_struct **ttys;
+	struct tty_port **ports;
 	struct ktermios **termios;
 	void *driver_state;
 
diff --git a/include/linux/uhid.h b/include/linux/uhid.h
new file mode 100644
index 0000000..9c6974f
--- /dev/null
+++ b/include/linux/uhid.h
@@ -0,0 +1,104 @@
+#ifndef __UHID_H_
+#define __UHID_H_
+
+/*
+ * User-space I/O driver support for HID subsystem
+ * Copyright (c) 2012 David Herrmann
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * Public header for user-space communication. We try to keep every structure
+ * aligned but to be safe we also use __attribute__((__packed__)). Therefore,
+ * the communication should be ABI compatible even between architectures.
+ */
+
+#include <linux/input.h>
+#include <linux/types.h>
+
+enum uhid_event_type {
+	UHID_CREATE,
+	UHID_DESTROY,
+	UHID_START,
+	UHID_STOP,
+	UHID_OPEN,
+	UHID_CLOSE,
+	UHID_OUTPUT,
+	UHID_OUTPUT_EV,
+	UHID_INPUT,
+	UHID_FEATURE,
+	UHID_FEATURE_ANSWER,
+};
+
+struct uhid_create_req {
+	__u8 name[128];
+	__u8 phys[64];
+	__u8 uniq[64];
+	__u8 __user *rd_data;
+	__u16 rd_size;
+
+	__u16 bus;
+	__u32 vendor;
+	__u32 product;
+	__u32 version;
+	__u32 country;
+} __attribute__((__packed__));
+
+#define UHID_DATA_MAX 4096
+
+enum uhid_report_type {
+	UHID_FEATURE_REPORT,
+	UHID_OUTPUT_REPORT,
+	UHID_INPUT_REPORT,
+};
+
+struct uhid_input_req {
+	__u8 data[UHID_DATA_MAX];
+	__u16 size;
+} __attribute__((__packed__));
+
+struct uhid_output_req {
+	__u8 data[UHID_DATA_MAX];
+	__u16 size;
+	__u8 rtype;
+} __attribute__((__packed__));
+
+struct uhid_output_ev_req {
+	__u16 type;
+	__u16 code;
+	__s32 value;
+} __attribute__((__packed__));
+
+struct uhid_feature_req {
+	__u32 id;
+	__u8 rnum;
+	__u8 rtype;
+} __attribute__((__packed__));
+
+struct uhid_feature_answer_req {
+	__u32 id;
+	__u16 err;
+	__u16 size;
+	__u8 data[UHID_DATA_MAX];
+};
+
+struct uhid_event {
+	__u32 type;
+
+	union {
+		struct uhid_create_req create;
+		struct uhid_input_req input;
+		struct uhid_output_req output;
+		struct uhid_output_ev_req output_ev;
+		struct uhid_feature_req feature;
+		struct uhid_feature_answer_req feature_answer;
+	} u;
+} __attribute__((__packed__));
+
+#endif /* __UHID_H_ */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index dea39dc..f717fbd 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -777,6 +777,22 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
 	.bInterfaceProtocol = (pr)
 
 /**
+ * USB_DEVICE_INTERFACE_NUMBER - describe a usb device with a specific interface number
+ * @vend: the 16 bit USB Vendor ID
+ * @prod: the 16 bit USB Product ID
+ * @num: bInterfaceNumber value
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific interface number of devices.
+ */
+#define USB_DEVICE_INTERFACE_NUMBER(vend, prod, num) \
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+		       USB_DEVICE_ID_MATCH_INT_NUMBER, \
+	.idVendor = (vend), \
+	.idProduct = (prod), \
+	.bInterfaceNumber = (num)
+
+/**
  * USB_DEVICE_INFO - macro used to describe a class of usb devices
  * @cl: bDeviceClass value
  * @sc: bDeviceSubClass value
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 49b3ac2..c5fdb14 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -93,6 +93,12 @@ struct usb_hcd {
 	 */
 	const struct hc_driver	*driver;	/* hw-specific hooks */
 
+	/*
+	 * OTG and some Host controllers need software interaction with phys;
+	 * other external phys should be software-transparent
+	 */
+	struct usb_phy	*phy;
+
 	/* Flags that need to be manipulated atomically because they can
 	 * change while the host controller is running.  Always use
 	 * set_bit() or clear_bit() to change their values.
diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h
index 547e59c..c5d36c6 100644
--- a/include/linux/usb/renesas_usbhs.h
+++ b/include/linux/usb/renesas_usbhs.h
@@ -132,6 +132,14 @@ struct renesas_usbhs_driver_param {
 	 * option:
 	 *
 	 * dma id for dmaengine
+	 * The data transfer direction on D0FIFO/D1FIFO should be
+	 * fixed for keeping consistency.
+	 * So, the platform id settings will be..
+	 *	.d0_tx_id = xx_TX,
+	 *	.d1_rx_id = xx_RX,
+	 * or
+	 *	.d1_tx_id = xx_TX,
+	 *	.d0_rx_id = xx_RX,
 	 */
 	int d0_tx_id;
 	int d0_rx_id;
diff --git a/include/linux/usb/tilegx.h b/include/linux/usb/tilegx.h
new file mode 100644
index 0000000..2d65e34
--- /dev/null
+++ b/include/linux/usb/tilegx.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Structure to contain platform-specific data related to Tile-Gx USB
+ * controllers.
+ */
+
+#ifndef _LINUX_USB_TILEGX_H
+#define _LINUX_USB_TILEGX_H
+
+#include <gxio/usb_host.h>
+
+struct tilegx_usb_platform_data {
+	/* GXIO device index. */
+	int dev_index;
+
+	/* GXIO device context. */
+	gxio_usb_host_context_t usb_ctx;
+
+	/* Device IRQ. */
+	unsigned int irq;
+};
+
+#endif /* _LINUX_USB_TILEGX_H */
diff --git a/include/linux/usb/uas.h b/include/linux/usb/uas.h
index 9a988e4..5499ab5 100644
--- a/include/linux/usb/uas.h
+++ b/include/linux/usb/uas.h
@@ -20,6 +20,28 @@ enum {
 	IU_ID_WRITE_READY	= 0x07,
 };
 
+enum {
+	TMF_ABORT_TASK          = 0x01,
+	TMF_ABORT_TASK_SET      = 0x02,
+	TMF_CLEAR_TASK_SET      = 0x04,
+	TMF_LOGICAL_UNIT_RESET  = 0x08,
+	TMF_I_T_NEXUS_RESET     = 0x10,
+	TMF_CLEAR_ACA           = 0x40,
+	TMF_QUERY_TASK          = 0x80,
+	TMF_QUERY_TASK_SET      = 0x81,
+	TMF_QUERY_ASYNC_EVENT   = 0x82,
+};
+
+enum {
+	RC_TMF_COMPLETE         = 0x00,
+	RC_INVALID_INFO_UNIT    = 0x02,
+	RC_TMF_NOT_SUPPORTED    = 0x04,
+	RC_TMF_FAILED           = 0x05,
+	RC_TMF_SUCCEEDED        = 0x08,
+	RC_INCORRECT_LUN        = 0x09,
+	RC_OVERLAPPED_TAG       = 0x0a,
+};
+
 struct command_iu {
 	__u8 iu_id;
 	__u8 rsvd1;
@@ -32,6 +54,16 @@ struct command_iu {
 	__u8 cdb[16];	/* XXX: Overflow-checking tools may misunderstand */
 };
 
+struct task_mgmt_iu {
+	__u8 iu_id;
+	__u8 rsvd1;
+	__be16 tag;
+	__u8 function;
+	__u8 rsvd2;
+	__be16 task_tag;
+	struct scsi_lun lun;
+};
+
 /*
  * Also used for the Read Ready and Write Ready IUs since they have the
  * same first four bytes
@@ -47,6 +79,14 @@ struct sense_iu {
 	__u8 sense[SCSI_SENSE_BUFFERSIZE];
 };
 
+struct response_ui {
+	__u8 iu_id;
+	__u8 rsvd1;
+	__be16 tag;
+	__be16 add_response_info;
+	__u8 response_code;
+};
+
 struct usb_pipe_usage_descriptor {
 	__u8  bLength;
 	__u8  bDescriptorType;
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index 76f4396..f87cf62 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -66,9 +66,8 @@ struct usbnet {
 #		define EVENT_STS_SPLIT	3
 #		define EVENT_LINK_RESET	4
 #		define EVENT_RX_PAUSED	5
-#		define EVENT_DEV_WAKING 6
-#		define EVENT_DEV_ASLEEP 7
-#		define EVENT_DEV_OPEN	8
+#		define EVENT_DEV_ASLEEP 6
+#		define EVENT_DEV_OPEN	7
 };
 
 static inline struct usb_driver *driver_of(struct usb_interface *intf)
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
new file mode 100644
index 0000000..300d49b
--- /dev/null
+++ b/include/linux/vfio.h
@@ -0,0 +1,445 @@
+/*
+ * VFIO API definition
+ *
+ * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
+ *     Author: Alex Williamson <alex.williamson@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.
+ */
+#ifndef VFIO_H
+#define VFIO_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define VFIO_API_VERSION	0
+
+#ifdef __KERNEL__	/* Internal VFIO-core/bus driver API */
+
+#include <linux/iommu.h>
+#include <linux/mm.h>
+
+/**
+ * struct vfio_device_ops - VFIO bus driver device callbacks
+ *
+ * @open: Called when userspace creates new file descriptor for device
+ * @release: Called when userspace releases file descriptor for device
+ * @read: Perform read(2) on device file descriptor
+ * @write: Perform write(2) on device file descriptor
+ * @ioctl: Perform ioctl(2) on device file descriptor, supporting VFIO_DEVICE_*
+ *         operations documented below
+ * @mmap: Perform mmap(2) on a region of the device file descriptor
+ */
+struct vfio_device_ops {
+	char	*name;
+	int	(*open)(void *device_data);
+	void	(*release)(void *device_data);
+	ssize_t	(*read)(void *device_data, char __user *buf,
+			size_t count, loff_t *ppos);
+	ssize_t	(*write)(void *device_data, const char __user *buf,
+			 size_t count, loff_t *size);
+	long	(*ioctl)(void *device_data, unsigned int cmd,
+			 unsigned long arg);
+	int	(*mmap)(void *device_data, struct vm_area_struct *vma);
+};
+
+extern int vfio_add_group_dev(struct device *dev,
+			      const struct vfio_device_ops *ops,
+			      void *device_data);
+
+extern void *vfio_del_group_dev(struct device *dev);
+
+/**
+ * struct vfio_iommu_driver_ops - VFIO IOMMU driver callbacks
+ */
+struct vfio_iommu_driver_ops {
+	char		*name;
+	struct module	*owner;
+	void		*(*open)(unsigned long arg);
+	void		(*release)(void *iommu_data);
+	ssize_t		(*read)(void *iommu_data, char __user *buf,
+				size_t count, loff_t *ppos);
+	ssize_t		(*write)(void *iommu_data, const char __user *buf,
+				 size_t count, loff_t *size);
+	long		(*ioctl)(void *iommu_data, unsigned int cmd,
+				 unsigned long arg);
+	int		(*mmap)(void *iommu_data, struct vm_area_struct *vma);
+	int		(*attach_group)(void *iommu_data,
+					struct iommu_group *group);
+	void		(*detach_group)(void *iommu_data,
+					struct iommu_group *group);
+
+};
+
+extern int vfio_register_iommu_driver(const struct vfio_iommu_driver_ops *ops);
+
+extern void vfio_unregister_iommu_driver(
+				const struct vfio_iommu_driver_ops *ops);
+
+/**
+ * offsetofend(TYPE, MEMBER)
+ *
+ * @TYPE: The type of the structure
+ * @MEMBER: The member within the structure to get the end offset of
+ *
+ * Simple helper macro for dealing with variable sized structures passed
+ * from user space.  This allows us to easily determine if the provided
+ * structure is sized to include various fields.
+ */
+#define offsetofend(TYPE, MEMBER) ({				\
+	TYPE tmp;						\
+	offsetof(TYPE, MEMBER) + sizeof(tmp.MEMBER); })		\
+
+#endif /* __KERNEL__ */
+
+/* Kernel & User level defines for VFIO IOCTLs. */
+
+/* Extensions */
+
+#define VFIO_TYPE1_IOMMU		1
+
+/*
+ * The IOCTL interface is designed for extensibility by embedding the
+ * structure length (argsz) and flags into structures passed between
+ * kernel and userspace.  We therefore use the _IO() macro for these
+ * defines to avoid implicitly embedding a size into the ioctl request.
+ * As structure fields are added, argsz will increase to match and flag
+ * bits will be defined to indicate additional fields with valid data.
+ * It's *always* the caller's responsibility to indicate the size of
+ * the structure passed by setting argsz appropriately.
+ */
+
+#define VFIO_TYPE	(';')
+#define VFIO_BASE	100
+
+/* -------- IOCTLs for VFIO file descriptor (/dev/vfio/vfio) -------- */
+
+/**
+ * VFIO_GET_API_VERSION - _IO(VFIO_TYPE, VFIO_BASE + 0)
+ *
+ * Report the version of the VFIO API.  This allows us to bump the entire
+ * API version should we later need to add or change features in incompatible
+ * ways.
+ * Return: VFIO_API_VERSION
+ * Availability: Always
+ */
+#define VFIO_GET_API_VERSION		_IO(VFIO_TYPE, VFIO_BASE + 0)
+
+/**
+ * VFIO_CHECK_EXTENSION - _IOW(VFIO_TYPE, VFIO_BASE + 1, __s32)
+ *
+ * Check whether an extension is supported.
+ * Return: 0 if not supported, 1 (or some other positive integer) if supported.
+ * Availability: Always
+ */
+#define VFIO_CHECK_EXTENSION		_IO(VFIO_TYPE, VFIO_BASE + 1)
+
+/**
+ * VFIO_SET_IOMMU - _IOW(VFIO_TYPE, VFIO_BASE + 2, __s32)
+ *
+ * Set the iommu to the given type.  The type must be supported by an
+ * iommu driver as verified by calling CHECK_EXTENSION using the same
+ * type.  A group must be set to this file descriptor before this
+ * ioctl is available.  The IOMMU interfaces enabled by this call are
+ * specific to the value set.
+ * Return: 0 on success, -errno on failure
+ * Availability: When VFIO group attached
+ */
+#define VFIO_SET_IOMMU			_IO(VFIO_TYPE, VFIO_BASE + 2)
+
+/* -------- IOCTLs for GROUP file descriptors (/dev/vfio/$GROUP) -------- */
+
+/**
+ * VFIO_GROUP_GET_STATUS - _IOR(VFIO_TYPE, VFIO_BASE + 3,
+ *						struct vfio_group_status)
+ *
+ * Retrieve information about the group.  Fills in provided
+ * struct vfio_group_info.  Caller sets argsz.
+ * Return: 0 on succes, -errno on failure.
+ * Availability: Always
+ */
+struct vfio_group_status {
+	__u32	argsz;
+	__u32	flags;
+#define VFIO_GROUP_FLAGS_VIABLE		(1 << 0)
+#define VFIO_GROUP_FLAGS_CONTAINER_SET	(1 << 1)
+};
+#define VFIO_GROUP_GET_STATUS		_IO(VFIO_TYPE, VFIO_BASE + 3)
+
+/**
+ * VFIO_GROUP_SET_CONTAINER - _IOW(VFIO_TYPE, VFIO_BASE + 4, __s32)
+ *
+ * Set the container for the VFIO group to the open VFIO file
+ * descriptor provided.  Groups may only belong to a single
+ * container.  Containers may, at their discretion, support multiple
+ * groups.  Only when a container is set are all of the interfaces
+ * of the VFIO file descriptor and the VFIO group file descriptor
+ * available to the user.
+ * Return: 0 on success, -errno on failure.
+ * Availability: Always
+ */
+#define VFIO_GROUP_SET_CONTAINER	_IO(VFIO_TYPE, VFIO_BASE + 4)
+
+/**
+ * VFIO_GROUP_UNSET_CONTAINER - _IO(VFIO_TYPE, VFIO_BASE + 5)
+ *
+ * Remove the group from the attached container.  This is the
+ * opposite of the SET_CONTAINER call and returns the group to
+ * an initial state.  All device file descriptors must be released
+ * prior to calling this interface.  When removing the last group
+ * from a container, the IOMMU will be disabled and all state lost,
+ * effectively also returning the VFIO file descriptor to an initial
+ * state.
+ * Return: 0 on success, -errno on failure.
+ * Availability: When attached to container
+ */
+#define VFIO_GROUP_UNSET_CONTAINER	_IO(VFIO_TYPE, VFIO_BASE + 5)
+
+/**
+ * VFIO_GROUP_GET_DEVICE_FD - _IOW(VFIO_TYPE, VFIO_BASE + 6, char)
+ *
+ * Return a new file descriptor for the device object described by
+ * the provided string.  The string should match a device listed in
+ * the devices subdirectory of the IOMMU group sysfs entry.  The
+ * group containing the device must already be added to this context.
+ * Return: new file descriptor on success, -errno on failure.
+ * Availability: When attached to container
+ */
+#define VFIO_GROUP_GET_DEVICE_FD	_IO(VFIO_TYPE, VFIO_BASE + 6)
+
+/* --------------- IOCTLs for DEVICE file descriptors --------------- */
+
+/**
+ * VFIO_DEVICE_GET_INFO - _IOR(VFIO_TYPE, VFIO_BASE + 7,
+ *						struct vfio_device_info)
+ *
+ * Retrieve information about the device.  Fills in provided
+ * struct vfio_device_info.  Caller sets argsz.
+ * Return: 0 on success, -errno on failure.
+ */
+struct vfio_device_info {
+	__u32	argsz;
+	__u32	flags;
+#define VFIO_DEVICE_FLAGS_RESET	(1 << 0)	/* Device supports reset */
+#define VFIO_DEVICE_FLAGS_PCI	(1 << 1)	/* vfio-pci device */
+	__u32	num_regions;	/* Max region index + 1 */
+	__u32	num_irqs;	/* Max IRQ index + 1 */
+};
+#define VFIO_DEVICE_GET_INFO		_IO(VFIO_TYPE, VFIO_BASE + 7)
+
+/**
+ * VFIO_DEVICE_GET_REGION_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 8,
+ *				       struct vfio_region_info)
+ *
+ * Retrieve information about a device region.  Caller provides
+ * struct vfio_region_info with index value set.  Caller sets argsz.
+ * Implementation of region mapping is bus driver specific.  This is
+ * intended to describe MMIO, I/O port, as well as bus specific
+ * regions (ex. PCI config space).  Zero sized regions may be used
+ * to describe unimplemented regions (ex. unimplemented PCI BARs).
+ * Return: 0 on success, -errno on failure.
+ */
+struct vfio_region_info {
+	__u32	argsz;
+	__u32	flags;
+#define VFIO_REGION_INFO_FLAG_READ	(1 << 0) /* Region supports read */
+#define VFIO_REGION_INFO_FLAG_WRITE	(1 << 1) /* Region supports write */
+#define VFIO_REGION_INFO_FLAG_MMAP	(1 << 2) /* Region supports mmap */
+	__u32	index;		/* Region index */
+	__u32	resv;		/* Reserved for alignment */
+	__u64	size;		/* Region size (bytes) */
+	__u64	offset;		/* Region offset from start of device fd */
+};
+#define VFIO_DEVICE_GET_REGION_INFO	_IO(VFIO_TYPE, VFIO_BASE + 8)
+
+/**
+ * VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9,
+ *				    struct vfio_irq_info)
+ *
+ * Retrieve information about a device IRQ.  Caller provides
+ * struct vfio_irq_info with index value set.  Caller sets argsz.
+ * Implementation of IRQ mapping is bus driver specific.  Indexes
+ * using multiple IRQs are primarily intended to support MSI-like
+ * interrupt blocks.  Zero count irq blocks may be used to describe
+ * unimplemented interrupt types.
+ *
+ * The EVENTFD flag indicates the interrupt index supports eventfd based
+ * signaling.
+ *
+ * The MASKABLE flags indicates the index supports MASK and UNMASK
+ * actions described below.
+ *
+ * AUTOMASKED indicates that after signaling, the interrupt line is
+ * automatically masked by VFIO and the user needs to unmask the line
+ * to receive new interrupts.  This is primarily intended to distinguish
+ * level triggered interrupts.
+ *
+ * The NORESIZE flag indicates that the interrupt lines within the index
+ * are setup as a set and new subindexes cannot be enabled without first
+ * disabling the entire index.  This is used for interrupts like PCI MSI
+ * and MSI-X where the driver may only use a subset of the available
+ * indexes, but VFIO needs to enable a specific number of vectors
+ * upfront.  In the case of MSI-X, where the user can enable MSI-X and
+ * then add and unmask vectors, it's up to userspace to make the decision
+ * whether to allocate the maximum supported number of vectors or tear
+ * down setup and incrementally increase the vectors as each is enabled.
+ */
+struct vfio_irq_info {
+	__u32	argsz;
+	__u32	flags;
+#define VFIO_IRQ_INFO_EVENTFD		(1 << 0)
+#define VFIO_IRQ_INFO_MASKABLE		(1 << 1)
+#define VFIO_IRQ_INFO_AUTOMASKED	(1 << 2)
+#define VFIO_IRQ_INFO_NORESIZE		(1 << 3)
+	__u32	index;		/* IRQ index */
+	__s32	count;		/* Number of IRQs within this index */
+};
+#define VFIO_DEVICE_GET_IRQ_INFO	_IO(VFIO_TYPE, VFIO_BASE + 9)
+
+/**
+ * VFIO_DEVICE_SET_IRQS - _IOW(VFIO_TYPE, VFIO_BASE + 10, struct vfio_irq_set)
+ *
+ * Set signaling, masking, and unmasking of interrupts.  Caller provides
+ * struct vfio_irq_set with all fields set.  'start' and 'count' indicate
+ * the range of subindexes being specified.
+ *
+ * The DATA flags specify the type of data provided.  If DATA_NONE, the
+ * operation performs the specified action immediately on the specified
+ * interrupt(s).  For example, to unmask AUTOMASKED interrupt [0,0]:
+ * flags = (DATA_NONE|ACTION_UNMASK), index = 0, start = 0, count = 1.
+ *
+ * DATA_BOOL allows sparse support for the same on arrays of interrupts.
+ * For example, to mask interrupts [0,1] and [0,3] (but not [0,2]):
+ * flags = (DATA_BOOL|ACTION_MASK), index = 0, start = 1, count = 3,
+ * data = {1,0,1}
+ *
+ * DATA_EVENTFD binds the specified ACTION to the provided __s32 eventfd.
+ * A value of -1 can be used to either de-assign interrupts if already
+ * assigned or skip un-assigned interrupts.  For example, to set an eventfd
+ * to be trigger for interrupts [0,0] and [0,2]:
+ * flags = (DATA_EVENTFD|ACTION_TRIGGER), index = 0, start = 0, count = 3,
+ * data = {fd1, -1, fd2}
+ * If index [0,1] is previously set, two count = 1 ioctls calls would be
+ * required to set [0,0] and [0,2] without changing [0,1].
+ *
+ * Once a signaling mechanism is set, DATA_BOOL or DATA_NONE can be used
+ * with ACTION_TRIGGER to perform kernel level interrupt loopback testing
+ * from userspace (ie. simulate hardware triggering).
+ *
+ * Setting of an event triggering mechanism to userspace for ACTION_TRIGGER
+ * enables the interrupt index for the device.  Individual subindex interrupts
+ * can be disabled using the -1 value for DATA_EVENTFD or the index can be
+ * disabled as a whole with: flags = (DATA_NONE|ACTION_TRIGGER), count = 0.
+ *
+ * Note that ACTION_[UN]MASK specify user->kernel signaling (irqfds) while
+ * ACTION_TRIGGER specifies kernel->user signaling.
+ */
+struct vfio_irq_set {
+	__u32	argsz;
+	__u32	flags;
+#define VFIO_IRQ_SET_DATA_NONE		(1 << 0) /* Data not present */
+#define VFIO_IRQ_SET_DATA_BOOL		(1 << 1) /* Data is bool (u8) */
+#define VFIO_IRQ_SET_DATA_EVENTFD	(1 << 2) /* Data is eventfd (s32) */
+#define VFIO_IRQ_SET_ACTION_MASK	(1 << 3) /* Mask interrupt */
+#define VFIO_IRQ_SET_ACTION_UNMASK	(1 << 4) /* Unmask interrupt */
+#define VFIO_IRQ_SET_ACTION_TRIGGER	(1 << 5) /* Trigger interrupt */
+	__u32	index;
+	__s32	start;
+	__s32	count;
+	__u8	data[];
+};
+#define VFIO_DEVICE_SET_IRQS		_IO(VFIO_TYPE, VFIO_BASE + 10)
+
+#define VFIO_IRQ_SET_DATA_TYPE_MASK	(VFIO_IRQ_SET_DATA_NONE | \
+					 VFIO_IRQ_SET_DATA_BOOL | \
+					 VFIO_IRQ_SET_DATA_EVENTFD)
+#define VFIO_IRQ_SET_ACTION_TYPE_MASK	(VFIO_IRQ_SET_ACTION_MASK | \
+					 VFIO_IRQ_SET_ACTION_UNMASK | \
+					 VFIO_IRQ_SET_ACTION_TRIGGER)
+/**
+ * VFIO_DEVICE_RESET - _IO(VFIO_TYPE, VFIO_BASE + 11)
+ *
+ * Reset a device.
+ */
+#define VFIO_DEVICE_RESET		_IO(VFIO_TYPE, VFIO_BASE + 11)
+
+/*
+ * The VFIO-PCI bus driver makes use of the following fixed region and
+ * IRQ index mapping.  Unimplemented regions return a size of zero.
+ * Unimplemented IRQ types return a count of zero.
+ */
+
+enum {
+	VFIO_PCI_BAR0_REGION_INDEX,
+	VFIO_PCI_BAR1_REGION_INDEX,
+	VFIO_PCI_BAR2_REGION_INDEX,
+	VFIO_PCI_BAR3_REGION_INDEX,
+	VFIO_PCI_BAR4_REGION_INDEX,
+	VFIO_PCI_BAR5_REGION_INDEX,
+	VFIO_PCI_ROM_REGION_INDEX,
+	VFIO_PCI_CONFIG_REGION_INDEX,
+	VFIO_PCI_NUM_REGIONS
+};
+
+enum {
+	VFIO_PCI_INTX_IRQ_INDEX,
+	VFIO_PCI_MSI_IRQ_INDEX,
+	VFIO_PCI_MSIX_IRQ_INDEX,
+	VFIO_PCI_NUM_IRQS
+};
+
+/* -------- API for Type1 VFIO IOMMU -------- */
+
+/**
+ * VFIO_IOMMU_GET_INFO - _IOR(VFIO_TYPE, VFIO_BASE + 12, struct vfio_iommu_info)
+ *
+ * Retrieve information about the IOMMU object. Fills in provided
+ * struct vfio_iommu_info. Caller sets argsz.
+ *
+ * XXX Should we do these by CHECK_EXTENSION too?
+ */
+struct vfio_iommu_type1_info {
+	__u32	argsz;
+	__u32	flags;
+#define VFIO_IOMMU_INFO_PGSIZES (1 << 0)	/* supported page sizes info */
+	__u64	iova_pgsizes;		/* Bitmap of supported page sizes */
+};
+
+#define VFIO_IOMMU_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12)
+
+/**
+ * VFIO_IOMMU_MAP_DMA - _IOW(VFIO_TYPE, VFIO_BASE + 13, struct vfio_dma_map)
+ *
+ * Map process virtual addresses to IO virtual addresses using the
+ * provided struct vfio_dma_map. Caller sets argsz. READ &/ WRITE required.
+ */
+struct vfio_iommu_type1_dma_map {
+	__u32	argsz;
+	__u32	flags;
+#define VFIO_DMA_MAP_FLAG_READ (1 << 0)		/* readable from device */
+#define VFIO_DMA_MAP_FLAG_WRITE (1 << 1)	/* writable from device */
+	__u64	vaddr;				/* Process virtual address */
+	__u64	iova;				/* IO virtual address */
+	__u64	size;				/* Size of mapping (bytes) */
+};
+
+#define VFIO_IOMMU_MAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 13)
+
+/**
+ * VFIO_IOMMU_UNMAP_DMA - _IOW(VFIO_TYPE, VFIO_BASE + 14, struct vfio_dma_unmap)
+ *
+ * Unmap IO virtual addresses using the provided struct vfio_dma_unmap.
+ * Caller sets argsz.
+ */
+struct vfio_iommu_type1_dma_unmap {
+	__u32	argsz;
+	__u32	flags;
+	__u64	iova;				/* IO virtual address */
+	__u64	size;				/* Size of mapping (bytes) */
+};
+
+#define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14)
+
+#endif /* VFIO_H */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 370d111..f79d0cc 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -2039,6 +2039,8 @@ struct v4l2_modulator {
 /*  Flags for the 'capability' field */
 #define V4L2_TUNER_CAP_LOW		0x0001
 #define V4L2_TUNER_CAP_NORM		0x0002
+#define V4L2_TUNER_CAP_HWSEEK_BOUNDED	0x0004
+#define V4L2_TUNER_CAP_HWSEEK_WRAP	0x0008
 #define V4L2_TUNER_CAP_STEREO		0x0010
 #define V4L2_TUNER_CAP_LANG2		0x0020
 #define V4L2_TUNER_CAP_SAP		0x0020
@@ -2640,9 +2642,9 @@ struct v4l2_create_buffers {
 
 /* Experimental, these three ioctls may change over the next couple of kernel
    versions. */
-#define VIDIOC_ENUM_DV_TIMINGS  _IOWR('V', 96, struct v4l2_enum_dv_timings)
-#define VIDIOC_QUERY_DV_TIMINGS  _IOR('V', 97, struct v4l2_dv_timings)
-#define VIDIOC_DV_TIMINGS_CAP   _IOWR('V', 98, struct v4l2_dv_timings_cap)
+#define VIDIOC_ENUM_DV_TIMINGS  _IOWR('V', 98, struct v4l2_enum_dv_timings)
+#define VIDIOC_QUERY_DV_TIMINGS  _IOR('V', 99, struct v4l2_dv_timings)
+#define VIDIOC_DV_TIMINGS_CAP   _IOWR('V', 100, struct v4l2_dv_timings_cap)
 
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
diff --git a/include/linux/virtio_ids.h b/include/linux/virtio_ids.h
index 7529b85..270fb22 100644
--- a/include/linux/virtio_ids.h
+++ b/include/linux/virtio_ids.h
@@ -32,7 +32,7 @@
 #define VIRTIO_ID_NET		1 /* virtio net */
 #define VIRTIO_ID_BLOCK		2 /* virtio block */
 #define VIRTIO_ID_CONSOLE	3 /* virtio console */
-#define VIRTIO_ID_RNG		4 /* virtio ring */
+#define VIRTIO_ID_RNG		4 /* virtio rng */
 #define VIRTIO_ID_BALLOON	5 /* virtio balloon */
 #define VIRTIO_ID_RPMSG		7 /* virtio remote processor messaging */
 #define VIRTIO_ID_SCSI		8 /* virtio scsi */
diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h
index 06f8e38..3b54c36 100644
--- a/include/linux/vm_event_item.h
+++ b/include/linux/vm_event_item.h
@@ -40,6 +40,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
 #ifdef CONFIG_COMPACTION
 		COMPACTBLOCKS, COMPACTPAGES, COMPACTPAGEFAILED,
 		COMPACTSTALL, COMPACTFAIL, COMPACTSUCCESS,
+		COMPACT_RESCUED_UNMOVABLE_BLOCKS,
 #endif
 #ifdef CONFIG_HUGETLB_PAGE
 		HTLB_BUDDY_PGALLOC, HTLB_BUDDY_PGALLOC_FAIL,
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index dcdfc2b..6071e91 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -32,7 +32,7 @@ struct vm_struct {
 	struct page		**pages;
 	unsigned int		nr_pages;
 	phys_addr_t		phys_addr;
-	void			*caller;
+	const void		*caller;
 };
 
 /*
@@ -62,7 +62,7 @@ extern void *vmalloc_32_user(unsigned long size);
 extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot);
 extern void *__vmalloc_node_range(unsigned long size, unsigned long align,
 			unsigned long start, unsigned long end, gfp_t gfp_mask,
-			pgprot_t prot, int node, void *caller);
+			pgprot_t prot, int node, const void *caller);
 extern void vfree(const void *addr);
 
 extern void *vmap(struct page **pages, unsigned int count,
@@ -85,14 +85,15 @@ static inline size_t get_vm_area_size(const struct vm_struct *area)
 
 extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
 extern struct vm_struct *get_vm_area_caller(unsigned long size,
-					unsigned long flags, void *caller);
+					unsigned long flags, const void *caller);
 extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
 					unsigned long start, unsigned long end);
 extern struct vm_struct *__get_vm_area_caller(unsigned long size,
 					unsigned long flags,
 					unsigned long start, unsigned long end,
-					void *caller);
+					const void *caller);
 extern struct vm_struct *remove_vm_area(const void *addr);
+extern struct vm_struct *find_vm_area(const void *addr);
 
 extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
 			struct page ***pages);
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 6d0a0fc..c66fe33 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -189,9 +189,4 @@ void tag_pages_for_writeback(struct address_space *mapping,
 
 void account_page_redirty(struct page *page);
 
-/* pdflush.c */
-extern int nr_pdflush_threads;	/* Global so it can be exported to sysctl
-				   read-only. */
-
-
 #endif		/* WRITEBACK_H */
diff --git a/include/media/mt9t001.h b/include/media/mt9t001.h
index e839a78..03fd63e 100644
--- a/include/media/mt9t001.h
+++ b/include/media/mt9t001.h
@@ -3,6 +3,7 @@
 
 struct mt9t001_platform_data {
 	unsigned int clk_pol:1;
+	unsigned int ext_clk;
 };
 
 #endif
diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h
index 19ae1e3..8197f87 100644
--- a/include/media/videobuf2-dma-contig.h
+++ b/include/media/videobuf2-dma-contig.h
@@ -1,5 +1,5 @@
 /*
- * videobuf2-dma-coherent.h - DMA coherent memory allocator for videobuf2
+ * videobuf2-dma-contig.h - DMA contig memory allocator for videobuf2
  *
  * Copyright (C) 2010 Samsung Electronics
  *
@@ -10,8 +10,8 @@
  * the Free Software Foundation.
  */
 
-#ifndef _MEDIA_VIDEOBUF2_DMA_COHERENT_H
-#define _MEDIA_VIDEOBUF2_DMA_COHERENT_H
+#ifndef _MEDIA_VIDEOBUF2_DMA_CONTIG_H
+#define _MEDIA_VIDEOBUF2_DMA_CONTIG_H
 
 #include <media/videobuf2-core.h>
 #include <linux/dma-mapping.h>
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 2ee33da..b5f8988 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -14,10 +14,11 @@ extern struct sock *unix_get_socket(struct file *filp);
 extern struct sock *unix_peer_get(struct sock *);
 
 #define UNIX_HASH_SIZE	256
+#define UNIX_HASH_BITS	8
 
 extern unsigned int unix_tot_inflight;
 extern spinlock_t unix_table_lock;
-extern struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1];
+extern struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
 
 struct unix_address {
 	atomic_t	refcnt;
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
new file mode 100644
index 0000000..6a76e0a
--- /dev/null
+++ b/include/net/bluetooth/a2mp.h
@@ -0,0 +1,126 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only version 2 as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+#ifndef __A2MP_H
+#define __A2MP_H
+
+#include <net/bluetooth/l2cap.h>
+
+#define A2MP_FEAT_EXT	0x8000
+
+struct amp_mgr {
+	struct l2cap_conn	*l2cap_conn;
+	struct l2cap_chan	*a2mp_chan;
+	struct kref		kref;
+	__u8			ident;
+	__u8			handle;
+	unsigned long		flags;
+};
+
+struct a2mp_cmd {
+	__u8	code;
+	__u8	ident;
+	__le16	len;
+	__u8	data[0];
+} __packed;
+
+/* A2MP command codes */
+#define A2MP_COMMAND_REJ         0x01
+struct a2mp_cmd_rej {
+	__le16	reason;
+	__u8	data[0];
+} __packed;
+
+#define A2MP_DISCOVER_REQ        0x02
+struct a2mp_discov_req {
+	__le16	mtu;
+	__le16	ext_feat;
+} __packed;
+
+struct a2mp_cl {
+	__u8	id;
+	__u8	type;
+	__u8	status;
+} __packed;
+
+#define A2MP_DISCOVER_RSP        0x03
+struct a2mp_discov_rsp {
+	__le16     mtu;
+	__le16     ext_feat;
+	struct a2mp_cl cl[0];
+} __packed;
+
+#define A2MP_CHANGE_NOTIFY       0x04
+#define A2MP_CHANGE_RSP          0x05
+
+#define A2MP_GETINFO_REQ         0x06
+struct a2mp_info_req {
+	__u8       id;
+} __packed;
+
+#define A2MP_GETINFO_RSP         0x07
+struct a2mp_info_rsp {
+	__u8	id;
+	__u8	status;
+	__le32	total_bw;
+	__le32	max_bw;
+	__le32	min_latency;
+	__le16	pal_cap;
+	__le16	assoc_size;
+} __packed;
+
+#define A2MP_GETAMPASSOC_REQ     0x08
+struct a2mp_amp_assoc_req {
+	__u8	id;
+} __packed;
+
+#define A2MP_GETAMPASSOC_RSP     0x09
+struct a2mp_amp_assoc_rsp {
+	__u8	id;
+	__u8	status;
+	__u8	amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_REQ  0x0A
+#define A2MP_DISCONNPHYSLINK_REQ 0x0C
+struct a2mp_physlink_req {
+	__u8	local_id;
+	__u8	remote_id;
+	__u8	amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_RSP  0x0B
+#define A2MP_DISCONNPHYSLINK_RSP 0x0D
+struct a2mp_physlink_rsp {
+	__u8	local_id;
+	__u8	remote_id;
+	__u8	status;
+} __packed;
+
+/* A2MP response status */
+#define A2MP_STATUS_SUCCESS			0x00
+#define A2MP_STATUS_INVALID_CTRL_ID		0x01
+#define A2MP_STATUS_UNABLE_START_LINK_CREATION	0x02
+#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS	0x02
+#define A2MP_STATUS_COLLISION_OCCURED		0x03
+#define A2MP_STATUS_DISCONN_REQ_RECVD		0x04
+#define A2MP_STATUS_PHYS_LINK_EXISTS		0x05
+#define A2MP_STATUS_SECURITY_VIOLATION		0x06
+
+void amp_mgr_get(struct amp_mgr *mgr);
+int amp_mgr_put(struct amp_mgr *mgr);
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+				       struct sk_buff *skb);
+
+#endif /* __A2MP_H */
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 961669b..565d4be 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -1,4 +1,4 @@
-/* 
+/*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
 
@@ -12,22 +12,19 @@
    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.
 */
 
 #ifndef __BLUETOOTH_H
 #define __BLUETOOTH_H
 
-#include <asm/types.h>
-#include <asm/byteorder.h>
-#include <linux/list.h>
 #include <linux/poll.h>
 #include <net/sock.h>
 
@@ -168,8 +165,8 @@ typedef struct {
 #define BDADDR_LE_PUBLIC	0x01
 #define BDADDR_LE_RANDOM	0x02
 
-#define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
-#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
+#define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0} })
+#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} })
 
 /* Copy, swap, convert BD Address */
 static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
@@ -215,7 +212,7 @@ int  bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
 				struct msghdr *msg, size_t len, int flags);
 int  bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
 			struct msghdr *msg, size_t len, int flags);
-uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
+uint bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait);
 int  bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
 int  bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
 
@@ -225,12 +222,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
 
 /* Skb helpers */
 struct l2cap_ctrl {
-	unsigned int	sframe	: 1,
-			poll	: 1,
-			final	: 1,
-			fcs	: 1,
-			sar	: 2,
-			super	: 2;
+	unsigned int	sframe:1,
+			poll:1,
+			final:1,
+			fcs:1,
+			sar:2,
+			super:2;
 	__u16		reqseq;
 	__u16		txseq;
 	__u8		retries;
@@ -249,7 +246,8 @@ static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)
 {
 	struct sk_buff *skb;
 
-	if ((skb = alloc_skb(len + BT_SKB_RESERVE, how))) {
+	skb = alloc_skb(len + BT_SKB_RESERVE, how);
+	if (skb) {
 		skb_reserve(skb, BT_SKB_RESERVE);
 		bt_cb(skb)->incoming  = 0;
 	}
@@ -261,7 +259,8 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk,
 {
 	struct sk_buff *skb;
 
-	if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) {
+	skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err);
+	if (skb) {
 		skb_reserve(skb, BT_SKB_RESERVE);
 		bt_cb(skb)->incoming  = 0;
 	}
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 66a7b57..ccd723e 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -30,6 +30,9 @@
 #define HCI_MAX_EVENT_SIZE	260
 #define HCI_MAX_FRAME_SIZE	(HCI_MAX_ACL_SIZE + 4)
 
+#define HCI_LINK_KEY_SIZE	16
+#define HCI_AMP_LINK_KEY_SIZE	(2 * HCI_LINK_KEY_SIZE)
+
 /* HCI dev events */
 #define HCI_DEV_REG			1
 #define HCI_DEV_UNREG			2
@@ -56,9 +59,12 @@
 #define HCI_BREDR	0x00
 #define HCI_AMP		0x01
 
+/* First BR/EDR Controller shall have ID = 0 */
+#define HCI_BREDR_ID	0
+
 /* HCI device quirks */
 enum {
-	HCI_QUIRK_NO_RESET,
+	HCI_QUIRK_RESET_ON_CLOSE,
 	HCI_QUIRK_RAW_DEVICE,
 	HCI_QUIRK_FIXUP_BUFFER_SIZE
 };
@@ -133,13 +139,12 @@ enum {
 #define HCIINQUIRY	_IOR('H', 240, int)
 
 /* HCI timeouts */
-#define HCI_CONNECT_TIMEOUT	(40000)	/* 40 seconds */
-#define HCI_DISCONN_TIMEOUT	(2000)	/* 2 seconds */
-#define HCI_PAIRING_TIMEOUT	(60000)	/* 60 seconds */
-#define HCI_IDLE_TIMEOUT	(6000)	/* 6 seconds */
-#define HCI_INIT_TIMEOUT	(10000)	/* 10 seconds */
-#define HCI_CMD_TIMEOUT		(1000)	/* 1 seconds */
-#define HCI_ACL_TX_TIMEOUT	(45000)	/* 45 seconds */
+#define HCI_DISCONN_TIMEOUT	msecs_to_jiffies(2000)	/* 2 seconds */
+#define HCI_PAIRING_TIMEOUT	msecs_to_jiffies(60000)	/* 60 seconds */
+#define HCI_INIT_TIMEOUT	msecs_to_jiffies(10000)	/* 10 seconds */
+#define HCI_CMD_TIMEOUT		msecs_to_jiffies(1000)	/* 1 second */
+#define HCI_ACL_TX_TIMEOUT	msecs_to_jiffies(45000)	/* 45 seconds */
+#define HCI_AUTO_OFF_TIMEOUT	msecs_to_jiffies(2000)	/* 2 seconds */
 
 /* HCI data types */
 #define HCI_COMMAND_PKT		0x01
@@ -371,7 +376,7 @@ struct hci_cp_reject_conn_req {
 #define HCI_OP_LINK_KEY_REPLY		0x040b
 struct hci_cp_link_key_reply {
 	bdaddr_t bdaddr;
-	__u8     link_key[16];
+	__u8     link_key[HCI_LINK_KEY_SIZE];
 } __packed;
 
 #define HCI_OP_LINK_KEY_NEG_REPLY	0x040c
@@ -523,6 +528,28 @@ struct hci_cp_io_capability_neg_reply {
 	__u8     reason;
 } __packed;
 
+#define HCI_OP_CREATE_PHY_LINK		0x0435
+struct hci_cp_create_phy_link {
+	__u8     phy_handle;
+	__u8     key_len;
+	__u8     key_type;
+	__u8     key[HCI_AMP_LINK_KEY_SIZE];
+} __packed;
+
+#define HCI_OP_ACCEPT_PHY_LINK		0x0436
+struct hci_cp_accept_phy_link {
+	__u8     phy_handle;
+	__u8     key_len;
+	__u8     key_type;
+	__u8     key[HCI_AMP_LINK_KEY_SIZE];
+} __packed;
+
+#define HCI_OP_DISCONN_PHY_LINK	0x0437
+struct hci_cp_disconn_phy_link {
+	__u8     phy_handle;
+	__u8     reason;
+} __packed;
+
 #define HCI_OP_SNIFF_MODE		0x0803
 struct hci_cp_sniff_mode {
 	__le16   handle;
@@ -818,6 +845,31 @@ struct hci_rp_read_local_amp_info {
 	__le32   be_flush_to;
 } __packed;
 
+#define HCI_OP_READ_LOCAL_AMP_ASSOC	0x140a
+struct hci_cp_read_local_amp_assoc {
+	__u8     phy_handle;
+	__le16   len_so_far;
+	__le16   max_len;
+} __packed;
+struct hci_rp_read_local_amp_assoc {
+	__u8     status;
+	__u8     phy_handle;
+	__le16   rem_len;
+	__u8     frag[0];
+} __packed;
+
+#define HCI_OP_WRITE_REMOTE_AMP_ASSOC	0x140b
+struct hci_cp_write_remote_amp_assoc {
+	__u8     phy_handle;
+	__le16   len_so_far;
+	__le16   rem_len;
+	__u8     frag[0];
+} __packed;
+struct hci_rp_write_remote_amp_assoc {
+	__u8     status;
+	__u8     phy_handle;
+} __packed;
+
 #define HCI_OP_LE_SET_EVENT_MASK	0x2001
 struct hci_cp_le_set_event_mask {
 	__u8     mask[8];
@@ -1048,7 +1100,7 @@ struct hci_ev_link_key_req {
 #define HCI_EV_LINK_KEY_NOTIFY		0x18
 struct hci_ev_link_key_notify {
 	bdaddr_t bdaddr;
-	__u8     link_key[16];
+	__u8     link_key[HCI_LINK_KEY_SIZE];
 	__u8     key_type;
 } __packed;
 
@@ -1144,6 +1196,12 @@ struct extended_inquiry_info {
 	__u8     data[240];
 } __packed;
 
+#define HCI_EV_KEY_REFRESH_COMPLETE	0x30
+struct hci_ev_key_refresh_complete {
+	__u8	status;
+	__le16	handle;
+} __packed;
+
 #define HCI_EV_IO_CAPA_REQUEST		0x31
 struct hci_ev_io_capa_request {
 	bdaddr_t bdaddr;
@@ -1190,6 +1248,39 @@ struct hci_ev_le_meta {
 	__u8     subevent;
 } __packed;
 
+#define HCI_EV_PHY_LINK_COMPLETE	0x40
+struct hci_ev_phy_link_complete {
+	__u8     status;
+	__u8     phy_handle;
+} __packed;
+
+#define HCI_EV_CHANNEL_SELECTED		0x41
+struct hci_ev_channel_selected {
+	__u8     phy_handle;
+} __packed;
+
+#define HCI_EV_DISCONN_PHY_LINK_COMPLETE	0x42
+struct hci_ev_disconn_phy_link_complete {
+	__u8     status;
+	__u8     phy_handle;
+	__u8     reason;
+} __packed;
+
+#define HCI_EV_LOGICAL_LINK_COMPLETE		0x45
+struct hci_ev_logical_link_complete {
+	__u8     status;
+	__le16   handle;
+	__u8     phy_handle;
+	__u8     flow_spec_id;
+} __packed;
+
+#define HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE	0x46
+struct hci_ev_disconn_logical_link_complete {
+	__u8     status;
+	__le16   handle;
+	__u8     reason;
+} __packed;
+
 #define HCI_EV_NUM_COMP_BLOCKS		0x48
 struct hci_comp_blocks_info {
 	__le16   handle;
@@ -1290,7 +1381,6 @@ struct hci_sco_hdr {
 	__u8	dlen;
 } __packed;
 
-#include <linux/skbuff.h>
 static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb)
 {
 	return (struct hci_event_hdr *) skb->data;
@@ -1307,12 +1397,12 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
 }
 
 /* Command opcode pack/unpack */
-#define hci_opcode_pack(ogf, ocf)	(__u16) ((ocf & 0x03ff)|(ogf << 10))
+#define hci_opcode_pack(ogf, ocf)	((__u16) ((ocf & 0x03ff)|(ogf << 10)))
 #define hci_opcode_ogf(op)		(op >> 10)
 #define hci_opcode_ocf(op)		(op & 0x03ff)
 
 /* ACL handle and flags pack/unpack */
-#define hci_handle_pack(h, f)	(__u16) ((h & 0x0fff)|(f << 12))
+#define hci_handle_pack(h, f)	((__u16) ((h & 0x0fff)|(f << 12)))
 #define hci_handle(h)		(h & 0x0fff)
 #define hci_flags(h)		(h >> 12)
 
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 9fc7728..75766b7 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -25,7 +25,6 @@
 #ifndef __HCI_CORE_H
 #define __HCI_CORE_H
 
-#include <linux/interrupt.h>
 #include <net/bluetooth/hci.h>
 
 /* HCI priority */
@@ -65,7 +64,7 @@ struct discovery_state {
 		DISCOVERY_RESOLVING,
 		DISCOVERY_STOPPING,
 	} state;
-	struct list_head	all;		/* All devices found during inquiry */
+	struct list_head	all;	/* All devices found during inquiry */
 	struct list_head	unknown;	/* Name state not known */
 	struct list_head	resolve;	/* Name needs to be resolved */
 	__u32			timestamp;
@@ -105,7 +104,7 @@ struct link_key {
 	struct list_head list;
 	bdaddr_t bdaddr;
 	u8 type;
-	u8 val[16];
+	u8 val[HCI_LINK_KEY_SIZE];
 	u8 pin_len;
 };
 
@@ -333,6 +332,7 @@ struct hci_conn {
 	void		*l2cap_data;
 	void		*sco_data;
 	void		*smp_conn;
+	struct amp_mgr	*amp_mgr;
 
 	struct hci_conn	*link;
 
@@ -360,7 +360,8 @@ extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
 extern int l2cap_disconn_ind(struct hci_conn *hcon);
 extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
 extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
-extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);
+extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb,
+			      u16 flags);
 
 extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
 extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status);
@@ -429,8 +430,8 @@ enum {
 static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
 {
 	struct hci_dev *hdev = conn->hdev;
-	return (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
-				test_bit(HCI_CONN_SSP_ENABLED, &conn->flags));
+	return test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
+	       test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
 }
 
 static inline void hci_conn_hash_init(struct hci_dev *hdev)
@@ -597,7 +598,7 @@ static inline void hci_conn_put(struct hci_conn *conn)
 		if (conn->type == ACL_LINK || conn->type == LE_LINK) {
 			del_timer(&conn->idle_timer);
 			if (conn->state == BT_CONNECTED) {
-				timeo = msecs_to_jiffies(conn->disc_timeout);
+				timeo = conn->disc_timeout;
 				if (!conn->out)
 					timeo *= 2;
 			} else {
@@ -640,6 +641,19 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
 	dev_set_drvdata(&hdev->dev, data);
 }
 
+/* hci_dev_list shall be locked */
+static inline uint8_t __hci_num_ctrl(void)
+{
+	uint8_t count = 0;
+	struct list_head *p;
+
+	list_for_each(p, &hci_dev_list) {
+		count++;
+	}
+
+	return count;
+}
+
 struct hci_dev *hci_dev_get(int index);
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 
@@ -661,7 +675,8 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg);
 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);
+struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
+					 bdaddr_t *bdaddr);
 int hci_blacklist_clear(struct hci_dev *hdev);
 int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 1c7d1cd..d80e3f0 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -40,11 +40,11 @@
 #define L2CAP_DEFAULT_MONITOR_TO	12000   /* 12 seconds */
 #define L2CAP_DEFAULT_MAX_PDU_SIZE	1009    /* Sized for 3-DH5 packet */
 #define L2CAP_DEFAULT_ACK_TO		200
-#define L2CAP_LE_DEFAULT_MTU		23
 #define L2CAP_DEFAULT_MAX_SDU_SIZE	0xFFFF
 #define L2CAP_DEFAULT_SDU_ITIME		0xFFFFFFFF
 #define L2CAP_DEFAULT_ACC_LAT		0xFFFFFFFF
 #define L2CAP_BREDR_MAX_PAYLOAD		1019    /* 3-DH5 packet */
+#define L2CAP_LE_MIN_MTU		23
 
 #define L2CAP_DISC_TIMEOUT		msecs_to_jiffies(100)
 #define L2CAP_DISC_REJ_TIMEOUT		msecs_to_jiffies(5000)
@@ -52,6 +52,8 @@
 #define L2CAP_CONN_TIMEOUT		msecs_to_jiffies(40000)
 #define L2CAP_INFO_TIMEOUT		msecs_to_jiffies(4000)
 
+#define L2CAP_A2MP_DEFAULT_MTU		670
+
 /* L2CAP socket address */
 struct sockaddr_l2 {
 	sa_family_t	l2_family;
@@ -229,9 +231,14 @@ struct l2cap_conn_rsp {
 	__le16     status;
 } __packed;
 
+/* protocol/service multiplexer (PSM) */
+#define L2CAP_PSM_SDP		0x0001
+#define L2CAP_PSM_RFCOMM	0x0003
+
 /* channel indentifier */
 #define L2CAP_CID_SIGNALING	0x0001
 #define L2CAP_CID_CONN_LESS	0x0002
+#define L2CAP_CID_A2MP		0x0003
 #define L2CAP_CID_LE_DATA	0x0004
 #define L2CAP_CID_LE_SIGNALING	0x0005
 #define L2CAP_CID_SMP		0x0006
@@ -271,6 +278,9 @@ struct l2cap_conf_rsp {
 #define L2CAP_CONF_PENDING	0x0004
 #define L2CAP_CONF_EFS_REJECT	0x0005
 
+/* configuration req/rsp continuation flag */
+#define L2CAP_CONF_FLAG_CONTINUATION	0x0001
+
 struct l2cap_conf_opt {
 	__u8       type;
 	__u8       len;
@@ -419,11 +429,6 @@ struct l2cap_seq_list {
 #define L2CAP_SEQ_LIST_CLEAR	0xFFFF
 #define L2CAP_SEQ_LIST_TAIL	0x8000
 
-struct srej_list {
-	__u16	tx_seq;
-	struct list_head list;
-};
-
 struct l2cap_chan {
 	struct sock *sk;
 
@@ -475,14 +480,12 @@ struct l2cap_chan {
 	__u16		expected_ack_seq;
 	__u16		expected_tx_seq;
 	__u16		buffer_seq;
-	__u16		buffer_seq_srej;
 	__u16		srej_save_reqseq;
 	__u16		last_acked_seq;
 	__u16		frames_sent;
 	__u16		unacked_frames;
 	__u8		retry_count;
 	__u16		srej_queue_next;
-	__u8		num_acked;
 	__u16		sdu_len;
 	struct sk_buff	*sdu;
 	struct sk_buff	*sdu_last_frag;
@@ -515,7 +518,6 @@ struct l2cap_chan {
 	struct sk_buff_head	srej_q;
 	struct l2cap_seq_list	srej_list;
 	struct l2cap_seq_list	retrans_list;
-	struct list_head	srej_l;
 
 	struct list_head	list;
 	struct list_head	global_l;
@@ -528,10 +530,14 @@ struct l2cap_chan {
 struct l2cap_ops {
 	char			*name;
 
-	struct l2cap_chan	*(*new_connection) (void *data);
-	int			(*recv) (void *data, struct sk_buff *skb);
-	void			(*close) (void *data);
-	void			(*state_change) (void *data, int state);
+	struct l2cap_chan	*(*new_connection) (struct l2cap_chan *chan);
+	int			(*recv) (struct l2cap_chan * chan,
+					 struct sk_buff *skb);
+	void			(*teardown) (struct l2cap_chan *chan, int err);
+	void			(*close) (struct l2cap_chan *chan);
+	void			(*state_change) (struct l2cap_chan *chan,
+						 int state);
+	void			(*ready) (struct l2cap_chan *chan);
 	struct sk_buff		*(*alloc_skb) (struct l2cap_chan *chan,
 					       unsigned long len, int nb);
 };
@@ -575,6 +581,7 @@ struct l2cap_conn {
 #define L2CAP_CHAN_RAW			1
 #define L2CAP_CHAN_CONN_LESS		2
 #define L2CAP_CHAN_CONN_ORIENTED	3
+#define L2CAP_CHAN_CONN_FIX_A2MP	4
 
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
@@ -597,6 +604,7 @@ enum {
 	CONF_EWS_RECV,
 	CONF_LOC_CONF_PEND,
 	CONF_REM_CONF_PEND,
+	CONF_NOT_COMPLETE,
 };
 
 #define L2CAP_CONF_MAX_CONF_REQ 2
@@ -713,11 +721,7 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
 
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
 #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
-#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
-		msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
 #define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
-#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
-		msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
 #define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
 #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
 		msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
@@ -736,173 +740,17 @@ static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
 	return (seq + 1) % (chan->tx_win_max + 1);
 }
 
-static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
-{
-	int sub;
-
-	sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64;
-
-	if (sub < 0)
-		sub += 64;
-
-	return sub == ch->remote_tx_win;
-}
-
-static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (ctrl & L2CAP_EXT_CTRL_REQSEQ) >>
-						L2CAP_EXT_CTRL_REQSEQ_SHIFT;
-	else
-		return (ctrl & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
-}
-
-static inline __u32 __set_reqseq(struct l2cap_chan *chan, __u32 reqseq)
+static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan *chan)
 {
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT) &
-							L2CAP_EXT_CTRL_REQSEQ;
-	else
-		return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & L2CAP_CTRL_REQSEQ;
+	return NULL;
 }
 
-static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl)
+static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err)
 {
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >>
-						L2CAP_EXT_CTRL_TXSEQ_SHIFT;
-	else
-		return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
 }
 
-static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq)
+static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
 {
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) &
-							L2CAP_EXT_CTRL_TXSEQ;
-	else
-		return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ;
-}
-
-static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE;
-	else
-		return ctrl & L2CAP_CTRL_FRAME_TYPE;
-}
-
-static inline __u32 __set_sframe(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_FRAME_TYPE;
-	else
-		return L2CAP_CTRL_FRAME_TYPE;
-}
-
-static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
-	else
-		return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
-}
-
-static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR;
-	else
-		return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR;
-}
-
-static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl)
-{
-	return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START;
-}
-
-static inline __u32 __get_sar_mask(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_SAR;
-	else
-		return L2CAP_CTRL_SAR;
-}
-
-static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >>
-						L2CAP_EXT_CTRL_SUPER_SHIFT;
-	else
-		return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
-}
-
-static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) &
-						L2CAP_EXT_CTRL_SUPERVISE;
-	else
-		return (super << L2CAP_CTRL_SUPER_SHIFT) &
-							L2CAP_CTRL_SUPERVISE;
-}
-
-static inline __u32 __set_ctrl_final(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_FINAL;
-	else
-		return L2CAP_CTRL_FINAL;
-}
-
-static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return ctrl & L2CAP_EXT_CTRL_FINAL;
-	else
-		return ctrl & L2CAP_CTRL_FINAL;
-}
-
-static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_POLL;
-	else
-		return L2CAP_CTRL_POLL;
-}
-
-static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return ctrl & L2CAP_EXT_CTRL_POLL;
-	else
-		return ctrl & L2CAP_CTRL_POLL;
-}
-
-static inline __u32 __get_control(struct l2cap_chan *chan, void *p)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return get_unaligned_le32(p);
-	else
-		return get_unaligned_le16(p);
-}
-
-static inline void __put_control(struct l2cap_chan *chan, __u32 control,
-								void *p)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return put_unaligned_le32(control, p);
-	else
-		return put_unaligned_le16(control, p);
-}
-
-static inline __u8 __ctrl_size(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
-	else
-		return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
 }
 
 extern bool disable_ertm;
@@ -926,5 +774,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 int l2cap_chan_check_security(struct l2cap_chan *chan);
 void l2cap_chan_set_defaults(struct l2cap_chan *chan);
+int l2cap_ertm_init(struct l2cap_chan *chan);
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+void l2cap_chan_del(struct l2cap_chan *chan, int err);
 
 #endif /* __L2CAP_H */
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 23fd054..4348ee8 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -444,7 +444,7 @@ struct mgmt_ev_auth_failed {
 struct mgmt_ev_device_found {
 	struct mgmt_addr_info addr;
 	__s8	rssi;
-	__u8	flags[4];
+	__le32	flags;
 	__le16	eir_len;
 	__u8	eir[0];
 } __packed;
diff --git a/include/net/caif/caif_hsi.h b/include/net/caif/caif_hsi.h
index 439dadc..bcb9cc3 100644
--- a/include/net/caif/caif_hsi.h
+++ b/include/net/caif/caif_hsi.h
@@ -93,25 +93,25 @@ struct cfhsi_desc {
 #endif
 
 /* Structure implemented by the CAIF HSI driver. */
-struct cfhsi_drv {
-	void (*tx_done_cb) (struct cfhsi_drv *drv);
-	void (*rx_done_cb) (struct cfhsi_drv *drv);
-	void (*wake_up_cb) (struct cfhsi_drv *drv);
-	void (*wake_down_cb) (struct cfhsi_drv *drv);
+struct cfhsi_cb_ops {
+	void (*tx_done_cb) (struct cfhsi_cb_ops *drv);
+	void (*rx_done_cb) (struct cfhsi_cb_ops *drv);
+	void (*wake_up_cb) (struct cfhsi_cb_ops *drv);
+	void (*wake_down_cb) (struct cfhsi_cb_ops *drv);
 };
 
 /* Structure implemented by HSI device. */
-struct cfhsi_dev {
-	int (*cfhsi_up) (struct cfhsi_dev *dev);
-	int (*cfhsi_down) (struct cfhsi_dev *dev);
-	int (*cfhsi_tx) (u8 *ptr, int len, struct cfhsi_dev *dev);
-	int (*cfhsi_rx) (u8 *ptr, int len, struct cfhsi_dev *dev);
-	int (*cfhsi_wake_up) (struct cfhsi_dev *dev);
-	int (*cfhsi_wake_down) (struct cfhsi_dev *dev);
-	int (*cfhsi_get_peer_wake) (struct cfhsi_dev *dev, bool *status);
-	int (*cfhsi_fifo_occupancy)(struct cfhsi_dev *dev, size_t *occupancy);
-	int (*cfhsi_rx_cancel)(struct cfhsi_dev *dev);
-	struct cfhsi_drv *drv;
+struct cfhsi_ops {
+	int (*cfhsi_up) (struct cfhsi_ops *dev);
+	int (*cfhsi_down) (struct cfhsi_ops *dev);
+	int (*cfhsi_tx) (u8 *ptr, int len, struct cfhsi_ops *dev);
+	int (*cfhsi_rx) (u8 *ptr, int len, struct cfhsi_ops *dev);
+	int (*cfhsi_wake_up) (struct cfhsi_ops *dev);
+	int (*cfhsi_wake_down) (struct cfhsi_ops *dev);
+	int (*cfhsi_get_peer_wake) (struct cfhsi_ops *dev, bool *status);
+	int (*cfhsi_fifo_occupancy) (struct cfhsi_ops *dev, size_t *occupancy);
+	int (*cfhsi_rx_cancel)(struct cfhsi_ops *dev);
+	struct cfhsi_cb_ops *cb_ops;
 };
 
 /* Structure holds status of received CAIF frames processing */
@@ -132,17 +132,26 @@ enum {
 	CFHSI_PRIO_LAST,
 };
 
+struct cfhsi_config {
+	u32 inactivity_timeout;
+	u32 aggregation_timeout;
+	u32 head_align;
+	u32 tail_align;
+	u32 q_high_mark;
+	u32 q_low_mark;
+};
+
 /* Structure implemented by CAIF HSI drivers. */
 struct cfhsi {
 	struct caif_dev_common cfdev;
 	struct net_device *ndev;
 	struct platform_device *pdev;
 	struct sk_buff_head qhead[CFHSI_PRIO_LAST];
-	struct cfhsi_drv drv;
-	struct cfhsi_dev *dev;
+	struct cfhsi_cb_ops cb_ops;
+	struct cfhsi_ops *ops;
 	int tx_state;
 	struct cfhsi_rx_state rx_state;
-	unsigned long inactivity_timeout;
+	struct cfhsi_config cfg;
 	int rx_len;
 	u8 *rx_ptr;
 	u8 *tx_buf;
@@ -150,8 +159,6 @@ struct cfhsi {
 	u8 *rx_flip_buf;
 	spinlock_t lock;
 	int flow_off_sent;
-	u32 q_low_mark;
-	u32 q_high_mark;
 	struct list_head list;
 	struct work_struct wake_up_work;
 	struct work_struct wake_down_work;
@@ -164,13 +171,31 @@ struct cfhsi {
 	struct timer_list rx_slowpath_timer;
 
 	/* TX aggregation */
-	unsigned long aggregation_timeout;
 	int aggregation_len;
 	struct timer_list aggregation_timer;
 
 	unsigned long bits;
 };
-
 extern struct platform_driver cfhsi_driver;
 
+/**
+ * enum ifla_caif_hsi - CAIF HSI NetlinkRT parameters.
+ * @IFLA_CAIF_HSI_INACTIVITY_TOUT: Inactivity timeout before
+ *			taking the HSI wakeline down, in milliseconds.
+ * When using RT Netlink to create, destroy or configure a CAIF HSI interface,
+ * enum ifla_caif_hsi is used to specify the configuration attributes.
+ */
+enum ifla_caif_hsi {
+	__IFLA_CAIF_HSI_UNSPEC,
+	__IFLA_CAIF_HSI_INACTIVITY_TOUT,
+	__IFLA_CAIF_HSI_AGGREGATION_TOUT,
+	__IFLA_CAIF_HSI_HEAD_ALIGN,
+	__IFLA_CAIF_HSI_TAIL_ALIGN,
+	__IFLA_CAIF_HSI_QHIGH_WATERMARK,
+	__IFLA_CAIF_HSI_QLOW_WATERMARK,
+	__IFLA_CAIF_HSI_MAX
+};
+
+extern struct cfhsi_ops *cfhsi_get_ops(void);
+
 #endif		/* CAIF_HSI_H_ */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0289d4c..061c019 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -404,6 +404,8 @@ struct cfg80211_beacon_data {
  *
  * Used to configure an AP interface.
  *
+ * @channel: the channel to start the AP on
+ * @channel_type: the channel type to use
  * @beacon: beacon data
  * @beacon_interval: beacon interval
  * @dtim_period: DTIM period
@@ -417,6 +419,9 @@ struct cfg80211_beacon_data {
  * @inactivity_timeout: time in seconds to determine station's inactivity.
  */
 struct cfg80211_ap_settings {
+	struct ieee80211_channel *channel;
+	enum nl80211_channel_type channel_type;
+
 	struct cfg80211_beacon_data beacon;
 
 	int beacon_interval, dtim_period;
@@ -622,10 +627,10 @@ struct sta_bss_parameters {
  * @llid: mesh local link id
  * @plid: mesh peer link id
  * @plink_state: mesh peer link state
- * @signal: the signal strength, type depends on the wiphy's signal_type
-	NOTE: For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
- * @signal_avg: avg signal strength, type depends on the wiphy's signal_type
-	NOTE: For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
+ * @signal: The signal strength, type depends on the wiphy's signal_type.
+ *	For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
+ * @signal_avg: Average signal strength, type depends on the wiphy's signal_type.
+ *	For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
  * @txrate: current unicast bitrate from this station
  * @rxrate: current unicast bitrate to this station
  * @rx_packets: packets received from this station
@@ -785,47 +790,101 @@ struct bss_parameters {
 	int ht_opmode;
 };
 
-/*
+/**
  * struct mesh_config - 802.11s mesh configuration
  *
  * These parameters can be changed while the mesh is active.
+ *
+ * @dot11MeshRetryTimeout: the initial retry timeout in millisecond units used
+ *	by the Mesh Peering Open message
+ * @dot11MeshConfirmTimeout: the initial retry timeout in millisecond units
+ *	used by the Mesh Peering Open message
+ * @dot11MeshHoldingTimeout: the confirm timeout in millisecond units used by
+ *	the mesh peering management to close a mesh peering
+ * @dot11MeshMaxPeerLinks: the maximum number of peer links allowed on this
+ *	mesh interface
+ * @dot11MeshMaxRetries: the maximum number of peer link open retries that can
+ *	be sent to establish a new peer link instance in a mesh
+ * @dot11MeshTTL: the value of TTL field set at a source mesh STA
+ * @element_ttl: the value of TTL field set at a mesh STA for path selection
+ *	elements
+ * @auto_open_plinks: whether we should automatically open peer links when we
+ *	detect compatible mesh peers
+ * @dot11MeshNbrOffsetMaxNeighbor: the maximum number of neighbors to
+ *	synchronize to for 11s default synchronization method
+ * @dot11MeshHWMPmaxPREQretries: the number of action frames containing a PREQ
+ *	that an originator mesh STA can send to a particular path target
+ * @path_refresh_time: how frequently to refresh mesh paths in milliseconds
+ * @min_discovery_timeout: the minimum length of time to wait until giving up on
+ *	a path discovery in milliseconds
+ * @dot11MeshHWMPactivePathTimeout: the time (in TUs) for which mesh STAs
+ *	receiving a PREQ shall consider the forwarding information from the
+ *	root to be valid. (TU = time unit)
+ * @dot11MeshHWMPpreqMinInterval: the minimum interval of time (in TUs) during
+ *	which a mesh STA can send only one action frame containing a PREQ
+ *	element
+ * @dot11MeshHWMPperrMinInterval: the minimum interval of time (in TUs) during
+ *	which a mesh STA can send only one Action frame containing a PERR
+ *	element
+ * @dot11MeshHWMPnetDiameterTraversalTime: the interval of time (in TUs) that
+ *	it takes for an HWMP information element to propagate across the mesh
+ * @dot11MeshHWMPRootMode: the configuration of a mesh STA as root mesh STA
+ * @dot11MeshHWMPRannInterval: the interval of time (in TUs) between root
+ *	announcements are transmitted
+ * @dot11MeshGateAnnouncementProtocol: whether to advertise that this mesh
+ *	station has access to a broader network beyond the MBSS. (This is
+ *	missnamed in draft 12.0: dot11MeshGateAnnouncementProtocol set to true
+ *	only means that the station will announce others it's a mesh gate, but
+ *	not necessarily using the gate announcement protocol. Still keeping the
+ *	same nomenclature to be in sync with the spec)
+ * @dot11MeshForwarding: whether the Mesh STA is forwarding or non-forwarding
+ *	entity (default is TRUE - forwarding entity)
+ * @rssi_threshold: the threshold for average signal strength of candidate
+ *	station to establish a peer link
+ * @ht_opmode: mesh HT protection mode
+ *
+ * @dot11MeshHWMPactivePathToRootTimeout: The time (in TUs) for which mesh STAs
+ *	receiving a proactive PREQ shall consider the forwarding information to
+ *	the root mesh STA to be valid.
+ *
+ * @dot11MeshHWMProotInterval: The interval of time (in TUs) between proactive
+ *	PREQs are transmitted.
+ * @dot11MeshHWMPconfirmationInterval: The minimum interval of time (in TUs)
+ *	during which a mesh STA can send only one Action frame containing
+ *	a PREQ element for root path confirmation.
  */
 struct mesh_config {
-	/* Timeouts in ms */
-	/* Mesh plink management parameters */
 	u16 dot11MeshRetryTimeout;
 	u16 dot11MeshConfirmTimeout;
 	u16 dot11MeshHoldingTimeout;
 	u16 dot11MeshMaxPeerLinks;
-	u8  dot11MeshMaxRetries;
-	u8  dot11MeshTTL;
-	/* ttl used in path selection information elements */
-	u8  element_ttl;
+	u8 dot11MeshMaxRetries;
+	u8 dot11MeshTTL;
+	u8 element_ttl;
 	bool auto_open_plinks;
-	/* neighbor offset synchronization */
 	u32 dot11MeshNbrOffsetMaxNeighbor;
-	/* HWMP parameters */
-	u8  dot11MeshHWMPmaxPREQretries;
+	u8 dot11MeshHWMPmaxPREQretries;
 	u32 path_refresh_time;
 	u16 min_discovery_timeout;
 	u32 dot11MeshHWMPactivePathTimeout;
 	u16 dot11MeshHWMPpreqMinInterval;
 	u16 dot11MeshHWMPperrMinInterval;
 	u16 dot11MeshHWMPnetDiameterTraversalTime;
-	u8  dot11MeshHWMPRootMode;
+	u8 dot11MeshHWMPRootMode;
 	u16 dot11MeshHWMPRannInterval;
-	/* This is missnamed in draft 12.0: dot11MeshGateAnnouncementProtocol
-	 * set to true only means that the station will announce others it's a
-	 * mesh gate, but not necessarily using the gate announcement protocol.
-	 * Still keeping the same nomenclature to be in sync with the spec. */
-	bool  dot11MeshGateAnnouncementProtocol;
+	bool dot11MeshGateAnnouncementProtocol;
 	bool dot11MeshForwarding;
 	s32 rssi_threshold;
 	u16 ht_opmode;
+	u32 dot11MeshHWMPactivePathToRootTimeout;
+	u16 dot11MeshHWMProotInterval;
+	u16 dot11MeshHWMPconfirmationInterval;
 };
 
 /**
  * struct mesh_setup - 802.11s mesh setup configuration
+ * @channel: the channel to start the mesh network on
+ * @channel_type: the channel type to use
  * @mesh_id: the mesh ID
  * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
  * @sync_method: which synchronization method to use
@@ -840,6 +899,8 @@ struct mesh_config {
  * These parameters are fixed when the mesh is created.
  */
 struct mesh_setup {
+	struct ieee80211_channel *channel;
+	enum nl80211_channel_type channel_type;
 	const u8 *mesh_id;
 	u8 mesh_id_len;
 	u8 sync_method;
@@ -966,6 +1027,7 @@ struct cfg80211_match_set {
  * @wiphy: the wiphy this was for
  * @dev: the interface
  * @channels: channels to scan
+ * @rssi_thold: don't report scan results below this threshold (in s32 dBm)
  */
 struct cfg80211_sched_scan_request {
 	struct cfg80211_ssid *ssids;
@@ -976,6 +1038,7 @@ struct cfg80211_sched_scan_request {
 	size_t ie_len;
 	struct cfg80211_match_set *match_sets;
 	int n_match_sets;
+	s32 rssi_thold;
 
 	/* internal */
 	struct wiphy *wiphy;
@@ -1411,11 +1474,14 @@ struct cfg80211_gtk_rekey_data {
  *
  * @set_txq_params: Set TX queue parameters
  *
- * @set_channel: Set channel for a given wireless interface. Some devices
- *	may support multi-channel operation (by channel hopping) so cfg80211
- *	doesn't verify much. Note, however, that the passed netdev may be
- *	%NULL as well if the user requested changing the channel for the
- *	device itself, or for a monitor interface.
+ * @libertas_set_mesh_channel: Only for backward compatibility for libertas,
+ *	as it doesn't implement join_mesh and needs to set the channel to
+ *	join the mesh instead.
+ *
+ * @set_monitor_channel: Set the monitor mode channel for the device. If other
+ *	interfaces are active this callback should reject the configuration.
+ *	If no interfaces are active or the device is down, the channel should
+ *	be stored for when a monitor interface becomes active.
  * @get_channel: Get the current operating channel, should return %NULL if
  *	there's no single defined operating channel if for example the
  *	device implements channel hopping for multi-channel virtual interfaces.
@@ -1605,9 +1671,13 @@ struct cfg80211_ops {
 	int	(*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
 				  struct ieee80211_txq_params *params);
 
-	int	(*set_channel)(struct wiphy *wiphy, struct net_device *dev,
-			       struct ieee80211_channel *chan,
-			       enum nl80211_channel_type channel_type);
+	int	(*libertas_set_mesh_channel)(struct wiphy *wiphy,
+					     struct net_device *dev,
+					     struct ieee80211_channel *chan);
+
+	int	(*set_monitor_channel)(struct wiphy *wiphy,
+				       struct ieee80211_channel *chan,
+				       enum nl80211_channel_type channel_type);
 
 	int	(*scan)(struct wiphy *wiphy, struct net_device *dev,
 			struct cfg80211_scan_request *request);
@@ -2263,7 +2333,10 @@ struct cfg80211_cached_keys;
  * @netdev: (private) Used to reference back to the netdev
  * @current_bss: (private) Used by the internal configuration code
  * @channel: (private) Used by the internal configuration code to track
- *	user-set AP, monitor and WDS channels for wireless extensions
+ *	the user-set AP, monitor and WDS channel
+ * @preset_chan: (private) Used by the internal configuration code to
+ *	track the channel to be used for AP later
+ * @preset_chantype: (private) the corresponding channel type
  * @bssid: (private) Used by the internal configuration code
  * @ssid: (private) Used by the internal configuration code
  * @ssid_len: (private) Used by the internal configuration code
@@ -2313,7 +2386,8 @@ struct wireless_dev {
 	spinlock_t event_lock;
 
 	struct cfg80211_internal_bss *current_bss; /* associated / joined */
-	struct ieee80211_channel *channel;
+	struct ieee80211_channel *preset_chan;
+	enum nl80211_channel_type preset_chantype;
 
 	bool ps;
 	int ps_timeout;
@@ -3359,11 +3433,14 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
 				 const u8 *frame, size_t len,
 				 int freq, int sig_dbm, gfp_t gfp);
 
-/*
+/**
  * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
  * @wiphy: the wiphy
  * @chan: main channel
  * @channel_type: HT mode
+ *
+ * This function returns true if there is no secondary channel or the secondary
+ * channel can be used for beaconing (i.e. is not a radar channel etc.)
  */
 bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
 				  struct ieee80211_channel *chan,
diff --git a/include/net/dst.h b/include/net/dst.h
index 8197ead..f0bf3b8 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -48,8 +48,8 @@ struct dst_entry {
 #else
 	void			*__pad1;
 #endif
-	int			(*input)(struct sk_buff*);
-	int			(*output)(struct sk_buff*);
+	int			(*input)(struct sk_buff *);
+	int			(*output)(struct sk_buff *);
 
 	int			flags;
 #define DST_HOST		0x0001
@@ -241,7 +241,7 @@ dst_metric_locked(const struct dst_entry *dst, int metric)
 	return dst_metric(dst, RTAX_LOCK) & (1<<metric);
 }
 
-static inline void dst_hold(struct dst_entry * dst)
+static inline void dst_hold(struct dst_entry *dst)
 {
 	/*
 	 * If your kernel compilation stops here, please check
@@ -264,8 +264,7 @@ static inline void dst_use_noref(struct dst_entry *dst, unsigned long time)
 	dst->lastuse = time;
 }
 
-static inline
-struct dst_entry * dst_clone(struct dst_entry * dst)
+static inline struct dst_entry *dst_clone(struct dst_entry *dst)
 {
 	if (dst)
 		atomic_inc(&dst->__refcnt);
@@ -371,12 +370,12 @@ static inline struct dst_entry *skb_dst_pop(struct sk_buff *skb)
 }
 
 extern int dst_discard(struct sk_buff *skb);
-extern void *dst_alloc(struct dst_ops * ops, struct net_device *dev,
+extern void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
 		       int initial_ref, int initial_obsolete, int flags);
-extern void __dst_free(struct dst_entry * dst);
-extern struct dst_entry *dst_destroy(struct dst_entry * dst);
+extern void __dst_free(struct dst_entry *dst);
+extern struct dst_entry *dst_destroy(struct dst_entry *dst);
 
-static inline void dst_free(struct dst_entry * dst)
+static inline void dst_free(struct dst_entry *dst)
 {
 	if (dst->obsolete > 1)
 		return;
diff --git a/include/net/flow.h b/include/net/flow.h
index 6c469db..bd524f5 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -22,6 +22,7 @@ struct flowi_common {
 #define FLOWI_FLAG_ANYSRC		0x01
 #define FLOWI_FLAG_PRECOW_METRICS	0x02
 #define FLOWI_FLAG_CAN_SLEEP		0x04
+#define FLOWI_FLAG_RT_NOCACHE		0x08
 	__u32	flowic_secid;
 };
 
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index 7d83f90..af3c743 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -43,7 +43,7 @@ struct inet_connection_sock_af_ops {
 	struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb,
 				      struct request_sock *req,
 				      struct dst_entry *dst);
-	struct inet_peer *(*get_peer)(struct sock *sk, bool *release_it);
+	struct inet_peer *(*get_peer)(struct sock *sk);
 	u16	    net_header_len;
 	u16	    net_frag_header_len;
 	u16	    sockaddr_len;
@@ -251,7 +251,8 @@ extern int inet_csk_get_port(struct sock *sk, unsigned short snum);
 
 extern struct dst_entry* inet_csk_route_req(struct sock *sk,
 					    struct flowi4 *fl4,
-					    const struct request_sock *req);
+					    const struct request_sock *req,
+					    bool nocache);
 extern struct dst_entry* inet_csk_route_child_sock(struct sock *sk,
 						   struct sock *newsk,
 						   const struct request_sock *req);
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 808fc5f..54be028 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -379,10 +379,10 @@ static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo,
 					     const __be16 sport,
 					     const __be16 dport)
 {
-	struct sock *sk;
+	struct sock *sk = skb_steal_sock(skb);
 	const struct iphdr *iph = ip_hdr(skb);
 
-	if (unlikely(sk = skb_steal_sock(skb)))
+	if (sk)
 		return sk;
 	else
 		return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo,
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index 2040bff..c27c8f1 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -65,6 +65,69 @@ struct inet_peer {
 	atomic_t		refcnt;
 };
 
+struct inet_peer_base {
+	struct inet_peer __rcu	*root;
+	seqlock_t		lock;
+	u32			flush_seq;
+	int			total;
+};
+
+#define INETPEER_BASE_BIT	0x1UL
+
+static inline struct inet_peer *inetpeer_ptr(unsigned long val)
+{
+	BUG_ON(val & INETPEER_BASE_BIT);
+	return (struct inet_peer *) val;
+}
+
+static inline struct inet_peer_base *inetpeer_base_ptr(unsigned long val)
+{
+	if (!(val & INETPEER_BASE_BIT))
+		return NULL;
+	val &= ~INETPEER_BASE_BIT;
+	return (struct inet_peer_base *) val;
+}
+
+static inline bool inetpeer_ptr_is_peer(unsigned long val)
+{
+	return !(val & INETPEER_BASE_BIT);
+}
+
+static inline void __inetpeer_ptr_set_peer(unsigned long *val, struct inet_peer *peer)
+{
+	/* This implicitly clears INETPEER_BASE_BIT */
+	*val = (unsigned long) peer;
+}
+
+static inline bool inetpeer_ptr_set_peer(unsigned long *ptr, struct inet_peer *peer)
+{
+	unsigned long val = (unsigned long) peer;
+	unsigned long orig = *ptr;
+
+	if (!(orig & INETPEER_BASE_BIT) ||
+	    cmpxchg(ptr, orig, val) != orig)
+		return false;
+	return true;
+}
+
+static inline void inetpeer_init_ptr(unsigned long *ptr, struct inet_peer_base *base)
+{
+	*ptr = (unsigned long) base | INETPEER_BASE_BIT;
+}
+
+static inline void inetpeer_transfer_peer(unsigned long *to, unsigned long *from)
+{
+	unsigned long val = *from;
+
+	*to = val;
+	if (inetpeer_ptr_is_peer(val)) {
+		struct inet_peer *peer = inetpeer_ptr(val);
+		atomic_inc(&peer->refcnt);
+	}
+}
+
+extern void inet_peer_base_init(struct inet_peer_base *);
+
 void			inet_initpeers(void) __init;
 
 #define INETPEER_METRICS_NEW	(~(u32) 0)
@@ -75,31 +138,38 @@ static inline bool inet_metrics_new(const struct inet_peer *p)
 }
 
 /* can be called with or without local BH being disabled */
-struct inet_peer	*inet_getpeer(const struct inetpeer_addr *daddr, int create);
+struct inet_peer *inet_getpeer(struct inet_peer_base *base,
+			       const struct inetpeer_addr *daddr,
+			       int create);
 
-static inline struct inet_peer *inet_getpeer_v4(__be32 v4daddr, int create)
+static inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base,
+						__be32 v4daddr,
+						int create)
 {
 	struct inetpeer_addr daddr;
 
 	daddr.addr.a4 = v4daddr;
 	daddr.family = AF_INET;
-	return inet_getpeer(&daddr, create);
+	return inet_getpeer(base, &daddr, create);
 }
 
-static inline struct inet_peer *inet_getpeer_v6(const struct in6_addr *v6daddr, int create)
+static inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base,
+						const struct in6_addr *v6daddr,
+						int create)
 {
 	struct inetpeer_addr daddr;
 
 	*(struct in6_addr *)daddr.addr.a6 = *v6daddr;
 	daddr.family = AF_INET6;
-	return inet_getpeer(&daddr, create);
+	return inet_getpeer(base, &daddr, create);
 }
 
 /* can be called from BH context or outside */
 extern void inet_putpeer(struct inet_peer *p);
 extern bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout);
 
-extern void inetpeer_invalidate_tree(int family);
+extern void inetpeer_invalidate_tree(struct inet_peer_base *);
+extern void inetpeer_invalidate_family(int family);
 
 /*
  * temporary check to make sure we dont access rid, ip_id_count, tcp_ts,
diff --git a/include/net/ip.h b/include/net/ip.h
index 83e0619..50841bd 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -210,6 +210,9 @@ extern int inet_peer_threshold;
 extern int inet_peer_minttl;
 extern int inet_peer_maxttl;
 
+/* From ip_input.c */
+extern int sysctl_ip_early_demux;
+
 /* From ip_output.c */
 extern int sysctl_ip_dynaddr;
 
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 0ae759a..a192f78 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -107,7 +107,7 @@ struct rt6_info {
 	u32				rt6i_peer_genid;
 
 	struct inet6_dev		*rt6i_idev;
-	struct inet_peer		*rt6i_peer;
+	unsigned long			_rt6i_peer;
 
 #ifdef CONFIG_XFRM
 	u32				rt6i_flow_cache_genid;
@@ -118,6 +118,36 @@ struct rt6_info {
 	u8				rt6i_protocol;
 };
 
+static inline struct inet_peer *rt6_peer_ptr(struct rt6_info *rt)
+{
+	return inetpeer_ptr(rt->_rt6i_peer);
+}
+
+static inline bool rt6_has_peer(struct rt6_info *rt)
+{
+	return inetpeer_ptr_is_peer(rt->_rt6i_peer);
+}
+
+static inline void __rt6_set_peer(struct rt6_info *rt, struct inet_peer *peer)
+{
+	__inetpeer_ptr_set_peer(&rt->_rt6i_peer, peer);
+}
+
+static inline bool rt6_set_peer(struct rt6_info *rt, struct inet_peer *peer)
+{
+	return inetpeer_ptr_set_peer(&rt->_rt6i_peer, peer);
+}
+
+static inline void rt6_init_peer(struct rt6_info *rt, struct inet_peer_base *base)
+{
+	inetpeer_init_ptr(&rt->_rt6i_peer, base);
+}
+
+static inline void rt6_transfer_peer(struct rt6_info *rt, struct rt6_info *ort)
+{
+	inetpeer_transfer_peer(&rt->_rt6i_peer, &ort->_rt6i_peer);
+}
+
 static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
 {
 	return ((struct rt6_info *)dst)->rt6i_idev;
@@ -207,6 +237,7 @@ struct fib6_table {
 	u32			tb6_id;
 	rwlock_t		tb6_lock;
 	struct fib6_node	tb6_root;
+	struct inet_peer_base	tb6_peers;
 };
 
 #define RT6_TABLE_UNSPEC	RT_TABLE_UNSPEC
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 37c1a1e..58cb3fc 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -53,16 +53,25 @@ static inline unsigned int rt6_flags2srcprefs(int flags)
 	return (flags >> 3) & 7;
 }
 
-extern void			rt6_bind_peer(struct rt6_info *rt,
-					      int create);
+extern void rt6_bind_peer(struct rt6_info *rt, int create);
+
+static inline struct inet_peer *__rt6_get_peer(struct rt6_info *rt, int create)
+{
+	if (rt6_has_peer(rt))
+		return rt6_peer_ptr(rt);
+
+	rt6_bind_peer(rt, create);
+	return (rt6_has_peer(rt) ? rt6_peer_ptr(rt) : NULL);
+}
 
 static inline struct inet_peer *rt6_get_peer(struct rt6_info *rt)
 {
-	if (rt->rt6i_peer)
-		return rt->rt6i_peer;
+	return __rt6_get_peer(rt, 0);
+}
 
-	rt6_bind_peer(rt, 0);
-	return rt->rt6i_peer;
+static inline struct inet_peer *rt6_get_peer_create(struct rt6_info *rt)
+{
+	return __rt6_get_peer(rt, 1);
 }
 
 extern void			ip6_route_input(struct sk_buff *skb);
@@ -131,10 +140,10 @@ extern void			rt6_redirect(const struct in6_addr *dest,
 					     u8 *lladdr,
 					     int on_link);
 
-extern void			rt6_pmtu_discovery(const struct in6_addr *daddr,
-						   const struct in6_addr *saddr,
-						   struct net_device *dev,
-						   u32 pmtu);
+extern void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
+			    int oif, u32 mark);
+extern void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk,
+			       __be32 mtu);
 
 struct netlink_callback;
 
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 78df0866..4b347c0 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -19,6 +19,7 @@
 #include <net/flow.h>
 #include <linux/seq_file.h>
 #include <net/fib_rules.h>
+#include <net/inetpeer.h>
 
 struct fib_config {
 	u8			fc_dst_len;
@@ -157,11 +158,12 @@ extern __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh);
 					 FIB_RES_SADDR(net, res))
 
 struct fib_table {
-	struct hlist_node tb_hlist;
-	u32		tb_id;
-	int		tb_default;
-	int		tb_num_default;
-	unsigned long	tb_data[0];
+	struct hlist_node	tb_hlist;
+	u32			tb_id;
+	int			tb_default;
+	int			tb_num_default;
+	struct inet_peer_base	tb_peers;
+	unsigned long		tb_data[0];
 };
 
 extern int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h
index 59ba38bc..80ffde3 100644
--- a/include/net/irda/ircomm_tty.h
+++ b/include/net/irda/ircomm_tty.h
@@ -52,21 +52,16 @@
 /* Same for payload size. See qos.c for the smallest max data size */
 #define IRCOMM_TTY_DATA_UNINITIALISED	(64 - IRCOMM_TTY_HDR_UNINITIALISED)
 
-/* Those are really defined in include/linux/serial.h - Jean II */
-#define ASYNC_B_INITIALIZED	31	/* Serial port was initialized */
-#define ASYNC_B_NORMAL_ACTIVE	29	/* Normal device is active */
-#define ASYNC_B_CLOSING		27	/* Serial port is closing */
-
 /*
  * IrCOMM TTY driver state
  */
 struct ircomm_tty_cb {
 	irda_queue_t queue;            /* Must be first */
+	struct tty_port port;
 	magic_t magic;
 
 	int state;                /* Connect state */
 
-	struct tty_struct *tty;
 	struct ircomm_cb *ircomm; /* IrCOMM layer instance */
 
 	struct sk_buff *tx_skb;   /* Transmit buffer */
@@ -80,7 +75,6 @@ struct ircomm_tty_cb {
 	LOCAL_FLOW flow;          /* IrTTP flow status */
 
 	int line;
-	unsigned long flags;
 
 	__u8 dlsap_sel;
 	__u8 slsap_sel;
@@ -97,19 +91,10 @@ struct ircomm_tty_cb {
 	void *skey;
 	void *ckey;
 
-	wait_queue_head_t open_wait;
-	wait_queue_head_t close_wait;
 	struct timer_list watchdog_timer;
 	struct work_struct  tqueue;
 
-        unsigned short    close_delay;
-        unsigned short    closing_wait; /* time to wait before closing */
-
-	int  open_count;
-	int  blocked_open;	/* # of blocked opens */
-
 	/* Protect concurent access to :
-	 *	o self->open_count
 	 *	o self->ctrl_skb
 	 *	o self->tx_skb
 	 * Maybe other things may gain to be protected as well...
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 1937c7d..670a58b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1297,6 +1297,10 @@ enum ieee80211_hw_flags {
  *	reports, by default it is set to _MCS, _GI and _BW but doesn't
  *	include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only
  *	adding _BW is supported today.
+ *
+ * @netdev_features: netdev features to be set in each netdev created
+ *	from this HW. Note only HW checksum features are currently
+ *	compatible with mac80211. Other feature bits will be rejected.
  */
 struct ieee80211_hw {
 	struct ieee80211_conf conf;
@@ -1319,6 +1323,7 @@ struct ieee80211_hw {
 	u8 max_tx_aggregation_subframes;
 	u8 offchannel_tx_hw_queue;
 	u8 radiotap_mcs_details;
+	netdev_features_t netdev_features;
 };
 
 /**
@@ -1940,6 +1945,11 @@ enum ieee80211_rate_control_changed {
  *	to also unregister the device. If it returns 1, then mac80211
  *	will also go through the regular complete restart on resume.
  *
+ * @set_wakeup: Enable or disable wakeup when WoWLAN configuration is
+ *	modified. The reason is that device_set_wakeup_enable() is
+ *	supposed to be called when the configuration changes, not only
+ *	in suspend().
+ *
  * @add_interface: Called when a netdevice attached to the hardware is
  *	enabled. Because it is not called for monitor mode devices, @start
  *	and @stop must be implemented.
@@ -2178,7 +2188,10 @@ enum ieee80211_rate_control_changed {
  *	offload. Frames to transmit on the off-channel channel are transmitted
  *	normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the
  *	duration (which will always be non-zero) expires, the driver must call
- *	ieee80211_remain_on_channel_expired(). This callback may sleep.
+ *	ieee80211_remain_on_channel_expired().
+ *	Note that this callback may be called while the device is in IDLE and
+ *	must be accepted in this case.
+ *	This callback may sleep.
  * @cancel_remain_on_channel: Requests that an ongoing off-channel period is
  *	aborted before it expires. This callback may sleep.
  *
@@ -2241,6 +2254,9 @@ enum ieee80211_rate_control_changed {
  * @get_et_strings:  Ethtool API to get a set of strings to describe stats
  *	and perhaps other supported types of ethtool data-sets.
  *
+ * @get_rssi: Get current signal strength in dBm, the function is optional
+ *	and can sleep.
+ *
  */
 struct ieee80211_ops {
 	void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -2380,6 +2396,8 @@ struct ieee80211_ops {
 	void	(*get_et_strings)(struct ieee80211_hw *hw,
 				  struct ieee80211_vif *vif,
 				  u32 sset, u8 *data);
+	int	(*get_rssi)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			    struct ieee80211_sta *sta, s8 *rssi_dbm);
 };
 
 /**
@@ -2966,6 +2984,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
  * ieee80211_generic_frame_duration - Calculate the duration field for a frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @band: the band to calculate the frame duration on
  * @frame_len: the length of the frame.
  * @rate: the rate at which the frame is going to be transmitted.
  *
@@ -3551,16 +3570,6 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 			       gfp_t gfp);
 
 /**
- * ieee80211_get_operstate - get the operstate of the vif
- *
- * @vif: &struct ieee80211_vif pointer from the add_interface callback.
- *
- * The driver might need to know the operstate of the net_device
- * (specifically, whether the link is IF_OPER_UP after resume)
- */
-unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif);
-
-/**
  * ieee80211_chswitch_done - Complete channel switch process
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @success: make the channel switch successful or not
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index cce7f6a..f1494fe 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -39,36 +39,6 @@ union nf_conntrack_expect_proto {
 	/* insert expect proto private data here */
 };
 
-/* Add protocol helper include file here */
-#include <linux/netfilter/nf_conntrack_ftp.h>
-#include <linux/netfilter/nf_conntrack_pptp.h>
-#include <linux/netfilter/nf_conntrack_h323.h>
-#include <linux/netfilter/nf_conntrack_sane.h>
-#include <linux/netfilter/nf_conntrack_sip.h>
-
-/* per conntrack: application helper private data */
-union nf_conntrack_help {
-	/* insert conntrack helper private data (master) here */
-#if defined(CONFIG_NF_CONNTRACK_FTP) || defined(CONFIG_NF_CONNTRACK_FTP_MODULE)
-	struct nf_ct_ftp_master ct_ftp_info;
-#endif
-#if defined(CONFIG_NF_CONNTRACK_PPTP) || \
-    defined(CONFIG_NF_CONNTRACK_PPTP_MODULE)
-	struct nf_ct_pptp_master ct_pptp_info;
-#endif
-#if defined(CONFIG_NF_CONNTRACK_H323) || \
-    defined(CONFIG_NF_CONNTRACK_H323_MODULE)
-	struct nf_ct_h323_master ct_h323_info;
-#endif
-#if defined(CONFIG_NF_CONNTRACK_SANE) || \
-    defined(CONFIG_NF_CONNTRACK_SANE_MODULE)
-	struct nf_ct_sane_master ct_sane_info;
-#endif
-#if defined(CONFIG_NF_CONNTRACK_SIP) || defined(CONFIG_NF_CONNTRACK_SIP_MODULE)
-	struct nf_ct_sip_master ct_sip_info;
-#endif
-};
-
 #include <linux/types.h>
 #include <linux/skbuff.h>
 #include <linux/timer.h>
@@ -89,12 +59,13 @@ struct nf_conn_help {
 	/* Helper. if any */
 	struct nf_conntrack_helper __rcu *helper;
 
-	union nf_conntrack_help help;
-
 	struct hlist_head expectations;
 
 	/* Current number of expected connections */
 	u8 expecting[NF_CT_MAX_EXPECT_CLASSES];
+
+	/* private helper information. */
+	char data[];
 };
 
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index aced085..d8f5b9f 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -28,8 +28,8 @@ extern unsigned int nf_conntrack_in(struct net *net,
 extern int nf_conntrack_init(struct net *net);
 extern void nf_conntrack_cleanup(struct net *net);
 
-extern int nf_conntrack_proto_init(void);
-extern void nf_conntrack_proto_fini(void);
+extern int nf_conntrack_proto_init(struct net *net);
+extern void nf_conntrack_proto_fini(struct net *net);
 
 extern bool
 nf_ct_get_tuple(const struct sk_buff *skb,
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index 4619caa..983f002 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -59,10 +59,12 @@ static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
 	return nf_ct_net(exp->master);
 }
 
+#define NF_CT_EXP_POLICY_NAME_LEN	16
+
 struct nf_conntrack_expect_policy {
 	unsigned int	max_expected;
 	unsigned int	timeout;
-	const char	*name;
+	char		name[NF_CT_EXP_POLICY_NAME_LEN];
 };
 
 #define NF_CT_EXPECT_CLASS_DEFAULT	0
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index 96755c3..8b4d1fc2 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -80,10 +80,13 @@ static inline void nf_ct_ext_free(struct nf_conn *ct)
 }
 
 /* Add this type, returns pointer to data or NULL. */
-void *
-__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp);
+void *__nf_ct_ext_add_length(struct nf_conn *ct, enum nf_ct_ext_id id,
+			     size_t var_alloc_len, gfp_t gfp);
+
 #define nf_ct_ext_add(ct, id, gfp) \
-	((id##_TYPE *)__nf_ct_ext_add((ct), (id), (gfp)))
+	((id##_TYPE *)__nf_ct_ext_add_length((ct), (id), 0, (gfp)))
+#define nf_ct_ext_add_length(ct, id, len, gfp) \
+	((id##_TYPE *)__nf_ct_ext_add_length((ct), (id), (len), (gfp)))
 
 #define NF_CT_EXT_F_PREALLOC	0x0001
 
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index 1d18894..9aad956 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -11,18 +11,27 @@
 #define _NF_CONNTRACK_HELPER_H
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_extend.h>
+#include <net/netfilter/nf_conntrack_expect.h>
 
 struct module;
 
+enum nf_ct_helper_flags {
+	NF_CT_HELPER_F_USERSPACE	= (1 << 0),
+	NF_CT_HELPER_F_CONFIGURED	= (1 << 1),
+};
+
 #define NF_CT_HELPER_NAME_LEN	16
 
 struct nf_conntrack_helper {
 	struct hlist_node hnode;	/* Internal use. */
 
-	const char *name;		/* name of the module */
+	char name[NF_CT_HELPER_NAME_LEN]; /* name of the module */
 	struct module *me;		/* pointer to self */
 	const struct nf_conntrack_expect_policy *expect_policy;
 
+	/* length of internal data, ie. sizeof(struct nf_ct_*_master) */
+	size_t data_len;
+
 	/* Tuple of things we will help (compared against server response) */
 	struct nf_conntrack_tuple tuple;
 
@@ -35,8 +44,12 @@ struct nf_conntrack_helper {
 
 	void (*destroy)(struct nf_conn *ct);
 
+	int (*from_nlattr)(struct nlattr *attr, struct nf_conn *ct);
 	int (*to_nlattr)(struct sk_buff *skb, const struct nf_conn *ct);
 	unsigned int expect_class_max;
+
+	unsigned int flags;
+	unsigned int queue_num;		/* For user-space helpers. */
 };
 
 extern struct nf_conntrack_helper *
@@ -48,7 +61,7 @@ nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum);
 extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
 extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
 
-extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp);
+extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, struct nf_conntrack_helper *helper, gfp_t gfp);
 
 extern int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
 				     gfp_t flags);
@@ -60,6 +73,15 @@ static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
 	return nf_ct_ext_find(ct, NF_CT_EXT_HELPER);
 }
 
+static inline void *nfct_help_data(const struct nf_conn *ct)
+{
+	struct nf_conn_help *help;
+
+	help = nf_ct_ext_find(ct, NF_CT_EXT_HELPER);
+
+	return (void *)help->data;
+}
+
 extern int nf_conntrack_helper_init(struct net *net);
 extern void nf_conntrack_helper_fini(struct net *net);
 
@@ -82,4 +104,7 @@ nf_ct_helper_expectfn_find_by_name(const char *name);
 struct nf_ct_helper_expectfn *
 nf_ct_helper_expectfn_find_by_symbol(const void *symbol);
 
+extern struct hlist_head *nf_ct_helper_hash;
+extern unsigned int nf_ct_helper_hsize;
+
 #endif /*_NF_CONNTRACK_HELPER_H*/
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index 9699c02..6f7c13f 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -64,11 +64,12 @@ struct nf_conntrack_l3proto {
 	size_t nla_size;
 
 #ifdef CONFIG_SYSCTL
-	struct ctl_table_header	*ctl_table_header;
 	const char		*ctl_table_path;
-	struct ctl_table	*ctl_table;
 #endif /* CONFIG_SYSCTL */
 
+	/* Init l3proto pernet data */
+	int (*init_net)(struct net *net);
+
 	/* Module (if any) which this is connected to. */
 	struct module *me;
 };
@@ -76,8 +77,10 @@ struct nf_conntrack_l3proto {
 extern struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX];
 
 /* Protocol registration. */
-extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto);
-extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto);
+extern int nf_conntrack_l3proto_register(struct net *net,
+					 struct nf_conntrack_l3proto *proto);
+extern void nf_conntrack_l3proto_unregister(struct net *net,
+					    struct nf_conntrack_l3proto *proto);
 extern struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto);
 extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p);
 
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index 3b572bb..81c52b5 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -12,6 +12,7 @@
 #include <linux/netlink.h>
 #include <net/netlink.h>
 #include <net/netfilter/nf_conntrack.h>
+#include <net/netns/generic.h>
 
 struct seq_file;
 
@@ -86,23 +87,18 @@ struct nf_conntrack_l4proto {
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 	struct {
 		size_t obj_size;
-		int (*nlattr_to_obj)(struct nlattr *tb[], void *data);
+		int (*nlattr_to_obj)(struct nlattr *tb[],
+				     struct net *net, void *data);
 		int (*obj_to_nlattr)(struct sk_buff *skb, const void *data);
 
 		unsigned int nlattr_max;
 		const struct nla_policy *nla_policy;
 	} ctnl_timeout;
 #endif
+	int	*net_id;
+	/* Init l4proto pernet data */
+	int (*init_net)(struct net *net);
 
-#ifdef CONFIG_SYSCTL
-	struct ctl_table_header	**ctl_table_header;
-	struct ctl_table	*ctl_table;
-	unsigned int		*ctl_table_users;
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-	struct ctl_table_header	*ctl_compat_table_header;
-	struct ctl_table	*ctl_compat_table;
-#endif
-#endif
 	/* Protocol name */
 	const char *name;
 
@@ -123,8 +119,10 @@ nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto);
 extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p);
 
 /* Protocol registration. */
-extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto);
-extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto);
+extern int nf_conntrack_l4proto_register(struct net *net,
+					 struct nf_conntrack_l4proto *proto);
+extern void nf_conntrack_l4proto_unregister(struct net *net,
+					    struct nf_conntrack_l4proto *proto);
 
 /* Generic netlink helpers */
 extern int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb,
diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h
index 02bb6c2..7d8fb7b 100644
--- a/include/net/netfilter/nf_nat_helper.h
+++ b/include/net/netfilter/nf_nat_helper.h
@@ -54,4 +54,8 @@ extern void nf_nat_follow_master(struct nf_conn *ct,
 extern s16 nf_nat_get_offset(const struct nf_conn *ct,
 			     enum ip_conntrack_dir dir,
 			     u32 seq);
+
+extern void nf_nat_tcp_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
+				  u32 dir, int off);
+
 #endif
diff --git a/include/net/netfilter/nfnetlink_queue.h b/include/net/netfilter/nfnetlink_queue.h
new file mode 100644
index 0000000..86267a5
--- /dev/null
+++ b/include/net/netfilter/nfnetlink_queue.h
@@ -0,0 +1,43 @@
+#ifndef _NET_NFNL_QUEUE_H_
+#define _NET_NFNL_QUEUE_H_
+
+#include <linux/netfilter/nf_conntrack_common.h>
+
+struct nf_conn;
+
+#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
+struct nf_conn *nfqnl_ct_get(struct sk_buff *entskb, size_t *size,
+			     enum ip_conntrack_info *ctinfo);
+struct nf_conn *nfqnl_ct_parse(const struct sk_buff *skb,
+			       const struct nlattr *attr,
+			       enum ip_conntrack_info *ctinfo);
+int nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct,
+		 enum ip_conntrack_info ctinfo);
+void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
+			 enum ip_conntrack_info ctinfo, int diff);
+#else
+inline struct nf_conn *
+nfqnl_ct_get(struct sk_buff *entskb, size_t *size, enum ip_conntrack_info *ctinfo)
+{
+	return NULL;
+}
+
+inline struct nf_conn *nfqnl_ct_parse(const struct sk_buff *skb,
+				      const struct nlattr *attr,
+				      enum ip_conntrack_info *ctinfo)
+{
+	return NULL;
+}
+
+inline int
+nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo)
+{
+	return 0;
+}
+
+inline void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
+				enum ip_conntrack_info ctinfo, int diff)
+{
+}
+#endif /* NF_CONNTRACK */
+#endif
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index a053a19..3aecdc7 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -4,10 +4,64 @@
 #include <linux/list.h>
 #include <linux/list_nulls.h>
 #include <linux/atomic.h>
+#include <linux/netfilter/nf_conntrack_tcp.h>
 
 struct ctl_table_header;
 struct nf_conntrack_ecache;
 
+struct nf_proto_net {
+#ifdef CONFIG_SYSCTL
+	struct ctl_table_header *ctl_table_header;
+	struct ctl_table        *ctl_table;
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+	struct ctl_table_header *ctl_compat_header;
+	struct ctl_table        *ctl_compat_table;
+#endif
+#endif
+	unsigned int		users;
+};
+
+struct nf_generic_net {
+	struct nf_proto_net pn;
+	unsigned int timeout;
+};
+
+struct nf_tcp_net {
+	struct nf_proto_net pn;
+	unsigned int timeouts[TCP_CONNTRACK_TIMEOUT_MAX];
+	unsigned int tcp_loose;
+	unsigned int tcp_be_liberal;
+	unsigned int tcp_max_retrans;
+};
+
+enum udp_conntrack {
+	UDP_CT_UNREPLIED,
+	UDP_CT_REPLIED,
+	UDP_CT_MAX
+};
+
+struct nf_udp_net {
+	struct nf_proto_net pn;
+	unsigned int timeouts[UDP_CT_MAX];
+};
+
+struct nf_icmp_net {
+	struct nf_proto_net pn;
+	unsigned int timeout;
+};
+
+struct nf_ip_net {
+	struct nf_generic_net   generic;
+	struct nf_tcp_net	tcp;
+	struct nf_udp_net	udp;
+	struct nf_icmp_net	icmp;
+	struct nf_icmp_net	icmpv6;
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+	struct ctl_table_header *ctl_table_header;
+	struct ctl_table	*ctl_table;
+#endif
+};
+
 struct netns_ct {
 	atomic_t		count;
 	unsigned int		expect_count;
@@ -28,6 +82,7 @@ struct netns_ct {
 	unsigned int		sysctl_log_invalid; /* Log invalid packets */
 	int			sysctl_auto_assign_helper;
 	bool			auto_assign_helper_warned;
+	struct nf_ip_net	nf_ct_proto;
 #ifdef CONFIG_SYSCTL
 	struct ctl_table_header	*sysctl_header;
 	struct ctl_table_header	*acct_sysctl_header;
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index bbd023a..227f0cd 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -30,7 +30,7 @@ struct netns_ipv4 {
 
 	struct sock		**icmp_sk;
 	struct sock		*tcp_sock;
-
+	struct inet_peer_base	*peers;
 	struct netns_frags	frags;
 #ifdef CONFIG_NETFILTER
 	struct xt_table		*iptable_filter;
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index b42be53..df0a545 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -33,6 +33,7 @@ struct netns_ipv6 {
 	struct netns_sysctl_ipv6 sysctl;
 	struct ipv6_devconf	*devconf_all;
 	struct ipv6_devconf	*devconf_dflt;
+	struct inet_peer_base	*peers;
 	struct netns_frags	frags;
 #ifdef CONFIG_NETFILTER
 	struct xt_table		*ip6table_filter;
diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h
index 4467c94..e30e6a8 100644
--- a/include/net/nfc/hci.h
+++ b/include/net/nfc/hci.h
@@ -31,7 +31,8 @@ struct nfc_hci_ops {
 	void (*close) (struct nfc_hci_dev *hdev);
 	int (*hci_ready) (struct nfc_hci_dev *hdev);
 	int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
-	int (*start_poll) (struct nfc_hci_dev *hdev, u32 protocols);
+	int (*start_poll) (struct nfc_hci_dev *hdev,
+			   u32 im_protocols, u32 tm_protocols);
 	int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
 				 struct nfc_target *target);
 	int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index b7ca4a2..180964b 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -53,7 +53,8 @@ struct nfc_target;
 struct nfc_ops {
 	int (*dev_up)(struct nfc_dev *dev);
 	int (*dev_down)(struct nfc_dev *dev);
-	int (*start_poll)(struct nfc_dev *dev, u32 protocols);
+	int (*start_poll)(struct nfc_dev *dev,
+			  u32 im_protocols, u32 tm_protocols);
 	void (*stop_poll)(struct nfc_dev *dev);
 	int (*dep_link_up)(struct nfc_dev *dev, struct nfc_target *target,
 			   u8 comm_mode, u8 *gb, size_t gb_len);
@@ -62,9 +63,10 @@ struct nfc_ops {
 			       u32 protocol);
 	void (*deactivate_target)(struct nfc_dev *dev,
 				  struct nfc_target *target);
-	int (*data_exchange)(struct nfc_dev *dev, struct nfc_target *target,
+	int (*im_transceive)(struct nfc_dev *dev, struct nfc_target *target,
 			     struct sk_buff *skb, data_exchange_cb_t cb,
 			     void *cb_context);
+	int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb);
 	int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target);
 };
 
@@ -99,10 +101,10 @@ struct nfc_dev {
 	int targets_generation;
 	struct device dev;
 	bool dev_up;
+	u8 rf_mode;
 	bool polling;
 	struct nfc_target *active_target;
 	bool dep_link_up;
-	u32 dep_rf_mode;
 	struct nfc_genl_data genl_data;
 	u32 supported_protocols;
 
@@ -188,6 +190,7 @@ struct sk_buff *nfc_alloc_recv_skb(unsigned int size, gfp_t gfp);
 
 int nfc_set_remote_general_bytes(struct nfc_dev *dev,
 				 u8 *gt, u8 gt_len);
+u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len);
 
 int nfc_targets_found(struct nfc_dev *dev,
 		      struct nfc_target *targets, int ntargets);
@@ -196,4 +199,9 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx);
 int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
 		       u8 comm_mode, u8 rf_mode);
 
+int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
+		     u8 *gb, size_t gb_len);
+int nfc_tm_deactivated(struct nfc_dev *dev);
+int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb);
+
 #endif /* __NET_NFC_H */
diff --git a/include/net/nfc/shdlc.h b/include/net/nfc/shdlc.h
index ab06afd..35e930d 100644
--- a/include/net/nfc/shdlc.h
+++ b/include/net/nfc/shdlc.h
@@ -27,7 +27,8 @@ struct nfc_shdlc_ops {
 	void (*close) (struct nfc_shdlc *shdlc);
 	int (*hci_ready) (struct nfc_shdlc *shdlc);
 	int (*xmit) (struct nfc_shdlc *shdlc, struct sk_buff *skb);
-	int (*start_poll) (struct nfc_shdlc *shdlc, u32 protocols);
+	int (*start_poll) (struct nfc_shdlc *shdlc,
+			   u32 im_protocols, u32 tm_protocols);
 	int (*target_from_gate) (struct nfc_shdlc *shdlc, u8 gate,
 				 struct nfc_target *target);
 	int (*complete_target_discovered) (struct nfc_shdlc *shdlc, u8 gate,
diff --git a/include/net/phonet/gprs.h b/include/net/phonet/gprs.h
index 928daf5..bcd525e 100644
--- a/include/net/phonet/gprs.h
+++ b/include/net/phonet/gprs.h
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation.
  *
- * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
+ * Author: Rémi Denis-Courmont
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/include/net/protocol.h b/include/net/protocol.h
index 875f489..967b926 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -29,11 +29,15 @@
 #include <linux/ipv6.h>
 #endif
 
-#define MAX_INET_PROTOS	256		/* Must be a power of 2		*/
-
+/* This is one larger than the largest protocol value that can be
+ * found in an ipv4 or ipv6 header.  Since in both cases the protocol
+ * value is presented in a __u8, this is defined to be 256.
+ */
+#define MAX_INET_PROTOS		256
 
 /* This is used to register protocols. */
 struct net_protocol {
+	int			(*early_demux)(struct sk_buff *skb);
 	int			(*handler)(struct sk_buff *skb);
 	void			(*err_handler)(struct sk_buff *skb, u32 info);
 	int			(*gso_send_check)(struct sk_buff *skb);
diff --git a/include/net/route.h b/include/net/route.h
index 9870546..47eb25a 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -67,10 +67,44 @@ struct rtable {
 	/* Miscellaneous cached information */
 	__be32			rt_spec_dst; /* RFC1122 specific destination */
 	u32			rt_peer_genid;
-	struct inet_peer	*peer; /* long-living peer info */
+	unsigned long		_peer; /* long-living peer info */
 	struct fib_info		*fi; /* for client ref to shared metrics */
 };
 
+static inline struct inet_peer *rt_peer_ptr(struct rtable *rt)
+{
+	return inetpeer_ptr(rt->_peer);
+}
+
+static inline bool rt_has_peer(struct rtable *rt)
+{
+	return inetpeer_ptr_is_peer(rt->_peer);
+}
+
+static inline void __rt_set_peer(struct rtable *rt, struct inet_peer *peer)
+{
+	__inetpeer_ptr_set_peer(&rt->_peer, peer);
+}
+
+static inline bool rt_set_peer(struct rtable *rt, struct inet_peer *peer)
+{
+	return inetpeer_ptr_set_peer(&rt->_peer, peer);
+}
+
+static inline void rt_init_peer(struct rtable *rt, struct inet_peer_base *base)
+{
+	inetpeer_init_ptr(&rt->_peer, base);
+}
+
+static inline void rt_transfer_peer(struct rtable *rt, struct rtable *ort)
+{
+	rt->_peer = ort->_peer;
+	if (rt_has_peer(ort)) {
+		struct inet_peer *peer = rt_peer_ptr(ort);
+		atomic_inc(&peer->refcnt);
+	}
+}
+
 static inline bool rt_is_input_route(const struct rtable *rt)
 {
 	return rt->rt_route_iif != 0;
@@ -181,9 +215,10 @@ static inline int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 s
 	return ip_route_input_common(skb, dst, src, tos, devin, true);
 }
 
-extern unsigned short	ip_rt_frag_needed(struct net *net, const struct iphdr *iph,
-					  unsigned short new_mtu, struct net_device *dev);
-extern void		ip_rt_send_redirect(struct sk_buff *skb);
+extern void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
+			     int oif, u32 mark, u8 protocol, int flow_flags);
+extern void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu);
+extern void ip_rt_send_redirect(struct sk_buff *skb);
 
 extern unsigned int		inet_addr_type(struct net *net, __be32 addr);
 extern unsigned int		inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr);
@@ -296,13 +331,23 @@ static inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable
 
 extern void rt_bind_peer(struct rtable *rt, __be32 daddr, int create);
 
+static inline struct inet_peer *__rt_get_peer(struct rtable *rt, __be32 daddr, int create)
+{
+	if (rt_has_peer(rt))
+		return rt_peer_ptr(rt);
+
+	rt_bind_peer(rt, daddr, create);
+	return (rt_has_peer(rt) ? rt_peer_ptr(rt) : NULL);
+}
+
 static inline struct inet_peer *rt_get_peer(struct rtable *rt, __be32 daddr)
 {
-	if (rt->peer)
-		return rt->peer;
+	return __rt_get_peer(rt, daddr, 0);
+}
 
-	rt_bind_peer(rt, daddr, 0);
-	return rt->peer;
+static inline struct inet_peer *rt_get_peer_create(struct rtable *rt, __be32 daddr)
+{
+	return __rt_get_peer(rt, daddr, 1);
 }
 
 static inline int inet_iif(const struct sk_buff *skb)
diff --git a/include/net/sock.h b/include/net/sock.h
index 4a45216..dcb54a0 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -198,6 +198,7 @@ struct cg_proto;
   *	@sk_lock:	synchronizer
   *	@sk_rcvbuf: size of receive buffer in bytes
   *	@sk_wq: sock wait queue and async head
+  *	@sk_rx_dst: receive input route used by early tcp demux
   *	@sk_dst_cache: destination cache
   *	@sk_dst_lock: destination cache lock
   *	@sk_policy: flow policy
@@ -317,6 +318,7 @@ struct sock {
 	struct xfrm_policy	*sk_policy[2];
 #endif
 	unsigned long 		sk_flags;
+	struct dst_entry	*sk_rx_dst;
 	struct dst_entry	*sk_dst_cache;
 	spinlock_t		sk_dst_lock;
 	atomic_t		sk_wmem_alloc;
@@ -1426,6 +1428,7 @@ extern struct sk_buff		*sock_rmalloc(struct sock *sk,
 					      gfp_t priority);
 extern void			sock_wfree(struct sk_buff *skb);
 extern void			sock_rfree(struct sk_buff *skb);
+extern void			sock_edemux(struct sk_buff *skb);
 
 extern int			sock_setsockopt(struct socket *sock, int level,
 						int op, char __user *optval,
@@ -2152,7 +2155,7 @@ static inline void sk_change_net(struct sock *sk, struct net *net)
 
 static inline struct sock *skb_steal_sock(struct sk_buff *skb)
 {
-	if (unlikely(skb->sk)) {
+	if (skb->sk) {
 		struct sock *sk = skb->sk;
 
 		skb->destructor = NULL;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index e79aa48..6660ffc 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -325,10 +325,10 @@ extern void tcp_v4_err(struct sk_buff *skb, u32);
 
 extern void tcp_shutdown (struct sock *sk, int how);
 
+extern int tcp_v4_early_demux(struct sk_buff *skb);
 extern int tcp_v4_rcv(struct sk_buff *skb);
 
-extern struct inet_peer *tcp_v4_get_peer(struct sock *sk, bool *release_it);
-extern void *tcp_v4_tw_get_peer(struct sock *sk);
+extern struct inet_peer *tcp_v4_get_peer(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);
diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h
index 8d6689c..68f0eca 100644
--- a/include/net/timewait_sock.h
+++ b/include/net/timewait_sock.h
@@ -22,7 +22,6 @@ struct timewait_sock_ops {
 	int		(*twsk_unique)(struct sock *sk,
 				       struct sock *sktw, void *twp);
 	void		(*twsk_destructor)(struct sock *sk);
-	void		*(*twsk_getpeer)(struct sock *sk);
 };
 
 static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
@@ -41,11 +40,4 @@ static inline void twsk_destructor(struct sock *sk)
 		sk->sk_prot->twsk_prot->twsk_destructor(sk);
 }
 
-static inline void *twsk_getpeer(struct sock *sk)
-{
-	if (sk->sk_prot->twsk_prot->twsk_getpeer)
-		return sk->sk_prot->twsk_prot->twsk_getpeer(sk);
-	return NULL;
-}
-
 #endif /* _TIMEWAIT_SOCK_H */
diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
new file mode 100644
index 0000000..260470e
--- /dev/null
+++ b/include/ras/ras_event.h
@@ -0,0 +1,102 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ras
+#define TRACE_INCLUDE_FILE ras_event
+
+#if !defined(_TRACE_HW_EVENT_MC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_HW_EVENT_MC_H
+
+#include <linux/tracepoint.h>
+#include <linux/edac.h>
+#include <linux/ktime.h>
+
+/*
+ * Hardware Events Report
+ *
+ * Those events are generated when hardware detected a corrected or
+ * uncorrected event, and are meant to replace the current API to report
+ * errors defined on both EDAC and MCE subsystems.
+ *
+ * FIXME: Add events for handling memory errors originated from the
+ *        MCE subsystem.
+ */
+
+/*
+ * Hardware-independent Memory Controller specific events
+ */
+
+/*
+ * Default error mechanisms for Memory Controller errors (CE and UE)
+ */
+TRACE_EVENT(mc_event,
+
+	TP_PROTO(const unsigned int err_type,
+		 const char *error_msg,
+		 const char *label,
+		 const int error_count,
+		 const u8 mc_index,
+		 const s8 top_layer,
+		 const s8 mid_layer,
+		 const s8 low_layer,
+		 unsigned long address,
+		 const u8 grain_bits,
+		 unsigned long syndrome,
+		 const char *driver_detail),
+
+	TP_ARGS(err_type, error_msg, label, error_count, mc_index,
+		top_layer, mid_layer, low_layer, address, grain_bits,
+		syndrome, driver_detail),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	error_type		)
+		__string(	msg,		error_msg		)
+		__string(	label,		label			)
+		__field(	u16,		error_count		)
+		__field(	u8,		mc_index		)
+		__field(	s8,		top_layer		)
+		__field(	s8,		middle_layer		)
+		__field(	s8,		lower_layer		)
+		__field(	long,		address			)
+		__field(	u8,		grain_bits		)
+		__field(	long,		syndrome		)
+		__string(	driver_detail,	driver_detail		)
+	),
+
+	TP_fast_assign(
+		__entry->error_type		= err_type;
+		__assign_str(msg, error_msg);
+		__assign_str(label, label);
+		__entry->error_count		= error_count;
+		__entry->mc_index		= mc_index;
+		__entry->top_layer		= top_layer;
+		__entry->middle_layer		= mid_layer;
+		__entry->lower_layer		= low_layer;
+		__entry->address		= address;
+		__entry->grain_bits		= grain_bits;
+		__entry->syndrome		= syndrome;
+		__assign_str(driver_detail, driver_detail);
+	),
+
+	TP_printk("%d %s error%s:%s%s on %s (mc:%d location:%d:%d:%d address:0x%08lx grain:%d syndrome:0x%08lx%s%s)",
+		  __entry->error_count,
+		  (__entry->error_type == HW_EVENT_ERR_CORRECTED) ? "Corrected" :
+			((__entry->error_type == HW_EVENT_ERR_FATAL) ?
+			"Fatal" : "Uncorrected"),
+		  __entry->error_count > 1 ? "s" : "",
+		  ((char *)__get_str(msg))[0] ? " " : "",
+		  __get_str(msg),
+		  __get_str(label),
+		  __entry->mc_index,
+		  __entry->top_layer,
+		  __entry->middle_layer,
+		  __entry->lower_layer,
+		  __entry->address,
+		  1 << __entry->grain_bits,
+		  __entry->syndrome,
+		  ((char *)__get_str(driver_detail))[0] ? " " : "",
+		  __get_str(driver_detail))
+);
+
+#endif /* _TRACE_HW_EVENT_MC_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 8f9dfba..399162b 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -224,7 +224,7 @@ struct fc_rport_priv {
 };
 
 /**
- * struct fcoe_dev_stats - fcoe stats structure
+ * struct fc_stats - fc stats structure
  * @SecondsSinceLastReset: Seconds since the last reset
  * @TxFrames:              Number of transmitted frames
  * @TxWords:               Number of transmitted words
@@ -232,6 +232,9 @@ struct fc_rport_priv {
  * @RxWords:               Number of received words
  * @ErrorFrames:           Number of received error frames
  * @DumpedFrames:          Number of dumped frames
+ * @FcpPktAllocFails:      Number of fcp packet allocation failures
+ * @FcpPktAborts:          Number of fcp packet aborts
+ * @FcpFrameAllocFails:    Number of fcp frame allocation failures
  * @LinkFailureCount:      Number of link failures
  * @LossOfSignalCount:     Number for signal losses
  * @InvalidTxWordCount:    Number of invalid transmitted words
@@ -244,7 +247,7 @@ struct fc_rport_priv {
  * @VLinkFailureCount:     Number of virtual link failures
  * @MissDiscAdvCount:      Number of missing FIP discovery advertisement
  */
-struct fcoe_dev_stats {
+struct fc_stats {
 	u64		SecondsSinceLastReset;
 	u64		TxFrames;
 	u64		TxWords;
@@ -252,6 +255,9 @@ struct fcoe_dev_stats {
 	u64		RxWords;
 	u64		ErrorFrames;
 	u64		DumpedFrames;
+	u64		FcpPktAllocFails;
+	u64		FcpPktAborts;
+	u64		FcpFrameAllocFails;
 	u64		LinkFailureCount;
 	u64		LossOfSignalCount;
 	u64		InvalidTxWordCount;
@@ -510,7 +516,7 @@ struct libfc_function_template {
 	int (*ddp_done)(struct fc_lport *, u16);
 	/*
 	 * Sets up the DDP context for a given exchange id on the given
-	 * scatterlist if LLD supports DDP for FCoE target.
+	 * scatterlist if LLD supports DDP for target.
 	 *
 	 * STATUS: OPTIONAL
 	 */
@@ -817,8 +823,7 @@ enum fc_lport_event {
  * @state:                 Identifies the state
  * @boot_time:             Timestamp indicating when the local port came online
  * @host_stats:            SCSI host statistics
- * @dev_stats:             FCoE device stats (TODO: libfc should not be
- *                         FCoE aware)
+ * @stats:                 FC local port stats (TODO separate libfc LLD stats)
  * @retry_count:           Number of retries in the current state
  * @port_id:               FC Port ID
  * @wwpn:                  World Wide Port Name
@@ -867,7 +872,7 @@ struct fc_lport {
 	enum fc_lport_state	       state;
 	unsigned long		       boot_time;
 	struct fc_host_statistics      host_stats;
-	struct fcoe_dev_stats __percpu *dev_stats;
+	struct fc_stats	__percpu       *stats;
 	u8			       retry_count;
 
 	/* Fabric information */
@@ -980,8 +985,8 @@ static inline void fc_lport_state_enter(struct fc_lport *lport,
  */
 static inline int fc_lport_init_stats(struct fc_lport *lport)
 {
-	lport->dev_stats = alloc_percpu(struct fcoe_dev_stats);
-	if (!lport->dev_stats)
+	lport->stats = alloc_percpu(struct fc_stats);
+	if (!lport->stats)
 		return -ENOMEM;
 	return 0;
 }
@@ -992,7 +997,7 @@ static inline int fc_lport_init_stats(struct fc_lport *lport)
  */
 static inline void fc_lport_free_stats(struct fc_lport *lport)
 {
-	free_percpu(lport->dev_stats);
+	free_percpu(lport->stats);
 }
 
 /**
@@ -1116,6 +1121,7 @@ void fc_fill_hdr(struct fc_frame *, const struct fc_frame *,
  * EXCHANGE MANAGER LAYER
  *****************************/
 int fc_exch_init(struct fc_lport *);
+void fc_exch_update_stats(struct fc_lport *lport);
 struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *,
 					   struct fc_exch_mgr *,
 					   bool (*match)(struct fc_frame *));
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index f4f1c96..5c7677f 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -79,7 +79,8 @@ enum phy_event {
 	PHYE_OOB_DONE         = 1,
 	PHYE_OOB_ERROR        = 2,
 	PHYE_SPINUP_HOLD      = 3, /* hot plug SATA, no COMWAKE sent */
-	PHY_NUM_EVENTS        = 4,
+	PHYE_RESUME_TIMEOUT   = 4,
+	PHY_NUM_EVENTS        = 5,
 };
 
 enum discover_event {
@@ -87,8 +88,10 @@ enum discover_event {
 	DISCE_REVALIDATE_DOMAIN = 1,
 	DISCE_PORT_GONE         = 2,
 	DISCE_PROBE		= 3,
-	DISCE_DESTRUCT		= 4,
-	DISC_NUM_EVENTS		= 5,
+	DISCE_SUSPEND		= 4,
+	DISCE_RESUME		= 5,
+	DISCE_DESTRUCT		= 6,
+	DISC_NUM_EVENTS		= 7,
 };
 
 /* ---------- Expander Devices ---------- */
@@ -128,7 +131,7 @@ struct ex_phy {
 	u8   attached_sas_addr[SAS_ADDR_SIZE];
 	u8   attached_phy_id;
 
-	u8   phy_change_count;
+	int phy_change_count;
 	enum routing_attribute routing_attr;
 	u8   virtual:1;
 
@@ -141,7 +144,7 @@ struct ex_phy {
 struct expander_device {
 	struct list_head children;
 
-	u16    ex_change_count;
+	int    ex_change_count;
 	u16    max_route_indexes;
 	u8     num_phys;
 
@@ -167,16 +170,25 @@ struct sata_device {
         enum   ata_command_set command_set;
         struct smp_resp        rps_resp; /* report_phy_sata_resp */
         u8     port_no;        /* port number, if this is a PM (Port) */
-        struct list_head children; /* PM Ports if this is a PM */
+	int    pm_result;
 
 	struct ata_port *ap;
 	struct ata_host ata_host;
 	struct ata_taskfile tf;
 };
 
+struct ssp_device {
+	struct list_head eh_list_node; /* pending a user requested eh action */
+	struct scsi_lun reset_lun;
+};
+
 enum {
 	SAS_DEV_GONE,
+	SAS_DEV_FOUND, /* device notified to lldd */
 	SAS_DEV_DESTROY,
+	SAS_DEV_EH_PENDING,
+	SAS_DEV_LU_RESET,
+	SAS_DEV_RESET,
 };
 
 struct domain_device {
@@ -210,6 +222,7 @@ struct domain_device {
         union {
                 struct expander_device ex_dev;
                 struct sata_device     sata_dev; /* STP & directly attached */
+		struct ssp_device      ssp_dev;
         };
 
         void *lldd_dev;
@@ -263,6 +276,7 @@ struct asd_sas_port {
 	enum   sas_linkrate linkrate;
 
 	struct sas_work work;
+	int suspended;
 
 /* public: */
 	int id;
@@ -311,6 +325,7 @@ struct asd_sas_phy {
 	unsigned long phy_events_pending;
 
 	int error;
+	int suspended;
 
 	struct sas_phy *phy;
 
@@ -384,7 +399,10 @@ struct sas_ha_struct {
 	struct list_head  defer_q; /* work queued while draining */
 	struct mutex	  drain_mutex;
 	unsigned long	  state;
-	spinlock_t 	  state_lock;
+	spinlock_t	  lock;
+	int		  eh_active;
+	wait_queue_head_t eh_wait_q;
+	struct list_head  eh_dev_q;
 
 	struct mutex disco_mutex;
 
@@ -600,10 +618,6 @@ struct sas_task {
 
 	enum   sas_protocol      task_proto;
 
-	/* Used by the discovery code. */
-	struct timer_list     timer;
-	struct completion     completion;
-
 	union {
 		struct sas_ata_task ata_task;
 		struct sas_smp_task smp_task;
@@ -620,8 +634,15 @@ struct sas_task {
 
 	void   *lldd_task;	  /* for use by LLDDs */
 	void   *uldd_task;
+	struct sas_task_slow *slow_task;
+};
 
-	struct work_struct abort_work;
+struct sas_task_slow {
+	/* standard/extra infrastructure for slow path commands (SMP and
+	 * internal lldd commands
+	 */
+	struct timer_list     timer;
+	struct completion     completion;
 };
 
 #define SAS_TASK_STATE_PENDING      1
@@ -631,6 +652,7 @@ struct sas_task {
 #define SAS_TASK_AT_INITIATOR       16
 
 extern struct sas_task *sas_alloc_task(gfp_t flags);
+extern struct sas_task *sas_alloc_slow_task(gfp_t flags);
 extern void sas_free_task(struct sas_task *task);
 
 struct sas_domain_function_template {
@@ -670,6 +692,9 @@ struct sas_domain_function_template {
 
 extern int sas_register_ha(struct sas_ha_struct *);
 extern int sas_unregister_ha(struct sas_ha_struct *);
+extern void sas_prep_resume_ha(struct sas_ha_struct *sas_ha);
+extern void sas_resume_ha(struct sas_ha_struct *sas_ha);
+extern void sas_suspend_ha(struct sas_ha_struct *sas_ha);
 
 int sas_set_phy_speed(struct sas_phy *phy,
 		      struct sas_phy_linkrates *rates);
@@ -706,6 +731,7 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *);
 void sas_init_dev(struct domain_device *);
 
 void sas_task_abort(struct sas_task *);
+int sas_eh_abort_handler(struct scsi_cmnd *cmd);
 int sas_eh_device_reset_handler(struct scsi_cmnd *cmd);
 int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd);
 
diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h
index 77670e8..ff71a56 100644
--- a/include/scsi/sas_ata.h
+++ b/include/scsi/sas_ata.h
@@ -45,6 +45,9 @@ void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
 void sas_ata_schedule_reset(struct domain_device *dev);
 void sas_ata_wait_eh(struct domain_device *dev);
 void sas_probe_sata(struct asd_sas_port *port);
+void sas_suspend_sata(struct asd_sas_port *port);
+void sas_resume_sata(struct asd_sas_port *port);
+void sas_ata_end_eh(struct ata_port *ap);
 #else
 
 
@@ -81,10 +84,22 @@ static inline void sas_probe_sata(struct asd_sas_port *port)
 {
 }
 
+static inline void sas_suspend_sata(struct asd_sas_port *port)
+{
+}
+
+static inline void sas_resume_sata(struct asd_sas_port *port)
+{
+}
+
 static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy)
 {
 	return 0;
 }
+
+static inline void sas_ata_end_eh(struct ata_port *ap)
+{
+}
 #endif
 
 #endif /* _SAS_ATA_H_ */
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index f34a5a8..c6f0974 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -161,6 +161,8 @@ struct scsi_cmnd;
 #define MI_REPORT_PRIORITY   0x0e
 #define MI_REPORT_TIMESTAMP  0x0f
 #define MI_MANAGEMENT_PROTOCOL_IN 0x10
+/* value for MI_REPORT_TARGET_PGS ext header */
+#define MI_EXT_HDR_PARAM_FMT  0x20
 /* values for maintenance out */
 #define MO_SET_IDENTIFYING_INFORMATION 0x06
 #define MO_SET_TARGET_PGS     0x0a
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 6efb2e1..bd1a14d 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -42,6 +42,7 @@ enum scsi_device_state {
 				 * originate in the mid-layer) */
 	SDEV_OFFLINE,		/* Device offlined (by error handling or
 				 * user request */
+	SDEV_TRANSPORT_OFFLINE,	/* Offlined by transport class error handler */
 	SDEV_BLOCK,		/* Device blocked by scsi lld.  No
 				 * scsi commands from user or midlayer
 				 * should be issued to the scsi
@@ -151,6 +152,7 @@ struct scsi_device {
 					   SD_LAST_BUGGY_SECTORS */
 	unsigned no_read_disc_info:1;	/* Avoid READ_DISC_INFO cmds */
 	unsigned no_read_capacity_16:1; /* Avoid READ_CAPACITY_16 cmds */
+	unsigned try_rc_10_first:1;	/* Try READ_CAPACACITY_10 first */
 	unsigned is_visible:1;	/* is the device visible in sysfs */
 
 	DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
@@ -372,7 +374,7 @@ extern void scsi_scan_target(struct device *parent, unsigned int channel,
 			     unsigned int id, unsigned int lun, int rescan);
 extern void scsi_target_reap(struct scsi_target *);
 extern void scsi_target_block(struct device *);
-extern void scsi_target_unblock(struct device *);
+extern void scsi_target_unblock(struct device *, enum scsi_device_state);
 extern void scsi_remove_target(struct device *);
 extern void int_to_scsilun(unsigned int, struct scsi_lun *);
 extern int scsilun_to_int(struct scsi_lun *);
@@ -420,6 +422,7 @@ static inline unsigned int sdev_id(struct scsi_device *sdev)
 static inline int scsi_device_online(struct scsi_device *sdev)
 {
 	return (sdev->sdev_state != SDEV_OFFLINE &&
+		sdev->sdev_state != SDEV_TRANSPORT_OFFLINE &&
 		sdev->sdev_state != SDEV_DEL);
 }
 static inline int scsi_device_blocked(struct scsi_device *sdev)
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index 719faf1..b797e8f 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -426,6 +426,18 @@ struct fc_host_statistics {
 	u64 fcp_control_requests;
 	u64 fcp_input_megabytes;
 	u64 fcp_output_megabytes;
+	u64 fcp_packet_alloc_failures;	/* fcp packet allocation failures */
+	u64 fcp_packet_aborts;		/* fcp packet aborted */
+	u64 fcp_frame_alloc_failures;	/* fcp frame allocation failures */
+
+	/* fc exches statistics */
+	u64 fc_no_free_exch;		/* no free exch memory */
+	u64 fc_no_free_exch_xid;	/* no free exch id */
+	u64 fc_xid_not_found;		/* exch not found for a response */
+	u64 fc_xid_busy;		/* exch exist for new a request */
+	u64 fc_seq_not_found;		/* seq is not found for exchange */
+	u64 fc_non_bls_resp;		/* a non BLS response frame with
+					   a sequence responder in new exch */
 };
 
 
diff --git a/include/sound/designware_i2s.h b/include/sound/designware_i2s.h
new file mode 100644
index 0000000..26f406e
--- /dev/null
+++ b/include/sound/designware_i2s.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (ST) 2012 Rajeev Kumar (rajeev-dlh.kumar@st.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __SOUND_DESIGNWARE_I2S_H
+#define __SOUND_DESIGNWARE_I2S_H
+
+#include <linux/dmaengine.h>
+#include <linux/types.h>
+
+/*
+ * struct i2s_clk_config_data - represent i2s clk configuration data
+ * @chan_nr: number of channel
+ * @data_width: number of bits per sample (8/16/24/32 bit)
+ * @sample_rate: sampling frequency (8Khz, 16Khz, 32Khz, 44Khz, 48Khz)
+ */
+struct i2s_clk_config_data {
+	int chan_nr;
+	u32 data_width;
+	u32 sample_rate;
+};
+
+struct i2s_platform_data {
+	#define DWC_I2S_PLAY	(1 << 0)
+	#define DWC_I2S_RECORD	(1 << 1)
+	unsigned int cap;
+	int channel;
+	u32 snd_fmts;
+	u32 snd_rates;
+
+	void *play_dma_data;
+	void *capture_dma_data;
+	bool (*filter)(struct dma_chan *chan, void *slave);
+	int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
+};
+
+struct i2s_dma_data {
+	void *data;
+	dma_addr_t addr;
+	u32 max_burst;
+	enum dma_slave_buswidth addr_width;
+	bool (*filter)(struct dma_chan *chan, void *slave);
+};
+
+/* I2S DMA registers */
+#define I2S_RXDMA		0x01C0
+#define I2S_TXDMA		0x01C8
+
+#define TWO_CHANNEL_SUPPORT	2	/* up to 2.0 */
+#define FOUR_CHANNEL_SUPPORT	4	/* up to 3.1 */
+#define SIX_CHANNEL_SUPPORT	6	/* up to 5.1 */
+#define EIGHT_CHANNEL_SUPPORT	8	/* up to 7.1 */
+
+#endif /*  __SOUND_DESIGNWARE_I2S_H */
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h
index a8fcaa6..b877334 100644
--- a/include/sound/dmaengine_pcm.h
+++ b/include/sound/dmaengine_pcm.h
@@ -39,6 +39,7 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
 	const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config);
 int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
 snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream);
+snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream);
 
 int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
 	dma_filter_fn filter_fn, void *filter_data);
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 0d11128..e7afcc9 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -893,6 +893,7 @@ extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates;
 
 int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime);
 unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate);
+unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit);
 
 static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substream,
 					      struct snd_dma_buffer *bufp)
@@ -1073,4 +1074,15 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
 
 const char *snd_pcm_format_name(snd_pcm_format_t format);
 
+/**
+ * Get a string naming the direction of a stream
+ */
+static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return "Playback";
+	else
+		return "Capture";
+}
+
 #endif /* __SOUND_PCM_H */
diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h
index f494f1e..37ae12e 100644
--- a/include/sound/pcm_params.h
+++ b/include/sound/pcm_params.h
@@ -22,6 +22,8 @@
  *
  */
 
+#include <sound/pcm.h>
+
 int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, 
 			   struct snd_pcm_hw_params *params,
 			   snd_pcm_hw_param_t var, int *dir);
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index e3833d9..05559e5 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -229,6 +229,10 @@ struct device;
 {	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
 	.shift = wshift, .invert = winvert, \
 	.event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \
+{	.id = snd_soc_dapm_clock_supply, .name = wname, \
+	.reg = SND_SOC_NOPM, .event = dapm_clock_event, \
+	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
 
 /* generic widgets */
 #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
@@ -245,6 +249,7 @@ struct device;
 	.reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
 
+
 /* dapm kcontrol types */
 #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -327,6 +332,8 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event);
 int dapm_regulator_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event);
+int dapm_clock_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event);
 
 /* dapm controls */
 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
@@ -432,6 +439,7 @@ enum snd_soc_dapm_type {
 	snd_soc_dapm_post,			/* machine specific post widget - exec last */
 	snd_soc_dapm_supply,		/* power/clock supply */
 	snd_soc_dapm_regulator_supply,	/* external regulator */
+	snd_soc_dapm_clock_supply,	/* external clock */
 	snd_soc_dapm_aif_in,		/* audio interface input */
 	snd_soc_dapm_aif_out,		/* audio interface output */
 	snd_soc_dapm_siggen,		/* signal generator */
@@ -537,6 +545,8 @@ struct snd_soc_dapm_widget {
 	struct list_head dirty;
 	int inputs;
 	int outputs;
+
+	struct clk *clk;
 };
 
 struct snd_soc_dapm_update {
diff --git a/include/sound/soc.h b/include/sound/soc.h
index c703871..e063380 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -42,11 +42,22 @@
 	((unsigned long)&(struct soc_mixer_control) \
 	{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
 	.max = xmax, .platform_max = xmax, .invert = xinvert})
+#define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \
+	((unsigned long)&(struct soc_mixer_control) \
+	{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
+	.min = xmin, .max = xmax, .platform_max = xmax, .invert = xinvert})
 #define SOC_SINGLE(xname, reg, shift, max, invert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
 	.put = snd_soc_put_volsw, \
 	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+#define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+	.info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \
+	.put = snd_soc_put_volsw_range, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg, .shift = xshift, .min = xmin,\
+		 .max = xmax, .platform_max = xmax, .invert = xinvert} }
 #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
@@ -67,6 +78,16 @@
 		{.reg = xreg, .rreg = xreg, \
 		.shift = xshift, .rshift = xshift, \
 		.max = xmax, .min = xmin} }
+#define SOC_SINGLE_RANGE_TLV(xname, xreg, xshift, xmin, xmax, xinvert, tlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.tlv.p = (tlv_array), \
+	.info = snd_soc_info_volsw_range, \
+	.get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg, .shift = xshift, .min = xmin,\
+		 .max = xmax, .platform_max = xmax, .invert = xinvert} }
 #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
@@ -79,6 +100,13 @@
 	.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
 	.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
 					    xmax, xinvert) }
+#define SOC_DOUBLE_R_RANGE(xname, reg_left, reg_right, xshift, xmin, \
+			   xmax, xinvert)		\
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+	.info = snd_soc_info_volsw_range, \
+	.get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
+	.private_value = SOC_DOUBLE_R_RANGE_VALUE(reg_left, reg_right, \
+					    xshift, xmin, xmax, xinvert) }
 #define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
@@ -97,6 +125,16 @@
 	.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
 	.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
 					    xmax, xinvert) }
+#define SOC_DOUBLE_R_RANGE_TLV(xname, reg_left, reg_right, xshift, xmin, \
+			       xmax, xinvert, tlv_array)		\
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.tlv.p = (tlv_array), \
+	.info = snd_soc_info_volsw_range, \
+	.get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
+	.private_value = SOC_DOUBLE_R_RANGE_VALUE(reg_left, reg_right, \
+					    xshift, xmin, xmax, xinvert) }
 #define SOC_DOUBLE_R_SX_TLV(xname, xreg, xrreg, xshift, xmin, xmax, tlv_array) \
 {       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
@@ -460,6 +498,12 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_limit_volume(struct snd_soc_codec *codec,
 	const char *name, int max);
 int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
@@ -785,13 +829,36 @@ struct snd_soc_dai_link {
 	/* config - must be set by machine driver */
 	const char *name;			/* Codec name */
 	const char *stream_name;		/* Stream name */
-	const char *codec_name;		/* for multi-codec */
-	const struct device_node *codec_of_node;
-	const char *platform_name;	/* for multi-platform */
-	const struct device_node *platform_of_node;
+	/*
+	 * You MAY specify the link's CPU-side device, either by device name,
+	 * or by DT/OF node, but not both. If this information is omitted,
+	 * the CPU-side DAI is matched using .cpu_dai_name only, which hence
+	 * must be globally unique. These fields are currently typically used
+	 * only for codec to codec links, or systems using device tree.
+	 */
+	const char *cpu_name;
+	const struct device_node *cpu_of_node;
+	/*
+	 * You MAY specify the DAI name of the CPU DAI. If this information is
+	 * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node
+	 * only, which only works well when that device exposes a single DAI.
+	 */
 	const char *cpu_dai_name;
-	const struct device_node *cpu_dai_of_node;
+	/*
+	 * You MUST specify the link's codec, either by device name, or by
+	 * DT/OF node, but not both.
+	 */
+	const char *codec_name;
+	const struct device_node *codec_of_node;
+	/* You MUST specify the DAI name within the codec */
 	const char *codec_dai_name;
+	/*
+	 * You MAY specify the link's platform/PCM/DMA driver, either by
+	 * device name, or by DT/OF node, but not both. Some forms of link
+	 * do not need a platform.
+	 */
+	const char *platform_name;
+	const struct device_node *platform_of_node;
 	int be_id;	/* optional ID for machine driver BE identification */
 
 	const struct snd_soc_pcm_stream *params;
diff --git a/include/sound/spear_dma.h b/include/sound/spear_dma.h
new file mode 100644
index 0000000..1b365bf
--- /dev/null
+++ b/include/sound/spear_dma.h
@@ -0,0 +1,35 @@
+/*
+* linux/spear_dma.h
+*
+* Copyright (ST) 2012 Rajeev Kumar (rajeev-dlh.kumar@st.com)
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#ifndef SPEAR_DMA_H
+#define SPEAR_DMA_H
+
+#include <linux/dmaengine.h>
+
+struct spear_dma_data {
+	void *data;
+	dma_addr_t addr;
+	u32 max_burst;
+	enum dma_slave_buswidth addr_width;
+	bool (*filter)(struct dma_chan *chan, void *slave);
+};
+
+#endif /* SPEAR_DMA_H */
diff --git a/include/sound/spear_spdif.h b/include/sound/spear_spdif.h
new file mode 100644
index 0000000..a12f396
--- /dev/null
+++ b/include/sound/spear_spdif.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (ST) 2012 Vipin Kumar (vipin.kumar@st.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __SOUND_SPDIF_H
+#define __SOUND_SPDIF_H
+
+struct spear_spdif_platform_data {
+	/* DMA params */
+	void *dma_params;
+	bool (*filter)(struct dma_chan *chan, void *slave);
+	void (*reset_perip)(void);
+};
+
+#endif /* SOUND_SPDIF_H */
diff --git a/include/sound/tea575x-tuner.h b/include/sound/tea575x-tuner.h
index ec3f910..0c3c2fb 100644
--- a/include/sound/tea575x-tuner.h
+++ b/include/sound/tea575x-tuner.h
@@ -44,6 +44,7 @@ struct snd_tea575x_ops {
 
 struct snd_tea575x {
 	struct v4l2_device *v4l2_dev;
+	struct v4l2_file_operations fops;
 	struct video_device vd;		/* video device */
 	int radio_nr;			/* radio_nr */
 	bool tea5759;			/* 5759 chip is present */
@@ -62,7 +63,7 @@ struct snd_tea575x {
 	int (*ext_init)(struct snd_tea575x *tea);
 };
 
-int snd_tea575x_init(struct snd_tea575x *tea);
+int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner);
 void snd_tea575x_exit(struct snd_tea575x *tea);
 
 #endif /* __SOUND_TEA575X_TUNER_H */
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h
index 2d7db85..f1405d33 100644
--- a/include/target/target_core_backend.h
+++ b/include/target/target_core_backend.h
@@ -24,10 +24,8 @@ struct se_subsystem_api {
 				struct se_subsystem_dev *, void *);
 	void (*free_device)(void *);
 	int (*transport_complete)(struct se_cmd *cmd, struct scatterlist *);
-	int (*execute_cmd)(struct se_cmd *, struct scatterlist *, u32,
-			enum dma_data_direction);
-	int (*do_discard)(struct se_device *, sector_t, u32);
-	void (*do_sync_cache)(struct se_cmd *);
+
+	int (*parse_cdb)(struct se_cmd *cmd);
 	ssize_t (*check_configfs_dev_params)(struct se_hba *,
 			struct se_subsystem_dev *);
 	ssize_t (*set_configfs_dev_params)(struct se_hba *,
@@ -40,6 +38,13 @@ struct se_subsystem_api {
 	unsigned char *(*get_sense_buffer)(struct se_cmd *);
 };
 
+struct spc_ops {
+	int (*execute_rw)(struct se_cmd *cmd);
+	int (*execute_sync_cache)(struct se_cmd *cmd);
+	int (*execute_write_same)(struct se_cmd *cmd);
+	int (*execute_unmap)(struct se_cmd *cmd);
+};
+
 int	transport_subsystem_register(struct se_subsystem_api *);
 void	transport_subsystem_release(struct se_subsystem_api *);
 
@@ -49,6 +54,10 @@ struct se_device *transport_add_device_to_core_hba(struct se_hba *,
 
 void	target_complete_cmd(struct se_cmd *, u8);
 
+int	sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops);
+int	spc_parse_cdb(struct se_cmd *cmd, unsigned int *size);
+int	spc_get_write_same_sectors(struct se_cmd *cmd);
+
 void	transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *);
 int	transport_set_vpd_assoc(struct t10_vpd *, unsigned char *);
 int	transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *);
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index dc35d86..1ae97fe 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -160,25 +160,20 @@ enum se_cmd_flags_table {
 	SCF_SUPPORTED_SAM_OPCODE	= 0x00000001,
 	SCF_TRANSPORT_TASK_SENSE	= 0x00000002,
 	SCF_EMULATED_TASK_SENSE		= 0x00000004,
-	SCF_SCSI_DATA_SG_IO_CDB		= 0x00000008,
-	SCF_SCSI_CONTROL_SG_IO_CDB	= 0x00000010,
-	SCF_SCSI_NON_DATA_CDB		= 0x00000020,
-	SCF_SCSI_TMR_CDB		= 0x00000040,
-	SCF_SCSI_CDB_EXCEPTION		= 0x00000080,
-	SCF_SCSI_RESERVATION_CONFLICT	= 0x00000100,
-	SCF_FUA				= 0x00000200,
-	SCF_SE_LUN_CMD			= 0x00000800,
-	SCF_SE_ALLOW_EOO		= 0x00001000,
-	SCF_BIDI			= 0x00002000,
-	SCF_SENT_CHECK_CONDITION	= 0x00004000,
-	SCF_OVERFLOW_BIT		= 0x00008000,
-	SCF_UNDERFLOW_BIT		= 0x00010000,
-	SCF_SENT_DELAYED_TAS		= 0x00020000,
-	SCF_ALUA_NON_OPTIMIZED		= 0x00040000,
-	SCF_DELAYED_CMD_FROM_SAM_ATTR	= 0x00080000,
-	SCF_UNUSED			= 0x00100000,
-	SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00200000,
-	SCF_ACK_KREF			= 0x00400000,
+	SCF_SCSI_DATA_CDB		= 0x00000008,
+	SCF_SCSI_TMR_CDB		= 0x00000010,
+	SCF_SCSI_CDB_EXCEPTION		= 0x00000020,
+	SCF_SCSI_RESERVATION_CONFLICT	= 0x00000040,
+	SCF_FUA				= 0x00000080,
+	SCF_SE_LUN_CMD			= 0x00000100,
+	SCF_BIDI			= 0x00000400,
+	SCF_SENT_CHECK_CONDITION	= 0x00000800,
+	SCF_OVERFLOW_BIT		= 0x00001000,
+	SCF_UNDERFLOW_BIT		= 0x00002000,
+	SCF_SENT_DELAYED_TAS		= 0x00004000,
+	SCF_ALUA_NON_OPTIMIZED		= 0x00008000,
+	SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000,
+	SCF_ACK_KREF			= 0x00040000,
 };
 
 /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
@@ -486,11 +481,8 @@ struct se_tmr_req {
 	int			call_transport;
 	/* Reference to ITT that Task Mgmt should be performed */
 	u32			ref_task_tag;
-	/* 64-bit encoded SAM LUN from $FABRIC_MOD TMR header */
-	u64			ref_task_lun;
 	void 			*fabric_tmr_ptr;
 	struct se_cmd		*task_cmd;
-	struct se_cmd		*ref_cmd;
 	struct se_device	*tmr_dev;
 	struct se_lun		*tmr_lun;
 	struct list_head	tmr_list;
@@ -575,7 +567,6 @@ struct se_cmd {
 	struct scatterlist	*t_bidi_data_sg;
 	unsigned int		t_bidi_data_nents;
 
-	struct list_head	execute_list;
 	struct list_head	state_list;
 	bool			state_active;
 
@@ -780,7 +771,6 @@ struct se_device {
 	/* Active commands on this virtual SE device */
 	atomic_t		simple_cmds;
 	atomic_t		dev_ordered_id;
-	atomic_t		execute_tasks;
 	atomic_t		dev_ordered_sync;
 	atomic_t		dev_qf_count;
 	struct se_obj		dev_obj;
@@ -806,7 +796,6 @@ struct se_device {
 	struct task_struct	*process_thread;
 	struct work_struct	qf_work_queue;
 	struct list_head	delayed_cmd_list;
-	struct list_head	execute_list;
 	struct list_head	state_list;
 	struct list_head	qf_cmd_list;
 	/* Pointer to associated SE HBA */
diff --git a/include/trace/events/frontswap.h b/include/trace/events/frontswap.h
new file mode 100644
index 0000000..2e5efab
--- /dev/null
+++ b/include/trace/events/frontswap.h
@@ -0,0 +1,167 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM frontswap
+
+#if !defined(_TRACE_FRONTSWAP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_FRONTSWAP_H
+
+#include <linux/tracepoint.h>
+
+struct frontswap_ops;
+
+TRACE_EVENT(frontswap_init,
+	TP_PROTO(unsigned int type, void *sis, void *frontswap_map),
+	TP_ARGS(type, sis, frontswap_map),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	type		)
+		__field(	void *,		sis		)
+		__field(	void *,		frontswap_map	)
+	),
+
+	TP_fast_assign(
+		__entry->type		= type;
+		__entry->sis		= sis;
+		__entry->frontswap_map	= frontswap_map;
+	),
+
+	TP_printk("type: %u sis: %p frontswap_map: %p",
+		  __entry->type, __entry->sis, __entry->frontswap_map)
+);
+
+TRACE_EVENT(frontswap_register_ops,
+	TP_PROTO(struct frontswap_ops *old, struct frontswap_ops *new),
+	TP_ARGS(old, new),
+
+	TP_STRUCT__entry(
+		__field(struct frontswap_ops *,		old		)
+		__field(struct frontswap_ops *,		new		)
+	),
+
+	TP_fast_assign(
+		__entry->old		= old;
+		__entry->new		= new;
+	),
+
+	TP_printk("old: {init=%p store=%p load=%p invalidate_page=%p invalidate_area=%p}"
+		" new: {init=%p store=%p load=%p invalidate_page=%p invalidate_area=%p}",
+		__entry->old->init,__entry->old->store,__entry->old->load,
+		__entry->old->invalidate_page,__entry->old->invalidate_area,__entry->new->init,
+		__entry->new->store,__entry->new->load,__entry->new->invalidate_page,
+		__entry->new->invalidate_area)
+);
+
+TRACE_EVENT(frontswap_store,
+	TP_PROTO(void *page, int dup, int ret),
+	TP_ARGS(page, dup, ret),
+
+	TP_STRUCT__entry(
+		__field(	int,		dup		)
+		__field(	int,		ret		)
+		__field(	void *,		page		)
+	),
+
+	TP_fast_assign(
+		__entry->dup		= dup;
+		__entry->ret		= ret;
+		__entry->page		= page;
+	),
+
+	TP_printk("page: %p dup: %d ret: %d",
+		  __entry->page, __entry->dup, __entry->ret)
+);
+
+TRACE_EVENT(frontswap_load,
+	TP_PROTO(void *page, int ret),
+	TP_ARGS(page, ret),
+
+	TP_STRUCT__entry(
+		__field(	int,		ret		)
+		__field(	void *,		page		)
+	),
+
+	TP_fast_assign(
+		__entry->ret		= ret;
+		__entry->page		= page;
+	),
+
+	TP_printk("page: %p ret: %d",
+		  __entry->page, __entry->ret)
+);
+
+TRACE_EVENT(frontswap_invalidate_page,
+	TP_PROTO(int type, unsigned long offset, void *sis, int test),
+	TP_ARGS(type, offset, sis, test),
+
+	TP_STRUCT__entry(
+		__field(	int,		type		)
+		__field(	unsigned long,	offset		)
+		__field(	void *,		sis		)
+		__field(	int,		test		)
+	),
+
+	TP_fast_assign(
+		__entry->type		= type;
+		__entry->offset		= offset;
+		__entry->sis		= sis;
+		__entry->test		= test;
+	),
+
+	TP_printk("type: %d offset: %lu sys: %p frontswap_test: %d",
+		  __entry->type, __entry->offset, __entry->sis, __entry->test)
+);
+
+TRACE_EVENT(frontswap_invalidate_area,
+	TP_PROTO(int type, void *sis, void *map),
+	TP_ARGS(type, sis, map),
+
+	TP_STRUCT__entry(
+		__field(	int,		type		)
+		__field(	void *,		map		)
+		__field(	void *,		sis		)
+	),
+
+	TP_fast_assign(
+		__entry->type		= type;
+		__entry->sis		= sis;
+		__entry->map		= map;
+	),
+
+	TP_printk("type: %d sys: %p map: %p",
+		  __entry->type, __entry->sis, __entry->map)
+);
+
+TRACE_EVENT(frontswap_curr_pages,
+	TP_PROTO(unsigned long totalpages),
+	TP_ARGS(totalpages),
+
+	TP_STRUCT__entry(
+		__field(unsigned long,		totalpages	)
+	),
+
+	TP_fast_assign(
+		__entry->totalpages	= totalpages;
+	),
+
+	TP_printk("total pages: %lu",
+		  __entry->totalpages)
+);
+
+TRACE_EVENT(frontswap_shrink,
+	TP_PROTO(unsigned long target_pages),
+	TP_ARGS(target_pages),
+
+	TP_STRUCT__entry(
+		__field(unsigned long,		target_pages	)
+	),
+
+	TP_fast_assign(
+		__entry->target_pages	= target_pages;
+	),
+
+	TP_printk("target pages: %lu",
+		  __entry->target_pages)
+);
+
+#endif /* _TRACE_FRONTSWAP_H */
+
+#include <trace/define_trace.h>
diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h
index 46e3cd8..3df5925 100644
--- a/include/trace/events/kvm.h
+++ b/include/trace/events/kvm.h
@@ -13,7 +13,8 @@
 	ERSN(DEBUG), ERSN(HLT), ERSN(MMIO), ERSN(IRQ_WINDOW_OPEN),	\
 	ERSN(SHUTDOWN), ERSN(FAIL_ENTRY), ERSN(INTR), ERSN(SET_TPR),	\
 	ERSN(TPR_ACCESS), ERSN(S390_SIEIC), ERSN(S390_RESET), ERSN(DCR),\
-	ERSN(NMI), ERSN(INTERNAL_ERROR), ERSN(OSI)
+	ERSN(NMI), ERSN(INTERNAL_ERROR), ERSN(OSI), ERSN(PAPR_HCALL),	\
+	ERSN(S390_UCONTROL)
 
 TRACE_EVENT(kvm_userspace_exit,
 	    TP_PROTO(__u32 reason, int errno),
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
index d274734..5bde94d 100644
--- a/include/trace/events/rcu.h
+++ b/include/trace/events/rcu.h
@@ -541,6 +541,50 @@ TRACE_EVENT(rcu_torture_read,
 		  __entry->rcutorturename, __entry->rhp)
 );
 
+/*
+ * Tracepoint for _rcu_barrier() execution.  The string "s" describes
+ * the _rcu_barrier phase:
+ *	"Begin": rcu_barrier_callback() started.
+ *	"Check": rcu_barrier_callback() checking for piggybacking.
+ *	"EarlyExit": rcu_barrier_callback() piggybacked, thus early exit.
+ *	"Inc1": rcu_barrier_callback() piggyback check counter incremented.
+ *	"Offline": rcu_barrier_callback() found offline CPU
+ *	"OnlineQ": rcu_barrier_callback() found online CPU with callbacks.
+ *	"OnlineNQ": rcu_barrier_callback() found online CPU, no callbacks.
+ *	"IRQ": An rcu_barrier_callback() callback posted on remote CPU.
+ *	"CB": An rcu_barrier_callback() invoked a callback, not the last.
+ *	"LastCB": An rcu_barrier_callback() invoked the last callback.
+ *	"Inc2": rcu_barrier_callback() piggyback check counter incremented.
+ * The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument
+ * is the count of remaining callbacks, and "done" is the piggybacking count.
+ */
+TRACE_EVENT(rcu_barrier,
+
+	TP_PROTO(char *rcuname, char *s, int cpu, int cnt, unsigned long done),
+
+	TP_ARGS(rcuname, s, cpu, cnt, done),
+
+	TP_STRUCT__entry(
+		__field(char *, rcuname)
+		__field(char *, s)
+		__field(int, cpu)
+		__field(int, cnt)
+		__field(unsigned long, done)
+	),
+
+	TP_fast_assign(
+		__entry->rcuname = rcuname;
+		__entry->s = s;
+		__entry->cpu = cpu;
+		__entry->cnt = cnt;
+		__entry->done = done;
+	),
+
+	TP_printk("%s %s cpu %d remaining %d # %lu",
+		  __entry->rcuname, __entry->s, __entry->cpu, __entry->cnt,
+		  __entry->done)
+);
+
 #else /* #ifdef CONFIG_RCU_TRACE */
 
 #define trace_rcu_grace_period(rcuname, gpnum, gpevent) do { } while (0)
@@ -564,6 +608,7 @@ TRACE_EVENT(rcu_torture_read,
 #define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \
 	do { } while (0)
 #define trace_rcu_torture_read(rcutorturename, rhp) do { } while (0)
+#define trace_rcu_barrier(name, s, cpu, cnt, done) do { } while (0)
 
 #endif /* #else #ifdef CONFIG_RCU_TRACE */
 
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
index 7571b27..ff43ffc 100644
--- a/include/video/sh_mobile_lcdc.h
+++ b/include/video/sh_mobile_lcdc.h
@@ -166,6 +166,12 @@ struct sh_mobile_lcdc_bl_info {
 	int (*get_brightness)(void);
 };
 
+struct sh_mobile_lcdc_overlay_cfg {
+	int fourcc;
+	unsigned int max_xres;
+	unsigned int max_yres;
+};
+
 struct sh_mobile_lcdc_chan_cfg {
 	int chan;
 	int fourcc;
@@ -186,6 +192,7 @@ struct sh_mobile_lcdc_chan_cfg {
 struct sh_mobile_lcdc_info {
 	int clock_source;
 	struct sh_mobile_lcdc_chan_cfg ch[2];
+	struct sh_mobile_lcdc_overlay_cfg overlays[4];
 	struct sh_mobile_meram_info *meram_dev;
 };
 
diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h
index 486653f..61fa661 100644
--- a/include/xen/interface/platform.h
+++ b/include/xen/interface/platform.h
@@ -314,6 +314,13 @@ struct xenpf_pcpuinfo {
 };
 DEFINE_GUEST_HANDLE_STRUCT(xenpf_pcpuinfo);
 
+#define XENPF_cpu_online	56
+#define XENPF_cpu_offline	57
+struct xenpf_cpu_ol {
+	uint32_t cpuid;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xenpf_cpu_ol);
+
 struct xen_platform_op {
 	uint32_t cmd;
 	uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
@@ -330,6 +337,7 @@ struct xen_platform_op {
 		struct xenpf_getidletime       getidletime;
 		struct xenpf_set_processor_pminfo set_pminfo;
 		struct xenpf_pcpuinfo          pcpu_info;
+		struct xenpf_cpu_ol            cpu_ol;
 		uint8_t                        pad[128];
 	} u;
 };
diff --git a/include/xen/interface/xen-mca.h b/include/xen/interface/xen-mca.h
new file mode 100644
index 0000000..73a4ea7
--- /dev/null
+++ b/include/xen/interface/xen-mca.h
@@ -0,0 +1,385 @@
+/******************************************************************************
+ * arch-x86/mca.h
+ * Guest OS machine check interface to x86 Xen.
+ *
+ * Contributed by Advanced Micro Devices, Inc.
+ * Author: Christoph Egger <Christoph.Egger@amd.com>
+ *
+ * Updated by Intel Corporation
+ * Author: Liu, Jinsong <jinsong.liu@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __XEN_PUBLIC_ARCH_X86_MCA_H__
+#define __XEN_PUBLIC_ARCH_X86_MCA_H__
+
+/* Hypercall */
+#define __HYPERVISOR_mca __HYPERVISOR_arch_0
+
+#define XEN_MCA_INTERFACE_VERSION	0x01ecc003
+
+/* IN: Dom0 calls hypercall to retrieve nonurgent error log entry */
+#define XEN_MC_NONURGENT	0x1
+/* IN: Dom0 calls hypercall to retrieve urgent error log entry */
+#define XEN_MC_URGENT		0x2
+/* IN: Dom0 acknowledges previosly-fetched error log entry */
+#define XEN_MC_ACK		0x4
+
+/* OUT: All is ok */
+#define XEN_MC_OK		0x0
+/* OUT: Domain could not fetch data. */
+#define XEN_MC_FETCHFAILED	0x1
+/* OUT: There was no machine check data to fetch. */
+#define XEN_MC_NODATA		0x2
+
+#ifndef __ASSEMBLY__
+/* vIRQ injected to Dom0 */
+#define VIRQ_MCA VIRQ_ARCH_0
+
+/*
+ * mc_info entry types
+ * mca machine check info are recorded in mc_info entries.
+ * when fetch mca info, it can use MC_TYPE_... to distinguish
+ * different mca info.
+ */
+#define MC_TYPE_GLOBAL		0
+#define MC_TYPE_BANK		1
+#define MC_TYPE_EXTENDED	2
+#define MC_TYPE_RECOVERY	3
+
+struct mcinfo_common {
+	uint16_t type; /* structure type */
+	uint16_t size; /* size of this struct in bytes */
+};
+
+#define MC_FLAG_CORRECTABLE	(1 << 0)
+#define MC_FLAG_UNCORRECTABLE	(1 << 1)
+#define MC_FLAG_RECOVERABLE	(1 << 2)
+#define MC_FLAG_POLLED		(1 << 3)
+#define MC_FLAG_RESET		(1 << 4)
+#define MC_FLAG_CMCI		(1 << 5)
+#define MC_FLAG_MCE		(1 << 6)
+
+/* contains x86 global mc information */
+struct mcinfo_global {
+	struct mcinfo_common common;
+
+	uint16_t mc_domid; /* running domain at the time in error */
+	uint16_t mc_vcpuid; /* virtual cpu scheduled for mc_domid */
+	uint32_t mc_socketid; /* physical socket of the physical core */
+	uint16_t mc_coreid; /* physical impacted core */
+	uint16_t mc_core_threadid; /* core thread of physical core */
+	uint32_t mc_apicid;
+	uint32_t mc_flags;
+	uint64_t mc_gstatus; /* global status */
+};
+
+/* contains x86 bank mc information */
+struct mcinfo_bank {
+	struct mcinfo_common common;
+
+	uint16_t mc_bank; /* bank nr */
+	uint16_t mc_domid; /* domain referenced by mc_addr if valid */
+	uint64_t mc_status; /* bank status */
+	uint64_t mc_addr; /* bank address */
+	uint64_t mc_misc;
+	uint64_t mc_ctrl2;
+	uint64_t mc_tsc;
+};
+
+struct mcinfo_msr {
+	uint64_t reg; /* MSR */
+	uint64_t value; /* MSR value */
+};
+
+/* contains mc information from other or additional mc MSRs */
+struct mcinfo_extended {
+	struct mcinfo_common common;
+	uint32_t mc_msrs; /* Number of msr with valid values. */
+	/*
+	 * Currently Intel extended MSR (32/64) include all gp registers
+	 * and E(R)FLAGS, E(R)IP, E(R)MISC, up to 11/19 of them might be
+	 * useful at present. So expand this array to 16/32 to leave room.
+	 */
+	struct mcinfo_msr mc_msr[sizeof(void *) * 4];
+};
+
+/* Recovery Action flags. Giving recovery result information to DOM0 */
+
+/* Xen takes successful recovery action, the error is recovered */
+#define REC_ACTION_RECOVERED (0x1 << 0)
+/* No action is performed by XEN */
+#define REC_ACTION_NONE (0x1 << 1)
+/* It's possible DOM0 might take action ownership in some case */
+#define REC_ACTION_NEED_RESET (0x1 << 2)
+
+/*
+ * Different Recovery Action types, if the action is performed successfully,
+ * REC_ACTION_RECOVERED flag will be returned.
+ */
+
+/* Page Offline Action */
+#define MC_ACTION_PAGE_OFFLINE (0x1 << 0)
+/* CPU offline Action */
+#define MC_ACTION_CPU_OFFLINE (0x1 << 1)
+/* L3 cache disable Action */
+#define MC_ACTION_CACHE_SHRINK (0x1 << 2)
+
+/*
+ * Below interface used between XEN/DOM0 for passing XEN's recovery action
+ * information to DOM0.
+ */
+struct page_offline_action {
+	/* Params for passing the offlined page number to DOM0 */
+	uint64_t mfn;
+	uint64_t status;
+};
+
+struct cpu_offline_action {
+	/* Params for passing the identity of the offlined CPU to DOM0 */
+	uint32_t mc_socketid;
+	uint16_t mc_coreid;
+	uint16_t mc_core_threadid;
+};
+
+#define MAX_UNION_SIZE 16
+struct mcinfo_recovery {
+	struct mcinfo_common common;
+	uint16_t mc_bank; /* bank nr */
+	uint8_t action_flags;
+	uint8_t action_types;
+	union {
+		struct page_offline_action page_retire;
+		struct cpu_offline_action cpu_offline;
+		uint8_t pad[MAX_UNION_SIZE];
+	} action_info;
+};
+
+
+#define MCINFO_MAXSIZE 768
+struct mc_info {
+	/* Number of mcinfo_* entries in mi_data */
+	uint32_t mi_nentries;
+	uint32_t flags;
+	uint64_t mi_data[(MCINFO_MAXSIZE - 1) / 8];
+};
+DEFINE_GUEST_HANDLE_STRUCT(mc_info);
+
+#define __MC_MSR_ARRAYSIZE 8
+#define __MC_MSR_MCGCAP 0
+#define __MC_NMSRS 1
+#define MC_NCAPS 7
+struct mcinfo_logical_cpu {
+	uint32_t mc_cpunr;
+	uint32_t mc_chipid;
+	uint16_t mc_coreid;
+	uint16_t mc_threadid;
+	uint32_t mc_apicid;
+	uint32_t mc_clusterid;
+	uint32_t mc_ncores;
+	uint32_t mc_ncores_active;
+	uint32_t mc_nthreads;
+	uint32_t mc_cpuid_level;
+	uint32_t mc_family;
+	uint32_t mc_vendor;
+	uint32_t mc_model;
+	uint32_t mc_step;
+	char mc_vendorid[16];
+	char mc_brandid[64];
+	uint32_t mc_cpu_caps[MC_NCAPS];
+	uint32_t mc_cache_size;
+	uint32_t mc_cache_alignment;
+	uint32_t mc_nmsrvals;
+	struct mcinfo_msr mc_msrvalues[__MC_MSR_ARRAYSIZE];
+};
+DEFINE_GUEST_HANDLE_STRUCT(mcinfo_logical_cpu);
+
+/*
+ * Prototype:
+ *    uint32_t x86_mcinfo_nentries(struct mc_info *mi);
+ */
+#define x86_mcinfo_nentries(_mi)    \
+	((_mi)->mi_nentries)
+/*
+ * Prototype:
+ *    struct mcinfo_common *x86_mcinfo_first(struct mc_info *mi);
+ */
+#define x86_mcinfo_first(_mi)       \
+	((struct mcinfo_common *)(_mi)->mi_data)
+/*
+ * Prototype:
+ *    struct mcinfo_common *x86_mcinfo_next(struct mcinfo_common *mic);
+ */
+#define x86_mcinfo_next(_mic)       \
+	((struct mcinfo_common *)((uint8_t *)(_mic) + (_mic)->size))
+
+/*
+ * Prototype:
+ *    void x86_mcinfo_lookup(void *ret, struct mc_info *mi, uint16_t type);
+ */
+static inline void x86_mcinfo_lookup(struct mcinfo_common **ret,
+				     struct mc_info *mi, uint16_t type)
+{
+	uint32_t i;
+	struct mcinfo_common *mic;
+	bool found = 0;
+
+	if (!ret || !mi)
+		return;
+
+	mic = x86_mcinfo_first(mi);
+	for (i = 0; i < x86_mcinfo_nentries(mi); i++) {
+		if (mic->type == type) {
+			found = 1;
+			break;
+		}
+		mic = x86_mcinfo_next(mic);
+	}
+
+	*ret = found ? mic : NULL;
+}
+
+/*
+ * Fetch machine check data from hypervisor.
+ */
+#define XEN_MC_fetch		1
+struct xen_mc_fetch {
+	/*
+	 * IN: XEN_MC_NONURGENT, XEN_MC_URGENT,
+	 * XEN_MC_ACK if ack'king an earlier fetch
+	 * OUT: XEN_MC_OK, XEN_MC_FETCHAILED, XEN_MC_NODATA
+	 */
+	uint32_t flags;
+	uint32_t _pad0;
+	/* OUT: id for ack, IN: id we are ack'ing */
+	uint64_t fetch_id;
+
+	/* OUT variables. */
+	GUEST_HANDLE(mc_info) data;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_mc_fetch);
+
+
+/*
+ * This tells the hypervisor to notify a DomU about the machine check error
+ */
+#define XEN_MC_notifydomain	2
+struct xen_mc_notifydomain {
+	/* IN variables */
+	uint16_t mc_domid; /* The unprivileged domain to notify */
+	uint16_t mc_vcpuid; /* The vcpu in mc_domid to notify */
+
+	/* IN/OUT variables */
+	uint32_t flags;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_mc_notifydomain);
+
+#define XEN_MC_physcpuinfo	3
+struct xen_mc_physcpuinfo {
+	/* IN/OUT */
+	uint32_t ncpus;
+	uint32_t _pad0;
+	/* OUT */
+	GUEST_HANDLE(mcinfo_logical_cpu) info;
+};
+
+#define XEN_MC_msrinject	4
+#define MC_MSRINJ_MAXMSRS	8
+struct xen_mc_msrinject {
+	/* IN */
+	uint32_t mcinj_cpunr; /* target processor id */
+	uint32_t mcinj_flags; /* see MC_MSRINJ_F_* below */
+	uint32_t mcinj_count; /* 0 .. count-1 in array are valid */
+	uint32_t _pad0;
+	struct mcinfo_msr mcinj_msr[MC_MSRINJ_MAXMSRS];
+};
+
+/* Flags for mcinj_flags above; bits 16-31 are reserved */
+#define MC_MSRINJ_F_INTERPOSE	0x1
+
+#define XEN_MC_mceinject	5
+struct xen_mc_mceinject {
+	unsigned int mceinj_cpunr; /* target processor id */
+};
+
+struct xen_mc {
+	uint32_t cmd;
+	uint32_t interface_version; /* XEN_MCA_INTERFACE_VERSION */
+	union {
+		struct xen_mc_fetch        mc_fetch;
+		struct xen_mc_notifydomain mc_notifydomain;
+		struct xen_mc_physcpuinfo  mc_physcpuinfo;
+		struct xen_mc_msrinject    mc_msrinject;
+		struct xen_mc_mceinject    mc_mceinject;
+	} u;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_mc);
+
+/* Fields are zero when not available */
+struct xen_mce {
+	__u64 status;
+	__u64 misc;
+	__u64 addr;
+	__u64 mcgstatus;
+	__u64 ip;
+	__u64 tsc;	/* cpu time stamp counter */
+	__u64 time;	/* wall time_t when error was detected */
+	__u8  cpuvendor;	/* cpu vendor as encoded in system.h */
+	__u8  inject_flags;	/* software inject flags */
+	__u16  pad;
+	__u32 cpuid;	/* CPUID 1 EAX */
+	__u8  cs;		/* code segment */
+	__u8  bank;	/* machine check bank */
+	__u8  cpu;	/* cpu number; obsolete; use extcpu now */
+	__u8  finished;   /* entry is valid */
+	__u32 extcpu;	/* linux cpu number that detected the error */
+	__u32 socketid;	/* CPU socket ID */
+	__u32 apicid;	/* CPU initial apic ID */
+	__u64 mcgcap;	/* MCGCAP MSR: machine check capabilities of CPU */
+};
+
+/*
+ * This structure contains all data related to the MCE log.  Also
+ * carries a signature to make it easier to find from external
+ * debugging tools.  Each entry is only valid when its finished flag
+ * is set.
+ */
+
+#define XEN_MCE_LOG_LEN 32
+
+struct xen_mce_log {
+	char signature[12]; /* "MACHINECHECK" */
+	unsigned len;	    /* = XEN_MCE_LOG_LEN */
+	unsigned next;
+	unsigned flags;
+	unsigned recordlen;	/* length of struct xen_mce */
+	struct xen_mce entry[XEN_MCE_LOG_LEN];
+};
+
+#define XEN_MCE_OVERFLOW 0		/* bit 0 in flags means overflow */
+
+#define XEN_MCE_LOG_SIGNATURE	"MACHINECHECK"
+
+#define MCE_GET_RECORD_LEN   _IOR('M', 1, int)
+#define MCE_GET_LOG_LEN      _IOR('M', 2, int)
+#define MCE_GETCLEAR_FLAGS   _IOR('M', 3, int)
+
+#endif /* __ASSEMBLY__ */
+#endif /* __XEN_PUBLIC_ARCH_X86_MCA_H__ */
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index a890804..0801468 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -80,6 +80,7 @@
 #define VIRQ_CONSOLE    2  /* (DOM0) Bytes received on emergency console. */
 #define VIRQ_DOM_EXC    3  /* (DOM0) Exceptional event for some domain.   */
 #define VIRQ_DEBUGGER   6  /* (DOM0) A domain has paused for debugging.   */
+#define VIRQ_PCPU_STATE 9  /* (DOM0) PCPU state changed                   */
 
 /* Architecture-specific VIRQ definitions. */
 #define VIRQ_ARCH_0    16
diff --git a/init/Kconfig b/init/Kconfig
index d07dcf9..84e13b8 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -751,6 +751,21 @@ config CGROUP_MEM_RES_CTLR_KMEM
 	  the kmem extension can use it to guarantee that no group of processes
 	  will ever exhaust kernel resources alone.
 
+config CGROUP_HUGETLB_RES_CTLR
+	bool "HugeTLB Resource Controller for Control Groups"
+	depends on RESOURCE_COUNTERS && HUGETLB_PAGE && EXPERIMENTAL
+	default n
+	help
+	  Provides a cgroup Resource Controller for HugeTLB pages.
+	  When you enable this, you can put a per cgroup limit on HugeTLB usage.
+	  The limit is enforced during page fault. Since HugeTLB doesn't
+	  support page reclaim, enforcing the limit at page fault time implies
+	  that, the application will get SIGBUS signal if it tries to access
+	  HugeTLB pages beyond its limit. This requires the application to know
+	  beforehand how much HugeTLB pages it would require for its use. The
+	  control group is tracked in the third page lru pointer. This means
+	  that we cannot use the controller with huge page less than 3 pages.
+
 config CGROUP_PERF
 	bool "Enable perf_event per-cpu per-container group (cgroup) monitoring"
 	depends on PERF_EVENTS && CGROUPS
@@ -948,7 +963,6 @@ config UIDGID_CONVERTED
 	depends on ATALK = n
 
 	# Filesystems
-	depends on USB_DEVICEFS = n
 	depends on USB_GADGETFS = n
 	depends on USB_FUNCTIONFS = n
 	depends on DEVTMPFS = n
@@ -1039,7 +1053,7 @@ config SCHED_AUTOGROUP
 	  upon task session.
 
 config MM_OWNER
-	bool
+	def_bool NUMA
 
 config SYSFS_DEPRECATED
 	bool "Enable deprecated sysfs features to support old userspace tools"
diff --git a/init/main.c b/init/main.c
index b5cc0a7..5c6bef7 100644
--- a/init/main.c
+++ b/init/main.c
@@ -460,6 +460,10 @@ static void __init mm_init(void)
 	percpu_init_late();
 	pgtable_cache_init();
 	vmalloc_init();
+#ifdef CONFIG_X86
+	if (efi_enabled)
+		efi_enter_virtual_mode();
+#endif
 }
 
 asmlinkage void __init start_kernel(void)
@@ -601,10 +605,6 @@ asmlinkage void __init start_kernel(void)
 	calibrate_delay();
 	pidmap_init();
 	anon_vma_init();
-#ifdef CONFIG_X86
-	if (efi_enabled)
-		efi_enter_virtual_mode();
-#endif
 	thread_info_cache_init();
 	cred_init();
 	fork_init(totalram_pages);
@@ -724,6 +724,7 @@ static initcall_t *initcall_levels[] __initdata = {
 	__initcall_end,
 };
 
+/* Keep these in sync with initcalls in include/linux/init.h */
 static char *initcall_level_names[] __initdata = {
 	"early",
 	"core",
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 8ce5769..2dee38d 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -413,7 +413,7 @@ static void mqueue_evict_inode(struct inode *inode)
 }
 
 static int mqueue_create(struct inode *dir, struct dentry *dentry,
-				umode_t mode, struct nameidata *nd)
+				umode_t mode, bool excl)
 {
 	struct inode *inode;
 	struct mq_attr *attr = dentry->d_fsdata;
@@ -751,7 +751,7 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
 	ret = mnt_want_write(ipc_ns->mq_mnt);
 	if (ret)
 		goto out;
-	ret = vfs_create(dir->d_inode, dentry, mode, NULL);
+	ret = vfs_create(dir->d_inode, dentry, mode, true);
 	dentry->d_fsdata = NULL;
 	if (ret)
 		goto out_drop_write;
diff --git a/ipc/sem.c b/ipc/sem.c
index 5215a81..10386b8 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -61,8 +61,8 @@
  * - A woken up task may not even touch the semaphore array anymore, it may
  *   have been destroyed already by a semctl(RMID).
  * - The synchronizations between wake-ups due to a timeout/signal and a
- *   wake-up due to a completed semaphore operation is achieved by using an
- *   intermediate state (IN_WAKEUP).
+ *   wake-up due to a completed semaphore operation is achieved by using a
+ *   special wakeup scheme (queuewakeup_wait and support functions)
  * - UNDO values are stored in an array (one per process and per
  *   semaphore array, lazily allocated). For backwards compatibility, multiple
  *   modes for the UNDO variables are supported (per process, per thread)
@@ -90,6 +90,135 @@
 #include <asm/uaccess.h>
 #include "util.h"
 
+
+#ifdef CONFIG_PREEMPT_RT_BASE
+	#define SYSVSEM_COMPLETION 1
+#else
+	#define SYSVSEM_CUSTOM 1
+#endif
+
+#ifdef SYSVSEM_COMPLETION
+	/* Using a completion causes some overhead, but avoids a busy loop
+	 * that increases the worst case latency.
+	 */
+	struct queue_done {
+		struct completion done;
+	};
+
+	static void queuewakeup_prepare(void)
+	{
+		/* no preparation necessary */
+	}
+
+	static void queuewakeup_completed(void)
+	{
+		/* empty */
+	}
+
+	static void queuewakeup_block(struct queue_done *qd)
+	{
+		/* empty */
+	}
+
+	static void queuewakeup_handsoff(struct queue_done *qd)
+	{
+		complete_all(&qd->done);
+	}
+
+	static void queuewakeup_init(struct queue_done *qd)
+	{
+		init_completion(&qd->done);
+	}
+
+	static void queuewakeup_wait(struct queue_done *qd)
+	{
+		wait_for_completion(&qd->done);
+	}
+
+#elif defined(SYSVSEM_SPINLOCK)
+	/* Note: Spinlocks do not work because:
+	 * - lockdep complains [could be fixed]
+	 * - only 255 concurrent spin_lock() calls are permitted, then the
+	 *   preempt-counter overflows
+	 */
+#error SYSVSEM_SPINLOCK is a prove of concept, does not work.
+	struct queue_done {
+		spinlock_t done;
+	};
+
+	static void queuewakeup_prepare(void)
+	{
+		/* empty */
+	}
+
+	static void queuewakeup_completed(void)
+	{
+		/* empty */
+	}
+
+	static void queuewakeup_block(struct queue_done *qd)
+	{
+		BUG_ON(spin_is_locked(&qd->done));
+		spin_lock(&qd->done);
+	}
+
+	static void queuewakeup_handsoff(struct queue_done *qd)
+	{
+		spin_unlock(&qd->done);
+	}
+
+	static void queuewakeup_init(struct queue_done *qd)
+	{
+		spin_lock_init(&qd->done);
+	}
+
+	static void queuewakeup_wait(struct queue_done *qd)
+	{
+		spin_unlock_wait(&qd->done);
+	}
+#else
+	struct queue_done {
+		atomic_t done;
+	};
+
+	static void queuewakeup_prepare(void)
+	{
+		preempt_disable();
+	}
+
+	static void queuewakeup_completed(void)
+	{
+		preempt_enable();
+	}
+
+	static void queuewakeup_block(struct queue_done *qd)
+	{
+		BUG_ON(atomic_read(&qd->done) != 1);
+		atomic_set(&qd->done, 2);
+	}
+
+	static void queuewakeup_handsoff(struct queue_done *qd)
+	{
+		BUG_ON(atomic_read(&qd->done) != 2);
+		smp_mb();
+		atomic_set(&qd->done, 1);
+	}
+
+	static void queuewakeup_init(struct queue_done *qd)
+	{
+		atomic_set(&qd->done, 1);
+	}
+
+	static void queuewakeup_wait(struct queue_done *qd)
+	{
+		while (atomic_read(&qd->done) != 1)
+			cpu_relax();
+
+		smp_mb();
+	}
+#endif
+
+
 /* One semaphore structure for each semaphore in the system. */
 struct sem {
 	int	semval;		/* current value */
@@ -108,6 +237,7 @@ struct sem_queue {
 	struct sembuf		*sops;	 /* array of pending operations */
 	int			nsops;	 /* number of operations */
 	int			alter;	 /* does *sops alter the array? */
+	struct queue_done	done;	 /* completion synchronization */
 };
 
 /* Each task has a list of undo requests. They are executed automatically
@@ -245,23 +375,27 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
  * - queue.status is initialized to -EINTR before blocking.
  * - wakeup is performed by
  *	* unlinking the queue entry from sma->sem_pending
- *	* setting queue.status to IN_WAKEUP
- *	  This is the notification for the blocked thread that a
- *	  result value is imminent.
+ *	* setting queue.status to the actual result code
+ *	  This is the notification for the blocked thread that someone
+ *	  (usually: update_queue()) completed the semtimedop() operation.
  *	* call wake_up_process
- *	* set queue.status to the final value.
+ *	* queuewakeup_handsoff(&q->done);
  * - the previously blocked thread checks queue.status:
- *   	* if it's IN_WAKEUP, then it must wait until the value changes
- *   	* if it's not -EINTR, then the operation was completed by
- *   	  update_queue. semtimedop can return queue.status without
- *   	  performing any operation on the sem array.
- *   	* otherwise it must acquire the spinlock and check what's up.
+ *	* if it's not -EINTR, then someone completed the operation.
+ *	  First, queuewakeup_wait() must be called. Afterwards,
+ *	  semtimedop must return queue.status without performing any
+ *	  operation on the sem array.
+ *	  - otherwise it must acquire the spinlock and repeat the test
+ *	  - If it is still -EINTR, then no update_queue() completed the
+ *	    operation, thus semtimedop() can proceed normally.
  *
- * The two-stage algorithm is necessary to protect against the following
+ * queuewakeup_wait() is necessary to protect against the following
  * races:
  * - if queue.status is set after wake_up_process, then the woken up idle
  *   thread could race forward and try (and fail) to acquire sma->lock
- *   before update_queue had a chance to set queue.status
+ *   before update_queue had a chance to set queue.status.
+ *   More importantly, it would mean that wake_up_process must be done
+ *   while holding sma->lock, i.e. this would reduce the scalability.
  * - if queue.status is written before wake_up_process and if the
  *   blocked process is woken up by a signal between writing
  *   queue.status and the wake_up_process, then the woken up
@@ -271,7 +405,6 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
  *   (yes, this happened on s390 with sysv msg).
  *
  */
-#define IN_WAKEUP	1
 
 /**
  * newary - Create a new semaphore set
@@ -461,15 +594,11 @@ undo:
 static void wake_up_sem_queue_prepare(struct list_head *pt,
 				struct sem_queue *q, int error)
 {
-	if (list_empty(pt)) {
-		/*
-		 * Hold preempt off so that we don't get preempted and have the
-		 * wakee busy-wait until we're scheduled back on.
-		 */
-		preempt_disable();
-	}
-	q->status = IN_WAKEUP;
-	q->pid = error;
+	if (list_empty(pt))
+		queuewakeup_prepare();
+
+	queuewakeup_block(&q->done);
+	q->status = error;
 
 	list_add_tail(&q->simple_list, pt);
 }
@@ -480,8 +609,8 @@ static void wake_up_sem_queue_prepare(struct list_head *pt,
  *
  * Do the actual wake-up.
  * The function is called without any locks held, thus the semaphore array
- * could be destroyed already and the tasks can disappear as soon as the
- * status is set to the actual return code.
+ * could be destroyed already and the tasks can disappear as soon as
+ * queuewakeup_handsoff() is called.
  */
 static void wake_up_sem_queue_do(struct list_head *pt)
 {
@@ -491,12 +620,11 @@ static void wake_up_sem_queue_do(struct list_head *pt)
 	did_something = !list_empty(pt);
 	list_for_each_entry_safe(q, t, pt, simple_list) {
 		wake_up_process(q->sleeper);
-		/* q can disappear immediately after writing q->status. */
-		smp_wmb();
-		q->status = q->pid;
+		/* q can disappear immediately after completing q->done */
+		queuewakeup_handsoff(&q->done);
 	}
 	if (did_something)
-		preempt_enable();
+		queuewakeup_completed();
 }
 
 static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
@@ -1300,33 +1428,6 @@ out:
 	return un;
 }
 
-
-/**
- * get_queue_result - Retrieve the result code from sem_queue
- * @q: Pointer to queue structure
- *
- * Retrieve the return code from the pending queue. If IN_WAKEUP is found in
- * q->status, then we must loop until the value is replaced with the final
- * value: This may happen if a task is woken up by an unrelated event (e.g.
- * signal) and in parallel the task is woken up by another task because it got
- * the requested semaphores.
- *
- * The function can be called with or without holding the semaphore spinlock.
- */
-static int get_queue_result(struct sem_queue *q)
-{
-	int error;
-
-	error = q->status;
-	while (unlikely(error == IN_WAKEUP)) {
-		cpu_relax();
-		error = q->status;
-	}
-
-	return error;
-}
-
-
 SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
 		unsigned, nsops, const struct timespec __user *, timeout)
 {
@@ -1472,6 +1573,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
 
 	queue.status = -EINTR;
 	queue.sleeper = current;
+	queuewakeup_init(&queue.done);
 
 sleep_again:
 	current->state = TASK_INTERRUPTIBLE;
@@ -1482,17 +1584,14 @@ sleep_again:
 	else
 		schedule();
 
-	error = get_queue_result(&queue);
+	error = queue.status;
 
 	if (error != -EINTR) {
 		/* fast path: update_queue already obtained all requested
-		 * resources.
-		 * Perform a smp_mb(): User space could assume that semop()
-		 * is a memory barrier: Without the mb(), the cpu could
-		 * speculatively read in user space stale data that was
-		 * overwritten by the previous owner of the semaphore.
+		 * resources. Just ensure that update_queue completed
+		 * it's access to &queue.
 		 */
-		smp_mb();
+		queuewakeup_wait(&queue.done);
 
 		goto out_free;
 	}
@@ -1502,23 +1601,16 @@ sleep_again:
 	/*
 	 * Wait until it's guaranteed that no wakeup_sem_queue_do() is ongoing.
 	 */
-	error = get_queue_result(&queue);
-
-	/*
-	 * Array removed? If yes, leave without sem_unlock().
-	 */
-	if (IS_ERR(sma)) {
-		goto out_free;
-	}
-
-
-	/*
-	 * If queue.status != -EINTR we are woken up by another process.
-	 * Leave without unlink_queue(), but with sem_unlock().
-	 */
-
+	error = queue.status;
 	if (error != -EINTR) {
-		goto out_unlock_free;
+		/* If there is a return code, then we can leave immediately. */
+		if (!IS_ERR(sma)) {
+			/* sem_lock() succeeded - then unlock */
+			sem_unlock(sma);
+		}
+		/* Except that we must wait for the hands-off */
+		queuewakeup_wait(&queue.done);
+		goto out_free;
 	}
 
 	/*
diff --git a/kernel/audit.c b/kernel/audit.c
index 1c7f2c6..0d879ab 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1450,6 +1450,26 @@ void audit_log_key(struct audit_buffer *ab, char *key)
 }
 
 /**
+ * audit_log_link_denied - report a link restriction denial
+ * @operation: specific link opreation
+ * @link: the path that triggered the restriction
+ */
+void audit_log_link_denied(const char *operation, struct path *link)
+{
+	struct audit_buffer *ab;
+
+	ab = audit_log_start(current->audit_context, GFP_KERNEL, AUDIT_AVC);
+	audit_log_format(ab, "op=%s action=denied", operation);
+	audit_log_format(ab, " pid=%d comm=", current->pid);
+	audit_log_untrustedstring(ab, current->comm);
+	audit_log_d_path(ab, " path=", link);
+	audit_log_format(ab, " dev=");
+	audit_log_untrustedstring(ab, link->dentry->d_inode->i_sb->s_id);
+	audit_log_format(ab, " ino=%lu", link->dentry->d_inode->i_ino);
+	audit_log_end(ab);
+}
+
+/**
  * audit_log_end - end one audit record
  * @ab: the audit_buffer
  *
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 5bf0790..9cedf31 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -249,7 +249,7 @@ static void untag_chunk(struct node *p)
 		list_del_rcu(&chunk->hash);
 		spin_unlock(&hash_lock);
 		spin_unlock(&entry->lock);
-		fsnotify_destroy_mark(entry);
+		fsnotify_destroy_mark(entry, audit_tree_group);
 		fsnotify_put_mark(entry);
 		goto out;
 	}
@@ -292,7 +292,7 @@ static void untag_chunk(struct node *p)
 		owner->root = new;
 	spin_unlock(&hash_lock);
 	spin_unlock(&entry->lock);
-	fsnotify_destroy_mark(entry);
+	fsnotify_destroy_mark(entry, audit_tree_group);
 	fsnotify_put_mark(entry);
 	goto out;
 
@@ -332,7 +332,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)
 		spin_unlock(&hash_lock);
 		chunk->dead = 1;
 		spin_unlock(&entry->lock);
-		fsnotify_destroy_mark(entry);
+		fsnotify_destroy_mark(entry, audit_tree_group);
 		fsnotify_put_mark(entry);
 		return 0;
 	}
@@ -412,7 +412,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
 		spin_unlock(&chunk_entry->lock);
 		spin_unlock(&old_entry->lock);
 
-		fsnotify_destroy_mark(chunk_entry);
+		fsnotify_destroy_mark(chunk_entry, audit_tree_group);
 
 		fsnotify_put_mark(chunk_entry);
 		fsnotify_put_mark(old_entry);
@@ -443,7 +443,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
 	spin_unlock(&hash_lock);
 	spin_unlock(&chunk_entry->lock);
 	spin_unlock(&old_entry->lock);
-	fsnotify_destroy_mark(old_entry);
+	fsnotify_destroy_mark(old_entry, audit_tree_group);
 	fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */
 	fsnotify_put_mark(old_entry); /* and kill it */
 	return 0;
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index e683869..a66affc 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -349,40 +349,21 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
 	}
 	mutex_unlock(&audit_filter_mutex);
 
-	fsnotify_destroy_mark(&parent->mark);
+	fsnotify_destroy_mark(&parent->mark, audit_watch_group);
 }
 
 /* Get path information necessary for adding watches. */
 static int audit_get_nd(struct audit_watch *watch, struct path *parent)
 {
-	struct nameidata nd;
-	struct dentry *d;
-	int err;
-
-	err = kern_path_parent(watch->path, &nd);
-	if (err)
-		return err;
-
-	if (nd.last_type != LAST_NORM) {
-		path_put(&nd.path);
-		return -EINVAL;
-	}
-
-	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
-	d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
-	if (IS_ERR(d)) {
-		mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-		path_put(&nd.path);
+	struct dentry *d = kern_path_locked(watch->path, parent);
+	if (IS_ERR(d))
 		return PTR_ERR(d);
-	}
+	mutex_unlock(&parent->dentry->d_inode->i_mutex);
 	if (d->d_inode) {
 		/* update watch filter fields */
 		watch->dev = d->d_inode->i_sb->s_dev;
 		watch->ino = d->d_inode->i_ino;
 	}
-	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-
-	*parent = nd.path;
 	dput(d);
 	return 0;
 }
@@ -475,7 +456,7 @@ void audit_remove_watch_rule(struct audit_krule *krule)
 
 		if (list_empty(&parent->watches)) {
 			audit_get_parent(parent);
-			fsnotify_destroy_mark(&parent->mark);
+			fsnotify_destroy_mark(&parent->mark, audit_watch_group);
 			audit_put_parent(parent);
 		}
 	}
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 2097684..5feed46 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -822,7 +822,7 @@ EXPORT_SYMBOL_GPL(cgroup_unlock);
  */
 
 static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
-static struct dentry *cgroup_lookup(struct inode *, struct dentry *, struct nameidata *);
+static struct dentry *cgroup_lookup(struct inode *, struct dentry *, unsigned int);
 static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry);
 static int cgroup_populate_dir(struct cgroup *cgrp);
 static const struct inode_operations cgroup_dir_inode_operations;
@@ -1078,28 +1078,24 @@ static int rebind_subsystems(struct cgroupfs_root *root,
 			BUG_ON(cgrp->subsys[i]);
 			BUG_ON(!dummytop->subsys[i]);
 			BUG_ON(dummytop->subsys[i]->cgroup != dummytop);
-			mutex_lock(&ss->hierarchy_mutex);
 			cgrp->subsys[i] = dummytop->subsys[i];
 			cgrp->subsys[i]->cgroup = cgrp;
 			list_move(&ss->sibling, &root->subsys_list);
 			ss->root = root;
 			if (ss->bind)
 				ss->bind(cgrp);
-			mutex_unlock(&ss->hierarchy_mutex);
 			/* refcount was already taken, and we're keeping it */
 		} else if (bit & removed_bits) {
 			/* We're removing this subsystem */
 			BUG_ON(ss == NULL);
 			BUG_ON(cgrp->subsys[i] != dummytop->subsys[i]);
 			BUG_ON(cgrp->subsys[i]->cgroup != cgrp);
-			mutex_lock(&ss->hierarchy_mutex);
 			if (ss->bind)
 				ss->bind(dummytop);
 			dummytop->subsys[i]->cgroup = dummytop;
 			cgrp->subsys[i] = NULL;
 			subsys[i]->root = &rootnode;
 			list_move(&ss->sibling, &rootnode.subsys_list);
-			mutex_unlock(&ss->hierarchy_mutex);
 			/* subsystem is now free - drop reference on module */
 			module_put(ss->module);
 		} else if (bit & final_bits) {
@@ -2581,7 +2577,7 @@ static const struct inode_operations cgroup_dir_inode_operations = {
 	.rename = cgroup_rename,
 };
 
-static struct dentry *cgroup_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *cgroup_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
 	if (dentry->d_name.len > NAME_MAX)
 		return ERR_PTR(-ENAMETOOLONG);
@@ -3922,37 +3918,6 @@ static void init_cgroup_css(struct cgroup_subsys_state *css,
 		set_bit(CSS_CLEAR_CSS_REFS, &css->flags);
 }
 
-static void cgroup_lock_hierarchy(struct cgroupfs_root *root)
-{
-	/* We need to take each hierarchy_mutex in a consistent order */
-	int i;
-
-	/*
-	 * No worry about a race with rebind_subsystems that might mess up the
-	 * locking order, since both parties are under cgroup_mutex.
-	 */
-	for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-		struct cgroup_subsys *ss = subsys[i];
-		if (ss == NULL)
-			continue;
-		if (ss->root == root)
-			mutex_lock(&ss->hierarchy_mutex);
-	}
-}
-
-static void cgroup_unlock_hierarchy(struct cgroupfs_root *root)
-{
-	int i;
-
-	for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-		struct cgroup_subsys *ss = subsys[i];
-		if (ss == NULL)
-			continue;
-		if (ss->root == root)
-			mutex_unlock(&ss->hierarchy_mutex);
-	}
-}
-
 /*
  * cgroup_create - create a cgroup
  * @parent: cgroup that will be parent of the new cgroup
@@ -4013,9 +3978,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
 			ss->post_clone(cgrp);
 	}
 
-	cgroup_lock_hierarchy(root);
 	list_add(&cgrp->sibling, &cgrp->parent->children);
-	cgroup_unlock_hierarchy(root);
 	root->number_of_cgroups++;
 
 	err = cgroup_create_dir(cgrp, dentry, mode);
@@ -4042,9 +4005,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
 
  err_remove:
 
-	cgroup_lock_hierarchy(root);
 	list_del(&cgrp->sibling);
-	cgroup_unlock_hierarchy(root);
 	root->number_of_cgroups--;
 
  err_destroy:
@@ -4252,10 +4213,8 @@ again:
 		list_del_init(&cgrp->release_list);
 	raw_spin_unlock(&release_list_lock);
 
-	cgroup_lock_hierarchy(cgrp->root);
 	/* delete this cgroup from parent->children */
 	list_del_init(&cgrp->sibling);
-	cgroup_unlock_hierarchy(cgrp->root);
 
 	list_del_init(&cgrp->allcg_node);
 
@@ -4329,8 +4288,6 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
 	 * need to invoke fork callbacks here. */
 	BUG_ON(!list_empty(&init_task.tasks));
 
-	mutex_init(&ss->hierarchy_mutex);
-	lockdep_set_class(&ss->hierarchy_mutex, &ss->subsys_key);
 	ss->active = 1;
 
 	/* this function shouldn't be used with modular subsystems, since they
@@ -4457,8 +4414,6 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
 	}
 	write_unlock(&css_set_lock);
 
-	mutex_init(&ss->hierarchy_mutex);
-	lockdep_set_class(&ss->hierarchy_mutex, &ss->subsys_key);
 	ss->active = 1;
 
 	/* success! */
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 8c8bd65..0cbc631 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -147,6 +147,12 @@ typedef enum {
 	CS_SPREAD_SLAB,
 } cpuset_flagbits_t;
 
+/* the type of hotplug event */
+enum hotplug_event {
+	CPUSET_CPU_OFFLINE,
+	CPUSET_MEM_OFFLINE,
+};
+
 /* convenient tests for these bits */
 static inline int is_cpu_exclusive(const struct cpuset *cs)
 {
@@ -976,7 +982,7 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
 	task_lock(tsk);
 	/*
 	 * Determine if a loop is necessary if another thread is doing
-	 * get_mems_allowed().  If at least one node remains unchanged and
+	 * read_mems_allowed_begin().  If at least one node remains unchanged and
 	 * tsk does not have a mempolicy, then an empty nodemask will not be
 	 * possible when mems_allowed is larger than a word.
 	 */
@@ -1990,8 +1996,36 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
 }
 
 /*
- * Walk the specified cpuset subtree and look for empty cpusets.
- * The tasks of such cpuset must be moved to a parent cpuset.
+ * Helper function to traverse cpusets.
+ * It can be used to walk the cpuset tree from top to bottom, completing
+ * one layer before dropping down to the next (thus always processing a
+ * node before any of its children).
+ */
+static struct cpuset *cpuset_next(struct list_head *queue)
+{
+	struct cpuset *cp;
+	struct cpuset *child;	/* scans child cpusets of cp */
+	struct cgroup *cont;
+
+	if (list_empty(queue))
+		return NULL;
+
+	cp = list_first_entry(queue, struct cpuset, stack_list);
+	list_del(queue->next);
+	list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
+		child = cgroup_cs(cont);
+		list_add_tail(&child->stack_list, queue);
+	}
+
+	return cp;
+}
+
+
+/*
+ * Walk the specified cpuset subtree upon a hotplug operation (CPU/Memory
+ * online/offline) and update the cpusets accordingly.
+ * For regular CPU/Mem hotplug, look for empty cpusets; the tasks of such
+ * cpuset must be moved to a parent cpuset.
  *
  * Called with cgroup_mutex held.  We take callback_mutex to modify
  * cpus_allowed and mems_allowed.
@@ -2000,50 +2034,61 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
  * before dropping down to the next.  It always processes a node before
  * any of its children.
  *
- * For now, since we lack memory hot unplug, we'll never see a cpuset
- * that has tasks along with an empty 'mems'.  But if we did see such
- * a cpuset, we'd handle it just like we do if its 'cpus' was empty.
+ * In the case of memory hot-unplug, it will remove nodes from N_HIGH_MEMORY
+ * if all present pages from a node are offlined.
  */
-static void scan_for_empty_cpusets(struct cpuset *root)
+static void
+scan_cpusets_upon_hotplug(struct cpuset *root, enum hotplug_event event)
 {
 	LIST_HEAD(queue);
-	struct cpuset *cp;	/* scans cpusets being updated */
-	struct cpuset *child;	/* scans child cpusets of cp */
-	struct cgroup *cont;
+	struct cpuset *cp;		/* scans cpusets being updated */
 	static nodemask_t oldmems;	/* protected by cgroup_mutex */
 
 	list_add_tail((struct list_head *)&root->stack_list, &queue);
 
-	while (!list_empty(&queue)) {
-		cp = list_first_entry(&queue, struct cpuset, stack_list);
-		list_del(queue.next);
-		list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
-			child = cgroup_cs(cont);
-			list_add_tail(&child->stack_list, &queue);
+	switch (event) {
+	case CPUSET_CPU_OFFLINE:
+		while ((cp = cpuset_next(&queue)) != NULL) {
+
+			/* Continue past cpusets with all cpus online */
+			if (cpumask_subset(cp->cpus_allowed, cpu_active_mask))
+				continue;
+
+			/* Remove offline cpus from this cpuset. */
+			mutex_lock(&callback_mutex);
+			cpumask_and(cp->cpus_allowed, cp->cpus_allowed,
+							cpu_active_mask);
+			mutex_unlock(&callback_mutex);
+
+			/* Move tasks from the empty cpuset to a parent */
+			if (cpumask_empty(cp->cpus_allowed))
+				remove_tasks_in_empty_cpuset(cp);
+			else
+				update_tasks_cpumask(cp, NULL);
 		}
+		break;
 
-		/* Continue past cpusets with all cpus, mems online */
-		if (cpumask_subset(cp->cpus_allowed, cpu_active_mask) &&
-		    nodes_subset(cp->mems_allowed, node_states[N_HIGH_MEMORY]))
-			continue;
+	case CPUSET_MEM_OFFLINE:
+		while ((cp = cpuset_next(&queue)) != NULL) {
 
-		oldmems = cp->mems_allowed;
+			/* Continue past cpusets with all mems online */
+			if (nodes_subset(cp->mems_allowed,
+					node_states[N_HIGH_MEMORY]))
+				continue;
 
-		/* Remove offline cpus and mems from this cpuset. */
-		mutex_lock(&callback_mutex);
-		cpumask_and(cp->cpus_allowed, cp->cpus_allowed,
-			    cpu_active_mask);
-		nodes_and(cp->mems_allowed, cp->mems_allowed,
+			oldmems = cp->mems_allowed;
+
+			/* Remove offline mems from this cpuset. */
+			mutex_lock(&callback_mutex);
+			nodes_and(cp->mems_allowed, cp->mems_allowed,
 						node_states[N_HIGH_MEMORY]);
-		mutex_unlock(&callback_mutex);
+			mutex_unlock(&callback_mutex);
 
-		/* Move tasks from the empty cpuset to a parent */
-		if (cpumask_empty(cp->cpus_allowed) ||
-		     nodes_empty(cp->mems_allowed))
-			remove_tasks_in_empty_cpuset(cp);
-		else {
-			update_tasks_cpumask(cp, NULL);
-			update_tasks_nodemask(cp, &oldmems, NULL);
+			/* Move tasks from the empty cpuset to a parent */
+			if (nodes_empty(cp->mems_allowed))
+				remove_tasks_in_empty_cpuset(cp);
+			else
+				update_tasks_nodemask(cp, &oldmems, NULL);
 		}
 	}
 }
@@ -2054,13 +2099,19 @@ static void scan_for_empty_cpusets(struct cpuset *root)
  * (of no affect) on systems that are actively using CPU hotplug
  * but making no active use of cpusets.
  *
+ * The only exception to this is suspend/resume, where we don't
+ * modify cpusets at all.
+ *
  * This routine ensures that top_cpuset.cpus_allowed tracks
  * cpu_active_mask on each CPU hotplug (cpuhp) event.
  *
  * Called within get_online_cpus().  Needs to call cgroup_lock()
  * before calling generate_sched_domains().
+ *
+ * @cpu_online: Indicates whether this is a CPU online event (true) or
+ * a CPU offline event (false).
  */
-void cpuset_update_active_cpus(void)
+void cpuset_update_active_cpus(bool cpu_online)
 {
 	struct sched_domain_attr *attr;
 	cpumask_var_t *doms;
@@ -2070,7 +2121,10 @@ void cpuset_update_active_cpus(void)
 	mutex_lock(&callback_mutex);
 	cpumask_copy(top_cpuset.cpus_allowed, cpu_active_mask);
 	mutex_unlock(&callback_mutex);
-	scan_for_empty_cpusets(&top_cpuset);
+
+	if (!cpu_online)
+		scan_cpusets_upon_hotplug(&top_cpuset, CPUSET_CPU_OFFLINE);
+
 	ndoms = generate_sched_domains(&doms, &attr);
 	cgroup_unlock();
 
@@ -2082,7 +2136,7 @@ void cpuset_update_active_cpus(void)
 /*
  * Keep top_cpuset.mems_allowed tracking node_states[N_HIGH_MEMORY].
  * Call this routine anytime after node_states[N_HIGH_MEMORY] changes.
- * See also the previous routine cpuset_track_online_cpus().
+ * See cpuset_update_active_cpus() for CPU hotplug handling.
  */
 static int cpuset_track_online_nodes(struct notifier_block *self,
 				unsigned long action, void *arg)
@@ -2101,9 +2155,9 @@ static int cpuset_track_online_nodes(struct notifier_block *self,
 	case MEM_OFFLINE:
 		/*
 		 * needn't update top_cpuset.mems_allowed explicitly because
-		 * scan_for_empty_cpusets() will update it.
+		 * scan_cpusets_upon_hotplug() will update it.
 		 */
-		scan_for_empty_cpusets(&top_cpuset);
+		scan_cpusets_upon_hotplug(&top_cpuset, CPUSET_MEM_OFFLINE);
 		break;
 	default:
 		break;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index d7d71d6..f1cf0ed 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -1645,6 +1645,8 @@ perf_install_in_context(struct perf_event_context *ctx,
 	lockdep_assert_held(&ctx->mutex);
 
 	event->ctx = ctx;
+	if (event->cpu != -1)
+		event->cpu = cpu;
 
 	if (!task) {
 		/*
@@ -6252,6 +6254,8 @@ SYSCALL_DEFINE5(perf_event_open,
 		}
 	}
 
+	get_online_cpus();
+
 	event = perf_event_alloc(&attr, cpu, task, group_leader, NULL,
 				 NULL, NULL);
 	if (IS_ERR(event)) {
@@ -6304,7 +6308,7 @@ SYSCALL_DEFINE5(perf_event_open,
 	/*
 	 * Get the target context (task or percpu):
 	 */
-	ctx = find_get_context(pmu, task, cpu);
+	ctx = find_get_context(pmu, task, event->cpu);
 	if (IS_ERR(ctx)) {
 		err = PTR_ERR(ctx);
 		goto err_alloc;
@@ -6377,20 +6381,23 @@ SYSCALL_DEFINE5(perf_event_open,
 	mutex_lock(&ctx->mutex);
 
 	if (move_group) {
-		perf_install_in_context(ctx, group_leader, cpu);
+		synchronize_rcu();
+		perf_install_in_context(ctx, group_leader, event->cpu);
 		get_ctx(ctx);
 		list_for_each_entry(sibling, &group_leader->sibling_list,
 				    group_entry) {
-			perf_install_in_context(ctx, sibling, cpu);
+			perf_install_in_context(ctx, sibling, event->cpu);
 			get_ctx(ctx);
 		}
 	}
 
-	perf_install_in_context(ctx, event, cpu);
+	perf_install_in_context(ctx, event, event->cpu);
 	++ctx->generation;
 	perf_unpin_context(ctx);
 	mutex_unlock(&ctx->mutex);
 
+	put_online_cpus();
+
 	event->owner = current;
 
 	mutex_lock(&current->perf_event_mutex);
@@ -6419,6 +6426,7 @@ err_context:
 err_alloc:
 	free_event(event);
 err_task:
+	put_online_cpus();
 	if (task)
 		put_task_struct(task);
 err_group_fd:
@@ -6479,6 +6487,39 @@ err:
 }
 EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter);
 
+void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu)
+{
+	struct perf_event_context *src_ctx;
+	struct perf_event_context *dst_ctx;
+	struct perf_event *event, *tmp;
+	LIST_HEAD(events);
+
+	src_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, src_cpu)->ctx;
+	dst_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, dst_cpu)->ctx;
+
+	mutex_lock(&src_ctx->mutex);
+	list_for_each_entry_safe(event, tmp, &src_ctx->event_list,
+				 event_entry) {
+		perf_remove_from_context(event);
+		put_ctx(src_ctx);
+		list_add(&event->event_entry, &events);
+	}
+	mutex_unlock(&src_ctx->mutex);
+
+	synchronize_rcu();
+
+	mutex_lock(&dst_ctx->mutex);
+	list_for_each_entry_safe(event, tmp, &events, event_entry) {
+		list_del(&event->event_entry);
+		if (event->state >= PERF_EVENT_STATE_OFF)
+			event->state = PERF_EVENT_STATE_INACTIVE;
+		perf_install_in_context(dst_ctx, event, dst_cpu);
+		get_ctx(dst_ctx);
+	}
+	mutex_unlock(&dst_ctx->mutex);
+}
+EXPORT_SYMBOL_GPL(perf_pmu_migrate_context);
+
 static void sync_child_event(struct perf_event *child_event,
 			       struct task_struct *child)
 {
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 985be4d..f935327 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -38,13 +38,29 @@
 #define UINSNS_PER_PAGE			(PAGE_SIZE/UPROBE_XOL_SLOT_BYTES)
 #define MAX_UPROBE_XOL_SLOTS		UINSNS_PER_PAGE
 
-static struct srcu_struct uprobes_srcu;
 static struct rb_root uprobes_tree = RB_ROOT;
 
 static DEFINE_SPINLOCK(uprobes_treelock);	/* serialize rbtree access */
 
 #define UPROBES_HASH_SZ	13
 
+/*
+ * We need separate register/unregister and mmap/munmap lock hashes because
+ * of mmap_sem nesting.
+ *
+ * uprobe_register() needs to install probes on (potentially) all processes
+ * and thus needs to acquire multiple mmap_sems (consequtively, not
+ * concurrently), whereas uprobe_mmap() is called while holding mmap_sem
+ * for the particular process doing the mmap.
+ *
+ * uprobe_register()->register_for_each_vma() needs to drop/acquire mmap_sem
+ * because of lock order against i_mmap_mutex. This means there's a hole in
+ * the register vma iteration where a mmap() can happen.
+ *
+ * Thus uprobe_register() can race with uprobe_mmap() and we can try and
+ * install a probe where one is already installed.
+ */
+
 /* serialize (un)register */
 static struct mutex uprobes_mutex[UPROBES_HASH_SZ];
 
@@ -61,17 +77,6 @@ static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ];
  */
 static atomic_t uprobe_events = ATOMIC_INIT(0);
 
-/*
- * Maintain a temporary per vma info that can be used to search if a vma
- * has already been handled. This structure is introduced since extending
- * vm_area_struct wasnt recommended.
- */
-struct vma_info {
-	struct list_head	probe_list;
-	struct mm_struct	*mm;
-	loff_t			vaddr;
-};
-
 struct uprobe {
 	struct rb_node		rb_node;	/* node in the rb tree */
 	atomic_t		ref;
@@ -100,7 +105,8 @@ static bool valid_vma(struct vm_area_struct *vma, bool is_register)
 	if (!is_register)
 		return true;
 
-	if ((vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) == (VM_READ|VM_EXEC))
+	if ((vma->vm_flags & (VM_HUGETLB|VM_READ|VM_WRITE|VM_EXEC|VM_SHARED))
+				== (VM_READ|VM_EXEC))
 		return true;
 
 	return false;
@@ -129,33 +135,17 @@ static loff_t vma_address(struct vm_area_struct *vma, loff_t offset)
 static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage)
 {
 	struct mm_struct *mm = vma->vm_mm;
-	pgd_t *pgd;
-	pud_t *pud;
-	pmd_t *pmd;
-	pte_t *ptep;
-	spinlock_t *ptl;
 	unsigned long addr;
-	int err = -EFAULT;
+	spinlock_t *ptl;
+	pte_t *ptep;
 
 	addr = page_address_in_vma(page, vma);
 	if (addr == -EFAULT)
-		goto out;
-
-	pgd = pgd_offset(mm, addr);
-	if (!pgd_present(*pgd))
-		goto out;
-
-	pud = pud_offset(pgd, addr);
-	if (!pud_present(*pud))
-		goto out;
-
-	pmd = pmd_offset(pud, addr);
-	if (!pmd_present(*pmd))
-		goto out;
+		return -EFAULT;
 
-	ptep = pte_offset_map_lock(mm, pmd, addr, &ptl);
+	ptep = page_check_address(page, mm, addr, &ptl, 0);
 	if (!ptep)
-		goto out;
+		return -EAGAIN;
 
 	get_page(kpage);
 	page_add_new_anon_rmap(kpage, vma, addr);
@@ -174,10 +164,8 @@ static int __replace_page(struct vm_area_struct *vma, struct page *page, struct
 		try_to_free_swap(page);
 	put_page(page);
 	pte_unmap_unlock(ptep, ptl);
-	err = 0;
 
-out:
-	return err;
+	return 0;
 }
 
 /**
@@ -222,9 +210,8 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
 	void *vaddr_old, *vaddr_new;
 	struct vm_area_struct *vma;
 	struct uprobe *uprobe;
-	loff_t addr;
 	int ret;
-
+retry:
 	/* Read the page with vaddr into memory */
 	ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma);
 	if (ret <= 0)
@@ -246,10 +233,6 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
 	if (mapping != vma->vm_file->f_mapping)
 		goto put_out;
 
-	addr = vma_address(vma, uprobe->offset);
-	if (vaddr != (unsigned long)addr)
-		goto put_out;
-
 	ret = -ENOMEM;
 	new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
 	if (!new_page)
@@ -267,11 +250,7 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
 	vaddr_new = kmap_atomic(new_page);
 
 	memcpy(vaddr_new, vaddr_old, PAGE_SIZE);
-
-	/* poke the new insn in, ASSUMES we don't cross page boundary */
-	vaddr &= ~PAGE_MASK;
-	BUG_ON(vaddr + UPROBE_SWBP_INSN_SIZE > PAGE_SIZE);
-	memcpy(vaddr_new + vaddr, &opcode, UPROBE_SWBP_INSN_SIZE);
+	memcpy(vaddr_new + (vaddr & ~PAGE_MASK), &opcode, UPROBE_SWBP_INSN_SIZE);
 
 	kunmap_atomic(vaddr_new);
 	kunmap_atomic(vaddr_old);
@@ -291,6 +270,8 @@ unlock_out:
 put_out:
 	put_page(old_page);
 
+	if (unlikely(ret == -EAGAIN))
+		goto retry;
 	return ret;
 }
 
@@ -312,7 +293,7 @@ static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_
 	void *vaddr_new;
 	int ret;
 
-	ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &page, NULL);
+	ret = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
 	if (ret <= 0)
 		return ret;
 
@@ -333,10 +314,20 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
 	uprobe_opcode_t opcode;
 	int result;
 
+	if (current->mm == mm) {
+		pagefault_disable();
+		result = __copy_from_user_inatomic(&opcode, (void __user*)vaddr,
+								sizeof(opcode));
+		pagefault_enable();
+
+		if (likely(result == 0))
+			goto out;
+	}
+
 	result = read_opcode(mm, vaddr, &opcode);
 	if (result)
 		return result;
-
+out:
 	if (is_swbp_insn(&opcode))
 		return 1;
 
@@ -355,7 +346,9 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
 int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
 {
 	int result;
-
+	/*
+	 * See the comment near uprobes_hash().
+	 */
 	result = is_swbp_at_addr(mm, vaddr);
 	if (result == 1)
 		return -EEXIST;
@@ -520,7 +513,6 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
 	uprobe->inode = igrab(inode);
 	uprobe->offset = offset;
 	init_rwsem(&uprobe->consumer_rwsem);
-	INIT_LIST_HEAD(&uprobe->pending_list);
 
 	/* add to uprobes_tree, sorted on inode:offset */
 	cur_uprobe = insert_uprobe(uprobe);
@@ -588,20 +580,22 @@ static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *uc)
 }
 
 static int
-__copy_insn(struct address_space *mapping, struct vm_area_struct *vma, char *insn,
-			unsigned long nbytes, unsigned long offset)
+__copy_insn(struct address_space *mapping, struct file *filp, char *insn,
+			unsigned long nbytes, loff_t offset)
 {
-	struct file *filp = vma->vm_file;
 	struct page *page;
 	void *vaddr;
-	unsigned long off1;
-	unsigned long idx;
+	unsigned long off;
+	pgoff_t idx;
 
 	if (!filp)
 		return -EINVAL;
 
-	idx = (unsigned long)(offset >> PAGE_CACHE_SHIFT);
-	off1 = offset &= ~PAGE_MASK;
+	if (!mapping->a_ops->readpage)
+		return -EIO;
+
+	idx = offset >> PAGE_CACHE_SHIFT;
+	off = offset & ~PAGE_MASK;
 
 	/*
 	 * Ensure that the page that has the original instruction is
@@ -612,22 +606,20 @@ __copy_insn(struct address_space *mapping, struct vm_area_struct *vma, char *ins
 		return PTR_ERR(page);
 
 	vaddr = kmap_atomic(page);
-	memcpy(insn, vaddr + off1, nbytes);
+	memcpy(insn, vaddr + off, nbytes);
 	kunmap_atomic(vaddr);
 	page_cache_release(page);
 
 	return 0;
 }
 
-static int
-copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr)
+static int copy_insn(struct uprobe *uprobe, struct file *filp)
 {
 	struct address_space *mapping;
 	unsigned long nbytes;
 	int bytes;
 
-	addr &= ~PAGE_MASK;
-	nbytes = PAGE_SIZE - addr;
+	nbytes = PAGE_SIZE - (uprobe->offset & ~PAGE_MASK);
 	mapping = uprobe->inode->i_mapping;
 
 	/* Instruction at end of binary; copy only available bytes */
@@ -638,13 +630,13 @@ copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr)
 
 	/* Instruction at the page-boundary; copy bytes in second page */
 	if (nbytes < bytes) {
-		if (__copy_insn(mapping, vma, uprobe->arch.insn + nbytes,
-				bytes - nbytes, uprobe->offset + nbytes))
-			return -ENOMEM;
-
+		int err = __copy_insn(mapping, filp, uprobe->arch.insn + nbytes,
+				bytes - nbytes, uprobe->offset + nbytes);
+		if (err)
+			return err;
 		bytes = nbytes;
 	}
-	return __copy_insn(mapping, vma, uprobe->arch.insn, bytes, uprobe->offset);
+	return __copy_insn(mapping, filp, uprobe->arch.insn, bytes, uprobe->offset);
 }
 
 /*
@@ -672,9 +664,8 @@ copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr)
  */
 static int
 install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
-			struct vm_area_struct *vma, loff_t vaddr)
+			struct vm_area_struct *vma, unsigned long vaddr)
 {
-	unsigned long addr;
 	int ret;
 
 	/*
@@ -687,20 +678,22 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
 	if (!uprobe->consumers)
 		return -EEXIST;
 
-	addr = (unsigned long)vaddr;
-
 	if (!(uprobe->flags & UPROBE_COPY_INSN)) {
-		ret = copy_insn(uprobe, vma, addr);
+		ret = copy_insn(uprobe, vma->vm_file);
 		if (ret)
 			return ret;
 
 		if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn))
-			return -EEXIST;
+			return -ENOTSUPP;
 
-		ret = arch_uprobe_analyze_insn(&uprobe->arch, mm);
+		ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr);
 		if (ret)
 			return ret;
 
+		/* write_opcode() assumes we don't cross page boundary */
+		BUG_ON((uprobe->offset & ~PAGE_MASK) +
+				UPROBE_SWBP_INSN_SIZE > PAGE_SIZE);
+
 		uprobe->flags |= UPROBE_COPY_INSN;
 	}
 
@@ -713,7 +706,7 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
 	 * Hence increment before and decrement on failure.
 	 */
 	atomic_inc(&mm->uprobes_state.count);
-	ret = set_swbp(&uprobe->arch, mm, addr);
+	ret = set_swbp(&uprobe->arch, mm, vaddr);
 	if (ret)
 		atomic_dec(&mm->uprobes_state.count);
 
@@ -721,27 +714,21 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
 }
 
 static void
-remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, loff_t vaddr)
+remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr)
 {
-	if (!set_orig_insn(&uprobe->arch, mm, (unsigned long)vaddr, true))
+	if (!set_orig_insn(&uprobe->arch, mm, vaddr, true))
 		atomic_dec(&mm->uprobes_state.count);
 }
 
 /*
- * There could be threads that have hit the breakpoint and are entering the
- * notifier code and trying to acquire the uprobes_treelock. The thread
- * calling delete_uprobe() that is removing the uprobe from the rb_tree can
- * race with these threads and might acquire the uprobes_treelock compared
- * to some of the breakpoint hit threads. In such a case, the breakpoint
- * hit threads will not find the uprobe. The current unregistering thread
- * waits till all other threads have hit a breakpoint, to acquire the
- * uprobes_treelock before the uprobe is removed from the rbtree.
+ * There could be threads that have already hit the breakpoint. They
+ * will recheck the current insn and restart if find_uprobe() fails.
+ * See find_active_uprobe().
  */
 static void delete_uprobe(struct uprobe *uprobe)
 {
 	unsigned long flags;
 
-	synchronize_srcu(&uprobes_srcu);
 	spin_lock_irqsave(&uprobes_treelock, flags);
 	rb_erase(&uprobe->rb_node, &uprobes_tree);
 	spin_unlock_irqrestore(&uprobes_treelock, flags);
@@ -750,139 +737,135 @@ static void delete_uprobe(struct uprobe *uprobe)
 	atomic_dec(&uprobe_events);
 }
 
-static struct vma_info *
-__find_next_vma_info(struct address_space *mapping, struct list_head *head,
-			struct vma_info *vi, loff_t offset, bool is_register)
+struct map_info {
+	struct map_info *next;
+	struct mm_struct *mm;
+	unsigned long vaddr;
+};
+
+static inline struct map_info *free_map_info(struct map_info *info)
+{
+	struct map_info *next = info->next;
+	kfree(info);
+	return next;
+}
+
+static struct map_info *
+build_map_info(struct address_space *mapping, loff_t offset, bool is_register)
 {
+	unsigned long pgoff = offset >> PAGE_SHIFT;
 	struct prio_tree_iter iter;
 	struct vm_area_struct *vma;
-	struct vma_info *tmpvi;
-	unsigned long pgoff;
-	int existing_vma;
-	loff_t vaddr;
-
-	pgoff = offset >> PAGE_SHIFT;
+	struct map_info *curr = NULL;
+	struct map_info *prev = NULL;
+	struct map_info *info;
+	int more = 0;
 
+ again:
+	mutex_lock(&mapping->i_mmap_mutex);
 	vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
 		if (!valid_vma(vma, is_register))
 			continue;
 
-		existing_vma = 0;
-		vaddr = vma_address(vma, offset);
-
-		list_for_each_entry(tmpvi, head, probe_list) {
-			if (tmpvi->mm == vma->vm_mm && tmpvi->vaddr == vaddr) {
-				existing_vma = 1;
-				break;
-			}
+		if (!prev && !more) {
+			/*
+			 * Needs GFP_NOWAIT to avoid i_mmap_mutex recursion through
+			 * reclaim. This is optimistic, no harm done if it fails.
+			 */
+			prev = kmalloc(sizeof(struct map_info),
+					GFP_NOWAIT | __GFP_NOMEMALLOC | __GFP_NOWARN);
+			if (prev)
+				prev->next = NULL;
 		}
-
-		/*
-		 * Another vma needs a probe to be installed. However skip
-		 * installing the probe if the vma is about to be unlinked.
-		 */
-		if (!existing_vma && atomic_inc_not_zero(&vma->vm_mm->mm_users)) {
-			vi->mm = vma->vm_mm;
-			vi->vaddr = vaddr;
-			list_add(&vi->probe_list, head);
-
-			return vi;
+		if (!prev) {
+			more++;
+			continue;
 		}
-	}
 
-	return NULL;
-}
-
-/*
- * Iterate in the rmap prio tree  and find a vma where a probe has not
- * yet been inserted.
- */
-static struct vma_info *
-find_next_vma_info(struct address_space *mapping, struct list_head *head,
-		loff_t offset, bool is_register)
-{
-	struct vma_info *vi, *retvi;
+		if (!atomic_inc_not_zero(&vma->vm_mm->mm_users))
+			continue;
 
-	vi = kzalloc(sizeof(struct vma_info), GFP_KERNEL);
-	if (!vi)
-		return ERR_PTR(-ENOMEM);
+		info = prev;
+		prev = prev->next;
+		info->next = curr;
+		curr = info;
 
-	mutex_lock(&mapping->i_mmap_mutex);
-	retvi = __find_next_vma_info(mapping, head, vi, offset, is_register);
+		info->mm = vma->vm_mm;
+		info->vaddr = vma_address(vma, offset);
+	}
 	mutex_unlock(&mapping->i_mmap_mutex);
 
-	if (!retvi)
-		kfree(vi);
+	if (!more)
+		goto out;
+
+	prev = curr;
+	while (curr) {
+		mmput(curr->mm);
+		curr = curr->next;
+	}
 
-	return retvi;
+	do {
+		info = kmalloc(sizeof(struct map_info), GFP_KERNEL);
+		if (!info) {
+			curr = ERR_PTR(-ENOMEM);
+			goto out;
+		}
+		info->next = prev;
+		prev = info;
+	} while (--more);
+
+	goto again;
+ out:
+	while (prev)
+		prev = free_map_info(prev);
+	return curr;
 }
 
 static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
 {
-	struct list_head try_list;
-	struct vm_area_struct *vma;
-	struct address_space *mapping;
-	struct vma_info *vi, *tmpvi;
-	struct mm_struct *mm;
-	loff_t vaddr;
-	int ret;
+	struct map_info *info;
+	int err = 0;
 
-	mapping = uprobe->inode->i_mapping;
-	INIT_LIST_HEAD(&try_list);
+	info = build_map_info(uprobe->inode->i_mapping,
+					uprobe->offset, is_register);
+	if (IS_ERR(info))
+		return PTR_ERR(info);
 
-	ret = 0;
+	while (info) {
+		struct mm_struct *mm = info->mm;
+		struct vm_area_struct *vma;
 
-	for (;;) {
-		vi = find_next_vma_info(mapping, &try_list, uprobe->offset, is_register);
-		if (!vi)
-			break;
+		if (err)
+			goto free;
 
-		if (IS_ERR(vi)) {
-			ret = PTR_ERR(vi);
-			break;
-		}
+		down_write(&mm->mmap_sem);
+		vma = find_vma(mm, (unsigned long)info->vaddr);
+		if (!vma || !valid_vma(vma, is_register))
+			goto unlock;
 
-		mm = vi->mm;
-		down_read(&mm->mmap_sem);
-		vma = find_vma(mm, (unsigned long)vi->vaddr);
-		if (!vma || !valid_vma(vma, is_register)) {
-			list_del(&vi->probe_list);
-			kfree(vi);
-			up_read(&mm->mmap_sem);
-			mmput(mm);
-			continue;
-		}
-		vaddr = vma_address(vma, uprobe->offset);
 		if (vma->vm_file->f_mapping->host != uprobe->inode ||
-						vaddr != vi->vaddr) {
-			list_del(&vi->probe_list);
-			kfree(vi);
-			up_read(&mm->mmap_sem);
-			mmput(mm);
-			continue;
-		}
-
-		if (is_register)
-			ret = install_breakpoint(uprobe, mm, vma, vi->vaddr);
-		else
-			remove_breakpoint(uprobe, mm, vi->vaddr);
+		    vma_address(vma, uprobe->offset) != info->vaddr)
+			goto unlock;
 
-		up_read(&mm->mmap_sem);
-		mmput(mm);
 		if (is_register) {
-			if (ret && ret == -EEXIST)
-				ret = 0;
-			if (ret)
-				break;
+			err = install_breakpoint(uprobe, mm, vma, info->vaddr);
+			/*
+			 * We can race against uprobe_mmap(), see the
+			 * comment near uprobe_hash().
+			 */
+			if (err == -EEXIST)
+				err = 0;
+		} else {
+			remove_breakpoint(uprobe, mm, info->vaddr);
 		}
+ unlock:
+		up_write(&mm->mmap_sem);
+ free:
+		mmput(mm);
+		info = free_map_info(info);
 	}
 
-	list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) {
-		list_del(&vi->probe_list);
-		kfree(vi);
-	}
-
-	return ret;
+	return err;
 }
 
 static int __uprobe_register(struct uprobe *uprobe)
@@ -1048,7 +1031,7 @@ static void build_probe_list(struct inode *inode, struct list_head *head)
 int uprobe_mmap(struct vm_area_struct *vma)
 {
 	struct list_head tmp_list;
-	struct uprobe *uprobe, *u;
+	struct uprobe *uprobe;
 	struct inode *inode;
 	int ret, count;
 
@@ -1066,12 +1049,9 @@ int uprobe_mmap(struct vm_area_struct *vma)
 	ret = 0;
 	count = 0;
 
-	list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
-		loff_t vaddr;
-
-		list_del(&uprobe->pending_list);
+	list_for_each_entry(uprobe, &tmp_list, pending_list) {
 		if (!ret) {
-			vaddr = vma_address(vma, uprobe->offset);
+			loff_t vaddr = vma_address(vma, uprobe->offset);
 
 			if (vaddr < vma->vm_start || vaddr >= vma->vm_end) {
 				put_uprobe(uprobe);
@@ -1079,8 +1059,10 @@ int uprobe_mmap(struct vm_area_struct *vma)
 			}
 
 			ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
-
-			/* Ignore double add: */
+			/*
+			 * We can race against uprobe_register(), see the
+			 * comment near uprobe_hash().
+			 */
 			if (ret == -EEXIST) {
 				ret = 0;
 
@@ -1115,7 +1097,7 @@ int uprobe_mmap(struct vm_area_struct *vma)
 void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
 	struct list_head tmp_list;
-	struct uprobe *uprobe, *u;
+	struct uprobe *uprobe;
 	struct inode *inode;
 
 	if (!atomic_read(&uprobe_events) || !valid_vma(vma, false))
@@ -1132,11 +1114,8 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon
 	mutex_lock(uprobes_mmap_hash(inode));
 	build_probe_list(inode, &tmp_list);
 
-	list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
-		loff_t vaddr;
-
-		list_del(&uprobe->pending_list);
-		vaddr = vma_address(vma, uprobe->offset);
+	list_for_each_entry(uprobe, &tmp_list, pending_list) {
+		loff_t vaddr = vma_address(vma, uprobe->offset);
 
 		if (vaddr >= start && vaddr < end) {
 			/*
@@ -1378,9 +1357,6 @@ void uprobe_free_utask(struct task_struct *t)
 {
 	struct uprobe_task *utask = t->utask;
 
-	if (t->uprobe_srcu_id != -1)
-		srcu_read_unlock_raw(&uprobes_srcu, t->uprobe_srcu_id);
-
 	if (!utask)
 		return;
 
@@ -1398,7 +1374,6 @@ void uprobe_free_utask(struct task_struct *t)
 void uprobe_copy_process(struct task_struct *t)
 {
 	t->utask = NULL;
-	t->uprobe_srcu_id = -1;
 }
 
 /*
@@ -1417,7 +1392,6 @@ static struct uprobe_task *add_utask(void)
 	if (unlikely(!utask))
 		return NULL;
 
-	utask->active_uprobe = NULL;
 	current->utask = utask;
 	return utask;
 }
@@ -1479,41 +1453,64 @@ static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs)
 	return false;
 }
 
+static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
+{
+	struct mm_struct *mm = current->mm;
+	struct uprobe *uprobe = NULL;
+	struct vm_area_struct *vma;
+
+	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, bp_vaddr);
+	if (vma && vma->vm_start <= bp_vaddr) {
+		if (valid_vma(vma, false)) {
+			struct inode *inode;
+			loff_t offset;
+
+			inode = vma->vm_file->f_mapping->host;
+			offset = bp_vaddr - vma->vm_start;
+			offset += (vma->vm_pgoff << PAGE_SHIFT);
+			uprobe = find_uprobe(inode, offset);
+		}
+
+		if (!uprobe)
+			*is_swbp = is_swbp_at_addr(mm, bp_vaddr);
+	} else {
+		*is_swbp = -EFAULT;
+	}
+	up_read(&mm->mmap_sem);
+
+	return uprobe;
+}
+
 /*
  * Run handler and ask thread to singlestep.
  * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
  */
 static void handle_swbp(struct pt_regs *regs)
 {
-	struct vm_area_struct *vma;
 	struct uprobe_task *utask;
 	struct uprobe *uprobe;
-	struct mm_struct *mm;
 	unsigned long bp_vaddr;
+	int uninitialized_var(is_swbp);
 
-	uprobe = NULL;
 	bp_vaddr = uprobe_get_swbp_addr(regs);
-	mm = current->mm;
-	down_read(&mm->mmap_sem);
-	vma = find_vma(mm, bp_vaddr);
-
-	if (vma && vma->vm_start <= bp_vaddr && valid_vma(vma, false)) {
-		struct inode *inode;
-		loff_t offset;
-
-		inode = vma->vm_file->f_mapping->host;
-		offset = bp_vaddr - vma->vm_start;
-		offset += (vma->vm_pgoff << PAGE_SHIFT);
-		uprobe = find_uprobe(inode, offset);
-	}
-
-	srcu_read_unlock_raw(&uprobes_srcu, current->uprobe_srcu_id);
-	current->uprobe_srcu_id = -1;
-	up_read(&mm->mmap_sem);
+	uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
 
 	if (!uprobe) {
-		/* No matching uprobe; signal SIGTRAP. */
-		send_sig(SIGTRAP, current, 0);
+		if (is_swbp > 0) {
+			/* No matching uprobe; signal SIGTRAP. */
+			send_sig(SIGTRAP, current, 0);
+		} else {
+			/*
+			 * Either we raced with uprobe_unregister() or we can't
+			 * access this memory. The latter is only possible if
+			 * another thread plays with our ->mm. In both cases
+			 * we can simply restart. If this vma was unmapped we
+			 * can pretend this insn was not executed yet and get
+			 * the (correct) SIGSEGV after restart.
+			 */
+			instruction_pointer_set(regs, bp_vaddr);
+		}
 		return;
 	}
 
@@ -1620,7 +1617,6 @@ int uprobe_pre_sstep_notifier(struct pt_regs *regs)
 		utask->state = UTASK_BP_HIT;
 
 	set_thread_flag(TIF_UPROBE);
-	current->uprobe_srcu_id = srcu_read_lock_raw(&uprobes_srcu);
 
 	return 1;
 }
@@ -1655,7 +1651,6 @@ static int __init init_uprobes(void)
 		mutex_init(&uprobes_mutex[i]);
 		mutex_init(&uprobes_mmap_mutex[i]);
 	}
-	init_srcu_struct(&uprobes_srcu);
 
 	return register_die_notifier(&uprobe_exception_nb);
 }
diff --git a/kernel/fork.c b/kernel/fork.c
index ab5211b..df667a0 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -346,7 +346,6 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
 	struct rb_node **rb_link, *rb_parent;
 	int retval;
 	unsigned long charge;
-	struct mempolicy *pol;
 
 	down_write(&oldmm->mmap_sem);
 	flush_cache_dup_mm(oldmm);
@@ -378,16 +377,14 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
 		struct file *file;
 
 		if (mpnt->vm_flags & VM_DONTCOPY) {
-			long pages = vma_pages(mpnt);
-			mm->total_vm -= pages;
 			vm_stat_account(mm, mpnt->vm_flags, mpnt->vm_file,
-								-pages);
+							-vma_pages(mpnt));
 			continue;
 		}
 		charge = 0;
 		if (mpnt->vm_flags & VM_ACCOUNT) {
-			unsigned long len;
-			len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
+			unsigned long len = vma_pages(mpnt);
+
 			if (security_vm_enough_memory_mm(oldmm, len)) /* sic */
 				goto fail_nomem;
 			charge = len;
@@ -397,11 +394,9 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
 			goto fail_nomem;
 		*tmp = *mpnt;
 		INIT_LIST_HEAD(&tmp->anon_vma_chain);
-		pol = mpol_dup(vma_policy(mpnt));
-		retval = PTR_ERR(pol);
-		if (IS_ERR(pol))
+		retval = vma_dup_policy(tmp, mpnt);
+		if (retval)
 			goto fail_nomem_policy;
-		vma_set_policy(tmp, pol);
 		tmp->vm_mm = mm;
 		if (anon_vma_fork(tmp, mpnt))
 			goto fail_nomem_anon_vma_fork;
@@ -466,7 +461,7 @@ out:
 	up_write(&oldmm->mmap_sem);
 	return retval;
 fail_nomem_anon_vma_fork:
-	mpol_put(pol);
+	mpol_put(vma_policy(tmp));
 fail_nomem_policy:
 	kmem_cache_free(vm_area_cachep, tmp);
 fail_nomem:
@@ -536,6 +531,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p)
 	mm->cached_hole_size = ~0UL;
 	mm_init_aio(mm);
 	mm_init_owner(mm, p);
+	mm_init_numa(mm);
 
 	if (likely(!mm_alloc_pgd(mm))) {
 		mm->def_flags = 0;
@@ -604,6 +600,7 @@ void mmput(struct mm_struct *mm)
 	might_sleep();
 
 	if (atomic_dec_and_test(&mm->mm_users)) {
+		exit_numa(mm);
 		uprobe_clear_state(mm);
 		exit_aio(mm);
 		ksm_exit(mm);
@@ -1310,9 +1307,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	p->memcg_batch.memcg = NULL;
 #endif
 
-	/* Perform scheduler related setup. Assign this task to a CPU. */
-	sched_fork(p);
-
 	retval = perf_event_init_task(p);
 	if (retval)
 		goto bad_fork_cleanup_policy;
@@ -1365,6 +1359,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	 * Clear TID on mm_release()?
 	 */
 	p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
+
+	INIT_LIST_HEAD(&p->thread_group);
+	/* Perform scheduler related setup. Assign this task to a CPU. */
+	sched_fork(p);
+
 #ifdef CONFIG_BLOCK
 	p->plug = NULL;
 #endif
@@ -1414,7 +1413,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	 * We dont wake it up yet.
 	 */
 	p->group_leader = p;
-	INIT_LIST_HEAD(&p->thread_group);
 	INIT_HLIST_HEAD(&p->task_works);
 
 	/* Now that the task is set up, run cgroup callbacks if
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 41c1564..d3968e9 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -10,6 +10,7 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/topology.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
@@ -45,7 +46,8 @@ static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
 {
 	struct irq_domain *domain;
 
-	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+	domain = kzalloc_node(sizeof(*domain), GFP_KERNEL,
+			      of_node_to_nid(of_node));
 	if (WARN_ON(!domain))
 		return NULL;
 
@@ -203,7 +205,8 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
 		 * one can then use irq_create_mapping() to
 		 * explicitly change them
 		 */
-		ops->map(domain, irq, hwirq);
+		if (ops->map)
+			ops->map(domain, irq, hwirq);
 
 		/* Clear norequest flags */
 		irq_clear_status_flags(irq, IRQ_NOREQUEST);
@@ -229,7 +232,8 @@ struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
 	struct irq_domain *domain;
 	unsigned int *revmap;
 
-	revmap = kzalloc(sizeof(*revmap) * size, GFP_KERNEL);
+	revmap = kzalloc_node(sizeof(*revmap) * size, GFP_KERNEL,
+			      of_node_to_nid(of_node));
 	if (WARN_ON(!revmap))
 		return NULL;
 
@@ -337,8 +341,8 @@ static int irq_setup_virq(struct irq_domain *domain, unsigned int virq,
 
 	irq_data->hwirq = hwirq;
 	irq_data->domain = domain;
-	if (domain->ops->map(domain, virq, hwirq)) {
-		pr_debug("irq-%i==>hwirq-0x%lx mapping failed\n", virq, hwirq);
+	if (domain->ops->map && domain->ops->map(domain, virq, hwirq)) {
+		pr_err("irq-%i==>hwirq-0x%lx mapping failed\n", virq, hwirq);
 		irq_data->domain = NULL;
 		irq_data->hwirq = 0;
 		return -1;
@@ -367,7 +371,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
 	BUG_ON(domain == NULL);
 	WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_NOMAP);
 
-	virq = irq_alloc_desc_from(1, 0);
+	virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
 	if (!virq) {
 		pr_debug("create_direct virq allocation failed\n");
 		return 0;
@@ -433,22 +437,21 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
 	hint = hwirq % nr_irqs;
 	if (hint == 0)
 		hint++;
-	virq = irq_alloc_desc_from(hint, 0);
+	virq = irq_alloc_desc_from(hint, of_node_to_nid(domain->of_node));
 	if (virq <= 0)
-		virq = irq_alloc_desc_from(1, 0);
+		virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
 	if (virq <= 0) {
 		pr_debug("-> virq allocation failed\n");
 		return 0;
 	}
 
 	if (irq_setup_virq(domain, virq, hwirq)) {
-		if (domain->revmap_type != IRQ_DOMAIN_MAP_LEGACY)
-			irq_free_desc(virq);
+		irq_free_desc(virq);
 		return 0;
 	}
 
 	pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
-		hwirq, domain->of_node ? domain->of_node->full_name : "null", virq);
+		hwirq, of_node_full_name(domain->of_node), virq);
 
 	return virq;
 }
@@ -477,7 +480,7 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
 			return intspec[0];
 #endif
 		pr_warning("no irq domain found for %s !\n",
-			   controller->full_name);
+			   of_node_full_name(controller));
 		return 0;
 	}
 
@@ -725,8 +728,8 @@ static int virq_debug_show(struct seq_file *m, void *private)
 			data = irq_desc_get_chip_data(desc);
 			seq_printf(m, data ? "0x%p  " : "  %p  ", data);
 
-			if (desc->irq_data.domain && desc->irq_data.domain->of_node)
-				p = desc->irq_data.domain->of_node->full_name;
+			if (desc->irq_data.domain)
+				p = of_node_full_name(desc->irq_data.domain->of_node);
 			else
 				p = none;
 			seq_printf(m, "%s\n", p);
@@ -761,12 +764,6 @@ static int __init irq_debugfs_init(void)
 __initcall(irq_debugfs_init);
 #endif /* CONFIG_IRQ_DOMAIN_DEBUG */
 
-static int irq_domain_simple_map(struct irq_domain *d, unsigned int irq,
-				 irq_hw_number_t hwirq)
-{
-	return 0;
-}
-
 /**
  * irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings
  *
@@ -829,7 +826,6 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d,
 EXPORT_SYMBOL_GPL(irq_domain_xlate_onetwocell);
 
 const struct irq_domain_ops irq_domain_simple_ops = {
-	.map = irq_domain_simple_map,
 	.xlate = irq_domain_xlate_onetwocell,
 };
 EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
diff --git a/kernel/kmod.c b/kernel/kmod.c
index ff2c7cb..5bf7a5e 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -45,6 +45,13 @@ extern int max_threads;
 
 static struct workqueue_struct *khelper_wq;
 
+/*
+ * kmod_thread_locker is used for deadlock avoidance.  There is no explicit
+ * locking to protect this global - it is private to the singleton khelper
+ * thread and should only ever be modified by that thread.
+ */
+static const struct task_struct *kmod_thread_locker;
+
 #define CAP_BSET	(void *)1
 #define CAP_PI		(void *)2
 
@@ -221,6 +228,13 @@ fail:
 	return 0;
 }
 
+static int call_helper(void *data)
+{
+	/* Worker thread started blocking khelper thread. */
+	kmod_thread_locker = current;
+	return ____call_usermodehelper(data);
+}
+
 static void call_usermodehelper_freeinfo(struct subprocess_info *info)
 {
 	if (info->cleanup)
@@ -295,9 +309,12 @@ static void __call_usermodehelper(struct work_struct *work)
 	if (wait == UMH_WAIT_PROC)
 		pid = kernel_thread(wait_for_helper, sub_info,
 				    CLONE_FS | CLONE_FILES | SIGCHLD);
-	else
-		pid = kernel_thread(____call_usermodehelper, sub_info,
+	else {
+		pid = kernel_thread(call_helper, sub_info,
 				    CLONE_VFORK | SIGCHLD);
+		/* Worker thread stopped blocking khelper thread. */
+		kmod_thread_locker = NULL;
+	}
 
 	switch (wait) {
 	case UMH_NO_WAIT:
@@ -548,6 +565,16 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
 		retval = -EBUSY;
 		goto out;
 	}
+	/*
+	 * Worker thread must not wait for khelper thread at below
+	 * wait_for_completion() if the thread was created with CLONE_VFORK
+	 * flag, for khelper thread is already waiting for the thread at
+	 * wait_for_completion() in do_fork().
+	 */
+	if (wait != UMH_NO_WAIT && current == kmod_thread_locker) {
+		retval = -EBUSY;
+		goto out;
+	}
 
 	sub_info->complete = &done;
 	sub_info->wait = wait;
diff --git a/kernel/module.c b/kernel/module.c
index 4edbd9c..9ad9ee9 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2730,6 +2730,10 @@ static int check_module_license_and_versions(struct module *mod)
 	if (strcmp(mod->name, "driverloader") == 0)
 		add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
 
+	/* lve claims to be GPL but upstream won't provide source */
+	if (strcmp(mod->name, "lve") == 0)
+		add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
+
 #ifdef CONFIG_MODVERSIONS
 	if ((mod->num_syms && !mod->crcs)
 	    || (mod->num_gpl_syms && !mod->gpl_crcs)
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 8f9b4eb..a70518c 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -175,7 +175,7 @@ config PM_TEST_SUSPEND
 	You probably want to have your system's RTC driver statically
 	linked, ensuring that it's available when this test runs.
 
-config CAN_PM_TRACE
+config PM_SLEEP_DEBUG
 	def_bool y
 	depends on PM_DEBUG && PM_SLEEP
 
@@ -196,7 +196,7 @@ config PM_TRACE
 
 config PM_TRACE_RTC
 	bool "Suspend/resume event tracing"
-	depends on CAN_PM_TRACE
+	depends on PM_SLEEP_DEBUG
 	depends on X86
 	select PM_TRACE
 	---help---
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 8b53db3..0d4b354 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2003 Open Source Development Lab
  * Copyright (c) 2004 Pavel Machek <pavel@ucw.cz>
  * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc.
+ * Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com>
  *
  * This file is released under the GPLv2.
  */
@@ -46,6 +47,9 @@ enum {
 	HIBERNATION_PLATFORM,
 	HIBERNATION_SHUTDOWN,
 	HIBERNATION_REBOOT,
+#ifdef CONFIG_SUSPEND
+	HIBERNATION_SUSPEND,
+#endif
 	/* keep last */
 	__HIBERNATION_AFTER_LAST
 };
@@ -354,6 +358,7 @@ int hibernation_snapshot(int platform_mode)
 	}
 
 	suspend_console();
+	ftrace_stop();
 	pm_restrict_gfp_mask();
 
 	error = dpm_suspend(PMSG_FREEZE);
@@ -379,6 +384,7 @@ int hibernation_snapshot(int platform_mode)
 	if (error || !in_suspend)
 		pm_restore_gfp_mask();
 
+	ftrace_start();
 	resume_console();
 	dpm_complete(msg);
 
@@ -481,6 +487,7 @@ int hibernation_restore(int platform_mode)
 
 	pm_prepare_console();
 	suspend_console();
+	ftrace_stop();
 	pm_restrict_gfp_mask();
 	error = dpm_suspend_start(PMSG_QUIESCE);
 	if (!error) {
@@ -488,6 +495,7 @@ int hibernation_restore(int platform_mode)
 		dpm_resume_end(PMSG_RECOVER);
 	}
 	pm_restore_gfp_mask();
+	ftrace_start();
 	resume_console();
 	pm_restore_console();
 	return error;
@@ -514,6 +522,7 @@ int hibernation_platform_enter(void)
 
 	entering_platform_hibernation = true;
 	suspend_console();
+	ftrace_stop();
 	error = dpm_suspend_start(PMSG_HIBERNATE);
 	if (error) {
 		if (hibernation_ops->recover)
@@ -557,6 +566,7 @@ int hibernation_platform_enter(void)
  Resume_devices:
 	entering_platform_hibernation = false;
 	dpm_resume_end(PMSG_RESTORE);
+	ftrace_start();
 	resume_console();
 
  Close:
@@ -574,6 +584,10 @@ int hibernation_platform_enter(void)
  */
 static void power_down(void)
 {
+#ifdef CONFIG_SUSPEND
+	int error;
+#endif
+
 	switch (hibernation_mode) {
 	case HIBERNATION_REBOOT:
 		kernel_restart(NULL);
@@ -583,6 +597,25 @@ static void power_down(void)
 	case HIBERNATION_SHUTDOWN:
 		kernel_power_off();
 		break;
+#ifdef CONFIG_SUSPEND
+	case HIBERNATION_SUSPEND:
+		error = suspend_devices_and_enter(PM_SUSPEND_MEM);
+		if (error) {
+			if (hibernation_ops)
+				hibernation_mode = HIBERNATION_PLATFORM;
+			else
+				hibernation_mode = HIBERNATION_SHUTDOWN;
+			power_down();
+		}
+		/*
+		 * Restore swap signature.
+		 */
+		error = swsusp_unmark();
+		if (error)
+			printk(KERN_ERR "PM: Swap will be unusable! "
+			                "Try swapon -a.\n");
+		return;
+#endif
 	}
 	kernel_halt();
 	/*
@@ -827,6 +860,9 @@ static const char * const hibernation_modes[] = {
 	[HIBERNATION_PLATFORM]	= "platform",
 	[HIBERNATION_SHUTDOWN]	= "shutdown",
 	[HIBERNATION_REBOOT]	= "reboot",
+#ifdef CONFIG_SUSPEND
+	[HIBERNATION_SUSPEND]	= "suspend",
+#endif
 };
 
 /*
@@ -867,6 +903,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
 		switch (i) {
 		case HIBERNATION_SHUTDOWN:
 		case HIBERNATION_REBOOT:
+#ifdef CONFIG_SUSPEND
+		case HIBERNATION_SUSPEND:
+#endif
 			break;
 		case HIBERNATION_PLATFORM:
 			if (hibernation_ops)
@@ -907,6 +946,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
 		switch (mode) {
 		case HIBERNATION_SHUTDOWN:
 		case HIBERNATION_REBOOT:
+#ifdef CONFIG_SUSPEND
+		case HIBERNATION_SUSPEND:
+#endif
 			hibernation_mode = mode;
 			break;
 		case HIBERNATION_PLATFORM:
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 428f8a0..f458238 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -235,6 +235,47 @@ late_initcall(pm_debugfs_init);
 
 #endif /* CONFIG_PM_SLEEP */
 
+#ifdef CONFIG_PM_SLEEP_DEBUG
+/*
+ * pm_print_times: print time taken by devices to suspend and resume.
+ *
+ * show() returns whether printing of suspend and resume times is enabled.
+ * store() accepts 0 or 1.  0 disables printing and 1 enables it.
+ */
+bool pm_print_times_enabled;
+
+static ssize_t pm_print_times_show(struct kobject *kobj,
+				   struct kobj_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", pm_print_times_enabled);
+}
+
+static ssize_t pm_print_times_store(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	if (val > 1)
+		return -EINVAL;
+
+	pm_print_times_enabled = !!val;
+	return n;
+}
+
+power_attr(pm_print_times);
+
+static inline void pm_print_times_init(void)
+{
+	pm_print_times_enabled = !!initcall_debug;
+}
+#else /* !CONFIG_PP_SLEEP_DEBUG */
+static inline void pm_print_times_init(void) {}
+#endif /* CONFIG_PM_SLEEP_DEBUG */
+
 struct kobject *power_kobj;
 
 /**
@@ -531,6 +572,9 @@ static struct attribute * g[] = {
 #ifdef CONFIG_PM_DEBUG
 	&pm_test_attr.attr,
 #endif
+#ifdef CONFIG_PM_SLEEP_DEBUG
+	&pm_print_times_attr.attr,
+#endif
 #endif
 	NULL,
 };
@@ -566,6 +610,7 @@ static int __init pm_init(void)
 	error = sysfs_create_group(power_kobj, &attr_group);
 	if (error)
 		return error;
+	pm_print_times_init();
 	return pm_autosleep_init();
 }
 
diff --git a/kernel/power/power.h b/kernel/power/power.h
index b0bd4be..7d4b7ff 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -156,6 +156,9 @@ extern void swsusp_free(void);
 extern int swsusp_read(unsigned int *flags_p);
 extern int swsusp_write(unsigned int flags);
 extern void swsusp_close(fmode_t);
+#ifdef CONFIG_SUSPEND
+extern int swsusp_unmark(void);
+#endif
 
 /* kernel/power/block_io.c */
 extern struct block_device *hib_resume_bdev;
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 396d262..1da39ea 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -24,6 +24,7 @@
 #include <linux/export.h>
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
+#include <linux/ftrace.h>
 #include <trace/events/power.h>
 
 #include "power.h"
@@ -177,6 +178,9 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
 	arch_suspend_enable_irqs();
 	BUG_ON(irqs_disabled());
 
+	/* Kick the lockup detector */
+	lockup_detector_bootcpu_resume();
+
  Enable_cpus:
 	enable_nonboot_cpus();
 
@@ -212,6 +216,7 @@ int suspend_devices_and_enter(suspend_state_t state)
 			goto Close;
 	}
 	suspend_console();
+	ftrace_stop();
 	suspend_test_start();
 	error = dpm_suspend_start(PMSG_SUSPEND);
 	if (error) {
@@ -231,6 +236,7 @@ int suspend_devices_and_enter(suspend_state_t state)
 	suspend_test_start();
 	dpm_resume_end(PMSG_RESUME);
 	suspend_test_finish("resume devices");
+	ftrace_start();
 	resume_console();
  Close:
 	if (suspend_ops->end)
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 11e22c0..3c9d764 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -448,9 +448,9 @@ static int save_image(struct swap_map_handle *handle,
 	struct timeval start;
 	struct timeval stop;
 
-	printk(KERN_INFO "PM: Saving image data pages (%u pages) ...     ",
+	printk(KERN_INFO "PM: Saving image data pages (%u pages)...\n",
 		nr_to_write);
-	m = nr_to_write / 100;
+	m = nr_to_write / 10;
 	if (!m)
 		m = 1;
 	nr_pages = 0;
@@ -464,7 +464,8 @@ static int save_image(struct swap_map_handle *handle,
 		if (ret)
 			break;
 		if (!(nr_pages % m))
-			printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
+			printk(KERN_INFO "PM: Image saving progress: %3d%%\n",
+			       nr_pages / m * 10);
 		nr_pages++;
 	}
 	err2 = hib_wait_on_bio_chain(&bio);
@@ -472,9 +473,7 @@ static int save_image(struct swap_map_handle *handle,
 	if (!ret)
 		ret = err2;
 	if (!ret)
-		printk(KERN_CONT "\b\b\b\bdone\n");
-	else
-		printk(KERN_CONT "\n");
+		printk(KERN_INFO "PM: Image saving done.\n");
 	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
 	return ret;
 }
@@ -668,9 +667,9 @@ static int save_image_lzo(struct swap_map_handle *handle,
 
 	printk(KERN_INFO
 		"PM: Using %u thread(s) for compression.\n"
-		"PM: Compressing and saving image data (%u pages) ...     ",
+		"PM: Compressing and saving image data (%u pages)...\n",
 		nr_threads, nr_to_write);
-	m = nr_to_write / 100;
+	m = nr_to_write / 10;
 	if (!m)
 		m = 1;
 	nr_pages = 0;
@@ -690,8 +689,10 @@ static int save_image_lzo(struct swap_map_handle *handle,
 				       data_of(*snapshot), PAGE_SIZE);
 
 				if (!(nr_pages % m))
-					printk(KERN_CONT "\b\b\b\b%3d%%",
-				               nr_pages / m);
+					printk(KERN_INFO
+					       "PM: Image saving progress: "
+					       "%3d%%\n",
+				               nr_pages / m * 10);
 				nr_pages++;
 			}
 			if (!off)
@@ -761,11 +762,8 @@ out_finish:
 	do_gettimeofday(&stop);
 	if (!ret)
 		ret = err2;
-	if (!ret) {
-		printk(KERN_CONT "\b\b\b\bdone\n");
-	} else {
-		printk(KERN_CONT "\n");
-	}
+	if (!ret)
+		printk(KERN_INFO "PM: Image saving done.\n");
 	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
 out_clean:
 	if (crc) {
@@ -973,9 +971,9 @@ static int load_image(struct swap_map_handle *handle,
 	int err2;
 	unsigned nr_pages;
 
-	printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ",
+	printk(KERN_INFO "PM: Loading image data pages (%u pages)...\n",
 		nr_to_read);
-	m = nr_to_read / 100;
+	m = nr_to_read / 10;
 	if (!m)
 		m = 1;
 	nr_pages = 0;
@@ -993,7 +991,8 @@ static int load_image(struct swap_map_handle *handle,
 		if (ret)
 			break;
 		if (!(nr_pages % m))
-			printk("\b\b\b\b%3d%%", nr_pages / m);
+			printk(KERN_INFO "PM: Image loading progress: %3d%%\n",
+			       nr_pages / m * 10);
 		nr_pages++;
 	}
 	err2 = hib_wait_on_bio_chain(&bio);
@@ -1001,12 +1000,11 @@ static int load_image(struct swap_map_handle *handle,
 	if (!ret)
 		ret = err2;
 	if (!ret) {
-		printk("\b\b\b\bdone\n");
+		printk(KERN_INFO "PM: Image loading done.\n");
 		snapshot_write_finalize(snapshot);
 		if (!snapshot_image_loaded(snapshot))
 			ret = -ENODATA;
-	} else
-		printk("\n");
+	}
 	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
 	return ret;
 }
@@ -1185,9 +1183,9 @@ static int load_image_lzo(struct swap_map_handle *handle,
 
 	printk(KERN_INFO
 		"PM: Using %u thread(s) for decompression.\n"
-		"PM: Loading and decompressing image data (%u pages) ...     ",
+		"PM: Loading and decompressing image data (%u pages)...\n",
 		nr_threads, nr_to_read);
-	m = nr_to_read / 100;
+	m = nr_to_read / 10;
 	if (!m)
 		m = 1;
 	nr_pages = 0;
@@ -1319,7 +1317,10 @@ static int load_image_lzo(struct swap_map_handle *handle,
 				       data[thr].unc + off, PAGE_SIZE);
 
 				if (!(nr_pages % m))
-					printk("\b\b\b\b%3d%%", nr_pages / m);
+					printk(KERN_INFO
+					       "PM: Image loading progress: "
+					       "%3d%%\n",
+					       nr_pages / m * 10);
 				nr_pages++;
 
 				ret = snapshot_write_next(snapshot);
@@ -1344,7 +1345,7 @@ out_finish:
 	}
 	do_gettimeofday(&stop);
 	if (!ret) {
-		printk("\b\b\b\bdone\n");
+		printk(KERN_INFO "PM: Image loading done.\n");
 		snapshot_write_finalize(snapshot);
 		if (!snapshot_image_loaded(snapshot))
 			ret = -ENODATA;
@@ -1357,8 +1358,7 @@ out_finish:
 				}
 			}
 		}
-	} else
-		printk("\n");
+	}
 	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
 out_clean:
 	for (i = 0; i < ring_size; i++)
@@ -1472,6 +1472,34 @@ void swsusp_close(fmode_t mode)
 	blkdev_put(hib_resume_bdev, mode);
 }
 
+/**
+ *      swsusp_unmark - Unmark swsusp signature in the resume device
+ */
+
+#ifdef CONFIG_SUSPEND
+int swsusp_unmark(void)
+{
+	int error;
+
+	hib_bio_read_page(swsusp_resume_block, swsusp_header, NULL);
+	if (!memcmp(HIBERNATE_SIG,swsusp_header->sig, 10)) {
+		memcpy(swsusp_header->sig,swsusp_header->orig_sig, 10);
+		error = hib_bio_write_page(swsusp_resume_block,
+					swsusp_header, NULL);
+	} else {
+		printk(KERN_ERR "PM: Cannot find swsusp signature!\n");
+		error = -ENODEV;
+	}
+
+	/*
+	 * We just returned from suspend, we don't need the image any more.
+	 */
+	free_all_swap_pages(root_swap);
+
+	return error;
+}
+#endif
+
 static int swsusp_header_init(void)
 {
 	swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);
diff --git a/kernel/printk.c b/kernel/printk.c
index a2276b9..2a43e31 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -365,8 +365,10 @@ static ssize_t devkmsg_writev(struct kiocb *iocb, const struct iovec *iv,
 
 	line = buf;
 	for (i = 0; i < count; i++) {
-		if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len))
+		if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len)) {
+			ret = -EFAULT;
 			goto out;
+		}
 		line += iv[i].iov_len;
 	}
 
@@ -862,28 +864,49 @@ static int syslog_print(char __user *buf, int size)
 {
 	char *text;
 	struct log *msg;
-	int len;
+	int len = 0;
 
 	text = kmalloc(LOG_LINE_MAX, GFP_KERNEL);
 	if (!text)
 		return -ENOMEM;
 
-	raw_spin_lock_irq(&logbuf_lock);
-	if (syslog_seq < log_first_seq) {
-		/* messages are gone, move to first one */
-		syslog_seq = log_first_seq;
-		syslog_idx = log_first_idx;
-	}
-	msg = log_from_idx(syslog_idx);
-	len = msg_print_text(msg, true, text, LOG_LINE_MAX);
-	syslog_idx = log_next(syslog_idx);
-	syslog_seq++;
-	raw_spin_unlock_irq(&logbuf_lock);
+	while (size > 0) {
+		size_t n;
+
+		raw_spin_lock_irq(&logbuf_lock);
+		if (syslog_seq < log_first_seq) {
+			/* messages are gone, move to first one */
+			syslog_seq = log_first_seq;
+			syslog_idx = log_first_idx;
+		}
+		if (syslog_seq == log_next_seq) {
+			raw_spin_unlock_irq(&logbuf_lock);
+			break;
+		}
+		msg = log_from_idx(syslog_idx);
+		n = msg_print_text(msg, true, text, LOG_LINE_MAX);
+		if (n <= size) {
+			syslog_idx = log_next(syslog_idx);
+			syslog_seq++;
+		} else
+			n = 0;
+		raw_spin_unlock_irq(&logbuf_lock);
 
-	if (len > size)
-		len = -EINVAL;
-	else if (len > 0 && copy_to_user(buf, text, len))
-		len = -EFAULT;
+		if (!n)
+			break;
+
+		len += n;
+		size -= n;
+		buf += n;
+		n = copy_to_user(buf - n, text, n);
+
+		if (n) {
+			len -= n;
+			if (!len)
+				len = -EFAULT;
+			break;
+		}
+	}
 
 	kfree(text);
 	return len;
@@ -1040,6 +1063,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
 	/* Clear ring buffer */
 	case SYSLOG_ACTION_CLEAR:
 		syslog_print_all(NULL, 0, true);
+		break;
 	/* Disable logging to console */
 	case SYSLOG_ACTION_CONSOLE_OFF:
 		if (saved_console_loglevel == -1)
@@ -1341,17 +1365,23 @@ asmlinkage int vprintk_emit(int facility, int level,
 		newline = true;
 	}
 
-	/* strip syslog prefix and extract log level or control flags */
-	if (text[0] == '<' && text[1] && text[2] == '>') {
-		switch (text[1]) {
-		case '0' ... '7':
-			if (level == -1)
-				level = text[1] - '0';
-		case 'd':	/* KERN_DEFAULT */
-			prefix = true;
-		case 'c':	/* KERN_CONT */
-			text += 3;
-			text_len -= 3;
+	/* strip kernel syslog prefix and extract log level or control flags */
+	if (facility == 0) {
+		int kern_level = printk_get_level(text);
+
+		if (kern_level) {
+			const char *end_of_header = printk_skip_level(text);
+			switch (kern_level) {
+			case '0' ... '7':
+				if (level == -1)
+					level = kern_level - '0';
+			case 'd':	/* KERN_DEFAULT */
+				prefix = true;
+			case 'c':	/* KERN_CONT */
+				break;
+			}
+			text_len -= end_of_header - text;
+			text = (char *)end_of_header;
 		}
 	}
 
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 95cba41..4e6a61b 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -54,6 +54,50 @@
 #ifdef CONFIG_PREEMPT_RCU
 
 /*
+ * Preemptible RCU implementation for rcu_read_lock().
+ * Just increment ->rcu_read_lock_nesting, shared state will be updated
+ * if we block.
+ */
+void __rcu_read_lock(void)
+{
+	current->rcu_read_lock_nesting++;
+	barrier();  /* critical section after entry code. */
+}
+EXPORT_SYMBOL_GPL(__rcu_read_lock);
+
+/*
+ * Preemptible RCU implementation for rcu_read_unlock().
+ * Decrement ->rcu_read_lock_nesting.  If the result is zero (outermost
+ * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then
+ * invoke rcu_read_unlock_special() to clean up after a context switch
+ * in an RCU read-side critical section and other special cases.
+ */
+void __rcu_read_unlock(void)
+{
+	struct task_struct *t = current;
+
+	if (t->rcu_read_lock_nesting != 1) {
+		--t->rcu_read_lock_nesting;
+	} else {
+		barrier();  /* critical section before exit code. */
+		t->rcu_read_lock_nesting = INT_MIN;
+		barrier();  /* assign before ->rcu_read_unlock_special load */
+		if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
+			rcu_read_unlock_special(t);
+		barrier();  /* ->rcu_read_unlock_special load before assign */
+		t->rcu_read_lock_nesting = 0;
+	}
+#ifdef CONFIG_PROVE_LOCKING
+	{
+		int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting);
+
+		WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2);
+	}
+#endif /* #ifdef CONFIG_PROVE_LOCKING */
+}
+EXPORT_SYMBOL_GPL(__rcu_read_unlock);
+
+/*
  * Check for a task exiting while in a preemptible-RCU read-side
  * critical section, clean up if so.  No need to issue warnings,
  * as debug_check_no_locks_held() already does this if lockdep
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index 37a5444..547b1fe 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -172,7 +172,7 @@ void rcu_irq_enter(void)
 	local_irq_restore(flags);
 }
 
-#ifdef CONFIG_PROVE_RCU
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
 
 /*
  * Test whether RCU thinks that the current CPU is idle.
@@ -183,7 +183,7 @@ int rcu_is_cpu_idle(void)
 }
 EXPORT_SYMBOL(rcu_is_cpu_idle);
 
-#endif /* #ifdef CONFIG_PROVE_RCU */
+#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
 
 /*
  * Test whether the current CPU was interrupted from idle.  Nested
diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h
index fc31a2d..116725b 100644
--- a/kernel/rcutiny_plugin.h
+++ b/kernel/rcutiny_plugin.h
@@ -132,7 +132,6 @@ static struct rcu_preempt_ctrlblk rcu_preempt_ctrlblk = {
 	RCU_TRACE(.rcb.name = "rcu_preempt")
 };
 
-static void rcu_read_unlock_special(struct task_struct *t);
 static int rcu_preempted_readers_exp(void);
 static void rcu_report_exp_done(void);
 
@@ -527,23 +526,11 @@ void rcu_preempt_note_context_switch(void)
 }
 
 /*
- * Tiny-preemptible RCU implementation for rcu_read_lock().
- * Just increment ->rcu_read_lock_nesting, shared state will be updated
- * if we block.
- */
-void __rcu_read_lock(void)
-{
-	current->rcu_read_lock_nesting++;
-	barrier();  /* needed if we ever invoke rcu_read_lock in rcutiny.c */
-}
-EXPORT_SYMBOL_GPL(__rcu_read_lock);
-
-/*
  * Handle special cases during rcu_read_unlock(), such as needing to
  * notify RCU core processing or task having blocked during the RCU
  * read-side critical section.
  */
-static noinline void rcu_read_unlock_special(struct task_struct *t)
+void rcu_read_unlock_special(struct task_struct *t)
 {
 	int empty;
 	int empty_exp;
@@ -627,38 +614,6 @@ static noinline void rcu_read_unlock_special(struct task_struct *t)
 }
 
 /*
- * Tiny-preemptible RCU implementation for rcu_read_unlock().
- * Decrement ->rcu_read_lock_nesting.  If the result is zero (outermost
- * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then
- * invoke rcu_read_unlock_special() to clean up after a context switch
- * in an RCU read-side critical section and other special cases.
- */
-void __rcu_read_unlock(void)
-{
-	struct task_struct *t = current;
-
-	barrier();  /* needed if we ever invoke rcu_read_unlock in rcutiny.c */
-	if (t->rcu_read_lock_nesting != 1)
-		--t->rcu_read_lock_nesting;
-	else {
-		t->rcu_read_lock_nesting = INT_MIN;
-		barrier();  /* assign before ->rcu_read_unlock_special load */
-		if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
-			rcu_read_unlock_special(t);
-		barrier();  /* ->rcu_read_unlock_special load before assign */
-		t->rcu_read_lock_nesting = 0;
-	}
-#ifdef CONFIG_PROVE_LOCKING
-	{
-		int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting);
-
-		WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2);
-	}
-#endif /* #ifdef CONFIG_PROVE_LOCKING */
-}
-EXPORT_SYMBOL_GPL(__rcu_read_unlock);
-
-/*
  * Check for a quiescent state from the current CPU.  When a task blocks,
  * the task is recorded in the rcu_preempt_ctrlblk structure, which is
  * checked elsewhere.  This is called from the scheduling-clock interrupt.
@@ -846,8 +801,6 @@ EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
  */
 int rcu_preempt_needs_cpu(void)
 {
-	if (!rcu_preempt_running_reader())
-		rcu_preempt_cpu_qs();
 	return rcu_preempt_ctrlblk.rcb.rcucblist != NULL;
 }
 
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index e66b34a..c279ee9 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -206,6 +206,7 @@ static unsigned long boost_starttime;	/* jiffies of next boost test start. */
 DEFINE_MUTEX(boost_mutex);		/* protect setting boost_starttime */
 					/*  and boost task create/destroy. */
 static atomic_t barrier_cbs_count;	/* Barrier callbacks registered. */
+static bool barrier_phase;		/* Test phase. */
 static atomic_t barrier_cbs_invoked;	/* Barrier callbacks invoked. */
 static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */
 static DECLARE_WAIT_QUEUE_HEAD(barrier_wq);
@@ -635,6 +636,17 @@ static void srcu_torture_synchronize(void)
 	synchronize_srcu(&srcu_ctl);
 }
 
+static void srcu_torture_call(struct rcu_head *head,
+			      void (*func)(struct rcu_head *head))
+{
+	call_srcu(&srcu_ctl, head, func);
+}
+
+static void srcu_torture_barrier(void)
+{
+	srcu_barrier(&srcu_ctl);
+}
+
 static int srcu_torture_stats(char *page)
 {
 	int cnt = 0;
@@ -661,8 +673,8 @@ static struct rcu_torture_ops srcu_ops = {
 	.completed	= srcu_torture_completed,
 	.deferred_free	= srcu_torture_deferred_free,
 	.sync		= srcu_torture_synchronize,
-	.call		= NULL,
-	.cb_barrier	= NULL,
+	.call		= srcu_torture_call,
+	.cb_barrier	= srcu_torture_barrier,
 	.stats		= srcu_torture_stats,
 	.name		= "srcu"
 };
@@ -1013,7 +1025,11 @@ rcu_torture_fakewriter(void *arg)
 	do {
 		schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
 		udelay(rcu_random(&rand) & 0x3ff);
-		cur_ops->sync();
+		if (cur_ops->cb_barrier != NULL &&
+		    rcu_random(&rand) % (nfakewriters * 8) == 0)
+			cur_ops->cb_barrier();
+		else
+			cur_ops->sync();
 		rcu_stutter_wait("rcu_torture_fakewriter");
 	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
 
@@ -1631,6 +1647,7 @@ void rcu_torture_barrier_cbf(struct rcu_head *rcu)
 static int rcu_torture_barrier_cbs(void *arg)
 {
 	long myid = (long)arg;
+	bool lastphase = 0;
 	struct rcu_head rcu;
 
 	init_rcu_head_on_stack(&rcu);
@@ -1638,9 +1655,11 @@ static int rcu_torture_barrier_cbs(void *arg)
 	set_user_nice(current, 19);
 	do {
 		wait_event(barrier_cbs_wq[myid],
-			   atomic_read(&barrier_cbs_count) == n_barrier_cbs ||
+			   barrier_phase != lastphase ||
 			   kthread_should_stop() ||
 			   fullstop != FULLSTOP_DONTSTOP);
+		lastphase = barrier_phase;
+		smp_mb(); /* ensure barrier_phase load before ->call(). */
 		if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP)
 			break;
 		cur_ops->call(&rcu, rcu_torture_barrier_cbf);
@@ -1665,7 +1684,8 @@ static int rcu_torture_barrier(void *arg)
 	do {
 		atomic_set(&barrier_cbs_invoked, 0);
 		atomic_set(&barrier_cbs_count, n_barrier_cbs);
-		/* wake_up() path contains the required barriers. */
+		smp_mb(); /* Ensure barrier_phase after prior assignments. */
+		barrier_phase = !barrier_phase;
 		for (i = 0; i < n_barrier_cbs; i++)
 			wake_up(&barrier_cbs_wq[i]);
 		wait_event(barrier_wq,
@@ -1684,7 +1704,7 @@ static int rcu_torture_barrier(void *arg)
 		schedule_timeout_interruptible(HZ / 10);
 	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
 	VERBOSE_PRINTK_STRING("rcu_torture_barrier task stopping");
-	rcutorture_shutdown_absorb("rcu_torture_barrier_cbs");
+	rcutorture_shutdown_absorb("rcu_torture_barrier");
 	while (!kthread_should_stop())
 		schedule_timeout_interruptible(1);
 	return 0;
@@ -1908,8 +1928,8 @@ rcu_torture_init(void)
 	static struct rcu_torture_ops *torture_ops[] =
 		{ &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops,
 		  &rcu_bh_ops, &rcu_bh_sync_ops, &rcu_bh_expedited_ops,
-		  &srcu_ops, &srcu_sync_ops, &srcu_raw_ops,
-		  &srcu_raw_sync_ops, &srcu_expedited_ops,
+		  &srcu_ops, &srcu_sync_ops, &srcu_expedited_ops,
+		  &srcu_raw_ops, &srcu_raw_sync_ops,
 		  &sched_ops, &sched_sync_ops, &sched_expedited_ops, };
 
 	mutex_lock(&fullstop_mutex);
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 3b0f133..eb39bd6 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -60,36 +60,44 @@
 
 /* Data structures. */
 
-static struct lock_class_key rcu_node_class[NUM_RCU_LVLS];
-
-#define RCU_STATE_INITIALIZER(structname) { \
-	.level = { &structname##_state.node[0] }, \
-	.levelcnt = { \
-		NUM_RCU_LVL_0,  /* root of hierarchy. */ \
-		NUM_RCU_LVL_1, \
-		NUM_RCU_LVL_2, \
-		NUM_RCU_LVL_3, \
-		NUM_RCU_LVL_4, /* == MAX_RCU_LVLS */ \
-	}, \
+static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
+
+#define RCU_STATE_INITIALIZER(sname, cr) { \
+	.level = { &sname##_state.node[0] }, \
+	.call = cr, \
 	.fqs_state = RCU_GP_IDLE, \
 	.gpnum = -300, \
 	.completed = -300, \
-	.onofflock = __RAW_SPIN_LOCK_UNLOCKED(&structname##_state.onofflock), \
-	.orphan_nxttail = &structname##_state.orphan_nxtlist, \
-	.orphan_donetail = &structname##_state.orphan_donelist, \
-	.fqslock = __RAW_SPIN_LOCK_UNLOCKED(&structname##_state.fqslock), \
-	.n_force_qs = 0, \
-	.n_force_qs_ngp = 0, \
-	.name = #structname, \
+	.onofflock = __RAW_SPIN_LOCK_UNLOCKED(&sname##_state.onofflock), \
+	.orphan_nxttail = &sname##_state.orphan_nxtlist, \
+	.orphan_donetail = &sname##_state.orphan_donelist, \
+	.barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \
+	.fqslock = __RAW_SPIN_LOCK_UNLOCKED(&sname##_state.fqslock), \
+	.name = #sname, \
 }
 
-struct rcu_state rcu_sched_state = RCU_STATE_INITIALIZER(rcu_sched);
+struct rcu_state rcu_sched_state =
+	RCU_STATE_INITIALIZER(rcu_sched, call_rcu_sched);
 DEFINE_PER_CPU(struct rcu_data, rcu_sched_data);
 
-struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh);
+struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh, call_rcu_bh);
 DEFINE_PER_CPU(struct rcu_data, rcu_bh_data);
 
 static struct rcu_state *rcu_state;
+LIST_HEAD(rcu_struct_flavors);
+
+/* Increase (but not decrease) the CONFIG_RCU_FANOUT_LEAF at boot time. */
+static int rcu_fanout_leaf = CONFIG_RCU_FANOUT_LEAF;
+module_param(rcu_fanout_leaf, int, 0);
+int rcu_num_lvls __read_mostly = RCU_NUM_LVLS;
+static int num_rcu_lvl[] = {  /* Number of rcu_nodes at specified level. */
+	NUM_RCU_LVL_0,
+	NUM_RCU_LVL_1,
+	NUM_RCU_LVL_2,
+	NUM_RCU_LVL_3,
+	NUM_RCU_LVL_4,
+};
+int rcu_num_nodes __read_mostly = NUM_RCU_NODES; /* Total # rcu_nodes in use. */
 
 /*
  * The rcu_scheduler_active variable transitions from zero to one just
@@ -147,13 +155,6 @@ static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp);
 unsigned long rcutorture_testseq;
 unsigned long rcutorture_vernum;
 
-/* State information for rcu_barrier() and friends. */
-
-static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL};
-static atomic_t rcu_barrier_cpu_count;
-static DEFINE_MUTEX(rcu_barrier_mutex);
-static struct completion rcu_barrier_completion;
-
 /*
  * Return true if an RCU grace period is in progress.  The ACCESS_ONCE()s
  * permit this function to be invoked without holding the root rcu_node
@@ -224,7 +225,8 @@ int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT;
 module_param(rcu_cpu_stall_suppress, int, 0644);
 module_param(rcu_cpu_stall_timeout, int, 0644);
 
-static void force_quiescent_state(struct rcu_state *rsp, int relaxed);
+static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *));
+static void force_quiescent_state(struct rcu_state *rsp);
 static int rcu_pending(int cpu);
 
 /*
@@ -250,7 +252,7 @@ EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
  */
 void rcu_bh_force_quiescent_state(void)
 {
-	force_quiescent_state(&rcu_bh_state, 0);
+	force_quiescent_state(&rcu_bh_state);
 }
 EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state);
 
@@ -284,7 +286,7 @@ EXPORT_SYMBOL_GPL(rcutorture_record_progress);
  */
 void rcu_sched_force_quiescent_state(void)
 {
-	force_quiescent_state(&rcu_sched_state, 0);
+	force_quiescent_state(&rcu_sched_state);
 }
 EXPORT_SYMBOL_GPL(rcu_sched_force_quiescent_state);
 
@@ -357,7 +359,7 @@ static void rcu_idle_enter_common(struct rcu_dynticks *rdtp, long long oldval)
 		struct task_struct *idle = idle_task(smp_processor_id());
 
 		trace_rcu_dyntick("Error on entry: not idle task", oldval, 0);
-		ftrace_dump(DUMP_ALL);
+		ftrace_dump(DUMP_ORIG);
 		WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s",
 			  current->pid, current->comm,
 			  idle->pid, idle->comm); /* must be idle task! */
@@ -467,7 +469,7 @@ static void rcu_idle_exit_common(struct rcu_dynticks *rdtp, long long oldval)
 
 		trace_rcu_dyntick("Error on exit: not idle task",
 				  oldval, rdtp->dynticks_nesting);
-		ftrace_dump(DUMP_ALL);
+		ftrace_dump(DUMP_ORIG);
 		WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s",
 			  current->pid, current->comm,
 			  idle->pid, idle->comm); /* must be idle task! */
@@ -584,8 +586,6 @@ void rcu_nmi_exit(void)
 	WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1);
 }
 
-#ifdef CONFIG_PROVE_RCU
-
 /**
  * rcu_is_cpu_idle - see if RCU thinks that the current CPU is idle
  *
@@ -603,7 +603,7 @@ int rcu_is_cpu_idle(void)
 }
 EXPORT_SYMBOL(rcu_is_cpu_idle);
 
-#ifdef CONFIG_HOTPLUG_CPU
+#if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU)
 
 /*
  * Is the current CPU online?  Disable preemption to avoid false positives
@@ -644,9 +644,7 @@ bool rcu_lockdep_current_cpu_online(void)
 }
 EXPORT_SYMBOL_GPL(rcu_lockdep_current_cpu_online);
 
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
-
-#endif /* #ifdef CONFIG_PROVE_RCU */
+#endif /* #if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU) */
 
 /**
  * rcu_is_cpu_rrupt_from_idle - see if idle or immediately interrupted from idle
@@ -732,7 +730,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
 	int cpu;
 	long delta;
 	unsigned long flags;
-	int ndetected;
+	int ndetected = 0;
 	struct rcu_node *rnp = rcu_get_root(rsp);
 
 	/* Only let one CPU complain about others per time interval. */
@@ -773,7 +771,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
 	 */
 	rnp = rcu_get_root(rsp);
 	raw_spin_lock_irqsave(&rnp->lock, flags);
-	ndetected = rcu_print_task_stall(rnp);
+	ndetected += rcu_print_task_stall(rnp);
 	raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
 	print_cpu_stall_info_end();
@@ -784,11 +782,11 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
 	else if (!trigger_all_cpu_backtrace())
 		dump_stack();
 
-	/* If so configured, complain about tasks blocking the grace period. */
+	/* Complain about tasks blocking the grace period. */
 
 	rcu_print_detail_task_stall(rsp);
 
-	force_quiescent_state(rsp, 0);  /* Kick them all. */
+	force_quiescent_state(rsp);  /* Kick them all. */
 }
 
 static void print_cpu_stall(struct rcu_state *rsp)
@@ -859,9 +857,10 @@ static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr)
  */
 void rcu_cpu_stall_reset(void)
 {
-	rcu_sched_state.jiffies_stall = jiffies + ULONG_MAX / 2;
-	rcu_bh_state.jiffies_stall = jiffies + ULONG_MAX / 2;
-	rcu_preempt_stall_reset();
+	struct rcu_state *rsp;
+
+	for_each_rcu_flavor(rsp)
+		rsp->jiffies_stall = jiffies + ULONG_MAX / 2;
 }
 
 static struct notifier_block rcu_panic_block = {
@@ -936,6 +935,18 @@ check_for_new_grace_period(struct rcu_state *rsp, struct rcu_data *rdp)
 }
 
 /*
+ * Initialize the specified rcu_data structure's callback list to empty.
+ */
+static void init_callback_list(struct rcu_data *rdp)
+{
+	int i;
+
+	rdp->nxtlist = NULL;
+	for (i = 0; i < RCU_NEXT_SIZE; i++)
+		rdp->nxttail[i] = &rdp->nxtlist;
+}
+
+/*
  * Advance this CPU's callbacks, but only if the current grace period
  * has ended.  This may be called only from the CPU to whom the rdp
  * belongs.  In addition, the corresponding leaf rcu_node structure's
@@ -1028,75 +1039,48 @@ rcu_start_gp_per_cpu(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_dat
 }
 
 /*
- * Start a new RCU grace period if warranted, re-initializing the hierarchy
- * in preparation for detecting the next grace period.  The caller must hold
- * the root node's ->lock, which is released before return.  Hard irqs must
- * be disabled.
- *
- * Note that it is legal for a dying CPU (which is marked as offline) to
- * invoke this function.  This can happen when the dying CPU reports its
- * quiescent state.
+ * Initialize a new grace period.
  */
-static void
-rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
-	__releases(rcu_get_root(rsp)->lock)
+static int rcu_gp_init(struct rcu_state *rsp)
 {
-	struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
+	unsigned long flags;
+	struct rcu_data *rdp;
 	struct rcu_node *rnp = rcu_get_root(rsp);
 
-	if (!rcu_scheduler_fully_active ||
-	    !cpu_needs_another_gp(rsp, rdp)) {
-		/*
-		 * Either the scheduler hasn't yet spawned the first
-		 * non-idle task or this CPU does not need another
-		 * grace period.  Either way, don't start a new grace
-		 * period.
-		 */
-		raw_spin_unlock_irqrestore(&rnp->lock, flags);
-		return;
-	}
+	raw_spin_lock_irqsave(&rnp->lock, flags);
+	rsp->gp_flags = 0; /* Clear all flags: New grace period. */
 
-	if (rsp->fqs_active) {
-		/*
-		 * This CPU needs a grace period, but force_quiescent_state()
-		 * is running.  Tell it to start one on this CPU's behalf.
-		 */
-		rsp->fqs_need_gp = 1;
+	if (rcu_gp_in_progress(rsp)) {
+		/* Grace period already in progress, don't start another. */
 		raw_spin_unlock_irqrestore(&rnp->lock, flags);
-		return;
+		return 0;
 	}
 
 	/* Advance to a new grace period and initialize state. */
 	rsp->gpnum++;
 	trace_rcu_grace_period(rsp->name, rsp->gpnum, "start");
-	WARN_ON_ONCE(rsp->fqs_state == RCU_GP_INIT);
-	rsp->fqs_state = RCU_GP_INIT; /* Hold off force_quiescent_state. */
-	rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS;
 	record_gp_stall_check_time(rsp);
-	raw_spin_unlock(&rnp->lock);  /* leave irqs disabled. */
+	raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
 	/* Exclude any concurrent CPU-hotplug operations. */
-	raw_spin_lock(&rsp->onofflock);  /* irqs already disabled. */
+	get_online_cpus();
 
 	/*
 	 * Set the quiescent-state-needed bits in all the rcu_node
-	 * structures for all currently online CPUs in breadth-first
-	 * order, starting from the root rcu_node structure.  This
-	 * operation relies on the layout of the hierarchy within the
-	 * rsp->node[] array.  Note that other CPUs will access only
-	 * the leaves of the hierarchy, which still indicate that no
+	 * structures for all currently online CPUs in breadth-first order,
+	 * starting from the root rcu_node structure, relying on the layout
+	 * of the tree within the rsp->node[] array.  Note that other CPUs
+	 * access only the leaves of the hierarchy, thus seeing that no
 	 * grace period is in progress, at least until the corresponding
 	 * leaf node has been initialized.  In addition, we have excluded
 	 * CPU-hotplug operations.
 	 *
-	 * Note that the grace period cannot complete until we finish
-	 * the initialization process, as there will be at least one
-	 * qsmask bit set in the root node until that time, namely the
-	 * one corresponding to this CPU, due to the fact that we have
-	 * irqs disabled.
+	 * The grace period cannot complete until the initialization
+	 * process finishes, because this kthread handles both.
 	 */
 	rcu_for_each_node_breadth_first(rsp, rnp) {
-		raw_spin_lock(&rnp->lock);	/* irqs already disabled. */
+		raw_spin_lock_irqsave(&rnp->lock, flags);
+		rdp = this_cpu_ptr(rsp->rda);
 		rcu_preempt_check_blocked_tasks(rnp);
 		rnp->qsmask = rnp->qsmaskinit;
 		rnp->gpnum = rsp->gpnum;
@@ -1107,37 +1091,52 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
 		trace_rcu_grace_period_init(rsp->name, rnp->gpnum,
 					    rnp->level, rnp->grplo,
 					    rnp->grphi, rnp->qsmask);
-		raw_spin_unlock(&rnp->lock);	/* irqs remain disabled. */
+		raw_spin_unlock_irqrestore(&rnp->lock, flags);
+		cond_resched();
 	}
 
-	rnp = rcu_get_root(rsp);
-	raw_spin_lock(&rnp->lock);		/* irqs already disabled. */
-	rsp->fqs_state = RCU_SIGNAL_INIT; /* force_quiescent_state now OK. */
-	raw_spin_unlock(&rnp->lock);		/* irqs remain disabled. */
-	raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
+	put_online_cpus();
+	return 1;
 }
 
 /*
- * Report a full set of quiescent states to the specified rcu_state
- * data structure.  This involves cleaning up after the prior grace
- * period and letting rcu_start_gp() start up the next grace period
- * if one is needed.  Note that the caller must hold rnp->lock, as
- * required by rcu_start_gp(), which will release it.
+ * Do one round of quiescent-state forcing.
  */
-static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
-	__releases(rcu_get_root(rsp)->lock)
+int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)
 {
-	unsigned long gp_duration;
+	unsigned long flags;
+	int fqs_state = fqs_state_in;
 	struct rcu_node *rnp = rcu_get_root(rsp);
-	struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
 
-	WARN_ON_ONCE(!rcu_gp_in_progress(rsp));
+	rsp->n_force_qs++;
+	if (fqs_state == RCU_SAVE_DYNTICK) {
+		/* Collect dyntick-idle snapshots. */
+		force_qs_rnp(rsp, dyntick_save_progress_counter);
+		fqs_state = RCU_FORCE_QS;
+	} else {
+		/* Handle dyntick-idle and offline CPUs. */
+		force_qs_rnp(rsp, rcu_implicit_dynticks_qs);
+	}
+	/* Clear flag to prevent immediate re-entry. */
+	if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
+		raw_spin_lock_irqsave(&rnp->lock, flags);
+		rsp->gp_flags &= ~RCU_GP_FLAG_FQS;
+		raw_spin_unlock_irqrestore(&rnp->lock, flags);
+	}
+	return fqs_state;
+}
 
-	/*
-	 * Ensure that all grace-period and pre-grace-period activity
-	 * is seen before the assignment to rsp->completed.
-	 */
-	smp_mb(); /* See above block comment. */
+/*
+ * Clean up after the old grace period.
+ */
+static void rcu_gp_cleanup(struct rcu_state *rsp)
+{
+	unsigned long flags;
+	unsigned long gp_duration;
+	struct rcu_data *rdp;
+	struct rcu_node *rnp = rcu_get_root(rsp);
+
+	raw_spin_lock_irqsave(&rnp->lock, flags);
 	gp_duration = jiffies - rsp->gp_start;
 	if (gp_duration > rsp->gp_max)
 		rsp->gp_max = gp_duration;
@@ -1157,27 +1156,134 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
 	 * callbacks are waiting on the grace period that just now
 	 * completed.
 	 */
+	rdp = this_cpu_ptr(rsp->rda);
 	if (*rdp->nxttail[RCU_WAIT_TAIL] == NULL) {
-		raw_spin_unlock(&rnp->lock);	 /* irqs remain disabled. */
+		raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
 		/*
-		 * Propagate new ->completed value to rcu_node structures
-		 * so that other CPUs don't have to wait until the start
-		 * of the next grace period to process their callbacks.
+		 * Propagate new ->completed value to rcu_node
+		 * structures so that other CPUs don't have to
+		 * wait until the start of the next grace period
+		 * to process their callbacks.
 		 */
 		rcu_for_each_node_breadth_first(rsp, rnp) {
-			raw_spin_lock(&rnp->lock); /* irqs already disabled. */
+			raw_spin_lock_irqsave(&rnp->lock, flags);
 			rnp->completed = rsp->gpnum;
-			raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
+			raw_spin_unlock_irqrestore(&rnp->lock, flags);
+			cond_resched();
 		}
 		rnp = rcu_get_root(rsp);
-		raw_spin_lock(&rnp->lock); /* irqs already disabled. */
+		raw_spin_lock_irqsave(&rnp->lock, flags);
 	}
 
-	rsp->completed = rsp->gpnum;  /* Declare the grace period complete. */
+	rsp->completed = rsp->gpnum; /* Declare grace period done. */
 	trace_rcu_grace_period(rsp->name, rsp->completed, "end");
 	rsp->fqs_state = RCU_GP_IDLE;
-	rcu_start_gp(rsp, flags);  /* releases root node's rnp->lock. */
+	rdp = this_cpu_ptr(rsp->rda);
+	if (cpu_needs_another_gp(rsp, rdp))
+		rsp->gp_flags = 1;
+	raw_spin_unlock_irqrestore(&rnp->lock, flags);
+}
+
+/*
+ * Body of kthread that handles grace periods.
+ */
+static int rcu_gp_kthread(void *arg)
+{
+	int fqs_state;
+	int ret;
+	struct rcu_state *rsp = arg;
+	struct rcu_node *rnp = rcu_get_root(rsp);
+
+	for (;;) {
+
+		/* Handle grace-period start. */
+		for (;;) {
+			wait_event_interruptible(rsp->gp_wq,
+						 rsp->gp_flags &
+						 RCU_GP_FLAG_INIT);
+			if ((rsp->gp_flags & RCU_GP_FLAG_INIT) &&
+			    rcu_gp_init(rsp))
+				break;
+			cond_resched();
+			flush_signals(current);
+		}
+
+		/* Handle quiescent-state forcing. */
+		fqs_state = RCU_SAVE_DYNTICK;
+		for (;;) {
+			ret = wait_event_interruptible_timeout(rsp->gp_wq,
+					(rsp->gp_flags & RCU_GP_FLAG_FQS) ||
+					(!ACCESS_ONCE(rnp->qsmask) &&
+					 !rcu_preempt_blocked_readers_cgp(rnp)),
+					RCU_JIFFIES_TILL_FORCE_QS);
+			/* If grace period done, leave loop. */
+			if (!ACCESS_ONCE(rnp->qsmask) &&
+			    !rcu_preempt_blocked_readers_cgp(rnp))
+				break;
+			/* If time for quiescent-state forcing, do it. */
+			if (ret == 0 || (rsp->gp_flags & RCU_GP_FLAG_FQS)) {
+				fqs_state = rcu_gp_fqs(rsp, fqs_state);
+				cond_resched();
+			} else {
+				/* Deal with stray signal. */
+				cond_resched();
+				flush_signals(current);
+			}
+		}
+
+		/* Handle grace-period end. */
+		rcu_gp_cleanup(rsp);
+	}
+	return 0;
+}
+
+/*
+ * Start a new RCU grace period if warranted, re-initializing the hierarchy
+ * in preparation for detecting the next grace period.  The caller must hold
+ * the root node's ->lock, which is released before return.  Hard irqs must
+ * be disabled.
+ *
+ * Note that it is legal for a dying CPU (which is marked as offline) to
+ * invoke this function.  This can happen when the dying CPU reports its
+ * quiescent state.
+ */
+static void
+rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
+	__releases(rcu_get_root(rsp)->lock)
+{
+	struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
+	struct rcu_node *rnp = rcu_get_root(rsp);
+
+	if (!rsp->gp_kthread ||
+	    !cpu_needs_another_gp(rsp, rdp)) {
+		/*
+		 * Either we have not yet spawned the grace-period
+		 * task or this CPU does not need another grace period.
+		 * Either way, don't start a new grace period.
+		 */
+		raw_spin_unlock_irqrestore(&rnp->lock, flags);
+		return;
+	}
+
+	rsp->gp_flags = 1;
+	raw_spin_unlock_irqrestore(&rnp->lock, flags);
+	wake_up(&rsp->gp_wq);
+}
+
+/*
+ * Report a full set of quiescent states to the specified rcu_state
+ * data structure.  This involves cleaning up after the prior grace
+ * period and letting rcu_start_gp() start up the next grace period
+ * if one is needed.  Note that the caller must hold rnp->lock, as
+ * required by rcu_start_gp(), which will release it.
+ */
+static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
+	__releases(rcu_get_root(rsp)->lock)
+{
+	WARN_ON_ONCE(!rcu_gp_in_progress(rsp));
+	raw_spin_unlock_irqrestore(&rcu_get_root(rsp)->lock, flags);
+	wake_up(&rsp->gp_wq);  /* Memory barrier implied by wake_up() path. */
 }
 
 /*
@@ -1327,8 +1433,6 @@ static void
 rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp,
 			  struct rcu_node *rnp, struct rcu_data *rdp)
 {
-	int i;
-
 	/*
 	 * Orphan the callbacks.  First adjust the counts.  This is safe
 	 * because ->onofflock excludes _rcu_barrier()'s adoption of
@@ -1339,7 +1443,7 @@ rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp,
 		rsp->qlen += rdp->qlen;
 		rdp->n_cbs_orphaned += rdp->qlen;
 		rdp->qlen_lazy = 0;
-		rdp->qlen = 0;
+		ACCESS_ONCE(rdp->qlen) = 0;
 	}
 
 	/*
@@ -1368,9 +1472,7 @@ rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp,
 	}
 
 	/* Finally, initialize the rcu_data structure's list to empty.  */
-	rdp->nxtlist = NULL;
-	for (i = 0; i < RCU_NEXT_SIZE; i++)
-		rdp->nxttail[i] = &rdp->nxtlist;
+	init_callback_list(rdp);
 }
 
 /*
@@ -1504,6 +1606,9 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)
 		raw_spin_unlock_irqrestore(&rnp->lock, flags);
 	if (need_report & RCU_OFL_TASKS_EXP_GP)
 		rcu_report_exp_rnp(rsp, rnp, true);
+	WARN_ONCE(rdp->qlen != 0 || rdp->nxtlist != NULL,
+		  "rcu_cleanup_dead_cpu: Callbacks on offline CPU %d: qlen=%lu, nxtlist=%p\n",
+		  cpu, rdp->qlen, rdp->nxtlist);
 }
 
 #else /* #ifdef CONFIG_HOTPLUG_CPU */
@@ -1530,7 +1635,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
 {
 	unsigned long flags;
 	struct rcu_head *next, *list, **tail;
-	int bl, count, count_lazy;
+	int bl, count, count_lazy, i;
 
 	/* If no callbacks are ready, just return.*/
 	if (!cpu_has_callbacks_ready_to_invoke(rdp)) {
@@ -1553,9 +1658,9 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
 	rdp->nxtlist = *rdp->nxttail[RCU_DONE_TAIL];
 	*rdp->nxttail[RCU_DONE_TAIL] = NULL;
 	tail = rdp->nxttail[RCU_DONE_TAIL];
-	for (count = RCU_NEXT_SIZE - 1; count >= 0; count--)
-		if (rdp->nxttail[count] == rdp->nxttail[RCU_DONE_TAIL])
-			rdp->nxttail[count] = &rdp->nxtlist;
+	for (i = RCU_NEXT_SIZE - 1; i >= 0; i--)
+		if (rdp->nxttail[i] == rdp->nxttail[RCU_DONE_TAIL])
+			rdp->nxttail[i] = &rdp->nxtlist;
 	local_irq_restore(flags);
 
 	/* Invoke callbacks. */
@@ -1583,15 +1688,15 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
 	if (list != NULL) {
 		*tail = rdp->nxtlist;
 		rdp->nxtlist = list;
-		for (count = 0; count < RCU_NEXT_SIZE; count++)
-			if (&rdp->nxtlist == rdp->nxttail[count])
-				rdp->nxttail[count] = tail;
+		for (i = 0; i < RCU_NEXT_SIZE; i++)
+			if (&rdp->nxtlist == rdp->nxttail[i])
+				rdp->nxttail[i] = tail;
 			else
 				break;
 	}
 	smp_mb(); /* List handling before counting for rcu_barrier(). */
 	rdp->qlen_lazy -= count_lazy;
-	rdp->qlen -= count;
+	ACCESS_ONCE(rdp->qlen) -= count;
 	rdp->n_cbs_invoked += count;
 
 	/* Reinstate batch limit if we have worked down the excess. */
@@ -1604,6 +1709,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
 		rdp->n_force_qs_snap = rsp->n_force_qs;
 	} else if (rdp->qlen < rdp->qlen_last_fqs_check - qhimark)
 		rdp->qlen_last_fqs_check = rdp->qlen;
+	WARN_ON_ONCE((rdp->nxtlist == NULL) != (rdp->qlen == 0));
 
 	local_irq_restore(flags);
 
@@ -1675,6 +1781,7 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *))
 	struct rcu_node *rnp;
 
 	rcu_for_each_leaf_node(rsp, rnp) {
+		cond_resched();
 		mask = 0;
 		raw_spin_lock_irqsave(&rnp->lock, flags);
 		if (!rcu_gp_in_progress(rsp)) {
@@ -1711,74 +1818,18 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *))
  * Force quiescent states on reluctant CPUs, and also detect which
  * CPUs are in dyntick-idle mode.
  */
-static void force_quiescent_state(struct rcu_state *rsp, int relaxed)
+static void force_quiescent_state(struct rcu_state *rsp)
 {
 	unsigned long flags;
 	struct rcu_node *rnp = rcu_get_root(rsp);
 
-	trace_rcu_utilization("Start fqs");
-	if (!rcu_gp_in_progress(rsp)) {
-		trace_rcu_utilization("End fqs");
-		return;  /* No grace period in progress, nothing to force. */
-	}
-	if (!raw_spin_trylock_irqsave(&rsp->fqslock, flags)) {
-		rsp->n_force_qs_lh++; /* Inexact, can lose counts.  Tough! */
-		trace_rcu_utilization("End fqs");
-		return;	/* Someone else is already on the job. */
-	}
-	if (relaxed && ULONG_CMP_GE(rsp->jiffies_force_qs, jiffies))
-		goto unlock_fqs_ret; /* no emergency and done recently. */
-	rsp->n_force_qs++;
-	raw_spin_lock(&rnp->lock);  /* irqs already disabled */
-	rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS;
-	if(!rcu_gp_in_progress(rsp)) {
-		rsp->n_force_qs_ngp++;
-		raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-		goto unlock_fqs_ret;  /* no GP in progress, time updated. */
-	}
-	rsp->fqs_active = 1;
-	switch (rsp->fqs_state) {
-	case RCU_GP_IDLE:
-	case RCU_GP_INIT:
-
-		break; /* grace period idle or initializing, ignore. */
-
-	case RCU_SAVE_DYNTICK:
-		if (RCU_SIGNAL_INIT != RCU_SAVE_DYNTICK)
-			break; /* So gcc recognizes the dead code. */
-
-		raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-
-		/* Record dyntick-idle state. */
-		force_qs_rnp(rsp, dyntick_save_progress_counter);
-		raw_spin_lock(&rnp->lock);  /* irqs already disabled */
-		if (rcu_gp_in_progress(rsp))
-			rsp->fqs_state = RCU_FORCE_QS;
-		break;
-
-	case RCU_FORCE_QS:
-
-		/* Check dyntick-idle state, send IPI to laggarts. */
-		raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-		force_qs_rnp(rsp, rcu_implicit_dynticks_qs);
-
-		/* Leave state in case more forcing is required. */
-
-		raw_spin_lock(&rnp->lock);  /* irqs already disabled */
-		break;
-	}
-	rsp->fqs_active = 0;
-	if (rsp->fqs_need_gp) {
-		raw_spin_unlock(&rsp->fqslock); /* irqs remain disabled */
-		rsp->fqs_need_gp = 0;
-		rcu_start_gp(rsp, flags); /* releases rnp->lock */
-		trace_rcu_utilization("End fqs");
+	if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS)
+		return;  /* Someone beat us to it. */
+	if (!raw_spin_trylock_irqsave(&rnp->lock, flags))
 		return;
-	}
-	raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-unlock_fqs_ret:
-	raw_spin_unlock_irqrestore(&rsp->fqslock, flags);
-	trace_rcu_utilization("End fqs");
+	rsp->gp_flags |= RCU_GP_FLAG_FQS;
+	raw_spin_unlock_irqrestore(&rnp->lock, flags);
+	wake_up(&rsp->gp_wq);  /* Memory barrier implied by wake_up() path. */
 }
 
 /*
@@ -1787,20 +1838,14 @@ unlock_fqs_ret:
  * whom the rdp belongs.
  */
 static void
-__rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
+__rcu_process_callbacks(struct rcu_state *rsp)
 {
 	unsigned long flags;
+	struct rcu_data *rdp = __this_cpu_ptr(rsp->rda);
 
 	WARN_ON_ONCE(rdp->beenonline == 0);
 
 	/*
-	 * If an RCU GP has gone long enough, go check for dyntick
-	 * idle CPUs and, if needed, send resched IPIs.
-	 */
-	if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies))
-		force_quiescent_state(rsp, 1);
-
-	/*
 	 * Advance callbacks in response to end of earlier grace
 	 * period that some other CPU ended.
 	 */
@@ -1825,11 +1870,13 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
  */
 static void rcu_process_callbacks(struct softirq_action *unused)
 {
+	struct rcu_state *rsp;
+
+	if (cpu_is_offline(smp_processor_id()))
+		return;
 	trace_rcu_utilization("Start RCU core");
-	__rcu_process_callbacks(&rcu_sched_state,
-				&__get_cpu_var(rcu_sched_data));
-	__rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data));
-	rcu_preempt_process_callbacks();
+	for_each_rcu_flavor(rsp)
+		__rcu_process_callbacks(rsp);
 	trace_rcu_utilization("End RCU core");
 }
 
@@ -1856,6 +1903,55 @@ static void invoke_rcu_core(void)
 	raise_softirq(RCU_SOFTIRQ);
 }
 
+/*
+ * Handle any core-RCU processing required by a call_rcu() invocation.
+ */
+static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp,
+			    struct rcu_head *head, unsigned long flags)
+{
+	/*
+	 * If called from an extended quiescent state, invoke the RCU
+	 * core in order to force a re-evaluation of RCU's idleness.
+	 */
+	if (rcu_is_cpu_idle() && cpu_online(smp_processor_id()))
+		invoke_rcu_core();
+
+	/* If interrupts were disabled or CPU offline, don't invoke RCU core. */
+	if (irqs_disabled_flags(flags) || cpu_is_offline(smp_processor_id()))
+		return;
+
+	/*
+	 * Force the grace period if too many callbacks or too long waiting.
+	 * Enforce hysteresis, and don't invoke force_quiescent_state()
+	 * if some other CPU has recently done so.  Also, don't bother
+	 * invoking force_quiescent_state() if the newly enqueued callback
+	 * is the only one waiting for a grace period to complete.
+	 */
+	if (unlikely(rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) {
+
+		/* Are we ignoring a completed grace period? */
+		rcu_process_gp_end(rsp, rdp);
+		check_for_new_grace_period(rsp, rdp);
+
+		/* Start a new grace period if one not already started. */
+		if (!rcu_gp_in_progress(rsp)) {
+			unsigned long nestflag;
+			struct rcu_node *rnp_root = rcu_get_root(rsp);
+
+			raw_spin_lock_irqsave(&rnp_root->lock, nestflag);
+			rcu_start_gp(rsp, nestflag);  /* rlses rnp_root->lock */
+		} else {
+			/* Give the grace period a kick. */
+			rdp->blimit = LONG_MAX;
+			if (rsp->n_force_qs == rdp->n_force_qs_snap &&
+			    *rdp->nxttail[RCU_DONE_TAIL] != head)
+				force_quiescent_state(rsp);
+			rdp->n_force_qs_snap = rsp->n_force_qs;
+			rdp->qlen_last_fqs_check = rdp->qlen;
+		}
+	}
+}
+
 static void
 __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
 	   struct rcu_state *rsp, bool lazy)
@@ -1880,7 +1976,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
 	rdp = this_cpu_ptr(rsp->rda);
 
 	/* Add the callback to our list. */
-	rdp->qlen++;
+	ACCESS_ONCE(rdp->qlen)++;
 	if (lazy)
 		rdp->qlen_lazy++;
 	else
@@ -1895,43 +1991,8 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
 	else
 		trace_rcu_callback(rsp->name, head, rdp->qlen_lazy, rdp->qlen);
 
-	/* If interrupts were disabled, don't dive into RCU core. */
-	if (irqs_disabled_flags(flags)) {
-		local_irq_restore(flags);
-		return;
-	}
-
-	/*
-	 * Force the grace period if too many callbacks or too long waiting.
-	 * Enforce hysteresis, and don't invoke force_quiescent_state()
-	 * if some other CPU has recently done so.  Also, don't bother
-	 * invoking force_quiescent_state() if the newly enqueued callback
-	 * is the only one waiting for a grace period to complete.
-	 */
-	if (unlikely(rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) {
-
-		/* Are we ignoring a completed grace period? */
-		rcu_process_gp_end(rsp, rdp);
-		check_for_new_grace_period(rsp, rdp);
-
-		/* Start a new grace period if one not already started. */
-		if (!rcu_gp_in_progress(rsp)) {
-			unsigned long nestflag;
-			struct rcu_node *rnp_root = rcu_get_root(rsp);
-
-			raw_spin_lock_irqsave(&rnp_root->lock, nestflag);
-			rcu_start_gp(rsp, nestflag);  /* rlses rnp_root->lock */
-		} else {
-			/* Give the grace period a kick. */
-			rdp->blimit = LONG_MAX;
-			if (rsp->n_force_qs == rdp->n_force_qs_snap &&
-			    *rdp->nxttail[RCU_DONE_TAIL] != head)
-				force_quiescent_state(rsp, 0);
-			rdp->n_force_qs_snap = rsp->n_force_qs;
-			rdp->qlen_last_fqs_check = rdp->qlen;
-		}
-	} else if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies))
-		force_quiescent_state(rsp, 1);
+	/* Go handle any RCU core processing required. */
+	__call_rcu_core(rsp, rdp, head, flags);
 	local_irq_restore(flags);
 }
 
@@ -1961,28 +2022,16 @@ EXPORT_SYMBOL_GPL(call_rcu_bh);
  * occasionally incorrectly indicate that there are multiple CPUs online
  * when there was in fact only one the whole time, as this just adds
  * some overhead: RCU still operates correctly.
- *
- * Of course, sampling num_online_cpus() with preemption enabled can
- * give erroneous results if there are concurrent CPU-hotplug operations.
- * For example, given a demonic sequence of preemptions in num_online_cpus()
- * and CPU-hotplug operations, there could be two or more CPUs online at
- * all times, but num_online_cpus() might well return one (or even zero).
- *
- * However, all such demonic sequences require at least one CPU-offline
- * operation.  Furthermore, rcu_blocking_is_gp() giving the wrong answer
- * is only a problem if there is an RCU read-side critical section executing
- * throughout.  But RCU-sched and RCU-bh read-side critical sections
- * disable either preemption or bh, which prevents a CPU from going offline.
- * Therefore, the only way that rcu_blocking_is_gp() can incorrectly return
- * that there is only one CPU when in fact there was more than one throughout
- * is when there were no RCU readers in the system.  If there are no
- * RCU readers, the grace period by definition can be of zero length,
- * regardless of the number of online CPUs.
  */
 static inline int rcu_blocking_is_gp(void)
 {
+	int ret;
+
 	might_sleep();  /* Check for RCU read-side critical section. */
-	return num_online_cpus() <= 1;
+	preempt_disable();
+	ret = num_online_cpus() <= 1;
+	preempt_enable();
+	return ret;
 }
 
 /**
@@ -2240,9 +2289,12 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
  */
 static int rcu_pending(int cpu)
 {
-	return __rcu_pending(&rcu_sched_state, &per_cpu(rcu_sched_data, cpu)) ||
-	       __rcu_pending(&rcu_bh_state, &per_cpu(rcu_bh_data, cpu)) ||
-	       rcu_preempt_pending(cpu);
+	struct rcu_state *rsp;
+
+	for_each_rcu_flavor(rsp)
+		if (__rcu_pending(rsp, per_cpu_ptr(rsp->rda, cpu)))
+			return 1;
+	return 0;
 }
 
 /*
@@ -2252,20 +2304,41 @@ static int rcu_pending(int cpu)
  */
 static int rcu_cpu_has_callbacks(int cpu)
 {
+	struct rcu_state *rsp;
+
 	/* RCU callbacks either ready or pending? */
-	return per_cpu(rcu_sched_data, cpu).nxtlist ||
-	       per_cpu(rcu_bh_data, cpu).nxtlist ||
-	       rcu_preempt_cpu_has_callbacks(cpu);
+	for_each_rcu_flavor(rsp)
+		if (per_cpu_ptr(rsp->rda, cpu)->nxtlist)
+			return 1;
+	return 0;
+}
+
+/*
+ * Helper function for _rcu_barrier() tracing.  If tracing is disabled,
+ * the compiler is expected to optimize this away.
+ */
+static void _rcu_barrier_trace(struct rcu_state *rsp, char *s,
+			       int cpu, unsigned long done)
+{
+	trace_rcu_barrier(rsp->name, s, cpu,
+			  atomic_read(&rsp->barrier_cpu_count), done);
 }
 
 /*
  * RCU callback function for _rcu_barrier().  If we are last, wake
  * up the task executing _rcu_barrier().
  */
-static void rcu_barrier_callback(struct rcu_head *notused)
+static void rcu_barrier_callback(struct rcu_head *rhp)
 {
-	if (atomic_dec_and_test(&rcu_barrier_cpu_count))
-		complete(&rcu_barrier_completion);
+	struct rcu_data *rdp = container_of(rhp, struct rcu_data, barrier_head);
+	struct rcu_state *rsp = rdp->rsp;
+
+	if (atomic_dec_and_test(&rsp->barrier_cpu_count)) {
+		_rcu_barrier_trace(rsp, "LastCB", -1, rsp->n_barrier_done);
+		complete(&rsp->barrier_completion);
+	} else {
+		_rcu_barrier_trace(rsp, "CB", -1, rsp->n_barrier_done);
+	}
 }
 
 /*
@@ -2273,35 +2346,63 @@ static void rcu_barrier_callback(struct rcu_head *notused)
  */
 static void rcu_barrier_func(void *type)
 {
-	int cpu = smp_processor_id();
-	struct rcu_head *head = &per_cpu(rcu_barrier_head, cpu);
-	void (*call_rcu_func)(struct rcu_head *head,
-			      void (*func)(struct rcu_head *head));
+	struct rcu_state *rsp = type;
+	struct rcu_data *rdp = __this_cpu_ptr(rsp->rda);
 
-	atomic_inc(&rcu_barrier_cpu_count);
-	call_rcu_func = type;
-	call_rcu_func(head, rcu_barrier_callback);
+	_rcu_barrier_trace(rsp, "IRQ", -1, rsp->n_barrier_done);
+	atomic_inc(&rsp->barrier_cpu_count);
+	rsp->call(&rdp->barrier_head, rcu_barrier_callback);
 }
 
 /*
  * Orchestrate the specified type of RCU barrier, waiting for all
  * RCU callbacks of the specified type to complete.
  */
-static void _rcu_barrier(struct rcu_state *rsp,
-			 void (*call_rcu_func)(struct rcu_head *head,
-					       void (*func)(struct rcu_head *head)))
+static void _rcu_barrier(struct rcu_state *rsp)
 {
 	int cpu;
 	unsigned long flags;
 	struct rcu_data *rdp;
-	struct rcu_head rh;
+	struct rcu_data rd;
+	unsigned long snap = ACCESS_ONCE(rsp->n_barrier_done);
+	unsigned long snap_done;
 
-	init_rcu_head_on_stack(&rh);
+	init_rcu_head_on_stack(&rd.barrier_head);
+	_rcu_barrier_trace(rsp, "Begin", -1, snap);
 
 	/* Take mutex to serialize concurrent rcu_barrier() requests. */
-	mutex_lock(&rcu_barrier_mutex);
+	mutex_lock(&rsp->barrier_mutex);
 
-	smp_mb();  /* Prevent any prior operations from leaking in. */
+	/*
+	 * Ensure that all prior references, including to ->n_barrier_done,
+	 * are ordered before the _rcu_barrier() machinery.
+	 */
+	smp_mb();  /* See above block comment. */
+
+	/*
+	 * Recheck ->n_barrier_done to see if others did our work for us.
+	 * This means checking ->n_barrier_done for an even-to-odd-to-even
+	 * transition.  The "if" expression below therefore rounds the old
+	 * value up to the next even number and adds two before comparing.
+	 */
+	snap_done = ACCESS_ONCE(rsp->n_barrier_done);
+	_rcu_barrier_trace(rsp, "Check", -1, snap_done);
+	if (ULONG_CMP_GE(snap_done, ((snap + 1) & ~0x1) + 2)) {
+		_rcu_barrier_trace(rsp, "EarlyExit", -1, snap_done);
+		smp_mb(); /* caller's subsequent code after above check. */
+		mutex_unlock(&rsp->barrier_mutex);
+		return;
+	}
+
+	/*
+	 * Increment ->n_barrier_done to avoid duplicate work.  Use
+	 * ACCESS_ONCE() to prevent the compiler from speculating
+	 * the increment to precede the early-exit check.
+	 */
+	ACCESS_ONCE(rsp->n_barrier_done)++;
+	WARN_ON_ONCE((rsp->n_barrier_done & 0x1) != 1);
+	_rcu_barrier_trace(rsp, "Inc1", -1, rsp->n_barrier_done);
+	smp_mb(); /* Order ->n_barrier_done increment with below mechanism. */
 
 	/*
 	 * Initialize the count to one rather than to zero in order to
@@ -2320,8 +2421,8 @@ static void _rcu_barrier(struct rcu_state *rsp,
 	 * 6.	Both rcu_barrier_callback() callbacks are invoked, awakening
 	 *	us -- but before CPU 1's orphaned callbacks are invoked!!!
 	 */
-	init_completion(&rcu_barrier_completion);
-	atomic_set(&rcu_barrier_cpu_count, 1);
+	init_completion(&rsp->barrier_completion);
+	atomic_set(&rsp->barrier_cpu_count, 1);
 	raw_spin_lock_irqsave(&rsp->onofflock, flags);
 	rsp->rcu_barrier_in_progress = current;
 	raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
@@ -2337,14 +2438,19 @@ static void _rcu_barrier(struct rcu_state *rsp,
 		preempt_disable();
 		rdp = per_cpu_ptr(rsp->rda, cpu);
 		if (cpu_is_offline(cpu)) {
+			_rcu_barrier_trace(rsp, "Offline", cpu,
+					   rsp->n_barrier_done);
 			preempt_enable();
 			while (cpu_is_offline(cpu) && ACCESS_ONCE(rdp->qlen))
 				schedule_timeout_interruptible(1);
 		} else if (ACCESS_ONCE(rdp->qlen)) {
-			smp_call_function_single(cpu, rcu_barrier_func,
-						 (void *)call_rcu_func, 1);
+			_rcu_barrier_trace(rsp, "OnlineQ", cpu,
+					   rsp->n_barrier_done);
+			smp_call_function_single(cpu, rcu_barrier_func, rsp, 1);
 			preempt_enable();
 		} else {
+			_rcu_barrier_trace(rsp, "OnlineNQ", cpu,
+					   rsp->n_barrier_done);
 			preempt_enable();
 		}
 	}
@@ -2361,24 +2467,32 @@ static void _rcu_barrier(struct rcu_state *rsp,
 	rcu_adopt_orphan_cbs(rsp);
 	rsp->rcu_barrier_in_progress = NULL;
 	raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
-	atomic_inc(&rcu_barrier_cpu_count);
+	atomic_inc(&rsp->barrier_cpu_count);
 	smp_mb__after_atomic_inc(); /* Ensure atomic_inc() before callback. */
-	call_rcu_func(&rh, rcu_barrier_callback);
+	rd.rsp = rsp;
+	rsp->call(&rd.barrier_head, rcu_barrier_callback);
 
 	/*
 	 * Now that we have an rcu_barrier_callback() callback on each
 	 * CPU, and thus each counted, remove the initial count.
 	 */
-	if (atomic_dec_and_test(&rcu_barrier_cpu_count))
-		complete(&rcu_barrier_completion);
+	if (atomic_dec_and_test(&rsp->barrier_cpu_count))
+		complete(&rsp->barrier_completion);
+
+	/* Increment ->n_barrier_done to prevent duplicate work. */
+	smp_mb(); /* Keep increment after above mechanism. */
+	ACCESS_ONCE(rsp->n_barrier_done)++;
+	WARN_ON_ONCE((rsp->n_barrier_done & 0x1) != 0);
+	_rcu_barrier_trace(rsp, "Inc2", -1, rsp->n_barrier_done);
+	smp_mb(); /* Keep increment before caller's subsequent code. */
 
 	/* Wait for all rcu_barrier_callback() callbacks to be invoked. */
-	wait_for_completion(&rcu_barrier_completion);
+	wait_for_completion(&rsp->barrier_completion);
 
 	/* Other rcu_barrier() invocations can now safely proceed. */
-	mutex_unlock(&rcu_barrier_mutex);
+	mutex_unlock(&rsp->barrier_mutex);
 
-	destroy_rcu_head_on_stack(&rh);
+	destroy_rcu_head_on_stack(&rd.barrier_head);
 }
 
 /**
@@ -2386,7 +2500,7 @@ static void _rcu_barrier(struct rcu_state *rsp,
  */
 void rcu_barrier_bh(void)
 {
-	_rcu_barrier(&rcu_bh_state, call_rcu_bh);
+	_rcu_barrier(&rcu_bh_state);
 }
 EXPORT_SYMBOL_GPL(rcu_barrier_bh);
 
@@ -2395,7 +2509,7 @@ EXPORT_SYMBOL_GPL(rcu_barrier_bh);
  */
 void rcu_barrier_sched(void)
 {
-	_rcu_barrier(&rcu_sched_state, call_rcu_sched);
+	_rcu_barrier(&rcu_sched_state);
 }
 EXPORT_SYMBOL_GPL(rcu_barrier_sched);
 
@@ -2406,18 +2520,15 @@ static void __init
 rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
 {
 	unsigned long flags;
-	int i;
 	struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
 	struct rcu_node *rnp = rcu_get_root(rsp);
 
 	/* Set up local state, ensuring consistent view of global state. */
 	raw_spin_lock_irqsave(&rnp->lock, flags);
 	rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo);
-	rdp->nxtlist = NULL;
-	for (i = 0; i < RCU_NEXT_SIZE; i++)
-		rdp->nxttail[i] = &rdp->nxtlist;
+	init_callback_list(rdp);
 	rdp->qlen_lazy = 0;
-	rdp->qlen = 0;
+	ACCESS_ONCE(rdp->qlen) = 0;
 	rdp->dynticks = &per_cpu(rcu_dynticks, cpu);
 	WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE);
 	WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1);
@@ -2491,9 +2602,11 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
 
 static void __cpuinit rcu_prepare_cpu(int cpu)
 {
-	rcu_init_percpu_data(cpu, &rcu_sched_state, 0);
-	rcu_init_percpu_data(cpu, &rcu_bh_state, 0);
-	rcu_preempt_init_percpu_data(cpu);
+	struct rcu_state *rsp;
+
+	for_each_rcu_flavor(rsp)
+		rcu_init_percpu_data(cpu, rsp,
+				     strcmp(rsp->name, "rcu_preempt") == 0);
 }
 
 /*
@@ -2505,6 +2618,7 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
 	long cpu = (long)hcpu;
 	struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
 	struct rcu_node *rnp = rdp->mynode;
+	struct rcu_state *rsp;
 
 	trace_rcu_utilization("Start CPU hotplug");
 	switch (action) {
@@ -2529,18 +2643,16 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
 		 * touch any data without introducing corruption. We send the
 		 * dying CPU's callbacks to an arbitrarily chosen online CPU.
 		 */
-		rcu_cleanup_dying_cpu(&rcu_bh_state);
-		rcu_cleanup_dying_cpu(&rcu_sched_state);
-		rcu_preempt_cleanup_dying_cpu();
+		for_each_rcu_flavor(rsp)
+			rcu_cleanup_dying_cpu(rsp);
 		rcu_cleanup_after_idle(cpu);
 		break;
 	case CPU_DEAD:
 	case CPU_DEAD_FROZEN:
 	case CPU_UP_CANCELED:
 	case CPU_UP_CANCELED_FROZEN:
-		rcu_cleanup_dead_cpu(cpu, &rcu_bh_state);
-		rcu_cleanup_dead_cpu(cpu, &rcu_sched_state);
-		rcu_preempt_cleanup_dead_cpu(cpu);
+		for_each_rcu_flavor(rsp)
+			rcu_cleanup_dead_cpu(cpu, rsp);
 		break;
 	default:
 		break;
@@ -2550,6 +2662,28 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
 }
 
 /*
+ * Spawn the kthread that handles this RCU flavor's grace periods.
+ */
+static int __init rcu_spawn_gp_kthread(void)
+{
+	unsigned long flags;
+	struct rcu_node *rnp;
+	struct rcu_state *rsp;
+	struct task_struct *t;
+
+	for_each_rcu_flavor(rsp) {
+		t = kthread_run(rcu_gp_kthread, rsp, rsp->name);
+		BUG_ON(IS_ERR(t));
+		rnp = rcu_get_root(rsp);
+		raw_spin_lock_irqsave(&rnp->lock, flags);
+		rsp->gp_kthread = t;
+		raw_spin_unlock_irqrestore(&rnp->lock, flags);
+	}
+	return 0;
+}
+early_initcall(rcu_spawn_gp_kthread);
+
+/*
  * This function is invoked towards the end of the scheduler's initialization
  * process.  Before this is called, the idle task might contain
  * RCU read-side critical sections (during which time, this idle
@@ -2573,9 +2707,9 @@ static void __init rcu_init_levelspread(struct rcu_state *rsp)
 {
 	int i;
 
-	for (i = NUM_RCU_LVLS - 1; i > 0; i--)
+	for (i = rcu_num_lvls - 1; i > 0; i--)
 		rsp->levelspread[i] = CONFIG_RCU_FANOUT;
-	rsp->levelspread[0] = CONFIG_RCU_FANOUT_LEAF;
+	rsp->levelspread[0] = rcu_fanout_leaf;
 }
 #else /* #ifdef CONFIG_RCU_FANOUT_EXACT */
 static void __init rcu_init_levelspread(struct rcu_state *rsp)
@@ -2585,7 +2719,7 @@ static void __init rcu_init_levelspread(struct rcu_state *rsp)
 	int i;
 
 	cprv = NR_CPUS;
-	for (i = NUM_RCU_LVLS - 1; i >= 0; i--) {
+	for (i = rcu_num_lvls - 1; i >= 0; i--) {
 		ccur = rsp->levelcnt[i];
 		rsp->levelspread[i] = (cprv + ccur - 1) / ccur;
 		cprv = ccur;
@@ -2612,13 +2746,15 @@ static void __init rcu_init_one(struct rcu_state *rsp,
 
 	/* Initialize the level-tracking arrays. */
 
-	for (i = 1; i < NUM_RCU_LVLS; i++)
+	for (i = 0; i < rcu_num_lvls; i++)
+		rsp->levelcnt[i] = num_rcu_lvl[i];
+	for (i = 1; i < rcu_num_lvls; i++)
 		rsp->level[i] = rsp->level[i - 1] + rsp->levelcnt[i - 1];
 	rcu_init_levelspread(rsp);
 
 	/* Initialize the elements themselves, starting from the leaves. */
 
-	for (i = NUM_RCU_LVLS - 1; i >= 0; i--) {
+	for (i = rcu_num_lvls - 1; i >= 0; i--) {
 		cpustride *= rsp->levelspread[i];
 		rnp = rsp->level[i];
 		for (j = 0; j < rsp->levelcnt[i]; j++, rnp++) {
@@ -2648,13 +2784,75 @@ static void __init rcu_init_one(struct rcu_state *rsp,
 	}
 
 	rsp->rda = rda;
-	rnp = rsp->level[NUM_RCU_LVLS - 1];
+	init_waitqueue_head(&rsp->gp_wq);
+	rnp = rsp->level[rcu_num_lvls - 1];
 	for_each_possible_cpu(i) {
 		while (i > rnp->grphi)
 			rnp++;
 		per_cpu_ptr(rsp->rda, i)->mynode = rnp;
 		rcu_boot_init_percpu_data(i, rsp);
 	}
+	list_add(&rsp->flavors, &rcu_struct_flavors);
+}
+
+/*
+ * Compute the rcu_node tree geometry from kernel parameters.  This cannot
+ * replace the definitions in rcutree.h because those are needed to size
+ * the ->node array in the rcu_state structure.
+ */
+static void __init rcu_init_geometry(void)
+{
+	int i;
+	int j;
+	int n = nr_cpu_ids;
+	int rcu_capacity[MAX_RCU_LVLS + 1];
+
+	/* If the compile-time values are accurate, just leave. */
+	if (rcu_fanout_leaf == CONFIG_RCU_FANOUT_LEAF)
+		return;
+
+	/*
+	 * Compute number of nodes that can be handled an rcu_node tree
+	 * with the given number of levels.  Setting rcu_capacity[0] makes
+	 * some of the arithmetic easier.
+	 */
+	rcu_capacity[0] = 1;
+	rcu_capacity[1] = rcu_fanout_leaf;
+	for (i = 2; i <= MAX_RCU_LVLS; i++)
+		rcu_capacity[i] = rcu_capacity[i - 1] * CONFIG_RCU_FANOUT;
+
+	/*
+	 * The boot-time rcu_fanout_leaf parameter is only permitted
+	 * to increase the leaf-level fanout, not decrease it.  Of course,
+	 * the leaf-level fanout cannot exceed the number of bits in
+	 * the rcu_node masks.  Finally, the tree must be able to accommodate
+	 * the configured number of CPUs.  Complain and fall back to the
+	 * compile-time values if these limits are exceeded.
+	 */
+	if (rcu_fanout_leaf < CONFIG_RCU_FANOUT_LEAF ||
+	    rcu_fanout_leaf > sizeof(unsigned long) * 8 ||
+	    n > rcu_capacity[MAX_RCU_LVLS]) {
+		WARN_ON(1);
+		return;
+	}
+
+	/* Calculate the number of rcu_nodes at each level of the tree. */
+	for (i = 1; i <= MAX_RCU_LVLS; i++)
+		if (n <= rcu_capacity[i]) {
+			for (j = 0; j <= i; j++)
+				num_rcu_lvl[j] =
+					DIV_ROUND_UP(n, rcu_capacity[i - j]);
+			rcu_num_lvls = i;
+			for (j = i + 1; j <= MAX_RCU_LVLS; j++)
+				num_rcu_lvl[j] = 0;
+			break;
+		}
+
+	/* Calculate the total number of rcu_node structures. */
+	rcu_num_nodes = 0;
+	for (i = 0; i <= MAX_RCU_LVLS; i++)
+		rcu_num_nodes += num_rcu_lvl[i];
+	rcu_num_nodes -= n;
 }
 
 void __init rcu_init(void)
@@ -2662,6 +2860,7 @@ void __init rcu_init(void)
 	int cpu;
 
 	rcu_bootup_announce();
+	rcu_init_geometry();
 	rcu_init_one(&rcu_sched_state, &rcu_sched_data);
 	rcu_init_one(&rcu_bh_state, &rcu_bh_data);
 	__rcu_init_preempt();
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index ea05649..1e092d23 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -42,28 +42,28 @@
 #define RCU_FANOUT_4	      (RCU_FANOUT_3 * CONFIG_RCU_FANOUT)
 
 #if NR_CPUS <= RCU_FANOUT_1
-#  define NUM_RCU_LVLS	      1
+#  define RCU_NUM_LVLS	      1
 #  define NUM_RCU_LVL_0	      1
 #  define NUM_RCU_LVL_1	      (NR_CPUS)
 #  define NUM_RCU_LVL_2	      0
 #  define NUM_RCU_LVL_3	      0
 #  define NUM_RCU_LVL_4	      0
 #elif NR_CPUS <= RCU_FANOUT_2
-#  define NUM_RCU_LVLS	      2
+#  define RCU_NUM_LVLS	      2
 #  define NUM_RCU_LVL_0	      1
 #  define NUM_RCU_LVL_1	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1)
 #  define NUM_RCU_LVL_2	      (NR_CPUS)
 #  define NUM_RCU_LVL_3	      0
 #  define NUM_RCU_LVL_4	      0
 #elif NR_CPUS <= RCU_FANOUT_3
-#  define NUM_RCU_LVLS	      3
+#  define RCU_NUM_LVLS	      3
 #  define NUM_RCU_LVL_0	      1
 #  define NUM_RCU_LVL_1	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2)
 #  define NUM_RCU_LVL_2	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1)
 #  define NUM_RCU_LVL_3	      (NR_CPUS)
 #  define NUM_RCU_LVL_4	      0
 #elif NR_CPUS <= RCU_FANOUT_4
-#  define NUM_RCU_LVLS	      4
+#  define RCU_NUM_LVLS	      4
 #  define NUM_RCU_LVL_0	      1
 #  define NUM_RCU_LVL_1	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_3)
 #  define NUM_RCU_LVL_2	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2)
@@ -76,6 +76,9 @@
 #define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3 + NUM_RCU_LVL_4)
 #define NUM_RCU_NODES (RCU_SUM - NR_CPUS)
 
+extern int rcu_num_lvls;
+extern int rcu_num_nodes;
+
 /*
  * Dynticks per-CPU state.
  */
@@ -97,6 +100,7 @@ struct rcu_dynticks {
 				    /* # times non-lazy CBs posted to CPU. */
 	unsigned long nonlazy_posted_snap;
 				    /* idle-period nonlazy_posted snapshot. */
+	int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */
 #endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
 };
 
@@ -206,7 +210,7 @@ struct rcu_node {
  */
 #define rcu_for_each_node_breadth_first(rsp, rnp) \
 	for ((rnp) = &(rsp)->node[0]; \
-	     (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++)
+	     (rnp) < &(rsp)->node[rcu_num_nodes]; (rnp)++)
 
 /*
  * Do a breadth-first scan of the non-leaf rcu_node structures for the
@@ -215,7 +219,7 @@ struct rcu_node {
  */
 #define rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) \
 	for ((rnp) = &(rsp)->node[0]; \
-	     (rnp) < (rsp)->level[NUM_RCU_LVLS - 1]; (rnp)++)
+	     (rnp) < (rsp)->level[rcu_num_lvls - 1]; (rnp)++)
 
 /*
  * Scan the leaves of the rcu_node hierarchy for the specified rcu_state
@@ -224,8 +228,8 @@ struct rcu_node {
  * It is still a leaf node, even if it is also the root node.
  */
 #define rcu_for_each_leaf_node(rsp, rnp) \
-	for ((rnp) = (rsp)->level[NUM_RCU_LVLS - 1]; \
-	     (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++)
+	for ((rnp) = (rsp)->level[rcu_num_lvls - 1]; \
+	     (rnp) < &(rsp)->node[rcu_num_nodes]; (rnp)++)
 
 /* Index values for nxttail array in struct rcu_data. */
 #define RCU_DONE_TAIL		0	/* Also RCU_WAIT head. */
@@ -311,6 +315,9 @@ struct rcu_data {
 	unsigned long n_rp_need_fqs;
 	unsigned long n_rp_need_nothing;
 
+	/* 6) _rcu_barrier() callback. */
+	struct rcu_head barrier_head;
+
 	int cpu;
 	struct rcu_state *rsp;
 };
@@ -357,10 +364,12 @@ do {									\
  */
 struct rcu_state {
 	struct rcu_node node[NUM_RCU_NODES];	/* Hierarchy. */
-	struct rcu_node *level[NUM_RCU_LVLS];	/* Hierarchy levels. */
+	struct rcu_node *level[RCU_NUM_LVLS];	/* Hierarchy levels. */
 	u32 levelcnt[MAX_RCU_LVLS + 1];		/* # nodes in each level. */
-	u8 levelspread[NUM_RCU_LVLS];		/* kids/node in each level. */
+	u8 levelspread[RCU_NUM_LVLS];		/* kids/node in each level. */
 	struct rcu_data __percpu *rda;		/* pointer of percu rcu_data. */
+	void (*call)(struct rcu_head *head,	/* call_rcu() flavor. */
+		     void (*func)(struct rcu_head *head));
 
 	/* The following fields are guarded by the root rcu_node's lock. */
 
@@ -376,6 +385,9 @@ struct rcu_state {
 	u8	boost;				/* Subject to priority boost. */
 	unsigned long gpnum;			/* Current gp number. */
 	unsigned long completed;		/* # of last completed gp. */
+	struct task_struct *gp_kthread;		/* Task for grace periods. */
+	wait_queue_head_t gp_wq;		/* Where GP task waits. */
+	int gp_flags;				/* Commands for GP task. */
 
 	/* End of fields guarded by root rcu_node's lock. */
 
@@ -392,6 +404,11 @@ struct rcu_state {
 	struct task_struct *rcu_barrier_in_progress;
 						/* Task doing rcu_barrier(), */
 						/*  or NULL if no barrier. */
+	struct mutex barrier_mutex;		/* Guards barrier fields. */
+	atomic_t barrier_cpu_count;		/* # CPUs waiting on. */
+	struct completion barrier_completion;	/* Wake at barrier end. */
+	unsigned long n_barrier_done;		/* ++ at start and end of */
+						/*  _rcu_barrier(). */
 	raw_spinlock_t fqslock;			/* Only one task forcing */
 						/*  quiescent states. */
 	unsigned long jiffies_force_qs;		/* Time at which to invoke */
@@ -409,8 +426,17 @@ struct rcu_state {
 	unsigned long gp_max;			/* Maximum GP duration in */
 						/*  jiffies. */
 	char *name;				/* Name of structure. */
+	struct list_head flavors;		/* List of RCU flavors. */
 };
 
+/* Values for rcu_state structure's gp_flags field. */
+#define RCU_GP_FLAG_INIT 0x1	/* Need grace-period initialization. */
+#define RCU_GP_FLAG_FQS  0x2	/* Need grace-period quiescent-state forcing. */
+
+extern struct list_head rcu_struct_flavors;
+#define for_each_rcu_flavor(rsp) \
+	list_for_each_entry((rsp), &rcu_struct_flavors, flavors)
+
 /* Return values for rcu_preempt_offline_tasks(). */
 
 #define RCU_OFL_TASKS_NORM_GP	0x1		/* Tasks blocking normal */
@@ -452,25 +478,18 @@ static void rcu_stop_cpu_kthread(int cpu);
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 static void rcu_print_detail_task_stall(struct rcu_state *rsp);
 static int rcu_print_task_stall(struct rcu_node *rnp);
-static void rcu_preempt_stall_reset(void);
 static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp);
 #ifdef CONFIG_HOTPLUG_CPU
 static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
 				     struct rcu_node *rnp,
 				     struct rcu_data *rdp);
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
-static void rcu_preempt_cleanup_dead_cpu(int cpu);
 static void rcu_preempt_check_callbacks(int cpu);
-static void rcu_preempt_process_callbacks(void);
 void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
 #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU)
 static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp,
 			       bool wake);
 #endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) */
-static int rcu_preempt_pending(int cpu);
-static int rcu_preempt_cpu_has_callbacks(int cpu);
-static void __cpuinit rcu_preempt_init_percpu_data(int cpu);
-static void rcu_preempt_cleanup_dying_cpu(void);
 static void __init __rcu_init_preempt(void);
 static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags);
 static void rcu_preempt_boost_start_gp(struct rcu_node *rnp);
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 5271a02..189eedb 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -25,6 +25,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/oom.h>
 
 #define RCU_KTHREAD_PRIO 1
 
@@ -68,17 +69,21 @@ static void __init rcu_bootup_announce_oddness(void)
 	printk(KERN_INFO "\tAdditional per-CPU info printed with stalls.\n");
 #endif
 #if NUM_RCU_LVL_4 != 0
-	printk(KERN_INFO "\tExperimental four-level hierarchy is enabled.\n");
+	printk(KERN_INFO "\tFour-level hierarchy is enabled.\n");
 #endif
+	if (rcu_fanout_leaf != CONFIG_RCU_FANOUT_LEAF)
+		printk(KERN_INFO "\tExperimental boot-time adjustment of leaf fanout to %d.\n", rcu_fanout_leaf);
+	if (nr_cpu_ids != NR_CPUS)
+		printk(KERN_INFO "\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%d.\n", NR_CPUS, nr_cpu_ids);
 }
 
 #ifdef CONFIG_TREE_PREEMPT_RCU
 
-struct rcu_state rcu_preempt_state = RCU_STATE_INITIALIZER(rcu_preempt);
+struct rcu_state rcu_preempt_state =
+	RCU_STATE_INITIALIZER(rcu_preempt, call_rcu);
 DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data);
 static struct rcu_state *rcu_state = &rcu_preempt_state;
 
-static void rcu_read_unlock_special(struct task_struct *t);
 static int rcu_preempted_readers_exp(struct rcu_node *rnp);
 
 /*
@@ -114,7 +119,7 @@ EXPORT_SYMBOL_GPL(rcu_batches_completed);
  */
 void rcu_force_quiescent_state(void)
 {
-	force_quiescent_state(&rcu_preempt_state, 0);
+	force_quiescent_state(&rcu_preempt_state);
 }
 EXPORT_SYMBOL_GPL(rcu_force_quiescent_state);
 
@@ -233,18 +238,6 @@ void rcu_preempt_note_context_switch(void)
 }
 
 /*
- * Tree-preemptible RCU implementation for rcu_read_lock().
- * Just increment ->rcu_read_lock_nesting, shared state will be updated
- * if we block.
- */
-void __rcu_read_lock(void)
-{
-	current->rcu_read_lock_nesting++;
-	barrier();  /* needed if we ever invoke rcu_read_lock in rcutree.c */
-}
-EXPORT_SYMBOL_GPL(__rcu_read_lock);
-
-/*
  * Check for preempted RCU readers blocking the current grace period
  * for the specified rcu_node structure.  If the caller needs a reliable
  * answer, it must hold the rcu_node's ->lock.
@@ -310,7 +303,7 @@ static struct list_head *rcu_next_node_entry(struct task_struct *t,
  * notify RCU core processing or task having blocked during the RCU
  * read-side critical section.
  */
-static noinline void rcu_read_unlock_special(struct task_struct *t)
+void rcu_read_unlock_special(struct task_struct *t)
 {
 	int empty;
 	int empty_exp;
@@ -418,38 +411,6 @@ static noinline void rcu_read_unlock_special(struct task_struct *t)
 	}
 }
 
-/*
- * Tree-preemptible RCU implementation for rcu_read_unlock().
- * Decrement ->rcu_read_lock_nesting.  If the result is zero (outermost
- * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then
- * invoke rcu_read_unlock_special() to clean up after a context switch
- * in an RCU read-side critical section and other special cases.
- */
-void __rcu_read_unlock(void)
-{
-	struct task_struct *t = current;
-
-	if (t->rcu_read_lock_nesting != 1)
-		--t->rcu_read_lock_nesting;
-	else {
-		barrier();  /* critical section before exit code. */
-		t->rcu_read_lock_nesting = INT_MIN;
-		barrier();  /* assign before ->rcu_read_unlock_special load */
-		if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
-			rcu_read_unlock_special(t);
-		barrier();  /* ->rcu_read_unlock_special load before assign */
-		t->rcu_read_lock_nesting = 0;
-	}
-#ifdef CONFIG_PROVE_LOCKING
-	{
-		int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting);
-
-		WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2);
-	}
-#endif /* #ifdef CONFIG_PROVE_LOCKING */
-}
-EXPORT_SYMBOL_GPL(__rcu_read_unlock);
-
 #ifdef CONFIG_RCU_CPU_STALL_VERBOSE
 
 /*
@@ -540,16 +501,6 @@ static int rcu_print_task_stall(struct rcu_node *rnp)
 }
 
 /*
- * Suppress preemptible RCU's CPU stall warnings by pushing the
- * time of the next stall-warning message comfortably far into the
- * future.
- */
-static void rcu_preempt_stall_reset(void)
-{
-	rcu_preempt_state.jiffies_stall = jiffies + ULONG_MAX / 2;
-}
-
-/*
  * Check that the list of blocked tasks for the newly completed grace
  * period is in fact empty.  It is a serious bug to complete a grace
  * period that still has RCU readers blocked!  This function must be
@@ -650,14 +601,6 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 
 /*
- * Do CPU-offline processing for preemptible RCU.
- */
-static void rcu_preempt_cleanup_dead_cpu(int cpu)
-{
-	rcu_cleanup_dead_cpu(cpu, &rcu_preempt_state);
-}
-
-/*
  * Check for a quiescent state from the current CPU.  When a task blocks,
  * the task is recorded in the corresponding CPU's rcu_node structure,
  * which is checked elsewhere.
@@ -677,15 +620,6 @@ static void rcu_preempt_check_callbacks(int cpu)
 		t->rcu_read_unlock_special |= RCU_READ_UNLOCK_NEED_QS;
 }
 
-/*
- * Process callbacks for preemptible RCU.
- */
-static void rcu_preempt_process_callbacks(void)
-{
-	__rcu_process_callbacks(&rcu_preempt_state,
-				&__get_cpu_var(rcu_preempt_data));
-}
-
 #ifdef CONFIG_RCU_BOOST
 
 static void rcu_preempt_do_callbacks(void)
@@ -917,51 +851,16 @@ mb_ret:
 }
 EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
 
-/*
- * Check to see if there is any immediate preemptible-RCU-related work
- * to be done.
- */
-static int rcu_preempt_pending(int cpu)
-{
-	return __rcu_pending(&rcu_preempt_state,
-			     &per_cpu(rcu_preempt_data, cpu));
-}
-
-/*
- * Does preemptible RCU have callbacks on this CPU?
- */
-static int rcu_preempt_cpu_has_callbacks(int cpu)
-{
-	return !!per_cpu(rcu_preempt_data, cpu).nxtlist;
-}
-
 /**
  * rcu_barrier - Wait until all in-flight call_rcu() callbacks complete.
  */
 void rcu_barrier(void)
 {
-	_rcu_barrier(&rcu_preempt_state, call_rcu);
+	_rcu_barrier(&rcu_preempt_state);
 }
 EXPORT_SYMBOL_GPL(rcu_barrier);
 
 /*
- * Initialize preemptible RCU's per-CPU data.
- */
-static void __cpuinit rcu_preempt_init_percpu_data(int cpu)
-{
-	rcu_init_percpu_data(cpu, &rcu_preempt_state, 1);
-}
-
-/*
- * Move preemptible RCU's callbacks from dying CPU to other online CPU
- * and record a quiescent state.
- */
-static void rcu_preempt_cleanup_dying_cpu(void)
-{
-	rcu_cleanup_dying_cpu(&rcu_preempt_state);
-}
-
-/*
  * Initialize preemptible RCU's state structures.
  */
 static void __init __rcu_init_preempt(void)
@@ -1038,14 +937,6 @@ static int rcu_print_task_stall(struct rcu_node *rnp)
 }
 
 /*
- * Because preemptible RCU does not exist, there is no need to suppress
- * its CPU stall warnings.
- */
-static void rcu_preempt_stall_reset(void)
-{
-}
-
-/*
  * Because there is no preemptible RCU, there can be no readers blocked,
  * so there is no need to check for blocked tasks.  So check only for
  * bogus qsmask values.
@@ -1073,14 +964,6 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 
 /*
- * Because preemptible RCU does not exist, it never needs CPU-offline
- * processing.
- */
-static void rcu_preempt_cleanup_dead_cpu(int cpu)
-{
-}
-
-/*
  * Because preemptible RCU does not exist, it never has any callbacks
  * to check.
  */
@@ -1089,14 +972,6 @@ static void rcu_preempt_check_callbacks(int cpu)
 }
 
 /*
- * Because preemptible RCU does not exist, it never has any callbacks
- * to process.
- */
-static void rcu_preempt_process_callbacks(void)
-{
-}
-
-/*
  * Queue an RCU callback for lazy invocation after a grace period.
  * This will likely be later named something like "call_rcu_lazy()",
  * but this change will require some way of tagging the lazy RCU
@@ -1137,22 +1012,6 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp,
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 
 /*
- * Because preemptible RCU does not exist, it never has any work to do.
- */
-static int rcu_preempt_pending(int cpu)
-{
-	return 0;
-}
-
-/*
- * Because preemptible RCU does not exist, it never has callbacks
- */
-static int rcu_preempt_cpu_has_callbacks(int cpu)
-{
-	return 0;
-}
-
-/*
  * Because preemptible RCU does not exist, rcu_barrier() is just
  * another name for rcu_barrier_sched().
  */
@@ -1163,21 +1022,6 @@ void rcu_barrier(void)
 EXPORT_SYMBOL_GPL(rcu_barrier);
 
 /*
- * Because preemptible RCU does not exist, there is no per-CPU
- * data to initialize.
- */
-static void __cpuinit rcu_preempt_init_percpu_data(int cpu)
-{
-}
-
-/*
- * Because there is no preemptible RCU, there is no cleanup to do.
- */
-static void rcu_preempt_cleanup_dying_cpu(void)
-{
-}
-
-/*
  * Because preemptible RCU does not exist, it need not be initialized.
  */
 static void __init __rcu_init_preempt(void)
@@ -1960,9 +1804,11 @@ static void rcu_idle_count_callbacks_posted(void)
  */
 #define RCU_IDLE_FLUSHES 5		/* Number of dyntick-idle tries. */
 #define RCU_IDLE_OPT_FLUSHES 3		/* Optional dyntick-idle tries. */
-#define RCU_IDLE_GP_DELAY 6		/* Roughly one grace period. */
+#define RCU_IDLE_GP_DELAY 4		/* Roughly one grace period. */
 #define RCU_IDLE_LAZY_GP_DELAY (6 * HZ)	/* Roughly six seconds. */
 
+extern int tick_nohz_enabled;
+
 /*
  * Does the specified flavor of RCU have non-lazy callbacks pending on
  * the specified CPU?  Both RCU flavor and CPU are specified by the
@@ -2039,10 +1885,13 @@ int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
 		return 1;
 	}
 	/* Set up for the possibility that RCU will post a timer. */
-	if (rcu_cpu_has_nonlazy_callbacks(cpu))
-		*delta_jiffies = RCU_IDLE_GP_DELAY;
-	else
-		*delta_jiffies = RCU_IDLE_LAZY_GP_DELAY;
+	if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
+		*delta_jiffies = round_up(RCU_IDLE_GP_DELAY + jiffies,
+					  RCU_IDLE_GP_DELAY) - jiffies;
+	} else {
+		*delta_jiffies = jiffies + RCU_IDLE_LAZY_GP_DELAY;
+		*delta_jiffies = round_jiffies(*delta_jiffies) - jiffies;
+	}
 	return 0;
 }
 
@@ -2101,6 +1950,7 @@ static void rcu_cleanup_after_idle(int cpu)
 
 	del_timer(&rdtp->idle_gp_timer);
 	trace_rcu_prep_idle("Cleanup after idle");
+	rdtp->tick_nohz_enabled_snap = ACCESS_ONCE(tick_nohz_enabled);
 }
 
 /*
@@ -2126,6 +1976,18 @@ static void rcu_prepare_for_idle(int cpu)
 {
 	struct timer_list *tp;
 	struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
+	int tne;
+
+	/* Handle nohz enablement switches conservatively. */
+	tne = ACCESS_ONCE(tick_nohz_enabled);
+	if (tne != rdtp->tick_nohz_enabled_snap) {
+		if (rcu_cpu_has_callbacks(cpu))
+			invoke_rcu_core(); /* force nohz to see update. */
+		rdtp->tick_nohz_enabled_snap = tne;
+		return;
+	}
+	if (!tne)
+		return;
 
 	/*
 	 * If this is an idle re-entry, for example, due to use of
@@ -2179,10 +2041,11 @@ static void rcu_prepare_for_idle(int cpu)
 		if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
 			trace_rcu_prep_idle("Dyntick with callbacks");
 			rdtp->idle_gp_timer_expires =
-					   jiffies + RCU_IDLE_GP_DELAY;
+				round_up(jiffies + RCU_IDLE_GP_DELAY,
+					 RCU_IDLE_GP_DELAY);
 		} else {
 			rdtp->idle_gp_timer_expires =
-					   jiffies + RCU_IDLE_LAZY_GP_DELAY;
+				round_jiffies(jiffies + RCU_IDLE_LAZY_GP_DELAY);
 			trace_rcu_prep_idle("Dyntick with lazy callbacks");
 		}
 		tp = &rdtp->idle_gp_timer;
@@ -2204,16 +2067,16 @@ static void rcu_prepare_for_idle(int cpu)
 #ifdef CONFIG_TREE_PREEMPT_RCU
 	if (per_cpu(rcu_preempt_data, cpu).nxtlist) {
 		rcu_preempt_qs(cpu);
-		force_quiescent_state(&rcu_preempt_state, 0);
+		force_quiescent_state(&rcu_preempt_state);
 	}
 #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 	if (per_cpu(rcu_sched_data, cpu).nxtlist) {
 		rcu_sched_qs(cpu);
-		force_quiescent_state(&rcu_sched_state, 0);
+		force_quiescent_state(&rcu_sched_state);
 	}
 	if (per_cpu(rcu_bh_data, cpu).nxtlist) {
 		rcu_bh_qs(cpu);
-		force_quiescent_state(&rcu_bh_state, 0);
+		force_quiescent_state(&rcu_bh_state);
 	}
 
 	/*
@@ -2240,6 +2103,35 @@ static void rcu_idle_count_callbacks_posted(void)
 	__this_cpu_add(rcu_dynticks.nonlazy_posted, 1);
 }
 
+/*
+ * If low on memory, do a full round of rcu_barrier() calls to ensure
+ * that each CPU has a non-lazy callback.  This will wake up CPUs that
+ * have only lazy callbacks, ensuring that they free up the corresponding
+ * memory in a timely manner.
+ */
+static int rcu_oom_notify(struct notifier_block *self,
+                          unsigned long notused, void *nfreed)
+{
+#ifdef CONFIG_PREEMPT_RCU
+	rcu_barrier();
+#endif /* #ifdef CONFIG_PREEMPT_RCU */
+	rcu_barrier_bh();
+	rcu_barrier_sched();
+	*(unsigned long *)nfreed = 1;
+	return NOTIFY_OK;
+}
+
+static struct notifier_block rcu_oom_nb = {
+	.notifier_call = rcu_oom_notify
+};
+
+static int __init rcu_register_oom_notifier(void)
+{
+	register_oom_notifier(&rcu_oom_nb);
+	return 0;
+}
+early_initcall(rcu_register_oom_notifier);
+
 #endif /* #else #if !defined(CONFIG_RCU_FAST_NO_HZ) */
 
 #ifdef CONFIG_RCU_CPU_STALL_INFO
@@ -2261,6 +2153,7 @@ static void print_cpu_stall_fast_no_hz(char *cp, int cpu)
 
 static void print_cpu_stall_fast_no_hz(char *cp, int cpu)
 {
+	*cp = '\0';
 }
 
 #endif /* #else #ifdef CONFIG_RCU_FAST_NO_HZ */
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c
index d4bc16d..a16ddbd 100644
--- a/kernel/rcutree_trace.c
+++ b/kernel/rcutree_trace.c
@@ -46,6 +46,31 @@
 #define RCU_TREE_NONCORE
 #include "rcutree.h"
 
+static int show_rcubarrier(struct seq_file *m, void *unused)
+{
+	struct rcu_state *rsp;
+
+	for_each_rcu_flavor(rsp)
+		seq_printf(m, "%s: %c bcc: %d nbd: %lu\n",
+			   rsp->name, rsp->rcu_barrier_in_progress ? 'B' : '.',
+			   atomic_read(&rsp->barrier_cpu_count),
+			   rsp->n_barrier_done);
+	return 0;
+}
+
+static int rcubarrier_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, show_rcubarrier, NULL);
+}
+
+static const struct file_operations rcubarrier_fops = {
+	.owner = THIS_MODULE,
+	.open = rcubarrier_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 #ifdef CONFIG_RCU_BOOST
 
 static char convert_kthread_status(unsigned int kthread_status)
@@ -95,24 +120,16 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
 		   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
 }
 
-#define PRINT_RCU_DATA(name, func, m) \
-	do { \
-		int _p_r_d_i; \
-		\
-		for_each_possible_cpu(_p_r_d_i) \
-			func(m, &per_cpu(name, _p_r_d_i)); \
-	} while (0)
-
 static int show_rcudata(struct seq_file *m, void *unused)
 {
-#ifdef CONFIG_TREE_PREEMPT_RCU
-	seq_puts(m, "rcu_preempt:\n");
-	PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data, m);
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-	seq_puts(m, "rcu_sched:\n");
-	PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data, m);
-	seq_puts(m, "rcu_bh:\n");
-	PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data, m);
+	int cpu;
+	struct rcu_state *rsp;
+
+	for_each_rcu_flavor(rsp) {
+		seq_printf(m, "%s:\n", rsp->name);
+		for_each_possible_cpu(cpu)
+			print_one_rcu_data(m, per_cpu_ptr(rsp->rda, cpu));
+	}
 	return 0;
 }
 
@@ -166,6 +183,9 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
 
 static int show_rcudata_csv(struct seq_file *m, void *unused)
 {
+	int cpu;
+	struct rcu_state *rsp;
+
 	seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pgp\",\"pq\",");
 	seq_puts(m, "\"dt\",\"dt nesting\",\"dt NMI nesting\",\"df\",");
 	seq_puts(m, "\"of\",\"qll\",\"ql\",\"qs\"");
@@ -173,14 +193,11 @@ static int show_rcudata_csv(struct seq_file *m, void *unused)
 	seq_puts(m, "\"kt\",\"ktl\"");
 #endif /* #ifdef CONFIG_RCU_BOOST */
 	seq_puts(m, ",\"b\",\"ci\",\"co\",\"ca\"\n");
-#ifdef CONFIG_TREE_PREEMPT_RCU
-	seq_puts(m, "\"rcu_preempt:\"\n");
-	PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data_csv, m);
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-	seq_puts(m, "\"rcu_sched:\"\n");
-	PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data_csv, m);
-	seq_puts(m, "\"rcu_bh:\"\n");
-	PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data_csv, m);
+	for_each_rcu_flavor(rsp) {
+		seq_printf(m, "\"%s:\"\n", rsp->name);
+		for_each_possible_cpu(cpu)
+			print_one_rcu_data_csv(m, per_cpu_ptr(rsp->rda, cpu));
+	}
 	return 0;
 }
 
@@ -270,15 +287,15 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
 	struct rcu_node *rnp;
 
 	gpnum = rsp->gpnum;
-	seq_printf(m, "c=%lu g=%lu s=%d jfq=%ld j=%x "
+	seq_printf(m, "%s: c=%lu g=%lu s=%d jfq=%ld j=%x "
 		      "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld/%ld\n",
-		   rsp->completed, gpnum, rsp->fqs_state,
+		   rsp->name, rsp->completed, gpnum, rsp->fqs_state,
 		   (long)(rsp->jiffies_force_qs - jiffies),
 		   (int)(jiffies & 0xffff),
 		   rsp->n_force_qs, rsp->n_force_qs_ngp,
 		   rsp->n_force_qs - rsp->n_force_qs_ngp,
 		   rsp->n_force_qs_lh, rsp->qlen_lazy, rsp->qlen);
-	for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < NUM_RCU_NODES; rnp++) {
+	for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < rcu_num_nodes; rnp++) {
 		if (rnp->level != level) {
 			seq_puts(m, "\n");
 			level = rnp->level;
@@ -295,14 +312,10 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
 
 static int show_rcuhier(struct seq_file *m, void *unused)
 {
-#ifdef CONFIG_TREE_PREEMPT_RCU
-	seq_puts(m, "rcu_preempt:\n");
-	print_one_rcu_state(m, &rcu_preempt_state);
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-	seq_puts(m, "rcu_sched:\n");
-	print_one_rcu_state(m, &rcu_sched_state);
-	seq_puts(m, "rcu_bh:\n");
-	print_one_rcu_state(m, &rcu_bh_state);
+	struct rcu_state *rsp;
+
+	for_each_rcu_flavor(rsp)
+		print_one_rcu_state(m, rsp);
 	return 0;
 }
 
@@ -343,11 +356,10 @@ static void show_one_rcugp(struct seq_file *m, struct rcu_state *rsp)
 
 static int show_rcugp(struct seq_file *m, void *unused)
 {
-#ifdef CONFIG_TREE_PREEMPT_RCU
-	show_one_rcugp(m, &rcu_preempt_state);
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-	show_one_rcugp(m, &rcu_sched_state);
-	show_one_rcugp(m, &rcu_bh_state);
+	struct rcu_state *rsp;
+
+	for_each_rcu_flavor(rsp)
+		show_one_rcugp(m, rsp);
 	return 0;
 }
 
@@ -382,28 +394,20 @@ static void print_one_rcu_pending(struct seq_file *m, struct rcu_data *rdp)
 		   rdp->n_rp_need_nothing);
 }
 
-static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp)
+static int show_rcu_pending(struct seq_file *m, void *unused)
 {
 	int cpu;
 	struct rcu_data *rdp;
-
-	for_each_possible_cpu(cpu) {
-		rdp = per_cpu_ptr(rsp->rda, cpu);
-		if (rdp->beenonline)
-			print_one_rcu_pending(m, rdp);
+	struct rcu_state *rsp;
+
+	for_each_rcu_flavor(rsp) {
+		seq_printf(m, "%s:\n", rsp->name);
+		for_each_possible_cpu(cpu) {
+			rdp = per_cpu_ptr(rsp->rda, cpu);
+			if (rdp->beenonline)
+				print_one_rcu_pending(m, rdp);
+		}
 	}
-}
-
-static int show_rcu_pending(struct seq_file *m, void *unused)
-{
-#ifdef CONFIG_TREE_PREEMPT_RCU
-	seq_puts(m, "rcu_preempt:\n");
-	print_rcu_pendings(m, &rcu_preempt_state);
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-	seq_puts(m, "rcu_sched:\n");
-	print_rcu_pendings(m, &rcu_sched_state);
-	seq_puts(m, "rcu_bh:\n");
-	print_rcu_pendings(m, &rcu_bh_state);
 	return 0;
 }
 
@@ -453,6 +457,11 @@ static int __init rcutree_trace_init(void)
 	if (!rcudir)
 		goto free_out;
 
+	retval = debugfs_create_file("rcubarrier", 0444, rcudir,
+						NULL, &rcubarrier_fops);
+	if (!retval)
+		goto free_out;
+
 	retval = debugfs_create_file("rcudata", 0444, rcudir,
 						NULL, &rcudata_fops);
 	if (!retval)
diff --git a/kernel/relay.c b/kernel/relay.c
index ab56a17..e8cd202 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -1235,6 +1235,7 @@ static ssize_t subbuf_splice_actor(struct file *in,
 	struct splice_pipe_desc spd = {
 		.pages = pages,
 		.nr_pages = 0,
+		.nr_pages_max = PIPE_DEF_BUFFERS,
 		.partial = partial,
 		.flags = flags,
 		.ops = &relay_pipe_buf_ops,
@@ -1302,8 +1303,8 @@ static ssize_t subbuf_splice_actor(struct file *in,
                 ret += padding;
 
 out:
-	splice_shrink_spd(pipe, &spd);
-        return ret;
+	splice_shrink_spd(&spd);
+	return ret;
 }
 
 static ssize_t relay_file_splice_read(struct file *in,
diff --git a/kernel/resource.c b/kernel/resource.c
index e1d2b8e..dc8b477 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -722,14 +722,12 @@ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t
 
 	write_lock(&resource_lock);
 
+	if (!parent)
+		goto skip;
+
 	if ((start < parent->start) || (end > parent->end))
 		goto out;
 
-	for (tmp = res->child; tmp; tmp = tmp->sibling) {
-		if ((tmp->start < start) || (tmp->end > end))
-			goto out;
-	}
-
 	if (res->sibling && (res->sibling->start <= end))
 		goto out;
 
@@ -741,6 +739,11 @@ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t
 			goto out;
 	}
 
+skip:
+	for (tmp = res->child; tmp; tmp = tmp->sibling)
+		if ((tmp->start < start) || (tmp->end > end))
+			goto out;
+
 	res->start = start;
 	res->end = end;
 	result = 0;
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index 173ea52..19026ba 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_SMP) += cpupri.o
 obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
 obj-$(CONFIG_SCHEDSTATS) += stats.o
 obj-$(CONFIG_SCHED_DEBUG) += debug.o
+obj-$(CONFIG_NUMA) += numa.o
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index d5594a4..2df035a 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -505,7 +505,7 @@ static inline void init_hrtick(void)
 #ifdef CONFIG_SMP
 
 #ifndef tsk_is_polling
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+#define tsk_is_polling(t) 0
 #endif
 
 void resched_task(struct task_struct *p)
@@ -1797,8 +1797,9 @@ void sched_fork(struct task_struct *p)
 #ifdef CONFIG_SMP
 	plist_node_init(&p->pushable_tasks, MAX_PRIO);
 #endif
-
 	put_cpu();
+
+	select_task_node(p, p->mm, SD_BALANCE_FORK);
 }
 
 /*
@@ -2367,7 +2368,7 @@ void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
  * calc_load - update the avenrun load estimates 10 ticks after the
  * CPUs have updated calc_load_tasks.
  */
-void calc_global_load(unsigned long ticks)
+void calc_global_load(void)
 {
 	long active;
 
@@ -2395,7 +2396,7 @@ void calc_global_load(unsigned long ticks)
 }
 
 /*
- * Called from update_cpu_load() to periodically update this CPU's
+ * Called from update_cpu_load_active() to periodically update this CPU's
  * active count.
  */
 static void calc_load_account_active(struct rq *this_rq)
@@ -2598,12 +2599,14 @@ static void update_cpu_load_active(struct rq *this_rq)
  * sched_exec - execve() is a valuable balancing opportunity, because at
  * this point the task has the smallest effective memory and cache footprint.
  */
-void sched_exec(void)
+void sched_exec(struct mm_struct *mm)
 {
 	struct task_struct *p = current;
 	unsigned long flags;
 	int dest_cpu;
 
+	select_task_node(p, mm, SD_BALANCE_EXEC);
+
 	raw_spin_lock_irqsave(&p->pi_lock, flags);
 	dest_cpu = p->sched_class->select_task_rq(p, SD_BALANCE_EXEC, 0);
 	if (dest_cpu == smp_processor_id())
@@ -5894,6 +5897,11 @@ static void destroy_sched_domains(struct sched_domain *sd, int cpu)
  * SD_SHARE_PKG_RESOURCE set (Last Level Cache Domain) for this
  * allows us to avoid some pointer chasing select_idle_sibling().
  *
+ * Iterate domains and sched_groups downward, assigning CPUs to be
+ * select_idle_sibling() hw buddy.  Cross-wiring hw makes bouncing
+ * due to random perturbation self canceling, ie sw buddies pull
+ * their counterpart to their CPU's hw counterpart.
+ *
  * Also keep a unique ID per domain (we use the first cpu number in
  * the cpumask of the domain), this allows us to quickly tell if
  * two cpus are in the same cache domain, see cpus_share_cache().
@@ -5901,17 +5909,60 @@ static void destroy_sched_domains(struct sched_domain *sd, int cpu)
 DEFINE_PER_CPU(struct sched_domain *, sd_llc);
 DEFINE_PER_CPU(int, sd_llc_id);
 
-static void update_top_cache_domain(int cpu)
+DEFINE_PER_CPU(struct sched_domain *, sd_node);
+
+static void update_domain_cache(int cpu)
 {
 	struct sched_domain *sd;
 	int id = cpu;
 
 	sd = highest_flag_domain(cpu, SD_SHARE_PKG_RESOURCES);
-	if (sd)
+	if (sd) {
+		struct sched_domain *tmp = sd;
+		struct sched_group *sg, *prev;
+		bool right;
+
+		/*
+		 * Traverse to first CPU in group, and count hops
+		 * to cpu from there, switching direction on each
+		 * hop, never ever pointing the last CPU rightward.
+		 */
+		do {
+			id = cpumask_first(sched_domain_span(tmp));
+			prev = sg = tmp->groups;
+			right = 1;
+
+			while (cpumask_first(sched_group_cpus(sg)) != id)
+				sg = sg->next;
+
+			while (!cpumask_test_cpu(cpu, sched_group_cpus(sg))) {
+				prev = sg;
+				sg = sg->next;
+				right = !right;
+			}
+
+			/* A CPU went down, never point back to domain start. */
+			if (right && cpumask_first(sched_group_cpus(sg->next)) == id)
+				right = false;
+
+			sg = right ? sg->next : prev;
+			tmp->idle_buddy = cpumask_first(sched_group_cpus(sg));
+		} while ((tmp = tmp->child));
+
 		id = cpumask_first(sched_domain_span(sd));
+	}
 
 	rcu_assign_pointer(per_cpu(sd_llc, cpu), sd);
 	per_cpu(sd_llc_id, cpu) = id;
+
+	for_each_domain(cpu, sd) {
+		if (cpumask_equal(sched_domain_span(sd),
+				  cpumask_of_node(cpu_to_node(cpu))))
+			goto got_node;
+	}
+	sd = NULL;
+got_node:
+	rcu_assign_pointer(per_cpu(sd_node, cpu), sd);
 }
 
 /*
@@ -5954,7 +6005,7 @@ cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu)
 	rcu_assign_pointer(rq->sd, sd);
 	destroy_sched_domains(tmp, cpu);
 
-	update_top_cache_domain(cpu);
+	update_domain_cache(cpu);
 }
 
 /* cpus with isolated domains */
@@ -6378,6 +6429,38 @@ static struct sched_domain_topology_level *sched_domain_topology = default_topol
 
 #ifdef CONFIG_NUMA
 
+/*
+ * Requeues a task ensuring its on the right load-balance list so
+ * that it might get migrated to its new home.
+ *
+ * Note that we cannot actively migrate ourselves since our callers
+ * can be from atomic context. We rely on the regular load-balance
+ * mechanisms to move us around -- its all preference anyway.
+ */
+void sched_setnode(struct task_struct *p, int node)
+{
+	unsigned long flags;
+	int on_rq, running;
+	struct rq *rq;
+
+	rq = task_rq_lock(p, &flags);
+	on_rq = p->on_rq;
+	running = task_current(rq, p);
+
+	if (on_rq)
+		dequeue_task(rq, p, 0);
+	if (running)
+		p->sched_class->put_prev_task(rq, p);
+
+	p->node = node;
+
+	if (running)
+		p->sched_class->set_curr_task(rq);
+	if (on_rq)
+		enqueue_task(rq, p, 0);
+	task_rq_unlock(rq, p, &flags);
+}
+
 static int sched_domains_numa_levels;
 static int *sched_domains_numa_distance;
 static struct cpumask ***sched_domains_numa_masks;
@@ -6422,6 +6505,7 @@ sd_numa_init(struct sched_domain_topology_level *tl, int cpu)
 					| 0*SD_SHARE_PKG_RESOURCES
 					| 1*SD_SERIALIZE
 					| 0*SD_PREFER_SIBLING
+					| 1*SD_NUMA
 					| sd_local_flags(level)
 					,
 		.last_balance		= jiffies,
@@ -6967,34 +7051,66 @@ match2:
 	mutex_unlock(&sched_domains_mutex);
 }
 
+static int num_cpus_frozen;	/* used to mark begin/end of suspend/resume */
+
 /*
  * Update cpusets according to cpu_active mask.  If cpusets are
  * disabled, cpuset_update_active_cpus() becomes a simple wrapper
  * around partition_sched_domains().
+ *
+ * If we come here as part of a suspend/resume, don't touch cpusets because we
+ * want to restore it back to its original state upon resume anyway.
  */
 static int cpuset_cpu_active(struct notifier_block *nfb, unsigned long action,
 			     void *hcpu)
 {
-	switch (action & ~CPU_TASKS_FROZEN) {
+	switch (action) {
+	case CPU_ONLINE_FROZEN:
+	case CPU_DOWN_FAILED_FROZEN:
+
+		/*
+		 * num_cpus_frozen tracks how many CPUs are involved in suspend
+		 * resume sequence. As long as this is not the last online
+		 * operation in the resume sequence, just build a single sched
+		 * domain, ignoring cpusets.
+		 */
+		num_cpus_frozen--;
+		if (likely(num_cpus_frozen)) {
+			partition_sched_domains(1, NULL, NULL);
+			break;
+		}
+
+		/*
+		 * This is the last CPU online operation. So fall through and
+		 * restore the original sched domains by considering the
+		 * cpuset configurations.
+		 */
+
 	case CPU_ONLINE:
 	case CPU_DOWN_FAILED:
-		cpuset_update_active_cpus();
-		return NOTIFY_OK;
+		cpuset_update_active_cpus(true);
+		break;
 	default:
 		return NOTIFY_DONE;
 	}
+	return NOTIFY_OK;
 }
 
 static int cpuset_cpu_inactive(struct notifier_block *nfb, unsigned long action,
 			       void *hcpu)
 {
-	switch (action & ~CPU_TASKS_FROZEN) {
+	switch (action) {
 	case CPU_DOWN_PREPARE:
-		cpuset_update_active_cpus();
-		return NOTIFY_OK;
+		cpuset_update_active_cpus(false);
+		break;
+	case CPU_DOWN_PREPARE_FROZEN:
+		num_cpus_frozen++;
+		partition_sched_domains(1, NULL, NULL);
+		break;
 	default:
 		return NOTIFY_DONE;
 	}
+	return NOTIFY_OK;
 }
 
 void __init sched_init_smp(void)
@@ -7181,6 +7297,11 @@ void __init sched_init(void)
 		rq->avg_idle = 2*sysctl_sched_migration_cost;
 
 		INIT_LIST_HEAD(&rq->cfs_tasks);
+#ifdef CONFIG_NUMA
+		INIT_LIST_HEAD(&rq->offnode_tasks);
+		rq->offnode_running = 0;
+		rq->offnode_weight = 0;
+#endif
 
 		rq_attach_root(rq, &def_root_domain);
 #ifdef CONFIG_NO_HZ
@@ -7230,6 +7351,7 @@ void __init sched_init(void)
 	idle_thread_set_boot_cpu();
 #endif
 	init_sched_fair_class();
+	init_sched_numa();
 
 	scheduler_running = 1;
 }
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 6f79596..c09a4e7 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -132,6 +132,9 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
 	SEQ_printf(m, "%15Ld %15Ld %15Ld.%06ld %15Ld.%06ld %15Ld.%06ld",
 		0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L);
 #endif
+#ifdef CONFIG_NUMA
+	SEQ_printf(m, " %d/%d", p->node, cpu_to_node(task_cpu(p)));
+#endif
 #ifdef CONFIG_CGROUP_SCHED
 	SEQ_printf(m, " %s", task_group_path(task_group(p)));
 #endif
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index c099cc6..3704ad3 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/profile.h>
 #include <linux/interrupt.h>
+#include <linux/random.h>
 
 #include <trace/events/sched.h>
 
@@ -783,8 +784,10 @@ account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
 	if (!parent_entity(se))
 		update_load_add(&rq_of(cfs_rq)->load, se->load.weight);
 #ifdef CONFIG_SMP
-	if (entity_is_task(se))
-		list_add(&se->group_node, &rq_of(cfs_rq)->cfs_tasks);
+	if (entity_is_task(se)) {
+		if (!account_numa_enqueue(task_of(se)))
+			list_add(&se->group_node, &rq_of(cfs_rq)->cfs_tasks);
+	}
 #endif
 	cfs_rq->nr_running++;
 }
@@ -795,8 +798,10 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
 	update_load_sub(&cfs_rq->load, se->load.weight);
 	if (!parent_entity(se))
 		update_load_sub(&rq_of(cfs_rq)->load, se->load.weight);
-	if (entity_is_task(se))
+	if (entity_is_task(se)) {
 		list_del_init(&se->group_node);
+		account_numa_dequeue(task_of(se));
+	}
 	cfs_rq->nr_running--;
 }
 
@@ -2637,8 +2642,6 @@ static int select_idle_sibling(struct task_struct *p, int target)
 	int cpu = smp_processor_id();
 	int prev_cpu = task_cpu(p);
 	struct sched_domain *sd;
-	struct sched_group *sg;
-	int i;
 
 	/*
 	 * If the task is going to be woken-up on this cpu and if it is
@@ -2655,29 +2658,17 @@ static int select_idle_sibling(struct task_struct *p, int target)
 		return prev_cpu;
 
 	/*
-	 * Otherwise, iterate the domains and find an elegible idle cpu.
+	 * Otherwise, check assigned siblings to find an elegible idle cpu.
 	 */
 	sd = rcu_dereference(per_cpu(sd_llc, target));
-	for_each_lower_domain(sd) {
-		sg = sd->groups;
-		do {
-			if (!cpumask_intersects(sched_group_cpus(sg),
-						tsk_cpus_allowed(p)))
-				goto next;
-
-			for_each_cpu(i, sched_group_cpus(sg)) {
-				if (!idle_cpu(i))
-					goto next;
-			}
 
-			target = cpumask_first_and(sched_group_cpus(sg),
-					tsk_cpus_allowed(p));
-			goto done;
-next:
-			sg = sg->next;
-		} while (sg != sd->groups);
+	for_each_lower_domain(sd) {
+		if (!cpumask_test_cpu(sd->idle_buddy, tsk_cpus_allowed(p)))
+			continue;
+		if (idle_cpu(sd->idle_buddy))
+			return sd->idle_buddy;
 	}
-done:
+
 	return target;
 }
 
@@ -2702,6 +2693,7 @@ select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flags)
 	int want_affine = 0;
 	int want_sd = 1;
 	int sync = wake_flags & WF_SYNC;
+	int node = tsk_home_node(p);
 
 	if (p->nr_cpus_allowed == 1)
 		return prev_cpu;
@@ -2713,6 +2705,29 @@ select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flags)
 	}
 
 	rcu_read_lock();
+	if (sched_feat_numa(NUMA_BIAS) && node != -1) {
+		int node_cpu;
+
+		node_cpu = cpumask_any_and(tsk_cpus_allowed(p), cpumask_of_node(node));
+		if (node_cpu >= nr_cpu_ids)
+			goto find_sd;
+
+		/*
+		 * For fork,exec find the idlest cpu in the home-node.
+		 */
+		if (sd_flag & (SD_BALANCE_FORK|SD_BALANCE_EXEC)) {
+			new_cpu = cpu = node_cpu;
+			sd = per_cpu(sd_node, cpu);
+			goto pick_idlest;
+		}
+
+		/*
+		 * For wake, pretend we were running in the home-node.
+		 */
+		prev_cpu = node_cpu;
+	}
+
+find_sd:
 	for_each_domain(cpu, tmp) {
 		if (!(tmp->flags & SD_LOAD_BALANCE))
 			continue;
@@ -2766,6 +2781,7 @@ select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flags)
 		goto unlock;
 	}
 
+pick_idlest:
 	while (sd) {
 		int load_idx = sd->forkexec_idx;
 		struct sched_group *group;
@@ -3082,9 +3098,15 @@ struct lb_env {
 	long			imbalance;
 	unsigned int		flags;
 
+	struct list_head	*tasks;
+
 	unsigned int		loop;
 	unsigned int		loop_break;
 	unsigned int		loop_max;
+
+	struct rq *		(*find_busiest_queue)(struct lb_env *,
+						      struct sched_group *,
+						      const struct cpumask *);
 };
 
 /*
@@ -3099,6 +3121,23 @@ static void move_task(struct task_struct *p, struct lb_env *env)
 	check_preempt_curr(env->dst_rq, p, 0);
 }
 
+static int task_numa_hot(struct task_struct *p, int from_cpu, int to_cpu)
+{
+	int from_dist, to_dist;
+	int node = tsk_home_node(p);
+
+	if (!sched_feat_numa(NUMA_HOT) || node == -1)
+		return 0; /* no node preference */
+
+	from_dist = node_distance(cpu_to_node(from_cpu), node);
+	to_dist = node_distance(cpu_to_node(to_cpu), node);
+
+	if (to_dist < from_dist)
+		return 0; /* getting closer is ok */
+
+	return 1; /* stick to where we are */
+}
+
 /*
  * Is this task likely cache-hot:
  */
@@ -3162,6 +3201,7 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
 	 */
 
 	tsk_cache_hot = task_hot(p, env->src_rq->clock_task, env->sd);
+	tsk_cache_hot |= task_numa_hot(p, env->src_cpu, env->dst_cpu);
 	if (!tsk_cache_hot ||
 		env->sd->nr_balance_failed > env->sd->cache_nice_tries) {
 #ifdef CONFIG_SCHEDSTATS
@@ -3187,11 +3227,11 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
  *
  * Called with both runqueues locked.
  */
-static int move_one_task(struct lb_env *env)
+static int __move_one_task(struct lb_env *env)
 {
 	struct task_struct *p, *n;
 
-	list_for_each_entry_safe(p, n, &env->src_rq->cfs_tasks, se.group_node) {
+	list_for_each_entry_safe(p, n, env->tasks, se.group_node) {
 		if (throttled_lb_pair(task_group(p), env->src_rq->cpu, env->dst_cpu))
 			continue;
 
@@ -3210,7 +3250,20 @@ static int move_one_task(struct lb_env *env)
 	return 0;
 }
 
-static unsigned long task_h_load(struct task_struct *p);
+static int move_one_task(struct lb_env *env)
+{
+	if (sched_feat_numa(NUMA_PULL)) {
+		env->tasks = offnode_tasks(env->src_rq);
+		if (__move_one_task(env))
+			return 1;
+	}
+
+	env->tasks = &env->src_rq->cfs_tasks;
+	if (__move_one_task(env))
+		return 1;
+
+	return 0;
+}
 
 static const unsigned int sched_nr_migrate_break = 32;
 
@@ -3223,7 +3276,6 @@ static const unsigned int sched_nr_migrate_break = 32;
  */
 static int move_tasks(struct lb_env *env)
 {
-	struct list_head *tasks = &env->src_rq->cfs_tasks;
 	struct task_struct *p;
 	unsigned long load;
 	int pulled = 0;
@@ -3231,8 +3283,9 @@ static int move_tasks(struct lb_env *env)
 	if (env->imbalance <= 0)
 		return 0;
 
-	while (!list_empty(tasks)) {
-		p = list_first_entry(tasks, struct task_struct, se.group_node);
+again:
+	while (!list_empty(env->tasks)) {
+		p = list_first_entry(env->tasks, struct task_struct, se.group_node);
 
 		env->loop++;
 		/* We've more or less seen every task there is, call it quits */
@@ -3243,7 +3296,7 @@ static int move_tasks(struct lb_env *env)
 		if (env->loop > env->loop_break) {
 			env->loop_break += sched_nr_migrate_break;
 			env->flags |= LBF_NEED_BREAK;
-			break;
+			goto out;
 		}
 
 		if (throttled_lb_pair(task_group(p), env->src_cpu, env->dst_cpu))
@@ -3271,7 +3324,7 @@ static int move_tasks(struct lb_env *env)
 		 * the critical section.
 		 */
 		if (env->idle == CPU_NEWLY_IDLE)
-			break;
+			goto out;
 #endif
 
 		/*
@@ -3279,13 +3332,20 @@ static int move_tasks(struct lb_env *env)
 		 * weighted load.
 		 */
 		if (env->imbalance <= 0)
-			break;
+			goto out;
 
 		continue;
 next:
-		list_move_tail(&p->se.group_node, tasks);
+		list_move_tail(&p->se.group_node, env->tasks);
+	}
+
+	if (env->tasks == offnode_tasks(env->src_rq)) {
+		env->tasks = &env->src_rq->cfs_tasks;
+		env->loop = 0;
+		goto again;
 	}
 
+out:
 	/*
 	 * Right now, this is one of only two places move_task() is called,
 	 * so we can safely collect move_task() stats here rather than
@@ -3378,7 +3438,7 @@ static void update_h_load(long cpu)
 	rcu_read_unlock();
 }
 
-static unsigned long task_h_load(struct task_struct *p)
+unsigned long task_h_load(struct task_struct *p)
 {
 	struct cfs_rq *cfs_rq = task_cfs_rq(p);
 	unsigned long load;
@@ -3397,7 +3457,7 @@ static inline void update_h_load(long cpu)
 {
 }
 
-static unsigned long task_h_load(struct task_struct *p)
+unsigned long task_h_load(struct task_struct *p)
 {
 	return p->se.load.weight;
 }
@@ -3432,6 +3492,11 @@ struct sd_lb_stats {
 	unsigned int  busiest_group_weight;
 
 	int group_imb; /* Is there imbalance in this sd */
+#ifdef CONFIG_NUMA
+	struct sched_group *numa_group; /* group which has offnode_tasks */
+	unsigned long numa_group_weight;
+	unsigned long numa_group_running;
+#endif
 };
 
 /*
@@ -3447,6 +3512,10 @@ struct sg_lb_stats {
 	unsigned long group_weight;
 	int group_imb; /* Is there an imbalance in the group ? */
 	int group_has_capacity; /* Is there extra capacity in the group? */
+#ifdef CONFIG_NUMA
+	unsigned long numa_weight;
+	unsigned long numa_running;
+#endif
 };
 
 /**
@@ -3475,6 +3544,117 @@ static inline int get_sd_load_idx(struct sched_domain *sd,
 	return load_idx;
 }
 
+#ifdef CONFIG_NUMA
+static inline void update_sg_numa_stats(struct sg_lb_stats *sgs, struct rq *rq)
+{
+	sgs->numa_weight += rq->offnode_weight;
+	sgs->numa_running += rq->offnode_running;
+}
+
+/*
+ * Since the offnode lists are indiscriminate (they contain tasks for all other
+ * nodes) it is impossible to say if there's any task on there that wants to
+ * move towards the pulling cpu. Therefore select a random offnode list to pull
+ * from such that eventually we'll try them all.
+ */
+static inline bool pick_numa_rand(void)
+{
+	return get_random_int() & 1;
+}
+
+/*
+ * Select a random group that has offnode tasks as sds->numa_group
+ */
+static inline void update_sd_numa_stats(struct sched_domain *sd,
+		struct sched_group *group, struct sd_lb_stats *sds,
+		int local_group, struct sg_lb_stats *sgs)
+{
+	if (!(sd->flags & SD_NUMA))
+		return;
+
+	if (local_group)
+		return;
+
+	if (!sgs->numa_running)
+		return;
+
+	if (!sds->numa_group || pick_numa_rand()) {
+		sds->numa_group = group;
+		sds->numa_group_weight = sgs->numa_weight;
+		sds->numa_group_running = sgs->numa_running;
+	}
+}
+
+/*
+ * Pick a random queue from the group that has offnode tasks.
+ */
+static struct rq *find_busiest_numa_queue(struct lb_env *env,
+					  struct sched_group *group,
+					  const struct cpumask *cpus)
+{
+	struct rq *busiest = NULL, *rq;
+	int cpu;
+
+	for_each_cpu_and(cpu, sched_group_cpus(group), cpus) {
+		rq = cpu_rq(cpu);
+		if (!rq->offnode_running)
+			continue;
+		if (!busiest || pick_numa_rand())
+			busiest = rq;
+	}
+
+	return busiest;
+}
+
+/*
+ * Called in case of no other imbalance, if there is a queue running offnode
+ * tasksk we'll say we're imbalanced anyway to nudge these tasks towards their
+ * proper node.
+ */
+static inline int check_numa_busiest_group(struct lb_env *env, struct sd_lb_stats *sds)
+{
+	if (!sched_feat(NUMA_PULL_BIAS))
+		return 0;
+
+	if (!sds->numa_group)
+		return 0;
+
+	env->imbalance = sds->numa_group_weight / sds->numa_group_running;
+	sds->busiest = sds->numa_group;
+	env->find_busiest_queue = find_busiest_numa_queue;
+	return 1;
+}
+
+static inline bool need_active_numa_balance(struct lb_env *env)
+{
+	return env->find_busiest_queue == find_busiest_numa_queue &&
+			env->src_rq->offnode_running == 1 &&
+			env->src_rq->nr_running == 1;
+}
+
+#else /* CONFIG_NUMA */
+
+static inline void update_sg_numa_stats(struct sg_lb_stats *sgs, struct rq *rq)
+{
+}
+
+static inline void update_sd_numa_stats(struct sched_domain *sd,
+		struct sched_group *group, struct sd_lb_stats *sds,
+		int local_group, struct sg_lb_stats *sgs)
+{
+}
+
+static inline int check_numa_busiest_group(struct lb_env *env, struct sd_lb_stats *sds)
+{
+	return 0;
+}
+
+static inline bool need_active_numa_balance(struct lb_env *env)
+{
+	return false;
+}
+#endif /* CONFIG_NUMA */
+
 unsigned long default_scale_freq_power(struct sched_domain *sd, int cpu)
 {
 	return SCHED_POWER_SCALE;
@@ -3692,6 +3872,8 @@ static inline void update_sg_lb_stats(struct lb_env *env,
 		sgs->sum_weighted_load += weighted_cpuload(i);
 		if (idle_cpu(i))
 			sgs->idle_cpus++;
+
+		update_sg_numa_stats(sgs, rq);
 	}
 
 	/*
@@ -3848,6 +4030,8 @@ static inline void update_sd_lb_stats(struct lb_env *env,
 			sds->group_imb = sgs.group_imb;
 		}
 
+		update_sd_numa_stats(env->sd, sg, sds, local_group, &sgs);
+
 		sg = sg->next;
 	} while (sg != env->sd->groups);
 }
@@ -4135,6 +4319,9 @@ force_balance:
 	return sds.busiest;
 
 out_balanced:
+	if (check_numa_busiest_group(env, &sds))
+		return sds.busiest;
+
 ret:
 	env->imbalance = 0;
 	return NULL;
@@ -4214,6 +4401,9 @@ static int need_active_balance(struct lb_env *env)
 			return 1;
 	}
 
+	if (need_active_numa_balance(env))
+		return 1;
+
 	return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2);
 }
 
@@ -4234,11 +4424,12 @@ static int load_balance(int this_cpu, struct rq *this_rq,
 	struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask);
 
 	struct lb_env env = {
-		.sd		= sd,
-		.dst_cpu	= this_cpu,
-		.dst_rq		= this_rq,
-		.idle		= idle,
-		.loop_break	= sched_nr_migrate_break,
+		.sd		    = sd,
+		.dst_cpu	    = this_cpu,
+		.dst_rq		    = this_rq,
+		.idle		    = idle,
+		.loop_break	    = sched_nr_migrate_break,
+		.find_busiest_queue = find_busiest_queue,
 	};
 
 	cpumask_copy(cpus, cpu_active_mask);
@@ -4256,11 +4447,13 @@ redo:
 		goto out_balanced;
 	}
 
-	busiest = find_busiest_queue(&env, group, cpus);
+	busiest = env.find_busiest_queue(&env, group, cpus);
 	if (!busiest) {
 		schedstat_inc(sd, lb_nobusyq[idle]);
 		goto out_balanced;
 	}
+	env.src_rq  = busiest;
+	env.src_cpu = busiest->cpu;
 
 	BUG_ON(busiest == this_rq);
 
@@ -4275,9 +4468,11 @@ redo:
 		 * correctly treated as an imbalance.
 		 */
 		env.flags |= LBF_ALL_PINNED;
-		env.src_cpu   = busiest->cpu;
-		env.src_rq    = busiest;
-		env.loop_max  = min(sysctl_sched_nr_migrate, busiest->nr_running);
+		env.loop_max = min(sysctl_sched_nr_migrate, busiest->nr_running);
+		if (sched_feat_numa(NUMA_PULL))
+			env.tasks = offnode_tasks(busiest);
+		else
+			env.tasks = &busiest->cfs_tasks;
 
 more_balance:
 		local_irq_save(flags);
diff --git a/kernel/sched/features.h b/kernel/sched/features.h
index de00a48..dc65178 100644
--- a/kernel/sched/features.h
+++ b/kernel/sched/features.h
@@ -69,3 +69,15 @@ SCHED_FEAT(TTWU_QUEUE, true)
 SCHED_FEAT(FORCE_SD_OVERLAP, false)
 SCHED_FEAT(RT_RUNTIME_SHARE, true)
 SCHED_FEAT(LB_MIN, false)
+
+#ifdef CONFIG_NUMA
+SCHED_FEAT(NUMA_HOT,       true)
+SCHED_FEAT(NUMA_BIAS,      true)
+SCHED_FEAT(NUMA_PULL,      true)
+SCHED_FEAT(NUMA_PULL_BIAS, true)
+SCHED_FEAT(NUMA_BALANCE,   true)
+SCHED_FEAT(NUMA_SELECT,    true)
+SCHED_FEAT(NUMA_SLOW,      false)
+SCHED_FEAT(NUMA_BALANCE_FILTER, false)
+#endif
+
diff --git a/kernel/sched/numa.c b/kernel/sched/numa.c
new file mode 100644
index 0000000..002f71c
--- /dev/null
+++ b/kernel/sched/numa.c
@@ -0,0 +1,855 @@
+/*
+ * NUMA scheduler
+ *
+ *  Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *
+ * With input and fixes from:
+ *
+ *  Ingo Molnar <mingo@elte.hu>
+ *  Bharata B Rao <bharata@linux.vnet.ibm.com>
+ *  Dan Smith <danms@us.ibm.com>
+ *
+ * For licensing details see kernel-base/COPYING
+ */
+
+#include <linux/mempolicy.h>
+#include <linux/kthread.h>
+
+#include "sched.h"
+
+
+static const int numa_balance_interval = 2 * HZ; /* 2 seconds */
+
+struct numa_ops {
+	unsigned long	(*mem_load)(struct numa_entity *ne);
+	unsigned long	(*cpu_load)(struct numa_entity *ne);
+
+	void		(*mem_migrate)(struct numa_entity *ne, int node);
+	void		(*cpu_migrate)(struct numa_entity *ne, int node);
+
+	bool		(*can_migrate)(struct numa_entity *ne, int node);
+
+	bool		(*tryget)(struct numa_entity *ne);
+	void		(*put)(struct numa_entity *ne);
+};
+
+struct numa_cpu_load {
+	unsigned long	remote; /* load of tasks running away from their home node */
+	unsigned long	all;	/* load of tasks that should be running on this node */
+};
+
+static struct numa_cpu_load **numa_load_array;
+
+static struct {
+	spinlock_t		lock;
+	unsigned long		load;
+} max_mem_load = {
+	.lock = __SPIN_LOCK_UNLOCKED(max_mem_load.lock),
+	.load = 0,
+};
+
+/*
+ * Assumes symmetric NUMA -- that is, each node is of equal size.
+ */
+static void set_max_mem_load(unsigned long load)
+{
+	unsigned long old_load;
+
+	spin_lock(&max_mem_load.lock);
+	old_load = max_mem_load.load;
+	if (!old_load)
+		old_load = load;
+	max_mem_load.load = (old_load + load) >> 1;
+	spin_unlock(&max_mem_load.lock);
+}
+
+static unsigned long get_max_mem_load(void)
+{
+	return max_mem_load.load;
+}
+
+struct node_queue {
+	struct task_struct	*numad;
+
+	unsigned long		remote_cpu_load;
+	unsigned long		cpu_load;
+
+	unsigned long		prev_numa_foreign;
+	unsigned long		remote_mem_load;
+
+	spinlock_t		lock;
+	struct list_head	entity_list;
+	int			nr_processes;
+
+	unsigned long		next_schedule;
+	int			node;
+};
+
+static struct node_queue **nqs;
+
+static inline struct node_queue *nq_of(int node)
+{
+	return nqs[node];
+}
+
+static inline struct node_queue *this_nq(void)
+{
+	return nq_of(numa_node_id());
+}
+
+bool account_numa_enqueue(struct task_struct *p)
+{
+	int home_node = tsk_home_node(p);
+	int cpu = task_cpu(p);
+	int node = cpu_to_node(cpu);
+	struct rq *rq = cpu_rq(cpu);
+	struct numa_cpu_load *nl;
+	unsigned long load;
+
+	/*
+	 * not actually an auto-numa task, ignore
+	 */
+	if (home_node == -1)
+		return false;
+
+	load = task_h_load(p);
+	nl = this_cpu_ptr(numa_load_array[home_node]);
+	p->numa_remote = (node != home_node);
+	p->numa_contrib = load;
+	nl->all += load;
+	if (p->numa_remote)
+		nl->remote += load;
+
+	/*
+	 * the task is on its home-node, we're done, the rest is offnode
+	 * accounting.
+	 */
+	if (!p->numa_remote)
+		return false;
+
+	list_add_tail(&p->se.group_node, &rq->offnode_tasks);
+	rq->offnode_running++;
+	rq->offnode_weight += load;
+
+	return true;
+}
+
+void account_numa_dequeue(struct task_struct *p)
+{
+	int home_node = tsk_home_node(p);
+	struct numa_cpu_load *nl;
+	struct rq *rq;
+
+	/*
+	 * not actually an auto-numa task, ignore
+	 */
+	if (home_node == -1)
+		return;
+
+	nl = this_cpu_ptr(numa_load_array[home_node]);
+	nl->all -= p->numa_contrib;
+	if (p->numa_remote)
+		nl->remote -= p->numa_contrib;
+
+	/*
+	 * the task is on its home-node, we're done, the rest is offnode
+	 * accounting.
+	 */
+	if (!p->numa_remote)
+		return;
+
+	rq = task_rq(p);
+	rq->offnode_running--;
+	rq->offnode_weight -= p->numa_contrib;
+}
+
+static inline struct mm_struct *ne_mm(struct numa_entity *ne)
+{
+	return container_of(ne, struct mm_struct, numa);
+}
+
+static inline struct task_struct *ne_owner(struct numa_entity *ne)
+{
+	return rcu_dereference(ne_mm(ne)->owner);
+}
+
+static unsigned long process_cpu_load(struct numa_entity *ne)
+{
+	unsigned long load = 0;
+	struct task_struct *t, *p;
+
+	rcu_read_lock();
+	t = p = ne_owner(ne);
+	if (p) do {
+		load += t->numa_contrib;
+	} while ((t = next_thread(t)) != p);
+	rcu_read_unlock();
+
+	return load;
+}
+
+static unsigned long process_mem_load(struct numa_entity *ne)
+{
+	return get_mm_counter(ne_mm(ne), MM_ANONPAGES);
+}
+
+static void process_cpu_migrate(struct numa_entity *ne, int node)
+{
+	struct task_struct *p, *t;
+
+	rcu_read_lock();
+	t = p = ne_owner(ne);
+	if (p) do {
+		sched_setnode(t, node);
+	} while ((t = next_thread(t)) != p);
+	rcu_read_unlock();
+}
+
+static void process_mem_migrate(struct numa_entity *ne, int node)
+{
+	lazy_migrate_process(ne_mm(ne), node);
+}
+
+static bool __task_can_migrate(struct task_struct *t, u64 *runtime, int node)
+{
+#ifdef CONFIG_CPUSETS
+	if (!node_isset(node, t->mems_allowed))
+		return false;
+#endif
+
+	if (!cpumask_intersects(cpumask_of_node(node), tsk_cpus_allowed(t)))
+		return false;
+
+	*runtime += t->se.sum_exec_runtime; // @#$#@ 32bit
+
+	return true;
+}
+
+static bool process_can_migrate(struct numa_entity *ne, int node)
+{
+	struct task_struct *p, *t;
+	bool allowed = false;
+	u64 runtime = 0;
+
+	rcu_read_lock();
+	t = p = ne_owner(ne);
+	if (p) do {
+		allowed = __task_can_migrate(t, &runtime, node);
+		if (!allowed)
+			break;
+	} while ((t = next_thread(t)) != p);
+	rcu_read_unlock();
+
+	/*
+	 * Don't bother migrating memory if there's less than 1 second
+	 * of runtime on the tasks.
+	 */
+	return allowed && runtime > NSEC_PER_SEC;
+}
+
+static bool process_tryget(struct numa_entity *ne)
+{
+	/*
+	 * This is possible when we hold &nq_of(ne->node)->lock since then
+	 * numa_exit() will block on that lock, we can't however write an
+	 * assertion to check this, since if we don't hold the lock that
+	 * expression isn't safe to evaluate.
+	 */
+	return atomic_inc_not_zero(&ne_mm(ne)->mm_users);
+}
+
+static void process_put(struct numa_entity *ne)
+{
+	mmput(ne_mm(ne));
+}
+
+static const struct numa_ops process_numa_ops = {
+	.mem_load	= process_mem_load,
+	.cpu_load	= process_cpu_load,
+
+	.mem_migrate	= process_mem_migrate,
+	.cpu_migrate	= process_cpu_migrate,
+
+	.can_migrate	= process_can_migrate,
+
+	.tryget		= process_tryget,
+	.put		= process_put,
+};
+
+static struct node_queue *lock_ne_nq(struct numa_entity *ne)
+{
+	struct node_queue *nq;
+	int node;
+
+	for (;;) {
+		node = ACCESS_ONCE(ne->node);
+		/*
+		 * Make sure any dequeue is properly done before
+		 * we can observe node == -1, see dequeue_ne().
+		 */
+		smp_rmb();
+		if (node == -1)
+			return NULL;
+
+		nq = nq_of(node);
+		spin_lock(&nq->lock);
+		if (likely(ne->node == node))
+			break;
+		spin_unlock(&nq->lock);
+	}
+
+	return nq;
+}
+
+static void double_lock_nq(struct node_queue *nq1, struct node_queue *nq2)
+{
+	if (nq1 > nq2)
+		swap(nq1, nq2);
+
+	spin_lock(&nq1->lock);
+	if (nq2 != nq1)
+		spin_lock_nested(&nq2->lock, SINGLE_DEPTH_NESTING);
+}
+
+static void double_unlock_nq(struct node_queue *nq1, struct node_queue *nq2)
+{
+	if (nq1 > nq2)
+		swap(nq1, nq2);
+
+	if (nq2 != nq1)
+		spin_unlock(&nq2->lock);
+	spin_unlock(&nq1->lock);
+}
+
+static void __enqueue_ne(struct node_queue *nq, struct numa_entity *ne)
+{
+	ne->node = nq->node;
+	list_add_tail(&ne->numa_entry, &nq->entity_list);
+	nq->nr_processes++;
+}
+
+static void __dequeue_ne(struct node_queue *nq, struct numa_entity *ne)
+{
+	list_del(&ne->numa_entry);
+	nq->nr_processes--;
+	BUG_ON(nq->nr_processes < 0);
+}
+
+static void enqueue_ne(struct numa_entity *ne, int node)
+{
+	struct node_queue *nq = nq_of(node);
+
+	BUG_ON(ne->node != -1);
+
+	ne->nops->cpu_migrate(ne, node);
+	ne->nops->mem_migrate(ne, node);
+
+	spin_lock(&nq->lock);
+	__enqueue_ne(nq, ne);
+	spin_unlock(&nq->lock);
+}
+
+static void dequeue_ne(struct numa_entity *ne)
+{
+	struct node_queue *nq;
+
+	nq = lock_ne_nq(ne);
+	if (nq) {
+		__dequeue_ne(nq, ne);
+		/*
+		 * ensure the dequeue is complete before lock_ne_nq()
+		 * can observe the ne->node == -1.
+		 */
+		smp_wmb();
+		ne->node = -1;
+		spin_unlock(&nq->lock);
+	}
+}
+
+static void init_ne(struct numa_entity *ne, const struct numa_ops *nops)
+{
+	ne->node = -1;
+	ne->nops = nops;
+}
+
+void mm_init_numa(struct mm_struct *mm)
+{
+	init_ne(&mm->numa, &process_numa_ops);
+}
+
+void exit_numa(struct mm_struct *mm)
+{
+	dequeue_ne(&mm->numa);
+}
+
+static inline unsigned long node_pages_load(int node)
+{
+	unsigned long pages = 0;
+
+	pages += node_page_state(node, NR_ANON_PAGES);
+	pages += node_page_state(node, NR_ACTIVE_FILE);
+
+	return pages;
+}
+
+static int find_idlest_node(int this_node)
+{
+	unsigned long mem_load, cpu_load;
+	unsigned long min_cpu_load;
+	unsigned long this_cpu_load;
+	int min_node;
+	int node, cpu;
+
+	min_node = -1;
+	this_cpu_load = min_cpu_load = ULONG_MAX;
+
+	// XXX should be sched_domain aware
+	for_each_online_node(node) {
+		struct node_queue *nq = nq_of(node);
+		/*
+		 * Pick the node that has least cpu load provided there's no
+		 * foreign memory load.
+		 *
+		 * XXX if all nodes were to have foreign allocations we'd OOM,
+		 *     however check the low-pass filter in update_node_load().
+		 */
+		mem_load = nq->remote_mem_load;
+		if (mem_load)
+			continue;
+
+		cpu_load = 0;
+		for_each_cpu_mask(cpu, *cpumask_of_node(node))
+			cpu_load += cpu_rq(cpu)->load.weight;
+		cpu_load += nq->remote_cpu_load;
+
+		if (this_node == node)
+			this_cpu_load = cpu_load;
+
+		if (cpu_load < min_cpu_load) {
+			min_cpu_load = cpu_load;
+			min_node = node;
+		}
+	}
+
+	/*
+	 * If there's no choice, stick to where we are.
+	 */
+	if (min_node == -1)
+		return this_node;
+
+	/*
+	 * Add a little hysteresis so we don't hard-interleave over nodes
+	 * scattering workloads.
+	 */
+	if (this_cpu_load != ULONG_MAX && this_node != min_node) {
+		if (this_cpu_load * 100 < min_cpu_load * 110)
+			return this_node;
+	}
+
+	return min_node;
+}
+
+void select_task_node(struct task_struct *p, struct mm_struct *mm, int sd_flags)
+{
+	int node;
+
+	if (!sched_feat(NUMA_SELECT)) {
+		p->node = -1;
+		return;
+	}
+
+	if (!mm)
+		return;
+
+	/*
+	 * If there's an explicit task policy set, bail.
+	 */
+	if (p->flags & PF_MEMPOLICY) {
+		p->node = -1;
+		return;
+	}
+
+	if (sd_flags & SD_BALANCE_FORK) {
+		/* For new threads, set the home-node. */
+		if (mm == current->mm) {
+			p->node = mm->numa.node;
+			return;
+		}
+	}
+
+	node = find_idlest_node(p->node);
+	if (node == -1)
+		node = numa_node_id();
+	enqueue_ne(&mm->numa, node);
+}
+
+__init void init_sched_numa(void)
+{
+	int node;
+
+	numa_load_array = kzalloc(sizeof(struct numa_cpu_load *) * nr_node_ids, GFP_KERNEL);
+	BUG_ON(!numa_load_array);
+
+	for_each_node(node) {
+		numa_load_array[node] = alloc_percpu(struct numa_cpu_load);
+		BUG_ON(!numa_load_array[node]);
+	}
+}
+
+static void add_load(unsigned long *load, unsigned long new_load)
+{
+	if (sched_feat(NUMA_SLOW)) {
+		*load = (*load + new_load) >> 1;
+		return;
+	}
+
+	*load = new_load;
+}
+
+/*
+ * Called every @numa_balance_interval to update current node state.
+ */
+static void update_node_load(struct node_queue *nq)
+{
+	unsigned long pages, delta;
+	struct numa_cpu_load l;
+	int cpu;
+
+	memset(&l, 0, sizeof(l));
+
+	/*
+	 * Aggregate per-cpu cpu-load values for this node as per
+	 * account_numa_{en,de}queue().
+	 *
+	 * XXX limit to max balance sched_domain
+	 */
+	for_each_online_cpu(cpu) {
+		struct numa_cpu_load *nl = per_cpu_ptr(numa_load_array[nq->node], cpu);
+
+		l.remote += nl->remote;
+		l.all += nl->all;
+	}
+
+	add_load(&nq->remote_cpu_load, l.remote);
+	add_load(&nq->cpu_load, l.all);
+
+	/*
+	 * Fold regular samples of NUMA_FOREIGN into a memory load measure.
+	 */
+	pages = node_page_state(nq->node, NUMA_FOREIGN);
+	delta = pages - nq->prev_numa_foreign;
+	nq->prev_numa_foreign = pages;
+	add_load(&nq->remote_mem_load, delta);
+
+	/*
+	 * If there was NUMA_FOREIGN load, that means this node was at its
+	 * maximum memory capacity, record that.
+	 */
+	set_max_mem_load(node_pages_load(nq->node));
+}
+
+enum numa_balance_type {
+	NUMA_BALANCE_NONE = 0,
+	NUMA_BALANCE_CPU  = 1,
+	NUMA_BALANCE_MEM  = 2,
+	NUMA_BALANCE_ALL  = 3,
+};
+
+struct numa_imbalance {
+	long cpu, mem;
+	long mem_load;
+	enum numa_balance_type type;
+};
+
+static int find_busiest_node(int this_node, struct numa_imbalance *imb)
+{
+	unsigned long cpu_load, mem_load;
+	unsigned long max_cpu_load, max_mem_load;
+	unsigned long sum_cpu_load, sum_mem_load;
+	unsigned long mem_cpu_load, cpu_mem_load;
+	int cpu_node, mem_node;
+	struct node_queue *nq;
+	int node;
+
+	sum_cpu_load = sum_mem_load = 0;
+	max_cpu_load = max_mem_load = 0;
+	mem_cpu_load = cpu_mem_load = 0;
+	cpu_node = mem_node = -1;
+
+	/* XXX scalability -- sched_domain */
+	for_each_online_node(node) {
+		nq = nq_of(node);
+
+		cpu_load = nq->remote_cpu_load;
+		mem_load = nq->remote_mem_load;
+
+		/*
+		 * If this node is overloaded on memory, we don't want more
+		 * tasks, bail!
+		 */
+		if (node == this_node) {
+			if (mem_load)
+				return -1;
+		}
+
+		sum_cpu_load += cpu_load;
+		if (cpu_load > max_cpu_load) {
+			max_cpu_load = cpu_load;
+			cpu_mem_load = mem_load;
+			cpu_node = node;
+		}
+
+		sum_mem_load += mem_load;
+		if (mem_load > max_mem_load) {
+			max_mem_load = mem_load;
+			mem_cpu_load = cpu_load;
+			mem_node = node;
+		}
+	}
+
+	/*
+	 * Nobody had overload of any kind, cool we're done!
+	 */
+	if (cpu_node == -1 && mem_node == -1)
+		return -1;
+
+	if (mem_node == -1) {
+set_cpu_node:
+		node = cpu_node;
+		cpu_load = max_cpu_load;
+		mem_load = cpu_mem_load;
+		goto calc_imb;
+	}
+
+	if (cpu_node == -1) {
+set_mem_node:
+		node = mem_node;
+		cpu_load = mem_cpu_load;
+		mem_load = max_mem_load;
+		goto calc_imb;
+	}
+
+	/*
+	 * We have both cpu and mem overload, oh my! pick whichever is most
+	 * overloaded wrt the average.
+	 */
+	if ((u64)max_mem_load * sum_cpu_load > (u64)max_cpu_load * sum_mem_load)
+		goto set_mem_node;
+
+	goto set_cpu_node;
+
+calc_imb:
+	memset(imb, 0, sizeof(*imb));
+
+	if (cpu_node != -1) {
+		imb->type |= NUMA_BALANCE_CPU;
+		imb->cpu = (long)(nq_of(node)->cpu_load -
+				  nq_of(this_node)->cpu_load) / 2;
+	}
+
+	if (mem_node != -1) {
+		imb->type |= NUMA_BALANCE_MEM;
+		imb->mem_load = node_pages_load(this_node);
+		imb->mem = (long)(node_pages_load(node) - imb->mem_load) / 2;
+	}
+
+	return node;
+}
+
+static void move_processes(struct node_queue *busiest_nq,
+			   struct node_queue *this_nq,
+			   struct numa_imbalance *imb)
+{
+	unsigned long max_mem_load = get_max_mem_load();
+	long cpu_moved = 0, mem_moved = 0;
+	struct numa_entity *ne;
+	long ne_mem, ne_cpu;
+	int loops;
+
+	double_lock_nq(this_nq, busiest_nq);
+	loops = busiest_nq->nr_processes;
+	while (!list_empty(&busiest_nq->entity_list) && loops--) {
+		ne = list_first_entry(&busiest_nq->entity_list,
+				     struct numa_entity,
+				     numa_entry);
+
+		ne_cpu = ne->nops->cpu_load(ne);
+		ne_mem = ne->nops->mem_load(ne);
+
+		if (sched_feat(NUMA_BALANCE_FILTER)) {
+			/*
+			 * Avoid moving ne's when we create a larger imbalance
+			 * on the other end.
+			 */
+			if ((imb->type & NUMA_BALANCE_CPU) &&
+			    imb->cpu - cpu_moved < ne_cpu / 2)
+				goto next;
+
+			/*
+			 * Avoid migrating ne's when we'll know we'll push our
+			 * node over the memory limit.
+			 */
+			if (max_mem_load &&
+			    imb->mem_load + mem_moved + ne_mem > max_mem_load)
+				goto next;
+		}
+
+		if (!ne->nops->can_migrate(ne, this_nq->node))
+			goto next;
+
+		__dequeue_ne(busiest_nq, ne);
+		__enqueue_ne(this_nq, ne);
+		if (ne->nops->tryget(ne)) {
+			double_unlock_nq(this_nq, busiest_nq);
+
+			ne->nops->cpu_migrate(ne, this_nq->node);
+			ne->nops->mem_migrate(ne, this_nq->node);
+			ne->nops->put(ne);
+
+			double_lock_nq(this_nq, busiest_nq);
+		}
+
+		cpu_moved += ne_cpu;
+		mem_moved += ne_mem;
+
+		if (imb->cpu - cpu_moved <= 0 &&
+		    imb->mem - mem_moved <= 0)
+			break;
+
+		continue;
+
+next:
+		list_move_tail(&ne->numa_entry, &busiest_nq->entity_list);
+	}
+	double_unlock_nq(this_nq, busiest_nq);
+}
+
+static void numa_balance(struct node_queue *this_nq)
+{
+	struct numa_imbalance imb;
+	int busiest;
+
+	busiest = find_busiest_node(this_nq->node, &imb);
+	if (busiest == -1)
+		return;
+
+	if (imb.cpu <= 0 && imb.mem <= 0)
+		return;
+
+	move_processes(nq_of(busiest), this_nq, &imb);
+}
+
+static int wait_for_next_balance(struct node_queue *nq)
+{
+	set_current_state(TASK_INTERRUPTIBLE);
+	while (!kthread_should_stop()) {
+		long timeout = nq->next_schedule - jiffies;
+		if (timeout <= 0) {
+			__set_current_state(TASK_RUNNING);
+			return 1;
+		}
+		schedule_timeout(timeout);
+	}
+	__set_current_state(TASK_RUNNING);
+	return 0;
+}
+
+static int numad_thread(void *data)
+{
+	struct node_queue *nq = data;
+	struct task_struct *p = nq->numad;
+
+	set_cpus_allowed_ptr(p, cpumask_of_node(nq->node));
+
+	while (wait_for_next_balance(nq)) {
+
+		get_online_cpus();
+		update_node_load(nq);
+		if (sched_feat(NUMA_BALANCE))
+			numa_balance(nq);
+		put_online_cpus();
+
+		nq->next_schedule += numa_balance_interval;
+	}
+
+	return 0;
+}
+
+static int __cpuinit
+numa_hotplug(struct notifier_block *nb, unsigned long action, void *hcpu)
+{
+	int cpu = (long)hcpu;
+	int node = cpu_to_node(cpu);
+	struct node_queue *nq = nq_of(node);
+	struct task_struct *numad;
+	int err = 0;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_UP_PREPARE:
+		if (nq->numad)
+			break;
+
+		numad = kthread_create_on_node(numad_thread,
+				nq, node, "numad/%d", node);
+		if (IS_ERR(numad)) {
+			err = PTR_ERR(numad);
+			break;
+		}
+
+		nq->numad = numad;
+		nq->next_schedule = jiffies + HZ; // XXX sync-up?
+		break;
+
+	case CPU_ONLINE:
+		wake_up_process(nq->numad);
+		break;
+
+	case CPU_DEAD:
+	case CPU_UP_CANCELED:
+		if (!nq->numad)
+			break;
+
+		if (cpumask_any_and(cpu_online_mask,
+				    cpumask_of_node(node)) >= nr_cpu_ids) {
+			kthread_stop(nq->numad);
+			nq->numad = NULL;
+		}
+		break;
+	}
+
+	return notifier_from_errno(err);
+}
+
+static __init int numa_init(void)
+{
+	int node, cpu, err;
+
+	nqs = kzalloc(sizeof(struct node_queue*) * nr_node_ids, GFP_KERNEL);
+	BUG_ON(!nqs);
+
+	for_each_node(node) {
+		struct node_queue *nq = kmalloc_node(sizeof(*nq),
+				GFP_KERNEL | __GFP_ZERO,
+				node_online(node) ? node : NUMA_NO_NODE);
+		BUG_ON(!nq);
+
+		spin_lock_init(&nq->lock);
+		INIT_LIST_HEAD(&nq->entity_list);
+
+		nq->next_schedule = jiffies + HZ;
+		nq->node = node;
+		nqs[node] = nq;
+	}
+
+	get_online_cpus();
+	cpu_notifier(numa_hotplug, 0);
+	for_each_online_cpu(cpu) {
+		err = numa_hotplug(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
+		BUG_ON(notifier_to_errno(err));
+		numa_hotplug(NULL, CPU_ONLINE, (void *)(long)cpu);
+	}
+	put_online_cpus();
+
+	return 0;
+}
+early_initcall(numa_init);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 6d52cea..4134d37 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -414,6 +414,12 @@ struct rq {
 
 	struct list_head cfs_tasks;
 
+#ifdef CONFIG_NUMA
+	unsigned long    offnode_running;
+	unsigned long	 offnode_weight;
+	struct list_head offnode_tasks;
+#endif
+
 	u64 rt_avg;
 	u64 age_stamp;
 	u64 idle_stamp;
@@ -465,6 +471,15 @@ struct rq {
 #endif
 };
 
+static inline struct list_head *offnode_tasks(struct rq *rq)
+{
+#ifdef CONFIG_NUMA
+	return &rq->offnode_tasks;
+#else
+	return NULL;
+#endif
+}
+
 static inline int cpu_of(struct rq *rq)
 {
 #ifdef CONFIG_SMP
@@ -525,6 +540,7 @@ static inline struct sched_domain *highest_flag_domain(int cpu, int flag)
 
 DECLARE_PER_CPU(struct sched_domain *, sd_llc);
 DECLARE_PER_CPU(int, sd_llc_id);
+DECLARE_PER_CPU(struct sched_domain *, sd_node);
 
 extern int group_balance_cpu(struct sched_group *sg);
 
@@ -647,6 +663,12 @@ extern struct static_key sched_feat_keys[__SCHED_FEAT_NR];
 #define sched_feat(x) (sysctl_sched_features & (1UL << __SCHED_FEAT_##x))
 #endif /* SCHED_DEBUG && HAVE_JUMP_LABEL */
 
+#ifdef CONFIG_NUMA
+#define sched_feat_numa(x) sched_feat(x)
+#else
+#define sched_feat_numa(x) (0)
+#endif
+
 static inline u64 global_rt_period(void)
 {
 	return (u64)sysctl_sched_rt_period * NSEC_PER_USEC;
@@ -1158,3 +1180,26 @@ enum rq_nohz_flag_bits {
 
 #define nohz_flags(cpu)	(&cpu_rq(cpu)->nohz_flags)
 #endif
+
+unsigned long task_h_load(struct task_struct *p);
+
+#ifdef CONFIG_NUMA
+
+void sched_setnode(struct task_struct *p, int node);
+void select_task_node(struct task_struct *p, struct mm_struct *mm, int sd_flags);
+bool account_numa_enqueue(struct task_struct *p);
+void account_numa_dequeue(struct task_struct *p);
+void init_sched_numa(void);
+
+#else /* CONFIG_NUMA */
+
+/*
+ * Macro to avoid argument evaluation
+ */
+#define select_task_node(p, mm, sd_flags) do { } while (0)
+static inline bool account_numa_enqueue(struct task_struct *p) { return false; }
+static inline void account_numa_dequeue(struct task_struct *p) { }
+static inline void init_sched_numa(void) { }
+
+#endif /* CONFIG_NUMA */
+
diff --git a/kernel/smp.c b/kernel/smp.c
index d0ae5b2..29dd40a 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -581,26 +581,6 @@ int smp_call_function(smp_call_func_t func, void *info, int wait)
 	return 0;
 }
 EXPORT_SYMBOL(smp_call_function);
-
-void ipi_call_lock(void)
-{
-	raw_spin_lock(&call_function.lock);
-}
-
-void ipi_call_unlock(void)
-{
-	raw_spin_unlock(&call_function.lock);
-}
-
-void ipi_call_lock_irq(void)
-{
-	raw_spin_lock_irq(&call_function.lock);
-}
-
-void ipi_call_unlock_irq(void)
-{
-	raw_spin_unlock_irq(&call_function.lock);
-}
 #endif /* USE_GENERIC_SMP_HELPERS */
 
 /* Setup configured maximum number of CPUs to activate */
diff --git a/kernel/smpboot.h b/kernel/smpboot.h
index 80c0acf..6ef9433 100644
--- a/kernel/smpboot.h
+++ b/kernel/smpboot.h
@@ -3,8 +3,6 @@
 
 struct task_struct;
 
-int smpboot_prepare(unsigned int cpu);
-
 #ifdef CONFIG_GENERIC_SMP_IDLE_THREAD
 struct task_struct *idle_thread_get(unsigned int cpu);
 void idle_thread_set_boot_cpu(void);
diff --git a/kernel/sys.c b/kernel/sys.c
index e0c8ffc..2d39a84 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1788,7 +1788,6 @@ SYSCALL_DEFINE1(umask, int, mask)
 #ifdef CONFIG_CHECKPOINT_RESTORE
 static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
 {
-	struct vm_area_struct *vma;
 	struct file *exe_file;
 	struct dentry *dentry;
 	int err;
@@ -1816,13 +1815,17 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
 	down_write(&mm->mmap_sem);
 
 	/*
-	 * Forbid mm->exe_file change if there are mapped other files.
+	 * Forbid mm->exe_file change if old file still mapped.
 	 */
 	err = -EBUSY;
-	for (vma = mm->mmap; vma; vma = vma->vm_next) {
-		if (vma->vm_file && !path_equal(&vma->vm_file->f_path,
-						&exe_file->f_path))
-			goto exit_unlock;
+	if (mm->exe_file) {
+		struct vm_area_struct *vma;
+
+		for (vma = mm->mmap; vma; vma = vma->vm_next)
+			if (vma->vm_file &&
+			    path_equal(&vma->vm_file->f_path,
+				       &mm->exe_file->f_path))
+				goto exit_unlock;
 	}
 
 	/*
@@ -1835,6 +1838,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
 	if (test_and_set_bit(MMF_EXE_FILE_CHANGED, &mm->flags))
 		goto exit_unlock;
 
+	err = 0;
 	set_mm_exe_file(mm, exe_file);
 exit_unlock:
 	up_write(&mm->mmap_sem);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 4ab1187..c6a4b65 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1095,11 +1095,9 @@ static struct ctl_table vm_table[] = {
 		.extra1		= &zero,
 	},
 	{
-		.procname	= "nr_pdflush_threads",
-		.data		= &nr_pdflush_threads,
-		.maxlen		= sizeof nr_pdflush_threads,
-		.mode		= 0444 /* read-only*/,
-		.proc_handler	= proc_dointvec,
+		.procname       = "nr_pdflush_threads",
+		.mode           = 0444 /* read-only */,
+		.proc_handler   = pdflush_proc_obsolete,
 	},
 	{
 		.procname	= "swappiness",
@@ -1493,6 +1491,26 @@ static struct ctl_table fs_table[] = {
 	},
 #endif
 #endif
+#ifdef CONFIG_PROTECTED_LINKS
+	{
+		.procname	= "protected_symlinks",
+		.data		= &sysctl_protected_symlinks,
+		.maxlen		= sizeof(int),
+		.mode		= 0600,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &one,
+	},
+	{
+		.procname	= "protected_hardlinks",
+		.data		= &sysctl_protected_hardlinks,
+		.maxlen		= sizeof(int),
+		.mode		= 0600,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &one,
+	},
+#endif
 	{
 		.procname	= "suid_dumpable",
 		.data		= &suid_dumpable,
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index a650694..65bdcf1 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -147,7 +147,7 @@ static const struct bin_table bin_vm_table[] = {
 	{ CTL_INT,	VM_DIRTY_RATIO,			"dirty_ratio" },
 	/* VM_DIRTY_WB_CS "dirty_writeback_centisecs" no longer used */
 	/* VM_DIRTY_EXPIRE_CS "dirty_expire_centisecs" no longer used */
-	{ CTL_INT,	VM_NR_PDFLUSH_THREADS,		"nr_pdflush_threads" },
+	/* VM_NR_PDFLUSH_THREADS "nr_pdflush_threads" no longer used */
 	{ CTL_INT,	VM_OVERCOMMIT_RATIO,		"overcommit_ratio" },
 	/* VM_PAGEBUF unused */
 	/* VM_HUGETLB_PAGES "nr_hugepages" no longer used */
diff --git a/kernel/time.c b/kernel/time.c
index ba744cf..8d8bebd9 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -232,7 +232,7 @@ EXPORT_SYMBOL(current_fs_time);
  * Avoid unnecessary multiplications/divisions in the
  * two most common HZ cases:
  */
-inline unsigned int jiffies_to_msecs(const unsigned long j)
+unsigned int jiffies_to_msecs(const unsigned long j)
 {
 #if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
 	return (MSEC_PER_SEC / HZ) * j;
@@ -248,7 +248,7 @@ inline unsigned int jiffies_to_msecs(const unsigned long j)
 }
 EXPORT_SYMBOL(jiffies_to_msecs);
 
-inline unsigned int jiffies_to_usecs(const unsigned long j)
+unsigned int jiffies_to_usecs(const unsigned long j)
 {
 #if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ)
 	return (USEC_PER_SEC / HZ) * j;
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 8699978..f6c6cc6 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -105,7 +105,7 @@ static ktime_t tick_init_jiffy_update(void)
 /*
  * NO HZ enabled ?
  */
-static int tick_nohz_enabled __read_mostly  = 1;
+int tick_nohz_enabled __read_mostly  = 1;
 
 /*
  * Enable / Disable tickless mode
@@ -271,50 +271,15 @@ u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time)
 }
 EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us);
 
-static void tick_nohz_stop_sched_tick(struct tick_sched *ts)
+static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, ktime_t now, int cpu)
 {
 	unsigned long seq, last_jiffies, next_jiffies, delta_jiffies;
 	unsigned long rcu_delta_jiffies;
-	ktime_t last_update, expires, now;
+	ktime_t last_update, expires, ret = { .tv64 = 0 };
 	struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
 	u64 time_delta;
-	int cpu;
-
-	cpu = smp_processor_id();
-	ts = &per_cpu(tick_cpu_sched, cpu);
-
-	now = tick_nohz_start_idle(cpu, ts);
-
-	/*
-	 * If this cpu is offline and it is the one which updates
-	 * jiffies, then give up the assignment and let it be taken by
-	 * the cpu which runs the tick timer next. If we don't drop
-	 * this here the jiffies might be stale and do_timer() never
-	 * invoked.
-	 */
-	if (unlikely(!cpu_online(cpu))) {
-		if (cpu == tick_do_timer_cpu)
-			tick_do_timer_cpu = TICK_DO_TIMER_NONE;
-	}
-
-	if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
-		return;
 
-	if (need_resched())
-		return;
-
-	if (unlikely(local_softirq_pending() && cpu_online(cpu))) {
-		static int ratelimit;
-
-		if (ratelimit < 10) {
-			printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n",
-			       (unsigned int) local_softirq_pending());
-			ratelimit++;
-		}
-		return;
-	}
 
-	ts->idle_calls++;
 	/* Read jiffies and the time when jiffies were updated last */
 	do {
 		seq = read_seqbegin(&xtime_lock);
@@ -397,6 +362,8 @@ static void tick_nohz_stop_sched_tick(struct tick_sched *ts)
 		if (ts->tick_stopped && ktime_equal(expires, dev->next_event))
 			goto out;
 
+		ret = expires;
+
 		/*
 		 * nohz_stop_sched_tick can be called several times before
 		 * the nohz_restart_sched_tick is called. This happens when
@@ -407,16 +374,10 @@ static void tick_nohz_stop_sched_tick(struct tick_sched *ts)
 		if (!ts->tick_stopped) {
 			select_nohz_load_balancer(1);
 
-			ts->idle_tick = hrtimer_get_expires(&ts->sched_timer);
+			ts->last_tick = hrtimer_get_expires(&ts->sched_timer);
 			ts->tick_stopped = 1;
-			ts->idle_jiffies = last_jiffies;
 		}
 
-		ts->idle_sleeps++;
-
-		/* Mark expires */
-		ts->idle_expires = expires;
-
 		/*
 		 * If the expiration time == KTIME_MAX, then
 		 * in this case we simply stop the tick timer.
@@ -447,6 +408,65 @@ out:
 	ts->next_jiffies = next_jiffies;
 	ts->last_jiffies = last_jiffies;
 	ts->sleep_length = ktime_sub(dev->next_event, now);
+
+	return ret;
+}
+
+static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
+{
+	/*
+	 * If this cpu is offline and it is the one which updates
+	 * jiffies, then give up the assignment and let it be taken by
+	 * the cpu which runs the tick timer next. If we don't drop
+	 * this here the jiffies might be stale and do_timer() never
+	 * invoked.
+	 */
+	if (unlikely(!cpu_online(cpu))) {
+		if (cpu == tick_do_timer_cpu)
+			tick_do_timer_cpu = TICK_DO_TIMER_NONE;
+	}
+
+	if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
+		return false;
+
+	if (need_resched())
+		return false;
+
+	if (unlikely(local_softirq_pending() && cpu_online(cpu))) {
+		static int ratelimit;
+
+		if (ratelimit < 10) {
+			printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n",
+			       (unsigned int) local_softirq_pending());
+			ratelimit++;
+		}
+		return false;
+	}
+
+	return true;
+}
+
+static void __tick_nohz_idle_enter(struct tick_sched *ts)
+{
+	ktime_t now, expires;
+	int cpu = smp_processor_id();
+
+	now = tick_nohz_start_idle(cpu, ts);
+
+	if (can_stop_idle_tick(cpu, ts)) {
+		int was_stopped = ts->tick_stopped;
+
+		ts->idle_calls++;
+
+		expires = tick_nohz_stop_sched_tick(ts, now, cpu);
+		if (expires.tv64 > 0LL) {
+			ts->idle_sleeps++;
+			ts->idle_expires = expires;
+		}
+
+		if (!was_stopped && ts->tick_stopped)
+			ts->idle_jiffies = ts->last_jiffies;
+	}
 }
 
 /**
@@ -484,7 +504,7 @@ void tick_nohz_idle_enter(void)
 	 * update of the idle time accounting in tick_nohz_start_idle().
 	 */
 	ts->inidle = 1;
-	tick_nohz_stop_sched_tick(ts);
+	__tick_nohz_idle_enter(ts);
 
 	local_irq_enable();
 }
@@ -504,7 +524,7 @@ void tick_nohz_irq_exit(void)
 	if (!ts->inidle)
 		return;
 
-	tick_nohz_stop_sched_tick(ts);
+	__tick_nohz_idle_enter(ts);
 }
 
 /**
@@ -522,7 +542,7 @@ ktime_t tick_nohz_get_sleep_length(void)
 static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
 {
 	hrtimer_cancel(&ts->sched_timer);
-	hrtimer_set_expires(&ts->sched_timer, ts->idle_tick);
+	hrtimer_set_expires(&ts->sched_timer, ts->last_tick);
 
 	while (1) {
 		/* Forward the time to expire in the future */
@@ -545,6 +565,41 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
 	}
 }
 
+static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
+{
+	/* Update jiffies first */
+	select_nohz_load_balancer(0);
+	tick_do_update_jiffies64(now);
+	update_cpu_load_nohz();
+
+	touch_softlockup_watchdog();
+	/*
+	 * Cancel the scheduled timer and restore the tick
+	 */
+	ts->tick_stopped  = 0;
+	ts->idle_exittime = now;
+
+	tick_nohz_restart(ts, now);
+}
+
+static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
+{
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+	unsigned long ticks;
+	/*
+	 * We stopped the tick in idle. Update process times would miss the
+	 * time we slept as update_process_times does only a 1 tick
+	 * accounting. Enforce that this is accounted to idle !
+	 */
+	ticks = jiffies - ts->idle_jiffies;
+	/*
+	 * We might be one off. Do not randomly account a huge number of ticks!
+	 */
+	if (ticks && ticks < LONG_MAX)
+		account_idle_ticks(ticks);
+#endif
+}
+
 /**
  * tick_nohz_idle_exit - restart the idle tick from the idle task
  *
@@ -556,9 +611,6 @@ void tick_nohz_idle_exit(void)
 {
 	int cpu = smp_processor_id();
 	struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
-	unsigned long ticks;
-#endif
 	ktime_t now;
 
 	local_irq_disable();
@@ -573,39 +625,11 @@ void tick_nohz_idle_exit(void)
 	if (ts->idle_active)
 		tick_nohz_stop_idle(cpu, now);
 
-	if (!ts->tick_stopped) {
-		local_irq_enable();
-		return;
+	if (ts->tick_stopped) {
+		tick_nohz_restart_sched_tick(ts, now);
+		tick_nohz_account_idle_ticks(ts);
 	}
 
-	/* Update jiffies first */
-	select_nohz_load_balancer(0);
-	tick_do_update_jiffies64(now);
-	update_cpu_load_nohz();
-
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
-	/*
-	 * We stopped the tick in idle. Update process times would miss the
-	 * time we slept as update_process_times does only a 1 tick
-	 * accounting. Enforce that this is accounted to idle !
-	 */
-	ticks = jiffies - ts->idle_jiffies;
-	/*
-	 * We might be one off. Do not randomly account a huge number of ticks!
-	 */
-	if (ticks && ticks < LONG_MAX)
-		account_idle_ticks(ticks);
-#endif
-
-	touch_softlockup_watchdog();
-	/*
-	 * Cancel the scheduled timer and restore the tick
-	 */
-	ts->tick_stopped  = 0;
-	ts->idle_exittime = now;
-
-	tick_nohz_restart(ts, now);
-
 	local_irq_enable();
 }
 
@@ -809,7 +833,8 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
 		 */
 		if (ts->tick_stopped) {
 			touch_softlockup_watchdog();
-			ts->idle_jiffies++;
+			if (idle_cpu(cpu))
+				ts->idle_jiffies++;
 		}
 		update_process_times(user_mode(regs));
 		profile_tick(CPU_PROFILING);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 6f46a00..87be8c2 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1223,7 +1223,7 @@ void do_timer(unsigned long ticks)
 {
 	jiffies_64 += ticks;
 	update_wall_time();
-	calc_global_load(ticks);
+	calc_global_load();
 }
 
 /**
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 3258455..af5a7e9 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -167,7 +167,7 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
 	{
 		struct tick_sched *ts = tick_get_tick_sched(cpu);
 		P(nohz_mode);
-		P_ns(idle_tick);
+		P_ns(last_tick);
 		P(tick_stopped);
 		P(idle_jiffies);
 		P(idle_calls);
@@ -259,7 +259,7 @@ static int timer_list_show(struct seq_file *m, void *v)
 	u64 now = ktime_to_ns(ktime_get());
 	int cpu;
 
-	SEQ_printf(m, "Timer List Version: v0.6\n");
+	SEQ_printf(m, "Timer List Version: v0.7\n");
 	SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES);
 	SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);
 
diff --git a/kernel/timeconst.pl b/kernel/timeconst.pl
index eb51d76..0461239 100644
--- a/kernel/timeconst.pl
+++ b/kernel/timeconst.pl
@@ -370,7 +370,7 @@ if ($hz eq '--can') {
 	}
 
 	@val = @{$canned_values{$hz}};
-	if (!defined(@val)) {
+	if (!@val) {
 		@val = compute_values($hz);
 	}
 	output($hz, @val);
diff --git a/kernel/timer.c b/kernel/timer.c
index 6ec7e7e..8c5e7b9 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -77,6 +77,7 @@ struct tvec_base {
 	struct timer_list *running_timer;
 	unsigned long timer_jiffies;
 	unsigned long next_timer;
+	unsigned long active_timers;
 	struct tvec_root tv1;
 	struct tvec tv2;
 	struct tvec tv3;
@@ -330,7 +331,8 @@ void set_timer_slack(struct timer_list *timer, int slack_hz)
 }
 EXPORT_SYMBOL_GPL(set_timer_slack);
 
-static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
+static void
+__internal_add_timer(struct tvec_base *base, struct timer_list *timer)
 {
 	unsigned long expires = timer->expires;
 	unsigned long idx = expires - base->timer_jiffies;
@@ -372,6 +374,19 @@ static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
 	list_add_tail(&timer->entry, vec);
 }
 
+static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
+{
+	__internal_add_timer(base, timer);
+	/*
+	 * Update base->active_timers and base->next_timer
+	 */
+	if (!tbase_get_deferrable(timer->base)) {
+		if (time_before(timer->expires, base->next_timer))
+			base->next_timer = timer->expires;
+		base->active_timers++;
+	}
+}
+
 #ifdef CONFIG_TIMER_STATS
 void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr)
 {
@@ -654,8 +669,7 @@ void init_timer_deferrable_key(struct timer_list *timer,
 }
 EXPORT_SYMBOL(init_timer_deferrable_key);
 
-static inline void detach_timer(struct timer_list *timer,
-				int clear_pending)
+static inline void detach_timer(struct timer_list *timer, bool clear_pending)
 {
 	struct list_head *entry = &timer->entry;
 
@@ -667,6 +681,29 @@ static inline void detach_timer(struct timer_list *timer,
 	entry->prev = LIST_POISON2;
 }
 
+static inline void
+detach_expired_timer(struct timer_list *timer, struct tvec_base *base)
+{
+	detach_timer(timer, true);
+	if (!tbase_get_deferrable(timer->base))
+		timer->base->active_timers--;
+}
+
+static int detach_if_pending(struct timer_list *timer, struct tvec_base *base,
+			     bool clear_pending)
+{
+	if (!timer_pending(timer))
+		return 0;
+
+	detach_timer(timer, clear_pending);
+	if (!tbase_get_deferrable(timer->base)) {
+		timer->base->active_timers--;
+		if (timer->expires == base->next_timer)
+			base->next_timer = base->timer_jiffies;
+	}
+	return 1;
+}
+
 /*
  * We are using hashed locking: holding per_cpu(tvec_bases).lock
  * means that all timers which are tied to this base via timer->base are
@@ -712,16 +749,9 @@ __mod_timer(struct timer_list *timer, unsigned long expires,
 
 	base = lock_timer_base(timer, &flags);
 
-	if (timer_pending(timer)) {
-		detach_timer(timer, 0);
-		if (timer->expires == base->next_timer &&
-		    !tbase_get_deferrable(timer->base))
-			base->next_timer = base->timer_jiffies;
-		ret = 1;
-	} else {
-		if (pending_only)
-			goto out_unlock;
-	}
+	ret = detach_if_pending(timer, base, false);
+	if (!ret && pending_only)
+		goto out_unlock;
 
 	debug_activate(timer, expires);
 
@@ -752,9 +782,6 @@ __mod_timer(struct timer_list *timer, unsigned long expires,
 	}
 
 	timer->expires = expires;
-	if (time_before(timer->expires, base->next_timer) &&
-	    !tbase_get_deferrable(timer->base))
-		base->next_timer = timer->expires;
 	internal_add_timer(base, timer);
 
 out_unlock:
@@ -920,9 +947,6 @@ void add_timer_on(struct timer_list *timer, int cpu)
 	spin_lock_irqsave(&base->lock, flags);
 	timer_set_base(timer, base);
 	debug_activate(timer, timer->expires);
-	if (time_before(timer->expires, base->next_timer) &&
-	    !tbase_get_deferrable(timer->base))
-		base->next_timer = timer->expires;
 	internal_add_timer(base, timer);
 	/*
 	 * Check whether the other CPU is idle and needs to be
@@ -959,13 +983,7 @@ int del_timer(struct timer_list *timer)
 	timer_stats_timer_clear_start_info(timer);
 	if (timer_pending(timer)) {
 		base = lock_timer_base(timer, &flags);
-		if (timer_pending(timer)) {
-			detach_timer(timer, 1);
-			if (timer->expires == base->next_timer &&
-			    !tbase_get_deferrable(timer->base))
-				base->next_timer = base->timer_jiffies;
-			ret = 1;
-		}
+		ret = detach_if_pending(timer, base, true);
 		spin_unlock_irqrestore(&base->lock, flags);
 	}
 
@@ -990,19 +1008,10 @@ int try_to_del_timer_sync(struct timer_list *timer)
 
 	base = lock_timer_base(timer, &flags);
 
-	if (base->running_timer == timer)
-		goto out;
-
-	timer_stats_timer_clear_start_info(timer);
-	ret = 0;
-	if (timer_pending(timer)) {
-		detach_timer(timer, 1);
-		if (timer->expires == base->next_timer &&
-		    !tbase_get_deferrable(timer->base))
-			base->next_timer = base->timer_jiffies;
-		ret = 1;
+	if (base->running_timer != timer) {
+		timer_stats_timer_clear_start_info(timer);
+		ret = detach_if_pending(timer, base, true);
 	}
-out:
 	spin_unlock_irqrestore(&base->lock, flags);
 
 	return ret;
@@ -1089,7 +1098,8 @@ static int cascade(struct tvec_base *base, struct tvec *tv, int index)
 	 */
 	list_for_each_entry_safe(timer, tmp, &tv_list, entry) {
 		BUG_ON(tbase_get_base(timer->base) != base);
-		internal_add_timer(base, timer);
+		/* No accounting, while moving them */
+		__internal_add_timer(base, timer);
 	}
 
 	return index;
@@ -1178,7 +1188,7 @@ static inline void __run_timers(struct tvec_base *base)
 			timer_stats_account_timer(timer);
 
 			base->running_timer = timer;
-			detach_timer(timer, 1);
+			detach_expired_timer(timer, base);
 
 			spin_unlock_irq(&base->lock);
 			call_timer_fn(timer, fn, data);
@@ -1316,18 +1326,21 @@ static unsigned long cmp_next_hrtimer_event(unsigned long now,
 unsigned long get_next_timer_interrupt(unsigned long now)
 {
 	struct tvec_base *base = __this_cpu_read(tvec_bases);
-	unsigned long expires;
+	unsigned long expires = now + NEXT_TIMER_MAX_DELTA;
 
 	/*
 	 * Pretend that there is no timer pending if the cpu is offline.
 	 * Possible pending timers will be migrated later to an active cpu.
 	 */
 	if (cpu_is_offline(smp_processor_id()))
-		return now + NEXT_TIMER_MAX_DELTA;
+		return expires;
+
 	spin_lock(&base->lock);
-	if (time_before_eq(base->next_timer, base->timer_jiffies))
-		base->next_timer = __next_timer_interrupt(base);
-	expires = base->next_timer;
+	if (base->active_timers) {
+		if (time_before_eq(base->next_timer, base->timer_jiffies))
+			base->next_timer = __next_timer_interrupt(base);
+		expires = base->next_timer;
+	}
 	spin_unlock(&base->lock);
 
 	if (time_before_eq(expires, now))
@@ -1394,13 +1407,6 @@ SYSCALL_DEFINE1(alarm, unsigned int, seconds)
 
 #endif
 
-#ifndef __alpha__
-
-/*
- * The Alpha uses getxpid, getxuid, and getxgid instead.  Maybe this
- * should be moved into arch/i386 instead?
- */
-
 /**
  * sys_getpid - return the thread group id of the current process
  *
@@ -1456,8 +1462,6 @@ SYSCALL_DEFINE0(getegid)
 	return from_kgid_munged(current_user_ns(), current_egid());
 }
 
-#endif
-
 static void process_timeout(unsigned long __data)
 {
 	wake_up_process((struct task_struct *)__data);
@@ -1704,6 +1708,7 @@ static int __cpuinit init_timers_cpu(int cpu)
 
 	base->timer_jiffies = jiffies;
 	base->next_timer = base->timer_jiffies;
+	base->active_timers = 0;
 	return 0;
 }
 
@@ -1714,11 +1719,9 @@ static void migrate_timer_list(struct tvec_base *new_base, struct list_head *hea
 
 	while (!list_empty(head)) {
 		timer = list_first_entry(head, struct timer_list, entry);
-		detach_timer(timer, 0);
+		/* We ignore the accounting on the dying cpu */
+		detach_timer(timer, false);
 		timer_set_base(timer, new_base);
-		if (time_before(timer->expires, new_base->next_timer) &&
-		    !tbase_get_deferrable(timer->base))
-			new_base->next_timer = timer->expires;
 		internal_add_timer(new_base, timer);
 	}
 }
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index a008663..b4f20fb 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -312,7 +312,7 @@ static int remove_ftrace_list_ops(struct ftrace_ops **list,
 
 static int __register_ftrace_function(struct ftrace_ops *ops)
 {
-	if (ftrace_disabled)
+	if (unlikely(ftrace_disabled))
 		return -ENODEV;
 
 	if (FTRACE_WARN_ON(ops == &global_ops))
@@ -4299,16 +4299,12 @@ int register_ftrace_function(struct ftrace_ops *ops)
 
 	mutex_lock(&ftrace_lock);
 
-	if (unlikely(ftrace_disabled))
-		goto out_unlock;
-
 	ret = __register_ftrace_function(ops);
 	if (!ret)
 		ret = ftrace_startup(ops, 0);
 
-
- out_unlock:
 	mutex_unlock(&ftrace_lock);
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(register_ftrace_function);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 49249c2..a7fa070 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -3609,6 +3609,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
 		.pages		= pages_def,
 		.partial	= partial_def,
 		.nr_pages	= 0, /* This gets updated below. */
+		.nr_pages_max	= PIPE_DEF_BUFFERS,
 		.flags		= flags,
 		.ops		= &tracing_pipe_buf_ops,
 		.spd_release	= tracing_spd_release_pipe,
@@ -3680,7 +3681,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
 
 	ret = splice_to_pipe(pipe, &spd);
 out:
-	splice_shrink_spd(pipe, &spd);
+	splice_shrink_spd(&spd);
 	return ret;
 
 out_err:
@@ -4231,6 +4232,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
 	struct splice_pipe_desc spd = {
 		.pages		= pages_def,
 		.partial	= partial_def,
+		.nr_pages_max	= PIPE_DEF_BUFFERS,
 		.flags		= flags,
 		.ops		= &buffer_pipe_buf_ops,
 		.spd_release	= buffer_spd_release,
@@ -4318,7 +4320,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
 	}
 
 	ret = splice_to_pipe(pipe, &spd);
-	splice_shrink_spd(pipe, &spd);
+	splice_shrink_spd(&spd);
 out:
 	return ret;
 }
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index df611a0..123b189 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -1325,4 +1325,4 @@ __init static int init_events(void)
 
 	return 0;
 }
-device_initcall(init_events);
+early_initcall(init_events);
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 4b1dfba..69add8a 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -575,7 +575,7 @@ out:
 /*
  * Create/destroy watchdog threads as CPUs come and go:
  */
-static int __cpuinit
+static int
 cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
 	int hotcpu = (unsigned long)hcpu;
@@ -610,10 +610,27 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 	return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata cpu_nfb = {
+static struct notifier_block cpu_nfb = {
 	.notifier_call = cpu_callback
 };
 
+#ifdef CONFIG_SUSPEND
+/*
+ * On exit from suspend we force an offline->online transition on the boot CPU
+ * so that the PMU state that was lost while in suspended state gets set up
+ * properly for the boot CPU.  This information is required for restarting the
+ * NMI watchdog.
+ */
+void lockup_detector_bootcpu_resume(void)
+{
+	void *cpu = (void *)(long)smp_processor_id();
+
+	cpu_callback(&cpu_nfb, CPU_DEAD_FROZEN, cpu);
+	cpu_callback(&cpu_nfb, CPU_UP_PREPARE_FROZEN, cpu);
+	cpu_callback(&cpu_nfb, CPU_ONLINE_FROZEN, cpu);
+}
+#endif
+
 void __init lockup_detector_init(void)
 {
 	void *cpu = (void *)(long)smp_processor_id();
diff --git a/lib/Kconfig b/lib/Kconfig
index a9e1540..bfdbb1f 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -378,14 +378,6 @@ config MPILIB
 	  It is used to implement RSA digital signature verification,
 	  which is used by IMA/EVM digital signature extension.
 
-config MPILIB_EXTRA
-	bool
-	depends on MPILIB
-	help
-	  Additional sources of multiprecision maths library from GnuPG.
-	  This code is unnecessary for RSA digital signature verification,
-	  but can be compiled if needed.
-
 config SIGNATURE
 	tristate
 	depends on KEYS && CRYPTO
@@ -395,4 +387,10 @@ config SIGNATURE
 	  Digital signature verification. Currently only RSA is supported.
 	  Implementation is done using GnuPG MPI library
 
+#
+# libfdt files, only selected if needed.
+#
+config LIBFDT
+	bool
+
 endmenu
diff --git a/lib/Makefile b/lib/Makefile
index 8c31a0c..3d84768 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -11,7 +11,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
 	 rbtree.o radix-tree.o dump_stack.o timerqueue.o\
 	 idr.o int_sqrt.o extable.o prio_tree.o \
 	 sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
-	 proportions.o prio_heap.o ratelimit.o show_mem.o \
+	 proportions.o flex_proportions.o prio_heap.o ratelimit.o show_mem.o \
 	 is_single_threaded.o plist.o decompress.o
 
 lib-$(CONFIG_MMU) += ioremap.o
@@ -22,7 +22,7 @@ lib-y	+= kobject.o klist.o
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
 	 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
 	 string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \
-	 bsearch.o find_last_bit.o find_next_bit.o llist.o
+	 bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o
 obj-y += kstrtox.o
 obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
 
@@ -130,6 +130,11 @@ obj-$(CONFIG_GENERIC_STRNLEN_USER) += strnlen_user.o
 
 obj-$(CONFIG_STMP_DEVICE) += stmp_device.o
 
+libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o
+$(foreach file, $(libfdt_files), \
+	$(eval CFLAGS_$(file) = -I$(src)/../scripts/dtc/libfdt))
+lib-$(CONFIG_LIBFDT) += $(libfdt_files)
+
 hostprogs-y	:= gen_crc32table
 clean-files	:= crc32table.h
 
diff --git a/lib/fdt.c b/lib/fdt.c
new file mode 100644
index 0000000..97f2006
--- /dev/null
+++ b/lib/fdt.c
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt.c"
diff --git a/lib/fdt_ro.c b/lib/fdt_ro.c
new file mode 100644
index 0000000..f73c04e
--- /dev/null
+++ b/lib/fdt_ro.c
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_ro.c"
diff --git a/lib/fdt_rw.c b/lib/fdt_rw.c
new file mode 100644
index 0000000..0c1f0f4
--- /dev/null
+++ b/lib/fdt_rw.c
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_rw.c"
diff --git a/lib/fdt_strerror.c b/lib/fdt_strerror.c
new file mode 100644
index 0000000..8713e3f
--- /dev/null
+++ b/lib/fdt_strerror.c
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_strerror.c"
diff --git a/lib/fdt_sw.c b/lib/fdt_sw.c
new file mode 100644
index 0000000..9ac7e50
--- /dev/null
+++ b/lib/fdt_sw.c
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_sw.c"
diff --git a/lib/fdt_wip.c b/lib/fdt_wip.c
new file mode 100644
index 0000000..45b3fc3
--- /dev/null
+++ b/lib/fdt_wip.c
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_wip.c"
diff --git a/lib/flex_proportions.c b/lib/flex_proportions.c
new file mode 100644
index 0000000..c785554
--- /dev/null
+++ b/lib/flex_proportions.c
@@ -0,0 +1,272 @@
+/*
+ *  Floating proportions with flexible aging period
+ *
+ *   Copyright (C) 2011, SUSE, Jan Kara <jack@suse.cz>
+ *
+ * The goal of this code is: Given different types of event, measure proportion
+ * of each type of event over time. The proportions are measured with
+ * exponentially decaying history to give smooth transitions. A formula
+ * expressing proportion of event of type 'j' is:
+ *
+ *   p_{j} = (\Sum_{i>=0} x_{i,j}/2^{i+1})/(\Sum_{i>=0} x_i/2^{i+1})
+ *
+ * Where x_{i,j} is j's number of events in i-th last time period and x_i is
+ * total number of events in i-th last time period.
+ *
+ * Note that p_{j}'s are normalised, i.e.
+ *
+ *   \Sum_{j} p_{j} = 1,
+ *
+ * This formula can be straightforwardly computed by maintaing denominator
+ * (let's call it 'd') and for each event type its numerator (let's call it
+ * 'n_j'). When an event of type 'j' happens, we simply need to do:
+ *   n_j++; d++;
+ *
+ * When a new period is declared, we could do:
+ *   d /= 2
+ *   for each j
+ *     n_j /= 2
+ *
+ * To avoid iteration over all event types, we instead shift numerator of event
+ * j lazily when someone asks for a proportion of event j or when event j
+ * occurs. This can bit trivially implemented by remembering last period in
+ * which something happened with proportion of type j.
+ */
+#include <linux/flex_proportions.h>
+
+int fprop_global_init(struct fprop_global *p)
+{
+	int err;
+
+	p->period = 0;
+	/* Use 1 to avoid dealing with periods with 0 events... */
+	err = percpu_counter_init(&p->events, 1);
+	if (err)
+		return err;
+	seqcount_init(&p->sequence);
+	return 0;
+}
+
+void fprop_global_destroy(struct fprop_global *p)
+{
+	percpu_counter_destroy(&p->events);
+}
+
+/*
+ * Declare @periods new periods. It is upto the caller to make sure period
+ * transitions cannot happen in parallel.
+ *
+ * The function returns true if the proportions are still defined and false
+ * if aging zeroed out all events. This can be used to detect whether declaring
+ * further periods has any effect.
+ */
+bool fprop_new_period(struct fprop_global *p, int periods)
+{
+	u64 events;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	events = percpu_counter_sum(&p->events);
+	/*
+	 * Don't do anything if there are no events.
+	 */
+	if (events <= 1) {
+		local_irq_restore(flags);
+		return false;
+	}
+	write_seqcount_begin(&p->sequence);
+	if (periods < 64)
+		events -= events >> periods;
+	/* Use addition to avoid losing events happening between sum and set */
+	percpu_counter_add(&p->events, -events);
+	p->period += periods;
+	write_seqcount_end(&p->sequence);
+	local_irq_restore(flags);
+
+	return true;
+}
+
+/*
+ * ---- SINGLE ----
+ */
+
+int fprop_local_init_single(struct fprop_local_single *pl)
+{
+	pl->events = 0;
+	pl->period = 0;
+	raw_spin_lock_init(&pl->lock);
+	return 0;
+}
+
+void fprop_local_destroy_single(struct fprop_local_single *pl)
+{
+}
+
+static void fprop_reflect_period_single(struct fprop_global *p,
+					struct fprop_local_single *pl)
+{
+	unsigned int period = p->period;
+	unsigned long flags;
+
+	/* Fast path - period didn't change */
+	if (pl->period == period)
+		return;
+	raw_spin_lock_irqsave(&pl->lock, flags);
+	/* Someone updated pl->period while we were spinning? */
+	if (pl->period >= period) {
+		raw_spin_unlock_irqrestore(&pl->lock, flags);
+		return;
+	}
+	/* Aging zeroed our fraction? */
+	if (period - pl->period < BITS_PER_LONG)
+		pl->events >>= period - pl->period;
+	else
+		pl->events = 0;
+	pl->period = period;
+	raw_spin_unlock_irqrestore(&pl->lock, flags);
+}
+
+/* Event of type pl happened */
+void __fprop_inc_single(struct fprop_global *p, struct fprop_local_single *pl)
+{
+	fprop_reflect_period_single(p, pl);
+	pl->events++;
+	percpu_counter_add(&p->events, 1);
+}
+
+/* Return fraction of events of type pl */
+void fprop_fraction_single(struct fprop_global *p,
+			   struct fprop_local_single *pl,
+			   unsigned long *numerator, unsigned long *denominator)
+{
+	unsigned int seq;
+	s64 num, den;
+
+	do {
+		seq = read_seqcount_begin(&p->sequence);
+		fprop_reflect_period_single(p, pl);
+		num = pl->events;
+		den = percpu_counter_read_positive(&p->events);
+	} while (read_seqcount_retry(&p->sequence, seq));
+
+	/*
+	 * Make fraction <= 1 and denominator > 0 even in presence of percpu
+	 * counter errors
+	 */
+	if (den <= num) {
+		if (num)
+			den = num;
+		else
+			den = 1;
+	}
+	*denominator = den;
+	*numerator = num;
+}
+
+/*
+ * ---- PERCPU ----
+ */
+#define PROP_BATCH (8*(1+ilog2(nr_cpu_ids)))
+
+int fprop_local_init_percpu(struct fprop_local_percpu *pl)
+{
+	int err;
+
+	err = percpu_counter_init(&pl->events, 0);
+	if (err)
+		return err;
+	pl->period = 0;
+	raw_spin_lock_init(&pl->lock);
+	return 0;
+}
+
+void fprop_local_destroy_percpu(struct fprop_local_percpu *pl)
+{
+	percpu_counter_destroy(&pl->events);
+}
+
+static void fprop_reflect_period_percpu(struct fprop_global *p,
+					struct fprop_local_percpu *pl)
+{
+	unsigned int period = p->period;
+	unsigned long flags;
+
+	/* Fast path - period didn't change */
+	if (pl->period == period)
+		return;
+	raw_spin_lock_irqsave(&pl->lock, flags);
+	/* Someone updated pl->period while we were spinning? */
+	if (pl->period >= period) {
+		raw_spin_unlock_irqrestore(&pl->lock, flags);
+		return;
+	}
+	/* Aging zeroed our fraction? */
+	if (period - pl->period < BITS_PER_LONG) {
+		s64 val = percpu_counter_read(&pl->events);
+
+		if (val < (nr_cpu_ids * PROP_BATCH))
+			val = percpu_counter_sum(&pl->events);
+
+		__percpu_counter_add(&pl->events,
+			-val + (val >> (period-pl->period)), PROP_BATCH);
+	} else
+		percpu_counter_set(&pl->events, 0);
+	pl->period = period;
+	raw_spin_unlock_irqrestore(&pl->lock, flags);
+}
+
+/* Event of type pl happened */
+void __fprop_inc_percpu(struct fprop_global *p, struct fprop_local_percpu *pl)
+{
+	fprop_reflect_period_percpu(p, pl);
+	__percpu_counter_add(&pl->events, 1, PROP_BATCH);
+	percpu_counter_add(&p->events, 1);
+}
+
+void fprop_fraction_percpu(struct fprop_global *p,
+			   struct fprop_local_percpu *pl,
+			   unsigned long *numerator, unsigned long *denominator)
+{
+	unsigned int seq;
+	s64 num, den;
+
+	do {
+		seq = read_seqcount_begin(&p->sequence);
+		fprop_reflect_period_percpu(p, pl);
+		num = percpu_counter_read_positive(&pl->events);
+		den = percpu_counter_read_positive(&p->events);
+	} while (read_seqcount_retry(&p->sequence, seq));
+
+	/*
+	 * Make fraction <= 1 and denominator > 0 even in presence of percpu
+	 * counter errors
+	 */
+	if (den <= num) {
+		if (num)
+			den = num;
+		else
+			den = 1;
+	}
+	*denominator = den;
+	*numerator = num;
+}
+
+/*
+ * Like __fprop_inc_percpu() except that event is counted only if the given
+ * type has fraction smaller than @max_frac/FPROP_FRAC_BASE
+ */
+void __fprop_inc_percpu_max(struct fprop_global *p,
+			    struct fprop_local_percpu *pl, int max_frac)
+{
+	if (unlikely(max_frac < FPROP_FRAC_BASE)) {
+		unsigned long numerator, denominator;
+
+		fprop_fraction_percpu(p, pl, &numerator, &denominator);
+		if (numerator >
+		    (((u64)denominator) * max_frac) >> FPROP_FRAC_SHIFT)
+			return;
+	} else
+		fprop_reflect_period_percpu(p, pl);
+	__percpu_counter_add(&pl->events, 1, PROP_BATCH);
+	percpu_counter_add(&p->events, 1);
+}
diff --git a/lib/memweight.c b/lib/memweight.c
new file mode 100644
index 0000000..e35fc87
--- /dev/null
+++ b/lib/memweight.c
@@ -0,0 +1,38 @@
+#include <linux/export.h>
+#include <linux/bug.h>
+#include <linux/bitmap.h>
+
+/**
+ * memweight - count the total number of bits set in memory area
+ * @ptr: pointer to the start of the area
+ * @bytes: the size of the area
+ */
+size_t memweight(const void *ptr, size_t bytes)
+{
+	size_t ret = 0;
+	size_t longs;
+	const unsigned char *bitmap = ptr;
+
+	for (; bytes > 0 && ((unsigned long)bitmap) % sizeof(long);
+			bytes--, bitmap++)
+		ret += hweight8(*bitmap);
+
+	longs = bytes / sizeof(long);
+	if (longs) {
+		BUG_ON(longs >= INT_MAX / BITS_PER_LONG);
+		ret += bitmap_weight((unsigned long *)bitmap,
+				longs * BITS_PER_LONG);
+		bytes -= longs * sizeof(long);
+		bitmap += longs * sizeof(long);
+	}
+	/*
+	 * The reason that this last loop is distinct from the preceding
+	 * bitmap_weight() call is to compute 1-bits in the last region smaller
+	 * than sizeof(long) properly on big-endian systems.
+	 */
+	for (; bytes > 0; bytes--, bitmap++)
+		ret += hweight8(*bitmap);
+
+	return ret;
+}
+EXPORT_SYMBOL(memweight);
diff --git a/lib/mpi/Makefile b/lib/mpi/Makefile
index 567d52e..45ca90a 100644
--- a/lib/mpi/Makefile
+++ b/lib/mpi/Makefile
@@ -19,14 +19,3 @@ mpi-y = \
 	mpih-mul.o			\
 	mpi-pow.o			\
 	mpiutil.o
-
-mpi-$(CONFIG_MPILIB_EXTRA) += \
-	mpi-add.o			\
-	mpi-div.o			\
-	mpi-cmp.o			\
-	mpi-gcd.o			\
-	mpi-inline.o			\
-	mpi-inv.o			\
-	mpi-mpow.o			\
-	mpi-mul.o			\
-	mpi-scan.o
diff --git a/lib/mpi/generic_mpi-asm-defs.h b/lib/mpi/generic_mpi-asm-defs.h
deleted file mode 100644
index 047d1f5..0000000
--- a/lib/mpi/generic_mpi-asm-defs.h
+++ /dev/null
@@ -1,4 +0,0 @@
-/* This file defines some basic constants for the MPI machinery.  We
- * need to define the types on a per-CPU basis, so it is done with
- * this file here.  */
-#define BYTES_PER_MPI_LIMB  (SIZEOF_UNSIGNED_LONG)
diff --git a/lib/mpi/mpi-add.c b/lib/mpi/mpi-add.c
deleted file mode 100644
index f56b9ba..0000000
--- a/lib/mpi/mpi-add.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/* mpi-add.c  -  MPI functions
- *	Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- *	Copyright (C) 1994, 1996 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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
- *
- * Note: This code is heavily based on the GNU MP Library.
- *	 Actually it's the same code with only minor changes in the
- *	 way the data is stored; this is to support the abstraction
- *	 of an optional secure memory allocation which may be used
- *	 to avoid revealing of sensitive data due to paging etc.
- *	 The GNU MP Library itself is published under the LGPL;
- *	 however I decided to publish this code under the plain GPL.
- */
-
-#include "mpi-internal.h"
-
-/****************
- * Add the unsigned integer V to the mpi-integer U and store the
- * result in W. U and V may be the same.
- */
-int mpi_add_ui(MPI w, const MPI u, unsigned long v)
-{
-	mpi_ptr_t wp, up;
-	mpi_size_t usize, wsize;
-	int usign, wsign;
-
-	usize = u->nlimbs;
-	usign = u->sign;
-	wsign = 0;
-
-	/* If not space for W (and possible carry), increase space.  */
-	wsize = usize + 1;
-	if (w->alloced < wsize)
-		if (mpi_resize(w, wsize) < 0)
-			return -ENOMEM;
-
-	/* These must be after realloc (U may be the same as W).  */
-	up = u->d;
-	wp = w->d;
-
-	if (!usize) {		/* simple */
-		wp[0] = v;
-		wsize = v ? 1 : 0;
-	} else if (!usign) {	/* mpi is not negative */
-		mpi_limb_t cy;
-		cy = mpihelp_add_1(wp, up, usize, v);
-		wp[usize] = cy;
-		wsize = usize + cy;
-	} else {		/* The signs are different.  Need exact comparison to determine
-				 * which operand to subtract from which.  */
-		if (usize == 1 && up[0] < v) {
-			wp[0] = v - up[0];
-			wsize = 1;
-		} else {
-			mpihelp_sub_1(wp, up, usize, v);
-			/* Size can decrease with at most one limb. */
-			wsize = usize - (wp[usize - 1] == 0);
-			wsign = 1;
-		}
-	}
-
-	w->nlimbs = wsize;
-	w->sign = wsign;
-	return 0;
-}
-
-int mpi_add(MPI w, MPI u, MPI v)
-{
-	mpi_ptr_t wp, up, vp;
-	mpi_size_t usize, vsize, wsize;
-	int usign, vsign, wsign;
-
-	if (u->nlimbs < v->nlimbs) {	/* Swap U and V. */
-		usize = v->nlimbs;
-		usign = v->sign;
-		vsize = u->nlimbs;
-		vsign = u->sign;
-		wsize = usize + 1;
-		if (RESIZE_IF_NEEDED(w, wsize) < 0)
-			return -ENOMEM;
-		/* These must be after realloc (u or v may be the same as w).  */
-		up = v->d;
-		vp = u->d;
-	} else {
-		usize = u->nlimbs;
-		usign = u->sign;
-		vsize = v->nlimbs;
-		vsign = v->sign;
-		wsize = usize + 1;
-		if (RESIZE_IF_NEEDED(w, wsize) < 0)
-			return -ENOMEM;
-		/* These must be after realloc (u or v may be the same as w).  */
-		up = u->d;
-		vp = v->d;
-	}
-	wp = w->d;
-	wsign = 0;
-
-	if (!vsize) {		/* simple */
-		MPN_COPY(wp, up, usize);
-		wsize = usize;
-		wsign = usign;
-	} else if (usign != vsign) {	/* different sign */
-		/* This test is right since USIZE >= VSIZE */
-		if (usize != vsize) {
-			mpihelp_sub(wp, up, usize, vp, vsize);
-			wsize = usize;
-			MPN_NORMALIZE(wp, wsize);
-			wsign = usign;
-		} else if (mpihelp_cmp(up, vp, usize) < 0) {
-			mpihelp_sub_n(wp, vp, up, usize);
-			wsize = usize;
-			MPN_NORMALIZE(wp, wsize);
-			if (!usign)
-				wsign = 1;
-		} else {
-			mpihelp_sub_n(wp, up, vp, usize);
-			wsize = usize;
-			MPN_NORMALIZE(wp, wsize);
-			if (usign)
-				wsign = 1;
-		}
-	} else {		/* U and V have same sign. Add them. */
-		mpi_limb_t cy = mpihelp_add(wp, up, usize, vp, vsize);
-		wp[usize] = cy;
-		wsize = usize + cy;
-		if (usign)
-			wsign = 1;
-	}
-
-	w->nlimbs = wsize;
-	w->sign = wsign;
-	return 0;
-}
-
-/****************
- * Subtract the unsigned integer V from the mpi-integer U and store the
- * result in W.
- */
-int mpi_sub_ui(MPI w, MPI u, unsigned long v)
-{
-	mpi_ptr_t wp, up;
-	mpi_size_t usize, wsize;
-	int usign, wsign;
-
-	usize = u->nlimbs;
-	usign = u->sign;
-	wsign = 0;
-
-	/* If not space for W (and possible carry), increase space.  */
-	wsize = usize + 1;
-	if (w->alloced < wsize)
-		if (mpi_resize(w, wsize) < 0)
-			return -ENOMEM;
-
-	/* These must be after realloc (U may be the same as W).  */
-	up = u->d;
-	wp = w->d;
-
-	if (!usize) {		/* simple */
-		wp[0] = v;
-		wsize = v ? 1 : 0;
-		wsign = 1;
-	} else if (usign) {	/* mpi and v are negative */
-		mpi_limb_t cy;
-		cy = mpihelp_add_1(wp, up, usize, v);
-		wp[usize] = cy;
-		wsize = usize + cy;
-	} else {		/* The signs are different.  Need exact comparison to determine
-				 * which operand to subtract from which.  */
-		if (usize == 1 && up[0] < v) {
-			wp[0] = v - up[0];
-			wsize = 1;
-			wsign = 1;
-		} else {
-			mpihelp_sub_1(wp, up, usize, v);
-			/* Size can decrease with at most one limb. */
-			wsize = usize - (wp[usize - 1] == 0);
-		}
-	}
-
-	w->nlimbs = wsize;
-	w->sign = wsign;
-	return 0;
-}
-
-int mpi_sub(MPI w, MPI u, MPI v)
-{
-	int rc;
-
-	if (w == v) {
-		MPI vv;
-		if (mpi_copy(&vv, v) < 0)
-			return -ENOMEM;
-		vv->sign = !vv->sign;
-		rc = mpi_add(w, u, vv);
-		mpi_free(vv);
-	} else {
-		/* fixme: this is not thread-save (we temp. modify v) */
-		v->sign = !v->sign;
-		rc = mpi_add(w, u, v);
-		v->sign = !v->sign;
-	}
-	return rc;
-}
-
-int mpi_addm(MPI w, MPI u, MPI v, MPI m)
-{
-	if (mpi_add(w, u, v) < 0 || mpi_fdiv_r(w, w, m) < 0)
-		return -ENOMEM;
-	return 0;
-}
-
-int mpi_subm(MPI w, MPI u, MPI v, MPI m)
-{
-	if (mpi_sub(w, u, v) < 0 || mpi_fdiv_r(w, w, m) < 0)
-		return -ENOMEM;
-	return 0;
-}
diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c
index 0c50536..5687248 100644
--- a/lib/mpi/mpi-bit.c
+++ b/lib/mpi/mpi-bit.c
@@ -54,165 +54,3 @@ unsigned mpi_get_nbits(MPI a)
 	return n;
 }
 EXPORT_SYMBOL_GPL(mpi_get_nbits);
-
-/****************
- * Test whether bit N is set.
- */
-int mpi_test_bit(MPI a, unsigned n)
-{
-	unsigned limbno, bitno;
-	mpi_limb_t limb;
-
-	limbno = n / BITS_PER_MPI_LIMB;
-	bitno = n % BITS_PER_MPI_LIMB;
-
-	if (limbno >= a->nlimbs)
-		return 0;	/* too far left: this is a 0 */
-	limb = a->d[limbno];
-	return (limb & (A_LIMB_1 << bitno)) ? 1 : 0;
-}
-
-/****************
- * Set bit N of A.
- */
-int mpi_set_bit(MPI a, unsigned n)
-{
-	unsigned limbno, bitno;
-
-	limbno = n / BITS_PER_MPI_LIMB;
-	bitno = n % BITS_PER_MPI_LIMB;
-
-	if (limbno >= a->nlimbs) {	/* resize */
-		if (a->alloced >= limbno)
-			if (mpi_resize(a, limbno + 1) < 0)
-				return -ENOMEM;
-		a->nlimbs = limbno + 1;
-	}
-	a->d[limbno] |= (A_LIMB_1 << bitno);
-	return 0;
-}
-
-/****************
- * Set bit N of A. and clear all bits above
- */
-int mpi_set_highbit(MPI a, unsigned n)
-{
-	unsigned limbno, bitno;
-
-	limbno = n / BITS_PER_MPI_LIMB;
-	bitno = n % BITS_PER_MPI_LIMB;
-
-	if (limbno >= a->nlimbs) {	/* resize */
-		if (a->alloced >= limbno)
-			if (mpi_resize(a, limbno + 1) < 0)
-				return -ENOMEM;
-		a->nlimbs = limbno + 1;
-	}
-	a->d[limbno] |= (A_LIMB_1 << bitno);
-	for (bitno++; bitno < BITS_PER_MPI_LIMB; bitno++)
-		a->d[limbno] &= ~(A_LIMB_1 << bitno);
-	a->nlimbs = limbno + 1;
-	return 0;
-}
-
-/****************
- * clear bit N of A and all bits above
- */
-void mpi_clear_highbit(MPI a, unsigned n)
-{
-	unsigned limbno, bitno;
-
-	limbno = n / BITS_PER_MPI_LIMB;
-	bitno = n % BITS_PER_MPI_LIMB;
-
-	if (limbno >= a->nlimbs)
-		return;		/* not allocated, so need to clear bits :-) */
-
-	for (; bitno < BITS_PER_MPI_LIMB; bitno++)
-		a->d[limbno] &= ~(A_LIMB_1 << bitno);
-	a->nlimbs = limbno + 1;
-}
-
-/****************
- * Clear bit N of A.
- */
-void mpi_clear_bit(MPI a, unsigned n)
-{
-	unsigned limbno, bitno;
-
-	limbno = n / BITS_PER_MPI_LIMB;
-	bitno = n % BITS_PER_MPI_LIMB;
-
-	if (limbno >= a->nlimbs)
-		return;		/* don't need to clear this bit, it's to far to left */
-	a->d[limbno] &= ~(A_LIMB_1 << bitno);
-}
-
-/****************
- * Shift A by N bits to the right
- * FIXME: should use alloc_limb if X and A are same.
- */
-int mpi_rshift(MPI x, MPI a, unsigned n)
-{
-	mpi_ptr_t xp;
-	mpi_size_t xsize;
-
-	xsize = a->nlimbs;
-	x->sign = a->sign;
-	if (RESIZE_IF_NEEDED(x, (size_t) xsize) < 0)
-		return -ENOMEM;
-	xp = x->d;
-
-	if (xsize) {
-		mpihelp_rshift(xp, a->d, xsize, n);
-		MPN_NORMALIZE(xp, xsize);
-	}
-	x->nlimbs = xsize;
-	return 0;
-}
-
-/****************
- * Shift A by COUNT limbs to the left
- * This is used only within the MPI library
- */
-int mpi_lshift_limbs(MPI a, unsigned int count)
-{
-	const int n = a->nlimbs;
-	mpi_ptr_t ap;
-	int i;
-
-	if (!count || !n)
-		return 0;
-
-	if (RESIZE_IF_NEEDED(a, n + count) < 0)
-		return -ENOMEM;
-
-	ap = a->d;
-	for (i = n - 1; i >= 0; i--)
-		ap[i + count] = ap[i];
-	for (i = 0; i < count; i++)
-		ap[i] = 0;
-	a->nlimbs += count;
-	return 0;
-}
-
-/****************
- * Shift A by COUNT limbs to the right
- * This is used only within the MPI library
- */
-void mpi_rshift_limbs(MPI a, unsigned int count)
-{
-	mpi_ptr_t ap = a->d;
-	mpi_size_t n = a->nlimbs;
-	unsigned int i;
-
-	if (count >= n) {
-		a->nlimbs = 0;
-		return;
-	}
-
-	for (i = 0; i < n - count; i++)
-		ap[i] = ap[i + count];
-	ap[i] = 0;
-	a->nlimbs -= count;
-}
diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c
deleted file mode 100644
index 914bc42..0000000
--- a/lib/mpi/mpi-cmp.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/* mpi-cmp.c  -  MPI functions
- * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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 "mpi-internal.h"
-
-int mpi_cmp_ui(MPI u, unsigned long v)
-{
-	mpi_limb_t limb = v;
-
-	mpi_normalize(u);
-	if (!u->nlimbs && !limb)
-		return 0;
-	if (u->sign)
-		return -1;
-	if (u->nlimbs > 1)
-		return 1;
-
-	if (u->d[0] == limb)
-		return 0;
-	else if (u->d[0] > limb)
-		return 1;
-	else
-		return -1;
-}
-
-int mpi_cmp(MPI u, MPI v)
-{
-	mpi_size_t usize, vsize;
-	int cmp;
-
-	mpi_normalize(u);
-	mpi_normalize(v);
-	usize = u->nlimbs;
-	vsize = v->nlimbs;
-	if (!u->sign && v->sign)
-		return 1;
-	if (u->sign && !v->sign)
-		return -1;
-	if (usize != vsize && !u->sign && !v->sign)
-		return usize - vsize;
-	if (usize != vsize && u->sign && v->sign)
-		return vsize + usize;
-	if (!usize)
-		return 0;
-	cmp = mpihelp_cmp(u->d, v->d, usize);
-	if (!cmp)
-		return 0;
-	if ((cmp < 0 ? 1 : 0) == (u->sign ? 1 : 0))
-		return 1;
-	return -1;
-}
diff --git a/lib/mpi/mpi-div.c b/lib/mpi/mpi-div.c
deleted file mode 100644
index f68cbbb..0000000
--- a/lib/mpi/mpi-div.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/* mpi-div.c  -  MPI functions
- *	Copyright (C) 1994, 1996 Free Software Foundation, Inc.
- *	Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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
- *
- * Note: This code is heavily based on the GNU MP Library.
- *	 Actually it's the same code with only minor changes in the
- *	 way the data is stored; this is to support the abstraction
- *	 of an optional secure memory allocation which may be used
- *	 to avoid revealing of sensitive data due to paging etc.
- *	 The GNU MP Library itself is published under the LGPL;
- *	 however I decided to publish this code under the plain GPL.
- */
-
-#include <linux/string.h>
-#include "mpi-internal.h"
-#include "longlong.h"
-
-int mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor)
-{
-	int rc = -ENOMEM;
-	int divisor_sign = divisor->sign;
-	MPI temp_divisor = NULL;
-
-	/* We need the original value of the divisor after the remainder has been
-	 * preliminary calculated.      We have to copy it to temporary space if it's
-	 * the same variable as REM.  */
-	if (rem == divisor) {
-		if (mpi_copy(&temp_divisor, divisor) < 0)
-			goto nomem;
-		divisor = temp_divisor;
-	}
-
-	if (mpi_tdiv_qr(NULL, rem, dividend, divisor) < 0)
-		goto nomem;
-	if (((divisor_sign ? 1 : 0) ^ (dividend->sign ? 1 : 0)) && rem->nlimbs)
-		if (mpi_add(rem, rem, divisor) < 0)
-			goto nomem;
-
-	rc = 0;
-
-nomem:
-	if (temp_divisor)
-		mpi_free(temp_divisor);
-	return rc;
-}
-
-/****************
- * Division rounding the quotient towards -infinity.
- * The remainder gets the same sign as the denominator.
- * rem is optional
- */
-
-ulong mpi_fdiv_r_ui(MPI rem, MPI dividend, ulong divisor)
-{
-	mpi_limb_t rlimb;
-
-	rlimb = mpihelp_mod_1(dividend->d, dividend->nlimbs, divisor);
-	if (rlimb && dividend->sign)
-		rlimb = divisor - rlimb;
-
-	if (rem) {
-		rem->d[0] = rlimb;
-		rem->nlimbs = rlimb ? 1 : 0;
-	}
-	return rlimb;
-}
-
-int mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor)
-{
-	MPI tmp = mpi_alloc(mpi_get_nlimbs(quot));
-	if (!tmp)
-		return -ENOMEM;
-	mpi_fdiv_qr(quot, tmp, dividend, divisor);
-	mpi_free(tmp);
-	return 0;
-}
-
-int mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor)
-{
-	int divisor_sign = divisor->sign;
-	MPI temp_divisor = NULL;
-
-	if (quot == divisor || rem == divisor) {
-		if (mpi_copy(&temp_divisor, divisor) < 0)
-			return -ENOMEM;
-		divisor = temp_divisor;
-	}
-
-	if (mpi_tdiv_qr(quot, rem, dividend, divisor) < 0)
-		goto nomem;
-
-	if ((divisor_sign ^ dividend->sign) && rem->nlimbs) {
-		if (mpi_sub_ui(quot, quot, 1) < 0)
-			goto nomem;
-		if (mpi_add(rem, rem, divisor) < 0)
-			goto nomem;
-	}
-
-	if (temp_divisor)
-		mpi_free(temp_divisor);
-
-	return 0;
-
-nomem:
-	mpi_free(temp_divisor);
-	return -ENOMEM;
-}
-
-/* If den == quot, den needs temporary storage.
- * If den == rem, den needs temporary storage.
- * If num == quot, num needs temporary storage.
- * If den has temporary storage, it can be normalized while being copied,
- *   i.e no extra storage should be allocated.
- */
-
-int mpi_tdiv_r(MPI rem, MPI num, MPI den)
-{
-	return mpi_tdiv_qr(NULL, rem, num, den);
-}
-
-int mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den)
-{
-	int rc = -ENOMEM;
-	mpi_ptr_t np, dp;
-	mpi_ptr_t qp, rp;
-	mpi_size_t nsize = num->nlimbs;
-	mpi_size_t dsize = den->nlimbs;
-	mpi_size_t qsize, rsize;
-	mpi_size_t sign_remainder = num->sign;
-	mpi_size_t sign_quotient = num->sign ^ den->sign;
-	unsigned normalization_steps;
-	mpi_limb_t q_limb;
-	mpi_ptr_t marker[5];
-	int markidx = 0;
-
-	if (!dsize)
-		return -EINVAL;
-
-	memset(marker, 0, sizeof(marker));
-
-	/* Ensure space is enough for quotient and remainder.
-	 * We need space for an extra limb in the remainder, because it's
-	 * up-shifted (normalized) below.  */
-	rsize = nsize + 1;
-	if (mpi_resize(rem, rsize) < 0)
-		goto nomem;
-
-	qsize = rsize - dsize;	/* qsize cannot be bigger than this.  */
-	if (qsize <= 0) {
-		if (num != rem) {
-			rem->nlimbs = num->nlimbs;
-			rem->sign = num->sign;
-			MPN_COPY(rem->d, num->d, nsize);
-		}
-		if (quot) {
-			/* This needs to follow the assignment to rem, in case the
-			 * numerator and quotient are the same.  */
-			quot->nlimbs = 0;
-			quot->sign = 0;
-		}
-		return 0;
-	}
-
-	if (quot)
-		if (mpi_resize(quot, qsize) < 0)
-			goto nomem;
-
-	/* Read pointers here, when reallocation is finished.  */
-	np = num->d;
-	dp = den->d;
-	rp = rem->d;
-
-	/* Optimize division by a single-limb divisor.  */
-	if (dsize == 1) {
-		mpi_limb_t rlimb;
-		if (quot) {
-			qp = quot->d;
-			rlimb = mpihelp_divmod_1(qp, np, nsize, dp[0]);
-			qsize -= qp[qsize - 1] == 0;
-			quot->nlimbs = qsize;
-			quot->sign = sign_quotient;
-		} else
-			rlimb = mpihelp_mod_1(np, nsize, dp[0]);
-		rp[0] = rlimb;
-		rsize = rlimb != 0 ? 1 : 0;
-		rem->nlimbs = rsize;
-		rem->sign = sign_remainder;
-		return 0;
-	}
-
-	if (quot) {
-		qp = quot->d;
-		/* Make sure QP and NP point to different objects.  Otherwise the
-		 * numerator would be gradually overwritten by the quotient limbs.  */
-		if (qp == np) {	/* Copy NP object to temporary space.  */
-			np = marker[markidx++] = mpi_alloc_limb_space(nsize);
-			if (!np)
-				goto nomem;
-			MPN_COPY(np, qp, nsize);
-		}
-	} else			/* Put quotient at top of remainder. */
-		qp = rp + dsize;
-
-	count_leading_zeros(normalization_steps, dp[dsize - 1]);
-
-	/* Normalize the denominator, i.e. make its most significant bit set by
-	 * shifting it NORMALIZATION_STEPS bits to the left.  Also shift the
-	 * numerator the same number of steps (to keep the quotient the same!).
-	 */
-	if (normalization_steps) {
-		mpi_ptr_t tp;
-		mpi_limb_t nlimb;
-
-		/* Shift up the denominator setting the most significant bit of
-		 * the most significant word.  Use temporary storage not to clobber
-		 * the original contents of the denominator.  */
-		tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
-		if (!tp)
-			goto nomem;
-		mpihelp_lshift(tp, dp, dsize, normalization_steps);
-		dp = tp;
-
-		/* Shift up the numerator, possibly introducing a new most
-		 * significant word.  Move the shifted numerator in the remainder
-		 * meanwhile.  */
-		nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps);
-		if (nlimb) {
-			rp[nsize] = nlimb;
-			rsize = nsize + 1;
-		} else
-			rsize = nsize;
-	} else {
-		/* The denominator is already normalized, as required.  Copy it to
-		 * temporary space if it overlaps with the quotient or remainder.  */
-		if (dp == rp || (quot && (dp == qp))) {
-			mpi_ptr_t tp;
-
-			tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
-			if (!tp)
-				goto nomem;
-			MPN_COPY(tp, dp, dsize);
-			dp = tp;
-		}
-
-		/* Move the numerator to the remainder.  */
-		if (rp != np)
-			MPN_COPY(rp, np, nsize);
-
-		rsize = nsize;
-	}
-
-	q_limb = mpihelp_divrem(qp, 0, rp, rsize, dp, dsize);
-
-	if (quot) {
-		qsize = rsize - dsize;
-		if (q_limb) {
-			qp[qsize] = q_limb;
-			qsize += 1;
-		}
-
-		quot->nlimbs = qsize;
-		quot->sign = sign_quotient;
-	}
-
-	rsize = dsize;
-	MPN_NORMALIZE(rp, rsize);
-
-	if (normalization_steps && rsize) {
-		mpihelp_rshift(rp, rp, rsize, normalization_steps);
-		rsize -= rp[rsize - 1] == 0 ? 1 : 0;
-	}
-
-	rem->nlimbs = rsize;
-	rem->sign = sign_remainder;
-
-	rc = 0;
-nomem:
-	while (markidx)
-		mpi_free_limb_space(marker[--markidx]);
-	return rc;
-}
-
-int mpi_tdiv_q_2exp(MPI w, MPI u, unsigned count)
-{
-	mpi_size_t usize, wsize;
-	mpi_size_t limb_cnt;
-
-	usize = u->nlimbs;
-	limb_cnt = count / BITS_PER_MPI_LIMB;
-	wsize = usize - limb_cnt;
-	if (limb_cnt >= usize)
-		w->nlimbs = 0;
-	else {
-		mpi_ptr_t wp;
-		mpi_ptr_t up;
-
-		if (RESIZE_IF_NEEDED(w, wsize) < 0)
-			return -ENOMEM;
-		wp = w->d;
-		up = u->d;
-
-		count %= BITS_PER_MPI_LIMB;
-		if (count) {
-			mpihelp_rshift(wp, up + limb_cnt, wsize, count);
-			wsize -= !wp[wsize - 1];
-		} else {
-			MPN_COPY_INCR(wp, up + limb_cnt, wsize);
-		}
-
-		w->nlimbs = wsize;
-	}
-	return 0;
-}
-
-/****************
- * Check whether dividend is divisible by divisor
- * (note: divisor must fit into a limb)
- */
-int mpi_divisible_ui(MPI dividend, ulong divisor)
-{
-	return !mpihelp_mod_1(dividend->d, dividend->nlimbs, divisor);
-}
diff --git a/lib/mpi/mpi-gcd.c b/lib/mpi/mpi-gcd.c
deleted file mode 100644
index 13c48ae..0000000
--- a/lib/mpi/mpi-gcd.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/* mpi-gcd.c  -  MPI functions
- * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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 "mpi-internal.h"
-
-/****************
- * Find the greatest common divisor G of A and B.
- * Return: true if this 1, false in all other cases
- */
-int mpi_gcd(MPI g, const MPI xa, const MPI xb)
-{
-	MPI a = NULL, b = NULL;
-
-	if (mpi_copy(&a, xa) < 0)
-		goto nomem;
-
-	if (mpi_copy(&b, xb) < 0)
-		goto nomem;
-
-	/* TAOCP Vol II, 4.5.2, Algorithm A */
-	a->sign = 0;
-	b->sign = 0;
-	while (mpi_cmp_ui(b, 0)) {
-		if (mpi_fdiv_r(g, a, b) < 0)	/* g used as temorary variable */
-			goto nomem;
-		if (mpi_set(a, b) < 0)
-			goto nomem;
-		if (mpi_set(b, g) < 0)
-			goto nomem;
-	}
-	if (mpi_set(g, a) < 0)
-		goto nomem;
-
-	mpi_free(a);
-	mpi_free(b);
-	return !mpi_cmp_ui(g, 1);
-
-nomem:
-	mpi_free(a);
-	mpi_free(b);
-	return -ENOMEM;
-}
diff --git a/lib/mpi/mpi-inline.c b/lib/mpi/mpi-inline.c
deleted file mode 100644
index 654f68a..0000000
--- a/lib/mpi/mpi-inline.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* mpi-inline.c
- * Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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
- */
-
-/* put the inline functions as real functions into the lib */
-#define G10_MPI_INLINE_DECL
-
-#include "mpi-internal.h"
-
-/* always include the header becuase it is only
- * included by mpi-internal if __GCC__ is defined but we
- * need it here in all cases and the above definition of
- * of the macro allows us to do so
- */
-#include "mpi-inline.h"
diff --git a/lib/mpi/mpi-inv.c b/lib/mpi/mpi-inv.c
deleted file mode 100644
index 0951f98..0000000
--- a/lib/mpi/mpi-inv.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/* mpi-inv.c  -  MPI functions
- * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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 "mpi-internal.h"
-
-/****************
- * Calculate the multiplicative inverse X of A mod N
- * That is: Find the solution x for
- *		1 = (a*x) mod n
- */
-int mpi_invm(MPI x, const MPI a, const MPI n)
-{
-	/* Extended Euclid's algorithm (See TAOPC Vol II, 4.5.2, Alg X)
-	 * modified according to Michael Penk's solution for Exercice 35
-	 * with further enhancement */
-	MPI u = NULL, v = NULL;
-	MPI u1 = NULL, u2 = NULL, u3 = NULL;
-	MPI v1 = NULL, v2 = NULL, v3 = NULL;
-	MPI t1 = NULL, t2 = NULL, t3 = NULL;
-	unsigned k;
-	int sign;
-	int odd = 0;
-	int rc = -ENOMEM;
-
-	if (mpi_copy(&u, a) < 0)
-		goto cleanup;
-	if (mpi_copy(&v, n) < 0)
-		goto cleanup;
-
-	for (k = 0; !mpi_test_bit(u, 0) && !mpi_test_bit(v, 0); k++) {
-		if (mpi_rshift(u, u, 1) < 0)
-			goto cleanup;
-		if (mpi_rshift(v, v, 1) < 0)
-			goto cleanup;
-	}
-	odd = mpi_test_bit(v, 0);
-
-	u1 = mpi_alloc_set_ui(1);
-	if (!u1)
-		goto cleanup;
-	if (!odd) {
-		u2 = mpi_alloc_set_ui(0);
-		if (!u2)
-			goto cleanup;
-	}
-	if (mpi_copy(&u3, u) < 0)
-		goto cleanup;
-	if (mpi_copy(&v1, v) < 0)
-		goto cleanup;
-	if (!odd) {
-		v2 = mpi_alloc(mpi_get_nlimbs(u));
-		if (!v2)
-			goto cleanup;
-		if (mpi_sub(v2, u1, u) < 0)
-			goto cleanup;	/* U is used as const 1 */
-	}
-	if (mpi_copy(&v3, v) < 0)
-		goto cleanup;
-	if (mpi_test_bit(u, 0)) {	/* u is odd */
-		t1 = mpi_alloc_set_ui(0);
-		if (!t1)
-			goto cleanup;
-		if (!odd) {
-			t2 = mpi_alloc_set_ui(1);
-			if (!t2)
-				goto cleanup;
-			t2->sign = 1;
-		}
-		if (mpi_copy(&t3, v) < 0)
-			goto cleanup;
-		t3->sign = !t3->sign;
-		goto Y4;
-	} else {
-		t1 = mpi_alloc_set_ui(1);
-		if (!t1)
-			goto cleanup;
-		if (!odd) {
-			t2 = mpi_alloc_set_ui(0);
-			if (!t2)
-				goto cleanup;
-		}
-		if (mpi_copy(&t3, u) < 0)
-			goto cleanup;
-	}
-	do {
-		do {
-			if (!odd) {
-				if (mpi_test_bit(t1, 0) || mpi_test_bit(t2, 0)) {	/* one is odd */
-					if (mpi_add(t1, t1, v) < 0)
-						goto cleanup;
-					if (mpi_sub(t2, t2, u) < 0)
-						goto cleanup;
-				}
-				if (mpi_rshift(t1, t1, 1) < 0)
-					goto cleanup;
-				if (mpi_rshift(t2, t2, 1) < 0)
-					goto cleanup;
-				if (mpi_rshift(t3, t3, 1) < 0)
-					goto cleanup;
-			} else {
-				if (mpi_test_bit(t1, 0))
-					if (mpi_add(t1, t1, v) < 0)
-						goto cleanup;
-				if (mpi_rshift(t1, t1, 1) < 0)
-					goto cleanup;
-				if (mpi_rshift(t3, t3, 1) < 0)
-					goto cleanup;
-			}
-Y4:
-			;
-		} while (!mpi_test_bit(t3, 0));	/* while t3 is even */
-
-		if (!t3->sign) {
-			if (mpi_set(u1, t1) < 0)
-				goto cleanup;
-			if (!odd)
-				if (mpi_set(u2, t2) < 0)
-					goto cleanup;
-			if (mpi_set(u3, t3) < 0)
-				goto cleanup;
-		} else {
-			if (mpi_sub(v1, v, t1) < 0)
-				goto cleanup;
-			sign = u->sign;
-			u->sign = !u->sign;
-			if (!odd)
-				if (mpi_sub(v2, u, t2) < 0)
-					goto cleanup;
-			u->sign = sign;
-			sign = t3->sign;
-			t3->sign = !t3->sign;
-			if (mpi_set(v3, t3) < 0)
-				goto cleanup;
-			t3->sign = sign;
-		}
-		if (mpi_sub(t1, u1, v1) < 0)
-			goto cleanup;
-		if (!odd)
-			if (mpi_sub(t2, u2, v2) < 0)
-				goto cleanup;
-		if (mpi_sub(t3, u3, v3) < 0)
-			goto cleanup;
-		if (t1->sign) {
-			if (mpi_add(t1, t1, v) < 0)
-				goto cleanup;
-			if (!odd)
-				if (mpi_sub(t2, t2, u) < 0)
-					goto cleanup;
-		}
-	} while (mpi_cmp_ui(t3, 0));	/* while t3 != 0 */
-	/* mpi_lshift( u3, k ); */
-	rc = mpi_set(x, u1);
-
-cleanup:
-	mpi_free(u1);
-	mpi_free(v1);
-	mpi_free(t1);
-	if (!odd) {
-		mpi_free(u2);
-		mpi_free(v2);
-		mpi_free(t2);
-	}
-	mpi_free(u3);
-	mpi_free(v3);
-	mpi_free(t3);
-
-	mpi_free(u);
-	mpi_free(v);
-	return rc;
-}
diff --git a/lib/mpi/mpi-mpow.c b/lib/mpi/mpi-mpow.c
deleted file mode 100644
index 7328d0d..0000000
--- a/lib/mpi/mpi-mpow.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/* mpi-mpow.c  -  MPI functions
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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 "mpi-internal.h"
-#include "longlong.h"
-
-static int build_index(const MPI *exparray, int k, int i, int t)
-{
-	int j, bitno;
-	int index = 0;
-
-	bitno = t - i;
-	for (j = k - 1; j >= 0; j--) {
-		index <<= 1;
-		if (mpi_test_bit(exparray[j], bitno))
-			index |= 1;
-	}
-	return index;
-}
-
-/****************
- * RES = (BASE[0] ^ EXP[0]) *  (BASE[1] ^ EXP[1]) * ... * mod M
- */
-int mpi_mulpowm(MPI res, MPI *basearray, MPI *exparray, MPI m)
-{
-	int rc = -ENOMEM;
-	int k;			/* number of elements */
-	int t;			/* bit size of largest exponent */
-	int i, j, idx;
-	MPI *G = NULL;		/* table with precomputed values of size 2^k */
-	MPI tmp = NULL;
-
-	for (k = 0; basearray[k]; k++)
-		;
-	if (!k) {
-		pr_emerg("mpi_mulpowm: assert(k) failed\n");
-		BUG();
-	}
-	for (t = 0, i = 0; (tmp = exparray[i]); i++) {
-		j = mpi_get_nbits(tmp);
-		if (j > t)
-			t = j;
-	}
-	if (i != k) {
-		pr_emerg("mpi_mulpowm: assert(i==k) failed\n");
-		BUG();
-	}
-	if (!t) {
-		pr_emerg("mpi_mulpowm: assert(t) failed\n");
-		BUG();
-	}
-	if (k >= 10) {
-		pr_emerg("mpi_mulpowm: assert(k<10) failed\n");
-		BUG();
-	}
-
-	G = kzalloc((1 << k) * sizeof *G, GFP_KERNEL);
-	if (!G)
-		goto err_out;
-
-	/* and calculate */
-	tmp = mpi_alloc(mpi_get_nlimbs(m) + 1);
-	if (!tmp)
-		goto nomem;
-	if (mpi_set_ui(res, 1) < 0)
-		goto nomem;
-	for (i = 1; i <= t; i++) {
-		if (mpi_mulm(tmp, res, res, m) < 0)
-			goto nomem;
-		idx = build_index(exparray, k, i, t);
-		if (!(idx >= 0 && idx < (1 << k))) {
-			pr_emerg("mpi_mulpowm: assert(idx >= 0 && idx < (1<<k)) failed\n");
-			BUG();
-		}
-		if (!G[idx]) {
-			if (!idx) {
-				G[0] = mpi_alloc_set_ui(1);
-				if (!G[0])
-					goto nomem;
-			} else {
-				for (j = 0; j < k; j++) {
-					if ((idx & (1 << j))) {
-						if (!G[idx]) {
-							if (mpi_copy
-							    (&G[idx],
-							     basearray[j]) < 0)
-								goto nomem;
-						} else {
-							if (mpi_mulm
-							    (G[idx], G[idx],
-							     basearray[j],
-							     m) < 0)
-								goto nomem;
-						}
-					}
-				}
-				if (!G[idx]) {
-					G[idx] = mpi_alloc(0);
-					if (!G[idx])
-						goto nomem;
-				}
-			}
-		}
-		if (mpi_mulm(res, tmp, G[idx], m) < 0)
-			goto nomem;
-	}
-
-	rc = 0;
-nomem:
-	/* cleanup */
-	mpi_free(tmp);
-	for (i = 0; i < (1 << k); i++)
-		mpi_free(G[i]);
-	kfree(G);
-err_out:
-	return rc;
-}
diff --git a/lib/mpi/mpi-mul.c b/lib/mpi/mpi-mul.c
deleted file mode 100644
index 1f3219e..0000000
--- a/lib/mpi/mpi-mul.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/* mpi-mul.c  -  MPI functions
- *	Copyright (C) 1994, 1996 Free Software Foundation, Inc.
- *	Copyright (C) 1998, 2001 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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
- *
- * Note: This code is heavily based on the GNU MP Library.
- *	 Actually it's the same code with only minor changes in the
- *	 way the data is stored; this is to support the abstraction
- *	 of an optional secure memory allocation which may be used
- *	 to avoid revealing of sensitive data due to paging etc.
- *	 The GNU MP Library itself is published under the LGPL;
- *	 however I decided to publish this code under the plain GPL.
- */
-
-#include "mpi-internal.h"
-
-int mpi_mul_ui(MPI prod, MPI mult, unsigned long small_mult)
-{
-	mpi_size_t size, prod_size;
-	mpi_ptr_t prod_ptr;
-	mpi_limb_t cy;
-	int sign;
-
-	size = mult->nlimbs;
-	sign = mult->sign;
-
-	if (!size || !small_mult) {
-		prod->nlimbs = 0;
-		prod->sign = 0;
-		return 0;
-	}
-
-	prod_size = size + 1;
-	if (prod->alloced < prod_size)
-		if (mpi_resize(prod, prod_size) < 0)
-			return -ENOMEM;
-	prod_ptr = prod->d;
-
-	cy = mpihelp_mul_1(prod_ptr, mult->d, size, (mpi_limb_t) small_mult);
-	if (cy)
-		prod_ptr[size++] = cy;
-	prod->nlimbs = size;
-	prod->sign = sign;
-	return 0;
-}
-
-int mpi_mul_2exp(MPI w, MPI u, unsigned long cnt)
-{
-	mpi_size_t usize, wsize, limb_cnt;
-	mpi_ptr_t wp;
-	mpi_limb_t wlimb;
-	int usign, wsign;
-
-	usize = u->nlimbs;
-	usign = u->sign;
-
-	if (!usize) {
-		w->nlimbs = 0;
-		w->sign = 0;
-		return 0;
-	}
-
-	limb_cnt = cnt / BITS_PER_MPI_LIMB;
-	wsize = usize + limb_cnt + 1;
-	if (w->alloced < wsize)
-		if (mpi_resize(w, wsize) < 0)
-			return -ENOMEM;
-	wp = w->d;
-	wsize = usize + limb_cnt;
-	wsign = usign;
-
-	cnt %= BITS_PER_MPI_LIMB;
-	if (cnt) {
-		wlimb = mpihelp_lshift(wp + limb_cnt, u->d, usize, cnt);
-		if (wlimb) {
-			wp[wsize] = wlimb;
-			wsize++;
-		}
-	} else {
-		MPN_COPY_DECR(wp + limb_cnt, u->d, usize);
-	}
-
-	/* Zero all whole limbs at low end.  Do it here and not before calling
-	 * mpn_lshift, not to lose for U == W.  */
-	MPN_ZERO(wp, limb_cnt);
-
-	w->nlimbs = wsize;
-	w->sign = wsign;
-	return 0;
-}
-
-int mpi_mul(MPI w, MPI u, MPI v)
-{
-	int rc = -ENOMEM;
-	mpi_size_t usize, vsize, wsize;
-	mpi_ptr_t up, vp, wp;
-	mpi_limb_t cy;
-	int usign, vsign, sign_product;
-	int assign_wp = 0;
-	mpi_ptr_t tmp_limb = NULL;
-
-	if (u->nlimbs < v->nlimbs) {	/* Swap U and V. */
-		usize = v->nlimbs;
-		usign = v->sign;
-		up = v->d;
-		vsize = u->nlimbs;
-		vsign = u->sign;
-		vp = u->d;
-	} else {
-		usize = u->nlimbs;
-		usign = u->sign;
-		up = u->d;
-		vsize = v->nlimbs;
-		vsign = v->sign;
-		vp = v->d;
-	}
-	sign_product = usign ^ vsign;
-	wp = w->d;
-
-	/* Ensure W has space enough to store the result.  */
-	wsize = usize + vsize;
-	if (w->alloced < (size_t) wsize) {
-		if (wp == up || wp == vp) {
-			wp = mpi_alloc_limb_space(wsize);
-			if (!wp)
-				goto nomem;
-			assign_wp = 1;
-		} else {
-			if (mpi_resize(w, wsize) < 0)
-				goto nomem;
-			wp = w->d;
-		}
-	} else {		/* Make U and V not overlap with W.      */
-		if (wp == up) {
-			/* W and U are identical.  Allocate temporary space for U.      */
-			up = tmp_limb = mpi_alloc_limb_space(usize);
-			if (!up)
-				goto nomem;
-			/* Is V identical too?  Keep it identical with U.  */
-			if (wp == vp)
-				vp = up;
-			/* Copy to the temporary space.  */
-			MPN_COPY(up, wp, usize);
-		} else if (wp == vp) {
-			/* W and V are identical.  Allocate temporary space for V.      */
-			vp = tmp_limb = mpi_alloc_limb_space(vsize);
-			if (!vp)
-				goto nomem;
-			/* Copy to the temporary space.  */
-			MPN_COPY(vp, wp, vsize);
-		}
-	}
-
-	if (!vsize)
-		wsize = 0;
-	else {
-		if (mpihelp_mul(wp, up, usize, vp, vsize, &cy) < 0)
-			goto nomem;
-		wsize -= cy ? 0 : 1;
-	}
-
-	if (assign_wp)
-		mpi_assign_limb_space(w, wp, wsize);
-
-	w->nlimbs = wsize;
-	w->sign = sign_product;
-	rc = 0;
-nomem:
-	if (tmp_limb)
-		mpi_free_limb_space(tmp_limb);
-	return rc;
-}
-
-int mpi_mulm(MPI w, MPI u, MPI v, MPI m)
-{
-	if (mpi_mul(w, u, v) < 0)
-		return -ENOMEM;
-	return mpi_fdiv_r(w, w, m);
-}
diff --git a/lib/mpi/mpi-scan.c b/lib/mpi/mpi-scan.c
deleted file mode 100644
index b2da5ad..0000000
--- a/lib/mpi/mpi-scan.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* mpi-scan.c  -  MPI functions
- * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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 "mpi-internal.h"
-#include "longlong.h"
-
-/****************
- * Scan through an mpi and return byte for byte. a -1 is returned to indicate
- * the end of the mpi. Scanning is done from the lsb to the msb, returned
- * values are in the range of 0 .. 255.
- *
- * FIXME: This code is VERY ugly!
- */
-int mpi_getbyte(const MPI a, unsigned idx)
-{
-	int i, j;
-	unsigned n;
-	mpi_ptr_t ap;
-	mpi_limb_t limb;
-
-	ap = a->d;
-	for (n = 0, i = 0; i < a->nlimbs; i++) {
-		limb = ap[i];
-		for (j = 0; j < BYTES_PER_MPI_LIMB; j++, n++)
-			if (n == idx)
-				return (limb >> j * 8) & 0xff;
-	}
-	return -1;
-}
-
-/****************
- * Put a value at position IDX into A. idx counts from lsb to msb
- */
-void mpi_putbyte(MPI a, unsigned idx, int xc)
-{
-	int i, j;
-	unsigned n;
-	mpi_ptr_t ap;
-	mpi_limb_t limb, c;
-
-	c = xc & 0xff;
-	ap = a->d;
-	for (n = 0, i = 0; i < a->alloced; i++) {
-		limb = ap[i];
-		for (j = 0; j < BYTES_PER_MPI_LIMB; j++, n++)
-			if (n == idx) {
-#if BYTES_PER_MPI_LIMB == 4
-				if (j == 0)
-					limb = (limb & 0xffffff00) | c;
-				else if (j == 1)
-					limb = (limb & 0xffff00ff) | (c << 8);
-				else if (j == 2)
-					limb = (limb & 0xff00ffff) | (c << 16);
-				else
-					limb = (limb & 0x00ffffff) | (c << 24);
-#elif BYTES_PER_MPI_LIMB == 8
-				if (j == 0)
-					limb = (limb & 0xffffffffffffff00) | c;
-				else if (j == 1)
-					limb =
-					    (limb & 0xffffffffffff00ff) | (c <<
-									   8);
-				else if (j == 2)
-					limb =
-					    (limb & 0xffffffffff00ffff) | (c <<
-									   16);
-				else if (j == 3)
-					limb =
-					    (limb & 0xffffffff00ffffff) | (c <<
-									   24);
-				else if (j == 4)
-					limb =
-					    (limb & 0xffffff00ffffffff) | (c <<
-									   32);
-				else if (j == 5)
-					limb =
-					    (limb & 0xffff00ffffffffff) | (c <<
-									   40);
-				else if (j == 6)
-					limb =
-					    (limb & 0xff00ffffffffffff) | (c <<
-									   48);
-				else
-					limb =
-					    (limb & 0x00ffffffffffffff) | (c <<
-									   56);
-#else
-#error please enhance this function, its ugly - i know.
-#endif
-				if (a->nlimbs <= i)
-					a->nlimbs = i + 1;
-				ap[i] = limb;
-				return;
-			}
-	}
-	log_bug("index out of range\n");
-}
-
-/****************
- * Count the number of zerobits at the low end of A
- */
-unsigned mpi_trailing_zeros(const MPI a)
-{
-	unsigned n, count = 0;
-
-	for (n = 0; n < a->nlimbs; n++) {
-		if (a->d[n]) {
-			unsigned nn;
-			mpi_limb_t alimb = a->d[n];
-
-			count_trailing_zeros(nn, alimb);
-			count += nn;
-			break;
-		}
-		count += BITS_PER_MPI_LIMB;
-	}
-	return count;
-
-}
diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c
index f26b41f..f0fa659 100644
--- a/lib/mpi/mpicoder.c
+++ b/lib/mpi/mpicoder.c
@@ -74,81 +74,6 @@ leave:
 EXPORT_SYMBOL_GPL(mpi_read_from_buffer);
 
 /****************
- * Make an mpi from a character string.
- */
-int mpi_fromstr(MPI val, const char *str)
-{
-	int hexmode = 0, sign = 0, prepend_zero = 0, i, j, c, c1, c2;
-	unsigned nbits, nbytes, nlimbs;
-	mpi_limb_t a;
-
-	if (*str == '-') {
-		sign = 1;
-		str++;
-	}
-	if (*str == '0' && str[1] == 'x')
-		hexmode = 1;
-	else
-		return -EINVAL;	/* other bases are not yet supported */
-	str += 2;
-
-	nbits = strlen(str) * 4;
-	if (nbits % 8)
-		prepend_zero = 1;
-	nbytes = (nbits + 7) / 8;
-	nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
-	if (val->alloced < nlimbs)
-		if (!mpi_resize(val, nlimbs))
-			return -ENOMEM;
-	i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
-	i %= BYTES_PER_MPI_LIMB;
-	j = val->nlimbs = nlimbs;
-	val->sign = sign;
-	for (; j > 0; j--) {
-		a = 0;
-		for (; i < BYTES_PER_MPI_LIMB; i++) {
-			if (prepend_zero) {
-				c1 = '0';
-				prepend_zero = 0;
-			} else
-				c1 = *str++;
-			assert(c1);
-			c2 = *str++;
-			assert(c2);
-			if (c1 >= '0' && c1 <= '9')
-				c = c1 - '0';
-			else if (c1 >= 'a' && c1 <= 'f')
-				c = c1 - 'a' + 10;
-			else if (c1 >= 'A' && c1 <= 'F')
-				c = c1 - 'A' + 10;
-			else {
-				mpi_clear(val);
-				return 1;
-			}
-			c <<= 4;
-			if (c2 >= '0' && c2 <= '9')
-				c |= c2 - '0';
-			else if (c2 >= 'a' && c2 <= 'f')
-				c |= c2 - 'a' + 10;
-			else if (c2 >= 'A' && c2 <= 'F')
-				c |= c2 - 'A' + 10;
-			else {
-				mpi_clear(val);
-				return 1;
-			}
-			a <<= 8;
-			a |= c;
-		}
-		i = 0;
-
-		val->d[j - 1] = a;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(mpi_fromstr);
-
-/****************
  * Return an allocated buffer with the MPI (msb first).
  * NBYTES receives the length of this buffer. Caller must free the
  * return string (This function does return a 0 byte buffer with NBYTES
diff --git a/lib/mpi/mpih-div.c b/lib/mpi/mpih-div.c
index cde1aae..c57d1d4 100644
--- a/lib/mpi/mpih-div.c
+++ b/lib/mpi/mpih-div.c
@@ -37,159 +37,6 @@
 #define UDIV_TIME UMUL_TIME
 #endif
 
-/* FIXME: We should be using invert_limb (or invert_normalized_limb)
- * here (not udiv_qrnnd).
- */
-
-mpi_limb_t
-mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
-	      mpi_limb_t divisor_limb)
-{
-	mpi_size_t i;
-	mpi_limb_t n1, n0, r;
-	int dummy;
-
-	/* Botch: Should this be handled at all?  Rely on callers?  */
-	if (!dividend_size)
-		return 0;
-
-	/* If multiplication is much faster than division, and the
-	 * dividend is large, pre-invert the divisor, and use
-	 * only multiplications in the inner loop.
-	 *
-	 * This test should be read:
-	 *   Does it ever help to use udiv_qrnnd_preinv?
-	 *     && Does what we save compensate for the inversion overhead?
-	 */
-	if (UDIV_TIME > (2 * UMUL_TIME + 6)
-	    && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) {
-		int normalization_steps;
-
-		count_leading_zeros(normalization_steps, divisor_limb);
-		if (normalization_steps) {
-			mpi_limb_t divisor_limb_inverted;
-
-			divisor_limb <<= normalization_steps;
-
-			/* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
-			 * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
-			 * most significant bit (with weight 2**N) implicit.
-			 *
-			 * Special case for DIVISOR_LIMB == 100...000.
-			 */
-			if (!(divisor_limb << 1))
-				divisor_limb_inverted = ~(mpi_limb_t) 0;
-			else
-				udiv_qrnnd(divisor_limb_inverted, dummy,
-					   -divisor_limb, 0, divisor_limb);
-
-			n1 = dividend_ptr[dividend_size - 1];
-			r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
-
-			/* Possible optimization:
-			 * if (r == 0
-			 * && divisor_limb > ((n1 << normalization_steps)
-			 *                 | (dividend_ptr[dividend_size - 2] >> ...)))
-			 * ...one division less...
-			 */
-			for (i = dividend_size - 2; i >= 0; i--) {
-				n0 = dividend_ptr[i];
-				UDIV_QRNND_PREINV(dummy, r, r,
-						  ((n1 << normalization_steps)
-						   | (n0 >>
-						      (BITS_PER_MPI_LIMB -
-						       normalization_steps))),
-						  divisor_limb,
-						  divisor_limb_inverted);
-				n1 = n0;
-			}
-			UDIV_QRNND_PREINV(dummy, r, r,
-					  n1 << normalization_steps,
-					  divisor_limb, divisor_limb_inverted);
-			return r >> normalization_steps;
-		} else {
-			mpi_limb_t divisor_limb_inverted;
-
-			/* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
-			 * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
-			 * most significant bit (with weight 2**N) implicit.
-			 *
-			 * Special case for DIVISOR_LIMB == 100...000.
-			 */
-			if (!(divisor_limb << 1))
-				divisor_limb_inverted = ~(mpi_limb_t) 0;
-			else
-				udiv_qrnnd(divisor_limb_inverted, dummy,
-					   -divisor_limb, 0, divisor_limb);
-
-			i = dividend_size - 1;
-			r = dividend_ptr[i];
-
-			if (r >= divisor_limb)
-				r = 0;
-			else
-				i--;
-
-			for (; i >= 0; i--) {
-				n0 = dividend_ptr[i];
-				UDIV_QRNND_PREINV(dummy, r, r,
-						  n0, divisor_limb,
-						  divisor_limb_inverted);
-			}
-			return r;
-		}
-	} else {
-		if (UDIV_NEEDS_NORMALIZATION) {
-			int normalization_steps;
-
-			count_leading_zeros(normalization_steps, divisor_limb);
-			if (normalization_steps) {
-				divisor_limb <<= normalization_steps;
-
-				n1 = dividend_ptr[dividend_size - 1];
-				r = n1 >> (BITS_PER_MPI_LIMB -
-					   normalization_steps);
-
-				/* Possible optimization:
-				 * if (r == 0
-				 * && divisor_limb > ((n1 << normalization_steps)
-				 *                 | (dividend_ptr[dividend_size - 2] >> ...)))
-				 * ...one division less...
-				 */
-				for (i = dividend_size - 2; i >= 0; i--) {
-					n0 = dividend_ptr[i];
-					udiv_qrnnd(dummy, r, r,
-						   ((n1 << normalization_steps)
-						    | (n0 >>
-						       (BITS_PER_MPI_LIMB -
-							normalization_steps))),
-						   divisor_limb);
-					n1 = n0;
-				}
-				udiv_qrnnd(dummy, r, r,
-					   n1 << normalization_steps,
-					   divisor_limb);
-				return r >> normalization_steps;
-			}
-		}
-		/* No normalization needed, either because udiv_qrnnd doesn't require
-		 * it, or because DIVISOR_LIMB is already normalized.  */
-		i = dividend_size - 1;
-		r = dividend_ptr[i];
-
-		if (r >= divisor_limb)
-			r = 0;
-		else
-			i--;
-
-		for (; i >= 0; i--) {
-			n0 = dividend_ptr[i];
-			udiv_qrnnd(dummy, r, r, n0, divisor_limb);
-		}
-		return r;
-	}
-}
-
 /* Divide num (NP/NSIZE) by den (DP/DSIZE) and write
  * the NSIZE-DSIZE least significant quotient limbs at QP
  * and the DSIZE long remainder at NP.	If QEXTRA_LIMBS is
@@ -387,159 +234,3 @@ q_test:
 
 	return most_significant_q_limb;
 }
-
-/****************
- * Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB.
- * Write DIVIDEND_SIZE limbs of quotient at QUOT_PTR.
- * Return the single-limb remainder.
- * There are no constraints on the value of the divisor.
- *
- * QUOT_PTR and DIVIDEND_PTR might point to the same limb.
- */
-
-mpi_limb_t
-mpihelp_divmod_1(mpi_ptr_t quot_ptr,
-		 mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
-		 mpi_limb_t divisor_limb)
-{
-	mpi_size_t i;
-	mpi_limb_t n1, n0, r;
-	int dummy;
-
-	if (!dividend_size)
-		return 0;
-
-	/* If multiplication is much faster than division, and the
-	 * dividend is large, pre-invert the divisor, and use
-	 * only multiplications in the inner loop.
-	 *
-	 * This test should be read:
-	 * Does it ever help to use udiv_qrnnd_preinv?
-	 * && Does what we save compensate for the inversion overhead?
-	 */
-	if (UDIV_TIME > (2 * UMUL_TIME + 6)
-	    && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) {
-		int normalization_steps;
-
-		count_leading_zeros(normalization_steps, divisor_limb);
-		if (normalization_steps) {
-			mpi_limb_t divisor_limb_inverted;
-
-			divisor_limb <<= normalization_steps;
-
-			/* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
-			 * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
-			 * most significant bit (with weight 2**N) implicit.
-			 */
-			/* Special case for DIVISOR_LIMB == 100...000.  */
-			if (!(divisor_limb << 1))
-				divisor_limb_inverted = ~(mpi_limb_t) 0;
-			else
-				udiv_qrnnd(divisor_limb_inverted, dummy,
-					   -divisor_limb, 0, divisor_limb);
-
-			n1 = dividend_ptr[dividend_size - 1];
-			r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
-
-			/* Possible optimization:
-			 * if (r == 0
-			 * && divisor_limb > ((n1 << normalization_steps)
-			 *                 | (dividend_ptr[dividend_size - 2] >> ...)))
-			 * ...one division less...
-			 */
-			for (i = dividend_size - 2; i >= 0; i--) {
-				n0 = dividend_ptr[i];
-				UDIV_QRNND_PREINV(quot_ptr[i + 1], r, r,
-						  ((n1 << normalization_steps)
-						   | (n0 >>
-						      (BITS_PER_MPI_LIMB -
-						       normalization_steps))),
-						  divisor_limb,
-						  divisor_limb_inverted);
-				n1 = n0;
-			}
-			UDIV_QRNND_PREINV(quot_ptr[0], r, r,
-					  n1 << normalization_steps,
-					  divisor_limb, divisor_limb_inverted);
-			return r >> normalization_steps;
-		} else {
-			mpi_limb_t divisor_limb_inverted;
-
-			/* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
-			 * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
-			 * most significant bit (with weight 2**N) implicit.
-			 */
-			/* Special case for DIVISOR_LIMB == 100...000.  */
-			if (!(divisor_limb << 1))
-				divisor_limb_inverted = ~(mpi_limb_t) 0;
-			else
-				udiv_qrnnd(divisor_limb_inverted, dummy,
-					   -divisor_limb, 0, divisor_limb);
-
-			i = dividend_size - 1;
-			r = dividend_ptr[i];
-
-			if (r >= divisor_limb)
-				r = 0;
-			else
-				quot_ptr[i--] = 0;
-
-			for (; i >= 0; i--) {
-				n0 = dividend_ptr[i];
-				UDIV_QRNND_PREINV(quot_ptr[i], r, r,
-						  n0, divisor_limb,
-						  divisor_limb_inverted);
-			}
-			return r;
-		}
-	} else {
-		if (UDIV_NEEDS_NORMALIZATION) {
-			int normalization_steps;
-
-			count_leading_zeros(normalization_steps, divisor_limb);
-			if (normalization_steps) {
-				divisor_limb <<= normalization_steps;
-
-				n1 = dividend_ptr[dividend_size - 1];
-				r = n1 >> (BITS_PER_MPI_LIMB -
-					   normalization_steps);
-
-				/* Possible optimization:
-				 * if (r == 0
-				 * && divisor_limb > ((n1 << normalization_steps)
-				 *                 | (dividend_ptr[dividend_size - 2] >> ...)))
-				 * ...one division less...
-				 */
-				for (i = dividend_size - 2; i >= 0; i--) {
-					n0 = dividend_ptr[i];
-					udiv_qrnnd(quot_ptr[i + 1], r, r,
-						   ((n1 << normalization_steps)
-						    | (n0 >>
-						       (BITS_PER_MPI_LIMB -
-							normalization_steps))),
-						   divisor_limb);
-					n1 = n0;
-				}
-				udiv_qrnnd(quot_ptr[0], r, r,
-					   n1 << normalization_steps,
-					   divisor_limb);
-				return r >> normalization_steps;
-			}
-		}
-		/* No normalization needed, either because udiv_qrnnd doesn't require
-		 * it, or because DIVISOR_LIMB is already normalized.  */
-		i = dividend_size - 1;
-		r = dividend_ptr[i];
-
-		if (r >= divisor_limb)
-			r = 0;
-		else
-			quot_ptr[i--] = 0;
-
-		for (; i >= 0; i--) {
-			n0 = dividend_ptr[i];
-			udiv_qrnnd(quot_ptr[i], r, r, n0, divisor_limb);
-		}
-		return r;
-	}
-}
diff --git a/lib/mpi/mpih-mul.c b/lib/mpi/mpih-mul.c
index c69c5ee..7c84171 100644
--- a/lib/mpi/mpih-mul.c
+++ b/lib/mpi/mpih-mul.c
@@ -330,36 +330,6 @@ mpih_sqr_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace)
 	}
 }
 
-/* This should be made into an inline function in gmp.h.  */
-int mpihelp_mul_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size)
-{
-	if (up == vp) {
-		if (size < KARATSUBA_THRESHOLD)
-			mpih_sqr_n_basecase(prodp, up, size);
-		else {
-			mpi_ptr_t tspace;
-			tspace = mpi_alloc_limb_space(2 * size);
-			if (!tspace)
-				return -ENOMEM;
-			mpih_sqr_n(prodp, up, size, tspace);
-			mpi_free_limb_space(tspace);
-		}
-	} else {
-		if (size < KARATSUBA_THRESHOLD)
-			mul_n_basecase(prodp, up, vp, size);
-		else {
-			mpi_ptr_t tspace;
-			tspace = mpi_alloc_limb_space(2 * size);
-			if (!tspace)
-				return -ENOMEM;
-			mul_n(prodp, up, vp, size, tspace);
-			mpi_free_limb_space(tspace);
-		}
-	}
-
-	return 0;
-}
-
 int
 mpihelp_mul_karatsuba_case(mpi_ptr_t prodp,
 			   mpi_ptr_t up, mpi_size_t usize,
diff --git a/lib/mpi/mpiutil.c b/lib/mpi/mpiutil.c
index 26e4ed3..657979f 100644
--- a/lib/mpi/mpiutil.c
+++ b/lib/mpi/mpiutil.c
@@ -106,13 +106,6 @@ int mpi_resize(MPI a, unsigned nlimbs)
 	return 0;
 }
 
-void mpi_clear(MPI a)
-{
-	a->nlimbs = 0;
-	a->nbits = 0;
-	a->flags = 0;
-}
-
 void mpi_free(MPI a)
 {
 	if (!a)
@@ -128,84 +121,3 @@ void mpi_free(MPI a)
 	kfree(a);
 }
 EXPORT_SYMBOL_GPL(mpi_free);
-
-/****************
- * Note: This copy function should not interpret the MPI
- *	 but copy it transparently.
- */
-int mpi_copy(MPI *copied, const MPI a)
-{
-	size_t i;
-	MPI b;
-
-	*copied = NULL;
-
-	if (a) {
-		b = mpi_alloc(a->nlimbs);
-		if (!b)
-			return -ENOMEM;
-
-		b->nlimbs = a->nlimbs;
-		b->sign = a->sign;
-		b->flags = a->flags;
-		b->nbits = a->nbits;
-
-		for (i = 0; i < b->nlimbs; i++)
-			b->d[i] = a->d[i];
-
-		*copied = b;
-	}
-
-	return 0;
-}
-
-int mpi_set(MPI w, const MPI u)
-{
-	mpi_ptr_t wp, up;
-	mpi_size_t usize = u->nlimbs;
-	int usign = u->sign;
-
-	if (RESIZE_IF_NEEDED(w, (size_t) usize) < 0)
-		return -ENOMEM;
-
-	wp = w->d;
-	up = u->d;
-	MPN_COPY(wp, up, usize);
-	w->nlimbs = usize;
-	w->nbits = u->nbits;
-	w->flags = u->flags;
-	w->sign = usign;
-	return 0;
-}
-
-int mpi_set_ui(MPI w, unsigned long u)
-{
-	if (RESIZE_IF_NEEDED(w, 1) < 0)
-		return -ENOMEM;
-	w->d[0] = u;
-	w->nlimbs = u ? 1 : 0;
-	w->sign = 0;
-	w->nbits = 0;
-	w->flags = 0;
-	return 0;
-}
-
-MPI mpi_alloc_set_ui(unsigned long u)
-{
-	MPI w = mpi_alloc(1);
-	if (!w)
-		return w;
-	w->d[0] = u;
-	w->nlimbs = u ? 1 : 0;
-	w->sign = 0;
-	return w;
-}
-
-void mpi_swap(MPI a, MPI b)
-{
-	struct gcry_mpi tmp;
-
-	tmp = *a;
-	*a = *b;
-	*b = tmp;
-}
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 6096e89..e719adf 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -319,6 +319,70 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
 EXPORT_SYMBOL(sg_alloc_table);
 
 /**
+ * sg_alloc_table_from_pages - Allocate and initialize an sg table from
+ *			       an array of pages
+ * @sgt:	The sg table header to use
+ * @pages:	Pointer to an array of page pointers
+ * @n_pages:	Number of pages in the pages array
+ * @offset:     Offset from start of the first page to the start of a buffer
+ * @size:       Number of valid bytes in the buffer (after offset)
+ * @gfp_mask:	GFP allocation mask
+ *
+ *  Description:
+ *    Allocate and initialize an sg table from a list of pages. Contiguous
+ *    ranges of the pages are squashed into a single scatterlist node. A user
+ *    may provide an offset at a start and a size of valid data in a buffer
+ *    specified by the page array. The returned sg table is released by
+ *    sg_free_table.
+ *
+ * Returns:
+ *   0 on success, negative error on failure
+ */
+int sg_alloc_table_from_pages(struct sg_table *sgt,
+	struct page **pages, unsigned int n_pages,
+	unsigned long offset, unsigned long size,
+	gfp_t gfp_mask)
+{
+	unsigned int chunks;
+	unsigned int i;
+	unsigned int cur_page;
+	int ret;
+	struct scatterlist *s;
+
+	/* compute number of contiguous chunks */
+	chunks = 1;
+	for (i = 1; i < n_pages; ++i)
+		if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)
+			++chunks;
+
+	ret = sg_alloc_table(sgt, chunks, gfp_mask);
+	if (unlikely(ret))
+		return ret;
+
+	/* merging chunks and putting them into the scatterlist */
+	cur_page = 0;
+	for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
+		unsigned long chunk_size;
+		unsigned int j;
+
+		/* look for the end of the current chunk */
+		for (j = cur_page + 1; j < n_pages; ++j)
+			if (page_to_pfn(pages[j]) !=
+			    page_to_pfn(pages[j - 1]) + 1)
+				break;
+
+		chunk_size = ((j - cur_page) << PAGE_SHIFT) - offset;
+		sg_set_page(s, pages[cur_page], min(size, chunk_size), offset);
+		size -= chunk_size;
+		offset = 0;
+		cur_page = j;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(sg_alloc_table_from_pages);
+
+/**
  * sg_miter_start - start mapping iteration over a sg list
  * @miter: sg mapping iter to be started
  * @sgl: sg list to iterate over
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index c3f36d41..a0b5f15 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -662,15 +662,28 @@ char *mac_address_string(char *buf, char *end, u8 *addr,
 	char *p = mac_addr;
 	int i;
 	char separator;
+	bool reversed = false;
 
-	if (fmt[1] == 'F') {		/* FDDI canonical format */
+	switch (fmt[1]) {
+	case 'F':
 		separator = '-';
-	} else {
+		break;
+
+	case 'R':
+		reversed = true;
+		/* fall through */
+
+	default:
 		separator = ':';
+		break;
 	}
 
 	for (i = 0; i < 6; i++) {
-		p = hex_byte_pack(p, addr[i]);
+		if (reversed)
+			p = hex_byte_pack(p, addr[5 - i]);
+		else
+			p = hex_byte_pack(p, addr[i]);
+
 		if (fmt[0] == 'M' && i != 5)
 			*p++ = separator;
 	}
@@ -933,6 +946,7 @@ int kptr_restrict __read_mostly;
  * - 'm' For a 6-byte MAC address, it prints the hex address without colons
  * - 'MF' For a 6-byte MAC FDDI address, it prints the address
  *       with a dash-separated hex notation
+ * - '[mM]R For a 6-byte MAC address, Reverse order (Bluetooth)
  * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
  *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
  *       IPv6 uses colon separated network-order 16 bit hex with leading 0's
@@ -995,7 +1009,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
 		return resource_string(buf, end, ptr, spec, fmt);
 	case 'M':			/* Colon separated: 00:01:02:03:04:05 */
 	case 'm':			/* Contiguous: 000102030405 */
-					/* [mM]F (FDDI, bit reversed) */
+					/* [mM]F (FDDI) */
+					/* [mM]R (Reverse order; Bluetooth) */
 		return mac_address_string(buf, end, ptr, spec, fmt);
 	case 'I':			/* Formatted IP supported
 					 * 4:	1.2.3.4
@@ -1282,6 +1297,8 @@ qualifier:
  *   case.
  * %n is ignored
  *
+ * ** Please update Documentation/printk-formats.txt when making changes **
+ *
  * The return value is the number of characters which would
  * be generated for the given input, excluding the trailing
  * '\0', as per ISO C99. If you want to have the exact
diff --git a/localversion-next b/localversion-next
new file mode 100644
index 0000000..94ab5ce
--- /dev/null
+++ b/localversion-next
@@ -0,0 +1 @@
+-next-20120627
diff --git a/mm/Makefile b/mm/Makefile
index 2e2fbbe..25e8002 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_MIGRATION) += migrate.o
 obj-$(CONFIG_QUICKLIST) += quicklist.o
 obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o
 obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o page_cgroup.o
+obj-$(CONFIG_CGROUP_HUGETLB_RES_CTLR) += hugetlb_cgroup.o
 obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o
 obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o
 obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index dd8e2aa..6b4718e 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -677,7 +677,7 @@ int bdi_init(struct backing_dev_info *bdi)
 
 	bdi->min_ratio = 0;
 	bdi->max_ratio = 100;
-	bdi->max_prop_frac = PROP_FRAC_BASE;
+	bdi->max_prop_frac = FPROP_FRAC_BASE;
 	spin_lock_init(&bdi->wb_lock);
 	INIT_LIST_HEAD(&bdi->bdi_list);
 	INIT_LIST_HEAD(&bdi->work_list);
@@ -700,7 +700,7 @@ int bdi_init(struct backing_dev_info *bdi)
 	bdi->write_bandwidth = INIT_BW;
 	bdi->avg_write_bandwidth = INIT_BW;
 
-	err = prop_local_init_percpu(&bdi->completions);
+	err = fprop_local_init_percpu(&bdi->completions);
 
 	if (err) {
 err:
@@ -744,7 +744,7 @@ void bdi_destroy(struct backing_dev_info *bdi)
 	for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
 		percpu_counter_destroy(&bdi->bdi_stat[i]);
 
-	prop_local_destroy_percpu(&bdi->completions);
+	fprop_local_destroy_percpu(&bdi->completions);
 }
 EXPORT_SYMBOL(bdi_destroy);
 
@@ -886,3 +886,23 @@ out:
 	return ret;
 }
 EXPORT_SYMBOL(wait_iff_congested);
+
+int pdflush_proc_obsolete(struct ctl_table *table, int write,
+			void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	char kbuf[] = "0\n";
+
+	if (*ppos) {
+		*lenp = 0;
+		return 0;
+	}
+
+	if (copy_to_user(buffer, kbuf, sizeof(kbuf)))
+		return -EFAULT;
+	printk_once(KERN_WARNING "%s exported in /proc is scheduled for removal\n",
+			table->procname);
+
+	*lenp = 2;
+	*ppos += *lenp;
+	return 2;
+}
diff --git a/mm/bounce.c b/mm/bounce.c
index d1be02c..0420867 100644
--- a/mm/bounce.c
+++ b/mm/bounce.c
@@ -24,23 +24,25 @@
 
 static mempool_t *page_pool, *isa_page_pool;
 
-#ifdef CONFIG_HIGHMEM
+#if defined(CONFIG_HIGHMEM) || defined(CONFIG_NEED_BOUNCE_POOL)
 static __init int init_emergency_pool(void)
 {
-#ifndef CONFIG_MEMORY_HOTPLUG
+#if defined(CONFIG_HIGHMEM) && !defined(CONFIG_MEMORY_HOTPLUG)
 	if (max_pfn <= max_low_pfn)
 		return 0;
 #endif
 
 	page_pool = mempool_create_page_pool(POOL_SIZE, 0);
 	BUG_ON(!page_pool);
-	printk("highmem bounce pool size: %d pages\n", POOL_SIZE);
+	printk("bounce pool size: %d pages\n", POOL_SIZE);
 
 	return 0;
 }
 
 __initcall(init_emergency_pool);
+#endif
 
+#ifdef CONFIG_HIGHMEM
 /*
  * highmem version, map in to vec
  */
diff --git a/mm/compaction.c b/mm/compaction.c
index 7ea259d..b14cc21 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -236,7 +236,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
 	 */
 	while (unlikely(too_many_isolated(zone))) {
 		/* async migration should just abort */
-		if (!cc->sync)
+		if (cc->mode != COMPACT_SYNC)
 			return 0;
 
 		congestion_wait(BLK_RW_ASYNC, HZ/10);
@@ -304,7 +304,8 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
 		 * satisfies the allocation
 		 */
 		pageblock_nr = low_pfn >> pageblock_order;
-		if (!cc->sync && last_pageblock_nr != pageblock_nr &&
+		if (cc->mode != COMPACT_SYNC &&
+		    last_pageblock_nr != pageblock_nr &&
 		    !migrate_async_suitable(get_pageblock_migratetype(page))) {
 			low_pfn += pageblock_nr_pages;
 			low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1;
@@ -325,7 +326,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
 			continue;
 		}
 
-		if (!cc->sync)
+		if (cc->mode != COMPACT_SYNC)
 			mode |= ISOLATE_ASYNC_MIGRATE;
 
 		lruvec = mem_cgroup_page_lruvec(page, zone);
@@ -360,27 +361,87 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
 
 #endif /* CONFIG_COMPACTION || CONFIG_CMA */
 #ifdef CONFIG_COMPACTION
+/*
+ * Returns true if MIGRATE_UNMOVABLE pageblock can be successfully
+ * converted to MIGRATE_MOVABLE type, false otherwise.
+ */
+static bool can_rescue_unmovable_pageblock(struct page *page)
+{
+	struct zone *zone;
+	unsigned long pfn, start_pfn;
+	struct page *start_page;
+
+	zone = page_zone(page);
+	pfn = page_to_pfn(page);
+	start_pfn = pfn & ~(pageblock_nr_pages - 1);
+	start_page = pfn_to_page(start_pfn);
+
+	/*
+	 * Race with page allocator/reclaimer can happen so it is possible
+	 * that MIGRATE_UNMOVABLE type page will end up in MIGRATE_MOVABLE
+	 * type pageblock.  However such situation is rare and not critical
+	 * (because page allocator fallback mechanism can also allocate
+	 * MIGRATE_UNMOVABLE type pages in MIGRATE_MOVABLE type pageblock).
+	 */
+	return __count_immobile_pages(zone, start_page, 0);
+}
 
-/* Returns true if the page is within a block suitable for migration to */
-static bool suitable_migration_target(struct page *page)
+static void rescue_unmovable_pageblock(struct page *page)
+{
+	set_pageblock_migratetype(page, MIGRATE_MOVABLE);
+	move_freepages_block(page_zone(page), page, MIGRATE_MOVABLE);
+
+	count_vm_event(COMPACT_RESCUED_UNMOVABLE_BLOCKS);
+}
+
+/*
+ * MIGRATE_TARGET: good for migration target
+ * RESCUE_UNMOVABLE_TARGET: good only if we can rescue the unmovable pageblock.
+ * UNMOVABLE_TARGET: can't migrate because it's a page in unmovable pageblock.
+ * SKIP_TARGET: can't migrate by another reasons.
+ */
+enum smt_result {
+	MIGRATE_TARGET,
+	RESCUE_UNMOVABLE_TARGET,
+	UNMOVABLE_TARGET,
+	SKIP_TARGET,
+};
+
+/*
+ * Returns MIGRATE_TARGET if the page is within a block suitable for migration
+ * to, UNMOVABLE_TARGET if the page is within a MIGRATE_UNMOVABLE block,
+ * SKIP_TARGET otherwise.
+ */
+static enum smt_result suitable_migration_target(struct page *page,
+			      struct compact_control *cc)
 {
 
 	int migratetype = get_pageblock_migratetype(page);
 
 	/* Don't interfere with memory hot-remove or the min_free_kbytes blocks */
 	if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE)
-		return false;
+		return SKIP_TARGET;
 
 	/* If the page is a large free page, then allow migration */
 	if (PageBuddy(page) && page_order(page) >= pageblock_order)
-		return true;
+		return MIGRATE_TARGET;
 
 	/* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */
-	if (migrate_async_suitable(migratetype))
-		return true;
+	if (cc->mode != COMPACT_ASYNC_UNMOVABLE &&
+	    migrate_async_suitable(migratetype))
+		return MIGRATE_TARGET;
+
+	if (cc->mode == COMPACT_ASYNC_MOVABLE &&
+	    migratetype == MIGRATE_UNMOVABLE)
+		return UNMOVABLE_TARGET;
+
+	if (cc->mode != COMPACT_ASYNC_MOVABLE &&
+	    migratetype == MIGRATE_UNMOVABLE &&
+	    can_rescue_unmovable_pageblock(page))
+		return RESCUE_UNMOVABLE_TARGET;
 
 	/* Otherwise skip the block */
-	return false;
+	return SKIP_TARGET;
 }
 
 /*
@@ -414,6 +475,13 @@ static void isolate_freepages(struct zone *zone,
 	zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages;
 
 	/*
+	 * isolate_freepages() may be called more than once during
+	 * compact_zone_order() run and we want only the most recent
+	 * count.
+	 */
+	cc->nr_unmovable_pageblock = 0;
+
+	/*
 	 * Isolate free pages until enough are available to migrate the
 	 * pages on cc->migratepages. We stop searching if the migrate
 	 * and free page scanners meet or enough free pages are isolated.
@@ -421,6 +489,7 @@ static void isolate_freepages(struct zone *zone,
 	for (; pfn > low_pfn && cc->nr_migratepages > nr_freepages;
 					pfn -= pageblock_nr_pages) {
 		unsigned long isolated;
+		enum smt_result ret;
 
 		if (!pfn_valid(pfn))
 			continue;
@@ -437,9 +506,12 @@ static void isolate_freepages(struct zone *zone,
 			continue;
 
 		/* Check the block is suitable for migration */
-		if (!suitable_migration_target(page))
+		ret = suitable_migration_target(page, cc);
+		if (ret != MIGRATE_TARGET && ret != RESCUE_UNMOVABLE_TARGET) {
+			if (ret == UNMOVABLE_TARGET)
+				cc->nr_unmovable_pageblock++;
 			continue;
-
+		}
 		/*
 		 * Found a block suitable for isolating free pages from. Now
 		 * we disabled interrupts, double check things are ok and
@@ -448,12 +520,16 @@ static void isolate_freepages(struct zone *zone,
 		 */
 		isolated = 0;
 		spin_lock_irqsave(&zone->lock, flags);
-		if (suitable_migration_target(page)) {
+		ret = suitable_migration_target(page, cc);
+		if (ret == MIGRATE_TARGET || ret == RESCUE_UNMOVABLE_TARGET) {
+			if (ret == RESCUE_UNMOVABLE_TARGET)
+				rescue_unmovable_pageblock(page);
 			end_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn);
 			isolated = isolate_freepages_block(pfn, end_pfn,
 							   freelist, false);
 			nr_freepages += isolated;
-		}
+		} else if (ret == UNMOVABLE_TARGET)
+			cc->nr_unmovable_pageblock++;
 		spin_unlock_irqrestore(&zone->lock, flags);
 
 		/*
@@ -685,8 +761,9 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
 
 		nr_migrate = cc->nr_migratepages;
 		err = migrate_pages(&cc->migratepages, compaction_alloc,
-				(unsigned long)cc, false,
-				cc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC);
+			(unsigned long)&cc->freepages, false,
+			(cc->mode == COMPACT_SYNC) ? MIGRATE_SYNC_LIGHT
+						      : MIGRATE_ASYNC);
 		update_nr_listpages(cc);
 		nr_remaining = cc->nr_migratepages;
 
@@ -701,8 +778,11 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
 		if (err) {
 			putback_lru_pages(&cc->migratepages);
 			cc->nr_migratepages = 0;
+			if (err == -ENOMEM) {
+				ret = COMPACT_PARTIAL;
+				goto out;
+			}
 		}
-
 	}
 
 out:
@@ -715,7 +795,8 @@ out:
 
 static unsigned long compact_zone_order(struct zone *zone,
 				 int order, gfp_t gfp_mask,
-				 bool sync)
+				 enum compact_mode mode,
+				 unsigned long *nr_pageblocks_skipped)
 {
 	struct compact_control cc = {
 		.nr_freepages = 0,
@@ -723,12 +804,17 @@ static unsigned long compact_zone_order(struct zone *zone,
 		.order = order,
 		.migratetype = allocflags_to_migratetype(gfp_mask),
 		.zone = zone,
-		.sync = sync,
+		.mode = mode,
 	};
+	unsigned long rc;
+
 	INIT_LIST_HEAD(&cc.freepages);
 	INIT_LIST_HEAD(&cc.migratepages);
 
-	return compact_zone(zone, &cc);
+	rc = compact_zone(zone, &cc);
+	*nr_pageblocks_skipped = cc.nr_unmovable_pageblock;
+
+	return rc;
 }
 
 int sysctl_extfrag_threshold = 500;
@@ -753,6 +839,8 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
 	struct zoneref *z;
 	struct zone *zone;
 	int rc = COMPACT_SKIPPED;
+	unsigned long nr_pageblocks_skipped;
+	enum compact_mode mode;
 
 	/*
 	 * Check whether it is worth even starting compaction. The order check is
@@ -769,12 +857,22 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
 								nodemask) {
 		int status;
 
-		status = compact_zone_order(zone, order, gfp_mask, sync);
+		mode = sync ? COMPACT_SYNC : COMPACT_ASYNC_MOVABLE;
+retry:
+		status = compact_zone_order(zone, order, gfp_mask, mode,
+						&nr_pageblocks_skipped);
 		rc = max(status, rc);
 
 		/* If a normal allocation would succeed, stop compacting */
 		if (zone_watermark_ok(zone, order, low_wmark_pages(zone), 0, 0))
 			break;
+
+		if (rc == COMPACT_COMPLETE && mode == COMPACT_ASYNC_MOVABLE) {
+			if (nr_pageblocks_skipped) {
+				mode = COMPACT_ASYNC_UNMOVABLE;
+				goto retry;
+			}
+		}
 	}
 
 	return rc;
@@ -808,7 +906,7 @@ static int __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)
 			if (ok && cc->order > zone->compact_order_failed)
 				zone->compact_order_failed = cc->order + 1;
 			/* Currently async compaction is never deferred. */
-			else if (!ok && cc->sync)
+			else if (!ok && cc->mode == COMPACT_SYNC)
 				defer_compaction(zone, cc->order);
 		}
 
@@ -823,7 +921,7 @@ int compact_pgdat(pg_data_t *pgdat, int order)
 {
 	struct compact_control cc = {
 		.order = order,
-		.sync = false,
+		.mode = COMPACT_ASYNC_MOVABLE,
 	};
 
 	return __compact_pgdat(pgdat, &cc);
@@ -833,7 +931,7 @@ static int compact_node(int nid)
 {
 	struct compact_control cc = {
 		.order = -1,
-		.sync = true,
+		.mode = COMPACT_SYNC,
 	};
 
 	return __compact_pgdat(NODE_DATA(nid), &cc);
diff --git a/mm/filemap.c b/mm/filemap.c
index a4a5260..1f19ec3 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -500,10 +500,10 @@ struct page *__page_cache_alloc(gfp_t gfp)
 	if (cpuset_do_page_mem_spread()) {
 		unsigned int cpuset_mems_cookie;
 		do {
-			cpuset_mems_cookie = get_mems_allowed();
+			cpuset_mems_cookie = read_mems_allowed_begin();
 			n = cpuset_mem_spread_node();
 			page = alloc_pages_exact_node(n, gfp, 0);
-		} while (!put_mems_allowed(cpuset_mems_cookie) && !page);
+		} while (!page && read_mems_allowed_retry(cpuset_mems_cookie));
 
 		return page;
 	}
diff --git a/mm/frontswap.c b/mm/frontswap.c
index e250255..491bcd3 100644
--- a/mm/frontswap.c
+++ b/mm/frontswap.c
@@ -11,18 +11,16 @@
  * This work is licensed under the terms of the GNU GPL, version 2.
  */
 
-#include <linux/mm.h>
+#define CREATE_TRACE_POINTS
 #include <linux/mman.h>
 #include <linux/swap.h>
 #include <linux/swapops.h>
-#include <linux/proc_fs.h>
 #include <linux/security.h>
-#include <linux/capability.h>
 #include <linux/module.h>
-#include <linux/uaccess.h>
 #include <linux/debugfs.h>
 #include <linux/frontswap.h>
 #include <linux/swapfile.h>
+#include <trace/events/frontswap.h>
 
 /*
  * frontswap_ops is set by frontswap_register_ops to contain the pointers
@@ -85,6 +83,7 @@ struct frontswap_ops frontswap_register_ops(struct frontswap_ops *ops)
 {
 	struct frontswap_ops old = frontswap_ops;
 
+	trace_frontswap_register_ops(&old, ops);
 	frontswap_ops = *ops;
 	frontswap_enabled = true;
 	return old;
@@ -108,18 +107,26 @@ void __frontswap_init(unsigned type)
 	struct swap_info_struct *sis = swap_info[type];
 
 	BUG_ON(sis == NULL);
+
+	trace_frontswap_init(type, sis, sis->frontswap_map);
+
 	if (sis->frontswap_map == NULL)
 		return;
-	if (frontswap_enabled)
-		(*frontswap_ops.init)(type);
+	frontswap_ops.init(type);
 }
 EXPORT_SYMBOL(__frontswap_init);
 
+static inline void __frontswap_clear(struct swap_info_struct *sis, pgoff_t offset)
+{
+	frontswap_clear(sis, offset);
+	atomic_dec(&sis->frontswap_pages);
+}
+
 /*
  * "Store" data from a page to frontswap and associate it with the page's
  * swaptype and offset.  Page must be locked and in the swap cache.
  * If frontswap already contains a page with matching swaptype and
- * offset, the frontswap implmentation may either overwrite the data and
+ * offset, the frontswap implementation may either overwrite the data and
  * return success or invalidate the page from frontswap and return failure.
  */
 int __frontswap_store(struct page *page)
@@ -134,22 +141,22 @@ int __frontswap_store(struct page *page)
 	BUG_ON(sis == NULL);
 	if (frontswap_test(sis, offset))
 		dup = 1;
-	ret = (*frontswap_ops.store)(type, offset, page);
+	ret = frontswap_ops.store(type, offset, page);
+	trace_frontswap_store(page, dup, ret);
 	if (ret == 0) {
 		frontswap_set(sis, offset);
 		inc_frontswap_succ_stores();
 		if (!dup)
 			atomic_inc(&sis->frontswap_pages);
-	} else if (dup) {
+	} else {
 		/*
 		  failed dup always results in automatic invalidate of
 		  the (older) page from frontswap
 		 */
-		frontswap_clear(sis, offset);
-		atomic_dec(&sis->frontswap_pages);
-		inc_frontswap_failed_stores();
-	} else
 		inc_frontswap_failed_stores();
+		if (dup)
+			__frontswap_clear(sis, offset);
+	}
 	if (frontswap_writethrough_enabled)
 		/* report failure so swap also writes to swap device */
 		ret = -1;
@@ -173,7 +180,8 @@ int __frontswap_load(struct page *page)
 	BUG_ON(!PageLocked(page));
 	BUG_ON(sis == NULL);
 	if (frontswap_test(sis, offset))
-		ret = (*frontswap_ops.load)(type, offset, page);
+		ret = frontswap_ops.load(type, offset, page);
+	trace_frontswap_load(page, ret);
 	if (ret == 0)
 		inc_frontswap_loads();
 	return ret;
@@ -189,10 +197,10 @@ void __frontswap_invalidate_page(unsigned type, pgoff_t offset)
 	struct swap_info_struct *sis = swap_info[type];
 
 	BUG_ON(sis == NULL);
+	trace_frontswap_invalidate_page(type, offset, sis, frontswap_test(sis, offset));
 	if (frontswap_test(sis, offset)) {
-		(*frontswap_ops.invalidate_page)(type, offset);
-		atomic_dec(&sis->frontswap_pages);
-		frontswap_clear(sis, offset);
+		frontswap_ops.invalidate_page(type, offset);
+		__frontswap_clear(sis, offset);
 		inc_frontswap_invalidates();
 	}
 }
@@ -207,69 +215,107 @@ void __frontswap_invalidate_area(unsigned type)
 	struct swap_info_struct *sis = swap_info[type];
 
 	BUG_ON(sis == NULL);
+	trace_frontswap_invalidate_area(type, sis, sis->frontswap_map);
 	if (sis->frontswap_map == NULL)
 		return;
-	(*frontswap_ops.invalidate_area)(type);
+	frontswap_ops.invalidate_area(type);
 	atomic_set(&sis->frontswap_pages, 0);
 	memset(sis->frontswap_map, 0, sis->max / sizeof(long));
 }
 EXPORT_SYMBOL(__frontswap_invalidate_area);
 
-/*
- * Frontswap, like a true swap device, may unnecessarily retain pages
- * under certain circumstances; "shrink" frontswap is essentially a
- * "partial swapoff" and works by calling try_to_unuse to attempt to
- * unuse enough frontswap pages to attempt to -- subject to memory
- * constraints -- reduce the number of pages in frontswap to the
- * number given in the parameter target_pages.
- */
-void frontswap_shrink(unsigned long target_pages)
+static unsigned long __frontswap_curr_pages(void)
 {
-	struct swap_info_struct *si = NULL;
-	int si_frontswap_pages;
-	unsigned long total_pages = 0, total_pages_to_unuse;
-	unsigned long pages = 0, pages_to_unuse = 0;
 	int type;
-	bool locked = false;
+	unsigned long totalpages = 0;
+	struct swap_info_struct *si = NULL;
 
-	/*
-	 * we don't want to hold swap_lock while doing a very
-	 * lengthy try_to_unuse, but swap_list may change
-	 * so restart scan from swap_list.head each time
-	 */
-	spin_lock(&swap_lock);
-	locked = true;
-	total_pages = 0;
+	assert_spin_locked(&swap_lock);
 	for (type = swap_list.head; type >= 0; type = si->next) {
 		si = swap_info[type];
-		total_pages += atomic_read(&si->frontswap_pages);
+		totalpages += atomic_read(&si->frontswap_pages);
 	}
-	if (total_pages <= target_pages)
-		goto out;
-	total_pages_to_unuse = total_pages - target_pages;
+	return totalpages;
+}
+
+static int __frontswap_unuse_pages(unsigned long total, unsigned long *unused,
+					int *swapid)
+{
+	int ret = -EINVAL;
+	struct swap_info_struct *si = NULL;
+	int si_frontswap_pages;
+	unsigned long total_pages_to_unuse = total;
+	unsigned long pages = 0, pages_to_unuse = 0;
+	int type;
+
+	assert_spin_locked(&swap_lock);
 	for (type = swap_list.head; type >= 0; type = si->next) {
 		si = swap_info[type];
 		si_frontswap_pages = atomic_read(&si->frontswap_pages);
-		if (total_pages_to_unuse < si_frontswap_pages)
+		if (total_pages_to_unuse < si_frontswap_pages) {
 			pages = pages_to_unuse = total_pages_to_unuse;
-		else {
+		} else {
 			pages = si_frontswap_pages;
 			pages_to_unuse = 0; /* unuse all */
 		}
 		/* ensure there is enough RAM to fetch pages from frontswap */
-		if (security_vm_enough_memory_mm(current->mm, pages))
+		if (security_vm_enough_memory_mm(current->mm, pages)) {
+			ret = -ENOMEM;
 			continue;
+		}
 		vm_unacct_memory(pages);
+		*unused = pages_to_unuse;
+		*swapid = type;
+		ret = 0;
 		break;
 	}
-	if (type < 0)
-		goto out;
-	locked = false;
+
+	return ret;
+}
+
+static int __frontswap_shrink(unsigned long target_pages,
+				unsigned long *pages_to_unuse,
+				int *type)
+{
+	unsigned long total_pages = 0, total_pages_to_unuse;
+
+	assert_spin_locked(&swap_lock);
+
+	total_pages = __frontswap_curr_pages();
+	if (total_pages <= target_pages) {
+		/* Nothing to do */
+		*pages_to_unuse = 0;
+		return 0;
+	}
+	total_pages_to_unuse = total_pages - target_pages;
+	return __frontswap_unuse_pages(total_pages_to_unuse, pages_to_unuse, type);
+}
+
+/*
+ * Frontswap, like a true swap device, may unnecessarily retain pages
+ * under certain circumstances; "shrink" frontswap is essentially a
+ * "partial swapoff" and works by calling try_to_unuse to attempt to
+ * unuse enough frontswap pages to attempt to -- subject to memory
+ * constraints -- reduce the number of pages in frontswap to the
+ * number given in the parameter target_pages.
+ */
+void frontswap_shrink(unsigned long target_pages)
+{
+	unsigned long pages_to_unuse = 0;
+	int type, ret;
+
+	trace_frontswap_shrink(target_pages);
+
+	/*
+	 * we don't want to hold swap_lock while doing a very
+	 * lengthy try_to_unuse, but swap_list may change
+	 * so restart scan from swap_list.head each time
+	 */
+	spin_lock(&swap_lock);
+	ret = __frontswap_shrink(target_pages, &pages_to_unuse, &type);
 	spin_unlock(&swap_lock);
-	try_to_unuse(type, true, pages_to_unuse);
-out:
-	if (locked)
-		spin_unlock(&swap_lock);
+	if (ret == 0 && pages_to_unuse)
+		try_to_unuse(type, true, pages_to_unuse);
 	return;
 }
 EXPORT_SYMBOL(frontswap_shrink);
@@ -281,16 +327,14 @@ EXPORT_SYMBOL(frontswap_shrink);
  */
 unsigned long frontswap_curr_pages(void)
 {
-	int type;
 	unsigned long totalpages = 0;
-	struct swap_info_struct *si = NULL;
 
 	spin_lock(&swap_lock);
-	for (type = swap_list.head; type >= 0; type = si->next) {
-		si = swap_info[type];
-		totalpages += atomic_read(&si->frontswap_pages);
-	}
+	totalpages = __frontswap_curr_pages();
 	spin_unlock(&swap_lock);
+
+	trace_frontswap_curr_pages(totalpages);
+
 	return totalpages;
 }
 EXPORT_SYMBOL(frontswap_curr_pages);
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index e198831..fd1d530 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -24,17 +24,20 @@
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <linux/io.h>
+#include <asm/tlb.h>
 
+#include <linux/io.h>
 #include <linux/hugetlb.h>
+#include <linux/hugetlb_cgroup.h>
 #include <linux/node.h>
+#include <linux/hugetlb_cgroup.h>
 #include "internal.h"
 
 const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL;
 static gfp_t htlb_alloc_mask = GFP_HIGHUSER;
 unsigned long hugepages_treat_as_movable;
 
-static int max_hstate;
+int hugetlb_max_hstate __read_mostly;
 unsigned int default_hstate_idx;
 struct hstate hstates[HUGE_MAX_HSTATE];
 
@@ -45,13 +48,10 @@ static struct hstate * __initdata parsed_hstate;
 static unsigned long __initdata default_hstate_max_huge_pages;
 static unsigned long __initdata default_hstate_size;
 
-#define for_each_hstate(h) \
-	for ((h) = hstates; (h) < &hstates[max_hstate]; (h)++)
-
 /*
  * Protects updates to hugepage_freelists, nr_huge_pages, and free_huge_pages
  */
-static DEFINE_SPINLOCK(hugetlb_lock);
+DEFINE_SPINLOCK(hugetlb_lock);
 
 static inline void unlock_or_release_subpool(struct hugepage_subpool *spool)
 {
@@ -509,7 +509,7 @@ void copy_huge_page(struct page *dst, struct page *src)
 static void enqueue_huge_page(struct hstate *h, struct page *page)
 {
 	int nid = page_to_nid(page);
-	list_add(&page->lru, &h->hugepage_freelists[nid]);
+	list_move(&page->lru, &h->hugepage_freelists[nid]);
 	h->free_huge_pages++;
 	h->free_huge_pages_node[nid]++;
 }
@@ -521,7 +521,7 @@ static struct page *dequeue_huge_page_node(struct hstate *h, int nid)
 	if (list_empty(&h->hugepage_freelists[nid]))
 		return NULL;
 	page = list_entry(h->hugepage_freelists[nid].next, struct page, lru);
-	list_del(&page->lru);
+	list_move(&page->lru, &h->hugepage_activelist);
 	set_page_refcounted(page);
 	h->free_huge_pages--;
 	h->free_huge_pages_node[nid]--;
@@ -541,7 +541,7 @@ static struct page *dequeue_huge_page_vma(struct hstate *h,
 	unsigned int cpuset_mems_cookie;
 
 retry_cpuset:
-	cpuset_mems_cookie = get_mems_allowed();
+	cpuset_mems_cookie = read_mems_allowed_begin();
 	zonelist = huge_zonelist(vma, address,
 					htlb_alloc_mask, &mpol, &nodemask);
 	/*
@@ -570,7 +570,7 @@ retry_cpuset:
 	}
 
 	mpol_cond_put(mpol);
-	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+	if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
 		goto retry_cpuset;
 	return page;
 
@@ -593,6 +593,7 @@ static void update_and_free_page(struct hstate *h, struct page *page)
 				1 << PG_active | 1 << PG_reserved |
 				1 << PG_private | 1 << PG_writeback);
 	}
+	VM_BUG_ON(hugetlb_cgroup_from_page(page));
 	set_compound_page_dtor(page, NULL);
 	set_page_refcounted(page);
 	arch_release_hugepage(page);
@@ -625,10 +626,13 @@ static void free_huge_page(struct page *page)
 	page->mapping = NULL;
 	BUG_ON(page_count(page));
 	BUG_ON(page_mapcount(page));
-	INIT_LIST_HEAD(&page->lru);
 
 	spin_lock(&hugetlb_lock);
+	hugetlb_cgroup_uncharge_page(hstate_index(h),
+				     pages_per_huge_page(h), page);
 	if (h->surplus_huge_pages_node[nid] && huge_page_order(h) < MAX_ORDER) {
+		/* remove the page from active list */
+		list_del(&page->lru);
 		update_and_free_page(h, page);
 		h->surplus_huge_pages--;
 		h->surplus_huge_pages_node[nid]--;
@@ -641,8 +645,10 @@ static void free_huge_page(struct page *page)
 
 static void prep_new_huge_page(struct hstate *h, struct page *page, int nid)
 {
+	INIT_LIST_HEAD(&page->lru);
 	set_compound_page_dtor(page, free_huge_page);
 	spin_lock(&hugetlb_lock);
+	set_hugetlb_cgroup(page, NULL);
 	h->nr_huge_pages++;
 	h->nr_huge_pages_node[nid]++;
 	spin_unlock(&hugetlb_lock);
@@ -889,8 +895,10 @@ static struct page *alloc_buddy_huge_page(struct hstate *h, int nid)
 
 	spin_lock(&hugetlb_lock);
 	if (page) {
+		INIT_LIST_HEAD(&page->lru);
 		r_nid = page_to_nid(page);
 		set_compound_page_dtor(page, free_huge_page);
+		set_hugetlb_cgroup(page, NULL);
 		/*
 		 * We incremented the global counters already
 		 */
@@ -993,7 +1001,6 @@ retry:
 	list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
 		if ((--needed) < 0)
 			break;
-		list_del(&page->lru);
 		/*
 		 * This page is now managed by the hugetlb allocator and has
 		 * no users -- drop the buddy allocator's reference.
@@ -1008,7 +1015,6 @@ free:
 	/* Free unnecessary surplus pages to the buddy allocator */
 	if (!list_empty(&surplus_list)) {
 		list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
-			list_del(&page->lru);
 			put_page(page);
 		}
 	}
@@ -1112,7 +1118,10 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
 	struct hstate *h = hstate_vma(vma);
 	struct page *page;
 	long chg;
+	int ret, idx;
+	struct hugetlb_cgroup *h_cg;
 
+	idx = hstate_index(h);
 	/*
 	 * Processes that did not create the mapping will have no
 	 * reserves and will not have accounted against subpool
@@ -1123,27 +1132,43 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
 	 */
 	chg = vma_needs_reservation(h, vma, addr);
 	if (chg < 0)
-		return ERR_PTR(-VM_FAULT_OOM);
+		return ERR_PTR(-ENOMEM);
 	if (chg)
 		if (hugepage_subpool_get_pages(spool, chg))
-			return ERR_PTR(-VM_FAULT_SIGBUS);
+			return ERR_PTR(-ENOSPC);
 
+	ret = hugetlb_cgroup_charge_cgroup(idx, pages_per_huge_page(h), &h_cg);
+	if (ret) {
+		hugepage_subpool_put_pages(spool, chg);
+		return ERR_PTR(-ENOSPC);
+	}
 	spin_lock(&hugetlb_lock);
 	page = dequeue_huge_page_vma(h, vma, addr, avoid_reserve);
-	spin_unlock(&hugetlb_lock);
-
-	if (!page) {
+	if (page) {
+		/* update page cgroup details */
+		hugetlb_cgroup_commit_charge(idx, pages_per_huge_page(h),
+					     h_cg, page);
+		spin_unlock(&hugetlb_lock);
+	} else {
+		spin_unlock(&hugetlb_lock);
 		page = alloc_buddy_huge_page(h, NUMA_NO_NODE);
 		if (!page) {
+			hugetlb_cgroup_uncharge_cgroup(idx,
+						       pages_per_huge_page(h),
+						       h_cg);
 			hugepage_subpool_put_pages(spool, chg);
-			return ERR_PTR(-VM_FAULT_SIGBUS);
+			return ERR_PTR(-ENOSPC);
 		}
+		spin_lock(&hugetlb_lock);
+		hugetlb_cgroup_commit_charge(idx, pages_per_huge_page(h),
+					     h_cg, page);
+		list_move(&page->lru, &h->hugepage_activelist);
+		spin_unlock(&hugetlb_lock);
 	}
 
 	set_page_private(page, (unsigned long)spool);
 
 	vma_commit_reservation(h, vma, addr);
-
 	return page;
 }
 
@@ -1646,7 +1671,7 @@ static int hugetlb_sysfs_add_hstate(struct hstate *h, struct kobject *parent,
 				    struct attribute_group *hstate_attr_group)
 {
 	int retval;
-	int hi = h - hstates;
+	int hi = hstate_index(h);
 
 	hstate_kobjs[hi] = kobject_create_and_add(h->name, parent);
 	if (!hstate_kobjs[hi])
@@ -1741,11 +1766,13 @@ void hugetlb_unregister_node(struct node *node)
 	if (!nhs->hugepages_kobj)
 		return;		/* no hstate attributes */
 
-	for_each_hstate(h)
-		if (nhs->hstate_kobjs[h - hstates]) {
-			kobject_put(nhs->hstate_kobjs[h - hstates]);
-			nhs->hstate_kobjs[h - hstates] = NULL;
+	for_each_hstate(h) {
+		int idx = hstate_index(h);
+		if (nhs->hstate_kobjs[idx]) {
+			kobject_put(nhs->hstate_kobjs[idx]);
+			nhs->hstate_kobjs[idx] = NULL;
 		}
+	}
 
 	kobject_put(nhs->hugepages_kobj);
 	nhs->hugepages_kobj = NULL;
@@ -1848,7 +1875,7 @@ static void __exit hugetlb_exit(void)
 	hugetlb_unregister_all_nodes();
 
 	for_each_hstate(h) {
-		kobject_put(hstate_kobjs[h - hstates]);
+		kobject_put(hstate_kobjs[hstate_index(h)]);
 	}
 
 	kobject_put(hugepages_kobj);
@@ -1869,7 +1896,7 @@ static int __init hugetlb_init(void)
 		if (!size_to_hstate(default_hstate_size))
 			hugetlb_add_hstate(HUGETLB_PAGE_ORDER);
 	}
-	default_hstate_idx = size_to_hstate(default_hstate_size) - hstates;
+	default_hstate_idx = hstate_index(size_to_hstate(default_hstate_size));
 	if (default_hstate_max_huge_pages)
 		default_hstate.max_huge_pages = default_hstate_max_huge_pages;
 
@@ -1897,19 +1924,27 @@ void __init hugetlb_add_hstate(unsigned order)
 		printk(KERN_WARNING "hugepagesz= specified twice, ignoring\n");
 		return;
 	}
-	BUG_ON(max_hstate >= HUGE_MAX_HSTATE);
+	BUG_ON(hugetlb_max_hstate >= HUGE_MAX_HSTATE);
 	BUG_ON(order == 0);
-	h = &hstates[max_hstate++];
+	h = &hstates[hugetlb_max_hstate++];
 	h->order = order;
 	h->mask = ~((1ULL << (order + PAGE_SHIFT)) - 1);
 	h->nr_huge_pages = 0;
 	h->free_huge_pages = 0;
 	for (i = 0; i < MAX_NUMNODES; ++i)
 		INIT_LIST_HEAD(&h->hugepage_freelists[i]);
+	INIT_LIST_HEAD(&h->hugepage_activelist);
 	h->next_nid_to_alloc = first_node(node_states[N_HIGH_MEMORY]);
 	h->next_nid_to_free = first_node(node_states[N_HIGH_MEMORY]);
 	snprintf(h->name, HSTATE_NAME_LEN, "hugepages-%lukB",
 					huge_page_size(h)/1024);
+	/*
+	 * Add cgroup control files only if the huge page consists
+	 * of more than two normal pages. This is because we use
+	 * page[2].lru.next for storing cgoup details.
+	 */
+	if (order >= HUGETLB_CGROUP_MIN_ORDER)
+		hugetlb_cgroup_file_init(hugetlb_max_hstate - 1);
 
 	parsed_hstate = h;
 }
@@ -1920,10 +1955,10 @@ static int __init hugetlb_nrpages_setup(char *s)
 	static unsigned long *last_mhp;
 
 	/*
-	 * !max_hstate means we haven't parsed a hugepagesz= parameter yet,
+	 * !hugetlb_max_hstate means we haven't parsed a hugepagesz= parameter yet,
 	 * so this hugepages= parameter goes to the "default hstate".
 	 */
-	if (!max_hstate)
+	if (!hugetlb_max_hstate)
 		mhp = &default_hstate_max_huge_pages;
 	else
 		mhp = &parsed_hstate->max_huge_pages;
@@ -1942,7 +1977,7 @@ static int __init hugetlb_nrpages_setup(char *s)
 	 * But we need to allocate >= MAX_ORDER hstates here early to still
 	 * use the bootmem allocator.
 	 */
-	if (max_hstate && parsed_hstate->order >= MAX_ORDER)
+	if (hugetlb_max_hstate && parsed_hstate->order >= MAX_ORDER)
 		hugetlb_hstate_alloc_pages(parsed_hstate);
 
 	last_mhp = mhp;
@@ -2308,30 +2343,26 @@ static int is_hugetlb_entry_hwpoisoned(pte_t pte)
 		return 0;
 }
 
-void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
-			    unsigned long end, struct page *ref_page)
+void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+			    unsigned long start, unsigned long end,
+			    struct page *ref_page)
 {
+	int force_flush = 0;
 	struct mm_struct *mm = vma->vm_mm;
 	unsigned long address;
 	pte_t *ptep;
 	pte_t pte;
 	struct page *page;
-	struct page *tmp;
 	struct hstate *h = hstate_vma(vma);
 	unsigned long sz = huge_page_size(h);
 
-	/*
-	 * A page gathering list, protected by per file i_mmap_mutex. The
-	 * lock is used to avoid list corruption from multiple unmapping
-	 * of the same page since we are using page->lru.
-	 */
-	LIST_HEAD(page_list);
-
 	WARN_ON(!is_vm_hugetlb_page(vma));
 	BUG_ON(start & ~huge_page_mask(h));
 	BUG_ON(end & ~huge_page_mask(h));
 
+	tlb_start_vma(tlb, vma);
 	mmu_notifier_invalidate_range_start(mm, start, end);
+again:
 	spin_lock(&mm->page_table_lock);
 	for (address = start; address < end; address += sz) {
 		ptep = huge_pte_offset(mm, address);
@@ -2370,30 +2401,45 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
 		}
 
 		pte = huge_ptep_get_and_clear(mm, address, ptep);
+		tlb_remove_tlb_entry(tlb, ptep, address);
 		if (pte_dirty(pte))
 			set_page_dirty(page);
-		list_add(&page->lru, &page_list);
 
+		page_remove_rmap(page);
+		force_flush = !__tlb_remove_page(tlb, page);
+		if (force_flush)
+			break;
 		/* Bail out after unmapping reference page if supplied */
 		if (ref_page)
 			break;
 	}
-	flush_tlb_range(vma, start, end);
 	spin_unlock(&mm->page_table_lock);
-	mmu_notifier_invalidate_range_end(mm, start, end);
-	list_for_each_entry_safe(page, tmp, &page_list, lru) {
-		page_remove_rmap(page);
-		list_del(&page->lru);
-		put_page(page);
+	/*
+	 * mmu_gather ran out of room to batch pages, we break out of
+	 * the PTE lock to avoid doing the potential expensive TLB invalidate
+	 * and page-free while holding it.
+	 */
+	if (force_flush) {
+		force_flush = 0;
+		tlb_flush_mmu(tlb);
+		if (address < end && !ref_page)
+			goto again;
 	}
+	mmu_notifier_invalidate_range_end(mm, start, end);
+	tlb_end_vma(tlb, vma);
 }
 
 void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
 			  unsigned long end, struct page *ref_page)
 {
-	mutex_lock(&vma->vm_file->f_mapping->i_mmap_mutex);
-	__unmap_hugepage_range(vma, start, end, ref_page);
-	mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
+	struct mm_struct *mm;
+	struct mmu_gather tlb;
+
+	mm = vma->vm_mm;
+
+	tlb_gather_mmu(&tlb, mm, 0);
+	__unmap_hugepage_range(&tlb, vma, start, end, ref_page);
+	tlb_finish_mmu(&tlb, start, end);
 }
 
 /*
@@ -2438,9 +2484,8 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
 		 * from the time of fork. This would look like data corruption
 		 */
 		if (!is_vma_resv_set(iter_vma, HPAGE_RESV_OWNER))
-			__unmap_hugepage_range(iter_vma,
-				address, address + huge_page_size(h),
-				page);
+			unmap_hugepage_range(iter_vma, address,
+					     address + huge_page_size(h), page);
 	}
 	mutex_unlock(&mapping->i_mmap_mutex);
 
@@ -2496,6 +2541,7 @@ retry_avoidcopy:
 	new_page = alloc_huge_page(vma, address, outside_reserve);
 
 	if (IS_ERR(new_page)) {
+		long err = PTR_ERR(new_page);
 		page_cache_release(old_page);
 
 		/*
@@ -2524,7 +2570,10 @@ retry_avoidcopy:
 
 		/* Caller expects lock to be held */
 		spin_lock(&mm->page_table_lock);
-		return -PTR_ERR(new_page);
+		if (err == -ENOMEM)
+			return VM_FAULT_OOM;
+		else
+			return VM_FAULT_SIGBUS;
 	}
 
 	/*
@@ -2642,7 +2691,11 @@ retry:
 			goto out;
 		page = alloc_huge_page(vma, address, 0);
 		if (IS_ERR(page)) {
-			ret = -PTR_ERR(page);
+			ret = PTR_ERR(page);
+			if (ret == -ENOMEM)
+				ret = VM_FAULT_OOM;
+			else
+				ret = VM_FAULT_SIGBUS;
 			goto out;
 		}
 		clear_huge_page(page, address, pages_per_huge_page(h));
@@ -2679,7 +2732,7 @@ retry:
 		 */
 		if (unlikely(PageHWPoison(page))) {
 			ret = VM_FAULT_HWPOISON |
-			      VM_FAULT_SET_HINDEX(h - hstates);
+				VM_FAULT_SET_HINDEX(hstate_index(h));
 			goto backout_unlocked;
 		}
 	}
@@ -2752,7 +2805,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
 			return 0;
 		} else if (unlikely(is_hugetlb_entry_hwpoisoned(entry)))
 			return VM_FAULT_HWPOISON_LARGE |
-			       VM_FAULT_SET_HINDEX(h - hstates);
+				VM_FAULT_SET_HINDEX(hstate_index(h));
 	}
 
 	ptep = huge_pte_alloc(mm, address, huge_page_size(h));
diff --git a/mm/hugetlb_cgroup.c b/mm/hugetlb_cgroup.c
new file mode 100644
index 0000000..db40669
--- /dev/null
+++ b/mm/hugetlb_cgroup.c
@@ -0,0 +1,420 @@
+/*
+ *
+ * Copyright IBM Corporation, 2012
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <linux/cgroup.h>
+#include <linux/slab.h>
+#include <linux/hugetlb.h>
+#include <linux/hugetlb_cgroup.h>
+
+struct hugetlb_cgroup {
+	struct cgroup_subsys_state css;
+	/*
+	 * the counter to account for hugepages from hugetlb.
+	 */
+	struct res_counter hugepage[HUGE_MAX_HSTATE];
+};
+
+#define MEMFILE_PRIVATE(x, val)	(((x) << 16) | (val))
+#define MEMFILE_IDX(val)	(((val) >> 16) & 0xffff)
+#define MEMFILE_ATTR(val)	((val) & 0xffff)
+
+struct cgroup_subsys hugetlb_subsys __read_mostly;
+static struct hugetlb_cgroup *root_h_cgroup __read_mostly;
+
+static inline
+struct hugetlb_cgroup *hugetlb_cgroup_from_css(struct cgroup_subsys_state *s)
+{
+	if (s)
+		return container_of(s, struct hugetlb_cgroup, css);
+	return NULL;
+}
+
+static inline
+struct hugetlb_cgroup *hugetlb_cgroup_from_cgroup(struct cgroup *cgroup)
+{
+	return hugetlb_cgroup_from_css(cgroup_subsys_state(cgroup,
+							   hugetlb_subsys_id));
+}
+
+static inline
+struct hugetlb_cgroup *hugetlb_cgroup_from_task(struct task_struct *task)
+{
+	return hugetlb_cgroup_from_css(task_subsys_state(task,
+							 hugetlb_subsys_id));
+}
+
+static inline bool hugetlb_cgroup_is_root(struct hugetlb_cgroup *h_cg)
+{
+	return (h_cg == root_h_cgroup);
+}
+
+static inline struct hugetlb_cgroup *parent_hugetlb_cgroup(struct cgroup *cg)
+{
+	if (!cg->parent)
+		return NULL;
+	return hugetlb_cgroup_from_cgroup(cg->parent);
+}
+
+static inline bool hugetlb_cgroup_have_usage(struct cgroup *cg)
+{
+	int idx;
+	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_cgroup(cg);
+
+	for (idx = 0; idx < hugetlb_max_hstate; idx++) {
+		if ((res_counter_read_u64(&h_cg->hugepage[idx], RES_USAGE)) > 0)
+			return true;
+	}
+	return false;
+}
+
+static struct cgroup_subsys_state *hugetlb_cgroup_create(struct cgroup *cgroup)
+{
+	int idx;
+	struct cgroup *parent_cgroup;
+	struct hugetlb_cgroup *h_cgroup, *parent_h_cgroup;
+
+	h_cgroup = kzalloc(sizeof(*h_cgroup), GFP_KERNEL);
+	if (!h_cgroup)
+		return ERR_PTR(-ENOMEM);
+
+	parent_cgroup = cgroup->parent;
+	if (parent_cgroup) {
+		parent_h_cgroup = hugetlb_cgroup_from_cgroup(parent_cgroup);
+		for (idx = 0; idx < HUGE_MAX_HSTATE; idx++)
+			res_counter_init(&h_cgroup->hugepage[idx],
+					 &parent_h_cgroup->hugepage[idx]);
+	} else {
+		root_h_cgroup = h_cgroup;
+		for (idx = 0; idx < HUGE_MAX_HSTATE; idx++)
+			res_counter_init(&h_cgroup->hugepage[idx], NULL);
+	}
+	return &h_cgroup->css;
+}
+
+static void hugetlb_cgroup_destroy(struct cgroup *cgroup)
+{
+	struct hugetlb_cgroup *h_cgroup;
+
+	h_cgroup = hugetlb_cgroup_from_cgroup(cgroup);
+	kfree(h_cgroup);
+}
+
+
+/*
+ * Should be called with hugetlb_lock held.
+ * Since we are holding hugetlb_lock, pages cannot get moved from
+ * active list or uncharged from the cgroup, So no need to get
+ * page reference and test for page active here. This function
+ * cannot fail.
+ */
+static void hugetlb_cgroup_move_parent(int idx, struct cgroup *cgroup,
+				       struct page *page)
+{
+	int csize;
+	struct res_counter *counter;
+	struct res_counter *fail_res;
+	struct hugetlb_cgroup *page_hcg;
+	struct hugetlb_cgroup *h_cg   = hugetlb_cgroup_from_cgroup(cgroup);
+	struct hugetlb_cgroup *parent = parent_hugetlb_cgroup(cgroup);
+
+	page_hcg = hugetlb_cgroup_from_page(page);
+	/*
+	 * We can have pages in active list without any cgroup
+	 * ie, hugepage with less than 3 pages. We can safely
+	 * ignore those pages.
+	 */
+	if (!page_hcg || page_hcg != h_cg)
+		goto out;
+
+	csize = PAGE_SIZE << compound_order(page);
+	if (!parent) {
+		parent = root_h_cgroup;
+		/* root has no limit */
+		res_counter_charge_nofail(&parent->hugepage[idx],
+					  csize, &fail_res);
+	}
+	counter = &h_cg->hugepage[idx];
+	res_counter_uncharge_until(counter, counter->parent, csize);
+
+	set_hugetlb_cgroup(page, parent);
+out:
+	return;
+}
+
+/*
+ * Force the hugetlb cgroup to empty the hugetlb resources by moving them to
+ * the parent cgroup.
+ */
+static int hugetlb_cgroup_pre_destroy(struct cgroup *cgroup)
+{
+	struct hstate *h;
+	struct page *page;
+	int ret = 0, idx = 0;
+
+	do {
+		if (cgroup_task_count(cgroup) ||
+		    !list_empty(&cgroup->children)) {
+			ret = -EBUSY;
+			goto out;
+		}
+		for_each_hstate(h) {
+			spin_lock(&hugetlb_lock);
+			list_for_each_entry(page, &h->hugepage_activelist, lru)
+				hugetlb_cgroup_move_parent(idx, cgroup, page);
+
+			spin_unlock(&hugetlb_lock);
+			idx++;
+		}
+		cond_resched();
+	} while (hugetlb_cgroup_have_usage(cgroup));
+out:
+	return ret;
+}
+
+int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
+				 struct hugetlb_cgroup **ptr)
+{
+	int ret = 0;
+	struct res_counter *fail_res;
+	struct hugetlb_cgroup *h_cg = NULL;
+	unsigned long csize = nr_pages * PAGE_SIZE;
+
+	if (hugetlb_cgroup_disabled())
+		goto done;
+	/*
+	 * We don't charge any cgroup if the compound page have less
+	 * than 3 pages.
+	 */
+	if (huge_page_order(&hstates[idx]) < HUGETLB_CGROUP_MIN_ORDER)
+		goto done;
+again:
+	rcu_read_lock();
+	h_cg = hugetlb_cgroup_from_task(current);
+	if (!h_cg)
+		h_cg = root_h_cgroup;
+
+	if (!css_tryget(&h_cg->css)) {
+		rcu_read_unlock();
+		goto again;
+	}
+	rcu_read_unlock();
+
+	ret = res_counter_charge(&h_cg->hugepage[idx], csize, &fail_res);
+	css_put(&h_cg->css);
+done:
+	*ptr = h_cg;
+	return ret;
+}
+
+/* Should be called with hugetlb_lock held */
+void hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages,
+				  struct hugetlb_cgroup *h_cg,
+				  struct page *page)
+{
+	if (hugetlb_cgroup_disabled() || !h_cg)
+		return;
+
+	set_hugetlb_cgroup(page, h_cg);
+	return;
+}
+
+/*
+ * Should be called with hugetlb_lock held
+ */
+void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages,
+				  struct page *page)
+{
+	struct hugetlb_cgroup *h_cg;
+	unsigned long csize = nr_pages * PAGE_SIZE;
+
+	if (hugetlb_cgroup_disabled())
+		return;
+	VM_BUG_ON(!spin_is_locked(&hugetlb_lock));
+	h_cg = hugetlb_cgroup_from_page(page);
+	if (unlikely(!h_cg))
+		return;
+	set_hugetlb_cgroup(page, NULL);
+	res_counter_uncharge(&h_cg->hugepage[idx], csize);
+	return;
+}
+
+void hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages,
+				    struct hugetlb_cgroup *h_cg)
+{
+	unsigned long csize = nr_pages * PAGE_SIZE;
+
+	if (hugetlb_cgroup_disabled() || !h_cg)
+		return;
+
+	res_counter_uncharge(&h_cg->hugepage[idx], csize);
+	return;
+}
+
+static ssize_t hugetlb_cgroup_read(struct cgroup *cgroup, struct cftype *cft,
+				   struct file *file, char __user *buf,
+				   size_t nbytes, loff_t *ppos)
+{
+	u64 val;
+	char str[64];
+	int idx, name, len;
+	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_cgroup(cgroup);
+
+	idx = MEMFILE_IDX(cft->private);
+	name = MEMFILE_ATTR(cft->private);
+
+	val = res_counter_read_u64(&h_cg->hugepage[idx], name);
+	len = scnprintf(str, sizeof(str), "%llu\n", (unsigned long long)val);
+	return simple_read_from_buffer(buf, nbytes, ppos, str, len);
+}
+
+static int hugetlb_cgroup_write(struct cgroup *cgroup, struct cftype *cft,
+				const char *buffer)
+{
+	int idx, name, ret;
+	unsigned long long val;
+	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_cgroup(cgroup);
+
+	idx = MEMFILE_IDX(cft->private);
+	name = MEMFILE_ATTR(cft->private);
+
+	switch (name) {
+	case RES_LIMIT:
+		if (hugetlb_cgroup_is_root(h_cg)) {
+			/* Can't set limit on root */
+			ret = -EINVAL;
+			break;
+		}
+		/* This function does all necessary parse...reuse it */
+		ret = res_counter_memparse_write_strategy(buffer, &val);
+		if (ret)
+			break;
+		ret = res_counter_set_limit(&h_cg->hugepage[idx], val);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int hugetlb_cgroup_reset(struct cgroup *cgroup, unsigned int event)
+{
+	int idx, name, ret = 0;
+	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_cgroup(cgroup);
+
+	idx = MEMFILE_IDX(event);
+	name = MEMFILE_ATTR(event);
+
+	switch (name) {
+	case RES_MAX_USAGE:
+		res_counter_reset_max(&h_cg->hugepage[idx]);
+		break;
+	case RES_FAILCNT:
+		res_counter_reset_failcnt(&h_cg->hugepage[idx]);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static char *mem_fmt(char *buf, int size, unsigned long hsize)
+{
+	if (hsize >= (1UL << 30))
+		snprintf(buf, size, "%luGB", hsize >> 30);
+	else if (hsize >= (1UL << 20))
+		snprintf(buf, size, "%luMB", hsize >> 20);
+	else
+		snprintf(buf, size, "%luKB", hsize >> 10);
+	return buf;
+}
+
+int __init hugetlb_cgroup_file_init(int idx)
+{
+	char buf[32];
+	struct cftype *cft;
+	struct hstate *h = &hstates[idx];
+
+	/* format the size */
+	mem_fmt(buf, 32, huge_page_size(h));
+
+	/* Add the limit file */
+	cft = &h->cgroup_files[0];
+	snprintf(cft->name, MAX_CFTYPE_NAME, "%s.limit_in_bytes", buf);
+	cft->private = MEMFILE_PRIVATE(idx, RES_LIMIT);
+	cft->read = hugetlb_cgroup_read;
+	cft->write_string = hugetlb_cgroup_write;
+
+	/* Add the usage file */
+	cft = &h->cgroup_files[1];
+	snprintf(cft->name, MAX_CFTYPE_NAME, "%s.usage_in_bytes", buf);
+	cft->private = MEMFILE_PRIVATE(idx, RES_USAGE);
+	cft->read = hugetlb_cgroup_read;
+
+	/* Add the MAX usage file */
+	cft = &h->cgroup_files[2];
+	snprintf(cft->name, MAX_CFTYPE_NAME, "%s.max_usage_in_bytes", buf);
+	cft->private = MEMFILE_PRIVATE(idx, RES_MAX_USAGE);
+	cft->trigger = hugetlb_cgroup_reset;
+	cft->read = hugetlb_cgroup_read;
+
+	/* Add the failcntfile */
+	cft = &h->cgroup_files[3];
+	snprintf(cft->name, MAX_CFTYPE_NAME, "%s.failcnt", buf);
+	cft->private  = MEMFILE_PRIVATE(idx, RES_FAILCNT);
+	cft->trigger  = hugetlb_cgroup_reset;
+	cft->read = hugetlb_cgroup_read;
+
+	/* NULL terminate the last cft */
+	cft = &h->cgroup_files[4];
+	memset(cft, 0, sizeof(*cft));
+
+	WARN_ON(cgroup_add_cftypes(&hugetlb_subsys, h->cgroup_files));
+
+	return 0;
+}
+
+/*
+ * hugetlb_lock will make sure a parallel cgroup rmdir won't happen
+ * when we migrate hugepages
+ */
+void hugetlb_cgroup_migrate(struct page *oldhpage, struct page *newhpage)
+{
+	struct hugetlb_cgroup *h_cg;
+	struct hstate *h = page_hstate(oldhpage);
+
+	if (hugetlb_cgroup_disabled())
+		return;
+
+	VM_BUG_ON(!PageHuge(oldhpage));
+	spin_lock(&hugetlb_lock);
+	h_cg = hugetlb_cgroup_from_page(oldhpage);
+	set_hugetlb_cgroup(oldhpage, NULL);
+
+	/* move the h_cg details to new cgroup */
+	set_hugetlb_cgroup(newhpage, h_cg);
+	list_move(&newhpage->lru, &h->hugepage_activelist);
+	spin_unlock(&hugetlb_lock);
+	return;
+}
+
+struct cgroup_subsys hugetlb_subsys = {
+	.name = "hugetlb",
+	.create     = hugetlb_cgroup_create,
+	.pre_destroy = hugetlb_cgroup_pre_destroy,
+	.destroy    = hugetlb_cgroup_destroy,
+	.subsys_id  = hugetlb_subsys_id,
+};
diff --git a/mm/init-mm.c b/mm/init-mm.c
index a56a851..4649c40 100644
--- a/mm/init-mm.c
+++ b/mm/init-mm.c
@@ -13,6 +13,15 @@
 #define INIT_MM_CONTEXT(name)
 #endif
 
+#ifdef CONFIG_NUMA
+# define INIT_MM_NUMA(mm)						\
+	.numa = {							\
+		.node = -1,						\
+	},
+#else
+# define INIT_MM_NUMA(mm)
+#endif
+
 struct mm_struct init_mm = {
 	.mm_rb		= RB_ROOT,
 	.pgd		= swapper_pg_dir,
@@ -22,4 +31,5 @@ struct mm_struct init_mm = {
 	.page_table_lock =  __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
 	.mmlist		= LIST_HEAD_INIT(init_mm.mmlist),
 	INIT_MM_CONTEXT(init_mm)
+	INIT_MM_NUMA(init_mm)
 };
diff --git a/mm/internal.h b/mm/internal.h
index 2ba87fb..0e20156 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -94,6 +94,11 @@ extern void putback_lru_page(struct page *page);
 /*
  * in mm/page_alloc.c
  */
+extern void set_pageblock_migratetype(struct page *page, int migratetype);
+extern int move_freepages_block(struct zone *zone, struct page *page,
+				int migratetype);
+extern bool __count_immobile_pages(struct zone *zone, struct page *page,
+				  int count);
 extern void __free_pages_bootmem(struct page *page, unsigned int order);
 extern void prep_compound_page(struct page *page, unsigned long order);
 #ifdef CONFIG_MEMORY_FAILURE
@@ -101,6 +106,7 @@ extern bool is_free_buddy_page(struct page *page);
 #endif
 
 #if defined CONFIG_COMPACTION || defined CONFIG_CMA
+#include <linux/compaction.h>
 
 /*
  * in mm/compaction.c
@@ -119,11 +125,14 @@ struct compact_control {
 	unsigned long nr_migratepages;	/* Number of pages to migrate */
 	unsigned long free_pfn;		/* isolate_freepages search base */
 	unsigned long migrate_pfn;	/* isolate_migratepages search base */
-	bool sync;			/* Synchronous migration */
+	enum compact_mode mode;		/* Compaction mode */
 
 	int order;			/* order a direct compactor needs */
 	int migratetype;		/* MOVABLE, RECLAIMABLE etc */
 	struct zone *zone;
+
+	/* Number of UNMOVABLE destination pageblocks skipped during scan */
+	unsigned long nr_unmovable_pageblock;
 };
 
 unsigned long
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 45eb621..5f05993 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -578,6 +578,7 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size,
 	if (node != &object->tree_node) {
 		kmemleak_stop("Cannot insert 0x%lx into the object search tree "
 			      "(already existing)\n", ptr);
+		kmem_cache_free(object_cache, object);
 		object = lookup_object(ptr, 1);
 		spin_lock(&object->lock);
 		dump_object_info(object);
diff --git a/mm/memblock.c b/mm/memblock.c
index d438209..6b430f5 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -227,13 +227,13 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
 	/* Try to find some space for it.
 	 *
 	 * WARNING: We assume that either slab_is_available() and we use it or
-	 * we use MEMBLOCK for allocations. That means that this is unsafe to use
-	 * when bootmem is currently active (unless bootmem itself is implemented
-	 * on top of MEMBLOCK which isn't the case yet)
+	 * we use MEMBLOCK for allocations. That means that this is unsafe to
+	 * use when bootmem is currently active (unless bootmem itself is
+	 * implemented on top of MEMBLOCK which isn't the case yet)
 	 *
 	 * This should however not be an issue for now, as we currently only
-	 * call into MEMBLOCK while it's still active, or much later when slab is
-	 * active for memory hotplug operations
+	 * call into MEMBLOCK while it's still active, or much later when slab
+	 * is active for memory hotplug operations
 	 */
 	if (use_slab) {
 		new_array = kmalloc(new_size, GFP_KERNEL);
@@ -248,8 +248,8 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
 						new_size, sizeof(phys_addr_t));
 		if (!addr && new_area_size)
 			addr = memblock_find_in_range(0,
-					min(new_area_start, memblock.current_limit),
-					new_size, sizeof(phys_addr_t));
+				    min(new_area_start, memblock.current_limit),
+				    new_size, sizeof(phys_addr_t));
 
 		new_array = addr ? __va(addr) : 0;
 	}
@@ -259,12 +259,14 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
 		return -1;
 	}
 
-	memblock_dbg("memblock: %s array is doubled to %ld at [%#010llx-%#010llx]",
-		 memblock_type_name(type), type->max * 2, (u64)addr, (u64)addr + new_size - 1);
+	memblock_dbg("memblock: %s is doubled to %ld at [%#010llx-%#010llx]",
+			memblock_type_name(type), type->max * 2, (u64)addr,
+			(u64)addr + new_size - 1);
 
-	/* Found space, we now need to move the array over before
-	 * we add the reserved region since it may be our reserved
-	 * array itself that is full.
+	/*
+	 * Found space, we now need to move the array over before we add the
+	 * reserved region since it may be our reserved array itself that is
+	 * full.
 	 */
 	memcpy(new_array, type->regions, old_size);
 	memset(new_array + type->max, 0, old_size);
@@ -272,17 +274,16 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
 	type->regions = new_array;
 	type->max <<= 1;
 
-	/* Free old array. We needn't free it if the array is the
-	 * static one
-	 */
+	/* Free old array. We needn't free it if the array is the static one */
 	if (*in_slab)
 		kfree(old_array);
 	else if (old_array != memblock_memory_init_regions &&
 		 old_array != memblock_reserved_init_regions)
 		memblock_free(__pa(old_array), old_size);
 
-	/* Reserve the new array if that comes from the memblock.
-	 * Otherwise, we needn't do it
+	/*
+	 * Reserve the new array if that comes from the memblock.  Otherwise, we
+	 * needn't do it
 	 */
 	if (!use_slab)
 		BUG_ON(memblock_reserve(addr, new_size));
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index f72b5e5..a2677e0 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -87,7 +87,7 @@ enum mem_cgroup_stat_index {
 	MEM_CGROUP_STAT_CACHE, 	   /* # of pages charged as cache */
 	MEM_CGROUP_STAT_RSS,	   /* # of pages charged as anon rss */
 	MEM_CGROUP_STAT_FILE_MAPPED,  /* # of pages charged as file rss */
-	MEM_CGROUP_STAT_SWAPOUT, /* # of pages, swapped out */
+	MEM_CGROUP_STAT_SWAP, /* # of pages, swapped out */
 	MEM_CGROUP_STAT_NSTATS,
 };
 
@@ -378,9 +378,8 @@ static bool move_file(void)
 
 enum charge_type {
 	MEM_CGROUP_CHARGE_TYPE_CACHE = 0,
-	MEM_CGROUP_CHARGE_TYPE_MAPPED,
+	MEM_CGROUP_CHARGE_TYPE_ANON,
 	MEM_CGROUP_CHARGE_TYPE_SHMEM,	/* used by page migration of shmem */
-	MEM_CGROUP_CHARGE_TYPE_FORCE,	/* used by force_empty */
 	MEM_CGROUP_CHARGE_TYPE_SWAPOUT,	/* for accounting swapcache */
 	MEM_CGROUP_CHARGE_TYPE_DROP,	/* a page was unused swap cache */
 	NR_CHARGE_TYPE,
@@ -703,7 +702,7 @@ static void mem_cgroup_swap_statistics(struct mem_cgroup *memcg,
 					 bool charge)
 {
 	int val = (charge) ? 1 : -1;
-	this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_SWAPOUT], val);
+	this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_SWAP], val);
 }
 
 static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg,
@@ -2519,7 +2518,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
 		spin_unlock_irq(&zone->lru_lock);
 	}
 
-	if (ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED)
+	if (ctype == MEM_CGROUP_CHARGE_TYPE_ANON)
 		anon = true;
 	else
 		anon = false;
@@ -2644,8 +2643,7 @@ out:
 
 static int mem_cgroup_move_parent(struct page *page,
 				  struct page_cgroup *pc,
-				  struct mem_cgroup *child,
-				  gfp_t gfp_mask)
+				  struct mem_cgroup *child)
 {
 	struct mem_cgroup *parent;
 	unsigned int nr_pages;
@@ -2728,7 +2726,7 @@ int mem_cgroup_newpage_charge(struct page *page,
 	VM_BUG_ON(page->mapping && !PageAnon(page));
 	VM_BUG_ON(!mm);
 	return mem_cgroup_charge_common(page, mm, gfp_mask,
-					MEM_CGROUP_CHARGE_TYPE_MAPPED);
+					MEM_CGROUP_CHARGE_TYPE_ANON);
 }
 
 static void
@@ -2842,7 +2840,7 @@ void mem_cgroup_commit_charge_swapin(struct page *page,
 				     struct mem_cgroup *memcg)
 {
 	__mem_cgroup_commit_charge_swapin(page, memcg,
-					  MEM_CGROUP_CHARGE_TYPE_MAPPED);
+					  MEM_CGROUP_CHARGE_TYPE_ANON);
 }
 
 void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *memcg)
@@ -2945,7 +2943,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
 	anon = PageAnon(page);
 
 	switch (ctype) {
-	case MEM_CGROUP_CHARGE_TYPE_MAPPED:
+	case MEM_CGROUP_CHARGE_TYPE_ANON:
 		/*
 		 * Generally PageAnon tells if it's the anon statistics to be
 		 * updated; but sometimes e.g. mem_cgroup_uncharge_page() is
@@ -3005,7 +3003,7 @@ void mem_cgroup_uncharge_page(struct page *page)
 	if (page_mapped(page))
 		return;
 	VM_BUG_ON(page->mapping && !PageAnon(page));
-	__mem_cgroup_uncharge_common(page, MEM_CGROUP_CHARGE_TYPE_MAPPED);
+	__mem_cgroup_uncharge_common(page, MEM_CGROUP_CHARGE_TYPE_ANON);
 }
 
 void mem_cgroup_uncharge_cache_page(struct page *page)
@@ -3248,7 +3246,7 @@ int mem_cgroup_prepare_migration(struct page *page,
 	 * mapcount will be finally 0 and we call uncharge in end_migration().
 	 */
 	if (PageAnon(page))
-		ctype = MEM_CGROUP_CHARGE_TYPE_MAPPED;
+		ctype = MEM_CGROUP_CHARGE_TYPE_ANON;
 	else if (page_is_file_cache(page))
 		ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
 	else
@@ -3287,7 +3285,7 @@ void mem_cgroup_end_migration(struct mem_cgroup *memcg,
 	unlock_page_cgroup(pc);
 	anon = PageAnon(used);
 	__mem_cgroup_uncharge_common(unused,
-		anon ? MEM_CGROUP_CHARGE_TYPE_MAPPED
+		anon ? MEM_CGROUP_CHARGE_TYPE_ANON
 		     : MEM_CGROUP_CHARGE_TYPE_CACHE);
 
 	/*
@@ -3611,10 +3609,12 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
 }
 
 /*
- * This routine traverse page_cgroup in given list and drop them all.
- * *And* this routine doesn't reclaim page itself, just removes page_cgroup.
+ * Traverse a specified page_cgroup list and try to drop them all.  This doesn't
+ * reclaim the pages page themselves - it just removes the page_cgroups.
+ * Returns true if some page_cgroups were not freed, indicating that the caller
+ * must retry this operation.
  */
-static int mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
+static bool mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
 				int node, int zid, enum lru_list lru)
 {
 	struct mem_cgroup_per_zone *mz;
@@ -3622,7 +3622,6 @@ static int mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
 	struct list_head *list;
 	struct page *busy;
 	struct zone *zone;
-	int ret = 0;
 
 	zone = &NODE_DATA(node)->node_zones[zid];
 	mz = mem_cgroup_zoneinfo(memcg, node, zid);
@@ -3636,7 +3635,6 @@ static int mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
 		struct page_cgroup *pc;
 		struct page *page;
 
-		ret = 0;
 		spin_lock_irqsave(&zone->lru_lock, flags);
 		if (list_empty(list)) {
 			spin_unlock_irqrestore(&zone->lru_lock, flags);
@@ -3653,21 +3651,14 @@ static int mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
 
 		pc = lookup_page_cgroup(page);
 
-		ret = mem_cgroup_move_parent(page, pc, memcg, GFP_KERNEL);
-		if (ret == -ENOMEM || ret == -EINTR)
-			break;
-
-		if (ret == -EBUSY || ret == -EINVAL) {
+		if (mem_cgroup_move_parent(page, pc, memcg)) {
 			/* found lock contention or "pc" is obsolete. */
 			busy = page;
 			cond_resched();
 		} else
 			busy = NULL;
 	}
-
-	if (!ret && !list_empty(list))
-		return -EBUSY;
-	return ret;
+	return !list_empty(list);
 }
 
 /*
@@ -3692,9 +3683,6 @@ move_account:
 		ret = -EBUSY;
 		if (cgroup_task_count(cgrp) || !list_empty(&cgrp->children))
 			goto out;
-		ret = -EINTR;
-		if (signal_pending(current))
-			goto out;
 		/* This is for making all *used* pages to be on LRU. */
 		lru_add_drain_all();
 		drain_all_stock_sync(memcg);
@@ -3715,9 +3703,6 @@ move_account:
 		}
 		mem_cgroup_end_move(memcg);
 		memcg_oom_recover(memcg);
-		/* it seems parent cgroup doesn't have enough mem */
-		if (ret == -ENOMEM)
-			goto try_to_free;
 		cond_resched();
 	/* "ret" should also be checked to ensure all lists are empty. */
 	} while (res_counter_read_u64(&memcg->res, RES_USAGE) > 0 || ret);
@@ -3831,7 +3816,7 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *memcg, bool swap)
 	val += mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_RSS);
 
 	if (swap)
-		val += mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_SWAPOUT);
+		val += mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_SWAP);
 
 	return val << PAGE_SHIFT;
 }
@@ -4082,7 +4067,7 @@ static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
 	unsigned int i;
 
 	for (i = 0; i < MEM_CGROUP_STAT_NSTATS; i++) {
-		if (i == MEM_CGROUP_STAT_SWAPOUT && !do_swap_account)
+		if (i == MEM_CGROUP_STAT_SWAP && !do_swap_account)
 			continue;
 		seq_printf(m, "%s %ld\n", mem_cgroup_stat_names[i],
 			   mem_cgroup_read_stat(memcg, i) * PAGE_SIZE);
@@ -4109,7 +4094,7 @@ static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
 	for (i = 0; i < MEM_CGROUP_STAT_NSTATS; i++) {
 		long long val = 0;
 
-		if (i == MEM_CGROUP_STAT_SWAPOUT && !do_swap_account)
+		if (i == MEM_CGROUP_STAT_SWAP && !do_swap_account)
 			continue;
 		for_each_mem_cgroup_tree(mi, memcg)
 			val += mem_cgroup_read_stat(mi, i) * PAGE_SIZE;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index ab1e714..53a1495 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1414,7 +1414,6 @@ static int soft_offline_huge_page(struct page *page, int flags)
 	int ret;
 	unsigned long pfn = page_to_pfn(page);
 	struct page *hpage = compound_head(page);
-	LIST_HEAD(pagelist);
 
 	ret = get_any_page(page, pfn, flags);
 	if (ret < 0)
@@ -1429,19 +1428,11 @@ static int soft_offline_huge_page(struct page *page, int flags)
 	}
 
 	/* Keep page count to indicate a given hugepage is isolated. */
-
-	list_add(&hpage->lru, &pagelist);
-	ret = migrate_huge_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, 0,
-				true);
+	ret = migrate_huge_page(hpage, new_page, MPOL_MF_MOVE_ALL, 0, true);
+	put_page(hpage);
 	if (ret) {
-		struct page *page1, *page2;
-		list_for_each_entry_safe(page1, page2, &pagelist, lru)
-			put_page(page1);
-
 		pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
 			pfn, ret, page->flags);
-		if (ret > 0)
-			ret = -EIO;
 		return ret;
 	}
 done:
diff --git a/mm/memory.c b/mm/memory.c
index 2466d12..6322d36 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -57,6 +57,7 @@
 #include <linux/swapops.h>
 #include <linux/elf.h>
 #include <linux/gfp.h>
+#include <linux/mempolicy.h>	/* check_migrate_misplaced_page() */
 
 #include <asm/io.h>
 #include <asm/pgalloc.h>
@@ -1335,7 +1336,7 @@ static void unmap_single_vma(struct mmu_gather *tlb,
 			 * safe to do nothing in this case.
 			 */
 			if (vma->vm_file)
-				unmap_hugepage_range(vma, start, end, NULL);
+				__unmap_hugepage_range(tlb, vma, start, end, NULL);
 		} else
 			unmap_page_range(tlb, vma, start, end, details);
 	}
@@ -2979,6 +2980,22 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
 	}
 
 	/*
+	 * No sense in migrating a page that will be "COWed" as the new
+	 * new page will be allocated according to effective mempolicy.
+	 */
+	if ((flags & FAULT_FLAG_WRITE) && can_reuse_swap_page(page)) {
+		/*
+		 * check for misplacement and migrate, if necessary/possible,
+		 * here and now.  Note that if we're racing with another thread,
+		 * we may end up discarding the migrated page after locking
+		 * the page table and checking the pte below.  However, we
+		 * don't want to hold the page table locked over migration, so
+		 * we'll live with that [unlikely, one hopes] possibility.
+		 */
+		page = check_migrate_misplaced_page(page, vma, address);
+	}
+
+	/*
 	 * Back out if somebody else already faulted in this pte.
 	 */
 	page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 1d771e4..4fd7b75 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -117,6 +117,22 @@ static struct mempolicy default_policy = {
 	.flags = MPOL_F_LOCAL,
 };
 
+static struct mempolicy preferred_node_policy[MAX_NUMNODES];
+
+static struct mempolicy *get_task_policy(struct task_struct *p)
+{
+	struct mempolicy *pol = p->mempolicy;
+	int node;
+
+	if (!pol) {
+		node = tsk_home_node(p);
+		if (node != -1)
+			pol = &preferred_node_policy[node];
+	}
+
+	return pol;
+}
+
 static const struct mempolicy_operations {
 	int (*create)(struct mempolicy *pol, const nodemask_t *nodes);
 	/*
@@ -243,7 +259,7 @@ static int mpol_set_nodemask(struct mempolicy *pol,
  * This function just creates a new policy, does some check and simple
  * initialization. You must invoke mpol_set_nodemask() to set nodes.
  */
-static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags,
+struct mempolicy *mpol_new(unsigned short mode, unsigned short flags,
 				  nodemask_t *nodes)
 {
 	struct mempolicy *policy;
@@ -251,10 +267,10 @@ static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags,
 	pr_debug("setting mode %d flags %d nodes[0] %lx\n",
 		 mode, flags, nodes ? nodes_addr(*nodes)[0] : -1);
 
-	if (mode == MPOL_DEFAULT) {
+	if (mode == MPOL_DEFAULT || mode == MPOL_NOOP) {
 		if (nodes && !nodes_empty(*nodes))
 			return ERR_PTR(-EINVAL);
-		return NULL;	/* simply delete any existing policy */
+		return NULL;
 	}
 	VM_BUG_ON(!nodes);
 
@@ -269,6 +285,10 @@ static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags,
 			     (flags & MPOL_F_RELATIVE_NODES)))
 				return ERR_PTR(-EINVAL);
 		}
+	} else if (mode == MPOL_LOCAL) {
+		if (!nodes_empty(*nodes))
+			return ERR_PTR(-EINVAL);
+		mode = MPOL_PREFERRED;
 	} else if (nodes_empty(*nodes))
 		return ERR_PTR(-EINVAL);
 	policy = kmem_cache_alloc(policy_cache, GFP_KERNEL);
@@ -385,7 +405,7 @@ static void mpol_rebind_preferred(struct mempolicy *pol,
  * 	MPOL_REBIND_STEP1 - set all the newly nodes
  * 	MPOL_REBIND_STEP2 - clean all the disallowed nodes
  */
-static void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *newmask,
+void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *newmask,
 				enum mpol_rebind_step step)
 {
 	if (!pol)
@@ -460,105 +480,64 @@ static const struct mempolicy_operations mpol_ops[MPOL_MAX] = {
 static void migrate_page_add(struct page *page, struct list_head *pagelist,
 				unsigned long flags);
 
-/* Scan through pages checking if pages follow certain conditions. */
-static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
-		unsigned long addr, unsigned long end,
-		const nodemask_t *nodes, unsigned long flags,
-		void *private)
+/*
+ * Check whether a vma is migratable
+ */
+int vma_migratable(struct vm_area_struct *vma)
 {
-	pte_t *orig_pte;
-	pte_t *pte;
-	spinlock_t *ptl;
-
-	orig_pte = pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
-	do {
-		struct page *page;
-		int nid;
-
-		if (!pte_present(*pte))
-			continue;
-		page = vm_normal_page(vma, addr, *pte);
-		if (!page)
-			continue;
-		/*
-		 * vm_normal_page() filters out zero pages, but there might
-		 * still be PageReserved pages to skip, perhaps in a VDSO.
-		 * And we cannot move PageKsm pages sensibly or safely yet.
-		 */
-		if (PageReserved(page) || PageKsm(page))
-			continue;
-		nid = page_to_nid(page);
-		if (node_isset(nid, *nodes) == !!(flags & MPOL_MF_INVERT))
-			continue;
-
-		if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
-			migrate_page_add(page, private, flags);
-		else
-			break;
-	} while (pte++, addr += PAGE_SIZE, addr != end);
-	pte_unmap_unlock(orig_pte, ptl);
-	return addr != end;
+	if (vma->vm_flags & (VM_IO|VM_HUGETLB|VM_PFNMAP|VM_RESERVED))
+		return 0;
+	/*
+	 * Migration allocates pages in the highest zone. If we cannot
+	 * do so then migration (at least from node to node) is not
+	 * possible.
+	 */
+	if (vma->vm_file &&
+		gfp_zone(mapping_gfp_mask(vma->vm_file->f_mapping))
+								< policy_zone)
+			return 0;
+	return 1;
 }
 
-static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud,
-		unsigned long addr, unsigned long end,
-		const nodemask_t *nodes, unsigned long flags,
-		void *private)
+struct mempol_walk_data {
+	struct vm_area_struct *vma;
+	const nodemask_t *nodes;
+	unsigned long flags;
+	void *private;
+};
+
+static int check_pte_entry(pte_t *pte, unsigned long addr,
+			   unsigned long end, struct mm_walk *walk)
 {
-	pmd_t *pmd;
-	unsigned long next;
+	struct mempol_walk_data *data = walk->private;
+	struct page *page;
+	int nid;
 
-	pmd = pmd_offset(pud, addr);
-	do {
-		next = pmd_addr_end(addr, end);
-		split_huge_page_pmd(vma->vm_mm, pmd);
-		if (pmd_none_or_trans_huge_or_clear_bad(pmd))
-			continue;
-		if (check_pte_range(vma, pmd, addr, next, nodes,
-				    flags, private))
-			return -EIO;
-	} while (pmd++, addr = next, addr != end);
-	return 0;
-}
+	if (!pte_present(*pte))
+		return 0;
 
-static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
-		unsigned long addr, unsigned long end,
-		const nodemask_t *nodes, unsigned long flags,
-		void *private)
-{
-	pud_t *pud;
-	unsigned long next;
+	page = vm_normal_page(data->vma, addr, *pte);
+	if (!page)
+		return 0;
 
-	pud = pud_offset(pgd, addr);
-	do {
-		next = pud_addr_end(addr, end);
-		if (pud_none_or_clear_bad(pud))
-			continue;
-		if (check_pmd_range(vma, pud, addr, next, nodes,
-				    flags, private))
-			return -EIO;
-	} while (pud++, addr = next, addr != end);
-	return 0;
-}
+	/*
+	 * vm_normal_page() filters out zero pages, but there might
+	 * still be PageReserved pages to skip, perhaps in a VDSO.
+	 * And we cannot move PageKsm pages sensibly or safely yet.
+	 */
+	if (PageReserved(page) || PageKsm(page))
+		return 0;
 
-static inline int check_pgd_range(struct vm_area_struct *vma,
-		unsigned long addr, unsigned long end,
-		const nodemask_t *nodes, unsigned long flags,
-		void *private)
-{
-	pgd_t *pgd;
-	unsigned long next;
+	nid = page_to_nid(page);
+	if (node_isset(nid, *data->nodes) == !!(data->flags & MPOL_MF_INVERT))
+		return 0;
 
-	pgd = pgd_offset(vma->vm_mm, addr);
-	do {
-		next = pgd_addr_end(addr, end);
-		if (pgd_none_or_clear_bad(pgd))
-			continue;
-		if (check_pud_range(vma, pgd, addr, next, nodes,
-				    flags, private))
-			return -EIO;
-	} while (pgd++, addr = next, addr != end);
-	return 0;
+	if (data->flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) {
+		migrate_page_add(page, data->private, data->flags);
+		return 0;
+	}
+
+	return -EIO;
 }
 
 /*
@@ -570,9 +549,18 @@ static struct vm_area_struct *
 check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
 		const nodemask_t *nodes, unsigned long flags, void *private)
 {
-	int err;
 	struct vm_area_struct *first, *vma, *prev;
-
+	struct mempol_walk_data data = {
+		.nodes = nodes,
+		.flags = flags,
+		.private = private,
+	};
+	struct mm_walk walk = {
+		.pte_entry = check_pte_entry,
+		.mm = mm,
+		.private = &data,
+	};
+	int err;
 
 	first = find_vma(mm, start);
 	if (!first)
@@ -595,8 +583,8 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
 				endvma = end;
 			if (vma->vm_start > start)
 				start = vma->vm_start;
-			err = check_pgd_range(vma, start, endvma, nodes,
-						flags, private);
+			data.vma = vma;
+			err = walk_page_range(start, endvma, &walk);
 			if (err) {
 				first = ERR_PTR(err);
 				break;
@@ -1097,102 +1085,211 @@ static struct page *new_vma_page(struct page *page, unsigned long private, int *
 }
 #endif
 
-static long do_mbind(unsigned long start, unsigned long len,
-		     unsigned short mode, unsigned short mode_flags,
-		     nodemask_t *nmask, unsigned long flags)
+long mpol_do_mbind(unsigned long start, unsigned long len,
+		struct mempolicy *new, unsigned long mode,
+		nodemask_t *nmask, unsigned long flags)
 {
-	struct vm_area_struct *vma;
 	struct mm_struct *mm = current->mm;
-	struct mempolicy *new;
+	struct vm_area_struct *vma;
+	int err, nr_failed = 0;
 	unsigned long end;
-	int err;
 	LIST_HEAD(pagelist);
 
-	if (flags & ~(unsigned long)(MPOL_MF_STRICT |
-				     MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
-		return -EINVAL;
-	if ((flags & MPOL_MF_MOVE_ALL) && !capable(CAP_SYS_NICE))
-		return -EPERM;
-
-	if (start & ~PAGE_MASK)
-		return -EINVAL;
-
-	if (mode == MPOL_DEFAULT)
-		flags &= ~MPOL_MF_STRICT;
-
 	len = (len + PAGE_SIZE - 1) & PAGE_MASK;
 	end = start + len;
 
-	if (end < start)
-		return -EINVAL;
-	if (end == start)
-		return 0;
-
-	new = mpol_new(mode, mode_flags, nmask);
-	if (IS_ERR(new))
-		return PTR_ERR(new);
-
-	/*
-	 * If we are using the default policy then operation
-	 * on discontinuous address spaces is okay after all
-	 */
-	if (!new)
-		flags |= MPOL_MF_DISCONTIG_OK;
+	if (end < start) {
+		err = -EINVAL;
+		goto mpol_out;
+	}
 
-	pr_debug("mbind %lx-%lx mode:%d flags:%d nodes:%lx\n",
-		 start, start + len, mode, mode_flags,
-		 nmask ? nodes_addr(*nmask)[0] : -1);
+	if (end == start) {
+		err = 0;
+		goto mpol_out;
+	}
 
 	if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) {
-
 		err = migrate_prep();
 		if (err)
 			goto mpol_out;
 	}
-	{
+
+	if (mode != MPOL_NOOP) {
 		NODEMASK_SCRATCH(scratch);
+		err = -ENOMEM;
 		if (scratch) {
-			down_write(&mm->mmap_sem);
 			task_lock(current);
 			err = mpol_set_nodemask(new, nmask, scratch);
 			task_unlock(current);
-			if (err)
-				up_write(&mm->mmap_sem);
-		} else
-			err = -ENOMEM;
+		}
 		NODEMASK_SCRATCH_FREE(scratch);
+		if (err)
+			goto mpol_out;
 	}
-	if (err)
-		goto mpol_out;
 
 	vma = check_range(mm, start, end, nmask,
 			  flags | MPOL_MF_INVERT, &pagelist);
 
-	err = PTR_ERR(vma);
-	if (!IS_ERR(vma)) {
-		int nr_failed = 0;
+	err = PTR_ERR(vma);	/* maybe ... */
+	if (IS_ERR(vma))
+		goto mpol_out_putback;
 
+	if (mode != MPOL_NOOP) {
 		err = mbind_range(mm, start, end, new);
+		if (err)
+			goto mpol_out_putback;
+	}
 
-		if (!list_empty(&pagelist)) {
+	if (!list_empty(&pagelist)) {
+		if (flags & MPOL_MF_LAZY)
+			nr_failed = migrate_pages_unmap_only(&pagelist);
+		else {
 			nr_failed = migrate_pages(&pagelist, new_vma_page,
-						(unsigned long)vma,
+					(unsigned long)vma,
 						false, MIGRATE_SYNC);
-			if (nr_failed)
-				putback_lru_pages(&pagelist);
 		}
+	}
 
-		if (!err && nr_failed && (flags & MPOL_MF_STRICT))
-			err = -EIO;
-	} else
-		putback_lru_pages(&pagelist);
+	if (nr_failed && (flags & MPOL_MF_STRICT))
+		err = -EIO;
+
+mpol_out_putback:
+	putback_lru_pages(&pagelist);
+
+mpol_out:
+	return err;
+}
+
+static long do_mbind(unsigned long start, unsigned long len,
+		     unsigned short mode, unsigned short mode_flags,
+		     nodemask_t *nmask, unsigned long flags)
+{
+	struct mm_struct *mm = current->mm;
+	struct mempolicy *new = NULL;
+	int err;
+
+	if (flags & ~(unsigned long)MPOL_MF_VALID)
+		return -EINVAL;
+	if ((flags & MPOL_MF_MOVE_ALL) && !capable(CAP_SYS_NICE))
+		return -EPERM;
+
+	if (start & ~PAGE_MASK)
+		return -EINVAL;
+
+	if (mode == MPOL_DEFAULT || mode == MPOL_NOOP)
+		flags &= ~MPOL_MF_STRICT;
+
+	if (mode != MPOL_NOOP) {
+		new = mpol_new(mode, mode_flags, nmask);
+		if (IS_ERR(new))
+			return PTR_ERR(new);
+
+		if (flags & MPOL_MF_LAZY)
+			new->flags |= MPOL_F_MOF;
+	}
+	/*
+	 * If we are using the default policy then operation
+	 * on discontinuous address spaces is okay after all
+	 */
+	if (!new)
+		flags |= MPOL_MF_DISCONTIG_OK;
+
+	pr_debug("mbind %lx-%lx mode:%d flags:%d nodes:%lx\n",
+		 start, start + len, mode, mode_flags,
+		 nmask ? nodes_addr(*nmask)[0] : -1);
 
+	down_write(&mm->mmap_sem);
+	err = mpol_do_mbind(start, len, new, mode, nmask, flags);
 	up_write(&mm->mmap_sem);
- mpol_out:
 	mpol_put(new);
+
 	return err;
 }
 
+static nodemask_t mpol_node_mask(struct mempolicy *pol, int node)
+{
+	if (pol->mode == MPOL_PREFERRED) {
+		if (pol->flags & MPOL_F_LOCAL)
+			return nodemask_of_node(node);
+
+		return nodemask_of_node(pol->v.preferred_node);
+	}
+
+	return pol->v.nodes;
+}
+
+void lazy_migrate_vma(struct vm_area_struct *vma, int node)
+{
+	struct mempolicy *pol = NULL;
+	struct mempol_walk_data data;
+	struct mm_walk walk;
+	LIST_HEAD(pagelist);
+	nodemask_t nmask;
+
+	if (vma->vm_file)
+		return;
+
+	if (!vma_migratable(vma))
+		return;
+
+	/*
+	 * Obtain a more-or-less correct nodemask to find which pages we need
+	 * to unmap so that MoF can put them right again.
+	 *
+	 * Not quite correct for INTERLEAVE, that would need us doing
+	 * offset_il_node() from check_pte_entry().
+	 *
+	 * Also not quite correct for task policies since we don't have a task,
+	 * approximate by having @node function as local / task-home-node.
+	 */
+
+	if (vma->vm_ops && vma->vm_ops->get_policy)
+	        pol = vma->vm_ops->get_policy(vma, vma->vm_start);
+	else if (vma->vm_policy)
+		pol = vma->vm_policy;
+
+	if (pol) {
+		nmask = mpol_node_mask(pol, node);
+		mpol_cond_put(pol);
+
+		/*
+		 * If there's an explicit policy that doesn't support MoF, skip
+		 * this vma, there's nothing we can do about that.
+		 */
+		if (!(pol->flags & MPOL_F_MOF))
+			return;
+	} else
+		nmask = nodemask_of_node(node);
+
+	data = (struct mempol_walk_data){
+		.nodes = &nmask,
+		.flags = MPOL_MF_MOVE | MPOL_MF_INVERT, /* move all pages not in set */
+		.private = &pagelist,
+		.vma = vma,
+	};
+
+	walk = (struct mm_walk){
+		.pte_entry = check_pte_entry,
+		.mm = vma->vm_mm,
+		.private = &data,
+	};
+
+	if (!walk_page_range(vma->vm_start, vma->vm_end, &walk))
+		migrate_pages_unmap_only(&pagelist);
+
+	putback_lru_pages(&pagelist);
+}
+
+void lazy_migrate_process(struct mm_struct *mm, int node)
+{
+	struct vm_area_struct *vma;
+
+	down_read(&mm->mmap_sem);
+	for (vma = mm->mmap; vma; vma = vma->vm_next)
+		lazy_migrate_vma(vma, node);
+	up_read(&mm->mmap_sem);
+}
+
 /*
  * User space interface with variable sized bitmaps for nodelists.
  */
@@ -1522,7 +1619,7 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
 struct mempolicy *get_vma_policy(struct task_struct *task,
 		struct vm_area_struct *vma, unsigned long addr)
 {
-	struct mempolicy *pol = task->mempolicy;
+	struct mempolicy *pol = get_task_policy(task);
 
 	if (vma) {
 		if (vma->vm_ops && vma->vm_ops->get_policy) {
@@ -1553,11 +1650,29 @@ static nodemask_t *policy_nodemask(gfp_t gfp, struct mempolicy *policy)
 	return NULL;
 }
 
+/* Do dynamic interleaving for a process */
+static unsigned interleave_nodes(struct mempolicy *policy)
+{
+	unsigned nid, next;
+	struct task_struct *me = current;
+
+	nid = me->il_next;
+	next = next_node(nid, policy->v.nodes);
+	if (next >= MAX_NUMNODES)
+		next = first_node(policy->v.nodes);
+	if (next < MAX_NUMNODES)
+		me->il_next = next;
+	return nid;
+}
+
 /* Return a zonelist indicated by gfp for node representing a mempolicy */
 static struct zonelist *policy_zonelist(gfp_t gfp, struct mempolicy *policy,
 	int nd)
 {
 	switch (policy->mode) {
+	case MPOL_INTERLEAVE:
+		nd = interleave_nodes(policy);
+		break;
 	case MPOL_PREFERRED:
 		if (!(policy->flags & MPOL_F_LOCAL))
 			nd = policy->v.preferred_node;
@@ -1579,21 +1694,6 @@ static struct zonelist *policy_zonelist(gfp_t gfp, struct mempolicy *policy,
 	return node_zonelist(nd, gfp);
 }
 
-/* Do dynamic interleaving for a process */
-static unsigned interleave_nodes(struct mempolicy *policy)
-{
-	unsigned nid, next;
-	struct task_struct *me = current;
-
-	nid = me->il_next;
-	next = next_node(nid, policy->v.nodes);
-	if (next >= MAX_NUMNODES)
-		next = first_node(policy->v.nodes);
-	if (next < MAX_NUMNODES)
-		me->il_next = next;
-	return nid;
-}
-
 /*
  * Depending on the memory policy provide a node from which to allocate the
  * next slab entry.
@@ -1602,8 +1702,14 @@ static unsigned interleave_nodes(struct mempolicy *policy)
  * task can change it's policy.  The system default policy requires no
  * such protection.
  */
-unsigned slab_node(struct mempolicy *policy)
+unsigned slab_node(void)
 {
+	struct mempolicy *policy;
+
+	if (in_interrupt())
+		return numa_node_id();
+
+	policy = current->mempolicy;
 	if (!policy || policy->flags & MPOL_F_LOCAL)
 		return numa_node_id();
 
@@ -1708,7 +1814,7 @@ int node_random(const nodemask_t *maskp)
  * If the effective policy is 'BIND, returns a pointer to the mempolicy's
  * @nodemask for filtering the zonelist.
  *
- * Must be protected by get_mems_allowed()
+ * Must be protected by read_mems_allowed_begin()
  */
 struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr,
 				gfp_t gfp_flags, struct mempolicy **mpol,
@@ -1824,21 +1930,6 @@ out:
 	return ret;
 }
 
-/* Allocate a page in interleaved policy.
-   Own path because it needs to do special accounting. */
-static struct page *alloc_page_interleave(gfp_t gfp, unsigned order,
-					unsigned nid)
-{
-	struct zonelist *zl;
-	struct page *page;
-
-	zl = node_zonelist(nid, gfp);
-	page = __alloc_pages(gfp, order, zl);
-	if (page && page_zone(page) == zonelist_zone(&zl->_zonerefs[0]))
-		inc_zone_page_state(page, NUMA_INTERLEAVE_HIT);
-	return page;
-}
-
 /**
  * 	alloc_pages_vma	- Allocate a page for a VMA.
  *
@@ -1873,19 +1964,8 @@ alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
 
 retry_cpuset:
 	pol = get_vma_policy(current, vma, addr);
-	cpuset_mems_cookie = get_mems_allowed();
-
-	if (unlikely(pol->mode == MPOL_INTERLEAVE)) {
-		unsigned nid;
+	cpuset_mems_cookie = read_mems_allowed_begin();
 
-		nid = interleave_nid(pol, vma, addr, PAGE_SHIFT + order);
-		mpol_cond_put(pol);
-		page = alloc_page_interleave(gfp, order, nid);
-		if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
-			goto retry_cpuset;
-
-		return page;
-	}
 	zl = policy_zonelist(gfp, pol, node);
 	if (unlikely(mpol_needs_cond_ref(pol))) {
 		/*
@@ -1894,7 +1974,7 @@ retry_cpuset:
 		struct page *page =  __alloc_pages_nodemask(gfp, order,
 						zl, policy_nodemask(gfp, pol));
 		__mpol_put(pol);
-		if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+		if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
 			goto retry_cpuset;
 		return page;
 	}
@@ -1903,7 +1983,7 @@ retry_cpuset:
 	 */
 	page = __alloc_pages_nodemask(gfp, order, zl,
 				      policy_nodemask(gfp, pol));
-	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+	if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
 		goto retry_cpuset;
 	return page;
 }
@@ -1929,7 +2009,7 @@ retry_cpuset:
  */
 struct page *alloc_pages_current(gfp_t gfp, unsigned order)
 {
-	struct mempolicy *pol = current->mempolicy;
+	struct mempolicy *pol = get_task_policy(current);
 	struct page *page;
 	unsigned int cpuset_mems_cookie;
 
@@ -1937,20 +2017,17 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order)
 		pol = &default_policy;
 
 retry_cpuset:
-	cpuset_mems_cookie = get_mems_allowed();
+	cpuset_mems_cookie = read_mems_allowed_begin();
 
 	/*
 	 * No reference counting needed for current->mempolicy
 	 * nor system default_policy
 	 */
-	if (pol->mode == MPOL_INTERLEAVE)
-		page = alloc_page_interleave(gfp, order, interleave_nodes(pol));
-	else
-		page = __alloc_pages_nodemask(gfp, order,
-				policy_zonelist(gfp, pol, numa_node_id()),
-				policy_nodemask(gfp, pol));
+	page = __alloc_pages_nodemask(gfp, order,
+			policy_zonelist(gfp, pol, numa_node_id()),
+			policy_nodemask(gfp, pol));
 
-	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+	if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
 		goto retry_cpuset;
 
 	return page;
@@ -1997,6 +2074,22 @@ struct mempolicy *__mpol_dup(struct mempolicy *old)
 	return new;
 }
 
+int vma_dup_policy(struct vm_area_struct *new, struct vm_area_struct *old)
+{
+	struct mempolicy *mpol;
+
+	mpol = mpol_dup(vma_policy(old));
+	if (IS_ERR(mpol))
+		return PTR_ERR(mpol);
+	vma_set_policy(new, mpol);
+	return 0;
+}
+
+void vma_put_policy(struct vm_area_struct *vma)
+{
+	mpol_put(vma_policy(vma));
+}
+
 /*
  * If *frompol needs [has] an extra ref, copy *frompol to *tompol ,
  * eliminate the * MPOL_F_* flags that require conditional ref and
@@ -2129,6 +2222,82 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx)
 	return pol;
 }
 
+/**
+ * mpol_misplaced - check whether current page node is valid in policy
+ *
+ * @page   - page to be checked
+ * @vma    - vm area where page mapped
+ * @addr   - virtual address where page mapped
+ *
+ * Lookup current policy node id for vma,addr and "compare to" page's
+ * node id.
+ *
+ * Returns:
+ * 	-1	- not misplaced, page is in the right node
+ * 	node	- node id where the page should be
+ *
+ * Policy determination "mimics" alloc_page_vma().
+ * Called from fault path where we know the vma and faulting address.
+ */
+int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long addr)
+{
+	struct mempolicy *pol;
+	struct zone *zone;
+	int curnid = page_to_nid(page);
+	unsigned long pgoff;
+	int polnid = -1;
+	int ret = -1;
+
+	BUG_ON(!vma);
+
+	pol = get_vma_policy(current, vma, addr);
+	if (!(pol->flags & MPOL_F_MOF))
+		goto out;
+
+	switch (pol->mode) {
+	case MPOL_INTERLEAVE:
+		BUG_ON(addr >= vma->vm_end);
+		BUG_ON(addr < vma->vm_start);
+
+		pgoff = vma->vm_pgoff;
+		pgoff += (addr - vma->vm_start) >> PAGE_SHIFT;
+		polnid = offset_il_node(pol, vma, pgoff);
+		break;
+
+	case MPOL_PREFERRED:
+		if (pol->flags & MPOL_F_LOCAL)
+			polnid = numa_node_id();
+		else
+			polnid = pol->v.preferred_node;
+		break;
+
+	case MPOL_BIND:
+		/*
+		 * allows binding to multiple nodes.
+		 * use current page if in policy nodemask,
+		 * else select nearest allowed node, if any.
+		 * If no allowed nodes, use current [!misplaced].
+		 */
+		if (node_isset(curnid, pol->v.nodes))
+			goto out;
+		(void)first_zones_zonelist(
+				node_zonelist(numa_node_id(), GFP_HIGHUSER),
+				gfp_zone(GFP_HIGHUSER),
+				&pol->v.nodes, &zone);
+		polnid = zone->node;
+		break;
+
+	default:
+		BUG();
+	}
+	if (curnid != polnid)
+		ret = polnid;
+out:
+	mpol_cond_put(pol);
+
+	return ret;
+}
+
 static void sp_delete(struct shared_policy *sp, struct sp_node *n)
 {
 	pr_debug("deleting %lx-l%lx\n", n->start, n->end);
@@ -2308,6 +2477,15 @@ void __init numa_policy_init(void)
 				     sizeof(struct sp_node),
 				     0, SLAB_PANIC, NULL);
 
+	for_each_node(nid) {
+		preferred_node_policy[nid] = (struct mempolicy) {
+			.refcnt = ATOMIC_INIT(1),
+			.mode = MPOL_PREFERRED,
+			.flags = MPOL_F_MOF,
+			.v = { .preferred_node = nid, },
+		};
+	}
+
 	/*
 	 * Set interleaving policy for system init. Interleaving is only
 	 * enabled across suitably sized nodes (default is >= 16MB), or
@@ -2350,7 +2528,6 @@ void numa_default_policy(void)
  * "local" is pseudo-policy:  MPOL_PREFERRED with MPOL_F_LOCAL flag
  * Used only for mpol_parse_str() and mpol_to_str()
  */
-#define MPOL_LOCAL MPOL_MAX
 static const char * const policy_modes[] =
 {
 	[MPOL_DEFAULT]    = "default",
@@ -2403,12 +2580,12 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context)
 	if (flags)
 		*flags++ = '\0';	/* terminate mode string */
 
-	for (mode = 0; mode <= MPOL_LOCAL; mode++) {
+	for (mode = 0; mode < MPOL_MAX; mode++) {
 		if (!strcmp(str, policy_modes[mode])) {
 			break;
 		}
 	}
-	if (mode > MPOL_LOCAL)
+	if (mode >= MPOL_MAX)
 		goto out;
 
 	switch (mode) {
diff --git a/mm/migrate.c b/mm/migrate.c
index be26d5c..8137aea 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -33,6 +33,7 @@
 #include <linux/memcontrol.h>
 #include <linux/syscalls.h>
 #include <linux/hugetlb.h>
+#include <linux/hugetlb_cgroup.h>
 #include <linux/gfp.h>
 
 #include <asm/tlbflush.h>
@@ -294,6 +295,10 @@ static int migrate_page_move_mapping(struct address_space *mapping,
  					page_index(page));
 
 	expected_count = 2 + page_has_private(page);
+	if (mode == MIGRATE_FAULT) {
+		expected_count++;
+		mode = MIGRATE_ASYNC; /* don't bother blocking for MoF */
+	}
 	if (page_count(page) != expected_count ||
 		radix_tree_deref_slot_protected(pslot, &mapping->tree_lock) != page) {
 		spin_unlock_irq(&mapping->tree_lock);
@@ -805,7 +810,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
 	}
 
 	/* Establish migration ptes or remove ptes */
-	try_to_unmap(page, TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+	try_to_unmap(page, TTU_MIGRATE_DIRECT|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
 
 skip_unmap:
 	if (!page_mapped(page))
@@ -921,7 +926,7 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
 	if (PageAnon(hpage))
 		anon_vma = page_get_anon_vma(hpage);
 
-	try_to_unmap(hpage, TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+	try_to_unmap(hpage, TTU_MIGRATE_DIRECT|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
 
 	if (!page_mapped(hpage))
 		rc = move_to_new_page(new_hpage, hpage, 1, mode);
@@ -931,16 +936,13 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
 
 	if (anon_vma)
 		put_anon_vma(anon_vma);
-	unlock_page(hpage);
 
-out:
-	if (rc != -EAGAIN) {
-		list_del(&hpage->lru);
-		put_page(hpage);
-	}
+	if (!rc)
+		hugetlb_cgroup_migrate(hpage, new_hpage);
 
+	unlock_page(hpage);
+out:
 	put_page(new_hpage);
-
 	if (result) {
 		if (rc)
 			*result = rc;
@@ -951,6 +953,98 @@ out:
 }
 
 /*
+ * Lazy migration:  just unmap pages, moving anon pages to swap cache, if
+ * necessary.  Migration will occur, if policy dictates, when a task faults
+ * an unmapped page back into its page table--i.e., on "first touch" after
+ * unmapping.  Note that migrate-on-fault only migrates pages whose mapping
+ * [e.g., file system] supplies a migratepage op, so we skip pages that
+ * wouldn't migrate on fault.
+ *
+ * Pages are placed back on the lru whether or not they were successfully
+ * unmapped.  Like migrate_pages().
+ *
+ * Unline migrate_pages(), this function is only called in the context of
+ * a task that is unmapping it's own pages while holding its map semaphore
+ * for write.
+ */
+int migrate_pages_unmap_only(struct list_head *pagelist)
+{
+	struct page *page;
+	struct page *page2;
+	int nr_failed = 0;
+	int nr_unmapped = 0;
+
+	list_for_each_entry_safe(page, page2, pagelist, lru) {
+		int ret;
+
+		cond_resched();
+
+		/*
+		 * Give up easily.  We ARE being lazy.
+		 */
+		if (page_count(page) == 1)
+			goto next;
+
+		if (unlikely(PageTransHuge(page)))
+			if (unlikely(split_huge_page(page)))
+				goto next;
+
+		if (!trylock_page(page))
+			goto next;
+
+		if (PageKsm(page) || PageWriteback(page))
+			goto unlock;
+
+		/*
+		 * see comments in unmap_and_move()
+		 */
+		if (!page->mapping)
+			goto unlock;
+
+		if (PageAnon(page)) {
+			if (!PageSwapCache(page) && !add_to_swap(page)) {
+				nr_failed++;
+				goto unlock;
+			}
+		} else {
+			struct address_space *mapping = page_mapping(page);
+			BUG_ON(!mapping);
+			if (!mapping->a_ops->migratepage)
+				goto unlock;
+		}
+
+		ret = try_to_unmap(page,
+	             TTU_MIGRATE_DEFERRED|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+		if (ret != SWAP_SUCCESS || page_mapped(page))
+			nr_failed++;
+		else
+			nr_unmapped++;
+
+unlock:
+		unlock_page(page);
+next:
+		list_del(&page->lru);
+		dec_zone_page_state(page, NR_ISOLATED_ANON +
+				page_is_file_cache(page));
+		putback_lru_page(page);
+
+	}
+
+	/*
+	 * Drain local per cpu pagevecs so fault path can find the the pages
+	 * on the lru.  If we got migrated during the loop above, we may
+	 * have left pages cached on other cpus.  But, we'll live with that
+	 * here to avoid lru_add_drain_all().
+	 * TODO:  mechanism to drain on only those cpus we've been
+	 *        scheduled on between two points--e.g., during the loop.
+	 */
+	if (nr_unmapped)
+		lru_add_drain();
+
+	return nr_failed;
+}
+
+/*
  * migrate_pages
  *
  * The function takes one list of pages to migrate and a function
@@ -1016,48 +1110,32 @@ out:
 	return nr_failed + retry;
 }
 
-int migrate_huge_pages(struct list_head *from,
-		new_page_t get_new_page, unsigned long private, bool offlining,
-		enum migrate_mode mode)
+int migrate_huge_page(struct page *hpage, new_page_t get_new_page,
+		      unsigned long private, bool offlining,
+		      enum migrate_mode mode)
 {
-	int retry = 1;
-	int nr_failed = 0;
-	int pass = 0;
-	struct page *page;
-	struct page *page2;
-	int rc;
-
-	for (pass = 0; pass < 10 && retry; pass++) {
-		retry = 0;
-
-		list_for_each_entry_safe(page, page2, from, lru) {
+	int pass, rc;
+
+	for (pass = 0; pass < 10; pass++) {
+		rc = unmap_and_move_huge_page(get_new_page,
+					      private, hpage, pass > 2, offlining,
+					      mode);
+		switch (rc) {
+		case -ENOMEM:
+			goto out;
+		case -EAGAIN:
+			/* try again */
 			cond_resched();
-
-			rc = unmap_and_move_huge_page(get_new_page,
-					private, page, pass > 2, offlining,
-					mode);
-
-			switch(rc) {
-			case -ENOMEM:
-				goto out;
-			case -EAGAIN:
-				retry++;
-				break;
-			case 0:
-				break;
-			default:
-				/* Permanent failure */
-				nr_failed++;
-				break;
-			}
+			break;
+		case 0:
+			goto out;
+		default:
+			rc = -EIO;
+			goto out;
 		}
 	}
-	rc = 0;
 out:
-	if (rc)
-		return rc;
-
-	return nr_failed + retry;
+	return rc;
 }
 
 #ifdef CONFIG_NUMA
@@ -1428,4 +1506,128 @@ int migrate_vmas(struct mm_struct *mm, const nodemask_t *to,
  	}
  	return err;
 }
-#endif
+
+/*
+ * Attempt to migrate a misplaced page to the specified destination
+ * node.  Page is already unmapped, up to date and locked by caller.
+ * Anon pages are in the swap cache.  Page's mapping has a migratepage aop.
+ *
+ * page refs on entry/exit:  cache + fault path [+ bufs]
+ */
+struct page *
+migrate_misplaced_page(struct page *page, struct mm_struct *mm, int node)
+{
+	struct page *oldpage = page, *newpage;
+	struct address_space *mapping = page_mapping(page);
+	struct mem_cgroup *mcg;
+	unsigned int gfp;
+	int rc = 0;
+	int charge = -ENOMEM;
+
+	VM_BUG_ON(!PageLocked(page));
+	VM_BUG_ON(page_mapcount(page));
+	VM_BUG_ON(PageAnon(page) && !PageSwapCache(page));
+	VM_BUG_ON(!mapping || !mapping->a_ops->migratepage);
+
+	/*
+	 * remove old page from LRU so it can't be found while migrating
+	 * except thru' the cache by other faulting tasks who will
+	 * block behind my lock.
+	 */
+	if (isolate_lru_page(page))	/* incrs page count on success */
+		goto out_nolru;	/* we lost */
+
+	/*
+	 * Never wait for allocations just to migrate on fault,
+	 * but don't dip into reserves.
+	 * And, only accept pages from specified node.
+	 * No sense migrating to a different "misplaced" page!
+	 */
+	gfp = (unsigned int)mapping_gfp_mask(mapping) & ~__GFP_WAIT;
+	gfp |= __GFP_NOMEMALLOC | GFP_THISNODE ;
+
+	newpage = alloc_pages_node(node, gfp, 0);
+	if (!newpage)
+		goto out;	/* give up */
+
+	/*
+	 * can't just lock_page() -- "might sleep" in atomic context
+	 */
+	if (!trylock_page(newpage))
+		BUG();		/* new page should be unlocked!!! */
+
+	// XXX hnaz, is this right?
+	charge = mem_cgroup_prepare_migration(page, newpage, &mcg, gfp);
+	if (charge == -ENOMEM) {
+		rc = charge;
+		goto out;
+	}
+
+	newpage->index = page->index;
+	newpage->mapping = page->mapping;
+	if (PageSwapBacked(page))		/* like move_to_new_page() */
+		SetPageSwapBacked(newpage);
+
+	/*
+	 * migrate a_op transfers cache [+ buf] refs
+	 */
+	rc = mapping->a_ops->migratepage(mapping, newpage, page, MIGRATE_FAULT);
+	if (!rc) {
+		get_page(newpage);	/* add isolate_lru_page ref */
+		put_page(page);		/* drop       "          "  */
+
+		unlock_page(page);
+
+		page = newpage;
+	}
+
+out:
+	if (!charge)
+		mem_cgroup_end_migration(mcg, oldpage, newpage, !rc);
+
+       if (oldpage != page)
+               put_page(oldpage);
+
+	if (rc) {
+		unlock_page(newpage);
+		__free_page(newpage);
+	}
+
+	putback_lru_page(page);		/* ultimately, drops a page ref */
+
+out_nolru:
+	return page;			/* locked, to complete fault */
+}
+
+/*
+ * Called in fault path, if migrate_on_fault_enabled(current) for a page
+ * found in the cache, page is locked, and page_mapping(page) != NULL;
+ * We check for page uptodate here because we want to be able to do any
+ * needed migration before grabbing the page table lock.  In the anon fault
+ * path, PageUptodate() isn't checked until after locking the page table.
+ *
+ * For migrate on fault, we only migrate pages whose mapping has a
+ * migratepage op.  The fallback path requires writing out the page and
+ * reading it back in.  That sort of defeats the purpose of
+ * migrate-on-fault [performance].  So, we don't even bother to check
+ * for misplacment unless the op is present.  Of course, this is an extra
+ * check in the fault path for pages we care about :-(
+ */
+struct page *check_migrate_misplaced_page(struct page *page,
+		struct vm_area_struct *vma, unsigned long address)
+{
+	int node;
+
+	if (page_mapcount(page) || PageWriteback(page) ||
+			unlikely(!PageUptodate(page))  ||
+			!page_mapping(page)->a_ops->migratepage)
+		return page;
+
+	node = mpol_misplaced(page, vma, address);
+	if (node == -1)
+		return page;
+
+	return migrate_misplaced_page(page, vma->vm_mm, node);
+}
+
+#endif /* CONFIG_NUMA */
diff --git a/mm/mmap.c b/mm/mmap.c
index 3edfcdf..e7fd6c7 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -236,7 +236,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
 		if (vma->vm_flags & VM_EXECUTABLE)
 			removed_exe_file_vma(vma->vm_mm);
 	}
-	mpol_put(vma_policy(vma));
+	vma_put_policy(vma);
 	kmem_cache_free(vm_area_cachep, vma);
 	return next;
 }
@@ -642,7 +642,7 @@ again:			remove_next = 1 + (end > next->vm_end);
 		if (next->anon_vma)
 			anon_vma_merge(vma, next);
 		mm->map_count--;
-		mpol_put(vma_policy(next));
+		vma_put_policy(next);
 		kmem_cache_free(vm_area_cachep, next);
 		/*
 		 * In mprotect's case 6 (see comments on vma_merge),
@@ -943,6 +943,8 @@ void vm_stat_account(struct mm_struct *mm, unsigned long flags,
 	const unsigned long stack_flags
 		= VM_STACK_FLAGS & (VM_GROWSUP|VM_GROWSDOWN);
 
+	mm->total_vm += pages;
+
 	if (file) {
 		mm->shared_vm += pages;
 		if ((flags & (VM_EXEC|VM_WRITE)) == VM_EXEC)
@@ -1347,7 +1349,6 @@ munmap_back:
 out:
 	perf_event_mmap(vma);
 
-	mm->total_vm += len >> PAGE_SHIFT;
 	vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT);
 	if (vm_flags & VM_LOCKED) {
 		if (!mlock_vma_pages_range(vma, addr, addr + len))
@@ -1707,7 +1708,6 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
 		return -ENOMEM;
 
 	/* Ok, everything looks good - let it rip */
-	mm->total_vm += grow;
 	if (vma->vm_flags & VM_LOCKED)
 		mm->locked_vm += grow;
 	vm_stat_account(mm, vma->vm_flags, vma->vm_file, grow);
@@ -1889,7 +1889,6 @@ static void remove_vma_list(struct mm_struct *mm, struct vm_area_struct *vma)
 
 		if (vma->vm_flags & VM_ACCOUNT)
 			nr_accounted += nrpages;
-		mm->total_vm -= nrpages;
 		vm_stat_account(mm, vma->vm_flags, vma->vm_file, -nrpages);
 		vma = remove_vma(vma);
 	} while (vma);
@@ -1957,7 +1956,6 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma,
 static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
 	      unsigned long addr, int new_below)
 {
-	struct mempolicy *pol;
 	struct vm_area_struct *new;
 	int err = -ENOMEM;
 
@@ -1981,12 +1979,9 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
 		new->vm_pgoff += ((addr - vma->vm_start) >> PAGE_SHIFT);
 	}
 
-	pol = mpol_dup(vma_policy(vma));
-	if (IS_ERR(pol)) {
-		err = PTR_ERR(pol);
+	err = vma_dup_policy(new, vma);
+	if (err)
 		goto out_free_vma;
-	}
-	vma_set_policy(new, pol);
 
 	if (anon_vma_clone(new, vma))
 		goto out_free_mpol;
@@ -2020,7 +2015,7 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
 	}
 	unlink_anon_vmas(new);
  out_free_mpol:
-	mpol_put(pol);
+	vma_put_policy(new);
  out_free_vma:
 	kmem_cache_free(vm_area_cachep, new);
  out_err:
@@ -2364,7 +2359,6 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
 	struct mm_struct *mm = vma->vm_mm;
 	struct vm_area_struct *new_vma, *prev;
 	struct rb_node **rb_link, *rb_parent;
-	struct mempolicy *pol;
 	bool faulted_in_anon_vma = true;
 
 	/*
@@ -2405,13 +2399,11 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
 		new_vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
 		if (new_vma) {
 			*new_vma = *vma;
-			pol = mpol_dup(vma_policy(vma));
-			if (IS_ERR(pol))
+			if (vma_dup_policy(new_vma, vma))
 				goto out_free_vma;
 			INIT_LIST_HEAD(&new_vma->anon_vma_chain);
 			if (anon_vma_clone(new_vma, vma))
 				goto out_free_mempol;
-			vma_set_policy(new_vma, pol);
 			new_vma->vm_start = addr;
 			new_vma->vm_end = addr + len;
 			new_vma->vm_pgoff = pgoff;
@@ -2432,7 +2424,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
 	return new_vma;
 
  out_free_mempol:
-	mpol_put(pol);
+	vma_put_policy(new_vma);
  out_free_vma:
 	kmem_cache_free(vm_area_cachep, new_vma);
 	return NULL;
diff --git a/mm/mremap.c b/mm/mremap.c
index 21fed20..cc06d0e 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -260,7 +260,6 @@ static unsigned long move_vma(struct vm_area_struct *vma,
 	 * If this were a serious issue, we'd add a flag to do_munmap().
 	 */
 	hiwater_vm = mm->hiwater_vm;
-	mm->total_vm += new_len >> PAGE_SHIFT;
 	vm_stat_account(mm, vma->vm_flags, vma->vm_file, new_len>>PAGE_SHIFT);
 
 	if (do_munmap(mm, old_addr, old_len) < 0) {
@@ -497,7 +496,6 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
 				goto out;
 			}
 
-			mm->total_vm += pages;
 			vm_stat_account(mm, vma->vm_flags, vma->vm_file, pages);
 			if (vma->vm_flags & VM_LOCKED) {
 				mm->locked_vm += pages;
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index ac300c9..e8ab3df 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -745,11 +745,11 @@ out:
 	read_unlock(&tasklist_lock);
 
 	/*
-	 * Give "p" a good chance of killing itself before we
-	 * retry to allocate memory unless "p" is current
+	 * Give the killed threads a good chance of exiting before trying to
+	 * allocate memory again.
 	 */
-	if (killed && !test_thread_flag(TIF_MEMDIE))
-		schedule_timeout_uninterruptible(1);
+	if (killed)
+		schedule_timeout_killable(1);
 }
 
 /*
@@ -764,6 +764,5 @@ void pagefault_out_of_memory(void)
 		out_of_memory(NULL, 0, 0, NULL, false);
 		clear_system_oom();
 	}
-	if (!test_thread_flag(TIF_MEMDIE))
-		schedule_timeout_uninterruptible(1);
+	schedule_timeout_killable(1);
 }
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 93d8d2f..e5363f3 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -34,6 +34,7 @@
 #include <linux/syscalls.h>
 #include <linux/buffer_head.h> /* __set_page_dirty_buffers */
 #include <linux/pagevec.h>
+#include <linux/timer.h>
 #include <trace/events/writeback.h>
 
 /*
@@ -135,7 +136,20 @@ unsigned long global_dirty_limit;
  * measured in page writeback completions.
  *
  */
-static struct prop_descriptor vm_completions;
+static struct fprop_global writeout_completions;
+
+static void writeout_period(unsigned long t);
+/* Timer for aging of writeout_completions */
+static struct timer_list writeout_period_timer =
+		TIMER_DEFERRED_INITIALIZER(writeout_period, 0, 0);
+static unsigned long writeout_period_time = 0;
+
+/*
+ * Length of period for aging writeout fractions of bdis. This is an
+ * arbitrarily chosen number. The longer the period, the slower fractions will
+ * reflect changes in current writeout rate.
+ */
+#define VM_COMPLETIONS_PERIOD_LEN (3*HZ)
 
 /*
  * Work out the current dirty-memory clamping and background writeout
@@ -322,34 +336,6 @@ bool zone_dirty_ok(struct zone *zone)
 	       zone_page_state(zone, NR_WRITEBACK) <= limit;
 }
 
-/*
- * couple the period to the dirty_ratio:
- *
- *   period/2 ~ roundup_pow_of_two(dirty limit)
- */
-static int calc_period_shift(void)
-{
-	unsigned long dirty_total;
-
-	if (vm_dirty_bytes)
-		dirty_total = vm_dirty_bytes / PAGE_SIZE;
-	else
-		dirty_total = (vm_dirty_ratio * global_dirtyable_memory()) /
-				100;
-	return 2 + ilog2(dirty_total - 1);
-}
-
-/*
- * update the period when the dirty threshold changes.
- */
-static void update_completion_period(void)
-{
-	int shift = calc_period_shift();
-	prop_change_shift(&vm_completions, shift);
-
-	writeback_set_ratelimit();
-}
-
 int dirty_background_ratio_handler(struct ctl_table *table, int write,
 		void __user *buffer, size_t *lenp,
 		loff_t *ppos)
@@ -383,7 +369,7 @@ int dirty_ratio_handler(struct ctl_table *table, int write,
 
 	ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 	if (ret == 0 && write && vm_dirty_ratio != old_ratio) {
-		update_completion_period();
+		writeback_set_ratelimit();
 		vm_dirty_bytes = 0;
 	}
 	return ret;
@@ -398,12 +384,21 @@ int dirty_bytes_handler(struct ctl_table *table, int write,
 
 	ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
 	if (ret == 0 && write && vm_dirty_bytes != old_bytes) {
-		update_completion_period();
+		writeback_set_ratelimit();
 		vm_dirty_ratio = 0;
 	}
 	return ret;
 }
 
+static unsigned long wp_next_time(unsigned long cur_time)
+{
+	cur_time += VM_COMPLETIONS_PERIOD_LEN;
+	/* 0 has a special meaning... */
+	if (!cur_time)
+		return 1;
+	return cur_time;
+}
+
 /*
  * Increment the BDI's writeout completion count and the global writeout
  * completion count. Called from test_clear_page_writeback().
@@ -411,8 +406,19 @@ int dirty_bytes_handler(struct ctl_table *table, int write,
 static inline void __bdi_writeout_inc(struct backing_dev_info *bdi)
 {
 	__inc_bdi_stat(bdi, BDI_WRITTEN);
-	__prop_inc_percpu_max(&vm_completions, &bdi->completions,
-			      bdi->max_prop_frac);
+	__fprop_inc_percpu_max(&writeout_completions, &bdi->completions,
+			       bdi->max_prop_frac);
+	/* First event after period switching was turned off? */
+	if (!unlikely(writeout_period_time)) {
+		/*
+		 * We can race with other __bdi_writeout_inc calls here but
+		 * it does not cause any harm since the resulting time when
+		 * timer will fire and what is in writeout_period_time will be
+		 * roughly the same.
+		 */
+		writeout_period_time = wp_next_time(jiffies);
+		mod_timer(&writeout_period_timer, writeout_period_time);
+	}
 }
 
 void bdi_writeout_inc(struct backing_dev_info *bdi)
@@ -431,11 +437,33 @@ EXPORT_SYMBOL_GPL(bdi_writeout_inc);
 static void bdi_writeout_fraction(struct backing_dev_info *bdi,
 		long *numerator, long *denominator)
 {
-	prop_fraction_percpu(&vm_completions, &bdi->completions,
+	fprop_fraction_percpu(&writeout_completions, &bdi->completions,
 				numerator, denominator);
 }
 
 /*
+ * On idle system, we can be called long after we scheduled because we use
+ * deferred timers so count with missed periods.
+ */
+static void writeout_period(unsigned long t)
+{
+	int miss_periods = (jiffies - writeout_period_time) /
+						 VM_COMPLETIONS_PERIOD_LEN;
+
+	if (fprop_new_period(&writeout_completions, miss_periods + 1)) {
+		writeout_period_time = wp_next_time(writeout_period_time +
+				miss_periods * VM_COMPLETIONS_PERIOD_LEN);
+		mod_timer(&writeout_period_timer, writeout_period_time);
+	} else {
+		/*
+		 * Aging has zeroed all fractions. Stop wasting CPU on period
+		 * updates.
+		 */
+		writeout_period_time = 0;
+	}
+}
+
+/*
  * bdi_min_ratio keeps the sum of the minimum dirty shares of all
  * registered backing devices, which, for obvious reasons, can not
  * exceed 100%.
@@ -475,7 +503,7 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned max_ratio)
 		ret = -EINVAL;
 	} else {
 		bdi->max_ratio = max_ratio;
-		bdi->max_prop_frac = (PROP_FRAC_BASE * max_ratio) / 100;
+		bdi->max_prop_frac = (FPROP_FRAC_BASE * max_ratio) / 100;
 	}
 	spin_unlock_bh(&bdi_lock);
 
@@ -918,7 +946,7 @@ static void bdi_update_dirty_ratelimit(struct backing_dev_info *bdi,
 	 *	bdi->dirty_ratelimit = balanced_dirty_ratelimit;
 	 *
 	 * However to get a more stable dirty_ratelimit, the below elaborated
-	 * code makes use of task_ratelimit to filter out sigular points and
+	 * code makes use of task_ratelimit to filter out singular points and
 	 * limit the step size.
 	 *
 	 * The below code essentially only uses the relative value of
@@ -941,7 +969,7 @@ static void bdi_update_dirty_ratelimit(struct backing_dev_info *bdi,
 	 * feel and care are stable dirty rate and small position error.
 	 *
 	 * |task_ratelimit - dirty_ratelimit| is used to limit the step size
-	 * and filter out the sigular points of balanced_dirty_ratelimit. Which
+	 * and filter out the singular points of balanced_dirty_ratelimit. Which
 	 * keeps jumping around randomly and can even leap far away at times
 	 * due to the small 200ms estimation period of dirty_rate (we want to
 	 * keep that period small to reduce time lags).
@@ -1606,13 +1634,10 @@ static struct notifier_block __cpuinitdata ratelimit_nb = {
  */
 void __init page_writeback_init(void)
 {
-	int shift;
-
 	writeback_set_ratelimit();
 	register_cpu_notifier(&ratelimit_nb);
 
-	shift = calc_period_shift();
-	prop_descriptor_init(&vm_completions, shift);
+	fprop_global_init(&writeout_completions);
 }
 
 /**
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 4403009..2c29b1c 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -219,9 +219,8 @@ EXPORT_SYMBOL(nr_online_nodes);
 
 int page_group_by_mobility_disabled __read_mostly;
 
-static void set_pageblock_migratetype(struct page *page, int migratetype)
+void set_pageblock_migratetype(struct page *page, int migratetype)
 {
-
 	if (unlikely(page_group_by_mobility_disabled))
 		migratetype = MIGRATE_UNMOVABLE;
 
@@ -364,8 +363,7 @@ static int destroy_compound_page(struct page *page, unsigned long order)
 	int nr_pages = 1 << order;
 	int bad = 0;
 
-	if (unlikely(compound_order(page) != order) ||
-	    unlikely(!PageHead(page))) {
+	if (unlikely(compound_order(page) != order)) {
 		bad_page(page);
 		bad++;
 	}
@@ -954,8 +952,8 @@ static int move_freepages(struct zone *zone,
 	return pages_moved;
 }
 
-static int move_freepages_block(struct zone *zone, struct page *page,
-				int migratetype)
+int move_freepages_block(struct zone *zone, struct page *page,
+			 int migratetype)
 {
 	unsigned long start_pfn, end_pfn;
 	struct page *start_page, *end_page;
@@ -1529,16 +1527,16 @@ static int __init setup_fail_page_alloc(char *str)
 }
 __setup("fail_page_alloc=", setup_fail_page_alloc);
 
-static int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
+static bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
 {
 	if (order < fail_page_alloc.min_order)
-		return 0;
+		return false;
 	if (gfp_mask & __GFP_NOFAIL)
-		return 0;
+		return false;
 	if (fail_page_alloc.ignore_gfp_highmem && (gfp_mask & __GFP_HIGHMEM))
-		return 0;
+		return false;
 	if (fail_page_alloc.ignore_gfp_wait && (gfp_mask & __GFP_WAIT))
-		return 0;
+		return false;
 
 	return should_fail(&fail_page_alloc.attr, 1 << order);
 }
@@ -1578,9 +1576,9 @@ late_initcall(fail_page_alloc_debugfs);
 
 #else /* CONFIG_FAIL_PAGE_ALLOC */
 
-static inline int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
+static inline bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
 {
-	return 0;
+	return false;
 }
 
 #endif /* CONFIG_FAIL_PAGE_ALLOC */
@@ -2498,7 +2496,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
 		return NULL;
 
 retry_cpuset:
-	cpuset_mems_cookie = get_mems_allowed();
+	cpuset_mems_cookie = read_mems_allowed_begin();
 
 	/* The preferred zone is used for statistics later */
 	first_zones_zonelist(zonelist, high_zoneidx,
@@ -2525,7 +2523,7 @@ out:
 	 * the mask is being updated. If a page allocation is about to fail,
 	 * check if the cpuset changed during allocation and if so, retry.
 	 */
-	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+	if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
 		goto retry_cpuset;
 
 	return page;
@@ -2747,9 +2745,9 @@ bool skip_free_areas_node(unsigned int flags, int nid)
 		goto out;
 
 	do {
-		cpuset_mems_cookie = get_mems_allowed();
+		cpuset_mems_cookie = read_mems_allowed_begin();
 		ret = !node_isset(nid, cpuset_current_mems_allowed);
-	} while (!put_mems_allowed(cpuset_mems_cookie));
+	} while (read_mems_allowed_retry(cpuset_mems_cookie));
 out:
 	return ret;
 }
@@ -5467,14 +5465,19 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
 			__clear_bit(bitidx + start_bitidx, bitmap);
 }
 
-/*
- * This is designed as sub function...plz see page_isolation.c also.
- * set/clear page block's type to be ISOLATE.
- * page allocater never alloc memory from ISOLATE block.
+/**
+ * __count_immobile_pages - Check pageblock for MIGRATE_UNMOVABLE type pages.
+ * @zone: Zone pages are in.
+ * @page: The first page in the pageblock.
+ * @count: The count of allowed MIGRATE_UNMOVABLE type pages.
+ *
+ * Count the number of MIGRATE_UNMOVABLE type pages in the pageblock
+ * starting with @page.  Returns true If the @zone is of ZONE_MOVABLE
+ * type or the pageblock is of MIGRATE_MOVABLE or MIGRATE_CMA type.
+ * If the number of MIGRATE_UNMOVABLE type pages inside the pageblock
+ * is higher than given by @count returns false, true otherwise.
  */
-
-static int
-__count_immobile_pages(struct zone *zone, struct page *page, int count)
+bool __count_immobile_pages(struct zone *zone, struct page *page, int count)
 {
 	unsigned long pfn, iter, found;
 	int mt;
@@ -5497,6 +5500,11 @@ __count_immobile_pages(struct zone *zone, struct page *page, int count)
 			continue;
 
 		page = pfn_to_page(check);
+
+		/* Do not deal with pageblocks that overlap zones */
+		if (page_zone(page) != zone)
+			return false;
+
 		if (!page_count(page)) {
 			if (PageBuddy(page))
 				iter += (1 << page_order(page)) - 1;
@@ -5651,7 +5659,7 @@ static int __alloc_contig_migrate_range(unsigned long start, unsigned long end)
 		.nr_migratepages = 0,
 		.order = -1,
 		.zone = page_zone(pfn_to_page(start)),
-		.sync = true,
+		.mode = COMPACT_SYNC,
 	};
 	INIT_LIST_HEAD(&cc.migratepages);
 
diff --git a/mm/rmap.c b/mm/rmap.c
index 0f3b7cd..2144160 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1299,13 +1299,13 @@ int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
 			 * pte. do_swap_page() will wait until the migration
 			 * pte is removed and then restart fault handling.
 			 */
-			BUG_ON(TTU_ACTION(flags) != TTU_MIGRATION);
+			BUG_ON(TTU_ACTION(flags) != TTU_MIGRATE_DIRECT);
 			entry = make_migration_entry(page, pte_write(pteval));
 		}
 		set_pte_at(mm, address, pte, swp_entry_to_pte(entry));
 		BUG_ON(pte_file(*pte));
 	} else if (IS_ENABLED(CONFIG_MIGRATION) &&
-		   (TTU_ACTION(flags) == TTU_MIGRATION)) {
+		   (TTU_ACTION(flags) == TTU_MIGRATE_DIRECT)) {
 		/* Establish migration entry for a file page */
 		swp_entry_t entry;
 		entry = make_migration_entry(page, pte_write(pteval));
@@ -1511,7 +1511,7 @@ static int try_to_unmap_anon(struct page *page, enum ttu_flags flags)
 		 * locking requirements of exec(), migration skips
 		 * temporary VMAs until after exec() completes.
 		 */
-		if (IS_ENABLED(CONFIG_MIGRATION) && (flags & TTU_MIGRATION) &&
+		if (IS_ENABLED(CONFIG_MIGRATION) && (flags & TTU_MIGRATE_DIRECT) &&
 				is_vma_temporary_stack(vma))
 			continue;
 
diff --git a/mm/shmem.c b/mm/shmem.c
index a15a466..ee1c5a2 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -938,9 +938,12 @@ static struct page *shmem_alloc_page(gfp_t gfp,
 	pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index);
 
 	/*
-	 * alloc_page_vma() will drop the shared policy reference
+	 * alloc_page_vma() will drop the shared policy reference.
+	 *
+	 * To avoid allocating all tmpfs pages on node 0, we fake up a virtual
+	 * address based on this file's predetermined preferred node.
 	 */
-	return alloc_page_vma(gfp, &pvma, 0);
+	return alloc_page_vma(gfp, &pvma, info->node_offset << PAGE_SHIFT);
 }
 #else /* !CONFIG_NUMA */
 #ifdef CONFIG_TMPFS
@@ -1374,6 +1377,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
 			inode->i_fop = &shmem_file_operations;
 			mpol_shared_policy_init(&info->policy,
 						 shmem_get_sbmpol(sbinfo));
+			info->node_offset = node_random(&node_online_map);
 			break;
 		case S_IFDIR:
 			inc_nlink(inode);
@@ -1594,6 +1598,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
 	struct splice_pipe_desc spd = {
 		.pages = pages,
 		.partial = partial,
+		.nr_pages_max = PIPE_DEF_BUFFERS,
 		.flags = flags,
 		.ops = &page_cache_pipe_buf_ops,
 		.spd_release = spd_release_page,
@@ -1682,7 +1687,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
 	if (spd.nr_pages)
 		error = splice_to_pipe(pipe, &spd);
 
-	splice_shrink_spd(pipe, &spd);
+	splice_shrink_spd(&spd);
 
 	if (error > 0) {
 		*ppos += error;
@@ -1953,7 +1958,7 @@ static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 }
 
 static int shmem_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		struct nameidata *nd)
+		bool excl)
 {
 	return shmem_mknod(dir, dentry, mode | S_IFREG, 0);
 }
diff --git a/mm/slab.c b/mm/slab.c
index e901a36..64c3d03 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -424,8 +424,8 @@ static void kmem_list3_init(struct kmem_list3 *parent)
  * cachep->obj_offset - BYTES_PER_WORD .. cachep->obj_offset - 1:
  * 		redzone word.
  * cachep->obj_offset: The real object.
- * cachep->buffer_size - 2* BYTES_PER_WORD: redzone word [BYTES_PER_WORD long]
- * cachep->buffer_size - 1* BYTES_PER_WORD: last caller address
+ * cachep->size - 2* BYTES_PER_WORD: redzone word [BYTES_PER_WORD long]
+ * cachep->size - 1* BYTES_PER_WORD: last caller address
  *					[BYTES_PER_WORD long]
  */
 static int obj_offset(struct kmem_cache *cachep)
@@ -433,11 +433,6 @@ static int obj_offset(struct kmem_cache *cachep)
 	return cachep->obj_offset;
 }
 
-static int obj_size(struct kmem_cache *cachep)
-{
-	return cachep->obj_size;
-}
-
 static unsigned long long *dbg_redzone1(struct kmem_cache *cachep, void *objp)
 {
 	BUG_ON(!(cachep->flags & SLAB_RED_ZONE));
@@ -449,23 +444,22 @@ static unsigned long long *dbg_redzone2(struct kmem_cache *cachep, void *objp)
 {
 	BUG_ON(!(cachep->flags & SLAB_RED_ZONE));
 	if (cachep->flags & SLAB_STORE_USER)
-		return (unsigned long long *)(objp + cachep->buffer_size -
+		return (unsigned long long *)(objp + cachep->size -
 					      sizeof(unsigned long long) -
 					      REDZONE_ALIGN);
-	return (unsigned long long *) (objp + cachep->buffer_size -
+	return (unsigned long long *) (objp + cachep->size -
 				       sizeof(unsigned long long));
 }
 
 static void **dbg_userword(struct kmem_cache *cachep, void *objp)
 {
 	BUG_ON(!(cachep->flags & SLAB_STORE_USER));
-	return (void **)(objp + cachep->buffer_size - BYTES_PER_WORD);
+	return (void **)(objp + cachep->size - BYTES_PER_WORD);
 }
 
 #else
 
 #define obj_offset(x)			0
-#define obj_size(cachep)		(cachep->buffer_size)
 #define dbg_redzone1(cachep, objp)	({BUG(); (unsigned long long *)NULL;})
 #define dbg_redzone2(cachep, objp)	({BUG(); (unsigned long long *)NULL;})
 #define dbg_userword(cachep, objp)	({BUG(); (void **)NULL;})
@@ -475,7 +469,7 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp)
 #ifdef CONFIG_TRACING
 size_t slab_buffer_size(struct kmem_cache *cachep)
 {
-	return cachep->buffer_size;
+	return cachep->size;
 }
 EXPORT_SYMBOL(slab_buffer_size);
 #endif
@@ -489,56 +483,37 @@ EXPORT_SYMBOL(slab_buffer_size);
 static int slab_max_order = SLAB_MAX_ORDER_LO;
 static bool slab_max_order_set __initdata;
 
-/*
- * Functions for storing/retrieving the cachep and or slab from the page
- * allocator.  These are used to find the slab an obj belongs to.  With kfree(),
- * these are used to find the cache which an obj belongs to.
- */
-static inline void page_set_cache(struct page *page, struct kmem_cache *cache)
-{
-	page->lru.next = (struct list_head *)cache;
-}
-
 static inline struct kmem_cache *page_get_cache(struct page *page)
 {
 	page = compound_head(page);
 	BUG_ON(!PageSlab(page));
-	return (struct kmem_cache *)page->lru.next;
-}
-
-static inline void page_set_slab(struct page *page, struct slab *slab)
-{
-	page->lru.prev = (struct list_head *)slab;
-}
-
-static inline struct slab *page_get_slab(struct page *page)
-{
-	BUG_ON(!PageSlab(page));
-	return (struct slab *)page->lru.prev;
+	return page->slab_cache;
 }
 
 static inline struct kmem_cache *virt_to_cache(const void *obj)
 {
 	struct page *page = virt_to_head_page(obj);
-	return page_get_cache(page);
+	return page->slab_cache;
 }
 
 static inline struct slab *virt_to_slab(const void *obj)
 {
 	struct page *page = virt_to_head_page(obj);
-	return page_get_slab(page);
+
+	VM_BUG_ON(!PageSlab(page));
+	return page->slab_page;
 }
 
 static inline void *index_to_obj(struct kmem_cache *cache, struct slab *slab,
 				 unsigned int idx)
 {
-	return slab->s_mem + cache->buffer_size * idx;
+	return slab->s_mem + cache->size * idx;
 }
 
 /*
- * We want to avoid an expensive divide : (offset / cache->buffer_size)
- *   Using the fact that buffer_size is a constant for a particular cache,
- *   we can replace (offset / cache->buffer_size) by
+ * We want to avoid an expensive divide : (offset / cache->size)
+ *   Using the fact that size is a constant for a particular cache,
+ *   we can replace (offset / cache->size) by
  *   reciprocal_divide(offset, cache->reciprocal_buffer_size)
  */
 static inline unsigned int obj_to_index(const struct kmem_cache *cache,
@@ -584,7 +559,7 @@ static struct kmem_cache cache_cache = {
 	.batchcount = 1,
 	.limit = BOOT_CPUCACHE_ENTRIES,
 	.shared = 1,
-	.buffer_size = sizeof(struct kmem_cache),
+	.size = sizeof(struct kmem_cache),
 	.name = "kmem_cache",
 };
 
@@ -1153,7 +1128,7 @@ static int init_cache_nodelists_node(int node)
 	struct kmem_list3 *l3;
 	const int memsize = sizeof(struct kmem_list3);
 
-	list_for_each_entry(cachep, &cache_chain, next) {
+	list_for_each_entry(cachep, &cache_chain, list) {
 		/*
 		 * Set up the size64 kmemlist for cpu before we can
 		 * begin anything. Make sure some other cpu on this
@@ -1191,7 +1166,7 @@ static void __cpuinit cpuup_canceled(long cpu)
 	int node = cpu_to_mem(cpu);
 	const struct cpumask *mask = cpumask_of_node(node);
 
-	list_for_each_entry(cachep, &cache_chain, next) {
+	list_for_each_entry(cachep, &cache_chain, list) {
 		struct array_cache *nc;
 		struct array_cache *shared;
 		struct array_cache **alien;
@@ -1241,7 +1216,7 @@ free_array_cache:
 	 * the respective cache's slabs,  now we can go ahead and
 	 * shrink each nodelist to its limit.
 	 */
-	list_for_each_entry(cachep, &cache_chain, next) {
+	list_for_each_entry(cachep, &cache_chain, list) {
 		l3 = cachep->nodelists[node];
 		if (!l3)
 			continue;
@@ -1270,7 +1245,7 @@ static int __cpuinit cpuup_prepare(long cpu)
 	 * Now we can go ahead with allocating the shared arrays and
 	 * array caches
 	 */
-	list_for_each_entry(cachep, &cache_chain, next) {
+	list_for_each_entry(cachep, &cache_chain, list) {
 		struct array_cache *nc;
 		struct array_cache *shared = NULL;
 		struct array_cache **alien = NULL;
@@ -1402,7 +1377,7 @@ static int __meminit drain_cache_nodelists_node(int node)
 	struct kmem_cache *cachep;
 	int ret = 0;
 
-	list_for_each_entry(cachep, &cache_chain, next) {
+	list_for_each_entry(cachep, &cache_chain, list) {
 		struct kmem_list3 *l3;
 
 		l3 = cachep->nodelists[node];
@@ -1545,7 +1520,7 @@ void __init kmem_cache_init(void)
 
 	/* 1) create the cache_cache */
 	INIT_LIST_HEAD(&cache_chain);
-	list_add(&cache_cache.next, &cache_chain);
+	list_add(&cache_cache.list, &cache_chain);
 	cache_cache.colour_off = cache_line_size();
 	cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
 	cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE + node];
@@ -1553,18 +1528,16 @@ void __init kmem_cache_init(void)
 	/*
 	 * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids
 	 */
-	cache_cache.buffer_size = offsetof(struct kmem_cache, array[nr_cpu_ids]) +
+	cache_cache.size = offsetof(struct kmem_cache, array[nr_cpu_ids]) +
 				  nr_node_ids * sizeof(struct kmem_list3 *);
-#if DEBUG
-	cache_cache.obj_size = cache_cache.buffer_size;
-#endif
-	cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,
+	cache_cache.object_size = cache_cache.size;
+	cache_cache.size = ALIGN(cache_cache.size,
 					cache_line_size());
 	cache_cache.reciprocal_buffer_size =
-		reciprocal_value(cache_cache.buffer_size);
+		reciprocal_value(cache_cache.size);
 
 	for (order = 0; order < MAX_ORDER; order++) {
-		cache_estimate(order, cache_cache.buffer_size,
+		cache_estimate(order, cache_cache.size,
 			cache_line_size(), 0, &left_over, &cache_cache.num);
 		if (cache_cache.num)
 			break;
@@ -1690,14 +1663,11 @@ void __init kmem_cache_init_late(void)
 
 	/* 6) resize the head arrays to their final sizes */
 	mutex_lock(&cache_chain_mutex);
-	list_for_each_entry(cachep, &cache_chain, next)
+	list_for_each_entry(cachep, &cache_chain, list)
 		if (enable_cpucache(cachep, GFP_NOWAIT))
 			BUG();
 	mutex_unlock(&cache_chain_mutex);
 
-	/* Done! */
-	g_cpucache_up = FULL;
-
 	/*
 	 * Register a cpu startup notifier callback that initializes
 	 * cpu_cache_get for all new cpus
@@ -1727,6 +1697,9 @@ static int __init cpucache_init(void)
 	 */
 	for_each_online_cpu(cpu)
 		start_cpu_timer(cpu);
+
+	/* Done! */
+	g_cpucache_up = FULL;
 	return 0;
 }
 __initcall(cpucache_init);
@@ -1743,7 +1716,7 @@ slab_out_of_memory(struct kmem_cache *cachep, gfp_t gfpflags, int nodeid)
 		"SLAB: Unable to allocate memory on node %d (gfp=0x%x)\n",
 		nodeid, gfpflags);
 	printk(KERN_WARNING "  cache: %s, object size: %d, order: %d\n",
-		cachep->name, cachep->buffer_size, cachep->gfporder);
+		cachep->name, cachep->size, cachep->gfporder);
 
 	for_each_online_node(node) {
 		unsigned long active_objs = 0, num_objs = 0, free_objects = 0;
@@ -1874,7 +1847,7 @@ static void kmem_rcu_free(struct rcu_head *head)
 static void store_stackinfo(struct kmem_cache *cachep, unsigned long *addr,
 			    unsigned long caller)
 {
-	int size = obj_size(cachep);
+	int size = cachep->object_size;
 
 	addr = (unsigned long *)&((char *)addr)[obj_offset(cachep)];
 
@@ -1906,7 +1879,7 @@ static void store_stackinfo(struct kmem_cache *cachep, unsigned long *addr,
 
 static void poison_obj(struct kmem_cache *cachep, void *addr, unsigned char val)
 {
-	int size = obj_size(cachep);
+	int size = cachep->object_size;
 	addr = &((char *)addr)[obj_offset(cachep)];
 
 	memset(addr, val, size);
@@ -1966,7 +1939,7 @@ static void print_objinfo(struct kmem_cache *cachep, void *objp, int lines)
 		printk("\n");
 	}
 	realobj = (char *)objp + obj_offset(cachep);
-	size = obj_size(cachep);
+	size = cachep->object_size;
 	for (i = 0; i < size && lines; i += 16, lines--) {
 		int limit;
 		limit = 16;
@@ -1983,7 +1956,7 @@ static void check_poison_obj(struct kmem_cache *cachep, void *objp)
 	int lines = 0;
 
 	realobj = (char *)objp + obj_offset(cachep);
-	size = obj_size(cachep);
+	size = cachep->object_size;
 
 	for (i = 0; i < size; i++) {
 		char exp = POISON_FREE;
@@ -2047,10 +2020,10 @@ static void slab_destroy_debugcheck(struct kmem_cache *cachep, struct slab *slab
 
 		if (cachep->flags & SLAB_POISON) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
-			if (cachep->buffer_size % PAGE_SIZE == 0 &&
+			if (cachep->size % PAGE_SIZE == 0 &&
 					OFF_SLAB(cachep))
 				kernel_map_pages(virt_to_page(objp),
-					cachep->buffer_size / PAGE_SIZE, 1);
+					cachep->size / PAGE_SIZE, 1);
 			else
 				check_poison_obj(cachep, objp);
 #else
@@ -2194,7 +2167,7 @@ static size_t calculate_slab_order(struct kmem_cache *cachep,
 
 static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
 {
-	if (g_cpucache_up == FULL)
+	if (g_cpucache_up >= LATE)
 		return enable_cpucache(cachep, gfp);
 
 	if (g_cpucache_up == NONE) {
@@ -2300,7 +2273,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
 		mutex_lock(&cache_chain_mutex);
 	}
 
-	list_for_each_entry(pc, &cache_chain, next) {
+	list_for_each_entry(pc, &cache_chain, list) {
 		char tmp;
 		int res;
 
@@ -2313,7 +2286,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
 		if (res) {
 			printk(KERN_ERR
 			       "SLAB: cache with size %d has lost its name\n",
-			       pc->buffer_size);
+			       pc->size);
 			continue;
 		}
 
@@ -2418,8 +2391,9 @@ kmem_cache_create (const char *name, size_t size, size_t align,
 		goto oops;
 
 	cachep->nodelists = (struct kmem_list3 **)&cachep->array[nr_cpu_ids];
+	cachep->object_size = size;
+	cachep->align = align;
 #if DEBUG
-	cachep->obj_size = size;
 
 	/*
 	 * Both debugging options require word-alignment which is calculated
@@ -2442,7 +2416,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
 	}
 #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC)
 	if (size >= malloc_sizes[INDEX_L3 + 1].cs_size
-	    && cachep->obj_size > cache_line_size() && ALIGN(size, align) < PAGE_SIZE) {
+	    && cachep->object_size > cache_line_size() && ALIGN(size, align) < PAGE_SIZE) {
 		cachep->obj_offset += PAGE_SIZE - ALIGN(size, align);
 		size = PAGE_SIZE;
 	}
@@ -2511,7 +2485,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
 	cachep->gfpflags = 0;
 	if (CONFIG_ZONE_DMA_FLAG && (flags & SLAB_CACHE_DMA))
 		cachep->gfpflags |= GFP_DMA;
-	cachep->buffer_size = size;
+	cachep->size = size;
 	cachep->reciprocal_buffer_size = reciprocal_value(size);
 
 	if (flags & CFLGS_OFF_SLAB) {
@@ -2545,7 +2519,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
 	}
 
 	/* cache setup completed, link it into the list */
-	list_add(&cachep->next, &cache_chain);
+	list_add(&cachep->list, &cache_chain);
 oops:
 	if (!cachep && (flags & SLAB_PANIC))
 		panic("kmem_cache_create(): failed to create slab `%s'\n",
@@ -2740,10 +2714,10 @@ void kmem_cache_destroy(struct kmem_cache *cachep)
 	/*
 	 * the chain is never empty, cache_cache is never destroyed
 	 */
-	list_del(&cachep->next);
+	list_del(&cachep->list);
 	if (__cache_shrink(cachep)) {
 		slab_error(cachep, "Can't free all objects");
-		list_add(&cachep->next, &cache_chain);
+		list_add(&cachep->list, &cache_chain);
 		mutex_unlock(&cache_chain_mutex);
 		put_online_cpus();
 		return;
@@ -2840,10 +2814,10 @@ static void cache_init_objs(struct kmem_cache *cachep,
 				slab_error(cachep, "constructor overwrote the"
 					   " start of an object");
 		}
-		if ((cachep->buffer_size % PAGE_SIZE) == 0 &&
+		if ((cachep->size % PAGE_SIZE) == 0 &&
 			    OFF_SLAB(cachep) && cachep->flags & SLAB_POISON)
 			kernel_map_pages(virt_to_page(objp),
-					 cachep->buffer_size / PAGE_SIZE, 0);
+					 cachep->size / PAGE_SIZE, 0);
 #else
 		if (cachep->ctor)
 			cachep->ctor(objp);
@@ -2918,8 +2892,8 @@ static void slab_map_pages(struct kmem_cache *cache, struct slab *slab,
 		nr_pages <<= cache->gfporder;
 
 	do {
-		page_set_cache(page, cache);
-		page_set_slab(page, slab);
+		page->slab_cache = cache;
+		page->slab_page = slab;
 		page++;
 	} while (--nr_pages);
 }
@@ -3057,7 +3031,7 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
 	kfree_debugcheck(objp);
 	page = virt_to_head_page(objp);
 
-	slabp = page_get_slab(page);
+	slabp = page->slab_page;
 
 	if (cachep->flags & SLAB_RED_ZONE) {
 		verify_redzone_free(cachep, objp);
@@ -3077,10 +3051,10 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
 #endif
 	if (cachep->flags & SLAB_POISON) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
-		if ((cachep->buffer_size % PAGE_SIZE)==0 && OFF_SLAB(cachep)) {
+		if ((cachep->size % PAGE_SIZE)==0 && OFF_SLAB(cachep)) {
 			store_stackinfo(cachep, objp, (unsigned long)caller);
 			kernel_map_pages(virt_to_page(objp),
-					 cachep->buffer_size / PAGE_SIZE, 0);
+					 cachep->size / PAGE_SIZE, 0);
 		} else {
 			poison_obj(cachep, objp, POISON_FREE);
 		}
@@ -3230,9 +3204,9 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
 		return objp;
 	if (cachep->flags & SLAB_POISON) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
-		if ((cachep->buffer_size % PAGE_SIZE) == 0 && OFF_SLAB(cachep))
+		if ((cachep->size % PAGE_SIZE) == 0 && OFF_SLAB(cachep))
 			kernel_map_pages(virt_to_page(objp),
-					 cachep->buffer_size / PAGE_SIZE, 1);
+					 cachep->size / PAGE_SIZE, 1);
 		else
 			check_poison_obj(cachep, objp);
 #else
@@ -3261,8 +3235,8 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
 		struct slab *slabp;
 		unsigned objnr;
 
-		slabp = page_get_slab(virt_to_head_page(objp));
-		objnr = (unsigned)(objp - slabp->s_mem) / cachep->buffer_size;
+		slabp = virt_to_head_page(objp)->slab_page;
+		objnr = (unsigned)(objp - slabp->s_mem) / cachep->size;
 		slab_bufctl(slabp)[objnr] = BUFCTL_ACTIVE;
 	}
 #endif
@@ -3285,7 +3259,7 @@ static bool slab_should_failslab(struct kmem_cache *cachep, gfp_t flags)
 	if (cachep == &cache_cache)
 		return false;
 
-	return should_failslab(obj_size(cachep), flags, cachep->flags);
+	return should_failslab(cachep->object_size, flags, cachep->flags);
 }
 
 static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
@@ -3336,7 +3310,7 @@ static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags)
 	if (cpuset_do_slab_mem_spread() && (cachep->flags & SLAB_MEM_SPREAD))
 		nid_alloc = cpuset_slab_spread_node();
 	else if (current->mempolicy)
-		nid_alloc = slab_node(current->mempolicy);
+		nid_alloc = slab_node();
 	if (nid_alloc != nid_here)
 		return ____cache_alloc_node(cachep, flags, nid_alloc);
 	return NULL;
@@ -3367,8 +3341,8 @@ static void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
 	local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK);
 
 retry_cpuset:
-	cpuset_mems_cookie = get_mems_allowed();
-	zonelist = node_zonelist(slab_node(current->mempolicy), flags);
+	cpuset_mems_cookie = read_mems_allowed_begin();
+	zonelist = node_zonelist(slab_node(), flags);
 
 retry:
 	/*
@@ -3423,7 +3397,7 @@ retry:
 		}
 	}
 
-	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !obj))
+	if (unlikely(!obj && read_mems_allowed_retry(cpuset_mems_cookie)))
 		goto retry_cpuset;
 	return obj;
 }
@@ -3545,14 +3519,14 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
   out:
 	local_irq_restore(save_flags);
 	ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, caller);
-	kmemleak_alloc_recursive(ptr, obj_size(cachep), 1, cachep->flags,
+	kmemleak_alloc_recursive(ptr, cachep->object_size, 1, cachep->flags,
 				 flags);
 
 	if (likely(ptr))
-		kmemcheck_slab_alloc(cachep, flags, ptr, obj_size(cachep));
+		kmemcheck_slab_alloc(cachep, flags, ptr, cachep->object_size);
 
 	if (unlikely((flags & __GFP_ZERO) && ptr))
-		memset(ptr, 0, obj_size(cachep));
+		memset(ptr, 0, cachep->object_size);
 
 	return ptr;
 }
@@ -3607,15 +3581,15 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller)
 	objp = __do_cache_alloc(cachep, flags);
 	local_irq_restore(save_flags);
 	objp = cache_alloc_debugcheck_after(cachep, flags, objp, caller);
-	kmemleak_alloc_recursive(objp, obj_size(cachep), 1, cachep->flags,
+	kmemleak_alloc_recursive(objp, cachep->object_size, 1, cachep->flags,
 				 flags);
 	prefetchw(objp);
 
 	if (likely(objp))
-		kmemcheck_slab_alloc(cachep, flags, objp, obj_size(cachep));
+		kmemcheck_slab_alloc(cachep, flags, objp, cachep->object_size);
 
 	if (unlikely((flags & __GFP_ZERO) && objp))
-		memset(objp, 0, obj_size(cachep));
+		memset(objp, 0, cachep->object_size);
 
 	return objp;
 }
@@ -3731,7 +3705,7 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp,
 	kmemleak_free_recursive(objp, cachep->flags);
 	objp = cache_free_debugcheck(cachep, objp, caller);
 
-	kmemcheck_slab_free(cachep, objp, obj_size(cachep));
+	kmemcheck_slab_free(cachep, objp, cachep->object_size);
 
 	/*
 	 * Skip calling cache_free_alien() when the platform is not numa.
@@ -3766,7 +3740,7 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
 	void *ret = __cache_alloc(cachep, flags, __builtin_return_address(0));
 
 	trace_kmem_cache_alloc(_RET_IP_, ret,
-			       obj_size(cachep), cachep->buffer_size, flags);
+			       cachep->object_size, cachep->size, flags);
 
 	return ret;
 }
@@ -3794,7 +3768,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid)
 				       __builtin_return_address(0));
 
 	trace_kmem_cache_alloc_node(_RET_IP_, ret,
-				    obj_size(cachep), cachep->buffer_size,
+				    cachep->object_size, cachep->size,
 				    flags, nodeid);
 
 	return ret;
@@ -3876,7 +3850,7 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
 	ret = __cache_alloc(cachep, flags, caller);
 
 	trace_kmalloc((unsigned long) caller, ret,
-		      size, cachep->buffer_size, flags);
+		      size, cachep->size, flags);
 
 	return ret;
 }
@@ -3916,9 +3890,9 @@ void kmem_cache_free(struct kmem_cache *cachep, void *objp)
 	unsigned long flags;
 
 	local_irq_save(flags);
-	debug_check_no_locks_freed(objp, obj_size(cachep));
+	debug_check_no_locks_freed(objp, cachep->size);
 	if (!(cachep->flags & SLAB_DEBUG_OBJECTS))
-		debug_check_no_obj_freed(objp, obj_size(cachep));
+		debug_check_no_obj_freed(objp, cachep->object_size);
 	__cache_free(cachep, objp, __builtin_return_address(0));
 	local_irq_restore(flags);
 
@@ -3947,8 +3921,9 @@ void kfree(const void *objp)
 	local_irq_save(flags);
 	kfree_debugcheck(objp);
 	c = virt_to_cache(objp);
-	debug_check_no_locks_freed(objp, obj_size(c));
-	debug_check_no_obj_freed(objp, obj_size(c));
+	debug_check_no_locks_freed(objp, c->object_size);
+
+	debug_check_no_obj_freed(objp, c->object_size);
 	__cache_free(c, (void *)objp, __builtin_return_address(0));
 	local_irq_restore(flags);
 }
@@ -3956,7 +3931,7 @@ EXPORT_SYMBOL(kfree);
 
 unsigned int kmem_cache_size(struct kmem_cache *cachep)
 {
-	return obj_size(cachep);
+	return cachep->object_size;
 }
 EXPORT_SYMBOL(kmem_cache_size);
 
@@ -4030,7 +4005,7 @@ static int alloc_kmemlist(struct kmem_cache *cachep, gfp_t gfp)
 	return 0;
 
 fail:
-	if (!cachep->next.next) {
+	if (!cachep->list.next) {
 		/* Cache is not active yet. Roll back what we did */
 		node--;
 		while (node >= 0) {
@@ -4124,13 +4099,13 @@ static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp)
 	 * The numbers are guessed, we should auto-tune as described by
 	 * Bonwick.
 	 */
-	if (cachep->buffer_size > 131072)
+	if (cachep->size > 131072)
 		limit = 1;
-	else if (cachep->buffer_size > PAGE_SIZE)
+	else if (cachep->size > PAGE_SIZE)
 		limit = 8;
-	else if (cachep->buffer_size > 1024)
+	else if (cachep->size > 1024)
 		limit = 24;
-	else if (cachep->buffer_size > 256)
+	else if (cachep->size > 256)
 		limit = 54;
 	else
 		limit = 120;
@@ -4145,7 +4120,7 @@ static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp)
 	 * to a larger limit. Thus disabled by default.
 	 */
 	shared = 0;
-	if (cachep->buffer_size <= PAGE_SIZE && num_possible_cpus() > 1)
+	if (cachep->size <= PAGE_SIZE && num_possible_cpus() > 1)
 		shared = 8;
 
 #if DEBUG
@@ -4215,7 +4190,7 @@ static void cache_reap(struct work_struct *w)
 		/* Give up. Setup the next iteration. */
 		goto out;
 
-	list_for_each_entry(searchp, &cache_chain, next) {
+	list_for_each_entry(searchp, &cache_chain, list) {
 		check_irq_on();
 
 		/*
@@ -4308,7 +4283,7 @@ static void s_stop(struct seq_file *m, void *p)
 
 static int s_show(struct seq_file *m, void *p)
 {
-	struct kmem_cache *cachep = list_entry(p, struct kmem_cache, next);
+	struct kmem_cache *cachep = list_entry(p, struct kmem_cache, list);
 	struct slab *slabp;
 	unsigned long active_objs;
 	unsigned long num_objs;
@@ -4364,7 +4339,7 @@ static int s_show(struct seq_file *m, void *p)
 		printk(KERN_ERR "slab: cache %s error: %s\n", name, error);
 
 	seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d",
-		   name, active_objs, num_objs, cachep->buffer_size,
+		   name, active_objs, num_objs, cachep->size,
 		   cachep->num, (1 << cachep->gfporder));
 	seq_printf(m, " : tunables %4u %4u %4u",
 		   cachep->limit, cachep->batchcount, cachep->shared);
@@ -4456,7 +4431,7 @@ static ssize_t slabinfo_write(struct file *file, const char __user *buffer,
 	/* Find the cache in the chain of caches. */
 	mutex_lock(&cache_chain_mutex);
 	res = -EINVAL;
-	list_for_each_entry(cachep, &cache_chain, next) {
+	list_for_each_entry(cachep, &cache_chain, list) {
 		if (!strcmp(cachep->name, kbuf)) {
 			if (limit < 1 || batchcount < 1 ||
 					batchcount > limit || shared < 0) {
@@ -4532,7 +4507,7 @@ static void handle_slab(unsigned long *n, struct kmem_cache *c, struct slab *s)
 	int i;
 	if (n[0] == n[1])
 		return;
-	for (i = 0, p = s->s_mem; i < c->num; i++, p += c->buffer_size) {
+	for (i = 0, p = s->s_mem; i < c->num; i++, p += c->size) {
 		if (slab_bufctl(s)[i] != BUFCTL_ACTIVE)
 			continue;
 		if (!add_caller(n, (unsigned long)*dbg_userword(c, p)))
@@ -4677,6 +4652,6 @@ size_t ksize(const void *objp)
 	if (unlikely(objp == ZERO_SIZE_PTR))
 		return 0;
 
-	return obj_size(virt_to_cache(objp));
+	return virt_to_cache(objp)->object_size;
 }
 EXPORT_SYMBOL(ksize);
diff --git a/mm/slob.c b/mm/slob.c
index 8105be4..95d1c7d 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -92,36 +92,6 @@ struct slob_block {
 typedef struct slob_block slob_t;
 
 /*
- * We use struct page fields to manage some slob allocation aspects,
- * however to avoid the horrible mess in include/linux/mm_types.h, we'll
- * just define our own struct page type variant here.
- */
-struct slob_page {
-	union {
-		struct {
-			unsigned long flags;	/* mandatory */
-			atomic_t _count;	/* mandatory */
-			slobidx_t units;	/* free units left in page */
-			unsigned long pad[2];
-			slob_t *free;		/* first free slob_t in page */
-			struct list_head list;	/* linked list of free pages */
-		};
-		struct page page;
-	};
-};
-static inline void struct_slob_page_wrong_size(void)
-{ BUILD_BUG_ON(sizeof(struct slob_page) != sizeof(struct page)); }
-
-/*
- * free_slob_page: call before a slob_page is returned to the page allocator.
- */
-static inline void free_slob_page(struct slob_page *sp)
-{
-	reset_page_mapcount(&sp->page);
-	sp->page.mapping = NULL;
-}
-
-/*
  * All partially free slob pages go on these lists.
  */
 #define SLOB_BREAK1 256
@@ -131,46 +101,23 @@ static LIST_HEAD(free_slob_medium);
 static LIST_HEAD(free_slob_large);
 
 /*
- * is_slob_page: True for all slob pages (false for bigblock pages)
- */
-static inline int is_slob_page(struct slob_page *sp)
-{
-	return PageSlab((struct page *)sp);
-}
-
-static inline void set_slob_page(struct slob_page *sp)
-{
-	__SetPageSlab((struct page *)sp);
-}
-
-static inline void clear_slob_page(struct slob_page *sp)
-{
-	__ClearPageSlab((struct page *)sp);
-}
-
-static inline struct slob_page *slob_page(const void *addr)
-{
-	return (struct slob_page *)virt_to_page(addr);
-}
-
-/*
  * slob_page_free: true for pages on free_slob_pages list.
  */
-static inline int slob_page_free(struct slob_page *sp)
+static inline int slob_page_free(struct page *sp)
 {
-	return PageSlobFree((struct page *)sp);
+	return PageSlobFree(sp);
 }
 
-static void set_slob_page_free(struct slob_page *sp, struct list_head *list)
+static void set_slob_page_free(struct page *sp, struct list_head *list)
 {
 	list_add(&sp->list, list);
-	__SetPageSlobFree((struct page *)sp);
+	__SetPageSlobFree(sp);
 }
 
-static inline void clear_slob_page_free(struct slob_page *sp)
+static inline void clear_slob_page_free(struct page *sp)
 {
 	list_del(&sp->list);
-	__ClearPageSlobFree((struct page *)sp);
+	__ClearPageSlobFree(sp);
 }
 
 #define SLOB_UNIT sizeof(slob_t)
@@ -267,12 +214,12 @@ static void slob_free_pages(void *b, int order)
 /*
  * Allocate a slob block within a given slob_page sp.
  */
-static void *slob_page_alloc(struct slob_page *sp, size_t size, int align)
+static void *slob_page_alloc(struct page *sp, size_t size, int align)
 {
 	slob_t *prev, *cur, *aligned = NULL;
 	int delta = 0, units = SLOB_UNITS(size);
 
-	for (prev = NULL, cur = sp->free; ; prev = cur, cur = slob_next(cur)) {
+	for (prev = NULL, cur = sp->freelist; ; prev = cur, cur = slob_next(cur)) {
 		slobidx_t avail = slob_units(cur);
 
 		if (align) {
@@ -296,12 +243,12 @@ static void *slob_page_alloc(struct slob_page *sp, size_t size, int align)
 				if (prev)
 					set_slob(prev, slob_units(prev), next);
 				else
-					sp->free = next;
+					sp->freelist = next;
 			} else { /* fragment */
 				if (prev)
 					set_slob(prev, slob_units(prev), cur + units);
 				else
-					sp->free = cur + units;
+					sp->freelist = cur + units;
 				set_slob(cur + units, avail - units, next);
 			}
 
@@ -320,7 +267,7 @@ static void *slob_page_alloc(struct slob_page *sp, size_t size, int align)
  */
 static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
 {
-	struct slob_page *sp;
+	struct page *sp;
 	struct list_head *prev;
 	struct list_head *slob_list;
 	slob_t *b = NULL;
@@ -341,7 +288,7 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
 		 * If there's a node specification, search for a partial
 		 * page with a matching node id in the freelist.
 		 */
-		if (node != -1 && page_to_nid(&sp->page) != node)
+		if (node != -1 && page_to_nid(sp) != node)
 			continue;
 #endif
 		/* Enough room on this page? */
@@ -369,12 +316,12 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
 		b = slob_new_pages(gfp & ~__GFP_ZERO, 0, node);
 		if (!b)
 			return NULL;
-		sp = slob_page(b);
-		set_slob_page(sp);
+		sp = virt_to_page(b);
+		__SetPageSlab(sp);
 
 		spin_lock_irqsave(&slob_lock, flags);
 		sp->units = SLOB_UNITS(PAGE_SIZE);
-		sp->free = b;
+		sp->freelist = b;
 		INIT_LIST_HEAD(&sp->list);
 		set_slob(b, SLOB_UNITS(PAGE_SIZE), b + SLOB_UNITS(PAGE_SIZE));
 		set_slob_page_free(sp, slob_list);
@@ -392,7 +339,7 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
  */
 static void slob_free(void *block, int size)
 {
-	struct slob_page *sp;
+	struct page *sp;
 	slob_t *prev, *next, *b = (slob_t *)block;
 	slobidx_t units;
 	unsigned long flags;
@@ -402,7 +349,7 @@ static void slob_free(void *block, int size)
 		return;
 	BUG_ON(!size);
 
-	sp = slob_page(block);
+	sp = virt_to_page(block);
 	units = SLOB_UNITS(size);
 
 	spin_lock_irqsave(&slob_lock, flags);
@@ -412,8 +359,8 @@ static void slob_free(void *block, int size)
 		if (slob_page_free(sp))
 			clear_slob_page_free(sp);
 		spin_unlock_irqrestore(&slob_lock, flags);
-		clear_slob_page(sp);
-		free_slob_page(sp);
+		__ClearPageSlab(sp);
+		reset_page_mapcount(sp);
 		slob_free_pages(b, 0);
 		return;
 	}
@@ -421,7 +368,7 @@ static void slob_free(void *block, int size)
 	if (!slob_page_free(sp)) {
 		/* This slob page is about to become partially free. Easy! */
 		sp->units = units;
-		sp->free = b;
+		sp->freelist = b;
 		set_slob(b, units,
 			(void *)((unsigned long)(b +
 					SLOB_UNITS(PAGE_SIZE)) & PAGE_MASK));
@@ -441,15 +388,15 @@ static void slob_free(void *block, int size)
 	 */
 	sp->units += units;
 
-	if (b < sp->free) {
-		if (b + units == sp->free) {
-			units += slob_units(sp->free);
-			sp->free = slob_next(sp->free);
+	if (b < (slob_t *)sp->freelist) {
+		if (b + units == sp->freelist) {
+			units += slob_units(sp->freelist);
+			sp->freelist = slob_next(sp->freelist);
 		}
-		set_slob(b, units, sp->free);
-		sp->free = b;
+		set_slob(b, units, sp->freelist);
+		sp->freelist = b;
 	} else {
-		prev = sp->free;
+		prev = sp->freelist;
 		next = slob_next(prev);
 		while (b > next) {
 			prev = next;
@@ -522,7 +469,7 @@ EXPORT_SYMBOL(__kmalloc_node);
 
 void kfree(const void *block)
 {
-	struct slob_page *sp;
+	struct page *sp;
 
 	trace_kfree(_RET_IP_, block);
 
@@ -530,42 +477,35 @@ void kfree(const void *block)
 		return;
 	kmemleak_free(block);
 
-	sp = slob_page(block);
-	if (is_slob_page(sp)) {
+	sp = virt_to_page(block);
+	if (PageSlab(sp)) {
 		int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
 		unsigned int *m = (unsigned int *)(block - align);
 		slob_free(m, *m + align);
 	} else
-		put_page(&sp->page);
+		put_page(sp);
 }
 EXPORT_SYMBOL(kfree);
 
 /* can't use ksize for kmem_cache_alloc memory, only kmalloc */
 size_t ksize(const void *block)
 {
-	struct slob_page *sp;
+	struct page *sp;
 
 	BUG_ON(!block);
 	if (unlikely(block == ZERO_SIZE_PTR))
 		return 0;
 
-	sp = slob_page(block);
-	if (is_slob_page(sp)) {
+	sp = virt_to_page(block);
+	if (PageSlab(sp)) {
 		int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
 		unsigned int *m = (unsigned int *)(block - align);
 		return SLOB_UNITS(*m) * SLOB_UNIT;
 	} else
-		return sp->page.private;
+		return sp->private;
 }
 EXPORT_SYMBOL(ksize);
 
-struct kmem_cache {
-	unsigned int size, align;
-	unsigned long flags;
-	const char *name;
-	void (*ctor)(void *);
-};
-
 struct kmem_cache *kmem_cache_create(const char *name, size_t size,
 	size_t align, unsigned long flags, void (*ctor)(void *))
 {
@@ -576,7 +516,7 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
 
 	if (c) {
 		c->name = name;
-		c->size = size;
+		c->size = c->object_size;
 		if (flags & SLAB_DESTROY_BY_RCU) {
 			/* leave room for rcu footer at the end of object */
 			c->size += sizeof(struct slob_rcu);
diff --git a/mm/slub.c b/mm/slub.c
index 8c691fa..cc4ed03 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -311,7 +311,7 @@ static inline size_t slab_ksize(const struct kmem_cache *s)
 	 * and whatever may come after it.
 	 */
 	if (s->flags & (SLAB_RED_ZONE | SLAB_POISON))
-		return s->objsize;
+		return s->object_size;
 
 #endif
 	/*
@@ -609,11 +609,11 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
 	if (p > addr + 16)
 		print_section("Bytes b4 ", p - 16, 16);
 
-	print_section("Object ", p, min_t(unsigned long, s->objsize,
+	print_section("Object ", p, min_t(unsigned long, s->object_size,
 				PAGE_SIZE));
 	if (s->flags & SLAB_RED_ZONE)
-		print_section("Redzone ", p + s->objsize,
-			s->inuse - s->objsize);
+		print_section("Redzone ", p + s->object_size,
+			s->inuse - s->object_size);
 
 	if (s->offset)
 		off = s->offset + sizeof(void *);
@@ -655,12 +655,12 @@ static void init_object(struct kmem_cache *s, void *object, u8 val)
 	u8 *p = object;
 
 	if (s->flags & __OBJECT_POISON) {
-		memset(p, POISON_FREE, s->objsize - 1);
-		p[s->objsize - 1] = POISON_END;
+		memset(p, POISON_FREE, s->object_size - 1);
+		p[s->object_size - 1] = POISON_END;
 	}
 
 	if (s->flags & SLAB_RED_ZONE)
-		memset(p + s->objsize, val, s->inuse - s->objsize);
+		memset(p + s->object_size, val, s->inuse - s->object_size);
 }
 
 static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
@@ -705,10 +705,10 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
  * 	Poisoning uses 0x6b (POISON_FREE) and the last byte is
  * 	0xa5 (POISON_END)
  *
- * object + s->objsize
+ * object + s->object_size
  * 	Padding to reach word boundary. This is also used for Redzoning.
  * 	Padding is extended by another word if Redzoning is enabled and
- * 	objsize == inuse.
+ * 	object_size == inuse.
  *
  * 	We fill with 0xbb (RED_INACTIVE) for inactive objects and with
  * 	0xcc (RED_ACTIVE) for objects in use.
@@ -727,7 +727,7 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
  * object + s->size
  * 	Nothing is used beyond s->size.
  *
- * If slabcaches are merged then the objsize and inuse boundaries are mostly
+ * If slabcaches are merged then the object_size and inuse boundaries are mostly
  * ignored. And therefore no slab options that rely on these boundaries
  * may be used with merged slabcaches.
  */
@@ -787,25 +787,25 @@ static int check_object(struct kmem_cache *s, struct page *page,
 					void *object, u8 val)
 {
 	u8 *p = object;
-	u8 *endobject = object + s->objsize;
+	u8 *endobject = object + s->object_size;
 
 	if (s->flags & SLAB_RED_ZONE) {
 		if (!check_bytes_and_report(s, page, object, "Redzone",
-			endobject, val, s->inuse - s->objsize))
+			endobject, val, s->inuse - s->object_size))
 			return 0;
 	} else {
-		if ((s->flags & SLAB_POISON) && s->objsize < s->inuse) {
+		if ((s->flags & SLAB_POISON) && s->object_size < s->inuse) {
 			check_bytes_and_report(s, page, p, "Alignment padding",
-				endobject, POISON_INUSE, s->inuse - s->objsize);
+				endobject, POISON_INUSE, s->inuse - s->object_size);
 		}
 	}
 
 	if (s->flags & SLAB_POISON) {
 		if (val != SLUB_RED_ACTIVE && (s->flags & __OBJECT_POISON) &&
 			(!check_bytes_and_report(s, page, p, "Poison", p,
-					POISON_FREE, s->objsize - 1) ||
+					POISON_FREE, s->object_size - 1) ||
 			 !check_bytes_and_report(s, page, p, "Poison",
-				p + s->objsize - 1, POISON_END, 1)))
+				p + s->object_size - 1, POISON_END, 1)))
 			return 0;
 		/*
 		 * check_pad_bytes cleans up on its own.
@@ -926,7 +926,7 @@ static void trace(struct kmem_cache *s, struct page *page, void *object,
 			page->freelist);
 
 		if (!alloc)
-			print_section("Object ", (void *)object, s->objsize);
+			print_section("Object ", (void *)object, s->object_size);
 
 		dump_stack();
 	}
@@ -942,14 +942,14 @@ static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
 	lockdep_trace_alloc(flags);
 	might_sleep_if(flags & __GFP_WAIT);
 
-	return should_failslab(s->objsize, flags, s->flags);
+	return should_failslab(s->object_size, flags, s->flags);
 }
 
 static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags, void *object)
 {
 	flags &= gfp_allowed_mask;
 	kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
-	kmemleak_alloc_recursive(object, s->objsize, 1, s->flags, flags);
+	kmemleak_alloc_recursive(object, s->object_size, 1, s->flags, flags);
 }
 
 static inline void slab_free_hook(struct kmem_cache *s, void *x)
@@ -966,13 +966,13 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x)
 		unsigned long flags;
 
 		local_irq_save(flags);
-		kmemcheck_slab_free(s, x, s->objsize);
-		debug_check_no_locks_freed(x, s->objsize);
+		kmemcheck_slab_free(s, x, s->object_size);
+		debug_check_no_locks_freed(x, s->object_size);
 		local_irq_restore(flags);
 	}
 #endif
 	if (!(s->flags & SLAB_DEBUG_OBJECTS))
-		debug_check_no_obj_freed(x, s->objsize);
+		debug_check_no_obj_freed(x, s->object_size);
 }
 
 /*
@@ -1207,7 +1207,7 @@ out:
 
 __setup("slub_debug", setup_slub_debug);
 
-static unsigned long kmem_cache_flags(unsigned long objsize,
+static unsigned long kmem_cache_flags(unsigned long object_size,
 	unsigned long flags, const char *name,
 	void (*ctor)(void *))
 {
@@ -1237,7 +1237,7 @@ static inline int check_object(struct kmem_cache *s, struct page *page,
 static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
 					struct page *page) {}
 static inline void remove_full(struct kmem_cache *s, struct page *page) {}
-static inline unsigned long kmem_cache_flags(unsigned long objsize,
+static inline unsigned long kmem_cache_flags(unsigned long object_size,
 	unsigned long flags, const char *name,
 	void (*ctor)(void *))
 {
@@ -1490,12 +1490,12 @@ static inline void remove_partial(struct kmem_cache_node *n,
 }
 
 /*
- * Lock slab, remove from the partial list and put the object into the
- * per cpu freelist.
+ * Remove slab from the partial list, freeze it and
+ * return the pointer to the freelist.
  *
  * Returns a list of objects or NULL if it fails.
  *
- * Must hold list_lock.
+ * Must hold list_lock since we modify the partial list.
  */
 static inline void *acquire_slab(struct kmem_cache *s,
 		struct kmem_cache_node *n, struct page *page,
@@ -1510,26 +1510,27 @@ static inline void *acquire_slab(struct kmem_cache *s,
 	 * The old freelist is the list of objects for the
 	 * per cpu allocation list.
 	 */
-	do {
-		freelist = page->freelist;
-		counters = page->counters;
-		new.counters = counters;
-		if (mode) {
-			new.inuse = page->objects;
-			new.freelist = NULL;
-		} else {
-			new.freelist = freelist;
-		}
+	freelist = page->freelist;
+	counters = page->counters;
+	new.counters = counters;
+	if (mode) {
+		new.inuse = page->objects;
+		new.freelist = NULL;
+	} else {
+		new.freelist = freelist;
+	}
 
-		VM_BUG_ON(new.frozen);
-		new.frozen = 1;
+	VM_BUG_ON(new.frozen);
+	new.frozen = 1;
 
-	} while (!__cmpxchg_double_slab(s, page,
+	if (!__cmpxchg_double_slab(s, page,
 			freelist, counters,
 			new.freelist, new.counters,
-			"lock and freeze"));
+			"acquire_slab"))
+		return NULL;
 
 	remove_partial(n, page);
+	WARN_ON(!freelist);
 	return freelist;
 }
 
@@ -1563,7 +1564,6 @@ static void *get_partial_node(struct kmem_cache *s,
 
 		if (!object) {
 			c->page = page;
-			c->node = page_to_nid(page);
 			stat(s, ALLOC_FROM_PARTIAL);
 			object = t;
 			available =  page->objects - page->inuse;
@@ -1616,8 +1616,8 @@ static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
 		return NULL;
 
 	do {
-		cpuset_mems_cookie = get_mems_allowed();
-		zonelist = node_zonelist(slab_node(current->mempolicy), flags);
+		cpuset_mems_cookie = read_mems_allowed_begin();
+		zonelist = node_zonelist(slab_node(), flags);
 		for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
 			struct kmem_cache_node *n;
 
@@ -1626,21 +1626,11 @@ static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
 			if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
 					n->nr_partial > s->min_partial) {
 				object = get_partial_node(s, n, c);
-				if (object) {
-					/*
-					 * Return the object even if
-					 * put_mems_allowed indicated that
-					 * the cpuset mems_allowed was
-					 * updated in parallel. It's a
-					 * harmless race between the alloc
-					 * and the cpuset update.
-					 */
-					put_mems_allowed(cpuset_mems_cookie);
+				if (object)
 					return object;
-				}
 			}
 		}
-	} while (!put_mems_allowed(cpuset_mems_cookie));
+	} while (read_mems_allowed_retry(cpuset_mems_cookie));
 #endif
 	return NULL;
 }
@@ -1731,14 +1721,12 @@ void init_kmem_cache_cpus(struct kmem_cache *s)
 /*
  * Remove the cpu slab
  */
-static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
+static void deactivate_slab(struct kmem_cache *s, struct page *page, void *freelist)
 {
 	enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
-	struct page *page = c->page;
 	struct kmem_cache_node *n = get_node(s, page_to_nid(page));
 	int lock = 0;
 	enum slab_modes l = M_NONE, m = M_NONE;
-	void *freelist;
 	void *nextfree;
 	int tail = DEACTIVATE_TO_HEAD;
 	struct page new;
@@ -1749,11 +1737,6 @@ static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
 		tail = DEACTIVATE_TO_TAIL;
 	}
 
-	c->tid = next_tid(c->tid);
-	c->page = NULL;
-	freelist = c->freelist;
-	c->freelist = NULL;
-
 	/*
 	 * Stage one: Free all available per cpu objects back
 	 * to the page freelist while it is still frozen. Leave the
@@ -1879,21 +1862,31 @@ redo:
 	}
 }
 
-/* Unfreeze all the cpu partial slabs */
+/*
+ * Unfreeze all the cpu partial slabs.
+ *
+ * This function must be called with interrupt disabled.
+ */
 static void unfreeze_partials(struct kmem_cache *s)
 {
-	struct kmem_cache_node *n = NULL;
+	struct kmem_cache_node *n = NULL, *n2 = NULL;
 	struct kmem_cache_cpu *c = this_cpu_ptr(s->cpu_slab);
 	struct page *page, *discard_page = NULL;
 
 	while ((page = c->partial)) {
-		enum slab_modes { M_PARTIAL, M_FREE };
-		enum slab_modes l, m;
 		struct page new;
 		struct page old;
 
 		c->partial = page->next;
-		l = M_FREE;
+
+		n2 = get_node(s, page_to_nid(page));
+		if (n != n2) {
+			if (n)
+				spin_unlock(&n->list_lock);
+
+			n = n2;
+			spin_lock(&n->list_lock);
+		}
 
 		do {
 
@@ -1906,43 +1899,17 @@ static void unfreeze_partials(struct kmem_cache *s)
 
 			new.frozen = 0;
 
-			if (!new.inuse && (!n || n->nr_partial > s->min_partial))
-				m = M_FREE;
-			else {
-				struct kmem_cache_node *n2 = get_node(s,
-							page_to_nid(page));
-
-				m = M_PARTIAL;
-				if (n != n2) {
-					if (n)
-						spin_unlock(&n->list_lock);
-
-					n = n2;
-					spin_lock(&n->list_lock);
-				}
-			}
-
-			if (l != m) {
-				if (l == M_PARTIAL) {
-					remove_partial(n, page);
-					stat(s, FREE_REMOVE_PARTIAL);
-				} else {
-					add_partial(n, page,
-						DEACTIVATE_TO_TAIL);
-					stat(s, FREE_ADD_PARTIAL);
-				}
-
-				l = m;
-			}
-
-		} while (!cmpxchg_double_slab(s, page,
+		} while (!__cmpxchg_double_slab(s, page,
 				old.freelist, old.counters,
 				new.freelist, new.counters,
 				"unfreezing slab"));
 
-		if (m == M_FREE) {
+		if (unlikely(!new.inuse && n->nr_partial > s->min_partial)) {
 			page->next = discard_page;
 			discard_page = page;
+		} else {
+			add_partial(n, page, DEACTIVATE_TO_TAIL);
+			stat(s, FREE_ADD_PARTIAL);
 		}
 	}
 
@@ -2011,7 +1978,11 @@ int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
 static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
 {
 	stat(s, CPUSLAB_FLUSH);
-	deactivate_slab(s, c);
+	deactivate_slab(s, c->page, c->freelist);
+
+	c->tid = next_tid(c->tid);
+	c->page = NULL;
+	c->freelist = NULL;
 }
 
 /*
@@ -2055,10 +2026,10 @@ static void flush_all(struct kmem_cache *s)
  * Check if the objects in a per cpu structure fit numa
  * locality expectations.
  */
-static inline int node_match(struct kmem_cache_cpu *c, int node)
+static inline int node_match(struct page *page, int node)
 {
 #ifdef CONFIG_NUMA
-	if (node != NUMA_NO_NODE && c->node != node)
+	if (node != NUMA_NO_NODE && page_to_nid(page) != node)
 		return 0;
 #endif
 	return 1;
@@ -2101,10 +2072,10 @@ slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
 		"SLUB: Unable to allocate memory on node %d (gfp=0x%x)\n",
 		nid, gfpflags);
 	printk(KERN_WARNING "  cache: %s, object size: %d, buffer size: %d, "
-		"default order: %d, min order: %d\n", s->name, s->objsize,
+		"default order: %d, min order: %d\n", s->name, s->object_size,
 		s->size, oo_order(s->oo), oo_order(s->min));
 
-	if (oo_order(s->min) > get_order(s->objsize))
+	if (oo_order(s->min) > get_order(s->object_size))
 		printk(KERN_WARNING "  %s debugging increased min order, use "
 		       "slub_debug=O to disable.\n", s->name);
 
@@ -2130,10 +2101,16 @@ slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
 static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
 			int node, struct kmem_cache_cpu **pc)
 {
-	void *object;
-	struct kmem_cache_cpu *c;
-	struct page *page = new_slab(s, flags, node);
+	void *freelist;
+	struct kmem_cache_cpu *c = *pc;
+	struct page *page;
+
+	freelist = get_partial(s, flags, node, c);
 
+	if (freelist)
+		return freelist;
+
+	page = new_slab(s, flags, node);
 	if (page) {
 		c = __this_cpu_ptr(s->cpu_slab);
 		if (c->page)
@@ -2143,17 +2120,16 @@ static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
 		 * No other reference to the page yet so we can
 		 * muck around with it freely without cmpxchg
 		 */
-		object = page->freelist;
+		freelist = page->freelist;
 		page->freelist = NULL;
 
 		stat(s, ALLOC_SLAB);
-		c->node = page_to_nid(page);
 		c->page = page;
 		*pc = c;
 	} else
-		object = NULL;
+		freelist = NULL;
 
-	return object;
+	return freelist;
 }
 
 /*
@@ -2163,6 +2139,8 @@ static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
  * The page is still frozen if the return value is not NULL.
  *
  * If this function returns NULL then the page has been unfrozen.
+ *
+ * This function must be called with interrupt disabled.
  */
 static inline void *get_freelist(struct kmem_cache *s, struct page *page)
 {
@@ -2173,13 +2151,14 @@ static inline void *get_freelist(struct kmem_cache *s, struct page *page)
 	do {
 		freelist = page->freelist;
 		counters = page->counters;
+
 		new.counters = counters;
 		VM_BUG_ON(!new.frozen);
 
 		new.inuse = page->objects;
 		new.frozen = freelist != NULL;
 
-	} while (!cmpxchg_double_slab(s, page,
+	} while (!__cmpxchg_double_slab(s, page,
 		freelist, counters,
 		NULL, new.counters,
 		"get_freelist"));
@@ -2206,7 +2185,8 @@ static inline void *get_freelist(struct kmem_cache *s, struct page *page)
 static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
 			  unsigned long addr, struct kmem_cache_cpu *c)
 {
-	void **object;
+	void *freelist;
+	struct page *page;
 	unsigned long flags;
 
 	local_irq_save(flags);
@@ -2219,25 +2199,29 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
 	c = this_cpu_ptr(s->cpu_slab);
 #endif
 
-	if (!c->page)
+	page = c->page;
+	if (!page)
 		goto new_slab;
 redo:
-	if (unlikely(!node_match(c, node))) {
+
+	if (unlikely(!node_match(page, node))) {
 		stat(s, ALLOC_NODE_MISMATCH);
-		deactivate_slab(s, c);
+		deactivate_slab(s, page, c->freelist);
+		c->page = NULL;
+		c->freelist = NULL;
 		goto new_slab;
 	}
 
 	/* must check again c->freelist in case of cpu migration or IRQ */
-	object = c->freelist;
-	if (object)
+	freelist = c->freelist;
+	if (freelist)
 		goto load_freelist;
 
 	stat(s, ALLOC_SLOWPATH);
 
-	object = get_freelist(s, c->page);
+	freelist = get_freelist(s, page);
 
-	if (!object) {
+	if (!freelist) {
 		c->page = NULL;
 		stat(s, DEACTIVATE_BYPASS);
 		goto new_slab;
@@ -2246,50 +2230,50 @@ redo:
 	stat(s, ALLOC_REFILL);
 
 load_freelist:
-	c->freelist = get_freepointer(s, object);
+	/*
+	 * freelist is pointing to the list of objects to be used.
+	 * page is pointing to the page from which the objects are obtained.
+	 * That page must be frozen for per cpu allocations to work.
+	 */
+	VM_BUG_ON(!c->page->frozen);
+	c->freelist = get_freepointer(s, freelist);
 	c->tid = next_tid(c->tid);
 	local_irq_restore(flags);
-	return object;
+	return freelist;
 
 new_slab:
 
 	if (c->partial) {
-		c->page = c->partial;
-		c->partial = c->page->next;
-		c->node = page_to_nid(c->page);
+		page = c->page = c->partial;
+		c->partial = page->next;
 		stat(s, CPU_PARTIAL_ALLOC);
 		c->freelist = NULL;
 		goto redo;
 	}
 
-	/* Then do expensive stuff like retrieving pages from the partial lists */
-	object = get_partial(s, gfpflags, node, c);
-
-	if (unlikely(!object)) {
+	freelist = new_slab_objects(s, gfpflags, node, &c);
 
-		object = new_slab_objects(s, gfpflags, node, &c);
+	if (unlikely(!freelist)) {
+		if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
+			slab_out_of_memory(s, gfpflags, node);
 
-		if (unlikely(!object)) {
-			if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
-				slab_out_of_memory(s, gfpflags, node);
-
-			local_irq_restore(flags);
-			return NULL;
-		}
+		local_irq_restore(flags);
+		return NULL;
 	}
 
+	page = c->page;
 	if (likely(!kmem_cache_debug(s)))
 		goto load_freelist;
 
 	/* Only entered in the debug case */
-	if (!alloc_debug_processing(s, c->page, object, addr))
+	if (!alloc_debug_processing(s, page, freelist, addr))
 		goto new_slab;	/* Slab failed checks. Next slab needed */
 
-	c->freelist = get_freepointer(s, object);
-	deactivate_slab(s, c);
-	c->node = NUMA_NO_NODE;
+	deactivate_slab(s, page, get_freepointer(s, freelist));
+	c->page = NULL;
+	c->freelist = NULL;
 	local_irq_restore(flags);
-	return object;
+	return freelist;
 }
 
 /*
@@ -2307,6 +2291,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
 {
 	void **object;
 	struct kmem_cache_cpu *c;
+	struct page *page;
 	unsigned long tid;
 
 	if (slab_pre_alloc_hook(s, gfpflags))
@@ -2332,7 +2317,8 @@ redo:
 	barrier();
 
 	object = c->freelist;
-	if (unlikely(!object || !node_match(c, node)))
+	page = c->page;
+	if (unlikely(!object || !node_match(page, node)))
 
 		object = __slab_alloc(s, gfpflags, node, addr, c);
 
@@ -2364,7 +2350,7 @@ redo:
 	}
 
 	if (unlikely(gfpflags & __GFP_ZERO) && object)
-		memset(object, 0, s->objsize);
+		memset(object, 0, s->object_size);
 
 	slab_post_alloc_hook(s, gfpflags, object);
 
@@ -2375,7 +2361,7 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
 {
 	void *ret = slab_alloc(s, gfpflags, NUMA_NO_NODE, _RET_IP_);
 
-	trace_kmem_cache_alloc(_RET_IP_, ret, s->objsize, s->size, gfpflags);
+	trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size, s->size, gfpflags);
 
 	return ret;
 }
@@ -2405,7 +2391,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
 	void *ret = slab_alloc(s, gfpflags, node, _RET_IP_);
 
 	trace_kmem_cache_alloc_node(_RET_IP_, ret,
-				    s->objsize, s->size, gfpflags, node);
+				    s->object_size, s->size, gfpflags, node);
 
 	return ret;
 }
@@ -2900,7 +2886,7 @@ static void set_min_partial(struct kmem_cache *s, unsigned long min)
 static int calculate_sizes(struct kmem_cache *s, int forced_order)
 {
 	unsigned long flags = s->flags;
-	unsigned long size = s->objsize;
+	unsigned long size = s->object_size;
 	unsigned long align = s->align;
 	int order;
 
@@ -2929,7 +2915,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
 	 * end of the object and the free pointer. If not then add an
 	 * additional word to have some bytes to store Redzone information.
 	 */
-	if ((flags & SLAB_RED_ZONE) && size == s->objsize)
+	if ((flags & SLAB_RED_ZONE) && size == s->object_size)
 		size += sizeof(void *);
 #endif
 
@@ -2977,7 +2963,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
 	 * user specified and the dynamic determination of cache line size
 	 * on bootup.
 	 */
-	align = calculate_alignment(flags, align, s->objsize);
+	align = calculate_alignment(flags, align, s->object_size);
 	s->align = align;
 
 	/*
@@ -3025,7 +3011,7 @@ static int kmem_cache_open(struct kmem_cache *s,
 	memset(s, 0, kmem_size);
 	s->name = name;
 	s->ctor = ctor;
-	s->objsize = size;
+	s->object_size = size;
 	s->align = align;
 	s->flags = kmem_cache_flags(size, flags, name, ctor);
 	s->reserved = 0;
@@ -3040,7 +3026,7 @@ static int kmem_cache_open(struct kmem_cache *s,
 		 * Disable debugging flags that store metadata if the min slab
 		 * order increased.
 		 */
-		if (get_order(s->size) > get_order(s->objsize)) {
+		if (get_order(s->size) > get_order(s->object_size)) {
 			s->flags &= ~DEBUG_METADATA_FLAGS;
 			s->offset = 0;
 			if (!calculate_sizes(s, -1))
@@ -3114,7 +3100,7 @@ error:
  */
 unsigned int kmem_cache_size(struct kmem_cache *s)
 {
-	return s->objsize;
+	return s->object_size;
 }
 EXPORT_SYMBOL(kmem_cache_size);
 
@@ -3843,11 +3829,11 @@ void __init kmem_cache_init(void)
 
 		if (s && s->size) {
 			char *name = kasprintf(GFP_NOWAIT,
-				 "dma-kmalloc-%d", s->objsize);
+				 "dma-kmalloc-%d", s->object_size);
 
 			BUG_ON(!name);
 			kmalloc_dma_caches[i] = create_kmalloc_cache(name,
-				s->objsize, SLAB_CACHE_DMA);
+				s->object_size, SLAB_CACHE_DMA);
 		}
 	}
 #endif
@@ -3941,7 +3927,7 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
 		 * Adjust the object sizes so that we clear
 		 * the complete object on kzalloc.
 		 */
-		s->objsize = max(s->objsize, (int)size);
+		s->object_size = max(s->object_size, (int)size);
 		s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *)));
 
 		if (sysfs_slab_alias(s, name)) {
@@ -4500,30 +4486,31 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
 
 		for_each_possible_cpu(cpu) {
 			struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
-			int node = ACCESS_ONCE(c->node);
+			int node;
 			struct page *page;
 
-			if (node < 0)
-				continue;
 			page = ACCESS_ONCE(c->page);
-			if (page) {
-				if (flags & SO_TOTAL)
-					x = page->objects;
-				else if (flags & SO_OBJECTS)
-					x = page->inuse;
-				else
-					x = 1;
+			if (!page)
+				continue;
 
-				total += x;
-				nodes[node] += x;
-			}
-			page = c->partial;
+			node = page_to_nid(page);
+			if (flags & SO_TOTAL)
+				x = page->objects;
+			else if (flags & SO_OBJECTS)
+				x = page->inuse;
+			else
+				x = 1;
 
+			total += x;
+			nodes[node] += x;
+
+			page = ACCESS_ONCE(c->partial);
 			if (page) {
 				x = page->pobjects;
 				total += x;
 				nodes[node] += x;
 			}
+
 			per_cpu[node]++;
 		}
 	}
@@ -4623,7 +4610,7 @@ SLAB_ATTR_RO(align);
 
 static ssize_t object_size_show(struct kmem_cache *s, char *buf)
 {
-	return sprintf(buf, "%d\n", s->objsize);
+	return sprintf(buf, "%d\n", s->object_size);
 }
 SLAB_ATTR_RO(object_size);
 
@@ -5427,7 +5414,7 @@ __initcall(slab_sysfs_init);
 static void print_slabinfo_header(struct seq_file *m)
 {
 	seq_puts(m, "slabinfo - version: 2.1\n");
-	seq_puts(m, "# name            <active_objs> <num_objs> <objsize> "
+	seq_puts(m, "# name            <active_objs> <num_objs> <object_size> "
 		 "<objperslab> <pagesperslab>");
 	seq_puts(m, " : tunables <limit> <batchcount> <sharedfactor>");
 	seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>");
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 4c5ff7f..c85b559 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/pagemap.h>
 #include <linux/backing-dev.h>
+#include <linux/blkdev.h>
 #include <linux/pagevec.h>
 #include <linux/migrate.h>
 #include <linux/page_cgroup.h>
@@ -376,6 +377,7 @@ struct page *swapin_readahead(swp_entry_t entry, gfp_t gfp_mask,
 	unsigned long offset = swp_offset(entry);
 	unsigned long start_offset, end_offset;
 	unsigned long mask = (1UL << page_cluster) - 1;
+	struct blk_plug plug;
 
 	/* Read a page_cluster sized and aligned cluster around offset. */
 	start_offset = offset & ~mask;
@@ -383,6 +385,7 @@ struct page *swapin_readahead(swp_entry_t entry, gfp_t gfp_mask,
 	if (!start_offset)	/* First page is swap header. */
 		start_offset++;
 
+	blk_start_plug(&plug);
 	for (offset = start_offset; offset <= end_offset ; offset++) {
 		/* Ok, do the async read-ahead now */
 		page = read_swap_cache_async(swp_entry(swp_type(entry), offset),
@@ -391,6 +394,8 @@ struct page *swapin_readahead(swp_entry_t entry, gfp_t gfp_mask,
 			continue;
 		page_cache_release(page);
 	}
+	blk_finish_plug(&plug);
+
 	lru_add_drain();	/* Push any new pages onto the LRU now */
 	return read_swap_cache_async(entry, gfp_mask, vma, addr);
 }
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 71373d0..64408be 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -643,6 +643,19 @@ int reuse_swap_page(struct page *page)
 	return count <= 1;
 }
 
+int can_reuse_swap_page(struct page *page)
+{
+	int count;
+
+	VM_BUG_ON(!PageLocked(page));
+	if (unlikely(PageKsm(page)))
+		return 0;
+	count = page_mapcount(page);
+	if (count <= 1 && PageSwapCache(page))
+		count += page_swapcount(page);
+	return count <= 1;
+}
+
 /*
  * If swap is getting full, or if there are no more mappings of this page,
  * then try_to_free_swap is called to free its swap space.
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 2aad499..2bb90b1 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -413,11 +413,11 @@ nocache:
 		if (addr + size - 1 < addr)
 			goto overflow;
 
-		n = rb_next(&first->rb_node);
-		if (n)
-			first = rb_entry(n, struct vmap_area, rb_node);
-		else
+		if (list_is_last(&first->list, &vmap_area_list))
 			goto found;
+
+		first = list_entry(first->list.next,
+				struct vmap_area, list);
 	}
 
 found:
@@ -904,6 +904,14 @@ static void *vb_alloc(unsigned long size, gfp_t gfp_mask)
 
 	BUG_ON(size & ~PAGE_MASK);
 	BUG_ON(size > PAGE_SIZE*VMAP_MAX_ALLOC);
+	if (WARN_ON(size == 0)) {
+		/*
+		 * Allocating 0 bytes isn't what caller wants since
+		 * get_order(0) returns funny result. Just warn and terminate
+		 * early.
+		 */
+		return NULL;
+	}
 	order = get_order(size);
 
 again:
@@ -1280,7 +1288,7 @@ DEFINE_RWLOCK(vmlist_lock);
 struct vm_struct *vmlist;
 
 static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
-			      unsigned long flags, void *caller)
+			      unsigned long flags, const void *caller)
 {
 	vm->flags = flags;
 	vm->addr = (void *)va->va_start;
@@ -1306,7 +1314,7 @@ static void insert_vmalloc_vmlist(struct vm_struct *vm)
 }
 
 static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
-			      unsigned long flags, void *caller)
+			      unsigned long flags, const void *caller)
 {
 	setup_vmalloc_vm(vm, va, flags, caller);
 	insert_vmalloc_vmlist(vm);
@@ -1314,7 +1322,7 @@ static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
 
 static struct vm_struct *__get_vm_area_node(unsigned long size,
 		unsigned long align, unsigned long flags, unsigned long start,
-		unsigned long end, int node, gfp_t gfp_mask, void *caller)
+		unsigned long end, int node, gfp_t gfp_mask, const void *caller)
 {
 	struct vmap_area *va;
 	struct vm_struct *area;
@@ -1375,7 +1383,7 @@ EXPORT_SYMBOL_GPL(__get_vm_area);
 
 struct vm_struct *__get_vm_area_caller(unsigned long size, unsigned long flags,
 				       unsigned long start, unsigned long end,
-				       void *caller)
+				       const void *caller)
 {
 	return __get_vm_area_node(size, 1, flags, start, end, -1, GFP_KERNEL,
 				  caller);
@@ -1397,13 +1405,21 @@ struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
 }
 
 struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
-				void *caller)
+				const void *caller)
 {
 	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
 						-1, GFP_KERNEL, caller);
 }
 
-static struct vm_struct *find_vm_area(const void *addr)
+/**
+ *	find_vm_area  -  find a continuous kernel virtual area
+ *	@addr:		base address
+ *
+ *	Search for the kernel VM area starting at @addr, and return it.
+ *	It is up to the caller to do all required locking to keep the returned
+ *	pointer valid.
+ */
+struct vm_struct *find_vm_area(const void *addr)
 {
 	struct vmap_area *va;
 
@@ -1568,9 +1584,9 @@ EXPORT_SYMBOL(vmap);
 
 static void *__vmalloc_node(unsigned long size, unsigned long align,
 			    gfp_t gfp_mask, pgprot_t prot,
-			    int node, void *caller);
+			    int node, const void *caller);
 static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
-				 pgprot_t prot, int node, void *caller)
+				 pgprot_t prot, int node, const void *caller)
 {
 	const int order = 0;
 	struct page **pages;
@@ -1643,7 +1659,7 @@ fail:
  */
 void *__vmalloc_node_range(unsigned long size, unsigned long align,
 			unsigned long start, unsigned long end, gfp_t gfp_mask,
-			pgprot_t prot, int node, void *caller)
+			pgprot_t prot, int node, const void *caller)
 {
 	struct vm_struct *area;
 	void *addr;
@@ -1699,7 +1715,7 @@ fail:
  */
 static void *__vmalloc_node(unsigned long size, unsigned long align,
 			    gfp_t gfp_mask, pgprot_t prot,
-			    int node, void *caller)
+			    int node, const void *caller)
 {
 	return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
 				gfp_mask, prot, node, caller);
@@ -1975,9 +1991,7 @@ static int aligned_vwrite(char *buf, char *addr, unsigned long count)
  *	IOREMAP area is treated as memory hole and no copy is done.
  *
  *	If [addr...addr+count) doesn't includes any intersects with alive
- *	vm_struct area, returns 0.
- *	@buf should be kernel's buffer. Because	this function uses KM_USER0,
- *	the caller should guarantee KM_USER0 is not used.
+ *	vm_struct area, returns 0. @buf should be kernel's buffer.
  *
  *	Note: In usual ops, vread() is never necessary because the caller
  *	should know vmalloc() area is valid and can use memcpy().
@@ -2051,9 +2065,7 @@ finished:
  *	IOREMAP area is treated as memory hole and no copy is done.
  *
  *	If [addr...addr+count) doesn't includes any intersects with alive
- *	vm_struct area, returns 0.
- *	@buf should be kernel's buffer. Because	this function uses KM_USER0,
- *	the caller should guarantee KM_USER0 is not used.
+ *	vm_struct area, returns 0. @buf should be kernel's buffer.
  *
  *	Note: In usual ops, vwrite() is never necessary because the caller
  *	should know vmalloc() area is valid and can use memcpy().
diff --git a/mm/vmscan.c b/mm/vmscan.c
index eeb3bc9..45950f5 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -720,9 +720,19 @@ static unsigned long shrink_page_list(struct list_head *page_list,
 			(PageSwapCache(page) && (sc->gfp_mask & __GFP_IO));
 
 		if (PageWriteback(page)) {
-			nr_writeback++;
-			unlock_page(page);
-			goto keep;
+			/*
+			 * memcg doesn't have any dirty pages throttling so we
+			 * could easily OOM just because too many pages are in
+			 * writeback from reclaim and there is nothing else to
+			 * reclaim.
+			 */
+			if (!global_reclaim(sc) && PageReclaim(page))
+				wait_on_page_writeback(page);
+			else {
+				nr_writeback++;
+				unlock_page(page);
+				goto keep;
+			}
 		}
 
 		references = page_check_references(page, sc);
@@ -2955,14 +2965,17 @@ int kswapd_run(int nid)
 }
 
 /*
- * Called by memory hotplug when all memory in a node is offlined.
+ * Called by memory hotplug when all memory in a node is offlined.  Caller must
+ * hold lock_memory_hotplug().
  */
 void kswapd_stop(int nid)
 {
 	struct task_struct *kswapd = NODE_DATA(nid)->kswapd;
 
-	if (kswapd)
+	if (kswapd) {
 		kthread_stop(kswapd);
+		NODE_DATA(nid)->kswapd = NULL;
+	}
 }
 
 static int __init kswapd_init(void)
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 1bbbbd9..35e0cee 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -767,6 +767,7 @@ const char * const vmstat_text[] = {
 	"compact_stall",
 	"compact_fail",
 	"compact_success",
+	"compact_rescued_unmovable_blocks",
 #endif
 
 #ifdef CONFIG_HUGETLB_PAGE
diff --git a/net/9p/client.c b/net/9p/client.c
index a170893..8260f13 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -1548,7 +1548,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
 			kernel_buf = 1;
 			indata = data;
 		} else
-			indata = (char *)udata;
+			indata = (__force char *)udata;
 		/*
 		 * response header len is 11
 		 * PDU Header(7) + IO Size (4)
diff --git a/net/atm/lec.c b/net/atm/lec.c
index a7d1721..2e3d942 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -231,9 +231,11 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
 	if (skb_headroom(skb) < 2) {
 		pr_debug("reallocating skb\n");
 		skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
-		kfree_skb(skb);
-		if (skb2 == NULL)
+		if (unlikely(!skb2)) {
+			kfree_skb(skb);
 			return NETDEV_TX_OK;
+		}
+		consume_skb(skb);
 		skb = skb2;
 	}
 	skb_push(skb, 2);
@@ -1602,7 +1604,7 @@ static void lec_arp_expire_vcc(unsigned long data)
 {
 	unsigned long flags;
 	struct lec_arp_table *to_remove = (struct lec_arp_table *)data;
-	struct lec_priv *priv = (struct lec_priv *)to_remove->priv;
+	struct lec_priv *priv = to_remove->priv;
 
 	del_timer(&to_remove->timer);
 
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
index ce1e59f..226dca9 100644
--- a/net/atm/pppoatm.c
+++ b/net/atm/pppoatm.c
@@ -283,7 +283,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
 				kfree_skb(n);
 				goto nospace;
 			}
-			kfree_skb(skb);
+			consume_skb(skb);
 			skb = n;
 			if (skb == NULL)
 				return DROP_PACKET;
diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c
index be8a25e..be2acab 100644
--- a/net/ax25/ax25_out.c
+++ b/net/ax25/ax25_out.c
@@ -350,7 +350,7 @@ void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
 		if (skb->sk != NULL)
 			skb_set_owner_w(skbn, skb->sk);
 
-		kfree_skb(skb);
+		consume_skb(skb);
 		skb = skbn;
 	}
 
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index a655880..d390977 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -474,7 +474,7 @@ struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
 		if (skb->sk != NULL)
 			skb_set_owner_w(skbn, skb->sk);
 
-		kfree_skb(skb);
+		consume_skb(skb);
 
 		skb = skbn;
 	}
diff --git a/net/batman-adv/bat_algo.h b/net/batman-adv/bat_algo.h
index 9852a68..a0ba3bf 100644
--- a/net/batman-adv/bat_algo.h
+++ b/net/batman-adv/bat_algo.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,12 +15,11 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_BAT_ALGO_H_
 #define _NET_BATMAN_ADV_BAT_ALGO_H_
 
-int bat_iv_init(void);
+int batadv_iv_init(void);
 
 #endif /* _NET_BATMAN_ADV_BAT_ALGO_H_ */
diff --git a/net/batman-adv/bat_debugfs.c b/net/batman-adv/bat_debugfs.c
index 3b588f8..03f09f0 100644
--- a/net/batman-adv/bat_debugfs.c
+++ b/net/batman-adv/bat_debugfs.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -34,25 +32,25 @@
 #include "icmp_socket.h"
 #include "bridge_loop_avoidance.h"
 
-static struct dentry *bat_debugfs;
+static struct dentry *batadv_debugfs;
 
 #ifdef CONFIG_BATMAN_ADV_DEBUG
-#define LOG_BUFF_MASK (log_buff_len-1)
+#define LOG_BUFF_MASK (batadv_log_buff_len - 1)
 #define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK])
 
-static int log_buff_len = LOG_BUF_LEN;
+static int batadv_log_buff_len = LOG_BUF_LEN;
 
-static void emit_log_char(struct debug_log *debug_log, char c)
+static void batadv_emit_log_char(struct debug_log *debug_log, char c)
 {
 	LOG_BUFF(debug_log->log_end) = c;
 	debug_log->log_end++;
 
-	if (debug_log->log_end - debug_log->log_start > log_buff_len)
-		debug_log->log_start = debug_log->log_end - log_buff_len;
+	if (debug_log->log_end - debug_log->log_start > batadv_log_buff_len)
+		debug_log->log_start = debug_log->log_end - batadv_log_buff_len;
 }
 
 __printf(2, 3)
-static int fdebug_log(struct debug_log *debug_log, const char *fmt, ...)
+static int batadv_fdebug_log(struct debug_log *debug_log, const char *fmt, ...)
 {
 	va_list args;
 	static char debug_log_buf[256];
@@ -67,7 +65,7 @@ static int fdebug_log(struct debug_log *debug_log, const char *fmt, ...)
 	va_end(args);
 
 	for (p = debug_log_buf; *p != 0; p++)
-		emit_log_char(debug_log, *p);
+		batadv_emit_log_char(debug_log, *p);
 
 	spin_unlock_bh(&debug_log->lock);
 
@@ -76,36 +74,36 @@ static int fdebug_log(struct debug_log *debug_log, const char *fmt, ...)
 	return 0;
 }
 
-int debug_log(struct bat_priv *bat_priv, const char *fmt, ...)
+int batadv_debug_log(struct bat_priv *bat_priv, const char *fmt, ...)
 {
 	va_list args;
 	char tmp_log_buf[256];
 
 	va_start(args, fmt);
 	vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
-	fdebug_log(bat_priv->debug_log, "[%10u] %s",
-		   jiffies_to_msecs(jiffies), tmp_log_buf);
+	batadv_fdebug_log(bat_priv->debug_log, "[%10u] %s",
+			  jiffies_to_msecs(jiffies), tmp_log_buf);
 	va_end(args);
 
 	return 0;
 }
 
-static int log_open(struct inode *inode, struct file *file)
+static int batadv_log_open(struct inode *inode, struct file *file)
 {
 	nonseekable_open(inode, file);
 	file->private_data = inode->i_private;
-	inc_module_count();
+	batadv_inc_module_count();
 	return 0;
 }
 
-static int log_release(struct inode *inode, struct file *file)
+static int batadv_log_release(struct inode *inode, struct file *file)
 {
-	dec_module_count();
+	batadv_dec_module_count();
 	return 0;
 }
 
-static ssize_t log_read(struct file *file, char __user *buf,
-			size_t count, loff_t *ppos)
+static ssize_t batadv_log_read(struct file *file, char __user *buf,
+			       size_t count, loff_t *ppos)
 {
 	struct bat_priv *bat_priv = file->private_data;
 	struct debug_log *debug_log = bat_priv->debug_log;
@@ -158,7 +156,7 @@ static ssize_t log_read(struct file *file, char __user *buf,
 	return error;
 }
 
-static unsigned int log_poll(struct file *file, poll_table *wait)
+static unsigned int batadv_log_poll(struct file *file, poll_table *wait)
 {
 	struct bat_priv *bat_priv = file->private_data;
 	struct debug_log *debug_log = bat_priv->debug_log;
@@ -171,15 +169,15 @@ static unsigned int log_poll(struct file *file, poll_table *wait)
 	return 0;
 }
 
-static const struct file_operations log_fops = {
-	.open           = log_open,
-	.release        = log_release,
-	.read           = log_read,
-	.poll           = log_poll,
+static const struct file_operations batadv_log_fops = {
+	.open           = batadv_log_open,
+	.release        = batadv_log_release,
+	.read           = batadv_log_read,
+	.poll           = batadv_log_poll,
 	.llseek         = no_llseek,
 };
 
-static int debug_log_setup(struct bat_priv *bat_priv)
+static int batadv_debug_log_setup(struct bat_priv *bat_priv)
 {
 	struct dentry *d;
 
@@ -194,75 +192,77 @@ static int debug_log_setup(struct bat_priv *bat_priv)
 	init_waitqueue_head(&bat_priv->debug_log->queue_wait);
 
 	d = debugfs_create_file("log", S_IFREG | S_IRUSR,
-				bat_priv->debug_dir, bat_priv, &log_fops);
-	if (d)
+				bat_priv->debug_dir, bat_priv,
+				&batadv_log_fops);
+	if (!d)
 		goto err;
 
 	return 0;
 
 err:
-	return 1;
+	return -ENOMEM;
 }
 
-static void debug_log_cleanup(struct bat_priv *bat_priv)
+static void batadv_debug_log_cleanup(struct bat_priv *bat_priv)
 {
 	kfree(bat_priv->debug_log);
 	bat_priv->debug_log = NULL;
 }
 #else /* CONFIG_BATMAN_ADV_DEBUG */
-static int debug_log_setup(struct bat_priv *bat_priv)
+static int batadv_debug_log_setup(struct bat_priv *bat_priv)
 {
 	bat_priv->debug_log = NULL;
 	return 0;
 }
 
-static void debug_log_cleanup(struct bat_priv *bat_priv)
+static void batadv_debug_log_cleanup(struct bat_priv *bat_priv)
 {
 	return;
 }
 #endif
 
-static int bat_algorithms_open(struct inode *inode, struct file *file)
+static int batadv_algorithms_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, bat_algo_seq_print_text, NULL);
+	return single_open(file, batadv_algo_seq_print_text, NULL);
 }
 
-static int originators_open(struct inode *inode, struct file *file)
+static int batadv_originators_open(struct inode *inode, struct file *file)
 {
 	struct net_device *net_dev = (struct net_device *)inode->i_private;
-	return single_open(file, orig_seq_print_text, net_dev);
+	return single_open(file, batadv_orig_seq_print_text, net_dev);
 }
 
-static int gateways_open(struct inode *inode, struct file *file)
+static int batadv_gateways_open(struct inode *inode, struct file *file)
 {
 	struct net_device *net_dev = (struct net_device *)inode->i_private;
-	return single_open(file, gw_client_seq_print_text, net_dev);
+	return single_open(file, batadv_gw_client_seq_print_text, net_dev);
 }
 
-static int transtable_global_open(struct inode *inode, struct file *file)
+static int batadv_transtable_global_open(struct inode *inode, struct file *file)
 {
 	struct net_device *net_dev = (struct net_device *)inode->i_private;
-	return single_open(file, tt_global_seq_print_text, net_dev);
+	return single_open(file, batadv_tt_global_seq_print_text, net_dev);
 }
 
 #ifdef CONFIG_BATMAN_ADV_BLA
-static int bla_claim_table_open(struct inode *inode, struct file *file)
+static int batadv_bla_claim_table_open(struct inode *inode, struct file *file)
 {
 	struct net_device *net_dev = (struct net_device *)inode->i_private;
-	return single_open(file, bla_claim_table_seq_print_text, net_dev);
+	return single_open(file, batadv_bla_claim_table_seq_print_text,
+			   net_dev);
 }
 #endif
 
-static int transtable_local_open(struct inode *inode, struct file *file)
+static int batadv_transtable_local_open(struct inode *inode, struct file *file)
 {
 	struct net_device *net_dev = (struct net_device *)inode->i_private;
-	return single_open(file, tt_local_seq_print_text, net_dev);
+	return single_open(file, batadv_tt_local_seq_print_text, net_dev);
 }
 
-static int vis_data_open(struct inode *inode, struct file *file)
+static int batadv_vis_data_open(struct inode *inode, struct file *file)
 {
 	struct net_device *net_dev = (struct net_device *)inode->i_private;
-	return single_open(file, vis_seq_print_text, net_dev);
+	return single_open(file, batadv_vis_seq_print_text, net_dev);
 }
 
 struct bat_debuginfo {
@@ -270,56 +270,56 @@ struct bat_debuginfo {
 	const struct file_operations fops;
 };
 
-#define BAT_DEBUGINFO(_name, _mode, _open)	\
-struct bat_debuginfo bat_debuginfo_##_name = {	\
-	.attr = { .name = __stringify(_name),	\
-		  .mode = _mode, },		\
-	.fops = { .owner = THIS_MODULE,		\
-		  .open = _open,		\
-		  .read	= seq_read,		\
-		  .llseek = seq_lseek,		\
-		  .release = single_release,	\
-		}				\
+#define BAT_DEBUGINFO(_name, _mode, _open)		\
+struct bat_debuginfo batadv_debuginfo_##_name = {	\
+	.attr = { .name = __stringify(_name),		\
+		  .mode = _mode, },			\
+	.fops = { .owner = THIS_MODULE,			\
+		  .open = _open,			\
+		  .read	= seq_read,			\
+		  .llseek = seq_lseek,			\
+		  .release = single_release,		\
+		}					\
 };
 
-static BAT_DEBUGINFO(routing_algos, S_IRUGO, bat_algorithms_open);
-static BAT_DEBUGINFO(originators, S_IRUGO, originators_open);
-static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open);
-static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open);
+static BAT_DEBUGINFO(routing_algos, S_IRUGO, batadv_algorithms_open);
+static BAT_DEBUGINFO(originators, S_IRUGO, batadv_originators_open);
+static BAT_DEBUGINFO(gateways, S_IRUGO, batadv_gateways_open);
+static BAT_DEBUGINFO(transtable_global, S_IRUGO, batadv_transtable_global_open);
 #ifdef CONFIG_BATMAN_ADV_BLA
-static BAT_DEBUGINFO(bla_claim_table, S_IRUGO, bla_claim_table_open);
+static BAT_DEBUGINFO(bla_claim_table, S_IRUGO, batadv_bla_claim_table_open);
 #endif
-static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open);
-static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open);
+static BAT_DEBUGINFO(transtable_local, S_IRUGO, batadv_transtable_local_open);
+static BAT_DEBUGINFO(vis_data, S_IRUGO, batadv_vis_data_open);
 
-static struct bat_debuginfo *mesh_debuginfos[] = {
-	&bat_debuginfo_originators,
-	&bat_debuginfo_gateways,
-	&bat_debuginfo_transtable_global,
+static struct bat_debuginfo *batadv_mesh_debuginfos[] = {
+	&batadv_debuginfo_originators,
+	&batadv_debuginfo_gateways,
+	&batadv_debuginfo_transtable_global,
 #ifdef CONFIG_BATMAN_ADV_BLA
-	&bat_debuginfo_bla_claim_table,
+	&batadv_debuginfo_bla_claim_table,
 #endif
-	&bat_debuginfo_transtable_local,
-	&bat_debuginfo_vis_data,
+	&batadv_debuginfo_transtable_local,
+	&batadv_debuginfo_vis_data,
 	NULL,
 };
 
-void debugfs_init(void)
+void batadv_debugfs_init(void)
 {
 	struct bat_debuginfo *bat_debug;
 	struct dentry *file;
 
-	bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL);
-	if (bat_debugfs == ERR_PTR(-ENODEV))
-		bat_debugfs = NULL;
+	batadv_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL);
+	if (batadv_debugfs == ERR_PTR(-ENODEV))
+		batadv_debugfs = NULL;
 
-	if (!bat_debugfs)
+	if (!batadv_debugfs)
 		goto out;
 
-	bat_debug = &bat_debuginfo_routing_algos;
+	bat_debug = &batadv_debuginfo_routing_algos;
 	file = debugfs_create_file(bat_debug->attr.name,
 				   S_IFREG | bat_debug->attr.mode,
-				   bat_debugfs, NULL, &bat_debug->fops);
+				   batadv_debugfs, NULL, &bat_debug->fops);
 	if (!file)
 		pr_err("Can't add debugfs file: %s\n", bat_debug->attr.name);
 
@@ -327,31 +327,34 @@ out:
 	return;
 }
 
-void debugfs_destroy(void)
+void batadv_debugfs_destroy(void)
 {
-	if (bat_debugfs) {
-		debugfs_remove_recursive(bat_debugfs);
-		bat_debugfs = NULL;
+	if (batadv_debugfs) {
+		debugfs_remove_recursive(batadv_debugfs);
+		batadv_debugfs = NULL;
 	}
 }
 
-int debugfs_add_meshif(struct net_device *dev)
+int batadv_debugfs_add_meshif(struct net_device *dev)
 {
 	struct bat_priv *bat_priv = netdev_priv(dev);
 	struct bat_debuginfo **bat_debug;
 	struct dentry *file;
 
-	if (!bat_debugfs)
+	if (!batadv_debugfs)
 		goto out;
 
-	bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs);
+	bat_priv->debug_dir = debugfs_create_dir(dev->name, batadv_debugfs);
 	if (!bat_priv->debug_dir)
 		goto out;
 
-	bat_socket_setup(bat_priv);
-	debug_log_setup(bat_priv);
+	if (batadv_socket_setup(bat_priv) < 0)
+		goto rem_attr;
+
+	if (batadv_debug_log_setup(bat_priv) < 0)
+		goto rem_attr;
 
-	for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) {
+	for (bat_debug = batadv_mesh_debuginfos; *bat_debug; ++bat_debug) {
 		file = debugfs_create_file(((*bat_debug)->attr).name,
 					  S_IFREG | ((*bat_debug)->attr).mode,
 					  bat_priv->debug_dir,
@@ -375,13 +378,13 @@ out:
 #endif /* CONFIG_DEBUG_FS */
 }
 
-void debugfs_del_meshif(struct net_device *dev)
+void batadv_debugfs_del_meshif(struct net_device *dev)
 {
 	struct bat_priv *bat_priv = netdev_priv(dev);
 
-	debug_log_cleanup(bat_priv);
+	batadv_debug_log_cleanup(bat_priv);
 
-	if (bat_debugfs) {
+	if (batadv_debugfs) {
 		debugfs_remove_recursive(bat_priv->debug_dir);
 		bat_priv->debug_dir = NULL;
 	}
diff --git a/net/batman-adv/bat_debugfs.h b/net/batman-adv/bat_debugfs.h
index d605c67..eb0d576 100644
--- a/net/batman-adv/bat_debugfs.h
+++ b/net/batman-adv/bat_debugfs.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,18 +15,16 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
-
 #ifndef _NET_BATMAN_ADV_DEBUGFS_H_
 #define _NET_BATMAN_ADV_DEBUGFS_H_
 
 #define DEBUGFS_BAT_SUBDIR "batman_adv"
 
-void debugfs_init(void);
-void debugfs_destroy(void);
-int debugfs_add_meshif(struct net_device *dev);
-void debugfs_del_meshif(struct net_device *dev);
+void batadv_debugfs_init(void);
+void batadv_debugfs_destroy(void);
+int batadv_debugfs_add_meshif(struct net_device *dev);
+void batadv_debugfs_del_meshif(struct net_device *dev);
 
 #endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index dc53798..ca64665 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -30,15 +28,16 @@
 #include "send.h"
 #include "bat_algo.h"
 
-static struct neigh_node *bat_iv_ogm_neigh_new(struct hard_iface *hard_iface,
-					       const uint8_t *neigh_addr,
-					       struct orig_node *orig_node,
-					       struct orig_node *orig_neigh,
-					       uint32_t seqno)
+static struct neigh_node *batadv_iv_ogm_neigh_new(struct hard_iface *hard_iface,
+						  const uint8_t *neigh_addr,
+						  struct orig_node *orig_node,
+						  struct orig_node *orig_neigh,
+						  __be32 seqno)
 {
 	struct neigh_node *neigh_node;
 
-	neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr, seqno);
+	neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr,
+					   ntohl(seqno));
 	if (!neigh_node)
 		goto out;
 
@@ -55,11 +54,11 @@ out:
 	return neigh_node;
 }
 
-static int bat_iv_ogm_iface_enable(struct hard_iface *hard_iface)
+static int batadv_iv_ogm_iface_enable(struct hard_iface *hard_iface)
 {
 	struct batman_ogm_packet *batman_ogm_packet;
 	uint32_t random_seqno;
-	int res = -1;
+	int res = -ENOMEM;
 
 	/* randomize initial seqno to avoid collision */
 	get_random_bytes(&random_seqno, sizeof(random_seqno));
@@ -86,13 +85,13 @@ out:
 	return res;
 }
 
-static void bat_iv_ogm_iface_disable(struct hard_iface *hard_iface)
+static void batadv_iv_ogm_iface_disable(struct hard_iface *hard_iface)
 {
 	kfree(hard_iface->packet_buff);
 	hard_iface->packet_buff = NULL;
 }
 
-static void bat_iv_ogm_iface_update_mac(struct hard_iface *hard_iface)
+static void batadv_iv_ogm_iface_update_mac(struct hard_iface *hard_iface)
 {
 	struct batman_ogm_packet *batman_ogm_packet;
 
@@ -103,7 +102,7 @@ static void bat_iv_ogm_iface_update_mac(struct hard_iface *hard_iface)
 	       hard_iface->net_dev->dev_addr, ETH_ALEN);
 }
 
-static void bat_iv_ogm_primary_iface_set(struct hard_iface *hard_iface)
+static void batadv_iv_ogm_primary_iface_set(struct hard_iface *hard_iface)
 {
 	struct batman_ogm_packet *batman_ogm_packet;
 
@@ -113,7 +112,8 @@ static void bat_iv_ogm_primary_iface_set(struct hard_iface *hard_iface)
 }
 
 /* when do we schedule our own ogm to be sent */
-static unsigned long bat_iv_ogm_emit_send_time(const struct bat_priv *bat_priv)
+static unsigned long
+batadv_iv_ogm_emit_send_time(const struct bat_priv *bat_priv)
 {
 	return jiffies + msecs_to_jiffies(
 		   atomic_read(&bat_priv->orig_interval) -
@@ -121,30 +121,33 @@ static unsigned long bat_iv_ogm_emit_send_time(const struct bat_priv *bat_priv)
 }
 
 /* when do we schedule a ogm packet to be sent */
-static unsigned long bat_iv_ogm_fwd_send_time(void)
+static unsigned long batadv_iv_ogm_fwd_send_time(void)
 {
 	return jiffies + msecs_to_jiffies(random32() % (JITTER/2));
 }
 
 /* apply hop penalty for a normal link */
-static uint8_t hop_penalty(uint8_t tq, const struct bat_priv *bat_priv)
+static uint8_t batadv_hop_penalty(uint8_t tq, const struct bat_priv *bat_priv)
 {
 	int hop_penalty = atomic_read(&bat_priv->hop_penalty);
 	return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE);
 }
 
 /* is there another aggregated packet here? */
-static int bat_iv_ogm_aggr_packet(int buff_pos, int packet_len,
-				  int tt_num_changes)
+static int batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
+				     int tt_num_changes)
 {
-	int next_buff_pos = buff_pos + BATMAN_OGM_HLEN + tt_len(tt_num_changes);
+	int next_buff_pos = 0;
+
+	next_buff_pos += buff_pos + BATMAN_OGM_HLEN;
+	next_buff_pos += batadv_tt_len(tt_num_changes);
 
 	return (next_buff_pos <= packet_len) &&
 		(next_buff_pos <= MAX_AGGREGATION_BYTES);
 }
 
 /* send a batman ogm to a given interface */
-static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet,
+static void batadv_iv_ogm_send_to_if(struct forw_packet *forw_packet,
 				  struct hard_iface *hard_iface)
 {
 	struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
@@ -162,11 +165,12 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet,
 	batman_ogm_packet = (struct batman_ogm_packet *)forw_packet->skb->data;
 
 	/* adjust all flags and log packets */
-	while (bat_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len,
-				      batman_ogm_packet->tt_num_changes)) {
+	while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len,
+					 batman_ogm_packet->tt_num_changes)) {
 
 		/* we might have aggregated direct link packets with an
-		 * ordinary base packet */
+		 * ordinary base packet
+		 */
 		if ((forw_packet->direct_link_flags & (1 << packet_num)) &&
 		    (forw_packet->if_incoming == hard_iface))
 			batman_ogm_packet->flags |= DIRECTLINK;
@@ -176,19 +180,19 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet,
 		fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?
 							    "Sending own" :
 							    "Forwarding"));
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM]\n",
-			fwd_str, (packet_num > 0 ? "aggregated " : ""),
-			batman_ogm_packet->orig,
-			ntohl(batman_ogm_packet->seqno),
-			batman_ogm_packet->tq, batman_ogm_packet->header.ttl,
-			(batman_ogm_packet->flags & DIRECTLINK ?
-			 "on" : "off"),
-			batman_ogm_packet->ttvn, hard_iface->net_dev->name,
-			hard_iface->net_dev->dev_addr);
-
-		buff_pos += BATMAN_OGM_HLEN +
-				tt_len(batman_ogm_packet->tt_num_changes);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM]\n",
+			   fwd_str, (packet_num > 0 ? "aggregated " : ""),
+			   batman_ogm_packet->orig,
+			   ntohl(batman_ogm_packet->seqno),
+			   batman_ogm_packet->tq, batman_ogm_packet->header.ttl,
+			   (batman_ogm_packet->flags & DIRECTLINK ?
+			    "on" : "off"),
+			   batman_ogm_packet->ttvn, hard_iface->net_dev->name,
+			   hard_iface->net_dev->dev_addr);
+
+		buff_pos += BATMAN_OGM_HLEN;
+		buff_pos += batadv_tt_len(batman_ogm_packet->tt_num_changes);
 		packet_num++;
 		batman_ogm_packet = (struct batman_ogm_packet *)
 					(forw_packet->skb->data + buff_pos);
@@ -196,12 +200,16 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet,
 
 	/* create clone because function is called more than once */
 	skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
-	if (skb)
-		send_skb_packet(skb, hard_iface, broadcast_addr);
+	if (skb) {
+		batadv_inc_counter(bat_priv, BAT_CNT_MGMT_TX);
+		batadv_add_counter(bat_priv, BAT_CNT_MGMT_TX_BYTES,
+				   skb->len + ETH_HLEN);
+		batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
+	}
 }
 
 /* send a batman ogm packet */
-static void bat_iv_ogm_emit(struct forw_packet *forw_packet)
+static void batadv_iv_ogm_emit(struct forw_packet *forw_packet)
 {
 	struct hard_iface *hard_iface;
 	struct net_device *soft_iface;
@@ -225,28 +233,30 @@ static void bat_iv_ogm_emit(struct forw_packet *forw_packet)
 	if (forw_packet->if_incoming->if_status != IF_ACTIVE)
 		goto out;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
-	/* multihomed peer assumed */
-	/* non-primary OGMs are only broadcasted on their interface */
+	/* multihomed peer assumed
+	 * non-primary OGMs are only broadcasted on their interface
+	 */
 	if ((directlink && (batman_ogm_packet->header.ttl == 1)) ||
 	    (forw_packet->own && (forw_packet->if_incoming != primary_if))) {
 
 		/* FIXME: what about aggregated packets ? */
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"%s packet (originator %pM, seqno %u, TTL %d) on interface %s [%pM]\n",
-			(forw_packet->own ? "Sending own" : "Forwarding"),
-			batman_ogm_packet->orig,
-			ntohl(batman_ogm_packet->seqno),
-			batman_ogm_packet->header.ttl,
-			forw_packet->if_incoming->net_dev->name,
-			forw_packet->if_incoming->net_dev->dev_addr);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "%s packet (originator %pM, seqno %u, TTL %d) on interface %s [%pM]\n",
+			   (forw_packet->own ? "Sending own" : "Forwarding"),
+			   batman_ogm_packet->orig,
+			   ntohl(batman_ogm_packet->seqno),
+			   batman_ogm_packet->header.ttl,
+			   forw_packet->if_incoming->net_dev->name,
+			   forw_packet->if_incoming->net_dev->dev_addr);
 
 		/* skb is only used once and than forw_packet is free'd */
-		send_skb_packet(forw_packet->skb, forw_packet->if_incoming,
-				broadcast_addr);
+		batadv_send_skb_packet(forw_packet->skb,
+				       forw_packet->if_incoming,
+				       batadv_broadcast_addr);
 		forw_packet->skb = NULL;
 
 		goto out;
@@ -254,27 +264,27 @@ static void bat_iv_ogm_emit(struct forw_packet *forw_packet)
 
 	/* broadcast on every interface */
 	rcu_read_lock();
-	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 		if (hard_iface->soft_iface != soft_iface)
 			continue;
 
-		bat_iv_ogm_send_to_if(forw_packet, hard_iface);
+		batadv_iv_ogm_send_to_if(forw_packet, hard_iface);
 	}
 	rcu_read_unlock();
 
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 }
 
 /* return true if new_packet can be aggregated with forw_packet */
-static bool bat_iv_ogm_can_aggregate(const struct batman_ogm_packet
-							*new_batman_ogm_packet,
-				     struct bat_priv *bat_priv,
-				     int packet_len, unsigned long send_time,
-				     bool directlink,
-				     const struct hard_iface *if_incoming,
-				     const struct forw_packet *forw_packet)
+static bool
+batadv_iv_ogm_can_aggregate(const struct batman_ogm_packet *new_bat_ogm_packet,
+			    struct bat_priv *bat_priv,
+			    int packet_len, unsigned long send_time,
+			    bool directlink,
+			    const struct hard_iface *if_incoming,
+			    const struct forw_packet *forw_packet)
 {
 	struct batman_ogm_packet *batman_ogm_packet;
 	int aggregated_bytes = forw_packet->packet_len + packet_len;
@@ -283,41 +293,39 @@ static bool bat_iv_ogm_can_aggregate(const struct batman_ogm_packet
 
 	batman_ogm_packet = (struct batman_ogm_packet *)forw_packet->skb->data;
 
-	/**
-	 * we can aggregate the current packet to this aggregated packet
+	/* we can aggregate the current packet to this aggregated packet
 	 * if:
 	 *
 	 * - the send time is within our MAX_AGGREGATION_MS time
 	 * - the resulting packet wont be bigger than
 	 *   MAX_AGGREGATION_BYTES
 	 */
-
 	if (time_before(send_time, forw_packet->send_time) &&
 	    time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS),
 					forw_packet->send_time) &&
 	    (aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
 
-		/**
-		 * check aggregation compatibility
+		/* check aggregation compatibility
 		 * -> direct link packets are broadcasted on
 		 *    their interface only
 		 * -> aggregate packet if the current packet is
 		 *    a "global" packet as well as the base
 		 *    packet
 		 */
-
-		primary_if = primary_if_get_selected(bat_priv);
+		primary_if = batadv_primary_if_get_selected(bat_priv);
 		if (!primary_if)
 			goto out;
 
 		/* packets without direct link flag and high TTL
-		 * are flooded through the net  */
+		 * are flooded through the net
+		 */
 		if ((!directlink) &&
 		    (!(batman_ogm_packet->flags & DIRECTLINK)) &&
 		    (batman_ogm_packet->header.ttl != 1) &&
 
 		    /* own packets originating non-primary
-		     * interfaces leave only that interface */
+		     * interfaces leave only that interface
+		     */
 		    ((!forw_packet->own) ||
 		     (forw_packet->if_incoming == primary_if))) {
 			res = true;
@@ -325,14 +333,16 @@ static bool bat_iv_ogm_can_aggregate(const struct batman_ogm_packet
 		}
 
 		/* if the incoming packet is sent via this one
-		 * interface only - we still can aggregate */
+		 * interface only - we still can aggregate
+		 */
 		if ((directlink) &&
-		    (new_batman_ogm_packet->header.ttl == 1) &&
+		    (new_bat_ogm_packet->header.ttl == 1) &&
 		    (forw_packet->if_incoming == if_incoming) &&
 
 		    /* packets from direct neighbors or
 		     * own secondary interface packets
-		     * (= secondary interface packets in general) */
+		     * (= secondary interface packets in general)
+		     */
 		    (batman_ogm_packet->flags & DIRECTLINK ||
 		     (forw_packet->own &&
 		      forw_packet->if_incoming != primary_if))) {
@@ -343,16 +353,16 @@ static bool bat_iv_ogm_can_aggregate(const struct batman_ogm_packet
 
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	return res;
 }
 
 /* create a new aggregated packet and add this packet to it */
-static void bat_iv_ogm_aggregate_new(const unsigned char *packet_buff,
-				     int packet_len, unsigned long send_time,
-				     bool direct_link,
-				     struct hard_iface *if_incoming,
-				     int own_packet)
+static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
+					int packet_len, unsigned long send_time,
+					bool direct_link,
+					struct hard_iface *if_incoming,
+					int own_packet)
 {
 	struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 	struct forw_packet *forw_packet_aggr;
@@ -364,8 +374,8 @@ static void bat_iv_ogm_aggregate_new(const unsigned char *packet_buff,
 	/* own packet should always be scheduled */
 	if (!own_packet) {
 		if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
-			bat_dbg(DBG_BATMAN, bat_priv,
-				"batman packet queue full\n");
+			batadv_dbg(DBG_BATMAN, bat_priv,
+				   "batman packet queue full\n");
 			goto out;
 		}
 	}
@@ -415,20 +425,20 @@ static void bat_iv_ogm_aggregate_new(const unsigned char *packet_buff,
 
 	/* start timer for this packet */
 	INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
-			  send_outstanding_bat_ogm_packet);
-	queue_delayed_work(bat_event_workqueue,
+			  batadv_send_outstanding_bat_ogm_packet);
+	queue_delayed_work(batadv_event_workqueue,
 			   &forw_packet_aggr->delayed_work,
 			   send_time - jiffies);
 
 	return;
 out:
-	hardif_free_ref(if_incoming);
+	batadv_hardif_free_ref(if_incoming);
 }
 
 /* aggregate a new packet into the existing ogm packet */
-static void bat_iv_ogm_aggregate(struct forw_packet *forw_packet_aggr,
-				 const unsigned char *packet_buff,
-				 int packet_len, bool direct_link)
+static void batadv_iv_ogm_aggregate(struct forw_packet *forw_packet_aggr,
+				    const unsigned char *packet_buff,
+				    int packet_len, bool direct_link)
 {
 	unsigned char *skb_buff;
 
@@ -443,13 +453,13 @@ static void bat_iv_ogm_aggregate(struct forw_packet *forw_packet_aggr,
 			(1 << forw_packet_aggr->num_packets);
 }
 
-static void bat_iv_ogm_queue_add(struct bat_priv *bat_priv,
-				 unsigned char *packet_buff,
-				 int packet_len, struct hard_iface *if_incoming,
-				 int own_packet, unsigned long send_time)
+static void batadv_iv_ogm_queue_add(struct bat_priv *bat_priv,
+				    unsigned char *packet_buff,
+				    int packet_len,
+				    struct hard_iface *if_incoming,
+				    int own_packet, unsigned long send_time)
 {
-	/**
-	 * _aggr -> pointer to the packet we want to aggregate with
+	/* _aggr -> pointer to the packet we want to aggregate with
 	 * _pos -> pointer to the position in the queue
 	 */
 	struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
@@ -466,11 +476,11 @@ static void bat_iv_ogm_queue_add(struct bat_priv *bat_priv,
 	if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) {
 		hlist_for_each_entry(forw_packet_pos, tmp_node,
 				     &bat_priv->forw_bat_list, list) {
-			if (bat_iv_ogm_can_aggregate(batman_ogm_packet,
-						     bat_priv, packet_len,
-						     send_time, direct_link,
-						     if_incoming,
-						     forw_packet_pos)) {
+			if (batadv_iv_ogm_can_aggregate(batman_ogm_packet,
+							bat_priv, packet_len,
+							send_time, direct_link,
+							if_incoming,
+							forw_packet_pos)) {
 				forw_packet_aggr = forw_packet_pos;
 				break;
 			}
@@ -478,13 +488,13 @@ static void bat_iv_ogm_queue_add(struct bat_priv *bat_priv,
 	}
 
 	/* nothing to aggregate with - either aggregation disabled or no
-	 * suitable aggregation packet found */
+	 * suitable aggregation packet found
+	 */
 	if (!forw_packet_aggr) {
 		/* the following section can run without the lock */
 		spin_unlock_bh(&bat_priv->forw_bat_list_lock);
 
-		/**
-		 * if we could not aggregate this packet with one of the others
+		/* if we could not aggregate this packet with one of the others
 		 * we hold it back for a while, so that it might be aggregated
 		 * later on
 		 */
@@ -492,28 +502,28 @@ static void bat_iv_ogm_queue_add(struct bat_priv *bat_priv,
 		    (atomic_read(&bat_priv->aggregated_ogms)))
 			send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);
 
-		bat_iv_ogm_aggregate_new(packet_buff, packet_len,
-					 send_time, direct_link,
-					 if_incoming, own_packet);
+		batadv_iv_ogm_aggregate_new(packet_buff, packet_len,
+					    send_time, direct_link,
+					    if_incoming, own_packet);
 	} else {
-		bat_iv_ogm_aggregate(forw_packet_aggr, packet_buff,
-				     packet_len, direct_link);
+		batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff,
+					packet_len, direct_link);
 		spin_unlock_bh(&bat_priv->forw_bat_list_lock);
 	}
 }
 
-static void bat_iv_ogm_forward(struct orig_node *orig_node,
-			       const struct ethhdr *ethhdr,
-			       struct batman_ogm_packet *batman_ogm_packet,
-			       bool is_single_hop_neigh,
-			       bool is_from_best_next_hop,
-			       struct hard_iface *if_incoming)
+static void batadv_iv_ogm_forward(struct orig_node *orig_node,
+				  const struct ethhdr *ethhdr,
+				  struct batman_ogm_packet *batman_ogm_packet,
+				  bool is_single_hop_neigh,
+				  bool is_from_best_next_hop,
+				  struct hard_iface *if_incoming)
 {
 	struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 	uint8_t tt_num_changes;
 
 	if (batman_ogm_packet->header.ttl <= 1) {
-		bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
+		batadv_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
 		return;
 	}
 
@@ -536,14 +546,12 @@ static void bat_iv_ogm_forward(struct orig_node *orig_node,
 	memcpy(batman_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
 
 	/* apply hop penalty */
-	batman_ogm_packet->tq = hop_penalty(batman_ogm_packet->tq, bat_priv);
-
-	bat_dbg(DBG_BATMAN, bat_priv,
-		"Forwarding packet: tq: %i, ttl: %i\n",
-		batman_ogm_packet->tq, batman_ogm_packet->header.ttl);
+	batman_ogm_packet->tq = batadv_hop_penalty(batman_ogm_packet->tq,
+						   bat_priv);
 
-	batman_ogm_packet->seqno = htonl(batman_ogm_packet->seqno);
-	batman_ogm_packet->tt_crc = htons(batman_ogm_packet->tt_crc);
+	batadv_dbg(DBG_BATMAN, bat_priv,
+		   "Forwarding packet: tq: %i, ttl: %i\n",
+		   batman_ogm_packet->tq, batman_ogm_packet->header.ttl);
 
 	/* switch of primaries first hop flag when forwarding */
 	batman_ogm_packet->flags &= ~PRIMARIES_FIRST_HOP;
@@ -552,31 +560,36 @@ static void bat_iv_ogm_forward(struct orig_node *orig_node,
 	else
 		batman_ogm_packet->flags &= ~DIRECTLINK;
 
-	bat_iv_ogm_queue_add(bat_priv, (unsigned char *)batman_ogm_packet,
-			     BATMAN_OGM_HLEN + tt_len(tt_num_changes),
-			     if_incoming, 0, bat_iv_ogm_fwd_send_time());
+	batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batman_ogm_packet,
+				BATMAN_OGM_HLEN + batadv_tt_len(tt_num_changes),
+				if_incoming, 0, batadv_iv_ogm_fwd_send_time());
 }
 
-static void bat_iv_ogm_schedule(struct hard_iface *hard_iface,
-				int tt_num_changes)
+static void batadv_iv_ogm_schedule(struct hard_iface *hard_iface)
 {
 	struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
 	struct batman_ogm_packet *batman_ogm_packet;
 	struct hard_iface *primary_if;
-	int vis_server;
+	int vis_server, tt_num_changes = 0;
 
 	vis_server = atomic_read(&bat_priv->vis_mode);
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
+
+	if (hard_iface == primary_if)
+		tt_num_changes = batadv_tt_append_diff(bat_priv,
+						       &hard_iface->packet_buff,
+						       &hard_iface->packet_len,
+						       BATMAN_OGM_HLEN);
 
 	batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
 
 	/* change sequence number to network order */
 	batman_ogm_packet->seqno =
 			htonl((uint32_t)atomic_read(&hard_iface->seqno));
+	atomic_inc(&hard_iface->seqno);
 
 	batman_ogm_packet->ttvn = atomic_read(&bat_priv->ttvn);
-	batman_ogm_packet->tt_crc = htons((uint16_t)
-						atomic_read(&bat_priv->tt_crc));
+	batman_ogm_packet->tt_crc = htons(bat_priv->tt_crc);
 	if (tt_num_changes >= 0)
 		batman_ogm_packet->tt_num_changes = tt_num_changes;
 
@@ -592,43 +605,43 @@ static void bat_iv_ogm_schedule(struct hard_iface *hard_iface,
 	else
 		batman_ogm_packet->gw_flags = NO_FLAGS;
 
-	atomic_inc(&hard_iface->seqno);
-
-	slide_own_bcast_window(hard_iface);
-	bat_iv_ogm_queue_add(bat_priv, hard_iface->packet_buff,
-			     hard_iface->packet_len, hard_iface, 1,
-			     bat_iv_ogm_emit_send_time(bat_priv));
+	batadv_slide_own_bcast_window(hard_iface);
+	batadv_iv_ogm_queue_add(bat_priv, hard_iface->packet_buff,
+				hard_iface->packet_len, hard_iface, 1,
+				batadv_iv_ogm_emit_send_time(bat_priv));
 
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 }
 
-static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv,
-				   struct orig_node *orig_node,
-				   const struct ethhdr *ethhdr,
-				   const struct batman_ogm_packet
-							*batman_ogm_packet,
-				   struct hard_iface *if_incoming,
-				   const unsigned char *tt_buff,
-				   int is_duplicate)
+static void
+batadv_iv_ogm_orig_update(struct bat_priv *bat_priv,
+			  struct orig_node *orig_node,
+			  const struct ethhdr *ethhdr,
+			  const struct batman_ogm_packet *batman_ogm_packet,
+			  struct hard_iface *if_incoming,
+			  const unsigned char *tt_buff,
+			  int is_duplicate)
 {
 	struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
 	struct neigh_node *router = NULL;
 	struct orig_node *orig_node_tmp;
 	struct hlist_node *node;
 	uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
+	uint8_t *neigh_addr;
 
-	bat_dbg(DBG_BATMAN, bat_priv,
-		"update_originator(): Searching and updating originator entry of received packet\n");
+	batadv_dbg(DBG_BATMAN, bat_priv,
+		   "update_originator(): Searching and updating originator entry of received packet\n");
 
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(tmp_neigh_node, node,
 				 &orig_node->neigh_list, list) {
-		if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
-		    (tmp_neigh_node->if_incoming == if_incoming) &&
-		     atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
+		neigh_addr = tmp_neigh_node->addr;
+		if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
+		    tmp_neigh_node->if_incoming == if_incoming &&
+		    atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
 			if (neigh_node)
-				neigh_node_free_ref(neigh_node);
+				batadv_neigh_node_free_ref(neigh_node);
 			neigh_node = tmp_neigh_node;
 			continue;
 		}
@@ -637,30 +650,31 @@ static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv,
 			continue;
 
 		spin_lock_bh(&tmp_neigh_node->lq_update_lock);
-		ring_buffer_set(tmp_neigh_node->tq_recv,
-				&tmp_neigh_node->tq_index, 0);
+		batadv_ring_buffer_set(tmp_neigh_node->tq_recv,
+				       &tmp_neigh_node->tq_index, 0);
 		tmp_neigh_node->tq_avg =
-			ring_buffer_avg(tmp_neigh_node->tq_recv);
+			batadv_ring_buffer_avg(tmp_neigh_node->tq_recv);
 		spin_unlock_bh(&tmp_neigh_node->lq_update_lock);
 	}
 
 	if (!neigh_node) {
 		struct orig_node *orig_tmp;
 
-		orig_tmp = get_orig_node(bat_priv, ethhdr->h_source);
+		orig_tmp = batadv_get_orig_node(bat_priv, ethhdr->h_source);
 		if (!orig_tmp)
 			goto unlock;
 
-		neigh_node = bat_iv_ogm_neigh_new(if_incoming, ethhdr->h_source,
-						  orig_node, orig_tmp,
-						  batman_ogm_packet->seqno);
+		neigh_node = batadv_iv_ogm_neigh_new(if_incoming,
+						     ethhdr->h_source,
+						     orig_node, orig_tmp,
+						     batman_ogm_packet->seqno);
 
-		orig_node_free_ref(orig_tmp);
+		batadv_orig_node_free_ref(orig_tmp);
 		if (!neigh_node)
 			goto unlock;
 	} else
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Updating existing last-hop neighbor of originator\n");
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Updating existing last-hop neighbor of originator\n");
 
 	rcu_read_unlock();
 
@@ -668,10 +682,10 @@ static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv,
 	neigh_node->last_seen = jiffies;
 
 	spin_lock_bh(&neigh_node->lq_update_lock);
-	ring_buffer_set(neigh_node->tq_recv,
-			&neigh_node->tq_index,
-			batman_ogm_packet->tq);
-	neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
+	batadv_ring_buffer_set(neigh_node->tq_recv,
+			       &neigh_node->tq_index,
+			       batman_ogm_packet->tq);
+	neigh_node->tq_avg = batadv_ring_buffer_avg(neigh_node->tq_recv);
 	spin_unlock_bh(&neigh_node->lq_update_lock);
 
 	if (!is_duplicate) {
@@ -679,11 +693,12 @@ static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv,
 		neigh_node->last_ttl = batman_ogm_packet->header.ttl;
 	}
 
-	bonding_candidate_add(orig_node, neigh_node);
+	batadv_bonding_candidate_add(orig_node, neigh_node);
 
 	/* if this neighbor already is our next hop there is nothing
-	 * to change */
-	router = orig_node_get_router(orig_node);
+	 * to change
+	 */
+	router = batadv_orig_node_get_router(orig_node);
 	if (router == neigh_node)
 		goto update_tt;
 
@@ -692,7 +707,8 @@ static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv,
 		goto update_tt;
 
 	/* if the TQ is the same and the link not more symmetric we
-	 * won't consider it either */
+	 * won't consider it either
+	 */
 	if (router && (neigh_node->tq_avg == router->tq_avg)) {
 		orig_node_tmp = router->orig_node;
 		spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
@@ -710,22 +726,23 @@ static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv,
 			goto update_tt;
 	}
 
-	update_route(bat_priv, orig_node, neigh_node);
+	batadv_update_route(bat_priv, orig_node, neigh_node);
 
 update_tt:
 	/* I have to check for transtable changes only if the OGM has been
-	 * sent through a primary interface */
+	 * sent through a primary interface
+	 */
 	if (((batman_ogm_packet->orig != ethhdr->h_source) &&
 	     (batman_ogm_packet->header.ttl > 2)) ||
 	    (batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
-		tt_update_orig(bat_priv, orig_node, tt_buff,
-			       batman_ogm_packet->tt_num_changes,
-			       batman_ogm_packet->ttvn,
-			       batman_ogm_packet->tt_crc);
+		batadv_tt_update_orig(bat_priv, orig_node, tt_buff,
+				      batman_ogm_packet->tt_num_changes,
+				      batman_ogm_packet->ttvn,
+				      ntohs(batman_ogm_packet->tt_crc));
 
 	if (orig_node->gw_flags != batman_ogm_packet->gw_flags)
-		gw_node_update(bat_priv, orig_node,
-			       batman_ogm_packet->gw_flags);
+		batadv_gw_node_update(bat_priv, orig_node,
+				      batman_ogm_packet->gw_flags);
 
 	orig_node->gw_flags = batman_ogm_packet->gw_flags;
 
@@ -733,7 +750,7 @@ update_tt:
 	if ((orig_node->gw_flags) &&
 	    (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) &&
 	    (atomic_read(&bat_priv->gw_sel_class) > 2))
-		gw_check_election(bat_priv, orig_node);
+		batadv_gw_check_election(bat_priv, orig_node);
 
 	goto out;
 
@@ -741,15 +758,15 @@ unlock:
 	rcu_read_unlock();
 out:
 	if (neigh_node)
-		neigh_node_free_ref(neigh_node);
+		batadv_neigh_node_free_ref(neigh_node);
 	if (router)
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 }
 
-static int bat_iv_ogm_calc_tq(struct orig_node *orig_node,
-			      struct orig_node *orig_neigh_node,
-			      struct batman_ogm_packet *batman_ogm_packet,
-			      struct hard_iface *if_incoming)
+static int batadv_iv_ogm_calc_tq(struct orig_node *orig_node,
+				 struct orig_node *orig_neigh_node,
+				 struct batman_ogm_packet *batman_ogm_packet,
+				 struct hard_iface *if_incoming)
 {
 	struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 	struct neigh_node *neigh_node = NULL, *tmp_neigh_node;
@@ -763,7 +780,8 @@ static int bat_iv_ogm_calc_tq(struct orig_node *orig_node,
 	hlist_for_each_entry_rcu(tmp_neigh_node, node,
 				 &orig_neigh_node->neigh_list, list) {
 
-		if (!compare_eth(tmp_neigh_node->addr, orig_neigh_node->orig))
+		if (!batadv_compare_eth(tmp_neigh_node->addr,
+					orig_neigh_node->orig))
 			continue;
 
 		if (tmp_neigh_node->if_incoming != if_incoming)
@@ -778,11 +796,11 @@ static int bat_iv_ogm_calc_tq(struct orig_node *orig_node,
 	rcu_read_unlock();
 
 	if (!neigh_node)
-		neigh_node = bat_iv_ogm_neigh_new(if_incoming,
-						  orig_neigh_node->orig,
-						  orig_neigh_node,
-						  orig_neigh_node,
-						  batman_ogm_packet->seqno);
+		neigh_node = batadv_iv_ogm_neigh_new(if_incoming,
+						     orig_neigh_node->orig,
+						     orig_neigh_node,
+						     orig_neigh_node,
+						     batman_ogm_packet->seqno);
 
 	if (!neigh_node)
 		goto out;
@@ -803,15 +821,17 @@ static int bat_iv_ogm_calc_tq(struct orig_node *orig_node,
 	total_count = (orig_eq_count > neigh_rq_count ?
 		       neigh_rq_count : orig_eq_count);
 
-	/* if we have too few packets (too less data) we set tq_own to zero */
-	/* if we receive too few packets it is not considered bidirectional */
+	/* if we have too few packets (too less data) we set tq_own to zero
+	 * if we receive too few packets it is not considered bidirectional
+	 */
 	if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
 	    (neigh_rq_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
 		tq_own = 0;
 	else
 		/* neigh_node->real_packet_count is never zero as we
 		 * only purge old information when getting new
-		 * information */
+		 * information
+		 */
 		tq_own = (TQ_MAX_VALUE * total_count) /	neigh_rq_count;
 
 	/* 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
@@ -831,19 +851,21 @@ static int bat_iv_ogm_calc_tq(struct orig_node *orig_node,
 							* tq_asym_penalty) /
 						(TQ_MAX_VALUE * TQ_MAX_VALUE));
 
-	bat_dbg(DBG_BATMAN, bat_priv,
-		"bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i\n",
-		orig_node->orig, orig_neigh_node->orig, total_count,
-		neigh_rq_count, tq_own,	tq_asym_penalty, batman_ogm_packet->tq);
+	batadv_dbg(DBG_BATMAN, bat_priv,
+		   "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i\n",
+		   orig_node->orig, orig_neigh_node->orig, total_count,
+		   neigh_rq_count, tq_own,
+		   tq_asym_penalty, batman_ogm_packet->tq);
 
 	/* if link has the minimum required transmission quality
-	 * consider it bidirectional */
+	 * consider it bidirectional
+	 */
 	if (batman_ogm_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
 		ret = 1;
 
 out:
 	if (neigh_node)
-		neigh_node_free_ref(neigh_node);
+		batadv_neigh_node_free_ref(neigh_node);
 	return ret;
 }
 
@@ -855,10 +877,10 @@ out:
  *  -1 the packet is old and has been received while the seqno window
  *     was protected. Caller should drop it.
  */
-static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
-				    const struct batman_ogm_packet
-							*batman_ogm_packet,
-				    const struct hard_iface *if_incoming)
+static int
+batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
+			    const struct batman_ogm_packet *batman_ogm_packet,
+			    const struct hard_iface *if_incoming)
 {
 	struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 	struct orig_node *orig_node;
@@ -868,38 +890,41 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
 	int32_t seq_diff;
 	int need_update = 0;
 	int set_mark, ret = -1;
+	uint32_t seqno = ntohl(batman_ogm_packet->seqno);
+	uint8_t *neigh_addr;
 
-	orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);
+	orig_node = batadv_get_orig_node(bat_priv, batman_ogm_packet->orig);
 	if (!orig_node)
 		return 0;
 
 	spin_lock_bh(&orig_node->ogm_cnt_lock);
-	seq_diff = batman_ogm_packet->seqno - orig_node->last_real_seqno;
+	seq_diff = seqno - orig_node->last_real_seqno;
 
 	/* signalize caller that the packet is to be dropped. */
 	if (!hlist_empty(&orig_node->neigh_list) &&
-	    window_protected(bat_priv, seq_diff,
-			     &orig_node->batman_seqno_reset))
+	    batadv_window_protected(bat_priv, seq_diff,
+				    &orig_node->batman_seqno_reset))
 		goto out;
 
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(tmp_neigh_node, node,
 				 &orig_node->neigh_list, list) {
 
-		is_duplicate |= bat_test_bit(tmp_neigh_node->real_bits,
-					     orig_node->last_real_seqno,
-					     batman_ogm_packet->seqno);
+		is_duplicate |= batadv_test_bit(tmp_neigh_node->real_bits,
+						orig_node->last_real_seqno,
+						seqno);
 
-		if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
-		    (tmp_neigh_node->if_incoming == if_incoming))
+		neigh_addr = tmp_neigh_node->addr;
+		if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
+		    tmp_neigh_node->if_incoming == if_incoming)
 			set_mark = 1;
 		else
 			set_mark = 0;
 
 		/* if the window moved, set the update flag. */
-		need_update |= bit_get_packet(bat_priv,
-					      tmp_neigh_node->real_bits,
-					      seq_diff, set_mark);
+		need_update |= batadv_bit_get_packet(bat_priv,
+						     tmp_neigh_node->real_bits,
+						     seq_diff, set_mark);
 
 		tmp_neigh_node->real_packet_count =
 			bitmap_weight(tmp_neigh_node->real_bits,
@@ -908,24 +933,24 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
 	rcu_read_unlock();
 
 	if (need_update) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"updating last_seqno: old %u, new %u\n",
-			orig_node->last_real_seqno, batman_ogm_packet->seqno);
-		orig_node->last_real_seqno = batman_ogm_packet->seqno;
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "updating last_seqno: old %u, new %u\n",
+			   orig_node->last_real_seqno, seqno);
+		orig_node->last_real_seqno = seqno;
 	}
 
 	ret = is_duplicate;
 
 out:
 	spin_unlock_bh(&orig_node->ogm_cnt_lock);
-	orig_node_free_ref(orig_node);
+	batadv_orig_node_free_ref(orig_node);
 	return ret;
 }
 
-static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
-			       struct batman_ogm_packet *batman_ogm_packet,
-			       const unsigned char *tt_buff,
-			       struct hard_iface *if_incoming)
+static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
+				  struct batman_ogm_packet *batman_ogm_packet,
+				  const unsigned char *tt_buff,
+				  struct hard_iface *if_incoming)
 {
 	struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 	struct hard_iface *hard_iface;
@@ -934,11 +959,12 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
 	struct neigh_node *orig_neigh_router = NULL;
 	int has_directlink_flag;
 	int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
-	int is_broadcast = 0, is_bidirectional;
+	int is_broadcast = 0, is_bidirect;
 	bool is_single_hop_neigh = false;
 	bool is_from_best_next_hop = false;
-	int is_duplicate;
+	int is_duplicate, sameseq, simlar_ttl;
 	uint32_t if_incoming_seqno;
+	uint8_t *prev_sender;
 
 	/* Silently drop when the batman packet is actually not a
 	 * correct packet.
@@ -960,37 +986,38 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
 
 	has_directlink_flag = (batman_ogm_packet->flags & DIRECTLINK ? 1 : 0);
 
-	if (compare_eth(ethhdr->h_source, batman_ogm_packet->orig))
+	if (batadv_compare_eth(ethhdr->h_source, batman_ogm_packet->orig))
 		is_single_hop_neigh = true;
 
-	bat_dbg(DBG_BATMAN, bat_priv,
-		"Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
-		ethhdr->h_source, if_incoming->net_dev->name,
-		if_incoming->net_dev->dev_addr, batman_ogm_packet->orig,
-		batman_ogm_packet->prev_sender, batman_ogm_packet->seqno,
-		batman_ogm_packet->ttvn, batman_ogm_packet->tt_crc,
-		batman_ogm_packet->tt_num_changes, batman_ogm_packet->tq,
-		batman_ogm_packet->header.ttl,
-		batman_ogm_packet->header.version, has_directlink_flag);
+	batadv_dbg(DBG_BATMAN, bat_priv,
+		   "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
+		   ethhdr->h_source, if_incoming->net_dev->name,
+		   if_incoming->net_dev->dev_addr, batman_ogm_packet->orig,
+		   batman_ogm_packet->prev_sender,
+		   ntohl(batman_ogm_packet->seqno), batman_ogm_packet->ttvn,
+		   ntohs(batman_ogm_packet->tt_crc),
+		   batman_ogm_packet->tt_num_changes, batman_ogm_packet->tq,
+		   batman_ogm_packet->header.ttl,
+		   batman_ogm_packet->header.version, has_directlink_flag);
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 		if (hard_iface->if_status != IF_ACTIVE)
 			continue;
 
 		if (hard_iface->soft_iface != if_incoming->soft_iface)
 			continue;
 
-		if (compare_eth(ethhdr->h_source,
-				hard_iface->net_dev->dev_addr))
+		if (batadv_compare_eth(ethhdr->h_source,
+				       hard_iface->net_dev->dev_addr))
 			is_my_addr = 1;
 
-		if (compare_eth(batman_ogm_packet->orig,
-				hard_iface->net_dev->dev_addr))
+		if (batadv_compare_eth(batman_ogm_packet->orig,
+				       hard_iface->net_dev->dev_addr))
 			is_my_orig = 1;
 
-		if (compare_eth(batman_ogm_packet->prev_sender,
-				hard_iface->net_dev->dev_addr))
+		if (batadv_compare_eth(batman_ogm_packet->prev_sender,
+				       hard_iface->net_dev->dev_addr))
 			is_my_oldorig = 1;
 
 		if (is_broadcast_ether_addr(ethhdr->h_source))
@@ -999,193 +1026,199 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
 	rcu_read_unlock();
 
 	if (batman_ogm_packet->header.version != COMPAT_VERSION) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: incompatible batman version (%i)\n",
-			batman_ogm_packet->header.version);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: incompatible batman version (%i)\n",
+			   batman_ogm_packet->header.version);
 		return;
 	}
 
 	if (is_my_addr) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: received my own broadcast (sender: %pM)\n",
-			ethhdr->h_source);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: received my own broadcast (sender: %pM)\n",
+			   ethhdr->h_source);
 		return;
 	}
 
 	if (is_broadcast) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: ignoring all packets with broadcast source addr (sender: %pM)\n",
-			ethhdr->h_source);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: ignoring all packets with broadcast source addr (sender: %pM)\n",
+			   ethhdr->h_source);
 		return;
 	}
 
 	if (is_my_orig) {
 		unsigned long *word;
 		int offset;
+		int32_t bit_pos;
 
-		orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
+		orig_neigh_node = batadv_get_orig_node(bat_priv,
+						       ethhdr->h_source);
 		if (!orig_neigh_node)
 			return;
 
 		/* neighbor has to indicate direct link and it has to
-		 * come via the corresponding interface */
-		/* save packet seqno for bidirectional check */
+		 * come via the corresponding interface
+		 * save packet seqno for bidirectional check
+		 */
 		if (has_directlink_flag &&
-		    compare_eth(if_incoming->net_dev->dev_addr,
-				batman_ogm_packet->orig)) {
+		    batadv_compare_eth(if_incoming->net_dev->dev_addr,
+				       batman_ogm_packet->orig)) {
 			offset = if_incoming->if_num * NUM_WORDS;
 
 			spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
 			word = &(orig_neigh_node->bcast_own[offset]);
-			bat_set_bit(word,
-				    if_incoming_seqno -
-						batman_ogm_packet->seqno - 2);
+			bit_pos = if_incoming_seqno - 2;
+			bit_pos -= ntohl(batman_ogm_packet->seqno);
+			batadv_set_bit(word, bit_pos);
 			orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
 				bitmap_weight(word, TQ_LOCAL_WINDOW_SIZE);
 			spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
 		}
 
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: originator packet from myself (via neighbor)\n");
-		orig_node_free_ref(orig_neigh_node);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: originator packet from myself (via neighbor)\n");
+		batadv_orig_node_free_ref(orig_neigh_node);
 		return;
 	}
 
 	if (is_my_oldorig) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: ignoring all rebroadcast echos (sender: %pM)\n",
-			ethhdr->h_source);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n",
+			   ethhdr->h_source);
 		return;
 	}
 
 	if (batman_ogm_packet->flags & NOT_BEST_NEXT_HOP) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n",
-			ethhdr->h_source);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n",
+			   ethhdr->h_source);
 		return;
 	}
 
-	orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);
+	orig_node = batadv_get_orig_node(bat_priv, batman_ogm_packet->orig);
 	if (!orig_node)
 		return;
 
-	is_duplicate = bat_iv_ogm_update_seqnos(ethhdr, batman_ogm_packet,
-						if_incoming);
+	is_duplicate = batadv_iv_ogm_update_seqnos(ethhdr, batman_ogm_packet,
+						   if_incoming);
 
 	if (is_duplicate == -1) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: packet within seqno protection time (sender: %pM)\n",
-			ethhdr->h_source);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: packet within seqno protection time (sender: %pM)\n",
+			   ethhdr->h_source);
 		goto out;
 	}
 
 	if (batman_ogm_packet->tq == 0) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: originator packet with tq equal 0\n");
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: originator packet with tq equal 0\n");
 		goto out;
 	}
 
-	router = orig_node_get_router(orig_node);
+	router = batadv_orig_node_get_router(orig_node);
 	if (router)
-		router_router = orig_node_get_router(router->orig_node);
+		router_router = batadv_orig_node_get_router(router->orig_node);
 
 	if ((router && router->tq_avg != 0) &&
-	    (compare_eth(router->addr, ethhdr->h_source)))
+	    (batadv_compare_eth(router->addr, ethhdr->h_source)))
 		is_from_best_next_hop = true;
 
+	prev_sender = batman_ogm_packet->prev_sender;
 	/* avoid temporary routing loops */
 	if (router && router_router &&
-	    (compare_eth(router->addr, batman_ogm_packet->prev_sender)) &&
-	    !(compare_eth(batman_ogm_packet->orig,
-			  batman_ogm_packet->prev_sender)) &&
-	    (compare_eth(router->addr, router_router->addr))) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n",
-			ethhdr->h_source);
+	    (batadv_compare_eth(router->addr, prev_sender)) &&
+	    !(batadv_compare_eth(batman_ogm_packet->orig, prev_sender)) &&
+	    (batadv_compare_eth(router->addr, router_router->addr))) {
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n",
+			   ethhdr->h_source);
 		goto out;
 	}
 
 	/* if sender is a direct neighbor the sender mac equals
-	 * originator mac */
+	 * originator mac
+	 */
 	orig_neigh_node = (is_single_hop_neigh ?
 			   orig_node :
-			   get_orig_node(bat_priv, ethhdr->h_source));
+			   batadv_get_orig_node(bat_priv, ethhdr->h_source));
 	if (!orig_neigh_node)
 		goto out;
 
-	orig_neigh_router = orig_node_get_router(orig_neigh_node);
+	orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node);
 
 	/* drop packet if sender is not a direct neighbor and if we
-	 * don't route towards it */
+	 * don't route towards it
+	 */
 	if (!is_single_hop_neigh && (!orig_neigh_router)) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: OGM via unknown neighbor!\n");
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: OGM via unknown neighbor!\n");
 		goto out_neigh;
 	}
 
-	is_bidirectional = bat_iv_ogm_calc_tq(orig_node, orig_neigh_node,
-					      batman_ogm_packet, if_incoming);
+	is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
+					    batman_ogm_packet, if_incoming);
 
-	bonding_save_primary(orig_node, orig_neigh_node, batman_ogm_packet);
+	batadv_bonding_save_primary(orig_node, orig_neigh_node,
+				    batman_ogm_packet);
 
 	/* update ranking if it is not a duplicate or has the same
-	 * seqno and similar ttl as the non-duplicate */
-	if (is_bidirectional &&
-	    (!is_duplicate ||
-	     ((orig_node->last_real_seqno == batman_ogm_packet->seqno) &&
-	      (orig_node->last_ttl - 3 <= batman_ogm_packet->header.ttl))))
-		bat_iv_ogm_orig_update(bat_priv, orig_node, ethhdr,
-				       batman_ogm_packet, if_incoming,
-				       tt_buff, is_duplicate);
+	 * seqno and similar ttl as the non-duplicate
+	 */
+	sameseq = orig_node->last_real_seqno == ntohl(batman_ogm_packet->seqno);
+	simlar_ttl = orig_node->last_ttl - 3 <= batman_ogm_packet->header.ttl;
+	if (is_bidirect && (!is_duplicate || (sameseq && simlar_ttl)))
+		batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr,
+					  batman_ogm_packet, if_incoming,
+					  tt_buff, is_duplicate);
 
 	/* is single hop (direct) neighbor */
 	if (is_single_hop_neigh) {
 
 		/* mark direct link on incoming interface */
-		bat_iv_ogm_forward(orig_node, ethhdr, batman_ogm_packet,
-				   is_single_hop_neigh, is_from_best_next_hop,
-				   if_incoming);
+		batadv_iv_ogm_forward(orig_node, ethhdr, batman_ogm_packet,
+				      is_single_hop_neigh,
+				      is_from_best_next_hop, if_incoming);
 
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
 		goto out_neigh;
 	}
 
 	/* multihop originator */
-	if (!is_bidirectional) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: not received via bidirectional link\n");
+	if (!is_bidirect) {
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: not received via bidirectional link\n");
 		goto out_neigh;
 	}
 
 	if (is_duplicate) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: duplicate packet received\n");
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: duplicate packet received\n");
 		goto out_neigh;
 	}
 
-	bat_dbg(DBG_BATMAN, bat_priv,
-		"Forwarding packet: rebroadcast originator packet\n");
-	bat_iv_ogm_forward(orig_node, ethhdr, batman_ogm_packet,
-			   is_single_hop_neigh, is_from_best_next_hop,
-			   if_incoming);
+	batadv_dbg(DBG_BATMAN, bat_priv,
+		   "Forwarding packet: rebroadcast originator packet\n");
+	batadv_iv_ogm_forward(orig_node, ethhdr, batman_ogm_packet,
+			      is_single_hop_neigh, is_from_best_next_hop,
+			      if_incoming);
 
 out_neigh:
 	if ((orig_neigh_node) && (!is_single_hop_neigh))
-		orig_node_free_ref(orig_neigh_node);
+		batadv_orig_node_free_ref(orig_neigh_node);
 out:
 	if (router)
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 	if (router_router)
-		neigh_node_free_ref(router_router);
+		batadv_neigh_node_free_ref(router_router);
 	if (orig_neigh_router)
-		neigh_node_free_ref(orig_neigh_router);
+		batadv_neigh_node_free_ref(orig_neigh_router);
 
-	orig_node_free_ref(orig_node);
+	batadv_orig_node_free_ref(orig_node);
 }
 
-static int bat_iv_ogm_receive(struct sk_buff *skb,
-			      struct hard_iface *if_incoming)
+static int batadv_iv_ogm_receive(struct sk_buff *skb,
+				 struct hard_iface *if_incoming)
 {
 	struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 	struct batman_ogm_packet *batman_ogm_packet;
@@ -1194,16 +1227,20 @@ static int bat_iv_ogm_receive(struct sk_buff *skb,
 	unsigned char *tt_buff, *packet_buff;
 	bool ret;
 
-	ret = check_management_packet(skb, if_incoming, BATMAN_OGM_HLEN);
+	ret = batadv_check_management_packet(skb, if_incoming, BATMAN_OGM_HLEN);
 	if (!ret)
 		return NET_RX_DROP;
 
 	/* did we receive a B.A.T.M.A.N. IV OGM packet on an interface
 	 * that does not have B.A.T.M.A.N. IV enabled ?
 	 */
-	if (bat_priv->bat_algo_ops->bat_ogm_emit != bat_iv_ogm_emit)
+	if (bat_priv->bat_algo_ops->bat_ogm_emit != batadv_iv_ogm_emit)
 		return NET_RX_DROP;
 
+	batadv_inc_counter(bat_priv, BAT_CNT_MGMT_RX);
+	batadv_add_counter(bat_priv, BAT_CNT_MGMT_RX_BYTES,
+			   skb->len + ETH_HLEN);
+
 	packet_len = skb_headlen(skb);
 	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 	packet_buff = skb->data;
@@ -1211,55 +1248,50 @@ static int bat_iv_ogm_receive(struct sk_buff *skb,
 
 	/* unpack the aggregated packets and process them one by one */
 	do {
-		/* network to host order for our 32bit seqno and the
-		   orig_interval */
-		batman_ogm_packet->seqno = ntohl(batman_ogm_packet->seqno);
-		batman_ogm_packet->tt_crc = ntohs(batman_ogm_packet->tt_crc);
-
 		tt_buff = packet_buff + buff_pos + BATMAN_OGM_HLEN;
 
-		bat_iv_ogm_process(ethhdr, batman_ogm_packet,
-				   tt_buff, if_incoming);
+		batadv_iv_ogm_process(ethhdr, batman_ogm_packet, tt_buff,
+				      if_incoming);
 
-		buff_pos += BATMAN_OGM_HLEN +
-				tt_len(batman_ogm_packet->tt_num_changes);
+		buff_pos += BATMAN_OGM_HLEN;
+		buff_pos += batadv_tt_len(batman_ogm_packet->tt_num_changes);
 
 		batman_ogm_packet = (struct batman_ogm_packet *)
 						(packet_buff + buff_pos);
-	} while (bat_iv_ogm_aggr_packet(buff_pos, packet_len,
-					batman_ogm_packet->tt_num_changes));
+	} while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len,
+					   batman_ogm_packet->tt_num_changes));
 
 	kfree_skb(skb);
 	return NET_RX_SUCCESS;
 }
 
-static struct bat_algo_ops batman_iv __read_mostly = {
-	.name = "BATMAN IV",
-	.bat_iface_enable = bat_iv_ogm_iface_enable,
-	.bat_iface_disable = bat_iv_ogm_iface_disable,
-	.bat_iface_update_mac = bat_iv_ogm_iface_update_mac,
-	.bat_primary_iface_set = bat_iv_ogm_primary_iface_set,
-	.bat_ogm_schedule = bat_iv_ogm_schedule,
-	.bat_ogm_emit = bat_iv_ogm_emit,
+static struct bat_algo_ops batadv_batman_iv __read_mostly = {
+	.name = "BATMAN_IV",
+	.bat_iface_enable = batadv_iv_ogm_iface_enable,
+	.bat_iface_disable = batadv_iv_ogm_iface_disable,
+	.bat_iface_update_mac = batadv_iv_ogm_iface_update_mac,
+	.bat_primary_iface_set = batadv_iv_ogm_primary_iface_set,
+	.bat_ogm_schedule = batadv_iv_ogm_schedule,
+	.bat_ogm_emit = batadv_iv_ogm_emit,
 };
 
-int __init bat_iv_init(void)
+int __init batadv_iv_init(void)
 {
 	int ret;
 
 	/* batman originator packet */
-	ret = recv_handler_register(BAT_IV_OGM, bat_iv_ogm_receive);
+	ret = batadv_recv_handler_register(BAT_IV_OGM, batadv_iv_ogm_receive);
 	if (ret < 0)
 		goto out;
 
-	ret = bat_algo_register(&batman_iv);
+	ret = batadv_algo_register(&batadv_batman_iv);
 	if (ret < 0)
 		goto handler_unregister;
 
 	goto out;
 
 handler_unregister:
-	recv_handler_unregister(BAT_IV_OGM);
+	batadv_recv_handler_unregister(BAT_IV_OGM);
 out:
 	return ret;
 }
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c
index 5bc7b66..03b76a4 100644
--- a/net/batman-adv/bat_sysfs.c
+++ b/net/batman-adv/bat_sysfs.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -28,15 +26,15 @@
 #include "gateway_client.h"
 #include "vis.h"
 
-static struct net_device *kobj_to_netdev(struct kobject *obj)
+static struct net_device *batadv_kobj_to_netdev(struct kobject *obj)
 {
 	struct device *dev = container_of(obj->parent, struct device, kobj);
 	return to_net_dev(dev);
 }
 
-static struct bat_priv *kobj_to_batpriv(struct kobject *obj)
+static struct bat_priv *batadv_kobj_to_batpriv(struct kobject *obj)
 {
-	struct net_device *net_dev = kobj_to_netdev(obj);
+	struct net_device *net_dev = batadv_kobj_to_netdev(obj);
 	return netdev_priv(net_dev);
 }
 
@@ -44,19 +42,19 @@ static struct bat_priv *kobj_to_batpriv(struct kobject *obj)
 #define UEV_ACTION_VAR	"BATACTION="
 #define UEV_DATA_VAR	"BATDATA="
 
-static char *uev_action_str[] = {
+static char *batadv_uev_action_str[] = {
 	"add",
 	"del",
 	"change"
 };
 
-static char *uev_type_str[] = {
+static char *batadv_uev_type_str[] = {
 	"gw"
 };
 
 /* Use this, if you have customized show and store functions */
 #define BAT_ATTR(_name, _mode, _show, _store)	\
-struct bat_attribute bat_attr_##_name = {	\
+struct bat_attribute batadv_attr_##_name = {	\
 	.attr = {.name = __stringify(_name),	\
 		 .mode = _mode },		\
 	.show   = _show,			\
@@ -64,105 +62,118 @@ struct bat_attribute bat_attr_##_name = {	\
 };
 
 #define BAT_ATTR_SIF_STORE_BOOL(_name, _post_func)			\
-ssize_t store_##_name(struct kobject *kobj, struct attribute *attr,	\
-		      char *buff, size_t count)				\
+ssize_t batadv_store_##_name(struct kobject *kobj,			\
+			     struct attribute *attr, char *buff,	\
+			     size_t count)				\
 {									\
-	struct net_device *net_dev = kobj_to_netdev(kobj);		\
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);	\
 	struct bat_priv *bat_priv = netdev_priv(net_dev);		\
-	return __store_bool_attr(buff, count, _post_func, attr,		\
-				 &bat_priv->_name, net_dev);		\
+	return __batadv_store_bool_attr(buff, count, _post_func, attr,	\
+					&bat_priv->_name, net_dev);	\
 }
 
 #define BAT_ATTR_SIF_SHOW_BOOL(_name)					\
-ssize_t show_##_name(struct kobject *kobj,				\
-		     struct attribute *attr, char *buff)		\
+ssize_t batadv_show_##_name(struct kobject *kobj,			\
+			    struct attribute *attr, char *buff)		\
 {									\
-	struct bat_priv *bat_priv = kobj_to_batpriv(kobj);		\
+	struct bat_priv *bat_priv = batadv_kobj_to_batpriv(kobj);	\
 	return sprintf(buff, "%s\n",					\
 		       atomic_read(&bat_priv->_name) == 0 ?		\
 		       "disabled" : "enabled");				\
 }									\
 
 /* Use this, if you are going to turn a [name] in the soft-interface
- * (bat_priv) on or off */
+ * (bat_priv) on or off
+ */
 #define BAT_ATTR_SIF_BOOL(_name, _mode, _post_func)			\
 	static BAT_ATTR_SIF_STORE_BOOL(_name, _post_func)		\
 	static BAT_ATTR_SIF_SHOW_BOOL(_name)				\
-	static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
+	static BAT_ATTR(_name, _mode, batadv_show_##_name,		\
+			batadv_store_##_name)
 
 
 #define BAT_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func)		\
-ssize_t store_##_name(struct kobject *kobj, struct attribute *attr,	\
-		      char *buff, size_t count)				\
+ssize_t batadv_store_##_name(struct kobject *kobj,			\
+			     struct attribute *attr, char *buff,	\
+			     size_t count)				\
 {									\
-	struct net_device *net_dev = kobj_to_netdev(kobj);		\
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);	\
 	struct bat_priv *bat_priv = netdev_priv(net_dev);		\
-	return __store_uint_attr(buff, count, _min, _max, _post_func,	\
-				 attr, &bat_priv->_name, net_dev);	\
+	return __batadv_store_uint_attr(buff, count, _min, _max,	\
+					_post_func, attr,		\
+					&bat_priv->_name, net_dev);	\
 }
 
 #define BAT_ATTR_SIF_SHOW_UINT(_name)					\
-ssize_t show_##_name(struct kobject *kobj,				\
-		     struct attribute *attr, char *buff)		\
+ssize_t batadv_show_##_name(struct kobject *kobj,			\
+			    struct attribute *attr, char *buff)		\
 {									\
-	struct bat_priv *bat_priv = kobj_to_batpriv(kobj);		\
+	struct bat_priv *bat_priv = batadv_kobj_to_batpriv(kobj);	\
 	return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name));	\
 }									\
 
 /* Use this, if you are going to set [name] in the soft-interface
- * (bat_priv) to an unsigned integer value */
+ * (bat_priv) to an unsigned integer value
+ */
 #define BAT_ATTR_SIF_UINT(_name, _mode, _min, _max, _post_func)		\
 	static BAT_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func)	\
 	static BAT_ATTR_SIF_SHOW_UINT(_name)				\
-	static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
+	static BAT_ATTR(_name, _mode, batadv_show_##_name,		\
+			batadv_store_##_name)
 
 
 #define BAT_ATTR_HIF_STORE_UINT(_name, _min, _max, _post_func)		\
-ssize_t store_##_name(struct kobject *kobj, struct attribute *attr,	\
-		      char *buff, size_t count)				\
+ssize_t batadv_store_##_name(struct kobject *kobj,			\
+			     struct attribute *attr, char *buff,	\
+			     size_t count)				\
 {									\
-	struct net_device *net_dev = kobj_to_netdev(kobj);		\
-	struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);	\
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);	\
+	struct hard_iface *hard_iface;					\
 	ssize_t length;							\
 									\
+	hard_iface = batadv_hardif_get_by_netdev(net_dev);		\
 	if (!hard_iface)						\
 		return 0;						\
 									\
-	length = __store_uint_attr(buff, count, _min, _max, _post_func,	\
-				   attr, &hard_iface->_name, net_dev);	\
+	length = __batadv_store_uint_attr(buff, count, _min, _max,	\
+					  _post_func, attr,		\
+					  &hard_iface->_name, net_dev);	\
 									\
-	hardif_free_ref(hard_iface);					\
+	batadv_hardif_free_ref(hard_iface);				\
 	return length;							\
 }
 
 #define BAT_ATTR_HIF_SHOW_UINT(_name)					\
-ssize_t show_##_name(struct kobject *kobj,				\
-		     struct attribute *attr, char *buff)		\
+ssize_t batadv_show_##_name(struct kobject *kobj,			\
+			    struct attribute *attr, char *buff)		\
 {									\
-	struct net_device *net_dev = kobj_to_netdev(kobj);		\
-	struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);	\
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);	\
+	struct hard_iface *hard_iface;					\
 	ssize_t length;							\
 									\
+	hard_iface = batadv_hardif_get_by_netdev(net_dev);		\
 	if (!hard_iface)						\
 		return 0;						\
 									\
 	length = sprintf(buff, "%i\n", atomic_read(&hard_iface->_name));\
 									\
-	hardif_free_ref(hard_iface);					\
+	batadv_hardif_free_ref(hard_iface);				\
 	return length;							\
 }
 
 /* Use this, if you are going to set [name] in hard_iface to an
- * unsigned integer value*/
+ * unsigned integer value
+ */
 #define BAT_ATTR_HIF_UINT(_name, _mode, _min, _max, _post_func)		\
 	static BAT_ATTR_HIF_STORE_UINT(_name, _min, _max, _post_func)	\
 	static BAT_ATTR_HIF_SHOW_UINT(_name)				\
-	static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
+	static BAT_ATTR(_name, _mode, batadv_show_##_name,		\
+			batadv_store_##_name)
 
 
-static int store_bool_attr(char *buff, size_t count,
-			   struct net_device *net_dev,
-			   const char *attr_name, atomic_t *attr)
+static int batadv_store_bool_attr(char *buff, size_t count,
+				  struct net_device *net_dev,
+				  const char *attr_name, atomic_t *attr)
 {
 	int enabled = -1;
 
@@ -197,23 +208,27 @@ static int store_bool_attr(char *buff, size_t count,
 	return count;
 }
 
-static inline ssize_t __store_bool_attr(char *buff, size_t count,
-			void (*post_func)(struct net_device *),
-			struct attribute *attr,
-			atomic_t *attr_store, struct net_device *net_dev)
+static inline ssize_t
+__batadv_store_bool_attr(char *buff, size_t count,
+			 void (*post_func)(struct net_device *),
+			 struct attribute *attr,
+			 atomic_t *attr_store, struct net_device *net_dev)
 {
 	int ret;
 
-	ret = store_bool_attr(buff, count, net_dev, attr->name, attr_store);
+	ret = batadv_store_bool_attr(buff, count, net_dev, attr->name,
+				     attr_store);
 	if (post_func && ret)
 		post_func(net_dev);
 
 	return ret;
 }
 
-static int store_uint_attr(const char *buff, size_t count,
-			   struct net_device *net_dev, const char *attr_name,
-			   unsigned int min, unsigned int max, atomic_t *attr)
+static int batadv_store_uint_attr(const char *buff, size_t count,
+				  struct net_device *net_dev,
+				  const char *attr_name,
+				  unsigned int min, unsigned int max,
+				  atomic_t *attr)
 {
 	unsigned long uint_val;
 	int ret;
@@ -248,26 +263,27 @@ static int store_uint_attr(const char *buff, size_t count,
 	return count;
 }
 
-static inline ssize_t __store_uint_attr(const char *buff, size_t count,
-			int min, int max,
-			void (*post_func)(struct net_device *),
-			const struct attribute *attr,
-			atomic_t *attr_store, struct net_device *net_dev)
+static inline ssize_t
+__batadv_store_uint_attr(const char *buff, size_t count,
+			 int min, int max,
+			 void (*post_func)(struct net_device *),
+			 const struct attribute *attr,
+			 atomic_t *attr_store, struct net_device *net_dev)
 {
 	int ret;
 
-	ret = store_uint_attr(buff, count, net_dev, attr->name,
-			      min, max, attr_store);
+	ret = batadv_store_uint_attr(buff, count, net_dev, attr->name, min, max,
+				     attr_store);
 	if (post_func && ret)
 		post_func(net_dev);
 
 	return ret;
 }
 
-static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr,
-			     char *buff)
+static ssize_t batadv_show_vis_mode(struct kobject *kobj,
+				    struct attribute *attr, char *buff)
 {
-	struct bat_priv *bat_priv = kobj_to_batpriv(kobj);
+	struct bat_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
 	int vis_mode = atomic_read(&bat_priv->vis_mode);
 
 	return sprintf(buff, "%s\n",
@@ -275,10 +291,11 @@ static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr,
 							"client" : "server");
 }
 
-static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
-			      char *buff, size_t count)
+static ssize_t batadv_store_vis_mode(struct kobject *kobj,
+				     struct attribute *attr, char *buff,
+				     size_t count)
 {
-	struct net_device *net_dev = kobj_to_netdev(kobj);
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
 	struct bat_priv *bat_priv = netdev_priv(net_dev);
 	unsigned long val;
 	int ret, vis_mode_tmp = -1;
@@ -316,23 +333,23 @@ static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
 	return count;
 }
 
-static ssize_t show_bat_algo(struct kobject *kobj, struct attribute *attr,
-			    char *buff)
+static ssize_t batadv_show_bat_algo(struct kobject *kobj,
+				    struct attribute *attr, char *buff)
 {
-	struct bat_priv *bat_priv = kobj_to_batpriv(kobj);
+	struct bat_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
 	return sprintf(buff, "%s\n", bat_priv->bat_algo_ops->name);
 }
 
-static void post_gw_deselect(struct net_device *net_dev)
+static void batadv_post_gw_deselect(struct net_device *net_dev)
 {
 	struct bat_priv *bat_priv = netdev_priv(net_dev);
-	gw_deselect(bat_priv);
+	batadv_gw_deselect(bat_priv);
 }
 
-static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr,
-			    char *buff)
+static ssize_t batadv_show_gw_mode(struct kobject *kobj, struct attribute *attr,
+				   char *buff)
 {
-	struct bat_priv *bat_priv = kobj_to_batpriv(kobj);
+	struct bat_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
 	int bytes_written;
 
 	switch (atomic_read(&bat_priv->gw_mode)) {
@@ -350,10 +367,11 @@ static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr,
 	return bytes_written;
 }
 
-static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr,
-			     char *buff, size_t count)
+static ssize_t batadv_store_gw_mode(struct kobject *kobj,
+				    struct attribute *attr, char *buff,
+				    size_t count)
 {
-	struct net_device *net_dev = kobj_to_netdev(kobj);
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
 	struct bat_priv *bat_priv = netdev_priv(net_dev);
 	char *curr_gw_mode_str;
 	int gw_mode_tmp = -1;
@@ -397,19 +415,19 @@ static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr,
 	bat_info(net_dev, "Changing gw mode from: %s to: %s\n",
 		 curr_gw_mode_str, buff);
 
-	gw_deselect(bat_priv);
+	batadv_gw_deselect(bat_priv);
 	atomic_set(&bat_priv->gw_mode, (unsigned int)gw_mode_tmp);
 	return count;
 }
 
-static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr,
-			      char *buff)
+static ssize_t batadv_show_gw_bwidth(struct kobject *kobj,
+				     struct attribute *attr, char *buff)
 {
-	struct bat_priv *bat_priv = kobj_to_batpriv(kobj);
+	struct bat_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
 	int down, up;
 	int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth);
 
-	gw_bandwidth_to_kbit(gw_bandwidth, &down, &up);
+	batadv_gw_bandwidth_to_kbit(gw_bandwidth, &down, &up);
 	return sprintf(buff, "%i%s/%i%s\n",
 		       (down > 2048 ? down / 1024 : down),
 		       (down > 2048 ? "MBit" : "KBit"),
@@ -417,15 +435,16 @@ static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr,
 		       (up > 2048 ? "MBit" : "KBit"));
 }
 
-static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr,
-			       char *buff, size_t count)
+static ssize_t batadv_store_gw_bwidth(struct kobject *kobj,
+				      struct attribute *attr, char *buff,
+				      size_t count)
 {
-	struct net_device *net_dev = kobj_to_netdev(kobj);
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
 
 	if (buff[count - 1] == '\n')
 		buff[count - 1] = '\0';
 
-	return gw_bandwidth_set(net_dev, buff, count);
+	return batadv_gw_bandwidth_set(net_dev, buff, count);
 }
 
 BAT_ATTR_SIF_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
@@ -433,43 +452,45 @@ BAT_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
 #ifdef CONFIG_BATMAN_ADV_BLA
 BAT_ATTR_SIF_BOOL(bridge_loop_avoidance, S_IRUGO | S_IWUSR, NULL);
 #endif
-BAT_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu);
+BAT_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu);
 BAT_ATTR_SIF_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
-static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
-static BAT_ATTR(routing_algo, S_IRUGO, show_bat_algo, NULL);
-static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode);
+static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, batadv_show_vis_mode,
+		batadv_store_vis_mode);
+static BAT_ATTR(routing_algo, S_IRUGO, batadv_show_bat_algo, NULL);
+static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, batadv_show_gw_mode,
+		batadv_store_gw_mode);
 BAT_ATTR_SIF_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL);
 BAT_ATTR_SIF_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL);
 BAT_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
-		  post_gw_deselect);
-static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth,
-		store_gw_bwidth);
+		  batadv_post_gw_deselect);
+static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth,
+		batadv_store_gw_bwidth);
 #ifdef CONFIG_BATMAN_ADV_DEBUG
-BAT_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, 15, NULL);
+BAT_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, DBG_ALL, NULL);
 #endif
 
-static struct bat_attribute *mesh_attrs[] = {
-	&bat_attr_aggregated_ogms,
-	&bat_attr_bonding,
+static struct bat_attribute *batadv_mesh_attrs[] = {
+	&batadv_attr_aggregated_ogms,
+	&batadv_attr_bonding,
 #ifdef CONFIG_BATMAN_ADV_BLA
-	&bat_attr_bridge_loop_avoidance,
+	&batadv_attr_bridge_loop_avoidance,
 #endif
-	&bat_attr_fragmentation,
-	&bat_attr_ap_isolation,
-	&bat_attr_vis_mode,
-	&bat_attr_routing_algo,
-	&bat_attr_gw_mode,
-	&bat_attr_orig_interval,
-	&bat_attr_hop_penalty,
-	&bat_attr_gw_sel_class,
-	&bat_attr_gw_bandwidth,
+	&batadv_attr_fragmentation,
+	&batadv_attr_ap_isolation,
+	&batadv_attr_vis_mode,
+	&batadv_attr_routing_algo,
+	&batadv_attr_gw_mode,
+	&batadv_attr_orig_interval,
+	&batadv_attr_hop_penalty,
+	&batadv_attr_gw_sel_class,
+	&batadv_attr_gw_bandwidth,
 #ifdef CONFIG_BATMAN_ADV_DEBUG
-	&bat_attr_log_level,
+	&batadv_attr_log_level,
 #endif
 	NULL,
 };
 
-int sysfs_add_meshif(struct net_device *dev)
+int batadv_sysfs_add_meshif(struct net_device *dev)
 {
 	struct kobject *batif_kobject = &dev->dev.kobj;
 	struct bat_priv *bat_priv = netdev_priv(dev);
@@ -484,7 +505,7 @@ int sysfs_add_meshif(struct net_device *dev)
 		goto out;
 	}
 
-	for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) {
+	for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr) {
 		err = sysfs_create_file(bat_priv->mesh_obj,
 					&((*bat_attr)->attr));
 		if (err) {
@@ -498,7 +519,7 @@ int sysfs_add_meshif(struct net_device *dev)
 	return 0;
 
 rem_attr:
-	for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
+	for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr)
 		sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
 
 	kobject_put(bat_priv->mesh_obj);
@@ -507,23 +528,23 @@ out:
 	return -ENOMEM;
 }
 
-void sysfs_del_meshif(struct net_device *dev)
+void batadv_sysfs_del_meshif(struct net_device *dev)
 {
 	struct bat_priv *bat_priv = netdev_priv(dev);
 	struct bat_attribute **bat_attr;
 
-	for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
+	for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr)
 		sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
 
 	kobject_put(bat_priv->mesh_obj);
 	bat_priv->mesh_obj = NULL;
 }
 
-static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr,
-			       char *buff)
+static ssize_t batadv_show_mesh_iface(struct kobject *kobj,
+				      struct attribute *attr, char *buff)
 {
-	struct net_device *net_dev = kobj_to_netdev(kobj);
-	struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
+	struct hard_iface *hard_iface = batadv_hardif_get_by_netdev(net_dev);
 	ssize_t length;
 
 	if (!hard_iface)
@@ -532,16 +553,17 @@ static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr,
 	length = sprintf(buff, "%s\n", hard_iface->if_status == IF_NOT_IN_USE ?
 			 "none" : hard_iface->soft_iface->name);
 
-	hardif_free_ref(hard_iface);
+	batadv_hardif_free_ref(hard_iface);
 
 	return length;
 }
 
-static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
-				char *buff, size_t count)
+static ssize_t batadv_store_mesh_iface(struct kobject *kobj,
+				       struct attribute *attr, char *buff,
+				       size_t count)
 {
-	struct net_device *net_dev = kobj_to_netdev(kobj);
-	struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
+	struct hard_iface *hard_iface = batadv_hardif_get_by_netdev(net_dev);
 	int status_tmp = -1;
 	int ret = count;
 
@@ -554,7 +576,7 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
 	if (strlen(buff) >= IFNAMSIZ) {
 		pr_err("Invalid parameter for 'mesh_iface' setting received: interface name too long '%s'\n",
 		       buff);
-		hardif_free_ref(hard_iface);
+		batadv_hardif_free_ref(hard_iface);
 		return -EINVAL;
 	}
 
@@ -576,28 +598,28 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
 	}
 
 	if (status_tmp == IF_NOT_IN_USE) {
-		hardif_disable_interface(hard_iface);
+		batadv_hardif_disable_interface(hard_iface);
 		goto unlock;
 	}
 
 	/* if the interface already is in use */
 	if (hard_iface->if_status != IF_NOT_IN_USE)
-		hardif_disable_interface(hard_iface);
+		batadv_hardif_disable_interface(hard_iface);
 
-	ret = hardif_enable_interface(hard_iface, buff);
+	ret = batadv_hardif_enable_interface(hard_iface, buff);
 
 unlock:
 	rtnl_unlock();
 out:
-	hardif_free_ref(hard_iface);
+	batadv_hardif_free_ref(hard_iface);
 	return ret;
 }
 
-static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
-				 char *buff)
+static ssize_t batadv_show_iface_status(struct kobject *kobj,
+					struct attribute *attr, char *buff)
 {
-	struct net_device *net_dev = kobj_to_netdev(kobj);
-	struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
+	struct hard_iface *hard_iface = batadv_hardif_get_by_netdev(net_dev);
 	ssize_t length;
 
 	if (!hard_iface)
@@ -622,22 +644,22 @@ static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
 		break;
 	}
 
-	hardif_free_ref(hard_iface);
+	batadv_hardif_free_ref(hard_iface);
 
 	return length;
 }
 
 static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR,
-		show_mesh_iface, store_mesh_iface);
-static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL);
+		batadv_show_mesh_iface, batadv_store_mesh_iface);
+static BAT_ATTR(iface_status, S_IRUGO, batadv_show_iface_status, NULL);
 
-static struct bat_attribute *batman_attrs[] = {
-	&bat_attr_mesh_iface,
-	&bat_attr_iface_status,
+static struct bat_attribute *batadv_batman_attrs[] = {
+	&batadv_attr_mesh_iface,
+	&batadv_attr_iface_status,
 	NULL,
 };
 
-int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
+int batadv_sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
 {
 	struct kobject *hardif_kobject = &dev->dev.kobj;
 	struct bat_attribute **bat_attr;
@@ -652,7 +674,7 @@ int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
 		goto out;
 	}
 
-	for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) {
+	for (bat_attr = batadv_batman_attrs; *bat_attr; ++bat_attr) {
 		err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr));
 		if (err) {
 			bat_err(dev, "Can't add sysfs file: %s/%s/%s\n",
@@ -665,47 +687,48 @@ int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
 	return 0;
 
 rem_attr:
-	for (bat_attr = batman_attrs; *bat_attr; ++bat_attr)
+	for (bat_attr = batadv_batman_attrs; *bat_attr; ++bat_attr)
 		sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr));
 out:
 	return -ENOMEM;
 }
 
-void sysfs_del_hardif(struct kobject **hardif_obj)
+void batadv_sysfs_del_hardif(struct kobject **hardif_obj)
 {
 	kobject_put(*hardif_obj);
 	*hardif_obj = NULL;
 }
 
-int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
-		 enum uev_action action, const char *data)
+int batadv_throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
+			enum uev_action action, const char *data)
 {
-	int ret = -1;
+	int ret = -ENOMEM;
 	struct hard_iface *primary_if = NULL;
 	struct kobject *bat_kobj;
 	char *uevent_env[4] = { NULL, NULL, NULL, NULL };
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
 	bat_kobj = &primary_if->soft_iface->dev.kobj;
 
 	uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) +
-				strlen(uev_type_str[type]) + 1,
+				strlen(batadv_uev_type_str[type]) + 1,
 				GFP_ATOMIC);
 	if (!uevent_env[0])
 		goto out;
 
-	sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]);
+	sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, batadv_uev_type_str[type]);
 
 	uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) +
-				strlen(uev_action_str[action]) + 1,
+				strlen(batadv_uev_action_str[action]) + 1,
 				GFP_ATOMIC);
 	if (!uevent_env[1])
 		goto out;
 
-	sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]);
+	sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR,
+		batadv_uev_action_str[action]);
 
 	/* If the event is DEL, ignore the data field */
 	if (action != UEV_DEL) {
@@ -724,12 +747,13 @@ out:
 	kfree(uevent_env[2]);
 
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 
 	if (ret)
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Impossible to send uevent for (%s,%s,%s) event (err: %d)\n",
-			uev_type_str[type], uev_action_str[action],
-			(action == UEV_DEL ? "NULL" : data), ret);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Impossible to send uevent for (%s,%s,%s) event (err: %d)\n",
+			   batadv_uev_type_str[type],
+			   batadv_uev_action_str[action],
+			   (action == UEV_DEL ? "NULL" : data), ret);
 	return ret;
 }
diff --git a/net/batman-adv/bat_sysfs.h b/net/batman-adv/bat_sysfs.h
index fece77a..3672277 100644
--- a/net/batman-adv/bat_sysfs.h
+++ b/net/batman-adv/bat_sysfs.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,10 +15,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
-
 #ifndef _NET_BATMAN_ADV_SYSFS_H_
 #define _NET_BATMAN_ADV_SYSFS_H_
 
@@ -34,11 +31,12 @@ struct bat_attribute {
 			 char *buf, size_t count);
 };
 
-int sysfs_add_meshif(struct net_device *dev);
-void sysfs_del_meshif(struct net_device *dev);
-int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
-void sysfs_del_hardif(struct kobject **hardif_obj);
-int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
-		 enum uev_action action, const char *data);
+int batadv_sysfs_add_meshif(struct net_device *dev);
+void batadv_sysfs_del_meshif(struct net_device *dev);
+int batadv_sysfs_add_hardif(struct kobject **hardif_obj,
+			    struct net_device *dev);
+void batadv_sysfs_del_hardif(struct kobject **hardif_obj);
+int batadv_throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
+			enum uev_action action, const char *data);
 
 #endif /* _NET_BATMAN_ADV_SYSFS_H_ */
diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c
index 07ae6e1..e195b9e 100644
--- a/net/batman-adv/bitarray.c
+++ b/net/batman-adv/bitarray.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -25,7 +23,7 @@
 #include <linux/bitops.h>
 
 /* shift the packet array by n places. */
-static void bat_bitmap_shift_left(unsigned long *seq_bits, int32_t n)
+static void batadv_bitmap_shift_left(unsigned long *seq_bits, int32_t n)
 {
 	if (n <= 0 || n >= TQ_LOCAL_WINDOW_SIZE)
 		return;
@@ -40,58 +38,57 @@ static void bat_bitmap_shift_left(unsigned long *seq_bits, int32_t n)
  *  1 if the window was moved (either new or very old)
  *  0 if the window was not moved/shifted.
  */
-int bit_get_packet(void *priv, unsigned long *seq_bits,
-		    int32_t seq_num_diff, int set_mark)
+int batadv_bit_get_packet(void *priv, unsigned long *seq_bits,
+			  int32_t seq_num_diff, int set_mark)
 {
 	struct bat_priv *bat_priv = priv;
 
 	/* sequence number is slightly older. We already got a sequence number
-	 * higher than this one, so we just mark it. */
-
+	 * higher than this one, so we just mark it.
+	 */
 	if ((seq_num_diff <= 0) && (seq_num_diff > -TQ_LOCAL_WINDOW_SIZE)) {
 		if (set_mark)
-			bat_set_bit(seq_bits, -seq_num_diff);
+			batadv_set_bit(seq_bits, -seq_num_diff);
 		return 0;
 	}
 
 	/* sequence number is slightly newer, so we shift the window and
-	 * set the mark if required */
-
+	 * set the mark if required
+	 */
 	if ((seq_num_diff > 0) && (seq_num_diff < TQ_LOCAL_WINDOW_SIZE)) {
-		bat_bitmap_shift_left(seq_bits, seq_num_diff);
+		batadv_bitmap_shift_left(seq_bits, seq_num_diff);
 
 		if (set_mark)
-			bat_set_bit(seq_bits, 0);
+			batadv_set_bit(seq_bits, 0);
 		return 1;
 	}
 
 	/* sequence number is much newer, probably missed a lot of packets */
-
 	if ((seq_num_diff >= TQ_LOCAL_WINDOW_SIZE) &&
 	    (seq_num_diff < EXPECTED_SEQNO_RANGE)) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"We missed a lot of packets (%i) !\n",
-			seq_num_diff - 1);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "We missed a lot of packets (%i) !\n",
+			   seq_num_diff - 1);
 		bitmap_zero(seq_bits, TQ_LOCAL_WINDOW_SIZE);
 		if (set_mark)
-			bat_set_bit(seq_bits, 0);
+			batadv_set_bit(seq_bits, 0);
 		return 1;
 	}
 
 	/* received a much older packet. The other host either restarted
 	 * or the old packet got delayed somewhere in the network. The
 	 * packet should be dropped without calling this function if the
-	 * seqno window is protected. */
-
+	 * seqno window is protected.
+	 */
 	if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) ||
 	    (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
 
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Other host probably restarted!\n");
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Other host probably restarted!\n");
 
 		bitmap_zero(seq_bits, TQ_LOCAL_WINDOW_SIZE);
 		if (set_mark)
-			bat_set_bit(seq_bits, 0);
+			batadv_set_bit(seq_bits, 0);
 
 		return 1;
 	}
diff --git a/net/batman-adv/bitarray.h b/net/batman-adv/bitarray.h
index 1835c15..7954ba8 100644
--- a/net/batman-adv/bitarray.h
+++ b/net/batman-adv/bitarray.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
@@ -16,16 +15,16 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_BITARRAY_H_
 #define _NET_BATMAN_ADV_BITARRAY_H_
 
 /* returns true if the corresponding bit in the given seq_bits indicates true
- * and curr_seqno is within range of last_seqno */
-static inline int bat_test_bit(const unsigned long *seq_bits,
-			       uint32_t last_seqno, uint32_t curr_seqno)
+ * and curr_seqno is within range of last_seqno
+ */
+static inline int batadv_test_bit(const unsigned long *seq_bits,
+				  uint32_t last_seqno, uint32_t curr_seqno)
 {
 	int32_t diff;
 
@@ -37,7 +36,7 @@ static inline int bat_test_bit(const unsigned long *seq_bits,
 }
 
 /* turn corresponding bit on, so we can remember that we got the packet */
-static inline void bat_set_bit(unsigned long *seq_bits, int32_t n)
+static inline void batadv_set_bit(unsigned long *seq_bits, int32_t n)
 {
 	/* if too old, just drop it */
 	if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE)
@@ -47,8 +46,9 @@ static inline void bat_set_bit(unsigned long *seq_bits, int32_t n)
 }
 
 /* receive and process one packet, returns 1 if received seq_num is considered
- * new, 0 if old  */
-int bit_get_packet(void *priv, unsigned long *seq_bits,
-		   int32_t seq_num_diff, int set_mark);
+ * new, 0 if old
+ */
+int batadv_bit_get_packet(void *priv, unsigned long *seq_bits,
+			  int32_t seq_num_diff, int set_mark);
 
 #endif /* _NET_BATMAN_ADV_BITARRAY_H_ */
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index 8bf9751..0592d2b 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -33,14 +31,14 @@
 #include <net/arp.h>
 #include <linux/if_vlan.h>
 
-static const uint8_t announce_mac[4] = {0x43, 0x05, 0x43, 0x05};
+static const uint8_t batadv_announce_mac[4] = {0x43, 0x05, 0x43, 0x05};
 
-static void bla_periodic_work(struct work_struct *work);
-static void bla_send_announce(struct bat_priv *bat_priv,
-			      struct backbone_gw *backbone_gw);
+static void batadv_bla_periodic_work(struct work_struct *work);
+static void batadv_bla_send_announce(struct bat_priv *bat_priv,
+				     struct backbone_gw *backbone_gw);
 
 /* return the index of the claim */
-static inline uint32_t choose_claim(const void *data, uint32_t size)
+static inline uint32_t batadv_choose_claim(const void *data, uint32_t size)
 {
 	const unsigned char *key = data;
 	uint32_t hash = 0;
@@ -60,7 +58,8 @@ static inline uint32_t choose_claim(const void *data, uint32_t size)
 }
 
 /* return the index of the backbone gateway */
-static inline uint32_t choose_backbone_gw(const void *data, uint32_t size)
+static inline uint32_t batadv_choose_backbone_gw(const void *data,
+						 uint32_t size)
 {
 	const unsigned char *key = data;
 	uint32_t hash = 0;
@@ -81,7 +80,8 @@ static inline uint32_t choose_backbone_gw(const void *data, uint32_t size)
 
 
 /* compares address and vid of two backbone gws */
-static int compare_backbone_gw(const struct hlist_node *node, const void *data2)
+static int batadv_compare_backbone_gw(const struct hlist_node *node,
+				      const void *data2)
 {
 	const void *data1 = container_of(node, struct backbone_gw,
 					 hash_entry);
@@ -90,7 +90,8 @@ static int compare_backbone_gw(const struct hlist_node *node, const void *data2)
 }
 
 /* compares address and vid of two claims */
-static int compare_claim(const struct hlist_node *node, const void *data2)
+static int batadv_compare_claim(const struct hlist_node *node,
+				const void *data2)
 {
 	const void *data1 = container_of(node, struct claim,
 					 hash_entry);
@@ -99,39 +100,38 @@ static int compare_claim(const struct hlist_node *node, const void *data2)
 }
 
 /* free a backbone gw */
-static void backbone_gw_free_ref(struct backbone_gw *backbone_gw)
+static void batadv_backbone_gw_free_ref(struct backbone_gw *backbone_gw)
 {
 	if (atomic_dec_and_test(&backbone_gw->refcount))
 		kfree_rcu(backbone_gw, rcu);
 }
 
 /* finally deinitialize the claim */
-static void claim_free_rcu(struct rcu_head *rcu)
+static void batadv_claim_free_rcu(struct rcu_head *rcu)
 {
 	struct claim *claim;
 
 	claim = container_of(rcu, struct claim, rcu);
 
-	backbone_gw_free_ref(claim->backbone_gw);
+	batadv_backbone_gw_free_ref(claim->backbone_gw);
 	kfree(claim);
 }
 
 /* free a claim, call claim_free_rcu if its the last reference */
-static void claim_free_ref(struct claim *claim)
+static void batadv_claim_free_ref(struct claim *claim)
 {
 	if (atomic_dec_and_test(&claim->refcount))
-		call_rcu(&claim->rcu, claim_free_rcu);
+		call_rcu(&claim->rcu, batadv_claim_free_rcu);
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @data: search data (may be local/static data)
  *
  * looks for a claim in the hash, and returns it if found
  * or NULL otherwise.
  */
-static struct claim *claim_hash_find(struct bat_priv *bat_priv,
-				     struct claim *data)
+static struct claim *batadv_claim_hash_find(struct bat_priv *bat_priv,
+					    struct claim *data)
 {
 	struct hashtable_t *hash = bat_priv->claim_hash;
 	struct hlist_head *head;
@@ -143,12 +143,12 @@ static struct claim *claim_hash_find(struct bat_priv *bat_priv,
 	if (!hash)
 		return NULL;
 
-	index = choose_claim(data, hash->size);
+	index = batadv_choose_claim(data, hash->size);
 	head = &hash->table[index];
 
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(claim, node, head, hash_entry) {
-		if (!compare_claim(&claim->hash_entry, data))
+		if (!batadv_compare_claim(&claim->hash_entry, data))
 			continue;
 
 		if (!atomic_inc_not_zero(&claim->refcount))
@@ -162,16 +162,15 @@ static struct claim *claim_hash_find(struct bat_priv *bat_priv,
 	return claim_tmp;
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @addr: the address of the originator
  * @vid: the VLAN ID
  *
  * looks for a claim in the hash, and returns it if found
  * or NULL otherwise.
  */
-static struct backbone_gw *backbone_hash_find(struct bat_priv *bat_priv,
-					      uint8_t *addr, short vid)
+static struct backbone_gw *batadv_backbone_hash_find(struct bat_priv *bat_priv,
+						     uint8_t *addr, short vid)
 {
 	struct hashtable_t *hash = bat_priv->backbone_hash;
 	struct hlist_head *head;
@@ -186,13 +185,13 @@ static struct backbone_gw *backbone_hash_find(struct bat_priv *bat_priv,
 	memcpy(search_entry.orig, addr, ETH_ALEN);
 	search_entry.vid = vid;
 
-	index = choose_backbone_gw(&search_entry, hash->size);
+	index = batadv_choose_backbone_gw(&search_entry, hash->size);
 	head = &hash->table[index];
 
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(backbone_gw, node, head, hash_entry) {
-		if (!compare_backbone_gw(&backbone_gw->hash_entry,
-					 &search_entry))
+		if (!batadv_compare_backbone_gw(&backbone_gw->hash_entry,
+						&search_entry))
 			continue;
 
 		if (!atomic_inc_not_zero(&backbone_gw->refcount))
@@ -207,7 +206,7 @@ static struct backbone_gw *backbone_hash_find(struct bat_priv *bat_priv,
 }
 
 /* delete all claims for a backbone */
-static void bla_del_backbone_claims(struct backbone_gw *backbone_gw)
+static void batadv_bla_del_backbone_claims(struct backbone_gw *backbone_gw)
 {
 	struct hashtable_t *hash;
 	struct hlist_node *node, *node_tmp;
@@ -231,7 +230,7 @@ static void bla_del_backbone_claims(struct backbone_gw *backbone_gw)
 			if (claim->backbone_gw != backbone_gw)
 				continue;
 
-			claim_free_ref(claim);
+			batadv_claim_free_ref(claim);
 			hlist_del_rcu(node);
 		}
 		spin_unlock_bh(list_lock);
@@ -241,16 +240,15 @@ static void bla_del_backbone_claims(struct backbone_gw *backbone_gw)
 	backbone_gw->crc = BLA_CRC_INIT;
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @orig: the mac address to be announced within the claim
  * @vid: the VLAN ID
  * @claimtype: the type of the claim (CLAIM, UNCLAIM, ANNOUNCE, ...)
  *
  * sends a claim frame according to the provided info.
  */
-static void bla_send_claim(struct bat_priv *bat_priv, uint8_t *mac,
-			   short vid, int claimtype)
+static void batadv_bla_send_claim(struct bat_priv *bat_priv, uint8_t *mac,
+				  short vid, int claimtype)
 {
 	struct sk_buff *skb;
 	struct ethhdr *ethhdr;
@@ -258,9 +256,9 @@ static void bla_send_claim(struct bat_priv *bat_priv, uint8_t *mac,
 	struct net_device *soft_iface;
 	uint8_t *hw_src;
 	struct bla_claim_dst local_claim_dest;
-	uint32_t zeroip = 0;
+	__be32 zeroip = 0;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		return;
 
@@ -299,25 +297,26 @@ static void bla_send_claim(struct bat_priv *bat_priv, uint8_t *mac,
 		 * set Ethernet SRC to the clients mac
 		 */
 		memcpy(ethhdr->h_source, mac, ETH_ALEN);
-		bat_dbg(DBG_BLA, bat_priv,
-			"bla_send_claim(): CLAIM %pM on vid %d\n", mac, vid);
+		batadv_dbg(DBG_BLA, bat_priv,
+			   "bla_send_claim(): CLAIM %pM on vid %d\n", mac, vid);
 		break;
 	case CLAIM_TYPE_DEL:
 		/* unclaim frame
 		 * set HW SRC to the clients mac
 		 */
 		memcpy(hw_src, mac, ETH_ALEN);
-		bat_dbg(DBG_BLA, bat_priv,
-			"bla_send_claim(): UNCLAIM %pM on vid %d\n", mac, vid);
+		batadv_dbg(DBG_BLA, bat_priv,
+			   "bla_send_claim(): UNCLAIM %pM on vid %d\n", mac,
+			   vid);
 		break;
 	case CLAIM_TYPE_ANNOUNCE:
 		/* announcement frame
 		 * set HW SRC to the special mac containg the crc
 		 */
 		memcpy(hw_src, mac, ETH_ALEN);
-		bat_dbg(DBG_BLA, bat_priv,
-			"bla_send_claim(): ANNOUNCE of %pM on vid %d\n",
-			ethhdr->h_source, vid);
+		batadv_dbg(DBG_BLA, bat_priv,
+			   "bla_send_claim(): ANNOUNCE of %pM on vid %d\n",
+			   ethhdr->h_source, vid);
 		break;
 	case CLAIM_TYPE_REQUEST:
 		/* request frame
@@ -325,9 +324,9 @@ static void bla_send_claim(struct bat_priv *bat_priv, uint8_t *mac,
 		 */
 		memcpy(hw_src, mac, ETH_ALEN);
 		memcpy(ethhdr->h_dest, mac, ETH_ALEN);
-		bat_dbg(DBG_BLA, bat_priv,
-			"bla_send_claim(): REQUEST of %pM to %pMon vid %d\n",
-			ethhdr->h_source, ethhdr->h_dest, vid);
+		batadv_dbg(DBG_BLA, bat_priv,
+			   "bla_send_claim(): REQUEST of %pM to %pMon vid %d\n",
+			   ethhdr->h_source, ethhdr->h_dest, vid);
 		break;
 
 	}
@@ -344,32 +343,31 @@ static void bla_send_claim(struct bat_priv *bat_priv, uint8_t *mac,
 	netif_rx(skb);
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @orig: the mac address of the originator
  * @vid: the VLAN ID
  *
  * searches for the backbone gw or creates a new one if it could not
  * be found.
  */
-static struct backbone_gw *bla_get_backbone_gw(struct bat_priv *bat_priv,
-					       uint8_t *orig, short vid)
+static struct backbone_gw *batadv_bla_get_backbone_gw(struct bat_priv *bat_priv,
+						      uint8_t *orig, short vid)
 {
 	struct backbone_gw *entry;
 	struct orig_node *orig_node;
 	int hash_added;
 
-	entry = backbone_hash_find(bat_priv, orig, vid);
+	entry = batadv_backbone_hash_find(bat_priv, orig, vid);
 
 	if (entry)
 		return entry;
 
-	bat_dbg(DBG_BLA, bat_priv,
-		"bla_get_backbone_gw(): not found (%pM, %d), creating new entry\n",
-		orig, vid);
+	batadv_dbg(DBG_BLA, bat_priv,
+		   "bla_get_backbone_gw(): not found (%pM, %d), creating new entry\n",
+		   orig, vid);
 
 	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 	if (!entry)
@@ -385,8 +383,10 @@ static struct backbone_gw *bla_get_backbone_gw(struct bat_priv *bat_priv,
 	/* one for the hash, one for returning */
 	atomic_set(&entry->refcount, 2);
 
-	hash_added = hash_add(bat_priv->backbone_hash, compare_backbone_gw,
-			      choose_backbone_gw, entry, &entry->hash_entry);
+	hash_added = batadv_hash_add(bat_priv->backbone_hash,
+				     batadv_compare_backbone_gw,
+				     batadv_choose_backbone_gw, entry,
+				     &entry->hash_entry);
 
 	if (unlikely(hash_added != 0)) {
 		/* hash failed, free the structure */
@@ -395,11 +395,11 @@ static struct backbone_gw *bla_get_backbone_gw(struct bat_priv *bat_priv,
 	}
 
 	/* this is a gateway now, remove any tt entries */
-	orig_node = orig_hash_find(bat_priv, orig);
+	orig_node = batadv_orig_hash_find(bat_priv, orig);
 	if (orig_node) {
-		tt_global_del_orig(bat_priv, orig_node,
-				   "became a backbone gateway");
-		orig_node_free_ref(orig_node);
+		batadv_tt_global_del_orig(bat_priv, orig_node,
+					  "became a backbone gateway");
+		batadv_orig_node_free_ref(orig_node);
 	}
 	return entry;
 }
@@ -407,30 +407,30 @@ static struct backbone_gw *bla_get_backbone_gw(struct bat_priv *bat_priv,
 /* update or add the own backbone gw to make sure we announce
  * where we receive other backbone gws
  */
-static void bla_update_own_backbone_gw(struct bat_priv *bat_priv,
-				       struct hard_iface *primary_if,
-				       short vid)
+static void batadv_bla_update_own_backbone_gw(struct bat_priv *bat_priv,
+					      struct hard_iface *primary_if,
+					      short vid)
 {
 	struct backbone_gw *backbone_gw;
 
-	backbone_gw = bla_get_backbone_gw(bat_priv,
-					  primary_if->net_dev->dev_addr, vid);
+	backbone_gw = batadv_bla_get_backbone_gw(bat_priv,
+						 primary_if->net_dev->dev_addr,
+						 vid);
 	if (unlikely(!backbone_gw))
 		return;
 
 	backbone_gw->lasttime = jiffies;
-	backbone_gw_free_ref(backbone_gw);
+	batadv_backbone_gw_free_ref(backbone_gw);
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @vid: the vid where the request came on
  *
  * Repeat all of our own claims, and finally send an ANNOUNCE frame
  * to allow the requester another check if the CRC is correct now.
  */
-static void bla_answer_request(struct bat_priv *bat_priv,
-			       struct hard_iface *primary_if, short vid)
+static void batadv_bla_answer_request(struct bat_priv *bat_priv,
+				      struct hard_iface *primary_if, short vid)
 {
 	struct hlist_node *node;
 	struct hlist_head *head;
@@ -439,11 +439,12 @@ static void bla_answer_request(struct bat_priv *bat_priv,
 	struct backbone_gw *backbone_gw;
 	int i;
 
-	bat_dbg(DBG_BLA, bat_priv,
-		"bla_answer_request(): received a claim request, send all of our own claims again\n");
+	batadv_dbg(DBG_BLA, bat_priv,
+		   "bla_answer_request(): received a claim request, send all of our own claims again\n");
 
-	backbone_gw = backbone_hash_find(bat_priv,
-					 primary_if->net_dev->dev_addr, vid);
+	backbone_gw = batadv_backbone_hash_find(bat_priv,
+						primary_if->net_dev->dev_addr,
+						vid);
 	if (!backbone_gw)
 		return;
 
@@ -457,36 +458,34 @@ static void bla_answer_request(struct bat_priv *bat_priv,
 			if (claim->backbone_gw != backbone_gw)
 				continue;
 
-			bla_send_claim(bat_priv, claim->addr, claim->vid,
-				       CLAIM_TYPE_ADD);
+			batadv_bla_send_claim(bat_priv, claim->addr, claim->vid,
+					      CLAIM_TYPE_ADD);
 		}
 		rcu_read_unlock();
 	}
 
 	/* finally, send an announcement frame */
-	bla_send_announce(bat_priv, backbone_gw);
-	backbone_gw_free_ref(backbone_gw);
+	batadv_bla_send_announce(bat_priv, backbone_gw);
+	batadv_backbone_gw_free_ref(backbone_gw);
 }
 
-/**
- * @backbone_gw: the backbone gateway from whom we are out of sync
+/* @backbone_gw: the backbone gateway from whom we are out of sync
  *
  * When the crc is wrong, ask the backbone gateway for a full table update.
  * After the request, it will repeat all of his own claims and finally
  * send an announcement claim with which we can check again.
  */
-static void bla_send_request(struct backbone_gw *backbone_gw)
+static void batadv_bla_send_request(struct backbone_gw *backbone_gw)
 {
 	/* first, remove all old entries */
-	bla_del_backbone_claims(backbone_gw);
+	batadv_bla_del_backbone_claims(backbone_gw);
 
-	bat_dbg(DBG_BLA, backbone_gw->bat_priv,
-		"Sending REQUEST to %pM\n",
-		backbone_gw->orig);
+	batadv_dbg(DBG_BLA, backbone_gw->bat_priv, "Sending REQUEST to %pM\n",
+		   backbone_gw->orig);
 
 	/* send request */
-	bla_send_claim(backbone_gw->bat_priv, backbone_gw->orig,
-		       backbone_gw->vid, CLAIM_TYPE_REQUEST);
+	batadv_bla_send_claim(backbone_gw->bat_priv, backbone_gw->orig,
+			      backbone_gw->vid, CLAIM_TYPE_REQUEST);
 
 	/* no local broadcasts should be sent or received, for now. */
 	if (!atomic_read(&backbone_gw->request_sent)) {
@@ -495,37 +494,37 @@ static void bla_send_request(struct backbone_gw *backbone_gw)
 	}
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @backbone_gw: our backbone gateway which should be announced
  *
  * This function sends an announcement. It is called from multiple
  * places.
  */
-static void bla_send_announce(struct bat_priv *bat_priv,
-			      struct backbone_gw *backbone_gw)
+static void batadv_bla_send_announce(struct bat_priv *bat_priv,
+				     struct backbone_gw *backbone_gw)
 {
 	uint8_t mac[ETH_ALEN];
-	uint16_t crc;
+	__be16 crc;
 
-	memcpy(mac, announce_mac, 4);
+	memcpy(mac, batadv_announce_mac, 4);
 	crc = htons(backbone_gw->crc);
-	memcpy(&mac[4], (uint8_t *)&crc, 2);
+	memcpy(&mac[4], &crc, 2);
 
-	bla_send_claim(bat_priv, mac, backbone_gw->vid, CLAIM_TYPE_ANNOUNCE);
+	batadv_bla_send_claim(bat_priv, mac, backbone_gw->vid,
+			      CLAIM_TYPE_ANNOUNCE);
 
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @mac: the mac address of the claim
  * @vid: the VLAN ID of the frame
  * @backbone_gw: the backbone gateway which claims it
  *
  * Adds a claim in the claim hash.
  */
-static void bla_add_claim(struct bat_priv *bat_priv, const uint8_t *mac,
-			  const short vid, struct backbone_gw *backbone_gw)
+static void batadv_bla_add_claim(struct bat_priv *bat_priv, const uint8_t *mac,
+				 const short vid,
+				 struct backbone_gw *backbone_gw)
 {
 	struct claim *claim;
 	struct claim search_claim;
@@ -533,7 +532,7 @@ static void bla_add_claim(struct bat_priv *bat_priv, const uint8_t *mac,
 
 	memcpy(search_claim.addr, mac, ETH_ALEN);
 	search_claim.vid = vid;
-	claim = claim_hash_find(bat_priv, &search_claim);
+	claim = batadv_claim_hash_find(bat_priv, &search_claim);
 
 	/* create a new claim entry if it does not exist yet. */
 	if (!claim) {
@@ -547,11 +546,13 @@ static void bla_add_claim(struct bat_priv *bat_priv, const uint8_t *mac,
 		claim->backbone_gw = backbone_gw;
 
 		atomic_set(&claim->refcount, 2);
-		bat_dbg(DBG_BLA, bat_priv,
-			"bla_add_claim(): adding new entry %pM, vid %d to hash ...\n",
-			mac, vid);
-		hash_added = hash_add(bat_priv->claim_hash, compare_claim,
-				      choose_claim, claim, &claim->hash_entry);
+		batadv_dbg(DBG_BLA, bat_priv,
+			   "bla_add_claim(): adding new entry %pM, vid %d to hash ...\n",
+			   mac, vid);
+		hash_added = batadv_hash_add(bat_priv->claim_hash,
+					     batadv_compare_claim,
+					     batadv_choose_claim, claim,
+					     &claim->hash_entry);
 
 		if (unlikely(hash_added != 0)) {
 			/* only local changes happened. */
@@ -564,13 +565,13 @@ static void bla_add_claim(struct bat_priv *bat_priv, const uint8_t *mac,
 			/* no need to register a new backbone */
 			goto claim_free_ref;
 
-		bat_dbg(DBG_BLA, bat_priv,
-			"bla_add_claim(): changing ownership for %pM, vid %d\n",
-			mac, vid);
+		batadv_dbg(DBG_BLA, bat_priv,
+			   "bla_add_claim(): changing ownership for %pM, vid %d\n",
+			   mac, vid);
 
 		claim->backbone_gw->crc ^=
 			crc16(0, claim->addr, ETH_ALEN);
-		backbone_gw_free_ref(claim->backbone_gw);
+		batadv_backbone_gw_free_ref(claim->backbone_gw);
 
 	}
 	/* set (new) backbone gw */
@@ -581,45 +582,48 @@ static void bla_add_claim(struct bat_priv *bat_priv, const uint8_t *mac,
 	backbone_gw->lasttime = jiffies;
 
 claim_free_ref:
-	claim_free_ref(claim);
+	batadv_claim_free_ref(claim);
 }
 
 /* Delete a claim from the claim hash which has the
  * given mac address and vid.
  */
-static void bla_del_claim(struct bat_priv *bat_priv, const uint8_t *mac,
-			  const short vid)
+static void batadv_bla_del_claim(struct bat_priv *bat_priv, const uint8_t *mac,
+				 const short vid)
 {
 	struct claim search_claim, *claim;
 
 	memcpy(search_claim.addr, mac, ETH_ALEN);
 	search_claim.vid = vid;
-	claim = claim_hash_find(bat_priv, &search_claim);
+	claim = batadv_claim_hash_find(bat_priv, &search_claim);
 	if (!claim)
 		return;
 
-	bat_dbg(DBG_BLA, bat_priv, "bla_del_claim(): %pM, vid %d\n", mac, vid);
+	batadv_dbg(DBG_BLA, bat_priv, "bla_del_claim(): %pM, vid %d\n", mac,
+		   vid);
 
-	hash_remove(bat_priv->claim_hash, compare_claim, choose_claim, claim);
-	claim_free_ref(claim); /* reference from the hash is gone */
+	batadv_hash_remove(bat_priv->claim_hash, batadv_compare_claim,
+			   batadv_choose_claim, claim);
+	batadv_claim_free_ref(claim); /* reference from the hash is gone */
 
 	claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
 
 	/* don't need the reference from hash_find() anymore */
-	claim_free_ref(claim);
+	batadv_claim_free_ref(claim);
 }
 
 /* check for ANNOUNCE frame, return 1 if handled */
-static int handle_announce(struct bat_priv *bat_priv,
-			   uint8_t *an_addr, uint8_t *backbone_addr, short vid)
+static int batadv_handle_announce(struct bat_priv *bat_priv,
+				  uint8_t *an_addr, uint8_t *backbone_addr,
+				  short vid)
 {
 	struct backbone_gw *backbone_gw;
 	uint16_t crc;
 
-	if (memcmp(an_addr, announce_mac, 4) != 0)
+	if (memcmp(an_addr, batadv_announce_mac, 4) != 0)
 		return 0;
 
-	backbone_gw = bla_get_backbone_gw(bat_priv, backbone_addr, vid);
+	backbone_gw = batadv_bla_get_backbone_gw(bat_priv, backbone_addr, vid);
 
 	if (unlikely(!backbone_gw))
 		return 1;
@@ -627,19 +631,19 @@ static int handle_announce(struct bat_priv *bat_priv,
 
 	/* handle as ANNOUNCE frame */
 	backbone_gw->lasttime = jiffies;
-	crc = ntohs(*((uint16_t *)(&an_addr[4])));
+	crc = ntohs(*((__be16 *)(&an_addr[4])));
 
-	bat_dbg(DBG_BLA, bat_priv,
-		"handle_announce(): ANNOUNCE vid %d (sent by %pM)... CRC = %04x\n",
-		vid, backbone_gw->orig, crc);
+	batadv_dbg(DBG_BLA, bat_priv,
+		   "handle_announce(): ANNOUNCE vid %d (sent by %pM)... CRC = %04x\n",
+		   vid, backbone_gw->orig, crc);
 
 	if (backbone_gw->crc != crc) {
-		bat_dbg(DBG_BLA, backbone_gw->bat_priv,
-			"handle_announce(): CRC FAILED for %pM/%d (my = %04x, sent = %04x)\n",
-			backbone_gw->orig, backbone_gw->vid, backbone_gw->crc,
-			crc);
+		batadv_dbg(DBG_BLA, backbone_gw->bat_priv,
+			   "handle_announce(): CRC FAILED for %pM/%d (my = %04x, sent = %04x)\n",
+			   backbone_gw->orig, backbone_gw->vid,
+			   backbone_gw->crc, crc);
 
-		bla_send_request(backbone_gw);
+		batadv_bla_send_request(backbone_gw);
 	} else {
 		/* if we have sent a request and the crc was OK,
 		 * we can allow traffic again.
@@ -650,89 +654,91 @@ static int handle_announce(struct bat_priv *bat_priv,
 		}
 	}
 
-	backbone_gw_free_ref(backbone_gw);
+	batadv_backbone_gw_free_ref(backbone_gw);
 	return 1;
 }
 
 /* check for REQUEST frame, return 1 if handled */
-static int handle_request(struct bat_priv *bat_priv,
-			  struct hard_iface *primary_if,
-			  uint8_t *backbone_addr,
-			  struct ethhdr *ethhdr, short vid)
+static int batadv_handle_request(struct bat_priv *bat_priv,
+				 struct hard_iface *primary_if,
+				 uint8_t *backbone_addr,
+				 struct ethhdr *ethhdr, short vid)
 {
 	/* check for REQUEST frame */
-	if (!compare_eth(backbone_addr, ethhdr->h_dest))
+	if (!batadv_compare_eth(backbone_addr, ethhdr->h_dest))
 		return 0;
 
 	/* sanity check, this should not happen on a normal switch,
 	 * we ignore it in this case.
 	 */
-	if (!compare_eth(ethhdr->h_dest, primary_if->net_dev->dev_addr))
+	if (!batadv_compare_eth(ethhdr->h_dest, primary_if->net_dev->dev_addr))
 		return 1;
 
-	bat_dbg(DBG_BLA, bat_priv,
-		"handle_request(): REQUEST vid %d (sent by %pM)...\n",
-		vid, ethhdr->h_source);
+	batadv_dbg(DBG_BLA, bat_priv,
+		   "handle_request(): REQUEST vid %d (sent by %pM)...\n",
+		   vid, ethhdr->h_source);
 
-	bla_answer_request(bat_priv, primary_if, vid);
+	batadv_bla_answer_request(bat_priv, primary_if, vid);
 	return 1;
 }
 
 /* check for UNCLAIM frame, return 1 if handled */
-static int handle_unclaim(struct bat_priv *bat_priv,
-			  struct hard_iface *primary_if,
-			  uint8_t *backbone_addr,
-			  uint8_t *claim_addr, short vid)
+static int batadv_handle_unclaim(struct bat_priv *bat_priv,
+				 struct hard_iface *primary_if,
+				 uint8_t *backbone_addr,
+				 uint8_t *claim_addr, short vid)
 {
 	struct backbone_gw *backbone_gw;
 
 	/* unclaim in any case if it is our own */
-	if (primary_if && compare_eth(backbone_addr,
-				      primary_if->net_dev->dev_addr))
-		bla_send_claim(bat_priv, claim_addr, vid, CLAIM_TYPE_DEL);
+	if (primary_if && batadv_compare_eth(backbone_addr,
+					     primary_if->net_dev->dev_addr))
+		batadv_bla_send_claim(bat_priv, claim_addr, vid,
+				      CLAIM_TYPE_DEL);
 
-	backbone_gw = backbone_hash_find(bat_priv, backbone_addr, vid);
+	backbone_gw = batadv_backbone_hash_find(bat_priv, backbone_addr, vid);
 
 	if (!backbone_gw)
 		return 1;
 
 	/* this must be an UNCLAIM frame */
-	bat_dbg(DBG_BLA, bat_priv,
-		"handle_unclaim(): UNCLAIM %pM on vid %d (sent by %pM)...\n",
-		claim_addr, vid, backbone_gw->orig);
+	batadv_dbg(DBG_BLA, bat_priv,
+		   "handle_unclaim(): UNCLAIM %pM on vid %d (sent by %pM)...\n",
+		   claim_addr, vid, backbone_gw->orig);
 
-	bla_del_claim(bat_priv, claim_addr, vid);
-	backbone_gw_free_ref(backbone_gw);
+	batadv_bla_del_claim(bat_priv, claim_addr, vid);
+	batadv_backbone_gw_free_ref(backbone_gw);
 	return 1;
 }
 
 /* check for CLAIM frame, return 1 if handled */
-static int handle_claim(struct bat_priv *bat_priv,
-			struct hard_iface *primary_if, uint8_t *backbone_addr,
-			uint8_t *claim_addr, short vid)
+static int batadv_handle_claim(struct bat_priv *bat_priv,
+			       struct hard_iface *primary_if,
+			       uint8_t *backbone_addr, uint8_t *claim_addr,
+			       short vid)
 {
 	struct backbone_gw *backbone_gw;
 
 	/* register the gateway if not yet available, and add the claim. */
 
-	backbone_gw = bla_get_backbone_gw(bat_priv, backbone_addr, vid);
+	backbone_gw = batadv_bla_get_backbone_gw(bat_priv, backbone_addr, vid);
 
 	if (unlikely(!backbone_gw))
 		return 1;
 
 	/* this must be a CLAIM frame */
-	bla_add_claim(bat_priv, claim_addr, vid, backbone_gw);
-	if (compare_eth(backbone_addr, primary_if->net_dev->dev_addr))
-		bla_send_claim(bat_priv, claim_addr, vid, CLAIM_TYPE_ADD);
+	batadv_bla_add_claim(bat_priv, claim_addr, vid, backbone_gw);
+	if (batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr))
+		batadv_bla_send_claim(bat_priv, claim_addr, vid,
+				      CLAIM_TYPE_ADD);
 
 	/* TODO: we could call something like tt_local_del() here. */
 
-	backbone_gw_free_ref(backbone_gw);
+	batadv_backbone_gw_free_ref(backbone_gw);
 	return 1;
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @hw_src: the Hardware source in the ARP Header
  * @hw_dst: the Hardware destination in the ARP Header
  * @ethhdr: pointer to the Ethernet header of the claim frame
@@ -746,10 +752,10 @@ static int handle_claim(struct bat_priv *bat_priv,
  *	1  - if is a claim packet from another group
  *	0  - if it is not a claim packet
  */
-static int check_claim_group(struct bat_priv *bat_priv,
-			     struct hard_iface *primary_if,
-			     uint8_t *hw_src, uint8_t *hw_dst,
-			     struct ethhdr *ethhdr)
+static int batadv_check_claim_group(struct bat_priv *bat_priv,
+				    struct hard_iface *primary_if,
+				    uint8_t *hw_src, uint8_t *hw_dst,
+				    struct ethhdr *ethhdr)
 {
 	uint8_t *backbone_addr;
 	struct orig_node *orig_node;
@@ -780,7 +786,7 @@ static int check_claim_group(struct bat_priv *bat_priv,
 	}
 
 	/* don't accept claim frames from ourselves */
-	if (compare_eth(backbone_addr, primary_if->net_dev->dev_addr))
+	if (batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr))
 		return 0;
 
 	/* if its already the same group, it is fine. */
@@ -788,7 +794,7 @@ static int check_claim_group(struct bat_priv *bat_priv,
 		return 2;
 
 	/* lets see if this originator is in our mesh */
-	orig_node = orig_hash_find(bat_priv, backbone_addr);
+	orig_node = batadv_orig_hash_find(bat_priv, backbone_addr);
 
 	/* dont accept claims from gateways which are not in
 	 * the same mesh or group.
@@ -798,20 +804,19 @@ static int check_claim_group(struct bat_priv *bat_priv,
 
 	/* if our mesh friends mac is bigger, use it for ourselves. */
 	if (ntohs(bla_dst->group) > ntohs(bla_dst_own->group)) {
-		bat_dbg(DBG_BLA, bat_priv,
-			"taking other backbones claim group: %04x\n",
-			ntohs(bla_dst->group));
+		batadv_dbg(DBG_BLA, bat_priv,
+			   "taking other backbones claim group: %04x\n",
+			   ntohs(bla_dst->group));
 		bla_dst_own->group = bla_dst->group;
 	}
 
-	orig_node_free_ref(orig_node);
+	batadv_orig_node_free_ref(orig_node);
 
 	return 2;
 }
 
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @skb: the frame to be checked
  *
  * Check if this is a claim frame, and process it accordingly.
@@ -819,9 +824,9 @@ static int check_claim_group(struct bat_priv *bat_priv,
  * returns 1 if it was a claim frame, otherwise return 0 to
  * tell the callee that it can use the frame on its own.
  */
-static int bla_process_claim(struct bat_priv *bat_priv,
-			     struct hard_iface *primary_if,
-			     struct sk_buff *skb)
+static int batadv_bla_process_claim(struct bat_priv *bat_priv,
+				    struct hard_iface *primary_if,
+				    struct sk_buff *skb)
 {
 	struct ethhdr *ethhdr;
 	struct vlan_ethhdr *vhdr;
@@ -860,7 +865,6 @@ static int bla_process_claim(struct bat_priv *bat_priv,
 	/* Check whether the ARP frame carries a valid
 	 * IP information
 	 */
-
 	if (arphdr->ar_hrd != htons(ARPHRD_ETHER))
 		return 0;
 	if (arphdr->ar_pro != htons(ETH_P_IP))
@@ -875,51 +879,54 @@ static int bla_process_claim(struct bat_priv *bat_priv,
 	bla_dst = (struct bla_claim_dst *)hw_dst;
 
 	/* check if it is a claim frame. */
-	ret = check_claim_group(bat_priv, primary_if, hw_src, hw_dst, ethhdr);
+	ret = batadv_check_claim_group(bat_priv, primary_if, hw_src, hw_dst,
+				       ethhdr);
 	if (ret == 1)
-		bat_dbg(DBG_BLA, bat_priv,
-			"bla_process_claim(): received a claim frame from another group. From: %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
-			ethhdr->h_source, vid, hw_src, hw_dst);
+		batadv_dbg(DBG_BLA, bat_priv,
+			   "bla_process_claim(): received a claim frame from another group. From: %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
+			   ethhdr->h_source, vid, hw_src, hw_dst);
 
 	if (ret < 2)
 		return ret;
 
 	/* become a backbone gw ourselves on this vlan if not happened yet */
-	bla_update_own_backbone_gw(bat_priv, primary_if, vid);
+	batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
 
 	/* check for the different types of claim frames ... */
 	switch (bla_dst->type) {
 	case CLAIM_TYPE_ADD:
-		if (handle_claim(bat_priv, primary_if, hw_src,
-				 ethhdr->h_source, vid))
+		if (batadv_handle_claim(bat_priv, primary_if, hw_src,
+					ethhdr->h_source, vid))
 			return 1;
 		break;
 	case CLAIM_TYPE_DEL:
-		if (handle_unclaim(bat_priv, primary_if,
-				   ethhdr->h_source, hw_src, vid))
+		if (batadv_handle_unclaim(bat_priv, primary_if,
+					  ethhdr->h_source, hw_src, vid))
 			return 1;
 		break;
 
 	case CLAIM_TYPE_ANNOUNCE:
-		if (handle_announce(bat_priv, hw_src, ethhdr->h_source, vid))
+		if (batadv_handle_announce(bat_priv, hw_src, ethhdr->h_source,
+					   vid))
 			return 1;
 		break;
 	case CLAIM_TYPE_REQUEST:
-		if (handle_request(bat_priv, primary_if, hw_src, ethhdr, vid))
+		if (batadv_handle_request(bat_priv, primary_if, hw_src, ethhdr,
+					  vid))
 			return 1;
 		break;
 	}
 
-	bat_dbg(DBG_BLA, bat_priv,
-		"bla_process_claim(): ERROR - this looks like a claim frame, but is useless. eth src %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
-		ethhdr->h_source, vid, hw_src, hw_dst);
+	batadv_dbg(DBG_BLA, bat_priv,
+		   "bla_process_claim(): ERROR - this looks like a claim frame, but is useless. eth src %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
+		   ethhdr->h_source, vid, hw_src, hw_dst);
 	return 1;
 }
 
 /* Check when we last heard from other nodes, and remove them in case of
  * a time out, or clean all backbone gws if now is set.
  */
-static void bla_purge_backbone_gw(struct bat_priv *bat_priv, int now)
+static void batadv_bla_purge_backbone_gw(struct bat_priv *bat_priv, int now)
 {
 	struct backbone_gw *backbone_gw;
 	struct hlist_node *node, *node_tmp;
@@ -941,38 +948,37 @@ static void bla_purge_backbone_gw(struct bat_priv *bat_priv, int now)
 					  head, hash_entry) {
 			if (now)
 				goto purge_now;
-			if (!has_timed_out(backbone_gw->lasttime,
-					   BLA_BACKBONE_TIMEOUT))
+			if (!batadv_has_timed_out(backbone_gw->lasttime,
+						  BLA_BACKBONE_TIMEOUT))
 				continue;
 
-			bat_dbg(DBG_BLA, backbone_gw->bat_priv,
-				"bla_purge_backbone_gw(): backbone gw %pM timed out\n",
-				backbone_gw->orig);
+			batadv_dbg(DBG_BLA, backbone_gw->bat_priv,
+				   "bla_purge_backbone_gw(): backbone gw %pM timed out\n",
+				   backbone_gw->orig);
 
 purge_now:
 			/* don't wait for the pending request anymore */
 			if (atomic_read(&backbone_gw->request_sent))
 				atomic_dec(&bat_priv->bla_num_requests);
 
-			bla_del_backbone_claims(backbone_gw);
+			batadv_bla_del_backbone_claims(backbone_gw);
 
 			hlist_del_rcu(node);
-			backbone_gw_free_ref(backbone_gw);
+			batadv_backbone_gw_free_ref(backbone_gw);
 		}
 		spin_unlock_bh(list_lock);
 	}
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @primary_if: the selected primary interface, may be NULL if now is set
  * @now: whether the whole hash shall be wiped now
  *
  * Check when we heard last time from our own claims, and remove them in case of
  * a time out, or clean all claims if now is set
  */
-static void bla_purge_claims(struct bat_priv *bat_priv,
-			     struct hard_iface *primary_if, int now)
+static void batadv_bla_purge_claims(struct bat_priv *bat_priv,
+				    struct hard_iface *primary_if, int now)
 {
 	struct claim *claim;
 	struct hlist_node *node;
@@ -991,37 +997,35 @@ static void bla_purge_claims(struct bat_priv *bat_priv,
 		hlist_for_each_entry_rcu(claim, node, head, hash_entry) {
 			if (now)
 				goto purge_now;
-			if (!compare_eth(claim->backbone_gw->orig,
-					 primary_if->net_dev->dev_addr))
+			if (!batadv_compare_eth(claim->backbone_gw->orig,
+						primary_if->net_dev->dev_addr))
 				continue;
-			if (!has_timed_out(claim->lasttime,
-					   BLA_CLAIM_TIMEOUT))
+			if (!batadv_has_timed_out(claim->lasttime,
+						  BLA_CLAIM_TIMEOUT))
 				continue;
 
-			bat_dbg(DBG_BLA, bat_priv,
-				"bla_purge_claims(): %pM, vid %d, time out\n",
-				claim->addr, claim->vid);
+			batadv_dbg(DBG_BLA, bat_priv,
+				   "bla_purge_claims(): %pM, vid %d, time out\n",
+				   claim->addr, claim->vid);
 
 purge_now:
-			handle_unclaim(bat_priv, primary_if,
-				       claim->backbone_gw->orig,
-				       claim->addr, claim->vid);
+			batadv_handle_unclaim(bat_priv, primary_if,
+					      claim->backbone_gw->orig,
+					      claim->addr, claim->vid);
 		}
 		rcu_read_unlock();
 	}
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @primary_if: the new selected primary_if
  * @oldif: the old primary interface, may be NULL
  *
  * Update the backbone gateways when the own orig address changes.
- *
  */
-void bla_update_orig_address(struct bat_priv *bat_priv,
-			     struct hard_iface *primary_if,
-			     struct hard_iface *oldif)
+void batadv_bla_update_orig_address(struct bat_priv *bat_priv,
+				    struct hard_iface *primary_if,
+				    struct hard_iface *oldif)
 {
 	struct backbone_gw *backbone_gw;
 	struct hlist_node *node;
@@ -1034,8 +1038,8 @@ void bla_update_orig_address(struct bat_priv *bat_priv,
 		htons(crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN));
 
 	if (!oldif) {
-		bla_purge_claims(bat_priv, NULL, 1);
-		bla_purge_backbone_gw(bat_priv, 1);
+		batadv_bla_purge_claims(bat_priv, NULL, 1);
+		batadv_bla_purge_backbone_gw(bat_priv, 1);
 		return;
 	}
 
@@ -1049,8 +1053,8 @@ void bla_update_orig_address(struct bat_priv *bat_priv,
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(backbone_gw, node, head, hash_entry) {
 			/* own orig still holds the old value. */
-			if (!compare_eth(backbone_gw->orig,
-					 oldif->net_dev->dev_addr))
+			if (!batadv_compare_eth(backbone_gw->orig,
+						oldif->net_dev->dev_addr))
 				continue;
 
 			memcpy(backbone_gw->orig,
@@ -1058,7 +1062,7 @@ void bla_update_orig_address(struct bat_priv *bat_priv,
 			/* send an announce frame so others will ask for our
 			 * claims and update their tables.
 			 */
-			bla_send_announce(bat_priv, backbone_gw);
+			batadv_bla_send_announce(bat_priv, backbone_gw);
 		}
 		rcu_read_unlock();
 	}
@@ -1067,10 +1071,10 @@ void bla_update_orig_address(struct bat_priv *bat_priv,
 
 
 /* (re)start the timer */
-static void bla_start_timer(struct bat_priv *bat_priv)
+static void batadv_bla_start_timer(struct bat_priv *bat_priv)
 {
-	INIT_DELAYED_WORK(&bat_priv->bla_work, bla_periodic_work);
-	queue_delayed_work(bat_event_workqueue, &bat_priv->bla_work,
+	INIT_DELAYED_WORK(&bat_priv->bla_work, batadv_bla_periodic_work);
+	queue_delayed_work(batadv_event_workqueue, &bat_priv->bla_work,
 			   msecs_to_jiffies(BLA_PERIOD_LENGTH));
 }
 
@@ -1078,7 +1082,7 @@ static void bla_start_timer(struct bat_priv *bat_priv)
  *  * purge structures when they are too old
  *  * send announcements
  */
-static void bla_periodic_work(struct work_struct *work)
+static void batadv_bla_periodic_work(struct work_struct *work)
 {
 	struct delayed_work *delayed_work =
 		container_of(work, struct delayed_work, work);
@@ -1091,12 +1095,12 @@ static void bla_periodic_work(struct work_struct *work)
 	struct hard_iface *primary_if;
 	int i;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
-	bla_purge_claims(bat_priv, primary_if, 0);
-	bla_purge_backbone_gw(bat_priv, 0);
+	batadv_bla_purge_claims(bat_priv, primary_if, 0);
+	batadv_bla_purge_backbone_gw(bat_priv, 0);
 
 	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
 		goto out;
@@ -1110,41 +1114,49 @@ static void bla_periodic_work(struct work_struct *work)
 
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(backbone_gw, node, head, hash_entry) {
-			if (!compare_eth(backbone_gw->orig,
-					 primary_if->net_dev->dev_addr))
+			if (!batadv_compare_eth(backbone_gw->orig,
+						primary_if->net_dev->dev_addr))
 				continue;
 
 			backbone_gw->lasttime = jiffies;
 
-			bla_send_announce(bat_priv, backbone_gw);
+			batadv_bla_send_announce(bat_priv, backbone_gw);
 		}
 		rcu_read_unlock();
 	}
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 
-	bla_start_timer(bat_priv);
+	batadv_bla_start_timer(bat_priv);
 }
 
+/* The hash for claim and backbone hash receive the same key because they
+ * are getting initialized by hash_new with the same key. Reinitializing
+ * them with to different keys to allow nested locking without generating
+ * lockdep warnings
+ */
+static struct lock_class_key batadv_claim_hash_lock_class_key;
+static struct lock_class_key batadv_backbone_hash_lock_class_key;
+
 /* initialize all bla structures */
-int bla_init(struct bat_priv *bat_priv)
+int batadv_bla_init(struct bat_priv *bat_priv)
 {
 	int i;
 	uint8_t claim_dest[ETH_ALEN] = {0xff, 0x43, 0x05, 0x00, 0x00, 0x00};
 	struct hard_iface *primary_if;
 
-	bat_dbg(DBG_BLA, bat_priv, "bla hash registering\n");
+	batadv_dbg(DBG_BLA, bat_priv, "bla hash registering\n");
 
 	/* setting claim destination address */
 	memcpy(&bat_priv->claim_dest.magic, claim_dest, 3);
 	bat_priv->claim_dest.type = 0;
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (primary_if) {
 		bat_priv->claim_dest.group =
 			htons(crc16(0, primary_if->net_dev->dev_addr,
 				    ETH_ALEN));
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	} else {
 		bat_priv->claim_dest.group = 0; /* will be set later */
 	}
@@ -1156,22 +1168,26 @@ int bla_init(struct bat_priv *bat_priv)
 	bat_priv->bcast_duplist_curr = 0;
 
 	if (bat_priv->claim_hash)
-		return 1;
+		return 0;
 
-	bat_priv->claim_hash = hash_new(128);
-	bat_priv->backbone_hash = hash_new(32);
+	bat_priv->claim_hash = batadv_hash_new(128);
+	bat_priv->backbone_hash = batadv_hash_new(32);
 
 	if (!bat_priv->claim_hash || !bat_priv->backbone_hash)
-		return -1;
+		return -ENOMEM;
 
-	bat_dbg(DBG_BLA, bat_priv, "bla hashes initialized\n");
+	batadv_hash_set_lock_class(bat_priv->claim_hash,
+				   &batadv_claim_hash_lock_class_key);
+	batadv_hash_set_lock_class(bat_priv->backbone_hash,
+				   &batadv_backbone_hash_lock_class_key);
 
-	bla_start_timer(bat_priv);
-	return 1;
+	batadv_dbg(DBG_BLA, bat_priv, "bla hashes initialized\n");
+
+	batadv_bla_start_timer(bat_priv);
+	return 0;
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @bcast_packet: originator mac address
  * @hdr_size: maximum length of the frame
  *
@@ -1183,12 +1199,10 @@ int bla_init(struct bat_priv *bat_priv)
  * with a good chance that it is the same packet. If it is furthermore
  * sent by another host, drop it. We allow equal packets from
  * the same host however as this might be intended.
- *
- **/
-
-int bla_check_bcast_duplist(struct bat_priv *bat_priv,
-			    struct bcast_packet *bcast_packet,
-			    int hdr_size)
+ */
+int batadv_bla_check_bcast_duplist(struct bat_priv *bat_priv,
+				   struct bcast_packet *bcast_packet,
+				   int hdr_size)
 {
 	int i, length, curr;
 	uint8_t *content;
@@ -1209,13 +1223,13 @@ int bla_check_bcast_duplist(struct bat_priv *bat_priv,
 		/* we can stop searching if the entry is too old ;
 		 * later entries will be even older
 		 */
-		if (has_timed_out(entry->entrytime, DUPLIST_TIMEOUT))
+		if (batadv_has_timed_out(entry->entrytime, DUPLIST_TIMEOUT))
 			break;
 
 		if (entry->crc != crc)
 			continue;
 
-		if (compare_eth(entry->orig, bcast_packet->orig))
+		if (batadv_compare_eth(entry->orig, bcast_packet->orig))
 			continue;
 
 		/* this entry seems to match: same crc, not too old,
@@ -1237,17 +1251,14 @@ int bla_check_bcast_duplist(struct bat_priv *bat_priv,
 
 
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @orig: originator mac address
  *
  * check if the originator is a gateway for any VLAN ID.
  *
  * returns 1 if it is found, 0 otherwise
- *
  */
-
-int bla_is_backbone_gw_orig(struct bat_priv *bat_priv, uint8_t *orig)
+int batadv_bla_is_backbone_gw_orig(struct bat_priv *bat_priv, uint8_t *orig)
 {
 	struct hashtable_t *hash = bat_priv->backbone_hash;
 	struct hlist_head *head;
@@ -1266,7 +1277,7 @@ int bla_is_backbone_gw_orig(struct bat_priv *bat_priv, uint8_t *orig)
 
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(backbone_gw, node, head, hash_entry) {
-			if (compare_eth(backbone_gw->orig, orig)) {
+			if (batadv_compare_eth(backbone_gw->orig, orig)) {
 				rcu_read_unlock();
 				return 1;
 			}
@@ -1278,18 +1289,16 @@ int bla_is_backbone_gw_orig(struct bat_priv *bat_priv, uint8_t *orig)
 }
 
 
-/**
- * @skb: the frame to be checked
+/* @skb: the frame to be checked
  * @orig_node: the orig_node of the frame
  * @hdr_size: maximum length of the frame
  *
  * bla_is_backbone_gw inspects the skb for the VLAN ID and returns 1
  * if the orig_node is also a gateway on the soft interface, otherwise it
  * returns 0.
- *
  */
-int bla_is_backbone_gw(struct sk_buff *skb,
-		       struct orig_node *orig_node, int hdr_size)
+int batadv_bla_is_backbone_gw(struct sk_buff *skb,
+			      struct orig_node *orig_node, int hdr_size)
 {
 	struct ethhdr *ethhdr;
 	struct vlan_ethhdr *vhdr;
@@ -1315,40 +1324,38 @@ int bla_is_backbone_gw(struct sk_buff *skb,
 	}
 
 	/* see if this originator is a backbone gw for this VLAN */
-
-	backbone_gw = backbone_hash_find(orig_node->bat_priv,
-					 orig_node->orig, vid);
+	backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv,
+						orig_node->orig, vid);
 	if (!backbone_gw)
 		return 0;
 
-	backbone_gw_free_ref(backbone_gw);
+	batadv_backbone_gw_free_ref(backbone_gw);
 	return 1;
 }
 
 /* free all bla structures (for softinterface free or module unload) */
-void bla_free(struct bat_priv *bat_priv)
+void batadv_bla_free(struct bat_priv *bat_priv)
 {
 	struct hard_iface *primary_if;
 
 	cancel_delayed_work_sync(&bat_priv->bla_work);
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 
 	if (bat_priv->claim_hash) {
-		bla_purge_claims(bat_priv, primary_if, 1);
-		hash_destroy(bat_priv->claim_hash);
+		batadv_bla_purge_claims(bat_priv, primary_if, 1);
+		batadv_hash_destroy(bat_priv->claim_hash);
 		bat_priv->claim_hash = NULL;
 	}
 	if (bat_priv->backbone_hash) {
-		bla_purge_backbone_gw(bat_priv, 1);
-		hash_destroy(bat_priv->backbone_hash);
+		batadv_bla_purge_backbone_gw(bat_priv, 1);
+		batadv_hash_destroy(bat_priv->backbone_hash);
 		bat_priv->backbone_hash = NULL;
 	}
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @skb: the frame to be checked
  * @vid: the VLAN ID of the frame
  *
@@ -1359,9 +1366,8 @@ void bla_free(struct bat_priv *bat_priv)
  * in these cases, the skb is further handled by this function and
  * returns 1, otherwise it returns 0 and the caller shall further
  * process the skb.
- *
  */
-int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
+int batadv_bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
 {
 	struct ethhdr *ethhdr;
 	struct claim search_claim, *claim = NULL;
@@ -1370,7 +1376,7 @@ int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
 
 	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto handled;
 
@@ -1385,21 +1391,21 @@ int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
 
 	memcpy(search_claim.addr, ethhdr->h_source, ETH_ALEN);
 	search_claim.vid = vid;
-	claim = claim_hash_find(bat_priv, &search_claim);
+	claim = batadv_claim_hash_find(bat_priv, &search_claim);
 
 	if (!claim) {
 		/* possible optimization: race for a claim */
 		/* No claim exists yet, claim it for us!
 		 */
-		handle_claim(bat_priv, primary_if,
-			     primary_if->net_dev->dev_addr,
-			     ethhdr->h_source, vid);
+		batadv_handle_claim(bat_priv, primary_if,
+				    primary_if->net_dev->dev_addr,
+				    ethhdr->h_source, vid);
 		goto allow;
 	}
 
 	/* if it is our own claim ... */
-	if (compare_eth(claim->backbone_gw->orig,
-			primary_if->net_dev->dev_addr)) {
+	if (batadv_compare_eth(claim->backbone_gw->orig,
+			       primary_if->net_dev->dev_addr)) {
 		/* ... allow it in any case */
 		claim->lasttime = jiffies;
 		goto allow;
@@ -1414,13 +1420,13 @@ int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
 		 * send a claim and update the claim table
 		 * immediately.
 		 */
-		handle_claim(bat_priv, primary_if,
-			     primary_if->net_dev->dev_addr,
-			     ethhdr->h_source, vid);
+		batadv_handle_claim(bat_priv, primary_if,
+				    primary_if->net_dev->dev_addr,
+				    ethhdr->h_source, vid);
 		goto allow;
 	}
 allow:
-	bla_update_own_backbone_gw(bat_priv, primary_if, vid);
+	batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
 	ret = 0;
 	goto out;
 
@@ -1430,14 +1436,13 @@ handled:
 
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	if (claim)
-		claim_free_ref(claim);
+		batadv_claim_free_ref(claim);
 	return ret;
 }
 
-/**
- * @bat_priv: the bat priv with all the soft interface information
+/* @bat_priv: the bat priv with all the soft interface information
  * @skb: the frame to be checked
  * @vid: the VLAN ID of the frame
  *
@@ -1448,16 +1453,15 @@ out:
  * in these cases, the skb is further handled by this function and
  * returns 1, otherwise it returns 0 and the caller shall further
  * process the skb.
- *
  */
-int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
+int batadv_bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
 {
 	struct ethhdr *ethhdr;
 	struct claim search_claim, *claim = NULL;
 	struct hard_iface *primary_if;
 	int ret = 0;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
@@ -1467,7 +1471,7 @@ int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
 	/* in VLAN case, the mac header might not be set. */
 	skb_reset_mac_header(skb);
 
-	if (bla_process_claim(bat_priv, primary_if, skb))
+	if (batadv_bla_process_claim(bat_priv, primary_if, skb))
 		goto handled;
 
 	ethhdr = (struct ethhdr *)skb_mac_header(skb);
@@ -1480,21 +1484,21 @@ int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
 	memcpy(search_claim.addr, ethhdr->h_source, ETH_ALEN);
 	search_claim.vid = vid;
 
-	claim = claim_hash_find(bat_priv, &search_claim);
+	claim = batadv_claim_hash_find(bat_priv, &search_claim);
 
 	/* if no claim exists, allow it. */
 	if (!claim)
 		goto allow;
 
 	/* check if we are responsible. */
-	if (compare_eth(claim->backbone_gw->orig,
-			primary_if->net_dev->dev_addr)) {
+	if (batadv_compare_eth(claim->backbone_gw->orig,
+			       primary_if->net_dev->dev_addr)) {
 		/* if yes, the client has roamed and we have
 		 * to unclaim it.
 		 */
-		handle_unclaim(bat_priv, primary_if,
-			       primary_if->net_dev->dev_addr,
-			       ethhdr->h_source, vid);
+		batadv_handle_unclaim(bat_priv, primary_if,
+				      primary_if->net_dev->dev_addr,
+				      ethhdr->h_source, vid);
 		goto allow;
 	}
 
@@ -1511,20 +1515,20 @@ int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
 		goto allow;
 	}
 allow:
-	bla_update_own_backbone_gw(bat_priv, primary_if, vid);
+	batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
 	ret = 0;
 	goto out;
 handled:
 	ret = 1;
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	if (claim)
-		claim_free_ref(claim);
+		batadv_claim_free_ref(claim);
 	return ret;
 }
 
-int bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
+int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
 {
 	struct net_device *net_dev = (struct net_device *)seq->private;
 	struct bat_priv *bat_priv = netdev_priv(net_dev);
@@ -1536,8 +1540,9 @@ int bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
 	uint32_t i;
 	bool is_own;
 	int ret = 0;
+	uint8_t *primary_addr;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if) {
 		ret = seq_printf(seq,
 				 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
@@ -1552,9 +1557,10 @@ int bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
 		goto out;
 	}
 
+	primary_addr = primary_if->net_dev->dev_addr;
 	seq_printf(seq,
 		   "Claims announced for the mesh %s (orig %pM, group id %04x)\n",
-		   net_dev->name, primary_if->net_dev->dev_addr,
+		   net_dev->name, primary_addr,
 		   ntohs(bat_priv->claim_dest.group));
 	seq_printf(seq, "   %-17s    %-5s    %-17s [o] (%-4s)\n",
 		   "Client", "VID", "Originator", "CRC");
@@ -1563,8 +1569,8 @@ int bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
 
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(claim, node, head, hash_entry) {
-			is_own = compare_eth(claim->backbone_gw->orig,
-					     primary_if->net_dev->dev_addr);
+			is_own = batadv_compare_eth(claim->backbone_gw->orig,
+						    primary_addr);
 			seq_printf(seq,	" * %pM on % 5d by %pM [%c] (%04x)\n",
 				   claim->addr, claim->vid,
 				   claim->backbone_gw->orig,
@@ -1575,6 +1581,6 @@ int bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
 	}
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	return ret;
 }
diff --git a/net/batman-adv/bridge_loop_avoidance.h b/net/batman-adv/bridge_loop_avoidance.h
index e39f93a..9818b1e 100644
--- a/net/batman-adv/bridge_loop_avoidance.h
+++ b/net/batman-adv/bridge_loop_avoidance.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich
  *
@@ -16,80 +15,82 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_BLA_H_
 #define _NET_BATMAN_ADV_BLA_H_
 
 #ifdef CONFIG_BATMAN_ADV_BLA
-int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid);
-int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid);
-int bla_is_backbone_gw(struct sk_buff *skb,
-		       struct orig_node *orig_node, int hdr_size);
-int bla_claim_table_seq_print_text(struct seq_file *seq, void *offset);
-int bla_is_backbone_gw_orig(struct bat_priv *bat_priv, uint8_t *orig);
-int bla_check_bcast_duplist(struct bat_priv *bat_priv,
-			    struct bcast_packet *bcast_packet, int hdr_size);
-void bla_update_orig_address(struct bat_priv *bat_priv,
-			     struct hard_iface *primary_if,
-			     struct hard_iface *oldif);
-int bla_init(struct bat_priv *bat_priv);
-void bla_free(struct bat_priv *bat_priv);
+int batadv_bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid);
+int batadv_bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid);
+int batadv_bla_is_backbone_gw(struct sk_buff *skb,
+			      struct orig_node *orig_node, int hdr_size);
+int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset);
+int batadv_bla_is_backbone_gw_orig(struct bat_priv *bat_priv, uint8_t *orig);
+int batadv_bla_check_bcast_duplist(struct bat_priv *bat_priv,
+				   struct bcast_packet *bcast_packet,
+				   int hdr_size);
+void batadv_bla_update_orig_address(struct bat_priv *bat_priv,
+				    struct hard_iface *primary_if,
+				    struct hard_iface *oldif);
+int batadv_bla_init(struct bat_priv *bat_priv);
+void batadv_bla_free(struct bat_priv *bat_priv);
 
 #define BLA_CRC_INIT	0
 #else /* ifdef CONFIG_BATMAN_ADV_BLA */
 
-static inline int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb,
-			 short vid)
+static inline int batadv_bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb,
+				short vid)
 {
 	return 0;
 }
 
-static inline int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb,
-			 short vid)
+static inline int batadv_bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb,
+				short vid)
 {
 	return 0;
 }
 
-static inline int bla_is_backbone_gw(struct sk_buff *skb,
-				     struct orig_node *orig_node,
-				     int hdr_size)
+static inline int batadv_bla_is_backbone_gw(struct sk_buff *skb,
+					    struct orig_node *orig_node,
+					    int hdr_size)
 {
 	return 0;
 }
 
-static inline int bla_claim_table_seq_print_text(struct seq_file *seq,
-						 void *offset)
+static inline int batadv_bla_claim_table_seq_print_text(struct seq_file *seq,
+							void *offset)
 {
 	return 0;
 }
 
-static inline int bla_is_backbone_gw_orig(struct bat_priv *bat_priv,
-					  uint8_t *orig)
+static inline int batadv_bla_is_backbone_gw_orig(struct bat_priv *bat_priv,
+						 uint8_t *orig)
 {
 	return 0;
 }
 
-static inline int bla_check_bcast_duplist(struct bat_priv *bat_priv,
-					  struct bcast_packet *bcast_packet,
-					  int hdr_size)
+static inline int
+batadv_bla_check_bcast_duplist(struct bat_priv *bat_priv,
+			       struct bcast_packet *bcast_packet,
+			       int hdr_size)
 {
 	return 0;
 }
 
-static inline void bla_update_orig_address(struct bat_priv *bat_priv,
-					   struct hard_iface *primary_if,
-					   struct hard_iface *oldif)
+static inline void
+batadv_bla_update_orig_address(struct bat_priv *bat_priv,
+			       struct hard_iface *primary_if,
+			       struct hard_iface *oldif)
 {
 }
 
-static inline int bla_init(struct bat_priv *bat_priv)
+static inline int batadv_bla_init(struct bat_priv *bat_priv)
 {
 	return 1;
 }
 
-static inline void bla_free(struct bat_priv *bat_priv)
+static inline void batadv_bla_free(struct bat_priv *bat_priv)
 {
 }
 
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 47f7186..efe7519 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -33,17 +31,18 @@
 #include <linux/if_vlan.h>
 
 /* This is the offset of the options field in a dhcp packet starting at
- * the beginning of the dhcp header */
+ * the beginning of the dhcp header
+ */
 #define DHCP_OPTIONS_OFFSET 240
 #define DHCP_REQUEST 3
 
-static void gw_node_free_ref(struct gw_node *gw_node)
+static void batadv_gw_node_free_ref(struct gw_node *gw_node)
 {
 	if (atomic_dec_and_test(&gw_node->refcount))
 		kfree_rcu(gw_node, rcu);
 }
 
-static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv)
+static struct gw_node *batadv_gw_get_selected_gw_node(struct bat_priv *bat_priv)
 {
 	struct gw_node *gw_node;
 
@@ -60,12 +59,12 @@ out:
 	return gw_node;
 }
 
-struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv)
+struct orig_node *batadv_gw_get_selected_orig(struct bat_priv *bat_priv)
 {
 	struct gw_node *gw_node;
 	struct orig_node *orig_node = NULL;
 
-	gw_node = gw_get_selected_gw_node(bat_priv);
+	gw_node = batadv_gw_get_selected_gw_node(bat_priv);
 	if (!gw_node)
 		goto out;
 
@@ -81,11 +80,12 @@ unlock:
 	rcu_read_unlock();
 out:
 	if (gw_node)
-		gw_node_free_ref(gw_node);
+		batadv_gw_node_free_ref(gw_node);
 	return orig_node;
 }
 
-static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
+static void batadv_gw_select(struct bat_priv *bat_priv,
+			     struct gw_node *new_gw_node)
 {
 	struct gw_node *curr_gw_node;
 
@@ -98,17 +98,17 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
 	rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
 
 	if (curr_gw_node)
-		gw_node_free_ref(curr_gw_node);
+		batadv_gw_node_free_ref(curr_gw_node);
 
 	spin_unlock_bh(&bat_priv->gw_list_lock);
 }
 
-void gw_deselect(struct bat_priv *bat_priv)
+void batadv_gw_deselect(struct bat_priv *bat_priv)
 {
 	atomic_set(&bat_priv->gw_reselect, 1);
 }
 
-static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
+static struct gw_node *batadv_gw_get_best_gw_node(struct bat_priv *bat_priv)
 {
 	struct neigh_node *router;
 	struct hlist_node *node;
@@ -116,13 +116,15 @@ static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
 	uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
 	uint8_t max_tq = 0;
 	int down, up;
+	struct orig_node *orig_node;
 
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
 		if (gw_node->deleted)
 			continue;
 
-		router = orig_node_get_router(gw_node->orig_node);
+		orig_node = gw_node->orig_node;
+		router = batadv_orig_node_get_router(orig_node);
 		if (!router)
 			continue;
 
@@ -131,8 +133,8 @@ static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
 
 		switch (atomic_read(&bat_priv->gw_sel_class)) {
 		case 1: /* fast connection */
-			gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
-					     &down, &up);
+			batadv_gw_bandwidth_to_kbit(orig_node->gw_flags,
+						    &down, &up);
 
 			tmp_gw_factor = (router->tq_avg * router->tq_avg *
 					 down * 100 * 100) /
@@ -143,23 +145,22 @@ static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
 			    ((tmp_gw_factor == max_gw_factor) &&
 			     (router->tq_avg > max_tq))) {
 				if (curr_gw)
-					gw_node_free_ref(curr_gw);
+					batadv_gw_node_free_ref(curr_gw);
 				curr_gw = gw_node;
 				atomic_inc(&curr_gw->refcount);
 			}
 			break;
 
-		default: /**
-			  * 2:  stable connection (use best statistic)
+		default: /* 2:  stable connection (use best statistic)
 			  * 3:  fast-switch (use best statistic but change as
 			  *     soon as a better gateway appears)
 			  * XX: late-switch (use best statistic but change as
 			  *     soon as a better gateway appears which has
 			  *     $routing_class more tq points)
-			  **/
+			  */
 			if (router->tq_avg > max_tq) {
 				if (curr_gw)
-					gw_node_free_ref(curr_gw);
+					batadv_gw_node_free_ref(curr_gw);
 				curr_gw = gw_node;
 				atomic_inc(&curr_gw->refcount);
 			}
@@ -172,37 +173,36 @@ static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
 		if (tmp_gw_factor > max_gw_factor)
 			max_gw_factor = tmp_gw_factor;
 
-		gw_node_free_ref(gw_node);
+		batadv_gw_node_free_ref(gw_node);
 
 next:
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 	}
 	rcu_read_unlock();
 
 	return curr_gw;
 }
 
-void gw_election(struct bat_priv *bat_priv)
+void batadv_gw_election(struct bat_priv *bat_priv)
 {
 	struct gw_node *curr_gw = NULL, *next_gw = NULL;
 	struct neigh_node *router = NULL;
 	char gw_addr[18] = { '\0' };
 
-	/**
-	 * The batman daemon checks here if we already passed a full originator
+	/* The batman daemon checks here if we already passed a full originator
 	 * cycle in order to make sure we don't choose the first gateway we
 	 * hear about. This check is based on the daemon's uptime which we
 	 * don't have.
-	 **/
+	 */
 	if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
 		goto out;
 
 	if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
 		goto out;
 
-	curr_gw = gw_get_selected_gw_node(bat_priv);
+	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 
-	next_gw = gw_get_best_gw_node(bat_priv);
+	next_gw = batadv_gw_get_best_gw_node(bat_priv);
 
 	if (curr_gw == next_gw)
 		goto out;
@@ -210,53 +210,54 @@ void gw_election(struct bat_priv *bat_priv)
 	if (next_gw) {
 		sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
 
-		router = orig_node_get_router(next_gw->orig_node);
+		router = batadv_orig_node_get_router(next_gw->orig_node);
 		if (!router) {
-			gw_deselect(bat_priv);
+			batadv_gw_deselect(bat_priv);
 			goto out;
 		}
 	}
 
 	if ((curr_gw) && (!next_gw)) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Removing selected gateway - no gateway in range\n");
-		throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Removing selected gateway - no gateway in range\n");
+		batadv_throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
 	} else if ((!curr_gw) && (next_gw)) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
-			next_gw->orig_node->orig, next_gw->orig_node->gw_flags,
-			router->tq_avg);
-		throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
+			   next_gw->orig_node->orig,
+			   next_gw->orig_node->gw_flags, router->tq_avg);
+		batadv_throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
 	} else {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Changing route to gateway %pM (gw_flags: %i, tq: %i)\n",
-			next_gw->orig_node->orig, next_gw->orig_node->gw_flags,
-			router->tq_avg);
-		throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Changing route to gateway %pM (gw_flags: %i, tq: %i)\n",
+			   next_gw->orig_node->orig,
+			   next_gw->orig_node->gw_flags, router->tq_avg);
+		batadv_throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
 	}
 
-	gw_select(bat_priv, next_gw);
+	batadv_gw_select(bat_priv, next_gw);
 
 out:
 	if (curr_gw)
-		gw_node_free_ref(curr_gw);
+		batadv_gw_node_free_ref(curr_gw);
 	if (next_gw)
-		gw_node_free_ref(next_gw);
+		batadv_gw_node_free_ref(next_gw);
 	if (router)
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 }
 
-void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
+void batadv_gw_check_election(struct bat_priv *bat_priv,
+			      struct orig_node *orig_node)
 {
 	struct orig_node *curr_gw_orig;
 	struct neigh_node *router_gw = NULL, *router_orig = NULL;
 	uint8_t gw_tq_avg, orig_tq_avg;
 
-	curr_gw_orig = gw_get_selected_orig(bat_priv);
+	curr_gw_orig = batadv_gw_get_selected_orig(bat_priv);
 	if (!curr_gw_orig)
 		goto deselect;
 
-	router_gw = orig_node_get_router(curr_gw_orig);
+	router_gw = batadv_orig_node_get_router(curr_gw_orig);
 	if (!router_gw)
 		goto deselect;
 
@@ -264,7 +265,7 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
 	if (curr_gw_orig == orig_node)
 		goto out;
 
-	router_orig = orig_node_get_router(orig_node);
+	router_orig = batadv_orig_node_get_router(orig_node);
 	if (!router_orig)
 		goto out;
 
@@ -275,33 +276,33 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
 	if (orig_tq_avg < gw_tq_avg)
 		goto out;
 
-	/**
-	 * if the routing class is greater than 3 the value tells us how much
+	/* if the routing class is greater than 3 the value tells us how much
 	 * greater the TQ value of the new gateway must be
-	 **/
+	 */
 	if ((atomic_read(&bat_priv->gw_sel_class) > 3) &&
 	    (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class)))
 		goto out;
 
-	bat_dbg(DBG_BATMAN, bat_priv,
-		"Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n",
-		gw_tq_avg, orig_tq_avg);
+	batadv_dbg(DBG_BATMAN, bat_priv,
+		   "Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n",
+		   gw_tq_avg, orig_tq_avg);
 
 deselect:
-	gw_deselect(bat_priv);
+	batadv_gw_deselect(bat_priv);
 out:
 	if (curr_gw_orig)
-		orig_node_free_ref(curr_gw_orig);
+		batadv_orig_node_free_ref(curr_gw_orig);
 	if (router_gw)
-		neigh_node_free_ref(router_gw);
+		batadv_neigh_node_free_ref(router_gw);
 	if (router_orig)
-		neigh_node_free_ref(router_orig);
+		batadv_neigh_node_free_ref(router_orig);
 
 	return;
 }
 
-static void gw_node_add(struct bat_priv *bat_priv,
-			struct orig_node *orig_node, uint8_t new_gwflags)
+static void batadv_gw_node_add(struct bat_priv *bat_priv,
+			       struct orig_node *orig_node,
+			       uint8_t new_gwflags)
 {
 	struct gw_node *gw_node;
 	int down, up;
@@ -318,47 +319,46 @@ static void gw_node_add(struct bat_priv *bat_priv,
 	hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list);
 	spin_unlock_bh(&bat_priv->gw_list_lock);
 
-	gw_bandwidth_to_kbit(new_gwflags, &down, &up);
-	bat_dbg(DBG_BATMAN, bat_priv,
-		"Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n",
-		orig_node->orig, new_gwflags,
-		(down > 2048 ? down / 1024 : down),
-		(down > 2048 ? "MBit" : "KBit"),
-		(up > 2048 ? up / 1024 : up),
-		(up > 2048 ? "MBit" : "KBit"));
+	batadv_gw_bandwidth_to_kbit(new_gwflags, &down, &up);
+	batadv_dbg(DBG_BATMAN, bat_priv,
+		   "Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n",
+		   orig_node->orig, new_gwflags,
+		   (down > 2048 ? down / 1024 : down),
+		   (down > 2048 ? "MBit" : "KBit"),
+		   (up > 2048 ? up / 1024 : up),
+		   (up > 2048 ? "MBit" : "KBit"));
 }
 
-void gw_node_update(struct bat_priv *bat_priv,
-		    struct orig_node *orig_node, uint8_t new_gwflags)
+void batadv_gw_node_update(struct bat_priv *bat_priv,
+			   struct orig_node *orig_node, uint8_t new_gwflags)
 {
 	struct hlist_node *node;
 	struct gw_node *gw_node, *curr_gw;
 
-	/**
-	 * Note: We don't need a NULL check here, since curr_gw never gets
+	/* Note: We don't need a NULL check here, since curr_gw never gets
 	 * dereferenced. If curr_gw is NULL we also should not exit as we may
 	 * have this gateway in our list (duplication check!) even though we
 	 * have no currently selected gateway.
 	 */
-	curr_gw = gw_get_selected_gw_node(bat_priv);
+	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
 		if (gw_node->orig_node != orig_node)
 			continue;
 
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Gateway class of originator %pM changed from %i to %i\n",
-			orig_node->orig, gw_node->orig_node->gw_flags,
-			new_gwflags);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Gateway class of originator %pM changed from %i to %i\n",
+			   orig_node->orig, gw_node->orig_node->gw_flags,
+			   new_gwflags);
 
 		gw_node->deleted = 0;
 
 		if (new_gwflags == NO_FLAGS) {
 			gw_node->deleted = jiffies;
-			bat_dbg(DBG_BATMAN, bat_priv,
-				"Gateway %pM removed from gateway list\n",
-				orig_node->orig);
+			batadv_dbg(DBG_BATMAN, bat_priv,
+				   "Gateway %pM removed from gateway list\n",
+				   orig_node->orig);
 
 			if (gw_node == curr_gw)
 				goto deselect;
@@ -370,31 +370,32 @@ void gw_node_update(struct bat_priv *bat_priv,
 	if (new_gwflags == NO_FLAGS)
 		goto unlock;
 
-	gw_node_add(bat_priv, orig_node, new_gwflags);
+	batadv_gw_node_add(bat_priv, orig_node, new_gwflags);
 	goto unlock;
 
 deselect:
-	gw_deselect(bat_priv);
+	batadv_gw_deselect(bat_priv);
 unlock:
 	rcu_read_unlock();
 
 	if (curr_gw)
-		gw_node_free_ref(curr_gw);
+		batadv_gw_node_free_ref(curr_gw);
 }
 
-void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
+void batadv_gw_node_delete(struct bat_priv *bat_priv,
+			   struct orig_node *orig_node)
 {
-	gw_node_update(bat_priv, orig_node, 0);
+	batadv_gw_node_update(bat_priv, orig_node, 0);
 }
 
-void gw_node_purge(struct bat_priv *bat_priv)
+void batadv_gw_node_purge(struct bat_priv *bat_priv)
 {
 	struct gw_node *gw_node, *curr_gw;
 	struct hlist_node *node, *node_tmp;
 	unsigned long timeout = msecs_to_jiffies(2 * PURGE_TIMEOUT);
 	int do_deselect = 0;
 
-	curr_gw = gw_get_selected_gw_node(bat_priv);
+	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 
 	spin_lock_bh(&bat_priv->gw_list_lock);
 
@@ -409,36 +410,35 @@ void gw_node_purge(struct bat_priv *bat_priv)
 			do_deselect = 1;
 
 		hlist_del_rcu(&gw_node->list);
-		gw_node_free_ref(gw_node);
+		batadv_gw_node_free_ref(gw_node);
 	}
 
 	spin_unlock_bh(&bat_priv->gw_list_lock);
 
 	/* gw_deselect() needs to acquire the gw_list_lock */
 	if (do_deselect)
-		gw_deselect(bat_priv);
+		batadv_gw_deselect(bat_priv);
 
 	if (curr_gw)
-		gw_node_free_ref(curr_gw);
+		batadv_gw_node_free_ref(curr_gw);
 }
 
-/**
- * fails if orig_node has no router
- */
-static int _write_buffer_text(struct bat_priv *bat_priv, struct seq_file *seq,
-			      const struct gw_node *gw_node)
+/* fails if orig_node has no router */
+static int batadv_write_buffer_text(struct bat_priv *bat_priv,
+				     struct seq_file *seq,
+				     const struct gw_node *gw_node)
 {
 	struct gw_node *curr_gw;
 	struct neigh_node *router;
 	int down, up, ret = -1;
 
-	gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
+	batadv_gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
 
-	router = orig_node_get_router(gw_node->orig_node);
+	router = batadv_orig_node_get_router(gw_node->orig_node);
 	if (!router)
 		goto out;
 
-	curr_gw = gw_get_selected_gw_node(bat_priv);
+	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 
 	ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
 			 (curr_gw == gw_node ? "=>" : "  "),
@@ -451,14 +451,14 @@ static int _write_buffer_text(struct bat_priv *bat_priv, struct seq_file *seq,
 			 (up > 2048 ? up / 1024 : up),
 			 (up > 2048 ? "MBit" : "KBit"));
 
-	neigh_node_free_ref(router);
+	batadv_neigh_node_free_ref(router);
 	if (curr_gw)
-		gw_node_free_ref(curr_gw);
+		batadv_gw_node_free_ref(curr_gw);
 out:
 	return ret;
 }
 
-int gw_client_seq_print_text(struct seq_file *seq, void *offset)
+int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
 {
 	struct net_device *net_dev = (struct net_device *)seq->private;
 	struct bat_priv *bat_priv = netdev_priv(net_dev);
@@ -467,7 +467,7 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
 	struct hlist_node *node;
 	int gw_count = 0, ret = 0;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if) {
 		ret = seq_printf(seq,
 				 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
@@ -494,7 +494,7 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
 			continue;
 
 		/* fails if orig_node has no router */
-		if (_write_buffer_text(bat_priv, seq, gw_node) < 0)
+		if (batadv_write_buffer_text(bat_priv, seq, gw_node) < 0)
 			continue;
 
 		gw_count++;
@@ -506,11 +506,11 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
 
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	return ret;
 }
 
-static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
+static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
 {
 	int ret = false;
 	unsigned char *p;
@@ -530,12 +530,14 @@ static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
 	/* Access the dhcp option lists. Each entry is made up by:
 	 * - octet 1: option type
 	 * - octet 2: option data len (only if type != 255 and 0)
-	 * - octet 3: option data */
+	 * - octet 3: option data
+	 */
 	while (*p != 255 && !ret) {
 		/* p now points to the first octet: option type */
 		if (*p == 53) {
 			/* type 53 is the message type option.
-			 * Jump the len octet and go to the data octet */
+			 * Jump the len octet and go to the data octet
+			 */
 			if (pkt_len < 2)
 				goto out;
 			p += 2;
@@ -568,7 +570,7 @@ out:
 	return ret;
 }
 
-bool gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
+bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
 {
 	struct ethhdr *ethhdr;
 	struct iphdr *iphdr;
@@ -634,8 +636,8 @@ bool gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
 	return true;
 }
 
-bool gw_out_of_range(struct bat_priv *bat_priv,
-		     struct sk_buff *skb, struct ethhdr *ethhdr)
+bool batadv_gw_out_of_range(struct bat_priv *bat_priv,
+			    struct sk_buff *skb, struct ethhdr *ethhdr)
 {
 	struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
 	struct orig_node *orig_dst_node = NULL;
@@ -644,30 +646,31 @@ bool gw_out_of_range(struct bat_priv *bat_priv,
 	unsigned int header_len = 0;
 	uint8_t curr_tq_avg;
 
-	ret = gw_is_dhcp_target(skb, &header_len);
+	ret = batadv_gw_is_dhcp_target(skb, &header_len);
 	if (!ret)
 		goto out;
 
-	orig_dst_node = transtable_search(bat_priv, ethhdr->h_source,
-					  ethhdr->h_dest);
+	orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
+						 ethhdr->h_dest);
 	if (!orig_dst_node)
 		goto out;
 
 	if (!orig_dst_node->gw_flags)
 		goto out;
 
-	ret = is_type_dhcprequest(skb, header_len);
+	ret = batadv_is_type_dhcprequest(skb, header_len);
 	if (!ret)
 		goto out;
 
 	switch (atomic_read(&bat_priv->gw_mode)) {
 	case GW_MODE_SERVER:
 		/* If we are a GW then we are our best GW. We can artificially
-		 * set the tq towards ourself as the maximum value */
+		 * set the tq towards ourself as the maximum value
+		 */
 		curr_tq_avg = TQ_MAX_VALUE;
 		break;
 	case GW_MODE_CLIENT:
-		curr_gw = gw_get_selected_gw_node(bat_priv);
+		curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 		if (!curr_gw)
 			goto out;
 
@@ -677,8 +680,10 @@ bool gw_out_of_range(struct bat_priv *bat_priv,
 
 		/* If the dhcp packet has been sent to a different gw,
 		 * we have to evaluate whether the old gw is still
-		 * reliable enough */
-		neigh_curr = find_router(bat_priv, curr_gw->orig_node, NULL);
+		 * reliable enough
+		 */
+		neigh_curr = batadv_find_router(bat_priv, curr_gw->orig_node,
+						NULL);
 		if (!neigh_curr)
 			goto out;
 
@@ -689,7 +694,7 @@ bool gw_out_of_range(struct bat_priv *bat_priv,
 		goto out;
 	}
 
-	neigh_old = find_router(bat_priv, orig_dst_node, NULL);
+	neigh_old = batadv_find_router(bat_priv, orig_dst_node, NULL);
 	if (!neigh_old)
 		goto out;
 
@@ -698,12 +703,12 @@ bool gw_out_of_range(struct bat_priv *bat_priv,
 
 out:
 	if (orig_dst_node)
-		orig_node_free_ref(orig_dst_node);
+		batadv_orig_node_free_ref(orig_dst_node);
 	if (curr_gw)
-		gw_node_free_ref(curr_gw);
+		batadv_gw_node_free_ref(curr_gw);
 	if (neigh_old)
-		neigh_node_free_ref(neigh_old);
+		batadv_neigh_node_free_ref(neigh_old);
 	if (neigh_curr)
-		neigh_node_free_ref(neigh_curr);
+		batadv_neigh_node_free_ref(neigh_curr);
 	return out_of_range;
 }
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h
index bf56a5a..4529d42 100644
--- a/net/batman-adv/gateway_client.h
+++ b/net/batman-adv/gateway_client.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,23 +15,24 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_
 #define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_
 
-void gw_deselect(struct bat_priv *bat_priv);
-void gw_election(struct bat_priv *bat_priv);
-struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv);
-void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node);
-void gw_node_update(struct bat_priv *bat_priv,
-		    struct orig_node *orig_node, uint8_t new_gwflags);
-void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
-void gw_node_purge(struct bat_priv *bat_priv);
-int gw_client_seq_print_text(struct seq_file *seq, void *offset);
-bool gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len);
-bool gw_out_of_range(struct bat_priv *bat_priv,
-		     struct sk_buff *skb, struct ethhdr *ethhdr);
+void batadv_gw_deselect(struct bat_priv *bat_priv);
+void batadv_gw_election(struct bat_priv *bat_priv);
+struct orig_node *batadv_gw_get_selected_orig(struct bat_priv *bat_priv);
+void batadv_gw_check_election(struct bat_priv *bat_priv,
+			      struct orig_node *orig_node);
+void batadv_gw_node_update(struct bat_priv *bat_priv,
+			   struct orig_node *orig_node, uint8_t new_gwflags);
+void batadv_gw_node_delete(struct bat_priv *bat_priv,
+			   struct orig_node *orig_node);
+void batadv_gw_node_purge(struct bat_priv *bat_priv);
+int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset);
+bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len);
+bool batadv_gw_out_of_range(struct bat_priv *bat_priv,
+			    struct sk_buff *skb, struct ethhdr *ethhdr);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c
index ca57ac7..6edf37f 100644
--- a/net/batman-adv/gateway_common.c
+++ b/net/batman-adv/gateway_common.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -24,7 +22,7 @@
 #include "gateway_client.h"
 
 /* calculates the gateway class from kbit */
-static void kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class)
+static void batadv_kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class)
 {
 	int mdown = 0, tdown, tup, difference;
 	uint8_t sbit, part;
@@ -59,7 +57,7 @@ static void kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class)
 }
 
 /* returns the up and downspeeds in kbit, calculated from the class */
-void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up)
+void batadv_gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up)
 {
 	int sbit = (gw_srv_class & 0x80) >> 7;
 	int dpart = (gw_srv_class & 0x78) >> 3;
@@ -75,8 +73,8 @@ void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up)
 	*up = ((upart + 1) * (*down)) / 8;
 }
 
-static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
-			       int *up, int *down)
+static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff,
+				      int *up, int *down)
 {
 	int ret, multi = 1;
 	char *slash_ptr, *tmp_ptr;
@@ -136,14 +134,15 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
 	return true;
 }
 
-ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count)
+ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff,
+				size_t count)
 {
 	struct bat_priv *bat_priv = netdev_priv(net_dev);
 	long gw_bandwidth_tmp = 0;
 	int up = 0, down = 0;
 	bool ret;
 
-	ret = parse_gw_bandwidth(net_dev, buff, &up, &down);
+	ret = batadv_parse_gw_bandwidth(net_dev, buff, &up, &down);
 	if (!ret)
 		goto end;
 
@@ -153,16 +152,18 @@ ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count)
 	if (!up)
 		up = down / 5;
 
-	kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp);
+	batadv_kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp);
 
-	/**
-	 * the gw bandwidth we guessed above might not match the given
+	/* the gw bandwidth we guessed above might not match the given
 	 * speeds, hence we need to calculate it back to show the number
 	 * that is going to be propagated
-	 **/
-	gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, &down, &up);
+	 */
+	batadv_gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, &down, &up);
+
+	if (atomic_read(&bat_priv->gw_bandwidth) == gw_bandwidth_tmp)
+		return count;
 
-	gw_deselect(bat_priv);
+	batadv_gw_deselect(bat_priv);
 	bat_info(net_dev,
 		 "Changing gateway bandwidth from: '%i' to: '%ld' (propagating: %d%s/%d%s)\n",
 		 atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp,
diff --git a/net/batman-adv/gateway_common.h b/net/batman-adv/gateway_common.h
index b8fb11c..6f8a4d0 100644
--- a/net/batman-adv/gateway_common.h
+++ b/net/batman-adv/gateway_common.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_
@@ -32,7 +30,8 @@ enum gw_modes {
 #define GW_MODE_CLIENT_NAME	"client"
 #define GW_MODE_SERVER_NAME	"server"
 
-void gw_bandwidth_to_kbit(uint8_t gw_class, int *down, int *up);
-ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count);
+void batadv_gw_bandwidth_to_kbit(uint8_t gw_class, int *down, int *up);
+ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff,
+				size_t count);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index dc334fa..c22c145 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -32,7 +30,7 @@
 
 #include <linux/if_arp.h>
 
-void hardif_free_rcu(struct rcu_head *rcu)
+void batadv_hardif_free_rcu(struct rcu_head *rcu)
 {
 	struct hard_iface *hard_iface;
 
@@ -41,12 +39,12 @@ void hardif_free_rcu(struct rcu_head *rcu)
 	kfree(hard_iface);
 }
 
-struct hard_iface *hardif_get_by_netdev(const struct net_device *net_dev)
+struct hard_iface *batadv_hardif_get_by_netdev(const struct net_device *net_dev)
 {
 	struct hard_iface *hard_iface;
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 		if (hard_iface->net_dev == net_dev &&
 		    atomic_inc_not_zero(&hard_iface->refcount))
 			goto out;
@@ -59,7 +57,7 @@ out:
 	return hard_iface;
 }
 
-static int is_valid_iface(const struct net_device *net_dev)
+static int batadv_is_valid_iface(const struct net_device *net_dev)
 {
 	if (net_dev->flags & IFF_LOOPBACK)
 		return 0;
@@ -71,22 +69,19 @@ static int is_valid_iface(const struct net_device *net_dev)
 		return 0;
 
 	/* no batman over batman */
-	if (softif_is_valid(net_dev))
+	if (batadv_softif_is_valid(net_dev))
 		return 0;
 
-	/* Device is being bridged */
-	/* if (net_dev->priv_flags & IFF_BRIDGE_PORT)
-		return 0; */
-
 	return 1;
 }
 
-static struct hard_iface *hardif_get_active(const struct net_device *soft_iface)
+static struct hard_iface *
+batadv_hardif_get_active(const struct net_device *soft_iface)
 {
 	struct hard_iface *hard_iface;
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 		if (hard_iface->soft_iface != soft_iface)
 			continue;
 
@@ -102,13 +97,13 @@ out:
 	return hard_iface;
 }
 
-static void primary_if_update_addr(struct bat_priv *bat_priv,
-				   struct hard_iface *oldif)
+static void batadv_primary_if_update_addr(struct bat_priv *bat_priv,
+					  struct hard_iface *oldif)
 {
 	struct vis_packet *vis_packet;
 	struct hard_iface *primary_if;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
@@ -118,14 +113,14 @@ static void primary_if_update_addr(struct bat_priv *bat_priv,
 	memcpy(vis_packet->sender_orig,
 	       primary_if->net_dev->dev_addr, ETH_ALEN);
 
-	bla_update_orig_address(bat_priv, primary_if, oldif);
+	batadv_bla_update_orig_address(bat_priv, primary_if, oldif);
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 }
 
-static void primary_if_select(struct bat_priv *bat_priv,
-			      struct hard_iface *new_hard_iface)
+static void batadv_primary_if_select(struct bat_priv *bat_priv,
+				     struct hard_iface *new_hard_iface)
 {
 	struct hard_iface *curr_hard_iface;
 
@@ -141,14 +136,14 @@ static void primary_if_select(struct bat_priv *bat_priv,
 		goto out;
 
 	bat_priv->bat_algo_ops->bat_primary_iface_set(new_hard_iface);
-	primary_if_update_addr(bat_priv, curr_hard_iface);
+	batadv_primary_if_update_addr(bat_priv, curr_hard_iface);
 
 out:
 	if (curr_hard_iface)
-		hardif_free_ref(curr_hard_iface);
+		batadv_hardif_free_ref(curr_hard_iface);
 }
 
-static bool hardif_is_iface_up(const struct hard_iface *hard_iface)
+static bool batadv_hardif_is_iface_up(const struct hard_iface *hard_iface)
 {
 	if (hard_iface->net_dev->flags & IFF_UP)
 		return true;
@@ -156,12 +151,12 @@ static bool hardif_is_iface_up(const struct hard_iface *hard_iface)
 	return false;
 }
 
-static void check_known_mac_addr(const struct net_device *net_dev)
+static void batadv_check_known_mac_addr(const struct net_device *net_dev)
 {
 	const struct hard_iface *hard_iface;
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 		if ((hard_iface->if_status != IF_ACTIVE) &&
 		    (hard_iface->if_status != IF_TO_BE_ACTIVATED))
 			continue;
@@ -169,8 +164,8 @@ static void check_known_mac_addr(const struct net_device *net_dev)
 		if (hard_iface->net_dev == net_dev)
 			continue;
 
-		if (!compare_eth(hard_iface->net_dev->dev_addr,
-				 net_dev->dev_addr))
+		if (!batadv_compare_eth(hard_iface->net_dev->dev_addr,
+					net_dev->dev_addr))
 			continue;
 
 		pr_warn("The newly added mac address (%pM) already exists on: %s\n",
@@ -180,19 +175,20 @@ static void check_known_mac_addr(const struct net_device *net_dev)
 	rcu_read_unlock();
 }
 
-int hardif_min_mtu(struct net_device *soft_iface)
+int batadv_hardif_min_mtu(struct net_device *soft_iface)
 {
 	const struct bat_priv *bat_priv = netdev_priv(soft_iface);
 	const struct hard_iface *hard_iface;
 	/* allow big frames if all devices are capable to do so
-	 * (have MTU > 1500 + BAT_HEADER_LEN) */
+	 * (have MTU > 1500 + BAT_HEADER_LEN)
+	 */
 	int min_mtu = ETH_DATA_LEN;
 
 	if (atomic_read(&bat_priv->fragmentation))
 		goto out;
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 		if ((hard_iface->if_status != IF_ACTIVE) &&
 		    (hard_iface->if_status != IF_TO_BE_ACTIVATED))
 			continue;
@@ -209,16 +205,16 @@ out:
 }
 
 /* adjusts the MTU if a new interface with a smaller MTU appeared. */
-void update_min_mtu(struct net_device *soft_iface)
+void batadv_update_min_mtu(struct net_device *soft_iface)
 {
 	int min_mtu;
 
-	min_mtu = hardif_min_mtu(soft_iface);
+	min_mtu = batadv_hardif_min_mtu(soft_iface);
 	if (soft_iface->mtu != min_mtu)
 		soft_iface->mtu = min_mtu;
 }
 
-static void hardif_activate_interface(struct hard_iface *hard_iface)
+static void batadv_hardif_activate_interface(struct hard_iface *hard_iface)
 {
 	struct bat_priv *bat_priv;
 	struct hard_iface *primary_if = NULL;
@@ -231,25 +227,24 @@ static void hardif_activate_interface(struct hard_iface *hard_iface)
 	bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
 	hard_iface->if_status = IF_TO_BE_ACTIVATED;
 
-	/**
-	 * the first active interface becomes our primary interface or
+	/* the first active interface becomes our primary interface or
 	 * the next active interface after the old primary interface was removed
 	 */
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
-		primary_if_select(bat_priv, hard_iface);
+		batadv_primary_if_select(bat_priv, hard_iface);
 
 	bat_info(hard_iface->soft_iface, "Interface activated: %s\n",
 		 hard_iface->net_dev->name);
 
-	update_min_mtu(hard_iface->soft_iface);
+	batadv_update_min_mtu(hard_iface->soft_iface);
 
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 }
 
-static void hardif_deactivate_interface(struct hard_iface *hard_iface)
+static void batadv_hardif_deactivate_interface(struct hard_iface *hard_iface)
 {
 	if ((hard_iface->if_status != IF_ACTIVE) &&
 	    (hard_iface->if_status != IF_TO_BE_ACTIVATED))
@@ -260,11 +255,11 @@ static void hardif_deactivate_interface(struct hard_iface *hard_iface)
 	bat_info(hard_iface->soft_iface, "Interface deactivated: %s\n",
 		 hard_iface->net_dev->name);
 
-	update_min_mtu(hard_iface->soft_iface);
+	batadv_update_min_mtu(hard_iface->soft_iface);
 }
 
-int hardif_enable_interface(struct hard_iface *hard_iface,
-			    const char *iface_name)
+int batadv_hardif_enable_interface(struct hard_iface *hard_iface,
+				   const char *iface_name)
 {
 	struct bat_priv *bat_priv;
 	struct net_device *soft_iface;
@@ -284,7 +279,7 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
 	soft_iface = dev_get_by_name(&init_net, iface_name);
 
 	if (!soft_iface) {
-		soft_iface = softif_create(iface_name);
+		soft_iface = batadv_softif_create(iface_name);
 
 		if (!soft_iface) {
 			ret = -ENOMEM;
@@ -295,7 +290,7 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
 		dev_hold(soft_iface);
 	}
 
-	if (!softif_is_valid(soft_iface)) {
+	if (!batadv_softif_is_valid(soft_iface)) {
 		pr_err("Can't create batman mesh interface %s: already exists as regular interface\n",
 		       soft_iface->name);
 		ret = -EINVAL;
@@ -306,18 +301,16 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
 	bat_priv = netdev_priv(hard_iface->soft_iface);
 
 	ret = bat_priv->bat_algo_ops->bat_iface_enable(hard_iface);
-	if (ret < 0) {
-		ret = -ENOMEM;
+	if (ret < 0)
 		goto err_dev;
-	}
 
 	hard_iface->if_num = bat_priv->num_ifaces;
 	bat_priv->num_ifaces++;
 	hard_iface->if_status = IF_INACTIVE;
-	orig_hash_add_if(hard_iface, bat_priv->num_ifaces);
+	batadv_orig_hash_add_if(hard_iface, bat_priv->num_ifaces);
 
 	hard_iface->batman_adv_ptype.type = __constant_htons(ETH_P_BATMAN);
-	hard_iface->batman_adv_ptype.func = batman_skb_recv;
+	hard_iface->batman_adv_ptype.func = batadv_batman_skb_recv;
 	hard_iface->batman_adv_ptype.dev = hard_iface->net_dev;
 	dev_add_pack(&hard_iface->batman_adv_ptype);
 
@@ -339,15 +332,15 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
 			 hard_iface->net_dev->name, hard_iface->net_dev->mtu,
 			 ETH_DATA_LEN + BAT_HEADER_LEN);
 
-	if (hardif_is_iface_up(hard_iface))
-		hardif_activate_interface(hard_iface);
+	if (batadv_hardif_is_iface_up(hard_iface))
+		batadv_hardif_activate_interface(hard_iface);
 	else
 		bat_err(hard_iface->soft_iface,
 			"Not using interface %s (retrying later): interface not active\n",
 			hard_iface->net_dev->name);
 
 	/* begin scheduling originator messages on that interface */
-	schedule_bat_ogm(hard_iface);
+	batadv_schedule_bat_ogm(hard_iface);
 
 out:
 	return 0;
@@ -355,17 +348,17 @@ out:
 err_dev:
 	dev_put(soft_iface);
 err:
-	hardif_free_ref(hard_iface);
+	batadv_hardif_free_ref(hard_iface);
 	return ret;
 }
 
-void hardif_disable_interface(struct hard_iface *hard_iface)
+void batadv_hardif_disable_interface(struct hard_iface *hard_iface)
 {
 	struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
 	struct hard_iface *primary_if = NULL;
 
 	if (hard_iface->if_status == IF_ACTIVE)
-		hardif_deactivate_interface(hard_iface);
+		batadv_hardif_deactivate_interface(hard_iface);
 
 	if (hard_iface->if_status != IF_INACTIVE)
 		goto out;
@@ -375,47 +368,48 @@ void hardif_disable_interface(struct hard_iface *hard_iface)
 	dev_remove_pack(&hard_iface->batman_adv_ptype);
 
 	bat_priv->num_ifaces--;
-	orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
+	batadv_orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (hard_iface == primary_if) {
 		struct hard_iface *new_if;
 
-		new_if = hardif_get_active(hard_iface->soft_iface);
-		primary_if_select(bat_priv, new_if);
+		new_if = batadv_hardif_get_active(hard_iface->soft_iface);
+		batadv_primary_if_select(bat_priv, new_if);
 
 		if (new_if)
-			hardif_free_ref(new_if);
+			batadv_hardif_free_ref(new_if);
 	}
 
 	bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
 	hard_iface->if_status = IF_NOT_IN_USE;
 
 	/* delete all references to this hard_iface */
-	purge_orig_ref(bat_priv);
-	purge_outstanding_packets(bat_priv, hard_iface);
+	batadv_purge_orig_ref(bat_priv);
+	batadv_purge_outstanding_packets(bat_priv, hard_iface);
 	dev_put(hard_iface->soft_iface);
 
 	/* nobody uses this interface anymore */
 	if (!bat_priv->num_ifaces)
-		softif_destroy(hard_iface->soft_iface);
+		batadv_softif_destroy(hard_iface->soft_iface);
 
 	hard_iface->soft_iface = NULL;
-	hardif_free_ref(hard_iface);
+	batadv_hardif_free_ref(hard_iface);
 
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 }
 
-static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
+static struct hard_iface *
+batadv_hardif_add_interface(struct net_device *net_dev)
 {
 	struct hard_iface *hard_iface;
 	int ret;
 
 	ASSERT_RTNL();
 
-	ret = is_valid_iface(net_dev);
+	ret = batadv_is_valid_iface(net_dev);
 	if (ret != 1)
 		goto out;
 
@@ -425,7 +419,7 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
 	if (!hard_iface)
 		goto release_dev;
 
-	ret = sysfs_add_hardif(&hard_iface->hardif_obj, net_dev);
+	ret = batadv_sysfs_add_hardif(&hard_iface->hardif_obj, net_dev);
 	if (ret)
 		goto free_if;
 
@@ -437,11 +431,10 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
 	/* extra reference for return */
 	atomic_set(&hard_iface->refcount, 2);
 
-	check_known_mac_addr(hard_iface->net_dev);
-	list_add_tail_rcu(&hard_iface->list, &hardif_list);
+	batadv_check_known_mac_addr(hard_iface->net_dev);
+	list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list);
 
-	/**
-	 * This can't be called via a bat_priv callback because
+	/* This can't be called via a bat_priv callback because
 	 * we have no bat_priv yet.
 	 */
 	atomic_set(&hard_iface->seqno, 1);
@@ -457,97 +450,98 @@ out:
 	return NULL;
 }
 
-static void hardif_remove_interface(struct hard_iface *hard_iface)
+static void batadv_hardif_remove_interface(struct hard_iface *hard_iface)
 {
 	ASSERT_RTNL();
 
 	/* first deactivate interface */
 	if (hard_iface->if_status != IF_NOT_IN_USE)
-		hardif_disable_interface(hard_iface);
+		batadv_hardif_disable_interface(hard_iface);
 
 	if (hard_iface->if_status != IF_NOT_IN_USE)
 		return;
 
 	hard_iface->if_status = IF_TO_BE_REMOVED;
-	sysfs_del_hardif(&hard_iface->hardif_obj);
-	hardif_free_ref(hard_iface);
+	batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
+	batadv_hardif_free_ref(hard_iface);
 }
 
-void hardif_remove_interfaces(void)
+void batadv_hardif_remove_interfaces(void)
 {
 	struct hard_iface *hard_iface, *hard_iface_tmp;
 
 	rtnl_lock();
 	list_for_each_entry_safe(hard_iface, hard_iface_tmp,
-				 &hardif_list, list) {
+				 &batadv_hardif_list, list) {
 		list_del_rcu(&hard_iface->list);
-		hardif_remove_interface(hard_iface);
+		batadv_hardif_remove_interface(hard_iface);
 	}
 	rtnl_unlock();
 }
 
-static int hard_if_event(struct notifier_block *this,
-			 unsigned long event, void *ptr)
+static int batadv_hard_if_event(struct notifier_block *this,
+				unsigned long event, void *ptr)
 {
 	struct net_device *net_dev = ptr;
-	struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
+	struct hard_iface *hard_iface = batadv_hardif_get_by_netdev(net_dev);
 	struct hard_iface *primary_if = NULL;
 	struct bat_priv *bat_priv;
 
 	if (!hard_iface && event == NETDEV_REGISTER)
-		hard_iface = hardif_add_interface(net_dev);
+		hard_iface = batadv_hardif_add_interface(net_dev);
 
 	if (!hard_iface)
 		goto out;
 
 	switch (event) {
 	case NETDEV_UP:
-		hardif_activate_interface(hard_iface);
+		batadv_hardif_activate_interface(hard_iface);
 		break;
 	case NETDEV_GOING_DOWN:
 	case NETDEV_DOWN:
-		hardif_deactivate_interface(hard_iface);
+		batadv_hardif_deactivate_interface(hard_iface);
 		break;
 	case NETDEV_UNREGISTER:
 		list_del_rcu(&hard_iface->list);
 
-		hardif_remove_interface(hard_iface);
+		batadv_hardif_remove_interface(hard_iface);
 		break;
 	case NETDEV_CHANGEMTU:
 		if (hard_iface->soft_iface)
-			update_min_mtu(hard_iface->soft_iface);
+			batadv_update_min_mtu(hard_iface->soft_iface);
 		break;
 	case NETDEV_CHANGEADDR:
 		if (hard_iface->if_status == IF_NOT_IN_USE)
 			goto hardif_put;
 
-		check_known_mac_addr(hard_iface->net_dev);
+		batadv_check_known_mac_addr(hard_iface->net_dev);
 
 		bat_priv = netdev_priv(hard_iface->soft_iface);
 		bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
 
-		primary_if = primary_if_get_selected(bat_priv);
+		primary_if = batadv_primary_if_get_selected(bat_priv);
 		if (!primary_if)
 			goto hardif_put;
 
 		if (hard_iface == primary_if)
-			primary_if_update_addr(bat_priv, NULL);
+			batadv_primary_if_update_addr(bat_priv, NULL);
 		break;
 	default:
 		break;
 	}
 
 hardif_put:
-	hardif_free_ref(hard_iface);
+	batadv_hardif_free_ref(hard_iface);
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	return NOTIFY_DONE;
 }
 
 /* This function returns true if the interface represented by ifindex is a
- * 802.11 wireless device */
-bool is_wifi_iface(int ifindex)
+ * 802.11 wireless device
+ */
+bool batadv_is_wifi_iface(int ifindex)
 {
 	struct net_device *net_device = NULL;
 	bool ret = false;
@@ -561,7 +555,8 @@ bool is_wifi_iface(int ifindex)
 
 #ifdef CONFIG_WIRELESS_EXT
 	/* pre-cfg80211 drivers have to implement WEXT, so it is possible to
-	 * check for wireless_handlers != NULL */
+	 * check for wireless_handlers != NULL
+	 */
 	if (net_device->wireless_handlers)
 		ret = true;
 	else
@@ -575,6 +570,6 @@ out:
 	return ret;
 }
 
-struct notifier_block hard_if_notifier = {
-	.notifier_call = hard_if_event,
+struct notifier_block batadv_hard_if_notifier = {
+	.notifier_call = batadv_hard_if_event,
 };
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index e68c565..d66dabd 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_
@@ -31,27 +29,28 @@ enum hard_if_state {
 	IF_I_WANT_YOU
 };
 
-extern struct notifier_block hard_if_notifier;
+extern struct notifier_block batadv_hard_if_notifier;
 
 struct hard_iface*
-hardif_get_by_netdev(const struct net_device *net_dev);
-int hardif_enable_interface(struct hard_iface *hard_iface,
-			    const char *iface_name);
-void hardif_disable_interface(struct hard_iface *hard_iface);
-void hardif_remove_interfaces(void);
-int hardif_min_mtu(struct net_device *soft_iface);
-void update_min_mtu(struct net_device *soft_iface);
-void hardif_free_rcu(struct rcu_head *rcu);
-bool is_wifi_iface(int ifindex);
+batadv_hardif_get_by_netdev(const struct net_device *net_dev);
+int batadv_hardif_enable_interface(struct hard_iface *hard_iface,
+				   const char *iface_name);
+void batadv_hardif_disable_interface(struct hard_iface *hard_iface);
+void batadv_hardif_remove_interfaces(void);
+int batadv_hardif_min_mtu(struct net_device *soft_iface);
+void batadv_update_min_mtu(struct net_device *soft_iface);
+void batadv_hardif_free_rcu(struct rcu_head *rcu);
+bool batadv_is_wifi_iface(int ifindex);
 
-static inline void hardif_free_ref(struct hard_iface *hard_iface)
+static inline void
+batadv_hardif_free_ref(struct hard_iface *hard_iface)
 {
 	if (atomic_dec_and_test(&hard_iface->refcount))
-		call_rcu(&hard_iface->rcu, hardif_free_rcu);
+		call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu);
 }
 
-static inline struct hard_iface *primary_if_get_selected(
-						struct bat_priv *bat_priv)
+static inline struct hard_iface *
+batadv_primary_if_get_selected(struct bat_priv *bat_priv)
 {
 	struct hard_iface *hard_iface;
 
diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c
index 117687b..1fb961c 100644
--- a/net/batman-adv/hash.c
+++ b/net/batman-adv/hash.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
@@ -16,14 +15,13 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
 #include "hash.h"
 
 /* clears the hash */
-static void hash_init(struct hashtable_t *hash)
+static void batadv_hash_init(struct hashtable_t *hash)
 {
 	uint32_t i;
 
@@ -34,7 +32,7 @@ static void hash_init(struct hashtable_t *hash)
 }
 
 /* free only the hashtable and the hash itself. */
-void hash_destroy(struct hashtable_t *hash)
+void batadv_hash_destroy(struct hashtable_t *hash)
 {
 	kfree(hash->list_locks);
 	kfree(hash->table);
@@ -42,7 +40,7 @@ void hash_destroy(struct hashtable_t *hash)
 }
 
 /* allocates and clears the hash */
-struct hashtable_t *hash_new(uint32_t size)
+struct hashtable_t *batadv_hash_new(uint32_t size)
 {
 	struct hashtable_t *hash;
 
@@ -60,7 +58,7 @@ struct hashtable_t *hash_new(uint32_t size)
 		goto free_table;
 
 	hash->size = size;
-	hash_init(hash);
+	batadv_hash_init(hash);
 	return hash;
 
 free_table:
@@ -69,3 +67,12 @@ free_hash:
 	kfree(hash);
 	return NULL;
 }
+
+void batadv_hash_set_lock_class(struct hashtable_t *hash,
+				struct lock_class_key *key)
+{
+	uint32_t i;
+
+	for (i = 0; i < hash->size; i++)
+		lockdep_set_class(&hash->list_locks[i], key);
+}
diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h
index d4bd786..7ec4e5b 100644
--- a/net/batman-adv/hash.h
+++ b/net/batman-adv/hash.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_HASH_H_
@@ -24,15 +22,15 @@
 
 #include <linux/list.h>
 
-/* callback to a compare function.  should
- * compare 2 element datas for their keys,
- * return 0 if same and not 0 if not
- * same */
+/* callback to a compare function.  should compare 2 element datas for their
+ * keys, return 0 if same and not 0 if not same
+ */
 typedef int (*hashdata_compare_cb)(const struct hlist_node *, const void *);
 
 /* the hashfunction, should return an index
  * based on the key in the data of the first
- * argument and the size the second */
+ * argument and the size the second
+ */
 typedef uint32_t (*hashdata_choose_cb)(const void *, uint32_t);
 typedef void (*hashdata_free_cb)(struct hlist_node *, void *);
 
@@ -43,16 +41,21 @@ struct hashtable_t {
 };
 
 /* allocates and clears the hash */
-struct hashtable_t *hash_new(uint32_t size);
+struct hashtable_t *batadv_hash_new(uint32_t size);
+
+/* set class key for all locks */
+void batadv_hash_set_lock_class(struct hashtable_t *hash,
+				struct lock_class_key *key);
 
 /* free only the hashtable and the hash itself. */
-void hash_destroy(struct hashtable_t *hash);
+void batadv_hash_destroy(struct hashtable_t *hash);
 
 /* remove the hash structure. if hashdata_free_cb != NULL, this function will be
  * called to remove the elements inside of the hash.  if you don't remove the
- * elements, memory might be leaked. */
-static inline void hash_delete(struct hashtable_t *hash,
-			       hashdata_free_cb free_cb, void *arg)
+ * elements, memory might be leaked.
+ */
+static inline void batadv_hash_delete(struct hashtable_t *hash,
+				      hashdata_free_cb free_cb, void *arg)
 {
 	struct hlist_head *head;
 	struct hlist_node *node, *node_tmp;
@@ -73,11 +76,10 @@ static inline void hash_delete(struct hashtable_t *hash,
 		spin_unlock_bh(list_lock);
 	}
 
-	hash_destroy(hash);
+	batadv_hash_destroy(hash);
 }
 
-/**
- *	hash_add - adds data to the hashtable
+/*	hash_add - adds data to the hashtable
  *	@hash: storage hash table
  *	@compare: callback to determine if 2 hash elements are identical
  *	@choose: callback calculating the hash index
@@ -87,11 +89,11 @@ static inline void hash_delete(struct hashtable_t *hash,
  *	Returns 0 on success, 1 if the element already is in the hash
  *	and -1 on error.
  */
-
-static inline int hash_add(struct hashtable_t *hash,
-			   hashdata_compare_cb compare,
-			   hashdata_choose_cb choose,
-			   const void *data, struct hlist_node *data_node)
+static inline int batadv_hash_add(struct hashtable_t *hash,
+				  hashdata_compare_cb compare,
+				  hashdata_choose_cb choose,
+				  const void *data,
+				  struct hlist_node *data_node)
 {
 	uint32_t index;
 	int ret = -1;
@@ -106,26 +108,23 @@ static inline int hash_add(struct hashtable_t *hash,
 	head = &hash->table[index];
 	list_lock = &hash->list_locks[index];
 
-	rcu_read_lock();
-	__hlist_for_each_rcu(node, head) {
+	spin_lock_bh(list_lock);
+
+	hlist_for_each(node, head) {
 		if (!compare(node, data))
 			continue;
 
 		ret = 1;
-		goto err_unlock;
+		goto unlock;
 	}
-	rcu_read_unlock();
 
 	/* no duplicate found in list, add new element */
-	spin_lock_bh(list_lock);
 	hlist_add_head_rcu(data_node, head);
-	spin_unlock_bh(list_lock);
 
 	ret = 0;
-	goto out;
 
-err_unlock:
-	rcu_read_unlock();
+unlock:
+	spin_unlock_bh(list_lock);
 out:
 	return ret;
 }
@@ -133,10 +132,11 @@ out:
 /* removes data from hash, if found. returns pointer do data on success, so you
  * can remove the used structure yourself, or NULL on error .  data could be the
  * structure you use with just the key filled, we just need the key for
- * comparing. */
-static inline void *hash_remove(struct hashtable_t *hash,
-				hashdata_compare_cb compare,
-				hashdata_choose_cb choose, void *data)
+ * comparing.
+ */
+static inline void *batadv_hash_remove(struct hashtable_t *hash,
+				       hashdata_compare_cb compare,
+				       hashdata_choose_cb choose, void *data)
 {
 	uint32_t index;
 	struct hlist_node *node;
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c
index 2e98a57..b285c31 100644
--- a/net/batman-adv/icmp_socket.c
+++ b/net/batman-adv/icmp_socket.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -28,18 +26,18 @@
 #include "originator.h"
 #include "hard-interface.h"
 
-static struct socket_client *socket_client_hash[256];
+static struct socket_client *batadv_socket_client_hash[256];
 
-static void bat_socket_add_packet(struct socket_client *socket_client,
-				  struct icmp_packet_rr *icmp_packet,
-				  size_t icmp_len);
+static void batadv_socket_add_packet(struct socket_client *socket_client,
+				     struct icmp_packet_rr *icmp_packet,
+				     size_t icmp_len);
 
-void bat_socket_init(void)
+void batadv_socket_init(void)
 {
-	memset(socket_client_hash, 0, sizeof(socket_client_hash));
+	memset(batadv_socket_client_hash, 0, sizeof(batadv_socket_client_hash));
 }
 
-static int bat_socket_open(struct inode *inode, struct file *file)
+static int batadv_socket_open(struct inode *inode, struct file *file)
 {
 	unsigned int i;
 	struct socket_client *socket_client;
@@ -51,14 +49,14 @@ static int bat_socket_open(struct inode *inode, struct file *file)
 	if (!socket_client)
 		return -ENOMEM;
 
-	for (i = 0; i < ARRAY_SIZE(socket_client_hash); i++) {
-		if (!socket_client_hash[i]) {
-			socket_client_hash[i] = socket_client;
+	for (i = 0; i < ARRAY_SIZE(batadv_socket_client_hash); i++) {
+		if (!batadv_socket_client_hash[i]) {
+			batadv_socket_client_hash[i] = socket_client;
 			break;
 		}
 	}
 
-	if (i == ARRAY_SIZE(socket_client_hash)) {
+	if (i == ARRAY_SIZE(batadv_socket_client_hash)) {
 		pr_err("Error - can't add another packet client: maximum number of clients reached\n");
 		kfree(socket_client);
 		return -EXFULL;
@@ -73,11 +71,11 @@ static int bat_socket_open(struct inode *inode, struct file *file)
 
 	file->private_data = socket_client;
 
-	inc_module_count();
+	batadv_inc_module_count();
 	return 0;
 }
 
-static int bat_socket_release(struct inode *inode, struct file *file)
+static int batadv_socket_release(struct inode *inode, struct file *file)
 {
 	struct socket_client *socket_client = file->private_data;
 	struct socket_packet *socket_packet;
@@ -94,17 +92,17 @@ static int bat_socket_release(struct inode *inode, struct file *file)
 		kfree(socket_packet);
 	}
 
-	socket_client_hash[socket_client->index] = NULL;
+	batadv_socket_client_hash[socket_client->index] = NULL;
 	spin_unlock_bh(&socket_client->lock);
 
 	kfree(socket_client);
-	dec_module_count();
+	batadv_dec_module_count();
 
 	return 0;
 }
 
-static ssize_t bat_socket_read(struct file *file, char __user *buf,
-			       size_t count, loff_t *ppos)
+static ssize_t batadv_socket_read(struct file *file, char __user *buf,
+				  size_t count, loff_t *ppos)
 {
 	struct socket_client *socket_client = file->private_data;
 	struct socket_packet *socket_packet;
@@ -146,8 +144,8 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf,
 	return packet_len;
 }
 
-static ssize_t bat_socket_write(struct file *file, const char __user *buff,
-				size_t len, loff_t *off)
+static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
+				   size_t len, loff_t *off)
 {
 	struct socket_client *socket_client = file->private_data;
 	struct bat_priv *bat_priv = socket_client->bat_priv;
@@ -160,12 +158,12 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
 	size_t packet_len = sizeof(struct icmp_packet);
 
 	if (len < sizeof(struct icmp_packet)) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Error - can't send packet from char device: invalid packet size\n");
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Error - can't send packet from char device: invalid packet size\n");
 		return -EINVAL;
 	}
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 
 	if (!primary_if) {
 		len = -EFAULT;
@@ -190,15 +188,15 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
 	}
 
 	if (icmp_packet->header.packet_type != BAT_ICMP) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n");
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n");
 		len = -EINVAL;
 		goto free_skb;
 	}
 
 	if (icmp_packet->msg_type != ECHO_REQUEST) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n");
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n");
 		len = -EINVAL;
 		goto free_skb;
 	}
@@ -208,18 +206,19 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
 	if (icmp_packet->header.version != COMPAT_VERSION) {
 		icmp_packet->msg_type = PARAMETER_PROBLEM;
 		icmp_packet->header.version = COMPAT_VERSION;
-		bat_socket_add_packet(socket_client, icmp_packet, packet_len);
+		batadv_socket_add_packet(socket_client, icmp_packet,
+					 packet_len);
 		goto free_skb;
 	}
 
 	if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
 		goto dst_unreach;
 
-	orig_node = orig_hash_find(bat_priv, icmp_packet->dst);
+	orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->dst);
 	if (!orig_node)
 		goto dst_unreach;
 
-	neigh_node = orig_node_get_router(orig_node);
+	neigh_node = batadv_orig_node_get_router(orig_node);
 	if (!neigh_node)
 		goto dst_unreach;
 
@@ -236,25 +235,25 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
 		memcpy(icmp_packet->rr,
 		       neigh_node->if_incoming->net_dev->dev_addr, ETH_ALEN);
 
-	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
 	goto out;
 
 dst_unreach:
 	icmp_packet->msg_type = DESTINATION_UNREACHABLE;
-	bat_socket_add_packet(socket_client, icmp_packet, packet_len);
+	batadv_socket_add_packet(socket_client, icmp_packet, packet_len);
 free_skb:
 	kfree_skb(skb);
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	if (neigh_node)
-		neigh_node_free_ref(neigh_node);
+		batadv_neigh_node_free_ref(neigh_node);
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 	return len;
 }
 
-static unsigned int bat_socket_poll(struct file *file, poll_table *wait)
+static unsigned int batadv_socket_poll(struct file *file, poll_table *wait)
 {
 	struct socket_client *socket_client = file->private_data;
 
@@ -266,17 +265,17 @@ static unsigned int bat_socket_poll(struct file *file, poll_table *wait)
 	return 0;
 }
 
-static const struct file_operations fops = {
+static const struct file_operations batadv_fops = {
 	.owner = THIS_MODULE,
-	.open = bat_socket_open,
-	.release = bat_socket_release,
-	.read = bat_socket_read,
-	.write = bat_socket_write,
-	.poll = bat_socket_poll,
+	.open = batadv_socket_open,
+	.release = batadv_socket_release,
+	.read = batadv_socket_read,
+	.write = batadv_socket_write,
+	.poll = batadv_socket_poll,
 	.llseek = no_llseek,
 };
 
-int bat_socket_setup(struct bat_priv *bat_priv)
+int batadv_socket_setup(struct bat_priv *bat_priv)
 {
 	struct dentry *d;
 
@@ -284,19 +283,19 @@ int bat_socket_setup(struct bat_priv *bat_priv)
 		goto err;
 
 	d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR,
-				bat_priv->debug_dir, bat_priv, &fops);
-	if (d)
+				bat_priv->debug_dir, bat_priv, &batadv_fops);
+	if (!d)
 		goto err;
 
 	return 0;
 
 err:
-	return 1;
+	return -ENOMEM;
 }
 
-static void bat_socket_add_packet(struct socket_client *socket_client,
-				  struct icmp_packet_rr *icmp_packet,
-				  size_t icmp_len)
+static void batadv_socket_add_packet(struct socket_client *socket_client,
+				     struct icmp_packet_rr *icmp_packet,
+				     size_t icmp_len)
 {
 	struct socket_packet *socket_packet;
 
@@ -312,8 +311,9 @@ static void bat_socket_add_packet(struct socket_client *socket_client,
 	spin_lock_bh(&socket_client->lock);
 
 	/* while waiting for the lock the socket_client could have been
-	 * deleted */
-	if (!socket_client_hash[icmp_packet->uid]) {
+	 * deleted
+	 */
+	if (!batadv_socket_client_hash[icmp_packet->uid]) {
 		spin_unlock_bh(&socket_client->lock);
 		kfree(socket_packet);
 		return;
@@ -336,11 +336,12 @@ static void bat_socket_add_packet(struct socket_client *socket_client,
 	wake_up(&socket_client->queue_wait);
 }
 
-void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
-			       size_t icmp_len)
+void batadv_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
+				  size_t icmp_len)
 {
-	struct socket_client *hash = socket_client_hash[icmp_packet->uid];
+	struct socket_client *hash;
 
+	hash = batadv_socket_client_hash[icmp_packet->uid];
 	if (hash)
-		bat_socket_add_packet(hash, icmp_packet, icmp_len);
+		batadv_socket_add_packet(hash, icmp_packet, icmp_len);
 }
diff --git a/net/batman-adv/icmp_socket.h b/net/batman-adv/icmp_socket.h
index 380ed4c..a62ab80 100644
--- a/net/batman-adv/icmp_socket.h
+++ b/net/batman-adv/icmp_socket.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_ICMP_SOCKET_H_
@@ -24,9 +22,9 @@
 
 #define ICMP_SOCKET "socket"
 
-void bat_socket_init(void);
-int bat_socket_setup(struct bat_priv *bat_priv);
-void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
-			       size_t icmp_len);
+void batadv_socket_init(void);
+int batadv_socket_setup(struct bat_priv *bat_priv);
+void batadv_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
+				  size_t icmp_len);
 
 #endif /* _NET_BATMAN_ADV_ICMP_SOCKET_H_ */
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 083a299..e456430 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -37,38 +35,40 @@
 
 
 /* List manipulations on hardif_list have to be rtnl_lock()'ed,
- * list traversals just rcu-locked */
-struct list_head hardif_list;
+ * list traversals just rcu-locked
+ */
+struct list_head batadv_hardif_list;
 static int (*recv_packet_handler[256])(struct sk_buff *, struct hard_iface *);
-char bat_routing_algo[20] = "BATMAN IV";
+char batadv_routing_algo[20] = "BATMAN_IV";
 static struct hlist_head bat_algo_list;
 
-unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+unsigned char batadv_broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
-struct workqueue_struct *bat_event_workqueue;
+struct workqueue_struct *batadv_event_workqueue;
 
 static void recv_handler_init(void);
 
 static int __init batman_init(void)
 {
-	INIT_LIST_HEAD(&hardif_list);
+	INIT_LIST_HEAD(&batadv_hardif_list);
 	INIT_HLIST_HEAD(&bat_algo_list);
 
 	recv_handler_init();
 
-	bat_iv_init();
+	batadv_iv_init();
 
 	/* the name should not be longer than 10 chars - see
-	 * http://lwn.net/Articles/23634/ */
-	bat_event_workqueue = create_singlethread_workqueue("bat_events");
+	 * http://lwn.net/Articles/23634/
+	 */
+	batadv_event_workqueue = create_singlethread_workqueue("bat_events");
 
-	if (!bat_event_workqueue)
+	if (!batadv_event_workqueue)
 		return -ENOMEM;
 
-	bat_socket_init();
-	debugfs_init();
+	batadv_socket_init();
+	batadv_debugfs_init();
 
-	register_netdevice_notifier(&hard_if_notifier);
+	register_netdevice_notifier(&batadv_hard_if_notifier);
 
 	pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n",
 		SOURCE_VERSION, COMPAT_VERSION);
@@ -78,20 +78,21 @@ static int __init batman_init(void)
 
 static void __exit batman_exit(void)
 {
-	debugfs_destroy();
-	unregister_netdevice_notifier(&hard_if_notifier);
-	hardif_remove_interfaces();
+	batadv_debugfs_destroy();
+	unregister_netdevice_notifier(&batadv_hard_if_notifier);
+	batadv_hardif_remove_interfaces();
 
-	flush_workqueue(bat_event_workqueue);
-	destroy_workqueue(bat_event_workqueue);
-	bat_event_workqueue = NULL;
+	flush_workqueue(batadv_event_workqueue);
+	destroy_workqueue(batadv_event_workqueue);
+	batadv_event_workqueue = NULL;
 
 	rcu_barrier();
 }
 
-int mesh_init(struct net_device *soft_iface)
+int batadv_mesh_init(struct net_device *soft_iface)
 {
 	struct bat_priv *bat_priv = netdev_priv(soft_iface);
+	int ret;
 
 	spin_lock_init(&bat_priv->forw_bat_list_lock);
 	spin_lock_init(&bat_priv->forw_bcast_list_lock);
@@ -110,72 +111,76 @@ int mesh_init(struct net_device *soft_iface)
 	INIT_LIST_HEAD(&bat_priv->tt_req_list);
 	INIT_LIST_HEAD(&bat_priv->tt_roam_list);
 
-	if (originator_init(bat_priv) < 1)
+	ret = batadv_originator_init(bat_priv);
+	if (ret < 0)
 		goto err;
 
-	if (tt_init(bat_priv) < 1)
+	ret = batadv_tt_init(bat_priv);
+	if (ret < 0)
 		goto err;
 
-	tt_local_add(soft_iface, soft_iface->dev_addr, NULL_IFINDEX);
+	batadv_tt_local_add(soft_iface, soft_iface->dev_addr, NULL_IFINDEX);
 
-	if (vis_init(bat_priv) < 1)
+	ret = batadv_vis_init(bat_priv);
+	if (ret < 0)
 		goto err;
 
-	if (bla_init(bat_priv) < 1)
+	ret = batadv_bla_init(bat_priv);
+	if (ret < 0)
 		goto err;
 
 	atomic_set(&bat_priv->gw_reselect, 0);
 	atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
-	goto end;
-
-err:
-	mesh_free(soft_iface);
-	return -1;
 
-end:
 	return 0;
+
+err:
+	batadv_mesh_free(soft_iface);
+	return ret;
 }
 
-void mesh_free(struct net_device *soft_iface)
+void batadv_mesh_free(struct net_device *soft_iface)
 {
 	struct bat_priv *bat_priv = netdev_priv(soft_iface);
 
 	atomic_set(&bat_priv->mesh_state, MESH_DEACTIVATING);
 
-	purge_outstanding_packets(bat_priv, NULL);
+	batadv_purge_outstanding_packets(bat_priv, NULL);
 
-	vis_quit(bat_priv);
+	batadv_vis_quit(bat_priv);
 
-	gw_node_purge(bat_priv);
-	originator_free(bat_priv);
+	batadv_gw_node_purge(bat_priv);
+	batadv_originator_free(bat_priv);
 
-	tt_free(bat_priv);
+	batadv_tt_free(bat_priv);
 
-	bla_free(bat_priv);
+	batadv_bla_free(bat_priv);
+
+	free_percpu(bat_priv->bat_counters);
 
 	atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
 }
 
-void inc_module_count(void)
+void batadv_inc_module_count(void)
 {
 	try_module_get(THIS_MODULE);
 }
 
-void dec_module_count(void)
+void batadv_dec_module_count(void)
 {
 	module_put(THIS_MODULE);
 }
 
-int is_my_mac(const uint8_t *addr)
+int batadv_is_my_mac(const uint8_t *addr)
 {
 	const struct hard_iface *hard_iface;
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 		if (hard_iface->if_status != IF_ACTIVE)
 			continue;
 
-		if (compare_eth(hard_iface->net_dev->dev_addr, addr)) {
+		if (batadv_compare_eth(hard_iface->net_dev->dev_addr, addr)) {
 			rcu_read_unlock();
 			return 1;
 		}
@@ -193,8 +198,9 @@ static int recv_unhandled_packet(struct sk_buff *skb,
 /* incoming packets with the batman ethertype received on any active hard
  * interface
  */
-int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
-		    struct packet_type *ptype, struct net_device *orig_dev)
+int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
+			   struct packet_type *ptype,
+			   struct net_device *orig_dev)
 {
 	struct bat_priv *bat_priv;
 	struct batman_ogm_packet *batman_ogm_packet;
@@ -232,9 +238,9 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
 	batman_ogm_packet = (struct batman_ogm_packet *)skb->data;
 
 	if (batman_ogm_packet->header.version != COMPAT_VERSION) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Drop packet: incompatible batman version (%i)\n",
-			batman_ogm_packet->header.version);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Drop packet: incompatible batman version (%i)\n",
+			   batman_ogm_packet->header.version);
 		goto err_free;
 	}
 
@@ -267,24 +273,24 @@ static void recv_handler_init(void)
 		recv_packet_handler[i] = recv_unhandled_packet;
 
 	/* batman icmp packet */
-	recv_packet_handler[BAT_ICMP] = recv_icmp_packet;
+	recv_packet_handler[BAT_ICMP] = batadv_recv_icmp_packet;
 	/* unicast packet */
-	recv_packet_handler[BAT_UNICAST] = recv_unicast_packet;
+	recv_packet_handler[BAT_UNICAST] = batadv_recv_unicast_packet;
 	/* fragmented unicast packet */
-	recv_packet_handler[BAT_UNICAST_FRAG] = recv_ucast_frag_packet;
+	recv_packet_handler[BAT_UNICAST_FRAG] = batadv_recv_ucast_frag_packet;
 	/* broadcast packet */
-	recv_packet_handler[BAT_BCAST] = recv_bcast_packet;
+	recv_packet_handler[BAT_BCAST] = batadv_recv_bcast_packet;
 	/* vis packet */
-	recv_packet_handler[BAT_VIS] = recv_vis_packet;
+	recv_packet_handler[BAT_VIS] = batadv_recv_vis_packet;
 	/* Translation table query (request or response) */
-	recv_packet_handler[BAT_TT_QUERY] = recv_tt_query;
+	recv_packet_handler[BAT_TT_QUERY] = batadv_recv_tt_query;
 	/* Roaming advertisement */
-	recv_packet_handler[BAT_ROAM_ADV] = recv_roam_adv;
+	recv_packet_handler[BAT_ROAM_ADV] = batadv_recv_roam_adv;
 }
 
-int recv_handler_register(uint8_t packet_type,
-			  int (*recv_handler)(struct sk_buff *,
-					      struct hard_iface *))
+int batadv_recv_handler_register(uint8_t packet_type,
+				 int (*recv_handler)(struct sk_buff *,
+						     struct hard_iface *))
 {
 	if (recv_packet_handler[packet_type] != &recv_unhandled_packet)
 		return -EBUSY;
@@ -293,7 +299,7 @@ int recv_handler_register(uint8_t packet_type,
 	return 0;
 }
 
-void recv_handler_unregister(uint8_t packet_type)
+void batadv_recv_handler_unregister(uint8_t packet_type)
 {
 	recv_packet_handler[packet_type] = recv_unhandled_packet;
 }
@@ -314,15 +320,16 @@ static struct bat_algo_ops *bat_algo_get(char *name)
 	return bat_algo_ops;
 }
 
-int bat_algo_register(struct bat_algo_ops *bat_algo_ops)
+int batadv_algo_register(struct bat_algo_ops *bat_algo_ops)
 {
 	struct bat_algo_ops *bat_algo_ops_tmp;
-	int ret = -1;
+	int ret;
 
 	bat_algo_ops_tmp = bat_algo_get(bat_algo_ops->name);
 	if (bat_algo_ops_tmp) {
 		pr_info("Trying to register already registered routing algorithm: %s\n",
 			bat_algo_ops->name);
+		ret = -EEXIST;
 		goto out;
 	}
 
@@ -335,6 +342,7 @@ int bat_algo_register(struct bat_algo_ops *bat_algo_ops)
 	    !bat_algo_ops->bat_ogm_emit) {
 		pr_info("Routing algo '%s' does not implement required ops\n",
 			bat_algo_ops->name);
+		ret = -EINVAL;
 		goto out;
 	}
 
@@ -346,10 +354,10 @@ out:
 	return ret;
 }
 
-int bat_algo_select(struct bat_priv *bat_priv, char *name)
+int batadv_algo_select(struct bat_priv *bat_priv, char *name)
 {
 	struct bat_algo_ops *bat_algo_ops;
-	int ret = -1;
+	int ret = -EINVAL;
 
 	bat_algo_ops = bat_algo_get(name);
 	if (!bat_algo_ops)
@@ -362,7 +370,7 @@ out:
 	return ret;
 }
 
-int bat_algo_seq_print_text(struct seq_file *seq, void *offset)
+int batadv_algo_seq_print_text(struct seq_file *seq, void *offset)
 {
 	struct bat_algo_ops *bat_algo_ops;
 	struct hlist_node *node;
@@ -379,14 +387,19 @@ int bat_algo_seq_print_text(struct seq_file *seq, void *offset)
 static int param_set_ra(const char *val, const struct kernel_param *kp)
 {
 	struct bat_algo_ops *bat_algo_ops;
+	char *algo_name = (char *)val;
+	size_t name_len = strlen(algo_name);
+
+	if (algo_name[name_len - 1] == '\n')
+		algo_name[name_len - 1] = '\0';
 
-	bat_algo_ops = bat_algo_get((char *)val);
+	bat_algo_ops = bat_algo_get(algo_name);
 	if (!bat_algo_ops) {
-		pr_err("Routing algorithm '%s' is not supported\n", val);
+		pr_err("Routing algorithm '%s' is not supported\n", algo_name);
 		return -EINVAL;
 	}
 
-	return param_set_copystring(val, kp);
+	return param_set_copystring(algo_name, kp);
 }
 
 static const struct kernel_param_ops param_ops_ra = {
@@ -395,8 +408,8 @@ static const struct kernel_param_ops param_ops_ra = {
 };
 
 static struct kparam_string __param_string_ra = {
-	.maxlen = sizeof(bat_routing_algo),
-	.string = bat_routing_algo,
+	.maxlen = sizeof(batadv_routing_algo),
+	.string = batadv_routing_algo,
 };
 
 module_param_cb(routing_algo, &param_ops_ra, &__param_string_ra, 0644);
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index f4a3ec0..2824264 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_MAIN_H_
@@ -28,7 +26,7 @@
 #define DRIVER_DEVICE "batman-adv"
 
 #ifndef SOURCE_VERSION
-#define SOURCE_VERSION "2012.2.0"
+#define SOURCE_VERSION "2012.3.0"
 #endif
 
 /* B.A.T.M.A.N. parameters */
@@ -36,19 +34,21 @@
 #define TQ_MAX_VALUE 255
 #define JITTER 20
 
- /* Time To Live of broadcast messages */
+/* Time To Live of broadcast messages */
 #define TTL 50
 
 /* purge originators after time in seconds if no valid packet comes in
- * -> TODO: check influence on TQ_LOCAL_WINDOW_SIZE */
+ * -> TODO: check influence on TQ_LOCAL_WINDOW_SIZE
+ */
 #define PURGE_TIMEOUT 200000 /* 200 seconds */
 #define TT_LOCAL_TIMEOUT 3600000 /* in miliseconds */
 #define TT_CLIENT_ROAM_TIMEOUT 600000 /* in miliseconds */
 /* sliding packet range of received originator messages in sequence numbers
- * (should be a multiple of our word size) */
+ * (should be a multiple of our word size)
+ */
 #define TQ_LOCAL_WINDOW_SIZE 64
-#define TT_REQUEST_TIMEOUT 3000 /* miliseconds we have to keep
-				 * pending tt_req */
+/* miliseconds we have to keep pending tt_req */
+#define TT_REQUEST_TIMEOUT 3000
 
 #define TQ_GLOBAL_WINDOW_SIZE 5
 #define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
@@ -57,8 +57,10 @@
 
 #define TT_OGM_APPEND_MAX 3 /* number of OGMs sent with the last tt diff */
 
-#define ROAMING_MAX_TIME 20000 /* Time in which a client can roam at most
-				* ROAMING_MAX_COUNT times in miliseconds*/
+/* Time in which a client can roam at most ROAMING_MAX_COUNT times in
+ * miliseconds
+ */
+#define ROAMING_MAX_TIME 20000
 #define ROAMING_MAX_COUNT 5
 
 #define NO_FLAGS 0
@@ -72,11 +74,13 @@
 #define VIS_INTERVAL 5000	/* 5 seconds */
 
 /* how much worse secondary interfaces may be to be considered as bonding
- * candidates */
+ * candidates
+ */
 #define BONDING_TQ_THRESHOLD	50
 
 /* should not be bigger than 512 bytes or change the size of
- * forw_packet->direct_link_flags */
+ * forw_packet->direct_link_flags
+ */
 #define MAX_AGGREGATION_BYTES 512
 #define MAX_AGGREGATION_MS 100
 
@@ -138,47 +142,50 @@ enum dbg_level {
 #include <linux/kthread.h>	/* kernel threads */
 #include <linux/pkt_sched.h>	/* schedule types */
 #include <linux/workqueue.h>	/* workqueue */
+#include <linux/percpu.h>
 #include <linux/slab.h>
 #include <net/sock.h>		/* struct sock */
 #include <linux/jiffies.h>
 #include <linux/seq_file.h>
 #include "types.h"
 
-extern char bat_routing_algo[];
-extern struct list_head hardif_list;
-
-extern unsigned char broadcast_addr[];
-extern struct workqueue_struct *bat_event_workqueue;
-
-int mesh_init(struct net_device *soft_iface);
-void mesh_free(struct net_device *soft_iface);
-void inc_module_count(void);
-void dec_module_count(void);
-int is_my_mac(const uint8_t *addr);
-int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
-		    struct packet_type *ptype, struct net_device *orig_dev);
-int recv_handler_register(uint8_t packet_type,
-			  int (*recv_handler)(struct sk_buff *,
-					      struct hard_iface *));
-void recv_handler_unregister(uint8_t packet_type);
-int bat_algo_register(struct bat_algo_ops *bat_algo_ops);
-int bat_algo_select(struct bat_priv *bat_priv, char *name);
-int bat_algo_seq_print_text(struct seq_file *seq, void *offset);
+extern char batadv_routing_algo[];
+extern struct list_head batadv_hardif_list;
+
+extern unsigned char batadv_broadcast_addr[];
+extern struct workqueue_struct *batadv_event_workqueue;
+
+int batadv_mesh_init(struct net_device *soft_iface);
+void batadv_mesh_free(struct net_device *soft_iface);
+void batadv_inc_module_count(void);
+void batadv_dec_module_count(void);
+int batadv_is_my_mac(const uint8_t *addr);
+int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
+			   struct packet_type *ptype,
+			   struct net_device *orig_dev);
+int batadv_recv_handler_register(uint8_t packet_type,
+				 int (*recv_handler)(struct sk_buff *,
+						     struct hard_iface *));
+void batadv_recv_handler_unregister(uint8_t packet_type);
+int batadv_algo_register(struct bat_algo_ops *bat_algo_ops);
+int batadv_algo_select(struct bat_priv *bat_priv, char *name);
+int batadv_algo_seq_print_text(struct seq_file *seq, void *offset);
 
 #ifdef CONFIG_BATMAN_ADV_DEBUG
-int debug_log(struct bat_priv *bat_priv, const char *fmt, ...) __printf(2, 3);
+int batadv_debug_log(struct bat_priv *bat_priv, const char *fmt, ...)
+__printf(2, 3);
 
-#define bat_dbg(type, bat_priv, fmt, arg...)			\
+#define batadv_dbg(type, bat_priv, fmt, arg...)			\
 	do {							\
 		if (atomic_read(&bat_priv->log_level) & type)	\
-			debug_log(bat_priv, fmt, ## arg);	\
+			batadv_debug_log(bat_priv, fmt, ## arg);\
 	}							\
 	while (0)
 #else /* !CONFIG_BATMAN_ADV_DEBUG */
 __printf(3, 4)
-static inline void bat_dbg(int type __always_unused,
-			   struct bat_priv *bat_priv __always_unused,
-			   const char *fmt __always_unused, ...)
+static inline void batadv_dbg(int type __always_unused,
+			      struct bat_priv *bat_priv __always_unused,
+			      const char *fmt __always_unused, ...)
 {
 }
 #endif
@@ -187,36 +194,34 @@ static inline void bat_dbg(int type __always_unused,
 	do {								\
 		struct net_device *_netdev = (net_dev);                 \
 		struct bat_priv *_batpriv = netdev_priv(_netdev);       \
-		bat_dbg(DBG_ALL, _batpriv, fmt, ## arg);		\
+		batadv_dbg(DBG_ALL, _batpriv, fmt, ## arg);		\
 		pr_info("%s: " fmt, _netdev->name, ## arg);		\
 	} while (0)
 #define bat_err(net_dev, fmt, arg...)					\
 	do {								\
 		struct net_device *_netdev = (net_dev);                 \
 		struct bat_priv *_batpriv = netdev_priv(_netdev);       \
-		bat_dbg(DBG_ALL, _batpriv, fmt, ## arg);		\
+		batadv_dbg(DBG_ALL, _batpriv, fmt, ## arg);		\
 		pr_err("%s: " fmt, _netdev->name, ## arg);		\
 	} while (0)
 
-/**
- * returns 1 if they are the same ethernet addr
+/* returns 1 if they are the same ethernet addr
  *
  * note: can't use compare_ether_addr() as it requires aligned memory
  */
-
-static inline int compare_eth(const void *data1, const void *data2)
+static inline int batadv_compare_eth(const void *data1, const void *data2)
 {
 	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
 }
 
-/**
- * has_timed_out - compares current time (jiffies) and timestamp + timeout
+/* has_timed_out - compares current time (jiffies) and timestamp + timeout
  * @timestamp:		base value to compare with (in jiffies)
  * @timeout:		added to base value before comparing (in milliseconds)
  *
  * Returns true if current time is after timestamp + timeout
  */
-static inline bool has_timed_out(unsigned long timestamp, unsigned int timeout)
+static inline bool batadv_has_timed_out(unsigned long timestamp,
+					unsigned int timeout)
 {
 	return time_is_before_jiffies(timestamp + msecs_to_jiffies(timeout));
 }
@@ -234,7 +239,8 @@ static inline bool has_timed_out(unsigned long timestamp, unsigned int timeout)
  *  - when adding nothing - it is neither a predecessor nor a successor
  *  - before adding more than 127 to the starting value - it is a predecessor,
  *  - when adding 128 - it is neither a predecessor nor a successor,
- *  - after adding more than 127 to the starting value - it is a successor */
+ *  - after adding more than 127 to the starting value - it is a successor
+ */
 #define seq_before(x, y) ({typeof(x) _d1 = (x); \
 			  typeof(y) _d2 = (y); \
 			  typeof(x) _dummy = (_d1 - _d2); \
@@ -242,4 +248,30 @@ static inline bool has_timed_out(unsigned long timestamp, unsigned int timeout)
 			  _dummy > smallest_signed_int(_dummy); })
 #define seq_after(x, y) seq_before(y, x)
 
+/* Stop preemption on local cpu while incrementing the counter */
+static inline void batadv_add_counter(struct bat_priv *bat_priv, size_t idx,
+				      size_t count)
+{
+	int cpu = get_cpu();
+	per_cpu_ptr(bat_priv->bat_counters, cpu)[idx] += count;
+	put_cpu();
+}
+
+#define batadv_inc_counter(b, i) batadv_add_counter(b, i, 1)
+
+/* Sum and return the cpu-local counters for index 'idx' */
+static inline uint64_t batadv_sum_counter(struct bat_priv *bat_priv, size_t idx)
+{
+	uint64_t *counters;
+	int cpu;
+	int sum = 0;
+
+	for_each_possible_cpu(cpu) {
+		counters = per_cpu_ptr(bat_priv->bat_counters, cpu);
+		sum += counters[idx];
+	}
+
+	return sum;
+}
+
 #endif /* _NET_BATMAN_ADV_MAIN_H_ */
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 41147942..bf9ec39a 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -30,48 +28,48 @@
 #include "soft-interface.h"
 #include "bridge_loop_avoidance.h"
 
-static void purge_orig(struct work_struct *work);
+static void batadv_purge_orig(struct work_struct *work);
 
-static void start_purge_timer(struct bat_priv *bat_priv)
+static void batadv_start_purge_timer(struct bat_priv *bat_priv)
 {
-	INIT_DELAYED_WORK(&bat_priv->orig_work, purge_orig);
-	queue_delayed_work(bat_event_workqueue,
+	INIT_DELAYED_WORK(&bat_priv->orig_work, batadv_purge_orig);
+	queue_delayed_work(batadv_event_workqueue,
 			   &bat_priv->orig_work, msecs_to_jiffies(1000));
 }
 
 /* returns 1 if they are the same originator */
-static int compare_orig(const struct hlist_node *node, const void *data2)
+static int batadv_compare_orig(const struct hlist_node *node, const void *data2)
 {
 	const void *data1 = container_of(node, struct orig_node, hash_entry);
 
 	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
 }
 
-int originator_init(struct bat_priv *bat_priv)
+int batadv_originator_init(struct bat_priv *bat_priv)
 {
 	if (bat_priv->orig_hash)
-		return 1;
+		return 0;
 
-	bat_priv->orig_hash = hash_new(1024);
+	bat_priv->orig_hash = batadv_hash_new(1024);
 
 	if (!bat_priv->orig_hash)
 		goto err;
 
-	start_purge_timer(bat_priv);
-	return 1;
+	batadv_start_purge_timer(bat_priv);
+	return 0;
 
 err:
-	return 0;
+	return -ENOMEM;
 }
 
-void neigh_node_free_ref(struct neigh_node *neigh_node)
+void batadv_neigh_node_free_ref(struct neigh_node *neigh_node)
 {
 	if (atomic_dec_and_test(&neigh_node->refcount))
 		kfree_rcu(neigh_node, rcu);
 }
 
 /* increases the refcounter of a found router */
-struct neigh_node *orig_node_get_router(struct orig_node *orig_node)
+struct neigh_node *batadv_orig_node_get_router(struct orig_node *orig_node)
 {
 	struct neigh_node *router;
 
@@ -104,15 +102,15 @@ struct neigh_node *batadv_neigh_node_new(struct hard_iface *hard_iface,
 	/* extra reference for return */
 	atomic_set(&neigh_node->refcount, 2);
 
-	bat_dbg(DBG_BATMAN, bat_priv,
-		"Creating new neighbor %pM, initial seqno %d\n",
-		neigh_addr, seqno);
+	batadv_dbg(DBG_BATMAN, bat_priv,
+		   "Creating new neighbor %pM, initial seqno %d\n",
+		   neigh_addr, seqno);
 
 out:
 	return neigh_node;
 }
 
-static void orig_node_free_rcu(struct rcu_head *rcu)
+static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
 {
 	struct hlist_node *node, *node_tmp;
 	struct neigh_node *neigh_node, *tmp_neigh_node;
@@ -126,21 +124,21 @@ static void orig_node_free_rcu(struct rcu_head *rcu)
 	list_for_each_entry_safe(neigh_node, tmp_neigh_node,
 				 &orig_node->bond_list, bonding_list) {
 		list_del_rcu(&neigh_node->bonding_list);
-		neigh_node_free_ref(neigh_node);
+		batadv_neigh_node_free_ref(neigh_node);
 	}
 
 	/* for all neighbors towards this originator ... */
 	hlist_for_each_entry_safe(neigh_node, node, node_tmp,
 				  &orig_node->neigh_list, list) {
 		hlist_del_rcu(&neigh_node->list);
-		neigh_node_free_ref(neigh_node);
+		batadv_neigh_node_free_ref(neigh_node);
 	}
 
 	spin_unlock_bh(&orig_node->neigh_list_lock);
 
-	frag_list_free(&orig_node->frag_list);
-	tt_global_del_orig(orig_node->bat_priv, orig_node,
-			   "originator timed out");
+	batadv_frag_list_free(&orig_node->frag_list);
+	batadv_tt_global_del_orig(orig_node->bat_priv, orig_node,
+				  "originator timed out");
 
 	kfree(orig_node->tt_buff);
 	kfree(orig_node->bcast_own);
@@ -148,13 +146,13 @@ static void orig_node_free_rcu(struct rcu_head *rcu)
 	kfree(orig_node);
 }
 
-void orig_node_free_ref(struct orig_node *orig_node)
+void batadv_orig_node_free_ref(struct orig_node *orig_node)
 {
 	if (atomic_dec_and_test(&orig_node->refcount))
-		call_rcu(&orig_node->rcu, orig_node_free_rcu);
+		call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu);
 }
 
-void originator_free(struct bat_priv *bat_priv)
+void batadv_originator_free(struct bat_priv *bat_priv)
 {
 	struct hashtable_t *hash = bat_priv->orig_hash;
 	struct hlist_node *node, *node_tmp;
@@ -179,28 +177,30 @@ void originator_free(struct bat_priv *bat_priv)
 					  head, hash_entry) {
 
 			hlist_del_rcu(node);
-			orig_node_free_ref(orig_node);
+			batadv_orig_node_free_ref(orig_node);
 		}
 		spin_unlock_bh(list_lock);
 	}
 
-	hash_destroy(hash);
+	batadv_hash_destroy(hash);
 }
 
 /* this function finds or creates an originator entry for the given
- * address if it does not exits */
-struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
+ * address if it does not exits
+ */
+struct orig_node *batadv_get_orig_node(struct bat_priv *bat_priv,
+				       const uint8_t *addr)
 {
 	struct orig_node *orig_node;
 	int size;
 	int hash_added;
 
-	orig_node = orig_hash_find(bat_priv, addr);
+	orig_node = batadv_orig_hash_find(bat_priv, addr);
 	if (orig_node)
 		return orig_node;
 
-	bat_dbg(DBG_BATMAN, bat_priv,
-		"Creating new originator: %pM\n", addr);
+	batadv_dbg(DBG_BATMAN, bat_priv, "Creating new originator: %pM\n",
+		   addr);
 
 	orig_node = kzalloc(sizeof(*orig_node), GFP_ATOMIC);
 	if (!orig_node)
@@ -248,8 +248,9 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
 	if (!orig_node->bcast_own_sum)
 		goto free_bcast_own;
 
-	hash_added = hash_add(bat_priv->orig_hash, compare_orig,
-			      choose_orig, orig_node, &orig_node->hash_entry);
+	hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
+				     batadv_choose_orig, orig_node,
+				     &orig_node->hash_entry);
 	if (hash_added != 0)
 		goto free_bcast_own_sum;
 
@@ -263,14 +264,15 @@ free_orig_node:
 	return NULL;
 }
 
-static bool purge_orig_neighbors(struct bat_priv *bat_priv,
-				 struct orig_node *orig_node,
-				 struct neigh_node **best_neigh_node)
+static bool batadv_purge_orig_neighbors(struct bat_priv *bat_priv,
+					struct orig_node *orig_node,
+					struct neigh_node **best_neigh_node)
 {
 	struct hlist_node *node, *node_tmp;
 	struct neigh_node *neigh_node;
 	bool neigh_purged = false;
 	unsigned long last_seen;
+	struct hard_iface *if_incoming;
 
 	*best_neigh_node = NULL;
 
@@ -280,34 +282,32 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
 	hlist_for_each_entry_safe(neigh_node, node, node_tmp,
 				  &orig_node->neigh_list, list) {
 
-		if ((has_timed_out(neigh_node->last_seen, PURGE_TIMEOUT)) ||
-		    (neigh_node->if_incoming->if_status == IF_INACTIVE) ||
-		    (neigh_node->if_incoming->if_status == IF_NOT_IN_USE) ||
-		    (neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) {
-
-			last_seen = neigh_node->last_seen;
-
-			if ((neigh_node->if_incoming->if_status ==
-								IF_INACTIVE) ||
-			    (neigh_node->if_incoming->if_status ==
-							IF_NOT_IN_USE) ||
-			    (neigh_node->if_incoming->if_status ==
-							IF_TO_BE_REMOVED))
-				bat_dbg(DBG_BATMAN, bat_priv,
-					"neighbor purge: originator %pM, neighbor: %pM, iface: %s\n",
-					orig_node->orig, neigh_node->addr,
-					neigh_node->if_incoming->net_dev->name);
+		last_seen = neigh_node->last_seen;
+		if_incoming = neigh_node->if_incoming;
+
+		if ((batadv_has_timed_out(last_seen, PURGE_TIMEOUT)) ||
+		    (if_incoming->if_status == IF_INACTIVE) ||
+		    (if_incoming->if_status == IF_NOT_IN_USE) ||
+		    (if_incoming->if_status == IF_TO_BE_REMOVED)) {
+
+			if ((if_incoming->if_status == IF_INACTIVE) ||
+			    (if_incoming->if_status == IF_NOT_IN_USE) ||
+			    (if_incoming->if_status == IF_TO_BE_REMOVED))
+				batadv_dbg(DBG_BATMAN, bat_priv,
+					   "neighbor purge: originator %pM, neighbor: %pM, iface: %s\n",
+					   orig_node->orig, neigh_node->addr,
+					   if_incoming->net_dev->name);
 			else
-				bat_dbg(DBG_BATMAN, bat_priv,
-					"neighbor timeout: originator %pM, neighbor: %pM, last_seen: %u\n",
-					orig_node->orig, neigh_node->addr,
-					jiffies_to_msecs(last_seen));
+				batadv_dbg(DBG_BATMAN, bat_priv,
+					   "neighbor timeout: originator %pM, neighbor: %pM, last_seen: %u\n",
+					   orig_node->orig, neigh_node->addr,
+					   jiffies_to_msecs(last_seen));
 
 			neigh_purged = true;
 
 			hlist_del_rcu(&neigh_node->list);
-			bonding_candidate_del(orig_node, neigh_node);
-			neigh_node_free_ref(neigh_node);
+			batadv_bonding_candidate_del(orig_node, neigh_node);
+			batadv_neigh_node_free_ref(neigh_node);
 		} else {
 			if ((!*best_neigh_node) ||
 			    (neigh_node->tq_avg > (*best_neigh_node)->tq_avg))
@@ -319,27 +319,28 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
 	return neigh_purged;
 }
 
-static bool purge_orig_node(struct bat_priv *bat_priv,
-			    struct orig_node *orig_node)
+static bool batadv_purge_orig_node(struct bat_priv *bat_priv,
+				   struct orig_node *orig_node)
 {
 	struct neigh_node *best_neigh_node;
 
-	if (has_timed_out(orig_node->last_seen, 2 * PURGE_TIMEOUT)) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Originator timeout: originator %pM, last_seen %u\n",
-			orig_node->orig,
-			jiffies_to_msecs(orig_node->last_seen));
+	if (batadv_has_timed_out(orig_node->last_seen, 2 * PURGE_TIMEOUT)) {
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "Originator timeout: originator %pM, last_seen %u\n",
+			   orig_node->orig,
+			   jiffies_to_msecs(orig_node->last_seen));
 		return true;
 	} else {
-		if (purge_orig_neighbors(bat_priv, orig_node,
-					 &best_neigh_node))
-			update_route(bat_priv, orig_node, best_neigh_node);
+		if (batadv_purge_orig_neighbors(bat_priv, orig_node,
+						&best_neigh_node))
+			batadv_update_route(bat_priv, orig_node,
+					    best_neigh_node);
 	}
 
 	return false;
 }
 
-static void _purge_orig(struct bat_priv *bat_priv)
+static void _batadv_purge_orig(struct bat_priv *bat_priv)
 {
 	struct hashtable_t *hash = bat_priv->orig_hash;
 	struct hlist_node *node, *node_tmp;
@@ -359,42 +360,43 @@ static void _purge_orig(struct bat_priv *bat_priv)
 		spin_lock_bh(list_lock);
 		hlist_for_each_entry_safe(orig_node, node, node_tmp,
 					  head, hash_entry) {
-			if (purge_orig_node(bat_priv, orig_node)) {
+			if (batadv_purge_orig_node(bat_priv, orig_node)) {
 				if (orig_node->gw_flags)
-					gw_node_delete(bat_priv, orig_node);
+					batadv_gw_node_delete(bat_priv,
+							      orig_node);
 				hlist_del_rcu(node);
-				orig_node_free_ref(orig_node);
+				batadv_orig_node_free_ref(orig_node);
 				continue;
 			}
 
-			if (has_timed_out(orig_node->last_frag_packet,
-					  FRAG_TIMEOUT))
-				frag_list_free(&orig_node->frag_list);
+			if (batadv_has_timed_out(orig_node->last_frag_packet,
+						 FRAG_TIMEOUT))
+				batadv_frag_list_free(&orig_node->frag_list);
 		}
 		spin_unlock_bh(list_lock);
 	}
 
-	gw_node_purge(bat_priv);
-	gw_election(bat_priv);
+	batadv_gw_node_purge(bat_priv);
+	batadv_gw_election(bat_priv);
 }
 
-static void purge_orig(struct work_struct *work)
+static void batadv_purge_orig(struct work_struct *work)
 {
 	struct delayed_work *delayed_work =
 		container_of(work, struct delayed_work, work);
 	struct bat_priv *bat_priv =
 		container_of(delayed_work, struct bat_priv, orig_work);
 
-	_purge_orig(bat_priv);
-	start_purge_timer(bat_priv);
+	_batadv_purge_orig(bat_priv);
+	batadv_start_purge_timer(bat_priv);
 }
 
-void purge_orig_ref(struct bat_priv *bat_priv)
+void batadv_purge_orig_ref(struct bat_priv *bat_priv)
 {
-	_purge_orig(bat_priv);
+	_batadv_purge_orig(bat_priv);
 }
 
-int orig_seq_print_text(struct seq_file *seq, void *offset)
+int batadv_orig_seq_print_text(struct seq_file *seq, void *offset)
 {
 	struct net_device *net_dev = (struct net_device *)seq->private;
 	struct bat_priv *bat_priv = netdev_priv(net_dev);
@@ -410,7 +412,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
 	uint32_t i;
 	int ret = 0;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 
 	if (!primary_if) {
 		ret = seq_printf(seq,
@@ -438,7 +440,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
 
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
-			neigh_node = orig_node_get_router(orig_node);
+			neigh_node = batadv_orig_node_get_router(orig_node);
 			if (!neigh_node)
 				continue;
 
@@ -467,7 +469,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
 			batman_count++;
 
 next:
-			neigh_node_free_ref(neigh_node);
+			batadv_neigh_node_free_ref(neigh_node);
 		}
 		rcu_read_unlock();
 	}
@@ -477,18 +479,18 @@ next:
 
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	return ret;
 }
 
-static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
+static int batadv_orig_node_add_if(struct orig_node *orig_node, int max_if_num)
 {
 	void *data_ptr;
 
 	data_ptr = kmalloc(max_if_num * sizeof(unsigned long) * NUM_WORDS,
 			   GFP_ATOMIC);
 	if (!data_ptr)
-		return -1;
+		return -ENOMEM;
 
 	memcpy(data_ptr, orig_node->bcast_own,
 	       (max_if_num - 1) * sizeof(unsigned long) * NUM_WORDS);
@@ -497,7 +499,7 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
 
 	data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
 	if (!data_ptr)
-		return -1;
+		return -ENOMEM;
 
 	memcpy(data_ptr, orig_node->bcast_own_sum,
 	       (max_if_num - 1) * sizeof(uint8_t));
@@ -507,7 +509,7 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
 	return 0;
 }
 
-int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num)
+int batadv_orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num)
 {
 	struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
 	struct hashtable_t *hash = bat_priv->orig_hash;
@@ -518,17 +520,18 @@ int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num)
 	int ret;
 
 	/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
-	 * if_num */
+	 * if_num
+	 */
 	for (i = 0; i < hash->size; i++) {
 		head = &hash->table[i];
 
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
 			spin_lock_bh(&orig_node->ogm_cnt_lock);
-			ret = orig_node_add_if(orig_node, max_if_num);
+			ret = batadv_orig_node_add_if(orig_node, max_if_num);
 			spin_unlock_bh(&orig_node->ogm_cnt_lock);
 
-			if (ret == -1)
+			if (ret == -ENOMEM)
 				goto err;
 		}
 		rcu_read_unlock();
@@ -541,8 +544,8 @@ err:
 	return -ENOMEM;
 }
 
-static int orig_node_del_if(struct orig_node *orig_node,
-		     int max_if_num, int del_if_num)
+static int batadv_orig_node_del_if(struct orig_node *orig_node,
+				   int max_if_num, int del_if_num)
 {
 	void *data_ptr = NULL;
 	int chunk_size;
@@ -554,7 +557,7 @@ static int orig_node_del_if(struct orig_node *orig_node,
 	chunk_size = sizeof(unsigned long) * NUM_WORDS;
 	data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC);
 	if (!data_ptr)
-		return -1;
+		return -ENOMEM;
 
 	/* copy first part */
 	memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size);
@@ -573,7 +576,7 @@ free_bcast_own:
 
 	data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
 	if (!data_ptr)
-		return -1;
+		return -ENOMEM;
 
 	memcpy(data_ptr, orig_node->bcast_own_sum,
 	       del_if_num * sizeof(uint8_t));
@@ -589,7 +592,7 @@ free_own_sum:
 	return 0;
 }
 
-int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num)
+int batadv_orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num)
 {
 	struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
 	struct hashtable_t *hash = bat_priv->orig_hash;
@@ -601,18 +604,19 @@ int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num)
 	int ret;
 
 	/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
-	 * if_num */
+	 * if_num
+	 */
 	for (i = 0; i < hash->size; i++) {
 		head = &hash->table[i];
 
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
 			spin_lock_bh(&orig_node->ogm_cnt_lock);
-			ret = orig_node_del_if(orig_node, max_if_num,
-					hard_iface->if_num);
+			ret = batadv_orig_node_del_if(orig_node, max_if_num,
+						      hard_iface->if_num);
 			spin_unlock_bh(&orig_node->ogm_cnt_lock);
 
-			if (ret == -1)
+			if (ret == -ENOMEM)
 				goto err;
 		}
 		rcu_read_unlock();
@@ -620,7 +624,7 @@ int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num)
 
 	/* renumber remaining batman interfaces _inside_ of orig_hash_lock */
 	rcu_read_lock();
-	list_for_each_entry_rcu(hard_iface_tmp, &hardif_list, list) {
+	list_for_each_entry_rcu(hard_iface_tmp, &batadv_hardif_list, list) {
 		if (hard_iface_tmp->if_status == IF_NOT_IN_USE)
 			continue;
 
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index f74d0d6..35f67eb 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_ORIGINATOR_H_
@@ -24,24 +22,26 @@
 
 #include "hash.h"
 
-int originator_init(struct bat_priv *bat_priv);
-void originator_free(struct bat_priv *bat_priv);
-void purge_orig_ref(struct bat_priv *bat_priv);
-void orig_node_free_ref(struct orig_node *orig_node);
-struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr);
+int batadv_originator_init(struct bat_priv *bat_priv);
+void batadv_originator_free(struct bat_priv *bat_priv);
+void batadv_purge_orig_ref(struct bat_priv *bat_priv);
+void batadv_orig_node_free_ref(struct orig_node *orig_node);
+struct orig_node *batadv_get_orig_node(struct bat_priv *bat_priv,
+				       const uint8_t *addr);
 struct neigh_node *batadv_neigh_node_new(struct hard_iface *hard_iface,
 					 const uint8_t *neigh_addr,
 					 uint32_t seqno);
-void neigh_node_free_ref(struct neigh_node *neigh_node);
-struct neigh_node *orig_node_get_router(struct orig_node *orig_node);
-int orig_seq_print_text(struct seq_file *seq, void *offset);
-int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num);
-int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num);
+void batadv_neigh_node_free_ref(struct neigh_node *neigh_node);
+struct neigh_node *batadv_orig_node_get_router(struct orig_node *orig_node);
+int batadv_orig_seq_print_text(struct seq_file *seq, void *offset);
+int batadv_orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num);
+int batadv_orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num);
 
 
-/* hashfunction to choose an entry in a hash table of given size */
-/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
-static inline uint32_t choose_orig(const void *data, uint32_t size)
+/* hashfunction to choose an entry in a hash table of given size
+ * hash algorithm from http://en.wikipedia.org/wiki/Hash_table
+ */
+static inline uint32_t batadv_choose_orig(const void *data, uint32_t size)
 {
 	const unsigned char *key = data;
 	uint32_t hash = 0;
@@ -60,8 +60,8 @@ static inline uint32_t choose_orig(const void *data, uint32_t size)
 	return hash % size;
 }
 
-static inline struct orig_node *orig_hash_find(struct bat_priv *bat_priv,
-					       const void *data)
+static inline struct orig_node *batadv_orig_hash_find(struct bat_priv *bat_priv,
+						      const void *data)
 {
 	struct hashtable_t *hash = bat_priv->orig_hash;
 	struct hlist_head *head;
@@ -72,12 +72,12 @@ static inline struct orig_node *orig_hash_find(struct bat_priv *bat_priv,
 	if (!hash)
 		return NULL;
 
-	index = choose_orig(data, hash->size);
+	index = batadv_choose_orig(data, hash->size);
 	head = &hash->table[index];
 
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
-		if (!compare_eth(orig_node, data))
+		if (!batadv_compare_eth(orig_node, data))
 			continue;
 
 		if (!atomic_inc_not_zero(&orig_node->refcount))
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index 0ee1af7..c90219c 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_PACKET_H_
@@ -81,7 +79,8 @@ enum tt_query_flags {
 
 /* TT_CLIENT flags.
  * Flags from 1 to 1 << 7 are sent on the wire, while flags from 1 << 8 to
- * 1 << 15 are used for local computation only */
+ * 1 << 15 are used for local computation only
+ */
 enum tt_client_flags {
 	TT_CLIENT_DEL     = 1 << 0,
 	TT_CLIENT_ROAM    = 1 << 1,
@@ -105,7 +104,7 @@ enum bla_claimframe {
 struct bla_claim_dst {
 	uint8_t magic[3];	/* FF:43:05 */
 	uint8_t type;		/* bla_claimframe */
-	uint16_t group;		/* group id */
+	__be16 group;		/* group id */
 } __packed;
 
 struct batman_header {
@@ -117,14 +116,14 @@ struct batman_header {
 struct batman_ogm_packet {
 	struct batman_header header;
 	uint8_t  flags;    /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
-	uint32_t seqno;
+	__be32   seqno;
 	uint8_t  orig[ETH_ALEN];
 	uint8_t  prev_sender[ETH_ALEN];
 	uint8_t  gw_flags;  /* flags related to gateway class */
 	uint8_t  tq;
 	uint8_t  tt_num_changes;
 	uint8_t  ttvn; /* translation table version number */
-	uint16_t tt_crc;
+	__be16   tt_crc;
 } __packed;
 
 #define BATMAN_OGM_HLEN sizeof(struct batman_ogm_packet)
@@ -134,7 +133,7 @@ struct icmp_packet {
 	uint8_t  msg_type; /* see ICMP message types above */
 	uint8_t  dst[ETH_ALEN];
 	uint8_t  orig[ETH_ALEN];
-	uint16_t seqno;
+	__be16   seqno;
 	uint8_t  uid;
 	uint8_t  reserved;
 } __packed;
@@ -142,13 +141,14 @@ struct icmp_packet {
 #define BAT_RR_LEN 16
 
 /* icmp_packet_rr must start with all fields from imcp_packet
- * as this is assumed by code that handles ICMP packets */
+ * as this is assumed by code that handles ICMP packets
+ */
 struct icmp_packet_rr {
 	struct batman_header header;
 	uint8_t  msg_type; /* see ICMP message types above */
 	uint8_t  dst[ETH_ALEN];
 	uint8_t  orig[ETH_ALEN];
-	uint16_t seqno;
+	__be16   seqno;
 	uint8_t  uid;
 	uint8_t  rr_cur;
 	uint8_t  rr[BAT_RR_LEN][ETH_ALEN];
@@ -167,20 +167,20 @@ struct unicast_frag_packet {
 	uint8_t  flags;
 	uint8_t  align;
 	uint8_t  orig[ETH_ALEN];
-	uint16_t seqno;
+	__be16   seqno;
 } __packed;
 
 struct bcast_packet {
 	struct batman_header header;
 	uint8_t  reserved;
-	uint32_t seqno;
+	__be32   seqno;
 	uint8_t  orig[ETH_ALEN];
 } __packed;
 
 struct vis_packet {
 	struct batman_header header;
 	uint8_t  vis_type;	 /* which type of vis-participant sent this? */
-	uint32_t seqno;		 /* sequence number */
+	__be32   seqno;		 /* sequence number */
 	uint8_t  entries;	 /* number of entries behind this struct */
 	uint8_t  reserved;
 	uint8_t  vis_orig[ETH_ALEN];	/* originator reporting its neighbors */
@@ -192,7 +192,8 @@ struct tt_query_packet {
 	struct batman_header header;
 	/* the flag field is a combination of:
 	 * - TT_REQUEST or TT_RESPONSE
-	 * - TT_FULL_TABLE */
+	 * - TT_FULL_TABLE
+	 */
 	uint8_t  flags;
 	uint8_t  dst[ETH_ALEN];
 	uint8_t  src[ETH_ALEN];
@@ -200,13 +201,15 @@ struct tt_query_packet {
 	 * if TT_REQUEST: ttvn that triggered the
 	 *		  request
 	 * if TT_RESPONSE: new ttvn for the src
-	 *		   orig_node */
+	 *		   orig_node
+	 */
 	uint8_t  ttvn;
 	/* tt_data field is:
 	 * if TT_REQUEST: crc associated with the
 	 *		  ttvn
-	 * if TT_RESPONSE: table_size */
-	uint16_t tt_data;
+	 * if TT_RESPONSE: table_size
+	 */
+	__be16 tt_data;
 } __packed;
 
 struct roam_adv_packet {
diff --git a/net/batman-adv/ring_buffer.c b/net/batman-adv/ring_buffer.c
index fd63951..aff1ca2 100644
--- a/net/batman-adv/ring_buffer.c
+++ b/net/batman-adv/ring_buffer.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,19 +15,19 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
 #include "ring_buffer.h"
 
-void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value)
+void batadv_ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index,
+			    uint8_t value)
 {
 	lq_recv[*lq_index] = value;
 	*lq_index = (*lq_index + 1) % TQ_GLOBAL_WINDOW_SIZE;
 }
 
-uint8_t ring_buffer_avg(const uint8_t lq_recv[])
+uint8_t batadv_ring_buffer_avg(const uint8_t lq_recv[])
 {
 	const uint8_t *ptr;
 	uint16_t count = 0, i = 0, sum = 0;
diff --git a/net/batman-adv/ring_buffer.h b/net/batman-adv/ring_buffer.h
index 8b58bd8..fda8c17 100644
--- a/net/batman-adv/ring_buffer.h
+++ b/net/batman-adv/ring_buffer.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,13 +15,13 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_RING_BUFFER_H_
 #define _NET_BATMAN_ADV_RING_BUFFER_H_
 
-void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value);
-uint8_t ring_buffer_avg(const uint8_t lq_recv[]);
+void batadv_ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index,
+			    uint8_t value);
+uint8_t batadv_ring_buffer_avg(const uint8_t lq_recv[]);
 
 #endif /* _NET_BATMAN_ADV_RING_BUFFER_H_ */
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 840e2c6..e7ee40d 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -31,10 +29,10 @@
 #include "unicast.h"
 #include "bridge_loop_avoidance.h"
 
-static int route_unicast_packet(struct sk_buff *skb,
-				struct hard_iface *recv_if);
+static int batadv_route_unicast_packet(struct sk_buff *skb,
+				       struct hard_iface *recv_if);
 
-void slide_own_bcast_window(struct hard_iface *hard_iface)
+void batadv_slide_own_bcast_window(struct hard_iface *hard_iface)
 {
 	struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
 	struct hashtable_t *hash = bat_priv->orig_hash;
@@ -54,7 +52,7 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
 			word_index = hard_iface->if_num * NUM_WORDS;
 			word = &(orig_node->bcast_own[word_index]);
 
-			bit_get_packet(bat_priv, word, 1, 0);
+			batadv_bit_get_packet(bat_priv, word, 1, 0);
 			orig_node->bcast_own_sum[hard_iface->if_num] =
 				bitmap_weight(word, TQ_LOCAL_WINDOW_SIZE);
 			spin_unlock_bh(&orig_node->ogm_cnt_lock);
@@ -63,37 +61,37 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
 	}
 }
 
-static void _update_route(struct bat_priv *bat_priv,
-			  struct orig_node *orig_node,
-			  struct neigh_node *neigh_node)
+static void _batadv_update_route(struct bat_priv *bat_priv,
+				 struct orig_node *orig_node,
+				 struct neigh_node *neigh_node)
 {
 	struct neigh_node *curr_router;
 
-	curr_router = orig_node_get_router(orig_node);
+	curr_router = batadv_orig_node_get_router(orig_node);
 
 	/* route deleted */
 	if ((curr_router) && (!neigh_node)) {
-		bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
-			orig_node->orig);
-		tt_global_del_orig(bat_priv, orig_node,
-				   "Deleted route towards originator");
+		batadv_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
+			   orig_node->orig);
+		batadv_tt_global_del_orig(bat_priv, orig_node,
+					  "Deleted route towards originator");
 
 	/* route added */
 	} else if ((!curr_router) && (neigh_node)) {
 
-		bat_dbg(DBG_ROUTES, bat_priv,
-			"Adding route towards: %pM (via %pM)\n",
-			orig_node->orig, neigh_node->addr);
+		batadv_dbg(DBG_ROUTES, bat_priv,
+			   "Adding route towards: %pM (via %pM)\n",
+			   orig_node->orig, neigh_node->addr);
 	/* route changed */
 	} else if (neigh_node && curr_router) {
-		bat_dbg(DBG_ROUTES, bat_priv,
-			"Changing route towards: %pM (now via %pM - was via %pM)\n",
-			orig_node->orig, neigh_node->addr,
-			curr_router->addr);
+		batadv_dbg(DBG_ROUTES, bat_priv,
+			   "Changing route towards: %pM (now via %pM - was via %pM)\n",
+			   orig_node->orig, neigh_node->addr,
+			   curr_router->addr);
 	}
 
 	if (curr_router)
-		neigh_node_free_ref(curr_router);
+		batadv_neigh_node_free_ref(curr_router);
 
 	/* increase refcount of new best neighbor */
 	if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount))
@@ -105,30 +103,30 @@ static void _update_route(struct bat_priv *bat_priv,
 
 	/* decrease refcount of previous best neighbor */
 	if (curr_router)
-		neigh_node_free_ref(curr_router);
+		batadv_neigh_node_free_ref(curr_router);
 }
 
-void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
-		  struct neigh_node *neigh_node)
+void batadv_update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
+			 struct neigh_node *neigh_node)
 {
 	struct neigh_node *router = NULL;
 
 	if (!orig_node)
 		goto out;
 
-	router = orig_node_get_router(orig_node);
+	router = batadv_orig_node_get_router(orig_node);
 
 	if (router != neigh_node)
-		_update_route(bat_priv, orig_node, neigh_node);
+		_batadv_update_route(bat_priv, orig_node, neigh_node);
 
 out:
 	if (router)
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 }
 
 /* caller must hold the neigh_list_lock */
-void bonding_candidate_del(struct orig_node *orig_node,
-			   struct neigh_node *neigh_node)
+void batadv_bonding_candidate_del(struct orig_node *orig_node,
+				  struct neigh_node *neigh_node)
 {
 	/* this neighbor is not part of our candidate list */
 	if (list_empty(&neigh_node->bonding_list))
@@ -136,15 +134,15 @@ void bonding_candidate_del(struct orig_node *orig_node,
 
 	list_del_rcu(&neigh_node->bonding_list);
 	INIT_LIST_HEAD(&neigh_node->bonding_list);
-	neigh_node_free_ref(neigh_node);
+	batadv_neigh_node_free_ref(neigh_node);
 	atomic_dec(&orig_node->bond_candidates);
 
 out:
 	return;
 }
 
-void bonding_candidate_add(struct orig_node *orig_node,
-			   struct neigh_node *neigh_node)
+void batadv_bonding_candidate_add(struct orig_node *orig_node,
+				  struct neigh_node *neigh_node)
 {
 	struct hlist_node *node;
 	struct neigh_node *tmp_neigh_node, *router = NULL;
@@ -153,11 +151,11 @@ void bonding_candidate_add(struct orig_node *orig_node,
 	spin_lock_bh(&orig_node->neigh_list_lock);
 
 	/* only consider if it has the same primary address ...  */
-	if (!compare_eth(orig_node->orig,
-			 neigh_node->orig_node->primary_addr))
+	if (!batadv_compare_eth(orig_node->orig,
+				neigh_node->orig_node->primary_addr))
 		goto candidate_del;
 
-	router = orig_node_get_router(orig_node);
+	router = batadv_orig_node_get_router(orig_node);
 	if (!router)
 		goto candidate_del;
 
@@ -165,8 +163,7 @@ void bonding_candidate_add(struct orig_node *orig_node,
 	if (neigh_node->tq_avg < router->tq_avg - BONDING_TQ_THRESHOLD)
 		goto candidate_del;
 
-	/**
-	 * check if we have another candidate with the same mac address or
+	/* check if we have another candidate with the same mac address or
 	 * interface. If we do, we won't select this candidate because of
 	 * possible interference.
 	 */
@@ -177,12 +174,14 @@ void bonding_candidate_add(struct orig_node *orig_node,
 			continue;
 
 		/* we only care if the other candidate is even
-		* considered as candidate. */
+		 * considered as candidate.
+		 */
 		if (list_empty(&tmp_neigh_node->bonding_list))
 			continue;
 
 		if ((neigh_node->if_incoming == tmp_neigh_node->if_incoming) ||
-		    (compare_eth(neigh_node->addr, tmp_neigh_node->addr))) {
+		    (batadv_compare_eth(neigh_node->addr,
+					tmp_neigh_node->addr))) {
 			interference_candidate = 1;
 			break;
 		}
@@ -204,19 +203,20 @@ void bonding_candidate_add(struct orig_node *orig_node,
 	goto out;
 
 candidate_del:
-	bonding_candidate_del(orig_node, neigh_node);
+	batadv_bonding_candidate_del(orig_node, neigh_node);
 
 out:
 	spin_unlock_bh(&orig_node->neigh_list_lock);
 
 	if (router)
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 }
 
 /* copy primary address for bonding */
-void bonding_save_primary(const struct orig_node *orig_node,
-			  struct orig_node *orig_neigh_node,
-			  const struct batman_ogm_packet *batman_ogm_packet)
+void
+batadv_bonding_save_primary(const struct orig_node *orig_node,
+			    struct orig_node *orig_neigh_node,
+			    const struct batman_ogm_packet *batman_ogm_packet)
 {
 	if (!(batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
 		return;
@@ -229,25 +229,25 @@ void bonding_save_primary(const struct orig_node *orig_node,
  *  0 if the packet is to be accepted
  *  1 if the packet is to be ignored.
  */
-int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff,
-		     unsigned long *last_reset)
+int batadv_window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff,
+			    unsigned long *last_reset)
 {
 	if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) ||
 	    (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
-		if (!has_timed_out(*last_reset, RESET_PROTECTION_MS))
+		if (!batadv_has_timed_out(*last_reset, RESET_PROTECTION_MS))
 			return 1;
 
 		*last_reset = jiffies;
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"old packet received, start protection\n");
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "old packet received, start protection\n");
 	}
 
 	return 0;
 }
 
-bool check_management_packet(struct sk_buff *skb,
-			     struct hard_iface *hard_iface,
-			     int header_len)
+bool batadv_check_management_packet(struct sk_buff *skb,
+				    struct hard_iface *hard_iface,
+				    int header_len)
 {
 	struct ethhdr *ethhdr;
 
@@ -276,8 +276,8 @@ bool check_management_packet(struct sk_buff *skb,
 	return true;
 }
 
-static int recv_my_icmp_packet(struct bat_priv *bat_priv,
-			       struct sk_buff *skb, size_t icmp_len)
+static int batadv_recv_my_icmp_packet(struct bat_priv *bat_priv,
+				      struct sk_buff *skb, size_t icmp_len)
 {
 	struct hard_iface *primary_if = NULL;
 	struct orig_node *orig_node = NULL;
@@ -289,21 +289,21 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
 
 	/* add data to device queue */
 	if (icmp_packet->msg_type != ECHO_REQUEST) {
-		bat_socket_receive_packet(icmp_packet, icmp_len);
+		batadv_socket_receive_packet(icmp_packet, icmp_len);
 		goto out;
 	}
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
 	/* answer echo request (ping) */
 	/* get routing information */
-	orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
+	orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->orig);
 	if (!orig_node)
 		goto out;
 
-	router = orig_node_get_router(orig_node);
+	router = batadv_orig_node_get_router(orig_node);
 	if (!router)
 		goto out;
 
@@ -318,21 +318,21 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
 	icmp_packet->msg_type = ECHO_REPLY;
 	icmp_packet->header.ttl = TTL;
 
-	send_skb_packet(skb, router->if_incoming, router->addr);
+	batadv_send_skb_packet(skb, router->if_incoming, router->addr);
 	ret = NET_RX_SUCCESS;
 
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	if (router)
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 	return ret;
 }
 
-static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
-				  struct sk_buff *skb)
+static int batadv_recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
+					 struct sk_buff *skb)
 {
 	struct hard_iface *primary_if = NULL;
 	struct orig_node *orig_node = NULL;
@@ -349,16 +349,16 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
 		goto out;
 	}
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
 	/* get routing information */
-	orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
+	orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->orig);
 	if (!orig_node)
 		goto out;
 
-	router = orig_node_get_router(orig_node);
+	router = batadv_orig_node_get_router(orig_node);
 	if (!router)
 		goto out;
 
@@ -373,21 +373,21 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
 	icmp_packet->msg_type = TTL_EXCEEDED;
 	icmp_packet->header.ttl = TTL;
 
-	send_skb_packet(skb, router->if_incoming, router->addr);
+	batadv_send_skb_packet(skb, router->if_incoming, router->addr);
 	ret = NET_RX_SUCCESS;
 
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	if (router)
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 	return ret;
 }
 
 
-int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
+int batadv_recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 {
 	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 	struct icmp_packet_rr *icmp_packet;
@@ -397,9 +397,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 	int hdr_size = sizeof(struct icmp_packet);
 	int ret = NET_RX_DROP;
 
-	/**
-	 * we truncate all incoming icmp packets if they don't match our size
-	 */
+	/* we truncate all incoming icmp packets if they don't match our size */
 	if (skb->len >= sizeof(struct icmp_packet_rr))
 		hdr_size = sizeof(struct icmp_packet_rr);
 
@@ -418,7 +416,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 		goto out;
 
 	/* not for me */
-	if (!is_my_mac(ethhdr->h_dest))
+	if (!batadv_is_my_mac(ethhdr->h_dest))
 		goto out;
 
 	icmp_packet = (struct icmp_packet_rr *)skb->data;
@@ -432,19 +430,19 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 	}
 
 	/* packet for me */
-	if (is_my_mac(icmp_packet->dst))
-		return recv_my_icmp_packet(bat_priv, skb, hdr_size);
+	if (batadv_is_my_mac(icmp_packet->dst))
+		return batadv_recv_my_icmp_packet(bat_priv, skb, hdr_size);
 
 	/* TTL exceeded */
 	if (icmp_packet->header.ttl < 2)
-		return recv_icmp_ttl_exceeded(bat_priv, skb);
+		return batadv_recv_icmp_ttl_exceeded(bat_priv, skb);
 
 	/* get routing information */
-	orig_node = orig_hash_find(bat_priv, icmp_packet->dst);
+	orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->dst);
 	if (!orig_node)
 		goto out;
 
-	router = orig_node_get_router(orig_node);
+	router = batadv_orig_node_get_router(orig_node);
 	if (!router)
 		goto out;
 
@@ -458,14 +456,14 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 	icmp_packet->header.ttl--;
 
 	/* route it */
-	send_skb_packet(skb, router->if_incoming, router->addr);
+	batadv_send_skb_packet(skb, router->if_incoming, router->addr);
 	ret = NET_RX_SUCCESS;
 
 out:
 	if (router)
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 	return ret;
 }
 
@@ -473,9 +471,11 @@ out:
  * robin fashion over the remaining interfaces.
  *
  * This method rotates the bonding list and increases the
- * returned router's refcount. */
-static struct neigh_node *find_bond_router(struct orig_node *primary_orig,
-					   const struct hard_iface *recv_if)
+ * returned router's refcount.
+ */
+static struct neigh_node *
+batadv_find_bond_router(struct orig_node *primary_orig,
+			const struct hard_iface *recv_if)
 {
 	struct neigh_node *tmp_neigh_node;
 	struct neigh_node *router = NULL, *first_candidate = NULL;
@@ -506,10 +506,12 @@ static struct neigh_node *find_bond_router(struct orig_node *primary_orig,
 		goto out;
 
 	/* selected should point to the next element
-	 * after the current router */
+	 * after the current router
+	 */
 	spin_lock_bh(&primary_orig->neigh_list_lock);
 	/* this is a list_move(), which unfortunately
-	 * does not exist as rcu version */
+	 * does not exist as rcu version
+	 */
 	list_del_rcu(&primary_orig->bond_list);
 	list_add_rcu(&primary_orig->bond_list,
 		     &router->bonding_list);
@@ -524,9 +526,11 @@ out:
  * remaining candidates which are not using
  * this interface.
  *
- * Increases the returned router's refcount */
-static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
-					      const struct hard_iface *recv_if)
+ * Increases the returned router's refcount
+ */
+static struct neigh_node *
+batadv_find_ifalter_router(struct orig_node *primary_orig,
+			   const struct hard_iface *recv_if)
 {
 	struct neigh_node *tmp_neigh_node;
 	struct neigh_node *router = NULL, *first_candidate = NULL;
@@ -545,19 +549,21 @@ static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
 			continue;
 
 		/* if we don't have a router yet
-		 * or this one is better, choose it. */
+		 * or this one is better, choose it.
+		 */
 		if ((!router) ||
 		    (tmp_neigh_node->tq_avg > router->tq_avg)) {
 			/* decrement refcount of
-			 * previously selected router */
+			 * previously selected router
+			 */
 			if (router)
-				neigh_node_free_ref(router);
+				batadv_neigh_node_free_ref(router);
 
 			router = tmp_neigh_node;
 			atomic_inc_not_zero(&router->refcount);
 		}
 
-		neigh_node_free_ref(tmp_neigh_node);
+		batadv_neigh_node_free_ref(tmp_neigh_node);
 	}
 
 	/* use the first candidate if nothing was found. */
@@ -569,12 +575,13 @@ static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
 	return router;
 }
 
-int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
+int batadv_recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
 {
 	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 	struct tt_query_packet *tt_query;
-	uint16_t tt_len;
+	uint16_t tt_size;
 	struct ethhdr *ethhdr;
+	char tt_flag;
 
 	/* drop packet if it has not necessary minimum size */
 	if (unlikely(!pskb_may_pull(skb, sizeof(struct tt_query_packet))))
@@ -596,43 +603,49 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
 
 	tt_query = (struct tt_query_packet *)skb->data;
 
-	tt_query->tt_data = ntohs(tt_query->tt_data);
-
 	switch (tt_query->flags & TT_QUERY_TYPE_MASK) {
 	case TT_REQUEST:
+		batadv_inc_counter(bat_priv, BAT_CNT_TT_REQUEST_RX);
+
 		/* If we cannot provide an answer the tt_request is
-		 * forwarded */
-		if (!send_tt_response(bat_priv, tt_query)) {
-			bat_dbg(DBG_TT, bat_priv,
-				"Routing TT_REQUEST to %pM [%c]\n",
-				tt_query->dst,
-				(tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
-			tt_query->tt_data = htons(tt_query->tt_data);
-			return route_unicast_packet(skb, recv_if);
+		 * forwarded
+		 */
+		if (!batadv_send_tt_response(bat_priv, tt_query)) {
+			tt_flag = tt_query->flags & TT_FULL_TABLE ? 'F' : '.';
+			batadv_dbg(DBG_TT, bat_priv,
+				   "Routing TT_REQUEST to %pM [%c]\n",
+				   tt_query->dst,
+				   tt_flag);
+			return batadv_route_unicast_packet(skb, recv_if);
 		}
 		break;
 	case TT_RESPONSE:
-		if (is_my_mac(tt_query->dst)) {
+		batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_RX);
+
+		if (batadv_is_my_mac(tt_query->dst)) {
 			/* packet needs to be linearized to access the TT
-			 * changes */
+			 * changes
+			 */
 			if (skb_linearize(skb) < 0)
 				goto out;
+			/* skb_linearize() possibly changed skb->data */
+			tt_query = (struct tt_query_packet *)skb->data;
 
-			tt_len = tt_query->tt_data * sizeof(struct tt_change);
+			tt_size = batadv_tt_len(ntohs(tt_query->tt_data));
 
 			/* Ensure we have all the claimed data */
 			if (unlikely(skb_headlen(skb) <
-				     sizeof(struct tt_query_packet) + tt_len))
+				     sizeof(struct tt_query_packet) + tt_size))
 				goto out;
 
-			handle_tt_response(bat_priv, tt_query);
+			batadv_handle_tt_response(bat_priv, tt_query);
 		} else {
-			bat_dbg(DBG_TT, bat_priv,
-				"Routing TT_RESPONSE to %pM [%c]\n",
-				tt_query->dst,
-				(tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
-			tt_query->tt_data = htons(tt_query->tt_data);
-			return route_unicast_packet(skb, recv_if);
+			tt_flag = tt_query->flags & TT_FULL_TABLE ? 'F' : '.';
+			batadv_dbg(DBG_TT, bat_priv,
+				   "Routing TT_RESPONSE to %pM [%c]\n",
+				   tt_query->dst,
+				   tt_flag);
+			return batadv_route_unicast_packet(skb, recv_if);
 		}
 		break;
 	}
@@ -642,7 +655,7 @@ out:
 	return NET_RX_DROP;
 }
 
-int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
+int batadv_recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
 {
 	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 	struct roam_adv_packet *roam_adv_packet;
@@ -663,35 +676,39 @@ int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
 	if (is_broadcast_ether_addr(ethhdr->h_source))
 		goto out;
 
+	batadv_inc_counter(bat_priv, BAT_CNT_TT_ROAM_ADV_RX);
+
 	roam_adv_packet = (struct roam_adv_packet *)skb->data;
 
-	if (!is_my_mac(roam_adv_packet->dst))
-		return route_unicast_packet(skb, recv_if);
+	if (!batadv_is_my_mac(roam_adv_packet->dst))
+		return batadv_route_unicast_packet(skb, recv_if);
 
 	/* check if it is a backbone gateway. we don't accept
 	 * roaming advertisement from it, as it has the same
 	 * entries as we have.
 	 */
-	if (bla_is_backbone_gw_orig(bat_priv, roam_adv_packet->src))
+	if (batadv_bla_is_backbone_gw_orig(bat_priv, roam_adv_packet->src))
 		goto out;
 
-	orig_node = orig_hash_find(bat_priv, roam_adv_packet->src);
+	orig_node = batadv_orig_hash_find(bat_priv, roam_adv_packet->src);
 	if (!orig_node)
 		goto out;
 
-	bat_dbg(DBG_TT, bat_priv,
-		"Received ROAMING_ADV from %pM (client %pM)\n",
-		roam_adv_packet->src, roam_adv_packet->client);
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Received ROAMING_ADV from %pM (client %pM)\n",
+		   roam_adv_packet->src, roam_adv_packet->client);
 
-	tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
-		      atomic_read(&orig_node->last_ttvn) + 1, true, false);
+	batadv_tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
+			     atomic_read(&orig_node->last_ttvn) + 1, true,
+			     false);
 
 	/* Roaming phase starts: I have new information but the ttvn has not
 	 * been incremented yet. This flag will make me check all the incoming
-	 * packets for the correct destination. */
+	 * packets for the correct destination.
+	 */
 	bat_priv->tt_poss_change = true;
 
-	orig_node_free_ref(orig_node);
+	batadv_orig_node_free_ref(orig_node);
 out:
 	/* returning NET_RX_DROP will make the caller function kfree the skb */
 	return NET_RX_DROP;
@@ -699,26 +716,29 @@ out:
 
 /* find a suitable router for this originator, and use
  * bonding if possible. increases the found neighbors
- * refcount.*/
-struct neigh_node *find_router(struct bat_priv *bat_priv,
-			       struct orig_node *orig_node,
-			       const struct hard_iface *recv_if)
+ * refcount.
+ */
+struct neigh_node *batadv_find_router(struct bat_priv *bat_priv,
+				      struct orig_node *orig_node,
+				      const struct hard_iface *recv_if)
 {
 	struct orig_node *primary_orig_node;
 	struct orig_node *router_orig;
 	struct neigh_node *router;
 	static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
 	int bonding_enabled;
+	uint8_t *primary_addr;
 
 	if (!orig_node)
 		return NULL;
 
-	router = orig_node_get_router(orig_node);
+	router = batadv_orig_node_get_router(orig_node);
 	if (!router)
 		goto err;
 
 	/* without bonding, the first node should
-	 * always choose the default router. */
+	 * always choose the default router.
+	 */
 	bonding_enabled = atomic_read(&bat_priv->bonding);
 
 	rcu_read_lock();
@@ -730,40 +750,44 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
 	if ((!recv_if) && (!bonding_enabled))
 		goto return_router;
 
+	primary_addr = router_orig->primary_addr;
+
 	/* if we have something in the primary_addr, we can search
-	 * for a potential bonding candidate. */
-	if (compare_eth(router_orig->primary_addr, zero_mac))
+	 * for a potential bonding candidate.
+	 */
+	if (batadv_compare_eth(primary_addr, zero_mac))
 		goto return_router;
 
 	/* find the orig_node which has the primary interface. might
-	 * even be the same as our router_orig in many cases */
-
-	if (compare_eth(router_orig->primary_addr, router_orig->orig)) {
+	 * even be the same as our router_orig in many cases
+	 */
+	if (batadv_compare_eth(primary_addr, router_orig->orig)) {
 		primary_orig_node = router_orig;
 	} else {
-		primary_orig_node = orig_hash_find(bat_priv,
-						   router_orig->primary_addr);
+		primary_orig_node = batadv_orig_hash_find(bat_priv,
+							  primary_addr);
 		if (!primary_orig_node)
 			goto return_router;
 
-		orig_node_free_ref(primary_orig_node);
+		batadv_orig_node_free_ref(primary_orig_node);
 	}
 
 	/* with less than 2 candidates, we can't do any
-	 * bonding and prefer the original router. */
+	 * bonding and prefer the original router.
+	 */
 	if (atomic_read(&primary_orig_node->bond_candidates) < 2)
 		goto return_router;
 
 	/* all nodes between should choose a candidate which
 	 * is is not on the interface where the packet came
-	 * in. */
-
-	neigh_node_free_ref(router);
+	 * in.
+	 */
+	batadv_neigh_node_free_ref(router);
 
 	if (bonding_enabled)
-		router = find_bond_router(primary_orig_node, recv_if);
+		router = batadv_find_bond_router(primary_orig_node, recv_if);
 	else
-		router = find_ifalter_router(primary_orig_node, recv_if);
+		router = batadv_find_ifalter_router(primary_orig_node, recv_if);
 
 return_router:
 	if (router && router->if_incoming->if_status != IF_ACTIVE)
@@ -775,11 +799,11 @@ err_unlock:
 	rcu_read_unlock();
 err:
 	if (router)
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 	return NULL;
 }
 
-static int check_unicast_packet(struct sk_buff *skb, int hdr_size)
+static int batadv_check_unicast_packet(struct sk_buff *skb, int hdr_size)
 {
 	struct ethhdr *ethhdr;
 
@@ -798,13 +822,14 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size)
 		return -1;
 
 	/* not for me */
-	if (!is_my_mac(ethhdr->h_dest))
+	if (!batadv_is_my_mac(ethhdr->h_dest))
 		return -1;
 
 	return 0;
 }
 
-static int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
+static int batadv_route_unicast_packet(struct sk_buff *skb,
+				       struct hard_iface *recv_if)
 {
 	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 	struct orig_node *orig_node = NULL;
@@ -824,13 +849,13 @@ static int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 	}
 
 	/* get routing information */
-	orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
+	orig_node = batadv_orig_hash_find(bat_priv, unicast_packet->dest);
 
 	if (!orig_node)
 		goto out;
 
 	/* find_router() increases neigh_nodes refcount if found. */
-	neigh_node = find_router(bat_priv, orig_node, recv_if);
+	neigh_node = batadv_find_router(bat_priv, orig_node, recv_if);
 
 	if (!neigh_node)
 		goto out;
@@ -844,15 +869,17 @@ static int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 	if (unicast_packet->header.packet_type == BAT_UNICAST &&
 	    atomic_read(&bat_priv->fragmentation) &&
 	    skb->len > neigh_node->if_incoming->net_dev->mtu) {
-		ret = frag_send_skb(skb, bat_priv,
-				    neigh_node->if_incoming, neigh_node->addr);
+		ret = batadv_frag_send_skb(skb, bat_priv,
+					   neigh_node->if_incoming,
+					   neigh_node->addr);
 		goto out;
 	}
 
 	if (unicast_packet->header.packet_type == BAT_UNICAST_FRAG &&
-	    frag_can_reassemble(skb, neigh_node->if_incoming->net_dev->mtu)) {
+	    batadv_frag_can_reassemble(skb,
+				       neigh_node->if_incoming->net_dev->mtu)) {
 
-		ret = frag_reassemble_skb(skb, bat_priv, &new_skb);
+		ret = batadv_frag_reassemble_skb(skb, bat_priv, &new_skb);
 
 		if (ret == NET_RX_DROP)
 			goto out;
@@ -870,20 +897,25 @@ static int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 	/* decrement ttl */
 	unicast_packet->header.ttl--;
 
+	/* Update stats counter */
+	batadv_inc_counter(bat_priv, BAT_CNT_FORWARD);
+	batadv_add_counter(bat_priv, BAT_CNT_FORWARD_BYTES,
+			   skb->len + ETH_HLEN);
+
 	/* route it */
-	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
 	ret = NET_RX_SUCCESS;
 
 out:
 	if (neigh_node)
-		neigh_node_free_ref(neigh_node);
+		batadv_neigh_node_free_ref(neigh_node);
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 	return ret;
 }
 
-static int check_unicast_ttvn(struct bat_priv *bat_priv,
-			       struct sk_buff *skb) {
+static int batadv_check_unicast_ttvn(struct bat_priv *bat_priv,
+				     struct sk_buff *skb) {
 	uint8_t curr_ttvn;
 	struct orig_node *orig_node;
 	struct ethhdr *ethhdr;
@@ -897,18 +929,19 @@ static int check_unicast_ttvn(struct bat_priv *bat_priv,
 
 	unicast_packet = (struct unicast_packet *)skb->data;
 
-	if (is_my_mac(unicast_packet->dest)) {
+	if (batadv_is_my_mac(unicast_packet->dest)) {
 		tt_poss_change = bat_priv->tt_poss_change;
 		curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
 	} else {
-		orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
+		orig_node = batadv_orig_hash_find(bat_priv,
+						  unicast_packet->dest);
 
 		if (!orig_node)
 			return 0;
 
 		curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
 		tt_poss_change = orig_node->tt_poss_change;
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 	}
 
 	/* Check whether I have to reroute the packet */
@@ -924,62 +957,66 @@ static int check_unicast_ttvn(struct bat_priv *bat_priv,
 		/* we don't have an updated route for this client, so we should
 		 * not try to reroute the packet!!
 		 */
-		if (tt_global_client_is_roaming(bat_priv, ethhdr->h_dest))
+		if (batadv_tt_global_client_is_roaming(bat_priv,
+						       ethhdr->h_dest))
 			return 1;
 
-		orig_node = transtable_search(bat_priv, NULL, ethhdr->h_dest);
+		orig_node = batadv_transtable_search(bat_priv, NULL,
+						     ethhdr->h_dest);
 
 		if (!orig_node) {
-			if (!is_my_client(bat_priv, ethhdr->h_dest))
+			if (!batadv_is_my_client(bat_priv, ethhdr->h_dest))
 				return 0;
-			primary_if = primary_if_get_selected(bat_priv);
+			primary_if = batadv_primary_if_get_selected(bat_priv);
 			if (!primary_if)
 				return 0;
 			memcpy(unicast_packet->dest,
 			       primary_if->net_dev->dev_addr, ETH_ALEN);
-			hardif_free_ref(primary_if);
+			batadv_hardif_free_ref(primary_if);
 		} else {
 			memcpy(unicast_packet->dest, orig_node->orig,
 			       ETH_ALEN);
 			curr_ttvn = (uint8_t)
 				atomic_read(&orig_node->last_ttvn);
-			orig_node_free_ref(orig_node);
+			batadv_orig_node_free_ref(orig_node);
 		}
 
-		bat_dbg(DBG_ROUTES, bat_priv,
-			"TTVN mismatch (old_ttvn %u new_ttvn %u)! Rerouting unicast packet (for %pM) to %pM\n",
-			unicast_packet->ttvn, curr_ttvn, ethhdr->h_dest,
-			unicast_packet->dest);
+		batadv_dbg(DBG_ROUTES, bat_priv,
+			   "TTVN mismatch (old_ttvn %u new_ttvn %u)! Rerouting unicast packet (for %pM) to %pM\n",
+			   unicast_packet->ttvn, curr_ttvn, ethhdr->h_dest,
+			   unicast_packet->dest);
 
 		unicast_packet->ttvn = curr_ttvn;
 	}
 	return 1;
 }
 
-int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
+int batadv_recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 {
 	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 	struct unicast_packet *unicast_packet;
 	int hdr_size = sizeof(*unicast_packet);
 
-	if (check_unicast_packet(skb, hdr_size) < 0)
+	if (batadv_check_unicast_packet(skb, hdr_size) < 0)
 		return NET_RX_DROP;
 
-	if (!check_unicast_ttvn(bat_priv, skb))
+	if (!batadv_check_unicast_ttvn(bat_priv, skb))
 		return NET_RX_DROP;
 
 	unicast_packet = (struct unicast_packet *)skb->data;
 
 	/* packet for me */
-	if (is_my_mac(unicast_packet->dest)) {
-		interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
+	if (batadv_is_my_mac(unicast_packet->dest)) {
+		batadv_interface_rx(recv_if->soft_iface, skb, recv_if,
+				    hdr_size);
 		return NET_RX_SUCCESS;
 	}
 
-	return route_unicast_packet(skb, recv_if);
+	return batadv_route_unicast_packet(skb, recv_if);
 }
 
-int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
+int batadv_recv_ucast_frag_packet(struct sk_buff *skb,
+				  struct hard_iface *recv_if)
 {
 	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 	struct unicast_frag_packet *unicast_packet;
@@ -987,18 +1024,18 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 	struct sk_buff *new_skb = NULL;
 	int ret;
 
-	if (check_unicast_packet(skb, hdr_size) < 0)
+	if (batadv_check_unicast_packet(skb, hdr_size) < 0)
 		return NET_RX_DROP;
 
-	if (!check_unicast_ttvn(bat_priv, skb))
+	if (!batadv_check_unicast_ttvn(bat_priv, skb))
 		return NET_RX_DROP;
 
 	unicast_packet = (struct unicast_frag_packet *)skb->data;
 
 	/* packet for me */
-	if (is_my_mac(unicast_packet->dest)) {
+	if (batadv_is_my_mac(unicast_packet->dest)) {
 
-		ret = frag_reassemble_skb(skb, bat_priv, &new_skb);
+		ret = batadv_frag_reassemble_skb(skb, bat_priv, &new_skb);
 
 		if (ret == NET_RX_DROP)
 			return NET_RX_DROP;
@@ -1007,16 +1044,16 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 		if (!new_skb)
 			return NET_RX_SUCCESS;
 
-		interface_rx(recv_if->soft_iface, new_skb, recv_if,
-			     sizeof(struct unicast_packet));
+		batadv_interface_rx(recv_if->soft_iface, new_skb, recv_if,
+				    sizeof(struct unicast_packet));
 		return NET_RX_SUCCESS;
 	}
 
-	return route_unicast_packet(skb, recv_if);
+	return batadv_route_unicast_packet(skb, recv_if);
 }
 
 
-int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
+int batadv_recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 {
 	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 	struct orig_node *orig_node = NULL;
@@ -1041,19 +1078,19 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 		goto out;
 
 	/* ignore broadcasts sent by myself */
-	if (is_my_mac(ethhdr->h_source))
+	if (batadv_is_my_mac(ethhdr->h_source))
 		goto out;
 
 	bcast_packet = (struct bcast_packet *)skb->data;
 
 	/* ignore broadcasts originated by myself */
-	if (is_my_mac(bcast_packet->orig))
+	if (batadv_is_my_mac(bcast_packet->orig))
 		goto out;
 
 	if (bcast_packet->header.ttl < 2)
 		goto out;
 
-	orig_node = orig_hash_find(bat_priv, bcast_packet->orig);
+	orig_node = batadv_orig_hash_find(bat_priv, bcast_packet->orig);
 
 	if (!orig_node)
 		goto out;
@@ -1061,39 +1098,40 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 	spin_lock_bh(&orig_node->bcast_seqno_lock);
 
 	/* check whether the packet is a duplicate */
-	if (bat_test_bit(orig_node->bcast_bits, orig_node->last_bcast_seqno,
-			 ntohl(bcast_packet->seqno)))
+	if (batadv_test_bit(orig_node->bcast_bits, orig_node->last_bcast_seqno,
+			    ntohl(bcast_packet->seqno)))
 		goto spin_unlock;
 
 	seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
 
 	/* check whether the packet is old and the host just restarted. */
-	if (window_protected(bat_priv, seq_diff,
-			     &orig_node->bcast_seqno_reset))
+	if (batadv_window_protected(bat_priv, seq_diff,
+				    &orig_node->bcast_seqno_reset))
 		goto spin_unlock;
 
 	/* mark broadcast in flood history, update window position
-	 * if required. */
-	if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
+	 * if required.
+	 */
+	if (batadv_bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
 		orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
 
 	spin_unlock_bh(&orig_node->bcast_seqno_lock);
 
 	/* check whether this has been sent by another originator before */
-	if (bla_check_bcast_duplist(bat_priv, bcast_packet, hdr_size))
+	if (batadv_bla_check_bcast_duplist(bat_priv, bcast_packet, hdr_size))
 		goto out;
 
 	/* rebroadcast packet */
-	add_bcast_packet_to_list(bat_priv, skb, 1);
+	batadv_add_bcast_packet_to_list(bat_priv, skb, 1);
 
 	/* don't hand the broadcast up if it is from an originator
 	 * from the same backbone.
 	 */
-	if (bla_is_backbone_gw(skb, orig_node, hdr_size))
+	if (batadv_bla_is_backbone_gw(skb, orig_node, hdr_size))
 		goto out;
 
 	/* broadcast for me */
-	interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
+	batadv_interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
 	ret = NET_RX_SUCCESS;
 	goto out;
 
@@ -1101,11 +1139,11 @@ spin_unlock:
 	spin_unlock_bh(&orig_node->bcast_seqno_lock);
 out:
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 	return ret;
 }
 
-int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if)
+int batadv_recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 {
 	struct vis_packet *vis_packet;
 	struct ethhdr *ethhdr;
@@ -1123,25 +1161,25 @@ int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 
 	/* not for me */
-	if (!is_my_mac(ethhdr->h_dest))
+	if (!batadv_is_my_mac(ethhdr->h_dest))
 		return NET_RX_DROP;
 
 	/* ignore own packets */
-	if (is_my_mac(vis_packet->vis_orig))
+	if (batadv_is_my_mac(vis_packet->vis_orig))
 		return NET_RX_DROP;
 
-	if (is_my_mac(vis_packet->sender_orig))
+	if (batadv_is_my_mac(vis_packet->sender_orig))
 		return NET_RX_DROP;
 
 	switch (vis_packet->vis_type) {
 	case VIS_TYPE_SERVER_SYNC:
-		receive_server_sync_packet(bat_priv, vis_packet,
-					   skb_headlen(skb));
+		batadv_receive_server_sync_packet(bat_priv, vis_packet,
+						  skb_headlen(skb));
 		break;
 
 	case VIS_TYPE_CLIENT_UPDATE:
-		receive_client_update_packet(bat_priv, vis_packet,
-					     skb_headlen(skb));
+		batadv_receive_client_update_packet(bat_priv, vis_packet,
+						    skb_headlen(skb));
 		break;
 
 	default:	/* ignore unknown packet */
@@ -1149,6 +1187,7 @@ int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if)
 	}
 
 	/* We take a copy of the data in the packet, so we should
-	   always free the skbuf. */
+	 * always free the skbuf.
+	 */
 	return NET_RX_DROP;
 }
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h
index d6bbbeb..c3fd219 100644
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,36 +15,37 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_ROUTING_H_
 #define _NET_BATMAN_ADV_ROUTING_H_
 
-void slide_own_bcast_window(struct hard_iface *hard_iface);
-bool check_management_packet(struct sk_buff *skb,
-			     struct hard_iface *hard_iface,
-			     int header_len);
-void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
-		  struct neigh_node *neigh_node);
-int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if);
-int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
-int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if);
-int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
-int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if);
-int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if);
-int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if);
-struct neigh_node *find_router(struct bat_priv *bat_priv,
-			       struct orig_node *orig_node,
-			       const struct hard_iface *recv_if);
-void bonding_candidate_del(struct orig_node *orig_node,
-			   struct neigh_node *neigh_node);
-void bonding_candidate_add(struct orig_node *orig_node,
-			   struct neigh_node *neigh_node);
-void bonding_save_primary(const struct orig_node *orig_node,
-			  struct orig_node *orig_neigh_node,
-			  const struct batman_ogm_packet *batman_ogm_packet);
-int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff,
-		     unsigned long *last_reset);
+void batadv_slide_own_bcast_window(struct hard_iface *hard_iface);
+bool batadv_check_management_packet(struct sk_buff *skb,
+				    struct hard_iface *hard_iface,
+				    int header_len);
+void batadv_update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
+			 struct neigh_node *neigh_node);
+int batadv_recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if);
+int batadv_recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
+int batadv_recv_ucast_frag_packet(struct sk_buff *skb,
+				  struct hard_iface *recv_if);
+int batadv_recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
+int batadv_recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if);
+int batadv_recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if);
+int batadv_recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if);
+struct neigh_node *batadv_find_router(struct bat_priv *bat_priv,
+				      struct orig_node *orig_node,
+				      const struct hard_iface *recv_if);
+void batadv_bonding_candidate_del(struct orig_node *orig_node,
+				  struct neigh_node *neigh_node);
+void batadv_bonding_candidate_add(struct orig_node *orig_node,
+				  struct neigh_node *neigh_node);
+void batadv_bonding_save_primary(const struct orig_node *orig_node,
+				 struct orig_node *orig_neigh_node,
+				 const struct batman_ogm_packet
+				 *batman_ogm_packet);
+int batadv_window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff,
+			    unsigned long *last_reset);
 
 #endif /* _NET_BATMAN_ADV_ROUTING_H_ */
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index f47299f..1842cbc 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -29,12 +27,13 @@
 #include "gateway_common.h"
 #include "originator.h"
 
-static void send_outstanding_bcast_packet(struct work_struct *work);
+static void batadv_send_outstanding_bcast_packet(struct work_struct *work);
 
 /* send out an already prepared packet to the given address via the
- * specified batman interface */
-int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
-		    const uint8_t *dst_addr)
+ * specified batman interface
+ */
+int batadv_send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
+			   const uint8_t *dst_addr)
 {
 	struct ethhdr *ethhdr;
 
@@ -51,7 +50,7 @@ int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
 	}
 
 	/* push to the ethernet header. */
-	if (my_skb_head_push(skb, ETH_HLEN) < 0)
+	if (batadv_skb_head_push(skb, ETH_HLEN) < 0)
 		goto send_skb_err;
 
 	skb_reset_mac_header(skb);
@@ -69,77 +68,23 @@ int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
 
 	/* dev_queue_xmit() returns a negative result on error.	 However on
 	 * congestion and traffic shaping, it drops and returns NET_XMIT_DROP
-	 * (which is > 0). This will not be treated as an error. */
-
+	 * (which is > 0). This will not be treated as an error.
+	 */
 	return dev_queue_xmit(skb);
 send_skb_err:
 	kfree_skb(skb);
 	return NET_XMIT_DROP;
 }
 
-static void realloc_packet_buffer(struct hard_iface *hard_iface,
-				  int new_len)
-{
-	unsigned char *new_buff;
-
-	new_buff = kmalloc(new_len, GFP_ATOMIC);
-
-	/* keep old buffer if kmalloc should fail */
-	if (new_buff) {
-		memcpy(new_buff, hard_iface->packet_buff,
-		       BATMAN_OGM_HLEN);
-
-		kfree(hard_iface->packet_buff);
-		hard_iface->packet_buff = new_buff;
-		hard_iface->packet_len = new_len;
-	}
-}
-
-/* when calling this function (hard_iface == primary_if) has to be true */
-static int prepare_packet_buffer(struct bat_priv *bat_priv,
-				  struct hard_iface *hard_iface)
-{
-	int new_len;
-
-	new_len = BATMAN_OGM_HLEN +
-		  tt_len((uint8_t)atomic_read(&bat_priv->tt_local_changes));
-
-	/* if we have too many changes for one packet don't send any
-	 * and wait for the tt table request which will be fragmented */
-	if (new_len > hard_iface->soft_iface->mtu)
-		new_len = BATMAN_OGM_HLEN;
-
-	realloc_packet_buffer(hard_iface, new_len);
-
-	atomic_set(&bat_priv->tt_crc, tt_local_crc(bat_priv));
-
-	/* reset the sending counter */
-	atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX);
-
-	return tt_changes_fill_buffer(bat_priv,
-				      hard_iface->packet_buff + BATMAN_OGM_HLEN,
-				      hard_iface->packet_len - BATMAN_OGM_HLEN);
-}
-
-static int reset_packet_buffer(struct bat_priv *bat_priv,
-				struct hard_iface *hard_iface)
-{
-	realloc_packet_buffer(hard_iface, BATMAN_OGM_HLEN);
-	return 0;
-}
-
-void schedule_bat_ogm(struct hard_iface *hard_iface)
+void batadv_schedule_bat_ogm(struct hard_iface *hard_iface)
 {
 	struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
-	struct hard_iface *primary_if;
-	int tt_num_changes = -1;
 
 	if ((hard_iface->if_status == IF_NOT_IN_USE) ||
 	    (hard_iface->if_status == IF_TO_BE_REMOVED))
 		return;
 
-	/**
-	 * the interface gets activated here to avoid race conditions between
+	/* the interface gets activated here to avoid race conditions between
 	 * the moment of activating the interface in
 	 * hardif_activate_interface() where the originator mac is set and
 	 * outdated packets (especially uninitialized mac addresses) in the
@@ -148,40 +93,21 @@ void schedule_bat_ogm(struct hard_iface *hard_iface)
 	if (hard_iface->if_status == IF_TO_BE_ACTIVATED)
 		hard_iface->if_status = IF_ACTIVE;
 
-	primary_if = primary_if_get_selected(bat_priv);
-
-	if (hard_iface == primary_if) {
-		/* if at least one change happened */
-		if (atomic_read(&bat_priv->tt_local_changes) > 0) {
-			tt_commit_changes(bat_priv);
-			tt_num_changes = prepare_packet_buffer(bat_priv,
-							       hard_iface);
-		}
-
-		/* if the changes have been sent often enough */
-		if (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))
-			tt_num_changes = reset_packet_buffer(bat_priv,
-							     hard_iface);
-	}
-
-	if (primary_if)
-		hardif_free_ref(primary_if);
-
-	bat_priv->bat_algo_ops->bat_ogm_schedule(hard_iface, tt_num_changes);
+	bat_priv->bat_algo_ops->bat_ogm_schedule(hard_iface);
 }
 
-static void forw_packet_free(struct forw_packet *forw_packet)
+static void batadv_forw_packet_free(struct forw_packet *forw_packet)
 {
 	if (forw_packet->skb)
 		kfree_skb(forw_packet->skb);
 	if (forw_packet->if_incoming)
-		hardif_free_ref(forw_packet->if_incoming);
+		batadv_hardif_free_ref(forw_packet->if_incoming);
 	kfree(forw_packet);
 }
 
-static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
-				      struct forw_packet *forw_packet,
-				      unsigned long send_time)
+static void _batadv_add_bcast_packet_to_list(struct bat_priv *bat_priv,
+					     struct forw_packet *forw_packet,
+					     unsigned long send_time)
 {
 	INIT_HLIST_NODE(&forw_packet->list);
 
@@ -192,8 +118,8 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
 
 	/* start timer for this packet */
 	INIT_DELAYED_WORK(&forw_packet->delayed_work,
-			  send_outstanding_bcast_packet);
-	queue_delayed_work(bat_event_workqueue, &forw_packet->delayed_work,
+			  batadv_send_outstanding_bcast_packet);
+	queue_delayed_work(batadv_event_workqueue, &forw_packet->delayed_work,
 			   send_time);
 }
 
@@ -204,9 +130,11 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
  * errors.
  *
  * The skb is not consumed, so the caller should make sure that the
- * skb is freed. */
-int add_bcast_packet_to_list(struct bat_priv *bat_priv,
-			     const struct sk_buff *skb, unsigned long delay)
+ * skb is freed.
+ */
+int batadv_add_bcast_packet_to_list(struct bat_priv *bat_priv,
+				    const struct sk_buff *skb,
+				    unsigned long delay)
 {
 	struct hard_iface *primary_if = NULL;
 	struct forw_packet *forw_packet;
@@ -214,11 +142,11 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv,
 	struct sk_buff *newskb;
 
 	if (!atomic_dec_not_zero(&bat_priv->bcast_queue_left)) {
-		bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n");
+		batadv_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n");
 		goto out;
 	}
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out_and_inc;
 
@@ -243,7 +171,7 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv,
 	/* how often did we send the bcast packet ? */
 	forw_packet->num_packets = 0;
 
-	_add_bcast_packet_to_list(bat_priv, forw_packet, delay);
+	_batadv_add_bcast_packet_to_list(bat_priv, forw_packet, delay);
 	return NETDEV_TX_OK;
 
 packet_free:
@@ -252,11 +180,11 @@ out_and_inc:
 	atomic_inc(&bat_priv->bcast_queue_left);
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	return NETDEV_TX_BUSY;
 }
 
-static void send_outstanding_bcast_packet(struct work_struct *work)
+static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
 {
 	struct hard_iface *hard_iface;
 	struct delayed_work *delayed_work =
@@ -276,14 +204,15 @@ static void send_outstanding_bcast_packet(struct work_struct *work)
 
 	/* rebroadcast packet */
 	rcu_read_lock();
-	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 		if (hard_iface->soft_iface != soft_iface)
 			continue;
 
 		/* send a copy of the saved skb */
 		skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
 		if (skb1)
-			send_skb_packet(skb1, hard_iface, broadcast_addr);
+			batadv_send_skb_packet(skb1, hard_iface,
+					       batadv_broadcast_addr);
 	}
 	rcu_read_unlock();
 
@@ -291,17 +220,17 @@ static void send_outstanding_bcast_packet(struct work_struct *work)
 
 	/* if we still have some more bcasts to send */
 	if (forw_packet->num_packets < 3) {
-		_add_bcast_packet_to_list(bat_priv, forw_packet,
-					  msecs_to_jiffies(5));
+		_batadv_add_bcast_packet_to_list(bat_priv, forw_packet,
+						 msecs_to_jiffies(5));
 		return;
 	}
 
 out:
-	forw_packet_free(forw_packet);
+	batadv_forw_packet_free(forw_packet);
 	atomic_inc(&bat_priv->bcast_queue_left);
 }
 
-void send_outstanding_bat_ogm_packet(struct work_struct *work)
+void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work)
 {
 	struct delayed_work *delayed_work =
 		container_of(work, struct delayed_work, work);
@@ -319,44 +248,42 @@ void send_outstanding_bat_ogm_packet(struct work_struct *work)
 
 	bat_priv->bat_algo_ops->bat_ogm_emit(forw_packet);
 
-	/**
-	 * we have to have at least one packet in the queue
+	/* we have to have at least one packet in the queue
 	 * to determine the queues wake up time unless we are
 	 * shutting down
 	 */
 	if (forw_packet->own)
-		schedule_bat_ogm(forw_packet->if_incoming);
+		batadv_schedule_bat_ogm(forw_packet->if_incoming);
 
 out:
 	/* don't count own packet */
 	if (!forw_packet->own)
 		atomic_inc(&bat_priv->batman_queue_left);
 
-	forw_packet_free(forw_packet);
+	batadv_forw_packet_free(forw_packet);
 }
 
-void purge_outstanding_packets(struct bat_priv *bat_priv,
-			       const struct hard_iface *hard_iface)
+void batadv_purge_outstanding_packets(struct bat_priv *bat_priv,
+				      const struct hard_iface *hard_iface)
 {
 	struct forw_packet *forw_packet;
 	struct hlist_node *tmp_node, *safe_tmp_node;
 	bool pending;
 
 	if (hard_iface)
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"purge_outstanding_packets(): %s\n",
-			hard_iface->net_dev->name);
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "purge_outstanding_packets(): %s\n",
+			   hard_iface->net_dev->name);
 	else
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"purge_outstanding_packets()\n");
+		batadv_dbg(DBG_BATMAN, bat_priv,
+			   "purge_outstanding_packets()\n");
 
 	/* free bcast list */
 	spin_lock_bh(&bat_priv->forw_bcast_list_lock);
 	hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
 				  &bat_priv->forw_bcast_list, list) {
 
-		/**
-		 * if purge_outstanding_packets() was called with an argument
+		/* if purge_outstanding_packets() was called with an argument
 		 * we delete only packets belonging to the given interface
 		 */
 		if ((hard_iface) &&
@@ -365,8 +292,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
 
 		spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
 
-		/**
-		 * send_outstanding_bcast_packet() will lock the list to
+		/* batadv_send_outstanding_bcast_packet() will lock the list to
 		 * delete the item from the list
 		 */
 		pending = cancel_delayed_work_sync(&forw_packet->delayed_work);
@@ -374,7 +300,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
 
 		if (pending) {
 			hlist_del(&forw_packet->list);
-			forw_packet_free(forw_packet);
+			batadv_forw_packet_free(forw_packet);
 		}
 	}
 	spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
@@ -384,8 +310,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
 	hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
 				  &bat_priv->forw_bat_list, list) {
 
-		/**
-		 * if purge_outstanding_packets() was called with an argument
+		/* if purge_outstanding_packets() was called with an argument
 		 * we delete only packets belonging to the given interface
 		 */
 		if ((hard_iface) &&
@@ -394,8 +319,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
 
 		spin_unlock_bh(&bat_priv->forw_bat_list_lock);
 
-		/**
-		 * send_outstanding_bat_packet() will lock the list to
+		/* send_outstanding_bat_packet() will lock the list to
 		 * delete the item from the list
 		 */
 		pending = cancel_delayed_work_sync(&forw_packet->delayed_work);
@@ -403,7 +327,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
 
 		if (pending) {
 			hlist_del(&forw_packet->list);
-			forw_packet_free(forw_packet);
+			batadv_forw_packet_free(forw_packet);
 		}
 	}
 	spin_unlock_bh(&bat_priv->forw_bat_list_lock);
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h
index 824ef06..e3ac75b 100644
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,19 +15,19 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_SEND_H_
 #define _NET_BATMAN_ADV_SEND_H_
 
-int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
-		    const uint8_t *dst_addr);
-void schedule_bat_ogm(struct hard_iface *hard_iface);
-int add_bcast_packet_to_list(struct bat_priv *bat_priv,
-			     const struct sk_buff *skb, unsigned long delay);
-void send_outstanding_bat_ogm_packet(struct work_struct *work);
-void purge_outstanding_packets(struct bat_priv *bat_priv,
-			       const struct hard_iface *hard_iface);
+int batadv_send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
+			   const uint8_t *dst_addr);
+void batadv_schedule_bat_ogm(struct hard_iface *hard_iface);
+int batadv_add_bcast_packet_to_list(struct bat_priv *bat_priv,
+				    const struct sk_buff *skb,
+				    unsigned long delay);
+void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work);
+void batadv_purge_outstanding_packets(struct bat_priv *bat_priv,
+				      const struct hard_iface *hard_iface);
 
 #endif /* _NET_BATMAN_ADV_SEND_H_ */
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 6e2530b..2de1d74 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -39,27 +37,33 @@
 #include "bridge_loop_avoidance.h"
 
 
-static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
-static void bat_get_drvinfo(struct net_device *dev,
-			    struct ethtool_drvinfo *info);
-static u32 bat_get_msglevel(struct net_device *dev);
-static void bat_set_msglevel(struct net_device *dev, u32 value);
-static u32 bat_get_link(struct net_device *dev);
-
-static const struct ethtool_ops bat_ethtool_ops = {
-	.get_settings = bat_get_settings,
-	.get_drvinfo = bat_get_drvinfo,
-	.get_msglevel = bat_get_msglevel,
-	.set_msglevel = bat_set_msglevel,
-	.get_link = bat_get_link,
+static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
+static void batadv_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info);
+static u32 batadv_get_msglevel(struct net_device *dev);
+static void batadv_set_msglevel(struct net_device *dev, u32 value);
+static u32 batadv_get_link(struct net_device *dev);
+static void batadv_get_strings(struct net_device *dev, u32 stringset, u8 *data);
+static void batadv_get_ethtool_stats(struct net_device *dev,
+				     struct ethtool_stats *stats, u64 *data);
+static int batadv_get_sset_count(struct net_device *dev, int stringset);
+
+static const struct ethtool_ops batadv_ethtool_ops = {
+	.get_settings = batadv_get_settings,
+	.get_drvinfo = batadv_get_drvinfo,
+	.get_msglevel = batadv_get_msglevel,
+	.set_msglevel = batadv_set_msglevel,
+	.get_link = batadv_get_link,
+	.get_strings = batadv_get_strings,
+	.get_ethtool_stats = batadv_get_ethtool_stats,
+	.get_sset_count = batadv_get_sset_count,
 };
 
-int my_skb_head_push(struct sk_buff *skb, unsigned int len)
+int batadv_skb_head_push(struct sk_buff *skb, unsigned int len)
 {
 	int result;
 
-	/**
-	 * TODO: We must check if we can release all references to non-payload
+	/* TODO: We must check if we can release all references to non-payload
 	 * data using skb_header_release in our skbs to allow skb_cow_header to
 	 * work optimally. This means that those skbs are not allowed to read
 	 * or write any data which is before the current position of skb->data
@@ -74,25 +78,25 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len)
 	return 0;
 }
 
-static int interface_open(struct net_device *dev)
+static int batadv_interface_open(struct net_device *dev)
 {
 	netif_start_queue(dev);
 	return 0;
 }
 
-static int interface_release(struct net_device *dev)
+static int batadv_interface_release(struct net_device *dev)
 {
 	netif_stop_queue(dev);
 	return 0;
 }
 
-static struct net_device_stats *interface_stats(struct net_device *dev)
+static struct net_device_stats *batadv_interface_stats(struct net_device *dev)
 {
 	struct bat_priv *bat_priv = netdev_priv(dev);
 	return &bat_priv->stats;
 }
 
-static int interface_set_mac_addr(struct net_device *dev, void *p)
+static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
 {
 	struct bat_priv *bat_priv = netdev_priv(dev);
 	struct sockaddr *addr = p;
@@ -102,9 +106,9 @@ static int interface_set_mac_addr(struct net_device *dev, void *p)
 
 	/* only modify transtable if it has been initialized before */
 	if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
-		tt_local_remove(bat_priv, dev->dev_addr,
-				"mac address changed", false);
-		tt_local_add(dev, addr->sa_data, NULL_IFINDEX);
+		batadv_tt_local_remove(bat_priv, dev->dev_addr,
+				       "mac address changed", false);
+		batadv_tt_local_add(dev, addr->sa_data, NULL_IFINDEX);
 	}
 
 	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
@@ -112,10 +116,10 @@ static int interface_set_mac_addr(struct net_device *dev, void *p)
 	return 0;
 }
 
-static int interface_change_mtu(struct net_device *dev, int new_mtu)
+static int batadv_interface_change_mtu(struct net_device *dev, int new_mtu)
 {
 	/* check ranges */
-	if ((new_mtu < 68) || (new_mtu > hardif_min_mtu(dev)))
+	if ((new_mtu < 68) || (new_mtu > batadv_hardif_min_mtu(dev)))
 		return -EINVAL;
 
 	dev->mtu = new_mtu;
@@ -123,7 +127,8 @@ static int interface_change_mtu(struct net_device *dev, int new_mtu)
 	return 0;
 }
 
-static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
+static int batadv_interface_tx(struct sk_buff *skb,
+			       struct net_device *soft_iface)
 {
 	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
 	struct bat_priv *bat_priv = netdev_priv(soft_iface);
@@ -155,16 +160,16 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 		goto dropped;
 	}
 
-	if (bla_tx(bat_priv, skb, vid))
+	if (batadv_bla_tx(bat_priv, skb, vid))
 		goto dropped;
 
 	/* Register the client MAC in the transtable */
-	tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
+	batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
 
 	/* don't accept stp packets. STP does not help in meshes.
 	 * better use the bridge loop avoidance ...
 	 */
-	if (compare_eth(ethhdr->h_dest, stp_addr))
+	if (batadv_compare_eth(ethhdr->h_dest, stp_addr))
 		goto dropped;
 
 	if (is_multicast_ether_addr(ethhdr->h_dest)) {
@@ -173,15 +178,17 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 		switch (atomic_read(&bat_priv->gw_mode)) {
 		case GW_MODE_SERVER:
 			/* gateway servers should not send dhcp
-			 * requests into the mesh */
-			ret = gw_is_dhcp_target(skb, &header_len);
+			 * requests into the mesh
+			 */
+			ret = batadv_gw_is_dhcp_target(skb, &header_len);
 			if (ret)
 				goto dropped;
 			break;
 		case GW_MODE_CLIENT:
 			/* gateway clients should send dhcp requests
-			 * via unicast to their gateway */
-			ret = gw_is_dhcp_target(skb, &header_len);
+			 * via unicast to their gateway
+			 */
+			ret = batadv_gw_is_dhcp_target(skb, &header_len);
 			if (ret)
 				do_bcast = false;
 			break;
@@ -193,11 +200,11 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 
 	/* ethernet packet should be broadcasted */
 	if (do_bcast) {
-		primary_if = primary_if_get_selected(bat_priv);
+		primary_if = batadv_primary_if_get_selected(bat_priv);
 		if (!primary_if)
 			goto dropped;
 
-		if (my_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
+		if (batadv_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
 			goto dropped;
 
 		bcast_packet = (struct bcast_packet *)skb->data;
@@ -208,7 +215,8 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 		bcast_packet->header.packet_type = BAT_BCAST;
 
 		/* hw address of first interface is the orig mac because only
-		 * this mac is known throughout the mesh */
+		 * this mac is known throughout the mesh
+		 */
 		memcpy(bcast_packet->orig,
 		       primary_if->net_dev->dev_addr, ETH_ALEN);
 
@@ -216,21 +224,22 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 		bcast_packet->seqno =
 			htonl(atomic_inc_return(&bat_priv->bcast_seqno));
 
-		add_bcast_packet_to_list(bat_priv, skb, 1);
+		batadv_add_bcast_packet_to_list(bat_priv, skb, 1);
 
 		/* a copy is stored in the bcast list, therefore removing
-		 * the original skb. */
+		 * the original skb.
+		 */
 		kfree_skb(skb);
 
 	/* unicast packet */
 	} else {
 		if (atomic_read(&bat_priv->gw_mode) != GW_MODE_OFF) {
-			ret = gw_out_of_range(bat_priv, skb, ethhdr);
+			ret = batadv_gw_out_of_range(bat_priv, skb, ethhdr);
 			if (ret)
 				goto dropped;
 		}
 
-		ret = unicast_send_skb(skb, bat_priv);
+		ret = batadv_unicast_send_skb(skb, bat_priv);
 		if (ret != 0)
 			goto dropped_freed;
 	}
@@ -245,13 +254,13 @@ dropped_freed:
 	bat_priv->stats.tx_dropped++;
 end:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	return NETDEV_TX_OK;
 }
 
-void interface_rx(struct net_device *soft_iface,
-		  struct sk_buff *skb, struct hard_iface *recv_if,
-		  int hdr_size)
+void batadv_interface_rx(struct net_device *soft_iface,
+			 struct sk_buff *skb, struct hard_iface *recv_if,
+			 int hdr_size)
 {
 	struct bat_priv *bat_priv = netdev_priv(soft_iface);
 	struct ethhdr *ethhdr;
@@ -287,22 +296,23 @@ void interface_rx(struct net_device *soft_iface,
 
 	/* should not be necessary anymore as we use skb_pull_rcsum()
 	 * TODO: please verify this and remove this TODO
-	 * -- Dec 21st 2009, Simon Wunderlich */
+	 * -- Dec 21st 2009, Simon Wunderlich
+	 */
 
-/*	skb->ip_summed = CHECKSUM_UNNECESSARY;*/
+	/* skb->ip_summed = CHECKSUM_UNNECESSARY; */
 
 	bat_priv->stats.rx_packets++;
 	bat_priv->stats.rx_bytes += skb->len + ETH_HLEN;
 
 	soft_iface->last_rx = jiffies;
 
-	if (is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
+	if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
 		goto dropped;
 
 	/* Let the bridge loop avoidance check the packet. If will
 	 * not handle it, we can safely push it up.
 	 */
-	if (bla_rx(bat_priv, skb, vid))
+	if (batadv_bla_rx(bat_priv, skb, vid))
 		goto out;
 
 	netif_rx(skb);
@@ -314,28 +324,27 @@ out:
 	return;
 }
 
-static const struct net_device_ops bat_netdev_ops = {
-	.ndo_open = interface_open,
-	.ndo_stop = interface_release,
-	.ndo_get_stats = interface_stats,
-	.ndo_set_mac_address = interface_set_mac_addr,
-	.ndo_change_mtu = interface_change_mtu,
-	.ndo_start_xmit = interface_tx,
+static const struct net_device_ops batadv_netdev_ops = {
+	.ndo_open = batadv_interface_open,
+	.ndo_stop = batadv_interface_release,
+	.ndo_get_stats = batadv_interface_stats,
+	.ndo_set_mac_address = batadv_interface_set_mac_addr,
+	.ndo_change_mtu = batadv_interface_change_mtu,
+	.ndo_start_xmit = batadv_interface_tx,
 	.ndo_validate_addr = eth_validate_addr
 };
 
-static void interface_setup(struct net_device *dev)
+static void batadv_interface_setup(struct net_device *dev)
 {
 	struct bat_priv *priv = netdev_priv(dev);
 
 	ether_setup(dev);
 
-	dev->netdev_ops = &bat_netdev_ops;
+	dev->netdev_ops = &batadv_netdev_ops;
 	dev->destructor = free_netdev;
 	dev->tx_queue_len = 0;
 
-	/**
-	 * can't call min_mtu, because the needed variables
+	/* can't call min_mtu, because the needed variables
 	 * have not been initialized yet
 	 */
 	dev->mtu = ETH_DATA_LEN;
@@ -345,18 +354,19 @@ static void interface_setup(struct net_device *dev)
 	/* generate random address */
 	eth_hw_addr_random(dev);
 
-	SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
+	SET_ETHTOOL_OPS(dev, &batadv_ethtool_ops);
 
 	memset(priv, 0, sizeof(*priv));
 }
 
-struct net_device *softif_create(const char *name)
+struct net_device *batadv_softif_create(const char *name)
 {
 	struct net_device *soft_iface;
 	struct bat_priv *bat_priv;
 	int ret;
 
-	soft_iface = alloc_netdev(sizeof(*bat_priv), name, interface_setup);
+	soft_iface = alloc_netdev(sizeof(*bat_priv), name,
+				  batadv_interface_setup);
 
 	if (!soft_iface)
 		goto out;
@@ -399,28 +409,35 @@ struct net_device *softif_create(const char *name)
 	bat_priv->primary_if = NULL;
 	bat_priv->num_ifaces = 0;
 
-	ret = bat_algo_select(bat_priv, bat_routing_algo);
-	if (ret < 0)
+	bat_priv->bat_counters = __alloc_percpu(sizeof(uint64_t) * BAT_CNT_NUM,
+						__alignof__(uint64_t));
+	if (!bat_priv->bat_counters)
 		goto unreg_soft_iface;
 
-	ret = sysfs_add_meshif(soft_iface);
+	ret = batadv_algo_select(bat_priv, batadv_routing_algo);
 	if (ret < 0)
-		goto unreg_soft_iface;
+		goto free_bat_counters;
+
+	ret = batadv_sysfs_add_meshif(soft_iface);
+	if (ret < 0)
+		goto free_bat_counters;
 
-	ret = debugfs_add_meshif(soft_iface);
+	ret = batadv_debugfs_add_meshif(soft_iface);
 	if (ret < 0)
 		goto unreg_sysfs;
 
-	ret = mesh_init(soft_iface);
+	ret = batadv_mesh_init(soft_iface);
 	if (ret < 0)
 		goto unreg_debugfs;
 
 	return soft_iface;
 
 unreg_debugfs:
-	debugfs_del_meshif(soft_iface);
+	batadv_debugfs_del_meshif(soft_iface);
 unreg_sysfs:
-	sysfs_del_meshif(soft_iface);
+	batadv_sysfs_del_meshif(soft_iface);
+free_bat_counters:
+	free_percpu(bat_priv->bat_counters);
 unreg_soft_iface:
 	unregister_netdevice(soft_iface);
 	return NULL;
@@ -431,24 +448,24 @@ out:
 	return NULL;
 }
 
-void softif_destroy(struct net_device *soft_iface)
+void batadv_softif_destroy(struct net_device *soft_iface)
 {
-	debugfs_del_meshif(soft_iface);
-	sysfs_del_meshif(soft_iface);
-	mesh_free(soft_iface);
+	batadv_debugfs_del_meshif(soft_iface);
+	batadv_sysfs_del_meshif(soft_iface);
+	batadv_mesh_free(soft_iface);
 	unregister_netdevice(soft_iface);
 }
 
-int softif_is_valid(const struct net_device *net_dev)
+int batadv_softif_is_valid(const struct net_device *net_dev)
 {
-	if (net_dev->netdev_ops->ndo_start_xmit == interface_tx)
+	if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx)
 		return 1;
 
 	return 0;
 }
 
 /* ethtool */
-static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	cmd->supported = 0;
 	cmd->advertising = 0;
@@ -464,8 +481,8 @@ static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 	return 0;
 }
 
-static void bat_get_drvinfo(struct net_device *dev,
-			    struct ethtool_drvinfo *info)
+static void batadv_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
 	strcpy(info->driver, "B.A.T.M.A.N. advanced");
 	strcpy(info->version, SOURCE_VERSION);
@@ -473,16 +490,64 @@ static void bat_get_drvinfo(struct net_device *dev,
 	strcpy(info->bus_info, "batman");
 }
 
-static u32 bat_get_msglevel(struct net_device *dev)
+static u32 batadv_get_msglevel(struct net_device *dev)
 {
 	return -EOPNOTSUPP;
 }
 
-static void bat_set_msglevel(struct net_device *dev, u32 value)
+static void batadv_set_msglevel(struct net_device *dev, u32 value)
 {
 }
 
-static u32 bat_get_link(struct net_device *dev)
+static u32 batadv_get_link(struct net_device *dev)
 {
 	return 1;
 }
+
+/* Inspired by drivers/net/ethernet/dlink/sundance.c:1702
+ * Declare each description string in struct.name[] to get fixed sized buffer
+ * and compile time checking for strings longer than ETH_GSTRING_LEN.
+ */
+static const struct {
+	const char name[ETH_GSTRING_LEN];
+} batadv_counters_strings[] = {
+	{ "forward" },
+	{ "forward_bytes" },
+	{ "mgmt_tx" },
+	{ "mgmt_tx_bytes" },
+	{ "mgmt_rx" },
+	{ "mgmt_rx_bytes" },
+	{ "tt_request_tx" },
+	{ "tt_request_rx" },
+	{ "tt_response_tx" },
+	{ "tt_response_rx" },
+	{ "tt_roam_adv_tx" },
+	{ "tt_roam_adv_rx" },
+};
+
+static void batadv_get_strings(struct net_device *dev, uint32_t stringset,
+			       uint8_t *data)
+{
+	if (stringset == ETH_SS_STATS)
+		memcpy(data, batadv_counters_strings,
+		       sizeof(batadv_counters_strings));
+}
+
+static void batadv_get_ethtool_stats(struct net_device *dev,
+				     struct ethtool_stats *stats,
+				     uint64_t *data)
+{
+	struct bat_priv *bat_priv = netdev_priv(dev);
+	int i;
+
+	for (i = 0; i < BAT_CNT_NUM; i++)
+		data[i] = batadv_sum_counter(bat_priv, i);
+}
+
+static int batadv_get_sset_count(struct net_device *dev, int stringset)
+{
+	if (stringset == ETH_SS_STATS)
+		return BAT_CNT_NUM;
+
+	return -EOPNOTSUPP;
+}
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h
index 0203006..2711ba5 100644
--- a/net/batman-adv/soft-interface.h
+++ b/net/batman-adv/soft-interface.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -16,18 +15,16 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_SOFT_INTERFACE_H_
 #define _NET_BATMAN_ADV_SOFT_INTERFACE_H_
 
-int my_skb_head_push(struct sk_buff *skb, unsigned int len);
-void interface_rx(struct net_device *soft_iface,
-		  struct sk_buff *skb, struct hard_iface *recv_if,
-		  int hdr_size);
-struct net_device *softif_create(const char *name);
-void softif_destroy(struct net_device *soft_iface);
-int softif_is_valid(const struct net_device *net_dev);
+int batadv_skb_head_push(struct sk_buff *skb, unsigned int len);
+void batadv_interface_rx(struct net_device *soft_iface, struct sk_buff *skb,
+			 struct hard_iface *recv_if, int hdr_size);
+struct net_device *batadv_softif_create(const char *name);
+void batadv_softif_destroy(struct net_device *soft_iface);
+int batadv_softif_is_valid(const struct net_device *net_dev);
 
 #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index a66c2dc..c673b58 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich, Antonio Quartulli
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -31,13 +29,14 @@
 
 #include <linux/crc16.h>
 
-static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
-			  struct orig_node *orig_node);
-static void tt_purge(struct work_struct *work);
-static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry);
+static void batadv_send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
+				 struct orig_node *orig_node);
+static void batadv_tt_purge(struct work_struct *work);
+static void
+batadv_tt_global_del_orig_list(struct tt_global_entry *tt_global_entry);
 
 /* returns 1 if they are the same mac addr */
-static int compare_tt(const struct hlist_node *node, const void *data2)
+static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
 {
 	const void *data1 = container_of(node, struct tt_common_entry,
 					 hash_entry);
@@ -45,15 +44,15 @@ static int compare_tt(const struct hlist_node *node, const void *data2)
 	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
 }
 
-static void tt_start_timer(struct bat_priv *bat_priv)
+static void batadv_tt_start_timer(struct bat_priv *bat_priv)
 {
-	INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
-	queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
+	INIT_DELAYED_WORK(&bat_priv->tt_work, batadv_tt_purge);
+	queue_delayed_work(batadv_event_workqueue, &bat_priv->tt_work,
 			   msecs_to_jiffies(5000));
 }
 
-static struct tt_common_entry *tt_hash_find(struct hashtable_t *hash,
-					    const void *data)
+static struct tt_common_entry *batadv_tt_hash_find(struct hashtable_t *hash,
+						   const void *data)
 {
 	struct hlist_head *head;
 	struct hlist_node *node;
@@ -63,12 +62,12 @@ static struct tt_common_entry *tt_hash_find(struct hashtable_t *hash,
 	if (!hash)
 		return NULL;
 
-	index = choose_orig(data, hash->size);
+	index = batadv_choose_orig(data, hash->size);
 	head = &hash->table[index];
 
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) {
-		if (!compare_eth(tt_common_entry, data))
+		if (!batadv_compare_eth(tt_common_entry, data))
 			continue;
 
 		if (!atomic_inc_not_zero(&tt_common_entry->refcount))
@@ -82,26 +81,26 @@ static struct tt_common_entry *tt_hash_find(struct hashtable_t *hash,
 	return tt_common_entry_tmp;
 }
 
-static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
-						 const void *data)
+static struct tt_local_entry *
+batadv_tt_local_hash_find(struct bat_priv *bat_priv, const void *data)
 {
 	struct tt_common_entry *tt_common_entry;
 	struct tt_local_entry *tt_local_entry = NULL;
 
-	tt_common_entry = tt_hash_find(bat_priv->tt_local_hash, data);
+	tt_common_entry = batadv_tt_hash_find(bat_priv->tt_local_hash, data);
 	if (tt_common_entry)
 		tt_local_entry = container_of(tt_common_entry,
 					      struct tt_local_entry, common);
 	return tt_local_entry;
 }
 
-static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
-						   const void *data)
+static struct tt_global_entry *
+batadv_tt_global_hash_find(struct bat_priv *bat_priv, const void *data)
 {
 	struct tt_common_entry *tt_common_entry;
 	struct tt_global_entry *tt_global_entry = NULL;
 
-	tt_common_entry = tt_hash_find(bat_priv->tt_global_hash, data);
+	tt_common_entry = batadv_tt_hash_find(bat_priv->tt_global_hash, data);
 	if (tt_common_entry)
 		tt_global_entry = container_of(tt_common_entry,
 					       struct tt_global_entry, common);
@@ -109,13 +108,14 @@ static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
 
 }
 
-static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
+static void
+batadv_tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
 {
 	if (atomic_dec_and_test(&tt_local_entry->common.refcount))
 		kfree_rcu(tt_local_entry, common.rcu);
 }
 
-static void tt_global_entry_free_rcu(struct rcu_head *rcu)
+static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu)
 {
 	struct tt_common_entry *tt_common_entry;
 	struct tt_global_entry *tt_global_entry;
@@ -127,32 +127,35 @@ static void tt_global_entry_free_rcu(struct rcu_head *rcu)
 	kfree(tt_global_entry);
 }
 
-static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
+static void
+batadv_tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
 {
 	if (atomic_dec_and_test(&tt_global_entry->common.refcount)) {
-		tt_global_del_orig_list(tt_global_entry);
+		batadv_tt_global_del_orig_list(tt_global_entry);
 		call_rcu(&tt_global_entry->common.rcu,
-			 tt_global_entry_free_rcu);
+			 batadv_tt_global_entry_free_rcu);
 	}
 }
 
-static void tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
+static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
 {
 	struct tt_orig_list_entry *orig_entry;
 
 	orig_entry = container_of(rcu, struct tt_orig_list_entry, rcu);
-	atomic_dec(&orig_entry->orig_node->tt_size);
-	orig_node_free_ref(orig_entry->orig_node);
+	batadv_orig_node_free_ref(orig_entry->orig_node);
 	kfree(orig_entry);
 }
 
-static void tt_orig_list_entry_free_ref(struct tt_orig_list_entry *orig_entry)
+static void
+batadv_tt_orig_list_entry_free_ref(struct tt_orig_list_entry *orig_entry)
 {
-	call_rcu(&orig_entry->rcu, tt_orig_list_entry_free_rcu);
+	/* to avoid race conditions, immediately decrease the tt counter */
+	atomic_dec(&orig_entry->orig_node->tt_size);
+	call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
 }
 
-static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
-			   uint8_t flags)
+static void batadv_tt_local_event(struct bat_priv *bat_priv,
+				  const uint8_t *addr, uint8_t flags)
 {
 	struct tt_change_node *tt_change_node;
 
@@ -173,26 +176,26 @@ static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
 	atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
 }
 
-int tt_len(int changes_num)
+int batadv_tt_len(int changes_num)
 {
 	return changes_num * sizeof(struct tt_change);
 }
 
-static int tt_local_init(struct bat_priv *bat_priv)
+static int batadv_tt_local_init(struct bat_priv *bat_priv)
 {
 	if (bat_priv->tt_local_hash)
-		return 1;
+		return 0;
 
-	bat_priv->tt_local_hash = hash_new(1024);
+	bat_priv->tt_local_hash = batadv_hash_new(1024);
 
 	if (!bat_priv->tt_local_hash)
-		return 0;
+		return -ENOMEM;
 
-	return 1;
+	return 0;
 }
 
-void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
-		  int ifindex)
+void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
+			 int ifindex)
 {
 	struct bat_priv *bat_priv = netdev_priv(soft_iface);
 	struct tt_local_entry *tt_local_entry = NULL;
@@ -202,7 +205,7 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 	struct tt_orig_list_entry *orig_entry;
 	int hash_added;
 
-	tt_local_entry = tt_local_hash_find(bat_priv, addr);
+	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
 
 	if (tt_local_entry) {
 		tt_local_entry->last_seen = jiffies;
@@ -215,40 +218,42 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 	if (!tt_local_entry)
 		goto out;
 
-	bat_dbg(DBG_TT, bat_priv,
-		"Creating new local tt entry: %pM (ttvn: %d)\n", addr,
-		(uint8_t)atomic_read(&bat_priv->ttvn));
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
+		   (uint8_t)atomic_read(&bat_priv->ttvn));
 
 	memcpy(tt_local_entry->common.addr, addr, ETH_ALEN);
 	tt_local_entry->common.flags = NO_FLAGS;
-	if (is_wifi_iface(ifindex))
+	if (batadv_is_wifi_iface(ifindex))
 		tt_local_entry->common.flags |= TT_CLIENT_WIFI;
 	atomic_set(&tt_local_entry->common.refcount, 2);
 	tt_local_entry->last_seen = jiffies;
 
 	/* the batman interface mac address should never be purged */
-	if (compare_eth(addr, soft_iface->dev_addr))
+	if (batadv_compare_eth(addr, soft_iface->dev_addr))
 		tt_local_entry->common.flags |= TT_CLIENT_NOPURGE;
 
 	/* The local entry has to be marked as NEW to avoid to send it in
 	 * a full table response going out before the next ttvn increment
-	 * (consistency check) */
+	 * (consistency check)
+	 */
 	tt_local_entry->common.flags |= TT_CLIENT_NEW;
 
-	hash_added = hash_add(bat_priv->tt_local_hash, compare_tt, choose_orig,
-			 &tt_local_entry->common,
-			 &tt_local_entry->common.hash_entry);
+	hash_added = batadv_hash_add(bat_priv->tt_local_hash, batadv_compare_tt,
+				     batadv_choose_orig,
+				     &tt_local_entry->common,
+				     &tt_local_entry->common.hash_entry);
 
 	if (unlikely(hash_added != 0)) {
 		/* remove the reference for the hash */
-		tt_local_entry_free_ref(tt_local_entry);
+		batadv_tt_local_entry_free_ref(tt_local_entry);
 		goto out;
 	}
 
-	tt_local_event(bat_priv, addr, tt_local_entry->common.flags);
+	batadv_tt_local_event(bat_priv, addr, tt_local_entry->common.flags);
 
 	/* remove address from global hash if present */
-	tt_global_entry = tt_global_hash_find(bat_priv, addr);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
 
 	/* Check whether it is a roaming! */
 	if (tt_global_entry) {
@@ -258,8 +263,9 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 		hlist_for_each_entry_rcu(orig_entry, node, head, list) {
 			orig_entry->orig_node->tt_poss_change = true;
 
-			send_roam_adv(bat_priv, tt_global_entry->common.addr,
-				      orig_entry->orig_node);
+			batadv_send_roam_adv(bat_priv,
+					     tt_global_entry->common.addr,
+					     orig_entry->orig_node);
 		}
 		rcu_read_unlock();
 		/* The global entry has to be marked as ROAMING and
@@ -270,19 +276,72 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 	}
 out:
 	if (tt_local_entry)
-		tt_local_entry_free_ref(tt_local_entry);
+		batadv_tt_local_entry_free_ref(tt_local_entry);
 	if (tt_global_entry)
-		tt_global_entry_free_ref(tt_global_entry);
+		batadv_tt_global_entry_free_ref(tt_global_entry);
+}
+
+static void batadv_tt_realloc_packet_buff(unsigned char **packet_buff,
+					  int *packet_buff_len,
+					  int min_packet_len,
+					  int new_packet_len)
+{
+	unsigned char *new_buff;
+
+	new_buff = kmalloc(new_packet_len, GFP_ATOMIC);
+
+	/* keep old buffer if kmalloc should fail */
+	if (new_buff) {
+		memcpy(new_buff, *packet_buff, min_packet_len);
+		kfree(*packet_buff);
+		*packet_buff = new_buff;
+		*packet_buff_len = new_packet_len;
+	}
 }
 
-int tt_changes_fill_buffer(struct bat_priv *bat_priv,
-			   unsigned char *buff, int buff_len)
+static void batadv_tt_prepare_packet_buff(struct bat_priv *bat_priv,
+					  unsigned char **packet_buff,
+					  int *packet_buff_len,
+					  int min_packet_len)
+{
+	struct hard_iface *primary_if;
+	int req_len;
+
+	primary_if = batadv_primary_if_get_selected(bat_priv);
+
+	req_len = min_packet_len;
+	req_len += batadv_tt_len(atomic_read(&bat_priv->tt_local_changes));
+
+	/* if we have too many changes for one packet don't send any
+	 * and wait for the tt table request which will be fragmented
+	 */
+	if ((!primary_if) || (req_len > primary_if->soft_iface->mtu))
+		req_len = min_packet_len;
+
+	batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len,
+				      min_packet_len, req_len);
+
+	if (primary_if)
+		batadv_hardif_free_ref(primary_if);
+}
+
+static int batadv_tt_changes_fill_buff(struct bat_priv *bat_priv,
+				       unsigned char **packet_buff,
+				       int *packet_buff_len,
+				       int min_packet_len)
 {
-	int count = 0, tot_changes = 0;
 	struct tt_change_node *entry, *safe;
+	int count = 0, tot_changes = 0, new_len;
+	unsigned char *tt_buff;
 
-	if (buff_len > 0)
-		tot_changes = buff_len / tt_len(1);
+	batadv_tt_prepare_packet_buff(bat_priv, packet_buff,
+				      packet_buff_len, min_packet_len);
+
+	new_len = *packet_buff_len - min_packet_len;
+	tt_buff = *packet_buff + min_packet_len;
+
+	if (new_len > 0)
+		tot_changes = new_len / batadv_tt_len(1);
 
 	spin_lock_bh(&bat_priv->tt_changes_list_lock);
 	atomic_set(&bat_priv->tt_local_changes, 0);
@@ -290,7 +349,7 @@ int tt_changes_fill_buffer(struct bat_priv *bat_priv,
 	list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
 				 list) {
 		if (count < tot_changes) {
-			memcpy(buff + tt_len(count),
+			memcpy(tt_buff + batadv_tt_len(count),
 			       &entry->change, sizeof(struct tt_change));
 			count++;
 		}
@@ -304,25 +363,23 @@ int tt_changes_fill_buffer(struct bat_priv *bat_priv,
 	kfree(bat_priv->tt_buff);
 	bat_priv->tt_buff_len = 0;
 	bat_priv->tt_buff = NULL;
-	/* We check whether this new OGM has no changes due to size
-	 * problems */
-	if (buff_len > 0) {
-		/**
-		 * if kmalloc() fails we will reply with the full table
+	/* check whether this new OGM has no changes due to size problems */
+	if (new_len > 0) {
+		/* if kmalloc() fails we will reply with the full table
 		 * instead of providing the diff
 		 */
-		bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
+		bat_priv->tt_buff = kmalloc(new_len, GFP_ATOMIC);
 		if (bat_priv->tt_buff) {
-			memcpy(bat_priv->tt_buff, buff, buff_len);
-			bat_priv->tt_buff_len = buff_len;
+			memcpy(bat_priv->tt_buff, tt_buff, new_len);
+			bat_priv->tt_buff_len = new_len;
 		}
 	}
 	spin_unlock_bh(&bat_priv->tt_buff_lock);
 
-	return tot_changes;
+	return count;
 }
 
-int tt_local_seq_print_text(struct seq_file *seq, void *offset)
+int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
 {
 	struct net_device *net_dev = (struct net_device *)seq->private;
 	struct bat_priv *bat_priv = netdev_priv(net_dev);
@@ -334,7 +391,7 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
 	uint32_t i;
 	int ret = 0;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if) {
 		ret = seq_printf(seq,
 				 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
@@ -376,44 +433,46 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
 	}
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	return ret;
 }
 
-static void tt_local_set_pending(struct bat_priv *bat_priv,
-				 struct tt_local_entry *tt_local_entry,
-				 uint16_t flags, const char *message)
+static void batadv_tt_local_set_pending(struct bat_priv *bat_priv,
+					struct tt_local_entry *tt_local_entry,
+					uint16_t flags, const char *message)
 {
-	tt_local_event(bat_priv, tt_local_entry->common.addr,
-		       tt_local_entry->common.flags | flags);
+	batadv_tt_local_event(bat_priv, tt_local_entry->common.addr,
+			      tt_local_entry->common.flags | flags);
 
 	/* The local client has to be marked as "pending to be removed" but has
 	 * to be kept in the table in order to send it in a full table
-	 * response issued before the net ttvn increment (consistency check) */
+	 * response issued before the net ttvn increment (consistency check)
+	 */
 	tt_local_entry->common.flags |= TT_CLIENT_PENDING;
 
-	bat_dbg(DBG_TT, bat_priv,
-		"Local tt entry (%pM) pending to be removed: %s\n",
-		tt_local_entry->common.addr, message);
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Local tt entry (%pM) pending to be removed: %s\n",
+		   tt_local_entry->common.addr, message);
 }
 
-void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
-		     const char *message, bool roaming)
+void batadv_tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
+			    const char *message, bool roaming)
 {
 	struct tt_local_entry *tt_local_entry = NULL;
 
-	tt_local_entry = tt_local_hash_find(bat_priv, addr);
+	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
 	if (!tt_local_entry)
 		goto out;
 
-	tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
-			     (roaming ? TT_CLIENT_ROAM : NO_FLAGS), message);
+	batadv_tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
+				    (roaming ? TT_CLIENT_ROAM : NO_FLAGS),
+				    message);
 out:
 	if (tt_local_entry)
-		tt_local_entry_free_ref(tt_local_entry);
+		batadv_tt_local_entry_free_ref(tt_local_entry);
 }
 
-static void tt_local_purge(struct bat_priv *bat_priv)
+static void batadv_tt_local_purge(struct bat_priv *bat_priv)
 {
 	struct hashtable_t *hash = bat_priv->tt_local_hash;
 	struct tt_local_entry *tt_local_entry;
@@ -440,19 +499,19 @@ static void tt_local_purge(struct bat_priv *bat_priv)
 			if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
 				continue;
 
-			if (!has_timed_out(tt_local_entry->last_seen,
-					   TT_LOCAL_TIMEOUT))
+			if (!batadv_has_timed_out(tt_local_entry->last_seen,
+						  TT_LOCAL_TIMEOUT))
 				continue;
 
-			tt_local_set_pending(bat_priv, tt_local_entry,
-					     TT_CLIENT_DEL, "timed out");
+			batadv_tt_local_set_pending(bat_priv, tt_local_entry,
+						    TT_CLIENT_DEL, "timed out");
 		}
 		spin_unlock_bh(list_lock);
 	}
 
 }
 
-static void tt_local_table_free(struct bat_priv *bat_priv)
+static void batadv_tt_local_table_free(struct bat_priv *bat_priv)
 {
 	struct hashtable_t *hash;
 	spinlock_t *list_lock; /* protects write access to the hash lists */
@@ -478,30 +537,30 @@ static void tt_local_table_free(struct bat_priv *bat_priv)
 			tt_local_entry = container_of(tt_common_entry,
 						      struct tt_local_entry,
 						      common);
-			tt_local_entry_free_ref(tt_local_entry);
+			batadv_tt_local_entry_free_ref(tt_local_entry);
 		}
 		spin_unlock_bh(list_lock);
 	}
 
-	hash_destroy(hash);
+	batadv_hash_destroy(hash);
 
 	bat_priv->tt_local_hash = NULL;
 }
 
-static int tt_global_init(struct bat_priv *bat_priv)
+static int batadv_tt_global_init(struct bat_priv *bat_priv)
 {
 	if (bat_priv->tt_global_hash)
-		return 1;
+		return 0;
 
-	bat_priv->tt_global_hash = hash_new(1024);
+	bat_priv->tt_global_hash = batadv_hash_new(1024);
 
 	if (!bat_priv->tt_global_hash)
-		return 0;
+		return -ENOMEM;
 
-	return 1;
+	return 0;
 }
 
-static void tt_changes_list_free(struct bat_priv *bat_priv)
+static void batadv_tt_changes_list_free(struct bat_priv *bat_priv)
 {
 	struct tt_change_node *entry, *safe;
 
@@ -520,8 +579,8 @@ static void tt_changes_list_free(struct bat_priv *bat_priv)
 /* find out if an orig_node is already in the list of a tt_global_entry.
  * returns 1 if found, 0 otherwise
  */
-static bool tt_global_entry_has_orig(const struct tt_global_entry *entry,
-				     const struct orig_node *orig_node)
+static bool batadv_tt_global_entry_has_orig(const struct tt_global_entry *entry,
+					    const struct orig_node *orig_node)
 {
 	struct tt_orig_list_entry *tmp_orig_entry;
 	const struct hlist_head *head;
@@ -540,9 +599,9 @@ static bool tt_global_entry_has_orig(const struct tt_global_entry *entry,
 	return found;
 }
 
-static void tt_global_add_orig_entry(struct tt_global_entry *tt_global_entry,
-				     struct orig_node *orig_node,
-				     int ttvn)
+static void
+batadv_tt_global_add_orig_entry(struct tt_global_entry *tt_global_entry,
+				struct orig_node *orig_node, int ttvn)
 {
 	struct tt_orig_list_entry *orig_entry;
 
@@ -563,15 +622,16 @@ static void tt_global_add_orig_entry(struct tt_global_entry *tt_global_entry,
 }
 
 /* caller must hold orig_node refcount */
-int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
-		  const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
-		  bool wifi)
+int batadv_tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
+			 const unsigned char *tt_addr, uint8_t ttvn,
+			 bool roaming, bool wifi)
 {
 	struct tt_global_entry *tt_global_entry = NULL;
 	int ret = 0;
 	int hash_added;
+	struct tt_common_entry *common;
 
-	tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr);
 
 	if (!tt_global_entry) {
 		tt_global_entry = kzalloc(sizeof(*tt_global_entry),
@@ -579,26 +639,29 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
 		if (!tt_global_entry)
 			goto out;
 
-		memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN);
+		common = &tt_global_entry->common;
+		memcpy(common->addr, tt_addr, ETH_ALEN);
 
-		tt_global_entry->common.flags = NO_FLAGS;
+		common->flags = NO_FLAGS;
 		tt_global_entry->roam_at = 0;
-		atomic_set(&tt_global_entry->common.refcount, 2);
+		atomic_set(&common->refcount, 2);
 
 		INIT_HLIST_HEAD(&tt_global_entry->orig_list);
 		spin_lock_init(&tt_global_entry->list_lock);
 
-		hash_added = hash_add(bat_priv->tt_global_hash, compare_tt,
-				 choose_orig, &tt_global_entry->common,
-				 &tt_global_entry->common.hash_entry);
+		hash_added = batadv_hash_add(bat_priv->tt_global_hash,
+					     batadv_compare_tt,
+					     batadv_choose_orig, common,
+					     &common->hash_entry);
 
 		if (unlikely(hash_added != 0)) {
 			/* remove the reference for the hash */
-			tt_global_entry_free_ref(tt_global_entry);
+			batadv_tt_global_entry_free_ref(tt_global_entry);
 			goto out_remove;
 		}
 
-		tt_global_add_orig_entry(tt_global_entry, orig_node, ttvn);
+		batadv_tt_global_add_orig_entry(tt_global_entry, orig_node,
+						ttvn);
 	} else {
 		/* there is already a global entry, use this one. */
 
@@ -610,39 +673,41 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
 		 * new one.
 		 */
 		if (tt_global_entry->common.flags & TT_CLIENT_ROAM) {
-			tt_global_del_orig_list(tt_global_entry);
+			batadv_tt_global_del_orig_list(tt_global_entry);
 			tt_global_entry->common.flags &= ~TT_CLIENT_ROAM;
 			tt_global_entry->roam_at = 0;
 		}
 
-		if (!tt_global_entry_has_orig(tt_global_entry, orig_node))
-			tt_global_add_orig_entry(tt_global_entry, orig_node,
-						 ttvn);
+		if (!batadv_tt_global_entry_has_orig(tt_global_entry,
+						     orig_node))
+			batadv_tt_global_add_orig_entry(tt_global_entry,
+							orig_node, ttvn);
 	}
 
 	if (wifi)
 		tt_global_entry->common.flags |= TT_CLIENT_WIFI;
 
-	bat_dbg(DBG_TT, bat_priv,
-		"Creating new global tt entry: %pM (via %pM)\n",
-		tt_global_entry->common.addr, orig_node->orig);
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Creating new global tt entry: %pM (via %pM)\n",
+		   tt_global_entry->common.addr, orig_node->orig);
 
 out_remove:
 	/* remove address from local hash if present */
-	tt_local_remove(bat_priv, tt_global_entry->common.addr,
-			"global tt received", roaming);
+	batadv_tt_local_remove(bat_priv, tt_global_entry->common.addr,
+			       "global tt received", roaming);
 	ret = 1;
 out:
 	if (tt_global_entry)
-		tt_global_entry_free_ref(tt_global_entry);
+		batadv_tt_global_entry_free_ref(tt_global_entry);
 	return ret;
 }
 
 /* print all orig nodes who announce the address for this global entry.
  * it is assumed that the caller holds rcu_read_lock();
  */
-static void tt_global_print_entry(struct tt_global_entry *tt_global_entry,
-				  struct seq_file *seq)
+static void
+batadv_tt_global_print_entry(struct tt_global_entry *tt_global_entry,
+			     struct seq_file *seq)
 {
 	struct hlist_head *head;
 	struct hlist_node *node;
@@ -666,7 +731,7 @@ static void tt_global_print_entry(struct tt_global_entry *tt_global_entry,
 	}
 }
 
-int tt_global_seq_print_text(struct seq_file *seq, void *offset)
+int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset)
 {
 	struct net_device *net_dev = (struct net_device *)seq->private;
 	struct bat_priv *bat_priv = netdev_priv(net_dev);
@@ -679,7 +744,7 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
 	uint32_t i;
 	int ret = 0;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if) {
 		ret = seq_printf(seq,
 				 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
@@ -709,18 +774,19 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
 			tt_global_entry = container_of(tt_common_entry,
 						       struct tt_global_entry,
 						       common);
-			tt_global_print_entry(tt_global_entry, seq);
+			batadv_tt_global_print_entry(tt_global_entry, seq);
 		}
 		rcu_read_unlock();
 	}
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	return ret;
 }
 
 /* deletes the orig list of a tt_global_entry */
-static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry)
+static void
+batadv_tt_global_del_orig_list(struct tt_global_entry *tt_global_entry)
 {
 	struct hlist_head *head;
 	struct hlist_node *node, *safe;
@@ -730,16 +796,17 @@ static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry)
 	head = &tt_global_entry->orig_list;
 	hlist_for_each_entry_safe(orig_entry, node, safe, head, list) {
 		hlist_del_rcu(node);
-		tt_orig_list_entry_free_ref(orig_entry);
+		batadv_tt_orig_list_entry_free_ref(orig_entry);
 	}
 	spin_unlock_bh(&tt_global_entry->list_lock);
 
 }
 
-static void tt_global_del_orig_entry(struct bat_priv *bat_priv,
-				     struct tt_global_entry *tt_global_entry,
-				     struct orig_node *orig_node,
-				     const char *message)
+static void
+batadv_tt_global_del_orig_entry(struct bat_priv *bat_priv,
+				struct tt_global_entry *tt_global_entry,
+				struct orig_node *orig_node,
+				const char *message)
 {
 	struct hlist_head *head;
 	struct hlist_node *node, *safe;
@@ -749,28 +816,27 @@ static void tt_global_del_orig_entry(struct bat_priv *bat_priv,
 	head = &tt_global_entry->orig_list;
 	hlist_for_each_entry_safe(orig_entry, node, safe, head, list) {
 		if (orig_entry->orig_node == orig_node) {
-			bat_dbg(DBG_TT, bat_priv,
-				"Deleting %pM from global tt entry %pM: %s\n",
-				orig_node->orig, tt_global_entry->common.addr,
-				message);
+			batadv_dbg(DBG_TT, bat_priv,
+				   "Deleting %pM from global tt entry %pM: %s\n",
+				   orig_node->orig,
+				   tt_global_entry->common.addr, message);
 			hlist_del_rcu(node);
-			tt_orig_list_entry_free_ref(orig_entry);
+			batadv_tt_orig_list_entry_free_ref(orig_entry);
 		}
 	}
 	spin_unlock_bh(&tt_global_entry->list_lock);
 }
 
-static void tt_global_del_struct(struct bat_priv *bat_priv,
-				 struct tt_global_entry *tt_global_entry,
-				 const char *message)
+static void batadv_tt_global_del_struct(struct bat_priv *bat_priv,
+					struct tt_global_entry *tt_global_entry,
+					const char *message)
 {
-	bat_dbg(DBG_TT, bat_priv,
-		"Deleting global tt entry %pM: %s\n",
-		tt_global_entry->common.addr, message);
+	batadv_dbg(DBG_TT, bat_priv, "Deleting global tt entry %pM: %s\n",
+		   tt_global_entry->common.addr, message);
 
-	hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig,
-		    tt_global_entry->common.addr);
-	tt_global_entry_free_ref(tt_global_entry);
+	batadv_hash_remove(bat_priv->tt_global_hash, batadv_compare_tt,
+			   batadv_choose_orig, tt_global_entry->common.addr);
+	batadv_tt_global_entry_free_ref(tt_global_entry);
 
 }
 
@@ -778,10 +844,10 @@ static void tt_global_del_struct(struct bat_priv *bat_priv,
  * within tt_global entry. If yes, we set the TT_CLIENT_ROAM flag and the timer,
  * otherwise we simply remove the originator scheduled for deletion.
  */
-static void tt_global_del_roaming(struct bat_priv *bat_priv,
-				  struct tt_global_entry *tt_global_entry,
-				  struct orig_node *orig_node,
-				  const char *message)
+static void
+batadv_tt_global_del_roaming(struct bat_priv *bat_priv,
+			     struct tt_global_entry *tt_global_entry,
+			     struct orig_node *orig_node, const char *message)
 {
 	bool last_entry = true;
 	struct hlist_head *head;
@@ -810,31 +876,31 @@ static void tt_global_del_roaming(struct bat_priv *bat_priv,
 		/* there is another entry, we can simply delete this
 		 * one and can still use the other one.
 		 */
-		tt_global_del_orig_entry(bat_priv, tt_global_entry,
-					 orig_node, message);
+		batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry,
+						orig_node, message);
 }
 
 
 
-static void tt_global_del(struct bat_priv *bat_priv,
-			  struct orig_node *orig_node,
-			  const unsigned char *addr,
-			  const char *message, bool roaming)
+static void batadv_tt_global_del(struct bat_priv *bat_priv,
+				 struct orig_node *orig_node,
+				 const unsigned char *addr,
+				 const char *message, bool roaming)
 {
 	struct tt_global_entry *tt_global_entry = NULL;
-	struct tt_local_entry *tt_local_entry = NULL;
+	struct tt_local_entry *local_entry = NULL;
 
-	tt_global_entry = tt_global_hash_find(bat_priv, addr);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
 	if (!tt_global_entry)
 		goto out;
 
 	if (!roaming) {
-		tt_global_del_orig_entry(bat_priv, tt_global_entry, orig_node,
-					 message);
+		batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry,
+						orig_node, message);
 
 		if (hlist_empty(&tt_global_entry->orig_list))
-			tt_global_del_struct(bat_priv, tt_global_entry,
-					     message);
+			batadv_tt_global_del_struct(bat_priv, tt_global_entry,
+						    message);
 
 		goto out;
 	}
@@ -850,31 +916,31 @@ static void tt_global_del(struct bat_priv *bat_priv,
 	 *    If there are other originators left, we directly delete
 	 *    the originator.
 	 * 2) the client roamed to us => we can directly delete
-	 *    the global entry, since it is useless now. */
-
-	tt_local_entry = tt_local_hash_find(bat_priv,
-					    tt_global_entry->common.addr);
-	if (tt_local_entry) {
+	 *    the global entry, since it is useless now.
+	 */
+	local_entry = batadv_tt_local_hash_find(bat_priv,
+						tt_global_entry->common.addr);
+	if (local_entry) {
 		/* local entry exists, case 2: client roamed to us. */
-		tt_global_del_orig_list(tt_global_entry);
-		tt_global_del_struct(bat_priv, tt_global_entry, message);
+		batadv_tt_global_del_orig_list(tt_global_entry);
+		batadv_tt_global_del_struct(bat_priv, tt_global_entry, message);
 	} else
 		/* no local entry exists, case 1: check for roaming */
-		tt_global_del_roaming(bat_priv, tt_global_entry, orig_node,
-				      message);
+		batadv_tt_global_del_roaming(bat_priv, tt_global_entry,
+					     orig_node, message);
 
 
 out:
 	if (tt_global_entry)
-		tt_global_entry_free_ref(tt_global_entry);
-	if (tt_local_entry)
-		tt_local_entry_free_ref(tt_local_entry);
+		batadv_tt_global_entry_free_ref(tt_global_entry);
+	if (local_entry)
+		batadv_tt_local_entry_free_ref(local_entry);
 }
 
-void tt_global_del_orig(struct bat_priv *bat_priv,
-			struct orig_node *orig_node, const char *message)
+void batadv_tt_global_del_orig(struct bat_priv *bat_priv,
+			       struct orig_node *orig_node, const char *message)
 {
-	struct tt_global_entry *tt_global_entry;
+	struct tt_global_entry *global_entry;
 	struct tt_common_entry *tt_common_entry;
 	uint32_t i;
 	struct hashtable_t *hash = bat_priv->tt_global_hash;
@@ -892,29 +958,27 @@ void tt_global_del_orig(struct bat_priv *bat_priv,
 		spin_lock_bh(list_lock);
 		hlist_for_each_entry_safe(tt_common_entry, node, safe,
 					  head, hash_entry) {
-			tt_global_entry = container_of(tt_common_entry,
-						       struct tt_global_entry,
-						       common);
+			global_entry = container_of(tt_common_entry,
+						    struct tt_global_entry,
+						    common);
 
-			tt_global_del_orig_entry(bat_priv, tt_global_entry,
-						 orig_node, message);
+			batadv_tt_global_del_orig_entry(bat_priv, global_entry,
+							orig_node, message);
 
-			if (hlist_empty(&tt_global_entry->orig_list)) {
-				bat_dbg(DBG_TT, bat_priv,
-					"Deleting global tt entry %pM: %s\n",
-					tt_global_entry->common.addr,
-					message);
+			if (hlist_empty(&global_entry->orig_list)) {
+				batadv_dbg(DBG_TT, bat_priv,
+					   "Deleting global tt entry %pM: %s\n",
+					   global_entry->common.addr, message);
 				hlist_del_rcu(node);
-				tt_global_entry_free_ref(tt_global_entry);
+				batadv_tt_global_entry_free_ref(global_entry);
 			}
 		}
 		spin_unlock_bh(list_lock);
 	}
-	atomic_set(&orig_node->tt_size, 0);
 	orig_node->tt_initialised = false;
 }
 
-static void tt_global_roam_purge(struct bat_priv *bat_priv)
+static void batadv_tt_global_roam_purge(struct bat_priv *bat_priv)
 {
 	struct hashtable_t *hash = bat_priv->tt_global_hash;
 	struct tt_common_entry *tt_common_entry;
@@ -936,23 +1000,23 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv)
 						       common);
 			if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM))
 				continue;
-			if (!has_timed_out(tt_global_entry->roam_at,
-					   TT_CLIENT_ROAM_TIMEOUT))
+			if (!batadv_has_timed_out(tt_global_entry->roam_at,
+						  TT_CLIENT_ROAM_TIMEOUT))
 				continue;
 
-			bat_dbg(DBG_TT, bat_priv,
-				"Deleting global tt entry (%pM): Roaming timeout\n",
-				tt_global_entry->common.addr);
+			batadv_dbg(DBG_TT, bat_priv,
+				   "Deleting global tt entry (%pM): Roaming timeout\n",
+				   tt_global_entry->common.addr);
 
 			hlist_del_rcu(node);
-			tt_global_entry_free_ref(tt_global_entry);
+			batadv_tt_global_entry_free_ref(tt_global_entry);
 		}
 		spin_unlock_bh(list_lock);
 	}
 
 }
 
-static void tt_global_table_free(struct bat_priv *bat_priv)
+static void batadv_tt_global_table_free(struct bat_priv *bat_priv)
 {
 	struct hashtable_t *hash;
 	spinlock_t *list_lock; /* protects write access to the hash lists */
@@ -978,18 +1042,18 @@ static void tt_global_table_free(struct bat_priv *bat_priv)
 			tt_global_entry = container_of(tt_common_entry,
 						       struct tt_global_entry,
 						       common);
-			tt_global_entry_free_ref(tt_global_entry);
+			batadv_tt_global_entry_free_ref(tt_global_entry);
 		}
 		spin_unlock_bh(list_lock);
 	}
 
-	hash_destroy(hash);
+	batadv_hash_destroy(hash);
 
 	bat_priv->tt_global_hash = NULL;
 }
 
-static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
-			    struct tt_global_entry *tt_global_entry)
+static bool _batadv_is_ap_isolated(struct tt_local_entry *tt_local_entry,
+				   struct tt_global_entry *tt_global_entry)
 {
 	bool ret = false;
 
@@ -1000,8 +1064,9 @@ static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
 	return ret;
 }
 
-struct orig_node *transtable_search(struct bat_priv *bat_priv,
-				    const uint8_t *src, const uint8_t *addr)
+struct orig_node *batadv_transtable_search(struct bat_priv *bat_priv,
+					   const uint8_t *src,
+					   const uint8_t *addr)
 {
 	struct tt_local_entry *tt_local_entry = NULL;
 	struct tt_global_entry *tt_global_entry = NULL;
@@ -1013,18 +1078,20 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv,
 	int best_tq;
 
 	if (src && atomic_read(&bat_priv->ap_isolation)) {
-		tt_local_entry = tt_local_hash_find(bat_priv, src);
+		tt_local_entry = batadv_tt_local_hash_find(bat_priv, src);
 		if (!tt_local_entry)
 			goto out;
 	}
 
-	tt_global_entry = tt_global_hash_find(bat_priv, addr);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
 	if (!tt_global_entry)
 		goto out;
 
 	/* check whether the clients should not communicate due to AP
-	 * isolation */
-	if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
+	 * isolation
+	 */
+	if (tt_local_entry &&
+	    _batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
 		goto out;
 
 	best_tq = 0;
@@ -1032,7 +1099,7 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv,
 	rcu_read_lock();
 	head = &tt_global_entry->orig_list;
 	hlist_for_each_entry_rcu(orig_entry, node, head, list) {
-		router = orig_node_get_router(orig_entry->orig_node);
+		router = batadv_orig_node_get_router(orig_entry->orig_node);
 		if (!router)
 			continue;
 
@@ -1040,7 +1107,7 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv,
 			orig_node = orig_entry->orig_node;
 			best_tq = router->tq_avg;
 		}
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 	}
 	/* found anything? */
 	if (orig_node && !atomic_inc_not_zero(&orig_node->refcount))
@@ -1048,16 +1115,16 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv,
 	rcu_read_unlock();
 out:
 	if (tt_global_entry)
-		tt_global_entry_free_ref(tt_global_entry);
+		batadv_tt_global_entry_free_ref(tt_global_entry);
 	if (tt_local_entry)
-		tt_local_entry_free_ref(tt_local_entry);
+		batadv_tt_local_entry_free_ref(tt_local_entry);
 
 	return orig_node;
 }
 
 /* Calculates the checksum of the local table of a given orig_node */
-static uint16_t tt_global_crc(struct bat_priv *bat_priv,
-			      struct orig_node *orig_node)
+static uint16_t batadv_tt_global_crc(struct bat_priv *bat_priv,
+				     struct orig_node *orig_node)
 {
 	uint16_t total = 0, total_one;
 	struct hashtable_t *hash = bat_priv->tt_global_hash;
@@ -1088,8 +1155,8 @@ static uint16_t tt_global_crc(struct bat_priv *bat_priv,
 			/* find out if this global entry is announced by this
 			 * originator
 			 */
-			if (!tt_global_entry_has_orig(tt_global_entry,
-						      orig_node))
+			if (!batadv_tt_global_entry_has_orig(tt_global_entry,
+							     orig_node))
 				continue;
 
 			total_one = 0;
@@ -1105,7 +1172,7 @@ static uint16_t tt_global_crc(struct bat_priv *bat_priv,
 }
 
 /* Calculates the checksum of the local table */
-uint16_t tt_local_crc(struct bat_priv *bat_priv)
+static uint16_t batadv_tt_local_crc(struct bat_priv *bat_priv)
 {
 	uint16_t total = 0, total_one;
 	struct hashtable_t *hash = bat_priv->tt_local_hash;
@@ -1122,7 +1189,8 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv)
 		hlist_for_each_entry_rcu(tt_common_entry, node,
 					 head, hash_entry) {
 			/* not yet committed clients have not to be taken into
-			 * account while computing the CRC */
+			 * account while computing the CRC
+			 */
 			if (tt_common_entry->flags & TT_CLIENT_NEW)
 				continue;
 			total_one = 0;
@@ -1137,7 +1205,7 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv)
 	return total;
 }
 
-static void tt_req_list_free(struct bat_priv *bat_priv)
+static void batadv_tt_req_list_free(struct bat_priv *bat_priv)
 {
 	struct tt_req_node *node, *safe;
 
@@ -1151,15 +1219,16 @@ static void tt_req_list_free(struct bat_priv *bat_priv)
 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
 }
 
-static void tt_save_orig_buffer(struct bat_priv *bat_priv,
-				struct orig_node *orig_node,
-				const unsigned char *tt_buff,
-				uint8_t tt_num_changes)
+static void batadv_tt_save_orig_buffer(struct bat_priv *bat_priv,
+				       struct orig_node *orig_node,
+				       const unsigned char *tt_buff,
+				       uint8_t tt_num_changes)
 {
-	uint16_t tt_buff_len = tt_len(tt_num_changes);
+	uint16_t tt_buff_len = batadv_tt_len(tt_num_changes);
 
 	/* Replace the old buffer only if I received something in the
-	 * last OGM (the OGM could carry no changes) */
+	 * last OGM (the OGM could carry no changes)
+	 */
 	spin_lock_bh(&orig_node->tt_buff_lock);
 	if (tt_buff_len > 0) {
 		kfree(orig_node->tt_buff);
@@ -1173,13 +1242,13 @@ static void tt_save_orig_buffer(struct bat_priv *bat_priv,
 	spin_unlock_bh(&orig_node->tt_buff_lock);
 }
 
-static void tt_req_purge(struct bat_priv *bat_priv)
+static void batadv_tt_req_purge(struct bat_priv *bat_priv)
 {
 	struct tt_req_node *node, *safe;
 
 	spin_lock_bh(&bat_priv->tt_req_list_lock);
 	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
-		if (has_timed_out(node->issued_at, TT_REQUEST_TIMEOUT)) {
+		if (batadv_has_timed_out(node->issued_at, TT_REQUEST_TIMEOUT)) {
 			list_del(&node->list);
 			kfree(node);
 		}
@@ -1188,17 +1257,18 @@ static void tt_req_purge(struct bat_priv *bat_priv)
 }
 
 /* returns the pointer to the new tt_req_node struct if no request
- * has already been issued for this orig_node, NULL otherwise */
-static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
-					  struct orig_node *orig_node)
+ * has already been issued for this orig_node, NULL otherwise
+ */
+static struct tt_req_node *batadv_new_tt_req_node(struct bat_priv *bat_priv,
+						  struct orig_node *orig_node)
 {
 	struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
 
 	spin_lock_bh(&bat_priv->tt_req_list_lock);
 	list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
-		if (compare_eth(tt_req_node_tmp, orig_node) &&
-		    !has_timed_out(tt_req_node_tmp->issued_at,
-				   TT_REQUEST_TIMEOUT))
+		if (batadv_compare_eth(tt_req_node_tmp, orig_node) &&
+		    !batadv_has_timed_out(tt_req_node_tmp->issued_at,
+					  TT_REQUEST_TIMEOUT))
 			goto unlock;
 	}
 
@@ -1216,7 +1286,8 @@ unlock:
 }
 
 /* data_ptr is useless here, but has to be kept to respect the prototype */
-static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
+static int batadv_tt_local_valid_entry(const void *entry_ptr,
+				       const void *data_ptr)
 {
 	const struct tt_common_entry *tt_common_entry = entry_ptr;
 
@@ -1225,7 +1296,8 @@ static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
 	return 1;
 }
 
-static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
+static int batadv_tt_global_valid(const void *entry_ptr,
+				  const void *data_ptr)
 {
 	const struct tt_common_entry *tt_common_entry = entry_ptr;
 	const struct tt_global_entry *tt_global_entry;
@@ -1237,15 +1309,15 @@ static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
 	tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
 				       common);
 
-	return tt_global_entry_has_orig(tt_global_entry, orig_node);
+	return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node);
 }
 
-static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
-					      struct hashtable_t *hash,
-					      struct hard_iface *primary_if,
-					      int (*valid_cb)(const void *,
-							      const void *),
-					      void *cb_data)
+static struct sk_buff *
+batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
+			      struct hashtable_t *hash,
+			      struct hard_iface *primary_if,
+			      int (*valid_cb)(const void *, const void *),
+			      void *cb_data)
 {
 	struct tt_common_entry *tt_common_entry;
 	struct tt_query_packet *tt_response;
@@ -1298,16 +1370,18 @@ static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
 	rcu_read_unlock();
 
 	/* store in the message the number of entries we have successfully
-	 * copied */
+	 * copied
+	 */
 	tt_response->tt_data = htons(tt_count);
 
 out:
 	return skb;
 }
 
-static int send_tt_request(struct bat_priv *bat_priv,
-			   struct orig_node *dst_orig_node,
-			   uint8_t ttvn, uint16_t tt_crc, bool full_table)
+static int batadv_send_tt_request(struct bat_priv *bat_priv,
+				  struct orig_node *dst_orig_node,
+				  uint8_t ttvn, uint16_t tt_crc,
+				  bool full_table)
 {
 	struct sk_buff *skb = NULL;
 	struct tt_query_packet *tt_request;
@@ -1316,13 +1390,14 @@ static int send_tt_request(struct bat_priv *bat_priv,
 	struct tt_req_node *tt_req_node = NULL;
 	int ret = 1;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
 	/* The new tt_req will be issued only if I'm not waiting for a
-	 * reply from the same orig_node yet */
-	tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
+	 * reply from the same orig_node yet
+	 */
+	tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node);
 	if (!tt_req_node)
 		goto out;
 
@@ -1347,23 +1422,25 @@ static int send_tt_request(struct bat_priv *bat_priv,
 	if (full_table)
 		tt_request->flags |= TT_FULL_TABLE;
 
-	neigh_node = orig_node_get_router(dst_orig_node);
+	neigh_node = batadv_orig_node_get_router(dst_orig_node);
 	if (!neigh_node)
 		goto out;
 
-	bat_dbg(DBG_TT, bat_priv,
-		"Sending TT_REQUEST to %pM via %pM [%c]\n",
-		dst_orig_node->orig, neigh_node->addr,
-		(full_table ? 'F' : '.'));
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Sending TT_REQUEST to %pM via %pM [%c]\n",
+		   dst_orig_node->orig, neigh_node->addr,
+		   (full_table ? 'F' : '.'));
+
+	batadv_inc_counter(bat_priv, BAT_CNT_TT_REQUEST_TX);
 
-	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
 	ret = 0;
 
 out:
 	if (neigh_node)
-		neigh_node_free_ref(neigh_node);
+		batadv_neigh_node_free_ref(neigh_node);
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	if (ret)
 		kfree_skb(skb);
 	if (ret && tt_req_node) {
@@ -1375,8 +1452,8 @@ out:
 	return ret;
 }
 
-static bool send_other_tt_response(struct bat_priv *bat_priv,
-				   struct tt_query_packet *tt_request)
+static bool batadv_send_other_tt_response(struct bat_priv *bat_priv,
+					  struct tt_query_packet *tt_request)
 {
 	struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
 	struct neigh_node *neigh_node = NULL;
@@ -1389,25 +1466,25 @@ static bool send_other_tt_response(struct bat_priv *bat_priv,
 	struct sk_buff *skb = NULL;
 	struct tt_query_packet *tt_response;
 
-	bat_dbg(DBG_TT, bat_priv,
-		"Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n",
-		tt_request->src, tt_request->ttvn, tt_request->dst,
-		(tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n",
+		   tt_request->src, tt_request->ttvn, tt_request->dst,
+		   (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
 
 	/* Let's get the orig node of the REAL destination */
-	req_dst_orig_node = orig_hash_find(bat_priv, tt_request->dst);
+	req_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->dst);
 	if (!req_dst_orig_node)
 		goto out;
 
-	res_dst_orig_node = orig_hash_find(bat_priv, tt_request->src);
+	res_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->src);
 	if (!res_dst_orig_node)
 		goto out;
 
-	neigh_node = orig_node_get_router(res_dst_orig_node);
+	neigh_node = batadv_orig_node_get_router(res_dst_orig_node);
 	if (!neigh_node)
 		goto out;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
@@ -1416,7 +1493,7 @@ static bool send_other_tt_response(struct bat_priv *bat_priv,
 
 	/* I don't have the requested data */
 	if (orig_ttvn != req_ttvn ||
-	    tt_request->tt_data != req_dst_orig_node->tt_crc)
+	    tt_request->tt_data != htons(req_dst_orig_node->tt_crc))
 		goto out;
 
 	/* If the full table has been explicitly requested */
@@ -1427,7 +1504,8 @@ static bool send_other_tt_response(struct bat_priv *bat_priv,
 		full_table = false;
 
 	/* In this version, fragmentation is not implemented, then
-	 * I'll send only one packet with as much TT entries as I can */
+	 * I'll send only one packet with as much TT entries as I can
+	 */
 	if (!full_table) {
 		spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
 		tt_len = req_dst_orig_node->tt_buff_len;
@@ -1455,10 +1533,11 @@ static bool send_other_tt_response(struct bat_priv *bat_priv,
 						sizeof(struct tt_change);
 		ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
 
-		skb = tt_response_fill_table(tt_len, ttvn,
-					     bat_priv->tt_global_hash,
-					     primary_if, tt_global_valid_entry,
-					     req_dst_orig_node);
+		skb = batadv_tt_response_fill_table(tt_len, ttvn,
+						    bat_priv->tt_global_hash,
+						    primary_if,
+						    batadv_tt_global_valid,
+						    req_dst_orig_node);
 		if (!skb)
 			goto out;
 
@@ -1475,12 +1554,14 @@ static bool send_other_tt_response(struct bat_priv *bat_priv,
 	if (full_table)
 		tt_response->flags |= TT_FULL_TABLE;
 
-	bat_dbg(DBG_TT, bat_priv,
-		"Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
-		res_dst_orig_node->orig, neigh_node->addr,
-		req_dst_orig_node->orig, req_ttvn);
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
+		   res_dst_orig_node->orig, neigh_node->addr,
+		   req_dst_orig_node->orig, req_ttvn);
+
+	batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX);
 
-	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
 	ret = true;
 	goto out;
 
@@ -1489,20 +1570,20 @@ unlock:
 
 out:
 	if (res_dst_orig_node)
-		orig_node_free_ref(res_dst_orig_node);
+		batadv_orig_node_free_ref(res_dst_orig_node);
 	if (req_dst_orig_node)
-		orig_node_free_ref(req_dst_orig_node);
+		batadv_orig_node_free_ref(req_dst_orig_node);
 	if (neigh_node)
-		neigh_node_free_ref(neigh_node);
+		batadv_neigh_node_free_ref(neigh_node);
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	if (!ret)
 		kfree_skb(skb);
 	return ret;
 
 }
-static bool send_my_tt_response(struct bat_priv *bat_priv,
-				struct tt_query_packet *tt_request)
+static bool batadv_send_my_tt_response(struct bat_priv *bat_priv,
+				       struct tt_query_packet *tt_request)
 {
 	struct orig_node *orig_node = NULL;
 	struct neigh_node *neigh_node = NULL;
@@ -1515,29 +1596,30 @@ static bool send_my_tt_response(struct bat_priv *bat_priv,
 	struct sk_buff *skb = NULL;
 	struct tt_query_packet *tt_response;
 
-	bat_dbg(DBG_TT, bat_priv,
-		"Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
-		tt_request->src, tt_request->ttvn,
-		(tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
+		   tt_request->src, tt_request->ttvn,
+		   (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
 
 
 	my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
 	req_ttvn = tt_request->ttvn;
 
-	orig_node = orig_hash_find(bat_priv, tt_request->src);
+	orig_node = batadv_orig_hash_find(bat_priv, tt_request->src);
 	if (!orig_node)
 		goto out;
 
-	neigh_node = orig_node_get_router(orig_node);
+	neigh_node = batadv_orig_node_get_router(orig_node);
 	if (!neigh_node)
 		goto out;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
 	/* If the full table has been explicitly requested or the gap
-	 * is too big send the whole local translation table */
+	 * is too big send the whole local translation table
+	 */
 	if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
 	    !bat_priv->tt_buff)
 		full_table = true;
@@ -1545,7 +1627,8 @@ static bool send_my_tt_response(struct bat_priv *bat_priv,
 		full_table = false;
 
 	/* In this version, fragmentation is not implemented, then
-	 * I'll send only one packet with as much TT entries as I can */
+	 * I'll send only one packet with as much TT entries as I can
+	 */
 	if (!full_table) {
 		spin_lock_bh(&bat_priv->tt_buff_lock);
 		tt_len = bat_priv->tt_buff_len;
@@ -1571,10 +1654,11 @@ static bool send_my_tt_response(struct bat_priv *bat_priv,
 						sizeof(struct tt_change);
 		ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
 
-		skb = tt_response_fill_table(tt_len, ttvn,
-					     bat_priv->tt_local_hash,
-					     primary_if, tt_local_valid_entry,
-					     NULL);
+		skb = batadv_tt_response_fill_table(tt_len, ttvn,
+						    bat_priv->tt_local_hash,
+						    primary_if,
+						    batadv_tt_local_valid_entry,
+						    NULL);
 		if (!skb)
 			goto out;
 
@@ -1591,12 +1675,14 @@ static bool send_my_tt_response(struct bat_priv *bat_priv,
 	if (full_table)
 		tt_response->flags |= TT_FULL_TABLE;
 
-	bat_dbg(DBG_TT, bat_priv,
-		"Sending TT_RESPONSE to %pM via %pM [%c]\n",
-		orig_node->orig, neigh_node->addr,
-		(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Sending TT_RESPONSE to %pM via %pM [%c]\n",
+		   orig_node->orig, neigh_node->addr,
+		   (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
+
+	batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX);
 
-	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
 	ret = true;
 	goto out;
 
@@ -1604,49 +1690,52 @@ unlock:
 	spin_unlock_bh(&bat_priv->tt_buff_lock);
 out:
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 	if (neigh_node)
-		neigh_node_free_ref(neigh_node);
+		batadv_neigh_node_free_ref(neigh_node);
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	if (!ret)
 		kfree_skb(skb);
 	/* This packet was for me, so it doesn't need to be re-routed */
 	return true;
 }
 
-bool send_tt_response(struct bat_priv *bat_priv,
-		      struct tt_query_packet *tt_request)
+bool batadv_send_tt_response(struct bat_priv *bat_priv,
+			     struct tt_query_packet *tt_request)
 {
-	if (is_my_mac(tt_request->dst)) {
+	if (batadv_is_my_mac(tt_request->dst)) {
 		/* don't answer backbone gws! */
-		if (bla_is_backbone_gw_orig(bat_priv, tt_request->src))
+		if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_request->src))
 			return true;
 
-		return send_my_tt_response(bat_priv, tt_request);
+		return batadv_send_my_tt_response(bat_priv, tt_request);
 	} else {
-		return send_other_tt_response(bat_priv, tt_request);
+		return batadv_send_other_tt_response(bat_priv, tt_request);
 	}
 }
 
-static void _tt_update_changes(struct bat_priv *bat_priv,
-			       struct orig_node *orig_node,
-			       struct tt_change *tt_change,
-			       uint16_t tt_num_changes, uint8_t ttvn)
+static void _batadv_tt_update_changes(struct bat_priv *bat_priv,
+				      struct orig_node *orig_node,
+				      struct tt_change *tt_change,
+				      uint16_t tt_num_changes, uint8_t ttvn)
 {
 	int i;
+	int is_wifi;
+	int roams;
 
 	for (i = 0; i < tt_num_changes; i++) {
-		if ((tt_change + i)->flags & TT_CLIENT_DEL)
-			tt_global_del(bat_priv, orig_node,
-				      (tt_change + i)->addr,
-				      "tt removed by changes",
-				      (tt_change + i)->flags & TT_CLIENT_ROAM);
-		else
-			if (!tt_global_add(bat_priv, orig_node,
-					   (tt_change + i)->addr, ttvn, false,
-					   (tt_change + i)->flags &
-							TT_CLIENT_WIFI))
+		if ((tt_change + i)->flags & TT_CLIENT_DEL) {
+			roams = (tt_change + i)->flags & TT_CLIENT_ROAM;
+			batadv_tt_global_del(bat_priv, orig_node,
+					     (tt_change + i)->addr,
+					      "tt removed by changes",
+					      roams);
+		} else {
+			is_wifi = (tt_change + i)->flags & TT_CLIENT_WIFI;
+			if (!batadv_tt_global_add(bat_priv, orig_node,
+						  (tt_change + i)->addr, ttvn,
+						  false, is_wifi))
 				/* In case of problem while storing a
 				 * global_entry, we stop the updating
 				 * procedure without committing the
@@ -1654,25 +1743,27 @@ static void _tt_update_changes(struct bat_priv *bat_priv,
 				 * corrupted data on tt_request
 				 */
 				return;
+		}
 	}
 	orig_node->tt_initialised = true;
 }
 
-static void tt_fill_gtable(struct bat_priv *bat_priv,
-			   struct tt_query_packet *tt_response)
+static void batadv_tt_fill_gtable(struct bat_priv *bat_priv,
+				  struct tt_query_packet *tt_response)
 {
 	struct orig_node *orig_node = NULL;
 
-	orig_node = orig_hash_find(bat_priv, tt_response->src);
+	orig_node = batadv_orig_hash_find(bat_priv, tt_response->src);
 	if (!orig_node)
 		goto out;
 
 	/* Purge the old table first.. */
-	tt_global_del_orig(bat_priv, orig_node, "Received full table");
+	batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table");
 
-	_tt_update_changes(bat_priv, orig_node,
-			   (struct tt_change *)(tt_response + 1),
-			   tt_response->tt_data, tt_response->ttvn);
+	_batadv_tt_update_changes(bat_priv, orig_node,
+				  (struct tt_change *)(tt_response + 1),
+				  ntohs(tt_response->tt_data),
+				  tt_response->ttvn);
 
 	spin_lock_bh(&orig_node->tt_buff_lock);
 	kfree(orig_node->tt_buff);
@@ -1684,71 +1775,74 @@ static void tt_fill_gtable(struct bat_priv *bat_priv,
 
 out:
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 }
 
-static void tt_update_changes(struct bat_priv *bat_priv,
-			      struct orig_node *orig_node,
-			      uint16_t tt_num_changes, uint8_t ttvn,
-			      struct tt_change *tt_change)
+static void batadv_tt_update_changes(struct bat_priv *bat_priv,
+				     struct orig_node *orig_node,
+				     uint16_t tt_num_changes, uint8_t ttvn,
+				     struct tt_change *tt_change)
 {
-	_tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
-			   ttvn);
+	_batadv_tt_update_changes(bat_priv, orig_node, tt_change,
+				  tt_num_changes, ttvn);
 
-	tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
-			    tt_num_changes);
+	batadv_tt_save_orig_buffer(bat_priv, orig_node,
+				   (unsigned char *)tt_change, tt_num_changes);
 	atomic_set(&orig_node->last_ttvn, ttvn);
 }
 
-bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
+bool batadv_is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
 {
 	struct tt_local_entry *tt_local_entry = NULL;
 	bool ret = false;
 
-	tt_local_entry = tt_local_hash_find(bat_priv, addr);
+	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
 	if (!tt_local_entry)
 		goto out;
 	/* Check if the client has been logically deleted (but is kept for
-	 * consistency purpose) */
+	 * consistency purpose)
+	 */
 	if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
 		goto out;
 	ret = true;
 out:
 	if (tt_local_entry)
-		tt_local_entry_free_ref(tt_local_entry);
+		batadv_tt_local_entry_free_ref(tt_local_entry);
 	return ret;
 }
 
-void handle_tt_response(struct bat_priv *bat_priv,
-			struct tt_query_packet *tt_response)
+void batadv_handle_tt_response(struct bat_priv *bat_priv,
+			       struct tt_query_packet *tt_response)
 {
 	struct tt_req_node *node, *safe;
 	struct orig_node *orig_node = NULL;
 
-	bat_dbg(DBG_TT, bat_priv,
-		"Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
-		tt_response->src, tt_response->ttvn, tt_response->tt_data,
-		(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
+		   tt_response->src, tt_response->ttvn,
+		   ntohs(tt_response->tt_data),
+		   (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
 
 	/* we should have never asked a backbone gw */
-	if (bla_is_backbone_gw_orig(bat_priv, tt_response->src))
+	if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_response->src))
 		goto out;
 
-	orig_node = orig_hash_find(bat_priv, tt_response->src);
+	orig_node = batadv_orig_hash_find(bat_priv, tt_response->src);
 	if (!orig_node)
 		goto out;
 
 	if (tt_response->flags & TT_FULL_TABLE)
-		tt_fill_gtable(bat_priv, tt_response);
+		batadv_tt_fill_gtable(bat_priv, tt_response);
 	else
-		tt_update_changes(bat_priv, orig_node, tt_response->tt_data,
-				  tt_response->ttvn,
-				  (struct tt_change *)(tt_response + 1));
+		batadv_tt_update_changes(bat_priv, orig_node,
+					 ntohs(tt_response->tt_data),
+					 tt_response->ttvn,
+					 (struct tt_change *)(tt_response + 1));
 
 	/* Delete the tt_req_node from pending tt_requests list */
 	spin_lock_bh(&bat_priv->tt_req_list_lock);
 	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
-		if (!compare_eth(node->addr, tt_response->src))
+		if (!batadv_compare_eth(node->addr, tt_response->src))
 			continue;
 		list_del(&node->list);
 		kfree(node);
@@ -1756,29 +1850,34 @@ void handle_tt_response(struct bat_priv *bat_priv,
 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
 
 	/* Recalculate the CRC for this orig_node and store it */
-	orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
+	orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
 	/* Roaming phase is over: tables are in sync again. I can
-	 * unset the flag */
+	 * unset the flag
+	 */
 	orig_node->tt_poss_change = false;
 out:
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 }
 
-int tt_init(struct bat_priv *bat_priv)
+int batadv_tt_init(struct bat_priv *bat_priv)
 {
-	if (!tt_local_init(bat_priv))
-		return 0;
+	int ret;
 
-	if (!tt_global_init(bat_priv))
-		return 0;
+	ret = batadv_tt_local_init(bat_priv);
+	if (ret < 0)
+		return ret;
+
+	ret = batadv_tt_global_init(bat_priv);
+	if (ret < 0)
+		return ret;
 
-	tt_start_timer(bat_priv);
+	batadv_tt_start_timer(bat_priv);
 
 	return 1;
 }
 
-static void tt_roam_list_free(struct bat_priv *bat_priv)
+static void batadv_tt_roam_list_free(struct bat_priv *bat_priv)
 {
 	struct tt_roam_node *node, *safe;
 
@@ -1792,13 +1891,13 @@ static void tt_roam_list_free(struct bat_priv *bat_priv)
 	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
 }
 
-static void tt_roam_purge(struct bat_priv *bat_priv)
+static void batadv_tt_roam_purge(struct bat_priv *bat_priv)
 {
 	struct tt_roam_node *node, *safe;
 
 	spin_lock_bh(&bat_priv->tt_roam_list_lock);
 	list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
-		if (!has_timed_out(node->first_time, ROAMING_MAX_TIME))
+		if (!batadv_has_timed_out(node->first_time, ROAMING_MAX_TIME))
 			continue;
 
 		list_del(&node->list);
@@ -1811,21 +1910,24 @@ static void tt_roam_purge(struct bat_priv *bat_priv)
  * maximum number of possible roaming phases. In this case the ROAMING_ADV
  * will not be sent.
  *
- * returns true if the ROAMING_ADV can be sent, false otherwise */
-static bool tt_check_roam_count(struct bat_priv *bat_priv,
-				uint8_t *client)
+ * returns true if the ROAMING_ADV can be sent, false otherwise
+ */
+static bool batadv_tt_check_roam_count(struct bat_priv *bat_priv,
+				       uint8_t *client)
 {
 	struct tt_roam_node *tt_roam_node;
 	bool ret = false;
 
 	spin_lock_bh(&bat_priv->tt_roam_list_lock);
 	/* The new tt_req will be issued only if I'm not waiting for a
-	 * reply from the same orig_node yet */
+	 * reply from the same orig_node yet
+	 */
 	list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
-		if (!compare_eth(tt_roam_node->addr, client))
+		if (!batadv_compare_eth(tt_roam_node->addr, client))
 			continue;
 
-		if (has_timed_out(tt_roam_node->first_time, ROAMING_MAX_TIME))
+		if (batadv_has_timed_out(tt_roam_node->first_time,
+					 ROAMING_MAX_TIME))
 			continue;
 
 		if (!atomic_dec_not_zero(&tt_roam_node->counter))
@@ -1853,8 +1955,8 @@ unlock:
 	return ret;
 }
 
-static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
-			  struct orig_node *orig_node)
+static void batadv_send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
+				 struct orig_node *orig_node)
 {
 	struct neigh_node *neigh_node = NULL;
 	struct sk_buff *skb = NULL;
@@ -1863,8 +1965,9 @@ static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
 	struct hard_iface *primary_if;
 
 	/* before going on we have to check whether the client has
-	 * already roamed to us too many times */
-	if (!tt_check_roam_count(bat_priv, client))
+	 * already roamed to us too many times
+	 */
+	if (!batadv_tt_check_roam_count(bat_priv, client))
 		goto out;
 
 	skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
@@ -1879,65 +1982,68 @@ static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
 	roam_adv_packet->header.packet_type = BAT_ROAM_ADV;
 	roam_adv_packet->header.version = COMPAT_VERSION;
 	roam_adv_packet->header.ttl = TTL;
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 	memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
-	hardif_free_ref(primary_if);
+	batadv_hardif_free_ref(primary_if);
 	memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
 	memcpy(roam_adv_packet->client, client, ETH_ALEN);
 
-	neigh_node = orig_node_get_router(orig_node);
+	neigh_node = batadv_orig_node_get_router(orig_node);
 	if (!neigh_node)
 		goto out;
 
-	bat_dbg(DBG_TT, bat_priv,
-		"Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
-		orig_node->orig, client, neigh_node->addr);
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
+		   orig_node->orig, client, neigh_node->addr);
 
-	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+	batadv_inc_counter(bat_priv, BAT_CNT_TT_ROAM_ADV_TX);
+
+	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
 	ret = 0;
 
 out:
 	if (neigh_node)
-		neigh_node_free_ref(neigh_node);
+		batadv_neigh_node_free_ref(neigh_node);
 	if (ret)
 		kfree_skb(skb);
 	return;
 }
 
-static void tt_purge(struct work_struct *work)
+static void batadv_tt_purge(struct work_struct *work)
 {
 	struct delayed_work *delayed_work =
 		container_of(work, struct delayed_work, work);
 	struct bat_priv *bat_priv =
 		container_of(delayed_work, struct bat_priv, tt_work);
 
-	tt_local_purge(bat_priv);
-	tt_global_roam_purge(bat_priv);
-	tt_req_purge(bat_priv);
-	tt_roam_purge(bat_priv);
+	batadv_tt_local_purge(bat_priv);
+	batadv_tt_global_roam_purge(bat_priv);
+	batadv_tt_req_purge(bat_priv);
+	batadv_tt_roam_purge(bat_priv);
 
-	tt_start_timer(bat_priv);
+	batadv_tt_start_timer(bat_priv);
 }
 
-void tt_free(struct bat_priv *bat_priv)
+void batadv_tt_free(struct bat_priv *bat_priv)
 {
 	cancel_delayed_work_sync(&bat_priv->tt_work);
 
-	tt_local_table_free(bat_priv);
-	tt_global_table_free(bat_priv);
-	tt_req_list_free(bat_priv);
-	tt_changes_list_free(bat_priv);
-	tt_roam_list_free(bat_priv);
+	batadv_tt_local_table_free(bat_priv);
+	batadv_tt_global_table_free(bat_priv);
+	batadv_tt_req_list_free(bat_priv);
+	batadv_tt_changes_list_free(bat_priv);
+	batadv_tt_roam_list_free(bat_priv);
 
 	kfree(bat_priv->tt_buff);
 }
 
 /* This function will enable or disable the specified flags for all the entries
- * in the given hash table and returns the number of modified entries */
-static uint16_t tt_set_flags(struct hashtable_t *hash, uint16_t flags,
-			     bool enable)
+ * in the given hash table and returns the number of modified entries
+ */
+static uint16_t batadv_tt_set_flags(struct hashtable_t *hash, uint16_t flags,
+				    bool enable)
 {
 	uint32_t i;
 	uint16_t changed_num = 0;
@@ -1972,7 +2078,7 @@ out:
 }
 
 /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
-static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
+static void batadv_tt_local_purge_pending_clients(struct bat_priv *bat_priv)
 {
 	struct hashtable_t *hash = bat_priv->tt_local_hash;
 	struct tt_common_entry *tt_common_entry;
@@ -1995,98 +2101,141 @@ static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
 			if (!(tt_common_entry->flags & TT_CLIENT_PENDING))
 				continue;
 
-			bat_dbg(DBG_TT, bat_priv,
-				"Deleting local tt entry (%pM): pending\n",
-				tt_common_entry->addr);
+			batadv_dbg(DBG_TT, bat_priv,
+				   "Deleting local tt entry (%pM): pending\n",
+				   tt_common_entry->addr);
 
 			atomic_dec(&bat_priv->num_local_tt);
 			hlist_del_rcu(node);
 			tt_local_entry = container_of(tt_common_entry,
 						      struct tt_local_entry,
 						      common);
-			tt_local_entry_free_ref(tt_local_entry);
+			batadv_tt_local_entry_free_ref(tt_local_entry);
 		}
 		spin_unlock_bh(list_lock);
 	}
 
 }
 
-void tt_commit_changes(struct bat_priv *bat_priv)
+static int batadv_tt_commit_changes(struct bat_priv *bat_priv,
+				    unsigned char **packet_buff,
+				    int *packet_buff_len, int packet_min_len)
 {
-	uint16_t changed_num = tt_set_flags(bat_priv->tt_local_hash,
-					    TT_CLIENT_NEW, false);
-	/* all the reset entries have now to be effectively counted as local
-	 * entries */
+	uint16_t changed_num = 0;
+
+	if (atomic_read(&bat_priv->tt_local_changes) < 1)
+		return -ENOENT;
+
+	changed_num = batadv_tt_set_flags(bat_priv->tt_local_hash,
+					  TT_CLIENT_NEW, false);
+
+	/* all reset entries have to be counted as local entries */
 	atomic_add(changed_num, &bat_priv->num_local_tt);
-	tt_local_purge_pending_clients(bat_priv);
+	batadv_tt_local_purge_pending_clients(bat_priv);
+	bat_priv->tt_crc = batadv_tt_local_crc(bat_priv);
 
 	/* Increment the TTVN only once per OGM interval */
 	atomic_inc(&bat_priv->ttvn);
-	bat_dbg(DBG_TT, bat_priv, "Local changes committed, updating to ttvn %u\n",
-		(uint8_t)atomic_read(&bat_priv->ttvn));
+	batadv_dbg(DBG_TT, bat_priv,
+		   "Local changes committed, updating to ttvn %u\n",
+		   (uint8_t)atomic_read(&bat_priv->ttvn));
 	bat_priv->tt_poss_change = false;
+
+	/* reset the sending counter */
+	atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX);
+
+	return batadv_tt_changes_fill_buff(bat_priv, packet_buff,
+					   packet_buff_len, packet_min_len);
 }
 
-bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
+/* when calling this function (hard_iface == primary_if) has to be true */
+int batadv_tt_append_diff(struct bat_priv *bat_priv,
+			  unsigned char **packet_buff, int *packet_buff_len,
+			  int packet_min_len)
+{
+	int tt_num_changes;
+
+	/* if at least one change happened */
+	tt_num_changes = batadv_tt_commit_changes(bat_priv, packet_buff,
+						  packet_buff_len,
+						  packet_min_len);
+
+	/* if the changes have been sent often enough */
+	if ((tt_num_changes < 0) &&
+	    (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))) {
+		batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len,
+					      packet_min_len, packet_min_len);
+		tt_num_changes = 0;
+	}
+
+	return tt_num_changes;
+}
+
+bool batadv_is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src,
+			   uint8_t *dst)
 {
 	struct tt_local_entry *tt_local_entry = NULL;
 	struct tt_global_entry *tt_global_entry = NULL;
-	bool ret = true;
+	bool ret = false;
 
 	if (!atomic_read(&bat_priv->ap_isolation))
-		return false;
+		goto out;
 
-	tt_local_entry = tt_local_hash_find(bat_priv, dst);
+	tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst);
 	if (!tt_local_entry)
 		goto out;
 
-	tt_global_entry = tt_global_hash_find(bat_priv, src);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, src);
 	if (!tt_global_entry)
 		goto out;
 
-	if (_is_ap_isolated(tt_local_entry, tt_global_entry))
+	if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
 		goto out;
 
-	ret = false;
+	ret = true;
 
 out:
 	if (tt_global_entry)
-		tt_global_entry_free_ref(tt_global_entry);
+		batadv_tt_global_entry_free_ref(tt_global_entry);
 	if (tt_local_entry)
-		tt_local_entry_free_ref(tt_local_entry);
+		batadv_tt_local_entry_free_ref(tt_local_entry);
 	return ret;
 }
 
-void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
-		    const unsigned char *tt_buff, uint8_t tt_num_changes,
-		    uint8_t ttvn, uint16_t tt_crc)
+void batadv_tt_update_orig(struct bat_priv *bat_priv,
+			   struct orig_node *orig_node,
+			   const unsigned char *tt_buff, uint8_t tt_num_changes,
+			   uint8_t ttvn, uint16_t tt_crc)
 {
 	uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
 	bool full_table = true;
 
 	/* don't care about a backbone gateways updates. */
-	if (bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
+	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
 		return;
 
 	/* orig table not initialised AND first diff is in the OGM OR the ttvn
-	 * increased by one -> we can apply the attached changes */
+	 * increased by one -> we can apply the attached changes
+	 */
 	if ((!orig_node->tt_initialised && ttvn == 1) ||
 	    ttvn - orig_ttvn == 1) {
 		/* the OGM could not contain the changes due to their size or
 		 * because they have already been sent TT_OGM_APPEND_MAX times.
-		 * In this case send a tt request */
+		 * In this case send a tt request
+		 */
 		if (!tt_num_changes) {
 			full_table = false;
 			goto request_table;
 		}
 
-		tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
-				  (struct tt_change *)tt_buff);
+		batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
+					 ttvn, (struct tt_change *)tt_buff);
 
 		/* Even if we received the precomputed crc with the OGM, we
 		 * prefer to recompute it to spot any possible inconsistency
-		 * in the global table */
-		orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
+		 * in the global table
+		 */
+		orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
 
 		/* The ttvn alone is not enough to guarantee consistency
 		 * because a single value could represent different states
@@ -2095,26 +2244,28 @@ void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
 		 * consistent or not. E.g. a node could disconnect while its
 		 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
 		 * checking the CRC value is mandatory to detect the
-		 * inconsistency */
+		 * inconsistency
+		 */
 		if (orig_node->tt_crc != tt_crc)
 			goto request_table;
 
 		/* Roaming phase is over: tables are in sync again. I can
-		 * unset the flag */
+		 * unset the flag
+		 */
 		orig_node->tt_poss_change = false;
 	} else {
 		/* if we missed more than one change or our tables are not
-		 * in sync anymore -> request fresh tt data */
-
+		 * in sync anymore -> request fresh tt data
+		 */
 		if (!orig_node->tt_initialised || ttvn != orig_ttvn ||
 		    orig_node->tt_crc != tt_crc) {
 request_table:
-			bat_dbg(DBG_TT, bat_priv,
-				"TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %u last_crc: %u num_changes: %u)\n",
-				orig_node->orig, ttvn, orig_ttvn, tt_crc,
-				orig_node->tt_crc, tt_num_changes);
-			send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
-					full_table);
+			batadv_dbg(DBG_TT, bat_priv,
+				   "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %u last_crc: %u num_changes: %u)\n",
+				   orig_node->orig, ttvn, orig_ttvn, tt_crc,
+				   orig_node->tt_crc, tt_num_changes);
+			batadv_send_tt_request(bat_priv, orig_node, ttvn,
+					       tt_crc, full_table);
 			return;
 		}
 	}
@@ -2124,17 +2275,18 @@ request_table:
  * originator to another one. This entry is kept is still kept for consistency
  * purposes
  */
-bool tt_global_client_is_roaming(struct bat_priv *bat_priv, uint8_t *addr)
+bool batadv_tt_global_client_is_roaming(struct bat_priv *bat_priv,
+					uint8_t *addr)
 {
 	struct tt_global_entry *tt_global_entry;
 	bool ret = false;
 
-	tt_global_entry = tt_global_hash_find(bat_priv, addr);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
 	if (!tt_global_entry)
 		goto out;
 
 	ret = tt_global_entry->common.flags & TT_CLIENT_ROAM;
-	tt_global_entry_free_ref(tt_global_entry);
+	batadv_tt_global_entry_free_ref(tt_global_entry);
 out:
 	return ret;
 }
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h
index c43374d..7edc9df 100644
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich, Antonio Quartulli
  *
@@ -16,44 +15,49 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
 #define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
 
-int tt_len(int changes_num);
-int tt_changes_fill_buffer(struct bat_priv *bat_priv,
-			   unsigned char *buff, int buff_len);
-int tt_init(struct bat_priv *bat_priv);
-void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
-		  int ifindex);
-void tt_local_remove(struct bat_priv *bat_priv,
-		     const uint8_t *addr, const char *message, bool roaming);
-int tt_local_seq_print_text(struct seq_file *seq, void *offset);
-void tt_global_add_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
-			const unsigned char *tt_buff, int tt_buff_len);
-int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
-		  const unsigned char *addr, uint8_t ttvn, bool roaming,
-		  bool wifi);
-int tt_global_seq_print_text(struct seq_file *seq, void *offset);
-void tt_global_del_orig(struct bat_priv *bat_priv,
-			struct orig_node *orig_node, const char *message);
-struct orig_node *transtable_search(struct bat_priv *bat_priv,
-				    const uint8_t *src, const uint8_t *addr);
-uint16_t tt_local_crc(struct bat_priv *bat_priv);
-void tt_free(struct bat_priv *bat_priv);
-bool send_tt_response(struct bat_priv *bat_priv,
-		      struct tt_query_packet *tt_request);
-bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr);
-void handle_tt_response(struct bat_priv *bat_priv,
-			struct tt_query_packet *tt_response);
-void tt_commit_changes(struct bat_priv *bat_priv);
-bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst);
-void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
-		    const unsigned char *tt_buff, uint8_t tt_num_changes,
-		    uint8_t ttvn, uint16_t tt_crc);
-bool tt_global_client_is_roaming(struct bat_priv *bat_priv, uint8_t *addr);
+int batadv_tt_len(int changes_num);
+int batadv_tt_init(struct bat_priv *bat_priv);
+void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
+			 int ifindex);
+void batadv_tt_local_remove(struct bat_priv *bat_priv,
+			    const uint8_t *addr, const char *message,
+			    bool roaming);
+int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset);
+void batadv_tt_global_add_orig(struct bat_priv *bat_priv,
+			       struct orig_node *orig_node,
+			       const unsigned char *tt_buff, int tt_buff_len);
+int batadv_tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
+			 const unsigned char *addr, uint8_t ttvn, bool roaming,
+			 bool wifi);
+int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset);
+void batadv_tt_global_del_orig(struct bat_priv *bat_priv,
+			       struct orig_node *orig_node,
+			       const char *message);
+struct orig_node *batadv_transtable_search(struct bat_priv *bat_priv,
+					   const uint8_t *src,
+					   const uint8_t *addr);
+void batadv_tt_free(struct bat_priv *bat_priv);
+bool batadv_send_tt_response(struct bat_priv *bat_priv,
+			     struct tt_query_packet *tt_request);
+bool batadv_is_my_client(struct bat_priv *bat_priv, const uint8_t *addr);
+void batadv_handle_tt_response(struct bat_priv *bat_priv,
+			       struct tt_query_packet *tt_response);
+bool batadv_is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src,
+			   uint8_t *dst);
+void batadv_tt_update_orig(struct bat_priv *bat_priv,
+			   struct orig_node *orig_node,
+			   const unsigned char *tt_buff, uint8_t tt_num_changes,
+			   uint8_t ttvn, uint16_t tt_crc);
+int batadv_tt_append_diff(struct bat_priv *bat_priv,
+			  unsigned char **packet_buff, int *packet_buff_len,
+			  int packet_min_len);
+bool batadv_tt_global_client_is_roaming(struct bat_priv *bat_priv,
+					uint8_t *addr);
 
 
 #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 61308e8..053c5d4 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -16,11 +15,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
-
-
 #ifndef _NET_BATMAN_ADV_TYPES_H_
 #define _NET_BATMAN_ADV_TYPES_H_
 
@@ -49,8 +45,7 @@ struct hard_iface {
 	struct rcu_head rcu;
 };
 
-/**
- *	orig_node - structure for orig_list maintaining nodes of mesh
+/*	orig_node - structure for orig_list maintaining nodes of mesh
  *	@primary_addr: hosts primary interface address
  *	@last_seen: when last packet from this node was received
  *	@bcast_seqno_reset: time when the broadcast seqno window was reset
@@ -86,7 +81,8 @@ struct orig_node {
 	 * If true, then I sent a Roaming_adv to this orig_node and I have to
 	 * inspect every packet directed to it to check whether it is still
 	 * the true destination or not. This flag will be reset to false as
-	 * soon as I receive a new TTVN from this orig_node */
+	 * soon as I receive a new TTVN from this orig_node
+	 */
 	bool tt_poss_change;
 	uint32_t last_real_seqno;
 	uint8_t last_ttl;
@@ -101,7 +97,8 @@ struct orig_node {
 	struct bat_priv *bat_priv;
 	unsigned long last_frag_packet;
 	/* ogm_cnt_lock protects: bcast_own, bcast_own_sum,
-	 * neigh_node->real_bits, neigh_node->real_packet_count */
+	 * neigh_node->real_bits, neigh_node->real_packet_count
+	 */
 	spinlock_t ogm_cnt_lock;
 	/* bcast_seqno_lock protects bcast_bits, last_bcast_seqno */
 	spinlock_t bcast_seqno_lock;
@@ -118,8 +115,7 @@ struct gw_node {
 	struct rcu_head rcu;
 };
 
-/**
- *	neigh_node
+/*	neigh_node
  *	@last_seen: when last packet via this neighbor was received
  */
 struct neigh_node {
@@ -148,9 +144,26 @@ struct bcast_duplist_entry {
 };
 #endif
 
+enum bat_counters {
+	BAT_CNT_FORWARD,
+	BAT_CNT_FORWARD_BYTES,
+	BAT_CNT_MGMT_TX,
+	BAT_CNT_MGMT_TX_BYTES,
+	BAT_CNT_MGMT_RX,
+	BAT_CNT_MGMT_RX_BYTES,
+	BAT_CNT_TT_REQUEST_TX,
+	BAT_CNT_TT_REQUEST_RX,
+	BAT_CNT_TT_RESPONSE_TX,
+	BAT_CNT_TT_RESPONSE_RX,
+	BAT_CNT_TT_ROAM_ADV_TX,
+	BAT_CNT_TT_ROAM_ADV_RX,
+	BAT_CNT_NUM,
+};
+
 struct bat_priv {
 	atomic_t mesh_state;
 	struct net_device_stats stats;
+	uint64_t __percpu *bat_counters; /* Per cpu counters */
 	atomic_t aggregated_ogms;	/* boolean */
 	atomic_t bonding;		/* boolean */
 	atomic_t fragmentation;		/* boolean */
@@ -174,7 +187,8 @@ struct bat_priv {
 	 * If true, then I received a Roaming_adv and I have to inspect every
 	 * packet directed to me to check whether I am still the true
 	 * destination or not. This flag will be reset to false as soon as I
-	 * increase my TTVN */
+	 * increase my TTVN
+	 */
 	bool tt_poss_change;
 	char num_ifaces;
 	struct debug_log *debug_log;
@@ -210,7 +224,7 @@ struct bat_priv {
 	spinlock_t vis_list_lock; /* protects vis_info::recv_list */
 	atomic_t num_local_tt;
 	/* Checksum of the local table, recomputed before sending a new OGM */
-	atomic_t tt_crc;
+	uint16_t tt_crc;
 	unsigned char *tt_buff;
 	int16_t tt_buff_len;
 	spinlock_t tt_buff_lock; /* protects tt_buff */
@@ -309,8 +323,7 @@ struct tt_roam_node {
 	struct list_head list;
 };
 
-/**
- *	forw_packet - structure for forw_list maintaining packets to be
+/*	forw_packet - structure for forw_list maintaining packets to be
  *	              send/forwarded
  */
 struct forw_packet {
@@ -352,7 +365,8 @@ struct frag_packet_list_entry {
 struct vis_info {
 	unsigned long first_seen;
 	/* list of server-neighbors we received a vis-packet
-	 * from.  we should not reply to them. */
+	 * from.  we should not reply to them.
+	 */
 	struct list_head recv_list;
 	struct list_head send_list;
 	struct kref refcount;
@@ -360,7 +374,7 @@ struct vis_info {
 	struct bat_priv *bat_priv;
 	/* this packet might be part of the vis send queue. */
 	struct sk_buff *skb_packet;
-	/* vis_info may follow here*/
+	/* vis_info may follow here */
 } __packed;
 
 struct vis_info_entry {
@@ -388,8 +402,7 @@ struct bat_algo_ops {
 	/* called when primary interface is selected / changed */
 	void (*bat_primary_iface_set)(struct hard_iface *hard_iface);
 	/* prepare a new outgoing OGM for the send queue */
-	void (*bat_ogm_schedule)(struct hard_iface *hard_iface,
-				 int tt_num_changes);
+	void (*bat_ogm_schedule)(struct hard_iface *hard_iface);
 	/* send scheduled OGM */
 	void (*bat_ogm_emit)(struct forw_packet *forw_packet);
 };
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 74175c2..d021055 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
  *
  * Andreas Langer
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -101,7 +99,7 @@ static int frag_create_buffer(struct list_head *head)
 	for (i = 0; i < FRAG_BUFFER_SIZE; i++) {
 		tfp = kmalloc(sizeof(*tfp), GFP_ATOMIC);
 		if (!tfp) {
-			frag_list_free(head);
+			batadv_frag_list_free(head);
 			return -ENOMEM;
 		}
 		tfp->skb = NULL;
@@ -151,7 +149,7 @@ mov_tail:
 	return NULL;
 }
 
-void frag_list_free(struct list_head *head)
+void batadv_frag_list_free(struct list_head *head)
 {
 	struct frag_packet_list_entry *pf, *tmp_pf;
 
@@ -172,8 +170,8 @@ void frag_list_free(struct list_head *head)
  * or the skb could be reassembled (skb_new will point to the new packet and
  * skb was freed)
  */
-int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
-			struct sk_buff **new_skb)
+int batadv_frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
+			       struct sk_buff **new_skb)
 {
 	struct orig_node *orig_node;
 	struct frag_packet_list_entry *tmp_frag_entry;
@@ -183,7 +181,7 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
 
 	*new_skb = NULL;
 
-	orig_node = orig_hash_find(bat_priv, unicast_packet->orig);
+	orig_node = batadv_orig_hash_find(bat_priv, unicast_packet->orig);
 	if (!orig_node)
 		goto out;
 
@@ -212,12 +210,12 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
 
 out:
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 	return ret;
 }
 
-int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
-		  struct hard_iface *hard_iface, const uint8_t dstaddr[])
+int batadv_frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
+			 struct hard_iface *hard_iface, const uint8_t dstaddr[])
 {
 	struct unicast_packet tmp_uc, *unicast_packet;
 	struct hard_iface *primary_if;
@@ -229,7 +227,7 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
 	int large_tail = 0, ret = NET_RX_DROP;
 	uint16_t seqno;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto dropped;
 
@@ -242,8 +240,8 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
 	memcpy(&tmp_uc, unicast_packet, uc_hdr_len);
 	skb_split(skb, frag_skb, data_len / 2 + uc_hdr_len);
 
-	if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 ||
-	    my_skb_head_push(frag_skb, ucf_hdr_len) < 0)
+	if (batadv_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 ||
+	    batadv_skb_head_push(frag_skb, ucf_hdr_len) < 0)
 		goto drop_frag;
 
 	frag1 = (struct unicast_frag_packet *)skb->data;
@@ -268,8 +266,8 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
 	frag1->seqno = htons(seqno - 1);
 	frag2->seqno = htons(seqno);
 
-	send_skb_packet(skb, hard_iface, dstaddr);
-	send_skb_packet(frag_skb, hard_iface, dstaddr);
+	batadv_send_skb_packet(skb, hard_iface, dstaddr);
+	batadv_send_skb_packet(frag_skb, hard_iface, dstaddr);
 	ret = NET_RX_SUCCESS;
 	goto out;
 
@@ -279,11 +277,11 @@ dropped:
 	kfree_skb(skb);
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	return ret;
 }
 
-int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
+int batadv_unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
 {
 	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
 	struct unicast_packet *unicast_packet;
@@ -294,28 +292,26 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
 
 	/* get routing information */
 	if (is_multicast_ether_addr(ethhdr->h_dest)) {
-		orig_node = gw_get_selected_orig(bat_priv);
+		orig_node = batadv_gw_get_selected_orig(bat_priv);
 		if (orig_node)
 			goto find_router;
 	}
 
 	/* check for tt host - increases orig_node refcount.
-	 * returns NULL in case of AP isolation */
-	orig_node = transtable_search(bat_priv, ethhdr->h_source,
-				      ethhdr->h_dest);
-
+	 * returns NULL in case of AP isolation
+	 */
+	orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
+					     ethhdr->h_dest);
 find_router:
-	/**
-	 * find_router():
+	/* find_router():
 	 *  - if orig_node is NULL it returns NULL
 	 *  - increases neigh_nodes refcount if found.
 	 */
-	neigh_node = find_router(bat_priv, orig_node, NULL);
-
+	neigh_node = batadv_find_router(bat_priv, orig_node, NULL);
 	if (!neigh_node)
 		goto out;
 
-	if (my_skb_head_push(skb, sizeof(*unicast_packet)) < 0)
+	if (batadv_skb_head_push(skb, sizeof(*unicast_packet)) < 0)
 		goto out;
 
 	unicast_packet = (struct unicast_packet *)skb->data;
@@ -336,7 +332,7 @@ find_router:
 	 * try to reroute it because the ttvn contained in the header is less
 	 * than the current one
 	 */
-	if (tt_global_client_is_roaming(bat_priv, ethhdr->h_dest))
+	if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest))
 		unicast_packet->ttvn = unicast_packet->ttvn - 1;
 
 	if (atomic_read(&bat_priv->fragmentation) &&
@@ -344,20 +340,21 @@ find_router:
 				neigh_node->if_incoming->net_dev->mtu) {
 		/* send frag skb decreases ttl */
 		unicast_packet->header.ttl++;
-		ret = frag_send_skb(skb, bat_priv,
-				    neigh_node->if_incoming, neigh_node->addr);
+		ret = batadv_frag_send_skb(skb, bat_priv,
+					   neigh_node->if_incoming,
+					   neigh_node->addr);
 		goto out;
 	}
 
-	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
 	ret = 0;
 	goto out;
 
 out:
 	if (neigh_node)
-		neigh_node_free_ref(neigh_node);
+		batadv_neigh_node_free_ref(neigh_node);
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 	if (ret == 1)
 		kfree_skb(skb);
 	return ret;
diff --git a/net/batman-adv/unicast.h b/net/batman-adv/unicast.h
index a9faf6b..9257b83 100644
--- a/net/batman-adv/unicast.h
+++ b/net/batman-adv/unicast.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
  *
  * Andreas Langer
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_UNICAST_H_
@@ -27,14 +25,15 @@
 #define FRAG_TIMEOUT 10000	/* purge frag list entries after time in ms */
 #define FRAG_BUFFER_SIZE 6	/* number of list elements in buffer */
 
-int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
-			struct sk_buff **new_skb);
-void frag_list_free(struct list_head *head);
-int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv);
-int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
-		  struct hard_iface *hard_iface, const uint8_t dstaddr[]);
+int batadv_frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
+			       struct sk_buff **new_skb);
+void batadv_frag_list_free(struct list_head *head);
+int batadv_unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv);
+int batadv_frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
+			 struct hard_iface *hard_iface,
+			 const uint8_t dstaddr[]);
 
-static inline int frag_can_reassemble(const struct sk_buff *skb, int mtu)
+static inline int batadv_frag_can_reassemble(const struct sk_buff *skb, int mtu)
 {
 	const struct unicast_frag_packet *unicast_packet;
 	int uneven_correction = 0;
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index cec216f..d45989e 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2008-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2008-2012 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich
  *
@@ -16,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #include "main.h"
@@ -61,11 +59,12 @@ static int vis_info_cmp(const struct hlist_node *node, const void *data2)
 	d2 = data2;
 	p1 = (struct vis_packet *)d1->skb_packet->data;
 	p2 = (struct vis_packet *)d2->skb_packet->data;
-	return compare_eth(p1->vis_orig, p2->vis_orig);
+	return batadv_compare_eth(p1->vis_orig, p2->vis_orig);
 }
 
-/* hash function to choose an entry in a hash table of given size */
-/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
+/* hash function to choose an entry in a hash table of given size
+ * hash algorithm from http://en.wikipedia.org/wiki/Hash_table
+ */
 static uint32_t vis_info_choose(const void *data, uint32_t size)
 {
 	const struct vis_info *vis_info = data;
@@ -118,7 +117,8 @@ static struct vis_info *vis_hash_find(struct bat_priv *bat_priv,
 }
 
 /* insert interface to the list of interfaces of one originator, if it
- * does not already exist in the list */
+ * does not already exist in the list
+ */
 static void vis_data_insert_interface(const uint8_t *interface,
 				      struct hlist_head *if_list,
 				      bool primary)
@@ -127,7 +127,7 @@ static void vis_data_insert_interface(const uint8_t *interface,
 	struct hlist_node *pos;
 
 	hlist_for_each_entry(entry, pos, if_list, list) {
-		if (compare_eth(entry->addr, interface))
+		if (batadv_compare_eth(entry->addr, interface))
 			return;
 	}
 
@@ -181,14 +181,14 @@ static ssize_t vis_data_read_entry(char *buff,
 	/* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */
 	if (primary && entry->quality == 0)
 		return sprintf(buff, "TT %pM, ", entry->dest);
-	else if (compare_eth(entry->src, src))
+	else if (batadv_compare_eth(entry->src, src))
 		return sprintf(buff, "TQ %pM %d, ", entry->dest,
 			       entry->quality);
 
 	return 0;
 }
 
-int vis_seq_print_text(struct seq_file *seq, void *offset)
+int batadv_vis_seq_print_text(struct seq_file *seq, void *offset)
 {
 	struct hard_iface *primary_if;
 	struct hlist_node *node;
@@ -207,9 +207,8 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
 	int vis_server = atomic_read(&bat_priv->vis_mode);
 	size_t buff_pos, buf_size;
 	char *buff;
-	int compare;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
@@ -228,21 +227,26 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
 			entries = (struct vis_info_entry *)
 				((char *)packet + sizeof(*packet));
 
+			vis_data_insert_interface(packet->vis_orig,
+						  &vis_if_list, true);
+
 			for (j = 0; j < packet->entries; j++) {
 				if (entries[j].quality == 0)
 					continue;
-				compare =
-				 compare_eth(entries[j].src, packet->vis_orig);
+				if (batadv_compare_eth(entries[j].src,
+						       packet->vis_orig))
+					continue;
 				vis_data_insert_interface(entries[j].src,
 							  &vis_if_list,
-							  compare);
+							  false);
 			}
 
 			hlist_for_each_entry(entry, pos, &vis_if_list, list) {
 				buf_size += 18 + 26 * packet->entries;
 
 				/* add primary/secondary records */
-				if (compare_eth(entry->addr, packet->vis_orig))
+				if (batadv_compare_eth(entry->addr,
+						       packet->vis_orig))
 					buf_size +=
 					  vis_data_count_prim_sec(&vis_if_list);
 
@@ -276,14 +280,18 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
 			entries = (struct vis_info_entry *)
 				((char *)packet + sizeof(*packet));
 
+			vis_data_insert_interface(packet->vis_orig,
+						  &vis_if_list, true);
+
 			for (j = 0; j < packet->entries; j++) {
 				if (entries[j].quality == 0)
 					continue;
-				compare =
-				 compare_eth(entries[j].src, packet->vis_orig);
+				if (batadv_compare_eth(entries[j].src,
+						       packet->vis_orig))
+					continue;
 				vis_data_insert_interface(entries[j].src,
 							  &vis_if_list,
-							  compare);
+							  false);
 			}
 
 			hlist_for_each_entry(entry, pos, &vis_if_list, list) {
@@ -298,7 +306,8 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
 							entry->primary);
 
 				/* add primary/secondary records */
-				if (compare_eth(entry->addr, packet->vis_orig))
+				if (batadv_compare_eth(entry->addr,
+						       packet->vis_orig))
 					buff_pos +=
 					 vis_data_read_prim_sec(buff + buff_pos,
 								&vis_if_list);
@@ -322,12 +331,13 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
 
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 	return ret;
 }
 
 /* add the info packet to the send list, if it was not
- * already linked in. */
+ * already linked in.
+ */
 static void send_list_add(struct bat_priv *bat_priv, struct vis_info *info)
 {
 	if (list_empty(&info->send_list)) {
@@ -337,7 +347,8 @@ static void send_list_add(struct bat_priv *bat_priv, struct vis_info *info)
 }
 
 /* delete the info packet from the send list, if it was
- * linked in. */
+ * linked in.
+ */
 static void send_list_del(struct vis_info *info)
 {
 	if (!list_empty(&info->send_list)) {
@@ -370,7 +381,7 @@ static int recv_list_is_in(struct bat_priv *bat_priv,
 
 	spin_lock_bh(&bat_priv->vis_list_lock);
 	list_for_each_entry(entry, recv_list, list) {
-		if (compare_eth(entry->mac, mac)) {
+		if (batadv_compare_eth(entry->mac, mac)) {
 			spin_unlock_bh(&bat_priv->vis_list_lock);
 			return 1;
 		}
@@ -381,7 +392,8 @@ static int recv_list_is_in(struct bat_priv *bat_priv,
 
 /* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old,
  * broken.. ).	vis hash must be locked outside.  is_new is set when the packet
- * is newer than old entries in the hash. */
+ * is newer than old entries in the hash.
+ */
 static struct vis_info *add_packet(struct bat_priv *bat_priv,
 				   struct vis_packet *vis_packet,
 				   int vis_info_len, int *is_new,
@@ -423,8 +435,8 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
 			}
 		}
 		/* remove old entry */
-		hash_remove(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
-			    old_info);
+		batadv_hash_remove(bat_priv->vis_hash, vis_info_cmp,
+				   vis_info_choose, old_info);
 		send_list_del(old_info);
 		kref_put(&old_info->refcount, free_info);
 	}
@@ -455,7 +467,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
 
 	/* Make it a broadcast packet, if required */
 	if (make_broadcast)
-		memcpy(packet->target_orig, broadcast_addr, ETH_ALEN);
+		memcpy(packet->target_orig, batadv_broadcast_addr, ETH_ALEN);
 
 	/* repair if entries is longer than packet. */
 	if (packet->entries * sizeof(struct vis_info_entry) > vis_info_len)
@@ -464,8 +476,8 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
 	recv_list_add(bat_priv, &info->recv_list, packet->sender_orig);
 
 	/* try to add it */
-	hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
-			      info, &info->hash_entry);
+	hash_added = batadv_hash_add(bat_priv->vis_hash, vis_info_cmp,
+				     vis_info_choose, info, &info->hash_entry);
 	if (hash_added != 0) {
 		/* did not work (for some reason) */
 		kref_put(&info->refcount, free_info);
@@ -476,9 +488,9 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
 }
 
 /* handle the server sync packet, forward if needed. */
-void receive_server_sync_packet(struct bat_priv *bat_priv,
-				struct vis_packet *vis_packet,
-				int vis_info_len)
+void batadv_receive_server_sync_packet(struct bat_priv *bat_priv,
+				       struct vis_packet *vis_packet,
+				       int vis_info_len)
 {
 	struct vis_info *info;
 	int is_new, make_broadcast;
@@ -493,7 +505,8 @@ void receive_server_sync_packet(struct bat_priv *bat_priv,
 		goto end;
 
 	/* only if we are server ourselves and packet is newer than the one in
-	 * hash.*/
+	 * hash.
+	 */
 	if (vis_server == VIS_TYPE_SERVER_SYNC && is_new)
 		send_list_add(bat_priv, info);
 end:
@@ -501,9 +514,9 @@ end:
 }
 
 /* handle an incoming client update packet and schedule forward if needed. */
-void receive_client_update_packet(struct bat_priv *bat_priv,
-				  struct vis_packet *vis_packet,
-				  int vis_info_len)
+void batadv_receive_client_update_packet(struct bat_priv *bat_priv,
+					 struct vis_packet *vis_packet,
+					 int vis_info_len)
 {
 	struct vis_info *info;
 	struct vis_packet *packet;
@@ -517,7 +530,7 @@ void receive_client_update_packet(struct bat_priv *bat_priv,
 
 	/* Are we the target for this VIS packet? */
 	if (vis_server == VIS_TYPE_SERVER_SYNC	&&
-	    is_my_mac(vis_packet->target_orig))
+	    batadv_is_my_mac(vis_packet->target_orig))
 		are_target = 1;
 
 	spin_lock_bh(&bat_priv->vis_hash_lock);
@@ -536,7 +549,7 @@ void receive_client_update_packet(struct bat_priv *bat_priv,
 		send_list_add(bat_priv, info);
 
 		/* ... we're not the recipient (and thus need to forward). */
-	} else if (!is_my_mac(packet->target_orig)) {
+	} else if (!batadv_is_my_mac(packet->target_orig)) {
 		send_list_add(bat_priv, info);
 	}
 
@@ -547,7 +560,8 @@ end:
 /* Walk the originators and find the VIS server with the best tq. Set the packet
  * address to its address and return the best_tq.
  *
- * Must be called with the originator hash locked */
+ * Must be called with the originator hash locked
+ */
 static int find_best_vis_server(struct bat_priv *bat_priv,
 				struct vis_info *info)
 {
@@ -567,7 +581,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
 
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
-			router = orig_node_get_router(orig_node);
+			router = batadv_orig_node_get_router(orig_node);
 			if (!router)
 				continue;
 
@@ -577,7 +591,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
 				memcpy(packet->target_orig, orig_node->orig,
 				       ETH_ALEN);
 			}
-			neigh_node_free_ref(router);
+			batadv_neigh_node_free_ref(router);
 		}
 		rcu_read_unlock();
 	}
@@ -598,7 +612,8 @@ static bool vis_packet_full(const struct vis_info *info)
 }
 
 /* generates a packet of own vis data,
- * returns 0 on success, -1 if no packet could be generated */
+ * returns 0 on success, -1 if no packet could be generated
+ */
 static int generate_vis_packet(struct bat_priv *bat_priv)
 {
 	struct hashtable_t *hash = bat_priv->orig_hash;
@@ -616,7 +631,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
 	info->first_seen = jiffies;
 	packet->vis_type = atomic_read(&bat_priv->vis_mode);
 
-	memcpy(packet->target_orig, broadcast_addr, ETH_ALEN);
+	memcpy(packet->target_orig, batadv_broadcast_addr, ETH_ALEN);
 	packet->header.ttl = TTL;
 	packet->seqno = htonl(ntohl(packet->seqno) + 1);
 	packet->entries = 0;
@@ -626,7 +641,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
 		best_tq = find_best_vis_server(bat_priv, info);
 
 		if (best_tq < 0)
-			return -1;
+			return best_tq;
 	}
 
 	for (i = 0; i < hash->size; i++) {
@@ -634,11 +649,11 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
 
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
-			router = orig_node_get_router(orig_node);
+			router = batadv_orig_node_get_router(orig_node);
 			if (!router)
 				continue;
 
-			if (!compare_eth(router->addr, orig_node->orig))
+			if (!batadv_compare_eth(router->addr, orig_node->orig))
 				goto next;
 
 			if (router->if_incoming->if_status != IF_ACTIVE)
@@ -658,7 +673,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
 			packet->entries++;
 
 next:
-			neigh_node_free_ref(router);
+			batadv_neigh_node_free_ref(router);
 
 			if (vis_packet_full(info))
 				goto unlock;
@@ -696,7 +711,8 @@ unlock:
 }
 
 /* free old vis packets. Must be called with this vis_hash_lock
- * held */
+ * held
+ */
 static void purge_vis_packets(struct bat_priv *bat_priv)
 {
 	uint32_t i;
@@ -714,7 +730,8 @@ static void purge_vis_packets(struct bat_priv *bat_priv)
 			if (info == bat_priv->my_vis_info)
 				continue;
 
-			if (has_timed_out(info->first_seen, VIS_TIMEOUT)) {
+			if (batadv_has_timed_out(info->first_seen,
+						 VIS_TIMEOUT)) {
 				hlist_del(node);
 				send_list_del(info);
 				kref_put(&info->refcount, free_info);
@@ -750,15 +767,16 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv,
 			if (!(orig_node->flags & VIS_SERVER))
 				continue;
 
-			router = orig_node_get_router(orig_node);
+			router = batadv_orig_node_get_router(orig_node);
 			if (!router)
 				continue;
 
 			/* don't send it if we already received the packet from
-			 * this node. */
+			 * this node.
+			 */
 			if (recv_list_is_in(bat_priv, &info->recv_list,
 					    orig_node->orig)) {
-				neigh_node_free_ref(router);
+				batadv_neigh_node_free_ref(router);
 				continue;
 			}
 
@@ -766,11 +784,12 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv,
 			hard_iface = router->if_incoming;
 			memcpy(dstaddr, router->addr, ETH_ALEN);
 
-			neigh_node_free_ref(router);
+			batadv_neigh_node_free_ref(router);
 
 			skb = skb_clone(info->skb_packet, GFP_ATOMIC);
 			if (skb)
-				send_skb_packet(skb, hard_iface, dstaddr);
+				batadv_send_skb_packet(skb, hard_iface,
+						       dstaddr);
 
 		}
 		rcu_read_unlock();
@@ -787,23 +806,23 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
 
 	packet = (struct vis_packet *)info->skb_packet->data;
 
-	orig_node = orig_hash_find(bat_priv, packet->target_orig);
+	orig_node = batadv_orig_hash_find(bat_priv, packet->target_orig);
 	if (!orig_node)
 		goto out;
 
-	router = orig_node_get_router(orig_node);
+	router = batadv_orig_node_get_router(orig_node);
 	if (!router)
 		goto out;
 
 	skb = skb_clone(info->skb_packet, GFP_ATOMIC);
 	if (skb)
-		send_skb_packet(skb, router->if_incoming, router->addr);
+		batadv_send_skb_packet(skb, router->if_incoming, router->addr);
 
 out:
 	if (router)
-		neigh_node_free_ref(router);
+		batadv_neigh_node_free_ref(router);
 	if (orig_node)
-		orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
 }
 
 /* only send one vis packet. called from send_vis_packets() */
@@ -812,7 +831,7 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info)
 	struct hard_iface *primary_if;
 	struct vis_packet *packet;
 
-	primary_if = primary_if_get_selected(bat_priv);
+	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
 		goto out;
 
@@ -833,7 +852,7 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info)
 
 out:
 	if (primary_if)
-		hardif_free_ref(primary_if);
+		batadv_hardif_free_ref(primary_if);
 }
 
 /* called from timer; send (and maybe generate) vis packet. */
@@ -871,18 +890,19 @@ static void send_vis_packets(struct work_struct *work)
 }
 
 /* init the vis server. this may only be called when if_list is already
- * initialized (e.g. bat0 is initialized, interfaces have been added) */
-int vis_init(struct bat_priv *bat_priv)
+ * initialized (e.g. bat0 is initialized, interfaces have been added)
+ */
+int batadv_vis_init(struct bat_priv *bat_priv)
 {
 	struct vis_packet *packet;
 	int hash_added;
 
 	if (bat_priv->vis_hash)
-		return 1;
+		return 0;
 
 	spin_lock_bh(&bat_priv->vis_hash_lock);
 
-	bat_priv->vis_hash = hash_new(256);
+	bat_priv->vis_hash = batadv_hash_new(256);
 	if (!bat_priv->vis_hash) {
 		pr_err("Can't initialize vis_hash\n");
 		goto err;
@@ -917,9 +937,9 @@ int vis_init(struct bat_priv *bat_priv)
 
 	INIT_LIST_HEAD(&bat_priv->vis_send_list);
 
-	hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
-			      bat_priv->my_vis_info,
-			      &bat_priv->my_vis_info->hash_entry);
+	hash_added = batadv_hash_add(bat_priv->vis_hash, vis_info_cmp,
+				     vis_info_choose, bat_priv->my_vis_info,
+				     &bat_priv->my_vis_info->hash_entry);
 	if (hash_added != 0) {
 		pr_err("Can't add own vis packet into hash\n");
 		/* not in hash, need to remove it manually. */
@@ -929,15 +949,15 @@ int vis_init(struct bat_priv *bat_priv)
 
 	spin_unlock_bh(&bat_priv->vis_hash_lock);
 	start_vis_timer(bat_priv);
-	return 1;
+	return 0;
 
 free_info:
 	kfree(bat_priv->my_vis_info);
 	bat_priv->my_vis_info = NULL;
 err:
 	spin_unlock_bh(&bat_priv->vis_hash_lock);
-	vis_quit(bat_priv);
-	return 0;
+	batadv_vis_quit(bat_priv);
+	return -ENOMEM;
 }
 
 /* Decrease the reference count on a hash item info */
@@ -951,7 +971,7 @@ static void free_info_ref(struct hlist_node *node, void *arg)
 }
 
 /* shutdown vis-server */
-void vis_quit(struct bat_priv *bat_priv)
+void batadv_vis_quit(struct bat_priv *bat_priv)
 {
 	if (!bat_priv->vis_hash)
 		return;
@@ -960,7 +980,7 @@ void vis_quit(struct bat_priv *bat_priv)
 
 	spin_lock_bh(&bat_priv->vis_hash_lock);
 	/* properly remove, kill timers ... */
-	hash_delete(bat_priv->vis_hash, free_info_ref, NULL);
+	batadv_hash_delete(bat_priv->vis_hash, free_info_ref, NULL);
 	bat_priv->vis_hash = NULL;
 	bat_priv->my_vis_info = NULL;
 	spin_unlock_bh(&bat_priv->vis_hash_lock);
@@ -970,6 +990,6 @@ void vis_quit(struct bat_priv *bat_priv)
 static void start_vis_timer(struct bat_priv *bat_priv)
 {
 	INIT_DELAYED_WORK(&bat_priv->vis_work, send_vis_packets);
-	queue_delayed_work(bat_event_workqueue, &bat_priv->vis_work,
+	queue_delayed_work(batadv_event_workqueue, &bat_priv->vis_work,
 			   msecs_to_jiffies(VIS_INTERVAL));
 }
diff --git a/net/batman-adv/vis.h b/net/batman-adv/vis.h
index ee2e46e..dad5958 100644
--- a/net/batman-adv/vis.h
+++ b/net/batman-adv/vis.h
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2008-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2008-2012 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
@@ -16,23 +15,22 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  * 02110-1301, USA
- *
  */
 
 #ifndef _NET_BATMAN_ADV_VIS_H_
 #define _NET_BATMAN_ADV_VIS_H_
 
-#define VIS_TIMEOUT		200000	/* timeout of vis packets
-					 * in miliseconds */
+/* timeout of vis packets in miliseconds */
+#define VIS_TIMEOUT		200000
 
-int vis_seq_print_text(struct seq_file *seq, void *offset);
-void receive_server_sync_packet(struct bat_priv *bat_priv,
-				struct vis_packet *vis_packet,
-				int vis_info_len);
-void receive_client_update_packet(struct bat_priv *bat_priv,
-				  struct vis_packet *vis_packet,
-				  int vis_info_len);
-int vis_init(struct bat_priv *bat_priv);
-void vis_quit(struct bat_priv *bat_priv);
+int batadv_vis_seq_print_text(struct seq_file *seq, void *offset);
+void batadv_receive_server_sync_packet(struct bat_priv *bat_priv,
+				       struct vis_packet *vis_packet,
+				       int vis_info_len);
+void batadv_receive_client_update_packet(struct bat_priv *bat_priv,
+					 struct vis_packet *vis_packet,
+					 int vis_info_len);
+int batadv_vis_init(struct bat_priv *bat_priv);
+void batadv_vis_quit(struct bat_priv *bat_priv);
 
 #endif /* _NET_BATMAN_ADV_VIS_H_ */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index 2dc5a57..fa6d94a 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_BT_CMTP)	+= cmtp/
 obj-$(CONFIG_BT_HIDP)	+= hidp/
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
-	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
+	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
+	a2mp.o
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
new file mode 100644
index 0000000..fb93250
--- /dev/null
+++ b/net/bluetooth/a2mp.c
@@ -0,0 +1,568 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only version 2 as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/a2mp.h>
+
+/* A2MP build & send command helper functions */
+static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
+{
+	struct a2mp_cmd *cmd;
+	int plen;
+
+	plen = sizeof(*cmd) + len;
+	cmd = kzalloc(plen, GFP_KERNEL);
+	if (!cmd)
+		return NULL;
+
+	cmd->code = code;
+	cmd->ident = ident;
+	cmd->len = cpu_to_le16(len);
+
+	memcpy(cmd->data, data, len);
+
+	return cmd;
+}
+
+static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
+		      void *data)
+{
+	struct l2cap_chan *chan = mgr->a2mp_chan;
+	struct a2mp_cmd *cmd;
+	u16 total_len = len + sizeof(*cmd);
+	struct kvec iv;
+	struct msghdr msg;
+
+	cmd = __a2mp_build(code, ident, len, data);
+	if (!cmd)
+		return;
+
+	iv.iov_base = cmd;
+	iv.iov_len = total_len;
+
+	memset(&msg, 0, sizeof(msg));
+
+	msg.msg_iov = (struct iovec *) &iv;
+	msg.msg_iovlen = 1;
+
+	l2cap_chan_send(chan, &msg, total_len, 0);
+
+	kfree(cmd);
+}
+
+static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
+{
+	cl->id = 0;
+	cl->type = 0;
+	cl->status = 1;
+}
+
+/* hci_dev_list shall be locked */
+static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl)
+{
+	int i = 0;
+	struct hci_dev *hdev;
+
+	__a2mp_cl_bredr(cl);
+
+	list_for_each_entry(hdev, &hci_dev_list, list) {
+		/* Iterate through AMP controllers */
+		if (hdev->id == HCI_BREDR_ID)
+			continue;
+
+		/* Starting from second entry */
+		if (++i >= num_ctrl)
+			return;
+
+		cl[i].id = hdev->id;
+		cl[i].type = hdev->amp_type;
+		cl[i].status = hdev->amp_status;
+	}
+}
+
+/* Processing A2MP messages */
+static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
+			    struct a2mp_cmd *hdr)
+{
+	struct a2mp_cmd_rej *rej = (void *) skb->data;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*rej))
+		return -EINVAL;
+
+	BT_DBG("ident %d reason %d", hdr->ident, le16_to_cpu(rej->reason));
+
+	skb_pull(skb, sizeof(*rej));
+
+	return 0;
+}
+
+static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
+			     struct a2mp_cmd *hdr)
+{
+	struct a2mp_discov_req *req = (void *) skb->data;
+	u16 len = le16_to_cpu(hdr->len);
+	struct a2mp_discov_rsp *rsp;
+	u16 ext_feat;
+	u8 num_ctrl;
+
+	if (len < sizeof(*req))
+		return -EINVAL;
+
+	skb_pull(skb, sizeof(*req));
+
+	ext_feat = le16_to_cpu(req->ext_feat);
+
+	BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat);
+
+	/* check that packet is not broken for now */
+	while (ext_feat & A2MP_FEAT_EXT) {
+		if (len < sizeof(ext_feat))
+			return -EINVAL;
+
+		ext_feat = get_unaligned_le16(skb->data);
+		BT_DBG("efm 0x%4.4x", ext_feat);
+		len -= sizeof(ext_feat);
+		skb_pull(skb, sizeof(ext_feat));
+	}
+
+	read_lock(&hci_dev_list_lock);
+
+	num_ctrl = __hci_num_ctrl();
+	len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);
+	rsp = kmalloc(len, GFP_ATOMIC);
+	if (!rsp) {
+		read_unlock(&hci_dev_list_lock);
+		return -ENOMEM;
+	}
+
+	rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
+	rsp->ext_feat = 0;
+
+	__a2mp_add_cl(mgr, rsp->cl, num_ctrl);
+
+	read_unlock(&hci_dev_list_lock);
+
+	a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp);
+
+	kfree(rsp);
+	return 0;
+}
+
+static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
+			      struct a2mp_cmd *hdr)
+{
+	struct a2mp_cl *cl = (void *) skb->data;
+
+	while (skb->len >= sizeof(*cl)) {
+		BT_DBG("Controller id %d type %d status %d", cl->id, cl->type,
+		       cl->status);
+		cl = (struct a2mp_cl *) skb_pull(skb, sizeof(*cl));
+	}
+
+	/* TODO send A2MP_CHANGE_RSP */
+
+	return 0;
+}
+
+static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
+			    struct a2mp_cmd *hdr)
+{
+	struct a2mp_info_req *req  = (void *) skb->data;
+	struct a2mp_info_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("id %d", req->id);
+
+	rsp.id = req->id;
+	rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+	hdev = hci_dev_get(req->id);
+	if (hdev && hdev->amp_type != HCI_BREDR) {
+		rsp.status = 0;
+		rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
+		rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
+		rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
+		rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
+		rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+	}
+
+	if (hdev)
+		hci_dev_put(hdev);
+
+	a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
+static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				struct a2mp_cmd *hdr)
+{
+	struct a2mp_amp_assoc_req *req = (void *) skb->data;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("id %d", req->id);
+
+	hdev = hci_dev_get(req->id);
+	if (!hdev || hdev->amp_type == HCI_BREDR) {
+		struct a2mp_amp_assoc_rsp rsp;
+		rsp.id = req->id;
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+		a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
+			  &rsp);
+		goto clean;
+	}
+
+	/* Placeholder for HCI Read AMP Assoc */
+
+clean:
+	if (hdev)
+		hci_dev_put(hdev);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
+static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				   struct a2mp_cmd *hdr)
+{
+	struct a2mp_physlink_req *req = (void *) skb->data;
+
+	struct a2mp_physlink_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id);
+
+	rsp.local_id = req->remote_id;
+	rsp.remote_id = req->local_id;
+
+	hdev = hci_dev_get(req->remote_id);
+	if (!hdev || hdev->amp_type != HCI_AMP) {
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+		goto send_rsp;
+	}
+
+	/* TODO process physlink create */
+
+	rsp.status = A2MP_STATUS_SUCCESS;
+
+send_rsp:
+	if (hdev)
+		hci_dev_put(hdev);
+
+	a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp),
+		  &rsp);
+
+	skb_pull(skb, le16_to_cpu(hdr->len));
+	return 0;
+}
+
+static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				 struct a2mp_cmd *hdr)
+{
+	struct a2mp_physlink_req *req = (void *) skb->data;
+	struct a2mp_physlink_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id);
+
+	rsp.local_id = req->remote_id;
+	rsp.remote_id = req->local_id;
+	rsp.status = A2MP_STATUS_SUCCESS;
+
+	hdev = hci_dev_get(req->local_id);
+	if (!hdev) {
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+		goto send_rsp;
+	}
+
+	/* TODO Disconnect Phys Link here */
+
+	hci_dev_put(hdev);
+
+send_rsp:
+	a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
+static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+			       struct a2mp_cmd *hdr)
+{
+	BT_DBG("ident %d code %d", hdr->ident, hdr->code);
+
+	skb_pull(skb, le16_to_cpu(hdr->len));
+	return 0;
+}
+
+/* Handle A2MP signalling */
+static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+	struct a2mp_cmd *hdr = (void *) skb->data;
+	struct amp_mgr *mgr = chan->data;
+	int err = 0;
+
+	amp_mgr_get(mgr);
+
+	while (skb->len >= sizeof(*hdr)) {
+		struct a2mp_cmd *hdr = (void *) skb->data;
+		u16 len = le16_to_cpu(hdr->len);
+
+		BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
+
+		skb_pull(skb, sizeof(*hdr));
+
+		if (len > skb->len || !hdr->ident) {
+			err = -EINVAL;
+			break;
+		}
+
+		mgr->ident = hdr->ident;
+
+		switch (hdr->code) {
+		case A2MP_COMMAND_REJ:
+			a2mp_command_rej(mgr, skb, hdr);
+			break;
+
+		case A2MP_DISCOVER_REQ:
+			err = a2mp_discover_req(mgr, skb, hdr);
+			break;
+
+		case A2MP_CHANGE_NOTIFY:
+			err = a2mp_change_notify(mgr, skb, hdr);
+			break;
+
+		case A2MP_GETINFO_REQ:
+			err = a2mp_getinfo_req(mgr, skb, hdr);
+			break;
+
+		case A2MP_GETAMPASSOC_REQ:
+			err = a2mp_getampassoc_req(mgr, skb, hdr);
+			break;
+
+		case A2MP_CREATEPHYSLINK_REQ:
+			err = a2mp_createphyslink_req(mgr, skb, hdr);
+			break;
+
+		case A2MP_DISCONNPHYSLINK_REQ:
+			err = a2mp_discphyslink_req(mgr, skb, hdr);
+			break;
+
+		case A2MP_CHANGE_RSP:
+		case A2MP_DISCOVER_RSP:
+		case A2MP_GETINFO_RSP:
+		case A2MP_GETAMPASSOC_RSP:
+		case A2MP_CREATEPHYSLINK_RSP:
+		case A2MP_DISCONNPHYSLINK_RSP:
+			err = a2mp_cmd_rsp(mgr, skb, hdr);
+			break;
+
+		default:
+			BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
+			err = -EINVAL;
+			break;
+		}
+	}
+
+	if (err) {
+		struct a2mp_cmd_rej rej;
+		rej.reason = __constant_cpu_to_le16(0);
+
+		BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
+
+		a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej),
+			  &rej);
+	}
+
+	/* Always free skb and return success error code to prevent
+	   from sending L2CAP Disconnect over A2MP channel */
+	kfree_skb(skb);
+
+	amp_mgr_put(mgr);
+
+	return 0;
+}
+
+static void a2mp_chan_close_cb(struct l2cap_chan *chan)
+{
+	l2cap_chan_destroy(chan);
+}
+
+static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state)
+{
+	struct amp_mgr *mgr = chan->data;
+
+	if (!mgr)
+		return;
+
+	BT_DBG("chan %p state %s", chan, state_to_string(state));
+
+	chan->state = state;
+
+	switch (state) {
+	case BT_CLOSED:
+		if (mgr)
+			amp_mgr_put(mgr);
+		break;
+	}
+}
+
+static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
+					      unsigned long len, int nb)
+{
+	return bt_skb_alloc(len, GFP_KERNEL);
+}
+
+static struct l2cap_ops a2mp_chan_ops = {
+	.name = "L2CAP A2MP channel",
+	.recv = a2mp_chan_recv_cb,
+	.close = a2mp_chan_close_cb,
+	.state_change = a2mp_chan_state_change_cb,
+	.alloc_skb = a2mp_chan_alloc_skb_cb,
+
+	/* Not implemented for A2MP */
+	.new_connection = l2cap_chan_no_new_connection,
+	.teardown = l2cap_chan_no_teardown,
+	.ready = l2cap_chan_no_ready,
+};
+
+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
+{
+	struct l2cap_chan *chan;
+	int err;
+
+	chan = l2cap_chan_create();
+	if (!chan)
+		return NULL;
+
+	BT_DBG("chan %p", chan);
+
+	chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
+	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+
+	chan->ops = &a2mp_chan_ops;
+
+	l2cap_chan_set_defaults(chan);
+	chan->remote_max_tx = chan->max_tx;
+	chan->remote_tx_win = chan->tx_win;
+
+	chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
+	chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
+
+	skb_queue_head_init(&chan->tx_q);
+
+	chan->mode = L2CAP_MODE_ERTM;
+
+	err = l2cap_ertm_init(chan);
+	if (err < 0) {
+		l2cap_chan_del(chan, 0);
+		return NULL;
+	}
+
+	chan->conf_state = 0;
+
+	l2cap_chan_add(conn, chan);
+
+	chan->remote_mps = chan->omtu;
+	chan->mps = chan->omtu;
+
+	chan->state = BT_CONNECTED;
+
+	return chan;
+}
+
+/* AMP Manager functions */
+void amp_mgr_get(struct amp_mgr *mgr)
+{
+	BT_DBG("mgr %p", mgr);
+
+	kref_get(&mgr->kref);
+}
+
+static void amp_mgr_destroy(struct kref *kref)
+{
+	struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
+
+	BT_DBG("mgr %p", mgr);
+
+	kfree(mgr);
+}
+
+int amp_mgr_put(struct amp_mgr *mgr)
+{
+	BT_DBG("mgr %p", mgr);
+
+	return kref_put(&mgr->kref, &amp_mgr_destroy);
+}
+
+static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
+{
+	struct amp_mgr *mgr;
+	struct l2cap_chan *chan;
+
+	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+	if (!mgr)
+		return NULL;
+
+	BT_DBG("conn %p mgr %p", conn, mgr);
+
+	mgr->l2cap_conn = conn;
+
+	chan = a2mp_chan_open(conn);
+	if (!chan) {
+		kfree(mgr);
+		return NULL;
+	}
+
+	mgr->a2mp_chan = chan;
+	chan->data = mgr;
+
+	conn->hcon->amp_mgr = mgr;
+
+	kref_init(&mgr->kref);
+
+	return mgr;
+}
+
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+				       struct sk_buff *skb)
+{
+	struct amp_mgr *mgr;
+
+	mgr = amp_mgr_create(conn);
+	if (!mgr) {
+		BT_ERR("Could not create AMP manager");
+		return NULL;
+	}
+
+	BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
+
+	return mgr->a2mp_chan;
+}
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 3e18af4..f7db579 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -25,18 +25,7 @@
 /* Bluetooth address family and sockets. */
 
 #include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <net/sock.h>
 #include <asm/ioctls.h>
-#include <linux/kmod.h>
 
 #include <net/bluetooth/bluetooth.h>
 
@@ -418,7 +407,8 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
 	return 0;
 }
 
-unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait)
+unsigned int bt_sock_poll(struct file *file, struct socket *sock,
+			  poll_table *wait)
 {
 	struct sock *sk = sock->sk;
 	unsigned int mask = 0;
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 031d7d6..4a6620b 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -26,26 +26,9 @@
 */
 
 #include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/freezer.h>
-#include <linux/errno.h>
-#include <linux/net.h>
-#include <linux/slab.h>
 #include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/socket.h>
 #include <linux/file.h>
-
-#include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -306,7 +289,7 @@ static u8 __bnep_rx_hlen[] = {
 	ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
 };
 
-static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
 {
 	struct net_device *dev = s->dev;
 	struct sk_buff *nskb;
@@ -404,7 +387,7 @@ static u8 __bnep_tx_types[] = {
 	BNEP_COMPRESSED
 };
 
-static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
 {
 	struct ethhdr *eh = (void *) skb->data;
 	struct socket *sock = s->sock;
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
index bc40864..98f86f9 100644
--- a/net/bluetooth/bnep/netdev.c
+++ b/net/bluetooth/bnep/netdev.c
@@ -25,16 +25,8 @@
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <linux/socket.h>
-#include <linux/netdevice.h>
+#include <linux/export.h>
 #include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/wait.h>
-
-#include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -128,7 +120,7 @@ static void bnep_net_timeout(struct net_device *dev)
 }
 
 #ifdef CONFIG_BT_BNEP_MC_FILTER
-static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
+static int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
 {
 	struct ethhdr *eh = (void *) skb->data;
 
@@ -140,7 +132,7 @@ static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s
 
 #ifdef CONFIG_BT_BNEP_PROTO_FILTER
 /* Determine ether protocol. Based on eth_type_trans. */
-static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
+static u16 bnep_net_eth_proto(struct sk_buff *skb)
 {
 	struct ethhdr *eh = (void *) skb->data;
 	u16 proto = ntohs(eh->h_proto);
@@ -154,7 +146,7 @@ static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
 	return ETH_P_802_2;
 }
 
-static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
+static int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
 {
 	u16 proto = bnep_net_eth_proto(skb);
 	struct bnep_proto_filter *f = s->proto_filter;
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index 180bfc4..5e5f5b4 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -24,24 +24,8 @@
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
+#include <linux/export.h>
 #include <linux/file.h>
-#include <linux/init.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <net/sock.h>
-
 
 #include "bnep.h"
 
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 3f18a6e..2fcced3 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -24,24 +24,11 @@
 
 /* Bluetooth HCI connection handling. */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/export.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/a2mp.h>
 
 static void hci_le_connect(struct hci_conn *conn)
 {
@@ -54,15 +41,15 @@ static void hci_le_connect(struct hci_conn *conn)
 	conn->sec_level = BT_SECURITY_LOW;
 
 	memset(&cp, 0, sizeof(cp));
-	cp.scan_interval = cpu_to_le16(0x0060);
-	cp.scan_window = cpu_to_le16(0x0030);
+	cp.scan_interval = __constant_cpu_to_le16(0x0060);
+	cp.scan_window = __constant_cpu_to_le16(0x0030);
 	bacpy(&cp.peer_addr, &conn->dst);
 	cp.peer_addr_type = conn->dst_type;
-	cp.conn_interval_min = cpu_to_le16(0x0028);
-	cp.conn_interval_max = cpu_to_le16(0x0038);
-	cp.supervision_timeout = cpu_to_le16(0x002a);
-	cp.min_ce_len = cpu_to_le16(0x0000);
-	cp.max_ce_len = cpu_to_le16(0x0000);
+	cp.conn_interval_min = __constant_cpu_to_le16(0x0028);
+	cp.conn_interval_max = __constant_cpu_to_le16(0x0038);
+	cp.supervision_timeout = __constant_cpu_to_le16(0x002a);
+	cp.min_ce_len = __constant_cpu_to_le16(0x0000);
+	cp.max_ce_len = __constant_cpu_to_le16(0x0000);
 
 	hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
 }
@@ -99,7 +86,7 @@ void hci_acl_connect(struct hci_conn *conn)
 			cp.pscan_rep_mode = ie->data.pscan_rep_mode;
 			cp.pscan_mode     = ie->data.pscan_mode;
 			cp.clock_offset   = ie->data.clock_offset |
-							cpu_to_le16(0x8000);
+					    __constant_cpu_to_le16(0x8000);
 		}
 
 		memcpy(conn->dev_class, ie->data.dev_class, 3);
@@ -175,9 +162,9 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
 	cp.handle   = cpu_to_le16(handle);
 	cp.pkt_type = cpu_to_le16(conn->pkt_type);
 
-	cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
-	cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
-	cp.max_latency    = cpu_to_le16(0xffff);
+	cp.tx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
+	cp.rx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
+	cp.max_latency    = __constant_cpu_to_le16(0xffff);
 	cp.voice_setting  = cpu_to_le16(hdev->voice_setting);
 	cp.retrans_effort = 0xff;
 
@@ -185,7 +172,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
 }
 
 void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
-					u16 latency, u16 to_multiplier)
+			u16 latency, u16 to_multiplier)
 {
 	struct hci_cp_le_conn_update cp;
 	struct hci_dev *hdev = conn->hdev;
@@ -197,15 +184,14 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
 	cp.conn_interval_max	= cpu_to_le16(max);
 	cp.conn_latency		= cpu_to_le16(latency);
 	cp.supervision_timeout	= cpu_to_le16(to_multiplier);
-	cp.min_ce_len		= cpu_to_le16(0x0001);
-	cp.max_ce_len		= cpu_to_le16(0x0001);
+	cp.min_ce_len		= __constant_cpu_to_le16(0x0001);
+	cp.max_ce_len		= __constant_cpu_to_le16(0x0001);
 
 	hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
 }
-EXPORT_SYMBOL(hci_le_conn_update);
 
 void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
-							__u8 ltk[16])
+		      __u8 ltk[16])
 {
 	struct hci_dev *hdev = conn->hdev;
 	struct hci_cp_le_start_enc cp;
@@ -221,7 +207,6 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
 
 	hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
 }
-EXPORT_SYMBOL(hci_le_start_enc);
 
 /* Device _must_ be locked */
 void hci_sco_setup(struct hci_conn *conn, __u8 status)
@@ -247,7 +232,7 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)
 static void hci_conn_timeout(struct work_struct *work)
 {
 	struct hci_conn *conn = container_of(work, struct hci_conn,
-							disc_work.work);
+					     disc_work.work);
 	__u8 reason;
 
 	BT_DBG("conn %p state %s", conn, state_to_string(conn->state));
@@ -295,9 +280,9 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
 	if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
 		struct hci_cp_sniff_subrate cp;
 		cp.handle             = cpu_to_le16(conn->handle);
-		cp.max_latency        = cpu_to_le16(0);
-		cp.min_remote_timeout = cpu_to_le16(0);
-		cp.min_local_timeout  = cpu_to_le16(0);
+		cp.max_latency        = __constant_cpu_to_le16(0);
+		cp.min_remote_timeout = __constant_cpu_to_le16(0);
+		cp.min_local_timeout  = __constant_cpu_to_le16(0);
 		hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
 	}
 
@@ -306,8 +291,8 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
 		cp.handle       = cpu_to_le16(conn->handle);
 		cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
 		cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
-		cp.attempt      = cpu_to_le16(4);
-		cp.timeout      = cpu_to_le16(1);
+		cp.attempt      = __constant_cpu_to_le16(4);
+		cp.timeout      = __constant_cpu_to_le16(1);
 		hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
 	}
 }
@@ -327,7 +312,7 @@ static void hci_conn_auto_accept(unsigned long arg)
 	struct hci_dev *hdev = conn->hdev;
 
 	hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst),
-								&conn->dst);
+		     &conn->dst);
 }
 
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
@@ -376,7 +361,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 	INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
 	setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
 	setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
-							(unsigned long) conn);
+		    (unsigned long) conn);
 
 	atomic_set(&conn->refcnt, 0);
 
@@ -425,9 +410,11 @@ int hci_conn_del(struct hci_conn *conn)
 		}
 	}
 
-
 	hci_chan_list_flush(conn);
 
+	if (conn->amp_mgr)
+		amp_mgr_put(conn->amp_mgr);
+
 	hci_conn_hash_del(hdev, conn);
 	if (hdev->notify)
 		hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
@@ -454,7 +441,8 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
 	read_lock(&hci_dev_list_lock);
 
 	list_for_each_entry(d, &hci_dev_list, list) {
-		if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
+		if (!test_bit(HCI_UP, &d->flags) ||
+		    test_bit(HCI_RAW, &d->flags))
 			continue;
 
 		/* Simple routing:
@@ -495,6 +483,11 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
 	if (type == LE_LINK) {
 		le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
 		if (!le) {
+			le = hci_conn_hash_lookup_state(hdev, LE_LINK,
+							BT_CONNECT);
+			if (le)
+				return ERR_PTR(-EBUSY);
+
 			le = hci_conn_add(hdev, LE_LINK, dst);
 			if (!le)
 				return ERR_PTR(-ENOMEM);
@@ -545,7 +538,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
 	hci_conn_hold(sco);
 
 	if (acl->state == BT_CONNECTED &&
-			(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
+	    (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
 		set_bit(HCI_CONN_POWER_SAVE, &acl->flags);
 		hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
 
@@ -560,7 +553,6 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
 
 	return sco;
 }
-EXPORT_SYMBOL(hci_connect);
 
 /* Check link security requirement */
 int hci_conn_check_link_mode(struct hci_conn *conn)
@@ -572,7 +564,6 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
 
 	return 1;
 }
-EXPORT_SYMBOL(hci_conn_check_link_mode);
 
 /* Authenticate remote device */
 static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
@@ -600,7 +591,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 
 		cp.handle = cpu_to_le16(conn->handle);
 		hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
-							sizeof(cp), &cp);
+			     sizeof(cp), &cp);
 		if (conn->key_type != 0xff)
 			set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
 	}
@@ -618,7 +609,7 @@ static void hci_conn_encrypt(struct hci_conn *conn)
 		cp.handle  = cpu_to_le16(conn->handle);
 		cp.encrypt = 0x01;
 		hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
-									&cp);
+			     &cp);
 	}
 }
 
@@ -648,8 +639,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 	/* An unauthenticated combination key has sufficient security for
 	   security level 1 and 2. */
 	if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
-			(sec_level == BT_SECURITY_MEDIUM ||
-			sec_level == BT_SECURITY_LOW))
+	    (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW))
 		goto encrypt;
 
 	/* A combination key has always sufficient security for the security
@@ -657,8 +647,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 	   is generated using maximum PIN code length (16).
 	   For pre 2.1 units. */
 	if (conn->key_type == HCI_LK_COMBINATION &&
-			(sec_level != BT_SECURITY_HIGH ||
-			conn->pin_length == 16))
+	    (sec_level != BT_SECURITY_HIGH || conn->pin_length == 16))
 		goto encrypt;
 
 auth:
@@ -701,12 +690,11 @@ int hci_conn_change_link_key(struct hci_conn *conn)
 		struct hci_cp_change_conn_link_key cp;
 		cp.handle = cpu_to_le16(conn->handle);
 		hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
-							sizeof(cp), &cp);
+			     sizeof(cp), &cp);
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL(hci_conn_change_link_key);
 
 /* Switch role */
 int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
@@ -752,7 +740,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
 timer:
 	if (hdev->idle_timeout > 0)
 		mod_timer(&conn->idle_timer,
-			jiffies + msecs_to_jiffies(hdev->idle_timeout));
+			  jiffies + msecs_to_jiffies(hdev->idle_timeout));
 }
 
 /* Drop all connection on the device */
@@ -802,7 +790,7 @@ EXPORT_SYMBOL(hci_conn_put_device);
 
 int hci_get_conn_list(void __user *arg)
 {
-	register struct hci_conn *c;
+	struct hci_conn *c;
 	struct hci_conn_list_req req, *cl;
 	struct hci_conn_info *ci;
 	struct hci_dev *hdev;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 411ace8..32dcb09 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -25,34 +25,14 @@
 
 /* Bluetooth HCI core. */
 
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/kmod.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/rfkill.h>
-#include <linux/timer.h>
-#include <linux/crypto.h>
-#include <net/sock.h>
+#include <linux/export.h>
+#include <linux/idr.h>
 
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/rfkill.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#define AUTO_OFF_TIMEOUT 2000
-
 static void hci_rx_work(struct work_struct *work);
 static void hci_cmd_work(struct work_struct *work);
 static void hci_tx_work(struct work_struct *work);
@@ -65,6 +45,9 @@ DEFINE_RWLOCK(hci_dev_list_lock);
 LIST_HEAD(hci_cb_list);
 DEFINE_RWLOCK(hci_cb_list_lock);
 
+/* HCI ID Numbering */
+static DEFINE_IDA(hci_index_ida);
+
 /* ---- HCI notifications ---- */
 
 static void hci_notify(struct hci_dev *hdev, int event)
@@ -76,7 +59,7 @@ static void hci_notify(struct hci_dev *hdev, int event)
 
 void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
 {
-	BT_DBG("%s command 0x%04x result 0x%2.2x", hdev->name, cmd, result);
+	BT_DBG("%s command 0x%4.4x result 0x%2.2x", hdev->name, cmd, result);
 
 	/* If this is the init phase check if the completed command matches
 	 * the last init command, and if not just return.
@@ -124,8 +107,9 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
 }
 
 /* Execute request and wait for completion. */
-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
-					unsigned long opt, __u32 timeout)
+static int __hci_request(struct hci_dev *hdev,
+			 void (*req)(struct hci_dev *hdev, unsigned long opt),
+			 unsigned long opt, __u32 timeout)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	int err = 0;
@@ -166,8 +150,9 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
 	return err;
 }
 
-static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
-					unsigned long opt, __u32 timeout)
+static int hci_request(struct hci_dev *hdev,
+		       void (*req)(struct hci_dev *hdev, unsigned long opt),
+		       unsigned long opt, __u32 timeout)
 {
 	int ret;
 
@@ -201,12 +186,6 @@ static void bredr_init(struct hci_dev *hdev)
 
 	/* Mandatory initialization */
 
-	/* Reset */
-	if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
-		set_bit(HCI_RESET, &hdev->flags);
-		hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
-	}
-
 	/* Read Local Supported Features */
 	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
 
@@ -235,7 +214,7 @@ static void bredr_init(struct hci_dev *hdev)
 	hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
 
 	/* Connection accept timeout ~20 secs */
-	param = cpu_to_le16(0x7d00);
+	param = __constant_cpu_to_le16(0x7d00);
 	hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
 
 	bacpy(&cp.bdaddr, BDADDR_ANY);
@@ -247,9 +226,6 @@ static void amp_init(struct hci_dev *hdev)
 {
 	hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
 
-	/* Reset */
-	hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
-
 	/* Read Local Version */
 	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
 
@@ -275,6 +251,10 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 	}
 	skb_queue_purge(&hdev->driver_init);
 
+	/* Reset */
+	if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks))
+		hci_reset_req(hdev, 0);
+
 	switch (hdev->dev_type) {
 	case HCI_BREDR:
 		bredr_init(hdev);
@@ -417,7 +397,8 @@ static void inquiry_cache_flush(struct hci_dev *hdev)
 	INIT_LIST_HEAD(&cache->resolve);
 }
 
-struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
+struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
+					       bdaddr_t *bdaddr)
 {
 	struct discovery_state *cache = &hdev->discovery;
 	struct inquiry_entry *e;
@@ -478,7 +459,7 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
 
 	list_for_each_entry(p, &cache->resolve, list) {
 		if (p->name_state != NAME_PENDING &&
-				abs(p->data.rssi) >= abs(ie->data.rssi))
+		    abs(p->data.rssi) >= abs(ie->data.rssi))
 			break;
 		pos = &p->list;
 	}
@@ -503,7 +484,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
 			*ssp = true;
 
 		if (ie->name_state == NAME_NEEDED &&
-						data->rssi != ie->data.rssi) {
+		    data->rssi != ie->data.rssi) {
 			ie->data.rssi = data->rssi;
 			hci_inquiry_cache_update_resolve(hdev, ie);
 		}
@@ -527,7 +508,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
 
 update:
 	if (name_known && ie->name_state != NAME_KNOWN &&
-					ie->name_state != NAME_PENDING) {
+	    ie->name_state != NAME_PENDING) {
 		ie->name_state = NAME_KNOWN;
 		list_del(&ie->list);
 	}
@@ -605,8 +586,7 @@ int hci_inquiry(void __user *arg)
 
 	hci_dev_lock(hdev);
 	if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
-				inquiry_cache_empty(hdev) ||
-				ir.flags & IREQ_CACHE_FLUSH) {
+	    inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) {
 		inquiry_cache_flush(hdev);
 		do_inquiry = 1;
 	}
@@ -620,7 +600,9 @@ int hci_inquiry(void __user *arg)
 			goto done;
 	}
 
-	/* for unlimited number of responses we will use buffer with 255 entries */
+	/* for unlimited number of responses we will use buffer with
+	 * 255 entries
+	 */
 	max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
 
 	/* cache_dump can't sleep. Therefore we allocate temp buffer and then
@@ -641,7 +623,7 @@ int hci_inquiry(void __user *arg)
 	if (!copy_to_user(ptr, &ir, sizeof(ir))) {
 		ptr += sizeof(ir);
 		if (copy_to_user(ptr, buf, sizeof(struct inquiry_info) *
-					ir.num_rsp))
+				 ir.num_rsp))
 			err = -EFAULT;
 	} else
 		err = -EFAULT;
@@ -701,12 +683,11 @@ int hci_dev_open(__u16 dev)
 		set_bit(HCI_INIT, &hdev->flags);
 		hdev->init_last_cmd = 0;
 
-		ret = __hci_request(hdev, hci_init_req, 0,
-					msecs_to_jiffies(HCI_INIT_TIMEOUT));
+		ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
 
 		if (lmp_host_le_capable(hdev))
 			ret = __hci_request(hdev, hci_le_init_req, 0,
-					msecs_to_jiffies(HCI_INIT_TIMEOUT));
+					    HCI_INIT_TIMEOUT);
 
 		clear_bit(HCI_INIT, &hdev->flags);
 	}
@@ -791,10 +772,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 	skb_queue_purge(&hdev->cmd_q);
 	atomic_set(&hdev->cmd_cnt, 1);
 	if (!test_bit(HCI_RAW, &hdev->flags) &&
-				test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
+	    test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
 		set_bit(HCI_INIT, &hdev->flags);
-		__hci_request(hdev, hci_reset_req, 0,
-					msecs_to_jiffies(250));
+		__hci_request(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT);
 		clear_bit(HCI_INIT, &hdev->flags);
 	}
 
@@ -883,8 +863,7 @@ int hci_dev_reset(__u16 dev)
 	hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
 
 	if (!test_bit(HCI_RAW, &hdev->flags))
-		ret = __hci_request(hdev, hci_reset_req, 0,
-					msecs_to_jiffies(HCI_INIT_TIMEOUT));
+		ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
 
 done:
 	hci_req_unlock(hdev);
@@ -924,7 +903,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
 	switch (cmd) {
 	case HCISETAUTH:
 		err = hci_request(hdev, hci_auth_req, dr.dev_opt,
-					msecs_to_jiffies(HCI_INIT_TIMEOUT));
+				  HCI_INIT_TIMEOUT);
 		break;
 
 	case HCISETENCRYPT:
@@ -936,23 +915,23 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
 		if (!test_bit(HCI_AUTH, &hdev->flags)) {
 			/* Auth must be enabled first */
 			err = hci_request(hdev, hci_auth_req, dr.dev_opt,
-					msecs_to_jiffies(HCI_INIT_TIMEOUT));
+					  HCI_INIT_TIMEOUT);
 			if (err)
 				break;
 		}
 
 		err = hci_request(hdev, hci_encrypt_req, dr.dev_opt,
-					msecs_to_jiffies(HCI_INIT_TIMEOUT));
+				  HCI_INIT_TIMEOUT);
 		break;
 
 	case HCISETSCAN:
 		err = hci_request(hdev, hci_scan_req, dr.dev_opt,
-					msecs_to_jiffies(HCI_INIT_TIMEOUT));
+				  HCI_INIT_TIMEOUT);
 		break;
 
 	case HCISETLINKPOL:
 		err = hci_request(hdev, hci_linkpol_req, dr.dev_opt,
-					msecs_to_jiffies(HCI_INIT_TIMEOUT));
+				  HCI_INIT_TIMEOUT);
 		break;
 
 	case HCISETLINKMODE:
@@ -1102,8 +1081,7 @@ static void hci_power_on(struct work_struct *work)
 		return;
 
 	if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
-		schedule_delayed_work(&hdev->power_off,
-					msecs_to_jiffies(AUTO_OFF_TIMEOUT));
+		schedule_delayed_work(&hdev->power_off, HCI_AUTO_OFF_TIMEOUT);
 
 	if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
 		mgmt_index_added(hdev);
@@ -1112,7 +1090,7 @@ static void hci_power_on(struct work_struct *work)
 static void hci_power_off(struct work_struct *work)
 {
 	struct hci_dev *hdev = container_of(work, struct hci_dev,
-							power_off.work);
+					    power_off.work);
 
 	BT_DBG("%s", hdev->name);
 
@@ -1193,7 +1171,7 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 }
 
 static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
-						u8 key_type, u8 old_key_type)
+			       u8 key_type, u8 old_key_type)
 {
 	/* Legacy key */
 	if (key_type < 0x03)
@@ -1234,7 +1212,7 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
 
 	list_for_each_entry(k, &hdev->long_term_keys, list) {
 		if (k->ediv != ediv ||
-				memcmp(rand, k->rand, sizeof(k->rand)))
+		    memcmp(rand, k->rand, sizeof(k->rand)))
 			continue;
 
 		return k;
@@ -1242,7 +1220,6 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
 
 	return NULL;
 }
-EXPORT_SYMBOL(hci_find_ltk);
 
 struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
 				     u8 addr_type)
@@ -1251,12 +1228,11 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
 
 	list_for_each_entry(k, &hdev->long_term_keys, list)
 		if (addr_type == k->bdaddr_type &&
-					bacmp(bdaddr, &k->bdaddr) == 0)
+		    bacmp(bdaddr, &k->bdaddr) == 0)
 			return k;
 
 	return NULL;
 }
-EXPORT_SYMBOL(hci_find_ltk_by_addr);
 
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
 		     bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
@@ -1283,15 +1259,14 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
 	 * combination key for legacy pairing even when there's no
 	 * previous key */
 	if (type == HCI_LK_CHANGED_COMBINATION &&
-					(!conn || conn->remote_auth == 0xff) &&
-					old_key_type == 0xff) {
+	    (!conn || conn->remote_auth == 0xff) && old_key_type == 0xff) {
 		type = HCI_LK_COMBINATION;
 		if (conn)
 			conn->key_type = type;
 	}
 
 	bacpy(&key->bdaddr, bdaddr);
-	memcpy(key->val, val, 16);
+	memcpy(key->val, val, HCI_LINK_KEY_SIZE);
 	key->pin_len = pin_len;
 
 	if (type == HCI_LK_CHANGED_COMBINATION)
@@ -1383,11 +1358,19 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr)
 }
 
 /* HCI command timer function */
-static void hci_cmd_timer(unsigned long arg)
+static void hci_cmd_timeout(unsigned long arg)
 {
 	struct hci_dev *hdev = (void *) arg;
 
-	BT_ERR("%s command tx timeout", hdev->name);
+	if (hdev->sent_cmd) {
+		struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
+		u16 opcode = __le16_to_cpu(sent->opcode);
+
+		BT_ERR("%s command 0x%4.4x tx timeout", hdev->name, opcode);
+	} else {
+		BT_ERR("%s command tx timeout", hdev->name);
+	}
+
 	atomic_set(&hdev->cmd_cnt, 1);
 	queue_work(hdev->workqueue, &hdev->cmd_work);
 }
@@ -1540,6 +1523,7 @@ static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
 
 	memset(&cp, 0, sizeof(cp));
 	cp.enable = 1;
+	cp.filter_dup = 1;
 
 	hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
 }
@@ -1684,7 +1668,7 @@ struct hci_dev *hci_alloc_dev(void)
 
 	init_waitqueue_head(&hdev->req_wait_q);
 
-	setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev);
+	setup_timer(&hdev->cmd_timer, hci_cmd_timeout, (unsigned long) hdev);
 
 	hci_init_sysfs(hdev);
 	discovery_init(hdev);
@@ -1707,41 +1691,39 @@ EXPORT_SYMBOL(hci_free_dev);
 /* Register HCI device */
 int hci_register_dev(struct hci_dev *hdev)
 {
-	struct list_head *head, *p;
 	int id, error;
 
 	if (!hdev->open || !hdev->close)
 		return -EINVAL;
 
-	write_lock(&hci_dev_list_lock);
-
 	/* Do not allow HCI_AMP devices to register at index 0,
 	 * so the index can be used as the AMP controller ID.
 	 */
-	id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
-	head = &hci_dev_list;
-
-	/* Find first available device id */
-	list_for_each(p, &hci_dev_list) {
-		int nid = list_entry(p, struct hci_dev, list)->id;
-		if (nid > id)
-			break;
-		if (nid == id)
-			id++;
-		head = p;
+	switch (hdev->dev_type) {
+	case HCI_BREDR:
+		id = ida_simple_get(&hci_index_ida, 0, 0, GFP_KERNEL);
+		break;
+	case HCI_AMP:
+		id = ida_simple_get(&hci_index_ida, 1, 0, GFP_KERNEL);
+		break;
+	default:
+		return -EINVAL;
 	}
 
+	if (id < 0)
+		return id;
+
 	sprintf(hdev->name, "hci%d", id);
 	hdev->id = id;
 
 	BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
-	list_add(&hdev->list, head);
-
+	write_lock(&hci_dev_list_lock);
+	list_add(&hdev->list, &hci_dev_list);
 	write_unlock(&hci_dev_list_lock);
 
 	hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
-							WQ_MEM_RECLAIM, 1);
+					  WQ_MEM_RECLAIM, 1);
 	if (!hdev->workqueue) {
 		error = -ENOMEM;
 		goto err;
@@ -1752,7 +1734,8 @@ int hci_register_dev(struct hci_dev *hdev)
 		goto err_wqueue;
 
 	hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
-				RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
+				    RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
+				    hdev);
 	if (hdev->rfkill) {
 		if (rfkill_register(hdev->rfkill) < 0) {
 			rfkill_destroy(hdev->rfkill);
@@ -1772,6 +1755,7 @@ int hci_register_dev(struct hci_dev *hdev)
 err_wqueue:
 	destroy_workqueue(hdev->workqueue);
 err:
+	ida_simple_remove(&hci_index_ida, hdev->id);
 	write_lock(&hci_dev_list_lock);
 	list_del(&hdev->list);
 	write_unlock(&hci_dev_list_lock);
@@ -1783,12 +1767,14 @@ EXPORT_SYMBOL(hci_register_dev);
 /* Unregister HCI device */
 void hci_unregister_dev(struct hci_dev *hdev)
 {
-	int i;
+	int i, id;
 
 	BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
 	set_bit(HCI_UNREGISTER, &hdev->dev_flags);
 
+	id = hdev->id;
+
 	write_lock(&hci_dev_list_lock);
 	list_del(&hdev->list);
 	write_unlock(&hci_dev_list_lock);
@@ -1799,7 +1785,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
 		kfree_skb(hdev->reassembly[i]);
 
 	if (!test_bit(HCI_INIT, &hdev->flags) &&
-				!test_bit(HCI_SETUP, &hdev->dev_flags)) {
+	    !test_bit(HCI_SETUP, &hdev->dev_flags)) {
 		hci_dev_lock(hdev);
 		mgmt_index_removed(hdev);
 		hci_dev_unlock(hdev);
@@ -1829,6 +1815,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
 	hci_dev_unlock(hdev);
 
 	hci_dev_put(hdev);
+
+	ida_simple_remove(&hci_index_ida, id);
 }
 EXPORT_SYMBOL(hci_unregister_dev);
 
@@ -1853,7 +1841,7 @@ int hci_recv_frame(struct sk_buff *skb)
 {
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 	if (!hdev || (!test_bit(HCI_UP, &hdev->flags)
-				&& !test_bit(HCI_INIT, &hdev->flags))) {
+		      && !test_bit(HCI_INIT, &hdev->flags))) {
 		kfree_skb(skb);
 		return -ENXIO;
 	}
@@ -1872,7 +1860,7 @@ int hci_recv_frame(struct sk_buff *skb)
 EXPORT_SYMBOL(hci_recv_frame);
 
 static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
-						  int count, __u8 index)
+			  int count, __u8 index)
 {
 	int len = 0;
 	int hlen = 0;
@@ -1881,7 +1869,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
 	struct bt_skb_cb *scb;
 
 	if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ||
-				index >= NUM_REASSEMBLY)
+	    index >= NUM_REASSEMBLY)
 		return -EILSEQ;
 
 	skb = hdev->reassembly[index];
@@ -2023,7 +2011,7 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
 			type = bt_cb(skb)->pkt_type;
 
 		rem = hci_reassembly(hdev, type, data, count,
-							STREAM_REASSEMBLY);
+				     STREAM_REASSEMBLY);
 		if (rem < 0)
 			return rem;
 
@@ -2096,7 +2084,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
 	struct hci_command_hdr *hdr;
 	struct sk_buff *skb;
 
-	BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen);
+	BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
 
 	skb = bt_skb_alloc(len, GFP_ATOMIC);
 	if (!skb) {
@@ -2138,7 +2126,7 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
 	if (hdr->opcode != cpu_to_le16(opcode))
 		return NULL;
 
-	BT_DBG("%s opcode 0x%x", hdev->name, opcode);
+	BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
 
 	return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
 }
@@ -2157,7 +2145,7 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
 }
 
 static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
-				struct sk_buff *skb, __u16 flags)
+			  struct sk_buff *skb, __u16 flags)
 {
 	struct hci_dev *hdev = conn->hdev;
 	struct sk_buff *list;
@@ -2208,7 +2196,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
 	struct hci_conn *conn = chan->conn;
 	struct hci_dev *hdev = conn->hdev;
 
-	BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags);
+	BT_DBG("%s chan %p flags 0x%4.4x", hdev->name, chan, flags);
 
 	skb->dev = (void *) hdev;
 
@@ -2216,7 +2204,6 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
 
 	queue_work(hdev->workqueue, &hdev->tx_work);
 }
-EXPORT_SYMBOL(hci_send_acl);
 
 /* Send SCO data */
 void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
@@ -2239,12 +2226,12 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
 	skb_queue_tail(&conn->data_q, skb);
 	queue_work(hdev->workqueue, &hdev->tx_work);
 }
-EXPORT_SYMBOL(hci_send_sco);
 
 /* ---- HCI TX task (outgoing data) ---- */
 
 /* HCI Connection scheduler */
-static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
+static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type,
+				     int *quote)
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct hci_conn *conn = NULL, *c;
@@ -2303,7 +2290,7 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
 	return conn;
 }
 
-static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
+static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct hci_conn *c;
@@ -2316,16 +2303,16 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
 	list_for_each_entry_rcu(c, &h->list, list) {
 		if (c->type == type && c->sent) {
 			BT_ERR("%s killing stalled connection %s",
-				hdev->name, batostr(&c->dst));
-			hci_acl_disconn(c, 0x13);
+			       hdev->name, batostr(&c->dst));
+			hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM);
 		}
 	}
 
 	rcu_read_unlock();
 }
 
-static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
-						int *quote)
+static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
+				      int *quote)
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct hci_chan *chan = NULL;
@@ -2442,7 +2429,7 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
 			skb->priority = HCI_PRIO_MAX - 1;
 
 			BT_DBG("chan %p skb %p promoted to %d", chan, skb,
-								skb->priority);
+			       skb->priority);
 		}
 
 		if (hci_conn_num(hdev, type) == num)
@@ -2459,18 +2446,18 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
 	return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len);
 }
 
-static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
+static void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
 {
 	if (!test_bit(HCI_RAW, &hdev->flags)) {
 		/* ACL tx timeout must be longer than maximum
 		 * link supervision timeout (40.9 seconds) */
 		if (!cnt && time_after(jiffies, hdev->acl_last_tx +
-					msecs_to_jiffies(HCI_ACL_TX_TIMEOUT)))
+				       HCI_ACL_TX_TIMEOUT))
 			hci_link_tx_to(hdev, ACL_LINK);
 	}
 }
 
-static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
+static void hci_sched_acl_pkt(struct hci_dev *hdev)
 {
 	unsigned int cnt = hdev->acl_cnt;
 	struct hci_chan *chan;
@@ -2480,11 +2467,11 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
 	__check_timeout(hdev, cnt);
 
 	while (hdev->acl_cnt &&
-			(chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+	       (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
 		u32 priority = (skb_peek(&chan->data_q))->priority;
 		while (quote-- && (skb = skb_peek(&chan->data_q))) {
 			BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
-					skb->len, skb->priority);
+			       skb->len, skb->priority);
 
 			/* Stop if priority has changed */
 			if (skb->priority < priority)
@@ -2508,7 +2495,7 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
 		hci_prio_recalculate(hdev, ACL_LINK);
 }
 
-static inline void hci_sched_acl_blk(struct hci_dev *hdev)
+static void hci_sched_acl_blk(struct hci_dev *hdev)
 {
 	unsigned int cnt = hdev->block_cnt;
 	struct hci_chan *chan;
@@ -2518,13 +2505,13 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev)
 	__check_timeout(hdev, cnt);
 
 	while (hdev->block_cnt > 0 &&
-			(chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+	       (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
 		u32 priority = (skb_peek(&chan->data_q))->priority;
 		while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
 			int blocks;
 
 			BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
-						skb->len, skb->priority);
+			       skb->len, skb->priority);
 
 			/* Stop if priority has changed */
 			if (skb->priority < priority)
@@ -2537,7 +2524,7 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev)
 				return;
 
 			hci_conn_enter_active_mode(chan->conn,
-						bt_cb(skb)->force_active);
+						   bt_cb(skb)->force_active);
 
 			hci_send_frame(skb);
 			hdev->acl_last_tx = jiffies;
@@ -2554,7 +2541,7 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev)
 		hci_prio_recalculate(hdev, ACL_LINK);
 }
 
-static inline void hci_sched_acl(struct hci_dev *hdev)
+static void hci_sched_acl(struct hci_dev *hdev)
 {
 	BT_DBG("%s", hdev->name);
 
@@ -2573,7 +2560,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
 }
 
 /* Schedule SCO */
-static inline void hci_sched_sco(struct hci_dev *hdev)
+static void hci_sched_sco(struct hci_dev *hdev)
 {
 	struct hci_conn *conn;
 	struct sk_buff *skb;
@@ -2596,7 +2583,7 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
 	}
 }
 
-static inline void hci_sched_esco(struct hci_dev *hdev)
+static void hci_sched_esco(struct hci_dev *hdev)
 {
 	struct hci_conn *conn;
 	struct sk_buff *skb;
@@ -2607,7 +2594,8 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
 	if (!hci_conn_num(hdev, ESCO_LINK))
 		return;
 
-	while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
+	while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK,
+						     &quote))) {
 		while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
 			BT_DBG("skb %p len %d", skb, skb->len);
 			hci_send_frame(skb);
@@ -2619,7 +2607,7 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
 	}
 }
 
-static inline void hci_sched_le(struct hci_dev *hdev)
+static void hci_sched_le(struct hci_dev *hdev)
 {
 	struct hci_chan *chan;
 	struct sk_buff *skb;
@@ -2634,7 +2622,7 @@ static inline void hci_sched_le(struct hci_dev *hdev)
 		/* LE tx timeout must be longer than maximum
 		 * link supervision timeout (40.9 seconds) */
 		if (!hdev->le_cnt && hdev->le_pkts &&
-				time_after(jiffies, hdev->le_last_tx + HZ * 45))
+		    time_after(jiffies, hdev->le_last_tx + HZ * 45))
 			hci_link_tx_to(hdev, LE_LINK);
 	}
 
@@ -2644,7 +2632,7 @@ static inline void hci_sched_le(struct hci_dev *hdev)
 		u32 priority = (skb_peek(&chan->data_q))->priority;
 		while (quote-- && (skb = skb_peek(&chan->data_q))) {
 			BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
-					skb->len, skb->priority);
+			       skb->len, skb->priority);
 
 			/* Stop if priority has changed */
 			if (skb->priority < priority)
@@ -2676,7 +2664,7 @@ static void hci_tx_work(struct work_struct *work)
 	struct sk_buff *skb;
 
 	BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
-		hdev->sco_cnt, hdev->le_cnt);
+	       hdev->sco_cnt, hdev->le_cnt);
 
 	/* Schedule queues and send stuff to HCI driver */
 
@@ -2696,7 +2684,7 @@ static void hci_tx_work(struct work_struct *work)
 /* ----- HCI RX task (incoming data processing) ----- */
 
 /* ACL data packet */
-static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_acl_hdr *hdr = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2708,7 +2696,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 	flags  = hci_flags(handle);
 	handle = hci_handle(handle);
 
-	BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
+	BT_DBG("%s len %d handle 0x%4.4x flags 0x%4.4x", hdev->name, skb->len,
+	       handle, flags);
 
 	hdev->stat.acl_rx++;
 
@@ -2732,14 +2721,14 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		return;
 	} else {
 		BT_ERR("%s ACL packet for unknown connection handle %d",
-			hdev->name, handle);
+		       hdev->name, handle);
 	}
 
 	kfree_skb(skb);
 }
 
 /* SCO data packet */
-static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_sco_hdr *hdr = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2749,7 +2738,7 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 
 	handle = __le16_to_cpu(hdr->handle);
 
-	BT_DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle);
+	BT_DBG("%s len %d handle 0x%4.4x", hdev->name, skb->len, handle);
 
 	hdev->stat.sco_rx++;
 
@@ -2763,7 +2752,7 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		return;
 	} else {
 		BT_ERR("%s SCO packet for unknown connection handle %d",
-			hdev->name, handle);
+		       hdev->name, handle);
 	}
 
 	kfree_skb(skb);
@@ -2847,7 +2836,7 @@ static void hci_cmd_work(struct work_struct *work)
 				del_timer(&hdev->cmd_timer);
 			else
 				mod_timer(&hdev->cmd_timer,
-				  jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
+					  jiffies + HCI_CMD_TIMEOUT);
 		} else {
 			skb_queue_head(&hdev->cmd_q, skb);
 			queue_work(hdev->workqueue, &hdev->cmd_work);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 4eefb7f..1ba929c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -24,20 +24,7 @@
 
 /* Bluetooth HCI event handling. */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
+#include <linux/export.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -95,7 +82,8 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
 	hci_conn_check_pending(hdev);
 }
 
-static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev,
+					  struct sk_buff *skb)
 {
 	BT_DBG("%s", hdev->name);
 }
@@ -166,7 +154,8 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
 	hci_dev_unlock(hdev);
 }
 
-static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_read_def_link_policy(struct hci_dev *hdev,
+					struct sk_buff *skb)
 {
 	struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
 
@@ -178,7 +167,8 @@ static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *sk
 	hdev->link_policy = __le16_to_cpu(rp->policy);
 }
 
-static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_write_def_link_policy(struct hci_dev *hdev,
+					 struct sk_buff *skb)
 {
 	__u8 status = *((__u8 *) skb->data);
 	void *sent;
@@ -329,7 +319,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 		if (hdev->discov_timeout > 0) {
 			int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
 			queue_delayed_work(hdev->workqueue, &hdev->discov_off,
-									to);
+					   to);
 		}
 	} else if (old_iscan)
 		mgmt_discoverable(hdev, 0);
@@ -358,7 +348,7 @@ static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
 	memcpy(hdev->dev_class, rp->dev_class, 3);
 
 	BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name,
-		hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
+	       hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
 }
 
 static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
@@ -406,7 +396,8 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
 		hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
 }
 
-static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_write_voice_setting(struct hci_dev *hdev,
+				       struct sk_buff *skb)
 {
 	__u8 status = *((__u8 *) skb->data);
 	__u16 setting;
@@ -473,7 +464,7 @@ static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
 		return 1;
 
 	if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
-						hdev->lmp_subver == 0x0757)
+	    hdev->lmp_subver == 0x0757)
 		return 1;
 
 	if (hdev->manufacturer == 15) {
@@ -486,7 +477,7 @@ static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
 	}
 
 	if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
-						hdev->lmp_subver == 0x1805)
+	    hdev->lmp_subver == 0x1805)
 		return 1;
 
 	return 0;
@@ -566,7 +557,7 @@ static void hci_setup(struct hci_dev *hdev)
 	if (hdev->hci_ver > BLUETOOTH_VER_1_1)
 		hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
 
-	if (hdev->features[6] & LMP_SIMPLE_PAIR) {
+	if (lmp_ssp_capable(hdev)) {
 		if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
 			u8 mode = 0x01;
 			hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
@@ -618,8 +609,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
 	hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
 
 	BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
-					hdev->manufacturer,
-					hdev->hci_ver, hdev->hci_rev);
+	       hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
 
 	if (test_bit(HCI_INIT, &hdev->flags))
 		hci_setup(hdev);
@@ -646,7 +636,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
 	hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
 }
 
-static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_read_local_commands(struct hci_dev *hdev,
+				       struct sk_buff *skb)
 {
 	struct hci_rp_read_local_commands *rp = (void *) skb->data;
 
@@ -664,7 +655,8 @@ done:
 	hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
 }
 
-static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_read_local_features(struct hci_dev *hdev,
+				       struct sk_buff *skb)
 {
 	struct hci_rp_read_local_features *rp = (void *) skb->data;
 
@@ -713,10 +705,10 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
 		hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
 
 	BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
-					hdev->features[0], hdev->features[1],
-					hdev->features[2], hdev->features[3],
-					hdev->features[4], hdev->features[5],
-					hdev->features[6], hdev->features[7]);
+	       hdev->features[0], hdev->features[1],
+	       hdev->features[2], hdev->features[3],
+	       hdev->features[4], hdev->features[5],
+	       hdev->features[6], hdev->features[7]);
 }
 
 static void hci_set_le_support(struct hci_dev *hdev)
@@ -736,7 +728,7 @@ static void hci_set_le_support(struct hci_dev *hdev)
 }
 
 static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
-							struct sk_buff *skb)
+					   struct sk_buff *skb)
 {
 	struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
 
@@ -762,7 +754,7 @@ done:
 }
 
 static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
-						struct sk_buff *skb)
+					  struct sk_buff *skb)
 {
 	struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
 
@@ -798,9 +790,8 @@ static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
 	hdev->acl_cnt = hdev->acl_pkts;
 	hdev->sco_cnt = hdev->sco_pkts;
 
-	BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
-					hdev->acl_mtu, hdev->acl_pkts,
-					hdev->sco_mtu, hdev->sco_pkts);
+	BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, hdev->acl_mtu,
+	       hdev->acl_pkts, hdev->sco_mtu, hdev->sco_pkts);
 }
 
 static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
@@ -816,7 +807,7 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_read_data_block_size(struct hci_dev *hdev,
-							struct sk_buff *skb)
+					struct sk_buff *skb)
 {
 	struct hci_rp_read_data_block_size *rp = (void *) skb->data;
 
@@ -832,7 +823,7 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev,
 	hdev->block_cnt = hdev->num_blocks;
 
 	BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
-					hdev->block_cnt, hdev->block_len);
+	       hdev->block_cnt, hdev->block_len);
 
 	hci_req_complete(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, rp->status);
 }
@@ -847,7 +838,7 @@ static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
-		struct sk_buff *skb)
+				       struct sk_buff *skb)
 {
 	struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
 
@@ -871,7 +862,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
 }
 
 static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
-							struct sk_buff *skb)
+					  struct sk_buff *skb)
 {
 	__u8 status = *((__u8 *) skb->data);
 
@@ -890,7 +881,7 @@ static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
-							struct sk_buff *skb)
+				      struct sk_buff *skb)
 {
 	__u8 status = *((__u8 *) skb->data);
 
@@ -900,7 +891,7 @@ static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
 }
 
 static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
-							struct sk_buff *skb)
+					 struct sk_buff *skb)
 {
 	struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data;
 
@@ -959,7 +950,7 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
 	if (test_bit(HCI_MGMT, &hdev->dev_flags))
 		mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
-								rp->status);
+						 rp->status);
 
 	hci_dev_unlock(hdev);
 }
@@ -1000,7 +991,7 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
-							struct sk_buff *skb)
+					  struct sk_buff *skb)
 {
 	struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
 
@@ -1031,7 +1022,7 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
-							struct sk_buff *skb)
+					  struct sk_buff *skb)
 {
 	struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
 
@@ -1047,7 +1038,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
 }
 
 static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
-							struct sk_buff *skb)
+					     struct sk_buff *skb)
 {
 	struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
 
@@ -1076,7 +1067,7 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
-					struct sk_buff *skb)
+				      struct sk_buff *skb)
 {
 	struct hci_cp_le_set_scan_enable *cp;
 	__u8 status = *((__u8 *) skb->data);
@@ -1156,8 +1147,8 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 	hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
 }
 
-static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
-							struct sk_buff *skb)
+static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
+					   struct sk_buff *skb)
 {
 	struct hci_cp_write_le_host_supported *sent;
 	__u8 status = *((__u8 *) skb->data);
@@ -1176,13 +1167,13 @@ static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
 	}
 
 	if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
-					!test_bit(HCI_INIT, &hdev->flags))
+	    !test_bit(HCI_INIT, &hdev->flags))
 		mgmt_le_enable_complete(hdev, sent->le, status);
 
 	hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
 }
 
-static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
+static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
 	BT_DBG("%s status 0x%x", hdev->name, status);
 
@@ -1203,7 +1194,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
+static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 {
 	struct hci_cp_create_conn *cp;
 	struct hci_conn *conn;
@@ -1333,7 +1324,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
 }
 
 static int hci_outgoing_auth_needed(struct hci_dev *hdev,
-							struct hci_conn *conn)
+				    struct hci_conn *conn)
 {
 	if (conn->state != BT_CONFIG || !conn->out)
 		return 0;
@@ -1343,15 +1334,14 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
 
 	/* Only request authentication for SSP connections or non-SSP
 	 * devices with sec_level HIGH or if MITM protection is requested */
-	if (!hci_conn_ssp_enabled(conn) &&
-				conn->pending_sec_level != BT_SECURITY_HIGH &&
-				!(conn->auth_type & 0x01))
+	if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) &&
+	    conn->pending_sec_level != BT_SECURITY_HIGH)
 		return 0;
 
 	return 1;
 }
 
-static inline int hci_resolve_name(struct hci_dev *hdev,
+static int hci_resolve_name(struct hci_dev *hdev,
 				   struct inquiry_entry *e)
 {
 	struct hci_cp_remote_name_req cp;
@@ -1638,7 +1628,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
 	conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
 
 	BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
-		conn);
+	       conn);
 
 	if (status) {
 		if (conn && conn->state == BT_CONNECT) {
@@ -1668,7 +1658,7 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
 	BT_DBG("%s status 0x%x", hdev->name, status);
 }
 
-static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	__u8 status = *((__u8 *) skb->data);
 	struct discovery_state *discov = &hdev->discovery;
@@ -1708,7 +1698,7 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct inquiry_data data;
 	struct inquiry_info *info = (void *) (skb->data + 1);
@@ -1745,7 +1735,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_conn_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -1823,18 +1813,18 @@ unlock:
 	hci_conn_check_pending(hdev);
 }
 
-static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_conn_request *ev = (void *) skb->data;
 	int mask = hdev->link_mode;
 
-	BT_DBG("%s bdaddr %s type 0x%x", hdev->name,
-					batostr(&ev->bdaddr), ev->link_type);
+	BT_DBG("%s bdaddr %s type 0x%x", hdev->name, batostr(&ev->bdaddr),
+	       ev->link_type);
 
 	mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
 
 	if ((mask & HCI_LM_ACCEPT) &&
-			!hci_blacklist_lookup(hdev, &ev->bdaddr)) {
+	    !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
 		/* Connection accepted */
 		struct inquiry_entry *ie;
 		struct hci_conn *conn;
@@ -1845,7 +1835,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 		if (ie)
 			memcpy(ie->data.dev_class, ev->dev_class, 3);
 
-		conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
+		conn = hci_conn_hash_lookup_ba(hdev, ev->link_type,
+					       &ev->bdaddr);
 		if (!conn) {
 			conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr);
 			if (!conn) {
@@ -1878,9 +1869,9 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 			bacpy(&cp.bdaddr, &ev->bdaddr);
 			cp.pkt_type = cpu_to_le16(conn->pkt_type);
 
-			cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
-			cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
-			cp.max_latency    = cpu_to_le16(0xffff);
+			cp.tx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
+			cp.rx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
+			cp.max_latency    = __constant_cpu_to_le16(0xffff);
 			cp.content_format = cpu_to_le16(hdev->voice_setting);
 			cp.retrans_effort = 0xff;
 
@@ -1897,7 +1888,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 	}
 }
 
-static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_disconn_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -1914,10 +1905,10 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
 		conn->state = BT_CLOSED;
 
 	if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
-			(conn->type == ACL_LINK || conn->type == LE_LINK)) {
+	    (conn->type == ACL_LINK || conn->type == LE_LINK)) {
 		if (ev->status != 0)
 			mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
-						conn->dst_type, ev->status);
+					       conn->dst_type, ev->status);
 		else
 			mgmt_device_disconnected(hdev, &conn->dst, conn->type,
 						 conn->dst_type);
@@ -1934,7 +1925,7 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_auth_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -1949,7 +1940,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 
 	if (!ev->status) {
 		if (!hci_conn_ssp_enabled(conn) &&
-				test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) {
+		    test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) {
 			BT_INFO("re-auth of legacy device is not possible.");
 		} else {
 			conn->link_mode |= HCI_LM_AUTH;
@@ -1969,7 +1960,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 			cp.handle  = ev->handle;
 			cp.encrypt = 0x01;
 			hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
-									&cp);
+				     &cp);
 		} else {
 			conn->state = BT_CONNECTED;
 			hci_proto_connect_cfm(conn, ev->status);
@@ -1989,7 +1980,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 			cp.handle  = ev->handle;
 			cp.encrypt = 0x01;
 			hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
-									&cp);
+				     &cp);
 		} else {
 			clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
 			hci_encrypt_cfm(conn, ev->status, 0x00);
@@ -2000,7 +1991,7 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_remote_name *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2039,7 +2030,7 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_encrypt_change *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2082,7 +2073,8 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_change_link_key_complete_evt(struct hci_dev *hdev,
+					     struct sk_buff *skb)
 {
 	struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2104,7 +2096,8 @@ static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_remote_features_evt(struct hci_dev *hdev,
+				    struct sk_buff *skb)
 {
 	struct hci_ev_remote_features *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2128,7 +2121,7 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
 		cp.handle = ev->handle;
 		cp.page = 0x01;
 		hci_send_cmd(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES,
-							sizeof(cp), &cp);
+			     sizeof(cp), &cp);
 		goto unlock;
 	}
 
@@ -2153,17 +2146,18 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	BT_DBG("%s", hdev->name);
 }
 
-static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_qos_setup_complete_evt(struct hci_dev *hdev,
+				       struct sk_buff *skb)
 {
 	BT_DBG("%s", hdev->name);
 }
 
-static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_cmd_complete *ev = (void *) skb->data;
 	__u16 opcode;
@@ -2384,7 +2378,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
 	}
 }
 
-static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_cmd_status *ev = (void *) skb->data;
 	__u16 opcode;
@@ -2465,7 +2459,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
 	}
 }
 
-static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_role_change *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2491,7 +2485,7 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
 	int i;
@@ -2502,7 +2496,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
 	}
 
 	if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
-			ev->num_hndl * sizeof(struct hci_comp_pkts_info)) {
+	    ev->num_hndl * sizeof(struct hci_comp_pkts_info)) {
 		BT_DBG("%s bad parameters", hdev->name);
 		return;
 	}
@@ -2557,8 +2551,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
 	queue_work(hdev->workqueue, &hdev->tx_work);
 }
 
-static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
-					   struct sk_buff *skb)
+static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
 	int i;
@@ -2569,13 +2562,13 @@ static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
 	}
 
 	if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
-			ev->num_hndl * sizeof(struct hci_comp_blocks_info)) {
+	    ev->num_hndl * sizeof(struct hci_comp_blocks_info)) {
 		BT_DBG("%s bad parameters", hdev->name);
 		return;
 	}
 
 	BT_DBG("%s num_blocks %d num_hndl %d", hdev->name, ev->num_blocks,
-								ev->num_hndl);
+	       ev->num_hndl);
 
 	for (i = 0; i < ev->num_hndl; i++) {
 		struct hci_comp_blocks_info *info = &ev->handles[i];
@@ -2607,7 +2600,7 @@ static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
 	queue_work(hdev->workqueue, &hdev->tx_work);
 }
 
-static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_mode_change *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2621,7 +2614,8 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
 		conn->mode = ev->mode;
 		conn->interval = __le16_to_cpu(ev->interval);
 
-		if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
+		if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND,
+					&conn->flags)) {
 			if (conn->mode == HCI_CM_ACTIVE)
 				set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
 			else
@@ -2635,7 +2629,7 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_pin_code_req *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2656,7 +2650,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
 
 	if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags))
 		hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
-					sizeof(ev->bdaddr), &ev->bdaddr);
+			     sizeof(ev->bdaddr), &ev->bdaddr);
 	else if (test_bit(HCI_MGMT, &hdev->dev_flags)) {
 		u8 secure;
 
@@ -2672,7 +2666,7 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_link_key_req *ev = (void *) skb->data;
 	struct hci_cp_link_key_reply cp;
@@ -2689,15 +2683,15 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
 	key = hci_find_link_key(hdev, &ev->bdaddr);
 	if (!key) {
 		BT_DBG("%s link key not found for %s", hdev->name,
-							batostr(&ev->bdaddr));
+		       batostr(&ev->bdaddr));
 		goto not_found;
 	}
 
 	BT_DBG("%s found key type %u for %s", hdev->name, key->type,
-							batostr(&ev->bdaddr));
+	       batostr(&ev->bdaddr));
 
 	if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) &&
-				key->type == HCI_LK_DEBUG_COMBINATION) {
+	    key->type == HCI_LK_DEBUG_COMBINATION) {
 		BT_DBG("%s ignoring debug key", hdev->name);
 		goto not_found;
 	}
@@ -2705,16 +2699,15 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
 	if (conn) {
 		if (key->type == HCI_LK_UNAUTH_COMBINATION &&
-				conn->auth_type != 0xff &&
-				(conn->auth_type & 0x01)) {
+		    conn->auth_type != 0xff && (conn->auth_type & 0x01)) {
 			BT_DBG("%s ignoring unauthenticated key", hdev->name);
 			goto not_found;
 		}
 
 		if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 &&
-				conn->pending_sec_level == BT_SECURITY_HIGH) {
-			BT_DBG("%s ignoring key unauthenticated for high \
-							security", hdev->name);
+		    conn->pending_sec_level == BT_SECURITY_HIGH) {
+			BT_DBG("%s ignoring key unauthenticated for high security",
+			       hdev->name);
 			goto not_found;
 		}
 
@@ -2723,7 +2716,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
 	}
 
 	bacpy(&cp.bdaddr, &ev->bdaddr);
-	memcpy(cp.link_key, key->val, 16);
+	memcpy(cp.link_key, key->val, HCI_LINK_KEY_SIZE);
 
 	hci_send_cmd(hdev, HCI_OP_LINK_KEY_REPLY, sizeof(cp), &cp);
 
@@ -2736,7 +2729,7 @@ not_found:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_link_key_notify *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2760,12 +2753,12 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
 
 	if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
 		hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
-							ev->key_type, pin_len);
+				 ev->key_type, pin_len);
 
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_clock_offset *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2788,7 +2781,7 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_pkt_type_change *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2804,7 +2797,7 @@ static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
 	struct inquiry_entry *ie;
@@ -2822,7 +2815,8 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
+					     struct sk_buff *skb)
 {
 	struct inquiry_data data;
 	int num_rsp = *((__u8 *) skb->data);
@@ -2881,7 +2875,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_remote_ext_features_evt(struct hci_dev *hdev,
+					struct sk_buff *skb)
 {
 	struct hci_ev_remote_ext_features *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2929,7 +2924,8 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
+				       struct sk_buff *skb)
 {
 	struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -2984,19 +2980,20 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	BT_DBG("%s", hdev->name);
 }
 
-static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_sniff_subrate *ev = (void *) skb->data;
 
 	BT_DBG("%s status %d", hdev->name, ev->status);
 }
 
-static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
+					    struct sk_buff *skb)
 {
 	struct inquiry_data data;
 	struct extended_inquiry_info *info = (void *) (skb->data + 1);
@@ -3043,7 +3040,51 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
 	hci_dev_unlock(hdev);
 }
 
-static inline u8 hci_get_auth_req(struct hci_conn *conn)
+static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
+					 struct sk_buff *skb)
+{
+	struct hci_ev_key_refresh_complete *ev = (void *) skb->data;
+	struct hci_conn *conn;
+
+	BT_DBG("%s status %u handle %u", hdev->name, ev->status,
+	       __le16_to_cpu(ev->handle));
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+	if (!conn)
+		goto unlock;
+
+	if (!ev->status)
+		conn->sec_level = conn->pending_sec_level;
+
+	clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
+
+	if (ev->status && conn->state == BT_CONNECTED) {
+		hci_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE);
+		hci_conn_put(conn);
+		goto unlock;
+	}
+
+	if (conn->state == BT_CONFIG) {
+		if (!ev->status)
+			conn->state = BT_CONNECTED;
+
+		hci_proto_connect_cfm(conn, ev->status);
+		hci_conn_put(conn);
+	} else {
+		hci_auth_cfm(conn, ev->status);
+
+		hci_conn_hold(conn);
+		conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+		hci_conn_put(conn);
+	}
+
+unlock:
+	hci_dev_unlock(hdev);
+}
+
+static u8 hci_get_auth_req(struct hci_conn *conn)
 {
 	/* If remote requests dedicated bonding follow that lead */
 	if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) {
@@ -3062,7 +3103,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn)
 	return conn->auth_type;
 }
 
-static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_io_capa_request *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -3081,7 +3122,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
 		goto unlock;
 
 	if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) ||
-			(conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
+	    (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
 		struct hci_cp_io_capability_reply cp;
 
 		bacpy(&cp.bdaddr, &ev->bdaddr);
@@ -3092,14 +3133,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
 		conn->auth_type = hci_get_auth_req(conn);
 		cp.authentication = conn->auth_type;
 
-		if ((conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) &&
-				hci_find_remote_oob_data(hdev, &conn->dst))
+		if (hci_find_remote_oob_data(hdev, &conn->dst) &&
+		    (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)))
 			cp.oob_data = 0x01;
 		else
 			cp.oob_data = 0x00;
 
 		hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
-							sizeof(cp), &cp);
+			     sizeof(cp), &cp);
 	} else {
 		struct hci_cp_io_capability_neg_reply cp;
 
@@ -3107,14 +3148,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
 		cp.reason = HCI_ERROR_PAIRING_NOT_ALLOWED;
 
 		hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
-							sizeof(cp), &cp);
+			     sizeof(cp), &cp);
 	}
 
 unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_io_capa_reply *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -3136,8 +3177,8 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
-							struct sk_buff *skb)
+static void hci_user_confirm_request_evt(struct hci_dev *hdev,
+					 struct sk_buff *skb)
 {
 	struct hci_ev_user_confirm_req *ev = (void *) skb->data;
 	int loc_mitm, rem_mitm, confirm_hint = 0;
@@ -3165,13 +3206,13 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
 	if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) {
 		BT_DBG("Rejecting request: remote device can't provide MITM");
 		hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
-					sizeof(ev->bdaddr), &ev->bdaddr);
+			     sizeof(ev->bdaddr), &ev->bdaddr);
 		goto unlock;
 	}
 
 	/* If no side requires MITM protection; auto-accept */
 	if ((!loc_mitm || conn->remote_cap == 0x03) &&
-				(!rem_mitm || conn->io_capability == 0x03)) {
+	    (!rem_mitm || conn->io_capability == 0x03)) {
 
 		/* If we're not the initiators request authorization to
 		 * proceed from user space (mgmt_user_confirm with
@@ -3183,7 +3224,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
 		}
 
 		BT_DBG("Auto-accept of user confirmation with %ums delay",
-						hdev->auto_accept_delay);
+		       hdev->auto_accept_delay);
 
 		if (hdev->auto_accept_delay > 0) {
 			int delay = msecs_to_jiffies(hdev->auto_accept_delay);
@@ -3192,7 +3233,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
 		}
 
 		hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY,
-						sizeof(ev->bdaddr), &ev->bdaddr);
+			     sizeof(ev->bdaddr), &ev->bdaddr);
 		goto unlock;
 	}
 
@@ -3204,8 +3245,8 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
-							struct sk_buff *skb)
+static void hci_user_passkey_request_evt(struct hci_dev *hdev,
+					 struct sk_buff *skb)
 {
 	struct hci_ev_user_passkey_req *ev = (void *) skb->data;
 
@@ -3219,7 +3260,8 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
+					 struct sk_buff *skb)
 {
 	struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -3247,7 +3289,8 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_remote_host_features_evt(struct hci_dev *hdev,
+					 struct sk_buff *skb)
 {
 	struct hci_ev_remote_host_features *ev = (void *) skb->data;
 	struct inquiry_entry *ie;
@@ -3263,8 +3306,8 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
-						   struct sk_buff *skb)
+static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
+					    struct sk_buff *skb)
 {
 	struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
 	struct oob_data *data;
@@ -3285,20 +3328,20 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 		memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
 
 		hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
-									&cp);
+			     &cp);
 	} else {
 		struct hci_cp_remote_oob_data_neg_reply cp;
 
 		bacpy(&cp.bdaddr, &ev->bdaddr);
 		hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
-									&cp);
+			     &cp);
 	}
 
 unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_le_conn_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
@@ -3307,6 +3350,19 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
 
 	hci_dev_lock(hdev);
 
+	if (ev->status) {
+		conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+		if (!conn)
+			goto unlock;
+
+		mgmt_connect_failed(hdev, &conn->dst, conn->type,
+				    conn->dst_type, ev->status);
+		hci_proto_connect_cfm(conn, ev->status);
+		conn->state = BT_CLOSED;
+		hci_conn_del(conn);
+		goto unlock;
+	}
+
 	conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
 	if (!conn) {
 		conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
@@ -3319,15 +3375,6 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
 		conn->dst_type = ev->bdaddr_type;
 	}
 
-	if (ev->status) {
-		mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
-						conn->dst_type, ev->status);
-		hci_proto_connect_cfm(conn, ev->status);
-		conn->state = BT_CLOSED;
-		hci_conn_del(conn);
-		goto unlock;
-	}
-
 	if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
 		mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
 				      conn->dst_type, 0, NULL, 0, NULL);
@@ -3345,8 +3392,7 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
-						struct sk_buff *skb)
+static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	u8 num_reports = skb->data[0];
 	void *ptr = &skb->data[1];
@@ -3367,8 +3413,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
-						struct sk_buff *skb)
+static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_le_ltk_req *ev = (void *) skb->data;
 	struct hci_cp_le_ltk_reply cp;
@@ -3411,7 +3456,7 @@ not_found:
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_le_meta *le_ev = (void *) skb->data;
 
@@ -3559,6 +3604,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_extended_inquiry_result_evt(hdev, skb);
 		break;
 
+	case HCI_EV_KEY_REFRESH_COMPLETE:
+		hci_key_refresh_complete_evt(hdev, skb);
+		break;
+
 	case HCI_EV_IO_CAPA_REQUEST:
 		hci_io_capa_request_evt(hdev, skb);
 		break;
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 5914623..a7f04de 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -24,25 +24,7 @@
 
 /* Bluetooth HCI sockets. */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/compat.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
+#include <linux/export.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -113,11 +95,12 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
 		flt = &hci_pi(sk)->filter;
 
 		if (!test_bit((bt_cb(skb)->pkt_type == HCI_VENDOR_PKT) ?
-				0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
+			      0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS),
+			      &flt->type_mask))
 			continue;
 
 		if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) {
-			register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
+			int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
 
 			if (!hci_test_bit(evt, &flt->event_mask))
 				continue;
@@ -240,7 +223,8 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
 			struct hci_mon_hdr *hdr;
 
 			/* Create a private copy with headroom */
-			skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC);
+			skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE,
+					       GFP_ATOMIC);
 			if (!skb_copy)
 				continue;
 
@@ -495,7 +479,8 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
 }
 
 /* Ioctls that require bound socket */
-static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
+				unsigned long arg)
 {
 	struct hci_dev *hdev = hci_pi(sk)->hdev;
 
@@ -540,7 +525,8 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
 	}
 }
 
-static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
+			  unsigned long arg)
 {
 	struct sock *sk = sock->sk;
 	void __user *argp = (void __user *) arg;
@@ -601,7 +587,8 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a
 	}
 }
 
-static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
+			 int addr_len)
 {
 	struct sockaddr_hci haddr;
 	struct sock *sk = sock->sk;
@@ -690,7 +677,8 @@ done:
 	return err;
 }
 
-static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
+static int hci_sock_getname(struct socket *sock, struct sockaddr *addr,
+			    int *addr_len, int peer)
 {
 	struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
 	struct sock *sk = sock->sk;
@@ -711,13 +699,15 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *add
 	return 0;
 }
 
-static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
+static void hci_sock_cmsg(struct sock *sk, struct msghdr *msg,
+			  struct sk_buff *skb)
 {
 	__u32 mask = hci_pi(sk)->cmsg_mask;
 
 	if (mask & HCI_CMSG_DIR) {
 		int incoming = bt_cb(skb)->incoming;
-		put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming), &incoming);
+		put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming),
+			 &incoming);
 	}
 
 	if (mask & HCI_CMSG_TSTAMP) {
@@ -747,7 +737,7 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_
 }
 
 static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
-				struct msghdr *msg, size_t len, int flags)
+			    struct msghdr *msg, size_t len, int flags)
 {
 	int noblock = flags & MSG_DONTWAIT;
 	struct sock *sk = sock->sk;
@@ -857,8 +847,9 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 		u16 ocf = hci_opcode_ocf(opcode);
 
 		if (((ogf > HCI_SFLT_MAX_OGF) ||
-				!hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
-					!capable(CAP_NET_RAW)) {
+		     !hci_test_bit(ocf & HCI_FLT_OCF_BITS,
+				   &hci_sec_filter.ocf_mask[ogf])) &&
+		    !capable(CAP_NET_RAW)) {
 			err = -EPERM;
 			goto drop;
 		}
@@ -891,7 +882,8 @@ drop:
 	goto done;
 }
 
-static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int len)
+static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
+			       char __user *optval, unsigned int len)
 {
 	struct hci_ufilter uf = { .opcode = 0 };
 	struct sock *sk = sock->sk;
@@ -973,7 +965,8 @@ done:
 	return err;
 }
 
-static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
+			       char __user *optval, int __user *optlen)
 {
 	struct hci_ufilter uf;
 	struct sock *sk = sock->sk;
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 937f318..a20e61c 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -1,10 +1,6 @@
 /* Bluetooth HCI driver model support. */
 
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
 #include <linux/module.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -31,27 +27,30 @@ static inline char *link_typetostr(int type)
 	}
 }
 
-static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_link_type(struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
 	struct hci_conn *conn = to_hci_conn(dev);
 	return sprintf(buf, "%s\n", link_typetostr(conn->type));
 }
 
-static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_link_address(struct device *dev,
+				 struct device_attribute *attr, char *buf)
 {
 	struct hci_conn *conn = to_hci_conn(dev);
 	return sprintf(buf, "%s\n", batostr(&conn->dst));
 }
 
-static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_link_features(struct device *dev,
+				  struct device_attribute *attr, char *buf)
 {
 	struct hci_conn *conn = to_hci_conn(dev);
 
 	return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
-				conn->features[0], conn->features[1],
-				conn->features[2], conn->features[3],
-				conn->features[4], conn->features[5],
-				conn->features[6], conn->features[7]);
+		       conn->features[0], conn->features[1],
+		       conn->features[2], conn->features[3],
+		       conn->features[4], conn->features[5],
+		       conn->features[6], conn->features[7]);
 }
 
 #define LINK_ATTR(_name, _mode, _show, _store) \
@@ -185,19 +184,22 @@ static inline char *host_typetostr(int type)
 	}
 }
 
-static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_bus(struct device *dev,
+			struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
 }
 
-static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_type(struct device *dev,
+			 struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
 }
 
-static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_name(struct device *dev,
+			 struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	char name[HCI_MAX_NAME_LENGTH + 1];
@@ -210,55 +212,64 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char
 	return sprintf(buf, "%s\n", name);
 }
 
-static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_class(struct device *dev,
+			  struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
-	return sprintf(buf, "0x%.2x%.2x%.2x\n",
-			hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
+	return sprintf(buf, "0x%.2x%.2x%.2x\n", hdev->dev_class[2],
+		       hdev->dev_class[1], hdev->dev_class[0]);
 }
 
-static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_address(struct device *dev,
+			    struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
 }
 
-static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_features(struct device *dev,
+			     struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 
 	return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
-				hdev->features[0], hdev->features[1],
-				hdev->features[2], hdev->features[3],
-				hdev->features[4], hdev->features[5],
-				hdev->features[6], hdev->features[7]);
+		       hdev->features[0], hdev->features[1],
+		       hdev->features[2], hdev->features[3],
+		       hdev->features[4], hdev->features[5],
+		       hdev->features[6], hdev->features[7]);
 }
 
-static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_manufacturer(struct device *dev,
+				 struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->manufacturer);
 }
 
-static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_hci_version(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->hci_ver);
 }
 
-static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_hci_revision(struct device *dev,
+				 struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->hci_rev);
 }
 
-static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_idle_timeout(struct device *dev,
+				 struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->idle_timeout);
 }
 
-static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_idle_timeout(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	unsigned int val;
@@ -276,13 +287,16 @@ static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *a
 	return count;
 }
 
-static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_sniff_max_interval(struct device *dev,
+				       struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->sniff_max_interval);
 }
 
-static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_sniff_max_interval(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	u16 val;
@@ -300,13 +314,16 @@ static ssize_t store_sniff_max_interval(struct device *dev, struct device_attrib
 	return count;
 }
 
-static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_sniff_min_interval(struct device *dev,
+				       struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->sniff_min_interval);
 }
 
-static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_sniff_min_interval(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
 	u16 val;
@@ -335,11 +352,11 @@ static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
 static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
 
 static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
-				show_idle_timeout, store_idle_timeout);
+		   show_idle_timeout, store_idle_timeout);
 static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR,
-				show_sniff_max_interval, store_sniff_max_interval);
+		   show_sniff_max_interval, store_sniff_max_interval);
 static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
-				show_sniff_min_interval, store_sniff_min_interval);
+		   show_sniff_min_interval, store_sniff_min_interval);
 
 static struct attribute *bt_host_attrs[] = {
 	&dev_attr_bus.attr,
@@ -455,8 +472,8 @@ static void print_bt_uuid(struct seq_file *f, u8 *uuid)
 	memcpy(&data5, &uuid[14], 2);
 
 	seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x\n",
-				ntohl(data0), ntohs(data1), ntohs(data2),
-				ntohs(data3), ntohl(data4), ntohs(data5));
+		   ntohl(data0), ntohs(data1), ntohs(data2), ntohs(data3),
+		   ntohl(data4), ntohs(data5));
 }
 
 static int uuids_show(struct seq_file *f, void *p)
@@ -513,7 +530,7 @@ static int auto_accept_delay_get(void *data, u64 *val)
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
-					auto_accept_delay_set, "%llu\n");
+			auto_accept_delay_set, "%llu\n");
 
 void hci_init_sysfs(struct hci_dev *hdev)
 {
@@ -547,15 +564,15 @@ int hci_add_sysfs(struct hci_dev *hdev)
 		return 0;
 
 	debugfs_create_file("inquiry_cache", 0444, hdev->debugfs,
-						hdev, &inquiry_cache_fops);
+			    hdev, &inquiry_cache_fops);
 
 	debugfs_create_file("blacklist", 0444, hdev->debugfs,
-						hdev, &blacklist_fops);
+			    hdev, &blacklist_fops);
 
 	debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
 
 	debugfs_create_file("auto_accept_delay", 0444, hdev->debugfs, hdev,
-						&auto_accept_delay_fops);
+			    &auto_accept_delay_fops);
 	return 0;
 }
 
diff --git a/net/bluetooth/hidp/Kconfig b/net/bluetooth/hidp/Kconfig
index 4deaca7..9332bc7 100644
--- a/net/bluetooth/hidp/Kconfig
+++ b/net/bluetooth/hidp/Kconfig
@@ -1,6 +1,6 @@
 config BT_HIDP
 	tristate "HIDP protocol support"
-	depends on BT && INPUT && HID_SUPPORT
+	depends on BT && INPUT
 	select HID
 	help
 	  HIDP (Human Interface Device Protocol) is a transport layer
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 2c20d76..ccd985d 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -21,27 +21,8 @@
 */
 
 #include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/freezer.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
 #include <linux/file.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
 #include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/input.h>
-#include <linux/hid.h>
 #include <linux/hidraw.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -244,7 +225,8 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
 }
 
 static int __hidp_send_ctrl_message(struct hidp_session *session,
-			unsigned char hdr, unsigned char *data, int size)
+				    unsigned char hdr, unsigned char *data,
+				    int size)
 {
 	struct sk_buff *skb;
 
@@ -268,7 +250,7 @@ static int __hidp_send_ctrl_message(struct hidp_session *session,
 	return 0;
 }
 
-static inline int hidp_send_ctrl_message(struct hidp_session *session,
+static int hidp_send_ctrl_message(struct hidp_session *session,
 			unsigned char hdr, unsigned char *data, int size)
 {
 	int err;
@@ -471,7 +453,7 @@ static void hidp_set_timer(struct hidp_session *session)
 		mod_timer(&session->timer, jiffies + HZ * session->idle_to);
 }
 
-static inline void hidp_del_timer(struct hidp_session *session)
+static void hidp_del_timer(struct hidp_session *session)
 {
 	if (session->idle_to > 0)
 		del_timer(&session->timer);
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index 73a32d7..18b3f68 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -20,22 +20,8 @@
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
+#include <linux/export.h>
 #include <linux/file.h>
-#include <linux/init.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <net/sock.h>
 
 #include "hidp.h"
 
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 24f144b..d42dfdc 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -30,32 +30,14 @@
 
 #include <linux/module.h>
 
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/list.h>
-#include <linux/device.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/uaccess.h>
 #include <linux/crc16.h>
-#include <net/sock.h>
-
-#include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/smp.h>
+#include <net/bluetooth/a2mp.h>
 
 bool disable_ertm;
 
@@ -73,6 +55,9 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
 static void l2cap_send_disconn_req(struct l2cap_conn *conn,
 				   struct l2cap_chan *chan, int err);
 
+static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
+		    struct sk_buff_head *skbs, u8 event);
+
 /* ---- L2CAP channels ---- */
 
 static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
@@ -196,7 +181,7 @@ static void __l2cap_state_change(struct l2cap_chan *chan, int state)
 						state_to_string(state));
 
 	chan->state = state;
-	chan->ops->state_change(chan->data, state);
+	chan->ops->state_change(chan, state);
 }
 
 static void l2cap_state_change(struct l2cap_chan *chan, int state)
@@ -224,6 +209,37 @@ static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
 	release_sock(sk);
 }
 
+static void __set_retrans_timer(struct l2cap_chan *chan)
+{
+	if (!delayed_work_pending(&chan->monitor_timer) &&
+	    chan->retrans_timeout) {
+		l2cap_set_timer(chan, &chan->retrans_timer,
+				msecs_to_jiffies(chan->retrans_timeout));
+	}
+}
+
+static void __set_monitor_timer(struct l2cap_chan *chan)
+{
+	__clear_retrans_timer(chan);
+	if (chan->monitor_timeout) {
+		l2cap_set_timer(chan, &chan->monitor_timer,
+				msecs_to_jiffies(chan->monitor_timeout));
+	}
+}
+
+static struct sk_buff *l2cap_ertm_seq_in_queue(struct sk_buff_head *head,
+					       u16 seq)
+{
+	struct sk_buff *skb;
+
+	skb_queue_walk(head, skb) {
+		if (bt_cb(skb)->control.txseq == seq)
+			return skb;
+	}
+
+	return NULL;
+}
+
 /* ---- L2CAP sequence number lists ---- */
 
 /* For ERTM, ordered lists of sequence numbers must be tracked for
@@ -366,7 +382,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
 
 	l2cap_chan_unlock(chan);
 
-	chan->ops->close(chan->data);
+	chan->ops->close(chan);
 	mutex_unlock(&conn->chan_lock);
 
 	l2cap_chan_put(chan);
@@ -392,6 +408,9 @@ struct l2cap_chan *l2cap_chan_create(void)
 
 	atomic_set(&chan->refcnt, 1);
 
+	/* This flag is cleared in l2cap_chan_ready() */
+	set_bit(CONF_NOT_COMPLETE, &chan->conf_state);
+
 	BT_DBG("chan %p", chan);
 
 	return chan;
@@ -430,7 +449,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 	case L2CAP_CHAN_CONN_ORIENTED:
 		if (conn->hcon->type == LE_LINK) {
 			/* LE connection */
-			chan->omtu = L2CAP_LE_DEFAULT_MTU;
+			chan->omtu = L2CAP_DEFAULT_MTU;
 			chan->scid = L2CAP_CID_LE_DATA;
 			chan->dcid = L2CAP_CID_LE_DATA;
 		} else {
@@ -447,6 +466,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 		chan->omtu = L2CAP_DEFAULT_MTU;
 		break;
 
+	case L2CAP_CHAN_CONN_FIX_A2MP:
+		chan->scid = L2CAP_CID_A2MP;
+		chan->dcid = L2CAP_CID_A2MP;
+		chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+		chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+		break;
+
 	default:
 		/* Raw socket can send/recv signalling messages only */
 		chan->scid = L2CAP_CID_SIGNALING;
@@ -466,18 +492,16 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 	list_add(&chan->list, &conn->chan_l);
 }
 
-static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
 	mutex_lock(&conn->chan_lock);
 	__l2cap_chan_add(conn, chan);
 	mutex_unlock(&conn->chan_lock);
 }
 
-static void l2cap_chan_del(struct l2cap_chan *chan, int err)
+void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
-	struct sock *sk = chan->sk;
 	struct l2cap_conn *conn = chan->conn;
-	struct sock *parent = bt_sk(sk)->parent;
 
 	__clear_chan_timer(chan);
 
@@ -490,34 +514,22 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 		l2cap_chan_put(chan);
 
 		chan->conn = NULL;
-		hci_conn_put(conn->hcon);
-	}
-
-	lock_sock(sk);
-
-	__l2cap_state_change(chan, BT_CLOSED);
-	sock_set_flag(sk, SOCK_ZAPPED);
 
-	if (err)
-		__l2cap_chan_set_err(chan, err);
-
-	if (parent) {
-		bt_accept_unlink(sk);
-		parent->sk_data_ready(parent, 0);
-	} else
-		sk->sk_state_change(sk);
+		if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
+			hci_conn_put(conn->hcon);
+	}
 
-	release_sock(sk);
+	if (chan->ops->teardown)
+		chan->ops->teardown(chan, err);
 
-	if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
-			test_bit(CONF_INPUT_DONE, &chan->conf_state)))
+	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
 		return;
 
-	skb_queue_purge(&chan->tx_q);
-
-	if (chan->mode == L2CAP_MODE_ERTM) {
-		struct srej_list *l, *tmp;
+	switch(chan->mode) {
+	case L2CAP_MODE_BASIC:
+		break;
 
+	case L2CAP_MODE_ERTM:
 		__clear_retrans_timer(chan);
 		__clear_monitor_timer(chan);
 		__clear_ack_timer(chan);
@@ -526,30 +538,15 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 
 		l2cap_seq_list_free(&chan->srej_list);
 		l2cap_seq_list_free(&chan->retrans_list);
-		list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
-			list_del(&l->list);
-			kfree(l);
-		}
-	}
-}
-
-static void l2cap_chan_cleanup_listen(struct sock *parent)
-{
-	struct sock *sk;
 
-	BT_DBG("parent %p", parent);
-
-	/* Close not yet accepted channels */
-	while ((sk = bt_accept_dequeue(parent, NULL))) {
-		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-
-		l2cap_chan_lock(chan);
-		__clear_chan_timer(chan);
-		l2cap_chan_close(chan, ECONNRESET);
-		l2cap_chan_unlock(chan);
+		/* fall through */
 
-		chan->ops->close(chan->data);
+	case L2CAP_MODE_STREAMING:
+		skb_queue_purge(&chan->tx_q);
+		break;
 	}
+
+	return;
 }
 
 void l2cap_chan_close(struct l2cap_chan *chan, int reason)
@@ -562,12 +559,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 
 	switch (chan->state) {
 	case BT_LISTEN:
-		lock_sock(sk);
-		l2cap_chan_cleanup_listen(sk);
-
-		__l2cap_state_change(chan, BT_CLOSED);
-		sock_set_flag(sk, SOCK_ZAPPED);
-		release_sock(sk);
+		if (chan->ops->teardown)
+			chan->ops->teardown(chan, 0);
 		break;
 
 	case BT_CONNECTED:
@@ -595,7 +588,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 			rsp.scid   = cpu_to_le16(chan->dcid);
 			rsp.dcid   = cpu_to_le16(chan->scid);
 			rsp.result = cpu_to_le16(result);
-			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+			rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
 			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
 							sizeof(rsp), &rsp);
 		}
@@ -609,9 +602,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 		break;
 
 	default:
-		lock_sock(sk);
-		sock_set_flag(sk, SOCK_ZAPPED);
-		release_sock(sk);
+		if (chan->ops->teardown)
+			chan->ops->teardown(chan, 0);
 		break;
 	}
 }
@@ -627,7 +619,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 		default:
 			return HCI_AT_NO_BONDING;
 		}
-	} else if (chan->psm == cpu_to_le16(0x0001)) {
+	} else if (chan->psm == __constant_cpu_to_le16(L2CAP_PSM_SDP)) {
 		if (chan->sec_level == BT_SECURITY_LOW)
 			chan->sec_level = BT_SECURITY_SDP;
 
@@ -773,9 +765,11 @@ static inline void __unpack_control(struct l2cap_chan *chan,
 	if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
 		__unpack_extended_control(get_unaligned_le32(skb->data),
 					  &bt_cb(skb)->control);
+		skb_pull(skb, L2CAP_EXT_CTRL_SIZE);
 	} else {
 		__unpack_enhanced_control(get_unaligned_le16(skb->data),
 					  &bt_cb(skb)->control);
+		skb_pull(skb, L2CAP_ENH_CTRL_SIZE);
 	}
 }
 
@@ -830,66 +824,102 @@ static inline void __pack_control(struct l2cap_chan *chan,
 	}
 }
 
-static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
+static inline unsigned int __ertm_hdr_size(struct l2cap_chan *chan)
 {
-	struct sk_buff *skb;
-	struct l2cap_hdr *lh;
-	struct l2cap_conn *conn = chan->conn;
-	int count, hlen;
-
-	if (chan->state != BT_CONNECTED)
-		return;
-
 	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		hlen = L2CAP_EXT_HDR_SIZE;
+		return L2CAP_EXT_HDR_SIZE;
 	else
-		hlen = L2CAP_ENH_HDR_SIZE;
+		return L2CAP_ENH_HDR_SIZE;
+}
+
+static struct sk_buff *l2cap_create_sframe_pdu(struct l2cap_chan *chan,
+					       u32 control)
+{
+	struct sk_buff *skb;
+	struct l2cap_hdr *lh;
+	int hlen = __ertm_hdr_size(chan);
 
 	if (chan->fcs == L2CAP_FCS_CRC16)
 		hlen += L2CAP_FCS_SIZE;
 
-	BT_DBG("chan %p, control 0x%8.8x", chan, control);
-
-	count = min_t(unsigned int, conn->mtu, hlen);
-
-	control |= __set_sframe(chan);
-
-	if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-		control |= __set_ctrl_final(chan);
+	skb = bt_skb_alloc(hlen, GFP_KERNEL);
 
-	if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
-		control |= __set_ctrl_poll(chan);
-
-	skb = bt_skb_alloc(count, GFP_ATOMIC);
 	if (!skb)
-		return;
+		return ERR_PTR(-ENOMEM);
 
 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
 	lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
 	lh->cid = cpu_to_le16(chan->dcid);
 
-	__put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		put_unaligned_le32(control, skb_put(skb, L2CAP_EXT_CTRL_SIZE));
+	else
+		put_unaligned_le16(control, skb_put(skb, L2CAP_ENH_CTRL_SIZE));
 
 	if (chan->fcs == L2CAP_FCS_CRC16) {
-		u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
+		u16 fcs = crc16(0, (u8 *)skb->data, skb->len);
 		put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
 	}
 
 	skb->priority = HCI_PRIO_MAX;
-	l2cap_do_send(chan, skb);
+	return skb;
 }
 
-static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
+static void l2cap_send_sframe(struct l2cap_chan *chan,
+			      struct l2cap_ctrl *control)
 {
-	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-		control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
+	struct sk_buff *skb;
+	u32 control_field;
+
+	BT_DBG("chan %p, control %p", chan, control);
+
+	if (!control->sframe)
+		return;
+
+	if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) &&
+	    !control->poll)
+		control->final = 1;
+
+	if (control->super == L2CAP_SUPER_RR)
+		clear_bit(CONN_RNR_SENT, &chan->conn_state);
+	else if (control->super == L2CAP_SUPER_RNR)
 		set_bit(CONN_RNR_SENT, &chan->conn_state);
-	} else
-		control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
 
-	control |= __set_reqseq(chan, chan->buffer_seq);
+	if (control->super != L2CAP_SUPER_SREJ) {
+		chan->last_acked_seq = control->reqseq;
+		__clear_ack_timer(chan);
+	}
+
+	BT_DBG("reqseq %d, final %d, poll %d, super %d", control->reqseq,
+	       control->final, control->poll, control->super);
+
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		control_field = __pack_extended_control(control);
+	else
+		control_field = __pack_enhanced_control(control);
+
+	skb = l2cap_create_sframe_pdu(chan, control_field);
+	if (!IS_ERR(skb))
+		l2cap_do_send(chan, skb);
+}
+
+static void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, bool poll)
+{
+	struct l2cap_ctrl control;
+
+	BT_DBG("chan %p, poll %d", chan, poll);
+
+	memset(&control, 0, sizeof(control));
+	control.sframe = 1;
+	control.poll = poll;
+
+	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
+		control.super = L2CAP_SUPER_RNR;
+	else
+		control.super = L2CAP_SUPER_RR;
 
-	l2cap_send_sframe(chan, control);
+	control.reqseq = chan->buffer_seq;
+	l2cap_send_sframe(chan, &control);
 }
 
 static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
@@ -914,25 +944,13 @@ static void l2cap_send_conn_req(struct l2cap_chan *chan)
 
 static void l2cap_chan_ready(struct l2cap_chan *chan)
 {
-	struct sock *sk = chan->sk;
-	struct sock *parent;
-
-	lock_sock(sk);
-
-	parent = bt_sk(sk)->parent;
-
-	BT_DBG("sk %p, parent %p", sk, parent);
-
+	/* This clears all conf flags, including CONF_NOT_COMPLETE */
 	chan->conf_state = 0;
 	__clear_chan_timer(chan);
 
-	__l2cap_state_change(chan, BT_CONNECTED);
-	sk->sk_state_change(sk);
-
-	if (parent)
-		parent->sk_data_ready(parent, 0);
+	chan->state = BT_CONNECTED;
 
-	release_sock(sk);
+	chan->ops->ready(chan);
 }
 
 static void l2cap_do_start(struct l2cap_chan *chan)
@@ -953,7 +971,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
 			l2cap_send_conn_req(chan);
 	} else {
 		struct l2cap_info_req req;
-		req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+		req.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
 
 		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
 		conn->info_ident = l2cap_get_ident(conn);
@@ -995,6 +1013,11 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
 		__clear_ack_timer(chan);
 	}
 
+	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+		__l2cap_state_change(chan, BT_DISCONN);
+		return;
+	}
+
 	req.dcid = cpu_to_le16(chan->dcid);
 	req.scid = cpu_to_le16(chan->scid);
 	l2cap_send_cmd(conn, l2cap_get_ident(conn),
@@ -1053,20 +1076,20 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 				if (test_bit(BT_SK_DEFER_SETUP,
 					     &bt_sk(sk)->flags)) {
 					struct sock *parent = bt_sk(sk)->parent;
-					rsp.result = cpu_to_le16(L2CAP_CR_PEND);
-					rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
+					rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
+					rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
 					if (parent)
 						parent->sk_data_ready(parent, 0);
 
 				} else {
 					__l2cap_state_change(chan, BT_CONFIG);
-					rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
-					rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+					rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
+					rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
 				}
 				release_sock(sk);
 			} else {
-				rsp.result = cpu_to_le16(L2CAP_CR_PEND);
-				rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
+				rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
+				rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
 			}
 
 			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
@@ -1150,13 +1173,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
 	lock_sock(parent);
 
-	/* Check for backlog size */
-	if (sk_acceptq_is_full(parent)) {
-		BT_DBG("backlog full %d", parent->sk_ack_backlog);
-		goto clean;
-	}
-
-	chan = pchan->ops->new_connection(pchan->data);
+	chan = pchan->ops->new_connection(pchan);
 	if (!chan)
 		goto clean;
 
@@ -1171,10 +1188,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
 	l2cap_chan_add(conn, chan);
 
-	__set_chan_timer(chan, sk->sk_sndtimeo);
-
-	__l2cap_state_change(chan, BT_CONNECTED);
-	parent->sk_data_ready(parent, 0);
+	l2cap_chan_ready(chan);
 
 clean:
 	release_sock(parent);
@@ -1198,6 +1212,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
 		l2cap_chan_lock(chan);
 
+		if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+			l2cap_chan_unlock(chan);
+			continue;
+		}
+
 		if (conn->hcon->type == LE_LINK) {
 			if (smp_conn_security(conn, chan->sec_level))
 				l2cap_chan_ready(chan);
@@ -1270,7 +1289,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
 		l2cap_chan_unlock(chan);
 
-		chan->ops->close(chan->data);
+		chan->ops->close(chan);
 		l2cap_chan_put(chan);
 	}
 
@@ -1295,7 +1314,12 @@ static void security_timeout(struct work_struct *work)
 	struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
 						security_timer.work);
 
-	l2cap_conn_del(conn->hcon, ETIMEDOUT);
+	BT_DBG("conn %p", conn);
+
+	if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
+		smp_chan_destroy(conn);
+		l2cap_conn_del(conn->hcon, ETIMEDOUT);
+	}
 }
 
 static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
@@ -1439,21 +1463,17 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 		goto done;
 	}
 
-	lock_sock(sk);
-
-	switch (sk->sk_state) {
+	switch (chan->state) {
 	case BT_CONNECT:
 	case BT_CONNECT2:
 	case BT_CONFIG:
 		/* Already connecting */
 		err = 0;
-		release_sock(sk);
 		goto done;
 
 	case BT_CONNECTED:
 		/* Already connected */
 		err = -EISCONN;
-		release_sock(sk);
 		goto done;
 
 	case BT_OPEN:
@@ -1463,13 +1483,12 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 
 	default:
 		err = -EBADFD;
-		release_sock(sk);
 		goto done;
 	}
 
 	/* Set destination address and psm */
+	lock_sock(sk);
 	bacpy(&bt_sk(sk)->dst, dst);
-
 	release_sock(sk);
 
 	chan->psm = psm;
@@ -1571,23 +1590,20 @@ int __l2cap_wait_ack(struct sock *sk)
 static void l2cap_monitor_timeout(struct work_struct *work)
 {
 	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
-							monitor_timer.work);
+					       monitor_timer.work);
 
 	BT_DBG("chan %p", chan);
 
 	l2cap_chan_lock(chan);
 
-	if (chan->retry_count >= chan->remote_max_tx) {
-		l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
+	if (!chan->conn) {
 		l2cap_chan_unlock(chan);
 		l2cap_chan_put(chan);
 		return;
 	}
 
-	chan->retry_count++;
-	__set_monitor_timer(chan);
+	l2cap_tx(chan, NULL, NULL, L2CAP_EV_MONITOR_TO);
 
-	l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
 	l2cap_chan_unlock(chan);
 	l2cap_chan_put(chan);
 }
@@ -1595,234 +1611,293 @@ static void l2cap_monitor_timeout(struct work_struct *work)
 static void l2cap_retrans_timeout(struct work_struct *work)
 {
 	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
-							retrans_timer.work);
+					       retrans_timer.work);
 
 	BT_DBG("chan %p", chan);
 
 	l2cap_chan_lock(chan);
 
-	chan->retry_count = 1;
-	__set_monitor_timer(chan);
-
-	set_bit(CONN_WAIT_F, &chan->conn_state);
-
-	l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
+	if (!chan->conn) {
+		l2cap_chan_unlock(chan);
+		l2cap_chan_put(chan);
+		return;
+	}
 
+	l2cap_tx(chan, NULL, NULL, L2CAP_EV_RETRANS_TO);
 	l2cap_chan_unlock(chan);
 	l2cap_chan_put(chan);
 }
 
-static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
+static void l2cap_streaming_send(struct l2cap_chan *chan,
+				 struct sk_buff_head *skbs)
 {
 	struct sk_buff *skb;
+	struct l2cap_ctrl *control;
 
-	while ((skb = skb_peek(&chan->tx_q)) &&
-			chan->unacked_frames) {
-		if (bt_cb(skb)->control.txseq == chan->expected_ack_seq)
-			break;
+	BT_DBG("chan %p, skbs %p", chan, skbs);
 
-		skb = skb_dequeue(&chan->tx_q);
-		kfree_skb(skb);
+	skb_queue_splice_tail_init(skbs, &chan->tx_q);
 
-		chan->unacked_frames--;
-	}
+	while (!skb_queue_empty(&chan->tx_q)) {
 
-	if (!chan->unacked_frames)
-		__clear_retrans_timer(chan);
-}
+		skb = skb_dequeue(&chan->tx_q);
 
-static void l2cap_streaming_send(struct l2cap_chan *chan)
-{
-	struct sk_buff *skb;
-	u32 control;
-	u16 fcs;
+		bt_cb(skb)->control.retries = 1;
+		control = &bt_cb(skb)->control;
 
-	while ((skb = skb_dequeue(&chan->tx_q))) {
-		control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
-		control |= __set_txseq(chan, chan->next_tx_seq);
-		control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
-		__put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
+		control->reqseq = 0;
+		control->txseq = chan->next_tx_seq;
+
+		__pack_control(chan, control, skb);
 
 		if (chan->fcs == L2CAP_FCS_CRC16) {
-			fcs = crc16(0, (u8 *)skb->data,
-						skb->len - L2CAP_FCS_SIZE);
-			put_unaligned_le16(fcs,
-					skb->data + skb->len - L2CAP_FCS_SIZE);
+			u16 fcs = crc16(0, (u8 *) skb->data, skb->len);
+			put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
 		}
 
 		l2cap_do_send(chan, skb);
 
+		BT_DBG("Sent txseq %d", (int)control->txseq);
+
 		chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
+		chan->frames_sent++;
 	}
 }
 
-static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
+static int l2cap_ertm_send(struct l2cap_chan *chan)
 {
 	struct sk_buff *skb, *tx_skb;
-	u16 fcs;
-	u32 control;
+	struct l2cap_ctrl *control;
+	int sent = 0;
 
-	skb = skb_peek(&chan->tx_q);
-	if (!skb)
-		return;
+	BT_DBG("chan %p", chan);
 
-	while (bt_cb(skb)->control.txseq != tx_seq) {
-		if (skb_queue_is_last(&chan->tx_q, skb))
-			return;
+	if (chan->state != BT_CONNECTED)
+		return -ENOTCONN;
 
-		skb = skb_queue_next(&chan->tx_q, skb);
-	}
+	if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
+		return 0;
 
-	if (bt_cb(skb)->control.retries == chan->remote_max_tx &&
-	    chan->remote_max_tx) {
-		l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
-		return;
-	}
+	while (chan->tx_send_head &&
+	       chan->unacked_frames < chan->remote_tx_win &&
+	       chan->tx_state == L2CAP_TX_STATE_XMIT) {
 
-	tx_skb = skb_clone(skb, GFP_ATOMIC);
-	bt_cb(skb)->control.retries++;
+		skb = chan->tx_send_head;
 
-	control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
-	control &= __get_sar_mask(chan);
+		bt_cb(skb)->control.retries = 1;
+		control = &bt_cb(skb)->control;
 
-	if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-		control |= __set_ctrl_final(chan);
+		if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
+			control->final = 1;
 
-	control |= __set_reqseq(chan, chan->buffer_seq);
-	control |= __set_txseq(chan, tx_seq);
+		control->reqseq = chan->buffer_seq;
+		chan->last_acked_seq = chan->buffer_seq;
+		control->txseq = chan->next_tx_seq;
 
-	__put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
+		__pack_control(chan, control, skb);
 
-	if (chan->fcs == L2CAP_FCS_CRC16) {
-		fcs = crc16(0, (u8 *)tx_skb->data,
-						tx_skb->len - L2CAP_FCS_SIZE);
-		put_unaligned_le16(fcs,
-				tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
+		if (chan->fcs == L2CAP_FCS_CRC16) {
+			u16 fcs = crc16(0, (u8 *) skb->data, skb->len);
+			put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
+		}
+
+		/* Clone after data has been modified. Data is assumed to be
+		   read-only (for locking purposes) on cloned sk_buffs.
+		 */
+		tx_skb = skb_clone(skb, GFP_KERNEL);
+
+		if (!tx_skb)
+			break;
+
+		__set_retrans_timer(chan);
+
+		chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
+		chan->unacked_frames++;
+		chan->frames_sent++;
+		sent++;
+
+		if (skb_queue_is_last(&chan->tx_q, skb))
+			chan->tx_send_head = NULL;
+		else
+			chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
+
+		l2cap_do_send(chan, tx_skb);
+		BT_DBG("Sent txseq %d", (int)control->txseq);
 	}
 
-	l2cap_do_send(chan, tx_skb);
+	BT_DBG("Sent %d, %d unacked, %d in ERTM queue", sent,
+	       (int) chan->unacked_frames, skb_queue_len(&chan->tx_q));
+
+	return sent;
 }
 
-static int l2cap_ertm_send(struct l2cap_chan *chan)
+static void l2cap_ertm_resend(struct l2cap_chan *chan)
 {
-	struct sk_buff *skb, *tx_skb;
-	u16 fcs;
-	u32 control;
-	int nsent = 0;
+	struct l2cap_ctrl control;
+	struct sk_buff *skb;
+	struct sk_buff *tx_skb;
+	u16 seq;
 
-	if (chan->state != BT_CONNECTED)
-		return -ENOTCONN;
+	BT_DBG("chan %p", chan);
 
 	if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
-		return 0;
+		return;
 
-	while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
+	while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) {
+		seq = l2cap_seq_list_pop(&chan->retrans_list);
 
-		if (bt_cb(skb)->control.retries == chan->remote_max_tx &&
-		    chan->remote_max_tx) {
-			l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
-			break;
+		skb = l2cap_ertm_seq_in_queue(&chan->tx_q, seq);
+		if (!skb) {
+			BT_DBG("Error: Can't retransmit seq %d, frame missing",
+				seq);
+			continue;
 		}
 
-		tx_skb = skb_clone(skb, GFP_ATOMIC);
-
 		bt_cb(skb)->control.retries++;
+		control = bt_cb(skb)->control;
 
-		control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
-		control &= __get_sar_mask(chan);
+		if (chan->max_tx != 0 &&
+		    bt_cb(skb)->control.retries > chan->max_tx) {
+			BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
+			l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+			l2cap_seq_list_clear(&chan->retrans_list);
+			break;
+		}
 
+		control.reqseq = chan->buffer_seq;
 		if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-			control |= __set_ctrl_final(chan);
+			control.final = 1;
+		else
+			control.final = 0;
+
+		if (skb_cloned(skb)) {
+			/* Cloned sk_buffs are read-only, so we need a
+			 * writeable copy
+			 */
+			tx_skb = skb_copy(skb, GFP_ATOMIC);
+		} else {
+			tx_skb = skb_clone(skb, GFP_ATOMIC);
+		}
 
-		control |= __set_reqseq(chan, chan->buffer_seq);
-		control |= __set_txseq(chan, chan->next_tx_seq);
-		control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
+		if (!tx_skb) {
+			l2cap_seq_list_clear(&chan->retrans_list);
+			break;
+		}
 
-		__put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
+		/* Update skb contents */
+		if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
+			put_unaligned_le32(__pack_extended_control(&control),
+					   tx_skb->data + L2CAP_HDR_SIZE);
+		} else {
+			put_unaligned_le16(__pack_enhanced_control(&control),
+					   tx_skb->data + L2CAP_HDR_SIZE);
+		}
 
 		if (chan->fcs == L2CAP_FCS_CRC16) {
-			fcs = crc16(0, (u8 *)skb->data,
-						tx_skb->len - L2CAP_FCS_SIZE);
-			put_unaligned_le16(fcs, skb->data +
-						tx_skb->len - L2CAP_FCS_SIZE);
+			u16 fcs = crc16(0, (u8 *) tx_skb->data, tx_skb->len);
+			put_unaligned_le16(fcs, skb_put(tx_skb,
+							L2CAP_FCS_SIZE));
 		}
 
 		l2cap_do_send(chan, tx_skb);
 
-		__set_retrans_timer(chan);
-
-		bt_cb(skb)->control.txseq = chan->next_tx_seq;
-
-		chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
-
-		if (bt_cb(skb)->control.retries == 1) {
-			chan->unacked_frames++;
-
-			if (!nsent++)
-				__clear_ack_timer(chan);
-		}
-
-		chan->frames_sent++;
+		BT_DBG("Resent txseq %d", control.txseq);
 
-		if (skb_queue_is_last(&chan->tx_q, skb))
-			chan->tx_send_head = NULL;
-		else
-			chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
+		chan->last_acked_seq = chan->buffer_seq;
 	}
-
-	return nsent;
 }
 
-static int l2cap_retransmit_frames(struct l2cap_chan *chan)
+static void l2cap_retransmit(struct l2cap_chan *chan,
+			     struct l2cap_ctrl *control)
 {
-	int ret;
+	BT_DBG("chan %p, control %p", chan, control);
 
-	if (!skb_queue_empty(&chan->tx_q))
-		chan->tx_send_head = chan->tx_q.next;
-
-	chan->next_tx_seq = chan->expected_ack_seq;
-	ret = l2cap_ertm_send(chan);
-	return ret;
+	l2cap_seq_list_append(&chan->retrans_list, control->reqseq);
+	l2cap_ertm_resend(chan);
 }
 
-static void __l2cap_send_ack(struct l2cap_chan *chan)
+static void l2cap_retransmit_all(struct l2cap_chan *chan,
+				 struct l2cap_ctrl *control)
 {
-	u32 control = 0;
+	struct sk_buff *skb;
 
-	control |= __set_reqseq(chan, chan->buffer_seq);
+	BT_DBG("chan %p, control %p", chan, control);
 
-	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-		control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
-		set_bit(CONN_RNR_SENT, &chan->conn_state);
-		l2cap_send_sframe(chan, control);
-		return;
-	}
+	if (control->poll)
+		set_bit(CONN_SEND_FBIT, &chan->conn_state);
+
+	l2cap_seq_list_clear(&chan->retrans_list);
 
-	if (l2cap_ertm_send(chan) > 0)
+	if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
 		return;
 
-	control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
-	l2cap_send_sframe(chan, control);
+	if (chan->unacked_frames) {
+		skb_queue_walk(&chan->tx_q, skb) {
+			if (bt_cb(skb)->control.txseq == control->reqseq ||
+				skb == chan->tx_send_head)
+				break;
+		}
+
+		skb_queue_walk_from(&chan->tx_q, skb) {
+			if (skb == chan->tx_send_head)
+				break;
+
+			l2cap_seq_list_append(&chan->retrans_list,
+					      bt_cb(skb)->control.txseq);
+		}
+
+		l2cap_ertm_resend(chan);
+	}
 }
 
 static void l2cap_send_ack(struct l2cap_chan *chan)
 {
-	__clear_ack_timer(chan);
-	__l2cap_send_ack(chan);
-}
+	struct l2cap_ctrl control;
+	u16 frames_to_ack = __seq_offset(chan, chan->buffer_seq,
+					 chan->last_acked_seq);
+	int threshold;
 
-static void l2cap_send_srejtail(struct l2cap_chan *chan)
-{
-	struct srej_list *tail;
-	u32 control;
+	BT_DBG("chan %p last_acked_seq %d buffer_seq %d",
+	       chan, chan->last_acked_seq, chan->buffer_seq);
+
+	memset(&control, 0, sizeof(control));
+	control.sframe = 1;
 
-	control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
-	control |= __set_ctrl_final(chan);
+	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
+	    chan->rx_state == L2CAP_RX_STATE_RECV) {
+		__clear_ack_timer(chan);
+		control.super = L2CAP_SUPER_RNR;
+		control.reqseq = chan->buffer_seq;
+		l2cap_send_sframe(chan, &control);
+	} else {
+		if (!test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) {
+			l2cap_ertm_send(chan);
+			/* If any i-frames were sent, they included an ack */
+			if (chan->buffer_seq == chan->last_acked_seq)
+				frames_to_ack = 0;
+		}
 
-	tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
-	control |= __set_reqseq(chan, tail->tx_seq);
+		/* Ack now if the tx window is 3/4ths full.
+		 * Calculate without mul or div
+		 */
+		threshold = chan->tx_win;
+		threshold += threshold << 1;
+		threshold >>= 2;
+
+		BT_DBG("frames_to_ack %d, threshold %d", (int)frames_to_ack,
+		       threshold);
+
+		if (frames_to_ack >= threshold) {
+			__clear_ack_timer(chan);
+			control.super = L2CAP_SUPER_RR;
+			control.reqseq = chan->buffer_seq;
+			l2cap_send_sframe(chan, &control);
+			frames_to_ack = 0;
+		}
 
-	l2cap_send_sframe(chan, control);
+		if (frames_to_ack)
+			__set_ack_timer(chan);
+	}
 }
 
 static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
@@ -1951,10 +2026,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
 	if (!conn)
 		return ERR_PTR(-ENOTCONN);
 
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		hlen = L2CAP_EXT_HDR_SIZE;
-	else
-		hlen = L2CAP_ENH_HDR_SIZE;
+	hlen = __ertm_hdr_size(chan);
 
 	if (sdulen)
 		hlen += L2CAP_SDULEN_SIZE;
@@ -1974,7 +2046,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
 	lh->cid = cpu_to_le16(chan->dcid);
 	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 
-	__put_control(chan, 0, skb_put(skb, __ctrl_size(chan)));
+	/* Control header is populated later */
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		put_unaligned_le32(0, skb_put(skb, L2CAP_EXT_CTRL_SIZE));
+	else
+		put_unaligned_le16(0, skb_put(skb, L2CAP_ENH_CTRL_SIZE));
 
 	if (sdulen)
 		put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
@@ -1985,9 +2061,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
 		return ERR_PTR(err);
 	}
 
-	if (chan->fcs == L2CAP_FCS_CRC16)
-		put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
-
+	bt_cb(skb)->control.fcs = chan->fcs;
 	bt_cb(skb)->control.retries = 0;
 	return skb;
 }
@@ -1999,7 +2073,6 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
 	struct sk_buff *skb;
 	u16 sdu_len;
 	size_t pdu_len;
-	int err = 0;
 	u8 sar;
 
 	BT_DBG("chan %p, msg %p, len %d", chan, msg, (int)len);
@@ -2015,7 +2088,10 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
 	pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);
 
 	/* Adjust for largest possible L2CAP overhead. */
-	pdu_len -= L2CAP_EXT_HDR_SIZE + L2CAP_FCS_SIZE;
+	if (chan->fcs)
+		pdu_len -= L2CAP_FCS_SIZE;
+
+	pdu_len -= __ertm_hdr_size(chan);
 
 	/* Remote device may have requested smaller PDUs */
 	pdu_len = min_t(size_t, pdu_len, chan->remote_mps);
@@ -2055,7 +2131,7 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
 		}
 	}
 
-	return err;
+	return 0;
 }
 
 int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
@@ -2117,17 +2193,12 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 		if (err)
 			break;
 
-		if (chan->mode == L2CAP_MODE_ERTM && chan->tx_send_head == NULL)
-			chan->tx_send_head = seg_queue.next;
-		skb_queue_splice_tail_init(&seg_queue, &chan->tx_q);
-
 		if (chan->mode == L2CAP_MODE_ERTM)
-			err = l2cap_ertm_send(chan);
+			l2cap_tx(chan, NULL, &seg_queue, L2CAP_EV_DATA_REQUEST);
 		else
-			l2cap_streaming_send(chan);
+			l2cap_streaming_send(chan, &seg_queue);
 
-		if (err >= 0)
-			err = len;
+		err = len;
 
 		/* If the skbs were not queued for sending, they'll still be in
 		 * seg_queue and need to be purged.
@@ -2143,6 +2214,296 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 	return err;
 }
 
+static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq)
+{
+	struct l2cap_ctrl control;
+	u16 seq;
+
+	BT_DBG("chan %p, txseq %d", chan, txseq);
+
+	memset(&control, 0, sizeof(control));
+	control.sframe = 1;
+	control.super = L2CAP_SUPER_SREJ;
+
+	for (seq = chan->expected_tx_seq; seq != txseq;
+	     seq = __next_seq(chan, seq)) {
+		if (!l2cap_ertm_seq_in_queue(&chan->srej_q, seq)) {
+			control.reqseq = seq;
+			l2cap_send_sframe(chan, &control);
+			l2cap_seq_list_append(&chan->srej_list, seq);
+		}
+	}
+
+	chan->expected_tx_seq = __next_seq(chan, txseq);
+}
+
+static void l2cap_send_srej_tail(struct l2cap_chan *chan)
+{
+	struct l2cap_ctrl control;
+
+	BT_DBG("chan %p", chan);
+
+	if (chan->srej_list.tail == L2CAP_SEQ_LIST_CLEAR)
+		return;
+
+	memset(&control, 0, sizeof(control));
+	control.sframe = 1;
+	control.super = L2CAP_SUPER_SREJ;
+	control.reqseq = chan->srej_list.tail;
+	l2cap_send_sframe(chan, &control);
+}
+
+static void l2cap_send_srej_list(struct l2cap_chan *chan, u16 txseq)
+{
+	struct l2cap_ctrl control;
+	u16 initial_head;
+	u16 seq;
+
+	BT_DBG("chan %p, txseq %d", chan, txseq);
+
+	memset(&control, 0, sizeof(control));
+	control.sframe = 1;
+	control.super = L2CAP_SUPER_SREJ;
+
+	/* Capture initial list head to allow only one pass through the list. */
+	initial_head = chan->srej_list.head;
+
+	do {
+		seq = l2cap_seq_list_pop(&chan->srej_list);
+		if (seq == txseq || seq == L2CAP_SEQ_LIST_CLEAR)
+			break;
+
+		control.reqseq = seq;
+		l2cap_send_sframe(chan, &control);
+		l2cap_seq_list_append(&chan->srej_list, seq);
+	} while (chan->srej_list.head != initial_head);
+}
+
+static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq)
+{
+	struct sk_buff *acked_skb;
+	u16 ackseq;
+
+	BT_DBG("chan %p, reqseq %d", chan, reqseq);
+
+	if (chan->unacked_frames == 0 || reqseq == chan->expected_ack_seq)
+		return;
+
+	BT_DBG("expected_ack_seq %d, unacked_frames %d",
+	       chan->expected_ack_seq, chan->unacked_frames);
+
+	for (ackseq = chan->expected_ack_seq; ackseq != reqseq;
+	     ackseq = __next_seq(chan, ackseq)) {
+
+		acked_skb = l2cap_ertm_seq_in_queue(&chan->tx_q, ackseq);
+		if (acked_skb) {
+			skb_unlink(acked_skb, &chan->tx_q);
+			kfree_skb(acked_skb);
+			chan->unacked_frames--;
+		}
+	}
+
+	chan->expected_ack_seq = reqseq;
+
+	if (chan->unacked_frames == 0)
+		__clear_retrans_timer(chan);
+
+	BT_DBG("unacked_frames %d", (int) chan->unacked_frames);
+}
+
+static void l2cap_abort_rx_srej_sent(struct l2cap_chan *chan)
+{
+	BT_DBG("chan %p", chan);
+
+	chan->expected_tx_seq = chan->buffer_seq;
+	l2cap_seq_list_clear(&chan->srej_list);
+	skb_queue_purge(&chan->srej_q);
+	chan->rx_state = L2CAP_RX_STATE_RECV;
+}
+
+static void l2cap_tx_state_xmit(struct l2cap_chan *chan,
+				struct l2cap_ctrl *control,
+				struct sk_buff_head *skbs, u8 event)
+{
+	BT_DBG("chan %p, control %p, skbs %p, event %d", chan, control, skbs,
+	       event);
+
+	switch (event) {
+	case L2CAP_EV_DATA_REQUEST:
+		if (chan->tx_send_head == NULL)
+			chan->tx_send_head = skb_peek(skbs);
+
+		skb_queue_splice_tail_init(skbs, &chan->tx_q);
+		l2cap_ertm_send(chan);
+		break;
+	case L2CAP_EV_LOCAL_BUSY_DETECTED:
+		BT_DBG("Enter LOCAL_BUSY");
+		set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
+
+		if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
+			/* The SREJ_SENT state must be aborted if we are to
+			 * enter the LOCAL_BUSY state.
+			 */
+			l2cap_abort_rx_srej_sent(chan);
+		}
+
+		l2cap_send_ack(chan);
+
+		break;
+	case L2CAP_EV_LOCAL_BUSY_CLEAR:
+		BT_DBG("Exit LOCAL_BUSY");
+		clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
+
+		if (test_bit(CONN_RNR_SENT, &chan->conn_state)) {
+			struct l2cap_ctrl local_control;
+
+			memset(&local_control, 0, sizeof(local_control));
+			local_control.sframe = 1;
+			local_control.super = L2CAP_SUPER_RR;
+			local_control.poll = 1;
+			local_control.reqseq = chan->buffer_seq;
+			l2cap_send_sframe(chan, &local_control);
+
+			chan->retry_count = 1;
+			__set_monitor_timer(chan);
+			chan->tx_state = L2CAP_TX_STATE_WAIT_F;
+		}
+		break;
+	case L2CAP_EV_RECV_REQSEQ_AND_FBIT:
+		l2cap_process_reqseq(chan, control->reqseq);
+		break;
+	case L2CAP_EV_EXPLICIT_POLL:
+		l2cap_send_rr_or_rnr(chan, 1);
+		chan->retry_count = 1;
+		__set_monitor_timer(chan);
+		__clear_ack_timer(chan);
+		chan->tx_state = L2CAP_TX_STATE_WAIT_F;
+		break;
+	case L2CAP_EV_RETRANS_TO:
+		l2cap_send_rr_or_rnr(chan, 1);
+		chan->retry_count = 1;
+		__set_monitor_timer(chan);
+		chan->tx_state = L2CAP_TX_STATE_WAIT_F;
+		break;
+	case L2CAP_EV_RECV_FBIT:
+		/* Nothing to process */
+		break;
+	default:
+		break;
+	}
+}
+
+static void l2cap_tx_state_wait_f(struct l2cap_chan *chan,
+				  struct l2cap_ctrl *control,
+				  struct sk_buff_head *skbs, u8 event)
+{
+	BT_DBG("chan %p, control %p, skbs %p, event %d", chan, control, skbs,
+	       event);
+
+	switch (event) {
+	case L2CAP_EV_DATA_REQUEST:
+		if (chan->tx_send_head == NULL)
+			chan->tx_send_head = skb_peek(skbs);
+		/* Queue data, but don't send. */
+		skb_queue_splice_tail_init(skbs, &chan->tx_q);
+		break;
+	case L2CAP_EV_LOCAL_BUSY_DETECTED:
+		BT_DBG("Enter LOCAL_BUSY");
+		set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
+
+		if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
+			/* The SREJ_SENT state must be aborted if we are to
+			 * enter the LOCAL_BUSY state.
+			 */
+			l2cap_abort_rx_srej_sent(chan);
+		}
+
+		l2cap_send_ack(chan);
+
+		break;
+	case L2CAP_EV_LOCAL_BUSY_CLEAR:
+		BT_DBG("Exit LOCAL_BUSY");
+		clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
+
+		if (test_bit(CONN_RNR_SENT, &chan->conn_state)) {
+			struct l2cap_ctrl local_control;
+			memset(&local_control, 0, sizeof(local_control));
+			local_control.sframe = 1;
+			local_control.super = L2CAP_SUPER_RR;
+			local_control.poll = 1;
+			local_control.reqseq = chan->buffer_seq;
+			l2cap_send_sframe(chan, &local_control);
+
+			chan->retry_count = 1;
+			__set_monitor_timer(chan);
+			chan->tx_state = L2CAP_TX_STATE_WAIT_F;
+		}
+		break;
+	case L2CAP_EV_RECV_REQSEQ_AND_FBIT:
+		l2cap_process_reqseq(chan, control->reqseq);
+
+		/* Fall through */
+
+	case L2CAP_EV_RECV_FBIT:
+		if (control && control->final) {
+			__clear_monitor_timer(chan);
+			if (chan->unacked_frames > 0)
+				__set_retrans_timer(chan);
+			chan->retry_count = 0;
+			chan->tx_state = L2CAP_TX_STATE_XMIT;
+			BT_DBG("recv fbit tx_state 0x2.2%x", chan->tx_state);
+		}
+		break;
+	case L2CAP_EV_EXPLICIT_POLL:
+		/* Ignore */
+		break;
+	case L2CAP_EV_MONITOR_TO:
+		if (chan->max_tx == 0 || chan->retry_count < chan->max_tx) {
+			l2cap_send_rr_or_rnr(chan, 1);
+			__set_monitor_timer(chan);
+			chan->retry_count++;
+		} else {
+			l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
+		     struct sk_buff_head *skbs, u8 event)
+{
+	BT_DBG("chan %p, control %p, skbs %p, event %d, state %d",
+	       chan, control, skbs, event, chan->tx_state);
+
+	switch (chan->tx_state) {
+	case L2CAP_TX_STATE_XMIT:
+		l2cap_tx_state_xmit(chan, control, skbs, event);
+		break;
+	case L2CAP_TX_STATE_WAIT_F:
+		l2cap_tx_state_wait_f(chan, control, skbs, event);
+		break;
+	default:
+		/* Ignore event */
+		break;
+	}
+}
+
+static void l2cap_pass_to_tx(struct l2cap_chan *chan,
+			     struct l2cap_ctrl *control)
+{
+	BT_DBG("chan %p, control %p", chan, control);
+	l2cap_tx(chan, control, NULL, L2CAP_EV_RECV_REQSEQ_AND_FBIT);
+}
+
+static void l2cap_pass_to_tx_fbit(struct l2cap_chan *chan,
+				  struct l2cap_ctrl *control)
+{
+	BT_DBG("chan %p, control %p", chan, control);
+	l2cap_tx(chan, control, NULL, L2CAP_EV_RECV_FBIT);
+}
+
 /* Copy frame to all raw sockets on that connection */
 static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 {
@@ -2165,7 +2526,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 		if (!nskb)
 			continue;
 
-		if (chan->ops->recv(chan->data, nskb))
+		if (chan->ops->recv(chan, nskb))
 			kfree_skb(nskb);
 	}
 
@@ -2195,9 +2556,9 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
 	lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
 
 	if (conn->hcon->type == LE_LINK)
-		lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
+		lh->cid = __constant_cpu_to_le16(L2CAP_CID_LE_SIGNALING);
 	else
-		lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
+		lh->cid = __constant_cpu_to_le16(L2CAP_CID_SIGNALING);
 
 	cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
 	cmd->code  = code;
@@ -2309,8 +2670,8 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
 		efs.stype	= chan->local_stype;
 		efs.msdu	= cpu_to_le16(chan->local_msdu);
 		efs.sdu_itime	= cpu_to_le32(chan->local_sdu_itime);
-		efs.acc_lat	= cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
-		efs.flush_to	= cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
+		efs.acc_lat	= __constant_cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
+		efs.flush_to	= __constant_cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
 		break;
 
 	case L2CAP_MODE_STREAMING:
@@ -2333,20 +2694,24 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
 static void l2cap_ack_timeout(struct work_struct *work)
 {
 	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
-							ack_timer.work);
+					       ack_timer.work);
+	u16 frames_to_ack;
 
 	BT_DBG("chan %p", chan);
 
 	l2cap_chan_lock(chan);
 
-	__l2cap_send_ack(chan);
+	frames_to_ack = __seq_offset(chan, chan->buffer_seq,
+				     chan->last_acked_seq);
 
-	l2cap_chan_unlock(chan);
+	if (frames_to_ack)
+		l2cap_send_rr_or_rnr(chan, 0);
 
+	l2cap_chan_unlock(chan);
 	l2cap_chan_put(chan);
 }
 
-static inline int l2cap_ertm_init(struct l2cap_chan *chan)
+int l2cap_ertm_init(struct l2cap_chan *chan)
 {
 	int err;
 
@@ -2355,7 +2720,6 @@ static inline int l2cap_ertm_init(struct l2cap_chan *chan)
 	chan->expected_ack_seq = 0;
 	chan->unacked_frames = 0;
 	chan->buffer_seq = 0;
-	chan->num_acked = 0;
 	chan->frames_sent = 0;
 	chan->last_acked_seq = 0;
 	chan->sdu = NULL;
@@ -2376,12 +2740,15 @@ static inline int l2cap_ertm_init(struct l2cap_chan *chan)
 
 	skb_queue_head_init(&chan->srej_q);
 
-	INIT_LIST_HEAD(&chan->srej_l);
 	err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win);
 	if (err < 0)
 		return err;
 
-	return l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win);
+	err = l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win);
+	if (err < 0)
+		l2cap_seq_list_free(&chan->srej_list);
+
+	return err;
 }
 
 static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
@@ -2507,6 +2874,7 @@ done:
 		break;
 
 	case L2CAP_MODE_STREAMING:
+		l2cap_txwin_setup(chan);
 		rfc.mode            = L2CAP_MODE_STREAMING;
 		rfc.txwin_size      = 0;
 		rfc.max_transmit    = 0;
@@ -2537,7 +2905,7 @@ done:
 	}
 
 	req->dcid  = cpu_to_le16(chan->dcid);
-	req->flags = cpu_to_le16(0);
+	req->flags = __constant_cpu_to_le16(0);
 
 	return ptr - data;
 }
@@ -2757,7 +3125,7 @@ done:
 	}
 	rsp->scid   = cpu_to_le16(chan->dcid);
 	rsp->result = cpu_to_le16(result);
-	rsp->flags  = cpu_to_le16(0x0000);
+	rsp->flags  = __constant_cpu_to_le16(0);
 
 	return ptr - data;
 }
@@ -2856,7 +3224,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
 	}
 
 	req->dcid   = cpu_to_le16(chan->dcid);
-	req->flags  = cpu_to_le16(0x0000);
+	req->flags  = __constant_cpu_to_le16(0);
 
 	return ptr - data;
 }
@@ -2883,8 +3251,8 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
 
 	rsp.scid   = cpu_to_le16(chan->dcid);
 	rsp.dcid   = cpu_to_le16(chan->scid);
-	rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
-	rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+	rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
+	rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
 	l2cap_send_cmd(conn, chan->ident,
 				L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 
@@ -2910,20 +3278,22 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
 	while (len >= L2CAP_CONF_OPT_SIZE) {
 		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
 
-		switch (type) {
-		case L2CAP_CONF_RFC:
-			if (olen == sizeof(rfc))
-				memcpy(&rfc, (void *)val, olen);
-			goto done;
-		}
+		if (type != L2CAP_CONF_RFC)
+			continue;
+
+		if (olen != sizeof(rfc))
+			break;
+
+		memcpy(&rfc, (void *)val, olen);
+		goto done;
 	}
 
 	/* Use sane default values in case a misbehaving remote device
 	 * did not send an RFC option.
 	 */
 	rfc.mode = chan->mode;
-	rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
-	rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+	rfc.retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
+	rfc.monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
 	rfc.max_pdu_size = cpu_to_le16(chan->imtu);
 
 	BT_ERR("Expected RFC option was not found, using defaults");
@@ -2986,7 +3356,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 	lock_sock(parent);
 
 	/* Check if the ACL is secure enough (if not SDP) */
-	if (psm != cpu_to_le16(0x0001) &&
+	if (psm != __constant_cpu_to_le16(L2CAP_PSM_SDP) &&
 				!hci_conn_check_link_mode(conn->hcon)) {
 		conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
 		result = L2CAP_CR_SEC_BLOCK;
@@ -2995,25 +3365,16 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
 	result = L2CAP_CR_NO_MEM;
 
-	/* Check for backlog size */
-	if (sk_acceptq_is_full(parent)) {
-		BT_DBG("backlog full %d", parent->sk_ack_backlog);
+	/* Check if we already have channel with that dcid */
+	if (__l2cap_get_chan_by_dcid(conn, scid))
 		goto response;
-	}
 
-	chan = pchan->ops->new_connection(pchan->data);
+	chan = pchan->ops->new_connection(pchan);
 	if (!chan)
 		goto response;
 
 	sk = chan->sk;
 
-	/* Check if we already have channel with that dcid */
-	if (__l2cap_get_chan_by_dcid(conn, scid)) {
-		sock_set_flag(sk, SOCK_ZAPPED);
-		chan->ops->close(chan->data);
-		goto response;
-	}
-
 	hci_conn_hold(conn->hcon);
 
 	bacpy(&bt_sk(sk)->src, conn->src);
@@ -3067,7 +3428,7 @@ sendresp:
 
 	if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
 		struct l2cap_info_req info;
-		info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+		info.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
 
 		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
 		conn->info_ident = l2cap_get_ident(conn);
@@ -3189,7 +3550,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
 		struct l2cap_cmd_rej_cid rej;
 
-		rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
+		rej.reason = __constant_cpu_to_le16(L2CAP_REJ_INVALID_CID);
 		rej.scid = cpu_to_le16(chan->scid);
 		rej.dcid = cpu_to_le16(chan->dcid);
 
@@ -3211,11 +3572,11 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	memcpy(chan->conf_req + chan->conf_len, req->data, len);
 	chan->conf_len += len;
 
-	if (flags & 0x0001) {
+	if (flags & L2CAP_CONF_FLAG_CONTINUATION) {
 		/* Incomplete config. Send empty response. */
 		l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
 				l2cap_build_conf_rsp(chan, rsp,
-					L2CAP_CONF_SUCCESS, 0x0001), rsp);
+					L2CAP_CONF_SUCCESS, flags), rsp);
 		goto unlock;
 	}
 
@@ -3238,8 +3599,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
 		set_default_fcs(chan);
 
-		l2cap_state_change(chan, BT_CONNECTED);
-
 		if (chan->mode == L2CAP_MODE_ERTM ||
 		    chan->mode == L2CAP_MODE_STREAMING)
 			err = l2cap_ertm_init(chan);
@@ -3271,7 +3630,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
 		l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
 					l2cap_build_conf_rsp(chan, rsp,
-					L2CAP_CONF_SUCCESS, 0x0000), rsp);
+					L2CAP_CONF_SUCCESS, flags), rsp);
 	}
 
 unlock:
@@ -3362,7 +3721,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 		goto done;
 	}
 
-	if (flags & 0x01)
+	if (flags & L2CAP_CONF_FLAG_CONTINUATION)
 		goto done;
 
 	set_bit(CONF_INPUT_DONE, &chan->conf_state);
@@ -3370,7 +3729,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
 		set_default_fcs(chan);
 
-		l2cap_state_change(chan, BT_CONNECTED);
 		if (chan->mode == L2CAP_MODE_ERTM ||
 		    chan->mode == L2CAP_MODE_STREAMING)
 			err = l2cap_ertm_init(chan);
@@ -3424,7 +3782,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 
 	l2cap_chan_unlock(chan);
 
-	chan->ops->close(chan->data);
+	chan->ops->close(chan);
 	l2cap_chan_put(chan);
 
 	mutex_unlock(&conn->chan_lock);
@@ -3458,7 +3816,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
 
 	l2cap_chan_unlock(chan);
 
-	chan->ops->close(chan->data);
+	chan->ops->close(chan);
 	l2cap_chan_put(chan);
 
 	mutex_unlock(&conn->chan_lock);
@@ -3479,8 +3837,8 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
 		u8 buf[8];
 		u32 feat_mask = l2cap_feat_mask;
 		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);
+		rsp->type   = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
+		rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS);
 		if (!disable_ertm)
 			feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
 							 | L2CAP_FEAT_FCS;
@@ -3500,15 +3858,15 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
 		else
 			l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
 
-		rsp->type   = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
-		rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
+		rsp->type   = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN);
+		rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS);
 		memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
 		l2cap_send_cmd(conn, cmd->ident,
 					L2CAP_INFO_RSP, sizeof(buf), buf);
 	} else {
 		struct l2cap_info_rsp rsp;
 		rsp.type   = cpu_to_le16(type);
-		rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
+		rsp.result = __constant_cpu_to_le16(L2CAP_IR_NOTSUPP);
 		l2cap_send_cmd(conn, cmd->ident,
 					L2CAP_INFO_RSP, sizeof(rsp), &rsp);
 	}
@@ -3548,7 +3906,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
 		if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
 			struct l2cap_info_req req;
-			req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
+			req.type = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN);
 
 			conn->info_ident = l2cap_get_ident(conn);
 
@@ -3783,9 +4141,9 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
 
 	err = l2cap_check_conn_param(min, max, latency, to_multiplier);
 	if (err)
-		rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
+		rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
 	else
-		rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
+		rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
 
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
 							sizeof(rsp), &rsp);
@@ -3933,7 +4291,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 			BT_ERR("Wrong link type (%d)", err);
 
 			/* FIXME: Map err to a valid reason */
-			rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
+			rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
 			l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
 		}
 
@@ -3965,67 +4323,40 @@ static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 	return 0;
 }
 
-static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
+static void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 {
-	u32 control = 0;
+	struct l2cap_ctrl control;
 
-	chan->frames_sent = 0;
+	BT_DBG("chan %p", chan);
 
-	control |= __set_reqseq(chan, chan->buffer_seq);
+	memset(&control, 0, sizeof(control));
+	control.sframe = 1;
+	control.final = 1;
+	control.reqseq = chan->buffer_seq;
+	set_bit(CONN_SEND_FBIT, &chan->conn_state);
 
 	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-		control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
-		l2cap_send_sframe(chan, control);
-		set_bit(CONN_RNR_SENT, &chan->conn_state);
+		control.super = L2CAP_SUPER_RNR;
+		l2cap_send_sframe(chan, &control);
 	}
 
-	if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
-		l2cap_retransmit_frames(chan);
+	if (test_and_clear_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
+	    chan->unacked_frames > 0)
+		__set_retrans_timer(chan);
 
+	/* Send pending iframes */
 	l2cap_ertm_send(chan);
 
 	if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
-			chan->frames_sent == 0) {
-		control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
-		l2cap_send_sframe(chan, control);
+	    test_bit(CONN_SEND_FBIT, &chan->conn_state)) {
+		/* F-bit wasn't sent in an s-frame or i-frame yet, so
+		 * send it now.
+		 */
+		control.super = L2CAP_SUPER_RR;
+		l2cap_send_sframe(chan, &control);
 	}
 }
 
-static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
-{
-	struct sk_buff *next_skb;
-	int tx_seq_offset, next_tx_seq_offset;
-
-	bt_cb(skb)->control.txseq = tx_seq;
-	bt_cb(skb)->control.sar = sar;
-
-	next_skb = skb_peek(&chan->srej_q);
-
-	tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
-
-	while (next_skb) {
-		if (bt_cb(next_skb)->control.txseq == tx_seq)
-			return -EINVAL;
-
-		next_tx_seq_offset = __seq_offset(chan,
-			bt_cb(next_skb)->control.txseq, chan->buffer_seq);
-
-		if (next_tx_seq_offset > tx_seq_offset) {
-			__skb_queue_before(&chan->srej_q, next_skb, skb);
-			return 0;
-		}
-
-		if (skb_queue_is_last(&chan->srej_q, next_skb))
-			next_skb = NULL;
-		else
-			next_skb = skb_queue_next(&chan->srej_q, next_skb);
-	}
-
-	__skb_queue_tail(&chan->srej_q, skb);
-
-	return 0;
-}
-
 static void append_skb_frag(struct sk_buff *skb,
 			struct sk_buff *new_frag, struct sk_buff **last_frag)
 {
@@ -4045,16 +4376,17 @@ static void append_skb_frag(struct sk_buff *skb,
 	skb->truesize += new_frag->truesize;
 }
 
-static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
+static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb,
+				struct l2cap_ctrl *control)
 {
 	int err = -EINVAL;
 
-	switch (__get_ctrl_sar(chan, control)) {
+	switch (control->sar) {
 	case L2CAP_SAR_UNSEGMENTED:
 		if (chan->sdu)
 			break;
 
-		err = chan->ops->recv(chan->data, skb);
+		err = chan->ops->recv(chan, skb);
 		break;
 
 	case L2CAP_SAR_START:
@@ -4104,7 +4436,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3
 		if (chan->sdu->len != chan->sdu_len)
 			break;
 
-		err = chan->ops->recv(chan->data, chan->sdu);
+		err = chan->ops->recv(chan, chan->sdu);
 
 		if (!err) {
 			/* Reassembly complete */
@@ -4126,448 +4458,609 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3
 	return err;
 }
 
-static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
+void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
 {
-	BT_DBG("chan %p, Enter local busy", chan);
+	u8 event;
 
-	set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
-	l2cap_seq_list_clear(&chan->srej_list);
+	if (chan->mode != L2CAP_MODE_ERTM)
+		return;
 
-	__set_ack_timer(chan);
+	event = busy ? L2CAP_EV_LOCAL_BUSY_DETECTED : L2CAP_EV_LOCAL_BUSY_CLEAR;
+	l2cap_tx(chan, NULL, NULL, event);
 }
 
-static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
+static int l2cap_rx_queued_iframes(struct l2cap_chan *chan)
 {
-	u32 control;
-
-	if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
-		goto done;
+	int err = 0;
+	/* Pass sequential frames to l2cap_reassemble_sdu()
+	 * until a gap is encountered.
+	 */
 
-	control = __set_reqseq(chan, chan->buffer_seq);
-	control |= __set_ctrl_poll(chan);
-	control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
-	l2cap_send_sframe(chan, control);
-	chan->retry_count = 1;
+	BT_DBG("chan %p", chan);
 
-	__clear_retrans_timer(chan);
-	__set_monitor_timer(chan);
+	while (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+		struct sk_buff *skb;
+		BT_DBG("Searching for skb with txseq %d (queue len %d)",
+		       chan->buffer_seq, skb_queue_len(&chan->srej_q));
 
-	set_bit(CONN_WAIT_F, &chan->conn_state);
+		skb = l2cap_ertm_seq_in_queue(&chan->srej_q, chan->buffer_seq);
 
-done:
-	clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
-	clear_bit(CONN_RNR_SENT, &chan->conn_state);
+		if (!skb)
+			break;
 
-	BT_DBG("chan %p, Exit local busy", chan);
-}
+		skb_unlink(skb, &chan->srej_q);
+		chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
+		err = l2cap_reassemble_sdu(chan, skb, &bt_cb(skb)->control);
+		if (err)
+			break;
+	}
 
-void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
-{
-	if (chan->mode == L2CAP_MODE_ERTM) {
-		if (busy)
-			l2cap_ertm_enter_local_busy(chan);
-		else
-			l2cap_ertm_exit_local_busy(chan);
+	if (skb_queue_empty(&chan->srej_q)) {
+		chan->rx_state = L2CAP_RX_STATE_RECV;
+		l2cap_send_ack(chan);
 	}
+
+	return err;
 }
 
-static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
+static void l2cap_handle_srej(struct l2cap_chan *chan,
+			      struct l2cap_ctrl *control)
 {
 	struct sk_buff *skb;
-	u32 control;
 
-	while ((skb = skb_peek(&chan->srej_q)) &&
-			!test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-		int err;
+	BT_DBG("chan %p, control %p", chan, control);
 
-		if (bt_cb(skb)->control.txseq != tx_seq)
-			break;
+	if (control->reqseq == chan->next_tx_seq) {
+		BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
+		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+		return;
+	}
 
-		skb = skb_dequeue(&chan->srej_q);
-		control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
-		err = l2cap_reassemble_sdu(chan, skb, control);
+	skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq);
 
-		if (err < 0) {
-			l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-			break;
-		}
+	if (skb == NULL) {
+		BT_DBG("Seq %d not available for retransmission",
+		       control->reqseq);
+		return;
+	}
 
-		chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
-		tx_seq = __next_seq(chan, tx_seq);
+	if (chan->max_tx != 0 && bt_cb(skb)->control.retries >= chan->max_tx) {
+		BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
+		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+		return;
 	}
-}
 
-static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
-{
-	struct srej_list *l, *tmp;
-	u32 control;
+	clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-	list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
-		if (l->tx_seq == tx_seq) {
-			list_del(&l->list);
-			kfree(l);
-			return;
+	if (control->poll) {
+		l2cap_pass_to_tx(chan, control);
+
+		set_bit(CONN_SEND_FBIT, &chan->conn_state);
+		l2cap_retransmit(chan, control);
+		l2cap_ertm_send(chan);
+
+		if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) {
+			set_bit(CONN_SREJ_ACT, &chan->conn_state);
+			chan->srej_save_reqseq = control->reqseq;
+		}
+	} else {
+		l2cap_pass_to_tx_fbit(chan, control);
+
+		if (control->final) {
+			if (chan->srej_save_reqseq != control->reqseq ||
+			    !test_and_clear_bit(CONN_SREJ_ACT,
+						&chan->conn_state))
+				l2cap_retransmit(chan, control);
+		} else {
+			l2cap_retransmit(chan, control);
+			if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) {
+				set_bit(CONN_SREJ_ACT, &chan->conn_state);
+				chan->srej_save_reqseq = control->reqseq;
+			}
 		}
-		control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
-		control |= __set_reqseq(chan, l->tx_seq);
-		l2cap_send_sframe(chan, control);
-		list_del(&l->list);
-		list_add_tail(&l->list, &chan->srej_l);
 	}
 }
 
-static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
+static void l2cap_handle_rej(struct l2cap_chan *chan,
+			     struct l2cap_ctrl *control)
 {
-	struct srej_list *new;
-	u32 control;
-
-	while (tx_seq != chan->expected_tx_seq) {
-		control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
-		control |= __set_reqseq(chan, chan->expected_tx_seq);
-		l2cap_seq_list_append(&chan->srej_list, chan->expected_tx_seq);
-		l2cap_send_sframe(chan, control);
+	struct sk_buff *skb;
 
-		new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
-		if (!new)
-			return -ENOMEM;
+	BT_DBG("chan %p, control %p", chan, control);
 
-		new->tx_seq = chan->expected_tx_seq;
+	if (control->reqseq == chan->next_tx_seq) {
+		BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
+		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+		return;
+	}
 
-		chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
+	skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq);
 
-		list_add_tail(&new->list, &chan->srej_l);
+	if (chan->max_tx && skb &&
+	    bt_cb(skb)->control.retries >= chan->max_tx) {
+		BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
+		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+		return;
 	}
 
-	chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
+	clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-	return 0;
+	l2cap_pass_to_tx(chan, control);
+
+	if (control->final) {
+		if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
+			l2cap_retransmit_all(chan, control);
+	} else {
+		l2cap_retransmit_all(chan, control);
+		l2cap_ertm_send(chan);
+		if (chan->tx_state == L2CAP_TX_STATE_WAIT_F)
+			set_bit(CONN_REJ_ACT, &chan->conn_state);
+	}
 }
 
-static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
+static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq)
 {
-	u16 tx_seq = __get_txseq(chan, rx_control);
-	u16 req_seq = __get_reqseq(chan, rx_control);
-	u8 sar = __get_ctrl_sar(chan, rx_control);
-	int tx_seq_offset, expected_tx_seq_offset;
-	int num_to_ack = (chan->tx_win/6) + 1;
-	int err = 0;
+	BT_DBG("chan %p, txseq %d", chan, txseq);
 
-	BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
-							tx_seq, rx_control);
+	BT_DBG("last_acked_seq %d, expected_tx_seq %d", chan->last_acked_seq,
+	       chan->expected_tx_seq);
 
-	if (__is_ctrl_final(chan, rx_control) &&
-			test_bit(CONN_WAIT_F, &chan->conn_state)) {
-		__clear_monitor_timer(chan);
-		if (chan->unacked_frames > 0)
-			__set_retrans_timer(chan);
-		clear_bit(CONN_WAIT_F, &chan->conn_state);
-	}
+	if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
+		if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
+								chan->tx_win) {
+			/* See notes below regarding "double poll" and
+			 * invalid packets.
+			 */
+			if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) {
+				BT_DBG("Invalid/Ignore - after SREJ");
+				return L2CAP_TXSEQ_INVALID_IGNORE;
+			} else {
+				BT_DBG("Invalid - in window after SREJ sent");
+				return L2CAP_TXSEQ_INVALID;
+			}
+		}
 
-	chan->expected_ack_seq = req_seq;
-	l2cap_drop_acked_frames(chan);
+		if (chan->srej_list.head == txseq) {
+			BT_DBG("Expected SREJ");
+			return L2CAP_TXSEQ_EXPECTED_SREJ;
+		}
 
-	tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
+		if (l2cap_ertm_seq_in_queue(&chan->srej_q, txseq)) {
+			BT_DBG("Duplicate SREJ - txseq already stored");
+			return L2CAP_TXSEQ_DUPLICATE_SREJ;
+		}
 
-	/* invalid tx_seq */
-	if (tx_seq_offset >= chan->tx_win) {
-		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-		goto drop;
+		if (l2cap_seq_list_contains(&chan->srej_list, txseq)) {
+			BT_DBG("Unexpected SREJ - not requested");
+			return L2CAP_TXSEQ_UNEXPECTED_SREJ;
+		}
 	}
 
-	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-		if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
-			l2cap_send_ack(chan);
-		goto drop;
+	if (chan->expected_tx_seq == txseq) {
+		if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
+		    chan->tx_win) {
+			BT_DBG("Invalid - txseq outside tx window");
+			return L2CAP_TXSEQ_INVALID;
+		} else {
+			BT_DBG("Expected");
+			return L2CAP_TXSEQ_EXPECTED;
+		}
 	}
 
-	if (tx_seq == chan->expected_tx_seq)
-		goto expected;
+	if (__seq_offset(chan, txseq, chan->last_acked_seq) <
+		__seq_offset(chan, chan->expected_tx_seq,
+			     chan->last_acked_seq)){
+		BT_DBG("Duplicate - expected_tx_seq later than txseq");
+		return L2CAP_TXSEQ_DUPLICATE;
+	}
+
+	if (__seq_offset(chan, txseq, chan->last_acked_seq) >= chan->tx_win) {
+		/* A source of invalid packets is a "double poll" condition,
+		 * where delays cause us to send multiple poll packets.  If
+		 * the remote stack receives and processes both polls,
+		 * sequence numbers can wrap around in such a way that a
+		 * resent frame has a sequence number that looks like new data
+		 * with a sequence gap.  This would trigger an erroneous SREJ
+		 * request.
+		 *
+		 * Fortunately, this is impossible with a tx window that's
+		 * less than half of the maximum sequence number, which allows
+		 * invalid frames to be safely ignored.
+		 *
+		 * With tx window sizes greater than half of the tx window
+		 * maximum, the frame is invalid and cannot be ignored.  This
+		 * causes a disconnect.
+		 */
+
+		if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) {
+			BT_DBG("Invalid/Ignore - txseq outside tx window");
+			return L2CAP_TXSEQ_INVALID_IGNORE;
+		} else {
+			BT_DBG("Invalid - txseq outside tx window");
+			return L2CAP_TXSEQ_INVALID;
+		}
+	} else {
+		BT_DBG("Unexpected - txseq indicates missing frames");
+		return L2CAP_TXSEQ_UNEXPECTED;
+	}
+}
 
-	if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
-		struct srej_list *first;
+static int l2cap_rx_state_recv(struct l2cap_chan *chan,
+			       struct l2cap_ctrl *control,
+			       struct sk_buff *skb, u8 event)
+{
+	int err = 0;
+	bool skb_in_use = 0;
 
-		first = list_first_entry(&chan->srej_l,
-				struct srej_list, list);
-		if (tx_seq == first->tx_seq) {
-			l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
-			l2cap_check_srej_gap(chan, tx_seq);
+	BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
+	       event);
 
-			list_del(&first->list);
-			kfree(first);
+	switch (event) {
+	case L2CAP_EV_RECV_IFRAME:
+		switch (l2cap_classify_txseq(chan, control->txseq)) {
+		case L2CAP_TXSEQ_EXPECTED:
+			l2cap_pass_to_tx(chan, control);
 
-			if (list_empty(&chan->srej_l)) {
-				chan->buffer_seq = chan->buffer_seq_srej;
-				clear_bit(CONN_SREJ_SENT, &chan->conn_state);
-				l2cap_send_ack(chan);
-				BT_DBG("chan %p, Exit SREJ_SENT", chan);
+			if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+				BT_DBG("Busy, discarding expected seq %d",
+				       control->txseq);
+				break;
 			}
-		} else {
-			struct srej_list *l;
 
-			/* duplicated tx_seq */
-			if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
-				goto drop;
+			chan->expected_tx_seq = __next_seq(chan,
+							   control->txseq);
+
+			chan->buffer_seq = chan->expected_tx_seq;
+			skb_in_use = 1;
 
-			list_for_each_entry(l, &chan->srej_l, list) {
-				if (l->tx_seq == tx_seq) {
-					l2cap_resend_srejframe(chan, tx_seq);
-					return 0;
+			err = l2cap_reassemble_sdu(chan, skb, control);
+			if (err)
+				break;
+
+			if (control->final) {
+				if (!test_and_clear_bit(CONN_REJ_ACT,
+							&chan->conn_state)) {
+					control->final = 0;
+					l2cap_retransmit_all(chan, control);
+					l2cap_ertm_send(chan);
 				}
 			}
 
-			err = l2cap_send_srejframe(chan, tx_seq);
-			if (err < 0) {
-				l2cap_send_disconn_req(chan->conn, chan, -err);
-				return err;
+			if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
+				l2cap_send_ack(chan);
+			break;
+		case L2CAP_TXSEQ_UNEXPECTED:
+			l2cap_pass_to_tx(chan, control);
+
+			/* Can't issue SREJ frames in the local busy state.
+			 * Drop this frame, it will be seen as missing
+			 * when local busy is exited.
+			 */
+			if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+				BT_DBG("Busy, discarding unexpected seq %d",
+				       control->txseq);
+				break;
 			}
-		}
-	} else {
-		expected_tx_seq_offset = __seq_offset(chan,
-				chan->expected_tx_seq, chan->buffer_seq);
 
-		/* duplicated tx_seq */
-		if (tx_seq_offset < expected_tx_seq_offset)
-			goto drop;
-
-		set_bit(CONN_SREJ_SENT, &chan->conn_state);
+			/* There was a gap in the sequence, so an SREJ
+			 * must be sent for each missing frame.  The
+			 * current frame is stored for later use.
+			 */
+			skb_queue_tail(&chan->srej_q, skb);
+			skb_in_use = 1;
+			BT_DBG("Queued %p (queue len %d)", skb,
+			       skb_queue_len(&chan->srej_q));
 
-		BT_DBG("chan %p, Enter SREJ", chan);
+			clear_bit(CONN_SREJ_ACT, &chan->conn_state);
+			l2cap_seq_list_clear(&chan->srej_list);
+			l2cap_send_srej(chan, control->txseq);
 
-		INIT_LIST_HEAD(&chan->srej_l);
-		chan->buffer_seq_srej = chan->buffer_seq;
+			chan->rx_state = L2CAP_RX_STATE_SREJ_SENT;
+			break;
+		case L2CAP_TXSEQ_DUPLICATE:
+			l2cap_pass_to_tx(chan, control);
+			break;
+		case L2CAP_TXSEQ_INVALID_IGNORE:
+			break;
+		case L2CAP_TXSEQ_INVALID:
+		default:
+			l2cap_send_disconn_req(chan->conn, chan,
+					       ECONNRESET);
+			break;
+		}
+		break;
+	case L2CAP_EV_RECV_RR:
+		l2cap_pass_to_tx(chan, control);
+		if (control->final) {
+			clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-		__skb_queue_head_init(&chan->srej_q);
-		l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
+			if (!test_and_clear_bit(CONN_REJ_ACT,
+						&chan->conn_state)) {
+				control->final = 0;
+				l2cap_retransmit_all(chan, control);
+			}
 
-		/* Set P-bit only if there are some I-frames to ack. */
-		if (__clear_ack_timer(chan))
-			set_bit(CONN_SEND_PBIT, &chan->conn_state);
+			l2cap_ertm_send(chan);
+		} else if (control->poll) {
+			l2cap_send_i_or_rr_or_rnr(chan);
+		} else {
+			if (test_and_clear_bit(CONN_REMOTE_BUSY,
+					       &chan->conn_state) &&
+			    chan->unacked_frames)
+				__set_retrans_timer(chan);
 
-		err = l2cap_send_srejframe(chan, tx_seq);
-		if (err < 0) {
-			l2cap_send_disconn_req(chan->conn, chan, -err);
-			return err;
+			l2cap_ertm_send(chan);
 		}
+		break;
+	case L2CAP_EV_RECV_RNR:
+		set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
+		l2cap_pass_to_tx(chan, control);
+		if (control && control->poll) {
+			set_bit(CONN_SEND_FBIT, &chan->conn_state);
+			l2cap_send_rr_or_rnr(chan, 0);
+		}
+		__clear_retrans_timer(chan);
+		l2cap_seq_list_clear(&chan->retrans_list);
+		break;
+	case L2CAP_EV_RECV_REJ:
+		l2cap_handle_rej(chan, control);
+		break;
+	case L2CAP_EV_RECV_SREJ:
+		l2cap_handle_srej(chan, control);
+		break;
+	default:
+		break;
 	}
-	return 0;
-
-expected:
-	chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
-
-	if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
-		bt_cb(skb)->control.txseq = tx_seq;
-		bt_cb(skb)->control.sar = sar;
-		__skb_queue_tail(&chan->srej_q, skb);
-		return 0;
-	}
-
-	err = l2cap_reassemble_sdu(chan, skb, rx_control);
-	chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
 
-	if (err < 0) {
-		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-		return err;
+	if (skb && !skb_in_use) {
+		BT_DBG("Freeing %p", skb);
+		kfree_skb(skb);
 	}
 
-	if (__is_ctrl_final(chan, rx_control)) {
-		if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
-			l2cap_retransmit_frames(chan);
-	}
+	return err;
+}
 
+static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
+				    struct l2cap_ctrl *control,
+				    struct sk_buff *skb, u8 event)
+{
+	int err = 0;
+	u16 txseq = control->txseq;
+	bool skb_in_use = 0;
+
+	BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
+	       event);
+
+	switch (event) {
+	case L2CAP_EV_RECV_IFRAME:
+		switch (l2cap_classify_txseq(chan, txseq)) {
+		case L2CAP_TXSEQ_EXPECTED:
+			/* Keep frame for reassembly later */
+			l2cap_pass_to_tx(chan, control);
+			skb_queue_tail(&chan->srej_q, skb);
+			skb_in_use = 1;
+			BT_DBG("Queued %p (queue len %d)", skb,
+			       skb_queue_len(&chan->srej_q));
+
+			chan->expected_tx_seq = __next_seq(chan, txseq);
+			break;
+		case L2CAP_TXSEQ_EXPECTED_SREJ:
+			l2cap_seq_list_pop(&chan->srej_list);
 
-	chan->num_acked = (chan->num_acked + 1) % num_to_ack;
-	if (chan->num_acked == num_to_ack - 1)
-		l2cap_send_ack(chan);
-	else
-		__set_ack_timer(chan);
+			l2cap_pass_to_tx(chan, control);
+			skb_queue_tail(&chan->srej_q, skb);
+			skb_in_use = 1;
+			BT_DBG("Queued %p (queue len %d)", skb,
+			       skb_queue_len(&chan->srej_q));
 
-	return 0;
+			err = l2cap_rx_queued_iframes(chan);
+			if (err)
+				break;
 
-drop:
-	kfree_skb(skb);
-	return 0;
-}
+			break;
+		case L2CAP_TXSEQ_UNEXPECTED:
+			/* Got a frame that can't be reassembled yet.
+			 * Save it for later, and send SREJs to cover
+			 * the missing frames.
+			 */
+			skb_queue_tail(&chan->srej_q, skb);
+			skb_in_use = 1;
+			BT_DBG("Queued %p (queue len %d)", skb,
+			       skb_queue_len(&chan->srej_q));
+
+			l2cap_pass_to_tx(chan, control);
+			l2cap_send_srej(chan, control->txseq);
+			break;
+		case L2CAP_TXSEQ_UNEXPECTED_SREJ:
+			/* This frame was requested with an SREJ, but
+			 * some expected retransmitted frames are
+			 * missing.  Request retransmission of missing
+			 * SREJ'd frames.
+			 */
+			skb_queue_tail(&chan->srej_q, skb);
+			skb_in_use = 1;
+			BT_DBG("Queued %p (queue len %d)", skb,
+			       skb_queue_len(&chan->srej_q));
+
+			l2cap_pass_to_tx(chan, control);
+			l2cap_send_srej_list(chan, control->txseq);
+			break;
+		case L2CAP_TXSEQ_DUPLICATE_SREJ:
+			/* We've already queued this frame.  Drop this copy. */
+			l2cap_pass_to_tx(chan, control);
+			break;
+		case L2CAP_TXSEQ_DUPLICATE:
+			/* Expecting a later sequence number, so this frame
+			 * was already received.  Ignore it completely.
+			 */
+			break;
+		case L2CAP_TXSEQ_INVALID_IGNORE:
+			break;
+		case L2CAP_TXSEQ_INVALID:
+		default:
+			l2cap_send_disconn_req(chan->conn, chan,
+					       ECONNRESET);
+			break;
+		}
+		break;
+	case L2CAP_EV_RECV_RR:
+		l2cap_pass_to_tx(chan, control);
+		if (control->final) {
+			clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
-{
-	BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
-				__get_reqseq(chan, rx_control), rx_control);
+			if (!test_and_clear_bit(CONN_REJ_ACT,
+						&chan->conn_state)) {
+				control->final = 0;
+				l2cap_retransmit_all(chan, control);
+			}
 
-	chan->expected_ack_seq = __get_reqseq(chan, rx_control);
-	l2cap_drop_acked_frames(chan);
+			l2cap_ertm_send(chan);
+		} else if (control->poll) {
+			if (test_and_clear_bit(CONN_REMOTE_BUSY,
+					       &chan->conn_state) &&
+			    chan->unacked_frames) {
+				__set_retrans_timer(chan);
+			}
 
-	if (__is_ctrl_poll(chan, rx_control)) {
-		set_bit(CONN_SEND_FBIT, &chan->conn_state);
-		if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
-			if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
-					(chan->unacked_frames > 0))
+			set_bit(CONN_SEND_FBIT, &chan->conn_state);
+			l2cap_send_srej_tail(chan);
+		} else {
+			if (test_and_clear_bit(CONN_REMOTE_BUSY,
+					       &chan->conn_state) &&
+			    chan->unacked_frames)
 				__set_retrans_timer(chan);
 
-			clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-			l2cap_send_srejtail(chan);
+			l2cap_send_ack(chan);
+		}
+		break;
+	case L2CAP_EV_RECV_RNR:
+		set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
+		l2cap_pass_to_tx(chan, control);
+		if (control->poll) {
+			l2cap_send_srej_tail(chan);
 		} else {
-			l2cap_send_i_or_rr_or_rnr(chan);
+			struct l2cap_ctrl rr_control;
+			memset(&rr_control, 0, sizeof(rr_control));
+			rr_control.sframe = 1;
+			rr_control.super = L2CAP_SUPER_RR;
+			rr_control.reqseq = chan->buffer_seq;
+			l2cap_send_sframe(chan, &rr_control);
 		}
 
-	} else if (__is_ctrl_final(chan, rx_control)) {
-		clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-
-		if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
-			l2cap_retransmit_frames(chan);
-
-	} else {
-		if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
-				(chan->unacked_frames > 0))
-			__set_retrans_timer(chan);
+		break;
+	case L2CAP_EV_RECV_REJ:
+		l2cap_handle_rej(chan, control);
+		break;
+	case L2CAP_EV_RECV_SREJ:
+		l2cap_handle_srej(chan, control);
+		break;
+	}
 
-		clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-		if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
-			l2cap_send_ack(chan);
-		else
-			l2cap_ertm_send(chan);
+	if (skb && !skb_in_use) {
+		BT_DBG("Freeing %p", skb);
+		kfree_skb(skb);
 	}
+
+	return err;
 }
 
-static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
+static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq)
 {
-	u16 tx_seq = __get_reqseq(chan, rx_control);
+	/* Make sure reqseq is for a packet that has been sent but not acked */
+	u16 unacked;
 
-	BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
-
-	clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-
-	chan->expected_ack_seq = tx_seq;
-	l2cap_drop_acked_frames(chan);
-
-	if (__is_ctrl_final(chan, rx_control)) {
-		if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
-			l2cap_retransmit_frames(chan);
-	} else {
-		l2cap_retransmit_frames(chan);
-
-		if (test_bit(CONN_WAIT_F, &chan->conn_state))
-			set_bit(CONN_REJ_ACT, &chan->conn_state);
-	}
+	unacked = __seq_offset(chan, chan->next_tx_seq, chan->expected_ack_seq);
+	return __seq_offset(chan, chan->next_tx_seq, reqseq) <= unacked;
 }
-static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
-{
-	u16 tx_seq = __get_reqseq(chan, rx_control);
 
-	BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
-
-	clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-
-	if (__is_ctrl_poll(chan, rx_control)) {
-		chan->expected_ack_seq = tx_seq;
-		l2cap_drop_acked_frames(chan);
-
-		set_bit(CONN_SEND_FBIT, &chan->conn_state);
-		l2cap_retransmit_one_frame(chan, tx_seq);
+static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
+		    struct sk_buff *skb, u8 event)
+{
+	int err = 0;
 
-		l2cap_ertm_send(chan);
+	BT_DBG("chan %p, control %p, skb %p, event %d, state %d", chan,
+	       control, skb, event, chan->rx_state);
 
-		if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
-			chan->srej_save_reqseq = tx_seq;
-			set_bit(CONN_SREJ_ACT, &chan->conn_state);
+	if (__valid_reqseq(chan, control->reqseq)) {
+		switch (chan->rx_state) {
+		case L2CAP_RX_STATE_RECV:
+			err = l2cap_rx_state_recv(chan, control, skb, event);
+			break;
+		case L2CAP_RX_STATE_SREJ_SENT:
+			err = l2cap_rx_state_srej_sent(chan, control, skb,
+						       event);
+			break;
+		default:
+			/* shut it down */
+			break;
 		}
-	} else if (__is_ctrl_final(chan, rx_control)) {
-		if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
-				chan->srej_save_reqseq == tx_seq)
-			clear_bit(CONN_SREJ_ACT, &chan->conn_state);
-		else
-			l2cap_retransmit_one_frame(chan, tx_seq);
 	} else {
-		l2cap_retransmit_one_frame(chan, tx_seq);
-		if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
-			chan->srej_save_reqseq = tx_seq;
-			set_bit(CONN_SREJ_ACT, &chan->conn_state);
-		}
+		BT_DBG("Invalid reqseq %d (next_tx_seq %d, expected_ack_seq %d",
+		       control->reqseq, chan->next_tx_seq,
+		       chan->expected_ack_seq);
+		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 	}
+
+	return err;
 }
 
-static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
+static int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
+			   struct sk_buff *skb)
 {
-	u16 tx_seq = __get_reqseq(chan, rx_control);
+	int err = 0;
 
-	BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
+	BT_DBG("chan %p, control %p, skb %p, state %d", chan, control, skb,
+	       chan->rx_state);
 
-	set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-	chan->expected_ack_seq = tx_seq;
-	l2cap_drop_acked_frames(chan);
+	if (l2cap_classify_txseq(chan, control->txseq) ==
+	    L2CAP_TXSEQ_EXPECTED) {
+		l2cap_pass_to_tx(chan, control);
 
-	if (__is_ctrl_poll(chan, rx_control))
-		set_bit(CONN_SEND_FBIT, &chan->conn_state);
+		BT_DBG("buffer_seq %d->%d", chan->buffer_seq,
+		       __next_seq(chan, chan->buffer_seq));
 
-	if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
-		__clear_retrans_timer(chan);
-		if (__is_ctrl_poll(chan, rx_control))
-			l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
-		return;
-	}
+		chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
 
-	if (__is_ctrl_poll(chan, rx_control)) {
-		l2cap_send_srejtail(chan);
+		l2cap_reassemble_sdu(chan, skb, control);
 	} else {
-		rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
-		l2cap_send_sframe(chan, rx_control);
-	}
-}
-
-static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
-{
-	BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
+		if (chan->sdu) {
+			kfree_skb(chan->sdu);
+			chan->sdu = NULL;
+		}
+		chan->sdu_last_frag = NULL;
+		chan->sdu_len = 0;
 
-	if (__is_ctrl_final(chan, rx_control) &&
-			test_bit(CONN_WAIT_F, &chan->conn_state)) {
-		__clear_monitor_timer(chan);
-		if (chan->unacked_frames > 0)
-			__set_retrans_timer(chan);
-		clear_bit(CONN_WAIT_F, &chan->conn_state);
+		if (skb) {
+			BT_DBG("Freeing %p", skb);
+			kfree_skb(skb);
+		}
 	}
 
-	switch (__get_ctrl_super(chan, rx_control)) {
-	case L2CAP_SUPER_RR:
-		l2cap_data_channel_rrframe(chan, rx_control);
-		break;
-
-	case L2CAP_SUPER_REJ:
-		l2cap_data_channel_rejframe(chan, rx_control);
-		break;
-
-	case L2CAP_SUPER_SREJ:
-		l2cap_data_channel_srejframe(chan, rx_control);
-		break;
-
-	case L2CAP_SUPER_RNR:
-		l2cap_data_channel_rnrframe(chan, rx_control);
-		break;
-	}
+	chan->last_acked_seq = control->txseq;
+	chan->expected_tx_seq = __next_seq(chan, control->txseq);
 
-	kfree_skb(skb);
-	return 0;
+	return err;
 }
 
-static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
+static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
 {
-	u32 control;
-	u16 req_seq;
-	int len, next_tx_seq_offset, req_seq_offset;
+	struct l2cap_ctrl *control = &bt_cb(skb)->control;
+	u16 len;
+	u8 event;
 
 	__unpack_control(chan, skb);
 
-	control = __get_control(chan, skb->data);
-	skb_pull(skb, __ctrl_size(chan));
 	len = skb->len;
 
 	/*
 	 * We can just drop the corrupted I-frame here.
 	 * Receiver will miss it and start proper recovery
-	 * procedures and ask retransmission.
+	 * procedures and ask for retransmission.
 	 */
 	if (l2cap_check_fcs(chan, skb))
 		goto drop;
 
-	if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
+	if (!control->sframe && control->sar == L2CAP_SAR_START)
 		len -= L2CAP_SDULEN_SIZE;
 
 	if (chan->fcs == L2CAP_FCS_CRC16)
@@ -4578,34 +5071,57 @@ static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
 		goto drop;
 	}
 
-	req_seq = __get_reqseq(chan, control);
-
-	req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
-
-	next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
-						chan->expected_ack_seq);
+	if (!control->sframe) {
+		int err;
 
-	/* check for invalid req-seq */
-	if (req_seq_offset > next_tx_seq_offset) {
-		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-		goto drop;
-	}
+		BT_DBG("iframe sar %d, reqseq %d, final %d, txseq %d",
+		       control->sar, control->reqseq, control->final,
+		       control->txseq);
 
-	if (!__is_sframe(chan, control)) {
-		if (len < 0) {
-			l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+		/* Validate F-bit - F=0 always valid, F=1 only
+		 * valid in TX WAIT_F
+		 */
+		if (control->final && chan->tx_state != L2CAP_TX_STATE_WAIT_F)
 			goto drop;
+
+		if (chan->mode != L2CAP_MODE_STREAMING) {
+			event = L2CAP_EV_RECV_IFRAME;
+			err = l2cap_rx(chan, control, skb, event);
+		} else {
+			err = l2cap_stream_rx(chan, control, skb);
 		}
 
-		l2cap_data_channel_iframe(chan, control, skb);
+		if (err)
+			l2cap_send_disconn_req(chan->conn, chan,
+					       ECONNRESET);
 	} else {
+		const u8 rx_func_to_event[4] = {
+			L2CAP_EV_RECV_RR, L2CAP_EV_RECV_REJ,
+			L2CAP_EV_RECV_RNR, L2CAP_EV_RECV_SREJ
+		};
+
+		/* Only I-frames are expected in streaming mode */
+		if (chan->mode == L2CAP_MODE_STREAMING)
+			goto drop;
+
+		BT_DBG("sframe reqseq %d, final %d, poll %d, super %d",
+		       control->reqseq, control->final, control->poll,
+		       control->super);
+
 		if (len != 0) {
 			BT_ERR("%d", len);
 			l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 			goto drop;
 		}
 
-		l2cap_data_channel_sframe(chan, control, skb);
+		/* Validate F and P bits */
+		if (control->final && (control->poll ||
+				       chan->tx_state != L2CAP_TX_STATE_WAIT_F))
+			goto drop;
+
+		event = rx_func_to_event[control->super];
+		if (l2cap_rx(chan, control, skb, event))
+			l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 	}
 
 	return 0;
@@ -4615,19 +5131,27 @@ drop:
 	return 0;
 }
 
-static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
+static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
+			       struct sk_buff *skb)
 {
 	struct l2cap_chan *chan;
-	u32 control;
-	u16 tx_seq;
-	int len;
 
 	chan = l2cap_get_chan_by_scid(conn, cid);
 	if (!chan) {
-		BT_DBG("unknown cid 0x%4.4x", cid);
-		/* Drop packet and return */
-		kfree_skb(skb);
-		return 0;
+		if (cid == L2CAP_CID_A2MP) {
+			chan = a2mp_channel_create(conn, skb);
+			if (!chan) {
+				kfree_skb(skb);
+				return;
+			}
+
+			l2cap_chan_lock(chan);
+		} else {
+			BT_DBG("unknown cid 0x%4.4x", cid);
+			/* Drop packet and return */
+			kfree_skb(skb);
+			return;
+		}
 	}
 
 	BT_DBG("chan %p, len %d", chan, skb->len);
@@ -4645,49 +5169,13 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 		if (chan->imtu < skb->len)
 			goto drop;
 
-		if (!chan->ops->recv(chan->data, skb))
+		if (!chan->ops->recv(chan, skb))
 			goto done;
 		break;
 
 	case L2CAP_MODE_ERTM:
-		l2cap_ertm_data_rcv(chan, skb);
-
-		goto done;
-
 	case L2CAP_MODE_STREAMING:
-		control = __get_control(chan, skb->data);
-		skb_pull(skb, __ctrl_size(chan));
-		len = skb->len;
-
-		if (l2cap_check_fcs(chan, skb))
-			goto drop;
-
-		if (__is_sar_start(chan, control))
-			len -= L2CAP_SDULEN_SIZE;
-
-		if (chan->fcs == L2CAP_FCS_CRC16)
-			len -= L2CAP_FCS_SIZE;
-
-		if (len > chan->mps || len < 0 || __is_sframe(chan, control))
-			goto drop;
-
-		tx_seq = __get_txseq(chan, control);
-
-		if (chan->expected_tx_seq != tx_seq) {
-			/* Frame(s) missing - must discard partial SDU */
-			kfree_skb(chan->sdu);
-			chan->sdu = NULL;
-			chan->sdu_last_frag = NULL;
-			chan->sdu_len = 0;
-
-			/* TODO: Notify userland of missing data */
-		}
-
-		chan->expected_tx_seq = __next_seq(chan, tx_seq);
-
-		if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
-			l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-
+		l2cap_data_rcv(chan, skb);
 		goto done;
 
 	default:
@@ -4700,11 +5188,10 @@ drop:
 
 done:
 	l2cap_chan_unlock(chan);
-
-	return 0;
 }
 
-static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
+static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
+				  struct sk_buff *skb)
 {
 	struct l2cap_chan *chan;
 
@@ -4720,17 +5207,15 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
 	if (chan->imtu < skb->len)
 		goto drop;
 
-	if (!chan->ops->recv(chan->data, skb))
-		return 0;
+	if (!chan->ops->recv(chan, skb))
+		return;
 
 drop:
 	kfree_skb(skb);
-
-	return 0;
 }
 
-static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
-				    struct sk_buff *skb)
+static void l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
+			      struct sk_buff *skb)
 {
 	struct l2cap_chan *chan;
 
@@ -4746,13 +5231,11 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
 	if (chan->imtu < skb->len)
 		goto drop;
 
-	if (!chan->ops->recv(chan->data, skb))
-		return 0;
+	if (!chan->ops->recv(chan, skb))
+		return;
 
 drop:
 	kfree_skb(skb);
-
-	return 0;
 }
 
 static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
@@ -4780,7 +5263,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	case L2CAP_CID_CONN_LESS:
 		psm = get_unaligned((__le16 *) skb->data);
-		skb_pull(skb, 2);
+		skb_pull(skb, L2CAP_PSMLEN_SIZE);
 		l2cap_conless_channel(conn, psm, skb);
 		break;
 
@@ -4974,6 +5457,17 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 			rsp.status = cpu_to_le16(stat);
 			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
 							sizeof(rsp), &rsp);
+
+			if (!test_bit(CONF_REQ_SENT, &chan->conf_state) &&
+			    res == L2CAP_CR_SUCCESS) {
+				char buf[128];
+				set_bit(CONF_REQ_SENT, &chan->conf_state);
+				l2cap_send_cmd(conn, l2cap_get_ident(conn),
+					       L2CAP_CONF_REQ,
+					       l2cap_build_conf_req(chan, buf),
+					       buf);
+				chan->num_conf_req++;
+			}
 		}
 
 		l2cap_chan_unlock(chan);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 3bb1611..a4bb27e 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -27,7 +27,6 @@
 
 /* Bluetooth L2CAP sockets. */
 
-#include <linux/security.h>
 #include <linux/export.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -89,8 +88,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 	if (err < 0)
 		goto done;
 
-	if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
-				__le16_to_cpu(la.l2_psm) == 0x0003)
+	if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_SDP ||
+	    __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM)
 		chan->sec_level = BT_SECURITY_SDP;
 
 	bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
@@ -446,6 +445,22 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 	return err;
 }
 
+static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu)
+{
+	switch (chan->scid) {
+	case L2CAP_CID_LE_DATA:
+		if (mtu < L2CAP_LE_MIN_MTU)
+			return false;
+		break;
+
+	default:
+		if (mtu < L2CAP_DEFAULT_MIN_MTU)
+			return false;
+	}
+
+	return true;
+}
+
 static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
 {
 	struct sock *sk = sock->sk;
@@ -484,6 +499,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
 			break;
 		}
 
+		if (!l2cap_valid_mtu(chan, opts.imtu)) {
+			err = -EINVAL;
+			break;
+		}
+
 		chan->mode = opts.mode;
 		switch (chan->mode) {
 		case L2CAP_MODE_BASIC:
@@ -873,9 +893,34 @@ static int l2cap_sock_release(struct socket *sock)
 	return err;
 }
 
-static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
+static void l2cap_sock_cleanup_listen(struct sock *parent)
 {
-	struct sock *sk, *parent = data;
+	struct sock *sk;
+
+	BT_DBG("parent %p", parent);
+
+	/* Close not yet accepted channels */
+	while ((sk = bt_accept_dequeue(parent, NULL))) {
+		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
+		l2cap_chan_lock(chan);
+		__clear_chan_timer(chan);
+		l2cap_chan_close(chan, ECONNRESET);
+		l2cap_chan_unlock(chan);
+
+		l2cap_sock_kill(sk);
+	}
+}
+
+static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
+{
+	struct sock *sk, *parent = chan->data;
+
+	/* Check for backlog size */
+	if (sk_acceptq_is_full(parent)) {
+		BT_DBG("backlog full %d", parent->sk_ack_backlog);
+		return NULL;
+	}
 
 	sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
 								GFP_ATOMIC);
@@ -889,10 +934,10 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
 	return l2cap_pi(sk)->chan;
 }
 
-static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
+static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
 	int err;
-	struct sock *sk = data;
+	struct sock *sk = chan->data;
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 
 	lock_sock(sk);
@@ -925,16 +970,57 @@ done:
 	return err;
 }
 
-static void l2cap_sock_close_cb(void *data)
+static void l2cap_sock_close_cb(struct l2cap_chan *chan)
 {
-	struct sock *sk = data;
+	struct sock *sk = chan->data;
 
 	l2cap_sock_kill(sk);
 }
 
-static void l2cap_sock_state_change_cb(void *data, int state)
+static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
 {
-	struct sock *sk = data;
+	struct sock *sk = chan->data;
+	struct sock *parent;
+
+	lock_sock(sk);
+
+	parent = bt_sk(sk)->parent;
+
+	sock_set_flag(sk, SOCK_ZAPPED);
+
+	switch (chan->state) {
+	case BT_OPEN:
+	case BT_BOUND:
+	case BT_CLOSED:
+		break;
+	case BT_LISTEN:
+		l2cap_sock_cleanup_listen(sk);
+		sk->sk_state = BT_CLOSED;
+		chan->state = BT_CLOSED;
+
+		break;
+	default:
+		sk->sk_state = BT_CLOSED;
+		chan->state = BT_CLOSED;
+
+		sk->sk_err = err;
+
+		if (parent) {
+			bt_accept_unlink(sk);
+			parent->sk_data_ready(parent, 0);
+		} else {
+			sk->sk_state_change(sk);
+		}
+
+		break;
+	}
+
+	release_sock(sk);
+}
+
+static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state)
+{
+	struct sock *sk = chan->data;
 
 	sk->sk_state = state;
 }
@@ -955,12 +1041,34 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
 	return skb;
 }
 
+static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
+{
+	struct sock *sk = chan->data;
+	struct sock *parent;
+
+	lock_sock(sk);
+
+	parent = bt_sk(sk)->parent;
+
+	BT_DBG("sk %p, parent %p", sk, parent);
+
+	sk->sk_state = BT_CONNECTED;
+	sk->sk_state_change(sk);
+
+	if (parent)
+		parent->sk_data_ready(parent, 0);
+
+	release_sock(sk);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
 	.name		= "L2CAP Socket Interface",
 	.new_connection	= l2cap_sock_new_connection_cb,
 	.recv		= l2cap_sock_recv_cb,
 	.close		= l2cap_sock_close_cb,
+	.teardown	= l2cap_sock_teardown_cb,
 	.state_change	= l2cap_sock_state_change_cb,
+	.ready		= l2cap_sock_ready_cb,
 	.alloc_skb	= l2cap_sock_alloc_skb_cb,
 };
 
diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c
index 5066288..e1c9752 100644
--- a/net/bluetooth/lib.c
+++ b/net/bluetooth/lib.c
@@ -26,12 +26,7 @@
 
 #define pr_fmt(fmt) "Bluetooth: " fmt
 
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <asm/errno.h>
+#include <linux/export.h>
 
 #include <net/bluetooth/bluetooth.h>
 
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 25d2207..e83368f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -24,8 +24,6 @@
 
 /* Bluetooth HCI Management interface */
 
-#include <linux/kernel.h>
-#include <linux/uaccess.h>
 #include <linux/module.h>
 #include <asm/unaligned.h>
 
@@ -212,7 +210,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
 
 	BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
 
-	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
+	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
 	if (!skb)
 		return -ENOMEM;
 
@@ -243,7 +241,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
 
 	BT_DBG("sock %p", sk);
 
-	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
+	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
 	if (!skb)
 		return -ENOMEM;
 
@@ -689,14 +687,14 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
 {
 	struct pending_cmd *cmd;
 
-	cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
+	cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
 	if (!cmd)
 		return NULL;
 
 	cmd->opcode = opcode;
 	cmd->index = hdev->id;
 
-	cmd->param = kmalloc(len, GFP_ATOMIC);
+	cmd->param = kmalloc(len, GFP_KERNEL);
 	if (!cmd->param) {
 		kfree(cmd);
 		return NULL;
@@ -714,7 +712,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
 }
 
 static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
-				 void (*cb)(struct pending_cmd *cmd, void *data),
+				 void (*cb)(struct pending_cmd *cmd,
+					    void *data),
 				 void *data)
 {
 	struct list_head *p, *n;
@@ -813,7 +812,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
 	struct sk_buff *skb;
 	struct mgmt_hdr *hdr;
 
-	skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
+	skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
 	if (!skb)
 		return -ENOMEM;
 
@@ -871,7 +870,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
 	}
 
 	if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
-			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
+	    mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
 		err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
 				 MGMT_STATUS_BUSY);
 		goto failed;
@@ -978,7 +977,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
 	}
 
 	if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
-			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
+	    mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
 		err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
 				 MGMT_STATUS_BUSY);
 		goto failed;
@@ -1001,7 +1000,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
 		scan = 0;
 
 		if (test_bit(HCI_ISCAN, &hdev->flags) &&
-						hdev->discov_timeout > 0)
+		    hdev->discov_timeout > 0)
 			cancel_delayed_work(&hdev->discov_off);
 	}
 
@@ -1056,7 +1055,7 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
 		bool changed = false;
 
 		if (!!cp->val != test_bit(HCI_LINK_SECURITY,
-							&hdev->dev_flags)) {
+					  &hdev->dev_flags)) {
 			change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
 			changed = true;
 		}
@@ -1269,7 +1268,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 		goto failed;
 	}
 
-	uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
+	uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
 	if (!uuid) {
 		err = -ENOMEM;
 		goto failed;
@@ -1317,7 +1316,7 @@ static bool enable_service_cache(struct hci_dev *hdev)
 }
 
 static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
-								u16 len)
+		       u16 len)
 {
 	struct mgmt_cp_remove_uuid *cp = data;
 	struct pending_cmd *cmd;
@@ -1442,7 +1441,7 @@ unlock:
 }
 
 static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
-								u16 len)
+			  u16 len)
 {
 	struct mgmt_cp_load_link_keys *cp = data;
 	u16 key_count, expected_len;
@@ -1454,13 +1453,13 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
 					sizeof(struct mgmt_link_key_info);
 	if (expected_len != len) {
 		BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
-							len, expected_len);
+		       len, expected_len);
 		return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
 				  MGMT_STATUS_INVALID_PARAMS);
 	}
 
 	BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
-								key_count);
+	       key_count);
 
 	hci_dev_lock(hdev);
 
@@ -1535,10 +1534,10 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
 	if (cp->disconnect) {
 		if (cp->addr.type == BDADDR_BREDR)
 			conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
-							&cp->addr.bdaddr);
+						       &cp->addr.bdaddr);
 		else
 			conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
-							&cp->addr.bdaddr);
+						       &cp->addr.bdaddr);
 	} else {
 		conn = NULL;
 	}
@@ -1594,11 +1593,12 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
 	}
 
 	if (cp->addr.type == BDADDR_BREDR)
-		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
+		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+					       &cp->addr.bdaddr);
 	else
 		conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
 
-	if (!conn) {
+	if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
 		err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
 				 MGMT_STATUS_NOT_CONNECTED);
 		goto failed;
@@ -1611,7 +1611,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
 	}
 
 	dc.handle = cpu_to_le16(conn->handle);
-	dc.reason = 0x13; /* Remote User Terminated Connection */
+	dc.reason = HCI_ERROR_REMOTE_USER_TERM;
 
 	err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
 	if (err < 0)
@@ -1667,7 +1667,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
 	}
 
 	rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
-	rp = kmalloc(rp_len, GFP_ATOMIC);
+	rp = kmalloc(rp_len, GFP_KERNEL);
 	if (!rp) {
 		err = -ENOMEM;
 		goto unlock;
@@ -1813,7 +1813,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
 	hdev->io_capability = cp->io_capability;
 
 	BT_DBG("%s IO capability set to 0x%02x", hdev->name,
-							hdev->io_capability);
+	       hdev->io_capability);
 
 	hci_dev_unlock(hdev);
 
@@ -1821,7 +1821,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
 			    0);
 }
 
-static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
+static struct pending_cmd *find_pairing(struct hci_conn *conn)
 {
 	struct hci_dev *hdev = conn->hdev;
 	struct pending_cmd *cmd;
@@ -1873,6 +1873,22 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status)
 		pairing_complete(cmd, mgmt_status(status));
 }
 
+static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
+{
+	struct pending_cmd *cmd;
+
+	BT_DBG("status %u", status);
+
+	if (!status)
+		return;
+
+	cmd = find_pairing(conn);
+	if (!cmd)
+		BT_DBG("Unable to find a pending command");
+	else
+		pairing_complete(cmd, mgmt_status(status));
+}
+
 static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
 		       u16 len)
 {
@@ -1911,8 +1927,15 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
 	rp.addr.type = cp->addr.type;
 
 	if (IS_ERR(conn)) {
+		int status;
+
+		if (PTR_ERR(conn) == -EBUSY)
+			status = MGMT_STATUS_BUSY;
+		else
+			status = MGMT_STATUS_CONNECT_FAILED;
+
 		err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
-				   MGMT_STATUS_CONNECT_FAILED, &rp,
+				   status, &rp,
 				   sizeof(rp));
 		goto unlock;
 	}
@@ -1934,6 +1957,8 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
 	/* For LE, just connecting isn't a proof that the pairing finished */
 	if (cp->addr.type == BDADDR_BREDR)
 		conn->connect_cfm_cb = pairing_complete_cb;
+	else
+		conn->connect_cfm_cb = le_connect_complete_cb;
 
 	conn->security_cfm_cb = pairing_complete_cb;
 	conn->disconn_cfm_cb = pairing_complete_cb;
@@ -1941,7 +1966,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
 	cmd->user_data = conn;
 
 	if (conn->state == BT_CONNECTED &&
-				hci_conn_security(conn, sec_level, auth_type))
+	    hci_conn_security(conn, sec_level, auth_type))
 		pairing_complete(cmd, 0);
 
 	err = 0;
@@ -2238,7 +2263,7 @@ unlock:
 }
 
 static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
-						void *data, u16 len)
+				  void *data, u16 len)
 {
 	struct mgmt_cp_remove_remote_oob_data *cp = data;
 	u8 status;
@@ -2407,7 +2432,7 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
 
 	case DISCOVERY_RESOLVING:
 		e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
-							NAME_PENDING);
+						     NAME_PENDING);
 		if (!e) {
 			mgmt_pending_remove(cmd);
 			err = cmd_complete(sk, hdev->id,
@@ -2629,7 +2654,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
 					sizeof(struct mgmt_ltk_info);
 	if (expected_len != len) {
 		BT_ERR("load_keys: expected %u bytes, got %u bytes",
-							len, expected_len);
+		       len, expected_len);
 		return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
 				  EINVAL);
 	}
@@ -2754,7 +2779,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 	}
 
 	if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
-					mgmt_handlers[opcode].func == NULL) {
+	    mgmt_handlers[opcode].func == NULL) {
 		BT_DBG("Unknown op %u", opcode);
 		err = cmd_status(sk, index, opcode,
 				 MGMT_STATUS_UNKNOWN_COMMAND);
@@ -2762,7 +2787,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 	}
 
 	if ((hdev && opcode < MGMT_OP_READ_INFO) ||
-			(!hdev && opcode >= MGMT_OP_READ_INFO)) {
+	    (!hdev && opcode >= MGMT_OP_READ_INFO)) {
 		err = cmd_status(sk, index, opcode,
 				 MGMT_STATUS_INVALID_INDEX);
 		goto done;
@@ -2771,7 +2796,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 	handler = &mgmt_handlers[opcode];
 
 	if ((handler->var_len && len < handler->data_len) ||
-			(!handler->var_len && len != handler->data_len)) {
+	    (!handler->var_len && len != handler->data_len)) {
 		err = cmd_status(sk, index, opcode,
 				 MGMT_STATUS_INVALID_PARAMS);
 		goto done;
@@ -2955,7 +2980,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
 	bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
 	ev.key.addr.type = BDADDR_BREDR;
 	ev.key.type = key->type;
-	memcpy(ev.key.val, key->val, 16);
+	memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
 	ev.key.pin_len = key->pin_len;
 
 	return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
@@ -3090,7 +3115,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
 	mgmt_pending_remove(cmd);
 
 	mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
-									hdev);
+			     hdev);
 	return err;
 }
 
@@ -3180,7 +3205,7 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 
 int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
-						u8 link_type, u8 addr_type)
+			      u8 link_type, u8 addr_type)
 {
 	struct mgmt_ev_user_passkey_request ev;
 
@@ -3194,8 +3219,8 @@ int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 
 static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-					u8 link_type, u8 addr_type, u8 status,
-					u8 opcode)
+				      u8 link_type, u8 addr_type, u8 status,
+				      u8 opcode)
 {
 	struct pending_cmd *cmd;
 	struct mgmt_rp_user_confirm_reply rp;
@@ -3226,7 +3251,8 @@ int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 					 u8 link_type, u8 addr_type, u8 status)
 {
 	return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
-					  status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
+					  status,
+					  MGMT_OP_USER_CONFIRM_NEG_REPLY);
 }
 
 int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
@@ -3240,7 +3266,8 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 					 u8 link_type, u8 addr_type, u8 status)
 {
 	return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
-					  status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
+					  status,
+					  MGMT_OP_USER_PASSKEY_NEG_REPLY);
 }
 
 int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
@@ -3519,9 +3546,9 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 	ev->addr.type = link_to_bdaddr(link_type, addr_type);
 	ev->rssi = rssi;
 	if (cfm_name)
-		ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
+		ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
 	if (!ssp)
-		ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
+		ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
 
 	if (eir_len > 0)
 		memcpy(ev->eir, eir, eir_len);
@@ -3531,7 +3558,6 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 					  dev_class, 3);
 
 	ev->eir_len = cpu_to_le16(eir_len);
-
 	ev_size = sizeof(*ev) + eir_len;
 
 	return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 8a60238..c75107e 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -26,22 +26,8 @@
  */
 
 #include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/device.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/net.h>
-#include <linux/mutex.h>
 #include <linux/kthread.h>
-#include <linux/slab.h>
-
-#include <net/sock.h>
-#include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -115,14 +101,14 @@ static void rfcomm_session_del(struct rfcomm_session *s);
 #define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
 #define __get_rpn_parity(line)    (((line) >> 3) & 0x7)
 
-static inline void rfcomm_schedule(void)
+static void rfcomm_schedule(void)
 {
 	if (!rfcomm_thread)
 		return;
 	wake_up_process(rfcomm_thread);
 }
 
-static inline void rfcomm_session_put(struct rfcomm_session *s)
+static void rfcomm_session_put(struct rfcomm_session *s)
 {
 	if (atomic_dec_and_test(&s->refcnt))
 		rfcomm_session_del(s);
@@ -227,7 +213,7 @@ static int rfcomm_l2sock_create(struct socket **sock)
 	return err;
 }
 
-static inline int rfcomm_check_security(struct rfcomm_dlc *d)
+static int rfcomm_check_security(struct rfcomm_dlc *d)
 {
 	struct sock *sk = d->session->sock->sk;
 	struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
@@ -1750,7 +1736,7 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
 /* Send data queued for the DLC.
  * Return number of frames left in the queue.
  */
-static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
+static int rfcomm_process_tx(struct rfcomm_dlc *d)
 {
 	struct sk_buff *skb;
 	int err;
@@ -1798,7 +1784,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
 	return skb_queue_len(&d->tx_queue);
 }
 
-static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
+static void rfcomm_process_dlcs(struct rfcomm_session *s)
 {
 	struct rfcomm_dlc *d;
 	struct list_head *p, *n;
@@ -1858,7 +1844,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
 	}
 }
 
-static inline void rfcomm_process_rx(struct rfcomm_session *s)
+static void rfcomm_process_rx(struct rfcomm_session *s)
 {
 	struct socket *sock = s->sock;
 	struct sock *sk = sock->sk;
@@ -1883,7 +1869,7 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s)
 	}
 }
 
-static inline void rfcomm_accept_connection(struct rfcomm_session *s)
+static void rfcomm_accept_connection(struct rfcomm_session *s)
 {
 	struct socket *sock = s->sock, *nsock;
 	int err;
@@ -1917,7 +1903,7 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
 		sock_release(nsock);
 }
 
-static inline void rfcomm_check_connection(struct rfcomm_session *s)
+static void rfcomm_check_connection(struct rfcomm_session *s)
 {
 	struct sock *sk = s->sock->sk;
 
@@ -1941,7 +1927,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s)
 	}
 }
 
-static inline void rfcomm_process_sessions(void)
+static void rfcomm_process_sessions(void)
 {
 	struct list_head *p, *n;
 
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index e8707de..7e1e596 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -25,27 +25,8 @@
  * RFCOMM sockets.
  */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/list.h>
-#include <linux/device.h>
+#include <linux/export.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/security.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index d1820ff..cb96077 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -31,11 +31,6 @@
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 
-#include <linux/capability.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/rfcomm.h>
@@ -132,7 +127,7 @@ static struct rfcomm_dev *__rfcomm_dev_get(int id)
 	return NULL;
 }
 
-static inline struct rfcomm_dev *rfcomm_dev_get(int id)
+static struct rfcomm_dev *rfcomm_dev_get(int id)
 {
 	struct rfcomm_dev *dev;
 
@@ -345,7 +340,7 @@ static void rfcomm_wfree(struct sk_buff *skb)
 	tty_port_put(&dev->port);
 }
 
-static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
+static void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
 {
 	tty_port_get(&dev->port);
 	atomic_add(skb->truesize, &dev->wmem_alloc);
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index cbdd313..40bbe25 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -25,26 +25,8 @@
 /* Bluetooth SCO sockets. */
 
 #include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/device.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
-#include <linux/list.h>
-#include <linux/security.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -123,7 +105,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
 	return conn;
 }
 
-static inline struct sock *sco_chan_get(struct sco_conn *conn)
+static struct sock *sco_chan_get(struct sco_conn *conn)
 {
 	struct sock *sk = NULL;
 	sco_conn_lock(conn);
@@ -157,7 +139,8 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
 	return 0;
 }
 
-static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
+static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
+			struct sock *parent)
 {
 	int err = 0;
 
@@ -228,7 +211,7 @@ done:
 	return err;
 }
 
-static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
+static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
 {
 	struct sco_conn *conn = sco_pi(sk)->conn;
 	struct sk_buff *skb;
@@ -254,7 +237,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
 	return len;
 }
 
-static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
+static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
 {
 	struct sock *sk = sco_chan_get(conn);
 
@@ -523,7 +506,7 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
 		goto done;
 
 	err = bt_sock_wait_state(sk, BT_CONNECTED,
-			sock_sndtimeo(sk, flags & O_NONBLOCK));
+				 sock_sndtimeo(sk, flags & O_NONBLOCK));
 
 done:
 	release_sock(sk);
@@ -788,7 +771,7 @@ static int sco_sock_shutdown(struct socket *sock, int how)
 
 		if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
 			err = bt_sock_wait_state(sk, BT_CLOSED,
-							sk->sk_lingertime);
+						 sk->sk_lingertime);
 	}
 	release_sock(sk);
 	return err;
@@ -878,7 +861,7 @@ static void sco_conn_ready(struct sco_conn *conn)
 		bh_lock_sock(parent);
 
 		sk = sco_sock_alloc(sock_net(parent), NULL,
-				BTPROTO_SCO, GFP_ATOMIC);
+				    BTPROTO_SCO, GFP_ATOMIC);
 		if (!sk) {
 			bh_unlock_sock(parent);
 			goto done;
@@ -907,7 +890,7 @@ done:
 /* ----- SCO interface with lower layer (HCI) ----- */
 int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
-	register struct sock *sk;
+	struct sock *sk;
 	struct hlist_node *node;
 	int lm = 0;
 
@@ -920,7 +903,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
 			continue;
 
 		if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
-				!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
+		    !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
 			lm |= HCI_LM_ACCEPT;
 			break;
 		}
@@ -981,7 +964,7 @@ static int sco_debugfs_show(struct seq_file *f, void *p)
 
 	sk_for_each(sk, node, &sco_sk_list.head) {
 		seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src),
-				batostr(&bt_sk(sk)->dst), sk->sk_state);
+			   batostr(&bt_sk(sk)->dst), sk->sk_state);
 	}
 
 	read_unlock(&sco_sk_list.lock);
@@ -1044,8 +1027,8 @@ int __init sco_init(void)
 	}
 
 	if (bt_debugfs) {
-		sco_debugfs = debugfs_create_file("sco", 0444,
-					bt_debugfs, NULL, &sco_debugfs_fops);
+		sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
+						  NULL, &sco_debugfs_fops);
 		if (!sco_debugfs)
 			BT_ERR("Failed to create SCO debug file");
 	}
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 6fc7c47..16ef0dc 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -20,14 +20,15 @@
    SOFTWARE IS DISCLAIMED.
 */
 
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <crypto/b128ops.h>
+
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/mgmt.h>
 #include <net/bluetooth/smp.h>
-#include <linux/crypto.h>
-#include <linux/scatterlist.h>
-#include <crypto/b128ops.h>
 
 #define SMP_TIMEOUT	msecs_to_jiffies(30000)
 
@@ -648,7 +649,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM;
 
-	ret = tk_request(conn, 0, auth, rsp->io_capability, req->io_capability);
+	ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability);
 	if (ret)
 		return SMP_UNSPECIFIED;
 
@@ -703,7 +704,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 	return 0;
 }
 
-static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
+static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
 {
 	struct smp_ltk *key;
 	struct hci_conn *hcon = conn->hcon;
@@ -712,6 +713,9 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
 	if (!key)
 		return 0;
 
+	if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated)
+		return 0;
+
 	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
 		return 1;
 
@@ -732,7 +736,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req);
 
-	if (smp_ltk_encrypt(conn))
+	if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
 		return 0;
 
 	if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
@@ -771,7 +775,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
 		return 1;
 
 	if (hcon->link_mode & HCI_LM_MASTER)
-		if (smp_ltk_encrypt(conn))
+		if (smp_ltk_encrypt(conn, sec_level))
 			goto done;
 
 	if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index e41456b..20fa719 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -764,9 +764,9 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
 		return NF_DROP;
 
 	if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
-		pf = PF_INET;
+		pf = NFPROTO_IPV4;
 	else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
-		pf = PF_INET6;
+		pf = NFPROTO_IPV6;
 	else
 		return NF_ACCEPT;
 
@@ -778,13 +778,13 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
 		nf_bridge->mask |= BRNF_PKT_TYPE;
 	}
 
-	if (pf == PF_INET && br_parse_ip_options(skb))
+	if (pf == NFPROTO_IPV4 && br_parse_ip_options(skb))
 		return NF_DROP;
 
 	/* The physdev module checks on this */
 	nf_bridge->mask |= BRNF_BRIDGED;
 	nf_bridge->physoutdev = skb->dev;
-	if (pf == PF_INET)
+	if (pf == NFPROTO_IPV4)
 		skb->protocol = htons(ETH_P_IP);
 	else
 		skb->protocol = htons(ETH_P_IPV6);
@@ -871,9 +871,9 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
 		return NF_DROP;
 
 	if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
-		pf = PF_INET;
+		pf = NFPROTO_IPV4;
 	else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
-		pf = PF_INET6;
+		pf = NFPROTO_IPV6;
 	else
 		return NF_ACCEPT;
 
@@ -886,7 +886,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
 
 	nf_bridge_pull_encap_header(skb);
 	nf_bridge_save_header(skb);
-	if (pf == PF_INET)
+	if (pf == NFPROTO_IPV4)
 		skb->protocol = htons(ETH_P_IP);
 	else
 		skb->protocol = htons(ETH_P_IPV6);
@@ -919,49 +919,49 @@ static struct nf_hook_ops br_nf_ops[] __read_mostly = {
 	{
 		.hook = br_nf_pre_routing,
 		.owner = THIS_MODULE,
-		.pf = PF_BRIDGE,
+		.pf = NFPROTO_BRIDGE,
 		.hooknum = NF_BR_PRE_ROUTING,
 		.priority = NF_BR_PRI_BRNF,
 	},
 	{
 		.hook = br_nf_local_in,
 		.owner = THIS_MODULE,
-		.pf = PF_BRIDGE,
+		.pf = NFPROTO_BRIDGE,
 		.hooknum = NF_BR_LOCAL_IN,
 		.priority = NF_BR_PRI_BRNF,
 	},
 	{
 		.hook = br_nf_forward_ip,
 		.owner = THIS_MODULE,
-		.pf = PF_BRIDGE,
+		.pf = NFPROTO_BRIDGE,
 		.hooknum = NF_BR_FORWARD,
 		.priority = NF_BR_PRI_BRNF - 1,
 	},
 	{
 		.hook = br_nf_forward_arp,
 		.owner = THIS_MODULE,
-		.pf = PF_BRIDGE,
+		.pf = NFPROTO_BRIDGE,
 		.hooknum = NF_BR_FORWARD,
 		.priority = NF_BR_PRI_BRNF,
 	},
 	{
 		.hook = br_nf_post_routing,
 		.owner = THIS_MODULE,
-		.pf = PF_BRIDGE,
+		.pf = NFPROTO_BRIDGE,
 		.hooknum = NF_BR_POST_ROUTING,
 		.priority = NF_BR_PRI_LAST,
 	},
 	{
 		.hook = ip_sabotage_in,
 		.owner = THIS_MODULE,
-		.pf = PF_INET,
+		.pf = NFPROTO_IPV4,
 		.hooknum = NF_INET_PRE_ROUTING,
 		.priority = NF_IP_PRI_FIRST,
 	},
 	{
 		.hook = ip_sabotage_in,
 		.owner = THIS_MODULE,
-		.pf = PF_INET6,
+		.pf = NFPROTO_IPV6,
 		.hooknum = NF_INET_PRE_ROUTING,
 		.priority = NF_IP6_PRI_FIRST,
 	},
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index aa6f716..551d2fd 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -4,8 +4,7 @@
  * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
  * License terms: GNU General Public License (GPL) version 2
  *
- * Borrowed heavily from file: pn_dev.c. Thanks to
- *  Remi Denis-Courmont <remi.denis-courmont@nokia.com>
+ * Borrowed heavily from file: pn_dev.c. Thanks to Remi Denis-Courmont
  *  and Sakari Ailus <sakari.ailus@nokia.com>
  */
 
@@ -91,11 +90,8 @@ static int caifd_refcnt_read(struct caif_device_entry *e)
 /* Allocate new CAIF device. */
 static struct caif_device_entry *caif_device_alloc(struct net_device *dev)
 {
-	struct caif_device_entry_list *caifdevs;
 	struct caif_device_entry *caifd;
 
-	caifdevs = caif_device_list(dev_net(dev));
-
 	caifd = kzalloc(sizeof(*caifd), GFP_KERNEL);
 	if (!caifd)
 		return NULL;
@@ -132,6 +128,11 @@ void caif_flow_cb(struct sk_buff *skb)
 
 	rcu_read_lock();
 	caifd = caif_get(skb->dev);
+
+	WARN_ON(caifd == NULL);
+	if (caifd == NULL)
+		return;
+
 	caifd_hold(caifd);
 	rcu_read_unlock();
 
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index fb89443..78f1cda 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -220,6 +220,7 @@ static void caif_ctrl_cb(struct cflayer *layr,
 						cfsk_hold, cfsk_put);
 		cf_sk->sk.sk_state = CAIF_CONNECTED;
 		set_tx_flow_on(cf_sk);
+		cf_sk->sk.sk_shutdown = 0;
 		cf_sk->sk.sk_state_change(&cf_sk->sk);
 		break;
 
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index 047cd0e..44f270f 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -175,15 +175,17 @@ static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl)
 
 void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
 {
+	struct cfpkt *pkt;
 	struct cfctrl *cfctrl = container_obj(layer);
-	struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
 	struct cflayer *dn = cfctrl->serv.layer.dn;
-	if (!pkt)
-		return;
+
 	if (!dn) {
 		pr_debug("not able to send enum request\n");
 		return;
 	}
+	pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	if (!pkt)
+		return;
 	caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
 	init_info(cfpkt_info(pkt), cfctrl);
 	cfpkt_info(pkt)->dev_info->id = physlinkid;
@@ -302,18 +304,17 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
 				struct cflayer *client)
 {
 	int ret;
+	struct cfpkt *pkt;
 	struct cfctrl *cfctrl = container_obj(layer);
-	struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
 	struct cflayer *dn = cfctrl->serv.layer.dn;
 
-	if (!pkt)
-		return -ENOMEM;
-
 	if (!dn) {
 		pr_debug("not able to send link-down request\n");
 		return -ENODEV;
 	}
-
+	pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	if (!pkt)
+		return -ENOMEM;
 	cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY);
 	cfpkt_addbdy(pkt, channelid);
 	init_info(cfpkt_info(pkt), cfctrl);
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 0ce2ad0..821022a 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -41,6 +41,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
@@ -220,30 +221,46 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
  *  -ENOBUFS on full driver queue (see net_xmit_errno())
  *  -ENOMEM when local loopback failed at calling skb_clone()
  *  -EPERM when trying to send on a non-CAN interface
+ *  -EMSGSIZE CAN frame size is bigger than CAN interface MTU
  *  -EINVAL when the skb->data does not contain a valid CAN frame
  */
 int can_send(struct sk_buff *skb, int loop)
 {
 	struct sk_buff *newskb = NULL;
-	struct can_frame *cf = (struct can_frame *)skb->data;
-	int err;
+	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+	int err = -EINVAL;
+
+	if (skb->len == CAN_MTU) {
+		skb->protocol = htons(ETH_P_CAN);
+		if (unlikely(cfd->len > CAN_MAX_DLEN))
+			goto inval_skb;
+	} else if (skb->len == CANFD_MTU) {
+		skb->protocol = htons(ETH_P_CANFD);
+		if (unlikely(cfd->len > CANFD_MAX_DLEN))
+			goto inval_skb;
+	} else
+		goto inval_skb;
 
-	if (skb->len != sizeof(struct can_frame) || cf->can_dlc > 8) {
-		kfree_skb(skb);
-		return -EINVAL;
+	/*
+	 * Make sure the CAN frame can pass the selected CAN netdevice.
+	 * As structs can_frame and canfd_frame are similar, we can provide
+	 * CAN FD frames to legacy CAN drivers as long as the length is <= 8
+	 */
+	if (unlikely(skb->len > skb->dev->mtu && cfd->len > CAN_MAX_DLEN)) {
+		err = -EMSGSIZE;
+		goto inval_skb;
 	}
 
-	if (skb->dev->type != ARPHRD_CAN) {
-		kfree_skb(skb);
-		return -EPERM;
+	if (unlikely(skb->dev->type != ARPHRD_CAN)) {
+		err = -EPERM;
+		goto inval_skb;
 	}
 
-	if (!(skb->dev->flags & IFF_UP)) {
-		kfree_skb(skb);
-		return -ENETDOWN;
+	if (unlikely(!(skb->dev->flags & IFF_UP))) {
+		err = -ENETDOWN;
+		goto inval_skb;
 	}
 
-	skb->protocol = htons(ETH_P_CAN);
 	skb_reset_network_header(skb);
 	skb_reset_transport_header(skb);
 
@@ -300,6 +317,10 @@ int can_send(struct sk_buff *skb, int loop)
 	can_stats.tx_frames_delta++;
 
 	return 0;
+
+inval_skb:
+	kfree_skb(skb);
+	return err;
 }
 EXPORT_SYMBOL(can_send);
 
@@ -334,8 +355,8 @@ static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
  *  relevant bits for the filter.
  *
  *  The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
- *  filter for error frames (CAN_ERR_FLAG bit set in mask). For error frames
- *  there is a special filterlist and a special rx path filter handling.
+ *  filter for error messages (CAN_ERR_FLAG bit set in mask). For error msg
+ *  frames there is a special filterlist and a special rx path filter handling.
  *
  * Return:
  *  Pointer to optimal filterlist for the given can_id/mask pair.
@@ -347,7 +368,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
 {
 	canid_t inv = *can_id & CAN_INV_FILTER; /* save flag before masking */
 
-	/* filter for error frames in extra filterlist */
+	/* filter for error message frames in extra filterlist */
 	if (*mask & CAN_ERR_FLAG) {
 		/* clear CAN_ERR_FLAG in filter entry */
 		*mask &= CAN_ERR_MASK;
@@ -408,7 +429,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
  *          <received_can_id> & mask == can_id & mask
  *
  *  The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
- *  filter for error frames (CAN_ERR_FLAG bit set in mask).
+ *  filter for error message frames (CAN_ERR_FLAG bit set in mask).
  *
  *  The provided pointer to the sk_buff is guaranteed to be valid as long as
  *  the callback function is running. The callback function must *not* free
@@ -578,7 +599,7 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
 		return 0;
 
 	if (can_id & CAN_ERR_FLAG) {
-		/* check for error frame entries only */
+		/* check for error message frame entries only */
 		hlist_for_each_entry_rcu(r, n, &d->rx[RX_ERR], list) {
 			if (can_id & r->mask) {
 				deliver(skb, r);
@@ -632,24 +653,11 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
 	return matches;
 }
 
-static int can_rcv(struct sk_buff *skb, struct net_device *dev,
-		   struct packet_type *pt, struct net_device *orig_dev)
+static void can_receive(struct sk_buff *skb, struct net_device *dev)
 {
 	struct dev_rcv_lists *d;
-	struct can_frame *cf = (struct can_frame *)skb->data;
 	int matches;
 
-	if (!net_eq(dev_net(dev), &init_net))
-		goto drop;
-
-	if (WARN_ONCE(dev->type != ARPHRD_CAN ||
-		      skb->len != sizeof(struct can_frame) ||
-		      cf->can_dlc > 8,
-		      "PF_CAN: dropped non conform skbuf: "
-		      "dev type %d, len %d, can_dlc %d\n",
-		      dev->type, skb->len, cf->can_dlc))
-		goto drop;
-
 	/* update statistics */
 	can_stats.rx_frames++;
 	can_stats.rx_frames_delta++;
@@ -673,7 +681,49 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
 		can_stats.matches++;
 		can_stats.matches_delta++;
 	}
+}
 
+static int can_rcv(struct sk_buff *skb, struct net_device *dev,
+		   struct packet_type *pt, struct net_device *orig_dev)
+{
+	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+
+	if (unlikely(!net_eq(dev_net(dev), &init_net)))
+		goto drop;
+
+	if (WARN_ONCE(dev->type != ARPHRD_CAN ||
+		      skb->len != CAN_MTU ||
+		      cfd->len > CAN_MAX_DLEN,
+		      "PF_CAN: dropped non conform CAN skbuf: "
+		      "dev type %d, len %d, datalen %d\n",
+		      dev->type, skb->len, cfd->len))
+		goto drop;
+
+	can_receive(skb, dev);
+	return NET_RX_SUCCESS;
+
+drop:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
+		   struct packet_type *pt, struct net_device *orig_dev)
+{
+	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+
+	if (unlikely(!net_eq(dev_net(dev), &init_net)))
+		goto drop;
+
+	if (WARN_ONCE(dev->type != ARPHRD_CAN ||
+		      skb->len != CANFD_MTU ||
+		      cfd->len > CANFD_MAX_DLEN,
+		      "PF_CAN: dropped non conform CAN FD skbuf: "
+		      "dev type %d, len %d, datalen %d\n",
+		      dev->type, skb->len, cfd->len))
+		goto drop;
+
+	can_receive(skb, dev);
 	return NET_RX_SUCCESS;
 
 drop:
@@ -807,10 +857,14 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
 
 static struct packet_type can_packet __read_mostly = {
 	.type = cpu_to_be16(ETH_P_CAN),
-	.dev  = NULL,
 	.func = can_rcv,
 };
 
+static struct packet_type canfd_packet __read_mostly = {
+	.type = cpu_to_be16(ETH_P_CANFD),
+	.func = canfd_rcv,
+};
+
 static const struct net_proto_family can_family_ops = {
 	.family = PF_CAN,
 	.create = can_create,
@@ -824,6 +878,12 @@ static struct notifier_block can_netdev_notifier __read_mostly = {
 
 static __init int can_init(void)
 {
+	/* check for correct padding to be able to use the structs similarly */
+	BUILD_BUG_ON(offsetof(struct can_frame, can_dlc) !=
+		     offsetof(struct canfd_frame, len) ||
+		     offsetof(struct can_frame, data) !=
+		     offsetof(struct canfd_frame, data));
+
 	printk(banner);
 
 	memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list));
@@ -846,6 +906,7 @@ static __init int can_init(void)
 	sock_register(&can_family_ops);
 	register_netdevice_notifier(&can_netdev_notifier);
 	dev_add_pack(&can_packet);
+	dev_add_pack(&canfd_packet);
 
 	return 0;
 }
@@ -860,6 +921,7 @@ static __exit void can_exit(void)
 	can_remove_proc();
 
 	/* protocol unregister */
+	dev_remove_pack(&canfd_packet);
 	dev_remove_pack(&can_packet);
 	unregister_netdevice_notifier(&can_netdev_notifier);
 	sock_unregister(PF_CAN);
diff --git a/net/can/raw.c b/net/can/raw.c
index cde1b4a..3e9c893 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -82,6 +82,7 @@ struct raw_sock {
 	struct notifier_block notifier;
 	int loopback;
 	int recv_own_msgs;
+	int fd_frames;
 	int count;                 /* number of active filters */
 	struct can_filter dfilter; /* default/single filter */
 	struct can_filter *filter; /* pointer to filter(s) */
@@ -119,6 +120,14 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
 	if (!ro->recv_own_msgs && oskb->sk == sk)
 		return;
 
+	/* do not pass frames with DLC > 8 to a legacy socket */
+	if (!ro->fd_frames) {
+		struct canfd_frame *cfd = (struct canfd_frame *)oskb->data;
+
+		if (unlikely(cfd->len > CAN_MAX_DLEN))
+			return;
+	}
+
 	/* clone the given skb to be able to enqueue it into the rcv queue */
 	skb = skb_clone(oskb, GFP_ATOMIC);
 	if (!skb)
@@ -291,6 +300,7 @@ static int raw_init(struct sock *sk)
 	/* set default loopback behaviour */
 	ro->loopback         = 1;
 	ro->recv_own_msgs    = 0;
+	ro->fd_frames        = 0;
 
 	/* set notifier */
 	ro->notifier.notifier_call = raw_notifier;
@@ -569,6 +579,15 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
 
 		break;
 
+	case CAN_RAW_FD_FRAMES:
+		if (optlen != sizeof(ro->fd_frames))
+			return -EINVAL;
+
+		if (copy_from_user(&ro->fd_frames, optval, optlen))
+			return -EFAULT;
+
+		break;
+
 	default:
 		return -ENOPROTOOPT;
 	}
@@ -627,6 +646,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
 		val = &ro->recv_own_msgs;
 		break;
 
+	case CAN_RAW_FD_FRAMES:
+		if (len > sizeof(int))
+			len = sizeof(int);
+		val = &ro->fd_frames;
+		break;
+
 	default:
 		return -ENOPROTOOPT;
 	}
@@ -662,8 +687,13 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
 	} else
 		ifindex = ro->ifindex;
 
-	if (size != sizeof(struct can_frame))
-		return -EINVAL;
+	if (ro->fd_frames) {
+		if (unlikely(size != CANFD_MTU && size != CAN_MTU))
+			return -EINVAL;
+	} else {
+		if (unlikely(size != CAN_MTU))
+			return -EINVAL;
+	}
 
 	dev = dev_get_by_index(&init_net, ifindex);
 	if (!dev)
@@ -681,9 +711,6 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
 	if (err < 0)
 		goto free_skb;
 
-	/* to be able to check the received tx sock reference in raw_rcv() */
-	skb_shinfo(skb)->tx_flags |= SKBTX_DRV_NEEDS_SK_REF;
-
 	skb->dev = dev;
 	skb->sk  = sk;
 
@@ -708,7 +735,9 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
 		       struct msghdr *msg, size_t size, int flags)
 {
 	struct sock *sk = sock->sk;
+	struct raw_sock *ro = raw_sk(sk);
 	struct sk_buff *skb;
+	int rxmtu;
 	int err = 0;
 	int noblock;
 
@@ -719,10 +748,20 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
 	if (!skb)
 		return err;
 
-	if (size < skb->len)
+	/*
+	 * when serving a legacy socket the DLC <= 8 is already checked inside
+	 * raw_rcv(). Now check if we need to pass a canfd_frame to a legacy
+	 * socket and cut the possible CANFD_MTU/CAN_MTU length to CAN_MTU
+	 */
+	if (!ro->fd_frames)
+		rxmtu = CAN_MTU;
+	else
+		rxmtu = skb->len;
+
+	if (size < rxmtu)
 		msg->msg_flags |= MSG_TRUNC;
 	else
-		size = skb->len;
+		size = rxmtu;
 
 	err = memcpy_toiovec(msg->msg_iov, skb->data, size);
 	if (err < 0) {
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index ba4323b..58b09ef 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -468,19 +468,15 @@ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private,
 	/* msgr */
 	if (ceph_test_opt(client, MYIP))
 		myaddr = &client->options->my_addr;
-	client->msgr = ceph_messenger_create(myaddr,
-					     client->supported_features,
-					     client->required_features);
-	if (IS_ERR(client->msgr)) {
-		err = PTR_ERR(client->msgr);
-		goto fail;
-	}
-	client->msgr->nocrc = ceph_test_opt(client, NOCRC);
+	ceph_messenger_init(&client->msgr, myaddr,
+		client->supported_features,
+		client->required_features,
+		ceph_test_opt(client, NOCRC));
 
 	/* subsystems */
 	err = ceph_monc_init(&client->monc, client);
 	if (err < 0)
-		goto fail_msgr;
+		goto fail;
 	err = ceph_osdc_init(&client->osdc, client);
 	if (err < 0)
 		goto fail_monc;
@@ -489,8 +485,6 @@ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private,
 
 fail_monc:
 	ceph_monc_stop(&client->monc);
-fail_msgr:
-	ceph_messenger_destroy(client->msgr);
 fail:
 	kfree(client);
 	return ERR_PTR(err);
@@ -508,8 +502,6 @@ void ceph_destroy_client(struct ceph_client *client)
 
 	ceph_debugfs_client_cleanup(client);
 
-	ceph_messenger_destroy(client->msgr);
-
 	ceph_destroy_options(client->options);
 
 	kfree(client);
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index b332c3d..23073cf 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -29,6 +29,14 @@
  * the sender.
  */
 
+/* State values for ceph_connection->sock_state; NEW is assumed to be 0 */
+
+#define CON_SOCK_STATE_NEW		0	/* -> CLOSED */
+#define CON_SOCK_STATE_CLOSED		1	/* -> CONNECTING */
+#define CON_SOCK_STATE_CONNECTING	2	/* -> CONNECTED or -> CLOSING */
+#define CON_SOCK_STATE_CONNECTED	3	/* -> CLOSING or -> CLOSED */
+#define CON_SOCK_STATE_CLOSING		4	/* -> CLOSED */
+
 /* static tag bytes (protocol control messages) */
 static char tag_msg = CEPH_MSGR_TAG_MSG;
 static char tag_ack = CEPH_MSGR_TAG_ACK;
@@ -147,52 +155,101 @@ void ceph_msgr_flush(void)
 }
 EXPORT_SYMBOL(ceph_msgr_flush);
 
+/* Connection socket state transition functions */
+
+static void con_sock_state_init(struct ceph_connection *con)
+{
+	int old_state;
+
+	old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSED);
+	if (WARN_ON(old_state != CON_SOCK_STATE_NEW))
+		printk("%s: unexpected old state %d\n", __func__, old_state);
+}
+
+static void con_sock_state_connecting(struct ceph_connection *con)
+{
+	int old_state;
+
+	old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CONNECTING);
+	if (WARN_ON(old_state != CON_SOCK_STATE_CLOSED))
+		printk("%s: unexpected old state %d\n", __func__, old_state);
+}
+
+static void con_sock_state_connected(struct ceph_connection *con)
+{
+	int old_state;
+
+	old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CONNECTED);
+	if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTING))
+		printk("%s: unexpected old state %d\n", __func__, old_state);
+}
+
+static void con_sock_state_closing(struct ceph_connection *con)
+{
+	int old_state;
+
+	old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSING);
+	if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTING &&
+			old_state != CON_SOCK_STATE_CONNECTED &&
+			old_state != CON_SOCK_STATE_CLOSING))
+		printk("%s: unexpected old state %d\n", __func__, old_state);
+}
+
+static void con_sock_state_closed(struct ceph_connection *con)
+{
+	int old_state;
+
+	old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSED);
+	if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTED &&
+			old_state != CON_SOCK_STATE_CLOSING))
+		printk("%s: unexpected old state %d\n", __func__, old_state);
+}
 
 /*
  * socket callback functions
  */
 
 /* data available on socket, or listen socket received a connect */
-static void ceph_data_ready(struct sock *sk, int count_unused)
+static void ceph_sock_data_ready(struct sock *sk, int count_unused)
 {
 	struct ceph_connection *con = sk->sk_user_data;
 
 	if (sk->sk_state != TCP_CLOSE_WAIT) {
-		dout("ceph_data_ready on %p state = %lu, queueing work\n",
+		dout("%s on %p state = %lu, queueing work\n", __func__,
 		     con, con->state);
 		queue_con(con);
 	}
 }
 
 /* socket has buffer space for writing */
-static void ceph_write_space(struct sock *sk)
+static void ceph_sock_write_space(struct sock *sk)
 {
 	struct ceph_connection *con = sk->sk_user_data;
 
 	/* only queue to workqueue if there is data we want to write,
 	 * and there is sufficient space in the socket buffer to accept
-	 * more data.  clear SOCK_NOSPACE so that ceph_write_space()
+	 * more data.  clear SOCK_NOSPACE so that ceph_sock_write_space()
 	 * doesn't get called again until try_write() fills the socket
 	 * buffer. See net/ipv4/tcp_input.c:tcp_check_space()
 	 * and net/core/stream.c:sk_stream_write_space().
 	 */
-	if (test_bit(WRITE_PENDING, &con->state)) {
+	if (test_bit(WRITE_PENDING, &con->flags)) {
 		if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
-			dout("ceph_write_space %p queueing write work\n", con);
+			dout("%s %p queueing write work\n", __func__, con);
 			clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
 			queue_con(con);
 		}
 	} else {
-		dout("ceph_write_space %p nothing to write\n", con);
+		dout("%s %p nothing to write\n", __func__, con);
 	}
 }
 
 /* socket's state has changed */
-static void ceph_state_change(struct sock *sk)
+static void ceph_sock_state_change(struct sock *sk)
 {
 	struct ceph_connection *con = sk->sk_user_data;
 
-	dout("ceph_state_change %p state = %lu sk_state = %u\n",
+	dout("%s %p state = %lu sk_state = %u\n", __func__,
 	     con, con->state, sk->sk_state);
 
 	if (test_bit(CLOSED, &con->state))
@@ -200,10 +257,11 @@ static void ceph_state_change(struct sock *sk)
 
 	switch (sk->sk_state) {
 	case TCP_CLOSE:
-		dout("ceph_state_change TCP_CLOSE\n");
+		dout("%s TCP_CLOSE\n", __func__);
 	case TCP_CLOSE_WAIT:
-		dout("ceph_state_change TCP_CLOSE_WAIT\n");
-		if (test_and_set_bit(SOCK_CLOSED, &con->state) == 0) {
+		dout("%s TCP_CLOSE_WAIT\n", __func__);
+		con_sock_state_closing(con);
+		if (test_and_set_bit(SOCK_CLOSED, &con->flags) == 0) {
 			if (test_bit(CONNECTING, &con->state))
 				con->error_msg = "connection failed";
 			else
@@ -212,7 +270,8 @@ static void ceph_state_change(struct sock *sk)
 		}
 		break;
 	case TCP_ESTABLISHED:
-		dout("ceph_state_change TCP_ESTABLISHED\n");
+		dout("%s TCP_ESTABLISHED\n", __func__);
+		con_sock_state_connected(con);
 		queue_con(con);
 		break;
 	default:	/* Everything else is uninteresting */
@@ -228,9 +287,9 @@ static void set_sock_callbacks(struct socket *sock,
 {
 	struct sock *sk = sock->sk;
 	sk->sk_user_data = con;
-	sk->sk_data_ready = ceph_data_ready;
-	sk->sk_write_space = ceph_write_space;
-	sk->sk_state_change = ceph_state_change;
+	sk->sk_data_ready = ceph_sock_data_ready;
+	sk->sk_write_space = ceph_sock_write_space;
+	sk->sk_state_change = ceph_sock_state_change;
 }
 
 
@@ -262,6 +321,7 @@ static int ceph_tcp_connect(struct ceph_connection *con)
 
 	dout("connect %s\n", ceph_pr_addr(&con->peer_addr.in_addr));
 
+	con_sock_state_connecting(con);
 	ret = sock->ops->connect(sock, (struct sockaddr *)paddr, sizeof(*paddr),
 				 O_NONBLOCK);
 	if (ret == -EINPROGRESS) {
@@ -277,7 +337,6 @@ static int ceph_tcp_connect(struct ceph_connection *con)
 		return ret;
 	}
 	con->sock = sock;
-
 	return 0;
 }
 
@@ -343,6 +402,7 @@ static int con_close_socket(struct ceph_connection *con)
 	sock_release(con->sock);
 	con->sock = NULL;
 	clear_bit(SOCK_CLOSED, &con->state);
+	con_sock_state_closed(con);
 	return rc;
 }
 
@@ -353,6 +413,10 @@ static int con_close_socket(struct ceph_connection *con)
 static void ceph_msg_remove(struct ceph_msg *msg)
 {
 	list_del_init(&msg->list_head);
+	BUG_ON(msg->con == NULL);
+	ceph_con_put(msg->con);
+	msg->con = NULL;
+
 	ceph_msg_put(msg);
 }
 static void ceph_msg_remove_list(struct list_head *head)
@@ -372,8 +436,11 @@ static void reset_connection(struct ceph_connection *con)
 	ceph_msg_remove_list(&con->out_sent);
 
 	if (con->in_msg) {
+		BUG_ON(con->in_msg->con != con);
+		con->in_msg->con = NULL;
 		ceph_msg_put(con->in_msg);
 		con->in_msg = NULL;
+		ceph_con_put(con);
 	}
 
 	con->connect_seq = 0;
@@ -393,11 +460,14 @@ void ceph_con_close(struct ceph_connection *con)
 {
 	dout("con_close %p peer %s\n", con,
 	     ceph_pr_addr(&con->peer_addr.in_addr));
-	set_bit(CLOSED, &con->state);  /* in case there's queued work */
+	clear_bit(NEGOTIATING, &con->state);
 	clear_bit(STANDBY, &con->state);  /* avoid connect_seq bump */
-	clear_bit(LOSSYTX, &con->state);  /* so we retry next connect */
-	clear_bit(KEEPALIVE_PENDING, &con->state);
-	clear_bit(WRITE_PENDING, &con->state);
+	set_bit(CLOSED, &con->state);
+
+	clear_bit(LOSSYTX, &con->flags);  /* so we retry next connect */
+	clear_bit(KEEPALIVE_PENDING, &con->flags);
+	clear_bit(WRITE_PENDING, &con->flags);
+
 	mutex_lock(&con->mutex);
 	reset_connection(con);
 	con->peer_global_seq = 0;
@@ -414,7 +484,8 @@ void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr)
 {
 	dout("con_open %p %s\n", con, ceph_pr_addr(&addr->in_addr));
 	set_bit(OPENING, &con->state);
-	clear_bit(CLOSED, &con->state);
+	WARN_ON(!test_and_clear_bit(CLOSED, &con->state));
+
 	memcpy(&con->peer_addr, addr, sizeof(*addr));
 	con->delay = 0;      /* reset backoff memory */
 	queue_con(con);
@@ -456,16 +527,28 @@ void ceph_con_put(struct ceph_connection *con)
 /*
  * initialize a new connection.
  */
-void ceph_con_init(struct ceph_messenger *msgr, struct ceph_connection *con)
+void ceph_con_init(struct ceph_connection *con, void *private,
+	const struct ceph_connection_operations *ops,
+	struct ceph_messenger *msgr, __u8 entity_type, __u64 entity_num)
 {
 	dout("con_init %p\n", con);
 	memset(con, 0, sizeof(*con));
+	con->private = private;
+	con->ops = ops;
 	atomic_set(&con->nref, 1);
 	con->msgr = msgr;
+
+	con_sock_state_init(con);
+
+	con->peer_name.type = (__u8) entity_type;
+	con->peer_name.num = cpu_to_le64(entity_num);
+
 	mutex_init(&con->mutex);
 	INIT_LIST_HEAD(&con->out_queue);
 	INIT_LIST_HEAD(&con->out_sent);
 	INIT_DELAYED_WORK(&con->work, con_work);
+
+	set_bit(CLOSED, &con->state);
 }
 EXPORT_SYMBOL(ceph_con_init);
 
@@ -486,14 +569,14 @@ static u32 get_global_seq(struct ceph_messenger *msgr, u32 gt)
 	return ret;
 }
 
-static void ceph_con_out_kvec_reset(struct ceph_connection *con)
+static void con_out_kvec_reset(struct ceph_connection *con)
 {
 	con->out_kvec_left = 0;
 	con->out_kvec_bytes = 0;
 	con->out_kvec_cur = &con->out_kvec[0];
 }
 
-static void ceph_con_out_kvec_add(struct ceph_connection *con,
+static void con_out_kvec_add(struct ceph_connection *con,
 				size_t size, void *data)
 {
 	int index;
@@ -534,7 +617,7 @@ static void prepare_write_message(struct ceph_connection *con)
 	struct ceph_msg *m;
 	u32 crc;
 
-	ceph_con_out_kvec_reset(con);
+	con_out_kvec_reset(con);
 	con->out_kvec_is_msg = true;
 	con->out_msg_done = false;
 
@@ -542,14 +625,16 @@ static void prepare_write_message(struct ceph_connection *con)
 	 * TCP packet that's a good thing. */
 	if (con->in_seq > con->in_seq_acked) {
 		con->in_seq_acked = con->in_seq;
-		ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
+		con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
 		con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
-		ceph_con_out_kvec_add(con, sizeof (con->out_temp_ack),
+		con_out_kvec_add(con, sizeof (con->out_temp_ack),
 			&con->out_temp_ack);
 	}
 
+	BUG_ON(list_empty(&con->out_queue));
 	m = list_first_entry(&con->out_queue, struct ceph_msg, list_head);
 	con->out_msg = m;
+	BUG_ON(m->con != con);
 
 	/* put message on sent list */
 	ceph_msg_get(m);
@@ -576,12 +661,12 @@ static void prepare_write_message(struct ceph_connection *con)
 	BUG_ON(le32_to_cpu(m->hdr.front_len) != m->front.iov_len);
 
 	/* tag + hdr + front + middle */
-	ceph_con_out_kvec_add(con, sizeof (tag_msg), &tag_msg);
-	ceph_con_out_kvec_add(con, sizeof (m->hdr), &m->hdr);
-	ceph_con_out_kvec_add(con, m->front.iov_len, m->front.iov_base);
+	con_out_kvec_add(con, sizeof (tag_msg), &tag_msg);
+	con_out_kvec_add(con, sizeof (m->hdr), &m->hdr);
+	con_out_kvec_add(con, m->front.iov_len, m->front.iov_base);
 
 	if (m->middle)
-		ceph_con_out_kvec_add(con, m->middle->vec.iov_len,
+		con_out_kvec_add(con, m->middle->vec.iov_len,
 			m->middle->vec.iov_base);
 
 	/* fill in crc (except data pages), footer */
@@ -618,7 +703,7 @@ static void prepare_write_message(struct ceph_connection *con)
 		prepare_write_message_footer(con);
 	}
 
-	set_bit(WRITE_PENDING, &con->state);
+	set_bit(WRITE_PENDING, &con->flags);
 }
 
 /*
@@ -630,16 +715,16 @@ static void prepare_write_ack(struct ceph_connection *con)
 	     con->in_seq_acked, con->in_seq);
 	con->in_seq_acked = con->in_seq;
 
-	ceph_con_out_kvec_reset(con);
+	con_out_kvec_reset(con);
 
-	ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
+	con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
 
 	con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
-	ceph_con_out_kvec_add(con, sizeof (con->out_temp_ack),
+	con_out_kvec_add(con, sizeof (con->out_temp_ack),
 				&con->out_temp_ack);
 
 	con->out_more = 1;  /* more will follow.. eventually.. */
-	set_bit(WRITE_PENDING, &con->state);
+	set_bit(WRITE_PENDING, &con->flags);
 }
 
 /*
@@ -648,9 +733,9 @@ static void prepare_write_ack(struct ceph_connection *con)
 static void prepare_write_keepalive(struct ceph_connection *con)
 {
 	dout("prepare_write_keepalive %p\n", con);
-	ceph_con_out_kvec_reset(con);
-	ceph_con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive);
-	set_bit(WRITE_PENDING, &con->state);
+	con_out_kvec_reset(con);
+	con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive);
+	set_bit(WRITE_PENDING, &con->flags);
 }
 
 /*
@@ -679,7 +764,7 @@ static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection
 
 	if (IS_ERR(auth))
 		return auth;
-	if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state))
+	if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->flags))
 		return ERR_PTR(-EAGAIN);
 
 	con->auth_reply_buf = auth->authorizer_reply_buf;
@@ -694,12 +779,12 @@ static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection
  */
 static void prepare_write_banner(struct ceph_connection *con)
 {
-	ceph_con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER);
-	ceph_con_out_kvec_add(con, sizeof (con->msgr->my_enc_addr),
+	con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER);
+	con_out_kvec_add(con, sizeof (con->msgr->my_enc_addr),
 					&con->msgr->my_enc_addr);
 
 	con->out_more = 0;
-	set_bit(WRITE_PENDING, &con->state);
+	set_bit(WRITE_PENDING, &con->flags);
 }
 
 static int prepare_write_connect(struct ceph_connection *con)
@@ -742,14 +827,14 @@ static int prepare_write_connect(struct ceph_connection *con)
 	con->out_connect.authorizer_len = auth ?
 		cpu_to_le32(auth->authorizer_buf_len) : 0;
 
-	ceph_con_out_kvec_add(con, sizeof (con->out_connect),
+	con_out_kvec_add(con, sizeof (con->out_connect),
 					&con->out_connect);
 	if (auth && auth->authorizer_buf_len)
-		ceph_con_out_kvec_add(con, auth->authorizer_buf_len,
+		con_out_kvec_add(con, auth->authorizer_buf_len,
 					auth->authorizer_buf);
 
 	con->out_more = 0;
-	set_bit(WRITE_PENDING, &con->state);
+	set_bit(WRITE_PENDING, &con->flags);
 
 	return 0;
 }
@@ -939,7 +1024,7 @@ static int write_partial_msg_pages(struct ceph_connection *con)
 	/* prepare and queue up footer, too */
 	if (!do_datacrc)
 		con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC;
-	ceph_con_out_kvec_reset(con);
+	con_out_kvec_reset(con);
 	prepare_write_message_footer(con);
 	ret = 1;
 out:
@@ -1360,11 +1445,6 @@ static void fail_protocol(struct ceph_connection *con)
 {
 	reset_connection(con);
 	set_bit(CLOSED, &con->state);  /* in case there's queued work */
-
-	mutex_unlock(&con->mutex);
-	if (con->ops->bad_proto)
-		con->ops->bad_proto(con);
-	mutex_lock(&con->mutex);
 }
 
 static int process_connect(struct ceph_connection *con)
@@ -1407,7 +1487,7 @@ static int process_connect(struct ceph_connection *con)
 			return -1;
 		}
 		con->auth_retry = 1;
-		ceph_con_out_kvec_reset(con);
+		con_out_kvec_reset(con);
 		ret = prepare_write_connect(con);
 		if (ret < 0)
 			return ret;
@@ -1428,7 +1508,7 @@ static int process_connect(struct ceph_connection *con)
 		       ENTITY_NAME(con->peer_name),
 		       ceph_pr_addr(&con->peer_addr.in_addr));
 		reset_connection(con);
-		ceph_con_out_kvec_reset(con);
+		con_out_kvec_reset(con);
 		ret = prepare_write_connect(con);
 		if (ret < 0)
 			return ret;
@@ -1454,7 +1534,7 @@ static int process_connect(struct ceph_connection *con)
 		     le32_to_cpu(con->out_connect.connect_seq),
 		     le32_to_cpu(con->in_connect.connect_seq));
 		con->connect_seq = le32_to_cpu(con->in_connect.connect_seq);
-		ceph_con_out_kvec_reset(con);
+		con_out_kvec_reset(con);
 		ret = prepare_write_connect(con);
 		if (ret < 0)
 			return ret;
@@ -1471,7 +1551,7 @@ static int process_connect(struct ceph_connection *con)
 		     le32_to_cpu(con->in_connect.global_seq));
 		get_global_seq(con->msgr,
 			       le32_to_cpu(con->in_connect.global_seq));
-		ceph_con_out_kvec_reset(con);
+		con_out_kvec_reset(con);
 		ret = prepare_write_connect(con);
 		if (ret < 0)
 			return ret;
@@ -1501,7 +1581,7 @@ static int process_connect(struct ceph_connection *con)
 			le32_to_cpu(con->in_reply.connect_seq));
 
 		if (con->in_reply.flags & CEPH_MSG_CONNECT_LOSSY)
-			set_bit(LOSSYTX, &con->state);
+			set_bit(LOSSYTX, &con->flags);
 
 		prepare_read_tag(con);
 		break;
@@ -1587,9 +1667,8 @@ static int read_partial_message_section(struct ceph_connection *con,
 	return 1;
 }
 
-static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
-				struct ceph_msg_header *hdr,
-				int *skip);
+static bool ceph_con_in_msg_alloc(struct ceph_connection *con,
+				struct ceph_msg_header *hdr);
 
 
 static int read_partial_message_pages(struct ceph_connection *con,
@@ -1672,7 +1751,6 @@ static int read_partial_message(struct ceph_connection *con)
 	int ret;
 	unsigned int front_len, middle_len, data_len;
 	bool do_datacrc = !con->msgr->nocrc;
-	int skip;
 	u64 seq;
 	u32 crc;
 
@@ -1725,9 +1803,7 @@ static int read_partial_message(struct ceph_connection *con)
 	if (!con->in_msg) {
 		dout("got hdr type %d front %d data %d\n", con->in_hdr.type,
 		     con->in_hdr.front_len, con->in_hdr.data_len);
-		skip = 0;
-		con->in_msg = ceph_alloc_msg(con, &con->in_hdr, &skip);
-		if (skip) {
+		if (ceph_con_in_msg_alloc(con, &con->in_hdr)) {
 			/* skip this message */
 			dout("alloc_msg said skip message\n");
 			BUG_ON(con->in_msg);
@@ -1742,6 +1818,8 @@ static int read_partial_message(struct ceph_connection *con)
 				"error allocating memory for incoming message";
 			return -ENOMEM;
 		}
+
+		BUG_ON(con->in_msg->con != con);
 		m = con->in_msg;
 		m->front.iov_len = 0;    /* haven't read it yet */
 		if (m->middle)
@@ -1837,8 +1915,11 @@ static void process_message(struct ceph_connection *con)
 {
 	struct ceph_msg *msg;
 
+	BUG_ON(con->in_msg->con != con);
+	con->in_msg->con = NULL;
 	msg = con->in_msg;
 	con->in_msg = NULL;
+	ceph_con_put(con);
 
 	/* if first message, set peer_name */
 	if (con->peer_name.type == 0)
@@ -1878,14 +1959,15 @@ more:
 
 	/* open the socket first? */
 	if (con->sock == NULL) {
-		ceph_con_out_kvec_reset(con);
+		clear_bit(NEGOTIATING, &con->state);
+		set_bit(CONNECTING, &con->state);
+
+		con_out_kvec_reset(con);
 		prepare_write_banner(con);
 		ret = prepare_write_connect(con);
 		if (ret < 0)
 			goto out;
 		prepare_read_banner(con);
-		set_bit(CONNECTING, &con->state);
-		clear_bit(NEGOTIATING, &con->state);
 
 		BUG_ON(con->in_msg);
 		con->in_tag = CEPH_MSGR_TAG_READY;
@@ -1942,14 +2024,14 @@ do_next:
 			prepare_write_ack(con);
 			goto more;
 		}
-		if (test_and_clear_bit(KEEPALIVE_PENDING, &con->state)) {
+		if (test_and_clear_bit(KEEPALIVE_PENDING, &con->flags)) {
 			prepare_write_keepalive(con);
 			goto more;
 		}
 	}
 
 	/* Nothing to do! */
-	clear_bit(WRITE_PENDING, &con->state);
+	clear_bit(WRITE_PENDING, &con->flags);
 	dout("try_write nothing else to write.\n");
 	ret = 0;
 out:
@@ -2091,12 +2173,6 @@ bad_tag:
  */
 static void queue_con(struct ceph_connection *con)
 {
-	if (test_bit(DEAD, &con->state)) {
-		dout("queue_con %p ignoring: DEAD\n",
-		     con);
-		return;
-	}
-
 	if (!con->ops->get(con)) {
 		dout("queue_con %p ref count 0\n", con);
 		return;
@@ -2121,7 +2197,7 @@ static void con_work(struct work_struct *work)
 
 	mutex_lock(&con->mutex);
 restart:
-	if (test_and_clear_bit(BACKOFF, &con->state)) {
+	if (test_and_clear_bit(BACKOFF, &con->flags)) {
 		dout("con_work %p backing off\n", con);
 		if (queue_delayed_work(ceph_msgr_wq, &con->work,
 				       round_jiffies_relative(con->delay))) {
@@ -2150,7 +2226,7 @@ restart:
 		con_close_socket(con);
 	}
 
-	if (test_and_clear_bit(SOCK_CLOSED, &con->state))
+	if (test_and_clear_bit(SOCK_CLOSED, &con->flags))
 		goto fault;
 
 	ret = try_read(con);
@@ -2189,7 +2265,7 @@ static void ceph_fault(struct ceph_connection *con)
 	dout("fault %p state %lu to peer %s\n",
 	     con, con->state, ceph_pr_addr(&con->peer_addr.in_addr));
 
-	if (test_bit(LOSSYTX, &con->state)) {
+	if (test_bit(LOSSYTX, &con->flags)) {
 		dout("fault on LOSSYTX channel\n");
 		goto out;
 	}
@@ -2201,8 +2277,11 @@ static void ceph_fault(struct ceph_connection *con)
 	con_close_socket(con);
 
 	if (con->in_msg) {
+		BUG_ON(con->in_msg->con != con);
+		con->in_msg->con = NULL;
 		ceph_msg_put(con->in_msg);
 		con->in_msg = NULL;
+		ceph_con_put(con);
 	}
 
 	/* Requeue anything that hasn't been acked */
@@ -2211,9 +2290,9 @@ static void ceph_fault(struct ceph_connection *con)
 	/* If there are no messages queued or keepalive pending, place
 	 * the connection in a STANDBY state */
 	if (list_empty(&con->out_queue) &&
-	    !test_bit(KEEPALIVE_PENDING, &con->state)) {
+	    !test_bit(KEEPALIVE_PENDING, &con->flags)) {
 		dout("fault %p setting STANDBY clearing WRITE_PENDING\n", con);
-		clear_bit(WRITE_PENDING, &con->state);
+		clear_bit(WRITE_PENDING, &con->flags);
 		set_bit(STANDBY, &con->state);
 	} else {
 		/* retry after a delay. */
@@ -2237,7 +2316,7 @@ static void ceph_fault(struct ceph_connection *con)
 			 * that when con_work restarts we schedule the
 			 * delay then.
 			 */
-			set_bit(BACKOFF, &con->state);
+			set_bit(BACKOFF, &con->flags);
 		}
 	}
 
@@ -2260,18 +2339,14 @@ out:
 
 
 /*
- * create a new messenger instance
+ * initialize a new messenger instance
  */
-struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr,
-					     u32 supported_features,
-					     u32 required_features)
+void ceph_messenger_init(struct ceph_messenger *msgr,
+			struct ceph_entity_addr *myaddr,
+			u32 supported_features,
+			u32 required_features,
+			bool nocrc)
 {
-	struct ceph_messenger *msgr;
-
-	msgr = kzalloc(sizeof(*msgr), GFP_KERNEL);
-	if (msgr == NULL)
-		return ERR_PTR(-ENOMEM);
-
 	msgr->supported_features = supported_features;
 	msgr->required_features = required_features;
 
@@ -2284,19 +2359,11 @@ struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr,
 	msgr->inst.addr.type = 0;
 	get_random_bytes(&msgr->inst.addr.nonce, sizeof(msgr->inst.addr.nonce));
 	encode_my_addr(msgr);
+	msgr->nocrc = nocrc;
 
-	dout("messenger_create %p\n", msgr);
-	return msgr;
+	dout("%s %p\n", __func__, msgr);
 }
-EXPORT_SYMBOL(ceph_messenger_create);
-
-void ceph_messenger_destroy(struct ceph_messenger *msgr)
-{
-	dout("destroy %p\n", msgr);
-	kfree(msgr);
-	dout("destroyed messenger %p\n", msgr);
-}
-EXPORT_SYMBOL(ceph_messenger_destroy);
+EXPORT_SYMBOL(ceph_messenger_init);
 
 static void clear_standby(struct ceph_connection *con)
 {
@@ -2305,8 +2372,8 @@ static void clear_standby(struct ceph_connection *con)
 		mutex_lock(&con->mutex);
 		dout("clear_standby %p and ++connect_seq\n", con);
 		con->connect_seq++;
-		WARN_ON(test_bit(WRITE_PENDING, &con->state));
-		WARN_ON(test_bit(KEEPALIVE_PENDING, &con->state));
+		WARN_ON(test_bit(WRITE_PENDING, &con->flags));
+		WARN_ON(test_bit(KEEPALIVE_PENDING, &con->flags));
 		mutex_unlock(&con->mutex);
 	}
 }
@@ -2331,6 +2398,11 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg)
 
 	/* queue */
 	mutex_lock(&con->mutex);
+
+	BUG_ON(msg->con != NULL);
+	msg->con = ceph_con_get(con);
+	BUG_ON(msg->con == NULL);
+
 	BUG_ON(!list_empty(&msg->list_head));
 	list_add_tail(&msg->list_head, &con->out_queue);
 	dout("----- %p to %s%lld %d=%s len %d+%d+%d -----\n", msg,
@@ -2344,7 +2416,7 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg)
 	/* if there wasn't anything waiting to send before, queue
 	 * new work */
 	clear_standby(con);
-	if (test_and_set_bit(WRITE_PENDING, &con->state) == 0)
+	if (test_and_set_bit(WRITE_PENDING, &con->flags) == 0)
 		queue_con(con);
 }
 EXPORT_SYMBOL(ceph_con_send);
@@ -2352,24 +2424,34 @@ EXPORT_SYMBOL(ceph_con_send);
 /*
  * Revoke a message that was previously queued for send
  */
-void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg)
+void ceph_msg_revoke(struct ceph_msg *msg)
 {
+	struct ceph_connection *con = msg->con;
+
+	if (!con)
+		return;		/* Message not in our possession */
+
 	mutex_lock(&con->mutex);
 	if (!list_empty(&msg->list_head)) {
-		dout("con_revoke %p msg %p - was on queue\n", con, msg);
+		dout("%s %p msg %p - was on queue\n", __func__, con, msg);
 		list_del_init(&msg->list_head);
-		ceph_msg_put(msg);
+		BUG_ON(msg->con == NULL);
+		ceph_con_put(msg->con);
+		msg->con = NULL;
 		msg->hdr.seq = 0;
+
+		ceph_msg_put(msg);
 	}
 	if (con->out_msg == msg) {
-		dout("con_revoke %p msg %p - was sending\n", con, msg);
+		dout("%s %p msg %p - was sending\n", __func__, con, msg);
 		con->out_msg = NULL;
 		if (con->out_kvec_is_msg) {
 			con->out_skip = con->out_kvec_bytes;
 			con->out_kvec_is_msg = false;
 		}
-		ceph_msg_put(msg);
 		msg->hdr.seq = 0;
+
+		ceph_msg_put(msg);
 	}
 	mutex_unlock(&con->mutex);
 }
@@ -2377,17 +2459,27 @@ void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg)
 /*
  * Revoke a message that we may be reading data into
  */
-void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg)
+void ceph_msg_revoke_incoming(struct ceph_msg *msg)
 {
+	struct ceph_connection *con;
+
+	BUG_ON(msg == NULL);
+	if (!msg->con) {
+		dout("%s msg %p null con\n", __func__, msg);
+
+		return;		/* Message not in our possession */
+	}
+
+	con = msg->con;
 	mutex_lock(&con->mutex);
-	if (con->in_msg && con->in_msg == msg) {
+	if (con->in_msg == msg) {
 		unsigned int front_len = le32_to_cpu(con->in_hdr.front_len);
 		unsigned int middle_len = le32_to_cpu(con->in_hdr.middle_len);
 		unsigned int data_len = le32_to_cpu(con->in_hdr.data_len);
 
 		/* skip rest of message */
-		dout("con_revoke_pages %p msg %p revoked\n", con, msg);
-			con->in_base_pos = con->in_base_pos -
+		dout("%s %p msg %p revoked\n", __func__, con, msg);
+		con->in_base_pos = con->in_base_pos -
 				sizeof(struct ceph_msg_header) -
 				front_len -
 				middle_len -
@@ -2398,8 +2490,8 @@ void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg)
 		con->in_tag = CEPH_MSGR_TAG_READY;
 		con->in_seq++;
 	} else {
-		dout("con_revoke_pages %p msg %p pages %p no-op\n",
-		     con, con->in_msg, msg);
+		dout("%s %p in_msg %p msg %p no-op\n",
+		     __func__, con, con->in_msg, msg);
 	}
 	mutex_unlock(&con->mutex);
 }
@@ -2411,8 +2503,8 @@ void ceph_con_keepalive(struct ceph_connection *con)
 {
 	dout("con_keepalive %p\n", con);
 	clear_standby(con);
-	if (test_and_set_bit(KEEPALIVE_PENDING, &con->state) == 0 &&
-	    test_and_set_bit(WRITE_PENDING, &con->state) == 0)
+	if (test_and_set_bit(KEEPALIVE_PENDING, &con->flags) == 0 &&
+	    test_and_set_bit(WRITE_PENDING, &con->flags) == 0)
 		queue_con(con);
 }
 EXPORT_SYMBOL(ceph_con_keepalive);
@@ -2431,6 +2523,8 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags,
 	if (m == NULL)
 		goto out;
 	kref_init(&m->kref);
+
+	m->con = NULL;
 	INIT_LIST_HEAD(&m->list_head);
 
 	m->hdr.tid = 0;
@@ -2526,46 +2620,63 @@ static int ceph_alloc_middle(struct ceph_connection *con, struct ceph_msg *msg)
 }
 
 /*
- * Generic message allocator, for incoming messages.
+ * Allocate a message for receiving an incoming message on a
+ * connection, and save the result in con->in_msg.  Uses the
+ * connection's private alloc_msg op if available.
+ *
+ * Returns true if the message should be skipped, false otherwise.
+ * If true is returned (skip message), con->in_msg will be NULL.
+ * If false is returned, con->in_msg will contain a pointer to the
+ * newly-allocated message, or NULL in case of memory exhaustion.
  */
-static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
-				struct ceph_msg_header *hdr,
-				int *skip)
+static bool ceph_con_in_msg_alloc(struct ceph_connection *con,
+				struct ceph_msg_header *hdr)
 {
 	int type = le16_to_cpu(hdr->type);
 	int front_len = le32_to_cpu(hdr->front_len);
 	int middle_len = le32_to_cpu(hdr->middle_len);
-	struct ceph_msg *msg = NULL;
 	int ret;
 
+	BUG_ON(con->in_msg != NULL);
+
 	if (con->ops->alloc_msg) {
+		int skip = 0;
+
 		mutex_unlock(&con->mutex);
-		msg = con->ops->alloc_msg(con, hdr, skip);
+		con->in_msg = con->ops->alloc_msg(con, hdr, &skip);
 		mutex_lock(&con->mutex);
-		if (!msg || *skip)
-			return NULL;
+		if (con->in_msg) {
+			con->in_msg->con = ceph_con_get(con);
+			BUG_ON(con->in_msg->con == NULL);
+		}
+		if (skip)
+			con->in_msg = NULL;
+
+		if (!con->in_msg)
+			return skip != 0;
 	}
-	if (!msg) {
-		*skip = 0;
-		msg = ceph_msg_new(type, front_len, GFP_NOFS, false);
-		if (!msg) {
+	if (!con->in_msg) {
+		con->in_msg = ceph_msg_new(type, front_len, GFP_NOFS, false);
+		if (!con->in_msg) {
 			pr_err("unable to allocate msg type %d len %d\n",
 			       type, front_len);
-			return NULL;
+			return false;
 		}
-		msg->page_alignment = le16_to_cpu(hdr->data_off);
+		con->in_msg->con = ceph_con_get(con);
+		BUG_ON(con->in_msg->con == NULL);
+		con->in_msg->page_alignment = le16_to_cpu(hdr->data_off);
 	}
-	memcpy(&msg->hdr, &con->in_hdr, sizeof(con->in_hdr));
+	memcpy(&con->in_msg->hdr, &con->in_hdr, sizeof(con->in_hdr));
 
-	if (middle_len && !msg->middle) {
-		ret = ceph_alloc_middle(con, msg);
+	if (middle_len && !con->in_msg->middle) {
+		ret = ceph_alloc_middle(con, con->in_msg);
 		if (ret < 0) {
-			ceph_msg_put(msg);
-			return NULL;
+			ceph_msg_put(con->in_msg);
+			con->in_msg = NULL;
 		}
 	}
 
-	return msg;
+	return false;
 }
 
 
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
index d0649a9..e9db3de 100644
--- a/net/ceph/mon_client.c
+++ b/net/ceph/mon_client.c
@@ -106,9 +106,9 @@ static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len)
 	monc->pending_auth = 1;
 	monc->m_auth->front.iov_len = len;
 	monc->m_auth->hdr.front_len = cpu_to_le32(len);
-	ceph_con_revoke(monc->con, monc->m_auth);
+	ceph_msg_revoke(monc->m_auth);
 	ceph_msg_get(monc->m_auth);  /* keep our ref */
-	ceph_con_send(monc->con, monc->m_auth);
+	ceph_con_send(&monc->con, monc->m_auth);
 }
 
 /*
@@ -117,8 +117,9 @@ static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len)
 static void __close_session(struct ceph_mon_client *monc)
 {
 	dout("__close_session closing mon%d\n", monc->cur_mon);
-	ceph_con_revoke(monc->con, monc->m_auth);
-	ceph_con_close(monc->con);
+	ceph_msg_revoke(monc->m_auth);
+	ceph_con_close(&monc->con);
+	monc->con.private = NULL;
 	monc->cur_mon = -1;
 	monc->pending_auth = 0;
 	ceph_auth_reset(monc->auth);
@@ -141,10 +142,12 @@ static int __open_session(struct ceph_mon_client *monc)
 		monc->sub_renew_after = jiffies;  /* i.e., expired */
 		monc->want_next_osdmap = !!monc->want_next_osdmap;
 
+		ceph_con_init(&monc->con, monc, &mon_con_ops,
+			&monc->client->msgr,
+			CEPH_ENTITY_TYPE_MON, monc->cur_mon);
+
 		dout("open_session mon%d opening\n", monc->cur_mon);
-		monc->con->peer_name.type = CEPH_ENTITY_TYPE_MON;
-		monc->con->peer_name.num = cpu_to_le64(monc->cur_mon);
-		ceph_con_open(monc->con,
+		ceph_con_open(&monc->con,
 			      &monc->monmap->mon_inst[monc->cur_mon].addr);
 
 		/* initiatiate authentication handshake */
@@ -226,8 +229,8 @@ static void __send_subscribe(struct ceph_mon_client *monc)
 
 		msg->front.iov_len = p - msg->front.iov_base;
 		msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
-		ceph_con_revoke(monc->con, msg);
-		ceph_con_send(monc->con, ceph_msg_get(msg));
+		ceph_msg_revoke(msg);
+		ceph_con_send(&monc->con, ceph_msg_get(msg));
 
 		monc->sub_sent = jiffies | 1;  /* never 0 */
 	}
@@ -247,7 +250,7 @@ static void handle_subscribe_ack(struct ceph_mon_client *monc,
 	if (monc->hunting) {
 		pr_info("mon%d %s session established\n",
 			monc->cur_mon,
-			ceph_pr_addr(&monc->con->peer_addr.in_addr));
+			ceph_pr_addr(&monc->con.peer_addr.in_addr));
 		monc->hunting = false;
 	}
 	dout("handle_subscribe_ack after %d seconds\n", seconds);
@@ -439,6 +442,7 @@ static struct ceph_msg *get_generic_reply(struct ceph_connection *con,
 		m = NULL;
 	} else {
 		dout("get_generic_reply %lld got %p\n", tid, req->reply);
+		*skip = 0;
 		m = ceph_msg_get(req->reply);
 		/*
 		 * we don't need to track the connection reading into
@@ -461,7 +465,7 @@ static int do_generic_request(struct ceph_mon_client *monc,
 	req->request->hdr.tid = cpu_to_le64(req->tid);
 	__insert_generic_request(monc, req);
 	monc->num_generic_requests++;
-	ceph_con_send(monc->con, ceph_msg_get(req->request));
+	ceph_con_send(&monc->con, ceph_msg_get(req->request));
 	mutex_unlock(&monc->mutex);
 
 	err = wait_for_completion_interruptible(&req->completion);
@@ -684,8 +688,8 @@ static void __resend_generic_request(struct ceph_mon_client *monc)
 
 	for (p = rb_first(&monc->generic_request_tree); p; p = rb_next(p)) {
 		req = rb_entry(p, struct ceph_mon_generic_request, node);
-		ceph_con_revoke(monc->con, req->request);
-		ceph_con_send(monc->con, ceph_msg_get(req->request));
+		ceph_msg_revoke(req->request);
+		ceph_con_send(&monc->con, ceph_msg_get(req->request));
 	}
 }
 
@@ -705,7 +709,7 @@ static void delayed_work(struct work_struct *work)
 		__close_session(monc);
 		__open_session(monc);  /* continue hunting */
 	} else {
-		ceph_con_keepalive(monc->con);
+		ceph_con_keepalive(&monc->con);
 
 		__validate_auth(monc);
 
@@ -760,19 +764,12 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
 		goto out;
 
 	/* connection */
-	monc->con = kmalloc(sizeof(*monc->con), GFP_KERNEL);
-	if (!monc->con)
-		goto out_monmap;
-	ceph_con_init(monc->client->msgr, monc->con);
-	monc->con->private = monc;
-	monc->con->ops = &mon_con_ops;
-
 	/* authentication */
 	monc->auth = ceph_auth_init(cl->options->name,
 				    cl->options->key);
 	if (IS_ERR(monc->auth)) {
 		err = PTR_ERR(monc->auth);
-		goto out_con;
+		goto out_monmap;
 	}
 	monc->auth->want_keys =
 		CEPH_ENTITY_TYPE_AUTH | CEPH_ENTITY_TYPE_MON |
@@ -824,8 +821,6 @@ out_subscribe_ack:
 	ceph_msg_put(monc->m_subscribe_ack);
 out_auth:
 	ceph_auth_destroy(monc->auth);
-out_con:
-	monc->con->ops->put(monc->con);
 out_monmap:
 	kfree(monc->monmap);
 out:
@@ -841,10 +836,6 @@ void ceph_monc_stop(struct ceph_mon_client *monc)
 	mutex_lock(&monc->mutex);
 	__close_session(monc);
 
-	monc->con->private = NULL;
-	monc->con->ops->put(monc->con);
-	monc->con = NULL;
-
 	mutex_unlock(&monc->mutex);
 
 	/*
@@ -888,8 +879,8 @@ static void handle_auth_reply(struct ceph_mon_client *monc,
 	} else if (!was_auth && monc->auth->ops->is_authenticated(monc->auth)) {
 		dout("authenticated, starting session\n");
 
-		monc->client->msgr->inst.name.type = CEPH_ENTITY_TYPE_CLIENT;
-		monc->client->msgr->inst.name.num =
+		monc->client->msgr.inst.name.type = CEPH_ENTITY_TYPE_CLIENT;
+		monc->client->msgr.inst.name.num =
 					cpu_to_le64(monc->auth->global_id);
 
 		__send_subscribe(monc);
@@ -1000,6 +991,8 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
 	case CEPH_MSG_MDS_MAP:
 	case CEPH_MSG_OSD_MAP:
 		m = ceph_msg_new(type, front_len, GFP_NOFS, false);
+		if (!m)
+			return NULL;	/* ENOMEM--return skip == 0 */
 		break;
 	}
 
@@ -1029,7 +1022,7 @@ static void mon_fault(struct ceph_connection *con)
 	if (!monc->hunting)
 		pr_info("mon%d %s session lost, "
 			"hunting for new mon\n", monc->cur_mon,
-			ceph_pr_addr(&monc->con->peer_addr.in_addr));
+			ceph_pr_addr(&monc->con.peer_addr.in_addr));
 
 	__close_session(monc);
 	if (!monc->hunting) {
@@ -1044,9 +1037,23 @@ out:
 	mutex_unlock(&monc->mutex);
 }
 
+/*
+ * We can ignore refcounting on the connection struct, as all references
+ * will come from the messenger workqueue, which is drained prior to
+ * mon_client destruction.
+ */
+static struct ceph_connection *con_get(struct ceph_connection *con)
+{
+	return con;
+}
+
+static void con_put(struct ceph_connection *con)
+{
+}
+
 static const struct ceph_connection_operations mon_con_ops = {
-	.get = ceph_con_get,
-	.put = ceph_con_put,
+	.get = con_get,
+	.put = con_put,
 	.dispatch = dispatch,
 	.fault = mon_fault,
 	.alloc_msg = mon_alloc_msg,
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index ca59e66..db2da54 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -140,10 +140,9 @@ void ceph_osdc_release_request(struct kref *kref)
 	if (req->r_request)
 		ceph_msg_put(req->r_request);
 	if (req->r_con_filling_msg) {
-		dout("release_request revoking pages %p from con %p\n",
+		dout("%s revoking pages %p from con %p\n", __func__,
 		     req->r_pages, req->r_con_filling_msg);
-		ceph_con_revoke_message(req->r_con_filling_msg,
-				      req->r_reply);
+		ceph_msg_revoke_incoming(req->r_reply);
 		req->r_con_filling_msg->ops->put(req->r_con_filling_msg);
 	}
 	if (req->r_reply)
@@ -624,7 +623,7 @@ static void osd_reset(struct ceph_connection *con)
 /*
  * Track open sessions with osds.
  */
-static struct ceph_osd *create_osd(struct ceph_osd_client *osdc)
+static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum)
 {
 	struct ceph_osd *osd;
 
@@ -634,15 +633,14 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc)
 
 	atomic_set(&osd->o_ref, 1);
 	osd->o_osdc = osdc;
+	osd->o_osd = onum;
 	INIT_LIST_HEAD(&osd->o_requests);
 	INIT_LIST_HEAD(&osd->o_linger_requests);
 	INIT_LIST_HEAD(&osd->o_osd_lru);
 	osd->o_incarnation = 1;
 
-	ceph_con_init(osdc->client->msgr, &osd->o_con);
-	osd->o_con.private = osd;
-	osd->o_con.ops = &osd_con_ops;
-	osd->o_con.peer_name.type = CEPH_ENTITY_TYPE_OSD;
+	ceph_con_init(&osd->o_con, osd, &osd_con_ops, &osdc->client->msgr,
+		CEPH_ENTITY_TYPE_OSD, onum);
 
 	INIT_LIST_HEAD(&osd->o_keepalive_item);
 	return osd;
@@ -853,7 +851,7 @@ static void __unregister_request(struct ceph_osd_client *osdc,
 
 	if (req->r_osd) {
 		/* make sure the original request isn't in flight. */
-		ceph_con_revoke(&req->r_osd->o_con, req->r_request);
+		ceph_msg_revoke(req->r_request);
 
 		list_del_init(&req->r_osd_item);
 		if (list_empty(&req->r_osd->o_requests) &&
@@ -880,7 +878,7 @@ static void __unregister_request(struct ceph_osd_client *osdc,
 static void __cancel_request(struct ceph_osd_request *req)
 {
 	if (req->r_sent && req->r_osd) {
-		ceph_con_revoke(&req->r_osd->o_con, req->r_request);
+		ceph_msg_revoke(req->r_request);
 		req->r_sent = 0;
 	}
 }
@@ -998,15 +996,13 @@ static int __map_request(struct ceph_osd_client *osdc,
 	req->r_osd = __lookup_osd(osdc, o);
 	if (!req->r_osd && o >= 0) {
 		err = -ENOMEM;
-		req->r_osd = create_osd(osdc);
+		req->r_osd = create_osd(osdc, o);
 		if (!req->r_osd) {
 			list_move(&req->r_req_lru_item, &osdc->req_notarget);
 			goto out;
 		}
 
 		dout("map_request osd %p is osd%d\n", req->r_osd, o);
-		req->r_osd->o_osd = o;
-		req->r_osd->o_con.peer_name.num = cpu_to_le64(o);
 		__insert_osd(osdc, req->r_osd);
 
 		ceph_con_open(&req->r_osd->o_con, &osdc->osdmap->osd_addr[o]);
@@ -1391,7 +1387,7 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
 			     epoch, maplen);
 			newmap = osdmap_apply_incremental(&p, next,
 							  osdc->osdmap,
-							  osdc->client->msgr);
+							  &osdc->client->msgr);
 			if (IS_ERR(newmap)) {
 				err = PTR_ERR(newmap);
 				goto bad;
@@ -2025,9 +2021,9 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
 	}
 
 	if (req->r_con_filling_msg) {
-		dout("get_reply revoking msg %p from old con %p\n",
+		dout("%s revoking msg %p from old con %p\n", __func__,
 		     req->r_reply, req->r_con_filling_msg);
-		ceph_con_revoke_message(req->r_con_filling_msg, req->r_reply);
+		ceph_msg_revoke_incoming(req->r_reply);
 		req->r_con_filling_msg->ops->put(req->r_con_filling_msg);
 		req->r_con_filling_msg = NULL;
 	}
@@ -2080,6 +2076,7 @@ static struct ceph_msg *alloc_msg(struct ceph_connection *con,
 	int type = le16_to_cpu(hdr->type);
 	int front = le32_to_cpu(hdr->front_len);
 
+	*skip = 0;
 	switch (type) {
 	case CEPH_MSG_OSD_MAP:
 	case CEPH_MSG_WATCH_NOTIFY:
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index 81e3b84..9600674 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -488,15 +488,16 @@ static int __decode_pool_names(void **p, void *end, struct ceph_osdmap *map)
 		ceph_decode_32_safe(p, end, pool, bad);
 		ceph_decode_32_safe(p, end, len, bad);
 		dout("  pool %d len %d\n", pool, len);
+		ceph_decode_need(p, end, len, bad);
 		pi = __lookup_pg_pool(&map->pg_pools, pool);
 		if (pi) {
+			char *name = kstrndup(*p, len, GFP_NOFS);
+
+			if (!name)
+				return -ENOMEM;
 			kfree(pi->name);
-			pi->name = kmalloc(len + 1, GFP_NOFS);
-			if (pi->name) {
-				memcpy(pi->name, *p, len);
-				pi->name[len] = '\0';
-				dout("  name is %s\n", pi->name);
-			}
+			pi->name = name;
+			dout("  name is %s\n", pi->name);
 		}
 		*p += len;
 	}
@@ -666,6 +667,9 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end)
 		ceph_decode_need(p, end, sizeof(u32) + sizeof(u64), bad);
 		ceph_decode_copy(p, &pgid, sizeof(pgid));
 		n = ceph_decode_32(p);
+		err = -EINVAL;
+		if (n > (UINT_MAX - sizeof(*pg)) / sizeof(u32))
+			goto bad;
 		ceph_decode_need(p, end, n * sizeof(u32), bad);
 		err = -ENOMEM;
 		pg = kmalloc(sizeof(*pg) + n*sizeof(u32), GFP_NOFS);
@@ -889,6 +893,10 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
 			(void) __remove_pg_mapping(&map->pg_temp, pgid);
 
 			/* insert */
+			if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) {
+				err = -EINVAL;
+				goto bad;
+			}
 			pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS);
 			if (!pg) {
 				err = -ENOMEM;
diff --git a/net/core/dev.c b/net/core/dev.c
index cd09819..b8f3fdd 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1632,6 +1632,8 @@ static inline int deliver_skb(struct sk_buff *skb,
 			      struct packet_type *pt_prev,
 			      struct net_device *orig_dev)
 {
+	if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
+		return -ENOMEM;
 	atomic_inc(&skb->users);
 	return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
 }
@@ -2089,25 +2091,6 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
 	return 0;
 }
 
-/*
- * Try to orphan skb early, right before transmission by the device.
- * We cannot orphan skb if tx timestamp is requested or the sk-reference
- * is needed on driver level for other reasons, e.g. see net/can/raw.c
- */
-static inline void skb_orphan_try(struct sk_buff *skb)
-{
-	struct sock *sk = skb->sk;
-
-	if (sk && !skb_shinfo(skb)->tx_flags) {
-		/* skb_tx_hash() wont be able to get sk.
-		 * We copy sk_hash into skb->rxhash
-		 */
-		if (!skb->rxhash)
-			skb->rxhash = sk->sk_hash;
-		skb_orphan(skb);
-	}
-}
-
 static bool can_checksum_protocol(netdev_features_t features, __be16 protocol)
 {
 	return ((features & NETIF_F_GEN_CSUM) ||
@@ -2193,8 +2176,6 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 		if (!list_empty(&ptype_all))
 			dev_queue_xmit_nit(skb, dev);
 
-		skb_orphan_try(skb);
-
 		features = netif_skb_features(skb);
 
 		if (vlan_tx_tag_present(skb) &&
@@ -2304,7 +2285,7 @@ u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb,
 	if (skb->sk && skb->sk->sk_hash)
 		hash = skb->sk->sk_hash;
 	else
-		hash = (__force u16) skb->protocol ^ skb->rxhash;
+		hash = (__force u16) skb->protocol;
 	hash = jhash_1word(hash, hashrnd);
 
 	return (u16) (((u64) hash * qcount) >> 32) + qoffset;
@@ -2476,6 +2457,23 @@ static DEFINE_PER_CPU(int, xmit_recursion);
 #define RECURSION_LIMIT 10
 
 /**
+ *	dev_loopback_xmit - loop back @skb
+ *	@skb: buffer to transmit
+ */
+int dev_loopback_xmit(struct sk_buff *skb)
+{
+	skb_reset_mac_header(skb);
+	__skb_pull(skb, skb_network_offset(skb));
+	skb->pkt_type = PACKET_LOOPBACK;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	WARN_ON(!skb_dst(skb));
+	skb_dst_force(skb);
+	netif_rx_ni(skb);
+	return 0;
+}
+EXPORT_SYMBOL(dev_loopback_xmit);
+
+/**
  *	dev_queue_xmit - transmit a buffer
  *	@skb: buffer to transmit
  *
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 9c2afb4..cbf033d 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -729,6 +729,40 @@ static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
 	return dev->ethtool_ops->set_wol(dev, &wol);
 }
 
+static int ethtool_get_eee(struct net_device *dev, char __user *useraddr)
+{
+	struct ethtool_eee edata;
+	int rc;
+
+	if (!dev->ethtool_ops->get_eee)
+		return -EOPNOTSUPP;
+
+	memset(&edata, 0, sizeof(struct ethtool_eee));
+	edata.cmd = ETHTOOL_GEEE;
+	rc = dev->ethtool_ops->get_eee(dev, &edata);
+
+	if (rc)
+		return rc;
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int ethtool_set_eee(struct net_device *dev, char __user *useraddr)
+{
+	struct ethtool_eee edata;
+
+	if (!dev->ethtool_ops->set_eee)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	return dev->ethtool_ops->set_eee(dev, &edata);
+}
+
 static int ethtool_nway_reset(struct net_device *dev)
 {
 	if (!dev->ethtool_ops->nway_reset)
@@ -1409,6 +1443,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 	case ETHTOOL_GSET:
 	case ETHTOOL_GDRVINFO:
 	case ETHTOOL_GMSGLVL:
+	case ETHTOOL_GLINK:
 	case ETHTOOL_GCOALESCE:
 	case ETHTOOL_GRINGPARAM:
 	case ETHTOOL_GPAUSEPARAM:
@@ -1417,6 +1452,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 	case ETHTOOL_GSG:
 	case ETHTOOL_GSSET_INFO:
 	case ETHTOOL_GSTRINGS:
+	case ETHTOOL_GSTATS:
 	case ETHTOOL_GTSO:
 	case ETHTOOL_GPERMADDR:
 	case ETHTOOL_GUFO:
@@ -1429,8 +1465,11 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 	case ETHTOOL_GRXCLSRLCNT:
 	case ETHTOOL_GRXCLSRULE:
 	case ETHTOOL_GRXCLSRLALL:
+	case ETHTOOL_GRXFHINDIR:
 	case ETHTOOL_GFEATURES:
+	case ETHTOOL_GCHANNELS:
 	case ETHTOOL_GET_TS_INFO:
+	case ETHTOOL_GEEE:
 		break;
 	default:
 		if (!capable(CAP_NET_ADMIN))
@@ -1471,6 +1510,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 		rc = ethtool_set_value_void(dev, useraddr,
 				       dev->ethtool_ops->set_msglevel);
 		break;
+	case ETHTOOL_GEEE:
+		rc = ethtool_get_eee(dev, useraddr);
+		break;
+	case ETHTOOL_SEEE:
+		rc = ethtool_set_eee(dev, useraddr);
+		break;
 	case ETHTOOL_NWAY_RST:
 		rc = ethtool_nway_reset(dev);
 		break;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index fdf9e61..7260717 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -417,72 +417,6 @@ static struct attribute_group netstat_group = {
 	.name  = "statistics",
 	.attrs  = netstat_attrs,
 };
-
-#ifdef CONFIG_WIRELESS_EXT_SYSFS
-/* helper function that does all the locking etc for wireless stats */
-static ssize_t wireless_show(struct device *d, char *buf,
-			     ssize_t (*format)(const struct iw_statistics *,
-					       char *))
-{
-	struct net_device *dev = to_net_dev(d);
-	const struct iw_statistics *iw;
-	ssize_t ret = -EINVAL;
-
-	if (!rtnl_trylock())
-		return restart_syscall();
-	if (dev_isalive(dev)) {
-		iw = get_wireless_stats(dev);
-		if (iw)
-			ret = (*format)(iw, buf);
-	}
-	rtnl_unlock();
-
-	return ret;
-}
-
-/* show function template for wireless fields */
-#define WIRELESS_SHOW(name, field, format_string)			\
-static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \
-{									\
-	return sprintf(buf, format_string, iw->field);			\
-}									\
-static ssize_t show_iw_##name(struct device *d,				\
-			      struct device_attribute *attr, char *buf)	\
-{									\
-	return wireless_show(d, buf, format_iw_##name);			\
-}									\
-static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL)
-
-WIRELESS_SHOW(status, status, fmt_hex);
-WIRELESS_SHOW(link, qual.qual, fmt_dec);
-WIRELESS_SHOW(level, qual.level, fmt_dec);
-WIRELESS_SHOW(noise, qual.noise, fmt_dec);
-WIRELESS_SHOW(nwid, discard.nwid, fmt_dec);
-WIRELESS_SHOW(crypt, discard.code, fmt_dec);
-WIRELESS_SHOW(fragment, discard.fragment, fmt_dec);
-WIRELESS_SHOW(misc, discard.misc, fmt_dec);
-WIRELESS_SHOW(retries, discard.retries, fmt_dec);
-WIRELESS_SHOW(beacon, miss.beacon, fmt_dec);
-
-static struct attribute *wireless_attrs[] = {
-	&dev_attr_status.attr,
-	&dev_attr_link.attr,
-	&dev_attr_level.attr,
-	&dev_attr_noise.attr,
-	&dev_attr_nwid.attr,
-	&dev_attr_crypt.attr,
-	&dev_attr_fragment.attr,
-	&dev_attr_retries.attr,
-	&dev_attr_misc.attr,
-	&dev_attr_beacon.attr,
-	NULL
-};
-
-static struct attribute_group wireless_group = {
-	.name = "wireless",
-	.attrs = wireless_attrs,
-};
-#endif
 #endif /* CONFIG_SYSFS */
 
 #ifdef CONFIG_RPS
@@ -1463,14 +1397,6 @@ int netdev_register_kobject(struct net_device *net)
 		groups++;
 
 	*groups++ = &netstat_group;
-#ifdef CONFIG_WIRELESS_EXT_SYSFS
-	if (net->ieee80211_ptr)
-		*groups++ = &wireless_group;
-#ifdef CONFIG_WIRELESS_EXT
-	else if (net->wireless_handlers)
-		*groups++ = &wireless_group;
-#endif
-#endif
 #endif /* CONFIG_SYSFS */
 
 	error = device_add(dev);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d78671e..20106a4 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -160,8 +160,8 @@ static void skb_under_panic(struct sk_buff *skb, int sz, void *here)
  *	@node: numa node to allocate memory on
  *
  *	Allocate a new &sk_buff. The returned buffer has no headroom and a
- *	tail room of size bytes. The object has a reference count of one.
- *	The return is the buffer. On a failure the return is %NULL.
+ *	tail room of at least size bytes. The object has a reference count
+ *	of one. The return is the buffer. On a failure the return is %NULL.
  *
  *	Buffers may only be allocated from interrupts using a @gfp_mask of
  *	%GFP_ATOMIC.
@@ -771,7 +771,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
 	skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
 	return 0;
 }
-
+EXPORT_SYMBOL_GPL(skb_copy_ubufs);
 
 /**
  *	skb_clone	-	duplicate an sk_buff
@@ -791,10 +791,8 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
 {
 	struct sk_buff *n;
 
-	if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
-		if (skb_copy_ubufs(skb, gfp_mask))
-			return NULL;
-	}
+	if (skb_orphan_frags(skb, gfp_mask))
+		return NULL;
 
 	n = skb + 1;
 	if (skb->fclone == SKB_FCLONE_ORIG &&
@@ -914,12 +912,10 @@ struct sk_buff *__pskb_copy(struct sk_buff *skb, int headroom, gfp_t gfp_mask)
 	if (skb_shinfo(skb)->nr_frags) {
 		int i;
 
-		if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
-			if (skb_copy_ubufs(skb, gfp_mask)) {
-				kfree_skb(n);
-				n = NULL;
-				goto out;
-			}
+		if (skb_orphan_frags(skb, gfp_mask)) {
+			kfree_skb(n);
+			n = NULL;
+			goto out;
 		}
 		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
 			skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
@@ -992,10 +988,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 	 */
 	if (skb_cloned(skb)) {
 		/* copy this zero copy skb frags */
-		if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
-			if (skb_copy_ubufs(skb, gfp_mask))
-				goto nofrags;
-		}
+		if (skb_orphan_frags(skb, gfp_mask))
+			goto nofrags;
 		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
 			skb_frag_ref(skb, i);
 
@@ -1755,6 +1749,7 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
 	struct splice_pipe_desc spd = {
 		.pages = pages,
 		.partial = partial,
+		.nr_pages_max = MAX_SKB_FRAGS,
 		.flags = flags,
 		.ops = &sock_pipe_buf_ops,
 		.spd_release = sock_spd_release,
diff --git a/net/core/sock.c b/net/core/sock.c
index 9e5b71f..929bdcc 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1465,6 +1465,11 @@ void sock_rfree(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_rfree);
 
+void sock_edemux(struct sk_buff *skb)
+{
+	sock_put(skb->sk);
+}
+EXPORT_SYMBOL(sock_edemux);
 
 int sock_i_uid(struct sock *sk)
 {
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index 5fd1467..0d934ce 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -46,6 +46,7 @@ int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype)
 	mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc;
 	mem[SK_MEMINFO_WMEM_QUEUED] = sk->sk_wmem_queued;
 	mem[SK_MEMINFO_OPTMEM] = atomic_read(&sk->sk_omem_alloc);
+	mem[SK_MEMINFO_BACKLOG] = sk->sk_backlog.len;
 
 	return 0;
 
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index 656c7c7..013da86 100644
--- a/net/dcb/dcbnl.c
+++ b/net/dcb/dcbnl.c
@@ -196,92 +196,66 @@ static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = {
 static LIST_HEAD(dcb_app_list);
 static DEFINE_SPINLOCK(dcb_lock);
 
-/* standard netlink reply call */
-static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
-                       u32 seq, u16 flags)
+static struct sk_buff *dcbnl_newmsg(int type, u8 cmd, u32 port, u32 seq,
+				    u32 flags, struct nlmsghdr **nlhp)
 {
-	struct sk_buff *dcbnl_skb;
+	struct sk_buff *skb;
 	struct dcbmsg *dcb;
 	struct nlmsghdr *nlh;
-	int ret = -EINVAL;
 
-	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!dcbnl_skb)
-		return ret;
+	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!skb)
+		return NULL;
 
-	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
+	nlh = nlmsg_put(skb, port, seq, type, sizeof(*dcb), flags);
+	BUG_ON(!nlh);
 
-	dcb = NLMSG_DATA(nlh);
+	dcb = nlmsg_data(nlh);
 	dcb->dcb_family = AF_UNSPEC;
 	dcb->cmd = cmd;
 	dcb->dcb_pad = 0;
 
-	ret = nla_put_u8(dcbnl_skb, attr, value);
-	if (ret)
-		goto err;
+	if (nlhp)
+		*nlhp = nlh;
 
-	/* end the message, assign the nlmsg_len. */
-	nlmsg_end(dcbnl_skb, nlh);
-	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
-	if (ret)
-		return -EINVAL;
-
-	return 0;
-nlmsg_failure:
-err:
-	kfree_skb(dcbnl_skb);
-	return ret;
+	return skb;
 }
 
-static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
-                          u32 pid, u32 seq, u16 flags)
+static int dcbnl_getstate(struct net_device *netdev, struct nlmsghdr *nlh,
+			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	int ret = -EINVAL;
-
 	/* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
 	if (!netdev->dcbnl_ops->getstate)
-		return ret;
-
-	ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
-	                  DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
+		return -EOPNOTSUPP;
 
-	return ret;
+	return nla_put_u8(skb, DCB_ATTR_STATE,
+			  netdev->dcbnl_ops->getstate(netdev));
 }
 
-static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
-                           u32 pid, u32 seq, u16 flags)
+static int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	struct sk_buff *dcbnl_skb;
-	struct nlmsghdr *nlh;
-	struct dcbmsg *dcb;
 	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
 	u8 value;
-	int ret = -EINVAL;
+	int ret;
 	int i;
 	int getall = 0;
 
-	if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
-		return ret;
+	if (!tb[DCB_ATTR_PFC_CFG])
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops->getpfccfg)
+		return -EOPNOTSUPP;
 
 	ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
 	                       tb[DCB_ATTR_PFC_CFG],
 	                       dcbnl_pfc_up_nest);
 	if (ret)
-		goto err_out;
-
-	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!dcbnl_skb)
-		goto err_out;
-
-	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
-
-	dcb = NLMSG_DATA(nlh);
-	dcb->dcb_family = AF_UNSPEC;
-	dcb->cmd = DCB_CMD_PFC_GCFG;
+		return ret;
 
-	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
+	nest = nla_nest_start(skb, DCB_ATTR_PFC_CFG);
 	if (!nest)
-		goto err;
+		return -EMSGSIZE;
 
 	if (data[DCB_PFC_UP_ATTR_ALL])
 		getall = 1;
@@ -292,103 +266,53 @@ static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
 
 		netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
 		                             &value);
-		ret = nla_put_u8(dcbnl_skb, i, value);
-
+		ret = nla_put_u8(skb, i, value);
 		if (ret) {
-			nla_nest_cancel(dcbnl_skb, nest);
-			goto err;
+			nla_nest_cancel(skb, nest);
+			return ret;
 		}
 	}
-	nla_nest_end(dcbnl_skb, nest);
-
-	nlmsg_end(dcbnl_skb, nlh);
-
-	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
-	if (ret)
-		goto err_out;
+	nla_nest_end(skb, nest);
 
 	return 0;
-nlmsg_failure:
-err:
-	kfree_skb(dcbnl_skb);
-err_out:
-	return -EINVAL;
 }
 
-static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
-                                u32 pid, u32 seq, u16 flags)
+static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlmsghdr *nlh,
+				u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	struct sk_buff *dcbnl_skb;
-	struct nlmsghdr *nlh;
-	struct dcbmsg *dcb;
 	u8 perm_addr[MAX_ADDR_LEN];
-	int ret = -EINVAL;
 
 	if (!netdev->dcbnl_ops->getpermhwaddr)
-		return ret;
-
-	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!dcbnl_skb)
-		goto err_out;
-
-	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
-
-	dcb = NLMSG_DATA(nlh);
-	dcb->dcb_family = AF_UNSPEC;
-	dcb->cmd = DCB_CMD_GPERM_HWADDR;
+		return -EOPNOTSUPP;
 
 	netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
 
-	ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
-	              perm_addr);
-
-	nlmsg_end(dcbnl_skb, nlh);
-
-	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
-	if (ret)
-		goto err_out;
-
-	return 0;
-
-nlmsg_failure:
-	kfree_skb(dcbnl_skb);
-err_out:
-	return -EINVAL;
+	return nla_put(skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), perm_addr);
 }
 
-static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
-                        u32 pid, u32 seq, u16 flags)
+static int dcbnl_getcap(struct net_device *netdev, struct nlmsghdr *nlh,
+			u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	struct sk_buff *dcbnl_skb;
-	struct nlmsghdr *nlh;
-	struct dcbmsg *dcb;
 	struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
 	u8 value;
-	int ret = -EINVAL;
+	int ret;
 	int i;
 	int getall = 0;
 
-	if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
-		return ret;
+	if (!tb[DCB_ATTR_CAP])
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops->getcap)
+		return -EOPNOTSUPP;
 
 	ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
 	                       dcbnl_cap_nest);
 	if (ret)
-		goto err_out;
-
-	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!dcbnl_skb)
-		goto err_out;
-
-	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
-
-	dcb = NLMSG_DATA(nlh);
-	dcb->dcb_family = AF_UNSPEC;
-	dcb->cmd = DCB_CMD_GCAP;
+		return ret;
 
-	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
+	nest = nla_nest_start(skb, DCB_ATTR_CAP);
 	if (!nest)
-		goto err;
+		return -EMSGSIZE;
 
 	if (data[DCB_CAP_ATTR_ALL])
 		getall = 1;
@@ -398,69 +322,41 @@ static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
 			continue;
 
 		if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
-			ret = nla_put_u8(dcbnl_skb, i, value);
-
+			ret = nla_put_u8(skb, i, value);
 			if (ret) {
-				nla_nest_cancel(dcbnl_skb, nest);
-				goto err;
+				nla_nest_cancel(skb, nest);
+				return ret;
 			}
 		}
 	}
-	nla_nest_end(dcbnl_skb, nest);
-
-	nlmsg_end(dcbnl_skb, nlh);
-
-	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
-	if (ret)
-		goto err_out;
+	nla_nest_end(skb, nest);
 
 	return 0;
-nlmsg_failure:
-err:
-	kfree_skb(dcbnl_skb);
-err_out:
-	return -EINVAL;
 }
 
-static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
-                           u32 pid, u32 seq, u16 flags)
+static int dcbnl_getnumtcs(struct net_device *netdev, struct nlmsghdr *nlh,
+			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	struct sk_buff *dcbnl_skb;
-	struct nlmsghdr *nlh;
-	struct dcbmsg *dcb;
 	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
 	u8 value;
-	int ret = -EINVAL;
+	int ret;
 	int i;
 	int getall = 0;
 
-	if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs)
-		return ret;
+	if (!tb[DCB_ATTR_NUMTCS])
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops->getnumtcs)
+		return -EOPNOTSUPP;
 
 	ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
 	                       dcbnl_numtcs_nest);
-	if (ret) {
-		ret = -EINVAL;
-		goto err_out;
-	}
-
-	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!dcbnl_skb) {
-		ret = -EINVAL;
-		goto err_out;
-	}
-
-	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
-
-	dcb = NLMSG_DATA(nlh);
-	dcb->dcb_family = AF_UNSPEC;
-	dcb->cmd = DCB_CMD_GNUMTCS;
+	if (ret)
+		return ret;
 
-	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS);
-	if (!nest) {
-		ret = -EINVAL;
-		goto err;
-	}
+	nest = nla_nest_start(skb, DCB_ATTR_NUMTCS);
+	if (!nest)
+		return -EMSGSIZE;
 
 	if (data[DCB_NUMTCS_ATTR_ALL])
 		getall = 1;
@@ -471,53 +367,37 @@ static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
 
 		ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
 		if (!ret) {
-			ret = nla_put_u8(dcbnl_skb, i, value);
-
+			ret = nla_put_u8(skb, i, value);
 			if (ret) {
-				nla_nest_cancel(dcbnl_skb, nest);
-				ret = -EINVAL;
-				goto err;
+				nla_nest_cancel(skb, nest);
+				return ret;
 			}
-		} else {
-			goto err;
-		}
-	}
-	nla_nest_end(dcbnl_skb, nest);
-
-	nlmsg_end(dcbnl_skb, nlh);
-
-	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
-	if (ret) {
-		ret = -EINVAL;
-		goto err_out;
+		} else
+			return -EINVAL;
 	}
+	nla_nest_end(skb, nest);
 
 	return 0;
-nlmsg_failure:
-err:
-	kfree_skb(dcbnl_skb);
-err_out:
-	return ret;
 }
 
-static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
-                           u32 pid, u32 seq, u16 flags)
+static int dcbnl_setnumtcs(struct net_device *netdev, struct nlmsghdr *nlh,
+			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
 	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
-	int ret = -EINVAL;
+	int ret;
 	u8 value;
 	int i;
 
-	if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs)
-		return ret;
+	if (!tb[DCB_ATTR_NUMTCS])
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops->setnumtcs)
+		return -EOPNOTSUPP;
 
 	ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
 	                       dcbnl_numtcs_nest);
-
-	if (ret) {
-		ret = -EINVAL;
-		goto err;
-	}
+	if (ret)
+		return ret;
 
 	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
 		if (data[i] == NULL)
@@ -526,84 +406,68 @@ static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
 		value = nla_get_u8(data[i]);
 
 		ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
-
 		if (ret)
-			goto operr;
+			break;
 	}
 
-operr:
-	ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS,
-	                  DCB_ATTR_NUMTCS, pid, seq, flags);
-
-err:
-	return ret;
+	return nla_put_u8(skb, DCB_ATTR_NUMTCS, !!ret);
 }
 
-static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb,
-                             u32 pid, u32 seq, u16 flags)
+static int dcbnl_getpfcstate(struct net_device *netdev, struct nlmsghdr *nlh,
+			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	int ret = -EINVAL;
-
 	if (!netdev->dcbnl_ops->getpfcstate)
-		return ret;
-
-	ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB,
-	                  DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE,
-	                  pid, seq, flags);
+		return -EOPNOTSUPP;
 
-	return ret;
+	return nla_put_u8(skb, DCB_ATTR_PFC_STATE,
+			  netdev->dcbnl_ops->getpfcstate(netdev));
 }
 
-static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb,
-                             u32 pid, u32 seq, u16 flags)
+static int dcbnl_setpfcstate(struct net_device *netdev, struct nlmsghdr *nlh,
+			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	int ret = -EINVAL;
 	u8 value;
 
-	if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate)
-		return ret;
+	if (!tb[DCB_ATTR_PFC_STATE])
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops->setpfcstate)
+		return -EOPNOTSUPP;
 
 	value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
 
 	netdev->dcbnl_ops->setpfcstate(netdev, value);
 
-	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE,
-	                  pid, seq, flags);
-
-	return ret;
+	return nla_put_u8(skb, DCB_ATTR_PFC_STATE, 0);
 }
 
-static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
-                        u32 pid, u32 seq, u16 flags)
+static int dcbnl_getapp(struct net_device *netdev, struct nlmsghdr *nlh,
+			u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	struct sk_buff *dcbnl_skb;
-	struct nlmsghdr *nlh;
-	struct dcbmsg *dcb;
 	struct nlattr *app_nest;
 	struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
 	u16 id;
 	u8 up, idtype;
-	int ret = -EINVAL;
+	int ret;
 
 	if (!tb[DCB_ATTR_APP])
-		goto out;
+		return -EINVAL;
 
 	ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
 	                       dcbnl_app_nest);
 	if (ret)
-		goto out;
+		return ret;
 
-	ret = -EINVAL;
 	/* all must be non-null */
 	if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
 	    (!app_tb[DCB_APP_ATTR_ID]))
-		goto out;
+		return -EINVAL;
 
 	/* either by eth type or by socket number */
 	idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
 	if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
 	    (idtype != DCB_APP_IDTYPE_PORTNUM))
-		goto out;
+		return -EINVAL;
 
 	id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
 
@@ -617,138 +481,106 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
 		up = dcb_getapp(netdev, &app);
 	}
 
-	/* send this back */
-	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!dcbnl_skb)
-		goto out;
-
-	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
-	dcb = NLMSG_DATA(nlh);
-	dcb->dcb_family = AF_UNSPEC;
-	dcb->cmd = DCB_CMD_GAPP;
-
-	app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP);
+	app_nest = nla_nest_start(skb, DCB_ATTR_APP);
 	if (!app_nest)
-		goto out_cancel;
+		return -EMSGSIZE;
 
-	ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype);
+	ret = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, idtype);
 	if (ret)
 		goto out_cancel;
 
-	ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id);
+	ret = nla_put_u16(skb, DCB_APP_ATTR_ID, id);
 	if (ret)
 		goto out_cancel;
 
-	ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up);
+	ret = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, up);
 	if (ret)
 		goto out_cancel;
 
-	nla_nest_end(dcbnl_skb, app_nest);
-	nlmsg_end(dcbnl_skb, nlh);
-
-	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
-	if (ret)
-		goto nlmsg_failure;
+	nla_nest_end(skb, app_nest);
 
-	goto out;
+	return 0;
 
 out_cancel:
-	nla_nest_cancel(dcbnl_skb, app_nest);
-nlmsg_failure:
-	kfree_skb(dcbnl_skb);
-out:
+	nla_nest_cancel(skb, app_nest);
 	return ret;
 }
 
-static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb,
-                        u32 pid, u32 seq, u16 flags)
+static int dcbnl_setapp(struct net_device *netdev, struct nlmsghdr *nlh,
+			u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	int err, ret = -EINVAL;
+	int ret;
 	u16 id;
 	u8 up, idtype;
 	struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
 
 	if (!tb[DCB_ATTR_APP])
-		goto out;
+		return -EINVAL;
 
 	ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
 	                       dcbnl_app_nest);
 	if (ret)
-		goto out;
+		return ret;
 
-	ret = -EINVAL;
 	/* all must be non-null */
 	if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
 	    (!app_tb[DCB_APP_ATTR_ID]) ||
 	    (!app_tb[DCB_APP_ATTR_PRIORITY]))
-		goto out;
+		return -EINVAL;
 
 	/* either by eth type or by socket number */
 	idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
 	if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
 	    (idtype != DCB_APP_IDTYPE_PORTNUM))
-		goto out;
+		return -EINVAL;
 
 	id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
 	up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]);
 
 	if (netdev->dcbnl_ops->setapp) {
-		err = netdev->dcbnl_ops->setapp(netdev, idtype, id, up);
+		ret = netdev->dcbnl_ops->setapp(netdev, idtype, id, up);
 	} else {
 		struct dcb_app app;
 		app.selector = idtype;
 		app.protocol = id;
 		app.priority = up;
-		err = dcb_setapp(netdev, &app);
+		ret = dcb_setapp(netdev, &app);
 	}
 
-	ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP,
-			  pid, seq, flags);
+	ret = nla_put_u8(skb, DCB_ATTR_APP, ret);
 	dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SAPP, seq, 0);
-out:
+
 	return ret;
 }
 
-static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
-                             u32 pid, u32 seq, u16 flags, int dir)
+static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			     struct nlattr **tb, struct sk_buff *skb, int dir)
 {
-	struct sk_buff *dcbnl_skb;
-	struct nlmsghdr *nlh;
-	struct dcbmsg *dcb;
 	struct nlattr *pg_nest, *param_nest, *data;
 	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
 	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
 	u8 prio, pgid, tc_pct, up_map;
-	int ret  = -EINVAL;
+	int ret;
 	int getall = 0;
 	int i;
 
-	if (!tb[DCB_ATTR_PG_CFG] ||
-	    !netdev->dcbnl_ops->getpgtccfgtx ||
+	if (!tb[DCB_ATTR_PG_CFG])
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops->getpgtccfgtx ||
 	    !netdev->dcbnl_ops->getpgtccfgrx ||
 	    !netdev->dcbnl_ops->getpgbwgcfgtx ||
 	    !netdev->dcbnl_ops->getpgbwgcfgrx)
-		return ret;
+		return -EOPNOTSUPP;
 
 	ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
 	                       tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
-
 	if (ret)
-		goto err_out;
-
-	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!dcbnl_skb)
-		goto err_out;
-
-	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
-
-	dcb = NLMSG_DATA(nlh);
-	dcb->dcb_family = AF_UNSPEC;
-	dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
+		return ret;
 
-	pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
+	pg_nest = nla_nest_start(skb, DCB_ATTR_PG_CFG);
 	if (!pg_nest)
-		goto err;
+		return -EMSGSIZE;
 
 	if (pg_tb[DCB_PG_ATTR_TC_ALL])
 		getall = 1;
@@ -766,7 +598,7 @@ static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
 		if (ret)
 			goto err_pg;
 
-		param_nest = nla_nest_start(dcbnl_skb, i);
+		param_nest = nla_nest_start(skb, i);
 		if (!param_nest)
 			goto err_pg;
 
@@ -789,33 +621,33 @@ static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
 
 		if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
-			ret = nla_put_u8(dcbnl_skb,
+			ret = nla_put_u8(skb,
 			                 DCB_TC_ATTR_PARAM_PGID, pgid);
 			if (ret)
 				goto err_param;
 		}
 		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
-			ret = nla_put_u8(dcbnl_skb,
+			ret = nla_put_u8(skb,
 			                 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
 			if (ret)
 				goto err_param;
 		}
 		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
-			ret = nla_put_u8(dcbnl_skb,
+			ret = nla_put_u8(skb,
 			                 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
 			if (ret)
 				goto err_param;
 		}
 		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
 		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
-			ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
+			ret = nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT,
 			                 tc_pct);
 			if (ret)
 				goto err_param;
 		}
-		nla_nest_end(dcbnl_skb, param_nest);
+		nla_nest_end(skb, param_nest);
 	}
 
 	if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
@@ -838,80 +670,71 @@ static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
 			netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
 					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
 		}
-		ret = nla_put_u8(dcbnl_skb, i, tc_pct);
-
+		ret = nla_put_u8(skb, i, tc_pct);
 		if (ret)
 			goto err_pg;
 	}
 
-	nla_nest_end(dcbnl_skb, pg_nest);
-
-	nlmsg_end(dcbnl_skb, nlh);
-
-	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
-	if (ret)
-		goto err_out;
+	nla_nest_end(skb, pg_nest);
 
 	return 0;
 
 err_param:
-	nla_nest_cancel(dcbnl_skb, param_nest);
+	nla_nest_cancel(skb, param_nest);
 err_pg:
-	nla_nest_cancel(dcbnl_skb, pg_nest);
-nlmsg_failure:
-err:
-	kfree_skb(dcbnl_skb);
-err_out:
-	ret  = -EINVAL;
-	return ret;
+	nla_nest_cancel(skb, pg_nest);
+
+	return -EMSGSIZE;
 }
 
-static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
-                             u32 pid, u32 seq, u16 flags)
+static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
+	return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 0);
 }
 
-static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
-                             u32 pid, u32 seq, u16 flags)
+static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
+	return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 1);
 }
 
-static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
-                          u32 pid, u32 seq, u16 flags)
+static int dcbnl_setstate(struct net_device *netdev, struct nlmsghdr *nlh,
+			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	int ret = -EINVAL;
 	u8 value;
 
-	if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
-		return ret;
+	if (!tb[DCB_ATTR_STATE])
+		return -EINVAL;
 
-	value = nla_get_u8(tb[DCB_ATTR_STATE]);
+	if (!netdev->dcbnl_ops->setstate)
+		return -EOPNOTSUPP;
 
-	ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value),
-	                  RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
-	                  pid, seq, flags);
+	value = nla_get_u8(tb[DCB_ATTR_STATE]);
 
-	return ret;
+	return nla_put_u8(skb, DCB_ATTR_STATE,
+			  netdev->dcbnl_ops->setstate(netdev, value));
 }
 
-static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
-                           u32 pid, u32 seq, u16 flags)
+static int dcbnl_setpfccfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			   u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
 	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
 	int i;
-	int ret = -EINVAL;
+	int ret;
 	u8 value;
 
-	if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
-		return ret;
+	if (!tb[DCB_ATTR_PFC_CFG])
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops->setpfccfg)
+		return -EOPNOTSUPP;
 
 	ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
 	                       tb[DCB_ATTR_PFC_CFG],
 	                       dcbnl_pfc_up_nest);
 	if (ret)
-		goto err;
+		return ret;
 
 	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
 		if (data[i] == NULL)
@@ -921,50 +744,53 @@ static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
 			data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
 	}
 
-	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
-	                  pid, seq, flags);
-err:
-	return ret;
+	return nla_put_u8(skb, DCB_ATTR_PFC_CFG, 0);
 }
 
-static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
-                        u32 pid, u32 seq, u16 flags)
+static int dcbnl_setall(struct net_device *netdev, struct nlmsghdr *nlh,
+			u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	int ret = -EINVAL;
+	int ret;
 
-	if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
-		return ret;
+	if (!tb[DCB_ATTR_SET_ALL])
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops->setall)
+		return -EOPNOTSUPP;
 
-	ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
-	                  DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
+	ret = nla_put_u8(skb, DCB_ATTR_SET_ALL,
+			 netdev->dcbnl_ops->setall(netdev));
 	dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SET_ALL, seq, 0);
 
 	return ret;
 }
 
-static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
-                             u32 pid, u32 seq, u16 flags, int dir)
+static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			     u32 seq, struct nlattr **tb, struct sk_buff *skb,
+			     int dir)
 {
 	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
 	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
-	int ret = -EINVAL;
+	int ret;
 	int i;
 	u8 pgid;
 	u8 up_map;
 	u8 prio;
 	u8 tc_pct;
 
-	if (!tb[DCB_ATTR_PG_CFG] ||
-	    !netdev->dcbnl_ops->setpgtccfgtx ||
+	if (!tb[DCB_ATTR_PG_CFG])
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops->setpgtccfgtx ||
 	    !netdev->dcbnl_ops->setpgtccfgrx ||
 	    !netdev->dcbnl_ops->setpgbwgcfgtx ||
 	    !netdev->dcbnl_ops->setpgbwgcfgrx)
-		return ret;
+		return -EOPNOTSUPP;
 
 	ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
 	                       tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
 	if (ret)
-		goto err;
+		return ret;
 
 	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
 		if (!pg_tb[i])
@@ -973,7 +799,7 @@ static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
 		ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
 		                       pg_tb[i], dcbnl_tc_param_nest);
 		if (ret)
-			goto err;
+			return ret;
 
 		pgid = DCB_ATTR_VALUE_UNDEFINED;
 		prio = DCB_ATTR_VALUE_UNDEFINED;
@@ -1026,63 +852,47 @@ static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
 		}
 	}
 
-	ret = dcbnl_reply(0, RTM_SETDCB,
-			  (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
-			  DCB_ATTR_PG_CFG, pid, seq, flags);
-
-err:
-	return ret;
+	return nla_put_u8(skb, DCB_ATTR_PG_CFG, 0);
 }
 
-static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
-                             u32 pid, u32 seq, u16 flags)
+static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
+	return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 0);
 }
 
-static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
-                             u32 pid, u32 seq, u16 flags)
+static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			     u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
+	return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 1);
 }
 
-static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
-                            u32 pid, u32 seq, u16 flags)
+static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	struct sk_buff *dcbnl_skb;
-	struct nlmsghdr *nlh;
-	struct dcbmsg *dcb;
 	struct nlattr *bcn_nest;
 	struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
 	u8 value_byte;
 	u32 value_integer;
-	int ret  = -EINVAL;
+	int ret;
 	bool getall = false;
 	int i;
 
-	if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp ||
+	if (!tb[DCB_ATTR_BCN])
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops->getbcnrp ||
 	    !netdev->dcbnl_ops->getbcncfg)
-		return ret;
+		return -EOPNOTSUPP;
 
 	ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
 	                       tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
-
 	if (ret)
-		goto err_out;
-
-	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!dcbnl_skb)
-		goto err_out;
-
-	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
-
-	dcb = NLMSG_DATA(nlh);
-	dcb->dcb_family = AF_UNSPEC;
-	dcb->cmd = DCB_CMD_BCN_GCFG;
+		return ret;
 
-	bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN);
+	bcn_nest = nla_nest_start(skb, DCB_ATTR_BCN);
 	if (!bcn_nest)
-		goto err;
+		return -EMSGSIZE;
 
 	if (bcn_tb[DCB_BCN_ATTR_ALL])
 		getall = true;
@@ -1093,7 +903,7 @@ static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
 
 		netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
 		                            &value_byte);
-		ret = nla_put_u8(dcbnl_skb, i, value_byte);
+		ret = nla_put_u8(skb, i, value_byte);
 		if (ret)
 			goto err_bcn;
 	}
@@ -1104,49 +914,41 @@ static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
 
 		netdev->dcbnl_ops->getbcncfg(netdev, i,
 		                             &value_integer);
-		ret = nla_put_u32(dcbnl_skb, i, value_integer);
+		ret = nla_put_u32(skb, i, value_integer);
 		if (ret)
 			goto err_bcn;
 	}
 
-	nla_nest_end(dcbnl_skb, bcn_nest);
-
-	nlmsg_end(dcbnl_skb, nlh);
-
-	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
-	if (ret)
-		goto err_out;
+	nla_nest_end(skb, bcn_nest);
 
 	return 0;
 
 err_bcn:
-	nla_nest_cancel(dcbnl_skb, bcn_nest);
-nlmsg_failure:
-err:
-	kfree_skb(dcbnl_skb);
-err_out:
-	ret  = -EINVAL;
+	nla_nest_cancel(skb, bcn_nest);
 	return ret;
 }
 
-static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
-                            u32 pid, u32 seq, u16 flags)
+static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
 	struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
 	int i;
-	int ret = -EINVAL;
+	int ret;
 	u8 value_byte;
 	u32 value_int;
 
-	if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg ||
+	if (!tb[DCB_ATTR_BCN])
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops->setbcncfg ||
 	    !netdev->dcbnl_ops->setbcnrp)
-		return ret;
+		return -EOPNOTSUPP;
 
 	ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
 	                       tb[DCB_ATTR_BCN],
 	                       dcbnl_pfc_up_nest);
 	if (ret)
-		goto err;
+		return ret;
 
 	for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
 		if (data[i] == NULL)
@@ -1164,10 +966,7 @@ static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
 	                                     i, value_int);
 	}
 
-	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN,
-	                  pid, seq, flags);
-err:
-	return ret;
+	return nla_put_u8(skb, DCB_ATTR_BCN, 0);
 }
 
 static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb,
@@ -1233,20 +1032,21 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
 	struct dcb_app_type *itr;
 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
 	int dcbx;
-	int err = -EMSGSIZE;
+	int err;
 
 	if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name))
-		goto nla_put_failure;
+		return -EMSGSIZE;
+
 	ieee = nla_nest_start(skb, DCB_ATTR_IEEE);
 	if (!ieee)
-		goto nla_put_failure;
+		return -EMSGSIZE;
 
 	if (ops->ieee_getets) {
 		struct ieee_ets ets;
 		err = ops->ieee_getets(netdev, &ets);
 		if (!err &&
 		    nla_put(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets))
-			goto nla_put_failure;
+			return -EMSGSIZE;
 	}
 
 	if (ops->ieee_getmaxrate) {
@@ -1256,7 +1056,7 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
 			err = nla_put(skb, DCB_ATTR_IEEE_MAXRATE,
 				      sizeof(maxrate), &maxrate);
 			if (err)
-				goto nla_put_failure;
+				return -EMSGSIZE;
 		}
 	}
 
@@ -1265,12 +1065,12 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
 		err = ops->ieee_getpfc(netdev, &pfc);
 		if (!err &&
 		    nla_put(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc))
-			goto nla_put_failure;
+			return -EMSGSIZE;
 	}
 
 	app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE);
 	if (!app)
-		goto nla_put_failure;
+		return -EMSGSIZE;
 
 	spin_lock(&dcb_lock);
 	list_for_each_entry(itr, &dcb_app_list, list) {
@@ -1279,7 +1079,7 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
 					 &itr->app);
 			if (err) {
 				spin_unlock(&dcb_lock);
-				goto nla_put_failure;
+				return -EMSGSIZE;
 			}
 		}
 	}
@@ -1298,7 +1098,7 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
 		err = ops->ieee_peer_getets(netdev, &ets);
 		if (!err &&
 		    nla_put(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets))
-			goto nla_put_failure;
+			return -EMSGSIZE;
 	}
 
 	if (ops->ieee_peer_getpfc) {
@@ -1306,7 +1106,7 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
 		err = ops->ieee_peer_getpfc(netdev, &pfc);
 		if (!err &&
 		    nla_put(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc))
-			goto nla_put_failure;
+			return -EMSGSIZE;
 	}
 
 	if (ops->peer_getappinfo && ops->peer_getapptable) {
@@ -1315,20 +1115,17 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
 					   DCB_ATTR_IEEE_APP_UNSPEC,
 					   DCB_ATTR_IEEE_APP);
 		if (err)
-			goto nla_put_failure;
+			return -EMSGSIZE;
 	}
 
 	nla_nest_end(skb, ieee);
 	if (dcbx >= 0) {
 		err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
 		if (err)
-			goto nla_put_failure;
+			return -EMSGSIZE;
 	}
 
 	return 0;
-
-nla_put_failure:
-	return err;
 }
 
 static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
@@ -1340,13 +1137,13 @@ static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
 	struct nlattr *pg = nla_nest_start(skb, i);
 
 	if (!pg)
-		goto nla_put_failure;
+		return -EMSGSIZE;
 
 	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
 		struct nlattr *tc_nest = nla_nest_start(skb, i);
 
 		if (!tc_nest)
-			goto nla_put_failure;
+			return -EMSGSIZE;
 
 		pgid = DCB_ATTR_VALUE_UNDEFINED;
 		prio = DCB_ATTR_VALUE_UNDEFINED;
@@ -1364,7 +1161,7 @@ static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
 		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map) ||
 		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio) ||
 		    nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct))
-			goto nla_put_failure;
+			return -EMSGSIZE;
 		nla_nest_end(skb, tc_nest);
 	}
 
@@ -1378,13 +1175,10 @@ static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
 			ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0,
 					   &tc_pct);
 		if (nla_put_u8(skb, i, tc_pct))
-			goto nla_put_failure;
+			return -EMSGSIZE;
 	}
 	nla_nest_end(skb, pg);
 	return 0;
-
-nla_put_failure:
-	return -EMSGSIZE;
 }
 
 static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
@@ -1531,27 +1325,16 @@ static int dcbnl_notify(struct net_device *dev, int event, int cmd,
 	struct net *net = dev_net(dev);
 	struct sk_buff *skb;
 	struct nlmsghdr *nlh;
-	struct dcbmsg *dcb;
 	const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
 	int err;
 
 	if (!ops)
 		return -EOPNOTSUPP;
 
-	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	skb = dcbnl_newmsg(event, cmd, pid, seq, 0, &nlh);
 	if (!skb)
 		return -ENOBUFS;
 
-	nlh = nlmsg_put(skb, pid, 0, event, sizeof(*dcb), 0);
-	if (nlh == NULL) {
-		nlmsg_free(skb);
-		return -EMSGSIZE;
-	}
-
-	dcb = NLMSG_DATA(nlh);
-	dcb->dcb_family = AF_UNSPEC;
-	dcb->cmd = cmd;
-
 	if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE)
 		err = dcbnl_ieee_fill(skb, dev);
 	else
@@ -1559,8 +1342,7 @@ static int dcbnl_notify(struct net_device *dev, int event, int cmd,
 
 	if (err < 0) {
 		/* Report error to broadcast listeners */
-		nlmsg_cancel(skb, nlh);
-		kfree_skb(skb);
+		nlmsg_free(skb);
 		rtnl_set_sk_err(net, RTNLGRP_DCB, err);
 	} else {
 		/* End nlmsg and notify broadcast listeners */
@@ -1590,15 +1372,15 @@ EXPORT_SYMBOL(dcbnl_cee_notify);
  * No attempt is made to reconcile the case where only part of the
  * cmd can be completed.
  */
-static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
-			  u32 pid, u32 seq, u16 flags)
+static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh,
+			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
 	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
-	int err = -EOPNOTSUPP;
+	int err;
 
 	if (!ops)
-		return err;
+		return -EOPNOTSUPP;
 
 	if (!tb[DCB_ATTR_IEEE])
 		return -EINVAL;
@@ -1649,58 +1431,28 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
 	}
 
 err:
-	dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
-		    pid, seq, flags);
+	err = nla_put_u8(skb, DCB_ATTR_IEEE, err);
 	dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0);
 	return err;
 }
 
-static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
-			  u32 pid, u32 seq, u16 flags)
+static int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh,
+			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	struct net *net = dev_net(netdev);
-	struct sk_buff *skb;
-	struct nlmsghdr *nlh;
-	struct dcbmsg *dcb;
 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
-	int err;
 
 	if (!ops)
 		return -EOPNOTSUPP;
 
-	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!skb)
-		return -ENOBUFS;
-
-	nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
-	if (nlh == NULL) {
-		nlmsg_free(skb);
-		return -EMSGSIZE;
-	}
-
-	dcb = NLMSG_DATA(nlh);
-	dcb->dcb_family = AF_UNSPEC;
-	dcb->cmd = DCB_CMD_IEEE_GET;
-
-	err = dcbnl_ieee_fill(skb, netdev);
-
-	if (err < 0) {
-		nlmsg_cancel(skb, nlh);
-		kfree_skb(skb);
-	} else {
-		nlmsg_end(skb, nlh);
-		err = rtnl_unicast(skb, net, pid);
-	}
-
-	return err;
+	return dcbnl_ieee_fill(skb, netdev);
 }
 
-static int dcbnl_ieee_del(struct net_device *netdev, struct nlattr **tb,
-			  u32 pid, u32 seq, u16 flags)
+static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh,
+			  u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
 	struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
-	int err = -EOPNOTSUPP;
+	int err;
 
 	if (!ops)
 		return -EOPNOTSUPP;
@@ -1733,32 +1485,26 @@ static int dcbnl_ieee_del(struct net_device *netdev, struct nlattr **tb,
 	}
 
 err:
-	dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_DEL, DCB_ATTR_IEEE,
-		    pid, seq, flags);
+	err = nla_put_u8(skb, DCB_ATTR_IEEE, err);
 	dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0);
 	return err;
 }
 
 
 /* DCBX configuration */
-static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb,
-			 u32 pid, u32 seq, u16 flags)
+static int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh,
+			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	int ret;
-
 	if (!netdev->dcbnl_ops->getdcbx)
 		return -EOPNOTSUPP;
 
-	ret = dcbnl_reply(netdev->dcbnl_ops->getdcbx(netdev), RTM_GETDCB,
-			  DCB_CMD_GDCBX, DCB_ATTR_DCBX, pid, seq, flags);
-
-	return ret;
+	return nla_put_u8(skb, DCB_ATTR_DCBX,
+			  netdev->dcbnl_ops->getdcbx(netdev));
 }
 
-static int dcbnl_setdcbx(struct net_device *netdev, struct nlattr **tb,
-			 u32 pid, u32 seq, u16 flags)
+static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh,
+			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	int ret;
 	u8 value;
 
 	if (!netdev->dcbnl_ops->setdcbx)
@@ -1769,19 +1515,13 @@ static int dcbnl_setdcbx(struct net_device *netdev, struct nlattr **tb,
 
 	value = nla_get_u8(tb[DCB_ATTR_DCBX]);
 
-	ret = dcbnl_reply(netdev->dcbnl_ops->setdcbx(netdev, value),
-			  RTM_SETDCB, DCB_CMD_SDCBX, DCB_ATTR_DCBX,
-			  pid, seq, flags);
-
-	return ret;
+	return nla_put_u8(skb, DCB_ATTR_DCBX,
+			  netdev->dcbnl_ops->setdcbx(netdev, value));
 }
 
-static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb,
-			    u32 pid, u32 seq, u16 flags)
+static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	struct sk_buff *dcbnl_skb;
-	struct nlmsghdr *nlh;
-	struct dcbmsg *dcb;
 	struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest;
 	u8 value;
 	int ret, i;
@@ -1796,25 +1536,11 @@ static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb,
 	ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG],
 			       dcbnl_featcfg_nest);
 	if (ret)
-		goto err_out;
-
-	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!dcbnl_skb) {
-		ret = -ENOBUFS;
-		goto err_out;
-	}
-
-	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
-
-	dcb = NLMSG_DATA(nlh);
-	dcb->dcb_family = AF_UNSPEC;
-	dcb->cmd = DCB_CMD_GFEATCFG;
+		return ret;
 
-	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_FEATCFG);
-	if (!nest) {
-		ret = -EMSGSIZE;
-		goto nla_put_failure;
-	}
+	nest = nla_nest_start(skb, DCB_ATTR_FEATCFG);
+	if (!nest)
+		return -EMSGSIZE;
 
 	if (data[DCB_FEATCFG_ATTR_ALL])
 		getall = 1;
@@ -1825,28 +1551,21 @@ static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb,
 
 		ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value);
 		if (!ret)
-			ret = nla_put_u8(dcbnl_skb, i, value);
+			ret = nla_put_u8(skb, i, value);
 
 		if (ret) {
-			nla_nest_cancel(dcbnl_skb, nest);
+			nla_nest_cancel(skb, nest);
 			goto nla_put_failure;
 		}
 	}
-	nla_nest_end(dcbnl_skb, nest);
+	nla_nest_end(skb, nest);
 
-	nlmsg_end(dcbnl_skb, nlh);
-
-	return rtnl_unicast(dcbnl_skb, &init_net, pid);
 nla_put_failure:
-	nlmsg_cancel(dcbnl_skb, nlh);
-nlmsg_failure:
-	kfree_skb(dcbnl_skb);
-err_out:
 	return ret;
 }
 
-static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb,
-			    u32 pid, u32 seq, u16 flags)
+static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh,
+			    u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
 	struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1];
 	int ret, i;
@@ -1876,60 +1595,73 @@ static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb,
 			goto err;
 	}
 err:
-	dcbnl_reply(ret, RTM_SETDCB, DCB_CMD_SFEATCFG, DCB_ATTR_FEATCFG,
-		    pid, seq, flags);
+	ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret);
 
 	return ret;
 }
 
 /* Handle CEE DCBX GET commands. */
-static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,
-			 u32 pid, u32 seq, u16 flags)
+static int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh,
+			 u32 seq, struct nlattr **tb, struct sk_buff *skb)
 {
-	struct net *net = dev_net(netdev);
-	struct sk_buff *skb;
-	struct nlmsghdr *nlh;
-	struct dcbmsg *dcb;
 	const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
-	int err;
 
 	if (!ops)
 		return -EOPNOTSUPP;
 
-	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!skb)
-		return -ENOBUFS;
-
-	nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
-	if (nlh == NULL) {
-		nlmsg_free(skb);
-		return -EMSGSIZE;
-	}
+	return dcbnl_cee_fill(skb, netdev);
+}
 
-	dcb = NLMSG_DATA(nlh);
-	dcb->dcb_family = AF_UNSPEC;
-	dcb->cmd = DCB_CMD_CEE_GET;
+struct reply_func {
+	/* reply netlink message type */
+	int	type;
 
-	err = dcbnl_cee_fill(skb, netdev);
+	/* function to fill message contents */
+	int   (*cb)(struct net_device *, struct nlmsghdr *, u32,
+		    struct nlattr **, struct sk_buff *);
+};
 
-	if (err < 0) {
-		nlmsg_cancel(skb, nlh);
-		nlmsg_free(skb);
-	} else {
-		nlmsg_end(skb, nlh);
-		err = rtnl_unicast(skb, net, pid);
-	}
-	return err;
-}
+static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = {
+	[DCB_CMD_GSTATE]	= { RTM_GETDCB, dcbnl_getstate },
+	[DCB_CMD_SSTATE]	= { RTM_SETDCB, dcbnl_setstate },
+	[DCB_CMD_PFC_GCFG]	= { RTM_GETDCB, dcbnl_getpfccfg },
+	[DCB_CMD_PFC_SCFG]	= { RTM_SETDCB, dcbnl_setpfccfg },
+	[DCB_CMD_GPERM_HWADDR]	= { RTM_GETDCB, dcbnl_getperm_hwaddr },
+	[DCB_CMD_GCAP]		= { RTM_GETDCB, dcbnl_getcap },
+	[DCB_CMD_GNUMTCS]	= { RTM_GETDCB, dcbnl_getnumtcs },
+	[DCB_CMD_SNUMTCS]	= { RTM_SETDCB, dcbnl_setnumtcs },
+	[DCB_CMD_PFC_GSTATE]	= { RTM_GETDCB, dcbnl_getpfcstate },
+	[DCB_CMD_PFC_SSTATE]	= { RTM_SETDCB, dcbnl_setpfcstate },
+	[DCB_CMD_GAPP]		= { RTM_GETDCB, dcbnl_getapp },
+	[DCB_CMD_SAPP]		= { RTM_SETDCB, dcbnl_setapp },
+	[DCB_CMD_PGTX_GCFG]	= { RTM_GETDCB, dcbnl_pgtx_getcfg },
+	[DCB_CMD_PGTX_SCFG]	= { RTM_SETDCB, dcbnl_pgtx_setcfg },
+	[DCB_CMD_PGRX_GCFG]	= { RTM_GETDCB, dcbnl_pgrx_getcfg },
+	[DCB_CMD_PGRX_SCFG]	= { RTM_SETDCB, dcbnl_pgrx_setcfg },
+	[DCB_CMD_SET_ALL]	= { RTM_SETDCB, dcbnl_setall },
+	[DCB_CMD_BCN_GCFG]	= { RTM_GETDCB, dcbnl_bcn_getcfg },
+	[DCB_CMD_BCN_SCFG]	= { RTM_SETDCB, dcbnl_bcn_setcfg },
+	[DCB_CMD_IEEE_GET]	= { RTM_GETDCB, dcbnl_ieee_get },
+	[DCB_CMD_IEEE_SET]	= { RTM_SETDCB, dcbnl_ieee_set },
+	[DCB_CMD_IEEE_DEL]	= { RTM_SETDCB, dcbnl_ieee_del },
+	[DCB_CMD_GDCBX]		= { RTM_GETDCB, dcbnl_getdcbx },
+	[DCB_CMD_SDCBX]		= { RTM_SETDCB, dcbnl_setdcbx },
+	[DCB_CMD_GFEATCFG]	= { RTM_GETDCB, dcbnl_getfeatcfg },
+	[DCB_CMD_SFEATCFG]	= { RTM_SETDCB, dcbnl_setfeatcfg },
+	[DCB_CMD_CEE_GET]	= { RTM_GETDCB, dcbnl_cee_get },
+};
 
 static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct net *net = sock_net(skb->sk);
 	struct net_device *netdev;
-	struct dcbmsg  *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
+	struct dcbmsg *dcb = nlmsg_data(nlh);
 	struct nlattr *tb[DCB_ATTR_MAX + 1];
 	u32 pid = skb ? NETLINK_CB(skb).pid : 0;
 	int ret = -EINVAL;
+	struct sk_buff *reply_skb;
+	struct nlmsghdr *reply_nlh = NULL;
+	const struct reply_func *fn;
 
 	if (!net_eq(net, &init_net))
 		return -EINVAL;
@@ -1939,136 +1671,78 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 	if (ret < 0)
 		return ret;
 
+	if (dcb->cmd > DCB_CMD_MAX)
+		return -EINVAL;
+
+	/* check if a reply function has been defined for the command */
+	fn = &reply_funcs[dcb->cmd];
+	if (!fn->cb)
+		return -EOPNOTSUPP;
+
 	if (!tb[DCB_ATTR_IFNAME])
 		return -EINVAL;
 
 	netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
 	if (!netdev)
-		return -EINVAL;
+		return -ENODEV;
 
-	if (!netdev->dcbnl_ops)
-		goto errout;
-
-	switch (dcb->cmd) {
-	case DCB_CMD_GSTATE:
-		ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
-		                     nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_PFC_GCFG:
-		ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
-		                      nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_GPERM_HWADDR:
-		ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
-		                           nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_PGTX_GCFG:
-		ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
-		                        nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_PGRX_GCFG:
-		ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
-		                        nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_BCN_GCFG:
-		ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
-		                       nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_SSTATE:
-		ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
-		                     nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_PFC_SCFG:
-		ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
-		                      nlh->nlmsg_flags);
+	if (!netdev->dcbnl_ops) {
+		ret = -EOPNOTSUPP;
 		goto out;
+	}
 
-	case DCB_CMD_SET_ALL:
-		ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
-		                   nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_PGTX_SCFG:
-		ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
-		                        nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_PGRX_SCFG:
-		ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
-		                        nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_GCAP:
-		ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
-		                   nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_GNUMTCS:
-		ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
-		                      nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_SNUMTCS:
-		ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
-		                      nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_PFC_GSTATE:
-		ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
-		                        nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_PFC_SSTATE:
-		ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
-		                        nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_BCN_SCFG:
-		ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
-		                       nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_GAPP:
-		ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq,
-		                   nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_SAPP:
-		ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq,
-		                   nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_IEEE_SET:
-		ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq,
-				     nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_IEEE_GET:
-		ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq,
-				     nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_IEEE_DEL:
-		ret = dcbnl_ieee_del(netdev, tb, pid, nlh->nlmsg_seq,
-				     nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_GDCBX:
-		ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq,
-				    nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_SDCBX:
-		ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq,
-				    nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_GFEATCFG:
-		ret = dcbnl_getfeatcfg(netdev, tb, pid, nlh->nlmsg_seq,
-				       nlh->nlmsg_flags);
-		goto out;
-	case DCB_CMD_SFEATCFG:
-		ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq,
-				       nlh->nlmsg_flags);
+	reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, pid, nlh->nlmsg_seq,
+				 nlh->nlmsg_flags, &reply_nlh);
+	if (!reply_skb) {
+		ret = -ENOBUFS;
 		goto out;
-	case DCB_CMD_CEE_GET:
-		ret = dcbnl_cee_get(netdev, tb, pid, nlh->nlmsg_seq,
-				    nlh->nlmsg_flags);
+	}
+
+	ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb);
+	if (ret < 0) {
+		nlmsg_free(reply_skb);
 		goto out;
-	default:
-		goto errout;
 	}
-errout:
-	ret = -EINVAL;
+
+	nlmsg_end(reply_skb, reply_nlh);
+
+	ret = rtnl_unicast(reply_skb, &init_net, pid);
 out:
 	dev_put(netdev);
 	return ret;
 }
 
+static struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app,
+					   int ifindex, int prio)
+{
+	struct dcb_app_type *itr;
+
+	list_for_each_entry(itr, &dcb_app_list, list) {
+		if (itr->app.selector == app->selector &&
+		    itr->app.protocol == app->protocol &&
+		    itr->ifindex == ifindex &&
+		    (!prio || itr->app.priority == prio))
+			return itr;
+	}
+
+	return NULL;
+}
+
+static int dcb_app_add(const struct dcb_app *app, int ifindex)
+{
+	struct dcb_app_type *entry;
+
+	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+	if (!entry)
+		return -ENOMEM;
+
+	memcpy(&entry->app, app, sizeof(*app));
+	entry->ifindex = ifindex;
+	list_add(&entry->list, &dcb_app_list);
+
+	return 0;
+}
+
 /**
  * dcb_getapp - retrieve the DCBX application user priority
  *
@@ -2082,14 +1756,8 @@ u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
 	u8 prio = 0;
 
 	spin_lock(&dcb_lock);
-	list_for_each_entry(itr, &dcb_app_list, list) {
-		if (itr->app.selector == app->selector &&
-		    itr->app.protocol == app->protocol &&
-		    itr->ifindex == dev->ifindex) {
-			prio = itr->app.priority;
-			break;
-		}
-	}
+	if ((itr = dcb_app_lookup(app, dev->ifindex, 0)))
+		prio = itr->app.priority;
 	spin_unlock(&dcb_lock);
 
 	return prio;
@@ -2107,6 +1775,7 @@ int dcb_setapp(struct net_device *dev, struct dcb_app *new)
 {
 	struct dcb_app_type *itr;
 	struct dcb_app_type event;
+	int err = 0;
 
 	event.ifindex = dev->ifindex;
 	memcpy(&event.app, new, sizeof(event.app));
@@ -2115,36 +1784,23 @@ int dcb_setapp(struct net_device *dev, struct dcb_app *new)
 
 	spin_lock(&dcb_lock);
 	/* Search for existing match and replace */
-	list_for_each_entry(itr, &dcb_app_list, list) {
-		if (itr->app.selector == new->selector &&
-		    itr->app.protocol == new->protocol &&
-		    itr->ifindex == dev->ifindex) {
-			if (new->priority)
-				itr->app.priority = new->priority;
-			else {
-				list_del(&itr->list);
-				kfree(itr);
-			}
-			goto out;
+	if ((itr = dcb_app_lookup(new, dev->ifindex, 0))) {
+		if (new->priority)
+			itr->app.priority = new->priority;
+		else {
+			list_del(&itr->list);
+			kfree(itr);
 		}
+		goto out;
 	}
 	/* App type does not exist add new application type */
-	if (new->priority) {
-		struct dcb_app_type *entry;
-		entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC);
-		if (!entry) {
-			spin_unlock(&dcb_lock);
-			return -ENOMEM;
-		}
-
-		memcpy(&entry->app, new, sizeof(*new));
-		entry->ifindex = dev->ifindex;
-		list_add(&entry->list, &dcb_app_list);
-	}
+	if (new->priority)
+		err = dcb_app_add(new, dev->ifindex);
 out:
 	spin_unlock(&dcb_lock);
-	call_dcbevent_notifiers(DCB_APP_EVENT, &event);
-	return 0;
+	if (!err)
+		call_dcbevent_notifiers(DCB_APP_EVENT, &event);
+	return err;
 }
 EXPORT_SYMBOL(dcb_setapp);
 
@@ -2161,13 +1817,8 @@ u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app)
 	u8 prio = 0;
 
 	spin_lock(&dcb_lock);
-	list_for_each_entry(itr, &dcb_app_list, list) {
-		if (itr->app.selector == app->selector &&
-		    itr->app.protocol == app->protocol &&
-		    itr->ifindex == dev->ifindex) {
-			prio |= 1 << itr->app.priority;
-		}
-	}
+	if ((itr = dcb_app_lookup(app, dev->ifindex, 0)))
+		prio |= 1 << itr->app.priority;
 	spin_unlock(&dcb_lock);
 
 	return prio;
@@ -2183,7 +1834,6 @@ EXPORT_SYMBOL(dcb_ieee_getapp_mask);
  */
 int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
 {
-	struct dcb_app_type *itr, *entry;
 	struct dcb_app_type event;
 	int err = 0;
 
@@ -2194,26 +1844,12 @@ int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
 
 	spin_lock(&dcb_lock);
 	/* Search for existing match and abort if found */
-	list_for_each_entry(itr, &dcb_app_list, list) {
-		if (itr->app.selector == new->selector &&
-		    itr->app.protocol == new->protocol &&
-		    itr->app.priority == new->priority &&
-		    itr->ifindex == dev->ifindex) {
-			err = -EEXIST;
-			goto out;
-		}
-	}
-
-	/* App entry does not exist add new entry */
-	entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC);
-	if (!entry) {
-		err = -ENOMEM;
+	if (dcb_app_lookup(new, dev->ifindex, new->priority)) {
+		err = -EEXIST;
 		goto out;
 	}
 
-	memcpy(&entry->app, new, sizeof(*new));
-	entry->ifindex = dev->ifindex;
-	list_add(&entry->list, &dcb_app_list);
+	err = dcb_app_add(new, dev->ifindex);
 out:
 	spin_unlock(&dcb_lock);
 	if (!err)
@@ -2240,19 +1876,12 @@ int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
 
 	spin_lock(&dcb_lock);
 	/* Search for existing match and remove it. */
-	list_for_each_entry(itr, &dcb_app_list, list) {
-		if (itr->app.selector == del->selector &&
-		    itr->app.protocol == del->protocol &&
-		    itr->app.priority == del->priority &&
-		    itr->ifindex == dev->ifindex) {
-			list_del(&itr->list);
-			kfree(itr);
-			err = 0;
-			goto out;
-		}
+	if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) {
+		list_del(&itr->list);
+		kfree(itr);
+		err = 0;
 	}
 
-out:
 	spin_unlock(&dcb_lock);
 	if (!err)
 		call_dcbevent_notifiers(DCB_APP_EVENT, &event);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 07f5579..3eb76b5 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -504,7 +504,7 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
 	struct dst_entry *dst;
 	struct flowi4 fl4;
 
-	dst = inet_csk_route_req(sk, &fl4, req);
+	dst = inet_csk_route_req(sk, &fl4, req, false);
 	if (dst == NULL)
 		goto out;
 
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index fa9512d..9991be0 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -165,6 +165,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 		} else
 			dst_hold(dst);
 
+		dst->ops->update_pmtu(dst, ntohl(info));
+
 		if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
 			dccp_sync_mss(sk, dst_mtu(dst));
 		} /* else let the usual retransmit timer handle it */
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index ac90f658..8e9a35b 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -240,7 +240,7 @@ static int dn_long_output(struct neighbour *neigh, struct sk_buff *skb)
 			kfree_skb(skb);
 			return -ENOBUFS;
 		}
-		kfree_skb(skb);
+		consume_skb(skb);
 		skb = skb2;
 		net_info_ratelimited("dn_long_output: Increasing headroom\n");
 	}
@@ -283,7 +283,7 @@ static int dn_short_output(struct neighbour *neigh, struct sk_buff *skb)
 			kfree_skb(skb);
 			return -ENOBUFS;
 		}
-		kfree_skb(skb);
+		consume_skb(skb);
 		skb = skb2;
 		net_info_ratelimited("dn_short_output: Increasing headroom\n");
 	}
@@ -322,7 +322,7 @@ static int dn_phase3_output(struct neighbour *neigh, struct sk_buff *skb)
 			kfree_skb(skb);
 			return -ENOBUFS;
 		}
-		kfree_skb(skb);
+		consume_skb(skb);
 		skb = skb2;
 		net_info_ratelimited("dn_phase3_output: Increasing headroom\n");
 	}
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index 564a6ad..8a96047c 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -322,7 +322,7 @@ static __le16 *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, unsigned c
 	/* Set "cross subchannel" bit in ackcrs */
 	ackcrs |= 0x2000;
 
-	ptr = (__le16 *)dn_mk_common_header(scp, skb, msgflag, hlen);
+	ptr = dn_mk_common_header(scp, skb, msgflag, hlen);
 
 	*ptr++ = cpu_to_le16(acknum);
 	*ptr++ = cpu_to_le16(ackcrs);
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index 44b8909..e6f8862 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -117,7 +117,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
 
 static struct nf_hook_ops dnrmg_ops __read_mostly = {
 	.hook		= dnrmg_hook,
-	.pf		= PF_DECnet,
+	.pf		= NFPROTO_DECNET,
 	.hooknum	= NF_DN_ROUTE,
 	.priority	= NF_DN_PRI_DNRTMSG,
 };
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 32eb417..ad0c226 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -240,8 +240,7 @@ lowpan_uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr,
 		lowpan_uip_ds6_set_addr_iid(ipaddr, lladdr);
 	}
 
-	pr_debug("(%s): uncompressing %d + %d => ", __func__, prefcount,
-								postcount);
+	pr_debug("uncompressing %d + %d => ", prefcount, postcount);
 	lowpan_raw_dump_inline(NULL, NULL, ipaddr->s6_addr, 16);
 
 	return 0;
@@ -252,13 +251,11 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
 {
 	struct udphdr *uh = udp_hdr(skb);
 
-	pr_debug("(%s): UDP header compression\n", __func__);
-
 	if (((uh->source & LOWPAN_NHC_UDP_4BIT_MASK) ==
 				LOWPAN_NHC_UDP_4BIT_PORT) &&
 	    ((uh->dest & LOWPAN_NHC_UDP_4BIT_MASK) ==
 				LOWPAN_NHC_UDP_4BIT_PORT)) {
-		pr_debug("(%s): both ports compression to 4 bits\n", __func__);
+		pr_debug("UDP header: both ports compression to 4 bits\n");
 		**hc06_ptr = LOWPAN_NHC_UDP_CS_P_11;
 		**(hc06_ptr + 1) = /* subtraction is faster */
 		   (u8)((uh->dest - LOWPAN_NHC_UDP_4BIT_PORT) +
@@ -266,20 +263,20 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
 		*hc06_ptr += 2;
 	} else if ((uh->dest & LOWPAN_NHC_UDP_8BIT_MASK) ==
 			LOWPAN_NHC_UDP_8BIT_PORT) {
-		pr_debug("(%s): remove 8 bits of dest\n", __func__);
+		pr_debug("UDP header: remove 8 bits of dest\n");
 		**hc06_ptr = LOWPAN_NHC_UDP_CS_P_01;
 		memcpy(*hc06_ptr + 1, &uh->source, 2);
 		**(hc06_ptr + 3) = (u8)(uh->dest - LOWPAN_NHC_UDP_8BIT_PORT);
 		*hc06_ptr += 4;
 	} else if ((uh->source & LOWPAN_NHC_UDP_8BIT_MASK) ==
 			LOWPAN_NHC_UDP_8BIT_PORT) {
-		pr_debug("(%s): remove 8 bits of source\n", __func__);
+		pr_debug("UDP header: remove 8 bits of source\n");
 		**hc06_ptr = LOWPAN_NHC_UDP_CS_P_10;
 		memcpy(*hc06_ptr + 1, &uh->dest, 2);
 		**(hc06_ptr + 3) = (u8)(uh->source - LOWPAN_NHC_UDP_8BIT_PORT);
 		*hc06_ptr += 4;
 	} else {
-		pr_debug("(%s): can't compress header\n", __func__);
+		pr_debug("UDP header: can't compress\n");
 		**hc06_ptr = LOWPAN_NHC_UDP_CS_P_00;
 		memcpy(*hc06_ptr + 1, &uh->source, 2);
 		memcpy(*hc06_ptr + 3, &uh->dest, 2);
@@ -291,25 +288,26 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
 	*hc06_ptr += 2;
 }
 
-static u8 lowpan_fetch_skb_u8(struct sk_buff *skb)
+static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
 {
-	u8 ret;
+	if (unlikely(!pskb_may_pull(skb, 1)))
+		return -EINVAL;
 
-	ret = skb->data[0];
+	*val = skb->data[0];
 	skb_pull(skb, 1);
 
-	return ret;
+	return 0;
 }
 
-static u16 lowpan_fetch_skb_u16(struct sk_buff *skb)
+static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
 {
-	u16 ret;
-
-	BUG_ON(!pskb_may_pull(skb, 2));
+	if (unlikely(!pskb_may_pull(skb, 2)))
+		return -EINVAL;
 
-	ret = skb->data[0] | (skb->data[1] << 8);
+	*val = skb->data[0] | (skb->data[1] << 8);
 	skb_pull(skb, 2);
-	return ret;
+
+	return 0;
 }
 
 static int
@@ -318,10 +316,11 @@ lowpan_uncompress_udp_header(struct sk_buff *skb)
 	struct udphdr *uh = udp_hdr(skb);
 	u8 tmp;
 
-	tmp = lowpan_fetch_skb_u8(skb);
+	if (lowpan_fetch_skb_u8(skb, &tmp))
+		goto err;
 
 	if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
-		pr_debug("(%s): UDP header uncompression\n", __func__);
+		pr_debug("UDP header uncompression\n");
 		switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
 		case LOWPAN_NHC_UDP_CS_P_00:
 			memcpy(&uh->source, &skb->data[0], 2);
@@ -347,19 +346,19 @@ lowpan_uncompress_udp_header(struct sk_buff *skb)
 			skb_pull(skb, 1);
 			break;
 		default:
-			pr_debug("(%s) ERROR: unknown UDP format\n", __func__);
+			pr_debug("ERROR: unknown UDP format\n");
 			goto err;
 			break;
 		}
 
-		pr_debug("(%s): uncompressed UDP ports: src = %d, dst = %d\n",
-					__func__, uh->source, uh->dest);
+		pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
+			 uh->source, uh->dest);
 
 		/* copy checksum */
 		memcpy(&uh->check, &skb->data[0], 2);
 		skb_pull(skb, 2);
 	} else {
-		pr_debug("(%s): ERROR: unsupported NH format\n", __func__);
+		pr_debug("ERROR: unsupported NH format\n");
 		goto err;
 	}
 
@@ -392,10 +391,9 @@ static int lowpan_header_create(struct sk_buff *skb,
 	hdr = ipv6_hdr(skb);
 	hc06_ptr = head + 2;
 
-	pr_debug("(%s): IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n"
-		 "\tnexthdr = 0x%02x\n\thop_lim = %d\n", __func__,
-		hdr->version, ntohs(hdr->payload_len), hdr->nexthdr,
-		hdr->hop_limit);
+	pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n"
+		 "\tnexthdr = 0x%02x\n\thop_lim = %d\n", hdr->version,
+		 ntohs(hdr->payload_len), hdr->nexthdr, hdr->hop_limit);
 
 	lowpan_raw_dump_table(__func__, "raw skb network header dump",
 		skb_network_header(skb), sizeof(struct ipv6hdr));
@@ -490,28 +488,28 @@ static int lowpan_header_create(struct sk_buff *skb,
 		break;
 	default:
 		*hc06_ptr = hdr->hop_limit;
+		hc06_ptr += 1;
 		break;
 	}
 
 	/* source address compression */
 	if (is_addr_unspecified(&hdr->saddr)) {
-		pr_debug("(%s): source address is unspecified, setting SAC\n",
-								__func__);
+		pr_debug("source address is unspecified, setting SAC\n");
 		iphc1 |= LOWPAN_IPHC_SAC;
 	/* TODO: context lookup */
 	} else if (is_addr_link_local(&hdr->saddr)) {
-		pr_debug("(%s): source address is link-local\n", __func__);
+		pr_debug("source address is link-local\n");
 		iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
 				LOWPAN_IPHC_SAM_BIT, &hdr->saddr, saddr);
 	} else {
-		pr_debug("(%s): send the full source address\n", __func__);
+		pr_debug("send the full source address\n");
 		memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16);
 		hc06_ptr += 16;
 	}
 
 	/* destination address compression */
 	if (is_addr_mcast(&hdr->daddr)) {
-		pr_debug("(%s): destination address is multicast", __func__);
+		pr_debug("destination address is multicast: ");
 		iphc1 |= LOWPAN_IPHC_M;
 		if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
 			pr_debug("compressed to 1 octet\n");
@@ -540,14 +538,13 @@ static int lowpan_header_create(struct sk_buff *skb,
 			hc06_ptr += 16;
 		}
 	} else {
-		pr_debug("(%s): destination address is unicast: ", __func__);
 		/* TODO: context lookup */
 		if (is_addr_link_local(&hdr->daddr)) {
-			pr_debug("destination address is link-local\n");
+			pr_debug("dest address is unicast and link-local\n");
 			iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
 				LOWPAN_IPHC_DAM_BIT, &hdr->daddr, daddr);
 		} else {
-			pr_debug("using full address\n");
+			pr_debug("dest address is unicast: using full one\n");
 			memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16);
 			hc06_ptr += 16;
 		}
@@ -639,8 +636,7 @@ static void lowpan_fragment_timer_expired(unsigned long entry_addr)
 {
 	struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr;
 
-	pr_debug("%s: timer expired for frame with tag %d\n", __func__,
-								entry->tag);
+	pr_debug("timer expired for frame with tag %d\n", entry->tag);
 
 	spin_lock(&flist_lock);
 	list_del(&entry->list);
@@ -710,7 +706,9 @@ lowpan_process_data(struct sk_buff *skb)
 	/* at least two bytes will be used for the encoding */
 	if (skb->len < 2)
 		goto drop;
-	iphc0 = lowpan_fetch_skb_u8(skb);
+
+	if (lowpan_fetch_skb_u8(skb, &iphc0))
+		goto drop;
 
 	/* fragments assembling */
 	switch (iphc0 & LOWPAN_DISPATCH_MASK) {
@@ -722,8 +720,9 @@ lowpan_process_data(struct sk_buff *skb)
 		u16 tag;
 		bool found = false;
 
-		len = lowpan_fetch_skb_u8(skb); /* frame length */
-		tag = lowpan_fetch_skb_u16(skb);
+		if (lowpan_fetch_skb_u8(skb, &len) || /* frame length */
+		    lowpan_fetch_skb_u16(skb, &tag))  /* fragment tag */
+			goto drop;
 
 		/*
 		 * check if frame assembling with the same tag is
@@ -747,7 +746,8 @@ lowpan_process_data(struct sk_buff *skb)
 		if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1)
 			goto unlock_and_drop;
 
-		offset = lowpan_fetch_skb_u8(skb); /* fetch offset */
+		if (lowpan_fetch_skb_u8(skb, &offset)) /* fetch offset */
+			goto unlock_and_drop;
 
 		/* if payload fits buffer, copy it */
 		if (likely((offset * 8 + skb->len) <= frame->length))
@@ -769,7 +769,10 @@ lowpan_process_data(struct sk_buff *skb)
 			dev_kfree_skb(skb);
 			skb = frame->skb;
 			kfree(frame);
-			iphc0 = lowpan_fetch_skb_u8(skb);
+
+			if (lowpan_fetch_skb_u8(skb, &iphc0))
+				goto unlock_and_drop;
+
 			break;
 		}
 		spin_unlock(&flist_lock);
@@ -780,20 +783,19 @@ lowpan_process_data(struct sk_buff *skb)
 		break;
 	}
 
-	iphc1 = lowpan_fetch_skb_u8(skb);
+	if (lowpan_fetch_skb_u8(skb, &iphc1))
+		goto drop;
 
 	_saddr = mac_cb(skb)->sa.hwaddr;
 	_daddr = mac_cb(skb)->da.hwaddr;
 
-	pr_debug("(%s): iphc0 = %02x, iphc1 = %02x\n", __func__, iphc0, iphc1);
+	pr_debug("iphc0 = %02x, iphc1 = %02x\n", iphc0, iphc1);
 
 	/* another if the CID flag is set */
 	if (iphc1 & LOWPAN_IPHC_CID) {
-		pr_debug("(%s): CID flag is set, increase header with one\n",
-								__func__);
-		if (!skb->len)
+		pr_debug("CID flag is set, increase header with one\n");
+		if (lowpan_fetch_skb_u8(skb, &num_context))
 			goto drop;
-		num_context = lowpan_fetch_skb_u8(skb);
 	}
 
 	hdr.version = 6;
@@ -805,9 +807,9 @@ lowpan_process_data(struct sk_buff *skb)
 	 * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
 	 */
 	case 0: /* 00b */
-		if (!skb->len)
+		if (lowpan_fetch_skb_u8(skb, &tmp))
 			goto drop;
-		tmp = lowpan_fetch_skb_u8(skb);
+
 		memcpy(&hdr.flow_lbl, &skb->data[0], 3);
 		skb_pull(skb, 3);
 		hdr.priority = ((tmp >> 2) & 0x0f);
@@ -819,9 +821,9 @@ lowpan_process_data(struct sk_buff *skb)
 	 * ECN + DSCP (1 byte), Flow Label is elided
 	 */
 	case 1: /* 10b */
-		if (!skb->len)
+		if (lowpan_fetch_skb_u8(skb, &tmp))
 			goto drop;
-		tmp = lowpan_fetch_skb_u8(skb);
+
 		hdr.priority = ((tmp >> 2) & 0x0f);
 		hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
 		hdr.flow_lbl[1] = 0;
@@ -832,9 +834,9 @@ lowpan_process_data(struct sk_buff *skb)
 	 * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
 	 */
 	case 2: /* 01b */
-		if (!skb->len)
+		if (lowpan_fetch_skb_u8(skb, &tmp))
 			goto drop;
-		tmp = lowpan_fetch_skb_u8(skb);
+
 		hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
 		memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
 		skb_pull(skb, 2);
@@ -853,27 +855,26 @@ lowpan_process_data(struct sk_buff *skb)
 	/* Next Header */
 	if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
 		/* Next header is carried inline */
-		if (!skb->len)
+		if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
 			goto drop;
-		hdr.nexthdr = lowpan_fetch_skb_u8(skb);
-		pr_debug("(%s): NH flag is set, next header is carried "
-			 "inline: %02x\n", __func__, hdr.nexthdr);
+
+		pr_debug("NH flag is set, next header carried inline: %02x\n",
+			 hdr.nexthdr);
 	}
 
 	/* Hop Limit */
 	if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
 		hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
 	else {
-		if (!skb->len)
+		if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
 			goto drop;
-		hdr.hop_limit = lowpan_fetch_skb_u8(skb);
 	}
 
 	/* Extract SAM to the tmp variable */
 	tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
 
 	/* Source address uncompression */
-	pr_debug("(%s): source address stateless compression\n", __func__);
+	pr_debug("source address stateless compression\n");
 	err = lowpan_uncompress_addr(skb, &hdr.saddr, lowpan_llprefix,
 				lowpan_unc_llconf[tmp], skb->data);
 	if (err)
@@ -885,19 +886,15 @@ lowpan_process_data(struct sk_buff *skb)
 	/* check for Multicast Compression */
 	if (iphc1 & LOWPAN_IPHC_M) {
 		if (iphc1 & LOWPAN_IPHC_DAC) {
-			pr_debug("(%s): destination address context-based "
-				 "multicast compression\n", __func__);
+			pr_debug("dest: context-based mcast compression\n");
 			/* TODO: implement this */
 		} else {
 			u8 prefix[] = {0xff, 0x02};
 
-			pr_debug("(%s): destination address non-context-based"
-				 " multicast compression\n", __func__);
+			pr_debug("dest: non context-based mcast compression\n");
 			if (0 < tmp && tmp < 3) {
-				if (!skb->len)
+				if (lowpan_fetch_skb_u8(skb, &prefix[1]))
 					goto drop;
-				else
-					prefix[1] = lowpan_fetch_skb_u8(skb);
 			}
 
 			err = lowpan_uncompress_addr(skb, &hdr.daddr, prefix,
@@ -906,8 +903,7 @@ lowpan_process_data(struct sk_buff *skb)
 				goto drop;
 		}
 	} else {
-		pr_debug("(%s): destination address stateless compression\n",
-								__func__);
+		pr_debug("dest: stateless compression\n");
 		err = lowpan_uncompress_addr(skb, &hdr.daddr, lowpan_llprefix,
 				lowpan_unc_llconf[tmp], skb->data);
 		if (err)
@@ -922,11 +918,11 @@ lowpan_process_data(struct sk_buff *skb)
 	/* Not fragmented package */
 	hdr.payload_len = htons(skb->len);
 
-	pr_debug("(%s): skb headroom size = %d, data length = %d\n", __func__,
-						skb_headroom(skb), skb->len);
+	pr_debug("skb headroom size = %d, data length = %d\n",
+		 skb_headroom(skb), skb->len);
 
-	pr_debug("(%s): IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n\t"
-		 "nexthdr = 0x%02x\n\thop_lim = %d\n", __func__, hdr.version,
+	pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n\t"
+		 "nexthdr = 0x%02x\n\thop_lim = %d\n", hdr.version,
 		 ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit);
 
 	lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
@@ -1028,11 +1024,11 @@ static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	int err = -1;
 
-	pr_debug("(%s): package xmit\n", __func__);
+	pr_debug("package xmit\n");
 
 	skb->dev = lowpan_dev_info(dev)->real_dev;
 	if (skb->dev == NULL) {
-		pr_debug("(%s) ERROR: no real wpan device found\n", __func__);
+		pr_debug("ERROR: no real wpan device found\n");
 		goto error;
 	}
 
@@ -1041,14 +1037,13 @@ static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
 		goto out;
 	}
 
-	pr_debug("(%s): frame is too big, fragmentation is needed\n",
-								__func__);
+	pr_debug("frame is too big, fragmentation is needed\n");
 	err = lowpan_skb_fragmentation(skb);
 error:
 	dev_kfree_skb(skb);
 out:
 	if (err < 0)
-		pr_debug("(%s): ERROR: xmit failed\n", __func__);
+		pr_debug("ERROR: xmit failed\n");
 
 	return (err < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK);
 }
@@ -1094,8 +1089,6 @@ static struct ieee802154_mlme_ops lowpan_mlme = {
 
 static void lowpan_setup(struct net_device *dev)
 {
-	pr_debug("(%s)\n", __func__);
-
 	dev->addr_len		= IEEE802154_ADDR_LEN;
 	memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
 	dev->type		= ARPHRD_IEEE802154;
@@ -1115,8 +1108,6 @@ static void lowpan_setup(struct net_device *dev)
 
 static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[])
 {
-	pr_debug("(%s)\n", __func__);
-
 	if (tb[IFLA_ADDRESS]) {
 		if (nla_len(tb[IFLA_ADDRESS]) != IEEE802154_ADDR_LEN)
 			return -EINVAL;
@@ -1157,7 +1148,7 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev,
 	struct net_device *real_dev;
 	struct lowpan_dev_record *entry;
 
-	pr_debug("(%s)\n", __func__);
+	pr_debug("adding new link\n");
 
 	if (!tb[IFLA_LINK])
 		return -EINVAL;
@@ -1252,8 +1243,6 @@ static int __init lowpan_init_module(void)
 {
 	int err = 0;
 
-	pr_debug("(%s)\n", __func__);
-
 	err = lowpan_netlink_init();
 	if (err < 0)
 		goto out;
@@ -1265,8 +1254,6 @@ out:
 
 static void __exit lowpan_cleanup_module(void)
 {
-	pr_debug("(%s)\n", __func__);
-
 	lowpan_netlink_fini();
 
 	dev_remove_pack(&lowpan_packet_type);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index c8f7aee..07a02f6 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -157,6 +157,7 @@ void inet_sock_destruct(struct sock *sk)
 
 	kfree(rcu_dereference_protected(inet->inet_opt, 1));
 	dst_release(rcu_dereference_check(sk->sk_dst_cache, 1));
+	dst_release(sk->sk_rx_dst);
 	sk_refcnt_debug_dec(sk);
 }
 EXPORT_SYMBOL(inet_sock_destruct);
@@ -242,20 +243,18 @@ void build_ehash_secret(void)
 }
 EXPORT_SYMBOL(build_ehash_secret);
 
-static inline int inet_netns_ok(struct net *net, int protocol)
+static inline int inet_netns_ok(struct net *net, __u8 protocol)
 {
-	int hash;
 	const struct net_protocol *ipprot;
 
 	if (net_eq(net, &init_net))
 		return 1;
 
-	hash = protocol & (MAX_INET_PROTOS - 1);
-	ipprot = rcu_dereference(inet_protos[hash]);
-
-	if (ipprot == NULL)
+	ipprot = rcu_dereference(inet_protos[protocol]);
+	if (ipprot == NULL) {
 		/* raw IP is OK */
 		return 1;
+	}
 	return ipprot->netns_ok;
 }
 
@@ -553,7 +552,7 @@ int inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr,
 
 	if (!inet_sk(sk)->inet_num && inet_autobind(sk))
 		return -EAGAIN;
-	return sk->sk_prot->connect(sk, (struct sockaddr *)uaddr, addr_len);
+	return sk->sk_prot->connect(sk, uaddr, addr_len);
 }
 EXPORT_SYMBOL(inet_dgram_connect);
 
@@ -1216,8 +1215,8 @@ EXPORT_SYMBOL(inet_sk_rebuild_header);
 
 static int inet_gso_send_check(struct sk_buff *skb)
 {
-	const struct iphdr *iph;
 	const struct net_protocol *ops;
+	const struct iphdr *iph;
 	int proto;
 	int ihl;
 	int err = -EINVAL;
@@ -1236,7 +1235,7 @@ static int inet_gso_send_check(struct sk_buff *skb)
 	__skb_pull(skb, ihl);
 	skb_reset_transport_header(skb);
 	iph = ip_hdr(skb);
-	proto = iph->protocol & (MAX_INET_PROTOS - 1);
+	proto = iph->protocol;
 	err = -EPROTONOSUPPORT;
 
 	rcu_read_lock();
@@ -1253,8 +1252,8 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
 	netdev_features_t features)
 {
 	struct sk_buff *segs = ERR_PTR(-EINVAL);
-	struct iphdr *iph;
 	const struct net_protocol *ops;
+	struct iphdr *iph;
 	int proto;
 	int ihl;
 	int id;
@@ -1286,7 +1285,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
 	skb_reset_transport_header(skb);
 	iph = ip_hdr(skb);
 	id = ntohs(iph->id);
-	proto = iph->protocol & (MAX_INET_PROTOS - 1);
+	proto = iph->protocol;
 	segs = ERR_PTR(-EPROTONOSUPPORT);
 
 	rcu_read_lock();
@@ -1340,7 +1339,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
 			goto out;
 	}
 
-	proto = iph->protocol & (MAX_INET_PROTOS - 1);
+	proto = iph->protocol;
 
 	rcu_read_lock();
 	ops = rcu_dereference(inet_protos[proto]);
@@ -1398,11 +1397,11 @@ out:
 
 static int inet_gro_complete(struct sk_buff *skb)
 {
-	const struct net_protocol *ops;
+	__be16 newlen = htons(skb->len - skb_network_offset(skb));
 	struct iphdr *iph = ip_hdr(skb);
-	int proto = iph->protocol & (MAX_INET_PROTOS - 1);
+	const struct net_protocol *ops;
+	int proto = iph->protocol;
 	int err = -ENOSYS;
-	__be16 newlen = htons(skb->len - skb_network_offset(skb));
 
 	csum_replace2(&iph->check, iph->tot_len, newlen);
 	iph->tot_len = newlen;
@@ -1520,14 +1519,15 @@ static const struct net_protocol igmp_protocol = {
 #endif
 
 static const struct net_protocol tcp_protocol = {
-	.handler =	tcp_v4_rcv,
-	.err_handler =	tcp_v4_err,
-	.gso_send_check = tcp_v4_gso_send_check,
-	.gso_segment =	tcp_tso_segment,
-	.gro_receive =	tcp4_gro_receive,
-	.gro_complete =	tcp4_gro_complete,
-	.no_policy =	1,
-	.netns_ok =	1,
+	.early_demux	=	tcp_v4_early_demux,
+	.handler	=	tcp_v4_rcv,
+	.err_handler	=	tcp_v4_err,
+	.gso_send_check	=	tcp_v4_gso_send_check,
+	.gso_segment	=	tcp_tso_segment,
+	.gro_receive	=	tcp4_gro_receive,
+	.gro_complete	=	tcp4_gro_complete,
+	.no_policy	=	1,
+	.netns_ok	=	1,
 };
 
 static const struct net_protocol udp_protocol = {
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index e8f2617..916d5ec 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -408,6 +408,7 @@ static void ah4_err(struct sk_buff *skb, u32 info)
 		return;
 	pr_debug("pmtu discovery on SA AH/%08x/%08x\n",
 		 ntohl(ah->spi), ntohl(iph->daddr));
+	ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0);
 	xfrm_state_put(x);
 }
 
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index cda37be..2e560f0 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -790,7 +790,8 @@ static int arp_process(struct sk_buff *skb)
  *	Check for bad requests for 127.x.x.x and requests for multicast
  *	addresses.  If this is one such, delete it.
  */
-	if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
+	if (ipv4_is_multicast(tip) ||
+	    (!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip)))
 		goto out;
 
 /*
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 10e15a1..44bf82e 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1500,7 +1500,8 @@ static int devinet_conf_proc(ctl_table *ctl, int write,
 
 		if (cnf == net->ipv4.devconf_dflt)
 			devinet_copy_dflt_conf(net, i);
-		if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1)
+		if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
+		    i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
 			if ((new_value == 0) && (old_value != 0))
 				rt_cache_flush(net, 0);
 	}
@@ -1617,6 +1618,8 @@ static struct devinet_sysctl_table {
 					      "force_igmp_version"),
 		DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
 					      "promote_secondaries"),
+		DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
+					      "route_localnet"),
 	},
 };
 
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index cb982a6..7b95b49 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -494,6 +494,7 @@ static void esp4_err(struct sk_buff *skb, u32 info)
 		return;
 	NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n",
 		 ntohl(esph->spi), ntohl(iph->daddr));
+	ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0);
 	xfrm_state_put(x);
 }
 
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index e5b7182..415f823 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -779,9 +779,14 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
 			int type = nla_type(nla);
 
 			if (type) {
+				u32 val;
+
 				if (type > RTAX_MAX)
 					goto err_inval;
-				fi->fib_metrics[type - 1] = nla_get_u32(nla);
+				val = nla_get_u32(nla);
+				if (type == RTAX_ADVMSS && val > 65535 - 40)
+					val = 65535 - 40;
+				fi->fib_metrics[type - 1] = val;
 			}
 		}
 	}
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 30b88d7..9b0f259 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1007,9 +1007,9 @@ static void trie_rebalance(struct trie *t, struct tnode *tn)
 	while (tn != NULL && (tp = node_parent((struct rt_trie_node *)tn)) != NULL) {
 		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
 		wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
-		tn = (struct tnode *) resize(t, (struct tnode *)tn);
+		tn = (struct tnode *)resize(t, tn);
 
-		tnode_put_child_reorg((struct tnode *)tp, cindex,
+		tnode_put_child_reorg(tp, cindex,
 				      (struct rt_trie_node *)tn, wasfull);
 
 		tp = node_parent((struct rt_trie_node *) tn);
@@ -1024,7 +1024,7 @@ static void trie_rebalance(struct trie *t, struct tnode *tn)
 
 	/* Handle last (top) tnode */
 	if (IS_TNODE(tn))
-		tn = (struct tnode *)resize(t, (struct tnode *)tn);
+		tn = (struct tnode *)resize(t, tn);
 
 	rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
 	tnode_free_flush();
@@ -1125,7 +1125,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
 		node_set_parent((struct rt_trie_node *)l, tp);
 
 		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
-		put_child(t, (struct tnode *)tp, cindex, (struct rt_trie_node *)l);
+		put_child(t, tp, cindex, (struct rt_trie_node *)l);
 	} else {
 		/* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
 		/*
@@ -1160,8 +1160,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
 
 		if (tp) {
 			cindex = tkey_extract_bits(key, tp->pos, tp->bits);
-			put_child(t, (struct tnode *)tp, cindex,
-				  (struct rt_trie_node *)tn);
+			put_child(t, tp, cindex, (struct rt_trie_node *)tn);
 		} else {
 			rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
 			tp = tn;
@@ -1620,7 +1619,7 @@ static void trie_leaf_remove(struct trie *t, struct leaf *l)
 
 	if (tp) {
 		t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits);
-		put_child(t, (struct tnode *)tp, cindex, NULL);
+		put_child(t, tp, cindex, NULL);
 		trie_rebalance(t, tp);
 	} else
 		RCU_INIT_POINTER(t->trie, NULL);
@@ -1844,6 +1843,8 @@ int fib_table_flush(struct fib_table *tb)
 	if (ll && hlist_empty(&ll->list))
 		trie_leaf_remove(t, ll);
 
+	inetpeer_invalidate_tree(&tb->tb_peers);
+
 	pr_debug("trie_flush found=%d\n", found);
 	return found;
 }
@@ -1992,6 +1993,7 @@ struct fib_table *fib_trie_table(u32 id)
 	tb->tb_id = id;
 	tb->tb_default = -1;
 	tb->tb_num_default = 0;
+	inet_peer_base_init(&tb->tb_peers);
 
 	t = (struct trie *) tb->tb_data;
 	memset(t, 0, sizeof(*t));
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index c75efbd..49a74cc 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -253,9 +253,8 @@ static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
 
 	/* Limit if icmp type is enabled in ratemask. */
 	if ((1 << type) & net->ipv4.sysctl_icmp_ratemask) {
-		if (!rt->peer)
-			rt_bind_peer(rt, fl4->daddr, 1);
-		rc = inet_peer_xrlim_allow(rt->peer,
+		struct inet_peer *peer = rt_get_peer_create(rt, fl4->daddr);
+		rc = inet_peer_xrlim_allow(peer,
 					   net->ipv4.sysctl_icmp_ratelimit);
 	}
 out:
@@ -638,12 +637,12 @@ EXPORT_SYMBOL(icmp_send);
 
 static void icmp_unreach(struct sk_buff *skb)
 {
+	const struct net_protocol *ipprot;
 	const struct iphdr *iph;
 	struct icmphdr *icmph;
-	int hash, protocol;
-	const struct net_protocol *ipprot;
-	u32 info = 0;
 	struct net *net;
+	u32 info = 0;
+	int protocol;
 
 	net = dev_net(skb_dst(skb)->dev);
 
@@ -674,9 +673,7 @@ static void icmp_unreach(struct sk_buff *skb)
 				LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: fragmentation needed and DF set\n"),
 					       &iph->daddr);
 			} else {
-				info = ip_rt_frag_needed(net, iph,
-							 ntohs(icmph->un.frag.mtu),
-							 skb->dev);
+				info = ntohs(icmph->un.frag.mtu);
 				if (!info)
 					goto out;
 			}
@@ -734,9 +731,8 @@ static void icmp_unreach(struct sk_buff *skb)
 	 */
 	raw_icmp_error(skb, protocol, info);
 
-	hash = protocol & (MAX_INET_PROTOS - 1);
 	rcu_read_lock();
-	ipprot = rcu_dereference(inet_protos[hash]);
+	ipprot = rcu_dereference(inet_protos[protocol]);
 	if (ipprot && ipprot->err_handler)
 		ipprot->err_handler(skb, info);
 	rcu_read_unlock();
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index f9ee741..034ddbe 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -368,17 +368,21 @@ EXPORT_SYMBOL(inet_csk_reset_keepalive_timer);
 
 struct dst_entry *inet_csk_route_req(struct sock *sk,
 				     struct flowi4 *fl4,
-				     const struct request_sock *req)
+				     const struct request_sock *req,
+				     bool nocache)
 {
 	struct rtable *rt;
 	const struct inet_request_sock *ireq = inet_rsk(req);
 	struct ip_options_rcu *opt = inet_rsk(req)->opt;
 	struct net *net = sock_net(sk);
+	int flags = inet_sk_flowi_flags(sk) & ~FLOWI_FLAG_PRECOW_METRICS;
 
+	if (nocache)
+		flags |= FLOWI_FLAG_RT_NOCACHE;
 	flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark,
 			   RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
 			   sk->sk_protocol,
-			   inet_sk_flowi_flags(sk) & ~FLOWI_FLAG_PRECOW_METRICS,
+			   flags,
 			   (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr,
 			   ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport);
 	security_req_classify_flow(req, flowi4_to_flowi(fl4));
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 5ff2a51..85190e6 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -243,12 +243,12 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf,
 	if (q == NULL)
 		return NULL;
 
+	q->net = nf;
 	f->constructor(q, arg);
 	atomic_add(f->qsize, &nf->mem);
 	setup_timer(&q->timer, f->frag_expire, (unsigned long)q);
 	spin_lock_init(&q->lock);
 	atomic_set(&q->refcnt, 1);
-	q->net = nf;
 
 	return q;
 }
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index dfba343..da90a8c 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -82,23 +82,39 @@ static const struct inet_peer peer_fake_node = {
 	.avl_height	= 0
 };
 
-struct inet_peer_base {
-	struct inet_peer __rcu *root;
-	seqlock_t	lock;
-	int		total;
-};
+void inet_peer_base_init(struct inet_peer_base *bp)
+{
+	bp->root = peer_avl_empty_rcu;
+	seqlock_init(&bp->lock);
+	bp->flush_seq = ~0U;
+	bp->total = 0;
+}
+EXPORT_SYMBOL_GPL(inet_peer_base_init);
 
-static struct inet_peer_base v4_peers = {
-	.root		= peer_avl_empty_rcu,
-	.lock		= __SEQLOCK_UNLOCKED(v4_peers.lock),
-	.total		= 0,
-};
+static atomic_t v4_seq = ATOMIC_INIT(0);
+static atomic_t v6_seq = ATOMIC_INIT(0);
 
-static struct inet_peer_base v6_peers = {
-	.root		= peer_avl_empty_rcu,
-	.lock		= __SEQLOCK_UNLOCKED(v6_peers.lock),
-	.total		= 0,
-};
+static atomic_t *inetpeer_seq_ptr(int family)
+{
+	return (family == AF_INET ? &v4_seq : &v6_seq);
+}
+
+static inline void flush_check(struct inet_peer_base *base, int family)
+{
+	atomic_t *fp = inetpeer_seq_ptr(family);
+
+	if (unlikely(base->flush_seq != atomic_read(fp))) {
+		inetpeer_invalidate_tree(base);
+		base->flush_seq = atomic_read(fp);
+	}
+}
+
+void inetpeer_invalidate_family(int family)
+{
+	atomic_t *fp = inetpeer_seq_ptr(family);
+
+	atomic_inc(fp);
+}
 
 #define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */
 
@@ -110,7 +126,7 @@ int inet_peer_maxttl __read_mostly = 10 * 60 * HZ;	/* usual time to live: 10 min
 
 static void inetpeer_gc_worker(struct work_struct *work)
 {
-	struct inet_peer *p, *n;
+	struct inet_peer *p, *n, *c;
 	LIST_HEAD(list);
 
 	spin_lock_bh(&gc_lock);
@@ -122,17 +138,19 @@ static void inetpeer_gc_worker(struct work_struct *work)
 
 	list_for_each_entry_safe(p, n, &list, gc_list) {
 
-		if(need_resched())
+		if (need_resched())
 			cond_resched();
 
-		if (p->avl_left != peer_avl_empty) {
-			list_add_tail(&p->avl_left->gc_list, &list);
-			p->avl_left = peer_avl_empty;
+		c = rcu_dereference_protected(p->avl_left, 1);
+		if (c != peer_avl_empty) {
+			list_add_tail(&c->gc_list, &list);
+			p->avl_left = peer_avl_empty_rcu;
 		}
 
-		if (p->avl_right != peer_avl_empty) {
-			list_add_tail(&p->avl_right->gc_list, &list);
-			p->avl_right = peer_avl_empty;
+		c = rcu_dereference_protected(p->avl_right, 1);
+		if (c != peer_avl_empty) {
+			list_add_tail(&c->gc_list, &list);
+			p->avl_right = peer_avl_empty_rcu;
 		}
 
 		n = list_entry(p->gc_list.next, struct inet_peer, gc_list);
@@ -401,11 +419,6 @@ static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base,
 	call_rcu(&p->rcu, inetpeer_free_rcu);
 }
 
-static struct inet_peer_base *family_to_base(int family)
-{
-	return family == AF_INET ? &v4_peers : &v6_peers;
-}
-
 /* perform garbage collect on all items stacked during a lookup */
 static int inet_peer_gc(struct inet_peer_base *base,
 			struct inet_peer __rcu **stack[PEER_MAXDEPTH],
@@ -443,14 +456,17 @@ static int inet_peer_gc(struct inet_peer_base *base,
 	return cnt;
 }
 
-struct inet_peer *inet_getpeer(const struct inetpeer_addr *daddr, int create)
+struct inet_peer *inet_getpeer(struct inet_peer_base *base,
+			       const struct inetpeer_addr *daddr,
+			       int create)
 {
 	struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr;
-	struct inet_peer_base *base = family_to_base(daddr->family);
 	struct inet_peer *p;
 	unsigned int sequence;
 	int invalidated, gccnt = 0;
 
+	flush_check(base, daddr->family);
+
 	/* Attempt a lockless lookup first.
 	 * Because of a concurrent writer, we might not find an existing entry.
 	 */
@@ -571,26 +587,19 @@ static void inetpeer_inval_rcu(struct rcu_head *head)
 	schedule_delayed_work(&gc_work, gc_delay);
 }
 
-void inetpeer_invalidate_tree(int family)
+void inetpeer_invalidate_tree(struct inet_peer_base *base)
 {
-	struct inet_peer *old, *new, *prev;
-	struct inet_peer_base *base = family_to_base(family);
+	struct inet_peer *root;
 
 	write_seqlock_bh(&base->lock);
 
-	old = base->root;
-	if (old == peer_avl_empty_rcu)
-		goto out;
-
-	new = peer_avl_empty_rcu;
-
-	prev = cmpxchg(&base->root, old, new);
-	if (prev == old) {
+	root = rcu_deref_locked(base->root, base);
+	if (root != peer_avl_empty) {
+		base->root = peer_avl_empty_rcu;
 		base->total = 0;
-		call_rcu(&prev->gc_rcu, inetpeer_inval_rcu);
+		call_rcu(&root->gc_rcu, inetpeer_inval_rcu);
 	}
 
-out:
 	write_sequnlock_bh(&base->lock);
 }
 EXPORT_SYMBOL(inetpeer_invalidate_tree);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 9dbd3dd..8d07c97 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -171,6 +171,10 @@ static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb)
 static void ip4_frag_init(struct inet_frag_queue *q, void *a)
 {
 	struct ipq *qp = container_of(q, struct ipq, q);
+	struct netns_ipv4 *ipv4 = container_of(q->net, struct netns_ipv4,
+					       frags);
+	struct net *net = container_of(ipv4, struct net, ipv4);
+
 	struct ip4_create_arg *arg = a;
 
 	qp->protocol = arg->iph->protocol;
@@ -180,7 +184,7 @@ static void ip4_frag_init(struct inet_frag_queue *q, void *a)
 	qp->daddr = arg->iph->daddr;
 	qp->user = arg->user;
 	qp->peer = sysctl_ipfrag_max_dist ?
-		inet_getpeer_v4(arg->iph->saddr, 1) : NULL;
+		inet_getpeer_v4(net->ipv4.peers, arg->iph->saddr, 1) : NULL;
 }
 
 static __inline__ void ip4_frag_free(struct inet_frag_queue *q)
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index f49047b..594cec3 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -516,9 +516,6 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
 		case ICMP_PORT_UNREACH:
 			/* Impossible event. */
 			return;
-		case ICMP_FRAG_NEEDED:
-			/* Soft state for pmtu is maintained by IP core. */
-			return;
 		default:
 			/* All others are translated to HOST_UNREACH.
 			   rfc2003 contains "deep thoughts" about NET_UNREACH,
@@ -538,7 +535,16 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
 				flags & GRE_KEY ?
 				*(((__be32 *)p) + (grehlen / 4) - 1) : 0,
 				p[1]);
-	if (t == NULL || t->parms.iph.daddr == 0 ||
+	if (t == NULL)
+		goto out;
+
+	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
+		ipv4_update_pmtu(skb, dev_net(skb->dev), info,
+				 t->parms.link, 0, IPPROTO_GRE, 0);
+		goto out;
+	}
+
+	if (t->parms.iph.daddr == 0 ||
 	    ipv4_is_multicast(t->parms.iph.daddr))
 		goto out;
 
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 8590144..2a39204 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -198,14 +198,13 @@ static int ip_local_deliver_finish(struct sk_buff *skb)
 	rcu_read_lock();
 	{
 		int protocol = ip_hdr(skb)->protocol;
-		int hash, raw;
 		const struct net_protocol *ipprot;
+		int raw;
 
 	resubmit:
 		raw = raw_local_deliver(skb, protocol);
 
-		hash = protocol & (MAX_INET_PROTOS - 1);
-		ipprot = rcu_dereference(inet_protos[hash]);
+		ipprot = rcu_dereference(inet_protos[protocol]);
 		if (ipprot != NULL) {
 			int ret;
 
@@ -314,6 +313,8 @@ drop:
 	return true;
 }
 
+int sysctl_ip_early_demux __read_mostly = 1;
+
 static int ip_rcv_finish(struct sk_buff *skb)
 {
 	const struct iphdr *iph = ip_hdr(skb);
@@ -324,19 +325,28 @@ static int ip_rcv_finish(struct sk_buff *skb)
 	 *	how the packet travels inside Linux networking.
 	 */
 	if (skb_dst(skb) == NULL) {
-		int err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
-					       iph->tos, skb->dev);
-		if (unlikely(err)) {
-			if (err == -EHOSTUNREACH)
-				IP_INC_STATS_BH(dev_net(skb->dev),
-						IPSTATS_MIB_INADDRERRORS);
-			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;
+		int err = -ENOENT;
+
+		if (sysctl_ip_early_demux) {
+			const struct net_protocol *ipprot;
+			int protocol = iph->protocol;
+
+			rcu_read_lock();
+			ipprot = rcu_dereference(inet_protos[protocol]);
+			if (ipprot && ipprot->early_demux)
+				err = ipprot->early_demux(skb);
+			rcu_read_unlock();
+		}
+
+		if (err) {
+			err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
+						   iph->tos, skb->dev);
+			if (unlikely(err)) {
+				if (err == -EXDEV)
+					NET_INC_STATS_BH(dev_net(skb->dev),
+							 LINUX_MIB_IPRPFILTER);
+				goto drop;
+			}
 		}
 	}
 
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 451f97c..0f3185a 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -113,19 +113,6 @@ int ip_local_out(struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(ip_local_out);
 
-/* dev_loopback_xmit for use with netfilter. */
-static int ip_dev_loopback_xmit(struct sk_buff *newskb)
-{
-	skb_reset_mac_header(newskb);
-	__skb_pull(newskb, skb_network_offset(newskb));
-	newskb->pkt_type = PACKET_LOOPBACK;
-	newskb->ip_summed = CHECKSUM_UNNECESSARY;
-	WARN_ON(!skb_dst(newskb));
-	skb_dst_force(newskb);
-	netif_rx_ni(newskb);
-	return 0;
-}
-
 static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst)
 {
 	int ttl = inet->uc_ttl;
@@ -200,7 +187,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
 		}
 		if (skb->sk)
 			skb_set_owner_w(skb2, skb->sk);
-		kfree_skb(skb);
+		consume_skb(skb);
 		skb = skb2;
 	}
 
@@ -281,7 +268,7 @@ int ip_mc_output(struct sk_buff *skb)
 			if (newskb)
 				NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING,
 					newskb, NULL, newskb->dev,
-					ip_dev_loopback_xmit);
+					dev_loopback_xmit);
 		}
 
 		/* Multicasts with ttl 0 must not go beyond the host */
@@ -296,7 +283,7 @@ int ip_mc_output(struct sk_buff *skb)
 		struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
 		if (newskb)
 			NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, newskb,
-				NULL, newskb->dev, ip_dev_loopback_xmit);
+				NULL, newskb->dev, dev_loopback_xmit);
 	}
 
 	return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL,
@@ -709,7 +696,7 @@ slow_path:
 
 		IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGCREATES);
 	}
-	kfree_skb(skb);
+	consume_skb(skb);
 	IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGOKS);
 	return err;
 
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 63b64c4..b913754 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -42,6 +42,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
 		return;
 	NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%pI4\n",
 		 spi, &iph->daddr);
+	ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0);
 	xfrm_state_put(x);
 }
 
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 2d0f99b..715338a 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -348,9 +348,6 @@ static int ipip_err(struct sk_buff *skb, u32 info)
 		case ICMP_PORT_UNREACH:
 			/* Impossible event. */
 			return 0;
-		case ICMP_FRAG_NEEDED:
-			/* Soft state for pmtu is maintained by IP core. */
-			return 0;
 		default:
 			/* All others are translated to HOST_UNREACH.
 			   rfc2003 contains "deep thoughts" about NET_UNREACH,
@@ -369,7 +366,17 @@ static int ipip_err(struct sk_buff *skb, u32 info)
 
 	rcu_read_lock();
 	t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr);
-	if (t == NULL || t->parms.iph.daddr == 0)
+	if (t == NULL)
+		goto out;
+
+	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
+		ipv4_update_pmtu(skb, dev_net(skb->dev), info,
+				 t->dev->ifindex, 0, IPPROTO_IPIP, 0);
+		err = 0;
+		goto out;
+	}
+
+	if (t->parms.iph.daddr == 0)
 		goto out;
 
 	err = 0;
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 91747d4..e7ff2dc 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -95,11 +95,11 @@ static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
 	return NF_ACCEPT;
 }
 
-static unsigned int ipv4_confirm(unsigned int hooknum,
-				 struct sk_buff *skb,
-				 const struct net_device *in,
-				 const struct net_device *out,
-				 int (*okfn)(struct sk_buff *))
+static unsigned int ipv4_helper(unsigned int hooknum,
+				struct sk_buff *skb,
+				const struct net_device *in,
+				const struct net_device *out,
+				int (*okfn)(struct sk_buff *))
 {
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
@@ -110,24 +110,38 @@ static unsigned int ipv4_confirm(unsigned int hooknum,
 	/* This is where we call the helper: as the packet goes out. */
 	ct = nf_ct_get(skb, &ctinfo);
 	if (!ct || ctinfo == IP_CT_RELATED_REPLY)
-		goto out;
+		return NF_ACCEPT;
 
 	help = nfct_help(ct);
 	if (!help)
-		goto out;
+		return NF_ACCEPT;
 
 	/* rcu_read_lock()ed by nf_hook_slow */
 	helper = rcu_dereference(help->helper);
 	if (!helper)
-		goto out;
+		return NF_ACCEPT;
 
 	ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb),
 			   ct, ctinfo);
-	if (ret != NF_ACCEPT) {
+	if (ret != NF_ACCEPT && (ret & NF_VERDICT_MASK) != NF_QUEUE) {
 		nf_log_packet(NFPROTO_IPV4, hooknum, skb, in, out, NULL,
 			      "nf_ct_%s: dropping packet", helper->name);
-		return ret;
 	}
+	return ret;
+}
+
+static unsigned int ipv4_confirm(unsigned int hooknum,
+				 struct sk_buff *skb,
+				 const struct net_device *in,
+				 const struct net_device *out,
+				 int (*okfn)(struct sk_buff *))
+{
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+
+	ct = nf_ct_get(skb, &ctinfo);
+	if (!ct || ctinfo == IP_CT_RELATED_REPLY)
+		goto out;
 
 	/* adjust seqs for loopback traffic only in outgoing direction */
 	if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
@@ -185,6 +199,13 @@ static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = {
 		.priority	= NF_IP_PRI_CONNTRACK,
 	},
 	{
+		.hook		= ipv4_helper,
+		.owner		= THIS_MODULE,
+		.pf		= NFPROTO_IPV4,
+		.hooknum	= NF_INET_POST_ROUTING,
+		.priority	= NF_IP_PRI_CONNTRACK_HELPER,
+	},
+	{
 		.hook		= ipv4_confirm,
 		.owner		= THIS_MODULE,
 		.pf		= NFPROTO_IPV4,
@@ -192,6 +213,13 @@ static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = {
 		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
 	},
 	{
+		.hook		= ipv4_helper,
+		.owner		= THIS_MODULE,
+		.pf		= NFPROTO_IPV4,
+		.hooknum	= NF_INET_LOCAL_IN,
+		.priority	= NF_IP_PRI_CONNTRACK_HELPER,
+	},
+	{
 		.hook		= ipv4_confirm,
 		.owner		= THIS_MODULE,
 		.pf		= NFPROTO_IPV4,
@@ -207,35 +235,30 @@ static int log_invalid_proto_max = 255;
 static ctl_table ip_ct_sysctl_table[] = {
 	{
 		.procname	= "ip_conntrack_max",
-		.data		= &nf_conntrack_max,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname	= "ip_conntrack_count",
-		.data		= &init_net.ct.count,
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
 		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname	= "ip_conntrack_buckets",
-		.data		= &init_net.ct.htable_size,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0444,
 		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname	= "ip_conntrack_checksum",
-		.data		= &init_net.ct.sysctl_checksum,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname	= "ip_conntrack_log_invalid",
-		.data		= &init_net.ct.sysctl_log_invalid,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_minmax,
@@ -351,6 +374,25 @@ static struct nf_sockopt_ops so_getorigdst = {
 	.owner		= THIS_MODULE,
 };
 
+static int ipv4_init_net(struct net *net)
+{
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+	struct nf_ip_net *in = &net->ct.nf_ct_proto;
+	in->ctl_table = kmemdup(ip_ct_sysctl_table,
+				sizeof(ip_ct_sysctl_table),
+				GFP_KERNEL);
+	if (!in->ctl_table)
+		return -ENOMEM;
+
+	in->ctl_table[0].data = &nf_conntrack_max;
+	in->ctl_table[1].data = &net->ct.count;
+	in->ctl_table[2].data = &net->ct.htable_size;
+	in->ctl_table[3].data = &net->ct.sysctl_checksum;
+	in->ctl_table[4].data = &net->ct.sysctl_log_invalid;
+#endif
+	return 0;
+}
+
 struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = {
 	.l3proto	 = PF_INET,
 	.name		 = "ipv4",
@@ -366,8 +408,8 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = {
 #endif
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
 	.ctl_table_path  = "net/ipv4/netfilter",
-	.ctl_table	 = ip_ct_sysctl_table,
 #endif
+	.init_net	 = ipv4_init_net,
 	.me		 = THIS_MODULE,
 };
 
@@ -378,6 +420,65 @@ MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
 MODULE_ALIAS("ip_conntrack");
 MODULE_LICENSE("GPL");
 
+static int ipv4_net_init(struct net *net)
+{
+	int ret = 0;
+
+	ret = nf_conntrack_l4proto_register(net,
+					    &nf_conntrack_l4proto_tcp4);
+	if (ret < 0) {
+		pr_err("nf_conntrack_l4proto_tcp4 :protocol register failed\n");
+		goto out_tcp;
+	}
+	ret = nf_conntrack_l4proto_register(net,
+					    &nf_conntrack_l4proto_udp4);
+	if (ret < 0) {
+		pr_err("nf_conntrack_l4proto_udp4 :protocol register failed\n");
+		goto out_udp;
+	}
+	ret = nf_conntrack_l4proto_register(net,
+					    &nf_conntrack_l4proto_icmp);
+	if (ret < 0) {
+		pr_err("nf_conntrack_l4proto_icmp4 :protocol register failed\n");
+		goto out_icmp;
+	}
+	ret = nf_conntrack_l3proto_register(net,
+					    &nf_conntrack_l3proto_ipv4);
+	if (ret < 0) {
+		pr_err("nf_conntrack_l3proto_ipv4 :protocol register failed\n");
+		goto out_ipv4;
+	}
+	return 0;
+out_ipv4:
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_icmp);
+out_icmp:
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_udp4);
+out_udp:
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_tcp4);
+out_tcp:
+	return ret;
+}
+
+static void ipv4_net_exit(struct net *net)
+{
+	nf_conntrack_l3proto_unregister(net,
+					&nf_conntrack_l3proto_ipv4);
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_icmp);
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_udp4);
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_tcp4);
+}
+
+static struct pernet_operations ipv4_net_ops = {
+	.init = ipv4_net_init,
+	.exit = ipv4_net_exit,
+};
+
 static int __init nf_conntrack_l3proto_ipv4_init(void)
 {
 	int ret = 0;
@@ -391,35 +492,17 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
 		return ret;
 	}
 
-	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp4);
+	ret = register_pernet_subsys(&ipv4_net_ops);
 	if (ret < 0) {
-		pr_err("nf_conntrack_ipv4: can't register tcp.\n");
+		pr_err("nf_conntrack_ipv4: can't register pernet ops\n");
 		goto cleanup_sockopt;
 	}
 
-	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp4);
-	if (ret < 0) {
-		pr_err("nf_conntrack_ipv4: can't register udp.\n");
-		goto cleanup_tcp;
-	}
-
-	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmp);
-	if (ret < 0) {
-		pr_err("nf_conntrack_ipv4: can't register icmp.\n");
-		goto cleanup_udp;
-	}
-
-	ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv4);
-	if (ret < 0) {
-		pr_err("nf_conntrack_ipv4: can't register ipv4\n");
-		goto cleanup_icmp;
-	}
-
 	ret = nf_register_hooks(ipv4_conntrack_ops,
 				ARRAY_SIZE(ipv4_conntrack_ops));
 	if (ret < 0) {
 		pr_err("nf_conntrack_ipv4: can't register hooks.\n");
-		goto cleanup_ipv4;
+		goto cleanup_pernet;
 	}
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
 	ret = nf_conntrack_ipv4_compat_init();
@@ -431,14 +514,8 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
  cleanup_hooks:
 	nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
 #endif
- cleanup_ipv4:
-	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
- cleanup_icmp:
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp);
- cleanup_udp:
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4);
- cleanup_tcp:
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4);
+ cleanup_pernet:
+	unregister_pernet_subsys(&ipv4_net_ops);
  cleanup_sockopt:
 	nf_unregister_sockopt(&so_getorigdst);
 	return ret;
@@ -451,10 +528,7 @@ static void __exit nf_conntrack_l3proto_ipv4_fini(void)
 	nf_conntrack_ipv4_compat_fini();
 #endif
 	nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
-	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp);
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4);
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4);
+	unregister_pernet_subsys(&ipv4_net_ops);
 	nf_unregister_sockopt(&so_getorigdst);
 }
 
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 0847e37..041923c 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -23,6 +23,11 @@
 
 static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ;
 
+static inline struct nf_icmp_net *icmp_pernet(struct net *net)
+{
+	return &net->ct.nf_ct_proto.icmp;
+}
+
 static bool icmp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
 			      struct nf_conntrack_tuple *tuple)
 {
@@ -77,7 +82,7 @@ static int icmp_print_tuple(struct seq_file *s,
 
 static unsigned int *icmp_get_timeouts(struct net *net)
 {
-	return &nf_ct_icmp_timeout;
+	return &icmp_pernet(net)->timeout;
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
@@ -274,16 +279,18 @@ static int icmp_nlattr_tuple_size(void)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[],
+				      struct net *net, void *data)
 {
 	unsigned int *timeout = data;
+	struct nf_icmp_net *in = icmp_pernet(net);
 
 	if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) {
 		*timeout =
 			ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMP_TIMEOUT])) * HZ;
 	} else {
 		/* Set default ICMP timeout. */
-		*timeout = nf_ct_icmp_timeout;
+		*timeout = in->timeout;
 	}
 	return 0;
 }
@@ -308,11 +315,9 @@ icmp_timeout_nla_policy[CTA_TIMEOUT_ICMP_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table_header *icmp_sysctl_header;
 static struct ctl_table icmp_sysctl_table[] = {
 	{
 		.procname	= "nf_conntrack_icmp_timeout",
-		.data		= &nf_ct_icmp_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -323,7 +328,6 @@ static struct ctl_table icmp_sysctl_table[] = {
 static struct ctl_table icmp_compat_sysctl_table[] = {
 	{
 		.procname	= "ip_conntrack_icmp_timeout",
-		.data		= &nf_ct_icmp_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -333,6 +337,34 @@ static struct ctl_table icmp_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
 
+static int icmp_init_net(struct net *net)
+{
+	struct nf_icmp_net *in = icmp_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)in;
+	in->timeout = nf_ct_icmp_timeout;
+
+#ifdef CONFIG_SYSCTL
+	pn->ctl_table = kmemdup(icmp_sysctl_table,
+				sizeof(icmp_sysctl_table),
+				GFP_KERNEL);
+	if (!pn->ctl_table)
+		return -ENOMEM;
+	pn->ctl_table[0].data = &in->timeout;
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+	pn->ctl_compat_table = kmemdup(icmp_compat_sysctl_table,
+				       sizeof(icmp_compat_sysctl_table),
+				       GFP_KERNEL);
+	if (!pn->ctl_compat_table) {
+		kfree(pn->ctl_table);
+		pn->ctl_table = NULL;
+		return -ENOMEM;
+	}
+	pn->ctl_compat_table[0].data = &in->timeout;
+#endif
+#endif
+	return 0;
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
 {
 	.l3proto		= PF_INET,
@@ -362,11 +394,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
 		.nla_policy	= icmp_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-	.ctl_table_header	= &icmp_sysctl_header,
-	.ctl_table		= icmp_sysctl_table,
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-	.ctl_compat_table	= icmp_compat_sysctl_table,
-#endif
-#endif
+	.init_net		= icmp_init_net,
 };
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index 9bb1b8a..7428155 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -94,14 +94,14 @@ static struct nf_hook_ops ipv4_defrag_ops[] = {
 	{
 		.hook		= ipv4_conntrack_defrag,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
+		.pf		= NFPROTO_IPV4,
 		.hooknum	= NF_INET_PRE_ROUTING,
 		.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
 	},
 	{
 		.hook           = ipv4_conntrack_defrag,
 		.owner          = THIS_MODULE,
-		.pf             = PF_INET,
+		.pf             = NFPROTO_IPV4,
 		.hooknum        = NF_INET_LOCAL_OUT,
 		.priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
 	},
diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c
index 7b22382..3c04d24 100644
--- a/net/ipv4/netfilter/nf_nat_amanda.c
+++ b/net/ipv4/netfilter/nf_nat_amanda.c
@@ -13,10 +13,10 @@
 #include <linux/skbuff.h>
 #include <linux/udp.h>
 
-#include <net/netfilter/nf_nat_helper.h>
-#include <net/netfilter/nf_nat_rule.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
+#include <net/netfilter/nf_nat_helper.h>
+#include <net/netfilter/nf_nat_rule.h>
 #include <linux/netfilter/nf_conntrack_amanda.h>
 
 MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index abb52ad..44b082f 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -691,6 +691,10 @@ static struct nf_ct_helper_expectfn follow_master_nat = {
 	.expectfn	= nf_nat_follow_master,
 };
 
+static struct nfq_ct_nat_hook nfq_ct_nat = {
+	.seq_adjust	= nf_nat_tcp_seq_adjust,
+};
+
 static int __init nf_nat_init(void)
 {
 	size_t i;
@@ -731,6 +735,7 @@ static int __init nf_nat_init(void)
 			   nfnetlink_parse_nat_setup);
 	BUG_ON(nf_ct_nat_offset != NULL);
 	RCU_INIT_POINTER(nf_ct_nat_offset, nf_nat_get_offset);
+	RCU_INIT_POINTER(nfq_ct_nat_hook, &nfq_ct_nat);
 	return 0;
 
  cleanup_extend:
@@ -747,6 +752,7 @@ static void __exit nf_nat_cleanup(void)
 	RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL);
 	RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL);
 	RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
+	RCU_INIT_POINTER(nfq_ct_nat_hook, NULL);
 	synchronize_net();
 }
 
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index cad29c1..c6784a1 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -95,7 +95,7 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
 			unsigned char **data,
 			TransportAddress *taddr, int count)
 {
-	const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	const struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
 	int i;
 	__be16 port;
@@ -178,7 +178,7 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
 			struct nf_conntrack_expect *rtp_exp,
 			struct nf_conntrack_expect *rtcp_exp)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
 	int i;
 	u_int16_t nated_port;
@@ -330,7 +330,7 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
 		    TransportAddress *taddr, __be16 port,
 		    struct nf_conntrack_expect *exp)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
 	u_int16_t nated_port = ntohs(port);
 
@@ -419,7 +419,7 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
 		    unsigned char **data, TransportAddress *taddr, int idx,
 		    __be16 port, struct nf_conntrack_expect *exp)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
 	u_int16_t nated_port = ntohs(port);
 	union nf_inet_addr addr;
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index af65958..2e59ad0 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -153,6 +153,19 @@ void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
 }
 EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);
 
+void nf_nat_tcp_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
+			   u32 ctinfo, int off)
+{
+	const struct tcphdr *th;
+
+	if (nf_ct_protonum(ct) != IPPROTO_TCP)
+		return;
+
+	th = (struct tcphdr *)(skb_network_header(skb)+ ip_hdrlen(skb));
+	nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off);
+}
+EXPORT_SYMBOL_GPL(nf_nat_tcp_seq_adjust);
+
 static void nf_nat_csum(struct sk_buff *skb, const struct iphdr *iph, void *data,
 			int datalen, __sum16 *check, int oldlen)
 {
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index c273d58..3881408 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -49,7 +49,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
 	const struct nf_nat_pptp *nat_pptp_info;
 	struct nf_nat_ipv4_range range;
 
-	ct_pptp_info = &nfct_help(master)->help.ct_pptp_info;
+	ct_pptp_info = nfct_help_data(master);
 	nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info;
 
 	/* And here goes the grand finale of corrosion... */
@@ -123,7 +123,7 @@ pptp_outbound_pkt(struct sk_buff *skb,
 	__be16 new_callid;
 	unsigned int cid_off;
 
-	ct_pptp_info  = &nfct_help(ct)->help.ct_pptp_info;
+	ct_pptp_info = nfct_help_data(ct);
 	nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info;
 
 	new_callid = ct_pptp_info->pns_call_id;
@@ -192,7 +192,7 @@ pptp_exp_gre(struct nf_conntrack_expect *expect_orig,
 	struct nf_ct_pptp_master *ct_pptp_info;
 	struct nf_nat_pptp *nat_pptp_info;
 
-	ct_pptp_info  = &nfct_help(ct)->help.ct_pptp_info;
+	ct_pptp_info = nfct_help_data(ct);
 	nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info;
 
 	/* save original PAC call ID in nat_info */
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index 746edec..bac7122 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -405,7 +405,7 @@ static unsigned char asn1_octets_decode(struct asn1_ctx *ctx,
 
 	ptr = *octets;
 	while (ctx->pointer < eoc) {
-		if (!asn1_octet_decode(ctx, (unsigned char *)ptr++)) {
+		if (!asn1_octet_decode(ctx, ptr++)) {
 			kfree(*octets);
 			*octets = NULL;
 			return 0;
@@ -759,7 +759,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
 		}
 		break;
 	case SNMP_OBJECTID:
-		if (!asn1_oid_decode(ctx, end, (unsigned long **)&lp, &len)) {
+		if (!asn1_oid_decode(ctx, end, &lp, &len)) {
 			kfree(id);
 			return 0;
 		}
diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c
index a2901bf..9dbb8d2 100644
--- a/net/ipv4/netfilter/nf_nat_tftp.c
+++ b/net/ipv4/netfilter/nf_nat_tftp.c
@@ -8,10 +8,10 @@
 #include <linux/module.h>
 #include <linux/udp.h>
 
-#include <net/netfilter/nf_nat_helper.h>
-#include <net/netfilter/nf_nat_rule.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
+#include <net/netfilter/nf_nat_helper.h>
+#include <net/netfilter/nf_nat_rule.h>
 #include <linux/netfilter/nf_conntrack_tftp.h>
 
 MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 2c00e8b..340fcf2 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -371,6 +371,7 @@ void ping_err(struct sk_buff *skb, u32 info)
 		break;
 	case ICMP_DEST_UNREACH:
 		if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
+			ipv4_sk_update_pmtu(skb, sk, info);
 			if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) {
 				err = EMSGSIZE;
 				harderr = 1;
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c
index 9ae5c01..8918eff 100644
--- a/net/ipv4/protocol.c
+++ b/net/ipv4/protocol.c
@@ -36,9 +36,7 @@ const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS] __read_mostly;
 
 int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol)
 {
-	int hash = protocol & (MAX_INET_PROTOS - 1);
-
-	return !cmpxchg((const struct net_protocol **)&inet_protos[hash],
+	return !cmpxchg((const struct net_protocol **)&inet_protos[protocol],
 			NULL, prot) ? 0 : -1;
 }
 EXPORT_SYMBOL(inet_add_protocol);
@@ -49,9 +47,9 @@ EXPORT_SYMBOL(inet_add_protocol);
 
 int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol)
 {
-	int ret, hash = protocol & (MAX_INET_PROTOS - 1);
+	int ret;
 
-	ret = (cmpxchg((const struct net_protocol **)&inet_protos[hash],
+	ret = (cmpxchg((const struct net_protocol **)&inet_protos[protocol],
 		       prot, NULL) == prot) ? 0 : -1;
 
 	synchronize_net();
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 4032b81..659ddfb 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -216,6 +216,9 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
 	int err = 0;
 	int harderr = 0;
 
+	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
+		ipv4_sk_update_pmtu(skb, sk, info);
+
 	/* Report error on raw socket, if:
 	   1. User requested ip_recverr.
 	   2. Socket is connected (otherwise the error indication
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 98b30d0..81533e3 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -162,10 +162,7 @@ static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old)
 	struct inet_peer *peer;
 	u32 *p = NULL;
 
-	if (!rt->peer)
-		rt_bind_peer(rt, rt->rt_dst, 1);
-
-	peer = rt->peer;
+	peer = rt_get_peer_create(rt, rt->rt_dst);
 	if (peer) {
 		u32 *old_p = __DST_METRICS_PTR(old);
 		unsigned long prev, new;
@@ -680,7 +677,7 @@ static inline int rt_fast_clean(struct rtable *rth)
 static inline int rt_valuable(struct rtable *rth)
 {
 	return (rth->rt_flags & (RTCF_REDIRECTED | RTCF_NOTIFY)) ||
-		(rth->peer && rth->peer->pmtu_expires);
+		(rt_has_peer(rth) && rt_peer_ptr(rth)->pmtu_expires);
 }
 
 static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2)
@@ -873,34 +870,22 @@ static void rt_check_expire(void)
 		while ((rth = rcu_dereference_protected(*rthp,
 					lockdep_is_held(rt_hash_lock_addr(i)))) != NULL) {
 			prefetch(rth->dst.rt_next);
-			if (rt_is_expired(rth)) {
+			if (rt_is_expired(rth) ||
+			    rt_may_expire(rth, tmo, ip_rt_gc_timeout)) {
 				*rthp = rth->dst.rt_next;
 				rt_free(rth);
 				continue;
 			}
-			if (rth->dst.expires) {
-				/* Entry is expired even if it is in use */
-				if (time_before_eq(jiffies, rth->dst.expires)) {
-nofree:
-					tmo >>= 1;
-					rthp = &rth->dst.rt_next;
-					/*
-					 * We only count entries on
-					 * a chain with equal hash inputs once
-					 * so that entries for different QOS
-					 * levels, and other non-hash input
-					 * attributes don't unfairly skew
-					 * the length computation
-					 */
-					length += has_noalias(rt_hash_table[i].chain, rth);
-					continue;
-				}
-			} else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout))
-				goto nofree;
 
-			/* Cleanup aged off entries. */
-			*rthp = rth->dst.rt_next;
-			rt_free(rth);
+			/* We only count entries on a chain with equal
+			 * hash inputs once so that entries for
+			 * different QOS levels, and other non-hash
+			 * input attributes don't unfairly skew the
+			 * length computation
+			 */
+			tmo >>= 1;
+			rthp = &rth->dst.rt_next;
+			length += has_noalias(rt_hash_table[i].chain, rth);
 		}
 		spin_unlock_bh(rt_hash_lock_addr(i));
 		sum += length;
@@ -938,7 +923,7 @@ static void rt_cache_invalidate(struct net *net)
 
 	get_random_bytes(&shuffle, sizeof(shuffle));
 	atomic_add(shuffle + 1U, &net->ipv4.rt_genid);
-	inetpeer_invalidate_tree(AF_INET);
+	inetpeer_invalidate_family(AF_INET);
 }
 
 /*
@@ -1159,7 +1144,7 @@ restart:
 	candp = NULL;
 	now = jiffies;
 
-	if (!rt_caching(dev_net(rt->dst.dev))) {
+	if (!rt_caching(dev_net(rt->dst.dev)) || (rt->dst.flags & DST_NOCACHE)) {
 		/*
 		 * If we're not caching, just tell the caller we
 		 * were successful and don't touch the route.  The
@@ -1328,14 +1313,20 @@ static u32 rt_peer_genid(void)
 
 void rt_bind_peer(struct rtable *rt, __be32 daddr, int create)
 {
+	struct inet_peer_base *base;
 	struct inet_peer *peer;
 
-	peer = inet_getpeer_v4(daddr, create);
+	base = inetpeer_base_ptr(rt->_peer);
+	if (!base)
+		return;
 
-	if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL)
-		inet_putpeer(peer);
-	else
-		rt->rt_peer_genid = rt_peer_genid();
+	peer = inet_getpeer_v4(base, daddr, create);
+	if (peer) {
+		if (!rt_set_peer(rt, peer))
+			inet_putpeer(peer);
+		else
+			rt->rt_peer_genid = rt_peer_genid();
+	}
 }
 
 /*
@@ -1363,14 +1354,13 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
 	struct rtable *rt = (struct rtable *) dst;
 
 	if (rt && !(rt->dst.flags & DST_NOPEER)) {
-		if (rt->peer == NULL)
-			rt_bind_peer(rt, rt->rt_dst, 1);
+		struct inet_peer *peer = rt_get_peer_create(rt, rt->rt_dst);
 
 		/* If peer is attached to destination, it is never detached,
 		   so that we need not to grab a lock to dereference it.
 		 */
-		if (rt->peer) {
-			iph->id = htons(inet_getid(rt->peer, more));
+		if (peer) {
+			iph->id = htons(inet_getid(peer, more));
 			return;
 		}
 	} else if (!rt)
@@ -1480,10 +1470,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
 				    rt->rt_gateway != old_gw)
 					continue;
 
-				if (!rt->peer)
-					rt_bind_peer(rt, rt->rt_dst, 1);
-
-				peer = rt->peer;
+				peer = rt_get_peer_create(rt, rt->rt_dst);
 				if (peer) {
 					if (peer->redirect_learned.a4 != new_gw) {
 						peer->redirect_learned.a4 = new_gw;
@@ -1539,8 +1526,10 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
 						rt_genid(dev_net(dst->dev)));
 			rt_del(hash, rt);
 			ret = NULL;
-		} else if (rt->peer && peer_pmtu_expired(rt->peer)) {
-			dst_metric_set(dst, RTAX_MTU, rt->peer->pmtu_orig);
+		} else if (rt_has_peer(rt)) {
+			struct inet_peer *peer = rt_peer_ptr(rt);
+			if (peer_pmtu_expired(peer))
+				dst_metric_set(dst, RTAX_MTU, peer->pmtu_orig);
 		}
 	}
 	return ret;
@@ -1578,9 +1567,7 @@ void ip_rt_send_redirect(struct sk_buff *skb)
 	log_martians = IN_DEV_LOG_MARTIANS(in_dev);
 	rcu_read_unlock();
 
-	if (!rt->peer)
-		rt_bind_peer(rt, rt->rt_dst, 1);
-	peer = rt->peer;
+	peer = rt_get_peer_create(rt, rt->rt_dst);
 	if (!peer) {
 		icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
 		return;
@@ -1622,12 +1609,28 @@ void ip_rt_send_redirect(struct sk_buff *skb)
 
 static int ip_error(struct sk_buff *skb)
 {
+	struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
 	struct rtable *rt = skb_rtable(skb);
 	struct inet_peer *peer;
 	unsigned long now;
+	struct net *net;
 	bool send;
 	int code;
 
+	net = dev_net(rt->dst.dev);
+	if (!IN_DEV_FORWARD(in_dev)) {
+		switch (rt->dst.error) {
+		case EHOSTUNREACH:
+			IP_INC_STATS_BH(net, IPSTATS_MIB_INADDRERRORS);
+			break;
+
+		case ENETUNREACH:
+			IP_INC_STATS_BH(net, IPSTATS_MIB_INNOROUTES);
+			break;
+		}
+		goto out;
+	}
+
 	switch (rt->dst.error) {
 	case EINVAL:
 	default:
@@ -1637,17 +1640,14 @@ static int ip_error(struct sk_buff *skb)
 		break;
 	case ENETUNREACH:
 		code = ICMP_NET_UNREACH;
-		IP_INC_STATS_BH(dev_net(rt->dst.dev),
-				IPSTATS_MIB_INNOROUTES);
+		IP_INC_STATS_BH(net, IPSTATS_MIB_INNOROUTES);
 		break;
 	case EACCES:
 		code = ICMP_PKT_FILTERED;
 		break;
 	}
 
-	if (!rt->peer)
-		rt_bind_peer(rt, rt->rt_dst, 1);
-	peer = rt->peer;
+	peer = rt_get_peer_create(rt, rt->rt_dst);
 
 	send = true;
 	if (peer) {
@@ -1668,67 +1668,6 @@ out:	kfree_skb(skb);
 	return 0;
 }
 
-/*
- *	The last two values are not from the RFC but
- *	are needed for AMPRnet AX.25 paths.
- */
-
-static const unsigned short mtu_plateau[] =
-{32000, 17914, 8166, 4352, 2002, 1492, 576, 296, 216, 128 };
-
-static inline unsigned short guess_mtu(unsigned short old_mtu)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(mtu_plateau); i++)
-		if (old_mtu > mtu_plateau[i])
-			return mtu_plateau[i];
-	return 68;
-}
-
-unsigned short ip_rt_frag_needed(struct net *net, const struct iphdr *iph,
-				 unsigned short new_mtu,
-				 struct net_device *dev)
-{
-	unsigned short old_mtu = ntohs(iph->tot_len);
-	unsigned short est_mtu = 0;
-	struct inet_peer *peer;
-
-	peer = inet_getpeer_v4(iph->daddr, 1);
-	if (peer) {
-		unsigned short mtu = new_mtu;
-
-		if (new_mtu < 68 || new_mtu >= old_mtu) {
-			/* BSD 4.2 derived systems incorrectly adjust
-			 * tot_len by the IP header length, and report
-			 * a zero MTU in the ICMP message.
-			 */
-			if (mtu == 0 &&
-			    old_mtu >= 68 + (iph->ihl << 2))
-				old_mtu -= iph->ihl << 2;
-			mtu = guess_mtu(old_mtu);
-		}
-
-		if (mtu < ip_rt_min_pmtu)
-			mtu = ip_rt_min_pmtu;
-		if (!peer->pmtu_expires || mtu < peer->pmtu_learned) {
-			unsigned long pmtu_expires;
-
-			pmtu_expires = jiffies + ip_rt_mtu_expires;
-			if (!pmtu_expires)
-				pmtu_expires = 1UL;
-
-			est_mtu = mtu;
-			peer->pmtu_learned = mtu;
-			peer->pmtu_expires = pmtu_expires;
-			atomic_inc(&__rt_peer_genid);
-		}
-
-		inet_putpeer(peer);
-	}
-	return est_mtu ? : new_mtu;
-}
-
 static void check_peer_pmtu(struct dst_entry *dst, struct inet_peer *peer)
 {
 	unsigned long expires = ACCESS_ONCE(peer->pmtu_expires);
@@ -1753,9 +1692,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
 
 	dst_confirm(dst);
 
-	if (!rt->peer)
-		rt_bind_peer(rt, rt->rt_dst, 1);
-	peer = rt->peer;
+	peer = rt_get_peer_create(rt, rt->rt_dst);
 	if (peer) {
 		unsigned long pmtu_expires = ACCESS_ONCE(peer->pmtu_expires);
 
@@ -1777,16 +1714,40 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
 	}
 }
 
+void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
+		      int oif, u32 mark, u8 protocol, int flow_flags)
+{
+	const struct iphdr *iph = (const struct iphdr *)skb->data;
+	struct flowi4 fl4;
+	struct rtable *rt;
+
+	flowi4_init_output(&fl4, oif, mark, RT_TOS(iph->tos), RT_SCOPE_UNIVERSE,
+			   protocol, flow_flags | FLOWI_FLAG_PRECOW_METRICS,
+			   iph->daddr, iph->saddr, 0, 0);
+	rt = __ip_route_output_key(net, &fl4);
+	if (!IS_ERR(rt)) {
+		ip_rt_update_pmtu(&rt->dst, mtu);
+		ip_rt_put(rt);
+	}
+}
+EXPORT_SYMBOL_GPL(ipv4_update_pmtu);
+
+void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
+{
+	const struct inet_sock *inet = inet_sk(sk);
+
+	return ipv4_update_pmtu(skb, sock_net(sk), mtu,
+				sk->sk_bound_dev_if, sk->sk_mark,
+				inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
+				inet_sk_flowi_flags(sk));
+}
+EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu);
 
 static void ipv4_validate_peer(struct rtable *rt)
 {
 	if (rt->rt_peer_genid != rt_peer_genid()) {
-		struct inet_peer *peer;
+		struct inet_peer *peer = rt_get_peer(rt, rt->rt_dst);
 
-		if (!rt->peer)
-			rt_bind_peer(rt, rt->rt_dst, 0);
-
-		peer = rt->peer;
 		if (peer) {
 			check_peer_pmtu(&rt->dst, peer);
 
@@ -1812,14 +1773,13 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
 static void ipv4_dst_destroy(struct dst_entry *dst)
 {
 	struct rtable *rt = (struct rtable *) dst;
-	struct inet_peer *peer = rt->peer;
 
 	if (rt->fi) {
 		fib_info_put(rt->fi);
 		rt->fi = NULL;
 	}
-	if (peer) {
-		rt->peer = NULL;
+	if (rt_has_peer(rt)) {
+		struct inet_peer *peer = rt_peer_ptr(rt);
 		inet_putpeer(peer);
 	}
 }
@@ -1832,8 +1792,11 @@ static void ipv4_link_failure(struct sk_buff *skb)
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
 
 	rt = skb_rtable(skb);
-	if (rt && rt->peer && peer_pmtu_cleaned(rt->peer))
-		dst_metric_set(&rt->dst, RTAX_MTU, rt->peer->pmtu_orig);
+	if (rt && rt_has_peer(rt)) {
+		struct inet_peer *peer = rt_peer_ptr(rt);
+		if (peer_pmtu_cleaned(peer))
+			dst_metric_set(&rt->dst, RTAX_MTU, peer->pmtu_orig);
+	}
 }
 
 static int ip_rt_bug(struct sk_buff *skb)
@@ -1935,6 +1898,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
 static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
 			    struct fib_info *fi)
 {
+	struct inet_peer_base *base;
 	struct inet_peer *peer;
 	int create = 0;
 
@@ -1944,8 +1908,12 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
 	if (fl4 && (fl4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS))
 		create = 1;
 
-	rt->peer = peer = inet_getpeer_v4(rt->rt_dst, create);
+	base = inetpeer_base_ptr(rt->_peer);
+	BUG_ON(!base);
+
+	peer = inet_getpeer_v4(base, rt->rt_dst, create);
 	if (peer) {
+		__rt_set_peer(rt, peer);
 		rt->rt_peer_genid = rt_peer_genid();
 		if (inet_metrics_new(peer))
 			memcpy(peer->metrics, fi->fib_metrics,
@@ -1986,8 +1954,6 @@ static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *fl4,
 
 	if (dst_mtu(dst) > IP_MAX_MTU)
 		dst_metric_set(dst, RTAX_MTU, IP_MAX_MTU);
-	if (dst_metric_raw(dst, RTAX_ADVMSS) > 65535 - 40)
-		dst_metric_set(dst, RTAX_ADVMSS, 65535 - 40);
 
 #ifdef CONFIG_IP_ROUTE_CLASSID
 #ifdef CONFIG_IP_MULTIPLE_TABLES
@@ -2023,9 +1989,13 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 		return -EINVAL;
 
 	if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) ||
-	    ipv4_is_loopback(saddr) || skb->protocol != htons(ETH_P_IP))
+	    skb->protocol != htons(ETH_P_IP))
 		goto e_inval;
 
+	if (likely(!IN_DEV_ROUTE_LOCALNET(in_dev)))
+		if (ipv4_is_loopback(saddr))
+			goto e_inval;
+
 	if (ipv4_is_zeronet(saddr)) {
 		if (!ipv4_is_local_multicast(daddr))
 			goto e_inval;
@@ -2061,7 +2031,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 	rth->rt_gateway	= daddr;
 	rth->rt_spec_dst= spec_dst;
 	rth->rt_peer_genid = 0;
-	rth->peer = NULL;
+	rt_init_peer(rth, dev_net(dev)->ipv4.peers);
 	rth->fi = NULL;
 	if (our) {
 		rth->dst.input= ip_local_deliver;
@@ -2189,7 +2159,7 @@ static int __mkroute_input(struct sk_buff *skb,
 	rth->rt_gateway	= daddr;
 	rth->rt_spec_dst= spec_dst;
 	rth->rt_peer_genid = 0;
-	rth->peer = NULL;
+	rt_init_peer(rth, &res->table->tb_peers);
 	rth->fi = NULL;
 
 	rth->dst.input = ip_forward;
@@ -2266,8 +2236,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 	   by fib_lookup.
 	 */
 
-	if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) ||
-	    ipv4_is_loopback(saddr))
+	if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr))
 		goto martian_source;
 
 	if (ipv4_is_lbcast(daddr) || (saddr == 0 && daddr == 0))
@@ -2279,9 +2248,17 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 	if (ipv4_is_zeronet(saddr))
 		goto martian_source;
 
-	if (ipv4_is_zeronet(daddr) || ipv4_is_loopback(daddr))
+	if (ipv4_is_zeronet(daddr))
 		goto martian_destination;
 
+	if (likely(!IN_DEV_ROUTE_LOCALNET(in_dev))) {
+		if (ipv4_is_loopback(daddr))
+			goto martian_destination;
+
+		if (ipv4_is_loopback(saddr))
+			goto martian_source;
+	}
+
 	/*
 	 *	Now we are ready to route packet.
 	 */
@@ -2293,11 +2270,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 	fl4.daddr = daddr;
 	fl4.saddr = saddr;
 	err = fib_lookup(net, &fl4, &res);
-	if (err != 0) {
-		if (!IN_DEV_FORWARD(in_dev))
-			goto e_hostunreach;
+	if (err != 0)
 		goto no_route;
-	}
 
 	RT_CACHE_STAT_INC(in_slow_tot);
 
@@ -2317,7 +2291,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 	}
 
 	if (!IN_DEV_FORWARD(in_dev))
-		goto e_hostunreach;
+		goto no_route;
 	if (res.type != RTN_UNICAST)
 		goto martian_destination;
 
@@ -2372,7 +2346,7 @@ local_input:
 	rth->rt_gateway	= daddr;
 	rth->rt_spec_dst= spec_dst;
 	rth->rt_peer_genid = 0;
-	rth->peer = NULL;
+	rt_init_peer(rth, net->ipv4.peers);
 	rth->fi = NULL;
 	if (res.type == RTN_UNREACHABLE) {
 		rth->dst.input= ip_error;
@@ -2405,10 +2379,6 @@ martian_destination:
 				     &daddr, &saddr, dev->name);
 #endif
 
-e_hostunreach:
-	err = -EHOSTUNREACH;
-	goto out;
-
 e_inval:
 	err = -EINVAL;
 	goto out;
@@ -2520,9 +2490,14 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
 	u16 type = res->type;
 	struct rtable *rth;
 
-	if (ipv4_is_loopback(fl4->saddr) && !(dev_out->flags & IFF_LOOPBACK))
+	in_dev = __in_dev_get_rcu(dev_out);
+	if (!in_dev)
 		return ERR_PTR(-EINVAL);
 
+	if (likely(!IN_DEV_ROUTE_LOCALNET(in_dev)))
+		if (ipv4_is_loopback(fl4->saddr) && !(dev_out->flags & IFF_LOOPBACK))
+			return ERR_PTR(-EINVAL);
+
 	if (ipv4_is_lbcast(fl4->daddr))
 		type = RTN_BROADCAST;
 	else if (ipv4_is_multicast(fl4->daddr))
@@ -2533,10 +2508,6 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
 	if (dev_out->flags & IFF_LOOPBACK)
 		flags |= RTCF_LOCAL;
 
-	in_dev = __in_dev_get_rcu(dev_out);
-	if (!in_dev)
-		return ERR_PTR(-EINVAL);
-
 	if (type == RTN_BROADCAST) {
 		flags |= RTCF_BROADCAST | RTCF_LOCAL;
 		fi = NULL;
@@ -2576,7 +2547,9 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
 	rth->rt_gateway = fl4->daddr;
 	rth->rt_spec_dst= fl4->saddr;
 	rth->rt_peer_genid = 0;
-	rth->peer = NULL;
+	rt_init_peer(rth, (res->table ?
+			   &res->table->tb_peers :
+			   dev_net(dev_out)->ipv4.peers));
 	rth->fi = NULL;
 
 	RT_CACHE_STAT_INC(out_slow_tot);
@@ -2605,6 +2578,9 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
 
 	rt_set_nexthop(rth, fl4, res, fi, type, 0);
 
+	if (fl4->flowi4_flags & FLOWI_FLAG_RT_NOCACHE)
+		rth->dst.flags |= DST_NOCACHE;
+
 	return rth;
 }
 
@@ -2625,6 +2601,7 @@ static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4)
 	int orig_oif;
 
 	res.fi		= NULL;
+	res.table	= NULL;
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 	res.r		= NULL;
 #endif
@@ -2730,6 +2707,7 @@ static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4)
 
 	if (fib_lookup(net, fl4, &res)) {
 		res.fi = NULL;
+		res.table = NULL;
 		if (fl4->flowi4_oif) {
 			/* Apparently, routing tables are wrong. Assume,
 			   that the destination is on link.
@@ -2913,9 +2891,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
 		rt->rt_src = ort->rt_src;
 		rt->rt_gateway = ort->rt_gateway;
 		rt->rt_spec_dst = ort->rt_spec_dst;
-		rt->peer = ort->peer;
-		if (rt->peer)
-			atomic_inc(&rt->peer->refcnt);
+		rt_transfer_peer(rt, ort);
 		rt->fi = ort->fi;
 		if (rt->fi)
 			atomic_inc(&rt->fi->fib_clntref);
@@ -2953,7 +2929,6 @@ static int rt_fill_info(struct net *net,
 	struct rtmsg *r;
 	struct nlmsghdr *nlh;
 	unsigned long expires = 0;
-	const struct inet_peer *peer = rt->peer;
 	u32 id = 0, ts = 0, tsage = 0, error;
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
@@ -3009,8 +2984,9 @@ static int rt_fill_info(struct net *net,
 		goto nla_put_failure;
 
 	error = rt->dst.error;
-	if (peer) {
-		inet_peer_refcheck(rt->peer);
+	if (rt_has_peer(rt)) {
+		const struct inet_peer *peer = rt_peer_ptr(rt);
+		inet_peer_refcheck(peer);
 		id = atomic_read(&peer->ip_id_count) & 0xffff;
 		if (peer->tcp_ts_stamp) {
 			ts = peer->tcp_ts;
@@ -3400,6 +3376,30 @@ static __net_initdata struct pernet_operations rt_genid_ops = {
 	.init = rt_genid_init,
 };
 
+static int __net_init ipv4_inetpeer_init(struct net *net)
+{
+	struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
+
+	if (!bp)
+		return -ENOMEM;
+	inet_peer_base_init(bp);
+	net->ipv4.peers = bp;
+	return 0;
+}
+
+static void __net_exit ipv4_inetpeer_exit(struct net *net)
+{
+	struct inet_peer_base *bp = net->ipv4.peers;
+
+	net->ipv4.peers = NULL;
+	inetpeer_invalidate_tree(bp);
+	kfree(bp);
+}
+
+static __net_initdata struct pernet_operations ipv4_inetpeer_ops = {
+	.init	=	ipv4_inetpeer_init,
+	.exit	=	ipv4_inetpeer_exit,
+};
 
 #ifdef CONFIG_IP_ROUTE_CLASSID
 struct ip_rt_acct __percpu *ip_rt_acct __read_mostly;
@@ -3480,6 +3480,7 @@ int __init ip_rt_init(void)
 	register_pernet_subsys(&sysctl_route_ops);
 #endif
 	register_pernet_subsys(&rt_genid_ops);
+	register_pernet_subsys(&ipv4_inetpeer_ops);
 	return rc;
 }
 
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index ef32956..12aa0c5 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -301,6 +301,13 @@ static struct ctl_table ipv4_table[] = {
 		.proc_handler	= proc_dointvec
 	},
 	{
+		.procname	= "ip_early_demux",
+		.data		= &sysctl_ip_early_demux,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+	{
 		.procname	= "ip_dynaddr",
 		.data		= &sysctl_ip_dynaddr,
 		.maxlen		= sizeof(int),
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index b224eb8..8416f8a 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5518,6 +5518,18 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
 	struct tcp_sock *tp = tcp_sk(sk);
 	int res;
 
+	if (sk->sk_rx_dst) {
+		struct dst_entry *dst = sk->sk_rx_dst;
+		if (unlikely(dst->obsolete)) {
+			if (dst->ops->check(dst, 0) == NULL) {
+				dst_release(dst);
+				sk->sk_rx_dst = NULL;
+			}
+		}
+	}
+	if (unlikely(sk->sk_rx_dst == NULL))
+		sk->sk_rx_dst = dst_clone(skb_dst(skb));
+
 	/*
 	 *	Header prediction.
 	 *	The code loosely follows the one in the famous
@@ -5729,8 +5741,10 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
 
 	tcp_set_state(sk, TCP_ESTABLISHED);
 
-	if (skb != NULL)
+	if (skb != NULL) {
+		sk->sk_rx_dst = dst_clone(skb_dst(skb));
 		security_inet_conn_established(sk, skb);
+	}
 
 	/* Make sure socket is routed, for correct metrics.  */
 	icsk->icsk_af_ops->rebuild_header(sk);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index c8d28c4..1781dc6 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -825,7 +825,8 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
 			      struct request_sock *req,
 			      struct request_values *rvp,
-			      u16 queue_mapping)
+			      u16 queue_mapping,
+			      bool nocache)
 {
 	const struct inet_request_sock *ireq = inet_rsk(req);
 	struct flowi4 fl4;
@@ -833,7 +834,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
 	struct sk_buff * skb;
 
 	/* First, grab a route. */
-	if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)
+	if (!dst && (dst = inet_csk_route_req(sk, &fl4, req, nocache)) == NULL)
 		return -1;
 
 	skb = tcp_make_synack(sk, dst, req, rvp);
@@ -848,7 +849,6 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
 		err = net_xmit_eval(err);
 	}
 
-	dst_release(dst);
 	return err;
 }
 
@@ -856,7 +856,7 @@ static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req,
 			      struct request_values *rvp)
 {
 	TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
-	return tcp_v4_send_synack(sk, NULL, req, rvp, 0);
+	return tcp_v4_send_synack(sk, NULL, req, rvp, 0, false);
 }
 
 /*
@@ -1389,7 +1389,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 		 */
 		if (tmp_opt.saw_tstamp &&
 		    tcp_death_row.sysctl_tw_recycle &&
-		    (dst = inet_csk_route_req(sk, &fl4, req)) != NULL &&
+		    (dst = inet_csk_route_req(sk, &fl4, req, want_cookie)) != NULL &&
 		    fl4.daddr == saddr &&
 		    (peer = rt_get_peer((struct rtable *)dst, fl4.daddr)) != NULL) {
 			inet_peer_refcheck(peer);
@@ -1425,7 +1425,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 
 	if (tcp_v4_send_synack(sk, dst, req,
 			       (struct request_values *)&tmp_ext,
-			       skb_get_queue_mapping(skb)) ||
+			       skb_get_queue_mapping(skb),
+			       want_cookie) ||
 	    want_cookie)
 		goto drop_and_free;
 
@@ -1672,6 +1673,58 @@ csum_err:
 }
 EXPORT_SYMBOL(tcp_v4_do_rcv);
 
+int tcp_v4_early_demux(struct sk_buff *skb)
+{
+	struct net *net = dev_net(skb->dev);
+	const struct iphdr *iph;
+	const struct tcphdr *th;
+	struct net_device *dev;
+	struct sock *sk;
+	int err;
+
+	err = -ENOENT;
+	if (skb->pkt_type != PACKET_HOST)
+		goto out_err;
+
+	if (!pskb_may_pull(skb, ip_hdrlen(skb) + sizeof(struct tcphdr)))
+		goto out_err;
+
+	iph = ip_hdr(skb);
+	th = (struct tcphdr *) ((char *)iph + ip_hdrlen(skb));
+
+	if (th->doff < sizeof(struct tcphdr) / 4)
+		goto out_err;
+
+	if (!pskb_may_pull(skb, ip_hdrlen(skb) + th->doff * 4))
+		goto out_err;
+
+	dev = skb->dev;
+	sk = __inet_lookup_established(net, &tcp_hashinfo,
+				       iph->saddr, th->source,
+				       iph->daddr, ntohs(th->dest),
+				       dev->ifindex);
+	if (sk) {
+		skb->sk = sk;
+		skb->destructor = sock_edemux;
+		if (sk->sk_state != TCP_TIME_WAIT) {
+			struct dst_entry *dst = sk->sk_rx_dst;
+			if (dst)
+				dst = dst_check(dst, 0);
+			if (dst) {
+				struct rtable *rt = (struct rtable *) dst;
+
+				if (rt->rt_iif == dev->ifindex) {
+					skb_dst_set_noref(skb, dst);
+					err = 0;
+				}
+			}
+		}
+	}
+
+out_err:
+	return err;
+}
+
 /*
  *	From tcp_input.c
  */
@@ -1821,40 +1874,25 @@ do_time_wait:
 	goto discard_it;
 }
 
-struct inet_peer *tcp_v4_get_peer(struct sock *sk, bool *release_it)
+struct inet_peer *tcp_v4_get_peer(struct sock *sk)
 {
 	struct rtable *rt = (struct rtable *) __sk_dst_get(sk);
 	struct inet_sock *inet = inet_sk(sk);
-	struct inet_peer *peer;
 
-	if (!rt ||
-	    inet->cork.fl.u.ip4.daddr != inet->inet_daddr) {
-		peer = inet_getpeer_v4(inet->inet_daddr, 1);
-		*release_it = true;
-	} else {
-		if (!rt->peer)
-			rt_bind_peer(rt, inet->inet_daddr, 1);
-		peer = rt->peer;
-		*release_it = false;
-	}
-
-	return peer;
+	/* If we don't have a valid cached route, or we're doing IP
+	 * options which make the IPv4 header destination address
+	 * different from our peer's, do not bother with this.
+	 */
+	if (!rt || inet->cork.fl.u.ip4.daddr != inet->inet_daddr)
+		return NULL;
+	return rt_get_peer_create(rt, inet->inet_daddr);
 }
 EXPORT_SYMBOL(tcp_v4_get_peer);
 
-void *tcp_v4_tw_get_peer(struct sock *sk)
-{
-	const struct inet_timewait_sock *tw = inet_twsk(sk);
-
-	return inet_getpeer_v4(tw->tw_daddr, 1);
-}
-EXPORT_SYMBOL(tcp_v4_tw_get_peer);
-
 static struct timewait_sock_ops tcp_timewait_sock_ops = {
 	.twsk_obj_size	= sizeof(struct tcp_timewait_sock),
 	.twsk_unique	= tcp_twsk_unique,
 	.twsk_destructor= tcp_twsk_destructor,
-	.twsk_getpeer	= tcp_v4_tw_get_peer,
 };
 
 const struct inet_connection_sock_af_ops ipv4_specific = {
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index b85d9fe..72b7c63 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -60,9 +60,8 @@ static bool tcp_remember_stamp(struct sock *sk)
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct inet_peer *peer;
-	bool release_it;
 
-	peer = icsk->icsk_af_ops->get_peer(sk, &release_it);
+	peer = icsk->icsk_af_ops->get_peer(sk);
 	if (peer) {
 		if ((s32)(peer->tcp_ts - tp->rx_opt.ts_recent) <= 0 ||
 		    ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL &&
@@ -70,8 +69,6 @@ static bool tcp_remember_stamp(struct sock *sk)
 			peer->tcp_ts_stamp = (u32)tp->rx_opt.ts_recent_stamp;
 			peer->tcp_ts = tp->rx_opt.ts_recent;
 		}
-		if (release_it)
-			inet_putpeer(peer);
 		return true;
 	}
 
@@ -80,20 +77,19 @@ static bool tcp_remember_stamp(struct sock *sk)
 
 static bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw)
 {
+	const struct tcp_timewait_sock *tcptw;
 	struct sock *sk = (struct sock *) tw;
 	struct inet_peer *peer;
 
-	peer = twsk_getpeer(sk);
+	tcptw = tcp_twsk(sk);
+	peer = tcptw->tw_peer;
 	if (peer) {
-		const struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
-
 		if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 ||
 		    ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL &&
 		     peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) {
 			peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp;
 			peer->tcp_ts	   = tcptw->tw_ts_recent;
 		}
-		inet_putpeer(peer);
 		return true;
 	}
 	return false;
@@ -317,9 +313,12 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 	const struct tcp_sock *tp = tcp_sk(sk);
 	bool recycle_ok = false;
+	bool recycle_on = false;
 
-	if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
+	if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp) {
 		recycle_ok = tcp_remember_stamp(sk);
+		recycle_on = true;
+	}
 
 	if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets)
 		tw = inet_twsk_alloc(sk, state);
@@ -327,8 +326,10 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
 	if (tw != NULL) {
 		struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
 		const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
+		struct inet_sock *inet = inet_sk(sk);
+		struct inet_peer *peer = NULL;
 
-		tw->tw_transparent	= inet_sk(sk)->transparent;
+		tw->tw_transparent	= inet->transparent;
 		tw->tw_rcv_wscale	= tp->rx_opt.rcv_wscale;
 		tcptw->tw_rcv_nxt	= tp->rcv_nxt;
 		tcptw->tw_snd_nxt	= tp->snd_nxt;
@@ -350,6 +351,12 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
 		}
 #endif
 
+		if (recycle_on)
+			peer = icsk->icsk_af_ops->get_peer(sk);
+		tcptw->tw_peer = peer;
+		if (peer)
+			atomic_inc(&peer->refcnt);
+
 #ifdef CONFIG_TCP_MD5SIG
 		/*
 		 * The timewait bucket does not have the key DB from the
@@ -401,8 +408,11 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
 
 void tcp_twsk_destructor(struct sock *sk)
 {
-#ifdef CONFIG_TCP_MD5SIG
 	struct tcp_timewait_sock *twsk = tcp_twsk(sk);
+
+	if (twsk->tw_peer)
+		inet_putpeer(twsk->tw_peer);
+#ifdef CONFIG_TCP_MD5SIG
 	if (twsk->tw_md5_key) {
 		tcp_free_md5sig_pool();
 		kfree_rcu(twsk->tw_md5_key, rcu);
@@ -435,6 +445,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
 		struct tcp_sock *oldtp = tcp_sk(sk);
 		struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
 
+		newsk->sk_rx_dst = dst_clone(skb_dst(skb));
+
 		/* TCP Cookie Transactions require space for the cookie pair,
 		 * as it differs for each connection.  There is no need to
 		 * copy any s_data_payload stored at the original socket.
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 803cbfe..c465d3e 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2442,7 +2442,16 @@ int tcp_send_synack(struct sock *sk)
 	return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
 }
 
-/* Prepare a SYN-ACK. */
+/**
+ * tcp_make_synack - Prepare a SYN-ACK.
+ * sk: listener socket
+ * dst: dst entry attached to the SYNACK
+ * req: request_sock pointer
+ * rvp: request_values pointer
+ *
+ * Allocate one skb and build a SYNACK packet.
+ * @dst is consumed : Caller should not use it again.
+ */
 struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
 				struct request_sock *req,
 				struct request_values *rvp)
@@ -2461,14 +2470,15 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
 
 	if (cvp != NULL && cvp->s_data_constant && cvp->s_data_desired)
 		s_data_desired = cvp->s_data_desired;
-	skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15 + s_data_desired, 1, GFP_ATOMIC);
-	if (skb == NULL)
+	skb = alloc_skb(MAX_TCP_HEADER + 15 + s_data_desired, GFP_ATOMIC);
+	if (unlikely(!skb)) {
+		dst_release(dst);
 		return NULL;
-
+	}
 	/* Reserve space for headers. */
 	skb_reserve(skb, MAX_TCP_HEADER);
 
-	skb_dst_set(skb, dst_clone(dst));
+	skb_dst_set(skb, dst);
 
 	mss = dst_metric_advmss(dst);
 	if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index eaca736..db017ef 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -615,6 +615,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
 		break;
 	case ICMP_DEST_UNREACH:
 		if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
+			ipv4_sk_update_pmtu(skb, sk, info);
 			if (inet->pmtudisc != IP_PMTUDISC_DONT) {
 				err = EMSGSIZE;
 				harderr = 1;
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 0d3426c..8855d82 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -90,9 +90,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
 	xdst->u.dst.dev = dev;
 	dev_hold(dev);
 
-	xdst->u.rt.peer = rt->peer;
-	if (rt->peer)
-		atomic_inc(&rt->peer->refcnt);
+	rt_transfer_peer(&xdst->u.rt, rt);
 
 	/* Sheit... I remember I did this right. Apparently,
 	 * it was magically lost, so this code needs audit */
@@ -212,8 +210,10 @@ static void xfrm4_dst_destroy(struct dst_entry *dst)
 
 	dst_destroy_metrics_generic(dst);
 
-	if (likely(xdst->u.rt.peer))
-		inet_putpeer(xdst->u.rt.peer);
+	if (rt_has_peer(&xdst->u.rt)) {
+		struct inet_peer *peer = rt_peer_ptr(&xdst->u.rt);
+		inet_putpeer(peer);
+	}
 
 	xfrm_dst_destroy(xdst);
 }
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index f1a4a2c..49d4d26 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -35,6 +35,7 @@
 #include <linux/pfkeyv2.h>
 #include <linux/string.h>
 #include <linux/scatterlist.h>
+#include <net/ip6_route.h>
 #include <net/icmp.h>
 #include <net/ipv6.h>
 #include <net/protocol.h>
@@ -621,7 +622,7 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
 	NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/%pI6\n",
 		 ntohl(ah->spi), &iph->daddr);
-
+	ip6_update_pmtu(skb, net, info, 0, 0);
 	xfrm_state_put(x);
 }
 
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index db1521f..89a615b 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -39,6 +39,7 @@
 #include <linux/random.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <net/ip6_route.h>
 #include <net/icmp.h>
 #include <net/ipv6.h>
 #include <net/protocol.h>
@@ -442,6 +443,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 		return;
 	pr_debug("pmtu discovery on SA ESP/%08x/%pI6\n",
 		 ntohl(esph->spi), &iph->daddr);
+	ip6_update_pmtu(skb, net, info, 0, 0);
 	xfrm_state_put(x);
 }
 
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 6447dc4..fa3d9c3 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -791,14 +791,14 @@ static int ipv6_renew_option(void *ohdr,
 		if (ohdr) {
 			memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
 			*hdr = (struct ipv6_opt_hdr *)*p;
-			*p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));
+			*p += CMSG_ALIGN(ipv6_optlen(*hdr));
 		}
 	} else {
 		if (newopt) {
 			if (copy_from_user(*p, newopt, newoptlen))
 				return -EFAULT;
 			*hdr = (struct ipv6_opt_hdr *)*p;
-			if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
+			if (ipv6_optlen(*hdr) > newoptlen)
 				return -EINVAL;
 			*p += CMSG_ALIGN(newoptlen);
 		}
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 091a297..c7da142 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -188,14 +188,14 @@ static inline bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
 	} else {
 		struct rt6_info *rt = (struct rt6_info *)dst;
 		int tmo = net->ipv6.sysctl.icmpv6_time;
+		struct inet_peer *peer;
 
 		/* Give more bandwidth to wider prefixes. */
 		if (rt->rt6i_dst.plen < 128)
 			tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
 
-		if (!rt->rt6i_peer)
-			rt6_bind_peer(rt, 1);
-		res = inet_peer_xrlim_allow(rt->rt6i_peer, tmo);
+		peer = rt6_get_peer_create(rt);
+		res = inet_peer_xrlim_allow(peer, tmo);
 	}
 	dst_release(dst);
 	return res;
@@ -600,9 +600,8 @@ static void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
 {
 	const struct inet6_protocol *ipprot;
 	int inner_offset;
-	int hash;
-	u8 nexthdr;
 	__be16 frag_off;
+	u8 nexthdr;
 
 	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 		return;
@@ -629,10 +628,8 @@ static void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
 	   --ANK (980726)
 	 */
 
-	hash = nexthdr & (MAX_INET_PROTOS - 1);
-
 	rcu_read_lock();
-	ipprot = rcu_dereference(inet6_protos[hash]);
+	ipprot = rcu_dereference(inet6_protos[nexthdr]);
 	if (ipprot && ipprot->err_handler)
 		ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
 	rcu_read_unlock();
@@ -649,7 +646,6 @@ static int icmpv6_rcv(struct sk_buff *skb)
 	struct net_device *dev = skb->dev;
 	struct inet6_dev *idev = __in6_dev_get(dev);
 	const struct in6_addr *saddr, *daddr;
-	const struct ipv6hdr *orig_hdr;
 	struct icmp6hdr *hdr;
 	u8 type;
 
@@ -661,7 +657,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
 				 XFRM_STATE_ICMP))
 			goto drop_no_count;
 
-		if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(*orig_hdr)))
+		if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
 			goto drop_no_count;
 
 		nh = skb_network_offset(skb);
@@ -722,9 +718,6 @@ static int icmpv6_rcv(struct sk_buff *skb)
 		if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 			goto discard_it;
 		hdr = icmp6_hdr(skb);
-		orig_hdr = (struct ipv6hdr *) (hdr + 1);
-		rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
-				   ntohl(hdr->icmp6_mtu));
 
 		/*
 		 *	Drop through to notify
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 74c21b9..13690d6 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -197,6 +197,7 @@ static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
 		table->tb6_id = id;
 		table->tb6_root.leaf = net->ipv6.ip6_null_entry;
 		table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
+		inet_peer_base_init(&table->tb6_peers);
 	}
 
 	return table;
@@ -1349,8 +1350,8 @@ static int fib6_walk_continue(struct fib6_walker_t *w)
 			if (w->leaf && fn->fn_flags & RTN_RTINFO) {
 				int err;
 
-				if (w->count < w->skip) {
-					w->count++;
+				if (w->skip) {
+					w->skip--;
 					continue;
 				}
 
@@ -1633,6 +1634,7 @@ static int __net_init fib6_net_init(struct net *net)
 	net->ipv6.fib6_main_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
 	net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
 		RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
+	inet_peer_base_init(&net->ipv6.fib6_main_tbl->tb6_peers);
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 	net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl),
@@ -1643,6 +1645,7 @@ static int __net_init fib6_net_init(struct net *net)
 	net->ipv6.fib6_local_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
 	net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
 		RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
+	inet_peer_base_init(&net->ipv6.fib6_local_tbl->tb6_peers);
 #endif
 	fib6_tables_init(net);
 
@@ -1666,8 +1669,10 @@ static void fib6_net_exit(struct net *net)
 	del_timer_sync(&net->ipv6.ip6_fib_timer);
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+	inetpeer_invalidate_tree(&net->ipv6.fib6_local_tbl->tb6_peers);
 	kfree(net->ipv6.fib6_local_tbl);
 #endif
+	inetpeer_invalidate_tree(&net->ipv6.fib6_main_tbl->tb6_peers);
 	kfree(net->ipv6.fib6_main_tbl);
 	kfree(net->ipv6.fib_table_hash);
 	kfree(net->ipv6.rt6_stats);
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 21a15df..5ab923e 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -168,13 +168,12 @@ drop:
 
 static int ip6_input_finish(struct sk_buff *skb)
 {
+	struct net *net = dev_net(skb_dst(skb)->dev);
 	const struct inet6_protocol *ipprot;
+	struct inet6_dev *idev;
 	unsigned int nhoff;
 	int nexthdr;
 	bool raw;
-	u8 hash;
-	struct inet6_dev *idev;
-	struct net *net = dev_net(skb_dst(skb)->dev);
 
 	/*
 	 *	Parse extension headers
@@ -189,9 +188,7 @@ resubmit:
 	nexthdr = skb_network_header(skb)[nhoff];
 
 	raw = raw6_local_deliver(skb, nexthdr);
-
-	hash = nexthdr & (MAX_INET_PROTOS - 1);
-	if ((ipprot = rcu_dereference(inet6_protos[hash])) != NULL) {
+	if ((ipprot = rcu_dereference(inet6_protos[nexthdr])) != NULL) {
 		int ret;
 
 		if (ipprot->flags & INET6_PROTO_FINAL) {
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index decc21d1..a233a7c 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -83,19 +83,6 @@ int ip6_local_out(struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(ip6_local_out);
 
-/* dev_loopback_xmit for use with netfilter. */
-static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
-{
-	skb_reset_mac_header(newskb);
-	__skb_pull(newskb, skb_network_offset(newskb));
-	newskb->pkt_type = PACKET_LOOPBACK;
-	newskb->ip_summed = CHECKSUM_UNNECESSARY;
-	WARN_ON(!skb_dst(newskb));
-
-	netif_rx_ni(newskb);
-	return 0;
-}
-
 static int ip6_finish_output2(struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb_dst(skb);
@@ -121,7 +108,7 @@ static int ip6_finish_output2(struct sk_buff *skb)
 			if (newskb)
 				NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING,
 					newskb, NULL, newskb->dev,
-					ip6_dev_loopback_xmit);
+					dev_loopback_xmit);
 
 			if (ipv6_hdr(skb)->hop_limit == 0) {
 				IP6_INC_STATS(dev_net(dev), idev,
@@ -463,6 +450,7 @@ int ip6_forward(struct sk_buff *skb)
 	 */
 	if (skb->dev == dst->dev && opt->srcrt == 0 && !skb_sec_path(skb)) {
 		struct in6_addr *target = NULL;
+		struct inet_peer *peer;
 		struct rt6_info *rt;
 
 		/*
@@ -476,13 +464,12 @@ int ip6_forward(struct sk_buff *skb)
 		else
 			target = &hdr->daddr;
 
-		if (!rt->rt6i_peer)
-			rt6_bind_peer(rt, 1);
+		peer = rt6_get_peer_create(rt);
 
 		/* Limit redirects both by destination (here)
 		   and by source (inside ndisc_send_redirect)
 		 */
-		if (inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ))
+		if (inet_peer_xrlim_allow(peer, 1*HZ))
 			ndisc_send_redirect(skb, target);
 	} else {
 		int addrtype = ipv6_addr_type(&hdr->saddr);
@@ -603,11 +590,8 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
 	int old, new;
 
 	if (rt && !(rt->dst.flags & DST_NOPEER)) {
-		struct inet_peer *peer;
+		struct inet_peer *peer = rt6_get_peer_create(rt);
 
-		if (!rt->rt6i_peer)
-			rt6_bind_peer(rt, 1);
-		peer = rt->rt6i_peer;
 		if (peer) {
 			fhdr->identification = htonl(inet_getid(peer, 0));
 			return;
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 5cb75bf..9283238 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -46,6 +46,7 @@
 #include <linux/list.h>
 #include <linux/vmalloc.h>
 #include <linux/rtnetlink.h>
+#include <net/ip6_route.h>
 #include <net/icmp.h>
 #include <net/ipv6.h>
 #include <net/protocol.h>
@@ -74,6 +75,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
 	pr_debug("pmtu discovery on SA IPCOMP/%08x/%pI6\n",
 		 spi, &iph->daddr);
+	ip6_update_pmtu(skb, net, info, 0, 0);
 	xfrm_state_put(x);
 }
 
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 54f62d3..69a6330 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1472,6 +1472,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	struct net *net = dev_net(dev);
 	struct sock *sk = net->ipv6.ndisc_sk;
 	int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
+	struct inet_peer *peer;
 	struct sk_buff *buff;
 	struct icmp6hdr *icmph;
 	struct in6_addr saddr_buf;
@@ -1518,9 +1519,8 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 			  "Redirect: destination is not a neighbour\n");
 		goto release;
 	}
-	if (!rt->rt6i_peer)
-		rt6_bind_peer(rt, 1);
-	if (!inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ))
+	peer = rt6_get_peer_create(rt);
+	if (!inet_peer_xrlim_allow(peer, 1*HZ))
 		goto release;
 
 	if (dev->addr_len) {
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 3224ef9..4794f96 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -143,11 +143,11 @@ static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
 	return NF_ACCEPT;
 }
 
-static unsigned int ipv6_confirm(unsigned int hooknum,
-				 struct sk_buff *skb,
-				 const struct net_device *in,
-				 const struct net_device *out,
-				 int (*okfn)(struct sk_buff *))
+static unsigned int ipv6_helper(unsigned int hooknum,
+				struct sk_buff *skb,
+				const struct net_device *in,
+				const struct net_device *out,
+				int (*okfn)(struct sk_buff *))
 {
 	struct nf_conn *ct;
 	const struct nf_conn_help *help;
@@ -161,15 +161,15 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
 	/* This is where we call the helper: as the packet goes out. */
 	ct = nf_ct_get(skb, &ctinfo);
 	if (!ct || ctinfo == IP_CT_RELATED_REPLY)
-		goto out;
+		return NF_ACCEPT;
 
 	help = nfct_help(ct);
 	if (!help)
-		goto out;
+		return NF_ACCEPT;
 	/* rcu_read_lock()ed by nf_hook_slow */
 	helper = rcu_dereference(help->helper);
 	if (!helper)
-		goto out;
+		return NF_ACCEPT;
 
 	protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum,
 					 skb->len - extoff);
@@ -179,12 +179,19 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
 	}
 
 	ret = helper->help(skb, protoff, ct, ctinfo);
-	if (ret != NF_ACCEPT) {
+	if (ret != NF_ACCEPT && (ret & NF_VERDICT_MASK) != NF_QUEUE) {
 		nf_log_packet(NFPROTO_IPV6, hooknum, skb, in, out, NULL,
 			      "nf_ct_%s: dropping packet", helper->name);
-		return ret;
 	}
-out:
+	return ret;
+}
+
+static unsigned int ipv6_confirm(unsigned int hooknum,
+				 struct sk_buff *skb,
+				 const struct net_device *in,
+				 const struct net_device *out,
+				 int (*okfn)(struct sk_buff *))
+{
 	/* We've seen it coming out the other side: confirm it */
 	return nf_conntrack_confirm(skb);
 }
@@ -254,6 +261,13 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
 		.priority	= NF_IP6_PRI_CONNTRACK,
 	},
 	{
+		.hook		= ipv6_helper,
+		.owner		= THIS_MODULE,
+		.pf		= NFPROTO_IPV6,
+		.hooknum	= NF_INET_POST_ROUTING,
+		.priority	= NF_IP6_PRI_CONNTRACK_HELPER,
+	},
+	{
 		.hook		= ipv6_confirm,
 		.owner		= THIS_MODULE,
 		.pf		= NFPROTO_IPV6,
@@ -261,6 +275,13 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
 		.priority	= NF_IP6_PRI_LAST,
 	},
 	{
+		.hook		= ipv6_helper,
+		.owner		= THIS_MODULE,
+		.pf		= NFPROTO_IPV6,
+		.hooknum	= NF_INET_LOCAL_IN,
+		.priority	= NF_IP6_PRI_CONNTRACK_HELPER,
+	},
+	{
 		.hook		= ipv6_confirm,
 		.owner		= THIS_MODULE,
 		.pf		= NFPROTO_IPV6,
@@ -333,37 +354,75 @@ MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
 
-static int __init nf_conntrack_l3proto_ipv6_init(void)
+static int ipv6_net_init(struct net *net)
 {
 	int ret = 0;
 
-	need_conntrack();
-	nf_defrag_ipv6_enable();
-
-	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6);
+	ret = nf_conntrack_l4proto_register(net,
+					    &nf_conntrack_l4proto_tcp6);
 	if (ret < 0) {
-		pr_err("nf_conntrack_ipv6: can't register tcp.\n");
-		return ret;
+		printk(KERN_ERR "nf_conntrack_l4proto_tcp6: protocol register failed\n");
+		goto out;
 	}
-
-	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6);
+	ret = nf_conntrack_l4proto_register(net,
+					    &nf_conntrack_l4proto_udp6);
 	if (ret < 0) {
-		pr_err("nf_conntrack_ipv6: can't register udp.\n");
-		goto cleanup_tcp;
+		printk(KERN_ERR "nf_conntrack_l4proto_udp6: protocol register failed\n");
+		goto cleanup_tcp6;
 	}
-
-	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmpv6);
+	ret = nf_conntrack_l4proto_register(net,
+					    &nf_conntrack_l4proto_icmpv6);
 	if (ret < 0) {
-		pr_err("nf_conntrack_ipv6: can't register icmpv6.\n");
-		goto cleanup_udp;
+		printk(KERN_ERR "nf_conntrack_l4proto_icmp6: protocol register failed\n");
+		goto cleanup_udp6;
 	}
-
-	ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6);
+	ret = nf_conntrack_l3proto_register(net,
+					    &nf_conntrack_l3proto_ipv6);
 	if (ret < 0) {
-		pr_err("nf_conntrack_ipv6: can't register ipv6\n");
+		printk(KERN_ERR "nf_conntrack_l3proto_ipv6: protocol register failed\n");
 		goto cleanup_icmpv6;
 	}
+	return 0;
+ cleanup_icmpv6:
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_icmpv6);
+ cleanup_udp6:
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_udp6);
+ cleanup_tcp6:
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_tcp6);
+ out:
+	return ret;
+}
 
+static void ipv6_net_exit(struct net *net)
+{
+	nf_conntrack_l3proto_unregister(net,
+					&nf_conntrack_l3proto_ipv6);
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_icmpv6);
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_udp6);
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_tcp6);
+}
+
+static struct pernet_operations ipv6_net_ops = {
+	.init = ipv6_net_init,
+	.exit = ipv6_net_exit,
+};
+
+static int __init nf_conntrack_l3proto_ipv6_init(void)
+{
+	int ret = 0;
+
+	need_conntrack();
+	nf_defrag_ipv6_enable();
+
+	ret = register_pernet_subsys(&ipv6_net_ops);
+	if (ret < 0)
+		goto cleanup_pernet;
 	ret = nf_register_hooks(ipv6_conntrack_ops,
 				ARRAY_SIZE(ipv6_conntrack_ops));
 	if (ret < 0) {
@@ -374,13 +433,8 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
 	return ret;
 
  cleanup_ipv6:
-	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
- cleanup_icmpv6:
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
- cleanup_udp:
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6);
- cleanup_tcp:
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
+	unregister_pernet_subsys(&ipv6_net_ops);
+ cleanup_pernet:
 	return ret;
 }
 
@@ -388,10 +442,7 @@ static void __exit nf_conntrack_l3proto_ipv6_fini(void)
 {
 	synchronize_net();
 	nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
-	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6);
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
+	unregister_pernet_subsys(&ipv6_net_ops);
 }
 
 module_init(nf_conntrack_l3proto_ipv6_init);
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 3e81904..63ed012 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -29,6 +29,11 @@
 
 static unsigned int nf_ct_icmpv6_timeout __read_mostly = 30*HZ;
 
+static inline struct nf_icmp_net *icmpv6_pernet(struct net *net)
+{
+	return &net->ct.nf_ct_proto.icmpv6;
+}
+
 static bool icmpv6_pkt_to_tuple(const struct sk_buff *skb,
 				unsigned int dataoff,
 				struct nf_conntrack_tuple *tuple)
@@ -90,7 +95,7 @@ static int icmpv6_print_tuple(struct seq_file *s,
 
 static unsigned int *icmpv6_get_timeouts(struct net *net)
 {
-	return &nf_ct_icmpv6_timeout;
+	return &icmpv6_pernet(net)->timeout;
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
@@ -281,16 +286,18 @@ static int icmpv6_nlattr_tuple_size(void)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[],
+					struct net *net, void *data)
 {
 	unsigned int *timeout = data;
+	struct nf_icmp_net *in = icmpv6_pernet(net);
 
 	if (tb[CTA_TIMEOUT_ICMPV6_TIMEOUT]) {
 		*timeout =
 		    ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMPV6_TIMEOUT])) * HZ;
 	} else {
 		/* Set default ICMPv6 timeout. */
-		*timeout = nf_ct_icmpv6_timeout;
+		*timeout = in->timeout;
 	}
 	return 0;
 }
@@ -315,11 +322,9 @@ icmpv6_timeout_nla_policy[CTA_TIMEOUT_ICMPV6_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table_header *icmpv6_sysctl_header;
 static struct ctl_table icmpv6_sysctl_table[] = {
 	{
 		.procname	= "nf_conntrack_icmpv6_timeout",
-		.data		= &nf_ct_icmpv6_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -328,6 +333,22 @@ static struct ctl_table icmpv6_sysctl_table[] = {
 };
 #endif /* CONFIG_SYSCTL */
 
+static int icmpv6_init_net(struct net *net)
+{
+	struct nf_icmp_net *in = icmpv6_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)in;
+	in->timeout = nf_ct_icmpv6_timeout;
+#ifdef CONFIG_SYSCTL
+	pn->ctl_table = kmemdup(icmpv6_sysctl_table,
+				sizeof(icmpv6_sysctl_table),
+				GFP_KERNEL);
+	if (!pn->ctl_table)
+		return -ENOMEM;
+	pn->ctl_table[0].data = &in->timeout;
+#endif
+	return 0;
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
 {
 	.l3proto		= PF_INET6,
@@ -355,8 +376,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
 		.nla_policy	= icmpv6_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-	.ctl_table_header	= &icmpv6_sysctl_header,
-	.ctl_table		= icmpv6_sysctl_table,
-#endif
+	.init_net		= icmpv6_init_net,
 };
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c
index 9a7978f..053082d 100644
--- a/net/ipv6/protocol.c
+++ b/net/ipv6/protocol.c
@@ -29,9 +29,7 @@ const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly;
 
 int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol)
 {
-	int hash = protocol & (MAX_INET_PROTOS - 1);
-
-	return !cmpxchg((const struct inet6_protocol **)&inet6_protos[hash],
+	return !cmpxchg((const struct inet6_protocol **)&inet6_protos[protocol],
 			NULL, prot) ? 0 : -1;
 }
 EXPORT_SYMBOL(inet6_add_protocol);
@@ -42,9 +40,9 @@ EXPORT_SYMBOL(inet6_add_protocol);
 
 int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol)
 {
-	int ret, hash = protocol & (MAX_INET_PROTOS - 1);
+	int ret;
 
-	ret = (cmpxchg((const struct inet6_protocol **)&inet6_protos[hash],
+	ret = (cmpxchg((const struct inet6_protocol **)&inet6_protos[protocol],
 		       prot, NULL) == prot) ? 0 : -1;
 
 	synchronize_net();
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 93d6983..b5c1dcb 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -165,7 +165,7 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
 	saddr = &ipv6_hdr(skb)->saddr;
 	daddr = saddr + 1;
 
-	hash = nexthdr & (MAX_INET_PROTOS - 1);
+	hash = nexthdr & (RAW_HTABLE_SIZE - 1);
 
 	read_lock(&raw_v6_hashinfo.lock);
 	sk = sk_head(&raw_v6_hashinfo.ht[hash]);
@@ -229,7 +229,7 @@ bool raw6_local_deliver(struct sk_buff *skb, int nexthdr)
 {
 	struct sock *raw_sk;
 
-	raw_sk = sk_head(&raw_v6_hashinfo.ht[nexthdr & (MAX_INET_PROTOS - 1)]);
+	raw_sk = sk_head(&raw_v6_hashinfo.ht[nexthdr & (RAW_HTABLE_SIZE - 1)]);
 	if (raw_sk && !ipv6_raw_deliver(skb, nexthdr))
 		raw_sk = NULL;
 
@@ -328,9 +328,10 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb,
 		return;
 
 	harderr = icmpv6_err_convert(type, code, &err);
-	if (type == ICMPV6_PKT_TOOBIG)
+	if (type == ICMPV6_PKT_TOOBIG) {
+		ip6_sk_update_pmtu(skb, sk, info);
 		harderr = (np->pmtudisc == IPV6_PMTUDISC_DO);
-
+	}
 	if (np->recverr) {
 		u8 *payload = skb->data;
 		if (!inet->hdrincl)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 999a982..c518e4e 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -99,10 +99,7 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
 	if (!(rt->dst.flags & DST_HOST))
 		return NULL;
 
-	if (!rt->rt6i_peer)
-		rt6_bind_peer(rt, 1);
-
-	peer = rt->rt6i_peer;
+	peer = rt6_get_peer_create(rt);
 	if (peer) {
 		u32 *old_p = __DST_METRICS_PTR(old);
 		unsigned long prev, new;
@@ -261,16 +258,19 @@ static struct rt6_info ip6_blk_hole_entry_template = {
 #endif
 
 /* allocate dst with ip6_dst_ops */
-static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops,
+static inline struct rt6_info *ip6_dst_alloc(struct net *net,
 					     struct net_device *dev,
-					     int flags)
+					     int flags,
+					     struct fib6_table *table)
 {
-	struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, flags);
+	struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
+					0, 0, flags);
 
-	if (rt)
+	if (rt) {
 		memset(&rt->rt6i_table, 0,
 		       sizeof(*rt) - sizeof(struct dst_entry));
-
+		rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers);
+	}
 	return rt;
 }
 
@@ -278,7 +278,6 @@ static void ip6_dst_destroy(struct dst_entry *dst)
 {
 	struct rt6_info *rt = (struct rt6_info *)dst;
 	struct inet6_dev *idev = rt->rt6i_idev;
-	struct inet_peer *peer = rt->rt6i_peer;
 
 	if (!(rt->dst.flags & DST_HOST))
 		dst_destroy_metrics_generic(dst);
@@ -291,8 +290,8 @@ static void ip6_dst_destroy(struct dst_entry *dst)
 	if (!(rt->rt6i_flags & RTF_EXPIRES) && dst->from)
 		dst_release(dst->from);
 
-	if (peer) {
-		rt->rt6i_peer = NULL;
+	if (rt6_has_peer(rt)) {
+		struct inet_peer *peer = rt6_peer_ptr(rt);
 		inet_putpeer(peer);
 	}
 }
@@ -306,13 +305,20 @@ static u32 rt6_peer_genid(void)
 
 void rt6_bind_peer(struct rt6_info *rt, int create)
 {
+	struct inet_peer_base *base;
 	struct inet_peer *peer;
 
-	peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create);
-	if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL)
-		inet_putpeer(peer);
-	else
-		rt->rt6i_peer_genid = rt6_peer_genid();
+	base = inetpeer_base_ptr(rt->_rt6i_peer);
+	if (!base)
+		return;
+
+	peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create);
+	if (peer) {
+		if (!rt6_set_peer(rt, peer))
+			inet_putpeer(peer);
+		else
+			rt->rt6i_peer_genid = rt6_peer_genid();
+	}
 }
 
 static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
@@ -931,6 +937,8 @@ struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
 {
 	int flags = 0;
 
+	fl6->flowi6_iif = net->loopback_dev->ifindex;
+
 	if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
 		flags |= RT6_LOOKUP_F_IFACE;
 
@@ -952,6 +960,7 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
 	rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, 0, 0);
 	if (rt) {
 		memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry));
+		rt6_init_peer(rt, net->ipv6.peers);
 
 		new = &rt->dst;
 
@@ -996,7 +1005,7 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
 
 	if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) {
 		if (rt->rt6i_peer_genid != rt6_peer_genid()) {
-			if (!rt->rt6i_peer)
+			if (!rt6_has_peer(rt))
 				rt6_bind_peer(rt, 0);
 			rt->rt6i_peer_genid = rt6_peer_genid();
 		}
@@ -1042,7 +1051,10 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
 	struct rt6_info *rt6 = (struct rt6_info*)dst;
 
+	dst_confirm(dst);
 	if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
+		struct net *net = dev_net(dst->dev);
+
 		rt6->rt6i_flags |= RTF_MODIFIED;
 		if (mtu < IPV6_MIN_MTU) {
 			u32 features = dst_metric(dst, RTAX_FEATURES);
@@ -1051,9 +1063,39 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
 			dst_metric_set(dst, RTAX_FEATURES, features);
 		}
 		dst_metric_set(dst, RTAX_MTU, mtu);
+		rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires);
 	}
 }
 
+void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
+		     int oif, u32 mark)
+{
+	const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
+	struct dst_entry *dst;
+	struct flowi6 fl6;
+
+	memset(&fl6, 0, sizeof(fl6));
+	fl6.flowi6_oif = oif;
+	fl6.flowi6_mark = mark;
+	fl6.flowi6_flags = FLOWI_FLAG_PRECOW_METRICS;
+	fl6.daddr = iph->daddr;
+	fl6.saddr = iph->saddr;
+	fl6.flowlabel = (*(__be32 *) iph) & IPV6_FLOWINFO_MASK;
+
+	dst = ip6_route_output(net, NULL, &fl6);
+	if (!dst->error)
+		ip6_rt_update_pmtu(dst, ntohl(mtu));
+	dst_release(dst);
+}
+EXPORT_SYMBOL_GPL(ip6_update_pmtu);
+
+void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
+{
+	ip6_update_pmtu(skb, sock_net(sk), mtu,
+			sk->sk_bound_dev_if, sk->sk_mark);
+}
+EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
+
 static unsigned int ip6_default_advmss(const struct dst_entry *dst)
 {
 	struct net_device *dev = dst->dev;
@@ -1110,7 +1152,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
 	if (unlikely(!idev))
 		return ERR_PTR(-ENODEV);
 
-	rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0);
+	rt = ip6_dst_alloc(net, dev, 0, NULL);
 	if (unlikely(!rt)) {
 		in6_dev_put(idev);
 		dst = ERR_PTR(-ENOMEM);
@@ -1292,7 +1334,7 @@ int ip6_route_add(struct fib6_config *cfg)
 	if (!table)
 		goto out;
 
-	rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL, DST_NOCOUNT);
+	rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT, table);
 
 	if (!rt) {
 		err = -ENOMEM;
@@ -1697,116 +1739,6 @@ out:
 }
 
 /*
- *	Handle ICMP "packet too big" messages
- *	i.e. Path MTU discovery
- */
-
-static void rt6_do_pmtu_disc(const struct in6_addr *daddr, const struct in6_addr *saddr,
-			     struct net *net, u32 pmtu, int ifindex)
-{
-	struct rt6_info *rt, *nrt;
-	int allfrag = 0;
-again:
-	rt = rt6_lookup(net, daddr, saddr, ifindex, 0);
-	if (!rt)
-		return;
-
-	if (rt6_check_expired(rt)) {
-		ip6_del_rt(rt);
-		goto again;
-	}
-
-	if (pmtu >= dst_mtu(&rt->dst))
-		goto out;
-
-	if (pmtu < IPV6_MIN_MTU) {
-		/*
-		 * According to RFC2460, PMTU is set to the IPv6 Minimum Link
-		 * MTU (1280) and a fragment header should always be included
-		 * after a node receiving Too Big message reporting PMTU is
-		 * less than the IPv6 Minimum Link MTU.
-		 */
-		pmtu = IPV6_MIN_MTU;
-		allfrag = 1;
-	}
-
-	/* New mtu received -> path was valid.
-	   They are sent only in response to data packets,
-	   so that this nexthop apparently is reachable. --ANK
-	 */
-	dst_confirm(&rt->dst);
-
-	/* Host route. If it is static, it would be better
-	   not to override it, but add new one, so that
-	   when cache entry will expire old pmtu
-	   would return automatically.
-	 */
-	if (rt->rt6i_flags & RTF_CACHE) {
-		dst_metric_set(&rt->dst, RTAX_MTU, pmtu);
-		if (allfrag) {
-			u32 features = dst_metric(&rt->dst, RTAX_FEATURES);
-			features |= RTAX_FEATURE_ALLFRAG;
-			dst_metric_set(&rt->dst, RTAX_FEATURES, features);
-		}
-		rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
-		rt->rt6i_flags |= RTF_MODIFIED;
-		goto out;
-	}
-
-	/* Network route.
-	   Two cases are possible:
-	   1. It is connected route. Action: COW
-	   2. It is gatewayed route or NONEXTHOP route. Action: clone it.
-	 */
-	if (!dst_get_neighbour_noref_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
-		nrt = rt6_alloc_cow(rt, daddr, saddr);
-	else
-		nrt = rt6_alloc_clone(rt, daddr);
-
-	if (nrt) {
-		dst_metric_set(&nrt->dst, RTAX_MTU, pmtu);
-		if (allfrag) {
-			u32 features = dst_metric(&nrt->dst, RTAX_FEATURES);
-			features |= RTAX_FEATURE_ALLFRAG;
-			dst_metric_set(&nrt->dst, RTAX_FEATURES, features);
-		}
-
-		/* According to RFC 1981, detecting PMTU increase shouldn't be
-		 * happened within 5 mins, the recommended timer is 10 mins.
-		 * Here this route expiration time is set to ip6_rt_mtu_expires
-		 * which is 10 mins. After 10 mins the decreased pmtu is expired
-		 * and detecting PMTU increase will be automatically happened.
-		 */
-		rt6_update_expires(nrt, net->ipv6.sysctl.ip6_rt_mtu_expires);
-		nrt->rt6i_flags |= RTF_DYNAMIC;
-		ip6_ins_rt(nrt);
-	}
-out:
-	dst_release(&rt->dst);
-}
-
-void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *saddr,
-			struct net_device *dev, u32 pmtu)
-{
-	struct net *net = dev_net(dev);
-
-	/*
-	 * RFC 1981 states that a node "MUST reduce the size of the packets it
-	 * is sending along the path" that caused the Packet Too Big message.
-	 * Since it's not possible in the general case to determine which
-	 * interface was used to send the original packet, we update the MTU
-	 * on the interface that will be used to send future packets. We also
-	 * update the MTU on the interface that received the Packet Too Big in
-	 * case the original packet was forced out that interface with
-	 * SO_BINDTODEVICE or similar. This is the next best thing to the
-	 * correct behaviour, which would be to update the MTU on all
-	 * interfaces.
-	 */
-	rt6_do_pmtu_disc(daddr, saddr, net, pmtu, 0);
-	rt6_do_pmtu_disc(daddr, saddr, net, pmtu, dev->ifindex);
-}
-
-/*
  *	Misc support functions
  */
 
@@ -1814,8 +1746,8 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
 				    const struct in6_addr *dest)
 {
 	struct net *net = dev_net(ort->dst.dev);
-	struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops,
-					    ort->dst.dev, 0);
+	struct rt6_info *rt = ip6_dst_alloc(net, ort->dst.dev, 0,
+					    ort->rt6i_table);
 
 	if (rt) {
 		rt->dst.input = ort->dst.input;
@@ -2099,8 +2031,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
 				    bool anycast)
 {
 	struct net *net = dev_net(idev->dev);
-	struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops,
-					    net->loopback_dev, 0);
+	struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL);
 	int err;
 
 	if (!rt) {
@@ -2521,7 +2452,9 @@ static int rt6_fill_node(struct net *net,
 	else
 		expires = INT_MAX;
 
-	peer = rt->rt6i_peer;
+	peer = NULL;
+	if (rt6_has_peer(rt))
+		peer = rt6_peer_ptr(rt);
 	ts = tsage = 0;
 	if (peer && peer->tcp_ts_stamp) {
 		ts = peer->tcp_ts;
@@ -2957,10 +2890,6 @@ static int __net_init ip6_route_net_init(struct net *net)
 	net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
 	net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
 
-#ifdef CONFIG_PROC_FS
-	proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
-	proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
-#endif
 	net->ipv6.ip6_rt_gc_expire = 30*HZ;
 
 	ret = 0;
@@ -2981,10 +2910,6 @@ out_ip6_dst_ops:
 
 static void __net_exit ip6_route_net_exit(struct net *net)
 {
-#ifdef CONFIG_PROC_FS
-	proc_net_remove(net, "ipv6_route");
-	proc_net_remove(net, "rt6_stats");
-#endif
 	kfree(net->ipv6.ip6_null_entry);
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 	kfree(net->ipv6.ip6_prohibit_entry);
@@ -2993,11 +2918,58 @@ static void __net_exit ip6_route_net_exit(struct net *net)
 	dst_entries_destroy(&net->ipv6.ip6_dst_ops);
 }
 
+static int __net_init ip6_route_net_init_late(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+	proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
+	proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
+#endif
+	return 0;
+}
+
+static void __net_exit ip6_route_net_exit_late(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+	proc_net_remove(net, "ipv6_route");
+	proc_net_remove(net, "rt6_stats");
+#endif
+}
+
 static struct pernet_operations ip6_route_net_ops = {
 	.init = ip6_route_net_init,
 	.exit = ip6_route_net_exit,
 };
 
+static int __net_init ipv6_inetpeer_init(struct net *net)
+{
+	struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
+
+	if (!bp)
+		return -ENOMEM;
+	inet_peer_base_init(bp);
+	net->ipv6.peers = bp;
+	return 0;
+}
+
+static void __net_exit ipv6_inetpeer_exit(struct net *net)
+{
+	struct inet_peer_base *bp = net->ipv6.peers;
+
+	net->ipv6.peers = NULL;
+	inetpeer_invalidate_tree(bp);
+	kfree(bp);
+}
+
+static struct pernet_operations ipv6_inetpeer_ops = {
+	.init	=	ipv6_inetpeer_init,
+	.exit	=	ipv6_inetpeer_exit,
+};
+
+static struct pernet_operations ip6_route_net_late_ops = {
+	.init = ip6_route_net_init_late,
+	.exit = ip6_route_net_exit_late,
+};
+
 static struct notifier_block ip6_route_dev_notifier = {
 	.notifier_call = ip6_route_dev_notify,
 	.priority = 0,
@@ -3018,10 +2990,14 @@ int __init ip6_route_init(void)
 	if (ret)
 		goto out_kmem_cache;
 
-	ret = register_pernet_subsys(&ip6_route_net_ops);
+	ret = register_pernet_subsys(&ipv6_inetpeer_ops);
 	if (ret)
 		goto out_dst_entries;
 
+	ret = register_pernet_subsys(&ip6_route_net_ops);
+	if (ret)
+		goto out_register_inetpeer;
+
 	ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
 
 	/* Registering of the loopback is done before this portion of code,
@@ -3047,19 +3023,25 @@ int __init ip6_route_init(void)
 	if (ret)
 		goto xfrm6_init;
 
+	ret = register_pernet_subsys(&ip6_route_net_late_ops);
+	if (ret)
+		goto fib6_rules_init;
+
 	ret = -ENOBUFS;
 	if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
 	    __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
 	    __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
-		goto fib6_rules_init;
+		goto out_register_late_subsys;
 
 	ret = register_netdevice_notifier(&ip6_route_dev_notifier);
 	if (ret)
-		goto fib6_rules_init;
+		goto out_register_late_subsys;
 
 out:
 	return ret;
 
+out_register_late_subsys:
+	unregister_pernet_subsys(&ip6_route_net_late_ops);
 fib6_rules_init:
 	fib6_rules_cleanup();
 xfrm6_init:
@@ -3068,6 +3050,8 @@ out_fib6_init:
 	fib6_gc_cleanup();
 out_register_subsys:
 	unregister_pernet_subsys(&ip6_route_net_ops);
+out_register_inetpeer:
+	unregister_pernet_subsys(&ipv6_inetpeer_ops);
 out_dst_entries:
 	dst_entries_destroy(&ip6_dst_blackhole_ops);
 out_kmem_cache:
@@ -3078,9 +3062,11 @@ out_kmem_cache:
 void ip6_route_cleanup(void)
 {
 	unregister_netdevice_notifier(&ip6_route_dev_notifier);
+	unregister_pernet_subsys(&ip6_route_net_late_ops);
 	fib6_rules_cleanup();
 	xfrm6_fini();
 	fib6_gc_cleanup();
+	unregister_pernet_subsys(&ipv6_inetpeer_ops);
 	unregister_pernet_subsys(&ip6_route_net_ops);
 	dst_entries_destroy(&ip6_dst_blackhole_ops);
 	kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 6041571..49aea94 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -527,9 +527,6 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
 		case ICMP_PORT_UNREACH:
 			/* Impossible event. */
 			return 0;
-		case ICMP_FRAG_NEEDED:
-			/* Soft state for pmtu is maintained by IP core. */
-			return 0;
 		default:
 			/* All others are translated to HOST_UNREACH.
 			   rfc2003 contains "deep thoughts" about NET_UNREACH,
@@ -551,7 +548,17 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
 				skb->dev,
 				iph->daddr,
 				iph->saddr);
-	if (t == NULL || t->parms.iph.daddr == 0)
+	if (t == NULL)
+		goto out;
+
+	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
+		ipv4_update_pmtu(skb, dev_net(skb->dev), info,
+				 t->dev->ifindex, 0, IPPROTO_IPV6, 0);
+		err = 0;
+		goto out;
+	}
+
+	if (t->parms.iph.daddr == 0)
 		goto out;
 
 	err = 0;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 3a9aec2..fc0b96b 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -415,6 +415,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 		} else
 			dst_hold(dst);
 
+		dst->ops->update_pmtu(dst, ntohl(info));
+
 		if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
 			tcp_sync_mss(sk, dst_mtu(dst));
 			tcp_simple_retransmit(sk);
@@ -522,7 +524,6 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
 done:
 	if (opt && opt != np->opt)
 		sock_kfree_s(sk, opt, opt->tot_len);
-	dst_release(dst);
 	return err;
 }
 
@@ -1212,7 +1213,8 @@ have_isn:
 	tcp_rsk(req)->snt_isn = isn;
 	tcp_rsk(req)->snt_synack = tcp_time_stamp;
 
-	security_inet_conn_request(sk, skb, req);
+	if (security_inet_conn_request(sk, skb, req))
+		goto drop_and_release;
 
 	if (tcp_v6_send_synack(sk, req,
 			       (struct request_values *)&tmp_ext,
@@ -1733,42 +1735,24 @@ do_time_wait:
 	goto discard_it;
 }
 
-static struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it)
+static struct inet_peer *tcp_v6_get_peer(struct sock *sk)
 {
 	struct rt6_info *rt = (struct rt6_info *) __sk_dst_get(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
-	struct inet_peer *peer;
-
-	if (!rt ||
-	    !ipv6_addr_equal(&np->daddr, &rt->rt6i_dst.addr)) {
-		peer = inet_getpeer_v6(&np->daddr, 1);
-		*release_it = true;
-	} else {
-		if (!rt->rt6i_peer)
-			rt6_bind_peer(rt, 1);
-		peer = rt->rt6i_peer;
-		*release_it = false;
-	}
-
-	return peer;
-}
-
-static void *tcp_v6_tw_get_peer(struct sock *sk)
-{
-	const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
-	const struct inet_timewait_sock *tw = inet_twsk(sk);
 
-	if (tw->tw_family == AF_INET)
-		return tcp_v4_tw_get_peer(sk);
-
-	return inet_getpeer_v6(&tw6->tw_v6_daddr, 1);
+	/* If we don't have a valid cached route, or we're doing IP
+	 * options which make the IPv6 header destination address
+	 * different from our peer's, do not bother with this.
+	 */
+	if (!rt || !ipv6_addr_equal(&np->daddr, &rt->rt6i_dst.addr))
+		return NULL;
+	return rt6_get_peer_create(rt);
 }
 
 static struct timewait_sock_ops tcp6_timewait_sock_ops = {
 	.twsk_obj_size	= sizeof(struct tcp6_timewait_sock),
 	.twsk_unique	= tcp_twsk_unique,
 	.twsk_destructor= tcp_twsk_destructor,
-	.twsk_getpeer	= tcp_v6_tw_get_peer,
 };
 
 static const struct inet_connection_sock_af_ops ipv6_specific = {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index f05099f..051ad48 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -479,6 +479,9 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	if (sk == NULL)
 		return;
 
+	if (type == ICMPV6_PKT_TOOBIG)
+		ip6_sk_update_pmtu(skb, sk, info);
+
 	np = inet6_sk(sk);
 
 	if (!icmpv6_err_convert(type, code, &err) && !np->recverr)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 8625fba..d749484 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -99,9 +99,7 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
 	if (!xdst->u.rt6.rt6i_idev)
 		return -ENODEV;
 
-	xdst->u.rt6.rt6i_peer = rt->rt6i_peer;
-	if (rt->rt6i_peer)
-		atomic_inc(&rt->rt6i_peer->refcnt);
+	rt6_transfer_peer(&xdst->u.rt6, rt);
 
 	/* Sheit... I remember I did this right. Apparently,
 	 * it was magically lost, so this code needs audit */
@@ -223,8 +221,10 @@ static void xfrm6_dst_destroy(struct dst_entry *dst)
 	if (likely(xdst->u.rt6.rt6i_idev))
 		in6_dev_put(xdst->u.rt6.rt6i_idev);
 	dst_destroy_metrics_generic(dst);
-	if (likely(xdst->u.rt6.rt6i_peer))
-		inet_putpeer(xdst->u.rt6.rt6i_peer);
+	if (rt6_has_peer(&xdst->u.rt6)) {
+		struct inet_peer *peer = rt6_peer_ptr(&xdst->u.rt6);
+		inet_putpeer(peer);
+	}
 	xfrm_dst_destroy(xdst);
 }
 
diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c
index 8b915f3..3089391 100644
--- a/net/irda/ircomm/ircomm_param.c
+++ b/net/irda/ircomm/ircomm_param.c
@@ -99,7 +99,6 @@ pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 };
  */
 int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
 {
-	struct tty_struct *tty;
 	unsigned long flags;
 	struct sk_buff *skb;
 	int count;
@@ -109,10 +108,6 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
-	tty = self->tty;
-	if (!tty)
-		return 0;
-
 	/* Make sure we don't send parameters for raw mode */
 	if (self->service_type == IRCOMM_3_WIRE_RAW)
 		return 0;
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index 6b9d5a0..4e35b45 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -104,6 +104,35 @@ static const struct tty_operations ops = {
 #endif /* CONFIG_PROC_FS */
 };
 
+static void ircomm_port_raise_dtr_rts(struct tty_port *port, int raise)
+{
+	struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb,
+			port);
+	/*
+	 * Here, we use to lock those two guys, but as ircomm_param_request()
+	 * does it itself, I don't see the point (and I see the deadlock).
+	 * Jean II
+	 */
+	if (raise)
+		self->settings.dte |= IRCOMM_RTS | IRCOMM_DTR;
+	else
+		self->settings.dte &= ~(IRCOMM_RTS | IRCOMM_DTR);
+
+	ircomm_param_request(self, IRCOMM_DTE, TRUE);
+}
+
+static int ircomm_port_carrier_raised(struct tty_port *port)
+{
+	struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb,
+			port);
+	return self->settings.dce & IRCOMM_CD;
+}
+
+static const struct tty_port_operations ircomm_port_ops = {
+	.dtr_rts = ircomm_port_raise_dtr_rts,
+	.carrier_raised = ircomm_port_carrier_raised,
+};
+
 /*
  * Function ircomm_tty_init()
  *
@@ -194,7 +223,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	/* Check if already open */
-	if (test_and_set_bit(ASYNC_B_INITIALIZED, &self->flags)) {
+	if (test_and_set_bit(ASYNCB_INITIALIZED, &self->port.flags)) {
 		IRDA_DEBUG(2, "%s(), already open so break out!\n", __func__ );
 		return 0;
 	}
@@ -231,7 +260,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
 
 	return 0;
 err:
-	clear_bit(ASYNC_B_INITIALIZED, &self->flags);
+	clear_bit(ASYNCB_INITIALIZED, &self->port.flags);
 	return ret;
 }
 
@@ -242,25 +271,23 @@ err:
  *
  */
 static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
-				      struct file *filp)
+		struct tty_struct *tty, struct file *filp)
 {
+	struct tty_port *port = &self->port;
 	DECLARE_WAITQUEUE(wait, current);
 	int		retval;
 	int		do_clocal = 0, extra_count = 0;
 	unsigned long	flags;
-	struct tty_struct *tty;
 
 	IRDA_DEBUG(2, "%s()\n", __func__ );
 
-	tty = self->tty;
-
 	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
 		/* nonblock mode is set or port is not enabled */
-		self->flags |= ASYNC_NORMAL_ACTIVE;
+		port->flags |= ASYNC_NORMAL_ACTIVE;
 		IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __func__ );
 		return 0;
 	}
@@ -272,42 +299,34 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
 
 	/* Wait for carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, self->open_count is dropped by one, so that
+	 * this loop, port->count is dropped by one, so that
 	 * mgsl_close() knows when to free things.  We restore it upon
 	 * exit, either normal or abnormal.
 	 */
 
 	retval = 0;
-	add_wait_queue(&self->open_wait, &wait);
+	add_wait_queue(&port->open_wait, &wait);
 
 	IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n",
-	      __FILE__,__LINE__, tty->driver->name, self->open_count );
+	      __FILE__, __LINE__, tty->driver->name, port->count);
 
-	/* As far as I can see, we protect open_count - Jean II */
-	spin_lock_irqsave(&self->spinlock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 	if (!tty_hung_up_p(filp)) {
 		extra_count = 1;
-		self->open_count--;
+		port->count--;
 	}
-	spin_unlock_irqrestore(&self->spinlock, flags);
-	self->blocked_open++;
+	spin_unlock_irqrestore(&port->lock, flags);
+	port->blocked_open++;
 
 	while (1) {
-		if (tty->termios->c_cflag & CBAUD) {
-			/* Here, we use to lock those two guys, but
-			 * as ircomm_param_request() does it itself,
-			 * I don't see the point (and I see the deadlock).
-			 * Jean II */
-			self->settings.dte |= IRCOMM_RTS + IRCOMM_DTR;
-
-			ircomm_param_request(self, IRCOMM_DTE, TRUE);
-		}
+		if (tty->termios->c_cflag & CBAUD)
+			tty_port_raise_dtr_rts(port);
 
 		current->state = TASK_INTERRUPTIBLE;
 
 		if (tty_hung_up_p(filp) ||
-		    !test_bit(ASYNC_B_INITIALIZED, &self->flags)) {
-			retval = (self->flags & ASYNC_HUP_NOTIFY) ?
+		    !test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+			retval = (port->flags & ASYNC_HUP_NOTIFY) ?
 					-EAGAIN : -ERESTARTSYS;
 			break;
 		}
@@ -317,8 +336,8 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
 		 * specified, we cannot return before the IrCOMM link is
 		 * ready
 		 */
-		if (!test_bit(ASYNC_B_CLOSING, &self->flags) &&
-		    (do_clocal || (self->settings.dce & IRCOMM_CD)) &&
+		if (!test_bit(ASYNCB_CLOSING, &port->flags) &&
+		    (do_clocal || tty_port_carrier_raised(port)) &&
 		    self->state == IRCOMM_TTY_READY)
 		{
 			break;
@@ -330,27 +349,27 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
 		}
 
 		IRDA_DEBUG(1, "%s(%d):block_til_ready blocking on %s open_count=%d\n",
-		      __FILE__,__LINE__, tty->driver->name, self->open_count );
+		      __FILE__, __LINE__, tty->driver->name, port->count);
 
 		schedule();
 	}
 
 	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&self->open_wait, &wait);
+	remove_wait_queue(&port->open_wait, &wait);
 
 	if (extra_count) {
 		/* ++ is not atomic, so this should be protected - Jean II */
-		spin_lock_irqsave(&self->spinlock, flags);
-		self->open_count++;
-		spin_unlock_irqrestore(&self->spinlock, flags);
+		spin_lock_irqsave(&port->lock, flags);
+		port->count++;
+		spin_unlock_irqrestore(&port->lock, flags);
 	}
-	self->blocked_open--;
+	port->blocked_open--;
 
 	IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n",
-	      __FILE__,__LINE__, tty->driver->name, self->open_count);
+	      __FILE__, __LINE__, tty->driver->name, port->count);
 
 	if (!retval)
-		self->flags |= ASYNC_NORMAL_ACTIVE;
+		port->flags |= ASYNC_NORMAL_ACTIVE;
 
 	return retval;
 }
@@ -381,6 +400,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 			return -ENOMEM;
 		}
 
+		tty_port_init(&self->port);
+		self->port.ops = &ircomm_port_ops;
 		self->magic = IRCOMM_TTY_MAGIC;
 		self->flow = FLOW_STOP;
 
@@ -388,13 +409,9 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 		INIT_WORK(&self->tqueue, ircomm_tty_do_softint);
 		self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED;
 		self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED;
-		self->close_delay = 5*HZ/10;
-		self->closing_wait = 30*HZ;
 
 		/* Init some important stuff */
 		init_timer(&self->watchdog_timer);
-		init_waitqueue_head(&self->open_wait);
-		init_waitqueue_head(&self->close_wait);
 		spin_lock_init(&self->spinlock);
 
 		/*
@@ -408,27 +425,28 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 		tty->termios->c_oflag = 0;
 
 		/* Insert into hash */
+		/* FIXME there is a window from find to here */
 		hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL);
 	}
 	/* ++ is not atomic, so this should be protected - Jean II */
-	spin_lock_irqsave(&self->spinlock, flags);
-	self->open_count++;
+	spin_lock_irqsave(&self->port.lock, flags);
+	self->port.count++;
 
 	tty->driver_data = self;
-	self->tty = tty;
-	spin_unlock_irqrestore(&self->spinlock, flags);
+	spin_unlock_irqrestore(&self->port.lock, flags);
+	tty_port_tty_set(&self->port, tty);
 
 	IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name,
-		   self->line, self->open_count);
+		   self->line, self->port.count);
 
 	/* Not really used by us, but lets do it anyway */
-	self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	tty->low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	/*
 	 * If the port is the middle of closing, bail out now
 	 */
 	if (tty_hung_up_p(filp) ||
-	    test_bit(ASYNC_B_CLOSING, &self->flags)) {
+	    test_bit(ASYNCB_CLOSING, &self->port.flags)) {
 
 		/* Hm, why are we blocking on ASYNC_CLOSING if we
 		 * do return -EAGAIN/-ERESTARTSYS below anyway?
@@ -438,14 +456,15 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 		 * probably better sleep uninterruptible?
 		 */
 
-		if (wait_event_interruptible(self->close_wait, !test_bit(ASYNC_B_CLOSING, &self->flags))) {
+		if (wait_event_interruptible(self->port.close_wait,
+				!test_bit(ASYNCB_CLOSING, &self->port.flags))) {
 			IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
 				     __func__);
 			return -ERESTARTSYS;
 		}
 
 #ifdef SERIAL_DO_RESTART
-		return (self->flags & ASYNC_HUP_NOTIFY) ?
+		return (self->port.flags & ASYNC_HUP_NOTIFY) ?
 			-EAGAIN : -ERESTARTSYS;
 #else
 		return -EAGAIN;
@@ -469,7 +488,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 	if (ret)
 		return ret;
 
-	ret = ircomm_tty_block_til_ready(self, filp);
+	ret = ircomm_tty_block_til_ready(self, tty, filp);
 	if (ret) {
 		IRDA_DEBUG(2,
 		      "%s(), returning after block_til_ready with %d\n", __func__ ,
@@ -489,81 +508,22 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
-	unsigned long flags;
+	struct tty_port *port = &self->port;
 
 	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-	spin_lock_irqsave(&self->spinlock, flags);
-
-	if (tty_hung_up_p(filp)) {
-		spin_unlock_irqrestore(&self->spinlock, flags);
-
-		IRDA_DEBUG(0, "%s(), returning 1\n", __func__ );
-		return;
-	}
-
-	if ((tty->count == 1) && (self->open_count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  state->count should always
-		 * be one in these conditions.  If it's greater than
-		 * one, we've got real problems, since it means the
-		 * serial port won't be shutdown.
-		 */
-		IRDA_DEBUG(0, "%s(), bad serial port count; "
-			   "tty->count is 1, state->count is %d\n", __func__ ,
-			   self->open_count);
-		self->open_count = 1;
-	}
-
-	if (--self->open_count < 0) {
-		IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n",
-			   __func__, self->line, self->open_count);
-		self->open_count = 0;
-	}
-	if (self->open_count) {
-		spin_unlock_irqrestore(&self->spinlock, flags);
-
-		IRDA_DEBUG(0, "%s(), open count > 0\n", __func__ );
+	if (tty_port_close_start(port, tty, filp) == 0)
 		return;
-	}
-
-	/* Hum... Should be test_and_set_bit ??? - Jean II */
-	set_bit(ASYNC_B_CLOSING, &self->flags);
-
-	/* We need to unlock here (we were unlocking at the end of this
-	 * function), because tty_wait_until_sent() may schedule.
-	 * I don't know if the rest should be protected somehow,
-	 * so someone should check. - Jean II */
-	spin_unlock_irqrestore(&self->spinlock, flags);
-
-	/*
-	 * Now we wait for the transmit buffer to clear; and we notify
-	 * the line discipline to only process XON/XOFF characters.
-	 */
-	tty->closing = 1;
-	if (self->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent_from_close(tty, self->closing_wait);
 
 	ircomm_tty_shutdown(self);
 
 	tty_driver_flush_buffer(tty);
-	tty_ldisc_flush(tty);
 
-	tty->closing = 0;
-	self->tty = NULL;
-
-	if (self->blocked_open) {
-		if (self->close_delay)
-			schedule_timeout_interruptible(self->close_delay);
-		wake_up_interruptible(&self->open_wait);
-	}
-
-	self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&self->close_wait);
+	tty_port_close_end(port, tty);
+	tty_port_tty_set(port, NULL);
 }
 
 /*
@@ -606,7 +566,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
 	if (!self || self->magic != IRCOMM_TTY_MAGIC)
 		return;
 
-	tty = self->tty;
+	tty = tty_port_tty_get(&self->port);
 	if (!tty)
 		return;
 
@@ -627,7 +587,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
 	}
 
 	if (tty->hw_stopped)
-		return;
+		goto put;
 
 	/* Unlink transmit buffer */
 	spin_lock_irqsave(&self->spinlock, flags);
@@ -646,6 +606,8 @@ static void ircomm_tty_do_softint(struct work_struct *work)
 
 	/* Check if user (still) wants to be waken up */
 	tty_wakeup(tty);
+put:
+	tty_kref_put(tty);
 }
 
 /*
@@ -955,7 +917,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
 
 	IRDA_DEBUG(0, "%s()\n", __func__ );
 
-	if (!test_and_clear_bit(ASYNC_B_INITIALIZED, &self->flags))
+	if (!test_and_clear_bit(ASYNCB_INITIALIZED, &self->port.flags))
 		return;
 
 	ircomm_tty_detach_cable(self);
@@ -994,6 +956,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
 static void ircomm_tty_hangup(struct tty_struct *tty)
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+	struct tty_port *port = &self->port;
 	unsigned long	flags;
 
 	IRDA_DEBUG(0, "%s()\n", __func__ );
@@ -1004,14 +967,17 @@ static void ircomm_tty_hangup(struct tty_struct *tty)
 	/* ircomm_tty_flush_buffer(tty); */
 	ircomm_tty_shutdown(self);
 
-	/* I guess we need to lock here - Jean II */
-	spin_lock_irqsave(&self->spinlock, flags);
-	self->flags &= ~ASYNC_NORMAL_ACTIVE;
-	self->tty = NULL;
-	self->open_count = 0;
-	spin_unlock_irqrestore(&self->spinlock, flags);
+	spin_lock_irqsave(&port->lock, flags);
+	port->flags &= ~ASYNC_NORMAL_ACTIVE;
+	if (port->tty) {
+		set_bit(TTY_IO_ERROR, &port->tty->flags);
+		tty_kref_put(port->tty);
+	}
+	port->tty = NULL;
+	port->count = 0;
+	spin_unlock_irqrestore(&port->lock, flags);
 
-	wake_up_interruptible(&self->open_wait);
+	wake_up_interruptible(&port->open_wait);
 }
 
 /*
@@ -1071,20 +1037,20 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-	tty = self->tty;
+	tty = tty_port_tty_get(&self->port);
 
 	status = self->settings.dce;
 
 	if (status & IRCOMM_DCE_DELTA_ANY) {
 		/*wake_up_interruptible(&self->delta_msr_wait);*/
 	}
-	if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
+	if ((self->port.flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
 		IRDA_DEBUG(2,
 			   "%s(), ircomm%d CD now %s...\n", __func__ , self->line,
 			   (status & IRCOMM_CD) ? "on" : "off");
 
 		if (status & IRCOMM_CD) {
-			wake_up_interruptible(&self->open_wait);
+			wake_up_interruptible(&self->port.open_wait);
 		} else {
 			IRDA_DEBUG(2,
 				   "%s(), Doing serial hangup..\n", __func__ );
@@ -1092,10 +1058,10 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
 				tty_hangup(tty);
 
 			/* Hangup will remote the tty, so better break out */
-			return;
+			goto put;
 		}
 	}
-	if (self->flags & ASYNC_CTS_FLOW) {
+	if (tty && self->port.flags & ASYNC_CTS_FLOW) {
 		if (tty->hw_stopped) {
 			if (status & IRCOMM_CTS) {
 				IRDA_DEBUG(2,
@@ -1103,10 +1069,10 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
 				tty->hw_stopped = 0;
 
 				/* Wake up processes blocked on open */
-				wake_up_interruptible(&self->open_wait);
+				wake_up_interruptible(&self->port.open_wait);
 
 				schedule_work(&self->tqueue);
-				return;
+				goto put;
 			}
 		} else {
 			if (!(status & IRCOMM_CTS)) {
@@ -1116,6 +1082,8 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
 			}
 		}
 	}
+put:
+	tty_kref_put(tty);
 }
 
 /*
@@ -1128,6 +1096,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
 				      struct sk_buff *skb)
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+	struct tty_struct *tty;
 
 	IRDA_DEBUG(2, "%s()\n", __func__ );
 
@@ -1135,7 +1104,8 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 	IRDA_ASSERT(skb != NULL, return -1;);
 
-	if (!self->tty) {
+	tty = tty_port_tty_get(&self->port);
+	if (!tty) {
 		IRDA_DEBUG(0, "%s(), no tty!\n", __func__ );
 		return 0;
 	}
@@ -1146,7 +1116,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
 	 * Devices like WinCE can do this, and since they don't send any
 	 * params, we can just as well declare the hardware for running.
 	 */
-	if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
+	if (tty->hw_stopped && (self->flow == FLOW_START)) {
 		IRDA_DEBUG(0, "%s(), polling for line settings!\n", __func__ );
 		ircomm_param_request(self, IRCOMM_POLL, TRUE);
 
@@ -1159,8 +1129,9 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
 	 * Use flip buffer functions since the code may be called from interrupt
 	 * context
 	 */
-	tty_insert_flip_string(self->tty, skb->data, skb->len);
-	tty_flip_buffer_push(self->tty);
+	tty_insert_flip_string(tty, skb->data, skb->len);
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
 
 	/* No need to kfree_skb - see ircomm_ttp_data_indication() */
 
@@ -1211,12 +1182,13 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-	tty = self->tty;
+	tty = tty_port_tty_get(&self->port);
 
 	switch (cmd) {
 	case FLOW_START:
 		IRDA_DEBUG(2, "%s(), hw start!\n", __func__ );
-		tty->hw_stopped = 0;
+		if (tty)
+			tty->hw_stopped = 0;
 
 		/* ircomm_tty_do_softint will take care of the rest */
 		schedule_work(&self->tqueue);
@@ -1224,15 +1196,19 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
 	default:  /* If we get here, something is very wrong, better stop */
 	case FLOW_STOP:
 		IRDA_DEBUG(2, "%s(), hw stopped!\n", __func__ );
-		tty->hw_stopped = 1;
+		if (tty)
+			tty->hw_stopped = 1;
 		break;
 	}
+
+	tty_kref_put(tty);
 	self->flow = cmd;
 }
 
 #ifdef CONFIG_PROC_FS
 static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
 {
+	struct tty_struct *tty;
 	char sep;
 
 	seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]);
@@ -1328,40 +1304,43 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
 
 	seq_puts(m, "Flags:");
 	sep = ' ';
-	if (self->flags & ASYNC_CTS_FLOW) {
+	if (self->port.flags & ASYNC_CTS_FLOW) {
 		seq_printf(m, "%cASYNC_CTS_FLOW", sep);
 		sep = '|';
 	}
-	if (self->flags & ASYNC_CHECK_CD) {
+	if (self->port.flags & ASYNC_CHECK_CD) {
 		seq_printf(m, "%cASYNC_CHECK_CD", sep);
 		sep = '|';
 	}
-	if (self->flags & ASYNC_INITIALIZED) {
+	if (self->port.flags & ASYNC_INITIALIZED) {
 		seq_printf(m, "%cASYNC_INITIALIZED", sep);
 		sep = '|';
 	}
-	if (self->flags & ASYNC_LOW_LATENCY) {
+	if (self->port.flags & ASYNC_LOW_LATENCY) {
 		seq_printf(m, "%cASYNC_LOW_LATENCY", sep);
 		sep = '|';
 	}
-	if (self->flags & ASYNC_CLOSING) {
+	if (self->port.flags & ASYNC_CLOSING) {
 		seq_printf(m, "%cASYNC_CLOSING", sep);
 		sep = '|';
 	}
-	if (self->flags & ASYNC_NORMAL_ACTIVE) {
+	if (self->port.flags & ASYNC_NORMAL_ACTIVE) {
 		seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep);
 		sep = '|';
 	}
 	seq_putc(m, '\n');
 
 	seq_printf(m, "Role: %s\n", self->client ? "client" : "server");
-	seq_printf(m, "Open count: %d\n", self->open_count);
+	seq_printf(m, "Open count: %d\n", self->port.count);
 	seq_printf(m, "Max data size: %d\n", self->max_data_size);
 	seq_printf(m, "Max header size: %d\n", self->max_header_size);
 
-	if (self->tty)
+	tty = tty_port_tty_get(&self->port);
+	if (tty) {
 		seq_printf(m, "Hardware: %s\n",
-			       self->tty->hw_stopped ? "Stopped" : "Running");
+			       tty->hw_stopped ? "Stopped" : "Running");
+		tty_kref_put(tty);
+	}
 }
 
 static int ircomm_tty_proc_show(struct seq_file *m, void *v)
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
index b65d66e..3ab70e7 100644
--- a/net/irda/ircomm/ircomm_tty_attach.c
+++ b/net/irda/ircomm/ircomm_tty_attach.c
@@ -130,6 +130,8 @@ static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
  */
 int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
 {
+	struct tty_struct *tty;
+
 	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
@@ -142,7 +144,11 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
 	}
 
 	/* Make sure nobody tries to write before the link is up */
-	self->tty->hw_stopped = 1;
+	tty = tty_port_tty_get(&self->port);
+	if (tty) {
+		tty->hw_stopped = 1;
+		tty_kref_put(tty);
+	}
 
 	ircomm_tty_ias_register(self);
 
@@ -398,23 +404,26 @@ void ircomm_tty_disconnect_indication(void *instance, void *sap,
 				      struct sk_buff *skb)
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+	struct tty_struct *tty;
 
 	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-	if (!self->tty)
+	tty = tty_port_tty_get(&self->port);
+	if (!tty)
 		return;
 
 	/* This will stop control data transfers */
 	self->flow = FLOW_STOP;
 
 	/* Stop data transfers */
-	self->tty->hw_stopped = 1;
+	tty->hw_stopped = 1;
 
 	ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL,
 			    NULL);
+	tty_kref_put(tty);
 }
 
 /*
@@ -550,12 +559,15 @@ void ircomm_tty_connect_indication(void *instance, void *sap,
  */
 void ircomm_tty_link_established(struct ircomm_tty_cb *self)
 {
+	struct tty_struct *tty;
+
 	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-	if (!self->tty)
+	tty = tty_port_tty_get(&self->port);
+	if (!tty)
 		return;
 
 	del_timer(&self->watchdog_timer);
@@ -566,19 +578,22 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
 	 * will have to wait for the peer device (DCE) to raise the CTS
 	 * line.
 	 */
-	if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
+	if ((self->port.flags & ASYNC_CTS_FLOW) &&
+			((self->settings.dce & IRCOMM_CTS) == 0)) {
 		IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ );
-		return;
+		goto put;
 	} else {
 		IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ );
 
-		self->tty->hw_stopped = 0;
+		tty->hw_stopped = 0;
 
 		/* Wake up processes blocked on open */
-		wake_up_interruptible(&self->open_wait);
+		wake_up_interruptible(&self->port.open_wait);
 	}
 
 	schedule_work(&self->tqueue);
+put:
+	tty_kref_put(tty);
 }
 
 /*
@@ -977,14 +992,17 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
 		ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
 		ircomm_tty_start_watchdog_timer(self, 3*HZ);
 
-		if (self->flags & ASYNC_CHECK_CD) {
+		if (self->port.flags & ASYNC_CHECK_CD) {
 			/* Drop carrier */
 			self->settings.dce = IRCOMM_DELTA_CD;
 			ircomm_tty_check_modem_status(self);
 		} else {
+			struct tty_struct *tty = tty_port_tty_get(&self->port);
 			IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
-			if (self->tty)
-				tty_hangup(self->tty);
+			if (tty) {
+				tty_hangup(tty);
+				tty_kref_put(tty);
+			}
 		}
 		break;
 	default:
diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c
index d0667d6..0eab650 100644
--- a/net/irda/ircomm/ircomm_tty_ioctl.c
+++ b/net/irda/ircomm/ircomm_tty_ioctl.c
@@ -52,17 +52,18 @@
  *    Change speed of the driver. If the remote device is a DCE, then this
  *    should make it change the speed of its serial port
  */
-static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
+static void ircomm_tty_change_speed(struct ircomm_tty_cb *self,
+		struct tty_struct *tty)
 {
 	unsigned int cflag, cval;
 	int baud;
 
 	IRDA_DEBUG(2, "%s()\n", __func__ );
 
-	if (!self->tty || !self->tty->termios || !self->ircomm)
+	if (!self->ircomm)
 		return;
 
-	cflag = self->tty->termios->c_cflag;
+	cflag = tty->termios->c_cflag;
 
 	/*  byte size and parity */
 	switch (cflag & CSIZE) {
@@ -81,7 +82,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
 		cval |= IRCOMM_PARITY_EVEN;
 
 	/* Determine divisor based on baud rate */
-	baud = tty_get_baud_rate(self->tty);
+	baud = tty_get_baud_rate(tty);
 	if (!baud)
 		baud = 9600;	/* B0 transition handled in rs_set_termios */
 
@@ -90,19 +91,19 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
 
 	/* CTS flow control flag and modem status interrupts */
 	if (cflag & CRTSCTS) {
-		self->flags |= ASYNC_CTS_FLOW;
+		self->port.flags |= ASYNC_CTS_FLOW;
 		self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
 		/* This got me. Bummer. Jean II */
 		if (self->service_type == IRCOMM_3_WIRE_RAW)
 			IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __func__);
 	} else {
-		self->flags &= ~ASYNC_CTS_FLOW;
+		self->port.flags &= ~ASYNC_CTS_FLOW;
 		self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
 	}
 	if (cflag & CLOCAL)
-		self->flags &= ~ASYNC_CHECK_CD;
+		self->port.flags &= ~ASYNC_CHECK_CD;
 	else
-		self->flags |= ASYNC_CHECK_CD;
+		self->port.flags |= ASYNC_CHECK_CD;
 #if 0
 	/*
 	 * Set up parity check flag
@@ -159,7 +160,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
 		return;
 	}
 
-	ircomm_tty_change_speed(self);
+	ircomm_tty_change_speed(self, tty);
 
 	/* Handle transition to B0 status */
 	if ((old_termios->c_cflag & CBAUD) &&
@@ -270,10 +271,10 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
 
 	memset(&info, 0, sizeof(info));
 	info.line = self->line;
-	info.flags = self->flags;
+	info.flags = self->port.flags;
 	info.baud_base = self->settings.data_rate;
-	info.close_delay = self->close_delay;
-	info.closing_wait = self->closing_wait;
+	info.close_delay = self->port.close_delay;
+	info.closing_wait = self->port.closing_wait;
 
 	/* For compatibility  */
 	info.type = PORT_16550A;
diff --git a/net/irda/irqueue.c b/net/irda/irqueue.c
index f06947c..7152624 100644
--- a/net/irda/irqueue.c
+++ b/net/irda/irqueue.c
@@ -523,7 +523,7 @@ void *hashbin_remove_first( hashbin_t *hashbin)
 		 * Dequeue the entry...
 		 */
 		dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
-				 (irda_queue_t*) entry );
+				 entry);
 		hashbin->hb_size--;
 		entry->q_next = NULL;
 		entry->q_prev = NULL;
@@ -615,7 +615,7 @@ void* hashbin_remove( hashbin_t* hashbin, long hashv, const char* name)
 	 */
 	if ( found ) {
 		dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
-				 (irda_queue_t*) entry );
+				 entry);
 		hashbin->hb_size--;
 
 		/*
@@ -685,7 +685,7 @@ void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry)
 	 * Dequeue the entry...
 	 */
 	dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
-			 (irda_queue_t*) entry );
+			 entry);
 	hashbin->hb_size--;
 	entry->q_next = NULL;
 	entry->q_prev = NULL;
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index 07d7d55..cd6f7a9 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -372,7 +372,6 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
 			skb_trim(skb, skb->dev->mtu);
 	}
 	skb->protocol = ETH_P_AF_IUCV;
-	skb_shinfo(skb)->tx_flags |= SKBTX_DRV_NEEDS_SK_REF;
 	nskb = skb_clone(skb, GFP_ATOMIC);
 	if (!nskb)
 		return -ENOMEM;
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c
index 185f12f..c3738f4 100644
--- a/net/l2tp/l2tp_eth.c
+++ b/net/l2tp/l2tp_eth.c
@@ -88,12 +88,12 @@ static int l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev)
 	struct l2tp_eth *priv = netdev_priv(dev);
 	struct l2tp_session *session = priv->session;
 
-	l2tp_xmit_skb(session, skb, session->hdr_len);
-
 	dev->stats.tx_bytes += skb->len;
 	dev->stats.tx_packets++;
 
-	return 0;
+	l2tp_xmit_skb(session, skb, session->hdr_len);
+
+	return NETDEV_TX_OK;
 }
 
 static struct net_device_ops l2tp_eth_netdev_ops = {
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 8ef6b94..286366e 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1522,8 +1522,8 @@ static int pppol2tp_session_getsockopt(struct sock *sk,
  * handler, according to whether the PPPoX socket is a for a regular session
  * or the special tunnel type.
  */
-static int pppol2tp_getsockopt(struct socket *sock, int level,
-			       int optname, char __user *optval, int __user *optlen)
+static int pppol2tp_getsockopt(struct socket *sock, int level, int optname,
+			       char __user *optval, int __user *optlen)
 {
 	struct sock *sk = sock->sk;
 	struct l2tp_session *session;
@@ -1535,7 +1535,7 @@ static int pppol2tp_getsockopt(struct socket *sock, int level,
 	if (level != SOL_PPPOL2TP)
 		return udp_prot.getsockopt(sk, level, optname, optval, optlen);
 
-	if (get_user(len, (int __user *) optlen))
+	if (get_user(len, optlen))
 		return -EFAULT;
 
 	len = min_t(unsigned int, len, sizeof(int));
@@ -1568,7 +1568,7 @@ static int pppol2tp_getsockopt(struct socket *sock, int level,
 		err = pppol2tp_session_getsockopt(sk, session, optname, &val);
 
 	err = -EFAULT;
-	if (put_user(len, (int __user *) optlen))
+	if (put_user(len, optlen))
 		goto end_put_sess;
 
 	if (copy_to_user((void __user *) optval, &val, len))
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 8d249d7..63af254 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -107,6 +107,19 @@ config MAC80211_DEBUGFS
 
 	  Say N unless you know you need this.
 
+config MAC80211_MESSAGE_TRACING
+	bool "Trace all mac80211 debug messages"
+	depends on MAC80211
+	---help---
+	  Select this option to have mac80211 register the
+	  mac80211_msg trace subsystem with tracepoints to
+	  collect all debugging messages, independent of
+	  printing them into the kernel log.
+
+	  The overhead in this option is that all the messages
+	  need to be present in the binary and formatted at
+	  runtime for tracing.
+
 menuconfig MAC80211_DEBUG_MENU
 	bool "Select mac80211 debugging features"
 	depends on MAC80211
@@ -140,26 +153,35 @@ config MAC80211_VERBOSE_DEBUG
 
 	  Do not select this option.
 
-config MAC80211_HT_DEBUG
-	bool "Verbose HT debugging"
+config MAC80211_MLME_DEBUG
+	bool "Verbose managed MLME output"
 	depends on MAC80211_DEBUG_MENU
 	---help---
-	  This option enables 802.11n High Throughput features
-	  debug tracing output.
-
-	  It should not be selected on production systems as some
+	  Selecting this option causes mac80211 to print out
+	  debugging messages for the managed-mode MLME. It
+	  should not be selected on production systems as some
 	  of the messages are remotely triggerable.
 
 	  Do not select this option.
 
-config MAC80211_TKIP_DEBUG
-	bool "Verbose TKIP debugging"
+config MAC80211_STA_DEBUG
+	bool "Verbose station debugging"
 	depends on MAC80211_DEBUG_MENU
 	---help---
 	  Selecting this option causes mac80211 to print out
-	  very verbose TKIP debugging messages. It should not
-	  be selected on production systems as those messages
-	  are remotely triggerable.
+	  debugging messages for station addition/removal.
+
+	  Do not select this option.
+
+config MAC80211_HT_DEBUG
+	bool "Verbose HT debugging"
+	depends on MAC80211_DEBUG_MENU
+	---help---
+	  This option enables 802.11n High Throughput features
+	  debug tracing output.
+
+	  It should not be selected on production systems as some
+	  of the messages are remotely triggerable.
 
 	  Do not select this option.
 
@@ -174,7 +196,7 @@ config MAC80211_IBSS_DEBUG
 
 	  Do not select this option.
 
-config MAC80211_VERBOSE_PS_DEBUG
+config MAC80211_PS_DEBUG
 	bool "Verbose powersave mode debugging"
 	depends on MAC80211_DEBUG_MENU
 	---help---
@@ -186,7 +208,7 @@ config MAC80211_VERBOSE_PS_DEBUG
 
 	  Do not select this option.
 
-config MAC80211_VERBOSE_MPL_DEBUG
+config MAC80211_MPL_DEBUG
 	bool "Verbose mesh peer link debugging"
 	depends on MAC80211_DEBUG_MENU
 	depends on MAC80211_MESH
@@ -199,7 +221,7 @@ config MAC80211_VERBOSE_MPL_DEBUG
 
 	  Do not select this option.
 
-config MAC80211_VERBOSE_MPATH_DEBUG
+config MAC80211_MPATH_DEBUG
 	bool "Verbose mesh path debugging"
 	depends on MAC80211_DEBUG_MENU
 	depends on MAC80211_MESH
@@ -212,7 +234,7 @@ config MAC80211_VERBOSE_MPATH_DEBUG
 
 	  Do not select this option.
 
-config MAC80211_VERBOSE_MHWMP_DEBUG
+config MAC80211_MHWMP_DEBUG
 	bool "Verbose mesh HWMP routing debugging"
 	depends on MAC80211_DEBUG_MENU
 	depends on MAC80211_MESH
@@ -225,7 +247,7 @@ config MAC80211_VERBOSE_MHWMP_DEBUG
 
 	  Do not select this option.
 
-config MAC80211_VERBOSE_MESH_SYNC_DEBUG
+config MAC80211_MESH_SYNC_DEBUG
 	bool "Verbose mesh mesh synchronization debugging"
 	depends on MAC80211_DEBUG_MENU
 	depends on MAC80211_MESH
@@ -236,7 +258,7 @@ config MAC80211_VERBOSE_MESH_SYNC_DEBUG
 
 	  Do not select this option.
 
-config MAC80211_VERBOSE_TDLS_DEBUG
+config MAC80211_TDLS_DEBUG
 	bool "Verbose TDLS debugging"
 	depends on MAC80211_DEBUG_MENU
 	---help---
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 3e9d931..a7dd110 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -9,7 +9,6 @@ mac80211-y := \
 	scan.o offchannel.o \
 	ht.o agg-tx.o agg-rx.o \
 	ibss.o \
-	work.o \
 	iface.o \
 	rate.o \
 	michael.o \
@@ -25,7 +24,7 @@ mac80211-y := \
 	wme.o \
 	event.o \
 	chan.o \
-	driver-trace.o mlme.o
+	trace.o mlme.o
 
 mac80211-$(CONFIG_MAC80211_LEDS) += led.o
 mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
@@ -43,7 +42,7 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
 
 mac80211-$(CONFIG_PM) += pm.o
 
-CFLAGS_driver-trace.o := -I$(src)
+CFLAGS_trace.o := -I$(src)
 
 # objects for PID algorithm
 rc80211_pid-y := rc80211_pid_algo.o
@@ -59,4 +58,4 @@ 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__
+ccflags-y += -D__CHECK_ENDIAN__ -DDEBUG
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index c649188..186d991 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -74,18 +74,17 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 
 	RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG
+	ht_dbg(sta->sdata,
 	       "Rx BA session stop requested for %pM tid %u %s reason: %d\n",
 	       sta->sta.addr, tid,
 	       initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
 	       (int)reason);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
 
 	if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
 			     &sta->sta, tid, NULL, 0))
-		printk(KERN_DEBUG "HW problem - can not stop rx "
-				"aggregation for tid %d\n", tid);
+		sdata_info(sta->sdata,
+			   "HW problem - can not stop rx aggregation for tid %d\n",
+			   tid);
 
 	/* check if this is a self generated aggregation halt */
 	if (initiator == WLAN_BACK_RECIPIENT && tx)
@@ -160,9 +159,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
 	}
 	rcu_read_unlock();
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
-#endif
+	ht_dbg(sta->sdata, "rx session timer expired on tid %d\n", (u16)*ptid);
+
 	set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
 	ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
 }
@@ -249,10 +247,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
 	status = WLAN_STATUS_REQUEST_DECLINED;
 
 	if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Suspend in progress. "
-		       "Denying ADDBA request\n");
-#endif
+		ht_dbg(sta->sdata, "Suspend in progress - Denying ADDBA request\n");
 		goto end_no_lock;
 	}
 
@@ -264,10 +259,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
 	     (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) ||
 	    (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
 		status = WLAN_STATUS_INVALID_QOS_PARAM;
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		net_dbg_ratelimited("AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
-				    mgmt->sa, tid, ba_policy, buf_size);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+		ht_dbg_ratelimited(sta->sdata,
+				   "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
+				   mgmt->sa, tid, ba_policy, buf_size);
 		goto end_no_lock;
 	}
 	/* determine default buffer size */
@@ -282,10 +276,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
 	mutex_lock(&sta->ampdu_mlme.mtx);
 
 	if (sta->ampdu_mlme.tid_rx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		net_dbg_ratelimited("unexpected AddBA Req from %pM on tid %u\n",
-				    mgmt->sa, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+		ht_dbg_ratelimited(sta->sdata,
+				   "unexpected AddBA Req from %pM on tid %u\n",
+				   mgmt->sa, tid);
 
 		/* delete existing Rx BA session on the same tid */
 		___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
@@ -324,10 +317,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
 
 	ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
 			       &sta->sta, tid, &start_seq_num, 0);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
+	ht_dbg(sta->sdata, "Rx A-MPDU request on tid %d result %d\n", tid, ret);
 	if (ret) {
 		kfree(tid_agg_rx->reorder_buf);
 		kfree(tid_agg_rx->reorder_time);
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 7cf0715..5cc1bf7 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -184,10 +184,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 
 	spin_unlock_bh(&sta->lock);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
+	ht_dbg(sta->sdata, "Tx BA session stop requested for %pM tid %u\n",
 	       sta->sta.addr, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
 
 	del_timer_sync(&tid_tx->addba_resp_timer);
 	del_timer_sync(&tid_tx->session_timer);
@@ -253,17 +251,13 @@ static void sta_addba_resp_timer_expired(unsigned long data)
 	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",
-			tid);
-#endif
+		ht_dbg(sta->sdata,
+		       "timer expired on tid %d but we are not (or no longer) expecting addBA response there\n",
+		       tid);
 		return;
 	}
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
-#endif
+	ht_dbg(sta->sdata, "addBA response timer expired on tid %d\n", tid);
 
 	ieee80211_stop_tx_ba_session(&sta->sta, tid);
 	rcu_read_unlock();
@@ -323,8 +317,9 @@ ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata,
 
 	ieee80211_stop_queue_agg(sdata, tid);
 
-	if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
-			  " from the pending queue\n", tid))
+	if (WARN(!tid_tx,
+		 "TID %d gone but expected when splicing aggregates from the pending queue\n",
+		 tid))
 		return;
 
 	if (!skb_queue_empty(&tid_tx->pending)) {
@@ -372,10 +367,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 	ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
 			       &sta->sta, tid, &start_seq_num, 0);
 	if (ret) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA request denied - HW unavailable for"
-					" tid %d\n", tid);
-#endif
+		ht_dbg(sdata,
+		       "BA request denied - HW unavailable for tid %d\n", tid);
 		spin_lock_bh(&sta->lock);
 		ieee80211_agg_splice_packets(sdata, tid_tx, tid);
 		ieee80211_assign_tid_tx(sta, tid, NULL);
@@ -388,9 +381,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int 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
+	ht_dbg(sdata, "activated addBA response timer on tid %d\n", tid);
 
 	spin_lock_bh(&sta->lock);
 	sta->ampdu_mlme.last_addba_req_time[tid] = jiffies;
@@ -437,9 +428,7 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
 
 	rcu_read_unlock();
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
-#endif
+	ht_dbg(sta->sdata, "tx session timer expired on tid %d\n", (u16)*ptid);
 
 	ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
 }
@@ -463,10 +452,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
 	    (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW))
 		return -EINVAL;
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
+	ht_dbg(sdata, "Open BA session requested for %pM tid %u\n",
 	       pubsta->addr, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
 
 	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
 	    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
@@ -476,10 +463,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
 		return -EINVAL;
 
 	if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA sessions blocked. "
-		       "Denying BA session request\n");
-#endif
+		ht_dbg(sdata,
+		       "BA sessions blocked - Denying BA session request\n");
 		return -EINVAL;
 	}
 
@@ -497,10 +482,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
 	 */
 	if (sta->sdata->vif.type == NL80211_IFTYPE_ADHOC &&
 	    !sta->sta.ht_cap.ht_supported) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA request denied - IBSS STA %pM"
-		       "does not advertise HT support\n", pubsta->addr);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+		ht_dbg(sdata,
+		       "BA request denied - IBSS STA %pM does not advertise HT support\n",
+		       pubsta->addr);
 		return -EINVAL;
 	}
 
@@ -520,12 +504,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
 	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES &&
 	    time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
 			HT_AGG_RETRIES_PERIOD)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA request denied - "
-		       "waiting a grace period after %d failed requests "
-		       "on tid %u\n",
+		ht_dbg(sdata,
+		       "BA request denied - waiting a grace period after %d failed requests on tid %u\n",
 		       sta->ampdu_mlme.addba_req_num[tid], tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
 		ret = -EBUSY;
 		goto err_unlock_sta;
 	}
@@ -533,10 +514,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 	/* check if the TID is not in aggregation flow already */
 	if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA request denied - session is not "
-				 "idle on tid %u\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+		ht_dbg(sdata,
+		       "BA request denied - session is not idle on tid %u\n",
+		       tid);
 		ret = -EAGAIN;
 		goto err_unlock_sta;
 	}
@@ -591,9 +571,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
 
 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
-#endif
+	ht_dbg(sta->sdata, "Aggregation is on for tid %d\n", tid);
 
 	drv_ampdu_action(local, sta->sdata,
 			 IEEE80211_AMPDU_TX_OPERATIONAL,
@@ -627,10 +605,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
 	trace_api_start_tx_ba_cb(sdata, ra, tid);
 
 	if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
-				tid, STA_TID_NUM);
-#endif
+		ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n",
+		       tid, STA_TID_NUM);
 		return;
 	}
 
@@ -638,9 +614,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
 	sta = sta_info_get_bss(sdata, ra);
 	if (!sta) {
 		mutex_unlock(&local->sta_mtx);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
+		ht_dbg(sdata, "Could not find station: %pM\n", ra);
 		return;
 	}
 
@@ -648,9 +622,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
 	if (WARN_ON(!tid_tx)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "addBA was not requested!\n");
-#endif
+		ht_dbg(sdata, "addBA was not requested!\n");
 		goto unlock;
 	}
 
@@ -750,25 +722,18 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
 	trace_api_stop_tx_ba_cb(sdata, ra, tid);
 
 	if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
-				tid, STA_TID_NUM);
-#endif
+		ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n",
+		       tid, STA_TID_NUM);
 		return;
 	}
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
-	       ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+	ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n", ra, tid);
 
 	mutex_lock(&local->sta_mtx);
 
 	sta = sta_info_get_bss(sdata, ra);
 	if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
+		ht_dbg(sdata, "Could not find station: %pM\n", ra);
 		goto unlock;
 	}
 
@@ -777,9 +742,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
 	tid_tx = rcu_dereference_protected_tid_tx(sta, 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
+		ht_dbg(sdata, "unexpected callback to A-MPDU stop\n");
 		goto unlock_sta;
 	}
 
@@ -855,17 +818,13 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
 		goto out;
 
 	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
+		ht_dbg(sta->sdata, "wrong addBA response token, tid %d\n", tid);
 		goto out;
 	}
 
 	del_timer_sync(&tid_tx->addba_resp_timer);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
-#endif
+	ht_dbg(sta->sdata, "switched off addBA timer for tid %d\n", tid);
 
 	/*
 	 * addba_resp_timer may have fired before we got here, and
@@ -874,11 +833,9 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
 	 */
 	if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
 	    test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG
+		ht_dbg(sta->sdata,
 		       "got addBA resp for tid %d but we already gave up\n",
 		       tid);
-#endif
 		goto out;
 	}
 
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index e9cecca..c2a2dcb 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -353,6 +353,7 @@ void sta_set_rate_info_tx(struct sta_info *sta,
 static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 {
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	struct ieee80211_local *local = sdata->local;
 	struct timespec uptime;
 
 	sinfo->generation = sdata->local->sta_generation;
@@ -388,7 +389,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 	if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
 	    (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
 		sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
-		sinfo->signal = (s8)sta->last_signal;
+		if (!local->ops->get_rssi ||
+		    drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal))
+			sinfo->signal = (s8)sta->last_signal;
 		sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
 	}
 
@@ -517,7 +520,7 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
 	 * network device.
 	 */
 
-	rcu_read_lock();
+	mutex_lock(&local->sta_mtx);
 
 	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 		sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid);
@@ -546,7 +549,7 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
 			data[i] = (u8)sinfo.signal_avg;
 		i++;
 	} else {
-		list_for_each_entry_rcu(sta, &local->sta_list, list) {
+		list_for_each_entry(sta, &local->sta_list, list) {
 			/* Make sure this station belongs to the proper dev */
 			if (sta->sdata->dev != dev)
 				continue;
@@ -603,7 +606,7 @@ do_survey:
 	else
 		data[i++] = -1LL;
 
-	rcu_read_unlock();
+	mutex_unlock(&local->sta_mtx);
 
 	if (WARN_ON(i != STA_STATS_LEN))
 		return;
@@ -629,10 +632,11 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
 				 int idx, u8 *mac, struct station_info *sinfo)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	int ret = -ENOENT;
 
-	rcu_read_lock();
+	mutex_lock(&local->sta_mtx);
 
 	sta = sta_info_get_by_idx(sdata, idx);
 	if (sta) {
@@ -641,7 +645,7 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
 		sta_set_sinfo(sta, sinfo);
 	}
 
-	rcu_read_unlock();
+	mutex_unlock(&local->sta_mtx);
 
 	return ret;
 }
@@ -658,10 +662,11 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
 				 u8 *mac, struct station_info *sinfo)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	int ret = -ENOENT;
 
-	rcu_read_lock();
+	mutex_lock(&local->sta_mtx);
 
 	sta = sta_info_get_bss(sdata, mac);
 	if (sta) {
@@ -669,11 +674,54 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
 		sta_set_sinfo(sta, sinfo);
 	}
 
-	rcu_read_unlock();
+	mutex_unlock(&local->sta_mtx);
 
 	return ret;
 }
 
+static int ieee80211_set_channel(struct wiphy *wiphy,
+				 struct net_device *netdev,
+				 struct ieee80211_channel *chan,
+				 enum nl80211_channel_type channel_type)
+{
+	struct ieee80211_local *local = wiphy_priv(wiphy);
+	struct ieee80211_sub_if_data *sdata = NULL;
+
+	if (netdev)
+		sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
+
+	switch (ieee80211_get_channel_mode(local, NULL)) {
+	case CHAN_MODE_HOPPING:
+		return -EBUSY;
+	case CHAN_MODE_FIXED:
+		if (local->oper_channel != chan ||
+		    (!sdata && local->_oper_channel_type != channel_type))
+			return -EBUSY;
+		if (!sdata && local->_oper_channel_type == channel_type)
+			return 0;
+		break;
+	case CHAN_MODE_UNDEFINED:
+		break;
+	}
+
+	if (!ieee80211_set_channel_type(local, sdata, channel_type))
+		return -EBUSY;
+
+	local->oper_channel = chan;
+
+	/* auto-detects changes */
+	ieee80211_hw_config(local, 0);
+
+	return 0;
+}
+
+static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
+					 struct ieee80211_channel *chan,
+					 enum nl80211_channel_type channel_type)
+{
+	return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
+}
+
 static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
 				    const u8 *resp, size_t resp_len)
 {
@@ -788,6 +836,11 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
 	if (old)
 		return -EALREADY;
 
+	err = ieee80211_set_channel(wiphy, dev, params->channel,
+				    params->channel_type);
+	if (err)
+		return err;
+
 	/*
 	 * Apply control port protocol, this allows us to
 	 * not encrypt dynamic WEP control frames.
@@ -1482,7 +1535,7 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
 	if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask))
 		conf->dot11MeshTTL = nconf->dot11MeshTTL;
 	if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask))
-		conf->dot11MeshTTL = nconf->element_ttl;
+		conf->element_ttl = nconf->element_ttl;
 	if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))
 		conf->auto_open_plinks = nconf->auto_open_plinks;
 	if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask))
@@ -1517,17 +1570,16 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
 		 * announcements, so require this ifmsh to also be a root node
 		 * */
 		if (nconf->dot11MeshGateAnnouncementProtocol &&
-		    !conf->dot11MeshHWMPRootMode) {
-			conf->dot11MeshHWMPRootMode = 1;
+		    !(conf->dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)) {
+			conf->dot11MeshHWMPRootMode = IEEE80211_PROACTIVE_RANN;
 			ieee80211_mesh_root_setup(ifmsh);
 		}
 		conf->dot11MeshGateAnnouncementProtocol =
 			nconf->dot11MeshGateAnnouncementProtocol;
 	}
-	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) {
+	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask))
 		conf->dot11MeshHWMPRannInterval =
 			nconf->dot11MeshHWMPRannInterval;
-	}
 	if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask))
 		conf->dot11MeshForwarding = nconf->dot11MeshForwarding;
 	if (_chg_mesh_attr(NL80211_MESHCONF_RSSI_THRESHOLD, mask)) {
@@ -1543,6 +1595,15 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
 		sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode;
 		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
 	}
+	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask))
+		conf->dot11MeshHWMPactivePathToRootTimeout =
+			nconf->dot11MeshHWMPactivePathToRootTimeout;
+	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOT_INTERVAL, mask))
+		conf->dot11MeshHWMProotInterval =
+			nconf->dot11MeshHWMProotInterval;
+	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask))
+		conf->dot11MeshHWMPconfirmationInterval =
+			nconf->dot11MeshHWMPconfirmationInterval;
 	return 0;
 }
 
@@ -1558,6 +1619,12 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
 	err = copy_mesh_setup(ifmsh, setup);
 	if (err)
 		return err;
+
+	err = ieee80211_set_channel(wiphy, dev, setup->channel,
+				    setup->channel_type);
+	if (err)
+		return err;
+
 	ieee80211_start_mesh(sdata);
 
 	return 0;
@@ -1677,55 +1744,6 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
 	return 0;
 }
 
-static int ieee80211_set_channel(struct wiphy *wiphy,
-				 struct net_device *netdev,
-				 struct ieee80211_channel *chan,
-				 enum nl80211_channel_type channel_type)
-{
-	struct ieee80211_local *local = wiphy_priv(wiphy);
-	struct ieee80211_sub_if_data *sdata = NULL;
-	struct ieee80211_channel *old_oper;
-	enum nl80211_channel_type old_oper_type;
-	enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT;
-
-	if (netdev)
-		sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
-
-	switch (ieee80211_get_channel_mode(local, NULL)) {
-	case CHAN_MODE_HOPPING:
-		return -EBUSY;
-	case CHAN_MODE_FIXED:
-		if (local->oper_channel != chan)
-			return -EBUSY;
-		if (!sdata && local->_oper_channel_type == channel_type)
-			return 0;
-		break;
-	case CHAN_MODE_UNDEFINED:
-		break;
-	}
-
-	if (sdata)
-		old_vif_oper_type = sdata->vif.bss_conf.channel_type;
-	old_oper_type = local->_oper_channel_type;
-
-	if (!ieee80211_set_channel_type(local, sdata, channel_type))
-		return -EBUSY;
-
-	old_oper = local->oper_channel;
-	local->oper_channel = chan;
-
-	/* Update driver if changes were actually made. */
-	if ((old_oper != local->oper_channel) ||
-	    (old_oper_type != local->_oper_channel_type))
-		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-
-	if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR &&
-	    old_vif_oper_type != sdata->vif.bss_conf.channel_type)
-		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
-
-	return 0;
-}
-
 #ifdef CONFIG_PM
 static int ieee80211_suspend(struct wiphy *wiphy,
 			     struct cfg80211_wowlan *wowlan)
@@ -2093,6 +2111,9 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	int i, ret;
 
+	if (!ieee80211_sdata_running(sdata))
+		return -ENETDOWN;
+
 	if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) {
 		ret = drv_set_bitrate_mask(local, sdata, mask);
 		if (ret)
@@ -2108,35 +2129,171 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
 	return 0;
 }
 
-static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local,
-					  struct net_device *dev,
-					  struct ieee80211_channel *chan,
-					  enum nl80211_channel_type chantype,
-					  unsigned int duration, u64 *cookie)
+static int ieee80211_start_roc_work(struct ieee80211_local *local,
+				    struct ieee80211_sub_if_data *sdata,
+				    struct ieee80211_channel *channel,
+				    enum nl80211_channel_type channel_type,
+				    unsigned int duration, u64 *cookie,
+				    struct sk_buff *txskb)
 {
+	struct ieee80211_roc_work *roc, *tmp;
+	bool queued = false;
 	int ret;
-	u32 random_cookie;
 
 	lockdep_assert_held(&local->mtx);
 
-	if (local->hw_roc_cookie)
-		return -EBUSY;
-	/* must be nonzero */
-	random_cookie = random32() | 1;
-
-	*cookie = random_cookie;
-	local->hw_roc_dev = dev;
-	local->hw_roc_cookie = random_cookie;
-	local->hw_roc_channel = chan;
-	local->hw_roc_channel_type = chantype;
-	local->hw_roc_duration = duration;
-	ret = drv_remain_on_channel(local, chan, chantype, duration);
+	roc = kzalloc(sizeof(*roc), GFP_KERNEL);
+	if (!roc)
+		return -ENOMEM;
+
+	roc->chan = channel;
+	roc->chan_type = channel_type;
+	roc->duration = duration;
+	roc->req_duration = duration;
+	roc->frame = txskb;
+	roc->mgmt_tx_cookie = (unsigned long)txskb;
+	roc->sdata = sdata;
+	INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
+	INIT_LIST_HEAD(&roc->dependents);
+
+	/* if there's one pending or we're scanning, queue this one */
+	if (!list_empty(&local->roc_list) || local->scanning)
+		goto out_check_combine;
+
+	/* if not HW assist, just queue & schedule work */
+	if (!local->ops->remain_on_channel) {
+		ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
+		goto out_queue;
+	}
+
+	/* otherwise actually kick it off here (for error handling) */
+
+	/*
+	 * If the duration is zero, then the driver
+	 * wouldn't actually do anything. Set it to
+	 * 10 for now.
+	 *
+	 * TODO: cancel the off-channel operation
+	 *       when we get the SKB's TX status and
+	 *       the wait time was zero before.
+	 */
+	if (!duration)
+		duration = 10;
+
+	ret = drv_remain_on_channel(local, channel, channel_type, duration);
 	if (ret) {
-		local->hw_roc_channel = NULL;
-		local->hw_roc_cookie = 0;
+		kfree(roc);
+		return ret;
 	}
 
-	return ret;
+	roc->started = true;
+	goto out_queue;
+
+ out_check_combine:
+	list_for_each_entry(tmp, &local->roc_list, list) {
+		if (tmp->chan != channel || tmp->chan_type != channel_type)
+			continue;
+
+		/*
+		 * Extend this ROC if possible:
+		 *
+		 * If it hasn't started yet, just increase the duration
+		 * and add the new one to the list of dependents.
+		 */
+		if (!tmp->started) {
+			list_add_tail(&roc->list, &tmp->dependents);
+			tmp->duration = max(tmp->duration, roc->duration);
+			queued = true;
+			break;
+		}
+
+		/* If it has already started, it's more difficult ... */
+		if (local->ops->remain_on_channel) {
+			unsigned long j = jiffies;
+
+			/*
+			 * In the offloaded ROC case, if it hasn't begun, add
+			 * this new one to the dependent list to be handled
+			 * when the the master one begins. If it has begun,
+			 * check that there's still a minimum time left and
+			 * if so, start this one, transmitting the frame, but
+			 * add it to the list directly after this one with a
+			 * a reduced time so we'll ask the driver to execute
+			 * it right after finishing the previous one, in the
+			 * hope that it'll also be executed right afterwards,
+			 * effectively extending the old one.
+			 * If there's no minimum time left, just add it to the
+			 * normal list.
+			 */
+			if (!tmp->hw_begun) {
+				list_add_tail(&roc->list, &tmp->dependents);
+				queued = true;
+				break;
+			}
+
+			if (time_before(j + IEEE80211_ROC_MIN_LEFT,
+					tmp->hw_start_time +
+					msecs_to_jiffies(tmp->duration))) {
+				int new_dur;
+
+				ieee80211_handle_roc_started(roc);
+
+				new_dur = roc->duration -
+					  jiffies_to_msecs(tmp->hw_start_time +
+							   msecs_to_jiffies(
+								tmp->duration) -
+							   j);
+
+				if (new_dur > 0) {
+					/* add right after tmp */
+					list_add(&roc->list, &tmp->list);
+				} else {
+					list_add_tail(&roc->list,
+						      &tmp->dependents);
+				}
+				queued = true;
+			}
+		} else if (del_timer_sync(&tmp->work.timer)) {
+			unsigned long new_end;
+
+			/*
+			 * In the software ROC case, cancel the timer, if
+			 * that fails then the finish work is already
+			 * queued/pending and thus we queue the new ROC
+			 * normally, if that succeeds then we can extend
+			 * the timer duration and TX the frame (if any.)
+			 */
+
+			list_add_tail(&roc->list, &tmp->dependents);
+			queued = true;
+
+			new_end = jiffies + msecs_to_jiffies(roc->duration);
+
+			/* ok, it was started & we canceled timer */
+			if (time_after(new_end, tmp->work.timer.expires))
+				mod_timer(&tmp->work.timer, new_end);
+			else
+				add_timer(&tmp->work.timer);
+
+			ieee80211_handle_roc_started(roc);
+		}
+		break;
+	}
+
+ out_queue:
+	if (!queued)
+		list_add_tail(&roc->list, &local->roc_list);
+
+	/*
+	 * cookie is either the roc (for normal roc)
+	 * or the SKB (for mgmt TX)
+	 */
+	if (txskb)
+		*cookie = (unsigned long)txskb;
+	else
+		*cookie = (unsigned long)roc;
+
+	return 0;
 }
 
 static int ieee80211_remain_on_channel(struct wiphy *wiphy,
@@ -2148,86 +2305,98 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
+	int ret;
 
-	if (local->ops->remain_on_channel) {
-		int ret;
-
-		mutex_lock(&local->mtx);
-		ret = ieee80211_remain_on_channel_hw(local, dev,
-						     chan, channel_type,
-						     duration, cookie);
-		local->hw_roc_for_tx = false;
-		mutex_unlock(&local->mtx);
-
-		return ret;
-	}
+	mutex_lock(&local->mtx);
+	ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
+				       duration, cookie, NULL);
+	mutex_unlock(&local->mtx);
 
-	return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
-					      duration, cookie);
+	return ret;
 }
 
-static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local,
-						 u64 cookie)
+static int ieee80211_cancel_roc(struct ieee80211_local *local,
+				u64 cookie, bool mgmt_tx)
 {
+	struct ieee80211_roc_work *roc, *tmp, *found = NULL;
 	int ret;
 
-	lockdep_assert_held(&local->mtx);
+	mutex_lock(&local->mtx);
+	list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
+		struct ieee80211_roc_work *dep, *tmp2;
 
-	if (local->hw_roc_cookie != cookie)
-		return -ENOENT;
+		list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) {
+			if (!mgmt_tx && (unsigned long)dep != cookie)
+				continue;
+			else if (mgmt_tx && dep->mgmt_tx_cookie != cookie)
+				continue;
+			/* found dependent item -- just remove it */
+			list_del(&dep->list);
+			mutex_unlock(&local->mtx);
 
-	ret = drv_cancel_remain_on_channel(local);
-	if (ret)
-		return ret;
+			ieee80211_roc_notify_destroy(dep);
+			return 0;
+		}
 
-	local->hw_roc_cookie = 0;
-	local->hw_roc_channel = NULL;
+		if (!mgmt_tx && (unsigned long)roc != cookie)
+			continue;
+		else if (mgmt_tx && roc->mgmt_tx_cookie != cookie)
+			continue;
+
+		found = roc;
+		break;
+	}
 
-	ieee80211_recalc_idle(local);
+	if (!found) {
+		mutex_unlock(&local->mtx);
+		return -ENOENT;
+	}
 
-	return 0;
-}
+	/*
+	 * We found the item to cancel, so do that. Note that it
+	 * may have dependents, which we also cancel (and send
+	 * the expired signal for.) Not doing so would be quite
+	 * tricky here, but we may need to fix it later.
+	 */
 
-static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
-					      struct net_device *dev,
-					      u64 cookie)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_local *local = sdata->local;
+	if (local->ops->remain_on_channel) {
+		if (found->started) {
+			ret = drv_cancel_remain_on_channel(local);
+			if (WARN_ON_ONCE(ret)) {
+				mutex_unlock(&local->mtx);
+				return ret;
+			}
+		}
 
-	if (local->ops->cancel_remain_on_channel) {
-		int ret;
+		list_del(&found->list);
 
-		mutex_lock(&local->mtx);
-		ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
+		if (found->started)
+			ieee80211_start_next_roc(local);
 		mutex_unlock(&local->mtx);
 
-		return ret;
+		ieee80211_roc_notify_destroy(found);
+	} else {
+		/* work may be pending so use it all the time */
+		found->abort = true;
+		ieee80211_queue_delayed_work(&local->hw, &found->work, 0);
+
+		mutex_unlock(&local->mtx);
+
+		/* work will clean up etc */
+		flush_delayed_work(&found->work);
 	}
 
-	return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
+	return 0;
 }
 
-static enum work_done_result
-ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb)
+static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
+					      struct net_device *dev,
+					      u64 cookie)
 {
-	/*
-	 * Use the data embedded in the work struct for reporting
-	 * here so if the driver mangled the SKB before dropping
-	 * it (which is the only way we really should get here)
-	 * then we don't report mangled data.
-	 *
-	 * If there was no wait time, then by the time we get here
-	 * the driver will likely not have reported the status yet,
-	 * so in that case userspace will have to deal with it.
-	 */
-
-	if (wk->offchan_tx.wait && !wk->offchan_tx.status)
-		cfg80211_mgmt_tx_status(wk->sdata->dev,
-					(unsigned long) wk->offchan_tx.frame,
-					wk->data, wk->data_len, false, GFP_KERNEL);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
 
-	return WORK_DONE_DESTROY;
+	return ieee80211_cancel_roc(local, cookie, false);
 }
 
 static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
@@ -2241,10 +2410,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
 	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb;
 	struct sta_info *sta;
-	struct ieee80211_work *wk;
 	const struct ieee80211_mgmt *mgmt = (void *)buf;
+	bool need_offchan = false;
 	u32 flags;
-	bool is_offchan = false;
+	int ret;
 
 	if (dont_wait_for_ack)
 		flags = IEEE80211_TX_CTL_NO_ACK;
@@ -2252,33 +2421,28 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
 		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)
-		is_offchan = true;
-	if (channel_type_valid &&
-	    (channel_type != local->tmp_channel_type &&
-	     channel_type != local->_oper_channel_type))
-		is_offchan = true;
-
-	if (chan == local->hw_roc_channel) {
-		/* TODO: check channel type? */
-		is_offchan = false;
-		flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
-	}
-
 	if (no_cck)
 		flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
 
-	if (is_offchan && !offchan)
-		return -EBUSY;
-
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_ADHOC:
+		if (!sdata->vif.bss_conf.ibss_joined)
+			need_offchan = true;
+		/* fall through */
+#ifdef CONFIG_MAC80211_MESH
+	case NL80211_IFTYPE_MESH_POINT:
+		if (ieee80211_vif_is_mesh(&sdata->vif) &&
+		    !sdata->u.mesh.mesh_id_len)
+			need_offchan = true;
+		/* fall through */
+#endif
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_AP_VLAN:
 	case NL80211_IFTYPE_P2P_GO:
-	case NL80211_IFTYPE_MESH_POINT:
+		if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+		    !ieee80211_vif_is_mesh(&sdata->vif) &&
+		    !rcu_access_pointer(sdata->bss->beacon))
+			need_offchan = true;
 		if (!ieee80211_is_action(mgmt->frame_control) ||
 		    mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
 			break;
@@ -2290,103 +2454,60 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
 		break;
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_P2P_CLIENT:
+		if (!sdata->u.mgd.associated)
+			need_offchan = true;
 		break;
 	default:
 		return -EOPNOTSUPP;
 	}
 
+	mutex_lock(&local->mtx);
+
+	/* Check if the operating channel is the requested channel */
+	if (!need_offchan) {
+		need_offchan = chan != local->oper_channel;
+		if (channel_type_valid &&
+		    channel_type != local->_oper_channel_type)
+			need_offchan = true;
+	}
+
+	if (need_offchan && !offchan) {
+		ret = -EBUSY;
+		goto out_unlock;
+	}
+
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
-	if (!skb)
-		return -ENOMEM;
+	if (!skb) {
+		ret = -ENOMEM;
+		goto out_unlock;
+	}
 	skb_reserve(skb, local->hw.extra_tx_headroom);
 
 	memcpy(skb_put(skb, len), buf, len);
 
 	IEEE80211_SKB_CB(skb)->flags = flags;
 
-	if (flags & IEEE80211_TX_CTL_TX_OFFCHAN)
-		IEEE80211_SKB_CB(skb)->hw_queue =
-			local->hw.offchannel_tx_hw_queue;
-
 	skb->dev = sdata->dev;
 
-	*cookie = (unsigned long) skb;
-
-	if (is_offchan && local->ops->remain_on_channel) {
-		unsigned int duration;
-		int ret;
-
-		mutex_lock(&local->mtx);
-		/*
-		 * If the duration is zero, then the driver
-		 * wouldn't actually do anything. Set it to
-		 * 100 for now.
-		 *
-		 * TODO: cancel the off-channel operation
-		 *       when we get the SKB's TX status and
-		 *       the wait time was zero before.
-		 */
-		duration = 100;
-		if (wait)
-			duration = wait;
-		ret = ieee80211_remain_on_channel_hw(local, dev, chan,
-						     channel_type,
-						     duration, cookie);
-		if (ret) {
-			kfree_skb(skb);
-			mutex_unlock(&local->mtx);
-			return ret;
-		}
-
-		local->hw_roc_for_tx = true;
-		local->hw_roc_duration = wait;
-
-		/*
-		 * queue up frame for transmission after
-		 * ieee80211_ready_on_channel call
-		 */
+	if (!need_offchan) {
+		ieee80211_tx_skb(sdata, skb);
+		ret = 0;
+		goto out_unlock;
+	}
 
-		/* modify cookie to prevent API mismatches */
-		*cookie ^= 2;
-		IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
+	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
+	if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
 		IEEE80211_SKB_CB(skb)->hw_queue =
 			local->hw.offchannel_tx_hw_queue;
-		local->hw_roc_skb = skb;
-		local->hw_roc_skb_for_status = skb;
-		mutex_unlock(&local->mtx);
 
-		return 0;
-	}
-
-	/*
-	 * Can transmit right away if the channel was the
-	 * right one and there's no wait involved... If a
-	 * wait is involved, we might otherwise not be on
-	 * the right channel for long enough!
-	 */
-	if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) {
-		ieee80211_tx_skb(sdata, skb);
-		return 0;
-	}
-
-	wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL);
-	if (!wk) {
+	/* This will handle all kinds of coalescing and immediate TX */
+	ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
+				       wait, cookie, skb);
+	if (ret)
 		kfree_skb(skb);
-		return -ENOMEM;
-	}
-
-	wk->type = IEEE80211_WORK_OFFCHANNEL_TX;
-	wk->chan = chan;
-	wk->chan_type = channel_type;
-	wk->sdata = sdata;
-	wk->done = ieee80211_offchan_tx_done;
-	wk->offchan_tx.frame = skb;
-	wk->offchan_tx.wait = wait;
-	wk->data_len = len;
-	memcpy(wk->data, buf, len);
-
-	ieee80211_add_work(wk);
-	return 0;
+ out_unlock:
+	mutex_unlock(&local->mtx);
+	return ret;
 }
 
 static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
@@ -2395,45 +2516,8 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_work *wk;
-	int ret = -ENOENT;
-
-	mutex_lock(&local->mtx);
-
-	if (local->ops->cancel_remain_on_channel) {
-		cookie ^= 2;
-		ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
-
-		if (ret == 0) {
-			kfree_skb(local->hw_roc_skb);
-			local->hw_roc_skb = NULL;
-			local->hw_roc_skb_for_status = NULL;
-		}
-
-		mutex_unlock(&local->mtx);
 
-		return ret;
-	}
-
-	list_for_each_entry(wk, &local->work_list, list) {
-		if (wk->sdata != sdata)
-			continue;
-
-		if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
-			continue;
-
-		if (cookie != (unsigned long) wk->offchan_tx.frame)
-			continue;
-
-		wk->timeout = jiffies;
-
-		ieee80211_queue_work(&local->hw, &local->work_work);
-		ret = 0;
-		break;
-	}
-	mutex_unlock(&local->mtx);
-
-	return ret;
+	return ieee80211_cancel_roc(local, cookie, true);
 }
 
 static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
@@ -2441,16 +2525,30 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
 					  u16 frame_type, bool reg)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
-		return;
+	switch (frame_type) {
+	case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH:
+		if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+			struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 
-	if (reg)
-		local->probe_req_reg++;
-	else
-		local->probe_req_reg--;
+			if (reg)
+				ifibss->auth_frame_registrations++;
+			else
+				ifibss->auth_frame_registrations--;
+		}
+		break;
+	case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ:
+		if (reg)
+			local->probe_req_reg++;
+		else
+			local->probe_req_reg--;
 
-	ieee80211_queue_work(&local->hw, &local->reconfig_filter);
+		ieee80211_queue_work(&local->hw, &local->reconfig_filter);
+		break;
+	default:
+		break;
+	}
 }
 
 static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
@@ -2676,9 +2774,8 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
 	    !sdata->u.mgd.associated)
 		return -EINVAL;
 
-#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
-	printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer);
-#endif
+	tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n",
+		 action_code, peer);
 
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
 			    max(sizeof(struct ieee80211_mgmt),
@@ -2787,9 +2884,7 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
 	if (sdata->vif.type != NL80211_IFTYPE_STATION)
 		return -EINVAL;
 
-#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
-	printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer);
-#endif
+	tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
 
 	switch (oper) {
 	case NL80211_TDLS_ENABLE_LINK:
@@ -2933,7 +3028,7 @@ struct cfg80211_ops mac80211_config_ops = {
 #endif
 	.change_bss = ieee80211_change_bss,
 	.set_txq_params = ieee80211_set_txq_params,
-	.set_channel = ieee80211_set_channel,
+	.set_monitor_channel = ieee80211_set_monitor_channel,
 	.suspend = ieee80211_suspend,
 	.resume = ieee80211_resume,
 	.scan = ieee80211_scan,
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index c76cf72..f0f87e5 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -41,6 +41,10 @@ __ieee80211_get_channel_mode(struct ieee80211_local *local,
 			if (!sdata->u.ap.beacon)
 				continue;
 			break;
+		case NL80211_IFTYPE_MESH_POINT:
+			if (!sdata->wdev.mesh_id_len)
+				continue;
+			break;
 		default:
 			break;
 		}
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
new file mode 100644
index 0000000..8f383a5
--- /dev/null
+++ b/net/mac80211/debug.h
@@ -0,0 +1,170 @@
+#ifndef __MAC80211_DEBUG_H
+#define __MAC80211_DEBUG_H
+#include <net/cfg80211.h>
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+#define MAC80211_IBSS_DEBUG 1
+#else
+#define MAC80211_IBSS_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_PS_DEBUG
+#define MAC80211_PS_DEBUG 1
+#else
+#define MAC80211_PS_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+#define MAC80211_HT_DEBUG 1
+#else
+#define MAC80211_HT_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MPL_DEBUG
+#define MAC80211_MPL_DEBUG 1
+#else
+#define MAC80211_MPL_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MPATH_DEBUG
+#define MAC80211_MPATH_DEBUG 1
+#else
+#define MAC80211_MPATH_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MHWMP_DEBUG
+#define MAC80211_MHWMP_DEBUG 1
+#else
+#define MAC80211_MHWMP_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MESH_SYNC_DEBUG
+#define MAC80211_MESH_SYNC_DEBUG 1
+#else
+#define MAC80211_MESH_SYNC_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_TDLS_DEBUG
+#define MAC80211_TDLS_DEBUG 1
+#else
+#define MAC80211_TDLS_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_STA_DEBUG
+#define MAC80211_STA_DEBUG 1
+#else
+#define MAC80211_STA_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MLME_DEBUG
+#define MAC80211_MLME_DEBUG 1
+#else
+#define MAC80211_MLME_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MESSAGE_TRACING
+void __sdata_info(const char *fmt, ...) __printf(1, 2);
+void __sdata_dbg(bool print, const char *fmt, ...) __printf(2, 3);
+void __sdata_err(const char *fmt, ...) __printf(1, 2);
+void __wiphy_dbg(struct wiphy *wiphy, bool print, const char *fmt, ...)
+	__printf(3, 4);
+
+#define _sdata_info(sdata, fmt, ...)					\
+	__sdata_info("%s: " fmt, (sdata)->name, ##__VA_ARGS__)
+#define _sdata_dbg(print, sdata, fmt, ...)				\
+	__sdata_dbg(print, "%s: " fmt, (sdata)->name, ##__VA_ARGS__)
+#define _sdata_err(sdata, fmt, ...)					\
+	__sdata_err("%s: " fmt, (sdata)->name, ##__VA_ARGS__)
+#define _wiphy_dbg(print, wiphy, fmt, ...)				\
+	__wiphy_dbg(wiphy, print, fmt, ##__VA_ARGS__)
+#else
+#define _sdata_info(sdata, fmt, ...)					\
+do {									\
+	pr_info("%s: " fmt,						\
+		(sdata)->name, ##__VA_ARGS__);				\
+} while (0)
+
+#define _sdata_dbg(print, sdata, fmt, ...)				\
+do {									\
+	if (print)							\
+		pr_debug("%s: " fmt,					\
+			 (sdata)->name, ##__VA_ARGS__);			\
+} while (0)
+
+#define _sdata_err(sdata, fmt, ...)					\
+do {									\
+	pr_err("%s: " fmt,						\
+	       (sdata)->name, ##__VA_ARGS__);				\
+} while (0)
+
+#define _wiphy_dbg(print, wiphy, fmt, ...)				\
+do {									\
+	if (print)							\
+		wiphy_dbg((wiphy), fmt, ##__VA_ARGS__);			\
+} while (0)
+#endif
+
+#define sdata_info(sdata, fmt, ...)					\
+	_sdata_info(sdata, fmt, ##__VA_ARGS__)
+#define sdata_err(sdata, fmt, ...)					\
+	_sdata_err(sdata, fmt, ##__VA_ARGS__)
+#define sdata_dbg(sdata, fmt, ...)					\
+	_sdata_dbg(1, sdata, fmt, ##__VA_ARGS__)
+
+#define ht_dbg(sdata, fmt, ...)						\
+	_sdata_dbg(MAC80211_HT_DEBUG,					\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define ht_dbg_ratelimited(sdata, fmt, ...)				\
+	_sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(),		\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define ibss_dbg(sdata, fmt, ...)					\
+	_sdata_dbg(MAC80211_IBSS_DEBUG,					\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define ps_dbg(sdata, fmt, ...)						\
+	_sdata_dbg(MAC80211_PS_DEBUG,					\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define ps_dbg_hw(hw, fmt, ...)						\
+	_wiphy_dbg(MAC80211_PS_DEBUG,					\
+		   (hw)->wiphy, fmt, ##__VA_ARGS__)
+
+#define ps_dbg_ratelimited(sdata, fmt, ...)				\
+	_sdata_dbg(MAC80211_PS_DEBUG && net_ratelimit(),		\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define mpl_dbg(sdata, fmt, ...)					\
+	_sdata_dbg(MAC80211_MPL_DEBUG,					\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define mpath_dbg(sdata, fmt, ...)					\
+	_sdata_dbg(MAC80211_MPATH_DEBUG,				\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define mhwmp_dbg(sdata, fmt, ...)					\
+	_sdata_dbg(MAC80211_MHWMP_DEBUG,				\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define msync_dbg(sdata, fmt, ...)					\
+	_sdata_dbg(MAC80211_MESH_SYNC_DEBUG,				\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define tdls_dbg(sdata, fmt, ...)					\
+	_sdata_dbg(MAC80211_TDLS_DEBUG,					\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define sta_dbg(sdata, fmt, ...)					\
+	_sdata_dbg(MAC80211_STA_DEBUG,					\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define mlme_dbg(sdata, fmt, ...)					\
+	_sdata_dbg(MAC80211_MLME_DEBUG,					\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#define mlme_dbg_ratelimited(sdata, fmt, ...)				\
+	_sdata_dbg(MAC80211_MLME_DEBUG && net_ratelimit(),		\
+		   sdata, fmt, ##__VA_ARGS__)
+
+#endif /* __MAC80211_DEBUG_H */
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 7ed433c..6d5aec9 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -468,48 +468,54 @@ IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
 IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
 IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
 IEEE80211_IF_FILE(dropped_frames_congestion,
-		u.mesh.mshstats.dropped_frames_congestion, DEC);
+		  u.mesh.mshstats.dropped_frames_congestion, DEC);
 IEEE80211_IF_FILE(dropped_frames_no_route,
-		u.mesh.mshstats.dropped_frames_no_route, DEC);
+		  u.mesh.mshstats.dropped_frames_no_route, DEC);
 IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
 
 /* Mesh parameters */
 IEEE80211_IF_FILE(dot11MeshMaxRetries,
-		u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
+		  u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
 IEEE80211_IF_FILE(dot11MeshRetryTimeout,
-		u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
+		  u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
 IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
-		u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
+		  u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
 IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
-		u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
+		  u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
 IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
 IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC);
 IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
 IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
-		u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
+		  u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
-		u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
+		  u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
-		u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
+		  u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval,
-		u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);
+		  u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
-		u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
+		  u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
-		u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
+		  u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
 IEEE80211_IF_FILE(path_refresh_time,
-		u.mesh.mshcfg.path_refresh_time, DEC);
+		  u.mesh.mshcfg.path_refresh_time, DEC);
 IEEE80211_IF_FILE(min_discovery_timeout,
-		u.mesh.mshcfg.min_discovery_timeout, DEC);
+		  u.mesh.mshcfg.min_discovery_timeout, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
-		u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
+		  u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
 IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
-		u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
+		  u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
-		u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
+		  u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
 IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC);
 IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);
 IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPactivePathToRootTimeout,
+		  u.mesh.mshcfg.dot11MeshHWMPactivePathToRootTimeout, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMProotInterval,
+		  u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval,
+		  u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC);
 #endif
 
 #define DEBUGFS_ADD_MODE(name, mode) \
@@ -607,9 +613,13 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
 	MESHPARAMS_ADD(min_discovery_timeout);
 	MESHPARAMS_ADD(dot11MeshHWMPRootMode);
 	MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
+	MESHPARAMS_ADD(dot11MeshForwarding);
 	MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
 	MESHPARAMS_ADD(rssi_threshold);
 	MESHPARAMS_ADD(ht_opmode);
+	MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout);
+	MESHPARAMS_ADD(dot11MeshHWMProotInterval);
+	MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval);
 #undef MESHPARAMS_ADD
 }
 #endif
@@ -685,6 +695,7 @@ void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
 
 	sprintf(buf, "netdev:%s", sdata->name);
 	if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
-		printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
-		       "dir to %s\n", buf);
+		sdata_err(sdata,
+			  "debugfs: failed to rename debugfs dir to %s\n",
+			  buf);
 }
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 6d33a0c..44e8c12 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -3,7 +3,7 @@
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
-#include "driver-trace.h"
+#include "trace.h"
 
 static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
 {
@@ -845,4 +845,19 @@ drv_allow_buffered_frames(struct ieee80211_local *local,
 						  more_data);
 	trace_drv_return_void(local);
 }
+
+static inline int drv_get_rssi(struct ieee80211_local *local,
+				struct ieee80211_sub_if_data *sdata,
+				struct ieee80211_sta *sta,
+				s8 *rssi_dbm)
+{
+	int ret;
+
+	might_sleep();
+
+	ret = local->ops->get_rssi(&local->hw, &sdata->vif, sta, rssi_dbm);
+	trace_drv_get_rssi(local, sta, *rssi_dbm, ret);
+
+	return ret;
+}
 #endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c
deleted file mode 100644
index 8ed8711..0000000
--- a/net/mac80211/driver-trace.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/* bug in tracepoint.h, it should include this */
-#include <linux/module.h>
-
-/* sparse isn't too happy with all macros... */
-#ifndef __CHECKER__
-#include "driver-ops.h"
-#define CREATE_TRACE_POINTS
-#include "driver-trace.h"
-#endif
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
deleted file mode 100644
index 6de00b2..0000000
--- a/net/mac80211/driver-trace.h
+++ /dev/null
@@ -1,1615 +0,0 @@
-#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
-#define __MAC80211_DRIVER_TRACE
-
-#include <linux/tracepoint.h>
-#include <net/mac80211.h>
-#include "ieee80211_i.h"
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM mac80211
-
-#define MAXNAME		32
-#define LOCAL_ENTRY	__array(char, wiphy_name, 32)
-#define LOCAL_ASSIGN	strlcpy(__entry->wiphy_name, wiphy_name(local->hw.wiphy), MAXNAME)
-#define LOCAL_PR_FMT	"%s"
-#define LOCAL_PR_ARG	__entry->wiphy_name
-
-#define STA_ENTRY	__array(char, sta_addr, ETH_ALEN)
-#define STA_ASSIGN	(sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN))
-#define STA_PR_FMT	" sta:%pM"
-#define STA_PR_ARG	__entry->sta_addr
-
-#define VIF_ENTRY	__field(enum nl80211_iftype, vif_type) __field(void *, sdata)	\
-			__field(bool, p2p)						\
-			__string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
-#define VIF_ASSIGN	__entry->vif_type = sdata->vif.type; __entry->sdata = sdata;	\
-			__entry->p2p = sdata->vif.p2p;					\
-			__assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
-#define VIF_PR_FMT	" vif:%s(%d%s)"
-#define VIF_PR_ARG	__get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
-
-/*
- * Tracing for driver callbacks.
- */
-
-DECLARE_EVENT_CLASS(local_only_evt,
-	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)
-);
-
-DECLARE_EVENT_CLASS(local_sdata_addr_evt,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata),
-	TP_ARGS(local, sdata),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		__array(char, addr, 6)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		memcpy(__entry->addr, sdata->vif.addr, 6);
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT " addr:%pM",
-		LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
-	)
-);
-
-DECLARE_EVENT_CLASS(local_u32_evt,
-	TP_PROTO(struct ieee80211_local *local, u32 value),
-	TP_ARGS(local, value),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u32, value)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->value = value;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " value:%d",
-		LOCAL_PR_ARG, __entry->value
-	)
-);
-
-DECLARE_EVENT_CLASS(local_sdata_evt,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata),
-	TP_ARGS(local, sdata),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT VIF_PR_FMT,
-		LOCAL_PR_ARG, VIF_PR_ARG
-	)
-);
-
-DEFINE_EVENT(local_only_evt, drv_return_void,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-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_bool,
-	TP_PROTO(struct ieee80211_local *local, bool ret),
-	TP_ARGS(local, ret),
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(bool, ret)
-	),
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->ret = ret;
-	),
-	TP_printk(LOCAL_PR_FMT " - %s", LOCAL_PR_ARG, (__entry->ret) ?
-		  "true" : "false")
-);
-
-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)
-);
-
-DEFINE_EVENT(local_only_evt, drv_start,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_u32_evt, drv_get_et_strings,
-	     TP_PROTO(struct ieee80211_local *local, u32 sset),
-	     TP_ARGS(local, sset)
-);
-
-DEFINE_EVENT(local_u32_evt, drv_get_et_sset_count,
-	     TP_PROTO(struct ieee80211_local *local, u32 sset),
-	     TP_ARGS(local, sset)
-);
-
-DEFINE_EVENT(local_only_evt, drv_get_et_stats,
-	     TP_PROTO(struct ieee80211_local *local),
-	     TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_only_evt, drv_suspend,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_only_evt, drv_resume,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-TRACE_EVENT(drv_set_wakeup,
-	TP_PROTO(struct ieee80211_local *local, bool enabled),
-	TP_ARGS(local, enabled),
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(bool, enabled)
-	),
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->enabled = enabled;
-	),
-	TP_printk(LOCAL_PR_FMT " enabled:%d", LOCAL_PR_ARG, __entry->enabled)
-);
-
-DEFINE_EVENT(local_only_evt, drv_stop,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_sdata_addr_evt, drv_add_interface,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata),
-	TP_ARGS(local, sdata)
-);
-
-TRACE_EVENT(drv_change_interface,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 enum nl80211_iftype type, bool p2p),
-
-	TP_ARGS(local, sdata, type, p2p),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		__field(u32, new_type)
-		__field(bool, new_p2p)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		__entry->new_type = type;
-		__entry->new_p2p = p2p;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT " new type:%d%s",
-		LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type,
-		__entry->new_p2p ? "/p2p" : ""
-	)
-);
-
-DEFINE_EVENT(local_sdata_addr_evt, drv_remove_interface,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata),
-	TP_ARGS(local, sdata)
-);
-
-TRACE_EVENT(drv_config,
-	TP_PROTO(struct ieee80211_local *local,
-		 u32 changed),
-
-	TP_ARGS(local, changed),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u32, changed)
-		__field(u32, flags)
-		__field(int, power_level)
-		__field(int, dynamic_ps_timeout)
-		__field(int, max_sleep_period)
-		__field(u16, listen_interval)
-		__field(u8, long_frame_max_tx_count)
-		__field(u8, short_frame_max_tx_count)
-		__field(int, center_freq)
-		__field(int, channel_type)
-		__field(int, smps)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->changed = changed;
-		__entry->flags = local->hw.conf.flags;
-		__entry->power_level = local->hw.conf.power_level;
-		__entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout;
-		__entry->max_sleep_period = local->hw.conf.max_sleep_period;
-		__entry->listen_interval = local->hw.conf.listen_interval;
-		__entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count;
-		__entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count;
-		__entry->center_freq = local->hw.conf.channel->center_freq;
-		__entry->channel_type = local->hw.conf.channel_type;
-		__entry->smps = local->hw.conf.smps_mode;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " ch:%#x freq:%d",
-		LOCAL_PR_ARG, __entry->changed, __entry->center_freq
-	)
-);
-
-TRACE_EVENT(drv_bss_info_changed,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 struct ieee80211_bss_conf *info,
-		 u32 changed),
-
-	TP_ARGS(local, sdata, info, changed),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		__field(bool, assoc)
-		__field(u16, aid)
-		__field(bool, cts)
-		__field(bool, shortpre)
-		__field(bool, shortslot)
-		__field(u8, dtimper)
-		__field(u16, bcnint)
-		__field(u16, assoc_cap)
-		__field(u64, timestamp)
-		__field(u32, basic_rates)
-		__field(u32, changed)
-		__field(bool, enable_beacon)
-		__field(u16, ht_operation_mode)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		__entry->changed = changed;
-		__entry->aid = info->aid;
-		__entry->assoc = info->assoc;
-		__entry->shortpre = info->use_short_preamble;
-		__entry->cts = info->use_cts_prot;
-		__entry->shortslot = info->use_short_slot;
-		__entry->dtimper = info->dtim_period;
-		__entry->bcnint = info->beacon_int;
-		__entry->assoc_cap = info->assoc_capability;
-		__entry->timestamp = info->last_tsf;
-		__entry->basic_rates = info->basic_rates;
-		__entry->enable_beacon = info->enable_beacon;
-		__entry->ht_operation_mode = info->ht_operation_mode;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT " changed:%#x",
-		LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed
-	)
-);
-
-TRACE_EVENT(drv_prepare_multicast,
-	TP_PROTO(struct ieee80211_local *local, int mc_count),
-
-	TP_ARGS(local, mc_count),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(int, mc_count)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->mc_count = mc_count;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " prepare mc (%d)",
-		LOCAL_PR_ARG, __entry->mc_count
-	)
-);
-
-TRACE_EVENT(drv_configure_filter,
-	TP_PROTO(struct ieee80211_local *local,
-		 unsigned int changed_flags,
-		 unsigned int *total_flags,
-		 u64 multicast),
-
-	TP_ARGS(local, changed_flags, total_flags, multicast),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(unsigned int, changed)
-		__field(unsigned int, total)
-		__field(u64, multicast)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->changed = changed_flags;
-		__entry->total = *total_flags;
-		__entry->multicast = multicast;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " changed:%#x total:%#x",
-		LOCAL_PR_ARG, __entry->changed, __entry->total
-	)
-);
-
-TRACE_EVENT(drv_set_tim,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sta *sta, bool set),
-
-	TP_ARGS(local, sta, set),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		STA_ENTRY
-		__field(bool, set)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		STA_ASSIGN;
-		__entry->set = set;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT STA_PR_FMT " set:%d",
-		LOCAL_PR_ARG, STA_PR_FMT, __entry->set
-	)
-);
-
-TRACE_EVENT(drv_set_key,
-	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),
-
-	TP_ARGS(local, cmd, sdata, sta, key),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		STA_ENTRY
-		__field(u32, cipher)
-		__field(u8, hw_key_idx)
-		__field(u8, flags)
-		__field(s8, keyidx)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		STA_ASSIGN;
-		__entry->cipher = key->cipher;
-		__entry->flags = key->flags;
-		__entry->keyidx = key->keyidx;
-		__entry->hw_key_idx = key->hw_key_idx;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
-		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
-	)
-);
-
-TRACE_EVENT(drv_update_tkip_key,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 struct ieee80211_key_conf *conf,
-		 struct ieee80211_sta *sta, u32 iv32),
-
-	TP_ARGS(local, sdata, conf, sta, iv32),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		STA_ENTRY
-		__field(u32, iv32)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		STA_ASSIGN;
-		__entry->iv32 = iv32;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x",
-		LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32
-	)
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_hw_scan,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata),
-	TP_ARGS(local, sdata)
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_cancel_hw_scan,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata),
-	TP_ARGS(local, sdata)
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata),
-	TP_ARGS(local, sdata)
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata),
-	TP_ARGS(local, sdata)
-);
-
-DEFINE_EVENT(local_only_evt, drv_sw_scan_start,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_only_evt, drv_sw_scan_complete,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-TRACE_EVENT(drv_get_stats,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_low_level_stats *stats,
-		 int ret),
-
-	TP_ARGS(local, stats, ret),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(int, ret)
-		__field(unsigned int, ackfail)
-		__field(unsigned int, rtsfail)
-		__field(unsigned int, fcserr)
-		__field(unsigned int, rtssucc)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->ret = ret;
-		__entry->ackfail = stats->dot11ACKFailureCount;
-		__entry->rtsfail = stats->dot11RTSFailureCount;
-		__entry->fcserr = stats->dot11FCSErrorCount;
-		__entry->rtssucc = stats->dot11RTSSuccessCount;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " ret:%d",
-		LOCAL_PR_ARG, __entry->ret
-	)
-);
-
-TRACE_EVENT(drv_get_tkip_seq,
-	TP_PROTO(struct ieee80211_local *local,
-		 u8 hw_key_idx, u32 *iv32, u16 *iv16),
-
-	TP_ARGS(local, hw_key_idx, iv32, iv16),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u8, hw_key_idx)
-		__field(u32, iv32)
-		__field(u16, iv16)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->hw_key_idx = hw_key_idx;
-		__entry->iv32 = *iv32;
-		__entry->iv16 = *iv16;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT, LOCAL_PR_ARG
-	)
-);
-
-DEFINE_EVENT(local_u32_evt, drv_set_frag_threshold,
-	TP_PROTO(struct ieee80211_local *local, u32 value),
-	TP_ARGS(local, value)
-);
-
-DEFINE_EVENT(local_u32_evt, drv_set_rts_threshold,
-	TP_PROTO(struct ieee80211_local *local, u32 value),
-	TP_ARGS(local, value)
-);
-
-TRACE_EVENT(drv_set_coverage_class,
-	TP_PROTO(struct ieee80211_local *local, u8 value),
-
-	TP_ARGS(local, value),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u8, value)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->value = value;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " value:%d",
-		LOCAL_PR_ARG, __entry->value
-	)
-);
-
-TRACE_EVENT(drv_sta_notify,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 enum sta_notify_cmd cmd,
-		 struct ieee80211_sta *sta),
-
-	TP_ARGS(local, sdata, cmd, sta),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		STA_ENTRY
-		__field(u32, cmd)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		STA_ASSIGN;
-		__entry->cmd = cmd;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " cmd:%d",
-		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->cmd
-	)
-);
-
-TRACE_EVENT(drv_sta_state,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 struct ieee80211_sta *sta,
-		 enum ieee80211_sta_state old_state,
-		 enum ieee80211_sta_state new_state),
-
-	TP_ARGS(local, sdata, sta, old_state, new_state),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		STA_ENTRY
-		__field(u32, old_state)
-		__field(u32, new_state)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		STA_ASSIGN;
-		__entry->old_state = old_state;
-		__entry->new_state = new_state;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " state: %d->%d",
-		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG,
-		__entry->old_state, __entry->new_state
-	)
-);
-
-TRACE_EVENT(drv_sta_rc_update,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 struct ieee80211_sta *sta,
-		 u32 changed),
-
-	TP_ARGS(local, sdata, sta, changed),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		STA_ENTRY
-		__field(u32, changed)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		STA_ASSIGN;
-		__entry->changed = changed;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " changed: 0x%x",
-		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->changed
-	)
-);
-
-TRACE_EVENT(drv_sta_add,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 struct ieee80211_sta *sta),
-
-	TP_ARGS(local, sdata, sta),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		STA_ENTRY
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		STA_ASSIGN;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
-		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
-	)
-);
-
-TRACE_EVENT(drv_sta_remove,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 struct ieee80211_sta *sta),
-
-	TP_ARGS(local, sdata, sta),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		STA_ENTRY
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		STA_ASSIGN;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
-		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
-	)
-);
-
-TRACE_EVENT(drv_conf_tx,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 u16 ac, const struct ieee80211_tx_queue_params *params),
-
-	TP_ARGS(local, sdata, ac, params),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		__field(u16, ac)
-		__field(u16, txop)
-		__field(u16, cw_min)
-		__field(u16, cw_max)
-		__field(u8, aifs)
-		__field(bool, uapsd)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		__entry->ac = ac;
-		__entry->txop = params->txop;
-		__entry->cw_max = params->cw_max;
-		__entry->cw_min = params->cw_min;
-		__entry->aifs = params->aifs;
-		__entry->uapsd = params->uapsd;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT  " AC:%d",
-		LOCAL_PR_ARG, VIF_PR_ARG, __entry->ac
-	)
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_get_tsf,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata),
-	TP_ARGS(local, sdata)
-);
-
-TRACE_EVENT(drv_set_tsf,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 u64 tsf),
-
-	TP_ARGS(local, sdata, tsf),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		__field(u64, tsf)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		__entry->tsf = tsf;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT  " tsf:%llu",
-		LOCAL_PR_ARG, VIF_PR_ARG, (unsigned long long)__entry->tsf
-	)
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_reset_tsf,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata),
-	TP_ARGS(local, sdata)
-);
-
-DEFINE_EVENT(local_only_evt, drv_tx_last_beacon,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-TRACE_EVENT(drv_ampdu_action,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 enum ieee80211_ampdu_mlme_action action,
-		 struct ieee80211_sta *sta, u16 tid,
-		 u16 *ssn, u8 buf_size),
-
-	TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		STA_ENTRY
-		__field(u32, action)
-		__field(u16, tid)
-		__field(u16, ssn)
-		__field(u8, buf_size)
-		VIF_ENTRY
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		STA_ASSIGN;
-		__entry->action = action;
-		__entry->tid = tid;
-		__entry->ssn = ssn ? *ssn : 0;
-		__entry->buf_size = buf_size;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d",
-		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action,
-		__entry->tid, __entry->buf_size
-	)
-);
-
-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
-	)
-);
-
-TRACE_EVENT(drv_flush,
-	TP_PROTO(struct ieee80211_local *local, bool drop),
-
-	TP_ARGS(local, drop),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(bool, drop)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->drop = drop;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " drop:%d",
-		LOCAL_PR_ARG, __entry->drop
-	)
-);
-
-TRACE_EVENT(drv_channel_switch,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_channel_switch *ch_switch),
-
-	TP_ARGS(local, ch_switch),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u64, timestamp)
-		__field(bool, block_tx)
-		__field(u16, freq)
-		__field(u8, count)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->timestamp = ch_switch->timestamp;
-		__entry->block_tx = ch_switch->block_tx;
-		__entry->freq = ch_switch->channel->center_freq;
-		__entry->count = ch_switch->count;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " new freq:%u count:%d",
-		LOCAL_PR_ARG, __entry->freq, __entry->count
-	)
-);
-
-TRACE_EVENT(drv_set_antenna,
-	TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret),
-
-	TP_ARGS(local, tx_ant, rx_ant, ret),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u32, tx_ant)
-		__field(u32, rx_ant)
-		__field(int, ret)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->tx_ant = tx_ant;
-		__entry->rx_ant = rx_ant;
-		__entry->ret = ret;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d",
-		LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret
-	)
-);
-
-TRACE_EVENT(drv_get_antenna,
-	TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret),
-
-	TP_ARGS(local, tx_ant, rx_ant, ret),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u32, tx_ant)
-		__field(u32, rx_ant)
-		__field(int, ret)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->tx_ant = tx_ant;
-		__entry->rx_ant = rx_ant;
-		__entry->ret = ret;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d",
-		LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret
-	)
-);
-
-TRACE_EVENT(drv_remain_on_channel,
-	TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan,
-		 enum nl80211_channel_type chantype, unsigned int duration),
-
-	TP_ARGS(local, chan, chantype, duration),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(int, center_freq)
-		__field(int, channel_type)
-		__field(unsigned int, duration)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->center_freq = chan->center_freq;
-		__entry->channel_type = chantype;
-		__entry->duration = duration;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " freq:%dMHz duration:%dms",
-		LOCAL_PR_ARG, __entry->center_freq, __entry->duration
-	)
-);
-
-DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-TRACE_EVENT(drv_offchannel_tx,
-	TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb,
-		 struct ieee80211_channel *chan,
-		 enum nl80211_channel_type channel_type,
-		 unsigned int wait),
-
-	TP_ARGS(local, skb, chan, channel_type, wait),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(int, center_freq)
-		__field(int, channel_type)
-		__field(unsigned int, wait)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->center_freq = chan->center_freq;
-		__entry->channel_type = channel_type;
-		__entry->wait = wait;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " freq:%dMHz, wait:%dms",
-		LOCAL_PR_ARG, __entry->center_freq, __entry->wait
-	)
-);
-
-TRACE_EVENT(drv_set_ringparam,
-	TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx),
-
-	TP_ARGS(local, tx, rx),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u32, tx)
-		__field(u32, rx)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->tx = tx;
-		__entry->rx = rx;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " tx:%d rx %d",
-		LOCAL_PR_ARG, __entry->tx, __entry->rx
-	)
-);
-
-TRACE_EVENT(drv_get_ringparam,
-	TP_PROTO(struct ieee80211_local *local, u32 *tx, u32 *tx_max,
-		 u32 *rx, u32 *rx_max),
-
-	TP_ARGS(local, tx, tx_max, rx, rx_max),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u32, tx)
-		__field(u32, tx_max)
-		__field(u32, rx)
-		__field(u32, rx_max)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->tx = *tx;
-		__entry->tx_max = *tx_max;
-		__entry->rx = *rx;
-		__entry->rx_max = *rx_max;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " tx:%d tx_max %d rx %d rx_max %d",
-		LOCAL_PR_ARG,
-		__entry->tx, __entry->tx_max, __entry->rx, __entry->rx_max
-	)
-);
-
-DEFINE_EVENT(local_only_evt, drv_tx_frames_pending,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-TRACE_EVENT(drv_set_bitrate_mask,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 const struct cfg80211_bitrate_mask *mask),
-
-	TP_ARGS(local, sdata, mask),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		__field(u32, legacy_2g)
-		__field(u32, legacy_5g)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		__entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy;
-		__entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x",
-		LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g
-	)
-);
-
-TRACE_EVENT(drv_set_rekey_data,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 struct cfg80211_gtk_rekey_data *data),
-
-	TP_ARGS(local, sdata, data),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		VIF_ENTRY
-		__array(u8, kek, NL80211_KEK_LEN)
-		__array(u8, kck, NL80211_KCK_LEN)
-		__array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		memcpy(__entry->kek, data->kek, NL80211_KEK_LEN);
-		memcpy(__entry->kck, data->kck, NL80211_KCK_LEN);
-		memcpy(__entry->replay_ctr, data->replay_ctr,
-		       NL80211_REPLAY_CTR_LEN);
-	),
-
-	TP_printk(LOCAL_PR_FMT VIF_PR_FMT,
-		  LOCAL_PR_ARG, VIF_PR_ARG)
-);
-
-TRACE_EVENT(drv_rssi_callback,
-	TP_PROTO(struct ieee80211_local *local,
-		 enum ieee80211_rssi_event rssi_event),
-
-	TP_ARGS(local, rssi_event),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u32, rssi_event)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->rssi_event = rssi_event;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " rssi_event:%d",
-		LOCAL_PR_ARG, __entry->rssi_event
-	)
-);
-
-DECLARE_EVENT_CLASS(release_evt,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sta *sta,
-		 u16 tids, int num_frames,
-		 enum ieee80211_frame_release_type reason,
-		 bool more_data),
-
-	TP_ARGS(local, sta, tids, num_frames, reason, more_data),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		STA_ENTRY
-		__field(u16, tids)
-		__field(int, num_frames)
-		__field(int, reason)
-		__field(bool, more_data)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		STA_ASSIGN;
-		__entry->tids = tids;
-		__entry->num_frames = num_frames;
-		__entry->reason = reason;
-		__entry->more_data = more_data;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT STA_PR_FMT
-		" TIDs:0x%.4x frames:%d reason:%d more:%d",
-		LOCAL_PR_ARG, STA_PR_ARG, __entry->tids, __entry->num_frames,
-		__entry->reason, __entry->more_data
-	)
-);
-
-DEFINE_EVENT(release_evt, drv_release_buffered_frames,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sta *sta,
-		 u16 tids, int num_frames,
-		 enum ieee80211_frame_release_type reason,
-		 bool more_data),
-
-	TP_ARGS(local, sta, tids, num_frames, reason, more_data)
-);
-
-DEFINE_EVENT(release_evt, drv_allow_buffered_frames,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sta *sta,
-		 u16 tids, int num_frames,
-		 enum ieee80211_frame_release_type reason,
-		 bool more_data),
-
-	TP_ARGS(local, sta, tids, num_frames, reason, more_data)
-);
-
-/*
- * Tracing for API calls that drivers call.
- */
-
-TRACE_EVENT(api_start_tx_ba_session,
-	TP_PROTO(struct ieee80211_sta *sta, u16 tid),
-
-	TP_ARGS(sta, tid),
-
-	TP_STRUCT__entry(
-		STA_ENTRY
-		__field(u16, tid)
-	),
-
-	TP_fast_assign(
-		STA_ASSIGN;
-		__entry->tid = tid;
-	),
-
-	TP_printk(
-		STA_PR_FMT " tid:%d",
-		STA_PR_ARG, __entry->tid
-	)
-);
-
-TRACE_EVENT(api_start_tx_ba_cb,
-	TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
-
-	TP_ARGS(sdata, ra, tid),
-
-	TP_STRUCT__entry(
-		VIF_ENTRY
-		__array(u8, ra, ETH_ALEN)
-		__field(u16, tid)
-	),
-
-	TP_fast_assign(
-		VIF_ASSIGN;
-		memcpy(__entry->ra, ra, ETH_ALEN);
-		__entry->tid = tid;
-	),
-
-	TP_printk(
-		VIF_PR_FMT " ra:%pM tid:%d",
-		VIF_PR_ARG, __entry->ra, __entry->tid
-	)
-);
-
-TRACE_EVENT(api_stop_tx_ba_session,
-	TP_PROTO(struct ieee80211_sta *sta, u16 tid),
-
-	TP_ARGS(sta, tid),
-
-	TP_STRUCT__entry(
-		STA_ENTRY
-		__field(u16, tid)
-	),
-
-	TP_fast_assign(
-		STA_ASSIGN;
-		__entry->tid = tid;
-	),
-
-	TP_printk(
-		STA_PR_FMT " tid:%d",
-		STA_PR_ARG, __entry->tid
-	)
-);
-
-TRACE_EVENT(api_stop_tx_ba_cb,
-	TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
-
-	TP_ARGS(sdata, ra, tid),
-
-	TP_STRUCT__entry(
-		VIF_ENTRY
-		__array(u8, ra, ETH_ALEN)
-		__field(u16, tid)
-	),
-
-	TP_fast_assign(
-		VIF_ASSIGN;
-		memcpy(__entry->ra, ra, ETH_ALEN);
-		__entry->tid = tid;
-	),
-
-	TP_printk(
-		VIF_PR_FMT " ra:%pM tid:%d",
-		VIF_PR_ARG, __entry->ra, __entry->tid
-	)
-);
-
-DEFINE_EVENT(local_only_evt, api_restart_hw,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-TRACE_EVENT(api_beacon_loss,
-	TP_PROTO(struct ieee80211_sub_if_data *sdata),
-
-	TP_ARGS(sdata),
-
-	TP_STRUCT__entry(
-		VIF_ENTRY
-	),
-
-	TP_fast_assign(
-		VIF_ASSIGN;
-	),
-
-	TP_printk(
-		VIF_PR_FMT,
-		VIF_PR_ARG
-	)
-);
-
-TRACE_EVENT(api_connection_loss,
-	TP_PROTO(struct ieee80211_sub_if_data *sdata),
-
-	TP_ARGS(sdata),
-
-	TP_STRUCT__entry(
-		VIF_ENTRY
-	),
-
-	TP_fast_assign(
-		VIF_ASSIGN;
-	),
-
-	TP_printk(
-		VIF_PR_FMT,
-		VIF_PR_ARG
-	)
-);
-
-TRACE_EVENT(api_cqm_rssi_notify,
-	TP_PROTO(struct ieee80211_sub_if_data *sdata,
-		 enum nl80211_cqm_rssi_threshold_event rssi_event),
-
-	TP_ARGS(sdata, rssi_event),
-
-	TP_STRUCT__entry(
-		VIF_ENTRY
-		__field(u32, rssi_event)
-	),
-
-	TP_fast_assign(
-		VIF_ASSIGN;
-		__entry->rssi_event = rssi_event;
-	),
-
-	TP_printk(
-		VIF_PR_FMT " event:%d",
-		VIF_PR_ARG, __entry->rssi_event
-	)
-);
-
-TRACE_EVENT(api_scan_completed,
-	TP_PROTO(struct ieee80211_local *local, bool aborted),
-
-	TP_ARGS(local, aborted),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(bool, aborted)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->aborted = aborted;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " aborted:%d",
-		LOCAL_PR_ARG, __entry->aborted
-	)
-);
-
-TRACE_EVENT(api_sched_scan_results,
-	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(api_sched_scan_stopped,
-	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(api_sta_block_awake,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sta *sta, bool block),
-
-	TP_ARGS(local, sta, block),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		STA_ENTRY
-		__field(bool, block)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		STA_ASSIGN;
-		__entry->block = block;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT STA_PR_FMT " block:%d",
-		LOCAL_PR_ARG, STA_PR_FMT, __entry->block
-	)
-);
-
-TRACE_EVENT(api_chswitch_done,
-	TP_PROTO(struct ieee80211_sub_if_data *sdata, bool success),
-
-	TP_ARGS(sdata, success),
-
-	TP_STRUCT__entry(
-		VIF_ENTRY
-		__field(bool, success)
-	),
-
-	TP_fast_assign(
-		VIF_ASSIGN;
-		__entry->success = success;
-	),
-
-	TP_printk(
-		VIF_PR_FMT " success=%d",
-		VIF_PR_ARG, __entry->success
-	)
-);
-
-DEFINE_EVENT(local_only_evt, api_ready_on_channel,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_only_evt, api_remain_on_channel_expired,
-	TP_PROTO(struct ieee80211_local *local),
-	TP_ARGS(local)
-);
-
-TRACE_EVENT(api_gtk_rekey_notify,
-	TP_PROTO(struct ieee80211_sub_if_data *sdata,
-		 const u8 *bssid, const u8 *replay_ctr),
-
-	TP_ARGS(sdata, bssid, replay_ctr),
-
-	TP_STRUCT__entry(
-		VIF_ENTRY
-		__array(u8, bssid, ETH_ALEN)
-		__array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN)
-	),
-
-	TP_fast_assign(
-		VIF_ASSIGN;
-		memcpy(__entry->bssid, bssid, ETH_ALEN);
-		memcpy(__entry->replay_ctr, replay_ctr, NL80211_REPLAY_CTR_LEN);
-	),
-
-	TP_printk(VIF_PR_FMT, VIF_PR_ARG)
-);
-
-TRACE_EVENT(api_enable_rssi_reports,
-	TP_PROTO(struct ieee80211_sub_if_data *sdata,
-		 int rssi_min_thold, int rssi_max_thold),
-
-	TP_ARGS(sdata, rssi_min_thold, rssi_max_thold),
-
-	TP_STRUCT__entry(
-		VIF_ENTRY
-		__field(int, rssi_min_thold)
-		__field(int, rssi_max_thold)
-	),
-
-	TP_fast_assign(
-		VIF_ASSIGN;
-		__entry->rssi_min_thold = rssi_min_thold;
-		__entry->rssi_max_thold = rssi_max_thold;
-	),
-
-	TP_printk(
-		VIF_PR_FMT " rssi_min_thold =%d, rssi_max_thold = %d",
-		VIF_PR_ARG, __entry->rssi_min_thold, __entry->rssi_max_thold
-	)
-);
-
-TRACE_EVENT(api_eosp,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sta *sta),
-
-	TP_ARGS(local, sta),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		STA_ENTRY
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		STA_ASSIGN;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT STA_PR_FMT,
-		LOCAL_PR_ARG, STA_PR_FMT
-	)
-);
-
-/*
- * Tracing for internal functions
- * (which may also be called in response to driver calls)
- */
-
-TRACE_EVENT(wake_queue,
-	TP_PROTO(struct ieee80211_local *local, u16 queue,
-		 enum queue_stop_reason reason),
-
-	TP_ARGS(local, queue, reason),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u16, queue)
-		__field(u32, reason)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->queue = queue;
-		__entry->reason = reason;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " queue:%d, reason:%d",
-		LOCAL_PR_ARG, __entry->queue, __entry->reason
-	)
-);
-
-TRACE_EVENT(stop_queue,
-	TP_PROTO(struct ieee80211_local *local, u16 queue,
-		 enum queue_stop_reason reason),
-
-	TP_ARGS(local, queue, reason),
-
-	TP_STRUCT__entry(
-		LOCAL_ENTRY
-		__field(u16, queue)
-		__field(u32, reason)
-	),
-
-	TP_fast_assign(
-		LOCAL_ASSIGN;
-		__entry->queue = queue;
-		__entry->reason = reason;
-	),
-
-	TP_printk(
-		LOCAL_PR_FMT " queue:%d, reason:%d",
-		LOCAL_PR_ARG, __entry->queue, __entry->reason
-	)
-);
-#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
-
-#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_FILE driver-trace
-#include <trace/define_trace.h>
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 6f8615c..4b4538d 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -305,12 +305,10 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
 	tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
 	initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	net_dbg_ratelimited("delba from %pM (%s) tid %d reason code %d\n",
-			    mgmt->sa, initiator ? "initiator" : "recipient",
-			    tid,
-			    le16_to_cpu(mgmt->u.action.u.delba.reason_code));
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+	ht_dbg_ratelimited(sdata, "delba from %pM (%s) tid %d reason code %d\n",
+			   mgmt->sa, initiator ? "initiator" : "recipient",
+			   tid,
+			   le16_to_cpu(mgmt->u.action.u.delba.reason_code));
 
 	if (initiator == WLAN_BACK_INITIATOR)
 		__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 33d9d0c..5746d62 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -82,8 +82,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
 	local->oper_channel = chan;
 	channel_type = ifibss->channel_type;
-	if (channel_type > NL80211_CHAN_HT20 &&
-	    !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
+	if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
 		channel_type = NL80211_CHAN_HT20;
 	if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
 		/* can only fail due to HT40+/- mismatch */
@@ -262,11 +261,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
 
 	memcpy(addr, sta->sta.addr, ETH_ALEN);
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	wiphy_debug(sdata->local->hw.wiphy,
-		    "Adding new IBSS station %pM (dev=%s)\n",
-		    addr, sdata->name);
-#endif
+	ibss_dbg(sdata, "Adding new IBSS station %pM\n", addr);
 
 	sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
 	sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
@@ -280,12 +275,10 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
 	/* If it fails, maybe we raced another insertion? */
 	if (sta_info_insert_rcu(sta))
 		return sta_info_get(sdata, addr);
-	if (auth) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-		printk(KERN_DEBUG "TX Auth SA=%pM DA=%pM BSSID=%pM"
-		       "(auth_transaction=1)\n", sdata->vif.addr,
-		       sdata->u.ibss.bssid, addr);
-#endif
+	if (auth && !sdata->u.ibss.auth_frame_registrations) {
+		ibss_dbg(sdata,
+			 "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n",
+			 sdata->vif.addr, sdata->u.ibss.bssid, addr);
 		ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0,
 				    addr, sdata->u.ibss.bssid, NULL, 0, 0);
 	}
@@ -308,7 +301,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
 	 * 	allow new one to be added.
 	 */
 	if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
-		net_dbg_ratelimited("%s: No room for a new IBSS STA entry %pM\n",
+		net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n",
 				    sdata->name, addr);
 		rcu_read_lock();
 		return NULL;
@@ -355,11 +348,9 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
 
 	if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
 		return;
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "%s: RX Auth SA=%pM DA=%pM BSSID=%pM."
-	       "(auth_transaction=%d)\n",
-	       sdata->name, mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction);
-#endif
+	ibss_dbg(sdata,
+		 "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n",
+		 mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction);
 	sta_info_destroy_addr(sdata, mgmt->sa);
 	ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false);
 	rcu_read_unlock();
@@ -422,15 +413,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 					ieee80211_mandatory_rates(local, band);
 
 				if (sta->sta.supp_rates[band] != prev_rates) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-					printk(KERN_DEBUG
-						"%s: updated supp_rates set "
-						"for %pM based on beacon"
-						"/probe_resp (0x%x -> 0x%x)\n",
-						sdata->name, sta->sta.addr,
-						prev_rates,
-						sta->sta.supp_rates[band]);
-#endif
+					ibss_dbg(sdata,
+						 "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n",
+						 sta->sta.addr, prev_rates,
+						 sta->sta.supp_rates[band]);
 					rates_updated = true;
 				}
 			} else {
@@ -545,22 +531,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 		rx_timestamp = drv_get_tsf(local, sdata);
 	}
 
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
-	       "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
-	       mgmt->sa, mgmt->bssid,
-	       (unsigned long long)rx_timestamp,
-	       (unsigned long long)beacon_timestamp,
-	       (unsigned long long)(rx_timestamp - beacon_timestamp),
-	       jiffies);
-#endif
+	ibss_dbg(sdata,
+		 "RX beacon SA=%pM BSSID=%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
+		 mgmt->sa, mgmt->bssid,
+		 (unsigned long long)rx_timestamp,
+		 (unsigned long long)beacon_timestamp,
+		 (unsigned long long)(rx_timestamp - beacon_timestamp),
+		 jiffies);
 
 	if (beacon_timestamp > rx_timestamp) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-		printk(KERN_DEBUG "%s: beacon TSF higher than "
-		       "local TSF - IBSS merge with BSSID %pM\n",
-		       sdata->name, mgmt->bssid);
-#endif
+		ibss_dbg(sdata,
+			 "beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n",
+			 mgmt->bssid);
 		ieee80211_sta_join_ibss(sdata, bss);
 		supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL);
 		ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
@@ -586,7 +568,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
 	 * 	allow new one to be added.
 	 */
 	if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
-		net_dbg_ratelimited("%s: No room for a new IBSS STA entry %pM\n",
+		net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n",
 				    sdata->name, addr);
 		return;
 	}
@@ -662,8 +644,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
 	if (ifibss->fixed_channel)
 		return;
 
-	printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
-	       "IBSS networks with same SSID (merge)\n", sdata->name);
+	sdata_info(sdata,
+		   "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n");
 
 	ieee80211_request_internal_scan(sdata,
 			ifibss->ssid, ifibss->ssid_len, NULL);
@@ -691,8 +673,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
 		bssid[0] |= 0x02;
 	}
 
-	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
-	       sdata->name, bssid);
+	sdata_info(sdata, "Creating new IBSS network, BSSID %pM\n", bssid);
 
 	capability = WLAN_CAPABILITY_IBSS;
 
@@ -723,10 +704,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 	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",
-	       sdata->name, active_ibss);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+	ibss_dbg(sdata, "sta_find_ibss (active_ibss=%d)\n", active_ibss);
 
 	if (active_ibss)
 		return;
@@ -749,29 +727,24 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 		struct ieee80211_bss *bss;
 
 		bss = (void *)cbss->priv;
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-		printk(KERN_DEBUG "   sta_find_ibss: selected %pM current "
-		       "%pM\n", cbss->bssid, ifibss->bssid);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-
-		printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
-		       " based on configured SSID\n",
-		       sdata->name, cbss->bssid);
+		ibss_dbg(sdata,
+			 "sta_find_ibss: selected %pM current %pM\n",
+			 cbss->bssid, ifibss->bssid);
+		sdata_info(sdata,
+			   "Selected IBSS BSSID %pM based on configured SSID\n",
+			   cbss->bssid);
 
 		ieee80211_sta_join_ibss(sdata, bss);
 		ieee80211_rx_bss_put(local, bss);
 		return;
 	}
 
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "   did not try to join ibss\n");
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+	ibss_dbg(sdata, "sta_find_ibss: did not try to join ibss\n");
 
 	/* Selected IBSS not found in current scan results - try to scan */
 	if (time_after(jiffies, ifibss->last_scan_completed +
 					IEEE80211_SCAN_INTERVAL)) {
-		printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
-		       "join\n", sdata->name);
+		sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
 
 		ieee80211_request_internal_scan(sdata,
 				ifibss->ssid, ifibss->ssid_len,
@@ -785,9 +758,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 				ieee80211_sta_create_ibss(sdata);
 				return;
 			}
-			printk(KERN_DEBUG "%s: IBSS not allowed on"
-			       " %d MHz\n", sdata->name,
-			       local->hw.conf.channel->center_freq);
+			sdata_info(sdata, "IBSS not allowed on %d MHz\n",
+				   local->hw.conf.channel->center_freq);
 
 			/* No IBSS found - decrease scan interval and continue
 			 * scanning. */
@@ -822,12 +794,9 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 
 	tx_last_beacon = drv_tx_last_beacon(local);
 
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
-	       " (tx_last_beacon=%d)\n",
-	       sdata->name, mgmt->sa, mgmt->da,
-	       mgmt->bssid, tx_last_beacon);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+	ibss_dbg(sdata,
+		 "RX ProbeReq SA=%pM DA=%pM BSSID=%pM (tx_last_beacon=%d)\n",
+		 mgmt->sa, mgmt->da, mgmt->bssid, tx_last_beacon);
 
 	if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da))
 		return;
@@ -840,11 +809,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 	pos = mgmt->u.probe_req.variable;
 	if (pos[0] != WLAN_EID_SSID ||
 	    pos + 2 + pos[1] > end) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-		printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
-		       "from %pM\n",
-		       sdata->name, mgmt->sa);
-#endif
+		ibss_dbg(sdata, "Invalid SSID IE in ProbeReq from %pM\n",
+			 mgmt->sa);
 		return;
 	}
 	if (pos[1] != 0 &&
@@ -861,10 +827,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 
 	resp = (struct ieee80211_mgmt *) skb->data;
 	memcpy(resp->da, mgmt->sa, ETH_ALEN);
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
-	       sdata->name, resp->da);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+	ibss_dbg(sdata, "Sending ProbeResp to %pM\n", resp->da);
 	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
 	ieee80211_tx_skb(sdata, skb);
 }
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3f3cd50..f834a00 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -30,6 +30,7 @@
 #include <net/mac80211.h>
 #include "key.h"
 #include "sta_info.h"
+#include "debug.h"
 
 struct ieee80211_local;
 
@@ -55,11 +56,14 @@ struct ieee80211_local;
 #define TU_TO_JIFFIES(x)	(usecs_to_jiffies((x) * 1024))
 #define TU_TO_EXP_TIME(x)	(jiffies + TU_TO_JIFFIES(x))
 
+/*
+ * Some APs experience problems when working with U-APSD. Decrease the
+ * probability of that happening by using legacy mode for all ACs but VO.
+ * The AP that caused us trouble was a Cisco 4410N. It ignores our
+ * setting, and always treats non-VO ACs as legacy.
+ */
 #define IEEE80211_DEFAULT_UAPSD_QUEUES \
-	(IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |	\
-	 IEEE80211_WMM_IE_STA_QOSINFO_AC_BE |	\
-	 IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |	\
-	 IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+	IEEE80211_WMM_IE_STA_QOSINFO_AC_VO
 
 #define IEEE80211_DEFAULT_MAX_SP_LEN		\
 	IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL
@@ -317,55 +321,30 @@ struct mesh_preq_queue {
 	u8 flags;
 };
 
-enum ieee80211_work_type {
-	IEEE80211_WORK_ABORT,
-	IEEE80211_WORK_REMAIN_ON_CHANNEL,
-	IEEE80211_WORK_OFFCHANNEL_TX,
-};
-
-/**
- * enum work_done_result - indicates what to do after work was done
- *
- * @WORK_DONE_DESTROY: This work item is no longer needed, destroy.
- * @WORK_DONE_REQUEUE: This work item was reset to be reused, and
- *	should be requeued.
- */
-enum work_done_result {
-	WORK_DONE_DESTROY,
-	WORK_DONE_REQUEUE,
-};
+#if HZ/100 == 0
+#define IEEE80211_ROC_MIN_LEFT	1
+#else
+#define IEEE80211_ROC_MIN_LEFT	(HZ/100)
+#endif
 
-struct ieee80211_work {
+struct ieee80211_roc_work {
 	struct list_head list;
+	struct list_head dependents;
 
-	struct rcu_head rcu_head;
+	struct delayed_work work;
 
 	struct ieee80211_sub_if_data *sdata;
 
-	enum work_done_result (*done)(struct ieee80211_work *wk,
-				      struct sk_buff *skb);
-
 	struct ieee80211_channel *chan;
 	enum nl80211_channel_type chan_type;
 
-	unsigned long timeout;
-	enum ieee80211_work_type type;
+	bool started, abort, hw_begun, notified;
 
-	bool started;
+	unsigned long hw_start_time;
 
-	union {
-		struct {
-			u32 duration;
-		} remain;
-		struct {
-			struct sk_buff *frame;
-			u32 wait;
-			bool status;
-		} offchan_tx;
-	};
-
-	size_t data_len;
-	u8 data[];
+	u32 duration, req_duration;
+	struct sk_buff *frame;
+	u64 mgmt_tx_cookie;
 };
 
 /* flags used in struct ieee80211_if_managed.flags */
@@ -399,7 +378,6 @@ struct ieee80211_mgd_auth_data {
 struct ieee80211_mgd_assoc_data {
 	struct cfg80211_bss *bss;
 	const u8 *supp_rates;
-	const u8 *ht_operation_ie;
 
 	unsigned long timeout;
 	int tries;
@@ -414,6 +392,8 @@ struct ieee80211_mgd_assoc_data {
 	bool sent_assoc;
 	bool synced;
 
+	u8 ap_ht_param;
+
 	size_t ie_len;
 	u8 ie[];
 };
@@ -532,6 +512,7 @@ struct ieee80211_if_ibss {
 	bool privacy;
 
 	bool control_port;
+	unsigned int auth_frame_registrations;
 
 	u8 bssid[ETH_ALEN] __aligned(2);
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -701,6 +682,9 @@ struct ieee80211_sub_if_data {
 	/* TID bitmap for NoAck policy */
 	u16 noack_map;
 
+	/* bit field of ACM bits (BIT(802.1D tag)) */
+	u8 wmm_acm;
+
 	struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
 	struct ieee80211_key __rcu *default_unicast_key;
 	struct ieee80211_key __rcu *default_multicast_key;
@@ -847,13 +831,6 @@ struct ieee80211_local {
 	const struct ieee80211_ops *ops;
 
 	/*
-	 * work stuff, potentially off-channel (in the future)
-	 */
-	struct list_head work_list;
-	struct timer_list work_timer;
-	struct work_struct work_work;
-
-	/*
 	 * private workqueue to mac80211. mac80211 makes this accessible
 	 * via ieee80211_queue_work()
 	 */
@@ -912,6 +889,9 @@ struct ieee80211_local {
 	/* device is started */
 	bool started;
 
+	/* device is during a HW reconfig */
+	bool in_reconfig;
+
 	/* wowlan is enabled -- don't reconfig on resume */
 	bool wowlan;
 
@@ -1050,7 +1030,6 @@ struct ieee80211_local {
 	int total_ps_buffered; /* total number of all buffered unicast and
 				* multicast packets for power saving stations
 				*/
-	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
 	bool pspolling;
 	bool offchannel_ps_enabled;
@@ -1087,14 +1066,12 @@ struct ieee80211_local {
 	} debugfs;
 #endif
 
-	struct ieee80211_channel *hw_roc_channel;
-	struct net_device *hw_roc_dev;
-	struct sk_buff *hw_roc_skb, *hw_roc_skb_for_status;
+	/*
+	 * Remain-on-channel support
+	 */
+	struct list_head roc_list;
 	struct work_struct hw_roc_start, hw_roc_done;
-	enum nl80211_channel_type hw_roc_channel_type;
-	unsigned int hw_roc_duration;
-	u32 hw_roc_cookie;
-	bool hw_roc_for_tx;
+	unsigned long hw_roc_start_time;
 
 	struct idr ack_status_frames;
 	spinlock_t ack_status_lock;
@@ -1290,7 +1267,12 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
 				    bool offchannel_ps_enable);
 void ieee80211_offchannel_return(struct ieee80211_local *local,
 				 bool offchannel_ps_disable);
-void ieee80211_hw_roc_setup(struct ieee80211_local *local);
+void ieee80211_roc_setup(struct ieee80211_local *local);
+void ieee80211_start_next_roc(struct ieee80211_local *local);
+void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata);
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc);
+void ieee80211_sw_roc_work(struct work_struct *work);
+void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
 
 /* interface handling */
 int ieee80211_iface_init(void);
@@ -1500,18 +1482,6 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
 			       enum nl80211_channel_type channel_type,
 			       u16 prot_mode);
 
-/* internal work items */
-void ieee80211_work_init(struct ieee80211_local *local);
-void ieee80211_add_work(struct ieee80211_work *wk);
-void free_work(struct ieee80211_work *wk);
-void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata);
-int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
-				   struct ieee80211_channel *chan,
-				   enum nl80211_channel_type channel_type,
-				   unsigned int duration, u64 *cookie);
-int ieee80211_wk_cancel_remain_on_channel(
-	struct ieee80211_sub_if_data *sdata, u64 cookie);
-
 /* channel management */
 enum ieee80211_chan_mode {
 	CHAN_MODE_UNDEFINED,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8664111..58c2ab3 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -57,9 +57,6 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
 		return -EINVAL;
 	}
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 	dev->mtu = new_mtu;
 	return 0;
 }
@@ -100,15 +97,12 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_sub_if_data *nsdata;
-	struct net_device *dev = sdata->dev;
 
 	ASSERT_RTNL();
 
 	/* we hold the RTNL here so can safely walk the list */
 	list_for_each_entry(nsdata, &local->interfaces, list) {
-		struct net_device *ndev = nsdata->dev;
-
-		if (ndev != dev && ieee80211_sdata_running(nsdata)) {
+		if (nsdata != sdata && ieee80211_sdata_running(nsdata)) {
 			/*
 			 * Allow only a single IBSS interface to be up at any
 			 * time. This is restricted because beacon distribution
@@ -127,7 +121,8 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
 			 * The remaining checks are only performed for interfaces
 			 * with the same MAC address.
 			 */
-			if (!ether_addr_equal(dev->dev_addr, ndev->dev_addr))
+			if (!ether_addr_equal(sdata->vif.addr,
+					      nsdata->vif.addr))
 				continue;
 
 			/*
@@ -528,10 +523,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 	 */
 	netif_tx_stop_all_queues(sdata->dev);
 
-	/*
-	 * Purge work for this interface.
-	 */
-	ieee80211_work_purge(sdata);
+	ieee80211_roc_purge(sdata);
 
 	/*
 	 * Remove all stations associated with this interface.
@@ -637,18 +629,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 		ieee80211_configure_filter(local);
 		break;
 	default:
-		mutex_lock(&local->mtx);
-		if (local->hw_roc_dev == sdata->dev &&
-		    local->hw_roc_channel) {
-			/* ignore return value since this is racy */
-			drv_cancel_remain_on_channel(local);
-			ieee80211_queue_work(&local->hw, &local->hw_roc_done);
-		}
-		mutex_unlock(&local->mtx);
-
-		flush_work(&local->hw_roc_start);
-		flush_work(&local->hw_roc_done);
-
 		flush_work(&sdata->work);
 		/*
 		 * When we get here, the interface is marked down.
@@ -823,7 +803,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
 
 	hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len));
 
-	return ieee80211_select_queue_80211(local, skb, hdr);
+	return ieee80211_select_queue_80211(sdata, skb, hdr);
 }
 
 static const struct net_device_ops ieee80211_monitorif_ops = {
@@ -1238,7 +1218,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
 
 		if (__ffs64(mask) + hweight64(mask) != fls64(mask)) {
 			/* not a contiguous mask ... not handled now! */
-			printk(KERN_DEBUG "not contiguous\n");
+			pr_info("not contiguous\n");
 			break;
 		}
 
@@ -1364,6 +1344,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 			sdata->u.mgd.use_4addr = params->use_4addr;
 	}
 
+	ndev->features |= local->hw.netdev_features;
+
 	ret = register_netdevice(ndev);
 	if (ret)
 		goto fail;
@@ -1427,10 +1409,6 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local,
 	if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
 		return 0;
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason);
-#endif
-
 	local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
 	return IEEE80211_CONF_CHANGE_IDLE;
 }
@@ -1440,10 +1418,6 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
 	if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
 		return 0;
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	wiphy_debug(local->hw.wiphy, "device now idle\n");
-#endif
-
 	drv_flush(local, false);
 
 	local->hw.conf.flags |= IEEE80211_CONF_IDLE;
@@ -1454,9 +1428,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 {
 	struct ieee80211_sub_if_data *sdata;
 	int count = 0;
-	bool working = false, scanning = false, hw_roc = false;
-	struct ieee80211_work *wk;
+	bool working = false, scanning = false;
 	unsigned int led_trig_start = 0, led_trig_stop = 0;
+	struct ieee80211_roc_work *roc;
 
 #ifdef CONFIG_PROVE_LOCKING
 	WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
@@ -1491,9 +1465,11 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 		count++;
 	}
 
-	list_for_each_entry(wk, &local->work_list, list) {
-		working = true;
-		wk->sdata->vif.bss_conf.idle = false;
+	if (!local->ops->remain_on_channel) {
+		list_for_each_entry(roc, &local->roc_list, list) {
+			working = true;
+			roc->sdata->vif.bss_conf.idle = false;
+		}
 	}
 
 	if (local->scan_sdata &&
@@ -1502,9 +1478,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 		local->scan_sdata->vif.bss_conf.idle = false;
 	}
 
-	if (local->hw_roc_channel)
-		hw_roc = true;
-
 	list_for_each_entry(sdata, &local->interfaces, list) {
 		if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
 		    sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -1516,7 +1489,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
 	}
 
-	if (working || scanning || hw_roc)
+	if (working || scanning)
 		led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK;
 	else
 		led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK;
@@ -1528,8 +1501,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 
 	ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
 
-	if (hw_roc)
-		return ieee80211_idle_off(local, "hw remain-on-channel");
 	if (working)
 		return ieee80211_idle_off(local, "working");
 	if (scanning)
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 5bb600d..b3b7e52 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -139,7 +139,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 	}
 
 	if (ret != -ENOSPC && ret != -EOPNOTSUPP)
-		wiphy_err(key->local->hw.wiphy,
+		sdata_err(sdata,
 			  "failed to set key (%d, %pM) to hardware (%d)\n",
 			  key->conf.keyidx,
 			  sta ? sta->sta.addr : bcast_addr, ret);
@@ -186,7 +186,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 			  sta ? &sta->sta : NULL, &key->conf);
 
 	if (ret)
-		wiphy_err(key->local->hw.wiphy,
+		sdata_err(sdata,
 			  "failed to remove key (%d, %pM) from hardware (%d)\n",
 			  key->conf.keyidx,
 			  sta ? sta->sta.addr : bcast_addr, ret);
diff --git a/net/mac80211/led.c b/net/mac80211/led.c
index 1bf7903..bcffa69 100644
--- a/net/mac80211/led.c
+++ b/net/mac80211/led.c
@@ -276,7 +276,7 @@ static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
 
 	read_lock(&tpt_trig->trig.leddev_list_lock);
 	list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
-		led_brightness_set(led_cdev, LED_OFF);
+		led_set_brightness(led_cdev, LED_OFF);
 	read_unlock(&tpt_trig->trig.leddev_list_lock);
 }
 
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index f5548e9..0b040fb 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -345,6 +345,13 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
 	ieee80211_stop_queues_by_reason(hw,
 		IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
+	/*
+	 * Stop all Rx during the reconfig. We don't want state changes
+	 * or driver callbacks while this is in progress.
+	 */
+	local->in_reconfig = true;
+	barrier();
+
 	schedule_work(&local->restart_work);
 }
 EXPORT_SYMBOL(ieee80211_restart_hw);
@@ -455,7 +462,9 @@ static const struct ieee80211_txrx_stypes
 ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
 	[NL80211_IFTYPE_ADHOC] = {
 		.tx = 0xffff,
-		.rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+			BIT(IEEE80211_STYPE_AUTH >> 4) |
+			BIT(IEEE80211_STYPE_DEAUTH >> 4),
 	},
 	[NL80211_IFTYPE_STATION] = {
 		.tx = 0xffff,
@@ -625,8 +634,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
 	INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 
-	ieee80211_work_init(local);
-
 	INIT_WORK(&local->restart_work, ieee80211_restart_work);
 
 	INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
@@ -669,7 +676,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
 	ieee80211_led_names(local);
 
-	ieee80211_hw_roc_setup(local);
+	ieee80211_roc_setup(local);
 
 	return &local->hw;
 }
@@ -682,6 +689,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	enum ieee80211_band band;
 	int channels, max_bitrates;
 	bool supp_ht;
+	netdev_features_t feature_whitelist;
 	static const u32 cipher_suites[] = {
 		/* keep WEP first, it may be removed below */
 		WLAN_CIPHER_SUITE_WEP40,
@@ -708,6 +716,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
 		return -EINVAL;
 
+	/* Only HW csum features are currently compatible with mac80211 */
+	feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+			    NETIF_F_HW_CSUM;
+	if (WARN_ON(hw->netdev_features & ~feature_whitelist))
+		return -EINVAL;
+
 	if (hw->max_report_rates == 0)
 		hw->max_report_rates = hw->max_rates;
 
@@ -1009,12 +1023,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 
 	rtnl_unlock();
 
-	/*
-	 * Now all work items will be gone, but the
-	 * timer might still be armed, so delete it
-	 */
-	del_timer_sync(&local->work_timer);
-
 	cancel_work_sync(&local->restart_work);
 	cancel_work_sync(&local->reconfig_filter);
 
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 2913113..764593d 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -443,7 +443,7 @@ static void ieee80211_mesh_path_root_timer(unsigned long data)
 
 void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
 {
-	if (ifmsh->mshcfg.dot11MeshHWMPRootMode)
+	if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)
 		set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
 	else {
 		clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
@@ -523,11 +523,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
 {
 	bool free_plinks;
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: running mesh housekeeping\n",
-	       sdata->name);
-#endif
-
 	ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
 	mesh_path_expire(sdata);
 
@@ -542,11 +537,17 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	u32 interval;
 
 	mesh_path_tx_root_frame(sdata);
+
+	if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN)
+		interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
+	else
+		interval = ifmsh->mshcfg.dot11MeshHWMProotInterval;
+
 	mod_timer(&ifmsh->mesh_path_root_timer,
-		  round_jiffies(TU_TO_EXP_TIME(
-				  ifmsh->mshcfg.dot11MeshHWMPRannInterval)));
+		  round_jiffies(TU_TO_EXP_TIME(interval)));
 }
 
 #ifdef CONFIG_PM
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index e364275..faaa39b 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -104,6 +104,7 @@ enum mesh_deferred_task_flags {
  * an mpath to a hash bucket on a path table.
  * @rann_snd_addr: the RANN sender address
  * @rann_metric: the aggregated path metric towards the root node
+ * @last_preq_to_root: Timestamp of last PREQ sent to root
  * @is_root: the destination station of this path is a root node
  * @is_gate: the destination station of this path is a mesh gate
  *
@@ -131,6 +132,7 @@ struct mesh_path {
 	spinlock_t state_lock;
 	u8 rann_snd_addr[ETH_ALEN];
 	u32 rann_metric;
+	unsigned long last_preq_to_root;
 	bool is_root;
 	bool is_gate;
 };
@@ -245,7 +247,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
 void ieee80211s_init(void);
 void ieee80211s_update_metric(struct ieee80211_local *local,
-		struct sta_info *stainfo, struct sk_buff *skb);
+		struct sta_info *sta, struct sk_buff *skb);
 void ieee80211s_stop(void);
 void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
 void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 9b59658..fb7b6a1 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -13,13 +13,6 @@
 #include "wme.h"
 #include "mesh.h"
 
-#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG
-#define mhwmp_dbg(fmt, args...) \
-	printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "\n", sdata->name, ##args)
-#else
-#define mhwmp_dbg(fmt, args...)   do { (void)(0); } while (0)
-#endif
-
 #define TEST_FRAME_LEN	8192
 #define MAX_METRIC	0xffffffff
 #define ARITH_SHIFT	8
@@ -98,6 +91,8 @@ static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae)
 #define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries)
 #define disc_timeout_jiff(s) \
 	msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout)
+#define root_path_confirmation_jiffies(s) \
+	msecs_to_jiffies(sdata->u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval)
 
 enum mpath_frame_type {
 	MPATH_PREQ = 0,
@@ -142,19 +137,19 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
 
 	switch (action) {
 	case MPATH_PREQ:
-		mhwmp_dbg("sending PREQ to %pM", target);
+		mhwmp_dbg(sdata, "sending PREQ to %pM\n", target);
 		ie_len = 37;
 		pos = skb_put(skb, 2 + ie_len);
 		*pos++ = WLAN_EID_PREQ;
 		break;
 	case MPATH_PREP:
-		mhwmp_dbg("sending PREP to %pM", target);
+		mhwmp_dbg(sdata, "sending PREP to %pM\n", target);
 		ie_len = 31;
 		pos = skb_put(skb, 2 + ie_len);
 		*pos++ = WLAN_EID_PREP;
 		break;
 	case MPATH_RANN:
-		mhwmp_dbg("sending RANN from %pM", orig_addr);
+		mhwmp_dbg(sdata, "sending RANN from %pM\n", orig_addr);
 		ie_len = sizeof(struct ieee80211_rann_ie);
 		pos = skb_put(skb, 2 + ie_len);
 		*pos++ = WLAN_EID_RANN;
@@ -303,7 +298,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
 }
 
 void ieee80211s_update_metric(struct ieee80211_local *local,
-		struct sta_info *stainfo, struct sk_buff *skb)
+		struct sta_info *sta, struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -315,15 +310,14 @@ void ieee80211s_update_metric(struct ieee80211_local *local,
 	failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK);
 
 	/* moving average, scaled to 100 */
-	stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed);
-	if (stainfo->fail_avg > 95)
-		mesh_plink_broken(stainfo);
+	sta->fail_avg = ((80 * sta->fail_avg + 5) / 100 + 20 * failed);
+	if (sta->fail_avg > 95)
+		mesh_plink_broken(sta);
 }
 
 static u32 airtime_link_metric_get(struct ieee80211_local *local,
 				   struct sta_info *sta)
 {
-	struct ieee80211_supported_band *sband;
 	struct rate_info rinfo;
 	/* This should be adjusted for each device */
 	int device_constant = 1 << ARITH_SHIFT;
@@ -333,8 +327,6 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
 	u32 tx_time, estimated_retx;
 	u64 result;
 
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
 	if (sta->fail_avg >= 100)
 		return MAX_METRIC;
 
@@ -519,10 +511,11 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 	struct mesh_path *mpath = NULL;
 	u8 *target_addr, *orig_addr;
 	const u8 *da;
-	u8 target_flags, ttl;
-	u32 orig_sn, target_sn, lifetime;
+	u8 target_flags, ttl, flags;
+	u32 orig_sn, target_sn, lifetime, orig_metric;
 	bool reply = false;
 	bool forward = true;
+	bool root_is_gate;
 
 	/* Update target SN, if present */
 	target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
@@ -530,11 +523,15 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 	target_sn = PREQ_IE_TARGET_SN(preq_elem);
 	orig_sn = PREQ_IE_ORIG_SN(preq_elem);
 	target_flags = PREQ_IE_TARGET_F(preq_elem);
+	orig_metric = metric;
+	/* Proactive PREQ gate announcements */
+	flags = PREQ_IE_FLAGS(preq_elem);
+	root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
 
-	mhwmp_dbg("received PREQ from %pM", orig_addr);
+	mhwmp_dbg(sdata, "received PREQ from %pM\n", orig_addr);
 
 	if (ether_addr_equal(target_addr, sdata->vif.addr)) {
-		mhwmp_dbg("PREQ is for us");
+		mhwmp_dbg(sdata, "PREQ is for us\n");
 		forward = false;
 		reply = true;
 		metric = 0;
@@ -544,6 +541,22 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 			target_sn = ++ifmsh->sn;
 			ifmsh->last_sn_update = jiffies;
 		}
+	} else if (is_broadcast_ether_addr(target_addr) &&
+		   (target_flags & IEEE80211_PREQ_TO_FLAG)) {
+		rcu_read_lock();
+		mpath = mesh_path_lookup(orig_addr, sdata);
+		if (mpath) {
+			if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
+				reply = true;
+				target_addr = sdata->vif.addr;
+				target_sn = ++ifmsh->sn;
+				metric = 0;
+				ifmsh->last_sn_update = jiffies;
+			}
+			if (root_is_gate)
+				mesh_path_add_gate(mpath);
+		}
+		rcu_read_unlock();
 	} else {
 		rcu_read_lock();
 		mpath = mesh_path_lookup(target_addr, sdata);
@@ -570,19 +583,20 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 		lifetime = PREQ_IE_LIFETIME(preq_elem);
 		ttl = ifmsh->mshcfg.element_ttl;
 		if (ttl != 0) {
-			mhwmp_dbg("replying to the PREQ");
+			mhwmp_dbg(sdata, "replying to the PREQ\n");
 			mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr,
 				cpu_to_le32(orig_sn), 0, target_addr,
 				cpu_to_le32(target_sn), mgmt->sa, 0, ttl,
 				cpu_to_le32(lifetime), cpu_to_le32(metric),
 				0, sdata);
-		} else
+		} else {
 			ifmsh->mshstats.dropped_frames_ttl++;
+		}
 	}
 
 	if (forward && ifmsh->mshcfg.dot11MeshForwarding) {
 		u32 preq_id;
-		u8 hopcount, flags;
+		u8 hopcount;
 
 		ttl = PREQ_IE_TTL(preq_elem);
 		lifetime = PREQ_IE_LIFETIME(preq_elem);
@@ -590,13 +604,19 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 			ifmsh->mshstats.dropped_frames_ttl++;
 			return;
 		}
-		mhwmp_dbg("forwarding the PREQ from %pM", orig_addr);
+		mhwmp_dbg(sdata, "forwarding the PREQ from %pM\n", orig_addr);
 		--ttl;
-		flags = PREQ_IE_FLAGS(preq_elem);
 		preq_id = PREQ_IE_PREQ_ID(preq_elem);
 		hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
 		da = (mpath && mpath->is_root) ?
 			mpath->rann_snd_addr : broadcast_addr;
+
+		if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
+			target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
+			target_sn = PREQ_IE_TARGET_SN(preq_elem);
+			metric = orig_metric;
+		}
+
 		mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
 				cpu_to_le32(orig_sn), target_flags, target_addr,
 				cpu_to_le32(target_sn), da,
@@ -631,7 +651,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
 	u8 next_hop[ETH_ALEN];
 	u32 target_sn, orig_sn, lifetime;
 
-	mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem));
+	mhwmp_dbg(sdata, "received PREP from %pM\n",
+		  PREP_IE_ORIG_ADDR(prep_elem));
 
 	orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
 	if (ether_addr_equal(orig_addr, sdata->vif.addr))
@@ -744,11 +765,6 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
 	bool root_is_gate;
 
 	ttl = rann->rann_ttl;
-	if (ttl <= 1) {
-		ifmsh->mshstats.dropped_frames_ttl++;
-		return;
-	}
-	ttl--;
 	flags = rann->rann_flags;
 	root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
 	orig_addr = rann->rann_addr;
@@ -762,8 +778,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
 	if (ether_addr_equal(orig_addr, sdata->vif.addr))
 		return;
 
-	mhwmp_dbg("received RANN from %pM via neighbour %pM (is_gate=%d)",
-			orig_addr, mgmt->sa, root_is_gate);
+	mhwmp_dbg(sdata,
+		  "received RANN from %pM via neighbour %pM (is_gate=%d)\n",
+		  orig_addr, mgmt->sa, root_is_gate);
 
 	rcu_read_lock();
 	sta = sta_info_get(sdata, mgmt->sa);
@@ -785,34 +802,50 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
+	if (!(SN_LT(mpath->sn, orig_sn)) &&
+	    !(mpath->sn == orig_sn && metric < mpath->rann_metric)) {
+		rcu_read_unlock();
+		return;
+	}
+
 	if ((!(mpath->flags & (MESH_PATH_ACTIVE | MESH_PATH_RESOLVING)) ||
-	     time_after(jiffies, mpath->exp_time - 1*HZ)) &&
-	     !(mpath->flags & MESH_PATH_FIXED)) {
-		mhwmp_dbg("%s time to refresh root mpath %pM", sdata->name,
-							       orig_addr);
+	     (time_after(jiffies, mpath->last_preq_to_root +
+				  root_path_confirmation_jiffies(sdata)) ||
+	     time_before(jiffies, mpath->last_preq_to_root))) &&
+	     !(mpath->flags & MESH_PATH_FIXED) && (ttl != 0)) {
+		mhwmp_dbg(sdata,
+			  "time to refresh root mpath %pM\n",
+			  orig_addr);
 		mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
+		mpath->last_preq_to_root = jiffies;
+	}
+
+	mpath->sn = orig_sn;
+	mpath->rann_metric = metric + metric_txsta;
+	mpath->is_root = true;
+	/* Recording RANNs sender address to send individually
+	 * addressed PREQs destined for root mesh STA */
+	memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN);
+
+	if (root_is_gate)
+		mesh_path_add_gate(mpath);
+
+	if (ttl <= 1) {
+		ifmsh->mshstats.dropped_frames_ttl++;
+		rcu_read_unlock();
+		return;
 	}
+	ttl--;
 
-	if ((SN_LT(mpath->sn, orig_sn) || (mpath->sn == orig_sn &&
-	   metric < mpath->rann_metric)) && ifmsh->mshcfg.dot11MeshForwarding) {
+	if (ifmsh->mshcfg.dot11MeshForwarding) {
 		mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
 				       cpu_to_le32(orig_sn),
 				       0, NULL, 0, broadcast_addr,
 				       hopcount, ttl, cpu_to_le32(interval),
 				       cpu_to_le32(metric + metric_txsta),
 				       0, sdata);
-		mpath->sn = orig_sn;
-		mpath->rann_metric = metric + metric_txsta;
-		/* Recording RANNs sender address to send individually
-		 * addressed PREQs destined for root mesh STA */
-		memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN);
 	}
 
-	mpath->is_root = true;
-
-	if (root_is_gate)
-		mesh_path_add_gate(mpath);
-
 	rcu_read_unlock();
 }
 
@@ -889,7 +922,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
 
 	preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
 	if (!preq_node) {
-		mhwmp_dbg("could not allocate PREQ node");
+		mhwmp_dbg(sdata, "could not allocate PREQ node\n");
 		return;
 	}
 
@@ -898,7 +931,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
 		spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
 		kfree(preq_node);
 		if (printk_ratelimit())
-			mhwmp_dbg("PREQ node queue full");
+			mhwmp_dbg(sdata, "PREQ node queue full\n");
 		return;
 	}
 
@@ -1146,7 +1179,7 @@ void mesh_path_timer(unsigned long data)
 		if (!mpath->is_gate && mesh_gate_num(sdata) > 0) {
 			ret = mesh_path_send_to_gates(mpath);
 			if (ret)
-				mhwmp_dbg("no gate was reachable");
+				mhwmp_dbg(sdata, "no gate was reachable\n");
 		} else
 			mesh_path_flush_pending(mpath);
 	}
@@ -1157,13 +1190,34 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
-	u8 flags;
+	u8 flags, target_flags = 0;
 
 	flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol)
 			? RANN_FLAG_IS_GATE : 0;
-	mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
+
+	switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) {
+	case IEEE80211_PROACTIVE_RANN:
+		mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
 			       cpu_to_le32(++ifmsh->sn),
 			       0, NULL, 0, broadcast_addr,
-			       0, sdata->u.mesh.mshcfg.element_ttl,
+			       0, ifmsh->mshcfg.element_ttl,
 			       cpu_to_le32(interval), 0, 0, sdata);
+		break;
+	case IEEE80211_PROACTIVE_PREQ_WITH_PREP:
+		flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG;
+	case IEEE80211_PROACTIVE_PREQ_NO_PREP:
+		interval = ifmsh->mshcfg.dot11MeshHWMPactivePathToRootTimeout;
+		target_flags |= IEEE80211_PREQ_TO_FLAG |
+				IEEE80211_PREQ_USN_FLAG;
+		mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr,
+				cpu_to_le32(++ifmsh->sn), target_flags,
+				(u8 *) broadcast_addr, 0, broadcast_addr,
+				0, ifmsh->mshcfg.element_ttl,
+				cpu_to_le32(interval),
+				0, cpu_to_le32(ifmsh->preq_id++), sdata);
+		break;
+	default:
+		mhwmp_dbg(sdata, "Proactive mechanism not supported\n");
+		return;
+	}
 }
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index b39224d..c9ae931 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -18,12 +18,6 @@
 #include "ieee80211_i.h"
 #include "mesh.h"
 
-#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG
-#define mpath_dbg(fmt, args...)	printk(KERN_DEBUG fmt, ##args)
-#else
-#define mpath_dbg(fmt, args...)	do { (void)(0); } while (0)
-#endif
-
 /* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
 #define INIT_PATHS_SIZE_ORDER	2
 
@@ -322,9 +316,8 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath,
 
 	spin_lock_irqsave(&gate_mpath->frame_queue.lock, flags);
 	skb_queue_splice(&gateq, &gate_mpath->frame_queue);
-	mpath_dbg("Mpath queue for gate %pM has %d frames\n",
-			gate_mpath->dst,
-			skb_queue_len(&gate_mpath->frame_queue));
+	mpath_dbg(gate_mpath->sdata, "Mpath queue for gate %pM has %d frames\n",
+		  gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue));
 	spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags);
 
 	if (!copy)
@@ -446,9 +439,9 @@ int mesh_path_add_gate(struct mesh_path *mpath)
 	hlist_add_head_rcu(&new_gate->list, tbl->known_gates);
 	spin_unlock_bh(&tbl->gates_lock);
 	rcu_read_unlock();
-	mpath_dbg("Mesh path (%s): Recorded new gate: %pM. %d known gates\n",
-		  mpath->sdata->name, mpath->dst,
-		  mpath->sdata->u.mesh.num_gates);
+	mpath_dbg(mpath->sdata,
+		  "Mesh path: Recorded new gate: %pM. %d known gates\n",
+		  mpath->dst, mpath->sdata->u.mesh.num_gates);
 	return 0;
 err_rcu:
 	rcu_read_unlock();
@@ -477,8 +470,8 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
 			spin_unlock_bh(&tbl->gates_lock);
 			mpath->sdata->u.mesh.num_gates--;
 			mpath->is_gate = false;
-			mpath_dbg("Mesh path (%s): Deleted gate: %pM. "
-				  "%d known gates\n", mpath->sdata->name,
+			mpath_dbg(mpath->sdata,
+				  "Mesh path: Deleted gate: %pM. %d known gates\n",
 				  mpath->dst, mpath->sdata->u.mesh.num_gates);
 			break;
 		}
@@ -946,19 +939,20 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
 			continue;
 
 		if (gate->mpath->flags & MESH_PATH_ACTIVE) {
-			mpath_dbg("Forwarding to %pM\n", gate->mpath->dst);
+			mpath_dbg(sdata, "Forwarding to %pM\n", gate->mpath->dst);
 			mesh_path_move_to_queue(gate->mpath, from_mpath, copy);
 			from_mpath = gate->mpath;
 			copy = true;
 		} else {
-			mpath_dbg("Not forwarding %p\n", gate->mpath);
-			mpath_dbg("flags %x\n", gate->mpath->flags);
+			mpath_dbg(sdata,
+				  "Not forwarding %p (flags %#x)\n",
+				  gate->mpath, gate->mpath->flags);
 		}
 	}
 
 	hlist_for_each_entry_rcu(gate, n, known_gates, list)
 		if (gate->mpath->sdata == sdata) {
-			mpath_dbg("Sending to %pM\n", gate->mpath->dst);
+			mpath_dbg(sdata, "Sending to %pM\n", gate->mpath->dst);
 			mesh_path_tx_pending(gate->mpath);
 		}
 
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 60ef235..a1dbd15 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -13,12 +13,6 @@
 #include "rate.h"
 #include "mesh.h"
 
-#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
-#define mpl_dbg(fmt, args...)	printk(KERN_DEBUG fmt, ##args)
-#else
-#define mpl_dbg(fmt, args...)	do { (void)(0); } while (0)
-#endif
-
 #define PLINK_GET_LLID(p) (p + 2)
 #define PLINK_GET_PLID(p) (p + 4)
 
@@ -134,12 +128,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
 
 		switch (sta->ch_type) {
 		case NL80211_CHAN_NO_HT:
-			mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present",
+			mpl_dbg(sdata,
+				"mesh_plink %pM: nonHT sta (%pM) is present\n",
 				sdata->vif.addr, sta->sta.addr);
 			non_ht_sta = true;
 			goto out;
 		case NL80211_CHAN_HT20:
-			mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present",
+			mpl_dbg(sdata,
+				"mesh_plink %pM: HT20 sta (%pM) is present\n",
 				sdata->vif.addr, sta->sta.addr);
 			ht20_sta = true;
 		default:
@@ -160,7 +156,8 @@ out:
 		sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
 		sdata->u.mesh.mshcfg.ht_opmode = ht_opmode;
 		changed = BSS_CHANGED_HT;
-		mpl_dbg("mesh_plink %pM: protection mode changed to %d",
+		mpl_dbg(sdata,
+			"mesh_plink %pM: protection mode changed to %d\n",
 			sdata->vif.addr, ht_opmode);
 	}
 
@@ -437,7 +434,8 @@ static void mesh_plink_timer(unsigned long data)
 		spin_unlock_bh(&sta->lock);
 		return;
 	}
-	mpl_dbg("Mesh plink timer for %pM fired on state %d\n",
+	mpl_dbg(sta->sdata,
+		"Mesh plink timer for %pM fired on state %d\n",
 		sta->sta.addr, sta->plink_state);
 	reason = 0;
 	llid = sta->llid;
@@ -450,7 +448,8 @@ static void mesh_plink_timer(unsigned long data)
 		/* retry timer */
 		if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
 			u32 rand;
-			mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n",
+			mpl_dbg(sta->sdata,
+				"Mesh plink for %pM (retry, timeout): %d %d\n",
 				sta->sta.addr, sta->plink_retries,
 				sta->plink_timeout);
 			get_random_bytes(&rand, sizeof(u32));
@@ -530,7 +529,8 @@ int mesh_plink_open(struct sta_info *sta)
 	sta->plink_state = NL80211_PLINK_OPN_SNT;
 	mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
 	spin_unlock_bh(&sta->lock);
-	mpl_dbg("Mesh plink: starting establishment with %pM\n",
+	mpl_dbg(sdata,
+		"Mesh plink: starting establishment with %pM\n",
 		sta->sta.addr);
 
 	return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
@@ -565,7 +565,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 	u8 *baseaddr;
 	u32 changed = 0;
 	__le16 plid, llid, reason;
-#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
 	static const char *mplstates[] = {
 		[NL80211_PLINK_LISTEN] = "LISTEN",
 		[NL80211_PLINK_OPN_SNT] = "OPN-SNT",
@@ -575,14 +574,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 		[NL80211_PLINK_HOLDING] = "HOLDING",
 		[NL80211_PLINK_BLOCKED] = "BLOCKED"
 	};
-#endif
 
 	/* need action_code, aux */
 	if (len < IEEE80211_MIN_ACTION_SIZE + 3)
 		return;
 
 	if (is_multicast_ether_addr(mgmt->da)) {
-		mpl_dbg("Mesh plink: ignore frame from multicast address");
+		mpl_dbg(sdata,
+			"Mesh plink: ignore frame from multicast address\n");
 		return;
 	}
 
@@ -595,12 +594,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 	}
 	ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
 	if (!elems.peering) {
-		mpl_dbg("Mesh plink: missing necessary peer link ie\n");
+		mpl_dbg(sdata,
+			"Mesh plink: missing necessary peer link ie\n");
 		return;
 	}
 	if (elems.rsn_len &&
 			sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
-		mpl_dbg("Mesh plink: can't establish link with secure peer\n");
+		mpl_dbg(sdata,
+			"Mesh plink: can't establish link with secure peer\n");
 		return;
 	}
 
@@ -610,14 +611,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 	    (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
 	    (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
 							&& ie_len != 8)) {
-		mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n",
-		    ftype, ie_len);
+		mpl_dbg(sdata,
+			"Mesh plink: incorrect plink ie length %d %d\n",
+			ftype, ie_len);
 		return;
 	}
 
 	if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
 				(!elems.mesh_id || !elems.mesh_config)) {
-		mpl_dbg("Mesh plink: missing necessary ie\n");
+		mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
 		return;
 	}
 	/* Note the lines below are correct, the llid in the frame is the plid
@@ -632,21 +634,21 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 
 	sta = sta_info_get(sdata, mgmt->sa);
 	if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {
-		mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
+		mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
 		rcu_read_unlock();
 		return;
 	}
 
 	if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
 	    !rssi_threshold_check(sta, sdata)) {
-		mpl_dbg("Mesh plink: %pM does not meet rssi threshold\n",
+		mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
 			mgmt->sa);
 		rcu_read_unlock();
 		return;
 	}
 
 	if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
-		mpl_dbg("Mesh plink: Action frame from non-authed peer\n");
+		mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
 		rcu_read_unlock();
 		return;
 	}
@@ -683,7 +685,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 	} else if (!sta) {
 		/* ftype == WLAN_SP_MESH_PEERING_OPEN */
 		if (!mesh_plink_free_count(sdata)) {
-			mpl_dbg("Mesh plink error: no more free plinks\n");
+			mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
 			rcu_read_unlock();
 			return;
 		}
@@ -724,7 +726,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 				event = CLS_ACPT;
 			break;
 		default:
-			mpl_dbg("Mesh plink: unknown frame subtype\n");
+			mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
 			rcu_read_unlock();
 			return;
 		}
@@ -734,13 +736,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 		/* allocate sta entry if necessary and update info */
 		sta = mesh_peer_init(sdata, mgmt->sa, &elems);
 		if (!sta) {
-			mpl_dbg("Mesh plink: failed to init peer!\n");
+			mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
 			rcu_read_unlock();
 			return;
 		}
 	}
 
-	mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
+	mpl_dbg(sdata,
+		"Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
 		mgmt->sa, mplstates[sta->plink_state],
 		le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
 		event);
@@ -851,7 +854,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 			mesh_plink_inc_estab_count(sdata);
 			changed |= mesh_set_ht_prot_mode(sdata);
 			changed |= BSS_CHANGED_BEACON;
-			mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
+			mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
 				sta->sta.addr);
 			break;
 		default:
@@ -887,7 +890,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 			mesh_plink_inc_estab_count(sdata);
 			changed |= mesh_set_ht_prot_mode(sdata);
 			changed |= BSS_CHANGED_BEACON;
-			mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
+			mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
 				sta->sta.addr);
 			mesh_plink_frame_tx(sdata,
 					    WLAN_SP_MESH_PEERING_CONFIRM,
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c
index 38d30e8..accfa00 100644
--- a/net/mac80211/mesh_sync.c
+++ b/net/mac80211/mesh_sync.c
@@ -12,13 +12,6 @@
 #include "mesh.h"
 #include "driver-ops.h"
 
-#ifdef CONFIG_MAC80211_VERBOSE_MESH_SYNC_DEBUG
-#define msync_dbg(fmt, args...) \
-	printk(KERN_DEBUG "Mesh sync (%s): " fmt "\n", sdata->name, ##args)
-#else
-#define msync_dbg(fmt, args...)   do { (void)(0); } while (0)
-#endif
-
 /* This is not in the standard.  It represents a tolerable tbtt drift below
  * which we do no TSF adjustment.
  */
@@ -65,14 +58,14 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
 	spin_lock_bh(&ifmsh->sync_offset_lock);
 
 	if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) {
-		msync_dbg("TBTT : max clockdrift=%lld; adjusting",
-			(long long) ifmsh->sync_offset_clockdrift_max);
+		msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting\n",
+			  (long long) ifmsh->sync_offset_clockdrift_max);
 		tsfdelta = -ifmsh->sync_offset_clockdrift_max;
 		ifmsh->sync_offset_clockdrift_max = 0;
 	} else {
-		msync_dbg("TBTT : max clockdrift=%lld; adjusting by %llu",
-			(long long) ifmsh->sync_offset_clockdrift_max,
-			(unsigned long long) beacon_int_fraction);
+		msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting by %llu\n",
+			  (long long) ifmsh->sync_offset_clockdrift_max,
+			  (unsigned long long) beacon_int_fraction);
 		tsfdelta = -beacon_int_fraction;
 		ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction;
 	}
@@ -120,7 +113,7 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 
 	if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {
 		clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
-		msync_dbg("STA %pM : is adjusting TBTT", sta->sta.addr);
+		msync_dbg(sdata, "STA %pM : is adjusting TBTT\n", sta->sta.addr);
 		goto no_sync;
 	}
 
@@ -169,7 +162,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 	if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
 		s64 t_clockdrift = sta->t_offset_setpoint
 				   - sta->t_offset;
-		msync_dbg("STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld",
+		msync_dbg(sdata,
+			  "STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld\n",
 			  sta->sta.addr,
 			  (long long) sta->t_offset,
 			  (long long)
@@ -178,7 +172,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 
 		if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT ||
 			t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) {
-			msync_dbg("STA %pM : t_clockdrift=%lld too large, setpoint reset",
+			msync_dbg(sdata,
+				  "STA %pM : t_clockdrift=%lld too large, setpoint reset\n",
 				  sta->sta.addr,
 				  (long long) t_clockdrift);
 			clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
@@ -197,8 +192,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 	} else {
 		sta->t_offset_setpoint = sta->t_offset - TOFFSET_SET_MARGIN;
 		set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
-		msync_dbg("STA %pM : offset was invalid, "
-			  " sta->t_offset=%lld",
+		msync_dbg(sdata,
+			  "STA %pM : offset was invalid, sta->t_offset=%lld\n",
 			  sta->sta.addr,
 			  (long long) sta->t_offset);
 		rcu_read_unlock();
@@ -226,17 +221,15 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
 		 * to the driver tsf setter, we punt
 		 * the tsf adjustment to the mesh tasklet
 		 */
-		msync_dbg("TBTT : kicking off TBTT "
-			  "adjustment with "
-			  "clockdrift_max=%lld",
-		  ifmsh->sync_offset_clockdrift_max);
+		msync_dbg(sdata,
+			  "TBTT : kicking off TBTT adjustment with clockdrift_max=%lld\n",
+			  ifmsh->sync_offset_clockdrift_max);
 		set_bit(MESH_WORK_DRIFT_ADJUST,
 			&ifmsh->wrkq_flags);
 	} else {
-		msync_dbg("TBTT : max clockdrift=%lld; "
-			  "too small to adjust",
-			  (long long)
-		       ifmsh->sync_offset_clockdrift_max);
+		msync_dbg(sdata,
+			  "TBTT : max clockdrift=%lld; too small to adjust\n",
+			  (long long)ifmsh->sync_offset_clockdrift_max);
 		ifmsh->sync_offset_clockdrift_max = 0;
 	}
 	spin_unlock_bh(&ifmsh->sync_offset_lock);
@@ -268,7 +261,7 @@ static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 	const u8 *oui;
 
 	WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
-	msync_dbg("called mesh_sync_vendor_rx_bcn_presp");
+	msync_dbg(sdata, "called mesh_sync_vendor_rx_bcn_presp\n");
 	oui = mesh_get_vendor_oui(sdata);
 	/*  here you would implement the vendor offset tracking for this oui */
 }
@@ -278,7 +271,7 @@ static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
 	const u8 *oui;
 
 	WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
-	msync_dbg("called mesh_sync_vendor_adjust_tbtt");
+	msync_dbg(sdata, "called mesh_sync_vendor_adjust_tbtt\n");
 	oui = mesh_get_vendor_oui(sdata);
 	/*  here you would implement the vendor tsf adjustment for this oui */
 }
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 91d84cc..e6fe84a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -258,12 +258,11 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
 }
 
 static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
-				struct sk_buff *skb, const u8 *ht_oper_ie,
+				struct sk_buff *skb, u8 ap_ht_param,
 				struct ieee80211_supported_band *sband,
 				struct ieee80211_channel *channel,
 				enum ieee80211_smps_mode smps)
 {
-	struct ieee80211_ht_operation *ht_oper;
 	u8 *pos;
 	u32 flags = channel->flags;
 	u16 cap;
@@ -271,21 +270,13 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
 
 	BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
 
-	if (!ht_oper_ie)
-		return;
-
-	if (ht_oper_ie[1] < sizeof(struct ieee80211_ht_operation))
-		return;
-
 	memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
 	ieee80211_apply_htcap_overrides(sdata, &ht_cap);
 
-	ht_oper = (struct ieee80211_ht_operation *)(ht_oper_ie + 2);
-
 	/* determine capability flags */
 	cap = ht_cap.cap;
 
-	switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+	switch (ap_ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
 	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
 		if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
 			cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
@@ -509,7 +500,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 	}
 
 	if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
-		ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_operation_ie,
+		ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
 				    sband, local->oper_channel, ifmgd->ap_smps);
 
 	/* if present, add any custom non-vendor IEs that go after HT */
@@ -939,11 +930,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 		return;
 	}
 
-	if (!list_empty(&local->work_list)) {
-		local->ps_sdata = NULL;
-		goto change;
-	}
-
 	list_for_each_entry(sdata, &local->interfaces, list) {
 		if (!ieee80211_sdata_running(sdata))
 			continue;
@@ -1016,7 +1002,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 		local->ps_sdata = NULL;
 	}
 
- change:
 	ieee80211_change_ps(local);
 }
 
@@ -1156,7 +1141,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
 
 	memset(&params, 0, sizeof(params));
 
-	local->wmm_acm = 0;
+	sdata->wmm_acm = 0;
 	for (; left >= 4; left -= 4, pos += 4) {
 		int aci = (pos[0] >> 5) & 0x03;
 		int acm = (pos[0] >> 4) & 0x01;
@@ -1167,21 +1152,21 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
 		case 1: /* AC_BK */
 			queue = 3;
 			if (acm)
-				local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
+				sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
 			if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
 				uapsd = true;
 			break;
 		case 2: /* AC_VI */
 			queue = 1;
 			if (acm)
-				local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
+				sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
 			if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
 				uapsd = true;
 			break;
 		case 3: /* AC_VO */
 			queue = 0;
 			if (acm)
-				local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
+				sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
 			if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
 				uapsd = true;
 			break;
@@ -1189,7 +1174,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
 		default:
 			queue = 2;
 			if (acm)
-				local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
+				sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
 			if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
 				uapsd = true;
 			break;
@@ -1201,19 +1186,16 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
 		params.txop = get_unaligned_le16(pos + 2);
 		params.uapsd = uapsd;
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		wiphy_debug(local->hw.wiphy,
-			    "WMM queue=%d aci=%d acm=%d aifs=%d "
-			    "cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
-			    queue, aci, acm,
-			    params.aifs, params.cw_min, params.cw_max,
-			    params.txop, params.uapsd);
-#endif
+		mlme_dbg(sdata,
+			 "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
+			 queue, aci, acm,
+			 params.aifs, params.cw_min, params.cw_max,
+			 params.txop, params.uapsd);
 		sdata->tx_conf[queue] = params;
 		if (drv_conf_tx(local, sdata, queue, &params))
-			wiphy_debug(local->hw.wiphy,
-				    "failed to set TX queue parameters for queue %d\n",
-				    queue);
+			sdata_err(sdata,
+				  "failed to set TX queue parameters for queue %d\n",
+				  queue);
 	}
 
 	/* enable WMM or activate new settings */
@@ -1290,7 +1272,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 
 	bss_info_changed |= BSS_CHANGED_BEACON_INT;
 	bss_info_changed |= ieee80211_handle_bss_capability(sdata,
-		cbss->capability, bss->has_erp_value, bss->erp_value);
+		bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value);
 
 	sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec(
 		IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int));
@@ -1342,7 +1324,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	u32 changed = 0;
-	u8 bssid[ETH_ALEN];
 
 	ASSERT_MGD_MTX(ifmgd);
 
@@ -1352,10 +1333,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 	if (WARN_ON(!ifmgd->associated))
 		return;
 
-	memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
+	ieee80211_stop_poll(sdata);
 
 	ifmgd->associated = NULL;
-	memset(ifmgd->bssid, 0, ETH_ALEN);
 
 	/*
 	 * we need to commit the associated = NULL change because the
@@ -1375,7 +1355,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 	netif_carrier_off(sdata->dev);
 
 	mutex_lock(&local->sta_mtx);
-	sta = sta_info_get(sdata, bssid);
+	sta = sta_info_get(sdata, ifmgd->bssid);
 	if (sta) {
 		set_sta_flag(sta, WLAN_STA_BLOCK_BA);
 		ieee80211_sta_tear_down_BA_sessions(sta, tx);
@@ -1384,13 +1364,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
 	/* deauthenticate/disassociate now */
 	if (tx || frame_buf)
-		ieee80211_send_deauth_disassoc(sdata, bssid, stype, reason,
-					       tx, frame_buf);
+		ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype,
+					       reason, tx, frame_buf);
 
 	/* flush out frame */
 	if (tx)
 		drv_flush(local, false);
 
+	/* clear bssid only after building the needed mgmt frames */
+	memset(ifmgd->bssid, 0, ETH_ALEN);
+
 	/* remove AP and TDLS peers */
 	sta_info_flush(local, sdata);
 
@@ -1580,11 +1563,12 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
 		goto out;
 	}
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 	if (beacon)
-		net_dbg_ratelimited("%s: detected beacon loss from AP - sending probe request\n",
-				    sdata->name);
-#endif
+		mlme_dbg_ratelimited(sdata,
+				     "detected beacon loss from AP - sending probe request\n");
+
+	ieee80211_cqm_rssi_notify(&sdata->vif,
+		NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL);
 
 	/*
 	 * The driver/our work has already reported this event or the
@@ -1667,8 +1651,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
 
 	memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
 
-	printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n",
-	       sdata->name, bssid);
+	sdata_info(sdata, "Connection to AP %pM lost\n", bssid);
 
 	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
 			       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
@@ -1802,9 +1785,10 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 		return RX_MGMT_NONE;
 
 	if (status_code != WLAN_STATUS_SUCCESS) {
-		printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n",
-		       sdata->name, mgmt->sa, status_code);
-		goto out;
+		sdata_info(sdata, "%pM denied authentication (status %d)\n",
+			   mgmt->sa, status_code);
+		ieee80211_destroy_auth_data(sdata, false);
+		return RX_MGMT_CFG80211_RX_AUTH;
 	}
 
 	switch (ifmgd->auth_data->algorithm) {
@@ -1825,8 +1809,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 		return RX_MGMT_NONE;
 	}
 
-	printk(KERN_DEBUG "%s: authenticated\n", sdata->name);
- out:
+	sdata_info(sdata, "authenticated\n");
 	ifmgd->auth_data->done = true;
 	ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
 	run_again(ifmgd, ifmgd->auth_data->timeout);
@@ -1839,8 +1822,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 		goto out_err;
 	}
 	if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) {
-		printk(KERN_DEBUG "%s: failed moving %pM to auth\n",
-		       sdata->name, bssid);
+		sdata_info(sdata, "failed moving %pM to auth\n", bssid);
 		goto out_err;
 	}
 	mutex_unlock(&sdata->local->sta_mtx);
@@ -1874,8 +1856,8 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
 
 	reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
-	printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
-			sdata->name, bssid, reason_code);
+	sdata_info(sdata, "deauthenticated from %pM (Reason: %u)\n",
+		   bssid, reason_code);
 
 	ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
@@ -1905,8 +1887,8 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
 
 	reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
-	printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
-			sdata->name, mgmt->sa, reason_code);
+	sdata_info(sdata, "disassociated from %pM (Reason: %u)\n",
+		   mgmt->sa, reason_code);
 
 	ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
@@ -1998,17 +1980,15 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
 	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
 
 	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
-		printk(KERN_DEBUG
-		       "%s: invalid AID value 0x%x; bits 15:14 not set\n",
-		       sdata->name, aid);
+		sdata_info(sdata, "invalid AID value 0x%x; bits 15:14 not set\n",
+			   aid);
 	aid &= ~(BIT(15) | BIT(14));
 
 	ifmgd->broken_ap = false;
 
 	if (aid == 0 || aid > IEEE80211_MAX_AID) {
-		printk(KERN_DEBUG
-		       "%s: invalid AID value %d (out of range), turn off PS\n",
-		       sdata->name, aid);
+		sdata_info(sdata, "invalid AID value %d (out of range), turn off PS\n",
+			   aid);
 		aid = 0;
 		ifmgd->broken_ap = true;
 	}
@@ -2017,8 +1997,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
 	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
 
 	if (!elems.supp_rates) {
-		printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
-		       sdata->name);
+		sdata_info(sdata, "no SuppRates element in AssocResp\n");
 		return false;
 	}
 
@@ -2058,9 +2037,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
 	if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
 		err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
 	if (err) {
-		printk(KERN_DEBUG
-		       "%s: failed to move station %pM to desired state\n",
-		       sdata->name, sta->sta.addr);
+		sdata_info(sdata,
+			   "failed to move station %pM to desired state\n",
+			   sta->sta.addr);
 		WARN_ON(__sta_info_destroy(sta));
 		mutex_unlock(&sdata->local->sta_mtx);
 		return false;
@@ -2143,10 +2122,10 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
 	aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
 
-	printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
-	       "status=%d aid=%d)\n",
-	       sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
-	       capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
+	sdata_info(sdata,
+		   "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n",
+		   reassoc ? "Rea" : "A", mgmt->sa,
+		   capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
 
 	pos = mgmt->u.assoc_resp.variable;
 	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
@@ -2157,9 +2136,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 		u32 tu, ms;
 		tu = get_unaligned_le32(elems.timeout_int + 1);
 		ms = tu * 1024 / 1000;
-		printk(KERN_DEBUG "%s: %pM rejected association temporarily; "
-		       "comeback duration %u TU (%u ms)\n",
-		       sdata->name, mgmt->sa, tu, ms);
+		sdata_info(sdata,
+			   "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
+			   mgmt->sa, tu, ms);
 		assoc_data->timeout = jiffies + msecs_to_jiffies(ms);
 		if (ms > IEEE80211_ASSOC_TIMEOUT)
 			run_again(ifmgd, assoc_data->timeout);
@@ -2169,11 +2148,11 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 	*bss = assoc_data->bss;
 
 	if (status_code != WLAN_STATUS_SUCCESS) {
-		printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n",
-		       sdata->name, mgmt->sa, status_code);
+		sdata_info(sdata, "%pM denied association (code=%d)\n",
+			   mgmt->sa, status_code);
 		ieee80211_destroy_assoc_data(sdata, false);
 	} else {
-		printk(KERN_DEBUG "%s: associated\n", sdata->name);
+		sdata_info(sdata, "associated\n");
 
 		if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
 			/* oops -- internal error -- send timeout for now */
@@ -2281,7 +2260,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 	if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&
 	    ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) {
 		/* got probe response, continue with auth */
-		printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name);
+		sdata_info(sdata, "direct probe responded\n");
 		ifmgd->auth_data->tries = 0;
 		ifmgd->auth_data->timeout = jiffies;
 		run_again(ifmgd, ifmgd->auth_data->timeout);
@@ -2417,10 +2396,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 	}
 
 	if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		net_dbg_ratelimited("%s: cancelling probereq poll due to a received beacon\n",
-				    sdata->name);
-#endif
+		mlme_dbg_ratelimited(sdata,
+				     "cancelling probereq poll due to a received beacon\n");
 		mutex_lock(&local->mtx);
 		ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
 		ieee80211_run_deferred_scan(local);
@@ -2612,8 +2589,6 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	u8 frame_buf[DEAUTH_DISASSOC_LEN];
 
-	ieee80211_stop_poll(sdata);
-
 	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
 			       false, frame_buf);
 	mutex_unlock(&ifmgd->mtx);
@@ -2645,8 +2620,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
 	auth_data->tries++;
 
 	if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) {
-		printk(KERN_DEBUG "%s: authentication with %pM timed out\n",
-		       sdata->name, auth_data->bss->bssid);
+		sdata_info(sdata, "authentication with %pM timed out\n",
+			   auth_data->bss->bssid);
 
 		/*
 		 * Most likely AP is not in the range so remove the
@@ -2658,9 +2633,9 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
 	}
 
 	if (auth_data->bss->proberesp_ies) {
-		printk(KERN_DEBUG "%s: send auth to %pM (try %d/%d)\n",
-		       sdata->name, auth_data->bss->bssid, auth_data->tries,
-		       IEEE80211_AUTH_MAX_TRIES);
+		sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
+			   auth_data->bss->bssid, auth_data->tries,
+			   IEEE80211_AUTH_MAX_TRIES);
 
 		auth_data->expected_transaction = 2;
 		ieee80211_send_auth(sdata, 1, auth_data->algorithm,
@@ -2670,9 +2645,9 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
 	} else {
 		const u8 *ssidie;
 
-		printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n",
-		       sdata->name, auth_data->bss->bssid, auth_data->tries,
-		       IEEE80211_AUTH_MAX_TRIES);
+		sdata_info(sdata, "direct probe to %pM (try %d/%i)\n",
+			   auth_data->bss->bssid, auth_data->tries,
+			   IEEE80211_AUTH_MAX_TRIES);
 
 		ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID);
 		if (!ssidie)
@@ -2700,8 +2675,8 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
 
 	assoc_data->tries++;
 	if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) {
-		printk(KERN_DEBUG "%s: association with %pM timed out\n",
-		       sdata->name, assoc_data->bss->bssid);
+		sdata_info(sdata, "association with %pM timed out\n",
+			   assoc_data->bss->bssid);
 
 		/*
 		 * Most likely AP is not in the range so remove the
@@ -2712,9 +2687,9 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
 		return -ETIMEDOUT;
 	}
 
-	printk(KERN_DEBUG "%s: associate with %pM (try %d/%d)\n",
-	       sdata->name, assoc_data->bss->bssid, assoc_data->tries,
-	       IEEE80211_ASSOC_MAX_TRIES);
+	sdata_info(sdata, "associate with %pM (try %d/%d)\n",
+		   assoc_data->bss->bssid, assoc_data->tries,
+		   IEEE80211_ASSOC_MAX_TRIES);
 	ieee80211_send_assoc(sdata);
 
 	assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
@@ -2787,45 +2762,31 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
 			ieee80211_reset_ap_probe(sdata);
 		else if (ifmgd->nullfunc_failed) {
 			if (ifmgd->probe_send_count < max_tries) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-				wiphy_debug(local->hw.wiphy,
-					    "%s: No ack for nullfunc frame to"
-					    " AP %pM, try %d/%i\n",
-					    sdata->name, bssid,
-					    ifmgd->probe_send_count, max_tries);
-#endif
+				mlme_dbg(sdata,
+					 "No ack for nullfunc frame to AP %pM, try %d/%i\n",
+					 bssid, ifmgd->probe_send_count,
+					 max_tries);
 				ieee80211_mgd_probe_ap_send(sdata);
 			} else {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-				wiphy_debug(local->hw.wiphy,
-					    "%s: No ack for nullfunc frame to"
-					    " AP %pM, disconnecting.\n",
-					    sdata->name, bssid);
-#endif
+				mlme_dbg(sdata,
+					 "No ack for nullfunc frame to AP %pM, disconnecting.\n",
+					 bssid);
 				ieee80211_sta_connection_lost(sdata, bssid,
 					WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
 			}
 		} else if (time_is_after_jiffies(ifmgd->probe_timeout))
 			run_again(ifmgd, ifmgd->probe_timeout);
 		else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-			wiphy_debug(local->hw.wiphy,
-				    "%s: Failed to send nullfunc to AP %pM"
-				    " after %dms, disconnecting.\n",
-				    sdata->name,
-				    bssid, probe_wait_ms);
-#endif
+			mlme_dbg(sdata,
+				 "Failed to send nullfunc to AP %pM after %dms, disconnecting\n",
+				 bssid, probe_wait_ms);
 			ieee80211_sta_connection_lost(sdata, bssid,
 				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
 		} else if (ifmgd->probe_send_count < max_tries) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-			wiphy_debug(local->hw.wiphy,
-				    "%s: No probe response from AP %pM"
-				    " after %dms, try %d/%i\n",
-				    sdata->name,
-				    bssid, probe_wait_ms,
-				    ifmgd->probe_send_count, max_tries);
-#endif
+			mlme_dbg(sdata,
+				 "No probe response from AP %pM after %dms, try %d/%i\n",
+				 bssid, probe_wait_ms,
+				 ifmgd->probe_send_count, max_tries);
 			ieee80211_mgd_probe_ap_send(sdata);
 		} else {
 			/*
@@ -2940,11 +2901,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
 		sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
 		mutex_lock(&ifmgd->mtx);
 		if (ifmgd->associated) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-			wiphy_debug(sdata->local->hw.wiphy,
-				    "%s: driver requested disconnect after resume.\n",
-				    sdata->name);
-#endif
+			mlme_dbg(sdata,
+				 "driver requested disconnect after resume\n");
 			ieee80211_sta_connection_lost(sdata,
 				ifmgd->associated->bssid,
 				WLAN_REASON_UNSPECIFIED);
@@ -3032,7 +2990,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_bss *bss = (void *)cbss->priv;
-	struct sta_info *sta;
+	struct sta_info *sta = NULL;
 	bool have_sta = false;
 	int err;
 	int ht_cfreq;
@@ -3085,13 +3043,11 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
 			 * since we look at probe response/beacon data here
 			 * it should be OK.
 			 */
-			printk(KERN_DEBUG
-			       "%s: Wrong control channel: center-freq: %d"
-			       " ht-cfreq: %d ht->primary_chan: %d"
-			       " band: %d. Disabling HT.\n",
-			       sdata->name, cbss->channel->center_freq,
-			       ht_cfreq, ht_oper->primary_chan,
-			       cbss->channel->band);
+			sdata_info(sdata,
+				   "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
+				   cbss->channel->center_freq,
+				   ht_cfreq, ht_oper->primary_chan,
+				   cbss->channel->band);
 			ht_oper = NULL;
 		}
 	}
@@ -3115,9 +3071,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
 	if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
 		/* can only fail due to HT40+/- mismatch */
 		channel_type = NL80211_CHAN_HT20;
-		printk(KERN_DEBUG
-		       "%s: disabling 40 MHz due to multi-vif mismatch\n",
-		       sdata->name);
+		sdata_info(sdata,
+			   "disabling 40 MHz due to multi-vif mismatch\n");
 		ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
 		WARN_ON(!ieee80211_set_channel_type(local, sdata,
 						    channel_type));
@@ -3126,7 +3081,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
 	local->oper_channel = cbss->channel;
 	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
-	if (!have_sta) {
+	if (sta) {
 		u32 rates = 0, basic_rates = 0;
 		bool have_higher_than_11mbit;
 		int min_rate = INT_MAX, min_rate_index = -1;
@@ -3146,9 +3101,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
 		 * we can connect -- with a warning.
 		 */
 		if (!basic_rates && min_rate_index >= 0) {
-			printk(KERN_DEBUG
-			       "%s: No basic rates, using min rate instead.\n",
-			       sdata->name);
+			sdata_info(sdata,
+				   "No basic rates, using min rate instead\n");
 			basic_rates = BIT(min_rate_index);
 		}
 
@@ -3174,9 +3128,9 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
 		err = sta_info_insert(sta);
 		sta = NULL;
 		if (err) {
-			printk(KERN_DEBUG
-			       "%s: failed to insert STA entry for the AP (error %d)\n",
-			       sdata->name, err);
+			sdata_info(sdata,
+				   "failed to insert STA entry for the AP (error %d)\n",
+				   err);
 			return err;
 		}
 	} else
@@ -3254,8 +3208,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 	if (ifmgd->associated)
 		ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
-	printk(KERN_DEBUG "%s: authenticate with %pM\n",
-	       sdata->name, req->bss->bssid);
+	sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
 
 	err = ieee80211_prep_connection(sdata, req->bss, false);
 	if (err)
@@ -3290,7 +3243,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_bss *bss = (void *)req->bss->priv;
 	struct ieee80211_mgd_assoc_data *assoc_data;
 	struct ieee80211_supported_band *sband;
-	const u8 *ssidie;
+	const u8 *ssidie, *ht_ie;
 	int i, err;
 
 	ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
@@ -3338,11 +3291,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 	 * We can set this to true for non-11n hardware, that'll be checked
 	 * separately along with the peer capabilities.
 	 */
-	for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
+	for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) {
 		if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
 		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
-		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
+		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
 			ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+			netdev_info(sdata->dev,
+				    "disabling HT due to WEP/TKIP use\n");
+		}
+	}
 
 	if (req->flags & ASSOC_REQ_DISABLE_HT)
 		ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
@@ -3350,8 +3307,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 	/* Also disable HT if we don't support it or the AP doesn't use WMM */
 	sband = local->hw.wiphy->bands[req->bss->channel->band];
 	if (!sband->ht_cap.ht_supported ||
-	    local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used)
+	    local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
 		ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+		netdev_info(sdata->dev,
+			    "disabling HT as WMM/QoS is not supported\n");
+	}
 
 	memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
 	memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
@@ -3377,8 +3337,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 			  (local->hw.queues >= IEEE80211_NUM_ACS);
 	assoc_data->supp_rates = bss->supp_rates;
 	assoc_data->supp_rates_len = bss->supp_rates_len;
-	assoc_data->ht_operation_ie =
-		ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
+
+	ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
+	if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation))
+		assoc_data->ap_ht_param =
+			((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
+	else
+		ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
 
 	if (bss->wmm_used && bss->uapsd_supported &&
 	    (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
@@ -3425,8 +3390,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 		 * Wait up to one beacon interval ...
 		 * should this be more if we miss one?
 		 */
-		printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
-		       sdata->name, ifmgd->bssid);
+		sdata_info(sdata, "waiting for beacon from %pM\n",
+			   ifmgd->bssid);
 		assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
 	} else {
 		assoc_data->have_beacon = true;
@@ -3445,8 +3410,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 				corrupt_type = "beacon";
 		} else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)
 			corrupt_type = "probe response";
-		printk(KERN_DEBUG "%s: associating with AP with corrupt %s\n",
-		       sdata->name, corrupt_type);
+		sdata_info(sdata, "associating with AP with corrupt %s\n",
+			   corrupt_type);
 	}
 
 	err = 0;
@@ -3475,9 +3440,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 		return 0;
 	}
 
-	printk(KERN_DEBUG
-	       "%s: deauthenticating from %pM by local choice (reason=%d)\n",
-	       sdata->name, req->bssid, req->reason_code);
+	sdata_info(sdata,
+		   "deauthenticating from %pM by local choice (reason=%d)\n",
+		   req->bssid, req->reason_code);
 
 	if (ifmgd->associated &&
 	    ether_addr_equal(ifmgd->associated->bssid, req->bssid))
@@ -3519,8 +3484,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
 		return -ENOLINK;
 	}
 
-	printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
-	       sdata->name, req->bss->bssid, req->reason_code);
+	sdata_info(sdata,
+		   "disassociating from %pM by local choice (reason=%d)\n",
+		   req->bss->bssid, req->reason_code);
 
 	memcpy(bssid, req->bss->bssid, ETH_ALEN);
 	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
@@ -3561,10 +3527,3 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 	cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
 }
 EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
-
-unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif)
-{
-	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
-	return sdata->dev->operstate;
-}
-EXPORT_SYMBOL(ieee80211_get_operstate);
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 935aa4b..b0fb6a2 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -15,7 +15,7 @@
 #include <linux/export.h>
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
-#include "driver-trace.h"
+#include "driver-ops.h"
 
 /*
  * Tell our hardware to disable PS.
@@ -24,8 +24,7 @@
  * because we *may* be doing work on-operating channel, and want our
  * hardware unconditionally awake, but still let the AP send us normal frames.
  */
-static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata,
-					   bool tell_ap)
+static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -46,8 +45,8 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata,
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
 
-	if (tell_ap && (!local->offchannel_ps_enabled ||
-			!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)))
+	if (!local->offchannel_ps_enabled ||
+	    !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
 		/*
 		 * If power save was enabled, no need to send a nullfunc
 		 * frame because AP knows that we are sleeping. But if the
@@ -132,7 +131,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
 			if (offchannel_ps_enable &&
 			    (sdata->vif.type == NL80211_IFTYPE_STATION) &&
 			    sdata->u.mgd.associated)
-				ieee80211_offchannel_ps_enable(sdata, true);
+				ieee80211_offchannel_ps_enable(sdata);
 		}
 	}
 	mutex_unlock(&local->iflist_mtx);
@@ -181,34 +180,58 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
 	mutex_unlock(&local->iflist_mtx);
 }
 
+void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
+{
+	if (roc->notified)
+		return;
+
+	if (roc->mgmt_tx_cookie) {
+		if (!WARN_ON(!roc->frame)) {
+			ieee80211_tx_skb(roc->sdata, roc->frame);
+			roc->frame = NULL;
+		}
+	} else {
+		cfg80211_ready_on_channel(roc->sdata->dev, (unsigned long)roc,
+					  roc->chan, roc->chan_type,
+					  roc->req_duration, GFP_KERNEL);
+	}
+
+	roc->notified = true;
+}
+
 static void ieee80211_hw_roc_start(struct work_struct *work)
 {
 	struct ieee80211_local *local =
 		container_of(work, struct ieee80211_local, hw_roc_start);
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_roc_work *roc, *dep, *tmp;
 
 	mutex_lock(&local->mtx);
 
-	if (!local->hw_roc_channel) {
-		mutex_unlock(&local->mtx);
-		return;
-	}
+	if (list_empty(&local->roc_list))
+		goto out_unlock;
 
-	if (local->hw_roc_skb) {
-		sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev);
-		ieee80211_tx_skb(sdata, local->hw_roc_skb);
-		local->hw_roc_skb = NULL;
-	} else {
-		cfg80211_ready_on_channel(local->hw_roc_dev,
-					  local->hw_roc_cookie,
-					  local->hw_roc_channel,
-					  local->hw_roc_channel_type,
-					  local->hw_roc_duration,
-					  GFP_KERNEL);
-	}
+	roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
+			       list);
+
+	if (!roc->started)
+		goto out_unlock;
 
-	ieee80211_recalc_idle(local);
+	roc->hw_begun = true;
+	roc->hw_start_time = local->hw_roc_start_time;
 
+	ieee80211_handle_roc_started(roc);
+	list_for_each_entry_safe(dep, tmp, &roc->dependents, list) {
+		ieee80211_handle_roc_started(dep);
+
+		if (dep->duration > roc->duration) {
+			u32 dur = dep->duration;
+			dep->duration = dur - roc->duration;
+			roc->duration = dur;
+			list_del(&dep->list);
+			list_add(&dep->list, &roc->list);
+		}
+	}
+ out_unlock:
 	mutex_unlock(&local->mtx);
 }
 
@@ -216,52 +239,179 @@ void ieee80211_ready_on_channel(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 
+	local->hw_roc_start_time = jiffies;
+
 	trace_api_ready_on_channel(local);
 
 	ieee80211_queue_work(hw, &local->hw_roc_start);
 }
 EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel);
 
-static void ieee80211_hw_roc_done(struct work_struct *work)
+void ieee80211_start_next_roc(struct ieee80211_local *local)
 {
-	struct ieee80211_local *local =
-		container_of(work, struct ieee80211_local, hw_roc_done);
+	struct ieee80211_roc_work *roc;
 
-	mutex_lock(&local->mtx);
+	lockdep_assert_held(&local->mtx);
 
-	if (!local->hw_roc_channel) {
-		mutex_unlock(&local->mtx);
+	if (list_empty(&local->roc_list)) {
+		ieee80211_run_deferred_scan(local);
 		return;
 	}
 
-	/* was never transmitted */
-	if (local->hw_roc_skb) {
-		u64 cookie;
+	roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
+			       list);
 
-		cookie = local->hw_roc_cookie ^ 2;
+	if (WARN_ON_ONCE(roc->started))
+		return;
+
+	if (local->ops->remain_on_channel) {
+		int ret, duration = roc->duration;
+
+		/* XXX: duplicated, see ieee80211_start_roc_work() */
+		if (!duration)
+			duration = 10;
+
+		ret = drv_remain_on_channel(local, roc->chan,
+					    roc->chan_type,
+					    duration);
+
+		roc->started = true;
+
+		if (ret) {
+			wiphy_warn(local->hw.wiphy,
+				   "failed to start next HW ROC (%d)\n", ret);
+			/*
+			 * queue the work struct again to avoid recursion
+			 * when multiple failures occur
+			 */
+			ieee80211_remain_on_channel_expired(&local->hw);
+		}
+	} else {
+		/* delay it a bit */
+		ieee80211_queue_delayed_work(&local->hw, &roc->work,
+					     round_jiffies_relative(HZ/2));
+	}
+}
 
-		cfg80211_mgmt_tx_status(local->hw_roc_dev, cookie,
-					local->hw_roc_skb->data,
-					local->hw_roc_skb->len, false,
-					GFP_KERNEL);
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
+{
+	struct ieee80211_roc_work *dep, *tmp;
 
-		kfree_skb(local->hw_roc_skb);
-		local->hw_roc_skb = NULL;
-		local->hw_roc_skb_for_status = NULL;
+	/* was never transmitted */
+	if (roc->frame) {
+		cfg80211_mgmt_tx_status(roc->sdata->dev,
+					(unsigned long)roc->frame,
+					roc->frame->data, roc->frame->len,
+					false, GFP_KERNEL);
+		kfree_skb(roc->frame);
 	}
 
-	if (!local->hw_roc_for_tx)
-		cfg80211_remain_on_channel_expired(local->hw_roc_dev,
-						   local->hw_roc_cookie,
-						   local->hw_roc_channel,
-						   local->hw_roc_channel_type,
+	if (!roc->mgmt_tx_cookie)
+		cfg80211_remain_on_channel_expired(roc->sdata->dev,
+						   (unsigned long)roc,
+						   roc->chan, roc->chan_type,
 						   GFP_KERNEL);
 
-	local->hw_roc_channel = NULL;
-	local->hw_roc_cookie = 0;
+	list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
+		ieee80211_roc_notify_destroy(dep);
+
+	kfree(roc);
+}
+
+void ieee80211_sw_roc_work(struct work_struct *work)
+{
+	struct ieee80211_roc_work *roc =
+		container_of(work, struct ieee80211_roc_work, work.work);
+	struct ieee80211_sub_if_data *sdata = roc->sdata;
+	struct ieee80211_local *local = sdata->local;
+
+	mutex_lock(&local->mtx);
+
+	if (roc->abort)
+		goto finish;
+
+	if (WARN_ON(list_empty(&local->roc_list)))
+		goto out_unlock;
+
+	if (WARN_ON(roc != list_first_entry(&local->roc_list,
+					    struct ieee80211_roc_work,
+					    list)))
+		goto out_unlock;
 
-	ieee80211_recalc_idle(local);
+	if (!roc->started) {
+		struct ieee80211_roc_work *dep;
 
+		/* start this ROC */
+
+		/* switch channel etc */
+		ieee80211_recalc_idle(local);
+
+		local->tmp_channel = roc->chan;
+		local->tmp_channel_type = roc->chan_type;
+		ieee80211_hw_config(local, 0);
+
+		/* tell userspace or send frame */
+		ieee80211_handle_roc_started(roc);
+		list_for_each_entry(dep, &roc->dependents, list)
+			ieee80211_handle_roc_started(dep);
+
+		/* if it was pure TX, just finish right away */
+		if (!roc->duration)
+			goto finish;
+
+		roc->started = true;
+		ieee80211_queue_delayed_work(&local->hw, &roc->work,
+					     msecs_to_jiffies(roc->duration));
+	} else {
+		/* finish this ROC */
+ finish:
+		list_del(&roc->list);
+		ieee80211_roc_notify_destroy(roc);
+
+		if (roc->started) {
+			drv_flush(local, false);
+
+			local->tmp_channel = NULL;
+			ieee80211_hw_config(local, 0);
+
+			ieee80211_offchannel_return(local, true);
+		}
+
+		ieee80211_recalc_idle(local);
+
+		if (roc->started)
+			ieee80211_start_next_roc(local);
+	}
+
+ out_unlock:
+	mutex_unlock(&local->mtx);
+}
+
+static void ieee80211_hw_roc_done(struct work_struct *work)
+{
+	struct ieee80211_local *local =
+		container_of(work, struct ieee80211_local, hw_roc_done);
+	struct ieee80211_roc_work *roc;
+
+	mutex_lock(&local->mtx);
+
+	if (list_empty(&local->roc_list))
+		goto out_unlock;
+
+	roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
+			       list);
+
+	if (!roc->started)
+		goto out_unlock;
+
+	list_del(&roc->list);
+
+	ieee80211_roc_notify_destroy(roc);
+
+	/* if there's another roc, start it now */
+	ieee80211_start_next_roc(local);
+
+ out_unlock:
 	mutex_unlock(&local->mtx);
 }
 
@@ -275,8 +425,47 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired);
 
-void ieee80211_hw_roc_setup(struct ieee80211_local *local)
+void ieee80211_roc_setup(struct ieee80211_local *local)
 {
 	INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start);
 	INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done);
+	INIT_LIST_HEAD(&local->roc_list);
+}
+
+void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_roc_work *roc, *tmp;
+	LIST_HEAD(tmp_list);
+
+	mutex_lock(&local->mtx);
+	list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
+		if (roc->sdata != sdata)
+			continue;
+
+		if (roc->started && local->ops->remain_on_channel) {
+			/* can race, so ignore return value */
+			drv_cancel_remain_on_channel(local);
+		}
+
+		list_move_tail(&roc->list, &tmp_list);
+		roc->abort = true;
+	}
+
+	ieee80211_start_next_roc(local);
+	mutex_unlock(&local->mtx);
+
+	list_for_each_entry_safe(roc, tmp, &tmp_list, list) {
+		if (local->ops->remain_on_channel) {
+			list_del(&roc->list);
+			ieee80211_roc_notify_destroy(roc);
+		} else {
+			ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
+
+			/* work will clean up etc */
+			flush_delayed_work(&roc->work);
+		}
+	}
+
+	WARN_ON_ONCE(!list_empty(&tmp_list));
 }
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index af1c4e2..5c572e7 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -77,6 +77,17 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 		int err = drv_suspend(local, wowlan);
 		if (err < 0) {
 			local->quiescing = false;
+			local->wowlan = false;
+			if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
+				mutex_lock(&local->sta_mtx);
+				list_for_each_entry(sta,
+						    &local->sta_list, list) {
+					clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
+				}
+				mutex_unlock(&local->sta_mtx);
+			}
+			ieee80211_wake_queues_by_reason(hw,
+					IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 			return err;
 		} else if (err > 0) {
 			WARN_ON(err != 1);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 7bcecf7..ab51850 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -554,11 +554,11 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)
 }
 
 
-static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
+static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
 					    struct tid_ampdu_rx *tid_agg_rx,
 					    int index)
 {
-	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
 	struct ieee80211_rx_status *status;
 
@@ -578,7 +578,7 @@ no_frame:
 	tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
 }
 
-static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
+static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata,
 					     struct tid_ampdu_rx *tid_agg_rx,
 					     u16 head_seq_num)
 {
@@ -589,7 +589,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
 	while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
 		index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
 							tid_agg_rx->buf_size;
-		ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
+		ieee80211_release_reorder_frame(sdata, tid_agg_rx, index);
 	}
 }
 
@@ -604,7 +604,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
  */
 #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
 
-static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
+static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
 					  struct tid_ampdu_rx *tid_agg_rx)
 {
 	int index, j;
@@ -632,12 +632,9 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
 					HT_RX_REORDER_BUF_TIMEOUT))
 				goto set_release_timer;
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-			if (net_ratelimit())
-				wiphy_debug(hw->wiphy,
-					    "release an RX reorder frame due to timeout on earlier frames\n");
-#endif
-			ieee80211_release_reorder_frame(hw, tid_agg_rx, j);
+			ht_dbg_ratelimited(sdata,
+					   "release an RX reorder frame due to timeout on earlier frames\n");
+			ieee80211_release_reorder_frame(sdata, tid_agg_rx, j);
 
 			/*
 			 * Increment the head seq# also for the skipped slots.
@@ -647,7 +644,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
 			skipped = 0;
 		}
 	} else while (tid_agg_rx->reorder_buf[index]) {
-		ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
+		ieee80211_release_reorder_frame(sdata, tid_agg_rx, index);
 		index =	seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
 							tid_agg_rx->buf_size;
 	}
@@ -677,7 +674,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
  * rcu_read_lock protection. It returns false if the frame
  * can be processed immediately, true if it was consumed.
  */
-static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata,
 					     struct tid_ampdu_rx *tid_agg_rx,
 					     struct sk_buff *skb)
 {
@@ -706,7 +703,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 	if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
 		head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
 		/* release stored frames up to new head to stack */
-		ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num);
+		ieee80211_release_reorder_frames(sdata, tid_agg_rx,
+						 head_seq_num);
 	}
 
 	/* Now the new frame is always in the range of the reordering buffer */
@@ -736,7 +734,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 	tid_agg_rx->reorder_buf[index] = skb;
 	tid_agg_rx->reorder_time[index] = jiffies;
 	tid_agg_rx->stored_mpdu_num++;
-	ieee80211_sta_reorder_release(hw, tid_agg_rx);
+	ieee80211_sta_reorder_release(sdata, tid_agg_rx);
 
  out:
 	spin_unlock(&tid_agg_rx->reorder_lock);
@@ -751,7 +749,6 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
 {
 	struct sk_buff *skb = rx->skb;
 	struct ieee80211_local *local = rx->local;
-	struct ieee80211_hw *hw = &local->hw;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 	struct sta_info *sta = rx->sta;
@@ -813,7 +810,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
 	 * 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))
+	if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb))
 		return;
 
  dont_reorder:
@@ -1136,24 +1133,18 @@ static void ap_sta_ps_start(struct sta_info *sta)
 	set_sta_flag(sta, WLAN_STA_PS_STA);
 	if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
 		drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-	printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
-	       sdata->name, sta->sta.addr, sta->sta.aid);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+	ps_dbg(sdata, "STA %pM aid %d enters power save mode\n",
+	       sta->sta.addr, sta->sta.aid);
 }
 
 static void ap_sta_ps_end(struct sta_info *sta)
 {
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-	printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
-	       sta->sdata->name, sta->sta.addr, sta->sta.aid);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+	ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n",
+	       sta->sta.addr, sta->sta.aid);
 
 	if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
-		       sta->sdata->name, sta->sta.addr, sta->sta.aid);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+		ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
+		       sta->sta.addr, sta->sta.aid);
 		return;
 	}
 
@@ -1383,19 +1374,8 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
 	if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
 		sdata->fragment_next = 0;
 
-	if (!skb_queue_empty(&entry->skb_list)) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		struct ieee80211_hdr *hdr =
-			(struct ieee80211_hdr *) entry->skb_list.next->data;
-		printk(KERN_DEBUG "%s: RX reassembly removed oldest "
-		       "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
-		       "addr1=%pM addr2=%pM\n",
-		       sdata->name, idx,
-		       jiffies - entry->first_frag_time, entry->seq,
-		       entry->last_frag, hdr->addr1, hdr->addr2);
-#endif
+	if (!skb_queue_empty(&entry->skb_list))
 		__skb_queue_purge(&entry->skb_list);
-	}
 
 	__skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
 	*skb = NULL;
@@ -1753,7 +1733,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 			 */
 			xmit_skb = skb_copy(skb, GFP_ATOMIC);
 			if (!xmit_skb)
-				net_dbg_ratelimited("%s: failed to clone multicast frame\n",
+				net_info_ratelimited("%s: failed to clone multicast frame\n",
 						    dev->name);
 		} else {
 			dsta = sta_info_get(sdata, skb->data);
@@ -1937,7 +1917,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 	    ether_addr_equal(sdata->vif.addr, hdr->addr3))
 		return RX_CONTINUE;
 
-	q = ieee80211_select_queue_80211(local, skb, hdr);
+	q = ieee80211_select_queue_80211(sdata, skb, hdr);
 	if (ieee80211_queue_stopped(&local->hw, q)) {
 		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
 		return RX_DROP_MONITOR;
@@ -1957,7 +1937,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
 	fwd_skb = skb_copy(skb, GFP_ATOMIC);
 	if (!fwd_skb) {
-		net_dbg_ratelimited("%s: failed to clone mesh frame\n",
+		net_info_ratelimited("%s: failed to clone mesh frame\n",
 				    sdata->name);
 		goto out;
 	}
@@ -2060,8 +2040,6 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
 {
-	struct ieee80211_local *local = rx->local;
-	struct ieee80211_hw *hw = &local->hw;
 	struct sk_buff *skb = rx->skb;
 	struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
 	struct tid_ampdu_rx *tid_agg_rx;
@@ -2098,7 +2076,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
 
 		spin_lock(&tid_agg_rx->reorder_lock);
 		/* release stored frames up to start of BAR */
-		ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num);
+		ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx,
+						 start_seq_num);
 		spin_unlock(&tid_agg_rx->reorder_lock);
 
 		kfree_skb(skb);
@@ -2749,7 +2728,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
 		return;
 
 	spin_lock(&tid_agg_rx->reorder_lock);
-	ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx);
+	ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx);
 	spin_unlock(&tid_agg_rx->reorder_lock);
 
 	ieee80211_rx_handlers(&rx);
@@ -3029,6 +3008,10 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	if (unlikely(local->quiescing || local->suspended))
 		goto drop;
 
+	/* We might be during a HW reconfig, prevent Rx for the same reason */
+	if (unlikely(local->in_reconfig))
+		goto drop;
+
 	/*
 	 * The same happens when we're not even started,
 	 * but that's worth a warning.
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 169da07..267b294 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -114,8 +114,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
 
 	if (elems->tim && (!elems->parse_error ||
 			   !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) {
-		struct ieee80211_tim_ie *tim_ie =
-			(struct ieee80211_tim_ie *)elems->tim;
+		struct ieee80211_tim_ie *tim_ie = elems->tim;
 		bss->dtim_period = tim_ie->dtim_period;
 		if (!elems->parse_error)
 				bss->valid_data |= IEEE80211_BSS_VALID_DTIM;
@@ -323,7 +322,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
 	ieee80211_mlme_notify_scan_completed(local);
 	ieee80211_ibss_notify_scan_completed(local);
 	ieee80211_mesh_notify_scan_completed(local);
-	ieee80211_queue_work(&local->hw, &local->work_work);
+	ieee80211_start_next_roc(local);
 }
 
 void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
@@ -376,7 +375,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 static bool ieee80211_can_scan(struct ieee80211_local *local,
 			       struct ieee80211_sub_if_data *sdata)
 {
-	if (!list_empty(&local->work_list))
+	if (!list_empty(&local->roc_list))
 		return false;
 
 	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index de455f8..06fa75c 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -169,9 +169,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
 	if (sta->rate_ctrl)
 		rate_control_free_sta(sta);
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	wiphy_debug(local->hw.wiphy, "Destroyed STA %pM\n", sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
 
 	kfree(sta);
 }
@@ -278,9 +276,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 	for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
 		sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	wiphy_debug(local->hw.wiphy, "Allocated STA %pM\n", sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
 
 #ifdef CONFIG_MAC80211_MESH
 	sta->plink_state = NL80211_PLINK_LISTEN;
@@ -333,9 +329,9 @@ static int sta_info_insert_drv_state(struct ieee80211_local *local,
 	}
 
 	if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
-		printk(KERN_DEBUG
-		       "%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway.\n",
-		       sdata->name, sta->sta.addr, state + 1, err);
+		sdata_info(sdata,
+			   "failed to move IBSS STA %pM to state %d (%d) - keeping it anyway\n",
+			   sta->sta.addr, state + 1, err);
 		err = 0;
 	}
 
@@ -390,9 +386,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
 	sinfo.generation = local->sta_generation;
 	cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);
 
 	/* move reference to rcu-protected */
 	rcu_read_lock();
@@ -618,10 +612,8 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
 			break;
 
 		local->total_ps_buffered--;
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n",
+		ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n",
 		       sta->sta.addr);
-#endif
 		dev_kfree_skb(skb);
 	}
 
@@ -747,9 +739,8 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
 		mesh_accept_plinks_update(sdata);
 #endif
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
+
 	cancel_work_sync(&sta->drv_unblock_wk);
 
 	cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL);
@@ -889,10 +880,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
 			continue;
 
 		if (time_after(jiffies, sta->last_rx + exp_time)) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-			printk(KERN_DEBUG "%s: expiring inactive STA %pM\n",
-			       sdata->name, sta->sta.addr);
-#endif
+			ibss_dbg(sdata, "expiring inactive STA %pM\n",
+				 sta->sta.addr);
 			WARN_ON(__sta_info_destroy(sta));
 		}
 	}
@@ -990,11 +979,9 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
 
 	sta_info_recalc_tim(sta);
 
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-	printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
-	       "since STA not sleeping anymore\n", sdata->name,
+	ps_dbg(sdata,
+	       "STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n",
 	       sta->sta.addr, sta->sta.aid, filtered, buffered);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
 static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
@@ -1384,10 +1371,8 @@ int sta_info_move_state(struct sta_info *sta,
 		return -EINVAL;
 	}
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: moving STA %pM to state %d\n",
-		sta->sdata->name, sta->sta.addr, new_state);
-#endif
+	sta_dbg(sta->sdata, "moving STA %pM to state %d\n",
+		sta->sta.addr, new_state);
 
 	/*
 	 * notify the driver before the actual changes so it can
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 3bb24a1..a470e11 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -271,6 +271,9 @@ struct sta_ampdu_mlme {
  * @plink_timer: peer link watch timer
  * @plink_timer_was_running: used by suspend/resume to restore timers
  * @t_offset: timing offset relative to this host
+ * @t_offset_setpoint: reference timing offset of this sta to be used when
+ * 	calculating clockdrift
+ * @ch_type: peer's channel type
  * @debugfs: debug filesystem info
  * @dead: set to true when sta is unlinked
  * @uploaded: set to true when sta is uploaded to the driver
@@ -278,6 +281,8 @@ struct sta_ampdu_mlme {
  * @sta: station information we share with the driver
  * @sta_state: duplicates information about station state (for debug)
  * @beacon_loss_count: number of times beacon loss has triggered
+ * @supports_40mhz: tracks whether the station advertised 40 MHz support
+ *	as we overwrite its HT parameters with the currently used value
  */
 struct sta_info {
 	/* General information, mostly static */
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 28cfa98..2ed2f27 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -155,13 +155,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
 		return;
 	}
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	if (net_ratelimit())
-		wiphy_debug(local->hw.wiphy,
-			    "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
-			    skb_queue_len(&sta->tx_filtered[ac]),
-			    !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
-#endif
+	ps_dbg_ratelimited(sta->sdata,
+			   "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
+			   skb_queue_len(&sta->tx_filtered[ac]),
+			   !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
 	dev_kfree_skb(skb);
 }
 
@@ -520,36 +517,16 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 	if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
 		u64 cookie = (unsigned long)skb;
+		acked = info->flags & IEEE80211_TX_STAT_ACK;
 
 		if (ieee80211_is_nullfunc(hdr->frame_control) ||
-		    ieee80211_is_qos_nullfunc(hdr->frame_control)) {
-			acked = info->flags & IEEE80211_TX_STAT_ACK;
-
+		    ieee80211_is_qos_nullfunc(hdr->frame_control))
 			cfg80211_probe_status(skb->dev, hdr->addr1,
 					      cookie, acked, GFP_ATOMIC);
-		} else {
-			struct ieee80211_work *wk;
-
-			rcu_read_lock();
-			list_for_each_entry_rcu(wk, &local->work_list, list) {
-				if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
-					continue;
-				if (wk->offchan_tx.frame != skb)
-					continue;
-				wk->offchan_tx.status = true;
-				break;
-			}
-			rcu_read_unlock();
-			if (local->hw_roc_skb_for_status == skb) {
-				cookie = local->hw_roc_cookie ^ 2;
-				local->hw_roc_skb_for_status = NULL;
-			}
-
+		else
 			cfg80211_mgmt_tx_status(
 				skb->dev, cookie, skb->data, skb->len,
-				!!(info->flags & IEEE80211_TX_STAT_ACK),
-				GFP_ATOMIC);
-		}
+				acked, GFP_ATOMIC);
 	}
 
 	if (unlikely(info->ack_frame_id)) {
@@ -589,7 +566,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 	/* send frame to monitor interfaces now */
 	rtap_len = ieee80211_tx_radiotap_len(info);
 	if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
-		printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
+		pr_err("ieee80211_tx_status: headroom too small\n");
 		dev_kfree_skb(skb);
 		return;
 	}
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 51077a9..57e14d5 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -260,17 +260,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
 	keyid = pos[3];
 	iv32 = get_unaligned_le32(pos + 4);
 	pos += 8;
-#ifdef CONFIG_MAC80211_TKIP_DEBUG
-	{
-		int i;
-		printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len);
-		for (i = 0; i < payload_len; i++)
-			printk(" %02x", payload[i]);
-		printk("\n");
-		printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n",
-		       iv16, iv32);
-	}
-#endif
 
 	if (!(keyid & (1 << 5)))
 		return TKIP_DECRYPT_NO_EXT_IV;
@@ -281,16 +270,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
 	if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT &&
 	    (iv32 < key->u.tkip.rx[queue].iv32 ||
 	     (iv32 == key->u.tkip.rx[queue].iv32 &&
-	      iv16 <= key->u.tkip.rx[queue].iv16))) {
-#ifdef CONFIG_MAC80211_TKIP_DEBUG
-		printk(KERN_DEBUG "TKIP replay detected for RX frame from "
-		       "%pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
-		       ta,
-		       iv32, iv16, key->u.tkip.rx[queue].iv32,
-		       key->u.tkip.rx[queue].iv16);
-#endif
+	      iv16 <= key->u.tkip.rx[queue].iv16)))
 		return TKIP_DECRYPT_REPLAY;
-	}
 
 	if (only_iv) {
 		res = TKIP_DECRYPT_OK;
@@ -302,22 +283,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
 	    key->u.tkip.rx[queue].iv32 != iv32) {
 		/* IV16 wrapped around - perform TKIP phase 1 */
 		tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
-#ifdef CONFIG_MAC80211_TKIP_DEBUG
-		{
-			int i;
-			u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY;
-			printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%pM"
-			       " TK=", ta);
-			for (i = 0; i < 16; i++)
-				printk("%02x ",
-				       key->conf.key[key_offset + i]);
-			printk("\n");
-			printk(KERN_DEBUG "TKIP decrypt: P1K=");
-			for (i = 0; i < 5; i++)
-				printk("%04x ", key->u.tkip.rx[queue].p1k[i]);
-			printk("\n");
-		}
-#endif
 	}
 	if (key->local->ops->update_tkip_key &&
 	    key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
@@ -333,15 +298,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
 	}
 
 	tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key);
-#ifdef CONFIG_MAC80211_TKIP_DEBUG
-	{
-		int i;
-		printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key=");
-		for (i = 0; i < 16; i++)
-			printk("%02x ", rc4key[i]);
-		printk("\n");
-	}
-#endif
 
 	res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
  done:
diff --git a/net/mac80211/trace.c b/net/mac80211/trace.c
new file mode 100644
index 0000000..386e45d
--- /dev/null
+++ b/net/mac80211/trace.c
@@ -0,0 +1,75 @@
+/* bug in tracepoint.h, it should include this */
+#include <linux/module.h>
+
+/* sparse isn't too happy with all macros... */
+#ifndef __CHECKER__
+#include <net/cfg80211.h>
+#include "driver-ops.h"
+#include "debug.h"
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+#ifdef CONFIG_MAC80211_MESSAGE_TRACING
+void __sdata_info(const char *fmt, ...)
+{
+	struct va_format vaf = {
+		.fmt = fmt,
+	};
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.va = &args;
+
+	pr_info("%pV", &vaf);
+	trace_mac80211_info(&vaf);
+	va_end(args);
+}
+
+void __sdata_dbg(bool print, const char *fmt, ...)
+{
+	struct va_format vaf = {
+		.fmt = fmt,
+	};
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.va = &args;
+
+	if (print)
+		pr_debug("%pV", &vaf);
+	trace_mac80211_dbg(&vaf);
+	va_end(args);
+}
+
+void __sdata_err(const char *fmt, ...)
+{
+	struct va_format vaf = {
+		.fmt = fmt,
+	};
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.va = &args;
+
+	pr_err("%pV", &vaf);
+	trace_mac80211_err(&vaf);
+	va_end(args);
+}
+
+void __wiphy_dbg(struct wiphy *wiphy, bool print, const char *fmt, ...)
+{
+	struct va_format vaf = {
+		.fmt = fmt,
+	};
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.va = &args;
+
+	if (print)
+		wiphy_dbg(wiphy, "%pV", &vaf);
+	trace_mac80211_dbg(&vaf);
+	va_end(args);
+}
+#endif
+#endif
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
new file mode 100644
index 0000000..2e60f4a
--- /dev/null
+++ b/net/mac80211/trace.h
@@ -0,0 +1,1680 @@
+#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#define __MAC80211_DRIVER_TRACE
+
+#include <linux/tracepoint.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mac80211
+
+#define MAXNAME		32
+#define LOCAL_ENTRY	__array(char, wiphy_name, 32)
+#define LOCAL_ASSIGN	strlcpy(__entry->wiphy_name, wiphy_name(local->hw.wiphy), MAXNAME)
+#define LOCAL_PR_FMT	"%s"
+#define LOCAL_PR_ARG	__entry->wiphy_name
+
+#define STA_ENTRY	__array(char, sta_addr, ETH_ALEN)
+#define STA_ASSIGN	(sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN))
+#define STA_PR_FMT	" sta:%pM"
+#define STA_PR_ARG	__entry->sta_addr
+
+#define VIF_ENTRY	__field(enum nl80211_iftype, vif_type) __field(void *, sdata)	\
+			__field(bool, p2p)						\
+			__string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
+#define VIF_ASSIGN	__entry->vif_type = sdata->vif.type; __entry->sdata = sdata;	\
+			__entry->p2p = sdata->vif.p2p;					\
+			__assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
+#define VIF_PR_FMT	" vif:%s(%d%s)"
+#define VIF_PR_ARG	__get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
+
+/*
+ * Tracing for driver callbacks.
+ */
+
+DECLARE_EVENT_CLASS(local_only_evt,
+	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)
+);
+
+DECLARE_EVENT_CLASS(local_sdata_addr_evt,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata),
+	TP_ARGS(local, sdata),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__array(char, addr, 6)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		memcpy(__entry->addr, sdata->vif.addr, 6);
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT " addr:%pM",
+		LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
+	)
+);
+
+DECLARE_EVENT_CLASS(local_u32_evt,
+	TP_PROTO(struct ieee80211_local *local, u32 value),
+	TP_ARGS(local, value),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u32, value)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->value = value;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " value:%d",
+		LOCAL_PR_ARG, __entry->value
+	)
+);
+
+DECLARE_EVENT_CLASS(local_sdata_evt,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata),
+	TP_ARGS(local, sdata),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT VIF_PR_FMT,
+		LOCAL_PR_ARG, VIF_PR_ARG
+	)
+);
+
+DEFINE_EVENT(local_only_evt, drv_return_void,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+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_bool,
+	TP_PROTO(struct ieee80211_local *local, bool ret),
+	TP_ARGS(local, ret),
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(bool, ret)
+	),
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->ret = ret;
+	),
+	TP_printk(LOCAL_PR_FMT " - %s", LOCAL_PR_ARG, (__entry->ret) ?
+		  "true" : "false")
+);
+
+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)
+);
+
+DEFINE_EVENT(local_only_evt, drv_start,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_u32_evt, drv_get_et_strings,
+	     TP_PROTO(struct ieee80211_local *local, u32 sset),
+	     TP_ARGS(local, sset)
+);
+
+DEFINE_EVENT(local_u32_evt, drv_get_et_sset_count,
+	     TP_PROTO(struct ieee80211_local *local, u32 sset),
+	     TP_ARGS(local, sset)
+);
+
+DEFINE_EVENT(local_only_evt, drv_get_et_stats,
+	     TP_PROTO(struct ieee80211_local *local),
+	     TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_only_evt, drv_suspend,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_only_evt, drv_resume,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+TRACE_EVENT(drv_set_wakeup,
+	TP_PROTO(struct ieee80211_local *local, bool enabled),
+	TP_ARGS(local, enabled),
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(bool, enabled)
+	),
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->enabled = enabled;
+	),
+	TP_printk(LOCAL_PR_FMT " enabled:%d", LOCAL_PR_ARG, __entry->enabled)
+);
+
+DEFINE_EVENT(local_only_evt, drv_stop,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_sdata_addr_evt, drv_add_interface,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata),
+	TP_ARGS(local, sdata)
+);
+
+TRACE_EVENT(drv_change_interface,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 enum nl80211_iftype type, bool p2p),
+
+	TP_ARGS(local, sdata, type, p2p),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__field(u32, new_type)
+		__field(bool, new_p2p)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		__entry->new_type = type;
+		__entry->new_p2p = p2p;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT " new type:%d%s",
+		LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type,
+		__entry->new_p2p ? "/p2p" : ""
+	)
+);
+
+DEFINE_EVENT(local_sdata_addr_evt, drv_remove_interface,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata),
+	TP_ARGS(local, sdata)
+);
+
+TRACE_EVENT(drv_config,
+	TP_PROTO(struct ieee80211_local *local,
+		 u32 changed),
+
+	TP_ARGS(local, changed),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u32, changed)
+		__field(u32, flags)
+		__field(int, power_level)
+		__field(int, dynamic_ps_timeout)
+		__field(int, max_sleep_period)
+		__field(u16, listen_interval)
+		__field(u8, long_frame_max_tx_count)
+		__field(u8, short_frame_max_tx_count)
+		__field(int, center_freq)
+		__field(int, channel_type)
+		__field(int, smps)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->changed = changed;
+		__entry->flags = local->hw.conf.flags;
+		__entry->power_level = local->hw.conf.power_level;
+		__entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout;
+		__entry->max_sleep_period = local->hw.conf.max_sleep_period;
+		__entry->listen_interval = local->hw.conf.listen_interval;
+		__entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count;
+		__entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count;
+		__entry->center_freq = local->hw.conf.channel->center_freq;
+		__entry->channel_type = local->hw.conf.channel_type;
+		__entry->smps = local->hw.conf.smps_mode;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " ch:%#x freq:%d",
+		LOCAL_PR_ARG, __entry->changed, __entry->center_freq
+	)
+);
+
+TRACE_EVENT(drv_bss_info_changed,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct ieee80211_bss_conf *info,
+		 u32 changed),
+
+	TP_ARGS(local, sdata, info, changed),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__field(bool, assoc)
+		__field(u16, aid)
+		__field(bool, cts)
+		__field(bool, shortpre)
+		__field(bool, shortslot)
+		__field(u8, dtimper)
+		__field(u16, bcnint)
+		__field(u16, assoc_cap)
+		__field(u64, timestamp)
+		__field(u32, basic_rates)
+		__field(u32, changed)
+		__field(bool, enable_beacon)
+		__field(u16, ht_operation_mode)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		__entry->changed = changed;
+		__entry->aid = info->aid;
+		__entry->assoc = info->assoc;
+		__entry->shortpre = info->use_short_preamble;
+		__entry->cts = info->use_cts_prot;
+		__entry->shortslot = info->use_short_slot;
+		__entry->dtimper = info->dtim_period;
+		__entry->bcnint = info->beacon_int;
+		__entry->assoc_cap = info->assoc_capability;
+		__entry->timestamp = info->last_tsf;
+		__entry->basic_rates = info->basic_rates;
+		__entry->enable_beacon = info->enable_beacon;
+		__entry->ht_operation_mode = info->ht_operation_mode;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT " changed:%#x",
+		LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed
+	)
+);
+
+TRACE_EVENT(drv_prepare_multicast,
+	TP_PROTO(struct ieee80211_local *local, int mc_count),
+
+	TP_ARGS(local, mc_count),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(int, mc_count)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->mc_count = mc_count;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " prepare mc (%d)",
+		LOCAL_PR_ARG, __entry->mc_count
+	)
+);
+
+TRACE_EVENT(drv_configure_filter,
+	TP_PROTO(struct ieee80211_local *local,
+		 unsigned int changed_flags,
+		 unsigned int *total_flags,
+		 u64 multicast),
+
+	TP_ARGS(local, changed_flags, total_flags, multicast),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(unsigned int, changed)
+		__field(unsigned int, total)
+		__field(u64, multicast)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->changed = changed_flags;
+		__entry->total = *total_flags;
+		__entry->multicast = multicast;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " changed:%#x total:%#x",
+		LOCAL_PR_ARG, __entry->changed, __entry->total
+	)
+);
+
+TRACE_EVENT(drv_set_tim,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sta *sta, bool set),
+
+	TP_ARGS(local, sta, set),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		STA_ENTRY
+		__field(bool, set)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		STA_ASSIGN;
+		__entry->set = set;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT STA_PR_FMT " set:%d",
+		LOCAL_PR_ARG, STA_PR_FMT, __entry->set
+	)
+);
+
+TRACE_EVENT(drv_set_key,
+	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),
+
+	TP_ARGS(local, cmd, sdata, sta, key),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		STA_ENTRY
+		__field(u32, cipher)
+		__field(u8, hw_key_idx)
+		__field(u8, flags)
+		__field(s8, keyidx)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		STA_ASSIGN;
+		__entry->cipher = key->cipher;
+		__entry->flags = key->flags;
+		__entry->keyidx = key->keyidx;
+		__entry->hw_key_idx = key->hw_key_idx;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
+	)
+);
+
+TRACE_EVENT(drv_update_tkip_key,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct ieee80211_key_conf *conf,
+		 struct ieee80211_sta *sta, u32 iv32),
+
+	TP_ARGS(local, sdata, conf, sta, iv32),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		STA_ENTRY
+		__field(u32, iv32)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		STA_ASSIGN;
+		__entry->iv32 = iv32;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x",
+		LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32
+	)
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_hw_scan,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata),
+	TP_ARGS(local, sdata)
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_cancel_hw_scan,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata),
+	TP_ARGS(local, sdata)
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata),
+	TP_ARGS(local, sdata)
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata),
+	TP_ARGS(local, sdata)
+);
+
+DEFINE_EVENT(local_only_evt, drv_sw_scan_start,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_only_evt, drv_sw_scan_complete,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+TRACE_EVENT(drv_get_stats,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_low_level_stats *stats,
+		 int ret),
+
+	TP_ARGS(local, stats, ret),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(int, ret)
+		__field(unsigned int, ackfail)
+		__field(unsigned int, rtsfail)
+		__field(unsigned int, fcserr)
+		__field(unsigned int, rtssucc)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->ret = ret;
+		__entry->ackfail = stats->dot11ACKFailureCount;
+		__entry->rtsfail = stats->dot11RTSFailureCount;
+		__entry->fcserr = stats->dot11FCSErrorCount;
+		__entry->rtssucc = stats->dot11RTSSuccessCount;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " ret:%d",
+		LOCAL_PR_ARG, __entry->ret
+	)
+);
+
+TRACE_EVENT(drv_get_tkip_seq,
+	TP_PROTO(struct ieee80211_local *local,
+		 u8 hw_key_idx, u32 *iv32, u16 *iv16),
+
+	TP_ARGS(local, hw_key_idx, iv32, iv16),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u8, hw_key_idx)
+		__field(u32, iv32)
+		__field(u16, iv16)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->hw_key_idx = hw_key_idx;
+		__entry->iv32 = *iv32;
+		__entry->iv16 = *iv16;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT, LOCAL_PR_ARG
+	)
+);
+
+DEFINE_EVENT(local_u32_evt, drv_set_frag_threshold,
+	TP_PROTO(struct ieee80211_local *local, u32 value),
+	TP_ARGS(local, value)
+);
+
+DEFINE_EVENT(local_u32_evt, drv_set_rts_threshold,
+	TP_PROTO(struct ieee80211_local *local, u32 value),
+	TP_ARGS(local, value)
+);
+
+TRACE_EVENT(drv_set_coverage_class,
+	TP_PROTO(struct ieee80211_local *local, u8 value),
+
+	TP_ARGS(local, value),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u8, value)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->value = value;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " value:%d",
+		LOCAL_PR_ARG, __entry->value
+	)
+);
+
+TRACE_EVENT(drv_sta_notify,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 enum sta_notify_cmd cmd,
+		 struct ieee80211_sta *sta),
+
+	TP_ARGS(local, sdata, cmd, sta),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		STA_ENTRY
+		__field(u32, cmd)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		STA_ASSIGN;
+		__entry->cmd = cmd;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " cmd:%d",
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->cmd
+	)
+);
+
+TRACE_EVENT(drv_sta_state,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct ieee80211_sta *sta,
+		 enum ieee80211_sta_state old_state,
+		 enum ieee80211_sta_state new_state),
+
+	TP_ARGS(local, sdata, sta, old_state, new_state),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		STA_ENTRY
+		__field(u32, old_state)
+		__field(u32, new_state)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		STA_ASSIGN;
+		__entry->old_state = old_state;
+		__entry->new_state = new_state;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " state: %d->%d",
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG,
+		__entry->old_state, __entry->new_state
+	)
+);
+
+TRACE_EVENT(drv_sta_rc_update,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct ieee80211_sta *sta,
+		 u32 changed),
+
+	TP_ARGS(local, sdata, sta, changed),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		STA_ENTRY
+		__field(u32, changed)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		STA_ASSIGN;
+		__entry->changed = changed;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " changed: 0x%x",
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->changed
+	)
+);
+
+TRACE_EVENT(drv_sta_add,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct ieee80211_sta *sta),
+
+	TP_ARGS(local, sdata, sta),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		STA_ENTRY
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		STA_ASSIGN;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
+	)
+);
+
+TRACE_EVENT(drv_sta_remove,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct ieee80211_sta *sta),
+
+	TP_ARGS(local, sdata, sta),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		STA_ENTRY
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		STA_ASSIGN;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
+	)
+);
+
+TRACE_EVENT(drv_conf_tx,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 u16 ac, const struct ieee80211_tx_queue_params *params),
+
+	TP_ARGS(local, sdata, ac, params),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__field(u16, ac)
+		__field(u16, txop)
+		__field(u16, cw_min)
+		__field(u16, cw_max)
+		__field(u8, aifs)
+		__field(bool, uapsd)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		__entry->ac = ac;
+		__entry->txop = params->txop;
+		__entry->cw_max = params->cw_max;
+		__entry->cw_min = params->cw_min;
+		__entry->aifs = params->aifs;
+		__entry->uapsd = params->uapsd;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  " AC:%d",
+		LOCAL_PR_ARG, VIF_PR_ARG, __entry->ac
+	)
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_get_tsf,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata),
+	TP_ARGS(local, sdata)
+);
+
+TRACE_EVENT(drv_set_tsf,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 u64 tsf),
+
+	TP_ARGS(local, sdata, tsf),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__field(u64, tsf)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		__entry->tsf = tsf;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  " tsf:%llu",
+		LOCAL_PR_ARG, VIF_PR_ARG, (unsigned long long)__entry->tsf
+	)
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_reset_tsf,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata),
+	TP_ARGS(local, sdata)
+);
+
+DEFINE_EVENT(local_only_evt, drv_tx_last_beacon,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+TRACE_EVENT(drv_ampdu_action,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 enum ieee80211_ampdu_mlme_action action,
+		 struct ieee80211_sta *sta, u16 tid,
+		 u16 *ssn, u8 buf_size),
+
+	TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		STA_ENTRY
+		__field(u32, action)
+		__field(u16, tid)
+		__field(u16, ssn)
+		__field(u8, buf_size)
+		VIF_ENTRY
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		STA_ASSIGN;
+		__entry->action = action;
+		__entry->tid = tid;
+		__entry->ssn = ssn ? *ssn : 0;
+		__entry->buf_size = buf_size;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d",
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action,
+		__entry->tid, __entry->buf_size
+	)
+);
+
+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
+	)
+);
+
+TRACE_EVENT(drv_flush,
+	TP_PROTO(struct ieee80211_local *local, bool drop),
+
+	TP_ARGS(local, drop),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(bool, drop)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->drop = drop;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " drop:%d",
+		LOCAL_PR_ARG, __entry->drop
+	)
+);
+
+TRACE_EVENT(drv_channel_switch,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_channel_switch *ch_switch),
+
+	TP_ARGS(local, ch_switch),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u64, timestamp)
+		__field(bool, block_tx)
+		__field(u16, freq)
+		__field(u8, count)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->timestamp = ch_switch->timestamp;
+		__entry->block_tx = ch_switch->block_tx;
+		__entry->freq = ch_switch->channel->center_freq;
+		__entry->count = ch_switch->count;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " new freq:%u count:%d",
+		LOCAL_PR_ARG, __entry->freq, __entry->count
+	)
+);
+
+TRACE_EVENT(drv_set_antenna,
+	TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret),
+
+	TP_ARGS(local, tx_ant, rx_ant, ret),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u32, tx_ant)
+		__field(u32, rx_ant)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->tx_ant = tx_ant;
+		__entry->rx_ant = rx_ant;
+		__entry->ret = ret;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d",
+		LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret
+	)
+);
+
+TRACE_EVENT(drv_get_antenna,
+	TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret),
+
+	TP_ARGS(local, tx_ant, rx_ant, ret),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u32, tx_ant)
+		__field(u32, rx_ant)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->tx_ant = tx_ant;
+		__entry->rx_ant = rx_ant;
+		__entry->ret = ret;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d",
+		LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret
+	)
+);
+
+TRACE_EVENT(drv_remain_on_channel,
+	TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan,
+		 enum nl80211_channel_type chantype, unsigned int duration),
+
+	TP_ARGS(local, chan, chantype, duration),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(int, center_freq)
+		__field(int, channel_type)
+		__field(unsigned int, duration)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->center_freq = chan->center_freq;
+		__entry->channel_type = chantype;
+		__entry->duration = duration;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " freq:%dMHz duration:%dms",
+		LOCAL_PR_ARG, __entry->center_freq, __entry->duration
+	)
+);
+
+DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+TRACE_EVENT(drv_offchannel_tx,
+	TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb,
+		 struct ieee80211_channel *chan,
+		 enum nl80211_channel_type channel_type,
+		 unsigned int wait),
+
+	TP_ARGS(local, skb, chan, channel_type, wait),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(int, center_freq)
+		__field(int, channel_type)
+		__field(unsigned int, wait)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->center_freq = chan->center_freq;
+		__entry->channel_type = channel_type;
+		__entry->wait = wait;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " freq:%dMHz, wait:%dms",
+		LOCAL_PR_ARG, __entry->center_freq, __entry->wait
+	)
+);
+
+TRACE_EVENT(drv_set_ringparam,
+	TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx),
+
+	TP_ARGS(local, tx, rx),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u32, tx)
+		__field(u32, rx)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->tx = tx;
+		__entry->rx = rx;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " tx:%d rx %d",
+		LOCAL_PR_ARG, __entry->tx, __entry->rx
+	)
+);
+
+TRACE_EVENT(drv_get_ringparam,
+	TP_PROTO(struct ieee80211_local *local, u32 *tx, u32 *tx_max,
+		 u32 *rx, u32 *rx_max),
+
+	TP_ARGS(local, tx, tx_max, rx, rx_max),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u32, tx)
+		__field(u32, tx_max)
+		__field(u32, rx)
+		__field(u32, rx_max)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->tx = *tx;
+		__entry->tx_max = *tx_max;
+		__entry->rx = *rx;
+		__entry->rx_max = *rx_max;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " tx:%d tx_max %d rx %d rx_max %d",
+		LOCAL_PR_ARG,
+		__entry->tx, __entry->tx_max, __entry->rx, __entry->rx_max
+	)
+);
+
+DEFINE_EVENT(local_only_evt, drv_tx_frames_pending,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+TRACE_EVENT(drv_set_bitrate_mask,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 const struct cfg80211_bitrate_mask *mask),
+
+	TP_ARGS(local, sdata, mask),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__field(u32, legacy_2g)
+		__field(u32, legacy_5g)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		__entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy;
+		__entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x",
+		LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g
+	)
+);
+
+TRACE_EVENT(drv_set_rekey_data,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct cfg80211_gtk_rekey_data *data),
+
+	TP_ARGS(local, sdata, data),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__array(u8, kek, NL80211_KEK_LEN)
+		__array(u8, kck, NL80211_KCK_LEN)
+		__array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		memcpy(__entry->kek, data->kek, NL80211_KEK_LEN);
+		memcpy(__entry->kck, data->kck, NL80211_KCK_LEN);
+		memcpy(__entry->replay_ctr, data->replay_ctr,
+		       NL80211_REPLAY_CTR_LEN);
+	),
+
+	TP_printk(LOCAL_PR_FMT VIF_PR_FMT,
+		  LOCAL_PR_ARG, VIF_PR_ARG)
+);
+
+TRACE_EVENT(drv_rssi_callback,
+	TP_PROTO(struct ieee80211_local *local,
+		 enum ieee80211_rssi_event rssi_event),
+
+	TP_ARGS(local, rssi_event),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u32, rssi_event)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->rssi_event = rssi_event;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " rssi_event:%d",
+		LOCAL_PR_ARG, __entry->rssi_event
+	)
+);
+
+DECLARE_EVENT_CLASS(release_evt,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sta *sta,
+		 u16 tids, int num_frames,
+		 enum ieee80211_frame_release_type reason,
+		 bool more_data),
+
+	TP_ARGS(local, sta, tids, num_frames, reason, more_data),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		STA_ENTRY
+		__field(u16, tids)
+		__field(int, num_frames)
+		__field(int, reason)
+		__field(bool, more_data)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		STA_ASSIGN;
+		__entry->tids = tids;
+		__entry->num_frames = num_frames;
+		__entry->reason = reason;
+		__entry->more_data = more_data;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT STA_PR_FMT
+		" TIDs:0x%.4x frames:%d reason:%d more:%d",
+		LOCAL_PR_ARG, STA_PR_ARG, __entry->tids, __entry->num_frames,
+		__entry->reason, __entry->more_data
+	)
+);
+
+DEFINE_EVENT(release_evt, drv_release_buffered_frames,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sta *sta,
+		 u16 tids, int num_frames,
+		 enum ieee80211_frame_release_type reason,
+		 bool more_data),
+
+	TP_ARGS(local, sta, tids, num_frames, reason, more_data)
+);
+
+DEFINE_EVENT(release_evt, drv_allow_buffered_frames,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sta *sta,
+		 u16 tids, int num_frames,
+		 enum ieee80211_frame_release_type reason,
+		 bool more_data),
+
+	TP_ARGS(local, sta, tids, num_frames, reason, more_data)
+);
+
+TRACE_EVENT(drv_get_rssi,
+	TP_PROTO(struct ieee80211_local *local, struct ieee80211_sta *sta,
+		 s8 rssi, int ret),
+
+	TP_ARGS(local, sta, rssi, ret),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		STA_ENTRY
+		__field(s8, rssi)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		STA_ASSIGN;
+		__entry->rssi = rssi;
+		__entry->ret = ret;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT STA_PR_FMT " rssi:%d ret:%d",
+		LOCAL_PR_ARG, STA_PR_ARG, __entry->rssi, __entry->ret
+	)
+);
+
+/*
+ * Tracing for API calls that drivers call.
+ */
+
+TRACE_EVENT(api_start_tx_ba_session,
+	TP_PROTO(struct ieee80211_sta *sta, u16 tid),
+
+	TP_ARGS(sta, tid),
+
+	TP_STRUCT__entry(
+		STA_ENTRY
+		__field(u16, tid)
+	),
+
+	TP_fast_assign(
+		STA_ASSIGN;
+		__entry->tid = tid;
+	),
+
+	TP_printk(
+		STA_PR_FMT " tid:%d",
+		STA_PR_ARG, __entry->tid
+	)
+);
+
+TRACE_EVENT(api_start_tx_ba_cb,
+	TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
+
+	TP_ARGS(sdata, ra, tid),
+
+	TP_STRUCT__entry(
+		VIF_ENTRY
+		__array(u8, ra, ETH_ALEN)
+		__field(u16, tid)
+	),
+
+	TP_fast_assign(
+		VIF_ASSIGN;
+		memcpy(__entry->ra, ra, ETH_ALEN);
+		__entry->tid = tid;
+	),
+
+	TP_printk(
+		VIF_PR_FMT " ra:%pM tid:%d",
+		VIF_PR_ARG, __entry->ra, __entry->tid
+	)
+);
+
+TRACE_EVENT(api_stop_tx_ba_session,
+	TP_PROTO(struct ieee80211_sta *sta, u16 tid),
+
+	TP_ARGS(sta, tid),
+
+	TP_STRUCT__entry(
+		STA_ENTRY
+		__field(u16, tid)
+	),
+
+	TP_fast_assign(
+		STA_ASSIGN;
+		__entry->tid = tid;
+	),
+
+	TP_printk(
+		STA_PR_FMT " tid:%d",
+		STA_PR_ARG, __entry->tid
+	)
+);
+
+TRACE_EVENT(api_stop_tx_ba_cb,
+	TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
+
+	TP_ARGS(sdata, ra, tid),
+
+	TP_STRUCT__entry(
+		VIF_ENTRY
+		__array(u8, ra, ETH_ALEN)
+		__field(u16, tid)
+	),
+
+	TP_fast_assign(
+		VIF_ASSIGN;
+		memcpy(__entry->ra, ra, ETH_ALEN);
+		__entry->tid = tid;
+	),
+
+	TP_printk(
+		VIF_PR_FMT " ra:%pM tid:%d",
+		VIF_PR_ARG, __entry->ra, __entry->tid
+	)
+);
+
+DEFINE_EVENT(local_only_evt, api_restart_hw,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+TRACE_EVENT(api_beacon_loss,
+	TP_PROTO(struct ieee80211_sub_if_data *sdata),
+
+	TP_ARGS(sdata),
+
+	TP_STRUCT__entry(
+		VIF_ENTRY
+	),
+
+	TP_fast_assign(
+		VIF_ASSIGN;
+	),
+
+	TP_printk(
+		VIF_PR_FMT,
+		VIF_PR_ARG
+	)
+);
+
+TRACE_EVENT(api_connection_loss,
+	TP_PROTO(struct ieee80211_sub_if_data *sdata),
+
+	TP_ARGS(sdata),
+
+	TP_STRUCT__entry(
+		VIF_ENTRY
+	),
+
+	TP_fast_assign(
+		VIF_ASSIGN;
+	),
+
+	TP_printk(
+		VIF_PR_FMT,
+		VIF_PR_ARG
+	)
+);
+
+TRACE_EVENT(api_cqm_rssi_notify,
+	TP_PROTO(struct ieee80211_sub_if_data *sdata,
+		 enum nl80211_cqm_rssi_threshold_event rssi_event),
+
+	TP_ARGS(sdata, rssi_event),
+
+	TP_STRUCT__entry(
+		VIF_ENTRY
+		__field(u32, rssi_event)
+	),
+
+	TP_fast_assign(
+		VIF_ASSIGN;
+		__entry->rssi_event = rssi_event;
+	),
+
+	TP_printk(
+		VIF_PR_FMT " event:%d",
+		VIF_PR_ARG, __entry->rssi_event
+	)
+);
+
+TRACE_EVENT(api_scan_completed,
+	TP_PROTO(struct ieee80211_local *local, bool aborted),
+
+	TP_ARGS(local, aborted),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(bool, aborted)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->aborted = aborted;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " aborted:%d",
+		LOCAL_PR_ARG, __entry->aborted
+	)
+);
+
+TRACE_EVENT(api_sched_scan_results,
+	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(api_sched_scan_stopped,
+	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(api_sta_block_awake,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sta *sta, bool block),
+
+	TP_ARGS(local, sta, block),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		STA_ENTRY
+		__field(bool, block)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		STA_ASSIGN;
+		__entry->block = block;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT STA_PR_FMT " block:%d",
+		LOCAL_PR_ARG, STA_PR_FMT, __entry->block
+	)
+);
+
+TRACE_EVENT(api_chswitch_done,
+	TP_PROTO(struct ieee80211_sub_if_data *sdata, bool success),
+
+	TP_ARGS(sdata, success),
+
+	TP_STRUCT__entry(
+		VIF_ENTRY
+		__field(bool, success)
+	),
+
+	TP_fast_assign(
+		VIF_ASSIGN;
+		__entry->success = success;
+	),
+
+	TP_printk(
+		VIF_PR_FMT " success=%d",
+		VIF_PR_ARG, __entry->success
+	)
+);
+
+DEFINE_EVENT(local_only_evt, api_ready_on_channel,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_only_evt, api_remain_on_channel_expired,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
+TRACE_EVENT(api_gtk_rekey_notify,
+	TP_PROTO(struct ieee80211_sub_if_data *sdata,
+		 const u8 *bssid, const u8 *replay_ctr),
+
+	TP_ARGS(sdata, bssid, replay_ctr),
+
+	TP_STRUCT__entry(
+		VIF_ENTRY
+		__array(u8, bssid, ETH_ALEN)
+		__array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN)
+	),
+
+	TP_fast_assign(
+		VIF_ASSIGN;
+		memcpy(__entry->bssid, bssid, ETH_ALEN);
+		memcpy(__entry->replay_ctr, replay_ctr, NL80211_REPLAY_CTR_LEN);
+	),
+
+	TP_printk(VIF_PR_FMT, VIF_PR_ARG)
+);
+
+TRACE_EVENT(api_enable_rssi_reports,
+	TP_PROTO(struct ieee80211_sub_if_data *sdata,
+		 int rssi_min_thold, int rssi_max_thold),
+
+	TP_ARGS(sdata, rssi_min_thold, rssi_max_thold),
+
+	TP_STRUCT__entry(
+		VIF_ENTRY
+		__field(int, rssi_min_thold)
+		__field(int, rssi_max_thold)
+	),
+
+	TP_fast_assign(
+		VIF_ASSIGN;
+		__entry->rssi_min_thold = rssi_min_thold;
+		__entry->rssi_max_thold = rssi_max_thold;
+	),
+
+	TP_printk(
+		VIF_PR_FMT " rssi_min_thold =%d, rssi_max_thold = %d",
+		VIF_PR_ARG, __entry->rssi_min_thold, __entry->rssi_max_thold
+	)
+);
+
+TRACE_EVENT(api_eosp,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sta *sta),
+
+	TP_ARGS(local, sta),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		STA_ENTRY
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		STA_ASSIGN;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT STA_PR_FMT,
+		LOCAL_PR_ARG, STA_PR_FMT
+	)
+);
+
+/*
+ * Tracing for internal functions
+ * (which may also be called in response to driver calls)
+ */
+
+TRACE_EVENT(wake_queue,
+	TP_PROTO(struct ieee80211_local *local, u16 queue,
+		 enum queue_stop_reason reason),
+
+	TP_ARGS(local, queue, reason),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u16, queue)
+		__field(u32, reason)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->queue = queue;
+		__entry->reason = reason;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " queue:%d, reason:%d",
+		LOCAL_PR_ARG, __entry->queue, __entry->reason
+	)
+);
+
+TRACE_EVENT(stop_queue,
+	TP_PROTO(struct ieee80211_local *local, u16 queue,
+		 enum queue_stop_reason reason),
+
+	TP_ARGS(local, queue, reason),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u16, queue)
+		__field(u32, reason)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->queue = queue;
+		__entry->reason = reason;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " queue:%d, reason:%d",
+		LOCAL_PR_ARG, __entry->queue, __entry->reason
+	)
+);
+
+#ifdef CONFIG_MAC80211_MESSAGE_TRACING
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mac80211_msg
+
+#define MAX_MSG_LEN	100
+
+DECLARE_EVENT_CLASS(mac80211_msg_event,
+	TP_PROTO(struct va_format *vaf),
+
+	TP_ARGS(vaf),
+
+	TP_STRUCT__entry(
+		__dynamic_array(char, msg, MAX_MSG_LEN)
+	),
+
+	TP_fast_assign(
+		WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+				       MAX_MSG_LEN, vaf->fmt,
+				       *vaf->va) >= MAX_MSG_LEN);
+	),
+
+	TP_printk("%s", __get_str(msg))
+);
+
+DEFINE_EVENT(mac80211_msg_event, mac80211_info,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+DEFINE_EVENT(mac80211_msg_event, mac80211_dbg,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+DEFINE_EVENT(mac80211_msg_event, mac80211_err,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+#endif
+
+#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index e453212..ec8f5346 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -175,12 +175,6 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
 	return cpu_to_le16(dur);
 }
 
-static inline int is_ieee80211_device(struct ieee80211_local *local,
-				      struct net_device *dev)
-{
-	return local == wdev_priv(dev->ieee80211_ptr);
-}
-
 /* tx handlers */
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
@@ -297,10 +291,10 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 		if (unlikely(!assoc &&
 			     ieee80211_is_data(hdr->frame_control))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-			printk(KERN_DEBUG "%s: dropped data frame to not "
-			       "associated station %pM\n",
-			       tx->sdata->name, hdr->addr1);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+			sdata_info(tx->sdata,
+				   "dropped data frame to not associated station %pM\n",
+				   hdr->addr1);
+#endif
 			I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
 			return TX_DROP;
 		}
@@ -367,10 +361,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
 	rcu_read_unlock();
 
 	local->total_ps_buffered = total;
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-	wiphy_debug(local->hw.wiphy, "PS buffers full - purged %d frames\n",
-		    purged);
-#endif
+	ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged);
 }
 
 static ieee80211_tx_result
@@ -412,10 +403,8 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
 		purge_old_ps_buffers(tx->local);
 
 	if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) {
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		net_dbg_ratelimited("%s: BC TX buffer full - dropping the oldest frame\n",
-				    tx->sdata->name);
-#endif
+		ps_dbg(tx->sdata,
+		       "BC TX buffer full - dropping the oldest frame\n");
 		dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
 	} else
 		tx->local->total_ps_buffered++;
@@ -466,18 +455,15 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 			return TX_CONTINUE;
 		}
 
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
+		ps_dbg(sta->sdata, "STA %pM aid %d: PS buffer for AC %d\n",
 		       sta->sta.addr, sta->sta.aid, ac);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
 			purge_old_ps_buffers(tx->local);
 		if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
 			struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-			net_dbg_ratelimited("%s: STA %pM TX buffer for AC %d full - dropping oldest frame\n",
-					    tx->sdata->name, sta->sta.addr, ac);
-#endif
+			ps_dbg(tx->sdata,
+			       "STA %pM TX buffer for AC %d full - dropping oldest frame\n",
+			       sta->sta.addr, ac);
 			dev_kfree_skb(old);
 		} else
 			tx->local->total_ps_buffered++;
@@ -499,14 +485,11 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 		sta_info_recalc_tim(sta);
 
 		return TX_QUEUED;
+	} else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) {
+		ps_dbg(tx->sdata,
+		       "STA %pM in PS mode, but polling/in SP -> send frame\n",
+		       sta->sta.addr);
 	}
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-	else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) {
-		printk(KERN_DEBUG
-		       "%s: STA %pM in PS mode, but polling/in SP -> send frame\n",
-		       tx->sdata->name, sta->sta.addr);
-	}
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
 	return TX_CONTINUE;
 }
@@ -1965,7 +1948,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 		     (cpu_to_be16(ethertype) != sdata->control_port_protocol ||
 		      !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		net_dbg_ratelimited("%s: dropped frame to %pM (unauthorized port)\n",
+		net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n",
 				    dev->name, hdr.addr1);
 #endif
 
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 8dd4712..242ecde 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -804,7 +804,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_tx_queue_params qparam;
 	int ac;
-	bool use_11b;
+	bool use_11b, enable_qos;
 	int aCWmin, aCWmax;
 
 	if (!local->ops->conf_tx)
@@ -818,6 +818,13 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
 	use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
 		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
 
+	/*
+	 * By default disable QoS in STA mode for old access points, which do
+	 * not support 802.11e. New APs will provide proper queue parameters,
+	 * that we will configure later.
+	 */
+	enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
+
 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
 		/* Set defaults according to 802.11-2007 Table 7-37 */
 		aCWmax = 1023;
@@ -826,38 +833,47 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
 		else
 			aCWmin = 15;
 
-		switch (ac) {
-		case IEEE80211_AC_BK:
-			qparam.cw_max = aCWmax;
-			qparam.cw_min = aCWmin;
-			qparam.txop = 0;
-			qparam.aifs = 7;
-			break;
-		default: /* never happens but let's not leave undefined */
-		case IEEE80211_AC_BE:
+		if (enable_qos) {
+			switch (ac) {
+			case IEEE80211_AC_BK:
+				qparam.cw_max = aCWmax;
+				qparam.cw_min = aCWmin;
+				qparam.txop = 0;
+				qparam.aifs = 7;
+				break;
+			/* never happens but let's not leave undefined */
+			default:
+			case IEEE80211_AC_BE:
+				qparam.cw_max = aCWmax;
+				qparam.cw_min = aCWmin;
+				qparam.txop = 0;
+				qparam.aifs = 3;
+				break;
+			case IEEE80211_AC_VI:
+				qparam.cw_max = aCWmin;
+				qparam.cw_min = (aCWmin + 1) / 2 - 1;
+				if (use_11b)
+					qparam.txop = 6016/32;
+				else
+					qparam.txop = 3008/32;
+				qparam.aifs = 2;
+				break;
+			case IEEE80211_AC_VO:
+				qparam.cw_max = (aCWmin + 1) / 2 - 1;
+				qparam.cw_min = (aCWmin + 1) / 4 - 1;
+				if (use_11b)
+					qparam.txop = 3264/32;
+				else
+					qparam.txop = 1504/32;
+				qparam.aifs = 2;
+				break;
+			}
+		} else {
+			/* Confiure old 802.11b/g medium access rules. */
 			qparam.cw_max = aCWmax;
 			qparam.cw_min = aCWmin;
 			qparam.txop = 0;
-			qparam.aifs = 3;
-			break;
-		case IEEE80211_AC_VI:
-			qparam.cw_max = aCWmin;
-			qparam.cw_min = (aCWmin + 1) / 2 - 1;
-			if (use_11b)
-				qparam.txop = 6016/32;
-			else
-				qparam.txop = 3008/32;
-			qparam.aifs = 2;
-			break;
-		case IEEE80211_AC_VO:
-			qparam.cw_max = (aCWmin + 1) / 2 - 1;
-			qparam.cw_min = (aCWmin + 1) / 4 - 1;
-			if (use_11b)
-				qparam.txop = 3264/32;
-			else
-				qparam.txop = 1504/32;
 			qparam.aifs = 2;
-			break;
 		}
 
 		qparam.uapsd = false;
@@ -866,12 +882,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
 		drv_conf_tx(local, sdata, ac, &qparam);
 	}
 
-	/* after reinitialize QoS TX queues setting to default,
-	 * disable QoS at all */
-
 	if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
-		sdata->vif.bss_conf.qos =
-			sdata->vif.type != NL80211_IFTYPE_STATION;
+		sdata->vif.bss_conf.qos = enable_qos;
 		if (bss_notify)
 			ieee80211_bss_info_change_notify(sdata,
 							 BSS_CHANGED_QOS);
@@ -1267,14 +1279,19 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 	/* add STAs back */
 	mutex_lock(&local->sta_mtx);
 	list_for_each_entry(sta, &local->sta_list, list) {
-		if (sta->uploaded) {
-			enum ieee80211_sta_state state;
+		enum ieee80211_sta_state state;
 
-			for (state = IEEE80211_STA_NOTEXIST;
-			     state < sta->sta_state; state++)
-				WARN_ON(drv_sta_state(local, sta->sdata, sta,
-						      state, state + 1));
-		}
+		if (!sta->uploaded)
+			continue;
+
+		/* AP-mode stations will be added later */
+		if (sta->sdata->vif.type == NL80211_IFTYPE_AP)
+			continue;
+
+		for (state = IEEE80211_STA_NOTEXIST;
+		     state < sta->sta_state; state++)
+			WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
+					      state + 1));
 	}
 	mutex_unlock(&local->sta_mtx);
 
@@ -1371,11 +1388,32 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 		}
 	}
 
+	/* APs are now beaconing, add back stations */
+	mutex_lock(&local->sta_mtx);
+	list_for_each_entry(sta, &local->sta_list, list) {
+		enum ieee80211_sta_state state;
+
+		if (!sta->uploaded)
+			continue;
+
+		if (sta->sdata->vif.type != NL80211_IFTYPE_AP)
+			continue;
+
+		for (state = IEEE80211_STA_NOTEXIST;
+		     state < sta->sta_state; state++)
+			WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
+					      state + 1));
+	}
+	mutex_unlock(&local->sta_mtx);
+
 	/* add back keys */
 	list_for_each_entry(sdata, &local->interfaces, list)
 		if (ieee80211_sdata_running(sdata))
 			ieee80211_enable_keys(sdata);
 
+	local->in_reconfig = false;
+	barrier();
+
  wake_up:
 	/*
 	 * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index c3d643a..cea06e9 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -52,11 +52,11 @@ static int wme_downgrade_ac(struct sk_buff *skb)
 	}
 }
 
-static u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
+static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata,
 				     struct sk_buff *skb)
 {
 	/* in case we are a client verify acm is not set for this ac */
-	while (unlikely(local->wmm_acm & BIT(skb->priority))) {
+	while (unlikely(sdata->wmm_acm & BIT(skb->priority))) {
 		if (wme_downgrade_ac(skb)) {
 			/*
 			 * This should not really happen. The AP has marked all
@@ -73,10 +73,11 @@ static u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
 }
 
 /* Indicate which queue to use for this fully formed 802.11 frame */
-u16 ieee80211_select_queue_80211(struct ieee80211_local *local,
+u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
 				 struct sk_buff *skb,
 				 struct ieee80211_hdr *hdr)
 {
+	struct ieee80211_local *local = sdata->local;
 	u8 *p;
 
 	if (local->hw.queues < IEEE80211_NUM_ACS)
@@ -94,7 +95,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_local *local,
 	p = ieee80211_get_qos_ctl(hdr);
 	skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
 
-	return ieee80211_downgrade_queue(local, skb);
+	return ieee80211_downgrade_queue(sdata, skb);
 }
 
 /* Indicate which queue to use. */
@@ -156,7 +157,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
 	 * data frame has */
 	skb->priority = cfg80211_classify8021d(skb);
 
-	return ieee80211_downgrade_queue(local, skb);
+	return ieee80211_downgrade_queue(sdata, skb);
 }
 
 void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index ca80818..7fea4bb 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -15,7 +15,7 @@
 
 extern const int ieee802_1d_to_ac[8];
 
-u16 ieee80211_select_queue_80211(struct ieee80211_local *local,
+u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
 				 struct sk_buff *skb,
 				 struct ieee80211_hdr *hdr);
 u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
deleted file mode 100644
index b2650a9..0000000
--- a/net/mac80211/work.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * mac80211 work implementation
- *
- * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
- * Copyright 2004, Instant802 Networks, Inc.
- * Copyright 2005, Devicescape Software, Inc.
- * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
- * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/delay.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/crc32.h>
-#include <linux/slab.h>
-#include <net/mac80211.h>
-#include <asm/unaligned.h>
-
-#include "ieee80211_i.h"
-#include "rate.h"
-#include "driver-ops.h"
-
-enum work_action {
-	WORK_ACT_NONE,
-	WORK_ACT_TIMEOUT,
-};
-
-
-/* utils */
-static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
-{
-	lockdep_assert_held(&local->mtx);
-}
-
-/*
- * We can have multiple work items (and connection probing)
- * scheduling this timer, but we need to take care to only
- * reschedule it when it should fire _earlier_ than it was
- * asked for before, or if it's not pending right now. This
- * function ensures that. Note that it then is required to
- * run this function for all timeouts after the first one
- * has happened -- the work that runs from this timer will
- * do that.
- */
-static void run_again(struct ieee80211_local *local,
-		      unsigned long timeout)
-{
-	ASSERT_WORK_MTX(local);
-
-	if (!timer_pending(&local->work_timer) ||
-	    time_before(timeout, local->work_timer.expires))
-		mod_timer(&local->work_timer, timeout);
-}
-
-void free_work(struct ieee80211_work *wk)
-{
-	kfree_rcu(wk, rcu_head);
-}
-
-static enum work_action __must_check
-ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
-{
-	/*
-	 * First time we run, do nothing -- the generic code will
-	 * have switched to the right channel etc.
-	 */
-	if (!wk->started) {
-		wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration);
-
-		cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk,
-					  wk->chan, wk->chan_type,
-					  wk->remain.duration, GFP_KERNEL);
-
-		return WORK_ACT_NONE;
-	}
-
-	return WORK_ACT_TIMEOUT;
-}
-
-static enum work_action __must_check
-ieee80211_offchannel_tx(struct ieee80211_work *wk)
-{
-	if (!wk->started) {
-		wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait);
-
-		/*
-		 * After this, offchan_tx.frame remains but now is no
-		 * longer a valid pointer -- we still need it as the
-		 * cookie for canceling this work/status matching.
-		 */
-		ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame);
-
-		return WORK_ACT_NONE;
-	}
-
-	return WORK_ACT_TIMEOUT;
-}
-
-static void ieee80211_work_timer(unsigned long data)
-{
-	struct ieee80211_local *local = (void *) data;
-
-	if (local->quiescing)
-		return;
-
-	ieee80211_queue_work(&local->hw, &local->work_work);
-}
-
-static void ieee80211_work_work(struct work_struct *work)
-{
-	struct ieee80211_local *local =
-		container_of(work, struct ieee80211_local, work_work);
-	struct ieee80211_work *wk, *tmp;
-	LIST_HEAD(free_work);
-	enum work_action rma;
-	bool remain_off_channel = false;
-
-	/*
-	 * ieee80211_queue_work() should have picked up most cases,
-	 * here we'll pick the rest.
-	 */
-	if (WARN(local->suspended, "work scheduled while going to suspend\n"))
-		return;
-
-	mutex_lock(&local->mtx);
-
-	if (local->scanning) {
-		mutex_unlock(&local->mtx);
-		return;
-	}
-
-	ieee80211_recalc_idle(local);
-
-	list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
-		bool started = wk->started;
-
-		/* mark work as started if it's on the current off-channel */
-		if (!started && local->tmp_channel &&
-		    wk->chan == local->tmp_channel &&
-		    wk->chan_type == local->tmp_channel_type) {
-			started = true;
-			wk->timeout = jiffies;
-		}
-
-		if (!started && !local->tmp_channel) {
-			ieee80211_offchannel_stop_vifs(local, true);
-
-			local->tmp_channel = wk->chan;
-			local->tmp_channel_type = wk->chan_type;
-
-			ieee80211_hw_config(local, 0);
-
-			started = true;
-			wk->timeout = jiffies;
-		}
-
-		/* don't try to work with items that aren't started */
-		if (!started)
-			continue;
-
-		if (time_is_after_jiffies(wk->timeout)) {
-			/*
-			 * This work item isn't supposed to be worked on
-			 * right now, but take care to adjust the timer
-			 * properly.
-			 */
-			run_again(local, wk->timeout);
-			continue;
-		}
-
-		switch (wk->type) {
-		default:
-			WARN_ON(1);
-			/* nothing */
-			rma = WORK_ACT_NONE;
-			break;
-		case IEEE80211_WORK_ABORT:
-			rma = WORK_ACT_TIMEOUT;
-			break;
-		case IEEE80211_WORK_REMAIN_ON_CHANNEL:
-			rma = ieee80211_remain_on_channel_timeout(wk);
-			break;
-		case IEEE80211_WORK_OFFCHANNEL_TX:
-			rma = ieee80211_offchannel_tx(wk);
-			break;
-		}
-
-		wk->started = started;
-
-		switch (rma) {
-		case WORK_ACT_NONE:
-			/* might have changed the timeout */
-			run_again(local, wk->timeout);
-			break;
-		case WORK_ACT_TIMEOUT:
-			list_del_rcu(&wk->list);
-			synchronize_rcu();
-			list_add(&wk->list, &free_work);
-			break;
-		default:
-			WARN(1, "unexpected: %d", rma);
-		}
-	}
-
-	list_for_each_entry(wk, &local->work_list, list) {
-		if (!wk->started)
-			continue;
-		if (wk->chan != local->tmp_channel ||
-		    wk->chan_type != local->tmp_channel_type)
-			continue;
-		remain_off_channel = true;
-	}
-
-	if (!remain_off_channel && local->tmp_channel) {
-		local->tmp_channel = NULL;
-		ieee80211_hw_config(local, 0);
-
-		ieee80211_offchannel_return(local, true);
-
-		/* give connection some time to breathe */
-		run_again(local, jiffies + HZ/2);
-	}
-
-	ieee80211_recalc_idle(local);
-	ieee80211_run_deferred_scan(local);
-
-	mutex_unlock(&local->mtx);
-
-	list_for_each_entry_safe(wk, tmp, &free_work, list) {
-		wk->done(wk, NULL);
-		list_del(&wk->list);
-		kfree(wk);
-	}
-}
-
-void ieee80211_add_work(struct ieee80211_work *wk)
-{
-	struct ieee80211_local *local;
-
-	if (WARN_ON(!wk->chan))
-		return;
-
-	if (WARN_ON(!wk->sdata))
-		return;
-
-	if (WARN_ON(!wk->done))
-		return;
-
-	if (WARN_ON(!ieee80211_sdata_running(wk->sdata)))
-		return;
-
-	wk->started = false;
-
-	local = wk->sdata->local;
-	mutex_lock(&local->mtx);
-	list_add_tail(&wk->list, &local->work_list);
-	mutex_unlock(&local->mtx);
-
-	ieee80211_queue_work(&local->hw, &local->work_work);
-}
-
-void ieee80211_work_init(struct ieee80211_local *local)
-{
-	INIT_LIST_HEAD(&local->work_list);
-	setup_timer(&local->work_timer, ieee80211_work_timer,
-		    (unsigned long)local);
-	INIT_WORK(&local->work_work, ieee80211_work_work);
-}
-
-void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_work *wk;
-	bool cleanup = false;
-
-	mutex_lock(&local->mtx);
-	list_for_each_entry(wk, &local->work_list, list) {
-		if (wk->sdata != sdata)
-			continue;
-		cleanup = true;
-		wk->type = IEEE80211_WORK_ABORT;
-		wk->started = true;
-		wk->timeout = jiffies;
-	}
-	mutex_unlock(&local->mtx);
-
-	/* run cleanups etc. */
-	if (cleanup)
-		ieee80211_work_work(&local->work_work);
-
-	mutex_lock(&local->mtx);
-	list_for_each_entry(wk, &local->work_list, list) {
-		if (wk->sdata != sdata)
-			continue;
-		WARN_ON(1);
-		break;
-	}
-	mutex_unlock(&local->mtx);
-}
-
-static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk,
-						   struct sk_buff *skb)
-{
-	/*
-	 * We are done serving the remain-on-channel command.
-	 */
-	cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk,
-					   wk->chan, wk->chan_type,
-					   GFP_KERNEL);
-
-	return WORK_DONE_DESTROY;
-}
-
-int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
-				   struct ieee80211_channel *chan,
-				   enum nl80211_channel_type channel_type,
-				   unsigned int duration, u64 *cookie)
-{
-	struct ieee80211_work *wk;
-
-	wk = kzalloc(sizeof(*wk), GFP_KERNEL);
-	if (!wk)
-		return -ENOMEM;
-
-	wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL;
-	wk->chan = chan;
-	wk->chan_type = channel_type;
-	wk->sdata = sdata;
-	wk->done = ieee80211_remain_done;
-
-	wk->remain.duration = duration;
-
-	*cookie = (unsigned long) wk;
-
-	ieee80211_add_work(wk);
-
-	return 0;
-}
-
-int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
-					  u64 cookie)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_work *wk, *tmp;
-	bool found = false;
-
-	mutex_lock(&local->mtx);
-	list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
-		if ((unsigned long) wk == cookie) {
-			wk->timeout = jiffies;
-			found = true;
-			break;
-		}
-	}
-	mutex_unlock(&local->mtx);
-
-	if (!found)
-		return -ENOENT;
-
-	ieee80211_queue_work(&local->hw, &local->work_work);
-
-	return 0;
-}
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index 8781d8f9..434b687 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -83,9 +83,10 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
 {
 	struct xmit_work *work;
 
-	if (!(priv->phy->channels_supported[page] & (1 << chan)))
+	if (!(priv->phy->channels_supported[page] & (1 << chan))) {
 		WARN_ON(1);
 		return NETDEV_TX_OK;
+	}
 
 	if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) {
 		u16 crc = crc_ccitt(0, skb->data, skb->len);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 209c1ed..c19b214 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -335,6 +335,27 @@ config NF_CT_NETLINK_TIMEOUT
 
 	  If unsure, say `N'.
 
+config NF_CT_NETLINK_HELPER
+	tristate 'Connection tracking helpers in user-space via Netlink'
+	select NETFILTER_NETLINK
+	depends on NF_CT_NETLINK
+	depends on NETFILTER_NETLINK_QUEUE
+	depends on NETFILTER_NETLINK_QUEUE_CT
+	depends on NETFILTER_ADVANCED
+	help
+	  This option enables the user-space connection tracking helpers
+	  infrastructure.
+
+	  If unsure, say `N'.
+
+config NETFILTER_NETLINK_QUEUE_CT
+        bool "NFQUEUE integration with Connection Tracking"
+        default n
+        depends on NETFILTER_NETLINK_QUEUE
+	help
+	  If this option is enabled, NFQUEUE can include Connection Tracking
+	  information together with the packet is the enqueued via NFNETLINK.
+
 endif # NF_CONNTRACK
 
 # transparent proxy support
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 4e7960c..1c5160f 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -9,6 +9,8 @@ obj-$(CONFIG_NETFILTER) = netfilter.o
 
 obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
 obj-$(CONFIG_NETFILTER_NETLINK_ACCT) += nfnetlink_acct.o
+nfnetlink_queue-y := nfnetlink_queue_core.o
+nfnetlink_queue-$(CONFIG_NETFILTER_NETLINK_QUEUE_CT) += nfnetlink_queue_ct.o
 obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
 obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
 
@@ -24,6 +26,7 @@ obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o
 # netlink interface for nf_conntrack
 obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
 obj-$(CONFIG_NF_CT_NETLINK_TIMEOUT) += nfnetlink_cttimeout.o
+obj-$(CONFIG_NF_CT_NETLINK_HELPER) += nfnetlink_cthelper.o
 
 # connection tracking helpers
 nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index e19f365..0bc6b60 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -264,6 +264,13 @@ void nf_conntrack_destroy(struct nf_conntrack *nfct)
 	rcu_read_unlock();
 }
 EXPORT_SYMBOL(nf_conntrack_destroy);
+
+struct nfq_ct_hook __rcu *nfq_ct_hook __read_mostly;
+EXPORT_SYMBOL_GPL(nfq_ct_hook);
+
+struct nfq_ct_nat_hook __rcu *nfq_ct_nat_hook __read_mostly;
+EXPORT_SYMBOL_GPL(nfq_ct_nat_hook);
+
 #endif /* CONFIG_NF_CONNTRACK */
 
 #ifdef CONFIG_PROC_FS
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index a54b018c..b54ecce 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -1742,7 +1742,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_reply4,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
+		.pf		= NFPROTO_IPV4,
 		.hooknum	= NF_INET_LOCAL_IN,
 		.priority	= NF_IP_PRI_NAT_SRC - 2,
 	},
@@ -1752,7 +1752,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_remote_request4,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
+		.pf		= NFPROTO_IPV4,
 		.hooknum	= NF_INET_LOCAL_IN,
 		.priority	= NF_IP_PRI_NAT_SRC - 1,
 	},
@@ -1760,7 +1760,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_local_reply4,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
+		.pf		= NFPROTO_IPV4,
 		.hooknum	= NF_INET_LOCAL_OUT,
 		.priority	= NF_IP_PRI_NAT_DST + 1,
 	},
@@ -1768,7 +1768,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_local_request4,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
+		.pf		= NFPROTO_IPV4,
 		.hooknum	= NF_INET_LOCAL_OUT,
 		.priority	= NF_IP_PRI_NAT_DST + 2,
 	},
@@ -1777,7 +1777,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_forward_icmp,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
+		.pf		= NFPROTO_IPV4,
 		.hooknum	= NF_INET_FORWARD,
 		.priority	= 99,
 	},
@@ -1785,7 +1785,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_reply4,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
+		.pf		= NFPROTO_IPV4,
 		.hooknum	= NF_INET_FORWARD,
 		.priority	= 100,
 	},
@@ -1794,7 +1794,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_reply6,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET6,
+		.pf		= NFPROTO_IPV6,
 		.hooknum	= NF_INET_LOCAL_IN,
 		.priority	= NF_IP6_PRI_NAT_SRC - 2,
 	},
@@ -1804,7 +1804,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_remote_request6,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET6,
+		.pf		= NFPROTO_IPV6,
 		.hooknum	= NF_INET_LOCAL_IN,
 		.priority	= NF_IP6_PRI_NAT_SRC - 1,
 	},
@@ -1812,7 +1812,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_local_reply6,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
+		.pf		= NFPROTO_IPV4,
 		.hooknum	= NF_INET_LOCAL_OUT,
 		.priority	= NF_IP6_PRI_NAT_DST + 1,
 	},
@@ -1820,7 +1820,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_local_request6,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET6,
+		.pf		= NFPROTO_IPV6,
 		.hooknum	= NF_INET_LOCAL_OUT,
 		.priority	= NF_IP6_PRI_NAT_DST + 2,
 	},
@@ -1829,7 +1829,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_forward_icmp_v6,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET6,
+		.pf		= NFPROTO_IPV6,
 		.hooknum	= NF_INET_FORWARD,
 		.priority	= 99,
 	},
@@ -1837,7 +1837,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	{
 		.hook		= ip_vs_reply6,
 		.owner		= THIS_MODULE,
-		.pf		= PF_INET6,
+		.pf		= NFPROTO_IPV6,
 		.hooknum	= NF_INET_FORWARD,
 		.priority	= 100,
 	},
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 7fd66de..71d6ecb 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -823,7 +823,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 			IP_VS_ERR_RL("%s(): no memory\n", __func__);
 			return NF_STOLEN;
 		}
-		kfree_skb(skb);
+		consume_skb(skb);
 		skb = new_skb;
 		old_iph = ip_hdr(skb);
 	}
@@ -942,7 +942,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 			IP_VS_ERR_RL("%s(): no memory\n", __func__);
 			return NF_STOLEN;
 		}
-		kfree_skb(skb);
+		consume_skb(skb);
 		skb = new_skb;
 		old_iph = ipv6_hdr(skb);
 	}
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index ac3af97..cf48755 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -531,7 +531,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
 	tstamp = nf_conn_tstamp_find(ct);
 	if (tstamp) {
 		if (skb->tstamp.tv64 == 0)
-			__net_timestamp((struct sk_buff *)skb);
+			__net_timestamp(skb);
 
 		tstamp->start = ktime_to_ns(skb->tstamp);
 	}
@@ -819,7 +819,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
 		__set_bit(IPS_EXPECTED_BIT, &ct->status);
 		ct->master = exp->master;
 		if (exp->helper) {
-			help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
+			help = nf_ct_helper_ext_add(ct, exp->helper,
+						    GFP_ATOMIC);
 			if (help)
 				rcu_assign_pointer(help->helper, exp->helper);
 		}
@@ -1333,7 +1334,6 @@ static void nf_conntrack_cleanup_init_net(void)
 	while (untrack_refs() > 0)
 		schedule();
 
-	nf_conntrack_proto_fini();
 #ifdef CONFIG_NF_CONNTRACK_ZONES
 	nf_ct_extend_unregister(&nf_ct_zone_extend);
 #endif
@@ -1372,7 +1372,7 @@ void nf_conntrack_cleanup(struct net *net)
 	   netfilter framework.  Roll on, two-stage module
 	   delete... */
 	synchronize_net();
-
+	nf_conntrack_proto_fini(net);
 	nf_conntrack_cleanup_net(net);
 
 	if (net_eq(net, &init_net)) {
@@ -1496,11 +1496,6 @@ static int nf_conntrack_init_init_net(void)
 	printk(KERN_INFO "nf_conntrack version %s (%u buckets, %d max)\n",
 	       NF_CONNTRACK_VERSION, nf_conntrack_htable_size,
 	       nf_conntrack_max);
-
-	ret = nf_conntrack_proto_init();
-	if (ret < 0)
-		goto err_proto;
-
 #ifdef CONFIG_NF_CONNTRACK_ZONES
 	ret = nf_ct_extend_register(&nf_ct_zone_extend);
 	if (ret < 0)
@@ -1518,9 +1513,7 @@ static int nf_conntrack_init_init_net(void)
 
 #ifdef CONFIG_NF_CONNTRACK_ZONES
 err_extend:
-	nf_conntrack_proto_fini();
 #endif
-err_proto:
 	return ret;
 }
 
@@ -1583,9 +1576,7 @@ static int nf_conntrack_init_net(struct net *net)
 	ret = nf_conntrack_helper_init(net);
 	if (ret < 0)
 		goto err_helper;
-
 	return 0;
-
 err_helper:
 	nf_conntrack_timeout_fini(net);
 err_timeout:
@@ -1622,6 +1613,9 @@ int nf_conntrack_init(struct net *net)
 		if (ret < 0)
 			goto out_init_net;
 	}
+	ret = nf_conntrack_proto_init(net);
+	if (ret < 0)
+		goto out_proto;
 	ret = nf_conntrack_init_net(net);
 	if (ret < 0)
 		goto out_net;
@@ -1637,6 +1631,8 @@ int nf_conntrack_init(struct net *net)
 	return 0;
 
 out_net:
+	nf_conntrack_proto_fini(net);
+out_proto:
 	if (net_eq(net, &init_net))
 		nf_conntrack_cleanup_init_net();
 out_init_net:
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index 641ff5f..1a95459 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -44,7 +44,8 @@ void __nf_ct_ext_destroy(struct nf_conn *ct)
 EXPORT_SYMBOL(__nf_ct_ext_destroy);
 
 static void *
-nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp)
+nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id,
+		 size_t var_alloc_len, gfp_t gfp)
 {
 	unsigned int off, len;
 	struct nf_ct_ext_type *t;
@@ -54,8 +55,8 @@ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp)
 	t = rcu_dereference(nf_ct_ext_types[id]);
 	BUG_ON(t == NULL);
 	off = ALIGN(sizeof(struct nf_ct_ext), t->align);
-	len = off + t->len;
-	alloc_size = t->alloc_size;
+	len = off + t->len + var_alloc_len;
+	alloc_size = t->alloc_size + var_alloc_len;
 	rcu_read_unlock();
 
 	*ext = kzalloc(alloc_size, gfp);
@@ -68,7 +69,8 @@ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp)
 	return (void *)(*ext) + off;
 }
 
-void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
+void *__nf_ct_ext_add_length(struct nf_conn *ct, enum nf_ct_ext_id id,
+			     size_t var_alloc_len, gfp_t gfp)
 {
 	struct nf_ct_ext *old, *new;
 	int i, newlen, newoff;
@@ -79,7 +81,7 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
 
 	old = ct->ext;
 	if (!old)
-		return nf_ct_ext_create(&ct->ext, id, gfp);
+		return nf_ct_ext_create(&ct->ext, id, var_alloc_len, gfp);
 
 	if (__nf_ct_ext_exist(old, id))
 		return NULL;
@@ -89,7 +91,7 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
 	BUG_ON(t == NULL);
 
 	newoff = ALIGN(old->len, t->align);
-	newlen = newoff + t->len;
+	newlen = newoff + t->len + var_alloc_len;
 	rcu_read_unlock();
 
 	new = __krealloc(old, newlen, gfp);
@@ -117,7 +119,7 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
 	memset((void *)new + newoff, 0, newlen - newoff);
 	return (void *)new + newoff;
 }
-EXPORT_SYMBOL(__nf_ct_ext_add);
+EXPORT_SYMBOL(__nf_ct_ext_add_length);
 
 static void update_alloc_size(struct nf_ct_ext_type *type)
 {
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 8c5c95c..4bb771d 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -358,7 +358,7 @@ static int help(struct sk_buff *skb,
 	u32 seq;
 	int dir = CTINFO2DIR(ctinfo);
 	unsigned int uninitialized_var(matchlen), uninitialized_var(matchoff);
-	struct nf_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info;
+	struct nf_ct_ftp_master *ct_ftp_info = nfct_help_data(ct);
 	struct nf_conntrack_expect *exp;
 	union nf_inet_addr *daddr;
 	struct nf_conntrack_man cmd = {};
@@ -512,7 +512,6 @@ out_update_nl:
 }
 
 static struct nf_conntrack_helper ftp[MAX_PORTS][2] __read_mostly;
-static char ftp_names[MAX_PORTS][2][sizeof("ftp-65535")] __read_mostly;
 
 static const struct nf_conntrack_expect_policy ftp_exp_policy = {
 	.max_expected	= 1,
@@ -541,7 +540,6 @@ static void nf_conntrack_ftp_fini(void)
 static int __init nf_conntrack_ftp_init(void)
 {
 	int i, j = -1, ret = 0;
-	char *tmpname;
 
 	ftp_buffer = kmalloc(65536, GFP_KERNEL);
 	if (!ftp_buffer)
@@ -556,17 +554,16 @@ static int __init nf_conntrack_ftp_init(void)
 		ftp[i][0].tuple.src.l3num = PF_INET;
 		ftp[i][1].tuple.src.l3num = PF_INET6;
 		for (j = 0; j < 2; j++) {
+			ftp[i][j].data_len = sizeof(struct nf_ct_ftp_master);
 			ftp[i][j].tuple.src.u.tcp.port = htons(ports[i]);
 			ftp[i][j].tuple.dst.protonum = IPPROTO_TCP;
 			ftp[i][j].expect_policy = &ftp_exp_policy;
 			ftp[i][j].me = THIS_MODULE;
 			ftp[i][j].help = help;
-			tmpname = &ftp_names[i][j][0];
 			if (ports[i] == FTP_PORT)
-				sprintf(tmpname, "ftp");
+				sprintf(ftp[i][j].name, "ftp");
 			else
-				sprintf(tmpname, "ftp-%d", ports[i]);
-			ftp[i][j].name = tmpname;
+				sprintf(ftp[i][j].name, "ftp-%d", ports[i]);
 
 			pr_debug("nf_ct_ftp: registering helper for pf: %d "
 				 "port: %d\n",
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 31f50bc..4283b20 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -114,7 +114,7 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
 			 struct nf_conn *ct, enum ip_conntrack_info ctinfo,
 			 unsigned char **data, int *datalen, int *dataoff)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
 	const struct tcphdr *th;
 	struct tcphdr _tcph;
@@ -617,6 +617,7 @@ static const struct nf_conntrack_expect_policy h245_exp_policy = {
 static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = {
 	.name			= "H.245",
 	.me			= THIS_MODULE,
+	.data_len		= sizeof(struct nf_ct_h323_master),
 	.tuple.src.l3num	= AF_UNSPEC,
 	.tuple.dst.protonum	= IPPROTO_UDP,
 	.help			= h245_help,
@@ -1169,6 +1170,7 @@ static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
 	{
 		.name			= "Q.931",
 		.me			= THIS_MODULE,
+		.data_len		= sizeof(struct nf_ct_h323_master),
 		.tuple.src.l3num	= AF_INET,
 		.tuple.src.u.tcp.port	= cpu_to_be16(Q931_PORT),
 		.tuple.dst.protonum	= IPPROTO_TCP,
@@ -1244,7 +1246,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
 		       unsigned char **data,
 		       TransportAddress *taddr, int count)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
 	int ret = 0;
 	int i;
@@ -1359,7 +1361,7 @@ static int process_rrq(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned char **data, RegistrationRequest *rrq)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int ret;
 	typeof(set_ras_addr_hook) set_ras_addr;
 
@@ -1394,7 +1396,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned char **data, RegistrationConfirm *rcf)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
 	int ret;
 	struct nf_conntrack_expect *exp;
@@ -1443,7 +1445,7 @@ static int process_urq(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned char **data, UnregistrationRequest *urq)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
 	int ret;
 	typeof(set_sig_addr_hook) set_sig_addr;
@@ -1475,7 +1477,7 @@ static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned char **data, AdmissionRequest *arq)
 {
-	const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	const struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
 	__be16 port;
 	union nf_inet_addr addr;
@@ -1742,6 +1744,7 @@ static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = {
 	{
 		.name			= "RAS",
 		.me			= THIS_MODULE,
+		.data_len		= sizeof(struct nf_ct_h323_master),
 		.tuple.src.l3num	= AF_INET,
 		.tuple.src.u.udp.port	= cpu_to_be16(RAS_PORT),
 		.tuple.dst.protonum	= IPPROTO_UDP,
@@ -1751,6 +1754,7 @@ static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = {
 	{
 		.name			= "RAS",
 		.me			= THIS_MODULE,
+		.data_len		= sizeof(struct nf_ct_h323_master),
 		.tuple.src.l3num	= AF_INET6,
 		.tuple.src.u.udp.port	= cpu_to_be16(RAS_PORT),
 		.tuple.dst.protonum	= IPPROTO_UDP,
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 4fa2ff9..c4bc637 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -30,8 +30,10 @@
 #include <net/netfilter/nf_conntrack_extend.h>
 
 static DEFINE_MUTEX(nf_ct_helper_mutex);
-static struct hlist_head *nf_ct_helper_hash __read_mostly;
-static unsigned int nf_ct_helper_hsize __read_mostly;
+struct hlist_head *nf_ct_helper_hash __read_mostly;
+EXPORT_SYMBOL_GPL(nf_ct_helper_hash);
+unsigned int nf_ct_helper_hsize __read_mostly;
+EXPORT_SYMBOL_GPL(nf_ct_helper_hsize);
 static unsigned int nf_ct_helper_count __read_mostly;
 
 static bool nf_ct_auto_assign_helper __read_mostly = true;
@@ -161,11 +163,14 @@ nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get);
 
-struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
+struct nf_conn_help *
+nf_ct_helper_ext_add(struct nf_conn *ct,
+		     struct nf_conntrack_helper *helper, gfp_t gfp)
 {
 	struct nf_conn_help *help;
 
-	help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp);
+	help = nf_ct_ext_add_length(ct, NF_CT_EXT_HELPER,
+				    helper->data_len, gfp);
 	if (help)
 		INIT_HLIST_HEAD(&help->expectations);
 	else
@@ -218,13 +223,19 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
 	}
 
 	if (help == NULL) {
-		help = nf_ct_helper_ext_add(ct, flags);
+		help = nf_ct_helper_ext_add(ct, helper, flags);
 		if (help == NULL) {
 			ret = -ENOMEM;
 			goto out;
 		}
 	} else {
-		memset(&help->help, 0, sizeof(help->help));
+		/* We only allow helper re-assignment of the same sort since
+		 * we cannot reallocate the helper extension area.
+		 */
+		if (help->helper != helper) {
+			RCU_INIT_POINTER(help->helper, NULL);
+			goto out;
+		}
 	}
 
 	rcu_assign_pointer(help->helper, helper);
@@ -319,6 +330,9 @@ EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);
 
 int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
 {
+	int ret = 0;
+	struct nf_conntrack_helper *cur;
+	struct hlist_node *n;
 	unsigned int h = helper_hash(&me->tuple);
 
 	BUG_ON(me->expect_policy == NULL);
@@ -326,11 +340,19 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
 	BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1);
 
 	mutex_lock(&nf_ct_helper_mutex);
+	hlist_for_each_entry(cur, n, &nf_ct_helper_hash[h], hnode) {
+		if (strncmp(cur->name, me->name, NF_CT_HELPER_NAME_LEN) == 0 &&
+		    cur->tuple.src.l3num == me->tuple.src.l3num &&
+		    cur->tuple.dst.protonum == me->tuple.dst.protonum) {
+			ret = -EEXIST;
+			goto out;
+		}
+	}
 	hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
 	nf_ct_helper_count++;
+out:
 	mutex_unlock(&nf_ct_helper_mutex);
-
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
 
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index 81366c1..009c52c 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -221,7 +221,6 @@ static int help(struct sk_buff *skb, unsigned int protoff,
 }
 
 static struct nf_conntrack_helper irc[MAX_PORTS] __read_mostly;
-static char irc_names[MAX_PORTS][sizeof("irc-65535")] __read_mostly;
 static struct nf_conntrack_expect_policy irc_exp_policy;
 
 static void nf_conntrack_irc_fini(void);
@@ -229,7 +228,6 @@ static void nf_conntrack_irc_fini(void);
 static int __init nf_conntrack_irc_init(void)
 {
 	int i, ret;
-	char *tmpname;
 
 	if (max_dcc_channels < 1) {
 		printk(KERN_ERR "nf_ct_irc: max_dcc_channels must not be zero\n");
@@ -255,12 +253,10 @@ static int __init nf_conntrack_irc_init(void)
 		irc[i].me = THIS_MODULE;
 		irc[i].help = help;
 
-		tmpname = &irc_names[i][0];
 		if (ports[i] == IRC_PORT)
-			sprintf(tmpname, "irc");
+			sprintf(irc[i].name, "irc");
 		else
-			sprintf(tmpname, "irc-%u", i);
-		irc[i].name = tmpname;
+			sprintf(irc[i].name, "irc-%u", i);
 
 		ret = nf_conntrack_helper_register(&irc[i]);
 		if (ret) {
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 6f4b00a..b9b8f4a 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -46,6 +46,7 @@
 #ifdef CONFIG_NF_NAT_NEEDED
 #include <net/netfilter/nf_nat_core.h>
 #include <net/netfilter/nf_nat_protocol.h>
+#include <net/netfilter/nf_nat_helper.h>
 #endif
 
 #include <linux/netfilter/nfnetlink.h>
@@ -477,7 +478,6 @@ nla_put_failure:
 	return -1;
 }
 
-#ifdef CONFIG_NF_CONNTRACK_EVENTS
 static inline size_t
 ctnetlink_proto_size(const struct nf_conn *ct)
 {
@@ -564,6 +564,7 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct)
 	       ;
 }
 
+#ifdef CONFIG_NF_CONNTRACK_EVENTS
 static int
 ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
 {
@@ -901,7 +902,8 @@ static const struct nla_policy help_nla_policy[CTA_HELP_MAX+1] = {
 };
 
 static inline int
-ctnetlink_parse_help(const struct nlattr *attr, char **helper_name)
+ctnetlink_parse_help(const struct nlattr *attr, char **helper_name,
+		     struct nlattr **helpinfo)
 {
 	struct nlattr *tb[CTA_HELP_MAX+1];
 
@@ -912,6 +914,9 @@ ctnetlink_parse_help(const struct nlattr *attr, char **helper_name)
 
 	*helper_name = nla_data(tb[CTA_HELP_NAME]);
 
+	if (tb[CTA_HELP_INFO])
+		*helpinfo = tb[CTA_HELP_INFO];
+
 	return 0;
 }
 
@@ -1172,13 +1177,14 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
 	struct nf_conntrack_helper *helper;
 	struct nf_conn_help *help = nfct_help(ct);
 	char *helpname = NULL;
+	struct nlattr *helpinfo = NULL;
 	int err;
 
 	/* don't change helper of sibling connections */
 	if (ct->master)
 		return -EBUSY;
 
-	err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
+	err = ctnetlink_parse_help(cda[CTA_HELP], &helpname, &helpinfo);
 	if (err < 0)
 		return err;
 
@@ -1213,20 +1219,17 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
 	}
 
 	if (help) {
-		if (help->helper == helper)
+		if (help->helper == helper) {
+			/* update private helper data if allowed. */
+			if (helper->from_nlattr && helpinfo)
+				helper->from_nlattr(helpinfo, ct);
 			return 0;
-		if (help->helper)
+		} else
 			return -EBUSY;
-		/* need to zero data of old helper */
-		memset(&help->help, 0, sizeof(help->help));
-	} else {
-		/* we cannot set a helper for an existing conntrack */
-		return -EOPNOTSUPP;
 	}
 
-	rcu_assign_pointer(help->helper, helper);
-
-	return 0;
+	/* we cannot set a helper for an existing conntrack */
+	return -EOPNOTSUPP;
 }
 
 static inline int
@@ -1410,8 +1413,9 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
 	rcu_read_lock();
  	if (cda[CTA_HELP]) {
 		char *helpname = NULL;
- 
- 		err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
+		struct nlattr *helpinfo = NULL;
+
+		err = ctnetlink_parse_help(cda[CTA_HELP], &helpname, &helpinfo);
  		if (err < 0)
 			goto err2;
 
@@ -1440,11 +1444,14 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
 		} else {
 			struct nf_conn_help *help;
 
-			help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
+			help = nf_ct_helper_ext_add(ct, helper, GFP_ATOMIC);
 			if (help == NULL) {
 				err = -ENOMEM;
 				goto err2;
 			}
+			/* set private helper data if allowed. */
+			if (helper->from_nlattr && helpinfo)
+				helper->from_nlattr(helpinfo, ct);
 
 			/* not in hash table yet so not strictly necessary */
 			RCU_INIT_POINTER(help->helper, helper);
@@ -1620,6 +1627,139 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
 	return err;
 }
 
+#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
+static size_t
+ctnetlink_nfqueue_build_size(const struct nf_conn *ct)
+{
+	return 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */
+	       + 3 * nla_total_size(0) /* CTA_TUPLE_IP */
+	       + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */
+	       + 3 * nla_total_size(sizeof(u_int8_t)) /* CTA_PROTO_NUM */
+	       + nla_total_size(sizeof(u_int32_t)) /* CTA_ID */
+	       + nla_total_size(sizeof(u_int32_t)) /* CTA_STATUS */
+	       + nla_total_size(sizeof(u_int32_t)) /* CTA_TIMEOUT */
+	       + nla_total_size(0) /* CTA_PROTOINFO */
+	       + nla_total_size(0) /* CTA_HELP */
+	       + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */
+	       + ctnetlink_secctx_size(ct)
+#ifdef CONFIG_NF_NAT_NEEDED
+	       + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */
+	       + 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */
+#endif
+#ifdef CONFIG_NF_CONNTRACK_MARK
+	       + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */
+#endif
+	       + ctnetlink_proto_size(ct)
+	       ;
+}
+
+static int
+ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct)
+{
+	struct nlattr *nest_parms;
+
+	rcu_read_lock();
+	nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);
+	if (!nest_parms)
+		goto nla_put_failure;
+	if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
+		goto nla_put_failure;
+	nla_nest_end(skb, nest_parms);
+
+	nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED);
+	if (!nest_parms)
+		goto nla_put_failure;
+	if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_REPLY)) < 0)
+		goto nla_put_failure;
+	nla_nest_end(skb, nest_parms);
+
+	if (nf_ct_zone(ct)) {
+		if (nla_put_be16(skb, CTA_ZONE, htons(nf_ct_zone(ct))))
+			goto nla_put_failure;
+	}
+
+	if (ctnetlink_dump_id(skb, ct) < 0)
+		goto nla_put_failure;
+
+	if (ctnetlink_dump_status(skb, ct) < 0)
+		goto nla_put_failure;
+
+	if (ctnetlink_dump_timeout(skb, ct) < 0)
+		goto nla_put_failure;
+
+	if (ctnetlink_dump_protoinfo(skb, ct) < 0)
+		goto nla_put_failure;
+
+	if (ctnetlink_dump_helpinfo(skb, ct) < 0)
+		goto nla_put_failure;
+
+#ifdef CONFIG_NF_CONNTRACK_SECMARK
+	if (ct->secmark && ctnetlink_dump_secctx(skb, ct) < 0)
+		goto nla_put_failure;
+#endif
+	if (ct->master && ctnetlink_dump_master(skb, ct) < 0)
+		goto nla_put_failure;
+
+	if ((ct->status & IPS_SEQ_ADJUST) &&
+	    ctnetlink_dump_nat_seq_adj(skb, ct) < 0)
+		goto nla_put_failure;
+
+#ifdef CONFIG_NF_CONNTRACK_MARK
+	if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0)
+		goto nla_put_failure;
+#endif
+	rcu_read_unlock();
+	return 0;
+
+nla_put_failure:
+	rcu_read_unlock();
+	return -ENOSPC;
+}
+
+static int
+ctnetlink_nfqueue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
+{
+	int err;
+
+	if (cda[CTA_TIMEOUT]) {
+		err = ctnetlink_change_timeout(ct, cda);
+		if (err < 0)
+			return err;
+	}
+	if (cda[CTA_STATUS]) {
+		err = ctnetlink_change_status(ct, cda);
+		if (err < 0)
+			return err;
+	}
+	if (cda[CTA_HELP]) {
+		err = ctnetlink_change_helper(ct, cda);
+		if (err < 0)
+			return err;
+	}
+#if defined(CONFIG_NF_CONNTRACK_MARK)
+	if (cda[CTA_MARK])
+		ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
+#endif
+	return 0;
+}
+
+static int
+ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
+{
+	struct nlattr *cda[CTA_MAX+1];
+
+	nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy);
+
+	return ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct);
+}
+
+static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
+	.build_size	= ctnetlink_nfqueue_build_size,
+	.build		= ctnetlink_nfqueue_build,
+	.parse		= ctnetlink_nfqueue_parse,
+};
+#endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */
+
 /***********************************************************************
  * EXPECT
  ***********************************************************************/
@@ -2424,7 +2564,10 @@ static int __init ctnetlink_init(void)
 		pr_err("ctnetlink_init: cannot register pernet operations\n");
 		goto err_unreg_exp_subsys;
 	}
-
+#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
+	/* setup interaction between nf_queue and nf_conntrack_netlink. */
+	RCU_INIT_POINTER(nfq_ct_hook, &ctnetlink_nfqueue_hook);
+#endif
 	return 0;
 
 err_unreg_exp_subsys:
@@ -2442,6 +2585,9 @@ static void __exit ctnetlink_exit(void)
 	unregister_pernet_subsys(&ctnetlink_net_ops);
 	nfnetlink_subsys_unregister(&ctnl_exp_subsys);
 	nfnetlink_subsys_unregister(&ctnl_subsys);
+#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
+	RCU_INIT_POINTER(nfq_ct_hook, NULL);
+#endif
 }
 
 module_init(ctnetlink_init);
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 31d56b2..6fed9ec 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -174,7 +174,7 @@ static int destroy_sibling_or_exp(struct net *net, struct nf_conn *ct,
 static void pptp_destroy_siblings(struct nf_conn *ct)
 {
 	struct net *net = nf_ct_net(ct);
-	const struct nf_conn_help *help = nfct_help(ct);
+	const struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct);
 	struct nf_conntrack_tuple t;
 
 	nf_ct_gre_keymap_destroy(ct);
@@ -182,16 +182,16 @@ static void pptp_destroy_siblings(struct nf_conn *ct)
 	/* try original (pns->pac) tuple */
 	memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t));
 	t.dst.protonum = IPPROTO_GRE;
-	t.src.u.gre.key = help->help.ct_pptp_info.pns_call_id;
-	t.dst.u.gre.key = help->help.ct_pptp_info.pac_call_id;
+	t.src.u.gre.key = ct_pptp_info->pns_call_id;
+	t.dst.u.gre.key = ct_pptp_info->pac_call_id;
 	if (!destroy_sibling_or_exp(net, ct, &t))
 		pr_debug("failed to timeout original pns->pac ct/exp\n");
 
 	/* try reply (pac->pns) tuple */
 	memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t));
 	t.dst.protonum = IPPROTO_GRE;
-	t.src.u.gre.key = help->help.ct_pptp_info.pac_call_id;
-	t.dst.u.gre.key = help->help.ct_pptp_info.pns_call_id;
+	t.src.u.gre.key = ct_pptp_info->pac_call_id;
+	t.dst.u.gre.key = ct_pptp_info->pns_call_id;
 	if (!destroy_sibling_or_exp(net, ct, &t))
 		pr_debug("failed to timeout reply pac->pns ct/exp\n");
 }
@@ -269,7 +269,7 @@ pptp_inbound_pkt(struct sk_buff *skb,
 		 struct nf_conn *ct,
 		 enum ip_conntrack_info ctinfo)
 {
-	struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info;
+	struct nf_ct_pptp_master *info = nfct_help_data(ct);
 	u_int16_t msg;
 	__be16 cid = 0, pcid = 0;
 	typeof(nf_nat_pptp_hook_inbound) nf_nat_pptp_inbound;
@@ -396,7 +396,7 @@ pptp_outbound_pkt(struct sk_buff *skb,
 		  struct nf_conn *ct,
 		  enum ip_conntrack_info ctinfo)
 {
-	struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info;
+	struct nf_ct_pptp_master *info = nfct_help_data(ct);
 	u_int16_t msg;
 	__be16 cid = 0, pcid = 0;
 	typeof(nf_nat_pptp_hook_outbound) nf_nat_pptp_outbound;
@@ -506,7 +506,7 @@ conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff,
 
 {
 	int dir = CTINFO2DIR(ctinfo);
-	const struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info;
+	const struct nf_ct_pptp_master *info = nfct_help_data(ct);
 	const struct tcphdr *tcph;
 	struct tcphdr _tcph;
 	const struct pptp_pkt_hdr *pptph;
@@ -592,6 +592,7 @@ static const struct nf_conntrack_expect_policy pptp_exp_policy = {
 static struct nf_conntrack_helper pptp __read_mostly = {
 	.name			= "pptp",
 	.me			= THIS_MODULE,
+	.data_len		= sizeof(struct nf_ct_pptp_master),
 	.tuple.src.l3num	= AF_INET,
 	.tuple.src.u.tcp.port	= cpu_to_be16(PPTP_CONTROL_PORT),
 	.tuple.dst.protonum	= IPPROTO_TCP,
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 8b631b0..1ea9194 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -36,28 +36,35 @@ static DEFINE_MUTEX(nf_ct_proto_mutex);
 
 #ifdef CONFIG_SYSCTL
 static int
-nf_ct_register_sysctl(struct ctl_table_header **header, const char *path,
-		      struct ctl_table *table, unsigned int *users)
+nf_ct_register_sysctl(struct net *net,
+		      struct ctl_table_header **header,
+		      const char *path,
+		      struct ctl_table *table,
+		      unsigned int *users)
 {
 	if (*header == NULL) {
-		*header = register_net_sysctl(&init_net, path, table);
+		*header = register_net_sysctl(net, path, table);
 		if (*header == NULL)
 			return -ENOMEM;
 	}
 	if (users != NULL)
 		(*users)++;
+
 	return 0;
 }
 
 static void
 nf_ct_unregister_sysctl(struct ctl_table_header **header,
-			struct ctl_table *table, unsigned int *users)
+			struct ctl_table **table,
+			unsigned int *users)
 {
 	if (users != NULL && --*users > 0)
 		return;
 
 	unregister_net_sysctl_table(*header);
+	kfree(*table);
 	*header = NULL;
+	*table = NULL;
 }
 #endif
 
@@ -161,30 +168,57 @@ static int kill_l4proto(struct nf_conn *i, void *data)
 	       nf_ct_l3num(i) == l4proto->l3proto;
 }
 
-static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto)
+static struct nf_ip_net *nf_ct_l3proto_net(struct net *net,
+					   struct nf_conntrack_l3proto *l3proto)
 {
-	int err = 0;
+	if (l3proto->l3proto == PF_INET)
+		return &net->ct.nf_ct_proto;
+	else
+		return NULL;
+}
 
-#ifdef CONFIG_SYSCTL
-	if (l3proto->ctl_table != NULL) {
-		err = nf_ct_register_sysctl(&l3proto->ctl_table_header,
+static int nf_ct_l3proto_register_sysctl(struct net *net,
+					 struct nf_conntrack_l3proto *l3proto)
+{
+	int err = 0;
+	struct nf_ip_net *in = nf_ct_l3proto_net(net, l3proto);
+	/* nf_conntrack_l3proto_ipv6 doesn't support sysctl */
+	if (in == NULL)
+		return 0;
+
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+	if (in->ctl_table != NULL) {
+		err = nf_ct_register_sysctl(net,
+					    &in->ctl_table_header,
 					    l3proto->ctl_table_path,
-					    l3proto->ctl_table, NULL);
+					    in->ctl_table,
+					    NULL);
+		if (err < 0) {
+			kfree(in->ctl_table);
+			in->ctl_table = NULL;
+		}
 	}
 #endif
 	return err;
 }
 
-static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto)
+static void nf_ct_l3proto_unregister_sysctl(struct net *net,
+					    struct nf_conntrack_l3proto *l3proto)
 {
-#ifdef CONFIG_SYSCTL
-	if (l3proto->ctl_table_header != NULL)
-		nf_ct_unregister_sysctl(&l3proto->ctl_table_header,
-					l3proto->ctl_table, NULL);
+	struct nf_ip_net *in = nf_ct_l3proto_net(net, l3proto);
+
+	if (in == NULL)
+		return;
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+	if (in->ctl_table_header != NULL)
+		nf_ct_unregister_sysctl(&in->ctl_table_header,
+					&in->ctl_table,
+					NULL);
 #endif
 }
 
-int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
+static int
+nf_conntrack_l3proto_register_net(struct nf_conntrack_l3proto *proto)
 {
 	int ret = 0;
 	struct nf_conntrack_l3proto *old;
@@ -203,10 +237,6 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
 		goto out_unlock;
 	}
 
-	ret = nf_ct_l3proto_register_sysctl(proto);
-	if (ret < 0)
-		goto out_unlock;
-
 	if (proto->nlattr_tuple_size)
 		proto->nla_size = 3 * proto->nlattr_tuple_size();
 
@@ -215,13 +245,32 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
 out_unlock:
 	mutex_unlock(&nf_ct_proto_mutex);
 	return ret;
+
 }
-EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register);
 
-void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
+int nf_conntrack_l3proto_register(struct net *net,
+				  struct nf_conntrack_l3proto *proto)
 {
-	struct net *net;
+	int ret = 0;
 
+	if (net == &init_net)
+		ret = nf_conntrack_l3proto_register_net(proto);
+
+	if (ret < 0)
+		return ret;
+
+	if (proto->init_net) {
+		ret = proto->init_net(net);
+		if (ret < 0)
+			return ret;
+	}
+	return nf_ct_l3proto_register_sysctl(net, proto);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register);
+
+static void
+nf_conntrack_l3proto_unregister_net(struct nf_conntrack_l3proto *proto)
+{
 	BUG_ON(proto->l3proto >= AF_MAX);
 
 	mutex_lock(&nf_ct_proto_mutex);
@@ -230,42 +279,88 @@ void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
 					 ) != proto);
 	rcu_assign_pointer(nf_ct_l3protos[proto->l3proto],
 			   &nf_conntrack_l3proto_generic);
-	nf_ct_l3proto_unregister_sysctl(proto);
 	mutex_unlock(&nf_ct_proto_mutex);
 
 	synchronize_rcu();
+}
+
+void nf_conntrack_l3proto_unregister(struct net *net,
+				     struct nf_conntrack_l3proto *proto)
+{
+	if (net == &init_net)
+		nf_conntrack_l3proto_unregister_net(proto);
+
+	nf_ct_l3proto_unregister_sysctl(net, proto);
 
 	/* Remove all contrack entries for this protocol */
 	rtnl_lock();
-	for_each_net(net)
-		nf_ct_iterate_cleanup(net, kill_l3proto, proto);
+	nf_ct_iterate_cleanup(net, kill_l3proto, proto);
 	rtnl_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
 
-static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto)
+static struct nf_proto_net *nf_ct_l4proto_net(struct net *net,
+					      struct nf_conntrack_l4proto *l4proto)
+{
+	switch (l4proto->l4proto) {
+	case IPPROTO_TCP:
+		return (struct nf_proto_net *)&net->ct.nf_ct_proto.tcp;
+	case IPPROTO_UDP:
+		return (struct nf_proto_net *)&net->ct.nf_ct_proto.udp;
+	case IPPROTO_ICMP:
+		return (struct nf_proto_net *)&net->ct.nf_ct_proto.icmp;
+	case IPPROTO_ICMPV6:
+		return (struct nf_proto_net *)&net->ct.nf_ct_proto.icmpv6;
+	case 255: /* l4proto_generic */
+		return (struct nf_proto_net *)&net->ct.nf_ct_proto.generic;
+	default:
+		if (l4proto->net_id)
+			return net_generic(net, *l4proto->net_id);
+		else
+			return NULL;
+	}
+	return NULL;
+}
+
+static
+int nf_ct_l4proto_register_sysctl(struct net *net,
+				  struct nf_conntrack_l4proto *l4proto)
 {
 	int err = 0;
+	struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
+	if (pn == NULL)
+		return 0;
 
 #ifdef CONFIG_SYSCTL
-	if (l4proto->ctl_table != NULL) {
-		err = nf_ct_register_sysctl(l4proto->ctl_table_header,
+	if (pn->ctl_table != NULL) {
+		err = nf_ct_register_sysctl(net,
+					    &pn->ctl_table_header,
 					    "net/netfilter",
-					    l4proto->ctl_table,
-					    l4proto->ctl_table_users);
-		if (err < 0)
+					    pn->ctl_table,
+					    &pn->users);
+		if (err < 0) {
+			if (!pn->users) {
+				kfree(pn->ctl_table);
+				pn->ctl_table = NULL;
+			}
 			goto out;
+		}
 	}
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-	if (l4proto->ctl_compat_table != NULL) {
-		err = nf_ct_register_sysctl(&l4proto->ctl_compat_table_header,
+	if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_table != NULL) {
+		err = nf_ct_register_sysctl(net,
+					    &pn->ctl_compat_header,
 					    "net/ipv4/netfilter",
-					    l4proto->ctl_compat_table, NULL);
+					    pn->ctl_compat_table,
+					    NULL);
 		if (err == 0)
 			goto out;
-		nf_ct_unregister_sysctl(l4proto->ctl_table_header,
-					l4proto->ctl_table,
-					l4proto->ctl_table_users);
+
+		kfree(pn->ctl_compat_table);
+		pn->ctl_compat_table = NULL;
+		nf_ct_unregister_sysctl(&pn->ctl_table_header,
+					&pn->ctl_table,
+					&pn->users);
 	}
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 out:
@@ -273,25 +368,34 @@ out:
 	return err;
 }
 
-static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto)
+static
+void nf_ct_l4proto_unregister_sysctl(struct net *net,
+				     struct nf_conntrack_l4proto *l4proto)
 {
+	struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
+	if (pn == NULL)
+		return;
 #ifdef CONFIG_SYSCTL
-	if (l4proto->ctl_table_header != NULL &&
-	    *l4proto->ctl_table_header != NULL)
-		nf_ct_unregister_sysctl(l4proto->ctl_table_header,
-					l4proto->ctl_table,
-					l4proto->ctl_table_users);
+	if (pn->ctl_table_header != NULL)
+		nf_ct_unregister_sysctl(&pn->ctl_table_header,
+					&pn->ctl_table,
+					&pn->users);
+
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-	if (l4proto->ctl_compat_table_header != NULL)
-		nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header,
-					l4proto->ctl_compat_table, NULL);
+	if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_header != NULL)
+		nf_ct_unregister_sysctl(&pn->ctl_compat_header,
+					&pn->ctl_compat_table,
+					NULL);
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
+#else
+	pn->users--;
 #endif /* CONFIG_SYSCTL */
 }
 
 /* FIXME: Allow NULL functions and sub in pointers to generic for
    them. --RR */
-int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
+static int
+nf_conntrack_l4proto_register_net(struct nf_conntrack_l4proto *l4proto)
 {
 	int ret = 0;
 
@@ -333,10 +437,6 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
 		goto out_unlock;
 	}
 
-	ret = nf_ct_l4proto_register_sysctl(l4proto);
-	if (ret < 0)
-		goto out_unlock;
-
 	l4proto->nla_size = 0;
 	if (l4proto->nlattr_size)
 		l4proto->nla_size += l4proto->nlattr_size();
@@ -345,17 +445,34 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
 
 	rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
 			   l4proto);
-
 out_unlock:
 	mutex_unlock(&nf_ct_proto_mutex);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
 
-void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
+int nf_conntrack_l4proto_register(struct net *net,
+				  struct nf_conntrack_l4proto *l4proto)
 {
-	struct net *net;
+	int ret = 0;
+	if (net == &init_net)
+		ret = nf_conntrack_l4proto_register_net(l4proto);
+
+	if (ret < 0)
+		return ret;
+
+	if (l4proto->init_net)
+		ret = l4proto->init_net(net);
+
+	if (ret < 0)
+		return ret;
+
+	return nf_ct_l4proto_register_sysctl(net, l4proto);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
 
+static void
+nf_conntrack_l4proto_unregister_net(struct nf_conntrack_l4proto *l4proto)
+{
 	BUG_ON(l4proto->l3proto >= PF_MAX);
 
 	mutex_lock(&nf_ct_proto_mutex);
@@ -365,41 +482,53 @@ void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
 			) != l4proto);
 	rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
 			   &nf_conntrack_l4proto_generic);
-	nf_ct_l4proto_unregister_sysctl(l4proto);
 	mutex_unlock(&nf_ct_proto_mutex);
 
 	synchronize_rcu();
+}
+
+void nf_conntrack_l4proto_unregister(struct net *net,
+				     struct nf_conntrack_l4proto *l4proto)
+{
+	if (net == &init_net)
+		nf_conntrack_l4proto_unregister_net(l4proto);
 
+	nf_ct_l4proto_unregister_sysctl(net, l4proto);
 	/* Remove all contrack entries for this protocol */
 	rtnl_lock();
-	for_each_net(net)
-		nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
+	nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
 	rtnl_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister);
 
-int nf_conntrack_proto_init(void)
+int nf_conntrack_proto_init(struct net *net)
 {
 	unsigned int i;
 	int err;
-
-	err = nf_ct_l4proto_register_sysctl(&nf_conntrack_l4proto_generic);
+	err = nf_conntrack_l4proto_generic.init_net(net);
+	if (err < 0)
+		return err;
+	err = nf_ct_l4proto_register_sysctl(net,
+					    &nf_conntrack_l4proto_generic);
 	if (err < 0)
 		return err;
 
-	for (i = 0; i < AF_MAX; i++)
-		rcu_assign_pointer(nf_ct_l3protos[i],
-				   &nf_conntrack_l3proto_generic);
+	if (net == &init_net) {
+		for (i = 0; i < AF_MAX; i++)
+			rcu_assign_pointer(nf_ct_l3protos[i],
+					   &nf_conntrack_l3proto_generic);
+	}
 	return 0;
 }
 
-void nf_conntrack_proto_fini(void)
+void nf_conntrack_proto_fini(struct net *net)
 {
 	unsigned int i;
-
-	nf_ct_l4proto_unregister_sysctl(&nf_conntrack_l4proto_generic);
-
-	/* free l3proto protocol tables */
-	for (i = 0; i < PF_MAX; i++)
-		kfree(nf_ct_protos[i]);
+	nf_ct_l4proto_unregister_sysctl(net,
+					&nf_conntrack_l4proto_generic);
+	if (net == &init_net) {
+		/* free l3proto protocol tables */
+		for (i = 0; i < PF_MAX; i++)
+			kfree(nf_ct_protos[i]);
+	}
 }
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index ef706a4..c33f76a 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -387,12 +387,9 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
 /* this module per-net specifics */
 static int dccp_net_id __read_mostly;
 struct dccp_net {
+	struct nf_proto_net np;
 	int dccp_loose;
 	unsigned int dccp_timeout[CT_DCCP_MAX + 1];
-#ifdef CONFIG_SYSCTL
-	struct ctl_table_header *sysctl_header;
-	struct ctl_table *sysctl_table;
-#endif
 };
 
 static inline struct dccp_net *dccp_pernet(struct net *net)
@@ -715,9 +712,10 @@ static int dccp_nlattr_size(void)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[],
+				      struct net *net, void *data)
 {
-	struct dccp_net *dn = dccp_pernet(&init_net);
+	struct dccp_net *dn = dccp_pernet(net);
 	unsigned int *timeouts = data;
 	int i;
 
@@ -817,6 +815,45 @@ static struct ctl_table dccp_sysctl_table[] = {
 };
 #endif /* CONFIG_SYSCTL */
 
+static int dccp_init_net(struct net *net)
+{
+	struct dccp_net *dn = dccp_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)dn;
+
+#ifdef CONFIG_SYSCTL
+	if (!pn->ctl_table) {
+#else
+	if (!pn->users++) {
+#endif
+		/* default values */
+		dn->dccp_loose = 1;
+		dn->dccp_timeout[CT_DCCP_REQUEST]	= 2 * DCCP_MSL;
+		dn->dccp_timeout[CT_DCCP_RESPOND]	= 4 * DCCP_MSL;
+		dn->dccp_timeout[CT_DCCP_PARTOPEN]	= 4 * DCCP_MSL;
+		dn->dccp_timeout[CT_DCCP_OPEN]		= 12 * 3600 * HZ;
+		dn->dccp_timeout[CT_DCCP_CLOSEREQ]	= 64 * HZ;
+		dn->dccp_timeout[CT_DCCP_CLOSING]	= 64 * HZ;
+		dn->dccp_timeout[CT_DCCP_TIMEWAIT]	= 2 * DCCP_MSL;
+#ifdef CONFIG_SYSCTL
+		pn->ctl_table = kmemdup(dccp_sysctl_table,
+					sizeof(dccp_sysctl_table),
+					GFP_KERNEL);
+		if (!pn->ctl_table)
+			return -ENOMEM;
+
+		pn->ctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
+		pn->ctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
+		pn->ctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
+		pn->ctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
+		pn->ctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
+		pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
+		pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
+		pn->ctl_table[7].data = &dn->dccp_loose;
+#endif
+	}
+	return 0;
+}
+
 static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
 	.l3proto		= AF_INET,
 	.l4proto		= IPPROTO_DCCP,
@@ -847,6 +884,8 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
 		.nla_policy	= dccp_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+	.net_id			= &dccp_net_id,
+	.init_net		= dccp_init_net,
 };
 
 static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
@@ -879,55 +918,39 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
 		.nla_policy	= dccp_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+	.net_id			= &dccp_net_id,
+	.init_net		= dccp_init_net,
 };
 
 static __net_init int dccp_net_init(struct net *net)
 {
-	struct dccp_net *dn = dccp_pernet(net);
-
-	/* default values */
-	dn->dccp_loose = 1;
-	dn->dccp_timeout[CT_DCCP_REQUEST]	= 2 * DCCP_MSL;
-	dn->dccp_timeout[CT_DCCP_RESPOND]	= 4 * DCCP_MSL;
-	dn->dccp_timeout[CT_DCCP_PARTOPEN]	= 4 * DCCP_MSL;
-	dn->dccp_timeout[CT_DCCP_OPEN]		= 12 * 3600 * HZ;
-	dn->dccp_timeout[CT_DCCP_CLOSEREQ]	= 64 * HZ;
-	dn->dccp_timeout[CT_DCCP_CLOSING]	= 64 * HZ;
-	dn->dccp_timeout[CT_DCCP_TIMEWAIT]	= 2 * DCCP_MSL;
-
-#ifdef CONFIG_SYSCTL
-	dn->sysctl_table = kmemdup(dccp_sysctl_table,
-			sizeof(dccp_sysctl_table), GFP_KERNEL);
-	if (!dn->sysctl_table)
-		return -ENOMEM;
-
-	dn->sysctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
-	dn->sysctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
-	dn->sysctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
-	dn->sysctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
-	dn->sysctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
-	dn->sysctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
-	dn->sysctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
-	dn->sysctl_table[7].data = &dn->dccp_loose;
-
-	dn->sysctl_header = register_net_sysctl(net, "net/netfilter",
-						dn->sysctl_table);
-	if (!dn->sysctl_header) {
-		kfree(dn->sysctl_table);
-		return -ENOMEM;
+	int ret = 0;
+	ret = nf_conntrack_l4proto_register(net,
+					    &dccp_proto4);
+	if (ret < 0) {
+		pr_err("nf_conntrack_l4proto_dccp4 :protocol register failed.\n");
+		goto out;
+	}
+	ret = nf_conntrack_l4proto_register(net,
+					    &dccp_proto6);
+	if (ret < 0) {
+		pr_err("nf_conntrack_l4proto_dccp6 :protocol register failed.\n");
+		goto cleanup_dccp4;
 	}
-#endif
-
 	return 0;
+cleanup_dccp4:
+	nf_conntrack_l4proto_unregister(net,
+					&dccp_proto4);
+out:
+	return ret;
 }
 
 static __net_exit void dccp_net_exit(struct net *net)
 {
-	struct dccp_net *dn = dccp_pernet(net);
-#ifdef CONFIG_SYSCTL
-	unregister_net_sysctl_table(dn->sysctl_header);
-	kfree(dn->sysctl_table);
-#endif
+	nf_conntrack_l4proto_unregister(net,
+					&dccp_proto6);
+	nf_conntrack_l4proto_unregister(net,
+					&dccp_proto4);
 }
 
 static struct pernet_operations dccp_net_ops = {
@@ -939,34 +962,12 @@ static struct pernet_operations dccp_net_ops = {
 
 static int __init nf_conntrack_proto_dccp_init(void)
 {
-	int err;
-
-	err = register_pernet_subsys(&dccp_net_ops);
-	if (err < 0)
-		goto err1;
-
-	err = nf_conntrack_l4proto_register(&dccp_proto4);
-	if (err < 0)
-		goto err2;
-
-	err = nf_conntrack_l4proto_register(&dccp_proto6);
-	if (err < 0)
-		goto err3;
-	return 0;
-
-err3:
-	nf_conntrack_l4proto_unregister(&dccp_proto4);
-err2:
-	unregister_pernet_subsys(&dccp_net_ops);
-err1:
-	return err;
+	return register_pernet_subsys(&dccp_net_ops);
 }
 
 static void __exit nf_conntrack_proto_dccp_fini(void)
 {
 	unregister_pernet_subsys(&dccp_net_ops);
-	nf_conntrack_l4proto_unregister(&dccp_proto6);
-	nf_conntrack_l4proto_unregister(&dccp_proto4);
 }
 
 module_init(nf_conntrack_proto_dccp_init);
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index d8923d5..bb0e74f 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -14,6 +14,11 @@
 
 static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ;
 
+static inline struct nf_generic_net *generic_pernet(struct net *net)
+{
+	return &net->ct.nf_ct_proto.generic;
+}
+
 static bool generic_pkt_to_tuple(const struct sk_buff *skb,
 				 unsigned int dataoff,
 				 struct nf_conntrack_tuple *tuple)
@@ -42,7 +47,7 @@ static int generic_print_tuple(struct seq_file *s,
 
 static unsigned int *generic_get_timeouts(struct net *net)
 {
-	return &nf_ct_generic_timeout;
+	return &(generic_pernet(net)->timeout);
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
@@ -70,16 +75,18 @@ static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb,
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int generic_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int generic_timeout_nlattr_to_obj(struct nlattr *tb[],
+					 struct net *net, void *data)
 {
 	unsigned int *timeout = data;
+	struct nf_generic_net *gn = generic_pernet(net);
 
 	if (tb[CTA_TIMEOUT_GENERIC_TIMEOUT])
 		*timeout =
 		    ntohl(nla_get_be32(tb[CTA_TIMEOUT_GENERIC_TIMEOUT])) * HZ;
 	else {
 		/* Set default generic timeout. */
-		*timeout = nf_ct_generic_timeout;
+		*timeout = gn->timeout;
 	}
 
 	return 0;
@@ -106,11 +113,9 @@ generic_timeout_nla_policy[CTA_TIMEOUT_GENERIC_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table_header *generic_sysctl_header;
 static struct ctl_table generic_sysctl_table[] = {
 	{
 		.procname	= "nf_conntrack_generic_timeout",
-		.data		= &nf_ct_generic_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -121,7 +126,6 @@ static struct ctl_table generic_sysctl_table[] = {
 static struct ctl_table generic_compat_sysctl_table[] = {
 	{
 		.procname	= "ip_conntrack_generic_timeout",
-		.data		= &nf_ct_generic_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -131,6 +135,34 @@ static struct ctl_table generic_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
 
+static int generic_init_net(struct net *net)
+{
+	struct nf_generic_net *gn = generic_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)gn;
+	gn->timeout = nf_ct_generic_timeout;
+#ifdef CONFIG_SYSCTL
+	pn->ctl_table = kmemdup(generic_sysctl_table,
+				sizeof(generic_sysctl_table),
+				GFP_KERNEL);
+	if (!pn->ctl_table)
+		return -ENOMEM;
+	pn->ctl_table[0].data = &gn->timeout;
+
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+	pn->ctl_compat_table = kmemdup(generic_compat_sysctl_table,
+				       sizeof(generic_compat_sysctl_table),
+				       GFP_KERNEL);
+	if (!pn->ctl_compat_table) {
+		kfree(pn->ctl_table);
+		pn->ctl_table = NULL;
+		return -ENOMEM;
+	}
+	pn->ctl_compat_table[0].data = &gn->timeout;
+#endif
+#endif
+	return 0;
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
 {
 	.l3proto		= PF_UNSPEC,
@@ -151,11 +183,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
 		.nla_policy	= generic_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-	.ctl_table_header	= &generic_sysctl_header,
-	.ctl_table		= generic_sysctl_table,
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-	.ctl_compat_table	= generic_compat_sysctl_table,
-#endif
-#endif
+	.init_net		= generic_init_net,
 };
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 4bf6b4e..5cac41c 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -54,13 +54,20 @@ static unsigned int gre_timeouts[GRE_CT_MAX] = {
 
 static int proto_gre_net_id __read_mostly;
 struct netns_proto_gre {
+	struct nf_proto_net	nf;
 	rwlock_t		keymap_lock;
 	struct list_head	keymap_list;
+	unsigned int		gre_timeouts[GRE_CT_MAX];
 };
 
+static inline struct netns_proto_gre *gre_pernet(struct net *net)
+{
+	return net_generic(net, proto_gre_net_id);
+}
+
 void nf_ct_gre_keymap_flush(struct net *net)
 {
-	struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
+	struct netns_proto_gre *net_gre = gre_pernet(net);
 	struct nf_ct_gre_keymap *km, *tmp;
 
 	write_lock_bh(&net_gre->keymap_lock);
@@ -85,7 +92,7 @@ static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km,
 /* look up the source key for a given tuple */
 static __be16 gre_keymap_lookup(struct net *net, struct nf_conntrack_tuple *t)
 {
-	struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
+	struct netns_proto_gre *net_gre = gre_pernet(net);
 	struct nf_ct_gre_keymap *km;
 	__be16 key = 0;
 
@@ -109,11 +116,11 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
 			 struct nf_conntrack_tuple *t)
 {
 	struct net *net = nf_ct_net(ct);
-	struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
-	struct nf_conn_help *help = nfct_help(ct);
+	struct netns_proto_gre *net_gre = gre_pernet(net);
+	struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct);
 	struct nf_ct_gre_keymap **kmp, *km;
 
-	kmp = &help->help.ct_pptp_info.keymap[dir];
+	kmp = &ct_pptp_info->keymap[dir];
 	if (*kmp) {
 		/* check whether it's a retransmission */
 		read_lock_bh(&net_gre->keymap_lock);
@@ -150,20 +157,20 @@ EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_add);
 void nf_ct_gre_keymap_destroy(struct nf_conn *ct)
 {
 	struct net *net = nf_ct_net(ct);
-	struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
-	struct nf_conn_help *help = nfct_help(ct);
+	struct netns_proto_gre *net_gre = gre_pernet(net);
+	struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct);
 	enum ip_conntrack_dir dir;
 
 	pr_debug("entering for ct %p\n", ct);
 
 	write_lock_bh(&net_gre->keymap_lock);
 	for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) {
-		if (help->help.ct_pptp_info.keymap[dir]) {
+		if (ct_pptp_info->keymap[dir]) {
 			pr_debug("removing %p from list\n",
-				 help->help.ct_pptp_info.keymap[dir]);
-			list_del(&help->help.ct_pptp_info.keymap[dir]->list);
-			kfree(help->help.ct_pptp_info.keymap[dir]);
-			help->help.ct_pptp_info.keymap[dir] = NULL;
+				 ct_pptp_info->keymap[dir]);
+			list_del(&ct_pptp_info->keymap[dir]->list);
+			kfree(ct_pptp_info->keymap[dir]);
+			ct_pptp_info->keymap[dir] = NULL;
 		}
 	}
 	write_unlock_bh(&net_gre->keymap_lock);
@@ -237,7 +244,7 @@ static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct)
 
 static unsigned int *gre_get_timeouts(struct net *net)
 {
-	return gre_timeouts;
+	return gre_pernet(net)->gre_timeouts;
 }
 
 /* Returns verdict for packet, and may modify conntrack */
@@ -297,13 +304,15 @@ static void gre_destroy(struct nf_conn *ct)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int gre_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int gre_timeout_nlattr_to_obj(struct nlattr *tb[],
+				     struct net *net, void *data)
 {
 	unsigned int *timeouts = data;
+	struct netns_proto_gre *net_gre = gre_pernet(net);
 
 	/* set default timeouts for GRE. */
-	timeouts[GRE_CT_UNREPLIED] = gre_timeouts[GRE_CT_UNREPLIED];
-	timeouts[GRE_CT_REPLIED] = gre_timeouts[GRE_CT_REPLIED];
+	timeouts[GRE_CT_UNREPLIED] = net_gre->gre_timeouts[GRE_CT_UNREPLIED];
+	timeouts[GRE_CT_REPLIED] = net_gre->gre_timeouts[GRE_CT_REPLIED];
 
 	if (tb[CTA_TIMEOUT_GRE_UNREPLIED]) {
 		timeouts[GRE_CT_UNREPLIED] =
@@ -339,6 +348,19 @@ gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = {
 };
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
+static int gre_init_net(struct net *net)
+{
+	struct netns_proto_gre *net_gre = gre_pernet(net);
+	int i;
+
+	rwlock_init(&net_gre->keymap_lock);
+	INIT_LIST_HEAD(&net_gre->keymap_list);
+	for (i = 0; i < GRE_CT_MAX; i++)
+		net_gre->gre_timeouts[i] = gre_timeouts[i];
+
+	return 0;
+}
+
 /* protocol helper struct */
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
 	.l3proto	 = AF_INET,
@@ -368,20 +390,22 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
 		.nla_policy	= gre_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+	.net_id		= &proto_gre_net_id,
+	.init_net	= gre_init_net,
 };
 
 static int proto_gre_net_init(struct net *net)
 {
-	struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
-
-	rwlock_init(&net_gre->keymap_lock);
-	INIT_LIST_HEAD(&net_gre->keymap_list);
-
-	return 0;
+	int ret = 0;
+	ret = nf_conntrack_l4proto_register(net, &nf_conntrack_l4proto_gre4);
+	if (ret < 0)
+		pr_err("nf_conntrack_l4proto_gre4 :protocol register failed.\n");
+	return ret;
 }
 
 static void proto_gre_net_exit(struct net *net)
 {
+	nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_gre4);
 	nf_ct_gre_keymap_flush(net);
 }
 
@@ -394,20 +418,11 @@ static struct pernet_operations proto_gre_net_ops = {
 
 static int __init nf_ct_proto_gre_init(void)
 {
-	int rv;
-
-	rv = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4);
-	if (rv < 0)
-		return rv;
-	rv = register_pernet_subsys(&proto_gre_net_ops);
-	if (rv < 0)
-		nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4);
-	return rv;
+	return register_pernet_subsys(&proto_gre_net_ops);
 }
 
 static void __exit nf_ct_proto_gre_fini(void)
 {
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4);
 	unregister_pernet_subsys(&proto_gre_net_ops);
 }
 
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 996db2f..8fb0582 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -127,6 +127,17 @@ static const u8 sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = {
 	}
 };
 
+static int sctp_net_id	__read_mostly;
+struct sctp_net {
+	struct nf_proto_net pn;
+	unsigned int timeouts[SCTP_CONNTRACK_MAX];
+};
+
+static inline struct sctp_net *sctp_pernet(struct net *net)
+{
+	return net_generic(net, sctp_net_id);
+}
+
 static bool sctp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
 			      struct nf_conntrack_tuple *tuple)
 {
@@ -281,7 +292,7 @@ static int sctp_new_state(enum ip_conntrack_dir dir,
 
 static unsigned int *sctp_get_timeouts(struct net *net)
 {
-	return sctp_timeouts;
+	return sctp_pernet(net)->timeouts;
 }
 
 /* Returns verdict for packet, or -NF_ACCEPT for invalid. */
@@ -551,14 +562,16 @@ static int sctp_nlattr_size(void)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[],
+				      struct net *net, void *data)
 {
 	unsigned int *timeouts = data;
+	struct sctp_net *sn = sctp_pernet(net);
 	int i;
 
 	/* set default SCTP timeouts. */
 	for (i=0; i<SCTP_CONNTRACK_MAX; i++)
-		timeouts[i] = sctp_timeouts[i];
+		timeouts[i] = sn->timeouts[i];
 
 	/* there's a 1:1 mapping between attributes and protocol states. */
 	for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) {
@@ -599,54 +612,45 @@ sctp_timeout_nla_policy[CTA_TIMEOUT_SCTP_MAX+1] = {
 
 
 #ifdef CONFIG_SYSCTL
-static unsigned int sctp_sysctl_table_users;
-static struct ctl_table_header *sctp_sysctl_header;
 static struct ctl_table sctp_sysctl_table[] = {
 	{
 		.procname	= "nf_conntrack_sctp_timeout_closed",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_CLOSED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_cookie_wait",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_COOKIE_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_cookie_echoed",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_COOKIE_ECHOED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_established",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_ESTABLISHED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_shutdown_sent",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_shutdown_recd",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_shutdown_ack_sent",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -658,49 +662,42 @@ static struct ctl_table sctp_sysctl_table[] = {
 static struct ctl_table sctp_compat_sysctl_table[] = {
 	{
 		.procname	= "ip_conntrack_sctp_timeout_closed",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_CLOSED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_cookie_wait",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_COOKIE_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_cookie_echoed",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_COOKIE_ECHOED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_established",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_ESTABLISHED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_shutdown_sent",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_shutdown_recd",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_shutdown_ack_sent",
-		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -710,6 +707,101 @@ static struct ctl_table sctp_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif
 
+static void sctp_init_net_data(struct sctp_net *sn)
+{
+	int i;
+#ifdef CONFIG_SYSCTL
+	if (!sn->pn.ctl_table) {
+#else
+	if (!sn->pn.users++) {
+#endif
+		for (i = 0; i < SCTP_CONNTRACK_MAX; i++)
+			sn->timeouts[i] = sctp_timeouts[i];
+	}
+}
+
+static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+	struct sctp_net *sn = (struct sctp_net *)pn;
+	if (pn->ctl_table)
+		return 0;
+
+	pn->ctl_table = kmemdup(sctp_sysctl_table,
+				sizeof(sctp_sysctl_table),
+				GFP_KERNEL);
+	if (!pn->ctl_table)
+		return -ENOMEM;
+
+	pn->ctl_table[0].data = &sn->timeouts[SCTP_CONNTRACK_CLOSED];
+	pn->ctl_table[1].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_WAIT];
+	pn->ctl_table[2].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_ECHOED];
+	pn->ctl_table[3].data = &sn->timeouts[SCTP_CONNTRACK_ESTABLISHED];
+	pn->ctl_table[4].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT];
+	pn->ctl_table[5].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD];
+	pn->ctl_table[6].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT];
+#endif
+	return 0;
+}
+
+static int sctp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+	struct sctp_net *sn = (struct sctp_net *)pn;
+	pn->ctl_compat_table = kmemdup(sctp_compat_sysctl_table,
+				       sizeof(sctp_compat_sysctl_table),
+				       GFP_KERNEL);
+	if (!pn->ctl_compat_table)
+		return -ENOMEM;
+
+	pn->ctl_compat_table[0].data = &sn->timeouts[SCTP_CONNTRACK_CLOSED];
+	pn->ctl_compat_table[1].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_WAIT];
+	pn->ctl_compat_table[2].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_ECHOED];
+	pn->ctl_compat_table[3].data = &sn->timeouts[SCTP_CONNTRACK_ESTABLISHED];
+	pn->ctl_compat_table[4].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT];
+	pn->ctl_compat_table[5].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD];
+	pn->ctl_compat_table[6].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT];
+#endif
+#endif
+	return 0;
+}
+
+static int sctpv4_init_net(struct net *net)
+{
+	int ret;
+	struct sctp_net *sn = sctp_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)sn;
+
+	sctp_init_net_data(sn);
+
+	ret = sctp_kmemdup_compat_sysctl_table(pn);
+	if (ret < 0)
+		return ret;
+
+	ret = sctp_kmemdup_sysctl_table(pn);
+
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+	if (ret < 0) {
+
+		kfree(pn->ctl_compat_table);
+		pn->ctl_compat_table = NULL;
+	}
+#endif
+#endif
+	return ret;
+}
+
+static int sctpv6_init_net(struct net *net)
+{
+	struct sctp_net *sn = sctp_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)sn;
+
+	sctp_init_net_data(sn);
+	return sctp_kmemdup_sysctl_table(pn);
+}
+
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
 	.l3proto		= PF_INET,
 	.l4proto 		= IPPROTO_SCTP,
@@ -740,14 +832,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
 		.nla_policy	= sctp_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-	.ctl_table_users	= &sctp_sysctl_table_users,
-	.ctl_table_header	= &sctp_sysctl_header,
-	.ctl_table		= sctp_sysctl_table,
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-	.ctl_compat_table	= sctp_compat_sysctl_table,
-#endif
-#endif
+	.net_id			= &sctp_net_id,
+	.init_net		= sctpv4_init_net,
 };
 
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
@@ -780,40 +866,58 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #endif
-#ifdef CONFIG_SYSCTL
-	.ctl_table_users	= &sctp_sysctl_table_users,
-	.ctl_table_header	= &sctp_sysctl_header,
-	.ctl_table		= sctp_sysctl_table,
-#endif
+	.net_id			= &sctp_net_id,
+	.init_net		= sctpv6_init_net,
 };
 
-static int __init nf_conntrack_proto_sctp_init(void)
+static int sctp_net_init(struct net *net)
 {
-	int ret;
+	int ret = 0;
 
-	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_sctp4);
-	if (ret) {
-		pr_err("nf_conntrack_l4proto_sctp4: protocol register failed\n");
+	ret = nf_conntrack_l4proto_register(net,
+					    &nf_conntrack_l4proto_sctp4);
+	if (ret < 0) {
+		pr_err("nf_conntrack_l4proto_sctp4 :protocol register failed.\n");
 		goto out;
 	}
-	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_sctp6);
-	if (ret) {
-		pr_err("nf_conntrack_l4proto_sctp6: protocol register failed\n");
+	ret = nf_conntrack_l4proto_register(net,
+					    &nf_conntrack_l4proto_sctp6);
+	if (ret < 0) {
+		pr_err("nf_conntrack_l4proto_sctp6 :protocol register failed.\n");
 		goto cleanup_sctp4;
 	}
+	return 0;
 
+cleanup_sctp4:
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_sctp4);
+out:
 	return ret;
+}
 
- cleanup_sctp4:
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp4);
- out:
-	return ret;
+static void sctp_net_exit(struct net *net)
+{
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_sctp6);
+	nf_conntrack_l4proto_unregister(net,
+					&nf_conntrack_l4proto_sctp4);
+}
+
+static struct pernet_operations sctp_net_ops = {
+	.init = sctp_net_init,
+	.exit = sctp_net_exit,
+	.id   = &sctp_net_id,
+	.size = sizeof(struct sctp_net),
+};
+
+static int __init nf_conntrack_proto_sctp_init(void)
+{
+	return register_pernet_subsys(&sctp_net_ops);
 }
 
 static void __exit nf_conntrack_proto_sctp_fini(void)
 {
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp6);
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp4);
+	unregister_pernet_subsys(&sctp_net_ops);
 }
 
 module_init(nf_conntrack_proto_sctp_init);
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 21ff1a9..99caa13 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -270,6 +270,11 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
 	}
 };
 
+static inline struct nf_tcp_net *tcp_pernet(struct net *net)
+{
+	return &net->ct.nf_ct_proto.tcp;
+}
+
 static bool tcp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
 			     struct nf_conntrack_tuple *tuple)
 {
@@ -516,6 +521,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
 			  u_int8_t pf)
 {
 	struct net *net = nf_ct_net(ct);
+	struct nf_tcp_net *tn = tcp_pernet(net);
 	struct ip_ct_tcp_state *sender = &state->seen[dir];
 	struct ip_ct_tcp_state *receiver = &state->seen[!dir];
 	const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
@@ -720,7 +726,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
 	} else {
 		res = false;
 		if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
-		    nf_ct_tcp_be_liberal)
+		    tn->tcp_be_liberal)
 			res = true;
 		if (!res && LOG_INVALID(net, IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
@@ -828,6 +834,7 @@ static int tcp_packet(struct nf_conn *ct,
 		      unsigned int *timeouts)
 {
 	struct net *net = nf_ct_net(ct);
+	struct nf_tcp_net *tn = tcp_pernet(net);
 	struct nf_conntrack_tuple *tuple;
 	enum tcp_conntrack new_state, old_state;
 	enum ip_conntrack_dir dir;
@@ -1020,7 +1027,7 @@ static int tcp_packet(struct nf_conn *ct,
 	    && new_state == TCP_CONNTRACK_FIN_WAIT)
 		ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
 
-	if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans &&
+	if (ct->proto.tcp.retrans >= tn->tcp_max_retrans &&
 	    timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS])
 		timeout = timeouts[TCP_CONNTRACK_RETRANS];
 	else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) &
@@ -1065,6 +1072,8 @@ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,
 	enum tcp_conntrack new_state;
 	const struct tcphdr *th;
 	struct tcphdr _tcph;
+	struct net *net = nf_ct_net(ct);
+	struct nf_tcp_net *tn = tcp_pernet(net);
 	const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0];
 	const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1];
 
@@ -1093,7 +1102,7 @@ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,
 			ct->proto.tcp.seen[0].td_end;
 
 		tcp_options(skb, dataoff, th, &ct->proto.tcp.seen[0]);
-	} else if (nf_ct_tcp_loose == 0) {
+	} else if (tn->tcp_loose == 0) {
 		/* Don't try to pick up connections. */
 		return false;
 	} else {
@@ -1251,14 +1260,16 @@ static int tcp_nlattr_tuple_size(void)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[],
+				     struct net *net, void *data)
 {
 	unsigned int *timeouts = data;
+	struct nf_tcp_net *tn = tcp_pernet(net);
 	int i;
 
 	/* set default TCP timeouts. */
 	for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++)
-		timeouts[i] = tcp_timeouts[i];
+		timeouts[i] = tn->timeouts[i];
 
 	if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) {
 		timeouts[TCP_CONNTRACK_SYN_SENT] =
@@ -1355,96 +1366,81 @@ static const struct nla_policy tcp_timeout_nla_policy[CTA_TIMEOUT_TCP_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static unsigned int tcp_sysctl_table_users;
-static struct ctl_table_header *tcp_sysctl_header;
 static struct ctl_table tcp_sysctl_table[] = {
 	{
 		.procname	= "nf_conntrack_tcp_timeout_syn_sent",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_SYN_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_syn_recv",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_SYN_RECV],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_established",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_ESTABLISHED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_fin_wait",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_FIN_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_close_wait",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_CLOSE_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_last_ack",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_LAST_ACK],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_time_wait",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_TIME_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_close",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_CLOSE],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_max_retrans",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_RETRANS],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_unacknowledged",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_UNACK],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_loose",
-		.data		= &nf_ct_tcp_loose,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname       = "nf_conntrack_tcp_be_liberal",
-		.data           = &nf_ct_tcp_be_liberal,
 		.maxlen         = sizeof(unsigned int),
 		.mode           = 0644,
 		.proc_handler   = proc_dointvec,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_max_retrans",
-		.data		= &nf_ct_tcp_max_retrans,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
@@ -1456,91 +1452,78 @@ static struct ctl_table tcp_sysctl_table[] = {
 static struct ctl_table tcp_compat_sysctl_table[] = {
 	{
 		.procname	= "ip_conntrack_tcp_timeout_syn_sent",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_SYN_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_syn_sent2",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_SYN_SENT2],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_syn_recv",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_SYN_RECV],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_established",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_ESTABLISHED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_fin_wait",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_FIN_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_close_wait",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_CLOSE_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_last_ack",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_LAST_ACK],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_time_wait",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_TIME_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_close",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_CLOSE],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_max_retrans",
-		.data		= &tcp_timeouts[TCP_CONNTRACK_RETRANS],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_loose",
-		.data		= &nf_ct_tcp_loose,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_be_liberal",
-		.data		= &nf_ct_tcp_be_liberal,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_max_retrans",
-		.data		= &nf_ct_tcp_max_retrans,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
@@ -1550,6 +1533,125 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
 
+static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+	struct nf_tcp_net *tn = (struct nf_tcp_net *)pn;
+
+	if (pn->ctl_table)
+		return 0;
+
+	pn->ctl_table = kmemdup(tcp_sysctl_table,
+				sizeof(tcp_sysctl_table),
+				GFP_KERNEL);
+	if (!pn->ctl_table)
+		return -ENOMEM;
+
+	pn->ctl_table[0].data = &tn->timeouts[TCP_CONNTRACK_SYN_SENT];
+	pn->ctl_table[1].data = &tn->timeouts[TCP_CONNTRACK_SYN_RECV];
+	pn->ctl_table[2].data = &tn->timeouts[TCP_CONNTRACK_ESTABLISHED];
+	pn->ctl_table[3].data = &tn->timeouts[TCP_CONNTRACK_FIN_WAIT];
+	pn->ctl_table[4].data = &tn->timeouts[TCP_CONNTRACK_CLOSE_WAIT];
+	pn->ctl_table[5].data = &tn->timeouts[TCP_CONNTRACK_LAST_ACK];
+	pn->ctl_table[6].data = &tn->timeouts[TCP_CONNTRACK_TIME_WAIT];
+	pn->ctl_table[7].data = &tn->timeouts[TCP_CONNTRACK_CLOSE];
+	pn->ctl_table[8].data = &tn->timeouts[TCP_CONNTRACK_RETRANS];
+	pn->ctl_table[9].data = &tn->timeouts[TCP_CONNTRACK_UNACK];
+	pn->ctl_table[10].data = &tn->tcp_loose;
+	pn->ctl_table[11].data = &tn->tcp_be_liberal;
+	pn->ctl_table[12].data = &tn->tcp_max_retrans;
+#endif
+	return 0;
+}
+
+static int tcp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+	struct nf_tcp_net *tn = (struct nf_tcp_net *)pn;
+	pn->ctl_compat_table = kmemdup(tcp_compat_sysctl_table,
+				       sizeof(tcp_compat_sysctl_table),
+				       GFP_KERNEL);
+	if (!pn->ctl_compat_table)
+		return -ENOMEM;
+
+	pn->ctl_compat_table[0].data = &tn->timeouts[TCP_CONNTRACK_SYN_SENT];
+	pn->ctl_compat_table[1].data = &tn->timeouts[TCP_CONNTRACK_SYN_SENT2];
+	pn->ctl_compat_table[2].data = &tn->timeouts[TCP_CONNTRACK_SYN_RECV];
+	pn->ctl_compat_table[3].data = &tn->timeouts[TCP_CONNTRACK_ESTABLISHED];
+	pn->ctl_compat_table[4].data = &tn->timeouts[TCP_CONNTRACK_FIN_WAIT];
+	pn->ctl_compat_table[5].data = &tn->timeouts[TCP_CONNTRACK_CLOSE_WAIT];
+	pn->ctl_compat_table[6].data = &tn->timeouts[TCP_CONNTRACK_LAST_ACK];
+	pn->ctl_compat_table[7].data = &tn->timeouts[TCP_CONNTRACK_TIME_WAIT];
+	pn->ctl_compat_table[8].data = &tn->timeouts[TCP_CONNTRACK_CLOSE];
+	pn->ctl_compat_table[9].data = &tn->timeouts[TCP_CONNTRACK_RETRANS];
+	pn->ctl_compat_table[10].data = &tn->tcp_loose;
+	pn->ctl_compat_table[11].data = &tn->tcp_be_liberal;
+	pn->ctl_compat_table[12].data = &tn->tcp_max_retrans;
+#endif
+#endif
+	return 0;
+}
+
+static int tcpv4_init_net(struct net *net)
+{
+	int i;
+	int ret = 0;
+	struct nf_tcp_net *tn = tcp_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)tn;
+
+#ifdef CONFIG_SYSCTL
+	if (!pn->ctl_table) {
+#else
+	if (!pn->users++) {
+#endif
+		for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++)
+			tn->timeouts[i] = tcp_timeouts[i];
+
+		tn->tcp_loose = nf_ct_tcp_loose;
+		tn->tcp_be_liberal = nf_ct_tcp_be_liberal;
+		tn->tcp_max_retrans = nf_ct_tcp_max_retrans;
+	}
+
+	ret = tcp_kmemdup_compat_sysctl_table(pn);
+
+	if (ret < 0)
+		return ret;
+
+	ret = tcp_kmemdup_sysctl_table(pn);
+
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+	if (ret < 0) {
+		kfree(pn->ctl_compat_table);
+		pn->ctl_compat_table = NULL;
+	}
+#endif
+#endif
+	return ret;
+}
+
+static int tcpv6_init_net(struct net *net)
+{
+	int i;
+	struct nf_tcp_net *tn = tcp_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)tn;
+
+#ifdef CONFIG_SYSCTL
+	if (!pn->ctl_table) {
+#else
+	if (!pn->users++) {
+#endif
+		for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++)
+			tn->timeouts[i] = tcp_timeouts[i];
+		tn->tcp_loose = nf_ct_tcp_loose;
+		tn->tcp_be_liberal = nf_ct_tcp_be_liberal;
+		tn->tcp_max_retrans = nf_ct_tcp_max_retrans;
+	}
+
+	return tcp_kmemdup_sysctl_table(pn);
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
 {
 	.l3proto		= PF_INET,
@@ -1582,14 +1684,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
 		.nla_policy	= tcp_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-	.ctl_table_users	= &tcp_sysctl_table_users,
-	.ctl_table_header	= &tcp_sysctl_header,
-	.ctl_table		= tcp_sysctl_table,
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-	.ctl_compat_table	= tcp_compat_sysctl_table,
-#endif
-#endif
+	.init_net		= tcpv4_init_net,
 };
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4);
 
@@ -1625,10 +1720,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
 		.nla_policy	= tcp_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-	.ctl_table_users	= &tcp_sysctl_table_users,
-	.ctl_table_header	= &tcp_sysctl_header,
-	.ctl_table		= tcp_sysctl_table,
-#endif
+	.init_net		= tcpv6_init_net,
 };
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6);
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 7259a6b..a83cf93 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -25,17 +25,16 @@
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
 
-enum udp_conntrack {
-	UDP_CT_UNREPLIED,
-	UDP_CT_REPLIED,
-	UDP_CT_MAX
-};
-
 static unsigned int udp_timeouts[UDP_CT_MAX] = {
 	[UDP_CT_UNREPLIED]	= 30*HZ,
 	[UDP_CT_REPLIED]	= 180*HZ,
 };
 
+static inline struct nf_udp_net *udp_pernet(struct net *net)
+{
+	return &net->ct.nf_ct_proto.udp;
+}
+
 static bool udp_pkt_to_tuple(const struct sk_buff *skb,
 			     unsigned int dataoff,
 			     struct nf_conntrack_tuple *tuple)
@@ -73,7 +72,7 @@ static int udp_print_tuple(struct seq_file *s,
 
 static unsigned int *udp_get_timeouts(struct net *net)
 {
-	return udp_timeouts;
+	return udp_pernet(net)->timeouts;
 }
 
 /* Returns verdict for packet, and may modify conntracktype */
@@ -157,13 +156,15 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int udp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int udp_timeout_nlattr_to_obj(struct nlattr *tb[],
+				     struct net *net, void *data)
 {
 	unsigned int *timeouts = data;
+	struct nf_udp_net *un = udp_pernet(net);
 
 	/* set default timeouts for UDP. */
-	timeouts[UDP_CT_UNREPLIED] = udp_timeouts[UDP_CT_UNREPLIED];
-	timeouts[UDP_CT_REPLIED] = udp_timeouts[UDP_CT_REPLIED];
+	timeouts[UDP_CT_UNREPLIED] = un->timeouts[UDP_CT_UNREPLIED];
+	timeouts[UDP_CT_REPLIED] = un->timeouts[UDP_CT_REPLIED];
 
 	if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) {
 		timeouts[UDP_CT_UNREPLIED] =
@@ -200,19 +201,15 @@ udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static unsigned int udp_sysctl_table_users;
-static struct ctl_table_header *udp_sysctl_header;
 static struct ctl_table udp_sysctl_table[] = {
 	{
 		.procname	= "nf_conntrack_udp_timeout",
-		.data		= &udp_timeouts[UDP_CT_UNREPLIED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_udp_timeout_stream",
-		.data		= &udp_timeouts[UDP_CT_REPLIED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -223,14 +220,12 @@ static struct ctl_table udp_sysctl_table[] = {
 static struct ctl_table udp_compat_sysctl_table[] = {
 	{
 		.procname	= "ip_conntrack_udp_timeout",
-		.data		= &udp_timeouts[UDP_CT_UNREPLIED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_udp_timeout_stream",
-		.data		= &udp_timeouts[UDP_CT_REPLIED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -240,6 +235,87 @@ static struct ctl_table udp_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
 
+static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+	struct nf_udp_net *un = (struct nf_udp_net *)pn;
+	if (pn->ctl_table)
+		return 0;
+	pn->ctl_table = kmemdup(udp_sysctl_table,
+				sizeof(udp_sysctl_table),
+				GFP_KERNEL);
+	if (!pn->ctl_table)
+		return -ENOMEM;
+	pn->ctl_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
+	pn->ctl_table[1].data = &un->timeouts[UDP_CT_REPLIED];
+#endif
+	return 0;
+}
+
+static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+	struct nf_udp_net *un = (struct nf_udp_net *)pn;
+	pn->ctl_compat_table = kmemdup(udp_compat_sysctl_table,
+				       sizeof(udp_compat_sysctl_table),
+				       GFP_KERNEL);
+	if (!pn->ctl_compat_table)
+		return -ENOMEM;
+
+	pn->ctl_compat_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
+	pn->ctl_compat_table[1].data = &un->timeouts[UDP_CT_REPLIED];
+#endif
+#endif
+	return 0;
+}
+
+static void udp_init_net_data(struct nf_udp_net *un)
+{
+	int i;
+#ifdef CONFIG_SYSCTL
+	if (!un->pn.ctl_table) {
+#else
+	if (!un->pn.users++) {
+#endif
+		for (i = 0; i < UDP_CT_MAX; i++)
+			un->timeouts[i] = udp_timeouts[i];
+	}
+}
+
+static int udpv4_init_net(struct net *net)
+{
+	int ret;
+	struct nf_udp_net *un = udp_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)un;
+
+	udp_init_net_data(un);
+
+	ret = udp_kmemdup_compat_sysctl_table(pn);
+	if (ret < 0)
+		return ret;
+
+	ret = udp_kmemdup_sysctl_table(pn);
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+	if (ret < 0) {
+		kfree(pn->ctl_compat_table);
+		pn->ctl_compat_table = NULL;
+	}
+#endif
+#endif
+	return ret;
+}
+
+static int udpv6_init_net(struct net *net)
+{
+	struct nf_udp_net *un = udp_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)un;
+
+	udp_init_net_data(un);
+	return udp_kmemdup_sysctl_table(pn);
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
 {
 	.l3proto		= PF_INET,
@@ -267,14 +343,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
 		.nla_policy	= udp_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-	.ctl_table_users	= &udp_sysctl_table_users,
-	.ctl_table_header	= &udp_sysctl_header,
-	.ctl_table		= udp_sysctl_table,
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-	.ctl_compat_table	= udp_compat_sysctl_table,
-#endif
-#endif
+	.init_net		= udpv4_init_net,
 };
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
 
@@ -305,10 +374,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
 		.nla_policy	= udp_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-	.ctl_table_users	= &udp_sysctl_table_users,
-	.ctl_table_header	= &udp_sysctl_header,
-	.ctl_table		= udp_sysctl_table,
-#endif
+	.init_net		= udpv6_init_net,
 };
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6);
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
index 4d60a53..b32e700 100644
--- a/net/netfilter/nf_conntrack_proto_udplite.c
+++ b/net/netfilter/nf_conntrack_proto_udplite.c
@@ -35,6 +35,17 @@ static unsigned int udplite_timeouts[UDPLITE_CT_MAX] = {
 	[UDPLITE_CT_REPLIED]	= 180*HZ,
 };
 
+static int udplite_net_id __read_mostly;
+struct udplite_net {
+	struct nf_proto_net pn;
+	unsigned int timeouts[UDPLITE_CT_MAX];
+};
+
+static inline struct udplite_net *udplite_pernet(struct net *net)
+{
+	return net_generic(net, udplite_net_id);
+}
+
 static bool udplite_pkt_to_tuple(const struct sk_buff *skb,
 				 unsigned int dataoff,
 				 struct nf_conntrack_tuple *tuple)
@@ -70,7 +81,7 @@ static int udplite_print_tuple(struct seq_file *s,
 
 static unsigned int *udplite_get_timeouts(struct net *net)
 {
-	return udplite_timeouts;
+	return udplite_pernet(net)->timeouts;
 }
 
 /* Returns verdict for packet, and may modify conntracktype */
@@ -161,13 +172,15 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl,
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int udplite_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int udplite_timeout_nlattr_to_obj(struct nlattr *tb[],
+					 struct net *net, void *data)
 {
 	unsigned int *timeouts = data;
+	struct udplite_net *un = udplite_pernet(net);
 
 	/* set default timeouts for UDPlite. */
-	timeouts[UDPLITE_CT_UNREPLIED] = udplite_timeouts[UDPLITE_CT_UNREPLIED];
-	timeouts[UDPLITE_CT_REPLIED] = udplite_timeouts[UDPLITE_CT_REPLIED];
+	timeouts[UDPLITE_CT_UNREPLIED] = un->timeouts[UDPLITE_CT_UNREPLIED];
+	timeouts[UDPLITE_CT_REPLIED] = un->timeouts[UDPLITE_CT_REPLIED];
 
 	if (tb[CTA_TIMEOUT_UDPLITE_UNREPLIED]) {
 		timeouts[UDPLITE_CT_UNREPLIED] =
@@ -204,19 +217,15 @@ udplite_timeout_nla_policy[CTA_TIMEOUT_UDPLITE_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static unsigned int udplite_sysctl_table_users;
-static struct ctl_table_header *udplite_sysctl_header;
 static struct ctl_table udplite_sysctl_table[] = {
 	{
 		.procname	= "nf_conntrack_udplite_timeout",
-		.data		= &udplite_timeouts[UDPLITE_CT_UNREPLIED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_udplite_timeout_stream",
-		.data		= &udplite_timeouts[UDPLITE_CT_REPLIED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -225,6 +234,31 @@ static struct ctl_table udplite_sysctl_table[] = {
 };
 #endif /* CONFIG_SYSCTL */
 
+static int udplite_init_net(struct net *net)
+{
+	int i;
+	struct udplite_net *un = udplite_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)un;
+#ifdef CONFIG_SYSCTL
+	if (!pn->ctl_table) {
+#else
+	if (!pn->users++) {
+#endif
+		for (i = 0 ; i < UDPLITE_CT_MAX; i++)
+			un->timeouts[i] = udplite_timeouts[i];
+#ifdef CONFIG_SYSCTL
+		pn->ctl_table = kmemdup(udplite_sysctl_table,
+					sizeof(udplite_sysctl_table),
+					GFP_KERNEL);
+		if (!pn->ctl_table)
+			return -ENOMEM;
+		pn->ctl_table[0].data = &un->timeouts[UDPLITE_CT_UNREPLIED];
+		pn->ctl_table[1].data = &un->timeouts[UDPLITE_CT_REPLIED];
+#endif
+	}
+	return 0;
+}
+
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
 {
 	.l3proto		= PF_INET,
@@ -253,11 +287,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
 		.nla_policy	= udplite_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-	.ctl_table_users	= &udplite_sysctl_table_users,
-	.ctl_table_header	= &udplite_sysctl_header,
-	.ctl_table		= udplite_sysctl_table,
-#endif
+	.net_id			= &udplite_net_id,
+	.init_net		= udplite_init_net,
 };
 
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
@@ -288,34 +319,55 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
 		.nla_policy	= udplite_timeout_nla_policy,
 	},
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-	.ctl_table_users	= &udplite_sysctl_table_users,
-	.ctl_table_header	= &udplite_sysctl_header,
-	.ctl_table		= udplite_sysctl_table,
-#endif
+	.net_id			= &udplite_net_id,
+	.init_net		= udplite_init_net,
 };
 
-static int __init nf_conntrack_proto_udplite_init(void)
+static int udplite_net_init(struct net *net)
 {
-	int err;
-
-	err = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udplite4);
-	if (err < 0)
-		goto err1;
-	err = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udplite6);
-	if (err < 0)
-		goto err2;
+	int ret = 0;
+
+	ret = nf_conntrack_l4proto_register(net,
+					    &nf_conntrack_l4proto_udplite4);
+	if (ret < 0) {
+		pr_err("nf_conntrack_l4proto_udplite4 :protocol register failed.\n");
+		goto out;
+	}
+	ret = nf_conntrack_l4proto_register(net,
+					    &nf_conntrack_l4proto_udplite6);
+	if (ret < 0) {
+		pr_err("nf_conntrack_l4proto_udplite4 :protocol register failed.\n");
+		goto cleanup_udplite4;
+	}
 	return 0;
-err2:
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
-err1:
-	return err;
+
+cleanup_udplite4:
+	nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite4);
+out:
+	return ret;
+}
+
+static void udplite_net_exit(struct net *net)
+{
+	nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite6);
+	nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite4);
+}
+
+static struct pernet_operations udplite_net_ops = {
+	.init = udplite_net_init,
+	.exit = udplite_net_exit,
+	.id   = &udplite_net_id,
+	.size = sizeof(struct udplite_net),
+};
+
+static int __init nf_conntrack_proto_udplite_init(void)
+{
+	return register_pernet_subsys(&udplite_net_ops);
 }
 
 static void __exit nf_conntrack_proto_udplite_exit(void)
 {
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite6);
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
+	unregister_pernet_subsys(&udplite_net_ops);
 }
 
 module_init(nf_conntrack_proto_udplite_init);
diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c
index 8501823..295429f 100644
--- a/net/netfilter/nf_conntrack_sane.c
+++ b/net/netfilter/nf_conntrack_sane.c
@@ -69,13 +69,12 @@ static int help(struct sk_buff *skb,
 	void *sb_ptr;
 	int ret = NF_ACCEPT;
 	int dir = CTINFO2DIR(ctinfo);
-	struct nf_ct_sane_master *ct_sane_info;
+	struct nf_ct_sane_master *ct_sane_info = nfct_help_data(ct);
 	struct nf_conntrack_expect *exp;
 	struct nf_conntrack_tuple *tuple;
 	struct sane_request *req;
 	struct sane_reply_net_start *reply;
 
-	ct_sane_info = &nfct_help(ct)->help.ct_sane_info;
 	/* Until there's been traffic both ways, don't look in packets. */
 	if (ctinfo != IP_CT_ESTABLISHED &&
 	    ctinfo != IP_CT_ESTABLISHED_REPLY)
@@ -163,7 +162,6 @@ out:
 }
 
 static struct nf_conntrack_helper sane[MAX_PORTS][2] __read_mostly;
-static char sane_names[MAX_PORTS][2][sizeof("sane-65535")] __read_mostly;
 
 static const struct nf_conntrack_expect_policy sane_exp_policy = {
 	.max_expected	= 1,
@@ -190,7 +188,6 @@ static void nf_conntrack_sane_fini(void)
 static int __init nf_conntrack_sane_init(void)
 {
 	int i, j = -1, ret = 0;
-	char *tmpname;
 
 	sane_buffer = kmalloc(65536, GFP_KERNEL);
 	if (!sane_buffer)
@@ -205,17 +202,16 @@ static int __init nf_conntrack_sane_init(void)
 		sane[i][0].tuple.src.l3num = PF_INET;
 		sane[i][1].tuple.src.l3num = PF_INET6;
 		for (j = 0; j < 2; j++) {
+			sane[i][j].data_len = sizeof(struct nf_ct_sane_master);
 			sane[i][j].tuple.src.u.tcp.port = htons(ports[i]);
 			sane[i][j].tuple.dst.protonum = IPPROTO_TCP;
 			sane[i][j].expect_policy = &sane_exp_policy;
 			sane[i][j].me = THIS_MODULE;
 			sane[i][j].help = help;
-			tmpname = &sane_names[i][j][0];
 			if (ports[i] == SANE_PORT)
-				sprintf(tmpname, "sane");
+				sprintf(sane[i][j].name, "sane");
 			else
-				sprintf(tmpname, "sane-%d", ports[i]);
-			sane[i][j].name = tmpname;
+				sprintf(sane[i][j].name, "sane-%d", ports[i]);
 
 			pr_debug("nf_ct_sane: registering helper for pf: %d "
 				 "port: %d\n",
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 93faf6a..758a1ba 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -1075,12 +1075,12 @@ static int process_invite_response(struct sk_buff *skb, unsigned int dataoff,
 {
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
-	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
 
 	if ((code >= 100 && code <= 199) ||
 	    (code >= 200 && code <= 299))
 		return process_sdp(skb, dataoff, dptr, datalen, cseq);
-	else if (help->help.ct_sip_info.invite_cseq == cseq)
+	else if (ct_sip_info->invite_cseq == cseq)
 		flush_expectations(ct, true);
 	return NF_ACCEPT;
 }
@@ -1091,12 +1091,12 @@ static int process_update_response(struct sk_buff *skb, unsigned int dataoff,
 {
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
-	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
 
 	if ((code >= 100 && code <= 199) ||
 	    (code >= 200 && code <= 299))
 		return process_sdp(skb, dataoff, dptr, datalen, cseq);
-	else if (help->help.ct_sip_info.invite_cseq == cseq)
+	else if (ct_sip_info->invite_cseq == cseq)
 		flush_expectations(ct, true);
 	return NF_ACCEPT;
 }
@@ -1107,12 +1107,12 @@ static int process_prack_response(struct sk_buff *skb, unsigned int dataoff,
 {
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
-	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
 
 	if ((code >= 100 && code <= 199) ||
 	    (code >= 200 && code <= 299))
 		return process_sdp(skb, dataoff, dptr, datalen, cseq);
-	else if (help->help.ct_sip_info.invite_cseq == cseq)
+	else if (ct_sip_info->invite_cseq == cseq)
 		flush_expectations(ct, true);
 	return NF_ACCEPT;
 }
@@ -1123,13 +1123,13 @@ static int process_invite_request(struct sk_buff *skb, unsigned int dataoff,
 {
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
-	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
 	unsigned int ret;
 
 	flush_expectations(ct, true);
 	ret = process_sdp(skb, dataoff, dptr, datalen, cseq);
 	if (ret == NF_ACCEPT)
-		help->help.ct_sip_info.invite_cseq = cseq;
+		ct_sip_info->invite_cseq = cseq;
 	return ret;
 }
 
@@ -1154,7 +1154,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int dataoff,
 {
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
-	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 	unsigned int matchoff, matchlen;
 	struct nf_conntrack_expect *exp;
@@ -1235,7 +1235,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int dataoff,
 
 store_cseq:
 	if (ret == NF_ACCEPT)
-		help->help.ct_sip_info.register_cseq = cseq;
+		ct_sip_info->register_cseq = cseq;
 	return ret;
 }
 
@@ -1245,7 +1245,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int dataoff,
 {
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
-	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 	union nf_inet_addr addr;
 	__be16 port;
@@ -1262,7 +1262,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int dataoff,
 	 * responses, so we store the sequence number of the last valid
 	 * request and compare it here.
 	 */
-	if (help->help.ct_sip_info.register_cseq != cseq)
+	if (ct_sip_info->register_cseq != cseq)
 		return NF_ACCEPT;
 
 	if (code >= 100 && code <= 199)
@@ -1556,7 +1556,6 @@ static void nf_conntrack_sip_fini(void)
 static int __init nf_conntrack_sip_init(void)
 {
 	int i, j, ret;
-	char *tmpname;
 
 	if (ports_c == 0)
 		ports[ports_c++] = SIP_PORT;
@@ -1579,17 +1578,16 @@ static int __init nf_conntrack_sip_init(void)
 		sip[i][3].help = sip_help_tcp;
 
 		for (j = 0; j < ARRAY_SIZE(sip[i]); j++) {
+			sip[i][j].data_len = sizeof(struct nf_ct_sip_master);
 			sip[i][j].tuple.src.u.udp.port = htons(ports[i]);
 			sip[i][j].expect_policy = sip_exp_policy;
 			sip[i][j].expect_class_max = SIP_EXPECT_MAX;
 			sip[i][j].me = THIS_MODULE;
 
-			tmpname = &sip_names[i][j][0];
 			if (ports[i] == SIP_PORT)
-				sprintf(tmpname, "sip");
+				sprintf(sip_names[i][j], "sip");
 			else
-				sprintf(tmpname, "sip-%u", i);
-			sip[i][j].name = tmpname;
+				sprintf(sip_names[i][j], "sip-%u", i);
 
 			pr_debug("port #%u: %u\n", i, ports[i]);
 
diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c
index 75466fd..81fc61c 100644
--- a/net/netfilter/nf_conntrack_tftp.c
+++ b/net/netfilter/nf_conntrack_tftp.c
@@ -92,7 +92,6 @@ static int tftp_help(struct sk_buff *skb,
 }
 
 static struct nf_conntrack_helper tftp[MAX_PORTS][2] __read_mostly;
-static char tftp_names[MAX_PORTS][2][sizeof("tftp-65535")] __read_mostly;
 
 static const struct nf_conntrack_expect_policy tftp_exp_policy = {
 	.max_expected	= 1,
@@ -112,7 +111,6 @@ static void nf_conntrack_tftp_fini(void)
 static int __init nf_conntrack_tftp_init(void)
 {
 	int i, j, ret;
-	char *tmpname;
 
 	if (ports_c == 0)
 		ports[ports_c++] = TFTP_PORT;
@@ -129,12 +127,10 @@ static int __init nf_conntrack_tftp_init(void)
 			tftp[i][j].me = THIS_MODULE;
 			tftp[i][j].help = tftp_help;
 
-			tmpname = &tftp_names[i][j][0];
 			if (ports[i] == TFTP_PORT)
-				sprintf(tmpname, "tftp");
+				sprintf(tftp[i][j].name, "tftp");
 			else
-				sprintf(tmpname, "tftp-%u", i);
-			tftp[i][j].name = tmpname;
+				sprintf(tftp[i][j].name, "tftp-%u", i);
 
 			ret = nf_conntrack_helper_register(&tftp[i][j]);
 			if (ret) {
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c
new file mode 100644
index 0000000..d683619
--- /dev/null
+++ b/net/netfilter/nfnetlink_cthelper.c
@@ -0,0 +1,672 @@
+/*
+ * (C) 2012 Pablo Neira Ayuso <pablo@netfilter.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 (or any later at your option).
+ *
+ * This software has been sponsored by Vyatta Inc. <http://www.vyatta.com>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/rculist.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <net/netlink.h>
+#include <net/sock.h>
+
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_expect.h>
+#include <net/netfilter/nf_conntrack_ecache.h>
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+#include <linux/netfilter/nfnetlink_cthelper.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
+MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers");
+
+static int
+nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff,
+			struct nf_conn *ct, enum ip_conntrack_info ctinfo)
+{
+	const struct nf_conn_help *help;
+	struct nf_conntrack_helper *helper;
+
+	help = nfct_help(ct);
+	if (help == NULL)
+		return NF_DROP;
+
+	/* rcu_read_lock()ed by nf_hook_slow */
+	helper = rcu_dereference(help->helper);
+	if (helper == NULL)
+		return NF_DROP;
+
+	/* This is an user-space helper not yet configured, skip. */
+	if ((helper->flags &
+	    (NF_CT_HELPER_F_USERSPACE | NF_CT_HELPER_F_CONFIGURED)) ==
+	     NF_CT_HELPER_F_USERSPACE)
+		return NF_ACCEPT;
+
+	/* If the user-space helper is not available, don't block traffic. */
+	return NF_QUEUE_NR(helper->queue_num) | NF_VERDICT_FLAG_QUEUE_BYPASS;
+}
+
+static const struct nla_policy nfnl_cthelper_tuple_pol[NFCTH_TUPLE_MAX+1] = {
+	[NFCTH_TUPLE_L3PROTONUM] = { .type = NLA_U16, },
+	[NFCTH_TUPLE_L4PROTONUM] = { .type = NLA_U8, },
+};
+
+static int
+nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple,
+			  const struct nlattr *attr)
+{
+	struct nlattr *tb[NFCTH_TUPLE_MAX+1];
+
+	nla_parse_nested(tb, NFCTH_TUPLE_MAX, attr, nfnl_cthelper_tuple_pol);
+
+	if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM])
+		return -EINVAL;
+
+	tuple->src.l3num = ntohs(nla_get_u16(tb[NFCTH_TUPLE_L3PROTONUM]));
+	tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]);
+
+	return 0;
+}
+
+static int
+nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
+{
+	const struct nf_conn_help *help = nfct_help(ct);
+
+	if (help->helper->data_len == 0)
+		return -EINVAL;
+
+	memcpy(&help->data, nla_data(attr), help->helper->data_len);
+	return 0;
+}
+
+static int
+nfnl_cthelper_to_nlattr(struct sk_buff *skb, const struct nf_conn *ct)
+{
+	const struct nf_conn_help *help = nfct_help(ct);
+
+	if (help->helper->data_len &&
+	    nla_put(skb, CTA_HELP_INFO, help->helper->data_len, &help->data))
+		goto nla_put_failure;
+
+	return 0;
+
+nla_put_failure:
+	return -ENOSPC;
+}
+
+static const struct nla_policy nfnl_cthelper_expect_pol[NFCTH_POLICY_MAX+1] = {
+	[NFCTH_POLICY_NAME] = { .type = NLA_NUL_STRING,
+				.len = NF_CT_HELPER_NAME_LEN-1 },
+	[NFCTH_POLICY_EXPECT_MAX] = { .type = NLA_U32, },
+	[NFCTH_POLICY_EXPECT_TIMEOUT] = { .type = NLA_U32, },
+};
+
+static int
+nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy,
+			    const struct nlattr *attr)
+{
+	struct nlattr *tb[NFCTH_POLICY_MAX+1];
+
+	nla_parse_nested(tb, NFCTH_POLICY_MAX, attr, nfnl_cthelper_expect_pol);
+
+	if (!tb[NFCTH_POLICY_NAME] ||
+	    !tb[NFCTH_POLICY_EXPECT_MAX] ||
+	    !tb[NFCTH_POLICY_EXPECT_TIMEOUT])
+		return -EINVAL;
+
+	strncpy(expect_policy->name,
+		nla_data(tb[NFCTH_POLICY_NAME]), NF_CT_HELPER_NAME_LEN);
+	expect_policy->max_expected =
+		ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
+	expect_policy->timeout =
+		ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
+
+	return 0;
+}
+
+static const struct nla_policy
+nfnl_cthelper_expect_policy_set[NFCTH_POLICY_SET_MAX+1] = {
+	[NFCTH_POLICY_SET_NUM] = { .type = NLA_U32, },
+};
+
+static int
+nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper,
+				  const struct nlattr *attr)
+{
+	int i, ret;
+	struct nf_conntrack_expect_policy *expect_policy;
+	struct nlattr *tb[NFCTH_POLICY_SET_MAX+1];
+
+	nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr,
+					nfnl_cthelper_expect_policy_set);
+
+	if (!tb[NFCTH_POLICY_SET_NUM])
+		return -EINVAL;
+
+	helper->expect_class_max =
+		ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
+
+	if (helper->expect_class_max != 0 &&
+	    helper->expect_class_max > NF_CT_MAX_EXPECT_CLASSES)
+		return -EOVERFLOW;
+
+	expect_policy = kzalloc(sizeof(struct nf_conntrack_expect_policy) *
+				helper->expect_class_max, GFP_KERNEL);
+	if (expect_policy == NULL)
+		return -ENOMEM;
+
+	for (i=0; i<helper->expect_class_max; i++) {
+		if (!tb[NFCTH_POLICY_SET+i])
+			goto err;
+
+		ret = nfnl_cthelper_expect_policy(&expect_policy[i],
+						  tb[NFCTH_POLICY_SET+i]);
+		if (ret < 0)
+			goto err;
+	}
+	helper->expect_policy = expect_policy;
+	return 0;
+err:
+	kfree(expect_policy);
+	return -EINVAL;
+}
+
+static int
+nfnl_cthelper_create(const struct nlattr * const tb[],
+		     struct nf_conntrack_tuple *tuple)
+{
+	struct nf_conntrack_helper *helper;
+	int ret;
+
+	if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN])
+		return -EINVAL;
+
+	helper = kzalloc(sizeof(struct nf_conntrack_helper), GFP_KERNEL);
+	if (helper == NULL)
+		return -ENOMEM;
+
+	ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]);
+	if (ret < 0)
+		goto err;
+
+	strncpy(helper->name, nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN);
+	helper->data_len = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
+	helper->flags |= NF_CT_HELPER_F_USERSPACE;
+	memcpy(&helper->tuple, tuple, sizeof(struct nf_conntrack_tuple));
+
+	helper->me = THIS_MODULE;
+	helper->help = nfnl_userspace_cthelper;
+	helper->from_nlattr = nfnl_cthelper_from_nlattr;
+	helper->to_nlattr = nfnl_cthelper_to_nlattr;
+
+	/* Default to queue number zero, this can be updated at any time. */
+	if (tb[NFCTH_QUEUE_NUM])
+		helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
+
+	if (tb[NFCTH_STATUS]) {
+		int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
+
+		switch(status) {
+		case NFCT_HELPER_STATUS_ENABLED:
+			helper->flags |= NF_CT_HELPER_F_CONFIGURED;
+			break;
+		case NFCT_HELPER_STATUS_DISABLED:
+			helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
+			break;
+		}
+	}
+
+	ret = nf_conntrack_helper_register(helper);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+err:
+	kfree(helper);
+	return ret;
+}
+
+static int
+nfnl_cthelper_update(const struct nlattr * const tb[],
+		     struct nf_conntrack_helper *helper)
+{
+	int ret;
+
+	if (tb[NFCTH_PRIV_DATA_LEN])
+		return -EBUSY;
+
+	if (tb[NFCTH_POLICY]) {
+		ret = nfnl_cthelper_parse_expect_policy(helper,
+							tb[NFCTH_POLICY]);
+		if (ret < 0)
+			return ret;
+	}
+	if (tb[NFCTH_QUEUE_NUM])
+		helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
+
+	if (tb[NFCTH_STATUS]) {
+		int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
+
+		switch(status) {
+		case NFCT_HELPER_STATUS_ENABLED:
+			helper->flags |= NF_CT_HELPER_F_CONFIGURED;
+			break;
+		case NFCT_HELPER_STATUS_DISABLED:
+			helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
+			break;
+		}
+	}
+	return 0;
+}
+
+static int
+nfnl_cthelper_new(struct sock *nfnl, struct sk_buff *skb,
+		  const struct nlmsghdr *nlh, const struct nlattr * const tb[])
+{
+	const char *helper_name;
+	struct nf_conntrack_helper *cur, *helper = NULL;
+	struct nf_conntrack_tuple tuple;
+	struct hlist_node *n;
+	int ret = 0, i;
+
+	if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE])
+		return -EINVAL;
+
+	helper_name = nla_data(tb[NFCTH_NAME]);
+
+	ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
+	if (ret < 0)
+		return ret;
+
+	rcu_read_lock();
+	for (i = 0; i < nf_ct_helper_hsize && !helper; i++) {
+		hlist_for_each_entry_rcu(cur, n, &nf_ct_helper_hash[i], hnode) {
+
+			/* skip non-userspace conntrack helpers. */
+			if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
+				continue;
+
+			if (strncmp(cur->name, helper_name,
+					NF_CT_HELPER_NAME_LEN) != 0)
+				continue;
+
+			if ((tuple.src.l3num != cur->tuple.src.l3num ||
+			     tuple.dst.protonum != cur->tuple.dst.protonum))
+				continue;
+
+			if (nlh->nlmsg_flags & NLM_F_EXCL) {
+				ret = -EEXIST;
+				goto err;
+			}
+			helper = cur;
+			break;
+		}
+	}
+	rcu_read_unlock();
+
+	if (helper == NULL)
+		ret = nfnl_cthelper_create(tb, &tuple);
+	else
+		ret = nfnl_cthelper_update(tb, helper);
+
+	return ret;
+err:
+	rcu_read_unlock();
+	return ret;
+}
+
+static int
+nfnl_cthelper_dump_tuple(struct sk_buff *skb,
+			 struct nf_conntrack_helper *helper)
+{
+	struct nlattr *nest_parms;
+
+	nest_parms = nla_nest_start(skb, NFCTH_TUPLE | NLA_F_NESTED);
+	if (nest_parms == NULL)
+		goto nla_put_failure;
+
+	if (nla_put_be16(skb, NFCTH_TUPLE_L3PROTONUM,
+			 htons(helper->tuple.src.l3num)))
+		goto nla_put_failure;
+
+	if (nla_put_u8(skb, NFCTH_TUPLE_L4PROTONUM, helper->tuple.dst.protonum))
+		goto nla_put_failure;
+
+	nla_nest_end(skb, nest_parms);
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static int
+nfnl_cthelper_dump_policy(struct sk_buff *skb,
+			struct nf_conntrack_helper *helper)
+{
+	int i;
+	struct nlattr *nest_parms1, *nest_parms2;
+
+	nest_parms1 = nla_nest_start(skb, NFCTH_POLICY | NLA_F_NESTED);
+	if (nest_parms1 == NULL)
+		goto nla_put_failure;
+
+	if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM,
+			 htonl(helper->expect_class_max)))
+		goto nla_put_failure;
+
+	for (i=0; i<helper->expect_class_max; i++) {
+		nest_parms2 = nla_nest_start(skb,
+				(NFCTH_POLICY_SET+i) | NLA_F_NESTED);
+		if (nest_parms2 == NULL)
+			goto nla_put_failure;
+
+		if (nla_put_string(skb, NFCTH_POLICY_NAME,
+				   helper->expect_policy[i].name))
+			goto nla_put_failure;
+
+		if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_MAX,
+				 htonl(helper->expect_policy[i].max_expected)))
+			goto nla_put_failure;
+
+		if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_TIMEOUT,
+				 htonl(helper->expect_policy[i].timeout)))
+			goto nla_put_failure;
+
+		nla_nest_end(skb, nest_parms2);
+	}
+	nla_nest_end(skb, nest_parms1);
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static int
+nfnl_cthelper_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
+			int event, struct nf_conntrack_helper *helper)
+{
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfmsg;
+	unsigned int flags = pid ? NLM_F_MULTI : 0;
+	int status;
+
+	event |= NFNL_SUBSYS_CTHELPER << 8;
+	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
+	if (nlh == NULL)
+		goto nlmsg_failure;
+
+	nfmsg = nlmsg_data(nlh);
+	nfmsg->nfgen_family = AF_UNSPEC;
+	nfmsg->version = NFNETLINK_V0;
+	nfmsg->res_id = 0;
+
+	if (nla_put_string(skb, NFCTH_NAME, helper->name))
+		goto nla_put_failure;
+
+	if (nla_put_be32(skb, NFCTH_QUEUE_NUM, htonl(helper->queue_num)))
+		goto nla_put_failure;
+
+	if (nfnl_cthelper_dump_tuple(skb, helper) < 0)
+		goto nla_put_failure;
+
+	if (nfnl_cthelper_dump_policy(skb, helper) < 0)
+		goto nla_put_failure;
+
+	if (nla_put_be32(skb, NFCTH_PRIV_DATA_LEN, htonl(helper->data_len)))
+		goto nla_put_failure;
+
+	if (helper->flags & NF_CT_HELPER_F_CONFIGURED)
+		status = NFCT_HELPER_STATUS_ENABLED;
+	else
+		status = NFCT_HELPER_STATUS_DISABLED;
+
+	if (nla_put_be32(skb, NFCTH_STATUS, htonl(status)))
+		goto nla_put_failure;
+
+	nlmsg_end(skb, nlh);
+	return skb->len;
+
+nlmsg_failure:
+nla_put_failure:
+	nlmsg_cancel(skb, nlh);
+	return -1;
+}
+
+static int
+nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct nf_conntrack_helper *cur, *last;
+	struct hlist_node *n;
+
+	rcu_read_lock();
+	last = (struct nf_conntrack_helper *)cb->args[1];
+	for (; cb->args[0] < nf_ct_helper_hsize; cb->args[0]++) {
+restart:
+		hlist_for_each_entry_rcu(cur, n,
+				&nf_ct_helper_hash[cb->args[0]], hnode) {
+
+			/* skip non-userspace conntrack helpers. */
+			if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
+				continue;
+
+			if (cb->args[1]) {
+				if (cur != last)
+					continue;
+				cb->args[1] = 0;
+			}
+			if (nfnl_cthelper_fill_info(skb,
+					    NETLINK_CB(cb->skb).pid,
+					    cb->nlh->nlmsg_seq,
+					    NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
+					    NFNL_MSG_CTHELPER_NEW, cur) < 0) {
+				cb->args[1] = (unsigned long)cur;
+				goto out;
+			}
+		}
+	}
+	if (cb->args[1]) {
+		cb->args[1] = 0;
+		goto restart;
+	}
+out:
+	rcu_read_unlock();
+	return skb->len;
+}
+
+static int
+nfnl_cthelper_get(struct sock *nfnl, struct sk_buff *skb,
+		  const struct nlmsghdr *nlh, const struct nlattr * const tb[])
+{
+	int ret = -ENOENT, i;
+	struct nf_conntrack_helper *cur;
+	struct hlist_node *n;
+	struct sk_buff *skb2;
+	char *helper_name = NULL;
+	struct nf_conntrack_tuple tuple;
+	bool tuple_set = false;
+
+	if (nlh->nlmsg_flags & NLM_F_DUMP) {
+		struct netlink_dump_control c = {
+			.dump = nfnl_cthelper_dump_table,
+		};
+		return netlink_dump_start(nfnl, skb, nlh, &c);
+	}
+
+	if (tb[NFCTH_NAME])
+		helper_name = nla_data(tb[NFCTH_NAME]);
+
+	if (tb[NFCTH_TUPLE]) {
+		ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
+		if (ret < 0)
+			return ret;
+
+		tuple_set = true;
+	}
+
+	for (i = 0; i < nf_ct_helper_hsize; i++) {
+		hlist_for_each_entry_rcu(cur, n, &nf_ct_helper_hash[i], hnode) {
+
+			/* skip non-userspace conntrack helpers. */
+			if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
+				continue;
+
+			if (helper_name && strncmp(cur->name, helper_name,
+						NF_CT_HELPER_NAME_LEN) != 0) {
+				continue;
+			}
+			if (tuple_set &&
+			    (tuple.src.l3num != cur->tuple.src.l3num ||
+			     tuple.dst.protonum != cur->tuple.dst.protonum))
+				continue;
+
+			skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+			if (skb2 == NULL) {
+				ret = -ENOMEM;
+				break;
+			}
+
+			ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).pid,
+						nlh->nlmsg_seq,
+						NFNL_MSG_TYPE(nlh->nlmsg_type),
+						NFNL_MSG_CTHELPER_NEW, cur);
+			if (ret <= 0) {
+				kfree_skb(skb2);
+				break;
+			}
+
+			ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).pid,
+						MSG_DONTWAIT);
+			if (ret > 0)
+				ret = 0;
+
+			/* this avoids a loop in nfnetlink. */
+			return ret == -EAGAIN ? -ENOBUFS : ret;
+		}
+	}
+	return ret;
+}
+
+static int
+nfnl_cthelper_del(struct sock *nfnl, struct sk_buff *skb,
+	     const struct nlmsghdr *nlh, const struct nlattr * const tb[])
+{
+	char *helper_name = NULL;
+	struct nf_conntrack_helper *cur;
+	struct hlist_node *n, *tmp;
+	struct nf_conntrack_tuple tuple;
+	bool tuple_set = false, found = false;
+	int i, j = 0, ret;
+
+	if (tb[NFCTH_NAME])
+		helper_name = nla_data(tb[NFCTH_NAME]);
+
+	if (tb[NFCTH_TUPLE]) {
+		ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
+		if (ret < 0)
+			return ret;
+
+		tuple_set = true;
+	}
+
+	for (i = 0; i < nf_ct_helper_hsize; i++) {
+		hlist_for_each_entry_safe(cur, n, tmp, &nf_ct_helper_hash[i],
+								hnode) {
+			/* skip non-userspace conntrack helpers. */
+			if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
+				continue;
+
+			j++;
+
+			if (helper_name && strncmp(cur->name, helper_name,
+						NF_CT_HELPER_NAME_LEN) != 0) {
+				continue;
+			}
+			if (tuple_set &&
+			    (tuple.src.l3num != cur->tuple.src.l3num ||
+			     tuple.dst.protonum != cur->tuple.dst.protonum))
+				continue;
+
+			found = true;
+			nf_conntrack_helper_unregister(cur);
+		}
+	}
+	/* Make sure we return success if we flush and there is no helpers */
+	return (found || j == 0) ? 0 : -ENOENT;
+}
+
+static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {
+	[NFCTH_NAME] = { .type = NLA_NUL_STRING,
+			 .len = NF_CT_HELPER_NAME_LEN-1 },
+	[NFCTH_QUEUE_NUM] = { .type = NLA_U32, },
+};
+
+static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = {
+	[NFNL_MSG_CTHELPER_NEW]		= { .call = nfnl_cthelper_new,
+					    .attr_count = NFCTH_MAX,
+					    .policy = nfnl_cthelper_policy },
+	[NFNL_MSG_CTHELPER_GET]		= { .call = nfnl_cthelper_get,
+					    .attr_count = NFCTH_MAX,
+					    .policy = nfnl_cthelper_policy },
+	[NFNL_MSG_CTHELPER_DEL]		= { .call = nfnl_cthelper_del,
+					    .attr_count = NFCTH_MAX,
+					    .policy = nfnl_cthelper_policy },
+};
+
+static const struct nfnetlink_subsystem nfnl_cthelper_subsys = {
+	.name				= "cthelper",
+	.subsys_id			= NFNL_SUBSYS_CTHELPER,
+	.cb_count			= NFNL_MSG_CTHELPER_MAX,
+	.cb				= nfnl_cthelper_cb,
+};
+
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTHELPER);
+
+static int __init nfnl_cthelper_init(void)
+{
+	int ret;
+
+	ret = nfnetlink_subsys_register(&nfnl_cthelper_subsys);
+	if (ret < 0) {
+		pr_err("nfnl_cthelper: cannot register with nfnetlink.\n");
+		goto err_out;
+	}
+	return 0;
+err_out:
+	return ret;
+}
+
+static void __exit nfnl_cthelper_exit(void)
+{
+	struct nf_conntrack_helper *cur;
+	struct hlist_node *n, *tmp;
+	int i;
+
+	nfnetlink_subsys_unregister(&nfnl_cthelper_subsys);
+
+	for (i=0; i<nf_ct_helper_hsize; i++) {
+		hlist_for_each_entry_safe(cur, n, tmp, &nf_ct_helper_hash[i],
+									hnode) {
+			/* skip non-userspace conntrack helpers. */
+			if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
+				continue;
+
+			nf_conntrack_helper_unregister(cur);
+		}
+	}
+}
+
+module_init(nfnl_cthelper_init);
+module_exit(nfnl_cthelper_exit);
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c
index 3e65528..cdecbc8 100644
--- a/net/netfilter/nfnetlink_cttimeout.c
+++ b/net/netfilter/nfnetlink_cttimeout.c
@@ -49,8 +49,9 @@ static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = {
 
 static int
 ctnl_timeout_parse_policy(struct ctnl_timeout *timeout,
-			       struct nf_conntrack_l4proto *l4proto,
-			       const struct nlattr *attr)
+			  struct nf_conntrack_l4proto *l4proto,
+			  struct net *net,
+			  const struct nlattr *attr)
 {
 	int ret = 0;
 
@@ -60,7 +61,8 @@ ctnl_timeout_parse_policy(struct ctnl_timeout *timeout,
 		nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max,
 				 attr, l4proto->ctnl_timeout.nla_policy);
 
-		ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, &timeout->data);
+		ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net,
+							  &timeout->data);
 	}
 	return ret;
 }
@@ -74,6 +76,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
 	__u8 l4num;
 	struct nf_conntrack_l4proto *l4proto;
 	struct ctnl_timeout *timeout, *matching = NULL;
+	struct net *net = sock_net(skb->sk);
 	char *name;
 	int ret;
 
@@ -117,7 +120,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
 				goto err_proto_put;
 			}
 
-			ret = ctnl_timeout_parse_policy(matching, l4proto,
+			ret = ctnl_timeout_parse_policy(matching, l4proto, net,
 							cda[CTA_TIMEOUT_DATA]);
 			return ret;
 		}
@@ -132,7 +135,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
 		goto err_proto_put;
 	}
 
-	ret = ctnl_timeout_parse_policy(timeout, l4proto,
+	ret = ctnl_timeout_parse_policy(timeout, l4proto, net,
 					cda[CTA_TIMEOUT_DATA]);
 	if (ret < 0)
 		goto err;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
deleted file mode 100644
index 4162437..0000000
--- a/net/netfilter/nfnetlink_queue.c
+++ /dev/null
@@ -1,1036 +0,0 @@
-/*
- * This is a module which is used for queueing packets and communicating with
- * userspace via nfnetlink.
- *
- * (C) 2005 by Harald Welte <laforge@netfilter.org>
- * (C) 2007 by Patrick McHardy <kaber@trash.net>
- *
- * Based on the old ipv4-only ip_queue.c:
- * (C) 2000-2002 James Morris <jmorris@intercode.com.au>
- * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/notifier.h>
-#include <linux/netdevice.h>
-#include <linux/netfilter.h>
-#include <linux/proc_fs.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv6.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netfilter/nfnetlink_queue.h>
-#include <linux/list.h>
-#include <net/sock.h>
-#include <net/netfilter/nf_queue.h>
-
-#include <linux/atomic.h>
-
-#ifdef CONFIG_BRIDGE_NETFILTER
-#include "../bridge/br_private.h"
-#endif
-
-#define NFQNL_QMAX_DEFAULT 1024
-
-struct nfqnl_instance {
-	struct hlist_node hlist;		/* global list of queues */
-	struct rcu_head rcu;
-
-	int peer_pid;
-	unsigned int queue_maxlen;
-	unsigned int copy_range;
-	unsigned int queue_dropped;
-	unsigned int queue_user_dropped;
-
-
-	u_int16_t queue_num;			/* number of this queue */
-	u_int8_t copy_mode;
-/*
- * Following fields are dirtied for each queued packet,
- * keep them in same cache line if possible.
- */
-	spinlock_t	lock;
-	unsigned int	queue_total;
-	unsigned int	id_sequence;		/* 'sequence' of pkt ids */
-	struct list_head queue_list;		/* packets in queue */
-};
-
-typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long);
-
-static DEFINE_SPINLOCK(instances_lock);
-
-#define INSTANCE_BUCKETS	16
-static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly;
-
-static inline u_int8_t instance_hashfn(u_int16_t queue_num)
-{
-	return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS;
-}
-
-static struct nfqnl_instance *
-instance_lookup(u_int16_t queue_num)
-{
-	struct hlist_head *head;
-	struct hlist_node *pos;
-	struct nfqnl_instance *inst;
-
-	head = &instance_table[instance_hashfn(queue_num)];
-	hlist_for_each_entry_rcu(inst, pos, head, hlist) {
-		if (inst->queue_num == queue_num)
-			return inst;
-	}
-	return NULL;
-}
-
-static struct nfqnl_instance *
-instance_create(u_int16_t queue_num, int pid)
-{
-	struct nfqnl_instance *inst;
-	unsigned int h;
-	int err;
-
-	spin_lock(&instances_lock);
-	if (instance_lookup(queue_num)) {
-		err = -EEXIST;
-		goto out_unlock;
-	}
-
-	inst = kzalloc(sizeof(*inst), GFP_ATOMIC);
-	if (!inst) {
-		err = -ENOMEM;
-		goto out_unlock;
-	}
-
-	inst->queue_num = queue_num;
-	inst->peer_pid = pid;
-	inst->queue_maxlen = NFQNL_QMAX_DEFAULT;
-	inst->copy_range = 0xfffff;
-	inst->copy_mode = NFQNL_COPY_NONE;
-	spin_lock_init(&inst->lock);
-	INIT_LIST_HEAD(&inst->queue_list);
-
-	if (!try_module_get(THIS_MODULE)) {
-		err = -EAGAIN;
-		goto out_free;
-	}
-
-	h = instance_hashfn(queue_num);
-	hlist_add_head_rcu(&inst->hlist, &instance_table[h]);
-
-	spin_unlock(&instances_lock);
-
-	return inst;
-
-out_free:
-	kfree(inst);
-out_unlock:
-	spin_unlock(&instances_lock);
-	return ERR_PTR(err);
-}
-
-static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn,
-			unsigned long data);
-
-static void
-instance_destroy_rcu(struct rcu_head *head)
-{
-	struct nfqnl_instance *inst = container_of(head, struct nfqnl_instance,
-						   rcu);
-
-	nfqnl_flush(inst, NULL, 0);
-	kfree(inst);
-	module_put(THIS_MODULE);
-}
-
-static void
-__instance_destroy(struct nfqnl_instance *inst)
-{
-	hlist_del_rcu(&inst->hlist);
-	call_rcu(&inst->rcu, instance_destroy_rcu);
-}
-
-static void
-instance_destroy(struct nfqnl_instance *inst)
-{
-	spin_lock(&instances_lock);
-	__instance_destroy(inst);
-	spin_unlock(&instances_lock);
-}
-
-static inline void
-__enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
-{
-       list_add_tail(&entry->list, &queue->queue_list);
-       queue->queue_total++;
-}
-
-static void
-__dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
-{
-	list_del(&entry->list);
-	queue->queue_total--;
-}
-
-static struct nf_queue_entry *
-find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id)
-{
-	struct nf_queue_entry *entry = NULL, *i;
-
-	spin_lock_bh(&queue->lock);
-
-	list_for_each_entry(i, &queue->queue_list, list) {
-		if (i->id == id) {
-			entry = i;
-			break;
-		}
-	}
-
-	if (entry)
-		__dequeue_entry(queue, entry);
-
-	spin_unlock_bh(&queue->lock);
-
-	return entry;
-}
-
-static void
-nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
-{
-	struct nf_queue_entry *entry, *next;
-
-	spin_lock_bh(&queue->lock);
-	list_for_each_entry_safe(entry, next, &queue->queue_list, list) {
-		if (!cmpfn || cmpfn(entry, data)) {
-			list_del(&entry->list);
-			queue->queue_total--;
-			nf_reinject(entry, NF_DROP);
-		}
-	}
-	spin_unlock_bh(&queue->lock);
-}
-
-static struct sk_buff *
-nfqnl_build_packet_message(struct nfqnl_instance *queue,
-			   struct nf_queue_entry *entry,
-			   __be32 **packet_id_ptr)
-{
-	sk_buff_data_t old_tail;
-	size_t size;
-	size_t data_len = 0;
-	struct sk_buff *skb;
-	struct nlattr *nla;
-	struct nfqnl_msg_packet_hdr *pmsg;
-	struct nlmsghdr *nlh;
-	struct nfgenmsg *nfmsg;
-	struct sk_buff *entskb = entry->skb;
-	struct net_device *indev;
-	struct net_device *outdev;
-
-	size =    NLMSG_SPACE(sizeof(struct nfgenmsg))
-		+ nla_total_size(sizeof(struct nfqnl_msg_packet_hdr))
-		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
-		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
-#ifdef CONFIG_BRIDGE_NETFILTER
-		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
-		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
-#endif
-		+ nla_total_size(sizeof(u_int32_t))	/* mark */
-		+ nla_total_size(sizeof(struct nfqnl_msg_packet_hw))
-		+ nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp));
-
-	outdev = entry->outdev;
-
-	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))
-			return NULL;
-
-		data_len = ACCESS_ONCE(queue->copy_range);
-		if (data_len == 0 || data_len > entskb->len)
-			data_len = entskb->len;
-
-		size += nla_total_size(data_len);
-		break;
-	}
-
-
-	skb = alloc_skb(size, GFP_ATOMIC);
-	if (!skb)
-		goto nlmsg_failure;
-
-	old_tail = skb->tail;
-	nlh = NLMSG_PUT(skb, 0, 0,
-			NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
-			sizeof(struct nfgenmsg));
-	nfmsg = NLMSG_DATA(nlh);
-	nfmsg->nfgen_family = entry->pf;
-	nfmsg->version = NFNETLINK_V0;
-	nfmsg->res_id = htons(queue->queue_num);
-
-	nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg));
-	pmsg = nla_data(nla);
-	pmsg->hw_protocol	= entskb->protocol;
-	pmsg->hook		= entry->hook;
-	*packet_id_ptr		= &pmsg->packet_id;
-
-	indev = entry->indev;
-	if (indev) {
-#ifndef CONFIG_BRIDGE_NETFILTER
-		if (nla_put_be32(skb, NFQA_IFINDEX_INDEV, htonl(indev->ifindex)))
-			goto nla_put_failure;
-#else
-		if (entry->pf == PF_BRIDGE) {
-			/* Case 1: indev is physical input device, we need to
-			 * look for bridge group (when called from
-			 * netfilter_bridge) */
-			if (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(br_port_get_rcu(indev)->br->dev->ifindex)))
-				goto nla_put_failure;
-		} else {
-			/* Case 2: indev is bridge group, we need to look for
-			 * physical device (when called from ipv4) */
-			if (nla_put_be32(skb, NFQA_IFINDEX_INDEV,
-					 htonl(indev->ifindex)))
-				goto nla_put_failure;
-			if (entskb->nf_bridge && entskb->nf_bridge->physindev &&
-			    nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV,
-					 htonl(entskb->nf_bridge->physindev->ifindex)))
-				goto nla_put_failure;
-		}
-#endif
-	}
-
-	if (outdev) {
-#ifndef CONFIG_BRIDGE_NETFILTER
-		if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, htonl(outdev->ifindex)))
-			goto nla_put_failure;
-#else
-		if (entry->pf == PF_BRIDGE) {
-			/* Case 1: outdev is physical output device, we need to
-			 * look for bridge group (when called from
-			 * netfilter_bridge) */
-			if (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(br_port_get_rcu(outdev)->br->dev->ifindex)))
-				goto nla_put_failure;
-		} else {
-			/* Case 2: outdev is bridge group, we need to look for
-			 * physical output device (when called from ipv4) */
-			if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV,
-					 htonl(outdev->ifindex)))
-				goto nla_put_failure;
-			if (entskb->nf_bridge && entskb->nf_bridge->physoutdev &&
-			    nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV,
-					 htonl(entskb->nf_bridge->physoutdev->ifindex)))
-				goto nla_put_failure;
-		}
-#endif
-	}
-
-	if (entskb->mark &&
-	    nla_put_be32(skb, NFQA_MARK, htonl(entskb->mark)))
-		goto nla_put_failure;
-
-	if (indev && entskb->dev &&
-	    entskb->mac_header != entskb->network_header) {
-		struct nfqnl_msg_packet_hw phw;
-		int len = dev_parse_header(entskb, phw.hw_addr);
-		if (len) {
-			phw.hw_addrlen = htons(len);
-			if (nla_put(skb, NFQA_HWADDR, sizeof(phw), &phw))
-				goto nla_put_failure;
-		}
-	}
-
-	if (entskb->tstamp.tv64) {
-		struct nfqnl_msg_packet_timestamp ts;
-		struct timeval tv = ktime_to_timeval(entskb->tstamp);
-		ts.sec = cpu_to_be64(tv.tv_sec);
-		ts.usec = cpu_to_be64(tv.tv_usec);
-
-		if (nla_put(skb, NFQA_TIMESTAMP, sizeof(ts), &ts))
-			goto nla_put_failure;
-	}
-
-	if (data_len) {
-		struct nlattr *nla;
-		int sz = nla_attr_size(data_len);
-
-		if (skb_tailroom(skb) < nla_total_size(data_len)) {
-			printk(KERN_WARNING "nf_queue: no tailroom!\n");
-			goto nlmsg_failure;
-		}
-
-		nla = (struct nlattr *)skb_put(skb, nla_total_size(data_len));
-		nla->nla_type = NFQA_PAYLOAD;
-		nla->nla_len = sz;
-
-		if (skb_copy_bits(entskb, 0, nla_data(nla), data_len))
-			BUG();
-	}
-
-	nlh->nlmsg_len = skb->tail - old_tail;
-	return skb;
-
-nlmsg_failure:
-nla_put_failure:
-	if (skb)
-		kfree_skb(skb);
-	net_err_ratelimited("nf_queue: error creating packet message\n");
-	return NULL;
-}
-
-static int
-nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
-{
-	struct sk_buff *nskb;
-	struct nfqnl_instance *queue;
-	int err = -ENOBUFS;
-	__be32 *packet_id_ptr;
-
-	/* rcu_read_lock()ed by nf_hook_slow() */
-	queue = instance_lookup(queuenum);
-	if (!queue) {
-		err = -ESRCH;
-		goto err_out;
-	}
-
-	if (queue->copy_mode == NFQNL_COPY_NONE) {
-		err = -EINVAL;
-		goto err_out;
-	}
-
-	nskb = nfqnl_build_packet_message(queue, entry, &packet_id_ptr);
-	if (nskb == NULL) {
-		err = -ENOMEM;
-		goto err_out;
-	}
-	spin_lock_bh(&queue->lock);
-
-	if (!queue->peer_pid) {
-		err = -EINVAL;
-		goto err_out_free_nskb;
-	}
-	if (queue->queue_total >= queue->queue_maxlen) {
-		queue->queue_dropped++;
-		net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n",
-				     queue->queue_total);
-		goto err_out_free_nskb;
-	}
-	entry->id = ++queue->id_sequence;
-	*packet_id_ptr = htonl(entry->id);
-
-	/* nfnetlink_unicast will either free the nskb or add it to a socket */
-	err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT);
-	if (err < 0) {
-		queue->queue_user_dropped++;
-		goto err_out_unlock;
-	}
-
-	__enqueue_entry(queue, entry);
-
-	spin_unlock_bh(&queue->lock);
-	return 0;
-
-err_out_free_nskb:
-	kfree_skb(nskb);
-err_out_unlock:
-	spin_unlock_bh(&queue->lock);
-err_out:
-	return err;
-}
-
-static int
-nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e)
-{
-	struct sk_buff *nskb;
-	int diff;
-
-	diff = data_len - e->skb->len;
-	if (diff < 0) {
-		if (pskb_trim(e->skb, data_len))
-			return -ENOMEM;
-	} else if (diff > 0) {
-		if (data_len > 0xFFFF)
-			return -EINVAL;
-		if (diff > skb_tailroom(e->skb)) {
-			nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
-					       diff, GFP_ATOMIC);
-			if (!nskb) {
-				printk(KERN_WARNING "nf_queue: OOM "
-				      "in mangle, dropping packet\n");
-				return -ENOMEM;
-			}
-			kfree_skb(e->skb);
-			e->skb = nskb;
-		}
-		skb_put(e->skb, diff);
-	}
-	if (!skb_make_writable(e->skb, data_len))
-		return -ENOMEM;
-	skb_copy_to_linear_data(e->skb, data, data_len);
-	e->skb->ip_summed = CHECKSUM_NONE;
-	return 0;
-}
-
-static int
-nfqnl_set_mode(struct nfqnl_instance *queue,
-	       unsigned char mode, unsigned int range)
-{
-	int status = 0;
-
-	spin_lock_bh(&queue->lock);
-	switch (mode) {
-	case NFQNL_COPY_NONE:
-	case NFQNL_COPY_META:
-		queue->copy_mode = mode;
-		queue->copy_range = 0;
-		break;
-
-	case NFQNL_COPY_PACKET:
-		queue->copy_mode = mode;
-		/* we're using struct nlattr which has 16bit nla_len */
-		if (range > 0xffff)
-			queue->copy_range = 0xffff;
-		else
-			queue->copy_range = range;
-		break;
-
-	default:
-		status = -EINVAL;
-
-	}
-	spin_unlock_bh(&queue->lock);
-
-	return status;
-}
-
-static int
-dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
-{
-	if (entry->indev)
-		if (entry->indev->ifindex == ifindex)
-			return 1;
-	if (entry->outdev)
-		if (entry->outdev->ifindex == ifindex)
-			return 1;
-#ifdef CONFIG_BRIDGE_NETFILTER
-	if (entry->skb->nf_bridge) {
-		if (entry->skb->nf_bridge->physindev &&
-		    entry->skb->nf_bridge->physindev->ifindex == ifindex)
-			return 1;
-		if (entry->skb->nf_bridge->physoutdev &&
-		    entry->skb->nf_bridge->physoutdev->ifindex == ifindex)
-			return 1;
-	}
-#endif
-	return 0;
-}
-
-/* drop all packets with either indev or outdev == ifindex from all queue
- * instances */
-static void
-nfqnl_dev_drop(int ifindex)
-{
-	int i;
-
-	rcu_read_lock();
-
-	for (i = 0; i < INSTANCE_BUCKETS; i++) {
-		struct hlist_node *tmp;
-		struct nfqnl_instance *inst;
-		struct hlist_head *head = &instance_table[i];
-
-		hlist_for_each_entry_rcu(inst, tmp, head, hlist)
-			nfqnl_flush(inst, dev_cmp, ifindex);
-	}
-
-	rcu_read_unlock();
-}
-
-#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
-
-static int
-nfqnl_rcv_dev_event(struct notifier_block *this,
-		    unsigned long event, void *ptr)
-{
-	struct net_device *dev = ptr;
-
-	if (!net_eq(dev_net(dev), &init_net))
-		return NOTIFY_DONE;
-
-	/* Drop any packets associated with the downed device */
-	if (event == NETDEV_DOWN)
-		nfqnl_dev_drop(dev->ifindex);
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block nfqnl_dev_notifier = {
-	.notifier_call	= nfqnl_rcv_dev_event,
-};
-
-static int
-nfqnl_rcv_nl_event(struct notifier_block *this,
-		   unsigned long event, void *ptr)
-{
-	struct netlink_notify *n = ptr;
-
-	if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) {
-		int i;
-
-		/* destroy all instances for this pid */
-		spin_lock(&instances_lock);
-		for (i = 0; i < INSTANCE_BUCKETS; i++) {
-			struct hlist_node *tmp, *t2;
-			struct nfqnl_instance *inst;
-			struct hlist_head *head = &instance_table[i];
-
-			hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) {
-				if ((n->net == &init_net) &&
-				    (n->pid == inst->peer_pid))
-					__instance_destroy(inst);
-			}
-		}
-		spin_unlock(&instances_lock);
-	}
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block nfqnl_rtnl_notifier = {
-	.notifier_call	= nfqnl_rcv_nl_event,
-};
-
-static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = {
-	[NFQA_VERDICT_HDR]	= { .len = sizeof(struct nfqnl_msg_verdict_hdr) },
-	[NFQA_MARK]		= { .type = NLA_U32 },
-	[NFQA_PAYLOAD]		= { .type = NLA_UNSPEC },
-};
-
-static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
-	[NFQA_VERDICT_HDR]	= { .len = sizeof(struct nfqnl_msg_verdict_hdr) },
-	[NFQA_MARK]		= { .type = NLA_U32 },
-};
-
-static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlpid)
-{
-	struct nfqnl_instance *queue;
-
-	queue = instance_lookup(queue_num);
-	if (!queue)
-		return ERR_PTR(-ENODEV);
-
-	if (queue->peer_pid != nlpid)
-		return ERR_PTR(-EPERM);
-
-	return queue;
-}
-
-static struct nfqnl_msg_verdict_hdr*
-verdicthdr_get(const struct nlattr * const nfqa[])
-{
-	struct nfqnl_msg_verdict_hdr *vhdr;
-	unsigned int verdict;
-
-	if (!nfqa[NFQA_VERDICT_HDR])
-		return NULL;
-
-	vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
-	verdict = ntohl(vhdr->verdict) & NF_VERDICT_MASK;
-	if (verdict > NF_MAX_VERDICT || verdict == NF_STOLEN)
-		return NULL;
-	return vhdr;
-}
-
-static int nfq_id_after(unsigned int id, unsigned int max)
-{
-	return (int)(id - max) > 0;
-}
-
-static int
-nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
-		   const struct nlmsghdr *nlh,
-		   const struct nlattr * const nfqa[])
-{
-	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
-	struct nf_queue_entry *entry, *tmp;
-	unsigned int verdict, maxid;
-	struct nfqnl_msg_verdict_hdr *vhdr;
-	struct nfqnl_instance *queue;
-	LIST_HEAD(batch_list);
-	u16 queue_num = ntohs(nfmsg->res_id);
-
-	queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
-	if (IS_ERR(queue))
-		return PTR_ERR(queue);
-
-	vhdr = verdicthdr_get(nfqa);
-	if (!vhdr)
-		return -EINVAL;
-
-	verdict = ntohl(vhdr->verdict);
-	maxid = ntohl(vhdr->id);
-
-	spin_lock_bh(&queue->lock);
-
-	list_for_each_entry_safe(entry, tmp, &queue->queue_list, list) {
-		if (nfq_id_after(entry->id, maxid))
-			break;
-		__dequeue_entry(queue, entry);
-		list_add_tail(&entry->list, &batch_list);
-	}
-
-	spin_unlock_bh(&queue->lock);
-
-	if (list_empty(&batch_list))
-		return -ENOENT;
-
-	list_for_each_entry_safe(entry, tmp, &batch_list, list) {
-		if (nfqa[NFQA_MARK])
-			entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
-		nf_reinject(entry, verdict);
-	}
-	return 0;
-}
-
-static int
-nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
-		   const struct nlmsghdr *nlh,
-		   const struct nlattr * const nfqa[])
-{
-	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
-	u_int16_t queue_num = ntohs(nfmsg->res_id);
-
-	struct nfqnl_msg_verdict_hdr *vhdr;
-	struct nfqnl_instance *queue;
-	unsigned int verdict;
-	struct nf_queue_entry *entry;
-
-	queue = instance_lookup(queue_num);
-	if (!queue)
-
-	queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
-	if (IS_ERR(queue))
-		return PTR_ERR(queue);
-
-	vhdr = verdicthdr_get(nfqa);
-	if (!vhdr)
-		return -EINVAL;
-
-	verdict = ntohl(vhdr->verdict);
-
-	entry = find_dequeue_entry(queue, ntohl(vhdr->id));
-	if (entry == NULL)
-		return -ENOENT;
-
-	if (nfqa[NFQA_PAYLOAD]) {
-		if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]),
-				 nla_len(nfqa[NFQA_PAYLOAD]), entry) < 0)
-			verdict = NF_DROP;
-	}
-
-	if (nfqa[NFQA_MARK])
-		entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
-
-	nf_reinject(entry, verdict);
-	return 0;
-}
-
-static int
-nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
-		  const struct nlmsghdr *nlh,
-		  const struct nlattr * const nfqa[])
-{
-	return -ENOTSUPP;
-}
-
-static const struct nla_policy nfqa_cfg_policy[NFQA_CFG_MAX+1] = {
-	[NFQA_CFG_CMD]		= { .len = sizeof(struct nfqnl_msg_config_cmd) },
-	[NFQA_CFG_PARAMS]	= { .len = sizeof(struct nfqnl_msg_config_params) },
-};
-
-static const struct nf_queue_handler nfqh = {
-	.name 	= "nf_queue",
-	.outfn	= &nfqnl_enqueue_packet,
-};
-
-static int
-nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
-		  const struct nlmsghdr *nlh,
-		  const struct nlattr * const nfqa[])
-{
-	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
-	u_int16_t queue_num = ntohs(nfmsg->res_id);
-	struct nfqnl_instance *queue;
-	struct nfqnl_msg_config_cmd *cmd = NULL;
-	int ret = 0;
-
-	if (nfqa[NFQA_CFG_CMD]) {
-		cmd = nla_data(nfqa[NFQA_CFG_CMD]);
-
-		/* Commands without queue context - might sleep */
-		switch (cmd->command) {
-		case NFQNL_CFG_CMD_PF_BIND:
-			return nf_register_queue_handler(ntohs(cmd->pf),
-							 &nfqh);
-		case NFQNL_CFG_CMD_PF_UNBIND:
-			return nf_unregister_queue_handler(ntohs(cmd->pf),
-							   &nfqh);
-		}
-	}
-
-	rcu_read_lock();
-	queue = instance_lookup(queue_num);
-	if (queue && queue->peer_pid != NETLINK_CB(skb).pid) {
-		ret = -EPERM;
-		goto err_out_unlock;
-	}
-
-	if (cmd != NULL) {
-		switch (cmd->command) {
-		case NFQNL_CFG_CMD_BIND:
-			if (queue) {
-				ret = -EBUSY;
-				goto err_out_unlock;
-			}
-			queue = instance_create(queue_num, NETLINK_CB(skb).pid);
-			if (IS_ERR(queue)) {
-				ret = PTR_ERR(queue);
-				goto err_out_unlock;
-			}
-			break;
-		case NFQNL_CFG_CMD_UNBIND:
-			if (!queue) {
-				ret = -ENODEV;
-				goto err_out_unlock;
-			}
-			instance_destroy(queue);
-			break;
-		case NFQNL_CFG_CMD_PF_BIND:
-		case NFQNL_CFG_CMD_PF_UNBIND:
-			break;
-		default:
-			ret = -ENOTSUPP;
-			break;
-		}
-	}
-
-	if (nfqa[NFQA_CFG_PARAMS]) {
-		struct nfqnl_msg_config_params *params;
-
-		if (!queue) {
-			ret = -ENODEV;
-			goto err_out_unlock;
-		}
-		params = nla_data(nfqa[NFQA_CFG_PARAMS]);
-		nfqnl_set_mode(queue, params->copy_mode,
-				ntohl(params->copy_range));
-	}
-
-	if (nfqa[NFQA_CFG_QUEUE_MAXLEN]) {
-		__be32 *queue_maxlen;
-
-		if (!queue) {
-			ret = -ENODEV;
-			goto err_out_unlock;
-		}
-		queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]);
-		spin_lock_bh(&queue->lock);
-		queue->queue_maxlen = ntohl(*queue_maxlen);
-		spin_unlock_bh(&queue->lock);
-	}
-
-err_out_unlock:
-	rcu_read_unlock();
-	return ret;
-}
-
-static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
-	[NFQNL_MSG_PACKET]	= { .call_rcu = nfqnl_recv_unsupp,
-				    .attr_count = NFQA_MAX, },
-	[NFQNL_MSG_VERDICT]	= { .call_rcu = nfqnl_recv_verdict,
-				    .attr_count = NFQA_MAX,
-				    .policy = nfqa_verdict_policy },
-	[NFQNL_MSG_CONFIG]	= { .call = nfqnl_recv_config,
-				    .attr_count = NFQA_CFG_MAX,
-				    .policy = nfqa_cfg_policy },
-	[NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch,
-				    .attr_count = NFQA_MAX,
-				    .policy = nfqa_verdict_batch_policy },
-};
-
-static const struct nfnetlink_subsystem nfqnl_subsys = {
-	.name		= "nf_queue",
-	.subsys_id	= NFNL_SUBSYS_QUEUE,
-	.cb_count	= NFQNL_MSG_MAX,
-	.cb		= nfqnl_cb,
-};
-
-#ifdef CONFIG_PROC_FS
-struct iter_state {
-	unsigned int bucket;
-};
-
-static struct hlist_node *get_first(struct seq_file *seq)
-{
-	struct iter_state *st = seq->private;
-
-	if (!st)
-		return NULL;
-
-	for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
-		if (!hlist_empty(&instance_table[st->bucket]))
-			return instance_table[st->bucket].first;
-	}
-	return NULL;
-}
-
-static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
-{
-	struct iter_state *st = seq->private;
-
-	h = h->next;
-	while (!h) {
-		if (++st->bucket >= INSTANCE_BUCKETS)
-			return NULL;
-
-		h = instance_table[st->bucket].first;
-	}
-	return h;
-}
-
-static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
-{
-	struct hlist_node *head;
-	head = get_first(seq);
-
-	if (head)
-		while (pos && (head = get_next(seq, head)))
-			pos--;
-	return pos ? NULL : head;
-}
-
-static void *seq_start(struct seq_file *seq, loff_t *pos)
-	__acquires(instances_lock)
-{
-	spin_lock(&instances_lock);
-	return get_idx(seq, *pos);
-}
-
-static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
-{
-	(*pos)++;
-	return get_next(s, v);
-}
-
-static void seq_stop(struct seq_file *s, void *v)
-	__releases(instances_lock)
-{
-	spin_unlock(&instances_lock);
-}
-
-static int seq_show(struct seq_file *s, void *v)
-{
-	const struct nfqnl_instance *inst = v;
-
-	return seq_printf(s, "%5d %6d %5d %1d %5d %5d %5d %8d %2d\n",
-			  inst->queue_num,
-			  inst->peer_pid, inst->queue_total,
-			  inst->copy_mode, inst->copy_range,
-			  inst->queue_dropped, inst->queue_user_dropped,
-			  inst->id_sequence, 1);
-}
-
-static const struct seq_operations nfqnl_seq_ops = {
-	.start	= seq_start,
-	.next	= seq_next,
-	.stop	= seq_stop,
-	.show	= seq_show,
-};
-
-static int nfqnl_open(struct inode *inode, struct file *file)
-{
-	return seq_open_private(file, &nfqnl_seq_ops,
-			sizeof(struct iter_state));
-}
-
-static const struct file_operations nfqnl_file_ops = {
-	.owner	 = THIS_MODULE,
-	.open	 = nfqnl_open,
-	.read	 = seq_read,
-	.llseek	 = seq_lseek,
-	.release = seq_release_private,
-};
-
-#endif /* PROC_FS */
-
-static int __init nfnetlink_queue_init(void)
-{
-	int i, status = -ENOMEM;
-
-	for (i = 0; i < INSTANCE_BUCKETS; i++)
-		INIT_HLIST_HEAD(&instance_table[i]);
-
-	netlink_register_notifier(&nfqnl_rtnl_notifier);
-	status = nfnetlink_subsys_register(&nfqnl_subsys);
-	if (status < 0) {
-		printk(KERN_ERR "nf_queue: failed to create netlink socket\n");
-		goto cleanup_netlink_notifier;
-	}
-
-#ifdef CONFIG_PROC_FS
-	if (!proc_create("nfnetlink_queue", 0440,
-			 proc_net_netfilter, &nfqnl_file_ops))
-		goto cleanup_subsys;
-#endif
-
-	register_netdevice_notifier(&nfqnl_dev_notifier);
-	return status;
-
-#ifdef CONFIG_PROC_FS
-cleanup_subsys:
-	nfnetlink_subsys_unregister(&nfqnl_subsys);
-#endif
-cleanup_netlink_notifier:
-	netlink_unregister_notifier(&nfqnl_rtnl_notifier);
-	return status;
-}
-
-static void __exit nfnetlink_queue_fini(void)
-{
-	nf_unregister_queue_handlers(&nfqh);
-	unregister_netdevice_notifier(&nfqnl_dev_notifier);
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
-#endif
-	nfnetlink_subsys_unregister(&nfqnl_subsys);
-	netlink_unregister_notifier(&nfqnl_rtnl_notifier);
-
-	rcu_barrier(); /* Wait for completion of call_rcu()'s */
-}
-
-MODULE_DESCRIPTION("netfilter packet queue handler");
-MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_QUEUE);
-
-module_init(nfnetlink_queue_init);
-module_exit(nfnetlink_queue_fini);
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
new file mode 100644
index 0000000..d36b95e
--- /dev/null
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -0,0 +1,1090 @@
+/*
+ * This is a module which is used for queueing packets and communicating with
+ * userspace via nfnetlink.
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ * (C) 2007 by Patrick McHardy <kaber@trash.net>
+ *
+ * Based on the old ipv4-only ip_queue.c:
+ * (C) 2000-2002 James Morris <jmorris@intercode.com.au>
+ * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/proc_fs.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <linux/list.h>
+#include <net/sock.h>
+#include <net/netfilter/nf_queue.h>
+#include <net/netfilter/nfnetlink_queue.h>
+
+#include <linux/atomic.h>
+
+#ifdef CONFIG_BRIDGE_NETFILTER
+#include "../bridge/br_private.h"
+#endif
+
+#define NFQNL_QMAX_DEFAULT 1024
+
+struct nfqnl_instance {
+	struct hlist_node hlist;		/* global list of queues */
+	struct rcu_head rcu;
+
+	int peer_pid;
+	unsigned int queue_maxlen;
+	unsigned int copy_range;
+	unsigned int queue_dropped;
+	unsigned int queue_user_dropped;
+
+
+	u_int16_t queue_num;			/* number of this queue */
+	u_int8_t copy_mode;
+	u_int32_t flags;			/* Set using NFQA_CFG_FLAGS */
+/*
+ * Following fields are dirtied for each queued packet,
+ * keep them in same cache line if possible.
+ */
+	spinlock_t	lock;
+	unsigned int	queue_total;
+	unsigned int	id_sequence;		/* 'sequence' of pkt ids */
+	struct list_head queue_list;		/* packets in queue */
+};
+
+typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long);
+
+static DEFINE_SPINLOCK(instances_lock);
+
+#define INSTANCE_BUCKETS	16
+static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly;
+
+static inline u_int8_t instance_hashfn(u_int16_t queue_num)
+{
+	return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS;
+}
+
+static struct nfqnl_instance *
+instance_lookup(u_int16_t queue_num)
+{
+	struct hlist_head *head;
+	struct hlist_node *pos;
+	struct nfqnl_instance *inst;
+
+	head = &instance_table[instance_hashfn(queue_num)];
+	hlist_for_each_entry_rcu(inst, pos, head, hlist) {
+		if (inst->queue_num == queue_num)
+			return inst;
+	}
+	return NULL;
+}
+
+static struct nfqnl_instance *
+instance_create(u_int16_t queue_num, int pid)
+{
+	struct nfqnl_instance *inst;
+	unsigned int h;
+	int err;
+
+	spin_lock(&instances_lock);
+	if (instance_lookup(queue_num)) {
+		err = -EEXIST;
+		goto out_unlock;
+	}
+
+	inst = kzalloc(sizeof(*inst), GFP_ATOMIC);
+	if (!inst) {
+		err = -ENOMEM;
+		goto out_unlock;
+	}
+
+	inst->queue_num = queue_num;
+	inst->peer_pid = pid;
+	inst->queue_maxlen = NFQNL_QMAX_DEFAULT;
+	inst->copy_range = 0xfffff;
+	inst->copy_mode = NFQNL_COPY_NONE;
+	spin_lock_init(&inst->lock);
+	INIT_LIST_HEAD(&inst->queue_list);
+
+	if (!try_module_get(THIS_MODULE)) {
+		err = -EAGAIN;
+		goto out_free;
+	}
+
+	h = instance_hashfn(queue_num);
+	hlist_add_head_rcu(&inst->hlist, &instance_table[h]);
+
+	spin_unlock(&instances_lock);
+
+	return inst;
+
+out_free:
+	kfree(inst);
+out_unlock:
+	spin_unlock(&instances_lock);
+	return ERR_PTR(err);
+}
+
+static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn,
+			unsigned long data);
+
+static void
+instance_destroy_rcu(struct rcu_head *head)
+{
+	struct nfqnl_instance *inst = container_of(head, struct nfqnl_instance,
+						   rcu);
+
+	nfqnl_flush(inst, NULL, 0);
+	kfree(inst);
+	module_put(THIS_MODULE);
+}
+
+static void
+__instance_destroy(struct nfqnl_instance *inst)
+{
+	hlist_del_rcu(&inst->hlist);
+	call_rcu(&inst->rcu, instance_destroy_rcu);
+}
+
+static void
+instance_destroy(struct nfqnl_instance *inst)
+{
+	spin_lock(&instances_lock);
+	__instance_destroy(inst);
+	spin_unlock(&instances_lock);
+}
+
+static inline void
+__enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
+{
+       list_add_tail(&entry->list, &queue->queue_list);
+       queue->queue_total++;
+}
+
+static void
+__dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
+{
+	list_del(&entry->list);
+	queue->queue_total--;
+}
+
+static struct nf_queue_entry *
+find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id)
+{
+	struct nf_queue_entry *entry = NULL, *i;
+
+	spin_lock_bh(&queue->lock);
+
+	list_for_each_entry(i, &queue->queue_list, list) {
+		if (i->id == id) {
+			entry = i;
+			break;
+		}
+	}
+
+	if (entry)
+		__dequeue_entry(queue, entry);
+
+	spin_unlock_bh(&queue->lock);
+
+	return entry;
+}
+
+static void
+nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
+{
+	struct nf_queue_entry *entry, *next;
+
+	spin_lock_bh(&queue->lock);
+	list_for_each_entry_safe(entry, next, &queue->queue_list, list) {
+		if (!cmpfn || cmpfn(entry, data)) {
+			list_del(&entry->list);
+			queue->queue_total--;
+			nf_reinject(entry, NF_DROP);
+		}
+	}
+	spin_unlock_bh(&queue->lock);
+}
+
+static struct sk_buff *
+nfqnl_build_packet_message(struct nfqnl_instance *queue,
+			   struct nf_queue_entry *entry,
+			   __be32 **packet_id_ptr)
+{
+	sk_buff_data_t old_tail;
+	size_t size;
+	size_t data_len = 0;
+	struct sk_buff *skb;
+	struct nlattr *nla;
+	struct nfqnl_msg_packet_hdr *pmsg;
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfmsg;
+	struct sk_buff *entskb = entry->skb;
+	struct net_device *indev;
+	struct net_device *outdev;
+	struct nf_conn *ct = NULL;
+	enum ip_conntrack_info uninitialized_var(ctinfo);
+
+	size =    NLMSG_SPACE(sizeof(struct nfgenmsg))
+		+ nla_total_size(sizeof(struct nfqnl_msg_packet_hdr))
+		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
+		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
+#ifdef CONFIG_BRIDGE_NETFILTER
+		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
+		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
+#endif
+		+ nla_total_size(sizeof(u_int32_t))	/* mark */
+		+ nla_total_size(sizeof(struct nfqnl_msg_packet_hw))
+		+ nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp));
+
+	outdev = entry->outdev;
+
+	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))
+			return NULL;
+
+		data_len = ACCESS_ONCE(queue->copy_range);
+		if (data_len == 0 || data_len > entskb->len)
+			data_len = entskb->len;
+
+		size += nla_total_size(data_len);
+		break;
+	}
+
+	if (queue->flags & NFQA_CFG_F_CONNTRACK)
+		ct = nfqnl_ct_get(entskb, &size, &ctinfo);
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		goto nlmsg_failure;
+
+	old_tail = skb->tail;
+	nlh = NLMSG_PUT(skb, 0, 0,
+			NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
+			sizeof(struct nfgenmsg));
+	nfmsg = NLMSG_DATA(nlh);
+	nfmsg->nfgen_family = entry->pf;
+	nfmsg->version = NFNETLINK_V0;
+	nfmsg->res_id = htons(queue->queue_num);
+
+	nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg));
+	pmsg = nla_data(nla);
+	pmsg->hw_protocol	= entskb->protocol;
+	pmsg->hook		= entry->hook;
+	*packet_id_ptr		= &pmsg->packet_id;
+
+	indev = entry->indev;
+	if (indev) {
+#ifndef CONFIG_BRIDGE_NETFILTER
+		if (nla_put_be32(skb, NFQA_IFINDEX_INDEV, htonl(indev->ifindex)))
+			goto nla_put_failure;
+#else
+		if (entry->pf == PF_BRIDGE) {
+			/* Case 1: indev is physical input device, we need to
+			 * look for bridge group (when called from
+			 * netfilter_bridge) */
+			if (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(br_port_get_rcu(indev)->br->dev->ifindex)))
+				goto nla_put_failure;
+		} else {
+			/* Case 2: indev is bridge group, we need to look for
+			 * physical device (when called from ipv4) */
+			if (nla_put_be32(skb, NFQA_IFINDEX_INDEV,
+					 htonl(indev->ifindex)))
+				goto nla_put_failure;
+			if (entskb->nf_bridge && entskb->nf_bridge->physindev &&
+			    nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV,
+					 htonl(entskb->nf_bridge->physindev->ifindex)))
+				goto nla_put_failure;
+		}
+#endif
+	}
+
+	if (outdev) {
+#ifndef CONFIG_BRIDGE_NETFILTER
+		if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, htonl(outdev->ifindex)))
+			goto nla_put_failure;
+#else
+		if (entry->pf == PF_BRIDGE) {
+			/* Case 1: outdev is physical output device, we need to
+			 * look for bridge group (when called from
+			 * netfilter_bridge) */
+			if (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(br_port_get_rcu(outdev)->br->dev->ifindex)))
+				goto nla_put_failure;
+		} else {
+			/* Case 2: outdev is bridge group, we need to look for
+			 * physical output device (when called from ipv4) */
+			if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV,
+					 htonl(outdev->ifindex)))
+				goto nla_put_failure;
+			if (entskb->nf_bridge && entskb->nf_bridge->physoutdev &&
+			    nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV,
+					 htonl(entskb->nf_bridge->physoutdev->ifindex)))
+				goto nla_put_failure;
+		}
+#endif
+	}
+
+	if (entskb->mark &&
+	    nla_put_be32(skb, NFQA_MARK, htonl(entskb->mark)))
+		goto nla_put_failure;
+
+	if (indev && entskb->dev &&
+	    entskb->mac_header != entskb->network_header) {
+		struct nfqnl_msg_packet_hw phw;
+		int len = dev_parse_header(entskb, phw.hw_addr);
+		if (len) {
+			phw.hw_addrlen = htons(len);
+			if (nla_put(skb, NFQA_HWADDR, sizeof(phw), &phw))
+				goto nla_put_failure;
+		}
+	}
+
+	if (entskb->tstamp.tv64) {
+		struct nfqnl_msg_packet_timestamp ts;
+		struct timeval tv = ktime_to_timeval(entskb->tstamp);
+		ts.sec = cpu_to_be64(tv.tv_sec);
+		ts.usec = cpu_to_be64(tv.tv_usec);
+
+		if (nla_put(skb, NFQA_TIMESTAMP, sizeof(ts), &ts))
+			goto nla_put_failure;
+	}
+
+	if (data_len) {
+		struct nlattr *nla;
+		int sz = nla_attr_size(data_len);
+
+		if (skb_tailroom(skb) < nla_total_size(data_len)) {
+			printk(KERN_WARNING "nf_queue: no tailroom!\n");
+			goto nlmsg_failure;
+		}
+
+		nla = (struct nlattr *)skb_put(skb, nla_total_size(data_len));
+		nla->nla_type = NFQA_PAYLOAD;
+		nla->nla_len = sz;
+
+		if (skb_copy_bits(entskb, 0, nla_data(nla), data_len))
+			BUG();
+	}
+
+	if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0)
+		goto nla_put_failure;
+
+	nlh->nlmsg_len = skb->tail - old_tail;
+	return skb;
+
+nlmsg_failure:
+nla_put_failure:
+	if (skb)
+		kfree_skb(skb);
+	net_err_ratelimited("nf_queue: error creating packet message\n");
+	return NULL;
+}
+
+static int
+nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+{
+	struct sk_buff *nskb;
+	struct nfqnl_instance *queue;
+	int err = -ENOBUFS;
+	__be32 *packet_id_ptr;
+	int failopen = 0;
+
+	/* rcu_read_lock()ed by nf_hook_slow() */
+	queue = instance_lookup(queuenum);
+	if (!queue) {
+		err = -ESRCH;
+		goto err_out;
+	}
+
+	if (queue->copy_mode == NFQNL_COPY_NONE) {
+		err = -EINVAL;
+		goto err_out;
+	}
+
+	nskb = nfqnl_build_packet_message(queue, entry, &packet_id_ptr);
+	if (nskb == NULL) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+	spin_lock_bh(&queue->lock);
+
+	if (!queue->peer_pid) {
+		err = -EINVAL;
+		goto err_out_free_nskb;
+	}
+	if (queue->queue_total >= queue->queue_maxlen) {
+		if (queue->flags & NFQA_CFG_F_FAIL_OPEN) {
+			failopen = 1;
+			err = 0;
+		} else {
+			queue->queue_dropped++;
+			net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n",
+					     queue->queue_total);
+		}
+		goto err_out_free_nskb;
+	}
+	entry->id = ++queue->id_sequence;
+	*packet_id_ptr = htonl(entry->id);
+
+	/* nfnetlink_unicast will either free the nskb or add it to a socket */
+	err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT);
+	if (err < 0) {
+		queue->queue_user_dropped++;
+		goto err_out_unlock;
+	}
+
+	__enqueue_entry(queue, entry);
+
+	spin_unlock_bh(&queue->lock);
+	return 0;
+
+err_out_free_nskb:
+	kfree_skb(nskb);
+err_out_unlock:
+	spin_unlock_bh(&queue->lock);
+	if (failopen)
+		nf_reinject(entry, NF_ACCEPT);
+err_out:
+	return err;
+}
+
+static int
+nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff)
+{
+	struct sk_buff *nskb;
+
+	if (diff < 0) {
+		if (pskb_trim(e->skb, data_len))
+			return -ENOMEM;
+	} else if (diff > 0) {
+		if (data_len > 0xFFFF)
+			return -EINVAL;
+		if (diff > skb_tailroom(e->skb)) {
+			nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
+					       diff, GFP_ATOMIC);
+			if (!nskb) {
+				printk(KERN_WARNING "nf_queue: OOM "
+				      "in mangle, dropping packet\n");
+				return -ENOMEM;
+			}
+			kfree_skb(e->skb);
+			e->skb = nskb;
+		}
+		skb_put(e->skb, diff);
+	}
+	if (!skb_make_writable(e->skb, data_len))
+		return -ENOMEM;
+	skb_copy_to_linear_data(e->skb, data, data_len);
+	e->skb->ip_summed = CHECKSUM_NONE;
+	return 0;
+}
+
+static int
+nfqnl_set_mode(struct nfqnl_instance *queue,
+	       unsigned char mode, unsigned int range)
+{
+	int status = 0;
+
+	spin_lock_bh(&queue->lock);
+	switch (mode) {
+	case NFQNL_COPY_NONE:
+	case NFQNL_COPY_META:
+		queue->copy_mode = mode;
+		queue->copy_range = 0;
+		break;
+
+	case NFQNL_COPY_PACKET:
+		queue->copy_mode = mode;
+		/* we're using struct nlattr which has 16bit nla_len */
+		if (range > 0xffff)
+			queue->copy_range = 0xffff;
+		else
+			queue->copy_range = range;
+		break;
+
+	default:
+		status = -EINVAL;
+
+	}
+	spin_unlock_bh(&queue->lock);
+
+	return status;
+}
+
+static int
+dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
+{
+	if (entry->indev)
+		if (entry->indev->ifindex == ifindex)
+			return 1;
+	if (entry->outdev)
+		if (entry->outdev->ifindex == ifindex)
+			return 1;
+#ifdef CONFIG_BRIDGE_NETFILTER
+	if (entry->skb->nf_bridge) {
+		if (entry->skb->nf_bridge->physindev &&
+		    entry->skb->nf_bridge->physindev->ifindex == ifindex)
+			return 1;
+		if (entry->skb->nf_bridge->physoutdev &&
+		    entry->skb->nf_bridge->physoutdev->ifindex == ifindex)
+			return 1;
+	}
+#endif
+	return 0;
+}
+
+/* drop all packets with either indev or outdev == ifindex from all queue
+ * instances */
+static void
+nfqnl_dev_drop(int ifindex)
+{
+	int i;
+
+	rcu_read_lock();
+
+	for (i = 0; i < INSTANCE_BUCKETS; i++) {
+		struct hlist_node *tmp;
+		struct nfqnl_instance *inst;
+		struct hlist_head *head = &instance_table[i];
+
+		hlist_for_each_entry_rcu(inst, tmp, head, hlist)
+			nfqnl_flush(inst, dev_cmp, ifindex);
+	}
+
+	rcu_read_unlock();
+}
+
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
+
+static int
+nfqnl_rcv_dev_event(struct notifier_block *this,
+		    unsigned long event, void *ptr)
+{
+	struct net_device *dev = ptr;
+
+	if (!net_eq(dev_net(dev), &init_net))
+		return NOTIFY_DONE;
+
+	/* Drop any packets associated with the downed device */
+	if (event == NETDEV_DOWN)
+		nfqnl_dev_drop(dev->ifindex);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block nfqnl_dev_notifier = {
+	.notifier_call	= nfqnl_rcv_dev_event,
+};
+
+static int
+nfqnl_rcv_nl_event(struct notifier_block *this,
+		   unsigned long event, void *ptr)
+{
+	struct netlink_notify *n = ptr;
+
+	if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) {
+		int i;
+
+		/* destroy all instances for this pid */
+		spin_lock(&instances_lock);
+		for (i = 0; i < INSTANCE_BUCKETS; i++) {
+			struct hlist_node *tmp, *t2;
+			struct nfqnl_instance *inst;
+			struct hlist_head *head = &instance_table[i];
+
+			hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) {
+				if ((n->net == &init_net) &&
+				    (n->pid == inst->peer_pid))
+					__instance_destroy(inst);
+			}
+		}
+		spin_unlock(&instances_lock);
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block nfqnl_rtnl_notifier = {
+	.notifier_call	= nfqnl_rcv_nl_event,
+};
+
+static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = {
+	[NFQA_VERDICT_HDR]	= { .len = sizeof(struct nfqnl_msg_verdict_hdr) },
+	[NFQA_MARK]		= { .type = NLA_U32 },
+	[NFQA_PAYLOAD]		= { .type = NLA_UNSPEC },
+	[NFQA_CT]		= { .type = NLA_UNSPEC },
+};
+
+static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
+	[NFQA_VERDICT_HDR]	= { .len = sizeof(struct nfqnl_msg_verdict_hdr) },
+	[NFQA_MARK]		= { .type = NLA_U32 },
+};
+
+static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlpid)
+{
+	struct nfqnl_instance *queue;
+
+	queue = instance_lookup(queue_num);
+	if (!queue)
+		return ERR_PTR(-ENODEV);
+
+	if (queue->peer_pid != nlpid)
+		return ERR_PTR(-EPERM);
+
+	return queue;
+}
+
+static struct nfqnl_msg_verdict_hdr*
+verdicthdr_get(const struct nlattr * const nfqa[])
+{
+	struct nfqnl_msg_verdict_hdr *vhdr;
+	unsigned int verdict;
+
+	if (!nfqa[NFQA_VERDICT_HDR])
+		return NULL;
+
+	vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
+	verdict = ntohl(vhdr->verdict) & NF_VERDICT_MASK;
+	if (verdict > NF_MAX_VERDICT || verdict == NF_STOLEN)
+		return NULL;
+	return vhdr;
+}
+
+static int nfq_id_after(unsigned int id, unsigned int max)
+{
+	return (int)(id - max) > 0;
+}
+
+static int
+nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
+		   const struct nlmsghdr *nlh,
+		   const struct nlattr * const nfqa[])
+{
+	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
+	struct nf_queue_entry *entry, *tmp;
+	unsigned int verdict, maxid;
+	struct nfqnl_msg_verdict_hdr *vhdr;
+	struct nfqnl_instance *queue;
+	LIST_HEAD(batch_list);
+	u16 queue_num = ntohs(nfmsg->res_id);
+
+	queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
+	if (IS_ERR(queue))
+		return PTR_ERR(queue);
+
+	vhdr = verdicthdr_get(nfqa);
+	if (!vhdr)
+		return -EINVAL;
+
+	verdict = ntohl(vhdr->verdict);
+	maxid = ntohl(vhdr->id);
+
+	spin_lock_bh(&queue->lock);
+
+	list_for_each_entry_safe(entry, tmp, &queue->queue_list, list) {
+		if (nfq_id_after(entry->id, maxid))
+			break;
+		__dequeue_entry(queue, entry);
+		list_add_tail(&entry->list, &batch_list);
+	}
+
+	spin_unlock_bh(&queue->lock);
+
+	if (list_empty(&batch_list))
+		return -ENOENT;
+
+	list_for_each_entry_safe(entry, tmp, &batch_list, list) {
+		if (nfqa[NFQA_MARK])
+			entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
+		nf_reinject(entry, verdict);
+	}
+	return 0;
+}
+
+static int
+nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
+		   const struct nlmsghdr *nlh,
+		   const struct nlattr * const nfqa[])
+{
+	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
+	u_int16_t queue_num = ntohs(nfmsg->res_id);
+
+	struct nfqnl_msg_verdict_hdr *vhdr;
+	struct nfqnl_instance *queue;
+	unsigned int verdict;
+	struct nf_queue_entry *entry;
+	enum ip_conntrack_info uninitialized_var(ctinfo);
+	struct nf_conn *ct = NULL;
+
+	queue = instance_lookup(queue_num);
+	if (!queue)
+
+	queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
+	if (IS_ERR(queue))
+		return PTR_ERR(queue);
+
+	vhdr = verdicthdr_get(nfqa);
+	if (!vhdr)
+		return -EINVAL;
+
+	verdict = ntohl(vhdr->verdict);
+
+	entry = find_dequeue_entry(queue, ntohl(vhdr->id));
+	if (entry == NULL)
+		return -ENOENT;
+
+	rcu_read_lock();
+	if (nfqa[NFQA_CT] && (queue->flags & NFQA_CFG_F_CONNTRACK))
+		ct = nfqnl_ct_parse(entry->skb, nfqa[NFQA_CT], &ctinfo);
+
+	if (nfqa[NFQA_PAYLOAD]) {
+		u16 payload_len = nla_len(nfqa[NFQA_PAYLOAD]);
+		int diff = payload_len - entry->skb->len;
+
+		if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]),
+				 payload_len, entry, diff) < 0)
+			verdict = NF_DROP;
+
+		if (ct)
+			nfqnl_ct_seq_adjust(skb, ct, ctinfo, diff);
+	}
+	rcu_read_unlock();
+
+	if (nfqa[NFQA_MARK])
+		entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
+
+	nf_reinject(entry, verdict);
+	return 0;
+}
+
+static int
+nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
+		  const struct nlmsghdr *nlh,
+		  const struct nlattr * const nfqa[])
+{
+	return -ENOTSUPP;
+}
+
+static const struct nla_policy nfqa_cfg_policy[NFQA_CFG_MAX+1] = {
+	[NFQA_CFG_CMD]		= { .len = sizeof(struct nfqnl_msg_config_cmd) },
+	[NFQA_CFG_PARAMS]	= { .len = sizeof(struct nfqnl_msg_config_params) },
+};
+
+static const struct nf_queue_handler nfqh = {
+	.name 	= "nf_queue",
+	.outfn	= &nfqnl_enqueue_packet,
+};
+
+static int
+nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
+		  const struct nlmsghdr *nlh,
+		  const struct nlattr * const nfqa[])
+{
+	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
+	u_int16_t queue_num = ntohs(nfmsg->res_id);
+	struct nfqnl_instance *queue;
+	struct nfqnl_msg_config_cmd *cmd = NULL;
+	int ret = 0;
+
+	if (nfqa[NFQA_CFG_CMD]) {
+		cmd = nla_data(nfqa[NFQA_CFG_CMD]);
+
+		/* Commands without queue context - might sleep */
+		switch (cmd->command) {
+		case NFQNL_CFG_CMD_PF_BIND:
+			return nf_register_queue_handler(ntohs(cmd->pf),
+							 &nfqh);
+		case NFQNL_CFG_CMD_PF_UNBIND:
+			return nf_unregister_queue_handler(ntohs(cmd->pf),
+							   &nfqh);
+		}
+	}
+
+	rcu_read_lock();
+	queue = instance_lookup(queue_num);
+	if (queue && queue->peer_pid != NETLINK_CB(skb).pid) {
+		ret = -EPERM;
+		goto err_out_unlock;
+	}
+
+	if (cmd != NULL) {
+		switch (cmd->command) {
+		case NFQNL_CFG_CMD_BIND:
+			if (queue) {
+				ret = -EBUSY;
+				goto err_out_unlock;
+			}
+			queue = instance_create(queue_num, NETLINK_CB(skb).pid);
+			if (IS_ERR(queue)) {
+				ret = PTR_ERR(queue);
+				goto err_out_unlock;
+			}
+			break;
+		case NFQNL_CFG_CMD_UNBIND:
+			if (!queue) {
+				ret = -ENODEV;
+				goto err_out_unlock;
+			}
+			instance_destroy(queue);
+			break;
+		case NFQNL_CFG_CMD_PF_BIND:
+		case NFQNL_CFG_CMD_PF_UNBIND:
+			break;
+		default:
+			ret = -ENOTSUPP;
+			break;
+		}
+	}
+
+	if (nfqa[NFQA_CFG_PARAMS]) {
+		struct nfqnl_msg_config_params *params;
+
+		if (!queue) {
+			ret = -ENODEV;
+			goto err_out_unlock;
+		}
+		params = nla_data(nfqa[NFQA_CFG_PARAMS]);
+		nfqnl_set_mode(queue, params->copy_mode,
+				ntohl(params->copy_range));
+	}
+
+	if (nfqa[NFQA_CFG_QUEUE_MAXLEN]) {
+		__be32 *queue_maxlen;
+
+		if (!queue) {
+			ret = -ENODEV;
+			goto err_out_unlock;
+		}
+		queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]);
+		spin_lock_bh(&queue->lock);
+		queue->queue_maxlen = ntohl(*queue_maxlen);
+		spin_unlock_bh(&queue->lock);
+	}
+
+	if (nfqa[NFQA_CFG_FLAGS]) {
+		__u32 flags, mask;
+
+		if (!queue) {
+			ret = -ENODEV;
+			goto err_out_unlock;
+		}
+
+		if (!nfqa[NFQA_CFG_MASK]) {
+			/* A mask is needed to specify which flags are being
+			 * changed.
+			 */
+			ret = -EINVAL;
+			goto err_out_unlock;
+		}
+
+		flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
+		mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
+
+		spin_lock_bh(&queue->lock);
+		queue->flags &= ~mask;
+		queue->flags |= flags & mask;
+		spin_unlock_bh(&queue->lock);
+	}
+
+err_out_unlock:
+	rcu_read_unlock();
+	return ret;
+}
+
+static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
+	[NFQNL_MSG_PACKET]	= { .call_rcu = nfqnl_recv_unsupp,
+				    .attr_count = NFQA_MAX, },
+	[NFQNL_MSG_VERDICT]	= { .call_rcu = nfqnl_recv_verdict,
+				    .attr_count = NFQA_MAX,
+				    .policy = nfqa_verdict_policy },
+	[NFQNL_MSG_CONFIG]	= { .call = nfqnl_recv_config,
+				    .attr_count = NFQA_CFG_MAX,
+				    .policy = nfqa_cfg_policy },
+	[NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch,
+				    .attr_count = NFQA_MAX,
+				    .policy = nfqa_verdict_batch_policy },
+};
+
+static const struct nfnetlink_subsystem nfqnl_subsys = {
+	.name		= "nf_queue",
+	.subsys_id	= NFNL_SUBSYS_QUEUE,
+	.cb_count	= NFQNL_MSG_MAX,
+	.cb		= nfqnl_cb,
+};
+
+#ifdef CONFIG_PROC_FS
+struct iter_state {
+	unsigned int bucket;
+};
+
+static struct hlist_node *get_first(struct seq_file *seq)
+{
+	struct iter_state *st = seq->private;
+
+	if (!st)
+		return NULL;
+
+	for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
+		if (!hlist_empty(&instance_table[st->bucket]))
+			return instance_table[st->bucket].first;
+	}
+	return NULL;
+}
+
+static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
+{
+	struct iter_state *st = seq->private;
+
+	h = h->next;
+	while (!h) {
+		if (++st->bucket >= INSTANCE_BUCKETS)
+			return NULL;
+
+		h = instance_table[st->bucket].first;
+	}
+	return h;
+}
+
+static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
+{
+	struct hlist_node *head;
+	head = get_first(seq);
+
+	if (head)
+		while (pos && (head = get_next(seq, head)))
+			pos--;
+	return pos ? NULL : head;
+}
+
+static void *seq_start(struct seq_file *seq, loff_t *pos)
+	__acquires(instances_lock)
+{
+	spin_lock(&instances_lock);
+	return get_idx(seq, *pos);
+}
+
+static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	(*pos)++;
+	return get_next(s, v);
+}
+
+static void seq_stop(struct seq_file *s, void *v)
+	__releases(instances_lock)
+{
+	spin_unlock(&instances_lock);
+}
+
+static int seq_show(struct seq_file *s, void *v)
+{
+	const struct nfqnl_instance *inst = v;
+
+	return seq_printf(s, "%5d %6d %5d %1d %5d %5d %5d %8d %2d\n",
+			  inst->queue_num,
+			  inst->peer_pid, inst->queue_total,
+			  inst->copy_mode, inst->copy_range,
+			  inst->queue_dropped, inst->queue_user_dropped,
+			  inst->id_sequence, 1);
+}
+
+static const struct seq_operations nfqnl_seq_ops = {
+	.start	= seq_start,
+	.next	= seq_next,
+	.stop	= seq_stop,
+	.show	= seq_show,
+};
+
+static int nfqnl_open(struct inode *inode, struct file *file)
+{
+	return seq_open_private(file, &nfqnl_seq_ops,
+			sizeof(struct iter_state));
+}
+
+static const struct file_operations nfqnl_file_ops = {
+	.owner	 = THIS_MODULE,
+	.open	 = nfqnl_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release_private,
+};
+
+#endif /* PROC_FS */
+
+static int __init nfnetlink_queue_init(void)
+{
+	int i, status = -ENOMEM;
+
+	for (i = 0; i < INSTANCE_BUCKETS; i++)
+		INIT_HLIST_HEAD(&instance_table[i]);
+
+	netlink_register_notifier(&nfqnl_rtnl_notifier);
+	status = nfnetlink_subsys_register(&nfqnl_subsys);
+	if (status < 0) {
+		printk(KERN_ERR "nf_queue: failed to create netlink socket\n");
+		goto cleanup_netlink_notifier;
+	}
+
+#ifdef CONFIG_PROC_FS
+	if (!proc_create("nfnetlink_queue", 0440,
+			 proc_net_netfilter, &nfqnl_file_ops))
+		goto cleanup_subsys;
+#endif
+
+	register_netdevice_notifier(&nfqnl_dev_notifier);
+	return status;
+
+#ifdef CONFIG_PROC_FS
+cleanup_subsys:
+	nfnetlink_subsys_unregister(&nfqnl_subsys);
+#endif
+cleanup_netlink_notifier:
+	netlink_unregister_notifier(&nfqnl_rtnl_notifier);
+	return status;
+}
+
+static void __exit nfnetlink_queue_fini(void)
+{
+	nf_unregister_queue_handlers(&nfqh);
+	unregister_netdevice_notifier(&nfqnl_dev_notifier);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
+#endif
+	nfnetlink_subsys_unregister(&nfqnl_subsys);
+	netlink_unregister_notifier(&nfqnl_rtnl_notifier);
+
+	rcu_barrier(); /* Wait for completion of call_rcu()'s */
+}
+
+MODULE_DESCRIPTION("netfilter packet queue handler");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_QUEUE);
+
+module_init(nfnetlink_queue_init);
+module_exit(nfnetlink_queue_fini);
diff --git a/net/netfilter/nfnetlink_queue_ct.c b/net/netfilter/nfnetlink_queue_ct.c
new file mode 100644
index 0000000..ab61d66
--- /dev/null
+++ b/net/netfilter/nfnetlink_queue_ct.c
@@ -0,0 +1,98 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.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/skbuff.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nfnetlink_queue.h>
+
+struct nf_conn *nfqnl_ct_get(struct sk_buff *entskb, size_t *size,
+			     enum ip_conntrack_info *ctinfo)
+{
+	struct nfq_ct_hook *nfq_ct;
+	struct nf_conn *ct;
+
+	/* rcu_read_lock()ed by __nf_queue already. */
+	nfq_ct = rcu_dereference(nfq_ct_hook);
+	if (nfq_ct == NULL)
+		return NULL;
+
+	ct = nf_ct_get(entskb, ctinfo);
+	if (ct) {
+		if (!nf_ct_is_untracked(ct))
+			*size += nfq_ct->build_size(ct);
+		else
+			ct = NULL;
+	}
+	return ct;
+}
+
+struct nf_conn *
+nfqnl_ct_parse(const struct sk_buff *skb, const struct nlattr *attr,
+	       enum ip_conntrack_info *ctinfo)
+{
+	struct nfq_ct_hook *nfq_ct;
+	struct nf_conn *ct;
+
+	/* rcu_read_lock()ed by __nf_queue already. */
+	nfq_ct = rcu_dereference(nfq_ct_hook);
+	if (nfq_ct == NULL)
+		return NULL;
+
+	ct = nf_ct_get(skb, ctinfo);
+	if (ct && !nf_ct_is_untracked(ct))
+		nfq_ct->parse(attr, ct);
+
+	return ct;
+}
+
+int nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct,
+		 enum ip_conntrack_info ctinfo)
+{
+	struct nfq_ct_hook *nfq_ct;
+	struct nlattr *nest_parms;
+	u_int32_t tmp;
+
+	nfq_ct = rcu_dereference(nfq_ct_hook);
+	if (nfq_ct == NULL)
+		return 0;
+
+	nest_parms = nla_nest_start(skb, NFQA_CT | NLA_F_NESTED);
+	if (!nest_parms)
+		goto nla_put_failure;
+
+	if (nfq_ct->build(skb, ct) < 0)
+		goto nla_put_failure;
+
+	nla_nest_end(skb, nest_parms);
+
+	tmp = ctinfo;
+	if (nla_put_be32(skb, NFQA_CT_INFO, htonl(tmp)))
+		goto nla_put_failure;
+
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
+			 enum ip_conntrack_info ctinfo, int diff)
+{
+	struct nfq_ct_nat_hook *nfq_nat_ct;
+
+	nfq_nat_ct = rcu_dereference(nfq_ct_nat_hook);
+	if (nfq_nat_ct == NULL)
+		return;
+
+	if ((ct->status & IPS_NAT_MASK) && diff)
+		nfq_nat_ct->seq_adjust(skb, ct, ctinfo, diff);
+}
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index a51de9b..1160185 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -112,6 +112,8 @@ static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
 		goto err3;
 
 	if (info->helper[0]) {
+		struct nf_conntrack_helper *helper;
+
 		ret = -ENOENT;
 		proto = xt_ct_find_proto(par);
 		if (!proto) {
@@ -120,19 +122,21 @@ static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
 			goto err3;
 		}
 
-		ret = -ENOMEM;
-		help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
-		if (help == NULL)
-			goto err3;
-
 		ret = -ENOENT;
-		help->helper = nf_conntrack_helper_try_module_get(info->helper,
-								  par->family,
-								  proto);
-		if (help->helper == NULL) {
+		helper = nf_conntrack_helper_try_module_get(info->helper,
+							    par->family,
+							    proto);
+		if (helper == NULL) {
 			pr_info("No such helper \"%s\"\n", info->helper);
 			goto err3;
 		}
+
+		ret = -ENOMEM;
+		help = nf_ct_helper_ext_add(ct, helper, GFP_KERNEL);
+		if (help == NULL)
+			goto err3;
+
+		help->helper = helper;
 	}
 
 	__set_bit(IPS_TEMPLATE_BIT, &ct->status);
@@ -202,6 +206,8 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
 		goto err3;
 
 	if (info->helper[0]) {
+		struct nf_conntrack_helper *helper;
+
 		ret = -ENOENT;
 		proto = xt_ct_find_proto(par);
 		if (!proto) {
@@ -210,19 +216,21 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
 			goto err3;
 		}
 
-		ret = -ENOMEM;
-		help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
-		if (help == NULL)
-			goto err3;
-
 		ret = -ENOENT;
-		help->helper = nf_conntrack_helper_try_module_get(info->helper,
-								  par->family,
-								  proto);
-		if (help->helper == NULL) {
+		helper = nf_conntrack_helper_try_module_get(info->helper,
+							    par->family,
+							    proto);
+		if (helper == NULL) {
 			pr_info("No such helper \"%s\"\n", info->helper);
 			goto err3;
 		}
+
+		ret = -ENOMEM;
+		help = nf_ct_helper_ext_add(ct, helper, GFP_KERNEL);
+		if (help == NULL)
+			goto err3;
+
+		help->helper = helper;
 	}
 
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
index 95237c8..7babe7d 100644
--- a/net/netfilter/xt_NFQUEUE.c
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -41,26 +41,36 @@ nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par)
 static u32 hash_v4(const struct sk_buff *skb)
 {
 	const struct iphdr *iph = ip_hdr(skb);
-	__be32 ipaddr;
 
 	/* packets in either direction go into same queue */
-	ipaddr = iph->saddr ^ iph->daddr;
+	if (iph->saddr < iph->daddr)
+		return jhash_3words((__force u32)iph->saddr,
+			(__force u32)iph->daddr, iph->protocol, jhash_initval);
 
-	return jhash_2words((__force u32)ipaddr, iph->protocol, jhash_initval);
+	return jhash_3words((__force u32)iph->daddr,
+			(__force u32)iph->saddr, iph->protocol, jhash_initval);
 }
 
 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 static u32 hash_v6(const struct sk_buff *skb)
 {
 	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
-	__be32 addr[4];
+	u32 a, b, c;
+
+	if (ip6h->saddr.s6_addr32[3] < ip6h->daddr.s6_addr32[3]) {
+		a = (__force u32) ip6h->saddr.s6_addr32[3];
+		b = (__force u32) ip6h->daddr.s6_addr32[3];
+	} else {
+		b = (__force u32) ip6h->saddr.s6_addr32[3];
+		a = (__force u32) ip6h->daddr.s6_addr32[3];
+	}
 
-	addr[0] = ip6h->saddr.s6_addr32[0] ^ ip6h->daddr.s6_addr32[0];
-	addr[1] = ip6h->saddr.s6_addr32[1] ^ ip6h->daddr.s6_addr32[1];
-	addr[2] = ip6h->saddr.s6_addr32[2] ^ ip6h->daddr.s6_addr32[2];
-	addr[3] = ip6h->saddr.s6_addr32[3] ^ ip6h->daddr.s6_addr32[3];
+	if (ip6h->saddr.s6_addr32[1] < ip6h->daddr.s6_addr32[1])
+		c = (__force u32) ip6h->saddr.s6_addr32[1];
+	else
+		c = (__force u32) ip6h->daddr.s6_addr32[1];
 
-	return jhash2((__force u32 *)addr, ARRAY_SIZE(addr), jhash_initval);
+	return jhash_3words(a, b, c, jhash_initval);
 }
 #endif
 
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c
index c6d5a83..70b5591 100644
--- a/net/netfilter/xt_connlimit.c
+++ b/net/netfilter/xt_connlimit.c
@@ -274,38 +274,25 @@ static void connlimit_mt_destroy(const struct xt_mtdtor_param *par)
 	kfree(info->data);
 }
 
-static struct xt_match connlimit_mt_reg[] __read_mostly = {
-	{
-		.name       = "connlimit",
-		.revision   = 0,
-		.family     = NFPROTO_UNSPEC,
-		.checkentry = connlimit_mt_check,
-		.match      = connlimit_mt,
-		.matchsize  = sizeof(struct xt_connlimit_info),
-		.destroy    = connlimit_mt_destroy,
-		.me         = THIS_MODULE,
-	},
-	{
-		.name       = "connlimit",
-		.revision   = 1,
-		.family     = NFPROTO_UNSPEC,
-		.checkentry = connlimit_mt_check,
-		.match      = connlimit_mt,
-		.matchsize  = sizeof(struct xt_connlimit_info),
-		.destroy    = connlimit_mt_destroy,
-		.me         = THIS_MODULE,
-	},
+static struct xt_match connlimit_mt_reg __read_mostly = {
+	.name       = "connlimit",
+	.revision   = 1,
+	.family     = NFPROTO_UNSPEC,
+	.checkentry = connlimit_mt_check,
+	.match      = connlimit_mt,
+	.matchsize  = sizeof(struct xt_connlimit_info),
+	.destroy    = connlimit_mt_destroy,
+	.me         = THIS_MODULE,
 };
 
 static int __init connlimit_mt_init(void)
 {
-	return xt_register_matches(connlimit_mt_reg,
-	       ARRAY_SIZE(connlimit_mt_reg));
+	return xt_register_match(&connlimit_mt_reg);
 }
 
 static void __exit connlimit_mt_exit(void)
 {
-	xt_unregister_matches(connlimit_mt_reg, ARRAY_SIZE(connlimit_mt_reg));
+	xt_unregister_match(&connlimit_mt_reg);
 }
 
 module_init(connlimit_mt_init);
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index fc0d6db..ae2ad1e 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -75,6 +75,7 @@ struct recent_entry {
 struct recent_table {
 	struct list_head	list;
 	char			name[XT_RECENT_NAME_LEN];
+	union nf_inet_addr	mask;
 	unsigned int		refcnt;
 	unsigned int		entries;
 	struct list_head	lru_list;
@@ -228,10 +229,10 @@ recent_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
 	struct net *net = dev_net(par->in ? par->in : par->out);
 	struct recent_net *recent_net = recent_pernet(net);
-	const struct xt_recent_mtinfo *info = par->matchinfo;
+	const struct xt_recent_mtinfo_v1 *info = par->matchinfo;
 	struct recent_table *t;
 	struct recent_entry *e;
-	union nf_inet_addr addr = {};
+	union nf_inet_addr addr = {}, addr_mask;
 	u_int8_t ttl;
 	bool ret = info->invert;
 
@@ -261,12 +262,15 @@ recent_mt(const struct sk_buff *skb, struct xt_action_param *par)
 
 	spin_lock_bh(&recent_lock);
 	t = recent_table_lookup(recent_net, info->name);
-	e = recent_entry_lookup(t, &addr, par->family,
+
+	nf_inet_addr_mask(&addr, &addr_mask, &t->mask);
+
+	e = recent_entry_lookup(t, &addr_mask, par->family,
 				(info->check_set & XT_RECENT_TTL) ? ttl : 0);
 	if (e == NULL) {
 		if (!(info->check_set & XT_RECENT_SET))
 			goto out;
-		e = recent_entry_init(t, &addr, par->family, ttl);
+		e = recent_entry_init(t, &addr_mask, par->family, ttl);
 		if (e == NULL)
 			par->hotdrop = true;
 		ret = !ret;
@@ -306,10 +310,10 @@ out:
 	return ret;
 }
 
-static int recent_mt_check(const struct xt_mtchk_param *par)
+static int recent_mt_check(const struct xt_mtchk_param *par,
+			   const struct xt_recent_mtinfo_v1 *info)
 {
 	struct recent_net *recent_net = recent_pernet(par->net);
-	const struct xt_recent_mtinfo *info = par->matchinfo;
 	struct recent_table *t;
 #ifdef CONFIG_PROC_FS
 	struct proc_dir_entry *pde;
@@ -361,6 +365,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par)
 		goto out;
 	}
 	t->refcnt = 1;
+
+	memcpy(&t->mask, &info->mask, sizeof(t->mask));
 	strcpy(t->name, info->name);
 	INIT_LIST_HEAD(&t->lru_list);
 	for (i = 0; i < ip_list_hash_size; i++)
@@ -385,10 +391,28 @@ out:
 	return ret;
 }
 
+static int recent_mt_check_v0(const struct xt_mtchk_param *par)
+{
+	const struct xt_recent_mtinfo_v0 *info_v0 = par->matchinfo;
+	struct xt_recent_mtinfo_v1 info_v1;
+
+	/* Copy revision 0 structure to revision 1 */
+	memcpy(&info_v1, info_v0, sizeof(struct xt_recent_mtinfo));
+	/* Set default mask to ensure backward compatible behaviour */
+	memset(info_v1.mask.all, 0xFF, sizeof(info_v1.mask.all));
+
+	return recent_mt_check(par, &info_v1);
+}
+
+static int recent_mt_check_v1(const struct xt_mtchk_param *par)
+{
+	return recent_mt_check(par, par->matchinfo);
+}
+
 static void recent_mt_destroy(const struct xt_mtdtor_param *par)
 {
 	struct recent_net *recent_net = recent_pernet(par->net);
-	const struct xt_recent_mtinfo *info = par->matchinfo;
+	const struct xt_recent_mtinfo_v1 *info = par->matchinfo;
 	struct recent_table *t;
 
 	mutex_lock(&recent_mutex);
@@ -625,7 +649,7 @@ static struct xt_match recent_mt_reg[] __read_mostly = {
 		.family     = NFPROTO_IPV4,
 		.match      = recent_mt,
 		.matchsize  = sizeof(struct xt_recent_mtinfo),
-		.checkentry = recent_mt_check,
+		.checkentry = recent_mt_check_v0,
 		.destroy    = recent_mt_destroy,
 		.me         = THIS_MODULE,
 	},
@@ -635,10 +659,30 @@ static struct xt_match recent_mt_reg[] __read_mostly = {
 		.family     = NFPROTO_IPV6,
 		.match      = recent_mt,
 		.matchsize  = sizeof(struct xt_recent_mtinfo),
-		.checkentry = recent_mt_check,
+		.checkentry = recent_mt_check_v0,
+		.destroy    = recent_mt_destroy,
+		.me         = THIS_MODULE,
+	},
+	{
+		.name       = "recent",
+		.revision   = 1,
+		.family     = NFPROTO_IPV4,
+		.match      = recent_mt,
+		.matchsize  = sizeof(struct xt_recent_mtinfo_v1),
+		.checkentry = recent_mt_check_v1,
 		.destroy    = recent_mt_destroy,
 		.me         = THIS_MODULE,
 	},
+	{
+		.name       = "recent",
+		.revision   = 1,
+		.family     = NFPROTO_IPV6,
+		.match      = recent_mt,
+		.matchsize  = sizeof(struct xt_recent_mtinfo_v1),
+		.checkentry = recent_mt_check_v1,
+		.destroy    = recent_mt_destroy,
+		.me         = THIS_MODULE,
+	}
 };
 
 static int __init recent_mt_init(void)
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 9f6ce01..4177bb5 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -121,14 +121,14 @@ error:
  * The device remains polling for targets until a target is found or
  * the nfc_stop_poll function is called.
  */
-int nfc_start_poll(struct nfc_dev *dev, u32 protocols)
+int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
 {
 	int rc;
 
-	pr_debug("dev_name=%s protocols=0x%x\n",
-		 dev_name(&dev->dev), protocols);
+	pr_debug("dev_name %s initiator protocols 0x%x target protocols 0x%x\n",
+		 dev_name(&dev->dev), im_protocols, tm_protocols);
 
-	if (!protocols)
+	if (!im_protocols && !tm_protocols)
 		return -EINVAL;
 
 	device_lock(&dev->dev);
@@ -143,9 +143,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 protocols)
 		goto error;
 	}
 
-	rc = dev->ops->start_poll(dev, protocols);
-	if (!rc)
+	rc = dev->ops->start_poll(dev, im_protocols, tm_protocols);
+	if (!rc) {
 		dev->polling = true;
+		dev->rf_mode = NFC_RF_NONE;
+	}
 
 error:
 	device_unlock(&dev->dev);
@@ -235,8 +237,10 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
 	}
 
 	rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len);
-	if (!rc)
+	if (!rc) {
 		dev->active_target = target;
+		dev->rf_mode = NFC_RF_INITIATOR;
+	}
 
 error:
 	device_unlock(&dev->dev);
@@ -264,11 +268,6 @@ int nfc_dep_link_down(struct nfc_dev *dev)
 		goto error;
 	}
 
-	if (dev->dep_rf_mode == NFC_RF_TARGET) {
-		rc = -EOPNOTSUPP;
-		goto error;
-	}
-
 	rc = dev->ops->dep_link_down(dev);
 	if (!rc) {
 		dev->dep_link_up = false;
@@ -286,7 +285,6 @@ int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
 		       u8 comm_mode, u8 rf_mode)
 {
 	dev->dep_link_up = true;
-	dev->dep_rf_mode = rf_mode;
 
 	nfc_llcp_mac_is_up(dev, target_idx, comm_mode, rf_mode);
 
@@ -330,6 +328,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
 	rc = dev->ops->activate_target(dev, target, protocol);
 	if (!rc) {
 		dev->active_target = target;
+		dev->rf_mode = NFC_RF_INITIATOR;
 
 		if (dev->ops->check_presence)
 			mod_timer(&dev->check_pres_timer, jiffies +
@@ -409,27 +408,30 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
 		goto error;
 	}
 
-	if (dev->active_target == NULL) {
-		rc = -ENOTCONN;
-		kfree_skb(skb);
-		goto error;
-	}
+	if (dev->rf_mode == NFC_RF_INITIATOR && dev->active_target != NULL) {
+		if (dev->active_target->idx != target_idx) {
+			rc = -EADDRNOTAVAIL;
+			kfree_skb(skb);
+			goto error;
+		}
 
-	if (dev->active_target->idx != target_idx) {
-		rc = -EADDRNOTAVAIL;
+		if (dev->ops->check_presence)
+			del_timer_sync(&dev->check_pres_timer);
+
+		rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
+					     cb_context);
+
+		if (!rc && dev->ops->check_presence)
+			mod_timer(&dev->check_pres_timer, jiffies +
+				  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
+	} else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
+		rc = dev->ops->tm_send(dev, skb);
+	} else {
+		rc = -ENOTCONN;
 		kfree_skb(skb);
 		goto error;
 	}
 
-	if (dev->ops->check_presence)
-		del_timer_sync(&dev->check_pres_timer);
-
-	rc = dev->ops->data_exchange(dev, dev->active_target, skb, cb,
-				     cb_context);
-
-	if (!rc && dev->ops->check_presence)
-		mod_timer(&dev->check_pres_timer, jiffies +
-			  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
 
 error:
 	device_unlock(&dev->dev);
@@ -447,6 +449,63 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len)
 }
 EXPORT_SYMBOL(nfc_set_remote_general_bytes);
 
+u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len)
+{
+	pr_debug("dev_name=%s\n", dev_name(&dev->dev));
+
+	return nfc_llcp_general_bytes(dev, gb_len);
+}
+EXPORT_SYMBOL(nfc_get_local_general_bytes);
+
+int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb)
+{
+	/* Only LLCP target mode for now */
+	if (dev->dep_link_up == false) {
+		kfree_skb(skb);
+		return -ENOLINK;
+	}
+
+	return nfc_llcp_data_received(dev, skb);
+}
+EXPORT_SYMBOL(nfc_tm_data_received);
+
+int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
+		     u8 *gb, size_t gb_len)
+{
+	int rc;
+
+	device_lock(&dev->dev);
+
+	dev->polling = false;
+
+	if (gb != NULL) {
+		rc = nfc_set_remote_general_bytes(dev, gb, gb_len);
+		if (rc < 0)
+			goto out;
+	}
+
+	dev->rf_mode = NFC_RF_TARGET;
+
+	if (protocol == NFC_PROTO_NFC_DEP_MASK)
+		nfc_dep_link_is_up(dev, 0, comm_mode, NFC_RF_TARGET);
+
+	rc = nfc_genl_tm_activated(dev, protocol);
+
+out:
+	device_unlock(&dev->dev);
+
+	return rc;
+}
+EXPORT_SYMBOL(nfc_tm_activated);
+
+int nfc_tm_deactivated(struct nfc_dev *dev)
+{
+	dev->dep_link_up = false;
+
+	return nfc_genl_tm_deactivated(dev);
+}
+EXPORT_SYMBOL(nfc_tm_deactivated);
+
 /**
  * nfc_alloc_send_skb - allocate a skb for data exchange responses
  *
@@ -678,7 +737,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
 	struct nfc_dev *dev;
 
 	if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
-	    !ops->deactivate_target || !ops->data_exchange)
+	    !ops->deactivate_target || !ops->im_transceive)
 		return NULL;
 
 	if (!supported_protocols)
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index e1a640d..a8b0b71 100644
--- a/net/nfc/hci/core.c
+++ b/net/nfc/hci/core.c
@@ -481,12 +481,13 @@ static int hci_dev_down(struct nfc_dev *nfc_dev)
 	return 0;
 }
 
-static int hci_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
+static int hci_start_poll(struct nfc_dev *nfc_dev,
+			  u32 im_protocols, u32 tm_protocols)
 {
 	struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
 
 	if (hdev->ops->start_poll)
-		return hdev->ops->start_poll(hdev, protocols);
+		return hdev->ops->start_poll(hdev, im_protocols, tm_protocols);
 	else
 		return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
 				       NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
@@ -511,9 +512,9 @@ static void hci_deactivate_target(struct nfc_dev *nfc_dev,
 {
 }
 
-static int hci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target,
-			     struct sk_buff *skb, data_exchange_cb_t cb,
-			     void *cb_context)
+static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
+			  struct sk_buff *skb, data_exchange_cb_t cb,
+			  void *cb_context)
 {
 	struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
 	int r;
@@ -579,7 +580,7 @@ static struct nfc_ops hci_nfc_ops = {
 	.stop_poll = hci_stop_poll,
 	.activate_target = hci_activate_target,
 	.deactivate_target = hci_deactivate_target,
-	.data_exchange = hci_data_exchange,
+	.im_transceive = hci_transceive,
 	.check_presence = hci_check_presence,
 };
 
diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c
index 5665dc6..6b836e6 100644
--- a/net/nfc/hci/shdlc.c
+++ b/net/nfc/hci/shdlc.c
@@ -765,14 +765,16 @@ static int nfc_shdlc_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
 	return 0;
 }
 
-static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev, u32 protocols)
+static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev,
+				u32 im_protocols, u32 tm_protocols)
 {
 	struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
 
 	pr_debug("\n");
 
 	if (shdlc->ops->start_poll)
-		return shdlc->ops->start_poll(shdlc, protocols);
+		return shdlc->ops->start_poll(shdlc,
+					      im_protocols, tm_protocols);
 
 	return 0;
 }
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c
index bf8ae4f..b982b5b 100644
--- a/net/nfc/llcp/commands.c
+++ b/net/nfc/llcp/commands.c
@@ -51,7 +51,7 @@ static u8 llcp_tlv8(u8 *tlv, u8 type)
 	return tlv[2];
 }
 
-static u8 llcp_tlv16(u8 *tlv, u8 type)
+static u16 llcp_tlv16(u8 *tlv, u8 type)
 {
 	if (tlv[0] != type || tlv[1] != llcp_tlv_length[tlv[0]])
 		return 0;
@@ -67,7 +67,7 @@ static u8 llcp_tlv_version(u8 *tlv)
 
 static u16 llcp_tlv_miux(u8 *tlv)
 {
-	return llcp_tlv16(tlv, LLCP_TLV_MIUX) & 0x7f;
+	return llcp_tlv16(tlv, LLCP_TLV_MIUX) & 0x7ff;
 }
 
 static u16 llcp_tlv_wks(u8 *tlv)
@@ -117,8 +117,8 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length)
 	return tlv;
 }
 
-int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
-		       u8 *tlv_array, u16 tlv_array_len)
+int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
+			  u8 *tlv_array, u16 tlv_array_len)
 {
 	u8 *tlv = tlv_array, type, length, offset = 0;
 
@@ -149,8 +149,45 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
 		case LLCP_TLV_OPT:
 			local->remote_opt = llcp_tlv_opt(tlv);
 			break;
+		default:
+			pr_err("Invalid gt tlv value 0x%x\n", type);
+			break;
+		}
+
+		offset += length + 2;
+		tlv += length + 2;
+	}
+
+	pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x\n",
+		 local->remote_version, local->remote_miu,
+		 local->remote_lto, local->remote_opt,
+		 local->remote_wks);
+
+	return 0;
+}
+
+int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
+				  u8 *tlv_array, u16 tlv_array_len)
+{
+	u8 *tlv = tlv_array, type, length, offset = 0;
+
+	pr_debug("TLV array length %d\n", tlv_array_len);
+
+	if (sock == NULL)
+		return -ENOTCONN;
+
+	while (offset < tlv_array_len) {
+		type = tlv[0];
+		length = tlv[1];
+
+		pr_debug("type 0x%x length %d\n", type, length);
+
+		switch (type) {
+		case LLCP_TLV_MIUX:
+			sock->miu = llcp_tlv_miux(tlv) + 128;
+			break;
 		case LLCP_TLV_RW:
-			local->remote_rw = llcp_tlv_rw(tlv);
+			sock->rw = llcp_tlv_rw(tlv);
 			break;
 		case LLCP_TLV_SN:
 			break;
@@ -163,10 +200,7 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
 		tlv += length + 2;
 	}
 
-	pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x rw %d\n",
-		 local->remote_version, local->remote_miu,
-		 local->remote_lto, local->remote_opt,
-		 local->remote_wks, local->remote_rw);
+	pr_debug("sock %p rw %d miu %d\n", sock, sock->rw, sock->miu);
 
 	return 0;
 }
@@ -474,7 +508,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 
 	while (remaining_len > 0) {
 
-		frag_len = min_t(size_t, local->remote_miu, remaining_len);
+		frag_len = min_t(size_t, sock->miu, remaining_len);
 
 		pr_debug("Fragment %zd bytes remaining %zd",
 			 frag_len, remaining_len);
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 42994fa..5d503ee 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -31,47 +31,41 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d};
 
 static struct list_head llcp_devices;
 
-static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
+void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk)
 {
-	struct nfc_llcp_sock *parent, *s, *n;
-	struct sock *sk, *parent_sk;
-	int i;
-
-	mutex_lock(&local->socket_lock);
-
-	for (i = 0; i < LLCP_MAX_SAP; i++) {
-		parent = local->sockets[i];
-		if (parent == NULL)
-			continue;
-
-		/* Release all child sockets */
-		list_for_each_entry_safe(s, n, &parent->list, list) {
-			list_del_init(&s->list);
-			sk = &s->sk;
-
-			lock_sock(sk);
-
-			if (sk->sk_state == LLCP_CONNECTED)
-				nfc_put_device(s->dev);
+	write_lock(&l->lock);
+	sk_add_node(sk, &l->head);
+	write_unlock(&l->lock);
+}
 
-			sk->sk_state = LLCP_CLOSED;
+void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)
+{
+	write_lock(&l->lock);
+	sk_del_node_init(sk);
+	write_unlock(&l->lock);
+}
 
-			release_sock(sk);
+static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
+{
+	struct sock *sk;
+	struct hlist_node *node, *tmp;
+	struct nfc_llcp_sock *llcp_sock;
 
-			sock_orphan(sk);
+	write_lock(&local->sockets.lock);
 
-			s->local = NULL;
-		}
+	sk_for_each_safe(sk, node, tmp, &local->sockets.head) {
+		llcp_sock = nfc_llcp_sock(sk);
 
-		parent_sk = &parent->sk;
+		lock_sock(sk);
 
-		lock_sock(parent_sk);
+		if (sk->sk_state == LLCP_CONNECTED)
+			nfc_put_device(llcp_sock->dev);
 
-		if (parent_sk->sk_state == LLCP_LISTEN) {
+		if (sk->sk_state == LLCP_LISTEN) {
 			struct nfc_llcp_sock *lsk, *n;
 			struct sock *accept_sk;
 
-			list_for_each_entry_safe(lsk, n, &parent->accept_queue,
+			list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue,
 						 accept_queue) {
 				accept_sk = &lsk->sk;
 				lock_sock(accept_sk);
@@ -83,24 +77,53 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
 				release_sock(accept_sk);
 
 				sock_orphan(accept_sk);
-
-				lsk->local = NULL;
 			}
 		}
 
-		if (parent_sk->sk_state == LLCP_CONNECTED)
-			nfc_put_device(parent->dev);
-
-		parent_sk->sk_state = LLCP_CLOSED;
+		sk->sk_state = LLCP_CLOSED;
 
-		release_sock(parent_sk);
+		release_sock(sk);
 
-		sock_orphan(parent_sk);
+		sock_orphan(sk);
 
-		parent->local = NULL;
+		sk_del_node_init(sk);
 	}
 
-	mutex_unlock(&local->socket_lock);
+	write_unlock(&local->sockets.lock);
+}
+
+struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
+{
+	kref_get(&local->ref);
+
+	return local;
+}
+
+static void local_release(struct kref *ref)
+{
+	struct nfc_llcp_local *local;
+
+	local = container_of(ref, struct nfc_llcp_local, ref);
+
+	list_del(&local->list);
+	nfc_llcp_socket_release(local);
+	del_timer_sync(&local->link_timer);
+	skb_queue_purge(&local->tx_queue);
+	destroy_workqueue(local->tx_wq);
+	destroy_workqueue(local->rx_wq);
+	destroy_workqueue(local->timeout_wq);
+	kfree_skb(local->rx_pending);
+	kfree(local);
+}
+
+int nfc_llcp_local_put(struct nfc_llcp_local *local)
+{
+	WARN_ON(local == NULL);
+
+	if (local == NULL)
+		return 0;
+
+	return kref_put(&local->ref, local_release);
 }
 
 static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local)
@@ -384,31 +407,9 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len)
 		return -EINVAL;
 	}
 
-	return nfc_llcp_parse_tlv(local,
-				  &local->remote_gb[3],
-				  local->remote_gb_len - 3);
-}
-
-static void nfc_llcp_tx_work(struct work_struct *work)
-{
-	struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
-						    tx_work);
-	struct sk_buff *skb;
-
-	skb = skb_dequeue(&local->tx_queue);
-	if (skb != NULL) {
-		pr_debug("Sending pending skb\n");
-		print_hex_dump(KERN_DEBUG, "LLCP Tx: ", DUMP_PREFIX_OFFSET,
-			       16, 1, skb->data, skb->len, true);
-
-		nfc_data_exchange(local->dev, local->target_idx,
-				  skb, nfc_llcp_recv, local);
-	} else {
-		nfc_llcp_send_symm(local->dev);
-	}
-
-	mod_timer(&local->link_timer,
-		  jiffies + msecs_to_jiffies(local->remote_lto));
+	return nfc_llcp_parse_gb_tlv(local,
+				     &local->remote_gb[3],
+				     local->remote_gb_len - 3);
 }
 
 static u8 nfc_llcp_dsap(struct sk_buff *pdu)
@@ -443,46 +444,146 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu)
 	sock->recv_ack_n = (sock->recv_n - 1) % 16;
 }
 
+static void nfc_llcp_tx_work(struct work_struct *work)
+{
+	struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
+						    tx_work);
+	struct sk_buff *skb;
+	struct sock *sk;
+	struct nfc_llcp_sock *llcp_sock;
+
+	skb = skb_dequeue(&local->tx_queue);
+	if (skb != NULL) {
+		sk = skb->sk;
+		llcp_sock = nfc_llcp_sock(sk);
+		if (llcp_sock != NULL) {
+			int ret;
+
+			pr_debug("Sending pending skb\n");
+			print_hex_dump(KERN_DEBUG, "LLCP Tx: ",
+				       DUMP_PREFIX_OFFSET, 16, 1,
+				       skb->data, skb->len, true);
+
+			ret = nfc_data_exchange(local->dev, local->target_idx,
+						skb, nfc_llcp_recv, local);
+
+			if (!ret && nfc_llcp_ptype(skb) == LLCP_PDU_I) {
+				skb = skb_get(skb);
+				skb_queue_tail(&llcp_sock->tx_pending_queue,
+					       skb);
+			}
+		} else {
+			nfc_llcp_send_symm(local->dev);
+		}
+	} else {
+		nfc_llcp_send_symm(local->dev);
+	}
+
+	mod_timer(&local->link_timer,
+		  jiffies + msecs_to_jiffies(2 * local->remote_lto));
+}
+
+static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local *local,
+							  u8 ssap)
+{
+	struct sock *sk;
+	struct nfc_llcp_sock *llcp_sock;
+	struct hlist_node *node;
+
+	read_lock(&local->connecting_sockets.lock);
+
+	sk_for_each(sk, node, &local->connecting_sockets.head) {
+		llcp_sock = nfc_llcp_sock(sk);
+
+		if (llcp_sock->ssap == ssap) {
+			sock_hold(&llcp_sock->sk);
+			goto out;
+		}
+	}
+
+	llcp_sock = NULL;
+
+out:
+	read_unlock(&local->connecting_sockets.lock);
+
+	return llcp_sock;
+}
+
 static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
 					       u8 ssap, u8 dsap)
 {
-	struct nfc_llcp_sock *sock, *llcp_sock, *n;
+	struct sock *sk;
+	struct hlist_node *node;
+	struct nfc_llcp_sock *llcp_sock;
 
 	pr_debug("ssap dsap %d %d\n", ssap, dsap);
 
 	if (ssap == 0 && dsap == 0)
 		return NULL;
 
-	mutex_lock(&local->socket_lock);
-	sock = local->sockets[ssap];
-	if (sock == NULL) {
-		mutex_unlock(&local->socket_lock);
-		return NULL;
-	}
+	read_lock(&local->sockets.lock);
 
-	pr_debug("root dsap %d (%d)\n", sock->dsap, dsap);
+	llcp_sock = NULL;
 
-	if (sock->dsap == dsap) {
-		sock_hold(&sock->sk);
-		mutex_unlock(&local->socket_lock);
-		return sock;
+	sk_for_each(sk, node, &local->sockets.head) {
+		llcp_sock = nfc_llcp_sock(sk);
+
+		if (llcp_sock->ssap == ssap &&
+		    llcp_sock->dsap == dsap)
+			break;
 	}
 
-	list_for_each_entry_safe(llcp_sock, n, &sock->list, list) {
-		pr_debug("llcp_sock %p sk %p dsap %d\n", llcp_sock,
-			 &llcp_sock->sk, llcp_sock->dsap);
-		if (llcp_sock->dsap == dsap) {
-			sock_hold(&llcp_sock->sk);
-			mutex_unlock(&local->socket_lock);
-			return llcp_sock;
-		}
+	read_unlock(&local->sockets.lock);
+
+	if (llcp_sock == NULL)
+		return NULL;
+
+	sock_hold(&llcp_sock->sk);
+
+	return llcp_sock;
+}
+
+static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local,
+						  u8 *sn, size_t sn_len)
+{
+	struct sock *sk;
+	struct hlist_node *node;
+	struct nfc_llcp_sock *llcp_sock;
+
+	pr_debug("sn %zd\n", sn_len);
+
+	if (sn == NULL || sn_len == 0)
+		return NULL;
+
+	read_lock(&local->sockets.lock);
+
+	llcp_sock = NULL;
+
+	sk_for_each(sk, node, &local->sockets.head) {
+		llcp_sock = nfc_llcp_sock(sk);
+
+		if (llcp_sock->sk.sk_state != LLCP_LISTEN)
+			continue;
+
+		if (llcp_sock->service_name == NULL ||
+		    llcp_sock->service_name_len == 0)
+			continue;
+
+		if (llcp_sock->service_name_len != sn_len)
+			continue;
+
+		if (memcmp(sn, llcp_sock->service_name, sn_len) == 0)
+			break;
 	}
 
-	pr_err("Could not find socket for %d %d\n", ssap, dsap);
+	read_unlock(&local->sockets.lock);
 
-	mutex_unlock(&local->socket_lock);
+	if (llcp_sock == NULL)
+		return NULL;
 
-	return NULL;
+	sock_hold(&llcp_sock->sk);
+
+	return llcp_sock;
 }
 
 static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock)
@@ -518,35 +619,19 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
 {
 	struct sock *new_sk, *parent;
 	struct nfc_llcp_sock *sock, *new_sock;
-	u8 dsap, ssap, bound_sap, reason;
+	u8 dsap, ssap, reason;
 
 	dsap = nfc_llcp_dsap(skb);
 	ssap = nfc_llcp_ssap(skb);
 
 	pr_debug("%d %d\n", dsap, ssap);
 
-	nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
-			   skb->len - LLCP_HEADER_SIZE);
-
 	if (dsap != LLCP_SAP_SDP) {
-		bound_sap = dsap;
-
-		mutex_lock(&local->socket_lock);
-		sock = local->sockets[dsap];
-		if (sock == NULL) {
-			mutex_unlock(&local->socket_lock);
+		sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
+		if (sock == NULL || sock->sk.sk_state != LLCP_LISTEN) {
 			reason = LLCP_DM_NOBOUND;
 			goto fail;
 		}
-
-		sock_hold(&sock->sk);
-		mutex_unlock(&local->socket_lock);
-
-		lock_sock(&sock->sk);
-
-		if (sock->dsap == LLCP_SAP_SDP &&
-		    sock->sk.sk_state == LLCP_LISTEN)
-			goto enqueue;
 	} else {
 		u8 *sn;
 		size_t sn_len;
@@ -559,40 +644,15 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
 
 		pr_debug("Service name length %zu\n", sn_len);
 
-		mutex_lock(&local->socket_lock);
-		for (bound_sap = 0; bound_sap < LLCP_LOCAL_SAP_OFFSET;
-		     bound_sap++) {
-			sock = local->sockets[bound_sap];
-			if (sock == NULL)
-				continue;
-
-			if (sock->service_name == NULL ||
-			    sock->service_name_len == 0)
-					continue;
-
-			if (sock->service_name_len != sn_len)
-				continue;
-
-			if (sock->dsap == LLCP_SAP_SDP &&
-			    sock->sk.sk_state == LLCP_LISTEN &&
-			    !memcmp(sn, sock->service_name, sn_len)) {
-				pr_debug("Found service name at SAP %d\n",
-					 bound_sap);
-				sock_hold(&sock->sk);
-				mutex_unlock(&local->socket_lock);
-
-				lock_sock(&sock->sk);
-
-				goto enqueue;
-			}
+		sock = nfc_llcp_sock_get_sn(local, sn, sn_len);
+		if (sock == NULL) {
+			reason = LLCP_DM_NOBOUND;
+			goto fail;
 		}
-		mutex_unlock(&local->socket_lock);
 	}
 
-	reason = LLCP_DM_NOBOUND;
-	goto fail;
+	lock_sock(&sock->sk);
 
-enqueue:
 	parent = &sock->sk;
 
 	if (sk_acceptq_is_full(parent)) {
@@ -612,15 +672,19 @@ enqueue:
 
 	new_sock = nfc_llcp_sock(new_sk);
 	new_sock->dev = local->dev;
-	new_sock->local = local;
+	new_sock->local = nfc_llcp_local_get(local);
+	new_sock->miu = local->remote_miu;
 	new_sock->nfc_protocol = sock->nfc_protocol;
-	new_sock->ssap = bound_sap;
+	new_sock->ssap = sock->ssap;
 	new_sock->dsap = ssap;
 	new_sock->parent = parent;
 
+	nfc_llcp_parse_connection_tlv(new_sock, &skb->data[LLCP_HEADER_SIZE],
+				      skb->len - LLCP_HEADER_SIZE);
+
 	pr_debug("new sock %p sk %p\n", new_sock, &new_sock->sk);
 
-	list_add_tail(&new_sock->list, &sock->list);
+	nfc_llcp_sock_link(&local->sockets, new_sk);
 
 	nfc_llcp_accept_enqueue(&sock->sk, new_sk);
 
@@ -654,12 +718,12 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
 
 	pr_debug("Remote ready %d tx queue len %d remote rw %d",
 		 sock->remote_ready, skb_queue_len(&sock->tx_pending_queue),
-		 local->remote_rw);
+		 sock->rw);
 
 	/* Try to queue some I frames for transmission */
 	while (sock->remote_ready &&
-	       skb_queue_len(&sock->tx_pending_queue) < local->remote_rw) {
-		struct sk_buff *pdu, *pending_pdu;
+	       skb_queue_len(&sock->tx_pending_queue) < sock->rw) {
+		struct sk_buff *pdu;
 
 		pdu = skb_dequeue(&sock->tx_queue);
 		if (pdu == NULL)
@@ -668,10 +732,7 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
 		/* Update N(S)/N(R) */
 		nfc_llcp_set_nrns(sock, pdu);
 
-		pending_pdu = skb_clone(pdu, GFP_KERNEL);
-
 		skb_queue_tail(&local->tx_queue, pdu);
-		skb_queue_tail(&sock->tx_pending_queue, pending_pdu);
 		nr_frames++;
 	}
 
@@ -728,11 +789,21 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
 
 		llcp_sock->send_ack_n = nr;
 
-		skb_queue_walk_safe(&llcp_sock->tx_pending_queue, s, tmp)
-			if (nfc_llcp_ns(s) <= nr) {
-				skb_unlink(s, &llcp_sock->tx_pending_queue);
-				kfree_skb(s);
-			}
+		/* Remove and free all skbs until ns == nr */
+		skb_queue_walk_safe(&llcp_sock->tx_pending_queue, s, tmp) {
+			skb_unlink(s, &llcp_sock->tx_pending_queue);
+			kfree_skb(s);
+
+			if (nfc_llcp_ns(s) == nr)
+				break;
+		}
+
+		/* Re-queue the remaining skbs for transmission */
+		skb_queue_reverse_walk_safe(&llcp_sock->tx_pending_queue,
+					    s, tmp) {
+			skb_unlink(s, &llcp_sock->tx_pending_queue);
+			skb_queue_head(&local->tx_queue, s);
+		}
 	}
 
 	if (ptype == LLCP_PDU_RR)
@@ -740,7 +811,7 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
 	else if (ptype == LLCP_PDU_RNR)
 		llcp_sock->remote_ready = false;
 
-	if (nfc_llcp_queue_i_frames(llcp_sock) == 0)
+	if (nfc_llcp_queue_i_frames(llcp_sock) == 0 && ptype == LLCP_PDU_I)
 		nfc_llcp_send_rr(llcp_sock);
 
 	release_sock(sk);
@@ -791,11 +862,7 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
 	dsap = nfc_llcp_dsap(skb);
 	ssap = nfc_llcp_ssap(skb);
 
-	llcp_sock = nfc_llcp_sock_get(local, dsap, ssap);
-
-	if (llcp_sock == NULL)
-		llcp_sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
-
+	llcp_sock = nfc_llcp_connecting_sock_get(local, dsap);
 	if (llcp_sock == NULL) {
 		pr_err("Invalid CC\n");
 		nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN);
@@ -803,11 +870,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
 		return;
 	}
 
-	llcp_sock->dsap = ssap;
 	sk = &llcp_sock->sk;
 
-	nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
-			   skb->len - LLCP_HEADER_SIZE);
+	/* Unlink from connecting and link to the client array */
+	nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
+	nfc_llcp_sock_link(&local->sockets, sk);
+	llcp_sock->dsap = ssap;
+
+	nfc_llcp_parse_connection_tlv(llcp_sock, &skb->data[LLCP_HEADER_SIZE],
+				      skb->len - LLCP_HEADER_SIZE);
 
 	sk->sk_state = LLCP_CONNECTED;
 	sk->sk_state_change(sk);
@@ -891,6 +962,21 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
 	return;
 }
 
+int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
+{
+	struct nfc_llcp_local *local;
+
+	local = nfc_llcp_find_local(dev);
+	if (local == NULL)
+		return -ENODEV;
+
+	local->rx_pending = skb_get(skb);
+	del_timer(&local->link_timer);
+	queue_work(local->rx_wq, &local->rx_work);
+
+	return 0;
+}
+
 void nfc_llcp_mac_is_down(struct nfc_dev *dev)
 {
 	struct nfc_llcp_local *local;
@@ -943,8 +1029,8 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
 
 	local->dev = ndev;
 	INIT_LIST_HEAD(&local->list);
+	kref_init(&local->ref);
 	mutex_init(&local->sdp_lock);
-	mutex_init(&local->socket_lock);
 	init_timer(&local->link_timer);
 	local->link_timer.data = (unsigned long) local;
 	local->link_timer.function = nfc_llcp_symm_timer;
@@ -984,11 +1070,13 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
 		goto err_rx_wq;
 	}
 
+	local->sockets.lock = __RW_LOCK_UNLOCKED(local->sockets.lock);
+	local->connecting_sockets.lock = __RW_LOCK_UNLOCKED(local->connecting_sockets.lock);
+
 	nfc_llcp_build_gb(local);
 
 	local->remote_miu = LLCP_DEFAULT_MIU;
 	local->remote_lto = LLCP_DEFAULT_LTO;
-	local->remote_rw = LLCP_DEFAULT_RW;
 
 	list_add(&llcp_devices, &local->list);
 
@@ -1015,14 +1103,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev)
 		return;
 	}
 
-	list_del(&local->list);
-	nfc_llcp_socket_release(local);
-	del_timer_sync(&local->link_timer);
-	skb_queue_purge(&local->tx_queue);
-	destroy_workqueue(local->tx_wq);
-	destroy_workqueue(local->rx_wq);
-	kfree_skb(local->rx_pending);
-	kfree(local);
+	nfc_llcp_local_put(local);
 }
 
 int __init nfc_llcp_init(void)
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h
index 50680ce..7286c86 100644
--- a/net/nfc/llcp/llcp.h
+++ b/net/nfc/llcp/llcp.h
@@ -40,12 +40,18 @@ enum llcp_state {
 
 struct nfc_llcp_sock;
 
+struct llcp_sock_list {
+	struct hlist_head head;
+	rwlock_t          lock;
+};
+
 struct nfc_llcp_local {
 	struct list_head list;
 	struct nfc_dev *dev;
 
+	struct kref ref;
+
 	struct mutex sdp_lock;
-	struct mutex socket_lock;
 
 	struct timer_list link_timer;
 	struct sk_buff_head tx_queue;
@@ -77,24 +83,26 @@ struct nfc_llcp_local {
 	u16 remote_lto;
 	u8  remote_opt;
 	u16 remote_wks;
-	u8  remote_rw;
 
 	/* sockets array */
-	struct nfc_llcp_sock *sockets[LLCP_MAX_SAP];
+	struct llcp_sock_list sockets;
+	struct llcp_sock_list connecting_sockets;
 };
 
 struct nfc_llcp_sock {
 	struct sock sk;
-	struct list_head list;
 	struct nfc_dev *dev;
 	struct nfc_llcp_local *local;
 	u32 target_idx;
 	u32 nfc_protocol;
 
+	/* Link parameters */
 	u8 ssap;
 	u8 dsap;
 	char *service_name;
 	size_t service_name_len;
+	u8 rw;
+	u16 miu;
 
 	/* Link variables */
 	u8 send_n;
@@ -164,7 +172,11 @@ struct nfc_llcp_sock {
 #define LLCP_DM_REJ     0x03
 
 
+void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s);
+void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s);
 struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
+struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local);
+int nfc_llcp_local_put(struct nfc_llcp_local *local);
 u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
 			 struct nfc_llcp_sock *sock);
 u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local);
@@ -179,8 +191,10 @@ void nfc_llcp_accept_enqueue(struct sock *parent, struct sock *sk);
 struct sock *nfc_llcp_accept_dequeue(struct sock *sk, struct socket *newsock);
 
 /* TLV API */
-int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
-		       u8 *tlv_array, u16 tlv_array_len);
+int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
+			  u8 *tlv_array, u16 tlv_array_len);
+int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
+				  u8 *tlv_array, u16 tlv_array_len);
 
 /* Commands API */
 void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index 17a707d..2c0b317 100644
--- a/net/nfc/llcp/sock.c
+++ b/net/nfc/llcp/sock.c
@@ -111,7 +111,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 	}
 
 	llcp_sock->dev = dev;
-	llcp_sock->local = local;
+	llcp_sock->local = nfc_llcp_local_get(local);
 	llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
 	llcp_sock->service_name_len = min_t(unsigned int,
 					    llcp_addr.service_name_len,
@@ -124,7 +124,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 	if (llcp_sock->ssap == LLCP_MAX_SAP)
 		goto put_dev;
 
-	local->sockets[llcp_sock->ssap] = llcp_sock;
+	nfc_llcp_sock_link(&local->sockets, sk);
 
 	pr_debug("Socket bound to SAP %d\n", llcp_sock->ssap);
 
@@ -382,15 +382,6 @@ static int llcp_sock_release(struct socket *sock)
 		goto out;
 	}
 
-	mutex_lock(&local->socket_lock);
-
-	if (llcp_sock == local->sockets[llcp_sock->ssap])
-		local->sockets[llcp_sock->ssap] = NULL;
-	else
-		list_del_init(&llcp_sock->list);
-
-	mutex_unlock(&local->socket_lock);
-
 	lock_sock(sk);
 
 	/* Send a DISC */
@@ -415,14 +406,12 @@ static int llcp_sock_release(struct socket *sock)
 		}
 	}
 
-	/* Freeing the SAP */
-	if ((sk->sk_state == LLCP_CONNECTED
-	     && llcp_sock->ssap > LLCP_LOCAL_SAP_OFFSET) ||
-	    sk->sk_state == LLCP_BOUND || sk->sk_state == LLCP_LISTEN)
-		nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
+	nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
 
 	release_sock(sk);
 
+	nfc_llcp_sock_unlink(&local->sockets, sk);
+
 out:
 	sock_orphan(sk);
 	sock_put(sk);
@@ -490,7 +479,8 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
 	}
 
 	llcp_sock->dev = dev;
-	llcp_sock->local = local;
+	llcp_sock->local = nfc_llcp_local_get(local);
+	llcp_sock->miu = llcp_sock->local->remote_miu;
 	llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
 	if (llcp_sock->ssap == LLCP_SAP_MAX) {
 		ret = -ENOMEM;
@@ -508,21 +498,26 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
 					  llcp_sock->service_name_len,
 					  GFP_KERNEL);
 
-	local->sockets[llcp_sock->ssap] = llcp_sock;
+	nfc_llcp_sock_link(&local->connecting_sockets, sk);
 
 	ret = nfc_llcp_send_connect(llcp_sock);
 	if (ret)
-		goto put_dev;
+		goto sock_unlink;
 
 	ret = sock_wait_state(sk, LLCP_CONNECTED,
 			      sock_sndtimeo(sk, flags & O_NONBLOCK));
 	if (ret)
-		goto put_dev;
+		goto sock_unlink;
 
 	release_sock(sk);
 
 	return 0;
 
+sock_unlink:
+	nfc_llcp_put_ssap(local, llcp_sock->ssap);
+
+	nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
+
 put_dev:
 	nfc_put_device(dev);
 
@@ -687,13 +682,14 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
 
 	llcp_sock->ssap = 0;
 	llcp_sock->dsap = LLCP_SAP_SDP;
+	llcp_sock->rw = LLCP_DEFAULT_RW;
+	llcp_sock->miu = LLCP_DEFAULT_MIU;
 	llcp_sock->send_n = llcp_sock->send_ack_n = 0;
 	llcp_sock->recv_n = llcp_sock->recv_ack_n = 0;
 	llcp_sock->remote_ready = 1;
 	skb_queue_head_init(&llcp_sock->tx_queue);
 	skb_queue_head_init(&llcp_sock->tx_pending_queue);
 	skb_queue_head_init(&llcp_sock->tx_backlog_queue);
-	INIT_LIST_HEAD(&llcp_sock->list);
 	INIT_LIST_HEAD(&llcp_sock->accept_queue);
 
 	if (sock != NULL)
@@ -704,8 +700,6 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
 
 void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
 {
-	struct nfc_llcp_local *local = sock->local;
-
 	kfree(sock->service_name);
 
 	skb_queue_purge(&sock->tx_queue);
@@ -714,12 +708,9 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
 
 	list_del_init(&sock->accept_queue);
 
-	if (local != NULL && sock == local->sockets[sock->ssap])
-		local->sockets[sock->ssap] = NULL;
-	else
-		list_del_init(&sock->list);
-
 	sock->parent = NULL;
+
+	nfc_llcp_local_put(sock->local);
 }
 
 static int llcp_sock_create(struct net *net, struct socket *sock,
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index d560e6f..766a02b 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -387,7 +387,8 @@ static int nci_dev_down(struct nfc_dev *nfc_dev)
 	return nci_close_device(ndev);
 }
 
-static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
+static int nci_start_poll(struct nfc_dev *nfc_dev,
+			  __u32 im_protocols, __u32 tm_protocols)
 {
 	struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
 	int rc;
@@ -413,11 +414,11 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
 			return -EBUSY;
 	}
 
-	rc = nci_request(ndev, nci_rf_discover_req, protocols,
+	rc = nci_request(ndev, nci_rf_discover_req, im_protocols,
 			 msecs_to_jiffies(NCI_RF_DISC_TIMEOUT));
 
 	if (!rc)
-		ndev->poll_prots = protocols;
+		ndev->poll_prots = im_protocols;
 
 	return rc;
 }
@@ -521,9 +522,9 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev,
 	}
 }
 
-static int nci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target,
-			     struct sk_buff *skb,
-			     data_exchange_cb_t cb, void *cb_context)
+static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
+			  struct sk_buff *skb,
+			  data_exchange_cb_t cb, void *cb_context)
 {
 	struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
 	int rc;
@@ -556,7 +557,7 @@ static struct nfc_ops nci_nfc_ops = {
 	.stop_poll = nci_stop_poll,
 	.activate_target = nci_activate_target,
 	.deactivate_target = nci_deactivate_target,
-	.data_exchange = nci_data_exchange,
+	.im_transceive = nci_transceive,
 };
 
 /* ---- Interface to NCI drivers ---- */
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
index cb26461..2ab196a 100644
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -106,7 +106,7 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
 	nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
 	data += 2;
 
-	nfca_poll->nfcid1_len = *data++;
+	nfca_poll->nfcid1_len = min_t(__u8, *data++, NFC_NFCID1_MAXSIZE);
 
 	pr_debug("sens_res 0x%x, nfcid1_len %d\n",
 		 nfca_poll->sens_res, nfca_poll->nfcid1_len);
@@ -130,7 +130,7 @@ static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev,
 			struct rf_tech_specific_params_nfcb_poll *nfcb_poll,
 						     __u8 *data)
 {
-	nfcb_poll->sensb_res_len = *data++;
+	nfcb_poll->sensb_res_len = min_t(__u8, *data++, NFC_SENSB_RES_MAXSIZE);
 
 	pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len);
 
@@ -145,7 +145,7 @@ static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev,
 						     __u8 *data)
 {
 	nfcf_poll->bit_rate = *data++;
-	nfcf_poll->sensf_res_len = *data++;
+	nfcf_poll->sensf_res_len = min_t(__u8, *data++, NFC_SENSF_RES_MAXSIZE);
 
 	pr_debug("bit_rate %d, sensf_res_len %d\n",
 		 nfcf_poll->bit_rate, nfcf_poll->sensf_res_len);
@@ -331,7 +331,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
 	switch (ntf->activation_rf_tech_and_mode) {
 	case NCI_NFC_A_PASSIVE_POLL_MODE:
 		nfca_poll = &ntf->activation_params.nfca_poll_iso_dep;
-		nfca_poll->rats_res_len = *data++;
+		nfca_poll->rats_res_len = min_t(__u8, *data++, 20);
 		pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len);
 		if (nfca_poll->rats_res_len > 0) {
 			memcpy(nfca_poll->rats_res,
@@ -341,7 +341,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
 
 	case NCI_NFC_B_PASSIVE_POLL_MODE:
 		nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep;
-		nfcb_poll->attrib_res_len = *data++;
+		nfcb_poll->attrib_res_len = min_t(__u8, *data++, 50);
 		pr_debug("attrib_res_len %d\n", nfcb_poll->attrib_res_len);
 		if (nfcb_poll->attrib_res_len > 0) {
 			memcpy(nfcb_poll->attrib_res,
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index 581d419..03c31db 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -49,6 +49,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
 	[NFC_ATTR_COMM_MODE] = { .type = NLA_U8 },
 	[NFC_ATTR_RF_MODE] = { .type = NLA_U8 },
 	[NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
+	[NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 },
+	[NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 },
 };
 
 static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
@@ -219,6 +221,68 @@ free_msg:
 	return -EMSGSIZE;
 }
 
+int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+			  NFC_EVENT_TM_ACTIVATED);
+	if (!hdr)
+		goto free_msg;
+
+	if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+		goto nla_put_failure;
+	if (nla_put_u32(msg, NFC_ATTR_TM_PROTOCOLS, protocol))
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+
+	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+
+	return 0;
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+free_msg:
+	nlmsg_free(msg);
+	return -EMSGSIZE;
+}
+
+int nfc_genl_tm_deactivated(struct nfc_dev *dev)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+			  NFC_EVENT_TM_DEACTIVATED);
+	if (!hdr)
+		goto free_msg;
+
+	if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+
+	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+
+	return 0;
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+free_msg:
+	nlmsg_free(msg);
+	return -EMSGSIZE;
+}
+
 int nfc_genl_device_added(struct nfc_dev *dev)
 {
 	struct sk_buff *msg;
@@ -519,16 +583,25 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
 	struct nfc_dev *dev;
 	int rc;
 	u32 idx;
-	u32 protocols;
+	u32 im_protocols = 0, tm_protocols = 0;
 
 	pr_debug("Poll start\n");
 
 	if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
-	    !info->attrs[NFC_ATTR_PROTOCOLS])
+	    ((!info->attrs[NFC_ATTR_IM_PROTOCOLS] &&
+	      !info->attrs[NFC_ATTR_PROTOCOLS]) &&
+	     !info->attrs[NFC_ATTR_TM_PROTOCOLS]))
 		return -EINVAL;
 
 	idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
-	protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
+
+	if (info->attrs[NFC_ATTR_TM_PROTOCOLS])
+		tm_protocols = nla_get_u32(info->attrs[NFC_ATTR_TM_PROTOCOLS]);
+
+	if (info->attrs[NFC_ATTR_IM_PROTOCOLS])
+		im_protocols = nla_get_u32(info->attrs[NFC_ATTR_IM_PROTOCOLS]);
+	else if (info->attrs[NFC_ATTR_PROTOCOLS])
+		im_protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
 
 	dev = nfc_get_device(idx);
 	if (!dev)
@@ -536,7 +609,7 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
 
 	mutex_lock(&dev->genl_data.genl_data_mutex);
 
-	rc = nfc_start_poll(dev, protocols);
+	rc = nfc_start_poll(dev, im_protocols, tm_protocols);
 	if (!rc)
 		dev->genl_data.poll_req_pid = info->snd_pid;
 
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index 3dd4232..c5e42b7 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -55,6 +55,7 @@ int nfc_llcp_register_device(struct nfc_dev *dev);
 void nfc_llcp_unregister_device(struct nfc_dev *dev);
 int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len);
 u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len);
+int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb);
 int __init nfc_llcp_init(void);
 void nfc_llcp_exit(void);
 
@@ -90,6 +91,12 @@ static inline u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *gb_len)
 	return NULL;
 }
 
+static inline int nfc_llcp_data_received(struct nfc_dev *dev,
+					 struct sk_buff *skb)
+{
+	return 0;
+}
+
 static inline int nfc_llcp_init(void)
 {
 	return 0;
@@ -128,6 +135,9 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
 			       u8 comm_mode, u8 rf_mode);
 int nfc_genl_dep_link_down_event(struct nfc_dev *dev);
 
+int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol);
+int nfc_genl_tm_deactivated(struct nfc_dev *dev);
+
 struct nfc_dev *nfc_get_device(unsigned int idx);
 
 static inline void nfc_put_device(struct nfc_dev *dev)
@@ -158,7 +168,7 @@ int nfc_dev_up(struct nfc_dev *dev);
 
 int nfc_dev_down(struct nfc_dev *dev);
 
-int nfc_start_poll(struct nfc_dev *dev, u32 protocols);
+int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols);
 
 int nfc_stop_poll(struct nfc_dev *dev);
 
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
index ec1134c..8b8a6a2 100644
--- a/net/nfc/rawsock.c
+++ b/net/nfc/rawsock.c
@@ -54,7 +54,10 @@ static int rawsock_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
 
-	pr_debug("sock=%p\n", sock);
+	pr_debug("sock=%p sk=%p\n", sock, sk);
+
+	if (!sk)
+		return 0;
 
 	sock_orphan(sk);
 	sock_put(sk);
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 0f66174..8a10d5b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -592,7 +592,7 @@ static void init_prb_bdqc(struct packet_sock *po,
 	p1->knxt_seq_num = 1;
 	p1->pkbdq = pg_vec;
 	pbd = (struct tpacket_block_desc *)pg_vec[0].buffer;
-	p1->pkblk_start	= (char *)pg_vec[0].buffer;
+	p1->pkblk_start	= pg_vec[0].buffer;
 	p1->kblk_size = req_u->req3.tp_block_size;
 	p1->knum_blocks	= req_u->req3.tp_block_nr;
 	p1->hdrlen = po->tp_hdrlen;
@@ -824,8 +824,7 @@ static void prb_open_block(struct tpacket_kbdq_core *pkc1,
 		h1->ts_first_pkt.ts_sec = ts.tv_sec;
 		h1->ts_first_pkt.ts_nsec = ts.tv_nsec;
 		pkc1->pkblk_start = (char *)pbd1;
-		pkc1->nxt_offset = (char *)(pkc1->pkblk_start +
-		BLK_PLUS_PRIV(pkc1->blk_sizeof_priv));
+		pkc1->nxt_offset = pkc1->pkblk_start + BLK_PLUS_PRIV(pkc1->blk_sizeof_priv);
 		BLOCK_O2FP(pbd1) = (__u32)BLK_PLUS_PRIV(pkc1->blk_sizeof_priv);
 		BLOCK_O2PRIV(pbd1) = BLK_HDR_LEN;
 		pbd1->version = pkc1->version;
@@ -1018,7 +1017,7 @@ static void *__packet_lookup_frame_in_block(struct packet_sock *po,
 	struct tpacket_block_desc *pbd;
 	char *curr, *end;
 
-	pkc = GET_PBDQC_FROM_RB(((struct packet_ring_buffer *)&po->rx_ring));
+	pkc = GET_PBDQC_FROM_RB(&po->rx_ring);
 	pbd = GET_CURR_PBLOCK_DESC_FROM_CORE(pkc);
 
 	/* Queue is frozen when user space is lagging behind */
@@ -1044,7 +1043,7 @@ static void *__packet_lookup_frame_in_block(struct packet_sock *po,
 	smp_mb();
 	curr = pkc->nxt_offset;
 	pkc->skb = skb;
-	end = (char *) ((char *)pbd + pkc->kblk_size);
+	end = (char *)pbd + pkc->kblk_size;
 
 	/* first try the current block */
 	if (curr+TOTAL_PKT_LEN_INCL_ALIGN(len) < end) {
@@ -1476,7 +1475,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
 	 *	Find the device first to size check it
 	 */
 
-	saddr->spkt_device[13] = 0;
+	saddr->spkt_device[sizeof(saddr->spkt_device) - 1] = 0;
 retry:
 	rcu_read_lock();
 	dev = dev_get_by_name_rcu(sock_net(sk), saddr->spkt_device);
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index 779ce4f..5a940db 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -5,8 +5,8 @@
  *
  * Copyright (C) 2008 Nokia Corporation.
  *
- * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
- * Original author: Sakari Ailus <sakari.ailus@nokia.com>
+ * Authors: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Rémi Denis-Courmont
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c
index bf35b4e..12c30f3 100644
--- a/net/phonet/datagram.c
+++ b/net/phonet/datagram.c
@@ -5,8 +5,8 @@
  *
  * Copyright (C) 2008 Nokia Corporation.
  *
- * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
- * Original author: Sakari Ailus <sakari.ailus@nokia.com>
+ * Authors: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Rémi Denis-Courmont
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c
index d012089..a2fba7e 100644
--- a/net/phonet/pep-gprs.c
+++ b/net/phonet/pep-gprs.c
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation.
  *
- * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
+ * Author: Rémi Denis-Courmont
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 9dd4f92..576f22c 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation.
  *
- * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
+ * Author: Rémi Denis-Courmont
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 36f75a9..5bf6341 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -5,8 +5,8 @@
  *
  * Copyright (C) 2008 Nokia Corporation.
  *
- * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
- * Original author: Sakari Ailus <sakari.ailus@nokia.com>
+ * Authors: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Rémi Denis-Courmont
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
index cfdf135..7dd762a 100644
--- a/net/phonet/pn_netlink.c
+++ b/net/phonet/pn_netlink.c
@@ -5,8 +5,8 @@
  *
  * Copyright (C) 2008 Nokia Corporation.
  *
- * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
- * Original author: Sakari Ailus <sakari.ailus@nokia.com>
+ * Authors: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Remi Denis-Courmont
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 89cfa9c..0acc943 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -5,8 +5,8 @@
  *
  * Copyright (C) 2008 Nokia Corporation.
  *
- * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
- * Original author: Sakari Ailus <sakari.ailus@nokia.com>
+ * Authors: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Rémi Denis-Courmont
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/net/phonet/sysctl.c b/net/phonet/sysctl.c
index 696348f..d6bbbbd 100644
--- a/net/phonet/sysctl.c
+++ b/net/phonet/sysctl.c
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation.
  *
- * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
+ * Author: Rémi Denis-Courmont
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index f974961..752b723 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -325,7 +325,7 @@ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked)
 
 	rfkill_global_states[type].cur = blocked;
 	list_for_each_entry(rfkill, &rfkill_list, node) {
-		if (rfkill->type != type)
+		if (rfkill->type != type && type != RFKILL_TYPE_ALL)
 			continue;
 
 		rfkill_set_block(rfkill, blocked);
diff --git a/net/rxrpc/ar-error.c b/net/rxrpc/ar-error.c
index 5d6b572..a920608 100644
--- a/net/rxrpc/ar-error.c
+++ b/net/rxrpc/ar-error.c
@@ -81,10 +81,6 @@ void rxrpc_UDP_error_report(struct sock *sk)
 			_net("I/F MTU %u", mtu);
 		}
 
-		/* ip_rt_frag_needed() may have eaten the info */
-		if (mtu == 0)
-			mtu = ntohs(icmp_hdr(skb)->un.frag.mtu);
-
 		if (mtu == 0) {
 			/* they didn't give us a size, estimate one */
 			if (mtu > 1500) {
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 5942d27..9c90811 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -673,7 +673,9 @@ void sctp_addr_wq_timeout_handler(unsigned long arg)
 				SCTP_DEBUG_PRINTK("sctp_addrwq_timo_handler: sctp_asconf_mgmt failed\n");
 			sctp_bh_unlock_sock(sk);
 		}
+#if IS_ENABLED(CONFIG_IPV6)
 free_next:
+#endif
 		list_del(&addrw->list);
 		kfree(addrw);
 	}
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index fddcccf..3691132 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -129,34 +129,6 @@ xdr_terminate_string(struct xdr_buf *buf, const u32 len)
 EXPORT_SYMBOL_GPL(xdr_terminate_string);
 
 void
-xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
-		 unsigned int len)
-{
-	struct kvec *tail = xdr->tail;
-	u32 *p;
-
-	xdr->pages = pages;
-	xdr->page_base = base;
-	xdr->page_len = len;
-
-	p = (u32 *)xdr->head[0].iov_base + XDR_QUADLEN(xdr->head[0].iov_len);
-	tail->iov_base = p;
-	tail->iov_len = 0;
-
-	if (len & 3) {
-		unsigned int pad = 4 - (len & 3);
-
-		*p = 0;
-		tail->iov_base = (char *)p + (len & 3);
-		tail->iov_len  = pad;
-		len += pad;
-	}
-	xdr->buflen += len;
-	xdr->len += len;
-}
-EXPORT_SYMBOL_GPL(xdr_encode_pages);
-
-void
 xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
 		 struct page **pages, unsigned int base, unsigned int len)
 {
@@ -455,6 +427,16 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len)
 EXPORT_SYMBOL_GPL(xdr_shift_buf);
 
 /**
+ * xdr_stream_pos - Return the current offset from the start of the xdr_stream
+ * @xdr: pointer to struct xdr_stream
+ */
+unsigned int xdr_stream_pos(const struct xdr_stream *xdr)
+{
+	return (unsigned int)(XDR_QUADLEN(xdr->buf->len) - xdr->nwords) << 2;
+}
+EXPORT_SYMBOL_GPL(xdr_stream_pos);
+
+/**
  * xdr_init_encode - Initialize a struct xdr_stream for sending data.
  * @xdr: pointer to xdr_stream struct
  * @buf: pointer to XDR buffer in which to encode data
@@ -632,6 +614,7 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
 	xdr->buf = buf;
 	xdr->scratch.iov_base = NULL;
 	xdr->scratch.iov_len = 0;
+	xdr->nwords = XDR_QUADLEN(buf->len);
 	if (buf->head[0].iov_len != 0)
 		xdr_set_iov(xdr, buf->head, p, buf->len);
 	else if (buf->page_len != 0)
@@ -660,12 +643,14 @@ EXPORT_SYMBOL_GPL(xdr_init_decode_pages);
 
 static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
 {
+	unsigned int nwords = XDR_QUADLEN(nbytes);
 	__be32 *p = xdr->p;
-	__be32 *q = p + XDR_QUADLEN(nbytes);
+	__be32 *q = p + nwords;
 
-	if (unlikely(q > xdr->end || q < p))
+	if (unlikely(nwords > xdr->nwords || q > xdr->end || q < p))
 		return NULL;
 	xdr->p = q;
+	xdr->nwords -= nwords;
 	return p;
 }
 
@@ -732,6 +717,30 @@ __be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
 }
 EXPORT_SYMBOL_GPL(xdr_inline_decode);
 
+static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
+{
+	struct xdr_buf *buf = xdr->buf;
+	struct kvec *iov;
+	unsigned int nwords = XDR_QUADLEN(len);
+	unsigned int cur = xdr_stream_pos(xdr);
+
+	if (xdr->nwords == 0)
+		return 0;
+	if (nwords > xdr->nwords) {
+		nwords = xdr->nwords;
+		len = nwords << 2;
+	}
+	/* Realign pages to current pointer position */
+	iov  = buf->head;
+	if (cur < iov->iov_len)
+		xdr_shrink_bufhead(buf, iov->iov_len - cur);
+
+	/* Truncate page data and move it into the tail */
+	if (buf->page_len > len)
+		xdr_shrink_pagelen(buf, buf->page_len - len);
+	return len;
+}
+
 /**
  * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position
  * @xdr: pointer to xdr_stream struct
@@ -740,8 +749,10 @@ EXPORT_SYMBOL_GPL(xdr_inline_decode);
  * Moves data beyond the current pointer position from the XDR head[] buffer
  * into the page list. Any data that lies beyond current position + "len"
  * bytes is moved into the XDR tail[].
+ *
+ * Returns the number of XDR encoded bytes now contained in the pages
  */
-void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
+unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
 {
 	struct xdr_buf *buf = xdr->buf;
 	struct kvec *iov;
@@ -749,15 +760,10 @@ void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
 	unsigned int end;
 	int padding;
 
-	/* Realign pages to current pointer position */
-	iov  = buf->head;
-	shift = iov->iov_len + (char *)iov->iov_base - (char *)xdr->p;
-	if (shift > 0)
-		xdr_shrink_bufhead(buf, shift);
+	len = xdr_align_pages(xdr, len);
+	if (len == 0)
+		return 0;
 
-	/* Truncate page data and move it into the tail */
-	if (buf->page_len > len)
-		xdr_shrink_pagelen(buf, buf->page_len - len);
 	padding = (XDR_QUADLEN(len) << 2) - len;
 	xdr->iov = iov = buf->tail;
 	/* Compute remaining message length.  */
@@ -773,6 +779,8 @@ void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
 	 */
 	xdr->p = (__be32 *)((char *)iov->iov_base + padding);
 	xdr->end = (__be32 *)((char *)iov->iov_base + end);
+	xdr->nwords = XDR_QUADLEN(end);
+	return len;
 }
 EXPORT_SYMBOL_GPL(xdr_read_pages);
 
@@ -788,12 +796,13 @@ EXPORT_SYMBOL_GPL(xdr_read_pages);
  */
 void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
 {
-	xdr_read_pages(xdr, len);
+	len = xdr_align_pages(xdr, len);
 	/*
 	 * Position current pointer at beginning of tail, and
 	 * set remaining message length.
 	 */
-	xdr_set_page_base(xdr, 0, len);
+	if (len != 0)
+		xdr_set_page_base(xdr, 0, len);
 }
 EXPORT_SYMBOL_GPL(xdr_enter_page);
 
diff --git a/net/tipc/port.c b/net/tipc/port.c
index 2ad37a4..a1e8289 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -909,8 +909,8 @@ int tipc_createport(void *usr_handle,
 		warn("Port creation failed, no memory\n");
 		return -ENOMEM;
 	}
-	p_ptr = (struct tipc_port *)tipc_createport_raw(NULL, port_dispatcher,
-						   port_wakeup, importance);
+	p_ptr = tipc_createport_raw(NULL, port_dispatcher, port_wakeup,
+				    importance);
 	if (!p_ptr) {
 		kfree(up_ptr);
 		return -ENOMEM;
@@ -1078,8 +1078,7 @@ int tipc_disconnect_port(struct tipc_port *tp_ptr)
 	if (tp_ptr->connected) {
 		tp_ptr->connected = 0;
 		/* let timer expire on it's own to avoid deadlock! */
-		tipc_nodesub_unsubscribe(
-			&((struct tipc_port *)tp_ptr)->subscription);
+		tipc_nodesub_unsubscribe(&tp_ptr->subscription);
 		res = 0;
 	} else {
 		res = -ENOTCONN;
@@ -1099,7 +1098,7 @@ int tipc_disconnect(u32 ref)
 	p_ptr = tipc_port_lock(ref);
 	if (!p_ptr)
 		return -EINVAL;
-	res = tipc_disconnect_port((struct tipc_port *)p_ptr);
+	res = tipc_disconnect_port(p_ptr);
 	tipc_port_unlock(p_ptr);
 	return res;
 }
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 5577a44..11a863d 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -54,7 +54,7 @@ struct tipc_sock {
 };
 
 #define tipc_sk(sk) ((struct tipc_sock *)(sk))
-#define tipc_sk_port(sk) ((struct tipc_port *)(tipc_sk(sk)->p))
+#define tipc_sk_port(sk) (tipc_sk(sk)->p)
 
 #define tipc_rx_ready(sock) (!skb_queue_empty(&sock->sk->sk_receive_queue) || \
 			(sock->state == SS_DISCONNECTING))
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 641f2e4..79981d9 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -115,15 +115,24 @@
 #include <net/checksum.h>
 #include <linux/security.h>
 
-struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1];
+struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
 EXPORT_SYMBOL_GPL(unix_socket_table);
 DEFINE_SPINLOCK(unix_table_lock);
 EXPORT_SYMBOL_GPL(unix_table_lock);
 static atomic_long_t unix_nr_socks;
 
-#define unix_sockets_unbound	(&unix_socket_table[UNIX_HASH_SIZE])
 
-#define UNIX_ABSTRACT(sk)	(unix_sk(sk)->addr->hash != UNIX_HASH_SIZE)
+static struct hlist_head *unix_sockets_unbound(void *addr)
+{
+	unsigned long hash = (unsigned long)addr;
+
+	hash ^= hash >> 16;
+	hash ^= hash >> 8;
+	hash %= UNIX_HASH_SIZE;
+	return &unix_socket_table[UNIX_HASH_SIZE + hash];
+}
+
+#define UNIX_ABSTRACT(sk)	(unix_sk(sk)->addr->hash < UNIX_HASH_SIZE)
 
 #ifdef CONFIG_SECURITY_NETWORK
 static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
@@ -645,7 +654,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock)
 	INIT_LIST_HEAD(&u->link);
 	mutex_init(&u->readlock); /* single task reading lock */
 	init_waitqueue_head(&u->peer_wait);
-	unix_insert_socket(unix_sockets_unbound, sk);
+	unix_insert_socket(unix_sockets_unbound(sk), sk);
 out:
 	if (sk == NULL)
 		atomic_long_dec(&unix_nr_socks);
@@ -2239,47 +2248,54 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
 }
 
 #ifdef CONFIG_PROC_FS
-static struct sock *first_unix_socket(int *i)
+
+#define BUCKET_SPACE (BITS_PER_LONG - (UNIX_HASH_BITS + 1) - 1)
+
+#define get_bucket(x) ((x) >> BUCKET_SPACE)
+#define get_offset(x) ((x) & ((1L << BUCKET_SPACE) - 1))
+#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
+
+static struct sock *unix_from_bucket(struct seq_file *seq, loff_t *pos)
 {
-	for (*i = 0; *i <= UNIX_HASH_SIZE; (*i)++) {
-		if (!hlist_empty(&unix_socket_table[*i]))
-			return __sk_head(&unix_socket_table[*i]);
+	unsigned long offset = get_offset(*pos);
+	unsigned long bucket = get_bucket(*pos);
+	struct sock *sk;
+	unsigned long count = 0;
+
+	for (sk = sk_head(&unix_socket_table[bucket]); sk; sk = sk_next(sk)) {
+		if (sock_net(sk) != seq_file_net(seq))
+			continue;
+		if (++count == offset)
+			break;
 	}
-	return NULL;
+
+	return sk;
 }
 
-static struct sock *next_unix_socket(int *i, struct sock *s)
+static struct sock *unix_next_socket(struct seq_file *seq,
+				     struct sock *sk,
+				     loff_t *pos)
 {
-	struct sock *next = sk_next(s);
-	/* More in this chain? */
-	if (next)
-		return next;
-	/* Look for next non-empty chain. */
-	for ((*i)++; *i <= UNIX_HASH_SIZE; (*i)++) {
-		if (!hlist_empty(&unix_socket_table[*i]))
-			return __sk_head(&unix_socket_table[*i]);
+	unsigned long bucket;
+
+	while (sk > (struct sock *)SEQ_START_TOKEN) {
+		sk = sk_next(sk);
+		if (!sk)
+			goto next_bucket;
+		if (sock_net(sk) == seq_file_net(seq))
+			return sk;
 	}
-	return NULL;
-}
 
-struct unix_iter_state {
-	struct seq_net_private p;
-	int i;
-};
+	do {
+		sk = unix_from_bucket(seq, pos);
+		if (sk)
+			return sk;
 
-static struct sock *unix_seq_idx(struct seq_file *seq, loff_t pos)
-{
-	struct unix_iter_state *iter = seq->private;
-	loff_t off = 0;
-	struct sock *s;
+next_bucket:
+		bucket = get_bucket(*pos) + 1;
+		*pos = set_bucket_offset(bucket, 1);
+	} while (bucket < ARRAY_SIZE(unix_socket_table));
 
-	for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) {
-		if (sock_net(s) != seq_file_net(seq))
-			continue;
-		if (off == pos)
-			return s;
-		++off;
-	}
 	return NULL;
 }
 
@@ -2287,22 +2303,20 @@ static void *unix_seq_start(struct seq_file *seq, loff_t *pos)
 	__acquires(unix_table_lock)
 {
 	spin_lock(&unix_table_lock);
-	return *pos ? unix_seq_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+
+	if (!*pos)
+		return SEQ_START_TOKEN;
+
+	if (get_bucket(*pos) >= ARRAY_SIZE(unix_socket_table))
+		return NULL;
+
+	return unix_next_socket(seq, NULL, pos);
 }
 
 static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-	struct unix_iter_state *iter = seq->private;
-	struct sock *sk = v;
 	++*pos;
-
-	if (v == SEQ_START_TOKEN)
-		sk = first_unix_socket(&iter->i);
-	else
-		sk = next_unix_socket(&iter->i, sk);
-	while (sk && (sock_net(sk) != seq_file_net(seq)))
-		sk = next_unix_socket(&iter->i, sk);
-	return sk;
+	return unix_next_socket(seq, v, pos);
 }
 
 static void unix_seq_stop(struct seq_file *seq, void *v)
@@ -2365,7 +2379,7 @@ static const struct seq_operations unix_seq_ops = {
 static int unix_seq_open(struct inode *inode, struct file *file)
 {
 	return seq_open_net(inode, file, &unix_seq_ops,
-			    sizeof(struct unix_iter_state));
+			    sizeof(struct seq_net_private));
 }
 
 static const struct file_operations unix_seq_fops = {
diff --git a/net/unix/diag.c b/net/unix/diag.c
index 47d3002..7e8a24b 100644
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -195,7 +195,9 @@ static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 	num = s_num = cb->args[1];
 
 	spin_lock(&unix_table_lock);
-	for (slot = s_slot; slot <= UNIX_HASH_SIZE; s_num = 0, slot++) {
+	for (slot = s_slot;
+	     slot < ARRAY_SIZE(unix_socket_table);
+	     s_num = 0, slot++) {
 		struct sock *sk;
 		struct hlist_node *node;
 
@@ -228,7 +230,7 @@ static struct sock *unix_lookup_by_ino(int ino)
 	struct sock *sk;
 
 	spin_lock(&unix_table_lock);
-	for (i = 0; i <= UNIX_HASH_SIZE; i++) {
+	for (i = 0; i < ARRAY_SIZE(unix_socket_table); i++) {
 		struct hlist_node *node;
 
 		sk_for_each(sk, node, &unix_socket_table[i])
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 2e4444f..4d2b1ec 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -114,24 +114,10 @@ config CFG80211_WEXT
 	bool "cfg80211 wireless extensions compatibility"
 	depends on CFG80211
 	select WEXT_CORE
-	default y
 	help
 	  Enable this option if you need old userspace for wireless
 	  extensions with cfg80211-based drivers.
 
-config WIRELESS_EXT_SYSFS
-	bool "Wireless extensions sysfs files"
-	depends on WEXT_CORE && SYSFS
-	help
-	  This option enables the deprecated wireless statistics
-	  files in /sys/class/net/*/wireless/. The same information
-	  is available via the ioctls as well.
-
-	  Say N. If you know you have ancient tools requiring it,
-	  like very old versions of hal (prior to 0.5.12 release),
-	  say Y and update the tools as soon as possible as this
-	  option will be removed soon.
-
 config LIB80211
 	tristate "Common routines for IEEE802.11 drivers"
 	default n
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 884801a..c1999e4 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -60,7 +60,7 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
 		diff = -20;
 		break;
 	default:
-		return false;
+		return true;
 	}
 
 	sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
@@ -78,60 +78,17 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
 
-int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
-		      struct wireless_dev *wdev, int freq,
-		      enum nl80211_channel_type channel_type)
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+				 int freq, enum nl80211_channel_type chantype)
 {
 	struct ieee80211_channel *chan;
-	int result;
-
-	if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR)
-		wdev = NULL;
-
-	if (wdev) {
-		ASSERT_WDEV_LOCK(wdev);
-
-		if (!netif_running(wdev->netdev))
-			return -ENETDOWN;
-	}
 
-	if (!rdev->ops->set_channel)
+	if (!rdev->ops->set_monitor_channel)
 		return -EOPNOTSUPP;
 
-	chan = rdev_freq_to_chan(rdev, freq, channel_type);
+	chan = rdev_freq_to_chan(rdev, freq, chantype);
 	if (!chan)
 		return -EINVAL;
 
-	/* Both channels should be able to initiate communication */
-	if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
-		     wdev->iftype == NL80211_IFTYPE_AP ||
-		     wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
-		     wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
-		     wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
-		switch (channel_type) {
-		case NL80211_CHAN_HT40PLUS:
-		case NL80211_CHAN_HT40MINUS:
-			if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan,
-							  channel_type)) {
-				printk(KERN_DEBUG
-				       "cfg80211: Secondary channel not "
-				       "allowed to initiate communication\n");
-				return -EINVAL;
-			}
-			break;
-		default:
-			break;
-		}
-	}
-
-	result = rdev->ops->set_channel(&rdev->wiphy,
-					wdev ? wdev->netdev : NULL,
-					chan, channel_type);
-	if (result)
-		return result;
-
-	if (wdev)
-		wdev->channel = chan;
-
-	return 0;
+	return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
 }
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a87d435..907f62c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -96,69 +96,6 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
 	return &rdev->wiphy;
 }
 
-/* requires cfg80211_mutex to be held! */
-struct cfg80211_registered_device *
-__cfg80211_rdev_from_info(struct genl_info *info)
-{
-	int ifindex;
-	struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL;
-	struct net_device *dev;
-	int err = -EINVAL;
-
-	assert_cfg80211_lock();
-
-	if (info->attrs[NL80211_ATTR_WIPHY]) {
-		bywiphyidx = cfg80211_rdev_by_wiphy_idx(
-				nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
-		err = -ENODEV;
-	}
-
-	if (info->attrs[NL80211_ATTR_IFINDEX]) {
-		ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
-		dev = dev_get_by_index(genl_info_net(info), ifindex);
-		if (dev) {
-			if (dev->ieee80211_ptr)
-				byifidx =
-					wiphy_to_dev(dev->ieee80211_ptr->wiphy);
-			dev_put(dev);
-		}
-		err = -ENODEV;
-	}
-
-	if (bywiphyidx && byifidx) {
-		if (bywiphyidx != byifidx)
-			return ERR_PTR(-EINVAL);
-		else
-			return bywiphyidx; /* == byifidx */
-	}
-	if (bywiphyidx)
-		return bywiphyidx;
-
-	if (byifidx)
-		return byifidx;
-
-	return ERR_PTR(err);
-}
-
-struct cfg80211_registered_device *
-cfg80211_get_dev_from_info(struct genl_info *info)
-{
-	struct cfg80211_registered_device *rdev;
-
-	mutex_lock(&cfg80211_mutex);
-	rdev = __cfg80211_rdev_from_info(info);
-
-	/* if it is not an error we grab the lock on
-	 * it to assure it won't be going away while
-	 * we operate on it */
-	if (!IS_ERR(rdev))
-		mutex_lock(&rdev->mtx);
-
-	mutex_unlock(&cfg80211_mutex);
-
-	return rdev;
-}
-
 struct cfg80211_registered_device *
 cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)
 {
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 8523f38..609a579 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -159,32 +159,6 @@ static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss)
 struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx);
 int get_wiphy_idx(struct wiphy *wiphy);
 
-struct cfg80211_registered_device *
-__cfg80211_rdev_from_info(struct genl_info *info);
-
-/*
- * This function returns a pointer to the driver
- * that the genl_info item that is passed refers to.
- * If successful, it returns non-NULL and also locks
- * the driver's mutex!
- *
- * This means that you need to call cfg80211_unlock_rdev()
- * before being allowed to acquire &cfg80211_mutex!
- *
- * This is necessary because we need to lock the global
- * mutex to get an item off the list safely, and then
- * we lock the rdev mutex so it doesn't go away under us.
- *
- * We don't want to keep cfg80211_mutex locked
- * for all the time in order to allow requests on
- * other interfaces to go through at the same time.
- *
- * The result of this can be a PTR_ERR and hence must
- * be checked with IS_ERR() for errors.
- */
-extern struct cfg80211_registered_device *
-cfg80211_get_dev_from_info(struct genl_info *info);
-
 /* requires cfg80211_rdev_mutex to be held! */
 struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx);
 
@@ -303,14 +277,17 @@ extern const struct mesh_config default_mesh_config;
 extern const struct mesh_setup default_mesh_setup;
 int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 			 struct net_device *dev,
-			 const struct mesh_setup *setup,
+			 struct mesh_setup *setup,
 			 const struct mesh_config *conf);
 int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       const struct mesh_setup *setup,
+		       struct mesh_setup *setup,
 		       const struct mesh_config *conf);
 int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
 			struct net_device *dev);
+int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
+			   struct wireless_dev *wdev, int freq,
+			   enum nl80211_channel_type channel_type);
 
 /* MLME */
 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
@@ -441,9 +418,8 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
 struct ieee80211_channel *
 rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
 		  int freq, enum nl80211_channel_type channel_type);
-int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
-		      struct wireless_dev *wdev, int freq,
-		      enum nl80211_channel_type channel_type);
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+				 int freq, enum nl80211_channel_type chantype);
 
 int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
 			   const u8 *rates, unsigned int n_rates,
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 2749cb8..3b73b07 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -14,6 +14,9 @@
 
 #define MESH_PATH_TIMEOUT	5000
 #define MESH_RANN_INTERVAL      5000
+#define MESH_PATH_TO_ROOT_TIMEOUT      6000
+#define MESH_ROOT_INTERVAL     5000
+#define MESH_ROOT_CONFIRMATION_INTERVAL 2000
 
 /*
  * Minimum interval between two consecutive PREQs originated by the same
@@ -62,9 +65,15 @@ const struct mesh_config default_mesh_config = {
 	.dot11MeshForwarding = true,
 	.rssi_threshold = MESH_RSSI_THRESHOLD,
 	.ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED,
+	.dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT,
+	.dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL,
+	.dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL,
 };
 
 const struct mesh_setup default_mesh_setup = {
+	/* cfg80211_join_mesh() will pick a channel if needed */
+	.channel = NULL,
+	.channel_type = NL80211_CHAN_NO_HT,
 	.sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
 	.path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
 	.path_metric = IEEE80211_PATH_METRIC_AIRTIME,
@@ -75,7 +84,7 @@ const struct mesh_setup default_mesh_setup = {
 
 int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 			 struct net_device *dev,
-			 const struct mesh_setup *setup,
+			 struct mesh_setup *setup,
 			 const struct mesh_config *conf)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -101,6 +110,51 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 	if (!rdev->ops->join_mesh)
 		return -EOPNOTSUPP;
 
+	if (!setup->channel) {
+		/* if no channel explicitly given, use preset channel */
+		setup->channel = wdev->preset_chan;
+		setup->channel_type = wdev->preset_chantype;
+	}
+
+	if (!setup->channel) {
+		/* if we don't have that either, use the first usable channel */
+		enum ieee80211_band band;
+
+		for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+			struct ieee80211_supported_band *sband;
+			struct ieee80211_channel *chan;
+			int i;
+
+			sband = rdev->wiphy.bands[band];
+			if (!sband)
+				continue;
+
+			for (i = 0; i < sband->n_channels; i++) {
+				chan = &sband->channels[i];
+				if (chan->flags & (IEEE80211_CHAN_NO_IBSS |
+						   IEEE80211_CHAN_PASSIVE_SCAN |
+						   IEEE80211_CHAN_DISABLED |
+						   IEEE80211_CHAN_RADAR))
+					continue;
+				setup->channel = chan;
+				break;
+			}
+
+			if (setup->channel)
+				break;
+		}
+
+		/* no usable channel ... */
+		if (!setup->channel)
+			return -EINVAL;
+
+		setup->channel_type = NL80211_CHAN_NO_HT;
+	}
+
+	if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel,
+					  setup->channel_type))
+		return -EINVAL;
+
 	err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
 	if (!err) {
 		memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
@@ -112,7 +166,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 
 int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       const struct mesh_setup *setup,
+		       struct mesh_setup *setup,
 		       const struct mesh_config *conf)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -125,6 +179,45 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 	return err;
 }
 
+int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
+			   struct wireless_dev *wdev, int freq,
+			   enum nl80211_channel_type channel_type)
+{
+	struct ieee80211_channel *channel;
+
+	channel = rdev_freq_to_chan(rdev, freq, channel_type);
+	if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+						      channel,
+						      channel_type)) {
+		return -EINVAL;
+	}
+
+	/*
+	 * Workaround for libertas (only!), it puts the interface
+	 * into mesh mode but doesn't implement join_mesh. Instead,
+	 * it is configured via sysfs and then joins the mesh when
+	 * you set the channel. Note that the libertas mesh isn't
+	 * compatible with 802.11 mesh.
+	 */
+	if (rdev->ops->libertas_set_mesh_channel) {
+		if (channel_type != NL80211_CHAN_NO_HT)
+			return -EINVAL;
+
+		if (!netif_running(wdev->netdev))
+			return -ENETDOWN;
+		return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
+							    wdev->netdev,
+							    channel);
+	}
+
+	if (wdev->mesh_id_len)
+		return -EBUSY;
+
+	wdev->preset_chan = channel;
+	wdev->preset_chantype = channel_type;
+	return 0;
+}
+
 void cfg80211_notify_new_peer_candidate(struct net_device *dev,
 		const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
 {
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index eb90988..da4406f 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -947,8 +947,6 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
 	if (WARN_ON(!chan))
 		goto out;
 
-	wdev->channel = chan;
-
 	nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
 out:
 	wdev_unlock(wdev);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 206465d..234ff3b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -70,6 +70,94 @@ static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs,
 	return 0;
 }
 
+static struct cfg80211_registered_device *
+__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
+{
+	struct cfg80211_registered_device *rdev = NULL, *tmp;
+	struct net_device *netdev;
+
+	assert_cfg80211_lock();
+
+	if (!attrs[NL80211_ATTR_WIPHY] &&
+	    !attrs[NL80211_ATTR_IFINDEX])
+		return ERR_PTR(-EINVAL);
+
+	if (attrs[NL80211_ATTR_WIPHY])
+		rdev = cfg80211_rdev_by_wiphy_idx(
+				nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
+
+	if (attrs[NL80211_ATTR_IFINDEX]) {
+		int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
+		netdev = dev_get_by_index(netns, ifindex);
+		if (netdev) {
+			if (netdev->ieee80211_ptr)
+				tmp = wiphy_to_dev(
+						netdev->ieee80211_ptr->wiphy);
+			else
+				tmp = NULL;
+
+			dev_put(netdev);
+
+			/* not wireless device -- return error */
+			if (!tmp)
+				return ERR_PTR(-EINVAL);
+
+			/* mismatch -- return error */
+			if (rdev && tmp != rdev)
+				return ERR_PTR(-EINVAL);
+
+			rdev = tmp;
+		}
+	}
+
+	if (!rdev)
+		return ERR_PTR(-ENODEV);
+
+	if (netns != wiphy_net(&rdev->wiphy))
+		return ERR_PTR(-ENODEV);
+
+	return rdev;
+}
+
+/*
+ * This function returns a pointer to the driver
+ * that the genl_info item that is passed refers to.
+ * If successful, it returns non-NULL and also locks
+ * the driver's mutex!
+ *
+ * This means that you need to call cfg80211_unlock_rdev()
+ * before being allowed to acquire &cfg80211_mutex!
+ *
+ * This is necessary because we need to lock the global
+ * mutex to get an item off the list safely, and then
+ * we lock the rdev mutex so it doesn't go away under us.
+ *
+ * We don't want to keep cfg80211_mutex locked
+ * for all the time in order to allow requests on
+ * other interfaces to go through at the same time.
+ *
+ * The result of this can be a PTR_ERR and hence must
+ * be checked with IS_ERR() for errors.
+ */
+static struct cfg80211_registered_device *
+cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev;
+
+	mutex_lock(&cfg80211_mutex);
+	rdev = __cfg80211_rdev_from_attrs(netns, info->attrs);
+
+	/* if it is not an error we grab the lock on
+	 * it to assure it won't be going away while
+	 * we operate on it */
+	if (!IS_ERR(rdev))
+		mutex_lock(&rdev->mtx);
+
+	mutex_unlock(&cfg80211_mutex);
+
+	return rdev;
+}
+
 /* policy for the attributes */
 static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
 	[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
@@ -115,7 +203,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
 	[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
 	[NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
 	[NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
-				.len = IEEE80211_MAX_MESH_ID_LEN },
+				   .len = IEEE80211_MAX_MESH_ID_LEN },
 	[NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
 
 	[NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
@@ -250,8 +338,9 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
 
 static const struct nla_policy
 nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
-	[NL80211_ATTR_SCHED_SCAN_MATCH_SSID] = { .type = NLA_BINARY,
+	[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
 						 .len = IEEE80211_MAX_SSID_LEN },
+	[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
 };
 
 /* ifidx get helper */
@@ -921,7 +1010,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 		if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
 			goto nla_put_failure;
 	}
-	CMD(set_channel, SET_CHANNEL);
+	if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
+	    dev->ops->join_mesh) {
+		i++;
+		if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
+			goto nla_put_failure;
+	}
 	CMD(set_wds_peer, SET_WDS_PEER);
 	if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
 		CMD(tdls_mgmt, TDLS_MGMT);
@@ -1162,18 +1256,22 @@ static int parse_txq_params(struct nlattr *tb[],
 static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
 {
 	/*
-	 * You can only set the channel explicitly for AP, mesh
-	 * and WDS type interfaces; all others have their channel
-	 * managed via their respective "establish a connection"
-	 * command (connect, join, ...)
+	 * You can only set the channel explicitly for WDS interfaces,
+	 * all others have their channel managed via their respective
+	 * "establish a connection" command (connect, join, ...)
+	 *
+	 * For AP/GO and mesh mode, the channel can be set with the
+	 * channel userspace API, but is only stored and passed to the
+	 * low-level driver when the AP starts or the mesh is joined.
+	 * This is for backward compatibility, userspace can also give
+	 * the channel in the start-ap or join-mesh commands instead.
 	 *
 	 * Monitors are special as they are normally slaved to
-	 * whatever else is going on, so they behave as though
-	 * you tried setting the wiphy channel itself.
+	 * whatever else is going on, so they have their own special
+	 * operation to set the monitor channel if possible.
 	 */
 	return !wdev ||
 		wdev->iftype == NL80211_IFTYPE_AP ||
-		wdev->iftype == NL80211_IFTYPE_WDS ||
 		wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
 		wdev->iftype == NL80211_IFTYPE_MONITOR ||
 		wdev->iftype == NL80211_IFTYPE_P2P_GO;
@@ -1204,9 +1302,14 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
 				 struct wireless_dev *wdev,
 				 struct genl_info *info)
 {
+	struct ieee80211_channel *channel;
 	enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
 	u32 freq;
 	int result;
+	enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
+
+	if (wdev)
+		iftype = wdev->iftype;
 
 	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
 		return -EINVAL;
@@ -1221,12 +1324,32 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
 	freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
 
 	mutex_lock(&rdev->devlist_mtx);
-	if (wdev) {
-		wdev_lock(wdev);
-		result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
-		wdev_unlock(wdev);
-	} else {
-		result = cfg80211_set_freq(rdev, NULL, freq, channel_type);
+	switch (iftype) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
+		if (wdev->beacon_interval) {
+			result = -EBUSY;
+			break;
+		}
+		channel = rdev_freq_to_chan(rdev, freq, channel_type);
+		if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+							      channel,
+							      channel_type)) {
+			result = -EINVAL;
+			break;
+		}
+		wdev->preset_chan = channel;
+		wdev->preset_chantype = channel_type;
+		result = 0;
+		break;
+	case NL80211_IFTYPE_MESH_POINT:
+		result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
+		break;
+	case NL80211_IFTYPE_MONITOR:
+		result = cfg80211_set_monitor_channel(rdev, freq, channel_type);
+		break;
+	default:
+		result = -EINVAL;
 	}
 	mutex_unlock(&rdev->devlist_mtx);
 
@@ -1300,7 +1423,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 	}
 
 	if (!netdev) {
-		rdev = __cfg80211_rdev_from_info(info);
+		rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
+						  info->attrs);
 		if (IS_ERR(rdev)) {
 			mutex_unlock(&cfg80211_mutex);
 			return PTR_ERR(rdev);
@@ -1310,8 +1434,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 		result = 0;
 
 		mutex_lock(&rdev->mtx);
-	} else if (netif_running(netdev) &&
-		   nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
+	} else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
 		wdev = netdev->ieee80211_ptr;
 	else
 		wdev = NULL;
@@ -2213,6 +2336,33 @@ static int nl80211_parse_beacon(struct genl_info *info,
 	return 0;
 }
 
+static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
+				   struct cfg80211_ap_settings *params)
+{
+	struct wireless_dev *wdev;
+	bool ret = false;
+
+	mutex_lock(&rdev->devlist_mtx);
+
+	list_for_each_entry(wdev, &rdev->netdev_list, list) {
+		if (wdev->iftype != NL80211_IFTYPE_AP &&
+		    wdev->iftype != NL80211_IFTYPE_P2P_GO)
+			continue;
+
+		if (!wdev->preset_chan)
+			continue;
+
+		params->channel = wdev->preset_chan;
+		params->channel_type = wdev->preset_chantype;
+		ret = true;
+		break;
+	}
+
+	mutex_unlock(&rdev->devlist_mtx);
+
+	return ret;
+}
+
 static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -2299,9 +2449,35 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 			info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
 	}
 
+	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+		enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+
+		if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+		    !nl80211_valid_channel_type(info, &channel_type))
+			return -EINVAL;
+
+		params.channel = rdev_freq_to_chan(rdev,
+			nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
+			channel_type);
+		if (!params.channel)
+			return -EINVAL;
+		params.channel_type = channel_type;
+	} else if (wdev->preset_chan) {
+		params.channel = wdev->preset_chan;
+		params.channel_type = wdev->preset_chantype;
+	} else if (!nl80211_get_ap_channel(rdev, &params))
+		return -EINVAL;
+
+	if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel,
+					  params.channel_type))
+		return -EINVAL;
+
 	err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
-	if (!err)
+	if (!err) {
+		wdev->preset_chan = params.channel;
+		wdev->preset_chantype = params.channel_type;
 		wdev->beacon_interval = params.beacon_interval;
+	}
 	return err;
 }
 
@@ -3413,7 +3589,13 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
 	    nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
 			cur_params.rssi_threshold) ||
 	    nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
-			cur_params.ht_opmode))
+			cur_params.ht_opmode) ||
+	    nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
+			cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
+	    nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
+			cur_params.dot11MeshHWMProotInterval) ||
+	    nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
+			cur_params.dot11MeshHWMPconfirmationInterval))
 		goto nla_put_failure;
 	nla_nest_end(msg, pinfoattr);
 	genlmsg_end(msg, hdr);
@@ -3436,7 +3618,6 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
 	[NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
 	[NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
 	[NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
-
 	[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
 	[NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
 	[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
@@ -3448,8 +3629,11 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
 	[NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
 	[NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
 	[NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
-	[NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32},
-	[NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16},
+	[NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
+	[NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
+	[NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
+	[NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
+	[NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
 };
 
 static const struct nla_policy
@@ -3459,7 +3643,7 @@ static const struct nla_policy
 	[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
 	[NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
 	[NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
-		.len = IEEE80211_MAX_DATA_LEN },
+				    .len = IEEE80211_MAX_DATA_LEN },
 	[NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
 };
 
@@ -3492,63 +3676,82 @@ do {\
 
 	/* Fill in the params struct */
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout,
-			mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16);
+				  mask, NL80211_MESHCONF_RETRY_TIMEOUT,
+				  nla_get_u16);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout,
-			mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16);
+				  mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
+				  nla_get_u16);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout,
-			mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16);
+				  mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
+				  nla_get_u16);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks,
-			mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16);
+				  mask, NL80211_MESHCONF_MAX_PEER_LINKS,
+				  nla_get_u16);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries,
-			mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8);
+				  mask, NL80211_MESHCONF_MAX_RETRIES,
+				  nla_get_u8);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL,
-			mask, NL80211_MESHCONF_TTL, nla_get_u8);
+				  mask, NL80211_MESHCONF_TTL, nla_get_u8);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl,
-			mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8);
+				  mask, NL80211_MESHCONF_ELEMENT_TTL,
+				  nla_get_u8);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks,
-			mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8);
-	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
-			mask, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
-			nla_get_u32);
+				  mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+				  nla_get_u8);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, mask,
+				  NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
+				  nla_get_u32);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries,
-			mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
-			nla_get_u8);
+				  mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+				  nla_get_u8);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time,
-			mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32);
+				  mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
+				  nla_get_u32);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout,
-			mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
-			nla_get_u16);
-	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
-			mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
-			nla_get_u32);
+				  mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+				  nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, mask,
+				  NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+				  nla_get_u32);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
-			mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
-			nla_get_u16);
+				  mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+				  nla_get_u16);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
-			mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
-			nla_get_u16);
-	FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
-			dot11MeshHWMPnetDiameterTraversalTime,
-			mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
-			nla_get_u16);
+				  mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
+				  nla_get_u16);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
-			dot11MeshHWMPRootMode, mask,
-			NL80211_MESHCONF_HWMP_ROOTMODE,
-			nla_get_u8);
+				  dot11MeshHWMPnetDiameterTraversalTime, mask,
+				  NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+				  nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask,
+				  NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask,
+				  NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+				  nla_get_u16);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
-			dot11MeshHWMPRannInterval, mask,
-			NL80211_MESHCONF_HWMP_RANN_INTERVAL,
-			nla_get_u16);
-	FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
-			dot11MeshGateAnnouncementProtocol, mask,
-			NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
-			nla_get_u8);
+				  dot11MeshGateAnnouncementProtocol, mask,
+				  NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+				  nla_get_u8);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding,
-			mask, NL80211_MESHCONF_FORWARDING, nla_get_u8);
+				  mask, NL80211_MESHCONF_FORWARDING,
+				  nla_get_u8);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold,
-			mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32);
+				  mask, NL80211_MESHCONF_RSSI_THRESHOLD,
+				  nla_get_u32);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode,
-			mask, NL80211_MESHCONF_HT_OPMODE, nla_get_u16);
+				  mask, NL80211_MESHCONF_HT_OPMODE,
+				  nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
+				  mask,
+				  NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
+				  nla_get_u32);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval,
+				  mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
+				  nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+				  dot11MeshHWMPconfirmationInterval, mask,
+				  NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
+				  nla_get_u16);
 	if (mask_out)
 		*mask_out = mask;
 
@@ -4185,12 +4388,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
 		nla_for_each_nested(attr,
 				    info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
 				    tmp) {
-			struct nlattr *ssid;
+			struct nlattr *ssid, *rssi;
 
 			nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
 				  nla_data(attr), nla_len(attr),
 				  nl80211_match_policy);
-			ssid = tb[NL80211_ATTR_SCHED_SCAN_MATCH_SSID];
+			ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
 			if (ssid) {
 				if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
 					err = -EINVAL;
@@ -4201,6 +4404,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
 				request->match_sets[i].ssid.ssid_len =
 					nla_len(ssid);
 			}
+			rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
+			if (rssi)
+				request->rssi_thold = nla_get_u32(rssi);
+			else
+				request->rssi_thold =
+						   NL80211_SCAN_RSSI_THOLD_OFF;
 			i++;
 		}
 	}
@@ -5058,21 +5267,18 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
 				  nl80211_policy);
 		if (err)
 			return err;
-		if (nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) {
-			phy_idx = nla_get_u32(
-				nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]);
-		} else {
-			struct net_device *netdev;
 
-			err = get_rdev_dev_by_ifindex(sock_net(skb->sk),
-						      nl80211_fam.attrbuf,
-						      &rdev, &netdev);
-			if (err)
-				return err;
-			dev_put(netdev);
-			phy_idx = rdev->wiphy_idx;
-			cfg80211_unlock_rdev(rdev);
+		mutex_lock(&cfg80211_mutex);
+		rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
+						  nl80211_fam.attrbuf);
+		if (IS_ERR(rdev)) {
+			mutex_unlock(&cfg80211_mutex);
+			return PTR_ERR(rdev);
 		}
+		phy_idx = rdev->wiphy_idx;
+		rdev = NULL;
+		mutex_unlock(&cfg80211_mutex);
+
 		if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA])
 			cb->args[1] =
 				(long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA];
@@ -5489,18 +5695,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
 
 	duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
 
+	if (!rdev->ops->remain_on_channel ||
+	    !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
+		return -EOPNOTSUPP;
+
 	/*
-	 * We should be on that channel for at least one jiffie,
-	 * and more than 5 seconds seems excessive.
+	 * We should be on that channel for at least a minimum amount of
+	 * time (10ms) but no longer than the driver supports.
 	 */
-	if (!duration || !msecs_to_jiffies(duration) ||
+	if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
 	    duration > rdev->wiphy.max_remain_on_channel_duration)
 		return -EINVAL;
 
-	if (!rdev->ops->remain_on_channel ||
-	    !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
-		return -EOPNOTSUPP;
-
 	if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
 	    !nl80211_valid_channel_type(info, &channel_type))
 		return -EINVAL;
@@ -5771,6 +5977,15 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 		if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
 			return -EINVAL;
 		wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
+
+		/*
+		 * We should wait on the channel for at least a minimum amount
+		 * of time (10ms) but no longer than the driver supports.
+		 */
+		if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
+		    wait > rdev->wiphy.max_remain_on_channel_duration)
+			return -EINVAL;
+
 	}
 
 	if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
@@ -6032,6 +6247,24 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
 			return err;
 	}
 
+	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+		enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+
+		if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+		    !nl80211_valid_channel_type(info, &channel_type))
+			return -EINVAL;
+
+		setup.channel = rdev_freq_to_chan(rdev,
+			nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
+			channel_type);
+		if (!setup.channel)
+			return -EINVAL;
+		setup.channel_type = channel_type;
+	} else {
+		/* cfg80211_join_mesh() will sort it out */
+		setup.channel = NULL;
+	}
+
 	return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
 }
 
@@ -6428,7 +6661,7 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
 		rtnl_lock();
 
 	if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
-		rdev = cfg80211_get_dev_from_info(info);
+		rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
 		if (IS_ERR(rdev)) {
 			if (rtnl)
 				rtnl_unlock();
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 15f3474..baf5704 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1389,7 +1389,7 @@ static void reg_set_request_processed(void)
 	spin_unlock(&reg_requests_lock);
 
 	if (last_request->initiator == NL80211_REGDOM_SET_BY_USER)
-		cancel_delayed_work_sync(&reg_timeout);
+		cancel_delayed_work(&reg_timeout);
 
 	if (need_more_processing)
 		schedule_work(&reg_work);
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 8f2d68f..316cfd0 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -804,7 +804,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 	     ntype == NL80211_IFTYPE_P2P_CLIENT))
 		return -EBUSY;
 
-	if (ntype != otype) {
+	if (ntype != otype && netif_running(dev)) {
 		err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
 						    ntype);
 		if (err)
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 6a6181a..bc87983 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -796,7 +796,15 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
 	case NL80211_IFTYPE_ADHOC:
 		return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
 	case NL80211_IFTYPE_MONITOR:
-	case NL80211_IFTYPE_WDS:
+		freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
+		if (freq < 0)
+			return freq;
+		if (freq == 0)
+			return -EINVAL;
+		mutex_lock(&rdev->devlist_mtx);
+		err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
+		mutex_unlock(&rdev->devlist_mtx);
+		return err;
 	case NL80211_IFTYPE_MESH_POINT:
 		freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
 		if (freq < 0)
@@ -804,9 +812,8 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
 		if (freq == 0)
 			return -EINVAL;
 		mutex_lock(&rdev->devlist_mtx);
-		wdev_lock(wdev);
-		err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
-		wdev_unlock(wdev);
+		err = cfg80211_set_mesh_freq(rdev, wdev, freq,
+					     NL80211_CHAN_NO_HT);
 		mutex_unlock(&rdev->devlist_mtx);
 		return err;
 	default:
@@ -839,11 +846,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
 		freq->e = 6;
 		return 0;
 	default:
-		if (!wdev->channel)
-			return -EINVAL;
-		freq->m = wdev->channel->center_freq;
-		freq->e = 6;
-		return 0;
+		return -EINVAL;
 	}
 }
 
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 7decbd3..1f773f6 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -111,9 +111,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
 
 	wdev->wext.connect.channel = chan;
 
-	/* SSID is not set, we just want to switch channel */
+	/*
+	 * SSID is not set, we just want to switch monitor channel,
+	 * this is really just backward compatibility, if the SSID
+	 * is set then we use the channel to select the BSS to use
+	 * to connect to instead. If we were connected on another
+	 * channel we disconnected above and reconnect below.
+	 */
 	if (chan && !wdev->wext.connect.ssid_len) {
-		err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
+		err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
 		goto out;
 	}
 
diff --git a/samples/uhid/Makefile b/samples/uhid/Makefile
new file mode 100644
index 0000000..c95a696
--- /dev/null
+++ b/samples/uhid/Makefile
@@ -0,0 +1,10 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := uhid-example
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
+
+HOSTCFLAGS_uhid-example.o += -I$(objtree)/usr/include
diff --git a/samples/uhid/uhid-example.c b/samples/uhid/uhid-example.c
new file mode 100644
index 0000000..03ce3c0
--- /dev/null
+++ b/samples/uhid/uhid-example.c
@@ -0,0 +1,381 @@
+/*
+ * UHID Example
+ *
+ * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
+ *
+ * The code may be used by anyone for any purpose,
+ * and can serve as a starting point for developing
+ * applications using uhid.
+ */
+
+/* UHID Example
+ * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this
+ * program as root and then use the following keys to control the mouse:
+ *   q: Quit the application
+ *   1: Toggle left button (down, up, ...)
+ *   2: Toggle right button
+ *   3: Toggle middle button
+ *   a: Move mouse left
+ *   d: Move mouse right
+ *   w: Move mouse up
+ *   s: Move mouse down
+ *   r: Move wheel up
+ *   f: Move wheel down
+ *
+ * If uhid is not available as /dev/uhid, then you can pass a different path as
+ * first argument.
+ * If <linux/uhid.h> is not installed in /usr, then compile this with:
+ *   gcc -o ./uhid_test -Wall -I./include ./samples/uhid/uhid-example.c
+ * And ignore the warning about kernel headers. However, it is recommended to
+ * use the installed uhid.h if available.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <linux/uhid.h>
+
+/* HID Report Desciptor
+ * We emulate a basic 3 button mouse with wheel. This is the report-descriptor
+ * as the kernel will parse it:
+ *
+ * INPUT[INPUT]
+ *   Field(0)
+ *     Physical(GenericDesktop.Pointer)
+ *     Application(GenericDesktop.Mouse)
+ *     Usage(3)
+ *       Button.0001
+ *       Button.0002
+ *       Button.0003
+ *     Logical Minimum(0)
+ *     Logical Maximum(1)
+ *     Report Size(1)
+ *     Report Count(3)
+ *     Report Offset(0)
+ *     Flags( Variable Absolute )
+ *   Field(1)
+ *     Physical(GenericDesktop.Pointer)
+ *     Application(GenericDesktop.Mouse)
+ *     Usage(3)
+ *       GenericDesktop.X
+ *       GenericDesktop.Y
+ *       GenericDesktop.Wheel
+ *     Logical Minimum(-128)
+ *     Logical Maximum(127)
+ *     Report Size(8)
+ *     Report Count(3)
+ *     Report Offset(8)
+ *     Flags( Variable Relative )
+ *
+ * This is the mapping that we expect:
+ *   Button.0001 ---> Key.LeftBtn
+ *   Button.0002 ---> Key.RightBtn
+ *   Button.0003 ---> Key.MiddleBtn
+ *   GenericDesktop.X ---> Relative.X
+ *   GenericDesktop.Y ---> Relative.Y
+ *   GenericDesktop.Wheel ---> Relative.Wheel
+ *
+ * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc
+ * This file should print the same information as showed above.
+ */
+
+static unsigned char rdesc[] = {
+	0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
+	0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
+	0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
+	0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
+	0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38,
+	0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03,
+	0x81, 0x06, 0xc0, 0xc0,
+};
+
+static int uhid_write(int fd, const struct uhid_event *ev)
+{
+	ssize_t ret;
+
+	ret = write(fd, ev, sizeof(*ev));
+	if (ret < 0) {
+		fprintf(stderr, "Cannot write to uhid: %m\n");
+		return -errno;
+	} else if (ret != sizeof(*ev)) {
+		fprintf(stderr, "Wrong size written to uhid: %ld != %lu\n",
+			ret, sizeof(ev));
+		return -EFAULT;
+	} else {
+		return 0;
+	}
+}
+
+static int create(int fd)
+{
+	struct uhid_event ev;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.type = UHID_CREATE;
+	strcpy((char*)ev.u.create.name, "test-uhid-device");
+	ev.u.create.rd_data = rdesc;
+	ev.u.create.rd_size = sizeof(rdesc);
+	ev.u.create.bus = BUS_USB;
+	ev.u.create.vendor = 0x15d9;
+	ev.u.create.product = 0x0a37;
+	ev.u.create.version = 0;
+	ev.u.create.country = 0;
+
+	return uhid_write(fd, &ev);
+}
+
+static void destroy(int fd)
+{
+	struct uhid_event ev;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.type = UHID_DESTROY;
+
+	uhid_write(fd, &ev);
+}
+
+static int event(int fd)
+{
+	struct uhid_event ev;
+	ssize_t ret;
+
+	memset(&ev, 0, sizeof(ev));
+	ret = read(fd, &ev, sizeof(ev));
+	if (ret == 0) {
+		fprintf(stderr, "Read HUP on uhid-cdev\n");
+		return -EFAULT;
+	} else if (ret < 0) {
+		fprintf(stderr, "Cannot read uhid-cdev: %m\n");
+		return -errno;
+	} else if (ret != sizeof(ev)) {
+		fprintf(stderr, "Invalid size read from uhid-dev: %ld != %lu\n",
+			ret, sizeof(ev));
+		return -EFAULT;
+	}
+
+	switch (ev.type) {
+	case UHID_START:
+		fprintf(stderr, "UHID_START from uhid-dev\n");
+		break;
+	case UHID_STOP:
+		fprintf(stderr, "UHID_STOP from uhid-dev\n");
+		break;
+	case UHID_OPEN:
+		fprintf(stderr, "UHID_OPEN from uhid-dev\n");
+		break;
+	case UHID_CLOSE:
+		fprintf(stderr, "UHID_CLOSE from uhid-dev\n");
+		break;
+	case UHID_OUTPUT:
+		fprintf(stderr, "UHID_OUTPUT from uhid-dev\n");
+		break;
+	case UHID_OUTPUT_EV:
+		fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n");
+		break;
+	default:
+		fprintf(stderr, "Invalid event from uhid-dev: %u\n", ev.type);
+	}
+
+	return 0;
+}
+
+static bool btn1_down;
+static bool btn2_down;
+static bool btn3_down;
+static signed char abs_hor;
+static signed char abs_ver;
+static signed char wheel;
+
+static int send_event(int fd)
+{
+	struct uhid_event ev;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.type = UHID_INPUT;
+	ev.u.input.size = 4;
+
+	if (btn1_down)
+		ev.u.input.data[0] |= 0x1;
+	if (btn2_down)
+		ev.u.input.data[0] |= 0x2;
+	if (btn3_down)
+		ev.u.input.data[0] |= 0x4;
+
+	ev.u.input.data[1] = abs_hor;
+	ev.u.input.data[2] = abs_ver;
+	ev.u.input.data[3] = wheel;
+
+	return uhid_write(fd, &ev);
+}
+
+static int keyboard(int fd)
+{
+	char buf[128];
+	ssize_t ret, i;
+
+	ret = read(STDIN_FILENO, buf, sizeof(buf));
+	if (ret == 0) {
+		fprintf(stderr, "Read HUP on stdin\n");
+		return -EFAULT;
+	} else if (ret < 0) {
+		fprintf(stderr, "Cannot read stdin: %m\n");
+		return -errno;
+	}
+
+	for (i = 0; i < ret; ++i) {
+		switch (buf[i]) {
+		case '1':
+			btn1_down = !btn1_down;
+			ret = send_event(fd);
+			if (ret)
+				return ret;
+			break;
+		case '2':
+			btn2_down = !btn2_down;
+			ret = send_event(fd);
+			if (ret)
+				return ret;
+			break;
+		case '3':
+			btn3_down = !btn3_down;
+			ret = send_event(fd);
+			if (ret)
+				return ret;
+			break;
+		case 'a':
+			abs_hor = -20;
+			ret = send_event(fd);
+			abs_hor = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'd':
+			abs_hor = 20;
+			ret = send_event(fd);
+			abs_hor = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'w':
+			abs_ver = -20;
+			ret = send_event(fd);
+			abs_ver = 0;
+			if (ret)
+				return ret;
+			break;
+		case 's':
+			abs_ver = 20;
+			ret = send_event(fd);
+			abs_ver = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'r':
+			wheel = 1;
+			ret = send_event(fd);
+			wheel = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'f':
+			wheel = -1;
+			ret = send_event(fd);
+			wheel = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'q':
+			return -ECANCELED;
+		default:
+			fprintf(stderr, "Invalid input: %c\n", buf[i]);
+		}
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int fd;
+	const char *path = "/dev/uhid";
+	struct pollfd pfds[2];
+	int ret;
+	struct termios state;
+
+	ret = tcgetattr(STDIN_FILENO, &state);
+	if (ret) {
+		fprintf(stderr, "Cannot get tty state\n");
+	} else {
+		state.c_lflag &= ~ICANON;
+		state.c_cc[VMIN] = 1;
+		ret = tcsetattr(STDIN_FILENO, TCSANOW, &state);
+		if (ret)
+			fprintf(stderr, "Cannot set tty state\n");
+	}
+
+	if (argc >= 2) {
+		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+			fprintf(stderr, "Usage: %s [%s]\n", argv[0], path);
+			return EXIT_SUCCESS;
+		} else {
+			path = argv[1];
+		}
+	}
+
+	fprintf(stderr, "Open uhid-cdev %s\n", path);
+	fd = open(path, O_RDWR | O_CLOEXEC);
+	if (fd < 0) {
+		fprintf(stderr, "Cannot open uhid-cdev %s: %m\n", path);
+		return EXIT_FAILURE;
+	}
+
+	fprintf(stderr, "Create uhid device\n");
+	ret = create(fd);
+	if (ret) {
+		close(fd);
+		return EXIT_FAILURE;
+	}
+
+	pfds[0].fd = STDIN_FILENO;
+	pfds[0].events = POLLIN;
+	pfds[1].fd = fd;
+	pfds[1].events = POLLIN;
+
+	fprintf(stderr, "Press 'q' to quit...\n");
+	while (1) {
+		ret = poll(pfds, 2, -1);
+		if (ret < 0) {
+			fprintf(stderr, "Cannot poll for fds: %m\n");
+			break;
+		}
+		if (pfds[0].revents & POLLHUP) {
+			fprintf(stderr, "Received HUP on stdin\n");
+			break;
+		}
+		if (pfds[1].revents & POLLHUP) {
+			fprintf(stderr, "Received HUP on uhid-cdev\n");
+			break;
+		}
+
+		if (pfds[0].revents & POLLIN) {
+			ret = keyboard(fd);
+			if (ret)
+				break;
+		}
+		if (pfds[1].revents & POLLIN) {
+			ret = event(fd);
+			if (ret)
+				break;
+		}
+	}
+
+	fprintf(stderr, "Destroy uhid device\n");
+	destroy(fd);
+	return EXIT_SUCCESS;
+}
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index e5bd60f..7190f95 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1600,13 +1600,17 @@ sub process {
 
 # Check signature styles
 		if (!$in_header_lines &&
-		    $line =~ /^(\s*)($signature_tags)(\s*)(.*)/) {
+		    $line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) {
 			my $space_before = $1;
 			my $sign_off = $2;
 			my $space_after = $3;
 			my $email = $4;
 			my $ucfirst_sign_off = ucfirst(lc($sign_off));
 
+			if ($sign_off !~ /$signature_tags/) {
+				WARN("BAD_SIGN_OFF",
+				     "Non-standard signature: $sign_off\n" . $herecurr);
+			}
 			if (defined $space_before && $space_before ne "") {
 				WARN("BAD_SIGN_OFF",
 				     "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr);
@@ -1848,8 +1852,8 @@ sub process {
 
 			my $pos = pos_last_openparen($rest);
 			if ($pos >= 0) {
-				$line =~ /^\+([ \t]*)/;
-				my $newindent = $1;
+				$line =~ /^(\+| )([ \t]*)/;
+				my $newindent = $2;
 
 				my $goodtabindent = $oldindent .
 					"\t" x ($pos / 8) .
@@ -3309,6 +3313,22 @@ sub process {
 			}
 		}
 
+# check usleep_range arguments
+		if ($^V && $^V ge 5.10.0 &&
+		    defined $stat &&
+		    $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) {
+		 	my $min = $1;
+			my $max = $7;
+			if ($min eq $max) {
+				WARN("USLEEP_RANGE",
+				     "usleep_range should not use min == max args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
+			} elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ &&
+				 $min > $max) {
+				WARN("USLEEP_RANGE",
+				     "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
+			}
+		}
+
 # check for new externs in .c files.
 		if ($realfile =~ /\.c$/ && defined $stat &&
 		    $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 7966265..dce29cd 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -3,7 +3,7 @@
 # These targets are used from top-level makefile
 
 PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \
-	localmodconfig localyesconfig
+	localmodconfig localyesconfig kvmconfig
 
 ifdef KBUILD_KCONFIG
 Kconfig := $(KBUILD_KCONFIG)
@@ -33,6 +33,11 @@ silentoldconfig: $(obj)/conf
 	$(Q)mkdir -p include/generated
 	$< --$@ $(Kconfig)
 
+kvmconfig:
+	$(Q)$(CONFIG_SHELL) $(srctree)/scripts/config -e KVMTOOL_TEST_ENABLE
+	$(Q)yes "" | make oldconfig > /dev/null
+	@echo 'Kernel configuration modified to run as KVM guest.'
+
 localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
 	$(Q)mkdir -p include/generated
 	$(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl
index bccf07dd..2fbbbc1d 100644
--- a/scripts/kconfig/streamline_config.pl
+++ b/scripts/kconfig/streamline_config.pl
@@ -45,6 +45,16 @@
 use strict;
 use Getopt::Long;
 
+# set the environment variable LOCALMODCONFIG_DEBUG to get
+# debug output.
+my $debugprint = 0;
+$debugprint = 1 if (defined($ENV{LOCALMODCONFIG_DEBUG}));
+
+sub dprint {
+    return if (!$debugprint);
+    print STDERR @_;
+}
+
 my $config = ".config";
 
 my $uname = `uname -r`;
@@ -113,6 +123,10 @@ sub find_config {
 
 find_config;
 
+# Read in the entire config file into config_file
+my @config_file = <CIN>;
+close CIN;
+
 # Parse options
 my $localmodconfig = 0;
 my $localyesconfig = 0;
@@ -186,6 +200,7 @@ sub read_kconfig {
 	    $state = "NEW";
 	    $config = $2;
 
+	    # Add depends for 'if' nesting
 	    for (my $i = 0; $i < $iflevel; $i++) {
 		if ($i) {
 		    $depends{$config} .= " " . $ifdeps[$i];
@@ -204,10 +219,11 @@ sub read_kconfig {
 
 	# Get the configs that select this config
 	} elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) {
-	    if (defined($selects{$1})) {
-		$selects{$1} .= " " . $config;
+	    my $conf = $1;
+	    if (defined($selects{$conf})) {
+		$selects{$conf} .= " " . $config;
 	    } else {
-		$selects{$1} = $config;
+		$selects{$conf} = $config;
 	    }
 
 	# configs without prompts must be selected
@@ -250,6 +266,7 @@ if ($kconfig) {
     read_kconfig($kconfig);
 }
 
+# Makefiles can use variables to define their dependencies
 sub convert_vars {
     my ($line, %vars) = @_;
 
@@ -293,6 +310,7 @@ foreach my $makefile (@makefiles) {
 
 	my $objs;
 
+	# Convert variables in a line (could define configs)
 	$_ = convert_vars($_, %make_vars);
 
 	# collect objects after obj-$(CONFIG_FOO_BAR)
@@ -373,13 +391,15 @@ while (<LIN>) {
 close (LIN);
 
 # add to the configs hash all configs that are needed to enable
-# a loaded module.
+# a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o
+# where we know we need bar.o so we add FOO to the list.
 my %configs;
 foreach my $module (keys(%modules)) {
     if (defined($objects{$module})) {
 	my @arr = @{$objects{$module}};
 	foreach my $conf (@arr) {
 	    $configs{$conf} = $module;
+	    dprint "$conf added by direct ($module)\n";
 	}
     } else {
 	# Most likely, someone has a custom (binary?) module loaded.
@@ -387,9 +407,24 @@ foreach my $module (keys(%modules)) {
     }
 }
 
+# Read the current config, and see what is enabled. We want to
+# ignore configs that we would not enable anyway.
+
+my %orig_configs;
 my $valid = "A-Za-z_0-9";
+
+foreach my $line (@config_file) {
+    $_ = $line;
+
+    if (/(CONFIG_[$valid]*)=(m|y)/) {
+	$orig_configs{$1} = $2;
+    }
+}
+
 my $repeat = 1;
 
+my $depconfig;
+
 #
 # Note, we do not care about operands (like: &&, ||, !) we want to add any
 # config that is in the depend list of another config. This script does
@@ -398,7 +433,7 @@ my $repeat = 1;
 # to keep on. If A was on in the original config, B would not have been
 # and B would not be turned on by this script.
 #
-sub parse_config_dep_select
+sub parse_config_depends
 {
     my ($p) = @_;
 
@@ -409,10 +444,16 @@ sub parse_config_dep_select
 
 	    $p =~ s/^[^$valid]*[$valid]+//;
 
+	    # We only need to process if the depend config is a module
+	    if (!defined($orig_configs{$conf}) || !$orig_configs{conf} eq "m") {
+		next;
+	    }
+
 	    if (!defined($configs{$conf})) {
 		# We must make sure that this config has its
 		# dependencies met.
 		$repeat = 1; # do again
+		dprint "$conf selected by depend $depconfig\n";
 		$configs{$conf} = 1;
 	    }
 	} else {
@@ -421,31 +462,132 @@ sub parse_config_dep_select
     }
 }
 
-while ($repeat) {
-    $repeat = 0;
+# Select is treated a bit differently than depends. We call this
+# when a config has no prompt and requires another config to be
+# selected. We use to just select all configs that selected this
+# config, but found that that can balloon into enabling hundreds
+# of configs that we do not care about.
+#
+# The idea is we look at all the configs that select it. If one
+# is already in our list of configs to enable, then there's nothing
+# else to do. If there isn't, we pick the first config that was
+# enabled in the orignal config and use that.
+sub parse_config_selects
+{
+    my ($config, $p) = @_;
 
-    foreach my $config (keys %configs) {
-	$config =~ s/^CONFIG_//;
+    my $next_config;
+
+    while ($p =~ /[$valid]/) {
 
-	if (defined($depends{$config})) {
-	    # This config has dependencies. Make sure they are also included
-	    parse_config_dep_select $depends{$config};
+	if ($p =~ /^[^$valid]*([$valid]+)/) {
+	    my $conf = "CONFIG_" . $1;
+
+	    $p =~ s/^[^$valid]*[$valid]+//;
+
+	    # Make sure that this config exists in the current .config file
+	    if (!defined($orig_configs{$conf})) {
+		dprint "$conf not set for $config select\n";
+		next;
+	    }
+
+	    # Check if something other than a module selects this config
+	    if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") {
+		dprint "$conf (non module) selects config, we are good\n";
+		# we are good with this
+		return;
+	    }
+	    if (defined($configs{$conf})) {
+		dprint "$conf selects $config so we are good\n";
+		# A set config selects this config, we are good
+		return;
+	    }
+	    # Set this config to be selected
+	    if (!defined($next_config)) {
+		$next_config = $conf;
+	    }
+	} else {
+	    die "this should never happen";
 	}
+    }
 
-	if (defined($prompts{$config}) || !defined($selects{$config})) {
-	    next;
+    # If no possible config selected this, then something happened.
+    if (!defined($next_config)) {
+	print STDERR "WARNING: $config is required, but nothing in the\n";
+	print STDERR "  current config selects it.\n";
+	return;
+    }
+
+    # If we are here, then we found no config that is set and
+    # selects this config. Repeat.
+    $repeat = 1;
+    # Make this config need to be selected
+    $configs{$next_config} = 1;
+    dprint "$next_config selected by select $config\n";
+}
+
+my %process_selects;
+
+# loop through all configs, select their dependencies.
+sub loop_depend {
+    $repeat = 1;
+
+    while ($repeat) {
+	$repeat = 0;
+
+      forloop:
+	foreach my $config (keys %configs) {
+
+	    # If this config is not a module, we do not need to process it
+	    if (defined($orig_configs{$config}) && $orig_configs{$config} ne "m") {
+		next forloop;
+	    }
+
+	    $config =~ s/^CONFIG_//;
+	    $depconfig = $config;
+
+	    if (defined($depends{$config})) {
+		# This config has dependencies. Make sure they are also included
+		parse_config_depends $depends{$config};
+	    }
+
+	    # If the config has no prompt, then we need to check if a config
+	    # that is enabled selected it. Or if we need to enable one.
+	    if (!defined($prompts{$config}) && defined($selects{$config})) {
+		$process_selects{$config} = 1;
+	    }
 	}
+    }
+}
+
+sub loop_select {
+
+    foreach my $config (keys %process_selects) {
+	$config =~ s/^CONFIG_//;
+
+	dprint "Process select $config\n";
 
 	# config has no prompt and must be selected.
-	parse_config_dep_select $selects{$config};
+	parse_config_selects $config, $selects{$config};
     }
 }
 
+while ($repeat) {
+    # Get the first set of configs and their dependencies.
+    loop_depend;
+
+    $repeat = 0;
+
+    # Now we need to see if we have to check selects;
+    loop_select;
+}	    
+
 my %setconfigs;
 
 # Finally, read the .config file and turn off any module enabled that
 # we could not find a reason to keep enabled.
-while(<CIN>) {
+foreach my $line (@config_file) {
+    $_ = $line;
 
     if (/CONFIG_IKCONFIG/) {
 	if (/# CONFIG_IKCONFIG is not set/) {
@@ -473,7 +615,6 @@ while(<CIN>) {
     }
     print;
 }
-close(CIN);
 
 # Integrity check, make sure all modules that we want enabled do
 # indeed have their configs set.
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 5759751..7ed6864 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -156,7 +156,7 @@ static void device_id_check(const char *modname, const char *device_id,
 }
 
 /* USB is special because the bcdDevice can be matched against a numeric range */
-/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */
+/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */
 static void do_usb_entry(struct usb_device_id *id,
 			 unsigned int bcdDevice_initial, int bcdDevice_initial_digits,
 			 unsigned char range_lo, unsigned char range_hi,
@@ -210,6 +210,9 @@ static void do_usb_entry(struct usb_device_id *id,
 	ADD(alias, "ip",
 	    id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
 	    id->bInterfaceProtocol);
+	ADD(alias, "in",
+	    id->match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER,
+	    id->bInterfaceNumber);
 
 	add_wildcard(alias);
 	buf_printf(&mod->dev_table_buf,
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 0f84bb3..68e9f5e 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -865,6 +865,11 @@ static void check_section(const char *modname, struct elf_info *elf,
 #define ALL_EXIT_TEXT_SECTIONS \
 	".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$"
 
+#define ALL_PCI_INIT_SECTIONS	\
+	".pci_fixup_early$", ".pci_fixup_header$", ".pci_fixup_final$", \
+	".pci_fixup_enable$", ".pci_fixup_resume$", \
+	".pci_fixup_resume_early$", ".pci_fixup_suspend$"
+
 #define ALL_XXXINIT_SECTIONS DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, \
 	MEM_INIT_SECTIONS
 #define ALL_XXXEXIT_SECTIONS DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, \
@@ -1027,6 +1032,12 @@ const struct sectioncheck sectioncheck[] = {
 	.mismatch = ANY_EXIT_TO_ANY_INIT,
 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
+{
+	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
+	.tosec   = { INIT_SECTIONS, NULL },
+	.mismatch = ANY_INIT_TO_ANY_EXIT,
+	.symbol_white_list = { NULL },
+},
 /* Do not export init/exit functions or data */
 {
 	.fromsec = { "__ksymtab*", NULL },
diff --git a/security/keys/compat.c b/security/keys/compat.c
index c92d42b..1c26176 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -24,7 +24,7 @@
  *
  * If successful, 0 will be returned.
  */
-long compat_keyctl_instantiate_key_iov(
+static long compat_keyctl_instantiate_key_iov(
 	key_serial_t id,
 	const struct compat_iovec __user *_payload_iov,
 	unsigned ioc,
@@ -33,7 +33,7 @@ long compat_keyctl_instantiate_key_iov(
 	struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
 	long ret;
 
-	if (_payload_iov == 0 || ioc == 0)
+	if (!_payload_iov || !ioc)
 		goto no_payload;
 
 	ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc,
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 3dcbf86..c990b8c 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -242,7 +242,7 @@ extern long keyctl_instantiate_key_iov(key_serial_t,
 extern long keyctl_invalidate_key(key_serial_t);
 
 extern long keyctl_instantiate_key_common(key_serial_t,
-					  const struct iovec __user *,
+					  const struct iovec *,
 					  unsigned, size_t, key_serial_t);
 
 /*
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 0f5b3f0..3bdc419 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1106,7 +1106,7 @@ long keyctl_instantiate_key_iov(key_serial_t id,
 	struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
 	long ret;
 
-	if (_payload_iov == 0 || ioc == 0)
+	if (!_payload_iov || !ioc)
 		goto no_payload;
 
 	ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 7445875..81e7852 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -751,6 +751,7 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
 int __key_link_begin(struct key *keyring, const struct key_type *type,
 		     const char *description, unsigned long *_prealloc)
 	__acquires(&keyring->sem)
+	__acquires(&keyring_serialise_link_sem)
 {
 	struct keyring_list *klist, *nklist;
 	unsigned long prealloc;
@@ -960,6 +961,7 @@ void __key_link(struct key *keyring, struct key *key,
 void __key_link_end(struct key *keyring, struct key_type *type,
 		    unsigned long prealloc)
 	__releases(&keyring->sem)
+	__releases(&keyring_serialise_link_sem)
 {
 	BUG_ON(type == NULL);
 	BUG_ON(type->name == NULL);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 372ec65..cb2f1d0 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2717,7 +2717,7 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 			ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
 		return dentry_has_perm(cred, dentry, FILE__SETATTR);
 
-	if (ia_valid & ATTR_SIZE)
+	if ((ia_valid & ATTR_SIZE) && selinux_policycap_openperm)
 		av |= FILE__OPEN;
 
 	return dentry_has_perm(cred, dentry, av);
@@ -3181,6 +3181,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
 	case F_GETFL:
 	case F_GETOWN:
 	case F_GETSIG:
+	case F_GETOWNER_UIDS:
 		/* Just check FD__USE permission */
 		err = file_has_perm(cred, file, 0);
 		break;
@@ -5763,21 +5764,21 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
 	{
 		.hook =		selinux_ipv4_postroute,
 		.owner =	THIS_MODULE,
-		.pf =		PF_INET,
+		.pf =		NFPROTO_IPV4,
 		.hooknum =	NF_INET_POST_ROUTING,
 		.priority =	NF_IP_PRI_SELINUX_LAST,
 	},
 	{
 		.hook =		selinux_ipv4_forward,
 		.owner =	THIS_MODULE,
-		.pf =		PF_INET,
+		.pf =		NFPROTO_IPV4,
 		.hooknum =	NF_INET_FORWARD,
 		.priority =	NF_IP_PRI_SELINUX_FIRST,
 	},
 	{
 		.hook =		selinux_ipv4_output,
 		.owner =	THIS_MODULE,
-		.pf =		PF_INET,
+		.pf =		NFPROTO_IPV4,
 		.hooknum =	NF_INET_LOCAL_OUT,
 		.priority =	NF_IP_PRI_SELINUX_FIRST,
 	}
@@ -5789,14 +5790,14 @@ static struct nf_hook_ops selinux_ipv6_ops[] = {
 	{
 		.hook =		selinux_ipv6_postroute,
 		.owner =	THIS_MODULE,
-		.pf =		PF_INET6,
+		.pf =		NFPROTO_IPV6,
 		.hooknum =	NF_INET_POST_ROUTING,
 		.priority =	NF_IP6_PRI_SELINUX_LAST,
 	},
 	{
 		.hook =		selinux_ipv6_forward,
 		.owner =	THIS_MODULE,
-		.pf =		PF_INET6,
+		.pf =		NFPROTO_IPV6,
 		.hooknum =	NF_INET_FORWARD,
 		.priority =	NF_IP6_PRI_SELINUX_FIRST,
 	}
diff --git a/sound/core/misc.c b/sound/core/misc.c
index 7681679..30e027e 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -68,6 +68,7 @@ void __snd_printk(unsigned int level, const char *path, int line,
 {
 	va_list args;
 #ifdef CONFIG_SND_VERBOSE_PRINTK
+	int kern_level;
 	struct va_format vaf;
 	char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV";
 #endif
@@ -81,12 +82,16 @@ void __snd_printk(unsigned int level, const char *path, int line,
 #ifdef CONFIG_SND_VERBOSE_PRINTK
 	vaf.fmt = format;
 	vaf.va = &args;
-	if (format[0] == '<' && format[2] == '>') {
-		memcpy(verbose_fmt, format, 3);
-		vaf.fmt = format + 3;
+
+	kern_level = printk_get_level(format);
+	if (kern_level) {
+		const char *end_of_header = printk_skip_level(format);
+		memcpy(verbose_fmt, format, end_of_header - format);
+		vaf.fmt = end_of_header;
 	} else if (level)
-		memcpy(verbose_fmt, KERN_DEBUG, 3);
+		memcpy(verbose_fmt, KERN_DEBUG, sizeof(KERN_DEBUG) - 1);
 	printk(verbose_fmt, sanity_file_name(path), line, &vaf);
+
 #else
 	vprintk(format, args);
 #endif
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index 9c9eff9..d4fc1bf 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -488,3 +488,21 @@ unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
 	return SNDRV_PCM_RATE_KNOT;
 }
 EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit);
+
+/**
+ * snd_pcm_rate_bit_to_rate - converts SNDRV_PCM_RATE_xxx bit to sample rate
+ * @rate_bit: the rate bit to convert
+ *
+ * Returns the sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag
+ * or 0 for an unknown rate bit
+ */
+unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit)
+{
+	unsigned int i;
+
+	for (i = 0; i < snd_pcm_known_rates.count; i++)
+		if ((1u << i) == rate_bit)
+			return snd_pcm_known_rates.list[i];
+	return 0;
+}
+EXPORT_SYMBOL(snd_pcm_rate_bit_to_rate);
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c
index 582aace..b29b88f 100644
--- a/sound/i2c/other/tea575x-tuner.c
+++ b/sound/i2c/other/tea575x-tuner.c
@@ -37,8 +37,8 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips");
 MODULE_LICENSE("GPL");
 
-#define FREQ_LO		 (76U * 16000)
-#define FREQ_HI		(108U * 16000)
+#define FREQ_LO		((tea->tea5759 ? 760 :  875) * 1600U)
+#define FREQ_HI		((tea->tea5759 ? 910 : 1080) * 1600U)
 
 /*
  * definitions
@@ -120,9 +120,9 @@ static u32 snd_tea575x_read(struct snd_tea575x *tea)
 	return data;
 }
 
-static u32 snd_tea575x_get_freq(struct snd_tea575x *tea)
+static u32 snd_tea575x_val_to_freq(struct snd_tea575x *tea, u32 val)
 {
-	u32 freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK;
+	u32 freq = val & TEA575X_BIT_FREQ_MASK;
 
 	if (freq == 0)
 		return freq;
@@ -139,6 +139,11 @@ static u32 snd_tea575x_get_freq(struct snd_tea575x *tea)
 	return clamp(freq * 16, FREQ_LO, FREQ_HI); /* from kHz */
 }
 
+static u32 snd_tea575x_get_freq(struct snd_tea575x *tea)
+{
+	return snd_tea575x_val_to_freq(tea, snd_tea575x_read(tea));
+}
+
 static void snd_tea575x_set_freq(struct snd_tea575x *tea)
 {
 	u32 freq = tea->freq;
@@ -156,6 +161,7 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea)
 	tea->val &= ~TEA575X_BIT_FREQ_MASK;
 	tea->val |= freq & TEA575X_BIT_FREQ_MASK;
 	snd_tea575x_write(tea, tea->val);
+	tea->freq = snd_tea575x_val_to_freq(tea, tea->val);
 }
 
 /*
@@ -191,6 +197,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 	strcpy(v->name, "FM");
 	v->type = V4L2_TUNER_RADIO;
 	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+	if (!tea->cannot_read_data)
+		v->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED;
 	v->rangelow = FREQ_LO;
 	v->rangehigh = FREQ_HI;
 	v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
@@ -299,7 +307,7 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
 	}
 	tea->val &= ~TEA575X_BIT_SEARCH;
 	snd_tea575x_set_freq(tea);
-	return -EAGAIN;
+	return -ENODATA;
 }
 
 static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -317,7 +325,6 @@ static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
 }
 
 static const struct v4l2_file_operations tea575x_fops = {
-	.owner		= THIS_MODULE,
 	.unlocked_ioctl	= video_ioctl2,
 	.open           = v4l2_fh_open,
 	.release        = v4l2_fh_release,
@@ -337,7 +344,6 @@ static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
 };
 
 static const struct video_device tea575x_radio = {
-	.fops           = &tea575x_fops,
 	.ioctl_ops 	= &tea575x_ioctl_ops,
 	.release        = video_device_release_empty,
 };
@@ -349,7 +355,7 @@ static const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
 /*
  * initialize all the tea575x chips
  */
-int snd_tea575x_init(struct snd_tea575x *tea)
+int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner)
 {
 	int retval;
 
@@ -374,6 +380,9 @@ int snd_tea575x_init(struct snd_tea575x *tea)
 	tea->vd.lock = &tea->mutex;
 	tea->vd.v4l2_dev = tea->v4l2_dev;
 	tea->vd.ctrl_handler = &tea->ctrl_handler;
+	tea->fops = tea575x_fops;
+	tea->fops.owner = owner;
+	tea->vd.fops = &tea->fops;
 	set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags);
 	/* disable hw_freq_seek if we can't use it */
 	if (tea->cannot_read_data)
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index d7ccf28..ecc68df 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -135,7 +135,6 @@ struct snd_opti9xx {
 	unsigned long mc_base_size;
 #ifdef OPTi93X
 	unsigned long mc_indir_index;
-	unsigned long mc_indir_size;
 	struct resource *res_mc_indir;
 	struct snd_wss *codec;
 #endif	/* OPTi93X */
@@ -245,10 +244,8 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
 	case OPTi9XX_HW_82C931:
 	case OPTi9XX_HW_82C933:
 		chip->mc_base = (hardware == OPTi9XX_HW_82C930) ? 0xf8f : 0xf8d;
-		if (!chip->mc_indir_index) {
+		if (!chip->mc_indir_index)
 			chip->mc_indir_index = 0xe0e;
-			chip->mc_indir_size = 2;
-		}
 		chip->password = 0xe4;
 		chip->pwd_reg = 0;
 		break;
@@ -403,7 +400,9 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
 
 #else	/* OPTi93X */
 	case OPTi9XX_HW_82C931:
-	case OPTi9XX_HW_82C933:
+		/* disable 3D sound (set GPIO1 as output, low) */
+		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(20), 0x04, 0x0c);
+	case OPTi9XX_HW_82C933: /* FALL THROUGH */
 		/*
 		 * The BTC 1817DW has QS1000 wavetable which is connected
 		 * to the serial digital input of the OPTI931.
@@ -696,8 +695,7 @@ static int __devinit snd_opti9xx_read_check(struct snd_opti9xx *chip)
 		if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)))
 			return 0;
 #else	/* OPTi93X */
-	chip->res_mc_indir = request_region(chip->mc_indir_index,
-					    chip->mc_indir_size,
+	chip->res_mc_indir = request_region(chip->mc_indir_index, 2,
 					    "OPTi93x MC");
 	if (chip->res_mc_indir == NULL)
 		return -EBUSY;
@@ -770,8 +768,9 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
 #ifdef OPTi93X
 	port = pnp_port_start(pdev, 0) - 4;
 	fm_port = pnp_port_start(pdev, 1) + 8;
-	chip->mc_indir_index = pnp_port_start(pdev, 3) + 2;
-	chip->mc_indir_size = pnp_port_len(pdev, 3) - 2;
+	/* adjust mc_indir_index - some cards report it at 0xe?d,
+	   other at 0xe?c but it really is always at 0xe?e */
+	chip->mc_indir_index = (pnp_port_start(pdev, 3) & ~0xf) | 0xe;
 #else
 	devmc = pnp_request_card_device(card, pid->devs[2].id, NULL);
 	if (devmc == NULL)
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index 09d4648..7d8803a 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -69,7 +69,6 @@
 #include <linux/sound.h>
 #include <linux/slab.h>
 #include <linux/soundcard.h>
-#include <linux/ac97_codec.h>
 #include <linux/pci.h>
 #include <linux/bitops.h>
 #include <linux/interrupt.h>
@@ -199,6 +198,22 @@ static const char invalid_magic[] =
         }                                          \
 })
 
+/* AC97 registers */
+#define AC97_MASTER_VOL_STEREO   0x0002      /* Line Out		*/
+#define AC97_PCBEEP_VOL          0x000a      /* none			*/
+#define AC97_PHONE_VOL           0x000c      /* TAD Input (mono)	*/
+#define AC97_MIC_VOL             0x000e      /* MIC Input (mono)	*/
+#define AC97_LINEIN_VOL          0x0010      /* Line Input (stereo)	*/
+#define AC97_CD_VOL              0x0012      /* CD Input (stereo)	*/
+#define AC97_AUX_VOL             0x0016      /* Aux Input (stereo)	*/
+#define AC97_PCMOUT_VOL          0x0018      /* Wave Output (stereo)	*/
+#define AC97_RECORD_SELECT       0x001a      /*			*/
+#define AC97_RECORD_GAIN         0x001c
+#define AC97_GENERAL_PURPOSE     0x0020
+#define AC97_3D_CONTROL          0x0022
+#define AC97_POWER_CONTROL       0x0026
+#define AC97_VENDOR_ID1           0x007c
+
 struct list_head cs4297a_devs = { &cs4297a_devs, &cs4297a_devs };
 
 typedef struct serdma_descr_s {
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
index 643f111..7e814a5 100644
--- a/sound/oss/vwsnd.c
+++ b/sound/oss/vwsnd.c
@@ -438,7 +438,7 @@ static __inline__ void li_writeb(lithium_t *lith, int off, unsigned char val)
  *
  * Observe that (mask & -mask) is (1 << low_set_bit_of(mask)).
  * As long as mask is constant, we trust the compiler will change the
- * multipy and divide into shifts.
+ * multiply and divide into shifts.
  */
 
 #define SHIFT_FIELD(val, mask) (((val) * ((mask) & -(mask))) & (mask))
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c
index 557c782..fa13efb 100644
--- a/sound/pci/au88x0/au88x0_mixer.c
+++ b/sound/pci/au88x0/au88x0_mixer.c
@@ -10,6 +10,15 @@
 #include <sound/core.h>
 #include "au88x0.h"
 
+static int remove_ctl(struct snd_card *card, const char *name)
+{
+	struct snd_ctl_elem_id id;
+	memset(&id, 0, sizeof(id));
+	strcpy(id.name, name);
+	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	return snd_ctl_remove_id(card, &id);
+}
+
 static int __devinit snd_vortex_mixer(vortex_t * vortex)
 {
 	struct snd_ac97_bus *pbus;
@@ -28,5 +37,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex)
 	ac97.scaps = AC97_SCAP_NO_SPDIF;
 	err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
 	vortex->isquad = ((vortex->codec == NULL) ?  0 : (vortex->codec->ext_id&0x80));
+	remove_ctl(vortex->card, "Master Mono Playback Volume");
+	remove_ctl(vortex->card, "Master Mono Playback Switch");
 	return err;
 }
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 67f47d8..52b5c0b 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -2769,7 +2769,7 @@ static int __devinit snd_es1968_create(struct snd_card *card,
 	chip->tea.ops = &snd_es1968_tea_ops;
 	strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
 	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
-	if (!snd_tea575x_init(&chip->tea))
+	if (!snd_tea575x_init(&chip->tea, THIS_MODULE))
 		printk(KERN_INFO "es1968: detected TEA575x radio\n");
 #endif
 
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index f696623..b32e802 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1254,7 +1254,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
 	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
 	if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
 	    (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
-		if (snd_tea575x_init(&chip->tea)) {
+		if (snd_tea575x_init(&chip->tea, THIS_MODULE)) {
 			snd_printk(KERN_ERR "TEA575x radio not found\n");
 			snd_fm801_free(chip);
 			return -ENODEV;
@@ -1263,7 +1263,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
 		/* autodetect tuner connection */
 		for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) {
 			chip->tea575x_tuner = tea575x_tuner;
-			if (!snd_tea575x_init(&chip->tea)) {
+			if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) {
 				snd_printk(KERN_INFO "detected TEA575x radio type %s\n",
 					   get_tea575x_gpio(chip)->name);
 				break;
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 163b6b5..d030797 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -97,19 +97,6 @@ config SND_HDA_CODEC_REALTEK
 	  snd-hda-codec-realtek.
 	  This module is automatically loaded at probing.
 
-config SND_HDA_ENABLE_REALTEK_QUIRKS
-	bool "Build static quirks for Realtek codecs"
-	depends on SND_HDA_CODEC_REALTEK
-	default y
-	help
-	  Say Y here to build the static quirks codes for Realtek codecs.
-	  If you need the "model" preset that the default BIOS auto-parser
-	  can't handle, turn this option on.
-
-	  If your device works with model=auto option, basically you don't
-	  need the quirk code.  By turning this off, you can reduce the
-	  module size quite a lot.
-
 config SND_HDA_CODEC_ANALOG
 	bool "Build Analog Device HD-audio codec support"
 	default y
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 6e9ef3e..f7520b9 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -618,7 +618,6 @@ int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
 			  const struct hda_verb *list)
 {
 	const struct hda_verb **v;
-	snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8);
 	v = snd_array_new(&spec->verbs);
 	if (!v)
 		return -ENOMEM;
diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h
index 2a7889d..632ad0a 100644
--- a/sound/pci/hda/hda_auto_parser.h
+++ b/sound/pci/hda/hda_auto_parser.h
@@ -157,4 +157,14 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
 			const struct snd_pci_quirk *quirk,
 			const struct hda_fixup *fixlist);
 
+static inline void snd_hda_gen_init(struct hda_gen_spec *spec)
+{
+	snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8);
+}
+
+static inline void snd_hda_gen_free(struct hda_gen_spec *spec)
+{
+	snd_array_free(&spec->verbs);
+}
+
 #endif /* __SOUND_HDA_AUTO_PARSER_H */
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 7504e62..14bc1c8 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1184,6 +1184,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
 {
 	if (!codec)
 		return;
+	snd_hda_jack_tbl_clear(codec);
 	restore_init_pincfgs(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	cancel_delayed_work(&codec->power_work);
@@ -1192,6 +1193,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
 	list_del(&codec->list);
 	snd_array_free(&codec->mixers);
 	snd_array_free(&codec->nids);
+	snd_array_free(&codec->cvt_setups);
 	snd_array_free(&codec->conn_lists);
 	snd_array_free(&codec->spdif_out);
 	codec->bus->caddr_tbl[codec->addr] = NULL;
@@ -2333,6 +2335,8 @@ int snd_hda_codec_reset(struct hda_codec *codec)
 	/* free only driver_pins so that init_pins + user_pins are restored */
 	snd_array_free(&codec->driver_pins);
 	restore_pincfgs(codec);
+	snd_array_free(&codec->cvt_setups);
+	snd_array_free(&codec->spdif_out);
 	codec->num_pcms = 0;
 	codec->pcm_info = NULL;
 	codec->preset = NULL;
@@ -3505,22 +3509,52 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
 EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
 
 /*
+ *  supported power states check
+ */
+static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, hda_nid_t fg,
+				unsigned int power_state)
+{
+	int sup = snd_hda_param_read(codec, fg, AC_PAR_POWER_STATE);
+
+	if (sup < 0)
+		return false;
+	if (sup & power_state)
+		return true;
+	else
+		return false;
+}
+
+/*
  * set power state of the codec
  */
 static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
 				unsigned int power_state)
 {
+	int count;
+	unsigned int state;
+
 	if (codec->patch_ops.set_power_state) {
 		codec->patch_ops.set_power_state(codec, fg, power_state);
 		return;
 	}
 
 	/* this delay seems necessary to avoid click noise at power-down */
-	if (power_state == AC_PWRST_D3)
-		msleep(100);
-	snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
-			    power_state);
-	snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
+	if (power_state == AC_PWRST_D3) {
+		/* transition time less than 10ms for power down */
+		bool epss = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_EPSS);
+		msleep(epss ? 10 : 100);
+	}
+
+	/* repeat power states setting at most 10 times*/
+	for (count = 0; count < 10; count++) {
+		snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+				    power_state);
+		snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
+		state = snd_hda_codec_read(codec, fg, 0,
+					   AC_VERB_GET_POWER_STATE, 0);
+		if (!(state & AC_PWRST_ERROR))
+			break;
+	}
 }
 
 #ifdef CONFIG_SND_HDA_HWDEP
@@ -4414,6 +4448,13 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
 	cancel_delayed_work_sync(&codec->power_work);
 
 	spin_lock(&codec->power_lock);
+	/* If the power down delayed work was cancelled above before starting,
+	 * then there is no need to go through power up here.
+	 */
+	if (codec->power_on) {
+		spin_unlock(&codec->power_lock);
+		return;
+	}
 	trace_hda_power_up(codec);
 	snd_hda_update_power_acct(codec);
 	codec->power_on = 1;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 2fdaadb..a4ac1de 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -323,6 +323,9 @@ enum {
 #define AC_PWRST_D1			0x01
 #define AC_PWRST_D2			0x02
 #define AC_PWRST_D3			0x03
+#define AC_PWRST_ERROR                  (1<<8)
+#define AC_PWRST_CLK_STOP_OK            (1<<9)
+#define AC_PWRST_SETTING_RESET          (1<<10)
 
 /* Processing capabilies */
 #define AC_PCAP_BENIGN			(1<<0)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 7757536..86758dd 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -535,6 +535,7 @@ enum {
 #define AZX_DCAPS_BUFSIZE	(1 << 21)	/* no buffer size alignment */
 #define AZX_DCAPS_ALIGN_BUFSIZE	(1 << 22)	/* buffer size alignment */
 #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)	/* BDLE in 4k boundary */
+#define AZX_DCAPS_POSFIX_COMBO  (1 << 24)	/* Use COMBO as default */
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -2731,6 +2732,10 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
 		snd_printd(SFX "Using LPIB position fix\n");
 		return POS_FIX_LPIB;
 	}
+	if (chip->driver_caps & AZX_DCAPS_POSFIX_COMBO) {
+		snd_printd(SFX "Using COMBO position fix\n");
+		return POS_FIX_COMBO;
+	}
 	return POS_FIX_AUTO;
 }
 
@@ -3243,7 +3248,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
 	/* CPT */
 	{ PCI_DEVICE(0x8086, 0x1c20),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-	  AZX_DCAPS_BUFSIZE },
+	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
 	/* PBG */
 	{ PCI_DEVICE(0x8086, 0x1d20),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
@@ -3251,11 +3256,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
 	/* Panther Point */
 	{ PCI_DEVICE(0x8086, 0x1e20),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-	  AZX_DCAPS_BUFSIZE},
+	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
 	/* Lynx Point */
 	{ PCI_DEVICE(0x8086, 0x8c20),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-	  AZX_DCAPS_BUFSIZE},
+	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
 	/* SCH */
 	{ PCI_DEVICE(0x8086, 0x811b),
 	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
@@ -3341,6 +3346,10 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
 	/* VIA VT8251/VT8237A */
 	{ PCI_DEVICE(0x1106, 0x3288),
 	  .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
+	/* VIA GFX VT7122/VX900 */
+	{ PCI_DEVICE(0x1106, 0x9170), .driver_data = AZX_DRIVER_GENERIC },
+	/* VIA GFX VT6122/VX11 */
+	{ PCI_DEVICE(0x1106, 0x9140), .driver_data = AZX_DRIVER_GENERIC },
 	/* SIS966 */
 	{ PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS },
 	/* ULI M5461 */
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 2dd1c11..60c976f 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -127,10 +127,15 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec)
 static void jack_detect_update(struct hda_codec *codec,
 			       struct hda_jack_tbl *jack)
 {
-	if (jack->jack_dirty || !jack->jack_detect) {
+	if (!jack->jack_dirty)
+		return;
+
+	if (jack->phantom_jack)
+		jack->pin_sense = AC_PINSENSE_PRESENCE;
+	else
 		jack->pin_sense = read_pin_sense(codec, jack->nid);
-		jack->jack_dirty = 0;
-	}
+
+	jack->jack_dirty = 0;
 }
 
 /**
@@ -264,8 +269,8 @@ static void hda_free_jack_priv(struct snd_jack *jack)
  * This assigns a jack-detection kctl to the given pin.  The kcontrol
  * will have the given name and index.
  */
-int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
-			  const char *name, int idx)
+static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
+			  const char *name, int idx, bool phantom_jack)
 {
 	struct hda_jack_tbl *jack;
 	struct snd_kcontrol *kctl;
@@ -283,19 +288,30 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
 	if (err < 0)
 		return err;
 	jack->kctl = kctl;
+	jack->phantom_jack = !!phantom_jack;
+
 	state = snd_hda_jack_detect(codec, nid);
 	snd_kctl_jack_report(codec->bus->card, kctl, state);
 #ifdef CONFIG_SND_HDA_INPUT_JACK
-	jack->type = get_input_jack_type(codec, nid);
-	err = snd_jack_new(codec->bus->card, name, jack->type, &jack->jack);
-	if (err < 0)
-		return err;
-	jack->jack->private_data = jack;
-	jack->jack->private_free = hda_free_jack_priv;
-	snd_jack_report(jack->jack, state ? jack->type : 0);
+	if (!phantom_jack) {
+		jack->type = get_input_jack_type(codec, nid);
+		err = snd_jack_new(codec->bus->card, name, jack->type,
+				   &jack->jack);
+		if (err < 0)
+			return err;
+		jack->jack->private_data = jack;
+		jack->jack->private_free = hda_free_jack_priv;
+		snd_jack_report(jack->jack, state ? jack->type : 0);
+	}
 #endif
 	return 0;
 }
+
+int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
+			  const char *name, int idx)
+{
+	return __snd_hda_jack_add_kctl(codec, nid, name, idx, false);
+}
 EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl);
 
 static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
@@ -305,25 +321,32 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
 	unsigned int def_conf, conn;
 	char name[44];
 	int idx, err;
+	bool phantom_jack;
 
 	if (!nid)
 		return 0;
-	if (!is_jack_detectable(codec, nid))
-		return 0;
 	def_conf = snd_hda_codec_get_pincfg(codec, nid);
 	conn = get_defcfg_connect(def_conf);
-	if (conn != AC_JACK_PORT_COMPLEX)
+	if (conn == AC_JACK_PORT_NONE)
 		return 0;
+	phantom_jack = (conn != AC_JACK_PORT_COMPLEX) ||
+		       !is_jack_detectable(codec, nid);
 
 	snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx);
+	if (phantom_jack)
+		/* Example final name: "Internal Mic Phantom Jack" */
+		strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
 	if (!strcmp(name, lastname) && idx == *lastidx)
 		idx++;
-	strncpy(lastname, name, 44);
+	strncpy(lastname, name, sizeof(name));
 	*lastidx = idx;
-	err = snd_hda_jack_add_kctl(codec, nid, name, idx);
+	err = __snd_hda_jack_add_kctl(codec, nid, name, idx, phantom_jack);
 	if (err < 0)
 		return err;
-	return snd_hda_jack_detect_enable(codec, nid, 0);
+
+	if (!phantom_jack)
+		return snd_hda_jack_detect_enable(codec, nid, 0);
+	return 0;
 }
 
 /**
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index 8ae5246..a9803da 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -23,6 +23,7 @@ struct hda_jack_tbl {
 	unsigned int pin_sense;		/* cached pin-sense value */
 	unsigned int jack_detect:1;	/* capable of jack-detection? */
 	unsigned int jack_dirty:1;	/* needs to update? */
+	unsigned int phantom_jack:1;    /* a fixed, always present port? */
 	struct snd_kcontrol *kctl;	/* assigned kctl for jack-detection */
 #ifdef CONFIG_SND_HDA_INPUT_JACK
 	int type;
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index e59e2f0..7e46258 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -426,10 +426,10 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
 
 static const char *get_pwr_state(u32 state)
 {
-	static const char * const buf[4] = {
-		"D0", "D1", "D2", "D3"
+	static const char * const buf[] = {
+		"D0", "D1", "D2", "D3", "D3cold"
 	};
-	if (state < 4)
+	if (state < ARRAY_SIZE(buf))
 		return buf[state];
 	return "UNKNOWN";
 }
@@ -451,14 +451,21 @@ static void print_power_state(struct snd_info_buffer *buffer,
 	int sup = snd_hda_param_read(codec, nid, AC_PAR_POWER_STATE);
 	int pwr = snd_hda_codec_read(codec, nid, 0,
 				     AC_VERB_GET_POWER_STATE, 0);
-	if (sup)
+	if (sup != -1)
 		snd_iprintf(buffer, "  Power states: %s\n",
 			    bits_names(sup, names, ARRAY_SIZE(names)));
 
-	snd_iprintf(buffer, "  Power: setting=%s, actual=%s\n",
+	snd_iprintf(buffer, "  Power: setting=%s, actual=%s",
 		    get_pwr_state(pwr & AC_PWRST_SETTING),
 		    get_pwr_state((pwr & AC_PWRST_ACTUAL) >>
 				  AC_PWRST_ACTUAL_SHIFT));
+	if (pwr & AC_PWRST_ERROR)
+		snd_iprintf(buffer, ", Error");
+	if (pwr & AC_PWRST_CLK_STOP_OK)
+		snd_iprintf(buffer, ", Clock-stop-OK");
+	if (pwr & AC_PWRST_SETTING_RESET)
+		snd_iprintf(buffer, ", Setting-reset");
+	snd_iprintf(buffer, "\n");
 }
 
 static void print_unsol_cap(struct snd_info_buffer *buffer,
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 172370b..2bf99fc 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -445,8 +445,10 @@ static int conexant_init(struct hda_codec *codec)
 
 static void conexant_free(struct hda_codec *codec)
 {
+	struct conexant_spec *spec = codec->spec;
+	snd_hda_gen_free(&spec->gen);
 	snd_hda_detach_beep_device(codec);
-	kfree(codec->spec);
+	kfree(spec);
 }
 
 static const struct snd_kcontrol_new cxt_capture_mixers[] = {
@@ -4466,6 +4468,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
 	SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
+	SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
 	{}
 };
 
@@ -4497,6 +4500,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
 	if (!spec)
 		return -ENOMEM;
 	codec->spec = spec;
+	snd_hda_gen_init(&spec->gen);
 
 	switch (codec->vendor_id) {
 	case 0x14f15045:
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index ad319d4..d6a8260 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -85,7 +85,7 @@ struct hdmi_spec {
 	 * Non-generic ATI/NVIDIA specific
 	 */
 	struct hda_multi_out multiout;
-	const struct hda_pcm_stream *pcm_playback;
+	struct hda_pcm_stream pcm_playback;
 };
 
 
@@ -787,7 +787,7 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
 	int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
 
 	printk(KERN_INFO
-		"HDMI CP event: CODEC=%d PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+		"HDMI CP event: CODEC=%d TAG=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
 		codec->addr,
 		tag,
 		subtag,
@@ -1277,23 +1277,34 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
 	return 0;
 }
 
-static int generic_hdmi_init(struct hda_codec *codec)
+static int generic_hdmi_init_per_pins(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx;
 
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
 		struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
-		hda_nid_t pin_nid = per_pin->pin_nid;
 		struct hdmi_eld *eld = &per_pin->sink_eld;
 
-		hdmi_init_pin(codec, pin_nid);
-		snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
-
 		per_pin->codec = codec;
 		INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
 		snd_hda_eld_proc_new(codec, eld, pin_idx);
 	}
+	return 0;
+}
+
+static int generic_hdmi_init(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	int pin_idx;
+
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+		struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+		hda_nid_t pin_nid = per_pin->pin_nid;
+
+		hdmi_init_pin(codec, pin_nid);
+		snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
+	}
 	snd_hda_jack_report_sync(codec);
 	return 0;
 }
@@ -1338,6 +1349,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
 		return -EINVAL;
 	}
 	codec->patch_ops = generic_hdmi_patch_ops;
+	generic_hdmi_init_per_pins(codec);
 
 	init_channel_allocations();
 
@@ -1352,45 +1364,65 @@ static int simple_playback_build_pcms(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	struct hda_pcm *info = spec->pcm_rec;
-	int i;
+	unsigned int chans;
+	struct hda_pcm_stream *pstr;
 
-	codec->num_pcms = spec->num_cvts;
+	codec->num_pcms = 1;
 	codec->pcm_info = info;
 
-	for (i = 0; i < codec->num_pcms; i++, info++) {
-		unsigned int chans;
-		struct hda_pcm_stream *pstr;
-
-		chans = get_wcaps(codec, spec->cvts[i].cvt_nid);
-		chans = get_wcaps_channels(chans);
+	chans = get_wcaps(codec, spec->cvts[0].cvt_nid);
+	chans = get_wcaps_channels(chans);
 
-		info->name = get_hdmi_pcm_name(i);
-		info->pcm_type = HDA_PCM_TYPE_HDMI;
-		pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
-		snd_BUG_ON(!spec->pcm_playback);
-		*pstr = *spec->pcm_playback;
-		pstr->nid = spec->cvts[i].cvt_nid;
-		if (pstr->channels_max <= 2 && chans && chans <= 16)
-			pstr->channels_max = chans;
-	}
+	info->name = get_hdmi_pcm_name(0);
+	info->pcm_type = HDA_PCM_TYPE_HDMI;
+	pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
+	*pstr = spec->pcm_playback;
+	pstr->nid = spec->cvts[0].cvt_nid;
+	if (pstr->channels_max <= 2 && chans && chans <= 16)
+		pstr->channels_max = chans;
 
 	return 0;
 }
 
+/* unsolicited event for jack sensing */
+static void simple_hdmi_unsol_event(struct hda_codec *codec,
+				    unsigned int res)
+{
+	snd_hda_jack_set_dirty_all(codec);
+	snd_hda_jack_report_sync(codec);
+}
+
+/* generic_hdmi_build_jack can be used for simple_hdmi, too,
+ * as long as spec->pins[] is set correctly
+ */
+#define simple_hdmi_build_jack	generic_hdmi_build_jack
+
 static int simple_playback_build_controls(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int err;
-	int i;
 
-	for (i = 0; i < codec->num_pcms; i++) {
-		err = snd_hda_create_spdif_out_ctls(codec,
-						    spec->cvts[i].cvt_nid,
-						    spec->cvts[i].cvt_nid);
-		if (err < 0)
-			return err;
-	}
+	err = snd_hda_create_spdif_out_ctls(codec,
+					    spec->cvts[0].cvt_nid,
+					    spec->cvts[0].cvt_nid);
+	if (err < 0)
+		return err;
+	return simple_hdmi_build_jack(codec, 0);
+}
 
+static int simple_playback_init(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	hda_nid_t pin = spec->pins[0].pin_nid;
+
+	snd_hda_codec_write(codec, pin, 0,
+			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+	/* some codecs require to unmute the pin */
+	if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
+		snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_OUT_UNMUTE);
+	snd_hda_jack_detect_enable(codec, pin, pin);
+	snd_hda_jack_report_sync(codec);
 	return 0;
 }
 
@@ -1418,7 +1450,15 @@ static const hda_nid_t nvhdmi_con_nids_7x[4] = {
 	0x6, 0x8, 0xa, 0xc,
 };
 
-static const struct hda_verb nvhdmi_basic_init_7x[] = {
+static const struct hda_verb nvhdmi_basic_init_7x_2ch[] = {
+	/* set audio protect on */
+	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
+	/* enable digital output on pin widget */
+	{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+	{} /* terminator */
+};
+
+static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = {
 	/* set audio protect on */
 	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
 	/* enable digital output on pin widget */
@@ -1446,9 +1486,15 @@ static const struct hda_verb nvhdmi_basic_init_7x[] = {
 	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 #endif
 
-static int nvhdmi_7x_init(struct hda_codec *codec)
+static int nvhdmi_7x_init_2ch(struct hda_codec *codec)
 {
-	snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
+	snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch);
+	return 0;
+}
+
+static int nvhdmi_7x_init_8ch(struct hda_codec *codec)
+{
+	snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch);
 	return 0;
 }
 
@@ -1524,6 +1570,50 @@ static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 					     stream_tag, format, substream);
 }
 
+static const struct hda_pcm_stream simple_pcm_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.ops = {
+		.open = simple_playback_pcm_open,
+		.close = simple_playback_pcm_close,
+		.prepare = simple_playback_pcm_prepare
+	},
+};
+
+static const struct hda_codec_ops simple_hdmi_patch_ops = {
+	.build_controls = simple_playback_build_controls,
+	.build_pcms = simple_playback_build_pcms,
+	.init = simple_playback_init,
+	.free = simple_playback_free,
+	.unsol_event = simple_hdmi_unsol_event,
+};
+
+static int patch_simple_hdmi(struct hda_codec *codec,
+			     hda_nid_t cvt_nid, hda_nid_t pin_nid)
+{
+	struct hdmi_spec *spec;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (!spec)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	spec->multiout.num_dacs = 0;  /* no analog */
+	spec->multiout.max_channels = 2;
+	spec->multiout.dig_out_nid = cvt_nid;
+	spec->num_cvts = 1;
+	spec->num_pins = 1;
+	spec->cvts[0].cvt_nid = cvt_nid;
+	spec->pins[0].pin_nid = pin_nid;
+	spec->pcm_playback = simple_pcm_playback;
+
+	codec->patch_ops = simple_hdmi_patch_ops;
+
+	return 0;
+}
+
 static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec,
 						    int channels)
 {
@@ -1696,54 +1786,20 @@ static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
 	},
 };
 
-static const struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
-	.nid = nvhdmi_master_con_nid_7x,
-	.rates = SUPPORTED_RATES,
-	.maxbps = SUPPORTED_MAXBPS,
-	.formats = SUPPORTED_FORMATS,
-	.ops = {
-		.open = simple_playback_pcm_open,
-		.close = simple_playback_pcm_close,
-		.prepare = simple_playback_pcm_prepare
-	},
-};
-
-static const struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
-	.build_controls = simple_playback_build_controls,
-	.build_pcms = simple_playback_build_pcms,
-	.init = nvhdmi_7x_init,
-	.free = simple_playback_free,
-};
-
-static const struct hda_codec_ops nvhdmi_patch_ops_2ch = {
-	.build_controls = simple_playback_build_controls,
-	.build_pcms = simple_playback_build_pcms,
-	.init = nvhdmi_7x_init,
-	.free = simple_playback_free,
-};
-
 static int patch_nvhdmi_2ch(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec;
+	int err = patch_simple_hdmi(codec, nvhdmi_master_con_nid_7x,
+				    nvhdmi_master_pin_nid_7x);
+	if (err < 0)
+		return err;
 
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
-
-	codec->spec = spec;
-
-	spec->multiout.num_dacs = 0;  /* no analog */
-	spec->multiout.max_channels = 2;
-	spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
-	spec->num_cvts = 1;
-	spec->cvts[0].cvt_nid = nvhdmi_master_con_nid_7x;
-	spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
-
-	codec->patch_ops = nvhdmi_patch_ops_2ch;
-
+	codec->patch_ops.init = nvhdmi_7x_init_2ch;
+	/* override the PCM rates, etc, as the codec doesn't give full list */
+	spec = codec->spec;
+	spec->pcm_playback.rates = SUPPORTED_RATES;
+	spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
+	spec->pcm_playback.formats = SUPPORTED_FORMATS;
 	return 0;
 }
 
@@ -1751,13 +1807,12 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec;
 	int err = patch_nvhdmi_2ch(codec);
-
 	if (err < 0)
 		return err;
 	spec = codec->spec;
 	spec->multiout.max_channels = 8;
-	spec->pcm_playback = &nvhdmi_pcm_playback_8ch_7x;
-	codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
+	spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
+	codec->patch_ops.init = nvhdmi_7x_init_8ch;
 
 	/* Initialize the audio infoframe channel mask and checksum to something
 	 * valid */
@@ -1801,69 +1856,26 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
-static const struct hda_pcm_stream atihdmi_pcm_digital_playback = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
-	.nid = ATIHDMI_CVT_NID,
-	.ops = {
-		.open = simple_playback_pcm_open,
-		.close = simple_playback_pcm_close,
-		.prepare = atihdmi_playback_pcm_prepare
-	},
-};
-
-static const struct hda_verb atihdmi_basic_init[] = {
-	/* enable digital output on pin widget */
-	{ 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{} /* terminator */
-};
-
-static int atihdmi_init(struct hda_codec *codec)
+static int patch_atihdmi(struct hda_codec *codec)
 {
-	struct hdmi_spec *spec = codec->spec;
-
-	snd_hda_sequence_write(codec, atihdmi_basic_init);
-	/* SI codec requires to unmute the pin */
-	if (get_wcaps(codec, spec->pins[0].pin_nid) & AC_WCAP_OUT_AMP)
-		snd_hda_codec_write(codec, spec->pins[0].pin_nid, 0,
-				    AC_VERB_SET_AMP_GAIN_MUTE,
-				    AMP_OUT_UNMUTE);
+	struct hdmi_spec *spec;
+	int err = patch_simple_hdmi(codec, ATIHDMI_CVT_NID, ATIHDMI_PIN_NID);
+	if (err < 0)
+		return err;
+	spec = codec->spec;
+	spec->pcm_playback.ops.prepare = atihdmi_playback_pcm_prepare;
 	return 0;
 }
 
-static const struct hda_codec_ops atihdmi_patch_ops = {
-	.build_controls = simple_playback_build_controls,
-	.build_pcms = simple_playback_build_pcms,
-	.init = atihdmi_init,
-	.free = simple_playback_free,
-};
-
+/* VIA HDMI Implementation */
+#define VIAHDMI_CVT_NID	0x02	/* audio converter1 */
+#define VIAHDMI_PIN_NID	0x03	/* HDMI output pin1 */
 
-static int patch_atihdmi(struct hda_codec *codec)
+static int patch_via_hdmi(struct hda_codec *codec)
 {
-	struct hdmi_spec *spec;
-
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
-
-	codec->spec = spec;
-
-	spec->multiout.num_dacs = 0;	  /* no analog */
-	spec->multiout.max_channels = 2;
-	spec->multiout.dig_out_nid = ATIHDMI_CVT_NID;
-	spec->num_cvts = 1;
-	spec->cvts[0].cvt_nid = ATIHDMI_CVT_NID;
-	spec->pins[0].pin_nid = ATIHDMI_PIN_NID;
-	spec->pcm_playback = &atihdmi_pcm_digital_playback;
-
-	codec->patch_ops = atihdmi_patch_ops;
-
-	return 0;
+	return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID);
 }
 
-
 /*
  * patch entries
  */
@@ -1904,6 +1916,10 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x10de0044, .name = "GPU 44 HDMI/DP",	.patch = patch_generic_hdmi },
 { .id = 0x10de0067, .name = "MCP67 HDMI",	.patch = patch_nvhdmi_2ch },
 { .id = 0x10de8001, .name = "MCP73 HDMI",	.patch = patch_nvhdmi_2ch },
+{ .id = 0x11069f80, .name = "VX900 HDMI/DP",	.patch = patch_via_hdmi },
+{ .id = 0x11069f81, .name = "VX900 HDMI/DP",	.patch = patch_via_hdmi },
+{ .id = 0x11069f84, .name = "VX11 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x11069f85, .name = "VX11 HDMI/DP",	.patch = patch_generic_hdmi },
 { .id = 0x80860054, .name = "IbexPeak HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862801, .name = "Bearlake HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862802, .name = "Cantiga HDMI",	.patch = patch_generic_hdmi },
@@ -1950,6 +1966,10 @@ MODULE_ALIAS("snd-hda-codec-id:10de0043");
 MODULE_ALIAS("snd-hda-codec-id:10de0044");
 MODULE_ALIAS("snd-hda-codec-id:10de0067");
 MODULE_ALIAS("snd-hda-codec-id:10de8001");
+MODULE_ALIAS("snd-hda-codec-id:11069f80");
+MODULE_ALIAS("snd-hda-codec-id:11069f81");
+MODULE_ALIAS("snd-hda-codec-id:11069f84");
+MODULE_ALIAS("snd-hda-codec-id:11069f85");
 MODULE_ALIAS("snd-hda-codec-id:17e80047");
 MODULE_ALIAS("snd-hda-codec-id:80860054");
 MODULE_ALIAS("snd-hda-codec-id:80862801");
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index f8f4906..5c81ee9 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -170,6 +170,7 @@ struct alc_spec {
 	hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
 	unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
 	int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */
+	hda_nid_t inv_dmic_pin;
 
 	/* hooks */
 	void (*init_hook)(struct hda_codec *codec);
@@ -201,6 +202,8 @@ struct alc_spec {
 	unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */
 	unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */
 	unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */
+	unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */
+	unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */
 
 	/* auto-mute control */
 	int automute_mode;
@@ -298,6 +301,7 @@ static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx)
 }
 
 static void call_update_outputs(struct hda_codec *codec);
+static void alc_inv_dmic_sync(struct hda_codec *codec, bool force);
 
 /* select the given imux item; either unmute exclusively or select the route */
 static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
@@ -368,6 +372,7 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
 					  AC_VERB_SET_CONNECT_SEL,
 					  imux->items[idx].index);
 	}
+	alc_inv_dmic_sync(codec, true);
 	return 1;
 }
 
@@ -1556,14 +1561,14 @@ typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
 
 static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol,
-				 getput_call_t func, bool check_adc_switch)
+				 getput_call_t func, bool is_put)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct alc_spec *spec = codec->spec;
 	int i, err = 0;
 
 	mutex_lock(&codec->control_mutex);
-	if (check_adc_switch && spec->dyn_adc_switch) {
+	if (is_put && spec->dyn_adc_switch) {
 		for (i = 0; i < spec->num_adc_nids; i++) {
 			kcontrol->private_value =
 				HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
@@ -1584,6 +1589,8 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
 						    3, 0, HDA_INPUT);
 		err = func(kcontrol, ucontrol);
 	}
+	if (err >= 0 && is_put)
+		alc_inv_dmic_sync(codec, false);
  error:
 	mutex_unlock(&codec->control_mutex);
 	return err;
@@ -1676,6 +1683,116 @@ DEFINE_CAPMIX_NOSRC(2);
 DEFINE_CAPMIX_NOSRC(3);
 
 /*
+ * Inverted digital-mic handling
+ *
+ * First off, it's a bit tricky.  The "Inverted Internal Mic Capture Switch"
+ * gives the additional mute only to the right channel of the digital mic
+ * capture stream.  This is a workaround for avoiding the almost silence
+ * by summing the stereo stream from some (known to be ForteMedia)
+ * digital mic unit.
+ *
+ * The logic is to call alc_inv_dmic_sync() after each action (possibly)
+ * modifying ADC amp.  When the mute flag is set, it mutes the R-channel
+ * without caching so that the cache can still keep the original value.
+ * The cached value is then restored when the flag is set off or any other
+ * than d-mic is used as the current input source.
+ */
+static void alc_inv_dmic_sync(struct hda_codec *codec, bool force)
+{
+	struct alc_spec *spec = codec->spec;
+	int i;
+
+	if (!spec->inv_dmic_fixup)
+		return;
+	if (!spec->inv_dmic_muted && !force)
+		return;
+	for (i = 0; i < spec->num_adc_nids; i++) {
+		int src = spec->dyn_adc_switch ? 0 : i;
+		bool dmic_fixup = false;
+		hda_nid_t nid;
+		int parm, dir, v;
+
+		if (spec->inv_dmic_muted &&
+		    spec->imux_pins[spec->cur_mux[src]] == spec->inv_dmic_pin)
+			dmic_fixup = true;
+		if (!dmic_fixup && !force)
+			continue;
+		if (spec->vol_in_capsrc) {
+			nid = spec->capsrc_nids[i];
+			parm = AC_AMP_SET_RIGHT | AC_AMP_SET_OUTPUT;
+			dir = HDA_OUTPUT;
+		} else {
+			nid = spec->adc_nids[i];
+			parm = AC_AMP_SET_RIGHT | AC_AMP_SET_INPUT;
+			dir = HDA_INPUT;
+		}
+		/* we care only right channel */
+		v = snd_hda_codec_amp_read(codec, nid, 1, dir, 0);
+		if (v & 0x80) /* if already muted, we don't need to touch */
+			continue;
+		if (dmic_fixup) /* add mute for d-mic */
+			v |= 0x80;
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    parm | v);
+	}
+}
+
+static int alc_inv_dmic_sw_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+
+	ucontrol->value.integer.value[0] = !spec->inv_dmic_muted;
+	return 0;
+}
+
+static int alc_inv_dmic_sw_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	unsigned int val = !ucontrol->value.integer.value[0];
+
+	if (val == spec->inv_dmic_muted)
+		return 0;
+	spec->inv_dmic_muted = val;
+	alc_inv_dmic_sync(codec, true);
+	return 0;
+}
+
+static const struct snd_kcontrol_new alc_inv_dmic_sw = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.info = snd_ctl_boolean_mono_info,
+	.get = alc_inv_dmic_sw_get,
+	.put = alc_inv_dmic_sw_put,
+};
+
+static int alc_add_inv_dmic_mixer(struct hda_codec *codec, hda_nid_t nid)
+{
+	struct alc_spec *spec = codec->spec;
+	struct snd_kcontrol_new *knew = alc_kcontrol_new(spec);
+	if (!knew)
+		return -ENOMEM;
+	*knew = alc_inv_dmic_sw;
+	knew->name = kstrdup("Inverted Internal Mic Capture Switch", GFP_KERNEL);
+	if (!knew->name)
+		return -ENOMEM;
+	spec->inv_dmic_fixup = 1;
+	spec->inv_dmic_muted = 0;
+	spec->inv_dmic_pin = nid;
+	return 0;
+}
+
+/* typically the digital mic is put at node 0x12 */
+static void alc_fixup_inv_dmic_0x12(struct hda_codec *codec,
+				    const struct alc_fixup *fix, int action)
+{
+	if (action == ALC_FIXUP_ACT_PROBE)
+		alc_add_inv_dmic_mixer(codec, 0x12);
+}
+
+/*
  * virtual master controls
  */
 
@@ -2289,6 +2406,7 @@ static void alc_free(struct hda_codec *codec)
 	alc_shutup(codec);
 	alc_free_kctls(codec);
 	alc_free_bind_ctls(codec);
+	snd_hda_gen_free(&spec->gen);
 	kfree(spec);
 	snd_hda_detach_beep_device(codec);
 }
@@ -2316,6 +2434,7 @@ static int alc_resume(struct hda_codec *codec)
 	codec->patch_ops.init(codec);
 	snd_hda_codec_resume_amp(codec);
 	snd_hda_codec_resume_cache(codec);
+	alc_inv_dmic_sync(codec, true);
 	hda_call_check_power_status(codec, 0x01);
 	return 0;
 }
@@ -4253,6 +4372,7 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
 		return -ENOMEM;
 	codec->spec = spec;
 	spec->mixer_nid = mixer_nid;
+	snd_hda_gen_init(&spec->gen);
 
 	err = alc_codec_rename_from_preset(codec);
 	if (err < 0) {
@@ -4907,6 +5027,7 @@ enum {
 	ALC889_FIXUP_DAC_ROUTE,
 	ALC889_FIXUP_MBP_VREF,
 	ALC889_FIXUP_IMAC91_VREF,
+	ALC882_FIXUP_INV_DMIC,
 };
 
 static void alc889_fixup_coef(struct hda_codec *codec,
@@ -5210,6 +5331,10 @@ static const struct alc_fixup alc882_fixups[] = {
 		.chained = true,
 		.chain_id = ALC882_FIXUP_GPIO1,
 	},
+	[ALC882_FIXUP_INV_DMIC] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc_fixup_inv_dmic_0x12,
+	},
 };
 
 static const struct snd_pci_quirk alc882_fixup_tbl[] = {
@@ -5284,6 +5409,7 @@ static const struct alc_model_fixup alc882_fixup_models[] = {
 	{.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
 	{.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
 	{.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
+	{.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
 	{}
 };
 
@@ -5371,6 +5497,7 @@ enum {
 	ALC262_FIXUP_LENOVO_3000,
 	ALC262_FIXUP_BENQ,
 	ALC262_FIXUP_BENQ_T31,
+	ALC262_FIXUP_INV_DMIC,
 };
 
 static const struct alc_fixup alc262_fixups[] = {
@@ -5422,6 +5549,10 @@ static const struct alc_fixup alc262_fixups[] = {
 			{}
 		}
 	},
+	[ALC262_FIXUP_INV_DMIC] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc_fixup_inv_dmic_0x12,
+	},
 };
 
 static const struct snd_pci_quirk alc262_fixup_tbl[] = {
@@ -5436,6 +5567,10 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = {
 	{}
 };
 
+static const struct alc_model_fixup alc262_fixup_models[] = {
+	{.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
+	{}
+};
 
 /*
  */
@@ -5464,7 +5599,8 @@ static int patch_alc262(struct hda_codec *codec)
 #endif
 	alc_fix_pll_init(codec, 0x20, 0x0a, 10);
 
-	alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
+	alc_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
+		       alc262_fixups);
 	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
 
 	alc_auto_parse_customize_define(codec);
@@ -5520,6 +5656,22 @@ static const struct hda_verb alc268_beep_init_verbs[] = {
 	{ }
 };
 
+enum {
+	ALC268_FIXUP_INV_DMIC,
+};
+
+static const struct alc_fixup alc268_fixups[] = {
+	[ALC268_FIXUP_INV_DMIC] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc_fixup_inv_dmic_0x12,
+	},
+};
+
+static const struct alc_model_fixup alc268_fixup_models[] = {
+	{.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
+	{}
+};
+
 /*
  * BIOS auto configuration
  */
@@ -5551,6 +5703,9 @@ static int patch_alc268(struct hda_codec *codec)
 
 	spec = codec->spec;
 
+	alc_pick_fixup(codec, alc268_fixup_models, NULL, alc268_fixups);
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+
 	/* automatic parse from the BIOS config */
 	err = alc268_parse_auto_config(codec);
 	if (err < 0)
@@ -5580,6 +5735,8 @@ static int patch_alc268(struct hda_codec *codec)
 	codec->patch_ops = alc_patch_ops;
 	spec->shutup = alc_eapd_shutup;
 
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
+
 	return 0;
 
  error:
@@ -5808,6 +5965,7 @@ static void alc269_fixup_mic2_mute(struct hda_codec *codec,
 	}
 }
 
+
 enum {
 	ALC269_FIXUP_SONY_VAIO,
 	ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -5826,6 +5984,7 @@ enum {
 	ALC269VB_FIXUP_AMIC,
 	ALC269VB_FIXUP_DMIC,
 	ALC269_FIXUP_MIC2_MUTE_LED,
+	ALC269_FIXUP_INV_DMIC,
 };
 
 static const struct alc_fixup alc269_fixups[] = {
@@ -5950,12 +6109,19 @@ static const struct alc_fixup alc269_fixups[] = {
 		.type = ALC_FIXUP_FUNC,
 		.v.func = alc269_fixup_mic2_mute,
 	},
+	[ALC269_FIXUP_INV_DMIC] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc_fixup_inv_dmic_0x12,
+	},
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
+	SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
 	SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED),
 	SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
+	SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
@@ -6031,6 +6197,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 static const struct alc_model_fixup alc269_fixup_models[] = {
 	{.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"},
 	{.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"},
+	{.id = ALC269_FIXUP_STEREO_DMIC, .name = "alc269-dmic"},
+	{.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"},
+	{.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"},
 	{}
 };
 
@@ -6327,12 +6496,6 @@ static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
 	{}
 };
 
-static const struct hda_verb alc660vd_eapd_verbs[] = {
-	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-	{ }
-};
-
 /*
  */
 static int patch_alc861vd(struct hda_codec *codec)
@@ -6354,11 +6517,6 @@ static int patch_alc861vd(struct hda_codec *codec)
 	if (err < 0)
 		goto error;
 
-	if (codec->vendor_id == 0x10ec0660) {
-		/* always turn on EAPD */
-		snd_hda_gen_add_verbs(&spec->gen, alc660vd_eapd_verbs);
-	}
-
 	if (!spec->no_analog) {
 		err = snd_hda_attach_beep_device(codec, 0x23);
 		if (err < 0)
@@ -6441,6 +6599,7 @@ enum {
 	ALC662_FIXUP_ASUS_MODE8,
 	ALC662_FIXUP_NO_JACK_DETECT,
 	ALC662_FIXUP_ZOTAC_Z68,
+	ALC662_FIXUP_INV_DMIC,
 };
 
 static const struct alc_fixup alc662_fixups[] = {
@@ -6597,12 +6756,17 @@ static const struct alc_fixup alc662_fixups[] = {
 			{ }
 		}
 	},
+	[ALC662_FIXUP_INV_DMIC] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc_fixup_inv_dmic_0x12,
+	},
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
 	SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
+	SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
 	SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
 	SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
 	SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
@@ -6683,6 +6847,7 @@ static const struct alc_model_fixup alc662_fixup_models[] = {
 	{.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
 	{.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
 	{.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
+	{.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
 	{}
 };
 
@@ -6705,6 +6870,12 @@ static int patch_alc662(struct hda_codec *codec)
 
 	alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
+	alc_pick_fixup(codec, alc662_fixup_models,
+		       alc662_fixup_tbl, alc662_fixups);
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+
+	alc_auto_parse_customize_define(codec);
+
 	if ((alc_get_coef0(codec) & (1 << 14)) &&
 	    codec->bus->pci->subsystem_vendor == 0x1025 &&
 	    spec->cdefine.platform_type == 1) {
@@ -6712,12 +6883,6 @@ static int patch_alc662(struct hda_codec *codec)
 			goto error;
 	}
 
-	alc_pick_fixup(codec, alc662_fixup_models,
-		       alc662_fixup_tbl, alc662_fixups);
-	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-
-	alc_auto_parse_customize_define(codec);
-
 	/* automatic parse from the BIOS config */
 	err = alc662_parse_auto_config(codec);
 	if (err < 0)
@@ -6800,6 +6965,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
 	{ .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
 	{ .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
 	{ .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
+	{ .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 },
 	{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
 	  .patch = patch_alc861 },
 	{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 7db8228..0767528 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -4367,7 +4367,7 @@ static int stac92xx_init(struct hda_codec *codec)
 					 AC_PINCTL_IN_EN);
 	for (i = 0; i < spec->num_pwrs; i++)  {
 		hda_nid_t nid = spec->pwr_nids[i];
-		int pinctl, def_conf;
+		unsigned int pinctl, def_conf;
 
 		def_conf = snd_hda_codec_get_pincfg(codec, nid);
 		def_conf = get_defcfg_connect(def_conf);
@@ -4376,6 +4376,11 @@ static int stac92xx_init(struct hda_codec *codec)
 			stac_toggle_power_map(codec, nid, 0);
 			continue;
 		}
+		if (def_conf == AC_JACK_PORT_FIXED) {
+			/* no need for jack detection for fixed pins */
+			stac_toggle_power_map(codec, nid, 1);
+			continue;
+		}
 		/* power on when no jack detection is available */
 		/* or when the VREF is used for controlling LED */
 		if (!spec->hp_detect ||
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index deef213..adb3b4c 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -361,74 +361,6 @@ MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)");
 #define DSP2HOST_REQ_I2SRATE    0x02
 #define DSP2HOST_REQ_TIMER      0x04
 
-/* AC97 registers */
-/* XXX fix this crap up */
-/*#define AC97_RESET              0x00*/
-
-#define AC97_VOL_MUTE_B         0x8000
-#define AC97_VOL_M              0x1F
-#define AC97_LEFT_VOL_S         8
-
-#define AC97_MASTER_VOL         0x02
-#define AC97_LINE_LEVEL_VOL     0x04
-#define AC97_MASTER_MONO_VOL    0x06
-#define AC97_PC_BEEP_VOL        0x0A
-#define AC97_PC_BEEP_VOL_M      0x0F
-#define AC97_SROUND_MASTER_VOL  0x38
-#define AC97_PC_BEEP_VOL_S      1
-
-/*#define AC97_PHONE_VOL          0x0C
-#define AC97_MIC_VOL            0x0E*/
-#define AC97_MIC_20DB_ENABLE    0x40
-
-/*#define AC97_LINEIN_VOL         0x10
-#define AC97_CD_VOL             0x12
-#define AC97_VIDEO_VOL          0x14
-#define AC97_AUX_VOL            0x16*/
-#define AC97_PCM_OUT_VOL        0x18
-/*#define AC97_RECORD_SELECT      0x1A*/
-#define AC97_RECORD_MIC         0x00
-#define AC97_RECORD_CD          0x01
-#define AC97_RECORD_VIDEO       0x02
-#define AC97_RECORD_AUX         0x03
-#define AC97_RECORD_MONO_MUX    0x02
-#define AC97_RECORD_DIGITAL     0x03
-#define AC97_RECORD_LINE        0x04
-#define AC97_RECORD_STEREO      0x05
-#define AC97_RECORD_MONO        0x06
-#define AC97_RECORD_PHONE       0x07
-
-/*#define AC97_RECORD_GAIN        0x1C*/
-#define AC97_RECORD_VOL_M       0x0F
-
-/*#define AC97_GENERAL_PURPOSE    0x20*/
-#define AC97_POWER_DOWN_CTRL    0x26
-#define AC97_ADC_READY          0x0001
-#define AC97_DAC_READY          0x0002
-#define AC97_ANALOG_READY       0x0004
-#define AC97_VREF_ON            0x0008
-#define AC97_PR0                0x0100
-#define AC97_PR1                0x0200
-#define AC97_PR2                0x0400
-#define AC97_PR3                0x0800
-#define AC97_PR4                0x1000
-
-#define AC97_RESERVED1          0x28
-
-#define AC97_VENDOR_TEST        0x5A
-
-#define AC97_CLOCK_DELAY        0x5C
-#define AC97_LINEOUT_MUX_SEL    0x0001
-#define AC97_MONO_MUX_SEL       0x0002
-#define AC97_CLOCK_DELAY_SEL    0x1F
-#define AC97_DAC_CDS_SHIFT      6
-#define AC97_ADC_CDS_SHIFT      11
-
-#define AC97_MULTI_CHANNEL_SEL  0x74
-
-/*#define AC97_VENDOR_ID1         0x7C
-#define AC97_VENDOR_ID2         0x7E*/
-
 /*
  * ASSP control regs
  */
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index 0435f45..e3ac1f7 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -1368,6 +1368,67 @@ static void pcxhr_proc_gpo_write(struct snd_info_entry *entry,
 	}
 }
 
+/* Access to the results of the CMD_GET_TIME_CODE RMH */
+#define TIME_CODE_VALID_MASK	0x00800000
+#define TIME_CODE_NEW_MASK	0x00400000
+#define TIME_CODE_BACK_MASK	0x00200000
+#define TIME_CODE_WAIT_MASK	0x00100000
+
+/* Values for the CMD_MANAGE_SIGNAL RMH */
+#define MANAGE_SIGNAL_TIME_CODE	0x01
+#define MANAGE_SIGNAL_MIDI	0x02
+
+/* linear time code read proc*/
+static void pcxhr_proc_ltc(struct snd_info_entry *entry,
+			   struct snd_info_buffer *buffer)
+{
+	struct snd_pcxhr *chip = entry->private_data;
+	struct pcxhr_mgr *mgr = chip->mgr;
+	struct pcxhr_rmh rmh;
+	unsigned int ltcHrs, ltcMin, ltcSec, ltcFrm;
+	int err;
+	/* commands available when embedded DSP is running */
+	if (!(mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX))) {
+		snd_iprintf(buffer, "no firmware loaded\n");
+		return;
+	}
+	if (!mgr->capture_ltc) {
+		pcxhr_init_rmh(&rmh, CMD_MANAGE_SIGNAL);
+		rmh.cmd[0] |= MANAGE_SIGNAL_TIME_CODE;
+		err = pcxhr_send_msg(mgr, &rmh);
+		if (err) {
+			snd_iprintf(buffer, "ltc not activated (%d)\n", err);
+			return;
+		}
+		if (mgr->is_hr_stereo)
+			hr222_manage_timecode(mgr, 1);
+		else
+			pcxhr_write_io_num_reg_cont(mgr, REG_CONT_VALSMPTE,
+						    REG_CONT_VALSMPTE, NULL);
+		mgr->capture_ltc = 1;
+	}
+	pcxhr_init_rmh(&rmh, CMD_GET_TIME_CODE);
+	err = pcxhr_send_msg(mgr, &rmh);
+	if (err) {
+		snd_iprintf(buffer, "ltc read error (err=%d)\n", err);
+		return ;
+	}
+	ltcHrs = 10*((rmh.stat[0] >> 8) & 0x3) + (rmh.stat[0] & 0xf);
+	ltcMin = 10*((rmh.stat[1] >> 16) & 0x7) + ((rmh.stat[1] >> 8) & 0xf);
+	ltcSec = 10*(rmh.stat[1] & 0x7) + ((rmh.stat[2] >> 16) & 0xf);
+	ltcFrm = 10*((rmh.stat[2] >> 8) & 0x3) + (rmh.stat[2] & 0xf);
+
+	snd_iprintf(buffer, "timecode: %02u:%02u:%02u-%02u\n",
+			    ltcHrs, ltcMin, ltcSec, ltcFrm);
+	snd_iprintf(buffer, "raw: 0x%04x%06x%06x\n", rmh.stat[0] & 0x00ffff,
+			    rmh.stat[1] & 0xffffff, rmh.stat[2] & 0xffffff);
+	/*snd_iprintf(buffer, "dsp ref time: 0x%06x%06x\n",
+			    rmh.stat[3] & 0xffffff, rmh.stat[4] & 0xffffff);*/
+	if (!(rmh.stat[0] & TIME_CODE_VALID_MASK)) {
+		snd_iprintf(buffer, "warning: linear timecode not valid\n");
+	}
+}
+
 static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip)
 {
 	struct snd_info_entry *entry;
@@ -1383,6 +1444,8 @@ static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip)
 		entry->c.text.write = pcxhr_proc_gpo_write;
 		entry->mode |= S_IWUSR;
 	}
+	if (!snd_card_proc_new(chip->card, "ltc", &entry))
+		snd_info_set_text_ops(entry, chip, pcxhr_proc_ltc);
 }
 /* end of proc interface */
 
diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h
index bda776c..a4c602c 100644
--- a/sound/pci/pcxhr/pcxhr.h
+++ b/sound/pci/pcxhr/pcxhr.h
@@ -103,6 +103,7 @@ struct pcxhr_mgr {
 	unsigned int board_has_mic:1; /* if 1 the board has microphone input */
 	unsigned int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */
 	unsigned int mono_capture:1; /* if 1 the board does mono capture */
+	unsigned int capture_ltc:1; /* if 1 the board captures LTC input */
 
 	struct snd_dma_buffer hostport;
 
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index 304411c..b33db1e 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -504,6 +504,8 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = {
 [CMD_FORMAT_STREAM_IN] =		{ 0x870000, 0, RMH_SSIZE_FIXED },
 [CMD_STREAM_SAMPLE_COUNT] =		{ 0x902000, 2, RMH_SSIZE_FIXED },
 [CMD_AUDIO_LEVEL_ADJUST] =		{ 0xc22000, 0, RMH_SSIZE_FIXED },
+[CMD_GET_TIME_CODE] =			{ 0x060000, 5, RMH_SSIZE_FIXED },
+[CMD_MANAGE_SIGNAL] =			{ 0x0f0000, 0, RMH_SSIZE_FIXED },
 };
 
 #ifdef CONFIG_SND_DEBUG_VERBOSE
@@ -533,6 +535,8 @@ static char* cmd_names[] = {
 [CMD_FORMAT_STREAM_IN] =		"CMD_FORMAT_STREAM_IN",
 [CMD_STREAM_SAMPLE_COUNT] =		"CMD_STREAM_SAMPLE_COUNT",
 [CMD_AUDIO_LEVEL_ADJUST] =		"CMD_AUDIO_LEVEL_ADJUST",
+[CMD_GET_TIME_CODE] =			"CMD_GET_TIME_CODE",
+[CMD_MANAGE_SIGNAL] =			"CMD_MANAGE_SIGNAL",
 };
 #endif
 
@@ -1133,13 +1137,12 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr,
 	hw_sample_count = ((u_int64_t)rmh.stat[0]) << 24;
 	hw_sample_count += (u_int64_t)rmh.stat[1];
 
-	snd_printdd("stream %c%d : abs samples real(%ld) timer(%ld)\n",
+	snd_printdd("stream %c%d : abs samples real(%llu) timer(%llu)\n",
 		    stream->pipe->is_capture ? 'C' : 'P',
 		    stream->substream->number,
-		    (long unsigned int)hw_sample_count,
-		    (long unsigned int)(stream->timer_abs_periods +
-					stream->timer_period_frag +
-					mgr->granularity));
+		    hw_sample_count,
+		    stream->timer_abs_periods + stream->timer_period_frag +
+						mgr->granularity);
 	return hw_sample_count;
 }
 
@@ -1243,10 +1246,18 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
 
 		if ((dsp_time_diff < 0) &&
 		    (mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) {
-			snd_printdd("ERROR DSP TIME old(%d) new(%d) -> "
-				    "resynchronize all streams\n",
+			/* handle dsp counter wraparound without resync */
+			int tmp_diff = dsp_time_diff + PCXHR_DSP_TIME_MASK + 1;
+			snd_printdd("WARNING DSP timestamp old(%d) new(%d)",
 				    mgr->dsp_time_last, dsp_time_new);
-			mgr->dsp_time_err++;
+			if (tmp_diff > 0 && tmp_diff <= (2*mgr->granularity)) {
+				snd_printdd("-> timestamp wraparound OK: "
+					    "diff=%d\n", tmp_diff);
+				dsp_time_diff = tmp_diff;
+			} else {
+				snd_printdd("-> resynchronize all streams\n");
+				mgr->dsp_time_err++;
+			}
 		}
 #ifdef CONFIG_SND_DEBUG_VERBOSE
 		if (dsp_time_diff == 0)
diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h
index be01737..a81ab6b 100644
--- a/sound/pci/pcxhr/pcxhr_core.h
+++ b/sound/pci/pcxhr/pcxhr_core.h
@@ -79,6 +79,8 @@ enum {
 	CMD_FORMAT_STREAM_IN,		/* cmd_len >= 4	stat_len = 0 */
 	CMD_STREAM_SAMPLE_COUNT,	/* cmd_len = 2	stat_len = (2 * nb_stream) */
 	CMD_AUDIO_LEVEL_ADJUST,		/* cmd_len = 3	stat_len = 0 */
+	CMD_GET_TIME_CODE,		/* cmd_len = 1  stat_len = 5 */
+	CMD_MANAGE_SIGNAL,		/* cmd_len = 1  stat_len = 0 */
 	CMD_LAST_INDEX
 };
 
@@ -116,7 +118,7 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh);
 #define IO_NUM_REG_OUT_ANA_LEVEL	20
 #define IO_NUM_REG_IN_ANA_LEVEL		21
 
-
+#define REG_CONT_VALSMPTE		0x000800
 #define REG_CONT_UNMUTE_INPUTS		0x020000
 
 /* parameters used with register IO_NUM_REG_STATUS */
diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c
index 1cb82c0..84fe576 100644
--- a/sound/pci/pcxhr/pcxhr_mix22.c
+++ b/sound/pci/pcxhr/pcxhr_mix22.c
@@ -53,6 +53,7 @@
 #define PCXHR_DSP_RESET_DSP	0x01
 #define PCXHR_DSP_RESET_MUTE	0x02
 #define PCXHR_DSP_RESET_CODEC	0x08
+#define PCXHR_DSP_RESET_SMPTE	0x10
 #define PCXHR_DSP_RESET_GPO_OFFSET	5
 #define PCXHR_DSP_RESET_GPO_MASK	0x60
 
@@ -527,6 +528,16 @@ int hr222_write_gpo(struct pcxhr_mgr *mgr, int value)
 	return 0;
 }
 
+int hr222_manage_timecode(struct pcxhr_mgr *mgr, int enable)
+{
+	if (enable)
+		mgr->dsp_reset |= PCXHR_DSP_RESET_SMPTE;
+	else
+		mgr->dsp_reset &= ~PCXHR_DSP_RESET_SMPTE;
+
+	PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset);
+	return 0;
+}
 
 int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
 				    int is_capture, int channel)
diff --git a/sound/pci/pcxhr/pcxhr_mix22.h b/sound/pci/pcxhr/pcxhr_mix22.h
index 5a37a00..5971b99 100644
--- a/sound/pci/pcxhr/pcxhr_mix22.h
+++ b/sound/pci/pcxhr/pcxhr_mix22.h
@@ -34,6 +34,7 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr,
 
 int hr222_read_gpio(struct pcxhr_mgr *mgr, int is_gpi, int *value);
 int hr222_write_gpo(struct pcxhr_mgr *mgr, int value);
+int hr222_manage_timecode(struct pcxhr_mgr *mgr, int enable);
 
 #define HR222_LINE_PLAYBACK_LEVEL_MIN		0	/* -25.5 dB */
 #define HR222_LINE_PLAYBACK_ZERO_LEVEL		51	/* 0.0 dB */
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 40b2ad1..c5de0a8 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -33,6 +33,7 @@ source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/blackfin/Kconfig"
 source "sound/soc/davinci/Kconfig"
+source "sound/soc/dwc/Kconfig"
 source "sound/soc/ep93xx/Kconfig"
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/jz4740/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 70990f4..00a555a 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_SND_SOC)	+= atmel/
 obj-$(CONFIG_SND_SOC)	+= au1x/
 obj-$(CONFIG_SND_SOC)	+= blackfin/
 obj-$(CONFIG_SND_SOC)	+= davinci/
+obj-$(CONFIG_SND_SOC)	+= dwc/
 obj-$(CONFIG_SND_SOC)	+= ep93xx/
 obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)	+= jz4740/
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index 9f6bc55..16b88f5 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -1,7 +1,8 @@
 config SND_BF5XX_I2S
-	tristate "SoC I2S Audio for the ADI BF5xx chip"
+	tristate "SoC I2S Audio for the ADI Blackfin chip"
 	depends on BLACKFIN
-	select SND_BF5XX_SOC_SPORT
+	select SND_BF5XX_SOC_SPORT if !BF60x
+	select SND_BF6XX_SOC_SPORT if BF60x
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the Blackfin SPORT (synchronous serial ports) interface in I2S
@@ -9,12 +10,14 @@ config SND_BF5XX_I2S
 	  You will also need to select the audio interfaces to support below.
 
 config SND_BF5XX_SOC_SSM2602
-	tristate "SoC SSM2602 Audio support for BF52x ezkit"
+	tristate "SoC SSM2602 Audio Codec Add-On Card support"
 	depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
-	select SND_BF5XX_SOC_I2S
+	select SND_BF5XX_SOC_I2S if !BF60x
+	select SND_BF6XX_SOC_I2S if BF60x
 	select SND_SOC_SSM2602
 	help
-	  Say Y if you want to add support for SoC audio on BF527-EZKIT.
+	  Say Y if you want to add support for the Analog Devices
+	  SSM2602 Audio Codec Add-On Card.
 
 config SND_SOC_BFIN_EVAL_ADAU1701
 	tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards"
@@ -162,9 +165,15 @@ config SND_BF5XX_SOC_AD1980
 config SND_BF5XX_SOC_SPORT
 	tristate
 
+config SND_BF6XX_SOC_SPORT
+	tristate
+
 config SND_BF5XX_SOC_I2S
 	tristate
 
+config SND_BF6XX_SOC_I2S
+	tristate
+
 config SND_BF5XX_SOC_TDM
 	tristate
 
@@ -173,7 +182,7 @@ config SND_BF5XX_SOC_AC97
 
 config SND_BF5XX_SPORT_NUM
 	int "Set a SPORT for Sound chip"
-	depends on (SND_BF5XX_I2S || SND_BF5XX_AC97 || SND_BF5XX_TDM)
+	depends on (SND_BF5XX_SOC_SPORT || SND_BF6XX_SOC_SPORT)
 	range 0 3 if BF54x
 	range 0 1 if !BF54x
 	default 0
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile
index 1bf86cc..6fea1f4 100644
--- a/sound/soc/blackfin/Makefile
+++ b/sound/soc/blackfin/Makefile
@@ -3,16 +3,20 @@ snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
 snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
 snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o
 snd-soc-bf5xx-sport-objs := bf5xx-sport.o
+snd-soc-bf6xx-sport-objs := bf6xx-sport.o
 snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
 snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
+snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o
 snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o
 
 obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
 obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
 obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o
 obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
+obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o
 obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
 obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
+obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o
 obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o
 
 # Blackfin Machine Support
diff --git a/sound/soc/blackfin/bf6xx-i2s.c b/sound/soc/blackfin/bf6xx-i2s.c
new file mode 100644
index 0000000..c3c2466
--- /dev/null
+++ b/sound/soc/blackfin/bf6xx-i2s.c
@@ -0,0 +1,234 @@
+/*
+ * bf6xx-i2s.c - Analog Devices BF6XX i2s interface driver
+ *
+ * Copyright (c) 2012 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "bf6xx-sport.h"
+
+struct sport_params param;
+
+static int bfin_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+		unsigned int fmt)
+{
+	struct sport_device *sport = snd_soc_dai_get_drvdata(cpu_dai);
+	struct device *dev = &sport->pdev->dev;
+	int ret = 0;
+
+	param.spctl &= ~(SPORT_CTL_OPMODE | SPORT_CTL_CKRE | SPORT_CTL_FSR
+			| SPORT_CTL_LFS | SPORT_CTL_LAFS);
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_CKRE
+			| SPORT_CTL_LFS;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		param.spctl |= SPORT_CTL_FSR;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_LFS
+			| SPORT_CTL_LAFS;
+		break;
+	default:
+		dev_err(dev, "%s: Unknown DAI format type\n", __func__);
+		ret = -EINVAL;
+		break;
+	}
+
+	param.spctl &= ~(SPORT_CTL_ICLK | SPORT_CTL_IFS);
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	case SND_SOC_DAIFMT_CBS_CFM:
+		ret = -EINVAL;
+		break;
+	default:
+		dev_err(dev, "%s: Unknown DAI master type\n", __func__);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int bfin_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
+	struct device *dev = &sport->pdev->dev;
+	int ret = 0;
+
+	param.spctl &= ~SPORT_CTL_SLEN;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		param.spctl |= 0x70;
+		sport->wdsize = 1;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		param.spctl |= 0xf0;
+		sport->wdsize = 2;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		param.spctl |= 0x170;
+		sport->wdsize = 3;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		param.spctl |= 0x1f0;
+		sport->wdsize = 4;
+		break;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = sport_set_tx_params(sport, &param);
+		if (ret) {
+			dev_err(dev, "SPORT tx is busy!\n");
+			return ret;
+		}
+	} else {
+		ret = sport_set_rx_params(sport, &param);
+		if (ret) {
+			dev_err(dev, "SPORT rx is busy!\n");
+			return ret;
+		}
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_i2s_suspend(struct snd_soc_dai *dai)
+{
+	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
+
+	if (dai->capture_active)
+		sport_rx_stop(sport);
+	if (dai->playback_active)
+		sport_tx_stop(sport);
+	return 0;
+}
+
+static int bfin_i2s_resume(struct snd_soc_dai *dai)
+{
+	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
+	struct device *dev = &sport->pdev->dev;
+	int ret;
+
+	ret = sport_set_tx_params(sport, &param);
+	if (ret) {
+		dev_err(dev, "SPORT tx is busy!\n");
+		return ret;
+	}
+	ret = sport_set_rx_params(sport, &param);
+	if (ret) {
+		dev_err(dev, "SPORT rx is busy!\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+#else
+#define bfin_i2s_suspend NULL
+#define bfin_i2s_resume NULL
+#endif
+
+#define BFIN_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+		SNDRV_PCM_RATE_96000)
+
+#define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops bfin_i2s_dai_ops = {
+	.hw_params	= bfin_i2s_hw_params,
+	.set_fmt	= bfin_i2s_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver bfin_i2s_dai = {
+	.suspend = bfin_i2s_suspend,
+	.resume = bfin_i2s_resume,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = BFIN_I2S_RATES,
+		.formats = BFIN_I2S_FORMATS,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = BFIN_I2S_RATES,
+		.formats = BFIN_I2S_FORMATS,
+	},
+	.ops = &bfin_i2s_dai_ops,
+};
+
+static int __devinit bfin_i2s_probe(struct platform_device *pdev)
+{
+	struct sport_device *sport;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	sport = sport_create(pdev);
+	if (!sport)
+		return -ENODEV;
+
+	/* register with the ASoC layers */
+	ret = snd_soc_register_dai(dev, &bfin_i2s_dai);
+	if (ret) {
+		dev_err(dev, "Failed to register DAI: %d\n", ret);
+		sport_delete(sport);
+		return ret;
+	}
+	platform_set_drvdata(pdev, sport);
+
+	return 0;
+}
+
+static int __devexit bfin_i2s_remove(struct platform_device *pdev)
+{
+	struct sport_device *sport = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+	sport_delete(sport);
+
+	return 0;
+}
+
+static struct platform_driver bfin_i2s_driver = {
+	.probe  = bfin_i2s_probe,
+	.remove = __devexit_p(bfin_i2s_remove),
+	.driver = {
+		.name = "bfin-i2s",
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(bfin_i2s_driver);
+
+MODULE_DESCRIPTION("Analog Devices BF6XX i2s interface driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/blackfin/bf6xx-sport.c b/sound/soc/blackfin/bf6xx-sport.c
new file mode 100644
index 0000000..318c5ba
--- /dev/null
+++ b/sound/soc/blackfin/bf6xx-sport.c
@@ -0,0 +1,422 @@
+/*
+ * bf6xx_sport.c Analog Devices BF6XX SPORT driver
+ *
+ * Copyright (c) 2012 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <asm/blackfin.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#include "bf6xx-sport.h"
+
+int sport_set_tx_params(struct sport_device *sport,
+			struct sport_params *params)
+{
+	if (sport->tx_regs->spctl & SPORT_CTL_SPENPRI)
+		return -EBUSY;
+	sport->tx_regs->spctl = params->spctl | SPORT_CTL_SPTRAN;
+	sport->tx_regs->div = params->div;
+	SSYNC();
+	return 0;
+}
+EXPORT_SYMBOL(sport_set_tx_params);
+
+int sport_set_rx_params(struct sport_device *sport,
+			struct sport_params *params)
+{
+	if (sport->rx_regs->spctl & SPORT_CTL_SPENPRI)
+		return -EBUSY;
+	sport->rx_regs->spctl = params->spctl & ~SPORT_CTL_SPTRAN;
+	sport->rx_regs->div = params->div;
+	SSYNC();
+	return 0;
+}
+EXPORT_SYMBOL(sport_set_rx_params);
+
+static int compute_wdsize(size_t wdsize)
+{
+	switch (wdsize) {
+	case 1:
+		return WDSIZE_8 | PSIZE_8;
+	case 2:
+		return WDSIZE_16 | PSIZE_16;
+	default:
+		return WDSIZE_32 | PSIZE_32;
+	}
+}
+
+void sport_tx_start(struct sport_device *sport)
+{
+	set_dma_next_desc_addr(sport->tx_dma_chan, sport->tx_desc);
+	set_dma_config(sport->tx_dma_chan, DMAFLOW_LIST | DI_EN
+			| compute_wdsize(sport->wdsize) | NDSIZE_6);
+	enable_dma(sport->tx_dma_chan);
+	sport->tx_regs->spctl |= SPORT_CTL_SPENPRI;
+	SSYNC();
+}
+EXPORT_SYMBOL(sport_tx_start);
+
+void sport_rx_start(struct sport_device *sport)
+{
+	set_dma_next_desc_addr(sport->rx_dma_chan, sport->rx_desc);
+	set_dma_config(sport->rx_dma_chan, DMAFLOW_LIST | DI_EN | WNR
+			| compute_wdsize(sport->wdsize) | NDSIZE_6);
+	enable_dma(sport->rx_dma_chan);
+	sport->rx_regs->spctl |= SPORT_CTL_SPENPRI;
+	SSYNC();
+}
+EXPORT_SYMBOL(sport_rx_start);
+
+void sport_tx_stop(struct sport_device *sport)
+{
+	sport->tx_regs->spctl &= ~SPORT_CTL_SPENPRI;
+	SSYNC();
+	disable_dma(sport->tx_dma_chan);
+}
+EXPORT_SYMBOL(sport_tx_stop);
+
+void sport_rx_stop(struct sport_device *sport)
+{
+	sport->rx_regs->spctl &= ~SPORT_CTL_SPENPRI;
+	SSYNC();
+	disable_dma(sport->rx_dma_chan);
+}
+EXPORT_SYMBOL(sport_rx_stop);
+
+void sport_set_tx_callback(struct sport_device *sport,
+		void (*tx_callback)(void *), void *tx_data)
+{
+	sport->tx_callback = tx_callback;
+	sport->tx_data = tx_data;
+}
+EXPORT_SYMBOL(sport_set_tx_callback);
+
+void sport_set_rx_callback(struct sport_device *sport,
+		void (*rx_callback)(void *), void *rx_data)
+{
+	sport->rx_callback = rx_callback;
+	sport->rx_data = rx_data;
+}
+EXPORT_SYMBOL(sport_set_rx_callback);
+
+static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
+		size_t fragsize, unsigned int cfg,
+		unsigned int count, size_t wdsize)
+{
+
+	int i;
+
+	for (i = 0; i < fragcount; ++i) {
+		desc[i].next_desc_addr  = &(desc[i + 1]);
+		desc[i].start_addr = (unsigned long)buf + i*fragsize;
+		desc[i].cfg = cfg;
+		desc[i].x_count = count;
+		desc[i].x_modify = wdsize;
+		desc[i].y_count = 0;
+		desc[i].y_modify = 0;
+	}
+
+	/* make circular */
+	desc[fragcount-1].next_desc_addr = desc;
+}
+
+int sport_config_tx_dma(struct sport_device *sport, void *buf,
+		int fragcount, size_t fragsize)
+{
+	unsigned int count;
+	unsigned int cfg;
+	dma_addr_t addr;
+
+	count = fragsize/sport->wdsize;
+
+	if (sport->tx_desc)
+		dma_free_coherent(NULL, sport->tx_desc_size,
+				sport->tx_desc, 0);
+
+	sport->tx_desc = dma_alloc_coherent(NULL,
+			fragcount * sizeof(struct dmasg), &addr, 0);
+	sport->tx_desc_size = fragcount * sizeof(struct dmasg);
+	if (!sport->tx_desc)
+		return -ENOMEM;
+
+	sport->tx_buf = buf;
+	sport->tx_fragsize = fragsize;
+	sport->tx_frags = fragcount;
+	cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize) | NDSIZE_6;
+
+	setup_desc(sport->tx_desc, buf, fragcount, fragsize,
+			cfg|DMAEN, count, sport->wdsize);
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_config_tx_dma);
+
+int sport_config_rx_dma(struct sport_device *sport, void *buf,
+		int fragcount, size_t fragsize)
+{
+	unsigned int count;
+	unsigned int cfg;
+	dma_addr_t addr;
+
+	count = fragsize/sport->wdsize;
+
+	if (sport->rx_desc)
+		dma_free_coherent(NULL, sport->rx_desc_size,
+				sport->rx_desc, 0);
+
+	sport->rx_desc = dma_alloc_coherent(NULL,
+			fragcount * sizeof(struct dmasg), &addr, 0);
+	sport->rx_desc_size = fragcount * sizeof(struct dmasg);
+	if (!sport->rx_desc)
+		return -ENOMEM;
+
+	sport->rx_buf = buf;
+	sport->rx_fragsize = fragsize;
+	sport->rx_frags = fragcount;
+	cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize)
+		| WNR | NDSIZE_6;
+
+	setup_desc(sport->rx_desc, buf, fragcount, fragsize,
+			cfg|DMAEN, count, sport->wdsize);
+
+	return 0;
+}
+EXPORT_SYMBOL(sport_config_rx_dma);
+
+unsigned long sport_curr_offset_tx(struct sport_device *sport)
+{
+	unsigned long curr = get_dma_curr_addr(sport->tx_dma_chan);
+
+	return (unsigned char *)curr - sport->tx_buf;
+}
+EXPORT_SYMBOL(sport_curr_offset_tx);
+
+unsigned long sport_curr_offset_rx(struct sport_device *sport)
+{
+	unsigned long curr = get_dma_curr_addr(sport->rx_dma_chan);
+
+	return (unsigned char *)curr - sport->rx_buf;
+}
+EXPORT_SYMBOL(sport_curr_offset_rx);
+
+static irqreturn_t sport_tx_irq(int irq, void *dev_id)
+{
+	struct sport_device *sport = dev_id;
+	static unsigned long status;
+
+	status = get_dma_curr_irqstat(sport->tx_dma_chan);
+	if (status & (DMA_DONE|DMA_ERR)) {
+		clear_dma_irqstat(sport->tx_dma_chan);
+		SSYNC();
+	}
+	if (sport->tx_callback)
+		sport->tx_callback(sport->tx_data);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_rx_irq(int irq, void *dev_id)
+{
+	struct sport_device *sport = dev_id;
+	unsigned long status;
+
+	status = get_dma_curr_irqstat(sport->rx_dma_chan);
+	if (status & (DMA_DONE|DMA_ERR)) {
+		clear_dma_irqstat(sport->rx_dma_chan);
+		SSYNC();
+	}
+	if (sport->rx_callback)
+		sport->rx_callback(sport->rx_data);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_err_irq(int irq, void *dev_id)
+{
+	struct sport_device *sport = dev_id;
+	struct device *dev = &sport->pdev->dev;
+
+	if (sport->tx_regs->spctl & SPORT_CTL_DERRPRI)
+		dev_err(dev, "sport error: TUVF\n");
+	if (sport->rx_regs->spctl & SPORT_CTL_DERRPRI)
+		dev_err(dev, "sport error: ROVF\n");
+
+	return IRQ_HANDLED;
+}
+
+static int sport_get_resource(struct sport_device *sport)
+{
+	struct platform_device *pdev = sport->pdev;
+	struct device *dev = &pdev->dev;
+	struct bfin_snd_platform_data *pdata = dev->platform_data;
+	struct resource *res;
+
+	if (!pdata) {
+		dev_err(dev, "No platform data\n");
+		return -ENODEV;
+	}
+	sport->pin_req = pdata->pin_req;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "No tx MEM resource\n");
+		return -ENODEV;
+	}
+	sport->tx_regs = (struct sport_register *)res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(dev, "No rx MEM resource\n");
+		return -ENODEV;
+	}
+	sport->rx_regs = (struct sport_register *)res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!res) {
+		dev_err(dev, "No tx DMA resource\n");
+		return -ENODEV;
+	}
+	sport->tx_dma_chan = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!res) {
+		dev_err(dev, "No rx DMA resource\n");
+		return -ENODEV;
+	}
+	sport->rx_dma_chan = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(dev, "No tx error irq resource\n");
+		return -ENODEV;
+	}
+	sport->tx_err_irq = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+	if (!res) {
+		dev_err(dev, "No rx error irq resource\n");
+		return -ENODEV;
+	}
+	sport->rx_err_irq = res->start;
+
+	return 0;
+}
+
+static int sport_request_resource(struct sport_device *sport)
+{
+	struct device *dev = &sport->pdev->dev;
+	int ret;
+
+	ret = peripheral_request_list(sport->pin_req, "soc-audio");
+	if (ret) {
+		dev_err(dev, "Unable to request sport pin\n");
+		return ret;
+	}
+
+	ret = request_dma(sport->tx_dma_chan, "SPORT TX Data");
+	if (ret) {
+		dev_err(dev, "Unable to allocate DMA channel for sport tx\n");
+		goto err_tx_dma;
+	}
+	set_dma_callback(sport->tx_dma_chan, sport_tx_irq, sport);
+
+	ret = request_dma(sport->rx_dma_chan, "SPORT RX Data");
+	if (ret) {
+		dev_err(dev, "Unable to allocate DMA channel for sport rx\n");
+		goto err_rx_dma;
+	}
+	set_dma_callback(sport->rx_dma_chan, sport_rx_irq, sport);
+
+	ret = request_irq(sport->tx_err_irq, sport_err_irq,
+			0, "SPORT TX ERROR", sport);
+	if (ret) {
+		dev_err(dev, "Unable to allocate tx error IRQ for sport\n");
+		goto err_tx_irq;
+	}
+
+	ret = request_irq(sport->rx_err_irq, sport_err_irq,
+			0, "SPORT RX ERROR", sport);
+	if (ret) {
+		dev_err(dev, "Unable to allocate rx error IRQ for sport\n");
+		goto err_rx_irq;
+	}
+
+	return 0;
+err_rx_irq:
+	free_irq(sport->tx_err_irq, sport);
+err_tx_irq:
+	free_dma(sport->rx_dma_chan);
+err_rx_dma:
+	free_dma(sport->tx_dma_chan);
+err_tx_dma:
+	peripheral_free_list(sport->pin_req);
+	return ret;
+}
+
+static void sport_free_resource(struct sport_device *sport)
+{
+	free_irq(sport->rx_err_irq, sport);
+	free_irq(sport->tx_err_irq, sport);
+	free_dma(sport->rx_dma_chan);
+	free_dma(sport->tx_dma_chan);
+	peripheral_free_list(sport->pin_req);
+}
+
+struct sport_device *sport_create(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sport_device *sport;
+	int ret;
+
+	sport = kzalloc(sizeof(*sport), GFP_KERNEL);
+	if (!sport) {
+		dev_err(dev, "Unable to allocate memory for sport device\n");
+		return NULL;
+	}
+	sport->pdev = pdev;
+
+	ret = sport_get_resource(sport);
+	if (ret) {
+		kfree(sport);
+		return NULL;
+	}
+
+	ret = sport_request_resource(sport);
+	if (ret) {
+		kfree(sport);
+		return NULL;
+	}
+
+	dev_dbg(dev, "SPORT create success\n");
+	return sport;
+}
+EXPORT_SYMBOL(sport_create);
+
+void sport_delete(struct sport_device *sport)
+{
+	sport_free_resource(sport);
+}
+EXPORT_SYMBOL(sport_delete);
+
+MODULE_DESCRIPTION("Analog Devices BF6XX SPORT driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/blackfin/bf6xx-sport.h b/sound/soc/blackfin/bf6xx-sport.h
new file mode 100644
index 0000000..307d193
--- /dev/null
+++ b/sound/soc/blackfin/bf6xx-sport.h
@@ -0,0 +1,82 @@
+/*
+ * bf6xx_sport - Analog Devices BF6XX SPORT driver
+ *
+ * Copyright (c) 2012 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _BF6XX_SPORT_H_
+#define _BF6XX_SPORT_H_
+
+#include <linux/platform_device.h>
+#include <asm/bfin_sport3.h>
+
+struct sport_device {
+	struct platform_device *pdev;
+	const unsigned short *pin_req;
+	struct sport_register *tx_regs;
+	struct sport_register *rx_regs;
+	int tx_dma_chan;
+	int rx_dma_chan;
+	int tx_err_irq;
+	int rx_err_irq;
+
+	void (*tx_callback)(void *data);
+	void *tx_data;
+	void (*rx_callback)(void *data);
+	void *rx_data;
+
+	struct dmasg *tx_desc;
+	struct dmasg *rx_desc;
+	unsigned int tx_desc_size;
+	unsigned int rx_desc_size;
+	unsigned char *tx_buf;
+	unsigned char *rx_buf;
+	unsigned int tx_fragsize;
+	unsigned int rx_fragsize;
+	unsigned int tx_frags;
+	unsigned int rx_frags;
+	unsigned int wdsize;
+};
+
+struct sport_params {
+	u32 spctl;
+	u32 div;
+};
+
+struct sport_device *sport_create(struct platform_device *pdev);
+void sport_delete(struct sport_device *sport);
+int sport_set_tx_params(struct sport_device *sport,
+		struct sport_params *params);
+int sport_set_rx_params(struct sport_device *sport,
+		struct sport_params *params);
+void sport_tx_start(struct sport_device *sport);
+void sport_rx_start(struct sport_device *sport);
+void sport_tx_stop(struct sport_device *sport);
+void sport_rx_stop(struct sport_device *sport);
+void sport_set_tx_callback(struct sport_device *sport,
+	void (*tx_callback)(void *), void *tx_data);
+void sport_set_rx_callback(struct sport_device *sport,
+	void (*rx_callback)(void *), void *rx_data);
+int sport_config_tx_dma(struct sport_device *sport, void *buf,
+	int fragcount, size_t fragsize);
+int sport_config_rx_dma(struct sport_device *sport, void *buf,
+	int fragcount, size_t fragsize);
+unsigned long sport_curr_offset_tx(struct sport_device *sport);
+unsigned long sport_curr_offset_rx(struct sport_device *sport);
+
+
+
+#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 1e1613a..1de24cc 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -12,6 +12,7 @@ config SND_SOC_ALL_CODECS
 	tristate "Build all ASoC CODEC drivers"
 	select SND_SOC_88PM860X if MFD_88PM860X
 	select SND_SOC_L3
+	select SND_SOC_AB8500_CODEC if ABX500_CORE
 	select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
 	select SND_SOC_AD1836 if SPI_MASTER
 	select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
@@ -35,7 +36,9 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_CX20442
 	select SND_SOC_DA7210 if I2C
+	select SND_SOC_DA732X if I2C
 	select SND_SOC_DFBMCS320
+	select SND_SOC_ISABELLE if I2C
 	select SND_SOC_JZ4740_CODEC
 	select SND_SOC_LM4857 if I2C
 	select SND_SOC_LM49453 if I2C
@@ -70,6 +73,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_WM2000 if I2C
 	select SND_SOC_WM2200 if I2C
 	select SND_SOC_WM5100 if I2C
+	select SND_SOC_WM5102 if MFD_WM5102
 	select SND_SOC_WM8350 if MFD_WM8350
 	select SND_SOC_WM8400 if MFD_WM8400
 	select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
@@ -126,11 +130,19 @@ config SND_SOC_ALL_CODECS
 config SND_SOC_88PM860X
 	tristate
 
+config SND_SOC_ARIZONA
+	tristate
+	default y if SND_SOC_WM5102=y
+	default m if SND_SOC_WM5102=m
+
 config SND_SOC_WM_HUBS
 	tristate
 	default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
 	default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
 
+config SND_SOC_AB8500_CODEC
+	tristate
+
 config SND_SOC_AC97_CODEC
 	tristate
 	select SND_AC97_CODEC
@@ -219,12 +231,18 @@ config SND_SOC_L3
 config SND_SOC_DA7210
         tristate
 
+config SND_SOC_DA732X
+        tristate
+
 config SND_SOC_DFBMCS320
 	tristate
 
 config SND_SOC_DMIC
 	tristate
 
+config SND_SOC_ISABELLE
+        tristate
+
 config SND_SOC_LM49453
 	tristate
 
@@ -313,6 +331,9 @@ config SND_SOC_WM2200
 config SND_SOC_WM5100
 	tristate
 
+config SND_SOC_WM5102
+	tristate
+
 config SND_SOC_WM8350
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index fc27fec..d35ba7f 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,4 +1,5 @@
 snd-soc-88pm860x-objs := 88pm860x-codec.o
+snd-soc-ab8500-codec-objs := ab8500-codec.o
 snd-soc-ac97-objs := ac97.o
 snd-soc-ad1836-objs := ad1836.o
 snd-soc-ad193x-objs := ad193x.o
@@ -13,6 +14,7 @@ snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
+snd-soc-arizona-objs := arizona.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cs42l51-objs := cs42l51.o
 snd-soc-cs42l52-objs := cs42l52.o
@@ -21,8 +23,10 @@ snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4271-objs := cs4271.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
+snd-soc-da732x-objs := da732x.o
 snd-soc-dfbmcs320-objs := dfbmcs320.o
 snd-soc-dmic-objs := dmic.o
+snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
 snd-soc-lm4857-objs := lm4857.o
@@ -59,6 +63,7 @@ snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm2000-objs := wm2000.o
 snd-soc-wm2200-objs := wm2200.o
 snd-soc-wm5100-objs := wm5100.o wm5100-tables.o
+snd-soc-wm5102-objs := wm5102.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8510-objs := wm8510.o
@@ -108,6 +113,7 @@ snd-soc-max9877-objs := max9877.o
 snd-soc-tpa6130a2-objs := tpa6130a2.o
 
 obj-$(CONFIG_SND_SOC_88PM860X)	+= snd-soc-88pm860x.o
+obj-$(CONFIG_SND_SOC_AB8500_CODEC)	+= snd-soc-ab8500-codec.o
 obj-$(CONFIG_SND_SOC_AC97_CODEC)	+= snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1836)	+= snd-soc-ad1836.o
 obj-$(CONFIG_SND_SOC_AD193X)	+= snd-soc-ad193x.o
@@ -124,6 +130,7 @@ obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5632)	+= snd-soc-alc5632.o
+obj-$(CONFIG_SND_SOC_ARIZONA)	+= snd-soc-arizona.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
 obj-$(CONFIG_SND_SOC_CS42L51)	+= snd-soc-cs42l51.o
 obj-$(CONFIG_SND_SOC_CS42L52)	+= snd-soc-cs42l52.o
@@ -132,8 +139,10 @@ obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4271)	+= snd-soc-cs4271.o
 obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
+obj-$(CONFIG_SND_SOC_DA732X)	+= snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DFBMCS320)	+= snd-soc-dfbmcs320.o
 obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_ISABELLE)	+= snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_LM4857)	+= snd-soc-lm4857.o
@@ -168,6 +177,7 @@ obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
 obj-$(CONFIG_SND_SOC_WM2000)	+= snd-soc-wm2000.o
 obj-$(CONFIG_SND_SOC_WM2200)	+= snd-soc-wm2200.o
 obj-$(CONFIG_SND_SOC_WM5100)	+= snd-soc-wm5100.o
+obj-$(CONFIG_SND_SOC_WM5102)	+= snd-soc-wm5102.o
 obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8400)	+= snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8510)	+= snd-soc-wm8510.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
new file mode 100644
index 0000000..3c79592
--- /dev/null
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -0,0 +1,2522 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>,
+ *         for ST-Ericsson.
+ *
+ *         Based on the early work done by:
+ *         Mikko J. Lehto <mikko.lehto@symbio.com>,
+ *         Mikko Sarmanne <mikko.sarmanne@symbio.com>,
+ *         Jarmo K. Kuronen <jarmo.kuronen@symbio.com>,
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500-sysctrl.h>
+#include <linux/mfd/abx500/ab8500-codec.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "ab8500-codec.h"
+
+/* Macrocell value definitions */
+#define CLK_32K_OUT2_DISABLE			0x01
+#define INACTIVE_RESET_AUDIO			0x02
+#define ENABLE_AUDIO_CLK_TO_AUDIO_BLK		0x10
+#define ENABLE_VINTCORE12_SUPPLY		0x04
+#define GPIO27_DIR_OUTPUT			0x04
+#define GPIO29_DIR_OUTPUT			0x10
+#define GPIO31_DIR_OUTPUT			0x40
+
+/* Macrocell register definitions */
+#define AB8500_CTRL3_REG			0x0200
+#define AB8500_GPIO_DIR4_REG			0x1013
+
+/* Nr of FIR/IIR-coeff banks in ANC-block */
+#define AB8500_NR_OF_ANC_COEFF_BANKS		2
+
+/* Minimum duration to keep ANC IIR Init bit high or
+low before proceeding with the configuration sequence */
+#define AB8500_ANC_SM_DELAY			2000
+
+#define AB8500_FILTER_CONTROL(xname, xcount, xmin, xmax) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.info = filter_control_info, \
+	.get = filter_control_get, .put = filter_control_put, \
+	.private_value = (unsigned long)&(struct filter_control) \
+		{.count = xcount, .min = xmin, .max = xmax} }
+
+struct filter_control {
+	long min, max;
+	unsigned int count;
+	long value[128];
+};
+
+/* Sidetone states */
+static const char * const enum_sid_state[] = {
+	"Unconfigured",
+	"Apply FIR",
+	"FIR is configured",
+};
+enum sid_state {
+	SID_UNCONFIGURED = 0,
+	SID_APPLY_FIR = 1,
+	SID_FIR_CONFIGURED = 2,
+};
+
+static const char * const enum_anc_state[] = {
+	"Unconfigured",
+	"Apply FIR and IIR",
+	"FIR and IIR are configured",
+	"Apply FIR",
+	"FIR is configured",
+	"Apply IIR",
+	"IIR is configured"
+};
+enum anc_state {
+	ANC_UNCONFIGURED = 0,
+	ANC_APPLY_FIR_IIR = 1,
+	ANC_FIR_IIR_CONFIGURED = 2,
+	ANC_APPLY_FIR = 3,
+	ANC_FIR_CONFIGURED = 4,
+	ANC_APPLY_IIR = 5,
+	ANC_IIR_CONFIGURED = 6
+};
+
+/* Analog microphones */
+enum amic_idx {
+	AMIC_IDX_1A,
+	AMIC_IDX_1B,
+	AMIC_IDX_2
+};
+
+struct ab8500_codec_drvdata_dbg {
+	struct regulator *vaud;
+	struct regulator *vamic1;
+	struct regulator *vamic2;
+	struct regulator *vdmic;
+};
+
+/* Private data for AB8500 device-driver */
+struct ab8500_codec_drvdata {
+	/* Sidetone */
+	long *sid_fir_values;
+	enum sid_state sid_status;
+
+	/* ANC */
+	struct mutex anc_lock;
+	long *anc_fir_values;
+	long *anc_iir_values;
+	enum anc_state anc_status;
+};
+
+static inline const char *amic_micbias_str(enum amic_micbias micbias)
+{
+	switch (micbias) {
+	case AMIC_MICBIAS_VAMIC1:
+		return "VAMIC1";
+	case AMIC_MICBIAS_VAMIC2:
+		return "VAMIC2";
+	default:
+		return "Unknown";
+	}
+}
+
+static inline const char *amic_type_str(enum amic_type type)
+{
+	switch (type) {
+	case AMIC_TYPE_DIFFERENTIAL:
+		return "DIFFERENTIAL";
+	case AMIC_TYPE_SINGLE_ENDED:
+		return "SINGLE ENDED";
+	default:
+		return "Unknown";
+	}
+}
+
+/*
+ * Read'n'write functions
+ */
+
+/* Read a register from the audio-bank of AB8500 */
+static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec,
+					unsigned int reg)
+{
+	int status;
+	unsigned int value = 0;
+
+	u8 value8;
+	status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO,
+						reg, &value8);
+	if (status < 0) {
+		dev_err(codec->dev,
+			"%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n",
+			__func__, (u8)AB8500_AUDIO, (u8)reg, status);
+	} else {
+		dev_dbg(codec->dev,
+			"%s: Read 0x%02x from register 0x%02x:0x%02x\n",
+			__func__, value8, (u8)AB8500_AUDIO, (u8)reg);
+		value = (unsigned int)value8;
+	}
+
+	return value;
+}
+
+/* Write to a register in the audio-bank of AB8500 */
+static int ab8500_codec_write_reg(struct snd_soc_codec *codec,
+				unsigned int reg, unsigned int value)
+{
+	int status;
+
+	status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO,
+						reg, value);
+	if (status < 0)
+		dev_err(codec->dev,
+			"%s: ERROR: Register (%02x:%02x) write failed (%d).\n",
+			__func__, (u8)AB8500_AUDIO, (u8)reg, status);
+	else
+		dev_dbg(codec->dev,
+			"%s: Wrote 0x%02x into register %02x:%02x\n",
+			__func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg);
+
+	return status;
+}
+
+/*
+ * Controls - DAPM
+ */
+
+/* Earpiece */
+
+/* Earpiece source selector */
+static const char * const enum_ear_lineout_source[] = {"Headset Left",
+						"Speaker Left"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ear_lineout_source, AB8500_DMICFILTCONF,
+			AB8500_DMICFILTCONF_DA3TOEAR, enum_ear_lineout_source);
+static const struct snd_kcontrol_new dapm_ear_lineout_source =
+	SOC_DAPM_ENUM("Earpiece or LineOut Mono Source",
+		dapm_enum_ear_lineout_source);
+
+/* LineOut */
+
+/* LineOut source selector */
+static const char * const enum_lineout_source[] = {"Mono Path", "Stereo Path"};
+static SOC_ENUM_DOUBLE_DECL(dapm_enum_lineout_source, AB8500_ANACONF5,
+			AB8500_ANACONF5_HSLDACTOLOL,
+			AB8500_ANACONF5_HSRDACTOLOR, enum_lineout_source);
+static const struct snd_kcontrol_new dapm_lineout_source[] = {
+	SOC_DAPM_ENUM("LineOut Source", dapm_enum_lineout_source),
+};
+
+/* Handsfree */
+
+/* Speaker Left - ANC selector */
+static const char * const enum_HFx_sel[] = {"Audio Path", "ANC"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_HFl_sel, AB8500_DIGMULTCONF2,
+			AB8500_DIGMULTCONF2_HFLSEL, enum_HFx_sel);
+static const struct snd_kcontrol_new dapm_HFl_select[] = {
+	SOC_DAPM_ENUM("Speaker Left Source", dapm_enum_HFl_sel),
+};
+
+/* Speaker Right - ANC selector */
+static SOC_ENUM_SINGLE_DECL(dapm_enum_HFr_sel, AB8500_DIGMULTCONF2,
+			AB8500_DIGMULTCONF2_HFRSEL, enum_HFx_sel);
+static const struct snd_kcontrol_new dapm_HFr_select[] = {
+	SOC_DAPM_ENUM("Speaker Right Source", dapm_enum_HFr_sel),
+};
+
+/* Mic 1 */
+
+/* Mic 1 - Mic 1a or 1b selector */
+static const char * const enum_mic1ab_sel[] = {"Mic 1b", "Mic 1a"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_mic1ab_sel, AB8500_ANACONF3,
+			AB8500_ANACONF3_MIC1SEL, enum_mic1ab_sel);
+static const struct snd_kcontrol_new dapm_mic1ab_mux[] = {
+	SOC_DAPM_ENUM("Mic 1a or 1b Select", dapm_enum_mic1ab_sel),
+};
+
+/* Mic 1 - AD3 - Mic 1 or DMic 3 selector */
+static const char * const enum_ad3_sel[] = {"Mic 1", "DMic 3"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad3_sel, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_AD3SEL, enum_ad3_sel);
+static const struct snd_kcontrol_new dapm_ad3_select[] = {
+	SOC_DAPM_ENUM("AD3 Source Select", dapm_enum_ad3_sel),
+};
+
+/* Mic 1 - AD6 - Mic 1 or DMic 6 selector */
+static const char * const enum_ad6_sel[] = {"Mic 1", "DMic 6"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad6_sel, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_AD6SEL, enum_ad6_sel);
+static const struct snd_kcontrol_new dapm_ad6_select[] = {
+	SOC_DAPM_ENUM("AD6 Source Select", dapm_enum_ad6_sel),
+};
+
+/* Mic 2 */
+
+/* Mic 2 - AD5 - Mic 2 or DMic 5 selector */
+static const char * const enum_ad5_sel[] = {"Mic 2", "DMic 5"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad5_sel, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_AD5SEL, enum_ad5_sel);
+static const struct snd_kcontrol_new dapm_ad5_select[] = {
+	SOC_DAPM_ENUM("AD5 Source Select", dapm_enum_ad5_sel),
+};
+
+/* LineIn */
+
+/* LineIn left - AD1 - LineIn Left or DMic 1 selector */
+static const char * const enum_ad1_sel[] = {"LineIn Left", "DMic 1"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad1_sel, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_AD1SEL, enum_ad1_sel);
+static const struct snd_kcontrol_new dapm_ad1_select[] = {
+	SOC_DAPM_ENUM("AD1 Source Select", dapm_enum_ad1_sel),
+};
+
+/* LineIn right - Mic 2 or LineIn Right selector */
+static const char * const enum_mic2lr_sel[] = {"Mic 2", "LineIn Right"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_mic2lr_sel, AB8500_ANACONF3,
+			AB8500_ANACONF3_LINRSEL, enum_mic2lr_sel);
+static const struct snd_kcontrol_new dapm_mic2lr_select[] = {
+	SOC_DAPM_ENUM("Mic 2 or LINR Select", dapm_enum_mic2lr_sel),
+};
+
+/* LineIn right - AD2 - LineIn Right or DMic2 selector */
+static const char * const enum_ad2_sel[] = {"LineIn Right", "DMic 2"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad2_sel, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_AD2SEL, enum_ad2_sel);
+static const struct snd_kcontrol_new dapm_ad2_select[] = {
+	SOC_DAPM_ENUM("AD2 Source Select", dapm_enum_ad2_sel),
+};
+
+
+/* ANC */
+
+static const char * const enum_anc_in_sel[] = {"Mic 1 / DMic 6",
+					"Mic 2 / DMic 5"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_anc_in_sel, AB8500_DMICFILTCONF,
+			AB8500_DMICFILTCONF_ANCINSEL, enum_anc_in_sel);
+static const struct snd_kcontrol_new dapm_anc_in_select[] = {
+	SOC_DAPM_ENUM("ANC Source", dapm_enum_anc_in_sel),
+};
+
+/* ANC - Enable/Disable */
+static const struct snd_kcontrol_new dapm_anc_enable[] = {
+	SOC_DAPM_SINGLE("Switch", AB8500_ANCCONF1,
+			AB8500_ANCCONF1_ENANC, 0, 0),
+};
+
+/* ANC to Earpiece - Mute */
+static const struct snd_kcontrol_new dapm_anc_ear_mute[] = {
+	SOC_DAPM_SINGLE("Switch", AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_ANCSEL, 1, 0),
+};
+
+
+
+/* Sidetone left */
+
+/* Sidetone left - Input selector */
+static const char * const enum_stfir1_in_sel[] = {
+	"LineIn Left", "LineIn Right", "Mic 1", "Headset Left"
+};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir1_in_sel, AB8500_DIGMULTCONF2,
+			AB8500_DIGMULTCONF2_FIRSID1SEL, enum_stfir1_in_sel);
+static const struct snd_kcontrol_new dapm_stfir1_in_select[] = {
+	SOC_DAPM_ENUM("Sidetone Left Source", dapm_enum_stfir1_in_sel),
+};
+
+/* Sidetone right path */
+
+/* Sidetone right - Input selector */
+static const char * const enum_stfir2_in_sel[] = {
+	"LineIn Right", "Mic 1", "DMic 4", "Headset Right"
+};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir2_in_sel, AB8500_DIGMULTCONF2,
+			AB8500_DIGMULTCONF2_FIRSID2SEL, enum_stfir2_in_sel);
+static const struct snd_kcontrol_new dapm_stfir2_in_select[] = {
+	SOC_DAPM_ENUM("Sidetone Right Source", dapm_enum_stfir2_in_sel),
+};
+
+/* Vibra */
+
+static const char * const enum_pwm2vibx[] = {"Audio Path", "PWM Generator"};
+
+static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib1, AB8500_PWMGENCONF1,
+			AB8500_PWMGENCONF1_PWMTOVIB1, enum_pwm2vibx);
+
+static const struct snd_kcontrol_new dapm_pwm2vib1[] = {
+	SOC_DAPM_ENUM("Vibra 1 Controller", dapm_enum_pwm2vib1),
+};
+
+static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib2, AB8500_PWMGENCONF1,
+			AB8500_PWMGENCONF1_PWMTOVIB2, enum_pwm2vibx);
+
+static const struct snd_kcontrol_new dapm_pwm2vib2[] = {
+	SOC_DAPM_ENUM("Vibra 2 Controller", dapm_enum_pwm2vib2),
+};
+
+/*
+ * DAPM-widgets
+ */
+
+static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = {
+
+	/* Clocks */
+	SND_SOC_DAPM_CLOCK_SUPPLY("audioclk"),
+
+	/* Regulators */
+	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AUD", 0),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC1", 0),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC2", 0),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("V-DMIC", 0),
+
+	/* Power */
+	SND_SOC_DAPM_SUPPLY("Audio Power",
+			AB8500_POWERUP, AB8500_POWERUP_POWERUP, 0,
+			NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("Audio Analog Power",
+			AB8500_POWERUP, AB8500_POWERUP_ENANA, 0,
+			NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Main supply node */
+	SND_SOC_DAPM_SUPPLY("Main Supply", SND_SOC_NOPM, 0, 0,
+			NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* DA/AD */
+
+	SND_SOC_DAPM_INPUT("ADC Input"),
+	SND_SOC_DAPM_ADC("ADC", "ab8500_0c", SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_OUTPUT("DAC Output"),
+
+	SND_SOC_DAPM_AIF_IN("DA_IN1", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DA_IN2", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DA_IN3", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DA_IN4", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DA_IN5", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DA_IN6", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT1", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT2", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT3", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT4", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT57", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT68", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+	/* Headset path */
+
+	SND_SOC_DAPM_SUPPLY("Charge Pump", AB8500_ANACONF5,
+			AB8500_ANACONF5_ENCPHS, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("DA1 Enable", "ab8500_0p",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA1, 0),
+	SND_SOC_DAPM_DAC("DA2 Enable", "ab8500_0p",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA2, 0),
+
+	SND_SOC_DAPM_PGA("HSL Digital Volume", SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_PGA("HSR Digital Volume", SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_DAC("HSL DAC", "ab8500_0p",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHSL, 0),
+	SND_SOC_DAPM_DAC("HSR DAC", "ab8500_0p",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHSR, 0),
+	SND_SOC_DAPM_MIXER("HSL DAC Mute", AB8500_MUTECONF,
+			AB8500_MUTECONF_MUTDACHSL, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HSR DAC Mute", AB8500_MUTECONF,
+			AB8500_MUTECONF_MUTDACHSR, 1,
+			NULL, 0),
+	SND_SOC_DAPM_DAC("HSL DAC Driver", "ab8500_0p",
+			AB8500_ANACONF3, AB8500_ANACONF3_ENDRVHSL, 0),
+	SND_SOC_DAPM_DAC("HSR DAC Driver", "ab8500_0p",
+			AB8500_ANACONF3, AB8500_ANACONF3_ENDRVHSR, 0),
+
+	SND_SOC_DAPM_MIXER("HSL Mute",
+			AB8500_MUTECONF, AB8500_MUTECONF_MUTHSL, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HSR Mute",
+			AB8500_MUTECONF, AB8500_MUTECONF_MUTHSR, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HSL Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHSL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HSR Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHSR, 0,
+			NULL, 0),
+	SND_SOC_DAPM_PGA("HSL Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_PGA("HSR Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("Headset Left"),
+	SND_SOC_DAPM_OUTPUT("Headset Right"),
+
+	/* LineOut path */
+
+	SND_SOC_DAPM_MUX("LineOut Source",
+			SND_SOC_NOPM, 0, 0, dapm_lineout_source),
+
+	SND_SOC_DAPM_MIXER("LOL Disable HFL",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHFL, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LOR Disable HFR",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHFR, 1,
+			NULL, 0),
+
+	SND_SOC_DAPM_MIXER("LOL Enable",
+			AB8500_ANACONF5, AB8500_ANACONF5_ENLOL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LOR Enable",
+			AB8500_ANACONF5, AB8500_ANACONF5_ENLOR, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("LineOut Left"),
+	SND_SOC_DAPM_OUTPUT("LineOut Right"),
+
+	/* Earpiece path */
+
+	SND_SOC_DAPM_MUX("Earpiece or LineOut Mono Source",
+			SND_SOC_NOPM, 0, 0, &dapm_ear_lineout_source),
+	SND_SOC_DAPM_MIXER("EAR DAC",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACEAR, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("EAR Mute",
+			AB8500_MUTECONF, AB8500_MUTECONF_MUTEAR, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("EAR Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENEAR, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("Earpiece"),
+
+	/* Handsfree path */
+
+	SND_SOC_DAPM_MIXER("DA3 Channel Volume",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA3, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DA4 Channel Volume",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA4, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MUX("Speaker Left Source",
+			SND_SOC_NOPM, 0, 0, dapm_HFl_select),
+	SND_SOC_DAPM_MUX("Speaker Right Source",
+			SND_SOC_NOPM, 0, 0, dapm_HFr_select),
+	SND_SOC_DAPM_MIXER("HFL DAC", AB8500_DAPATHCONF,
+			AB8500_DAPATHCONF_ENDACHFL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HFR DAC",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHFR, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DA4 or ANC path to HfR",
+			AB8500_DIGMULTCONF2, AB8500_DIGMULTCONF2_DATOHFREN, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DA3 or ANC path to HfL",
+			AB8500_DIGMULTCONF2, AB8500_DIGMULTCONF2_DATOHFLEN, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HFL Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHFL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HFR Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHFR, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("Speaker Left"),
+	SND_SOC_DAPM_OUTPUT("Speaker Right"),
+
+	/* Vibrator path */
+
+	SND_SOC_DAPM_INPUT("PWMGEN1"),
+	SND_SOC_DAPM_INPUT("PWMGEN2"),
+
+	SND_SOC_DAPM_MIXER("DA5 Channel Volume",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA5, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DA6 Channel Volume",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA6, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("VIB1 DAC",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACVIB1, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("VIB2 DAC",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACVIB2, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MUX("Vibra 1 Controller",
+			SND_SOC_NOPM, 0, 0, dapm_pwm2vib1),
+	SND_SOC_DAPM_MUX("Vibra 2 Controller",
+			SND_SOC_NOPM, 0, 0, dapm_pwm2vib2),
+	SND_SOC_DAPM_MIXER("VIB1 Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENVIB1, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("VIB2 Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENVIB2, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("Vibra 1"),
+	SND_SOC_DAPM_OUTPUT("Vibra 2"),
+
+	/* Mic 1 */
+
+	SND_SOC_DAPM_INPUT("Mic 1"),
+
+	SND_SOC_DAPM_MUX("Mic 1a or 1b Select",
+			SND_SOC_NOPM, 0, 0, dapm_mic1ab_mux),
+	SND_SOC_DAPM_MIXER("MIC1 Mute",
+			AB8500_ANACONF2, AB8500_ANACONF2_MUTMIC1, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("MIC1A V-AMICx Enable",
+			AB8500_ANACONF2, AB8500_ANACONF2_ENMIC1, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("MIC1B V-AMICx Enable",
+			AB8500_ANACONF2, AB8500_ANACONF2_ENMIC1, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("MIC1 ADC",
+			AB8500_ANACONF3, AB8500_ANACONF3_ENADCMIC, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MUX("AD3 Source Select",
+			SND_SOC_NOPM, 0, 0, dapm_ad3_select),
+	SND_SOC_DAPM_MIXER("AD3 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD3 Enable",
+			AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34, 0,
+			NULL, 0),
+
+	/* Mic 2 */
+
+	SND_SOC_DAPM_INPUT("Mic 2"),
+
+	SND_SOC_DAPM_MIXER("MIC2 Mute",
+			AB8500_ANACONF2, AB8500_ANACONF2_MUTMIC2, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("MIC2 V-AMICx Enable", AB8500_ANACONF2,
+			AB8500_ANACONF2_ENMIC2, 0,
+			NULL, 0),
+
+	/* LineIn */
+
+	SND_SOC_DAPM_INPUT("LineIn Left"),
+	SND_SOC_DAPM_INPUT("LineIn Right"),
+
+	SND_SOC_DAPM_MIXER("LINL Mute",
+			AB8500_ANACONF2, AB8500_ANACONF2_MUTLINL, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LINR Mute",
+			AB8500_ANACONF2, AB8500_ANACONF2_MUTLINR, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LINL Enable", AB8500_ANACONF2,
+			AB8500_ANACONF2_ENLINL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LINR Enable", AB8500_ANACONF2,
+			AB8500_ANACONF2_ENLINR, 0,
+			NULL, 0),
+
+	/* LineIn Bypass path */
+	SND_SOC_DAPM_MIXER("LINL to HSL Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LINR to HSR Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+
+	/* LineIn, Mic 2 */
+	SND_SOC_DAPM_MUX("Mic 2 or LINR Select",
+			SND_SOC_NOPM, 0, 0, dapm_mic2lr_select),
+	SND_SOC_DAPM_MIXER("LINL ADC", AB8500_ANACONF3,
+			AB8500_ANACONF3_ENADCLINL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LINR ADC", AB8500_ANACONF3,
+			AB8500_ANACONF3_ENADCLINR, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MUX("AD1 Source Select",
+			SND_SOC_NOPM, 0, 0, dapm_ad1_select),
+	SND_SOC_DAPM_MUX("AD2 Source Select",
+			SND_SOC_NOPM, 0, 0, dapm_ad2_select),
+	SND_SOC_DAPM_MIXER("AD1 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD2 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_MIXER("AD12 Enable",
+			AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD12, 0,
+			NULL, 0),
+
+	/* HD Capture path */
+
+	SND_SOC_DAPM_MUX("AD5 Source Select",
+			SND_SOC_NOPM, 0, 0, dapm_ad5_select),
+	SND_SOC_DAPM_MUX("AD6 Source Select",
+			SND_SOC_NOPM, 0, 0, dapm_ad6_select),
+	SND_SOC_DAPM_MIXER("AD5 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD6 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD57 Enable",
+			AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD68 Enable",
+			AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0,
+			NULL, 0),
+
+	/* Digital Microphone path */
+
+	SND_SOC_DAPM_INPUT("DMic 1"),
+	SND_SOC_DAPM_INPUT("DMic 2"),
+	SND_SOC_DAPM_INPUT("DMic 3"),
+	SND_SOC_DAPM_INPUT("DMic 4"),
+	SND_SOC_DAPM_INPUT("DMic 5"),
+	SND_SOC_DAPM_INPUT("DMic 6"),
+
+	SND_SOC_DAPM_MIXER("DMIC1",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC1, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DMIC2",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC2, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DMIC3",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC3, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DMIC4",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC4, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DMIC5",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC5, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DMIC6",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC6, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD4 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD4 Enable",
+			AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34,
+			0, NULL, 0),
+
+	/* Acoustical Noise Cancellation path */
+
+	SND_SOC_DAPM_INPUT("ANC Configure Input"),
+	SND_SOC_DAPM_OUTPUT("ANC Configure Output"),
+
+	SND_SOC_DAPM_MUX("ANC Source",
+			SND_SOC_NOPM, 0, 0,
+			dapm_anc_in_select),
+	SND_SOC_DAPM_SWITCH("ANC",
+			SND_SOC_NOPM, 0, 0,
+			dapm_anc_enable),
+	SND_SOC_DAPM_SWITCH("ANC to Earpiece",
+			SND_SOC_NOPM, 0, 0,
+			dapm_anc_ear_mute),
+
+	/* Sidetone Filter path */
+
+	SND_SOC_DAPM_MUX("Sidetone Left Source",
+			SND_SOC_NOPM, 0, 0,
+			dapm_stfir1_in_select),
+	SND_SOC_DAPM_MUX("Sidetone Right Source",
+			SND_SOC_NOPM, 0, 0,
+			dapm_stfir2_in_select),
+	SND_SOC_DAPM_MIXER("STFIR1 Control",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("STFIR2 Control",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("STFIR1 Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("STFIR2 Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+};
+
+/*
+ * DAPM-routes
+ */
+static const struct snd_soc_dapm_route ab8500_dapm_routes[] = {
+	/* Power AB8500 audio-block when AD/DA is active */
+	{"Main Supply", NULL, "V-AUD"},
+	{"Main Supply", NULL, "audioclk"},
+	{"Main Supply", NULL, "Audio Power"},
+	{"Main Supply", NULL, "Audio Analog Power"},
+
+	{"DAC", NULL, "ab8500_0p"},
+	{"DAC", NULL, "Main Supply"},
+	{"ADC", NULL, "ab8500_0c"},
+	{"ADC", NULL, "Main Supply"},
+
+	/* ANC Configure */
+	{"ANC Configure Input", NULL, "Main Supply"},
+	{"ANC Configure Output", NULL, "ANC Configure Input"},
+
+	/* AD/DA */
+	{"ADC", NULL, "ADC Input"},
+	{"DAC Output", NULL, "DAC"},
+
+	/* Powerup charge pump if DA1/2 is in use */
+
+	{"DA_IN1", NULL, "ab8500_0p"},
+	{"DA_IN1", NULL, "Charge Pump"},
+	{"DA_IN2", NULL, "ab8500_0p"},
+	{"DA_IN2", NULL, "Charge Pump"},
+
+	/* Headset path */
+
+	{"DA1 Enable", NULL, "DA_IN1"},
+	{"DA2 Enable", NULL, "DA_IN2"},
+
+	{"HSL Digital Volume", NULL, "DA1 Enable"},
+	{"HSR Digital Volume", NULL, "DA2 Enable"},
+
+	{"HSL DAC", NULL, "HSL Digital Volume"},
+	{"HSR DAC", NULL, "HSR Digital Volume"},
+
+	{"HSL DAC Mute", NULL, "HSL DAC"},
+	{"HSR DAC Mute", NULL, "HSR DAC"},
+
+	{"HSL DAC Driver", NULL, "HSL DAC Mute"},
+	{"HSR DAC Driver", NULL, "HSR DAC Mute"},
+
+	{"HSL Mute", NULL, "HSL DAC Driver"},
+	{"HSR Mute", NULL, "HSR DAC Driver"},
+
+	{"HSL Enable", NULL, "HSL Mute"},
+	{"HSR Enable", NULL, "HSR Mute"},
+
+	{"HSL Volume", NULL, "HSL Enable"},
+	{"HSR Volume", NULL, "HSR Enable"},
+
+	{"Headset Left", NULL, "HSL Volume"},
+	{"Headset Right", NULL, "HSR Volume"},
+
+	/* HF or LineOut path */
+
+	{"DA_IN3", NULL, "ab8500_0p"},
+	{"DA3 Channel Volume", NULL, "DA_IN3"},
+	{"DA_IN4", NULL, "ab8500_0p"},
+	{"DA4 Channel Volume", NULL, "DA_IN4"},
+
+	{"Speaker Left Source", "Audio Path", "DA3 Channel Volume"},
+	{"Speaker Right Source", "Audio Path", "DA4 Channel Volume"},
+
+	{"DA3 or ANC path to HfL", NULL, "Speaker Left Source"},
+	{"DA4 or ANC path to HfR", NULL, "Speaker Right Source"},
+
+	/* HF path */
+
+	{"HFL DAC", NULL, "DA3 or ANC path to HfL"},
+	{"HFR DAC", NULL, "DA4 or ANC path to HfR"},
+
+	{"HFL Enable", NULL, "HFL DAC"},
+	{"HFR Enable", NULL, "HFR DAC"},
+
+	{"Speaker Left", NULL, "HFL Enable"},
+	{"Speaker Right", NULL, "HFR Enable"},
+
+	/* Earpiece path */
+
+	{"Earpiece or LineOut Mono Source", "Headset Left",
+		"HSL Digital Volume"},
+	{"Earpiece or LineOut Mono Source", "Speaker Left",
+		"DA3 or ANC path to HfL"},
+
+	{"EAR DAC", NULL, "Earpiece or LineOut Mono Source"},
+
+	{"EAR Mute", NULL, "EAR DAC"},
+
+	{"EAR Enable", NULL, "EAR Mute"},
+
+	{"Earpiece", NULL, "EAR Enable"},
+
+	/* LineOut path stereo */
+
+	{"LineOut Source", "Stereo Path", "HSL DAC Driver"},
+	{"LineOut Source", "Stereo Path", "HSR DAC Driver"},
+
+	/* LineOut path mono */
+
+	{"LineOut Source", "Mono Path", "EAR DAC"},
+
+	/* LineOut path */
+
+	{"LOL Disable HFL", NULL, "LineOut Source"},
+	{"LOR Disable HFR", NULL, "LineOut Source"},
+
+	{"LOL Enable", NULL, "LOL Disable HFL"},
+	{"LOR Enable", NULL, "LOR Disable HFR"},
+
+	{"LineOut Left", NULL, "LOL Enable"},
+	{"LineOut Right", NULL, "LOR Enable"},
+
+	/* Vibrator path */
+
+	{"DA_IN5", NULL, "ab8500_0p"},
+	{"DA5 Channel Volume", NULL, "DA_IN5"},
+	{"DA_IN6", NULL, "ab8500_0p"},
+	{"DA6 Channel Volume", NULL, "DA_IN6"},
+
+	{"VIB1 DAC", NULL, "DA5 Channel Volume"},
+	{"VIB2 DAC", NULL, "DA6 Channel Volume"},
+
+	{"Vibra 1 Controller", "Audio Path", "VIB1 DAC"},
+	{"Vibra 2 Controller", "Audio Path", "VIB2 DAC"},
+	{"Vibra 1 Controller", "PWM Generator", "PWMGEN1"},
+	{"Vibra 2 Controller", "PWM Generator", "PWMGEN2"},
+
+	{"VIB1 Enable", NULL, "Vibra 1 Controller"},
+	{"VIB2 Enable", NULL, "Vibra 2 Controller"},
+
+	{"Vibra 1", NULL, "VIB1 Enable"},
+	{"Vibra 2", NULL, "VIB2 Enable"},
+
+
+	/* Mic 2 */
+
+	{"MIC2 V-AMICx Enable", NULL, "Mic 2"},
+
+	/* LineIn */
+	{"LINL Mute", NULL, "LineIn Left"},
+	{"LINR Mute", NULL, "LineIn Right"},
+
+	{"LINL Enable", NULL, "LINL Mute"},
+	{"LINR Enable", NULL, "LINR Mute"},
+
+	/* LineIn, Mic 2 */
+	{"Mic 2 or LINR Select", "LineIn Right", "LINR Enable"},
+	{"Mic 2 or LINR Select", "Mic 2", "MIC2 V-AMICx Enable"},
+
+	{"LINL ADC", NULL, "LINL Enable"},
+	{"LINR ADC", NULL, "Mic 2 or LINR Select"},
+
+	{"AD1 Source Select", "LineIn Left", "LINL ADC"},
+	{"AD2 Source Select", "LineIn Right", "LINR ADC"},
+
+	{"AD1 Channel Volume", NULL, "AD1 Source Select"},
+	{"AD2 Channel Volume", NULL, "AD2 Source Select"},
+
+	{"AD12 Enable", NULL, "AD1 Channel Volume"},
+	{"AD12 Enable", NULL, "AD2 Channel Volume"},
+
+	{"AD_OUT1", NULL, "ab8500_0c"},
+	{"AD_OUT1", NULL, "AD12 Enable"},
+	{"AD_OUT2", NULL, "ab8500_0c"},
+	{"AD_OUT2", NULL, "AD12 Enable"},
+
+	/* Mic 1 */
+
+	{"MIC1 Mute", NULL, "Mic 1"},
+
+	{"MIC1A V-AMICx Enable", NULL, "MIC1 Mute"},
+	{"MIC1B V-AMICx Enable", NULL, "MIC1 Mute"},
+
+	{"Mic 1a or 1b Select", "Mic 1a", "MIC1A V-AMICx Enable"},
+	{"Mic 1a or 1b Select", "Mic 1b", "MIC1B V-AMICx Enable"},
+
+	{"MIC1 ADC", NULL, "Mic 1a or 1b Select"},
+
+	{"AD3 Source Select", "Mic 1", "MIC1 ADC"},
+
+	{"AD3 Channel Volume", NULL, "AD3 Source Select"},
+
+	{"AD3 Enable", NULL, "AD3 Channel Volume"},
+
+	{"AD_OUT3", NULL, "ab8500_0c"},
+	{"AD_OUT3", NULL, "AD3 Enable"},
+
+	/* HD Capture path */
+
+	{"AD5 Source Select", "Mic 2", "LINR ADC"},
+	{"AD6 Source Select", "Mic 1", "MIC1 ADC"},
+
+	{"AD5 Channel Volume", NULL, "AD5 Source Select"},
+	{"AD6 Channel Volume", NULL, "AD6 Source Select"},
+
+	{"AD57 Enable", NULL, "AD5 Channel Volume"},
+	{"AD68 Enable", NULL, "AD6 Channel Volume"},
+
+	{"AD_OUT57", NULL, "ab8500_0c"},
+	{"AD_OUT57", NULL, "AD57 Enable"},
+	{"AD_OUT68", NULL, "ab8500_0c"},
+	{"AD_OUT68", NULL, "AD68 Enable"},
+
+	/* Digital Microphone path */
+
+	{"DMic 1", NULL, "V-DMIC"},
+	{"DMic 2", NULL, "V-DMIC"},
+	{"DMic 3", NULL, "V-DMIC"},
+	{"DMic 4", NULL, "V-DMIC"},
+	{"DMic 5", NULL, "V-DMIC"},
+	{"DMic 6", NULL, "V-DMIC"},
+
+	{"AD1 Source Select", NULL, "DMic 1"},
+	{"AD2 Source Select", NULL, "DMic 2"},
+	{"AD3 Source Select", NULL, "DMic 3"},
+	{"AD5 Source Select", NULL, "DMic 5"},
+	{"AD6 Source Select", NULL, "DMic 6"},
+
+	{"AD4 Channel Volume", NULL, "DMic 4"},
+	{"AD4 Enable", NULL, "AD4 Channel Volume"},
+
+	{"AD_OUT4", NULL, "ab8500_0c"},
+	{"AD_OUT4", NULL, "AD4 Enable"},
+
+	/* LineIn Bypass path */
+
+	{"LINL to HSL Volume", NULL, "LINL Enable"},
+	{"LINR to HSR Volume", NULL, "LINR Enable"},
+
+	{"HSL DAC Driver", NULL, "LINL to HSL Volume"},
+	{"HSR DAC Driver", NULL, "LINR to HSR Volume"},
+
+	/* ANC path (Acoustic Noise Cancellation) */
+
+	{"ANC Source", "Mic 2 / DMic 5", "AD5 Channel Volume"},
+	{"ANC Source", "Mic 1 / DMic 6", "AD6 Channel Volume"},
+
+	{"ANC", "Switch", "ANC Source"},
+
+	{"Speaker Left Source", "ANC", "ANC"},
+	{"Speaker Right Source", "ANC", "ANC"},
+	{"ANC to Earpiece", "Switch", "ANC"},
+
+	{"HSL Digital Volume", NULL, "ANC to Earpiece"},
+
+	/* Sidetone Filter path */
+
+	{"Sidetone Left Source", "LineIn Left", "AD12 Enable"},
+	{"Sidetone Left Source", "LineIn Right", "AD12 Enable"},
+	{"Sidetone Left Source", "Mic 1", "AD3 Enable"},
+	{"Sidetone Left Source", "Headset Left", "DA_IN1"},
+	{"Sidetone Right Source", "LineIn Right", "AD12 Enable"},
+	{"Sidetone Right Source", "Mic 1", "AD3 Enable"},
+	{"Sidetone Right Source", "DMic 4", "AD4 Enable"},
+	{"Sidetone Right Source", "Headset Right", "DA_IN2"},
+
+	{"STFIR1 Control", NULL, "Sidetone Left Source"},
+	{"STFIR2 Control", NULL, "Sidetone Right Source"},
+
+	{"STFIR1 Volume", NULL, "STFIR1 Control"},
+	{"STFIR2 Volume", NULL, "STFIR2 Control"},
+
+	{"DA1 Enable", NULL, "STFIR1 Volume"},
+	{"DA2 Enable", NULL, "STFIR2 Volume"},
+};
+
+static const struct snd_soc_dapm_route ab8500_dapm_routes_mic1a_vamicx[] = {
+	{"MIC1A V-AMICx Enable", NULL, "V-AMIC1"},
+	{"MIC1A V-AMICx Enable", NULL, "V-AMIC2"},
+};
+
+static const struct snd_soc_dapm_route ab8500_dapm_routes_mic1b_vamicx[] = {
+	{"MIC1B V-AMICx Enable", NULL, "V-AMIC1"},
+	{"MIC1B V-AMICx Enable", NULL, "V-AMIC2"},
+};
+
+static const struct snd_soc_dapm_route ab8500_dapm_routes_mic2_vamicx[] = {
+	{"MIC2 V-AMICx Enable", NULL, "V-AMIC1"},
+	{"MIC2 V-AMICx Enable", NULL, "V-AMIC2"},
+};
+
+/* ANC FIR-coefficients configuration sequence */
+static void anc_fir(struct snd_soc_codec *codec,
+		unsigned int bnk, unsigned int par, unsigned int val)
+{
+	if (par == 0 && bnk == 0)
+		snd_soc_update_bits(codec, AB8500_ANCCONF1,
+			BIT(AB8500_ANCCONF1_ANCFIRUPDATE),
+			BIT(AB8500_ANCCONF1_ANCFIRUPDATE));
+
+	snd_soc_write(codec, AB8500_ANCCONF5, val >> 8 & 0xff);
+	snd_soc_write(codec, AB8500_ANCCONF6, val &  0xff);
+
+	if (par == AB8500_ANC_FIR_COEFFS - 1 && bnk == 1)
+		snd_soc_update_bits(codec, AB8500_ANCCONF1,
+			BIT(AB8500_ANCCONF1_ANCFIRUPDATE), 0);
+}
+
+/* ANC IIR-coefficients configuration sequence */
+static void anc_iir(struct snd_soc_codec *codec, unsigned int bnk,
+		unsigned int par, unsigned int val)
+{
+	if (par == 0) {
+		if (bnk == 0) {
+			snd_soc_update_bits(codec, AB8500_ANCCONF1,
+					BIT(AB8500_ANCCONF1_ANCIIRINIT),
+					BIT(AB8500_ANCCONF1_ANCIIRINIT));
+			usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY);
+			snd_soc_update_bits(codec, AB8500_ANCCONF1,
+					BIT(AB8500_ANCCONF1_ANCIIRINIT), 0);
+			usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY);
+		} else {
+			snd_soc_update_bits(codec, AB8500_ANCCONF1,
+					BIT(AB8500_ANCCONF1_ANCIIRUPDATE),
+					BIT(AB8500_ANCCONF1_ANCIIRUPDATE));
+		}
+	} else if (par > 3) {
+		snd_soc_write(codec, AB8500_ANCCONF7, 0);
+		snd_soc_write(codec, AB8500_ANCCONF8, val >> 16 & 0xff);
+	}
+
+	snd_soc_write(codec, AB8500_ANCCONF7, val >> 8 & 0xff);
+	snd_soc_write(codec, AB8500_ANCCONF8, val & 0xff);
+
+	if (par == AB8500_ANC_IIR_COEFFS - 1 && bnk == 1)
+		snd_soc_update_bits(codec, AB8500_ANCCONF1,
+			BIT(AB8500_ANCCONF1_ANCIIRUPDATE), 0);
+}
+
+/* ANC IIR-/FIR-coefficients configuration sequence */
+static void anc_configure(struct snd_soc_codec *codec,
+			bool apply_fir, bool apply_iir)
+{
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+	unsigned int bnk, par, val;
+
+	dev_dbg(codec->dev, "%s: Enter.\n", __func__);
+
+	if (apply_fir)
+		snd_soc_update_bits(codec, AB8500_ANCCONF1,
+			BIT(AB8500_ANCCONF1_ENANC), 0);
+
+	snd_soc_update_bits(codec, AB8500_ANCCONF1,
+		BIT(AB8500_ANCCONF1_ENANC), BIT(AB8500_ANCCONF1_ENANC));
+
+	if (apply_fir)
+		for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++)
+			for (par = 0; par < AB8500_ANC_FIR_COEFFS; par++) {
+				val = snd_soc_read(codec,
+						drvdata->anc_fir_values[par]);
+				anc_fir(codec, bnk, par, val);
+			}
+
+	if (apply_iir)
+		for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++)
+			for (par = 0; par < AB8500_ANC_IIR_COEFFS; par++) {
+				val = snd_soc_read(codec,
+						drvdata->anc_iir_values[par]);
+				anc_iir(codec, bnk, par, val);
+			}
+
+	dev_dbg(codec->dev, "%s: Exit.\n", __func__);
+}
+
+/*
+ * Control-events
+ */
+
+static int sid_status_control_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+
+	mutex_lock(&codec->mutex);
+	ucontrol->value.integer.value[0] = drvdata->sid_status;
+	mutex_unlock(&codec->mutex);
+
+	return 0;
+}
+
+/* Write sidetone FIR-coefficients configuration sequence */
+static int sid_status_control_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+	unsigned int param, sidconf, val;
+	int status = 1;
+
+	dev_dbg(codec->dev, "%s: Enter\n", __func__);
+
+	if (ucontrol->value.integer.value[0] != SID_APPLY_FIR) {
+		dev_err(codec->dev,
+			"%s: ERROR: This control supports '%s' only!\n",
+			__func__, enum_sid_state[SID_APPLY_FIR]);
+		return -EIO;
+	}
+
+	mutex_lock(&codec->mutex);
+
+	sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF);
+	if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
+		if ((sidconf & BIT(AB8500_SIDFIRCONF_ENFIRSIDS)) == 0) {
+			dev_err(codec->dev, "%s: Sidetone busy while off!\n",
+				__func__);
+			status = -EPERM;
+		} else {
+			status = -EBUSY;
+		}
+		goto out;
+	}
+
+	snd_soc_write(codec, AB8500_SIDFIRADR, 0);
+
+	for (param = 0; param < AB8500_SID_FIR_COEFFS; param++) {
+		val = snd_soc_read(codec, drvdata->sid_fir_values[param]);
+		snd_soc_write(codec, AB8500_SIDFIRCOEF1, val >> 8 & 0xff);
+		snd_soc_write(codec, AB8500_SIDFIRCOEF2, val & 0xff);
+	}
+
+	snd_soc_update_bits(codec, AB8500_SIDFIRADR,
+		BIT(AB8500_SIDFIRADR_FIRSIDSET),
+		BIT(AB8500_SIDFIRADR_FIRSIDSET));
+	snd_soc_update_bits(codec, AB8500_SIDFIRADR,
+		BIT(AB8500_SIDFIRADR_FIRSIDSET), 0);
+
+	drvdata->sid_status = SID_FIR_CONFIGURED;
+
+out:
+	mutex_unlock(&codec->mutex);
+
+	dev_dbg(codec->dev, "%s: Exit\n", __func__);
+
+	return status;
+}
+
+static int anc_status_control_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+
+	mutex_lock(&codec->mutex);
+	ucontrol->value.integer.value[0] = drvdata->anc_status;
+	mutex_unlock(&codec->mutex);
+
+	return 0;
+}
+
+static int anc_status_control_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+	struct device *dev = codec->dev;
+	bool apply_fir, apply_iir;
+	int req, status;
+
+	dev_dbg(dev, "%s: Enter.\n", __func__);
+
+	mutex_lock(&drvdata->anc_lock);
+
+	req = ucontrol->value.integer.value[0];
+	if (req != ANC_APPLY_FIR_IIR && req != ANC_APPLY_FIR &&
+		req != ANC_APPLY_IIR) {
+		dev_err(dev, "%s: ERROR: Unsupported status to set '%s'!\n",
+			__func__, enum_anc_state[req]);
+		status = -EINVAL;
+		goto cleanup;
+	}
+	apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR;
+	apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR;
+
+	status = snd_soc_dapm_force_enable_pin(&codec->dapm,
+					"ANC Configure Input");
+	if (status < 0) {
+		dev_err(dev,
+			"%s: ERROR: Failed to enable power (status = %d)!\n",
+			__func__, status);
+		goto cleanup;
+	}
+	snd_soc_dapm_sync(&codec->dapm);
+
+	mutex_lock(&codec->mutex);
+	anc_configure(codec, apply_fir, apply_iir);
+	mutex_unlock(&codec->mutex);
+
+	if (apply_fir) {
+		if (drvdata->anc_status == ANC_IIR_CONFIGURED)
+			drvdata->anc_status = ANC_FIR_IIR_CONFIGURED;
+		else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED)
+			drvdata->anc_status =  ANC_FIR_CONFIGURED;
+	}
+	if (apply_iir) {
+		if (drvdata->anc_status == ANC_FIR_CONFIGURED)
+			drvdata->anc_status = ANC_FIR_IIR_CONFIGURED;
+		else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED)
+			drvdata->anc_status =  ANC_IIR_CONFIGURED;
+	}
+
+	status = snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
+	snd_soc_dapm_sync(&codec->dapm);
+
+cleanup:
+	mutex_unlock(&drvdata->anc_lock);
+
+	if (status < 0)
+		dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n",
+			__func__, status);
+
+	dev_dbg(dev, "%s: Exit.\n", __func__);
+
+	return (status < 0) ? status : 1;
+}
+
+static int filter_control_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	struct filter_control *fc =
+			(struct filter_control *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = fc->count;
+	uinfo->value.integer.min = fc->min;
+	uinfo->value.integer.max = fc->max;
+
+	return 0;
+}
+
+static int filter_control_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct filter_control *fc =
+			(struct filter_control *)kcontrol->private_value;
+	unsigned int i;
+
+	mutex_lock(&codec->mutex);
+	for (i = 0; i < fc->count; i++)
+		ucontrol->value.integer.value[i] = fc->value[i];
+	mutex_unlock(&codec->mutex);
+
+	return 0;
+}
+
+static int filter_control_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct filter_control *fc =
+			(struct filter_control *)kcontrol->private_value;
+	unsigned int i;
+
+	mutex_lock(&codec->mutex);
+	for (i = 0; i < fc->count; i++)
+		fc->value[i] = ucontrol->value.integer.value[i];
+	mutex_unlock(&codec->mutex);
+
+	return 0;
+}
+
+/*
+ * Controls - Non-DAPM ASoC
+ */
+
+static DECLARE_TLV_DB_SCALE(adx_dig_gain_tlv, -3200, 100, 1);
+/* -32dB = Mute */
+
+static DECLARE_TLV_DB_SCALE(dax_dig_gain_tlv, -6300, 100, 1);
+/* -63dB = Mute */
+
+static DECLARE_TLV_DB_SCALE(hs_ear_dig_gain_tlv, -100, 100, 1);
+/* -1dB = Mute */
+
+static const unsigned int hs_gain_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0, 3, TLV_DB_SCALE_ITEM(-3200, 400, 0),
+	4, 15, TLV_DB_SCALE_ITEM(-1800, 200, 0),
+};
+
+static DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(lin_gain_tlv, -1000, 200, 0);
+
+static DECLARE_TLV_DB_SCALE(lin2hs_gain_tlv, -3800, 200, 1);
+/* -38dB = Mute */
+
+static const char * const enum_hsfadspeed[] = {"2ms", "0.5ms", "10.6ms",
+					"5ms"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_hsfadspeed,
+	AB8500_DIGMICCONF, AB8500_DIGMICCONF_HSFADSPEED, enum_hsfadspeed);
+
+static const char * const enum_envdetthre[] = {
+	"250mV", "300mV", "350mV", "400mV",
+	"450mV", "500mV", "550mV", "600mV",
+	"650mV", "700mV", "750mV", "800mV",
+	"850mV", "900mV", "950mV", "1.00V" };
+static SOC_ENUM_SINGLE_DECL(soc_enum_envdeththre,
+	AB8500_ENVCPCONF, AB8500_ENVCPCONF_ENVDETHTHRE, enum_envdetthre);
+static SOC_ENUM_SINGLE_DECL(soc_enum_envdetlthre,
+	AB8500_ENVCPCONF, AB8500_ENVCPCONF_ENVDETLTHRE, enum_envdetthre);
+static const char * const enum_envdettime[] = {
+	"26.6us", "53.2us", "106us",  "213us",
+	"426us",  "851us",  "1.70ms", "3.40ms",
+	"6.81ms", "13.6ms", "27.2ms", "54.5ms",
+	"109ms",  "218ms",  "436ms",  "872ms" };
+static SOC_ENUM_SINGLE_DECL(soc_enum_envdettime,
+	AB8500_SIGENVCONF, AB8500_SIGENVCONF_ENVDETTIME, enum_envdettime);
+
+static const char * const enum_sinc31[] = {"Sinc 3", "Sinc 1"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_hsesinc, AB8500_HSLEARDIGGAIN,
+			AB8500_HSLEARDIGGAIN_HSSINC1, enum_sinc31);
+
+static const char * const enum_fadespeed[] = {"1ms", "4ms", "8ms", "16ms"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_fadespeed, AB8500_HSRDIGGAIN,
+			AB8500_HSRDIGGAIN_FADESPEED, enum_fadespeed);
+
+/* Earpiece */
+
+static const char * const enum_lowpow[] = {"Normal", "Low Power"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_eardaclowpow, AB8500_ANACONF1,
+			AB8500_ANACONF1_EARDACLOWPOW, enum_lowpow);
+static SOC_ENUM_SINGLE_DECL(soc_enum_eardrvlowpow, AB8500_ANACONF1,
+			AB8500_ANACONF1_EARDRVLOWPOW, enum_lowpow);
+
+static const char * const enum_av_mode[] = {"Audio", "Voice"};
+static SOC_ENUM_DOUBLE_DECL(soc_enum_ad12voice, AB8500_ADFILTCONF,
+	AB8500_ADFILTCONF_AD1VOICE, AB8500_ADFILTCONF_AD2VOICE, enum_av_mode);
+static SOC_ENUM_DOUBLE_DECL(soc_enum_ad34voice, AB8500_ADFILTCONF,
+	AB8500_ADFILTCONF_AD3VOICE, AB8500_ADFILTCONF_AD4VOICE, enum_av_mode);
+
+/* DA */
+
+static SOC_ENUM_SINGLE_DECL(soc_enum_da12voice,
+			AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_DA12VOICE,
+			enum_av_mode);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da34voice,
+			AB8500_DASLOTCONF3, AB8500_DASLOTCONF3_DA34VOICE,
+			enum_av_mode);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da56voice,
+			AB8500_DASLOTCONF5, AB8500_DASLOTCONF5_DA56VOICE,
+			enum_av_mode);
+
+static const char * const enum_da2hslr[] = {"Sidetone", "Audio Path"};
+static SOC_ENUM_DOUBLE_DECL(soc_enum_da2hslr, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_DATOHSLEN,
+			AB8500_DIGMULTCONF1_DATOHSREN, enum_da2hslr);
+
+static const char * const enum_sinc53[] = {"Sinc 5", "Sinc 3"};
+static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic12sinc, AB8500_DMICFILTCONF,
+			AB8500_DMICFILTCONF_DMIC1SINC3,
+			AB8500_DMICFILTCONF_DMIC2SINC3, enum_sinc53);
+static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic34sinc, AB8500_DMICFILTCONF,
+			AB8500_DMICFILTCONF_DMIC3SINC3,
+			AB8500_DMICFILTCONF_DMIC4SINC3, enum_sinc53);
+static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic56sinc, AB8500_DMICFILTCONF,
+			AB8500_DMICFILTCONF_DMIC5SINC3,
+			AB8500_DMICFILTCONF_DMIC6SINC3, enum_sinc53);
+
+/* Digital interface - DA from slot mapping */
+static const char * const enum_da_from_slot_map[] = {"SLOT0",
+					"SLOT1",
+					"SLOT2",
+					"SLOT3",
+					"SLOT4",
+					"SLOT5",
+					"SLOT6",
+					"SLOT7",
+					"SLOT8",
+					"SLOT9",
+					"SLOT10",
+					"SLOT11",
+					"SLOT12",
+					"SLOT13",
+					"SLOT14",
+					"SLOT15",
+					"SLOT16",
+					"SLOT17",
+					"SLOT18",
+					"SLOT19",
+					"SLOT20",
+					"SLOT21",
+					"SLOT22",
+					"SLOT23",
+					"SLOT24",
+					"SLOT25",
+					"SLOT26",
+					"SLOT27",
+					"SLOT28",
+					"SLOT29",
+					"SLOT30",
+					"SLOT31"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_da1slotmap,
+			AB8500_DASLOTCONF1, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da2slotmap,
+			AB8500_DASLOTCONF2, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da3slotmap,
+			AB8500_DASLOTCONF3, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da4slotmap,
+			AB8500_DASLOTCONF4, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da5slotmap,
+			AB8500_DASLOTCONF5, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da6slotmap,
+			AB8500_DASLOTCONF6, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da7slotmap,
+			AB8500_DASLOTCONF7, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da8slotmap,
+			AB8500_DASLOTCONF8, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+
+/* Digital interface - AD to slot mapping */
+static const char * const enum_ad_to_slot_map[] = {"AD_OUT1",
+					"AD_OUT2",
+					"AD_OUT3",
+					"AD_OUT4",
+					"AD_OUT5",
+					"AD_OUT6",
+					"AD_OUT7",
+					"AD_OUT8",
+					"zeroes",
+					"tristate"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot0map,
+			AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot1map,
+			AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot2map,
+			AB8500_ADSLOTSEL2, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot3map,
+			AB8500_ADSLOTSEL2, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot4map,
+			AB8500_ADSLOTSEL3, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot5map,
+			AB8500_ADSLOTSEL3, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot6map,
+			AB8500_ADSLOTSEL4, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot7map,
+			AB8500_ADSLOTSEL4, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot8map,
+			AB8500_ADSLOTSEL5, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot9map,
+			AB8500_ADSLOTSEL5, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot10map,
+			AB8500_ADSLOTSEL6, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot11map,
+			AB8500_ADSLOTSEL6, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot12map,
+			AB8500_ADSLOTSEL7, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot13map,
+			AB8500_ADSLOTSEL7, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot14map,
+			AB8500_ADSLOTSEL8, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot15map,
+			AB8500_ADSLOTSEL8, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot16map,
+			AB8500_ADSLOTSEL9, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot17map,
+			AB8500_ADSLOTSEL9, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot18map,
+			AB8500_ADSLOTSEL10, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot19map,
+			AB8500_ADSLOTSEL10, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot20map,
+			AB8500_ADSLOTSEL11, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot21map,
+			AB8500_ADSLOTSEL11, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot22map,
+			AB8500_ADSLOTSEL12, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot23map,
+			AB8500_ADSLOTSEL12, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot24map,
+			AB8500_ADSLOTSEL13, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot25map,
+			AB8500_ADSLOTSEL13, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot26map,
+			AB8500_ADSLOTSEL14, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot27map,
+			AB8500_ADSLOTSEL14, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot28map,
+			AB8500_ADSLOTSEL15, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot29map,
+			AB8500_ADSLOTSEL15, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot30map,
+			AB8500_ADSLOTSEL16, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot31map,
+			AB8500_ADSLOTSEL16, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+
+/* Digital interface - Burst mode */
+static const char * const enum_mask[] = {"Unmasked", "Masked"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomask,
+			AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFOMASK,
+			enum_mask);
+static const char * const enum_bitclk0[] = {"19_2_MHz", "38_4_MHz"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_bfifo19m2,
+			AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFO19M2,
+			enum_bitclk0);
+static const char * const enum_slavemaster[] = {"Slave", "Master"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomast,
+			AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOMAST_SHIFT,
+			enum_slavemaster);
+
+/* Sidetone */
+static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_sidstate, enum_sid_state);
+
+/* ANC */
+static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_ancstate, enum_anc_state);
+
+static struct snd_kcontrol_new ab8500_ctrls[] = {
+	/* Charge pump */
+	SOC_ENUM("Charge Pump High Threshold For Low Voltage",
+		soc_enum_envdeththre),
+	SOC_ENUM("Charge Pump Low Threshold For Low Voltage",
+		soc_enum_envdetlthre),
+	SOC_SINGLE("Charge Pump Envelope Detection Switch",
+		AB8500_SIGENVCONF, AB8500_SIGENVCONF_ENVDETCPEN,
+		1, 0),
+	SOC_ENUM("Charge Pump Envelope Detection Decay Time",
+		soc_enum_envdettime),
+
+	/* Headset */
+	SOC_ENUM("Headset Mode", soc_enum_da12voice),
+	SOC_SINGLE("Headset High Pass Switch",
+		AB8500_ANACONF1, AB8500_ANACONF1_HSHPEN,
+		1, 0),
+	SOC_SINGLE("Headset Low Power Switch",
+		AB8500_ANACONF1, AB8500_ANACONF1_HSLOWPOW,
+		1, 0),
+	SOC_SINGLE("Headset DAC Low Power Switch",
+		AB8500_ANACONF1, AB8500_ANACONF1_DACLOWPOW1,
+		1, 0),
+	SOC_SINGLE("Headset DAC Drv Low Power Switch",
+		AB8500_ANACONF1, AB8500_ANACONF1_DACLOWPOW0,
+		1, 0),
+	SOC_ENUM("Headset Fade Speed", soc_enum_hsfadspeed),
+	SOC_ENUM("Headset Source", soc_enum_da2hslr),
+	SOC_ENUM("Headset Filter", soc_enum_hsesinc),
+	SOC_DOUBLE_R_TLV("Headset Master Volume",
+		AB8500_DADIGGAIN1, AB8500_DADIGGAIN2,
+		0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv),
+	SOC_DOUBLE_R_TLV("Headset Digital Volume",
+		AB8500_HSLEARDIGGAIN, AB8500_HSRDIGGAIN,
+		0, AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX, 1, hs_ear_dig_gain_tlv),
+	SOC_DOUBLE_TLV("Headset Volume",
+		AB8500_ANAGAIN3,
+		AB8500_ANAGAIN3_HSLGAIN, AB8500_ANAGAIN3_HSRGAIN,
+		AB8500_ANAGAIN3_HSXGAIN_MAX, 1, hs_gain_tlv),
+
+	/* Earpiece */
+	SOC_ENUM("Earpiece DAC Mode",
+		soc_enum_eardaclowpow),
+	SOC_ENUM("Earpiece DAC Drv Mode",
+		soc_enum_eardrvlowpow),
+
+	/* HandsFree */
+	SOC_ENUM("HF Mode", soc_enum_da34voice),
+	SOC_SINGLE("HF and Headset Swap Switch",
+		AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_SWAPDA12_34,
+		1, 0),
+	SOC_DOUBLE("HF Low EMI Mode Switch",
+		AB8500_CLASSDCONF1,
+		AB8500_CLASSDCONF1_HFLSWAPEN, AB8500_CLASSDCONF1_HFRSWAPEN,
+		1, 0),
+	SOC_DOUBLE("HF FIR Bypass Switch",
+		AB8500_CLASSDCONF2,
+		AB8500_CLASSDCONF2_FIRBYP0, AB8500_CLASSDCONF2_FIRBYP1,
+		1, 0),
+	SOC_DOUBLE("HF High Volume Switch",
+		AB8500_CLASSDCONF2,
+		AB8500_CLASSDCONF2_HIGHVOLEN0, AB8500_CLASSDCONF2_HIGHVOLEN1,
+		1, 0),
+	SOC_SINGLE("HF L and R Bridge Switch",
+		AB8500_CLASSDCONF1, AB8500_CLASSDCONF1_PARLHF,
+		1, 0),
+	SOC_DOUBLE_R_TLV("HF Master Volume",
+		AB8500_DADIGGAIN3, AB8500_DADIGGAIN4,
+		0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv),
+
+	/* Vibra */
+	SOC_DOUBLE("Vibra High Volume Switch",
+		AB8500_CLASSDCONF2,
+		AB8500_CLASSDCONF2_HIGHVOLEN2, AB8500_CLASSDCONF2_HIGHVOLEN3,
+		1, 0),
+	SOC_DOUBLE("Vibra Low EMI Mode Switch",
+		AB8500_CLASSDCONF1,
+		AB8500_CLASSDCONF1_VIB1SWAPEN, AB8500_CLASSDCONF1_VIB2SWAPEN,
+		1, 0),
+	SOC_DOUBLE("Vibra FIR Bypass Switch",
+		AB8500_CLASSDCONF2,
+		AB8500_CLASSDCONF2_FIRBYP2, AB8500_CLASSDCONF2_FIRBYP3,
+		1, 0),
+	SOC_ENUM("Vibra Mode", soc_enum_da56voice),
+	SOC_DOUBLE_R("Vibra PWM Duty Cycle N",
+		AB8500_PWMGENCONF3, AB8500_PWMGENCONF5,
+		AB8500_PWMGENCONFX_PWMVIBXDUTCYC,
+		AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX, 0),
+	SOC_DOUBLE_R("Vibra PWM Duty Cycle P",
+		AB8500_PWMGENCONF2, AB8500_PWMGENCONF4,
+		AB8500_PWMGENCONFX_PWMVIBXDUTCYC,
+		AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX, 0),
+	SOC_SINGLE("Vibra 1 and 2 Bridge Switch",
+		AB8500_CLASSDCONF1, AB8500_CLASSDCONF1_PARLVIB,
+		1, 0),
+	SOC_DOUBLE_R_TLV("Vibra Master Volume",
+		AB8500_DADIGGAIN5, AB8500_DADIGGAIN6,
+		0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv),
+
+	/* HandsFree, Vibra */
+	SOC_SINGLE("ClassD High Pass Volume",
+		AB8500_CLASSDCONF3, AB8500_CLASSDCONF3_DITHHPGAIN,
+		AB8500_CLASSDCONF3_DITHHPGAIN_MAX, 0),
+	SOC_SINGLE("ClassD White Volume",
+		AB8500_CLASSDCONF3, AB8500_CLASSDCONF3_DITHWGAIN,
+		AB8500_CLASSDCONF3_DITHWGAIN_MAX, 0),
+
+	/* Mic 1, Mic 2, LineIn */
+	SOC_DOUBLE_R_TLV("Mic Master Volume",
+		AB8500_ADDIGGAIN3, AB8500_ADDIGGAIN4,
+		0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv),
+
+	/* Mic 1 */
+	SOC_SINGLE_TLV("Mic 1",
+		AB8500_ANAGAIN1,
+		AB8500_ANAGAINX_MICXGAIN,
+		AB8500_ANAGAINX_MICXGAIN_MAX, 0, mic_gain_tlv),
+	SOC_SINGLE("Mic 1 Low Power Switch",
+		AB8500_ANAGAIN1, AB8500_ANAGAINX_LOWPOWMICX,
+		1, 0),
+
+	/* Mic 2 */
+	SOC_DOUBLE("Mic High Pass Switch",
+		AB8500_ADFILTCONF,
+		AB8500_ADFILTCONF_AD3NH, AB8500_ADFILTCONF_AD4NH,
+		1, 1),
+	SOC_ENUM("Mic Mode", soc_enum_ad34voice),
+	SOC_ENUM("Mic Filter", soc_enum_dmic34sinc),
+	SOC_SINGLE_TLV("Mic 2",
+		AB8500_ANAGAIN2,
+		AB8500_ANAGAINX_MICXGAIN,
+		AB8500_ANAGAINX_MICXGAIN_MAX, 0, mic_gain_tlv),
+	SOC_SINGLE("Mic 2 Low Power Switch",
+		AB8500_ANAGAIN2, AB8500_ANAGAINX_LOWPOWMICX,
+		1, 0),
+
+	/* LineIn */
+	SOC_DOUBLE("LineIn High Pass Switch",
+		AB8500_ADFILTCONF,
+		AB8500_ADFILTCONF_AD1NH, AB8500_ADFILTCONF_AD2NH,
+		1, 1),
+	SOC_ENUM("LineIn Filter", soc_enum_dmic12sinc),
+	SOC_ENUM("LineIn Mode", soc_enum_ad12voice),
+	SOC_DOUBLE_R_TLV("LineIn Master Volume",
+		AB8500_ADDIGGAIN1, AB8500_ADDIGGAIN2,
+		0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv),
+	SOC_DOUBLE_TLV("LineIn",
+		AB8500_ANAGAIN4,
+		AB8500_ANAGAIN4_LINLGAIN, AB8500_ANAGAIN4_LINRGAIN,
+		AB8500_ANAGAIN4_LINXGAIN_MAX, 0, lin_gain_tlv),
+	SOC_DOUBLE_R_TLV("LineIn to Headset Volume",
+		AB8500_DIGLINHSLGAIN, AB8500_DIGLINHSRGAIN,
+		AB8500_DIGLINHSXGAIN_LINTOHSXGAIN,
+		AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX,
+		1, lin2hs_gain_tlv),
+
+	/* DMic */
+	SOC_ENUM("DMic Filter", soc_enum_dmic56sinc),
+	SOC_DOUBLE_R_TLV("DMic Master Volume",
+		AB8500_ADDIGGAIN5, AB8500_ADDIGGAIN6,
+		0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv),
+
+	/* Digital gains */
+	SOC_ENUM("Digital Gain Fade Speed", soc_enum_fadespeed),
+
+	/* Analog loopback */
+	SOC_DOUBLE_R_TLV("Analog Loopback Volume",
+		AB8500_ADDIGLOOPGAIN1, AB8500_ADDIGLOOPGAIN2,
+		0, AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX, 1, dax_dig_gain_tlv),
+
+	/* Digital interface - DA from slot mapping */
+	SOC_ENUM("Digital Interface DA 1 From Slot Map", soc_enum_da1slotmap),
+	SOC_ENUM("Digital Interface DA 2 From Slot Map", soc_enum_da2slotmap),
+	SOC_ENUM("Digital Interface DA 3 From Slot Map", soc_enum_da3slotmap),
+	SOC_ENUM("Digital Interface DA 4 From Slot Map", soc_enum_da4slotmap),
+	SOC_ENUM("Digital Interface DA 5 From Slot Map", soc_enum_da5slotmap),
+	SOC_ENUM("Digital Interface DA 6 From Slot Map", soc_enum_da6slotmap),
+	SOC_ENUM("Digital Interface DA 7 From Slot Map", soc_enum_da7slotmap),
+	SOC_ENUM("Digital Interface DA 8 From Slot Map", soc_enum_da8slotmap),
+
+	/* Digital interface - AD to slot mapping */
+	SOC_ENUM("Digital Interface AD To Slot 0 Map", soc_enum_adslot0map),
+	SOC_ENUM("Digital Interface AD To Slot 1 Map", soc_enum_adslot1map),
+	SOC_ENUM("Digital Interface AD To Slot 2 Map", soc_enum_adslot2map),
+	SOC_ENUM("Digital Interface AD To Slot 3 Map", soc_enum_adslot3map),
+	SOC_ENUM("Digital Interface AD To Slot 4 Map", soc_enum_adslot4map),
+	SOC_ENUM("Digital Interface AD To Slot 5 Map", soc_enum_adslot5map),
+	SOC_ENUM("Digital Interface AD To Slot 6 Map", soc_enum_adslot6map),
+	SOC_ENUM("Digital Interface AD To Slot 7 Map", soc_enum_adslot7map),
+	SOC_ENUM("Digital Interface AD To Slot 8 Map", soc_enum_adslot8map),
+	SOC_ENUM("Digital Interface AD To Slot 9 Map", soc_enum_adslot9map),
+	SOC_ENUM("Digital Interface AD To Slot 10 Map", soc_enum_adslot10map),
+	SOC_ENUM("Digital Interface AD To Slot 11 Map", soc_enum_adslot11map),
+	SOC_ENUM("Digital Interface AD To Slot 12 Map", soc_enum_adslot12map),
+	SOC_ENUM("Digital Interface AD To Slot 13 Map", soc_enum_adslot13map),
+	SOC_ENUM("Digital Interface AD To Slot 14 Map", soc_enum_adslot14map),
+	SOC_ENUM("Digital Interface AD To Slot 15 Map", soc_enum_adslot15map),
+	SOC_ENUM("Digital Interface AD To Slot 16 Map", soc_enum_adslot16map),
+	SOC_ENUM("Digital Interface AD To Slot 17 Map", soc_enum_adslot17map),
+	SOC_ENUM("Digital Interface AD To Slot 18 Map", soc_enum_adslot18map),
+	SOC_ENUM("Digital Interface AD To Slot 19 Map", soc_enum_adslot19map),
+	SOC_ENUM("Digital Interface AD To Slot 20 Map", soc_enum_adslot20map),
+	SOC_ENUM("Digital Interface AD To Slot 21 Map", soc_enum_adslot21map),
+	SOC_ENUM("Digital Interface AD To Slot 22 Map", soc_enum_adslot22map),
+	SOC_ENUM("Digital Interface AD To Slot 23 Map", soc_enum_adslot23map),
+	SOC_ENUM("Digital Interface AD To Slot 24 Map", soc_enum_adslot24map),
+	SOC_ENUM("Digital Interface AD To Slot 25 Map", soc_enum_adslot25map),
+	SOC_ENUM("Digital Interface AD To Slot 26 Map", soc_enum_adslot26map),
+	SOC_ENUM("Digital Interface AD To Slot 27 Map", soc_enum_adslot27map),
+	SOC_ENUM("Digital Interface AD To Slot 28 Map", soc_enum_adslot28map),
+	SOC_ENUM("Digital Interface AD To Slot 29 Map", soc_enum_adslot29map),
+	SOC_ENUM("Digital Interface AD To Slot 30 Map", soc_enum_adslot30map),
+	SOC_ENUM("Digital Interface AD To Slot 31 Map", soc_enum_adslot31map),
+
+	/* Digital interface - Loopback */
+	SOC_SINGLE("Digital Interface AD 1 Loopback Switch",
+		AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_DAI7TOADO1,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 2 Loopback Switch",
+		AB8500_DASLOTCONF2, AB8500_DASLOTCONF2_DAI8TOADO2,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 3 Loopback Switch",
+		AB8500_DASLOTCONF3, AB8500_DASLOTCONF3_DAI7TOADO3,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 4 Loopback Switch",
+		AB8500_DASLOTCONF4, AB8500_DASLOTCONF4_DAI8TOADO4,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 5 Loopback Switch",
+		AB8500_DASLOTCONF5, AB8500_DASLOTCONF5_DAI7TOADO5,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 6 Loopback Switch",
+		AB8500_DASLOTCONF6, AB8500_DASLOTCONF6_DAI8TOADO6,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 7 Loopback Switch",
+		AB8500_DASLOTCONF7, AB8500_DASLOTCONF7_DAI8TOADO7,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 8 Loopback Switch",
+		AB8500_DASLOTCONF8, AB8500_DASLOTCONF8_DAI7TOADO8,
+		1, 0),
+
+	/* Digital interface - Burst FIFO */
+	SOC_SINGLE("Digital Interface 0 FIFO Enable Switch",
+		AB8500_DIGIFCONF3, AB8500_DIGIFCONF3_IF0BFIFOEN,
+		1, 0),
+	SOC_ENUM("Burst FIFO Mask", soc_enum_bfifomask),
+	SOC_ENUM("Burst FIFO Bit-clock Frequency", soc_enum_bfifo19m2),
+	SOC_SINGLE("Burst FIFO Threshold",
+		AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFOINT_SHIFT,
+		AB8500_FIFOCONF1_BFIFOINT_MAX, 0),
+	SOC_SINGLE("Burst FIFO Length",
+		AB8500_FIFOCONF2, AB8500_FIFOCONF2_BFIFOTX_SHIFT,
+		AB8500_FIFOCONF2_BFIFOTX_MAX, 0),
+	SOC_SINGLE("Burst FIFO EOS Extra Slots",
+		AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOEXSL_SHIFT,
+		AB8500_FIFOCONF3_BFIFOEXSL_MAX, 0),
+	SOC_SINGLE("Burst FIFO FS Extra Bit-clocks",
+		AB8500_FIFOCONF3, AB8500_FIFOCONF3_PREBITCLK0_SHIFT,
+		AB8500_FIFOCONF3_PREBITCLK0_MAX, 0),
+	SOC_ENUM("Burst FIFO Interface Mode", soc_enum_bfifomast),
+
+	SOC_SINGLE("Burst FIFO Interface Switch",
+		AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFORUN_SHIFT,
+		1, 0),
+	SOC_SINGLE("Burst FIFO Switch Frame Number",
+		AB8500_FIFOCONF4, AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT,
+		AB8500_FIFOCONF4_BFIFOFRAMSW_MAX, 0),
+	SOC_SINGLE("Burst FIFO Wake Up Delay",
+		AB8500_FIFOCONF5, AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT,
+		AB8500_FIFOCONF5_BFIFOWAKEUP_MAX, 0),
+	SOC_SINGLE("Burst FIFO Samples In FIFO",
+		AB8500_FIFOCONF6, AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT,
+		AB8500_FIFOCONF6_BFIFOSAMPLE_MAX, 0),
+
+	/* ANC */
+	SOC_ENUM_EXT("ANC Status", soc_enum_ancstate,
+		anc_status_control_get, anc_status_control_put),
+	SOC_SINGLE_XR_SX("ANC Warp Delay Shift",
+		AB8500_ANCCONF2, 1, AB8500_ANCCONF2_SHIFT,
+		AB8500_ANCCONF2_MIN, AB8500_ANCCONF2_MAX, 0),
+	SOC_SINGLE_XR_SX("ANC FIR Output Shift",
+		AB8500_ANCCONF3, 1, AB8500_ANCCONF3_SHIFT,
+		AB8500_ANCCONF3_MIN, AB8500_ANCCONF3_MAX, 0),
+	SOC_SINGLE_XR_SX("ANC IIR Output Shift",
+		AB8500_ANCCONF4, 1, AB8500_ANCCONF4_SHIFT,
+		AB8500_ANCCONF4_MIN, AB8500_ANCCONF4_MAX, 0),
+	SOC_SINGLE_XR_SX("ANC Warp Delay",
+		AB8500_ANCCONF9, 2, AB8500_ANC_WARP_DELAY_SHIFT,
+		AB8500_ANC_WARP_DELAY_MIN, AB8500_ANC_WARP_DELAY_MAX, 0),
+
+	/* Sidetone */
+	SOC_ENUM_EXT("Sidetone Status", soc_enum_sidstate,
+		sid_status_control_get, sid_status_control_put),
+	SOC_SINGLE_STROBE("Sidetone Reset",
+		AB8500_SIDFIRADR, AB8500_SIDFIRADR_FIRSIDSET, 0),
+};
+
+static struct snd_kcontrol_new ab8500_filter_controls[] = {
+	AB8500_FILTER_CONTROL("ANC FIR Coefficients", AB8500_ANC_FIR_COEFFS,
+		AB8500_ANC_FIR_COEFF_MIN, AB8500_ANC_FIR_COEFF_MAX),
+	AB8500_FILTER_CONTROL("ANC IIR Coefficients", AB8500_ANC_IIR_COEFFS,
+		AB8500_ANC_IIR_COEFF_MIN, AB8500_ANC_IIR_COEFF_MAX),
+	AB8500_FILTER_CONTROL("Sidetone FIR Coefficients",
+			AB8500_SID_FIR_COEFFS, AB8500_SID_FIR_COEFF_MIN,
+			AB8500_SID_FIR_COEFF_MAX)
+};
+enum ab8500_filter {
+	AB8500_FILTER_ANC_FIR = 0,
+	AB8500_FILTER_ANC_IIR = 1,
+	AB8500_FILTER_SID_FIR = 2,
+};
+
+/*
+ * Extended interface for codec-driver
+ */
+
+static int ab8500_audio_init_audioblock(struct snd_soc_codec *codec)
+{
+	int status;
+
+	dev_dbg(codec->dev, "%s: Enter.\n", __func__);
+
+	/* Reset audio-registers and disable 32kHz-clock output 2 */
+	status = ab8500_sysctrl_write(AB8500_STW4500CTRL3,
+				AB8500_STW4500CTRL3_CLK32KOUT2DIS |
+					AB8500_STW4500CTRL3_RESETAUDN,
+				AB8500_STW4500CTRL3_RESETAUDN);
+	if (status < 0)
+		return status;
+
+	return 0;
+}
+
+static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
+			struct amic_settings *amics)
+{
+	u8 value8;
+	unsigned int value;
+	int status;
+	const struct snd_soc_dapm_route *route;
+
+	dev_dbg(codec->dev, "%s: Enter.\n", __func__);
+
+	/* Set DMic-clocks to outputs */
+	status = abx500_get_register_interruptible(codec->dev, (u8)AB8500_MISC,
+						(u8)AB8500_GPIO_DIR4_REG,
+						&value8);
+	if (status < 0)
+		return status;
+	value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT |
+		GPIO31_DIR_OUTPUT;
+	status = abx500_set_register_interruptible(codec->dev,
+						(u8)AB8500_MISC,
+						(u8)AB8500_GPIO_DIR4_REG,
+						value);
+	if (status < 0)
+		return status;
+
+	/* Attach regulators to AMic DAPM-paths */
+	dev_dbg(codec->dev, "%s: Mic 1a regulator: %s\n", __func__,
+		amic_micbias_str(amics->mic1a_micbias));
+	route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias];
+	status = snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+	dev_dbg(codec->dev, "%s: Mic 1b regulator: %s\n", __func__,
+		amic_micbias_str(amics->mic1b_micbias));
+	route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias];
+	status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+	dev_dbg(codec->dev, "%s: Mic 2 regulator: %s\n", __func__,
+		amic_micbias_str(amics->mic2_micbias));
+	route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias];
+	status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+	if (status < 0) {
+		dev_err(codec->dev,
+			"%s: Failed to add AMic-regulator DAPM-routes (%d).\n",
+			__func__, status);
+		return status;
+	}
+
+	/* Set AMic-configuration */
+	dev_dbg(codec->dev, "%s: Mic 1 mic-type: %s\n", __func__,
+		amic_type_str(amics->mic1_type));
+	snd_soc_update_bits(codec, AB8500_ANAGAIN1, AB8500_ANAGAINX_ENSEMICX,
+			amics->mic1_type == AMIC_TYPE_DIFFERENTIAL ?
+				0 : AB8500_ANAGAINX_ENSEMICX);
+	dev_dbg(codec->dev, "%s: Mic 2 mic-type: %s\n", __func__,
+		amic_type_str(amics->mic2_type));
+	snd_soc_update_bits(codec, AB8500_ANAGAIN2, AB8500_ANAGAINX_ENSEMICX,
+			amics->mic2_type == AMIC_TYPE_DIFFERENTIAL ?
+				0 : AB8500_ANAGAINX_ENSEMICX);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ab8500_audio_setup_mics);
+
+static int ab8500_audio_set_ear_cmv(struct snd_soc_codec *codec,
+				enum ear_cm_voltage ear_cmv)
+{
+	char *cmv_str;
+
+	switch (ear_cmv) {
+	case EAR_CMV_0_95V:
+		cmv_str = "0.95V";
+		break;
+	case EAR_CMV_1_10V:
+		cmv_str = "1.10V";
+		break;
+	case EAR_CMV_1_27V:
+		cmv_str = "1.27V";
+		break;
+	case EAR_CMV_1_58V:
+		cmv_str = "1.58V";
+		break;
+	default:
+		dev_err(codec->dev,
+			"%s: Unknown earpiece CM-voltage (%d)!\n",
+			__func__, (int)ear_cmv);
+		return -EINVAL;
+	}
+	dev_dbg(codec->dev, "%s: Earpiece CM-voltage: %s\n", __func__,
+		cmv_str);
+	snd_soc_update_bits(codec, AB8500_ANACONF1, AB8500_ANACONF1_EARSELCM,
+			ear_cmv);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ab8500_audio_set_ear_cmv);
+
+static int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai,
+				unsigned int delay)
+{
+	unsigned int mask, val;
+	struct snd_soc_codec *codec = dai->codec;
+
+	mask = BIT(AB8500_DIGIFCONF2_IF0DEL);
+	val = 0;
+
+	switch (delay) {
+	case 0:
+		break;
+	case 1:
+		val |= BIT(AB8500_DIGIFCONF2_IF0DEL);
+		break;
+	default:
+		dev_err(dai->codec->dev,
+			"%s: ERROR: Unsupported bit-delay (0x%x)!\n",
+			__func__, delay);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->codec->dev, "%s: IF0 Bit-delay: %d bits.\n",
+		__func__, delay);
+	snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val);
+
+	return 0;
+}
+
+/* Gates clocking according format mask */
+static int ab8500_codec_set_dai_clock_gate(struct snd_soc_codec *codec,
+					unsigned int fmt)
+{
+	unsigned int mask;
+	unsigned int val;
+
+	mask = BIT(AB8500_DIGIFCONF1_ENMASTGEN) |
+			BIT(AB8500_DIGIFCONF1_ENFSBITCLK0);
+
+	val = BIT(AB8500_DIGIFCONF1_ENMASTGEN);
+
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+	case SND_SOC_DAIFMT_CONT: /* continuous clock */
+		dev_dbg(codec->dev, "%s: IF0 Clock is continuous.\n",
+			__func__);
+		val |= BIT(AB8500_DIGIFCONF1_ENFSBITCLK0);
+		break;
+	case SND_SOC_DAIFMT_GATED: /* clock is gated */
+		dev_dbg(codec->dev, "%s: IF0 Clock is gated.\n",
+			__func__);
+		break;
+	default:
+		dev_err(codec->dev,
+			"%s: ERROR: Unsupported clock mask (0x%x)!\n",
+			__func__, fmt & SND_SOC_DAIFMT_CLOCK_MASK);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val);
+
+	return 0;
+}
+
+static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	unsigned int mask;
+	unsigned int val;
+	struct snd_soc_codec *codec = dai->codec;
+	int status;
+
+	dev_dbg(codec->dev, "%s: Enter (fmt = 0x%x)\n", __func__, fmt);
+
+	mask = BIT(AB8500_DIGIFCONF3_IF1DATOIF0AD) |
+			BIT(AB8500_DIGIFCONF3_IF1CLKTOIF0CLK) |
+			BIT(AB8500_DIGIFCONF3_IF0BFIFOEN) |
+			BIT(AB8500_DIGIFCONF3_IF0MASTER);
+	val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */
+		dev_dbg(dai->codec->dev,
+			"%s: IF0 Master-mode: AB8500 master.\n", __func__);
+		val |= BIT(AB8500_DIGIFCONF3_IF0MASTER);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */
+		dev_dbg(dai->codec->dev,
+			"%s: IF0 Master-mode: AB8500 slave.\n", __func__);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */
+	case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
+		dev_err(dai->codec->dev,
+			"%s: ERROR: The device is either a master or a slave.\n",
+			__func__);
+	default:
+		dev_err(dai->codec->dev,
+			"%s: ERROR: Unsupporter master mask 0x%x\n",
+			__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+		return -EINVAL;
+		break;
+	}
+
+	snd_soc_update_bits(codec, AB8500_DIGIFCONF3, mask, val);
+
+	/* Set clock gating */
+	status = ab8500_codec_set_dai_clock_gate(codec, fmt);
+	if (status) {
+		dev_err(dai->codec->dev,
+			"%s: ERRROR: Failed to set clock gate (%d).\n",
+			__func__, status);
+		return status;
+	}
+
+	/* Setting data transfer format */
+
+	mask = BIT(AB8500_DIGIFCONF2_IF0FORMAT0) |
+		BIT(AB8500_DIGIFCONF2_IF0FORMAT1) |
+		BIT(AB8500_DIGIFCONF2_FSYNC0P) |
+		BIT(AB8500_DIGIFCONF2_BITCLK0P);
+	val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S: /* I2S mode */
+		dev_dbg(dai->codec->dev, "%s: IF0 Protocol: I2S\n", __func__);
+		val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT1);
+		ab8500_audio_set_bit_delay(dai, 0);
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */
+		dev_dbg(dai->codec->dev,
+			"%s: IF0 Protocol: DSP A (TDM)\n", __func__);
+		val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0);
+		ab8500_audio_set_bit_delay(dai, 1);
+		break;
+
+	case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */
+		dev_dbg(dai->codec->dev,
+			"%s: IF0 Protocol: DSP B (TDM)\n", __func__);
+		val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0);
+		ab8500_audio_set_bit_delay(dai, 0);
+		break;
+
+	default:
+		dev_err(dai->codec->dev,
+			"%s: ERROR: Unsupported format (0x%x)!\n",
+			__func__, fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
+		dev_dbg(dai->codec->dev,
+			"%s: IF0: Normal bit clock, normal frame\n",
+			__func__);
+		break;
+	case SND_SOC_DAIFMT_NB_IF: /* normal BCLK + inv FRM */
+		dev_dbg(dai->codec->dev,
+			"%s: IF0: Normal bit clock, inverted frame\n",
+			__func__);
+		val |= BIT(AB8500_DIGIFCONF2_FSYNC0P);
+		break;
+	case SND_SOC_DAIFMT_IB_NF: /* invert BCLK + nor FRM */
+		dev_dbg(dai->codec->dev,
+			"%s: IF0: Inverted bit clock, normal frame\n",
+			__func__);
+		val |= BIT(AB8500_DIGIFCONF2_BITCLK0P);
+		break;
+	case SND_SOC_DAIFMT_IB_IF: /* invert BCLK + FRM */
+		dev_dbg(dai->codec->dev,
+			"%s: IF0: Inverted bit clock, inverted frame\n",
+			__func__);
+		val |= BIT(AB8500_DIGIFCONF2_FSYNC0P);
+		val |= BIT(AB8500_DIGIFCONF2_BITCLK0P);
+		break;
+	default:
+		dev_err(dai->codec->dev,
+			"%s: ERROR: Unsupported INV mask 0x%x\n",
+			__func__, fmt & SND_SOC_DAIFMT_INV_MASK);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val);
+
+	return 0;
+}
+
+static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
+		unsigned int tx_mask, unsigned int rx_mask,
+		int slots, int slot_width)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int val, mask, slots_active;
+
+	mask = BIT(AB8500_DIGIFCONF2_IF0WL0) |
+		BIT(AB8500_DIGIFCONF2_IF0WL1);
+	val = 0;
+
+	switch (slot_width) {
+	case 16:
+		break;
+	case 20:
+		val |= BIT(AB8500_DIGIFCONF2_IF0WL0);
+		break;
+	case 24:
+		val |= BIT(AB8500_DIGIFCONF2_IF0WL1);
+		break;
+	case 32:
+		val |= BIT(AB8500_DIGIFCONF2_IF0WL1) |
+			BIT(AB8500_DIGIFCONF2_IF0WL0);
+		break;
+	default:
+		dev_err(dai->codec->dev, "%s: Unsupported slot-width 0x%x\n",
+			__func__, slot_width);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->codec->dev, "%s: IF0 slot-width: %d bits.\n",
+		__func__, slot_width);
+	snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val);
+
+	/* Setup TDM clocking according to slot count */
+	dev_dbg(dai->codec->dev, "%s: Slots, total: %d\n", __func__, slots);
+	mask = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) |
+			BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
+	switch (slots) {
+	case 2:
+		val = AB8500_MASK_NONE;
+		break;
+	case 4:
+		val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0);
+		break;
+	case 8:
+		val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
+		break;
+	case 16:
+		val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) |
+			BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
+		break;
+	default:
+		dev_err(dai->codec->dev,
+			"%s: ERROR: Unsupported number of slots (%d)!\n",
+			__func__, slots);
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val);
+
+	/* Setup TDM DA according to active tx slots */
+	mask = AB8500_DASLOTCONFX_SLTODAX_MASK;
+	slots_active = hweight32(tx_mask);
+	dev_dbg(dai->codec->dev, "%s: Slots, active, TX: %d\n", __func__,
+		slots_active);
+	switch (slots_active) {
+	case 0:
+		break;
+	case 1:
+		/* Slot 9 -> DA_IN1 & DA_IN3 */
+		snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 11);
+		snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 11);
+		snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11);
+		snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11);
+		break;
+	case 2:
+		/* Slot 9 -> DA_IN1 & DA_IN3, Slot 11 -> DA_IN2 & DA_IN4 */
+		snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 9);
+		snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 9);
+		snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11);
+		snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11);
+
+		break;
+	case 8:
+		dev_dbg(dai->codec->dev,
+			"%s: In 8-channel mode DA-from-slot mapping is set manually.",
+			__func__);
+		break;
+	default:
+		dev_err(dai->codec->dev,
+			"%s: Unsupported number of active TX-slots (%d)!\n",
+			__func__, slots_active);
+		return -EINVAL;
+	}
+
+	/* Setup TDM AD according to active RX-slots */
+	slots_active = hweight32(rx_mask);
+	dev_dbg(dai->codec->dev, "%s: Slots, active, RX: %d\n", __func__,
+		slots_active);
+	switch (slots_active) {
+	case 0:
+		break;
+	case 1:
+		/* AD_OUT3 -> slot 0 & 1 */
+		snd_soc_update_bits(codec, AB8500_ADSLOTSEL1, AB8500_MASK_ALL,
+				AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN |
+				AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD);
+		break;
+	case 2:
+		/* AD_OUT3 -> slot 0, AD_OUT2 -> slot 1 */
+		snd_soc_update_bits(codec,
+				AB8500_ADSLOTSEL1,
+				AB8500_MASK_ALL,
+				AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN |
+				AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD);
+		break;
+	case 8:
+		dev_dbg(dai->codec->dev,
+			"%s: In 8-channel mode AD-to-slot mapping is set manually.",
+			__func__);
+		break;
+	default:
+		dev_err(dai->codec->dev,
+			"%s: Unsupported number of active RX-slots (%d)!\n",
+			__func__, slots_active);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct snd_soc_dai_driver ab8500_codec_dai[] = {
+	{
+		.name = "ab8500-codec-dai.0",
+		.id = 0,
+		.playback = {
+			.stream_name = "ab8500_0p",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = AB8500_SUPPORTED_RATE,
+			.formats = AB8500_SUPPORTED_FMT,
+		},
+		.ops = (struct snd_soc_dai_ops[]) {
+			{
+				.set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
+				.set_fmt = ab8500_codec_set_dai_fmt,
+			}
+		},
+		.symmetric_rates = 1
+	},
+	{
+		.name = "ab8500-codec-dai.1",
+		.id = 1,
+		.capture = {
+			.stream_name = "ab8500_0c",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = AB8500_SUPPORTED_RATE,
+			.formats = AB8500_SUPPORTED_FMT,
+		},
+		.ops = (struct snd_soc_dai_ops[]) {
+			{
+				.set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
+				.set_fmt = ab8500_codec_set_dai_fmt,
+			}
+		},
+		.symmetric_rates = 1
+	}
+};
+
+static int ab8500_codec_probe(struct snd_soc_codec *codec)
+{
+	struct device *dev = codec->dev;
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
+	struct ab8500_platform_data *pdata;
+	struct filter_control *fc;
+	int status;
+
+	dev_dbg(dev, "%s: Enter.\n", __func__);
+
+	/* Setup AB8500 according to board-settings */
+	pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent);
+	status = ab8500_audio_setup_mics(codec, &pdata->codec->amics);
+	if (status < 0) {
+		pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
+		return status;
+	}
+	status = ab8500_audio_set_ear_cmv(codec, pdata->codec->ear_cmv);
+	if (status < 0) {
+		pr_err("%s: Failed to set earpiece CM-voltage (%d)!\n",
+			__func__, status);
+		return status;
+	}
+
+	status = ab8500_audio_init_audioblock(codec);
+	if (status < 0) {
+		dev_err(dev, "%s: failed to init audio-block (%d)!\n",
+			__func__, status);
+		return status;
+	}
+
+	/* Override HW-defaults */
+	ab8500_codec_write_reg(codec,
+				AB8500_ANACONF5,
+				BIT(AB8500_ANACONF5_HSAUTOEN));
+	ab8500_codec_write_reg(codec,
+				AB8500_SHORTCIRCONF,
+				BIT(AB8500_SHORTCIRCONF_HSZCDDIS));
+
+	/* Add filter controls */
+	status = snd_soc_add_codec_controls(codec, ab8500_filter_controls,
+				ARRAY_SIZE(ab8500_filter_controls));
+	if (status < 0) {
+		dev_err(dev,
+			"%s: failed to add ab8500 filter controls (%d).\n",
+			__func__, status);
+		return status;
+	}
+	fc = (struct filter_control *)
+		&ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value;
+	drvdata->anc_fir_values = (long *)fc->value;
+	fc = (struct filter_control *)
+		&ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value;
+	drvdata->anc_iir_values = (long *)fc->value;
+	fc = (struct filter_control *)
+		&ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
+	drvdata->sid_fir_values = (long *)fc->value;
+
+	(void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
+
+	mutex_init(&drvdata->anc_lock);
+
+	return status;
+}
+
+static struct snd_soc_codec_driver ab8500_codec_driver = {
+	.probe =		ab8500_codec_probe,
+	.read =			ab8500_codec_read_reg,
+	.write =		ab8500_codec_write_reg,
+	.reg_word_size =	sizeof(u8),
+	.controls =		ab8500_ctrls,
+	.num_controls =		ARRAY_SIZE(ab8500_ctrls),
+	.dapm_widgets =		ab8500_dapm_widgets,
+	.num_dapm_widgets =	ARRAY_SIZE(ab8500_dapm_widgets),
+	.dapm_routes =		ab8500_dapm_routes,
+	.num_dapm_routes =	ARRAY_SIZE(ab8500_dapm_routes),
+};
+
+static int __devinit ab8500_codec_driver_probe(struct platform_device *pdev)
+{
+	int status;
+	struct ab8500_codec_drvdata *drvdata;
+
+	dev_dbg(&pdev->dev, "%s: Enter.\n", __func__);
+
+	/* Create driver private-data struct */
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_codec_drvdata),
+			GFP_KERNEL);
+	drvdata->sid_status = SID_UNCONFIGURED;
+	drvdata->anc_status = ANC_UNCONFIGURED;
+	dev_set_drvdata(&pdev->dev, drvdata);
+
+	dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__);
+	status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver,
+				ab8500_codec_dai,
+				ARRAY_SIZE(ab8500_codec_dai));
+	if (status < 0)
+		dev_err(&pdev->dev,
+			"%s: Error: Failed to register codec (%d).\n",
+			__func__, status);
+
+	return status;
+}
+
+static int __devexit ab8500_codec_driver_remove(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s Enter.\n", __func__);
+
+	snd_soc_unregister_codec(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver ab8500_codec_platform_driver = {
+	.driver	= {
+		.name	= "ab8500-codec",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ab8500_codec_driver_probe,
+	.remove		= __devexit_p(ab8500_codec_driver_remove),
+	.suspend	= NULL,
+	.resume		= NULL,
+};
+module_platform_driver(ab8500_codec_platform_driver);
+
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ab8500-codec.h b/sound/soc/codecs/ab8500-codec.h
new file mode 100644
index 0000000..114f69a
--- /dev/null
+++ b/sound/soc/codecs/ab8500-codec.h
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>,
+ *         for ST-Ericsson.
+ *
+ *         Based on the early work done by:
+ *         Mikko J. Lehto <mikko.lehto@symbio.com>,
+ *         Mikko Sarmanne <mikko.sarmanne@symbio.com>,
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can 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 AB8500_CODEC_REGISTERS_H
+#define AB8500_CODEC_REGISTERS_H
+
+#define AB8500_SUPPORTED_RATE			(SNDRV_PCM_RATE_48000)
+#define AB8500_SUPPORTED_FMT			(SNDRV_PCM_FMTBIT_S16_LE)
+
+/* AB8500 audio bank (0x0d) register definitions */
+
+#define AB8500_POWERUP				0x00
+#define AB8500_AUDSWRESET			0x01
+#define AB8500_ADPATHENA			0x02
+#define AB8500_DAPATHENA			0x03
+#define AB8500_ANACONF1				0x04
+#define AB8500_ANACONF2				0x05
+#define AB8500_DIGMICCONF			0x06
+#define AB8500_ANACONF3				0x07
+#define AB8500_ANACONF4				0x08
+#define AB8500_DAPATHCONF			0x09
+#define AB8500_MUTECONF				0x0A
+#define AB8500_SHORTCIRCONF			0x0B
+#define AB8500_ANACONF5				0x0C
+#define AB8500_ENVCPCONF			0x0D
+#define AB8500_SIGENVCONF			0x0E
+#define AB8500_PWMGENCONF1			0x0F
+#define AB8500_PWMGENCONF2			0x10
+#define AB8500_PWMGENCONF3			0x11
+#define AB8500_PWMGENCONF4			0x12
+#define AB8500_PWMGENCONF5			0x13
+#define AB8500_ANAGAIN1				0x14
+#define AB8500_ANAGAIN2				0x15
+#define AB8500_ANAGAIN3				0x16
+#define AB8500_ANAGAIN4				0x17
+#define AB8500_DIGLINHSLGAIN			0x18
+#define AB8500_DIGLINHSRGAIN			0x19
+#define AB8500_ADFILTCONF			0x1A
+#define AB8500_DIGIFCONF1			0x1B
+#define AB8500_DIGIFCONF2			0x1C
+#define AB8500_DIGIFCONF3			0x1D
+#define AB8500_DIGIFCONF4			0x1E
+#define AB8500_ADSLOTSEL1			0x1F
+#define AB8500_ADSLOTSEL2			0x20
+#define AB8500_ADSLOTSEL3			0x21
+#define AB8500_ADSLOTSEL4			0x22
+#define AB8500_ADSLOTSEL5			0x23
+#define AB8500_ADSLOTSEL6			0x24
+#define AB8500_ADSLOTSEL7			0x25
+#define AB8500_ADSLOTSEL8			0x26
+#define AB8500_ADSLOTSEL9			0x27
+#define AB8500_ADSLOTSEL10			0x28
+#define AB8500_ADSLOTSEL11			0x29
+#define AB8500_ADSLOTSEL12			0x2A
+#define AB8500_ADSLOTSEL13			0x2B
+#define AB8500_ADSLOTSEL14			0x2C
+#define AB8500_ADSLOTSEL15			0x2D
+#define AB8500_ADSLOTSEL16			0x2E
+#define AB8500_ADSLOTHIZCTRL1			0x2F
+#define AB8500_ADSLOTHIZCTRL2			0x30
+#define AB8500_ADSLOTHIZCTRL3			0x31
+#define AB8500_ADSLOTHIZCTRL4			0x32
+#define AB8500_DASLOTCONF1			0x33
+#define AB8500_DASLOTCONF2			0x34
+#define AB8500_DASLOTCONF3			0x35
+#define AB8500_DASLOTCONF4			0x36
+#define AB8500_DASLOTCONF5			0x37
+#define AB8500_DASLOTCONF6			0x38
+#define AB8500_DASLOTCONF7			0x39
+#define AB8500_DASLOTCONF8			0x3A
+#define AB8500_CLASSDCONF1			0x3B
+#define AB8500_CLASSDCONF2			0x3C
+#define AB8500_CLASSDCONF3			0x3D
+#define AB8500_DMICFILTCONF			0x3E
+#define AB8500_DIGMULTCONF1			0x3F
+#define AB8500_DIGMULTCONF2			0x40
+#define AB8500_ADDIGGAIN1			0x41
+#define AB8500_ADDIGGAIN2			0x42
+#define AB8500_ADDIGGAIN3			0x43
+#define AB8500_ADDIGGAIN4			0x44
+#define AB8500_ADDIGGAIN5			0x45
+#define AB8500_ADDIGGAIN6			0x46
+#define AB8500_DADIGGAIN1			0x47
+#define AB8500_DADIGGAIN2			0x48
+#define AB8500_DADIGGAIN3			0x49
+#define AB8500_DADIGGAIN4			0x4A
+#define AB8500_DADIGGAIN5			0x4B
+#define AB8500_DADIGGAIN6			0x4C
+#define AB8500_ADDIGLOOPGAIN1			0x4D
+#define AB8500_ADDIGLOOPGAIN2			0x4E
+#define AB8500_HSLEARDIGGAIN			0x4F
+#define AB8500_HSRDIGGAIN			0x50
+#define AB8500_SIDFIRGAIN1			0x51
+#define AB8500_SIDFIRGAIN2			0x52
+#define AB8500_ANCCONF1				0x53
+#define AB8500_ANCCONF2				0x54
+#define AB8500_ANCCONF3				0x55
+#define AB8500_ANCCONF4				0x56
+#define AB8500_ANCCONF5				0x57
+#define AB8500_ANCCONF6				0x58
+#define AB8500_ANCCONF7				0x59
+#define AB8500_ANCCONF8				0x5A
+#define AB8500_ANCCONF9				0x5B
+#define AB8500_ANCCONF10			0x5C
+#define AB8500_ANCCONF11			0x5D
+#define AB8500_ANCCONF12			0x5E
+#define AB8500_ANCCONF13			0x5F
+#define AB8500_ANCCONF14			0x60
+#define AB8500_SIDFIRADR			0x61
+#define AB8500_SIDFIRCOEF1			0x62
+#define AB8500_SIDFIRCOEF2			0x63
+#define AB8500_SIDFIRCONF			0x64
+#define AB8500_AUDINTMASK1			0x65
+#define AB8500_AUDINTSOURCE1			0x66
+#define AB8500_AUDINTMASK2			0x67
+#define AB8500_AUDINTSOURCE2			0x68
+#define AB8500_FIFOCONF1			0x69
+#define AB8500_FIFOCONF2			0x6A
+#define AB8500_FIFOCONF3			0x6B
+#define AB8500_FIFOCONF4			0x6C
+#define AB8500_FIFOCONF5			0x6D
+#define AB8500_FIFOCONF6			0x6E
+#define AB8500_AUDREV				0x6F
+
+#define AB8500_FIRST_REG			AB8500_POWERUP
+#define AB8500_LAST_REG				AB8500_AUDREV
+#define AB8500_CACHEREGNUM			(AB8500_LAST_REG + 1)
+
+#define AB8500_MASK_ALL				0xFF
+#define AB8500_MASK_NONE			0x00
+
+/* AB8500_POWERUP */
+#define AB8500_POWERUP_POWERUP			7
+#define AB8500_POWERUP_ENANA			3
+
+/* AB8500_AUDSWRESET */
+#define AB8500_AUDSWRESET_SWRESET		7
+
+/* AB8500_ADPATHENA */
+#define AB8500_ADPATHENA_ENAD12			7
+#define AB8500_ADPATHENA_ENAD34			5
+#define AB8500_ADPATHENA_ENAD5768		3
+
+/* AB8500_DAPATHENA */
+#define AB8500_DAPATHENA_ENDA1			7
+#define AB8500_DAPATHENA_ENDA2			6
+#define AB8500_DAPATHENA_ENDA3			5
+#define AB8500_DAPATHENA_ENDA4			4
+#define AB8500_DAPATHENA_ENDA5			3
+#define AB8500_DAPATHENA_ENDA6			2
+
+/* AB8500_ANACONF1 */
+#define AB8500_ANACONF1_HSLOWPOW		7
+#define AB8500_ANACONF1_DACLOWPOW1		6
+#define AB8500_ANACONF1_DACLOWPOW0		5
+#define AB8500_ANACONF1_EARDACLOWPOW		4
+#define AB8500_ANACONF1_EARSELCM		2
+#define AB8500_ANACONF1_HSHPEN			1
+#define AB8500_ANACONF1_EARDRVLOWPOW		0
+
+/* AB8500_ANACONF2 */
+#define AB8500_ANACONF2_ENMIC1			7
+#define AB8500_ANACONF2_ENMIC2			6
+#define AB8500_ANACONF2_ENLINL			5
+#define AB8500_ANACONF2_ENLINR			4
+#define AB8500_ANACONF2_MUTMIC1			3
+#define AB8500_ANACONF2_MUTMIC2			2
+#define AB8500_ANACONF2_MUTLINL			1
+#define AB8500_ANACONF2_MUTLINR			0
+
+/* AB8500_DIGMICCONF */
+#define AB8500_DIGMICCONF_ENDMIC1		7
+#define AB8500_DIGMICCONF_ENDMIC2		6
+#define AB8500_DIGMICCONF_ENDMIC3		5
+#define AB8500_DIGMICCONF_ENDMIC4		4
+#define AB8500_DIGMICCONF_ENDMIC5		3
+#define AB8500_DIGMICCONF_ENDMIC6		2
+#define AB8500_DIGMICCONF_HSFADSPEED		0
+
+/* AB8500_ANACONF3 */
+#define AB8500_ANACONF3_MIC1SEL			7
+#define AB8500_ANACONF3_LINRSEL			6
+#define AB8500_ANACONF3_ENDRVHSL		5
+#define AB8500_ANACONF3_ENDRVHSR		4
+#define AB8500_ANACONF3_ENADCMIC		2
+#define AB8500_ANACONF3_ENADCLINL		1
+#define AB8500_ANACONF3_ENADCLINR		0
+
+/* AB8500_ANACONF4 */
+#define AB8500_ANACONF4_DISPDVSS		7
+#define AB8500_ANACONF4_ENEAR			6
+#define AB8500_ANACONF4_ENHSL			5
+#define AB8500_ANACONF4_ENHSR			4
+#define AB8500_ANACONF4_ENHFL			3
+#define AB8500_ANACONF4_ENHFR			2
+#define AB8500_ANACONF4_ENVIB1			1
+#define AB8500_ANACONF4_ENVIB2			0
+
+/* AB8500_DAPATHCONF */
+#define AB8500_DAPATHCONF_ENDACEAR		6
+#define AB8500_DAPATHCONF_ENDACHSL		5
+#define AB8500_DAPATHCONF_ENDACHSR		4
+#define AB8500_DAPATHCONF_ENDACHFL		3
+#define AB8500_DAPATHCONF_ENDACHFR		2
+#define AB8500_DAPATHCONF_ENDACVIB1		1
+#define AB8500_DAPATHCONF_ENDACVIB2		0
+
+/* AB8500_MUTECONF */
+#define AB8500_MUTECONF_MUTEAR			6
+#define AB8500_MUTECONF_MUTHSL			5
+#define AB8500_MUTECONF_MUTHSR			4
+#define AB8500_MUTECONF_MUTDACEAR		2
+#define AB8500_MUTECONF_MUTDACHSL		1
+#define AB8500_MUTECONF_MUTDACHSR		0
+
+/* AB8500_SHORTCIRCONF */
+#define AB8500_SHORTCIRCONF_ENSHORTPWD		7
+#define AB8500_SHORTCIRCONF_EARSHORTDIS		6
+#define AB8500_SHORTCIRCONF_HSSHORTDIS		5
+#define AB8500_SHORTCIRCONF_HSPULLDEN		4
+#define AB8500_SHORTCIRCONF_HSOSCEN		2
+#define AB8500_SHORTCIRCONF_HSFADDIS		1
+#define AB8500_SHORTCIRCONF_HSZCDDIS		0
+/* Zero cross should be disabled */
+
+/* AB8500_ANACONF5 */
+#define AB8500_ANACONF5_ENCPHS			7
+#define AB8500_ANACONF5_HSLDACTOLOL		5
+#define AB8500_ANACONF5_HSRDACTOLOR		4
+#define AB8500_ANACONF5_ENLOL			3
+#define AB8500_ANACONF5_ENLOR			2
+#define AB8500_ANACONF5_HSAUTOEN		0
+
+/* AB8500_ENVCPCONF */
+#define AB8500_ENVCPCONF_ENVDETHTHRE		4
+#define AB8500_ENVCPCONF_ENVDETLTHRE		0
+#define AB8500_ENVCPCONF_ENVDETHTHRE_MAX	0x0F
+#define AB8500_ENVCPCONF_ENVDETLTHRE_MAX	0x0F
+
+/* AB8500_SIGENVCONF */
+#define AB8500_SIGENVCONF_CPLVEN		5
+#define AB8500_SIGENVCONF_ENVDETCPEN		4
+#define AB8500_SIGENVCONF_ENVDETTIME		0
+#define AB8500_SIGENVCONF_ENVDETTIME_MAX	0x0F
+
+/* AB8500_PWMGENCONF1 */
+#define AB8500_PWMGENCONF1_PWMTOVIB1		7
+#define AB8500_PWMGENCONF1_PWMTOVIB2		6
+#define AB8500_PWMGENCONF1_PWM1CTRL		5
+#define AB8500_PWMGENCONF1_PWM2CTRL		4
+#define AB8500_PWMGENCONF1_PWM1NCTRL		3
+#define AB8500_PWMGENCONF1_PWM1PCTRL		2
+#define AB8500_PWMGENCONF1_PWM2NCTRL		1
+#define AB8500_PWMGENCONF1_PWM2PCTRL		0
+
+/* AB8500_PWMGENCONF2 */
+/* AB8500_PWMGENCONF3 */
+/* AB8500_PWMGENCONF4 */
+/* AB8500_PWMGENCONF5 */
+#define AB8500_PWMGENCONFX_PWMVIBXPOL		7
+#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC	0
+#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX	0x64
+
+/* AB8500_ANAGAIN1 */
+/* AB8500_ANAGAIN2 */
+#define AB8500_ANAGAINX_ENSEMICX		7
+#define AB8500_ANAGAINX_LOWPOWMICX		6
+#define AB8500_ANAGAINX_MICXGAIN		0
+#define AB8500_ANAGAINX_MICXGAIN_MAX		0x1F
+
+/* AB8500_ANAGAIN3 */
+#define AB8500_ANAGAIN3_HSLGAIN			4
+#define AB8500_ANAGAIN3_HSRGAIN			0
+#define AB8500_ANAGAIN3_HSXGAIN_MAX		0x0F
+
+/* AB8500_ANAGAIN4 */
+#define AB8500_ANAGAIN4_LINLGAIN		4
+#define AB8500_ANAGAIN4_LINRGAIN		0
+#define AB8500_ANAGAIN4_LINXGAIN_MAX		0x0F
+
+/* AB8500_DIGLINHSLGAIN */
+/* AB8500_DIGLINHSRGAIN */
+#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN	0
+#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX	0x13
+
+/* AB8500_ADFILTCONF */
+#define AB8500_ADFILTCONF_AD1NH			7
+#define AB8500_ADFILTCONF_AD2NH			6
+#define AB8500_ADFILTCONF_AD3NH			5
+#define AB8500_ADFILTCONF_AD4NH			4
+#define AB8500_ADFILTCONF_AD1VOICE		3
+#define AB8500_ADFILTCONF_AD2VOICE		2
+#define AB8500_ADFILTCONF_AD3VOICE		1
+#define AB8500_ADFILTCONF_AD4VOICE		0
+
+/* AB8500_DIGIFCONF1 */
+#define AB8500_DIGIFCONF1_ENMASTGEN		7
+#define AB8500_DIGIFCONF1_IF1BITCLKOS1		6
+#define AB8500_DIGIFCONF1_IF1BITCLKOS0		5
+#define AB8500_DIGIFCONF1_ENFSBITCLK1		4
+#define AB8500_DIGIFCONF1_IF0BITCLKOS1		2
+#define AB8500_DIGIFCONF1_IF0BITCLKOS0		1
+#define AB8500_DIGIFCONF1_ENFSBITCLK0		0
+
+/* AB8500_DIGIFCONF2 */
+#define AB8500_DIGIFCONF2_FSYNC0P		6
+#define AB8500_DIGIFCONF2_BITCLK0P		5
+#define AB8500_DIGIFCONF2_IF0DEL		4
+#define AB8500_DIGIFCONF2_IF0FORMAT1		3
+#define AB8500_DIGIFCONF2_IF0FORMAT0		2
+#define AB8500_DIGIFCONF2_IF0WL1		1
+#define AB8500_DIGIFCONF2_IF0WL0		0
+
+/* AB8500_DIGIFCONF3 */
+#define AB8500_DIGIFCONF3_IF0DATOIF1AD		7
+#define AB8500_DIGIFCONF3_IF0CLKTOIF1CLK	6
+#define AB8500_DIGIFCONF3_IF1MASTER		5
+#define AB8500_DIGIFCONF3_IF1DATOIF0AD		3
+#define AB8500_DIGIFCONF3_IF1CLKTOIF0CLK	2
+#define AB8500_DIGIFCONF3_IF0MASTER		1
+#define AB8500_DIGIFCONF3_IF0BFIFOEN		0
+
+/* AB8500_DIGIFCONF4 */
+#define AB8500_DIGIFCONF4_FSYNC1P		6
+#define AB8500_DIGIFCONF4_BITCLK1P		5
+#define AB8500_DIGIFCONF4_IF1DEL		4
+#define AB8500_DIGIFCONF4_IF1FORMAT1		3
+#define AB8500_DIGIFCONF4_IF1FORMAT0		2
+#define AB8500_DIGIFCONF4_IF1WL1		1
+#define AB8500_DIGIFCONF4_IF1WL0		0
+
+/* AB8500_ADSLOTSELX */
+#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_ODD	0x00
+#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD	0x01
+#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD	0x02
+#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_ODD	0x03
+#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_ODD	0x04
+#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_ODD	0x05
+#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_ODD	0x06
+#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_ODD	0x07
+#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_ODD	0x08
+#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_ODD	0x0F
+#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_EVEN	0x00
+#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_EVEN	0x10
+#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN	0x20
+#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_EVEN	0x30
+#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_EVEN	0x40
+#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_EVEN	0x50
+#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_EVEN	0x60
+#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_EVEN	0x70
+#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_EVEN	0x80
+#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_EVEN	0xF0
+#define AB8500_ADSLOTSELX_EVEN_SHIFT		0
+#define AB8500_ADSLOTSELX_ODD_SHIFT		4
+
+/* AB8500_ADSLOTHIZCTRL1 */
+/* AB8500_ADSLOTHIZCTRL2 */
+/* AB8500_ADSLOTHIZCTRL3 */
+/* AB8500_ADSLOTHIZCTRL4 */
+/* AB8500_DASLOTCONF1 */
+#define AB8500_DASLOTCONF1_DA12VOICE		7
+#define AB8500_DASLOTCONF1_SWAPDA12_34		6
+#define AB8500_DASLOTCONF1_DAI7TOADO1		5
+
+/* AB8500_DASLOTCONF2 */
+#define AB8500_DASLOTCONF2_DAI8TOADO2		5
+
+/* AB8500_DASLOTCONF3 */
+#define AB8500_DASLOTCONF3_DA34VOICE		7
+#define AB8500_DASLOTCONF3_DAI7TOADO3		5
+
+/* AB8500_DASLOTCONF4 */
+#define AB8500_DASLOTCONF4_DAI8TOADO4		5
+
+/* AB8500_DASLOTCONF5 */
+#define AB8500_DASLOTCONF5_DA56VOICE		7
+#define AB8500_DASLOTCONF5_DAI7TOADO5		5
+
+/* AB8500_DASLOTCONF6 */
+#define AB8500_DASLOTCONF6_DAI8TOADO6		5
+
+/* AB8500_DASLOTCONF7 */
+#define AB8500_DASLOTCONF7_DAI8TOADO7		5
+
+/* AB8500_DASLOTCONF8 */
+#define AB8500_DASLOTCONF8_DAI7TOADO8		5
+
+#define AB8500_DASLOTCONFX_SLTODAX_SHIFT	0
+#define AB8500_DASLOTCONFX_SLTODAX_MASK		0x1F
+
+/* AB8500_CLASSDCONF1 */
+#define AB8500_CLASSDCONF1_PARLHF		7
+#define AB8500_CLASSDCONF1_PARLVIB		6
+#define AB8500_CLASSDCONF1_VIB1SWAPEN		3
+#define AB8500_CLASSDCONF1_VIB2SWAPEN		2
+#define AB8500_CLASSDCONF1_HFLSWAPEN		1
+#define AB8500_CLASSDCONF1_HFRSWAPEN		0
+
+/* AB8500_CLASSDCONF2 */
+#define AB8500_CLASSDCONF2_FIRBYP3		7
+#define AB8500_CLASSDCONF2_FIRBYP2		6
+#define AB8500_CLASSDCONF2_FIRBYP1		5
+#define AB8500_CLASSDCONF2_FIRBYP0		4
+#define AB8500_CLASSDCONF2_HIGHVOLEN3		3
+#define AB8500_CLASSDCONF2_HIGHVOLEN2		2
+#define AB8500_CLASSDCONF2_HIGHVOLEN1		1
+#define AB8500_CLASSDCONF2_HIGHVOLEN0		0
+
+/* AB8500_CLASSDCONF3 */
+#define AB8500_CLASSDCONF3_DITHHPGAIN		4
+#define AB8500_CLASSDCONF3_DITHHPGAIN_MAX	0x0A
+#define AB8500_CLASSDCONF3_DITHWGAIN		0
+#define AB8500_CLASSDCONF3_DITHWGAIN_MAX	0x0A
+
+/* AB8500_DMICFILTCONF */
+#define AB8500_DMICFILTCONF_ANCINSEL		7
+#define AB8500_DMICFILTCONF_DA3TOEAR		6
+#define AB8500_DMICFILTCONF_DMIC1SINC3		5
+#define AB8500_DMICFILTCONF_DMIC2SINC3		4
+#define AB8500_DMICFILTCONF_DMIC3SINC3		3
+#define AB8500_DMICFILTCONF_DMIC4SINC3		2
+#define AB8500_DMICFILTCONF_DMIC5SINC3		1
+#define AB8500_DMICFILTCONF_DMIC6SINC3		0
+
+/* AB8500_DIGMULTCONF1 */
+#define AB8500_DIGMULTCONF1_DATOHSLEN		7
+#define AB8500_DIGMULTCONF1_DATOHSREN		6
+#define AB8500_DIGMULTCONF1_AD1SEL		5
+#define AB8500_DIGMULTCONF1_AD2SEL		4
+#define AB8500_DIGMULTCONF1_AD3SEL		3
+#define AB8500_DIGMULTCONF1_AD5SEL		2
+#define AB8500_DIGMULTCONF1_AD6SEL		1
+#define AB8500_DIGMULTCONF1_ANCSEL		0
+
+/* AB8500_DIGMULTCONF2 */
+#define AB8500_DIGMULTCONF2_DATOHFREN		7
+#define AB8500_DIGMULTCONF2_DATOHFLEN		6
+#define AB8500_DIGMULTCONF2_HFRSEL		5
+#define AB8500_DIGMULTCONF2_HFLSEL		4
+#define AB8500_DIGMULTCONF2_FIRSID1SEL		2
+#define AB8500_DIGMULTCONF2_FIRSID2SEL		0
+
+/* AB8500_ADDIGGAIN1 */
+/* AB8500_ADDIGGAIN2 */
+/* AB8500_ADDIGGAIN3 */
+/* AB8500_ADDIGGAIN4 */
+/* AB8500_ADDIGGAIN5 */
+/* AB8500_ADDIGGAIN6 */
+#define AB8500_ADDIGGAINX_FADEDISADX		6
+#define AB8500_ADDIGGAINX_ADXGAIN_MAX		0x3F
+
+/* AB8500_DADIGGAIN1 */
+/* AB8500_DADIGGAIN2 */
+/* AB8500_DADIGGAIN3 */
+/* AB8500_DADIGGAIN4 */
+/* AB8500_DADIGGAIN5 */
+/* AB8500_DADIGGAIN6 */
+#define AB8500_DADIGGAINX_FADEDISDAX		6
+#define AB8500_DADIGGAINX_DAXGAIN_MAX		0x3F
+
+/* AB8500_ADDIGLOOPGAIN1 */
+/* AB8500_ADDIGLOOPGAIN2 */
+#define AB8500_ADDIGLOOPGAINX_FADEDISADXL	6
+#define AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX	0x3F
+
+/* AB8500_HSLEARDIGGAIN */
+#define AB8500_HSLEARDIGGAIN_HSSINC1		7
+#define AB8500_HSLEARDIGGAIN_FADEDISHSL		4
+#define AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX	0x09
+
+/* AB8500_HSRDIGGAIN */
+#define AB8500_HSRDIGGAIN_FADESPEED		6
+#define AB8500_HSRDIGGAIN_FADEDISHSR		4
+#define AB8500_HSRDIGGAIN_HSRDGAIN_MAX		0x09
+
+/* AB8500_SIDFIRGAIN1 */
+/* AB8500_SIDFIRGAIN2 */
+#define AB8500_SIDFIRGAINX_FIRSIDXGAIN_MAX	0x1F
+
+/* AB8500_ANCCONF1 */
+#define AB8500_ANCCONF1_ANCIIRUPDATE		3
+#define AB8500_ANCCONF1_ENANC			2
+#define AB8500_ANCCONF1_ANCIIRINIT		1
+#define AB8500_ANCCONF1_ANCFIRUPDATE		0
+
+/* AB8500_ANCCONF2 */
+#define AB8500_ANCCONF2_SHIFT			5
+#define AB8500_ANCCONF2_MIN			-0x10
+#define AB8500_ANCCONF2_MAX			0xF
+
+/* AB8500_ANCCONF3 */
+#define AB8500_ANCCONF3_SHIFT			5
+#define AB8500_ANCCONF3_MIN			-0x10
+#define AB8500_ANCCONF3_MAX			0xF
+
+/* AB8500_ANCCONF4 */
+#define AB8500_ANCCONF4_SHIFT			5
+#define AB8500_ANCCONF4_MIN			-0x10
+#define AB8500_ANCCONF4_MAX			0xF
+
+/* AB8500_ANC_FIR_COEFFS */
+#define AB8500_ANC_FIR_COEFF_MIN		-0x8000
+#define AB8500_ANC_FIR_COEFF_MAX		0x7FFF
+#define AB8500_ANC_FIR_COEFFS			15
+
+/* AB8500_ANC_IIR_COEFFS */
+#define AB8500_ANC_IIR_COEFF_MIN		-0x800000
+#define AB8500_ANC_IIR_COEFF_MAX		0x7FFFFF
+#define AB8500_ANC_IIR_COEFFS			24
+/* AB8500_ANC_WARP_DELAY */
+#define AB8500_ANC_WARP_DELAY_SHIFT		16
+#define AB8500_ANC_WARP_DELAY_MIN		0x0000
+#define AB8500_ANC_WARP_DELAY_MAX		0xFFFF
+
+/* AB8500_ANCCONF11 */
+/* AB8500_ANCCONF12 */
+/* AB8500_ANCCONF13 */
+/* AB8500_ANCCONF14 */
+
+/* AB8500_SIDFIRADR */
+#define AB8500_SIDFIRADR_FIRSIDSET		7
+#define AB8500_SIDFIRADR_ADDRESS_SHIFT		0
+#define AB8500_SIDFIRADR_ADDRESS_MAX		0x7F
+
+/* AB8500_SIDFIRCOEF1 */
+/* AB8500_SIDFIRCOEF2 */
+#define AB8500_SID_FIR_COEFF_MIN		0
+#define AB8500_SID_FIR_COEFF_MAX		0xFFFF
+#define AB8500_SID_FIR_COEFFS			128
+
+/* AB8500_SIDFIRCONF */
+#define AB8500_SIDFIRCONF_ENFIRSIDS		2
+#define AB8500_SIDFIRCONF_FIRSIDSTOIF1		1
+#define AB8500_SIDFIRCONF_FIRSIDBUSY		0
+
+/* AB8500_AUDINTMASK1 */
+/* AB8500_AUDINTSOURCE1 */
+/* AB8500_AUDINTMASK2 */
+/* AB8500_AUDINTSOURCE2 */
+
+/* AB8500_FIFOCONF1 */
+#define AB8500_FIFOCONF1_BFIFOMASK		0x80
+#define AB8500_FIFOCONF1_BFIFO19M2		0x40
+#define AB8500_FIFOCONF1_BFIFOINT_SHIFT		0
+#define AB8500_FIFOCONF1_BFIFOINT_MAX		0x3F
+
+/* AB8500_FIFOCONF2 */
+#define AB8500_FIFOCONF2_BFIFOTX_SHIFT		0
+#define AB8500_FIFOCONF2_BFIFOTX_MAX		0xFF
+
+/* AB8500_FIFOCONF3 */
+#define AB8500_FIFOCONF3_BFIFOEXSL_SHIFT	5
+#define AB8500_FIFOCONF3_BFIFOEXSL_MAX		0x5
+#define AB8500_FIFOCONF3_PREBITCLK0_SHIFT	2
+#define AB8500_FIFOCONF3_PREBITCLK0_MAX		0x7
+#define AB8500_FIFOCONF3_BFIFOMAST_SHIFT	1
+#define AB8500_FIFOCONF3_BFIFORUN_SHIFT		0
+
+/* AB8500_FIFOCONF4 */
+#define AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT	0
+#define AB8500_FIFOCONF4_BFIFOFRAMSW_MAX	0xFF
+
+/* AB8500_FIFOCONF5 */
+#define AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT	0
+#define AB8500_FIFOCONF5_BFIFOWAKEUP_MAX	0xFF
+
+/* AB8500_FIFOCONF6 */
+#define AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT	0
+#define AB8500_FIFOCONF6_BFIFOSAMPLE_MAX	0xFF
+
+/* AB8500_AUDREV */
+
+#endif
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 2023c74..ea06b83 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -91,11 +91,6 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int ac97_soc_remove(struct snd_soc_codec *codec)
-{
-	return 0;
-}
-
 #ifdef CONFIG_PM
 static int ac97_soc_suspend(struct snd_soc_codec *codec)
 {
@@ -119,7 +114,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
 	.write =	ac97_write,
 	.read =		ac97_read,
 	.probe = 	ac97_soc_probe,
-	.remove = 	ac97_soc_remove,
 	.suspend =	ac97_soc_suspend,
 	.resume =	ac97_soc_resume,
 };
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
new file mode 100644
index 0000000..3b5730b
--- /dev/null
+++ b/sound/soc/codecs/arizona.c
@@ -0,0 +1,781 @@
+/*
+ * arizona.c - Wolfson Arizona class device shared support
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gcd.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+
+#define ARIZONA_AIF_BCLK_CTRL                   0x00
+#define ARIZONA_AIF_TX_PIN_CTRL                 0x01
+#define ARIZONA_AIF_RX_PIN_CTRL                 0x02
+#define ARIZONA_AIF_RATE_CTRL                   0x03
+#define ARIZONA_AIF_FORMAT                      0x04
+#define ARIZONA_AIF_TX_BCLK_RATE                0x05
+#define ARIZONA_AIF_RX_BCLK_RATE                0x06
+#define ARIZONA_AIF_FRAME_CTRL_1                0x07
+#define ARIZONA_AIF_FRAME_CTRL_2                0x08
+#define ARIZONA_AIF_FRAME_CTRL_3                0x09
+#define ARIZONA_AIF_FRAME_CTRL_4                0x0A
+#define ARIZONA_AIF_FRAME_CTRL_5                0x0B
+#define ARIZONA_AIF_FRAME_CTRL_6                0x0C
+#define ARIZONA_AIF_FRAME_CTRL_7                0x0D
+#define ARIZONA_AIF_FRAME_CTRL_8                0x0E
+#define ARIZONA_AIF_FRAME_CTRL_9                0x0F
+#define ARIZONA_AIF_FRAME_CTRL_10               0x10
+#define ARIZONA_AIF_FRAME_CTRL_11               0x11
+#define ARIZONA_AIF_FRAME_CTRL_12               0x12
+#define ARIZONA_AIF_FRAME_CTRL_13               0x13
+#define ARIZONA_AIF_FRAME_CTRL_14               0x14
+#define ARIZONA_AIF_FRAME_CTRL_15               0x15
+#define ARIZONA_AIF_FRAME_CTRL_16               0x16
+#define ARIZONA_AIF_FRAME_CTRL_17               0x17
+#define ARIZONA_AIF_FRAME_CTRL_18               0x18
+#define ARIZONA_AIF_TX_ENABLES                  0x19
+#define ARIZONA_AIF_RX_ENABLES                  0x1A
+#define ARIZONA_AIF_FORCE_WRITE                 0x1B
+
+#define arizona_fll_err(_fll, fmt, ...) \
+	dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
+#define arizona_fll_warn(_fll, fmt, ...) \
+	dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
+#define arizona_fll_dbg(_fll, fmt, ...) \
+	dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
+
+#define arizona_aif_err(_dai, fmt, ...) \
+	dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
+#define arizona_aif_warn(_dai, fmt, ...) \
+	dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
+#define arizona_aif_dbg(_dai, fmt, ...) \
+	dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
+
+const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
+	"None",
+	"Tone Generator 1",
+	"Tone Generator 2",
+	"Haptics",
+	"AEC",
+	"Mic Mute Mixer",
+	"Noise Generator",
+	"IN1L",
+	"IN1R",
+	"IN2L",
+	"IN2R",
+	"IN3L",
+	"IN3R",
+	"AIF1RX1",
+	"AIF1RX2",
+	"AIF1RX3",
+	"AIF1RX4",
+	"AIF1RX5",
+	"AIF1RX6",
+	"AIF1RX7",
+	"AIF1RX8",
+	"AIF2RX1",
+	"AIF2RX2",
+	"AIF3RX1",
+	"AIF3RX2",
+	"SLIMRX1",
+	"SLIMRX2",
+	"SLIMRX3",
+	"SLIMRX4",
+	"SLIMRX5",
+	"SLIMRX6",
+	"SLIMRX7",
+	"SLIMRX8",
+	"EQ1",
+	"EQ2",
+	"EQ3",
+	"EQ4",
+	"DRC1L",
+	"DRC1R",
+	"DRC2L",
+	"DRC2R",
+	"LHPF1",
+	"LHPF2",
+	"LHPF3",
+	"LHPF4",
+	"DSP1.1",
+	"DSP1.2",
+	"DSP1.3",
+	"DSP1.4",
+	"DSP1.5",
+	"DSP1.6",
+	"ASRC1L",
+	"ASRC1R",
+	"ASRC2L",
+	"ASRC2R",
+};
+EXPORT_SYMBOL_GPL(arizona_mixer_texts);
+
+int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
+	0x00,  /* None */
+	0x04,  /* Tone */
+	0x05,
+	0x06,  /* Haptics */
+	0x08,  /* AEC */
+	0x0c,  /* Noise mixer */
+	0x0d,  /* Comfort noise */
+	0x10,  /* IN1L */
+	0x11,
+	0x12,
+	0x13,
+	0x14,
+	0x15,
+	0x20,  /* AIF1RX1 */
+	0x21,
+	0x22,
+	0x23,
+	0x24,
+	0x25,
+	0x26,
+	0x27,
+	0x28,  /* AIF2RX1 */
+	0x29,
+	0x30,  /* AIF3RX1 */
+	0x31,
+	0x38,  /* SLIMRX1 */
+	0x39,
+	0x3a,
+	0x3b,
+	0x3c,
+	0x3d,
+	0x3e,
+	0x3f,
+	0x50,  /* EQ1 */
+	0x51,
+	0x52,
+	0x53,
+	0x58,  /* DRC1L */
+	0x59,
+	0x5a,
+	0x5b,
+	0x60,  /* LHPF1 */
+	0x61,
+	0x62,
+	0x63,
+	0x68,  /* DSP1.1 */
+	0x69,
+	0x6a,
+	0x6b,
+	0x6c,
+	0x6d,
+	0x90,  /* ASRC1L */
+	0x91,
+	0x92,
+	0x93,
+};
+EXPORT_SYMBOL_GPL(arizona_mixer_values);
+
+const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
+EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
+
+static const char *arizona_lhpf_mode_text[] = {
+	"Low-pass", "High-pass"
+};
+
+const struct soc_enum arizona_lhpf1_mode =
+	SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
+			arizona_lhpf_mode_text);
+EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
+
+const struct soc_enum arizona_lhpf2_mode =
+	SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
+			arizona_lhpf_mode_text);
+EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
+
+const struct soc_enum arizona_lhpf3_mode =
+	SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
+			arizona_lhpf_mode_text);
+EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
+
+const struct soc_enum arizona_lhpf4_mode =
+	SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
+			arizona_lhpf_mode_text);
+EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
+
+int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+		  int event)
+{
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_in_ev);
+
+int arizona_out_ev(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol,
+		   int event)
+{
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_out_ev);
+
+int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+		       int source, unsigned int freq, int dir)
+{
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->arizona;
+	char *name;
+	unsigned int reg;
+	unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
+	unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
+	unsigned int *clk;
+
+	switch (clk_id) {
+	case ARIZONA_CLK_SYSCLK:
+		name = "SYSCLK";
+		reg = ARIZONA_SYSTEM_CLOCK_1;
+		clk = &priv->sysclk;
+		mask |= ARIZONA_SYSCLK_FRAC;
+		break;
+	case ARIZONA_CLK_ASYNCCLK:
+		name = "ASYNCCLK";
+		reg = ARIZONA_ASYNC_CLOCK_1;
+		clk = &priv->asyncclk;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case  5644800:
+	case  6144000:
+		break;
+	case 11289600:
+	case 12288000:
+		val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
+		break;
+	case 22579200:
+	case 24576000:
+		val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
+		break;
+	case 45158400:
+	case 49152000:
+		val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*clk = freq;
+
+	if (freq % 6144000)
+		val |= ARIZONA_SYSCLK_FRAC;
+
+	dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
+
+	return regmap_update_bits(arizona->regmap, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(arizona_set_sysclk);
+
+static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int lrclk, bclk, mode, base;
+
+	base = dai->driver->base;
+
+	lrclk = 0;
+	bclk = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		mode = 0;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		mode = 1;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		mode = 2;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		mode = 3;
+		break;
+	default:
+		arizona_aif_err(dai, "Unsupported DAI format %d\n",
+				fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		bclk |= ARIZONA_AIF1_BCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		bclk |= ARIZONA_AIF1_BCLK_MSTR;
+		lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
+		break;
+	default:
+		arizona_aif_err(dai, "Unsupported master mode %d\n",
+				fmt & SND_SOC_DAIFMT_MASTER_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bclk |= ARIZONA_AIF1_BCLK_INV;
+		lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bclk |= ARIZONA_AIF1_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
+			    ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
+			    bclk);
+	snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
+			    ARIZONA_AIF1TX_LRCLK_INV |
+			    ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
+	snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
+			    ARIZONA_AIF1RX_LRCLK_INV |
+			    ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
+	snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
+			    ARIZONA_AIF1_FMT_MASK, mode);
+
+	return 0;
+}
+
+static const int arizona_48k_rates[] = {
+	-1,
+	48000,
+	64000,
+	96000,
+	128000,
+	192000,
+	256000,
+	384000,
+	512000,
+	768000,
+	1024000,
+	1536000,
+	2048000,
+	3072000,
+	4096000,
+	6144000,
+	8192000,
+	12288000,
+	24576000,
+};
+
+static const int arizona_44k1_rates[] = {
+	-1,
+	44100,
+	58800,
+	88200,
+	117600,
+	177640,
+	235200,
+	352800,
+	470400,
+	705600,
+	940800,
+	1411200,
+	1881600,
+	2882400,
+	3763200,
+	5644800,
+	7526400,
+	11289600,
+	22579200,
+};
+
+static int arizona_sr_vals[] = {
+	0,
+	12000,
+	24000,
+	48000,
+	96000,
+	192000,
+	384000,
+	768000,
+	0,
+	11025,
+	22050,
+	44100,
+	88200,
+	176400,
+	352800,
+	705600,
+	4000,
+	8000,
+	16000,
+	32000,
+	64000,
+	128000,
+	256000,
+	512000,
+};
+
+static int arizona_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int base = dai->driver->base;
+	const int *rates;
+	int i;
+	int bclk, lrclk, wl, frame, sr_val;
+
+	if (params_rate(params) % 8000)
+		rates = &arizona_44k1_rates[0];
+	else
+		rates = &arizona_48k_rates[0];
+
+	for (i = 0; i < ARRAY_SIZE(arizona_44k1_rates); i++) {
+		if (rates[i] == snd_soc_params_to_bclk(params)) {
+			bclk = i;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(arizona_44k1_rates)) {
+		arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
+				params_rate(params));
+		return -EINVAL;
+	}
+
+	/*
+	 * We will need to be more flexible than this in future,
+	 * currently we use a single sample rate for the chip.
+	 */
+	for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
+		if (arizona_sr_vals[i] == params_rate(params))
+			break;
+	if (i == ARRAY_SIZE(arizona_sr_vals)) {
+		arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
+				params_rate(params));
+		return -EINVAL;
+	}
+	sr_val = i;
+
+	lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
+
+	arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
+			rates[bclk], rates[bclk] / lrclk);
+
+	wl = snd_pcm_format_width(params_format(params));
+	frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
+
+	snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
+			    ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
+	snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
+			    ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
+	snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
+			    ARIZONA_AIF1TX_BCPF_MASK, lrclk);
+	snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
+			    ARIZONA_AIF1RX_BCPF_MASK, lrclk);
+	snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
+			    ARIZONA_AIF1TX_WL_MASK |
+			    ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
+	snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
+			    ARIZONA_AIF1RX_WL_MASK |
+			    ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
+
+	return 0;
+}
+
+const struct snd_soc_dai_ops arizona_dai_ops = {
+	.set_fmt = arizona_set_fmt,
+	.hw_params = arizona_hw_params,
+};
+
+static irqreturn_t arizona_fll_lock(int irq, void *data)
+{
+	struct arizona_fll *fll = data;
+
+	arizona_fll_dbg(fll, "Locked\n");
+
+	complete(&fll->lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
+{
+	struct arizona_fll *fll = data;
+
+	arizona_fll_dbg(fll, "clock OK\n");
+
+	complete(&fll->ok);
+
+	return IRQ_HANDLED;
+}
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+struct arizona_fll_cfg {
+	int n;
+	int theta;
+	int lambda;
+	int refdiv;
+	int outdiv;
+	int fratio;
+};
+
+static int arizona_calc_fll(struct arizona_fll *fll,
+			    struct arizona_fll_cfg *cfg,
+			    unsigned int Fref,
+			    unsigned int Fout)
+{
+	unsigned int target, div, gcd_fll;
+	int i, ratio;
+
+	arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	cfg->refdiv = 0;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+		cfg->refdiv++;
+
+		if (div > 8) {
+			arizona_fll_err(fll,
+					"Can't scale %dMHz in to <=13.5MHz\n",
+					Fref);
+			return -EINVAL;
+		}
+	}
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 1;
+	while (Fout * div < 90000000) {
+		div++;
+		if (div > 7) {
+			arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
+					Fout);
+			return -EINVAL;
+		}
+	}
+	target = Fout * div;
+	cfg->outdiv = div;
+
+	arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
+
+	/* Find an appropraite FLL_FRATIO and factor it out of the target */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			cfg->fratio = fll_fratios[i].fratio;
+			ratio = fll_fratios[i].ratio;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_fratios)) {
+		arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
+				Fref);
+		return -EINVAL;
+	}
+
+	cfg->n = target / (ratio * Fref);
+
+	if (target % Fref) {
+		gcd_fll = gcd(target, ratio * Fref);
+		arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
+
+		cfg->theta = (target - (cfg->n * ratio * Fref))
+			/ gcd_fll;
+		cfg->lambda = (ratio * Fref) / gcd_fll;
+	} else {
+		cfg->theta = 0;
+		cfg->lambda = 0;
+	}
+
+	arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
+			cfg->n, cfg->theta, cfg->lambda);
+	arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
+			cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
+
+	return 0;
+
+}
+
+static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
+			      struct arizona_fll_cfg *cfg, int source)
+{
+	regmap_update_bits(arizona->regmap, base + 3,
+			   ARIZONA_FLL1_THETA_MASK, cfg->theta);
+	regmap_update_bits(arizona->regmap, base + 4,
+			   ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
+	regmap_update_bits(arizona->regmap, base + 5,
+			   ARIZONA_FLL1_FRATIO_MASK,
+			   cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
+	regmap_update_bits(arizona->regmap, base + 6,
+			   ARIZONA_FLL1_CLK_REF_DIV_MASK |
+			   ARIZONA_FLL1_CLK_REF_SRC_MASK,
+			   cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
+			   source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
+
+	regmap_update_bits(arizona->regmap, base + 2,
+			   ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
+			   ARIZONA_FLL1_CTRL_UPD | cfg->n);
+}
+
+int arizona_set_fll(struct arizona_fll *fll, int source,
+		    unsigned int Fref, unsigned int Fout)
+{
+	struct arizona *arizona = fll->arizona;
+	struct arizona_fll_cfg cfg, sync;
+	unsigned int reg, val;
+	int syncsrc;
+	bool ena;
+	int ret;
+
+	ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
+	if (ret != 0) {
+		arizona_fll_err(fll, "Failed to read current state: %d\n",
+				ret);
+		return ret;
+	}
+	ena = reg & ARIZONA_FLL1_ENA;
+
+	if (Fout) {
+		/* Do we have a 32kHz reference? */
+		regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
+		switch (val & ARIZONA_CLK_32K_SRC_MASK) {
+		case ARIZONA_CLK_SRC_MCLK1:
+		case ARIZONA_CLK_SRC_MCLK2:
+			syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
+			break;
+		default:
+			syncsrc = -1;
+		}
+
+		if (source == syncsrc)
+			syncsrc = -1;
+
+		if (syncsrc >= 0) {
+			ret = arizona_calc_fll(fll, &sync, Fref, Fout);
+			if (ret != 0)
+				return ret;
+
+			ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
+			if (ret != 0)
+				return ret;
+		} else {
+			ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
+			if (ret != 0)
+				return ret;
+		}
+	} else {
+		regmap_update_bits(arizona->regmap, fll->base + 1,
+				   ARIZONA_FLL1_ENA, 0);
+		regmap_update_bits(arizona->regmap, fll->base + 0x11,
+				   ARIZONA_FLL1_SYNC_ENA, 0);
+
+		if (ena)
+			pm_runtime_put_autosuspend(arizona->dev);
+
+		return 0;
+	}
+
+	regmap_update_bits(arizona->regmap, fll->base + 5,
+			   ARIZONA_FLL1_OUTDIV_MASK,
+			   cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+
+	if (syncsrc >= 0) {
+		arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
+		arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
+	} else {
+		arizona_apply_fll(arizona, fll->base, &cfg, source);
+	}
+
+	if (!ena)
+		pm_runtime_get(arizona->dev);
+
+	/* Clear any pending completions */
+	try_wait_for_completion(&fll->ok);
+
+	regmap_update_bits(arizona->regmap, fll->base + 1,
+			   ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
+	if (syncsrc >= 0)
+		regmap_update_bits(arizona->regmap, fll->base + 0x11,
+				   ARIZONA_FLL1_SYNC_ENA,
+				   ARIZONA_FLL1_SYNC_ENA);
+
+	ret = wait_for_completion_timeout(&fll->ok,
+					  msecs_to_jiffies(25));
+	if (ret == 0)
+		arizona_fll_warn(fll, "Timed out waiting for lock\n");
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_set_fll);
+
+int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
+		     int ok_irq, struct arizona_fll *fll)
+{
+	int ret;
+
+	init_completion(&fll->lock);
+	init_completion(&fll->ok);
+
+	fll->id = id;
+	fll->base = base;
+	fll->arizona = arizona;
+
+	snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
+	snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
+		 "FLL%d clock OK", id);
+
+	ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
+				  arizona_fll_lock, fll);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
+			id, ret);
+	}
+
+	ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
+				  arizona_fll_clock_ok, fll);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
+			id, ret);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_fll);
+
+MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
new file mode 100644
index 0000000..8c2ca1d
--- /dev/null
+++ b/sound/soc/codecs/arizona.h
@@ -0,0 +1,149 @@
+/*
+ * arizona.h - Wolfson Arizona class device shared support
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ASOC_ARIZONA_H
+#define _ASOC_ARIZONA_H
+
+#include <linux/completion.h>
+
+#include <sound/soc.h>
+
+#define ARIZONA_CLK_SYSCLK   1
+#define ARIZONA_CLK_ASYNCCLK 2
+
+#define ARIZONA_CLK_SRC_MCLK1    0x0
+#define ARIZONA_CLK_SRC_MCLK2    0x1
+#define ARIZONA_CLK_SRC_FLL1     0x4
+#define ARIZONA_CLK_SRC_FLL2     0x5
+#define ARIZONA_CLK_SRC_AIF1BCLK 0x8
+#define ARIZONA_CLK_SRC_AIF2BCLK 0x9
+#define ARIZONA_CLK_SRC_AIF3BCLK 0xa
+
+#define ARIZONA_FLL_SRC_MCLK1      0
+#define ARIZONA_FLL_SRC_MCLK2      1
+#define ARIZONA_FLL_SRC_SLIMCLK    2
+#define ARIZONA_FLL_SRC_FLL1       3
+#define ARIZONA_FLL_SRC_FLL2       4
+#define ARIZONA_FLL_SRC_AIF1BCLK   5
+#define ARIZONA_FLL_SRC_AIF2BCLK   6
+#define ARIZONA_FLL_SRC_AIF3BCLK   7
+#define ARIZONA_FLL_SRC_AIF1LRCLK  8
+#define ARIZONA_FLL_SRC_AIF2LRCLK  9
+#define ARIZONA_FLL_SRC_AIF3LRCLK 10
+
+#define ARIZONA_MIXER_VOL_MASK             0x00FE
+#define ARIZONA_MIXER_VOL_SHIFT                 1
+#define ARIZONA_MIXER_VOL_WIDTH                 7
+
+struct arizona;
+
+struct arizona_priv {
+	struct arizona *arizona;
+	int sysclk;
+	int asyncclk;
+};
+
+#define ARIZONA_NUM_MIXER_INPUTS 55
+
+extern const unsigned int arizona_mixer_tlv[];
+extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
+extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
+
+#define ARIZONA_MIXER_CONTROLS(name, base) \
+	SOC_SINGLE_RANGE_TLV(name " Input 1 Volume", base + 1,		\
+			     ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,	\
+			     arizona_mixer_tlv),			\
+	SOC_SINGLE_RANGE_TLV(name " Input 2 Volume", base + 3,		\
+			     ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,	\
+			     arizona_mixer_tlv),			\
+	SOC_SINGLE_RANGE_TLV(name " Input 3 Volume", base + 5,		\
+			     ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,	\
+			     arizona_mixer_tlv),			\
+	SOC_SINGLE_RANGE_TLV(name " Input 4 Volume", base + 7,		\
+			     ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,	\
+			     arizona_mixer_tlv)
+
+#define ARIZONA_MUX_ENUM_DECL(name, reg) \
+	SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff,			\
+				   arizona_mixer_texts, arizona_mixer_values)
+
+#define ARIZONA_MUX_CTL_DECL(name) \
+	const struct snd_kcontrol_new name##_mux =	\
+		SOC_DAPM_VALUE_ENUM("Route", name##_enum)
+
+#define ARIZONA_MIXER_ENUMS(name, base_reg) \
+	static ARIZONA_MUX_ENUM_DECL(name##_in1_enum, base_reg);      \
+	static ARIZONA_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2);  \
+	static ARIZONA_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4);  \
+	static ARIZONA_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6);  \
+	static ARIZONA_MUX_CTL_DECL(name##_in1); \
+	static ARIZONA_MUX_CTL_DECL(name##_in2); \
+	static ARIZONA_MUX_CTL_DECL(name##_in3); \
+	static ARIZONA_MUX_CTL_DECL(name##_in4)
+
+#define ARIZONA_MUX(name, ctrl) \
+	SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+
+#define ARIZONA_MIXER_WIDGETS(name, name_str)	\
+	ARIZONA_MUX(name_str " Input 1", &name##_in1_mux), \
+	ARIZONA_MUX(name_str " Input 2", &name##_in2_mux), \
+	ARIZONA_MUX(name_str " Input 3", &name##_in3_mux), \
+	ARIZONA_MUX(name_str " Input 4", &name##_in4_mux), \
+	SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
+
+#define ARIZONA_MIXER_ROUTES(widget, name) \
+	{ widget, NULL, name " Mixer" },         \
+	{ name " Mixer", NULL, name " Input 1" }, \
+	{ name " Mixer", NULL, name " Input 2" }, \
+	{ name " Mixer", NULL, name " Input 3" }, \
+	{ name " Mixer", NULL, name " Input 4" }, \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Input 1"), \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Input 2"), \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Input 3"), \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Input 4")
+
+extern const struct soc_enum arizona_lhpf1_mode;
+extern const struct soc_enum arizona_lhpf2_mode;
+extern const struct soc_enum arizona_lhpf3_mode;
+extern const struct soc_enum arizona_lhpf4_mode;
+
+extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol,
+			 int event);
+extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event);
+
+extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+			      int source, unsigned int freq, int dir);
+
+extern const struct snd_soc_dai_ops arizona_dai_ops;
+
+#define ARIZONA_FLL_NAME_LEN 20
+
+struct arizona_fll {
+	struct arizona *arizona;
+	int id;
+	unsigned int base;
+	struct completion lock;
+	struct completion ok;
+
+	char lock_name[ARIZONA_FLL_NAME_LEN];
+	char clock_ok_name[ARIZONA_FLL_NAME_LEN];
+};
+
+extern int arizona_init_fll(struct arizona *arizona, int id, int base,
+			    int lock_irq, int ok_irq, struct arizona_fll *fll);
+extern int arizona_set_fll(struct arizona_fll *fll, int source,
+			   unsigned int Fref, unsigned int Fout);
+
+#endif
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index a710941..628daf6 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -14,7 +14,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -1217,11 +1216,11 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
 		return -ENOMEM;
 	cs42l52->dev = &i2c_client->dev;
 
-	cs42l52->regmap = regmap_init_i2c(i2c_client, &cs42l52_regmap);
+	cs42l52->regmap = devm_regmap_init_i2c(i2c_client, &cs42l52_regmap);
 	if (IS_ERR(cs42l52->regmap)) {
 		ret = PTR_ERR(cs42l52->regmap);
 		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
-		goto err;
+		return ret;
 	}
 
 	i2c_set_clientdata(i2c_client, cs42l52);
@@ -1243,7 +1242,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
 		dev_err(&i2c_client->dev,
 			"CS42L52 Device ID (%X). Expected %X\n",
 			devid, CS42L52_CHIP_ID);
-		goto err_regmap;
+		return ret;
 	}
 
 	regcache_cache_only(cs42l52->regmap, true);
@@ -1251,23 +1250,13 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
 	ret =  snd_soc_register_codec(&i2c_client->dev,
 			&soc_codec_dev_cs42l52, &cs42l52_dai, 1);
 	if (ret < 0)
-		goto err_regmap;
+		return ret;
 	return 0;
-
-err_regmap:
-	regmap_exit(cs42l52->regmap);
-
-err:
-	return ret;
 }
 
 static int cs42l52_i2c_remove(struct i2c_client *client)
 {
-	struct cs42l52_private *cs42l52 = i2c_get_clientdata(client);
-
 	snd_soc_unregister_codec(&client->dev);
-	regmap_exit(cs42l52->regmap);
-
 	return 0;
 }
 
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index e0d45fd..2c08c4c 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -1362,11 +1362,11 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
 
 	i2c_set_clientdata(i2c_client, cs42l73);
 
-	cs42l73->regmap = regmap_init_i2c(i2c_client, &cs42l73_regmap);
+	cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap);
 	if (IS_ERR(cs42l73->regmap)) {
 		ret = PTR_ERR(cs42l73->regmap);
 		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
-		goto err;
+		return ret;
 	}
 	/* initialize codec */
 	ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, &reg);
@@ -1384,13 +1384,13 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
 		dev_err(&i2c_client->dev,
 			"CS42L73 Device ID (%X). Expected %X\n",
 			devid, CS42L73_DEVID);
-		goto err_regmap;
+		return ret;
 	}
 
 	ret = regmap_read(cs42l73->regmap, CS42L73_REVID, &reg);
 	if (ret < 0) {
 		dev_err(&i2c_client->dev, "Get Revision ID failed\n");
-		goto err_regmap;
+		return ret;;
 	}
 
 	dev_info(&i2c_client->dev,
@@ -1402,23 +1402,13 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
 			&soc_codec_dev_cs42l73, cs42l73_dai,
 			ARRAY_SIZE(cs42l73_dai));
 	if (ret < 0)
-		goto err_regmap;
+		return ret;
 	return 0;
-
-err_regmap:
-	regmap_exit(cs42l73->regmap);
-
-err:
-	return ret;
 }
 
 static __devexit int cs42l73_i2c_remove(struct i2c_client *client)
 {
-	struct cs42l73_private *cs42l73 = i2c_get_clientdata(client);
-
 	snd_soc_unregister_codec(&client->dev);
-	regmap_exit(cs42l73->regmap);
-
 	return 0;
 }
 
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
new file mode 100644
index 0000000..01be2a3
--- /dev/null
+++ b/sound/soc/codecs/da732x.c
@@ -0,0 +1,1627 @@
+/*
+ * da732x.c --- Dialog DA732X ALSA SoC Audio Driver
+ *
+ * Copyright (C) 2012 Dialog Semiconductor GmbH
+ *
+ * Author: Michal Hajduk <Michal.Hajduk@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include "da732x.h"
+#include "da732x_reg.h"
+
+
+struct da732x_priv {
+	struct regmap *regmap;
+	struct snd_soc_codec *codec;
+
+	unsigned int sysclk;
+	bool pll_en;
+};
+
+/*
+ * da732x register cache - default settings
+ */
+static struct reg_default da732x_reg_cache[] = {
+	{ DA732X_REG_REF1		, 0x02 },
+	{ DA732X_REG_BIAS_EN		, 0x80 },
+	{ DA732X_REG_BIAS1		, 0x00 },
+	{ DA732X_REG_BIAS2		, 0x00 },
+	{ DA732X_REG_BIAS3		, 0x00 },
+	{ DA732X_REG_BIAS4		, 0x00 },
+	{ DA732X_REG_MICBIAS2		, 0x00 },
+	{ DA732X_REG_MICBIAS1		, 0x00 },
+	{ DA732X_REG_MICDET		, 0x00 },
+	{ DA732X_REG_MIC1_PRE		, 0x01 },
+	{ DA732X_REG_MIC1		, 0x40 },
+	{ DA732X_REG_MIC2_PRE		, 0x01 },
+	{ DA732X_REG_MIC2		, 0x40 },
+	{ DA732X_REG_AUX1L		, 0x75 },
+	{ DA732X_REG_AUX1R		, 0x75 },
+	{ DA732X_REG_MIC3_PRE		, 0x01 },
+	{ DA732X_REG_MIC3		, 0x40 },
+	{ DA732X_REG_INP_PINBIAS	, 0x00 },
+	{ DA732X_REG_INP_ZC_EN		, 0x00 },
+	{ DA732X_REG_INP_MUX		, 0x50 },
+	{ DA732X_REG_HP_DET		, 0x00 },
+	{ DA732X_REG_HPL_DAC_OFFSET	, 0x00 },
+	{ DA732X_REG_HPL_DAC_OFF_CNTL	, 0x00 },
+	{ DA732X_REG_HPL_OUT_OFFSET	, 0x00 },
+	{ DA732X_REG_HPL		, 0x40 },
+	{ DA732X_REG_HPL_VOL		, 0x0F },
+	{ DA732X_REG_HPR_DAC_OFFSET	, 0x00 },
+	{ DA732X_REG_HPR_DAC_OFF_CNTL	, 0x00 },
+	{ DA732X_REG_HPR_OUT_OFFSET	, 0x00 },
+	{ DA732X_REG_HPR		, 0x40 },
+	{ DA732X_REG_HPR_VOL		, 0x0F },
+	{ DA732X_REG_LIN2		, 0x4F },
+	{ DA732X_REG_LIN3		, 0x4F },
+	{ DA732X_REG_LIN4		, 0x4F },
+	{ DA732X_REG_OUT_ZC_EN		, 0x00 },
+	{ DA732X_REG_HP_LIN1_GNDSEL	, 0x00 },
+	{ DA732X_REG_CP_HP1		, 0x0C },
+	{ DA732X_REG_CP_HP2		, 0x03 },
+	{ DA732X_REG_CP_CTRL1		, 0x00 },
+	{ DA732X_REG_CP_CTRL2		, 0x99 },
+	{ DA732X_REG_CP_CTRL3		, 0x25 },
+	{ DA732X_REG_CP_LEVEL_MASK	, 0x3F },
+	{ DA732X_REG_CP_DET		, 0x00 },
+	{ DA732X_REG_CP_STATUS		, 0x00 },
+	{ DA732X_REG_CP_THRESH1		, 0x00 },
+	{ DA732X_REG_CP_THRESH2		, 0x00 },
+	{ DA732X_REG_CP_THRESH3		, 0x00 },
+	{ DA732X_REG_CP_THRESH4		, 0x00 },
+	{ DA732X_REG_CP_THRESH5		, 0x00 },
+	{ DA732X_REG_CP_THRESH6		, 0x00 },
+	{ DA732X_REG_CP_THRESH7		, 0x00 },
+	{ DA732X_REG_CP_THRESH8		, 0x00 },
+	{ DA732X_REG_PLL_DIV_LO		, 0x00 },
+	{ DA732X_REG_PLL_DIV_MID	, 0x00 },
+	{ DA732X_REG_PLL_DIV_HI		, 0x00 },
+	{ DA732X_REG_PLL_CTRL		, 0x02 },
+	{ DA732X_REG_CLK_CTRL		, 0xaa },
+	{ DA732X_REG_CLK_DSP		, 0x07 },
+	{ DA732X_REG_CLK_EN1		, 0x00 },
+	{ DA732X_REG_CLK_EN2		, 0x00 },
+	{ DA732X_REG_CLK_EN3		, 0x00 },
+	{ DA732X_REG_CLK_EN4		, 0x00 },
+	{ DA732X_REG_CLK_EN5		, 0x00 },
+	{ DA732X_REG_AIF_MCLK		, 0x00 },
+	{ DA732X_REG_AIFA1		, 0x02 },
+	{ DA732X_REG_AIFA2		, 0x00 },
+	{ DA732X_REG_AIFA3		, 0x08 },
+	{ DA732X_REG_AIFB1		, 0x02 },
+	{ DA732X_REG_AIFB2		, 0x00 },
+	{ DA732X_REG_AIFB3		, 0x08 },
+	{ DA732X_REG_PC_CTRL		, 0xC0 },
+	{ DA732X_REG_DATA_ROUTE		, 0x00 },
+	{ DA732X_REG_DSP_CTRL		, 0x00 },
+	{ DA732X_REG_CIF_CTRL2		, 0x00 },
+	{ DA732X_REG_HANDSHAKE		, 0x00 },
+	{ DA732X_REG_SPARE1_OUT		, 0x00 },
+	{ DA732X_REG_SPARE2_OUT		, 0x00 },
+	{ DA732X_REG_SPARE1_IN		, 0x00 },
+	{ DA732X_REG_ADC1_PD		, 0x00 },
+	{ DA732X_REG_ADC1_HPF		, 0x00 },
+	{ DA732X_REG_ADC1_SEL		, 0x00 },
+	{ DA732X_REG_ADC1_EQ12		, 0x00 },
+	{ DA732X_REG_ADC1_EQ34		, 0x00 },
+	{ DA732X_REG_ADC1_EQ5		, 0x00 },
+	{ DA732X_REG_ADC2_PD		, 0x00 },
+	{ DA732X_REG_ADC2_HPF		, 0x00 },
+	{ DA732X_REG_ADC2_SEL		, 0x00 },
+	{ DA732X_REG_ADC2_EQ12		, 0x00 },
+	{ DA732X_REG_ADC2_EQ34		, 0x00 },
+	{ DA732X_REG_ADC2_EQ5		, 0x00 },
+	{ DA732X_REG_DAC1_HPF		, 0x00 },
+	{ DA732X_REG_DAC1_L_VOL		, 0x00 },
+	{ DA732X_REG_DAC1_R_VOL		, 0x00 },
+	{ DA732X_REG_DAC1_SEL		, 0x00 },
+	{ DA732X_REG_DAC1_SOFTMUTE	, 0x00 },
+	{ DA732X_REG_DAC1_EQ12		, 0x00 },
+	{ DA732X_REG_DAC1_EQ34		, 0x00 },
+	{ DA732X_REG_DAC1_EQ5		, 0x00 },
+	{ DA732X_REG_DAC2_HPF		, 0x00 },
+	{ DA732X_REG_DAC2_L_VOL		, 0x00 },
+	{ DA732X_REG_DAC2_R_VOL		, 0x00 },
+	{ DA732X_REG_DAC2_SEL		, 0x00 },
+	{ DA732X_REG_DAC2_SOFTMUTE	, 0x00 },
+	{ DA732X_REG_DAC2_EQ12		, 0x00 },
+	{ DA732X_REG_DAC2_EQ34		, 0x00 },
+	{ DA732X_REG_DAC2_EQ5		, 0x00 },
+	{ DA732X_REG_DAC3_HPF		, 0x00 },
+	{ DA732X_REG_DAC3_VOL		, 0x00 },
+	{ DA732X_REG_DAC3_SEL		, 0x00 },
+	{ DA732X_REG_DAC3_SOFTMUTE	, 0x00 },
+	{ DA732X_REG_DAC3_EQ12		, 0x00 },
+	{ DA732X_REG_DAC3_EQ34		, 0x00 },
+	{ DA732X_REG_DAC3_EQ5		, 0x00 },
+	{ DA732X_REG_BIQ_BYP		, 0x00 },
+	{ DA732X_REG_DMA_CMD		, 0x00 },
+	{ DA732X_REG_DMA_ADDR0		, 0x00 },
+	{ DA732X_REG_DMA_ADDR1		, 0x00 },
+	{ DA732X_REG_DMA_DATA0		, 0x00 },
+	{ DA732X_REG_DMA_DATA1		, 0x00 },
+	{ DA732X_REG_DMA_DATA2		, 0x00 },
+	{ DA732X_REG_DMA_DATA3		, 0x00 },
+	{ DA732X_REG_UNLOCK		, 0x00 },
+};
+
+static inline int da732x_get_input_div(struct snd_soc_codec *codec, int sysclk)
+{
+	int val;
+	int ret;
+
+	if (sysclk < DA732X_MCLK_10MHZ) {
+		val = DA732X_MCLK_RET_0_10MHZ;
+		ret = DA732X_MCLK_VAL_0_10MHZ;
+	} else if ((sysclk >= DA732X_MCLK_10MHZ) &&
+	    (sysclk < DA732X_MCLK_20MHZ)) {
+		val = DA732X_MCLK_RET_10_20MHZ;
+		ret = DA732X_MCLK_VAL_10_20MHZ;
+	} else if ((sysclk >= DA732X_MCLK_20MHZ) &&
+	    (sysclk < DA732X_MCLK_40MHZ)) {
+		val = DA732X_MCLK_RET_20_40MHZ;
+		ret = DA732X_MCLK_VAL_20_40MHZ;
+	} else if ((sysclk >= DA732X_MCLK_40MHZ) &&
+	    (sysclk <= DA732X_MCLK_54MHZ)) {
+		val = DA732X_MCLK_RET_40_54MHZ;
+		ret = DA732X_MCLK_VAL_40_54MHZ;
+	} else {
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, DA732X_REG_PLL_CTRL, val);
+
+	return ret;
+}
+
+static void da732x_set_charge_pump(struct snd_soc_codec *codec, int state)
+{
+	switch (state) {
+	case DA732X_ENABLE_CP:
+		snd_soc_write(codec, DA732X_REG_CLK_EN2, DA732X_CP_CLK_EN);
+		snd_soc_write(codec, DA732X_REG_CP_HP2, DA732X_HP_CP_EN |
+			      DA732X_HP_CP_REG | DA732X_HP_CP_PULSESKIP);
+		snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA732X_CP_EN |
+			      DA732X_CP_CTRL_CPVDD1);
+		snd_soc_write(codec, DA732X_REG_CP_CTRL2,
+			      DA732X_CP_MANAGE_MAGNITUDE | DA732X_CP_BOOST);
+		snd_soc_write(codec, DA732X_REG_CP_CTRL3, DA732X_CP_1MHZ);
+		break;
+	case DA732X_DISABLE_CP:
+		snd_soc_write(codec, DA732X_REG_CLK_EN2, DA732X_CP_CLK_DIS);
+		snd_soc_write(codec, DA732X_REG_CP_HP2, DA732X_HP_CP_DIS);
+		snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS);
+		break;
+	default:
+		pr_err(KERN_ERR "Wrong charge pump state\n");
+		break;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, DA732X_MIC_PRE_VOL_DB_MIN,
+				  DA732X_MIC_PRE_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, DA732X_MIC_VOL_DB_MIN,
+				  DA732X_MIC_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(aux_pga_tlv, DA732X_AUX_VOL_DB_MIN,
+				  DA732X_AUX_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(hp_pga_tlv, DA732X_HP_VOL_DB_MIN,
+				  DA732X_AUX_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(lin2_pga_tlv, DA732X_LIN2_VOL_DB_MIN,
+				  DA732X_LIN2_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(lin3_pga_tlv, DA732X_LIN3_VOL_DB_MIN,
+				  DA732X_LIN3_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(lin4_pga_tlv, DA732X_LIN4_VOL_DB_MIN,
+				  DA732X_LIN4_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(adc_pga_tlv, DA732X_ADC_VOL_DB_MIN,
+				  DA732X_ADC_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(dac_pga_tlv, DA732X_DAC_VOL_DB_MIN,
+				  DA732X_DAC_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(eq_band_pga_tlv, DA732X_EQ_BAND_VOL_DB_MIN,
+				  DA732X_EQ_BAND_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(eq_overall_tlv, DA732X_EQ_OVERALL_VOL_DB_MIN,
+				  DA732X_EQ_OVERALL_VOL_DB_INC, 0);
+
+/* High Pass Filter */
+static const char *da732x_hpf_mode[] = {
+	"Disable", "Music", "Voice",
+};
+
+static const char *da732x_hpf_music[] = {
+	"1.8Hz", "3.75Hz", "7.5Hz", "15Hz",
+};
+
+static const char *da732x_hpf_voice[] = {
+	"2.5Hz", "25Hz", "50Hz", "100Hz",
+	"150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum da732x_dac1_hpf_mode_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT,
+			DA732X_HPF_MODE_MAX, da732x_hpf_mode)
+};
+
+static const struct soc_enum da732x_dac2_hpf_mode_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT,
+			DA732X_HPF_MODE_MAX, da732x_hpf_mode)
+};
+
+static const struct soc_enum da732x_dac3_hpf_mode_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT,
+			DA732X_HPF_MODE_MAX, da732x_hpf_mode)
+};
+
+static const struct soc_enum da732x_adc1_hpf_mode_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT,
+			DA732X_HPF_MODE_MAX, da732x_hpf_mode)
+};
+
+static const struct soc_enum da732x_adc2_hpf_mode_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT,
+			DA732X_HPF_MODE_MAX, da732x_hpf_mode)
+};
+
+static const struct soc_enum da732x_dac1_hp_filter_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT,
+			DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
+};
+
+static const struct soc_enum da732x_dac2_hp_filter_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT,
+			DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
+};
+
+static const struct soc_enum da732x_dac3_hp_filter_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT,
+			DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
+};
+
+static const struct soc_enum da732x_adc1_hp_filter_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT,
+			DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
+};
+
+static const struct soc_enum da732x_adc2_hp_filter_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT,
+			DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
+};
+
+static const struct soc_enum da732x_dac1_voice_filter_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT,
+			DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
+};
+
+static const struct soc_enum da732x_dac2_voice_filter_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT,
+			DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
+};
+
+static const struct soc_enum da732x_dac3_voice_filter_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT,
+			DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
+};
+
+static const struct soc_enum da732x_adc1_voice_filter_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT,
+			DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
+};
+
+static const struct soc_enum da732x_adc2_voice_filter_enum[] = {
+	SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT,
+			DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
+};
+
+
+static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
+	unsigned int reg = enum_ctrl->reg;
+	unsigned int sel = ucontrol->value.integer.value[0];
+	unsigned int bits;
+
+	switch (sel) {
+	case DA732X_HPF_DISABLED:
+		bits = DA732X_HPF_DIS;
+		break;
+	case DA732X_HPF_VOICE:
+		bits = DA732X_HPF_VOICE_EN;
+		break;
+	case DA732X_HPF_MUSIC:
+		bits = DA732X_HPF_MUSIC_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, reg, DA732X_HPF_MASK, bits);
+
+	return 0;
+}
+
+static int da732x_hpf_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
+	unsigned int reg = enum_ctrl->reg;
+	int val;
+
+	val = snd_soc_read(codec, reg) & DA732X_HPF_MASK;
+
+	switch (val) {
+	case DA732X_HPF_VOICE_EN:
+		ucontrol->value.integer.value[0] = DA732X_HPF_VOICE;
+		break;
+	case DA732X_HPF_MUSIC_EN:
+		ucontrol->value.integer.value[0] = DA732X_HPF_MUSIC;
+		break;
+	default:
+		ucontrol->value.integer.value[0] = DA732X_HPF_DISABLED;
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new da732x_snd_controls[] = {
+	/* Input PGAs */
+	SOC_SINGLE_RANGE_TLV("MIC1 Boost Volume", DA732X_REG_MIC1_PRE,
+			     DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN,
+			     DA732X_MICBOOST_MAX, 0, mic_boost_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC2 Boost Volume", DA732X_REG_MIC2_PRE,
+			     DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN,
+			     DA732X_MICBOOST_MAX, 0, mic_boost_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC3 Boost Volume", DA732X_REG_MIC3_PRE,
+			     DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN,
+			     DA732X_MICBOOST_MAX, 0, mic_boost_tlv),
+
+	/* MICs */
+	SOC_SINGLE("MIC1 Switch", DA732X_REG_MIC1, DA732X_MIC_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_RANGE_TLV("MIC1 Volume", DA732X_REG_MIC1,
+			     DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN,
+			     DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv),
+	SOC_SINGLE("MIC2 Switch", DA732X_REG_MIC2, DA732X_MIC_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_RANGE_TLV("MIC2 Volume", DA732X_REG_MIC2,
+			     DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN,
+			     DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv),
+	SOC_SINGLE("MIC3 Switch", DA732X_REG_MIC3, DA732X_MIC_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_RANGE_TLV("MIC3 Volume", DA732X_REG_MIC3,
+			     DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN,
+			     DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv),
+
+	/* AUXs */
+	SOC_SINGLE("AUX1L Switch", DA732X_REG_AUX1L, DA732X_AUX_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("AUX1L Volume", DA732X_REG_AUX1L,
+		       DA732X_AUX_VOL_SHIFT, DA732X_AUX_VOL_VAL_MAX,
+		       DA732X_NO_INVERT, aux_pga_tlv),
+	SOC_SINGLE("AUX1R Switch", DA732X_REG_AUX1R, DA732X_AUX_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("AUX1R Volume", DA732X_REG_AUX1R,
+		       DA732X_AUX_VOL_SHIFT, DA732X_AUX_VOL_VAL_MAX,
+		       DA732X_NO_INVERT, aux_pga_tlv),
+
+	/* ADCs */
+	SOC_DOUBLE_TLV("ADC1 Volume", DA732X_REG_ADC1_SEL,
+		       DA732X_ADCL_VOL_SHIFT, DA732X_ADCR_VOL_SHIFT,
+		       DA732X_ADC_VOL_VAL_MAX, DA732X_INVERT, adc_pga_tlv),
+
+	SOC_DOUBLE_TLV("ADC2 Volume", DA732X_REG_ADC2_SEL,
+		       DA732X_ADCL_VOL_SHIFT, DA732X_ADCR_VOL_SHIFT,
+		       DA732X_ADC_VOL_VAL_MAX, DA732X_INVERT, adc_pga_tlv),
+
+	/* DACs */
+	SOC_DOUBLE("Digital Playback DAC12 Switch", DA732X_REG_DAC1_SEL,
+		   DA732X_DACL_MUTE_SHIFT, DA732X_DACR_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_DOUBLE_R_TLV("Digital Playback DAC12 Volume", DA732X_REG_DAC1_L_VOL,
+			 DA732X_REG_DAC1_R_VOL, DA732X_DAC_VOL_SHIFT,
+			 DA732X_DAC_VOL_VAL_MAX, DA732X_INVERT, dac_pga_tlv),
+	SOC_SINGLE("Digital Playback DAC3 Switch", DA732X_REG_DAC2_SEL,
+		   DA732X_DACL_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Digital Playback DAC3 Volume", DA732X_REG_DAC2_L_VOL,
+			DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX,
+			DA732X_INVERT, dac_pga_tlv),
+	SOC_SINGLE("Digital Playback DAC4 Switch", DA732X_REG_DAC2_SEL,
+		   DA732X_DACR_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Digital Playback DAC4 Volume", DA732X_REG_DAC2_R_VOL,
+		       DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX,
+		       DA732X_INVERT, dac_pga_tlv),
+	SOC_SINGLE("Digital Playback DAC5 Switch", DA732X_REG_DAC3_SEL,
+		   DA732X_DACL_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Digital Playback DAC5 Volume", DA732X_REG_DAC3_VOL,
+		       DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX,
+		       DA732X_INVERT, dac_pga_tlv),
+
+	/* High Pass Filters */
+	SOC_ENUM_EXT("DAC1 High Pass Filter Mode",
+		     da732x_dac1_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+	SOC_ENUM("DAC1 High Pass Filter", da732x_dac1_hp_filter_enum),
+	SOC_ENUM("DAC1 Voice Filter", da732x_dac1_voice_filter_enum),
+
+	SOC_ENUM_EXT("DAC2 High Pass Filter Mode",
+		     da732x_dac2_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+	SOC_ENUM("DAC2 High Pass Filter", da732x_dac2_hp_filter_enum),
+	SOC_ENUM("DAC2 Voice Filter", da732x_dac2_voice_filter_enum),
+
+	SOC_ENUM_EXT("DAC3 High Pass Filter Mode",
+		     da732x_dac3_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+	SOC_ENUM("DAC3 High Pass Filter", da732x_dac3_hp_filter_enum),
+	SOC_ENUM("DAC3 Filter Mode", da732x_dac3_voice_filter_enum),
+
+	SOC_ENUM_EXT("ADC1 High Pass Filter Mode",
+		     da732x_adc1_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+	SOC_ENUM("ADC1 High Pass Filter", da732x_adc1_hp_filter_enum),
+	SOC_ENUM("ADC1 Voice Filter", da732x_adc1_voice_filter_enum),
+
+	SOC_ENUM_EXT("ADC2 High Pass Filter Mode",
+		     da732x_adc2_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+	SOC_ENUM("ADC2 High Pass Filter", da732x_adc2_hp_filter_enum),
+	SOC_ENUM("ADC2 Voice Filter", da732x_adc2_voice_filter_enum),
+
+	/* Equalizers */
+	SOC_SINGLE("ADC1 EQ Switch", DA732X_REG_ADC1_EQ5,
+		   DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+	SOC_SINGLE_TLV("ADC1 EQ Band 1 Volume", DA732X_REG_ADC1_EQ12,
+		       DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC1 EQ Band 2 Volume", DA732X_REG_ADC1_EQ12,
+		       DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC1 EQ Band 3 Volume", DA732X_REG_ADC1_EQ34,
+		       DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC1 EQ Band 4 Volume", DA732X_REG_ADC1_EQ34,
+		       DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC1 EQ Band 5 Volume", DA732X_REG_ADC1_EQ5,
+		       DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC1 EQ Overall Volume", DA732X_REG_ADC1_EQ5,
+		       DA732X_EQ_OVERALL_SHIFT, DA732X_EQ_OVERALL_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_overall_tlv),
+
+	SOC_SINGLE("ADC2 EQ Switch", DA732X_REG_ADC2_EQ5,
+		   DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+	SOC_SINGLE_TLV("ADC2 EQ Band 1 Volume", DA732X_REG_ADC2_EQ12,
+		       DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC2 EQ Band 2 Volume", DA732X_REG_ADC2_EQ12,
+		       DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC2 EQ Band 3 Volume", DA732X_REG_ADC2_EQ34,
+		       DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ACD2 EQ Band 4 Volume", DA732X_REG_ADC2_EQ34,
+		       DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ACD2 EQ Band 5 Volume", DA732X_REG_ADC2_EQ5,
+		       DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC2 EQ Overall Volume", DA732X_REG_ADC1_EQ5,
+		       DA732X_EQ_OVERALL_SHIFT, DA732X_EQ_OVERALL_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_overall_tlv),
+
+	SOC_SINGLE("DAC1 EQ Switch", DA732X_REG_DAC1_EQ5,
+		   DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+	SOC_SINGLE_TLV("DAC1 EQ Band 1 Volume", DA732X_REG_DAC1_EQ12,
+		       DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC1 EQ Band 2 Volume", DA732X_REG_DAC1_EQ12,
+		       DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC1 EQ Band 3 Volume", DA732X_REG_DAC1_EQ34,
+		       DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC1 EQ Band 4 Volume", DA732X_REG_DAC1_EQ34,
+		       DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC1 EQ Band 5 Volume", DA732X_REG_DAC1_EQ5,
+		       DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+
+	SOC_SINGLE("DAC2 EQ Switch", DA732X_REG_DAC2_EQ5,
+		   DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+	SOC_SINGLE_TLV("DAC2 EQ Band 1 Volume", DA732X_REG_DAC2_EQ12,
+		       DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC2 EQ Band 2 Volume", DA732X_REG_DAC2_EQ12,
+		       DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC2 EQ Band 3 Volume", DA732X_REG_DAC2_EQ34,
+		       DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC2 EQ Band 4 Volume", DA732X_REG_DAC2_EQ34,
+		       DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC2 EQ Band 5 Volume", DA732X_REG_DAC2_EQ5,
+		       DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+
+	SOC_SINGLE("DAC3 EQ Switch", DA732X_REG_DAC3_EQ5,
+		   DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+	SOC_SINGLE_TLV("DAC3 EQ Band 1 Volume", DA732X_REG_DAC3_EQ12,
+		       DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC3 EQ Band 2 Volume", DA732X_REG_DAC3_EQ12,
+		       DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC3 EQ Band 3 Volume", DA732X_REG_DAC3_EQ34,
+		       DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC3 EQ Band 4 Volume", DA732X_REG_DAC3_EQ34,
+		       DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC3 EQ Band 5 Volume", DA732X_REG_DAC3_EQ5,
+		       DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+
+	/* Lineout 2 Reciever*/
+	SOC_SINGLE("Lineout 2 Switch", DA732X_REG_LIN2, DA732X_LOUT_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Lineout 2 Volume", DA732X_REG_LIN2,
+		       DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX,
+		       DA732X_NO_INVERT, lin2_pga_tlv),
+
+	/* Lineout 3 SPEAKER*/
+	SOC_SINGLE("Lineout 3 Switch", DA732X_REG_LIN3, DA732X_LOUT_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Lineout 3 Volume", DA732X_REG_LIN3,
+		       DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX,
+		       DA732X_NO_INVERT, lin3_pga_tlv),
+
+	/* Lineout 4 */
+	SOC_SINGLE("Lineout 4 Switch", DA732X_REG_LIN4, DA732X_LOUT_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Lineout 4 Volume", DA732X_REG_LIN4,
+		       DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX,
+		       DA732X_NO_INVERT, lin4_pga_tlv),
+
+	/* Headphones */
+	SOC_DOUBLE_R("Headphone Switch", DA732X_REG_HPR, DA732X_REG_HPL,
+		     DA732X_HP_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_DOUBLE_R_TLV("Headphone Volume", DA732X_REG_HPL_VOL,
+			 DA732X_REG_HPR_VOL, DA732X_HP_VOL_SHIFT,
+			 DA732X_HP_VOL_VAL_MAX, DA732X_NO_INVERT, hp_pga_tlv),
+};
+
+static int da732x_adc_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		switch (w->reg) {
+		case DA732X_REG_ADC1_PD:
+			snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+					    DA732X_ADCA_BB_CLK_EN,
+					    DA732X_ADCA_BB_CLK_EN);
+			break;
+		case DA732X_REG_ADC2_PD:
+			snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+					    DA732X_ADCC_BB_CLK_EN,
+					    DA732X_ADCC_BB_CLK_EN);
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_update_bits(codec, w->reg, DA732X_ADC_RST_MASK,
+				    DA732X_ADC_SET_ACT);
+		snd_soc_update_bits(codec, w->reg, DA732X_ADC_PD_MASK,
+				    DA732X_ADC_ON);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, w->reg, DA732X_ADC_PD_MASK,
+				    DA732X_ADC_OFF);
+		snd_soc_update_bits(codec, w->reg, DA732X_ADC_RST_MASK,
+				    DA732X_ADC_SET_RST);
+
+		switch (w->reg) {
+		case DA732X_REG_ADC1_PD:
+			snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+					    DA732X_ADCA_BB_CLK_EN, 0);
+			break;
+		case DA732X_REG_ADC2_PD:
+			snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+					    DA732X_ADCC_BB_CLK_EN, 0);
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int da732x_out_pga_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, w->reg,
+				    (1 << w->shift) | DA732X_OUT_HIZ_EN,
+				    (1 << w->shift) | DA732X_OUT_HIZ_EN);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, w->reg,
+				    (1 << w->shift) | DA732X_OUT_HIZ_EN,
+				    (1 << w->shift) | DA732X_OUT_HIZ_DIS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const char *adcl_text[] = {
+	"AUX1L", "MIC1"
+};
+
+static const char *adcr_text[] = {
+	"AUX1R", "MIC2", "MIC3"
+};
+
+static const char *enable_text[] = {
+	"Disabled",
+	"Enabled"
+};
+
+/* ADC1LMUX */
+static const struct soc_enum adc1l_enum =
+	SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT,
+			DA732X_ADCL_MUX_MAX, adcl_text);
+static const struct snd_kcontrol_new adc1l_mux =
+	SOC_DAPM_ENUM("ADC Route", adc1l_enum);
+
+/* ADC1RMUX */
+static const struct soc_enum adc1r_enum =
+	SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT,
+			DA732X_ADCR_MUX_MAX, adcr_text);
+static const struct snd_kcontrol_new adc1r_mux =
+	SOC_DAPM_ENUM("ADC Route", adc1r_enum);
+
+/* ADC2LMUX */
+static const struct soc_enum adc2l_enum =
+	SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT,
+			DA732X_ADCL_MUX_MAX, adcl_text);
+static const struct snd_kcontrol_new adc2l_mux =
+	SOC_DAPM_ENUM("ADC Route", adc2l_enum);
+
+/* ADC2RMUX */
+static const struct soc_enum adc2r_enum =
+	SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT,
+			DA732X_ADCR_MUX_MAX, adcr_text);
+
+static const struct snd_kcontrol_new adc2r_mux =
+	SOC_DAPM_ENUM("ADC Route", adc2r_enum);
+
+static const struct soc_enum da732x_hp_left_output =
+	SOC_ENUM_SINGLE(DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT,
+			DA732X_DAC_EN_MAX, enable_text);
+
+static const struct snd_kcontrol_new hpl_mux =
+	SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output);
+
+static const struct soc_enum da732x_hp_right_output =
+	SOC_ENUM_SINGLE(DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT,
+			DA732X_DAC_EN_MAX, enable_text);
+
+static const struct snd_kcontrol_new hpr_mux =
+	SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output);
+
+static const struct soc_enum da732x_speaker_output =
+	SOC_ENUM_SINGLE(DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT,
+			DA732X_DAC_EN_MAX, enable_text);
+
+static const struct snd_kcontrol_new spk_mux =
+	SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output);
+
+static const struct soc_enum da732x_lout4_output =
+	SOC_ENUM_SINGLE(DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT,
+			DA732X_DAC_EN_MAX, enable_text);
+
+static const struct snd_kcontrol_new lout4_mux =
+	SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output);
+
+static const struct soc_enum da732x_lout2_output =
+	SOC_ENUM_SINGLE(DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT,
+			DA732X_DAC_EN_MAX, enable_text);
+
+static const struct snd_kcontrol_new lout2_mux =
+	SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output);
+
+static const struct snd_soc_dapm_widget da732x_dapm_widgets[] = {
+	/* Supplies */
+	SND_SOC_DAPM_SUPPLY("ADC1 Supply", DA732X_REG_ADC1_PD, 0,
+			    DA732X_NO_INVERT, da732x_adc_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("ADC2 Supply", DA732X_REG_ADC2_PD, 0,
+			    DA732X_NO_INVERT, da732x_adc_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("DAC1 CLK", DA732X_REG_CLK_EN4,
+			    DA732X_DACA_BB_CLK_SHIFT, DA732X_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC2 CLK", DA732X_REG_CLK_EN4,
+			    DA732X_DACC_BB_CLK_SHIFT, DA732X_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC3 CLK", DA732X_REG_CLK_EN5,
+			    DA732X_DACE_BB_CLK_SHIFT, DA732X_NO_INVERT,
+			    NULL, 0),
+
+	/* Micbias */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", DA732X_REG_MICBIAS1,
+			    DA732X_MICBIAS_EN_SHIFT,
+			    DA732X_NO_INVERT, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", DA732X_REG_MICBIAS2,
+			    DA732X_MICBIAS_EN_SHIFT,
+			    DA732X_NO_INVERT, NULL, 0),
+
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("MIC3"),
+	SND_SOC_DAPM_INPUT("AUX1L"),
+	SND_SOC_DAPM_INPUT("AUX1R"),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+	SND_SOC_DAPM_OUTPUT("ClassD"),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC1L", NULL, DA732X_REG_ADC1_SEL,
+			 DA732X_ADCL_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_ADC("ADC1R", NULL, DA732X_REG_ADC1_SEL,
+			 DA732X_ADCR_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_ADC("ADC2L", NULL, DA732X_REG_ADC2_SEL,
+			 DA732X_ADCL_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_ADC("ADC2R", NULL, DA732X_REG_ADC2_SEL,
+			 DA732X_ADCR_EN_SHIFT, DA732X_NO_INVERT),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC1L", NULL, DA732X_REG_DAC1_SEL,
+			 DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_DAC("DAC1R", NULL, DA732X_REG_DAC1_SEL,
+			 DA732X_DACR_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_DAC("DAC2L", NULL, DA732X_REG_DAC2_SEL,
+			 DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_DAC("DAC2R", NULL, DA732X_REG_DAC2_SEL,
+			 DA732X_DACR_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_DAC("DAC3", NULL, DA732X_REG_DAC3_SEL,
+			 DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT),
+
+	/* Input Pgas */
+	SND_SOC_DAPM_PGA("MIC1 PGA", DA732X_REG_MIC1, DA732X_MIC_EN_SHIFT,
+			 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIC2 PGA", DA732X_REG_MIC2, DA732X_MIC_EN_SHIFT,
+			 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIC3 PGA", DA732X_REG_MIC3, DA732X_MIC_EN_SHIFT,
+			 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX1L PGA", DA732X_REG_AUX1L, DA732X_AUX_EN_SHIFT,
+			 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX1R PGA", DA732X_REG_AUX1R, DA732X_AUX_EN_SHIFT,
+			 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA_E("HP Left", DA732X_REG_HPL, DA732X_HP_OUT_EN_SHIFT,
+			   0, NULL, 0, da732x_out_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HP Right", DA732X_REG_HPR, DA732X_HP_OUT_EN_SHIFT,
+			   0, NULL, 0, da732x_out_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LIN2", DA732X_REG_LIN2, DA732X_LIN_OUT_EN_SHIFT,
+			   0, NULL, 0, da732x_out_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LIN3", DA732X_REG_LIN3, DA732X_LIN_OUT_EN_SHIFT,
+			   0, NULL, 0, da732x_out_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LIN4", DA732X_REG_LIN4, DA732X_LIN_OUT_EN_SHIFT,
+			   0, NULL, 0, da732x_out_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* MUXs */
+	SND_SOC_DAPM_MUX("ADC1 Left MUX", SND_SOC_NOPM, 0, 0, &adc1l_mux),
+	SND_SOC_DAPM_MUX("ADC1 Right MUX", SND_SOC_NOPM, 0, 0, &adc1r_mux),
+	SND_SOC_DAPM_MUX("ADC2 Left MUX", SND_SOC_NOPM, 0, 0, &adc2l_mux),
+	SND_SOC_DAPM_MUX("ADC2 Right MUX", SND_SOC_NOPM, 0, 0, &adc2r_mux),
+
+	SND_SOC_DAPM_MUX("HP Left MUX", SND_SOC_NOPM, 0, 0, &hpl_mux),
+	SND_SOC_DAPM_MUX("HP Right MUX", SND_SOC_NOPM, 0, 0, &hpr_mux),
+	SND_SOC_DAPM_MUX("Speaker MUX", SND_SOC_NOPM, 0, 0, &spk_mux),
+	SND_SOC_DAPM_MUX("LOUT2 MUX", SND_SOC_NOPM, 0, 0, &lout2_mux),
+	SND_SOC_DAPM_MUX("LOUT4 MUX", SND_SOC_NOPM, 0, 0, &lout4_mux),
+
+	/* AIF interfaces */
+	SND_SOC_DAPM_AIF_OUT("AIFA Output", "AIFA Capture", 0, DA732X_REG_AIFA3,
+			     DA732X_AIF_EN_SHIFT, 0),
+	SND_SOC_DAPM_AIF_IN("AIFA Input", "AIFA Playback", 0, DA732X_REG_AIFA3,
+			    DA732X_AIF_EN_SHIFT, 0),
+
+	SND_SOC_DAPM_AIF_OUT("AIFB Output", "AIFB Capture", 0, DA732X_REG_AIFB3,
+			     DA732X_AIF_EN_SHIFT, 0),
+	SND_SOC_DAPM_AIF_IN("AIFB Input", "AIFB Playback", 0, DA732X_REG_AIFB3,
+			    DA732X_AIF_EN_SHIFT, 0),
+};
+
+static const struct snd_soc_dapm_route da732x_dapm_routes[] = {
+	/* Inputs */
+	{"AUX1L PGA", "NULL", "AUX1L"},
+	{"AUX1R PGA", "NULL", "AUX1R"},
+	{"MIC1 PGA", NULL, "MIC1"},
+	{"MIC2 PGA", "NULL", "MIC2"},
+	{"MIC3 PGA", "NULL", "MIC3"},
+
+	/* Capture Path */
+	{"ADC1 Left MUX", "MIC1", "MIC1 PGA"},
+	{"ADC1 Left MUX", "AUX1L", "AUX1L PGA"},
+
+	{"ADC1 Right MUX", "AUX1R", "AUX1R PGA"},
+	{"ADC1 Right MUX", "MIC2", "MIC2 PGA"},
+	{"ADC1 Right MUX", "MIC3", "MIC3 PGA"},
+
+	{"ADC2 Left MUX", "AUX1L", "AUX1L PGA"},
+	{"ADC2 Left MUX", "MIC1", "MIC1 PGA"},
+
+	{"ADC2 Right MUX", "AUX1R", "AUX1R PGA"},
+	{"ADC2 Right MUX", "MIC2", "MIC2 PGA"},
+	{"ADC2 Right MUX", "MIC3", "MIC3 PGA"},
+
+	{"ADC1L", NULL, "ADC1 Supply"},
+	{"ADC1R", NULL, "ADC1 Supply"},
+	{"ADC2L", NULL, "ADC2 Supply"},
+	{"ADC2R", NULL, "ADC2 Supply"},
+
+	{"ADC1L", NULL, "ADC1 Left MUX"},
+	{"ADC1R", NULL, "ADC1 Right MUX"},
+	{"ADC2L", NULL, "ADC2 Left MUX"},
+	{"ADC2R", NULL, "ADC2 Right MUX"},
+
+	{"AIFA Output", NULL, "ADC1L"},
+	{"AIFA Output", NULL, "ADC1R"},
+	{"AIFB Output", NULL, "ADC2L"},
+	{"AIFB Output", NULL, "ADC2R"},
+
+	{"HP Left MUX", "Enabled", "AIFA Input"},
+	{"HP Right MUX", "Enabled", "AIFA Input"},
+	{"Speaker MUX", "Enabled", "AIFB Input"},
+	{"LOUT2 MUX", "Enabled", "AIFB Input"},
+	{"LOUT4 MUX", "Enabled", "AIFB Input"},
+
+	{"DAC1L", NULL, "DAC1 CLK"},
+	{"DAC1R", NULL, "DAC1 CLK"},
+	{"DAC2L", NULL, "DAC2 CLK"},
+	{"DAC2R", NULL, "DAC2 CLK"},
+	{"DAC3", NULL, "DAC3 CLK"},
+
+	{"DAC1L", NULL, "HP Left MUX"},
+	{"DAC1R", NULL, "HP Right MUX"},
+	{"DAC2L", NULL, "Speaker MUX"},
+	{"DAC2R", NULL, "LOUT4 MUX"},
+	{"DAC3", NULL, "LOUT2 MUX"},
+
+	/* Output Pgas */
+	{"HP Left", NULL, "DAC1L"},
+	{"HP Right", NULL, "DAC1R"},
+	{"LIN3", NULL, "DAC2L"},
+	{"LIN4", NULL, "DAC2R"},
+	{"LIN2", NULL, "DAC3"},
+
+	/* Outputs */
+	{"ClassD", NULL, "LIN3"},
+	{"LOUTL", NULL, "LIN2"},
+	{"LOUTR", NULL, "LIN4"},
+	{"HPL", NULL, "HP Left"},
+	{"HPR", NULL, "HP Right"},
+};
+
+static int da732x_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u32 aif = 0;
+	u32 reg_aif;
+	u32 fs;
+
+	reg_aif = dai->driver->base;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		aif |= DA732X_AIF_WORD_16;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		aif |= DA732X_AIF_WORD_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		aif |= DA732X_AIF_WORD_24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		aif |= DA732X_AIF_WORD_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs = DA732X_SR_8KHZ;
+		break;
+	case 11025:
+		fs = DA732X_SR_11_025KHZ;
+		break;
+	case 12000:
+		fs = DA732X_SR_12KHZ;
+		break;
+	case 16000:
+		fs = DA732X_SR_16KHZ;
+		break;
+	case 22050:
+		fs = DA732X_SR_22_05KHZ;
+		break;
+	case 24000:
+		fs = DA732X_SR_24KHZ;
+		break;
+	case 32000:
+		fs = DA732X_SR_32KHZ;
+		break;
+	case 44100:
+		fs = DA732X_SR_44_1KHZ;
+		break;
+	case 48000:
+		fs = DA732X_SR_48KHZ;
+		break;
+	case 88100:
+		fs = DA732X_SR_88_1KHZ;
+		break;
+	case 96000:
+		fs = DA732X_SR_96KHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, reg_aif, DA732X_AIF_WORD_MASK, aif);
+	snd_soc_update_bits(codec, DA732X_REG_CLK_CTRL, DA732X_SR1_MASK, fs);
+
+	return 0;
+}
+
+static int da732x_set_dai_fmt(struct snd_soc_dai *dai, u32 fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u32 aif_mclk, pc_count;
+	u32 reg_aif1, aif1;
+	u32 reg_aif3, aif3;
+
+	switch (dai->id) {
+	case DA732X_DAI_ID1:
+		reg_aif1 = DA732X_REG_AIFA1;
+		reg_aif3 = DA732X_REG_AIFA3;
+		pc_count = DA732X_PC_PULSE_AIFA | DA732X_PC_RESYNC_NOT_AUT |
+			   DA732X_PC_SAME;
+		break;
+	case DA732X_DAI_ID2:
+		reg_aif1 = DA732X_REG_AIFB1;
+		reg_aif3 = DA732X_REG_AIFB3;
+		pc_count = DA732X_PC_PULSE_AIFB | DA732X_PC_RESYNC_NOT_AUT |
+			   DA732X_PC_SAME;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aif1 = DA732X_AIF_SLAVE;
+		aif_mclk = DA732X_AIFM_FRAME_64 | DA732X_AIFM_SRC_SEL_AIFA;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif1 = DA732X_AIF_CLK_FROM_SRC;
+		aif_mclk = DA732X_CLK_GENERATION_AIF_A;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		aif3 = DA732X_AIF_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		aif3 = DA732X_AIF_RIGHT_J_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif3 = DA732X_AIF_LEFT_J_MODE;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		aif3 = DA732X_AIF_DSP_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_B:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif3 |= DA732X_AIF_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif3 |= DA732X_AIF_BCLK_INV | DA732X_AIF_WCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif3 |= DA732X_AIF_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif3 |= DA732X_AIF_WCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, DA732X_REG_AIF_MCLK, aif_mclk);
+	snd_soc_update_bits(codec, reg_aif1, DA732X_AIF1_CLK_MASK, aif1);
+	snd_soc_update_bits(codec, reg_aif3, DA732X_AIF_BCLK_INV |
+			    DA732X_AIF_WCLK_INV | DA732X_AIF_MODE_MASK, aif3);
+	snd_soc_write(codec, DA732X_REG_PC_CTRL, pc_count);
+
+	return 0;
+}
+
+
+
+static int da732x_set_dai_pll(struct snd_soc_codec *codec, int pll_id,
+			      int source, unsigned int freq_in,
+			      unsigned int freq_out)
+{
+	struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
+	int fref, indiv;
+	u8 div_lo, div_mid, div_hi;
+	u64 frac_div;
+
+	/* Disable PLL */
+	if (freq_out == 0) {
+		snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL,
+				    DA732X_PLL_EN, 0);
+		da732x->pll_en = false;
+		return 0;
+	}
+
+	if (da732x->pll_en)
+		return -EBUSY;
+
+	if (source == DA732X_SRCCLK_MCLK) {
+		/* Validate Sysclk rate */
+		switch (da732x->sysclk) {
+		case 11290000:
+		case 12288000:
+		case 22580000:
+		case 24576000:
+		case 45160000:
+		case 49152000:
+			snd_soc_write(codec, DA732X_REG_PLL_CTRL,
+				      DA732X_PLL_BYPASS);
+			return 0;
+		default:
+			dev_err(codec->dev,
+				"Cannot use PLL Bypass, invalid SYSCLK rate\n");
+			return -EINVAL;
+		}
+	}
+
+	indiv = da732x_get_input_div(codec, da732x->sysclk);
+	if (indiv < 0)
+		return indiv;
+
+	fref = (da732x->sysclk / indiv);
+	div_hi = freq_out / fref;
+	frac_div = (u64)(freq_out % fref) * 8192ULL;
+	do_div(frac_div, fref);
+	div_mid = (frac_div >> DA732X_1BYTE_SHIFT) & DA732X_U8_MASK;
+	div_lo = (frac_div) & DA732X_U8_MASK;
+
+	snd_soc_write(codec, DA732X_REG_PLL_DIV_LO, div_lo);
+	snd_soc_write(codec, DA732X_REG_PLL_DIV_MID, div_mid);
+	snd_soc_write(codec, DA732X_REG_PLL_DIV_HI, div_hi);
+
+	snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL, DA732X_PLL_EN,
+			    DA732X_PLL_EN);
+
+	da732x->pll_en = true;
+
+	return 0;
+}
+
+static int da732x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				 unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
+
+	da732x->sysclk = freq;
+
+	return 0;
+}
+
+#define DA732X_RATES	SNDRV_PCM_RATE_8000_96000
+
+#define	DA732X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops da732x_dai1_ops = {
+	.hw_params	= da732x_hw_params,
+	.set_fmt	= da732x_set_dai_fmt,
+	.set_sysclk	= da732x_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops da732x_dai2_ops = {
+	.hw_params	= da732x_hw_params,
+	.set_fmt	= da732x_set_dai_fmt,
+	.set_sysclk	= da732x_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver da732x_dai[] = {
+	{
+		.name	= "DA732X_AIFA",
+		.id	= DA732X_DAI_ID1,
+		.base	= DA732X_REG_AIFA1,
+		.playback = {
+			.stream_name = "AIFA Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = DA732X_RATES,
+			.formats = DA732X_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIFA Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = DA732X_RATES,
+			.formats = DA732X_FORMATS,
+		},
+		.ops = &da732x_dai1_ops,
+	},
+	{
+		.name	= "DA732X_AIFB",
+		.id	= DA732X_DAI_ID2,
+		.base	= DA732X_REG_AIFB1,
+		.playback = {
+			.stream_name = "AIFB Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = DA732X_RATES,
+			.formats = DA732X_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIFB Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = DA732X_RATES,
+			.formats = DA732X_FORMATS,
+		},
+		.ops = &da732x_dai2_ops,
+	},
+};
+
+static const struct regmap_config da732x_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+
+	.max_register		= DA732X_MAX_REG,
+	.reg_defaults		= da732x_reg_cache,
+	.num_reg_defaults	= ARRAY_SIZE(da732x_reg_cache),
+	.cache_type		= REGCACHE_RBTREE,
+};
+
+
+static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)
+{
+	u8 offset[DA732X_HP_DACS];
+	u8 sign[DA732X_HP_DACS];
+	u8 step = DA732X_DAC_OFFSET_STEP;
+
+	/* Initialize DAC offset calibration circuits and registers */
+	snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET,
+		      DA732X_HP_DAC_OFFSET_TRIM_VAL);
+	snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET,
+		      DA732X_HP_DAC_OFFSET_TRIM_VAL);
+	snd_soc_write(codec, DA732X_REG_HPL_DAC_OFF_CNTL,
+		      DA732X_HP_DAC_OFF_CALIBRATION |
+		      DA732X_HP_DAC_OFF_SCALE_STEPS);
+	snd_soc_write(codec, DA732X_REG_HPR_DAC_OFF_CNTL,
+		      DA732X_HP_DAC_OFF_CALIBRATION |
+		      DA732X_HP_DAC_OFF_SCALE_STEPS);
+
+	/* Wait for voltage stabilization */
+	msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+	/* Check DAC offset sign */
+	sign[DA732X_HPL_DAC] = (codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
+				DA732X_HP_DAC_OFF_CNTL_COMPO);
+	sign[DA732X_HPR_DAC] = (codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
+				DA732X_HP_DAC_OFF_CNTL_COMPO);
+
+	/* Binary search DAC offset values (both channels at once) */
+	offset[DA732X_HPL_DAC] = sign[DA732X_HPL_DAC] << DA732X_HP_DAC_COMPO_SHIFT;
+	offset[DA732X_HPR_DAC] = sign[DA732X_HPR_DAC] << DA732X_HP_DAC_COMPO_SHIFT;
+
+	do {
+		offset[DA732X_HPL_DAC] |= step;
+		offset[DA732X_HPR_DAC] |= step;
+		snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET,
+			      ~offset[DA732X_HPL_DAC] & DA732X_HP_DAC_OFF_MASK);
+		snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET,
+			      ~offset[DA732X_HPR_DAC] & DA732X_HP_DAC_OFF_MASK);
+
+		msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+		if ((codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
+		     DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPL_DAC])
+			offset[DA732X_HPL_DAC] &= ~step;
+		if ((codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
+		     DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPR_DAC])
+			offset[DA732X_HPR_DAC] &= ~step;
+
+		step >>= 1;
+	} while (step);
+
+	/* Write final DAC offsets to registers */
+	snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET,
+		      ~offset[DA732X_HPL_DAC] &	DA732X_HP_DAC_OFF_MASK);
+	snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET,
+		      ~offset[DA732X_HPR_DAC] &	DA732X_HP_DAC_OFF_MASK);
+
+	/* End DAC calibration mode */
+	snd_soc_write(codec, DA732X_REG_HPL_DAC_OFF_CNTL,
+		DA732X_HP_DAC_OFF_SCALE_STEPS);
+	snd_soc_write(codec, DA732X_REG_HPR_DAC_OFF_CNTL,
+		DA732X_HP_DAC_OFF_SCALE_STEPS);
+}
+
+static void da732x_output_offset_adjust(struct snd_soc_codec *codec)
+{
+	u8 offset[DA732X_HP_AMPS];
+	u8 sign[DA732X_HP_AMPS];
+	u8 step = DA732X_OUTPUT_OFFSET_STEP;
+
+	offset[DA732X_HPL_AMP] = DA732X_HP_OUT_TRIM_VAL;
+	offset[DA732X_HPR_AMP] = DA732X_HP_OUT_TRIM_VAL;
+
+	/* Initialize output offset calibration circuits and registers  */
+	snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL);
+	snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL);
+	snd_soc_write(codec, DA732X_REG_HPL,
+		      DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN);
+	snd_soc_write(codec, DA732X_REG_HPR,
+		      DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN);
+
+	/* Wait for voltage stabilization */
+	msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+	/* Check output offset sign */
+	sign[DA732X_HPL_AMP] = codec->hw_read(codec, DA732X_REG_HPL) &
+			       DA732X_HP_OUT_COMPO;
+	sign[DA732X_HPR_AMP] = codec->hw_read(codec, DA732X_REG_HPR) &
+			       DA732X_HP_OUT_COMPO;
+
+	snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_COMP |
+		      (sign[DA732X_HPL_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) |
+		      DA732X_HP_OUT_EN);
+	snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_OUT_COMP |
+		      (sign[DA732X_HPR_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) |
+		      DA732X_HP_OUT_EN);
+
+	/* Binary search output offset values (both channels at once) */
+	do {
+		offset[DA732X_HPL_AMP] |= step;
+		offset[DA732X_HPR_AMP] |= step;
+		snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET,
+			      offset[DA732X_HPL_AMP]);
+		snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET,
+			      offset[DA732X_HPR_AMP]);
+
+		msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+		if ((codec->hw_read(codec, DA732X_REG_HPL) &
+		     DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPL_AMP])
+			offset[DA732X_HPL_AMP] &= ~step;
+		if ((codec->hw_read(codec, DA732X_REG_HPR) &
+		     DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPR_AMP])
+			offset[DA732X_HPR_AMP] &= ~step;
+
+		step >>= 1;
+	} while (step);
+
+	/* Write final DAC offsets to registers */
+	snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, offset[DA732X_HPL_AMP]);
+	snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, offset[DA732X_HPR_AMP]);
+}
+
+static void da732x_hp_dc_offset_cancellation(struct snd_soc_codec *codec)
+{
+	/* Make sure that we have Soft Mute enabled */
+	snd_soc_write(codec, DA732X_REG_DAC1_SOFTMUTE, DA732X_SOFTMUTE_EN |
+		      DA732X_GAIN_RAMPED | DA732X_16_SAMPLES);
+	snd_soc_write(codec, DA732X_REG_DAC1_SEL, DA732X_DACL_EN |
+		      DA732X_DACR_EN | DA732X_DACL_SDM | DA732X_DACR_SDM |
+		      DA732X_DACL_MUTE | DA732X_DACR_MUTE);
+	snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN |
+		      DA732X_HP_OUT_MUTE | DA732X_HP_OUT_EN);
+	snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_OUT_EN |
+		      DA732X_HP_OUT_MUTE | DA732X_HP_OUT_DAC_EN);
+
+	da732x_dac_offset_adjust(codec);
+	da732x_output_offset_adjust(codec);
+
+	snd_soc_write(codec, DA732X_REG_DAC1_SEL, DA732X_DACS_DIS);
+	snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_DIS);
+	snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_DIS);
+}
+
+static int da732x_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_update_bits(codec, DA732X_REG_BIAS_EN,
+				    DA732X_BIAS_BOOST_MASK,
+				    DA732X_BIAS_BOOST_100PC);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			/* Init Codec */
+			snd_soc_write(codec, DA732X_REG_REF1,
+				      DA732X_VMID_FASTCHG);
+			snd_soc_write(codec, DA732X_REG_BIAS_EN,
+				      DA732X_BIAS_EN);
+
+			mdelay(DA732X_STARTUP_DELAY);
+
+			/* Disable Fast Charge and enable DAC ref voltage */
+			snd_soc_write(codec, DA732X_REG_REF1,
+				      DA732X_REFBUFX2_EN);
+
+			/* Enable bypass DSP routing */
+			snd_soc_write(codec, DA732X_REG_DATA_ROUTE,
+				      DA732X_BYPASS_DSP);
+
+			/* Enable Digital subsystem */
+			snd_soc_write(codec, DA732X_REG_DSP_CTRL,
+				      DA732X_DIGITAL_EN);
+
+			snd_soc_write(codec, DA732X_REG_SPARE1_OUT,
+				      DA732X_HP_DRIVER_EN |
+				      DA732X_HP_GATE_LOW |
+				      DA732X_HP_LOOP_GAIN_CTRL);
+			snd_soc_write(codec, DA732X_REG_HP_LIN1_GNDSEL,
+				      DA732X_HP_OUT_GNDSEL);
+
+			da732x_set_charge_pump(codec, DA732X_ENABLE_CP);
+
+			snd_soc_write(codec, DA732X_REG_CLK_EN1,
+			      DA732X_SYS3_CLK_EN | DA732X_PC_CLK_EN);
+
+			/* Enable Zero Crossing */
+			snd_soc_write(codec, DA732X_REG_INP_ZC_EN,
+				      DA732X_MIC1_PRE_ZC_EN |
+				      DA732X_MIC1_ZC_EN |
+				      DA732X_MIC2_PRE_ZC_EN |
+				      DA732X_MIC2_ZC_EN |
+				      DA732X_AUXL_ZC_EN |
+				      DA732X_AUXR_ZC_EN |
+				      DA732X_MIC3_PRE_ZC_EN |
+				      DA732X_MIC3_ZC_EN);
+			snd_soc_write(codec, DA732X_REG_OUT_ZC_EN,
+				      DA732X_HPL_ZC_EN | DA732X_HPR_ZC_EN |
+				      DA732X_LIN2_ZC_EN | DA732X_LIN3_ZC_EN |
+				      DA732X_LIN4_ZC_EN);
+
+			da732x_hp_dc_offset_cancellation(codec);
+
+			regcache_cache_only(codec->control_data, false);
+			regcache_sync(codec->control_data);
+		} else {
+			snd_soc_update_bits(codec, DA732X_REG_BIAS_EN,
+					    DA732X_BIAS_BOOST_MASK,
+					    DA732X_BIAS_BOOST_50PC);
+			snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL,
+					    DA732X_PLL_EN, 0);
+			da732x->pll_en = false;
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		regcache_cache_only(codec->control_data, true);
+		da732x_set_charge_pump(codec, DA732X_DISABLE_CP);
+		snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN,
+				    DA732X_BIAS_DIS);
+		da732x->pll_en = false;
+		break;
+	}
+
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+static int da732x_probe(struct snd_soc_codec *codec)
+{
+	struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int ret = 0;
+
+	da732x->codec = codec;
+
+	dapm->idle_bias_off = false;
+
+	codec->control_data = da732x->regmap;
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register codec.\n");
+		goto err;
+	}
+
+	da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+err:
+	return ret;
+}
+
+static int da732x_remove(struct snd_soc_codec *codec)
+{
+
+	da732x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_da732x = {
+	.probe			= da732x_probe,
+	.remove			= da732x_remove,
+	.set_bias_level		= da732x_set_bias_level,
+	.controls		= da732x_snd_controls,
+	.num_controls		= ARRAY_SIZE(da732x_snd_controls),
+	.dapm_widgets		= da732x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da732x_dapm_widgets),
+	.dapm_routes		= da732x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(da732x_dapm_routes),
+	.set_pll		= da732x_set_dai_pll,
+	.reg_cache_size		= ARRAY_SIZE(da732x_reg_cache),
+};
+
+static __devinit int da732x_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct da732x_priv *da732x;
+	unsigned int reg;
+	int ret;
+
+	da732x = devm_kzalloc(&i2c->dev, sizeof(struct da732x_priv),
+			      GFP_KERNEL);
+	if (!da732x)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, da732x);
+
+	da732x->regmap = devm_regmap_init_i2c(i2c, &da732x_regmap);
+	if (IS_ERR(da732x->regmap)) {
+		ret = PTR_ERR(da732x->regmap);
+		dev_err(&i2c->dev, "Failed to initialize regmap\n");
+		goto err;
+	}
+
+	ret = regmap_read(da732x->regmap, DA732X_REG_ID, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
+		goto err;
+	}
+
+	dev_info(&i2c->dev, "Revision: %d.%d\n",
+		 (reg & DA732X_ID_MAJOR_MASK), (reg & DA732X_ID_MINOR_MASK));
+
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da732x,
+				     da732x_dai, ARRAY_SIZE(da732x_dai));
+	if (ret != 0)
+		dev_err(&i2c->dev, "Failed to register codec.\n");
+
+err:
+	return ret;
+}
+
+static __devexit int da732x_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id da732x_i2c_id[] = {
+	{ "da7320", 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, da732x_i2c_id);
+
+static struct i2c_driver da732x_i2c_driver = {
+	.driver		= {
+		.name	= "da7320",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= da732x_i2c_probe,
+	.remove		= __devexit_p(da732x_i2c_remove),
+	.id_table	= da732x_i2c_id,
+};
+
+module_i2c_driver(da732x_i2c_driver);
+
+
+MODULE_DESCRIPTION("ASoC DA732X driver");
+MODULE_AUTHOR("Michal Hajduk <michal.hajduk@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h
new file mode 100644
index 0000000..c8ce547
--- /dev/null
+++ b/sound/soc/codecs/da732x.h
@@ -0,0 +1,133 @@
+/*
+ * da732x.h -- Dialog DA732X ALSA SoC Audio Driver Header File
+ *
+ * Copyright (C) 2012 Dialog Semiconductor GmbH
+ *
+ * Author: Michal Hajduk <Michal.Hajduk@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DA732X_H_
+#define __DA732X_H
+
+#include <sound/soc.h>
+
+/* General */
+#define	DA732X_U8_MASK			0xFF
+#define	DA732X_4BYTES			4
+#define	DA732X_3BYTES			3
+#define	DA732X_2BYTES			2
+#define	DA732X_1BYTE			1
+#define	DA732X_1BYTE_SHIFT		8
+#define	DA732X_2BYTES_SHIFT		16
+#define	DA732X_3BYTES_SHIFT		24
+#define	DA732X_4BYTES_SHIFT		32
+
+#define	DA732X_DACS_DIS			0x0
+#define	DA732X_HP_DIS			0x0
+#define	DA732X_CLEAR_REG		0x0
+
+/* Calibration */
+#define	DA732X_DAC_OFFSET_STEP		0x20
+#define	DA732X_OUTPUT_OFFSET_STEP	0x80
+#define	DA732X_HP_OUT_TRIM_VAL		0x0
+#define	DA732X_WAIT_FOR_STABILIZATION	1
+#define	DA732X_HPL_DAC			0
+#define	DA732X_HPR_DAC			1
+#define	DA732X_HP_DACS			2
+#define	DA732X_HPL_AMP			0
+#define	DA732X_HPR_AMP			1
+#define	DA732X_HP_AMPS			2
+
+/* Clock settings */
+#define DA732X_STARTUP_DELAY		100
+#define	DA732X_PLL_OUT_196608		196608000
+#define	DA732X_PLL_OUT_180634		180633600
+#define	DA732X_PLL_OUT_SRM		188620800
+#define	DA732X_MCLK_10MHZ		10000000
+#define	DA732X_MCLK_20MHZ		20000000
+#define	DA732X_MCLK_40MHZ		40000000
+#define	DA732X_MCLK_54MHZ		54000000
+#define	DA732X_MCLK_RET_0_10MHZ		0
+#define	DA732X_MCLK_VAL_0_10MHZ		1
+#define	DA732X_MCLK_RET_10_20MHZ	1
+#define	DA732X_MCLK_VAL_10_20MHZ	2
+#define	DA732X_MCLK_RET_20_40MHZ	2
+#define	DA732X_MCLK_VAL_20_40MHZ	4
+#define	DA732X_MCLK_RET_40_54MHZ	3
+#define	DA732X_MCLK_VAL_40_54MHZ	8
+#define	DA732X_DAI_ID1			0
+#define	DA732X_DAI_ID2			1
+#define	DA732X_SRCCLK_PLL		0
+#define	DA732X_SRCCLK_MCLK		1
+
+#define	DA732X_LIN_LP_VOL		0x4F
+#define	DA732X_LP_VOL			0x40
+
+/* Kcontrols */
+#define	DA732X_DAC_EN_MAX		2
+#define	DA732X_ADCL_MUX_MAX		2
+#define	DA732X_ADCR_MUX_MAX		3
+#define	DA732X_HPF_MODE_MAX		3
+#define	DA732X_HPF_MODE_SHIFT		4
+#define	DA732X_HPF_MUSIC_SHIFT		0
+#define	DA732X_HPF_MUSIC_MAX		4
+#define	DA732X_HPF_VOICE_SHIFT		4
+#define	DA732X_HPF_VOICE_MAX		8
+#define	DA732X_EQ_EN_MAX		1
+#define	DA732X_HPF_VOICE		1
+#define	DA732X_HPF_MUSIC		2
+#define	DA732X_HPF_DISABLED		0
+#define	DA732X_NO_INVERT		0
+#define	DA732X_INVERT			1
+#define	DA732X_SWITCH_MAX		1
+#define	DA732X_ENABLE_CP		1
+#define	DA732X_DISABLE_CP		0
+#define	DA732X_DISABLE_ALL_CLKS		0
+#define	DA732X_RESET_ADCS		0
+
+/* dB values */
+#define DA732X_MIC_VOL_DB_MIN		0
+#define DA732X_MIC_VOL_DB_INC		50
+#define DA732X_MIC_PRE_VOL_DB_MIN	0
+#define DA732X_MIC_PRE_VOL_DB_INC	600
+#define DA732X_AUX_VOL_DB_MIN		-6000
+#define DA732X_AUX_VOL_DB_INC		150
+#define DA732X_HP_VOL_DB_MIN		-2250
+#define DA732X_HP_VOL_DB_INC		150
+#define	DA732X_LIN2_VOL_DB_MIN		-1650
+#define	DA732X_LIN2_VOL_DB_INC		150
+#define	DA732X_LIN3_VOL_DB_MIN		-1650
+#define DA732X_LIN3_VOL_DB_INC		150
+#define	DA732X_LIN4_VOL_DB_MIN		-2250
+#define DA732X_LIN4_VOL_DB_INC		150
+#define	DA732X_EQ_BAND_VOL_DB_MIN	-1050
+#define	DA732X_EQ_BAND_VOL_DB_INC	150
+#define DA732X_DAC_VOL_DB_MIN		-7725
+#define DA732X_DAC_VOL_DB_INC		75
+#define DA732X_ADC_VOL_DB_MIN		0
+#define DA732X_ADC_VOL_DB_INC		-1
+#define	DA732X_EQ_OVERALL_VOL_DB_MIN	-1800
+#define	DA732X_EQ_OVERALL_VOL_DB_INC	600
+
+#define DA732X_SOC_ENUM_DOUBLE_R(xreg, xrreg, xmax, xtext) \
+	{.reg = xreg, .reg2 = xrreg, .max = xmax, .texts = xtext}
+
+enum da732x_sysctl {
+	DA732X_SR_8KHZ		= 0x1,
+	DA732X_SR_11_025KHZ	= 0x2,
+	DA732X_SR_12KHZ		= 0x3,
+	DA732X_SR_16KHZ		= 0x5,
+	DA732X_SR_22_05KHZ	= 0x6,
+	DA732X_SR_24KHZ		= 0x7,
+	DA732X_SR_32KHZ		= 0x9,
+	DA732X_SR_44_1KHZ	= 0xA,
+	DA732X_SR_48KHZ		= 0xB,
+	DA732X_SR_88_1KHZ	= 0xE,
+	DA732X_SR_96KHZ		= 0xF,
+};
+
+#endif /* __DA732X_H_ */
diff --git a/sound/soc/codecs/da732x_reg.h b/sound/soc/codecs/da732x_reg.h
new file mode 100644
index 0000000..bdd03ca
--- /dev/null
+++ b/sound/soc/codecs/da732x_reg.h
@@ -0,0 +1,654 @@
+/*
+ * da732x_reg.h --- Dialog DA732X ALSA SoC Audio Registers Header File
+ *
+ * Copyright (C) 2012 Dialog Semiconductor GmbH
+ *
+ * Author: Michal Hajduk <Michal.Hajduk@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DA732X_REG_H_
+#define __DA732X_REG_H_
+
+/* DA732X registers */
+#define	DA732X_REG_STATUS_EXT		0x00
+#define DA732X_REG_STATUS		0x01
+#define DA732X_REG_REF1			0x02
+#define DA732X_REG_BIAS_EN		0x03
+#define DA732X_REG_BIAS1		0x04
+#define DA732X_REG_BIAS2		0x05
+#define DA732X_REG_BIAS3		0x06
+#define DA732X_REG_BIAS4		0x07
+#define DA732X_REG_MICBIAS2		0x0F
+#define DA732X_REG_MICBIAS1		0x10
+#define DA732X_REG_MICDET		0x11
+#define DA732X_REG_MIC1_PRE		0x12
+#define DA732X_REG_MIC1			0x13
+#define DA732X_REG_MIC2_PRE		0x14
+#define DA732X_REG_MIC2			0x15
+#define DA732X_REG_AUX1L		0x16
+#define DA732X_REG_AUX1R		0x17
+#define DA732X_REG_MIC3_PRE		0x18
+#define DA732X_REG_MIC3			0x19
+#define DA732X_REG_INP_PINBIAS		0x1A
+#define DA732X_REG_INP_ZC_EN		0x1B
+#define DA732X_REG_INP_MUX		0x1D
+#define DA732X_REG_HP_DET		0x20
+#define DA732X_REG_HPL_DAC_OFFSET	0x21
+#define DA732X_REG_HPL_DAC_OFF_CNTL	0x22
+#define DA732X_REG_HPL_OUT_OFFSET	0x23
+#define DA732X_REG_HPL			0x24
+#define DA732X_REG_HPL_VOL		0x25
+#define DA732X_REG_HPR_DAC_OFFSET	0x26
+#define DA732X_REG_HPR_DAC_OFF_CNTL	0x27
+#define DA732X_REG_HPR_OUT_OFFSET	0x28
+#define DA732X_REG_HPR			0x29
+#define DA732X_REG_HPR_VOL		0x2A
+#define DA732X_REG_LIN2			0x2B
+#define DA732X_REG_LIN3			0x2C
+#define DA732X_REG_LIN4			0x2D
+#define DA732X_REG_OUT_ZC_EN		0x2E
+#define DA732X_REG_HP_LIN1_GNDSEL	0x37
+#define DA732X_REG_CP_HP1		0x3A
+#define DA732X_REG_CP_HP2		0x3B
+#define DA732X_REG_CP_CTRL1		0x40
+#define DA732X_REG_CP_CTRL2		0x41
+#define DA732X_REG_CP_CTRL3		0x42
+#define DA732X_REG_CP_LEVEL_MASK	0x43
+#define DA732X_REG_CP_DET		0x44
+#define DA732X_REG_CP_STATUS		0x45
+#define DA732X_REG_CP_THRESH1		0x46
+#define DA732X_REG_CP_THRESH2		0x47
+#define DA732X_REG_CP_THRESH3		0x48
+#define DA732X_REG_CP_THRESH4		0x49
+#define DA732X_REG_CP_THRESH5		0x4A
+#define DA732X_REG_CP_THRESH6		0x4B
+#define DA732X_REG_CP_THRESH7		0x4C
+#define DA732X_REG_CP_THRESH8		0x4D
+#define DA732X_REG_PLL_DIV_LO		0x50
+#define DA732X_REG_PLL_DIV_MID		0x51
+#define DA732X_REG_PLL_DIV_HI		0x52
+#define DA732X_REG_PLL_CTRL		0x53
+#define DA732X_REG_CLK_CTRL		0x54
+#define DA732X_REG_CLK_DSP		0x5A
+#define DA732X_REG_CLK_EN1		0x5B
+#define DA732X_REG_CLK_EN2		0x5C
+#define DA732X_REG_CLK_EN3		0x5D
+#define DA732X_REG_CLK_EN4		0x5E
+#define DA732X_REG_CLK_EN5		0x5F
+#define DA732X_REG_AIF_MCLK		0x60
+#define DA732X_REG_AIFA1		0x61
+#define DA732X_REG_AIFA2		0x62
+#define DA732X_REG_AIFA3		0x63
+#define DA732X_REG_AIFB1		0x64
+#define DA732X_REG_AIFB2		0x65
+#define DA732X_REG_AIFB3		0x66
+#define DA732X_REG_PC_CTRL		0x6A
+#define DA732X_REG_DATA_ROUTE		0x70
+#define DA732X_REG_DSP_CTRL		0x71
+#define DA732X_REG_CIF_CTRL2		0x74
+#define DA732X_REG_HANDSHAKE		0x75
+#define DA732X_REG_MBOX0		0x76
+#define DA732X_REG_MBOX1		0x77
+#define DA732X_REG_MBOX2		0x78
+#define DA732X_REG_MBOX_STATUS		0x79
+#define DA732X_REG_SPARE1_OUT		0x7D
+#define DA732X_REG_SPARE2_OUT		0x7E
+#define DA732X_REG_SPARE1_IN		0x7F
+#define DA732X_REG_ID			0x81
+#define DA732X_REG_ADC1_PD		0x90
+#define DA732X_REG_ADC1_HPF		0x93
+#define DA732X_REG_ADC1_SEL		0x94
+#define DA732X_REG_ADC1_EQ12		0x95
+#define DA732X_REG_ADC1_EQ34		0x96
+#define DA732X_REG_ADC1_EQ5		0x97
+#define DA732X_REG_ADC2_PD		0x98
+#define DA732X_REG_ADC2_HPF		0x9B
+#define DA732X_REG_ADC2_SEL		0x9C
+#define DA732X_REG_ADC2_EQ12		0x9D
+#define DA732X_REG_ADC2_EQ34		0x9E
+#define DA732X_REG_ADC2_EQ5		0x9F
+#define DA732X_REG_DAC1_HPF		0xA0
+#define DA732X_REG_DAC1_L_VOL		0xA1
+#define DA732X_REG_DAC1_R_VOL		0xA2
+#define DA732X_REG_DAC1_SEL		0xA3
+#define DA732X_REG_DAC1_SOFTMUTE	0xA4
+#define DA732X_REG_DAC1_EQ12		0xA5
+#define DA732X_REG_DAC1_EQ34		0xA6
+#define DA732X_REG_DAC1_EQ5		0xA7
+#define DA732X_REG_DAC2_HPF		0xB0
+#define DA732X_REG_DAC2_L_VOL		0xB1
+#define DA732X_REG_DAC2_R_VOL		0xB2
+#define DA732X_REG_DAC2_SEL		0xB3
+#define DA732X_REG_DAC2_SOFTMUTE	0xB4
+#define DA732X_REG_DAC2_EQ12		0xB5
+#define DA732X_REG_DAC2_EQ34		0xB6
+#define DA732X_REG_DAC2_EQ5		0xB7
+#define DA732X_REG_DAC3_HPF		0xC0
+#define DA732X_REG_DAC3_VOL		0xC1
+#define DA732X_REG_DAC3_SEL		0xC3
+#define DA732X_REG_DAC3_SOFTMUTE	0xC4
+#define DA732X_REG_DAC3_EQ12		0xC5
+#define DA732X_REG_DAC3_EQ34		0xC6
+#define DA732X_REG_DAC3_EQ5		0xC7
+#define DA732X_REG_BIQ_BYP		0xD2
+#define DA732X_REG_DMA_CMD		0xD3
+#define DA732X_REG_DMA_ADDR0		0xD4
+#define DA732X_REG_DMA_ADDR1		0xD5
+#define DA732X_REG_DMA_DATA0		0xD6
+#define DA732X_REG_DMA_DATA1		0xD7
+#define DA732X_REG_DMA_DATA2		0xD8
+#define DA732X_REG_DMA_DATA3		0xD9
+#define DA732X_REG_DMA_STATUS		0xDA
+#define DA732X_REG_BROWNOUT		0xDF
+#define DA732X_REG_UNLOCK		0xE0
+
+#define	DA732X_MAX_REG			DA732X_REG_UNLOCK
+/*
+ * Bits
+ */
+
+/* DA732X_REG_STATUS_EXT (addr=0x00) */
+#define	DA732X_STATUS_EXT_DSP			(1 << 4)
+#define	DA732X_STATUS_EXT_CLEAR			(0 << 0)
+
+/* DA732X_REG_STATUS	(addr=0x01) */
+#define DA732X_STATUS_PLL_LOCK			(1 << 0)
+#define DA732X_STATUS_PLL_MCLK_DET		(1 << 1)
+#define DA732X_STATUS_HPDET_OUT			(1 << 2)
+#define DA732X_STATUS_INP_MIXDET_1		(1 << 3)
+#define DA732X_STATUS_INP_MIXDET_2		(1 << 4)
+#define DA732X_STATUS_BO_STATUS			(1 << 5)
+
+/* DA732X_REG_REF1	(addr=0x02) */
+#define DA732X_VMID_FASTCHG			(1 << 1)
+#define DA732X_VMID_FASTDISCHG			(1 << 2)
+#define DA732X_REFBUFX2_EN			(1 << 6)
+#define DA732X_REFBUFX2_DIS			(0 << 6)
+
+/* DA732X_REG_BIAS_EN	(addr=0x03) */
+#define DA732X_BIAS_BOOST_MASK			(3 << 0)
+#define DA732X_BIAS_BOOST_100PC			(0 << 0)
+#define DA732X_BIAS_BOOST_133PC			(1 << 0)
+#define DA732X_BIAS_BOOST_88PC			(2 << 0)
+#define DA732X_BIAS_BOOST_50PC			(3 << 0)
+#define DA732X_BIAS_EN				(1 << 7)
+#define DA732X_BIAS_DIS				(0 << 7)
+
+/* DA732X_REG_BIAS1	(addr=0x04) */
+#define DA732X_BIAS1_HP_DAC_BIAS_MASK		(3 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_100PC		(0 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_150PC		(1 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_50PC		(2 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_75PC		(3 << 0)
+#define DA732X_BIAS1_HP_OUT_BIAS_MASK		(7 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_100PC		(0 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_125PC		(1 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_150PC		(2 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_175PC		(3 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_200PC		(4 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_250PC		(5 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_300PC		(6 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_350PC		(7 << 4)
+
+/* DA732X_REG_BIAS2	(addr=0x05) */
+#define DA732X_BIAS2_LINE2_DAC_BIAS_MASK	(3 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_100PC	(0 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_150PC	(1 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_50PC	(2 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_75PC	(3 << 0)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_MASK	(7 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_100PC	(0 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_125PC	(1 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_150PC	(2 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_175PC	(3 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_200PC	(4 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_250PC	(5 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_300PC	(6 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_350PC	(7 << 4)
+
+/* DA732X_REG_BIAS3	(addr=0x06) */
+#define DA732X_BIAS3_LINE3_DAC_BIAS_MASK	(3 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_100PC	(0 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_150PC	(1 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_50PC	(2 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_75PC	(3 << 0)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_MASK	(7 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_100PC	(0 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_125PC	(1 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_150PC	(2 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_175PC	(3 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_200PC	(4 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_250PC	(5 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_300PC	(6 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_350PC	(7 << 4)
+
+/* DA732X_REG_BIAS4	(addr=0x07) */
+#define DA732X_BIAS4_LINE4_DAC_BIAS_MASK	(3 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_100PC	(0 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_150PC	(1 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_50PC	(2 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_75PC	(3 << 0)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_MASK	(7 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_100PC	(0 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_125PC	(1 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_150PC	(2 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_175PC	(3 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_200PC	(4 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_250PC	(5 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_300PC	(6 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_350PC	(7 << 4)
+
+/* DA732X_REG_SIF_VDD_SEL	(addr=0x08) */
+#define DA732X_SIF_VDD_SEL_AIFA_VDD2		(1 << 0)
+#define DA732X_SIF_VDD_SEL_AIFB_VDD2		(1 << 1)
+#define DA732X_SIF_VDD_SEL_CIFA_VDD2		(1 << 4)
+
+/* DA732X_REG_MICBIAS2/1	(addr=0x0F/0x10) */
+#define DA732X_MICBIAS_VOLTAGE_MASK		(0x0F << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V		(0x00 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V05		(0x01 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V1		(0x02 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V15		(0x03 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V2		(0x04 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V25		(0x05 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V3		(0x06 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V35		(0x07 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V4		(0x08 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V45		(0x09 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V5		(0x0A << 0)
+#define DA732X_MICBIAS_EN			(1 << 7)
+#define DA732X_MICBIAS_EN_SHIFT			7
+#define DA732X_MICBIAS_VOLTAGE_SHIFT		0
+#define	DA732X_MICBIAS_VOLTAGE_MAX		0x0B
+
+/* DA732X_REG_MICDET	(addr=0x11) */
+#define DA732X_MICDET_INP_MICRES		(1 << 0)
+#define DA732X_MICDET_INP_MICHOOK		(1 << 1)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_8MS	(0 << 0)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_16MS	(1 << 0)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_32MS	(2 << 0)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_64MS	(3 << 0)
+#define DA732X_MICDET_INP_MICDET_EN		(1 << 7)
+
+/* DA732X_REG_MIC1/2/3_PRE (addr=0x11/0x14/0x18) */
+#define	DA732X_MICBOOST_MASK			0x7
+#define	DA732X_MICBOOST_SHIFT			0
+#define	DA732X_MICBOOST_MIN			0x1
+#define	DA732X_MICBOOST_MAX			DA732X_MICBOOST_MASK
+
+/* DA732X_REG_MIC1/2/3	(addr=0x13/0x15/0x19) */
+#define	DA732X_MIC_VOL_SHIFT			0
+#define	DA732X_MIC_VOL_VAL_MASK			0x1F
+#define DA732X_MIC_MUTE_SHIFT			6
+#define DA732X_MIC_EN_SHIFT			7
+#define DA732X_MIC_VOL_VAL_MIN			0x7
+#define	DA732X_MIC_VOL_VAL_MAX			DA732X_MIC_VOL_VAL_MASK
+
+/* DA732X_REG_AUX1L/R	(addr=0x16/0x17) */
+#define	DA732X_AUX_VOL_SHIFT			0
+#define	DA732X_AUX_VOL_MASK			0x7
+#define DA732X_AUX_MUTE_SHIFT			6
+#define DA732X_AUX_EN_SHIFT			7
+#define	DA732X_AUX_VOL_VAL_MAX			DA732X_AUX_VOL_MASK
+
+/* DA732X_REG_INP_PINBIAS	(addr=0x1A) */
+#define DA732X_INP_MICL_PINBIAS_EN		(1 << 0)
+#define DA732X_INP_MICR_PINBIAS_EN		(1 << 1)
+#define DA732X_INP_AUX1L_PINBIAS_EN		(1 << 2)
+#define DA732X_INP_AUX1R_PINBIAS_EN		(1 << 3)
+#define DA732X_INP_AUX2_PINBIAS_EN		(1 << 4)
+
+/* DA732X_REG_INP_ZC_EN	(addr=0x1B) */
+#define	DA732X_MIC1_PRE_ZC_EN			(1 << 0)
+#define	DA732X_MIC1_ZC_EN			(1 << 1)
+#define	DA732X_MIC2_PRE_ZC_EN			(1 << 2)
+#define	DA732X_MIC2_ZC_EN			(1 << 3)
+#define	DA732X_AUXL_ZC_EN			(1 << 4)
+#define	DA732X_AUXR_ZC_EN			(1 << 5)
+#define	DA732X_MIC3_PRE_ZC_EN			(1 << 6)
+#define	DA732X_MIC3_ZC_EN			(1 << 7)
+
+/* DA732X_REG_INP_MUX	(addr=0x1D) */
+#define DA732X_INP_ADC1L_MUX_SEL_AUX1L		(0 << 0)
+#define DA732X_INP_ADC1L_MUX_SEL_MIC1		(1 << 0)
+#define DA732X_INP_ADC1R_MUX_SEL_MASK		(3 << 2)
+#define DA732X_INP_ADC1R_MUX_SEL_AUX1R		(0 << 2)
+#define DA732X_INP_ADC1R_MUX_SEL_MIC2		(1 << 2)
+#define DA732X_INP_ADC1R_MUX_SEL_MIC3		(2 << 2)
+#define DA732X_INP_ADC2L_MUX_SEL_AUX1L		(0 << 4)
+#define DA732X_INP_ADC2L_MUX_SEL_MICL		(1 << 4)
+#define DA732X_INP_ADC2R_MUX_SEL_MASK		(3 << 6)
+#define DA732X_INP_ADC2R_MUX_SEL_AUX1R		(0 << 6)
+#define DA732X_INP_ADC2R_MUX_SEL_MICR		(1 << 6)
+#define DA732X_INP_ADC2R_MUX_SEL_AUX2		(2 << 6)
+#define	DA732X_ADC1L_MUX_SEL_SHIFT		0
+#define	DA732X_ADC1R_MUX_SEL_SHIFT		2
+#define	DA732X_ADC2L_MUX_SEL_SHIFT		4
+#define	DA732X_ADC2R_MUX_SEL_SHIFT		6
+
+/* DA732X_REG_HP_DET		(addr=0x20) */
+#define DA732X_HP_DET_AZ			(1 << 0)
+#define DA732X_HP_DET_SEL1			(1 << 1)
+#define DA732X_HP_DET_IS_MASK			(3 << 2)
+#define DA732X_HP_DET_IS_0_5UA			(0 << 2)
+#define DA732X_HP_DET_IS_1UA			(1 << 2)
+#define DA732X_HP_DET_IS_2UA			(2 << 2)
+#define DA732X_HP_DET_IS_4UA			(3 << 2)
+#define DA732X_HP_DET_RS_MASK			(3 << 4)
+#define DA732X_HP_DET_RS_INFINITE		(0 << 4)
+#define DA732X_HP_DET_RS_100KOHM		(1 << 4)
+#define DA732X_HP_DET_RS_10KOHM			(2 << 4)
+#define DA732X_HP_DET_RS_1KOHM			(3 << 4)
+#define DA732X_HP_DET_EN			(1 << 7)
+
+/* DA732X_REG_HPL_DAC_OFFSET	(addr=0x21/0x26) */
+#define DA732X_HP_DAC_OFFSET_TRIM_MASK		(0x3F << 0)
+#define DA732X_HP_DAC_OFFSET_DAC_SIGN		(1 << 6)
+
+/* DA732X_REG_HPL_DAC_OFF_CNTL	(addr=0x22/0x27) */
+#define DA732X_HP_DAC_OFF_CNTL_CONT_MASK	(7 << 0)
+#define DA732X_HP_DAC_OFF_CNTL_COMPO		(1 << 3)
+#define	DA732X_HP_DAC_OFF_CALIBRATION		(1 << 0)
+#define	DA732X_HP_DAC_OFF_SCALE_STEPS		(1 << 1)
+#define	DA732X_HP_DAC_OFF_MASK			0x7F
+#define DA732X_HP_DAC_COMPO_SHIFT		3
+
+/* DA732X_REG_HPL_OUT_OFFSET	(addr=0x23/0x28) */
+#define DA732X_HP_OUT_OFFSET_MASK		(0xFF << 0)
+#define	DA732X_HP_DAC_OFFSET_TRIM_VAL		0x7F
+
+/* DA732X_REG_HPL/R	(addr=0x24/0x29) */
+#define DA732X_HP_OUT_SIGN			(1 << 0)
+#define DA732X_HP_OUT_COMP			(1 << 1)
+#define DA732X_HP_OUT_RESERVED			(1 << 2)
+#define DA732X_HP_OUT_COMPO			(1 << 3)
+#define DA732X_HP_OUT_DAC_EN			(1 << 4)
+#define DA732X_HP_OUT_HIZ_EN			(1 << 5)
+#define	DA732X_HP_OUT_HIZ_DIS			(0 << 5)
+#define DA732X_HP_OUT_MUTE			(1 << 6)
+#define DA732X_HP_OUT_EN			(1 << 7)
+#define	DA732X_HP_OUT_COMPO_SHIFT		3
+#define	DA732X_HP_OUT_DAC_EN_SHIFT		4
+#define	DA732X_HP_HIZ_SHIFT			5
+#define	DA732X_HP_MUTE_SHIFT			6
+#define DA732X_HP_OUT_EN_SHIFT			7
+
+#define DA732X_OUT_HIZ_EN			(1 << 5)
+#define	DA732X_OUT_HIZ_DIS			(0 << 5)
+
+/* DA732X_REG_HPL/R_VOL	(addr=0x25/0x2A) */
+#define	DA732X_HP_VOL_VAL_MASK			0xF
+#define	DA732X_HP_VOL_SHIFT			0
+#define	DA732X_HP_VOL_VAL_MAX			DA732X_HP_VOL_VAL_MASK
+
+/* DA732X_REG_LIN2/3/4	(addr=0x2B/0x2C/0x2D) */
+#define DA732X_LOUT_VOL_SHIFT			0
+#define DA732X_LOUT_VOL_MASK			0x0F
+#define DA732X_LOUT_DAC_OFF			(0 << 4)
+#define DA732X_LOUT_DAC_EN			(1 << 4)
+#define DA732X_LOUT_HIZ_N_DIS			(0 << 5)
+#define DA732X_LOUT_HIZ_N_EN			(1 << 5)
+#define DA732X_LOUT_UNMUTED			(0 << 6)
+#define DA732X_LOUT_MUTED			(1 << 6)
+#define DA732X_LOUT_EN				(0 << 7)
+#define DA732X_LOUT_DIS				(1 << 7)
+#define DA732X_LOUT_DAC_EN_SHIFT		4
+#define	DA732X_LOUT_MUTE_SHIFT			6
+#define DA732X_LIN_OUT_EN_SHIFT			7
+#define DA732X_LOUT_VOL_VAL_MAX			DA732X_LOUT_VOL_MASK
+
+/* DA732X_REG_OUT_ZC_EN		(addr=0x2E) */
+#define	DA732X_HPL_ZC_EN_SHIFT			0
+#define DA732X_HPR_ZC_EN_SHIFT			1
+#define DA732X_HPL_ZC_EN			(1 << 0)
+#define DA732X_HPL_ZC_DIS			(0 << 0)
+#define DA732X_HPR_ZC_EN			(1 << 1)
+#define DA732X_HPR_ZC_DIS			(0 << 1)
+#define DA732X_LIN2_ZC_EN			(1 << 2)
+#define DA732X_LIN2_ZC_DIS			(0 << 2)
+#define DA732X_LIN3_ZC_EN			(1 << 3)
+#define DA732X_LIN3_ZC_DIS			(0 << 3)
+#define DA732X_LIN4_ZC_EN			(1 << 4)
+#define DA732X_LIN4_ZC_DIS			(0 << 4)
+
+/* DA732X_REG_HP_LIN1_GNDSEL (addr=0x37) */
+#define	DA732X_HP_OUT_GNDSEL			(1 << 0)
+
+/* DA732X_REG_CP_HP2 (addr=0x3a) */
+#define	DA732X_HP_CP_PULSESKIP			(1 << 0)
+#define	DA732X_HP_CP_REG			(1 << 1)
+#define DA732X_HP_CP_EN				(1 << 3)
+#define DA732X_HP_CP_DIS			(0 << 3)
+
+/* DA732X_REG_CP_CTRL1 (addr=0x40) */
+#define	DA732X_CP_MODE_MASK			(7 << 1)
+#define	DA732X_CP_CTRL_STANDBY			(0 << 1)
+#define	DA732X_CP_CTRL_CPVDD6			(2 << 1)
+#define	DA732X_CP_CTRL_CPVDD5			(3 << 1)
+#define	DA732X_CP_CTRL_CPVDD4			(4 << 1)
+#define	DA732X_CP_CTRL_CPVDD3			(5 << 1)
+#define	DA732X_CP_CTRL_CPVDD2			(6 << 1)
+#define	DA732X_CP_CTRL_CPVDD1			(7 << 1)
+#define	DA723X_CP_DIS				(0 << 7)
+#define	DA732X_CP_EN				(1 << 7)
+
+/* DA732X_REG_CP_CTRL2 (addr=0x41) */
+#define	DA732X_CP_BOOST				(1 << 0)
+#define	DA732X_CP_MANAGE_MAGNITUDE		(2 << 2)
+
+/* DA732X_REG_CP_CTRL3 (addr=0x42) */
+#define	DA732X_CP_1MHZ				(0 << 0)
+#define	DA732X_CP_500KHZ			(1 << 0)
+#define	DA732X_CP_250KHZ			(2 << 0)
+#define	DA732X_CP_125KHZ			(3 << 0)
+#define	DA732X_CP_63KHZ				(4 << 0)
+#define	DA732X_CP_0KHZ				(5 << 0)
+
+/* DA732X_REG_PLL_CTRL (addr=0x53) */
+#define	DA732X_PLL_INDIV_MASK			(3 << 0)
+#define	DA732X_PLL_SRM_EN			(1 << 2)
+#define	DA732X_PLL_EN				(1 << 7)
+#define	DA732X_PLL_BYPASS			(0 << 0)
+
+/* DA732X_REG_CLK_CTRL (addr=0x54) */
+#define	DA732X_SR1_MASK				(0xF)
+#define	DA732X_SR2_MASK				(0xF0)
+
+/* DA732X_REG_CLK_DSP (addr=0x5A) */
+#define	DA732X_DSP_FREQ_MASK			(7 << 0)
+#define	DA732X_DSP_FREQ_12MHZ			(0 << 0)
+#define	DA732X_DSP_FREQ_24MHZ			(1 << 0)
+#define	DA732X_DSP_FREQ_36MHZ			(2 << 0)
+#define	DA732X_DSP_FREQ_48MHZ			(3 << 0)
+#define	DA732X_DSP_FREQ_60MHZ			(4 << 0)
+#define	DA732X_DSP_FREQ_72MHZ			(5 << 0)
+#define	DA732X_DSP_FREQ_84MHZ			(6 << 0)
+#define	DA732X_DSP_FREQ_96MHZ			(7 << 0)
+
+/* DA732X_REG_CLK_EN1 (addr=0x5B) */
+#define	DA732X_DSP_CLK_EN			(1 << 0)
+#define	DA732X_SYS3_CLK_EN			(1 << 1)
+#define	DA732X_DSP12_CLK_EN			(1 << 2)
+#define	DA732X_PC_CLK_EN			(1 << 3)
+#define	DA732X_MCLK_SQR_EN			(1 << 7)
+
+/* DA732X_REG_CLK_EN2 (addr=0x5C) */
+#define	DA732X_UART_CLK_EN			(1 << 1)
+#define	DA732X_CP_CLK_EN			(1 << 2)
+#define	DA732X_CP_CLK_DIS			(0 << 2)
+
+/* DA732X_REG_CLK_EN3 (addr=0x5D) */
+#define	DA732X_ADCA_BB_CLK_EN			(1 << 0)
+#define	DA732X_ADCC_BB_CLK_EN			(1 << 4)
+
+/* DA732X_REG_CLK_EN4 (addr=0x5E) */
+#define	DA732X_DACA_BB_CLK_EN			(1 << 0)
+#define	DA732X_DACC_BB_CLK_EN			(1 << 4)
+#define DA732X_DACA_BB_CLK_SHIFT		0
+#define DA732X_DACC_BB_CLK_SHIFT		4
+
+/* DA732X_REG_CLK_EN5 (addr=0x5F) */
+#define	DA732X_DACE_BB_CLK_EN			(1 << 0)
+#define DA732X_DACE_BB_CLK_SHIFT		0
+
+/* DA732X_REG_AIF_MCLK (addr=0x60) */
+#define DA732X_AIFM_FRAME_64			(1 << 2)
+#define	DA732X_AIFM_SRC_SEL_AIFA		(1 << 6)
+#define	DA732X_CLK_GENERATION_AIF_A		(1 << 4)
+#define	DA732X_NO_CLK_GENERATION		0x0
+
+/* DA732X_REG_AIFA1 (addr=0x61) */
+#define	DA732X_AIF_WORD_MASK			(0x3 << 0)
+#define	DA732X_AIF_WORD_16			(0 << 0)
+#define	DA732X_AIF_WORD_20			(1 << 0)
+#define	DA732X_AIF_WORD_24			(2 << 0)
+#define	DA732X_AIF_WORD_32			(3 << 0)
+#define	DA732X_AIF_TDM_MONO_SHIFT		(1 << 6)
+#define	DA732X_AIF1_CLK_MASK			(1 << 7)
+#define	DA732X_AIF_SLAVE			(0 << 7)
+#define DA732X_AIF_CLK_FROM_SRC			(1 << 7)
+
+/* DA732X_REG_AIFA3 (addr=0x63) */
+#define	DA732X_AIF_MODE_SHIFT			0
+#define	DA732X_AIF_MODE_MASK			0x3
+#define	DA732X_AIF_I2S_MODE			(0 << 0)
+#define	DA732X_AIF_LEFT_J_MODE			(1 << 0)
+#define	DA732X_AIF_RIGHT_J_MODE			(2 << 0)
+#define	DA732X_AIF_DSP_MODE			(3 << 0)
+#define DA732X_AIF_WCLK_INV			(1 << 4)
+#define DA732X_AIF_BCLK_INV			(1 << 5)
+#define	DA732X_AIF_EN				(1 << 7)
+#define	DA732X_AIF_EN_SHIFT			7
+
+/* DA732X_REG_PC_CTRL (addr=0x6a) */
+#define	DA732X_PC_PULSE_AIFA			(0 << 0)
+#define	DA732X_PC_PULSE_AIFB			(1 << 0)
+#define	DA732X_PC_RESYNC_AUT			(1 << 6)
+#define	DA732X_PC_RESYNC_NOT_AUT		(0 << 6)
+#define	DA732X_PC_SAME				(1 << 7)
+
+/* DA732X_REG_DATA_ROUTE (addr=0x70) */
+#define DA732X_ADC1_TO_AIFA			(0 << 0)
+#define DA732X_DSP_TO_AIFA			(1 << 0)
+#define DA732X_ADC2_TO_AIFB			(0 << 1)
+#define DA732X_DSP_TO_AIFB			(1 << 1)
+#define DA732X_AIFA_TO_DAC1L			(0 << 2)
+#define DA732X_DSP_TO_DAC1L			(1 << 2)
+#define DA732X_AIFA_TO_DAC1R			(0 << 3)
+#define DA732X_DSP_TO_DAC1R			(1 << 3)
+#define DA732X_AIFB_TO_DAC2L			(0 << 4)
+#define DA732X_DSP_TO_DAC2L			(1 << 4)
+#define DA732X_AIFB_TO_DAC2R			(0 << 5)
+#define DA732X_DSP_TO_DAC2R			(1 << 5)
+#define DA732X_AIFB_TO_DAC3			(0 << 6)
+#define DA732X_DSP_TO_DAC3			(1 << 6)
+#define	DA732X_BYPASS_DSP			(0 << 0)
+#define	DA732X_ALL_TO_DSP			(0x7F << 0)
+
+/* DA732X_REG_DSP_CTRL (addr=0x71) */
+#define	DA732X_DIGITAL_EN			(1 << 0)
+#define	DA732X_DIGITAL_RESET			(0 << 0)
+#define	DA732X_DSP_CORE_EN			(1 << 1)
+#define	DA732X_DSP_CORE_RESET			(0 << 1)
+
+/* DA732X_REG_SPARE1_OUT (addr=0x7D)*/
+#define	DA732X_HP_DRIVER_EN			(1 << 0)
+#define	DA732X_HP_GATE_LOW			(1 << 2)
+#define DA732X_HP_LOOP_GAIN_CTRL		(1 << 3)
+
+/* DA732X_REG_ID (addr=0x81)*/
+#define DA732X_ID_MINOR_MASK			(0xF << 0)
+#define DA732X_ID_MAJOR_MASK			(0xF << 4)
+
+/* DA732X_REG_ADC1/2_PD (addr=0x90/0x98) */
+#define	DA732X_ADC_RST_MASK			(0x3 << 0)
+#define	DA732X_ADC_PD_MASK			(0x3 << 2)
+#define	DA732X_ADC_SET_ACT			(0x3 << 0)
+#define	DA732X_ADC_SET_RST			(0x0 << 0)
+#define	DA732X_ADC_ON				(0x3 << 2)
+#define	DA732X_ADC_OFF				(0x0 << 2)
+
+/* DA732X_REG_ADC1/2_SEL (addr=0x94/0x9C) */
+#define	DA732X_ADC_VOL_VAL_MASK			0x7
+#define	DA732X_ADCL_VOL_SHIFT			0
+#define	DA732X_ADCR_VOL_SHIFT			4
+#define DA732X_ADCL_EN_SHIFT			2
+#define DA732X_ADCR_EN_SHIFT			3
+#define	DA732X_ADCL_EN				(1 << 2)
+#define	DA732X_ADCR_EN				(1 << 3)
+#define	DA732X_ADC_VOL_VAL_MAX			DA732X_ADC_VOL_VAL_MASK
+
+/*
+ * DA732X_REG_ADC1/2_HPF (addr=0x93/0x9b)
+ * DA732x_REG_DAC1/2/3_HPG	(addr=0xA5/0xB5/0xC5)
+ */
+#define	DA732X_HPF_MUSIC_EN			(1 << 3)
+#define	DA732X_HPF_VOICE_EN			((1 << 3) | (1 << 7))
+#define	DA732X_HPF_MASK				((1 << 3) | (1 << 7))
+#define DA732X_HPF_DIS				((0 << 3) | (0 << 7))
+
+/* DA732X_REG_DAC1/2/3_VOL */
+#define DA732X_DAC_VOL_VAL_MASK			0x7F
+#define DA732X_DAC_VOL_SHIFT			0
+#define DA732X_DAC_VOL_VAL_MAX			DA732X_DAC_VOL_VAL_MASK
+
+/* DA732X_REG_DAC1/2/3_SEL (addr=0xA3/0xB3/0xC3) */
+#define DA732X_DACL_EN_SHIFT			3
+#define	DA732X_DACR_EN_SHIFT			7
+#define DA732X_DACL_MUTE_SHIFT			2
+#define	DA732X_DACR_MUTE_SHIFT			6
+#define DA732X_DACL_EN				(1 << 3)
+#define	DA732X_DACR_EN				(1 << 7)
+#define	DA732X_DACL_SDM				(1 << 0)
+#define	DA732X_DACR_SDM				(1 << 4)
+#define	DA732X_DACL_MUTE			(1 << 2)
+#define	DA732X_DACR_MUTE			(1 << 6)
+
+/* DA732X_REG_DAC_SOFTMUTE (addr=0xA4/0xB4/0xC4) */
+#define	DA732X_SOFTMUTE_EN			(1 << 7)
+#define	DA732X_GAIN_RAMPED			(1 << 6)
+#define	DA732X_16_SAMPLES			(4 << 0)
+#define	DA732X_SOFTMUTE_MASK			(1 << 7)
+#define	DA732X_SOFTMUTE_SHIFT			7
+
+/*
+ * DA732x_REG_ADC1/2_EQ12	(addr=0x95/0x9D)
+ * DA732x_REG_ADC1/2_EQ34	(addr=0x96/0x9E)
+ * DA732x_REG_ADC1/2_EQ5	(addr=0x97/0x9F)
+ * DA732x_REG_DAC1/2/3_EQ12	(addr=0xA5/0xB5/0xC5)
+ * DA732x_REG_DAC1/2/3_EQ34	(addr=0xA6/0xB6/0xC6)
+ * DA732x_REG_DAC1/2/3_EQ5	(addr=0xA7/0xB7/0xB7)
+ */
+#define	DA732X_EQ_VOL_VAL_MASK			0xF
+#define	DA732X_EQ_BAND1_SHIFT			0
+#define	DA732X_EQ_BAND2_SHIFT			4
+#define	DA732X_EQ_BAND3_SHIFT			0
+#define	DA732X_EQ_BAND4_SHIFT			4
+#define	DA732X_EQ_BAND5_SHIFT			0
+#define	DA732X_EQ_OVERALL_SHIFT			4
+#define	DA732X_EQ_OVERALL_VOL_VAL_MASK		0x3
+#define	DA732X_EQ_DIS				(0 << 7)
+#define	DA732X_EQ_EN				(1 << 7)
+#define	DA732X_EQ_EN_SHIFT			7
+#define	DA732X_EQ_VOL_VAL_MAX			DA732X_EQ_VOL_VAL_MASK
+#define	DA732X_EQ_OVERALL_VOL_VAL_MAX		DA732X_EQ_OVERALL_VOL_VAL_MASK
+
+/* DA732X_REG_DMA_CMD (addr=0xD3) */
+#define	DA732X_SEL_DSP_DMA_MASK			(3 << 0)
+#define	DA732X_SEL_DSP_DMA_DIS			(0 << 0)
+#define	DA732X_SEL_DSP_DMA_PMEM			(1 << 0)
+#define	DA732X_SEL_DSP_DMA_XMEM			(2 << 0)
+#define	DA732X_SEL_DSP_DMA_YMEM			(3 << 0)
+#define	DA732X_DSP_RW_MASK			(1 << 4)
+#define	DA732X_DSP_DMA_WRITE			(0 << 4)
+#define	DA732X_DSP_DMA_READ			(1 << 4)
+
+/* DA732X_REG_DMA_STATUS (addr=0xDA) */
+#define	DA732X_DSP_DMA_FREE			(0 << 0)
+#define	DA732X_DSP_DMA_BUSY			(1 << 0)
+
+#endif /* __DA732X_REG_H_ */
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
new file mode 100644
index 0000000..5d8f39e
--- /dev/null
+++ b/sound/soc/codecs/isabelle.c
@@ -0,0 +1,1176 @@
+/*
+ * isabelle.c - Low power high fidelity audio codec driver
+ *
+ * Copyright (c) 2012 Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ *
+ * Initially based on sound/soc/codecs/twl6040.c
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+#include "isabelle.h"
+
+
+/* Register default values for ISABELLE driver. */
+static struct reg_default isabelle_reg_defs[] = {
+	{ 0, 0x00 },
+	{ 1, 0x00 },
+	{ 2, 0x00 },
+	{ 3, 0x00 },
+	{ 4, 0x00 },
+	{ 5, 0x00 },
+	{ 6, 0x00 },
+	{ 7, 0x00 },
+	{ 8, 0x00 },
+	{ 9, 0x00 },
+	{ 10, 0x00 },
+	{ 11, 0x00 },
+	{ 12, 0x00 },
+	{ 13, 0x00 },
+	{ 14, 0x00 },
+	{ 15, 0x00 },
+	{ 16, 0x00 },
+	{ 17, 0x00 },
+	{ 18, 0x00 },
+	{ 19, 0x00 },
+	{ 20, 0x00 },
+	{ 21, 0x02 },
+	{ 22, 0x02 },
+	{ 23, 0x02 },
+	{ 24, 0x02 },
+	{ 25, 0x0F },
+	{ 26, 0x8F },
+	{ 27, 0x0F },
+	{ 28, 0x8F },
+	{ 29, 0x00 },
+	{ 30, 0x00 },
+	{ 31, 0x00 },
+	{ 32, 0x00 },
+	{ 33, 0x00 },
+	{ 34, 0x00 },
+	{ 35, 0x00 },
+	{ 36, 0x00 },
+	{ 37, 0x00 },
+	{ 38, 0x00 },
+	{ 39, 0x00 },
+	{ 40, 0x00 },
+	{ 41, 0x00 },
+	{ 42, 0x00 },
+	{ 43, 0x00 },
+	{ 44, 0x00 },
+	{ 45, 0x00 },
+	{ 46, 0x00 },
+	{ 47, 0x00 },
+	{ 48, 0x00 },
+	{ 49, 0x00 },
+	{ 50, 0x00 },
+	{ 51, 0x00 },
+	{ 52, 0x00 },
+	{ 53, 0x00 },
+	{ 54, 0x00 },
+	{ 55, 0x00 },
+	{ 56, 0x00 },
+	{ 57, 0x00 },
+	{ 58, 0x00 },
+	{ 59, 0x00 },
+	{ 60, 0x00 },
+	{ 61, 0x00 },
+	{ 62, 0x00 },
+	{ 63, 0x00 },
+	{ 64, 0x00 },
+	{ 65, 0x00 },
+	{ 66, 0x00 },
+	{ 67, 0x00 },
+	{ 68, 0x00 },
+	{ 69, 0x90 },
+	{ 70, 0x90 },
+	{ 71, 0x90 },
+	{ 72, 0x00 },
+	{ 73, 0x00 },
+	{ 74, 0x00 },
+	{ 75, 0x00 },
+	{ 76, 0x00 },
+	{ 77, 0x00 },
+	{ 78, 0x00 },
+	{ 79, 0x00 },
+	{ 80, 0x00 },
+	{ 81, 0x00 },
+	{ 82, 0x00 },
+	{ 83, 0x00 },
+	{ 84, 0x00 },
+	{ 85, 0x07 },
+	{ 86, 0x00 },
+	{ 87, 0x00 },
+	{ 88, 0x00 },
+	{ 89, 0x07 },
+	{ 90, 0x80 },
+	{ 91, 0x07 },
+	{ 92, 0x07 },
+	{ 93, 0x00 },
+	{ 94, 0x00 },
+	{ 95, 0x00 },
+	{ 96, 0x00 },
+	{ 97, 0x00 },
+	{ 98, 0x00 },
+	{ 99, 0x00 },
+};
+
+static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"};
+static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"};
+
+static const struct soc_enum isabelle_rx1_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, 1, isabelle_rx1_texts),
+	SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, 1, isabelle_rx1_texts),
+};
+
+static const struct soc_enum isabelle_rx2_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, 1, isabelle_rx2_texts),
+	SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, 1, isabelle_rx2_texts),
+};
+
+/* Headset DAC playback switches */
+static const struct snd_kcontrol_new rx1_mux_controls =
+	SOC_DAPM_ENUM("Route", isabelle_rx1_enum);
+
+static const struct snd_kcontrol_new rx2_mux_controls =
+	SOC_DAPM_ENUM("Route", isabelle_rx2_enum);
+
+/* TX input selection */
+static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"};
+static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"};
+
+static const struct soc_enum isabelle_atx_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, 1, isabelle_atx_texts),
+	SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_atx_texts),
+};
+
+static const struct soc_enum isabelle_vtx_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, 1, isabelle_vtx_texts),
+	SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_vtx_texts),
+};
+
+static const struct snd_kcontrol_new atx_mux_controls =
+	SOC_DAPM_ENUM("Route", isabelle_atx_enum);
+
+static const struct snd_kcontrol_new vtx_mux_controls =
+	SOC_DAPM_ENUM("Route", isabelle_vtx_enum);
+
+/* Left analog microphone selection */
+static const char *isabelle_amic1_texts[] = {
+	"Main Mic", "Headset Mic", "Aux/FM Left"};
+
+/* Left analog microphone selection */
+static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"};
+
+static const struct soc_enum isabelle_amic1_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 5,
+			ARRAY_SIZE(isabelle_amic1_texts),
+			isabelle_amic1_texts),
+};
+
+static const struct soc_enum isabelle_amic2_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 4,
+			ARRAY_SIZE(isabelle_amic2_texts),
+			isabelle_amic2_texts),
+};
+
+static const struct snd_kcontrol_new amic1_control =
+	SOC_DAPM_ENUM("Route", isabelle_amic1_enum);
+
+static const struct snd_kcontrol_new amic2_control =
+	SOC_DAPM_ENUM("Route", isabelle_amic2_enum);
+
+static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"};
+
+static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"};
+
+static const struct soc_enum isabelle_st_audio_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, 1,
+			isabelle_st_audio_texts),
+	SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, 1,
+			isabelle_st_audio_texts),
+};
+
+static const struct soc_enum isabelle_st_voice_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, 1,
+			isabelle_st_voice_texts),
+	SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, 1,
+			isabelle_st_voice_texts),
+};
+
+static const struct snd_kcontrol_new st_audio_control =
+	SOC_DAPM_ENUM("Route", isabelle_st_audio_enum);
+
+static const struct snd_kcontrol_new st_voice_control =
+	SOC_DAPM_ENUM("Route", isabelle_st_voice_enum);
+
+/* Mixer controls */
+static const struct snd_kcontrol_new isabelle_hs_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC1L Playback Switch", ISABELLE_HSDRV_CFG1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_HSDRV_CFG1_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_hs_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC1R Playback Switch", ISABELLE_HSDRV_CFG1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_HSDRV_CFG1_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_hf_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC2L Playback Switch", ISABELLE_HFLPGA_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_HFLPGA_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_hf_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC2R Playback Switch", ISABELLE_HFRPGA_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_HFRPGA_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_ep_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC2L Playback Switch", ISABELLE_EARDRV_CFG1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_EARDRV_CFG1_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_aux_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC3L Playback Switch", ISABELLE_LINEAMP_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_LINEAMP_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_aux_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC3R Playback Switch", ISABELLE_LINEAMP_CFG_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_LINEAMP_CFG_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga1_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga1_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga2_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga2_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("USNC Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga3_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga3_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx1_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DL1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx2_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("DL2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx3_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("DL3 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx4_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DL4 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx5_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DL5 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx6_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("DL6 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new ep_path_enable_control =
+	SOC_DAPM_SINGLE("Switch", ISABELLE_EARDRV_CFG2_REG, 0, 1, 0);
+
+/* TLV Declarations */
+static const DECLARE_TLV_DB_SCALE(mic_amp_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(afm_amp_tlv, -3300, 300, 0);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -1200, 200, 0);
+static const DECLARE_TLV_DB_SCALE(hf_tlv, -5000, 200, 0);
+
+/* from -63 to 0 dB in 1 dB steps */
+static const DECLARE_TLV_DB_SCALE(dpga_tlv, -6300, 100, 1);
+
+/* from -63 to 9 dB in 1 dB steps */
+static const DECLARE_TLV_DB_SCALE(rx_tlv, -6300, 100, 1);
+
+static const DECLARE_TLV_DB_SCALE(st_tlv, -2700, 300, 1);
+static const DECLARE_TLV_DB_SCALE(tx_tlv, -600, 100, 0);
+
+static const struct snd_kcontrol_new isabelle_snd_controls[] = {
+	SOC_DOUBLE_TLV("Headset Playback Volume", ISABELLE_HSDRV_GAIN_REG,
+			4, 0, 0xF, 0, dac_tlv),
+	SOC_DOUBLE_R_TLV("Handsfree Playback Volume",
+			ISABELLE_HFLPGA_CFG_REG, ISABELLE_HFRPGA_CFG_REG,
+			0, 0x1F, 0, hf_tlv),
+	SOC_DOUBLE_TLV("Aux Playback Volume", ISABELLE_LINEAMP_GAIN_REG,
+			4, 0, 0xF, 0, dac_tlv),
+	SOC_SINGLE_TLV("Earpiece Playback Volume", ISABELLE_EARDRV_CFG1_REG,
+			0, 0xF, 0, dac_tlv),
+
+	SOC_DOUBLE_TLV("Aux FM Volume", ISABELLE_APGA_GAIN_REG, 4, 0, 0xF, 0,
+			afm_amp_tlv),
+	SOC_SINGLE_TLV("Mic1 Capture Volume", ISABELLE_MIC1_GAIN_REG, 3, 0x1F,
+			0, mic_amp_tlv),
+	SOC_SINGLE_TLV("Mic2 Capture Volume", ISABELLE_MIC2_GAIN_REG, 3, 0x1F,
+			0, mic_amp_tlv),
+
+	SOC_DOUBLE_R_TLV("DPGA1 Volume", ISABELLE_DPGA1L_GAIN_REG,
+			ISABELLE_DPGA1R_GAIN_REG, 0, 0x3F, 0, dpga_tlv),
+	SOC_DOUBLE_R_TLV("DPGA2 Volume", ISABELLE_DPGA2L_GAIN_REG,
+			ISABELLE_DPGA2R_GAIN_REG, 0, 0x3F, 0, dpga_tlv),
+	SOC_DOUBLE_R_TLV("DPGA3 Volume", ISABELLE_DPGA3L_GAIN_REG,
+			ISABELLE_DPGA3R_GAIN_REG, 0, 0x3F, 0, dpga_tlv),
+
+	SOC_SINGLE_TLV("Sidetone Audio TX1 Volume",
+			ISABELLE_ATX_STPGA1_CFG_REG, 0, 0xF, 0, st_tlv),
+	SOC_SINGLE_TLV("Sidetone Audio TX2 Volume",
+			ISABELLE_ATX_STPGA2_CFG_REG, 0, 0xF, 0, st_tlv),
+	SOC_SINGLE_TLV("Sidetone Voice TX1 Volume",
+			ISABELLE_VTX_STPGA1_CFG_REG, 0, 0xF, 0, st_tlv),
+	SOC_SINGLE_TLV("Sidetone Voice TX2 Volume",
+			ISABELLE_VTX2_STPGA2_CFG_REG, 0, 0xF, 0, st_tlv),
+
+	SOC_SINGLE_TLV("Audio TX1 Volume", ISABELLE_ATX1_DPGA_REG, 4, 0xF, 0,
+			tx_tlv),
+	SOC_SINGLE_TLV("Audio TX2 Volume", ISABELLE_ATX2_DPGA_REG, 4, 0xF, 0,
+			tx_tlv),
+	SOC_SINGLE_TLV("Voice TX1 Volume", ISABELLE_VTX1_DPGA_REG, 4, 0xF, 0,
+			tx_tlv),
+	SOC_SINGLE_TLV("Voice TX2 Volume", ISABELLE_VTX2_DPGA_REG, 4, 0xF, 0,
+			tx_tlv),
+
+	SOC_SINGLE_TLV("RX1 DPGA Volume", ISABELLE_RX1_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+	SOC_SINGLE_TLV("RX2 DPGA Volume", ISABELLE_RX2_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+	SOC_SINGLE_TLV("RX3 DPGA Volume", ISABELLE_RX3_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+	SOC_SINGLE_TLV("RX4 DPGA Volume", ISABELLE_RX4_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+	SOC_SINGLE_TLV("RX5 DPGA Volume", ISABELLE_RX5_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+	SOC_SINGLE_TLV("RX6 DPGA Volume", ISABELLE_RX6_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+
+	SOC_SINGLE("Headset Noise Gate", ISABELLE_HS_NG_CFG1_REG, 7, 1, 0),
+	SOC_SINGLE("Handsfree Noise Gate", ISABELLE_HF_NG_CFG1_REG, 7, 1, 0),
+
+	SOC_SINGLE("ATX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		7, 1, 0),
+	SOC_SINGLE("ATX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		6, 1, 0),
+	SOC_SINGLE("ARX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		5, 1, 0),
+	SOC_SINGLE("ARX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		4, 1, 0),
+	SOC_SINGLE("ARX3 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		3, 1, 0),
+	SOC_SINGLE("ARX4 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		2, 1, 0),
+	SOC_SINGLE("ARX5 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		1, 1, 0),
+	SOC_SINGLE("ARX6 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		0, 1, 0),
+	SOC_SINGLE("VRX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		3, 1, 0),
+	SOC_SINGLE("VRX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		2, 1, 0),
+
+	SOC_SINGLE("ATX1 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+		7, 1, 0),
+	SOC_SINGLE("ATX2 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+		6, 1, 0),
+	SOC_SINGLE("VTX1 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+		5, 1, 0),
+	SOC_SINGLE("VTX2 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+		4, 1, 0),
+	SOC_SINGLE("RX1 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		5, 1, 0),
+	SOC_SINGLE("RX2 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		4, 1, 0),
+	SOC_SINGLE("RX3 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		3, 1, 0),
+	SOC_SINGLE("RX4 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		2, 1, 0),
+	SOC_SINGLE("RX5 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		1, 1, 0),
+	SOC_SINGLE("RX6 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		0, 1, 0),
+
+	SOC_SINGLE("ULATX12 Capture Switch", ISABELLE_ULATX12_INTF_CFG_REG,
+		7, 1, 0),
+
+	SOC_SINGLE("DL12 Playback Switch", ISABELLE_DL12_INTF_CFG_REG,
+		7, 1, 0),
+	SOC_SINGLE("DL34 Playback Switch", ISABELLE_DL34_INTF_CFG_REG,
+		7, 1, 0),
+	SOC_SINGLE("DL56 Playback Switch", ISABELLE_DL56_INTF_CFG_REG,
+		7, 1, 0),
+
+	/* DMIC Switch */
+	SOC_SINGLE("DMIC Switch", ISABELLE_DMIC_CFG_REG, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget isabelle_dapm_widgets[] = {
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MAINMIC"),
+	SND_SOC_DAPM_INPUT("HSMIC"),
+	SND_SOC_DAPM_INPUT("SUBMIC"),
+	SND_SOC_DAPM_INPUT("LINEIN1"),
+	SND_SOC_DAPM_INPUT("LINEIN2"),
+	SND_SOC_DAPM_INPUT("DMICDAT"),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HSOL"),
+	SND_SOC_DAPM_OUTPUT("HSOR"),
+	SND_SOC_DAPM_OUTPUT("HFL"),
+	SND_SOC_DAPM_OUTPUT("HFR"),
+	SND_SOC_DAPM_OUTPUT("EP"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+
+	SND_SOC_DAPM_PGA("DL1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DL2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DL3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DL4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DL5", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DL6", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Analog input muxes for the capture amplifiers */
+	SND_SOC_DAPM_MUX("Analog Left Capture Route",
+			SND_SOC_NOPM, 0, 0, &amic1_control),
+	SND_SOC_DAPM_MUX("Analog Right Capture Route",
+			SND_SOC_NOPM, 0, 0, &amic2_control),
+
+	SND_SOC_DAPM_MUX("Sidetone Audio Playback", SND_SOC_NOPM, 0, 0,
+			&st_audio_control),
+	SND_SOC_DAPM_MUX("Sidetone Voice Playback", SND_SOC_NOPM, 0, 0,
+			&st_voice_control),
+
+	/* AIF */
+	SND_SOC_DAPM_AIF_IN("INTF1_SDI", NULL, 0, ISABELLE_INTF_EN_REG, 7, 0),
+	SND_SOC_DAPM_AIF_IN("INTF2_SDI", NULL, 0, ISABELLE_INTF_EN_REG, 6, 0),
+
+	SND_SOC_DAPM_AIF_OUT("INTF1_SDO", NULL, 0, ISABELLE_INTF_EN_REG, 5, 0),
+	SND_SOC_DAPM_AIF_OUT("INTF2_SDO", NULL, 0, ISABELLE_INTF_EN_REG, 4, 0),
+
+	SND_SOC_DAPM_OUT_DRV("ULATX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("ULATX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("ULVTX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("ULVTX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Analog Capture PGAs */
+	SND_SOC_DAPM_PGA("MicAmp1", ISABELLE_AMIC_CFG_REG, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MicAmp2", ISABELLE_AMIC_CFG_REG, 4, 0, NULL, 0),
+
+	/* Auxiliary FM PGAs */
+	SND_SOC_DAPM_PGA("APGA1", ISABELLE_APGA_CFG_REG, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("APGA2", ISABELLE_APGA_CFG_REG, 6, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC1", "Left Front Capture",
+			ISABELLE_AMIC_CFG_REG, 7, 0),
+	SND_SOC_DAPM_ADC("ADC2", "Right Front Capture",
+			ISABELLE_AMIC_CFG_REG, 6, 0),
+
+	/* Microphone Bias */
+	SND_SOC_DAPM_SUPPLY("Headset Mic Bias", ISABELLE_ABIAS_CFG_REG,
+			3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Main Mic Bias", ISABELLE_ABIAS_CFG_REG,
+			2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Digital Mic1 Bias",
+			ISABELLE_DBIAS_CFG_REG, 3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Digital Mic2 Bias",
+			ISABELLE_DBIAS_CFG_REG, 2, 0, NULL, 0),
+
+	/* Mixers */
+	SND_SOC_DAPM_MIXER("Headset Left Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_hs_left_mixer_controls,
+			ARRAY_SIZE(isabelle_hs_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Headset Right Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_hs_right_mixer_controls,
+			ARRAY_SIZE(isabelle_hs_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Handsfree Left Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_hf_left_mixer_controls,
+			ARRAY_SIZE(isabelle_hf_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Handsfree Right Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_hf_right_mixer_controls,
+			ARRAY_SIZE(isabelle_hf_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_aux_left_mixer_controls,
+			ARRAY_SIZE(isabelle_aux_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_aux_right_mixer_controls,
+			ARRAY_SIZE(isabelle_aux_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Earphone Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_ep_mixer_controls,
+			ARRAY_SIZE(isabelle_ep_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("DPGA1L Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga1_left_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga1_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("DPGA1R Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga1_right_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga1_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("DPGA2L Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga2_left_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga2_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("DPGA2R Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga2_right_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga2_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("DPGA3L Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga3_left_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga3_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("DPGA3R Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga3_right_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga3_right_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("RX1 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx1_mixer_controls,
+			ARRAY_SIZE(isabelle_rx1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("RX2 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx2_mixer_controls,
+			ARRAY_SIZE(isabelle_rx2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("RX3 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx3_mixer_controls,
+			ARRAY_SIZE(isabelle_rx3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("RX4 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx4_mixer_controls,
+			ARRAY_SIZE(isabelle_rx4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("RX5 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx5_mixer_controls,
+			ARRAY_SIZE(isabelle_rx5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("RX6 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx6_mixer_controls,
+			ARRAY_SIZE(isabelle_rx6_mixer_controls)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC1L", "Headset Playback", ISABELLE_DAC_CFG_REG,
+			5, 0),
+	SND_SOC_DAPM_DAC("DAC1R", "Headset Playback", ISABELLE_DAC_CFG_REG,
+			4, 0),
+	SND_SOC_DAPM_DAC("DAC2L", "Handsfree Playback", ISABELLE_DAC_CFG_REG,
+			3, 0),
+	SND_SOC_DAPM_DAC("DAC2R", "Handsfree Playback", ISABELLE_DAC_CFG_REG,
+			2, 0),
+	SND_SOC_DAPM_DAC("DAC3L", "Lineout Playback", ISABELLE_DAC_CFG_REG,
+			1, 0),
+	SND_SOC_DAPM_DAC("DAC3R", "Lineout Playback", ISABELLE_DAC_CFG_REG,
+			0, 0),
+
+	/* Analog Playback PGAs */
+	SND_SOC_DAPM_PGA("Sidetone Audio PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Sidetone Voice PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HF Left PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HF Right PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA1L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA1R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA2L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA2R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA3L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA3R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Analog Playback Mux */
+	SND_SOC_DAPM_MUX("RX1 Playback", ISABELLE_ALU_RX_EN_REG, 5, 0,
+			&rx1_mux_controls),
+	SND_SOC_DAPM_MUX("RX2 Playback", ISABELLE_ALU_RX_EN_REG, 4, 0,
+			&rx2_mux_controls),
+
+	/* TX Select */
+	SND_SOC_DAPM_MUX("ATX Select", ISABELLE_TX_INPUT_CFG_REG,
+			7, 0, &atx_mux_controls),
+	SND_SOC_DAPM_MUX("VTX Select", ISABELLE_TX_INPUT_CFG_REG,
+			6, 0, &vtx_mux_controls),
+
+	SND_SOC_DAPM_SWITCH("Earphone Playback", SND_SOC_NOPM, 0, 0,
+			&ep_path_enable_control),
+
+	/* Output Drivers */
+	SND_SOC_DAPM_OUT_DRV("HS Left Driver", ISABELLE_HSDRV_CFG2_REG,
+			1, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HS Right Driver", ISABELLE_HSDRV_CFG2_REG,
+			0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("LINEOUT1 Left Driver", ISABELLE_LINEAMP_CFG_REG,
+			1, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("LINEOUT2 Right Driver", ISABELLE_LINEAMP_CFG_REG,
+			0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Earphone Driver", ISABELLE_EARDRV_CFG2_REG,
+			1, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUT_DRV("HF Left Driver", ISABELLE_HFDRV_CFG_REG,
+			1, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HF Right Driver", ISABELLE_HFDRV_CFG_REG,
+			0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route isabelle_intercon[] = {
+	/* Interface mapping */
+	{ "DL1", "DL12 Playback Switch", "INTF1_SDI" },
+	{ "DL2", "DL12 Playback Switch", "INTF1_SDI" },
+	{ "DL3", "DL34 Playback Switch", "INTF1_SDI" },
+	{ "DL4", "DL34 Playback Switch", "INTF1_SDI" },
+	{ "DL5", "DL56 Playback Switch", "INTF1_SDI" },
+	{ "DL6", "DL56 Playback Switch", "INTF1_SDI" },
+
+	{ "DL1", "DL12 Playback Switch", "INTF2_SDI" },
+	{ "DL2", "DL12 Playback Switch", "INTF2_SDI" },
+	{ "DL3", "DL34 Playback Switch", "INTF2_SDI" },
+	{ "DL4", "DL34 Playback Switch", "INTF2_SDI" },
+	{ "DL5", "DL56 Playback Switch", "INTF2_SDI" },
+	{ "DL6", "DL56 Playback Switch", "INTF2_SDI" },
+
+	/* Input side mapping */
+	{ "Sidetone Audio PGA", NULL, "Sidetone Audio Playback" },
+	{ "Sidetone Voice PGA", NULL, "Sidetone Voice Playback" },
+
+	{ "RX1 Mixer", "ST1 Playback Switch", "Sidetone Audio PGA" },
+
+	{ "RX1 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX1 Mixer", "DL1 Playback Switch", "DL1" },
+
+	{ "RX2 Mixer", "ST2 Playback Switch", "Sidetone Audio PGA" },
+
+	{ "RX2 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX2 Mixer", "DL2 Playback Switch", "DL2" },
+
+	{ "RX3 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX3 Mixer", "DL3 Playback Switch", "DL3" },
+
+	{ "RX4 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX4 Mixer", "DL4 Playback Switch", "DL4" },
+
+	{ "RX5 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX5 Mixer", "DL5 Playback Switch", "DL5" },
+
+	{ "RX6 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX6 Mixer", "DL6 Playback Switch", "DL6" },
+
+	/* Capture path */
+	{ "Analog Left Capture Route", "Headset Mic", "HSMIC" },
+	{ "Analog Left Capture Route", "Main Mic", "MAINMIC" },
+	{ "Analog Left Capture Route", "Aux/FM Left", "LINEIN1" },
+
+	{ "Analog Right Capture Route", "Sub Mic", "SUBMIC" },
+	{ "Analog Right Capture Route", "Aux/FM Right", "LINEIN2" },
+
+	{ "MicAmp1", NULL, "Analog Left Capture Route" },
+	{ "MicAmp2", NULL, "Analog Right Capture Route" },
+
+	{ "ADC1", NULL, "MicAmp1" },
+	{ "ADC2", NULL, "MicAmp2" },
+
+	{ "ATX Select", "AMIC1", "ADC1" },
+	{ "ATX Select", "DMIC", "DMICDAT" },
+	{ "ATX Select", "AMIC2", "ADC2" },
+
+	{ "VTX Select", "AMIC1", "ADC1" },
+	{ "VTX Select", "DMIC", "DMICDAT" },
+	{ "VTX Select", "AMIC2", "ADC2" },
+
+	{ "ULATX1", "ATX1 Filter Enable Switch", "ATX Select" },
+	{ "ULATX1", "ATX1 Filter Bypass Switch", "ATX Select" },
+	{ "ULATX2", "ATX2 Filter Enable Switch", "ATX Select" },
+	{ "ULATX2", "ATX2 Filter Bypass Switch", "ATX Select" },
+
+	{ "ULVTX1", "VTX1 Filter Enable Switch", "VTX Select" },
+	{ "ULVTX1", "VTX1 Filter Bypass Switch", "VTX Select" },
+	{ "ULVTX2", "VTX2 Filter Enable Switch", "VTX Select" },
+	{ "ULVTX2", "VTX2 Filter Bypass Switch", "VTX Select" },
+
+	{ "INTF1_SDO", "ULATX12 Capture Switch", "ULATX1" },
+	{ "INTF1_SDO", "ULATX12 Capture Switch", "ULATX2" },
+	{ "INTF2_SDO", "ULATX12 Capture Switch", "ULATX1" },
+	{ "INTF2_SDO", "ULATX12 Capture Switch", "ULATX2" },
+
+	{ "INTF1_SDO", NULL, "ULVTX1" },
+	{ "INTF1_SDO", NULL, "ULVTX2" },
+	{ "INTF2_SDO", NULL, "ULVTX1" },
+	{ "INTF2_SDO", NULL, "ULVTX2" },
+
+	/* AFM Path */
+	{ "APGA1", NULL, "LINEIN1" },
+	{ "APGA2", NULL, "LINEIN2" },
+
+	{ "RX1 Playback", "VRX1 Filter Bypass Switch", "RX1 Mixer" },
+	{ "RX1 Playback", "ARX1 Filter Bypass Switch", "RX1 Mixer" },
+	{ "RX1 Playback", "RX1 Filter Enable Switch", "RX1 Mixer" },
+
+	{ "RX2 Playback", "VRX2 Filter Bypass Switch", "RX2 Mixer" },
+	{ "RX2 Playback", "ARX2 Filter Bypass Switch", "RX2 Mixer" },
+	{ "RX2 Playback", "RX2 Filter Enable Switch", "RX2 Mixer" },
+
+	{ "RX3 Playback", "ARX3 Filter Bypass Switch", "RX3 Mixer" },
+	{ "RX3 Playback", "RX3 Filter Enable Switch", "RX3 Mixer" },
+
+	{ "RX4 Playback", "ARX4 Filter Bypass Switch", "RX4 Mixer" },
+	{ "RX4 Playback", "RX4 Filter Enable Switch", "RX4 Mixer" },
+
+	{ "RX5 Playback", "ARX5 Filter Bypass Switch", "RX5 Mixer" },
+	{ "RX5 Playback", "RX5 Filter Enable Switch", "RX5 Mixer" },
+
+	{ "RX6 Playback", "ARX6 Filter Bypass Switch", "RX6 Mixer" },
+	{ "RX6 Playback", "RX6 Filter Enable Switch", "RX6 Mixer" },
+
+	{ "DPGA1L Mixer", "RX1 Playback Switch", "RX1 Playback" },
+	{ "DPGA1L Mixer", "RX3 Playback Switch", "RX3 Playback" },
+	{ "DPGA1L Mixer", "RX5 Playback Switch", "RX5 Playback" },
+
+	{ "DPGA1R Mixer", "RX2 Playback Switch", "RX2 Playback" },
+	{ "DPGA1R Mixer", "RX4 Playback Switch", "RX4 Playback" },
+	{ "DPGA1R Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+	{ "DPGA1L", NULL, "DPGA1L Mixer" },
+	{ "DPGA1R", NULL, "DPGA1R Mixer" },
+
+	{ "DAC1L", NULL, "DPGA1L" },
+	{ "DAC1R", NULL, "DPGA1R" },
+
+	{ "DPGA2L Mixer", "RX1 Playback Switch", "RX1 Playback" },
+	{ "DPGA2L Mixer", "RX2 Playback Switch", "RX2 Playback" },
+	{ "DPGA2L Mixer", "RX3 Playback Switch", "RX3 Playback" },
+	{ "DPGA2L Mixer", "RX4 Playback Switch", "RX4 Playback" },
+	{ "DPGA2L Mixer", "RX5 Playback Switch", "RX5 Playback" },
+	{ "DPGA2L Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+	{ "DPGA2R Mixer", "RX2 Playback Switch", "RX2 Playback" },
+	{ "DPGA2R Mixer", "RX4 Playback Switch", "RX4 Playback" },
+	{ "DPGA2R Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+	{ "DPGA2L", NULL, "DPGA2L Mixer" },
+	{ "DPGA2R", NULL, "DPGA2R Mixer" },
+
+	{ "DAC2L", NULL, "DPGA2L" },
+	{ "DAC2R", NULL, "DPGA2R" },
+
+	{ "DPGA3L Mixer", "RX1 Playback Switch", "RX1 Playback" },
+	{ "DPGA3L Mixer", "RX3 Playback Switch", "RX3 Playback" },
+	{ "DPGA3L Mixer", "RX5 Playback Switch", "RX5 Playback" },
+
+	{ "DPGA3R Mixer", "RX2 Playback Switch", "RX2 Playback" },
+	{ "DPGA3R Mixer", "RX4 Playback Switch", "RX4 Playback" },
+	{ "DPGA3R Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+	{ "DPGA3L", NULL, "DPGA3L Mixer" },
+	{ "DPGA3R", NULL, "DPGA3R Mixer" },
+
+	{ "DAC3L", NULL, "DPGA3L" },
+	{ "DAC3R", NULL, "DPGA3R" },
+
+	{ "Headset Left Mixer", "DAC1L Playback Switch", "DAC1L" },
+	{ "Headset Left Mixer", "APGA1 Playback Switch", "APGA1" },
+
+	{ "Headset Right Mixer", "DAC1R Playback Switch", "DAC1R" },
+	{ "Headset Right Mixer", "APGA2 Playback Switch", "APGA2" },
+
+	{ "HS Left Driver", NULL, "Headset Left Mixer" },
+	{ "HS Right Driver", NULL, "Headset Right Mixer" },
+
+	{ "HSOL", NULL, "HS Left Driver" },
+	{ "HSOR", NULL, "HS Right Driver" },
+
+	/* Earphone playback path */
+	{ "Earphone Mixer", "DAC2L Playback Switch", "DAC2L" },
+	{ "Earphone Mixer", "APGA1 Playback Switch", "APGA1" },
+
+	{ "Earphone Playback", "Switch", "Earphone Mixer" },
+	{ "Earphone Driver", NULL, "Earphone Playback" },
+	{ "EP", NULL, "Earphone Driver" },
+
+	{ "Handsfree Left Mixer", "DAC2L Playback Switch", "DAC2L" },
+	{ "Handsfree Left Mixer", "APGA1 Playback Switch", "APGA1" },
+
+	{ "Handsfree Right Mixer", "DAC2R Playback Switch", "DAC2R" },
+	{ "Handsfree Right Mixer", "APGA2 Playback Switch", "APGA2" },
+
+	{ "HF Left PGA", NULL, "Handsfree Left Mixer" },
+	{ "HF Right PGA", NULL, "Handsfree Right Mixer" },
+
+	{ "HF Left Driver", NULL, "HF Left PGA" },
+	{ "HF Right Driver", NULL, "HF Right PGA" },
+
+	{ "HFL", NULL, "HF Left Driver" },
+	{ "HFR", NULL, "HF Right Driver" },
+
+	{ "LINEOUT1 Mixer", "DAC3L Playback Switch", "DAC3L" },
+	{ "LINEOUT1 Mixer", "APGA1 Playback Switch", "APGA1" },
+
+	{ "LINEOUT2 Mixer", "DAC3R Playback Switch", "DAC3R" },
+	{ "LINEOUT2 Mixer", "APGA2 Playback Switch", "APGA2" },
+
+	{ "LINEOUT1 Driver", NULL, "LINEOUT1 Mixer" },
+	{ "LINEOUT2 Driver", NULL, "LINEOUT2 Mixer" },
+
+	{ "LINEOUT1", NULL, "LINEOUT1 Driver" },
+	{ "LINEOUT2", NULL, "LINEOUT2 Driver" },
+};
+
+static int isabelle_hs_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, ISABELLE_DAC1_SOFTRAMP_REG,
+			BIT(4), (mute ? BIT(4) : 0));
+
+	return 0;
+}
+
+static int isabelle_hf_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, ISABELLE_DAC2_SOFTRAMP_REG,
+			BIT(4), (mute ? BIT(4) : 0));
+
+	return 0;
+}
+
+static int isabelle_line_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, ISABELLE_DAC3_SOFTRAMP_REG,
+			BIT(4), (mute ? BIT(4) : 0));
+
+	return 0;
+}
+
+static int isabelle_set_bias_level(struct snd_soc_codec *codec,
+				enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_update_bits(codec, ISABELLE_PWR_EN_REG,
+				ISABELLE_CHIP_EN, BIT(0));
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, ISABELLE_PWR_EN_REG,
+				ISABELLE_CHIP_EN, 0);
+		break;
+	}
+
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+static int isabelle_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	u16 aif = 0;
+	unsigned int fs_val = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs_val = ISABELLE_FS_RATE_8;
+		break;
+	case 11025:
+		fs_val = ISABELLE_FS_RATE_11;
+		break;
+	case 12000:
+		fs_val = ISABELLE_FS_RATE_12;
+		break;
+	case 16000:
+		fs_val = ISABELLE_FS_RATE_16;
+		break;
+	case 22050:
+		fs_val = ISABELLE_FS_RATE_22;
+		break;
+	case 24000:
+		fs_val = ISABELLE_FS_RATE_24;
+		break;
+	case 32000:
+		fs_val = ISABELLE_FS_RATE_32;
+		break;
+	case 44100:
+		fs_val = ISABELLE_FS_RATE_44;
+		break;
+	case 48000:
+		fs_val = ISABELLE_FS_RATE_48;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, ISABELLE_FS_RATE_CFG_REG,
+			ISABELLE_FS_RATE_MASK, fs_val);
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		aif |= ISABELLE_AIF_LENGTH_20;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		aif |= ISABELLE_AIF_LENGTH_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, ISABELLE_INTF_CFG_REG,
+			ISABELLE_AIF_LENGTH_MASK, aif);
+
+	return 0;
+}
+
+static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	unsigned int aif_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aif_val &= ~ISABELLE_AIF_MS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif_val |= ISABELLE_AIF_MS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		aif_val |= ISABELLE_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif_val |= ISABELLE_LEFT_J_MODE;
+		break;
+	case SND_SOC_DAIFMT_PDM:
+		aif_val |= ISABELLE_PDM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, ISABELLE_INTF_CFG_REG,
+			(ISABELLE_AIF_MS | ISABELLE_AIF_FMT_MASK), aif_val);
+
+	return 0;
+}
+
+/* Rates supported by Isabelle driver */
+#define ISABELLE_RATES		SNDRV_PCM_RATE_8000_48000
+
+/* Formates supported by Isabelle driver. */
+#define ISABELLE_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops isabelle_hs_dai_ops = {
+	.hw_params	= isabelle_hw_params,
+	.set_fmt	= isabelle_set_dai_fmt,
+	.digital_mute	= isabelle_hs_mute,
+};
+
+static struct snd_soc_dai_ops isabelle_hf_dai_ops = {
+	.hw_params	= isabelle_hw_params,
+	.set_fmt	= isabelle_set_dai_fmt,
+	.digital_mute	= isabelle_hf_mute,
+};
+
+static struct snd_soc_dai_ops isabelle_line_dai_ops = {
+	.hw_params	= isabelle_hw_params,
+	.set_fmt	= isabelle_set_dai_fmt,
+	.digital_mute	= isabelle_line_mute,
+};
+
+static struct snd_soc_dai_ops isabelle_ul_dai_ops = {
+	.hw_params	= isabelle_hw_params,
+	.set_fmt	= isabelle_set_dai_fmt,
+};
+
+/* ISABELLE dai structure */
+static struct snd_soc_dai_driver isabelle_dai[] = {
+	{
+		.name = "isabelle-dl1",
+		.playback = {
+			.stream_name = "Headset Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ISABELLE_RATES,
+			.formats = ISABELLE_FORMATS,
+		},
+		.ops = &isabelle_hs_dai_ops,
+	},
+	{
+		.name = "isabelle-dl2",
+		.playback = {
+			.stream_name = "Handsfree Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ISABELLE_RATES,
+			.formats = ISABELLE_FORMATS,
+		},
+		.ops = &isabelle_hf_dai_ops,
+	},
+	{
+		.name = "isabelle-lineout",
+		.playback = {
+			.stream_name = "Lineout Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ISABELLE_RATES,
+			.formats = ISABELLE_FORMATS,
+		},
+		.ops = &isabelle_line_dai_ops,
+	},
+	{
+		.name = "isabelle-ul",
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ISABELLE_RATES,
+			.formats = ISABELLE_FORMATS,
+		},
+		.ops = &isabelle_ul_dai_ops,
+	},
+};
+
+static int isabelle_probe(struct snd_soc_codec *codec)
+{
+	int ret = 0;
+
+	codec->control_data = dev_get_regmap(codec->dev, NULL);
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_isabelle = {
+	.probe = isabelle_probe,
+	.set_bias_level = isabelle_set_bias_level,
+	.controls = isabelle_snd_controls,
+	.num_controls = ARRAY_SIZE(isabelle_snd_controls),
+	.dapm_widgets = isabelle_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(isabelle_dapm_widgets),
+	.dapm_routes = isabelle_intercon,
+	.num_dapm_routes = ARRAY_SIZE(isabelle_intercon),
+	.idle_bias_off = true,
+};
+
+static const struct regmap_config isabelle_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = ISABELLE_MAX_REGISTER,
+	.reg_defaults = isabelle_reg_defs,
+	.num_reg_defaults = ARRAY_SIZE(isabelle_reg_defs),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit isabelle_i2c_probe(struct i2c_client *i2c,
+					const struct i2c_device_id *id)
+{
+	struct regmap *isabelle_regmap;
+	int ret = 0;
+
+	isabelle_regmap = devm_regmap_init_i2c(i2c, &isabelle_regmap_config);
+	if (IS_ERR(isabelle_regmap)) {
+		ret = PTR_ERR(isabelle_regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+	i2c_set_clientdata(i2c, isabelle_regmap);
+
+	ret =  snd_soc_register_codec(&i2c->dev,
+				&soc_codec_dev_isabelle, isabelle_dai,
+				ARRAY_SIZE(isabelle_dai));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int __devexit isabelle_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id isabelle_i2c_id[] = {
+	{ "isabelle", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, isabelle_i2c_id);
+
+static struct i2c_driver isabelle_i2c_driver = {
+	.driver = {
+		.name = "isabelle",
+		.owner = THIS_MODULE,
+	},
+	.probe = isabelle_i2c_probe,
+	.remove = __devexit_p(isabelle_i2c_remove),
+	.id_table = isabelle_i2c_id,
+};
+
+module_i2c_driver(isabelle_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ISABELLE driver");
+MODULE_AUTHOR("Vishwas A Deshpande <vishwas.a.deshpande@ti.com>");
+MODULE_AUTHOR("M R Swami Reddy <MR.Swami.Reddy@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/isabelle.h b/sound/soc/codecs/isabelle.h
new file mode 100644
index 0000000..96d839a
--- /dev/null
+++ b/sound/soc/codecs/isabelle.h
@@ -0,0 +1,143 @@
+/*
+ * isabelle.h - Low power high fidelity audio codec driver header file
+ *
+ * Copyright (c) 2012 Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+
+#ifndef _ISABELLE_H
+#define _ISABELLE_H
+
+#include <linux/bitops.h>
+
+/* ISABELLE REGISTERS */
+
+#define ISABELLE_PWR_CFG_REG		0x01
+#define ISABELLE_PWR_EN_REG		0x02
+#define ISABELLE_PS_EN1_REG		0x03
+#define ISABELLE_INT1_STATUS_REG	0x04
+#define ISABELLE_INT1_MASK_REG		0x05
+#define ISABELLE_INT2_STATUS_REG	0x06
+#define ISABELLE_INT2_MASK_REG		0x07
+#define ISABELLE_HKCTL1_REG		0x08
+#define ISABELLE_HKCTL2_REG		0x09
+#define ISABELLE_HKCTL3_REG		0x0A
+#define ISABELLE_ACCDET_STATUS_REG	0x0B
+#define ISABELLE_BUTTON_ID_REG		0x0C
+#define ISABELLE_PLL_CFG_REG		0x10
+#define ISABELLE_PLL_EN_REG		0x11
+#define ISABELLE_FS_RATE_CFG_REG	0x12
+#define ISABELLE_INTF_CFG_REG		0x13
+#define ISABELLE_INTF_EN_REG		0x14
+#define ISABELLE_ULATX12_INTF_CFG_REG	0x15
+#define ISABELLE_DL12_INTF_CFG_REG	0x16
+#define ISABELLE_DL34_INTF_CFG_REG	0x17
+#define ISABELLE_DL56_INTF_CFG_REG	0x18
+#define ISABELLE_ATX_STPGA1_CFG_REG	0x19
+#define ISABELLE_ATX_STPGA2_CFG_REG	0x1A
+#define ISABELLE_VTX_STPGA1_CFG_REG	0x1B
+#define ISABELLE_VTX2_STPGA2_CFG_REG	0x1C
+#define ISABELLE_ATX1_DPGA_REG		0x1D
+#define ISABELLE_ATX2_DPGA_REG		0x1E
+#define ISABELLE_VTX1_DPGA_REG		0x1F
+#define ISABELLE_VTX2_DPGA_REG		0x20
+#define ISABELLE_TX_INPUT_CFG_REG	0x21
+#define ISABELLE_RX_INPUT_CFG_REG	0x22
+#define ISABELLE_RX_INPUT_CFG2_REG	0x23
+#define ISABELLE_VOICE_HPF_CFG_REG	0x24
+#define ISABELLE_AUDIO_HPF_CFG_REG	0x25
+#define ISABELLE_RX1_DPGA_REG		0x26
+#define ISABELLE_RX2_DPGA_REG		0x27
+#define ISABELLE_RX3_DPGA_REG		0x28
+#define ISABELLE_RX4_DPGA_REG		0x29
+#define ISABELLE_RX5_DPGA_REG		0x2A
+#define ISABELLE_RX6_DPGA_REG		0x2B
+#define ISABELLE_ALU_TX_EN_REG		0x2C
+#define ISABELLE_ALU_RX_EN_REG		0x2D
+#define ISABELLE_IIR_RESYNC_REG		0x2E
+#define ISABELLE_ABIAS_CFG_REG		0x30
+#define ISABELLE_DBIAS_CFG_REG		0x31
+#define ISABELLE_MIC1_GAIN_REG		0x32
+#define ISABELLE_MIC2_GAIN_REG		0x33
+#define ISABELLE_AMIC_CFG_REG		0x34
+#define ISABELLE_DMIC_CFG_REG		0x35
+#define ISABELLE_APGA_GAIN_REG		0x36
+#define ISABELLE_APGA_CFG_REG		0x37
+#define ISABELLE_TX_GAIN_DLY_REG	0x38
+#define ISABELLE_RX_GAIN_DLY_REG	0x39
+#define ISABELLE_RX_PWR_CTRL_REG	0x3A
+#define ISABELLE_DPGA1LR_IN_SEL_REG	0x3B
+#define ISABELLE_DPGA1L_GAIN_REG	0x3C
+#define ISABELLE_DPGA1R_GAIN_REG	0x3D
+#define ISABELLE_DPGA2L_IN_SEL_REG	0x3E
+#define ISABELLE_DPGA2R_IN_SEL_REG	0x3F
+#define ISABELLE_DPGA2L_GAIN_REG	0x40
+#define ISABELLE_DPGA2R_GAIN_REG	0x41
+#define ISABELLE_DPGA3LR_IN_SEL_REG	0x42
+#define ISABELLE_DPGA3L_GAIN_REG	0x43
+#define ISABELLE_DPGA3R_GAIN_REG	0x44
+#define ISABELLE_DAC1_SOFTRAMP_REG	0x45
+#define ISABELLE_DAC2_SOFTRAMP_REG	0x46
+#define ISABELLE_DAC3_SOFTRAMP_REG	0x47
+#define ISABELLE_DAC_CFG_REG		0x48
+#define ISABELLE_EARDRV_CFG1_REG	0x49
+#define ISABELLE_EARDRV_CFG2_REG	0x4A
+#define ISABELLE_HSDRV_GAIN_REG		0x4B
+#define ISABELLE_HSDRV_CFG1_REG		0x4C
+#define ISABELLE_HSDRV_CFG2_REG		0x4D
+#define ISABELLE_HS_NG_CFG1_REG		0x4E
+#define ISABELLE_HS_NG_CFG2_REG		0x4F
+#define ISABELLE_LINEAMP_GAIN_REG	0x50
+#define ISABELLE_LINEAMP_CFG_REG	0x51
+#define ISABELLE_HFL_VOL_CTRL_REG	0x52
+#define ISABELLE_HFL_SFTVOL_CTRL_REG	0x53
+#define ISABELLE_HFL_LIM_CTRL_1_REG	0x54
+#define ISABELLE_HFL_LIM_CTRL_2_REG	0x55
+#define ISABELLE_HFR_VOL_CTRL_REG	0x56
+#define ISABELLE_HFR_SFTVOL_CTRL_REG	0x57
+#define ISABELLE_HFR_LIM_CTRL_1_REG	0x58
+#define ISABELLE_HFR_LIM_CTRL_2_REG	0x59
+#define ISABELLE_HF_MODE_REG		0x5A
+#define ISABELLE_HFLPGA_CFG_REG		0x5B
+#define ISABELLE_HFRPGA_CFG_REG		0x5C
+#define ISABELLE_HFDRV_CFG_REG		0x5D
+#define ISABELLE_PDMOUT_CFG1_REG	0x5E
+#define ISABELLE_PDMOUT_CFG2_REG	0x5F
+#define ISABELLE_PDMOUT_L_WM_REG	0x60
+#define ISABELLE_PDMOUT_R_WM_REG	0x61
+#define ISABELLE_HF_NG_CFG1_REG		0x62
+#define ISABELLE_HF_NG_CFG2_REG		0x63
+
+/* ISABELLE_PWR_EN_REG (0x02h) */
+#define ISABELLE_CHIP_EN		BIT(0)
+
+/* ISABELLE DAI FORMATS */
+#define ISABELLE_AIF_FMT_MASK		0x70
+#define ISABELLE_I2S_MODE		0x0
+#define ISABELLE_LEFT_J_MODE		0x1
+#define ISABELLE_PDM_MODE		0x2
+
+#define ISABELLE_AIF_LENGTH_MASK	0x30
+#define ISABELLE_AIF_LENGTH_20		0x00
+#define ISABELLE_AIF_LENGTH_32		0x10
+
+#define ISABELLE_AIF_MS			0x80
+
+#define ISABELLE_FS_RATE_MASK		0xF
+#define ISABELLE_FS_RATE_8		0x0
+#define ISABELLE_FS_RATE_11		0x1
+#define ISABELLE_FS_RATE_12		0x2
+#define ISABELLE_FS_RATE_16		0x4
+#define ISABELLE_FS_RATE_22		0x5
+#define ISABELLE_FS_RATE_24		0x6
+#define ISABELLE_FS_RATE_32		0x8
+#define ISABELLE_FS_RATE_44		0x9
+#define ISABELLE_FS_RATE_48		0xA
+
+#define ISABELLE_MAX_REGISTER		0xFF
+
+#endif
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index 802b9f1..99b0a9d 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -12,7 +12,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -1358,7 +1357,7 @@ static struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
 };
 
 /* LM49453 dai structure. */
-static const struct snd_soc_dai_driver lm49453_dai[] = {
+static struct snd_soc_dai_driver lm49453_dai[] = {
 	{
 		.name = "LM49453 Headset",
 		.playback = {
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 35179e2..7cd508e 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -2216,7 +2216,7 @@ static irqreturn_t max98095_report_jack(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-int max98095_jack_detect_enable(struct snd_soc_codec *codec)
+static int max98095_jack_detect_enable(struct snd_soc_codec *codec)
 {
 	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 	int ret = 0;
@@ -2245,7 +2245,7 @@ int max98095_jack_detect_enable(struct snd_soc_codec *codec)
 	return ret;
 }
 
-int max98095_jack_detect_disable(struct snd_soc_codec *codec)
+static int max98095_jack_detect_disable(struct snd_soc_codec *codec)
 {
 	int ret = 0;
 
@@ -2286,6 +2286,7 @@ int max98095_jack_detect(struct snd_soc_codec *codec,
 	max98095_report_jack(client->irq, codec);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(max98095_jack_detect);
 
 #ifdef CONFIG_PM
 static int max98095_suspend(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 22cb5bf..96aa5fa 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -638,7 +638,7 @@ static __devinit int ml26124_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, priv);
 
-	priv->regmap = regmap_init_i2c(i2c, &ml26124_i2c_regmap);
+	priv->regmap = devm_regmap_init_i2c(i2c, &ml26124_i2c_regmap);
 	if (IS_ERR(priv->regmap)) {
 		ret = PTR_ERR(priv->regmap);
 		dev_err(&i2c->dev, "regmap_init_i2c() failed: %d\n", ret);
@@ -651,10 +651,7 @@ static __devinit int ml26124_i2c_probe(struct i2c_client *i2c,
 
 static __devexit int ml26124_i2c_remove(struct i2c_client *client)
 {
-	struct ml26124_priv *priv = i2c_get_clientdata(client);
-
 	snd_soc_unregister_codec(&client->dev);
-	regmap_exit(priv->regmap);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 64d2a4f..58ef59d 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -368,7 +368,7 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
 static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
 
 static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
-	SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
+	SOC_DOUBLE_TLV("Class-D Playback Volume", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
 
 /* Left DAC Mux */
 static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 0418fa1..3fd5b29 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -1,7 +1,7 @@
 /*
  * wm2000.c  --  WM2000 ALSA Soc Audio driver
  *
- * Copyright 2008-2010 Wolfson Microelectronics PLC.
+ * Copyright 2008-2011 Wolfson Microelectronics PLC.
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
@@ -674,9 +674,39 @@ static int wm2000_resume(struct snd_soc_codec *codec)
 #define wm2000_resume NULL
 #endif
 
+static bool wm2000_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM2000_REG_SYS_START:
+	case WM2000_REG_SPEECH_CLARITY:
+	case WM2000_REG_SYS_WATCHDOG:
+	case WM2000_REG_ANA_VMID_PD_TIME:
+	case WM2000_REG_ANA_VMID_PU_TIME:
+	case WM2000_REG_CAT_FLTR_INDX:
+	case WM2000_REG_CAT_GAIN_0:
+	case WM2000_REG_SYS_STATUS:
+	case WM2000_REG_SYS_MODE_CNTRL:
+	case WM2000_REG_SYS_START0:
+	case WM2000_REG_SYS_START1:
+	case WM2000_REG_ID1:
+	case WM2000_REG_ID2:
+	case WM2000_REG_REVISON:
+	case WM2000_REG_SYS_CTL1:
+	case WM2000_REG_SYS_CTL2:
+	case WM2000_REG_ANC_STAT:
+	case WM2000_REG_IF_CTL:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static const struct regmap_config wm2000_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
+
+	.max_register = WM2000_REG_IF_CTL,
+	.readable_reg = wm2000_readable_reg,
 };
 
 static int wm2000_probe(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index acbdc5f..32682c1 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1491,6 +1491,7 @@ static int wm2200_bclk_rates_dat[WM2200_NUM_BCLK_RATES] = {
 
 static int wm2200_bclk_rates_cd[WM2200_NUM_BCLK_RATES] = {
 	5644800,
+	3763200,
 	2882400,
 	1881600,
 	1411200,
diff --git a/sound/soc/codecs/wm5100-tables.c b/sound/soc/codecs/wm5100-tables.c
index e167207..e239f4b 100644
--- a/sound/soc/codecs/wm5100-tables.c
+++ b/sound/soc/codecs/wm5100-tables.c
@@ -1,7 +1,7 @@
 /*
  * wm5100-tables.c  --  WM5100 ALSA SoC Audio driver data
  *
- * Copyright 2011 Wolfson Microelectronics plc
+ * Copyright 2011-2 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index cb6d537..f481729 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -1,7 +1,7 @@
 /*
  * wm5100.c  --  WM5100 ALSA SoC Audio driver
  *
- * Copyright 2011 Wolfson Microelectronics plc
+ * Copyright 2011-2 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
@@ -2378,13 +2378,6 @@ static int wm5100_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int wm5100_soc_volatile(struct snd_soc_codec *codec,
-			       unsigned int reg)
-{
-	return true;
-}
-
-
 static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
 	.probe =	wm5100_probe,
 	.remove =	wm5100_remove,
@@ -2392,8 +2385,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
 	.set_sysclk = wm5100_set_sysclk,
 	.set_pll = wm5100_set_fll,
 	.idle_bias_off = 1,
-	.reg_cache_size = WM5100_MAX_REGISTER,
-	.volatile_register = wm5100_soc_volatile,
 
 	.seq_notifier = wm5100_seq_notifier,
 	.controls = wm5100_snd_controls,
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
new file mode 100644
index 0000000..9b9ea7f
--- /dev/null
+++ b/sound/soc/codecs/wm5102.c
@@ -0,0 +1,870 @@
+/*
+ * wm5102.c  --  WM5102 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm5102.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+#include "wm5102.h"
+
+struct wm5102_priv {
+	struct arizona_priv core;
+	struct arizona_fll fll[2];
+};
+
+static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new wm5102_snd_controls[] = {
+SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
+	   ARIZONA_IN1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL,
+	   ARIZONA_IN2_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL,
+	   ARIZONA_IN3_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R_RANGE_TLV("IN1 Volume", ARIZONA_IN1L_CONTROL,
+		       ARIZONA_IN1R_CONTROL,
+		       ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_DOUBLE_R_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL,
+		       ARIZONA_IN2R_CONTROL,
+		       ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_DOUBLE_R_RANGE_TLV("IN3 Volume", ARIZONA_IN3L_CONTROL,
+		       ARIZONA_IN3R_CONTROL,
+		       ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+
+SOC_DOUBLE_R("IN1 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+	     ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN2 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+	     ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN3 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L,
+	     ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("IN1 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+		 ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_PGA_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+		 ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_PGA_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
+		 ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_PGA_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+
+ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
+
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+		   ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5,
+		   ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
+	       ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
+
+ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT2L", ARIZONA_OUT2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT2R", ARIZONA_OUT2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L,
+	   ARIZONA_OUT1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("OUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L,
+	   ARIZONA_OUT2_OSR_SHIFT, 1, 0),
+SOC_SINGLE("EPOUT High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L,
+	   ARIZONA_OUT3_OSR_SHIFT, 1, 0),
+SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
+	   ARIZONA_OUT4_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
+	   ARIZONA_OUT5_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("OUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	   ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("OUT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	       ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+
+SOC_DOUBLE_R_RANGE_TLV("HPOUT1 Volume", ARIZONA_OUTPUT_PATH_CONFIG_1L,
+		       ARIZONA_OUTPUT_PATH_CONFIG_1R,
+		       ARIZONA_OUT1L_PGA_VOL_SHIFT,
+		       0x34, 0x40, 0, ana_tlv),
+SOC_DOUBLE_R_RANGE_TLV("OUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L,
+		       ARIZONA_OUTPUT_PATH_CONFIG_2R,
+		       ARIZONA_OUT2L_PGA_VOL_SHIFT,
+		       0x34, 0x40, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("EPOUT Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L,
+		     ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv),
+
+SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
+	   ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+};
+
+ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1R, ARIZONA_OUT5RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
+
+static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
+		    0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("NOISE"),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
+		 ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Mic Mute Mixer", ARIZONA_MIC_NOISE_MIX_CONTROL_1,
+		 ARIZONA_MICMUTE_MIX_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+		 0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+		 0, NULL, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
+ARIZONA_MIXER_WIDGETS(EQ3, "EQ3"),
+ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"),
+
+ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
+ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"),
+ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(Mic, "Mic"),
+ARIZONA_MIXER_WIDGETS(Noise, "Noise"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
+ARIZONA_MIXER_WIDGETS(OUT2L, "HPOUT2L"),
+ARIZONA_MIXER_WIDGETS(OUT2R, "HPOUT2R"),
+ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"),
+ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
+ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+
+ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
+ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2L"),
+SND_SOC_DAPM_OUTPUT("HPOUT2R"),
+SND_SOC_DAPM_OUTPUT("EPOUTN"),
+SND_SOC_DAPM_OUTPUT("EPOUTP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Noise Generator", "Noise Generator" }, \
+	{ name, "Tone Generator 1", "Tone Generator 1" }, \
+	{ name, "Tone Generator 2", "Tone Generator 2" }, \
+	{ name, "IN1L", "IN1L PGA" }, \
+	{ name, "IN1R", "IN1R PGA" }, \
+	{ name, "IN2L", "IN2L PGA" }, \
+	{ name, "IN2R", "IN2R PGA" }, \
+	{ name, "IN3L", "IN3L PGA" }, \
+	{ name, "IN3R", "IN3R PGA" }, \
+	{ name, "Mic Mute Mixer", "Mic Mute Mixer" }, \
+	{ name, "AIF1RX1", "AIF1RX1" }, \
+	{ name, "AIF1RX2", "AIF1RX2" }, \
+	{ name, "AIF1RX3", "AIF1RX3" }, \
+	{ name, "AIF1RX4", "AIF1RX4" }, \
+	{ name, "AIF1RX5", "AIF1RX5" }, \
+	{ name, "AIF1RX6", "AIF1RX6" }, \
+	{ name, "AIF1RX7", "AIF1RX7" }, \
+	{ name, "AIF1RX8", "AIF1RX8" }, \
+	{ name, "AIF2RX1", "AIF2RX1" }, \
+	{ name, "AIF2RX2", "AIF2RX2" }, \
+	{ name, "AIF3RX1", "AIF3RX1" }, \
+	{ name, "AIF3RX2", "AIF3RX2" }, \
+	{ name, "EQ1", "EQ1" }, \
+	{ name, "EQ2", "EQ2" }, \
+	{ name, "EQ3", "EQ3" }, \
+	{ name, "EQ4", "EQ4" }, \
+	{ name, "DRC1L", "DRC1L" }, \
+	{ name, "DRC1R", "DRC1R" }, \
+	{ name, "DRC2L", "DRC2L" }, \
+	{ name, "DRC2R", "DRC2R" }, \
+	{ name, "LHPF1", "LHPF1" }, \
+	{ name, "LHPF2", "LHPF2" }, \
+	{ name, "LHPF3", "LHPF3" }, \
+	{ name, "LHPF4", "LHPF4" }
+
+static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
+	{ "AIF2 Capture", NULL, "DBVDD2" },
+	{ "AIF2 Playback", NULL, "DBVDD2" },
+
+	{ "AIF3 Capture", NULL, "DBVDD3" },
+	{ "AIF3 Playback", NULL, "DBVDD3" },
+
+	{ "OUT1L", NULL, "CPVDD" },
+	{ "OUT1R", NULL, "CPVDD" },
+	{ "OUT2L", NULL, "CPVDD" },
+	{ "OUT2R", NULL, "CPVDD" },
+	{ "OUT3L", NULL, "CPVDD" },
+
+	{ "OUT4L", NULL, "SPKVDDL" },
+	{ "OUT4R", NULL, "SPKVDDR" },
+
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT2L", NULL, "SYSCLK" },
+	{ "OUT2R", NULL, "SYSCLK" },
+	{ "OUT3L", NULL, "SYSCLK" },
+	{ "OUT4L", NULL, "SYSCLK" },
+	{ "OUT4R", NULL, "SYSCLK" },
+	{ "OUT5L", NULL, "SYSCLK" },
+	{ "OUT5R", NULL, "SYSCLK" },
+
+	{ "MICBIAS1", NULL, "MICVDD" },
+	{ "MICBIAS2", NULL, "MICVDD" },
+	{ "MICBIAS3", NULL, "MICVDD" },
+
+	{ "Noise Generator", NULL, "NOISE" },
+	{ "Tone Generator 1", NULL, "TONE" },
+	{ "Tone Generator 2", NULL, "TONE" },
+
+	{ "Mic Mute Mixer", NULL, "Noise Mixer" },
+	{ "Mic Mute Mixer", NULL, "Mic Mixer" },
+
+	{ "AIF1 Capture", NULL, "AIF1TX1" },
+	{ "AIF1 Capture", NULL, "AIF1TX2" },
+	{ "AIF1 Capture", NULL, "AIF1TX3" },
+	{ "AIF1 Capture", NULL, "AIF1TX4" },
+	{ "AIF1 Capture", NULL, "AIF1TX5" },
+	{ "AIF1 Capture", NULL, "AIF1TX6" },
+	{ "AIF1 Capture", NULL, "AIF1TX7" },
+	{ "AIF1 Capture", NULL, "AIF1TX8" },
+
+	{ "AIF1RX1", NULL, "AIF1 Playback" },
+	{ "AIF1RX2", NULL, "AIF1 Playback" },
+	{ "AIF1RX3", NULL, "AIF1 Playback" },
+	{ "AIF1RX4", NULL, "AIF1 Playback" },
+	{ "AIF1RX5", NULL, "AIF1 Playback" },
+	{ "AIF1RX6", NULL, "AIF1 Playback" },
+	{ "AIF1RX7", NULL, "AIF1 Playback" },
+	{ "AIF1RX8", NULL, "AIF1 Playback" },
+
+	{ "AIF2 Capture", NULL, "AIF2TX1" },
+	{ "AIF2 Capture", NULL, "AIF2TX2" },
+
+	{ "AIF2RX1", NULL, "AIF2 Playback" },
+	{ "AIF2RX2", NULL, "AIF2 Playback" },
+
+	{ "AIF3 Capture", NULL, "AIF3TX1" },
+	{ "AIF3 Capture", NULL, "AIF3TX2" },
+
+	{ "AIF3RX1", NULL, "AIF3 Playback" },
+	{ "AIF3RX2", NULL, "AIF3 Playback" },
+
+	{ "AIF1 Playback", NULL, "SYSCLK" },
+	{ "AIF2 Playback", NULL, "SYSCLK" },
+	{ "AIF3 Playback", NULL, "SYSCLK" },
+
+	{ "AIF1 Capture", NULL, "SYSCLK" },
+	{ "AIF2 Capture", NULL, "SYSCLK" },
+	{ "AIF3 Capture", NULL, "SYSCLK" },
+
+	ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+	ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
+	ARIZONA_MIXER_ROUTES("OUT2R", "HPOUT2R"),
+	ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"),
+
+	ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"),
+	ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"),
+	ARIZONA_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
+	ARIZONA_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
+
+	ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+	ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+	ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+	ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+	ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+	ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+	ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+
+	ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
+	ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
+
+	ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
+	ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
+	ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
+	ARIZONA_MIXER_ROUTES("EQ4", "EQ4"),
+
+	ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
+	ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
+	ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"),
+	ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"),
+
+	ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+	ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+	ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+	ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+	{ "HPOUT1L", NULL, "OUT1L" },
+	{ "HPOUT1R", NULL, "OUT1R" },
+
+	{ "HPOUT2L", NULL, "OUT2L" },
+	{ "HPOUT2R", NULL, "OUT2R" },
+
+	{ "EPOUTN", NULL, "OUT3L" },
+	{ "EPOUTP", NULL, "OUT3L" },
+
+	{ "SPKOUTLN", NULL, "OUT4L" },
+	{ "SPKOUTLP", NULL, "OUT4L" },
+
+	{ "SPKOUTRN", NULL, "OUT4R" },
+	{ "SPKOUTRP", NULL, "OUT4R" },
+
+	{ "SPKDAT1L", NULL, "OUT5L" },
+	{ "SPKDAT1R", NULL, "OUT5R" },
+};
+
+static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec);
+
+	switch (fll_id) {
+	case WM5102_FLL1:
+		return arizona_set_fll(&wm5102->fll[0], source, Fref, Fout);
+	case WM5102_FLL2:
+		return arizona_set_fll(&wm5102->fll[1], source, Fref, Fout);
+	default:
+		return -EINVAL;
+	}
+}
+
+#define WM5102_RATES SNDRV_PCM_RATE_8000_192000
+
+#define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm5102_dai[] = {
+	{
+		.name = "wm5102-aif1",
+		.id = 1,
+		.base = ARIZONA_AIF1_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = WM5102_RATES,
+			.formats = WM5102_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 8,
+			 .rates = WM5102_RATES,
+			 .formats = WM5102_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "wm5102-aif2",
+		.id = 2,
+		.base = ARIZONA_AIF2_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM5102_RATES,
+			.formats = WM5102_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM5102_RATES,
+			 .formats = WM5102_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "wm5102-aif3",
+		.id = 3,
+		.base = ARIZONA_AIF3_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM5102_RATES,
+			.formats = WM5102_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF3 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM5102_RATES,
+			 .formats = WM5102_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static int wm5102_codec_probe(struct snd_soc_codec *codec)
+{
+	struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	codec->control_data = priv->core.arizona->regmap;
+	return snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP);
+}
+
+#define WM5102_DIG_VU 0x0200
+
+static unsigned int wm5102_digital_vu[] = {
+	ARIZONA_ADC_DIGITAL_VOLUME_1L,
+	ARIZONA_ADC_DIGITAL_VOLUME_1R,
+	ARIZONA_ADC_DIGITAL_VOLUME_2L,
+	ARIZONA_ADC_DIGITAL_VOLUME_2R,
+	ARIZONA_ADC_DIGITAL_VOLUME_3L,
+	ARIZONA_ADC_DIGITAL_VOLUME_3R,
+
+	ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	ARIZONA_DAC_DIGITAL_VOLUME_1R,
+	ARIZONA_DAC_DIGITAL_VOLUME_2L,
+	ARIZONA_DAC_DIGITAL_VOLUME_2R,
+	ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	ARIZONA_DAC_DIGITAL_VOLUME_3R,
+	ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	ARIZONA_DAC_DIGITAL_VOLUME_4R,
+	ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	ARIZONA_DAC_DIGITAL_VOLUME_5R,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
+	.probe = wm5102_codec_probe,
+
+	.idle_bias_off = true,
+
+	.set_sysclk = arizona_set_sysclk,
+	.set_pll = wm5102_set_fll,
+
+	.controls = wm5102_snd_controls,
+	.num_controls = ARRAY_SIZE(wm5102_snd_controls),
+	.dapm_widgets = wm5102_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm5102_dapm_widgets),
+	.dapm_routes = wm5102_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes),
+};
+
+static int __devinit wm5102_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct wm5102_priv *wm5102;
+	int i;
+
+	wm5102 = devm_kzalloc(&pdev->dev, sizeof(struct wm5102_priv),
+			      GFP_KERNEL);
+	if (wm5102 == NULL)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, wm5102);
+
+	wm5102->core.arizona = arizona;
+
+	arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+			 &wm5102->fll[0]);
+	arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+			 &wm5102->fll[1]);
+
+	/* Latch volume update bits */
+	for (i = 0; i < ARRAY_SIZE(wm5102_digital_vu); i++)
+		regmap_update_bits(arizona->regmap, wm5102_digital_vu[i],
+				   WM5102_DIG_VU, WM5102_DIG_VU);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_idle(&pdev->dev);
+
+	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102,
+				      wm5102_dai, ARRAY_SIZE(wm5102_dai));
+}
+
+static int __devexit wm5102_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver wm5102_codec_driver = {
+	.driver = {
+		.name = "wm5102-codec",
+		.owner = THIS_MODULE,
+	},
+	.probe = wm5102_probe,
+	.remove = __devexit_p(wm5102_remove),
+};
+
+module_platform_driver(wm5102_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM5102 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm5102-codec");
diff --git a/sound/soc/codecs/wm5102.h b/sound/soc/codecs/wm5102.h
new file mode 100644
index 0000000..d30477f
--- /dev/null
+++ b/sound/soc/codecs/wm5102.h
@@ -0,0 +1,21 @@
+/*
+ * wm5102.h  --  WM5102 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM5102_H
+#define _WM5102_H
+
+#include "arizona.h"
+
+#define WM5102_FLL1 1
+#define WM5102_FLL2 2
+
+#endif
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 555ee14..d26c8ae 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1,7 +1,7 @@
 /*
  * wm8350.c -- WM8350 ALSA SoC audio driver
  *
- * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
+ * Copyright (C) 2007-12 Wolfson Microelectronics PLC.
  *
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
@@ -71,20 +71,6 @@ struct wm8350_data {
 	int fll_freq_in;
 };
 
-static unsigned int wm8350_codec_read(struct snd_soc_codec *codec,
-				      unsigned int reg)
-{
-	struct wm8350 *wm8350 = codec->control_data;
-	return wm8350_reg_read(wm8350, reg);
-}
-
-static int wm8350_codec_write(struct snd_soc_codec *codec, unsigned int reg,
-			      unsigned int value)
-{
-	struct wm8350 *wm8350 = codec->control_data;
-	return wm8350_reg_write(wm8350, reg, value);
-}
-
 /*
  * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown.
  */
@@ -1519,7 +1505,9 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
 	if (ret != 0)
 		return ret;
 
-	codec->control_data = wm8350;
+	codec->control_data = wm8350->regmap;
+
+	snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
 
 	/* Put the codec into reset if it wasn't already */
 	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
@@ -1629,8 +1617,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
 	.remove =	wm8350_codec_remove,
 	.suspend = 	wm8350_suspend,
 	.resume =	wm8350_resume,
-	.read = wm8350_codec_read,
-	.write = wm8350_codec_write,
 	.set_bias_level = wm8350_set_bias_level,
 
 	.controls = wm8350_snd_controls,
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 5dc31eb..5d277a9 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -1,7 +1,7 @@
 /*
  * wm8400.c  --  WM8400 ALSA Soc Audio driver
  *
- * Copyright 2008, 2009 Wolfson Microelectronics PLC.
+ * Copyright 2008-11 Wolfson Microelectronics PLC.
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 2112851..7c68226 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -1,7 +1,7 @@
 /*
  * wm8580.c  --  WM8580 ALSA Soc Audio driver
  *
- * Copyright 2008, 2009 Wolfson Microelectronics PLC.
+ * Copyright 2008-11 Wolfson Microelectronics PLC.
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 9d1b9b02..bb1d269 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -2,6 +2,7 @@
  * wm8731.c  --  WM8731 ALSA SoC Audio driver
  *
  * Copyright 2005 Openedhand Ltd.
+ * Copyright 2006-12 Wolfson Microelectronics, plc
  *
  * Author: Richard Purdie <richard@openedhand.com>
  *
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 6e849cb..35f3d23 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -1,7 +1,7 @@
 /*
  * wm8741.c  --  WM8741 ALSA SoC Audio driver
  *
- * Copyright 2010 Wolfson Microelectronics plc
+ * Copyright 2010-1 Wolfson Microelectronics plc
  *
  * Author: Ian Lartey <ian@opensource.wolfsonmicro.com>
  *
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index a26482c..13bff87 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1,7 +1,7 @@
 /*
  * wm8753.c  --  WM8753 ALSA Soc Audio driver
  *
- * Copyright 2003 Wolfson Microelectronics PLC.
+ * Copyright 2003-11 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index a19db5a..879c356 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -1,7 +1,7 @@
 /*
  * wm8776.c  --  WM8776 ALSA SoC Audio driver
  *
- * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 6bd1b76..c088020 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -1,7 +1,7 @@
 /*
  * wm8804.c  --  WM8804 S/PDIF transceiver driver
  *
- * Copyright 2010 Wolfson Microelectronics plc
+ * Copyright 2010-11 Wolfson Microelectronics plc
  *
  * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
  *
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 86b8a29..73f1c8d 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1,8 +1,8 @@
 /*
  * wm8903.c  --  WM8903 ALSA SoC Audio driver
  *
- * Copyright 2008 Wolfson Microelectronics
- * Copyright 2011 NVIDIA, Inc.
+ * Copyright 2008-12 Wolfson Microelectronics
+ * Copyright 2011-2012 NVIDIA, Inc.
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
@@ -116,6 +116,7 @@ static const struct reg_default wm8903_reg_defaults[] = {
 
 struct wm8903_priv {
 	struct wm8903_platform_data *pdata;
+	struct device *dev;
 	struct snd_soc_codec *codec;
 	struct regmap *regmap;
 
@@ -1635,17 +1636,27 @@ EXPORT_SYMBOL_GPL(wm8903_mic_detect);
 
 static irqreturn_t wm8903_irq(int irq, void *data)
 {
-	struct snd_soc_codec *codec = data;
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-	int mic_report;
-	int int_pol;
-	int int_val = 0;
-	int mask = ~snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1_MASK);
+	struct wm8903_priv *wm8903 = data;
+	int mic_report, ret;
+	unsigned int int_val, mask, int_pol;
 
-	int_val = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1) & mask;
+	ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1_MASK,
+			  &mask);
+	if (ret != 0) {
+		dev_err(wm8903->dev, "Failed to read IRQ mask: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1, &int_val);
+	if (ret != 0) {
+		dev_err(wm8903->dev, "Failed to read IRQ status: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	int_val &= ~mask;
 
 	if (int_val & WM8903_WSEQ_BUSY_EINT) {
-		dev_warn(codec->dev, "Write sequencer done\n");
+		dev_warn(wm8903->dev, "Write sequencer done\n");
 	}
 
 	/*
@@ -1656,22 +1667,28 @@ static irqreturn_t wm8903_irq(int irq, void *data)
 	 * the polarity register.
 	 */
 	mic_report = wm8903->mic_last_report;
-	int_pol = snd_soc_read(codec, WM8903_INTERRUPT_POLARITY_1);
+	ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
+			  &int_pol);
+	if (ret != 0) {
+		dev_err(wm8903->dev, "Failed to read interrupt polarity: %d\n",
+			ret);
+		return IRQ_HANDLED;
+	}
 
 #ifndef CONFIG_SND_SOC_WM8903_MODULE
 	if (int_val & (WM8903_MICSHRT_EINT | WM8903_MICDET_EINT))
-		trace_snd_soc_jack_irq(dev_name(codec->dev));
+		trace_snd_soc_jack_irq(dev_name(wm8903->dev));
 #endif
 
 	if (int_val & WM8903_MICSHRT_EINT) {
-		dev_dbg(codec->dev, "Microphone short (pol=%x)\n", int_pol);
+		dev_dbg(wm8903->dev, "Microphone short (pol=%x)\n", int_pol);
 
 		mic_report ^= wm8903->mic_short;
 		int_pol ^= WM8903_MICSHRT_INV;
 	}
 
 	if (int_val & WM8903_MICDET_EINT) {
-		dev_dbg(codec->dev, "Microphone detect (pol=%x)\n", int_pol);
+		dev_dbg(wm8903->dev, "Microphone detect (pol=%x)\n", int_pol);
 
 		mic_report ^= wm8903->mic_det;
 		int_pol ^= WM8903_MICDET_INV;
@@ -1679,8 +1696,8 @@ static irqreturn_t wm8903_irq(int irq, void *data)
 		msleep(wm8903->mic_delay);
 	}
 
-	snd_soc_update_bits(codec, WM8903_INTERRUPT_POLARITY_1,
-			    WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
+	regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
+			   WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
 
 	snd_soc_jack_report(wm8903->mic_jack, mic_report,
 			    wm8903->mic_short | wm8903->mic_det);
@@ -1774,7 +1791,6 @@ static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset)
 static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
 	struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
-	struct snd_soc_codec *codec = wm8903->codec;
 	unsigned int mask, val;
 	int ret;
 
@@ -1782,8 +1798,8 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 	val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) |
 		WM8903_GP1_DIR;
 
-	ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
-				  mask, val);
+	ret = regmap_update_bits(wm8903->regmap,
+				 WM8903_GPIO_CONTROL_1 + offset, mask, val);
 	if (ret < 0)
 		return ret;
 
@@ -1793,10 +1809,9 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
 	struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
-	struct snd_soc_codec *codec = wm8903->codec;
-	int reg;
+	unsigned int reg;
 
-	reg = snd_soc_read(codec, WM8903_GPIO_CONTROL_1 + offset);
+	regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, &reg);
 
 	return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT;
 }
@@ -1805,7 +1820,6 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
 				     unsigned offset, int value)
 {
 	struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
-	struct snd_soc_codec *codec = wm8903->codec;
 	unsigned int mask, val;
 	int ret;
 
@@ -1813,8 +1827,8 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
 	val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) |
 		(value << WM8903_GP2_LVL_SHIFT);
 
-	ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
-				  mask, val);
+	ret = regmap_update_bits(wm8903->regmap,
+				 WM8903_GPIO_CONTROL_1 + offset, mask, val);
 	if (ret < 0)
 		return ret;
 
@@ -1824,11 +1838,10 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
 static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
-	struct snd_soc_codec *codec = wm8903->codec;
 
-	snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
-			    WM8903_GP1_LVL_MASK,
-			    !!value << WM8903_GP1_LVL_SHIFT);
+	regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset,
+			   WM8903_GP1_LVL_MASK,
+			   !!value << WM8903_GP1_LVL_SHIFT);
 }
 
 static struct gpio_chip wm8903_template_chip = {
@@ -1842,15 +1855,14 @@ static struct gpio_chip wm8903_template_chip = {
 	.can_sleep		= 1,
 };
 
-static void wm8903_init_gpio(struct snd_soc_codec *codec)
+static void wm8903_init_gpio(struct wm8903_priv *wm8903)
 {
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 	struct wm8903_platform_data *pdata = wm8903->pdata;
 	int ret;
 
 	wm8903->gpio_chip = wm8903_template_chip;
 	wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
-	wm8903->gpio_chip.dev = codec->dev;
+	wm8903->gpio_chip.dev = wm8903->dev;
 
 	if (pdata->gpio_base)
 		wm8903->gpio_chip.base = pdata->gpio_base;
@@ -1859,24 +1871,23 @@ static void wm8903_init_gpio(struct snd_soc_codec *codec)
 
 	ret = gpiochip_add(&wm8903->gpio_chip);
 	if (ret != 0)
-		dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+		dev_err(wm8903->dev, "Failed to add GPIOs: %d\n", ret);
 }
 
-static void wm8903_free_gpio(struct snd_soc_codec *codec)
+static void wm8903_free_gpio(struct wm8903_priv *wm8903)
 {
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 
 	ret = gpiochip_remove(&wm8903->gpio_chip);
 	if (ret != 0)
-		dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+		dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret);
 }
 #else
-static void wm8903_init_gpio(struct snd_soc_codec *codec)
+static void wm8903_init_gpio(struct wm8903_priv *wm8903)
 {
 }
 
-static void wm8903_free_gpio(struct snd_soc_codec *codec)
+static void wm8903_free_gpio(struct wm8903_priv *wm8903)
 {
 }
 #endif
@@ -1884,11 +1895,7 @@ static void wm8903_free_gpio(struct snd_soc_codec *codec)
 static int wm8903_probe(struct snd_soc_codec *codec)
 {
 	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-	struct wm8903_platform_data *pdata = wm8903->pdata;
-	int ret, i;
-	int trigger, irq_pol;
-	u16 val;
-	bool mic_gpio = false;
+	int ret;
 
 	wm8903->codec = codec;
 	codec->control_data = wm8903->regmap;
@@ -1899,121 +1906,16 @@ static int wm8903_probe(struct snd_soc_codec *codec)
 		return ret;
 	}
 
-	/* Set up GPIOs, detect if any are MIC detect outputs */
-	for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
-		if ((!pdata->gpio_cfg[i]) ||
-		    (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO))
-			continue;
-
-		snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i,
-				pdata->gpio_cfg[i] & 0x7fff);
-
-		val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK)
-			>> WM8903_GP1_FN_SHIFT;
-
-		switch (val) {
-		case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
-		case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
-			mic_gpio = true;
-			break;
-		default:
-			break;
-		}
-	}
-
-	/* Set up microphone detection */
-	snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0,
-			pdata->micdet_cfg);
-
-	/* Microphone detection needs the WSEQ clock */
-	if (pdata->micdet_cfg)
-		snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
-				    WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
-
-	/* If microphone detection is enabled by pdata but
-	    * detected via IRQ then interrupts can be lost before
-	    * the machine driver has set up microphone detection
-	    * IRQs as the IRQs are clear on read.  The detection
-	    * will be enabled when the machine driver configures.
-	    */
-	WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
-
-	wm8903->mic_delay = pdata->micdet_delay;
-
-	if (wm8903->irq) {
-		if (pdata->irq_active_low) {
-			trigger = IRQF_TRIGGER_LOW;
-			irq_pol = WM8903_IRQ_POL;
-		} else {
-			trigger = IRQF_TRIGGER_HIGH;
-			irq_pol = 0;
-		}
-
-		snd_soc_update_bits(codec, WM8903_INTERRUPT_CONTROL,
-				    WM8903_IRQ_POL, irq_pol);
-		
-		ret = request_threaded_irq(wm8903->irq, NULL, wm8903_irq,
-					   trigger | IRQF_ONESHOT,
-					   "wm8903", codec);
-		if (ret != 0) {
-			dev_err(codec->dev, "Failed to request IRQ: %d\n",
-				ret);
-			return ret;
-		}
-
-		/* Enable write sequencer interrupts */
-		snd_soc_update_bits(codec, WM8903_INTERRUPT_STATUS_1_MASK,
-				    WM8903_IM_WSEQ_BUSY_EINT, 0);
-	}
-
 	/* power on device */
 	wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-	/* Latch volume update bits */
-	val = snd_soc_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT);
-	val |= WM8903_ADCVU;
-	snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val);
-	snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val);
-
-	val = snd_soc_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT);
-	val |= WM8903_DACVU;
-	snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val);
-	snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val);
-
-	val = snd_soc_read(codec, WM8903_ANALOGUE_OUT1_LEFT);
-	val |= WM8903_HPOUTVU;
-	snd_soc_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val);
-	snd_soc_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val);
-
-	val = snd_soc_read(codec, WM8903_ANALOGUE_OUT2_LEFT);
-	val |= WM8903_LINEOUTVU;
-	snd_soc_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val);
-	snd_soc_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val);
-
-	val = snd_soc_read(codec, WM8903_ANALOGUE_OUT3_LEFT);
-	val |= WM8903_SPKVU;
-	snd_soc_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val);
-	snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val);
-
-	/* Enable DAC soft mute by default */
-	snd_soc_update_bits(codec, WM8903_DAC_DIGITAL_1,
-			    WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE,
-			    WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE);
-
-	wm8903_init_gpio(codec);
-
 	return ret;
 }
 
 /* power down chip */
 static int wm8903_remove(struct snd_soc_codec *codec)
 {
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-
-	wm8903_free_gpio(codec);
 	wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	if (wm8903->irq)
-		free_irq(wm8903->irq, codec);
 
 	return 0;
 }
@@ -2123,15 +2025,18 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
 {
 	struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
 	struct wm8903_priv *wm8903;
-	unsigned int val;
-	int ret;
+	int trigger;
+	bool mic_gpio = false;
+	unsigned int val, irq_pol;
+	int ret, i;
 
 	wm8903 = devm_kzalloc(&i2c->dev,  sizeof(struct wm8903_priv),
 			      GFP_KERNEL);
 	if (wm8903 == NULL)
 		return -ENOMEM;
+	wm8903->dev = &i2c->dev;
 
-	wm8903->regmap = regmap_init_i2c(i2c, &wm8903_regmap);
+	wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap);
 	if (IS_ERR(wm8903->regmap)) {
 		ret = PTR_ERR(wm8903->regmap);
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -2140,7 +2045,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
 	}
 
 	i2c_set_clientdata(i2c, wm8903);
-	wm8903->irq = i2c->irq;
 
 	/* If no platform data was supplied, create storage for defaults */
 	if (pdata) {
@@ -2167,6 +2071,8 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
 		}
 	}
 
+	pdata = wm8903->pdata;
+
 	ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
@@ -2189,6 +2095,107 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
 	/* Reset the device */
 	regmap_write(wm8903->regmap, WM8903_SW_RESET_AND_ID, 0x8903);
 
+	wm8903_init_gpio(wm8903);
+
+	/* Set up GPIO pin state, detect if any are MIC detect outputs */
+	for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
+		if ((!pdata->gpio_cfg[i]) ||
+		    (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO))
+			continue;
+
+		regmap_write(wm8903->regmap, WM8903_GPIO_CONTROL_1 + i,
+				pdata->gpio_cfg[i] & 0x7fff);
+
+		val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK)
+			>> WM8903_GP1_FN_SHIFT;
+
+		switch (val) {
+		case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
+		case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
+			mic_gpio = true;
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* Set up microphone detection */
+	regmap_write(wm8903->regmap, WM8903_MIC_BIAS_CONTROL_0,
+		     pdata->micdet_cfg);
+
+	/* Microphone detection needs the WSEQ clock */
+	if (pdata->micdet_cfg)
+		regmap_update_bits(wm8903->regmap, WM8903_WRITE_SEQUENCER_0,
+				   WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
+
+	/* If microphone detection is enabled by pdata but
+	 * detected via IRQ then interrupts can be lost before
+	 * the machine driver has set up microphone detection
+	 * IRQs as the IRQs are clear on read.  The detection
+	 * will be enabled when the machine driver configures.
+	 */
+	WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
+
+	wm8903->mic_delay = pdata->micdet_delay;
+
+	if (i2c->irq) {
+		if (pdata->irq_active_low) {
+			trigger = IRQF_TRIGGER_LOW;
+			irq_pol = WM8903_IRQ_POL;
+		} else {
+			trigger = IRQF_TRIGGER_HIGH;
+			irq_pol = 0;
+		}
+
+		regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_CONTROL,
+				   WM8903_IRQ_POL, irq_pol);
+
+		ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq,
+					   trigger | IRQF_ONESHOT,
+					   "wm8903", wm8903);
+		if (ret != 0) {
+			dev_err(wm8903->dev, "Failed to request IRQ: %d\n",
+				ret);
+			return ret;
+		}
+
+		/* Enable write sequencer interrupts */
+		regmap_update_bits(wm8903->regmap,
+				   WM8903_INTERRUPT_STATUS_1_MASK,
+				   WM8903_IM_WSEQ_BUSY_EINT, 0);
+	}
+
+	/* Latch volume update bits */
+	regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_LEFT,
+			   WM8903_ADCVU, WM8903_ADCVU);
+	regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_RIGHT,
+			   WM8903_ADCVU, WM8903_ADCVU);
+
+	regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_LEFT,
+			   WM8903_DACVU, WM8903_DACVU);
+	regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_RIGHT,
+			   WM8903_DACVU, WM8903_DACVU);
+
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_LEFT,
+			   WM8903_HPOUTVU, WM8903_HPOUTVU);
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_RIGHT,
+			   WM8903_HPOUTVU, WM8903_HPOUTVU);
+
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_LEFT,
+			   WM8903_LINEOUTVU, WM8903_LINEOUTVU);
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_RIGHT,
+			   WM8903_LINEOUTVU, WM8903_LINEOUTVU);
+
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_LEFT,
+			   WM8903_SPKVU, WM8903_SPKVU);
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_RIGHT,
+			   WM8903_SPKVU, WM8903_SPKVU);
+
+	/* Enable DAC soft mute by default */
+	regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_1,
+			   WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE,
+			   WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE);
+
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8903, &wm8903_dai, 1);
 	if (ret != 0)
@@ -2196,7 +2203,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
 
 	return 0;
 err:
-	regmap_exit(wm8903->regmap);
 	return ret;
 }
 
@@ -2204,7 +2210,9 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client)
 {
 	struct wm8903_priv *wm8903 = i2c_get_clientdata(client);
 
-	regmap_exit(wm8903->regmap);
+	if (client->irq)
+		free_irq(client->irq, wm8903);
+	wm8903_free_gpio(wm8903);
 	snd_soc_unregister_codec(&client->dev);
 
 	return 0;
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 812acd8..0013afe 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -1,7 +1,7 @@
 /*
  * wm8904.c  --  WM8904 ALSA SoC Audio driver
  *
- * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
@@ -314,11 +314,6 @@ static bool wm8904_readable_register(struct device *dev, unsigned int reg)
 	}
 }
 
-static int wm8904_reset(struct snd_soc_codec *codec)
-{
-	return snd_soc_write(codec, WM8904_SW_RESET_AND_ID, 0);
-}
-
 static int wm8904_configure_clocking(struct snd_soc_codec *codec)
 {
 	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
@@ -1945,25 +1940,6 @@ static struct snd_soc_dai_driver wm8904_dai = {
 	.symmetric_rates = 1,
 };
 
-#ifdef CONFIG_PM
-static int wm8904_suspend(struct snd_soc_codec *codec)
-{
-	wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
-static int wm8904_resume(struct snd_soc_codec *codec)
-{
-	wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-#else
-#define wm8904_suspend NULL
-#define wm8904_resume NULL
-#endif
-
 static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec)
 {
 	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
@@ -2078,8 +2054,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec)
 static int wm8904_probe(struct snd_soc_codec *codec)
 {
 	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
-	struct wm8904_pdata *pdata = wm8904->pdata;
-	int ret, i;
+	int ret;
 
 	codec->control_data = wm8904->regmap;
 
@@ -2101,127 +2076,17 @@ static int wm8904_probe(struct snd_soc_codec *codec)
 		return ret;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
-		wm8904->supplies[i].supply = wm8904_supply_names[i];
-
-	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8904->supplies),
-				 wm8904->supplies);
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-		return ret;
-	}
-
-	ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
-				    wm8904->supplies);
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-		goto err_get;
-	}
-
-	ret = snd_soc_read(codec, WM8904_SW_RESET_AND_ID);
-	if (ret < 0) {
-		dev_err(codec->dev, "Failed to read ID register\n");
-		goto err_enable;
-	}
-	if (ret != 0x8904) {
-		dev_err(codec->dev, "Device is not a WM8904, ID is %x\n", ret);
-		ret = -EINVAL;
-		goto err_enable;
-	}
-
-	ret = snd_soc_read(codec, WM8904_REVISION);
-	if (ret < 0) {
-		dev_err(codec->dev, "Failed to read device revision: %d\n",
-			ret);
-		goto err_enable;
-	}
-	dev_info(codec->dev, "revision %c\n", ret + 'A');
-
-	ret = wm8904_reset(codec);
-	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset\n");
-		goto err_enable;
-	}
-
-	regcache_cache_only(wm8904->regmap, true);
-	/* Change some default settings - latch VU and enable ZC */
-	snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_LEFT,
-			    WM8904_ADC_VU, WM8904_ADC_VU);
-	snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_RIGHT,
-			    WM8904_ADC_VU, WM8904_ADC_VU);
-	snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_LEFT,
-			    WM8904_DAC_VU, WM8904_DAC_VU);
-	snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_RIGHT,
-			    WM8904_DAC_VU, WM8904_DAC_VU);
-	snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_LEFT,
-			    WM8904_HPOUT_VU | WM8904_HPOUTLZC,
-			    WM8904_HPOUT_VU | WM8904_HPOUTLZC);
-	snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_RIGHT,
-			    WM8904_HPOUT_VU | WM8904_HPOUTRZC,
-			    WM8904_HPOUT_VU | WM8904_HPOUTRZC);
-	snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_LEFT,
-			    WM8904_LINEOUT_VU | WM8904_LINEOUTLZC,
-			    WM8904_LINEOUT_VU | WM8904_LINEOUTLZC);
-	snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_RIGHT,
-			    WM8904_LINEOUT_VU | WM8904_LINEOUTRZC,
-			    WM8904_LINEOUT_VU | WM8904_LINEOUTRZC);
-	snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0,
-			    WM8904_SR_MODE, 0);
-
-	/* Apply configuration from the platform data. */
-	if (wm8904->pdata) {
-		for (i = 0; i < WM8904_GPIO_REGS; i++) {
-			if (!pdata->gpio_cfg[i])
-				continue;
-
-			regmap_update_bits(wm8904->regmap,
-					   WM8904_GPIO_CONTROL_1 + i,
-					   0xffff,
-					   pdata->gpio_cfg[i]);
-		}
-
-		/* Zero is the default value for these anyway */
-		for (i = 0; i < WM8904_MIC_REGS; i++)
-			regmap_update_bits(wm8904->regmap,
-					   WM8904_MIC_BIAS_CONTROL_0 + i,
-					   0xffff,
-					   pdata->mic_cfg[i]);
-	}
-
-	/* Set Class W by default - this will be managed by the Class
-	 * G widget at runtime where bypass paths are available.
-	 */
-	snd_soc_update_bits(codec, WM8904_CLASS_W_0,
-			    WM8904_CP_DYN_PWR, WM8904_CP_DYN_PWR);
-
-	/* Use normal bias source */
-	snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
-			    WM8904_POBCTRL, 0);
-
-	wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	/* Bias level configuration will have done an extra enable */
-	regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
-
 	wm8904_handle_pdata(codec);
 
 	wm8904_add_widgets(codec);
 
 	return 0;
-
-err_enable:
-	regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
-err_get:
-	regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
-	return ret;
 }
 
 static int wm8904_remove(struct snd_soc_codec *codec)
 {
 	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 
-	wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
 	kfree(wm8904->retune_mobile_texts);
 	kfree(wm8904->drc_texts);
 
@@ -2231,8 +2096,6 @@ static int wm8904_remove(struct snd_soc_codec *codec)
 static struct snd_soc_codec_driver soc_codec_dev_wm8904 = {
 	.probe =	wm8904_probe,
 	.remove =	wm8904_remove,
-	.suspend =	wm8904_suspend,
-	.resume =	wm8904_resume,
 	.set_bias_level = wm8904_set_bias_level,
 	.idle_bias_off = true,
 };
@@ -2254,14 +2117,15 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
 	struct wm8904_priv *wm8904;
-	int ret;
+	unsigned int val;
+	int ret, i;
 
 	wm8904 = devm_kzalloc(&i2c->dev, sizeof(struct wm8904_priv),
 			      GFP_KERNEL);
 	if (wm8904 == NULL)
 		return -ENOMEM;
 
-	wm8904->regmap = regmap_init_i2c(i2c, &wm8904_regmap);
+	wm8904->regmap = devm_regmap_init_i2c(i2c, &wm8904_regmap);
 	if (IS_ERR(wm8904->regmap)) {
 		ret = PTR_ERR(wm8904->regmap);
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -2273,23 +2137,121 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
 	i2c_set_clientdata(i2c, wm8904);
 	wm8904->pdata = i2c->dev.platform_data;
 
+	for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
+		wm8904->supplies[i].supply = wm8904_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8904->supplies),
+				      wm8904->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
+				    wm8904->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(wm8904->regmap, WM8904_SW_RESET_AND_ID, &val);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
+		goto err_enable;
+	}
+	if (val != 0x8904) {
+		dev_err(&i2c->dev, "Device is not a WM8904, ID is %x\n", val);
+		ret = -EINVAL;
+		goto err_enable;
+	}
+
+	ret = regmap_read(wm8904->regmap, WM8904_REVISION, &val);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read device revision: %d\n",
+			ret);
+		goto err_enable;
+	}
+	dev_info(&i2c->dev, "revision %c\n", val + 'A');
+
+	ret = regmap_write(wm8904->regmap, WM8904_SW_RESET_AND_ID, 0);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
+		goto err_enable;
+	}
+
+	/* Change some default settings - latch VU and enable ZC */
+	regmap_update_bits(wm8904->regmap, WM8904_ADC_DIGITAL_VOLUME_LEFT,
+			   WM8904_ADC_VU, WM8904_ADC_VU);
+	regmap_update_bits(wm8904->regmap, WM8904_ADC_DIGITAL_VOLUME_RIGHT,
+			   WM8904_ADC_VU, WM8904_ADC_VU);
+	regmap_update_bits(wm8904->regmap, WM8904_DAC_DIGITAL_VOLUME_LEFT,
+			   WM8904_DAC_VU, WM8904_DAC_VU);
+	regmap_update_bits(wm8904->regmap, WM8904_DAC_DIGITAL_VOLUME_RIGHT,
+			   WM8904_DAC_VU, WM8904_DAC_VU);
+	regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT1_LEFT,
+			   WM8904_HPOUT_VU | WM8904_HPOUTLZC,
+			   WM8904_HPOUT_VU | WM8904_HPOUTLZC);
+	regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT1_RIGHT,
+			   WM8904_HPOUT_VU | WM8904_HPOUTRZC,
+			   WM8904_HPOUT_VU | WM8904_HPOUTRZC);
+	regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT2_LEFT,
+			   WM8904_LINEOUT_VU | WM8904_LINEOUTLZC,
+			   WM8904_LINEOUT_VU | WM8904_LINEOUTLZC);
+	regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT2_RIGHT,
+			   WM8904_LINEOUT_VU | WM8904_LINEOUTRZC,
+			   WM8904_LINEOUT_VU | WM8904_LINEOUTRZC);
+	regmap_update_bits(wm8904->regmap, WM8904_CLOCK_RATES_0,
+			   WM8904_SR_MODE, 0);
+
+	/* Apply configuration from the platform data. */
+	if (wm8904->pdata) {
+		for (i = 0; i < WM8904_GPIO_REGS; i++) {
+			if (!wm8904->pdata->gpio_cfg[i])
+				continue;
+
+			regmap_update_bits(wm8904->regmap,
+					   WM8904_GPIO_CONTROL_1 + i,
+					   0xffff,
+					   wm8904->pdata->gpio_cfg[i]);
+		}
+
+		/* Zero is the default value for these anyway */
+		for (i = 0; i < WM8904_MIC_REGS; i++)
+			regmap_update_bits(wm8904->regmap,
+					   WM8904_MIC_BIAS_CONTROL_0 + i,
+					   0xffff,
+					   wm8904->pdata->mic_cfg[i]);
+	}
+
+	/* Set Class W by default - this will be managed by the Class
+	 * G widget at runtime where bypass paths are available.
+	 */
+	regmap_update_bits(wm8904->regmap, WM8904_CLASS_W_0,
+			    WM8904_CP_DYN_PWR, WM8904_CP_DYN_PWR);
+
+	/* Use normal bias source */
+	regmap_update_bits(wm8904->regmap, WM8904_BIAS_CONTROL_0,
+			    WM8904_POBCTRL, 0);
+
+	/* Can leave the device powered off until we need it */
+	regcache_cache_only(wm8904->regmap, true);
+	regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
+
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8904, &wm8904_dai, 1);
 	if (ret != 0)
-		goto err;
+		return ret;
 
 	return 0;
 
-err:
-	regmap_exit(wm8904->regmap);
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
 	return ret;
 }
 
 static __devexit int wm8904_i2c_remove(struct i2c_client *client)
 {
-	struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
 	snd_soc_unregister_codec(&client->dev);
-	regmap_exit(wm8904->regmap);
 	return 0;
 }
 
@@ -2311,23 +2273,7 @@ static struct i2c_driver wm8904_i2c_driver = {
 	.id_table = wm8904_i2c_id,
 };
 
-static int __init wm8904_modinit(void)
-{
-	int ret = 0;
-	ret = i2c_add_driver(&wm8904_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(wm8904_modinit);
-
-static void __exit wm8904_exit(void)
-{
-	i2c_del_driver(&wm8904_i2c_driver);
-}
-module_exit(wm8904_exit);
+module_i2c_driver(wm8904_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8904 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 8bc659d..96518ac 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -1,6 +1,8 @@
 /*
  * wm8960.c  --  WM8960 ALSA SoC Audio driver
  *
+ * Copyright 2007-11 Wolfson Microelectronics, plc
+ *
  * Author: Liam Girdwood
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 05ea7c2..01edbcc 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -1,6 +1,8 @@
 /*
  * wm8961.c  --  WM8961 ALSA SoC Audio driver
  *
+ * Copyright 2009-10 Wolfson Microelectronics, plc
+ *
  * Author: Mark Brown
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 0cfce99..27da4d7 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -1,7 +1,7 @@
 /*
  * wm8962.c  --  WM8962 ALSA SoC Audio driver
  *
- * Copyright 2010 Wolfson Microelectronics plc
+ * Copyright 2010-2 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 36acfcc..9fd80d6 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -1,7 +1,7 @@
 /*
  * wm8993.c -- WM8993 ALSA SoC audio driver
  *
- * Copyright 2009, 2010 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index aa8c98b..ae56c1d 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -1,7 +1,7 @@
 /*
  * wm8994.c  --  WM8994 ALSA SoC Audio driver
  *
- * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
@@ -727,9 +727,6 @@ static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode)
 	if (!wm8994->jackdet || !wm8994->jack_cb)
 		return;
 
-	if (!wm8994->jackdet || !wm8994->jack_cb)
-		return;
-
 	if (wm8994->active_refcount)
 		mode = WM1811_JACKDET_MODE_AUDIO;
 
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index dc9b42b..00f183d 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -1,7 +1,7 @@
 /*
  * wm8996.c - WM8996 audio codec interface
  *
- * Copyright 2011 Wolfson Microelectronics PLC.
+ * Copyright 2011-2 Wolfson Microelectronics PLC.
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -296,184 +296,6 @@ static struct reg_default wm8996_reg[] = {
 	{ WM8996_RIGHT_PDM_SPEAKER, 0x1 },
 	{ WM8996_PDM_SPEAKER_MUTE_SEQUENCE, 0x69 },
 	{ WM8996_PDM_SPEAKER_VOLUME, 0x66 },
-	{ WM8996_WRITE_SEQUENCER_0, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_1, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_3, 0x6 },
-	{ WM8996_WRITE_SEQUENCER_4, 0x40 },
-	{ WM8996_WRITE_SEQUENCER_5, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_6, 0xf },
-	{ WM8996_WRITE_SEQUENCER_7, 0x6 },
-	{ WM8996_WRITE_SEQUENCER_8, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_9, 0x3 },
-	{ WM8996_WRITE_SEQUENCER_10, 0x104 },
-	{ WM8996_WRITE_SEQUENCER_12, 0x60 },
-	{ WM8996_WRITE_SEQUENCER_13, 0x11 },
-	{ WM8996_WRITE_SEQUENCER_14, 0x401 },
-	{ WM8996_WRITE_SEQUENCER_16, 0x50 },
-	{ WM8996_WRITE_SEQUENCER_17, 0x3 },
-	{ WM8996_WRITE_SEQUENCER_18, 0x100 },
-	{ WM8996_WRITE_SEQUENCER_20, 0x51 },
-	{ WM8996_WRITE_SEQUENCER_21, 0x3 },
-	{ WM8996_WRITE_SEQUENCER_22, 0x104 },
-	{ WM8996_WRITE_SEQUENCER_23, 0xa },
-	{ WM8996_WRITE_SEQUENCER_24, 0x60 },
-	{ WM8996_WRITE_SEQUENCER_25, 0x3b },
-	{ WM8996_WRITE_SEQUENCER_26, 0x502 },
-	{ WM8996_WRITE_SEQUENCER_27, 0x100 },
-	{ WM8996_WRITE_SEQUENCER_28, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_32, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_36, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_40, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_44, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_48, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_52, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_56, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_60, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_64, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_65, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_67, 0x6 },
-	{ WM8996_WRITE_SEQUENCER_68, 0x40 },
-	{ WM8996_WRITE_SEQUENCER_69, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_70, 0xf },
-	{ WM8996_WRITE_SEQUENCER_71, 0x6 },
-	{ WM8996_WRITE_SEQUENCER_72, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_73, 0x3 },
-	{ WM8996_WRITE_SEQUENCER_74, 0x104 },
-	{ WM8996_WRITE_SEQUENCER_76, 0x60 },
-	{ WM8996_WRITE_SEQUENCER_77, 0x11 },
-	{ WM8996_WRITE_SEQUENCER_78, 0x401 },
-	{ WM8996_WRITE_SEQUENCER_80, 0x50 },
-	{ WM8996_WRITE_SEQUENCER_81, 0x3 },
-	{ WM8996_WRITE_SEQUENCER_82, 0x100 },
-	{ WM8996_WRITE_SEQUENCER_84, 0x60 },
-	{ WM8996_WRITE_SEQUENCER_85, 0x3b },
-	{ WM8996_WRITE_SEQUENCER_86, 0x502 },
-	{ WM8996_WRITE_SEQUENCER_87, 0x100 },
-	{ WM8996_WRITE_SEQUENCER_88, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_92, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_96, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_100, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_104, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_108, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_112, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_116, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_120, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_124, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_128, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_129, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_131, 0x6 },
-	{ WM8996_WRITE_SEQUENCER_132, 0x40 },
-	{ WM8996_WRITE_SEQUENCER_133, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_134, 0xf },
-	{ WM8996_WRITE_SEQUENCER_135, 0x6 },
-	{ WM8996_WRITE_SEQUENCER_136, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_137, 0x3 },
-	{ WM8996_WRITE_SEQUENCER_138, 0x106 },
-	{ WM8996_WRITE_SEQUENCER_140, 0x61 },
-	{ WM8996_WRITE_SEQUENCER_141, 0x11 },
-	{ WM8996_WRITE_SEQUENCER_142, 0x401 },
-	{ WM8996_WRITE_SEQUENCER_144, 0x50 },
-	{ WM8996_WRITE_SEQUENCER_145, 0x3 },
-	{ WM8996_WRITE_SEQUENCER_146, 0x102 },
-	{ WM8996_WRITE_SEQUENCER_148, 0x51 },
-	{ WM8996_WRITE_SEQUENCER_149, 0x3 },
-	{ WM8996_WRITE_SEQUENCER_150, 0x106 },
-	{ WM8996_WRITE_SEQUENCER_151, 0xa },
-	{ WM8996_WRITE_SEQUENCER_152, 0x61 },
-	{ WM8996_WRITE_SEQUENCER_153, 0x3b },
-	{ WM8996_WRITE_SEQUENCER_154, 0x502 },
-	{ WM8996_WRITE_SEQUENCER_155, 0x100 },
-	{ WM8996_WRITE_SEQUENCER_156, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_160, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_164, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_168, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_172, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_176, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_180, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_184, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_188, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_192, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_193, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_195, 0x6 },
-	{ WM8996_WRITE_SEQUENCER_196, 0x40 },
-	{ WM8996_WRITE_SEQUENCER_197, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_198, 0xf },
-	{ WM8996_WRITE_SEQUENCER_199, 0x6 },
-	{ WM8996_WRITE_SEQUENCER_200, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_201, 0x3 },
-	{ WM8996_WRITE_SEQUENCER_202, 0x106 },
-	{ WM8996_WRITE_SEQUENCER_204, 0x61 },
-	{ WM8996_WRITE_SEQUENCER_205, 0x11 },
-	{ WM8996_WRITE_SEQUENCER_206, 0x401 },
-	{ WM8996_WRITE_SEQUENCER_208, 0x50 },
-	{ WM8996_WRITE_SEQUENCER_209, 0x3 },
-	{ WM8996_WRITE_SEQUENCER_210, 0x102 },
-	{ WM8996_WRITE_SEQUENCER_212, 0x61 },
-	{ WM8996_WRITE_SEQUENCER_213, 0x3b },
-	{ WM8996_WRITE_SEQUENCER_214, 0x502 },
-	{ WM8996_WRITE_SEQUENCER_215, 0x100 },
-	{ WM8996_WRITE_SEQUENCER_216, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_220, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_224, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_228, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_232, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_236, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_240, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_244, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_248, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_252, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_256, 0x60 },
-	{ WM8996_WRITE_SEQUENCER_258, 0x601 },
-	{ WM8996_WRITE_SEQUENCER_260, 0x50 },
-	{ WM8996_WRITE_SEQUENCER_262, 0x100 },
-	{ WM8996_WRITE_SEQUENCER_264, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_266, 0x104 },
-	{ WM8996_WRITE_SEQUENCER_267, 0x100 },
-	{ WM8996_WRITE_SEQUENCER_268, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_272, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_276, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_280, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_284, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_288, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_292, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_296, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_300, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_304, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_308, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_312, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_316, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_320, 0x61 },
-	{ WM8996_WRITE_SEQUENCER_322, 0x601 },
-	{ WM8996_WRITE_SEQUENCER_324, 0x50 },
-	{ WM8996_WRITE_SEQUENCER_326, 0x102 },
-	{ WM8996_WRITE_SEQUENCER_328, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_330, 0x106 },
-	{ WM8996_WRITE_SEQUENCER_331, 0x100 },
-	{ WM8996_WRITE_SEQUENCER_332, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_336, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_340, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_344, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_348, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_352, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_356, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_360, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_364, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_368, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_372, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_376, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_380, 0x2fff },
-	{ WM8996_WRITE_SEQUENCER_384, 0x60 },
-	{ WM8996_WRITE_SEQUENCER_386, 0x601 },
-	{ WM8996_WRITE_SEQUENCER_388, 0x61 },
-	{ WM8996_WRITE_SEQUENCER_390, 0x601 },
-	{ WM8996_WRITE_SEQUENCER_392, 0x50 },
-	{ WM8996_WRITE_SEQUENCER_394, 0x300 },
-	{ WM8996_WRITE_SEQUENCER_396, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_398, 0x304 },
-	{ WM8996_WRITE_SEQUENCER_400, 0x40 },
-	{ WM8996_WRITE_SEQUENCER_402, 0xf },
-	{ WM8996_WRITE_SEQUENCER_404, 0x1 },
-	{ WM8996_WRITE_SEQUENCER_407, 0x100 },
 };
 
 static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
@@ -1706,18 +1528,6 @@ static bool wm8996_volatile_register(struct device *dev, unsigned int reg)
 	}
 }
 
-static int wm8996_reset(struct wm8996_priv *wm8996)
-{
-	if (wm8996->pdata.ldo_ena > 0) {
-		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
-		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 1);
-		return 0;
-	} else {
-		return regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET,
-				    0x8915);
-	}
-}
-
 static const int bclk_divs[] = {
 	1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
 };
@@ -1809,8 +1619,10 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_OFF:
 		regcache_cache_only(codec->control_data, true);
-		if (wm8996->pdata.ldo_ena >= 0)
+		if (wm8996->pdata.ldo_ena >= 0) {
 			gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+			regcache_cache_only(codec->control_data, true);
+		}
 		regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies),
 				       wm8996->supplies);
 		break;
@@ -2807,7 +2619,7 @@ static int wm8996_probe(struct snd_soc_codec *codec)
 	int ret;
 	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
 	struct i2c_client *i2c = to_i2c_client(codec->dev);
-	int i, irq_flags;
+	int irq_flags;
 
 	wm8996->codec = codec;
 
@@ -2822,177 +2634,12 @@ static int wm8996_probe(struct snd_soc_codec *codec)
 		goto err;
 	}
 
-	wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0;
-	wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1;
-	wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2;
-
-	/* This should really be moved into the regulator core */
-	for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) {
-		ret = regulator_register_notifier(wm8996->supplies[i].consumer,
-						  &wm8996->disable_nb[i]);
-		if (ret != 0) {
-			dev_err(codec->dev,
-				"Failed to register regulator notifier: %d\n",
-				ret);
-		}
-	}
-
-	/* Apply platform data settings */
-	snd_soc_update_bits(codec, WM8996_LINE_INPUT_CONTROL,
-			    WM8996_INL_MODE_MASK | WM8996_INR_MODE_MASK,
-			    wm8996->pdata.inl_mode << WM8996_INL_MODE_SHIFT |
-			    wm8996->pdata.inr_mode);
-
-	for (i = 0; i < ARRAY_SIZE(wm8996->pdata.gpio_default); i++) {
-		if (!wm8996->pdata.gpio_default[i])
-			continue;
-
-		snd_soc_write(codec, WM8996_GPIO_1 + i,
-			      wm8996->pdata.gpio_default[i] & 0xffff);
-	}
-
-	if (wm8996->pdata.spkmute_seq)
-		snd_soc_update_bits(codec, WM8996_PDM_SPEAKER_MUTE_SEQUENCE,
-				    WM8996_SPK_MUTE_ENDIAN |
-				    WM8996_SPK_MUTE_SEQ1_MASK,
-				    wm8996->pdata.spkmute_seq);
-
-	snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_2,
-			    WM8996_MICD_BIAS_SRC | WM8996_HPOUT1FB_SRC |
-			    WM8996_MICD_SRC, wm8996->pdata.micdet_def);
-
-	/* Latch volume update bits */
-	snd_soc_update_bits(codec, WM8996_LEFT_LINE_INPUT_VOLUME,
-			    WM8996_IN1_VU, WM8996_IN1_VU);
-	snd_soc_update_bits(codec, WM8996_RIGHT_LINE_INPUT_VOLUME,
-			    WM8996_IN1_VU, WM8996_IN1_VU);
-
-	snd_soc_update_bits(codec, WM8996_DAC1_LEFT_VOLUME,
-			    WM8996_DAC1_VU, WM8996_DAC1_VU);
-	snd_soc_update_bits(codec, WM8996_DAC1_RIGHT_VOLUME,
-			    WM8996_DAC1_VU, WM8996_DAC1_VU);
-	snd_soc_update_bits(codec, WM8996_DAC2_LEFT_VOLUME,
-			    WM8996_DAC2_VU, WM8996_DAC2_VU);
-	snd_soc_update_bits(codec, WM8996_DAC2_RIGHT_VOLUME,
-			    WM8996_DAC2_VU, WM8996_DAC2_VU);
-
-	snd_soc_update_bits(codec, WM8996_OUTPUT1_LEFT_VOLUME,
-			    WM8996_DAC1_VU, WM8996_DAC1_VU);
-	snd_soc_update_bits(codec, WM8996_OUTPUT1_RIGHT_VOLUME,
-			    WM8996_DAC1_VU, WM8996_DAC1_VU);
-	snd_soc_update_bits(codec, WM8996_OUTPUT2_LEFT_VOLUME,
-			    WM8996_DAC2_VU, WM8996_DAC2_VU);
-	snd_soc_update_bits(codec, WM8996_OUTPUT2_RIGHT_VOLUME,
-			    WM8996_DAC2_VU, WM8996_DAC2_VU);
-
-	snd_soc_update_bits(codec, WM8996_DSP1_TX_LEFT_VOLUME,
-			    WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
-	snd_soc_update_bits(codec, WM8996_DSP1_TX_RIGHT_VOLUME,
-			    WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
-	snd_soc_update_bits(codec, WM8996_DSP2_TX_LEFT_VOLUME,
-			    WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
-	snd_soc_update_bits(codec, WM8996_DSP2_TX_RIGHT_VOLUME,
-			    WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
-
-	snd_soc_update_bits(codec, WM8996_DSP1_RX_LEFT_VOLUME,
-			    WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
-	snd_soc_update_bits(codec, WM8996_DSP1_RX_RIGHT_VOLUME,
-			    WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
-	snd_soc_update_bits(codec, WM8996_DSP2_RX_LEFT_VOLUME,
-			    WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
-	snd_soc_update_bits(codec, WM8996_DSP2_RX_RIGHT_VOLUME,
-			    WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
-
-	/* No support currently for the underclocked TDM modes and
-	 * pick a default TDM layout with each channel pair working with
-	 * slots 0 and 1. */
-	snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_0_CONFIGURATION,
-			    WM8996_AIF1RX_CHAN0_SLOTS_MASK |
-			    WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
-	snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_1_CONFIGURATION,
-			    WM8996_AIF1RX_CHAN1_SLOTS_MASK |
-			    WM8996_AIF1RX_CHAN1_START_SLOT_MASK,
-			    1 << WM8996_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
-	snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_2_CONFIGURATION,
-			    WM8996_AIF1RX_CHAN2_SLOTS_MASK |
-			    WM8996_AIF1RX_CHAN2_START_SLOT_MASK,
-			    1 << WM8996_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
-	snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_3_CONFIGURATION,
-			    WM8996_AIF1RX_CHAN3_SLOTS_MASK |
-			    WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
-	snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_4_CONFIGURATION,
-			    WM8996_AIF1RX_CHAN4_SLOTS_MASK |
-			    WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
-	snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_5_CONFIGURATION,
-			    WM8996_AIF1RX_CHAN5_SLOTS_MASK |
-			    WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
-
-	snd_soc_update_bits(codec, WM8996_AIF2RX_CHANNEL_0_CONFIGURATION,
-			    WM8996_AIF2RX_CHAN0_SLOTS_MASK |
-			    WM8996_AIF2RX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
-	snd_soc_update_bits(codec, WM8996_AIF2RX_CHANNEL_1_CONFIGURATION,
-			    WM8996_AIF2RX_CHAN1_SLOTS_MASK |
-			    WM8996_AIF2RX_CHAN1_START_SLOT_MASK,
-			    1 << WM8996_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
-
-	snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_0_CONFIGURATION,
-			    WM8996_AIF1TX_CHAN0_SLOTS_MASK |
-			    WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
-	snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
-			    WM8996_AIF1TX_CHAN1_SLOTS_MASK |
-			    WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
-	snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_2_CONFIGURATION,
-			    WM8996_AIF1TX_CHAN2_SLOTS_MASK |
-			    WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
-	snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_3_CONFIGURATION,
-			    WM8996_AIF1TX_CHAN3_SLOTS_MASK |
-			    WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
-	snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_4_CONFIGURATION,
-			    WM8996_AIF1TX_CHAN4_SLOTS_MASK |
-			    WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
-	snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_5_CONFIGURATION,
-			    WM8996_AIF1TX_CHAN5_SLOTS_MASK |
-			    WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
-
-	snd_soc_update_bits(codec, WM8996_AIF2TX_CHANNEL_0_CONFIGURATION,
-			    WM8996_AIF2TX_CHAN0_SLOTS_MASK |
-			    WM8996_AIF2TX_CHAN0_START_SLOT_MASK,
-			    1 << WM8996_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
-	snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
-			    WM8996_AIF2TX_CHAN1_SLOTS_MASK |
-			    WM8996_AIF2TX_CHAN1_START_SLOT_MASK,
-			    1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
-
 	if (wm8996->pdata.num_retune_mobile_cfgs)
 		wm8996_retune_mobile_pdata(codec);
 	else
 		snd_soc_add_codec_controls(codec, wm8996_eq_controls,
 				     ARRAY_SIZE(wm8996_eq_controls));
 
-	/* If the TX LRCLK pins are not in LRCLK mode configure the
-	 * AIFs to source their clocks from the RX LRCLKs.
-	 */
-	if ((snd_soc_read(codec, WM8996_GPIO_1)))
-		snd_soc_update_bits(codec, WM8996_AIF1_TX_LRCLK_2,
-				    WM8996_AIF1TX_LRCLK_MODE,
-				    WM8996_AIF1TX_LRCLK_MODE);
-
-	if ((snd_soc_read(codec, WM8996_GPIO_2)))
-		snd_soc_update_bits(codec, WM8996_AIF2_TX_LRCLK_2,
-				    WM8996_AIF2TX_LRCLK_MODE,
-				    WM8996_AIF2TX_LRCLK_MODE);
-
 	if (i2c->irq) {
 		if (wm8996->pdata.irq_flags)
 			irq_flags = wm8996->pdata.irq_flags;
@@ -3036,9 +2683,7 @@ err:
 
 static int wm8996_remove(struct snd_soc_codec *codec)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
 	struct i2c_client *i2c = to_i2c_client(codec->dev);
-	int i;
 
 	snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL,
 			    WM8996_IM_IRQ, WM8996_IM_IRQ);
@@ -3046,10 +2691,6 @@ static int wm8996_remove(struct snd_soc_codec *codec)
 	if (i2c->irq)
 		free_irq(i2c->irq, codec);
 
-	for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
-		regulator_unregister_notifier(wm8996->supplies[i].consumer,
-					      &wm8996->disable_nb[i]);
-
 	return 0;
 }
 
@@ -3163,6 +2804,21 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
 		goto err_gpio;
 	}
 
+	wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0;
+	wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1;
+	wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2;
+
+	/* This should really be moved into the regulator core */
+	for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) {
+		ret = regulator_register_notifier(wm8996->supplies[i].consumer,
+						  &wm8996->disable_nb[i]);
+		if (ret != 0) {
+			dev_err(&i2c->dev,
+				"Failed to register regulator notifier: %d\n",
+				ret);
+		}
+	}
+
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
 				    wm8996->supplies);
 	if (ret != 0) {
@@ -3175,7 +2831,7 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
 		msleep(5);
 	}
 
-	wm8996->regmap = regmap_init_i2c(i2c, &wm8996_regmap);
+	wm8996->regmap = devm_regmap_init_i2c(i2c, &wm8996_regmap);
 	if (IS_ERR(wm8996->regmap)) {
 		ret = PTR_ERR(wm8996->regmap);
 		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
@@ -3203,15 +2859,199 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
 	dev_info(&i2c->dev, "revision %c\n",
 		 (reg & WM8996_CHIP_REV_MASK) + 'A');
 
-	ret = wm8996_reset(wm8996);
-	if (ret < 0) {
-		dev_err(&i2c->dev, "Failed to issue reset\n");
-		goto err_regmap;
+	if (wm8996->pdata.ldo_ena > 0) {
+		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+		regcache_cache_only(wm8996->regmap, true);
+	} else {
+		ret = regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET,
+				   0x8915);
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
+			goto err_regmap;
+		}
 	}
 
-	regcache_cache_only(wm8996->regmap, true);
 	regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
 
+	/* Apply platform data settings */
+	regmap_update_bits(wm8996->regmap, WM8996_LINE_INPUT_CONTROL,
+			   WM8996_INL_MODE_MASK | WM8996_INR_MODE_MASK,
+			   wm8996->pdata.inl_mode << WM8996_INL_MODE_SHIFT |
+			   wm8996->pdata.inr_mode);
+
+	for (i = 0; i < ARRAY_SIZE(wm8996->pdata.gpio_default); i++) {
+		if (!wm8996->pdata.gpio_default[i])
+			continue;
+
+		regmap_write(wm8996->regmap, WM8996_GPIO_1 + i,
+			     wm8996->pdata.gpio_default[i] & 0xffff);
+	}
+
+	if (wm8996->pdata.spkmute_seq)
+		regmap_update_bits(wm8996->regmap,
+				   WM8996_PDM_SPEAKER_MUTE_SEQUENCE,
+				   WM8996_SPK_MUTE_ENDIAN |
+				   WM8996_SPK_MUTE_SEQ1_MASK,
+				   wm8996->pdata.spkmute_seq);
+
+	regmap_update_bits(wm8996->regmap, WM8996_ACCESSORY_DETECT_MODE_2,
+			   WM8996_MICD_BIAS_SRC | WM8996_HPOUT1FB_SRC |
+			   WM8996_MICD_SRC, wm8996->pdata.micdet_def);
+
+	/* Latch volume update bits */
+	regmap_update_bits(wm8996->regmap, WM8996_LEFT_LINE_INPUT_VOLUME,
+			   WM8996_IN1_VU, WM8996_IN1_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_RIGHT_LINE_INPUT_VOLUME,
+			   WM8996_IN1_VU, WM8996_IN1_VU);
+
+	regmap_update_bits(wm8996->regmap, WM8996_DAC1_LEFT_VOLUME,
+			   WM8996_DAC1_VU, WM8996_DAC1_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DAC1_RIGHT_VOLUME,
+			   WM8996_DAC1_VU, WM8996_DAC1_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DAC2_LEFT_VOLUME,
+			   WM8996_DAC2_VU, WM8996_DAC2_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DAC2_RIGHT_VOLUME,
+			   WM8996_DAC2_VU, WM8996_DAC2_VU);
+
+	regmap_update_bits(wm8996->regmap, WM8996_OUTPUT1_LEFT_VOLUME,
+			   WM8996_DAC1_VU, WM8996_DAC1_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_OUTPUT1_RIGHT_VOLUME,
+			   WM8996_DAC1_VU, WM8996_DAC1_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_OUTPUT2_LEFT_VOLUME,
+			   WM8996_DAC2_VU, WM8996_DAC2_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_OUTPUT2_RIGHT_VOLUME,
+			   WM8996_DAC2_VU, WM8996_DAC2_VU);
+
+	regmap_update_bits(wm8996->regmap, WM8996_DSP1_TX_LEFT_VOLUME,
+			   WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP1_TX_RIGHT_VOLUME,
+			   WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP2_TX_LEFT_VOLUME,
+			   WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP2_TX_RIGHT_VOLUME,
+			   WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
+
+	regmap_update_bits(wm8996->regmap, WM8996_DSP1_RX_LEFT_VOLUME,
+			   WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP1_RX_RIGHT_VOLUME,
+			   WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP2_RX_LEFT_VOLUME,
+			   WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP2_RX_RIGHT_VOLUME,
+			   WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
+
+	/* No support currently for the underclocked TDM modes and
+	 * pick a default TDM layout with each channel pair working with
+	 * slots 0 and 1. */
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_0_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN0_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_1_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN1_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN1_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_2_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN2_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN2_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_3_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN3_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_4_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN4_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_5_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN5_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
+
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF2RX_CHANNEL_0_CONFIGURATION,
+			   WM8996_AIF2RX_CHAN0_SLOTS_MASK |
+			   WM8996_AIF2RX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF2RX_CHANNEL_1_CONFIGURATION,
+			   WM8996_AIF2RX_CHAN1_SLOTS_MASK |
+			   WM8996_AIF2RX_CHAN1_START_SLOT_MASK,
+			   1 << WM8996_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
+
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_0_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN0_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN1_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_2_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN2_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_3_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN3_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_4_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN4_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_5_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN5_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
+
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF2TX_CHANNEL_0_CONFIGURATION,
+			   WM8996_AIF2TX_CHAN0_SLOTS_MASK |
+			   WM8996_AIF2TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
+			   WM8996_AIF2TX_CHAN1_SLOTS_MASK |
+			   WM8996_AIF2TX_CHAN1_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+
+	/* If the TX LRCLK pins are not in LRCLK mode configure the
+	 * AIFs to source their clocks from the RX LRCLKs.
+	 */
+	ret = regmap_read(wm8996->regmap, WM8996_GPIO_1, &reg);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read GPIO1: %d\n", ret);
+		goto err_regmap;
+	}
+
+	if (reg & WM8996_GP1_FN_MASK)
+		regmap_update_bits(wm8996->regmap, WM8996_AIF1_TX_LRCLK_2,
+				   WM8996_AIF1TX_LRCLK_MODE,
+				   WM8996_AIF1TX_LRCLK_MODE);
+
+	ret = regmap_read(wm8996->regmap, WM8996_GPIO_2, &reg);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read GPIO2: %d\n", ret);
+		goto err_regmap;
+	}
+
+	if (reg & WM8996_GP2_FN_MASK)
+		regmap_update_bits(wm8996->regmap, WM8996_AIF2_TX_LRCLK_2,
+				   WM8996_AIF2TX_LRCLK_MODE,
+				   WM8996_AIF2TX_LRCLK_MODE);
+
 	wm8996_init_gpio(wm8996);
 
 	ret = snd_soc_register_codec(&i2c->dev,
@@ -3225,7 +3065,6 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
 err_gpiolib:
 	wm8996_free_gpio(wm8996);
 err_regmap:
-	regmap_exit(wm8996->regmap);
 err_enable:
 	if (wm8996->pdata.ldo_ena > 0)
 		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
@@ -3241,14 +3080,18 @@ err:
 static __devexit int wm8996_i2c_remove(struct i2c_client *client)
 {
 	struct wm8996_priv *wm8996 = i2c_get_clientdata(client);
+	int i;
 
 	snd_soc_unregister_codec(&client->dev);
 	wm8996_free_gpio(wm8996);
-	regmap_exit(wm8996->regmap);
 	if (wm8996->pdata.ldo_ena > 0) {
 		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
 		gpio_free(wm8996->pdata.ldo_ena);
 	}
+	for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
+		regulator_unregister_notifier(wm8996->supplies[i].consumer,
+					      &wm8996->disable_nb[i]);
+
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 9328270..2de74e1 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -3,7 +3,7 @@
  *
  * Author: Mark Brown
  *
- * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index 4b263b6..2c2346f 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC WM9090 driver
  *
- * Copyright 2009, 2010 Wolfson Microelectronics
+ * Copyright 2009-12 Wolfson Microelectronics
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index a154141..099e6ec 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -1,7 +1,7 @@
 /*
  * wm9712.c  --  ALSA Soc WM9712 codec support
  *
- * Copyright 2006 Wolfson Microelectronics PLC.
+ * Copyright 2006-12 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 2d22cc7..3eb19fb 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -1,7 +1,7 @@
 /*
  * wm9713.c  --  ALSA Soc WM9713 codec support
  *
- * Copyright 2006 Wolfson Microelectronics PLC.
+ * Copyright 2006-10 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index dfe957a..61baa48 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -1,7 +1,7 @@
 /*
  * wm_hubs.c  --  WM8993/4 common code
  *
- * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig
new file mode 100644
index 0000000..e334900
--- /dev/null
+++ b/sound/soc/dwc/Kconfig
@@ -0,0 +1,9 @@
+config SND_DESIGNWARE_I2S
+	tristate "Synopsys I2S Device Driver"
+	depends on CLKDEV_LOOKUP
+	help
+	 Say Y or M if you want to add support for I2S driver for
+	 Synopsys desigwnware I2S device. The device supports upto
+	 maximum of 8 channels each for play and record.
+
+
diff --git a/sound/soc/dwc/Makefile b/sound/soc/dwc/Makefile
new file mode 100644
index 0000000..319371f
--- /dev/null
+++ b/sound/soc/dwc/Makefile
@@ -0,0 +1,3 @@
+# SYNOPSYS Platform Support
+obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_i2s.o
+
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
new file mode 100644
index 0000000..e667e2b
--- /dev/null
+++ b/sound/soc/dwc/designware_i2s.c
@@ -0,0 +1,454 @@
+/*
+ * ALSA SoC Synopsys I2S Audio Layer
+ *
+ * sound/soc/spear/designware_i2s.c
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Rajeev Kumar <rajeev-dlh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/designware_i2s.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+/* common register for all channel */
+#define IER		0x000
+#define IRER		0x004
+#define ITER		0x008
+#define CER		0x00C
+#define CCR		0x010
+#define RXFFR		0x014
+#define TXFFR		0x018
+
+/* I2STxRxRegisters for all channels */
+#define LRBR_LTHR(x)	(0x40 * x + 0x020)
+#define RRBR_RTHR(x)	(0x40 * x + 0x024)
+#define RER(x)		(0x40 * x + 0x028)
+#define TER(x)		(0x40 * x + 0x02C)
+#define RCR(x)		(0x40 * x + 0x030)
+#define TCR(x)		(0x40 * x + 0x034)
+#define ISR(x)		(0x40 * x + 0x038)
+#define IMR(x)		(0x40 * x + 0x03C)
+#define ROR(x)		(0x40 * x + 0x040)
+#define TOR(x)		(0x40 * x + 0x044)
+#define RFCR(x)		(0x40 * x + 0x048)
+#define TFCR(x)		(0x40 * x + 0x04C)
+#define RFF(x)		(0x40 * x + 0x050)
+#define TFF(x)		(0x40 * x + 0x054)
+
+/* I2SCOMPRegisters */
+#define I2S_COMP_PARAM_2	0x01F0
+#define I2S_COMP_PARAM_1	0x01F4
+#define I2S_COMP_VERSION	0x01F8
+#define I2S_COMP_TYPE		0x01FC
+
+#define MAX_CHANNEL_NUM		8
+#define MIN_CHANNEL_NUM		2
+
+struct dw_i2s_dev {
+	void __iomem *i2s_base;
+	struct clk *clk;
+	int active;
+	unsigned int capability;
+	struct device *dev;
+
+	/* data related to DMA transfers b/w i2s and DMAC */
+	struct i2s_dma_data play_dma_data;
+	struct i2s_dma_data capture_dma_data;
+	struct i2s_clk_config_data config;
+	int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
+};
+
+static inline void i2s_write_reg(void *io_base, int reg, u32 val)
+{
+	writel(val, io_base + reg);
+}
+
+static inline u32 i2s_read_reg(void *io_base, int reg)
+{
+	return readl(io_base + reg);
+}
+
+static inline void i2s_disable_channels(struct dw_i2s_dev *dev, u32 stream)
+{
+	u32 i = 0;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		for (i = 0; i < 4; i++)
+			i2s_write_reg(dev->i2s_base, TER(i), 0);
+	} else {
+		for (i = 0; i < 4; i++)
+			i2s_write_reg(dev->i2s_base, RER(i), 0);
+	}
+}
+
+static inline void i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream)
+{
+	u32 i = 0;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		for (i = 0; i < 4; i++)
+			i2s_write_reg(dev->i2s_base, TOR(i), 0);
+	} else {
+		for (i = 0; i < 4; i++)
+			i2s_write_reg(dev->i2s_base, ROR(i), 0);
+	}
+}
+
+void i2s_start(struct dw_i2s_dev *dev, struct snd_pcm_substream *substream)
+{
+
+	i2s_write_reg(dev->i2s_base, IER, 1);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		i2s_write_reg(dev->i2s_base, ITER, 1);
+	else
+		i2s_write_reg(dev->i2s_base, IRER, 1);
+
+	i2s_write_reg(dev->i2s_base, CER, 1);
+}
+
+static void i2s_stop(struct dw_i2s_dev *dev,
+		struct snd_pcm_substream *substream)
+{
+	u32 i = 0, irq;
+
+	i2s_clear_irqs(dev, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		i2s_write_reg(dev->i2s_base, ITER, 0);
+
+		for (i = 0; i < 4; i++) {
+			irq = i2s_read_reg(dev->i2s_base, IMR(i));
+			i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x30);
+		}
+	} else {
+		i2s_write_reg(dev->i2s_base, IRER, 0);
+
+		for (i = 0; i < 4; i++) {
+			irq = i2s_read_reg(dev->i2s_base, IMR(i));
+			i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x03);
+		}
+	}
+
+	if (!dev->active) {
+		i2s_write_reg(dev->i2s_base, CER, 0);
+		i2s_write_reg(dev->i2s_base, IER, 0);
+	}
+}
+
+static int dw_i2s_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *cpu_dai)
+{
+	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+	struct i2s_dma_data *dma_data = NULL;
+
+	if (!(dev->capability & DWC_I2S_RECORD) &&
+			(substream->stream == SNDRV_PCM_STREAM_CAPTURE))
+		return -EINVAL;
+
+	if (!(dev->capability & DWC_I2S_PLAY) &&
+			(substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
+		return -EINVAL;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_data = &dev->play_dma_data;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		dma_data = &dev->capture_dma_data;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
+
+	return 0;
+}
+
+static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	struct i2s_clk_config_data *config = &dev->config;
+	u32 ccr, xfer_resolution, ch_reg, irq;
+	int ret;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		config->data_width = 16;
+		ccr = 0x00;
+		xfer_resolution = 0x02;
+		break;
+
+	case SNDRV_PCM_FORMAT_S24_LE:
+		config->data_width = 24;
+		ccr = 0x08;
+		xfer_resolution = 0x04;
+		break;
+
+	case SNDRV_PCM_FORMAT_S32_LE:
+		config->data_width = 32;
+		ccr = 0x10;
+		xfer_resolution = 0x05;
+		break;
+
+	default:
+		dev_err(dev->dev, "designware-i2s: unsuppted PCM fmt");
+		return -EINVAL;
+	}
+
+	config->chan_nr = params_channels(params);
+
+	switch (config->chan_nr) {
+	case EIGHT_CHANNEL_SUPPORT:
+		ch_reg = 3;
+	case SIX_CHANNEL_SUPPORT:
+		ch_reg = 2;
+	case FOUR_CHANNEL_SUPPORT:
+		ch_reg = 1;
+	case TWO_CHANNEL_SUPPORT:
+		ch_reg = 0;
+		break;
+	default:
+		dev_err(dev->dev, "channel not supported\n");
+	}
+
+	i2s_disable_channels(dev, substream->stream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		i2s_write_reg(dev->i2s_base, TCR(ch_reg), xfer_resolution);
+		i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
+		irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
+		i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
+		i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
+	} else {
+		i2s_write_reg(dev->i2s_base, RCR(ch_reg), xfer_resolution);
+		i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
+		irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
+		i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
+		i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
+	}
+
+	i2s_write_reg(dev->i2s_base, CCR, ccr);
+
+	config->sample_rate = params_rate(params);
+
+	if (!dev->i2s_clk_cfg)
+		return -EINVAL;
+
+	ret = dev->i2s_clk_cfg(config);
+	if (ret < 0) {
+		dev_err(dev->dev, "runtime audio clk config fail\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int dw_i2s_trigger(struct snd_pcm_substream *substream,
+		int cmd, struct snd_soc_dai *dai)
+{
+	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		dev->active++;
+		i2s_start(dev, substream);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		dev->active--;
+		i2s_stop(dev, substream);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static struct snd_soc_dai_ops dw_i2s_dai_ops = {
+	.startup	= dw_i2s_startup,
+	.shutdown	= dw_i2s_shutdown,
+	.hw_params	= dw_i2s_hw_params,
+	.trigger	= dw_i2s_trigger,
+};
+
+#ifdef CONFIG_PM
+
+static int dw_i2s_suspend(struct snd_soc_dai *dai)
+{
+	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+	clk_disable(dev->clk);
+	return 0;
+}
+
+static int dw_i2s_resume(struct snd_soc_dai *dai)
+{
+	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+	clk_enable(dev->clk);
+	return 0;
+}
+
+#else
+#define dw_i2s_suspend	NULL
+#define dw_i2s_resume	NULL
+#endif
+
+static int dw_i2s_probe(struct platform_device *pdev)
+{
+	const struct i2s_platform_data *pdata = pdev->dev.platform_data;
+	struct dw_i2s_dev *dev;
+	struct resource *res;
+	int ret;
+	unsigned int cap;
+	struct snd_soc_dai_driver *dw_i2s_dai;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "Invalid platform data\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no i2s resource defined\n");
+		return -ENODEV;
+	}
+
+	if (!devm_request_mem_region(&pdev->dev, res->start,
+				resource_size(res), pdev->name)) {
+		dev_err(&pdev->dev, "i2s region already claimed\n");
+		return -EBUSY;
+	}
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		dev_warn(&pdev->dev, "kzalloc fail\n");
+		return -ENOMEM;
+	}
+
+	dev->i2s_base = devm_ioremap(&pdev->dev, res->start,
+			resource_size(res));
+	if (!dev->i2s_base) {
+		dev_err(&pdev->dev, "ioremap fail for i2s_region\n");
+		return -ENOMEM;
+	}
+
+	cap = pdata->cap;
+	dev->capability = cap;
+	dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
+
+	/* Set DMA slaves info */
+
+	dev->play_dma_data.data = pdata->play_dma_data;
+	dev->capture_dma_data.data = pdata->capture_dma_data;
+	dev->play_dma_data.addr = res->start + I2S_TXDMA;
+	dev->capture_dma_data.addr = res->start + I2S_RXDMA;
+	dev->play_dma_data.max_burst = 16;
+	dev->capture_dma_data.max_burst = 16;
+	dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+	dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+	dev->play_dma_data.filter = pdata->filter;
+	dev->capture_dma_data.filter = pdata->filter;
+
+	dev->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dev->clk))
+		return  PTR_ERR(dev->clk);
+
+	ret = clk_enable(dev->clk);
+	if (ret < 0)
+		goto err_clk_put;
+
+	dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
+	if (!dw_i2s_dai) {
+		dev_err(&pdev->dev, "mem allocation failed for dai driver\n");
+		ret = -ENOMEM;
+		goto err_clk_disable;
+	}
+
+	if (cap & DWC_I2S_PLAY) {
+		dev_dbg(&pdev->dev, " SPEAr: play supported\n");
+		dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
+		dw_i2s_dai->playback.channels_max = pdata->channel;
+		dw_i2s_dai->playback.formats = pdata->snd_fmts;
+		dw_i2s_dai->playback.rates = pdata->snd_rates;
+	}
+
+	if (cap & DWC_I2S_RECORD) {
+		dev_dbg(&pdev->dev, "SPEAr: record supported\n");
+		dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
+		dw_i2s_dai->capture.channels_max = pdata->channel;
+		dw_i2s_dai->capture.formats = pdata->snd_fmts;
+		dw_i2s_dai->capture.rates = pdata->snd_rates;
+	}
+
+	dw_i2s_dai->ops = &dw_i2s_dai_ops;
+	dw_i2s_dai->suspend = dw_i2s_suspend;
+	dw_i2s_dai->resume = dw_i2s_resume;
+
+	dev->dev = &pdev->dev;
+	dev_set_drvdata(&pdev->dev, dev);
+	ret = snd_soc_register_dai(&pdev->dev, dw_i2s_dai);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "not able to register dai\n");
+		goto err_set_drvdata;
+	}
+
+	return 0;
+
+err_set_drvdata:
+	dev_set_drvdata(&pdev->dev, NULL);
+err_clk_disable:
+	clk_disable(dev->clk);
+err_clk_put:
+	clk_put(dev->clk);
+	return ret;
+}
+
+static int dw_i2s_remove(struct platform_device *pdev)
+{
+	struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	clk_put(dev->clk);
+
+	return 0;
+}
+
+static struct platform_driver dw_i2s_driver = {
+	.probe		= dw_i2s_probe,
+	.remove		= dw_i2s_remove,
+	.driver		= {
+		.name	= "designware-i2s",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(dw_i2s_driver);
+
+MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
+MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:designware_i2s");
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
index 162dbb7..4eea98b 100644
--- a/sound/soc/ep93xx/ep93xx-pcm.c
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -136,7 +136,7 @@ static struct snd_pcm_ops ep93xx_pcm_ops = {
 	.hw_params	= ep93xx_pcm_hw_params,
 	.hw_free	= ep93xx_pcm_hw_free,
 	.trigger	= snd_dmaengine_pcm_trigger,
-	.pointer	= snd_dmaengine_pcm_pointer,
+	.pointer	= snd_dmaengine_pcm_pointer_no_residue,
 	.mmap		= ep93xx_pcm_mmap,
 };
 
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index f3c0a5e..48f9d88 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -141,7 +141,7 @@ static struct snd_pcm_ops imx_pcm_ops = {
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= snd_imx_pcm_hw_params,
 	.trigger	= snd_dmaengine_pcm_trigger,
-	.pointer	= snd_dmaengine_pcm_pointer,
+	.pointer	= snd_dmaengine_pcm_pointer_no_residue,
 	.mmap		= snd_imx_pcm_mmap,
 };
 
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
index 373dec9..f82d766 100644
--- a/sound/soc/mxs/mxs-pcm.c
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -141,7 +141,7 @@ static struct snd_pcm_ops mxs_pcm_ops = {
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= snd_mxs_pcm_hw_params,
 	.trigger	= snd_dmaengine_pcm_trigger,
-	.pointer	= snd_dmaengine_pcm_pointer,
+	.pointer	= snd_dmaengine_pcm_pointer_no_residue,
 	.mmap		= snd_mxs_pcm_mmap,
 };
 
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index 3e6e876..215113b 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -133,7 +133,7 @@ static int __devinit mxs_sgtl5000_probe_dt(struct platform_device *pdev)
 		mxs_sgtl5000_dai[i].codec_name = NULL;
 		mxs_sgtl5000_dai[i].codec_of_node = codec_np;
 		mxs_sgtl5000_dai[i].cpu_dai_name = NULL;
-		mxs_sgtl5000_dai[i].cpu_dai_of_node = saif_np[i];
+		mxs_sgtl5000_dai[i].cpu_of_node = saif_np[i];
 		mxs_sgtl5000_dai[i].platform_name = NULL;
 		mxs_sgtl5000_dai[i].platform_of_node = saif_np[i];
 	}
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index a0f7d3c..4d2e46f 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -8,6 +8,15 @@ config SND_PXA2XX_SOC
 	  the PXA2xx AC97, I2S or SSP interface. You will also need
 	  to select the audio interfaces to support below.
 
+config SND_MMP_SOC
+	bool "Soc Audio for Marvell MMP chips"
+	depends on ARCH_MMP
+	select SND_SOC_DMAENGINE_PCM
+	select SND_ARM
+	help
+	  Say Y if you want to add support for codecs attached to
+	  the MMP SSPA interface.
+
 config SND_PXA2XX_AC97
 	tristate
 	select SND_AC97_CODEC
@@ -26,6 +35,9 @@ config SND_PXA_SOC_SSP
 	tristate
 	select PXA_SSP
 
+config SND_MMP_SOC_SSPA
+	tristate
+
 config SND_PXA2XX_SOC_CORGI
 	tristate "SoC Audio support for Sharp Zaurus SL-C7x0"
 	depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx
@@ -138,6 +150,26 @@ config SND_SOC_TAVOREVB3
 	  Say Y if you want to add support for SoC audio on the
 	  Marvell Saarb reference platform.
 
+config SND_PXA910_SOC
+	tristate "SoC Audio for Marvell PXA910 chip"
+	depends on ARCH_MMP && SND
+	select SND_PCM
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  Marvell PXA910 reference platform.
+
+config SND_SOC_TTC_DKB
+	bool "SoC Audio support for TTC DKB"
+	depends on SND_PXA910_SOC && MACH_TTC_DKB
+	select PXA_SSP
+	select SND_PXA_SOC_SSP
+	select SND_MMP_SOC
+	select MFD_88PM860X
+	select SND_SOC_88PM860X
+	help
+	  Say Y if you want to add support for SoC audio on TTC DKB
+
+
 config SND_SOC_ZYLONITE
 	tristate "SoC Audio support for Marvell Zylonite"
 	depends on SND_PXA2XX_SOC && MACH_ZYLONITE
@@ -194,3 +226,13 @@ config SND_PXA2XX_SOC_IMOTE2
        help
          Say Y if you want to add support for SoC audio on the
 	 IMote 2.
+
+config SND_MMP_SOC_BROWNSTONE
+	tristate "SoC Audio support for Marvell Brownstone"
+	depends on SND_MMP_SOC && MACH_BROWNSTONE
+	select SND_MMP_SOC_SSPA
+	select MFD_WM8994
+	select SND_SOC_WM8994
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  Marvell Brownstone reference platform.
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index af35762..d8a265d 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -3,11 +3,15 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o
 snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
 snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
 snd-soc-pxa-ssp-objs := pxa-ssp.o
+snd-soc-mmp-objs := mmp-pcm.o
+snd-soc-mmp-sspa-objs := mmp-sspa.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
 obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
 obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
 obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o
+obj-$(CONFIG_SND_MMP_SOC) += snd-soc-mmp.o
+obj-$(CONFIG_SND_MMP_SOC_SSPA) += snd-soc-mmp-sspa.o
 
 # PXA Machine Support
 snd-soc-corgi-objs := corgi.o
@@ -28,6 +32,8 @@ snd-soc-mioa701-objs := mioa701_wm9713.o
 snd-soc-z2-objs := z2.o
 snd-soc-imote2-objs := imote2.o
 snd-soc-raumfeld-objs := raumfeld.o
+snd-soc-brownstone-objs := brownstone.o
+snd-soc-ttc-dkb-objs := ttc-dkb.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
 obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
@@ -47,3 +53,5 @@ obj-$(CONFIG_SND_SOC_TAVOREVB3) += snd-soc-tavorevb3.o
 obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
 obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
 obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
+obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o
+obj-$(CONFIG_SND_SOC_TTC_DKB) += snd-soc-ttc-dkb.o
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c
new file mode 100644
index 0000000..5e666e0
--- /dev/null
+++ b/sound/soc/pxa/brownstone.c
@@ -0,0 +1,174 @@
+/*
+ * linux/sound/soc/pxa/brownstone.c
+ *
+ * Copyright (C) 2011 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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 <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "../codecs/wm8994.h"
+#include "mmp-sspa.h"
+
+static const struct snd_kcontrol_new brownstone_dapm_control[] = {
+	SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static const struct snd_soc_dapm_widget brownstone_dapm_widgets[] = {
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+	SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Main Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route brownstone_audio_map[] = {
+	{"Ext Spk", NULL, "SPKOUTLP"},
+	{"Ext Spk", NULL, "SPKOUTLN"},
+	{"Ext Spk", NULL, "SPKOUTRP"},
+	{"Ext Spk", NULL, "SPKOUTRN"},
+
+	{"Headset Stereophone", NULL, "HPOUT1L"},
+	{"Headset Stereophone", NULL, "HPOUT1R"},
+
+	{"IN1RN", NULL, "Headset Mic"},
+
+	{"DMIC1DAT", NULL, "MICBIAS1"},
+	{"MICBIAS1", NULL, "Main Mic"},
+};
+
+static int brownstone_wm8994_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+	snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
+	snd_soc_dapm_enable_pin(dapm, "Headset Mic");
+	snd_soc_dapm_enable_pin(dapm, "Main Mic");
+
+	/* set endpoints to not connected */
+	snd_soc_dapm_nc_pin(dapm, "HPOUT2P");
+	snd_soc_dapm_nc_pin(dapm, "HPOUT2N");
+	snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
+	snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
+	snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
+	snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
+	snd_soc_dapm_nc_pin(dapm, "IN1LN");
+	snd_soc_dapm_nc_pin(dapm, "IN1LP");
+	snd_soc_dapm_nc_pin(dapm, "IN1RP");
+	snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
+	snd_soc_dapm_nc_pin(dapm, "IN2RN");
+	snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
+	snd_soc_dapm_nc_pin(dapm, "IN2LN");
+
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream,
+				       struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int freq_out, sspa_mclk, sysclk;
+	int sspa_div;
+
+	if (params_rate(params) > 11025) {
+		freq_out  = params_rate(params) * 512;
+		sysclk    = params_rate(params) * 256;
+		sspa_mclk = params_rate(params) * 64;
+	} else {
+		freq_out  = params_rate(params) * 1024;
+		sysclk    = params_rate(params) * 512;
+		sspa_mclk = params_rate(params) * 64;
+	}
+	sspa_div = freq_out;
+	do_div(sspa_div, sspa_mclk);
+
+	snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0);
+	snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk);
+	snd_soc_dai_set_pll(cpu_dai, MMP_SSPA_CLK, 0, freq_out, sspa_mclk);
+
+	/* set wm8994 sysclk */
+	snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, sysclk, 0);
+
+	return 0;
+}
+
+/* machine stream operations */
+static struct snd_soc_ops brownstone_ops = {
+	.hw_params = brownstone_wm8994_hw_params,
+};
+
+static struct snd_soc_dai_link brownstone_wm8994_dai[] = {
+{
+	.name		= "WM8994",
+	.stream_name	= "WM8994 HiFi",
+	.cpu_dai_name	= "mmp-sspa-dai.0",
+	.codec_dai_name	= "wm8994-aif1",
+	.platform_name	= "mmp-pcm-audio",
+	.codec_name	= "wm8994-codec",
+	.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+				SND_SOC_DAIFMT_CBS_CFS,
+	.ops		= &brownstone_ops,
+	.init		= brownstone_wm8994_init,
+},
+};
+
+/* audio machine driver */
+static struct snd_soc_card brownstone = {
+	.name         = "brownstone",
+	.dai_link     = brownstone_wm8994_dai,
+	.num_links    = ARRAY_SIZE(brownstone_wm8994_dai),
+
+	.controls = brownstone_dapm_control,
+	.num_controls = ARRAY_SIZE(brownstone_dapm_control),
+	.dapm_widgets = brownstone_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(brownstone_dapm_widgets),
+	.dapm_routes = brownstone_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(brownstone_audio_map),
+};
+
+static int __devinit brownstone_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	brownstone.dev = &pdev->dev;
+	ret = snd_soc_register_card(&brownstone);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+				ret);
+	return ret;
+}
+
+static int __devexit brownstone_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_card(&brownstone);
+	return 0;
+}
+
+static struct platform_driver mmp_driver = {
+	.driver		= {
+		.name	= "brownstone-audio",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= brownstone_probe,
+	.remove		= __devexit_p(brownstone_remove),
+};
+
+module_platform_driver(mmp_driver);
+
+MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC Brownstone");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
new file mode 100644
index 0000000..73ac546
--- /dev/null
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -0,0 +1,297 @@
+/*
+ * linux/sound/soc/pxa/mmp-pcm.c
+ *
+ * Copyright (C) 2011 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_data/mmp_audio.h>
+#include <sound/pxa2xx-lib.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <mach/sram.h>
+#include <sound/dmaengine_pcm.h>
+
+struct mmp_dma_data {
+	int ssp_id;
+	struct resource *dma_res;
+};
+
+#define MMP_PCM_INFO (SNDRV_PCM_INFO_MMAP |	\
+		SNDRV_PCM_INFO_MMAP_VALID |	\
+		SNDRV_PCM_INFO_INTERLEAVED |	\
+		SNDRV_PCM_INFO_PAUSE |		\
+		SNDRV_PCM_INFO_RESUME)
+
+#define MMP_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			 SNDRV_PCM_FMTBIT_S24_LE | \
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_pcm_hardware mmp_pcm_hardware[] = {
+	{
+		.info			= MMP_PCM_INFO,
+		.formats		= MMP_PCM_FORMATS,
+		.period_bytes_min	= 1024,
+		.period_bytes_max	= 2048,
+		.periods_min		= 2,
+		.periods_max		= 32,
+		.buffer_bytes_max	= 4096,
+		.fifo_size		= 32,
+	},
+	{
+		.info			= MMP_PCM_INFO,
+		.formats		= MMP_PCM_FORMATS,
+		.period_bytes_min	= 1024,
+		.period_bytes_max	= 2048,
+		.periods_min		= 2,
+		.periods_max		= 32,
+		.buffer_bytes_max	= 4096,
+		.fifo_size		= 32,
+	},
+};
+
+static int mmp_pcm_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params)
+{
+	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct pxa2xx_pcm_dma_params *dma_params;
+	struct dma_slave_config slave_config;
+	int ret;
+
+	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+	if (!dma_params)
+		return 0;
+
+	ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
+	if (ret)
+		return ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config.dst_addr     = dma_params->dev_addr;
+		slave_config.dst_maxburst = 4;
+	} else {
+		slave_config.src_addr	  = dma_params->dev_addr;
+		slave_config.src_maxburst = 4;
+	}
+
+	ret = dmaengine_slave_config(chan, &slave_config);
+	if (ret)
+		return ret;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static bool filter(struct dma_chan *chan, void *param)
+{
+	struct mmp_dma_data *dma_data = param;
+	bool found = false;
+	char *devname;
+
+	devname = kasprintf(GFP_KERNEL, "%s.%d", dma_data->dma_res->name,
+		dma_data->ssp_id);
+	if ((strcmp(dev_name(chan->device->dev), devname) == 0) &&
+		(chan->chan_id == dma_data->dma_res->start)) {
+		found = true;
+	}
+
+	kfree(devname);
+	return found;
+}
+
+static int mmp_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct platform_device *pdev = to_platform_device(rtd->platform->dev);
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct mmp_dma_data *dma_data;
+	struct resource *r;
+	int ret;
+
+	r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream);
+	if (!r)
+		return -EBUSY;
+
+	snd_soc_set_runtime_hwparams(substream,
+				&mmp_pcm_hardware[substream->stream]);
+	dma_data = devm_kzalloc(&pdev->dev,
+			sizeof(struct mmp_dma_data), GFP_KERNEL);
+	if (dma_data == NULL)
+		return -ENOMEM;
+
+	dma_data->dma_res = r;
+	dma_data->ssp_id = cpu_dai->id;
+
+	ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
+	if (ret) {
+		devm_kfree(&pdev->dev, dma_data);
+		return ret;
+	}
+
+	snd_dmaengine_pcm_set_data(substream, dma_data);
+	return 0;
+}
+
+static int mmp_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct mmp_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct platform_device *pdev = to_platform_device(rtd->platform->dev);
+
+	snd_dmaengine_pcm_close(substream);
+	devm_kfree(&pdev->dev, dma_data);
+	return 0;
+}
+
+static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
+			 struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned long off = vma->vm_pgoff;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	return remap_pfn_range(vma, vma->vm_start,
+		__phys_to_pfn(runtime->dma_addr) + off,
+		vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+struct snd_pcm_ops mmp_pcm_ops = {
+	.open		= mmp_pcm_open,
+	.close		= mmp_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= mmp_pcm_hw_params,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer,
+	.mmap		= mmp_pcm_mmap,
+};
+
+static void mmp_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+	struct gen_pool *gpool;
+
+	gpool = sram_get_gpool("asram");
+	if (!gpool)
+		return;
+
+	for (stream = 0; stream < 2; stream++) {
+		size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
+
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+		gen_pool_free(gpool, (unsigned long)buf->area, size);
+		buf->area = NULL;
+	}
+
+	return;
+}
+
+static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream,
+								int stream)
+{
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
+	struct gen_pool *gpool;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = substream->pcm->card->dev;
+	buf->private_data = NULL;
+
+	gpool = sram_get_gpool("asram");
+	if (!gpool)
+		return -ENOMEM;
+
+	buf->area = (unsigned char *)gen_pool_alloc(gpool, size);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->addr = gen_pool_virt_to_phys(gpool, (unsigned long)buf->area);
+	buf->bytes = size;
+	return 0;
+}
+
+int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_pcm *pcm = rtd->pcm;
+	int ret = 0, stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+
+		ret = mmp_pcm_preallocate_dma_buffer(substream,	stream);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	mmp_pcm_free_dma_buffers(pcm);
+	return ret;
+}
+
+struct snd_soc_platform_driver mmp_soc_platform = {
+	.ops		= &mmp_pcm_ops,
+	.pcm_new	= mmp_pcm_new,
+	.pcm_free	= mmp_pcm_free_dma_buffers,
+};
+
+static __devinit int mmp_pcm_probe(struct platform_device *pdev)
+{
+	struct mmp_audio_platdata *pdata = pdev->dev.platform_data;
+
+	if (pdata) {
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].buffer_bytes_max =
+						pdata->buffer_max_playback;
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].period_bytes_max =
+						pdata->period_max_playback;
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].buffer_bytes_max =
+						pdata->buffer_max_capture;
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].period_bytes_max =
+						pdata->period_max_capture;
+	}
+	return snd_soc_register_platform(&pdev->dev, &mmp_soc_platform);
+}
+
+static int __devexit mmp_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver mmp_pcm_driver = {
+	.driver = {
+		.name = "mmp-pcm-audio",
+		.owner = THIS_MODULE,
+	},
+
+	.probe = mmp_pcm_probe,
+	.remove = __devexit_p(mmp_pcm_remove),
+};
+
+module_platform_driver(mmp_pcm_driver);
+
+MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
+MODULE_DESCRIPTION("MMP Soc Audio DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
new file mode 100644
index 0000000..4d6cb8a
--- /dev/null
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -0,0 +1,480 @@
+/*
+ * linux/sound/soc/pxa/mmp-sspa.c
+ * Base on pxa2xx-ssp.c
+ *
+ * Copyright (C) 2011 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
+#include "mmp-sspa.h"
+
+/*
+ * SSPA audio private data
+ */
+struct sspa_priv {
+	struct ssp_device *sspa;
+	struct pxa2xx_pcm_dma_params *dma_params;
+	struct clk *audio_clk;
+	struct clk *sysclk;
+	int dai_fmt;
+	int running_cnt;
+};
+
+static void mmp_sspa_write_reg(struct ssp_device *sspa, u32 reg, u32 val)
+{
+	__raw_writel(val, sspa->mmio_base + reg);
+}
+
+static u32 mmp_sspa_read_reg(struct ssp_device *sspa, u32 reg)
+{
+	return __raw_readl(sspa->mmio_base + reg);
+}
+
+static void mmp_sspa_tx_enable(struct ssp_device *sspa)
+{
+	unsigned int sspa_sp;
+
+	sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP);
+	sspa_sp |= SSPA_SP_S_EN;
+	sspa_sp |= SSPA_SP_WEN;
+	mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
+}
+
+static void mmp_sspa_tx_disable(struct ssp_device *sspa)
+{
+	unsigned int sspa_sp;
+
+	sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP);
+	sspa_sp &= ~SSPA_SP_S_EN;
+	sspa_sp |= SSPA_SP_WEN;
+	mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
+}
+
+static void mmp_sspa_rx_enable(struct ssp_device *sspa)
+{
+	unsigned int sspa_sp;
+
+	sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP);
+	sspa_sp |= SSPA_SP_S_EN;
+	sspa_sp |= SSPA_SP_WEN;
+	mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
+}
+
+static void mmp_sspa_rx_disable(struct ssp_device *sspa)
+{
+	unsigned int sspa_sp;
+
+	sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP);
+	sspa_sp &= ~SSPA_SP_S_EN;
+	sspa_sp |= SSPA_SP_WEN;
+	mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
+}
+
+static int mmp_sspa_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+	clk_enable(priv->sysclk);
+	clk_enable(priv->sspa->clk);
+
+	return 0;
+}
+
+static void mmp_sspa_shutdown(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+	clk_disable(priv->sspa->clk);
+	clk_disable(priv->sysclk);
+
+	return;
+}
+
+/*
+ * Set the SSP ports SYSCLK.
+ */
+static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+				    int clk_id, unsigned int freq, int dir)
+{
+	struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+	int ret = 0;
+
+	switch (clk_id) {
+	case MMP_SSPA_CLK_AUDIO:
+		ret = clk_set_rate(priv->audio_clk, freq);
+		if (ret)
+			return ret;
+		break;
+	case MMP_SSPA_CLK_PLL:
+	case MMP_SSPA_CLK_VCXO:
+		/* not support yet */
+		return -EINVAL;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mmp_sspa_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
+				 int source, unsigned int freq_in,
+				 unsigned int freq_out)
+{
+	struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+	int ret = 0;
+
+	switch (pll_id) {
+	case MMP_SYSCLK:
+		ret = clk_set_rate(priv->sysclk, freq_out);
+		if (ret)
+			return ret;
+		break;
+	case MMP_SSPA_CLK:
+		ret = clk_set_rate(priv->sspa->clk, freq_out);
+		if (ret)
+			return ret;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/*
+ * Set up the sspa dai format. The sspa port must be inactive
+ * before calling this function as the physical
+ * interface format is changed.
+ */
+static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+				 unsigned int fmt)
+{
+	struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct ssp_device *sspa = sspa_priv->sspa;
+	u32 sspa_sp, sspa_ctrl;
+
+	/* check if we need to change anything at all */
+	if (sspa_priv->dai_fmt == fmt)
+		return 0;
+
+	/* we can only change the settings if the port is not in use */
+	if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) ||
+	    (mmp_sspa_read_reg(sspa, SSPA_RXSP) & SSPA_SP_S_EN)) {
+		dev_err(&sspa->pdev->dev,
+			"can't change hardware dai format: stream is in use\n");
+		return -EINVAL;
+	}
+
+	/* reset port settings */
+	sspa_sp   = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH;
+	sspa_ctrl = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		sspa_sp |= SSPA_SP_MSL;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		sspa_sp |= SSPA_SP_FSP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		sspa_sp |= SSPA_TXSP_FPER(63);
+		sspa_sp |= SSPA_SP_FWID(31);
+		sspa_ctrl |= SSPA_CTL_XDATDLY(1);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
+	mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
+
+	sspa_sp &= ~(SSPA_SP_S_RST | SSPA_SP_FFLUSH);
+	mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
+	mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
+
+	/*
+	 * FIXME: hw issue, for the tx serial port,
+	 * can not config the master/slave mode;
+	 * so must clean this bit.
+	 * The master/slave mode has been set in the
+	 * rx port.
+	 */
+	sspa_sp &= ~SSPA_SP_MSL;
+	mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
+
+	mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl);
+	mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl);
+
+	/* Since we are configuring the timings for the format by hand
+	 * we have to defer some things until hw_params() where we
+	 * know parameters like the sample size.
+	 */
+	sspa_priv->dai_fmt = fmt;
+	return 0;
+}
+
+/*
+ * Set the SSPA audio DMA parameters and sample size.
+ * Can be called multiple times by oss emulation.
+ */
+static int mmp_sspa_hw_params(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *params,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai);
+	struct ssp_device *sspa = sspa_priv->sspa;
+	struct pxa2xx_pcm_dma_params *dma_params;
+	u32 sspa_ctrl;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_TXCTL);
+	else
+		sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_RXCTL);
+
+	sspa_ctrl &= ~SSPA_CTL_XFRLEN1_MASK;
+	sspa_ctrl |= SSPA_CTL_XFRLEN1(params_channels(params) - 1);
+	sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK;
+	sspa_ctrl |= SSPA_CTL_XWDLEN1(SSPA_CTL_32_BITS);
+	sspa_ctrl &= ~SSPA_CTL_XSSZ1_MASK;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_8_BITS);
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS);
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_20_BITS);
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS);
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_32_BITS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl);
+		mmp_sspa_write_reg(sspa, SSPA_TXFIFO_LL, 0x1);
+	} else {
+		mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl);
+		mmp_sspa_write_reg(sspa, SSPA_RXFIFO_UL, 0x0);
+	}
+
+	dma_params = &sspa_priv->dma_params[substream->stream];
+	dma_params->dev_addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+				(sspa->phys_base + SSPA_TXD) :
+				(sspa->phys_base + SSPA_RXD);
+	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_params);
+	return 0;
+}
+
+static int mmp_sspa_trigger(struct snd_pcm_substream *substream, int cmd,
+			     struct snd_soc_dai *dai)
+{
+	struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai);
+	struct ssp_device *sspa = sspa_priv->sspa;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		/*
+		 * whatever playback or capture, must enable rx.
+		 * this is a hw issue, so need check if rx has been
+		 * enabled or not; if has been enabled by another
+		 * stream, do not enable again.
+		 */
+		if (!sspa_priv->running_cnt)
+			mmp_sspa_rx_enable(sspa);
+
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			mmp_sspa_tx_enable(sspa);
+
+		sspa_priv->running_cnt++;
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		sspa_priv->running_cnt--;
+
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			mmp_sspa_tx_disable(sspa);
+
+		/* have no capture stream, disable rx port */
+		if (!sspa_priv->running_cnt)
+			mmp_sspa_rx_disable(sspa);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int mmp_sspa_probe(struct snd_soc_dai *dai)
+{
+	struct sspa_priv *priv = dev_get_drvdata(dai->dev);
+
+	snd_soc_dai_set_drvdata(dai, priv);
+	return 0;
+
+}
+
+#define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000
+#define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+		SNDRV_PCM_FMTBIT_S16_LE | \
+		SNDRV_PCM_FMTBIT_S24_LE | \
+		SNDRV_PCM_FMTBIT_S24_LE | \
+		SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops mmp_sspa_dai_ops = {
+	.startup	= mmp_sspa_startup,
+	.shutdown	= mmp_sspa_shutdown,
+	.trigger	= mmp_sspa_trigger,
+	.hw_params	= mmp_sspa_hw_params,
+	.set_sysclk	= mmp_sspa_set_dai_sysclk,
+	.set_pll	= mmp_sspa_set_dai_pll,
+	.set_fmt	= mmp_sspa_set_dai_fmt,
+};
+
+struct snd_soc_dai_driver mmp_sspa_dai = {
+	.probe = mmp_sspa_probe,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 128,
+		.rates = MMP_SSPA_RATES,
+		.formats = MMP_SSPA_FORMATS,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = MMP_SSPA_RATES,
+		.formats = MMP_SSPA_FORMATS,
+	},
+	.ops = &mmp_sspa_dai_ops,
+};
+
+static __devinit int asoc_mmp_sspa_probe(struct platform_device *pdev)
+{
+	struct sspa_priv *priv;
+	struct resource *res;
+
+	priv = devm_kzalloc(&pdev->dev,
+				sizeof(struct sspa_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->sspa = devm_kzalloc(&pdev->dev,
+				sizeof(struct ssp_device), GFP_KERNEL);
+	if (priv->sspa == NULL)
+		return -ENOMEM;
+
+	priv->dma_params = devm_kzalloc(&pdev->dev,
+			2 * sizeof(struct pxa2xx_pcm_dma_params), GFP_KERNEL);
+	if (priv->dma_params == NULL)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -ENOMEM;
+
+	priv->sspa->mmio_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (priv->sspa->mmio_base == NULL)
+		return -ENODEV;
+
+	priv->sspa->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->sspa->clk))
+		return PTR_ERR(priv->sspa->clk);
+
+	priv->audio_clk = clk_get(NULL, "mmp-audio");
+	if (IS_ERR(priv->audio_clk))
+		return PTR_ERR(priv->audio_clk);
+
+	priv->sysclk = clk_get(NULL, "mmp-sysclk");
+	if (IS_ERR(priv->sysclk)) {
+		clk_put(priv->audio_clk);
+		return PTR_ERR(priv->sysclk);
+	}
+	clk_enable(priv->audio_clk);
+	priv->dai_fmt = (unsigned int) -1;
+	platform_set_drvdata(pdev, priv);
+
+	return snd_soc_register_dai(&pdev->dev, &mmp_sspa_dai);
+}
+
+static int __devexit asoc_mmp_sspa_remove(struct platform_device *pdev)
+{
+	struct sspa_priv *priv = platform_get_drvdata(pdev);
+
+	clk_disable(priv->audio_clk);
+	clk_put(priv->audio_clk);
+	clk_put(priv->sysclk);
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver asoc_mmp_sspa_driver = {
+	.driver = {
+		.name = "mmp-sspa-dai",
+		.owner = THIS_MODULE,
+	},
+	.probe = asoc_mmp_sspa_probe,
+	.remove = __devexit_p(asoc_mmp_sspa_remove),
+};
+
+module_platform_driver(asoc_mmp_sspa_driver);
+
+MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
+MODULE_DESCRIPTION("MMP SSPA SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/mmp-sspa.h b/sound/soc/pxa/mmp-sspa.h
new file mode 100644
index 0000000..ea365cb
--- /dev/null
+++ b/sound/soc/pxa/mmp-sspa.h
@@ -0,0 +1,92 @@
+/*
+ * linux/sound/soc/pxa/mmp-sspa.h
+ *
+ * Copyright (C) 2011 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef _MMP_SSPA_H
+#define _MMP_SSPA_H
+
+/*
+ * SSPA Registers
+ */
+#define SSPA_RXD		(0x00)
+#define SSPA_RXID		(0x04)
+#define SSPA_RXCTL		(0x08)
+#define SSPA_RXSP		(0x0c)
+#define SSPA_RXFIFO_UL		(0x10)
+#define SSPA_RXINT_MASK		(0x14)
+#define SSPA_RXC		(0x18)
+#define SSPA_RXFIFO_NOFS	(0x1c)
+#define SSPA_RXFIFO_SIZE	(0x20)
+
+#define SSPA_TXD		(0x80)
+#define SSPA_TXID		(0x84)
+#define SSPA_TXCTL		(0x88)
+#define SSPA_TXSP		(0x8c)
+#define SSPA_TXFIFO_LL		(0x90)
+#define SSPA_TXINT_MASK		(0x94)
+#define SSPA_TXC		(0x98)
+#define SSPA_TXFIFO_NOFS	(0x9c)
+#define SSPA_TXFIFO_SIZE	(0xa0)
+
+/* SSPA Control Register */
+#define	SSPA_CTL_XPH		(1 << 31)	/* Read Phase */
+#define	SSPA_CTL_XFIG		(1 << 15)	/* Transmit Zeros when FIFO Empty */
+#define	SSPA_CTL_JST		(1 << 3)	/* Audio Sample Justification */
+#define	SSPA_CTL_XFRLEN2_MASK	(7 << 24)
+#define	SSPA_CTL_XFRLEN2(x)	((x) << 24)	/* Transmit Frame Length in Phase 2 */
+#define	SSPA_CTL_XWDLEN2_MASK	(7 << 21)
+#define	SSPA_CTL_XWDLEN2(x)	((x) << 21)	/* Transmit Word Length in Phase 2 */
+#define	SSPA_CTL_XDATDLY(x)	((x) << 19)	/* Tansmit Data Delay */
+#define	SSPA_CTL_XSSZ2_MASK	(7 << 16)
+#define	SSPA_CTL_XSSZ2(x)	((x) << 16)	/* Transmit Sample Audio Size */
+#define	SSPA_CTL_XFRLEN1_MASK	(7 << 8)
+#define	SSPA_CTL_XFRLEN1(x)	((x) << 8)	/* Transmit Frame Length in Phase 1 */
+#define	SSPA_CTL_XWDLEN1_MASK	(7 << 5)
+#define	SSPA_CTL_XWDLEN1(x)	((x) << 5)	/* Transmit Word Length in Phase 1 */
+#define	SSPA_CTL_XSSZ1_MASK	(7 << 0)
+#define	SSPA_CTL_XSSZ1(x)	((x) << 0)	/* XSSZ1 */
+
+#define SSPA_CTL_8_BITS		(0x0)		/* Sample Size */
+#define SSPA_CTL_12_BITS	(0x1)
+#define SSPA_CTL_16_BITS	(0x2)
+#define SSPA_CTL_20_BITS	(0x3)
+#define SSPA_CTL_24_BITS	(0x4)
+#define SSPA_CTL_32_BITS	(0x5)
+
+/* SSPA Serial Port Register */
+#define	SSPA_SP_WEN		(1 << 31)	/* Write Configuration Enable */
+#define	SSPA_SP_MSL		(1 << 18)	/* Master Slave Configuration */
+#define	SSPA_SP_CLKP		(1 << 17)	/* CLKP Polarity Clock Edge Select */
+#define	SSPA_SP_FSP		(1 << 16)	/* FSP Polarity Clock Edge Select */
+#define	SSPA_SP_FFLUSH		(1 << 2)	/* FIFO Flush */
+#define	SSPA_SP_S_RST		(1 << 1)	/* Active High Reset Signal */
+#define	SSPA_SP_S_EN		(1 << 0)	/* Serial Clock Domain Enable */
+#define	SSPA_SP_FWID(x)		((x) << 20)	/* Frame-Sync Width */
+#define	SSPA_TXSP_FPER(x)	((x) << 4)	/* Frame-Sync Active */
+
+/* sspa clock sources */
+#define MMP_SSPA_CLK_PLL	0
+#define MMP_SSPA_CLK_VCXO	1
+#define MMP_SSPA_CLK_AUDIO	3
+
+/* sspa pll id */
+#define MMP_SYSCLK		0
+#define MMP_SSPA_CLK		1
+
+#endif /* _MMP_SSPA_H */
diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c
new file mode 100644
index 0000000..935491a
--- /dev/null
+++ b/sound/soc/pxa/ttc-dkb.c
@@ -0,0 +1,173 @@
+/*
+ * linux/sound/soc/pxa/ttc_dkb.c
+ *
+ * Copyright (C) 2012 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <sound/pcm_params.h>
+#include "../codecs/88pm860x-codec.h"
+
+static struct snd_soc_jack hs_jack, mic_jack;
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+	{ .pin = "Headset Stereophone",	.mask = SND_JACK_HEADPHONE, },
+};
+
+static struct snd_soc_jack_pin mic_jack_pins[] = {
+	{ .pin = "Headset Mic 2",	.mask = SND_JACK_MICROPHONE, },
+};
+
+/* ttc machine dapm widgets */
+static const struct snd_soc_dapm_widget ttc_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+	SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
+	SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
+	SND_SOC_DAPM_SPK("Ext Speaker", NULL),
+	SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic 2", NULL),
+	SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
+};
+
+/* ttc machine audio map */
+static const struct snd_soc_dapm_route ttc_audio_map[] = {
+	{"Headset Stereophone", NULL, "HS1"},
+	{"Headset Stereophone", NULL, "HS2"},
+
+	{"Ext Speaker", NULL, "LSP"},
+	{"Ext Speaker", NULL, "LSN"},
+
+	{"Lineout Out 1", NULL, "LINEOUT1"},
+	{"Lineout Out 2", NULL, "LINEOUT2"},
+
+	{"MIC1P", NULL, "Mic1 Bias"},
+	{"MIC1N", NULL, "Mic1 Bias"},
+	{"Mic1 Bias", NULL, "Ext Mic 1"},
+
+	{"MIC2P", NULL, "Mic1 Bias"},
+	{"MIC2N", NULL, "Mic1 Bias"},
+	{"Mic1 Bias", NULL, "Headset Mic 2"},
+
+	{"MIC3P", NULL, "Mic3 Bias"},
+	{"MIC3N", NULL, "Mic3 Bias"},
+	{"Mic3 Bias", NULL, "Ext Mic 3"},
+};
+
+static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	/* connected pins */
+	snd_soc_dapm_enable_pin(dapm, "Ext Speaker");
+	snd_soc_dapm_enable_pin(dapm, "Ext Mic 1");
+	snd_soc_dapm_enable_pin(dapm, "Ext Mic 3");
+	snd_soc_dapm_disable_pin(dapm, "Headset Mic 2");
+	snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
+
+	/* Headset jack detection */
+	snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
+			| SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+			&hs_jack);
+	snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+			      hs_jack_pins);
+	snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
+			 &mic_jack);
+	snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
+			      mic_jack_pins);
+
+	/* headphone, microphone detection & headset short detection */
+	pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
+			      SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
+	pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
+
+	return 0;
+}
+
+/* ttc/td-dkb digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link ttc_pm860x_hifi_dai[] = {
+{
+	 .name = "88pm860x i2s",
+	 .stream_name = "audio playback",
+	 .codec_name = "88pm860x-codec",
+	 .platform_name = "mmp-pcm-audio",
+	 .cpu_dai_name = "pxa-ssp-dai.1",
+	 .codec_dai_name = "88pm860x-i2s",
+	 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBM_CFM,
+	 .init = ttc_pm860x_init,
+},
+};
+
+/* ttc/td audio machine driver */
+static struct snd_soc_card ttc_dkb_card = {
+	.name = "ttc-dkb-hifi",
+	.dai_link = ttc_pm860x_hifi_dai,
+	.num_links = ARRAY_SIZE(ttc_pm860x_hifi_dai),
+
+	.dapm_widgets = ttc_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ttc_dapm_widgets),
+	.dapm_routes = ttc_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(ttc_audio_map),
+};
+
+static int __devinit ttc_dkb_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &ttc_dkb_card;
+	int ret;
+
+	card->dev = &pdev->dev;
+
+	ret = snd_soc_register_card(card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+
+	return ret;
+}
+
+static int __devexit ttc_dkb_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
+
+	return 0;
+}
+
+static struct platform_driver ttc_dkb_driver = {
+	.driver		= {
+		.name	= "ttc-dkb-audio",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ttc_dkb_probe,
+	.remove		= __devexit_p(ttc_dkb_remove),
+};
+
+module_platform_driver(ttc_dkb_driver);
+
+/* Module information */
+MODULE_AUTHOR("Qiao Zhou, <zhouqiao@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC TTC DKB");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ttc-dkb-audio");
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
index ddc6cde..f3ebc38 100644
--- a/sound/soc/samsung/dma.c
+++ b/sound/soc/samsung/dma.c
@@ -74,7 +74,7 @@ static void dma_enqueue(struct snd_pcm_substream *substream)
 	struct runtime_data *prtd = substream->runtime->private_data;
 	dma_addr_t pos = prtd->dma_pos;
 	unsigned int limit;
-	struct samsung_dma_prep_info dma_info;
+	struct samsung_dma_prep dma_info;
 
 	pr_debug("Entered %s\n", __func__);
 
@@ -146,7 +146,8 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
 	unsigned long totbytes = params_buffer_bytes(params);
 	struct s3c_dma_params *dma =
 		snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-	struct samsung_dma_info dma_info;
+	struct samsung_dma_req req;
+	struct samsung_dma_config config;
 
 	pr_debug("Entered %s\n", __func__);
 
@@ -166,16 +167,17 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
 
 		prtd->params->ops = samsung_dma_get_ops();
 
-		dma_info.cap = (samsung_dma_has_circular() ?
+		req.cap = (samsung_dma_has_circular() ?
 			DMA_CYCLIC : DMA_SLAVE);
-		dma_info.client = prtd->params->client;
-		dma_info.direction =
+		req.client = prtd->params->client;
+		config.direction =
 			(substream->stream == SNDRV_PCM_STREAM_PLAYBACK
 			? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
-		dma_info.width = prtd->params->dma_size;
-		dma_info.fifo = prtd->params->dma_addr;
+		config.width = prtd->params->dma_size;
+		config.fifo = prtd->params->dma_addr;
 		prtd->params->ch = prtd->params->ops->request(
-				prtd->params->channel, &dma_info);
+				prtd->params->channel, &req);
+		prtd->params->ops->config(prtd->params->ch, &config);
 	}
 
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 2ef9853..53486ff 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -247,7 +247,7 @@ struct fsi_priv {
 struct fsi_stream_handler {
 	int (*init)(struct fsi_priv *fsi, struct fsi_stream *io);
 	int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io);
-	int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io);
+	int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev);
 	int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io);
 	int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io);
 	void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
@@ -571,16 +571,16 @@ static int fsi_stream_transfer(struct fsi_stream *io)
 #define fsi_stream_stop(fsi, io)\
 	fsi_stream_handler_call(io, start_stop, fsi, io, 0)
 
-static int fsi_stream_probe(struct fsi_priv *fsi)
+static int fsi_stream_probe(struct fsi_priv *fsi, struct device *dev)
 {
 	struct fsi_stream *io;
 	int ret1, ret2;
 
 	io = &fsi->playback;
-	ret1 = fsi_stream_handler_call(io, probe, fsi, io);
+	ret1 = fsi_stream_handler_call(io, probe, fsi, io, dev);
 
 	io = &fsi->capture;
-	ret2 = fsi_stream_handler_call(io, probe, fsi, io);
+	ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev);
 
 	if (ret1 < 0)
 		return ret1;
@@ -1089,13 +1089,10 @@ static void fsi_dma_do_tasklet(unsigned long data)
 {
 	struct fsi_stream *io = (struct fsi_stream *)data;
 	struct fsi_priv *fsi = fsi_stream_to_priv(io);
-	struct dma_chan *chan;
 	struct snd_soc_dai *dai;
 	struct dma_async_tx_descriptor *desc;
-	struct scatterlist sg;
 	struct snd_pcm_runtime *runtime;
 	enum dma_data_direction dir;
-	dma_cookie_t cookie;
 	int is_play = fsi_stream_is_play(fsi, io);
 	int len;
 	dma_addr_t buf;
@@ -1104,7 +1101,6 @@ static void fsi_dma_do_tasklet(unsigned long data)
 		return;
 
 	dai	= fsi_get_dai(io->substream);
-	chan	= io->chan;
 	runtime	= io->substream->runtime;
 	dir	= is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
 	len	= samples_to_bytes(runtime, io->period_samples);
@@ -1112,14 +1108,8 @@ static void fsi_dma_do_tasklet(unsigned long data)
 
 	dma_sync_single_for_device(dai->dev, buf, len, dir);
 
-	sg_init_table(&sg, 1);
-	sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)),
-		    len , offset_in_page(buf));
-	sg_dma_address(&sg) = buf;
-	sg_dma_len(&sg) = len;
-
-	desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir,
-				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	desc = dmaengine_prep_slave_single(io->chan, buf, len, dir,
+					   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc) {
 		dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n");
 		return;
@@ -1128,13 +1118,12 @@ static void fsi_dma_do_tasklet(unsigned long data)
 	desc->callback		= fsi_dma_complete;
 	desc->callback_param	= io;
 
-	cookie = desc->tx_submit(desc);
-	if (cookie < 0) {
+	if (dmaengine_submit(desc) < 0) {
 		dev_err(dai->dev, "tx_submit() fail\n");
 		return;
 	}
 
-	dma_async_issue_pending(chan);
+	dma_async_issue_pending(io->chan);
 
 	/*
 	 * FIXME
@@ -1184,7 +1173,7 @@ static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
 		fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
 }
 
-static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
+static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
 {
 	dma_cap_mask_t mask;
 
@@ -1192,8 +1181,19 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
 	dma_cap_set(DMA_SLAVE, mask);
 
 	io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave);
-	if (!io->chan)
-		return -EIO;
+	if (!io->chan) {
+
+		/* switch to PIO handler */
+		if (fsi_stream_is_play(fsi, io))
+			fsi->playback.handler	= &fsi_pio_push_handler;
+		else
+			fsi->capture.handler	= &fsi_pio_pop_handler;
+
+		dev_info(dev, "switch handler (dma => pio)\n");
+
+		/* probe again */
+		return fsi_stream_probe(fsi, dev);
+	}
 
 	tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io);
 
@@ -1683,7 +1683,7 @@ static int fsi_probe(struct platform_device *pdev)
 	master->fsia.master	= master;
 	master->fsia.info	= &info->port_a;
 	fsi_handler_init(&master->fsia);
-	ret = fsi_stream_probe(&master->fsia);
+	ret = fsi_stream_probe(&master->fsia, &pdev->dev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "FSIA stream probe failed\n");
 		goto exit_iounmap;
@@ -1694,7 +1694,7 @@ static int fsi_probe(struct platform_device *pdev)
 	master->fsib.master	= master;
 	master->fsib.info	= &info->port_b;
 	fsi_handler_init(&master->fsib);
-	ret = fsi_stream_probe(&master->fsib);
+	ret = fsi_stream_probe(&master->fsib, &pdev->dev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "FSIB stream probe failed\n");
 		goto exit_fsia;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index b37ee80..fe16135 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -812,13 +812,15 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 
 	/* Find CPU DAI from registered DAIs*/
 	list_for_each_entry(cpu_dai, &dai_list, list) {
-		if (dai_link->cpu_dai_of_node) {
-			if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
-				continue;
-		} else {
-			if (strcmp(cpu_dai->name, dai_link->cpu_dai_name))
-				continue;
-		}
+		if (dai_link->cpu_of_node &&
+		    (cpu_dai->dev->of_node != dai_link->cpu_of_node))
+			continue;
+		if (dai_link->cpu_name &&
+		    strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name))
+			continue;
+		if (dai_link->cpu_dai_name &&
+		    strcmp(cpu_dai->name, dai_link->cpu_dai_name))
+			continue;
 
 		rtd->cpu_dai = cpu_dai;
 	}
@@ -896,6 +898,28 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 	return 0;
 }
 
+static int soc_remove_platform(struct snd_soc_platform *platform)
+{
+	int ret;
+
+	if (platform->driver->remove) {
+		ret = platform->driver->remove(platform);
+		if (ret < 0)
+			pr_err("asoc: failed to remove %s: %d\n",
+				platform->name, ret);
+	}
+
+	/* Make sure all DAPM widgets are freed */
+	snd_soc_dapm_free(&platform->dapm);
+
+	soc_cleanup_platform_debugfs(platform);
+	platform->probed = 0;
+	list_del(&platform->card_list);
+	module_put(platform->dev->driver->owner);
+
+	return 0;
+}
+
 static void soc_remove_codec(struct snd_soc_codec *codec)
 {
 	int err;
@@ -917,11 +941,9 @@ static void soc_remove_codec(struct snd_soc_codec *codec)
 	module_put(codec->dev->driver->owner);
 }
 
-static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
+static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
 {
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
-	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
 	int err;
 
@@ -946,30 +968,6 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
 		list_del(&codec_dai->card_list);
 	}
 
-	/* remove the platform */
-	if (platform && platform->probed &&
-			platform->driver->remove_order == order) {
-		if (platform->driver->remove) {
-			err = platform->driver->remove(platform);
-			if (err < 0)
-				pr_err("asoc: failed to remove %s: %d\n",
-							platform->name, err);
-		}
-
-		/* Make sure all DAPM widgets are freed */
-		snd_soc_dapm_free(&platform->dapm);
-
-		soc_cleanup_platform_debugfs(platform);
-		platform->probed = 0;
-		list_del(&platform->card_list);
-		module_put(platform->dev->driver->owner);
-	}
-
-	/* remove the CODEC */
-	if (codec && codec->probed &&
-			codec->driver->remove_order == order)
-		soc_remove_codec(codec);
-
 	/* remove the cpu_dai */
 	if (cpu_dai && cpu_dai->probed &&
 			cpu_dai->driver->remove_order == order) {
@@ -981,7 +979,43 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
 		}
 		cpu_dai->probed = 0;
 		list_del(&cpu_dai->card_list);
-		module_put(cpu_dai->dev->driver->owner);
+
+		if (!cpu_dai->codec) {
+			snd_soc_dapm_free(&cpu_dai->dapm);
+			module_put(cpu_dai->dev->driver->owner);
+		}
+	}
+}
+
+static void soc_remove_link_components(struct snd_soc_card *card, int num,
+				       int order)
+{
+	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_platform *platform = rtd->platform;
+	struct snd_soc_codec *codec;
+
+	/* remove the platform */
+	if (platform && platform->probed &&
+	    platform->driver->remove_order == order) {
+		soc_remove_platform(platform);
+	}
+
+	/* remove the CODEC-side CODEC */
+	if (codec_dai) {
+		codec = codec_dai->codec;
+		if (codec && codec->probed &&
+		    codec->driver->remove_order == order)
+			soc_remove_codec(codec);
+	}
+
+	/* remove any CPU-side CODEC */
+	if (cpu_dai) {
+		codec = cpu_dai->codec;
+		if (codec && codec->probed &&
+		    codec->driver->remove_order == order)
+			soc_remove_codec(codec);
 	}
 }
 
@@ -992,8 +1026,15 @@ static void soc_remove_dai_links(struct snd_soc_card *card)
 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
 			order++) {
 		for (dai = 0; dai < card->num_rtd; dai++)
-			soc_remove_dai_link(card, dai, order);
+			soc_remove_link_dais(card, dai, order);
 	}
+
+	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
+			order++) {
+		for (dai = 0; dai < card->num_rtd; dai++)
+			soc_remove_link_components(card, dai, order);
+	}
+
 	card->num_rtd = 0;
 }
 
@@ -1230,7 +1271,44 @@ out:
 	return 0;
 }
 
-static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
+static int soc_probe_link_components(struct snd_soc_card *card, int num,
+				     int order)
+{
+	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_platform *platform = rtd->platform;
+	int ret;
+
+	/* probe the CPU-side component, if it is a CODEC */
+	if (cpu_dai->codec &&
+	    !cpu_dai->codec->probed &&
+	    cpu_dai->codec->driver->probe_order == order) {
+		ret = soc_probe_codec(card, cpu_dai->codec);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* probe the CODEC-side component */
+	if (!codec_dai->codec->probed &&
+	    codec_dai->codec->driver->probe_order == order) {
+		ret = soc_probe_codec(card, codec_dai->codec);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* probe the platform */
+	if (!platform->probed &&
+	    platform->driver->probe_order == order) {
+		ret = soc_probe_platform(card, platform);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
 {
 	struct snd_soc_dai_link *dai_link = &card->dai_link[num];
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
@@ -1255,11 +1333,14 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
 	/* probe the cpu_dai */
 	if (!cpu_dai->probed &&
 			cpu_dai->driver->probe_order == order) {
-		cpu_dai->dapm.card = card;
-		if (!try_module_get(cpu_dai->dev->driver->owner))
-			return -ENODEV;
+		if (!cpu_dai->codec) {
+			cpu_dai->dapm.card = card;
+			if (!try_module_get(cpu_dai->dev->driver->owner))
+				return -ENODEV;
 
-		snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai);
+			list_add(&cpu_dai->dapm.list, &card->dapm_list);
+			snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai);
+		}
 
 		if (cpu_dai->driver->probe) {
 			ret = cpu_dai->driver->probe(cpu_dai);
@@ -1275,22 +1356,6 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
 		list_add(&cpu_dai->card_list, &card->dai_dev_list);
 	}
 
-	/* probe the CODEC */
-	if (!codec->probed &&
-			codec->driver->probe_order == order) {
-		ret = soc_probe_codec(card, codec);
-		if (ret < 0)
-			return ret;
-	}
-
-	/* probe the platform */
-	if (!platform->probed &&
-			platform->driver->probe_order == order) {
-		ret = soc_probe_platform(card, platform);
-		if (ret < 0)
-			return ret;
-	}
-
 	/* probe the CODEC DAI */
 	if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
 		if (codec_dai->driver->probe) {
@@ -1565,14 +1630,27 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
 			goto card_probe_error;
 	}
 
-	/* early DAI link probe */
+	/* probe all components used by DAI links on this card */
 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
 			order++) {
 		for (i = 0; i < card->num_links; i++) {
-			ret = soc_probe_dai_link(card, i, order);
+			ret = soc_probe_link_components(card, i, order);
 			if (ret < 0) {
 				pr_err("asoc: failed to instantiate card %s: %d\n",
-			       card->name, ret);
+				       card->name, ret);
+				goto probe_dai_err;
+			}
+		}
+	}
+
+	/* probe all DAI links on this card */
+	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
+			order++) {
+		for (i = 0; i < card->num_links; i++) {
+			ret = soc_probe_link_dais(card, i, order);
+			if (ret < 0) {
+				pr_err("asoc: failed to instantiate card %s: %d\n",
+				       card->name, ret);
 				goto probe_dai_err;
 			}
 		}
@@ -2790,6 +2868,104 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
 
 /**
+ * snd_soc_info_volsw_range - single mixer info callback with range.
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information, within a range, about a single
+ * mixer control.
+ *
+ * returns 0 for success.
+ */
+int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	int platform_max;
+	int min = mc->min;
+
+	if (!mc->platform_max)
+		mc->platform_max = mc->max;
+	platform_max = mc->platform_max;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = platform_max - min;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range);
+
+/**
+ * snd_soc_put_volsw_range - single mixer put value callback with range.
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to set the value, within a range, for a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int shift = mc->shift;
+	int min = mc->min;
+	int max = mc->max;
+	unsigned int mask = (1 << fls(max)) - 1;
+	unsigned int invert = mc->invert;
+	unsigned int val, val_mask;
+
+	val = ((ucontrol->value.integer.value[0] + min) & mask);
+	if (invert)
+		val = max - val;
+	val_mask = mask << shift;
+	val = val << shift;
+
+	return snd_soc_update_bits_locked(codec, reg, val_mask, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);
+
+/**
+ * snd_soc_get_volsw_range - single mixer get callback with range
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value, within a range, of a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int shift = mc->shift;
+	int min = mc->min;
+	int max = mc->max;
+	unsigned int mask = (1 << fls(max)) - 1;
+	unsigned int invert = mc->invert;
+
+	ucontrol->value.integer.value[0] =
+		(snd_soc_read(codec, reg) >> shift) & mask;
+	if (invert)
+		ucontrol->value.integer.value[0] =
+			max - ucontrol->value.integer.value[0];
+	ucontrol->value.integer.value[0] =
+		ucontrol->value.integer.value[0] - min;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
+
+/**
  * snd_soc_limit_volume - Set new limit to an existing volume control.
  *
  * @codec: where to look for the control
@@ -3346,6 +3522,12 @@ int snd_soc_register_card(struct snd_soc_card *card)
 				link->name);
 			return -EINVAL;
 		}
+		/* Codec DAI name must be specified */
+		if (!link->codec_dai_name) {
+			dev_err(card->dev, "codec_dai_name not set for %s\n",
+				link->name);
+			return -EINVAL;
+		}
 
 		/*
 		 * Platform may be specified by either name or OF node, but
@@ -3358,12 +3540,24 @@ int snd_soc_register_card(struct snd_soc_card *card)
 		}
 
 		/*
-		 * CPU DAI must be specified by 1 of name or OF node,
-		 * not both or neither.
+		 * CPU device may be specified by either name or OF node, but
+		 * can be left unspecified, and will be matched based on DAI
+		 * name alone..
+		 */
+		if (link->cpu_name && link->cpu_of_node) {
+			dev_err(card->dev,
+				"Neither/both cpu name/of_node are set for %s\n",
+				link->name);
+			return -EINVAL;
+		}
+		/*
+		 * At least one of CPU DAI name or CPU device name/node must be
+		 * specified
 		 */
-		if (!!link->cpu_dai_name == !!link->cpu_dai_of_node) {
+		if (!link->cpu_dai_name &&
+		    !(link->cpu_name || link->cpu_of_node)) {
 			dev_err(card->dev,
-				"Neither/both cpu_dai name/of_node are set for %s\n",
+				"Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
 				link->name);
 			return -EINVAL;
 		}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 89eae93..9670668 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -35,6 +35,7 @@
 #include <linux/debugfs.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/clk.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -51,6 +52,7 @@ static int dapm_up_seq[] = {
 	[snd_soc_dapm_pre] = 0,
 	[snd_soc_dapm_supply] = 1,
 	[snd_soc_dapm_regulator_supply] = 1,
+	[snd_soc_dapm_clock_supply] = 1,
 	[snd_soc_dapm_micbias] = 2,
 	[snd_soc_dapm_dai_link] = 2,
 	[snd_soc_dapm_dai] = 3,
@@ -92,6 +94,7 @@ static int dapm_down_seq[] = {
 	[snd_soc_dapm_aif_out] = 10,
 	[snd_soc_dapm_dai] = 10,
 	[snd_soc_dapm_dai_link] = 11,
+	[snd_soc_dapm_clock_supply] = 12,
 	[snd_soc_dapm_regulator_supply] = 12,
 	[snd_soc_dapm_supply] = 12,
 	[snd_soc_dapm_post] = 13,
@@ -391,6 +394,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
 	case snd_soc_dapm_vmid:
 	case snd_soc_dapm_supply:
 	case snd_soc_dapm_regulator_supply:
+	case snd_soc_dapm_clock_supply:
 	case snd_soc_dapm_aif_in:
 	case snd_soc_dapm_aif_out:
 	case snd_soc_dapm_dai:
@@ -764,6 +768,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
 	switch (widget->id) {
 	case snd_soc_dapm_supply:
 	case snd_soc_dapm_regulator_supply:
+	case snd_soc_dapm_clock_supply:
 		return 0;
 	default:
 		break;
@@ -850,6 +855,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
 	switch (widget->id) {
 	case snd_soc_dapm_supply:
 	case snd_soc_dapm_regulator_supply:
+	case snd_soc_dapm_clock_supply:
 		return 0;
 	default:
 		break;
@@ -996,6 +1002,26 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(dapm_regulator_event);
 
+/*
+ * Handler for clock supply widget.
+ */
+int dapm_clock_event(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol, int event)
+{
+	if (!w->clk)
+		return -EIO;
+
+#ifdef CONFIG_HAVE_CLK
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		return clk_enable(w->clk);
+	} else {
+		clk_disable(w->clk);
+		return 0;
+	}
+#endif
+}
+EXPORT_SYMBOL_GPL(dapm_clock_event);
+
 static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
 {
 	if (w->power_checked)
@@ -1487,6 +1513,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
 	switch (w->id) {
 	case snd_soc_dapm_supply:
 	case snd_soc_dapm_regulator_supply:
+	case snd_soc_dapm_clock_supply:
 		/* Supplies can't affect their outputs, only their inputs */
 		break;
 	default:
@@ -1587,6 +1614,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
 				break;
 			case snd_soc_dapm_supply:
 			case snd_soc_dapm_regulator_supply:
+			case snd_soc_dapm_clock_supply:
 			case snd_soc_dapm_micbias:
 				if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
 					d->target_bias_level = SND_SOC_BIAS_STANDBY;
@@ -1941,6 +1969,7 @@ static ssize_t dapm_widget_show(struct device *dev,
 		case snd_soc_dapm_mixer_named_ctl:
 		case snd_soc_dapm_supply:
 		case snd_soc_dapm_regulator_supply:
+		case snd_soc_dapm_clock_supply:
 			if (w->name)
 				count += sprintf(buf + count, "%s: %s\n",
 					w->name, w->power ? "On":"Off");
@@ -2187,6 +2216,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
 	case snd_soc_dapm_post:
 	case snd_soc_dapm_supply:
 	case snd_soc_dapm_regulator_supply:
+	case snd_soc_dapm_clock_supply:
 	case snd_soc_dapm_aif_in:
 	case snd_soc_dapm_aif_out:
 	case snd_soc_dapm_dai:
@@ -2246,15 +2276,15 @@ err:
 int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
 			    const struct snd_soc_dapm_route *route, int num)
 {
-	int i, ret = 0;
+	int i, r, ret = 0;
 
 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 	for (i = 0; i < num; i++) {
-		ret = snd_soc_dapm_add_route(dapm, route);
-		if (ret < 0) {
+		r = snd_soc_dapm_add_route(dapm, route);
+		if (r < 0) {
 			dev_err(dapm->dev, "Failed to add route %s->%s\n",
 				route->source, route->sink);
-			break;
+			ret = r;
 		}
 		route++;
 	}
@@ -2485,19 +2515,13 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
 	int wi;
 
 	val = (ucontrol->value.integer.value[0] & mask);
+	connect = !!val;
 
 	if (invert)
 		val = max - val;
 	mask = mask << shift;
 	val = val << shift;
 
-	if (val)
-		/* new connection */
-		connect = invert ? 0 : 1;
-	else
-		/* old connection must be powered down */
-		connect = invert ? 1 : 0;
-
 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	change = snd_soc_test_bits(widget->codec, reg, mask, val);
@@ -2873,6 +2897,19 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 			return NULL;
 		}
 		break;
+	case snd_soc_dapm_clock_supply:
+#ifdef CONFIG_CLKDEV_LOOKUP
+		w->clk = devm_clk_get(dapm->dev, w->name);
+		if (IS_ERR(w->clk)) {
+			ret = PTR_ERR(w->clk);
+			dev_err(dapm->dev, "Failed to request %s: %d\n",
+				w->name, ret);
+			return NULL;
+		}
+#else
+		return NULL;
+#endif
+		break;
 	default:
 		break;
 	}
@@ -2924,6 +2961,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 		break;
 	case snd_soc_dapm_supply:
 	case snd_soc_dapm_regulator_supply:
+	case snd_soc_dapm_clock_supply:
 		w->power_check = dapm_supply_check_power;
 		break;
 	case snd_soc_dapm_dai:
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c
index 4756952..5df529e 100644
--- a/sound/soc/soc-dmaengine-pcm.c
+++ b/sound/soc/soc-dmaengine-pcm.c
@@ -30,6 +30,7 @@
 
 struct dmaengine_pcm_runtime_data {
 	struct dma_chan *dma_chan;
+	dma_cookie_t cookie;
 
 	unsigned int pos;
 
@@ -153,7 +154,7 @@ static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
 
 	desc->callback = dmaengine_pcm_dma_complete;
 	desc->callback_param = substream;
-	dmaengine_submit(desc);
+	prtd->cookie = dmaengine_submit(desc);
 
 	return 0;
 }
@@ -200,6 +201,20 @@ int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger);
 
 /**
+ * snd_dmaengine_pcm_pointer_no_residue - dmaengine based PCM pointer implementation
+ * @substream: PCM substream
+ *
+ * This function is deprecated and should not be used by new drivers, as its
+ * results may be unreliable.
+ */
+snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+	return bytes_to_frames(substream->runtime, prtd->pos);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer_no_residue);
+
+/**
  * snd_dmaengine_pcm_pointer - dmaengine based PCM pointer implementation
  * @substream: PCM substream
  *
@@ -209,7 +224,19 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger);
 snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
 {
 	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
-	return bytes_to_frames(substream->runtime, prtd->pos);
+	struct dma_tx_state state;
+	enum dma_status status;
+	unsigned int buf_size;
+	unsigned int pos = 0;
+
+	status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state);
+	if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) {
+		buf_size = snd_pcm_lib_buffer_bytes(substream);
+		if (state.residue > 0 && state.residue <= buf_size)
+			pos = buf_size - state.residue;
+	}
+
+	return bytes_to_frames(substream->runtime, pos);
 }
 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
 
@@ -243,7 +270,7 @@ static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd
  * Note that this function will use private_data field of the substream's
  * runtime. So it is not availabe to your pcm driver implementation. If you need
  * to keep additional data attached to a substream use
- * snd_dmaeinge_pcm_{set,get}_data.
+ * snd_dmaengine_pcm_{set,get}_data.
  */
 int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
 	dma_filter_fn filter_fn, void *filter_data)
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 4d8dc6a..29183ef 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -142,11 +142,16 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 	case SND_SOC_REGMAP:
 		/* Device has made its own regmap arrangements */
 		codec->using_regmap = true;
-
-		ret = regmap_get_val_bytes(codec->control_data);
-		/* Errors are legitimate for non-integer byte multiples */
-		if (ret > 0)
-			codec->val_bytes = ret;
+		if (!codec->control_data)
+			codec->control_data = dev_get_regmap(codec->dev, NULL);
+
+		if (codec->control_data) {
+			ret = regmap_get_val_bytes(codec->control_data);
+			/* Errors are legitimate for non-integer byte
+			 * multiples */
+			if (ret > 0)
+				codec->val_bytes = ret;
+		}
 		break;
 
 	default:
diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c
new file mode 100644
index 0000000..c7c4b20
--- /dev/null
+++ b/sound/soc/spear/spdif_in.c
@@ -0,0 +1,297 @@
+/*
+ * ALSA SoC SPDIF In Audio Layer for spear processors
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Vipin Kumar <vipin.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/spear_dma.h>
+#include <sound/spear_spdif.h>
+#include "spdif_in_regs.h"
+
+struct spdif_in_params {
+	u32 format;
+};
+
+struct spdif_in_dev {
+	struct clk *clk;
+	struct spear_dma_data dma_params;
+	struct spdif_in_params saved_params;
+	void *io_base;
+	struct device *dev;
+	void (*reset_perip)(void);
+	int irq;
+};
+
+static void spdif_in_configure(struct spdif_in_dev *host)
+{
+	u32 ctrl = SPDIF_IN_PRTYEN | SPDIF_IN_STATEN | SPDIF_IN_USREN |
+		SPDIF_IN_VALEN | SPDIF_IN_BLKEN;
+	ctrl |= SPDIF_MODE_16BIT | SPDIF_FIFO_THRES_16;
+
+	writel(ctrl, host->io_base + SPDIF_IN_CTRL);
+	writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK);
+}
+
+static int spdif_in_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *cpu_dai)
+{
+	struct spdif_in_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
+
+	if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+		return -EINVAL;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&host->dma_params);
+	return 0;
+}
+
+static void spdif_in_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
+
+	if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+		return;
+
+	writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK);
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static void spdif_in_format(struct spdif_in_dev *host, u32 format)
+{
+	u32 ctrl = readl(host->io_base + SPDIF_IN_CTRL);
+
+	switch (format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		ctrl |= SPDIF_XTRACT_16BIT;
+		break;
+
+	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+		ctrl &= ~SPDIF_XTRACT_16BIT;
+		break;
+	}
+
+	writel(ctrl, host->io_base + SPDIF_IN_CTRL);
+}
+
+static int spdif_in_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
+	u32 format;
+
+	if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+		return -EINVAL;
+
+	format = params_format(params);
+	host->saved_params.format = format;
+
+	return 0;
+}
+
+static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
+	u32 ctrl;
+	int ret = 0;
+
+	if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+		return -EINVAL;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		clk_enable(host->clk);
+		spdif_in_configure(host);
+		spdif_in_format(host, host->saved_params.format);
+
+		ctrl = readl(host->io_base + SPDIF_IN_CTRL);
+		ctrl |= SPDIF_IN_SAMPLE | SPDIF_IN_ENB;
+		writel(ctrl, host->io_base + SPDIF_IN_CTRL);
+		writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ctrl = readl(host->io_base + SPDIF_IN_CTRL);
+		ctrl &= ~(SPDIF_IN_SAMPLE | SPDIF_IN_ENB);
+		writel(ctrl, host->io_base + SPDIF_IN_CTRL);
+		writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK);
+
+		if (host->reset_perip)
+			host->reset_perip();
+		clk_disable(host->clk);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static struct snd_soc_dai_ops spdif_in_dai_ops = {
+	.startup	= spdif_in_startup,
+	.shutdown	= spdif_in_shutdown,
+	.trigger	= spdif_in_trigger,
+	.hw_params	= spdif_in_hw_params,
+};
+
+struct snd_soc_dai_driver spdif_in_dai = {
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
+				 SNDRV_PCM_RATE_192000),
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | \
+			   SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+	},
+	.ops = &spdif_in_dai_ops,
+};
+
+static irqreturn_t spdif_in_irq(int irq, void *arg)
+{
+	struct spdif_in_dev *host = (struct spdif_in_dev *)arg;
+
+	u32 irq_status = readl(host->io_base + SPDIF_IN_IRQ);
+
+	if (!irq_status)
+		return IRQ_NONE;
+
+	if (irq_status & SPDIF_IRQ_FIFOWRITE)
+		dev_err(host->dev, "spdif in: fifo write error");
+	if (irq_status & SPDIF_IRQ_EMPTYFIFOREAD)
+		dev_err(host->dev, "spdif in: empty fifo read error");
+	if (irq_status & SPDIF_IRQ_FIFOFULL)
+		dev_err(host->dev, "spdif in: fifo full error");
+	if (irq_status & SPDIF_IRQ_OUTOFRANGE)
+		dev_err(host->dev, "spdif in: out of range error");
+
+	writel(0, host->io_base + SPDIF_IN_IRQ);
+
+	return IRQ_HANDLED;
+}
+
+static int spdif_in_probe(struct platform_device *pdev)
+{
+	struct spdif_in_dev *host;
+	struct spear_spdif_platform_data *pdata;
+	struct resource *res, *res_fifo;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	res_fifo = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!res_fifo)
+		return -EINVAL;
+
+	if (!devm_request_mem_region(&pdev->dev, res->start,
+				resource_size(res), pdev->name)) {
+		dev_warn(&pdev->dev, "Failed to get memory resourse\n");
+		return -ENOENT;
+	}
+
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+	if (!host) {
+		dev_warn(&pdev->dev, "kzalloc fail\n");
+		return -ENOMEM;
+	}
+
+	host->io_base = devm_ioremap(&pdev->dev, res->start,
+				resource_size(res));
+	if (!host->io_base) {
+		dev_warn(&pdev->dev, "ioremap failed\n");
+		return -ENOMEM;
+	}
+
+	host->irq = platform_get_irq(pdev, 0);
+	if (host->irq < 0)
+		return -EINVAL;
+
+	host->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(host->clk))
+		return PTR_ERR(host->clk);
+
+	pdata = dev_get_platdata(&pdev->dev);
+
+	if (!pdata)
+		return -EINVAL;
+
+	host->dma_params.data = pdata->dma_params;
+	host->dma_params.addr = res_fifo->start;
+	host->dma_params.max_burst = 16;
+	host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	host->dma_params.filter = pdata->filter;
+	host->reset_perip = pdata->reset_perip;
+
+	host->dev = &pdev->dev;
+	dev_set_drvdata(&pdev->dev, host);
+
+	ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0,
+			"spdif-in", host);
+	if (ret) {
+		clk_put(host->clk);
+		dev_warn(&pdev->dev, "request_irq failed\n");
+		return ret;
+	}
+
+	ret = snd_soc_register_dai(&pdev->dev, &spdif_in_dai);
+	if (ret != 0) {
+		clk_put(host->clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int spdif_in_remove(struct platform_device *pdev)
+{
+	struct spdif_in_dev *host = dev_get_drvdata(&pdev->dev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	clk_put(host->clk);
+
+	return 0;
+}
+
+
+static struct platform_driver spdif_in_driver = {
+	.probe		= spdif_in_probe,
+	.remove		= spdif_in_remove,
+	.driver		= {
+		.name	= "spdif-in",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(spdif_in_driver);
+
+MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>");
+MODULE_DESCRIPTION("SPEAr SPDIF IN SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:spdif_in");
diff --git a/sound/soc/spear/spdif_in_regs.h b/sound/soc/spear/spdif_in_regs.h
new file mode 100644
index 0000000..37af7bc
--- /dev/null
+++ b/sound/soc/spear/spdif_in_regs.h
@@ -0,0 +1,60 @@
+/*
+ * SPEAr SPDIF IN controller header file
+ *
+ * Copyright (ST) 2011 Vipin Kumar (vipin.kumar@st.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef SPDIF_IN_REGS_H
+#define SPDIF_IN_REGS_H
+
+#define SPDIF_IN_CTRL		0x00
+	#define SPDIF_IN_PRTYEN		(1 << 20)
+	#define SPDIF_IN_STATEN		(1 << 19)
+	#define SPDIF_IN_USREN		(1 << 18)
+	#define SPDIF_IN_VALEN		(1 << 17)
+	#define SPDIF_IN_BLKEN		(1 << 16)
+
+	#define SPDIF_MODE_24BIT	(8 << 12)
+	#define SPDIF_MODE_23BIT	(7 << 12)
+	#define SPDIF_MODE_22BIT	(6 << 12)
+	#define SPDIF_MODE_21BIT	(5 << 12)
+	#define SPDIF_MODE_20BIT	(4 << 12)
+	#define SPDIF_MODE_19BIT	(3 << 12)
+	#define SPDIF_MODE_18BIT	(2 << 12)
+	#define SPDIF_MODE_17BIT	(1 << 12)
+	#define SPDIF_MODE_16BIT	(0 << 12)
+	#define SPDIF_MODE_MASK		(0x0F << 12)
+
+	#define SPDIF_IN_VALID		(1 << 11)
+	#define SPDIF_IN_SAMPLE		(1 << 10)
+	#define SPDIF_DATA_SWAP		(1 << 9)
+	#define SPDIF_IN_ENB		(1 << 8)
+	#define SPDIF_DATA_REVERT	(1 << 7)
+	#define SPDIF_XTRACT_16BIT	(1 << 6)
+	#define SPDIF_FIFO_THRES_16	(16 << 0)
+
+#define SPDIF_IN_IRQ_MASK	0x04
+#define SPDIF_IN_IRQ		0x08
+	#define SPDIF_IRQ_FIFOWRITE	(1 << 0)
+	#define SPDIF_IRQ_EMPTYFIFOREAD	(1 << 1)
+	#define SPDIF_IRQ_FIFOFULL	(1 << 2)
+	#define SPDIF_IRQ_OUTOFRANGE	(1 << 3)
+
+#define SPDIF_IN_STA		0x0C
+	#define SPDIF_IN_LOCK		(0x1 << 0)
+
+#endif /* SPDIF_IN_REGS_H */
diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c
new file mode 100644
index 0000000..97c2cac
--- /dev/null
+++ b/sound/soc/spear/spear_pcm.c
@@ -0,0 +1,214 @@
+/*
+ * ALSA PCM interface for ST SPEAr Processors
+ *
+ * sound/soc/spear/spear_pcm.c
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/spear_dma.h>
+
+struct snd_pcm_hardware spear_pcm_hardware = {
+	.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+		 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.buffer_bytes_max = 16 * 1024, /* max buffer size */
+	.period_bytes_min = 2 * 1024, /* 1 msec data minimum period size */
+	.period_bytes_max = 2 * 1024, /* maximum period size */
+	.periods_min = 1, /* min # periods */
+	.periods_max = 8, /* max # of periods */
+	.fifo_size = 0, /* fifo size in bytes */
+};
+
+static int spear_pcm_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params)
+{
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static int spear_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+
+	return 0;
+}
+
+static int spear_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	struct spear_dma_data *dma_data = (struct spear_dma_data *)
+		snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+	int ret;
+
+	ret = snd_soc_set_runtime_hwparams(substream, &spear_pcm_hardware);
+	if (ret)
+		return ret;
+
+	ret = snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data);
+	if (ret)
+		return ret;
+
+	snd_dmaengine_pcm_set_data(substream, dma_data);
+
+	return 0;
+}
+
+static int spear_pcm_close(struct snd_pcm_substream *substream)
+{
+
+	snd_dmaengine_pcm_close(substream);
+
+	return 0;
+}
+
+static int spear_pcm_mmap(struct snd_pcm_substream *substream,
+		struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+			runtime->dma_area, runtime->dma_addr,
+			runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops spear_pcm_ops = {
+	.open		= spear_pcm_open,
+	.close		= spear_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= spear_pcm_hw_params,
+	.hw_free	= spear_pcm_hw_free,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer,
+	.mmap		= spear_pcm_mmap,
+};
+
+static int
+spear_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
+		size_t size)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+			&buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+
+	dev_info(buf->dev.dev,
+			" preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
+			(void *)buf->area, (void *)buf->addr, size);
+
+	buf->bytes = size;
+	return 0;
+}
+
+static void spear_pcm_free(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf && !buf->area)
+			continue;
+
+		dma_free_writecombine(pcm->card->dev, buf->bytes,
+				buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static u64 spear_pcm_dmamask = DMA_BIT_MASK(32);
+
+static int spear_pcm_new(struct snd_card *card,
+		struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+	int ret;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &spear_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	if (dai->driver->playback.channels_min) {
+		ret = spear_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_PLAYBACK,
+				spear_pcm_hardware.buffer_bytes_max);
+		if (ret)
+			return ret;
+	}
+
+	if (dai->driver->capture.channels_min) {
+		ret = spear_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_CAPTURE,
+				spear_pcm_hardware.buffer_bytes_max);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+struct snd_soc_platform_driver spear_soc_platform = {
+	.ops		=	&spear_pcm_ops,
+	.pcm_new	=	spear_pcm_new,
+	.pcm_free	=	spear_pcm_free,
+};
+
+static int __devinit spear_soc_platform_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_platform(&pdev->dev, &spear_soc_platform);
+}
+
+static int __devexit spear_soc_platform_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver spear_pcm_driver = {
+	.driver = {
+		.name = "spear-pcm-audio",
+		.owner = THIS_MODULE,
+	},
+
+	.probe = spear_soc_platform_probe,
+	.remove = __devexit_p(spear_soc_platform_remove),
+};
+
+module_platform_driver(spear_pcm_driver);
+
+MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
+MODULE_DESCRIPTION("SPEAr PCM DMA module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:spear-pcm-audio");
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index c1c8e95..76dc230 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -58,17 +58,9 @@ config SND_SOC_TEGRA_WM8753
 	  Say Y or M here if you want to add support for SoC audio on Tegra
 	  boards using the WM8753 codec, such as Whistler.
 
-config MACH_HAS_SND_SOC_TEGRA_WM8903
-	bool
-	help
-	  Machines that use the SND_SOC_TEGRA_WM8903 driver should select
-	  this config option, in order to allow the user to enable
-	  SND_SOC_TEGRA_WM8903.
-
 config SND_SOC_TEGRA_WM8903
 	tristate "SoC Audio support for Tegra boards using a WM8903 codec"
 	depends on SND_SOC_TEGRA && I2C
-	depends on MACH_HAS_SND_SOC_TEGRA_WM8903
 	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
 	select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
 	select SND_SOC_WM8903
@@ -79,7 +71,7 @@ config SND_SOC_TEGRA_WM8903
 
 config SND_SOC_TEGRA_TRIMSLICE
 	tristate "SoC Audio support for TrimSlice board"
-	depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C
+	depends on SND_SOC_TEGRA && I2C
 	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
 	select SND_SOC_TLV320AIC23
 	help
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 0c7af63..0832e8a 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -46,23 +46,11 @@
 
 #define DRV_NAME "tegra20-i2s"
 
-static inline void tegra20_i2s_write(struct tegra20_i2s *i2s, u32 reg, u32 val)
-{
-	regmap_write(i2s->regmap, reg, val);
-}
-
-static inline u32 tegra20_i2s_read(struct tegra20_i2s *i2s, u32 reg)
-{
-	u32 val;
-	regmap_read(i2s->regmap, reg, &val);
-	return val;
-}
-
 static int tegra20_i2s_runtime_suspend(struct device *dev)
 {
 	struct tegra20_i2s *i2s = dev_get_drvdata(dev);
 
-	clk_disable(i2s->clk_i2s);
+	clk_disable_unprepare(i2s->clk_i2s);
 
 	return 0;
 }
@@ -72,7 +60,7 @@ static int tegra20_i2s_runtime_resume(struct device *dev)
 	struct tegra20_i2s *i2s = dev_get_drvdata(dev);
 	int ret;
 
-	ret = clk_enable(i2s->clk_i2s);
+	ret = clk_prepare_enable(i2s->clk_i2s);
 	if (ret) {
 		dev_err(dev, "clk_enable failed: %d\n", ret);
 		return ret;
@@ -85,6 +73,7 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
 				unsigned int fmt)
 {
 	struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int mask, val;
 
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF:
@@ -93,10 +82,10 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
 		return -EINVAL;
 	}
 
-	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_MASTER_ENABLE;
+	mask = TEGRA20_I2S_CTRL_MASTER_ENABLE;
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
+		val = TEGRA20_I2S_CTRL_MASTER_ENABLE;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM:
 		break;
@@ -104,33 +93,35 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
 		return -EINVAL;
 	}
 
-	i2s->reg_ctrl &= ~(TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
-			   TEGRA20_I2S_CTRL_LRCK_MASK);
+	mask |= TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
+		TEGRA20_I2S_CTRL_LRCK_MASK;
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_DSP_A:
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+		val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
+		val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+		val |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
 		break;
 	case SND_SOC_DAIFMT_I2S:
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		val |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
+		val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
 		break;
 	case SND_SOC_DAIFMT_RIGHT_J:
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		val |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
+		val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		val |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
+		val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
+
 	return 0;
 }
 
@@ -138,29 +129,34 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct device *dev = substream->pcm->card->dev;
+	struct device *dev = dai->dev;
 	struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-	u32 reg;
+	unsigned int mask, val;
 	int ret, sample_size, srate, i2sclock, bitcnt;
 
-	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
+	mask = TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_16;
+		val = TEGRA20_I2S_CTRL_BIT_SIZE_16;
 		sample_size = 16;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_24;
+		val = TEGRA20_I2S_CTRL_BIT_SIZE_24;
 		sample_size = 24;
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
-		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_32;
+		val = TEGRA20_I2S_CTRL_BIT_SIZE_32;
 		sample_size = 32;
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	mask |= TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK;
+	val |= TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
+
+	regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
+
 	srate = params_rate(params);
 
 	/* Final "* 2" required by Tegra hardware */
@@ -175,42 +171,44 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
 	bitcnt = (i2sclock / (2 * srate)) - 1;
 	if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
 		return -EINVAL;
-	reg = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+	val = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
 
 	if (i2sclock % (2 * srate))
-		reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
+		val |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
 
-	tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg);
+	regmap_write(i2s->regmap, TEGRA20_I2S_TIMING, val);
 
-	tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR,
-		TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
-		TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
+	regmap_write(i2s->regmap, TEGRA20_I2S_FIFO_SCR,
+		     TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
+		     TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
 
 	return 0;
 }
 
 static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s)
 {
-	i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO1_ENABLE;
-	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+	regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+			   TEGRA20_I2S_CTRL_FIFO1_ENABLE,
+			   TEGRA20_I2S_CTRL_FIFO1_ENABLE);
 }
 
 static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s)
 {
-	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO1_ENABLE;
-	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+	regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+			   TEGRA20_I2S_CTRL_FIFO1_ENABLE, 0);
 }
 
 static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s)
 {
-	i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO2_ENABLE;
-	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+	regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+			   TEGRA20_I2S_CTRL_FIFO2_ENABLE,
+			   TEGRA20_I2S_CTRL_FIFO2_ENABLE);
 }
 
 static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s)
 {
-	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO2_ENABLE;
-	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+	regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+			   TEGRA20_I2S_CTRL_FIFO2_ENABLE, 0);
 }
 
 static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -261,12 +259,14 @@ static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
 static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
 	.probe = tegra20_i2s_probe,
 	.playback = {
+		.stream_name = "Playback",
 		.channels_min = 2,
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_8000_96000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
 	.capture = {
+		.stream_name = "Capture",
 		.channels_min = 2,
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_8000_96000,
@@ -412,8 +412,6 @@ static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
 	i2s->playback_dma_data.width = 32;
 	i2s->playback_dma_data.req_sel = dma_ch;
 
-	i2s->reg_ctrl = TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
-
 	pm_runtime_enable(&pdev->dev);
 	if (!pm_runtime_enabled(&pdev->dev)) {
 		ret = tegra20_i2s_runtime_resume(&pdev->dev);
diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h
index a57efc6..c27069d 100644
--- a/sound/soc/tegra/tegra20_i2s.h
+++ b/sound/soc/tegra/tegra20_i2s.h
@@ -158,7 +158,6 @@ struct tegra20_i2s {
 	struct tegra_pcm_dma_params capture_dma_data;
 	struct tegra_pcm_dma_params playback_dma_data;
 	struct regmap *regmap;
-	u32 reg_ctrl;
 };
 
 #endif
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index f9b5741..3ebc867 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -37,24 +37,11 @@
 
 #define DRV_NAME "tegra20-spdif"
 
-static inline void tegra20_spdif_write(struct tegra20_spdif *spdif, u32 reg,
-					u32 val)
-{
-	regmap_write(spdif->regmap, reg, val);
-}
-
-static inline u32 tegra20_spdif_read(struct tegra20_spdif *spdif, u32 reg)
-{
-	u32 val;
-	regmap_read(spdif->regmap, reg, &val);
-	return val;
-}
-
 static int tegra20_spdif_runtime_suspend(struct device *dev)
 {
 	struct tegra20_spdif *spdif = dev_get_drvdata(dev);
 
-	clk_disable(spdif->clk_spdif_out);
+	clk_disable_unprepare(spdif->clk_spdif_out);
 
 	return 0;
 }
@@ -64,7 +51,7 @@ static int tegra20_spdif_runtime_resume(struct device *dev)
 	struct tegra20_spdif *spdif = dev_get_drvdata(dev);
 	int ret;
 
-	ret = clk_enable(spdif->clk_spdif_out);
+	ret = clk_prepare_enable(spdif->clk_spdif_out);
 	if (ret) {
 		dev_err(dev, "clk_enable failed: %d\n", ret);
 		return ret;
@@ -77,21 +64,24 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct device *dev = substream->pcm->card->dev;
+	struct device *dev = dai->dev;
 	struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+	unsigned int mask, val;
 	int ret, spdifclock;
 
-	spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_PACK;
-	spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
+	mask = TEGRA20_SPDIF_CTRL_PACK |
+	       TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
-		spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_PACK;
-		spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT;
+		val = TEGRA20_SPDIF_CTRL_PACK |
+		      TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT;
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, mask, val);
+
 	switch (params_rate(params)) {
 	case 32000:
 		spdifclock = 4096000;
@@ -129,14 +119,15 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
 
 static void tegra20_spdif_start_playback(struct tegra20_spdif *spdif)
 {
-	spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_TX_EN;
-	tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+	regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL,
+			   TEGRA20_SPDIF_CTRL_TX_EN,
+			   TEGRA20_SPDIF_CTRL_TX_EN);
 }
 
 static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif)
 {
-	spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_TX_EN;
-	tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+	regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL,
+			   TEGRA20_SPDIF_CTRL_TX_EN, 0);
 }
 
 static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -181,6 +172,7 @@ static struct snd_soc_dai_driver tegra20_spdif_dai = {
 	.name = DRV_NAME,
 	.probe = tegra20_spdif_probe,
 	.playback = {
+		.stream_name = "Playback",
 		.channels_min = 2,
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h
index ed75652..b48d699 100644
--- a/sound/soc/tegra/tegra20_spdif.h
+++ b/sound/soc/tegra/tegra20_spdif.h
@@ -465,7 +465,6 @@ struct tegra20_spdif {
 	struct tegra_pcm_dma_params capture_dma_data;
 	struct tegra_pcm_dma_params playback_dma_data;
 	struct regmap *regmap;
-	u32 reg_ctrl;
 };
 
 #endif
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index f43edb3..bf56101 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -56,8 +56,8 @@ static int tegra30_ahub_runtime_suspend(struct device *dev)
 	regcache_cache_only(ahub->regmap_apbif, true);
 	regcache_cache_only(ahub->regmap_ahub, true);
 
-	clk_disable(ahub->clk_apbif);
-	clk_disable(ahub->clk_d_audio);
+	clk_disable_unprepare(ahub->clk_apbif);
+	clk_disable_unprepare(ahub->clk_d_audio);
 
 	return 0;
 }
@@ -77,12 +77,12 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
 {
 	int ret;
 
-	ret = clk_enable(ahub->clk_d_audio);
+	ret = clk_prepare_enable(ahub->clk_d_audio);
 	if (ret) {
 		dev_err(dev, "clk_enable d_audio failed: %d\n", ret);
 		return ret;
 	}
-	ret = clk_enable(ahub->clk_apbif);
+	ret = clk_prepare_enable(ahub->clk_apbif);
 	if (ret) {
 		dev_err(dev, "clk_enable apbif failed: %d\n", ret);
 		clk_disable(ahub->clk_d_audio);
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 8596032..4418422 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -44,25 +44,13 @@
 
 #define DRV_NAME "tegra30-i2s"
 
-static inline void tegra30_i2s_write(struct tegra30_i2s *i2s, u32 reg, u32 val)
-{
-	regmap_write(i2s->regmap, reg, val);
-}
-
-static inline u32 tegra30_i2s_read(struct tegra30_i2s *i2s, u32 reg)
-{
-	u32 val;
-	regmap_read(i2s->regmap, reg, &val);
-	return val;
-}
-
 static int tegra30_i2s_runtime_suspend(struct device *dev)
 {
 	struct tegra30_i2s *i2s = dev_get_drvdata(dev);
 
 	regcache_cache_only(i2s->regmap, true);
 
-	clk_disable(i2s->clk_i2s);
+	clk_disable_unprepare(i2s->clk_i2s);
 
 	return 0;
 }
@@ -72,7 +60,7 @@ static int tegra30_i2s_runtime_resume(struct device *dev)
 	struct tegra30_i2s *i2s = dev_get_drvdata(dev);
 	int ret;
 
-	ret = clk_enable(i2s->clk_i2s);
+	ret = clk_prepare_enable(i2s->clk_i2s);
 	if (ret) {
 		dev_err(dev, "clk_enable failed: %d\n", ret);
 		return ret;
@@ -128,6 +116,7 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
 				unsigned int fmt)
 {
 	struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int mask, val;
 
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF:
@@ -136,10 +125,10 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
 		return -EINVAL;
 	}
 
-	i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_MASTER_ENABLE;
+	mask = TEGRA30_I2S_CTRL_MASTER_ENABLE;
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
+		val = TEGRA30_I2S_CTRL_MASTER_ENABLE;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM:
 		break;
@@ -147,33 +136,37 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
 		return -EINVAL;
 	}
 
-	i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK |
-			   TEGRA30_I2S_CTRL_LRCK_MASK);
+	mask |= TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK |
+		TEGRA30_I2S_CTRL_LRCK_MASK;
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_DSP_A:
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+		val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
+		val |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW;
+		val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
+		val |= TEGRA30_I2S_CTRL_LRCK_R_LOW;
 		break;
 	case SND_SOC_DAIFMT_I2S:
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+		val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+		val |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
 		break;
 	case SND_SOC_DAIFMT_RIGHT_J:
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+		val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+		val |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+		val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+		val |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	pm_runtime_get_sync(dai->dev);
+	regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val);
+	pm_runtime_put(dai->dev);
+
 	return 0;
 }
 
@@ -181,24 +174,26 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct device *dev = substream->pcm->card->dev;
+	struct device *dev = dai->dev;
 	struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-	u32 val;
+	unsigned int mask, val, reg;
 	int ret, sample_size, srate, i2sclock, bitcnt;
 
 	if (params_channels(params) != 2)
 		return -EINVAL;
 
-	i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK;
+	mask = TEGRA30_I2S_CTRL_BIT_SIZE_MASK;
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
-		i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16;
+		val = TEGRA30_I2S_CTRL_BIT_SIZE_16;
 		sample_size = 16;
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val);
+
 	srate = params_rate(params);
 
 	/* Final "* 2" required by Tegra hardware */
@@ -219,7 +214,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
 	if (i2sclock % (2 * srate))
 		val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE;
 
-	tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val);
+	regmap_write(i2s->regmap, TEGRA30_I2S_TIMING, val);
 
 	val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
 	      (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
@@ -229,15 +224,17 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
-		tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val);
+		reg = TEGRA30_I2S_CIF_RX_CTRL;
 	} else {
 		val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
-		tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val);
+		reg = TEGRA30_I2S_CIF_RX_CTRL;
 	}
 
+	regmap_write(i2s->regmap, reg, val);
+
 	val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) |
 	      (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT);
-	tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val);
+	regmap_write(i2s->regmap, TEGRA30_I2S_OFFSET, val);
 
 	return 0;
 }
@@ -245,29 +242,31 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
 static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s)
 {
 	tegra30_ahub_enable_tx_fifo(i2s->playback_fifo_cif);
-	i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX;
-	tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+	regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL,
+			   TEGRA30_I2S_CTRL_XFER_EN_TX,
+			   TEGRA30_I2S_CTRL_XFER_EN_TX);
 }
 
 static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s)
 {
 	tegra30_ahub_disable_tx_fifo(i2s->playback_fifo_cif);
-	i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX;
-	tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+	regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL,
+			   TEGRA30_I2S_CTRL_XFER_EN_TX, 0);
 }
 
 static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s)
 {
 	tegra30_ahub_enable_rx_fifo(i2s->capture_fifo_cif);
-	i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX;
-	tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+	regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL,
+			   TEGRA30_I2S_CTRL_XFER_EN_RX,
+			   TEGRA30_I2S_CTRL_XFER_EN_RX);
 }
 
 static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s)
 {
 	tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif);
-	i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX;
-	tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+	regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL,
+			   TEGRA30_I2S_CTRL_XFER_EN_RX, 0);
 }
 
 static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -320,12 +319,14 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
 static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
 	.probe = tegra30_i2s_probe,
 	.playback = {
+		.stream_name = "Playback",
 		.channels_min = 2,
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_8000_96000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
 	.capture = {
+		.stream_name = "Capture",
 		.channels_min = 2,
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_8000_96000,
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h
index 91adf29..34dc47b 100644
--- a/sound/soc/tegra/tegra30_i2s.h
+++ b/sound/soc/tegra/tegra30_i2s.h
@@ -236,7 +236,6 @@ struct tegra30_i2s {
 	enum tegra30_ahub_txcif playback_fifo_cif;
 	struct tegra_pcm_dma_params playback_dma_data;
 	struct regmap *regmap;
-	u32 reg_ctrl;
 };
 
 #endif
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index 32de700..d684df2 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -1,5 +1,5 @@
 /*
- * tegra_alc5632.c  --  Toshiba AC100(PAZ00) machine ASoC driver
+* tegra_alc5632.c  --  Toshiba AC100(PAZ00) machine ASoC driver
  *
  * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
  * Copyright (C) 2012 - NVIDIA, Inc.
@@ -33,11 +33,8 @@
 
 #define DRV_NAME "tegra-alc5632"
 
-#define GPIO_HP_DET     BIT(0)
-
 struct tegra_alc5632 {
 	struct tegra_asoc_utils_data util_data;
-	int gpio_requested;
 	int gpio_hp_det;
 };
 
@@ -46,7 +43,7 @@ static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = codec_dai->codec;
 	struct snd_soc_card *card = codec->card;
 	struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card);
 	int srate, mclk;
@@ -108,9 +105,9 @@ static const struct snd_kcontrol_new tegra_alc5632_controls[] = {
 
 static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_codec *codec = codec_dai->codec;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
-	struct device_node *np = codec->card->dev->of_node;
 	struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(codec->card);
 
 	snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
@@ -119,14 +116,11 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
 			ARRAY_SIZE(tegra_alc5632_hs_jack_pins),
 			tegra_alc5632_hs_jack_pins);
 
-	machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
-
 	if (gpio_is_valid(machine->gpio_hp_det)) {
 		tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det;
 		snd_soc_jack_add_gpios(&tegra_alc5632_hs_jack,
 						1,
 						&tegra_alc5632_hp_jack_gpio);
-		machine->gpio_requested |= GPIO_HP_DET;
 	}
 
 	snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
@@ -159,6 +153,7 @@ static struct snd_soc_card snd_soc_tegra_alc5632 = {
 
 static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
 	struct snd_soc_card *card = &snd_soc_tegra_alc5632;
 	struct tegra_alc5632 *alc5632;
 	int ret;
@@ -181,6 +176,10 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
 		goto err;
 	}
 
+	alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+	if (alc5632->gpio_hp_det == -ENODEV)
+		return -EPROBE_DEFER;
+
 	ret = snd_soc_of_parse_card_name(card, "nvidia,model");
 	if (ret)
 		goto err;
@@ -199,16 +198,16 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	tegra_alc5632_dai.cpu_dai_of_node = of_parse_phandle(
+	tegra_alc5632_dai.cpu_of_node = of_parse_phandle(
 			pdev->dev.of_node, "nvidia,i2s-controller", 0);
-	if (!tegra_alc5632_dai.cpu_dai_of_node) {
+	if (!tegra_alc5632_dai.cpu_of_node) {
 		dev_err(&pdev->dev,
 		"Property 'nvidia,i2s-controller' missing or invalid\n");
 		ret = -EINVAL;
 		goto err;
 	}
 
-	tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_dai_of_node;
+	tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_of_node;
 
 	ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
 	if (ret)
@@ -234,11 +233,8 @@ static int __devexit tegra_alc5632_remove(struct platform_device *pdev)
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
 	struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card);
 
-	if (machine->gpio_requested & GPIO_HP_DET)
-		snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack,
-					1,
-					&tegra_alc5632_hp_jack_gpio);
-	machine->gpio_requested = 0;
+	snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1,
+				&tegra_alc5632_hp_jack_gpio);
 
 	snd_soc_unregister_card(card);
 
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index 9515ce5..6872c77 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -69,9 +69,9 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
 	data->set_baseclock = 0;
 	data->set_mclk = 0;
 
-	clk_disable(data->clk_cdev1);
-	clk_disable(data->clk_pll_a_out0);
-	clk_disable(data->clk_pll_a);
+	clk_disable_unprepare(data->clk_cdev1);
+	clk_disable_unprepare(data->clk_pll_a_out0);
+	clk_disable_unprepare(data->clk_pll_a);
 
 	err = clk_set_rate(data->clk_pll_a, new_baseclock);
 	if (err) {
@@ -87,19 +87,19 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
 
 	/* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
 
-	err = clk_enable(data->clk_pll_a);
+	err = clk_prepare_enable(data->clk_pll_a);
 	if (err) {
 		dev_err(data->dev, "Can't enable pll_a: %d\n", err);
 		return err;
 	}
 
-	err = clk_enable(data->clk_pll_a_out0);
+	err = clk_prepare_enable(data->clk_pll_a_out0);
 	if (err) {
 		dev_err(data->dev, "Can't enable pll_a_out0: %d\n", err);
 		return err;
 	}
 
-	err = clk_enable(data->clk_cdev1);
+	err = clk_prepare_enable(data->clk_cdev1);
 	if (err) {
 		dev_err(data->dev, "Can't enable cdev1: %d\n", err);
 		return err;
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
index 4e77026..ea9166d 100644
--- a/sound/soc/tegra/tegra_wm8753.c
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -57,7 +57,7 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = codec_dai->codec;
 	struct snd_soc_card *card = codec->card;
 	struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
 	int srate, mclk;
@@ -157,9 +157,9 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	tegra_wm8753_dai.cpu_dai_of_node = of_parse_phandle(
+	tegra_wm8753_dai.cpu_of_node = of_parse_phandle(
 			pdev->dev.of_node, "nvidia,i2s-controller", 0);
-	if (!tegra_wm8753_dai.cpu_dai_of_node) {
+	if (!tegra_wm8753_dai.cpu_of_node) {
 		dev_err(&pdev->dev,
 			"Property 'nvidia,i2s-controller' missing or invalid\n");
 		ret = -EINVAL;
@@ -167,7 +167,7 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev)
 	}
 
 	tegra_wm8753_dai.platform_of_node =
-				tegra_wm8753_dai.cpu_dai_of_node;
+				tegra_wm8753_dai.cpu_of_node;
 
 	ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
 	if (ret)
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 3b6da91..0c5bb33 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -28,8 +28,6 @@
  *
  */
 
-#include <asm/mach-types.h>
-
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -50,16 +48,9 @@
 
 #define DRV_NAME "tegra-snd-wm8903"
 
-#define GPIO_SPKR_EN    BIT(0)
-#define GPIO_HP_MUTE    BIT(1)
-#define GPIO_INT_MIC_EN BIT(2)
-#define GPIO_EXT_MIC_EN BIT(3)
-#define GPIO_HP_DET     BIT(4)
-
 struct tegra_wm8903 {
 	struct tegra_wm8903_platform_data pdata;
 	struct tegra_asoc_utils_data util_data;
-	int gpio_requested;
 };
 
 static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
@@ -67,8 +58,7 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = codec_dai->codec;
 	struct snd_soc_card *card = codec->card;
 	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
 	int srate, mclk;
@@ -95,24 +85,6 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
 		return err;
 	}
 
-	err = snd_soc_dai_set_fmt(codec_dai,
-					SND_SOC_DAIFMT_I2S |
-					SND_SOC_DAIFMT_NB_NF |
-					SND_SOC_DAIFMT_CBS_CFS);
-	if (err < 0) {
-		dev_err(card->dev, "codec_dai fmt not set\n");
-		return err;
-	}
-
-	err = snd_soc_dai_set_fmt(cpu_dai,
-					SND_SOC_DAIFMT_I2S |
-					SND_SOC_DAIFMT_NB_NF |
-					SND_SOC_DAIFMT_CBS_CFS);
-	if (err < 0) {
-		dev_err(card->dev, "cpu_dai fmt not set\n");
-		return err;
-	}
-
 	err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
 					SND_SOC_CLOCK_IN);
 	if (err < 0) {
@@ -160,7 +132,7 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
 	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
 	struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-	if (!(machine->gpio_requested & GPIO_SPKR_EN))
+	if (!gpio_is_valid(pdata->gpio_spkr_en))
 		return 0;
 
 	gpio_set_value_cansleep(pdata->gpio_spkr_en,
@@ -177,7 +149,7 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
 	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
 	struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-	if (!(machine->gpio_requested & GPIO_HP_MUTE))
+	if (!gpio_is_valid(pdata->gpio_hp_mute))
 		return 0;
 
 	gpio_set_value_cansleep(pdata->gpio_hp_mute,
@@ -203,122 +175,18 @@ static const struct snd_soc_dapm_route harmony_audio_map[] = {
 	{"IN1L", NULL, "Mic Jack"},
 };
 
-static const struct snd_soc_dapm_route seaboard_audio_map[] = {
-	{"Headphone Jack", NULL, "HPOUTR"},
-	{"Headphone Jack", NULL, "HPOUTL"},
-	{"Int Spk", NULL, "ROP"},
-	{"Int Spk", NULL, "RON"},
-	{"Int Spk", NULL, "LOP"},
-	{"Int Spk", NULL, "LON"},
-	{"Mic Jack", NULL, "MICBIAS"},
-	{"IN1R", NULL, "Mic Jack"},
-};
-
-static const struct snd_soc_dapm_route kaen_audio_map[] = {
-	{"Headphone Jack", NULL, "HPOUTR"},
-	{"Headphone Jack", NULL, "HPOUTL"},
-	{"Int Spk", NULL, "ROP"},
-	{"Int Spk", NULL, "RON"},
-	{"Int Spk", NULL, "LOP"},
-	{"Int Spk", NULL, "LON"},
-	{"Mic Jack", NULL, "MICBIAS"},
-	{"IN2R", NULL, "Mic Jack"},
-};
-
-static const struct snd_soc_dapm_route aebl_audio_map[] = {
-	{"Headphone Jack", NULL, "HPOUTR"},
-	{"Headphone Jack", NULL, "HPOUTL"},
-	{"Int Spk", NULL, "LINEOUTR"},
-	{"Int Spk", NULL, "LINEOUTL"},
-	{"Mic Jack", NULL, "MICBIAS"},
-	{"IN1R", NULL, "Mic Jack"},
-};
-
 static const struct snd_kcontrol_new tegra_wm8903_controls[] = {
 	SOC_DAPM_PIN_SWITCH("Int Spk"),
 };
 
 static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_codec *codec = codec_dai->codec;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct snd_soc_card *card = codec->card;
 	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
 	struct tegra_wm8903_platform_data *pdata = &machine->pdata;
-	struct device_node *np = card->dev->of_node;
-	int ret;
-
-	if (card->dev->platform_data) {
-		memcpy(pdata, card->dev->platform_data, sizeof(*pdata));
-	} else if (np) {
-		/*
-		 * This part must be in init() rather than probe() in order to
-		 * guarantee that the WM8903 has been probed, and hence its
-		 * GPIO controller registered, which is a pre-condition for
-		 * of_get_named_gpio() to be able to map the phandles in the
-		 * properties to the controller node. Given this, all
-		 * pdata handling is in init() for consistency.
-		 */
-		pdata->gpio_spkr_en = of_get_named_gpio(np,
-						"nvidia,spkr-en-gpios", 0);
-		pdata->gpio_hp_mute = of_get_named_gpio(np,
-						"nvidia,hp-mute-gpios", 0);
-		pdata->gpio_hp_det = of_get_named_gpio(np,
-						"nvidia,hp-det-gpios", 0);
-		pdata->gpio_int_mic_en = of_get_named_gpio(np,
-						"nvidia,int-mic-en-gpios", 0);
-		pdata->gpio_ext_mic_en = of_get_named_gpio(np,
-						"nvidia,ext-mic-en-gpios", 0);
-	} else {
-		dev_err(card->dev, "No platform data supplied\n");
-		return -EINVAL;
-	}
-
-	if (gpio_is_valid(pdata->gpio_spkr_en)) {
-		ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
-		if (ret) {
-			dev_err(card->dev, "cannot get spkr_en gpio\n");
-			return ret;
-		}
-		machine->gpio_requested |= GPIO_SPKR_EN;
-
-		gpio_direction_output(pdata->gpio_spkr_en, 0);
-	}
-
-	if (gpio_is_valid(pdata->gpio_hp_mute)) {
-		ret = gpio_request(pdata->gpio_hp_mute, "hp_mute");
-		if (ret) {
-			dev_err(card->dev, "cannot get hp_mute gpio\n");
-			return ret;
-		}
-		machine->gpio_requested |= GPIO_HP_MUTE;
-
-		gpio_direction_output(pdata->gpio_hp_mute, 1);
-	}
-
-	if (gpio_is_valid(pdata->gpio_int_mic_en)) {
-		ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en");
-		if (ret) {
-			dev_err(card->dev, "cannot get int_mic_en gpio\n");
-			return ret;
-		}
-		machine->gpio_requested |= GPIO_INT_MIC_EN;
-
-		/* Disable int mic; enable signal is active-high */
-		gpio_direction_output(pdata->gpio_int_mic_en, 0);
-	}
-
-	if (gpio_is_valid(pdata->gpio_ext_mic_en)) {
-		ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en");
-		if (ret) {
-			dev_err(card->dev, "cannot get ext_mic_en gpio\n");
-			return ret;
-		}
-		machine->gpio_requested |= GPIO_EXT_MIC_EN;
-
-		/* Enable ext mic; enable signal is active-low */
-		gpio_direction_output(pdata->gpio_ext_mic_en, 0);
-	}
 
 	if (gpio_is_valid(pdata->gpio_hp_det)) {
 		tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det;
@@ -330,7 +198,6 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
 		snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
 					1,
 					&tegra_wm8903_hp_jack_gpio);
-		machine->gpio_requested |= GPIO_HP_DET;
 	}
 
 	snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
@@ -366,6 +233,9 @@ static struct snd_soc_dai_link tegra_wm8903_dai = {
 	.codec_dai_name = "wm8903-hifi",
 	.init = tegra_wm8903_init,
 	.ops = &tegra_wm8903_ops,
+	.dai_fmt = SND_SOC_DAIFMT_I2S |
+		   SND_SOC_DAIFMT_NB_NF |
+		   SND_SOC_DAIFMT_CBS_CFS,
 };
 
 static struct snd_soc_card snd_soc_tegra_wm8903 = {
@@ -385,8 +255,10 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = {
 
 static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
 	struct snd_soc_card *card = &snd_soc_tegra_wm8903;
 	struct tegra_wm8903 *machine;
+	struct tegra_wm8903_platform_data *pdata;
 	int ret;
 
 	if (!pdev->dev.platform_data && !pdev->dev.of_node) {
@@ -401,12 +273,42 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
 		ret = -ENOMEM;
 		goto err;
 	}
+	pdata = &machine->pdata;
 
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 	snd_soc_card_set_drvdata(card, machine);
 
-	if (pdev->dev.of_node) {
+	if (pdev->dev.platform_data) {
+		memcpy(pdata, card->dev->platform_data, sizeof(*pdata));
+	} else if (np) {
+		pdata->gpio_spkr_en = of_get_named_gpio(np,
+						"nvidia,spkr-en-gpios", 0);
+		if (pdata->gpio_spkr_en == -ENODEV)
+			return -EPROBE_DEFER;
+
+		pdata->gpio_hp_mute = of_get_named_gpio(np,
+						"nvidia,hp-mute-gpios", 0);
+		if (pdata->gpio_hp_mute == -ENODEV)
+			return -EPROBE_DEFER;
+
+		pdata->gpio_hp_det = of_get_named_gpio(np,
+						"nvidia,hp-det-gpios", 0);
+		if (pdata->gpio_hp_det == -ENODEV)
+			return -EPROBE_DEFER;
+
+		pdata->gpio_int_mic_en = of_get_named_gpio(np,
+						"nvidia,int-mic-en-gpios", 0);
+		if (pdata->gpio_int_mic_en == -ENODEV)
+			return -EPROBE_DEFER;
+
+		pdata->gpio_ext_mic_en = of_get_named_gpio(np,
+						"nvidia,ext-mic-en-gpios", 0);
+		if (pdata->gpio_ext_mic_en == -ENODEV)
+			return -EPROBE_DEFER;
+	}
+
+	if (np) {
 		ret = snd_soc_of_parse_card_name(card, "nvidia,model");
 		if (ret)
 			goto err;
@@ -417,8 +319,8 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
 			goto err;
 
 		tegra_wm8903_dai.codec_name = NULL;
-		tegra_wm8903_dai.codec_of_node = of_parse_phandle(
-				pdev->dev.of_node, "nvidia,audio-codec", 0);
+		tegra_wm8903_dai.codec_of_node = of_parse_phandle(np,
+				"nvidia,audio-codec", 0);
 		if (!tegra_wm8903_dai.codec_of_node) {
 			dev_err(&pdev->dev,
 				"Property 'nvidia,audio-codec' missing or invalid\n");
@@ -427,9 +329,9 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
 		}
 
 		tegra_wm8903_dai.cpu_dai_name = NULL;
-		tegra_wm8903_dai.cpu_dai_of_node = of_parse_phandle(
-				pdev->dev.of_node, "nvidia,i2s-controller", 0);
-		if (!tegra_wm8903_dai.cpu_dai_of_node) {
+		tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np,
+				"nvidia,i2s-controller", 0);
+		if (!tegra_wm8903_dai.cpu_of_node) {
 			dev_err(&pdev->dev,
 				"Property 'nvidia,i2s-controller' missing or invalid\n");
 			ret = -EINVAL;
@@ -438,20 +340,47 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
 
 		tegra_wm8903_dai.platform_name = NULL;
 		tegra_wm8903_dai.platform_of_node =
-					tegra_wm8903_dai.cpu_dai_of_node;
+					tegra_wm8903_dai.cpu_of_node;
 	} else {
-		if (machine_is_harmony()) {
-			card->dapm_routes = harmony_audio_map;
-			card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
-		} else if (machine_is_seaboard()) {
-			card->dapm_routes = seaboard_audio_map;
-			card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map);
-		} else if (machine_is_kaen()) {
-			card->dapm_routes = kaen_audio_map;
-			card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map);
-		} else {
-			card->dapm_routes = aebl_audio_map;
-			card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map);
+		card->dapm_routes = harmony_audio_map;
+		card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
+	}
+
+	if (gpio_is_valid(pdata->gpio_spkr_en)) {
+		ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_spkr_en,
+					    GPIOF_OUT_INIT_LOW, "spkr_en");
+		if (ret) {
+			dev_err(card->dev, "cannot get spkr_en gpio\n");
+			return ret;
+		}
+	}
+
+	if (gpio_is_valid(pdata->gpio_hp_mute)) {
+		ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_hp_mute,
+					    GPIOF_OUT_INIT_HIGH, "hp_mute");
+		if (ret) {
+			dev_err(card->dev, "cannot get hp_mute gpio\n");
+			return ret;
+		}
+	}
+
+	if (gpio_is_valid(pdata->gpio_int_mic_en)) {
+		/* Disable int mic; enable signal is active-high */
+		ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_int_mic_en,
+					    GPIOF_OUT_INIT_LOW, "int_mic_en");
+		if (ret) {
+			dev_err(card->dev, "cannot get int_mic_en gpio\n");
+			return ret;
+		}
+	}
+
+	if (gpio_is_valid(pdata->gpio_ext_mic_en)) {
+		/* Enable ext mic; enable signal is active-low */
+		ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_ext_mic_en,
+					    GPIOF_OUT_INIT_LOW, "ext_mic_en");
+		if (ret) {
+			dev_err(card->dev, "cannot get ext_mic_en gpio\n");
+			return ret;
 		}
 	}
 
@@ -478,21 +407,9 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
 	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-	struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-	if (machine->gpio_requested & GPIO_HP_DET)
-		snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack,
-					1,
-					&tegra_wm8903_hp_jack_gpio);
-	if (machine->gpio_requested & GPIO_EXT_MIC_EN)
-		gpio_free(pdata->gpio_ext_mic_en);
-	if (machine->gpio_requested & GPIO_INT_MIC_EN)
-		gpio_free(pdata->gpio_int_mic_en);
-	if (machine->gpio_requested & GPIO_HP_MUTE)
-		gpio_free(pdata->gpio_hp_mute);
-	if (machine->gpio_requested & GPIO_SPKR_EN)
-		gpio_free(pdata->gpio_spkr_en);
-	machine->gpio_requested = 0;
+	snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1,
+				&tegra_wm8903_hp_jack_gpio);
 
 	snd_soc_unregister_card(card);
 
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
index 4a8d5b6..e69a4f7 100644
--- a/sound/soc/tegra/trimslice.c
+++ b/sound/soc/tegra/trimslice.c
@@ -52,8 +52,7 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = codec_dai->codec;
 	struct snd_soc_card *card = codec->card;
 	struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card);
 	int srate, mclk;
@@ -68,24 +67,6 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream,
 		return err;
 	}
 
-	err = snd_soc_dai_set_fmt(codec_dai,
-					SND_SOC_DAIFMT_I2S |
-					SND_SOC_DAIFMT_NB_NF |
-					SND_SOC_DAIFMT_CBS_CFS);
-	if (err < 0) {
-		dev_err(card->dev, "codec_dai fmt not set\n");
-		return err;
-	}
-
-	err = snd_soc_dai_set_fmt(cpu_dai,
-					SND_SOC_DAIFMT_I2S |
-					SND_SOC_DAIFMT_NB_NF |
-					SND_SOC_DAIFMT_CBS_CFS);
-	if (err < 0) {
-		dev_err(card->dev, "cpu_dai fmt not set\n");
-		return err;
-	}
-
 	err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
 					SND_SOC_CLOCK_IN);
 	if (err < 0) {
@@ -121,6 +102,9 @@ static struct snd_soc_dai_link trimslice_tlv320aic23_dai = {
 	.cpu_dai_name = "tegra20-i2s.0",
 	.codec_dai_name = "tlv320aic23-hifi",
 	.ops = &trimslice_asoc_ops,
+	.dai_fmt = SND_SOC_DAIFMT_I2S |
+		   SND_SOC_DAIFMT_NB_NF |
+		   SND_SOC_DAIFMT_CBS_CFS,
 };
 
 static struct snd_soc_card snd_soc_trimslice = {
@@ -162,9 +146,9 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
 		}
 
 		trimslice_tlv320aic23_dai.cpu_dai_name = NULL;
-		trimslice_tlv320aic23_dai.cpu_dai_of_node = of_parse_phandle(
+		trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle(
 				pdev->dev.of_node, "nvidia,i2s-controller", 0);
-		if (!trimslice_tlv320aic23_dai.cpu_dai_of_node) {
+		if (!trimslice_tlv320aic23_dai.cpu_of_node) {
 			dev_err(&pdev->dev,
 				"Property 'nvidia,i2s-controller' missing or invalid\n");
 			ret = -EINVAL;
@@ -173,7 +157,7 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
 
 		trimslice_tlv320aic23_dai.platform_name = NULL;
 		trimslice_tlv320aic23_dai.platform_of_node =
-				trimslice_tlv320aic23_dai.cpu_dai_of_node;
+				trimslice_tlv320aic23_dai.cpu_of_node;
 	}
 
 	ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig
index 44cf434..069330d 100644
--- a/sound/soc/ux500/Kconfig
+++ b/sound/soc/ux500/Kconfig
@@ -12,3 +12,21 @@ menuconfig SND_SOC_UX500
 config SND_SOC_UX500_PLAT_MSP_I2S
 	tristate
 	depends on SND_SOC_UX500
+
+config SND_SOC_UX500_PLAT_DMA
+	tristate "Platform - DB8500 (DMA)"
+	depends on SND_SOC_UX500
+	select SND_SOC_DMAENGINE_PCM
+	help
+		Say Y if you want to enable the Ux500 platform-driver.
+
++config SND_SOC_UX500_MACH_MOP500
++	tristate "Machine - MOP500 (Ux500 + AB8500)"
+	depends on AB8500_CORE && AB8500_GPADC && SND_SOC_UX500
+	select SND_SOC_AB8500_CODEC
+	select SND_SOC_UX500_PLAT_MSP_I2S
+	select SND_SOC_UX500_PLAT_DMA
+	help
+		Select this to enable the MOP500 machine-driver.
+		This will enable platform-drivers for: Ux500
+		This will enable codec-drivers for: AB8500
diff --git a/sound/soc/ux500/Makefile b/sound/soc/ux500/Makefile
index 19974c5..cce0c11 100644
--- a/sound/soc/ux500/Makefile
+++ b/sound/soc/ux500/Makefile
@@ -2,3 +2,9 @@
 
 snd-soc-ux500-plat-msp-i2s-objs := ux500_msp_dai.o ux500_msp_i2s.o
 obj-$(CONFIG_SND_SOC_UX500_PLAT_MSP_I2S) += snd-soc-ux500-plat-msp-i2s.o
+
+snd-soc-ux500-plat-dma-objs := ux500_pcm.o
+obj-$(CONFIG_SND_SOC_UX500_PLAT_DMA) += snd-soc-ux500-plat-dma.o
+
+snd-soc-ux500-mach-mop500-objs := mop500.o mop500_ab8500.o
+obj-$(CONFIG_SND_SOC_UX500_MACH_MOP500) += snd-soc-ux500-mach-mop500.o
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
new file mode 100644
index 0000000..31c4d26
--- /dev/null
+++ b/sound/soc/ux500/mop500.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja (ola.o.lilja@stericsson.com)
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can 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 <asm/mach-types.h>
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include "ux500_pcm.h"
+#include "ux500_msp_dai.h"
+
+#include <mop500_ab8500.h>
+
+/* Define the whole MOP500 soundcard, linking platform to the codec-drivers  */
+struct snd_soc_dai_link mop500_dai_links[] = {
+	{
+		.name = "ab8500_0",
+		.stream_name = "ab8500_0",
+		.cpu_dai_name = "ux500-msp-i2s.1",
+		.codec_dai_name = "ab8500-codec-dai.0",
+		.platform_name = "ux500-pcm.0",
+		.codec_name = "ab8500-codec.0",
+		.init = mop500_ab8500_machine_init,
+		.ops = mop500_ab8500_ops,
+	},
+	{
+		.name = "ab8500_1",
+		.stream_name = "ab8500_1",
+		.cpu_dai_name = "ux500-msp-i2s.3",
+		.codec_dai_name = "ab8500-codec-dai.1",
+		.platform_name = "ux500-pcm.0",
+		.codec_name = "ab8500-codec.0",
+		.init = NULL,
+		.ops = mop500_ab8500_ops,
+	},
+};
+
+static struct snd_soc_card mop500_card = {
+	.name = "MOP500-card",
+	.probe = NULL,
+	.dai_link = mop500_dai_links,
+	.num_links = ARRAY_SIZE(mop500_dai_links),
+};
+
+static int __devinit mop500_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	pr_debug("%s: Enter.\n", __func__);
+
+	dev_dbg(&pdev->dev, "%s: Enter.\n", __func__);
+
+	mop500_card.dev = &pdev->dev;
+
+	dev_dbg(&pdev->dev, "%s: Card %s: Set platform drvdata.\n",
+		__func__, mop500_card.name);
+	platform_set_drvdata(pdev, &mop500_card);
+
+	snd_soc_card_set_drvdata(&mop500_card, NULL);
+
+	dev_dbg(&pdev->dev, "%s: Card %s: num_links = %d\n",
+		__func__, mop500_card.name, mop500_card.num_links);
+	dev_dbg(&pdev->dev, "%s: Card %s: DAI-link 0: name = %s\n",
+		__func__, mop500_card.name, mop500_card.dai_link[0].name);
+	dev_dbg(&pdev->dev, "%s: Card %s: DAI-link 0: stream_name = %s\n",
+		__func__, mop500_card.name,
+		mop500_card.dai_link[0].stream_name);
+
+	ret = snd_soc_register_card(&mop500_card);
+	if (ret)
+		dev_err(&pdev->dev,
+			"Error: snd_soc_register_card failed (%d)!\n",
+			ret);
+
+	return ret;
+}
+
+static int __devexit mop500_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *mop500_card = platform_get_drvdata(pdev);
+
+	pr_debug("%s: Enter.\n", __func__);
+
+	snd_soc_unregister_card(mop500_card);
+	mop500_ab8500_remove(mop500_card);
+	
+	return 0;
+}
+
+static struct platform_driver snd_soc_mop500_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "snd-soc-mop500",
+	},
+	.probe = mop500_probe,
+	.remove = __devexit_p(mop500_remove),
+};
+
+module_platform_driver(snd_soc_mop500_driver);
diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c
new file mode 100644
index 0000000..78cce23
--- /dev/null
+++ b/sound/soc/ux500/mop500_ab8500.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can 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/device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <mach/hardware.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "ux500_pcm.h"
+#include "ux500_msp_dai.h"
+#include "../codecs/ab8500-codec.h"
+
+#define TX_SLOT_MONO	0x0008
+#define TX_SLOT_STEREO	0x000a
+#define RX_SLOT_MONO	0x0001
+#define RX_SLOT_STEREO	0x0003
+#define TX_SLOT_8CH	0x00FF
+#define RX_SLOT_8CH	0x00FF
+
+#define DEF_TX_SLOTS	TX_SLOT_STEREO
+#define DEF_RX_SLOTS	RX_SLOT_MONO
+
+#define DRIVERMODE_NORMAL	0
+#define DRIVERMODE_CODEC_ONLY	1
+
+/* Slot configuration */
+static unsigned int tx_slots = DEF_TX_SLOTS;
+static unsigned int rx_slots = DEF_RX_SLOTS;
+
+/* Clocks */
+static const char * const enum_mclk[] = {
+	"SYSCLK",
+	"ULPCLK"
+};
+enum mclk {
+	MCLK_SYSCLK,
+	MCLK_ULPCLK,
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_mclk, enum_mclk);
+
+/* Private data for machine-part MOP500<->AB8500 */
+struct mop500_ab8500_drvdata {
+	/* Clocks */
+	enum mclk mclk_sel;
+	struct clk *clk_ptr_intclk;
+	struct clk *clk_ptr_sysclk;
+	struct clk *clk_ptr_ulpclk;
+};
+
+static inline const char *get_mclk_str(enum mclk mclk_sel)
+{
+	switch (mclk_sel) {
+	case MCLK_SYSCLK:
+		return "SYSCLK";
+	case MCLK_ULPCLK:
+		return "ULPCLK";
+	default:
+		return "Unknown";
+	}
+}
+
+static int mop500_ab8500_set_mclk(struct device *dev,
+				struct mop500_ab8500_drvdata *drvdata)
+{
+	int status;
+	struct clk *clk_ptr;
+
+	if (IS_ERR(drvdata->clk_ptr_intclk)) {
+		dev_err(dev,
+			"%s: ERROR: intclk not initialized!\n", __func__);
+		return -EIO;
+	}
+
+	switch (drvdata->mclk_sel) {
+	case MCLK_SYSCLK:
+		clk_ptr = drvdata->clk_ptr_sysclk;
+		break;
+	case MCLK_ULPCLK:
+		clk_ptr = drvdata->clk_ptr_ulpclk;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (IS_ERR(clk_ptr)) {
+		dev_err(dev, "%s: ERROR: %s not initialized!\n", __func__,
+			get_mclk_str(drvdata->mclk_sel));
+		return -EIO;
+	}
+
+	status = clk_set_parent(drvdata->clk_ptr_intclk, clk_ptr);
+	if (status)
+		dev_err(dev,
+			"%s: ERROR: Setting intclk parent to %s failed (ret = %d)!",
+			__func__, get_mclk_str(drvdata->mclk_sel), status);
+	else
+		dev_dbg(dev,
+			"%s: intclk parent changed to %s.\n",
+			__func__, get_mclk_str(drvdata->mclk_sel));
+
+	return status;
+}
+
+/*
+ * Control-events
+ */
+
+static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct mop500_ab8500_drvdata *drvdata =
+				snd_soc_card_get_drvdata(codec->card);
+
+	ucontrol->value.enumerated.item[0] = drvdata->mclk_sel;
+
+	return 0;
+}
+
+static int mclk_input_control_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct mop500_ab8500_drvdata *drvdata =
+				snd_soc_card_get_drvdata(codec->card);
+	unsigned int val = ucontrol->value.enumerated.item[0];
+
+	if (val > (unsigned int)MCLK_ULPCLK)
+		return -EINVAL;
+	if (drvdata->mclk_sel == val)
+		return 0;
+
+	drvdata->mclk_sel = val;
+
+	return 1;
+}
+
+/*
+ * Controls
+ */
+
+static struct snd_kcontrol_new mop500_ab8500_ctrls[] = {
+	SOC_ENUM_EXT("Master Clock Select",
+		soc_enum_mclk,
+		mclk_input_control_get, mclk_input_control_put),
+	/* Digital interface - Clocks */
+	SOC_SINGLE("Digital Interface Master Generator Switch",
+		AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENMASTGEN,
+		1, 0),
+	SOC_SINGLE("Digital Interface 0 Bit-clock Switch",
+		AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENFSBITCLK0,
+		1, 0),
+	SOC_SINGLE("Digital Interface 1 Bit-clock Switch",
+		AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENFSBITCLK1,
+		1, 0),
+	SOC_DAPM_PIN_SWITCH("Headset Left"),
+	SOC_DAPM_PIN_SWITCH("Headset Right"),
+	SOC_DAPM_PIN_SWITCH("Earpiece"),
+	SOC_DAPM_PIN_SWITCH("Speaker Left"),
+	SOC_DAPM_PIN_SWITCH("Speaker Right"),
+	SOC_DAPM_PIN_SWITCH("LineOut Left"),
+	SOC_DAPM_PIN_SWITCH("LineOut Right"),
+	SOC_DAPM_PIN_SWITCH("Vibra 1"),
+	SOC_DAPM_PIN_SWITCH("Vibra 2"),
+	SOC_DAPM_PIN_SWITCH("Mic 1"),
+	SOC_DAPM_PIN_SWITCH("Mic 2"),
+	SOC_DAPM_PIN_SWITCH("LineIn Left"),
+	SOC_DAPM_PIN_SWITCH("LineIn Right"),
+	SOC_DAPM_PIN_SWITCH("DMic 1"),
+	SOC_DAPM_PIN_SWITCH("DMic 2"),
+	SOC_DAPM_PIN_SWITCH("DMic 3"),
+	SOC_DAPM_PIN_SWITCH("DMic 4"),
+	SOC_DAPM_PIN_SWITCH("DMic 5"),
+	SOC_DAPM_PIN_SWITCH("DMic 6"),
+};
+
+/* ASoC */
+
+int mop500_ab8500_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	/* Set audio-clock source */
+	return mop500_ab8500_set_mclk(rtd->card->dev,
+				snd_soc_card_get_drvdata(rtd->card));
+}
+
+void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct device *dev = rtd->card->dev;
+
+	dev_dbg(dev, "%s: Enter\n", __func__);
+
+	/* Reset slots configuration to default(s) */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		tx_slots = DEF_TX_SLOTS;
+	else
+		rx_slots = DEF_RX_SLOTS;
+}
+
+int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct device *dev = rtd->card->dev;
+	unsigned int fmt;
+	int channels, ret = 0, driver_mode, slots;
+	unsigned int sw_codec, sw_cpu;
+	bool is_playback;
+
+	dev_dbg(dev, "%s: Enter\n", __func__);
+
+	dev_dbg(dev, "%s: substream->pcm->name = %s\n"
+		"substream->pcm->id = %s.\n"
+		"substream->name = %s.\n"
+		"substream->number = %d.\n",
+		__func__,
+		substream->pcm->name,
+		substream->pcm->id,
+		substream->name,
+		substream->number);
+
+	channels = params_channels(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S32_LE:
+		sw_cpu = 32;
+		break;
+
+	case SNDRV_PCM_FORMAT_S16_LE:
+		sw_cpu = 16;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Setup codec depending on driver-mode */
+	if (channels == 8)
+		driver_mode = DRIVERMODE_CODEC_ONLY;
+	else
+		driver_mode = DRIVERMODE_NORMAL;
+	dev_dbg(dev, "%s: Driver-mode: %s.\n", __func__,
+		(driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY");
+
+	/* Setup format */
+
+	if (driver_mode == DRIVERMODE_NORMAL) {
+		fmt = SND_SOC_DAIFMT_DSP_A |
+			SND_SOC_DAIFMT_CBM_CFM |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CONT;
+	} else {
+		fmt = SND_SOC_DAIFMT_DSP_A |
+			SND_SOC_DAIFMT_CBM_CFM |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_GATED;
+	}
+
+	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+	if (ret < 0) {
+		dev_err(dev,
+			"%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n",
+			__func__, ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+	if (ret < 0) {
+		dev_err(dev,
+			"%s: ERROR: snd_soc_dai_set_fmt failed for cpu_dai (ret = %d)!\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/* Setup TDM-slots */
+
+	is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+	switch (channels) {
+	case 1:
+		slots = 16;
+		tx_slots = (is_playback) ? TX_SLOT_MONO : 0;
+		rx_slots = (is_playback) ? 0 : RX_SLOT_MONO;
+		break;
+	case 2:
+		slots = 16;
+		tx_slots = (is_playback) ? TX_SLOT_STEREO : 0;
+		rx_slots = (is_playback) ? 0 : RX_SLOT_STEREO;
+		break;
+	case 8:
+		slots = 16;
+		tx_slots = (is_playback) ? TX_SLOT_8CH : 0;
+		rx_slots = (is_playback) ? 0 : RX_SLOT_8CH;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (driver_mode == DRIVERMODE_NORMAL)
+		sw_codec = sw_cpu;
+	else
+		sw_codec = 20;
+
+	dev_dbg(dev, "%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
+		tx_slots, rx_slots);
+	ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots,
+				sw_cpu);
+	if (ret)
+		return ret;
+
+	dev_dbg(dev, "%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
+		tx_slots, rx_slots);
+	ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots,
+				sw_codec);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct snd_soc_ops mop500_ab8500_ops[] = {
+	{
+		.hw_params = mop500_ab8500_hw_params,
+		.startup = mop500_ab8500_startup,
+		.shutdown = mop500_ab8500_shutdown,
+	}
+};
+
+int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct device *dev = rtd->card->dev;
+	struct mop500_ab8500_drvdata *drvdata;
+	int ret;
+
+	dev_dbg(dev, "%s Enter.\n", __func__);
+
+	/* Create driver private-data struct */
+	drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata),
+			GFP_KERNEL);
+	snd_soc_card_set_drvdata(rtd->card, drvdata);
+
+	/* Setup clocks */
+
+	drvdata->clk_ptr_sysclk = clk_get(dev, "sysclk");
+	if (IS_ERR(drvdata->clk_ptr_sysclk))
+		dev_warn(dev, "%s: WARNING: clk_get failed for 'sysclk'!\n",
+			__func__);
+	drvdata->clk_ptr_ulpclk = clk_get(dev, "ulpclk");
+	if (IS_ERR(drvdata->clk_ptr_ulpclk))
+		dev_warn(dev, "%s: WARNING: clk_get failed for 'ulpclk'!\n",
+			__func__);
+	drvdata->clk_ptr_intclk = clk_get(dev, "intclk");
+	if (IS_ERR(drvdata->clk_ptr_intclk))
+		dev_warn(dev, "%s: WARNING: clk_get failed for 'intclk'!\n",
+			__func__);
+
+	/* Set intclk default parent to ulpclk */
+	drvdata->mclk_sel = MCLK_ULPCLK;
+	ret = mop500_ab8500_set_mclk(dev, drvdata);
+	if (ret < 0)
+		dev_warn(dev, "%s: WARNING: mop500_ab8500_set_mclk!\n",
+			__func__);
+
+	drvdata->mclk_sel = MCLK_ULPCLK;
+
+	/* Add controls */
+	ret = snd_soc_add_codec_controls(codec, mop500_ab8500_ctrls,
+			ARRAY_SIZE(mop500_ab8500_ctrls));
+	if (ret < 0) {
+		pr_err("%s: Failed to add machine-controls (%d)!\n",
+				__func__, ret);
+		return ret;
+	}
+
+	ret = snd_soc_dapm_disable_pin(&codec->dapm, "Earpiece");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Speaker Left");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Speaker Right");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineOut Left");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineOut Right");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Vibra 1");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Vibra 2");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Mic 1");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Mic 2");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineIn Left");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineIn Right");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 1");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 2");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 3");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 4");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 5");
+	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 6");
+
+	return ret;
+}
+
+void mop500_ab8500_remove(struct snd_soc_card *card)
+{
+	struct mop500_ab8500_drvdata *drvdata = snd_soc_card_get_drvdata(card);
+
+	if (drvdata->clk_ptr_sysclk != NULL)
+		clk_put(drvdata->clk_ptr_sysclk);
+	if (drvdata->clk_ptr_ulpclk != NULL)
+		clk_put(drvdata->clk_ptr_ulpclk);
+	if (drvdata->clk_ptr_intclk != NULL)
+		clk_put(drvdata->clk_ptr_intclk);
+
+	snd_soc_card_set_drvdata(card, drvdata);
+}
diff --git a/sound/soc/ux500/mop500_ab8500.h b/sound/soc/ux500/mop500_ab8500.h
new file mode 100644
index 0000000..cca5b33
--- /dev/null
+++ b/sound/soc/ux500/mop500_ab8500.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can 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 MOP500_AB8500_H
+#define MOP500_AB8500_H
+
+extern struct snd_soc_ops mop500_ab8500_ops[];
+
+int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *runtime);
+void mop500_ab8500_remove(struct snd_soc_card *card);
+
+#endif
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index 93c6c40..62ac028 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -840,4 +840,4 @@ static struct platform_driver msp_i2s_driver = {
 };
 module_platform_driver(msp_i2s_driver);
 
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
index 496dec1..ee14d2d 100644
--- a/sound/soc/ux500/ux500_msp_i2s.c
+++ b/sound/soc/ux500/ux500_msp_i2s.c
@@ -739,4 +739,4 @@ void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
 	devm_kfree(&pdev->dev, msp);
 }
 
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c
new file mode 100644
index 0000000..1a04e24
--- /dev/null
+++ b/sound/soc/ux500/ux500_pcm.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can 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 <asm/page.h>
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/slab.h>
+
+#include <plat/ste_dma40.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "ux500_msp_i2s.h"
+#include "ux500_pcm.h"
+
+static struct snd_pcm_hardware ux500_pcm_hw_playback = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_RESUME |
+		SNDRV_PCM_INFO_PAUSE,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE |
+		SNDRV_PCM_FMTBIT_U16_LE |
+		SNDRV_PCM_FMTBIT_S16_BE |
+		SNDRV_PCM_FMTBIT_U16_BE,
+	.rates = SNDRV_PCM_RATE_KNOT,
+	.rate_min = UX500_PLATFORM_MIN_RATE_PLAYBACK,
+	.rate_max = UX500_PLATFORM_MAX_RATE_PLAYBACK,
+	.channels_min = UX500_PLATFORM_MIN_CHANNELS,
+	.channels_max = UX500_PLATFORM_MAX_CHANNELS,
+	.buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
+	.period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
+	.period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
+	.periods_min = UX500_PLATFORM_PERIODS_MIN,
+	.periods_max = UX500_PLATFORM_PERIODS_MAX,
+};
+
+static struct snd_pcm_hardware ux500_pcm_hw_capture = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_RESUME |
+		SNDRV_PCM_INFO_PAUSE,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE |
+		SNDRV_PCM_FMTBIT_U16_LE |
+		SNDRV_PCM_FMTBIT_S16_BE |
+		SNDRV_PCM_FMTBIT_U16_BE,
+	.rates = SNDRV_PCM_RATE_KNOT,
+	.rate_min = UX500_PLATFORM_MIN_RATE_CAPTURE,
+	.rate_max = UX500_PLATFORM_MAX_RATE_CAPTURE,
+	.channels_min = UX500_PLATFORM_MIN_CHANNELS,
+	.channels_max = UX500_PLATFORM_MAX_CHANNELS,
+	.buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
+	.period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
+	.period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
+	.periods_min = UX500_PLATFORM_PERIODS_MIN,
+	.periods_max = UX500_PLATFORM_PERIODS_MAX,
+};
+
+static void ux500_pcm_dma_hw_free(struct device *dev,
+				struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dma_buffer *buf = runtime->dma_buffer_p;
+
+	if (runtime->dma_area == NULL)
+		return;
+
+	if (buf != &substream->dma_buffer) {
+		dma_free_coherent(buf->dev.dev, buf->bytes, buf->area,
+				buf->addr);
+		kfree(runtime->dma_buffer_p);
+	}
+
+	snd_pcm_set_runtime_buffer(substream, NULL);
+}
+
+static int ux500_pcm_open(struct snd_pcm_substream *substream)
+{
+	int stream_id = substream->pstr->stream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *dai = rtd->cpu_dai;
+	struct device *dev = dai->dev;
+	int ret;
+	struct ux500_msp_dma_params *dma_params;
+	u16 per_data_width, mem_data_width;
+	struct stedma40_chan_cfg *dma_cfg;
+
+	dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
+		snd_pcm_stream_str(substream));
+
+	dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__);
+	if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_soc_set_runtime_hwparams(substream,
+					&ux500_pcm_hw_playback);
+	else
+		snd_soc_set_runtime_hwparams(substream,
+					&ux500_pcm_hw_capture);
+
+	/* ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0) {
+		dev_err(dev, "%s: Error: snd_pcm_hw_constraints failed (%d)\n",
+			__func__, ret);
+		return ret;
+	}
+
+	dev_dbg(dev, "%s: Set hw-struct for %s.\n", __func__,
+		snd_pcm_stream_str(substream));
+	runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ?
+		ux500_pcm_hw_playback : ux500_pcm_hw_capture;
+
+	mem_data_width = STEDMA40_HALFWORD_WIDTH;
+
+	dma_params = snd_soc_dai_get_dma_data(dai, substream);
+	switch (dma_params->data_size) {
+	case 32:
+		per_data_width = STEDMA40_WORD_WIDTH;
+		break;
+	case 16:
+		per_data_width = STEDMA40_HALFWORD_WIDTH;
+		break;
+	case 8:
+		per_data_width = STEDMA40_BYTE_WIDTH;
+		break;
+	default:
+		per_data_width = STEDMA40_WORD_WIDTH;
+		dev_warn(rtd->platform->dev,
+			"%s: Unknown data-size (%d)! Assuming 32 bits.\n",
+			__func__, dma_params->data_size);
+	}
+
+	dma_cfg = dma_params->dma_cfg;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		dma_cfg->src_info.data_width = mem_data_width;
+		dma_cfg->dst_info.data_width = per_data_width;
+	} else {
+		dma_cfg->src_info.data_width = per_data_width;
+		dma_cfg->dst_info.data_width = mem_data_width;
+	}
+
+
+	ret = snd_dmaengine_pcm_open(substream, stedma40_filter, dma_cfg);
+	if (ret) {
+		dev_dbg(dai->dev,
+			"%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n",
+			__func__, ret);
+		return ret;
+	}
+
+	snd_dmaengine_pcm_set_data(substream, dma_cfg);
+
+	return 0;
+}
+
+static int ux500_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *dai = rtd->cpu_dai;
+
+	dev_dbg(dai->dev, "%s: Enter\n", __func__);
+
+	snd_dmaengine_pcm_close(substream);
+
+	return 0;
+}
+
+static int ux500_pcm_hw_params(struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dma_buffer *buf = runtime->dma_buffer_p;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	int ret = 0;
+	int size;
+
+	dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
+
+	size = params_buffer_bytes(hw_params);
+
+	if (buf) {
+		if (buf->bytes >= size)
+			goto out;
+		ux500_pcm_dma_hw_free(NULL, substream);
+	}
+
+	if (substream->dma_buffer.area != NULL &&
+		substream->dma_buffer.bytes >= size) {
+		buf = &substream->dma_buffer;
+	} else {
+		buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
+		if (!buf)
+			goto nomem;
+
+		buf->dev.type = SNDRV_DMA_TYPE_DEV;
+		buf->dev.dev = NULL;
+		buf->area = dma_alloc_coherent(NULL, size, &buf->addr,
+					GFP_KERNEL);
+		buf->bytes = size;
+		buf->private_data = NULL;
+
+		if (!buf->area)
+			goto free;
+	}
+	snd_pcm_set_runtime_buffer(substream, buf);
+	ret = 1;
+ out:
+	runtime->dma_bytes = size;
+	return ret;
+
+ free:
+	kfree(buf);
+ nomem:
+	return -ENOMEM;
+}
+
+static int ux500_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
+
+	ux500_pcm_dma_hw_free(NULL, substream);
+
+	return 0;
+}
+
+static int ux500_pcm_mmap(struct snd_pcm_substream *substream,
+			struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	dev_dbg(rtd->platform->dev, "%s: Enter.\n", __func__);
+
+	return dma_mmap_coherent(NULL, vma, runtime->dma_area,
+				runtime->dma_addr, runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops ux500_pcm_ops = {
+	.open		= ux500_pcm_open,
+	.close		= ux500_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= ux500_pcm_hw_params,
+	.hw_free	= ux500_pcm_hw_free,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer_no_residue,
+	.mmap		= ux500_pcm_mmap
+};
+
+int ux500_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+
+	dev_dbg(rtd->platform->dev, "%s: Enter (id = '%s').\n", __func__,
+		pcm->id);
+
+	pcm->info_flags = 0;
+
+	return 0;
+}
+
+static struct snd_soc_platform_driver ux500_pcm_soc_drv = {
+	.ops		= &ux500_pcm_ops,
+	.pcm_new        = ux500_pcm_new,
+};
+
+static int __devexit ux500_pcm_drv_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv);
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"%s: ERROR: Failed to register platform '%s' (%d)!\n",
+			__func__, pdev->name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devinit ux500_pcm_drv_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver ux500_pcm_driver = {
+	.driver = {
+		.name = "ux500-pcm",
+		.owner = THIS_MODULE,
+	},
+
+	.probe = ux500_pcm_drv_probe,
+	.remove = __devexit_p(ux500_pcm_drv_remove),
+};
+module_platform_driver(ux500_pcm_driver);
+
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h
new file mode 100644
index 0000000..77ed44d
--- /dev/null
+++ b/sound/soc/ux500/ux500_pcm.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can 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 UX500_PCM_H
+#define UX500_PCM_H
+
+#include <asm/page.h>
+
+#include <linux/workqueue.h>
+
+#define UX500_PLATFORM_MIN_RATE_PLAYBACK 8000
+#define UX500_PLATFORM_MAX_RATE_PLAYBACK 48000
+#define UX500_PLATFORM_MIN_RATE_CAPTURE	8000
+#define UX500_PLATFORM_MAX_RATE_CAPTURE	48000
+
+#define UX500_PLATFORM_MIN_CHANNELS 1
+#define UX500_PLATFORM_MAX_CHANNELS 8
+
+#define UX500_PLATFORM_PERIODS_BYTES_MIN	128
+#define UX500_PLATFORM_PERIODS_BYTES_MAX	(64 * PAGE_SIZE)
+#define UX500_PLATFORM_PERIODS_MIN		2
+#define UX500_PLATFORM_PERIODS_MAX		48
+#define UX500_PLATFORM_BUFFER_BYTES_MAX		(2048 * PAGE_SIZE)
+
+#endif
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index 41daaa2..e71fe55 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -341,6 +341,14 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
 		.map = audigy2nx_map,
 		.selector_map = audigy2nx_selectors,
 	},
+	{	/* Logitech, Inc. QuickCam Pro for Notebooks */
+		.id = USB_ID(0x046d, 0x0991),
+		.ignore_ctl_error = 1,
+	},
+	{	/* Logitech, Inc. QuickCam E 3500 */
+		.id = USB_ID(0x046d, 0x09a4),
+		.ignore_ctl_error = 1,
+	},
 	{
 		/* Hercules DJ Console (Windows Edition) */
 		.id = USB_ID(0x06f8, 0xb000),
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 41f4b69..690000d 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -42,6 +42,13 @@
 
 extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
 
+struct std_mono_table {
+	unsigned int unitid, control, cmask;
+	int val_type;
+	const char *name;
+	snd_kcontrol_tlv_rw_t *tlv_callback;
+};
+
 /* private_free callback */
 static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 {
@@ -114,6 +121,25 @@ static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
 }
 
 /*
+ * Create a set of standard UAC controls from a table
+ */
+static int snd_create_std_mono_table(struct usb_mixer_interface *mixer,
+				struct std_mono_table *t)
+{
+	int err;
+
+	while (t->name != NULL) {
+		err = snd_create_std_mono_ctl(mixer, t->unitid, t->control,
+				t->cmask, t->val_type, t->name, t->tlv_callback);
+		if (err < 0)
+			return err;
+		t++;
+	}
+
+	return 0;
+}
+
+/*
  * Sound Blaster remote control configuration
  *
  * format of remote control data:
@@ -916,61 +942,6 @@ static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer)
 	return 0;
 }
 
-
-/*
- * Create mixer for Electrix Ebox-44
- *
- * The mixer units from this device are corrupt, and even where they
- * are valid they presents mono controls as L and R channels of
- * stereo. So we create a good mixer in code.
- */
-
-static int snd_ebox44_create_mixer(struct usb_mixer_interface *mixer)
-{
-	int err;
-
-	err = snd_create_std_mono_ctl(mixer, 4, 1, 0x0, USB_MIXER_INV_BOOLEAN,
-				"Headphone Playback Switch", NULL);
-	if (err < 0)
-		return err;
-	err = snd_create_std_mono_ctl(mixer, 4, 2, 0x1, USB_MIXER_S16,
-				"Headphone A Mix Playback Volume", NULL);
-	if (err < 0)
-		return err;
-	err = snd_create_std_mono_ctl(mixer, 4, 2, 0x2, USB_MIXER_S16,
-				"Headphone B Mix Playback Volume", NULL);
-	if (err < 0)
-		return err;
-
-	err = snd_create_std_mono_ctl(mixer, 7, 1, 0x0, USB_MIXER_INV_BOOLEAN,
-				"Output Playback Switch", NULL);
-	if (err < 0)
-		return err;
-	err = snd_create_std_mono_ctl(mixer, 7, 2, 0x1, USB_MIXER_S16,
-				"Output A Playback Volume", NULL);
-	if (err < 0)
-		return err;
-	err = snd_create_std_mono_ctl(mixer, 7, 2, 0x2, USB_MIXER_S16,
-				"Output B Playback Volume", NULL);
-	if (err < 0)
-		return err;
-
-	err = snd_create_std_mono_ctl(mixer, 10, 1, 0x0, USB_MIXER_INV_BOOLEAN,
-				"Input Capture Switch", NULL);
-	if (err < 0)
-		return err;
-	err = snd_create_std_mono_ctl(mixer, 10, 2, 0x1, USB_MIXER_S16,
-				"Input A Capture Volume", NULL);
-	if (err < 0)
-		return err;
-	err = snd_create_std_mono_ctl(mixer, 10, 2, 0x2, USB_MIXER_S16,
-				"Input B Capture Volume", NULL);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
 void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
 			       unsigned char samplerate_id)
 {
@@ -990,6 +961,81 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
 	}
 }
 
+/*
+ * The mixer units for Ebox-44 are corrupt, and even where they
+ * are valid they presents mono controls as L and R channels of
+ * stereo. So we provide a good mixer here.
+ */
+struct std_mono_table ebox44_table[] = {
+	{
+		.unitid = 4,
+		.control = 1,
+		.cmask = 0x0,
+		.val_type = USB_MIXER_INV_BOOLEAN,
+		.name = "Headphone Playback Switch"
+	},
+	{
+		.unitid = 4,
+		.control = 2,
+		.cmask = 0x1,
+		.val_type = USB_MIXER_S16,
+		.name = "Headphone A Mix Playback Volume"
+	},
+	{
+		.unitid = 4,
+		.control = 2,
+		.cmask = 0x2,
+		.val_type = USB_MIXER_S16,
+		.name = "Headphone B Mix Playback Volume"
+	},
+
+	{
+		.unitid = 7,
+		.control = 1,
+		.cmask = 0x0,
+		.val_type = USB_MIXER_INV_BOOLEAN,
+		.name = "Output Playback Switch"
+	},
+	{
+		.unitid = 7,
+		.control = 2,
+		.cmask = 0x1,
+		.val_type = USB_MIXER_S16,
+		.name = "Output A Playback Volume"
+	},
+	{
+		.unitid = 7,
+		.control = 2,
+		.cmask = 0x2,
+		.val_type = USB_MIXER_S16,
+		.name = "Output B Playback Volume"
+	},
+
+	{
+		.unitid = 10,
+		.control = 1,
+		.cmask = 0x0,
+		.val_type = USB_MIXER_INV_BOOLEAN,
+		.name = "Input Capture Switch"
+	},
+	{
+		.unitid = 10,
+		.control = 2,
+		.cmask = 0x1,
+		.val_type = USB_MIXER_S16,
+		.name = "Input A Capture Volume"
+	},
+	{
+		.unitid = 10,
+		.control = 2,
+		.cmask = 0x2,
+		.val_type = USB_MIXER_S16,
+		.name = "Input B Capture Volume"
+	},
+
+	{}
+};
+
 int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 {
 	int err = 0;
@@ -1035,7 +1081,8 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 		break;
 
 	case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */
-		err = snd_ebox44_create_mixer(mixer);
+		/* detection is disabled in mixer_maps.c */
+		err = snd_create_std_mono_table(mixer, ebox44_table);
 		break;
 	}
 
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index d89ab4c..79780fa 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -1831,6 +1831,36 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 		}
 	}
 },
+{
+	USB_DEVICE(0x0582, 0x014d),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		/* .vendor_name = "BOSS", */
+		/* .product_name = "GT-100", */
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 3,
+				.type = QUIRK_MIDI_FIXED_ENDPOINT,
+				.data = & (const struct snd_usb_midi_endpoint_info) {
+					.out_cables = 0x0001,
+					.in_cables  = 0x0001
+				}
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
 
 /* Guillemot devices */
 {
diff --git a/tools/kvm/.gitignore b/tools/kvm/.gitignore
new file mode 100644
index 0000000..60dd6db
--- /dev/null
+++ b/tools/kvm/.gitignore
@@ -0,0 +1,12 @@
+/lkvm
+/vm
+*.o
+*.d
+.cscope
+tags
+include/common-cmds.h
+tests/boot/boot_test.iso
+tests/boot/rootfs/
+guest/init
+guest/init_stage2
+KVMTOOLS-VERSION-FILE
diff --git a/tools/kvm/CREDITS-Git b/tools/kvm/CREDITS-Git
new file mode 100644
index 0000000..c2ddcb3
--- /dev/null
+++ b/tools/kvm/CREDITS-Git
@@ -0,0 +1,30 @@
+Most of the infrastructure that 'perf' uses here has been reused
+from the Git project, as of version:
+
+    66996ec: Sync with 1.6.2.4
+
+Here is an (incomplete!) list of main contributors to those files
+in util/* and elsewhere:
+
+ Alex Riesen
+ Christian Couder
+ Dmitry Potapov
+ Jeff King
+ Johannes Schindelin
+ Johannes Sixt
+ Junio C Hamano
+ Linus Torvalds
+ Matthias Kestenholz
+ Michal Ostrowski
+ Miklos Vajna
+ Petr Baudis
+ Pierre Habouzit
+ René Scharfe
+ Samuel Tardieu
+ Shawn O. Pearce
+ Steffen Prohaska
+ Steve Haslam
+
+Thanks guys!
+
+The full history of the files can be found in the upstream Git commits.
diff --git a/tools/kvm/Documentation/kernel-debugging.txt b/tools/kvm/Documentation/kernel-debugging.txt
new file mode 100644
index 0000000..98b9438
--- /dev/null
+++ b/tools/kvm/Documentation/kernel-debugging.txt
@@ -0,0 +1,15 @@
+This document explains how to debug a guests' kernel using KGDB.
+
+1. Run the guest:
+        'lkvm run -k [vmlinuz] -p "kgdboc=ttyS1 kgdbwait" --tty 1'
+
+And see which PTY got assigned to ttyS1 (you'll see:
+'  Info: Assigned terminal 1 to pty /dev/pts/X').
+
+2. Run GDB on the host:
+        'gdb [vmlinuz]'
+
+3. Connect to the guest (from within GDB):
+        'target remote /dev/pty/X'
+
+4. Start debugging! (enter 'continue' to continue boot).
diff --git a/tools/kvm/Documentation/kvm-balloon.txt b/tools/kvm/Documentation/kvm-balloon.txt
new file mode 100644
index 0000000..efc0a87
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-balloon.txt
@@ -0,0 +1,24 @@
+lkvm-balloon(1)
+================
+
+NAME
+----
+lkvm-balloon - Inflate or deflate the virtio balloon
+
+SYNOPSIS
+--------
+[verse]
+'lkvm balloon [command] [size] [instance]'
+
+DESCRIPTION
+-----------
+The command inflates or deflates the virtio balloon located in the
+specified instance.
+For a list of running instances see 'lkvm list'.
+
+Command can be either 'inflate' or 'deflate'. Inflate increases the
+size of the balloon, thus decreasing the amount of virtual RAM available
+for the guest. Deflation returns previously inflated memory back to the
+guest.
+
+size is specified in Mb.
diff --git a/tools/kvm/Documentation/kvm-debug.txt b/tools/kvm/Documentation/kvm-debug.txt
new file mode 100644
index 0000000..a8eb2c0
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-debug.txt
@@ -0,0 +1,16 @@
+lkvm-debug(1)
+================
+
+NAME
+----
+lkvm-debug - Print debug information from a running instance
+
+SYNOPSIS
+--------
+[verse]
+'lkvm debug [instance]'
+
+DESCRIPTION
+-----------
+The command prints debug information from a running instance.
+For a list of running instances see 'lkvm list'.
diff --git a/tools/kvm/Documentation/kvm-list.txt b/tools/kvm/Documentation/kvm-list.txt
new file mode 100644
index 0000000..a245607
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-list.txt
@@ -0,0 +1,16 @@
+lkvm-list(1)
+================
+
+NAME
+----
+lkvm-list - Print a list of running instances on the host.
+
+SYNOPSIS
+--------
+[verse]
+'lkvm list'
+
+DESCRIPTION
+-----------
+This command prints a list of running instances on the host which
+belong to the user who currently ran 'lkvm list'.
diff --git a/tools/kvm/Documentation/kvm-pause.txt b/tools/kvm/Documentation/kvm-pause.txt
new file mode 100644
index 0000000..1ea2a23
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-pause.txt
@@ -0,0 +1,16 @@
+lkvm-pause(1)
+================
+
+NAME
+----
+lkvm-pause - Pause the virtual machine
+
+SYNOPSIS
+--------
+[verse]
+'lkvm pause [instance]'
+
+DESCRIPTION
+-----------
+The command pauses a virtual machine.
+For a list of running instances see 'lkvm list'.
diff --git a/tools/kvm/Documentation/kvm-resume.txt b/tools/kvm/Documentation/kvm-resume.txt
new file mode 100644
index 0000000..a36c4df
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-resume.txt
@@ -0,0 +1,16 @@
+lkvm-resume(1)
+================
+
+NAME
+----
+lkvm-resume - Resume the virtual machine
+
+SYNOPSIS
+--------
+[verse]
+'lkvm resume [instance]'
+
+DESCRIPTION
+-----------
+The command resumes a virtual machine.
+For a list of running instances see 'lkvm list'.
diff --git a/tools/kvm/Documentation/kvm-run.txt b/tools/kvm/Documentation/kvm-run.txt
new file mode 100644
index 0000000..8ddf470
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-run.txt
@@ -0,0 +1,62 @@
+lkvm-run(1)
+================
+
+NAME
+----
+lkvm-run - Start the virtual machine
+
+SYNOPSIS
+--------
+[verse]
+'lkvm run' [-k <kernel image> | --kernel <kernel image>]
+
+DESCRIPTION
+-----------
+The command starts a virtual machine.
+
+OPTIONS
+-------
+-m::
+--mem=::
+	Virtual machine memory size in MiB.
+
+-p::
+--params::
+	Additional kernel command line arguments.
+
+-r::
+--initrd=::
+	Initial RAM disk image.
+
+-k::
+--kernel=::
+	The virtual machine kernel.
+
+--dev=::
+	KVM device file.
+
+-i::
+--image=::
+	A disk image file.
+
+-s::
+--single-step::
+	Enable single stepping.
+
+-g::
+--ioport-debug::
+	Enable ioport debugging.
+
+-c::
+--enable-virtio-console::
+	Enable the virtual IO console.
+
+--cpus::
+	The number of virtual CPUs to run.
+
+--debug::
+	Enable debug messages.
+
+SEE ALSO
+--------
+linkkvm:
diff --git a/tools/kvm/Documentation/kvm-sandbox.txt b/tools/kvm/Documentation/kvm-sandbox.txt
new file mode 100644
index 0000000..2d7f558
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-sandbox.txt
@@ -0,0 +1,16 @@
+lkvm-sandbox(1)
+================
+
+NAME
+----
+lkvm-sandbox - Run a command in a sandboxed guest
+
+SYNOPSIS
+--------
+[verse]
+'lkvm sandbox ['lkvm run' arguments] -- [sandboxed command]'
+
+DESCRIPTION
+-----------
+The sandboxed command will run in a guest as part of it's init
+command.
diff --git a/tools/kvm/Documentation/kvm-setup.txt b/tools/kvm/Documentation/kvm-setup.txt
new file mode 100644
index 0000000..4b6e331
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-setup.txt
@@ -0,0 +1,15 @@
+lkvm-setup(1)
+================
+
+NAME
+----
+lkvm-setup - Setup a new virtual machine
+
+SYNOPSIS
+--------
+[verse]
+'lkvm setup <name>'
+
+DESCRIPTION
+-----------
+The command setups a virtual machine.
diff --git a/tools/kvm/Documentation/kvm-stat.txt b/tools/kvm/Documentation/kvm-stat.txt
new file mode 100644
index 0000000..101ce7a
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-stat.txt
@@ -0,0 +1,19 @@
+lkvm-stat(1)
+================
+
+NAME
+----
+lkvm-stat - Print statistics about a running instance
+
+SYNOPSIS
+--------
+[verse]
+'lkvm [command] [-n instance] [-p instance pid] [--all]'
+
+DESCRIPTION
+-----------
+The command prints statistics about a running instance.
+For a list of running instances see 'lkvm list'.
+
+Commands:
+ --memory, -m	Display memory statistics
diff --git a/tools/kvm/Documentation/kvm-stop.txt b/tools/kvm/Documentation/kvm-stop.txt
new file mode 100644
index 0000000..6e4bc83
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-stop.txt
@@ -0,0 +1,16 @@
+lkvm-stop(1)
+================
+
+NAME
+----
+lkvm-stop - Stop a running instance
+
+SYNOPSIS
+--------
+[verse]
+'lkvm stop [instance]'
+
+DESCRIPTION
+-----------
+The command stops a running instance.
+For a list of running instances see 'lkvm list'.
diff --git a/tools/kvm/Documentation/kvm-version.txt b/tools/kvm/Documentation/kvm-version.txt
new file mode 100644
index 0000000..41003d2
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-version.txt
@@ -0,0 +1,21 @@
+lkvm-version(1)
+================
+
+NAME
+----
+lkvm-version - Print the version of the kernel tree kvm tools
+was built on.
+
+SYNOPSIS
+--------
+[verse]
+'lkvm version'
+
+DESCRIPTION
+-----------
+The command prints the version of the kernel that was used to build
+kvm tools.
+
+Note that the version is not the version of the kernel which is currently
+running on the host, but is the version of the kernel tree from which kvm
+tools was built.
diff --git a/tools/kvm/Documentation/virtio-console.txt b/tools/kvm/Documentation/virtio-console.txt
new file mode 100644
index 0000000..4a58d56
--- /dev/null
+++ b/tools/kvm/Documentation/virtio-console.txt
@@ -0,0 +1,41 @@
+General
+--------
+
+virtio-console as the name implies is a console over virtio transport. Here is
+a simple head to head comparison of the virtio-console vs regular 8250 console:
+
+8250 serial console:
+
+ - Requires CONFIG_SERIAL_8250=y and CONFIG_SERIAL_8250_CONSOLE=y kernel configs,
+which are enabled almost everywhere.
+ - Doesn't require guest-side changes.
+ - Compatible with older guests.
+
+virtio-console:
+
+ - Requires CONFIG_VIRTIO_CONSOLE=y (along with all other virtio dependencies),
+which got enabled only in recent kernels (but not all of them).
+ - Much faster.
+ - Consumes less processing resources.
+ - Requires guest-side changes.
+
+Enabling virtio-console
+------------------------
+
+First, make sure guest kernel is built with CONFIG_VIRTIO_CONSOLE=y. Once this
+is done, the following has to be done inside guest image:
+
+ - Add the following line to /etc/inittab:
+	'hvc0:2345:respawn:/sbin/agetty -L 9600 hvc0'
+ - Add 'hvc0' to /etc/securetty (so you could actually log on)
+ - Start the guest with '--console virtio'
+
+Common errors
+--------------
+
+Q: I don't see anything on the screen!
+A: Make sure CONFIG_VIRTIO_CONSOLE=y is enabled in the *guest* kernel, also
+make sure you've updated /etc/inittab
+
+Q: It won't accept my username/password, but I enter them correctly!
+A: You didn't add 'hvc0' to /etc/securetty
diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
new file mode 100644
index 0000000..7a9d3b6
--- /dev/null
+++ b/tools/kvm/Makefile
@@ -0,0 +1,430 @@
+#
+# Define WERROR=0 to disable -Werror.
+#
+
+ifeq ($(strip $(V)),)
+	E = @echo
+	Q = @
+else
+	E = @\#
+	Q =
+endif
+ifneq ($(I), )
+	KINCL_PATH=$(I)
+else
+	KINCL_PATH=../..
+endif
+export E Q KINCL_PATH
+
+include config/utilities.mak
+include config/feature-tests.mak
+
+FIND	:= find
+CSCOPE	:= cscope
+TAGS	:= ctags
+
+PROGRAM	:= lkvm
+PROGRAM_ALIAS := vm
+
+GUEST_INIT := guest/init
+GUEST_INIT_S2 := guest/init_stage2
+
+OBJS	+= builtin-balloon.o
+OBJS	+= builtin-debug.o
+OBJS	+= builtin-help.o
+OBJS	+= builtin-list.o
+OBJS	+= builtin-stat.o
+OBJS	+= builtin-pause.o
+OBJS	+= builtin-resume.o
+OBJS	+= builtin-run.o
+OBJS	+= builtin-setup.o
+OBJS	+= builtin-stop.o
+OBJS	+= builtin-version.o
+OBJS	+= disk/core.o
+OBJS	+= framebuffer.o
+OBJS	+= guest_compat.o
+OBJS	+= hw/rtc.o
+OBJS	+= hw/serial.o
+OBJS	+= ioport.o
+OBJS	+= kvm-cpu.o
+OBJS	+= kvm.o
+OBJS	+= main.o
+OBJS	+= mmio.o
+OBJS	+= pci.o
+OBJS	+= term.o
+OBJS	+= virtio/blk.o
+OBJS	+= virtio/console.o
+OBJS	+= virtio/core.o
+OBJS	+= virtio/net.o
+OBJS	+= virtio/rng.o
+OBJS    += virtio/balloon.o
+OBJS	+= virtio/pci.o
+OBJS	+= disk/blk.o
+OBJS	+= disk/qcow.o
+OBJS	+= disk/raw.o
+OBJS	+= ioeventfd.o
+OBJS	+= net/uip/core.o
+OBJS	+= net/uip/arp.o
+OBJS	+= net/uip/icmp.o
+OBJS	+= net/uip/ipv4.o
+OBJS	+= net/uip/tcp.o
+OBJS	+= net/uip/udp.o
+OBJS	+= net/uip/buf.o
+OBJS	+= net/uip/csum.o
+OBJS	+= net/uip/dhcp.o
+OBJS	+= kvm-cmd.o
+OBJS	+= util/rbtree.o
+OBJS	+= util/threadpool.o
+OBJS	+= util/parse-options.o
+OBJS	+= util/rbtree-interval.o
+OBJS	+= util/strbuf.o
+OBJS	+= util/read-write.o
+OBJS	+= util/util.o
+OBJS	+= virtio/9p.o
+OBJS	+= virtio/9p-pdu.o
+OBJS	+= hw/vesa.o
+OBJS	+= hw/pci-shmem.o
+OBJS	+= kvm-ipc.o
+OBJS	+= builtin-sandbox.o
+OBJS	+= virtio/mmio.o
+
+# Additional ARCH settings for x86
+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+                  -e s/arm.*/arm/ -e s/sa110/arm/ \
+                  -e s/s390x/s390/ -e s/parisc64/parisc/ \
+                  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
+                  -e s/sh[234].*/sh/ )
+
+uname_M      := $(shell uname -m | sed -e s/i.86/i386/)
+ifeq ($(uname_M),i386)
+	ARCH         := x86
+	DEFINES      += -DCONFIG_X86_32
+endif
+ifeq ($(uname_M),x86_64)
+	ARCH         := x86
+	DEFINES      += -DCONFIG_X86_64
+endif
+
+LIBFDT_SRC = fdt.o fdt_ro.o fdt_wip.o fdt_sw.o fdt_rw.o fdt_strerror.o
+LIBFDT_OBJS = $(patsubst %,../../scripts/dtc/libfdt/%,$(LIBFDT_SRC))
+
+### Arch-specific stuff
+
+#x86
+ifeq ($(ARCH),x86)
+	DEFINES += -DCONFIG_X86
+	OBJS	+= x86/boot.o
+	OBJS	+= x86/cpuid.o
+	OBJS	+= x86/interrupt.o
+	OBJS	+= x86/ioport.o
+	OBJS	+= x86/irq.o
+	OBJS	+= x86/kvm.o
+	OBJS	+= x86/kvm-cpu.o
+	OBJS	+= x86/mptable.o
+	OBJS	+= hw/i8042.o
+# Exclude BIOS object files from header dependencies.
+	OTHEROBJS	+= x86/bios.o
+	OTHEROBJS	+= x86/bios/bios-rom.o
+	ARCH_INCLUDE := x86/include
+endif
+# POWER/ppc:  Actually only support ppc64 currently.
+ifeq ($(uname_M), ppc64)
+	DEFINES += -DCONFIG_PPC
+	OBJS	+= powerpc/boot.o
+	OBJS	+= powerpc/ioport.o
+	OBJS	+= powerpc/irq.o
+	OBJS	+= powerpc/kvm.o
+	OBJS	+= powerpc/cpu_info.o
+	OBJS	+= powerpc/kvm-cpu.o
+	OBJS	+= powerpc/spapr_hcall.o
+	OBJS	+= powerpc/spapr_rtas.o
+	OBJS	+= powerpc/spapr_hvcons.o
+	OBJS	+= powerpc/spapr_pci.o
+	OBJS	+= powerpc/xics.o
+# We use libfdt, but it's sometimes not packaged 64bit.  It's small too,
+# so just build it in:
+	CFLAGS 	+= -I../../scripts/dtc/libfdt
+	OTHEROBJS	+= $(LIBFDT_OBJS)
+	ARCH_INCLUDE := powerpc/include
+	CFLAGS 	+= -m64
+endif
+
+###
+
+ifeq (,$(ARCH_INCLUDE))
+	UNSUPP_ERR = @echo "This architecture is not supported in kvmtool." && exit 1
+else
+	UNSUPP_ERR =
+endif
+
+###
+
+# Detect optional features.
+# On a given system, some libs may link statically, some may not; so, check
+# both and only build those that link!
+
+FLAGS_BFD := $(CFLAGS) -lbfd
+ifeq ($(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD)),y)
+	CFLAGS_DYNOPT	+= -DCONFIG_HAS_BFD
+	OBJS_DYNOPT	+= symbol.o
+	LIBS_DYNOPT	+= -lbfd
+endif
+ifeq ($(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD) -static),y)
+	CFLAGS_STATOPT	+= -DCONFIG_HAS_BFD
+	OBJS_STATOPT	+= symbol.o
+	LIBS_STATOPT	+= -lbfd
+endif
+
+FLAGS_VNCSERVER := $(CFLAGS) -lvncserver
+ifeq ($(call try-cc,$(SOURCE_VNCSERVER),$(FLAGS_VNCSERVER)),y)
+	OBJS_DYNOPT	+= ui/vnc.o
+	CFLAGS_DYNOPT	+= -DCONFIG_HAS_VNCSERVER
+	LIBS_DYNOPT	+= -lvncserver
+endif
+ifeq ($(call try-cc,$(SOURCE_VNCSERVER),$(FLAGS_VNCSERVER) -static),y)
+	OBJS_STATOPT	+= ui/vnc.o
+	CFLAGS_STATOPT	+= -DCONFIG_HAS_VNCSERVER
+	LIBS_STATOPT	+= -lvncserver
+endif
+
+FLAGS_SDL := $(CFLAGS) -lSDL
+ifeq ($(call try-cc,$(SOURCE_SDL),$(FLAGS_SDL)),y)
+	OBJS_DYNOPT	+= ui/sdl.o
+	CFLAGS_DYNOPT	+= -DCONFIG_HAS_SDL
+	LIBS_DYNOPT	+= -lSDL
+endif
+ifeq ($(call try-cc,$(SOURCE_SDL),$(FLAGS_SDL) -static), y)
+	OBJS_STATOPT	+= ui/sdl.o
+	CFLAGS_STATOPT	+= -DCONFIG_HAS_SDL
+	LIBS_STATOPT	+= -lSDL
+endif
+
+FLAGS_ZLIB := $(CFLAGS) -lz
+ifeq ($(call try-cc,$(SOURCE_ZLIB),$(FLAGS_ZLIB)),y)
+	CFLAGS_DYNOPT	+= -DCONFIG_HAS_ZLIB
+	LIBS_DYNOPT	+= -lz
+endif
+ifeq ($(call try-cc,$(SOURCE_ZLIB),$(FLAGS_ZLIB) -static),y)
+	CFLAGS_STATOPT	+= -DCONFIG_HAS_ZLIB
+	LIBS_STATOPT	+= -lz
+endif
+
+FLAGS_AIO := $(CFLAGS) -laio
+ifeq ($(call try-cc,$(SOURCE_AIO),$(FLAGS_AIO)),y)
+	CFLAGS_DYNOPT	+= -DCONFIG_HAS_AIO
+	LIBS_DYNOPT	+= -laio
+endif
+ifeq ($(call try-cc,$(SOURCE_AIO),$(FLAGS_AIO) -static),y)
+	CFLAGS_STATOPT	+= -DCONFIG_HAS_AIO
+	LIBS_STATOPT	+= -laio
+endif
+
+ifneq ($(call try-build,$(SOURCE_STATIC),-static,),y)
+$(error No static libc found. Please install glibc-static package.)
+endif
+###
+
+LIBS	+= -lrt
+LIBS	+= -lpthread
+LIBS	+= -lutil
+
+
+DEPS	:= $(patsubst %.o,%.d,$(OBJS))
+
+DEFINES	+= -D_FILE_OFFSET_BITS=64
+DEFINES	+= -D_GNU_SOURCE
+DEFINES	+= -DKVMTOOLS_VERSION='"$(KVMTOOLS_VERSION)"'
+DEFINES	+= -DBUILD_ARCH='"$(ARCH)"'
+
+KVM_INCLUDE := include
+CFLAGS	+= $(CPPFLAGS) $(DEFINES) -I$(KVM_INCLUDE) -I$(ARCH_INCLUDE) -I$(KINCL_PATH)/include -I$(KINCL_PATH)/arch/$(ARCH)/include/ -O2 -fno-strict-aliasing -g
+
+WARNINGS += -Wall
+WARNINGS += -Wcast-align
+WARNINGS += -Wformat=2
+WARNINGS += -Winit-self
+WARNINGS += -Wmissing-declarations
+WARNINGS += -Wmissing-prototypes
+WARNINGS += -Wnested-externs
+WARNINGS += -Wno-system-headers
+WARNINGS += -Wold-style-definition
+WARNINGS += -Wredundant-decls
+WARNINGS += -Wsign-compare
+WARNINGS += -Wstrict-prototypes
+WARNINGS += -Wundef
+WARNINGS += -Wvolatile-register-var
+WARNINGS += -Wwrite-strings
+
+CFLAGS	+= $(WARNINGS)
+
+# Some targets may use 'external' sources that don't build totally cleanly.
+CFLAGS_EASYGOING := $(CFLAGS)
+
+ifneq ($(WERROR),0)
+	CFLAGS += -Werror
+endif
+
+all: arch_support_check $(PROGRAM) $(PROGRAM_ALIAS) $(GUEST_INIT) $(GUEST_INIT_S2)
+
+arch_support_check:
+	$(UNSUPP_ERR)
+
+KVMTOOLS-VERSION-FILE:
+	@$(SHELL_PATH) util/KVMTOOLS-VERSION-GEN $(OUTPUT)
+-include $(OUTPUT)KVMTOOLS-VERSION-FILE
+
+# When building -static all objects are built with appropriate flags, which
+# may differ between static & dynamic .o.  The objects are separated into
+# .o and .static.o.  See the %.o: %.c rules below.
+#
+# $(OTHEROBJS) are things that do not get substituted like this.
+#
+STATIC_OBJS = $(patsubst %.o,%.static.o,$(OBJS) $(OBJS_STATOPT))
+
+$(PROGRAM)-static:  $(DEPS) $(STATIC_OBJS) $(OTHEROBJS)
+	$(E) "  LINK    " $@
+	$(Q) $(CC) -static $(CFLAGS) $(STATIC_OBJS) $(OTHEROBJS) $(LIBS) $(LIBS_STATOPT) -o $@
+
+$(PROGRAM): $(DEPS) $(OBJS) $(OBJS_DYNOPT) $(OTHEROBJS)
+	$(E) "  LINK    " $@
+	$(Q) $(CC) $(CFLAGS) $(OBJS) $(OBJS_DYNOPT) $(OTHEROBJS) $(LIBS) $(LIBS_DYNOPT) -o $@
+
+$(PROGRAM_ALIAS): $(PROGRAM)
+	$(E) "  LN      " $@
+	$(Q) ln -f $(PROGRAM) $@
+
+$(GUEST_INIT): guest/init.c
+	$(E) "  LINK    " $@
+	$(Q) $(CC) -static guest/init.c -o $@
+
+$(GUEST_INIT_S2): guest/init_stage2.c
+	$(E) "  LINK    " $@
+	$(Q) $(CC) -static guest/init_stage2.c -o $@
+
+$(DEPS):
+
+util/rbtree.d: ../../lib/rbtree.c
+	$(Q) $(CC) -M -MT util/rbtree.o $(CFLAGS) $< -o $@
+
+%.d: %.c
+	$(Q) $(CC) -M -MT $(patsubst %.d,%.o,$@) $(CFLAGS) $< -o $@
+
+# The header file common-cmds.h is needed for compilation of builtin-help.c.
+builtin-help.d: $(KVM_INCLUDE)/common-cmds.h
+
+$(OBJS):
+
+# This rule relaxes the -Werror on libfdt, since for now it still has
+# a bunch of warnings. :(
+../../scripts/dtc/libfdt/%.o: ../../scripts/dtc/libfdt/%.c
+	$(E) "  CC      " $@
+	$(Q) $(CC) -c $(CFLAGS_EASYGOING) $< -o $@
+
+util/rbtree.static.o util/rbtree.o: ../../lib/rbtree.c
+	$(E) "  CC      " $@
+	$(Q) $(CC) -c $(CFLAGS) $< -o $@
+
+%.static.o: %.c
+	$(E) "  CC      " $@
+	$(Q) $(CC) -c $(CFLAGS) $(CFLAGS_STATOPT)  $< -o $@
+
+%.o: %.c
+	$(E) "  CC      " $@
+	$(Q) $(CC) -c $(CFLAGS) $(CFLAGS_DYNOPT) $< -o $@
+
+
+$(KVM_INCLUDE)/common-cmds.h: util/generate-cmdlist.sh command-list.txt
+
+$(KVM_INCLUDE)/common-cmds.h: $(wildcard Documentation/kvm-*.txt)
+	$(E) "  GEN     " $@
+	$(Q) util/generate-cmdlist.sh > $@+ && mv $@+ $@
+
+#
+# BIOS assembly weirdness
+#
+BIOS_CFLAGS += -m32
+BIOS_CFLAGS += -march=i386
+BIOS_CFLAGS += -mregparm=3
+
+BIOS_CFLAGS += -fno-stack-protector
+BIOS_CFLAGS += -I../../arch/$(ARCH)
+
+x86/bios.o: x86/bios/bios.bin x86/bios/bios-rom.h
+
+x86/bios/bios.bin.elf: x86/bios/entry.S x86/bios/e820.c x86/bios/int10.c x86/bios/int15.c x86/bios/rom.ld.S
+	$(E) "  CC       x86/bios/memcpy.o"
+	$(Q) $(CC) -include code16gcc.h $(CFLAGS) $(BIOS_CFLAGS) -c -s x86/bios/memcpy.c -o x86/bios/memcpy.o
+	$(E) "  CC       x86/bios/e820.o"
+	$(Q) $(CC) -include code16gcc.h $(CFLAGS) $(BIOS_CFLAGS) -c -s x86/bios/e820.c -o x86/bios/e820.o
+	$(E) "  CC       x86/bios/int10.o"
+	$(Q) $(CC) -include code16gcc.h $(CFLAGS) $(BIOS_CFLAGS) -c -s x86/bios/int10.c -o x86/bios/int10.o
+	$(E) "  CC       x86/bios/int15.o"
+	$(Q) $(CC) -include code16gcc.h $(CFLAGS) $(BIOS_CFLAGS) -c -s x86/bios/int15.c -o x86/bios/int15.o
+	$(E) "  CC       x86/bios/entry.o"
+	$(Q) $(CC) $(CFLAGS) $(BIOS_CFLAGS) -c -s x86/bios/entry.S -o x86/bios/entry.o
+	$(E) "  LD      " $@
+	$(Q) ld -T x86/bios/rom.ld.S -o x86/bios/bios.bin.elf x86/bios/memcpy.o x86/bios/entry.o x86/bios/e820.o x86/bios/int10.o x86/bios/int15.o
+
+x86/bios/bios.bin: x86/bios/bios.bin.elf
+	$(E) "  OBJCOPY " $@
+	$(Q) objcopy -O binary -j .text x86/bios/bios.bin.elf x86/bios/bios.bin
+
+x86/bios/bios-rom.o: x86/bios/bios-rom.S x86/bios/bios.bin x86/bios/bios-rom.h
+	$(E) "  CC      " $@
+	$(Q) $(CC) -c $(CFLAGS) x86/bios/bios-rom.S -o x86/bios/bios-rom.o
+
+x86/bios/bios-rom.h: x86/bios/bios.bin.elf
+	$(E) "  NM      " $@
+	$(Q) cd x86/bios && sh gen-offsets.sh > bios-rom.h && cd ..
+
+check: all
+	$(MAKE) -C tests
+	./$(PROGRAM) run tests/pit/tick.bin
+	./$(PROGRAM) run -d tests/boot/boot_test.iso -p "init=init"
+.PHONY: check
+
+clean:
+	$(E) "  CLEAN"
+	$(Q) rm -f x86/bios/*.bin
+	$(Q) rm -f x86/bios/*.elf
+	$(Q) rm -f x86/bios/*.o
+	$(Q) rm -f x86/bios/bios-rom.h
+	$(Q) rm -f tests/boot/boot_test.iso
+	$(Q) rm -rf tests/boot/rootfs/
+	$(Q) rm -f $(DEPS) $(OBJS) $(OTHEROBJS) $(OBJS_DYNOPT) $(STATIC_OBJS) $(PROGRAM) $(PROGRAM_ALIAS) $(PROGRAM)-static $(GUEST_INIT) $(GUEST_INIT_S2)
+	$(Q) rm -f cscope.*
+	$(Q) rm -f tags
+	$(Q) rm -f TAGS
+	$(Q) rm -f $(KVM_INCLUDE)/common-cmds.h
+	$(Q) rm -f KVMTOOLS-VERSION-FILE
+.PHONY: clean
+
+KVM_DEV	?= /dev/kvm
+
+$(KVM_DEV):
+	$(E) "  MKNOD " $@
+	$(Q) mknod $@ char 10 232
+
+devices: $(KVM_DEV)
+.PHONY: devices
+
+TAGS:
+	$(E) "  GEN" $@
+	$(Q) $(RM) -f TAGS
+	$(Q) $(FIND) . -name '*.[hcS]' -print | xargs etags -a
+.PHONY: TAGS
+
+tags:
+	$(E) "  GEN" $@
+	$(Q) $(RM) -f tags
+	$(Q) $(FIND) . -name '*.[hcS]' -print | xargs ctags -a
+.PHONY: tags
+
+cscope:
+	$(E) "  GEN" $@
+	$(Q) $(FIND) . -name '*.[hcS]' -print > cscope.files
+	$(Q) $(CSCOPE) -bkqu
+.PHONY: cscope
+
+# Deps
+-include $(DEPS)
diff --git a/tools/kvm/README b/tools/kvm/README
new file mode 100644
index 0000000..358fa23
--- /dev/null
+++ b/tools/kvm/README
@@ -0,0 +1,112 @@
+Native Linux KVM tool
+=====================
+The goal of this tool is to provide a clean, from-scratch, lightweight
+KVM host tool implementation that can boot Linux guest images (just a
+hobby, won't be big and professional like QEMU) with no BIOS
+dependencies and with only the minimal amount of legacy device
+emulation.
+
+It's great as a learning tool if you want to get your feet wet in
+virtualization land: it's only 5 KLOC of clean C code that can already
+boot a guest Linux image.
+
+Right now it can boot a Linux image and provide you output via a serial
+console, over the host terminal, i.e. you can use it to boot a guest
+Linux image in a terminal or over ssh and log into the guest without
+much guest or host side setup work needed.
+
+1. To try out the tool, clone the git repository:
+
+  git clone git://github.com/penberg/linux-kvm.git
+
+or alternatively, if you already have a kernel source tree:
+
+  git remote add kvm-tool git://github.com/penberg/linux-kvm.git
+  git remote update
+  git checkout -b kvm-tool/master kvm-tool
+
+2. Compile the tool:
+
+  cd tools/kvm && make
+
+3. Download a raw userspace image:
+
+  wget http://wiki.qemu.org/download/linux-0.2.img.bz2 && bunzip2
+linux-0.2.img.bz2
+
+4. The guest kernel has to be built with the following configuration:
+
+ - For the default console output:
+	CONFIG_SERIAL_8250=y
+	CONFIG_SERIAL_8250_CONSOLE=y
+
+ - For running 32bit images on 64bit hosts:
+	CONFIG_IA32_EMULATION=y
+
+ - Proper FS options according to image FS (e.g. CONFIG_EXT2_FS, CONFIG_EXT4_FS).
+
+ - For all virtio devices listed below:
+	CONFIG_VIRTIO=y
+	CONFIG_VIRTIO_RING=y
+	CONFIG_VIRTIO_PCI=y
+
+ - For virtio-blk devices (--disk, -d):
+	CONFIG_VIRTIO_BLK=y
+
+ - For virtio-net devices ([--network, -n] virtio):
+	CONFIG_VIRTIO_NET=y
+
+ - For virtio-9p devices (--virtio-9p):
+	CONFIG_NET_9P=y
+	CONFIG_NET_9P_VIRTIO=y
+	CONFIG_9P_FS=y
+
+ - For virtio-balloon device (--balloon):
+	CONFIG_VIRTIO_BALLOON=y
+
+ - For virtio-console device (--console virtio):
+	CONFIG_VIRTIO_CONSOLE=y
+
+ - For virtio-rng device (--rng):
+	CONFIG_HW_RANDOM_VIRTIO=y
+
+ - For vesa device (--sdl or --vnc):
+	CONFIG_FB_VESA=y
+
+
+5. And finally, launch the hypervisor:
+
+  ./lkvm run --disk linux-0.2.img \
+	    --kernel ../../arch/x86/boot/bzImage \
+or
+
+  sudo ./lkvm run --disk linux-0.2.img \
+		 --kernel ../../arch/x86/boot/bzImage \
+		 --network virtio
+
+The tool has been written by Pekka Enberg, Cyrill Gorcunov, Asias He,
+Sasha Levin and Prasad Joshi. Special thanks to Avi Kivity for his help
+on KVM internals and Ingo Molnar for all-around support and encouragement!
+
+See the following thread for original discussion for motivation of this
+project:
+
+http://thread.gmane.org/gmane.linux.kernel/962051/focus=962620
+
+Build dependencies
+=====================
+For deb based systems:
+32-bit:
+sudo apt-get install build-essential
+64-bit:
+sudo apt-get install build-essential libc6-dev-i386
+
+For rpm based systems:
+32-bit:
+yum install glibc-devel
+64-bit:
+yum install glibc-devel glibc-static
+
+On 64-bit Arch Linux make sure the multilib repository is enabled in your
+/etc/pacman.conf and run
+pacman -Sy lib32-glibc
diff --git a/tools/kvm/builtin-balloon.c b/tools/kvm/builtin-balloon.c
new file mode 100644
index 0000000..5bd2291
--- /dev/null
+++ b/tools/kvm/builtin-balloon.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-balloon.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm.h>
+#include <kvm/kvm-ipc.h>
+
+static const char *instance_name;
+static u64 inflate;
+static u64 deflate;
+
+static const char * const balloon_usage[] = {
+	"lkvm balloon [-n name] [-p pid] [-i amount] [-d amount]",
+	NULL
+};
+
+static const struct option balloon_options[] = {
+	OPT_GROUP("Instance options:"),
+	OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+	OPT_GROUP("Balloon options:"),
+	OPT_U64('i', "inflate", &inflate, "Amount to inflate"),
+	OPT_U64('d', "deflate", &deflate, "Amount to deflate"),
+	OPT_END(),
+};
+
+void kvm_balloon_help(void)
+{
+	usage_with_options(balloon_usage, balloon_options);
+}
+
+static void parse_balloon_options(int argc, const char **argv)
+{
+	while (argc != 0) {
+		argc = parse_options(argc, argv, balloon_options, balloon_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION);
+		if (argc != 0)
+			kvm_balloon_help();
+	}
+}
+
+int kvm_cmd_balloon(int argc, const char **argv, const char *prefix)
+{
+	int instance;
+	int r;
+	int amount;
+
+	parse_balloon_options(argc, argv);
+
+	if (inflate == 0 && deflate == 0)
+		kvm_balloon_help();
+
+	if (instance_name == NULL)
+		kvm_balloon_help();
+
+	instance = kvm__get_sock_by_instance(instance_name);
+
+	if (instance <= 0)
+		die("Failed locating instance");
+
+	if (inflate)
+		amount = inflate;
+	else if (deflate)
+		amount = -deflate;
+	else
+		kvm_balloon_help();
+
+	r = kvm_ipc__send_msg(instance, KVM_IPC_BALLOON,
+			sizeof(amount), (u8 *)&amount);
+
+	close(instance);
+
+	if (r < 0)
+		return -1;
+
+	return 0;
+}
diff --git a/tools/kvm/builtin-debug.c b/tools/kvm/builtin-debug.c
new file mode 100644
index 0000000..20e27ff
--- /dev/null
+++ b/tools/kvm/builtin-debug.c
@@ -0,0 +1,103 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-debug.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+#include <kvm/read-write.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#define BUFFER_SIZE 100
+
+static bool all;
+static int nmi = -1;
+static bool dump;
+static const char *instance_name;
+
+static const char * const debug_usage[] = {
+	"lkvm debug [--all] [-n name] [-d] [-m vcpu]",
+	NULL
+};
+
+static const struct option debug_options[] = {
+	OPT_GROUP("General options:"),
+	OPT_BOOLEAN('d', "dump", &dump, "Generate a debug dump from guest"),
+	OPT_INTEGER('m', "nmi", &nmi, "Generate NMI on VCPU"),
+	OPT_GROUP("Instance options:"),
+	OPT_BOOLEAN('a', "all", &all, "Debug all instances"),
+	OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+	OPT_END()
+};
+
+static void parse_debug_options(int argc, const char **argv)
+{
+	while (argc != 0) {
+		argc = parse_options(argc, argv, debug_options, debug_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION);
+		if (argc != 0)
+			kvm_debug_help();
+	}
+}
+
+void kvm_debug_help(void)
+{
+	usage_with_options(debug_usage, debug_options);
+}
+
+static int do_debug(const char *name, int sock)
+{
+	char buff[BUFFER_SIZE];
+	struct debug_cmd_params cmd = {.dbg_type = 0};
+	int r;
+
+	if (dump)
+		cmd.dbg_type |= KVM_DEBUG_CMD_TYPE_DUMP;
+
+	if (nmi != -1) {
+		cmd.dbg_type |= KVM_DEBUG_CMD_TYPE_NMI;
+		cmd.cpu = nmi;
+	}
+
+	r = kvm_ipc__send_msg(sock, KVM_IPC_DEBUG, sizeof(cmd), (u8 *)&cmd);
+	if (r < 0)
+		return r;
+
+	if (!dump)
+		return 0;
+
+	do {
+		r = xread(sock, buff, BUFFER_SIZE);
+		if (r < 0)
+			return 0;
+		printf("%.*s", r, buff);
+	} while (r > 0);
+
+	return 0;
+}
+
+int kvm_cmd_debug(int argc, const char **argv, const char *prefix)
+{
+	parse_debug_options(argc, argv);
+	int instance;
+	int r;
+
+	if (all)
+		return kvm__enumerate_instances(do_debug);
+
+	if (instance_name == NULL)
+		kvm_debug_help();
+
+	instance = kvm__get_sock_by_instance(instance_name);
+
+	if (instance <= 0)
+		die("Failed locating instance");
+
+	r = do_debug(instance_name, instance);
+
+	close(instance);
+
+	return r;
+}
diff --git a/tools/kvm/builtin-help.c b/tools/kvm/builtin-help.c
new file mode 100644
index 0000000..5970fb7
--- /dev/null
+++ b/tools/kvm/builtin-help.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <string.h>
+
+/* user defined headers */
+#include <common-cmds.h>
+
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-help.h>
+#include <kvm/kvm.h>
+
+
+const char kvm_usage_string[] =
+	"lkvm COMMAND [ARGS]";
+
+const char kvm_more_info_string[] =
+	"See 'lkvm help COMMAND' for more information on a specific command.";
+
+
+static void list_common_cmds_help(void)
+{
+	unsigned int i, longest = 0;
+
+	for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
+		if (longest < strlen(common_cmds[i].name))
+			longest = strlen(common_cmds[i].name);
+	}
+
+	puts(" The most commonly used lkvm commands are:");
+	for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
+		printf("   %-*s   ", longest, common_cmds[i].name);
+		puts(common_cmds[i].help);
+	}
+}
+
+static void kvm_help(void)
+{
+	printf("\n To start a simple non-privileged shell run '%s run'\n\n"
+		"usage: %s\n\n", KVM_BINARY_NAME, kvm_usage_string);
+	list_common_cmds_help();
+	printf("\n %s\n\n", kvm_more_info_string);
+}
+
+
+static void help_cmd(const char *cmd)
+{
+	struct cmd_struct *p;
+	p = kvm_get_command(kvm_commands, cmd);
+	if (!p)
+		kvm_help();
+	else if (p->help)
+		p->help();
+}
+
+int kvm_cmd_help(int argc, const char **argv, const char *prefix)
+{
+	if (!argv || !*argv) {
+		kvm_help();
+		return 0;
+	}
+	help_cmd(argv[0]);
+	return 0;
+}
diff --git a/tools/kvm/builtin-list.c b/tools/kvm/builtin-list.c
new file mode 100644
index 0000000..9299f17
--- /dev/null
+++ b/tools/kvm/builtin-list.c
@@ -0,0 +1,149 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-list.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+
+static bool run;
+static bool rootfs;
+
+static const char * const list_usage[] = {
+	"lkvm list",
+	NULL
+};
+
+static const struct option list_options[] = {
+	OPT_GROUP("General options:"),
+	OPT_BOOLEAN('i', "run", &run, "List running instances"),
+	OPT_BOOLEAN('r', "rootfs", &rootfs, "List rootfs instances"),
+	OPT_END()
+};
+
+#define KVM_INSTANCE_RUNNING	"running"
+#define KVM_INSTANCE_PAUSED	"paused"
+#define KVM_INSTANCE_SHUTOFF	"shut off"
+
+void kvm_list_help(void)
+{
+	usage_with_options(list_usage, list_options);
+}
+
+static pid_t get_pid(int sock)
+{
+	pid_t pid;
+	int r;
+
+	r = kvm_ipc__send(sock, KVM_IPC_PID);
+	if (r < 0)
+		return r;
+
+	r = read(sock, &pid, sizeof(pid));
+	if (r < 0)
+		return r;
+
+	return pid;
+}
+
+int get_vmstate(int sock)
+{
+	int vmstate;
+	int r;
+
+	r = kvm_ipc__send(sock, KVM_IPC_VMSTATE);
+	if (r < 0)
+		return r;
+
+	r = read(sock, &vmstate, sizeof(vmstate));
+	if (r < 0)
+		return r;
+
+	return vmstate;
+
+}
+
+static int print_guest(const char *name, int sock)
+{
+	pid_t pid;
+	int vmstate;
+
+	pid = get_pid(sock);
+	vmstate = get_vmstate(sock);
+
+	if ((int)pid < 0 || vmstate < 0)
+		return -1;
+
+	if (vmstate == KVM_VMSTATE_PAUSED)
+		printf("%5d %-20s %s\n", pid, name, KVM_INSTANCE_PAUSED);
+	else
+		printf("%5d %-20s %s\n", pid, name, KVM_INSTANCE_RUNNING);
+
+	return 0;
+}
+
+static int kvm_list_running_instances(void)
+{
+	return kvm__enumerate_instances(print_guest);
+}
+
+static int kvm_list_rootfs(void)
+{
+	DIR *dir;
+	struct dirent *dirent;
+
+	dir = opendir(kvm__get_dir());
+	if (dir == NULL)
+		return -1;
+
+	while ((dirent = readdir(dir))) {
+		if (dirent->d_type == DT_DIR &&
+			strcmp(dirent->d_name, ".") &&
+			strcmp(dirent->d_name, ".."))
+			printf("%5s %-20s %s\n", "", dirent->d_name, KVM_INSTANCE_SHUTOFF);
+	}
+
+	return 0;
+}
+
+static void parse_setup_options(int argc, const char **argv)
+{
+	while (argc != 0) {
+		argc = parse_options(argc, argv, list_options, list_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION);
+		if (argc != 0)
+			kvm_list_help();
+	}
+}
+
+int kvm_cmd_list(int argc, const char **argv, const char *prefix)
+{
+	int r;
+
+	parse_setup_options(argc, argv);
+
+	if (!run && !rootfs)
+		run = rootfs = true;
+
+	printf("%6s %-20s %s\n", "PID", "NAME", "STATE");
+	printf("------------------------------------\n");
+
+	if (run) {
+		r = kvm_list_running_instances();
+		if (r < 0)
+			perror("Error listing instances");
+	}
+
+	if (rootfs) {
+		r = kvm_list_rootfs();
+		if (r < 0)
+			perror("Error listing rootfs");
+	}
+
+	return 0;
+}
diff --git a/tools/kvm/builtin-pause.c b/tools/kvm/builtin-pause.c
new file mode 100644
index 0000000..c08595a
--- /dev/null
+++ b/tools/kvm/builtin-pause.c
@@ -0,0 +1,88 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-pause.h>
+#include <kvm/builtin-list.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+static bool all;
+static const char *instance_name;
+
+static const char * const pause_usage[] = {
+	"lkvm pause [--all] [-n name]",
+	NULL
+};
+
+static const struct option pause_options[] = {
+	OPT_GROUP("General options:"),
+	OPT_BOOLEAN('a', "all", &all, "Pause all instances"),
+	OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+	OPT_END()
+};
+
+static void parse_pause_options(int argc, const char **argv)
+{
+	while (argc != 0) {
+		argc = parse_options(argc, argv, pause_options, pause_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION);
+		if (argc != 0)
+			kvm_pause_help();
+	}
+}
+
+void kvm_pause_help(void)
+{
+	usage_with_options(pause_usage, pause_options);
+}
+
+static int do_pause(const char *name, int sock)
+{
+	int r;
+	int vmstate;
+
+	vmstate = get_vmstate(sock);
+	if (vmstate < 0)
+		return vmstate;
+	if (vmstate == KVM_VMSTATE_PAUSED) {
+		printf("Guest %s is already paused.\n", name);
+		return 0;
+	}
+
+	r = kvm_ipc__send(sock, KVM_IPC_PAUSE);
+	if (r)
+		return r;
+
+	printf("Guest %s paused\n", name);
+
+	return 0;
+}
+
+int kvm_cmd_pause(int argc, const char **argv, const char *prefix)
+{
+	int instance;
+	int r;
+
+	parse_pause_options(argc, argv);
+
+	if (all)
+		return kvm__enumerate_instances(do_pause);
+
+	if (instance_name == NULL)
+		kvm_pause_help();
+
+	instance = kvm__get_sock_by_instance(instance_name);
+
+	if (instance <= 0)
+		die("Failed locating instance");
+
+	r = do_pause(instance_name, instance);
+
+	close(instance);
+
+	return r;
+}
diff --git a/tools/kvm/builtin-resume.c b/tools/kvm/builtin-resume.c
new file mode 100644
index 0000000..0e954b4
--- /dev/null
+++ b/tools/kvm/builtin-resume.c
@@ -0,0 +1,88 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-resume.h>
+#include <kvm/builtin-list.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+static bool all;
+static const char *instance_name;
+
+static const char * const resume_usage[] = {
+	"lkvm resume [--all] [-n name]",
+	NULL
+};
+
+static const struct option resume_options[] = {
+	OPT_GROUP("General options:"),
+	OPT_BOOLEAN('a', "all", &all, "Resume all instances"),
+	OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+	OPT_END()
+};
+
+static void parse_resume_options(int argc, const char **argv)
+{
+	while (argc != 0) {
+		argc = parse_options(argc, argv, resume_options, resume_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION);
+		if (argc != 0)
+			kvm_resume_help();
+	}
+}
+
+void kvm_resume_help(void)
+{
+	usage_with_options(resume_usage, resume_options);
+}
+
+static int do_resume(const char *name, int sock)
+{
+	int r;
+	int vmstate;
+
+	vmstate = get_vmstate(sock);
+	if (vmstate < 0)
+		return vmstate;
+	if (vmstate == KVM_VMSTATE_RUNNING) {
+		printf("Guest %s is still running.\n", name);
+		return 0;
+	}
+
+	r = kvm_ipc__send(sock, KVM_IPC_RESUME);
+	if (r)
+		return r;
+
+	printf("Guest %s resumed\n", name);
+
+	return 0;
+}
+
+int kvm_cmd_resume(int argc, const char **argv, const char *prefix)
+{
+	int instance;
+	int r;
+
+	parse_resume_options(argc, argv);
+
+	if (all)
+		return kvm__enumerate_instances(do_resume);
+
+	if (instance_name == NULL)
+		kvm_resume_help();
+
+	instance = kvm__get_sock_by_instance(instance_name);
+
+	if (instance <= 0)
+		die("Failed locating instance");
+
+	r = do_resume(instance_name, instance);
+
+	close(instance);
+
+	return r;
+}
diff --git a/tools/kvm/builtin-run.c b/tools/kvm/builtin-run.c
new file mode 100644
index 0000000..4f6ea15
--- /dev/null
+++ b/tools/kvm/builtin-run.c
@@ -0,0 +1,1383 @@
+#include "kvm/builtin-run.h"
+
+#include "kvm/builtin-setup.h"
+#include "kvm/virtio-balloon.h"
+#include "kvm/virtio-console.h"
+#include "kvm/parse-options.h"
+#include "kvm/8250-serial.h"
+#include "kvm/framebuffer.h"
+#include "kvm/disk-image.h"
+#include "kvm/threadpool.h"
+#include "kvm/virtio-blk.h"
+#include "kvm/virtio-net.h"
+#include "kvm/virtio-rng.h"
+#include "kvm/ioeventfd.h"
+#include "kvm/virtio-9p.h"
+#include "kvm/barrier.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/ioport.h"
+#include "kvm/symbol.h"
+#include "kvm/i8042.h"
+#include "kvm/mutex.h"
+#include "kvm/term.h"
+#include "kvm/util.h"
+#include "kvm/strbuf.h"
+#include "kvm/vesa.h"
+#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+#include "kvm/rtc.h"
+#include "kvm/sdl.h"
+#include "kvm/vnc.h"
+#include "kvm/guest_compat.h"
+#include "kvm/pci-shmem.h"
+#include "kvm/kvm-ipc.h"
+#include "kvm/builtin-debug.h"
+
+#include <linux/types.h>
+#include <linux/err.h>
+
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#define DEFAULT_KVM_DEV		"/dev/kvm"
+#define DEFAULT_CONSOLE		"serial"
+#define DEFAULT_NETWORK		"user"
+#define DEFAULT_HOST_ADDR	"192.168.33.1"
+#define DEFAULT_GUEST_ADDR	"192.168.33.15"
+#define DEFAULT_GUEST_MAC	"02:15:15:15:15:15"
+#define DEFAULT_HOST_MAC	"02:01:01:01:01:01"
+#define DEFAULT_SCRIPT		"none"
+const char *DEFAULT_SANDBOX_FILENAME = "guest/sandbox.sh";
+
+#define MB_SHIFT		(20)
+#define KB_SHIFT		(10)
+#define GB_SHIFT		(30)
+#define MIN_RAM_SIZE_MB		(64ULL)
+#define MIN_RAM_SIZE_BYTE	(MIN_RAM_SIZE_MB << MB_SHIFT)
+
+struct kvm *kvm;
+struct kvm_cpu **kvm_cpus;
+__thread struct kvm_cpu *current_kvm_cpu;
+
+static u64 ram_size;
+static u8  image_count;
+static u8 num_net_devices;
+static bool virtio_rng;
+static const char *kernel_cmdline;
+static const char *kernel_filename;
+static const char *vmlinux_filename;
+static const char *initrd_filename;
+static const char *firmware_filename;
+static const char *image_filename[MAX_DISK_IMAGES];
+static const char *console;
+static const char *dev;
+static const char *network;
+static const char *host_ip;
+static const char *guest_ip;
+static const char *guest_mac;
+static const char *host_mac;
+static const char *script;
+static const char *guest_name;
+static const char *sandbox;
+static const char *hugetlbfs_path;
+static const char *custom_rootfs_name = "default";
+static struct virtio_net_params *net_params;
+static bool single_step;
+static bool readonly_image[MAX_DISK_IMAGES];
+static bool vnc;
+static bool sdl;
+static bool balloon;
+static bool using_rootfs;
+static bool custom_rootfs;
+static bool no_net;
+static bool no_dhcp;
+extern bool ioport_debug;
+extern bool mmio_debug;
+static int  kvm_run_wrapper;
+extern int  active_console;
+extern int  debug_iodelay;
+
+bool do_debug_print = false;
+
+static int nrcpus;
+static int vidmode = -1;
+
+static const char * const run_usage[] = {
+	"lkvm run [<options>] [<kernel image>]",
+	NULL
+};
+
+enum {
+	KVM_RUN_DEFAULT,
+	KVM_RUN_SANDBOX,
+};
+
+void kvm_run_set_wrapper_sandbox(void)
+{
+	kvm_run_wrapper = KVM_RUN_SANDBOX;
+}
+
+static int img_name_parser(const struct option *opt, const char *arg, int unset)
+{
+	char *sep;
+	struct stat st;
+	char path[PATH_MAX];
+
+	if (stat(arg, &st) == 0 &&
+	    S_ISDIR(st.st_mode)) {
+		char tmp[PATH_MAX];
+
+		if (using_rootfs)
+			die("Please use only one rootfs directory atmost");
+
+		if (realpath(arg, tmp) == 0 ||
+		    virtio_9p__register(kvm, tmp, "/dev/root") < 0)
+			die("Unable to initialize virtio 9p");
+		using_rootfs = 1;
+		return 0;
+	}
+
+	snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg);
+
+	if (stat(path, &st) == 0 &&
+	    S_ISDIR(st.st_mode)) {
+		char tmp[PATH_MAX];
+
+		if (using_rootfs)
+			die("Please use only one rootfs directory atmost");
+
+		if (realpath(path, tmp) == 0 ||
+		    virtio_9p__register(kvm, tmp, "/dev/root") < 0)
+			die("Unable to initialize virtio 9p");
+		if (virtio_9p__register(kvm, "/", "hostfs") < 0)
+			die("Unable to initialize virtio 9p");
+		kvm_setup_resolv(arg);
+		using_rootfs = custom_rootfs = 1;
+		custom_rootfs_name = arg;
+		return 0;
+	}
+
+	if (image_count >= MAX_DISK_IMAGES)
+		die("Currently only 4 images are supported");
+
+	image_filename[image_count] = arg;
+	sep = strstr(arg, ",");
+	if (sep) {
+		if (strcmp(sep + 1, "ro") == 0)
+			readonly_image[image_count] = 1;
+		*sep = 0;
+	}
+
+	image_count++;
+
+	return 0;
+}
+
+static int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset)
+{
+	char *tag_name;
+	char tmp[PATH_MAX];
+
+	/*
+	 * 9p dir can be of the form dirname,tag_name or
+	 * just dirname. In the later case we use the
+	 * default tag name
+	 */
+	tag_name = strstr(arg, ",");
+	if (tag_name) {
+		*tag_name = '\0';
+		tag_name++;
+	}
+	if (realpath(arg, tmp)) {
+		if (virtio_9p__register(kvm, tmp, tag_name) < 0)
+			die("Unable to initialize virtio 9p");
+	} else
+		die("Failed resolving 9p path");
+	return 0;
+}
+
+static int tty_parser(const struct option *opt, const char *arg, int unset)
+{
+	int tty = atoi(arg);
+
+	term_set_tty(tty);
+
+	return 0;
+}
+
+static inline void str_to_mac(const char *str, char *mac)
+{
+	sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+		mac, mac+1, mac+2, mac+3, mac+4, mac+5);
+}
+static int set_net_param(struct virtio_net_params *p, const char *param,
+				const char *val)
+{
+	if (strcmp(param, "guest_mac") == 0) {
+		str_to_mac(val, p->guest_mac);
+	} else if (strcmp(param, "mode") == 0) {
+		if (!strncmp(val, "user", 4)) {
+			int i;
+
+			for (i = 0; i < num_net_devices; i++)
+				if (net_params[i].mode == NET_MODE_USER)
+					die("Only one usermode network device allowed at a time");
+			p->mode = NET_MODE_USER;
+		} else if (!strncmp(val, "tap", 3)) {
+			p->mode = NET_MODE_TAP;
+		} else if (!strncmp(val, "none", 4)) {
+			no_net = 1;
+			return -1;
+		} else
+			die("Unkown network mode %s, please use user, tap or none", network);
+	} else if (strcmp(param, "script") == 0) {
+		p->script = strdup(val);
+	} else if (strcmp(param, "guest_ip") == 0) {
+		p->guest_ip = strdup(val);
+	} else if (strcmp(param, "host_ip") == 0) {
+		p->host_ip = strdup(val);
+	} else if (strcmp(param, "trans") == 0) {
+		p->trans = strdup(val);
+	} else if (strcmp(param, "vhost") == 0) {
+		p->vhost = atoi(val);
+	} else if (strcmp(param, "fd") == 0) {
+		p->fd = atoi(val);
+	}
+
+	return 0;
+}
+
+static int netdev_parser(const struct option *opt, const char *arg, int unset)
+{
+	struct virtio_net_params p;
+	char *buf = NULL, *cmd = NULL, *cur = NULL;
+	bool on_cmd = true;
+
+	if (arg) {
+		buf = strdup(arg);
+		if (buf == NULL)
+			die("Failed allocating new net buffer");
+		cur = strtok(buf, ",=");
+	}
+
+	p = (struct virtio_net_params) {
+		.guest_ip	= DEFAULT_GUEST_ADDR,
+		.host_ip	= DEFAULT_HOST_ADDR,
+		.script		= DEFAULT_SCRIPT,
+		.mode		= NET_MODE_TAP,
+	};
+
+	str_to_mac(DEFAULT_GUEST_MAC, p.guest_mac);
+	p.guest_mac[5] += num_net_devices;
+
+	while (cur) {
+		if (on_cmd) {
+			cmd = cur;
+		} else {
+			if (set_net_param(&p, cmd, cur) < 0)
+				goto done;
+		}
+		on_cmd = !on_cmd;
+
+		cur = strtok(NULL, ",=");
+	};
+
+	num_net_devices++;
+
+	net_params = realloc(net_params, num_net_devices * sizeof(*net_params));
+	if (net_params == NULL)
+		die("Failed adding new network device");
+
+	net_params[num_net_devices - 1] = p;
+
+done:
+	free(buf);
+	return 0;
+}
+
+static int shmem_parser(const struct option *opt, const char *arg, int unset)
+{
+	const u64 default_size = SHMEM_DEFAULT_SIZE;
+	const u64 default_phys_addr = SHMEM_DEFAULT_ADDR;
+	const char *default_handle = SHMEM_DEFAULT_HANDLE;
+	struct shmem_info *si = malloc(sizeof(struct shmem_info));
+	u64 phys_addr;
+	u64 size;
+	char *handle = NULL;
+	int create = 0;
+	const char *p = arg;
+	char *next;
+	int base = 10;
+	int verbose = 0;
+
+	const int skip_pci = strlen("pci:");
+	if (verbose)
+		pr_info("shmem_parser(%p,%s,%d)", opt, arg, unset);
+	/* parse out optional addr family */
+	if (strcasestr(p, "pci:")) {
+		p += skip_pci;
+	} else if (strcasestr(p, "mem:")) {
+		die("I can't add to E820 map yet.\n");
+	}
+	/* parse out physical addr */
+	base = 10;
+	if (strcasestr(p, "0x"))
+		base = 16;
+	phys_addr = strtoll(p, &next, base);
+	if (next == p && phys_addr == 0) {
+		pr_info("shmem: no physical addr specified, using default.");
+		phys_addr = default_phys_addr;
+	}
+	if (*next != ':' && *next != '\0')
+		die("shmem: unexpected chars after phys addr.\n");
+	if (*next == '\0')
+		p = next;
+	else
+		p = next + 1;
+	/* parse out size */
+	base = 10;
+	if (strcasestr(p, "0x"))
+		base = 16;
+	size = strtoll(p, &next, base);
+	if (next == p && size == 0) {
+		pr_info("shmem: no size specified, using default.");
+		size = default_size;
+	}
+	/* look for [KMGkmg][Bb]*  uses base 2. */
+	int skip_B = 0;
+	if (strspn(next, "KMGkmg")) {	/* might have a prefix */
+		if (*(next + 1) == 'B' || *(next + 1) == 'b')
+			skip_B = 1;
+		switch (*next) {
+		case 'K':
+		case 'k':
+			size = size << KB_SHIFT;
+			break;
+		case 'M':
+		case 'm':
+			size = size << MB_SHIFT;
+			break;
+		case 'G':
+		case 'g':
+			size = size << GB_SHIFT;
+			break;
+		default:
+			die("shmem: bug in detecting size prefix.");
+			break;
+		}
+		next += 1 + skip_B;
+	}
+	if (*next != ':' && *next != '\0') {
+		die("shmem: unexpected chars after phys size. <%c><%c>\n",
+		    *next, *p);
+	}
+	if (*next == '\0')
+		p = next;
+	else
+		p = next + 1;
+	/* parse out optional shmem handle */
+	const int skip_handle = strlen("handle=");
+	next = strcasestr(p, "handle=");
+	if (*p && next) {
+		if (p != next)
+			die("unexpected chars before handle\n");
+		p += skip_handle;
+		next = strchrnul(p, ':');
+		if (next - p) {
+			handle = malloc(next - p + 1);
+			strncpy(handle, p, next - p);
+			handle[next - p] = '\0';	/* just in case. */
+		}
+		if (*next == '\0')
+			p = next;
+		else
+			p = next + 1;
+	}
+	/* parse optional create flag to see if we should create shm seg. */
+	if (*p && strcasestr(p, "create")) {
+		create = 1;
+		p += strlen("create");
+	}
+	if (*p != '\0')
+		die("shmem: unexpected trailing chars\n");
+	if (handle == NULL) {
+		handle = malloc(strlen(default_handle) + 1);
+		strcpy(handle, default_handle);
+	}
+	if (verbose) {
+		pr_info("shmem: phys_addr = %llx", phys_addr);
+		pr_info("shmem: size      = %llx", size);
+		pr_info("shmem: handle    = %s", handle);
+		pr_info("shmem: create    = %d", create);
+	}
+
+	si->phys_addr = phys_addr;
+	si->size = size;
+	si->handle = handle;
+	si->create = create;
+	pci_shmem__register_mem(si);	/* ownership of si, etc. passed on. */
+	return 0;
+}
+
+static const struct option options[] = {
+	OPT_GROUP("Basic options:"),
+	OPT_STRING('\0', "name", &guest_name, "guest name",
+			"A name for the guest"),
+	OPT_INTEGER('c', "cpus", &nrcpus, "Number of CPUs"),
+	OPT_U64('m', "mem", &ram_size, "Virtual machine memory size in MiB."),
+	OPT_CALLBACK('\0', "shmem", NULL,
+		     "[pci:]<addr>:<size>[:handle=<handle>][:create]",
+		     "Share host shmem with guest via pci device",
+		     shmem_parser),
+	OPT_CALLBACK('d', "disk", NULL, "image or rootfs_dir", "Disk image or rootfs directory", img_name_parser),
+	OPT_BOOLEAN('\0', "balloon", &balloon, "Enable virtio balloon"),
+	OPT_BOOLEAN('\0', "vnc", &vnc, "Enable VNC framebuffer"),
+	OPT_BOOLEAN('\0', "sdl", &sdl, "Enable SDL framebuffer"),
+	OPT_BOOLEAN('\0', "rng", &virtio_rng, "Enable virtio Random Number Generator"),
+	OPT_CALLBACK('\0', "9p", NULL, "dir_to_share,tag_name",
+		     "Enable virtio 9p to share files between host and guest", virtio_9p_rootdir_parser),
+	OPT_STRING('\0', "console", &console, "serial, virtio or hv",
+			"Console to use"),
+	OPT_STRING('\0', "dev", &dev, "device_file", "KVM device file"),
+	OPT_CALLBACK('\0', "tty", NULL, "tty id",
+		     "Remap guest TTY into a pty on the host",
+		     tty_parser),
+	OPT_STRING('\0', "sandbox", &sandbox, "script",
+			"Run this script when booting into custom rootfs"),
+	OPT_STRING('\0', "hugetlbfs", &hugetlbfs_path, "path", "Hugetlbfs path"),
+
+	OPT_GROUP("Kernel options:"),
+	OPT_STRING('k', "kernel", &kernel_filename, "kernel",
+			"Kernel to boot in virtual machine"),
+	OPT_STRING('i', "initrd", &initrd_filename, "initrd",
+			"Initial RAM disk image"),
+	OPT_STRING('p', "params", &kernel_cmdline, "params",
+			"Kernel command line arguments"),
+	OPT_STRING('f', "firmware", &firmware_filename, "firmware",
+			"Firmware image to boot in virtual machine"),
+
+	OPT_GROUP("Networking options:"),
+	OPT_CALLBACK_DEFAULT('n', "network", NULL, "network params",
+		     "Create a new guest NIC",
+		     netdev_parser, NULL),
+	OPT_BOOLEAN('\0', "no-dhcp", &no_dhcp, "Disable kernel DHCP in rootfs mode"),
+
+	OPT_GROUP("BIOS options:"),
+	OPT_INTEGER('\0', "vidmode", &vidmode,
+		    "Video mode"),
+
+	OPT_GROUP("Debug options:"),
+	OPT_BOOLEAN('\0', "debug", &do_debug_print,
+			"Enable debug messages"),
+	OPT_BOOLEAN('\0', "debug-single-step", &single_step,
+			"Enable single stepping"),
+	OPT_BOOLEAN('\0', "debug-ioport", &ioport_debug,
+			"Enable ioport debugging"),
+	OPT_BOOLEAN('\0', "debug-mmio", &mmio_debug,
+			"Enable MMIO debugging"),
+	OPT_INTEGER('\0', "debug-iodelay", &debug_iodelay,
+			"Delay IO by millisecond"),
+	OPT_END()
+};
+
+/*
+ * Serialize debug printout so that the output of multiple vcpus does not
+ * get mixed up:
+ */
+static int printout_done;
+
+static void handle_sigusr1(int sig)
+{
+	struct kvm_cpu *cpu = current_kvm_cpu;
+	int fd = kvm_cpu__get_debug_fd();
+
+	if (!cpu || cpu->needs_nmi)
+		return;
+
+	dprintf(fd, "\n #\n # vCPU #%ld's dump:\n #\n", cpu->cpu_id);
+	kvm_cpu__show_registers(cpu);
+	kvm_cpu__show_code(cpu);
+	kvm_cpu__show_page_tables(cpu);
+	fflush(stdout);
+	printout_done = 1;
+	mb();
+}
+
+/* Pause/resume the guest using SIGUSR2 */
+static int is_paused;
+
+static void handle_pause(int fd, u32 type, u32 len, u8 *msg)
+{
+	if (WARN_ON(len))
+		return;
+
+	if (type == KVM_IPC_RESUME && is_paused) {
+		kvm->vm_state = KVM_VMSTATE_RUNNING;
+		kvm__continue();
+	} else if (type == KVM_IPC_PAUSE && !is_paused) {
+		kvm->vm_state = KVM_VMSTATE_PAUSED;
+		kvm__pause();
+	} else {
+		return;
+	}
+
+	is_paused = !is_paused;
+}
+
+static void handle_vmstate(int fd, u32 type, u32 len, u8 *msg)
+{
+	int r = 0;
+
+	if (type == KVM_IPC_VMSTATE)
+		r = write(fd, &kvm->vm_state, sizeof(kvm->vm_state));
+
+	if (r < 0)
+		pr_warning("Failed sending VMSTATE");
+}
+
+static void handle_debug(int fd, u32 type, u32 len, u8 *msg)
+{
+	int i;
+	struct debug_cmd_params *params;
+	u32 dbg_type;
+	u32 vcpu;
+
+	if (WARN_ON(type != KVM_IPC_DEBUG || len != sizeof(*params)))
+		return;
+
+	params = (void *)msg;
+	dbg_type = params->dbg_type;
+	vcpu = params->cpu;
+
+	if (dbg_type & KVM_DEBUG_CMD_TYPE_NMI) {
+		if ((int)vcpu >= kvm->nrcpus)
+			return;
+
+		kvm_cpus[vcpu]->needs_nmi = 1;
+		pthread_kill(kvm_cpus[vcpu]->thread, SIGUSR1);
+	}
+
+	if (!(dbg_type & KVM_DEBUG_CMD_TYPE_DUMP))
+		return;
+
+	for (i = 0; i < nrcpus; i++) {
+		struct kvm_cpu *cpu = kvm_cpus[i];
+
+		if (!cpu)
+			continue;
+
+		printout_done = 0;
+
+		kvm_cpu__set_debug_fd(fd);
+		pthread_kill(cpu->thread, SIGUSR1);
+		/*
+		 * Wait for the vCPU to dump state before signalling
+		 * the next thread. Since this is debug code it does
+		 * not matter that we are burning CPU time a bit:
+		 */
+		while (!printout_done)
+			mb();
+	}
+
+	close(fd);
+
+	serial8250__inject_sysrq(kvm);
+}
+
+static void handle_sigalrm(int sig)
+{
+	kvm__arch_periodic_poll(kvm);
+}
+
+static void handle_stop(int fd, u32 type, u32 len, u8 *msg)
+{
+	if (WARN_ON(type != KVM_IPC_STOP || len))
+		return;
+
+	kvm_cpu__reboot();
+}
+
+static void *kvm_cpu_thread(void *arg)
+{
+	current_kvm_cpu		= arg;
+
+	if (kvm_cpu__start(current_kvm_cpu))
+		goto panic_kvm;
+
+	return (void *) (intptr_t) 0;
+
+panic_kvm:
+	fprintf(stderr, "KVM exit reason: %u (\"%s\")\n",
+		current_kvm_cpu->kvm_run->exit_reason,
+		kvm_exit_reasons[current_kvm_cpu->kvm_run->exit_reason]);
+	if (current_kvm_cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN)
+		fprintf(stderr, "KVM exit code: 0x%Lu\n",
+			current_kvm_cpu->kvm_run->hw.hardware_exit_reason);
+
+	kvm_cpu__set_debug_fd(STDOUT_FILENO);
+	kvm_cpu__show_registers(current_kvm_cpu);
+	kvm_cpu__show_code(current_kvm_cpu);
+	kvm_cpu__show_page_tables(current_kvm_cpu);
+
+	return (void *) (intptr_t) 1;
+}
+
+static char kernel[PATH_MAX];
+
+static const char *host_kernels[] = {
+	"/boot/vmlinuz",
+	"/boot/bzImage",
+	NULL
+};
+
+static const char *default_kernels[] = {
+	"./bzImage",
+	"arch/" BUILD_ARCH "/boot/bzImage",
+	"../../arch/" BUILD_ARCH "/boot/bzImage",
+	NULL
+};
+
+static const char *default_vmlinux[] = {
+	"vmlinux",
+	"../../../vmlinux",
+	"../../vmlinux",
+	NULL
+};
+
+static void kernel_usage_with_options(void)
+{
+	const char **k;
+	struct utsname uts;
+
+	fprintf(stderr, "Fatal: could not find default kernel image in:\n");
+	k = &default_kernels[0];
+	while (*k) {
+		fprintf(stderr, "\t%s\n", *k);
+		k++;
+	}
+
+	if (uname(&uts) < 0)
+		return;
+
+	k = &host_kernels[0];
+	while (*k) {
+		if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0)
+			return;
+		fprintf(stderr, "\t%s\n", kernel);
+		k++;
+	}
+	fprintf(stderr, "\nPlease see '%s run --help' for more options.\n\n",
+		KVM_BINARY_NAME);
+}
+
+static u64 host_ram_size(void)
+{
+	long page_size;
+	long nr_pages;
+
+	nr_pages	= sysconf(_SC_PHYS_PAGES);
+	if (nr_pages < 0) {
+		pr_warning("sysconf(_SC_PHYS_PAGES) failed");
+		return 0;
+	}
+
+	page_size	= sysconf(_SC_PAGE_SIZE);
+	if (page_size < 0) {
+		pr_warning("sysconf(_SC_PAGE_SIZE) failed");
+		return 0;
+	}
+
+	return (nr_pages * page_size) >> MB_SHIFT;
+}
+
+/*
+ * If user didn't specify how much memory it wants to allocate for the guest,
+ * avoid filling the whole host RAM.
+ */
+#define RAM_SIZE_RATIO		0.8
+
+static u64 get_ram_size(int nr_cpus)
+{
+	u64 available;
+	u64 ram_size;
+
+	ram_size	= 64 * (nr_cpus + 3);
+
+	available	= host_ram_size() * RAM_SIZE_RATIO;
+	if (!available)
+		available = MIN_RAM_SIZE_MB;
+
+	if (ram_size > available)
+		ram_size	= available;
+
+	return ram_size;
+}
+
+static const char *find_kernel(void)
+{
+	const char **k;
+	struct stat st;
+	struct utsname uts;
+
+	k = &default_kernels[0];
+	while (*k) {
+		if (stat(*k, &st) < 0 || !S_ISREG(st.st_mode)) {
+			k++;
+			continue;
+		}
+		strncpy(kernel, *k, PATH_MAX);
+		return kernel;
+	}
+
+	if (uname(&uts) < 0)
+		return NULL;
+
+	k = &host_kernels[0];
+	while (*k) {
+		if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0)
+			return NULL;
+
+		if (stat(kernel, &st) < 0 || !S_ISREG(st.st_mode)) {
+			k++;
+			continue;
+		}
+		return kernel;
+
+	}
+	return NULL;
+}
+
+static const char *find_vmlinux(void)
+{
+	const char **vmlinux;
+
+	vmlinux = &default_vmlinux[0];
+	while (*vmlinux) {
+		struct stat st;
+
+		if (stat(*vmlinux, &st) < 0 || !S_ISREG(st.st_mode)) {
+			vmlinux++;
+			continue;
+		}
+		return *vmlinux;
+	}
+	return NULL;
+}
+
+void kvm_run_help(void)
+{
+	usage_with_options(run_usage, options);
+}
+
+static int kvm_custom_stage2(void)
+{
+	char tmp[PATH_MAX], dst[PATH_MAX], *src;
+	const char *rootfs = custom_rootfs_name;
+	int r;
+
+	src = realpath("guest/init_stage2", NULL);
+	if (src == NULL)
+		return -ENOMEM;
+
+	snprintf(tmp, PATH_MAX, "%s%s/virt/init_stage2", kvm__get_dir(), rootfs);
+	remove(tmp);
+
+	snprintf(dst, PATH_MAX, "/host/%s", src);
+	r = symlink(dst, tmp);
+	free(src);
+
+	return r;
+}
+
+static int kvm_run_set_sandbox(void)
+{
+	const char *guestfs_name = custom_rootfs_name;
+	char path[PATH_MAX], script[PATH_MAX], *tmp;
+
+	snprintf(path, PATH_MAX, "%s%s/virt/sandbox.sh", kvm__get_dir(), guestfs_name);
+
+	remove(path);
+
+	if (sandbox == NULL)
+		return 0;
+
+	tmp = realpath(sandbox, NULL);
+	if (tmp == NULL)
+		return -ENOMEM;
+
+	snprintf(script, PATH_MAX, "/host/%s", tmp);
+	free(tmp);
+
+	return symlink(script, path);
+}
+
+static void kvm_write_sandbox_cmd_exactly(int fd, const char *arg)
+{
+	const char *single_quote;
+
+	if (!*arg) { /* zero length string */
+		if (write(fd, "''", 2) <= 0)
+			die("Failed writing sandbox script");
+		return;
+	}
+
+	while (*arg) {
+		single_quote = strchrnul(arg, '\'');
+
+		/* write non-single-quote string as #('string') */
+		if (arg != single_quote) {
+			if (write(fd, "'", 1) <= 0 ||
+			    write(fd, arg, single_quote - arg) <= 0 ||
+			    write(fd, "'", 1) <= 0)
+				die("Failed writing sandbox script");
+		}
+
+		/* write single quote as #("'") */
+		if (*single_quote) {
+			if (write(fd, "\"'\"", 3) <= 0)
+				die("Failed writing sandbox script");
+		} else
+			break;
+
+		arg = single_quote + 1;
+	}
+}
+
+static void resolve_program(const char *src, char *dst, size_t len)
+{
+	struct stat st;
+	int err;
+
+	err = stat(src, &st);
+
+	if (!err && S_ISREG(st.st_mode)) {
+		char resolved_path[PATH_MAX];
+
+		if (!realpath(src, resolved_path))
+			die("Unable to resolve program %s: %s\n", src, strerror(errno));
+
+		snprintf(dst, len, "/host%s", resolved_path);
+	} else
+		strncpy(dst, src, len);
+}
+
+static void kvm_run_write_sandbox_cmd(const char **argv, int argc)
+{
+	const char script_hdr[] = "#! /bin/bash\n\n";
+	char program[PATH_MAX];
+	int fd;
+
+	remove(sandbox);
+
+	fd = open(sandbox, O_RDWR | O_CREAT, 0777);
+	if (fd < 0)
+		die("Failed creating sandbox script");
+
+	if (write(fd, script_hdr, sizeof(script_hdr) - 1) <= 0)
+		die("Failed writing sandbox script");
+
+	resolve_program(argv[0], program, PATH_MAX);
+	kvm_write_sandbox_cmd_exactly(fd, program);
+
+	argv++;
+	argc--;
+
+	while (argc) {
+		if (write(fd, " ", 1) <= 0)
+			die("Failed writing sandbox script");
+
+		kvm_write_sandbox_cmd_exactly(fd, argv[0]);
+		argv++;
+		argc--;
+	}
+	if (write(fd, "\n", 1) <= 0)
+		die("Failed writing sandbox script");
+
+	close(fd);
+}
+
+static int kvm_cmd_run_init(int argc, const char **argv)
+{
+	static char real_cmdline[2048], default_name[20];
+	struct framebuffer *fb = NULL;
+	unsigned int nr_online_cpus;
+	int max_cpus, recommended_cpus;
+	int i, r;
+
+	signal(SIGALRM, handle_sigalrm);
+	kvm_ipc__register_handler(KVM_IPC_DEBUG, handle_debug);
+	signal(SIGUSR1, handle_sigusr1);
+	kvm_ipc__register_handler(KVM_IPC_PAUSE, handle_pause);
+	kvm_ipc__register_handler(KVM_IPC_RESUME, handle_pause);
+	kvm_ipc__register_handler(KVM_IPC_STOP, handle_stop);
+	kvm_ipc__register_handler(KVM_IPC_VMSTATE, handle_vmstate);
+
+	nr_online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+	while (argc != 0) {
+		argc = parse_options(argc, argv, options, run_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION |
+				PARSE_OPT_KEEP_DASHDASH);
+		if (argc != 0) {
+			/* Cusrom options, should have been handled elsewhere */
+			if (strcmp(argv[0], "--") == 0) {
+				if (kvm_run_wrapper == KVM_RUN_SANDBOX) {
+					sandbox = DEFAULT_SANDBOX_FILENAME;
+					kvm_run_write_sandbox_cmd(argv+1, argc-1);
+					break;
+				}
+			}
+
+			if ((kvm_run_wrapper == KVM_RUN_DEFAULT && kernel_filename) ||
+				(kvm_run_wrapper == KVM_RUN_SANDBOX && sandbox)) {
+				fprintf(stderr, "Cannot handle parameter: "
+						"%s\n", argv[0]);
+				usage_with_options(run_usage, options);
+				return EINVAL;
+			}
+			if (kvm_run_wrapper == KVM_RUN_SANDBOX) {
+				/*
+				 * first unhandled parameter is treated as
+				 * sandbox command
+				 */
+				sandbox = DEFAULT_SANDBOX_FILENAME;
+				kvm_run_write_sandbox_cmd(argv, argc);
+			} else {
+				/*
+				 * first unhandled parameter is treated as a kernel
+				 * image
+				 */
+				kernel_filename = argv[0];
+			}
+			argv++;
+			argc--;
+		}
+
+	}
+
+	if (!kernel_filename)
+		kernel_filename = find_kernel();
+
+	if (!kernel_filename) {
+		kernel_usage_with_options();
+		return EINVAL;
+	}
+
+	vmlinux_filename = find_vmlinux();
+
+	if (nrcpus == 0)
+		nrcpus = nr_online_cpus;
+
+	if (!ram_size)
+		ram_size	= get_ram_size(nrcpus);
+
+	if (ram_size < MIN_RAM_SIZE_MB)
+		die("Not enough memory specified: %lluMB (min %lluMB)", ram_size, MIN_RAM_SIZE_MB);
+
+	if (ram_size > host_ram_size())
+		pr_warning("Guest memory size %lluMB exceeds host physical RAM size %lluMB", ram_size, host_ram_size());
+
+	ram_size <<= MB_SHIFT;
+
+	if (!dev)
+		dev = DEFAULT_KVM_DEV;
+
+	if (!console)
+		console = DEFAULT_CONSOLE;
+
+	if (!strncmp(console, "virtio", 6))
+		active_console  = CONSOLE_VIRTIO;
+	else if (!strncmp(console, "serial", 6))
+		active_console  = CONSOLE_8250;
+	else if (!strncmp(console, "hv", 2))
+		active_console = CONSOLE_HV;
+	else
+		pr_warning("No console!");
+
+	if (!host_ip)
+		host_ip = DEFAULT_HOST_ADDR;
+
+	if (!guest_ip)
+		guest_ip = DEFAULT_GUEST_ADDR;
+
+	if (!guest_mac)
+		guest_mac = DEFAULT_GUEST_MAC;
+
+	if (!host_mac)
+		host_mac = DEFAULT_HOST_MAC;
+
+	if (!script)
+		script = DEFAULT_SCRIPT;
+
+	term_init();
+
+	if (!guest_name) {
+		if (custom_rootfs) {
+			guest_name = custom_rootfs_name;
+		} else {
+			sprintf(default_name, "guest-%u", getpid());
+			guest_name = default_name;
+		}
+	}
+
+	kvm = kvm__init(dev, hugetlbfs_path, ram_size, guest_name);
+	if (IS_ERR(kvm)) {
+		r = PTR_ERR(kvm);
+		goto fail;
+	}
+
+	kvm->single_step = single_step;
+
+	r = ioeventfd__init(kvm);
+	if (r < 0) {
+		pr_err("ioeventfd__init() failed with error %d\n", r);
+		goto fail;
+	}
+
+	max_cpus = kvm__max_cpus(kvm);
+	recommended_cpus = kvm__recommended_cpus(kvm);
+
+	if (nrcpus > max_cpus) {
+		printf("  # Limit the number of CPUs to %d\n", max_cpus);
+		nrcpus = max_cpus;
+	} else if (nrcpus > recommended_cpus) {
+		printf("  # Warning: The maximum recommended amount of VCPUs"
+			" is %d\n", recommended_cpus);
+	}
+
+	kvm->nrcpus = nrcpus;
+
+	/* Alloc one pointer too many, so array ends up 0-terminated */
+	kvm_cpus = calloc(nrcpus + 1, sizeof(void *));
+	if (!kvm_cpus)
+		die("Couldn't allocate array for %d CPUs", nrcpus);
+
+	r = irq__init(kvm);
+	if (r < 0) {
+		pr_err("irq__init() failed with error %d\n", r);
+		goto fail;
+	}
+
+	r = pci__init(kvm);
+	if (r < 0) {
+		pr_err("pci__init() failed with error %d\n", r);
+		goto fail;
+	}
+
+	r = ioport__init(kvm);
+	if (r < 0) {
+		pr_err("ioport__init() failed with error %d\n", r);
+		goto fail;
+	}
+
+	/*
+	 * vidmode should be either specified
+	 * either set by default
+	 */
+	if (vnc || sdl) {
+		if (vidmode == -1)
+			vidmode = 0x312;
+	} else {
+		vidmode = 0;
+	}
+
+	memset(real_cmdline, 0, sizeof(real_cmdline));
+	kvm__arch_set_cmdline(real_cmdline, vnc || sdl);
+
+	if (strlen(real_cmdline) > 0)
+		strcat(real_cmdline, " ");
+
+	if (kernel_cmdline)
+		strlcat(real_cmdline, kernel_cmdline, sizeof(real_cmdline));
+
+	if (!using_rootfs && !image_filename[0] && !initrd_filename) {
+		char tmp[PATH_MAX];
+
+		kvm_setup_create_new(custom_rootfs_name);
+		kvm_setup_resolv(custom_rootfs_name);
+
+		snprintf(tmp, PATH_MAX, "%s%s", kvm__get_dir(), "default");
+		if (virtio_9p__register(kvm, tmp, "/dev/root") < 0)
+			die("Unable to initialize virtio 9p");
+		if (virtio_9p__register(kvm, "/", "hostfs") < 0)
+			die("Unable to initialize virtio 9p");
+		using_rootfs = custom_rootfs = 1;
+	}
+
+	if (using_rootfs) {
+		strcat(real_cmdline, " root=/dev/root rw rootflags=rw,trans=virtio,version=9p2000.L rootfstype=9p");
+		if (custom_rootfs) {
+			kvm_run_set_sandbox();
+
+			strcat(real_cmdline, " init=/virt/init");
+
+			if (!no_dhcp)
+				strcat(real_cmdline, "  ip=dhcp");
+			if (kvm_custom_stage2())
+				die("Failed linking stage 2 of init.");
+		}
+	} else if (!strstr(real_cmdline, "root=")) {
+		strlcat(real_cmdline, " root=/dev/vda rw ", sizeof(real_cmdline));
+	}
+
+	if (image_count) {
+		kvm->nr_disks = image_count;
+		kvm->disks = disk_image__open_all(image_filename, readonly_image, image_count);
+		if (IS_ERR(kvm->disks)) {
+			r = PTR_ERR(kvm->disks);
+			pr_err("disk_image__open_all() failed with error %ld\n",
+					PTR_ERR(kvm->disks));
+			goto fail;
+		}
+	}
+
+	printf("  # %s run -k %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME,
+		kernel_filename, ram_size / 1024 / 1024, nrcpus, guest_name);
+
+	if (!firmware_filename) {
+		if (!kvm__load_kernel(kvm, kernel_filename,
+				initrd_filename, real_cmdline, vidmode))
+			die("unable to load kernel %s", kernel_filename);
+
+		kvm->vmlinux = vmlinux_filename;
+		r = symbol_init(kvm);
+		if (r < 0)
+			pr_debug("symbol_init() failed with error %d\n", r);
+	}
+
+	ioport__setup_arch();
+
+	r = rtc__init(kvm);
+	if (r < 0) {
+		pr_err("rtc__init() failed with error %d\n", r);
+		goto fail;
+	}
+
+	r = serial8250__init(kvm);
+	if (r < 0) {
+		pr_err("serial__init() failed with error %d\n", r);
+		goto fail;
+	}
+
+	r = virtio_blk__init(kvm);
+	if (r < 0) {
+		pr_err("virtio_blk__init() failed with error %d\n", r);
+		goto fail;
+	}
+
+	if (active_console == CONSOLE_VIRTIO)
+		virtio_console__init(kvm);
+
+	if (virtio_rng)
+		virtio_rng__init(kvm);
+
+	if (balloon)
+		virtio_bln__init(kvm);
+
+	if (!network)
+		network = DEFAULT_NETWORK;
+
+	virtio_9p__init(kvm);
+
+	for (i = 0; i < num_net_devices; i++) {
+		net_params[i].kvm = kvm;
+		virtio_net__init(&net_params[i]);
+	}
+
+	if (num_net_devices == 0 && no_net == 0) {
+		struct virtio_net_params net_params;
+
+		net_params = (struct virtio_net_params) {
+			.guest_ip	= guest_ip,
+			.host_ip	= host_ip,
+			.kvm		= kvm,
+			.script		= script,
+			.mode		= NET_MODE_USER,
+		};
+		str_to_mac(guest_mac, net_params.guest_mac);
+		str_to_mac(host_mac, net_params.host_mac);
+
+		virtio_net__init(&net_params);
+	}
+
+	kvm__init_ram(kvm);
+
+#ifdef CONFIG_X86
+	kbd__init(kvm);
+#endif
+
+	pci_shmem__init(kvm);
+
+	if (vnc || sdl) {
+		fb = vesa__init(kvm);
+		if (IS_ERR(fb)) {
+			pr_err("vesa__init() failed with error %ld\n", PTR_ERR(fb));
+			goto fail;
+		}
+	}
+
+	if (vnc && fb) {
+		r = vnc__init(fb);
+		if (r < 0) {
+			pr_err("vnc__init() failed with error %d\n", r);
+			goto fail;
+		}
+	}
+
+	if (sdl && fb) {
+		sdl__init(fb);
+		if (r < 0) {
+			pr_err("sdl__init() failed with error %d\n", r);
+			goto fail;
+		}
+	}
+
+	r = fb__start();
+	if (r < 0) {
+		pr_err("fb__init() failed with error %d\n", r);
+		goto fail;
+	}
+
+	/* Device init all done; firmware init must
+	 * come after this (it may set up device trees etc.)
+	 */
+
+	kvm__start_timer(kvm);
+
+	if (firmware_filename) {
+		if (!kvm__load_firmware(kvm, firmware_filename))
+			die("unable to load firmware image %s: %s", firmware_filename, strerror(errno));
+	} else {
+		kvm__arch_setup_firmware(kvm);
+		if (r < 0) {
+			pr_err("kvm__arch_setup_firmware() failed with error %d\n", r);
+			goto fail;
+		}
+	}
+
+	for (i = 0; i < nrcpus; i++) {
+		kvm_cpus[i] = kvm_cpu__init(kvm, i);
+		if (!kvm_cpus[i])
+			die("unable to initialize KVM VCPU");
+	}
+
+	thread_pool__init(nr_online_cpus);
+fail:
+	return r;
+}
+
+static int kvm_cmd_run_work(void)
+{
+	int i, r = -1;
+	void *ret = NULL;
+
+	for (i = 0; i < nrcpus; i++) {
+		if (pthread_create(&kvm_cpus[i]->thread, NULL, kvm_cpu_thread, kvm_cpus[i]) != 0)
+			die("unable to create KVM VCPU thread");
+	}
+
+	/* Only VCPU #0 is going to exit by itself when shutting down */
+	if (pthread_join(kvm_cpus[0]->thread, &ret) != 0)
+		r = 0;
+
+	kvm_cpu__delete(kvm_cpus[0]);
+	kvm_cpus[0] = NULL;
+
+	for (i = 1; i < nrcpus; i++) {
+		if (kvm_cpus[i]->is_running) {
+			pthread_kill(kvm_cpus[i]->thread, SIGKVMEXIT);
+			if (pthread_join(kvm_cpus[i]->thread, &ret) != 0)
+				die("pthread_join");
+			kvm_cpu__delete(kvm_cpus[i]);
+		}
+		if (ret == NULL)
+			r = 0;
+	}
+
+	return r;
+}
+
+static void kvm_cmd_run_exit(int guest_ret)
+{
+	int r = 0;
+
+	compat__print_all_messages();
+
+	r = symbol_exit(kvm);
+	if (r < 0)
+		pr_warning("symbol_exit() failed with error %d\n", r);
+
+	r = irq__exit(kvm);
+	if (r < 0)
+		pr_warning("irq__exit() failed with error %d\n", r);
+
+	fb__stop();
+
+	r = virtio_blk__exit(kvm);
+	if (r < 0)
+		pr_warning("virtio_blk__exit() failed with error %d\n", r);
+
+	r = virtio_rng__exit(kvm);
+	if (r < 0)
+		pr_warning("virtio_rng__exit() failed with error %d\n", r);
+
+	r = disk_image__close_all(kvm->disks, image_count);
+	if (r < 0)
+		pr_warning("disk_image__close_all() failed with error %d\n", r);
+
+	r = serial8250__exit(kvm);
+	if (r < 0)
+		pr_warning("serial8250__exit() failed with error %d\n", r);
+
+	r = rtc__exit(kvm);
+	if (r < 0)
+		pr_warning("rtc__exit() failed with error %d\n", r);
+
+	r = kvm__arch_free_firmware(kvm);
+	if (r < 0)
+		pr_warning("kvm__arch_free_firmware() failed with error %d\n", r);
+
+	r = ioport__exit(kvm);
+	if (r < 0)
+		pr_warning("ioport__exit() failed with error %d\n", r);
+
+	r = ioeventfd__exit(kvm);
+	if (r < 0)
+		pr_warning("ioeventfd__exit() failed with error %d\n", r);
+
+	r = pci__exit(kvm);
+	if (r < 0)
+		pr_warning("pci__exit() failed with error %d\n", r);
+
+	r = kvm__exit(kvm);
+	if (r < 0)
+		pr_warning("pci__exit() failed with error %d\n", r);
+
+	free(kvm_cpus);
+
+	if (guest_ret == 0)
+		printf("\n  # KVM session ended normally.\n");
+}
+
+int kvm_cmd_run(int argc, const char **argv, const char *prefix)
+{
+	int r, ret = -EFAULT;
+
+	r = kvm_cmd_run_init(argc, argv);
+	if (r < 0)
+		return r;
+
+	ret = kvm_cmd_run_work();
+	kvm_cmd_run_exit(ret);
+
+	return ret;
+}
diff --git a/tools/kvm/builtin-sandbox.c b/tools/kvm/builtin-sandbox.c
new file mode 100644
index 0000000..433f536
--- /dev/null
+++ b/tools/kvm/builtin-sandbox.c
@@ -0,0 +1,9 @@
+#include "kvm/builtin-sandbox.h"
+#include "kvm/builtin-run.h"
+
+int kvm_cmd_sandbox(int argc, const char **argv, const char *prefix)
+{
+	kvm_run_set_wrapper_sandbox();
+
+	return kvm_cmd_run(argc, argv, prefix);
+}
diff --git a/tools/kvm/builtin-setup.c b/tools/kvm/builtin-setup.c
new file mode 100644
index 0000000..232aa60
--- /dev/null
+++ b/tools/kvm/builtin-setup.c
@@ -0,0 +1,232 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-setup.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+static const char *instance_name;
+
+static const char * const setup_usage[] = {
+	"lkvm setup [name]",
+	NULL
+};
+
+static const struct option setup_options[] = {
+	OPT_END()
+};
+
+static void parse_setup_options(int argc, const char **argv)
+{
+	while (argc != 0) {
+		argc = parse_options(argc, argv, setup_options, setup_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION);
+		if (argc != 0 && instance_name)
+			kvm_setup_help();
+		else
+			instance_name = argv[0];
+		argv++;
+		argc--;
+	}
+}
+
+void kvm_setup_help(void)
+{
+	printf("\n%s setup creates a new rootfs under %s.\n"
+		"This can be used later by the '-d' parameter of '%s run'.\n",
+		KVM_BINARY_NAME, kvm__get_dir(), KVM_BINARY_NAME);
+	usage_with_options(setup_usage, setup_options);
+}
+
+static int copy_file(const char *from, const char *to)
+{
+	int in_fd, out_fd;
+	void *src, *dst;
+	struct stat st;
+	int err = -1;
+
+	in_fd = open(from, O_RDONLY);
+	if (in_fd < 0)
+		return err;
+
+	if (fstat(in_fd, &st) < 0)
+		goto error_close_in;
+
+	out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
+	if (out_fd < 0)
+		goto error_close_in;
+
+	src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0);
+	if (src == MAP_FAILED)
+		goto error_close_out;
+
+	if (ftruncate(out_fd, st.st_size) < 0)
+		goto error_munmap_src;
+
+	dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0);
+	if (dst == MAP_FAILED)
+		goto error_munmap_src;
+
+	memcpy(dst, src, st.st_size);
+
+	if (fsync(out_fd) < 0)
+		goto error_munmap_dst;
+
+	err = 0;
+
+error_munmap_dst:
+	munmap(dst, st.st_size);
+error_munmap_src:
+	munmap(src, st.st_size);
+error_close_out:
+	close(out_fd);
+error_close_in:
+	close(in_fd);
+
+	return err;
+}
+
+static const char *guestfs_dirs[] = {
+	"/dev",
+	"/etc",
+	"/home",
+	"/host",
+	"/proc",
+	"/root",
+	"/sys",
+	"/tmp",
+	"/var",
+	"/var/lib",
+	"/virt",
+};
+
+static const char *guestfs_symlinks[] = {
+	"/bin",
+	"/lib",
+	"/lib64",
+	"/sbin",
+	"/usr",
+	"/etc/ld.so.conf",
+};
+
+static int copy_init(const char *guestfs_name)
+{
+	char path[PATH_MAX];
+
+	snprintf(path, PATH_MAX, "%s%s/virt/init", kvm__get_dir(), guestfs_name);
+
+	return copy_file("guest/init", path);
+}
+
+static int copy_passwd(const char *guestfs_name)
+{
+	char path[PATH_MAX];
+
+	snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name);
+
+	return copy_file("guest/passwd", path);
+}
+
+static int make_guestfs_symlink(const char *guestfs_name, const char *path)
+{
+	char target[PATH_MAX];
+	char name[PATH_MAX];
+
+	snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path);
+
+	snprintf(target, PATH_MAX, "/host%s", path);
+
+	return symlink(target, name);
+}
+
+static int make_dir(const char *dir)
+{
+	char name[PATH_MAX];
+
+	snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir);
+
+	return mkdir(name, 0777);
+}
+
+static void make_guestfs_dir(const char *guestfs_name, const char *dir)
+{
+	char name[PATH_MAX];
+
+	snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir);
+
+	make_dir(name);
+}
+
+void kvm_setup_resolv(const char *guestfs_name)
+{
+	char path[PATH_MAX];
+
+	snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name);
+
+	copy_file("/etc/resolv.conf", path);
+}
+
+static int do_setup(const char *guestfs_name)
+{
+	unsigned int i;
+	int ret;
+
+	ret = make_dir(guestfs_name);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++)
+		make_guestfs_dir(guestfs_name, guestfs_dirs[i]);
+
+	for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) {
+		make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]);
+	}
+
+	ret = copy_init(guestfs_name);
+	if (ret < 0)
+		return ret;
+
+	return copy_passwd(guestfs_name);
+}
+
+int kvm_setup_create_new(const char *guestfs_name)
+{
+	return do_setup(guestfs_name);
+}
+
+int kvm_cmd_setup(int argc, const char **argv, const char *prefix)
+{
+	int r;
+
+	parse_setup_options(argc, argv);
+
+	if (instance_name == NULL)
+		kvm_setup_help();
+
+	r = do_setup(instance_name);
+	if (r == 0)
+		printf("A new rootfs '%s' has been created in '%s%s'.\n\n"
+			"You can now start it by running the following command:\n\n"
+			"  %s run -d %s\n",
+			instance_name, kvm__get_dir(), instance_name,
+			KVM_BINARY_NAME,instance_name);
+	else
+		printf("Unable to create rootfs in %s%s: %s\n",
+			kvm__get_dir(), instance_name, strerror(errno));
+
+	return r;
+}
diff --git a/tools/kvm/builtin-stat.c b/tools/kvm/builtin-stat.c
new file mode 100644
index 0000000..ffd72e8
--- /dev/null
+++ b/tools/kvm/builtin-stat.c
@@ -0,0 +1,127 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-stat.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+
+#include <sys/select.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include <linux/virtio_balloon.h>
+
+static bool mem;
+static bool all;
+static const char *instance_name;
+
+static const char * const stat_usage[] = {
+	"lkvm stat [command] [--all] [-n name]",
+	NULL
+};
+
+static const struct option stat_options[] = {
+	OPT_GROUP("Commands options:"),
+	OPT_BOOLEAN('m', "memory", &mem, "Display memory statistics"),
+	OPT_GROUP("Instance options:"),
+	OPT_BOOLEAN('a', "all", &all, "All instances"),
+	OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+	OPT_END()
+};
+
+static void parse_stat_options(int argc, const char **argv)
+{
+	while (argc != 0) {
+		argc = parse_options(argc, argv, stat_options, stat_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION);
+		if (argc != 0)
+			kvm_stat_help();
+	}
+}
+
+void kvm_stat_help(void)
+{
+	usage_with_options(stat_usage, stat_options);
+}
+
+static int do_memstat(const char *name, int sock)
+{
+	struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
+	fd_set fdset;
+	struct timeval t = { .tv_sec = 1 };
+	int r;
+	u8 i;
+
+	FD_ZERO(&fdset);
+	FD_SET(sock, &fdset);
+	r = kvm_ipc__send(sock, KVM_IPC_STAT);
+	if (r < 0)
+		return r;
+
+	r = select(1, &fdset, NULL, NULL, &t);
+	if (r < 0) {
+		pr_err("Could not retrieve mem stats from %s", name);
+		return r;
+	}
+	r = read(sock, &stats, sizeof(stats));
+	if (r < 0)
+		return r;
+
+	printf("\n\n\t*** Guest memory statistics ***\n\n");
+	for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) {
+		switch (stats[i].tag) {
+		case VIRTIO_BALLOON_S_SWAP_IN:
+			printf("The amount of memory that has been swapped in (in bytes):");
+			break;
+		case VIRTIO_BALLOON_S_SWAP_OUT:
+			printf("The amount of memory that has been swapped out to disk (in bytes):");
+			break;
+		case VIRTIO_BALLOON_S_MAJFLT:
+			printf("The number of major page faults that have occurred:");
+			break;
+		case VIRTIO_BALLOON_S_MINFLT:
+			printf("The number of minor page faults that have occurred:");
+			break;
+		case VIRTIO_BALLOON_S_MEMFREE:
+			printf("The amount of memory not being used for any purpose (in bytes):");
+			break;
+		case VIRTIO_BALLOON_S_MEMTOT:
+			printf("The total amount of memory available (in bytes):");
+			break;
+		}
+		printf("%llu\n", stats[i].val);
+	}
+	printf("\n");
+
+	return 0;
+}
+
+int kvm_cmd_stat(int argc, const char **argv, const char *prefix)
+{
+	int instance;
+	int r = 0;
+
+	parse_stat_options(argc, argv);
+
+	if (!mem)
+		usage_with_options(stat_usage, stat_options);
+
+	if (mem && all)
+		return kvm__enumerate_instances(do_memstat);
+
+	if (instance_name == NULL)
+		kvm_stat_help();
+
+	instance = kvm__get_sock_by_instance(instance_name);
+
+	if (instance <= 0)
+		die("Failed locating instance");
+
+	if (mem)
+		r = do_memstat(instance_name, instance);
+
+	close(instance);
+
+	return r;
+}
diff --git a/tools/kvm/builtin-stop.c b/tools/kvm/builtin-stop.c
new file mode 100644
index 0000000..6067630
--- /dev/null
+++ b/tools/kvm/builtin-stop.c
@@ -0,0 +1,70 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-stop.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+static bool all;
+static const char *instance_name;
+
+static const char * const stop_usage[] = {
+	"lkvm stop [--all] [-n name]",
+	NULL
+};
+
+static const struct option stop_options[] = {
+	OPT_GROUP("General options:"),
+	OPT_BOOLEAN('a', "all", &all, "Stop all instances"),
+	OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+	OPT_END()
+};
+
+static void parse_stop_options(int argc, const char **argv)
+{
+	while (argc != 0) {
+		argc = parse_options(argc, argv, stop_options, stop_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION);
+		if (argc != 0)
+			kvm_stop_help();
+	}
+}
+
+void kvm_stop_help(void)
+{
+	usage_with_options(stop_usage, stop_options);
+}
+
+static int do_stop(const char *name, int sock)
+{
+	return kvm_ipc__send(sock, KVM_IPC_STOP);
+}
+
+int kvm_cmd_stop(int argc, const char **argv, const char *prefix)
+{
+	int instance;
+	int r;
+
+	parse_stop_options(argc, argv);
+
+	if (all)
+		return kvm__enumerate_instances(do_stop);
+
+	if (instance_name == NULL)
+		kvm_stop_help();
+
+	instance = kvm__get_sock_by_instance(instance_name);
+
+	if (instance <= 0)
+		die("Failed locating instance");
+
+	r = do_stop(instance_name, instance);
+
+	close(instance);
+
+	return r;
+}
diff --git a/tools/kvm/builtin-version.c b/tools/kvm/builtin-version.c
new file mode 100644
index 0000000..b8bb859
--- /dev/null
+++ b/tools/kvm/builtin-version.c
@@ -0,0 +1,15 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-version.h>
+#include <kvm/kvm.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+int kvm_cmd_version(int argc, const char **argv, const char *prefix)
+{
+	printf("kvm tool %s\n", KVMTOOLS_VERSION);
+
+	return 0;
+}
diff --git a/tools/kvm/code16gcc.h b/tools/kvm/code16gcc.h
new file mode 100644
index 0000000..d93e480
--- /dev/null
+++ b/tools/kvm/code16gcc.h
@@ -0,0 +1,15 @@
+/*
+ * code16gcc.h
+ *
+ * This file is -include'd when compiling 16-bit C code.
+ * Note: this asm() needs to be emitted before gcc emits any code.
+ * Depending on gcc version, this requires -fno-unit-at-a-time or
+ * -fno-toplevel-reorder.
+ *
+ * Hopefully gcc will eventually have a real -m16 option so we can
+ * drop this hack long term.
+ */
+
+#ifndef __ASSEMBLY__
+asm(".code16gcc");
+#endif
diff --git a/tools/kvm/command-list.txt b/tools/kvm/command-list.txt
new file mode 100644
index 0000000..d93597d
--- /dev/null
+++ b/tools/kvm/command-list.txt
@@ -0,0 +1,15 @@
+#
+# List of known perf commands.
+# command name			category [deprecated] [common]
+#
+lkvm-run			mainporcelain common
+lkvm-setup			mainporcelain common
+lkvm-pause			common
+lkvm-resume			common
+lkvm-version			common
+lkvm-list			common
+lkvm-debug			common
+lkvm-balloon			common
+lkvm-stop			common
+lkvm-stat			common
+lkvm-sandbox			common
diff --git a/tools/kvm/config/feature-tests.mak b/tools/kvm/config/feature-tests.mak
new file mode 100644
index 0000000..4a81f56
--- /dev/null
+++ b/tools/kvm/config/feature-tests.mak
@@ -0,0 +1,177 @@
+define SOURCE_HELLO
+#include <stdio.h>
+int main(void)
+{
+	return puts(\"hi\");
+}
+endef
+
+ifndef NO_DWARF
+define SOURCE_DWARF
+#include <dwarf.h>
+#include <elfutils/libdw.h>
+#include <elfutils/version.h>
+#ifndef _ELFUTILS_PREREQ
+#error
+#endif
+
+int main(void)
+{
+	Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
+	return (long)dbg;
+}
+endef
+endif
+
+define SOURCE_LIBELF
+#include <libelf.h>
+
+int main(void)
+{
+	Elf *elf = elf_begin(0, ELF_C_READ, 0);
+	return (long)elf;
+}
+endef
+
+define SOURCE_GLIBC
+#include <gnu/libc-version.h>
+
+int main(void)
+{
+	const char *version = gnu_get_libc_version();
+	return (long)version;
+}
+endef
+
+define SOURCE_ELF_MMAP
+#include <libelf.h>
+int main(void)
+{
+	Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0);
+	return (long)elf;
+}
+endef
+
+ifndef NO_NEWT
+define SOURCE_NEWT
+#include <newt.h>
+
+int main(void)
+{
+	newtInit();
+	newtCls();
+	return newtFinished();
+}
+endef
+endif
+
+ifndef NO_LIBPERL
+define SOURCE_PERL_EMBED
+#include <EXTERN.h>
+#include <perl.h>
+
+int main(void)
+{
+perl_alloc();
+return 0;
+}
+endef
+endif
+
+ifndef NO_LIBPYTHON
+define SOURCE_PYTHON_VERSION
+#include <Python.h>
+#if PY_VERSION_HEX >= 0x03000000
+	#error
+#endif
+int main(void){}
+endef
+define SOURCE_PYTHON_EMBED
+#include <Python.h>
+int main(void)
+{
+	Py_Initialize();
+	return 0;
+}
+endef
+endif
+
+define SOURCE_BFD
+#include <bfd.h>
+
+int main(void)
+{
+	bfd_demangle(0, 0, 0);
+	return 0;
+}
+endef
+
+define SOURCE_CPLUS_DEMANGLE
+extern char *cplus_demangle(const char *, int);
+
+int main(void)
+{
+	cplus_demangle(0, 0);
+	return 0;
+}
+endef
+
+define SOURCE_STRLCPY
+#include <stdlib.h>
+extern size_t strlcpy(char *dest, const char *src, size_t size);
+
+int main(void)
+{
+	strlcpy(NULL, NULL, 0);
+	return 0;
+}
+endef
+
+define SOURCE_VNCSERVER
+#include <rfb/rfb.h>
+
+int main(void)
+{
+	rfbIsActive((void *)0);
+	return 0;
+}
+endef
+
+define SOURCE_SDL
+#include <SDL/SDL.h>
+
+int main(void)
+{
+	SDL_Init(SDL_INIT_VIDEO);
+	return 0;
+}
+endef
+
+define SOURCE_ZLIB
+#include <zlib.h>
+
+int main(void)
+{
+	inflateInit2(NULL, 0);
+	return 0;
+}
+endef
+
+define SOURCE_AIO
+#include <libaio.h>
+
+int main(void)
+{
+	io_setup(0, NULL);
+	return 0;
+}
+endef
+
+define SOURCE_STATIC
+#include <stdlib.h>
+
+int main(void)
+{
+	return 0;
+}
+endef
diff --git a/tools/kvm/config/utilities.mak b/tools/kvm/config/utilities.mak
new file mode 100644
index 0000000..a70963b
--- /dev/null
+++ b/tools/kvm/config/utilities.mak
@@ -0,0 +1,196 @@
+# This allows us to work with the newline character:
+define newline
+
+
+endef
+newline := $(newline)
+
+# nl-escape
+#
+# Usage: escape = $(call nl-escape[,escape])
+#
+# This is used as the common way to specify
+# what should replace a newline when escaping
+# newlines; the default is a bizarre string.
+#
+nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n)
+
+# escape-nl
+#
+# Usage: escaped-text = $(call escape-nl,text[,escape])
+#
+# GNU make's $(shell ...) function converts to a
+# single space each newline character in the output
+# produced during the expansion; this may not be
+# desirable.
+#
+# The only solution is to change each newline into
+# something that won't be converted, so that the
+# information can be recovered later with
+# $(call unescape-nl...)
+#
+escape-nl = $(subst $(newline),$(call nl-escape,$(2)),$(1))
+
+# unescape-nl
+#
+# Usage: text = $(call unescape-nl,escaped-text[,escape])
+#
+# See escape-nl.
+#
+unescape-nl = $(subst $(call nl-escape,$(2)),$(newline),$(1))
+
+# shell-escape-nl
+#
+# Usage: $(shell some-command | $(call shell-escape-nl[,escape]))
+#
+# Use this to escape newlines from within a shell call;
+# the default escape is a bizarre string.
+#
+# NOTE: The escape is used directly as a string constant
+#       in an `awk' program that is delimited by shell
+#       single-quotes, so be wary of the characters
+#       that are chosen.
+#
+define shell-escape-nl
+awk 'NR==1 {t=$$0} NR>1 {t=t "$(nl-escape)" $$0} END {printf t}'
+endef
+
+# shell-unescape-nl
+#
+# Usage: $(shell some-command | $(call shell-unescape-nl[,escape]))
+#
+# Use this to unescape newlines from within a shell call;
+# the default escape is a bizarre string.
+#
+# NOTE: The escape is used directly as an extended regular
+#       expression constant in an `awk' program that is
+#       delimited by shell single-quotes, so be wary
+#       of the characters that are chosen.
+#
+# (The bash shell has a bug where `{gsub(...),...}' is
+#  misinterpreted as a brace expansion; this can be
+#  overcome by putting a space between `{' and `gsub').
+#
+define shell-unescape-nl
+awk 'NR==1 {t=$$0} NR>1 {t=t "\n" $$0} END { gsub(/$(nl-escape)/,"\n",t); printf t }'
+endef
+
+# escape-for-shell-sq
+#
+# Usage: embeddable-text = $(call escape-for-shell-sq,text)
+#
+# This function produces text that is suitable for
+# embedding in a shell string that is delimited by
+# single-quotes.
+#
+escape-for-shell-sq =  $(subst ','\'',$(1))
+
+# shell-sq
+#
+# Usage: single-quoted-and-escaped-text = $(call shell-sq,text)
+#
+shell-sq = '$(escape-for-shell-sq)'
+
+# shell-wordify
+#
+# Usage: wordified-text = $(call shell-wordify,text)
+#
+# For instance:
+#
+#  |define text
+#  |hello
+#  |world
+#  |endef
+#  |
+#  |target:
+#  |	echo $(call shell-wordify,$(text))
+#
+# At least GNU make gets confused by expanding a newline
+# within the context of a command line of a makefile rule
+# (this is in constrast to a `$(shell ...)' function call,
+# which can handle it just fine).
+#
+# This function avoids the problem by producing a string
+# that works as a shell word, regardless of whether or
+# not it contains a newline.
+#
+# If the text to be wordified contains a newline, then
+# an intrictate shell command substitution is constructed
+# to render the text as a single line; when the shell
+# processes the resulting escaped text, it transforms
+# it into the original unescaped text.
+#
+# If the text does not contain a newline, then this function
+# produces the same results as the `$(shell-sq)' function.
+#
+shell-wordify = $(if $(findstring $(newline),$(1)),$(_sw-esc-nl),$(shell-sq))
+define _sw-esc-nl
+"$$(echo $(call escape-nl,$(shell-sq),$(2)) | $(call shell-unescape-nl,$(2)))"
+endef
+
+# is-absolute
+#
+# Usage: bool-value = $(call is-absolute,path)
+#
+is-absolute = $(shell echo $(shell-sq) | grep ^/ -q && echo y)
+
+# lookup
+#
+# Usage: absolute-executable-path-or-empty = $(call lookup,path)
+#
+# (It's necessary to use `sh -c' because GNU make messes up by
+#  trying too hard and getting things wrong).
+#
+lookup = $(call unescape-nl,$(shell sh -c $(_l-sh)))
+_l-sh = $(call shell-sq,command -v $(shell-sq) | $(call shell-escape-nl,))
+
+# is-executable
+#
+# Usage: bool-value = $(call is-executable,path)
+#
+# (It's necessary to use `sh -c' because GNU make messes up by
+#  trying too hard and getting things wrong).
+#
+is-executable = $(call _is-executable-helper,$(shell-sq))
+_is-executable-helper = $(shell sh -c $(_is-executable-sh))
+_is-executable-sh = $(call shell-sq,test -f $(1) -a -x $(1) && echo y)
+
+# get-executable
+#
+# Usage: absolute-executable-path-or-empty = $(call get-executable,path)
+#
+# The goal is to get an absolute path for an executable;
+# the `command -v' is defined by POSIX, but it's not
+# necessarily very portable, so it's only used if
+# relative path resolution is requested, as determined
+# by the presence of a leading `/'.
+#
+get-executable = $(if $(1),$(if $(is-absolute),$(_ge-abspath),$(lookup)))
+_ge-abspath = $(if $(is-executable),$(1))
+
+# get-supplied-or-default-executable
+#
+# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
+#
+define get-executable-or-default
+$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
+endef
+_ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2)))
+_gea_warn = $(warning The path '$(1)' is not executable.)
+_gea_err  = $(if $(1),$(error Please set '$(1)' appropriately))
+
+# try-cc
+# Usage: option = $(call try-cc, source-to-build, cc-options)
+try-cc = $(shell sh -c						  \
+	'TMP="$(OUTPUT)$(TMPOUT).$$$$";				  \
+	 echo "$(1)" |						  \
+	 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
+	 rm -f "$$TMP"')
+
+# try-build
+# Usage: option = $(call try-build, source-to-build, cc-options, link-options)
+try-build = $(shell sh -c							\
+	'TMP="$(OUTPUT)$(TMPOUT).$$$$";						\
+	echo "$(1)" |								\
+	$(CC) -x c - $(2) $(3) -o "$$TMP" > /dev/null 2>&1 && echo y;		\
+	rm -f "$$TMP"')
diff --git a/tools/kvm/disk/blk.c b/tools/kvm/disk/blk.c
new file mode 100644
index 0000000..cf853c1
--- /dev/null
+++ b/tools/kvm/disk/blk.c
@@ -0,0 +1,76 @@
+#include "kvm/disk-image.h"
+
+#include <linux/err.h>
+#include <mntent.h>
+
+/*
+ * raw image and blk dev are similar, so reuse raw image ops.
+ */
+static struct disk_image_operations blk_dev_ops = {
+	.read	= raw_image__read,
+	.write	= raw_image__write,
+};
+
+static bool is_mounted(struct stat *st)
+{
+	struct stat st_buf;
+	struct mntent *mnt;
+	FILE *f;
+
+	f = setmntent("/proc/mounts", "r");
+	if (!f)
+		return false;
+
+	while ((mnt = getmntent(f)) != NULL) {
+		if (stat(mnt->mnt_fsname, &st_buf) == 0 &&
+		    S_ISBLK(st_buf.st_mode) && st->st_rdev == st_buf.st_rdev) {
+			fclose(f);
+			return true;
+		}
+	}
+
+	fclose(f);
+	return false;
+}
+
+struct disk_image *blkdev__probe(const char *filename, struct stat *st)
+{
+	struct disk_image *disk;
+	int fd, r;
+	u64 size;
+
+	if (!S_ISBLK(st->st_mode))
+		return ERR_PTR(-EINVAL);
+
+	if (is_mounted(st)) {
+		pr_err("Block device %s is already mounted! Unmount before use.",
+		       filename);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/*
+	 * Be careful! We are opening host block device!
+	 * Open it readonly since we do not want to break user's data on disk.
+	 */
+	fd = open(filename, O_RDWR);
+	if (fd < 0)
+		return ERR_PTR(fd);
+
+	if (ioctl(fd, BLKGETSIZE64, &size) < 0) {
+		r = -errno;
+		close(fd);
+		return ERR_PTR(r);
+	}
+
+	/*
+	 * FIXME: This will not work on 32-bit host because we can not
+	 * mmap large disk. There is not enough virtual address space
+	 * in 32-bit host. However, this works on 64-bit host.
+	 */
+	disk = disk_image__new(fd, size, &blk_dev_ops, DISK_IMAGE_REGULAR);
+#ifdef CONFIG_HAS_AIO
+		if (!IS_ERR_OR_NULL(disk))
+			disk->async = 1;
+#endif
+	return disk;
+}
diff --git a/tools/kvm/disk/core.c b/tools/kvm/disk/core.c
new file mode 100644
index 0000000..2739dcd
--- /dev/null
+++ b/tools/kvm/disk/core.c
@@ -0,0 +1,263 @@
+#include "kvm/disk-image.h"
+#include "kvm/qcow.h"
+#include "kvm/virtio-blk.h"
+
+#include <linux/err.h>
+#include <sys/eventfd.h>
+#include <sys/poll.h>
+
+#define AIO_MAX 256
+
+int debug_iodelay;
+
+#ifdef CONFIG_HAS_AIO
+static void *disk_image__thread(void *param)
+{
+	struct disk_image *disk = param;
+	struct io_event event[AIO_MAX];
+	struct timespec notime = {0};
+	int nr, i;
+	u64 dummy;
+
+	while (read(disk->evt, &dummy, sizeof(dummy)) > 0) {
+		nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, &notime);
+		for (i = 0; i < nr; i++)
+			disk->disk_req_cb(event[i].data, event[i].res);
+	}
+
+	return NULL;
+}
+#endif
+
+struct disk_image *disk_image__new(int fd, u64 size,
+				   struct disk_image_operations *ops,
+				   int use_mmap)
+{
+	struct disk_image *disk;
+	int r;
+
+	disk = malloc(sizeof *disk);
+	if (!disk)
+		return ERR_PTR(-ENOMEM);
+
+	*disk = (struct disk_image) {
+		.fd	= fd,
+		.size	= size,
+		.ops	= ops,
+	};
+
+	if (use_mmap == DISK_IMAGE_MMAP) {
+		/*
+		 * The write to disk image will be discarded
+		 */
+		disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
+		if (disk->priv == MAP_FAILED) {
+			r = -errno;
+			free(disk);
+			return ERR_PTR(r);
+		}
+	}
+
+#ifdef CONFIG_HAS_AIO
+	if (disk) {
+		pthread_t thread;
+
+		disk->evt = eventfd(0, 0);
+		io_setup(AIO_MAX, &disk->ctx);
+		r = pthread_create(&thread, NULL, disk_image__thread, disk);
+		if (r) {
+			r = -errno;
+			free(disk);
+			return ERR_PTR(r);
+		}
+	}
+#endif
+	return disk;
+}
+
+struct disk_image *disk_image__open(const char *filename, bool readonly)
+{
+	struct disk_image *disk;
+	struct stat st;
+	int fd;
+
+	if (stat(filename, &st) < 0)
+		return ERR_PTR(-errno);
+
+	/* blk device ?*/
+	disk = blkdev__probe(filename, &st);
+	if (!IS_ERR_OR_NULL(disk))
+		return disk;
+
+	fd = open(filename, readonly ? O_RDONLY : O_RDWR);
+	if (fd < 0)
+		return ERR_PTR(fd);
+
+	/* qcow image ?*/
+	disk = qcow_probe(fd, true);
+	if (!IS_ERR_OR_NULL(disk)) {
+		pr_warning("Forcing read-only support for QCOW");
+		return disk;
+	}
+
+	/* raw image ?*/
+	disk = raw_image__probe(fd, &st, readonly);
+	if (!IS_ERR_OR_NULL(disk))
+		return disk;
+
+	if (close(fd) < 0)
+		pr_warning("close() failed");
+
+	return ERR_PTR(-ENOSYS);
+}
+
+struct disk_image **disk_image__open_all(const char **filenames,
+					 bool *readonly, int count)
+{
+	struct disk_image **disks;
+	int i;
+	void *err;
+
+	if (!count)
+		return ERR_PTR(-EINVAL);
+	if (count > MAX_DISK_IMAGES)
+		return ERR_PTR(-ENOSPC);
+
+	disks = calloc(count, sizeof(*disks));
+	if (!disks)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < count; i++) {
+		if (!filenames[i])
+			continue;
+
+		disks[i] = disk_image__open(filenames[i], readonly[i]);
+		if (IS_ERR_OR_NULL(disks[i])) {
+			pr_err("Loading disk image '%s' failed", filenames[i]);
+			err = disks[i];
+			goto error;
+		}
+	}
+
+	return disks;
+error:
+	for (i = 0; i < count; i++)
+		if (!IS_ERR_OR_NULL(disks[i]))
+			disk_image__close(disks[i]);
+
+	free(disks);
+	return err;
+}
+
+int disk_image__flush(struct disk_image *disk)
+{
+	if (disk->ops->flush)
+		return disk->ops->flush(disk);
+
+	return fsync(disk->fd);
+}
+
+int disk_image__close(struct disk_image *disk)
+{
+	/* If there was no disk image then there's nothing to do: */
+	if (!disk)
+		return 0;
+
+	if (disk->ops->close)
+		return disk->ops->close(disk);
+
+	if (close(disk->fd) < 0)
+		pr_warning("close() failed");
+
+	free(disk);
+
+	return 0;
+}
+
+int disk_image__close_all(struct disk_image **disks, int count)
+{
+	while (count)
+		disk_image__close(disks[--count]);
+
+	free(disks);
+
+	return 0;
+}
+
+/*
+ * Fill iov with disk data, starting from sector 'sector'.
+ * Return amount of bytes read.
+ */
+ssize_t disk_image__read(struct disk_image *disk, u64 sector,
+			 const struct iovec *iov, int iovcount, void *param)
+{
+	ssize_t total = 0;
+
+	if (debug_iodelay)
+		msleep(debug_iodelay);
+
+	if (disk->ops->read) {
+		total = disk->ops->read(disk, sector, iov, iovcount, param);
+		if (total < 0) {
+			pr_info("disk_image__read error: total=%ld\n", (long)total);
+			return total;
+		}
+	}
+
+	if (!disk->async && disk->disk_req_cb)
+		disk->disk_req_cb(param, total);
+
+	return total;
+}
+
+/*
+ * Write iov to disk, starting from sector 'sector'.
+ * Return amount of bytes written.
+ */
+ssize_t disk_image__write(struct disk_image *disk, u64 sector,
+			  const struct iovec *iov, int iovcount, void *param)
+{
+	ssize_t total = 0;
+
+	if (debug_iodelay)
+		msleep(debug_iodelay);
+
+	if (disk->ops->write) {
+		/*
+		 * Try writev based operation first
+		 */
+
+		total = disk->ops->write(disk, sector, iov, iovcount, param);
+		if (total < 0) {
+			pr_info("disk_image__write error: total=%ld\n", (long)total);
+			return total;
+		}
+	} else {
+		/* Do nothing */
+	}
+
+	if (!disk->async && disk->disk_req_cb)
+		disk->disk_req_cb(param, total);
+
+	return total;
+}
+
+ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len)
+{
+	struct stat st;
+	int r;
+
+	r = fstat(disk->fd, &st);
+	if (r)
+		return r;
+
+	*len = snprintf(buffer, *len, "%llu%llu%llu",
+			(u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino);
+	return *len;
+}
+
+void disk_image__set_callback(struct disk_image *disk,
+			      void (*disk_req_cb)(void *param, long len))
+{
+	disk->disk_req_cb = disk_req_cb;
+}
diff --git a/tools/kvm/disk/qcow.c b/tools/kvm/disk/qcow.c
new file mode 100644
index 0000000..ee2992e
--- /dev/null
+++ b/tools/kvm/disk/qcow.c
@@ -0,0 +1,1529 @@
+#include "kvm/qcow.h"
+
+#include "kvm/disk-image.h"
+#include "kvm/read-write.h"
+#include "kvm/mutex.h"
+#include "kvm/util.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef CONFIG_HAS_ZLIB
+#include <zlib.h>
+#endif
+
+#include <linux/err.h>
+#include <linux/byteorder.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+static int update_cluster_refcount(struct qcow *q, u64 clust_idx, u16 append);
+static int qcow_write_refcount_table(struct qcow *q);
+static u64 qcow_alloc_clusters(struct qcow *q, u64 size, int update_ref);
+static void  qcow_free_clusters(struct qcow *q, u64 clust_start, u64 size);
+
+static inline int qcow_pwrite_sync(int fd,
+	void *buf, size_t count, off_t offset)
+{
+	if (pwrite_in_full(fd, buf, count, offset) < 0)
+		return -1;
+
+	return fdatasync(fd);
+}
+
+static int l2_table_insert(struct rb_root *root, struct qcow_l2_table *new)
+{
+	struct rb_node **link = &(root->rb_node), *parent = NULL;
+	u64 offset = new->offset;
+
+	/* search the tree */
+	while (*link) {
+		struct qcow_l2_table *t;
+
+		t = rb_entry(*link, struct qcow_l2_table, node);
+		if (!t)
+			goto error;
+
+		parent = *link;
+
+		if (t->offset > offset)
+			link = &(*link)->rb_left;
+		else if (t->offset < offset)
+			link = &(*link)->rb_right;
+		else
+			goto out;
+	}
+
+	/* add new node */
+	rb_link_node(&new->node, parent, link);
+	rb_insert_color(&new->node, root);
+out:
+	return 0;
+error:
+	return -1;
+}
+
+static struct qcow_l2_table *l2_table_lookup(struct rb_root *root, u64 offset)
+{
+	struct rb_node *link = root->rb_node;
+
+	while (link) {
+		struct qcow_l2_table *t;
+
+		t = rb_entry(link, struct qcow_l2_table, node);
+		if (!t)
+			goto out;
+
+		if (t->offset > offset)
+			link = link->rb_left;
+		else if (t->offset < offset)
+			link = link->rb_right;
+		else
+			return t;
+	}
+out:
+	return NULL;
+}
+
+static void l1_table_free_cache(struct qcow_l1_table *l1t)
+{
+	struct rb_root *r = &l1t->root;
+	struct list_head *pos, *n;
+	struct qcow_l2_table *t;
+
+	list_for_each_safe(pos, n, &l1t->lru_list) {
+		/* Remove cache table from the list and RB tree */
+		list_del(pos);
+		t = list_entry(pos, struct qcow_l2_table, list);
+		rb_erase(&t->node, r);
+
+		/* Free the cached node */
+		free(t);
+	}
+}
+
+static int qcow_l2_cache_write(struct qcow *q, struct qcow_l2_table *c)
+{
+	struct qcow_header *header = q->header;
+	u64 size;
+
+	if (!c->dirty)
+		return 0;
+
+	size = 1 << header->l2_bits;
+
+	if (qcow_pwrite_sync(q->fd, c->table,
+		size * sizeof(u64), c->offset) < 0)
+		return -1;
+
+	c->dirty = 0;
+
+	return 0;
+}
+
+static int cache_table(struct qcow *q, struct qcow_l2_table *c)
+{
+	struct qcow_l1_table *l1t = &q->table;
+	struct rb_root *r = &l1t->root;
+	struct qcow_l2_table *lru;
+
+	if (l1t->nr_cached == MAX_CACHE_NODES) {
+		/*
+		 * The node at the head of the list is least recently used
+		 * node. Remove it from the list and replaced with a new node.
+		 */
+		lru = list_first_entry(&l1t->lru_list, struct qcow_l2_table, list);
+
+		/* Remove the node from the cache */
+		rb_erase(&lru->node, r);
+		list_del_init(&lru->list);
+		l1t->nr_cached--;
+
+		/* Free the LRUed node */
+		free(lru);
+	}
+
+	/* Add new node in RB Tree: Helps in searching faster */
+	if (l2_table_insert(r, c) < 0)
+		goto error;
+
+	/* Add in LRU replacement list */
+	list_add_tail(&c->list, &l1t->lru_list);
+	l1t->nr_cached++;
+
+	return 0;
+error:
+	return -1;
+}
+
+static struct qcow_l2_table *l2_table_search(struct qcow *q, u64 offset)
+{
+	struct qcow_l1_table *l1t = &q->table;
+	struct qcow_l2_table *l2t;
+
+	l2t = l2_table_lookup(&l1t->root, offset);
+	if (!l2t)
+		return NULL;
+
+	/* Update the LRU state, by moving the searched node to list tail */
+	list_move_tail(&l2t->list, &l1t->lru_list);
+
+	return l2t;
+}
+
+/* Allocates a new node for caching L2 table */
+static struct qcow_l2_table *new_cache_table(struct qcow *q, u64 offset)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_l2_table *c;
+	u64 l2t_sz;
+	u64 size;
+
+	l2t_sz = 1 << header->l2_bits;
+	size   = sizeof(*c) + l2t_sz * sizeof(u64);
+	c      = calloc(1, size);
+	if (!c)
+		goto out;
+
+	c->offset = offset;
+	RB_CLEAR_NODE(&c->node);
+	INIT_LIST_HEAD(&c->list);
+out:
+	return c;
+}
+
+static inline u64 get_l1_index(struct qcow *q, u64 offset)
+{
+	struct qcow_header *header = q->header;
+
+	return offset >> (header->l2_bits + header->cluster_bits);
+}
+
+static inline u64 get_l2_index(struct qcow *q, u64 offset)
+{
+	struct qcow_header *header = q->header;
+
+	return (offset >> (header->cluster_bits)) & ((1 << header->l2_bits)-1);
+}
+
+static inline u64 get_cluster_offset(struct qcow *q, u64 offset)
+{
+	struct qcow_header *header = q->header;
+
+	return offset & ((1 << header->cluster_bits)-1);
+}
+
+static struct qcow_l2_table *qcow_read_l2_table(struct qcow *q, u64 offset)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_l2_table *l2t;
+	u64 size;
+
+	size = 1 << header->l2_bits;
+
+	/* search an entry for offset in cache */
+	l2t = l2_table_search(q, offset);
+	if (l2t)
+		return l2t;
+
+	/* allocate new node for caching l2 table */
+	l2t = new_cache_table(q, offset);
+	if (!l2t)
+		goto error;
+
+	/* table not cached: read from the disk */
+	if (pread_in_full(q->fd, l2t->table, size * sizeof(u64), offset) < 0)
+		goto error;
+
+	/* cache the table */
+	if (cache_table(q, l2t) < 0)
+		goto error;
+
+	return l2t;
+error:
+	free(l2t);
+	return NULL;
+}
+
+static int qcow_decompress_buffer(u8 *out_buf, int out_buf_size,
+	const u8 *buf, int buf_size)
+{
+#ifdef CONFIG_HAS_ZLIB
+	z_stream strm1, *strm = &strm1;
+	int ret, out_len;
+
+	memset(strm, 0, sizeof(*strm));
+
+	strm->next_in	= (u8 *)buf;
+	strm->avail_in	= buf_size;
+	strm->next_out	= out_buf;
+	strm->avail_out	= out_buf_size;
+
+	ret = inflateInit2(strm, -12);
+	if (ret != Z_OK)
+		return -1;
+
+	ret = inflate(strm, Z_FINISH);
+	out_len = strm->next_out - out_buf;
+	if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
+		out_len != out_buf_size) {
+		inflateEnd(strm);
+		return -1;
+	}
+
+	inflateEnd(strm);
+	return 0;
+#else
+	return -1;
+#endif
+}
+
+static ssize_t qcow1_read_cluster(struct qcow *q, u64 offset,
+	void *dst, u32 dst_len)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_l1_table *l1t = &q->table;
+	struct qcow_l2_table *l2t;
+	u64 clust_offset;
+	u64 clust_start;
+	u64 l2t_offset;
+	size_t length;
+	u64 l2t_size;
+	u64 l1_idx;
+	u64 l2_idx;
+	int coffset;
+	int csize;
+
+	l1_idx = get_l1_index(q, offset);
+	if (l1_idx >= l1t->table_size)
+		return -1;
+
+	clust_offset = get_cluster_offset(q, offset);
+	if (clust_offset >= q->cluster_size)
+		return -1;
+
+	length = q->cluster_size - clust_offset;
+	if (length > dst_len)
+		length = dst_len;
+
+	mutex_lock(&q->mutex);
+
+	l2t_offset = be64_to_cpu(l1t->l1_table[l1_idx]);
+	if (!l2t_offset)
+		goto zero_cluster;
+
+	l2t_size = 1 << header->l2_bits;
+
+	/* read and cache level 2 table */
+	l2t = qcow_read_l2_table(q, l2t_offset);
+	if (!l2t)
+		goto out_error;
+
+	l2_idx = get_l2_index(q, offset);
+	if (l2_idx >= l2t_size)
+		goto out_error;
+
+	clust_start = be64_to_cpu(l2t->table[l2_idx]);
+	if (clust_start & QCOW1_OFLAG_COMPRESSED) {
+		coffset	= clust_start & q->cluster_offset_mask;
+		csize	= clust_start >> (63 - q->header->cluster_bits);
+		csize	&= (q->cluster_size - 1);
+
+		if (pread_in_full(q->fd, q->cluster_data, csize,
+				  coffset) < 0)
+			goto out_error;
+
+		if (qcow_decompress_buffer(q->cluster_cache, q->cluster_size,
+					q->cluster_data, csize) < 0)
+			goto out_error;
+
+		memcpy(dst, q->cluster_cache + clust_offset, length);
+		mutex_unlock(&q->mutex);
+	} else {
+		if (!clust_start)
+			goto zero_cluster;
+
+		mutex_unlock(&q->mutex);
+
+		if (pread_in_full(q->fd, dst, length,
+				  clust_start + clust_offset) < 0)
+			return -1;
+	}
+
+	return length;
+
+zero_cluster:
+	mutex_unlock(&q->mutex);
+	memset(dst, 0, length);
+	return length;
+
+out_error:
+	mutex_unlock(&q->mutex);
+	length = -1;
+	return -1;
+}
+
+static ssize_t qcow2_read_cluster(struct qcow *q, u64 offset,
+	void *dst, u32 dst_len)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_l1_table *l1t = &q->table;
+	struct qcow_l2_table *l2t;
+	u64 clust_offset;
+	u64 clust_start;
+	u64 l2t_offset;
+	size_t length;
+	u64 l2t_size;
+	u64 l1_idx;
+	u64 l2_idx;
+	int coffset;
+	int sector_offset;
+	int nb_csectors;
+	int csize;
+
+	l1_idx = get_l1_index(q, offset);
+	if (l1_idx >= l1t->table_size)
+		return -1;
+
+	clust_offset = get_cluster_offset(q, offset);
+	if (clust_offset >= q->cluster_size)
+		return -1;
+
+	length = q->cluster_size - clust_offset;
+	if (length > dst_len)
+		length = dst_len;
+
+	mutex_lock(&q->mutex);
+
+	l2t_offset = be64_to_cpu(l1t->l1_table[l1_idx]);
+
+	l2t_offset &= ~QCOW2_OFLAG_COPIED;
+	if (!l2t_offset)
+		goto zero_cluster;
+
+	l2t_size = 1 << header->l2_bits;
+
+	/* read and cache level 2 table */
+	l2t = qcow_read_l2_table(q, l2t_offset);
+	if (!l2t)
+		goto out_error;
+
+	l2_idx = get_l2_index(q, offset);
+	if (l2_idx >= l2t_size)
+		goto out_error;
+
+	clust_start = be64_to_cpu(l2t->table[l2_idx]);
+	if (clust_start & QCOW2_OFLAG_COMPRESSED) {
+		coffset = clust_start & q->cluster_offset_mask;
+		nb_csectors = ((clust_start >> q->csize_shift)
+			& q->csize_mask) + 1;
+		sector_offset = coffset & (SECTOR_SIZE - 1);
+		csize = nb_csectors * SECTOR_SIZE - sector_offset;
+
+		if (pread_in_full(q->fd, q->cluster_data,
+				  nb_csectors * SECTOR_SIZE,
+				  coffset & ~(SECTOR_SIZE - 1)) < 0) {
+			goto out_error;
+		}
+
+		if (qcow_decompress_buffer(q->cluster_cache, q->cluster_size,
+					q->cluster_data + sector_offset,
+					csize) < 0) {
+			goto out_error;
+		}
+
+		memcpy(dst, q->cluster_cache + clust_offset, length);
+		mutex_unlock(&q->mutex);
+	} else {
+		clust_start &= QCOW2_OFFSET_MASK;
+		if (!clust_start)
+			goto zero_cluster;
+
+		mutex_unlock(&q->mutex);
+
+		if (pread_in_full(q->fd, dst, length,
+				  clust_start + clust_offset) < 0)
+			return -1;
+	}
+
+	return length;
+
+zero_cluster:
+	mutex_unlock(&q->mutex);
+	memset(dst, 0, length);
+	return length;
+
+out_error:
+	mutex_unlock(&q->mutex);
+	length = -1;
+	return -1;
+}
+
+static ssize_t qcow_read_sector_single(struct disk_image *disk, u64 sector,
+	void *dst, u32 dst_len)
+{
+	struct qcow *q = disk->priv;
+	struct qcow_header *header = q->header;
+	u32 nr_read;
+	u64 offset;
+	char *buf;
+	u32 nr;
+
+	buf = dst;
+	nr_read = 0;
+
+	while (nr_read < dst_len) {
+		offset = sector << SECTOR_SHIFT;
+		if (offset >= header->size)
+			return -1;
+
+		if (q->version == QCOW1_VERSION)
+			nr = qcow1_read_cluster(q, offset, buf,
+				dst_len - nr_read);
+		else
+			nr = qcow2_read_cluster(q, offset, buf,
+				dst_len - nr_read);
+
+		if (nr <= 0)
+			return -1;
+
+		nr_read	+= nr;
+		buf	+= nr;
+		sector	+= (nr >> SECTOR_SHIFT);
+	}
+
+	return dst_len;
+}
+
+static ssize_t qcow_read_sector(struct disk_image *disk, u64 sector,
+				const struct iovec *iov, int iovcount, void *param)
+{
+	ssize_t nr, total = 0;
+
+	while (iovcount--) {
+		nr = qcow_read_sector_single(disk, sector, iov->iov_base, iov->iov_len);
+		if (nr != (ssize_t)iov->iov_len) {
+			pr_info("qcow_read_sector error: nr=%ld iov_len=%ld\n", (long)nr, (long)iov->iov_len);
+			return -1;
+		}
+
+		sector += iov->iov_len >> SECTOR_SHIFT;
+		total += nr;
+		iov++;
+	}
+
+	return total;
+}
+
+static void refcount_table_free_cache(struct qcow_refcount_table *rft)
+{
+	struct rb_root *r = &rft->root;
+	struct list_head *pos, *n;
+	struct qcow_refcount_block *t;
+
+	list_for_each_safe(pos, n, &rft->lru_list) {
+		list_del(pos);
+		t = list_entry(pos, struct qcow_refcount_block, list);
+		rb_erase(&t->node, r);
+
+		free(t);
+	}
+}
+
+static int refcount_block_insert(struct rb_root *root, struct qcow_refcount_block *new)
+{
+	struct rb_node **link = &(root->rb_node), *parent = NULL;
+	u64 offset = new->offset;
+
+	/* search the tree */
+	while (*link) {
+		struct qcow_refcount_block *t;
+
+		t = rb_entry(*link, struct qcow_refcount_block, node);
+		if (!t)
+			goto error;
+
+		parent = *link;
+
+		if (t->offset > offset)
+			link = &(*link)->rb_left;
+		else if (t->offset < offset)
+			link = &(*link)->rb_right;
+		else
+			goto out;
+	}
+
+	/* add new node */
+	rb_link_node(&new->node, parent, link);
+	rb_insert_color(&new->node, root);
+out:
+	return 0;
+error:
+	return -1;
+}
+
+static int write_refcount_block(struct qcow *q, struct qcow_refcount_block *rfb)
+{
+	if (!rfb->dirty)
+		return 0;
+
+	if (qcow_pwrite_sync(q->fd, rfb->entries,
+		rfb->size * sizeof(u16), rfb->offset) < 0)
+		return -1;
+
+	rfb->dirty = 0;
+
+	return 0;
+}
+
+static int cache_refcount_block(struct qcow *q, struct qcow_refcount_block *c)
+{
+	struct qcow_refcount_table *rft = &q->refcount_table;
+	struct rb_root *r = &rft->root;
+	struct qcow_refcount_block *lru;
+
+	if (rft->nr_cached == MAX_CACHE_NODES) {
+		lru = list_first_entry(&rft->lru_list, struct qcow_refcount_block, list);
+
+		rb_erase(&lru->node, r);
+		list_del_init(&lru->list);
+		rft->nr_cached--;
+
+		free(lru);
+	}
+
+	if (refcount_block_insert(r, c) < 0)
+		goto error;
+
+	list_add_tail(&c->list, &rft->lru_list);
+	rft->nr_cached++;
+
+	return 0;
+error:
+	return -1;
+}
+
+static struct qcow_refcount_block *new_refcount_block(struct qcow *q, u64 rfb_offset)
+{
+	struct qcow_refcount_block *rfb;
+
+	rfb = malloc(sizeof *rfb + q->cluster_size);
+	if (!rfb)
+		return NULL;
+
+	rfb->offset = rfb_offset;
+	rfb->size = q->cluster_size / sizeof(u16);
+	RB_CLEAR_NODE(&rfb->node);
+	INIT_LIST_HEAD(&rfb->list);
+
+	return rfb;
+}
+
+static struct qcow_refcount_block *refcount_block_lookup(struct rb_root *root, u64 offset)
+{
+	struct rb_node *link = root->rb_node;
+
+	while (link) {
+		struct qcow_refcount_block *t;
+
+		t = rb_entry(link, struct qcow_refcount_block, node);
+		if (!t)
+			goto out;
+
+		if (t->offset > offset)
+			link = link->rb_left;
+		else if (t->offset < offset)
+			link = link->rb_right;
+		else
+			return t;
+	}
+out:
+	return NULL;
+}
+
+static struct qcow_refcount_block *refcount_block_search(struct qcow *q, u64 offset)
+{
+	struct qcow_refcount_table *rft = &q->refcount_table;
+	struct qcow_refcount_block *rfb;
+
+	rfb = refcount_block_lookup(&rft->root, offset);
+	if (!rfb)
+		return NULL;
+
+	/* Update the LRU state, by moving the searched node to list tail */
+	list_move_tail(&rfb->list, &rft->lru_list);
+
+	return rfb;
+}
+
+static struct qcow_refcount_block *qcow_grow_refcount_block(struct qcow *q,
+	u64 clust_idx)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_refcount_table *rft = &q->refcount_table;
+	struct qcow_refcount_block *rfb;
+	u64 new_block_offset;
+	u64 rft_idx;
+
+	rft_idx = clust_idx >> (header->cluster_bits -
+		QCOW_REFCOUNT_BLOCK_SHIFT);
+
+	if (rft_idx >= rft->rf_size) {
+		pr_warning("Don't support grow refcount block table");
+		return NULL;
+	}
+
+	new_block_offset = qcow_alloc_clusters(q, q->cluster_size, 0);
+	if (new_block_offset < 0)
+		return NULL;
+
+	rfb = new_refcount_block(q, new_block_offset);
+	if (!rfb)
+		return NULL;
+
+	memset(rfb->entries, 0x00, q->cluster_size);
+	rfb->dirty = 1;
+
+	/* write refcount block */
+	if (write_refcount_block(q, rfb) < 0)
+		goto free_rfb;
+
+	if (cache_refcount_block(q, rfb) < 0)
+		goto free_rfb;
+
+	rft->rf_table[rft_idx] = cpu_to_be64(new_block_offset);
+	if (update_cluster_refcount(q, new_block_offset >>
+		    header->cluster_bits, 1) < 0)
+		goto recover_rft;
+
+	if (qcow_write_refcount_table(q) < 0)
+		goto recover_rft;
+
+	return rfb;
+
+recover_rft:
+	rft->rf_table[rft_idx] = 0;
+free_rfb:
+	free(rfb);
+	return NULL;
+}
+
+static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64 clust_idx)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_refcount_table *rft = &q->refcount_table;
+	struct qcow_refcount_block *rfb;
+	u64 rfb_offset;
+	u64 rft_idx;
+
+	rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
+	if (rft_idx >= rft->rf_size)
+		return ERR_PTR(-ENOSPC);
+
+	rfb_offset = be64_to_cpu(rft->rf_table[rft_idx]);
+	if (!rfb_offset)
+		return ERR_PTR(-ENOSPC);
+
+	rfb = refcount_block_search(q, rfb_offset);
+	if (rfb)
+		return rfb;
+
+	rfb = new_refcount_block(q, rfb_offset);
+	if (!rfb)
+		return NULL;
+
+	if (pread_in_full(q->fd, rfb->entries, rfb->size * sizeof(u16), rfb_offset) < 0)
+		goto error_free_rfb;
+
+	if (cache_refcount_block(q, rfb) < 0)
+		goto error_free_rfb;
+
+	return rfb;
+
+error_free_rfb:
+	free(rfb);
+
+	return NULL;
+}
+
+static u16 qcow_get_refcount(struct qcow *q, u64 clust_idx)
+{
+	struct qcow_refcount_block *rfb = NULL;
+	struct qcow_header *header = q->header;
+	u64 rfb_idx;
+
+	rfb = qcow_read_refcount_block(q, clust_idx);
+	if (PTR_ERR(rfb) == -ENOSPC)
+		return 0;
+	else if (IS_ERR_OR_NULL(rfb)) {
+		pr_warning("Error while reading refcount table");
+		return -1;
+	}
+
+	rfb_idx = clust_idx & (((1ULL <<
+		(header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT)) - 1));
+
+	if (rfb_idx >= rfb->size) {
+		pr_warning("L1: refcount block index out of bounds");
+		return -1;
+	}
+
+	return be16_to_cpu(rfb->entries[rfb_idx]);
+}
+
+static int update_cluster_refcount(struct qcow *q, u64 clust_idx, u16 append)
+{
+	struct qcow_refcount_block *rfb = NULL;
+	struct qcow_header *header = q->header;
+	u16 refcount;
+	u64 rfb_idx;
+
+	rfb = qcow_read_refcount_block(q, clust_idx);
+	if (PTR_ERR(rfb) == -ENOSPC) {
+		rfb = qcow_grow_refcount_block(q, clust_idx);
+		if (!rfb) {
+			pr_warning("error while growing refcount table");
+			return -1;
+		}
+	} else if (IS_ERR_OR_NULL(rfb)) {
+		pr_warning("error while reading refcount table");
+		return -1;
+	}
+
+	rfb_idx = clust_idx & (((1ULL <<
+		(header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT)) - 1));
+	if (rfb_idx >= rfb->size) {
+		pr_warning("refcount block index out of bounds");
+		return -1;
+	}
+
+	refcount = be16_to_cpu(rfb->entries[rfb_idx]) + append;
+	rfb->entries[rfb_idx] = cpu_to_be16(refcount);
+	rfb->dirty = 1;
+
+	/* write refcount block */
+	if (write_refcount_block(q, rfb) < 0) {
+		pr_warning("refcount block index out of bounds");
+		return -1;
+	}
+
+	/* update free_clust_idx since refcount becomes zero */
+	if (!refcount && clust_idx < q->free_clust_idx)
+		q->free_clust_idx = clust_idx;
+
+	return 0;
+}
+
+static void  qcow_free_clusters(struct qcow *q, u64 clust_start, u64 size)
+{
+	struct qcow_header *header = q->header;
+	u64 start, end, offset;
+
+	start = clust_start & ~(q->cluster_size - 1);
+	end = (clust_start + size - 1) & ~(q->cluster_size - 1);
+	for (offset = start; offset <= end; offset += q->cluster_size)
+		update_cluster_refcount(q, offset >> header->cluster_bits, -1);
+}
+
+/*
+ * Allocate clusters according to the size. Find a postion that
+ * can satisfy the size. free_clust_idx is initialized to zero and
+ * Record last position.
+ */
+static u64 qcow_alloc_clusters(struct qcow *q, u64 size, int update_ref)
+{
+	struct qcow_header *header = q->header;
+	u16 clust_refcount;
+	u32 clust_idx = 0, i;
+	u64 clust_num;
+
+	clust_num = (size + (q->cluster_size - 1)) >> header->cluster_bits;
+
+again:
+	for (i = 0; i < clust_num; i++) {
+		clust_idx = q->free_clust_idx++;
+		clust_refcount = qcow_get_refcount(q, clust_idx);
+		if (clust_refcount < 0)
+			return -1;
+		else if (clust_refcount > 0)
+			goto again;
+	}
+
+	clust_idx++;
+
+	if (update_ref)
+		for (i = 0; i < clust_num; i++)
+			if (update_cluster_refcount(q,
+				clust_idx - clust_num + i, 1))
+				return -1;
+
+	return (clust_idx - clust_num) << header->cluster_bits;
+}
+
+static int qcow_write_l1_table(struct qcow *q)
+{
+	struct qcow_l1_table *l1t = &q->table;
+	struct qcow_header *header = q->header;
+
+	if (qcow_pwrite_sync(q->fd, l1t->l1_table,
+		l1t->table_size * sizeof(u64),
+		header->l1_table_offset) < 0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Get l2 table. If the table has been copied, read table directly.
+ * If the table exists, allocate a new cluster and copy the table
+ * to the new cluster.
+ */
+static int get_cluster_table(struct qcow *q, u64 offset,
+	struct qcow_l2_table **result_l2t, u64 *result_l2_index)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_l1_table *l1t = &q->table;
+	struct qcow_l2_table *l2t;
+	u64 l1t_idx;
+	u64 l2t_offset;
+	u64 l2t_idx;
+	u64 l2t_size;
+	u64 l2t_new_offset;
+
+	l2t_size = 1 << header->l2_bits;
+
+	l1t_idx = get_l1_index(q, offset);
+	if (l1t_idx >= l1t->table_size)
+		return -1;
+
+	l2t_idx = get_l2_index(q, offset);
+	if (l2t_idx >= l2t_size)
+		return -1;
+
+	l2t_offset = be64_to_cpu(l1t->l1_table[l1t_idx]);
+	if (l2t_offset & QCOW2_OFLAG_COPIED) {
+		l2t_offset &= ~QCOW2_OFLAG_COPIED;
+		l2t = qcow_read_l2_table(q, l2t_offset);
+		if (!l2t)
+			goto error;
+	} else {
+		l2t_new_offset = qcow_alloc_clusters(q,
+			l2t_size*sizeof(u64), 1);
+
+		if (l2t_new_offset < 0)
+			goto error;
+
+		l2t = new_cache_table(q, l2t_new_offset);
+		if (!l2t)
+			goto free_cluster;
+
+		if (l2t_offset) {
+			l2t = qcow_read_l2_table(q, l2t_offset);
+			if (!l2t)
+				goto free_cache;
+		} else
+			memset(l2t->table, 0x00, l2t_size * sizeof(u64));
+
+		/* write l2 table */
+		l2t->dirty = 1;
+		if (qcow_l2_cache_write(q, l2t) < 0)
+			goto free_cache;
+
+		/* cache l2 table */
+		if (cache_table(q, l2t))
+			goto free_cache;
+
+		/* update the l1 talble */
+		l1t->l1_table[l1t_idx] = cpu_to_be64(l2t_new_offset
+			| QCOW2_OFLAG_COPIED);
+		if (qcow_write_l1_table(q)) {
+			pr_warning("Update l1 table error");
+			goto free_cache;
+		}
+
+		/* free old cluster */
+		qcow_free_clusters(q, l2t_offset, q->cluster_size);
+	}
+
+	*result_l2t = l2t;
+	*result_l2_index = l2t_idx;
+
+	return 0;
+
+free_cache:
+	free(l2t);
+
+free_cluster:
+	qcow_free_clusters(q, l2t_new_offset, q->cluster_size);
+
+error:
+	return -1;
+}
+
+/*
+ * If the cluster has been copied, write data directly. If not,
+ * read the original data and write it to the new cluster with
+ * modification.
+ */
+static ssize_t qcow_write_cluster(struct qcow *q, u64 offset,
+		void *buf, u32 src_len)
+{
+	struct qcow_l2_table *l2t;
+	u64 clust_new_start;
+	u64 clust_start;
+	u64 clust_flags;
+	u64 clust_off;
+	u64 l2t_idx;
+	u64 len;
+
+	l2t = NULL;
+
+	clust_off = get_cluster_offset(q, offset);
+	if (clust_off >= q->cluster_size)
+		return -1;
+
+	len = q->cluster_size - clust_off;
+	if (len > src_len)
+		len = src_len;
+
+	mutex_lock(&q->mutex);
+
+	if (get_cluster_table(q, offset, &l2t, &l2t_idx)) {
+		pr_warning("Get l2 table error");
+		goto error;
+	}
+
+	clust_start = be64_to_cpu(l2t->table[l2t_idx]);
+	clust_flags = clust_start & QCOW2_OFLAGS_MASK;
+
+	clust_start &= QCOW2_OFFSET_MASK;
+	if (!(clust_flags & QCOW2_OFLAG_COPIED)) {
+		clust_new_start	= qcow_alloc_clusters(q, q->cluster_size, 1);
+		if (clust_new_start < 0) {
+			pr_warning("Cluster alloc error");
+			goto error;
+		}
+
+		offset &= ~(q->cluster_size - 1);
+
+		/* if clust_start is not zero, read the original data*/
+		if (clust_start) {
+			mutex_unlock(&q->mutex);
+			if (qcow2_read_cluster(q, offset, q->copy_buff,
+				q->cluster_size) < 0) {
+				pr_warning("Read copy cluster error");
+				qcow_free_clusters(q, clust_new_start,
+					q->cluster_size);
+				return -1;
+			}
+			mutex_lock(&q->mutex);
+		} else
+			memset(q->copy_buff, 0x00, q->cluster_size);
+
+		memcpy(q->copy_buff + clust_off, buf, len);
+
+		 /* Write actual data */
+		if (pwrite_in_full(q->fd, q->copy_buff, q->cluster_size,
+			clust_new_start) < 0)
+			goto free_cluster;
+
+		/* update l2 table*/
+		l2t->table[l2t_idx] = cpu_to_be64(clust_new_start
+			| QCOW2_OFLAG_COPIED);
+		l2t->dirty = 1;
+
+		if (qcow_l2_cache_write(q, l2t))
+			goto free_cluster;
+
+		/* free old cluster*/
+		if (clust_flags & QCOW2_OFLAG_COMPRESSED) {
+			int size;
+			size = ((clust_start >> q->csize_shift) &
+				q->csize_mask) + 1;
+			size *= 512;
+			clust_start &= q->cluster_offset_mask;
+			clust_start &= ~511;
+
+			qcow_free_clusters(q, clust_start, size);
+		} else if (clust_start)
+			qcow_free_clusters(q, clust_start, q->cluster_size);
+
+	} else {
+		/* Write actual data */
+		if (pwrite_in_full(q->fd, buf, len,
+			clust_start + clust_off) < 0)
+			goto error;
+	}
+	mutex_unlock(&q->mutex);
+	return len;
+
+free_cluster:
+	qcow_free_clusters(q, clust_new_start, q->cluster_size);
+
+error:
+	mutex_unlock(&q->mutex);
+	return -1;
+}
+
+static ssize_t qcow_write_sector_single(struct disk_image *disk, u64 sector, void *src, u32 src_len)
+{
+	struct qcow *q = disk->priv;
+	struct qcow_header *header = q->header;
+	u32 nr_written;
+	char *buf;
+	u64 offset;
+	ssize_t nr;
+
+	buf		= src;
+	nr_written	= 0;
+	offset		= sector << SECTOR_SHIFT;
+
+	while (nr_written < src_len) {
+		if (offset >= header->size)
+			return -1;
+
+		nr = qcow_write_cluster(q, offset, buf, src_len - nr_written);
+		if (nr < 0)
+			return -1;
+
+		nr_written	+= nr;
+		buf		+= nr;
+		offset		+= nr;
+	}
+
+	return nr_written;
+}
+
+static ssize_t qcow_write_sector(struct disk_image *disk, u64 sector,
+				const struct iovec *iov, int iovcount, void *param)
+{
+	ssize_t nr, total = 0;
+
+	while (iovcount--) {
+		nr = qcow_write_sector_single(disk, sector, iov->iov_base, iov->iov_len);
+		if (nr != (ssize_t)iov->iov_len) {
+			pr_info("qcow_write_sector error: nr=%ld iov_len=%ld\n", (long)nr, (long)iov->iov_len);
+			return -1;
+		}
+
+		sector	+= iov->iov_len >> SECTOR_SHIFT;
+		iov++;
+		total	+= nr;
+	}
+
+	return total;
+}
+
+static int qcow_disk_flush(struct disk_image *disk)
+{
+	struct qcow *q = disk->priv;
+	struct qcow_refcount_table *rft;
+	struct list_head *pos, *n;
+	struct qcow_l1_table *l1t;
+
+	l1t = &q->table;
+	rft = &q->refcount_table;
+
+	mutex_lock(&q->mutex);
+
+	list_for_each_safe(pos, n, &rft->lru_list) {
+		struct qcow_refcount_block *c = list_entry(pos, struct qcow_refcount_block, list);
+
+		if (write_refcount_block(q, c) < 0)
+			goto error_unlock;
+	}
+
+	list_for_each_safe(pos, n, &l1t->lru_list) {
+		struct qcow_l2_table *c = list_entry(pos, struct qcow_l2_table, list);
+
+		if (qcow_l2_cache_write(q, c) < 0)
+			goto error_unlock;
+	}
+
+	if (qcow_write_l1_table < 0)
+		goto error_unlock;
+
+	mutex_unlock(&q->mutex);
+
+	return fsync(disk->fd);
+
+error_unlock:
+	mutex_unlock(&q->mutex);
+	return -1;
+}
+
+static int qcow_disk_close(struct disk_image *disk)
+{
+	struct qcow *q;
+
+	if (!disk)
+		return 0;
+
+	q = disk->priv;
+
+	refcount_table_free_cache(&q->refcount_table);
+	l1_table_free_cache(&q->table);
+	free(q->copy_buff);
+	free(q->cluster_data);
+	free(q->cluster_cache);
+	free(q->refcount_table.rf_table);
+	free(q->table.l1_table);
+	free(q->header);
+	free(q);
+
+	return 0;
+}
+
+static struct disk_image_operations qcow_disk_readonly_ops = {
+	.read	= qcow_read_sector,
+	.close	= qcow_disk_close,
+};
+
+static struct disk_image_operations qcow_disk_ops = {
+	.read	= qcow_read_sector,
+	.write	= qcow_write_sector,
+	.flush	= qcow_disk_flush,
+	.close	= qcow_disk_close,
+};
+
+static int qcow_read_refcount_table(struct qcow *q)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_refcount_table *rft = &q->refcount_table;
+
+	rft->rf_size = (header->refcount_table_size * q->cluster_size)
+		/ sizeof(u64);
+
+	rft->rf_table = calloc(rft->rf_size, sizeof(u64));
+	if (!rft->rf_table)
+		return -1;
+
+	rft->root = RB_ROOT;
+	INIT_LIST_HEAD(&rft->lru_list);
+
+	return pread_in_full(q->fd, rft->rf_table, sizeof(u64) * rft->rf_size, header->refcount_table_offset);
+}
+
+static int qcow_write_refcount_table(struct qcow *q)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_refcount_table *rft = &q->refcount_table;
+
+	return qcow_pwrite_sync(q->fd, rft->rf_table,
+		rft->rf_size * sizeof(u64), header->refcount_table_offset);
+}
+
+static int qcow_read_l1_table(struct qcow *q)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_l1_table *table = &q->table;
+
+	table->table_size = header->l1_size;
+
+	table->l1_table	= calloc(table->table_size, sizeof(u64));
+	if (!table->l1_table)
+		return -1;
+
+	return pread_in_full(q->fd, table->l1_table, sizeof(u64) * table->table_size, header->l1_table_offset);
+}
+
+static void *qcow2_read_header(int fd)
+{
+	struct qcow2_header_disk f_header;
+	struct qcow_header *header;
+
+	header = malloc(sizeof(struct qcow_header));
+	if (!header)
+		return NULL;
+
+	if (pread_in_full(fd, &f_header, sizeof(struct qcow2_header_disk), 0) < 0) {
+		free(header);
+		return NULL;
+	}
+
+	be32_to_cpus(&f_header.magic);
+	be32_to_cpus(&f_header.version);
+	be64_to_cpus(&f_header.backing_file_offset);
+	be32_to_cpus(&f_header.backing_file_size);
+	be32_to_cpus(&f_header.cluster_bits);
+	be64_to_cpus(&f_header.size);
+	be32_to_cpus(&f_header.crypt_method);
+	be32_to_cpus(&f_header.l1_size);
+	be64_to_cpus(&f_header.l1_table_offset);
+	be64_to_cpus(&f_header.refcount_table_offset);
+	be32_to_cpus(&f_header.refcount_table_clusters);
+	be32_to_cpus(&f_header.nb_snapshots);
+	be64_to_cpus(&f_header.snapshots_offset);
+
+	*header		= (struct qcow_header) {
+		.size			= f_header.size,
+		.l1_table_offset	= f_header.l1_table_offset,
+		.l1_size		= f_header.l1_size,
+		.cluster_bits		= f_header.cluster_bits,
+		.l2_bits		= f_header.cluster_bits - 3,
+		.refcount_table_offset	= f_header.refcount_table_offset,
+		.refcount_table_size	= f_header.refcount_table_clusters,
+	};
+
+	return header;
+}
+
+static struct disk_image *qcow2_probe(int fd, bool readonly)
+{
+	struct disk_image *disk_image;
+	struct qcow_l1_table *l1t;
+	struct qcow_header *h;
+	struct qcow *q;
+
+	q = calloc(1, sizeof(struct qcow));
+	if (!q)
+		return NULL;
+
+	mutex_init(&q->mutex);
+	q->fd = fd;
+
+	l1t = &q->table;
+
+	l1t->root = RB_ROOT;
+	INIT_LIST_HEAD(&l1t->lru_list);
+
+	h = q->header = qcow2_read_header(fd);
+	if (!h)
+		goto free_qcow;
+
+	q->version = QCOW2_VERSION;
+	q->csize_shift = (62 - (q->header->cluster_bits - 8));
+	q->csize_mask = (1 << (q->header->cluster_bits - 8)) - 1;
+	q->cluster_offset_mask = (1LL << q->csize_shift) - 1;
+	q->cluster_size = 1 << q->header->cluster_bits;
+
+	q->copy_buff = malloc(q->cluster_size);
+	if (!q->copy_buff) {
+		pr_warning("copy buff malloc error");
+		goto free_header;
+	}
+
+	q->cluster_data = malloc(q->cluster_size);
+	if (!q->cluster_data) {
+		pr_warning("cluster data malloc error");
+		goto free_copy_buff;
+	}
+
+	q->cluster_cache = malloc(q->cluster_size);
+	if (!q->cluster_cache) {
+		pr_warning("cluster cache malloc error");
+		goto free_cluster_data;
+	}
+
+	if (qcow_read_l1_table(q) < 0)
+		goto free_cluster_cache;
+
+	if (qcow_read_refcount_table(q) < 0)
+		goto free_l1_table;
+
+	/*
+	 * Do not use mmap use read/write instead
+	 */
+	if (readonly)
+		disk_image = disk_image__new(fd, h->size, &qcow_disk_readonly_ops, DISK_IMAGE_REGULAR);
+	else
+		disk_image = disk_image__new(fd, h->size, &qcow_disk_ops, DISK_IMAGE_REGULAR);
+
+	if (IS_ERR_OR_NULL(disk_image))
+		goto free_refcount_table;
+
+	disk_image->async = 0;
+	disk_image->priv = q;
+
+	return disk_image;
+
+free_refcount_table:
+	if (q->refcount_table.rf_table)
+		free(q->refcount_table.rf_table);
+free_l1_table:
+	if (q->table.l1_table)
+		free(q->table.l1_table);
+free_cluster_cache:
+	if (q->cluster_cache)
+		free(q->cluster_cache);
+free_cluster_data:
+	if (q->cluster_data)
+		free(q->cluster_data);
+free_copy_buff:
+	if (q->copy_buff)
+		free(q->copy_buff);
+free_header:
+	if (q->header)
+		free(q->header);
+free_qcow:
+	if (q)
+		free(q);
+
+	return NULL;
+}
+
+static bool qcow2_check_image(int fd)
+{
+	struct qcow2_header_disk f_header;
+
+	if (pread_in_full(fd, &f_header, sizeof(struct qcow2_header_disk), 0) < 0)
+		return false;
+
+	be32_to_cpus(&f_header.magic);
+	be32_to_cpus(&f_header.version);
+
+	if (f_header.magic != QCOW_MAGIC)
+		return false;
+
+	if (f_header.version != QCOW2_VERSION)
+		return false;
+
+	return true;
+}
+
+static void *qcow1_read_header(int fd)
+{
+	struct qcow1_header_disk f_header;
+	struct qcow_header *header;
+
+	header = malloc(sizeof(struct qcow_header));
+	if (!header)
+		return NULL;
+
+	if (pread_in_full(fd, &f_header, sizeof(struct qcow1_header_disk), 0) < 0) {
+		free(header);
+		return NULL;
+	}
+
+	be32_to_cpus(&f_header.magic);
+	be32_to_cpus(&f_header.version);
+	be64_to_cpus(&f_header.backing_file_offset);
+	be32_to_cpus(&f_header.backing_file_size);
+	be32_to_cpus(&f_header.mtime);
+	be64_to_cpus(&f_header.size);
+	be32_to_cpus(&f_header.crypt_method);
+	be64_to_cpus(&f_header.l1_table_offset);
+
+	*header		= (struct qcow_header) {
+		.size			= f_header.size,
+		.l1_table_offset	= f_header.l1_table_offset,
+		.l1_size		= f_header.size / ((1 << f_header.l2_bits) * (1 << f_header.cluster_bits)),
+		.cluster_bits		= f_header.cluster_bits,
+		.l2_bits		= f_header.l2_bits,
+	};
+
+	return header;
+}
+
+static struct disk_image *qcow1_probe(int fd, bool readonly)
+{
+	struct disk_image *disk_image;
+	struct qcow_l1_table *l1t;
+	struct qcow_header *h;
+	struct qcow *q;
+
+	q = calloc(1, sizeof(struct qcow));
+	if (!q)
+		return NULL;
+
+	mutex_init(&q->mutex);
+	q->fd = fd;
+
+	l1t = &q->table;
+
+	l1t->root = RB_ROOT;
+	INIT_LIST_HEAD(&l1t->lru_list);
+
+	h = q->header = qcow1_read_header(fd);
+	if (!h)
+		goto free_qcow;
+
+	q->version = QCOW1_VERSION;
+	q->cluster_size = 1 << q->header->cluster_bits;
+	q->cluster_offset_mask = (1LL << (63 - q->header->cluster_bits)) - 1;
+	q->free_clust_idx = 0;
+
+	q->cluster_data = malloc(q->cluster_size);
+	if (!q->cluster_data) {
+		pr_warning("cluster data malloc error");
+		goto free_header;
+	}
+
+	q->cluster_cache = malloc(q->cluster_size);
+	if (!q->cluster_cache) {
+		pr_warning("cluster cache malloc error");
+		goto free_cluster_data;
+	}
+
+	if (qcow_read_l1_table(q) < 0)
+		goto free_cluster_cache;
+
+	/*
+	 * Do not use mmap use read/write instead
+	 */
+	if (readonly)
+		disk_image = disk_image__new(fd, h->size, &qcow_disk_readonly_ops, DISK_IMAGE_REGULAR);
+	else
+		disk_image = disk_image__new(fd, h->size, &qcow_disk_ops, DISK_IMAGE_REGULAR);
+
+	if (!disk_image)
+		goto free_l1_table;
+
+	disk_image->async = 1;
+	disk_image->priv = q;
+
+	return disk_image;
+
+free_l1_table:
+	if (q->table.l1_table)
+		free(q->table.l1_table);
+free_cluster_cache:
+	if (q->cluster_cache)
+		free(q->cluster_cache);
+free_cluster_data:
+	if (q->cluster_data)
+		free(q->cluster_data);
+free_header:
+	if (q->header)
+		free(q->header);
+free_qcow:
+	if (q)
+		free(q);
+
+	return NULL;
+}
+
+static bool qcow1_check_image(int fd)
+{
+	struct qcow1_header_disk f_header;
+
+	if (pread_in_full(fd, &f_header, sizeof(struct qcow1_header_disk), 0) < 0)
+		return false;
+
+	be32_to_cpus(&f_header.magic);
+	be32_to_cpus(&f_header.version);
+
+	if (f_header.magic != QCOW_MAGIC)
+		return false;
+
+	if (f_header.version != QCOW1_VERSION)
+		return false;
+
+	return true;
+}
+
+struct disk_image *qcow_probe(int fd, bool readonly)
+{
+	if (qcow1_check_image(fd))
+		return qcow1_probe(fd, readonly);
+
+	if (qcow2_check_image(fd))
+		return qcow2_probe(fd, readonly);
+
+	return NULL;
+}
diff --git a/tools/kvm/disk/raw.c b/tools/kvm/disk/raw.c
new file mode 100644
index 0000000..93b2b4e
--- /dev/null
+++ b/tools/kvm/disk/raw.c
@@ -0,0 +1,141 @@
+#include "kvm/disk-image.h"
+
+#include <linux/err.h>
+
+#ifdef CONFIG_HAS_AIO
+#include <libaio.h>
+#endif
+
+ssize_t raw_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov,
+				int iovcount, void *param)
+{
+	u64 offset = sector << SECTOR_SHIFT;
+
+#ifdef CONFIG_HAS_AIO
+	struct iocb iocb;
+
+	return aio_preadv(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
+				disk->evt, param);
+#else
+	return preadv_in_full(disk->fd, iov, iovcount, offset);
+#endif
+}
+
+ssize_t raw_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov,
+				int iovcount, void *param)
+{
+	u64 offset = sector << SECTOR_SHIFT;
+
+#ifdef CONFIG_HAS_AIO
+	struct iocb iocb;
+
+	return aio_pwritev(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
+				disk->evt, param);
+#else
+	return pwritev_in_full(disk->fd, iov, iovcount, offset);
+#endif
+}
+
+ssize_t raw_image__read_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov,
+				int iovcount, void *param)
+{
+	u64 offset = sector << SECTOR_SHIFT;
+	ssize_t total = 0;
+
+	while (iovcount--) {
+		memcpy(iov->iov_base, disk->priv + offset, iov->iov_len);
+
+		sector	+= iov->iov_len >> SECTOR_SHIFT;
+		offset	+= iov->iov_len;
+		total	+= iov->iov_len;
+		iov++;
+	}
+
+	return total;
+}
+
+ssize_t raw_image__write_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov,
+				int iovcount, void *param)
+{
+	u64 offset = sector << SECTOR_SHIFT;
+	ssize_t total = 0;
+
+	while (iovcount--) {
+		memcpy(disk->priv + offset, iov->iov_base, iov->iov_len);
+
+		sector	+= iov->iov_len >> SECTOR_SHIFT;
+		offset	+= iov->iov_len;
+		total	+= iov->iov_len;
+		iov++;
+	}
+
+	return total;
+}
+
+int raw_image__close(struct disk_image *disk)
+{
+	int ret = 0;
+
+	if (disk->priv != MAP_FAILED)
+		ret = munmap(disk->priv, disk->size);
+
+	close(disk->evt);
+
+#ifdef CONFIG_HAS_VIRTIO
+	io_destroy(disk->ctx);
+#endif
+
+	return ret;
+}
+
+/*
+ * multiple buffer based disk image operations
+ */
+static struct disk_image_operations raw_image_regular_ops = {
+	.read	= raw_image__read,
+	.write	= raw_image__write,
+};
+
+struct disk_image_operations ro_ops = {
+	.read	= raw_image__read_mmap,
+	.write	= raw_image__write_mmap,
+	.close	= raw_image__close,
+};
+
+struct disk_image_operations ro_ops_nowrite = {
+	.read	= raw_image__read,
+};
+
+struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly)
+{
+	struct disk_image *disk;
+
+	if (readonly) {
+		/*
+		 * Use mmap's MAP_PRIVATE to implement non-persistent write
+		 * FIXME: This does not work on 32-bit host.
+		 */
+		struct disk_image *disk;
+
+		disk = disk_image__new(fd, st->st_size, &ro_ops, DISK_IMAGE_MMAP);
+		if (IS_ERR_OR_NULL(disk)) {
+			disk = disk_image__new(fd, st->st_size, &ro_ops_nowrite, DISK_IMAGE_REGULAR);
+#ifdef CONFIG_HAS_AIO
+			if (!IS_ERR_OR_NULL(disk))
+				disk->async = 1;
+#endif
+		}
+
+		return disk;
+	} else {
+		/*
+		 * Use read/write instead of mmap
+		 */
+		disk = disk_image__new(fd, st->st_size, &raw_image_regular_ops, DISK_IMAGE_REGULAR);
+#ifdef CONFIG_HAS_AIO
+		if (!IS_ERR_OR_NULL(disk))
+			disk->async = 1;
+#endif
+		return disk;
+	}
+}
diff --git a/tools/kvm/framebuffer.c b/tools/kvm/framebuffer.c
new file mode 100644
index 0000000..e15b717
--- /dev/null
+++ b/tools/kvm/framebuffer.c
@@ -0,0 +1,75 @@
+#include "kvm/framebuffer.h"
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+static LIST_HEAD(framebuffers);
+
+struct framebuffer *fb__register(struct framebuffer *fb)
+{
+	INIT_LIST_HEAD(&fb->node);
+	list_add(&fb->node, &framebuffers);
+
+	return fb;
+}
+
+int fb__attach(struct framebuffer *fb, struct fb_target_operations *ops)
+{
+	if (fb->nr_targets >= FB_MAX_TARGETS)
+		return -ENOSPC;
+
+	fb->targets[fb->nr_targets++] = ops;
+
+	return 0;
+}
+
+static int start_targets(struct framebuffer *fb)
+{
+	unsigned long i;
+
+	for (i = 0; i < fb->nr_targets; i++) {
+		struct fb_target_operations *ops = fb->targets[i];
+		int err = 0;
+
+		if (ops->start)
+			err = ops->start(fb);
+
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+int fb__start(void)
+{
+	struct framebuffer *fb;
+
+	list_for_each_entry(fb, &framebuffers, node) {
+		int err;
+
+		err = start_targets(fb);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+void fb__stop(void)
+{
+	struct framebuffer *fb;
+
+	list_for_each_entry(fb, &framebuffers, node) {
+		u32 i;
+
+		for (i = 0; i < fb->nr_targets; i++)
+			if (fb->targets[i]->stop)
+				fb->targets[i]->stop(fb);
+
+		munmap(fb->mem, fb->mem_size);
+	}
+}
diff --git a/tools/kvm/guest/init.c b/tools/kvm/guest/init.c
new file mode 100644
index 0000000..032a261
--- /dev/null
+++ b/tools/kvm/guest/init.c
@@ -0,0 +1,38 @@
+/*
+ * This is a simple init for shared rootfs guests. This part should be limited
+ * to doing mounts and running stage 2 of the init process.
+ */
+#include <sys/mount.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+static int run_process(char *filename)
+{
+	char *new_argv[] = { filename, NULL };
+	char *new_env[] = { "TERM=linux", NULL };
+
+	return execve(filename, new_argv, new_env);
+}
+
+static void do_mounts(void)
+{
+	mount("hostfs", "/host", "9p", MS_RDONLY, "trans=virtio,version=9p2000.L");
+	mount("", "/sys", "sysfs", 0, NULL);
+	mount("proc", "/proc", "proc", 0, NULL);
+	mount("devtmpfs", "/dev", "devtmpfs", 0, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+	puts("Mounting...");
+
+	do_mounts();
+
+	run_process("/virt/init_stage2");
+
+	printf("Init failed: %s\n", strerror(errno));
+
+	return 0;
+}
diff --git a/tools/kvm/guest/init_stage2.c b/tools/kvm/guest/init_stage2.c
new file mode 100644
index 0000000..5f93894
--- /dev/null
+++ b/tools/kvm/guest/init_stage2.c
@@ -0,0 +1,55 @@
+/*
+ * This is a stage 2 of the init. This part should do all the heavy
+ * lifting such as setting up the console and calling /bin/sh.
+ */
+#include <sys/mount.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <linux/reboot.h>
+
+static int run_process(char *filename)
+{
+	char *new_argv[] = { filename, NULL };
+	char *new_env[] = { "TERM=linux", NULL };
+
+	return execve(filename, new_argv, new_env);
+}
+
+static int run_process_sandbox(char *filename)
+{
+	char *new_argv[] = { filename, "/virt/sandbox.sh", NULL };
+	char *new_env[] = { "TERM=linux", NULL };
+
+	return execve(filename, new_argv, new_env);
+}
+
+int main(int argc, char *argv[])
+{
+	pid_t child;
+	int status;
+
+	/* get session leader */
+	setsid();
+
+	/* set controlling terminal */
+	ioctl(0, TIOCSCTTY, 1);
+
+	child = fork();
+	if (child < 0) {
+		printf("Fatal: fork() failed with %d\n", child);
+		return 0;
+	} else if (child == 0) {
+		if (access("/virt/sandbox.sh", R_OK) == 0)
+			run_process_sandbox("/bin/sh");
+		else
+			run_process("/bin/sh");
+	} else {
+		waitpid(child, &status, 0);
+	}
+
+	reboot(LINUX_REBOOT_CMD_RESTART);
+
+	return 0;
+}
diff --git a/tools/kvm/guest/passwd b/tools/kvm/guest/passwd
new file mode 100644
index 0000000..eb85a55
--- /dev/null
+++ b/tools/kvm/guest/passwd
@@ -0,0 +1 @@
+root:x:0:0:root:/root:/bin/sh
diff --git a/tools/kvm/guest_compat.c b/tools/kvm/guest_compat.c
new file mode 100644
index 0000000..fd4704b
--- /dev/null
+++ b/tools/kvm/guest_compat.c
@@ -0,0 +1,99 @@
+#include "kvm/guest_compat.h"
+
+#include "kvm/mutex.h"
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+struct compat_message {
+	int id;
+	char *title;
+	char *desc;
+
+	struct list_head list;
+};
+
+static int id;
+static DEFINE_MUTEX(compat_mtx);
+static LIST_HEAD(messages);
+
+static void compat__free(struct compat_message *msg)
+{
+	free(msg->title);
+	free(msg->desc);
+	free(msg);
+}
+
+int compat__add_message(const char *title, const char *desc)
+{
+	struct compat_message *msg;
+	int msg_id;
+
+	msg = malloc(sizeof(*msg));
+	if (msg == NULL)
+		goto cleanup;
+
+	msg->title = strdup(title);
+	msg->desc = strdup(desc);
+
+	if (msg->title == NULL || msg->desc == NULL)
+		goto cleanup;
+
+	mutex_lock(&compat_mtx);
+
+	msg->id = msg_id = id++;
+	list_add_tail(&msg->list, &messages);
+
+	mutex_unlock(&compat_mtx);
+
+	return msg_id;
+
+cleanup:
+	if (msg)
+		compat__free(msg);
+
+	return -ENOMEM;
+}
+
+int compat__remove_message(int id)
+{
+	struct compat_message *pos, *n;
+
+	mutex_lock(&compat_mtx);
+
+	list_for_each_entry_safe(pos, n, &messages, list) {
+		if (pos->id == id) {
+			list_del(&pos->list);
+			compat__free(pos);
+
+			mutex_unlock(&compat_mtx);
+
+			return 0;
+		}
+	}
+
+	mutex_unlock(&compat_mtx);
+
+	return -ENOENT;
+}
+
+int compat__print_all_messages(void)
+{
+	mutex_lock(&compat_mtx);
+
+	while (!list_empty(&messages)) {
+		struct compat_message *msg;
+
+		msg = list_first_entry(&messages, struct compat_message, list);
+
+		printf("\n  # KVM compatibility warning.\n\t%s\n\t%s\n",
+			msg->title, msg->desc);
+
+		list_del(&msg->list);
+		compat__free(msg);
+	}
+
+	mutex_unlock(&compat_mtx);
+
+	return 0;
+}
diff --git a/tools/kvm/hw/i8042.c b/tools/kvm/hw/i8042.c
new file mode 100644
index 0000000..3a36425
--- /dev/null
+++ b/tools/kvm/hw/i8042.c
@@ -0,0 +1,348 @@
+#include "kvm/read-write.h"
+#include "kvm/ioport.h"
+#include "kvm/mutex.h"
+#include "kvm/util.h"
+#include "kvm/term.h"
+#include "kvm/kvm.h"
+#include "kvm/i8042.h"
+#include "kvm/kvm-cpu.h"
+
+#include <stdint.h>
+
+/*
+ * IRQs
+ */
+#define KBD_IRQ			1
+#define AUX_IRQ			12
+
+/*
+ * Registers
+ */
+#define I8042_DATA_REG		0x60
+#define I8042_COMMAND_REG	0x64
+
+/*
+ * Commands
+ */
+#define I8042_CMD_CTL_RCTR	0x20
+#define I8042_CMD_CTL_WCTR	0x60
+#define I8042_CMD_AUX_LOOP	0xD3
+#define I8042_CMD_AUX_SEND	0xD4
+#define I8042_CMD_AUX_TEST	0xA9
+#define I8042_CMD_AUX_DISABLE	0xA7
+#define I8042_CMD_AUX_ENABLE	0xA8
+#define I8042_CMD_SYSTEM_RESET	0xFE
+
+#define RESPONSE_ACK		0xFA
+
+#define MODE_DISABLE_AUX	0x20
+
+#define AUX_ENABLE_REPORTING	0x20
+#define AUX_SCALING_FLAG	0x10
+#define AUX_DEFAULT_RESOLUTION	0x2
+#define AUX_DEFAULT_SAMPLE	100
+
+/*
+ * Status register bits
+ */
+#define I8042_STR_AUXDATA	0x20
+#define I8042_STR_KEYLOCK	0x10
+#define I8042_STR_CMDDAT	0x08
+#define I8042_STR_MUXERR	0x04
+#define I8042_STR_OBF		0x01
+
+#define KBD_MODE_KBD_INT	0x01
+#define KBD_MODE_SYS		0x02
+
+#define QUEUE_SIZE		128
+
+/*
+ * This represents the current state of the PS/2 keyboard system,
+ * including the AUX device (the mouse)
+ */
+struct kbd_state {
+	struct kvm		*kvm;
+
+	char			kq[QUEUE_SIZE];	/* Keyboard queue */
+	int			kread, kwrite;	/* Indexes into the queue */
+	int			kcount;		/* number of elements in queue */
+
+	char			mq[QUEUE_SIZE];
+	int			mread, mwrite;
+	int			mcount;
+
+	u8			mstatus;	/* Mouse status byte */
+	u8			mres;		/* Current mouse resolution */
+	u8			msample;	/* Current mouse samples/second */
+
+	u8			mode;		/* i8042 mode register */
+	u8			status;		/* i8042 status register */
+	/*
+	 * Some commands (on port 0x64) have arguments;
+	 * we store the command here while we wait for the argument
+	 */
+	u32			write_cmd;
+};
+
+static struct kbd_state		state;
+
+/*
+ * If there are packets to be read, set the appropriate IRQs high
+ */
+static void kbd_update_irq(void)
+{
+	u8 klevel = 0;
+	u8 mlevel = 0;
+
+	/* First, clear the kbd and aux output buffer full bits */
+	state.status &= ~(I8042_STR_OBF | I8042_STR_AUXDATA);
+
+	if (state.kcount > 0) {
+		state.status |= I8042_STR_OBF;
+		klevel = 1;
+	}
+
+	/* Keyboard has higher priority than mouse */
+	if (klevel == 0 && state.mcount != 0) {
+		state.status |= I8042_STR_OBF | I8042_STR_AUXDATA;
+		mlevel = 1;
+	}
+
+	kvm__irq_line(state.kvm, KBD_IRQ, klevel);
+	kvm__irq_line(state.kvm, AUX_IRQ, mlevel);
+}
+
+/*
+ * Add a byte to the mouse queue, then set IRQs
+ */
+void mouse_queue(u8 c)
+{
+	if (state.mcount >= QUEUE_SIZE)
+		return;
+
+	state.mq[state.mwrite++ % QUEUE_SIZE] = c;
+
+	state.mcount++;
+	kbd_update_irq();
+}
+
+/*
+ * Add a byte to the keyboard queue, then set IRQs
+ */
+void kbd_queue(u8 c)
+{
+	if (state.kcount >= QUEUE_SIZE)
+		return;
+
+	state.kq[state.kwrite++ % QUEUE_SIZE] = c;
+
+	state.kcount++;
+	kbd_update_irq();
+}
+
+static void kbd_write_command(struct kvm *kvm, u8 val)
+{
+	switch (val) {
+	case I8042_CMD_CTL_RCTR:
+		kbd_queue(state.mode);
+		break;
+	case I8042_CMD_CTL_WCTR:
+	case I8042_CMD_AUX_SEND:
+	case I8042_CMD_AUX_LOOP:
+		state.write_cmd = val;
+		break;
+	case I8042_CMD_AUX_TEST:
+		/* 0 means we're a normal PS/2 mouse */
+		mouse_queue(0);
+		break;
+	case I8042_CMD_AUX_DISABLE:
+		state.mode |= MODE_DISABLE_AUX;
+		break;
+	case I8042_CMD_AUX_ENABLE:
+		state.mode &= ~MODE_DISABLE_AUX;
+		break;
+	case I8042_CMD_SYSTEM_RESET:
+		kvm_cpu__reboot();
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * Called when the OS reads from port 0x60 (PS/2 data)
+ */
+static u32 kbd_read_data(void)
+{
+	u32 ret;
+	int i;
+
+	if (state.kcount != 0) {
+		/* Keyboard data gets read first */
+		ret = state.kq[state.kread++ % QUEUE_SIZE];
+		state.kcount--;
+		kvm__irq_line(state.kvm, KBD_IRQ, 0);
+		kbd_update_irq();
+	} else if (state.mcount > 0) {
+		/* Followed by the mouse */
+		ret = state.mq[state.mread++ % QUEUE_SIZE];
+		state.mcount--;
+		kvm__irq_line(state.kvm, AUX_IRQ, 0);
+		kbd_update_irq();
+	} else if (state.kcount == 0) {
+		i = state.kread - 1;
+		if (i < 0)
+			i = QUEUE_SIZE;
+		ret = state.kq[i];
+	}
+	return ret;
+}
+
+/*
+ * Called when the OS read from port 0x64, the command port
+ */
+static u32 kbd_read_status(void)
+{
+	return (u32)state.status;
+}
+
+/*
+ * Called when the OS writes to port 0x60 (data port)
+ * Things written here are generally arguments to commands previously
+ * written to port 0x64 and stored in state.write_cmd
+ */
+static void kbd_write_data(u32 val)
+{
+	switch (state.write_cmd) {
+	case I8042_CMD_CTL_WCTR:
+		state.mode = val;
+		kbd_update_irq();
+		break;
+	case I8042_CMD_AUX_LOOP:
+		mouse_queue(val);
+		mouse_queue(RESPONSE_ACK);
+		break;
+	case I8042_CMD_AUX_SEND:
+		/* The OS wants to send a command to the mouse */
+		mouse_queue(RESPONSE_ACK);
+		switch (val) {
+		case 0xe6:
+			/* set scaling = 1:1 */
+			state.mstatus &= ~AUX_SCALING_FLAG;
+			break;
+		case 0xe8:
+			/* set resolution */
+			state.mres = val;
+			break;
+		case 0xe9:
+			/* Report mouse status/config */
+			mouse_queue(state.mstatus);
+			mouse_queue(state.mres);
+			mouse_queue(state.msample);
+			break;
+		case 0xf2:
+			/* send ID */
+			mouse_queue(0); /* normal mouse */
+			break;
+		case 0xf3:
+			/* set sample rate */
+			state.msample = val;
+			break;
+		case 0xf4:
+			/* enable reporting */
+			state.mstatus |= AUX_ENABLE_REPORTING;
+			break;
+		case 0xf5:
+			state.mstatus &= ~AUX_ENABLE_REPORTING;
+			break;
+		case 0xf6:
+			/* set defaults, just fall through to reset */
+		case 0xff:
+			/* reset */
+			state.mstatus = 0x0;
+			state.mres = AUX_DEFAULT_RESOLUTION;
+			state.msample = AUX_DEFAULT_SAMPLE;
+			break;
+		default:
+			break;
+	}
+	break;
+	case 0:
+		/* Just send the ID */
+		kbd_queue(RESPONSE_ACK);
+		kbd_queue(0xab);
+		kbd_queue(0x41);
+		kbd_update_irq();
+		break;
+	default:
+		/* Yeah whatever */
+		break;
+	}
+	state.write_cmd = 0;
+}
+
+static void kbd_reset(void)
+{
+	state = (struct kbd_state) {
+		.status		= I8042_STR_MUXERR | I8042_STR_CMDDAT | I8042_STR_KEYLOCK, /* 0x1c */
+		.mode		= KBD_MODE_KBD_INT | KBD_MODE_SYS, /* 0x3 */
+		.mres		= AUX_DEFAULT_RESOLUTION,
+		.msample	= AUX_DEFAULT_SAMPLE,
+	};
+}
+
+/*
+ * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
+ */
+static bool kbd_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	switch (port) {
+	case I8042_COMMAND_REG: {
+		u8 value = kbd_read_status();
+		ioport__write8(data, value);
+		break;
+	}
+	case I8042_DATA_REG: {
+		u32 value = kbd_read_data();
+		ioport__write32(data, value);
+		break;
+	}
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+static bool kbd_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	switch (port) {
+	case I8042_COMMAND_REG: {
+		u8 value = ioport__read8(data);
+		kbd_write_command(kvm, value);
+		break;
+	}
+	case I8042_DATA_REG: {
+		u32 value = ioport__read32(data);
+		kbd_write_data(value);
+		break;
+	}
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+static struct ioport_operations kbd_ops = {
+	.io_in		= kbd_in,
+	.io_out		= kbd_out,
+};
+
+void kbd__init(struct kvm *kvm)
+{
+	kbd_reset();
+	state.kvm = kvm;
+	ioport__register(I8042_DATA_REG, &kbd_ops, 2, NULL);
+	ioport__register(I8042_COMMAND_REG, &kbd_ops, 2, NULL);
+}
diff --git a/tools/kvm/hw/pci-shmem.c b/tools/kvm/hw/pci-shmem.c
new file mode 100644
index 0000000..ac2d264
--- /dev/null
+++ b/tools/kvm/hw/pci-shmem.c
@@ -0,0 +1,268 @@
+#include "kvm/pci-shmem.h"
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+#include "kvm/util.h"
+#include "kvm/ioport.h"
+#include "kvm/ioeventfd.h"
+
+#include <linux/kvm.h>
+#include <linux/byteorder.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+static struct pci_device_header pci_shmem_pci_device = {
+	.vendor_id	= cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
+	.device_id	= cpu_to_le16(0x1110),
+	.header_type	= PCI_HEADER_TYPE_NORMAL,
+	.class[2]	= 0xFF,	/* misc pci device */
+	.status		= cpu_to_le16(PCI_STATUS_CAP_LIST),
+	.capabilities	= (void *)&pci_shmem_pci_device.msix - (void *)&pci_shmem_pci_device,
+	.msix.cap	= PCI_CAP_ID_MSIX,
+	.msix.ctrl	= cpu_to_le16(1),
+	.msix.table_offset = cpu_to_le32(1),		/* Use BAR 1 */
+	.msix.pba_offset = cpu_to_le32(0x1001),		/* Use BAR 1 */
+};
+
+/* registers for the Inter-VM shared memory device */
+enum ivshmem_registers {
+	INTRMASK = 0,
+	INTRSTATUS = 4,
+	IVPOSITION = 8,
+	DOORBELL = 12,
+};
+
+static struct shmem_info *shmem_region;
+static u16 ivshmem_registers;
+static int local_fd;
+static u32 local_id;
+static u64 msix_block;
+static u64 msix_pba;
+static struct msix_table msix_table[2];
+
+int pci_shmem__register_mem(struct shmem_info *si)
+{
+	if (shmem_region == NULL) {
+		shmem_region = si;
+	} else {
+		pr_warning("only single shmem currently avail. ignoring.\n");
+		free(si);
+	}
+	return 0;
+}
+
+static bool shmem_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	u16 offset = port - ivshmem_registers;
+
+	switch (offset) {
+	case INTRMASK:
+		break;
+	case INTRSTATUS:
+		break;
+	case IVPOSITION:
+		ioport__write32(data, local_id);
+		break;
+	case DOORBELL:
+		break;
+	};
+
+	return true;
+}
+
+static bool shmem_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	u16 offset = port - ivshmem_registers;
+
+	switch (offset) {
+	case INTRMASK:
+		break;
+	case INTRSTATUS:
+		break;
+	case IVPOSITION:
+		break;
+	case DOORBELL:
+		break;
+	};
+
+	return true;
+}
+
+static struct ioport_operations shmem_pci__io_ops = {
+	.io_in	= shmem_pci__io_in,
+	.io_out	= shmem_pci__io_out,
+};
+
+static void callback_mmio_msix(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
+{
+	void *mem;
+
+	if (addr - msix_block < 0x1000)
+		mem = &msix_table;
+	else
+		mem = &msix_pba;
+
+	if (is_write)
+		memcpy(mem + addr - msix_block, data, len);
+	else
+		memcpy(data, mem + addr - msix_block, len);
+}
+
+/*
+ * Return an irqfd which can be used by other guests to signal this guest
+ * whenever they need to poke it
+ */
+int pci_shmem__get_local_irqfd(struct kvm *kvm)
+{
+	int fd, gsi, r;
+	struct kvm_irqfd irqfd;
+
+	if (local_fd == 0) {
+		fd = eventfd(0, 0);
+		if (fd < 0)
+			return fd;
+
+		if (pci_shmem_pci_device.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE)) {
+			gsi = irq__add_msix_route(kvm, &msix_table[0].msg);
+		} else {
+			gsi = pci_shmem_pci_device.irq_line;
+		}
+
+		irqfd = (struct kvm_irqfd) {
+			.fd = fd,
+			.gsi = gsi,
+		};
+
+		r = ioctl(kvm->vm_fd, KVM_IRQFD, &irqfd);
+		if (r < 0)
+			return r;
+
+		local_fd = fd;
+	}
+
+	return local_fd;
+}
+
+/*
+ * Connect a new client to ivshmem by adding the appropriate datamatch
+ * to the DOORBELL
+ */
+int pci_shmem__add_client(struct kvm *kvm, u32 id, int fd)
+{
+	struct kvm_ioeventfd ioevent;
+
+	ioevent = (struct kvm_ioeventfd) {
+		.addr		= ivshmem_registers + DOORBELL,
+		.len		= sizeof(u32),
+		.datamatch	= id,
+		.fd		= fd,
+		.flags		= KVM_IOEVENTFD_FLAG_PIO | KVM_IOEVENTFD_FLAG_DATAMATCH,
+	};
+
+	return ioctl(kvm->vm_fd, KVM_IOEVENTFD, &ioevent);
+}
+
+/*
+ * Remove a client connected to ivshmem by removing the appropriate datamatch
+ * from the DOORBELL
+ */
+int pci_shmem__remove_client(struct kvm *kvm, u32 id)
+{
+	struct kvm_ioeventfd ioevent;
+
+	ioevent = (struct kvm_ioeventfd) {
+		.addr		= ivshmem_registers + DOORBELL,
+		.len		= sizeof(u32),
+		.datamatch	= id,
+		.flags		= KVM_IOEVENTFD_FLAG_PIO
+				| KVM_IOEVENTFD_FLAG_DATAMATCH
+				| KVM_IOEVENTFD_FLAG_DEASSIGN,
+	};
+
+	return ioctl(kvm->vm_fd, KVM_IOEVENTFD, &ioevent);
+}
+
+static void *setup_shmem(const char *key, size_t len, int creating)
+{
+	int fd;
+	int rtn;
+	void *mem;
+	int flag = O_RDWR;
+
+	if (creating)
+		flag |= O_CREAT;
+
+	fd = shm_open(key, flag, S_IRUSR | S_IWUSR);
+	if (fd < 0) {
+		pr_warning("Failed to open shared memory file %s\n", key);
+		return NULL;
+	}
+
+	if (creating) {
+		rtn = ftruncate(fd, (off_t) len);
+		if (rtn < 0)
+			pr_warning("Can't ftruncate(fd,%zu)\n", len);
+	}
+	mem = mmap(NULL, len,
+		   PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd, 0);
+	if (mem == MAP_FAILED) {
+		pr_warning("Failed to mmap shared memory file");
+		mem = NULL;
+	}
+	close(fd);
+
+	return mem;
+}
+
+int pci_shmem__init(struct kvm *kvm)
+{
+	u8 dev, line, pin;
+	char *mem;
+	int r;
+
+	if (shmem_region == 0)
+		return 0;
+
+	/* Register good old INTx */
+	if (irq__register_device(PCI_DEVICE_ID_PCI_SHMEM, &dev, &pin, &line) < 0)
+		return 0;
+
+	pci_shmem_pci_device.irq_pin = pin;
+	pci_shmem_pci_device.irq_line = line;
+
+	/* Register MMIO space for MSI-X */
+	r = ioport__register(IOPORT_EMPTY, &shmem_pci__io_ops, IOPORT_SIZE, NULL);
+	if (r < 0)
+		return r;
+	ivshmem_registers = (u16)r;
+
+	msix_block = pci_get_io_space_block(0x1010);
+	kvm__register_mmio(kvm, msix_block, 0x1010, false, callback_mmio_msix, NULL);
+
+	/*
+	 * This registers 3 BARs:
+	 *
+	 * 0 - ivshmem registers
+	 * 1 - MSI-X MMIO space
+	 * 2 - Shared memory block
+	 */
+	pci_shmem_pci_device.bar[0] = cpu_to_le32(ivshmem_registers | PCI_BASE_ADDRESS_SPACE_IO);
+	pci_shmem_pci_device.bar_size[0] = shmem_region->size;
+	pci_shmem_pci_device.bar[1] = cpu_to_le32(msix_block | PCI_BASE_ADDRESS_SPACE_MEMORY);
+	pci_shmem_pci_device.bar_size[1] = 0x1010;
+	pci_shmem_pci_device.bar[2] = cpu_to_le32(shmem_region->phys_addr | PCI_BASE_ADDRESS_SPACE_MEMORY);
+	pci_shmem_pci_device.bar_size[2] = shmem_region->size;
+
+	pci__register(&pci_shmem_pci_device, dev);
+
+	/* Open shared memory and plug it into the guest */
+	mem = setup_shmem(shmem_region->handle, shmem_region->size,
+				shmem_region->create);
+	if (mem == NULL)
+		return 0;
+	kvm__register_mem(kvm, shmem_region->phys_addr, shmem_region->size,
+			  mem);
+	return 1;
+}
diff --git a/tools/kvm/hw/rtc.c b/tools/kvm/hw/rtc.c
new file mode 100644
index 0000000..b4f9f1f
--- /dev/null
+++ b/tools/kvm/hw/rtc.c
@@ -0,0 +1,137 @@
+#include "kvm/rtc.h"
+
+#include "kvm/ioport.h"
+#include "kvm/kvm.h"
+
+#include <time.h>
+
+/*
+ * MC146818 RTC registers
+ */
+#define RTC_SECONDS			0x00
+#define RTC_SECONDS_ALARM		0x01
+#define RTC_MINUTES			0x02
+#define RTC_MINUTES_ALARM		0x03
+#define RTC_HOURS			0x04
+#define RTC_HOURS_ALARM			0x05
+#define RTC_DAY_OF_WEEK			0x06
+#define RTC_DAY_OF_MONTH		0x07
+#define RTC_MONTH			0x08
+#define RTC_YEAR			0x09
+
+#define RTC_REG_A			0x0A
+#define RTC_REG_B			0x0B
+#define RTC_REG_C			0x0C
+#define RTC_REG_D			0x0D
+
+struct rtc_device {
+	u8			cmos_idx;
+	u8			cmos_data[128];
+};
+
+static struct rtc_device	rtc;
+
+static inline unsigned char bin2bcd(unsigned val)
+{
+	return ((val / 10) << 4) + val % 10;
+}
+
+static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	struct tm *tm;
+	time_t ti;
+
+	time(&ti);
+
+	tm = gmtime(&ti);
+
+	switch (rtc.cmos_idx) {
+	case RTC_SECONDS:
+		ioport__write8(data, bin2bcd(tm->tm_sec));
+		break;
+	case RTC_MINUTES:
+		ioport__write8(data, bin2bcd(tm->tm_min));
+		break;
+	case RTC_HOURS:
+		ioport__write8(data, bin2bcd(tm->tm_hour));
+		break;
+	case RTC_DAY_OF_WEEK:
+		ioport__write8(data, bin2bcd(tm->tm_wday + 1));
+		break;
+	case RTC_DAY_OF_MONTH:
+		ioport__write8(data, bin2bcd(tm->tm_mday));
+		break;
+	case RTC_MONTH:
+		ioport__write8(data, bin2bcd(tm->tm_mon + 1));
+		break;
+	case RTC_YEAR:
+		ioport__write8(data, bin2bcd(tm->tm_year));
+		break;
+	default:
+		ioport__write8(data, rtc.cmos_data[rtc.cmos_idx]);
+		break;
+	}
+
+	return true;
+}
+
+static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	switch (rtc.cmos_idx) {
+	case RTC_REG_C:
+	case RTC_REG_D:
+		/* Read-only */
+		break;
+	default:
+		rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data);
+		break;
+	}
+
+	return true;
+}
+
+static struct ioport_operations cmos_ram_data_ioport_ops = {
+	.io_out		= cmos_ram_data_out,
+	.io_in		= cmos_ram_data_in,
+};
+
+static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	u8 value = ioport__read8(data);
+
+	kvm->nmi_disabled	= value & (1UL << 7);
+	rtc.cmos_idx		= value & ~(1UL << 7);
+
+	return true;
+}
+
+static struct ioport_operations cmos_ram_index_ioport_ops = {
+	.io_out		= cmos_ram_index_out,
+};
+
+int rtc__init(struct kvm *kvm)
+{
+	int r = 0;
+
+	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
+	r = ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
+	if (r < 0)
+		return r;
+
+	r = ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
+	if (r < 0) {
+		ioport__unregister(0x0071);
+		return r;
+	}
+
+	return r;
+}
+
+int rtc__exit(struct kvm *kvm)
+{
+	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
+	ioport__unregister(0x0070);
+	ioport__unregister(0x0071);
+
+	return 0;
+}
\ No newline at end of file
diff --git a/tools/kvm/hw/serial.c b/tools/kvm/hw/serial.c
new file mode 100644
index 0000000..852aea4
--- /dev/null
+++ b/tools/kvm/hw/serial.c
@@ -0,0 +1,447 @@
+#include "kvm/8250-serial.h"
+
+#include "kvm/read-write.h"
+#include "kvm/ioport.h"
+#include "kvm/mutex.h"
+#include "kvm/util.h"
+#include "kvm/term.h"
+#include "kvm/kvm.h"
+
+#include <linux/types.h>
+#include <linux/serial_reg.h>
+
+#include <pthread.h>
+
+/*
+ * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel
+ * expects that for autodetection.
+ */
+#define FIFO_LEN		64
+#define FIFO_MASK		(FIFO_LEN - 1)
+
+#define UART_IIR_TYPE_BITS	0xc0
+
+struct serial8250_device {
+	pthread_mutex_t		mutex;
+	u8			id;
+
+	u16			iobase;
+	u8			irq;
+	u8			irq_state;
+	int			txcnt;
+	int			rxcnt;
+	int			rxdone;
+	char			txbuf[FIFO_LEN];
+	char			rxbuf[FIFO_LEN];
+
+	u8			dll;
+	u8			dlm;
+	u8			iir;
+	u8			ier;
+	u8			fcr;
+	u8			lcr;
+	u8			mcr;
+	u8			lsr;
+	u8			msr;
+	u8			scr;
+};
+
+#define SERIAL_REGS_SETTING \
+	.iir			= UART_IIR_NO_INT, \
+	.lsr			= UART_LSR_TEMT | UART_LSR_THRE, \
+	.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \
+	.mcr			= UART_MCR_OUT2,
+
+static struct serial8250_device devices[] = {
+	/* ttyS0 */
+	[0]	= {
+		.mutex			= PTHREAD_MUTEX_INITIALIZER,
+
+		.id			= 0,
+		.iobase			= 0x3f8,
+		.irq			= 4,
+
+		SERIAL_REGS_SETTING
+	},
+	/* ttyS1 */
+	[1]	= {
+		.mutex			= PTHREAD_MUTEX_INITIALIZER,
+
+		.id			= 1,
+		.iobase			= 0x2f8,
+		.irq			= 3,
+
+		SERIAL_REGS_SETTING
+	},
+	/* ttyS2 */
+	[2]	= {
+		.mutex			= PTHREAD_MUTEX_INITIALIZER,
+
+		.id			= 2,
+		.iobase			= 0x3e8,
+		.irq			= 4,
+
+		SERIAL_REGS_SETTING
+	},
+	/* ttyS3 */
+	[3]	= {
+		.mutex			= PTHREAD_MUTEX_INITIALIZER,
+
+		.id			= 3,
+		.iobase			= 0x2e8,
+		.irq			= 3,
+
+		SERIAL_REGS_SETTING
+	},
+};
+
+static void serial8250_flush_tx(struct serial8250_device *dev)
+{
+	dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
+
+	if (dev->txcnt) {
+		term_putc(CONSOLE_8250, dev->txbuf, dev->txcnt, dev->id);
+		dev->txcnt = 0;
+	}
+}
+
+static void serial8250_update_irq(struct kvm *kvm, struct serial8250_device *dev)
+{
+	u8 iir = 0;
+
+	/* Handle clear rx */
+	if (dev->lcr & UART_FCR_CLEAR_RCVR) {
+		dev->lcr &= ~UART_FCR_CLEAR_RCVR;
+		dev->rxcnt = dev->rxdone = 0;
+		dev->lsr &= ~UART_LSR_DR;
+	}
+
+	/* Handle clear tx */
+	if (dev->lcr & UART_FCR_CLEAR_XMIT) {
+		dev->lcr &= ~UART_FCR_CLEAR_XMIT;
+		dev->txcnt = 0;
+		dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
+	}
+
+	/* Data ready and rcv interrupt enabled ? */
+	if ((dev->ier & UART_IER_RDI) && (dev->lsr & UART_LSR_DR))
+		iir |= UART_IIR_RDI;
+
+	/* Transmitter empty and interrupt enabled ? */
+	if ((dev->ier & UART_IER_THRI) && (dev->lsr & UART_LSR_TEMT))
+		iir |= UART_IIR_THRI;
+
+	/* Now update the irq line, if necessary */
+	if (!iir) {
+		dev->iir = UART_IIR_NO_INT;
+		if (dev->irq_state)
+			kvm__irq_line(kvm, dev->irq, 0);
+	} else {
+		dev->iir = iir;
+		if (!dev->irq_state)
+			kvm__irq_line(kvm, dev->irq, 1);
+	}
+	dev->irq_state = iir;
+
+	/*
+	 * If the kernel disabled the tx interrupt, we know that there
+	 * is nothing more to transmit, so we can reset our tx logic
+	 * here.
+	 */
+	if (!(dev->ier & UART_IER_THRI))
+		serial8250_flush_tx(dev);
+}
+
+#define SYSRQ_PENDING_NONE		0
+#define SYSRQ_PENDING_BREAK		1
+
+static int sysrq_pending;
+
+static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev)
+{
+	dev->lsr |= UART_LSR_DR | UART_LSR_BI;
+	dev->rxbuf[dev->rxcnt++] = 'p';
+	sysrq_pending	= SYSRQ_PENDING_NONE;
+}
+
+static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev,
+				bool handle_sysrq)
+{
+	int c;
+
+	/*
+	 * If the guest transmitted a full fifo, we clear the
+	 * TEMT/THRE bits to let the kernel escape from the 8250
+	 * interrupt handler. We come here only once a ms, so that
+	 * should give the kernel the desired pause. That also flushes
+	 * the tx fifo to the terminal.
+	 */
+	serial8250_flush_tx(dev);
+
+	if (dev->mcr & UART_MCR_LOOP)
+		return;
+
+	if ((dev->lsr & UART_LSR_DR) || dev->rxcnt)
+		return;
+
+	if (handle_sysrq && sysrq_pending) {
+		serial8250__sysrq(kvm, dev);
+		return;
+	}
+
+	while (term_readable(CONSOLE_8250, dev->id) &&
+	       dev->rxcnt < FIFO_LEN) {
+
+		c = term_getc(CONSOLE_8250, dev->id);
+
+		if (c < 0)
+			break;
+		dev->rxbuf[dev->rxcnt++] = c;
+		dev->lsr |= UART_LSR_DR;
+	}
+}
+
+void serial8250__update_consoles(struct kvm *kvm)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(devices); i++) {
+		struct serial8250_device *dev = &devices[i];
+
+		mutex_lock(&dev->mutex);
+
+		/* Restrict sysrq injection to the first port */
+		serial8250__receive(kvm, dev, i == 0);
+
+		serial8250_update_irq(kvm, dev);
+
+		mutex_unlock(&dev->mutex);
+	}
+}
+
+void serial8250__inject_sysrq(struct kvm *kvm)
+{
+	sysrq_pending	= SYSRQ_PENDING_BREAK;
+}
+
+static struct serial8250_device *find_device(u16 port)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(devices); i++) {
+		struct serial8250_device *dev = &devices[i];
+
+		if (dev->iobase == (port & ~0x7))
+			return dev;
+	}
+	return NULL;
+}
+
+static bool serial8250_out(struct ioport *ioport, struct kvm *kvm, u16 port,
+			   void *data, int size)
+{
+	struct serial8250_device *dev;
+	u16 offset;
+	bool ret = true;
+	char *addr = data;
+
+	dev = find_device(port);
+	if (!dev)
+		return false;
+
+	mutex_lock(&dev->mutex);
+
+	offset = port - dev->iobase;
+
+	switch (offset) {
+	case UART_TX:
+		if (dev->lcr & UART_LCR_DLAB) {
+			dev->dll = ioport__read8(data);
+			break;
+		}
+
+		/* Loopback mode */
+		if (dev->mcr & UART_MCR_LOOP) {
+			if (dev->rxcnt < FIFO_LEN) {
+				dev->rxbuf[dev->rxcnt++] = *addr;
+				dev->lsr |= UART_LSR_DR;
+			}
+			break;
+		}
+
+		if (dev->txcnt < FIFO_LEN) {
+			dev->txbuf[dev->txcnt++] = *addr;
+			dev->lsr &= ~UART_LSR_TEMT;
+			if (dev->txcnt == FIFO_LEN / 2)
+				dev->lsr &= ~UART_LSR_THRE;
+		} else {
+			/* Should never happpen */
+			dev->lsr &= ~(UART_LSR_TEMT | UART_LSR_THRE);
+		}
+		break;
+	case UART_IER:
+		if (!(dev->lcr & UART_LCR_DLAB))
+			dev->ier = ioport__read8(data) & 0x0f;
+		else
+			dev->dlm = ioport__read8(data);
+		break;
+	case UART_FCR:
+		dev->fcr = ioport__read8(data);
+		break;
+	case UART_LCR:
+		dev->lcr = ioport__read8(data);
+		break;
+	case UART_MCR:
+		dev->mcr = ioport__read8(data);
+		break;
+	case UART_LSR:
+		/* Factory test */
+		break;
+	case UART_MSR:
+		/* Not used */
+		break;
+	case UART_SCR:
+		dev->scr = ioport__read8(data);
+		break;
+	default:
+		ret = false;
+		break;
+	}
+
+	serial8250_update_irq(kvm, dev);
+
+	mutex_unlock(&dev->mutex);
+
+	return ret;
+}
+
+static void serial8250_rx(struct serial8250_device *dev, void *data)
+{
+	if (dev->rxdone == dev->rxcnt)
+		return;
+
+	/* Break issued ? */
+	if (dev->lsr & UART_LSR_BI) {
+		dev->lsr &= ~UART_LSR_BI;
+		ioport__write8(data, 0);
+		return;
+	}
+
+	ioport__write8(data, dev->rxbuf[dev->rxdone++]);
+	if (dev->rxcnt == dev->rxdone) {
+		dev->lsr &= ~UART_LSR_DR;
+		dev->rxcnt = dev->rxdone = 0;
+	}
+}
+
+static bool serial8250_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	struct serial8250_device *dev;
+	u16 offset;
+	bool ret = true;
+
+	dev = find_device(port);
+	if (!dev)
+		return false;
+
+	mutex_lock(&dev->mutex);
+
+	offset = port - dev->iobase;
+
+	switch (offset) {
+	case UART_RX:
+		if (dev->lcr & UART_LCR_DLAB)
+			ioport__write8(data, dev->dll);
+		else
+			serial8250_rx(dev, data);
+		break;
+	case UART_IER:
+		if (dev->lcr & UART_LCR_DLAB)
+			ioport__write8(data, dev->dlm);
+		else
+			ioport__write8(data, dev->ier);
+		break;
+	case UART_IIR:
+		ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS);
+		break;
+	case UART_LCR:
+		ioport__write8(data, dev->lcr);
+		break;
+	case UART_MCR:
+		ioport__write8(data, dev->mcr);
+		break;
+	case UART_LSR:
+		ioport__write8(data, dev->lsr);
+		break;
+	case UART_MSR:
+		ioport__write8(data, dev->msr);
+		break;
+	case UART_SCR:
+		ioport__write8(data, dev->scr);
+		break;
+	default:
+		ret = false;
+		break;
+	}
+
+	serial8250_update_irq(kvm, dev);
+
+	mutex_unlock(&dev->mutex);
+
+	return ret;
+}
+
+static struct ioport_operations serial8250_ops = {
+	.io_in		= serial8250_in,
+	.io_out		= serial8250_out,
+};
+
+static int serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
+{
+	int r;
+
+	r = ioport__register(dev->iobase, &serial8250_ops, 8, NULL);
+	kvm__irq_line(kvm, dev->irq, 0);
+
+	return r;
+}
+
+int serial8250__init(struct kvm *kvm)
+{
+	unsigned int i, j;
+	int r = 0;
+
+	for (i = 0; i < ARRAY_SIZE(devices); i++) {
+		struct serial8250_device *dev = &devices[i];
+
+		r = serial8250__device_init(kvm, dev);
+		if (r < 0)
+			goto cleanup;
+	}
+
+	return r;
+cleanup:
+	for (j = 0; j <= i; j++) {
+		struct serial8250_device *dev = &devices[j];
+
+		ioport__unregister(dev->iobase);
+	}
+
+	return r;
+}
+
+int serial8250__exit(struct kvm *kvm)
+{
+	unsigned int i;
+	int r;
+
+	for (i = 0; i < ARRAY_SIZE(devices); i++) {
+		struct serial8250_device *dev = &devices[i];
+
+		r = ioport__unregister(dev->iobase);
+		if (r < 0)
+			return r;
+	}
+
+	return 0;
+}
diff --git a/tools/kvm/hw/vesa.c b/tools/kvm/hw/vesa.c
new file mode 100644
index 0000000..757f0a2
--- /dev/null
+++ b/tools/kvm/hw/vesa.c
@@ -0,0 +1,85 @@
+#include "kvm/vesa.h"
+
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/framebuffer.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/ioport.h"
+#include "kvm/util.h"
+#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+
+#include <linux/byteorder.h>
+#include <sys/mman.h>
+#include <linux/err.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+static bool vesa_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	return true;
+}
+
+static bool vesa_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	return true;
+}
+
+static struct ioport_operations vesa_io_ops = {
+	.io_in			= vesa_pci_io_in,
+	.io_out			= vesa_pci_io_out,
+};
+
+static struct pci_device_header vesa_pci_device = {
+	.vendor_id		= cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
+	.device_id		= cpu_to_le16(PCI_DEVICE_ID_VESA),
+	.header_type		= PCI_HEADER_TYPE_NORMAL,
+	.revision_id		= 0,
+	.class[2]		= 0x03,
+	.subsys_vendor_id	= cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET),
+	.subsys_id		= cpu_to_le16(PCI_SUBSYSTEM_ID_VESA),
+	.bar[1]			= cpu_to_le32(VESA_MEM_ADDR | PCI_BASE_ADDRESS_SPACE_MEMORY),
+	.bar_size[1]		= VESA_MEM_SIZE,
+};
+
+static struct framebuffer vesafb;
+
+struct framebuffer *vesa__init(struct kvm *kvm)
+{
+	u16 vesa_base_addr;
+	u8 dev, line, pin;
+	char *mem;
+	int r;
+
+	r = irq__register_device(PCI_DEVICE_ID_VESA, &dev, &pin, &line);
+	if (r < 0)
+		return ERR_PTR(r);
+
+	r = ioport__register(IOPORT_EMPTY, &vesa_io_ops, IOPORT_SIZE, NULL);
+	if (r < 0)
+		return ERR_PTR(r);
+
+	vesa_pci_device.irq_pin		= pin;
+	vesa_pci_device.irq_line	= line;
+	vesa_base_addr			= (u16)r;
+	vesa_pci_device.bar[0]		= cpu_to_le32(vesa_base_addr | PCI_BASE_ADDRESS_SPACE_IO);
+	pci__register(&vesa_pci_device, dev);
+
+	mem = mmap(NULL, VESA_MEM_SIZE, PROT_RW, MAP_ANON_NORESERVE, -1, 0);
+	if (mem == MAP_FAILED)
+		ERR_PTR(-errno);
+
+	kvm__register_mem(kvm, VESA_MEM_ADDR, VESA_MEM_SIZE, mem);
+
+	vesafb = (struct framebuffer) {
+		.width			= VESA_WIDTH,
+		.height			= VESA_HEIGHT,
+		.depth			= VESA_BPP,
+		.mem			= mem,
+		.mem_addr		= VESA_MEM_ADDR,
+		.mem_size		= VESA_MEM_SIZE,
+	};
+	return fb__register(&vesafb);
+}
diff --git a/tools/kvm/include/asm/hweight.h b/tools/kvm/include/asm/hweight.h
new file mode 100644
index 0000000..1a43977
--- /dev/null
+++ b/tools/kvm/include/asm/hweight.h
@@ -0,0 +1,8 @@
+#ifndef _KVM_ASM_HWEIGHT_H_
+#define _KVM_ASM_HWEIGHT_H_
+
+#include <linux/types.h>
+unsigned int hweight32(unsigned int w);
+unsigned long hweight64(__u64 w);
+
+#endif /* _KVM_ASM_HWEIGHT_H_ */
diff --git a/tools/kvm/include/bios/memcpy.h b/tools/kvm/include/bios/memcpy.h
new file mode 100644
index 0000000..e021044
--- /dev/null
+++ b/tools/kvm/include/bios/memcpy.h
@@ -0,0 +1,9 @@
+#ifndef KVM_BIOS_MEMCPY_H
+#define KVM_BIOS_MEMCPY_H
+
+#include <linux/types.h>
+#include <stddef.h>
+
+void memcpy16(u16 dst_seg, void *dst, u16 src_seg, const void *src, size_t len);
+
+#endif /* KVM_BIOS_MEMCPY_H */
diff --git a/tools/kvm/include/kvm/8250-serial.h b/tools/kvm/include/kvm/8250-serial.h
new file mode 100644
index 0000000..df8ef53
--- /dev/null
+++ b/tools/kvm/include/kvm/8250-serial.h
@@ -0,0 +1,11 @@
+#ifndef KVM__8250_SERIAL_H
+#define KVM__8250_SERIAL_H
+
+struct kvm;
+
+int serial8250__init(struct kvm *kvm);
+int serial8250__exit(struct kvm *kvm);
+void serial8250__update_consoles(struct kvm *kvm);
+void serial8250__inject_sysrq(struct kvm *kvm);
+
+#endif /* KVM__8250_SERIAL_H */
diff --git a/tools/kvm/include/kvm/apic.h b/tools/kvm/include/kvm/apic.h
new file mode 100644
index 0000000..2129997
--- /dev/null
+++ b/tools/kvm/include/kvm/apic.h
@@ -0,0 +1,17 @@
+#ifndef KVM_APIC_H_
+#define KVM_APIC_H_
+
+#include <asm/apicdef.h>
+
+/*
+ * APIC, IOAPIC stuff
+ */
+#define APIC_BASE_ADDR_STEP	0x00400000
+#define IOAPIC_BASE_ADDR_STEP	0x00100000
+
+#define APIC_ADDR(apic)		(APIC_DEFAULT_PHYS_BASE + apic * APIC_BASE_ADDR_STEP)
+#define IOAPIC_ADDR(ioapic)	(IO_APIC_DEFAULT_PHYS_BASE + ioapic * IOAPIC_BASE_ADDR_STEP)
+
+#define KVM_APIC_VERSION	0x14 /* xAPIC */
+
+#endif /* KVM_APIC_H_ */
diff --git a/tools/kvm/include/kvm/brlock.h b/tools/kvm/include/kvm/brlock.h
new file mode 100644
index 0000000..bd1d882
--- /dev/null
+++ b/tools/kvm/include/kvm/brlock.h
@@ -0,0 +1,41 @@
+#ifndef KVM__BRLOCK_H
+#define KVM__BRLOCK_H
+
+#include "kvm/kvm.h"
+#include "kvm/barrier.h"
+
+/*
+ * brlock is a lock which is very cheap for reads, but very expensive
+ * for writes.
+ * This lock will be used when updates are very rare and reads are common.
+ * This lock is currently implemented by stopping the guest while
+ * performing the updates. We assume that the only threads whichread from
+ * the locked data are VCPU threads, and the only writer isn't a VCPU thread.
+ */
+
+#ifndef barrier
+#define barrier()		__asm__ __volatile__("": : :"memory")
+#endif
+
+#ifdef KVM_BRLOCK_DEBUG
+
+#include "kvm/rwsem.h"
+
+DECLARE_RWSEM(brlock_sem);
+
+#define br_read_lock()		down_read(&brlock_sem);
+#define br_read_unlock()	up_read(&brlock_sem);
+
+#define br_write_lock()		down_write(&brlock_sem);
+#define br_write_unlock()	up_write(&brlock_sem);
+
+#else
+
+#define br_read_lock()		barrier()
+#define br_read_unlock()	barrier()
+
+#define br_write_lock()		kvm__pause()
+#define br_write_unlock()	kvm__continue()
+#endif
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-balloon.h b/tools/kvm/include/kvm/builtin-balloon.h
new file mode 100644
index 0000000..77ee656
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-balloon.h
@@ -0,0 +1,9 @@
+#ifndef KVM__BALLOON_H
+#define KVM__BALLOON_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_balloon(int argc, const char **argv, const char *prefix);
+void kvm_balloon_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-debug.h b/tools/kvm/include/kvm/builtin-debug.h
new file mode 100644
index 0000000..6105a8c
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-debug.h
@@ -0,0 +1,18 @@
+#ifndef KVM__DEBUG_H
+#define KVM__DEBUG_H
+
+#include <kvm/util.h>
+#include <linux/types.h>
+
+#define KVM_DEBUG_CMD_TYPE_DUMP	(1 << 0)
+#define KVM_DEBUG_CMD_TYPE_NMI	(1 << 1)
+
+struct debug_cmd_params {
+	u32 dbg_type;
+	u32 cpu;
+};
+
+int kvm_cmd_debug(int argc, const char **argv, const char *prefix);
+void kvm_debug_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-help.h b/tools/kvm/include/kvm/builtin-help.h
new file mode 100644
index 0000000..2946743
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-help.h
@@ -0,0 +1,6 @@
+#ifndef __KVM_HELP_H__
+#define __KVM_HELP_H__
+
+int kvm_cmd_help(int argc, const char **argv, const char *prefix);
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-list.h b/tools/kvm/include/kvm/builtin-list.h
new file mode 100644
index 0000000..47029ca
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-list.h
@@ -0,0 +1,10 @@
+#ifndef KVM__LIST_H
+#define KVM__LIST_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_list(int argc, const char **argv, const char *prefix);
+void kvm_list_help(void) NORETURN;
+int get_vmstate(int sock);
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-pause.h b/tools/kvm/include/kvm/builtin-pause.h
new file mode 100644
index 0000000..84aaee3
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-pause.h
@@ -0,0 +1,9 @@
+#ifndef KVM__PAUSE_H
+#define KVM__PAUSE_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_pause(int argc, const char **argv, const char *prefix);
+void kvm_pause_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-resume.h b/tools/kvm/include/kvm/builtin-resume.h
new file mode 100644
index 0000000..7de999b
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-resume.h
@@ -0,0 +1,9 @@
+#ifndef KVM__RESUME_H
+#define KVM__RESUME_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_resume(int argc, const char **argv, const char *prefix);
+void kvm_resume_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-run.h b/tools/kvm/include/kvm/builtin-run.h
new file mode 100644
index 0000000..91521a5
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-run.h
@@ -0,0 +1,11 @@
+#ifndef __KVM_RUN_H__
+#define __KVM_RUN_H__
+
+#include <kvm/util.h>
+
+int kvm_cmd_run(int argc, const char **argv, const char *prefix);
+void kvm_run_help(void) NORETURN;
+
+void kvm_run_set_wrapper_sandbox(void);
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-sandbox.h b/tools/kvm/include/kvm/builtin-sandbox.h
new file mode 100644
index 0000000..98cd6be
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-sandbox.h
@@ -0,0 +1,6 @@
+#ifndef KVM__SANDBOX_H
+#define KVM__SANDBOX_H
+
+int kvm_cmd_sandbox(int argc, const char **argv, const char *prefix);
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-setup.h b/tools/kvm/include/kvm/builtin-setup.h
new file mode 100644
index 0000000..4a8d7ee
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-setup.h
@@ -0,0 +1,11 @@
+#ifndef KVM__SETUP_H
+#define KVM__SETUP_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_setup(int argc, const char **argv, const char *prefix);
+void kvm_setup_help(void) NORETURN;
+int kvm_setup_create_new(const char *guestfs_name);
+void kvm_setup_resolv(const char *guestfs_name);
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-stat.h b/tools/kvm/include/kvm/builtin-stat.h
new file mode 100644
index 0000000..4fecb37
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-stat.h
@@ -0,0 +1,9 @@
+#ifndef KVM__STAT_H
+#define KVM__STAT_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_stat(int argc, const char **argv, const char *prefix);
+void kvm_stat_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-stop.h b/tools/kvm/include/kvm/builtin-stop.h
new file mode 100644
index 0000000..b26b275
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-stop.h
@@ -0,0 +1,9 @@
+#ifndef KVM__STOP_H
+#define KVM__STOP_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_stop(int argc, const char **argv, const char *prefix);
+void kvm_stop_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-version.h b/tools/kvm/include/kvm/builtin-version.h
new file mode 100644
index 0000000..83cac4d
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-version.h
@@ -0,0 +1,6 @@
+#ifndef KVM__VERSION_H
+#define KVM__VERSION_H
+
+int kvm_cmd_version(int argc, const char **argv, const char *prefix);
+
+#endif
diff --git a/tools/kvm/include/kvm/compiler.h b/tools/kvm/include/kvm/compiler.h
new file mode 100644
index 0000000..2013a83
--- /dev/null
+++ b/tools/kvm/include/kvm/compiler.h
@@ -0,0 +1,10 @@
+#ifndef KVM_COMPILER_H_
+#define KVM_COMPILER_H_
+
+#ifndef __compiletime_error
+# define __compiletime_error(message)
+#endif
+
+#define notrace __attribute__((no_instrument_function))
+
+#endif /* KVM_COMPILER_H_ */
diff --git a/tools/kvm/include/kvm/disk-image.h b/tools/kvm/include/kvm/disk-image.h
new file mode 100644
index 0000000..9671438
--- /dev/null
+++ b/tools/kvm/include/kvm/disk-image.h
@@ -0,0 +1,81 @@
+#ifndef KVM__DISK_IMAGE_H
+#define KVM__DISK_IMAGE_H
+
+#include "kvm/read-write.h"
+#include "kvm/util.h"
+
+#include <linux/types.h>
+#include <linux/fs.h>	/* for BLKGETSIZE64 */
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <sys/uio.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define SECTOR_SHIFT		9
+#define SECTOR_SIZE		(1UL << SECTOR_SHIFT)
+
+enum {
+	DISK_IMAGE_REGULAR,
+	DISK_IMAGE_MMAP,
+};
+
+#define MAX_DISK_IMAGES         4
+
+struct disk_image;
+
+struct disk_image_operations {
+	ssize_t (*read)(struct disk_image *disk, u64 sector, const struct iovec *iov,
+			int iovcount, void *param);
+	ssize_t (*write)(struct disk_image *disk, u64 sector, const struct iovec *iov,
+			int iovcount, void *param);
+	int (*flush)(struct disk_image *disk);
+	int (*close)(struct disk_image *disk);
+};
+
+struct disk_image {
+	int				fd;
+	u64				size;
+	struct disk_image_operations	*ops;
+	void				*priv;
+	void				*disk_req_cb_param;
+	void				(*disk_req_cb)(void *param, long len);
+	bool				async;
+	int				evt;
+#ifdef CONFIG_HAS_AIO
+	io_context_t			ctx;
+#endif
+};
+
+struct disk_image *disk_image__open(const char *filename, bool readonly);
+struct disk_image **disk_image__open_all(const char **filenames, bool *readonly, int count);
+struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops, int mmap);
+int disk_image__close(struct disk_image *disk);
+int disk_image__close_all(struct disk_image **disks, int count);
+int disk_image__flush(struct disk_image *disk);
+ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov,
+				int iovcount, void *param);
+ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov,
+				int iovcount, void *param);
+ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len);
+
+struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly);
+struct disk_image *blkdev__probe(const char *filename, struct stat *st);
+
+ssize_t raw_image__read(struct disk_image *disk, u64 sector,
+				const struct iovec *iov, int iovcount, void *param);
+ssize_t raw_image__write(struct disk_image *disk, u64 sector,
+				const struct iovec *iov, int iovcount, void *param);
+ssize_t raw_image__read_mmap(struct disk_image *disk, u64 sector,
+				const struct iovec *iov, int iovcount, void *param);
+ssize_t raw_image__write_mmap(struct disk_image *disk, u64 sector,
+				const struct iovec *iov, int iovcount, void *param);
+int raw_image__close(struct disk_image *disk);
+void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param, long len));
+#endif /* KVM__DISK_IMAGE_H */
diff --git a/tools/kvm/include/kvm/e820.h b/tools/kvm/include/kvm/e820.h
new file mode 100644
index 0000000..15f62cc
--- /dev/null
+++ b/tools/kvm/include/kvm/e820.h
@@ -0,0 +1,13 @@
+#ifndef KVM_E820_H
+#define KVM_E820_H
+
+#include <linux/types.h>
+#include <kvm/bios.h>
+
+#define SMAP    0x534d4150      /* ASCII "SMAP" */
+
+struct biosregs;
+
+extern bioscall void e820_query_map(struct biosregs *regs);
+
+#endif /* KVM_E820_H */
diff --git a/tools/kvm/include/kvm/framebuffer.h b/tools/kvm/include/kvm/framebuffer.h
new file mode 100644
index 0000000..dc5022c
--- /dev/null
+++ b/tools/kvm/include/kvm/framebuffer.h
@@ -0,0 +1,35 @@
+#ifndef KVM__FRAMEBUFFER_H
+#define KVM__FRAMEBUFFER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct framebuffer;
+
+struct fb_target_operations {
+	int (*start)(struct framebuffer *fb);
+	int (*stop)(struct framebuffer *fb);
+};
+
+#define FB_MAX_TARGETS			2
+
+struct framebuffer {
+	struct list_head		node;
+
+	u32				width;
+	u32				height;
+	u8				depth;
+	char				*mem;
+	u64				mem_addr;
+	u64				mem_size;
+
+	unsigned long			nr_targets;
+	struct fb_target_operations	*targets[FB_MAX_TARGETS];
+};
+
+struct framebuffer *fb__register(struct framebuffer *fb);
+int fb__attach(struct framebuffer *fb, struct fb_target_operations *ops);
+int fb__start(void);
+void fb__stop(void);
+
+#endif /* KVM__FRAMEBUFFER_H */
diff --git a/tools/kvm/include/kvm/guest_compat.h b/tools/kvm/include/kvm/guest_compat.h
new file mode 100644
index 0000000..ae7abbd
--- /dev/null
+++ b/tools/kvm/include/kvm/guest_compat.h
@@ -0,0 +1,9 @@
+#ifndef KVM__GUEST_COMPAT_H
+#define KVM__GUEST_COMPAT_H
+
+int compat__print_all_messages(void);
+int compat__remove_message(int id);
+int compat__add_message(const char *title, const char *description);
+
+
+#endif
\ No newline at end of file
diff --git a/tools/kvm/include/kvm/i8042.h b/tools/kvm/include/kvm/i8042.h
new file mode 100644
index 0000000..13f18e2
--- /dev/null
+++ b/tools/kvm/include/kvm/i8042.h
@@ -0,0 +1,12 @@
+#ifndef KVM__PCKBD_H
+#define KVM__PCKBD_H
+
+#include <linux/types.h>
+
+struct kvm;
+
+void mouse_queue(u8 c);
+void kbd_queue(u8 c);
+void kbd__init(struct kvm *kvm);
+
+#endif
diff --git a/tools/kvm/include/kvm/ioeventfd.h b/tools/kvm/include/kvm/ioeventfd.h
new file mode 100644
index 0000000..70cce9a
--- /dev/null
+++ b/tools/kvm/include/kvm/ioeventfd.h
@@ -0,0 +1,28 @@
+#ifndef KVM__IOEVENTFD_H
+#define KVM__IOEVENTFD_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <sys/eventfd.h>
+#include "kvm/util.h"
+
+struct kvm;
+
+struct ioevent {
+	u64			io_addr;
+	u8			io_len;
+	void			(*fn)(struct kvm *kvm, void *ptr);
+	struct kvm		*fn_kvm;
+	void			*fn_ptr;
+	int			fd;
+	u64			datamatch;
+
+	struct list_head	list;
+};
+
+int ioeventfd__init(struct kvm *kvm);
+int ioeventfd__exit(struct kvm *kvm);
+int ioeventfd__add_event(struct ioevent *ioevent, bool is_pio);
+int ioeventfd__del_event(u64 addr, u64 datamatch);
+
+#endif
diff --git a/tools/kvm/include/kvm/ioport.h b/tools/kvm/include/kvm/ioport.h
new file mode 100644
index 0000000..ced8cf5
--- /dev/null
+++ b/tools/kvm/include/kvm/ioport.h
@@ -0,0 +1,69 @@
+#ifndef KVM__IOPORT_H
+#define KVM__IOPORT_H
+
+#include "kvm/rbtree-interval.h"
+
+#include <stdbool.h>
+#include <limits.h>
+#include <asm/types.h>
+#include <linux/types.h>
+#include <linux/byteorder.h>
+
+/* some ports we reserve for own use */
+#define IOPORT_DBG			0xe0
+#define IOPORT_START			0x6200
+#define IOPORT_SIZE			0x400
+
+#define IOPORT_EMPTY			USHRT_MAX
+
+struct kvm;
+
+struct ioport {
+	struct rb_int_node		node;
+	struct ioport_operations	*ops;
+	void				*priv;
+};
+
+struct ioport_operations {
+	bool (*io_in)(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size);
+	bool (*io_out)(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size);
+};
+
+void ioport__setup_arch(void);
+
+int ioport__register(u16 port, struct ioport_operations *ops, int count, void *param);
+int ioport__unregister(u16 port);
+int ioport__init(struct kvm *kvm);
+int ioport__exit(struct kvm *kvm);
+
+static inline u8 ioport__read8(u8 *data)
+{
+	return *data;
+}
+/* On BE platforms, PCI I/O is byteswapped, i.e. LE, so swap back. */
+static inline u16 ioport__read16(u16 *data)
+{
+	return le16_to_cpu(*data);
+}
+
+static inline u32 ioport__read32(u32 *data)
+{
+	return le32_to_cpu(*data);
+}
+
+static inline void ioport__write8(u8 *data, u8 value)
+{
+	*data		 = value;
+}
+
+static inline void ioport__write16(u16 *data, u16 value)
+{
+	*data		 = cpu_to_le16(value);
+}
+
+static inline void ioport__write32(u32 *data, u32 value)
+{
+	*data		 = cpu_to_le32(value);
+}
+
+#endif /* KVM__IOPORT_H */
diff --git a/tools/kvm/include/kvm/irq.h b/tools/kvm/include/kvm/irq.h
new file mode 100644
index 0000000..43fecaf
--- /dev/null
+++ b/tools/kvm/include/kvm/irq.h
@@ -0,0 +1,33 @@
+#ifndef KVM__IRQ_H
+#define KVM__IRQ_H
+
+#include <linux/types.h>
+#include <linux/rbtree.h>
+#include <linux/list.h>
+#include <linux/kvm.h>
+
+#include "kvm/msi.h"
+
+struct kvm;
+
+struct irq_line {
+	u8			line;
+	struct list_head	node;
+};
+
+struct pci_dev {
+	struct rb_node		node;
+	u32			id;
+	u8			pin;
+	struct list_head	lines;
+};
+
+int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line);
+
+struct rb_node *irq__get_pci_tree(void);
+
+int irq__init(struct kvm *kvm);
+int irq__exit(struct kvm *kvm);
+int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg);
+
+#endif
diff --git a/tools/kvm/include/kvm/kvm-cmd.h b/tools/kvm/include/kvm/kvm-cmd.h
new file mode 100644
index 0000000..0a73bce
--- /dev/null
+++ b/tools/kvm/include/kvm/kvm-cmd.h
@@ -0,0 +1,17 @@
+#ifndef __KVM_CMD_H__
+#define __KVM_CMD_H__
+
+struct cmd_struct {
+	const char *cmd;
+	int (*fn)(int, const char **, const char *);
+	void (*help)(void);
+	int option;
+};
+
+extern struct cmd_struct kvm_commands[];
+struct cmd_struct *kvm_get_command(struct cmd_struct *command,
+                const char *cmd);
+
+int handle_command(struct cmd_struct *command, int argc, const char **argv);
+
+#endif
diff --git a/tools/kvm/include/kvm/kvm-cpu.h b/tools/kvm/include/kvm/kvm-cpu.h
new file mode 100644
index 0000000..d4448f6
--- /dev/null
+++ b/tools/kvm/include/kvm/kvm-cpu.h
@@ -0,0 +1,24 @@
+#ifndef KVM__KVM_CPU_H
+#define KVM__KVM_CPU_H
+
+#include "kvm/kvm-cpu-arch.h"
+#include <stdbool.h>
+
+struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id);
+void kvm_cpu__delete(struct kvm_cpu *vcpu);
+void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu);
+void kvm_cpu__setup_cpuid(struct kvm_cpu *vcpu);
+void kvm_cpu__enable_singlestep(struct kvm_cpu *vcpu);
+void kvm_cpu__run(struct kvm_cpu *vcpu);
+void kvm_cpu__reboot(void);
+int kvm_cpu__start(struct kvm_cpu *cpu);
+bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu);
+
+int kvm_cpu__get_debug_fd(void);
+void kvm_cpu__set_debug_fd(int fd);
+void kvm_cpu__show_code(struct kvm_cpu *vcpu);
+void kvm_cpu__show_registers(struct kvm_cpu *vcpu);
+void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu);
+void kvm_cpu__arch_nmi(struct kvm_cpu *cpu);
+
+#endif /* KVM__KVM_CPU_H */
diff --git a/tools/kvm/include/kvm/kvm-ipc.h b/tools/kvm/include/kvm/kvm-ipc.h
new file mode 100644
index 0000000..aefffa4
--- /dev/null
+++ b/tools/kvm/include/kvm/kvm-ipc.h
@@ -0,0 +1,24 @@
+#ifndef KVM__IPC_H_
+#define KVM__IPC_H_
+
+#include <linux/types.h>
+
+enum {
+	KVM_IPC_BALLOON	= 1,
+	KVM_IPC_DEBUG	= 2,
+	KVM_IPC_STAT	= 3,
+	KVM_IPC_PAUSE	= 4,
+	KVM_IPC_RESUME	= 5,
+	KVM_IPC_STOP	= 6,
+	KVM_IPC_PID	= 7,
+	KVM_IPC_VMSTATE	= 8,
+};
+
+int kvm_ipc__register_handler(u32 type, void (*cb)(int fd, u32 type, u32 len, u8 *msg));
+int kvm_ipc__start(int sock);
+int kvm_ipc__stop(void);
+
+int kvm_ipc__send(int fd, u32 type);
+int kvm_ipc__send_msg(int fd, u32 type, u32 len, u8 *msg);
+
+#endif
diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h
new file mode 100644
index 0000000..22a1b0e
--- /dev/null
+++ b/tools/kvm/include/kvm/kvm.h
@@ -0,0 +1,93 @@
+#ifndef KVM__KVM_H
+#define KVM__KVM_H
+
+#include "kvm/kvm-arch.h"
+
+#include <stdbool.h>
+#include <linux/types.h>
+#include <time.h>
+#include <signal.h>
+
+#define SIGKVMEXIT		(SIGRTMIN + 0)
+#define SIGKVMPAUSE		(SIGRTMIN + 1)
+
+#define KVM_PID_FILE_PATH	"/.lkvm/"
+#define HOME_DIR		getenv("HOME")
+#define KVM_BINARY_NAME		"lkvm"
+
+#define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
+
+#define DEFINE_KVM_EXT(ext)		\
+	.name = #ext,			\
+	.code = ext
+
+enum {
+	KVM_VMSTATE_RUNNING,
+	KVM_VMSTATE_PAUSED,
+};
+
+struct kvm_ext {
+	const char *name;
+	int code;
+};
+
+void kvm__set_dir(const char *fmt, ...);
+const char *kvm__get_dir(void);
+
+struct kvm *kvm__init(const char *kvm_dev, const char *hugetlbfs_path, u64 ram_size, const char *name);
+int kvm__recommended_cpus(struct kvm *kvm);
+int kvm__max_cpus(struct kvm *kvm);
+void kvm__init_ram(struct kvm *kvm);
+int kvm__exit(struct kvm *kvm);
+bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename);
+bool kvm__load_kernel(struct kvm *kvm, const char *kernel_filename,
+			const char *initrd_filename, const char *kernel_cmdline, u16 vidmode);
+void kvm__start_timer(struct kvm *kvm);
+void kvm__stop_timer(struct kvm *kvm);
+void kvm__irq_line(struct kvm *kvm, int irq, int level);
+void kvm__irq_trigger(struct kvm *kvm, int irq);
+bool kvm__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count);
+bool kvm__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write);
+int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
+int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
+			void (*mmio_fn)(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr),
+			void *ptr);
+bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr);
+void kvm__pause(void);
+void kvm__continue(void);
+void kvm__notify_paused(void);
+int kvm__get_sock_by_instance(const char *name);
+int kvm__enumerate_instances(int (*callback)(const char *name, int pid));
+void kvm__remove_socket(const char *name);
+
+void kvm__arch_set_cmdline(char *cmdline, bool video);
+void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size);
+void kvm__arch_delete_ram(struct kvm *kvm);
+int kvm__arch_setup_firmware(struct kvm *kvm);
+int kvm__arch_free_firmware(struct kvm *kvm);
+bool kvm__arch_cpu_supports_vm(void);
+void kvm__arch_periodic_poll(struct kvm *kvm);
+
+int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline);
+bool load_bzimage(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline, u16 vidmode);
+
+/*
+ * Debugging
+ */
+void kvm__dump_mem(struct kvm *kvm, unsigned long addr, unsigned long size);
+
+extern const char *kvm_exit_reasons[];
+
+static inline bool host_ptr_in_ram(struct kvm *kvm, void *p)
+{
+	return kvm->ram_start <= p && p < (kvm->ram_start + kvm->ram_size);
+}
+
+static inline void *guest_flat_to_host(struct kvm *kvm, unsigned long offset)
+{
+	return kvm->ram_start + offset;
+}
+
+bool kvm__supports_extension(struct kvm *kvm, unsigned int extension);
+
+#endif /* KVM__KVM_H */
diff --git a/tools/kvm/include/kvm/msi.h b/tools/kvm/include/kvm/msi.h
new file mode 100644
index 0000000..885eb5b
--- /dev/null
+++ b/tools/kvm/include/kvm/msi.h
@@ -0,0 +1,10 @@
+#ifndef LKVM_MSI_H
+#define LKVM_MSI_H
+
+struct msi_msg {
+	u32	address_lo;	/* low 32 bits of msi message address */
+	u32	address_hi;	/* high 32 bits of msi message address */
+	u32	data;		/* 16 bits of msi message data */
+};
+
+#endif /* LKVM_MSI_H */
diff --git a/tools/kvm/include/kvm/mutex.h b/tools/kvm/include/kvm/mutex.h
new file mode 100644
index 0000000..3286cea
--- /dev/null
+++ b/tools/kvm/include/kvm/mutex.h
@@ -0,0 +1,33 @@
+#ifndef KVM__MUTEX_H
+#define KVM__MUTEX_H
+
+#include <pthread.h>
+
+#include "kvm/util.h"
+
+/*
+ * Kernel-alike mutex API - to make it easier for kernel developers
+ * to write user-space code! :-)
+ */
+
+#define DEFINE_MUTEX(mutex) pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
+
+static inline void mutex_init(pthread_mutex_t *mutex)
+{
+	if (pthread_mutex_init(mutex, NULL) != 0)
+		die("unexpected pthread_mutex_init() failure!");
+}
+
+static inline void mutex_lock(pthread_mutex_t *mutex)
+{
+	if (pthread_mutex_lock(mutex) != 0)
+		die("unexpected pthread_mutex_lock() failure!");
+}
+
+static inline void mutex_unlock(pthread_mutex_t *mutex)
+{
+	if (pthread_mutex_unlock(mutex) != 0)
+		die("unexpected pthread_mutex_unlock() failure!");
+}
+
+#endif /* KVM__MUTEX_H */
diff --git a/tools/kvm/include/kvm/parse-options.h b/tools/kvm/include/kvm/parse-options.h
new file mode 100644
index 0000000..7886ff7
--- /dev/null
+++ b/tools/kvm/include/kvm/parse-options.h
@@ -0,0 +1,214 @@
+#ifndef __PARSE_OPTIONS_H__
+#define __PARSE_OPTIONS_H__
+
+#include <inttypes.h>
+#include <kvm/util.h>
+
+enum parse_opt_type {
+	/* special types */
+	OPTION_END,
+	OPTION_ARGUMENT,
+	OPTION_GROUP,
+	/* options with no arguments */
+	OPTION_BIT,
+	OPTION_BOOLEAN,
+	OPTION_INCR,
+	OPTION_SET_UINT,
+	OPTION_SET_PTR,
+	/* options with arguments (usually) */
+	OPTION_STRING,
+	OPTION_INTEGER,
+	OPTION_LONG,
+	OPTION_CALLBACK,
+	OPTION_U64,
+	OPTION_UINTEGER,
+};
+
+enum parse_opt_flags {
+	PARSE_OPT_KEEP_DASHDASH = 1,
+	PARSE_OPT_STOP_AT_NON_OPTION = 2,
+	PARSE_OPT_KEEP_ARGV0 = 4,
+	PARSE_OPT_KEEP_UNKNOWN = 8,
+	PARSE_OPT_NO_INTERNAL_HELP = 16,
+};
+
+enum parse_opt_option_flags {
+	PARSE_OPT_OPTARG  = 1,
+	PARSE_OPT_NOARG   = 2,
+	PARSE_OPT_NONEG   = 4,
+	PARSE_OPT_HIDDEN  = 8,
+	PARSE_OPT_LASTARG_DEFAULT = 16,
+};
+
+struct option;
+typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
+/*
+ * `type`::
+ *   holds the type of the option, you must have an OPTION_END last in your
+ *   array.
+ *
+ * `short_name`::
+ *   the character to use as a short option name, '\0' if none.
+ *
+ * `long_name`::
+ *   the long option name, without the leading dashes, NULL if none.
+ *
+ * `value`::
+ *   stores pointers to the values to be filled.
+ *
+ * `argh`::
+ *   token to explain the kind of argument this option wants. Keep it
+ *   homogenous across the repository.
+ *
+ * `help`::
+ *   the short help associated to what the option does.
+ *   Must never be NULL (except for OPTION_END).
+ *   OPTION_GROUP uses this pointer to store the group header.
+ *
+ * `flags`::
+ *   mask of parse_opt_option_flags.
+ *   PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs)
+ *   PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
+ *   PARSE_OPT_NONEG: says that this option cannot be negated
+ *   PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in
+ *                    the long one.
+ *
+ * `callback`::
+ *   pointer to the callback to use for OPTION_CALLBACK.
+ *
+ * `defval`::
+ *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
+ *   OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in
+ *   the value when met.
+ *   CALLBACKS can use it like they want.
+ */
+struct option {
+enum parse_opt_type type;
+int short_name;
+const char *long_name;
+void *value;
+const char *argh;
+const char *help;
+
+int flags;
+parse_opt_cb *callback;
+intptr_t defval;
+};
+
+#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
+#define check_vtype(v, type) \
+	(BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v)
+
+#define OPT_INTEGER(s, l, v, h)             \
+{                                           \
+	.type = OPTION_INTEGER,             \
+	.short_name = (s),                  \
+	.long_name = (l),                   \
+	.value = check_vtype(v, int *),     \
+	.help = (h)                         \
+}
+
+#define OPT_U64(s, l, v, h)                 \
+{                                           \
+	.type = OPTION_U64,                 \
+	.short_name = (s),                  \
+	.long_name = (l),                   \
+	.value = check_vtype(v, u64 *),     \
+	.help = (h)                         \
+}
+
+#define OPT_STRING(s, l, v, a, h)           \
+{                                           \
+	.type = OPTION_STRING,              \
+	.short_name = (s),                  \
+	.long_name = (l),                   \
+	.value = check_vtype(v, const char **), (a), \
+	.help = (h)                         \
+}
+
+#define OPT_BOOLEAN(s, l, v, h)             \
+{                                           \
+	.type = OPTION_BOOLEAN,             \
+	.short_name = (s),                  \
+	.long_name = (l),                   \
+	.value = check_vtype(v, bool *),    \
+	.help = (h)                         \
+}
+
+#define OPT_INCR(s, l, v, h)                \
+{                                           \
+	.type = OPTION_INCR,	            \
+	.short_name = (s),                  \
+	.long_name = (l),                   \
+	.value = check_vtype(v, int *),     \
+	.help = (h)                         \
+}
+
+#define OPT_GROUP(h)                        \
+{                                           \
+	.type = OPTION_GROUP,               \
+	.help = (h)                         \
+}
+
+#define OPT_CALLBACK(s, l, v, a, h, f)      \
+{					    \
+	.type = OPTION_CALLBACK,	    \
+	.short_name = (s),		    \
+	.long_name = (l),		    \
+	.value = (v),			    \
+	(a),				    \
+	.help = (h),			    \
+	.callback = (f)			    \
+}
+
+#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \
+{					    \
+	.type = OPTION_CALLBACK,	    \
+	.short_name = (s),		    \
+	.long_name = (l),		    \
+	.value = (v),			    \
+	(a),				    \
+	.help = (h),			    \
+	.callback = (f),		    \
+	.flags = PARSE_OPT_NOARG	    \
+}
+
+#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
+{					    \
+	.type = OPTION_CALLBACK,	    \
+	.short_name = (s),		    \
+	.long_name = (l),		    \
+	.value = (v), (a),		    \
+	.help = (h),			    \
+	.callback = (f),		    \
+	.defval = (intptr_t)d,		    \
+	.flags = PARSE_OPT_LASTARG_DEFAULT  \
+}
+
+#define OPT_END() { .type = OPTION_END }
+
+enum {
+	PARSE_OPT_HELP = -1,
+	PARSE_OPT_DONE,
+	PARSE_OPT_UNKNOWN,
+};
+
+/*
+ * It's okay for the caller to consume argv/argc in the usual way.
+ * Other fields of that structure are private to parse-options and should not
+ * be modified in any way.
+ **/
+struct parse_opt_ctx_t {
+	const char **argv;
+	const char **out;
+	int argc, cpidx;
+	const char *opt;
+	int flags;
+};
+
+/* global functions */
+void usage_with_options(const char * const *usagestr,
+		const struct option *opts) NORETURN;
+int parse_options(int argc, const char **argv, const struct option *options,
+		const char * const usagestr[], int flags);
+#endif
diff --git a/tools/kvm/include/kvm/pci-shmem.h b/tools/kvm/include/kvm/pci-shmem.h
new file mode 100644
index 0000000..599ab37
--- /dev/null
+++ b/tools/kvm/include/kvm/pci-shmem.h
@@ -0,0 +1,28 @@
+#ifndef KVM__PCI_SHMEM_H
+#define KVM__PCI_SHMEM_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+#define SHMEM_DEFAULT_SIZE (16 << MB_SHIFT)
+#define SHMEM_DEFAULT_ADDR (0xc8000000)
+#define SHMEM_DEFAULT_HANDLE "/kvm_shmem"
+
+struct kvm;
+struct shmem_info;
+
+struct shmem_info {
+	u64 phys_addr;
+	u64 size;
+	char *handle;
+	int create;
+};
+
+int pci_shmem__init(struct kvm *self);
+int pci_shmem__register_mem(struct shmem_info *si);
+
+int pci_shmem__get_local_irqfd(struct kvm *kvm);
+int pci_shmem__add_client(struct kvm *kvm, u32 id, int fd);
+int pci_shmem__remove_client(struct kvm *kvm, u32 id);
+
+#endif
diff --git a/tools/kvm/include/kvm/pci.h b/tools/kvm/include/kvm/pci.h
new file mode 100644
index 0000000..26639b5
--- /dev/null
+++ b/tools/kvm/include/kvm/pci.h
@@ -0,0 +1,95 @@
+#ifndef KVM__PCI_H
+#define KVM__PCI_H
+
+#include <linux/types.h>
+#include <linux/kvm.h>
+#include <linux/pci_regs.h>
+#include <endian.h>
+
+#include "kvm/kvm.h"
+#include "kvm/msi.h"
+
+#define PCI_MAX_DEVICES		256
+/*
+ * PCI Configuration Mechanism #1 I/O ports. See Section 3.7.4.1.
+ * ("Configuration Mechanism #1") of the PCI Local Bus Specification 2.1 for
+ * details.
+ */
+#define PCI_CONFIG_ADDRESS	0xcf8
+#define PCI_CONFIG_DATA		0xcfc
+#define PCI_CONFIG_BUS_FORWARD	0xcfa
+#define PCI_IO_SIZE		0x100
+
+union pci_config_address {
+	struct {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+		unsigned	reg_offset	: 2;		/* 1  .. 0  */
+		unsigned	register_number	: 6;		/* 7  .. 2  */
+		unsigned	function_number	: 3;		/* 10 .. 8  */
+		unsigned	device_number	: 5;		/* 15 .. 11 */
+		unsigned	bus_number	: 8;		/* 23 .. 16 */
+		unsigned	reserved	: 7;		/* 30 .. 24 */
+		unsigned	enable_bit	: 1;		/* 31       */
+#else
+		unsigned	enable_bit	: 1;		/* 31       */
+		unsigned	reserved	: 7;		/* 30 .. 24 */
+		unsigned	bus_number	: 8;		/* 23 .. 16 */
+		unsigned	device_number	: 5;		/* 15 .. 11 */
+		unsigned	function_number	: 3;		/* 10 .. 8  */
+		unsigned	register_number	: 6;		/* 7  .. 2  */
+		unsigned	reg_offset	: 2;		/* 1  .. 0  */
+#endif
+	};
+	u32 w;
+};
+
+struct msix_table {
+	struct msi_msg msg;
+	u32 ctrl;
+};
+
+struct msix_cap {
+	u8 cap;
+	u8 next;
+	u16 ctrl;
+	u32 table_offset;
+	u32 pba_offset;
+};
+
+struct pci_device_header {
+	u16		vendor_id;
+	u16		device_id;
+	u16		command;
+	u16		status;
+	u8		revision_id;
+	u8		class[3];
+	u8		cacheline_size;
+	u8		latency_timer;
+	u8		header_type;
+	u8		bist;
+	u32		bar[6];
+	u32		card_bus;
+	u16		subsys_vendor_id;
+	u16		subsys_id;
+	u32		exp_rom_bar;
+	u8		capabilities;
+	u8		reserved1[3];
+	u32		reserved2;
+	u8		irq_line;
+	u8		irq_pin;
+	u8		min_gnt;
+	u8		max_lat;
+	struct msix_cap msix;
+	u8		empty[136]; /* Rest of PCI config space */
+	u32		bar_size[6];
+} __attribute__((packed));
+
+int pci__init(struct kvm *kvm);
+int pci__exit(struct kvm *kvm);
+int pci__register(struct pci_device_header *dev, u8 dev_num);
+struct pci_device_header *pci__find_dev(u8 dev_num);
+u32 pci_get_io_space_block(u32 size);
+void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data, int size);
+void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data, int size);
+
+#endif /* KVM__PCI_H */
diff --git a/tools/kvm/include/kvm/qcow.h b/tools/kvm/include/kvm/qcow.h
new file mode 100644
index 0000000..e032a1e
--- /dev/null
+++ b/tools/kvm/include/kvm/qcow.h
@@ -0,0 +1,133 @@
+#ifndef KVM__QCOW_H
+#define KVM__QCOW_H
+
+#include "kvm/mutex.h"
+
+#include <linux/types.h>
+#include <stdbool.h>
+#include <linux/rbtree.h>
+#include <linux/list.h>
+
+#define QCOW_MAGIC		(('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
+
+#define QCOW1_VERSION		1
+#define QCOW2_VERSION		2
+
+#define QCOW1_OFLAG_COMPRESSED	(1ULL << 63)
+
+#define QCOW2_OFLAG_COPIED	(1ULL << 63)
+#define QCOW2_OFLAG_COMPRESSED	(1ULL << 62)
+
+#define QCOW2_OFLAGS_MASK	(QCOW2_OFLAG_COPIED|QCOW2_OFLAG_COMPRESSED)
+
+#define QCOW2_OFFSET_MASK	(~QCOW2_OFLAGS_MASK)
+
+#define MAX_CACHE_NODES         32
+
+struct qcow_l2_table {
+	u64				offset;
+	struct rb_node			node;
+	struct list_head		list;
+	u8				dirty;
+	u64				table[];
+};
+
+struct qcow_l1_table {
+	u32				table_size;
+	u64				*l1_table;
+
+	/* Level2 caching data structures */
+	struct rb_root			root;
+	struct list_head		lru_list;
+	int				nr_cached;
+};
+
+#define QCOW_REFCOUNT_BLOCK_SHIFT	1
+
+struct qcow_refcount_block {
+	u64				offset;
+	struct rb_node			node;
+	struct list_head		list;
+	u64				size;
+	u8				dirty;
+	u16				entries[];
+};
+
+struct qcow_refcount_table {
+	u32				rf_size;
+	u64				*rf_table;
+
+	/* Refcount block caching data structures */
+	struct rb_root			root;
+	struct list_head		lru_list;
+	int				nr_cached;
+};
+
+struct qcow_header {
+	u64				size;	/* in bytes */
+	u64				l1_table_offset;
+	u32				l1_size;
+	u8				cluster_bits;
+	u8				l2_bits;
+	u64				refcount_table_offset;
+	u32				refcount_table_size;
+};
+
+struct qcow {
+	pthread_mutex_t			mutex;
+	struct qcow_header		*header;
+	struct qcow_l1_table		table;
+	struct qcow_refcount_table	refcount_table;
+	int				fd;
+	int				csize_shift;
+	int				csize_mask;
+	u32				version;
+	u64				cluster_size;
+	u64				cluster_offset_mask;
+	u64				free_clust_idx;
+	void				*cluster_cache;
+	void				*cluster_data;
+	void				*copy_buff;
+};
+
+struct qcow1_header_disk {
+	u32				magic;
+	u32				version;
+
+	u64				backing_file_offset;
+	u32 				backing_file_size;
+	u32				mtime;
+
+	u64				size;	/* in bytes */
+
+	u8				cluster_bits;
+	u8				l2_bits;
+	u32				crypt_method;
+
+	u64				l1_table_offset;
+};
+
+struct qcow2_header_disk {
+	u32				magic;
+	u32				version;
+
+	u64				backing_file_offset;
+	u32				backing_file_size;
+
+	u32				cluster_bits;
+	u64				size;	/* in bytes */
+	u32				crypt_method;
+
+	u32				l1_size;
+	u64				l1_table_offset;
+
+	u64				refcount_table_offset;
+	u32				refcount_table_clusters;
+
+	u32				nb_snapshots;
+	u64				snapshots_offset;
+};
+
+struct disk_image *qcow_probe(int fd, bool readonly);
+
+#endif /* KVM__QCOW_H */
diff --git a/tools/kvm/include/kvm/rbtree-interval.h b/tools/kvm/include/kvm/rbtree-interval.h
new file mode 100644
index 0000000..13245ba
--- /dev/null
+++ b/tools/kvm/include/kvm/rbtree-interval.h
@@ -0,0 +1,28 @@
+#ifndef KVM__INTERVAL_RBTREE_H
+#define KVM__INTERVAL_RBTREE_H
+
+#include <linux/rbtree.h>
+#include <linux/types.h>
+
+#define RB_INT_INIT(l, h) (struct rb_int_node){.low = l, .high = h}
+#define rb_int(n) rb_entry(n, struct rb_int_node, node)
+
+struct rb_int_node {
+	struct rb_node	node;
+	u64		low;
+	u64		high;
+
+	/* max_high will store the highest high of it's 2 children. */
+	u64		max_high;
+};
+
+/* Return the rb_int_node interval in which 'point' is located. */
+struct rb_int_node *rb_int_search_single(struct rb_root *root, u64 point);
+
+/* Return the rb_int_node in which start:len is located. */
+struct rb_int_node *rb_int_search_range(struct rb_root *root, u64 low, u64 high);
+
+int rb_int_insert(struct rb_root *root, struct rb_int_node *data);
+void rb_int_erase(struct rb_root *root, struct rb_int_node *node);
+
+#endif
diff --git a/tools/kvm/include/kvm/read-write.h b/tools/kvm/include/kvm/read-write.h
new file mode 100644
index 0000000..67571f9
--- /dev/null
+++ b/tools/kvm/include/kvm/read-write.h
@@ -0,0 +1,43 @@
+#ifndef KVM_READ_WRITE_H
+#define KVM_READ_WRITE_H
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#ifdef CONFIG_HAS_AIO
+#include <libaio.h>
+#endif
+
+ssize_t xread(int fd, void *buf, size_t count);
+ssize_t xwrite(int fd, const void *buf, size_t count);
+
+ssize_t read_in_full(int fd, void *buf, size_t count);
+ssize_t write_in_full(int fd, const void *buf, size_t count);
+
+ssize_t xpread(int fd, void *buf, size_t count, off_t offset);
+ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset);
+
+ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset);
+
+ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt);
+ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt);
+
+ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt);
+ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt);
+
+ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+
+ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+
+#ifdef CONFIG_HAS_AIO
+int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
+		off_t offset, int ev, void *param);
+int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
+		off_t offset, int ev, void *param);
+#endif
+
+#endif /* KVM_READ_WRITE_H */
diff --git a/tools/kvm/include/kvm/rtc.h b/tools/kvm/include/kvm/rtc.h
new file mode 100644
index 0000000..6aa9299
--- /dev/null
+++ b/tools/kvm/include/kvm/rtc.h
@@ -0,0 +1,9 @@
+#ifndef KVM__RTC_H
+#define KVM__RTC_H
+
+struct kvm;
+
+int rtc__init(struct kvm *kvm);
+int rtc__exit(struct kvm *kvm);
+
+#endif /* KVM__RTC_H */
diff --git a/tools/kvm/include/kvm/rwsem.h b/tools/kvm/include/kvm/rwsem.h
new file mode 100644
index 0000000..75a22f8
--- /dev/null
+++ b/tools/kvm/include/kvm/rwsem.h
@@ -0,0 +1,39 @@
+#ifndef KVM__RWSEM_H
+#define KVM__RWSEM_H
+
+#include <pthread.h>
+
+#include "kvm/util.h"
+
+/*
+ * Kernel-alike rwsem API - to make it easier for kernel developers
+ * to write user-space code! :-)
+ */
+
+#define DECLARE_RWSEM(sem) pthread_rwlock_t sem = PTHREAD_RWLOCK_INITIALIZER
+
+static inline void down_read(pthread_rwlock_t *rwsem)
+{
+	if (pthread_rwlock_rdlock(rwsem) != 0)
+		die("unexpected pthread_rwlock_rdlock() failure!");
+}
+
+static inline void down_write(pthread_rwlock_t *rwsem)
+{
+	if (pthread_rwlock_wrlock(rwsem) != 0)
+		die("unexpected pthread_rwlock_wrlock() failure!");
+}
+
+static inline void up_read(pthread_rwlock_t *rwsem)
+{
+	if (pthread_rwlock_unlock(rwsem) != 0)
+		die("unexpected pthread_rwlock_unlock() failure!");
+}
+
+static inline void up_write(pthread_rwlock_t *rwsem)
+{
+	if (pthread_rwlock_unlock(rwsem) != 0)
+		die("unexpected pthread_rwlock_unlock() failure!");
+}
+
+#endif /* KVM__RWSEM_H */
diff --git a/tools/kvm/include/kvm/sdl.h b/tools/kvm/include/kvm/sdl.h
new file mode 100644
index 0000000..36e5986
--- /dev/null
+++ b/tools/kvm/include/kvm/sdl.h
@@ -0,0 +1,22 @@
+#ifndef KVM__SDL_H
+#define KVM__SDL_H
+
+#include "kvm/util.h"
+
+struct framebuffer;
+
+#ifdef CONFIG_HAS_SDL
+int sdl__init(struct framebuffer *fb);
+int sdl__exit(struct framebuffer *fb);
+#else
+static inline void sdl__init(struct framebuffer *fb)
+{
+	die("SDL support not compiled in. (install the SDL-dev[el] package)");
+}
+static inline void sdl__exit(struct framebuffer *fb)
+{
+	die("SDL support not compiled in. (install the SDL-dev[el] package)");
+}
+#endif
+
+#endif /* KVM__SDL_H */
diff --git a/tools/kvm/include/kvm/segment.h b/tools/kvm/include/kvm/segment.h
new file mode 100644
index 0000000..9387a82
--- /dev/null
+++ b/tools/kvm/include/kvm/segment.h
@@ -0,0 +1,21 @@
+#ifndef KVM_SEGMENT_H
+#define KVM_SEGMENT_H
+
+#include <linux/types.h>
+
+static inline u32 segment_to_flat(u16 selector, u16 offset)
+{
+	return ((u32)selector << 4) + (u32) offset;
+}
+
+static inline u16 flat_to_seg16(u32 address)
+{
+	return address >> 4;
+}
+
+static inline u16 flat_to_off16(u32 address, u32 segment)
+{
+	return address - (segment << 4);
+}
+
+#endif /* KVM_SEGMENT_H */
diff --git a/tools/kvm/include/kvm/strbuf.h b/tools/kvm/include/kvm/strbuf.h
new file mode 100644
index 0000000..2beefbc
--- /dev/null
+++ b/tools/kvm/include/kvm/strbuf.h
@@ -0,0 +1,20 @@
+#ifndef __STRBUF_H__
+#define __STRBUF_H__
+
+#include <sys/types.h>
+#include <string.h>
+
+int prefixcmp(const char *str, const char *prefix);
+
+extern size_t strlcat(char *dest, const char *src, size_t count);
+extern size_t strlcpy(char *dest, const char *src, size_t size);
+
+/* some inline functions */
+
+static inline const char *skip_prefix(const char *str, const char *prefix)
+{
+	size_t len = strlen(prefix);
+	return strncmp(str, prefix, len) ? NULL : str + len;
+}
+
+#endif
diff --git a/tools/kvm/include/kvm/symbol.h b/tools/kvm/include/kvm/symbol.h
new file mode 100644
index 0000000..725bbaf
--- /dev/null
+++ b/tools/kvm/include/kvm/symbol.h
@@ -0,0 +1,30 @@
+#ifndef KVM__SYMBOL_H
+#define KVM__SYMBOL_H
+
+#include <stddef.h>
+#include <string.h>
+
+struct kvm;
+
+#define SYMBOL_DEFAULT_UNKNOWN "<unknown>"
+
+#ifdef CONFIG_HAS_BFD
+
+int symbol_init(struct kvm *kvm);
+int symbol_exit(struct kvm *kvm);
+char *symbol_lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size);
+
+#else
+
+static inline int symbol_init(struct kvm *kvm) { return 0; }
+static inline char *symbol_lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size)
+{
+	char *s = strncpy(sym, SYMBOL_DEFAULT_UNKNOWN, size);
+	sym[size - 1] = '\0';
+	return s;
+}
+static inline int symbol_exit(struct kvm *kvm) { return 0; }
+
+#endif
+
+#endif /* KVM__SYMBOL_H */
diff --git a/tools/kvm/include/kvm/term.h b/tools/kvm/include/kvm/term.h
new file mode 100644
index 0000000..a6a9822
--- /dev/null
+++ b/tools/kvm/include/kvm/term.h
@@ -0,0 +1,20 @@
+#ifndef KVM__TERM_H
+#define KVM__TERM_H
+
+#include <sys/uio.h>
+#include <stdbool.h>
+
+#define CONSOLE_8250	1
+#define CONSOLE_VIRTIO	2
+#define CONSOLE_HV	3
+
+int term_putc_iov(int who, struct iovec *iov, int iovcnt, int term);
+int term_getc_iov(int who, struct iovec *iov, int iovcnt, int term);
+int term_putc(int who, char *addr, int cnt, int term);
+int term_getc(int who, int term);
+
+bool term_readable(int who, int term);
+void term_set_tty(int term);
+void term_init(void);
+
+#endif /* KVM__TERM_H */
diff --git a/tools/kvm/include/kvm/threadpool.h b/tools/kvm/include/kvm/threadpool.h
new file mode 100644
index 0000000..768239f
--- /dev/null
+++ b/tools/kvm/include/kvm/threadpool.h
@@ -0,0 +1,37 @@
+#ifndef KVM__THREADPOOL_H
+#define KVM__THREADPOOL_H
+
+#include "kvm/mutex.h"
+
+#include <linux/list.h>
+
+struct kvm;
+
+typedef void (*kvm_thread_callback_fn_t)(struct kvm *kvm, void *data);
+
+struct thread_pool__job {
+	kvm_thread_callback_fn_t	callback;
+	struct kvm			*kvm;
+	void				*data;
+
+	int				signalcount;
+	pthread_mutex_t			mutex;
+
+	struct list_head		queue;
+};
+
+static inline void thread_pool__init_job(struct thread_pool__job *job, struct kvm *kvm, kvm_thread_callback_fn_t callback, void *data)
+{
+	*job = (struct thread_pool__job) {
+		.kvm		= kvm,
+		.callback	= callback,
+		.data		= data,
+		.mutex		= PTHREAD_MUTEX_INITIALIZER,
+	};
+}
+
+int thread_pool__init(unsigned long thread_count);
+
+void thread_pool__do_job(struct thread_pool__job *job);
+
+#endif
diff --git a/tools/kvm/include/kvm/types.h b/tools/kvm/include/kvm/types.h
new file mode 100644
index 0000000..0cbc5fb
--- /dev/null
+++ b/tools/kvm/include/kvm/types.h
@@ -0,0 +1,7 @@
+#ifndef KVM_TYPES_H
+#define KVM_TYPES_H
+
+/* FIXME: include/linux/if_tun.h and include/linux/if_ether.h complains */
+#define __be16 u16
+
+#endif /* KVM_TYPES_H */
diff --git a/tools/kvm/include/kvm/uip.h b/tools/kvm/include/kvm/uip.h
new file mode 100644
index 0000000..4497f6a
--- /dev/null
+++ b/tools/kvm/include/kvm/uip.h
@@ -0,0 +1,358 @@
+#ifndef KVM__UIP_H
+#define KVM__UIP_H
+
+#include "linux/types.h"
+#include "kvm/mutex.h"
+
+#include <netinet/in.h>
+#include <sys/uio.h>
+
+#define UIP_BUF_STATUS_FREE	0
+#define UIP_BUF_STATUS_INUSE	1
+#define UIP_BUF_STATUS_USED	2
+
+#define UIP_ETH_P_IP		0X0800
+#define UIP_ETH_P_ARP		0X0806
+
+#define UIP_IP_VER_4		0X40
+#define UIP_IP_HDR_LEN		0X05
+#define UIP_IP_TTL		0X40
+#define UIP_IP_P_UDP		0X11
+#define UIP_IP_P_TCP		0X06
+#define UIP_IP_P_ICMP		0X01
+
+#define UIP_TCP_HDR_LEN		0x50
+#define UIP_TCP_WIN_SIZE	14600
+#define UIP_TCP_FLAG_FIN	1
+#define UIP_TCP_FLAG_SYN	2
+#define UIP_TCP_FLAG_RST	4
+#define UIP_TCP_FLAG_PSH	8
+#define UIP_TCP_FLAG_ACK	16
+#define UIP_TCP_FLAG_URG	32
+
+#define UIP_BOOTP_VENDOR_SPECIFIC_LEN	64
+#define UIP_BOOTP_MAX_PAYLOAD_LEN	300
+#define UIP_DHCP_VENDOR_SPECIFIC_LEN	312
+#define UIP_DHCP_PORT_SERVER		67
+#define UIP_DHCP_PORT_CLIENT		68
+#define UIP_DHCP_MACPAD_LEN		10
+#define UIP_DHCP_HOSTNAME_LEN		64
+#define UIP_DHCP_FILENAME_LEN		128
+#define UIP_DHCP_MAGIC_COOKIE		0x63825363
+#define UIP_DHCP_MAGIC_COOKIE_LEN	4
+#define UIP_DHCP_LEASE_TIME		0x00003840
+#define UIP_DHCP_MAX_PAYLOAD_LEN	(UIP_BOOTP_MAX_PAYLOAD_LEN - UIP_BOOTP_VENDOR_SPECIFIC_LEN +  UIP_DHCP_VENDOR_SPECIFIC_LEN)
+#define UIP_DHCP_OPTION_LEN		(UIP_DHCP_VENDOR_SPECIFIC_LEN - UIP_DHCP_MAGIC_COOKIE_LEN)
+#define UIP_DHCP_DISCOVER		1
+#define UIP_DHCP_OFFER			2
+#define UIP_DHCP_REQUEST		3
+#define UIP_DHCP_ACK			5
+#define UIP_DHCP_MAX_DNS_SERVER_NR	3
+#define UIP_DHCP_MAX_DOMAIN_NAME_LEN	256
+#define UIP_DHCP_TAG_MSG_TYPE		53
+#define UIP_DHCP_TAG_MSG_TYPE_LEN	1
+#define UIP_DHCP_TAG_SERVER_ID		54
+#define UIP_DHCP_TAG_SERVER_ID_LEN	4
+#define UIP_DHCP_TAG_LEASE_TIME		51
+#define UIP_DHCP_TAG_LEASE_TIME_LEN	4
+#define UIP_DHCP_TAG_SUBMASK		1
+#define UIP_DHCP_TAG_SUBMASK_LEN	4
+#define UIP_DHCP_TAG_ROUTER		3
+#define UIP_DHCP_TAG_ROUTER_LEN		4
+#define UIP_DHCP_TAG_ROOT		17
+#define UIP_DHCP_TAG_ROOT_LEN		4
+#define UIP_DHCP_TAG_DNS_SERVER		6
+#define UIP_DHCP_TAG_DNS_SERVER_LEN	4
+#define UIP_DHCP_TAG_DOMAIN_NAME	15
+#define UIP_DHCP_TAG_END		255
+
+/*
+ * IP package maxium len == 64 KBytes
+ * IP header == 20 Bytes
+ * TCP header == 20 Bytes
+ * UDP header == 8 Bytes
+ */
+#define UIP_MAX_TCP_PAYLOAD	(64*1024 - 20 - 20 - 1)
+#define UIP_MAX_UDP_PAYLOAD	(64*1024 - 20 -  8 - 1)
+
+struct uip_eth_addr {
+	u8 addr[6];
+};
+
+struct uip_eth {
+	struct uip_eth_addr dst;
+	struct uip_eth_addr src;
+	u16 type;
+} __attribute__((packed));
+
+struct uip_arp {
+	struct uip_eth eth;
+	u16 hwtype;
+	u16 proto;
+	u8 hwlen;
+	u8 protolen;
+	u16 op;
+	struct uip_eth_addr smac;
+	u32 sip;
+	struct uip_eth_addr dmac;
+	u32 dip;
+} __attribute__((packed));
+
+struct uip_ip {
+	struct uip_eth eth;
+	u8 vhl;
+	u8 tos;
+	/*
+	 * len = IP hdr +  IP payload
+	 */
+	u16 len;
+	u16 id;
+	u16 flgfrag;
+	u8 ttl;
+	u8 proto;
+	u16 csum;
+	u32 sip;
+	u32 dip;
+} __attribute__((packed));
+
+struct uip_icmp {
+	struct uip_ip ip;
+	u8 type;
+	u8 code;
+	u16 csum;
+	u16 id;
+	u16 seq;
+} __attribute__((packed));
+
+struct uip_udp {
+	/*
+	 * FIXME: IP Options (IP hdr len > 20 bytes) are not supported
+	 */
+	struct uip_ip ip;
+	u16 sport;
+	u16 dport;
+	/*
+	 * len = UDP hdr +  UDP payload
+	 */
+	u16 len;
+	u16 csum;
+	u8 payload[0];
+} __attribute__((packed));
+
+struct uip_tcp {
+	/*
+	 * FIXME: IP Options (IP hdr len > 20 bytes) are not supported
+	 */
+	struct uip_ip ip;
+	u16 sport;
+	u16 dport;
+	u32 seq;
+	u32 ack;
+	u8  off;
+	u8  flg;
+	u16 win;
+	u16 csum;
+	u16 urgent;
+} __attribute__((packed));
+
+struct uip_pseudo_hdr {
+	u32 sip;
+	u32 dip;
+	u8 zero;
+	u8 proto;
+	u16 len;
+} __attribute__((packed));
+
+struct uip_dhcp {
+	struct uip_udp udp;
+	u8 msg_type;
+	u8 hardware_type;
+	u8 hardware_len;
+	u8 hops;
+	u32 id;
+	u16 time;
+	u16 flg;
+	u32 client_ip;
+	u32 your_ip;
+	u32 server_ip;
+	u32 agent_ip;
+	struct uip_eth_addr client_mac;
+	u8 pad[UIP_DHCP_MACPAD_LEN];
+	u8 server_hostname[UIP_DHCP_HOSTNAME_LEN];
+	u8 boot_filename[UIP_DHCP_FILENAME_LEN];
+	u32 magic_cookie;
+	u8 option[UIP_DHCP_OPTION_LEN];
+} __attribute__((packed));
+
+struct uip_info {
+	struct list_head udp_socket_head;
+	struct list_head tcp_socket_head;
+	pthread_mutex_t udp_socket_lock;
+	pthread_mutex_t tcp_socket_lock;
+	struct uip_eth_addr guest_mac;
+	struct uip_eth_addr host_mac;
+	pthread_cond_t buf_free_cond;
+	pthread_cond_t buf_used_cond;
+	struct list_head buf_head;
+	pthread_mutex_t buf_lock;
+	pthread_t udp_thread;
+	int udp_epollfd;
+	int buf_free_nr;
+	int buf_used_nr;
+	u32 guest_ip;
+	u32 guest_netmask;
+	u32 host_ip;
+	u32 dns_ip[UIP_DHCP_MAX_DNS_SERVER_NR];
+	char *domain_name;
+	u32 buf_nr;
+};
+
+struct uip_buf {
+	struct list_head list;
+	struct uip_info *info;
+	int vnet_len;
+	int eth_len;
+	int status;
+	char *vnet;
+	char *eth;
+	int id;
+};
+
+struct uip_udp_socket {
+	struct sockaddr_in addr;
+	struct list_head list;
+	pthread_mutex_t *lock;
+	u32 dport, sport;
+	u32 dip, sip;
+	int fd;
+};
+
+struct uip_tcp_socket {
+	struct sockaddr_in addr;
+	struct list_head list;
+	struct uip_info *info;
+	pthread_mutex_t *lock;
+	pthread_t thread;
+	u32 dport, sport;
+	u32 guest_acked;
+	/*
+	 * Initial Sequence Number
+	 */
+	u32 isn_server;
+	u32 isn_guest;
+	u32 ack_server;
+	u32 seq_server;
+	int write_done;
+	int read_done;
+	u32 dip, sip;
+	u8 *payload;
+	int fd;
+};
+
+struct uip_tx_arg {
+	struct virtio_net_hdr *vnet;
+	struct uip_info *info;
+	struct uip_eth *eth;
+	int vnet_len;
+	int eth_len;
+};
+
+static inline u16 uip_ip_hdrlen(struct uip_ip *ip)
+{
+	return (ip->vhl & 0x0f) * 4;
+}
+
+static inline u16 uip_ip_len(struct uip_ip *ip)
+{
+	return htons(ip->len);
+}
+
+static inline u16 uip_udp_hdrlen(struct uip_udp *udp)
+{
+	return 8;
+}
+
+static inline u16 uip_udp_len(struct uip_udp *udp)
+{
+	return ntohs(udp->len);
+}
+
+static inline u16 uip_tcp_hdrlen(struct uip_tcp *tcp)
+{
+	return (tcp->off >> 4) * 4;
+}
+
+static inline u16 uip_tcp_len(struct uip_tcp *tcp)
+{
+	struct uip_ip *ip;
+
+	ip = &tcp->ip;
+
+	return uip_ip_len(ip) - uip_ip_hdrlen(ip);
+}
+
+static inline u16 uip_tcp_payloadlen(struct uip_tcp *tcp)
+{
+	return uip_tcp_len(tcp) - uip_tcp_hdrlen(tcp);
+}
+
+static inline u8 *uip_tcp_payload(struct uip_tcp *tcp)
+{
+	return (u8 *)&tcp->sport + uip_tcp_hdrlen(tcp);
+}
+
+static inline bool uip_tcp_is_syn(struct uip_tcp *tcp)
+{
+	return (tcp->flg & UIP_TCP_FLAG_SYN) != 0;
+}
+
+static inline bool uip_tcp_is_fin(struct uip_tcp *tcp)
+{
+	return (tcp->flg & UIP_TCP_FLAG_FIN) != 0;
+}
+
+static inline u32 uip_tcp_isn(struct uip_tcp *tcp)
+{
+	return ntohl(tcp->seq);
+}
+
+static inline u32 uip_tcp_isn_alloc(void)
+{
+	/*
+	 * FIXME: should increase every 4ms
+	 */
+	return 10000000;
+}
+
+static inline u16 uip_eth_hdrlen(struct uip_eth *eth)
+{
+	return sizeof(*eth);
+}
+
+int uip_tx(struct iovec *iov, u16 out, struct uip_info *info);
+int uip_rx(struct iovec *iov, u16 in, struct uip_info *info);
+int uip_init(struct uip_info *info);
+
+int uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg *arg);
+int uip_tx_do_ipv4_icmp(struct uip_tx_arg *arg);
+int uip_tx_do_ipv4_tcp(struct uip_tx_arg *arg);
+int uip_tx_do_ipv4_udp(struct uip_tx_arg *arg);
+int uip_tx_do_ipv4(struct uip_tx_arg *arg);
+int uip_tx_do_arp(struct uip_tx_arg *arg);
+
+u16 uip_csum_icmp(struct uip_icmp *icmp);
+u16 uip_csum_udp(struct uip_udp *udp);
+u16 uip_csum_tcp(struct uip_tcp *tcp);
+u16 uip_csum_ip(struct uip_ip *ip);
+
+struct uip_buf *uip_buf_set_used(struct uip_info *info, struct uip_buf *buf);
+struct uip_buf *uip_buf_set_free(struct uip_info *info, struct uip_buf *buf);
+struct uip_buf *uip_buf_get_used(struct uip_info *info);
+struct uip_buf *uip_buf_get_free(struct uip_info *info);
+struct uip_buf *uip_buf_clone(struct uip_tx_arg *arg);
+
+int uip_udp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 *payload, int payload_len);
+bool uip_udp_is_dhcp(struct uip_udp *udp);
+
+int uip_dhcp_get_dns(struct uip_info *info);
+#endif /* KVM__UIP_H */
diff --git a/tools/kvm/include/kvm/util.h b/tools/kvm/include/kvm/util.h
new file mode 100644
index 0000000..dabf544
--- /dev/null
+++ b/tools/kvm/include/kvm/util.h
@@ -0,0 +1,95 @@
+#include <linux/stringify.h>
+
+#ifndef KVM__UTIL_H
+#define KVM__UTIL_H
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/*
+ * Some bits are stolen from perf tool :)
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <linux/types.h>
+
+#ifdef __GNUC__
+#define NORETURN __attribute__((__noreturn__))
+#else
+#define NORETURN
+#ifndef __attribute__
+#define __attribute__(x)
+#endif
+#endif
+
+extern bool do_debug_print;
+
+#define PROT_RW (PROT_READ|PROT_WRITE)
+#define MAP_ANON_NORESERVE (MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE)
+
+extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
+extern void die_perror(const char *s) NORETURN;
+extern int pr_err(const char *err, ...) __attribute__((format (printf, 1, 2)));
+extern void pr_warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
+extern void pr_info(const char *err, ...) __attribute__((format (printf, 1, 2)));
+extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
+
+#define pr_debug(fmt, ...)						\
+	do {								\
+		if (do_debug_print)					\
+			pr_info("(%s) %s:%d: " fmt, __FILE__,		\
+				__func__, __LINE__, ##__VA_ARGS__);	\
+	} while (0)
+
+
+#define BUILD_BUG_ON(condition)	((void)sizeof(char[1 - 2*!!(condition)]))
+
+#ifndef BUG_ON_HANDLER
+# define BUG_ON_HANDLER(condition)					\
+	do {								\
+		if ((condition)) {					\
+			pr_err("BUG at %s:%d", __FILE__, __LINE__);	\
+			raise(SIGABRT);					\
+		}							\
+	} while (0)
+#endif
+
+#define BUG_ON(condition)	BUG_ON_HANDLER((condition))
+
+#define DIE_IF(cnd)						\
+do {								\
+	if (cnd)						\
+	die(" at (" __FILE__ ":" __stringify(__LINE__) "): "	\
+		__stringify(cnd) "\n");				\
+} while (0)
+
+#define WARN_ON(condition) ({					\
+	int __ret_warn_on = !!(condition);			\
+	if (__ret_warn_on)					\
+		pr_warning("(%s) %s:%d: failed condition: %s",	\
+				__FILE__, __func__, __LINE__,	\
+				__stringify(condition));	\
+	__ret_warn_on;						\
+})
+
+#define MSECS_TO_USECS(s) ((s) * 1000)
+
+/* Millisecond sleep */
+static inline void msleep(unsigned int msecs)
+{
+	usleep(MSECS_TO_USECS(msecs));
+}
+
+void *mmap_hugetlbfs(const char *htlbfs_path, u64 size);
+
+#endif /* KVM__UTIL_H */
diff --git a/tools/kvm/include/kvm/vesa.h b/tools/kvm/include/kvm/vesa.h
new file mode 100644
index 0000000..ac041d9
--- /dev/null
+++ b/tools/kvm/include/kvm/vesa.h
@@ -0,0 +1,18 @@
+#ifndef KVM__VESA_H
+#define KVM__VESA_H
+
+#include <linux/types.h>
+
+#define VESA_WIDTH	640
+#define VESA_HEIGHT	480
+
+#define VESA_MEM_ADDR	0xd0000000
+#define VESA_MEM_SIZE	(4*VESA_WIDTH*VESA_HEIGHT)
+#define VESA_BPP	32
+
+struct kvm;
+struct biosregs;
+
+struct framebuffer *vesa__init(struct kvm *self);
+
+#endif
diff --git a/tools/kvm/include/kvm/virtio-9p.h b/tools/kvm/include/kvm/virtio-9p.h
new file mode 100644
index 0000000..5902701
--- /dev/null
+++ b/tools/kvm/include/kvm/virtio-9p.h
@@ -0,0 +1,73 @@
+#ifndef KVM__VIRTIO_9P_H
+#define KVM__VIRTIO_9P_H
+#include "kvm/virtio.h"
+#include "kvm/pci.h"
+#include "kvm/threadpool.h"
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <linux/list.h>
+
+#define NUM_VIRT_QUEUES		1
+#define VIRTQUEUE_NUM		128
+#define	VIRTIO_9P_DEFAULT_TAG	"kvm_9p"
+#define VIRTIO_9P_HDR_LEN	(sizeof(u32)+sizeof(u8)+sizeof(u16))
+#define VIRTIO_9P_MAX_FID	16384
+#define VIRTIO_9P_VERSION_DOTL	"9P2000.L"
+#define MAX_TAG_LEN		32
+
+struct p9_msg {
+	u32			size;
+	u8			cmd;
+	u16			tag;
+	u8			msg[0];
+} __attribute__((packed));
+
+struct p9_fid {
+	u32			fid;
+	u32			uid;
+	u8			is_dir;
+	char			abs_path[PATH_MAX];
+	char			*path;
+	DIR			*dir;
+	int			fd;
+};
+
+struct p9_dev_job {
+	struct virt_queue	*vq;
+	struct p9_dev		*p9dev;
+	struct thread_pool__job job_id;
+};
+
+struct p9_dev {
+	struct list_head	list;
+	struct virtio_device	vdev;
+
+	struct virtio_9p_config	*config;
+	u32			features;
+
+	/* virtio queue */
+	struct virt_queue	vqs[NUM_VIRT_QUEUES];
+	struct p9_dev_job	jobs[NUM_VIRT_QUEUES];
+	struct p9_fid		fids[VIRTIO_9P_MAX_FID];
+	char			root_dir[PATH_MAX];
+};
+
+struct p9_pdu {
+	u32			queue_head;
+	size_t			read_offset;
+	size_t			write_offset;
+	u16			out_iov_cnt;
+	u16			in_iov_cnt;
+	struct iovec		in_iov[VIRTQUEUE_NUM];
+	struct iovec		out_iov[VIRTQUEUE_NUM];
+};
+
+struct kvm;
+
+int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name);
+int virtio_9p__init(struct kvm *kvm);
+int virtio_p9_pdu_readf(struct p9_pdu *pdu, const char *fmt, ...);
+int virtio_p9_pdu_writef(struct p9_pdu *pdu, const char *fmt, ...);
+
+#endif
diff --git a/tools/kvm/include/kvm/virtio-balloon.h b/tools/kvm/include/kvm/virtio-balloon.h
new file mode 100644
index 0000000..eb49fd4
--- /dev/null
+++ b/tools/kvm/include/kvm/virtio-balloon.h
@@ -0,0 +1,8 @@
+#ifndef KVM__BLN_VIRTIO_H
+#define KVM__BLN_VIRTIO_H
+
+struct kvm;
+
+void virtio_bln__init(struct kvm *kvm);
+
+#endif /* KVM__BLN_VIRTIO_H */
diff --git a/tools/kvm/include/kvm/virtio-blk.h b/tools/kvm/include/kvm/virtio-blk.h
new file mode 100644
index 0000000..12e59b6
--- /dev/null
+++ b/tools/kvm/include/kvm/virtio-blk.h
@@ -0,0 +1,12 @@
+#ifndef KVM__BLK_VIRTIO_H
+#define KVM__BLK_VIRTIO_H
+
+#include "kvm/disk-image.h"
+
+struct kvm;
+
+int virtio_blk__init(struct kvm *kvm);
+int virtio_blk__exit(struct kvm *kvm);
+void virtio_blk_complete(void *param, long len);
+
+#endif /* KVM__BLK_VIRTIO_H */
diff --git a/tools/kvm/include/kvm/virtio-console.h b/tools/kvm/include/kvm/virtio-console.h
new file mode 100644
index 0000000..50d8653
--- /dev/null
+++ b/tools/kvm/include/kvm/virtio-console.h
@@ -0,0 +1,9 @@
+#ifndef KVM__CONSOLE_VIRTIO_H
+#define KVM__CONSOLE_VIRTIO_H
+
+struct kvm;
+
+void virtio_console__init(struct kvm *kvm);
+void virtio_console__inject_interrupt(struct kvm *kvm);
+
+#endif /* KVM__CONSOLE_VIRTIO_H */
diff --git a/tools/kvm/include/kvm/virtio-mmio.h b/tools/kvm/include/kvm/virtio-mmio.h
new file mode 100644
index 0000000..e0ede3c
--- /dev/null
+++ b/tools/kvm/include/kvm/virtio-mmio.h
@@ -0,0 +1,58 @@
+#ifndef KVM__VIRTIO_MMIO_H
+#define KVM__VIRTIO_MMIO_H
+
+#include <linux/types.h>
+#include <linux/virtio_mmio.h>
+
+#define VIRTIO_MMIO_MAX_VQ	3
+#define VIRTIO_MMIO_MAX_CONFIG	1
+#define VIRTIO_MMIO_IO_SIZE	0x200
+
+struct kvm;
+
+struct virtio_mmio_ioevent_param {
+	struct virtio_device	*vdev;
+	u32			vq;
+};
+
+struct virtio_mmio_hdr {
+	char	magic[4];
+	u32	version;
+	u32	device_id;
+	u32	vendor_id;
+	u32	host_features;
+	u32	host_features_sel;
+	u32	reserved_1[2];
+	u32	guest_features;
+	u32	guest_features_sel;
+	u32	guest_page_size;
+	u32	reserved_2;
+	u32	queue_sel;
+	u32	queue_num_max;
+	u32	queue_num;
+	u32	queue_align;
+	u32	queue_pfn;
+	u32	reserved_3[3];
+	u32	queue_notify;
+	u32	reserved_4[3];
+	u32	interrupt_state;
+	u32	interrupt_ack;
+	u32	reserved_5[2];
+	u32	status;
+} __attribute__((packed));
+
+struct virtio_mmio {
+	u32			addr;
+	void			*dev;
+	struct kvm		*kvm;
+	u8			irq;
+	struct virtio_mmio_hdr	hdr;
+	struct virtio_mmio_ioevent_param ioeventfds[VIRTIO_MMIO_MAX_VQ];
+};
+
+int virtio_mmio_signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq);
+int virtio_mmio_signal_config(struct kvm *kvm, struct virtio_device *vdev);
+int virtio_mmio_exit(struct kvm *kvm, struct virtio_device *vdev);
+int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+		      int device_id, int subsys_id, int class);
+#endif
diff --git a/tools/kvm/include/kvm/virtio-net.h b/tools/kvm/include/kvm/virtio-net.h
new file mode 100644
index 0000000..737676eb
--- /dev/null
+++ b/tools/kvm/include/kvm/virtio-net.h
@@ -0,0 +1,26 @@
+#ifndef KVM__VIRTIO_NET_H
+#define KVM__VIRTIO_NET_H
+
+struct kvm;
+
+struct virtio_net_params {
+	const char *guest_ip;
+	const char *host_ip;
+	const char *script;
+	const char *trans;
+	char guest_mac[6];
+	char host_mac[6];
+	struct kvm *kvm;
+	int mode;
+	int vhost;
+	int fd;
+};
+
+void virtio_net__init(const struct virtio_net_params *params);
+
+enum {
+	NET_MODE_USER,
+	NET_MODE_TAP
+};
+
+#endif /* KVM__VIRTIO_NET_H */
diff --git a/tools/kvm/include/kvm/virtio-pci-dev.h b/tools/kvm/include/kvm/virtio-pci-dev.h
new file mode 100644
index 0000000..7ceb125
--- /dev/null
+++ b/tools/kvm/include/kvm/virtio-pci-dev.h
@@ -0,0 +1,37 @@
+#ifndef VIRTIO_PCI_DEV_H_
+#define VIRTIO_PCI_DEV_H_
+
+#include <linux/virtio_ids.h>
+
+/*
+ * Virtio PCI device constants and resources
+ * they do use (such as irqs and pins).
+ */
+
+#define PCI_DEVICE_ID_VIRTIO_NET		0x1000
+#define PCI_DEVICE_ID_VIRTIO_BLK		0x1001
+#define PCI_DEVICE_ID_VIRTIO_CONSOLE		0x1003
+#define PCI_DEVICE_ID_VIRTIO_RNG		0x1004
+#define PCI_DEVICE_ID_VIRTIO_BLN		0x1005
+#define PCI_DEVICE_ID_VIRTIO_9P			0x1009
+#define PCI_DEVICE_ID_VESA			0x2000
+#define PCI_DEVICE_ID_PCI_SHMEM			0x0001
+
+#define PCI_VENDOR_ID_REDHAT_QUMRANET		0x1af4
+#define PCI_VENDOR_ID_PCI_SHMEM			0x0001
+#define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET	0x1af4
+
+#define PCI_SUBSYSTEM_ID_VESA			0x0004
+#define PCI_SUBSYSTEM_ID_PCI_SHMEM		0x0001
+
+#define PCI_CLASS_BLK				0x018000
+#define PCI_CLASS_NET				0x020000
+#define PCI_CLASS_CONSOLE			0x078000
+/*
+ * 0xFF Device does not fit in any defined classes
+ */
+#define PCI_CLASS_RNG				0xff0000
+#define PCI_CLASS_BLN				0xff0000
+#define PCI_CLASS_9P				0xff0000
+
+#endif /* VIRTIO_PCI_DEV_H_ */
diff --git a/tools/kvm/include/kvm/virtio-pci.h b/tools/kvm/include/kvm/virtio-pci.h
new file mode 100644
index 0000000..9e036b2
--- /dev/null
+++ b/tools/kvm/include/kvm/virtio-pci.h
@@ -0,0 +1,46 @@
+#ifndef KVM__VIRTIO_PCI_H
+#define KVM__VIRTIO_PCI_H
+
+#include "kvm/pci.h"
+
+#include <linux/types.h>
+
+#define VIRTIO_PCI_MAX_VQ	3
+#define VIRTIO_PCI_MAX_CONFIG	1
+
+struct kvm;
+
+struct virtio_pci_ioevent_param {
+	struct virtio_device	*vdev;
+	u32			vq;
+};
+
+struct virtio_pci {
+	struct pci_device_header pci_hdr;
+	void			*dev;
+
+	u16			base_addr;
+	u8			status;
+	u8			isr;
+
+	/* MSI-X */
+	u16			config_vector;
+	u32			config_gsi;
+	u32			vq_vector[VIRTIO_PCI_MAX_VQ];
+	u32			gsis[VIRTIO_PCI_MAX_VQ];
+	u32			msix_io_block;
+	u64			msix_pba;
+	struct msix_table	msix_table[VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG];
+
+	/* virtio queue */
+	u16			queue_selector;
+	struct virtio_pci_ioevent_param ioeventfds[VIRTIO_PCI_MAX_VQ];
+};
+
+int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq);
+int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev);
+int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev);
+int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+		     int device_id, int subsys_id, int class);
+
+#endif
diff --git a/tools/kvm/include/kvm/virtio-rng.h b/tools/kvm/include/kvm/virtio-rng.h
new file mode 100644
index 0000000..b585b37
--- /dev/null
+++ b/tools/kvm/include/kvm/virtio-rng.h
@@ -0,0 +1,9 @@
+#ifndef KVM__RNG_VIRTIO_H
+#define KVM__RNG_VIRTIO_H
+
+struct kvm;
+
+int virtio_rng__init(struct kvm *kvm);
+int virtio_rng__exit(struct kvm *kvm);
+
+#endif /* KVM__RNG_VIRTIO_H */
diff --git a/tools/kvm/include/kvm/virtio.h b/tools/kvm/include/kvm/virtio.h
new file mode 100644
index 0000000..a957a5b
--- /dev/null
+++ b/tools/kvm/include/kvm/virtio.h
@@ -0,0 +1,102 @@
+#ifndef KVM__VIRTIO_H
+#define KVM__VIRTIO_H
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_pci.h>
+
+#include <linux/types.h>
+#include <sys/uio.h>
+
+#include "kvm/kvm.h"
+
+#define VIRTIO_IRQ_LOW		0
+#define VIRTIO_IRQ_HIGH		1
+
+#define VIRTIO_PCI_O_CONFIG	0
+#define VIRTIO_PCI_O_MSIX	1
+
+struct virt_queue {
+	struct vring	vring;
+	u32		pfn;
+	/* The last_avail_idx field is an index to ->ring of struct vring_avail.
+	   It's where we assume the next request index is at.  */
+	u16		last_avail_idx;
+	u16		last_used_signalled;
+};
+
+static inline u16 virt_queue__pop(struct virt_queue *queue)
+{
+	return queue->vring.avail->ring[queue->last_avail_idx++ % queue->vring.num];
+}
+
+static inline struct vring_desc *virt_queue__get_desc(struct virt_queue *queue, u16 desc_ndx)
+{
+	return &queue->vring.desc[desc_ndx];
+}
+
+static inline bool virt_queue__available(struct virt_queue *vq)
+{
+	if (!vq->vring.avail)
+		return 0;
+
+	vring_avail_event(&vq->vring) = vq->last_avail_idx;
+	return vq->vring.avail->idx !=  vq->last_avail_idx;
+}
+
+/*
+ * Warning: on 32-bit hosts, shifting pfn left may cause a truncation of pfn values
+ * higher than 4GB - thus, pointing to the wrong area in guest virtual memory space
+ * and breaking the virt queue which owns this pfn.
+ */
+static inline void *guest_pfn_to_host(struct kvm *kvm, u32 pfn)
+{
+	return guest_flat_to_host(kvm, (unsigned long)pfn << VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+}
+
+
+struct vring_used_elem *virt_queue__set_used_elem(struct virt_queue *queue, u32 head, u32 len);
+
+bool virtio_queue__should_signal(struct virt_queue *vq);
+u16 virt_queue__get_iov(struct virt_queue *vq, struct iovec iov[],
+			u16 *out, u16 *in, struct kvm *kvm);
+u16 virt_queue__get_head_iov(struct virt_queue *vq, struct iovec iov[],
+			     u16 *out, u16 *in, u16 head, struct kvm *kvm);
+u16 virt_queue__get_inout_iov(struct kvm *kvm, struct virt_queue *queue,
+			      struct iovec in_iov[], struct iovec out_iov[],
+			      u16 *in, u16 *out);
+int virtio__get_dev_specific_field(int offset, bool msix, u32 *config_off);
+
+enum virtio_trans {
+	VIRTIO_PCI,
+	VIRTIO_MMIO,
+};
+
+struct virtio_device {
+	void			*virtio;
+	struct virtio_ops	*ops;
+};
+
+struct virtio_ops {
+	void (*set_config)(struct kvm *kvm, void *dev, u8 data, u32 offset);
+	u8 (*get_config)(struct kvm *kvm, void *dev, u32 offset);
+	u32 (*get_host_features)(struct kvm *kvm, void *dev);
+	void (*set_guest_features)(struct kvm *kvm, void *dev, u32 features);
+	int (*init_vq)(struct kvm *kvm, void *dev, u32 vq, u32 pfn);
+	int (*notify_vq)(struct kvm *kvm, void *dev, u32 vq);
+	int (*get_pfn_vq)(struct kvm *kvm, void *dev, u32 vq);
+	int (*get_size_vq)(struct kvm *kvm, void *dev, u32 vq);
+	int (*set_size_vq)(struct kvm *kvm, void *dev, u32 vq, int size);
+	void (*notify_vq_gsi)(struct kvm *kvm, void *dev, u32 vq, u32 gsi);
+	void (*notify_vq_eventfd)(struct kvm *kvm, void *dev, u32 vq, u32 efd);
+	int (*signal_vq)(struct kvm *kvm, struct virtio_device *vdev, u32 queueid);
+	int (*signal_config)(struct kvm *kvm, struct virtio_device *vdev);
+	int (*init)(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+		    int device_id, int subsys_id, int class);
+	int (*exit)(struct kvm *kvm, struct virtio_device *vdev);
+};
+
+int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+		struct virtio_ops *ops, enum virtio_trans trans,
+		int device_id, int subsys_id, int class);
+int virtio_compat_add_message(const char *device, const char *config);
+#endif /* KVM__VIRTIO_H */
diff --git a/tools/kvm/include/kvm/vnc.h b/tools/kvm/include/kvm/vnc.h
new file mode 100644
index 0000000..3278c07
--- /dev/null
+++ b/tools/kvm/include/kvm/vnc.h
@@ -0,0 +1,20 @@
+#ifndef KVM__VNC_H
+#define KVM__VNC_H
+
+struct framebuffer;
+
+#ifdef CONFIG_HAS_VNCSERVER
+int vnc__init(struct framebuffer *fb);
+int vnc__exit(struct framebuffer *fb);
+#else
+static inline int vnc__init(struct framebuffer *fb)
+{
+	return 0;
+}
+static inline int vnc__exit(struct framebuffer *fb)
+{
+	return 0;
+}
+#endif
+
+#endif /* KVM__VNC_H */
diff --git a/tools/kvm/include/linux/bitops.h b/tools/kvm/include/linux/bitops.h
new file mode 100644
index 0000000..56448b7
--- /dev/null
+++ b/tools/kvm/include/linux/bitops.h
@@ -0,0 +1,33 @@
+#ifndef _KVM_LINUX_BITOPS_H_
+#define _KVM_LINUX_BITOPS_H_
+
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <asm/hweight.h>
+
+#define BITS_PER_LONG __WORDSIZE
+#define BITS_PER_BYTE           8
+#define BITS_TO_LONGS(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+
+static inline void set_bit(int nr, unsigned long *addr)
+{
+	addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
+}
+
+static inline void clear_bit(int nr, unsigned long *addr)
+{
+	addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG));
+}
+
+static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
+{
+	return ((1UL << (nr % BITS_PER_LONG)) &
+		(((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
+}
+
+static inline unsigned long hweight_long(unsigned long w)
+{
+	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
+}
+
+#endif
diff --git a/tools/kvm/include/linux/byteorder.h b/tools/kvm/include/linux/byteorder.h
new file mode 100644
index 0000000..c490de8
--- /dev/null
+++ b/tools/kvm/include/linux/byteorder.h
@@ -0,0 +1,7 @@
+#ifndef __BYTE_ORDER_H__
+#define __BYTE_ORDER_H__
+
+#include <asm/byteorder.h>
+#include <linux/byteorder/generic.h>
+
+#endif
diff --git a/tools/kvm/include/linux/compiler.h b/tools/kvm/include/linux/compiler.h
new file mode 100644
index 0000000..b9c5346
--- /dev/null
+++ b/tools/kvm/include/linux/compiler.h
@@ -0,0 +1,19 @@
+#ifndef _PERF_LINUX_COMPILER_H_
+#define _PERF_LINUX_COMPILER_H_
+
+#ifndef __always_inline
+#define __always_inline	inline
+#endif
+#define __user
+
+#ifndef __attribute_const__
+#define __attribute_const__
+#endif
+
+#define __used		__attribute__((__unused__))
+#define __iomem
+#define __force
+#define __must_check
+#define unlikely
+
+#endif
diff --git a/tools/kvm/include/linux/kernel.h b/tools/kvm/include/linux/kernel.h
new file mode 100644
index 0000000..d2ec4a3
--- /dev/null
+++ b/tools/kvm/include/linux/kernel.h
@@ -0,0 +1,39 @@
+
+#ifndef KVM__LINUX_KERNEL_H_
+#define KVM__LINUX_KERNEL_H_
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+#define ALIGN(x,a)		__ALIGN_MASK(x,(typeof(x))(a)-1)
+#define __ALIGN_MASK(x,mask)	(((x)+(mask))&~(mask))
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#ifndef container_of
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:	the pointer to the member.
+ * @type:	the type of the container struct this is embedded in.
+ * @member:	the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({			\
+	const typeof(((type *)0)->member) * __mptr = (ptr);	\
+	(type *)((char *)__mptr - offsetof(type, member)); })
+#endif
+
+#define min(x, y) ({				\
+	typeof(x) _min1 = (x);			\
+	typeof(y) _min2 = (y);			\
+	(void) (&_min1 == &_min2);		\
+	_min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({				\
+	typeof(x) _max1 = (x);			\
+	typeof(y) _max2 = (y);			\
+	(void) (&_max1 == &_max2);		\
+	_max1 > _max2 ? _max1 : _max2; })
+
+#endif
diff --git a/tools/kvm/include/linux/module.h b/tools/kvm/include/linux/module.h
new file mode 100644
index 0000000..0e4c6a3
--- /dev/null
+++ b/tools/kvm/include/linux/module.h
@@ -0,0 +1,6 @@
+#ifndef KVM__LINUX_MODULE_H
+#define KVM__LINUX_MODULE_H
+
+#define EXPORT_SYMBOL(name)
+
+#endif
diff --git a/tools/kvm/include/linux/prefetch.h b/tools/kvm/include/linux/prefetch.h
new file mode 100644
index 0000000..62f6788
--- /dev/null
+++ b/tools/kvm/include/linux/prefetch.h
@@ -0,0 +1,6 @@
+#ifndef KVM__LINUX_PREFETCH_H
+#define KVM__LINUX_PREFETCH_H
+
+static inline void prefetch(void *a __attribute__((unused))) { }
+
+#endif
diff --git a/tools/kvm/include/linux/stddef.h b/tools/kvm/include/linux/stddef.h
new file mode 100644
index 0000000..60ea512
--- /dev/null
+++ b/tools/kvm/include/linux/stddef.h
@@ -0,0 +1,16 @@
+#ifndef _LINUX_STDDEF_H
+#define _LINUX_STDDEF_H
+
+#include <linux/compiler.h>
+
+#undef NULL
+#define NULL ((void *)0)
+
+#undef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#endif
diff --git a/tools/kvm/include/linux/types.h b/tools/kvm/include/linux/types.h
new file mode 100644
index 0000000..5e20f10
--- /dev/null
+++ b/tools/kvm/include/linux/types.h
@@ -0,0 +1,51 @@
+#ifndef LINUX_TYPES_H
+#define LINUX_TYPES_H
+
+#include <kvm/compiler.h>
+#define __SANE_USERSPACE_TYPES__	/* For PPC64, to get LL64 types */
+#include <asm/types.h>
+
+typedef __u64 u64;
+typedef __s64 s64;
+
+typedef __u32 u32;
+typedef __s32 s32;
+
+typedef __u16 u16;
+typedef __s16 s16;
+
+typedef __u8  u8;
+typedef __s8  s8;
+
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#ifdef __CHECK_ENDIAN__
+#define __bitwise __bitwise__
+#else
+#define __bitwise
+#endif
+
+
+typedef __u16 __bitwise __le16;
+typedef __u16 __bitwise __be16;
+typedef __u32 __bitwise __le32;
+typedef __u32 __bitwise __be32;
+typedef __u64 __bitwise __le64;
+typedef __u64 __bitwise __be64;
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+struct hlist_head {
+	struct hlist_node *first;
+};
+
+struct hlist_node {
+	struct hlist_node *next, **pprev;
+};
+
+#endif /* LINUX_TYPES_H */
diff --git a/tools/kvm/ioeventfd.c b/tools/kvm/ioeventfd.c
new file mode 100644
index 0000000..97deb06
--- /dev/null
+++ b/tools/kvm/ioeventfd.c
@@ -0,0 +1,212 @@
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <linux/kernel.h>
+#include <linux/kvm.h>
+#include <linux/types.h>
+
+#include "kvm/ioeventfd.h"
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+
+#define IOEVENTFD_MAX_EVENTS	20
+
+static struct	epoll_event events[IOEVENTFD_MAX_EVENTS];
+static int	epoll_fd, epoll_stop_fd;
+static LIST_HEAD(used_ioevents);
+static bool	ioeventfd_avail;
+
+static void *ioeventfd__thread(void *param)
+{
+	u64 tmp = 1;
+
+	for (;;) {
+		int nfds, i;
+
+		nfds = epoll_wait(epoll_fd, events, IOEVENTFD_MAX_EVENTS, -1);
+		for (i = 0; i < nfds; i++) {
+			struct ioevent *ioevent;
+
+			if (events[i].data.fd == epoll_stop_fd)
+				goto done;
+
+			ioevent = events[i].data.ptr;
+
+			if (read(ioevent->fd, &tmp, sizeof(tmp)) < 0)
+				die("Failed reading event");
+
+			ioevent->fn(ioevent->fn_kvm, ioevent->fn_ptr);
+		}
+	}
+
+done:
+	tmp = 1;
+	tmp = write(epoll_stop_fd, &tmp, sizeof(tmp));
+
+	return NULL;
+}
+
+static int ioeventfd__start(void)
+{
+	pthread_t thread;
+
+	if (!ioeventfd_avail)
+		return -ENOSYS;
+
+	return pthread_create(&thread, NULL, ioeventfd__thread, NULL);
+}
+
+int ioeventfd__init(struct kvm *kvm)
+{
+	struct epoll_event epoll_event = {.events = EPOLLIN};
+	int r;
+
+	ioeventfd_avail = kvm__supports_extension(kvm, KVM_CAP_IOEVENTFD);
+	if (!ioeventfd_avail)
+		return 1; /* Not fatal, but let caller determine no-go. */
+
+	epoll_fd = epoll_create(IOEVENTFD_MAX_EVENTS);
+	if (epoll_fd < 0)
+		return -errno;
+
+	epoll_stop_fd = eventfd(0, 0);
+	epoll_event.data.fd = epoll_stop_fd;
+
+	r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, epoll_stop_fd, &epoll_event);
+	if (r < 0)
+		goto cleanup;
+
+	r = ioeventfd__start();
+	if (r < 0)
+		goto cleanup;
+
+	r = 0;
+
+	return r;
+
+cleanup:
+	close(epoll_stop_fd);
+	close(epoll_fd);
+
+	return r;
+}
+
+int ioeventfd__exit(struct kvm *kvm)
+{
+	u64 tmp = 1;
+	int r;
+
+	if (!ioeventfd_avail)
+		return 0;
+
+	r = write(epoll_stop_fd, &tmp, sizeof(tmp));
+	if (r < 0)
+		return r;
+
+	r = read(epoll_stop_fd, &tmp, sizeof(tmp));
+	if (r < 0)
+		return r;
+
+	close(epoll_fd);
+	close(epoll_stop_fd);
+
+	return 0;
+}
+
+int ioeventfd__add_event(struct ioevent *ioevent, bool is_pio)
+{
+	struct kvm_ioeventfd kvm_ioevent;
+	struct epoll_event epoll_event;
+	struct ioevent *new_ioevent;
+	int event, r;
+
+	if (!ioeventfd_avail)
+		return -ENOSYS;
+
+	new_ioevent = malloc(sizeof(*new_ioevent));
+	if (new_ioevent == NULL)
+		return -ENOMEM;
+
+	*new_ioevent = *ioevent;
+	event = new_ioevent->fd;
+
+	kvm_ioevent = (struct kvm_ioeventfd) {
+		.addr		= ioevent->io_addr,
+		.len		= ioevent->io_len,
+		.datamatch	= ioevent->datamatch,
+		.fd		= event,
+		.flags		= KVM_IOEVENTFD_FLAG_DATAMATCH,
+	};
+
+	if (is_pio)
+		kvm_ioevent.flags |= KVM_IOEVENTFD_FLAG_PIO;
+
+	r = ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent);
+	if (r) {
+		r = -errno;
+		goto cleanup;
+	}
+
+	epoll_event = (struct epoll_event) {
+		.events		= EPOLLIN,
+		.data.ptr	= new_ioevent,
+	};
+
+	r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event, &epoll_event);
+	if (r) {
+		r = -errno;
+		goto cleanup;
+	}
+
+	list_add_tail(&new_ioevent->list, &used_ioevents);
+
+	return 0;
+
+cleanup:
+	free(new_ioevent);
+	return r;
+}
+
+int ioeventfd__del_event(u64 addr, u64 datamatch)
+{
+	struct kvm_ioeventfd kvm_ioevent;
+	struct ioevent *ioevent;
+	u8 found = 0;
+
+	if (!ioeventfd_avail)
+		return -ENOSYS;
+
+	list_for_each_entry(ioevent, &used_ioevents, list) {
+		if (ioevent->io_addr == addr) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found == 0 || ioevent == NULL)
+		return -ENOENT;
+
+	kvm_ioevent = (struct kvm_ioeventfd) {
+		.addr			= ioevent->io_addr,
+		.len			= ioevent->io_len,
+		.datamatch		= ioevent->datamatch,
+		.flags			= KVM_IOEVENTFD_FLAG_PIO
+					| KVM_IOEVENTFD_FLAG_DEASSIGN
+					| KVM_IOEVENTFD_FLAG_DATAMATCH,
+	};
+
+	ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent);
+
+	epoll_ctl(epoll_fd, EPOLL_CTL_DEL, ioevent->fd, NULL);
+
+	list_del(&ioevent->list);
+
+	close(ioevent->fd);
+	free(ioevent);
+
+	return 0;
+}
diff --git a/tools/kvm/ioport.c b/tools/kvm/ioport.c
new file mode 100644
index 0000000..662a78b
--- /dev/null
+++ b/tools/kvm/ioport.c
@@ -0,0 +1,195 @@
+#include "kvm/ioport.h"
+
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+#include "kvm/brlock.h"
+#include "kvm/rbtree-interval.h"
+#include "kvm/mutex.h"
+
+#include <linux/kvm.h>	/* for KVM_EXIT_* */
+#include <linux/types.h>
+
+#include <stdbool.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define ioport_node(n) rb_entry(n, struct ioport, node)
+
+DEFINE_MUTEX(ioport_mutex);
+
+static u16			free_io_port_idx; /* protected by ioport_mutex */
+
+static struct rb_root		ioport_tree = RB_ROOT;
+bool				ioport_debug;
+
+static u16 ioport__find_free_port(void)
+{
+	u16 free_port;
+
+	mutex_lock(&ioport_mutex);
+	free_port = IOPORT_START + free_io_port_idx * IOPORT_SIZE;
+	free_io_port_idx++;
+	mutex_unlock(&ioport_mutex);
+
+	return free_port;
+}
+
+static struct ioport *ioport_search(struct rb_root *root, u64 addr)
+{
+	struct rb_int_node *node;
+
+	node = rb_int_search_single(root, addr);
+	if (node == NULL)
+		return NULL;
+
+	return ioport_node(node);
+}
+
+static int ioport_insert(struct rb_root *root, struct ioport *data)
+{
+	return rb_int_insert(root, &data->node);
+}
+
+static void ioport_remove(struct rb_root *root, struct ioport *data)
+{
+	rb_int_erase(root, &data->node);
+}
+
+int ioport__register(u16 port, struct ioport_operations *ops, int count, void *param)
+{
+	struct ioport *entry;
+	int r;
+
+	br_write_lock();
+	if (port == IOPORT_EMPTY)
+		port = ioport__find_free_port();
+
+	entry = ioport_search(&ioport_tree, port);
+	if (entry) {
+		pr_warning("ioport re-registered: %x", port);
+		rb_int_erase(&ioport_tree, &entry->node);
+	}
+
+	entry = malloc(sizeof(*entry));
+	if (entry == NULL)
+		return -ENOMEM;
+
+	*entry = (struct ioport) {
+		.node	= RB_INT_INIT(port, port + count),
+		.ops	= ops,
+		.priv	= param,
+	};
+
+	r = ioport_insert(&ioport_tree, entry);
+	if (r < 0) {
+		free(entry);
+		br_write_unlock();
+		return r;
+	}
+	br_write_unlock();
+
+	return port;
+}
+
+int ioport__unregister(u16 port)
+{
+	struct ioport *entry;
+	int r;
+
+	br_write_lock();
+
+	r = -ENOENT;
+	entry = ioport_search(&ioport_tree, port);
+	if (!entry)
+		goto done;
+
+	ioport_remove(&ioport_tree, entry);
+
+	free(entry);
+
+	r = 0;
+
+done:
+	br_write_unlock();
+
+	return r;
+}
+
+static void ioport__unregister_all(void)
+{
+	struct ioport *entry;
+	struct rb_node *rb;
+	struct rb_int_node *rb_node;
+
+	rb = rb_first(&ioport_tree);
+	while (rb) {
+		rb_node = rb_int(rb);
+		entry = ioport_node(rb_node);
+		ioport_remove(&ioport_tree, entry);
+		free(entry);
+		rb = rb_first(&ioport_tree);
+	}
+}
+
+static const char *to_direction(int direction)
+{
+	if (direction == KVM_EXIT_IO_IN)
+		return "IN";
+	else
+		return "OUT";
+}
+
+static void ioport_error(u16 port, void *data, int direction, int size, u32 count)
+{
+	fprintf(stderr, "IO error: %s port=%x, size=%d, count=%u\n", to_direction(direction), port, size, count);
+}
+
+bool kvm__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count)
+{
+	struct ioport_operations *ops;
+	bool ret = false;
+	struct ioport *entry;
+	void *ptr = data;
+
+	br_read_lock();
+	entry = ioport_search(&ioport_tree, port);
+	if (!entry)
+		goto error;
+
+	ops	= entry->ops;
+
+	while (count--) {
+		if (direction == KVM_EXIT_IO_IN && ops->io_in)
+				ret = ops->io_in(entry, kvm, port, ptr, size);
+		else if (ops->io_out)
+				ret = ops->io_out(entry, kvm, port, ptr, size);
+
+		ptr += size;
+	}
+
+	br_read_unlock();
+
+	if (!ret)
+		goto error;
+
+	return true;
+error:
+	br_read_unlock();
+
+	if (ioport_debug)
+		ioport_error(port, data, direction, size, count);
+
+	return !ioport_debug;
+}
+
+int ioport__init(struct kvm *kvm)
+{
+	return 0;
+}
+
+int ioport__exit(struct kvm *kvm)
+{
+	ioport__unregister_all();
+	return 0;
+}
diff --git a/tools/kvm/kvm-cmd.c b/tools/kvm/kvm-cmd.c
new file mode 100644
index 0000000..2520b08
--- /dev/null
+++ b/tools/kvm/kvm-cmd.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* user defined header files */
+#include "kvm/builtin-debug.h"
+#include "kvm/builtin-pause.h"
+#include "kvm/builtin-resume.h"
+#include "kvm/builtin-balloon.h"
+#include "kvm/builtin-list.h"
+#include "kvm/builtin-version.h"
+#include "kvm/builtin-setup.h"
+#include "kvm/builtin-stop.h"
+#include "kvm/builtin-stat.h"
+#include "kvm/builtin-help.h"
+#include "kvm/builtin-sandbox.h"
+#include "kvm/kvm-cmd.h"
+#include "kvm/builtin-run.h"
+#include "kvm/util.h"
+
+struct cmd_struct kvm_commands[] = {
+	{ "pause",	kvm_cmd_pause,		kvm_pause_help,		0 },
+	{ "resume",	kvm_cmd_resume,		kvm_resume_help,	0 },
+	{ "debug",	kvm_cmd_debug,		kvm_debug_help,		0 },
+	{ "balloon",	kvm_cmd_balloon,	kvm_balloon_help,	0 },
+	{ "list",	kvm_cmd_list,		kvm_list_help,		0 },
+	{ "version",	kvm_cmd_version,	NULL,			0 },
+	{ "--version",	kvm_cmd_version,	NULL,			0 },
+	{ "stop",	kvm_cmd_stop,		kvm_stop_help,		0 },
+	{ "stat",	kvm_cmd_stat,		kvm_stat_help,		0 },
+	{ "help",	kvm_cmd_help,		NULL,			0 },
+	{ "setup",	kvm_cmd_setup,		kvm_setup_help,		0 },
+	{ "run",	kvm_cmd_run,		kvm_run_help,		0 },
+	{ "sandbox",	kvm_cmd_sandbox,	kvm_run_help,		0 },
+	{ NULL,		NULL,			NULL,			0 },
+};
+
+/*
+ * kvm_get_command: Searches the command in an array of the commands and
+ * returns a pointer to cmd_struct if a match is found.
+ *
+ * Input parameters:
+ * command: Array of possible commands. The last entry in the array must be
+ *          NULL.
+ * cmd: A string command to search in the array
+ *
+ * Return Value:
+ * NULL: If the cmd is not matched with any of the command in the command array
+ * p: Pointer to cmd_struct of the matching command
+ */
+struct cmd_struct *kvm_get_command(struct cmd_struct *command,
+		const char *cmd)
+{
+	struct cmd_struct *p = command;
+
+	while (p->cmd) {
+		if (!strcmp(p->cmd, cmd))
+			return p;
+		p++;
+	}
+	return NULL;
+}
+
+int handle_command(struct cmd_struct *command, int argc, const char **argv)
+{
+	struct cmd_struct *p;
+	const char *prefix = NULL;
+	int ret = 0;
+
+	if (!argv || !*argv) {
+		p = kvm_get_command(command, "help");
+		BUG_ON(!p);
+		return p->fn(argc, argv, prefix);
+	}
+
+	p = kvm_get_command(command, argv[0]);
+	if (!p) {
+		p = kvm_get_command(command, "help");
+		BUG_ON(!p);
+		p->fn(0, NULL, prefix);
+		return EINVAL;
+	}
+
+	ret = p->fn(argc - 1, &argv[1], prefix);
+	if (ret < 0) {
+		if (errno == EPERM)
+			die("Permission error - are you root?");
+	}
+
+	return ret;
+}
diff --git a/tools/kvm/kvm-cpu.c b/tools/kvm/kvm-cpu.c
new file mode 100644
index 0000000..12791dd
--- /dev/null
+++ b/tools/kvm/kvm-cpu.c
@@ -0,0 +1,175 @@
+#include "kvm/kvm-cpu.h"
+
+#include "kvm/symbol.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+extern struct kvm_cpu **kvm_cpus;
+extern __thread struct kvm_cpu *current_kvm_cpu;
+
+void kvm_cpu__enable_singlestep(struct kvm_cpu *vcpu)
+{
+	struct kvm_guest_debug debug = {
+		.control	= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP,
+	};
+
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_GUEST_DEBUG, &debug) < 0)
+		pr_warning("KVM_SET_GUEST_DEBUG failed");
+}
+
+void kvm_cpu__run(struct kvm_cpu *vcpu)
+{
+	int err;
+
+	if (!vcpu->is_running)
+		return;
+
+	err = ioctl(vcpu->vcpu_fd, KVM_RUN, 0);
+	if (err < 0 && (errno != EINTR && errno != EAGAIN))
+		die_perror("KVM_RUN failed");
+}
+
+static void kvm_cpu_signal_handler(int signum)
+{
+	if (signum == SIGKVMEXIT) {
+		if (current_kvm_cpu && current_kvm_cpu->is_running) {
+			current_kvm_cpu->is_running = false;
+			kvm__continue();
+		}
+	} else if (signum == SIGKVMPAUSE) {
+		current_kvm_cpu->paused = 1;
+	}
+}
+
+static void kvm_cpu__handle_coalesced_mmio(struct kvm_cpu *cpu)
+{
+	if (cpu->ring) {
+		while (cpu->ring->first != cpu->ring->last) {
+			struct kvm_coalesced_mmio *m;
+			m = &cpu->ring->coalesced_mmio[cpu->ring->first];
+			kvm_cpu__emulate_mmio(cpu->kvm,
+					      m->phys_addr,
+					      m->data,
+					      m->len,
+					      1);
+			cpu->ring->first = (cpu->ring->first + 1) % KVM_COALESCED_MMIO_MAX;
+		}
+	}
+}
+
+void kvm_cpu__reboot(void)
+{
+	int i;
+
+	/* The kvm_cpus array contains a null pointer in the last location */
+	for (i = 0; ; i++) {
+		if (kvm_cpus[i])
+			pthread_kill(kvm_cpus[i]->thread, SIGKVMEXIT);
+		else
+			break;
+	}
+}
+
+int kvm_cpu__start(struct kvm_cpu *cpu)
+{
+	sigset_t sigset;
+
+	sigemptyset(&sigset);
+	sigaddset(&sigset, SIGALRM);
+
+	pthread_sigmask(SIG_BLOCK, &sigset, NULL);
+
+	signal(SIGKVMEXIT, kvm_cpu_signal_handler);
+	signal(SIGKVMPAUSE, kvm_cpu_signal_handler);
+
+	kvm_cpu__reset_vcpu(cpu);
+
+	if (cpu->kvm->single_step)
+		kvm_cpu__enable_singlestep(cpu);
+
+	while (cpu->is_running) {
+		if (cpu->paused) {
+			kvm__notify_paused();
+			cpu->paused = 0;
+		}
+
+		if (cpu->needs_nmi) {
+			kvm_cpu__arch_nmi(cpu);
+			cpu->needs_nmi = 0;
+		}
+
+		kvm_cpu__run(cpu);
+
+		switch (cpu->kvm_run->exit_reason) {
+		case KVM_EXIT_UNKNOWN:
+			break;
+		case KVM_EXIT_DEBUG:
+			kvm_cpu__show_registers(cpu);
+			kvm_cpu__show_code(cpu);
+			break;
+		case KVM_EXIT_IO: {
+			bool ret;
+
+			ret = kvm_cpu__emulate_io(cpu->kvm,
+						  cpu->kvm_run->io.port,
+						  (u8 *)cpu->kvm_run +
+						  cpu->kvm_run->io.data_offset,
+						  cpu->kvm_run->io.direction,
+						  cpu->kvm_run->io.size,
+						  cpu->kvm_run->io.count);
+
+			if (!ret)
+				goto panic_kvm;
+			break;
+		}
+		case KVM_EXIT_MMIO: {
+			bool ret;
+
+			/*
+			 * If we had MMIO exit, coalesced ring should be processed
+			 * *before* processing the exit itself
+			 */
+			kvm_cpu__handle_coalesced_mmio(cpu);
+
+			ret = kvm_cpu__emulate_mmio(cpu->kvm,
+						    cpu->kvm_run->mmio.phys_addr,
+						    cpu->kvm_run->mmio.data,
+						    cpu->kvm_run->mmio.len,
+						    cpu->kvm_run->mmio.is_write);
+
+			if (!ret)
+				goto panic_kvm;
+			break;
+		}
+		case KVM_EXIT_INTR:
+			if (cpu->is_running)
+				break;
+			goto exit_kvm;
+		case KVM_EXIT_SHUTDOWN:
+			goto exit_kvm;
+		default: {
+			bool ret;
+
+			ret = kvm_cpu__handle_exit(cpu);
+			if (!ret)
+				goto panic_kvm;
+			break;
+		}
+		}
+		kvm_cpu__handle_coalesced_mmio(cpu);
+	}
+
+exit_kvm:
+	return 0;
+
+panic_kvm:
+	return 1;
+}
diff --git a/tools/kvm/kvm-ipc.c b/tools/kvm/kvm-ipc.c
new file mode 100644
index 0000000..70831b8
--- /dev/null
+++ b/tools/kvm/kvm-ipc.c
@@ -0,0 +1,231 @@
+#include "kvm/kvm-ipc.h"
+#include "kvm/rwsem.h"
+#include "kvm/read-write.h"
+#include "kvm/util.h"
+
+#include <sys/epoll.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/eventfd.h>
+
+struct kvm_ipc_head {
+	u32 type;
+	u32 len;
+};
+
+#define KVM_IPC_MAX_MSGS 16
+
+static void (*msgs[KVM_IPC_MAX_MSGS])(int fd, u32 type, u32 len, u8 *msg);
+static DECLARE_RWSEM(msgs_rwlock);
+static int epoll_fd, server_fd, stop_fd;
+static pthread_t thread;
+
+int kvm_ipc__register_handler(u32 type, void (*cb)(int fd, u32 type, u32 len, u8 *msg))
+{
+	if (type >= KVM_IPC_MAX_MSGS)
+		return -ENOSPC;
+
+	down_write(&msgs_rwlock);
+	msgs[type] = cb;
+	up_write(&msgs_rwlock);
+
+	return 0;
+}
+
+int kvm_ipc__send(int fd, u32 type)
+{
+	struct kvm_ipc_head head = {.type = type, .len = 0,};
+
+	if (write_in_full(fd, &head, sizeof(head)) < 0)
+		return -1;
+
+	return 0;
+}
+
+int kvm_ipc__send_msg(int fd, u32 type, u32 len, u8 *msg)
+{
+	struct kvm_ipc_head head = {.type = type, .len = len,};
+
+	if (write_in_full(fd, &head, sizeof(head)) < 0)
+		return -1;
+
+	if (write_in_full(fd, msg, len) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int kvm_ipc__handle(int fd, u32 type, u32 len, u8 *data)
+{
+	void (*cb)(int fd, u32 type, u32 len, u8 *msg);
+
+	if (type >= KVM_IPC_MAX_MSGS)
+		return -ENOSPC;
+
+	down_read(&msgs_rwlock);
+	cb = msgs[type];
+	up_read(&msgs_rwlock);
+
+	if (cb == NULL) {
+		pr_warning("No device handles type %u\n", type);
+		return -ENODEV;
+	}
+
+	cb(fd, type, len, data);
+
+	return 0;
+}
+
+static int kvm_ipc__new_conn(int fd)
+{
+	int client;
+	struct epoll_event ev;
+
+	client = accept(fd, NULL, NULL);
+	if (client < 0)
+		return -1;
+
+	ev.events = EPOLLIN | EPOLLRDHUP;
+	ev.data.fd = client;
+	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client, &ev) < 0) {
+		close(client);
+		return -1;
+	}
+
+	return client;
+}
+
+static void kvm_ipc__close_conn(int fd)
+{
+	epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
+	close(fd);
+}
+
+static int kvm_ipc__receive(int fd)
+{
+	struct kvm_ipc_head head;
+	u8 *msg = NULL;
+	u32 n;
+
+	n = read(fd, &head, sizeof(head));
+	if (n != sizeof(head))
+		goto done;
+
+	msg = malloc(head.len);
+	if (msg == NULL)
+		goto done;
+
+	n = read_in_full(fd, msg, head.len);
+	if (n != head.len)
+		goto done;
+
+	kvm_ipc__handle(fd, head.type, head.len, msg);
+
+	return 0;
+
+done:
+	free(msg);
+	return -1;
+}
+
+static void *kvm_ipc__thread(void *param)
+{
+	struct epoll_event event;
+
+	for (;;) {
+		int nfds;
+
+		nfds = epoll_wait(epoll_fd, &event, 1, -1);
+		if (nfds > 0) {
+			int fd = event.data.fd;
+
+			if (fd == stop_fd && event.events & EPOLLIN) {
+				break;
+			} else if (fd == server_fd) {
+				int client, r;
+
+				client = kvm_ipc__new_conn(fd);
+				/*
+				 * Handle multiple IPC cmd at a time
+				 */
+				do {
+					r = kvm_ipc__receive(client);
+				} while	(r == 0);
+
+			} else if (event.events & (EPOLLERR | EPOLLRDHUP | EPOLLHUP)) {
+				kvm_ipc__close_conn(fd);
+			} else {
+				kvm_ipc__receive(fd);
+			}
+		}
+	}
+
+	return NULL;
+}
+
+int kvm_ipc__start(int sock)
+{
+	int ret;
+	struct epoll_event ev = {0};
+
+	server_fd = sock;
+
+	epoll_fd = epoll_create(KVM_IPC_MAX_MSGS);
+	if (epoll_fd < 0) {
+		ret = epoll_fd;
+		goto err;
+	}
+
+	ev.events = EPOLLIN | EPOLLET;
+	ev.data.fd = sock;
+	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev) < 0) {
+		pr_err("Failed starting IPC thread");
+		ret = -EFAULT;
+		goto err_epoll;
+	}
+
+	stop_fd = eventfd(0, 0);
+	if (stop_fd < 0) {
+		ret = stop_fd;
+		goto err_epoll;
+	}
+
+	ev.events = EPOLLIN | EPOLLET;
+	ev.data.fd = stop_fd;
+	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, stop_fd, &ev) < 0) {
+		pr_err("Failed adding stop event to epoll");
+		ret = -EFAULT;
+		goto err_stop;
+	}
+
+	if (pthread_create(&thread, NULL, kvm_ipc__thread, NULL) != 0) {
+		pr_err("Failed starting IPC thread");
+		ret = -EFAULT;
+		goto err_stop;
+	}
+
+	return 0;
+
+err_stop:
+	close(stop_fd);
+err_epoll:
+	close(epoll_fd);
+err:
+	return ret;
+}
+
+int kvm_ipc__stop(void)
+{
+	u64 val = 1;
+	int ret;
+
+	ret = write(stop_fd, &val, sizeof(val));
+	if (ret < 0)
+		return ret;
+
+	close(server_fd);
+	close(epoll_fd);
+
+	return ret;
+}
diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c
new file mode 100644
index 0000000..64d8b51
--- /dev/null
+++ b/tools/kvm/kvm.c
@@ -0,0 +1,593 @@
+#include "kvm/kvm.h"
+#include "kvm/read-write.h"
+#include "kvm/util.h"
+#include "kvm/strbuf.h"
+#include "kvm/mutex.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/kvm-ipc.h"
+
+#include <linux/kvm.h>
+#include <linux/err.h>
+
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/eventfd.h>
+#include <asm/unistd.h>
+#include <dirent.h>
+
+#define DEFINE_KVM_EXIT_REASON(reason) [reason] = #reason
+
+const char *kvm_exit_reasons[] = {
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_UNKNOWN),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_EXCEPTION),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_IO),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_HYPERCALL),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_DEBUG),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_HLT),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_MMIO),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_IRQ_WINDOW_OPEN),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_SHUTDOWN),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_FAIL_ENTRY),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_INTR),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_SET_TPR),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_TPR_ACCESS),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_S390_SIEIC),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_S390_RESET),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_DCR),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_NMI),
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_INTERNAL_ERROR),
+#ifdef CONFIG_PPC64
+	DEFINE_KVM_EXIT_REASON(KVM_EXIT_PAPR_HCALL),
+#endif
+};
+
+extern struct kvm *kvm;
+extern struct kvm_cpu **kvm_cpus;
+static int pause_event;
+static DEFINE_MUTEX(pause_lock);
+extern struct kvm_ext kvm_req_ext[];
+
+static char kvm_dir[PATH_MAX];
+
+static int set_dir(const char *fmt, va_list args)
+{
+	char tmp[PATH_MAX];
+
+	vsnprintf(tmp, sizeof(tmp), fmt, args);
+
+	mkdir(tmp, 0777);
+
+	if (!realpath(tmp, kvm_dir))
+		return -errno;
+
+	strcat(kvm_dir, "/");
+
+	return 0;
+}
+
+void kvm__set_dir(const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	set_dir(fmt, args);
+	va_end(args);
+}
+
+const char *kvm__get_dir(void)
+{
+	return kvm_dir;
+}
+
+bool kvm__supports_extension(struct kvm *kvm, unsigned int extension)
+{
+	int ret;
+
+	ret = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, extension);
+	if (ret < 0)
+		return false;
+
+	return ret;
+}
+
+static int kvm__check_extensions(struct kvm *kvm)
+{
+	int i;
+
+	for (i = 0; ; i++) {
+		if (!kvm_req_ext[i].name)
+			break;
+		if (!kvm__supports_extension(kvm, kvm_req_ext[i].code)) {
+			pr_err("Unsuppored KVM extension detected: %s",
+				kvm_req_ext[i].name);
+			return -i;
+		}
+	}
+
+	return 0;
+}
+
+static struct kvm *kvm__new(void)
+{
+	struct kvm *kvm = calloc(1, sizeof(*kvm));
+	if (!kvm)
+		return ERR_PTR(-ENOMEM);
+
+	kvm->sys_fd = -1;
+	kvm->vm_fd = -1;
+
+	return kvm;
+}
+
+#define KVM_SOCK_SUFFIX		".sock"
+#define KVM_SOCK_SUFFIX_LEN	((ssize_t)sizeof(KVM_SOCK_SUFFIX) - 1)
+
+static int kvm__create_socket(struct kvm *kvm)
+{
+	char full_name[PATH_MAX];
+	unsigned int s;
+	struct sockaddr_un local;
+	int len, r;
+
+	/* This usually 108 bytes long */
+	BUILD_BUG_ON(sizeof(local.sun_path) < 32);
+
+	if (!kvm->name)
+		return -EINVAL;
+
+	snprintf(full_name, sizeof(full_name), "%s/%s%s",
+		 kvm__get_dir(), kvm->name, KVM_SOCK_SUFFIX);
+	if (access(full_name, F_OK) == 0) {
+		pr_err("Socket file %s already exist", full_name);
+		return -EEXIST;
+	}
+
+	s = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (s < 0)
+		return s;
+	local.sun_family = AF_UNIX;
+	strlcpy(local.sun_path, full_name, sizeof(local.sun_path));
+	len = strlen(local.sun_path) + sizeof(local.sun_family);
+	r = bind(s, (struct sockaddr *)&local, len);
+	if (r < 0)
+		goto fail;
+
+	r = listen(s, 5);
+	if (r < 0)
+		goto fail;
+
+	return s;
+
+fail:
+	close(s);
+	return r;
+}
+
+void kvm__remove_socket(const char *name)
+{
+	char full_name[PATH_MAX];
+
+	snprintf(full_name, sizeof(full_name), "%s/%s%s",
+		 kvm__get_dir(), name, KVM_SOCK_SUFFIX);
+	unlink(full_name);
+}
+
+int kvm__get_sock_by_instance(const char *name)
+{
+	int s, len, r;
+	char sock_file[PATH_MAX];
+	struct sockaddr_un local;
+
+	snprintf(sock_file, sizeof(sock_file), "%s/%s%s",
+		 kvm__get_dir(), name, KVM_SOCK_SUFFIX);
+	s = socket(AF_UNIX, SOCK_STREAM, 0);
+
+	local.sun_family = AF_UNIX;
+	strlcpy(local.sun_path, sock_file, sizeof(local.sun_path));
+	len = strlen(local.sun_path) + sizeof(local.sun_family);
+
+	r = connect(s, &local, len);
+	if (r < 0 && errno == ECONNREFUSED) {
+		/* Tell the user clean ghost socket file */
+		pr_err("\"%s\" could be a ghost socket file, please remove it",
+				sock_file);
+		return r;
+	} else if (r < 0) {
+		return r;
+	}
+
+	return s;
+}
+
+int kvm__enumerate_instances(int (*callback)(const char *name, int fd))
+{
+	int sock;
+	DIR *dir;
+	struct dirent entry, *result;
+	int ret = 0;
+
+	dir = opendir(kvm__get_dir());
+	if (!dir)
+		return -errno;
+
+	for (;;) {
+		readdir_r(dir, &entry, &result);
+		if (result == NULL)
+			break;
+		if (entry.d_type == DT_SOCK) {
+			ssize_t name_len = strlen(entry.d_name);
+			char *p;
+
+			if (name_len <= KVM_SOCK_SUFFIX_LEN)
+				continue;
+
+			p = &entry.d_name[name_len - KVM_SOCK_SUFFIX_LEN];
+			if (memcmp(KVM_SOCK_SUFFIX, p, KVM_SOCK_SUFFIX_LEN))
+				continue;
+
+			*p = 0;
+			sock = kvm__get_sock_by_instance(entry.d_name);
+			if (sock < 0)
+				continue;
+			ret = callback(entry.d_name, sock);
+			close(sock);
+			if (ret < 0)
+				break;
+		}
+	}
+
+	closedir(dir);
+
+	return ret;
+}
+
+int kvm__exit(struct kvm *kvm)
+{
+	kvm__stop_timer(kvm);
+
+	kvm__arch_delete_ram(kvm);
+	kvm_ipc__stop();
+	kvm__remove_socket(kvm->name);
+	free(kvm->name);
+	free(kvm);
+
+	return 0;
+}
+
+/*
+ * Note: KVM_SET_USER_MEMORY_REGION assumes that we don't pass overlapping
+ * memory regions to it. Therefore, be careful if you use this function for
+ * registering memory regions for emulating hardware.
+ */
+int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr)
+{
+	struct kvm_userspace_memory_region mem;
+	int ret;
+
+	mem = (struct kvm_userspace_memory_region) {
+		.slot			= kvm->mem_slots++,
+		.guest_phys_addr	= guest_phys,
+		.memory_size		= size,
+		.userspace_addr		= (unsigned long)userspace_addr,
+	};
+
+	ret = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &mem);
+	if (ret < 0)
+		return -errno;
+
+	return 0;
+}
+
+int kvm__recommended_cpus(struct kvm *kvm)
+{
+	int ret;
+
+	ret = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_NR_VCPUS);
+	if (ret <= 0)
+		/*
+		 * api.txt states that if KVM_CAP_NR_VCPUS does not exist,
+		 * assume 4.
+		 */
+		return 4;
+
+	return ret;
+}
+
+static void kvm__pid(int fd, u32 type, u32 len, u8 *msg)
+{
+	pid_t pid = getpid();
+	int r = 0;
+
+	if (type == KVM_IPC_PID)
+		r = write(fd, &pid, sizeof(pid));
+
+	if (r < 0)
+		pr_warning("Failed sending PID");
+}
+
+/*
+ * The following hack should be removed once 'x86: Raise the hard
+ * VCPU count limit' makes it's way into the mainline.
+ */
+#ifndef KVM_CAP_MAX_VCPUS
+#define KVM_CAP_MAX_VCPUS 66
+#endif
+
+int kvm__max_cpus(struct kvm *kvm)
+{
+	int ret;
+
+	ret = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_MAX_VCPUS);
+	if (ret <= 0)
+		ret = kvm__recommended_cpus(kvm);
+
+	return ret;
+}
+
+struct kvm *kvm__init(const char *kvm_dev, const char *hugetlbfs_path, u64 ram_size, const char *name)
+{
+	struct kvm *kvm;
+	int ret;
+
+	if (!kvm__arch_cpu_supports_vm()) {
+		pr_err("Your CPU does not support hardware virtualization");
+		ret = -ENOSYS;
+		goto err;
+	}
+
+	kvm = kvm__new();
+	if (IS_ERR(kvm))
+		return kvm;
+
+	kvm->sys_fd = open(kvm_dev, O_RDWR);
+	if (kvm->sys_fd < 0) {
+		if (errno == ENOENT)
+			pr_err("'%s' not found. Please make sure your kernel has CONFIG_KVM "
+			       "enabled and that the KVM modules are loaded.", kvm_dev);
+		else if (errno == ENODEV)
+			pr_err("'%s' KVM driver not available.\n  # (If the KVM "
+			       "module is loaded then 'dmesg' may offer further clues "
+			       "about the failure.)", kvm_dev);
+		else
+			pr_err("Could not open %s: ", kvm_dev);
+
+		ret = -errno;
+		goto err_free;
+	}
+
+	ret = ioctl(kvm->sys_fd, KVM_GET_API_VERSION, 0);
+	if (ret != KVM_API_VERSION) {
+		pr_err("KVM_API_VERSION ioctl");
+		ret = -errno;
+		goto err_sys_fd;
+	}
+
+	kvm->vm_fd = ioctl(kvm->sys_fd, KVM_CREATE_VM, 0);
+	if (kvm->vm_fd < 0) {
+		ret = kvm->vm_fd;
+		goto err_sys_fd;
+	}
+
+	kvm->name = strdup(name);
+	if (!kvm->name) {
+		ret = -ENOMEM;
+		goto err_vm_fd;
+	}
+
+	if (kvm__check_extensions(kvm)) {
+		pr_err("A required KVM extention is not supported by OS");
+		ret = -ENOSYS;
+		goto err_vm_fd;
+	}
+
+	kvm__arch_init(kvm, hugetlbfs_path, ram_size);
+
+	ret = kvm_ipc__start(kvm__create_socket(kvm));
+	if (ret < 0) {
+		pr_err("Starting ipc failed.");
+		goto err_vm_fd;
+	}
+
+	ret = kvm_ipc__register_handler(KVM_IPC_PID, kvm__pid);
+	if (ret < 0) {
+		pr_err("Register ipc handler failed.");
+		goto err_ipc;
+	}
+
+	return kvm;
+
+err_ipc:
+	kvm_ipc__stop();
+err_vm_fd:
+	close(kvm->vm_fd);
+err_sys_fd:
+	close(kvm->sys_fd);
+err_free:
+	free(kvm);
+err:
+	return ERR_PTR(ret);
+}
+
+/* RFC 1952 */
+#define GZIP_ID1		0x1f
+#define GZIP_ID2		0x8b
+#define CPIO_MAGIC		"0707"
+/* initrd may be gzipped, or a plain cpio */
+static bool initrd_check(int fd)
+{
+	unsigned char id[4];
+
+	if (read_in_full(fd, id, ARRAY_SIZE(id)) < 0)
+		return false;
+
+	if (lseek(fd, 0, SEEK_SET) < 0)
+		die_perror("lseek");
+
+	return (id[0] == GZIP_ID1 && id[1] == GZIP_ID2) ||
+		!memcmp(id, CPIO_MAGIC, 4);
+}
+
+bool kvm__load_kernel(struct kvm *kvm, const char *kernel_filename,
+		const char *initrd_filename, const char *kernel_cmdline, u16 vidmode)
+{
+	bool ret;
+	int fd_kernel = -1, fd_initrd = -1;
+
+	fd_kernel = open(kernel_filename, O_RDONLY);
+	if (fd_kernel < 0)
+		die("Unable to open kernel %s", kernel_filename);
+
+	if (initrd_filename) {
+		fd_initrd = open(initrd_filename, O_RDONLY);
+		if (fd_initrd < 0)
+			die("Unable to open initrd %s", initrd_filename);
+
+		if (!initrd_check(fd_initrd))
+			die("%s is not an initrd", initrd_filename);
+	}
+
+	ret = load_bzimage(kvm, fd_kernel, fd_initrd, kernel_cmdline, vidmode);
+
+	if (ret)
+		goto found_kernel;
+
+	pr_warning("%s is not a bzImage. Trying to load it as a flat binary...", kernel_filename);
+
+	ret = load_flat_binary(kvm, fd_kernel, fd_initrd, kernel_cmdline);
+
+	if (ret)
+		goto found_kernel;
+
+	if (initrd_filename)
+		close(fd_initrd);
+	close(fd_kernel);
+
+	die("%s is not a valid bzImage or flat binary", kernel_filename);
+
+found_kernel:
+	if (initrd_filename)
+		close(fd_initrd);
+	close(fd_kernel);
+
+	return ret;
+}
+
+#define TIMER_INTERVAL_NS 1000000	/* 1 msec */
+
+/*
+ * This function sets up a timer that's used to inject interrupts from the
+ * userspace hypervisor into the guest at periodical intervals. Please note
+ * that clock interrupt, for example, is not handled here.
+ */
+void kvm__start_timer(struct kvm *kvm)
+{
+	struct itimerspec its;
+	struct sigevent sev;
+
+	memset(&sev, 0, sizeof(struct sigevent));
+	sev.sigev_value.sival_int	= 0;
+	sev.sigev_notify		= SIGEV_THREAD_ID;
+	sev.sigev_signo			= SIGALRM;
+	sev._sigev_un._tid		= syscall(__NR_gettid);
+
+	if (timer_create(CLOCK_REALTIME, &sev, &kvm->timerid) < 0)
+		die("timer_create()");
+
+	its.it_value.tv_sec		= TIMER_INTERVAL_NS / 1000000000;
+	its.it_value.tv_nsec		= TIMER_INTERVAL_NS % 1000000000;
+	its.it_interval.tv_sec		= its.it_value.tv_sec;
+	its.it_interval.tv_nsec		= its.it_value.tv_nsec;
+
+	if (timer_settime(kvm->timerid, 0, &its, NULL) < 0)
+		die("timer_settime()");
+}
+
+void kvm__stop_timer(struct kvm *kvm)
+{
+	if (kvm->timerid)
+		if (timer_delete(kvm->timerid) < 0)
+			die("timer_delete()");
+
+	kvm->timerid = 0;
+}
+
+void kvm__dump_mem(struct kvm *kvm, unsigned long addr, unsigned long size)
+{
+	unsigned char *p;
+	unsigned long n;
+
+	size &= ~7; /* mod 8 */
+	if (!size)
+		return;
+
+	p = guest_flat_to_host(kvm, addr);
+
+	for (n = 0; n < size; n += 8) {
+		if (!host_ptr_in_ram(kvm, p + n))
+			break;
+
+		printf("  0x%08lx: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
+			addr + n, p[n + 0], p[n + 1], p[n + 2], p[n + 3],
+				  p[n + 4], p[n + 5], p[n + 6], p[n + 7]);
+	}
+}
+
+void kvm__pause(void)
+{
+	int i, paused_vcpus = 0;
+
+	/* Check if the guest is running */
+	if (!kvm_cpus[0] || kvm_cpus[0]->thread == 0)
+		return;
+
+	mutex_lock(&pause_lock);
+
+	pause_event = eventfd(0, 0);
+	if (pause_event < 0)
+		die("Failed creating pause notification event");
+	for (i = 0; i < kvm->nrcpus; i++)
+		pthread_kill(kvm_cpus[i]->thread, SIGKVMPAUSE);
+
+	while (paused_vcpus < kvm->nrcpus) {
+		u64 cur_read;
+
+		if (read(pause_event, &cur_read, sizeof(cur_read)) < 0)
+			die("Failed reading pause event");
+		paused_vcpus += cur_read;
+	}
+	close(pause_event);
+}
+
+void kvm__continue(void)
+{
+	/* Check if the guest is running */
+	if (!kvm_cpus[0] || kvm_cpus[0]->thread == 0)
+		return;
+
+	mutex_unlock(&pause_lock);
+}
+
+void kvm__notify_paused(void)
+{
+	u64 p = 1;
+
+	if (write(pause_event, &p, sizeof(p)) < 0)
+		die("Failed notifying of paused VCPU.");
+
+	mutex_lock(&pause_lock);
+	mutex_unlock(&pause_lock);
+}
diff --git a/tools/kvm/main.c b/tools/kvm/main.c
new file mode 100644
index 0000000..05bc82c
--- /dev/null
+++ b/tools/kvm/main.c
@@ -0,0 +1,19 @@
+#include "kvm/kvm.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/* user defined header files */
+#include <kvm/kvm-cmd.h>
+
+static int handle_kvm_command(int argc, char **argv)
+{
+	return handle_command(kvm_commands, argc, (const char **) &argv[0]);
+}
+
+int main(int argc, char *argv[])
+{
+	kvm__set_dir("%s/%s", HOME_DIR, KVM_PID_FILE_PATH);
+
+	return handle_kvm_command(argc - 1, &argv[1]);
+}
diff --git a/tools/kvm/mmio.c b/tools/kvm/mmio.c
new file mode 100644
index 0000000..dd28ef33
--- /dev/null
+++ b/tools/kvm/mmio.c
@@ -0,0 +1,140 @@
+#include "kvm/kvm.h"
+#include "kvm/rbtree-interval.h"
+#include "kvm/brlock.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/ioctl.h>
+#include <linux/kvm.h>
+#include <linux/types.h>
+#include <linux/rbtree.h>
+#include <linux/err.h>
+#include <errno.h>
+
+#define mmio_node(n) rb_entry(n, struct mmio_mapping, node)
+
+struct mmio_mapping {
+	struct rb_int_node	node;
+	void			(*mmio_fn)(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr);
+	void			*ptr;
+};
+
+static struct rb_root mmio_tree = RB_ROOT;
+bool mmio_debug = false;
+
+static struct mmio_mapping *mmio_search(struct rb_root *root, u64 addr, u64 len)
+{
+	struct rb_int_node *node;
+
+	node = rb_int_search_range(root, addr, addr + len);
+	if (node == NULL)
+		return NULL;
+
+	return mmio_node(node);
+}
+
+/* Find lowest match, Check for overlap */
+static struct mmio_mapping *mmio_search_single(struct rb_root *root, u64 addr)
+{
+	struct rb_int_node *node;
+
+	node = rb_int_search_single(root, addr);
+	if (node == NULL)
+		return NULL;
+
+	return mmio_node(node);
+}
+
+static int mmio_insert(struct rb_root *root, struct mmio_mapping *data)
+{
+	return rb_int_insert(root, &data->node);
+}
+
+static const char *to_direction(u8 is_write)
+{
+	if (is_write)
+		return "write";
+
+	return "read";
+}
+
+int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
+			void (*mmio_fn)(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr),
+			void *ptr)
+{
+	struct mmio_mapping *mmio;
+	struct kvm_coalesced_mmio_zone zone;
+	int ret;
+
+	mmio = malloc(sizeof(*mmio));
+	if (mmio == NULL)
+		return -ENOMEM;
+
+	*mmio = (struct mmio_mapping) {
+		.node = RB_INT_INIT(phys_addr, phys_addr + phys_addr_len),
+		.mmio_fn = mmio_fn,
+		.ptr	= ptr,
+	};
+
+	if (coalesce) {
+		zone = (struct kvm_coalesced_mmio_zone) {
+			.addr	= phys_addr,
+			.size	= phys_addr_len,
+		};
+		ret = ioctl(kvm->vm_fd, KVM_REGISTER_COALESCED_MMIO, &zone);
+		if (ret < 0) {
+			free(mmio);
+			return -errno;
+		}
+	}
+	br_write_lock();
+	ret = mmio_insert(&mmio_tree, mmio);
+	br_write_unlock();
+
+	return ret;
+}
+
+bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
+{
+	struct mmio_mapping *mmio;
+	struct kvm_coalesced_mmio_zone zone;
+
+	br_write_lock();
+	mmio = mmio_search_single(&mmio_tree, phys_addr);
+	if (mmio == NULL) {
+		br_write_unlock();
+		return false;
+	}
+
+	zone = (struct kvm_coalesced_mmio_zone) {
+		.addr	= phys_addr,
+		.size	= 1,
+	};
+	ioctl(kvm->vm_fd, KVM_UNREGISTER_COALESCED_MMIO, &zone);
+
+	rb_int_erase(&mmio_tree, &mmio->node);
+	br_write_unlock();
+
+	free(mmio);
+	return true;
+}
+
+bool kvm__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write)
+{
+	struct mmio_mapping *mmio;
+
+	br_read_lock();
+	mmio = mmio_search(&mmio_tree, phys_addr, len);
+
+	if (mmio)
+		mmio->mmio_fn(phys_addr, data, len, is_write, mmio->ptr);
+	else {
+		if (mmio_debug)
+			fprintf(stderr, "Warning: Ignoring MMIO %s at %016llx (length %u)\n",
+				to_direction(is_write), phys_addr, len);
+	}
+	br_read_unlock();
+
+	return true;
+}
diff --git a/tools/kvm/net/uip/arp.c b/tools/kvm/net/uip/arp.c
new file mode 100644
index 0000000..98423da
--- /dev/null
+++ b/tools/kvm/net/uip/arp.c
@@ -0,0 +1,30 @@
+#include "kvm/uip.h"
+
+int uip_tx_do_arp(struct uip_tx_arg *arg)
+{
+	struct uip_arp *arp, *arp2;
+	struct uip_info *info;
+	struct uip_buf *buf;
+
+	info = arg->info;
+	buf = uip_buf_clone(arg);
+
+	arp	 = (struct uip_arp *)(arg->eth);
+	arp2	 = (struct uip_arp *)(buf->eth);
+
+	/*
+	 * ARP replay code: 2
+	 */
+	arp2->op   = htons(0x2);
+	arp2->dmac = arp->smac;
+	arp2->dip  = arp->sip;
+
+	if (arp->dip == htonl(info->host_ip)) {
+		arp2->smac = info->host_mac;
+		arp2->sip = htonl(info->host_ip);
+
+		uip_buf_set_used(info, buf);
+	}
+
+	return 0;
+}
diff --git a/tools/kvm/net/uip/buf.c b/tools/kvm/net/uip/buf.c
new file mode 100644
index 0000000..5e564a9
--- /dev/null
+++ b/tools/kvm/net/uip/buf.c
@@ -0,0 +1,114 @@
+#include "kvm/uip.h"
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+struct uip_buf *uip_buf_get_used(struct uip_info *info)
+{
+	struct uip_buf *buf;
+	bool found = false;
+
+	mutex_lock(&info->buf_lock);
+
+	while (!(info->buf_used_nr > 0))
+		pthread_cond_wait(&info->buf_used_cond, &info->buf_lock);
+
+	list_for_each_entry(buf, &info->buf_head, list) {
+		if (buf->status == UIP_BUF_STATUS_USED) {
+			/*
+			 * Set status to INUSE immediately to prevent
+			 * someone from using this buf until we free it
+			 */
+			buf->status = UIP_BUF_STATUS_INUSE;
+			info->buf_used_nr--;
+			found = true;
+			break;
+		}
+	}
+
+	mutex_unlock(&info->buf_lock);
+
+	return found ? buf : NULL;
+}
+
+struct uip_buf *uip_buf_get_free(struct uip_info *info)
+{
+	struct uip_buf *buf;
+	bool found = false;
+
+	mutex_lock(&info->buf_lock);
+
+	while (!(info->buf_free_nr > 0))
+		pthread_cond_wait(&info->buf_free_cond, &info->buf_lock);
+
+	list_for_each_entry(buf, &info->buf_head, list) {
+		if (buf->status == UIP_BUF_STATUS_FREE) {
+			/*
+			 * Set status to INUSE immediately to prevent
+			 * someone from using this buf until we free it
+			 */
+			buf->status = UIP_BUF_STATUS_INUSE;
+			info->buf_free_nr--;
+			found = true;
+			break;
+		}
+	}
+
+	mutex_unlock(&info->buf_lock);
+
+	return found ? buf : NULL;
+}
+
+struct uip_buf *uip_buf_set_used(struct uip_info *info, struct uip_buf *buf)
+{
+	mutex_lock(&info->buf_lock);
+
+	buf->status = UIP_BUF_STATUS_USED;
+	info->buf_used_nr++;
+	pthread_cond_signal(&info->buf_used_cond);
+
+	mutex_unlock(&info->buf_lock);
+
+	return buf;
+}
+
+struct uip_buf *uip_buf_set_free(struct uip_info *info, struct uip_buf *buf)
+{
+	mutex_lock(&info->buf_lock);
+
+	buf->status = UIP_BUF_STATUS_FREE;
+	info->buf_free_nr++;
+	pthread_cond_signal(&info->buf_free_cond);
+
+	mutex_unlock(&info->buf_lock);
+
+	return buf;
+}
+
+struct uip_buf *uip_buf_clone(struct uip_tx_arg *arg)
+{
+	struct uip_buf *buf;
+	struct uip_eth *eth2;
+	struct uip_info *info;
+
+	info = arg->info;
+
+	/*
+	 * Get buffer from device to guest
+	 */
+	buf = uip_buf_get_free(info);
+
+	/*
+	 * Clone buffer
+	 */
+	memcpy(buf->vnet, arg->vnet, arg->vnet_len);
+	memcpy(buf->eth, arg->eth, arg->eth_len);
+	buf->vnet_len	= arg->vnet_len;
+	buf->eth_len	= arg->eth_len;
+
+	eth2		= (struct uip_eth *)buf->eth;
+	eth2->src	= info->host_mac;
+	eth2->dst	= arg->eth->src;
+
+	return buf;
+}
diff --git a/tools/kvm/net/uip/core.c b/tools/kvm/net/uip/core.c
new file mode 100644
index 0000000..2e7603c
--- /dev/null
+++ b/tools/kvm/net/uip/core.c
@@ -0,0 +1,190 @@
+#include "kvm/mutex.h"
+#include "kvm/uip.h"
+
+#include <linux/virtio_net.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+int uip_tx(struct iovec *iov, u16 out, struct uip_info *info)
+{
+	struct virtio_net_hdr *vnet;
+	struct uip_tx_arg arg;
+	int eth_len, vnet_len;
+	struct uip_eth *eth;
+	u8 *buf = NULL;
+	u16 proto;
+	int i;
+
+	/*
+	 * Buffer from guest to device
+	 */
+	vnet_len = iov[0].iov_len;
+	vnet	 = iov[0].iov_base;
+
+	eth_len	 = iov[1].iov_len;
+	eth	 = iov[1].iov_base;
+
+	/*
+	 * In case, ethernet frame is in more than one iov entry.
+	 * Copy iov buffer into one linear buffer.
+	 */
+	if (out > 2) {
+		eth_len = 0;
+		for (i = 1; i < out; i++)
+			eth_len += iov[i].iov_len;
+
+		buf = malloc(eth_len);
+		if (!buf)
+			return -1;
+
+		eth = (struct uip_eth *)buf;
+		for (i = 1; i < out; i++) {
+			memcpy(buf, iov[i].iov_base, iov[i].iov_len);
+			buf += iov[i].iov_len;
+		}
+	}
+
+	memset(&arg, 0, sizeof(arg));
+
+	arg.vnet_len = vnet_len;
+	arg.eth_len = eth_len;
+	arg.info = info;
+	arg.vnet = vnet;
+	arg.eth = eth;
+
+	/*
+	 * Check package type
+	 */
+	proto = ntohs(eth->type);
+
+	switch (proto) {
+	case UIP_ETH_P_ARP:
+		uip_tx_do_arp(&arg);
+		break;
+	case UIP_ETH_P_IP:
+		uip_tx_do_ipv4(&arg);
+		break;
+	default:
+		break;
+	}
+
+	if (out > 2 && buf)
+		free(eth);
+
+	return vnet_len + eth_len;
+}
+
+int uip_rx(struct iovec *iov, u16 in, struct uip_info *info)
+{
+	struct virtio_net_hdr *vnet;
+	struct uip_eth *eth;
+	struct uip_buf *buf;
+	int vnet_len;
+	int eth_len;
+	char *p;
+	int len;
+	int cnt;
+	int i;
+
+	/*
+	 * Sleep until there is a buffer for guest
+	 */
+	buf = uip_buf_get_used(info);
+
+	/*
+	 * Fill device to guest buffer, vnet hdr fisrt
+	 */
+	vnet_len = iov[0].iov_len;
+	vnet = iov[0].iov_base;
+	if (buf->vnet_len > vnet_len) {
+		len = -1;
+		goto out;
+	}
+	memcpy(vnet, buf->vnet, buf->vnet_len);
+
+	/*
+	 * Then, the real eth data
+	 * Note: Be sure buf->eth_len is not bigger than the buffer len that guest provides
+	 */
+	cnt = buf->eth_len;
+	p = buf->eth;
+	for (i = 1; i < in; i++) {
+		eth_len = iov[i].iov_len;
+		eth = iov[i].iov_base;
+		if (cnt > eth_len) {
+			memcpy(eth, p, eth_len);
+			cnt -= eth_len;
+			p += eth_len;
+		} else {
+			memcpy(eth, p, cnt);
+			cnt -= cnt;
+			break;
+		}
+	}
+
+	if (cnt) {
+		pr_warning("uip_rx error");
+		len = -1;
+		goto out;
+	}
+
+	len = buf->vnet_len + buf->eth_len;
+
+out:
+	uip_buf_set_free(info, buf);
+	return len;
+}
+
+int uip_init(struct uip_info *info)
+{
+	struct list_head *udp_socket_head;
+	struct list_head *tcp_socket_head;
+	struct list_head *buf_head;
+	struct uip_buf *buf;
+	int buf_nr;
+	int i;
+
+	udp_socket_head	= &info->udp_socket_head;
+	tcp_socket_head	= &info->tcp_socket_head;
+	buf_head	= &info->buf_head;
+	buf_nr		= info->buf_nr;
+
+	INIT_LIST_HEAD(udp_socket_head);
+	INIT_LIST_HEAD(tcp_socket_head);
+	INIT_LIST_HEAD(buf_head);
+
+	pthread_mutex_init(&info->udp_socket_lock, NULL);
+	pthread_mutex_init(&info->tcp_socket_lock, NULL);
+	pthread_mutex_init(&info->buf_lock, NULL);
+
+	pthread_cond_init(&info->buf_used_cond, NULL);
+	pthread_cond_init(&info->buf_free_cond, NULL);
+
+
+	for (i = 0; i < buf_nr; i++) {
+		buf = malloc(sizeof(*buf));
+		memset(buf, 0, sizeof(*buf));
+
+		buf->status	= UIP_BUF_STATUS_FREE;
+		buf->info	= info;
+		buf->id		= i;
+		list_add_tail(&buf->list, buf_head);
+	}
+
+	list_for_each_entry(buf, buf_head, list) {
+		buf->vnet	= malloc(sizeof(struct virtio_net_hdr));
+		buf->vnet_len	= sizeof(struct virtio_net_hdr);
+		buf->eth	= malloc(1024*64 + sizeof(struct uip_pseudo_hdr));
+		buf->eth_len	= 1024*64 + sizeof(struct uip_pseudo_hdr);
+
+		memset(buf->vnet, 0, buf->vnet_len);
+		memset(buf->eth, 0, buf->eth_len);
+	}
+
+	info->buf_free_nr = buf_nr;
+	info->buf_used_nr = 0;
+
+	uip_dhcp_get_dns(info);
+
+	return 0;
+}
diff --git a/tools/kvm/net/uip/csum.c b/tools/kvm/net/uip/csum.c
new file mode 100644
index 0000000..7ca8bad
--- /dev/null
+++ b/tools/kvm/net/uip/csum.c
@@ -0,0 +1,92 @@
+#include "kvm/uip.h"
+
+static u16 uip_csum(u16 csum, u8 *addr, u16 count)
+{
+	long sum = csum;
+
+	while (count > 1) {
+		sum	+= *(u16 *)addr;
+		addr	+= 2;
+		count	-= 2;
+	}
+
+	if (count > 0)
+		sum += *(unsigned char *)addr;
+
+	while (sum>>16)
+		sum = (sum & 0xffff) + (sum >> 16);
+
+	return ~sum;
+}
+
+u16 uip_csum_ip(struct uip_ip *ip)
+{
+	return uip_csum(0, &ip->vhl, uip_ip_hdrlen(ip));
+}
+
+u16 uip_csum_icmp(struct uip_icmp *icmp)
+{
+	struct uip_ip *ip;
+
+	ip = &icmp->ip;
+	return icmp->csum = uip_csum(0, &icmp->type, htons(ip->len) - uip_ip_hdrlen(ip) - 8); /* icmp header len = 8 */
+}
+
+u16 uip_csum_udp(struct uip_udp *udp)
+{
+	struct uip_pseudo_hdr hdr;
+	struct uip_ip *ip;
+	int udp_len;
+	u8 *pad;
+
+	ip	  = &udp->ip;
+
+	hdr.sip   = ip->sip;
+	hdr.dip	  = ip->dip;
+	hdr.zero  = 0;
+	hdr.proto = ip->proto;
+	hdr.len   = udp->len;
+
+	udp_len	  = uip_udp_len(udp);
+
+	if (udp_len % 2) {
+		pad = (u8 *)&udp->sport + udp_len;
+		*pad = 0;
+		memcpy((u8 *)&udp->sport + udp_len + 1, &hdr, sizeof(hdr));
+		return uip_csum(0, (u8 *)&udp->sport, udp_len + 1 + sizeof(hdr));
+	} else {
+		memcpy((u8 *)&udp->sport + udp_len, &hdr, sizeof(hdr));
+		return uip_csum(0, (u8 *)&udp->sport, udp_len + sizeof(hdr));
+	}
+
+}
+
+u16 uip_csum_tcp(struct uip_tcp *tcp)
+{
+	struct uip_pseudo_hdr hdr;
+	struct uip_ip *ip;
+	u16 tcp_len;
+	u8 *pad;
+
+	ip	  = &tcp->ip;
+	tcp_len   = ntohs(ip->len) - uip_ip_hdrlen(ip);
+
+	hdr.sip   = ip->sip;
+	hdr.dip	  = ip->dip;
+	hdr.zero  = 0;
+	hdr.proto = ip->proto;
+	hdr.len   = htons(tcp_len);
+
+	if (tcp_len > UIP_MAX_TCP_PAYLOAD + 20)
+		pr_warning("tcp_len(%d) is too large", tcp_len);
+
+	if (tcp_len % 2) {
+		pad = (u8 *)&tcp->sport + tcp_len;
+		*pad = 0;
+		memcpy((u8 *)&tcp->sport + tcp_len + 1, &hdr, sizeof(hdr));
+		return uip_csum(0, (u8 *)&tcp->sport, tcp_len + 1 + sizeof(hdr));
+	} else {
+		memcpy((u8 *)&tcp->sport + tcp_len, &hdr, sizeof(hdr));
+		return uip_csum(0, (u8 *)&tcp->sport, tcp_len + sizeof(hdr));
+	}
+}
diff --git a/tools/kvm/net/uip/dhcp.c b/tools/kvm/net/uip/dhcp.c
new file mode 100644
index 0000000..e91a7c7
--- /dev/null
+++ b/tools/kvm/net/uip/dhcp.c
@@ -0,0 +1,203 @@
+#include "kvm/uip.h"
+
+#include <arpa/inet.h>
+
+#define EMPTY_ADDR "0.0.0.0"
+
+static inline bool uip_dhcp_is_discovery(struct uip_dhcp *dhcp)
+{
+	return (dhcp->option[2] == UIP_DHCP_DISCOVER &&
+		dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
+		dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
+}
+
+static inline bool uip_dhcp_is_request(struct uip_dhcp *dhcp)
+{
+	return (dhcp->option[2] == UIP_DHCP_REQUEST &&
+		dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
+		dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
+}
+
+bool uip_udp_is_dhcp(struct uip_udp *udp)
+{
+	struct uip_dhcp *dhcp;
+
+	if (ntohs(udp->sport) != UIP_DHCP_PORT_CLIENT ||
+	    ntohs(udp->dport) != UIP_DHCP_PORT_SERVER)
+		return false;
+
+	dhcp = (struct uip_dhcp *)udp;
+
+	if (ntohl(dhcp->magic_cookie) != UIP_DHCP_MAGIC_COOKIE)
+		return false;
+
+	return true;
+}
+
+int uip_dhcp_get_dns(struct uip_info *info)
+{
+	char key[256], val[256];
+	struct in_addr addr;
+	int ret = -1;
+	int n = 0;
+	FILE *fp;
+	u32 ip;
+
+	fp = fopen("/etc/resolv.conf", "r");
+	if (!fp)
+		goto out;
+
+	while (!feof(fp)) {
+		if (fscanf(fp, "%s %s\n", key, val) != 2)
+			continue;
+		if (strncmp("domain", key, 6) == 0)
+			info->domain_name = strndup(val, UIP_DHCP_MAX_DOMAIN_NAME_LEN);
+		else if (strncmp("nameserver", key, 10) == 0) {
+			if (!inet_aton(val, &addr))
+				continue;
+			ip = ntohl(addr.s_addr);
+			if (n < UIP_DHCP_MAX_DNS_SERVER_NR)
+				info->dns_ip[n++] = ip;
+			ret = 0;
+		}
+	}
+
+out:
+	fclose(fp);
+	return ret;
+}
+
+static int uip_dhcp_fill_option_name_and_server(struct uip_info *info, u8 *opt, int i)
+{
+	u8 domain_name_len;
+	u32 *addr;
+	int n;
+
+	if (info->domain_name) {
+		domain_name_len	= strlen(info->domain_name);
+		opt[i++]	= UIP_DHCP_TAG_DOMAIN_NAME;
+		opt[i++]	= domain_name_len;
+		memcpy(&opt[i], info->domain_name, domain_name_len);
+		i		+= domain_name_len;
+	}
+
+	for (n = 0; n < UIP_DHCP_MAX_DNS_SERVER_NR; n++) {
+		if (info->dns_ip[n] == 0)
+			continue;
+		opt[i++]	= UIP_DHCP_TAG_DNS_SERVER;
+		opt[i++]	= UIP_DHCP_TAG_DNS_SERVER_LEN;
+		addr		= (u32 *)&opt[i];
+		*addr		= htonl(info->dns_ip[n]);
+		i		+= UIP_DHCP_TAG_DNS_SERVER_LEN;
+	}
+
+	return i;
+}
+static int uip_dhcp_fill_option(struct uip_info *info, struct uip_dhcp *dhcp, int reply_msg_type)
+{
+	int i = 0;
+	u32 *addr;
+	u8 *opt;
+
+	opt		= dhcp->option;
+
+	opt[i++]	= UIP_DHCP_TAG_MSG_TYPE;
+	opt[i++]	= UIP_DHCP_TAG_MSG_TYPE_LEN;
+	opt[i++]	= reply_msg_type;
+
+	opt[i++]	= UIP_DHCP_TAG_SERVER_ID;
+	opt[i++]	= UIP_DHCP_TAG_SERVER_ID_LEN;
+	addr		= (u32 *)&opt[i];
+	*addr		= htonl(info->host_ip);
+	i		+= UIP_DHCP_TAG_SERVER_ID_LEN;
+
+	opt[i++]	= UIP_DHCP_TAG_LEASE_TIME;
+	opt[i++]	= UIP_DHCP_TAG_LEASE_TIME_LEN;
+	addr		= (u32 *)&opt[i];
+	*addr		= htonl(UIP_DHCP_LEASE_TIME);
+	i		+= UIP_DHCP_TAG_LEASE_TIME_LEN;
+
+	opt[i++]	= UIP_DHCP_TAG_SUBMASK;
+	opt[i++]	= UIP_DHCP_TAG_SUBMASK_LEN;
+	addr		= (u32 *)&opt[i];
+	*addr		= htonl(info->guest_netmask);
+	i		+= UIP_DHCP_TAG_SUBMASK_LEN;
+
+	opt[i++]	= UIP_DHCP_TAG_ROUTER;
+	opt[i++]	= UIP_DHCP_TAG_ROUTER_LEN;
+	addr		= (u32 *)&opt[i];
+	*addr		= htonl(info->host_ip);
+	i		+= UIP_DHCP_TAG_ROUTER_LEN;
+
+	opt[i++]	= UIP_DHCP_TAG_ROOT;
+	opt[i++]	= strlen(EMPTY_ADDR);
+	addr		= (u32 *)&opt[i];
+	strncpy((void *) addr, EMPTY_ADDR, strlen(EMPTY_ADDR));
+	i		+= strlen(EMPTY_ADDR);
+
+	i 		= uip_dhcp_fill_option_name_and_server(info, opt, i);
+
+	opt[i++]	= UIP_DHCP_TAG_END;
+
+	return 0;
+}
+
+static int uip_dhcp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 reply_msg_type)
+{
+	struct uip_dhcp *dhcp;
+
+	dhcp		= (struct uip_dhcp *)buf->eth;
+
+	dhcp->msg_type	= 2;
+	dhcp->client_ip	= 0;
+	dhcp->your_ip	= htonl(info->guest_ip);
+	dhcp->server_ip	= htonl(info->host_ip);
+	dhcp->agent_ip	= 0;
+
+	uip_dhcp_fill_option(info, dhcp, reply_msg_type);
+
+	sk->sip		= htonl(info->guest_ip);
+	sk->dip		= htonl(info->host_ip);
+	sk->sport	= htons(UIP_DHCP_PORT_CLIENT);
+	sk->dport	= htons(UIP_DHCP_PORT_SERVER);
+
+	return 0;
+}
+
+int uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg *arg)
+{
+	struct uip_udp_socket sk;
+	struct uip_dhcp *dhcp;
+	struct uip_info *info;
+	struct uip_buf *buf;
+	u8 reply_msg_type;
+
+	dhcp = (struct uip_dhcp *)arg->eth;
+
+	if (uip_dhcp_is_discovery(dhcp))
+		reply_msg_type = UIP_DHCP_OFFER;
+	else if (uip_dhcp_is_request(dhcp))
+		reply_msg_type = UIP_DHCP_ACK;
+	else
+		return -1;
+
+	buf = uip_buf_clone(arg);
+	info = arg->info;
+
+	/*
+	 * Cook DHCP pkg
+	 */
+	uip_dhcp_make_pkg(info, &sk, buf, reply_msg_type);
+
+	/*
+	 * Cook UDP pkg
+	 */
+	uip_udp_make_pkg(info, &sk, buf, NULL, UIP_DHCP_MAX_PAYLOAD_LEN);
+
+	/*
+	 * Send data received from socket to guest
+	 */
+	uip_buf_set_used(info, buf);
+
+	return 0;
+}
diff --git a/tools/kvm/net/uip/icmp.c b/tools/kvm/net/uip/icmp.c
new file mode 100644
index 0000000..233297c
--- /dev/null
+++ b/tools/kvm/net/uip/icmp.c
@@ -0,0 +1,29 @@
+#include "kvm/uip.h"
+
+int uip_tx_do_ipv4_icmp(struct uip_tx_arg *arg)
+{
+	struct uip_ip *ip, *ip2;
+	struct uip_icmp *icmp2;
+	struct uip_buf *buf;
+
+	buf		= uip_buf_clone(arg);
+
+	icmp2		= (struct uip_icmp *)(buf->eth);
+	ip2		= (struct uip_ip *)(buf->eth);
+	ip		= (struct uip_ip *)(arg->eth);
+
+	ip2->sip	= ip->dip;
+	ip2->dip	= ip->sip;
+	ip2->csum	= 0;
+	/*
+	 * ICMP reply: 0
+	 */
+	icmp2->type	= 0;
+	icmp2->csum	= 0;
+	ip2->csum	= uip_csum_ip(ip2);
+	icmp2->csum	= uip_csum_icmp(icmp2);
+
+	uip_buf_set_used(arg->info, buf);
+
+	return 0;
+}
diff --git a/tools/kvm/net/uip/ipv4.c b/tools/kvm/net/uip/ipv4.c
new file mode 100644
index 0000000..58373fd
--- /dev/null
+++ b/tools/kvm/net/uip/ipv4.c
@@ -0,0 +1,29 @@
+#include "kvm/uip.h"
+
+int uip_tx_do_ipv4(struct uip_tx_arg *arg)
+{
+	struct uip_ip *ip;
+
+	ip = (struct uip_ip *)(arg->eth);
+
+	if (uip_ip_hdrlen(ip) != 20) {
+		pr_warning("IP header length is not 20 bytes");
+		return -1;
+	}
+
+	switch (ip->proto) {
+	case UIP_IP_P_ICMP:
+		uip_tx_do_ipv4_icmp(arg);
+		break;
+	case UIP_IP_P_TCP:
+		uip_tx_do_ipv4_tcp(arg);
+		break;
+	case UIP_IP_P_UDP:
+		uip_tx_do_ipv4_udp(arg);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
diff --git a/tools/kvm/net/uip/tcp.c b/tools/kvm/net/uip/tcp.c
new file mode 100644
index 0000000..586a45c
--- /dev/null
+++ b/tools/kvm/net/uip/tcp.c
@@ -0,0 +1,317 @@
+#include "kvm/uip.h"
+
+#include <linux/virtio_net.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+static int uip_tcp_socket_close(struct uip_tcp_socket *sk, int how)
+{
+	shutdown(sk->fd, how);
+
+	if (sk->write_done && sk->read_done) {
+		shutdown(sk->fd, SHUT_RDWR);
+		close(sk->fd);
+
+		mutex_lock(sk->lock);
+		list_del(&sk->list);
+		mutex_unlock(sk->lock);
+
+		free(sk);
+	}
+
+	return 0;
+}
+
+static struct uip_tcp_socket *uip_tcp_socket_find(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport)
+{
+	struct list_head *sk_head;
+	pthread_mutex_t *sk_lock;
+	struct uip_tcp_socket *sk;
+
+	sk_head = &arg->info->tcp_socket_head;
+	sk_lock = &arg->info->tcp_socket_lock;
+
+	mutex_lock(sk_lock);
+	list_for_each_entry(sk, sk_head, list) {
+		if (sk->sip == sip && sk->dip == dip && sk->sport == sport && sk->dport == dport) {
+			mutex_unlock(sk_lock);
+			return sk;
+		}
+	}
+	mutex_unlock(sk_lock);
+
+	return NULL;
+}
+
+static struct uip_tcp_socket *uip_tcp_socket_alloc(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport)
+{
+	struct list_head *sk_head;
+	struct uip_tcp_socket *sk;
+	pthread_mutex_t *sk_lock;
+	struct uip_tcp *tcp;
+	struct uip_ip *ip;
+	int ret;
+
+	tcp = (struct uip_tcp *)arg->eth;
+	ip = (struct uip_ip *)arg->eth;
+
+	sk_head = &arg->info->tcp_socket_head;
+	sk_lock = &arg->info->tcp_socket_lock;
+
+	sk = malloc(sizeof(*sk));
+	memset(sk, 0, sizeof(*sk));
+
+	sk->lock			= sk_lock;
+	sk->info			= arg->info;
+
+	sk->fd				= socket(AF_INET, SOCK_STREAM, 0);
+	sk->addr.sin_family		= AF_INET;
+	sk->addr.sin_addr.s_addr	= dip;
+	sk->addr.sin_port		= dport;
+
+	ret = connect(sk->fd, (struct sockaddr *)&sk->addr, sizeof(sk->addr));
+	if (ret) {
+		free(sk);
+		return NULL;
+	}
+
+	sk->sip		= ip->sip;
+	sk->dip		= ip->dip;
+	sk->sport	= tcp->sport;
+	sk->dport	= tcp->dport;
+
+	mutex_lock(sk_lock);
+	list_add_tail(&sk->list, sk_head);
+	mutex_unlock(sk_lock);
+
+	return sk;
+}
+
+static int uip_tcp_payload_send(struct uip_tcp_socket *sk, u8 flag, u16 payload_len)
+{
+	struct uip_info *info;
+	struct uip_eth *eth2;
+	struct uip_tcp *tcp2;
+	struct uip_buf *buf;
+	struct uip_ip *ip2;
+
+	info		= sk->info;
+
+	/*
+	 * Get free buffer to send data to guest
+	 */
+	buf		= uip_buf_get_free(info);
+
+	/*
+	 * Cook a ethernet frame
+	 */
+	tcp2		= (struct uip_tcp *)buf->eth;
+	eth2		= (struct uip_eth *)buf->eth;
+	ip2		= (struct uip_ip *)buf->eth;
+
+	eth2->src	= info->host_mac;
+	eth2->dst	= info->guest_mac;
+	eth2->type	= htons(UIP_ETH_P_IP);
+
+	ip2->vhl	= UIP_IP_VER_4 | UIP_IP_HDR_LEN;
+	ip2->tos	= 0;
+	ip2->id		= 0;
+	ip2->flgfrag	= 0;
+	ip2->ttl	= UIP_IP_TTL;
+	ip2->proto	= UIP_IP_P_TCP;
+	ip2->csum	= 0;
+	ip2->sip	= sk->dip;
+	ip2->dip	= sk->sip;
+
+	tcp2->sport	= sk->dport;
+	tcp2->dport	= sk->sport;
+	tcp2->seq	= htonl(sk->seq_server);
+	tcp2->ack	= htonl(sk->ack_server);
+	/*
+	 * Diable TCP options, tcp hdr len equals 20 bytes
+	 */
+	tcp2->off	= UIP_TCP_HDR_LEN;
+	tcp2->flg	= flag;
+	tcp2->win	= htons(UIP_TCP_WIN_SIZE);
+	tcp2->csum	= 0;
+	tcp2->urgent	= 0;
+
+	if (payload_len > 0)
+		memcpy(uip_tcp_payload(tcp2), sk->payload, payload_len);
+
+	ip2->len	= htons(uip_tcp_hdrlen(tcp2) + payload_len + uip_ip_hdrlen(ip2));
+	ip2->csum	= uip_csum_ip(ip2);
+	tcp2->csum	= uip_csum_tcp(tcp2);
+
+	/*
+	 * virtio_net_hdr
+	 */
+	buf->vnet_len	= sizeof(struct virtio_net_hdr);
+	memset(buf->vnet, 0, buf->vnet_len);
+
+	buf->eth_len	= ntohs(ip2->len) + uip_eth_hdrlen(&ip2->eth);
+
+	/*
+	 * Increase server seq
+	 */
+	sk->seq_server  += payload_len;
+
+	/*
+	 * Send data received from socket to guest
+	 */
+	uip_buf_set_used(info, buf);
+
+	return 0;
+}
+
+static void *uip_tcp_socket_thread(void *p)
+{
+	struct uip_tcp_socket *sk;
+	u8 *payload;
+	int ret;
+
+	sk = p;
+
+	payload = malloc(UIP_MAX_TCP_PAYLOAD);
+	sk->payload = payload;
+	if (!sk->payload)
+		goto out;
+
+	while (1) {
+
+		ret = read(sk->fd, payload, UIP_MAX_TCP_PAYLOAD);
+
+		if (ret <= 0 || ret > UIP_MAX_TCP_PAYLOAD)
+			goto out;
+
+		uip_tcp_payload_send(sk, UIP_TCP_FLAG_ACK, ret);
+
+	}
+
+out:
+	/*
+	 * Close server to guest TCP connection
+	 */
+	uip_tcp_socket_close(sk, SHUT_RD);
+
+	uip_tcp_payload_send(sk, UIP_TCP_FLAG_FIN | UIP_TCP_FLAG_ACK, 0);
+	sk->seq_server += 1;
+
+	sk->read_done = 1;
+
+	free(sk->payload);
+	pthread_exit(NULL);
+
+	return NULL;
+}
+
+static int uip_tcp_socket_receive(struct uip_tcp_socket *sk)
+{
+	if (sk->thread == 0)
+		return pthread_create(&sk->thread, NULL, uip_tcp_socket_thread, (void *)sk);
+
+	return 0;
+}
+
+static int uip_tcp_socket_send(struct uip_tcp_socket *sk, struct uip_tcp *tcp)
+{
+	int len;
+	int ret;
+	u8 *payload;
+
+	if (sk->write_done)
+		return 0;
+
+	payload = uip_tcp_payload(tcp);
+	len = uip_tcp_payloadlen(tcp);
+
+	ret = write(sk->fd, payload, len);
+	if (ret != len)
+		pr_warning("tcp send error");
+
+	return ret;
+}
+
+int uip_tx_do_ipv4_tcp(struct uip_tx_arg *arg)
+{
+	struct uip_tcp_socket *sk;
+	struct uip_tcp *tcp;
+	struct uip_ip *ip;
+	int ret;
+
+	tcp = (struct uip_tcp *)arg->eth;
+	ip = (struct uip_ip *)arg->eth;
+
+	/*
+	 * Guest is trying to start a TCP session, let's fake SYN-ACK to guest
+	 */
+	if (uip_tcp_is_syn(tcp)) {
+		sk = uip_tcp_socket_alloc(arg, ip->sip, ip->dip, tcp->sport, tcp->dport);
+		if (!sk)
+			return -1;
+
+		/*
+		 * Setup ISN number
+		 */
+		sk->isn_guest  = uip_tcp_isn(tcp);
+		sk->isn_server = uip_tcp_isn_alloc();
+
+		sk->seq_server = sk->isn_server;
+		sk->ack_server = sk->isn_guest + 1;
+		uip_tcp_payload_send(sk, UIP_TCP_FLAG_SYN | UIP_TCP_FLAG_ACK, 0);
+		sk->seq_server += 1;
+
+		/*
+		 * Start receive thread for data from remote to guest
+		 */
+		uip_tcp_socket_receive(sk);
+
+		goto out;
+	}
+
+	/*
+	 * Find socket we have allocated
+	 */
+	sk = uip_tcp_socket_find(arg, ip->sip, ip->dip, tcp->sport, tcp->dport);
+	if (!sk)
+		return -1;
+
+	sk->guest_acked = ntohl(tcp->ack);
+
+	if (uip_tcp_is_fin(tcp)) {
+		if (sk->write_done)
+			goto out;
+
+		sk->write_done = 1;
+		sk->ack_server += 1;
+		uip_tcp_payload_send(sk, UIP_TCP_FLAG_ACK, 0);
+
+		/*
+		 * Close guest to server TCP connection
+		 */
+		uip_tcp_socket_close(sk, SHUT_WR);
+
+		goto out;
+	}
+
+	/*
+	 * Ignore guest to server frames with zero tcp payload
+	 */
+	if (uip_tcp_payloadlen(tcp) == 0)
+		goto out;
+
+	/*
+	 * Sent out TCP data to remote host
+	 */
+	ret = uip_tcp_socket_send(sk, tcp);
+	if (ret < 0)
+		return -1;
+	/*
+	 * Send ACK to guest imediately
+	 */
+	sk->ack_server += ret;
+	uip_tcp_payload_send(sk, UIP_TCP_FLAG_ACK, 0);
+
+out:
+	return 0;
+}
diff --git a/tools/kvm/net/uip/udp.c b/tools/kvm/net/uip/udp.c
new file mode 100644
index 0000000..d4518b2
--- /dev/null
+++ b/tools/kvm/net/uip/udp.c
@@ -0,0 +1,236 @@
+#include "kvm/uip.h"
+
+#include <linux/virtio_net.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <sys/socket.h>
+#include <sys/epoll.h>
+#include <fcntl.h>
+
+#define UIP_UDP_MAX_EVENTS 1000
+
+static struct uip_udp_socket *uip_udp_socket_find(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport)
+{
+	struct list_head *sk_head;
+	struct uip_udp_socket *sk;
+	pthread_mutex_t *sk_lock;
+	struct epoll_event ev;
+	int flags;
+	int ret;
+
+	sk_head = &arg->info->udp_socket_head;
+	sk_lock = &arg->info->udp_socket_lock;
+
+	/*
+	 * Find existing sk
+	 */
+	mutex_lock(sk_lock);
+	list_for_each_entry(sk, sk_head, list) {
+		if (sk->sip == sip && sk->dip == dip && sk->sport == sport && sk->dport == dport) {
+			mutex_unlock(sk_lock);
+			return sk;
+		}
+	}
+	mutex_unlock(sk_lock);
+
+	/*
+	 * Allocate new one
+	 */
+	sk = malloc(sizeof(*sk));
+	memset(sk, 0, sizeof(*sk));
+
+	sk->lock = sk_lock;
+
+	sk->fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sk->fd < 0)
+		goto out;
+
+	/*
+	 * Set non-blocking
+	 */
+	flags = fcntl(sk->fd, F_GETFL, 0);
+	flags |= O_NONBLOCK;
+	fcntl(sk->fd, F_SETFL, flags);
+
+	/*
+	 * Add sk->fd to epoll_wait
+	 */
+	ev.events	= EPOLLIN;
+	ev.data.fd	= sk->fd;
+	ev.data.ptr	= sk;
+	if (arg->info->udp_epollfd <= 0)
+		arg->info->udp_epollfd = epoll_create(UIP_UDP_MAX_EVENTS);
+	ret = epoll_ctl(arg->info->udp_epollfd, EPOLL_CTL_ADD, sk->fd, &ev);
+	if (ret == -1)
+		pr_warning("epoll_ctl error");
+
+	sk->addr.sin_family	 = AF_INET;
+	sk->addr.sin_addr.s_addr = dip;
+	sk->addr.sin_port	 = dport;
+
+	sk->sip			 = sip;
+	sk->dip			 = dip;
+	sk->sport		 = sport;
+	sk->dport		 = dport;
+
+	mutex_lock(sk_lock);
+	list_add_tail(&sk->list, sk_head);
+	mutex_unlock(sk_lock);
+
+	return sk;
+
+out:
+	free(sk);
+	return NULL;
+}
+
+static int uip_udp_socket_send(struct uip_udp_socket *sk, struct uip_udp *udp)
+{
+	int len;
+	int ret;
+
+	len = ntohs(udp->len) - uip_udp_hdrlen(udp);
+
+	ret = sendto(sk->fd, udp->payload, len, 0, (struct sockaddr *)&sk->addr, sizeof(sk->addr));
+	if (ret != len)
+		return -1;
+
+	return 0;
+}
+
+int uip_udp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8* payload, int payload_len)
+{
+	struct uip_eth *eth2;
+	struct uip_udp *udp2;
+	struct uip_ip *ip2;
+
+	/*
+	 * Cook a ethernet frame
+	 */
+	udp2		= (struct uip_udp *)(buf->eth);
+	eth2		= (struct uip_eth *)buf->eth;
+	ip2		= (struct uip_ip *)(buf->eth);
+
+	eth2->src	= info->host_mac;
+	eth2->dst	= info->guest_mac;
+	eth2->type	= htons(UIP_ETH_P_IP);
+
+	ip2->vhl	= UIP_IP_VER_4 | UIP_IP_HDR_LEN;
+	ip2->tos	= 0;
+	ip2->id		= 0;
+	ip2->flgfrag	= 0;
+	ip2->ttl	= UIP_IP_TTL;
+	ip2->proto	= UIP_IP_P_UDP;
+	ip2->csum	= 0;
+
+	ip2->sip	= sk->dip;
+	ip2->dip	= sk->sip;
+	udp2->sport	= sk->dport;
+	udp2->dport	= sk->sport;
+
+	udp2->len	= htons(payload_len + uip_udp_hdrlen(udp2));
+	udp2->csum	= 0;
+
+	if (payload)
+		memcpy(udp2->payload, payload, payload_len);
+
+	ip2->len	= udp2->len + htons(uip_ip_hdrlen(ip2));
+	ip2->csum	= uip_csum_ip(ip2);
+	udp2->csum	= uip_csum_udp(udp2);
+
+	/*
+	 * virtio_net_hdr
+	 */
+	buf->vnet_len	= sizeof(struct virtio_net_hdr);
+	memset(buf->vnet, 0, buf->vnet_len);
+
+	buf->eth_len	= ntohs(ip2->len) + uip_eth_hdrlen(&ip2->eth);
+
+	return 0;
+}
+
+static void *uip_udp_socket_thread(void *p)
+{
+	struct epoll_event events[UIP_UDP_MAX_EVENTS];
+	struct uip_udp_socket *sk;
+	struct uip_info *info;
+	struct uip_buf *buf;
+	int payload_len;
+	u8 *payload;
+	int nfds;
+	int i;
+
+	info = p;
+
+	do {
+		payload = malloc(UIP_MAX_UDP_PAYLOAD);
+	} while (!payload);
+
+	while (1) {
+		nfds = epoll_wait(info->udp_epollfd, events, UIP_UDP_MAX_EVENTS, -1);
+
+		if (nfds == -1)
+			continue;
+
+		for (i = 0; i < nfds; i++) {
+
+			sk = events[i].data.ptr;
+			payload_len = recvfrom(sk->fd, payload, UIP_MAX_UDP_PAYLOAD, 0, NULL, NULL);
+			if (payload_len < 0)
+				continue;
+
+			/*
+			 * Get free buffer to send data to guest
+			 */
+			buf = uip_buf_get_free(info);
+
+			uip_udp_make_pkg(info, sk, buf, payload, payload_len);
+
+			/*
+			 * Send data received from socket to guest
+			 */
+			uip_buf_set_used(info, buf);
+		}
+	}
+
+	free(payload);
+	pthread_exit(NULL);
+	return NULL;
+}
+
+int uip_tx_do_ipv4_udp(struct uip_tx_arg *arg)
+{
+	struct uip_udp_socket *sk;
+	struct uip_info *info;
+	struct uip_udp *udp;
+	struct uip_ip *ip;
+	int ret;
+
+	udp	= (struct uip_udp *)(arg->eth);
+	ip	= (struct uip_ip *)(arg->eth);
+	info	= arg->info;
+
+	if (uip_udp_is_dhcp(udp)) {
+		uip_tx_do_ipv4_udp_dhcp(arg);
+		return 0;
+	}
+
+	/*
+	 * Find socket we have allocated before, otherwise allocate one
+	 */
+	sk = uip_udp_socket_find(arg, ip->sip, ip->dip, udp->sport, udp->dport);
+	if (!sk)
+		return -1;
+
+	/*
+	 * Send out UDP data to remote host
+	 */
+	ret = uip_udp_socket_send(sk, udp);
+	if (ret)
+		return -1;
+
+	if (!info->udp_thread)
+		pthread_create(&info->udp_thread, NULL, uip_udp_socket_thread, (void *)info);
+
+	return 0;
+}
diff --git a/tools/kvm/pci.c b/tools/kvm/pci.c
new file mode 100644
index 0000000..38f4778
--- /dev/null
+++ b/tools/kvm/pci.c
@@ -0,0 +1,213 @@
+#include "kvm/pci.h"
+#include "kvm/ioport.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+
+#include <linux/err.h>
+#include <assert.h>
+
+#define PCI_BAR_OFFSET(b)		(offsetof(struct pci_device_header, bar[b]))
+
+static struct pci_device_header		*pci_devices[PCI_MAX_DEVICES];
+
+static union pci_config_address		pci_config_address;
+
+/* This is within our PCI gap - in an unused area.
+ * Note this is a PCI *bus address*, is used to assign BARs etc.!
+ * (That's why it can still 32bit even with 64bit guests-- 64bit
+ * PCI isn't currently supported.)
+ */
+static u32 io_space_blocks		= KVM_PCI_MMIO_AREA;
+
+u32 pci_get_io_space_block(u32 size)
+{
+	u32 block = io_space_blocks;
+	io_space_blocks += size;
+
+	return block;
+}
+
+static void *pci_config_address_ptr(u16 port)
+{
+	unsigned long offset;
+	void *base;
+
+	offset	= port - PCI_CONFIG_ADDRESS;
+	base	= &pci_config_address;
+
+	return base + offset;
+}
+
+static bool pci_config_address_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	void *p = pci_config_address_ptr(port);
+
+	memcpy(p, data, size);
+
+	return true;
+}
+
+static bool pci_config_address_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	void *p = pci_config_address_ptr(port);
+
+	memcpy(data, p, size);
+
+	return true;
+}
+
+static struct ioport_operations pci_config_address_ops = {
+	.io_in	= pci_config_address_in,
+	.io_out	= pci_config_address_out,
+};
+
+static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_number)
+{
+	struct pci_device_header *dev;
+
+	if (pci_config_address.bus_number != bus_number)
+		return false;
+
+	if (pci_config_address.function_number != function_number)
+		return false;
+
+	if (device_number >= PCI_MAX_DEVICES)
+		return false;
+
+	dev = pci_devices[device_number];
+
+	return dev != NULL;
+}
+
+static bool pci_config_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	/*
+	 * If someone accesses PCI configuration space offsets that are not
+	 * aligned to 4 bytes, it uses ioports to signify that.
+	 */
+	pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
+
+	pci__config_wr(kvm, pci_config_address, data, size);
+
+	return true;
+}
+
+static bool pci_config_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	/*
+	 * If someone accesses PCI configuration space offsets that are not
+	 * aligned to 4 bytes, it uses ioports to signify that.
+	 */
+	pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
+
+	pci__config_rd(kvm, pci_config_address, data, size);
+
+	return true;
+}
+
+static struct ioport_operations pci_config_data_ops = {
+	.io_in	= pci_config_data_in,
+	.io_out	= pci_config_data_out,
+};
+
+void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data, int size)
+{
+	u8 dev_num;
+
+	dev_num	= addr.device_number;
+
+	if (pci_device_exists(0, dev_num, 0)) {
+		unsigned long offset;
+
+		offset = addr.w & 0xff;
+		if (offset < sizeof(struct pci_device_header)) {
+			void *p = pci_devices[dev_num];
+			u8 bar = (offset - PCI_BAR_OFFSET(0)) / (sizeof(u32));
+			u32 sz = PCI_IO_SIZE;
+
+			if (bar < 6 && pci_devices[dev_num]->bar_size[bar])
+				sz = pci_devices[dev_num]->bar_size[bar];
+
+			/*
+			 * If the kernel masks the BAR it would expect to find the
+			 * size of the BAR there next time it reads from it.
+			 * When the kernel got the size it would write the address
+			 * back.
+			 */
+			if (*(u32 *)(p + offset)) {
+				/* See if kernel tries to mask one of the BARs */
+				if ((offset >= PCI_BAR_OFFSET(0)) &&
+				    (offset <= PCI_BAR_OFFSET(6)) &&
+				    (ioport__read32(data)  == 0xFFFFFFFF))
+					memcpy(p + offset, &sz, sizeof(sz));
+				    else
+					memcpy(p + offset, data, size);
+			}
+		}
+	}
+}
+
+void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data, int size)
+{
+	u8 dev_num;
+
+	dev_num	= addr.device_number;
+
+	if (pci_device_exists(0, dev_num, 0)) {
+		unsigned long offset;
+
+		offset = addr.w & 0xff;
+		if (offset < sizeof(struct pci_device_header)) {
+			void *p = pci_devices[dev_num];
+
+			memcpy(data, p + offset, size);
+		} else {
+			memset(data, 0x00, size);
+		}
+	} else {
+		memset(data, 0xff, size);
+	}
+}
+
+int pci__register(struct pci_device_header *dev, u8 dev_num)
+{
+	if (dev_num >= PCI_MAX_DEVICES)
+		return -ENOSPC;
+
+	pci_devices[dev_num] = dev;
+
+	return 0;
+}
+
+struct pci_device_header *pci__find_dev(u8 dev_num)
+{
+	if (dev_num >= PCI_MAX_DEVICES)
+		return ERR_PTR(-EOVERFLOW);
+
+	return pci_devices[dev_num];
+}
+
+int pci__init(struct kvm *kvm)
+{
+	int r;
+
+	r = ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops, 4, NULL);
+	if (r < 0)
+		return r;
+
+	r = ioport__register(PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops, 4, NULL);
+	if (r < 0) {
+		ioport__unregister(PCI_CONFIG_DATA);
+		return r;
+	}
+
+	return 0;
+}
+
+int pci__exit(struct kvm *kvm)
+{
+	ioport__unregister(PCI_CONFIG_DATA);
+	ioport__unregister(PCI_CONFIG_ADDRESS);
+
+	return 0;
+}
diff --git a/tools/kvm/powerpc/boot.c b/tools/kvm/powerpc/boot.c
new file mode 100644
index 0000000..2557fc0
--- /dev/null
+++ b/tools/kvm/powerpc/boot.c
@@ -0,0 +1,8 @@
+#include "kvm/kvm.h"
+
+#include <stdbool.h>
+
+bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
+{
+	return false;
+}
diff --git a/tools/kvm/powerpc/cpu_info.c b/tools/kvm/powerpc/cpu_info.c
new file mode 100644
index 0000000..c364b74
--- /dev/null
+++ b/tools/kvm/powerpc/cpu_info.c
@@ -0,0 +1,83 @@
+/*
+ * PPC CPU identification
+ *
+ * This is a very simple "host CPU info" struct to get us going.
+ * For the little host information we need, I don't want to grub about
+ * parsing stuff in /proc/device-tree so just match host PVR to differentiate
+ * PPC970 and POWER7 (which is all that's currently supported).
+ *
+ * Qemu does something similar but this is MUCH simpler!
+ *
+ * Copyright 2012 Matt Evans <matt@ozlabs.org>, IBM 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.
+ */
+
+#include "cpu_info.h"
+#include "kvm/util.h"
+
+/* POWER7 */
+
+/*
+ * Basic set of pages for POWER7.  It actually supports more but there were some
+ * limitations as to which may be advertised to the guest.  FIXME when this
+ * settles down -- for now use basic set:
+ */
+static u32 power7_page_sizes_prop[] = {0xc, 0x0, 0x1, 0xc, 0x0, 0x18, 0x100, 0x1, 0x18, 0x0};
+/* POWER7 has 1T segments, so advertise these */
+static u32 power7_segment_sizes_prop[] = {0x1c, 0x28, 0xffffffff, 0xffffffff};
+
+static struct cpu_info cpu_power7_info = {
+	"POWER7",
+	power7_page_sizes_prop, sizeof(power7_page_sizes_prop),
+	power7_segment_sizes_prop, sizeof(power7_segment_sizes_prop),
+	32, 		/* SLB size */
+	512000000, 	/* TB frequency */
+	128,		/* d-cache block size */
+	128,		/* i-cache block size */
+	CPUINFO_FLAG_DFP | CPUINFO_FLAG_VSX | CPUINFO_FLAG_VMX
+};
+
+/* PPC970/G5 */
+
+static u32 g5_page_sizes_prop[] = {0xc, 0x0, 0x1, 0xc, 0x0, 0x18, 0x100, 0x1, 0x18, 0x0};
+
+static struct cpu_info cpu_970_info = {
+	"G5",
+	g5_page_sizes_prop, sizeof(g5_page_sizes_prop),
+	0 /* Null = no segment sizes prop, use defaults */, 0,
+	0, 		/* SLB size default */
+	33333333, 	/* TB frequency */
+	128,		/* d-cache block size */
+	128,		/* i-cache block size */
+	CPUINFO_FLAG_VMX
+};
+
+/* This is a default catchall for 'no match' on PVR: */
+static struct cpu_info cpu_dummy_info = { "unknown", 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static struct pvr_info host_pvr_info[] = {
+	{ 0xffffffff, 0x0f000003, &cpu_power7_info },
+	{ 0xffff0000, 0x003f0000, &cpu_power7_info },
+	{ 0xffff0000, 0x004a0000, &cpu_power7_info },
+	{ 0xffff0000, 0x00390000, &cpu_970_info },
+	{ 0xffff0000, 0x003c0000, &cpu_970_info },
+        { 0xffff0000, 0x00440000, &cpu_970_info },
+        { 0xffff0000, 0x00450000, &cpu_970_info },
+};
+
+struct cpu_info *find_cpu_info(u32 pvr)
+{
+	unsigned int i;
+	for (i = 0; i < sizeof(host_pvr_info)/sizeof(struct pvr_info); i++) {
+		if ((pvr & host_pvr_info[i].pvr_mask) ==
+		    host_pvr_info[i].pvr) {
+			return host_pvr_info[i].cpu_info;
+		}
+	}
+	/* Didn't find anything? Rut-ro. */
+	pr_warning("Host CPU unsupported by kvmtool\n");
+	return &cpu_dummy_info;
+}
diff --git a/tools/kvm/powerpc/cpu_info.h b/tools/kvm/powerpc/cpu_info.h
new file mode 100644
index 0000000..4a43ed5
--- /dev/null
+++ b/tools/kvm/powerpc/cpu_info.h
@@ -0,0 +1,43 @@
+/*
+ * PPC CPU identification
+ *
+ * Copyright 2012 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef CPU_INFO_H
+#define CPU_INFO_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+struct cpu_info {
+	const char	*name;
+	u32 		*page_sizes_prop;
+	u32		page_sizes_prop_len;
+	u32 		*segment_sizes_prop;
+	u32		segment_sizes_prop_len;
+	u32		slb_size;
+	u32		tb_freq;
+	u32		d_bsize;
+	u32		i_bsize;
+	u32		flags;
+};
+
+struct pvr_info {
+	u32		pvr_mask;
+	u32		pvr;
+	struct cpu_info *cpu_info;
+};
+
+/* Misc capabilities/CPU properties */
+#define CPUINFO_FLAG_DFP	0x00000001
+#define CPUINFO_FLAG_VMX	0x00000002
+#define CPUINFO_FLAG_VSX	0x00000004
+
+struct cpu_info *find_cpu_info(u32 pvr);
+
+#endif
diff --git a/tools/kvm/powerpc/include/kvm/barrier.h b/tools/kvm/powerpc/include/kvm/barrier.h
new file mode 100644
index 0000000..bc7d179
--- /dev/null
+++ b/tools/kvm/powerpc/include/kvm/barrier.h
@@ -0,0 +1,6 @@
+#ifndef _KVM_BARRIER_H_
+#define _KVM_BARRIER_H_
+
+#include <asm/system.h>
+
+#endif /* _KVM_BARRIER_H_ */
diff --git a/tools/kvm/powerpc/include/kvm/kvm-arch.h b/tools/kvm/powerpc/include/kvm/kvm-arch.h
new file mode 100644
index 0000000..c7620b2
--- /dev/null
+++ b/tools/kvm/powerpc/include/kvm/kvm-arch.h
@@ -0,0 +1,88 @@
+/*
+ * PPC64 architecture-specific definitions
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef KVM__KVM_ARCH_H
+#define KVM__KVM_ARCH_H
+
+#include <stdbool.h>
+#include <linux/types.h>
+#include <time.h>
+
+/*
+ * MMIO lives after RAM, but it'd be nice if it didn't constantly move.
+ * Choose a suitably high address, e.g. 63T...  This limits RAM size.
+ */
+#define PPC_MMIO_START			0x3F0000000000UL
+#define PPC_MMIO_SIZE			0x010000000000UL
+
+#define KERNEL_LOAD_ADDR        	0x0000000000000000
+#define KERNEL_START_ADDR       	0x0000000000000000
+#define KERNEL_SECONDARY_START_ADDR     0x0000000000000060
+#define INITRD_LOAD_ADDR        	0x0000000002800000
+
+#define FDT_MAX_SIZE            	0x10000
+#define RTAS_MAX_SIZE           	0x10000
+
+#define TIMEBASE_FREQ           	512000000ULL
+
+#define KVM_MMIO_START			PPC_MMIO_START
+
+/*
+ * This is the address that pci_get_io_space_block() starts allocating
+ * from.  Note that this is a PCI bus address.
+ */
+#define KVM_PCI_MMIO_AREA		0x1000000
+
+struct spapr_phb;
+
+struct kvm {
+	int			sys_fd;		/* For system ioctls(), i.e. /dev/kvm */
+	int			vm_fd;		/* For VM ioctls() */
+	timer_t			timerid;	/* Posix timer for interrupts */
+
+	int			nrcpus;		/* Number of cpus to run */
+
+	u32			mem_slots;	/* for KVM_SET_USER_MEMORY_REGION */
+
+	u64			ram_size;
+	void			*ram_start;
+
+	u64			sdr1;
+	u32			pvr;
+
+	bool			nmi_disabled;
+
+	bool			single_step;
+
+	const char		*vmlinux;
+	struct disk_image       **disks;
+	int                     nr_disks;
+	unsigned long		rtas_gra;
+	unsigned long		rtas_size;
+	unsigned long		fdt_gra;
+	unsigned long		initrd_gra;
+	unsigned long		initrd_size;
+	char			*name;
+	int			vm_state;
+	struct icp_state	*icp;
+	struct spapr_phb	*phb;
+};
+
+/* Helper for the various bits of code that generate FDT nodes */
+#define _FDT(exp)							\
+	do {								\
+		int ret = (exp);					\
+		if (ret < 0) {						\
+			die("Error creating device tree: %s: %s\n",	\
+			    #exp, fdt_strerror(ret));			\
+		}							\
+	} while (0)
+
+#endif /* KVM__KVM_ARCH_H */
diff --git a/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h b/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h
new file mode 100644
index 0000000..7520c04
--- /dev/null
+++ b/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h
@@ -0,0 +1,76 @@
+/*
+ * PPC64 cpu-specific definitions
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef KVM__KVM_CPU_ARCH_H
+#define KVM__KVM_CPU_ARCH_H
+
+/* Architecture-specific kvm_cpu definitions. */
+
+#include <linux/kvm.h>	/* for struct kvm_regs */
+#include <stdbool.h>
+#include <pthread.h>
+
+#define MSR_SF		(1UL<<63)
+#define MSR_HV		(1UL<<60)
+#define MSR_VEC		(1UL<<25)
+#define MSR_VSX		(1UL<<23)
+#define MSR_POW		(1UL<<18)
+#define MSR_EE		(1UL<<15)
+#define MSR_PR		(1UL<<14)
+#define MSR_FP		(1UL<<13)
+#define MSR_ME		(1UL<<12)
+#define MSR_FE0		(1UL<<11)
+#define MSR_SE		(1UL<<10)
+#define MSR_BE		(1UL<<9)
+#define MSR_FE1		(1UL<<8)
+#define MSR_IR		(1UL<<5)
+#define MSR_DR		(1UL<<4)
+#define MSR_PMM		(1UL<<2)
+#define MSR_RI		(1UL<<1)
+#define MSR_LE		(1UL<<0)
+
+#define POWER7_EXT_IRQ	0
+
+struct kvm;
+
+struct kvm_cpu {
+	pthread_t		thread;		/* VCPU thread */
+
+	unsigned long		cpu_id;
+
+	struct kvm		*kvm;		/* parent KVM */
+	int			vcpu_fd;	/* For VCPU ioctls() */
+	struct kvm_run		*kvm_run;
+
+	struct kvm_regs		regs;
+	struct kvm_sregs	sregs;
+	struct kvm_fpu		fpu;
+
+	u8			is_running;
+	u8			paused;
+	u8			needs_nmi;
+	/*
+	 * Although PPC KVM doesn't yet support coalesced MMIO, generic code
+	 * needs this in our kvm_cpu:
+	 */
+	struct kvm_coalesced_mmio_ring  *ring;
+};
+
+void kvm_cpu__irq(struct kvm_cpu *vcpu, int pin, int level);
+
+/* This is never actually called on PPC. */
+static inline bool kvm_cpu__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count)
+{
+	return false;
+}
+
+bool kvm_cpu__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write);
+
+#endif /* KVM__KVM_CPU_ARCH_H */
diff --git a/tools/kvm/powerpc/ioport.c b/tools/kvm/powerpc/ioport.c
new file mode 100644
index 0000000..a8e4dc3
--- /dev/null
+++ b/tools/kvm/powerpc/ioport.c
@@ -0,0 +1,18 @@
+/*
+ * PPC64 ioport platform setup.  There isn't any! :-)
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM 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.
+ */
+
+#include "kvm/ioport.h"
+
+#include <stdlib.h>
+
+void ioport__setup_arch(void)
+{
+	/* PPC has no legacy ioports to set up */
+}
diff --git a/tools/kvm/powerpc/irq.c b/tools/kvm/powerpc/irq.c
new file mode 100644
index 0000000..7da4012
--- /dev/null
+++ b/tools/kvm/powerpc/irq.c
@@ -0,0 +1,75 @@
+/*
+ * PPC64 IRQ routines
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM 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.
+ */
+
+#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+
+#include <linux/types.h>
+#include <linux/rbtree.h>
+#include <linux/list.h>
+#include <linux/kvm.h>
+#include <sys/ioctl.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "kvm/pci.h"
+
+#include "xics.h"
+#include "spapr_pci.h"
+
+#define XICS_IRQS               1024
+
+/*
+ * FIXME: The code in this file assumes an SPAPR guest, using XICS.  Make
+ * generic & cope with multiple PPC platform types.
+ */
+
+static int pci_devs = 0;
+
+int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line)
+{
+	if (pci_devs >= PCI_MAX_DEVICES)
+		die("Hit PCI device limit!\n");
+
+	*num = pci_devs++;
+
+	*pin = 1;
+	/*
+	 * Have I said how nasty I find this?  Line should be dontcare... PHB
+	 * should determine which CPU/XICS IRQ to fire.
+	 */
+	*line = xics_alloc_irqnum();
+	return 0;
+}
+
+int irq__init(struct kvm *kvm)
+{
+	/*
+	 * kvm->nr_cpus is now valid; for /now/, pass
+	 * this to xics_system_init(), which assumes servers
+	 * are numbered 0..nrcpus.  This may not really be true,
+	 * but it is OK currently.
+	 */
+	kvm->icp = xics_system_init(XICS_IRQS, kvm->nrcpus);
+	return 0;
+}
+
+int irq__exit(struct kvm *kvm)
+{
+	return 0;
+}
+
+int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg)
+{
+	die(__FUNCTION__);
+	return 0;
+}
diff --git a/tools/kvm/powerpc/kvm-cpu.c b/tools/kvm/powerpc/kvm-cpu.c
new file mode 100644
index 0000000..2505c69
--- /dev/null
+++ b/tools/kvm/powerpc/kvm-cpu.c
@@ -0,0 +1,291 @@
+/*
+ * PPC64 processor support
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM 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.
+ */
+
+#include "kvm/kvm-cpu.h"
+
+#include "kvm/symbol.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+
+#include "spapr.h"
+#include "spapr_pci.h"
+#include "xics.h"
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+
+static int debug_fd;
+
+void kvm_cpu__set_debug_fd(int fd)
+{
+	debug_fd = fd;
+}
+
+int kvm_cpu__get_debug_fd(void)
+{
+	return debug_fd;
+}
+
+static struct kvm_cpu *kvm_cpu__new(struct kvm *kvm)
+{
+	struct kvm_cpu *vcpu;
+
+	vcpu		= calloc(1, sizeof *vcpu);
+	if (!vcpu)
+		return NULL;
+
+	vcpu->kvm	= kvm;
+
+	return vcpu;
+}
+
+void kvm_cpu__delete(struct kvm_cpu *vcpu)
+{
+	free(vcpu);
+}
+
+struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id)
+{
+	struct kvm_cpu *vcpu;
+	int mmap_size;
+	struct kvm_enable_cap papr_cap = { .cap = KVM_CAP_PPC_PAPR };
+
+	vcpu		= kvm_cpu__new(kvm);
+	if (!vcpu)
+		return NULL;
+
+	vcpu->cpu_id	= cpu_id;
+
+	vcpu->vcpu_fd = ioctl(vcpu->kvm->vm_fd, KVM_CREATE_VCPU, cpu_id);
+	if (vcpu->vcpu_fd < 0)
+		die_perror("KVM_CREATE_VCPU ioctl");
+
+	mmap_size = ioctl(vcpu->kvm->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
+	if (mmap_size < 0)
+		die_perror("KVM_GET_VCPU_MMAP_SIZE ioctl");
+
+	vcpu->kvm_run = mmap(NULL, mmap_size, PROT_RW, MAP_SHARED, vcpu->vcpu_fd, 0);
+	if (vcpu->kvm_run == MAP_FAILED)
+		die("unable to mmap vcpu fd");
+
+	if (ioctl(vcpu->vcpu_fd, KVM_ENABLE_CAP, &papr_cap) < 0)
+		die("unable to enable PAPR capability");
+
+	/*
+	 * We start all CPUs, directing non-primary threads into the kernel's
+	 * secondary start point.  When we come to support SLOF, we will start
+	 * only one and SLOF will RTAS call us to ask for others to be
+	 * started.  (FIXME: make more generic & interface with whichever
+	 * firmware a platform may be using.)
+	 */
+	vcpu->is_running = true;
+
+	/* Register with IRQ controller (FIXME, assumes XICS) */
+	xics_cpu_register(vcpu);
+
+	return vcpu;
+}
+
+static void kvm_cpu__setup_fpu(struct kvm_cpu *vcpu)
+{
+	/* Don't have to do anything, there's no expected FPU state. */
+}
+
+static void kvm_cpu__setup_regs(struct kvm_cpu *vcpu)
+{
+	/*
+	 * FIXME: This assumes PPC64 and Linux guest.  It doesn't use the
+	 * OpenFirmware entry method, but instead the "embedded" entry which
+	 * passes the FDT address directly.
+	 */
+	struct kvm_regs *r = &vcpu->regs;
+
+	if (vcpu->cpu_id == 0) {
+		r->pc = KERNEL_START_ADDR;
+		r->gpr[3] = vcpu->kvm->fdt_gra;
+		r->gpr[5] = 0;
+	} else {
+		r->pc = KERNEL_SECONDARY_START_ADDR;
+		r->gpr[3] = vcpu->cpu_id;
+	}
+	r->msr = 0x8000000000001000UL; /* 64bit, non-HV, ME */
+
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_REGS, &vcpu->regs) < 0)
+		die_perror("KVM_SET_REGS failed");
+}
+
+static void kvm_cpu__setup_sregs(struct kvm_cpu *vcpu)
+{
+	/*
+	 * Some sregs setup to initialise SDR1/PVR/HIOR on PPC64 SPAPR
+	 * platforms using PR KVM.  (Technically, this is all ignored on
+	 * SPAPR HV KVM.)  Different setup is required for non-PV non-SPAPR
+	 * platforms!  (FIXME.)
+	 */
+	struct kvm_sregs sregs;
+	struct kvm_one_reg reg = {};
+
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &sregs) < 0)
+		die("KVM_GET_SREGS failed");
+
+	sregs.u.s.sdr1 = vcpu->kvm->sdr1;
+	sregs.pvr = vcpu->kvm->pvr;
+
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_SREGS, &sregs) < 0)
+		die("KVM_SET_SREGS failed");
+
+	reg.id = KVM_ONE_REG_PPC_HIOR;
+	reg.u.reg64 = 0;
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
+		die("KVM_SET_ONE_REG failed");
+}
+
+/**
+ * kvm_cpu__reset_vcpu - reset virtual CPU to a known state
+ */
+void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu)
+{
+	kvm_cpu__setup_regs(vcpu);
+	kvm_cpu__setup_sregs(vcpu);
+	kvm_cpu__setup_fpu(vcpu);
+}
+
+/* kvm_cpu__irq - set KVM's IRQ flag on this vcpu */
+void kvm_cpu__irq(struct kvm_cpu *vcpu, int pin, int level)
+{
+	unsigned int virq = level ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET;
+
+	/* FIXME: POWER-specific */
+	if (pin != POWER7_EXT_IRQ)
+		return;
+	if (ioctl(vcpu->vcpu_fd, KVM_INTERRUPT, &virq) < 0)
+		pr_warning("Could not KVM_INTERRUPT.");
+}
+
+void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
+{
+}
+
+bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
+{
+	bool ret = true;
+	struct kvm_run *run = vcpu->kvm_run;
+	switch(run->exit_reason) {
+	case KVM_EXIT_PAPR_HCALL:
+		run->papr_hcall.ret = spapr_hypercall(vcpu, run->papr_hcall.nr,
+						      (target_ulong*)run->papr_hcall.args);
+		break;
+	default:
+		ret = false;
+	}
+	return ret;
+}
+
+bool kvm_cpu__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write)
+{
+	/*
+	 * FIXME: This function will need to be split in order to support
+	 * various PowerPC platforms/PHB types, etc.  It currently assumes SPAPR
+	 * PPC64 guest.
+	 */
+	bool ret = false;
+
+	if ((phys_addr >= SPAPR_PCI_WIN_START) &&
+	    (phys_addr < SPAPR_PCI_WIN_END)) {
+		ret = spapr_phb_mmio(kvm, phys_addr, data, len, is_write);
+	} else {
+		pr_warning("MMIO %s unknown address %llx (size %d)!\n",
+			   is_write ? "write to" : "read from",
+			   phys_addr, len);
+	}
+	return ret;
+}
+
+#define CONDSTR_BIT(m, b) (((m) & MSR_##b) ? #b" " : "")
+
+void kvm_cpu__show_registers(struct kvm_cpu *vcpu)
+{
+	struct kvm_regs regs;
+	struct kvm_sregs sregs;
+	int r;
+
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_REGS, &regs) < 0)
+		die("KVM_GET_REGS failed");
+        if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &sregs) < 0)
+		die("KVM_GET_SREGS failed");
+
+	dprintf(debug_fd, "\n Registers:\n");
+	dprintf(debug_fd, " NIP:   %016llx  MSR:   %016llx "
+		"( %s%s%s%s%s%s%s%s%s%s%s%s)\n",
+		regs.pc, regs.msr,
+		CONDSTR_BIT(regs.msr, SF),
+		CONDSTR_BIT(regs.msr, HV), /* ! */
+		CONDSTR_BIT(regs.msr, VEC),
+		CONDSTR_BIT(regs.msr, VSX),
+		CONDSTR_BIT(regs.msr, EE),
+		CONDSTR_BIT(regs.msr, PR),
+		CONDSTR_BIT(regs.msr, FP),
+		CONDSTR_BIT(regs.msr, ME),
+		CONDSTR_BIT(regs.msr, IR),
+		CONDSTR_BIT(regs.msr, DR),
+		CONDSTR_BIT(regs.msr, RI),
+		CONDSTR_BIT(regs.msr, LE));
+	dprintf(debug_fd, " CTR:   %016llx  LR:    %016llx  CR:   %08llx\n",
+		regs.ctr, regs.lr, regs.cr);
+	dprintf(debug_fd, " SRR0:  %016llx  SRR1:  %016llx  XER:  %016llx\n",
+		regs.srr0, regs.srr1, regs.xer);
+	dprintf(debug_fd, " SPRG0: %016llx  SPRG1: %016llx\n",
+		regs.sprg0, regs.sprg1);
+	dprintf(debug_fd, " SPRG2: %016llx  SPRG3: %016llx\n",
+		regs.sprg2, regs.sprg3);
+	dprintf(debug_fd, " SPRG4: %016llx  SPRG5: %016llx\n",
+		regs.sprg4, regs.sprg5);
+	dprintf(debug_fd, " SPRG6: %016llx  SPRG7: %016llx\n",
+		regs.sprg6, regs.sprg7);
+	dprintf(debug_fd, " GPRs:\n ");
+	for (r = 0; r < 32; r++) {
+		dprintf(debug_fd, "%016llx  ", regs.gpr[r]);
+		if ((r & 3) == 3)
+			dprintf(debug_fd, "\n ");
+	}
+	dprintf(debug_fd, "\n");
+
+	/* FIXME: Assumes SLB-based (book3s) guest */
+	for (r = 0; r < 32; r++) {
+		dprintf(debug_fd, " SLB%02d  %016llx %016llx\n", r,
+			sregs.u.s.ppc64.slb[r].slbe,
+			sregs.u.s.ppc64.slb[r].slbv);
+	}
+	dprintf(debug_fd, "----------\n");
+}
+
+void kvm_cpu__show_code(struct kvm_cpu *vcpu)
+{
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_REGS, &vcpu->regs) < 0)
+		die("KVM_GET_REGS failed");
+
+	/* FIXME: Dump/disassemble some code...! */
+
+	dprintf(debug_fd, "\n Stack:\n");
+	dprintf(debug_fd,   " ------\n");
+	/* Only works in real mode: */
+	kvm__dump_mem(vcpu->kvm, vcpu->regs.gpr[1], 32);
+}
+
+void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
+{
+	/* Does nothing yet */
+}
diff --git a/tools/kvm/powerpc/kvm.c b/tools/kvm/powerpc/kvm.c
new file mode 100644
index 0000000..cbc0d8f
--- /dev/null
+++ b/tools/kvm/powerpc/kvm.c
@@ -0,0 +1,460 @@
+/*
+ * PPC64 (SPAPR) platform support
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * Portions of FDT setup borrowed from QEMU, copyright 2010 David Gibson, IBM
+ * 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.
+ */
+
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+#include "libfdt.h"
+#include "cpu_info.h"
+
+#include "spapr.h"
+#include "spapr_hvcons.h"
+#include "spapr_pci.h"
+
+#include <linux/kvm.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <asm/unistd.h>
+#include <errno.h>
+
+#include <linux/byteorder.h>
+
+#define HPT_ORDER 24
+
+#define HUGETLBFS_PATH "/var/lib/hugetlbfs/global/pagesize-16MB/"
+
+#define PHANDLE_XICP		0x00001111
+
+static char kern_cmdline[2048];
+
+struct kvm_ext kvm_req_ext[] = {
+	{ DEFINE_KVM_EXT(KVM_CAP_PPC_UNSET_IRQ) },
+	{ DEFINE_KVM_EXT(KVM_CAP_PPC_IRQ_LEVEL) },
+	{ 0, 0 }
+};
+
+static uint32_t mfpvr(void)
+{
+	uint32_t r;
+	asm volatile ("mfpvr %0" : "=r"(r));
+	return r;
+}
+
+bool kvm__arch_cpu_supports_vm(void)
+{
+	return true;
+}
+
+void kvm__init_ram(struct kvm *kvm)
+{
+	u64	phys_start, phys_size;
+	void	*host_mem;
+
+	phys_start = 0;
+	phys_size  = kvm->ram_size;
+	host_mem   = kvm->ram_start;
+
+	/*
+	 * We put MMIO at PPC_MMIO_START, high up.  Make sure that this doesn't
+	 * crash into the end of RAM -- on PPC64 at least, this is so high
+	 * (63TB!) that this is unlikely.
+	 */
+	if (phys_size >= PPC_MMIO_START)
+		die("Too much memory (%lld, what a nice problem): "
+		    "overlaps MMIO!\n",
+		    phys_size);
+
+	kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+}
+
+void kvm__arch_set_cmdline(char *cmdline, bool video)
+{
+	/* We don't need anything unusual in here. */
+}
+
+/* Architecture-specific KVM init */
+void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size)
+{
+	int cap_ppc_rma;
+	unsigned long hpt;
+
+	kvm->ram_size		= ram_size;
+
+	/*
+	 * Currently, HV-mode PPC64 SPAPR requires that we map from hugetlfs.
+	 * Allow a 'default' option to assist.
+	 * PR-mode does not require this.
+	 */
+	if (hugetlbfs_path) {
+		if (!strcmp(hugetlbfs_path, "default"))
+			hugetlbfs_path = HUGETLBFS_PATH;
+		kvm->ram_start = mmap_hugetlbfs(hugetlbfs_path, kvm->ram_size);
+	} else {
+		kvm->ram_start = mmap(0, kvm->ram_size, PROT_READ | PROT_WRITE,
+				      MAP_ANON | MAP_PRIVATE,
+				      -1, 0);
+	}
+	if (kvm->ram_start == MAP_FAILED)
+		die("Couldn't map %lld bytes for RAM (%d)\n",
+		    kvm->ram_size, errno);
+
+	/* FDT goes at top of memory, RTAS just below */
+	kvm->fdt_gra = kvm->ram_size - FDT_MAX_SIZE;
+	/* FIXME: Not all PPC systems have RTAS */
+	kvm->rtas_gra = kvm->fdt_gra - RTAS_MAX_SIZE;
+	madvise(kvm->ram_start, kvm->ram_size, MADV_MERGEABLE);
+
+	/* FIXME:  SPAPR-PR specific; allocate a guest HPT. */
+	if (posix_memalign((void **)&hpt, (1<<HPT_ORDER), (1<<HPT_ORDER)))
+		die("Can't allocate %d bytes for HPT\n", (1<<HPT_ORDER));
+
+	kvm->sdr1 = ((hpt + 0x3ffffULL) & ~0x3ffffULL) | (HPT_ORDER-18);
+
+	kvm->pvr = mfpvr();
+
+	/* FIXME: This is book3s-specific */
+	cap_ppc_rma = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_PPC_RMA);
+	if (cap_ppc_rma == 2)
+		die("Need contiguous RMA allocation on this hardware, "
+		    "which is not yet supported.");
+
+	/* Do these before FDT setup, IRQ setup, etc. */
+	/* FIXME: SPAPR-specific */
+	hypercall_init();
+	register_core_rtas();
+	/* Now that hypercalls are initialised, register a couple for the console: */
+	spapr_hvcons_init();
+	spapr_create_phb(kvm, "pci", SPAPR_PCI_BUID,
+			 SPAPR_PCI_MEM_WIN_ADDR,
+			 SPAPR_PCI_MEM_WIN_SIZE,
+			 SPAPR_PCI_IO_WIN_ADDR,
+			 SPAPR_PCI_IO_WIN_SIZE);
+}
+
+void kvm__arch_delete_ram(struct kvm *kvm)
+{
+	munmap(kvm->ram_start, kvm->ram_size);
+}
+
+void kvm__irq_trigger(struct kvm *kvm, int irq)
+{
+	kvm__irq_line(kvm, irq, 1);
+	kvm__irq_line(kvm, irq, 0);
+}
+
+void kvm__arch_periodic_poll(struct kvm *kvm)
+{
+	/* FIXME: Should register callbacks to platform-specific polls */
+	spapr_hvcons_poll(kvm);
+}
+
+int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline)
+{
+	void *p;
+	void *k_start;
+	void *i_start;
+	int nr;
+
+	if (lseek(fd_kernel, 0, SEEK_SET) < 0)
+		die_perror("lseek");
+
+	p = k_start = guest_flat_to_host(kvm, KERNEL_LOAD_ADDR);
+
+	while ((nr = read(fd_kernel, p, 65536)) > 0)
+		p += nr;
+
+	pr_info("Loaded kernel to 0x%x (%ld bytes)", KERNEL_LOAD_ADDR, p-k_start);
+
+	if (fd_initrd != -1) {
+		if (lseek(fd_initrd, 0, SEEK_SET) < 0)
+			die_perror("lseek");
+
+		if (p-k_start > INITRD_LOAD_ADDR)
+			die("Kernel overlaps initrd!");
+
+		/* Round up kernel size to 8byte alignment, and load initrd right after. */
+		i_start = p = guest_flat_to_host(kvm, INITRD_LOAD_ADDR);
+
+		while (((nr = read(fd_initrd, p, 65536)) > 0) &&
+		       p < (kvm->ram_start + kvm->ram_size))
+			p += nr;
+
+		if (p >= (kvm->ram_start + kvm->ram_size))
+			die("initrd too big to contain in guest RAM.\n");
+
+		pr_info("Loaded initrd to 0x%x (%ld bytes)",
+			INITRD_LOAD_ADDR, p-i_start);
+		kvm->initrd_gra = INITRD_LOAD_ADDR;
+		kvm->initrd_size = p-i_start;
+	} else {
+		kvm->initrd_size = 0;
+	}
+	strncpy(kern_cmdline, kernel_cmdline, 2048);
+	kern_cmdline[2047] = '\0';
+
+	return true;
+}
+
+bool load_bzimage(struct kvm *kvm, int fd_kernel,
+		  int fd_initrd, const char *kernel_cmdline, u16 vidmode)
+{
+	/* We don't support bzImages. */
+	return false;
+}
+
+#define SMT_THREADS 4
+
+/*
+ * Set up the FDT for the kernel: This function is currently fairly SPAPR-heavy,
+ * and whilst most PPC targets will require CPU/memory nodes, others like RTAS
+ * should eventually be added separately.
+ */
+static void setup_fdt(struct kvm *kvm)
+{
+	uint64_t 	mem_reg_property[] = { 0, cpu_to_be64(kvm->ram_size) };
+	int 		smp_cpus = kvm->nrcpus;
+	uint32_t	int_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
+	char 		hypertas_prop_kvm[] = "hcall-pft\0hcall-term\0"
+		"hcall-dabr\0hcall-interrupt\0hcall-tce\0hcall-vio\0"
+		"hcall-splpar\0hcall-bulk";
+	int 		i, j;
+	char 		cpu_name[30];
+	u8		staging_fdt[FDT_MAX_SIZE];
+	struct cpu_info *cpu_info = find_cpu_info(kvm->pvr);
+
+	/* Generate an appropriate DT at kvm->fdt_gra */
+	void *fdt_dest = guest_flat_to_host(kvm, kvm->fdt_gra);
+	void *fdt = staging_fdt;
+
+	_FDT(fdt_create(fdt, FDT_MAX_SIZE));
+	_FDT(fdt_finish_reservemap(fdt));
+
+	_FDT(fdt_begin_node(fdt, ""));
+
+	_FDT(fdt_property_string(fdt, "device_type", "chrp"));
+	_FDT(fdt_property_string(fdt, "model", "IBM pSeries (kvmtool)"));
+	_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
+	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
+
+	/* RTAS */
+	_FDT(fdt_begin_node(fdt, "rtas"));
+	/* This is what the kernel uses to switch 'We're an LPAR'! */
+        _FDT(fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop_kvm,
+                           sizeof(hypertas_prop_kvm)));
+	_FDT(fdt_property_cell(fdt, "linux,rtas-base", kvm->rtas_gra));
+	_FDT(fdt_property_cell(fdt, "linux,rtas-entry", kvm->rtas_gra));
+	_FDT(fdt_property_cell(fdt, "rtas-size", kvm->rtas_size));
+	/* Now add properties for all RTAS tokens: */
+	if (spapr_rtas_fdt_setup(kvm, fdt))
+		die("Couldn't create RTAS FDT properties\n");
+
+	_FDT(fdt_end_node(fdt));
+
+	/* /chosen */
+	_FDT(fdt_begin_node(fdt, "chosen"));
+	/* cmdline */
+	_FDT(fdt_property_string(fdt, "bootargs", kern_cmdline));
+	/* Initrd */
+	if (kvm->initrd_size != 0) {
+		uint32_t ird_st_prop = cpu_to_be32(kvm->initrd_gra);
+		uint32_t ird_end_prop = cpu_to_be32(kvm->initrd_gra +
+						    kvm->initrd_size);
+		_FDT(fdt_property(fdt, "linux,initrd-start",
+				   &ird_st_prop, sizeof(ird_st_prop)));
+		_FDT(fdt_property(fdt, "linux,initrd-end",
+				   &ird_end_prop, sizeof(ird_end_prop)));
+	}
+
+	/*
+	 * stdout-path: This is assuming we're using the HV console.  Also, the
+	 * address is hardwired until we do a VIO bus.
+	 */
+	_FDT(fdt_property_string(fdt, "linux,stdout-path",
+				 "/vdevice/vty@30000000"));
+	_FDT(fdt_end_node(fdt));
+
+	/*
+	 * Memory: We don't alloc. a separate RMA yet.  If we ever need to
+	 * (CAP_PPC_RMA == 2) then have one memory node for 0->RMAsize, and
+	 * another RMAsize->endOfMem.
+	 */
+	_FDT(fdt_begin_node(fdt, "memory@0"));
+	_FDT(fdt_property_string(fdt, "device_type", "memory"));
+	_FDT(fdt_property(fdt, "reg", mem_reg_property,
+			  sizeof(mem_reg_property)));
+	_FDT(fdt_end_node(fdt));
+
+	/* CPUs */
+	_FDT(fdt_begin_node(fdt, "cpus"));
+	_FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
+	_FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
+
+	for (i = 0; i < smp_cpus; i += SMT_THREADS) {
+		int32_t pft_size_prop[] = { 0, HPT_ORDER };
+		uint32_t servers_prop[SMT_THREADS];
+		uint32_t gservers_prop[SMT_THREADS * 2];
+		int threads = (smp_cpus - i) >= SMT_THREADS ? SMT_THREADS :
+			smp_cpus - i;
+
+		sprintf(cpu_name, "PowerPC,%s@%d", cpu_info->name, i);
+		_FDT(fdt_begin_node(fdt, cpu_name));
+		sprintf(cpu_name, "PowerPC,%s", cpu_info->name);
+		_FDT(fdt_property_string(fdt, "name", cpu_name));
+		_FDT(fdt_property_string(fdt, "device_type", "cpu"));
+
+		_FDT(fdt_property_cell(fdt, "reg", i));
+		_FDT(fdt_property_cell(fdt, "cpu-version", kvm->pvr));
+
+		_FDT(fdt_property_cell(fdt, "dcache-block-size", cpu_info->d_bsize));
+		_FDT(fdt_property_cell(fdt, "icache-block-size", cpu_info->i_bsize));
+
+		_FDT(fdt_property_cell(fdt, "timebase-frequency", cpu_info->tb_freq));
+		/* Lies, but safeish lies! */
+		_FDT(fdt_property_cell(fdt, "clock-frequency", 0xddbab200));
+
+		if (cpu_info->slb_size)
+			_FDT(fdt_property_cell(fdt, "ibm,slb-size", cpu_info->slb_size));
+		/*
+		 * HPT size is hardwired; KVM currently fixes it at 16MB but the
+		 * moment that changes we'll need to read it out of the kernel.
+		 */
+		_FDT(fdt_property(fdt, "ibm,pft-size", pft_size_prop,
+				  sizeof(pft_size_prop)));
+
+		_FDT(fdt_property_string(fdt, "status", "okay"));
+		_FDT(fdt_property(fdt, "64-bit", NULL, 0));
+		/* A server for each thread in this core */
+		for (j = 0; j < SMT_THREADS; j++) {
+			servers_prop[j] = cpu_to_be32(i+j);
+			/*
+			 * Hack borrowed from QEMU, direct the group queues back
+			 * to cpu 0:
+			 */
+			gservers_prop[j*2] = cpu_to_be32(i+j);
+			gservers_prop[j*2 + 1] = 0;
+		}
+		_FDT(fdt_property(fdt, "ibm,ppc-interrupt-server#s",
+				   servers_prop, threads * sizeof(uint32_t)));
+		_FDT(fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
+				  gservers_prop,
+				  threads * 2 * sizeof(uint32_t)));
+		if (cpu_info->page_sizes_prop)
+			_FDT(fdt_property(fdt, "ibm,segment-page-sizes",
+					  cpu_info->page_sizes_prop,
+					  cpu_info->page_sizes_prop_len));
+		if (cpu_info->segment_sizes_prop)
+			_FDT(fdt_property(fdt, "ibm,processor-segment-sizes",
+					  cpu_info->segment_sizes_prop,
+					  cpu_info->segment_sizes_prop_len));
+		/* VSX / DFP options: */
+		if (cpu_info->flags & CPUINFO_FLAG_VMX)
+			_FDT(fdt_property_cell(fdt, "ibm,vmx",
+					       (cpu_info->flags &
+						CPUINFO_FLAG_VSX) ? 2 : 1));
+		if (cpu_info->flags & CPUINFO_FLAG_DFP)
+			_FDT(fdt_property_cell(fdt, "ibm,dfp", 0x1));
+		_FDT(fdt_end_node(fdt));
+	}
+	_FDT(fdt_end_node(fdt));
+
+	/* IRQ controller */
+	_FDT(fdt_begin_node(fdt, "interrupt-controller@0"));
+
+	_FDT(fdt_property_string(fdt, "device_type",
+				 "PowerPC-External-Interrupt-Presentation"));
+	_FDT(fdt_property_string(fdt, "compatible", "IBM,ppc-xicp"));
+	_FDT(fdt_property_cell(fdt, "reg", 0));
+	_FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
+	_FDT(fdt_property(fdt, "ibm,interrupt-server-ranges",
+			   int_server_ranges_prop,
+			   sizeof(int_server_ranges_prop)));
+	_FDT(fdt_property_cell(fdt, "#interrupt-cells", 2));
+	_FDT(fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP));
+	_FDT(fdt_property_cell(fdt, "phandle", PHANDLE_XICP));
+	_FDT(fdt_end_node(fdt));
+
+	/*
+	 * VIO: See comment in linux,stdout-path; we don't yet represent a VIO
+	 * bus/address allocation so addresses are hardwired here.
+	 */
+	_FDT(fdt_begin_node(fdt, "vdevice"));
+	_FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
+	_FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
+	_FDT(fdt_property_string(fdt, "device_type", "vdevice"));
+	_FDT(fdt_property_string(fdt, "compatible", "IBM,vdevice"));
+	_FDT(fdt_begin_node(fdt, "vty@30000000"));
+	_FDT(fdt_property_string(fdt, "name", "vty"));
+	_FDT(fdt_property_string(fdt, "device_type", "serial"));
+	_FDT(fdt_property_string(fdt, "compatible", "hvterm1"));
+	_FDT(fdt_property_cell(fdt, "reg", 0x30000000));
+	_FDT(fdt_end_node(fdt));
+	_FDT(fdt_end_node(fdt));
+
+	/* Finalise: */
+	_FDT(fdt_end_node(fdt)); /* Root node */
+	_FDT(fdt_finish(fdt));
+
+	_FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
+
+	/* PCI */
+	if (spapr_populate_pci_devices(kvm, PHANDLE_XICP, fdt_dest))
+		die("Fail populating PCI device nodes");
+
+	_FDT(fdt_add_mem_rsv(fdt_dest, kvm->rtas_gra, kvm->rtas_size));
+	_FDT(fdt_pack(fdt_dest));
+}
+
+/**
+ * kvm__arch_setup_firmware
+ */
+int kvm__arch_setup_firmware(struct kvm *kvm)
+{
+	/*
+	 * Set up RTAS stub.  All it is is a single hypercall:
+	 *  0:   7c 64 1b 78     mr      r4,r3
+	 *  4:   3c 60 00 00     lis     r3,0
+	 *  8:   60 63 f0 00     ori     r3,r3,61440
+	 *  c:   44 00 00 22     sc      1
+	 * 10:   4e 80 00 20     blr
+	 */
+	uint32_t *rtas = guest_flat_to_host(kvm, kvm->rtas_gra);
+
+	rtas[0] = 0x7c641b78;
+	rtas[1] = 0x3c600000;
+	rtas[2] = 0x6063f000;
+	rtas[3] = 0x44000022;
+	rtas[4] = 0x4e800020;
+	kvm->rtas_size = 20;
+
+	pr_info("Set up %ld bytes of RTAS at 0x%lx\n",
+		kvm->rtas_size, kvm->rtas_gra);
+
+	/* Load SLOF */
+
+	/* Init FDT */
+	setup_fdt(kvm);
+
+	return 0;
+}
+
+int kvm__arch_free_firmware(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/tools/kvm/powerpc/spapr.h b/tools/kvm/powerpc/spapr.h
new file mode 100644
index 0000000..0537f88
--- /dev/null
+++ b/tools/kvm/powerpc/spapr.h
@@ -0,0 +1,93 @@
+/*
+ * SPAPR definitions and declarations
+ *
+ * Borrowed heavily from QEMU's spapr.h,
+ * Copyright (c) 2010 David Gibson, IBM Corporation.
+ *
+ * Modifications by Matt Evans <matt@ozlabs.org>, IBM 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.
+ */
+
+#if !defined(__HW_SPAPR_H__)
+#define __HW_SPAPR_H__
+
+#include <inttypes.h>
+
+/* We need some of the H_ hcall defs, but they're __KERNEL__ only. */
+#define __KERNEL__
+#include <asm/hvcall.h>
+#undef __KERNEL__
+
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+
+typedef unsigned long target_ulong;
+typedef uintptr_t target_phys_addr_t;
+
+/*
+ * The hcalls above are standardized in PAPR and implemented by pHyp
+ * as well.
+ *
+ * We also need some hcalls which are specific to qemu / KVM-on-POWER.
+ * So far we just need one for H_RTAS, but in future we'll need more
+ * for extensions like virtio.  We put those into the 0xf000-0xfffc
+ * range which is reserved by PAPR for "platform-specific" hcalls.
+ */
+#define KVMPPC_HCALL_BASE       0xf000
+#define KVMPPC_H_RTAS           (KVMPPC_HCALL_BASE + 0x0)
+#define KVMPPC_HCALL_MAX        KVMPPC_H_RTAS
+
+#define DEBUG_SPAPR_HCALLS
+
+#ifdef DEBUG_SPAPR_HCALLS
+#define hcall_dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define hcall_dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+typedef target_ulong (*spapr_hcall_fn)(struct kvm_cpu *vcpu,
+				       target_ulong opcode,
+                                       target_ulong *args);
+
+void hypercall_init(void);
+void register_core_rtas(void);
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
+target_ulong spapr_hypercall(struct kvm_cpu *vcpu, target_ulong opcode,
+                             target_ulong *args);
+
+int spapr_rtas_fdt_setup(struct kvm *kvm, void *fdt);
+
+static inline uint32_t rtas_ld(struct kvm *kvm, target_ulong phys, int n)
+{
+	return *((uint32_t *)guest_flat_to_host(kvm, phys + 4*n));
+}
+
+static inline void rtas_st(struct kvm *kvm, target_ulong phys, int n, uint32_t val)
+{
+	*((uint32_t *)guest_flat_to_host(kvm, phys + 4*n)) = val;
+}
+
+typedef void (*spapr_rtas_fn)(struct kvm_cpu *vcpu, uint32_t token,
+                              uint32_t nargs, target_ulong args,
+                              uint32_t nret, target_ulong rets);
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn);
+target_ulong spapr_rtas_call(struct kvm_cpu *vcpu,
+                             uint32_t token, uint32_t nargs, target_ulong args,
+                             uint32_t nret, target_ulong rets);
+
+#define SPAPR_PCI_BUID          0x800000020000001ULL
+#define SPAPR_PCI_MEM_WIN_ADDR  (KVM_MMIO_START + 0xA0000000)
+#define SPAPR_PCI_MEM_WIN_SIZE  0x20000000
+#define SPAPR_PCI_IO_WIN_ADDR   (SPAPR_PCI_MEM_WIN_ADDR + SPAPR_PCI_MEM_WIN_SIZE)
+#define SPAPR_PCI_IO_WIN_SIZE	0x2000000
+
+#define SPAPR_PCI_WIN_START	SPAPR_PCI_MEM_WIN_ADDR
+#define SPAPR_PCI_WIN_END	(SPAPR_PCI_IO_WIN_ADDR + SPAPR_PCI_IO_WIN_SIZE)
+
+#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/tools/kvm/powerpc/spapr_hcall.c b/tools/kvm/powerpc/spapr_hcall.c
new file mode 100644
index 0000000..ff1d63a
--- /dev/null
+++ b/tools/kvm/powerpc/spapr_hcall.c
@@ -0,0 +1,134 @@
+/*
+ * SPAPR hypercalls
+ *
+ * Borrowed heavily from QEMU's spapr_hcall.c,
+ * Copyright (c) 2010 David Gibson, IBM Corporation.
+ *
+ * Copyright (c) 2011 Matt Evans <matt@ozlabs.org>, IBM 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.
+ */
+
+#include "spapr.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
+static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX -
+					     KVMPPC_HCALL_BASE + 1];
+
+static target_ulong h_set_dabr(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+	/* FIXME:  Implement this for -PR.  (-HV does this in kernel.) */
+	return H_HARDWARE;
+}
+
+static target_ulong h_rtas(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+	target_ulong rtas_r3 = args[0];
+	/*
+	 * Pointer read from phys mem; these ptrs cannot be MMIO (!) so just
+	 * reference guest RAM directly.
+	 */
+	uint32_t token, nargs, nret;
+
+	token = rtas_ld(vcpu->kvm, rtas_r3, 0);
+	nargs = rtas_ld(vcpu->kvm, rtas_r3, 1);
+	nret  = rtas_ld(vcpu->kvm, rtas_r3, 2);
+
+	return spapr_rtas_call(vcpu, token, nargs, rtas_r3 + 12,
+			       nret, rtas_r3 + 12 + 4*nargs);
+}
+
+static target_ulong h_logical_load(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+	/* SLOF will require these, though kernel doesn't. */
+	die(__PRETTY_FUNCTION__);
+	return H_PARAMETER;
+}
+
+static target_ulong h_logical_store(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+	/* SLOF will require these, though kernel doesn't. */
+	die(__PRETTY_FUNCTION__);
+	return H_PARAMETER;
+}
+
+static target_ulong h_logical_icbi(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+	/* KVM will trap this in the kernel.  Die if it misses. */
+	die(__PRETTY_FUNCTION__);
+	return H_SUCCESS;
+}
+
+static target_ulong h_logical_dcbf(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+	/* KVM will trap this in the kernel.  Die if it misses. */
+	die(__PRETTY_FUNCTION__);
+	return H_SUCCESS;
+}
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
+{
+	spapr_hcall_fn *slot;
+
+	if (opcode <= MAX_HCALL_OPCODE) {
+		assert((opcode & 0x3) == 0);
+
+		slot = &papr_hypercall_table[opcode / 4];
+	} else {
+		assert((opcode >= KVMPPC_HCALL_BASE) &&
+		       (opcode <= KVMPPC_HCALL_MAX));
+
+		slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
+	}
+
+	assert(!(*slot) || (fn == *slot));
+	*slot = fn;
+}
+
+target_ulong spapr_hypercall(struct kvm_cpu *vcpu, target_ulong opcode,
+			     target_ulong *args)
+{
+	if ((opcode <= MAX_HCALL_OPCODE)
+	    && ((opcode & 0x3) == 0)) {
+		spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
+
+		if (fn) {
+			return fn(vcpu, opcode, args);
+		}
+	} else if ((opcode >= KVMPPC_HCALL_BASE) &&
+		   (opcode <= KVMPPC_HCALL_MAX)) {
+		spapr_hcall_fn fn = kvmppc_hypercall_table[opcode -
+							   KVMPPC_HCALL_BASE];
+
+		if (fn) {
+			return fn(vcpu, opcode, args);
+		}
+	}
+
+	hcall_dprintf("Unimplemented hcall 0x%lx\n", opcode);
+	return H_FUNCTION;
+}
+
+void hypercall_init(void)
+{
+	/* hcall-dabr */
+	spapr_register_hypercall(H_SET_DABR, h_set_dabr);
+
+	spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
+	spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
+	spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
+	spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
+	spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
+	spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
+
+	/* KVM-PPC specific hcalls */
+	spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
+}
diff --git a/tools/kvm/powerpc/spapr_hvcons.c b/tools/kvm/powerpc/spapr_hvcons.c
new file mode 100644
index 0000000..511dbe1
--- /dev/null
+++ b/tools/kvm/powerpc/spapr_hvcons.c
@@ -0,0 +1,102 @@
+/*
+ * SPAPR HV console
+ *
+ * Borrowed lightly from QEMU's spapr_vty.c, Copyright (c) 2010 David Gibson,
+ * IBM Corporation.
+ *
+ * Copyright (c) 2011 Matt Evans <matt@ozlabs.org>, IBM 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.
+ */
+
+#include "kvm/term.h"
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/util.h"
+#include "spapr.h"
+#include "spapr_hvcons.h"
+
+#include <stdio.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#include <linux/byteorder.h>
+
+union hv_chario {
+	struct {
+		uint64_t char0_7;
+		uint64_t char8_15;
+	} a;
+	uint8_t buf[16];
+};
+
+static unsigned long h_put_term_char(struct kvm_cpu *vcpu, unsigned long opcode, unsigned long *args)
+{
+	/* To do: Read register from args[0], and check it. */
+	unsigned long len = args[1];
+	union hv_chario data;
+	struct iovec iov;
+
+	if (len > 16) {
+		return H_PARAMETER;
+	}
+	data.a.char0_7 = cpu_to_be64(args[2]);
+	data.a.char8_15 = cpu_to_be64(args[3]);
+
+	iov.iov_base = data.buf;
+	iov.iov_len = len;
+	do {
+		int ret;
+
+		ret = term_putc_iov(CONSOLE_HV, &iov, 1, 0);
+		if (ret < 0) {
+			die("term_putc_iov error %d!\n", errno);
+		}
+		iov.iov_base += ret;
+		iov.iov_len -= ret;
+	} while (iov.iov_len > 0);
+
+	return H_SUCCESS;
+}
+
+
+static unsigned long h_get_term_char(struct kvm_cpu *vcpu, unsigned long opcode, unsigned long *args)
+{
+	/* To do: Read register from args[0], and check it. */
+	unsigned long *len = args + 0;
+	unsigned long *char0_7 = args + 1;
+	unsigned long *char8_15 = args + 2;
+	union hv_chario data;
+	struct iovec iov;
+
+	if (term_readable(CONSOLE_HV, 0)) {
+		iov.iov_base = data.buf;
+		iov.iov_len = 16;
+
+		*len = term_getc_iov(CONSOLE_HV, &iov, 1, 0);
+		*char0_7 = be64_to_cpu(data.a.char0_7);
+		*char8_15 = be64_to_cpu(data.a.char8_15);
+	} else {
+		*len = 0;
+	}
+
+	return H_SUCCESS;
+}
+
+void spapr_hvcons_poll(struct kvm *kvm)
+{
+	if (term_readable(CONSOLE_HV, 0)) {
+		/*
+		 * We can inject an IRQ to guest here if we want.  The guest
+		 * will happily poll, though, so not required.
+		 */
+	}
+}
+
+void spapr_hvcons_init(void)
+{
+	spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
+	spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
+}
diff --git a/tools/kvm/powerpc/spapr_hvcons.h b/tools/kvm/powerpc/spapr_hvcons.h
new file mode 100644
index 0000000..d3e4414
--- /dev/null
+++ b/tools/kvm/powerpc/spapr_hvcons.h
@@ -0,0 +1,19 @@
+/*
+ * SPAPR HV console
+ *
+ * Copyright (c) 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef spapr_hvcons_H
+#define spapr_hvcons_H
+
+#include "kvm/kvm.h"
+
+void spapr_hvcons_init(void);
+void spapr_hvcons_poll(struct kvm *kvm);
+
+#endif
diff --git a/tools/kvm/powerpc/spapr_pci.c b/tools/kvm/powerpc/spapr_pci.c
new file mode 100644
index 0000000..f9d29f0
--- /dev/null
+++ b/tools/kvm/powerpc/spapr_pci.c
@@ -0,0 +1,423 @@
+/*
+ * SPAPR PHB emulation, RTAS interface to PCI config space, device tree nodes
+ * for enumerated devices.
+ *
+ * Borrowed heavily from QEMU's spapr_pci.c,
+ * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation.
+ * Copyright (c) 2011 David Gibson, IBM Corporation.
+ *
+ * Modifications copyright 2011 Matt Evans <matt@ozlabs.org>, IBM 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.
+ */
+
+#include "spapr.h"
+#include "spapr_pci.h"
+#include "kvm/util.h"
+#include "kvm/pci.h"
+#include "libfdt.h"
+
+#include <linux/pci_regs.h>
+#include <linux/byteorder.h>
+
+
+/* #define DEBUG_PHB yes */
+#ifdef DEBUG_PHB
+#define phb_dprintf(fmt, ...)					\
+	do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define phb_dprintf(fmt, ...)			\
+	do { } while (0)
+#endif
+
+static const uint32_t bars[] = {
+	PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1,
+	PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3,
+	PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5
+	/*, PCI_ROM_ADDRESS*/
+};
+
+#define PCI_NUM_REGIONS		7
+
+/* Macros to operate with address in OF binding to PCI */
+#define b_x(x, p, l)	(((x) & ((1<<(l))-1)) << (p))
+#define b_n(x)		b_x((x), 31, 1) /* 0 if relocatable */
+#define b_p(x)		b_x((x), 30, 1) /* 1 if prefetchable */
+#define b_t(x)		b_x((x), 29, 1) /* 1 if the address is aliased */
+#define b_ss(x)		b_x((x), 24, 2) /* the space code */
+#define b_bbbbbbbb(x)	b_x((x), 16, 8) /* bus number */
+#define b_ddddd(x)	b_x((x), 11, 5) /* device number */
+#define b_fff(x)	b_x((x), 8, 3)	/* function number */
+#define b_rrrrrrrr(x)	b_x((x), 0, 8)	/* register number */
+
+#define SS_M64		3
+#define SS_M32		2
+#define SS_IO		1
+#define SS_CONFIG	0
+
+
+static struct spapr_phb phb;
+
+
+static void rtas_ibm_read_pci_config(struct kvm_cpu *vcpu,
+				     uint32_t token, uint32_t nargs,
+				     target_ulong args,
+				     uint32_t nret, target_ulong rets)
+{
+	uint32_t val = 0;
+	uint64_t buid = ((uint64_t)rtas_ld(vcpu->kvm, args, 1) << 32) | rtas_ld(vcpu->kvm, args, 2);
+	union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
+	struct pci_device_header *dev = pci__find_dev(addr.device_number);
+	uint32_t size = rtas_ld(vcpu->kvm, args, 3);
+
+	if (buid != phb.buid || !dev || (size > 4)) {
+		phb_dprintf("- cfgRd buid 0x%lx cfg addr 0x%x size %d not found\n",
+			    buid, addr.w, size);
+
+		rtas_st(vcpu->kvm, rets, 0, -1);
+		return;
+	}
+	pci__config_rd(vcpu->kvm, addr, &val, size);
+	/* It appears this wants a byteswapped result... */
+	switch (size) {
+	case 4:
+		val = le32_to_cpu(val);
+		break;
+	case 2:
+		val = le16_to_cpu(val>>16);
+		break;
+	case 1:
+		val = val >> 24;
+		break;
+	}
+	phb_dprintf("- cfgRd buid 0x%lx addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
+		    buid, addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
+		    addr.register_number, val);
+
+	rtas_st(vcpu->kvm, rets, 0, 0);
+	rtas_st(vcpu->kvm, rets, 1, val);
+}
+
+static void rtas_read_pci_config(struct kvm_cpu *vcpu,
+				 uint32_t token, uint32_t nargs,
+				 target_ulong args,
+				 uint32_t nret, target_ulong rets)
+{
+	uint32_t val;
+	union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
+	struct pci_device_header *dev = pci__find_dev(addr.device_number);
+	uint32_t size = rtas_ld(vcpu->kvm, args, 1);
+
+	if (!dev || (size > 4)) {
+		rtas_st(vcpu->kvm, rets, 0, -1);
+		return;
+	}
+	pci__config_rd(vcpu->kvm, addr, &val, size);
+	switch (size) {
+	case 4:
+		val = le32_to_cpu(val);
+		break;
+	case 2:
+		val = le16_to_cpu(val>>16); /* We're yuck-endian. */
+		break;
+	case 1:
+		val = val >> 24;
+		break;
+	}
+	phb_dprintf("- cfgRd addr 0x%x size %d, val 0x%x\n", addr.w, size, val);
+	rtas_st(vcpu->kvm, rets, 0, 0);
+	rtas_st(vcpu->kvm, rets, 1, val);
+}
+
+static void rtas_ibm_write_pci_config(struct kvm_cpu *vcpu,
+				      uint32_t token, uint32_t nargs,
+				      target_ulong args,
+				      uint32_t nret, target_ulong rets)
+{
+	uint64_t buid = ((uint64_t)rtas_ld(vcpu->kvm, args, 1) << 32) | rtas_ld(vcpu->kvm, args, 2);
+	union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
+	struct pci_device_header *dev = pci__find_dev(addr.device_number);
+	uint32_t size = rtas_ld(vcpu->kvm, args, 3);
+	uint32_t val = rtas_ld(vcpu->kvm, args, 4);
+
+	if (buid != phb.buid || !dev || (size > 4)) {
+		phb_dprintf("- cfgWr buid 0x%lx cfg addr 0x%x/%d error (val 0x%x)\n",
+			    buid, addr.w, size, val);
+
+		rtas_st(vcpu->kvm, rets, 0, -1);
+		return;
+	}
+	phb_dprintf("- cfgWr buid 0x%lx addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
+		    buid, addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
+		    addr.register_number, val);
+	switch (size) {
+	case 4:
+		val = le32_to_cpu(val);
+		break;
+	case 2:
+		val = le16_to_cpu(val) << 16;
+		break;
+	case 1:
+		val = val >> 24;
+		break;
+	}
+	pci__config_wr(vcpu->kvm, addr, &val, size);
+	rtas_st(vcpu->kvm, rets, 0, 0);
+}
+
+static void rtas_write_pci_config(struct kvm_cpu *vcpu,
+				  uint32_t token, uint32_t nargs,
+				  target_ulong args,
+				  uint32_t nret, target_ulong rets)
+{
+	union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
+	struct pci_device_header *dev = pci__find_dev(addr.device_number);
+	uint32_t size = rtas_ld(vcpu->kvm, args, 1);
+	uint32_t val = rtas_ld(vcpu->kvm, args, 2);
+
+	if (!dev || (size > 4)) {
+		rtas_st(vcpu->kvm, rets, 0, -1);
+		return;
+	}
+
+	phb_dprintf("- cfgWr addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
+		    addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
+		    addr.register_number, val);
+	switch (size) {
+	case 4:
+		val = le32_to_cpu(val);
+		break;
+	case 2:
+		val = le16_to_cpu(val) << 16;
+		break;
+	case 1:
+		val = val >> 24;
+		break;
+	}
+	pci__config_wr(vcpu->kvm, addr, &val, size);
+	rtas_st(vcpu->kvm, rets, 0, 0);
+}
+
+void spapr_create_phb(struct kvm *kvm,
+		      const char *busname, uint64_t buid,
+		      uint64_t mem_win_addr, uint64_t mem_win_size,
+		      uint64_t io_win_addr, uint64_t io_win_size)
+{
+	/*
+	 * Since kvmtool doesn't really have any concept of buses etc.,
+	 * there's nothing to register here.  Just register RTAS.
+	 */
+	spapr_rtas_register("read-pci-config", rtas_read_pci_config);
+	spapr_rtas_register("write-pci-config", rtas_write_pci_config);
+	spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
+	spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
+
+	phb.buid = buid;
+	phb.mem_addr = mem_win_addr;
+	phb.mem_size = mem_win_size;
+	phb.io_addr  = io_win_addr;
+	phb.io_size  = io_win_size;
+
+	kvm->phb = &phb;
+}
+
+static uint32_t bar_to_ss(unsigned long bar)
+{
+	if ((bar & PCI_BASE_ADDRESS_SPACE) ==
+	    PCI_BASE_ADDRESS_SPACE_IO)
+		return SS_IO;
+	else if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64)
+		return SS_M64;
+	else
+		return SS_M32;
+}
+
+static unsigned long bar_to_addr(unsigned long bar)
+{
+	if ((bar & PCI_BASE_ADDRESS_SPACE) ==
+	    PCI_BASE_ADDRESS_SPACE_IO)
+		return bar & PCI_BASE_ADDRESS_IO_MASK;
+	else
+		return bar & PCI_BASE_ADDRESS_MEM_MASK;
+}
+
+int spapr_populate_pci_devices(struct kvm *kvm,
+			       uint32_t xics_phandle,
+			       void *fdt)
+{
+	int bus_off, node_off = 0, devid, fn, i, n, devices;
+	char nodename[256];
+	struct {
+		uint32_t hi;
+		uint64_t addr;
+		uint64_t size;
+	} __attribute__((packed)) reg[PCI_NUM_REGIONS + 1],
+		  assigned_addresses[PCI_NUM_REGIONS];
+	uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
+	struct {
+		uint32_t hi;
+		uint64_t child;
+		uint64_t parent;
+		uint64_t size;
+	} __attribute__((packed)) ranges[] = {
+		{
+			cpu_to_be32(b_ss(1)), cpu_to_be64(0),
+			cpu_to_be64(phb.io_addr),
+			cpu_to_be64(phb.io_size),
+		},
+		{
+			cpu_to_be32(b_ss(2)), cpu_to_be64(0),
+			cpu_to_be64(phb.mem_addr),
+			cpu_to_be64(phb.mem_size),
+		},
+	};
+	uint64_t bus_reg[] = { cpu_to_be64(phb.buid), 0 };
+	uint32_t interrupt_map_mask[] = {
+		cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0};
+	uint32_t interrupt_map[SPAPR_PCI_NUM_LSI][7];
+
+	/* Start populating the FDT */
+	sprintf(nodename, "pci@%" PRIx64, phb.buid);
+	bus_off = fdt_add_subnode(fdt, 0, nodename);
+	if (bus_off < 0) {
+		die("error making bus subnode, %s\n", fdt_strerror(bus_off));
+		return bus_off;
+	}
+
+	/* Write PHB properties */
+	_FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
+	_FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
+	_FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3));
+	_FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2));
+	_FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
+	_FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
+	_FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
+	_FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
+	_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
+	_FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
+			 &interrupt_map_mask, sizeof(interrupt_map_mask)));
+
+	/* Populate PCI devices and allocate IRQs */
+	devices = 0;
+
+	for (devid = 0; devid < PCI_MAX_DEVICES; devid++) {
+		uint32_t *irqmap = interrupt_map[devices];
+		struct pci_device_header *hdr = pci__find_dev(devid);
+
+		if (!hdr)
+			continue;
+
+		fn = 0; /* kvmtool doesn't yet do multifunction devices */
+
+		sprintf(nodename, "pci@%u,%u", devid, fn);
+
+		/* Allocate interrupt from the map */
+		if (devid > SPAPR_PCI_NUM_LSI)	{
+			die("Unexpected behaviour in spapr_populate_pci_devices,"
+			    "wrong devid %u\n", devid);
+		}
+		irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn));
+		irqmap[1] = 0;
+		irqmap[2] = 0;
+		irqmap[3] = 0;
+		irqmap[4] = cpu_to_be32(xics_phandle);
+		/*
+		 * This is nasty; the PCI devs are set up such that their own
+		 * header's irq_line indicates the direct XICS IRQ number to
+		 * use.  There REALLY needs to be a hierarchical system in place
+		 * to 'raise' an IRQ on the bridge which indexes/looks up which
+		 * XICS IRQ to fire.
+		 */
+		irqmap[5] = cpu_to_be32(hdr->irq_line);
+		irqmap[6] = cpu_to_be32(0x8);
+
+		/* Add node to FDT */
+		node_off = fdt_add_subnode(fdt, bus_off, nodename);
+		if (node_off < 0) {
+			die("error making node subnode, %s\n", fdt_strerror(bus_off));
+			return node_off;
+		}
+
+		_FDT(fdt_setprop_cell(fdt, node_off, "vendor-id",
+				      le16_to_cpu(hdr->vendor_id)));
+		_FDT(fdt_setprop_cell(fdt, node_off, "device-id",
+				      le16_to_cpu(hdr->device_id)));
+		_FDT(fdt_setprop_cell(fdt, node_off, "revision-id",
+				      hdr->revision_id));
+		_FDT(fdt_setprop_cell(fdt, node_off, "class-code",
+				      hdr->class[0] | (hdr->class[1] << 8) | (hdr->class[2] << 16)));
+		_FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id",
+				      le16_to_cpu(hdr->subsys_id)));
+		_FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id",
+				      le16_to_cpu(hdr->subsys_vendor_id)));
+
+		/* Config space region comes first */
+		reg[0].hi = cpu_to_be32(
+			b_n(0) |
+			b_p(0) |
+			b_t(0) |
+			b_ss(SS_CONFIG) |
+			b_bbbbbbbb(0) |
+			b_ddddd(devid) |
+			b_fff(fn));
+		reg[0].addr = 0;
+		reg[0].size = 0;
+
+		n = 0;
+		/* Six BARs, no ROM supported, addresses are 32bit */
+		for (i = 0; i < 6; ++i) {
+			if (0 == hdr->bar[i]) {
+				continue;
+			}
+
+			reg[n+1].hi = cpu_to_be32(
+				b_n(0) |
+				b_p(0) |
+				b_t(0) |
+				b_ss(bar_to_ss(le32_to_cpu(hdr->bar[i]))) |
+				b_bbbbbbbb(0) |
+				b_ddddd(devid) |
+				b_fff(fn) |
+				b_rrrrrrrr(bars[i]));
+			reg[n+1].addr = 0;
+			reg[n+1].size = cpu_to_be64(hdr->bar_size[i]);
+
+			assigned_addresses[n].hi = cpu_to_be32(
+				b_n(1) |
+				b_p(0) |
+				b_t(0) |
+				b_ss(bar_to_ss(le32_to_cpu(hdr->bar[i]))) |
+				b_bbbbbbbb(0) |
+				b_ddddd(devid) |
+				b_fff(fn) |
+				b_rrrrrrrr(bars[i]));
+
+			/*
+			 * Writing zeroes to assigned_addresses causes the guest kernel to
+			 * reassign BARs
+			 */
+			assigned_addresses[n].addr = cpu_to_be64(bar_to_addr(le32_to_cpu(hdr->bar[i])));
+			assigned_addresses[n].size = reg[n+1].size;
+
+			++n;
+		}
+		_FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1)));
+		_FDT(fdt_setprop(fdt, node_off, "assigned-addresses",
+				 assigned_addresses,
+				 sizeof(assigned_addresses[0])*(n)));
+		_FDT(fdt_setprop_cell(fdt, node_off, "interrupts",
+				      hdr->irq_pin));
+
+		/* We don't set ibm,dma-window property as we don't have an IOMMU. */
+
+		++devices;
+	}
+
+	/* Write interrupt map */
+	_FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
+			 devices * sizeof(interrupt_map[0])));
+
+	return 0;
+}
diff --git a/tools/kvm/powerpc/spapr_pci.h b/tools/kvm/powerpc/spapr_pci.h
new file mode 100644
index 0000000..48b221c
--- /dev/null
+++ b/tools/kvm/powerpc/spapr_pci.h
@@ -0,0 +1,57 @@
+/*
+ * SPAPR PHB definitions
+ *
+ * Modifications by Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef SPAPR_PCI_H
+#define SPAPR_PCI_H
+
+#include "kvm/kvm.h"
+#include "spapr.h"
+#include <inttypes.h>
+
+/* With XICS, we can easily accomodate 1 IRQ per PCI device. */
+
+#define SPAPR_PCI_NUM_LSI 256
+
+struct spapr_phb {
+	uint64_t buid;
+	uint64_t mem_addr;
+	uint64_t mem_size;
+	uint64_t io_addr;
+	uint64_t io_size;
+};
+
+void spapr_create_phb(struct kvm *kvm,
+                      const char *busname, uint64_t buid,
+                      uint64_t mem_win_addr, uint64_t mem_win_size,
+                      uint64_t io_win_addr, uint64_t io_win_size);
+
+int spapr_populate_pci_devices(struct kvm *kvm,
+                               uint32_t xics_phandle,
+                               void *fdt);
+
+static inline bool spapr_phb_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write)
+{
+	if ((phys_addr >= SPAPR_PCI_IO_WIN_ADDR) &&
+	    (phys_addr < SPAPR_PCI_IO_WIN_ADDR +
+	     SPAPR_PCI_IO_WIN_SIZE)) {
+		return kvm__emulate_io(kvm, phys_addr - SPAPR_PCI_IO_WIN_ADDR,
+				       data, is_write ? KVM_EXIT_IO_OUT :
+				       KVM_EXIT_IO_IN,
+				       len, 1);
+	} else if ((phys_addr >= SPAPR_PCI_MEM_WIN_ADDR) &&
+		   (phys_addr < SPAPR_PCI_MEM_WIN_ADDR +
+		    SPAPR_PCI_MEM_WIN_SIZE)) {
+		return kvm__emulate_mmio(kvm, phys_addr - SPAPR_PCI_MEM_WIN_ADDR,
+					 data, len, is_write);
+	}
+	return false;
+}
+
+#endif
diff --git a/tools/kvm/powerpc/spapr_rtas.c b/tools/kvm/powerpc/spapr_rtas.c
new file mode 100644
index 0000000..14a3462
--- /dev/null
+++ b/tools/kvm/powerpc/spapr_rtas.c
@@ -0,0 +1,229 @@
+/*
+ * SPAPR base RTAS calls
+ *
+ * Borrowed heavily from QEMU's spapr_rtas.c
+ * Copyright (c) 2010-2011 David Gibson, IBM Corporation.
+ *
+ * Modifications copyright 2011 Matt Evans <matt@ozlabs.org>, IBM 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.
+ */
+
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/util.h"
+#include "kvm/term.h"
+#include "libfdt.h"
+
+#include "spapr.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+#define TOKEN_BASE      0x2000
+#define TOKEN_MAX       0x100
+
+#define RTAS_CONSOLE
+
+static struct rtas_call {
+	const char *name;
+	spapr_rtas_fn fn;
+} rtas_table[TOKEN_MAX];
+
+struct rtas_call *rtas_next = rtas_table;
+
+
+static void rtas_display_character(struct kvm_cpu *vcpu,
+                                   uint32_t token, uint32_t nargs,
+                                   target_ulong args,
+                                   uint32_t nret, target_ulong rets)
+{
+	char c = rtas_ld(vcpu->kvm, args, 0);
+	term_putc(CONSOLE_HV, &c, 1, 0);
+	rtas_st(vcpu->kvm, rets, 0, 0);
+}
+
+#ifdef RTAS_CONSOLE
+static void rtas_put_term_char(struct kvm_cpu *vcpu,
+			       uint32_t token, uint32_t nargs,
+			       target_ulong args,
+			       uint32_t nret, target_ulong rets)
+{
+	char c = rtas_ld(vcpu->kvm, args, 0);
+	term_putc(CONSOLE_HV, &c, 1, 0);
+	rtas_st(vcpu->kvm, rets, 0, 0);
+}
+
+static void rtas_get_term_char(struct kvm_cpu *vcpu,
+			       uint32_t token, uint32_t nargs,
+			       target_ulong args,
+			       uint32_t nret, target_ulong rets)
+{
+	int c;
+	if (term_readable(CONSOLE_HV, 0) &&
+	    (c = term_getc(CONSOLE_HV, 0)) >= 0) {
+		rtas_st(vcpu->kvm, rets, 0, 0);
+		rtas_st(vcpu->kvm, rets, 1, c);
+	} else {
+		rtas_st(vcpu->kvm, rets, 0, -2);
+	}
+}
+#endif
+
+static void rtas_get_time_of_day(struct kvm_cpu *vcpu,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+	struct tm tm;
+	time_t tnow;
+
+	if (nret != 8) {
+		rtas_st(vcpu->kvm, rets, 0, -3);
+		return;
+	}
+
+	tnow = time(NULL);
+	/* Guest time is currently not offset in any way. */
+	gmtime_r(&tnow, &tm);
+
+	rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
+	rtas_st(vcpu->kvm, rets, 1, tm.tm_year + 1900);
+	rtas_st(vcpu->kvm, rets, 2, tm.tm_mon + 1);
+	rtas_st(vcpu->kvm, rets, 3, tm.tm_mday);
+	rtas_st(vcpu->kvm, rets, 4, tm.tm_hour);
+	rtas_st(vcpu->kvm, rets, 5, tm.tm_min);
+	rtas_st(vcpu->kvm, rets, 6, tm.tm_sec);
+	rtas_st(vcpu->kvm, rets, 7, 0);
+}
+
+static void rtas_set_time_of_day(struct kvm_cpu *vcpu,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+	pr_warning("%s called; TOD set ignored.\n", __FUNCTION__);
+}
+
+static void rtas_power_off(struct kvm_cpu *vcpu,
+                           uint32_t token, uint32_t nargs, target_ulong args,
+                           uint32_t nret, target_ulong rets)
+{
+	if (nargs != 2 || nret != 1) {
+		rtas_st(vcpu->kvm, rets, 0, -3);
+		return;
+	}
+	kvm_cpu__reboot();
+}
+
+static void rtas_query_cpu_stopped_state(struct kvm_cpu *vcpu,
+                                         uint32_t token, uint32_t nargs,
+                                         target_ulong args,
+                                         uint32_t nret, target_ulong rets)
+{
+	if (nargs != 1 || nret != 2) {
+		rtas_st(vcpu->kvm, rets, 0, -3);
+		return;
+	}
+
+	/*
+	 * Can read id = rtas_ld(vcpu->kvm, args, 0), but
+	 * we currently start all CPUs.  So just return true.
+	 */
+	rtas_st(vcpu->kvm, rets, 0, 0);
+	rtas_st(vcpu->kvm, rets, 1, 2);
+}
+
+static void rtas_start_cpu(struct kvm_cpu *vcpu,
+                           uint32_t token, uint32_t nargs,
+                           target_ulong args,
+                           uint32_t nret, target_ulong rets)
+{
+	die(__FUNCTION__);
+}
+
+target_ulong spapr_rtas_call(struct kvm_cpu *vcpu,
+                             uint32_t token, uint32_t nargs, target_ulong args,
+                             uint32_t nret, target_ulong rets)
+{
+	if ((token >= TOKEN_BASE)
+	    && ((token - TOKEN_BASE) < TOKEN_MAX)) {
+		struct rtas_call *call = rtas_table + (token - TOKEN_BASE);
+
+		if (call->fn) {
+			call->fn(vcpu, token, nargs, args, nret, rets);
+			return H_SUCCESS;
+		}
+	}
+
+	/*
+	 * HACK: Some Linux early debug code uses RTAS display-character,
+	 * but assumes the token value is 0xa (which it is on some real
+	 * machines) without looking it up in the device tree.  This
+	 * special case makes this work
+	 */
+	if (token == 0xa) {
+		rtas_display_character(vcpu, 0xa, nargs, args, nret, rets);
+		return H_SUCCESS;
+	}
+
+	hcall_dprintf("Unknown RTAS token 0x%x\n", token);
+	rtas_st(vcpu->kvm, rets, 0, -3);
+	return H_PARAMETER;
+}
+
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn)
+{
+	assert(rtas_next < (rtas_table + TOKEN_MAX));
+
+	rtas_next->name = name;
+	rtas_next->fn = fn;
+
+	rtas_next++;
+}
+
+/*
+ * This is called from the context of an open /rtas node, in order to add
+ * properties for the rtas call tokens.
+ */
+int spapr_rtas_fdt_setup(struct kvm *kvm, void *fdt)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < TOKEN_MAX; i++) {
+		struct rtas_call *call = &rtas_table[i];
+
+		if (!call->fn) {
+			continue;
+		}
+
+		ret = fdt_property_cell(fdt, call->name, i + TOKEN_BASE);
+
+		if (ret < 0) {
+			pr_warning("Couldn't add rtas token for %s: %s\n",
+				   call->name, fdt_strerror(ret));
+			return ret;
+		}
+
+	}
+	return 0;
+}
+
+void register_core_rtas(void)
+{
+	spapr_rtas_register("display-character", rtas_display_character);
+	spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
+	spapr_rtas_register("set-time-of-day", rtas_set_time_of_day);
+	spapr_rtas_register("power-off", rtas_power_off);
+	spapr_rtas_register("query-cpu-stopped-state",
+			    rtas_query_cpu_stopped_state);
+	spapr_rtas_register("start-cpu", rtas_start_cpu);
+#ifdef RTAS_CONSOLE
+	/* These are unused: We do console I/O via hcalls, not rtas. */
+	spapr_rtas_register("put-term-char", rtas_put_term_char);
+	spapr_rtas_register("get-term-char", rtas_get_term_char);
+#endif
+}
diff --git a/tools/kvm/powerpc/xics.c b/tools/kvm/powerpc/xics.c
new file mode 100644
index 0000000..2d70d3c
--- /dev/null
+++ b/tools/kvm/powerpc/xics.c
@@ -0,0 +1,514 @@
+/*
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Borrowed heavily from QEMU's xics.c,
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * Modifications copyright 2011 Matt Evans <matt@ozlabs.org>, IBM 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.
+ */
+
+#include "spapr.h"
+#include "xics.h"
+#include "kvm/util.h"
+
+#include <stdio.h>
+#include <malloc.h>
+
+
+/* #define DEBUG_XICS yes */
+#ifdef DEBUG_XICS
+#define xics_dprintf(fmt, ...)					\
+	do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define xics_dprintf(fmt, ...)			\
+	do { } while (0)
+#endif
+
+/*
+ * ICP: Presentation layer
+ */
+
+struct icp_server_state {
+	uint32_t xirr;
+	uint8_t pending_priority;
+	uint8_t mfrr;
+	struct kvm_cpu *cpu;
+};
+
+#define XICS_IRQ_OFFSET 16
+#define XISR_MASK	0x00ffffff
+#define CPPR_MASK	0xff000000
+
+#define XISR(ss)   (((ss)->xirr) & XISR_MASK)
+#define CPPR(ss)   (((ss)->xirr) >> 24)
+
+struct ics_state;
+
+struct icp_state {
+	unsigned long nr_servers;
+	struct icp_server_state *ss;
+	struct ics_state *ics;
+};
+
+static void ics_reject(struct ics_state *ics, int nr);
+static void ics_resend(struct ics_state *ics);
+static void ics_eoi(struct ics_state *ics, int nr);
+
+static inline void cpu_irq_raise(struct kvm_cpu *vcpu)
+{
+	xics_dprintf("INT1[%p]\n", vcpu);
+	kvm_cpu__irq(vcpu, POWER7_EXT_IRQ, 1);
+}
+
+static inline void cpu_irq_lower(struct kvm_cpu *vcpu)
+{
+	xics_dprintf("INT0[%p]\n", vcpu);
+	kvm_cpu__irq(vcpu, POWER7_EXT_IRQ, 0);
+}
+
+static void icp_check_ipi(struct icp_state *icp, int server)
+{
+	struct icp_server_state *ss = icp->ss + server;
+
+	if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
+		return;
+	}
+
+	if (XISR(ss)) {
+		ics_reject(icp->ics, XISR(ss));
+	}
+
+	ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
+	ss->pending_priority = ss->mfrr;
+	cpu_irq_raise(ss->cpu);
+}
+
+static void icp_resend(struct icp_state *icp, int server)
+{
+	struct icp_server_state *ss = icp->ss + server;
+
+	if (ss->mfrr < CPPR(ss)) {
+		icp_check_ipi(icp, server);
+	}
+	ics_resend(icp->ics);
+}
+
+static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
+{
+	struct icp_server_state *ss = icp->ss + server;
+	uint8_t old_cppr;
+	uint32_t old_xisr;
+
+	old_cppr = CPPR(ss);
+	ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
+
+	if (cppr < old_cppr) {
+		if (XISR(ss) && (cppr <= ss->pending_priority)) {
+			old_xisr = XISR(ss);
+			ss->xirr &= ~XISR_MASK; /* Clear XISR */
+			cpu_irq_lower(ss->cpu);
+			ics_reject(icp->ics, old_xisr);
+		}
+	} else {
+		if (!XISR(ss)) {
+			icp_resend(icp, server);
+		}
+	}
+}
+
+static void icp_set_mfrr(struct icp_state *icp, int nr, uint8_t mfrr)
+{
+	struct icp_server_state *ss = icp->ss + nr;
+
+	ss->mfrr = mfrr;
+	if (mfrr < CPPR(ss)) {
+		icp_check_ipi(icp, nr);
+	}
+}
+
+static uint32_t icp_accept(struct icp_server_state *ss)
+{
+	uint32_t xirr;
+
+	cpu_irq_lower(ss->cpu);
+	xirr = ss->xirr;
+	ss->xirr = ss->pending_priority << 24;
+	return xirr;
+}
+
+static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
+{
+	struct icp_server_state *ss = icp->ss + server;
+
+	ics_eoi(icp->ics, xirr & XISR_MASK);
+	/* Send EOI -> ICS */
+	ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
+	if (!XISR(ss)) {
+		icp_resend(icp, server);
+	}
+}
+
+static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
+{
+	struct icp_server_state *ss = icp->ss + server;
+	xics_dprintf("icp_irq(nr %d, server %d, prio 0x%x)\n", nr, server, priority);
+	if ((priority >= CPPR(ss))
+	    || (XISR(ss) && (ss->pending_priority <= priority))) {
+		xics_dprintf("reject %d, CPPR 0x%x, XISR 0x%x, pprio 0x%x, prio 0x%x\n",
+			     nr, CPPR(ss), XISR(ss), ss->pending_priority, priority);
+		ics_reject(icp->ics, nr);
+	} else {
+		if (XISR(ss)) {
+			xics_dprintf("reject %d, CPPR 0x%x, XISR 0x%x, pprio 0x%x, prio 0x%x\n",
+				     nr, CPPR(ss), XISR(ss), ss->pending_priority, priority);
+			ics_reject(icp->ics, XISR(ss));
+		}
+		ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
+		ss->pending_priority = priority;
+		cpu_irq_raise(ss->cpu);
+	}
+}
+
+/*
+ * ICS: Source layer
+ */
+
+struct ics_irq_state {
+	int server;
+	uint8_t priority;
+	uint8_t saved_priority;
+	int rejected:1;
+	int masked_pending:1;
+};
+
+struct ics_state {
+	unsigned int nr_irqs;
+	unsigned int offset;
+	struct ics_irq_state *irqs;
+	struct icp_state *icp;
+};
+
+static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
+{
+	return (nr >= ics->offset)
+		&& (nr < (ics->offset + ics->nr_irqs));
+}
+
+static void ics_set_irq_msi(struct ics_state *ics, int srcno, int val)
+{
+	struct ics_irq_state *irq = ics->irqs + srcno;
+
+	if (val) {
+		if (irq->priority == 0xff) {
+			xics_dprintf(" irq pri ff, masked pending\n");
+			irq->masked_pending = 1;
+		} else	{
+			icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
+		}
+	}
+}
+
+static void ics_reject_msi(struct ics_state *ics, int nr)
+{
+	struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
+
+	irq->rejected = 1;
+}
+
+static void ics_resend_msi(struct ics_state *ics)
+{
+	unsigned int i;
+
+	for (i = 0; i < ics->nr_irqs; i++) {
+		struct ics_irq_state *irq = ics->irqs + i;
+
+		/* FIXME: filter by server#? */
+		if (irq->rejected) {
+			irq->rejected = 0;
+			if (irq->priority != 0xff) {
+				icp_irq(ics->icp, irq->server, i + ics->offset, irq->priority);
+			}
+		}
+	}
+}
+
+static void ics_write_xive_msi(struct ics_state *ics, int nr, int server,
+			       uint8_t priority)
+{
+	struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
+
+	irq->server = server;
+	irq->priority = priority;
+	xics_dprintf("ics_write_xive_msi(nr %d, server %d, pri 0x%x)\n", nr, server, priority);
+
+	if (!irq->masked_pending || (priority == 0xff)) {
+		return;
+	}
+
+	irq->masked_pending = 0;
+	icp_irq(ics->icp, server, nr, priority);
+}
+
+static void ics_reject(struct ics_state *ics, int nr)
+{
+	ics_reject_msi(ics, nr);
+}
+
+static void ics_resend(struct ics_state *ics)
+{
+	ics_resend_msi(ics);
+}
+
+static void ics_eoi(struct ics_state *ics, int nr)
+{
+}
+
+/*
+ * Exported functions
+ */
+
+static int allocated_irqnum = XICS_IRQ_OFFSET;
+
+/*
+ * xics_alloc_irqnum(): This is hacky.  The problem boils down to the PCI device
+ * code which just calls kvm__irq_line( .. pcidev->pci_hdr.irq_line ..) at will.
+ * Each PCI device's IRQ line is allocated by irq__register_device() (which
+ * allocates an IRQ AND allocates a.. PCI device num..).
+ *
+ * In future I'd like to at least mimic some kind of 'upstream IRQ controller'
+ * whereby PCI devices let their PHB know when they want to IRQ, and that
+ * percolates up.
+ *
+ * For now, allocate a REAL xics irq number and (via irq__register_device) push
+ * that into the config space.	8 bits only though!
+ */
+int xics_alloc_irqnum(void)
+{
+	int irq = allocated_irqnum++;
+
+	if (irq > 255)
+		die("Huge numbers of IRQs aren't supported with the daft kvmtool IRQ system.");
+
+	return irq;
+}
+
+static target_ulong h_cppr(struct kvm_cpu *vcpu,
+			   target_ulong opcode, target_ulong *args)
+{
+	target_ulong cppr = args[0];
+
+	xics_dprintf("h_cppr(%lx)\n", cppr);
+	icp_set_cppr(vcpu->kvm->icp, vcpu->cpu_id, cppr);
+	return H_SUCCESS;
+}
+
+static target_ulong h_ipi(struct kvm_cpu *vcpu,
+			  target_ulong opcode, target_ulong *args)
+{
+	target_ulong server = args[0];
+	target_ulong mfrr = args[1];
+
+	xics_dprintf("h_ipi(%lx, %lx)\n", server, mfrr);
+	if (server >= vcpu->kvm->icp->nr_servers) {
+		return H_PARAMETER;
+	}
+
+	icp_set_mfrr(vcpu->kvm->icp, server, mfrr);
+	return H_SUCCESS;
+}
+
+static target_ulong h_xirr(struct kvm_cpu *vcpu,
+			   target_ulong opcode, target_ulong *args)
+{
+	uint32_t xirr = icp_accept(vcpu->kvm->icp->ss + vcpu->cpu_id);
+
+	xics_dprintf("h_xirr() = %x\n", xirr);
+	args[0] = xirr;
+	return H_SUCCESS;
+}
+
+static target_ulong h_eoi(struct kvm_cpu *vcpu,
+			  target_ulong opcode, target_ulong *args)
+{
+	target_ulong xirr = args[0];
+
+	xics_dprintf("h_eoi(%lx)\n", xirr);
+	icp_eoi(vcpu->kvm->icp, vcpu->cpu_id, xirr);
+	return H_SUCCESS;
+}
+
+static void rtas_set_xive(struct kvm_cpu *vcpu, uint32_t token,
+			  uint32_t nargs, target_ulong args,
+			  uint32_t nret, target_ulong rets)
+{
+	struct ics_state *ics = vcpu->kvm->icp->ics;
+	uint32_t nr, server, priority;
+
+	if ((nargs != 3) || (nret != 1)) {
+		rtas_st(vcpu->kvm, rets, 0, -3);
+		return;
+	}
+
+	nr = rtas_ld(vcpu->kvm, args, 0);
+	server = rtas_ld(vcpu->kvm, args, 1);
+	priority = rtas_ld(vcpu->kvm, args, 2);
+
+	xics_dprintf("rtas_set_xive(%x,%x,%x)\n", nr, server, priority);
+	if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
+	    || (priority > 0xff)) {
+		rtas_st(vcpu->kvm, rets, 0, -3);
+		return;
+	}
+
+	ics_write_xive_msi(ics, nr, server, priority);
+
+	rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
+}
+
+static void rtas_get_xive(struct kvm_cpu *vcpu, uint32_t token,
+			  uint32_t nargs, target_ulong args,
+			  uint32_t nret, target_ulong rets)
+{
+	struct ics_state *ics = vcpu->kvm->icp->ics;
+	uint32_t nr;
+
+	if ((nargs != 1) || (nret != 3)) {
+		rtas_st(vcpu->kvm, rets, 0, -3);
+		return;
+	}
+
+	nr = rtas_ld(vcpu->kvm, args, 0);
+
+	if (!ics_valid_irq(ics, nr)) {
+		rtas_st(vcpu->kvm, rets, 0, -3);
+		return;
+	}
+
+	rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
+	rtas_st(vcpu->kvm, rets, 1, ics->irqs[nr - ics->offset].server);
+	rtas_st(vcpu->kvm, rets, 2, ics->irqs[nr - ics->offset].priority);
+}
+
+static void rtas_int_off(struct kvm_cpu *vcpu, uint32_t token,
+			 uint32_t nargs, target_ulong args,
+			 uint32_t nret, target_ulong rets)
+{
+	struct ics_state *ics = vcpu->kvm->icp->ics;
+	uint32_t nr;
+
+	if ((nargs != 1) || (nret != 1)) {
+		rtas_st(vcpu->kvm, rets, 0, -3);
+		return;
+	}
+
+	nr = rtas_ld(vcpu->kvm, args, 0);
+
+	if (!ics_valid_irq(ics, nr)) {
+		rtas_st(vcpu->kvm, rets, 0, -3);
+		return;
+	}
+
+	/* ME: QEMU wrote xive_msi here, in #if 0.  Deleted. */
+
+	rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
+}
+
+static void rtas_int_on(struct kvm_cpu *vcpu, uint32_t token,
+			uint32_t nargs, target_ulong args,
+			uint32_t nret, target_ulong rets)
+{
+	struct ics_state *ics = vcpu->kvm->icp->ics;
+	uint32_t nr;
+
+	if ((nargs != 1) || (nret != 1)) {
+		rtas_st(vcpu->kvm, rets, 0, -3);
+		return;
+	}
+
+	nr = rtas_ld(vcpu->kvm, args, 0);
+
+	if (!ics_valid_irq(ics, nr)) {
+		rtas_st(vcpu->kvm, rets, 0, -3);
+		return;
+	}
+
+	/* ME: QEMU wrote xive_msi here, in #if 0.  Deleted. */
+
+	rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
+}
+
+void xics_cpu_register(struct kvm_cpu *vcpu)
+{
+	if (vcpu->cpu_id < vcpu->kvm->icp->nr_servers)
+		vcpu->kvm->icp->ss[vcpu->cpu_id].cpu = vcpu;
+	else
+		die("Setting invalid server for cpuid %ld\n", vcpu->cpu_id);
+}
+
+struct icp_state *xics_system_init(unsigned int nr_irqs, unsigned int nr_cpus)
+{
+	int max_server_num;
+	unsigned int i;
+	struct icp_state *icp;
+	struct ics_state *ics;
+
+	max_server_num = nr_cpus;
+
+	icp = malloc(sizeof(*icp));
+	icp->nr_servers = max_server_num + 1;
+	icp->ss = malloc(icp->nr_servers*sizeof(struct icp_server_state));
+
+	for (i = 0; i < icp->nr_servers; i++) {
+		icp->ss[i].xirr = 0;
+		icp->ss[i].pending_priority = 0;
+		icp->ss[i].cpu = 0;
+		icp->ss[i].mfrr = 0xff;
+	}
+
+	/*
+	 * icp->ss[env->cpu_index].cpu is set by CPUs calling in to
+	 * xics_cpu_register().
+	 */
+
+	ics = malloc(sizeof(*ics));
+	ics->nr_irqs = nr_irqs;
+	ics->offset = XICS_IRQ_OFFSET;
+	ics->irqs = malloc(nr_irqs * sizeof(struct ics_irq_state));
+
+	icp->ics = ics;
+	ics->icp = icp;
+
+	for (i = 0; i < nr_irqs; i++) {
+		ics->irqs[i].server = 0;
+		ics->irqs[i].priority = 0xff;
+		ics->irqs[i].saved_priority = 0xff;
+		ics->irqs[i].rejected = 0;
+		ics->irqs[i].masked_pending = 0;
+	}
+
+	spapr_register_hypercall(H_CPPR, h_cppr);
+	spapr_register_hypercall(H_IPI, h_ipi);
+	spapr_register_hypercall(H_XIRR, h_xirr);
+	spapr_register_hypercall(H_EOI, h_eoi);
+
+	spapr_rtas_register("ibm,set-xive", rtas_set_xive);
+	spapr_rtas_register("ibm,get-xive", rtas_get_xive);
+	spapr_rtas_register("ibm,int-off", rtas_int_off);
+	spapr_rtas_register("ibm,int-on", rtas_int_on);
+
+	return icp;
+}
+
+void kvm__irq_line(struct kvm *kvm, int irq, int level)
+{
+	/*
+	 * Route event to ICS, which routes to ICP, which eventually does a
+	 * kvm_cpu__irq(vcpu, POWER7_EXT_IRQ, 1)
+	 */
+	xics_dprintf("Raising IRQ %d -> %d\n", irq, level);
+	ics_set_irq_msi(kvm->icp->ics, irq - kvm->icp->ics->offset, level);
+}
diff --git a/tools/kvm/powerpc/xics.h b/tools/kvm/powerpc/xics.h
new file mode 100644
index 0000000..144915b
--- /dev/null
+++ b/tools/kvm/powerpc/xics.h
@@ -0,0 +1,23 @@
+/*
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef XICS_H
+#define XICS_H
+
+#define XICS_IPI        0x2
+
+struct kvm_cpu;
+struct icp_state;
+
+struct icp_state *xics_system_init(unsigned int nr_irqs, unsigned int nr_cpus);
+void xics_cpu_register(struct kvm_cpu *vcpu);
+int xics_alloc_irqnum(void);
+
+#endif
diff --git a/tools/kvm/symbol.c b/tools/kvm/symbol.c
new file mode 100644
index 0000000..b76d98b
--- /dev/null
+++ b/tools/kvm/symbol.c
@@ -0,0 +1,131 @@
+#include "kvm/symbol.h"
+
+#include "kvm/kvm.h"
+
+#include <linux/err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <bfd.h>
+
+static bfd *abfd;
+
+int symbol_init(struct kvm *kvm)
+{
+	int ret = 0;
+
+	if (!kvm->vmlinux)
+		return -EINVAL;
+
+	bfd_init();
+
+	abfd = bfd_openr(kvm->vmlinux, NULL);
+	if (abfd == NULL) {
+		bfd_error_type err = bfd_get_error();
+
+		switch (err) {
+		case bfd_error_no_memory:
+			ret = -ENOMEM;
+			break;
+		case bfd_error_invalid_target:
+			ret = -EINVAL;
+			break;
+		default:
+			ret = -EFAULT;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static asymbol *lookup(asymbol **symbols, int nr_symbols, const char *symbol_name)
+{
+	int i, ret;
+
+	ret = -ENOENT;
+
+	for (i = 0; i < nr_symbols; i++) {
+		asymbol *symbol = symbols[i];
+
+		if (!strcmp(bfd_asymbol_name(symbol), symbol_name))
+			return symbol;
+	}
+
+	return ERR_PTR(ret);
+}
+
+char *symbol_lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size)
+{
+	const char *filename;
+	bfd_vma sym_offset;
+	bfd_vma sym_start;
+	asection *section;
+	unsigned int line;
+	const char *func;
+	long symtab_size;
+	asymbol *symbol;
+	asymbol **syms;
+	int nr_syms, ret;
+
+	ret = -ENOENT;
+	if (!abfd)
+		goto not_found;
+
+	if (!bfd_check_format(abfd, bfd_object))
+		goto not_found;
+
+	symtab_size = bfd_get_symtab_upper_bound(abfd);
+	if (!symtab_size)
+		goto not_found;
+
+	ret = -ENOMEM;
+	syms = malloc(symtab_size);
+	if (!syms)
+		goto not_found;
+
+	nr_syms = bfd_canonicalize_symtab(abfd, syms);
+
+	ret = -ENOENT;
+	section = bfd_get_section_by_name(abfd, ".debug_aranges");
+	if (!section)
+		goto not_found;
+
+	if (!bfd_find_nearest_line(abfd, section, NULL, addr, &filename, &func, &line))
+		goto not_found;
+
+	if (!func)
+		goto not_found;
+
+	symbol = lookup(syms, nr_syms, func);
+	if (IS_ERR(symbol))
+		goto not_found;
+
+	sym_start = bfd_asymbol_value(symbol);
+
+	sym_offset = addr - sym_start;
+
+	snprintf(sym, size, "%s+%llx (%s:%i)", func, (long long) sym_offset, filename, line);
+
+	sym[size - 1] = '\0';
+
+	free(syms);
+
+	return sym;
+
+not_found:
+	return ERR_PTR(ret);
+}
+
+int symbol_exit(struct kvm *kvm)
+{
+	bfd_boolean ret = TRUE;
+
+	if (abfd)
+		ret = bfd_close(abfd);
+
+	if (ret == TRUE)
+		return 0;
+
+	return -EFAULT;
+}
diff --git a/tools/kvm/term.c b/tools/kvm/term.c
new file mode 100644
index 0000000..cc0c5a5
--- /dev/null
+++ b/tools/kvm/term.c
@@ -0,0 +1,166 @@
+#include <poll.h>
+#include <stdbool.h>
+#include <termios.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <signal.h>
+#include <pty.h>
+#include <utmp.h>
+
+#include "kvm/read-write.h"
+#include "kvm/term.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+
+#define TERM_FD_IN      0
+#define TERM_FD_OUT     1
+
+extern struct kvm *kvm;
+static struct termios	orig_term;
+
+int term_escape_char	= 0x01; /* ctrl-a is used for escape */
+bool term_got_escape	= false;
+
+int active_console;
+
+int term_fds[4][2];
+
+int term_getc(int who, int term)
+{
+	unsigned char c;
+
+	if (who != active_console)
+		return -1;
+	if (read_in_full(term_fds[term][TERM_FD_IN], &c, 1) < 0)
+		return -1;
+
+	if (term_got_escape) {
+		term_got_escape = false;
+		if (c == 'x')
+			kvm_cpu__reboot();
+		if (c == term_escape_char)
+			return c;
+	}
+
+	if (c == term_escape_char) {
+		term_got_escape = true;
+		return -1;
+	}
+
+	return c;
+}
+
+int term_putc(int who, char *addr, int cnt, int term)
+{
+	int ret;
+
+	if (who != active_console)
+		return -1;
+
+	while (cnt--) {
+		ret = write(term_fds[term][TERM_FD_OUT], addr++, 1);
+		if (ret < 0)
+			return 0;
+	}
+
+	return cnt;
+}
+
+int term_getc_iov(int who, struct iovec *iov, int iovcnt, int term)
+{
+	int c;
+
+	if (who != active_console)
+		return 0;
+
+	c = term_getc(who, term);
+
+	if (c < 0)
+		return 0;
+
+	*((char *)iov[TERM_FD_IN].iov_base)	= (char)c;
+
+	return sizeof(char);
+}
+
+int term_putc_iov(int who, struct iovec *iov, int iovcnt, int term)
+{
+	if (who != active_console)
+		return 0;
+
+	return writev(term_fds[term][TERM_FD_OUT], iov, iovcnt);
+}
+
+bool term_readable(int who, int term)
+{
+	struct pollfd pollfd = (struct pollfd) {
+		.fd	= term_fds[term][TERM_FD_IN],
+		.events	= POLLIN,
+		.revents = 0,
+	};
+
+	if (who != active_console)
+		return false;
+
+	return poll(&pollfd, 1, 0) > 0;
+}
+
+static void term_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < 4; i++)
+		tcsetattr(term_fds[i][TERM_FD_IN], TCSANOW, &orig_term);
+}
+
+static void term_sig_cleanup(int sig)
+{
+	term_cleanup();
+	signal(sig, SIG_DFL);
+	raise(sig);
+}
+
+void term_set_tty(int term)
+{
+	struct termios orig_term;
+	int master, slave;
+	char new_pty[PATH_MAX];
+
+	if (tcgetattr(STDIN_FILENO, &orig_term) < 0)
+		die("unable to save initial standard input settings");
+
+	orig_term.c_lflag &= ~(ICANON | ECHO | ISIG);
+
+	if (openpty(&master, &slave, new_pty, &orig_term, NULL) < 0)
+		return;
+
+	close(slave);
+
+	pr_info("Assigned terminal %d to pty %s\n", term, new_pty);
+
+	term_fds[term][TERM_FD_IN] = term_fds[term][TERM_FD_OUT] = master;
+}
+
+void term_init(void)
+{
+	struct termios term;
+	int i;
+
+	if (tcgetattr(STDIN_FILENO, &orig_term) < 0)
+		die("unable to save initial standard input settings");
+
+	term = orig_term;
+	term.c_lflag &= ~(ICANON | ECHO | ISIG);
+	tcsetattr(STDIN_FILENO, TCSANOW, &term);
+
+	for (i = 0; i < 4; i++)
+		if (term_fds[i][TERM_FD_IN] == 0) {
+			term_fds[i][TERM_FD_IN] = STDIN_FILENO;
+			term_fds[i][TERM_FD_OUT] = STDOUT_FILENO;
+		}
+
+	signal(SIGTERM, term_sig_cleanup);
+	atexit(term_cleanup);
+}
diff --git a/tools/kvm/tests/Makefile b/tools/kvm/tests/Makefile
new file mode 100644
index 0000000..cad14ec
--- /dev/null
+++ b/tools/kvm/tests/Makefile
@@ -0,0 +1,19 @@
+all: kernel pit boot
+
+kernel:
+	$(MAKE) -C kernel
+.PHONY: kernel
+
+pit:
+	$(MAKE) -C pit
+.PHONY: pit
+
+boot:
+	$(MAKE) -C boot
+.PHONY: boot
+
+clean:
+	$(MAKE) -C kernel clean
+	$(MAKE) -C pit clean
+	$(MAKE) -C boot clean
+.PHONY: clean
diff --git a/tools/kvm/tests/boot/Makefile b/tools/kvm/tests/boot/Makefile
new file mode 100644
index 0000000..40cba68
--- /dev/null
+++ b/tools/kvm/tests/boot/Makefile
@@ -0,0 +1,13 @@
+NAME	:= init
+
+OBJ	:= $(NAME).o
+
+all: $(.o)
+	rm -rf rootfs
+	mkdir rootfs
+	gcc -static init.c -o rootfs/init
+	mkisofs rootfs > boot_test.iso
+
+clean:
+	rm -rf rootfs boot_test.iso
+.PHONY: clean
diff --git a/tools/kvm/tests/boot/init.c b/tools/kvm/tests/boot/init.c
new file mode 100644
index 0000000..094f8ba
--- /dev/null
+++ b/tools/kvm/tests/boot/init.c
@@ -0,0 +1,11 @@
+#include <linux/reboot.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+	puts("hello, KVM guest!\r");
+
+	reboot(LINUX_REBOOT_CMD_RESTART);
+
+	return 0;
+}
diff --git a/tools/kvm/tests/kernel/.gitignore b/tools/kvm/tests/kernel/.gitignore
new file mode 100644
index 0000000..d0cd209
--- /dev/null
+++ b/tools/kvm/tests/kernel/.gitignore
@@ -0,0 +1,2 @@
+kernel.bin
+kernel.elf
diff --git a/tools/kvm/tests/kernel/Makefile b/tools/kvm/tests/kernel/Makefile
new file mode 100644
index 0000000..c7dd8da
--- /dev/null
+++ b/tools/kvm/tests/kernel/Makefile
@@ -0,0 +1,20 @@
+NAME	:= kernel
+
+BIN	:= $(NAME).bin
+ELF	:= $(NAME).elf
+OBJ	:= $(NAME).o
+
+all: $(BIN)
+
+$(BIN): $(ELF)
+	objcopy -O binary $< $@
+
+$(ELF): $(OBJ)
+	ld -Ttext=0x00 -nostdlib -static $< -o $@
+
+%.o: %.S
+	gcc -nostdinc -c $< -o $@
+
+clean:
+	rm -f $(BIN) $(ELF) $(OBJ)
+.PHONY: clean
diff --git a/tools/kvm/tests/kernel/README b/tools/kvm/tests/kernel/README
new file mode 100644
index 0000000..2923777
--- /dev/null
+++ b/tools/kvm/tests/kernel/README
@@ -0,0 +1,16 @@
+Compiling
+---------
+
+You can simply type:
+
+  $ make
+
+to build a 16-bit binary that uses the i8086 instruction set.
+
+Disassembling
+-------------
+
+Use the "-m i8086" command line option with objdump to make sure it knows we're
+dealing with i8086 instruction set:
+
+  $ objdump -d -m i8086 i8086.elf
diff --git a/tools/kvm/tests/kernel/kernel.S b/tools/kvm/tests/kernel/kernel.S
new file mode 100644
index 0000000..2824b64
--- /dev/null
+++ b/tools/kvm/tests/kernel/kernel.S
@@ -0,0 +1,8 @@
+	.code16gcc
+	.text
+	.globl  _start
+	.type   _start, @function
+_start:
+	# "This is probably the largest possible kernel that is bug free." -- Avi Kivity
+	1:
+	jmp 1b
diff --git a/tools/kvm/tests/pit/.gitignore b/tools/kvm/tests/pit/.gitignore
new file mode 100644
index 0000000..43f0aa8
--- /dev/null
+++ b/tools/kvm/tests/pit/.gitignore
@@ -0,0 +1,2 @@
+*.bin
+*.elf
diff --git a/tools/kvm/tests/pit/Makefile b/tools/kvm/tests/pit/Makefile
new file mode 100644
index 0000000..2fae9b2
--- /dev/null
+++ b/tools/kvm/tests/pit/Makefile
@@ -0,0 +1,20 @@
+NAME	:= tick
+
+BIN	:= $(NAME).bin
+ELF	:= $(NAME).elf
+OBJ	:= $(NAME).o
+
+all: $(BIN)
+
+$(BIN): $(ELF)
+	objcopy -O binary $< $@
+
+$(ELF): $(OBJ)
+	ld -Ttext=0x00 -nostdlib -static $< -o $@
+
+%.o: %.S
+	gcc -nostdinc -c $< -o $@
+
+clean:
+	rm -f $(BIN) $(ELF) $(OBJ)
+.PHONY: clean
diff --git a/tools/kvm/tests/pit/README b/tools/kvm/tests/pit/README
new file mode 100644
index 0000000..2923777
--- /dev/null
+++ b/tools/kvm/tests/pit/README
@@ -0,0 +1,16 @@
+Compiling
+---------
+
+You can simply type:
+
+  $ make
+
+to build a 16-bit binary that uses the i8086 instruction set.
+
+Disassembling
+-------------
+
+Use the "-m i8086" command line option with objdump to make sure it knows we're
+dealing with i8086 instruction set:
+
+  $ objdump -d -m i8086 i8086.elf
diff --git a/tools/kvm/tests/pit/tick.S b/tools/kvm/tests/pit/tick.S
new file mode 100644
index 0000000..b9e5a80
--- /dev/null
+++ b/tools/kvm/tests/pit/tick.S
@@ -0,0 +1,109 @@
+#define IO_PIC		0x20
+#define IRQ_OFFSET	32
+#define IO_PIT		0x40
+#define TIMER_FREQ	1193182
+#define TIMER_DIV(x)	((TIMER_FREQ+(x)/2)/(x))
+
+/*
+ * hpa noted:
+ *
+ * 0xe0..0xef are "motherboard specific", but 0xe9 is
+ * used for Bochs debugging and 0xed is the Phoenix-reserved
+ * delay port
+ */
+#define DBG_PORT	0xe0
+
+#define TEST_COUNT	0x0200
+
+	.code16gcc
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+/*
+ * fill up noop handlers
+ */
+	xorw	%ax, %ax
+	xorw	%di, %di
+	movw	%ax, %es
+	movw	$256, %cx
+fill_noop_idt:
+	movw	$noop_handler, %es:(%di)
+	movw	%cs, %es:2(%di)
+	add	$4, %di
+	loop	fill_noop_idt
+
+set_idt:
+	movw	$timer_isr, %es:(IRQ_OFFSET*4)
+	movw	%cs, %es:(IRQ_OFFSET*4+2)
+
+set_pic:
+	# ICW1
+	mov	$0x11, %al
+	mov	$(IO_PIC), %dx
+	out	%al,%dx
+	# ICW2
+	mov	$(IRQ_OFFSET), %al
+	mov	$(IO_PIC+1), %dx
+	out	%al, %dx
+	# ICW3
+	mov	$0x00, %al
+	mov	$(IO_PIC+1), %dx
+	out	%al, %dx
+	# ICW4
+	mov	$0x3, %al
+	mov	$(IO_PIC+1), %dx
+	out	%al, %dx
+
+set_pit:
+	# set 8254 mode
+	mov	$(IO_PIT+3), %dx
+	mov	$0x34, %al
+	outb	%al, %dx
+	# set 8254 freq 1KHz
+	mov	$(IO_PIT), %dx
+	movb	$(TIMER_DIV(1000) % 256), %al
+	outb	%al, %dx
+	movb	$(TIMER_DIV(1000) / 256), %al
+	outb	%al, %dx
+
+enable_irq0:
+	mov	$0xfe, %al
+	mov	$(IO_PIC+1), %dx
+	out	%al, %dx
+	sti
+loop:
+	1:
+	jmp	1b
+
+test_ok:
+	mov	$0x3f8,%dx
+	cs lea	msg2, %si
+	mov	$(msg2_end-msg2), %cx
+	cs rep/outsb
+
+	/* not a valid port to force exit */
+	outb	%al, $DBG_PORT
+
+timer_isr:
+	cli
+	pushaw
+	pushfw
+	mov	$0x3f8,%dx
+	mov	$0x2e, %al	# .
+	out	%al,%dx
+	decw	count
+	jz	test_ok
+	popfw
+	popaw
+	iretw
+
+noop_handler:
+	iretw
+
+count:
+	.word	TEST_COUNT
+
+msg2:
+	.asciz "\nTest OK\n"
+msg2_end:
diff --git a/tools/kvm/ui/sdl.c b/tools/kvm/ui/sdl.c
new file mode 100644
index 0000000..708b9a9
--- /dev/null
+++ b/tools/kvm/ui/sdl.c
@@ -0,0 +1,303 @@
+#include "kvm/sdl.h"
+
+#include "kvm/framebuffer.h"
+#include "kvm/i8042.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+
+#include <SDL/SDL.h>
+#include <pthread.h>
+#include <signal.h>
+
+#define FRAME_RATE		25
+
+#define SCANCODE_UNKNOWN      0
+#define SCANCODE_NORMAL       1
+#define SCANCODE_ESCAPED      2
+#define SCANCODE_KEY_PAUSE    3
+#define SCANCODE_KEY_PRNTSCRN 4
+
+struct set2_scancode {
+	u8 code;
+	u8 type;
+};
+
+#define DEFINE_SC(_code) {\
+	.code = _code,\
+	.type = SCANCODE_NORMAL,\
+}
+
+/* escaped scancodes */
+#define DEFINE_ESC(_code) {\
+	.code = _code,\
+	.type = SCANCODE_ESCAPED,\
+}
+
+static const struct set2_scancode const keymap[256] = {
+	[9]	= DEFINE_SC(0x76),	/* <esc> */
+	[10]	= DEFINE_SC(0x16),	/* 1 */
+	[11]	= DEFINE_SC(0x1e),	/* 2 */
+	[12]	= DEFINE_SC(0x26),	/* 3 */
+	[13]	= DEFINE_SC(0x25),	/* 4 */
+	[14]	= DEFINE_SC(0x2e),	/* 5 */
+	[15]	= DEFINE_SC(0x36),	/* 6 */
+	[16]	= DEFINE_SC(0x3d),	/* 7 */
+	[17]	= DEFINE_SC(0x3e),	/* 8 */
+	[18]	= DEFINE_SC(0x46),	/* 9 */
+	[19]	= DEFINE_SC(0x45),	/* 9 */
+	[20]	= DEFINE_SC(0x4e),	/* - */
+	[21]	= DEFINE_SC(0x55),	/* + */
+	[22]	= DEFINE_SC(0x66),	/* <backspace> */
+	[23]	= DEFINE_SC(0x0d),	/* <tab> */
+	[24]	= DEFINE_SC(0x15),	/* q */
+	[25]	= DEFINE_SC(0x1d),	/* w */
+	[26]	= DEFINE_SC(0x24),	/* e */
+	[27]	= DEFINE_SC(0x2d),	/* r */
+	[28]	= DEFINE_SC(0x2c),	/* t */
+	[29]	= DEFINE_SC(0x35),	/* y */
+	[30]	= DEFINE_SC(0x3c),	/* u */
+	[31]	= DEFINE_SC(0x43),	/* i */
+	[32]	= DEFINE_SC(0x44),	/* o */
+	[33]	= DEFINE_SC(0x4d),	/* p */
+	[34]	= DEFINE_SC(0x54),	/* [ */
+	[35]	= DEFINE_SC(0x5b),	/* ] */
+	[36]	= DEFINE_SC(0x5a),	/* <enter> */
+	[37]	= DEFINE_SC(0x14),	/* <left ctrl> */
+	[38]	= DEFINE_SC(0x1c),	/* a */
+	[39]	= DEFINE_SC(0x1b),	/* s */
+	[40]	= DEFINE_SC(0x23),	/* d */
+	[41]	= DEFINE_SC(0x2b),	/* f */
+	[42]	= DEFINE_SC(0x34),	/* g */
+	[43]	= DEFINE_SC(0x33),	/* h */
+	[44]	= DEFINE_SC(0x3b),	/* j */
+	[45]	= DEFINE_SC(0x42),	/* k */
+	[46]	= DEFINE_SC(0x4b),	/* l */
+	[47]	= DEFINE_SC(0x4c),	/* ; */
+	[48]	= DEFINE_SC(0x52),	/* ' */
+	[49]	= DEFINE_SC(0x0e),	/* ` */
+	[50]	= DEFINE_SC(0x12),	/* <left shift> */
+	[51]	= DEFINE_SC(0x5d),	/* \ */
+	[52]	= DEFINE_SC(0x1a),	/* z */
+	[53]	= DEFINE_SC(0x22),	/* x */
+	[54]	= DEFINE_SC(0x21),	/* c */
+	[55]	= DEFINE_SC(0x2a),	/* v */
+	[56]	= DEFINE_SC(0x32),	/* b */
+	[57]	= DEFINE_SC(0x31),	/* n */
+	[58]	= DEFINE_SC(0x3a),	/* m */
+	[59]	= DEFINE_SC(0x41),	/* < */
+	[60]	= DEFINE_SC(0x49),	/* > */
+	[61]	= DEFINE_SC(0x4a),	/* / */
+	[62]	= DEFINE_SC(0x59),	/* <right shift> */
+	[63]	= DEFINE_SC(0x7c),	/* keypad * */
+	[64]	= DEFINE_SC(0x11),	/* <left alt> */
+	[65]	= DEFINE_SC(0x29),	/* <space> */
+
+	[67]	= DEFINE_SC(0x05),	/* <F1> */
+	[68]	= DEFINE_SC(0x06),	/* <F2> */
+	[69]	= DEFINE_SC(0x04),	/* <F3> */
+	[70]	= DEFINE_SC(0x0c),	/* <F4> */
+	[71]	= DEFINE_SC(0x03),	/* <F5> */
+	[72]	= DEFINE_SC(0x0b),	/* <F6> */
+	[73]	= DEFINE_SC(0x83),	/* <F7> */
+	[74]	= DEFINE_SC(0x0a),	/* <F8> */
+	[75]	= DEFINE_SC(0x01),	/* <F9> */
+	[76]	= DEFINE_SC(0x09),	/* <F10> */
+
+	[79]	= DEFINE_SC(0x6c),	/* keypad 7 */
+	[80]	= DEFINE_SC(0x75),	/* keypad 8 */
+	[81]	= DEFINE_SC(0x7d),	/* keypad 9 */
+	[82]	= DEFINE_SC(0x7b),	/* keypad - */
+	[83]	= DEFINE_SC(0x6b),	/* keypad 4 */
+	[84]	= DEFINE_SC(0x73),	/* keypad 5 */
+	[85]	= DEFINE_SC(0x74),	/* keypad 6 */
+	[86]	= DEFINE_SC(0x79),	/* keypad + */
+	[87]	= DEFINE_SC(0x69),	/* keypad 1 */
+	[88]	= DEFINE_SC(0x72),	/* keypad 2 */
+	[89]	= DEFINE_SC(0x7a),	/* keypad 3 */
+	[90]	= DEFINE_SC(0x70),	/* keypad 0 */
+	[91]	= DEFINE_SC(0x71),	/* keypad . */
+
+	[94]	= DEFINE_SC(0x61),	/* <INT 1> */
+	[95]	= DEFINE_SC(0x78),	/* <F11> */
+	[96]	= DEFINE_SC(0x07),	/* <F12> */
+
+	[104]	= DEFINE_ESC(0x5a),	/* keypad <enter> */
+	[105]	= DEFINE_ESC(0x14),	/* <right ctrl> */
+	[106]	= DEFINE_ESC(0x4a),	/* keypad / */
+	[108]	= DEFINE_ESC(0x11),	/* <right alt> */
+	[110]	= DEFINE_ESC(0x6c),	/* <home> */
+	[111]	= DEFINE_ESC(0x75),	/* <up> */
+	[112]	= DEFINE_ESC(0x7d),	/* <pag up> */
+	[113]	= DEFINE_ESC(0x6b),	/* <left> */
+	[114]	= DEFINE_ESC(0x74),	/* <right> */
+	[115]	= DEFINE_ESC(0x69),	/* <end> */
+	[116]	= DEFINE_ESC(0x72),	/* <down> */
+	[117]	= DEFINE_ESC(0x7a),	/* <pag down> */
+	[118]	= DEFINE_ESC(0x70),	/* <ins> */
+	[119]	= DEFINE_ESC(0x71),	/* <delete> */
+};
+static bool running, done;
+
+static const struct set2_scancode *to_code(u8 scancode)
+{
+	return &keymap[scancode];
+}
+
+static void key_press(const struct set2_scancode *sc)
+{
+	switch (sc->type) {
+	case SCANCODE_ESCAPED:
+		kbd_queue(0xe0);
+		/* fallthrough */
+	case SCANCODE_NORMAL:
+		kbd_queue(sc->code);
+		break;
+	case SCANCODE_KEY_PAUSE:
+		kbd_queue(0xe1);
+		kbd_queue(0x14);
+		kbd_queue(0x77);
+		kbd_queue(0xe1);
+		kbd_queue(0xf0);
+		kbd_queue(0x14);
+		kbd_queue(0x77);
+		break;
+	case SCANCODE_KEY_PRNTSCRN:
+		kbd_queue(0xe0);
+		kbd_queue(0x12);
+		kbd_queue(0xe0);
+		kbd_queue(0x7c);
+		break;
+	}
+}
+
+static void key_release(const struct set2_scancode *sc)
+{
+	switch (sc->type) {
+	case SCANCODE_ESCAPED:
+		kbd_queue(0xe0);
+		/* fallthrough */
+	case SCANCODE_NORMAL:
+		kbd_queue(0xf0);
+		kbd_queue(sc->code);
+		break;
+	case SCANCODE_KEY_PAUSE:
+		/* nothing to do */
+		break;
+	case SCANCODE_KEY_PRNTSCRN:
+		kbd_queue(0xe0);
+		kbd_queue(0xf0);
+		kbd_queue(0x7c);
+		kbd_queue(0xe0);
+		kbd_queue(0xf0);
+		kbd_queue(0x12);
+		break;
+	}
+}
+
+static void *sdl__thread(void *p)
+{
+	Uint32 rmask, gmask, bmask, amask;
+	struct framebuffer *fb = p;
+	SDL_Surface *guest_screen;
+	SDL_Surface *screen;
+	SDL_Event ev;
+	Uint32 flags;
+
+	if (SDL_Init(SDL_INIT_VIDEO) != 0)
+		die("Unable to initialize SDL");
+
+	rmask = 0x000000ff;
+	gmask = 0x0000ff00;
+	bmask = 0x00ff0000;
+	amask = 0x00000000;
+
+	guest_screen = SDL_CreateRGBSurfaceFrom(fb->mem, fb->width, fb->height, fb->depth, fb->width * fb->depth / 8, rmask, gmask, bmask, amask);
+	if (!guest_screen)
+		die("Unable to create SDL RBG surface");
+
+	flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_DOUBLEBUF;
+
+	SDL_WM_SetCaption("KVM tool", "KVM tool");
+
+	screen = SDL_SetVideoMode(fb->width, fb->height, fb->depth, flags);
+	if (!screen)
+		die("Unable to set SDL video mode");
+
+	SDL_EnableKeyRepeat(200, 50);
+
+	while (running) {
+		SDL_BlitSurface(guest_screen, NULL, screen, NULL);
+		SDL_Flip(screen);
+
+		while (SDL_PollEvent(&ev)) {
+			switch (ev.type) {
+			case SDL_KEYDOWN: {
+				const struct set2_scancode *sc = to_code(ev.key.keysym.scancode);
+				if (sc->type == SCANCODE_UNKNOWN) {
+					pr_warning("key '%d' not found in keymap", ev.key.keysym.scancode);
+					break;
+				}
+				key_press(sc);
+				break;
+			}
+			case SDL_KEYUP: {
+				const struct set2_scancode *sc = to_code(ev.key.keysym.scancode);
+				if (sc->type == SCANCODE_UNKNOWN)
+					break;
+				key_release(sc);
+				break;
+			}
+			case SDL_QUIT:
+				goto exit;
+			}
+		}
+
+		SDL_Delay(1000 / FRAME_RATE);
+	}
+
+	if (running == false && done == false) {
+		done = true;
+		return NULL;
+	}
+exit:
+	kvm_cpu__reboot();
+
+	return NULL;
+}
+
+static int sdl__start(struct framebuffer *fb)
+{
+	pthread_t thread;
+
+	running = true;
+
+	if (pthread_create(&thread, NULL, sdl__thread, fb) != 0)
+		return -1;
+
+	return 0;
+}
+
+static int sdl__stop(struct framebuffer *fb)
+{
+	running = false;
+	while (done == false)
+		sleep(0);
+
+	return 0;
+}
+
+static struct fb_target_operations sdl_ops = {
+	.start	= sdl__start,
+	.stop	= sdl__stop,
+};
+
+int sdl__init(struct framebuffer *fb)
+{
+	return fb__attach(fb, &sdl_ops);
+}
+
+int sdl__exit(struct framebuffer *fb)
+{
+	return sdl__stop(fb);
+}
diff --git a/tools/kvm/ui/vnc.c b/tools/kvm/ui/vnc.c
new file mode 100644
index 0000000..91254c5
--- /dev/null
+++ b/tools/kvm/ui/vnc.c
@@ -0,0 +1,230 @@
+#include "kvm/vnc.h"
+
+#include "kvm/framebuffer.h"
+#include "kvm/i8042.h"
+
+#include <linux/types.h>
+#include <rfb/keysym.h>
+#include <rfb/rfb.h>
+#include <pthread.h>
+
+#define VESA_QUEUE_SIZE		128
+#define VESA_IRQ		14
+
+/*
+ * This "6000" value is pretty much the result of experimentation
+ * It seems that around this value, things update pretty smoothly
+ */
+#define VESA_UPDATE_TIME	6000
+
+/*
+ * We can map the letters and numbers without a fuss,
+ * but the other characters not so much.
+ */
+static char letters[26] = {
+	0x1c, 0x32, 0x21, 0x23, 0x24, /* a-e */
+	0x2b, 0x34, 0x33, 0x43, 0x3b, /* f-j */
+	0x42, 0x4b, 0x3a, 0x31, 0x44, /* k-o */
+	0x4d, 0x15, 0x2d, 0x1b, 0x2c, /* p-t */
+	0x3c, 0x2a, 0x1d, 0x22, 0x35, /* u-y */
+	0x1a,
+};
+
+static rfbScreenInfoPtr server;
+static char num[10] = {
+	0x45, 0x16, 0x1e, 0x26, 0x2e, 0x23, 0x36, 0x3d, 0x3e, 0x46,
+};
+
+/*
+ * This is called when the VNC server receives a key event
+ * The reason this function is such a beast is that we have
+ * to convert from ASCII characters (which is what VNC gets)
+ * to PC keyboard scancodes, which is what Linux expects to
+ * get from its keyboard. ASCII and the scancode set don't
+ * really seem to mesh in any good way beyond some basics with
+ * the letters and numbers.
+ */
+static void kbd_handle_key(rfbBool down, rfbKeySym key, rfbClientPtr cl)
+{
+	char tosend = 0;
+
+	if (key >= 0x41 && key <= 0x5a)
+		key += 0x20; /* convert to lowercase */
+
+	if (key >= 0x61 && key <= 0x7a) /* a-z */
+		tosend = letters[key - 0x61];
+
+	if (key >= 0x30 && key <= 0x39)
+		tosend = num[key - 0x30];
+
+	switch (key) {
+	case XK_Insert:		kbd_queue(0xe0);	tosend = 0x70;	break;
+	case XK_Delete:		kbd_queue(0xe0);	tosend = 0x71;	break;
+	case XK_Up:		kbd_queue(0xe0);	tosend = 0x75;	break;
+	case XK_Down:		kbd_queue(0xe0);	tosend = 0x72;	break;
+	case XK_Left:		kbd_queue(0xe0);	tosend = 0x6b;	break;
+	case XK_Right:		kbd_queue(0xe0);	tosend = 0x74;	break;
+	case XK_Page_Up:	kbd_queue(0xe0);	tosend = 0x7d;	break;
+	case XK_Page_Down:	kbd_queue(0xe0);	tosend = 0x7a;	break;
+	case XK_Home:		kbd_queue(0xe0);	tosend = 0x6c;	break;
+	case XK_BackSpace:	tosend = 0x66;		break;
+	case XK_Tab:		tosend = 0x0d;		break;
+	case XK_Return:		tosend = 0x5a;		break;
+	case XK_Escape:		tosend = 0x76;		break;
+	case XK_End:		tosend = 0x69;		break;
+	case XK_Shift_L:	tosend = 0x12;		break;
+	case XK_Shift_R:	tosend = 0x59;		break;
+	case XK_Control_R:	kbd_queue(0xe0);
+	case XK_Control_L:	tosend = 0x14;		break;
+	case XK_Alt_R:		kbd_queue(0xe0);
+	case XK_Alt_L:		tosend = 0x11;		break;
+	case XK_quoteleft:	tosend = 0x0e;		break;
+	case XK_minus:		tosend = 0x4e;		break;
+	case XK_equal:		tosend = 0x55;		break;
+	case XK_bracketleft:	tosend = 0x54;		break;
+	case XK_bracketright:	tosend = 0x5b;		break;
+	case XK_backslash:	tosend = 0x5d;		break;
+	case XK_Caps_Lock:	tosend = 0x58;		break;
+	case XK_semicolon:	tosend = 0x4c;		break;
+	case XK_quoteright:	tosend = 0x52;		break;
+	case XK_comma:		tosend = 0x41;		break;
+	case XK_period:		tosend = 0x49;		break;
+	case XK_slash:		tosend = 0x4a;		break;
+	case XK_space:		tosend = 0x29;		break;
+
+	/*
+	 * This is where I handle the shifted characters.
+	 * They don't really map nicely the way A-Z maps to a-z,
+	 * so I'm doing it manually
+	 */
+	case XK_exclam:		tosend = 0x16;		break;
+	case XK_quotedbl:	tosend = 0x52;		break;
+	case XK_numbersign:	tosend = 0x26;		break;
+	case XK_dollar:		tosend = 0x25;		break;
+	case XK_percent:	tosend = 0x2e;		break;
+	case XK_ampersand:	tosend = 0x3d;		break;
+	case XK_parenleft:	tosend = 0x46;		break;
+	case XK_parenright:	tosend = 0x45;		break;
+	case XK_asterisk:	tosend = 0x3e;		break;
+	case XK_plus:		tosend = 0x55;		break;
+	case XK_colon:		tosend = 0x4c;		break;
+	case XK_less:		tosend = 0x41;		break;
+	case XK_greater:	tosend = 0x49;		break;
+	case XK_question:	tosend = 0x4a;		break;
+	case XK_at:		tosend = 0x1e;		break;
+	case XK_asciicircum:	tosend = 0x36;		break;
+	case XK_underscore:	tosend = 0x4e;		break;
+	case XK_braceleft:	tosend = 0x54;		break;
+	case XK_braceright:	tosend = 0x5b;		break;
+	case XK_bar:		tosend = 0x5d;		break;
+	case XK_asciitilde:	tosend = 0x0e;		break;
+	default:		break;
+	}
+
+	/*
+	 * If this is a "key up" event (the user has released the key, we
+	 * need to send 0xf0 first.
+	 */
+	if (!down && tosend != 0x0)
+		kbd_queue(0xf0);
+
+	if (tosend)
+		kbd_queue(tosend);
+}
+
+/* The previous X and Y coordinates of the mouse */
+static int xlast, ylast = -1;
+
+/*
+ * This function is called by the VNC server whenever a mouse event occurs.
+ */
+static void kbd_handle_ptr(int buttonMask, int x, int y, rfbClientPtr cl)
+{
+	int dx, dy;
+	char b1 = 0x8;
+
+	/* The VNC mask and the PS/2 button encoding are the same */
+	b1 |= buttonMask;
+
+	if (xlast >= 0 && ylast >= 0) {
+		/* The PS/2 mouse sends deltas, not absolutes */
+		dx = x - xlast;
+		dy = ylast - y;
+
+		/* Set overflow bits if needed */
+		if (dy > 255)
+			b1 |= 0x80;
+		if (dx > 255)
+			b1 |= 0x40;
+
+		/* Set negative bits if needed */
+		if (dy < 0)
+			b1 |= 0x20;
+		if (dx < 0)
+			b1 |= 0x10;
+
+		mouse_queue(b1);
+		mouse_queue(dx);
+		mouse_queue(dy);
+	}
+
+	xlast = x;
+	ylast = y;
+	rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
+}
+
+static void *vnc__thread(void *p)
+{
+	struct framebuffer *fb = p;
+	/*
+	 * Make a fake argc and argv because the getscreen function
+	 * seems to want it.
+	 */
+	char argv[1][1] = {{0}};
+	int argc = 1;
+
+	server = rfbGetScreen(&argc, (char **) argv, fb->width, fb->height, 8, 3, 4);
+	server->frameBuffer		= fb->mem;
+	server->alwaysShared		= TRUE;
+	server->kbdAddEvent		= kbd_handle_key;
+	server->ptrAddEvent		= kbd_handle_ptr;
+	rfbInitServer(server);
+
+	while (rfbIsActive(server)) {
+		rfbMarkRectAsModified(server, 0, 0, fb->width, fb->height);
+		rfbProcessEvents(server, server->deferUpdateTime * VESA_UPDATE_TIME);
+	}
+	return NULL;
+}
+
+static int vnc__start(struct framebuffer *fb)
+{
+	pthread_t thread;
+
+	if (pthread_create(&thread, NULL, vnc__thread, fb) != 0)
+		return -1;
+
+	return 0;
+}
+
+static int vnc__stop(struct framebuffer *fb)
+{
+	rfbShutdownServer(server, TRUE);
+
+	return 0;
+}
+
+static struct fb_target_operations vnc_ops = {
+	.start	= vnc__start,
+	.stop	= vnc__stop,
+};
+
+int vnc__init(struct framebuffer *fb)
+{
+	return fb__attach(fb, &vnc_ops);
+}
+
+int vnc__exit(struct framebuffer *fb)
+{
+	return vnc__stop(fb);
+}
\ No newline at end of file
diff --git a/tools/kvm/util/KVMTOOLS-VERSION-GEN b/tools/kvm/util/KVMTOOLS-VERSION-GEN
new file mode 100755
index 0000000..1af9d6c
--- /dev/null
+++ b/tools/kvm/util/KVMTOOLS-VERSION-GEN
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+if [ $# -eq 1 ]  ; then
+	OUTPUT=$1
+fi
+
+GVF=${OUTPUT}KVMTOOLS-VERSION-FILE
+
+LF='
+'
+
+# First check if there is a .git to get the version from git describe
+# otherwise try to get the version from the kernel makefile
+if test -d ../../.git -o -f ../../.git &&
+	VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
+	case "$VN" in
+	*$LF*) (exit 1) ;;
+	v[0-9]*)
+		git update-index -q --refresh
+		test -z "$(git diff-index --name-only HEAD --)" ||
+		VN="$VN-dirty" ;;
+	esac
+then
+	VN=$(echo "$VN" | sed -e 's/-/./g');
+else
+	VN=$(MAKEFLAGS= make -sC ../.. kernelversion)
+fi
+
+VN=$(expr "$VN" : v*'\(.*\)')
+
+if test -r $GVF
+then
+	VC=$(sed -e 's/^KVMTOOLS_VERSION = //' <$GVF)
+else
+	VC=unset
+fi
+test "$VN" = "$VC" || {
+	echo >&2 "KVMTOOLS_VERSION = $VN"
+	echo "KVMTOOLS_VERSION = $VN" >$GVF
+}
diff --git a/tools/kvm/util/generate-cmdlist.sh b/tools/kvm/util/generate-cmdlist.sh
new file mode 100755
index 0000000..c8be0bd
--- /dev/null
+++ b/tools/kvm/util/generate-cmdlist.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+echo "/* Automatically generated by $0 */
+struct cmdname_help
+{
+    char name[16];
+    char help[80];
+};
+
+static struct cmdname_help common_cmds[] = {"
+
+sed -n 's/^lkvm-\([^ \t]*\).*common/\1/p' command-list.txt |
+while read cmd
+do
+	 # TODO following sed command should be fixed
+     sed -n '/^NAME/,/^lkvm-'"$cmd"'/ {
+		 /NAME/d
+		 /--/d
+		 s/.*kvm-'"$cmd"' - \(.*\)/  {"'"$cmd"'", "\1"},/
+	     p
+	 }' "Documentation/kvm-$cmd.txt"
+done
+echo "};"
diff --git a/tools/kvm/util/kvm-ifup-vbr0 b/tools/kvm/util/kvm-ifup-vbr0
new file mode 100755
index 0000000..a91c37f
--- /dev/null
+++ b/tools/kvm/util/kvm-ifup-vbr0
@@ -0,0 +1,6 @@
+#!/bin/sh
+switch=vbr0
+/sbin/ifconfig $1 0.0.0.0 up
+/usr/sbin/brctl addif ${switch} $1
+/usr/sbin/brctl setfd ${switch} 0
+/usr/sbin/brctl stp ${switch} off
diff --git a/tools/kvm/util/parse-options.c b/tools/kvm/util/parse-options.c
new file mode 100644
index 0000000..9a1bbee
--- /dev/null
+++ b/tools/kvm/util/parse-options.c
@@ -0,0 +1,577 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <stdbool.h>
+
+/* user defined includes */
+#include <linux/types.h>
+#include <kvm/util.h>
+#include <kvm/parse-options.h>
+#include <kvm/strbuf.h>
+
+#define OPT_SHORT 1
+#define OPT_UNSET 2
+
+static int opterror(const struct option *opt, const char *reason, int flags)
+{
+	if (flags & OPT_SHORT)
+		return pr_err("switch `%c' %s", opt->short_name, reason);
+	if (flags & OPT_UNSET)
+		return pr_err("option `no-%s' %s", opt->long_name, reason);
+	return pr_err("option `%s' %s", opt->long_name, reason);
+}
+
+static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
+		int flags, const char **arg)
+{
+	if (p->opt) {
+		*arg = p->opt;
+		p->opt = NULL;
+	} else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
+				**(p->argv + 1) == '-')) {
+		*arg = (const char *)opt->defval;
+	} else if (p->argc > 1) {
+		p->argc--;
+		*arg = *++p->argv;
+	} else
+		return opterror(opt, "requires a value", flags);
+	return 0;
+}
+
+static int readnum(const struct option *opt, int flags,
+		   const char *str, char **end)
+{
+	switch (opt->type) {
+	case OPTION_INTEGER:
+		*(int *)opt->value = strtol(str, end, 0);
+		break;
+	case OPTION_UINTEGER:
+		*(unsigned int *)opt->value = strtol(str, end, 0);
+		break;
+	case OPTION_LONG:
+		*(long *)opt->value = strtol(str, end, 0);
+		break;
+	case OPTION_U64:
+		*(u64 *)opt->value = strtoull(str, end, 0);
+		break;
+	default:
+		return opterror(opt, "invalid numeric conversion", flags);
+	}
+
+	return 0;
+}
+
+static int get_value(struct parse_opt_ctx_t *p,
+		const struct option *opt, int flags)
+{
+	const char *s, *arg = NULL;
+	const int unset = flags & OPT_UNSET;
+
+	if (unset && p->opt)
+		return opterror(opt, "takes no value", flags);
+	if (unset && (opt->flags & PARSE_OPT_NONEG))
+		return opterror(opt, "isn't available", flags);
+
+	if (!(flags & OPT_SHORT) && p->opt) {
+		switch (opt->type) {
+		case OPTION_CALLBACK:
+			if (!(opt->flags & PARSE_OPT_NOARG))
+				break;
+		/* FALLTHROUGH */
+		case OPTION_BOOLEAN:
+		case OPTION_INCR:
+		case OPTION_BIT:
+		case OPTION_SET_UINT:
+		case OPTION_SET_PTR:
+			return opterror(opt, "takes no value", flags);
+		case OPTION_END:
+		case OPTION_ARGUMENT:
+		case OPTION_GROUP:
+		case OPTION_STRING:
+		case OPTION_INTEGER:
+		case OPTION_UINTEGER:
+		case OPTION_LONG:
+		case OPTION_U64:
+		default:
+			break;
+		}
+	}
+
+	switch (opt->type) {
+	case OPTION_BIT:
+		if (unset)
+			*(int *)opt->value &= ~opt->defval;
+		else
+			*(int *)opt->value |= opt->defval;
+		return 0;
+
+	case OPTION_BOOLEAN:
+		*(bool *)opt->value = unset ? false : true;
+		return 0;
+
+	case OPTION_INCR:
+		*(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
+		return 0;
+
+	case OPTION_SET_UINT:
+		*(unsigned int *)opt->value = unset ? 0 : opt->defval;
+		return 0;
+
+	case OPTION_SET_PTR:
+		*(void **)opt->value = unset ? NULL : (void *)opt->defval;
+		return 0;
+
+	case OPTION_STRING:
+		if (unset)
+			*(const char **)opt->value = NULL;
+		else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+			*(const char **)opt->value = (const char *)opt->defval;
+		else
+			return get_arg(p, opt, flags,
+					(const char **)opt->value);
+		return 0;
+
+	case OPTION_CALLBACK:
+		if (unset)
+			return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
+		if (opt->flags & PARSE_OPT_NOARG)
+			return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
+		if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+			return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
+		if (get_arg(p, opt, flags, &arg))
+			return -1;
+		return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
+
+	case OPTION_INTEGER:
+		if (unset) {
+			*(int *)opt->value = 0;
+			return 0;
+		}
+		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+			*(int *)opt->value = opt->defval;
+			return 0;
+		}
+		if (get_arg(p, opt, flags, &arg))
+			return -1;
+		return readnum(opt, flags, arg, (char **)&s);
+
+	case OPTION_UINTEGER:
+		if (unset) {
+			*(unsigned int *)opt->value = 0;
+			return 0;
+		}
+		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+			*(unsigned int *)opt->value = opt->defval;
+			return 0;
+		}
+		if (get_arg(p, opt, flags, &arg))
+			return -1;
+		return readnum(opt, flags, arg, (char **)&s);
+
+	case OPTION_LONG:
+		if (unset) {
+			*(long *)opt->value = 0;
+			return 0;
+		}
+		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+			*(long *)opt->value = opt->defval;
+			return 0;
+		}
+		if (get_arg(p, opt, flags, &arg))
+			return -1;
+		return readnum(opt, flags, arg, (char **)&s);
+
+	case OPTION_U64:
+		if (unset) {
+			*(u64 *)opt->value = 0;
+			return 0;
+		}
+		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+			*(u64 *)opt->value = opt->defval;
+			return 0;
+		}
+		if (get_arg(p, opt, flags, &arg))
+			return -1;
+		return readnum(opt, flags, arg, (char **)&s);
+
+	case OPTION_END:
+	case OPTION_ARGUMENT:
+	case OPTION_GROUP:
+	default:
+		die("should not happen, someone must be hit on the forehead");
+	}
+}
+
+#define USAGE_OPTS_WIDTH 24
+#define USAGE_GAP         2
+
+static int usage_with_options_internal(const char * const *usagestr,
+		const struct option *opts, int full)
+{
+	if (!usagestr)
+		return PARSE_OPT_HELP;
+
+	fprintf(stderr, "\n usage: %s\n", *usagestr++);
+	while (*usagestr && **usagestr)
+		fprintf(stderr, "    or: %s\n", *usagestr++);
+	while (*usagestr) {
+		fprintf(stderr, "%s%s\n",
+				**usagestr ? "    " : "",
+				*usagestr);
+		usagestr++;
+	}
+
+	if (opts->type != OPTION_GROUP)
+		fputc('\n', stderr);
+
+	for (; opts->type != OPTION_END; opts++) {
+		size_t pos;
+		int pad;
+
+		if (opts->type == OPTION_GROUP) {
+			fputc('\n', stderr);
+			if (*opts->help)
+				fprintf(stderr, "%s\n", opts->help);
+			continue;
+		}
+		if (!full && (opts->flags & PARSE_OPT_HIDDEN))
+			continue;
+
+		pos = fprintf(stderr, "    ");
+		if (opts->short_name)
+			pos += fprintf(stderr, "-%c", opts->short_name);
+		else
+			pos += fprintf(stderr, "    ");
+
+		if (opts->long_name && opts->short_name)
+			pos += fprintf(stderr, ", ");
+		if (opts->long_name)
+			pos += fprintf(stderr, "--%s", opts->long_name);
+
+		switch (opts->type) {
+		case OPTION_ARGUMENT:
+			break;
+		case OPTION_LONG:
+		case OPTION_U64:
+		case OPTION_INTEGER:
+		case OPTION_UINTEGER:
+			if (opts->flags & PARSE_OPT_OPTARG)
+				if (opts->long_name)
+					pos += fprintf(stderr, "[=<n>]");
+				else
+					pos += fprintf(stderr, "[<n>]");
+			else
+				pos += fprintf(stderr, " <n>");
+			break;
+		case OPTION_CALLBACK:
+			if (opts->flags & PARSE_OPT_NOARG)
+				break;
+		/* FALLTHROUGH */
+		case OPTION_STRING:
+			if (opts->argh) {
+				if (opts->flags & PARSE_OPT_OPTARG)
+					if (opts->long_name)
+						pos += fprintf(stderr, "[=<%s>]", opts->argh);
+					else
+						pos += fprintf(stderr, "[<%s>]", opts->argh);
+				else
+					pos += fprintf(stderr, " <%s>", opts->argh);
+			} else {
+				if (opts->flags & PARSE_OPT_OPTARG)
+					if (opts->long_name)
+						pos += fprintf(stderr, "[=...]");
+					else
+						pos += fprintf(stderr, "[...]");
+				else
+					pos += fprintf(stderr, " ...");
+			}
+				break;
+		default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
+		case OPTION_END:
+		case OPTION_GROUP:
+		case OPTION_BIT:
+		case OPTION_BOOLEAN:
+		case OPTION_INCR:
+		case OPTION_SET_UINT:
+		case OPTION_SET_PTR:
+			break;
+		}
+		if (pos <= USAGE_OPTS_WIDTH)
+			pad = USAGE_OPTS_WIDTH - pos;
+		else {
+			fputc('\n', stderr);
+			pad = USAGE_OPTS_WIDTH;
+		}
+		fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
+	}
+	fputc('\n', stderr);
+
+	return PARSE_OPT_HELP;
+}
+
+void usage_with_options(const char * const *usagestr,
+		const struct option *opts)
+{
+	usage_with_options_internal(usagestr, opts, 0);
+	exit(129);
+}
+
+static void check_typos(const char *arg, const struct option *options)
+{
+	if (strlen(arg) < 3)
+		return;
+
+	if (!prefixcmp(arg, "no-")) {
+		pr_err("did you mean `--%s` (with two dashes ?)", arg);
+		exit(129);
+	}
+
+	for (; options->type != OPTION_END; options++) {
+		if (!options->long_name)
+			continue;
+		if (!prefixcmp(options->long_name, arg)) {
+			pr_err("did you mean `--%s` (with two dashes ?)", arg);
+			exit(129);
+		}
+	}
+}
+
+static int parse_options_usage(const char * const *usagestr,
+		const struct option *opts)
+{
+	return usage_with_options_internal(usagestr, opts, 0);
+}
+
+static int parse_short_opt(struct parse_opt_ctx_t *p,
+        const struct option *options)
+{
+	for (; options->type != OPTION_END; options++) {
+		if (options->short_name == *p->opt) {
+			p->opt = p->opt[1] ? p->opt + 1 : NULL;
+			return get_value(p, options, OPT_SHORT);
+		}
+	}
+	return -2;
+}
+
+static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
+		const struct option *options)
+{
+	const char *arg_end = strchr(arg, '=');
+	const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
+	int abbrev_flags = 0, ambiguous_flags = 0;
+
+	if (!arg_end)
+		arg_end = arg + strlen(arg);
+
+	for (; options->type != OPTION_END; options++) {
+		const char *rest;
+		int flags = 0;
+
+		if (!options->long_name)
+			continue;
+
+		rest = skip_prefix(arg, options->long_name);
+		if (options->type == OPTION_ARGUMENT) {
+			if (!rest)
+				continue;
+			if (*rest == '=')
+				return opterror(options, "takes no value",
+						flags);
+			if (*rest)
+				continue;
+			p->out[p->cpidx++] = arg - 2;
+			return 0;
+		}
+		if (!rest) {
+			/* abbreviated? */
+			if (!strncmp(options->long_name, arg, arg_end - arg)) {
+is_abbreviated:
+				if (abbrev_option) {
+					/*
+					 * If this is abbreviated, it is
+					 * ambiguous. So when there is no
+					 * exact match later, we need to
+					 * error out.
+					 */
+					ambiguous_option = abbrev_option;
+					ambiguous_flags = abbrev_flags;
+				}
+				if (!(flags & OPT_UNSET) && *arg_end)
+					p->opt = arg_end + 1;
+				abbrev_option = options;
+				abbrev_flags = flags;
+				continue;
+			}
+			/* negated and abbreviated very much? */
+			if (!prefixcmp("no-", arg)) {
+				flags |= OPT_UNSET;
+				goto is_abbreviated;
+			}
+			/* negated? */
+			if (strncmp(arg, "no-", 3))
+				continue;
+			flags |= OPT_UNSET;
+			rest = skip_prefix(arg + 3, options->long_name);
+			/* abbreviated and negated? */
+			if (!rest && !prefixcmp(options->long_name, arg + 3))
+				goto is_abbreviated;
+			if (!rest)
+				continue;
+		}
+		if (*rest) {
+			if (*rest != '=')
+				continue;
+			p->opt = rest + 1;
+		}
+		return get_value(p, options, flags);
+	}
+
+	if (ambiguous_option)
+		return pr_err("Ambiguous option: %s "
+				"(could be --%s%s or --%s%s)",
+				arg,
+				(ambiguous_flags & OPT_UNSET) ?  "no-" : "",
+				ambiguous_option->long_name,
+				(abbrev_flags & OPT_UNSET) ?  "no-" : "",
+				abbrev_option->long_name);
+	if (abbrev_option)
+		return get_value(p, abbrev_option, abbrev_flags);
+	return -2;
+}
+
+
+static void parse_options_start(struct parse_opt_ctx_t *ctx, int argc,
+		const char **argv, int flags)
+{
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->argc = argc;
+	ctx->argv = argv;
+	ctx->out  = argv;
+	ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
+	ctx->flags = flags;
+	if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
+			(flags & PARSE_OPT_STOP_AT_NON_OPTION))
+		die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
+}
+
+static int parse_options_end(struct parse_opt_ctx_t *ctx)
+{
+	memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
+	ctx->out[ctx->cpidx + ctx->argc] = NULL;
+	return ctx->cpidx + ctx->argc;
+}
+
+
+static int parse_options_step(struct parse_opt_ctx_t *ctx,
+		const struct option *options, const char * const usagestr[])
+{
+	int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
+
+	/* we must reset ->opt, unknown short option leave it dangling */
+	ctx->opt = NULL;
+
+	for (; ctx->argc; ctx->argc--, ctx->argv++) {
+		const char *arg = ctx->argv[0];
+
+		if (*arg != '-' || !arg[1]) {
+			if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
+				break;
+			ctx->out[ctx->cpidx++] = ctx->argv[0];
+			continue;
+		}
+
+		if (arg[1] != '-') {
+			ctx->opt = arg + 1;
+			if (internal_help && *ctx->opt == 'h')
+				return parse_options_usage(usagestr, options);
+			switch (parse_short_opt(ctx, options)) {
+			case -1:
+				return parse_options_usage(usagestr, options);
+			case -2:
+				goto unknown;
+			default:
+				break;
+			}
+			if (ctx->opt)
+				check_typos(arg + 1, options);
+			while (ctx->opt) {
+				if (internal_help && *ctx->opt == 'h')
+					return parse_options_usage(usagestr,
+							options);
+				switch (parse_short_opt(ctx, options)) {
+				case -1:
+					return parse_options_usage(usagestr,
+							options);
+				case -2:
+					/* fake a short option thing to hide
+					 * the fact that we may have
+					 * started to parse aggregated stuff
+					 *
+					 * This is leaky, too bad.
+					 */
+					ctx->argv[0] = strdup(ctx->opt - 1);
+					*(char *)ctx->argv[0] = '-';
+					goto unknown;
+				default:
+					break;
+				}
+			}
+			continue;
+		}
+
+		if (!arg[2]) { /* "--" */
+			if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
+				ctx->argc--;
+				ctx->argv++;
+			}
+			break;
+		}
+
+		if (internal_help && !strcmp(arg + 2, "help-all"))
+			return usage_with_options_internal(usagestr, options,
+					1);
+		if (internal_help && !strcmp(arg + 2, "help"))
+			return parse_options_usage(usagestr, options);
+		switch (parse_long_opt(ctx, arg + 2, options)) {
+		case -1:
+			return parse_options_usage(usagestr, options);
+		case -2:
+			goto unknown;
+		default:
+			break;
+		}
+		continue;
+unknown:
+		if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
+			return PARSE_OPT_UNKNOWN;
+		ctx->out[ctx->cpidx++] = ctx->argv[0];
+		ctx->opt = NULL;
+	}
+	return PARSE_OPT_DONE;
+}
+
+int parse_options(int argc, const char **argv, const struct option *options,
+		const char * const usagestr[], int flags)
+{
+	struct parse_opt_ctx_t ctx;
+
+	parse_options_start(&ctx, argc, argv, flags);
+	switch (parse_options_step(&ctx, options, usagestr)) {
+	case PARSE_OPT_HELP:
+		exit(129);
+	case PARSE_OPT_DONE:
+		break;
+	default: /* PARSE_OPT_UNKNOWN */
+		if (ctx.argv[0][1] == '-') {
+			pr_err("unknown option `%s'", ctx.argv[0] + 2);
+		} else {
+			pr_err("unknown switch `%c'", *ctx.opt);
+		}
+		usage_with_options(usagestr, options);
+	}
+
+	return parse_options_end(&ctx);
+}
diff --git a/tools/kvm/util/rbtree-interval.c b/tools/kvm/util/rbtree-interval.c
new file mode 100644
index 0000000..f9bf4b8
--- /dev/null
+++ b/tools/kvm/util/rbtree-interval.c
@@ -0,0 +1,89 @@
+#include <kvm/rbtree-interval.h>
+#include <stddef.h>
+#include <errno.h>
+
+struct rb_int_node *rb_int_search_single(struct rb_root *root, u64 point)
+{
+	struct rb_node *node = root->rb_node;
+	struct rb_node *lowest = NULL;
+
+	while (node) {
+		struct rb_int_node *cur = rb_int(node);
+
+		if (node->rb_left && (rb_int(node->rb_left)->max_high > point)) {
+			node = node->rb_left;
+		} else if (cur->low <= point && cur->high > point) {
+			lowest = node;
+			break;
+		} else if (point > cur->low) {
+			node = node->rb_right;
+		} else {
+			break;
+		}
+	}
+
+	if (lowest == NULL)
+		return NULL;
+
+	return rb_int(lowest);
+}
+
+struct rb_int_node *rb_int_search_range(struct rb_root *root, u64 low, u64 high)
+{
+	struct rb_int_node *range;
+
+	range = rb_int_search_single(root, low);
+	if (range == NULL)
+		return NULL;
+
+	/* We simply verify that 'high' is smaller than the end of the range where 'low' is located */
+	if (range->high < high)
+		return NULL;
+
+	return range;
+}
+
+static void update_node_max_high(struct rb_node *node, void *arg)
+{
+	struct rb_int_node *i_node = rb_int(node);
+
+	i_node->max_high = i_node->high;
+
+	if (node->rb_left)
+		i_node->max_high = max(i_node->max_high, rb_int(node->rb_left)->max_high);
+	if (node->rb_right)
+		i_node->max_high = max(i_node->max_high, rb_int(node->rb_right)->max_high);
+}
+
+int rb_int_insert(struct rb_root *root, struct rb_int_node *i_node)
+{
+	struct rb_node **node = &(root->rb_node), *parent = NULL;
+
+	while (*node) {
+		int result = i_node->low - rb_int(*node)->low;
+
+		parent = *node;
+		if (result < 0)
+			node	= &((*node)->rb_left);
+		else if (result > 0)
+			node	= &((*node)->rb_right);
+		else
+			return -EEXIST;
+	}
+
+	rb_link_node(&i_node->node, parent, node);
+	rb_insert_color(&i_node->node, root);
+
+	rb_augment_insert(&i_node->node, update_node_max_high, NULL);
+	return 0;
+}
+
+void rb_int_erase(struct rb_root *root, struct rb_int_node *node)
+{
+	struct rb_node *deepest;
+
+	deepest = rb_augment_erase_begin(&node->node);
+	rb_erase(&node->node, root);
+	rb_augment_erase_end(deepest, update_node_max_high, NULL);
+
+}
diff --git a/tools/kvm/util/read-write.c b/tools/kvm/util/read-write.c
new file mode 100644
index 0000000..44709df
--- /dev/null
+++ b/tools/kvm/util/read-write.c
@@ -0,0 +1,354 @@
+#include "kvm/read-write.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+/* Same as read(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xread(int fd, void *buf, size_t count)
+{
+	ssize_t nr;
+
+restart:
+	nr = read(fd, buf, count);
+	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+		goto restart;
+
+	return nr;
+}
+
+/* Same as write(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xwrite(int fd, const void *buf, size_t count)
+{
+	ssize_t nr;
+
+restart:
+	nr = write(fd, buf, count);
+	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+		goto restart;
+
+	return nr;
+}
+
+ssize_t read_in_full(int fd, void *buf, size_t count)
+{
+	ssize_t total = 0;
+	char *p = buf;
+
+	while (count > 0) {
+		ssize_t nr;
+
+		nr = xread(fd, p, count);
+		if (nr <= 0) {
+			if (total > 0)
+				return total;
+
+			return -1;
+		}
+
+		count -= nr;
+		total += nr;
+		p += nr;
+	}
+
+	return total;
+}
+
+ssize_t write_in_full(int fd, const void *buf, size_t count)
+{
+	const char *p = buf;
+	ssize_t total = 0;
+
+	while (count > 0) {
+		ssize_t nr;
+
+		nr = xwrite(fd, p, count);
+		if (nr < 0)
+			return -1;
+		if (nr == 0) {
+			errno = ENOSPC;
+			return -1;
+		}
+		count -= nr;
+		total += nr;
+		p += nr;
+	}
+
+	return total;
+}
+
+/* Same as pread(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
+{
+	ssize_t nr;
+
+restart:
+	nr = pread(fd, buf, count, offset);
+	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+		goto restart;
+
+	return nr;
+}
+
+/* Same as pwrite(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+	ssize_t nr;
+
+restart:
+	nr = pwrite(fd, buf, count, offset);
+	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+		goto restart;
+
+	return nr;
+}
+
+ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset)
+{
+	ssize_t total = 0;
+	char *p = buf;
+
+	while (count > 0) {
+		ssize_t nr;
+
+		nr = xpread(fd, p, count, offset);
+		if (nr <= 0) {
+			if (total > 0)
+				return total;
+
+			return -1;
+		}
+
+		count -= nr;
+		total += nr;
+		p += nr;
+		offset += nr;
+	}
+
+	return total;
+}
+
+ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset)
+{
+	const char *p = buf;
+	ssize_t total = 0;
+
+	while (count > 0) {
+		ssize_t nr;
+
+		nr = xpwrite(fd, p, count, offset);
+		if (nr < 0)
+			return -1;
+		if (nr == 0) {
+			errno = ENOSPC;
+			return -1;
+		}
+		count -= nr;
+		total += nr;
+		p += nr;
+		offset += nr;
+	}
+
+	return total;
+}
+
+/* Same as readv(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt)
+{
+	ssize_t nr;
+
+restart:
+	nr = readv(fd, iov, iovcnt);
+	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+		goto restart;
+
+	return nr;
+}
+
+/* Same as writev(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt)
+{
+	ssize_t nr;
+
+restart:
+	nr = writev(fd, iov, iovcnt);
+	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+		goto restart;
+
+	return nr;
+}
+
+static inline ssize_t get_iov_size(const struct iovec *iov, int iovcnt)
+{
+	size_t size = 0;
+	while (iovcnt--)
+		size += (iov++)->iov_len;
+
+	return size;
+}
+
+static inline void shift_iovec(const struct iovec **iov, int *iovcnt,
+				size_t nr, ssize_t *total, size_t *count, off_t *offset)
+{
+	while (nr >= (*iov)->iov_len) {
+		nr -= (*iov)->iov_len;
+		*total += (*iov)->iov_len;
+		*count -= (*iov)->iov_len;
+		if (offset)
+			*offset += (*iov)->iov_len;
+		(*iovcnt)--;
+		(*iov)++;
+	}
+}
+
+ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt)
+{
+	ssize_t total = 0;
+	size_t count = get_iov_size(iov, iovcnt);
+
+	while (count > 0) {
+		ssize_t nr;
+
+		nr = xreadv(fd, iov, iovcnt);
+		if (nr <= 0) {
+			if (total > 0)
+				return total;
+
+			return -1;
+		}
+
+		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
+	}
+
+	return total;
+}
+
+ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt)
+{
+	ssize_t total = 0;
+	size_t count = get_iov_size(iov, iovcnt);
+
+	while (count > 0) {
+		ssize_t nr;
+
+		nr = xwritev(fd, iov, iovcnt);
+		if (nr < 0)
+			return -1;
+		if (nr == 0) {
+			errno = ENOSPC;
+			return -1;
+		}
+
+		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
+	}
+
+	return total;
+}
+
+/* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+	ssize_t nr;
+
+restart:
+	nr = preadv(fd, iov, iovcnt, offset);
+	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+		goto restart;
+
+	return nr;
+}
+
+/* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+	ssize_t nr;
+
+restart:
+	nr = pwritev(fd, iov, iovcnt, offset);
+	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+		goto restart;
+
+	return nr;
+}
+
+ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+	ssize_t total = 0;
+	size_t count = get_iov_size(iov, iovcnt);
+
+	while (count > 0) {
+		ssize_t nr;
+
+		nr = xpreadv(fd, iov, iovcnt, offset);
+		if (nr <= 0) {
+			if (total > 0)
+				return total;
+
+			return -1;
+		}
+
+		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
+	}
+
+	return total;
+}
+
+ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+	ssize_t total = 0;
+	size_t count = get_iov_size(iov, iovcnt);
+
+	while (count > 0) {
+		ssize_t nr;
+
+		nr = xpwritev(fd, iov, iovcnt, offset);
+		if (nr < 0)
+			return -1;
+		if (nr == 0) {
+			errno = ENOSPC;
+			return -1;
+		}
+
+		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
+	}
+
+	return total;
+}
+
+#ifdef CONFIG_HAS_AIO
+int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
+		off_t offset, int ev, void *param)
+{
+	struct iocb *ios[1] = { iocb };
+	int ret;
+
+	io_prep_pwritev(iocb, fd, iov, iovcnt, offset);
+	io_set_eventfd(iocb, ev);
+	iocb->data = param;
+
+restart:
+	ret = io_submit(ctx, 1, ios);
+	if (ret == -EAGAIN)
+		goto restart;
+	return ret;
+}
+
+int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
+		off_t offset, int ev, void *param)
+{
+	struct iocb *ios[1] = { iocb };
+	int ret;
+
+	io_prep_preadv(iocb, fd, iov, iovcnt, offset);
+	io_set_eventfd(iocb, ev);
+	iocb->data = param;
+
+restart:
+	ret = io_submit(ctx, 1, ios);
+	if (ret == -EAGAIN)
+		goto restart;
+	return ret;
+}
+#endif
diff --git a/tools/kvm/util/set_private_br.sh b/tools/kvm/util/set_private_br.sh
new file mode 100755
index 0000000..49867dd
--- /dev/null
+++ b/tools/kvm/util/set_private_br.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Author: Amos Kong <kongjianjun@gmail.com>
+# Date: Apr 14, 2011
+# Description: this script is used to create/delete a private bridge,
+# launch a dhcp server on the bridge by dnsmasq.
+#
+# @ ./set_private_br.sh $bridge_name $subnet_prefix
+# @ ./set_private_br.sh vbr0 192.168.33
+
+brname='vbr0'
+subnet='192.168.33'
+
+add_br()
+{
+    echo "add new private bridge: $brname"
+    /usr/sbin/brctl addbr $brname
+    echo 1 > /proc/sys/net/ipv6/conf/$brname/disable_ipv6
+    echo 1 > /proc/sys/net/ipv4/ip_forward
+    /usr/sbin/brctl stp $brname on
+    /usr/sbin/brctl setfd $brname 0
+    ifconfig $brname $subnet.1
+    ifconfig $brname up
+    # Add forward rule, then guest can access public network
+    iptables -t nat -A POSTROUTING -s $subnet.254/24 ! -d $subnet.254/24 -j MASQUERADE
+    /etc/init.d/dnsmasq stop
+    /etc/init.d/tftpd-hpa stop 2>/dev/null
+    dnsmasq --strict-order --bind-interfaces --listen-address $subnet.1 --dhcp-range $subnet.1,$subnet.254 $tftp_cmd
+}
+
+del_br()
+{
+    echo "cleanup bridge setup"
+    kill -9 `pgrep dnsmasq|tail -1`
+    ifconfig $brname down
+    /usr/sbin/brctl delbr $brname
+    iptables -t nat -D POSTROUTING -s $subnet.254/24 ! -d $subnet.254/24 -j MASQUERADE
+}
+
+
+if [ $# = 0 ]; then
+    del_br 2>/dev/null
+    exit
+fi
+if [ $# > 1 ]; then
+    brname="$1"
+fi
+if [ $# = 2 ]; then
+    subnet="$2"
+fi
+add_br
diff --git a/tools/kvm/util/strbuf.c b/tools/kvm/util/strbuf.c
new file mode 100644
index 0000000..99d6b0c
--- /dev/null
+++ b/tools/kvm/util/strbuf.c
@@ -0,0 +1,62 @@
+
+/* user defined headers */
+#include <kvm/util.h>
+#include <kvm/strbuf.h>
+
+int prefixcmp(const char *str, const char *prefix)
+{
+	for (; ; str++, prefix++) {
+		if (!*prefix)
+			return 0;
+		else if (*str != *prefix)
+			return (unsigned char)*prefix - (unsigned char)*str;
+	}
+}
+
+/**
+ * strlcat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @count: The size of the destination buffer.
+ */
+size_t strlcat(char *dest, const char *src, size_t count)
+{
+	size_t dsize = strlen(dest);
+	size_t len = strlen(src);
+	size_t res = dsize + len;
+
+	DIE_IF(dsize >= count);
+
+	dest += dsize;
+	count -= dsize;
+	if (len >= count)
+		len = count - 1;
+
+	memcpy(dest, src, len);
+	dest[len] = 0;
+
+	return res;
+}
+
+/**
+ * strlcpy - Copy a %NUL terminated string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ */
+size_t strlcpy(char *dest, const char *src, size_t size)
+{
+	size_t ret = strlen(src);
+
+	if (size) {
+		size_t len = (ret >= size) ? size - 1 : ret;
+		memcpy(dest, src, len);
+		dest[len] = '\0';
+	}
+	return ret;
+}
diff --git a/tools/kvm/util/threadpool.c b/tools/kvm/util/threadpool.c
new file mode 100644
index 0000000..bafbcd7
--- /dev/null
+++ b/tools/kvm/util/threadpool.c
@@ -0,0 +1,145 @@
+#include "kvm/threadpool.h"
+#include "kvm/mutex.h"
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+static pthread_mutex_t	job_mutex	= PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t	thread_mutex	= PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t	job_cond	= PTHREAD_COND_INITIALIZER;
+
+static LIST_HEAD(head);
+
+static pthread_t	*threads;
+static long		threadcount;
+
+static struct thread_pool__job *thread_pool__job_pop_locked(void)
+{
+	struct thread_pool__job *job;
+
+	if (list_empty(&head))
+		return NULL;
+
+	job = list_first_entry(&head, struct thread_pool__job, queue);
+	list_del(&job->queue);
+
+	return job;
+}
+
+static void thread_pool__job_push_locked(struct thread_pool__job *job)
+{
+	list_add_tail(&job->queue, &head);
+}
+
+static struct thread_pool__job *thread_pool__job_pop(void)
+{
+	struct thread_pool__job *job;
+
+	mutex_lock(&job_mutex);
+	job = thread_pool__job_pop_locked();
+	mutex_unlock(&job_mutex);
+	return job;
+}
+
+static void thread_pool__job_push(struct thread_pool__job *job)
+{
+	mutex_lock(&job_mutex);
+	thread_pool__job_push_locked(job);
+	mutex_unlock(&job_mutex);
+}
+
+static void thread_pool__handle_job(struct thread_pool__job *job)
+{
+	while (job) {
+		job->callback(job->kvm, job->data);
+
+		mutex_lock(&job->mutex);
+
+		if (--job->signalcount > 0)
+			/* If the job was signaled again while we were working */
+			thread_pool__job_push(job);
+
+		mutex_unlock(&job->mutex);
+
+		job = thread_pool__job_pop();
+	}
+}
+
+static void thread_pool__threadfunc_cleanup(void *param)
+{
+	mutex_unlock(&job_mutex);
+}
+
+static void *thread_pool__threadfunc(void *param)
+{
+	pthread_cleanup_push(thread_pool__threadfunc_cleanup, NULL);
+
+	for (;;) {
+		struct thread_pool__job *curjob;
+
+		mutex_lock(&job_mutex);
+		while ((curjob = thread_pool__job_pop_locked()) == NULL)
+			pthread_cond_wait(&job_cond, &job_mutex);
+		mutex_unlock(&job_mutex);
+
+		thread_pool__handle_job(curjob);
+	}
+
+	pthread_cleanup_pop(0);
+
+	return NULL;
+}
+
+static int thread_pool__addthread(void)
+{
+	int res;
+	void *newthreads;
+
+	mutex_lock(&thread_mutex);
+	newthreads = realloc(threads, (threadcount + 1) * sizeof(pthread_t));
+	if (newthreads == NULL) {
+		mutex_unlock(&thread_mutex);
+		return -1;
+	}
+
+	threads = newthreads;
+
+	res = pthread_create(threads + threadcount, NULL,
+			     thread_pool__threadfunc, NULL);
+
+	if (res == 0)
+		threadcount++;
+	mutex_unlock(&thread_mutex);
+
+	return res;
+}
+
+int thread_pool__init(unsigned long thread_count)
+{
+	unsigned long i;
+
+	for (i = 0; i < thread_count; i++)
+		if (thread_pool__addthread() < 0)
+			return i;
+
+	return i;
+}
+
+void thread_pool__do_job(struct thread_pool__job *job)
+{
+	struct thread_pool__job *jobinfo = job;
+
+	if (jobinfo == NULL || jobinfo->callback == NULL)
+		return;
+
+	mutex_lock(&jobinfo->mutex);
+	if (jobinfo->signalcount++ == 0)
+		thread_pool__job_push(job);
+	mutex_unlock(&jobinfo->mutex);
+
+	mutex_lock(&job_mutex);
+	pthread_cond_signal(&job_cond);
+	mutex_unlock(&job_mutex);
+}
diff --git a/tools/kvm/util/util.c b/tools/kvm/util/util.c
new file mode 100644
index 0000000..e7feebc
--- /dev/null
+++ b/tools/kvm/util/util.c
@@ -0,0 +1,115 @@
+/*
+ * Taken from perf which in turn take it from GIT
+ */
+
+#include "kvm/util.h"
+
+#include <linux/magic.h>	/* For HUGETLBFS_MAGIC */
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+
+static void report(const char *prefix, const char *err, va_list params)
+{
+	char msg[1024];
+	vsnprintf(msg, sizeof(msg), err, params);
+	fprintf(stderr, " %s%s\n", prefix, msg);
+}
+
+static NORETURN void die_builtin(const char *err, va_list params)
+{
+	report(" Fatal: ", err, params);
+	exit(128);
+}
+
+static void error_builtin(const char *err, va_list params)
+{
+	report(" Error: ", err, params);
+}
+
+static void warn_builtin(const char *warn, va_list params)
+{
+	report(" Warning: ", warn, params);
+}
+
+static void info_builtin(const char *info, va_list params)
+{
+	report(" Info: ", info, params);
+}
+
+void die(const char *err, ...)
+{
+	va_list params;
+
+	va_start(params, err);
+	die_builtin(err, params);
+	va_end(params);
+}
+
+int pr_err(const char *err, ...)
+{
+	va_list params;
+
+	va_start(params, err);
+	error_builtin(err, params);
+	va_end(params);
+	return -1;
+}
+
+void pr_warning(const char *warn, ...)
+{
+	va_list params;
+
+	va_start(params, warn);
+	warn_builtin(warn, params);
+	va_end(params);
+}
+
+void pr_info(const char *info, ...)
+{
+	va_list params;
+
+	va_start(params, info);
+	info_builtin(info, params);
+	va_end(params);
+}
+
+void die_perror(const char *s)
+{
+	perror(s);
+	exit(1);
+}
+
+void *mmap_hugetlbfs(const char *htlbfs_path, u64 size)
+{
+	char mpath[PATH_MAX];
+	int fd;
+	struct statfs sfs;
+	void *addr;
+	unsigned long blk_size;
+
+	if (statfs(htlbfs_path, &sfs) < 0)
+		die("Can't stat %s\n", htlbfs_path);
+
+	if ((unsigned int)sfs.f_type != HUGETLBFS_MAGIC)
+		die("%s is not hugetlbfs!\n", htlbfs_path);
+
+	blk_size = (unsigned long)sfs.f_bsize;
+	if (sfs.f_bsize == 0 || blk_size > size) {
+		die("Can't use hugetlbfs pagesize %ld for mem size %lld\n",
+		    blk_size, size);
+	}
+
+	snprintf(mpath, PATH_MAX, "%s/kvmtoolXXXXXX", htlbfs_path);
+	fd = mkstemp(mpath);
+	if (fd < 0)
+		die("Can't open %s for hugetlbfs map\n", mpath);
+	unlink(mpath);
+	if (ftruncate(fd, size) < 0)
+		die("Can't ftruncate for mem mapping size %lld\n",
+		    size);
+	addr = mmap(NULL, size, PROT_RW, MAP_PRIVATE, fd, 0);
+	close(fd);
+
+	return addr;
+}
diff --git a/tools/kvm/virtio/9p-pdu.c b/tools/kvm/virtio/9p-pdu.c
new file mode 100644
index 0000000..b9ce8ce
--- /dev/null
+++ b/tools/kvm/virtio/9p-pdu.c
@@ -0,0 +1,287 @@
+#include "kvm/util.h"
+#include "kvm/virtio-9p.h"
+
+#include <endian.h>
+#include <stdint.h>
+
+#include <linux/compiler.h>
+#include <net/9p/9p.h>
+
+static void virtio_p9_pdu_read(struct p9_pdu *pdu, void *data, size_t size)
+{
+	size_t len;
+	int i, copied = 0;
+	u16 iov_cnt = pdu->out_iov_cnt;
+	size_t offset = pdu->read_offset;
+	struct iovec *iov = pdu->out_iov;
+
+	for (i = 0; i < iov_cnt && size; i++) {
+		if (offset >= iov[i].iov_len) {
+			offset -= iov[i].iov_len;
+			continue;
+		} else {
+			len = MIN(iov[i].iov_len - offset, size);
+			memcpy(data, iov[i].iov_base + offset, len);
+			size -= len;
+			data += len;
+			offset = 0;
+			copied += len;
+		}
+	}
+	pdu->read_offset += copied;
+}
+
+static void virtio_p9_pdu_write(struct p9_pdu *pdu,
+				const void *data, size_t size)
+{
+	size_t len;
+	int i, copied = 0;
+	u16 iov_cnt = pdu->in_iov_cnt;
+	size_t offset = pdu->write_offset;
+	struct iovec *iov = pdu->in_iov;
+
+	for (i = 0; i < iov_cnt && size; i++) {
+		if (offset >= iov[i].iov_len) {
+			offset -= iov[i].iov_len;
+			continue;
+		} else {
+			len = MIN(iov[i].iov_len - offset, size);
+			memcpy(iov[i].iov_base + offset, data, len);
+			size -= len;
+			data += len;
+			offset = 0;
+			copied += len;
+		}
+	}
+	pdu->write_offset += copied;
+}
+
+static void virtio_p9_wstat_free(struct p9_wstat *stbuf)
+{
+	free(stbuf->name);
+	free(stbuf->uid);
+	free(stbuf->gid);
+	free(stbuf->muid);
+}
+
+static int virtio_p9_decode(struct p9_pdu *pdu, const char *fmt, va_list ap)
+{
+	int retval = 0;
+	const char *ptr;
+
+	for (ptr = fmt; *ptr; ptr++) {
+		switch (*ptr) {
+		case 'b':
+		{
+			int8_t *val = va_arg(ap, int8_t *);
+			virtio_p9_pdu_read(pdu, val, sizeof(*val));
+		}
+		break;
+		case 'w':
+		{
+			int16_t le_val;
+			int16_t *val = va_arg(ap, int16_t *);
+			virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val));
+			*val = le16toh(le_val);
+		}
+		break;
+		case 'd':
+		{
+			int32_t le_val;
+			int32_t *val = va_arg(ap, int32_t *);
+			virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val));
+			*val = le32toh(le_val);
+		}
+		break;
+		case 'q':
+		{
+			int64_t le_val;
+			int64_t *val = va_arg(ap, int64_t *);
+			virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val));
+			*val = le64toh(le_val);
+		}
+		break;
+		case 's':
+		{
+			int16_t len;
+			char **str = va_arg(ap, char **);
+
+			virtio_p9_pdu_readf(pdu, "w", &len);
+			*str = malloc(len + 1);
+			if (*str == NULL) {
+				retval = ENOMEM;
+				break;
+			}
+			virtio_p9_pdu_read(pdu, *str, len);
+			(*str)[len] = 0;
+		}
+		break;
+		case 'Q':
+		{
+			struct p9_qid *qid = va_arg(ap, struct p9_qid *);
+			retval = virtio_p9_pdu_readf(pdu, "bdq",
+						     &qid->type, &qid->version,
+						     &qid->path);
+		}
+		break;
+		case 'S':
+		{
+			struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *);
+			memset(stbuf, 0, sizeof(struct p9_wstat));
+			stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = -1;
+			retval = virtio_p9_pdu_readf(pdu, "wwdQdddqssss",
+						&stbuf->size, &stbuf->type,
+						&stbuf->dev, &stbuf->qid,
+						&stbuf->mode, &stbuf->atime,
+						&stbuf->mtime, &stbuf->length,
+						&stbuf->name, &stbuf->uid,
+						&stbuf->gid, &stbuf->muid);
+			if (retval)
+				virtio_p9_wstat_free(stbuf);
+		}
+		break;
+		case 'I':
+		{
+			struct p9_iattr_dotl *p9attr = va_arg(ap,
+						       struct p9_iattr_dotl *);
+
+			retval = virtio_p9_pdu_readf(pdu, "ddddqqqqq",
+						     &p9attr->valid,
+						     &p9attr->mode,
+						     &p9attr->uid,
+						     &p9attr->gid,
+						     &p9attr->size,
+						     &p9attr->atime_sec,
+						     &p9attr->atime_nsec,
+						     &p9attr->mtime_sec,
+						     &p9attr->mtime_nsec);
+		}
+		break;
+		default:
+			retval = EINVAL;
+			break;
+		}
+	}
+	return retval;
+}
+
+static int virtio_p9_pdu_encode(struct p9_pdu *pdu, const char *fmt, va_list ap)
+{
+	int retval = 0;
+	const char *ptr;
+
+	for (ptr = fmt; *ptr; ptr++) {
+		switch (*ptr) {
+		case 'b':
+		{
+			int8_t val = va_arg(ap, int);
+			virtio_p9_pdu_write(pdu, &val, sizeof(val));
+		}
+		break;
+		case 'w':
+		{
+			int16_t val = htole16(va_arg(ap, int));
+			virtio_p9_pdu_write(pdu, &val, sizeof(val));
+		}
+		break;
+		case 'd':
+		{
+			int32_t val = htole32(va_arg(ap, int32_t));
+			virtio_p9_pdu_write(pdu, &val, sizeof(val));
+		}
+		break;
+		case 'q':
+		{
+			int64_t val = htole64(va_arg(ap, int64_t));
+			virtio_p9_pdu_write(pdu, &val, sizeof(val));
+		}
+		break;
+		case 's':
+		{
+			uint16_t len = 0;
+			const char *s = va_arg(ap, char *);
+			if (s)
+				len = MIN(strlen(s), USHRT_MAX);
+			virtio_p9_pdu_writef(pdu, "w", len);
+			virtio_p9_pdu_write(pdu, s, len);
+		}
+		break;
+		case 'Q':
+		{
+			struct p9_qid *qid = va_arg(ap, struct p9_qid *);
+			retval = virtio_p9_pdu_writef(pdu, "bdq",
+						      qid->type, qid->version,
+						      qid->path);
+		}
+		break;
+		case 'S':
+		{
+			struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *);
+			retval = virtio_p9_pdu_writef(pdu, "wwdQdddqssss",
+						stbuf->size, stbuf->type,
+						stbuf->dev, &stbuf->qid,
+						stbuf->mode, stbuf->atime,
+						stbuf->mtime, stbuf->length,
+						stbuf->name, stbuf->uid,
+						stbuf->gid, stbuf->muid);
+		}
+		break;
+		case 'A':
+		{
+			struct p9_stat_dotl *stbuf = va_arg(ap,
+						      struct p9_stat_dotl *);
+			retval  = virtio_p9_pdu_writef(pdu,
+						       "qQdddqqqqqqqqqqqqqqq",
+						       stbuf->st_result_mask,
+						       &stbuf->qid,
+						       stbuf->st_mode,
+						       stbuf->st_uid,
+						       stbuf->st_gid,
+						       stbuf->st_nlink,
+						       stbuf->st_rdev,
+						       stbuf->st_size,
+						       stbuf->st_blksize,
+						       stbuf->st_blocks,
+						       stbuf->st_atime_sec,
+						       stbuf->st_atime_nsec,
+						       stbuf->st_mtime_sec,
+						       stbuf->st_mtime_nsec,
+						       stbuf->st_ctime_sec,
+						       stbuf->st_ctime_nsec,
+						       stbuf->st_btime_sec,
+						       stbuf->st_btime_nsec,
+						       stbuf->st_gen,
+						       stbuf->st_data_version);
+		}
+		break;
+		default:
+			retval = EINVAL;
+			break;
+		}
+	}
+	return retval;
+}
+
+int virtio_p9_pdu_readf(struct p9_pdu *pdu, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = virtio_p9_decode(pdu, fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
+
+int virtio_p9_pdu_writef(struct p9_pdu *pdu, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = virtio_p9_pdu_encode(pdu, fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
diff --git a/tools/kvm/virtio/9p.c b/tools/kvm/virtio/9p.c
new file mode 100644
index 0000000..830fc50
--- /dev/null
+++ b/tools/kvm/virtio/9p.c
@@ -0,0 +1,1338 @@
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/ioport.h"
+#include "kvm/util.h"
+#include "kvm/threadpool.h"
+#include "kvm/irq.h"
+#include "kvm/virtio-9p.h"
+#include "kvm/guest_compat.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/vfs.h>
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_9p.h>
+#include <net/9p/9p.h>
+
+static LIST_HEAD(devs);
+static int compat_id = -1;
+
+static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid)
+{
+	if (fid >= VIRTIO_9P_MAX_FID)
+		die("virtio-9p max FID (%u) reached!", VIRTIO_9P_MAX_FID);
+
+	return &p9dev->fids[fid];
+}
+
+/* Warning: Immediately use value returned from this function */
+static const char *rel_to_abs(struct p9_dev *p9dev,
+			      const char *path, char *abs_path)
+{
+	sprintf(abs_path, "%s/%s", p9dev->root_dir, path);
+
+	return abs_path;
+}
+
+static void stat2qid(struct stat *st, struct p9_qid *qid)
+{
+	*qid = (struct p9_qid) {
+		.path		= st->st_ino,
+		.version	= st->st_mtime,
+	};
+
+	if (S_ISDIR(st->st_mode))
+		qid->type	|= P9_QTDIR;
+}
+
+static void close_fid(struct p9_dev *p9dev, u32 fid)
+{
+	if (p9dev->fids[fid].fd > 0) {
+		close(p9dev->fids[fid].fd);
+		p9dev->fids[fid].fd = -1;
+	}
+	if (p9dev->fids[fid].dir) {
+		closedir(p9dev->fids[fid].dir);
+		p9dev->fids[fid].dir = NULL;
+	}
+	p9dev->fids[fid].fid = P9_NOFID;
+}
+
+static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size)
+{
+	u8 cmd;
+	u16 tag;
+
+	pdu->read_offset = sizeof(u32);
+	virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag);
+	pdu->write_offset = 0;
+	/* cmd + 1 is the reply message */
+	virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag);
+}
+
+static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt)
+{
+	int i;
+	u32 total = 0;
+	for (i = 0; (i < iov_cnt) && (total < count); i++) {
+		if (total + iov[i].iov_len > count) {
+			/* we don't need this iov fully */
+			iov[i].iov_len -= ((total + iov[i].iov_len) - count);
+			i++;
+			break;
+		}
+		total += iov[i].iov_len;
+	}
+	return i;
+}
+
+static void virtio_p9_error_reply(struct p9_dev *p9dev,
+				  struct p9_pdu *pdu, int err, u32 *outlen)
+{
+	u16 tag;
+
+	pdu->write_offset = VIRTIO_9P_HDR_LEN;
+	virtio_p9_pdu_writef(pdu, "d", err);
+	*outlen = pdu->write_offset;
+
+	/* read the tag from input */
+	pdu->read_offset = sizeof(u32) + sizeof(u8);
+	virtio_p9_pdu_readf(pdu, "w", &tag);
+
+	/* Update the header */
+	pdu->write_offset = 0;
+	virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag);
+}
+
+static void virtio_p9_version(struct p9_dev *p9dev,
+			      struct p9_pdu *pdu, u32 *outlen)
+{
+	u32 msize;
+	char *version;
+	virtio_p9_pdu_readf(pdu, "ds", &msize, &version);
+	/*
+	 * reply with the same msize the client sent us
+	 * Error out if the request is not for 9P2000.L
+	 */
+	if (!strcmp(version, VIRTIO_9P_VERSION_DOTL))
+		virtio_p9_pdu_writef(pdu, "ds", msize, version);
+	else
+		virtio_p9_pdu_writef(pdu, "ds", msize, "unknown");
+
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	free(version);
+	return;
+}
+
+static void virtio_p9_clunk(struct p9_dev *p9dev,
+			    struct p9_pdu *pdu, u32 *outlen)
+{
+	u32 fid;
+
+	virtio_p9_pdu_readf(pdu, "d", &fid);
+	close_fid(p9dev, fid);
+
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+}
+
+/*
+ * FIXME!! Need to map to protocol independent value. Upstream
+ * 9p also have the same BUG
+ */
+static int virtio_p9_openflags(int flags)
+{
+	flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT);
+	flags |= O_NOFOLLOW;
+	return flags;
+}
+
+static void virtio_p9_open(struct p9_dev *p9dev,
+			   struct p9_pdu *pdu, u32 *outlen)
+{
+	u32 fid, flags;
+	struct stat st;
+	struct p9_qid qid;
+	struct p9_fid *new_fid;
+
+
+	virtio_p9_pdu_readf(pdu, "dd", &fid, &flags);
+	new_fid = get_fid(p9dev, fid);
+
+	if (lstat(new_fid->abs_path, &st) < 0)
+		goto err_out;
+
+	stat2qid(&st, &qid);
+
+	if (new_fid->is_dir) {
+		new_fid->dir = opendir(new_fid->abs_path);
+		if (!new_fid->dir)
+			goto err_out;
+	} else {
+		new_fid->fd  = open(new_fid->abs_path,
+				    virtio_p9_openflags(flags));
+		if (new_fid->fd < 0)
+			goto err_out;
+	}
+	/* FIXME!! need ot send proper iounit  */
+	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
+
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_create(struct p9_dev *p9dev,
+			     struct p9_pdu *pdu, u32 *outlen)
+{
+	int fd, ret;
+	char *name;
+	struct stat st;
+	struct p9_qid qid;
+	struct p9_fid *dfid;
+	char full_path[PATH_MAX];
+	u32 dfid_val, flags, mode, gid;
+
+	virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val,
+			    &name, &flags, &mode, &gid);
+	dfid = get_fid(p9dev, dfid_val);
+
+	flags = virtio_p9_openflags(flags);
+
+	sprintf(full_path, "%s/%s", dfid->abs_path, name);
+	fd = open(full_path, flags | O_CREAT, mode);
+	if (fd < 0)
+		goto err_out;
+	close_fid(p9dev, dfid_val);
+	dfid->fd = fd;
+
+	if (lstat(full_path, &st) < 0)
+		goto err_out;
+
+	ret = chmod(full_path, mode & 0777);
+	if (ret < 0)
+		goto err_out;
+
+	ret = lchown(full_path, dfid->uid, gid);
+	if (ret < 0)
+		goto err_out;
+
+	sprintf(dfid->path, "%s/%s", dfid->path, name);
+	stat2qid(&st, &qid);
+	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	free(name);
+	return;
+err_out:
+	free(name);
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_mkdir(struct p9_dev *p9dev,
+			    struct p9_pdu *pdu, u32 *outlen)
+{
+	int ret;
+	char *name;
+	struct stat st;
+	struct p9_qid qid;
+	struct p9_fid *dfid;
+	char full_path[PATH_MAX];
+	u32 dfid_val, mode, gid;
+
+	virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val,
+			    &name, &mode, &gid);
+	dfid = get_fid(p9dev, dfid_val);
+
+	sprintf(full_path, "%s/%s", dfid->abs_path, name);
+	ret = mkdir(full_path, mode);
+	if (ret < 0)
+		goto err_out;
+
+	if (lstat(full_path, &st) < 0)
+		goto err_out;
+
+	ret = chmod(full_path, mode & 0777);
+	if (ret < 0)
+		goto err_out;
+
+	ret = lchown(full_path, dfid->uid, gid);
+	if (ret < 0)
+		goto err_out;
+
+	stat2qid(&st, &qid);
+	virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	free(name);
+	return;
+err_out:
+	free(name);
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_walk(struct p9_dev *p9dev,
+			   struct p9_pdu *pdu, u32 *outlen)
+{
+	u8 i;
+	u16 nwqid;
+	u16 nwname;
+	struct p9_qid wqid;
+	struct p9_fid *new_fid;
+	u32 fid_val, newfid_val;
+
+
+	virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname);
+	new_fid	= get_fid(p9dev, newfid_val);
+
+	nwqid = 0;
+	if (nwname) {
+		struct p9_fid *fid = get_fid(p9dev, fid_val);
+
+		strcpy(new_fid->path, fid->path);
+		/* skip the space for count */
+		pdu->write_offset += sizeof(u16);
+		for (i = 0; i < nwname; i++) {
+			struct stat st;
+			char tmp[PATH_MAX] = {0};
+			char full_path[PATH_MAX];
+			char *str;
+
+			virtio_p9_pdu_readf(pdu, "s", &str);
+
+			/* Format the new path we're 'walk'ing into */
+			sprintf(tmp, "%s/%s", new_fid->path, str);
+
+			free(str);
+
+			if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0)
+				goto err_out;
+
+			stat2qid(&st, &wqid);
+			new_fid->is_dir = S_ISDIR(st.st_mode);
+			strcpy(new_fid->path, tmp);
+			new_fid->fid = newfid_val;
+			new_fid->uid = fid->uid;
+			nwqid++;
+			virtio_p9_pdu_writef(pdu, "Q", &wqid);
+		}
+	} else {
+		/*
+		 * update write_offset so our outlen get correct value
+		 */
+		pdu->write_offset += sizeof(u16);
+		new_fid->is_dir = p9dev->fids[fid_val].is_dir;
+		strcpy(new_fid->path, p9dev->fids[fid_val].path);
+		new_fid->fid	= newfid_val;
+		new_fid->uid    = p9dev->fids[fid_val].uid;
+	}
+	*outlen = pdu->write_offset;
+	pdu->write_offset = VIRTIO_9P_HDR_LEN;
+	virtio_p9_pdu_writef(pdu, "d", nwqid);
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_attach(struct p9_dev *p9dev,
+			     struct p9_pdu *pdu, u32 *outlen)
+{
+	int i;
+	char *uname;
+	char *aname;
+	struct stat st;
+	struct p9_qid qid;
+	struct p9_fid *fid;
+	u32 fid_val, afid, uid;
+
+	virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid,
+			    &uname, &aname, &uid);
+
+	free(uname);
+	free(aname);
+
+	/* Reset everything */
+	for (i = 0; i < VIRTIO_9P_MAX_FID; i++)
+		p9dev->fids[i].fid = P9_NOFID;
+
+	if (lstat(p9dev->root_dir, &st) < 0)
+		goto err_out;
+
+	stat2qid(&st, &qid);
+
+	fid = get_fid(p9dev, fid_val);
+	fid->fid = fid_val;
+	fid->uid = uid;
+	fid->is_dir = 1;
+	strcpy(fid->path, "/");
+
+	virtio_p9_pdu_writef(pdu, "Q", &qid);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_fill_stat(struct p9_dev *p9dev,
+				struct stat *st, struct p9_stat_dotl *statl)
+{
+	memset(statl, 0, sizeof(*statl));
+	statl->st_mode		= st->st_mode;
+	statl->st_nlink		= st->st_nlink;
+	statl->st_uid		= st->st_uid;
+	statl->st_gid		= st->st_gid;
+	statl->st_rdev		= st->st_rdev;
+	statl->st_size		= st->st_size;
+	statl->st_blksize	= st->st_blksize;
+	statl->st_blocks	= st->st_blocks;
+	statl->st_atime_sec	= st->st_atime;
+	statl->st_atime_nsec	= st->st_atim.tv_nsec;
+	statl->st_mtime_sec	= st->st_mtime;
+	statl->st_mtime_nsec	= st->st_mtim.tv_nsec;
+	statl->st_ctime_sec	= st->st_ctime;
+	statl->st_ctime_nsec	= st->st_ctim.tv_nsec;
+	/* Currently we only support BASIC fields in stat */
+	statl->st_result_mask	= P9_STATS_BASIC;
+	stat2qid(st, &statl->qid);
+}
+
+static void virtio_p9_read(struct p9_dev *p9dev,
+			   struct p9_pdu *pdu, u32 *outlen)
+{
+	u64 offset;
+	u32 fid_val;
+	u16 iov_cnt;
+	void *iov_base;
+	size_t iov_len;
+	u32 count, rcount;
+	struct p9_fid *fid;
+
+
+	rcount = 0;
+	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
+	fid = get_fid(p9dev, fid_val);
+
+	iov_base = pdu->in_iov[0].iov_base;
+	iov_len  = pdu->in_iov[0].iov_len;
+	iov_cnt  = pdu->in_iov_cnt;
+	pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32);
+	pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32);
+	pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov,
+						   count,
+						   pdu->in_iov_cnt);
+	rcount = preadv(fid->fd, pdu->in_iov,
+			pdu->in_iov_cnt, offset);
+	if (rcount > count)
+		rcount = count;
+	/*
+	 * Update the iov_base back, so that rest of
+	 * pdu_writef works correctly.
+	 */
+	pdu->in_iov[0].iov_base = iov_base;
+	pdu->in_iov[0].iov_len  = iov_len;
+	pdu->in_iov_cnt         = iov_cnt;
+
+	pdu->write_offset = VIRTIO_9P_HDR_LEN;
+	virtio_p9_pdu_writef(pdu, "d", rcount);
+	*outlen = pdu->write_offset + rcount;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+}
+
+static int virtio_p9_dentry_size(struct dirent *dent)
+{
+	/*
+	 * Size of each dirent:
+	 * qid(13) + offset(8) + type(1) + name_len(2) + name
+	 */
+	return 24 + strlen(dent->d_name);
+}
+
+static void virtio_p9_readdir(struct p9_dev *p9dev,
+			      struct p9_pdu *pdu, u32 *outlen)
+{
+	u32 fid_val;
+	u32 count, rcount;
+	struct stat st;
+	struct p9_fid *fid;
+	struct dirent *dent;
+	char full_path[PATH_MAX];
+	u64 offset, old_offset;
+
+	rcount = 0;
+	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
+	fid = get_fid(p9dev, fid_val);
+
+	if (!fid->is_dir) {
+		errno = -EINVAL;
+		goto err_out;
+	}
+
+	/* Move the offset specified */
+	seekdir(fid->dir, offset);
+
+	old_offset = offset;
+	/* If reading a dir, fill the buffer with p9_stat entries */
+	dent = readdir(fid->dir);
+
+	/* Skip the space for writing count */
+	pdu->write_offset += sizeof(u32);
+	while (dent) {
+		u32 read;
+		struct p9_qid qid;
+
+		if ((rcount + virtio_p9_dentry_size(dent)) > count) {
+			/* seek to the previous offset and return */
+			seekdir(fid->dir, old_offset);
+			break;
+		}
+		old_offset = dent->d_off;
+		lstat(rel_to_abs(p9dev, dent->d_name, full_path), &st);
+		stat2qid(&st, &qid);
+		read = pdu->write_offset;
+		virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off,
+				     dent->d_type, dent->d_name);
+		rcount += pdu->write_offset - read;
+		dent = readdir(fid->dir);
+	}
+
+	pdu->write_offset = VIRTIO_9P_HDR_LEN;
+	virtio_p9_pdu_writef(pdu, "d", rcount);
+	*outlen = pdu->write_offset + rcount;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+
+static void virtio_p9_getattr(struct p9_dev *p9dev,
+			      struct p9_pdu *pdu, u32 *outlen)
+{
+	u32 fid_val;
+	struct stat st;
+	u64 request_mask;
+	struct p9_fid *fid;
+	struct p9_stat_dotl statl;
+
+	virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask);
+	fid = get_fid(p9dev, fid_val);
+	if (lstat(fid->abs_path, &st) < 0)
+		goto err_out;
+
+	virtio_p9_fill_stat(p9dev, &st, &statl);
+	virtio_p9_pdu_writef(pdu, "A", &statl);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+/* FIXME!! from linux/fs.h */
+/*
+ * Attribute flags.  These should be or-ed together to figure out what
+ * has been changed!
+ */
+#define ATTR_MODE	(1 << 0)
+#define ATTR_UID	(1 << 1)
+#define ATTR_GID	(1 << 2)
+#define ATTR_SIZE	(1 << 3)
+#define ATTR_ATIME	(1 << 4)
+#define ATTR_MTIME	(1 << 5)
+#define ATTR_CTIME	(1 << 6)
+#define ATTR_ATIME_SET	(1 << 7)
+#define ATTR_MTIME_SET	(1 << 8)
+#define ATTR_FORCE	(1 << 9) /* Not a change, but a change it */
+#define ATTR_ATTR_FLAG	(1 << 10)
+#define ATTR_KILL_SUID	(1 << 11)
+#define ATTR_KILL_SGID	(1 << 12)
+#define ATTR_FILE	(1 << 13)
+#define ATTR_KILL_PRIV	(1 << 14)
+#define ATTR_OPEN	(1 << 15) /* Truncating from open(O_TRUNC) */
+#define ATTR_TIMES_SET	(1 << 16)
+
+#define ATTR_MASK    127
+
+static void virtio_p9_setattr(struct p9_dev *p9dev,
+			      struct p9_pdu *pdu, u32 *outlen)
+{
+	int ret = 0;
+	u32 fid_val;
+	struct p9_fid *fid;
+	struct p9_iattr_dotl p9attr;
+
+	virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr);
+	fid = get_fid(p9dev, fid_val);
+
+	if (p9attr.valid & ATTR_MODE) {
+		ret = chmod(fid->abs_path, p9attr.mode);
+		if (ret < 0)
+			goto err_out;
+	}
+	if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) {
+		struct timespec times[2];
+		if (p9attr.valid & ATTR_ATIME) {
+			if (p9attr.valid & ATTR_ATIME_SET) {
+				times[0].tv_sec = p9attr.atime_sec;
+				times[0].tv_nsec = p9attr.atime_nsec;
+			} else {
+				times[0].tv_nsec = UTIME_NOW;
+			}
+		} else {
+			times[0].tv_nsec = UTIME_OMIT;
+		}
+		if (p9attr.valid & ATTR_MTIME) {
+			if (p9attr.valid & ATTR_MTIME_SET) {
+				times[1].tv_sec = p9attr.mtime_sec;
+				times[1].tv_nsec = p9attr.mtime_nsec;
+			} else {
+				times[1].tv_nsec = UTIME_NOW;
+			}
+		} else
+			times[1].tv_nsec = UTIME_OMIT;
+
+		ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW);
+		if (ret < 0)
+			goto err_out;
+	}
+	/*
+	 * If the only valid entry in iattr is ctime we can call
+	 * chown(-1,-1) to update the ctime of the file
+	 */
+	if ((p9attr.valid & (ATTR_UID | ATTR_GID)) ||
+	    ((p9attr.valid & ATTR_CTIME)
+	     && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
+		if (!(p9attr.valid & ATTR_UID))
+			p9attr.uid = -1;
+
+		if (!(p9attr.valid & ATTR_GID))
+			p9attr.gid = -1;
+
+		ret = lchown(fid->abs_path, p9attr.uid, p9attr.gid);
+		if (ret < 0)
+			goto err_out;
+	}
+	if (p9attr.valid & (ATTR_SIZE)) {
+		ret = truncate(fid->abs_path, p9attr.size);
+		if (ret < 0)
+			goto err_out;
+	}
+	*outlen = VIRTIO_9P_HDR_LEN;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_write(struct p9_dev *p9dev,
+			    struct p9_pdu *pdu, u32 *outlen)
+{
+
+	u64 offset;
+	u32 fid_val;
+	u32 count;
+	ssize_t res;
+	u16 iov_cnt;
+	void *iov_base;
+	size_t iov_len;
+	struct p9_fid *fid;
+	/* u32 fid + u64 offset + u32 count */
+	int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32);
+
+	virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
+	fid = get_fid(p9dev, fid_val);
+
+	iov_base = pdu->out_iov[0].iov_base;
+	iov_len  = pdu->out_iov[0].iov_len;
+	iov_cnt  = pdu->out_iov_cnt;
+
+	/* Adjust the iovec to skip the header and meta data */
+	pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size);
+	pdu->out_iov[0].iov_len -=  (sizeof(struct p9_msg) + twrite_size);
+	pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count,
+						    pdu->out_iov_cnt);
+	res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset);
+	/*
+	 * Update the iov_base back, so that rest of
+	 * pdu_readf works correctly.
+	 */
+	pdu->out_iov[0].iov_base = iov_base;
+	pdu->out_iov[0].iov_len  = iov_len;
+	pdu->out_iov_cnt         = iov_cnt;
+
+	if (res < 0)
+		goto err_out;
+	virtio_p9_pdu_writef(pdu, "d", res);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_remove(struct p9_dev *p9dev,
+			     struct p9_pdu *pdu, u32 *outlen)
+{
+	int ret;
+	u32 fid_val;
+	struct p9_fid *fid;
+
+	virtio_p9_pdu_readf(pdu, "d", &fid_val);
+	fid = get_fid(p9dev, fid_val);
+
+	ret = remove(fid->abs_path);
+	if (ret < 0)
+		goto err_out;
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_rename(struct p9_dev *p9dev,
+			     struct p9_pdu *pdu, u32 *outlen)
+{
+	int ret;
+	u32 fid_val, new_fid_val;
+	struct p9_fid *fid, *new_fid;
+	char full_path[PATH_MAX], *new_name;
+
+	virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name);
+	fid = get_fid(p9dev, fid_val);
+	new_fid = get_fid(p9dev, new_fid_val);
+
+	sprintf(full_path, "%s/%s", new_fid->abs_path, new_name);
+	ret = rename(fid->abs_path, full_path);
+	if (ret < 0)
+		goto err_out;
+	close_fid(p9dev, fid_val);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_readlink(struct p9_dev *p9dev,
+			       struct p9_pdu *pdu, u32 *outlen)
+{
+	int ret;
+	u32 fid_val;
+	struct p9_fid *fid;
+	char target_path[PATH_MAX];
+
+	virtio_p9_pdu_readf(pdu, "d", &fid_val);
+	fid = get_fid(p9dev, fid_val);
+
+	memset(target_path, 0, PATH_MAX);
+	ret = readlink(fid->abs_path, target_path, PATH_MAX - 1);
+	if (ret < 0)
+		goto err_out;
+
+	virtio_p9_pdu_writef(pdu, "s", target_path);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_statfs(struct p9_dev *p9dev,
+			     struct p9_pdu *pdu, u32 *outlen)
+{
+	int ret;
+	u64 fsid;
+	u32 fid_val;
+	struct p9_fid *fid;
+	struct statfs stat_buf;
+
+	virtio_p9_pdu_readf(pdu, "d", &fid_val);
+	fid = get_fid(p9dev, fid_val);
+
+	ret = statfs(fid->abs_path, &stat_buf);
+	if (ret < 0)
+		goto err_out;
+	/* FIXME!! f_blocks needs update based on client msize */
+	fsid = (unsigned int) stat_buf.f_fsid.__val[0] |
+		(unsigned long long)stat_buf.f_fsid.__val[1] << 32;
+	virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type,
+			     stat_buf.f_bsize, stat_buf.f_blocks,
+			     stat_buf.f_bfree, stat_buf.f_bavail,
+			     stat_buf.f_files, stat_buf.f_ffree,
+			     fsid, stat_buf.f_namelen);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_mknod(struct p9_dev *p9dev,
+			    struct p9_pdu *pdu, u32 *outlen)
+{
+	int ret;
+	char *name;
+	struct stat st;
+	struct p9_fid *dfid;
+	struct p9_qid qid;
+	char full_path[PATH_MAX];
+	u32 fid_val, mode, major, minor, gid;
+
+	virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode,
+			    &major, &minor, &gid);
+
+	dfid = get_fid(p9dev, fid_val);
+	sprintf(full_path, "%s/%s", dfid->abs_path, name);
+	ret = mknod(full_path, mode, makedev(major, minor));
+	if (ret < 0)
+		goto err_out;
+
+	if (lstat(full_path, &st) < 0)
+		goto err_out;
+
+	ret = chmod(full_path, mode & 0777);
+	if (ret < 0)
+		goto err_out;
+
+	ret = lchown(full_path, dfid->uid, gid);
+	if (ret < 0)
+		goto err_out;
+
+	stat2qid(&st, &qid);
+	virtio_p9_pdu_writef(pdu, "Q", &qid);
+	free(name);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	free(name);
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_fsync(struct p9_dev *p9dev,
+			    struct p9_pdu *pdu, u32 *outlen)
+{
+	int ret;
+	struct p9_fid *fid;
+	u32 fid_val, datasync;
+
+	virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync);
+	fid = get_fid(p9dev, fid_val);
+
+	if (datasync)
+		ret = fdatasync(fid->fd);
+	else
+		ret = fsync(fid->fd);
+	if (ret < 0)
+		goto err_out;
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_symlink(struct p9_dev *p9dev,
+			      struct p9_pdu *pdu, u32 *outlen)
+{
+	int ret;
+	struct stat st;
+	u32 fid_val, gid;
+	struct p9_qid qid;
+	struct p9_fid *dfid;
+	char new_name[PATH_MAX];
+	char *old_path, *name;
+
+	virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid);
+
+	dfid = get_fid(p9dev, fid_val);
+	sprintf(new_name, "%s/%s", dfid->abs_path, name);
+	ret = symlink(old_path, new_name);
+	if (ret < 0)
+		goto err_out;
+
+	if (lstat(new_name, &st) < 0)
+		goto err_out;
+
+	ret = lchown(new_name, dfid->uid, gid);
+	if (ret < 0)
+		goto err_out;
+
+	stat2qid(&st, &qid);
+	virtio_p9_pdu_writef(pdu, "Q", &qid);
+	free(name);
+	free(old_path);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	free(name);
+	free(old_path);
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_link(struct p9_dev *p9dev,
+			   struct p9_pdu *pdu, u32 *outlen)
+{
+	int ret;
+	char *name;
+	u32 fid_val, dfid_val;
+	struct p9_fid *dfid, *fid;
+	char full_path[PATH_MAX];
+
+	virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name);
+
+	dfid = get_fid(p9dev, dfid_val);
+	fid =  get_fid(p9dev, fid_val);
+	sprintf(full_path, "%s/%s", dfid->abs_path, name);
+	ret = link(fid->abs_path, full_path);
+	if (ret < 0)
+		goto err_out;
+	free(name);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	free(name);
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+
+}
+
+static void virtio_p9_lock(struct p9_dev *p9dev,
+			   struct p9_pdu *pdu, u32 *outlen)
+{
+	u8 ret;
+	u32 fid_val;
+	struct p9_flock flock;
+
+	virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type,
+			    &flock.flags, &flock.start, &flock.length,
+			    &flock.proc_id, &flock.client_id);
+
+	/* Just return success */
+	ret = P9_LOCK_SUCCESS;
+	virtio_p9_pdu_writef(pdu, "d", ret);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	free(flock.client_id);
+	return;
+}
+
+static void virtio_p9_getlock(struct p9_dev *p9dev,
+			      struct p9_pdu *pdu, u32 *outlen)
+{
+	u32 fid_val;
+	struct p9_getlock glock;
+	virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type,
+			    &glock.start, &glock.length, &glock.proc_id,
+			    &glock.client_id);
+
+	/* Just return success */
+	glock.type = F_UNLCK;
+	virtio_p9_pdu_writef(pdu, "bqqds", glock.type,
+			     glock.start, glock.length, glock.proc_id,
+			     glock.client_id);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	free(glock.client_id);
+	return;
+}
+
+static int virtio_p9_ancestor(char *path, char *ancestor)
+{
+	int size = strlen(ancestor);
+	if (!strncmp(path, ancestor, size)) {
+		/*
+		 * Now check whether ancestor is a full name or
+		 * or directory component and not just part
+		 * of a name.
+		 */
+		if (path[size] == '\0' || path[size] == '/')
+			return 1;
+	}
+	return 0;
+}
+
+static void virtio_p9_fix_path(char *fid_path, char *old_name, char *new_name)
+{
+	char tmp_name[PATH_MAX];
+	size_t rp_sz = strlen(old_name);
+
+	if (rp_sz == strlen(fid_path)) {
+		/* replace the full name */
+		strcpy(fid_path, new_name);
+		return;
+	}
+	/* save the trailing path details */
+	strcpy(tmp_name, fid_path + rp_sz);
+	sprintf(fid_path, "%s%s", new_name, tmp_name);
+	return;
+}
+
+static void virtio_p9_renameat(struct p9_dev *p9dev,
+			       struct p9_pdu *pdu, u32 *outlen)
+{
+	int i, ret;
+	char *old_name, *new_name;
+	u32 old_dfid_val, new_dfid_val;
+	struct p9_fid *old_dfid, *new_dfid;
+	char old_full_path[PATH_MAX], new_full_path[PATH_MAX];
+
+
+	virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name,
+			    &new_dfid_val, &new_name);
+
+	old_dfid = get_fid(p9dev, old_dfid_val);
+	new_dfid = get_fid(p9dev, new_dfid_val);
+
+	sprintf(old_full_path, "%s/%s", old_dfid->abs_path, old_name);
+	sprintf(new_full_path, "%s/%s", new_dfid->abs_path, new_name);
+	ret = rename(old_full_path, new_full_path);
+	if (ret < 0)
+		goto err_out;
+	/*
+	 * Now fix path in other fids, if the renamed path is part of
+	 * that.
+	 */
+	for (i = 0; i < VIRTIO_9P_MAX_FID; i++) {
+		if (get_fid(p9dev, i)->fid != P9_NOFID &&
+		    virtio_p9_ancestor(get_fid(p9dev, i)->path, old_name)) {
+			virtio_p9_fix_path(get_fid(p9dev, i)->path, old_name,
+					   new_name);
+		}
+	}
+	free(old_name);
+	free(new_name);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	free(old_name);
+	free(new_name);
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_unlinkat(struct p9_dev *p9dev,
+			       struct p9_pdu *pdu, u32 *outlen)
+{
+	int ret;
+	char *name;
+	u32 fid_val, flags;
+	struct p9_fid *fid;
+	char full_path[PATH_MAX];
+
+	virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags);
+	fid = get_fid(p9dev, fid_val);
+
+	sprintf(full_path, "%s/%s", fid->abs_path, name);
+	ret = remove(full_path);
+	if (ret < 0)
+		goto err_out;
+	free(name);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+	return;
+err_out:
+	free(name);
+	virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+	return;
+}
+
+static void virtio_p9_flush(struct p9_dev *p9dev,
+				struct p9_pdu *pdu, u32 *outlen)
+{
+	u16 tag, oldtag;
+
+	virtio_p9_pdu_readf(pdu, "ww", &tag, &oldtag);
+	virtio_p9_pdu_writef(pdu, "w", tag);
+	*outlen = pdu->write_offset;
+	virtio_p9_set_reply_header(pdu, *outlen);
+
+	return;
+}
+
+static void virtio_p9_eopnotsupp(struct p9_dev *p9dev,
+				 struct p9_pdu *pdu, u32 *outlen)
+{
+	return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen);
+}
+
+typedef void p9_handler(struct p9_dev *p9dev,
+			struct p9_pdu *pdu, u32 *outlen);
+
+/* FIXME should be removed when merging with latest linus tree */
+#define P9_TRENAMEAT 74
+#define P9_TUNLINKAT 76
+
+static p9_handler *virtio_9p_dotl_handler [] = {
+	[P9_TREADDIR]     = virtio_p9_readdir,
+	[P9_TSTATFS]      = virtio_p9_statfs,
+	[P9_TGETATTR]     = virtio_p9_getattr,
+	[P9_TSETATTR]     = virtio_p9_setattr,
+	[P9_TXATTRWALK]   = virtio_p9_eopnotsupp,
+	[P9_TXATTRCREATE] = virtio_p9_eopnotsupp,
+	[P9_TMKNOD]       = virtio_p9_mknod,
+	[P9_TLOCK]        = virtio_p9_lock,
+	[P9_TGETLOCK]     = virtio_p9_getlock,
+	[P9_TRENAMEAT]    = virtio_p9_renameat,
+	[P9_TREADLINK]    = virtio_p9_readlink,
+	[P9_TUNLINKAT]    = virtio_p9_unlinkat,
+	[P9_TMKDIR]       = virtio_p9_mkdir,
+	[P9_TVERSION]     = virtio_p9_version,
+	[P9_TLOPEN]       = virtio_p9_open,
+	[P9_TATTACH]      = virtio_p9_attach,
+	[P9_TWALK]        = virtio_p9_walk,
+	[P9_TCLUNK]       = virtio_p9_clunk,
+	[P9_TFSYNC]       = virtio_p9_fsync,
+	[P9_TREAD]        = virtio_p9_read,
+	[P9_TFLUSH]       = virtio_p9_flush,
+	[P9_TLINK]        = virtio_p9_link,
+	[P9_TSYMLINK]     = virtio_p9_symlink,
+	[P9_TLCREATE]     = virtio_p9_create,
+	[P9_TWRITE]       = virtio_p9_write,
+	[P9_TREMOVE]      = virtio_p9_remove,
+	[P9_TRENAME]      = virtio_p9_rename,
+};
+
+static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq)
+{
+	struct p9_pdu *pdu = calloc(1, sizeof(*pdu));
+	if (!pdu)
+		return NULL;
+
+	/* skip the pdu header p9_msg */
+	pdu->read_offset	= VIRTIO_9P_HDR_LEN;
+	pdu->write_offset	= VIRTIO_9P_HDR_LEN;
+	pdu->queue_head		= virt_queue__get_inout_iov(kvm, vq, pdu->in_iov,
+					pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt);
+	return pdu;
+}
+
+static u8 virtio_p9_get_cmd(struct p9_pdu *pdu)
+{
+	struct p9_msg *msg;
+	/*
+	 * we can peek directly into pdu for a u8
+	 * value. The host endianess won't be an issue
+	 */
+	msg = pdu->out_iov[0].iov_base;
+	return msg->cmd;
+}
+
+static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job)
+{
+	u8 cmd;
+	u32 len = 0;
+	p9_handler *handler;
+	struct p9_dev *p9dev;
+	struct virt_queue *vq;
+	struct p9_pdu *p9pdu;
+
+	vq = job->vq;
+	p9dev = job->p9dev;
+
+	p9pdu = virtio_p9_pdu_init(kvm, vq);
+	cmd = virtio_p9_get_cmd(p9pdu);
+
+	if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) ||
+	    !virtio_9p_dotl_handler[cmd])
+		handler = virtio_p9_eopnotsupp;
+	else
+		handler = virtio_9p_dotl_handler[cmd];
+
+	handler(p9dev, p9pdu, &len);
+	virt_queue__set_used_elem(vq, p9pdu->queue_head, len);
+	free(p9pdu);
+	return true;
+}
+
+static void virtio_p9_do_io(struct kvm *kvm, void *param)
+{
+	struct p9_dev_job *job = (struct p9_dev_job *)param;
+	struct p9_dev *p9dev   = job->p9dev;
+	struct virt_queue *vq  = job->vq;
+
+	while (virt_queue__available(vq)) {
+		virtio_p9_do_io_request(kvm, job);
+		p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs);
+	}
+}
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+	struct p9_dev *p9dev = dev;
+
+	((u8 *)(p9dev->config))[offset] = data;
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+	struct p9_dev *p9dev = dev;
+
+	return ((u8 *)(p9dev->config))[offset];
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+	return 1 << VIRTIO_9P_MOUNT_TAG;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+	struct p9_dev *p9dev = dev;
+
+	p9dev->features = features;
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+	struct p9_dev *p9dev = dev;
+	struct p9_dev_job *job;
+	struct virt_queue *queue;
+	void *p;
+
+	compat__remove_message(compat_id);
+
+	queue		= &p9dev->vqs[vq];
+	queue->pfn	= pfn;
+	p		= guest_pfn_to_host(kvm, queue->pfn);
+	job		= &p9dev->jobs[vq];
+
+	vring_init(&queue->vring, VIRTQUEUE_NUM, p, VIRTIO_PCI_VRING_ALIGN);
+
+	*job		= (struct p9_dev_job) {
+		.vq		= queue,
+		.p9dev		= p9dev,
+	};
+	thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job);
+
+	return 0;
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct p9_dev *p9dev = dev;
+
+	thread_pool__do_job(&p9dev->jobs[vq].job_id);
+
+	return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct p9_dev *p9dev = dev;
+
+	return p9dev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	return VIRTQUEUE_NUM;
+}
+
+struct virtio_ops p9_dev_virtio_ops = (struct virtio_ops) {
+	.set_config		= set_config,
+	.get_config		= get_config,
+	.get_host_features	= get_host_features,
+	.set_guest_features	= set_guest_features,
+	.init_vq		= init_vq,
+	.notify_vq		= notify_vq,
+	.get_pfn_vq		= get_pfn_vq,
+	.get_size_vq		= get_size_vq,
+};
+
+int virtio_9p__init(struct kvm *kvm)
+{
+	struct p9_dev *p9dev;
+
+	list_for_each_entry(p9dev, &devs, list) {
+		virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops,
+			    VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_9P, VIRTIO_ID_9P, PCI_CLASS_9P);
+	}
+
+	return 0;
+}
+
+int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name)
+{
+	struct p9_dev *p9dev;
+	u32 i, root_len;
+	int err = 0;
+
+	p9dev = calloc(1, sizeof(*p9dev));
+	if (!p9dev)
+		return -ENOMEM;
+
+	if (!tag_name)
+		tag_name = VIRTIO_9P_DEFAULT_TAG;
+
+	p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1);
+	if (p9dev->config == NULL) {
+		err = -ENOMEM;
+		goto free_p9dev;
+	}
+
+	strcpy(p9dev->root_dir, root);
+	root_len = strlen(root);
+	/*
+	 * We prefix the full path in all fids, This allows us to get the
+	 * absolute path of an fid without playing with strings.
+	 */
+	for (i = 0; i < VIRTIO_9P_MAX_FID; i++) {
+		strcpy(get_fid(p9dev, i)->abs_path, root);
+		get_fid(p9dev, i)->path = get_fid(p9dev, i)->abs_path + root_len;
+	}
+	p9dev->config->tag_len = strlen(tag_name);
+	if (p9dev->config->tag_len > MAX_TAG_LEN) {
+		err = -EINVAL;
+		goto free_p9dev_config;
+	}
+
+	memcpy(&p9dev->config->tag, tag_name, strlen(tag_name));
+
+	list_add(&p9dev->list, &devs);
+
+	if (compat_id == -1)
+		compat_id = virtio_compat_add_message("virtio-9p", "CONFIG_NET_9P_VIRTIO");
+
+	return err;
+
+free_p9dev_config:
+	free(p9dev->config);
+free_p9dev:
+	free(p9dev);
+	return err;
+}
diff --git a/tools/kvm/virtio/balloon.c b/tools/kvm/virtio/balloon.c
new file mode 100644
index 0000000..a838ff4
--- /dev/null
+++ b/tools/kvm/virtio/balloon.c
@@ -0,0 +1,267 @@
+#include "kvm/virtio-balloon.h"
+
+#include "kvm/virtio-pci-dev.h"
+
+#include "kvm/virtio.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+#include "kvm/threadpool.h"
+#include "kvm/guest_compat.h"
+#include "kvm/kvm-ipc.h"
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_balloon.h>
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
+
+#define NUM_VIRT_QUEUES		3
+#define VIRTIO_BLN_QUEUE_SIZE	128
+#define VIRTIO_BLN_INFLATE	0
+#define VIRTIO_BLN_DEFLATE	1
+#define VIRTIO_BLN_STATS	2
+
+struct bln_dev {
+	struct list_head	list;
+	struct virtio_device	vdev;
+
+	u32			features;
+
+	/* virtio queue */
+	struct virt_queue	vqs[NUM_VIRT_QUEUES];
+	struct thread_pool__job	jobs[NUM_VIRT_QUEUES];
+
+	struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
+	struct virtio_balloon_stat *cur_stat;
+	u32			cur_stat_head;
+	u16			stat_count;
+	int			stat_waitfd;
+
+	struct virtio_balloon_config config;
+};
+
+static struct bln_dev bdev;
+extern struct kvm *kvm;
+static int compat_id = -1;
+
+static bool virtio_bln_do_io_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue)
+{
+	struct iovec iov[VIRTIO_BLN_QUEUE_SIZE];
+	unsigned int len = 0;
+	u16 out, in, head;
+	u32 *ptrs, i;
+
+	head	= virt_queue__get_iov(queue, iov, &out, &in, kvm);
+	ptrs	= iov[0].iov_base;
+	len	= iov[0].iov_len / sizeof(u32);
+
+	for (i = 0 ; i < len ; i++) {
+		void *guest_ptr;
+
+		guest_ptr = guest_flat_to_host(kvm, ptrs[i] << VIRTIO_BALLOON_PFN_SHIFT);
+		if (queue == &bdev->vqs[VIRTIO_BLN_INFLATE]) {
+			madvise(guest_ptr, 1 << VIRTIO_BALLOON_PFN_SHIFT, MADV_DONTNEED);
+			bdev->config.actual++;
+		} else if (queue == &bdev->vqs[VIRTIO_BLN_DEFLATE]) {
+			bdev->config.actual--;
+		}
+	}
+
+	virt_queue__set_used_elem(queue, head, len);
+
+	return true;
+}
+
+static bool virtio_bln_do_stat_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue)
+{
+	struct iovec iov[VIRTIO_BLN_QUEUE_SIZE];
+	u16 out, in, head;
+	struct virtio_balloon_stat *stat;
+	u64 wait_val = 1;
+
+	head = virt_queue__get_iov(queue, iov, &out, &in, kvm);
+	stat = iov[0].iov_base;
+
+	/* Initial empty stat buffer */
+	if (bdev->cur_stat == NULL) {
+		bdev->cur_stat = stat;
+		bdev->cur_stat_head = head;
+
+		return true;
+	}
+
+	memcpy(bdev->stats, stat, iov[0].iov_len);
+
+	bdev->stat_count = iov[0].iov_len / sizeof(struct virtio_balloon_stat);
+	bdev->cur_stat = stat;
+	bdev->cur_stat_head = head;
+
+	if (write(bdev->stat_waitfd, &wait_val, sizeof(wait_val)) <= 0)
+		return -EFAULT;
+
+	return 1;
+}
+
+static void virtio_bln_do_io(struct kvm *kvm, void *param)
+{
+	struct virt_queue *vq = param;
+
+	if (vq == &bdev.vqs[VIRTIO_BLN_STATS]) {
+		virtio_bln_do_stat_request(kvm, &bdev, vq);
+		bdev.vdev.ops->signal_vq(kvm, &bdev.vdev, VIRTIO_BLN_STATS);
+		return;
+	}
+
+	while (virt_queue__available(vq)) {
+		virtio_bln_do_io_request(kvm, &bdev, vq);
+		bdev.vdev.ops->signal_vq(kvm, &bdev.vdev, vq - bdev.vqs);
+	}
+}
+
+static int virtio_bln__collect_stats(void)
+{
+	u64 tmp;
+
+	virt_queue__set_used_elem(&bdev.vqs[VIRTIO_BLN_STATS], bdev.cur_stat_head,
+				  sizeof(struct virtio_balloon_stat));
+	bdev.vdev.ops->signal_vq(kvm, &bdev.vdev, VIRTIO_BLN_STATS);
+
+	if (read(bdev.stat_waitfd, &tmp, sizeof(tmp)) <= 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+static void virtio_bln__print_stats(int fd, u32 type, u32 len, u8 *msg)
+{
+	int r;
+
+	if (WARN_ON(type != KVM_IPC_STAT || len))
+		return;
+
+	if (virtio_bln__collect_stats() < 0)
+		return;
+
+	r = write(fd, bdev.stats, sizeof(bdev.stats));
+	if (r < 0)
+		pr_warning("Failed sending memory stats");
+}
+
+static void handle_mem(int fd, u32 type, u32 len, u8 *msg)
+{
+	int mem;
+
+	if (WARN_ON(type != KVM_IPC_BALLOON || len != sizeof(int)))
+		return;
+
+	mem = *(int *)msg;
+	if (mem > 0) {
+		bdev.config.num_pages += 256 * mem;
+	} else if (mem < 0) {
+		if (bdev.config.num_pages < (u32)(256 * (-mem)))
+			return;
+
+		bdev.config.num_pages += 256 * mem;
+	}
+
+	/* Notify that the configuration space has changed */
+	bdev.vdev.ops->signal_config(kvm, &bdev.vdev);
+}
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+	struct bln_dev *bdev = dev;
+
+	((u8 *)(&bdev->config))[offset] = data;
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+	struct bln_dev *bdev = dev;
+
+	return ((u8 *)(&bdev->config))[offset];
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+	return 1 << VIRTIO_BALLOON_F_STATS_VQ;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+	struct bln_dev *bdev = dev;
+
+	bdev->features = features;
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+	struct bln_dev *bdev = dev;
+	struct virt_queue *queue;
+	void *p;
+
+	compat__remove_message(compat_id);
+
+	queue		= &bdev->vqs[vq];
+	queue->pfn	= pfn;
+	p		= guest_pfn_to_host(kvm, queue->pfn);
+
+	thread_pool__init_job(&bdev->jobs[vq], kvm, virtio_bln_do_io, queue);
+	vring_init(&queue->vring, VIRTIO_BLN_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
+
+	return 0;
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct bln_dev *bdev = dev;
+
+	thread_pool__do_job(&bdev->jobs[vq]);
+
+	return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct bln_dev *bdev = dev;
+
+	return bdev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	return VIRTIO_BLN_QUEUE_SIZE;
+}
+
+struct virtio_ops bln_dev_virtio_ops = (struct virtio_ops) {
+	.set_config		= set_config,
+	.get_config		= get_config,
+	.get_host_features	= get_host_features,
+	.set_guest_features	= set_guest_features,
+	.init_vq		= init_vq,
+	.notify_vq		= notify_vq,
+	.get_pfn_vq		= get_pfn_vq,
+	.get_size_vq		= get_size_vq,
+};
+
+void virtio_bln__init(struct kvm *kvm)
+{
+	kvm_ipc__register_handler(KVM_IPC_BALLOON, handle_mem);
+	kvm_ipc__register_handler(KVM_IPC_STAT, virtio_bln__print_stats);
+
+	bdev.stat_waitfd	= eventfd(0, 0);
+	memset(&bdev.config, 0, sizeof(struct virtio_balloon_config));
+
+	virtio_init(kvm, &bdev, &bdev.vdev, &bln_dev_virtio_ops,
+		    VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_BLN, VIRTIO_ID_BALLOON, PCI_CLASS_BLN);
+
+	if (compat_id == -1)
+		compat_id = virtio_compat_add_message("virtio-balloon", "CONFIG_VIRTIO_BALLOON");
+}
diff --git a/tools/kvm/virtio/blk.c b/tools/kvm/virtio/blk.c
new file mode 100644
index 0000000..beebd24
--- /dev/null
+++ b/tools/kvm/virtio/blk.c
@@ -0,0 +1,314 @@
+#include "kvm/virtio-blk.h"
+
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/disk-image.h"
+#include "kvm/mutex.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+#include "kvm/threadpool.h"
+#include "kvm/ioeventfd.h"
+#include "kvm/guest_compat.h"
+#include "kvm/virtio-pci.h"
+#include "kvm/virtio.h"
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_blk.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <pthread.h>
+
+#define VIRTIO_BLK_MAX_DEV		4
+
+/*
+ * the header and status consume too entries
+ */
+#define DISK_SEG_MAX			(VIRTIO_BLK_QUEUE_SIZE - 2)
+#define VIRTIO_BLK_QUEUE_SIZE		256
+#define NUM_VIRT_QUEUES			1
+
+struct blk_dev_req {
+	struct virt_queue		*vq;
+	struct blk_dev			*bdev;
+	struct iovec			iov[VIRTIO_BLK_QUEUE_SIZE];
+	u16				out, in, head;
+	struct kvm			*kvm;
+};
+
+struct blk_dev {
+	pthread_mutex_t			mutex;
+
+	struct list_head		list;
+	struct list_head		req_list;
+
+	struct virtio_device		vdev;
+	struct virtio_blk_config	blk_config;
+	struct disk_image		*disk;
+	u32				features;
+
+	struct virt_queue		vqs[NUM_VIRT_QUEUES];
+	struct blk_dev_req		reqs[VIRTIO_BLK_QUEUE_SIZE];
+
+	pthread_t			io_thread;
+	int				io_efd;
+
+	struct kvm			*kvm;
+};
+
+static LIST_HEAD(bdevs);
+static int compat_id = -1;
+
+void virtio_blk_complete(void *param, long len)
+{
+	struct blk_dev_req *req = param;
+	struct blk_dev *bdev = req->bdev;
+	int queueid = req->vq - bdev->vqs;
+	u8 *status;
+
+	/* status */
+	status	= req->iov[req->out + req->in - 1].iov_base;
+	*status	= (len < 0) ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
+
+	mutex_lock(&bdev->mutex);
+	virt_queue__set_used_elem(req->vq, req->head, len);
+	mutex_unlock(&bdev->mutex);
+
+	if (virtio_queue__should_signal(&bdev->vqs[queueid]))
+		bdev->vdev.ops->signal_vq(req->kvm, &bdev->vdev, queueid);
+}
+
+static void virtio_blk_do_io_request(struct kvm *kvm, struct blk_dev_req *req)
+{
+	struct virtio_blk_outhdr *req_hdr;
+	ssize_t block_cnt;
+	struct blk_dev *bdev;
+	struct iovec *iov;
+	u16 out, in;
+
+	block_cnt	= -1;
+	bdev		= req->bdev;
+	iov		= req->iov;
+	out		= req->out;
+	in		= req->in;
+	req_hdr		= iov[0].iov_base;
+
+	switch (req_hdr->type) {
+	case VIRTIO_BLK_T_IN:
+		block_cnt = disk_image__read(bdev->disk, req_hdr->sector,
+				iov + 1, in + out - 2, req);
+		break;
+	case VIRTIO_BLK_T_OUT:
+		block_cnt = disk_image__write(bdev->disk, req_hdr->sector,
+				iov + 1, in + out - 2, req);
+		break;
+	case VIRTIO_BLK_T_FLUSH:
+		block_cnt = disk_image__flush(bdev->disk);
+		virtio_blk_complete(req, block_cnt);
+		break;
+	case VIRTIO_BLK_T_GET_ID:
+		block_cnt = VIRTIO_BLK_ID_BYTES;
+		disk_image__get_serial(bdev->disk,
+				(iov + 1)->iov_base, &block_cnt);
+		virtio_blk_complete(req, block_cnt);
+		break;
+	default:
+		pr_warning("request type %d", req_hdr->type);
+		block_cnt	= -1;
+		break;
+	}
+}
+
+static void virtio_blk_do_io(struct kvm *kvm, struct virt_queue *vq, struct blk_dev *bdev)
+{
+	struct blk_dev_req *req;
+	u16 head;
+
+	while (virt_queue__available(vq)) {
+		head		= virt_queue__pop(vq);
+		req		= &bdev->reqs[head];
+		req->head	= virt_queue__get_head_iov(vq, req->iov, &req->out,
+					&req->in, head, kvm);
+		req->vq		= vq;
+
+		virtio_blk_do_io_request(kvm, req);
+	}
+}
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+	struct blk_dev *bdev = dev;
+
+	((u8 *)(&bdev->blk_config))[offset] = data;
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+	struct blk_dev *bdev = dev;
+
+	return ((u8 *)(&bdev->blk_config))[offset];
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+	return	1UL << VIRTIO_BLK_F_SEG_MAX
+		| 1UL << VIRTIO_BLK_F_FLUSH
+		| 1UL << VIRTIO_RING_F_EVENT_IDX
+		| 1UL << VIRTIO_RING_F_INDIRECT_DESC;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+	struct blk_dev *bdev = dev;
+
+	bdev->features = features;
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+	struct blk_dev *bdev = dev;
+	struct virt_queue *queue;
+	void *p;
+
+	compat__remove_message(compat_id);
+
+	queue		= &bdev->vqs[vq];
+	queue->pfn	= pfn;
+	p		= guest_pfn_to_host(kvm, queue->pfn);
+
+	vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
+
+	return 0;
+}
+
+static void *virtio_blk_thread(void *dev)
+{
+	struct blk_dev *bdev = dev;
+	u64 data;
+
+	while (1) {
+		read(bdev->io_efd, &data, sizeof(u64));
+		virtio_blk_do_io(bdev->kvm, &bdev->vqs[0], bdev);
+	}
+
+	pthread_exit(NULL);
+	return NULL;
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct blk_dev *bdev = dev;
+	u64 data = 1;
+
+	write(bdev->io_efd, &data, sizeof(data));
+
+	return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct blk_dev *bdev = dev;
+
+	return bdev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	/* FIXME: dynamic */
+	return VIRTIO_BLK_QUEUE_SIZE;
+}
+
+static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
+{
+	/* FIXME: dynamic */
+	return size;
+}
+
+static struct virtio_ops blk_dev_virtio_ops = (struct virtio_ops) {
+	.set_config		= set_config,
+	.get_config		= get_config,
+	.get_host_features	= get_host_features,
+	.set_guest_features	= set_guest_features,
+	.init_vq		= init_vq,
+	.notify_vq		= notify_vq,
+	.get_pfn_vq		= get_pfn_vq,
+	.get_size_vq		= get_size_vq,
+	.set_size_vq		= set_size_vq,
+};
+
+static int virtio_blk__init_one(struct kvm *kvm, struct disk_image *disk)
+{
+	struct blk_dev *bdev;
+	unsigned int i;
+
+	if (!disk)
+		return -EINVAL;
+
+	bdev = calloc(1, sizeof(struct blk_dev));
+	if (bdev == NULL)
+		return -ENOMEM;
+
+	*bdev = (struct blk_dev) {
+		.mutex			= PTHREAD_MUTEX_INITIALIZER,
+		.disk			= disk,
+		.blk_config		= (struct virtio_blk_config) {
+			.capacity	= disk->size / SECTOR_SIZE,
+			.seg_max	= DISK_SEG_MAX,
+		},
+		.io_efd			= eventfd(0, 0),
+		.kvm			= kvm,
+	};
+
+	virtio_init(kvm, bdev, &bdev->vdev, &blk_dev_virtio_ops,
+		    VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_BLK, VIRTIO_ID_BLOCK, PCI_CLASS_BLK);
+
+	list_add_tail(&bdev->list, &bdevs);
+
+	for (i = 0; i < ARRAY_SIZE(bdev->reqs); i++) {
+		bdev->reqs[i].bdev = bdev;
+		bdev->reqs[i].kvm = kvm;
+	}
+
+	disk_image__set_callback(bdev->disk, virtio_blk_complete);
+
+	pthread_create(&bdev->io_thread, NULL, virtio_blk_thread, bdev);
+	if (compat_id == -1)
+		compat_id = virtio_compat_add_message("virtio-blk", "CONFIG_VIRTIO_BLK");
+
+	return 0;
+}
+
+static int virtio_blk__exit_one(struct kvm *kvm, struct blk_dev *bdev)
+{
+	list_del(&bdev->list);
+	free(bdev);
+
+	return 0;
+}
+
+int virtio_blk__init(struct kvm *kvm)
+{
+	int i, r = 0;
+
+	for (i = 0; i < kvm->nr_disks; i++) {
+		r = virtio_blk__init_one(kvm, kvm->disks[i]);
+		if (r < 0)
+			goto cleanup;
+	}
+
+	return 0;
+cleanup:
+	return virtio_blk__exit(kvm);
+}
+
+int virtio_blk__exit(struct kvm *kvm)
+{
+	while (!list_empty(&bdevs)) {
+		struct blk_dev *bdev;
+
+		bdev = list_first_entry(&bdevs, struct blk_dev, list);
+		virtio_blk__exit_one(kvm, bdev);
+	}
+
+	return 0;
+}
diff --git a/tools/kvm/virtio/console.c b/tools/kvm/virtio/console.c
new file mode 100644
index 0000000..4bb1365
--- /dev/null
+++ b/tools/kvm/virtio/console.c
@@ -0,0 +1,193 @@
+#include "kvm/virtio-console.h"
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/disk-image.h"
+#include "kvm/virtio.h"
+#include "kvm/ioport.h"
+#include "kvm/util.h"
+#include "kvm/term.h"
+#include "kvm/mutex.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+#include "kvm/threadpool.h"
+#include "kvm/irq.h"
+#include "kvm/guest_compat.h"
+
+#include <linux/virtio_console.h>
+#include <linux/virtio_ring.h>
+#include <linux/virtio_blk.h>
+
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define VIRTIO_CONSOLE_QUEUE_SIZE	128
+#define VIRTIO_CONSOLE_NUM_QUEUES	2
+#define VIRTIO_CONSOLE_RX_QUEUE		0
+#define VIRTIO_CONSOLE_TX_QUEUE		1
+
+struct con_dev {
+	pthread_mutex_t			mutex;
+
+	struct virtio_device		vdev;
+	struct virt_queue		vqs[VIRTIO_CONSOLE_NUM_QUEUES];
+	struct virtio_console_config	config;
+	u32				features;
+
+	struct thread_pool__job		jobs[VIRTIO_CONSOLE_NUM_QUEUES];
+};
+
+static struct con_dev cdev = {
+	.mutex				= PTHREAD_MUTEX_INITIALIZER,
+
+	.config = {
+		.cols			= 80,
+		.rows			= 24,
+		.max_nr_ports		= 1,
+	},
+};
+
+static int compat_id = -1;
+
+/*
+ * Interrupts are injected for hvc0 only.
+ */
+static void virtio_console__inject_interrupt_callback(struct kvm *kvm, void *param)
+{
+	struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
+	struct virt_queue *vq;
+	u16 out, in;
+	u16 head;
+	int len;
+
+	mutex_lock(&cdev.mutex);
+
+	vq = param;
+
+	if (term_readable(CONSOLE_VIRTIO, 0) && virt_queue__available(vq)) {
+		head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
+		len = term_getc_iov(CONSOLE_VIRTIO, iov, in, 0);
+		virt_queue__set_used_elem(vq, head, len);
+		cdev.vdev.ops->signal_vq(kvm, &cdev.vdev, vq - cdev.vqs);
+	}
+
+	mutex_unlock(&cdev.mutex);
+}
+
+void virtio_console__inject_interrupt(struct kvm *kvm)
+{
+	thread_pool__do_job(&cdev.jobs[VIRTIO_CONSOLE_RX_QUEUE]);
+}
+
+static void virtio_console_handle_callback(struct kvm *kvm, void *param)
+{
+	struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
+	struct virt_queue *vq;
+	u16 out, in;
+	u16 head;
+	u32 len;
+
+	vq = param;
+
+	/*
+	 * The current Linux implementation polls for the buffer
+	 * to be used, rather than waiting for an interrupt.
+	 * So there is no need to inject an interrupt for the tx path.
+	 */
+
+	while (virt_queue__available(vq)) {
+		head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
+		len = term_putc_iov(CONSOLE_VIRTIO, iov, out, 0);
+		virt_queue__set_used_elem(vq, head, len);
+	}
+
+}
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+	struct con_dev *cdev = dev;
+
+	((u8 *)(&cdev->config))[offset] = data;
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+	struct con_dev *cdev = dev;
+
+	return ((u8 *)(&cdev->config))[offset];
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+	return 0;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+	/* Unused */
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+	struct virt_queue *queue;
+	void *p;
+
+	BUG_ON(vq >= VIRTIO_CONSOLE_NUM_QUEUES);
+
+	compat__remove_message(compat_id);
+
+	queue		= &cdev.vqs[vq];
+	queue->pfn	= pfn;
+	p		= guest_pfn_to_host(kvm, queue->pfn);
+
+	vring_init(&queue->vring, VIRTIO_CONSOLE_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
+
+	if (vq == VIRTIO_CONSOLE_TX_QUEUE)
+		thread_pool__init_job(&cdev.jobs[vq], kvm, virtio_console_handle_callback, queue);
+	else if (vq == VIRTIO_CONSOLE_RX_QUEUE)
+		thread_pool__init_job(&cdev.jobs[vq], kvm, virtio_console__inject_interrupt_callback, queue);
+
+	return 0;
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct con_dev *cdev = dev;
+
+	thread_pool__do_job(&cdev->jobs[vq]);
+
+	return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct con_dev *cdev = dev;
+
+	return cdev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	return VIRTIO_CONSOLE_QUEUE_SIZE;
+}
+
+static struct virtio_ops con_dev_virtio_ops = (struct virtio_ops) {
+	.set_config		= set_config,
+	.get_config		= get_config,
+	.get_host_features	= get_host_features,
+	.set_guest_features	= set_guest_features,
+	.init_vq		= init_vq,
+	.notify_vq		= notify_vq,
+	.get_pfn_vq		= get_pfn_vq,
+	.get_size_vq		= get_size_vq,
+};
+
+void virtio_console__init(struct kvm *kvm)
+{
+	virtio_init(kvm, &cdev, &cdev.vdev, &con_dev_virtio_ops,
+		    VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_CONSOLE, VIRTIO_ID_CONSOLE, PCI_CLASS_CONSOLE);
+	if (compat_id == -1)
+		compat_id = virtio_compat_add_message("virtio-console", "CONFIG_VIRTIO_CONSOLE");
+}
diff --git a/tools/kvm/virtio/core.c b/tools/kvm/virtio/core.c
new file mode 100644
index 0000000..2dfb828
--- /dev/null
+++ b/tools/kvm/virtio/core.c
@@ -0,0 +1,233 @@
+#include <linux/virtio_ring.h>
+#include <linux/types.h>
+#include <sys/uio.h>
+#include <stdlib.h>
+
+#include "kvm/guest_compat.h"
+#include "kvm/barrier.h"
+#include "kvm/virtio.h"
+#include "kvm/virtio-pci.h"
+#include "kvm/virtio-mmio.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+
+
+struct vring_used_elem *virt_queue__set_used_elem(struct virt_queue *queue, u32 head, u32 len)
+{
+	struct vring_used_elem *used_elem;
+
+	used_elem	= &queue->vring.used->ring[queue->vring.used->idx % queue->vring.num];
+	used_elem->id	= head;
+	used_elem->len	= len;
+
+	/*
+	 * Use wmb to assure that used elem was updated with head and len.
+	 * We need a wmb here since we can't advance idx unless we're ready
+	 * to pass the used element to the guest.
+	 */
+	wmb();
+	queue->vring.used->idx++;
+
+	/*
+	 * Use wmb to assure used idx has been increased before we signal the guest.
+	 * Without a wmb here the guest may ignore the queue since it won't see
+	 * an updated idx.
+	 */
+	wmb();
+
+	return used_elem;
+}
+
+/*
+ * Each buffer in the virtqueues is actually a chain of descriptors.  This
+ * function returns the next descriptor in the chain, or vq->vring.num if we're
+ * at the end.
+ */
+static unsigned next_desc(struct vring_desc *desc,
+			  unsigned int i, unsigned int max)
+{
+	unsigned int next;
+
+	/* If this descriptor says it doesn't chain, we're done. */
+	if (!(desc[i].flags & VRING_DESC_F_NEXT))
+		return max;
+
+	/* Check they're not leading us off end of descriptors. */
+	next = desc[i].next;
+	/* Make sure compiler knows to grab that: we don't want it changing! */
+	wmb();
+
+	return next;
+}
+
+u16 virt_queue__get_head_iov(struct virt_queue *vq, struct iovec iov[], u16 *out, u16 *in, u16 head, struct kvm *kvm)
+{
+	struct vring_desc *desc;
+	u16 idx;
+	u16 max;
+
+	idx = head;
+	*out = *in = 0;
+	max = vq->vring.num;
+	desc = vq->vring.desc;
+
+	if (desc[idx].flags & VRING_DESC_F_INDIRECT) {
+		max = desc[idx].len / sizeof(struct vring_desc);
+		desc = guest_flat_to_host(kvm, desc[idx].addr);
+		idx = 0;
+	}
+
+	do {
+		/* Grab the first descriptor, and check it's OK. */
+		iov[*out + *in].iov_len = desc[idx].len;
+		iov[*out + *in].iov_base = guest_flat_to_host(kvm, desc[idx].addr);
+		/* If this is an input descriptor, increment that count. */
+		if (desc[idx].flags & VRING_DESC_F_WRITE)
+			(*in)++;
+		else
+			(*out)++;
+	} while ((idx = next_desc(desc, idx, max)) != max);
+
+	return head;
+}
+
+u16 virt_queue__get_iov(struct virt_queue *vq, struct iovec iov[], u16 *out, u16 *in, struct kvm *kvm)
+{
+	u16 head;
+
+	head = virt_queue__pop(vq);
+
+	return virt_queue__get_head_iov(vq, iov, out, in, head, kvm);
+}
+
+/* in and out are relative to guest */
+u16 virt_queue__get_inout_iov(struct kvm *kvm, struct virt_queue *queue,
+			      struct iovec in_iov[], struct iovec out_iov[],
+			      u16 *in, u16 *out)
+{
+	struct vring_desc *desc;
+	u16 head, idx;
+
+	idx = head = virt_queue__pop(queue);
+	*out = *in = 0;
+	do {
+		desc = virt_queue__get_desc(queue, idx);
+		if (desc->flags & VRING_DESC_F_WRITE) {
+			in_iov[*in].iov_base = guest_flat_to_host(kvm,
+								  desc->addr);
+			in_iov[*in].iov_len = desc->len;
+			(*in)++;
+		} else {
+			out_iov[*out].iov_base = guest_flat_to_host(kvm,
+								    desc->addr);
+			out_iov[*out].iov_len = desc->len;
+			(*out)++;
+		}
+		if (desc->flags & VRING_DESC_F_NEXT)
+			idx = desc->next;
+		else
+			break;
+	} while (1);
+
+	return head;
+}
+
+int virtio__get_dev_specific_field(int offset, bool msix, u32 *config_off)
+{
+	if (msix) {
+		if (offset < 4)
+			return VIRTIO_PCI_O_MSIX;
+		else
+			offset -= 4;
+	}
+
+	*config_off = offset;
+
+	return VIRTIO_PCI_O_CONFIG;
+}
+
+bool virtio_queue__should_signal(struct virt_queue *vq)
+{
+	u16 old_idx, new_idx, event_idx;
+
+	old_idx		= vq->last_used_signalled;
+	new_idx		= vq->vring.used->idx;
+	event_idx	= vring_used_event(&vq->vring);
+
+	if (vring_need_event(event_idx, new_idx, old_idx)) {
+		vq->last_used_signalled = new_idx;
+		return true;
+	}
+
+	return false;
+}
+
+int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+		struct virtio_ops *ops, enum virtio_trans trans,
+		int device_id, int subsys_id, int class)
+{
+	void *virtio;
+
+	switch (trans) {
+	case VIRTIO_PCI:
+		virtio = calloc(sizeof(struct virtio_pci), 1);
+		if (!virtio)
+			return -ENOMEM;
+		vdev->virtio			= virtio;
+		vdev->ops			= ops;
+		vdev->ops->signal_vq		= virtio_pci__signal_vq;
+		vdev->ops->signal_config	= virtio_pci__signal_config;
+		vdev->ops->init			= virtio_pci__init;
+		vdev->ops->exit			= virtio_pci__exit;
+		vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class);
+		break;
+	case VIRTIO_MMIO:
+		virtio = calloc(sizeof(struct virtio_mmio), 1);
+		if (!virtio)
+			return -ENOMEM;
+		vdev->virtio			= virtio;
+		vdev->ops			= ops;
+		vdev->ops->signal_vq		= virtio_mmio_signal_vq;
+		vdev->ops->signal_config	= virtio_mmio_signal_config;
+		vdev->ops->init			= virtio_mmio_init;
+		vdev->ops->exit			= virtio_mmio_exit;
+		vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class);
+		break;
+	default:
+		return -1;
+	};
+
+	return 0;
+}
+
+int virtio_compat_add_message(const char *device, const char *config)
+{
+	int len = 1024;
+	int compat_id;
+	char *title;
+	char *desc;
+
+	title = malloc(len);
+	if (!title)
+		return -ENOMEM;
+
+	desc = malloc(len);
+	if (!desc) {
+		free(title);
+		return -ENOMEM;
+	}
+
+	snprintf(title, len, "%s device was not detected.", device);
+	snprintf(desc,  len, "While you have requested a %s device, "
+			     "the guest kernel did not initialize it.\n"
+			     "\tPlease make sure that the guest kernel was "
+			     "compiled with %s=y enabled in .config.",
+			     device, config);
+
+	compat_id = compat__add_message(title, desc);
+
+	free(desc);
+	free(title);
+
+	return compat_id;
+}
diff --git a/tools/kvm/virtio/mmio.c b/tools/kvm/virtio/mmio.c
new file mode 100644
index 0000000..8319954
--- /dev/null
+++ b/tools/kvm/virtio/mmio.c
@@ -0,0 +1,256 @@
+#include "kvm/virtio-mmio.h"
+#include "kvm/ioeventfd.h"
+#include "kvm/ioport.h"
+#include "kvm/virtio.h"
+#include "kvm/kvm.h"
+#include "kvm/irq.h"
+
+#include <linux/virtio_mmio.h>
+#include <string.h>
+
+static u32 virtio_mmio_io_space_blocks = KVM_VIRTIO_MMIO_AREA;
+
+static u32 virtio_mmio_get_io_space_block(u32 size)
+{
+	u32 block = virtio_mmio_io_space_blocks;
+	virtio_mmio_io_space_blocks += size;
+
+	return block;
+}
+
+static void virtio_mmio_ioevent_callback(struct kvm *kvm, void *param)
+{
+	struct virtio_mmio_ioevent_param *ioeventfd = param;
+	struct virtio_mmio *vmmio = ioeventfd->vdev->virtio;
+
+	ioeventfd->vdev->ops->notify_vq(kvm, vmmio->dev, ioeventfd->vq);
+}
+
+static int virtio_mmio_init_ioeventfd(struct kvm *kvm,
+				      struct virtio_device *vdev, u32 vq)
+{
+	struct virtio_mmio *vmmio = vdev->virtio;
+	struct ioevent ioevent;
+	int err;
+
+	vmmio->ioeventfds[vq] = (struct virtio_mmio_ioevent_param) {
+		.vdev		= vdev,
+		.vq		= vq,
+	};
+
+	ioevent = (struct ioevent) {
+		.io_addr	= vmmio->addr + VIRTIO_MMIO_QUEUE_NOTIFY,
+		.io_len		= sizeof(u32),
+		.fn		= virtio_mmio_ioevent_callback,
+		.fn_ptr		= &vmmio->ioeventfds[vq],
+		.datamatch	= vq,
+		.fn_kvm		= kvm,
+		.fd		= eventfd(0, 0),
+	};
+
+	err = ioeventfd__add_event(&ioevent, false);
+	if (err)
+		return err;
+
+	if (vdev->ops->notify_vq_eventfd)
+		vdev->ops->notify_vq_eventfd(kvm, vmmio->dev, vq, ioevent.fd);
+
+	return 0;
+}
+
+int virtio_mmio_signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
+{
+	struct virtio_mmio *vmmio = vdev->virtio;
+
+	vmmio->hdr.interrupt_state |= VIRTIO_MMIO_INT_VRING;
+	kvm__irq_trigger(vmmio->kvm, vmmio->irq);
+
+	return 0;
+}
+
+int virtio_mmio_signal_config(struct kvm *kvm, struct virtio_device *vdev)
+{
+	struct virtio_mmio *vmmio = vdev->virtio;
+
+	vmmio->hdr.interrupt_state |= VIRTIO_MMIO_INT_CONFIG;
+	kvm__irq_trigger(vmmio->kvm, vmmio->irq);
+
+	return 0;
+}
+
+static void virtio_mmio_device_specific(u64 addr, u8 *data, u32 len,
+					u8 is_write, struct virtio_device *vdev)
+{
+	struct virtio_mmio *vmmio = vdev->virtio;
+	u32 i;
+
+	for (i = 0; i < len; i++) {
+		if (is_write)
+			vdev->ops->set_config(vmmio->kvm, vmmio->dev,
+					      *(u8 *)data + i, addr + i);
+		else
+			data[i] = vdev->ops->get_config(vmmio->kvm,
+							vmmio->dev, addr + i);
+	}
+}
+
+static void virtio_mmio_config_in(u64 addr, void *data, u32 len,
+				  struct virtio_device *vdev)
+{
+	struct virtio_mmio *vmmio = vdev->virtio;
+	u32 val = 0;
+
+	switch (addr) {
+	case VIRTIO_MMIO_MAGIC_VALUE:
+	case VIRTIO_MMIO_VERSION:
+	case VIRTIO_MMIO_DEVICE_ID:
+	case VIRTIO_MMIO_VENDOR_ID:
+	case VIRTIO_MMIO_STATUS:
+	case VIRTIO_MMIO_INTERRUPT_STATUS:
+		ioport__write32(data, *(u32 *)(((void *)&vmmio->hdr) + addr));
+		break;
+	case VIRTIO_MMIO_HOST_FEATURES:
+		if (vmmio->hdr.host_features_sel == 0)
+			val = vdev->ops->get_host_features(vmmio->kvm,
+							   vmmio->dev);
+		ioport__write32(data, val);
+		break;
+	case VIRTIO_MMIO_QUEUE_PFN:
+		val = vdev->ops->get_pfn_vq(vmmio->kvm, vmmio->dev,
+					    vmmio->hdr.queue_sel);
+		ioport__write32(data, val);
+		break;
+	case VIRTIO_MMIO_QUEUE_NUM_MAX:
+		val = vdev->ops->get_size_vq(vmmio->kvm, vmmio->dev,
+					     vmmio->hdr.queue_sel);
+		ioport__write32(data, val);
+		break;
+	default:
+		break;
+	}
+}
+
+static void virtio_mmio_config_out(u64 addr, void *data, u32 len,
+				   struct virtio_device *vdev)
+{
+	struct virtio_mmio *vmmio = vdev->virtio;
+	u32 val = 0;
+
+	switch (addr) {
+	case VIRTIO_MMIO_HOST_FEATURES_SEL:
+	case VIRTIO_MMIO_GUEST_FEATURES_SEL:
+	case VIRTIO_MMIO_QUEUE_SEL:
+	case VIRTIO_MMIO_STATUS:
+		val = ioport__read32(data);
+		*(u32 *)(((void *)&vmmio->hdr) + addr) = val;
+		break;
+	case VIRTIO_MMIO_GUEST_FEATURES:
+		if (vmmio->hdr.guest_features_sel == 0) {
+			val = ioport__read32(data);
+			vdev->ops->set_guest_features(vmmio->kvm,
+						      vmmio->dev, val);
+		}
+		break;
+	case VIRTIO_MMIO_GUEST_PAGE_SIZE:
+		val = ioport__read32(data);
+		vmmio->hdr.guest_page_size = val;
+		/* FIXME: set guest page size */
+		break;
+	case VIRTIO_MMIO_QUEUE_NUM:
+		val = ioport__read32(data);
+		vmmio->hdr.queue_num = val;
+		/* FIXME: set vq size */
+		vdev->ops->set_size_vq(vmmio->kvm, vmmio->dev,
+				       vmmio->hdr.queue_sel, val);
+		break;
+	case VIRTIO_MMIO_QUEUE_ALIGN:
+		val = ioport__read32(data);
+		vmmio->hdr.queue_align = val;
+		/* FIXME: set used ring alignment */
+		break;
+	case VIRTIO_MMIO_QUEUE_PFN:
+		val = ioport__read32(data);
+		virtio_mmio_init_ioeventfd(vmmio->kvm, vdev, vmmio->hdr.queue_sel);
+		vdev->ops->init_vq(vmmio->kvm, vmmio->dev,
+				   vmmio->hdr.queue_sel, val);
+		break;
+	case VIRTIO_MMIO_QUEUE_NOTIFY:
+		val = ioport__read32(data);
+		vdev->ops->notify_vq(vmmio->kvm, vmmio->dev, val);
+		break;
+	case VIRTIO_MMIO_INTERRUPT_ACK:
+		val = ioport__read32(data);
+		vmmio->hdr.interrupt_state &= ~val;
+		break;
+	default:
+		break;
+	};
+}
+
+static void virtio_mmio_mmio_callback(u64 addr, u8 *data, u32 len,
+				      u8 is_write, void *ptr)
+{
+	struct virtio_device *vdev = ptr;
+	struct virtio_mmio *vmmio = vdev->virtio;
+	u32 offset = addr - vmmio->addr;
+
+	if (offset >= VIRTIO_MMIO_CONFIG) {
+		offset -= VIRTIO_MMIO_CONFIG;
+		virtio_mmio_device_specific(offset, data, len, is_write, ptr);
+		return;
+	}
+
+	if (is_write)
+		virtio_mmio_config_out(offset, data, len, ptr);
+	else
+		virtio_mmio_config_in(offset, data, len, ptr);
+}
+
+int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+		     int device_id, int subsys_id, int class)
+{
+	struct virtio_mmio *vmmio = vdev->virtio;
+	u8 device, pin, line;
+
+	vmmio->addr	= virtio_mmio_get_io_space_block(VIRTIO_MMIO_IO_SIZE);
+	vmmio->kvm	= kvm;
+	vmmio->dev	= dev;
+
+	kvm__register_mmio(kvm, vmmio->addr, VIRTIO_MMIO_IO_SIZE,
+			   false, virtio_mmio_mmio_callback, vdev);
+
+	vmmio->hdr = (struct virtio_mmio_hdr) {
+		.magic		= {'v', 'i', 'r', 't'},
+		.version	= 1,
+		.device_id	= device_id - 0x1000 + 1,
+		.vendor_id	= 0x4d564b4c , /* 'LKVM' */
+		.queue_num_max	= 256,
+	};
+
+	if (irq__register_device(subsys_id, &device, &pin, &line) < 0)
+		return -1;
+	vmmio->irq = line;
+
+	/*
+	 * Instantiate guest virtio-mmio devices using kernel command line
+	 * (or module) parameter, e.g
+	 *
+	 * virtio_mmio.devices=0x200@0xd2000000:5,0x200@0xd2000200:6
+	 */
+	pr_info("virtio-mmio.devices=0x%x@0x%x:%d\n", VIRTIO_MMIO_IO_SIZE, vmmio->addr, line);
+
+	return 0;
+}
+
+int virtio_mmio_exit(struct kvm *kvm, struct virtio_device *vdev)
+{
+	struct virtio_mmio *vmmio = vdev->virtio;
+	int i;
+
+	kvm__deregister_mmio(kvm, vmmio->addr);
+
+	for (i = 0; i < VIRTIO_MMIO_MAX_VQ; i++)
+		ioeventfd__del_event(vmmio->addr + VIRTIO_MMIO_QUEUE_NOTIFY, i);
+
+	return 0;
+}
diff --git a/tools/kvm/virtio/net.c b/tools/kvm/virtio/net.c
new file mode 100644
index 0000000..ae17eb5
--- /dev/null
+++ b/tools/kvm/virtio/net.c
@@ -0,0 +1,552 @@
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/virtio-net.h"
+#include "kvm/virtio.h"
+#include "kvm/types.h"
+#include "kvm/mutex.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/irq.h"
+#include "kvm/uip.h"
+#include "kvm/guest_compat.h"
+
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/if_tun.h>
+#include <linux/types.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/eventfd.h>
+
+#define VIRTIO_NET_QUEUE_SIZE		256
+#define VIRTIO_NET_NUM_QUEUES		2
+#define VIRTIO_NET_RX_QUEUE		0
+#define VIRTIO_NET_TX_QUEUE		1
+
+struct net_dev;
+
+extern struct kvm *kvm;
+
+struct net_dev_operations {
+	int (*rx)(struct iovec *iov, u16 in, struct net_dev *ndev);
+	int (*tx)(struct iovec *iov, u16 in, struct net_dev *ndev);
+};
+
+struct net_dev {
+	pthread_mutex_t			mutex;
+	struct virtio_device		vdev;
+	struct list_head		list;
+
+	struct virt_queue		vqs[VIRTIO_NET_NUM_QUEUES];
+	struct virtio_net_config	config;
+	u32				features;
+
+	pthread_t			io_rx_thread;
+	pthread_mutex_t			io_rx_lock;
+	pthread_cond_t			io_rx_cond;
+
+	pthread_t			io_tx_thread;
+	pthread_mutex_t			io_tx_lock;
+	pthread_cond_t			io_tx_cond;
+
+	int				vhost_fd;
+	int				tap_fd;
+	char				tap_name[IFNAMSIZ];
+
+	int				mode;
+
+	struct uip_info			info;
+	struct net_dev_operations	*ops;
+	struct kvm			*kvm;
+};
+
+static LIST_HEAD(ndevs);
+static int compat_id = -1;
+
+static void *virtio_net_rx_thread(void *p)
+{
+	struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
+	struct virt_queue *vq;
+	struct kvm *kvm;
+	struct net_dev *ndev = p;
+	u16 out, in;
+	u16 head;
+	int len;
+
+	kvm = ndev->kvm;
+	vq = &ndev->vqs[VIRTIO_NET_RX_QUEUE];
+
+	while (1) {
+		mutex_lock(&ndev->io_rx_lock);
+		if (!virt_queue__available(vq))
+			pthread_cond_wait(&ndev->io_rx_cond, &ndev->io_rx_lock);
+		mutex_unlock(&ndev->io_rx_lock);
+
+		while (virt_queue__available(vq)) {
+			head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
+			len = ndev->ops->rx(iov, in, ndev);
+			virt_queue__set_used_elem(vq, head, len);
+
+			/* We should interrupt guest right now, otherwise latency is huge. */
+			if (virtio_queue__should_signal(&ndev->vqs[VIRTIO_NET_RX_QUEUE]))
+				ndev->vdev.ops->signal_vq(kvm, &ndev->vdev,
+							   VIRTIO_NET_RX_QUEUE);
+		}
+	}
+
+	pthread_exit(NULL);
+	return NULL;
+
+}
+
+static void *virtio_net_tx_thread(void *p)
+{
+	struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
+	struct virt_queue *vq;
+	struct kvm *kvm;
+	struct net_dev *ndev = p;
+	u16 out, in;
+	u16 head;
+	int len;
+
+	kvm = ndev->kvm;
+	vq = &ndev->vqs[VIRTIO_NET_TX_QUEUE];
+
+	while (1) {
+		mutex_lock(&ndev->io_tx_lock);
+		if (!virt_queue__available(vq))
+			pthread_cond_wait(&ndev->io_tx_cond, &ndev->io_tx_lock);
+		mutex_unlock(&ndev->io_tx_lock);
+
+		while (virt_queue__available(vq)) {
+			head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
+			len = ndev->ops->tx(iov, out, ndev);
+			virt_queue__set_used_elem(vq, head, len);
+		}
+
+		if (virtio_queue__should_signal(&ndev->vqs[VIRTIO_NET_TX_QUEUE]))
+			ndev->vdev.ops->signal_vq(kvm, &ndev->vdev, VIRTIO_NET_TX_QUEUE);
+	}
+
+	pthread_exit(NULL);
+
+	return NULL;
+
+}
+
+static void virtio_net_handle_callback(struct kvm *kvm, struct net_dev *ndev, int queue)
+{
+	switch (queue) {
+	case VIRTIO_NET_TX_QUEUE:
+		mutex_lock(&ndev->io_tx_lock);
+		pthread_cond_signal(&ndev->io_tx_cond);
+		mutex_unlock(&ndev->io_tx_lock);
+		break;
+	case VIRTIO_NET_RX_QUEUE:
+		mutex_lock(&ndev->io_rx_lock);
+		pthread_cond_signal(&ndev->io_rx_cond);
+		mutex_unlock(&ndev->io_rx_lock);
+		break;
+	default:
+		pr_warning("Unknown queue index %u", queue);
+	}
+}
+
+static bool virtio_net__tap_init(const struct virtio_net_params *params,
+					struct net_dev *ndev)
+{
+	int sock = socket(AF_INET, SOCK_STREAM, 0);
+	int pid, status, offload, hdr_len;
+	struct sockaddr_in sin = {0};
+	struct ifreq ifr;
+
+	/* Did the user already gave us the FD? */
+	if (params->fd) {
+		ndev->tap_fd = params->fd;
+		return 1;
+	}
+
+	ndev->tap_fd = open("/dev/net/tun", O_RDWR);
+	if (ndev->tap_fd < 0) {
+		pr_warning("Unable to open /dev/net/tun");
+		goto fail;
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
+	if (ioctl(ndev->tap_fd, TUNSETIFF, &ifr) < 0) {
+		pr_warning("Config tap device error. Are you root?");
+		goto fail;
+	}
+
+	strncpy(ndev->tap_name, ifr.ifr_name, sizeof(ndev->tap_name));
+
+	if (ioctl(ndev->tap_fd, TUNSETNOCSUM, 1) < 0) {
+		pr_warning("Config tap device TUNSETNOCSUM error");
+		goto fail;
+	}
+
+	hdr_len = sizeof(struct virtio_net_hdr);
+	if (ioctl(ndev->tap_fd, TUNSETVNETHDRSZ, &hdr_len) < 0)
+		pr_warning("Config tap device TUNSETVNETHDRSZ error");
+
+	offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_UFO;
+	if (ioctl(ndev->tap_fd, TUNSETOFFLOAD, offload) < 0) {
+		pr_warning("Config tap device TUNSETOFFLOAD error");
+		goto fail;
+	}
+
+	if (strcmp(params->script, "none")) {
+		pid = fork();
+		if (pid == 0) {
+			execl(params->script, params->script, ndev->tap_name, NULL);
+			_exit(1);
+		} else {
+			waitpid(pid, &status, 0);
+			if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
+				pr_warning("Fail to setup tap by %s", params->script);
+				goto fail;
+			}
+		}
+	} else {
+		memset(&ifr, 0, sizeof(ifr));
+		strncpy(ifr.ifr_name, ndev->tap_name, sizeof(ndev->tap_name));
+		sin.sin_addr.s_addr = inet_addr(params->host_ip);
+		memcpy(&(ifr.ifr_addr), &sin, sizeof(ifr.ifr_addr));
+		ifr.ifr_addr.sa_family = AF_INET;
+		if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) {
+			pr_warning("Could not set ip address on tap device");
+			goto fail;
+		}
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, ndev->tap_name, sizeof(ndev->tap_name));
+	ioctl(sock, SIOCGIFFLAGS, &ifr);
+	ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+	if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0)
+		pr_warning("Could not bring tap device up");
+
+	close(sock);
+
+	return 1;
+
+fail:
+	if (sock >= 0)
+		close(sock);
+	if (ndev->tap_fd >= 0)
+		close(ndev->tap_fd);
+
+	return 0;
+}
+
+static void virtio_net__io_thread_init(struct kvm *kvm, struct net_dev *ndev)
+{
+	pthread_mutex_init(&ndev->io_tx_lock, NULL);
+	pthread_mutex_init(&ndev->io_rx_lock, NULL);
+
+	pthread_cond_init(&ndev->io_tx_cond, NULL);
+	pthread_cond_init(&ndev->io_rx_cond, NULL);
+
+	pthread_create(&ndev->io_tx_thread, NULL, virtio_net_tx_thread, ndev);
+	pthread_create(&ndev->io_rx_thread, NULL, virtio_net_rx_thread, ndev);
+}
+
+static inline int tap_ops_tx(struct iovec *iov, u16 out, struct net_dev *ndev)
+{
+	return writev(ndev->tap_fd, iov, out);
+}
+
+static inline int tap_ops_rx(struct iovec *iov, u16 in, struct net_dev *ndev)
+{
+	return readv(ndev->tap_fd, iov, in);
+}
+
+static inline int uip_ops_tx(struct iovec *iov, u16 out, struct net_dev *ndev)
+{
+	return uip_tx(iov, out, &ndev->info);
+}
+
+static inline int uip_ops_rx(struct iovec *iov, u16 in, struct net_dev *ndev)
+{
+	return uip_rx(iov, in, &ndev->info);
+}
+
+static struct net_dev_operations tap_ops = {
+	.rx	= tap_ops_rx,
+	.tx	= tap_ops_tx,
+};
+
+static struct net_dev_operations uip_ops = {
+	.rx	= uip_ops_rx,
+	.tx	= uip_ops_tx,
+};
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+	struct net_dev *ndev = dev;
+
+	((u8 *)(&ndev->config))[offset] = data;
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+	struct net_dev *ndev = dev;
+
+	return ((u8 *)(&ndev->config))[offset];
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+	return 1UL << VIRTIO_NET_F_MAC
+		| 1UL << VIRTIO_NET_F_CSUM
+		| 1UL << VIRTIO_NET_F_HOST_UFO
+		| 1UL << VIRTIO_NET_F_HOST_TSO4
+		| 1UL << VIRTIO_NET_F_HOST_TSO6
+		| 1UL << VIRTIO_NET_F_GUEST_UFO
+		| 1UL << VIRTIO_NET_F_GUEST_TSO4
+		| 1UL << VIRTIO_NET_F_GUEST_TSO6
+		| 1UL << VIRTIO_RING_F_EVENT_IDX
+		| 1UL << VIRTIO_RING_F_INDIRECT_DESC;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+	struct net_dev *ndev = dev;
+
+	ndev->features = features;
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+	struct vhost_vring_state state = { .index = vq };
+	struct vhost_vring_addr addr;
+	struct net_dev *ndev = dev;
+	struct virt_queue *queue;
+	void *p;
+	int r;
+
+	compat__remove_message(compat_id);
+
+	queue		= &ndev->vqs[vq];
+	queue->pfn	= pfn;
+	p		= guest_pfn_to_host(kvm, queue->pfn);
+
+	/* FIXME: respect pci and mmio vring alignment */
+	vring_init(&queue->vring, VIRTIO_NET_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
+
+	if (ndev->vhost_fd == 0)
+		return 0;
+
+	state.num = queue->vring.num;
+	r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_NUM, &state);
+	if (r < 0)
+		die_perror("VHOST_SET_VRING_NUM failed");
+	state.num = 0;
+	r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_BASE, &state);
+	if (r < 0)
+		die_perror("VHOST_SET_VRING_BASE failed");
+
+	addr = (struct vhost_vring_addr) {
+		.index = vq,
+		.desc_user_addr = (u64)(unsigned long)queue->vring.desc,
+		.avail_user_addr = (u64)(unsigned long)queue->vring.avail,
+		.used_user_addr = (u64)(unsigned long)queue->vring.used,
+	};
+
+	r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_ADDR, &addr);
+	if (r < 0)
+		die_perror("VHOST_SET_VRING_ADDR failed");
+
+	return 0;
+}
+
+static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi)
+{
+	struct net_dev *ndev = dev;
+	struct kvm_irqfd irq;
+	struct vhost_vring_file file;
+	int r;
+
+	if (ndev->vhost_fd == 0)
+		return;
+
+	irq = (struct kvm_irqfd) {
+		.gsi	= gsi,
+		.fd	= eventfd(0, 0),
+	};
+	file = (struct vhost_vring_file) {
+		.index	= vq,
+		.fd	= irq.fd,
+	};
+
+	r = ioctl(kvm->vm_fd, KVM_IRQFD, &irq);
+	if (r < 0)
+		die_perror("KVM_IRQFD failed");
+
+	r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_CALL, &file);
+	if (r < 0)
+		die_perror("VHOST_SET_VRING_CALL failed");
+	file.fd = ndev->tap_fd;
+	r = ioctl(ndev->vhost_fd, VHOST_NET_SET_BACKEND, &file);
+	if (r != 0)
+		die("VHOST_NET_SET_BACKEND failed %d", errno);
+
+}
+
+static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd)
+{
+	struct net_dev *ndev = dev;
+	struct vhost_vring_file file = {
+		.index	= vq,
+		.fd	= efd,
+	};
+	int r;
+
+	if (ndev->vhost_fd == 0)
+		return;
+
+	r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_KICK, &file);
+	if (r < 0)
+		die_perror("VHOST_SET_VRING_KICK failed");
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct net_dev *ndev = dev;
+
+	virtio_net_handle_callback(kvm, ndev, vq);
+
+	return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct net_dev *ndev = dev;
+
+	return ndev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	/* FIXME: dynamic */
+	return VIRTIO_NET_QUEUE_SIZE;
+}
+
+static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
+{
+	/* FIXME: dynamic */
+	return size;
+}
+
+static struct virtio_ops net_dev_virtio_ops = (struct virtio_ops) {
+	.set_config		= set_config,
+	.get_config		= get_config,
+	.get_host_features	= get_host_features,
+	.set_guest_features	= set_guest_features,
+	.init_vq		= init_vq,
+	.get_pfn_vq		= get_pfn_vq,
+	.get_size_vq		= get_size_vq,
+	.set_size_vq		= set_size_vq,
+	.notify_vq		= notify_vq,
+	.notify_vq_gsi		= notify_vq_gsi,
+	.notify_vq_eventfd	= notify_vq_eventfd,
+};
+
+static void virtio_net__vhost_init(struct kvm *kvm, struct net_dev *ndev)
+{
+	u64 features = 1UL << VIRTIO_RING_F_EVENT_IDX;
+	struct vhost_memory *mem;
+	int r;
+
+	ndev->vhost_fd = open("/dev/vhost-net", O_RDWR);
+	if (ndev->vhost_fd < 0)
+		die_perror("Failed openning vhost-net device");
+
+	mem = malloc(sizeof(*mem) + sizeof(struct vhost_memory_region));
+	if (mem == NULL)
+		die("Failed allocating memory for vhost memory map");
+
+	mem->nregions = 1;
+	mem->regions[0] = (struct vhost_memory_region) {
+		.guest_phys_addr	= 0,
+		.memory_size		= kvm->ram_size,
+		.userspace_addr		= (unsigned long)kvm->ram_start,
+	};
+
+	r = ioctl(ndev->vhost_fd, VHOST_SET_OWNER);
+	if (r != 0)
+		die_perror("VHOST_SET_OWNER failed");
+
+	r = ioctl(ndev->vhost_fd, VHOST_SET_FEATURES, &features);
+	if (r != 0)
+		die_perror("VHOST_SET_FEATURES failed");
+	r = ioctl(ndev->vhost_fd, VHOST_SET_MEM_TABLE, mem);
+	if (r != 0)
+		die_perror("VHOST_SET_MEM_TABLE failed");
+	free(mem);
+}
+
+void virtio_net__init(const struct virtio_net_params *params)
+{
+	int i;
+	struct net_dev *ndev;
+
+	if (!params)
+		return;
+
+	ndev = calloc(1, sizeof(struct net_dev));
+	if (ndev == NULL)
+		die("Failed allocating ndev");
+
+	list_add_tail(&ndev->list, &ndevs);
+
+	ndev->kvm = params->kvm;
+
+	mutex_init(&ndev->mutex);
+	ndev->config.status = VIRTIO_NET_S_LINK_UP;
+
+	for (i = 0 ; i < 6 ; i++) {
+		ndev->config.mac[i]		= params->guest_mac[i];
+		ndev->info.guest_mac.addr[i]	= params->guest_mac[i];
+		ndev->info.host_mac.addr[i]	= params->host_mac[i];
+	}
+
+	ndev->mode = params->mode;
+	if (ndev->mode == NET_MODE_TAP) {
+		if (!virtio_net__tap_init(params, ndev))
+			die_perror("You have requested a TAP device, but creation of one has"
+					"failed because:");
+		ndev->ops = &tap_ops;
+	} else {
+		ndev->info.host_ip		= ntohl(inet_addr(params->host_ip));
+		ndev->info.guest_ip		= ntohl(inet_addr(params->guest_ip));
+		ndev->info.guest_netmask	= ntohl(inet_addr("255.255.255.0"));
+		ndev->info.buf_nr		= 20,
+		uip_init(&ndev->info);
+		ndev->ops = &uip_ops;
+	}
+
+	if (params->trans && strcmp(params->trans, "mmio") == 0)
+		virtio_init(kvm, ndev, &ndev->vdev, &net_dev_virtio_ops,
+			    VIRTIO_MMIO, PCI_DEVICE_ID_VIRTIO_NET, VIRTIO_ID_NET, PCI_CLASS_NET);
+	else
+		virtio_init(kvm, ndev, &ndev->vdev, &net_dev_virtio_ops,
+			    VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_NET, VIRTIO_ID_NET, PCI_CLASS_NET);
+
+	if (params->vhost)
+		virtio_net__vhost_init(params->kvm, ndev);
+	else
+		virtio_net__io_thread_init(params->kvm, ndev);
+
+	if (compat_id == -1)
+		compat_id = virtio_compat_add_message("virtio-net", "CONFIG_VIRTIO_NET");
+}
diff --git a/tools/kvm/virtio/pci.c b/tools/kvm/virtio/pci.c
new file mode 100644
index 0000000..8558341e
--- /dev/null
+++ b/tools/kvm/virtio/pci.c
@@ -0,0 +1,369 @@
+#include "kvm/virtio-pci.h"
+
+#include "kvm/ioport.h"
+#include "kvm/kvm.h"
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/irq.h"
+#include "kvm/virtio.h"
+#include "kvm/ioeventfd.h"
+
+#include <linux/virtio_pci.h>
+#include <linux/byteorder.h>
+#include <string.h>
+
+static void virtio_pci__ioevent_callback(struct kvm *kvm, void *param)
+{
+	struct virtio_pci_ioevent_param *ioeventfd = param;
+	struct virtio_pci *vpci = ioeventfd->vdev->virtio;
+
+	ioeventfd->vdev->ops->notify_vq(kvm, vpci->dev, ioeventfd->vq);
+}
+
+static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
+{
+	struct ioevent ioevent;
+	struct virtio_pci *vpci = vdev->virtio;
+	int r;
+
+	vpci->ioeventfds[vq] = (struct virtio_pci_ioevent_param) {
+		.vdev		= vdev,
+		.vq		= vq,
+	};
+
+	ioevent = (struct ioevent) {
+		.io_addr	= vpci->base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
+		.io_len		= sizeof(u16),
+		.fn		= virtio_pci__ioevent_callback,
+		.fn_ptr		= &vpci->ioeventfds[vq],
+		.datamatch	= vq,
+		.fn_kvm		= kvm,
+		.fd		= eventfd(0, 0),
+	};
+
+	r = ioeventfd__add_event(&ioevent, true);
+	if (r)
+		return r;
+
+	if (vdev->ops->notify_vq_eventfd)
+		vdev->ops->notify_vq_eventfd(kvm, vpci->dev, vq, ioevent.fd);
+
+	return 0;
+}
+
+static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci)
+{
+	return vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE);
+}
+
+static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_device *vdev, u16 port,
+					void *data, int size, int offset)
+{
+	u32 config_offset;
+	struct virtio_pci *vpci = vdev->virtio;
+	int type = virtio__get_dev_specific_field(offset - 20,
+							virtio_pci__msix_enabled(vpci),
+							&config_offset);
+	if (type == VIRTIO_PCI_O_MSIX) {
+		switch (offset) {
+		case VIRTIO_MSI_CONFIG_VECTOR:
+			ioport__write16(data, vpci->config_vector);
+			break;
+		case VIRTIO_MSI_QUEUE_VECTOR:
+			ioport__write16(data, vpci->vq_vector[vpci->queue_selector]);
+			break;
+		};
+
+		return true;
+	} else if (type == VIRTIO_PCI_O_CONFIG) {
+		u8 cfg;
+
+		cfg = vdev->ops->get_config(kvm, vpci->dev, config_offset);
+		ioport__write8(data, cfg);
+		return true;
+	}
+
+	return false;
+}
+
+static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	unsigned long offset;
+	bool ret = true;
+	struct virtio_device *vdev;
+	struct virtio_pci *vpci;
+	u32 val;
+
+	vdev = ioport->priv;
+	vpci = vdev->virtio;
+	offset = port - vpci->base_addr;
+
+	switch (offset) {
+	case VIRTIO_PCI_HOST_FEATURES:
+		val = vdev->ops->get_host_features(kvm, vpci->dev);
+		ioport__write32(data, val);
+		break;
+	case VIRTIO_PCI_QUEUE_PFN:
+		val = vdev->ops->get_pfn_vq(kvm, vpci->dev, vpci->queue_selector);
+		ioport__write32(data, val);
+		break;
+	case VIRTIO_PCI_QUEUE_NUM:
+		val = vdev->ops->get_size_vq(kvm, vpci->dev, vpci->queue_selector);
+		ioport__write16(data, val);
+		break;
+	case VIRTIO_PCI_STATUS:
+		ioport__write8(data, vpci->status);
+		break;
+	case VIRTIO_PCI_ISR:
+		ioport__write8(data, vpci->isr);
+		kvm__irq_line(kvm, vpci->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
+		vpci->isr = VIRTIO_IRQ_LOW;
+		break;
+	default:
+		ret = virtio_pci__specific_io_in(kvm, vdev, port, data, size, offset);
+		break;
+	};
+
+	return ret;
+}
+
+static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_device *vdev, u16 port,
+					void *data, int size, int offset)
+{
+	struct virtio_pci *vpci = vdev->virtio;
+	u32 config_offset, gsi, vec;
+	int type = virtio__get_dev_specific_field(offset - 20, virtio_pci__msix_enabled(vpci),
+							&config_offset);
+	if (type == VIRTIO_PCI_O_MSIX) {
+		switch (offset) {
+		case VIRTIO_MSI_CONFIG_VECTOR:
+			vec = vpci->config_vector = ioport__read16(data);
+
+			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
+
+			vpci->config_gsi = gsi;
+			break;
+		case VIRTIO_MSI_QUEUE_VECTOR:
+			vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data);
+
+			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
+			vpci->gsis[vpci->queue_selector] = gsi;
+			if (vdev->ops->notify_vq_gsi)
+				vdev->ops->notify_vq_gsi(kvm, vpci->dev,
+							vpci->queue_selector, gsi);
+			break;
+		};
+
+		return true;
+	} else if (type == VIRTIO_PCI_O_CONFIG) {
+		vdev->ops->set_config(kvm, vpci->dev, *(u8 *)data, config_offset);
+
+		return true;
+	}
+
+	return false;
+}
+
+static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	unsigned long offset;
+	bool ret = true;
+	struct virtio_device *vdev;
+	struct virtio_pci *vpci;
+	u32 val;
+
+	vdev = ioport->priv;
+	vpci = vdev->virtio;
+	offset = port - vpci->base_addr;
+
+	switch (offset) {
+	case VIRTIO_PCI_GUEST_FEATURES:
+		val = ioport__read32(data);
+		vdev->ops->set_guest_features(kvm, vpci->dev, val);
+		break;
+	case VIRTIO_PCI_QUEUE_PFN:
+		val = ioport__read32(data);
+		virtio_pci__init_ioeventfd(kvm, vdev, vpci->queue_selector);
+		vdev->ops->init_vq(kvm, vpci->dev, vpci->queue_selector, val);
+		break;
+	case VIRTIO_PCI_QUEUE_SEL:
+		vpci->queue_selector = ioport__read16(data);
+		break;
+	case VIRTIO_PCI_QUEUE_NOTIFY:
+		val = ioport__read16(data);
+		vdev->ops->notify_vq(kvm, vpci->dev, val);
+		break;
+	case VIRTIO_PCI_STATUS:
+		vpci->status = ioport__read8(data);
+		break;
+	default:
+		ret = virtio_pci__specific_io_out(kvm, vdev, port, data, size, offset);
+		break;
+	};
+
+	return ret;
+}
+
+static struct ioport_operations virtio_pci__io_ops = {
+	.io_in	= virtio_pci__io_in,
+	.io_out	= virtio_pci__io_out,
+};
+
+static void virtio_pci__mmio_callback(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
+{
+	struct virtio_pci *vpci = ptr;
+	void *table;
+	u32 offset;
+
+	if (addr > vpci->msix_io_block + PCI_IO_SIZE) {
+		table	= &vpci->msix_pba;
+		offset	= vpci->msix_io_block + PCI_IO_SIZE;
+	} else {
+		table	= &vpci->msix_table;
+		offset	= vpci->msix_io_block;
+	}
+
+	if (is_write)
+		memcpy(table + addr - offset, data, len);
+	else
+		memcpy(data, table + addr - offset, len);
+}
+
+int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
+{
+	struct virtio_pci *vpci = vdev->virtio;
+	int tbl = vpci->vq_vector[vq];
+
+	if (virtio_pci__msix_enabled(vpci)) {
+		if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) ||
+		    vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
+
+			vpci->msix_pba |= 1 << tbl;
+			return 0;
+		}
+
+		kvm__irq_trigger(kvm, vpci->gsis[vq]);
+	} else {
+		vpci->isr = VIRTIO_IRQ_HIGH;
+		kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
+	}
+	return 0;
+}
+
+int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev)
+{
+	struct virtio_pci *vpci = vdev->virtio;
+	int tbl = vpci->config_vector;
+
+	if (virtio_pci__msix_enabled(vpci)) {
+		if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) ||
+		    vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
+
+			vpci->msix_pba |= 1 << tbl;
+			return 0;
+		}
+
+		kvm__irq_trigger(kvm, vpci->config_gsi);
+	} else {
+		vpci->isr = VIRTIO_PCI_ISR_CONFIG;
+		kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
+	}
+
+	return 0;
+}
+
+int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+		     int device_id, int subsys_id, int class)
+{
+	struct virtio_pci *vpci = vdev->virtio;
+	u8 pin, line, ndev;
+	int r;
+
+	vpci->dev = dev;
+	vpci->msix_io_block = pci_get_io_space_block(PCI_IO_SIZE * 2);
+
+	r = ioport__register(IOPORT_EMPTY, &virtio_pci__io_ops, IOPORT_SIZE, vdev);
+	if (r < 0)
+		return r;
+
+	vpci->base_addr = (u16)r;
+	r = kvm__register_mmio(kvm, vpci->msix_io_block, PCI_IO_SIZE, false,
+			       virtio_pci__mmio_callback, vpci);
+	if (r < 0)
+		goto free_ioport;
+
+	vpci->pci_hdr = (struct pci_device_header) {
+		.vendor_id		= cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
+		.device_id		= cpu_to_le16(device_id),
+		.header_type		= PCI_HEADER_TYPE_NORMAL,
+		.revision_id		= 0,
+		.class[0]		= class & 0xff,
+		.class[1]		= (class >> 8) & 0xff,
+		.class[2]		= (class >> 16) & 0xff,
+		.subsys_vendor_id	= cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET),
+		.subsys_id		= cpu_to_le16(subsys_id),
+		.bar[0]			= cpu_to_le32(vpci->base_addr
+							| PCI_BASE_ADDRESS_SPACE_IO),
+		.bar[1]			= cpu_to_le32(vpci->msix_io_block
+							| PCI_BASE_ADDRESS_SPACE_MEMORY),
+		.status			= cpu_to_le16(PCI_STATUS_CAP_LIST),
+		.capabilities		= (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
+		.bar_size[0]		= IOPORT_SIZE,
+		.bar_size[1]		= PCI_IO_SIZE,
+		.bar_size[3]		= PCI_IO_SIZE,
+	};
+
+	vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
+	vpci->pci_hdr.msix.next = 0;
+	/*
+	 * We at most have VIRTIO_PCI_MAX_VQ entries for virt queue,
+	 * VIRTIO_PCI_MAX_CONFIG entries for config.
+	 *
+	 * To quote the PCI spec:
+	 *
+	 * System software reads this field to determine the
+	 * MSI-X Table Size N, which is encoded as N-1.
+	 * For example, a returned value of "00000000011"
+	 * indicates a table size of 4.
+	 */
+	vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG - 1);
+
+	/*
+	 * Both table and PBA could be mapped on the same BAR, but for now
+	 * we're not in short of BARs
+	 */
+	vpci->pci_hdr.msix.table_offset = cpu_to_le32(1); /* Use BAR 1 */
+	vpci->pci_hdr.msix.pba_offset = cpu_to_le32(1 | PCI_IO_SIZE); /* Use BAR 3 */
+	vpci->config_vector = 0;
+
+	r = irq__register_device(subsys_id, &ndev, &pin, &line);
+	if (r < 0)
+		goto free_mmio;
+
+	vpci->pci_hdr.irq_pin	= pin;
+	vpci->pci_hdr.irq_line	= line;
+	r = pci__register(&vpci->pci_hdr, ndev);
+	if (r < 0)
+		goto free_ioport;
+
+	return 0;
+
+free_mmio:
+	kvm__deregister_mmio(kvm, vpci->msix_io_block);
+free_ioport:
+	ioport__unregister(vpci->base_addr);
+	return r;
+}
+
+int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev)
+{
+	struct virtio_pci *vpci = vdev->virtio;
+	int i;
+
+	kvm__deregister_mmio(kvm, vpci->msix_io_block);
+	ioport__unregister(vpci->base_addr);
+
+	for (i = 0; i < VIRTIO_PCI_MAX_VQ; i++)
+		ioeventfd__del_event(vpci->base_addr + VIRTIO_PCI_QUEUE_NOTIFY, i);
+
+	return 0;
+}
diff --git a/tools/kvm/virtio/rng.c b/tools/kvm/virtio/rng.c
new file mode 100644
index 0000000..5aa632d
--- /dev/null
+++ b/tools/kvm/virtio/rng.c
@@ -0,0 +1,194 @@
+#include "kvm/virtio-rng.h"
+
+#include "kvm/virtio-pci-dev.h"
+
+#include "kvm/virtio.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/threadpool.h"
+#include "kvm/guest_compat.h"
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_rng.h>
+
+#include <linux/list.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include <linux/kernel.h>
+
+#define NUM_VIRT_QUEUES		1
+#define VIRTIO_RNG_QUEUE_SIZE	128
+
+struct rng_dev_job {
+	struct virt_queue	*vq;
+	struct rng_dev		*rdev;
+	struct thread_pool__job	job_id;
+};
+
+struct rng_dev {
+	struct list_head	list;
+	struct virtio_device	vdev;
+
+	int			fd;
+
+	/* virtio queue */
+	struct virt_queue	vqs[NUM_VIRT_QUEUES];
+	struct rng_dev_job	jobs[NUM_VIRT_QUEUES];
+};
+
+static LIST_HEAD(rdevs);
+static int compat_id = -1;
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+	/* Unused */
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+	/* Unused */
+	return 0;
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+	/* Unused */
+	return 0;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+	/* Unused */
+}
+
+static bool virtio_rng_do_io_request(struct kvm *kvm, struct rng_dev *rdev, struct virt_queue *queue)
+{
+	struct iovec iov[VIRTIO_RNG_QUEUE_SIZE];
+	unsigned int len = 0;
+	u16 out, in, head;
+
+	head	= virt_queue__get_iov(queue, iov, &out, &in, kvm);
+	len	= readv(rdev->fd, iov, in);
+
+	virt_queue__set_used_elem(queue, head, len);
+
+	return true;
+}
+
+static void virtio_rng_do_io(struct kvm *kvm, void *param)
+{
+	struct rng_dev_job *job	= param;
+	struct virt_queue *vq	= job->vq;
+	struct rng_dev *rdev	= job->rdev;
+
+	while (virt_queue__available(vq))
+		virtio_rng_do_io_request(kvm, rdev, vq);
+
+	rdev->vdev.ops->signal_vq(kvm, &rdev->vdev, vq - rdev->vqs);
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+	struct rng_dev *rdev = dev;
+	struct virt_queue *queue;
+	struct rng_dev_job *job;
+	void *p;
+
+	compat__remove_message(compat_id);
+
+	queue		= &rdev->vqs[vq];
+	queue->pfn	= pfn;
+	p		= guest_pfn_to_host(kvm, queue->pfn);
+
+	job = &rdev->jobs[vq];
+
+	vring_init(&queue->vring, VIRTIO_RNG_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
+
+	*job = (struct rng_dev_job) {
+		.vq	= queue,
+		.rdev	= rdev,
+	};
+
+	thread_pool__init_job(&job->job_id, kvm, virtio_rng_do_io, job);
+
+	return 0;
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct rng_dev *rdev = dev;
+
+	thread_pool__do_job(&rdev->jobs[vq].job_id);
+
+	return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	struct rng_dev *rdev = dev;
+
+	return rdev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+	return VIRTIO_RNG_QUEUE_SIZE;
+}
+
+static struct virtio_ops rng_dev_virtio_ops = (struct virtio_ops) {
+	.set_config		= set_config,
+	.get_config		= get_config,
+	.get_host_features	= get_host_features,
+	.set_guest_features	= set_guest_features,
+	.init_vq		= init_vq,
+	.notify_vq		= notify_vq,
+	.get_pfn_vq		= get_pfn_vq,
+	.get_size_vq		= get_size_vq,
+};
+
+int virtio_rng__init(struct kvm *kvm)
+{
+	struct rng_dev *rdev;
+	int r;
+
+	rdev = malloc(sizeof(*rdev));
+	if (rdev == NULL)
+		return -ENOMEM;
+
+	rdev->fd = open("/dev/urandom", O_RDONLY);
+	if (rdev->fd < 0) {
+		r = rdev->fd;
+		goto cleanup;
+	}
+
+	r = virtio_init(kvm, rdev, &rdev->vdev, &rng_dev_virtio_ops,
+			VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_RNG, VIRTIO_ID_RNG, PCI_CLASS_RNG);
+	if (r < 0)
+		goto cleanup;
+
+	list_add_tail(&rdev->list, &rdevs);
+
+	if (compat_id == -1)
+		compat_id = virtio_compat_add_message("virtio-rng", "CONFIG_HW_RANDOM_VIRTIO");
+	return 0;
+cleanup:
+	close(rdev->fd);
+	free(rdev);
+
+	return r;
+}
+
+int virtio_rng__exit(struct kvm *kvm)
+{
+	struct rng_dev *rdev, *tmp;
+
+	list_for_each_entry_safe(rdev, tmp, &rdevs, list) {
+		list_del(&rdev->list);
+		rdev->vdev.ops->exit(kvm, &rdev->vdev);
+		free(rdev);
+	}
+
+	return 0;
+}
diff --git a/tools/kvm/x86/bios.c b/tools/kvm/x86/bios.c
new file mode 100644
index 0000000..0f1bd85
--- /dev/null
+++ b/tools/kvm/x86/bios.c
@@ -0,0 +1,174 @@
+#include "kvm/kvm.h"
+#include "kvm/boot-protocol.h"
+#include "kvm/e820.h"
+#include "kvm/interrupt.h"
+#include "kvm/util.h"
+
+#include <string.h>
+#include <asm/e820.h>
+
+#include "bios/bios-rom.h"
+
+struct irq_handler {
+	unsigned long		address;
+	unsigned int		irq;
+	void			*handler;
+	size_t			size;
+};
+
+#define BIOS_IRQ_PA_ADDR(name)	(MB_BIOS_BEGIN + BIOS_OFFSET__##name)
+#define BIOS_IRQ_FUNC(name)	((char *)&bios_rom[BIOS_OFFSET__##name])
+#define BIOS_IRQ_SIZE(name)	(BIOS_ENTRY_SIZE(BIOS_OFFSET__##name))
+
+#define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler)			\
+	{							\
+		.irq		= _irq,				\
+		.address	= BIOS_IRQ_PA_ADDR(_handler),	\
+		.handler	= BIOS_IRQ_FUNC(_handler),	\
+		.size		= BIOS_IRQ_SIZE(_handler),	\
+	}
+
+static struct irq_handler bios_irq_handlers[] = {
+	DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10),
+	DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15),
+};
+
+static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler)
+{
+	struct real_intr_desc intr_desc;
+	void *p;
+
+	p = guest_flat_to_host(kvm, handler->address);
+	memcpy(p, handler->handler, handler->size);
+
+	intr_desc = (struct real_intr_desc) {
+		.segment	= REAL_SEGMENT(MB_BIOS_BEGIN),
+		.offset		= handler->address - MB_BIOS_BEGIN,
+	};
+
+	DIE_IF((handler->address - MB_BIOS_BEGIN) > 0xffffUL);
+
+	interrupt_table__set(&kvm->interrupt_table, &intr_desc, handler->irq);
+}
+
+/**
+ * e820_setup - setup some simple E820 memory map
+ * @kvm - guest system descriptor
+ */
+static void e820_setup(struct kvm *kvm)
+{
+	struct e820map *e820;
+	struct e820entry *mem_map;
+	unsigned int i = 0;
+
+	e820		= guest_flat_to_host(kvm, E820_MAP_START);
+	mem_map		= e820->map;
+
+	mem_map[i++]	= (struct e820entry) {
+		.addr		= REAL_MODE_IVT_BEGIN,
+		.size		= EBDA_START - REAL_MODE_IVT_BEGIN,
+		.type		= E820_RAM,
+	};
+	mem_map[i++]	= (struct e820entry) {
+		.addr		= EBDA_START,
+		.size		= VGA_RAM_BEGIN - EBDA_START,
+		.type		= E820_RESERVED,
+	};
+	mem_map[i++]	= (struct e820entry) {
+		.addr		= MB_BIOS_BEGIN,
+		.size		= MB_BIOS_END - MB_BIOS_BEGIN,
+		.type		= E820_RESERVED,
+	};
+	if (kvm->ram_size < KVM_32BIT_GAP_START) {
+		mem_map[i++]	= (struct e820entry) {
+			.addr		= BZ_KERNEL_START,
+			.size		= kvm->ram_size - BZ_KERNEL_START,
+			.type		= E820_RAM,
+		};
+	} else {
+		mem_map[i++]	= (struct e820entry) {
+			.addr		= BZ_KERNEL_START,
+			.size		= KVM_32BIT_GAP_START - BZ_KERNEL_START,
+			.type		= E820_RAM,
+		};
+		mem_map[i++]	= (struct e820entry) {
+			.addr		= KVM_32BIT_MAX_MEM_SIZE,
+			.size		= kvm->ram_size - KVM_32BIT_MAX_MEM_SIZE,
+			.type		= E820_RAM,
+		};
+	}
+
+	BUG_ON(i > E820_X_MAX);
+
+	e820->nr_map = i;
+}
+
+static void setup_vga_rom(struct kvm *kvm)
+{
+	u16 *mode;
+	void *p;
+
+	p = guest_flat_to_host(kvm, VGA_ROM_OEM_STRING);
+	memset(p, 0, VGA_ROM_OEM_STRING_SIZE);
+	strncpy(p, "KVM VESA", VGA_ROM_OEM_STRING_SIZE);
+
+	mode = guest_flat_to_host(kvm, VGA_ROM_MODES);
+	mode[0]	= 0x0112;
+	mode[1] = 0xffff;
+}
+
+/**
+ * setup_bios - inject BIOS into guest memory
+ * @kvm - guest system descriptor
+ */
+void setup_bios(struct kvm *kvm)
+{
+	unsigned long address = MB_BIOS_BEGIN;
+	struct real_intr_desc intr_desc;
+	unsigned int i;
+	void *p;
+
+	/*
+	 * before anything else -- clean some known areas
+	 * we definitely don't want any trash here
+	 */
+	p = guest_flat_to_host(kvm, BDA_START);
+	memset(p, 0, BDA_END - BDA_START);
+
+	p = guest_flat_to_host(kvm, EBDA_START);
+	memset(p, 0, EBDA_END - EBDA_START);
+
+	p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
+	memset(p, 0, MB_BIOS_END - MB_BIOS_BEGIN);
+
+	p = guest_flat_to_host(kvm, VGA_ROM_BEGIN);
+	memset(p, 0, VGA_ROM_END - VGA_ROM_BEGIN);
+
+	/* just copy the bios rom into the place */
+	p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
+	memcpy(p, bios_rom, bios_rom_size);
+
+	/* E820 memory map must be present */
+	e820_setup(kvm);
+
+	/* VESA needs own tricks */
+	setup_vga_rom(kvm);
+
+	/*
+	 * Setup a *fake* real mode vector table, it has only
+	 * one real handler which does just iret
+	 */
+	address = BIOS_IRQ_PA_ADDR(bios_intfake);
+	intr_desc = (struct real_intr_desc) {
+		.segment	= REAL_SEGMENT(MB_BIOS_BEGIN),
+		.offset		= address - MB_BIOS_BEGIN,
+	};
+	interrupt_table__setup(&kvm->interrupt_table, &intr_desc);
+
+	for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++)
+		setup_irq_handler(kvm, &bios_irq_handlers[i]);
+
+	/* we almost done */
+	p = guest_flat_to_host(kvm, 0);
+	interrupt_table__copy(&kvm->interrupt_table, p, REAL_INTR_SIZE);
+}
diff --git a/tools/kvm/x86/bios/.gitignore b/tools/kvm/x86/bios/.gitignore
new file mode 100644
index 0000000..1f0080b
--- /dev/null
+++ b/tools/kvm/x86/bios/.gitignore
@@ -0,0 +1,3 @@
+bios-rom.bin
+bios-rom.bin.elf
+bios-rom.h
diff --git a/tools/kvm/x86/bios/bios-rom.S b/tools/kvm/x86/bios/bios-rom.S
new file mode 100644
index 0000000..3269ce9
--- /dev/null
+++ b/tools/kvm/x86/bios/bios-rom.S
@@ -0,0 +1,12 @@
+#include <kvm/assembly.h>
+
+	.org 0
+#ifdef CONFIG_X86_64
+	.code64
+#else
+	.code32
+#endif
+
+GLOBAL(bios_rom)
+	.incbin "x86/bios/bios.bin"
+END(bios_rom)
diff --git a/tools/kvm/x86/bios/e820.c b/tools/kvm/x86/bios/e820.c
new file mode 100644
index 0000000..a9bca29
--- /dev/null
+++ b/tools/kvm/x86/bios/e820.c
@@ -0,0 +1,72 @@
+#include "kvm/e820.h"
+
+#include "kvm/segment.h"
+#include "kvm/bios.h"
+
+#include <asm/processor-flags.h>
+#include <asm/e820.h>
+
+static inline void set_fs(u16 seg)
+{
+	asm volatile("movw %0,%%fs" : : "rm" (seg));
+}
+
+static inline u8 rdfs8(unsigned long addr)
+{
+	u8 v;
+
+	asm volatile("addr32 movb %%fs:%1,%0" : "=q" (v) : "m" (*(u8 *)addr));
+
+	return v;
+}
+
+static inline u32 rdfs32(unsigned long addr)
+{
+	u32 v;
+
+	asm volatile("addr32 movl %%fs:%1,%0" : "=q" (v) : "m" (*(u32 *)addr));
+
+	return v;
+}
+
+bioscall void e820_query_map(struct biosregs *regs)
+{
+	struct e820map *e820;
+	u32 map_size;
+	u16 fs_seg;
+	u32 ndx;
+
+	e820		= (struct e820map *)E820_MAP_START;
+	fs_seg		= flat_to_seg16(E820_MAP_START);
+	set_fs(fs_seg);
+
+	ndx		= regs->ebx;
+
+	map_size	= rdfs32(flat_to_off16((u32)&e820->nr_map, fs_seg));
+
+	if (ndx < map_size) {
+		u32 start;
+		unsigned int i;
+		u8 *p;
+
+		fs_seg	= flat_to_seg16(E820_MAP_START);
+		set_fs(fs_seg);
+
+		start	= (u32)&e820->map[ndx];
+
+		p	= (void *) regs->edi;
+
+		for (i = 0; i < sizeof(struct e820entry); i++)
+			*p++	= rdfs8(flat_to_off16(start + i, fs_seg));
+	}
+
+	regs->eax	= SMAP;
+	regs->ecx	= sizeof(struct e820entry);
+	regs->ebx	= ++ndx;
+
+	/* Clear CF to indicate success.  */
+	regs->eflags	&= ~X86_EFLAGS_CF;
+
+	if (ndx >= map_size)
+		regs->ebx	= 0;	/* end of map */
+}
diff --git a/tools/kvm/x86/bios/entry.S b/tools/kvm/x86/bios/entry.S
new file mode 100644
index 0000000..85056e9
--- /dev/null
+++ b/tools/kvm/x86/bios/entry.S
@@ -0,0 +1,92 @@
+/*
+ * Our pretty trivial BIOS emulation
+ */
+
+#include <kvm/bios.h>
+#include <kvm/assembly.h>
+
+	.org 0
+	.code16gcc
+
+#define EFLAGS_CF	(1 << 0)
+
+#include "macro.S"
+
+/* If you change these macros, remember to update 'struct biosregs' */
+.macro SAVE_BIOSREGS
+	pushl	%fs
+	pushl	%es
+	pushl	%ds
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebp
+	pushl	%esp
+	pushl	%edx
+	pushl	%ecx
+	pushl	%ebx
+	pushl	%eax
+.endm
+
+.macro RESTORE_BIOSREGS
+	popl	%eax
+	popl	%ebx
+	popl	%ecx
+	popl	%edx
+	popl	%esp
+	popl	%ebp
+	popl	%esi
+	popl	%edi
+	popl	%ds
+	popl	%es
+	popl	%fs
+.endm
+
+/*
+ * fake interrupt handler, nothing can be faster ever
+ */
+ENTRY(bios_intfake)
+	/*
+	 * Set CF to indicate failure. We don't want callers to think that the
+	 * interrupt handler succeeded and then treat the return values in
+	 * registers as valid data.
+	 */
+	orl	$EFLAGS_CF, 0x4(%esp)
+
+	IRET
+ENTRY_END(bios_intfake)
+
+/*
+ * int 10 - video - service
+ */
+ENTRY(bios_int10)
+	SAVE_BIOSREGS
+
+	movl		%esp, %eax
+	/* this is way easier than doing it in assembly */
+	/* just push all the regs and jump to a C handler */
+	call	int10_handler
+
+	RESTORE_BIOSREGS
+
+	/* Clear CF to indicate success.  */
+	andl	$~EFLAGS_CF, 0x4(%esp)
+
+	IRET
+ENTRY_END(bios_int10)
+
+ENTRY(bios_int15)
+	SAVE_BIOSREGS
+
+	movl	%esp, %eax
+	call	int15_handler
+
+	RESTORE_BIOSREGS
+
+	IRET
+ENTRY_END(bios_int15)
+
+GLOBAL(__locals)
+
+#include "local.S"
+
+END(__locals)
diff --git a/tools/kvm/x86/bios/gen-offsets.sh b/tools/kvm/x86/bios/gen-offsets.sh
new file mode 100644
index 0000000..8771bbe
--- /dev/null
+++ b/tools/kvm/x86/bios/gen-offsets.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+echo "/* Autogenerated file, don't edit */"
+echo "#ifndef BIOS_OFFSETS_H"
+echo "#define BIOS_OFFSETS_H"
+
+echo ""
+echo "#define BIOS_ENTRY_SIZE(name) (name##_end - name)"
+echo ""
+
+nm bios.bin.elf | grep ' [Tt] ' | awk '{ print "#define BIOS_OFFSET__" $3 " 0x" $1; }'
+
+echo ""
+echo "#endif"
diff --git a/tools/kvm/x86/bios/int10.c b/tools/kvm/x86/bios/int10.c
new file mode 100644
index 0000000..7cc0b3f
--- /dev/null
+++ b/tools/kvm/x86/bios/int10.c
@@ -0,0 +1,110 @@
+#include "kvm/segment.h"
+#include "kvm/bios.h"
+#include "kvm/vesa.h"
+
+#include "bios/memcpy.h"
+
+#include <boot/vesa.h>
+
+static far_ptr gen_far_ptr(unsigned int pa)
+{
+	far_ptr ptr;
+
+	ptr.seg = (pa >> 4);
+	ptr.off = pa - (ptr.seg << 4);
+
+	return ptr;
+}
+
+static inline void outb(unsigned short port, unsigned char val)
+{
+	asm volatile("outb %0, %1" : : "a"(val), "Nd"(port));
+}
+
+/*
+ * It's probably much more useful to make this print to the serial
+ * line rather than print to a non-displayed VGA memory
+ */
+static inline void int10_putchar(struct biosregs *args)
+{
+	u8 al = args->eax & 0xFF;
+
+	outb(0x3f8, al);
+}
+
+static void vbe_get_mode(struct biosregs *args)
+{
+	struct vesa_mode_info *info = (struct vesa_mode_info *) args->edi;
+
+	*info = (struct vesa_mode_info) {
+		.mode_attr		= 0xd9, /* 11011011 */
+		.logical_scan		= VESA_WIDTH*4,
+		.h_res			= VESA_WIDTH,
+		.v_res			= VESA_HEIGHT,
+		.bpp			= VESA_BPP,
+		.memory_layout		= 6,
+		.memory_planes		= 1,
+		.lfb_ptr		= VESA_MEM_ADDR,
+		.rmask			= 8,
+		.gmask			= 8,
+		.bmask			= 8,
+		.resv_mask		= 8,
+		.resv_pos		= 24,
+		.bpos			= 16,
+		.gpos			= 8,
+	};
+}
+
+static void vbe_get_info(struct biosregs *args)
+{
+	struct vesa_general_info *infop = (struct vesa_general_info *) args->edi;
+	struct vesa_general_info info;
+
+	info = (struct vesa_general_info) {
+		.signature		= VESA_MAGIC,
+		.version		= 0x102,
+		.vendor_string		= gen_far_ptr(VGA_ROM_BEGIN),
+		.capabilities		= 0x10,
+		.video_mode_ptr		= gen_far_ptr(VGA_ROM_MODES),
+		.total_memory		= (4 * VESA_WIDTH * VESA_HEIGHT) / 0x10000,
+	};
+
+	memcpy16(args->es, infop, args->ds, &info, sizeof(info));
+}
+
+#define VBE_STATUS_OK		0x004F
+
+static void int10_vesa(struct biosregs *args)
+{
+	u8 al;
+
+	al = args->eax & 0xff;
+
+	switch (al) {
+	case 0x00:
+		vbe_get_info(args);
+		break;
+	case 0x01:
+		vbe_get_mode(args);
+		break;
+	}
+
+	args->eax = VBE_STATUS_OK;
+}
+
+bioscall void int10_handler(struct biosregs *args)
+{
+	u8 ah;
+
+	ah = (args->eax & 0xff00) >> 8;
+
+	switch (ah) {
+	case 0x0e:
+		int10_putchar(args);
+		break;
+	case 0x4f:
+		int10_vesa(args);
+		break;
+	}
+
+}
diff --git a/tools/kvm/x86/bios/int15.c b/tools/kvm/x86/bios/int15.c
new file mode 100644
index 0000000..faf5343
--- /dev/null
+++ b/tools/kvm/x86/bios/int15.c
@@ -0,0 +1,18 @@
+#include "kvm/bios.h"
+
+#include "kvm/e820.h"
+
+#include <asm/processor-flags.h>
+
+bioscall void int15_handler(struct biosregs *regs)
+{
+	switch (regs->eax) {
+	case 0xe820:
+		e820_query_map(regs);
+		break;
+	default:
+		/* Set CF to indicate failure.  */
+		regs->eflags	|= X86_EFLAGS_CF;
+		break;
+	}
+}
diff --git a/tools/kvm/x86/bios/local.S b/tools/kvm/x86/bios/local.S
new file mode 100644
index 0000000..f2cdbf4
--- /dev/null
+++ b/tools/kvm/x86/bios/local.S
@@ -0,0 +1,7 @@
+/*
+ * Local variables for almost every BIOS irq handler
+ * Must be put somewhere inside irq handler body
+ */
+__CALLER_SS:		.int  0
+__CALLER_SP:		.long 0
+__CALLER_CLOBBER:	.long 0
diff --git a/tools/kvm/x86/bios/macro.S b/tools/kvm/x86/bios/macro.S
new file mode 100644
index 0000000..0d5e567e
--- /dev/null
+++ b/tools/kvm/x86/bios/macro.S
@@ -0,0 +1,25 @@
+/*
+ * handy BIOS macros
+ */
+
+/*
+ * switch to BIOS stack
+ */
+.macro stack_swap
+	movw %ss, %cs:(__CALLER_SS)
+	movl %esp, %cs:(__CALLER_SP)
+	movl %edx, %cs:(__CALLER_CLOBBER)
+	movw $MB_BIOS_SS, %dx
+	movw %dx, %ss
+	movw $MB_BIOS_SP, %sp
+	movl %cs:(__CALLER_CLOBBER), %edx
+.endm
+
+/*
+ * restore the original stack
+ */
+.macro stack_restore
+	movl %cs:(__CALLER_SP), %esp
+	movw %cs:(__CALLER_SS), %ss
+.endm
+
diff --git a/tools/kvm/x86/bios/memcpy.c b/tools/kvm/x86/bios/memcpy.c
new file mode 100644
index 0000000..40b9b65
--- /dev/null
+++ b/tools/kvm/x86/bios/memcpy.c
@@ -0,0 +1,23 @@
+#include "bios/memcpy.h"
+
+/*
+ *  Copy memory area in 16-bit real mode.
+ */
+void memcpy16(u16 dst_seg, void *dst, u16 src_seg, const void *src, size_t len)
+{
+	__asm__ __volatile__ (
+		"pushw	%%ds				\n"
+		"pushw	%%es				\n"
+		"movw	%[src_seg], %%ds		\n"
+		"movw	%[dst_seg], %%es		\n"
+		"rep movsb %%ds:(%%si), %%es:(%%di)	\n"
+		"popw	%%es				\n"
+		"popw	%%ds				\n"
+		:
+		: "S"(src),
+		  "D"(dst),
+		  "c"(len),
+		  [src_seg] "r"(src_seg),
+		  [dst_seg] "r"(dst_seg)
+		: "cc", "memory");
+}
diff --git a/tools/kvm/x86/bios/rom.ld.S b/tools/kvm/x86/bios/rom.ld.S
new file mode 100644
index 0000000..f4f1835
--- /dev/null
+++ b/tools/kvm/x86/bios/rom.ld.S
@@ -0,0 +1,16 @@
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+	.text 0 : {
+		*(.text)
+	}
+
+	/DISCARD/ : {
+		*(.debug*)
+		*(.data)
+		*(.bss)
+		*(.eh_frame*)
+	}
+}
+
diff --git a/tools/kvm/x86/boot.c b/tools/kvm/x86/boot.c
new file mode 100644
index 0000000..93d9677
--- /dev/null
+++ b/tools/kvm/x86/boot.c
@@ -0,0 +1,41 @@
+#include "kvm/kvm.h"
+
+#include "kvm/util.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <fcntl.h>
+
+#define BIOS_SELECTOR	0xf000
+#define BIOS_IP		0xfff0
+#define BIOS_SP		0x8000
+
+bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
+{
+	struct stat st;
+	void *p;
+	int fd;
+	int nr;
+
+	fd = open(firmware_filename, O_RDONLY);
+	if (fd < 0)
+		return false;
+
+	if (fstat(fd, &st))
+		return false;
+
+	if (st.st_size > MB_FIRMWARE_BIOS_SIZE)
+		die("firmware image %s is too big to fit in memory (%Lu KB).\n", firmware_filename, (u64)(st.st_size / 1024));
+
+	p = guest_flat_to_host(kvm, MB_FIRMWARE_BIOS_BEGIN);
+
+	while ((nr = read(fd, p, st.st_size)) > 0)
+		p += nr;
+
+	kvm->boot_selector	= BIOS_SELECTOR;
+	kvm->boot_ip		= BIOS_IP;
+	kvm->boot_sp		= BIOS_SP;
+
+	return true;
+}
diff --git a/tools/kvm/x86/cpuid.c b/tools/kvm/x86/cpuid.c
new file mode 100644
index 0000000..4c140f0
--- /dev/null
+++ b/tools/kvm/x86/cpuid.c
@@ -0,0 +1,60 @@
+#include "kvm/kvm-cpu.h"
+
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+
+#include <sys/ioctl.h>
+#include <stdlib.h>
+
+#define CPUID_FUNC_PERFMON		0x0A
+
+#define	MAX_KVM_CPUID_ENTRIES		100
+
+static void filter_cpuid(struct kvm_cpuid2 *kvm_cpuid)
+{
+	unsigned int i;
+
+	/*
+	 * Filter CPUID functions that are not supported by the hypervisor.
+	 */
+	for (i = 0; i < kvm_cpuid->nent; i++) {
+		struct kvm_cpuid_entry2 *entry = &kvm_cpuid->entries[i];
+
+		switch (entry->function) {
+		case 1:
+			/* Set X86_FEATURE_HYPERVISOR */
+			if (entry->index == 0)
+				entry->ecx |= (1 << 31);
+			break;
+		case 6:
+			/* Clear X86_FEATURE_EPB */
+			entry->ecx = entry->ecx & ~(1 << 3);
+			break;
+		case CPUID_FUNC_PERFMON:
+			entry->eax = 0x00; /* disable it */
+			break;
+		default:
+			/* Keep the CPUID function as -is */
+			break;
+		};
+	}
+}
+
+void kvm_cpu__setup_cpuid(struct kvm_cpu *vcpu)
+{
+	struct kvm_cpuid2 *kvm_cpuid;
+
+	kvm_cpuid = calloc(1, sizeof(*kvm_cpuid) +
+				MAX_KVM_CPUID_ENTRIES * sizeof(*kvm_cpuid->entries));
+
+	kvm_cpuid->nent = MAX_KVM_CPUID_ENTRIES;
+	if (ioctl(vcpu->kvm->sys_fd, KVM_GET_SUPPORTED_CPUID, kvm_cpuid) < 0)
+		die_perror("KVM_GET_SUPPORTED_CPUID failed");
+
+	filter_cpuid(kvm_cpuid);
+
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_CPUID2, kvm_cpuid) < 0)
+		die_perror("KVM_SET_CPUID2 failed");
+
+	free(kvm_cpuid);
+}
diff --git a/tools/kvm/x86/include/kvm/assembly.h b/tools/kvm/x86/include/kvm/assembly.h
new file mode 100644
index 0000000..e70baab
--- /dev/null
+++ b/tools/kvm/x86/include/kvm/assembly.h
@@ -0,0 +1,24 @@
+#ifndef ASSEMBLY_H_
+#define ASSEMBLY_H_
+
+#define __ALIGN	.p2align 4, 0x90
+#define ENTRY(name)	\
+	__ALIGN;	\
+	.globl name;	\
+	name:
+
+#define GLOBAL(name)	\
+	.globl name;	\
+	name:
+
+#define ENTRY_END(name)	GLOBAL(name##_end)
+#define END(name)	GLOBAL(name##_end)
+
+/*
+ * gas produces size override prefix with which
+ * we are unhappy, lets make it hardcoded for
+ * 16 bit mode
+ */
+#define IRET	.byte 0xcf
+
+#endif /* ASSEMBLY_H_ */
diff --git a/tools/kvm/x86/include/kvm/barrier.h b/tools/kvm/x86/include/kvm/barrier.h
new file mode 100644
index 0000000..46d14f6
--- /dev/null
+++ b/tools/kvm/x86/include/kvm/barrier.h
@@ -0,0 +1,20 @@
+#ifndef _KVM_BARRIER_H_
+#define _KVM_BARRIER_H_
+
+#define barrier() asm volatile("": : :"memory")
+
+#define mb()	asm volatile ("mfence": : :"memory")
+#define rmb()	asm volatile ("lfence": : :"memory")
+#define wmb()	asm volatile ("sfence": : :"memory")
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#define smp_rmb()	rmb()
+#define smp_wmb()	wmb()
+#else
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#endif
+
+#endif /* _KVM_BARRIER_H_ */
diff --git a/tools/kvm/x86/include/kvm/bios-export.h b/tools/kvm/x86/include/kvm/bios-export.h
new file mode 100644
index 0000000..23825aa
--- /dev/null
+++ b/tools/kvm/x86/include/kvm/bios-export.h
@@ -0,0 +1,13 @@
+#ifndef BIOS_EXPORT_H_
+#define BIOS_EXPORT_H_
+
+struct kvm;
+
+extern char bios_rom[0];
+extern char bios_rom_end[0];
+
+#define bios_rom_size		(bios_rom_end - bios_rom)
+
+extern void setup_bios(struct kvm *kvm);
+
+#endif /* BIOS_EXPORT_H_ */
diff --git a/tools/kvm/x86/include/kvm/bios.h b/tools/kvm/x86/include/kvm/bios.h
new file mode 100644
index 0000000..ec7ed71
--- /dev/null
+++ b/tools/kvm/x86/include/kvm/bios.h
@@ -0,0 +1,93 @@
+#ifndef BIOS_H_
+#define BIOS_H_
+
+/*
+ * X86-32 Memory Map (typical)
+ *					start      end
+ * Real Mode Interrupt Vector Table	0x00000000 0x000003FF
+ * BDA area				0x00000400 0x000004FF
+ * Conventional Low Memory		0x00000500 0x0009FBFF
+ * EBDA area				0x0009FC00 0x0009FFFF
+ * VIDEO RAM				0x000A0000 0x000BFFFF
+ * VIDEO ROM (BIOS)			0x000C0000 0x000C7FFF
+ * ROMs & unus. space (mapped hw & misc)0x000C8000 0x000EFFFF 160 KiB (typically)
+ * Motherboard BIOS			0x000F0000 0x000FFFFF
+ * Extended Memory			0x00100000 0xFEBFFFFF
+ * Reserved (configs, ACPI, PnP, etc)	0xFEC00000 0xFFFFFFFF
+ */
+
+#define REAL_MODE_IVT_BEGIN		0x00000000
+#define REAL_MODE_IVT_END		0x000003ff
+
+#define BDA_START			0x00000400
+#define BDA_END				0x000004ff
+
+#define EBDA_START			0x0009fc00
+#define EBDA_END			0x0009ffff
+
+#define E820_MAP_START			EBDA_START
+
+#define MB_BIOS_BEGIN			0x000f0000
+#define MB_FIRMWARE_BIOS_BEGIN		0x000e0000
+#define MB_BIOS_END			0x000fffff
+
+#define MB_BIOS_SIZE			(MB_BIOS_END - MB_BIOS_BEGIN + 1)
+#define MB_FIRMWARE_BIOS_SIZE		(MB_BIOS_END - MB_FIRMWARE_BIOS_BEGIN + 1)
+
+#define VGA_RAM_BEGIN			0x000a0000
+#define VGA_RAM_END			0x000bffff
+
+#define VGA_ROM_BEGIN			0x000c0000
+#define VGA_ROM_OEM_STRING		VGA_ROM_BEGIN
+#define VGA_ROM_OEM_STRING_SIZE		16
+#define VGA_ROM_MODES			(VGA_ROM_OEM_STRING + VGA_ROM_OEM_STRING_SIZE)
+#define VGA_ROM_MODES_SIZE		32
+#define VGA_ROM_END			0x000c7fff
+
+/* we handle one page only */
+#define VGA_RAM_SEG			(VGA_RAM_BEGIN >> 4)
+#define VGA_PAGE_SIZE			0x007d0 /* 80x25 */
+
+/* real mode interrupt vector table */
+#define REAL_INTR_BASE			REAL_MODE_IVT_BEGIN
+#define REAL_INTR_VECTORS		256
+
+/*
+ * BIOS stack must be at absolute predefined memory address
+ * We reserve 64 bytes for BIOS stack
+ */
+#define MB_BIOS_SS			0xfff7
+#define MB_BIOS_SP			0x40
+
+/*
+ * When interfere with assembler code we need to be sure how
+ * arguments are passed in real mode.
+ */
+#define bioscall __attribute__((regparm(3)))
+
+#ifndef __ASSEMBLER__
+
+#include <linux/types.h>
+
+struct biosregs {
+	u32			eax;
+	u32			ebx;
+	u32			ecx;
+	u32			edx;
+	u32			esp;
+	u32			ebp;
+	u32			esi;
+	u32			edi;
+	u32			ds;
+	u32			es;
+	u32			fs;
+	u32			eip;
+	u32			eflags;
+};
+
+extern bioscall void int10_handler(struct biosregs *regs);
+extern bioscall void int15_handler(struct biosregs *regs);
+
+#endif
+
+#endif /* BIOS_H_ */
diff --git a/tools/kvm/x86/include/kvm/boot-protocol.h b/tools/kvm/x86/include/kvm/boot-protocol.h
new file mode 100644
index 0000000..85b637f
--- /dev/null
+++ b/tools/kvm/x86/include/kvm/boot-protocol.h
@@ -0,0 +1,16 @@
+/*
+ * Linux boot protocol specifics
+ */
+
+#ifndef BOOT_PROTOCOL_H_
+#define BOOT_PROTOCOL_H_
+
+/*
+ * The protected mode kernel part of a modern bzImage is loaded
+ * at 1 MB by default.
+ */
+#define BZ_DEFAULT_SETUP_SECTS		4
+#define BZ_KERNEL_START			0x100000UL
+#define INITRD_START			0x1000000UL
+
+#endif /* BOOT_PROTOCOL_H_ */
diff --git a/tools/kvm/x86/include/kvm/cpufeature.h b/tools/kvm/x86/include/kvm/cpufeature.h
new file mode 100644
index 0000000..bc4abbb
--- /dev/null
+++ b/tools/kvm/x86/include/kvm/cpufeature.h
@@ -0,0 +1,41 @@
+#ifndef KVM__CPUFEATURE_H
+#define KVM__CPUFEATURE_H
+
+#define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */
+#define CPUID_VENDOR_INTEL_2 0x49656e69 /* "ineI" */
+#define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
+
+#define CPUID_VENDOR_AMD_1   0x68747541 /* "Auth" */
+#define CPUID_VENDOR_AMD_2   0x69746e65 /* "enti" */
+#define CPUID_VENDOR_AMD_3   0x444d4163 /* "cAMD" */
+
+/*
+ * CPUID flags we need to deal with
+ */
+#define KVM__X86_FEATURE_VMX		5	/* Hardware virtualization */
+#define KVM__X86_FEATURE_SVM		2	/* Secure virtual machine */
+#define KVM__X86_FEATURE_XSAVE		26	/* XSAVE/XRSTOR/XSETBV/XGETBV */
+
+#define cpu_feature_disable(reg, feature)	\
+	((reg) & ~(1 << (feature)))
+#define cpu_feature_enable(reg, feature)	\
+	((reg) |  (1 << (feature)))
+
+struct cpuid_regs {
+	u32	eax;
+	u32	ebx;
+	u32	ecx;
+	u32	edx;
+};
+
+static inline void host_cpuid(struct cpuid_regs *regs)
+{
+	asm volatile("cpuid"
+		: "=a" (regs->eax),
+		  "=b" (regs->ebx),
+		  "=c" (regs->ecx),
+		  "=d" (regs->edx)
+		: "0" (regs->eax), "2" (regs->ecx));
+}
+
+#endif /* KVM__CPUFEATURE_H */
diff --git a/tools/kvm/x86/include/kvm/interrupt.h b/tools/kvm/x86/include/kvm/interrupt.h
new file mode 100644
index 0000000..00c7ed7
--- /dev/null
+++ b/tools/kvm/x86/include/kvm/interrupt.h
@@ -0,0 +1,26 @@
+#ifndef KVM__INTERRUPT_H
+#define KVM__INTERRUPT_H
+
+#include <linux/types.h>
+#include "kvm/bios.h"
+#include "kvm/bios-export.h"
+
+struct real_intr_desc {
+	u16 offset;
+	u16 segment;
+} __attribute__((packed));
+
+#define REAL_SEGMENT_SHIFT	4
+#define REAL_SEGMENT(addr)	((addr) >> REAL_SEGMENT_SHIFT)
+#define REAL_OFFSET(addr)	((addr) & ((1 << REAL_SEGMENT_SHIFT) - 1))
+#define REAL_INTR_SIZE		(REAL_INTR_VECTORS * sizeof(struct real_intr_desc))
+
+struct interrupt_table {
+	struct real_intr_desc entries[REAL_INTR_VECTORS];
+};
+
+void interrupt_table__copy(struct interrupt_table *itable, void *dst, unsigned int size);
+void interrupt_table__setup(struct interrupt_table *itable, struct real_intr_desc *entry);
+void interrupt_table__set(struct interrupt_table *itable, struct real_intr_desc *entry, unsigned int num);
+
+#endif /* KVM__INTERRUPT_H */
diff --git a/tools/kvm/x86/include/kvm/kvm-arch.h b/tools/kvm/x86/include/kvm/kvm-arch.h
new file mode 100644
index 0000000..551c8b4
--- /dev/null
+++ b/tools/kvm/x86/include/kvm/kvm-arch.h
@@ -0,0 +1,66 @@
+#ifndef KVM__KVM_ARCH_H
+#define KVM__KVM_ARCH_H
+
+#include "kvm/interrupt.h"
+#include "kvm/segment.h"
+
+#include <stdbool.h>
+#include <linux/types.h>
+#include <time.h>
+
+/*
+ * The hole includes VESA framebuffer and PCI memory.
+ */
+#define KVM_32BIT_MAX_MEM_SIZE  (1ULL << 32)
+#define KVM_32BIT_GAP_SIZE	(768 << 20)
+#define KVM_32BIT_GAP_START	(KVM_32BIT_MAX_MEM_SIZE - KVM_32BIT_GAP_SIZE)
+
+#define KVM_MMIO_START		KVM_32BIT_GAP_START
+
+/* This is the address that pci_get_io_space_block() starts allocating
+ * from.  Note that this is a PCI bus address (though same on x86).
+ */
+#define KVM_PCI_MMIO_AREA	(KVM_MMIO_START + 0x1000000)
+#define KVM_VIRTIO_MMIO_AREA	(KVM_MMIO_START + 0x2000000)
+
+struct kvm {
+	int			sys_fd;		/* For system ioctls(), i.e. /dev/kvm */
+	int			vm_fd;		/* For VM ioctls() */
+	timer_t			timerid;	/* Posix timer for interrupts */
+
+	int			nrcpus;		/* Number of cpus to run */
+
+	u32			mem_slots;	/* for KVM_SET_USER_MEMORY_REGION */
+
+	u64			ram_size;
+	void			*ram_start;
+
+	bool			nmi_disabled;
+
+	bool			single_step;
+
+	u16			boot_selector;
+	u16			boot_ip;
+	u16			boot_sp;
+
+	struct interrupt_table	interrupt_table;
+
+	const char		*vmlinux;
+	struct disk_image       **disks;
+	int                     nr_disks;
+
+	char			*name;
+
+	int			vm_state;
+};
+
+static inline void *guest_flat_to_host(struct kvm *kvm, unsigned long offset); /* In kvm.h */
+
+static inline void *guest_real_to_host(struct kvm *kvm, u16 selector, u16 offset)
+{
+	unsigned long flat = segment_to_flat(selector, offset);
+
+	return guest_flat_to_host(kvm, flat);
+}
+
+#endif /* KVM__KVM_ARCH_H */
diff --git a/tools/kvm/x86/include/kvm/kvm-cpu-arch.h b/tools/kvm/x86/include/kvm/kvm-cpu-arch.h
new file mode 100644
index 0000000..198efe6
--- /dev/null
+++ b/tools/kvm/x86/include/kvm/kvm-cpu-arch.h
@@ -0,0 +1,49 @@
+#ifndef KVM__KVM_CPU_ARCH_H
+#define KVM__KVM_CPU_ARCH_H
+
+/* Architecture-specific kvm_cpu definitions. */
+
+#include <linux/kvm.h>	/* for struct kvm_regs */
+#include "kvm/kvm.h"	/* for kvm__emulate_{mm}io() */
+#include <stdbool.h>
+#include <pthread.h>
+
+struct kvm;
+
+struct kvm_cpu {
+	pthread_t		thread;		/* VCPU thread */
+
+	unsigned long		cpu_id;
+
+	struct kvm		*kvm;		/* parent KVM */
+	int			vcpu_fd;	/* For VCPU ioctls() */
+	struct kvm_run		*kvm_run;
+
+	struct kvm_regs		regs;
+	struct kvm_sregs	sregs;
+	struct kvm_fpu		fpu;
+
+	struct kvm_msrs		*msrs;		/* dynamically allocated */
+
+	u8			is_running;
+	u8			paused;
+	u8			needs_nmi;
+
+	struct kvm_coalesced_mmio_ring	*ring;
+};
+
+/*
+ * As these are such simple wrappers, let's have them in the header so they'll
+ * be cheaper to call:
+ */
+static inline bool kvm_cpu__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count)
+{
+	return kvm__emulate_io(kvm, port, data, direction, size, count);
+}
+
+static inline bool kvm_cpu__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write)
+{
+	return kvm__emulate_mmio(kvm, phys_addr, data, len, is_write);
+}
+
+#endif /* KVM__KVM_CPU_ARCH_H */
diff --git a/tools/kvm/x86/include/kvm/mptable.h b/tools/kvm/x86/include/kvm/mptable.h
new file mode 100644
index 0000000..9e3cfa6
--- /dev/null
+++ b/tools/kvm/x86/include/kvm/mptable.h
@@ -0,0 +1,9 @@
+#ifndef KVM_MPTABLE_H_
+#define KVM_MPTABLE_H_
+
+struct kvm;
+
+int mptable__init(struct kvm *kvm);
+int mptable__exit(struct kvm *kvm);
+
+#endif /* KVM_MPTABLE_H_ */
diff --git a/tools/kvm/x86/interrupt.c b/tools/kvm/x86/interrupt.c
new file mode 100644
index 0000000..7d47869
--- /dev/null
+++ b/tools/kvm/x86/interrupt.c
@@ -0,0 +1,28 @@
+#include "kvm/interrupt.h"
+
+#include "kvm/util.h"
+
+#include <string.h>
+
+void interrupt_table__copy(struct interrupt_table *itable, void *dst, unsigned int size)
+{
+	if (size < sizeof(itable->entries))
+		die("An attempt to overwrite host memory");
+
+	memcpy(dst, itable->entries, sizeof(itable->entries));
+}
+
+void interrupt_table__setup(struct interrupt_table *itable, struct real_intr_desc *entry)
+{
+	unsigned int i;
+
+	for (i = 0; i < REAL_INTR_VECTORS; i++)
+		itable->entries[i] = *entry;
+}
+
+void interrupt_table__set(struct interrupt_table *itable,
+				struct real_intr_desc *entry, unsigned int num)
+{
+	if (num < REAL_INTR_VECTORS)
+		itable->entries[num] = *entry;
+}
diff --git a/tools/kvm/x86/ioport.c b/tools/kvm/x86/ioport.c
new file mode 100644
index 0000000..86302e6
--- /dev/null
+++ b/tools/kvm/x86/ioport.c
@@ -0,0 +1,77 @@
+#include "kvm/ioport.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+static bool debug_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	exit(EXIT_SUCCESS);
+}
+
+static struct ioport_operations debug_ops = {
+	.io_out		= debug_io_out,
+};
+
+static bool seabios_debug_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	char ch;
+
+	ch = ioport__read8(data);
+
+	putchar(ch);
+
+	return true;
+}
+
+static struct ioport_operations seabios_debug_ops = {
+	.io_out		= seabios_debug_io_out,
+};
+
+static bool dummy_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	return true;
+}
+
+static bool dummy_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+	return true;
+}
+
+static struct ioport_operations dummy_read_write_ioport_ops = {
+	.io_in		= dummy_io_in,
+	.io_out		= dummy_io_out,
+};
+
+static struct ioport_operations dummy_write_only_ioport_ops = {
+	.io_out		= dummy_io_out,
+};
+
+void ioport__setup_arch(void)
+{
+	/* Legacy ioport setup */
+
+	/* 0x0020 - 0x003F - 8259A PIC 1 */
+	ioport__register(0x0020, &dummy_read_write_ioport_ops, 2, NULL);
+
+	/* PORT 0040-005F - PIT - PROGRAMMABLE INTERVAL TIMER (8253, 8254) */
+	ioport__register(0x0040, &dummy_read_write_ioport_ops, 4, NULL);
+
+	/* 0x00A0 - 0x00AF - 8259A PIC 2 */
+	ioport__register(0x00A0, &dummy_read_write_ioport_ops, 2, NULL);
+
+	/* PORT 00E0-00EF are 'motherboard specific' so we use them for our
+	   internal debugging purposes.  */
+	ioport__register(IOPORT_DBG, &debug_ops, 1, NULL);
+
+	/* PORT 00ED - DUMMY PORT FOR DELAY??? */
+	ioport__register(0x00ED, &dummy_write_only_ioport_ops, 1, NULL);
+
+	/* 0x00F0 - 0x00FF - Math co-processor */
+	ioport__register(0x00F0, &dummy_write_only_ioport_ops, 2, NULL);
+
+	/* PORT 03D4-03D5 - COLOR VIDEO - CRT CONTROL REGISTERS */
+	ioport__register(0x03D4, &dummy_read_write_ioport_ops, 1, NULL);
+	ioport__register(0x03D5, &dummy_write_only_ioport_ops, 1, NULL);
+
+	ioport__register(0x402, &seabios_debug_ops, 1, NULL);
+}
diff --git a/tools/kvm/x86/irq.c b/tools/kvm/x86/irq.c
new file mode 100644
index 0000000..e83df99
--- /dev/null
+++ b/tools/kvm/x86/irq.c
@@ -0,0 +1,222 @@
+#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+
+#include <linux/types.h>
+#include <linux/rbtree.h>
+#include <linux/list.h>
+#include <linux/kvm.h>
+#include <sys/ioctl.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#define IRQ_MAX_GSI			64
+#define IRQCHIP_MASTER			0
+#define IRQCHIP_SLAVE			1
+#define IRQCHIP_IOAPIC			2
+
+static u8		next_line	= 5;
+static u8		next_dev	= 1;
+static struct rb_root	pci_tree	= RB_ROOT;
+
+/* First 24 GSIs are routed between IRQCHIPs and IOAPICs */
+static u32 gsi = 24;
+
+struct kvm_irq_routing *irq_routing;
+
+static int irq__add_routing(u32 gsi, u32 type, u32 irqchip, u32 pin)
+{
+	if (gsi >= IRQ_MAX_GSI)
+		return -ENOSPC;
+
+	irq_routing->entries[irq_routing->nr++] =
+		(struct kvm_irq_routing_entry) {
+			.gsi = gsi,
+			.type = type,
+			.u.irqchip.irqchip = irqchip,
+			.u.irqchip.pin = pin,
+		};
+
+	return 0;
+}
+
+static struct pci_dev *search(struct rb_root *root, u32 id)
+{
+	struct rb_node *node = root->rb_node;
+
+	while (node) {
+		struct pci_dev *data = rb_entry(node, struct pci_dev, node);
+		int result;
+
+		result = id - data->id;
+
+		if (result < 0)
+			node = node->rb_left;
+		else if (result > 0)
+			node = node->rb_right;
+		else
+			return data;
+	}
+	return NULL;
+}
+
+static int insert(struct rb_root *root, struct pci_dev *data)
+{
+	struct rb_node **new = &(root->rb_node), *parent = NULL;
+
+	/* Figure out where to put new node */
+	while (*new) {
+		struct pci_dev *this	= container_of(*new, struct pci_dev, node);
+		int result		= data->id - this->id;
+
+		parent = *new;
+		if (result < 0)
+			new = &((*new)->rb_left);
+		else if (result > 0)
+			new = &((*new)->rb_right);
+		else
+			return -EEXIST;
+	}
+
+	/* Add new node and rebalance tree. */
+	rb_link_node(&data->node, parent, new);
+	rb_insert_color(&data->node, root);
+
+	return 0;
+}
+
+int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line)
+{
+	struct pci_dev *node;
+	int r;
+
+	node = search(&pci_tree, dev);
+
+	if (!node) {
+		/* We haven't found a node - First device of it's kind */
+		node = malloc(sizeof(*node));
+		if (node == NULL)
+			return -ENOMEM;
+
+		*node = (struct pci_dev) {
+			.id	= dev,
+			/*
+			 * PCI supports only INTA#,B#,C#,D# per device.
+			 * A#,B#,C#,D# are allowed for multifunctional
+			 * devices so stick with A# for our single
+			 * function devices.
+			 */
+			.pin	= 1,
+		};
+
+		INIT_LIST_HEAD(&node->lines);
+
+		r = insert(&pci_tree, node);
+		if (r) {
+			free(node);
+			return r;
+		}
+	}
+
+	if (node) {
+		/* This device already has a pin assigned, give out a new line and device id */
+		struct irq_line *new = malloc(sizeof(*new));
+		if (new == NULL)
+			return -ENOMEM;
+
+		new->line	= next_line++;
+		*line		= new->line;
+		*pin		= node->pin;
+		*num		= next_dev++;
+
+		list_add(&new->node, &node->lines);
+
+		return 0;
+	}
+
+	return -EFAULT;
+}
+
+int irq__init(struct kvm *kvm)
+{
+	int i, r;
+
+	irq_routing = calloc(sizeof(struct kvm_irq_routing) +
+			IRQ_MAX_GSI * sizeof(struct kvm_irq_routing_entry), 1);
+	if (irq_routing == NULL)
+		return -ENOMEM;
+
+	/* Hook first 8 GSIs to master IRQCHIP */
+	for (i = 0; i < 8; i++)
+		if (i != 2)
+			irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_MASTER, i);
+
+	/* Hook next 8 GSIs to slave IRQCHIP */
+	for (i = 8; i < 16; i++)
+		irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_SLAVE, i - 8);
+
+	/* Last but not least, IOAPIC */
+	for (i = 0; i < 24; i++) {
+		if (i == 0)
+			irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_IOAPIC, 2);
+		else if (i != 2)
+			irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_IOAPIC, i);
+	}
+
+	r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
+	if (r) {
+		free(irq_routing);
+		return errno;
+	}
+
+	return 0;
+}
+
+int irq__exit(struct kvm *kvm)
+{
+	struct rb_node *ent;
+
+	free(irq_routing);
+
+	while ((ent = rb_first(&pci_tree))) {
+		struct pci_dev *dev;
+		struct irq_line *line;
+
+		dev = rb_entry(ent, struct pci_dev, node);
+		while (!list_empty(&dev->lines)) {
+			line = list_first_entry(&dev->lines, struct irq_line, node);
+			list_del(&line->node);
+			free(line);
+		}
+		rb_erase(&dev->node, &pci_tree);
+		free(dev);
+	}
+
+	return 0;
+}
+
+int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg)
+{
+	int r;
+
+	irq_routing->entries[irq_routing->nr++] =
+		(struct kvm_irq_routing_entry) {
+			.gsi = gsi,
+			.type = KVM_IRQ_ROUTING_MSI,
+			.u.msi.address_hi = msg->address_hi,
+			.u.msi.address_lo = msg->address_lo,
+			.u.msi.data = msg->data,
+		};
+
+	r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
+	if (r)
+		return r;
+
+	return gsi++;
+}
+
+struct rb_node *irq__get_pci_tree(void)
+{
+	return rb_first(&pci_tree);
+}
diff --git a/tools/kvm/x86/kvm-cpu.c b/tools/kvm/x86/kvm-cpu.c
new file mode 100644
index 0000000..2b3d973
--- /dev/null
+++ b/tools/kvm/x86/kvm-cpu.c
@@ -0,0 +1,425 @@
+#include "kvm/kvm-cpu.h"
+
+#include "kvm/symbol.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+
+#include <asm/msr-index.h>
+#include <asm/apicdef.h>
+#include <linux/err.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+static int debug_fd;
+
+void kvm_cpu__set_debug_fd(int fd)
+{
+	debug_fd = fd;
+}
+
+int kvm_cpu__get_debug_fd(void)
+{
+	return debug_fd;
+}
+
+static inline bool is_in_protected_mode(struct kvm_cpu *vcpu)
+{
+	return vcpu->sregs.cr0 & 0x01;
+}
+
+static inline u64 ip_to_flat(struct kvm_cpu *vcpu, u64 ip)
+{
+	u64 cs;
+
+	/*
+	 * NOTE! We should take code segment base address into account here.
+	 * Luckily it's usually zero because Linux uses flat memory model.
+	 */
+	if (is_in_protected_mode(vcpu))
+		return ip;
+
+	cs = vcpu->sregs.cs.selector;
+
+	return ip + (cs << 4);
+}
+
+static inline u32 selector_to_base(u16 selector)
+{
+	/*
+	 * KVM on Intel requires 'base' to be 'selector * 16' in real mode.
+	 */
+	return (u32)selector << 4;
+}
+
+static struct kvm_cpu *kvm_cpu__new(struct kvm *kvm)
+{
+	struct kvm_cpu *vcpu;
+
+	vcpu = calloc(1, sizeof(*vcpu));
+	if (!vcpu)
+		return NULL;
+
+	vcpu->kvm = kvm;
+
+	return vcpu;
+}
+
+void kvm_cpu__delete(struct kvm_cpu *vcpu)
+{
+	if (vcpu->msrs)
+		free(vcpu->msrs);
+
+	free(vcpu);
+}
+
+static int kvm_cpu__set_lint(struct kvm_cpu *vcpu)
+{
+	struct local_apic lapic;
+
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_LAPIC, &lapic))
+		return -1;
+
+	lapic.lvt_lint0.delivery_mode = APIC_MODE_EXTINT;
+	lapic.lvt_lint1.delivery_mode = APIC_MODE_NMI;
+
+	return ioctl(vcpu->vcpu_fd, KVM_SET_LAPIC, &lapic);
+}
+
+struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id)
+{
+	struct kvm_cpu *vcpu;
+	int mmap_size;
+	int coalesced_offset;
+
+	vcpu = kvm_cpu__new(kvm);
+	if (!vcpu)
+		return NULL;
+
+	vcpu->cpu_id = cpu_id;
+
+	vcpu->vcpu_fd = ioctl(vcpu->kvm->vm_fd, KVM_CREATE_VCPU, cpu_id);
+	if (vcpu->vcpu_fd < 0)
+		die_perror("KVM_CREATE_VCPU ioctl");
+
+	mmap_size = ioctl(vcpu->kvm->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
+	if (mmap_size < 0)
+		die_perror("KVM_GET_VCPU_MMAP_SIZE ioctl");
+
+	vcpu->kvm_run = mmap(NULL, mmap_size, PROT_RW, MAP_SHARED, vcpu->vcpu_fd, 0);
+	if (vcpu->kvm_run == MAP_FAILED)
+		die("unable to mmap vcpu fd");
+
+	coalesced_offset = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_COALESCED_MMIO);
+	if (coalesced_offset)
+		vcpu->ring = (void *)vcpu->kvm_run + (coalesced_offset * PAGE_SIZE);
+
+	if (kvm_cpu__set_lint(vcpu))
+		die_perror("KVM_SET_LAPIC failed");
+
+	vcpu->is_running = true;
+
+	return vcpu;
+}
+
+static struct kvm_msrs *kvm_msrs__new(size_t nmsrs)
+{
+	struct kvm_msrs *vcpu = calloc(1, sizeof(*vcpu) + (sizeof(struct kvm_msr_entry) * nmsrs));
+
+	if (!vcpu)
+		die("out of memory");
+
+	return vcpu;
+}
+
+#define KVM_MSR_ENTRY(_index, _data)	\
+	(struct kvm_msr_entry) { .index = _index, .data = _data }
+
+static void kvm_cpu__setup_msrs(struct kvm_cpu *vcpu)
+{
+	unsigned long ndx = 0;
+
+	vcpu->msrs = kvm_msrs__new(100);
+
+	vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_IA32_SYSENTER_CS,	0x0);
+	vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_IA32_SYSENTER_ESP,	0x0);
+	vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_IA32_SYSENTER_EIP,	0x0);
+#ifdef CONFIG_X86_64
+	vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_STAR,			0x0);
+	vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_CSTAR,			0x0);
+	vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_KERNEL_GS_BASE,		0x0);
+	vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_SYSCALL_MASK,		0x0);
+	vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_LSTAR,			0x0);
+#endif
+	vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_IA32_TSC,		0x0);
+	vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_IA32_MISC_ENABLE,
+						MSR_IA32_MISC_ENABLE_FAST_STRING);
+
+	vcpu->msrs->nmsrs = ndx;
+
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_MSRS, vcpu->msrs) < 0)
+		die_perror("KVM_SET_MSRS failed");
+}
+
+static void kvm_cpu__setup_fpu(struct kvm_cpu *vcpu)
+{
+	vcpu->fpu = (struct kvm_fpu) {
+		.fcw	= 0x37f,
+		.mxcsr	= 0x1f80,
+	};
+
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_FPU, &vcpu->fpu) < 0)
+		die_perror("KVM_SET_FPU failed");
+}
+
+static void kvm_cpu__setup_regs(struct kvm_cpu *vcpu)
+{
+	vcpu->regs = (struct kvm_regs) {
+		/* We start the guest in 16-bit real mode  */
+		.rflags	= 0x0000000000000002ULL,
+
+		.rip	= vcpu->kvm->boot_ip,
+		.rsp	= vcpu->kvm->boot_sp,
+		.rbp	= vcpu->kvm->boot_sp,
+	};
+
+	if (vcpu->regs.rip > USHRT_MAX)
+		die("ip 0x%llx is too high for real mode", (u64)vcpu->regs.rip);
+
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_REGS, &vcpu->regs) < 0)
+		die_perror("KVM_SET_REGS failed");
+}
+
+static void kvm_cpu__setup_sregs(struct kvm_cpu *vcpu)
+{
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &vcpu->sregs) < 0)
+		die_perror("KVM_GET_SREGS failed");
+
+	vcpu->sregs.cs.selector	= vcpu->kvm->boot_selector;
+	vcpu->sregs.cs.base	= selector_to_base(vcpu->kvm->boot_selector);
+	vcpu->sregs.ss.selector	= vcpu->kvm->boot_selector;
+	vcpu->sregs.ss.base	= selector_to_base(vcpu->kvm->boot_selector);
+	vcpu->sregs.ds.selector	= vcpu->kvm->boot_selector;
+	vcpu->sregs.ds.base	= selector_to_base(vcpu->kvm->boot_selector);
+	vcpu->sregs.es.selector	= vcpu->kvm->boot_selector;
+	vcpu->sregs.es.base	= selector_to_base(vcpu->kvm->boot_selector);
+	vcpu->sregs.fs.selector	= vcpu->kvm->boot_selector;
+	vcpu->sregs.fs.base	= selector_to_base(vcpu->kvm->boot_selector);
+	vcpu->sregs.gs.selector	= vcpu->kvm->boot_selector;
+	vcpu->sregs.gs.base	= selector_to_base(vcpu->kvm->boot_selector);
+
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_SREGS, &vcpu->sregs) < 0)
+		die_perror("KVM_SET_SREGS failed");
+}
+
+/**
+ * kvm_cpu__reset_vcpu - reset virtual CPU to a known state
+ */
+void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu)
+{
+	kvm_cpu__setup_cpuid(vcpu);
+	kvm_cpu__setup_sregs(vcpu);
+	kvm_cpu__setup_regs(vcpu);
+	kvm_cpu__setup_fpu(vcpu);
+	kvm_cpu__setup_msrs(vcpu);
+}
+
+bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
+{
+	return false;
+}
+
+static void print_dtable(const char *name, struct kvm_dtable *dtable)
+{
+	dprintf(debug_fd, " %s                 %016llx  %08hx\n",
+		name, (u64) dtable->base, (u16) dtable->limit);
+}
+
+static void print_segment(const char *name, struct kvm_segment *seg)
+{
+	dprintf(debug_fd, " %s       %04hx      %016llx  %08x  %02hhx    %x %x   %x  %x %x %x %x\n",
+		name, (u16) seg->selector, (u64) seg->base, (u32) seg->limit,
+		(u8) seg->type, seg->present, seg->dpl, seg->db, seg->s, seg->l, seg->g, seg->avl);
+}
+
+void kvm_cpu__show_registers(struct kvm_cpu *vcpu)
+{
+	unsigned long cr0, cr2, cr3;
+	unsigned long cr4, cr8;
+	unsigned long rax, rbx, rcx;
+	unsigned long rdx, rsi, rdi;
+	unsigned long rbp,  r8,  r9;
+	unsigned long r10, r11, r12;
+	unsigned long r13, r14, r15;
+	unsigned long rip, rsp;
+	struct kvm_sregs sregs;
+	unsigned long rflags;
+	struct kvm_regs regs;
+	int i;
+
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_REGS, &regs) < 0)
+		die("KVM_GET_REGS failed");
+
+	rflags = regs.rflags;
+
+	rip = regs.rip; rsp = regs.rsp;
+	rax = regs.rax; rbx = regs.rbx; rcx = regs.rcx;
+	rdx = regs.rdx; rsi = regs.rsi; rdi = regs.rdi;
+	rbp = regs.rbp; r8  = regs.r8;  r9  = regs.r9;
+	r10 = regs.r10; r11 = regs.r11; r12 = regs.r12;
+	r13 = regs.r13; r14 = regs.r14; r15 = regs.r15;
+
+	dprintf(debug_fd, "\n Registers:\n");
+	dprintf(debug_fd,   " ----------\n");
+	dprintf(debug_fd, " rip: %016lx   rsp: %016lx flags: %016lx\n", rip, rsp, rflags);
+	dprintf(debug_fd, " rax: %016lx   rbx: %016lx   rcx: %016lx\n", rax, rbx, rcx);
+	dprintf(debug_fd, " rdx: %016lx   rsi: %016lx   rdi: %016lx\n", rdx, rsi, rdi);
+	dprintf(debug_fd, " rbp: %016lx    r8: %016lx    r9: %016lx\n", rbp, r8,  r9);
+	dprintf(debug_fd, " r10: %016lx   r11: %016lx   r12: %016lx\n", r10, r11, r12);
+	dprintf(debug_fd, " r13: %016lx   r14: %016lx   r15: %016lx\n", r13, r14, r15);
+
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &sregs) < 0)
+		die("KVM_GET_REGS failed");
+
+	cr0 = sregs.cr0; cr2 = sregs.cr2; cr3 = sregs.cr3;
+	cr4 = sregs.cr4; cr8 = sregs.cr8;
+
+	dprintf(debug_fd, " cr0: %016lx   cr2: %016lx   cr3: %016lx\n", cr0, cr2, cr3);
+	dprintf(debug_fd, " cr4: %016lx   cr8: %016lx\n", cr4, cr8);
+	dprintf(debug_fd, "\n Segment registers:\n");
+	dprintf(debug_fd,   " ------------------\n");
+	dprintf(debug_fd, " register  selector  base              limit     type  p dpl db s l g avl\n");
+	print_segment("cs ", &sregs.cs);
+	print_segment("ss ", &sregs.ss);
+	print_segment("ds ", &sregs.ds);
+	print_segment("es ", &sregs.es);
+	print_segment("fs ", &sregs.fs);
+	print_segment("gs ", &sregs.gs);
+	print_segment("tr ", &sregs.tr);
+	print_segment("ldt", &sregs.ldt);
+	print_dtable("gdt", &sregs.gdt);
+	print_dtable("idt", &sregs.idt);
+
+	dprintf(debug_fd, "\n APIC:\n");
+	dprintf(debug_fd,   " -----\n");
+	dprintf(debug_fd, " efer: %016llx  apic base: %016llx  nmi: %s\n",
+		(u64) sregs.efer, (u64) sregs.apic_base,
+		(vcpu->kvm->nmi_disabled ? "disabled" : "enabled"));
+
+	dprintf(debug_fd, "\n Interrupt bitmap:\n");
+	dprintf(debug_fd,   " -----------------\n");
+	for (i = 0; i < (KVM_NR_INTERRUPTS + 63) / 64; i++)
+		dprintf(debug_fd, " %016llx", (u64) sregs.interrupt_bitmap[i]);
+	dprintf(debug_fd, "\n");
+}
+
+#define MAX_SYM_LEN 128
+
+void kvm_cpu__show_code(struct kvm_cpu *vcpu)
+{
+	unsigned int code_bytes = 64;
+	unsigned int code_prologue = 43;
+	unsigned int code_len = code_bytes;
+	char sym[MAX_SYM_LEN] = SYMBOL_DEFAULT_UNKNOWN, *psym;
+	unsigned char c;
+	unsigned int i;
+	u8 *ip;
+
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_REGS, &vcpu->regs) < 0)
+		die("KVM_GET_REGS failed");
+
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &vcpu->sregs) < 0)
+		die("KVM_GET_SREGS failed");
+
+	ip = guest_flat_to_host(vcpu->kvm, ip_to_flat(vcpu, vcpu->regs.rip) - code_prologue);
+
+	dprintf(debug_fd, "\n Code:\n");
+	dprintf(debug_fd,   " -----\n");
+
+	psym = symbol_lookup(vcpu->kvm, vcpu->regs.rip, sym, MAX_SYM_LEN);
+	if (IS_ERR(psym))
+		dprintf(debug_fd,
+			"Warning: symbol_lookup() failed to find symbol "
+			"with error: %ld\n", PTR_ERR(psym));
+
+	dprintf(debug_fd, " rip: [<%016lx>] %s\n\n", (unsigned long) vcpu->regs.rip, sym);
+
+	for (i = 0; i < code_len; i++, ip++) {
+		if (!host_ptr_in_ram(vcpu->kvm, ip))
+			break;
+
+		c = *ip;
+
+		if (ip == guest_flat_to_host(vcpu->kvm, ip_to_flat(vcpu, vcpu->regs.rip)))
+			dprintf(debug_fd, " <%02x>", c);
+		else
+			dprintf(debug_fd, " %02x", c);
+	}
+
+	dprintf(debug_fd, "\n");
+
+	dprintf(debug_fd, "\n Stack:\n");
+	dprintf(debug_fd,   " ------\n");
+	kvm__dump_mem(vcpu->kvm, vcpu->regs.rsp, 32);
+}
+
+void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
+{
+	u64 *pte1;
+	u64 *pte2;
+	u64 *pte3;
+	u64 *pte4;
+
+	if (!is_in_protected_mode(vcpu))
+		return;
+
+	if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &vcpu->sregs) < 0)
+		die("KVM_GET_SREGS failed");
+
+	pte4 = guest_flat_to_host(vcpu->kvm, vcpu->sregs.cr3);
+	if (!host_ptr_in_ram(vcpu->kvm, pte4))
+		return;
+
+	pte3 = guest_flat_to_host(vcpu->kvm, (*pte4 & ~0xfff));
+	if (!host_ptr_in_ram(vcpu->kvm, pte3))
+		return;
+
+	pte2 = guest_flat_to_host(vcpu->kvm, (*pte3 & ~0xfff));
+	if (!host_ptr_in_ram(vcpu->kvm, pte2))
+		return;
+
+	pte1 = guest_flat_to_host(vcpu->kvm, (*pte2 & ~0xfff));
+	if (!host_ptr_in_ram(vcpu->kvm, pte1))
+		return;
+
+	dprintf(debug_fd, "Page Tables:\n");
+	if (*pte2 & (1 << 7))
+		dprintf(debug_fd, " pte4: %016llx   pte3: %016llx"
+			"   pte2: %016llx\n",
+			*pte4, *pte3, *pte2);
+	else
+		dprintf(debug_fd, " pte4: %016llx  pte3: %016llx   pte2: %016"
+			"llx   pte1: %016llx\n",
+			*pte4, *pte3, *pte2, *pte1);
+}
+
+void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
+{
+	struct kvm_lapic_state klapic;
+	struct local_apic *lapic = (void *)&klapic;
+
+	if (ioctl(cpu->vcpu_fd, KVM_GET_LAPIC, &klapic) != 0)
+		return;
+
+	if (lapic->lvt_lint1.mask)
+		return;
+
+	if (lapic->lvt_lint1.delivery_mode != APIC_MODE_NMI)
+		return;
+
+	ioctl(cpu->vcpu_fd, KVM_NMI);
+}
diff --git a/tools/kvm/x86/kvm.c b/tools/kvm/x86/kvm.c
new file mode 100644
index 0000000..10a1212
--- /dev/null
+++ b/tools/kvm/x86/kvm.c
@@ -0,0 +1,385 @@
+#include "kvm/kvm.h"
+#include "kvm/boot-protocol.h"
+#include "kvm/cpufeature.h"
+#include "kvm/interrupt.h"
+#include "kvm/mptable.h"
+#include "kvm/util.h"
+#include "kvm/8250-serial.h"
+#include "kvm/virtio-console.h"
+
+#include <asm/bootparam.h>
+#include <linux/kvm.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+struct kvm_ext kvm_req_ext[] = {
+	{ DEFINE_KVM_EXT(KVM_CAP_COALESCED_MMIO) },
+	{ DEFINE_KVM_EXT(KVM_CAP_SET_TSS_ADDR) },
+	{ DEFINE_KVM_EXT(KVM_CAP_PIT2) },
+	{ DEFINE_KVM_EXT(KVM_CAP_USER_MEMORY) },
+	{ DEFINE_KVM_EXT(KVM_CAP_IRQ_ROUTING) },
+	{ DEFINE_KVM_EXT(KVM_CAP_IRQCHIP) },
+	{ DEFINE_KVM_EXT(KVM_CAP_HLT) },
+	{ DEFINE_KVM_EXT(KVM_CAP_IRQ_INJECT_STATUS) },
+	{ DEFINE_KVM_EXT(KVM_CAP_EXT_CPUID) },
+	{ 0, 0 }
+};
+
+bool kvm__arch_cpu_supports_vm(void)
+{
+	struct cpuid_regs regs;
+	u32 eax_base;
+	int feature;
+
+	regs	= (struct cpuid_regs) {
+		.eax		= 0x00,
+	};
+	host_cpuid(&regs);
+
+	switch (regs.ebx) {
+	case CPUID_VENDOR_INTEL_1:
+		eax_base	= 0x00;
+		feature		= KVM__X86_FEATURE_VMX;
+		break;
+
+	case CPUID_VENDOR_AMD_1:
+		eax_base	= 0x80000000;
+		feature		= KVM__X86_FEATURE_SVM;
+		break;
+
+	default:
+		return false;
+	}
+
+	regs	= (struct cpuid_regs) {
+		.eax		= eax_base,
+	};
+	host_cpuid(&regs);
+
+	if (regs.eax < eax_base + 0x01)
+		return false;
+
+	regs	= (struct cpuid_regs) {
+		.eax		= eax_base + 0x01
+	};
+	host_cpuid(&regs);
+
+	return regs.ecx & (1 << feature);
+}
+
+/*
+ * Allocating RAM size bigger than 4GB requires us to leave a gap
+ * in the RAM which is used for PCI MMIO, hotplug, and unconfigured
+ * devices (see documentation of e820_setup_gap() for details).
+ *
+ * If we're required to initialize RAM bigger than 4GB, we will create
+ * a gap between 0xe0000000 and 0x100000000 in the guest virtual mem space.
+ */
+
+void kvm__init_ram(struct kvm *kvm)
+{
+	u64	phys_start, phys_size;
+	void	*host_mem;
+
+	if (kvm->ram_size < KVM_32BIT_GAP_START) {
+		/* Use a single block of RAM for 32bit RAM */
+
+		phys_start = 0;
+		phys_size  = kvm->ram_size;
+		host_mem   = kvm->ram_start;
+
+		kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+	} else {
+		/* First RAM range from zero to the PCI gap: */
+
+		phys_start = 0;
+		phys_size  = KVM_32BIT_GAP_START;
+		host_mem   = kvm->ram_start;
+
+		kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+
+		/* Second RAM range from 4GB to the end of RAM: */
+
+		phys_start = KVM_32BIT_MAX_MEM_SIZE;
+		phys_size  = kvm->ram_size - phys_start;
+		host_mem   = kvm->ram_start + phys_start;
+
+		kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+	}
+}
+
+/* Arch-specific commandline setup */
+void kvm__arch_set_cmdline(char *cmdline, bool video)
+{
+	strcpy(cmdline, "noapic noacpi pci=conf1 reboot=k panic=1 i8042.direct=1 "
+				"i8042.dumbkbd=1 i8042.nopnp=1");
+	if (video)
+		strcat(cmdline, " video=vesafb console=tty0");
+	else
+		strcat(cmdline, " console=ttyS0 earlyprintk=serial i8042.noaux=1");
+}
+
+/* This function wraps the decision between hugetlbfs map (if requested) or normal mmap */
+static void *mmap_anon_or_hugetlbfs(const char *hugetlbfs_path, u64 size)
+{
+	if (hugetlbfs_path)
+		/*
+		 * We don't /need/ to map guest RAM from hugetlbfs, but we do so
+		 * if the user specifies a hugetlbfs path.
+		 */
+		return mmap_hugetlbfs(hugetlbfs_path, size);
+	else
+		return mmap(NULL, size, PROT_RW, MAP_ANON_NORESERVE, -1, 0);
+}
+
+/* Architecture-specific KVM init */
+void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size)
+{
+	struct kvm_pit_config pit_config = { .flags = 0, };
+	int ret;
+
+	ret = ioctl(kvm->vm_fd, KVM_SET_TSS_ADDR, 0xfffbd000);
+	if (ret < 0)
+		die_perror("KVM_SET_TSS_ADDR ioctl");
+
+	ret = ioctl(kvm->vm_fd, KVM_CREATE_PIT2, &pit_config);
+	if (ret < 0)
+		die_perror("KVM_CREATE_PIT2 ioctl");
+
+	if (ram_size < KVM_32BIT_GAP_START) {
+		kvm->ram_size = ram_size;
+		kvm->ram_start = mmap_anon_or_hugetlbfs(hugetlbfs_path, ram_size);
+	} else {
+		kvm->ram_start = mmap_anon_or_hugetlbfs(hugetlbfs_path, ram_size + KVM_32BIT_GAP_SIZE);
+		kvm->ram_size = ram_size + KVM_32BIT_GAP_SIZE;
+		if (kvm->ram_start != MAP_FAILED)
+			/*
+			 * We mprotect the gap (see kvm__init_ram() for details) PROT_NONE so that
+			 * if we accidently write to it, we will know.
+			 */
+			mprotect(kvm->ram_start + KVM_32BIT_GAP_START, KVM_32BIT_GAP_SIZE, PROT_NONE);
+	}
+	if (kvm->ram_start == MAP_FAILED)
+		die("out of memory");
+
+	madvise(kvm->ram_start, kvm->ram_size, MADV_MERGEABLE);
+
+	ret = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP);
+	if (ret < 0)
+		die_perror("KVM_CREATE_IRQCHIP ioctl");
+}
+
+void kvm__arch_delete_ram(struct kvm *kvm)
+{
+	munmap(kvm->ram_start, kvm->ram_size);
+}
+
+void kvm__irq_line(struct kvm *kvm, int irq, int level)
+{
+	struct kvm_irq_level irq_level;
+
+	irq_level	= (struct kvm_irq_level) {
+		{
+			.irq		= irq,
+		},
+		.level		= level,
+	};
+
+	if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
+		die_perror("KVM_IRQ_LINE failed");
+}
+
+void kvm__irq_trigger(struct kvm *kvm, int irq)
+{
+	kvm__irq_line(kvm, irq, 1);
+	kvm__irq_line(kvm, irq, 0);
+}
+
+#define BOOT_LOADER_SELECTOR	0x1000
+#define BOOT_LOADER_IP		0x0000
+#define BOOT_LOADER_SP		0x8000
+#define BOOT_CMDLINE_OFFSET	0x20000
+
+#define BOOT_PROTOCOL_REQUIRED	0x206
+#define LOAD_HIGH		0x01
+
+int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline)
+{
+	void *p;
+	int nr;
+
+	/*
+	 * Some architectures may support loading an initrd alongside the flat kernel,
+	 * but we do not.
+	 */
+	if (fd_initrd != -1)
+		pr_warning("Loading initrd with flat binary not supported.");
+
+	if (lseek(fd_kernel, 0, SEEK_SET) < 0)
+		die_perror("lseek");
+
+	p = guest_real_to_host(kvm, BOOT_LOADER_SELECTOR, BOOT_LOADER_IP);
+
+	while ((nr = read(fd_kernel, p, 65536)) > 0)
+		p += nr;
+
+	kvm->boot_selector	= BOOT_LOADER_SELECTOR;
+	kvm->boot_ip		= BOOT_LOADER_IP;
+	kvm->boot_sp		= BOOT_LOADER_SP;
+
+	return true;
+}
+
+static const char *BZIMAGE_MAGIC = "HdrS";
+
+bool load_bzimage(struct kvm *kvm, int fd_kernel,
+		  int fd_initrd, const char *kernel_cmdline, u16 vidmode)
+{
+	struct boot_params *kern_boot;
+	unsigned long setup_sects;
+	struct boot_params boot;
+	size_t cmdline_size;
+	ssize_t setup_size;
+	void *p;
+	int nr;
+
+	/*
+	 * See Documentation/x86/boot.txt for details no bzImage on-disk and
+	 * memory layout.
+	 */
+
+	if (lseek(fd_kernel, 0, SEEK_SET) < 0)
+		die_perror("lseek");
+
+	if (read(fd_kernel, &boot, sizeof(boot)) != sizeof(boot))
+		return false;
+
+	if (memcmp(&boot.hdr.header, BZIMAGE_MAGIC, strlen(BZIMAGE_MAGIC)))
+		return false;
+
+	if (boot.hdr.version < BOOT_PROTOCOL_REQUIRED)
+		die("Too old kernel");
+
+	if (lseek(fd_kernel, 0, SEEK_SET) < 0)
+		die_perror("lseek");
+
+	if (!boot.hdr.setup_sects)
+		boot.hdr.setup_sects = BZ_DEFAULT_SETUP_SECTS;
+	setup_sects = boot.hdr.setup_sects + 1;
+
+	setup_size = setup_sects << 9;
+	p = guest_real_to_host(kvm, BOOT_LOADER_SELECTOR, BOOT_LOADER_IP);
+
+	/* copy setup.bin to mem*/
+	if (read(fd_kernel, p, setup_size) != setup_size)
+		die_perror("read");
+
+	/* copy vmlinux.bin to BZ_KERNEL_START*/
+	p = guest_flat_to_host(kvm, BZ_KERNEL_START);
+
+	while ((nr = read(fd_kernel, p, 65536)) > 0)
+		p += nr;
+
+	p = guest_flat_to_host(kvm, BOOT_CMDLINE_OFFSET);
+	if (kernel_cmdline) {
+		cmdline_size = strlen(kernel_cmdline) + 1;
+		if (cmdline_size > boot.hdr.cmdline_size)
+			cmdline_size = boot.hdr.cmdline_size;
+
+		memset(p, 0, boot.hdr.cmdline_size);
+		memcpy(p, kernel_cmdline, cmdline_size - 1);
+	}
+
+	kern_boot	= guest_real_to_host(kvm, BOOT_LOADER_SELECTOR, 0x00);
+
+	kern_boot->hdr.cmd_line_ptr	= BOOT_CMDLINE_OFFSET;
+	kern_boot->hdr.type_of_loader	= 0xff;
+	kern_boot->hdr.heap_end_ptr	= 0xfe00;
+	kern_boot->hdr.loadflags	|= CAN_USE_HEAP;
+	kern_boot->hdr.vid_mode		= vidmode;
+
+	/*
+	 * Read initrd image into guest memory
+	 */
+	if (fd_initrd >= 0) {
+		struct stat initrd_stat;
+		unsigned long addr;
+
+		if (fstat(fd_initrd, &initrd_stat))
+			die_perror("fstat");
+
+		addr = boot.hdr.initrd_addr_max & ~0xfffff;
+		for (;;) {
+			if (addr < BZ_KERNEL_START)
+				die("Not enough memory for initrd");
+			else if (addr < (kvm->ram_size - initrd_stat.st_size))
+				break;
+			addr -= 0x100000;
+		}
+
+		p = guest_flat_to_host(kvm, addr);
+		nr = read(fd_initrd, p, initrd_stat.st_size);
+		if (nr != initrd_stat.st_size)
+			die("Failed to read initrd");
+
+		kern_boot->hdr.ramdisk_image	= addr;
+		kern_boot->hdr.ramdisk_size	= initrd_stat.st_size;
+	}
+
+	kvm->boot_selector = BOOT_LOADER_SELECTOR;
+	/*
+	 * The real-mode setup code starts at offset 0x200 of a bzImage. See
+	 * Documentation/x86/boot.txt for details.
+	 */
+	kvm->boot_ip = BOOT_LOADER_IP + 0x200;
+	kvm->boot_sp = BOOT_LOADER_SP;
+
+	return true;
+}
+
+/**
+ * kvm__arch_setup_firmware - inject BIOS into guest system memory
+ * @kvm - guest system descriptor
+ *
+ * This function is a main routine where we poke guest memory
+ * and install BIOS there.
+ */
+int kvm__arch_setup_firmware(struct kvm *kvm)
+{
+	int r;
+
+	/* standart minimal configuration */
+	setup_bios(kvm);
+
+	/* FIXME: SMP, ACPI and friends here */
+
+	/* MP table */
+	r = mptable__init(kvm);
+
+	return r;
+}
+
+int kvm__arch_free_firmware(struct kvm *kvm)
+{
+	int r;
+
+	/* MP table */
+	r = mptable__exit(kvm);
+
+	return r;
+}
+
+void kvm__arch_periodic_poll(struct kvm *kvm)
+{
+	serial8250__update_consoles(kvm);
+	virtio_console__inject_interrupt(kvm);
+}
diff --git a/tools/kvm/x86/mptable.c b/tools/kvm/x86/mptable.c
new file mode 100644
index 0000000..12bdcf8
--- /dev/null
+++ b/tools/kvm/x86/mptable.c
@@ -0,0 +1,287 @@
+#include "kvm/kvm.h"
+#include "kvm/bios.h"
+#include "kvm/apic.h"
+#include "kvm/mptable.h"
+#include "kvm/util.h"
+#include "kvm/irq.h"
+
+#include <linux/kernel.h>
+#include <string.h>
+
+#include <asm/mpspec_def.h>
+#include <linux/types.h>
+
+/*
+ * FIXME: please make sure the addresses borrowed
+ * for apic/ioapic never overlaped! We need a global
+ * tracker of system resources (including io, mmio,
+ * and friends).
+ */
+
+static unsigned int mpf_checksum(unsigned char *mp, int len)
+{
+	unsigned int sum = 0;
+
+	while (len--)
+		sum += *mp++;
+
+	return sum & 0xFF;
+}
+
+static unsigned int gen_cpu_flag(unsigned int cpu, unsigned int ncpu)
+{
+	/* sets enabled/disabled | BSP/AP processor */
+	return ( (cpu < ncpu) ? CPU_ENABLED       : 0) |
+		((cpu == 0)   ? CPU_BOOTPROCESSOR : 0x00);
+}
+
+#define MPTABLE_SIG_FLOATING	"_MP_"
+#define MPTABLE_OEM		"KVMCPU00"
+#define MPTABLE_PRODUCTID	"0.1         "
+#define MPTABLE_PCIBUSTYPE	"PCI   "
+#define MPTABLE_ISABUSTYPE	"ISA   "
+
+#define MPTABLE_STRNCPY(d, s)	memcpy(d, s, sizeof(d))
+
+/* It should be more than enough */
+#define MPTABLE_MAX_SIZE	(32 << 20)
+
+/*
+ * Too many cpus will require x2apic mode
+ * and rather ACPI support so we limit it
+ * here for a while.
+ */
+#define MPTABLE_MAX_CPUS	255
+
+static void mptable_add_irq_src(struct mpc_intsrc *mpc_intsrc,
+				u16 srcbusid,	u16 srcbusirq,
+				u16 dstapic,	u16 dstirq)
+{
+	*mpc_intsrc = (struct mpc_intsrc) {
+		.type		= MP_INTSRC,
+		.irqtype	= mp_INT,
+		.irqflag	= MP_IRQDIR_DEFAULT,
+		.srcbus		= srcbusid,
+		.srcbusirq	= srcbusirq,
+		.dstapic	= dstapic,
+		.dstirq		= dstirq
+	};
+}
+
+/**
+ * mptable_setup - create mptable and fill guest memory with it
+ */
+int mptable__init(struct kvm *kvm)
+{
+	unsigned long real_mpc_table, real_mpf_intel, size;
+	struct mpf_intel *mpf_intel;
+	struct mpc_table *mpc_table;
+	struct mpc_cpu *mpc_cpu;
+	struct mpc_bus *mpc_bus;
+	struct mpc_ioapic *mpc_ioapic;
+	struct mpc_intsrc *mpc_intsrc;
+	struct rb_node *pci_tree;
+
+	const int pcibusid = 0;
+	const int isabusid = 1;
+
+	unsigned int i, nentries = 0, ncpus = kvm->nrcpus;
+	unsigned int ioapicid;
+	void *last_addr;
+
+	/* That is where MP table will be in guest memory */
+	real_mpc_table = ALIGN(MB_BIOS_BEGIN + bios_rom_size, 16);
+
+	if (ncpus > MPTABLE_MAX_CPUS) {
+		pr_warning("Too many cpus: %d limited to %d",
+			ncpus, MPTABLE_MAX_CPUS);
+		ncpus = MPTABLE_MAX_CPUS;
+	}
+
+	mpc_table = calloc(1, MPTABLE_MAX_SIZE);
+	if (!mpc_table)
+		return -ENOMEM;
+
+	MPTABLE_STRNCPY(mpc_table->signature,	MPC_SIGNATURE);
+	MPTABLE_STRNCPY(mpc_table->oem,		MPTABLE_OEM);
+	MPTABLE_STRNCPY(mpc_table->productid,	MPTABLE_PRODUCTID);
+
+	mpc_table->spec		= 4;
+	mpc_table->lapic	= APIC_ADDR(0);
+	mpc_table->oemcount	= ncpus; /* will be updated again at end */
+
+	/*
+	 * CPUs enumeration. Technically speaking we should
+	 * ask either host or HV for apic version supported
+	 * but for a while we simply put some random value
+	 * here.
+	 */
+	mpc_cpu = (void *)&mpc_table[1];
+	for (i = 0; i < ncpus; i++) {
+		mpc_cpu->type		= MP_PROCESSOR;
+		mpc_cpu->apicid		= i;
+		mpc_cpu->apicver	= KVM_APIC_VERSION;
+		mpc_cpu->cpuflag	= gen_cpu_flag(i, ncpus);
+		mpc_cpu->cpufeature	= 0x600; /* some default value */
+		mpc_cpu->featureflag	= 0x201; /* some default value */
+		mpc_cpu++;
+	}
+
+	last_addr = (void *)mpc_cpu;
+	nentries += ncpus;
+
+	/*
+	 * PCI buses.
+	 * FIXME: Some callback here to obtain real number
+	 * of PCI buses present in system.
+	 */
+	mpc_bus		= last_addr;
+	mpc_bus->type	= MP_BUS;
+	mpc_bus->busid	= pcibusid;
+	MPTABLE_STRNCPY(mpc_bus->bustype, MPTABLE_PCIBUSTYPE);
+
+	last_addr = (void *)&mpc_bus[1];
+	nentries++;
+
+	/*
+	 * ISA bus.
+	 * FIXME: Same issue as for PCI bus.
+	 */
+	mpc_bus		= last_addr;
+	mpc_bus->type	= MP_BUS;
+	mpc_bus->busid	= isabusid;
+	MPTABLE_STRNCPY(mpc_bus->bustype, MPTABLE_ISABUSTYPE);
+
+	last_addr = (void *)&mpc_bus[1];
+	nentries++;
+
+	/*
+	 * IO-APIC chip.
+	 */
+	ioapicid		= ncpus + 1;
+	mpc_ioapic		= last_addr;
+	mpc_ioapic->type	= MP_IOAPIC;
+	mpc_ioapic->apicid	= ioapicid;
+	mpc_ioapic->apicver	= KVM_APIC_VERSION;
+	mpc_ioapic->flags	= MPC_APIC_USABLE;
+	mpc_ioapic->apicaddr	= IOAPIC_ADDR(0);
+
+	last_addr = (void *)&mpc_ioapic[1];
+	nentries++;
+
+	/*
+	 * IRQ sources.
+	 *
+	 * FIXME: Same issue as with buses. We definitely
+	 * need kind of collector routine which enumerate
+	 * resources used first and pass them here.
+	 * At moment we know we have only virtio block device
+	 * and virtio console but this is g00berfish.
+	 *
+	 * Also note we use PCI irqs here, no for ISA bus yet.
+	 */
+
+	for (pci_tree = irq__get_pci_tree(); pci_tree; pci_tree = rb_next(pci_tree)) {
+		struct pci_dev *dev = rb_entry(pci_tree, struct pci_dev, node);
+		struct irq_line *irq_line;
+
+		list_for_each_entry(irq_line, &dev->lines, node) {
+			unsigned char srcbusirq;
+
+			srcbusirq = (dev->id << 2) | (dev->pin - 1);
+
+			mpc_intsrc = last_addr;
+
+			mptable_add_irq_src(mpc_intsrc, pcibusid, srcbusirq, ioapicid, irq_line->line);
+			last_addr = (void *)&mpc_intsrc[1];
+			nentries++;
+		}
+	}
+
+	/*
+	 * Local IRQs assignment (LINT0, LINT1)
+	 */
+	mpc_intsrc		= last_addr;
+	mpc_intsrc->type	= MP_LINTSRC;
+	mpc_intsrc->irqtype	= mp_ExtINT;
+	mpc_intsrc->irqtype	= mp_INT;
+	mpc_intsrc->irqflag	= MP_IRQDIR_DEFAULT;
+	mpc_intsrc->srcbus	= isabusid;
+	mpc_intsrc->srcbusirq	= 0;
+	mpc_intsrc->dstapic	= 0; /* FIXME: BSP apic */
+	mpc_intsrc->dstirq	= 0; /* LINT0 */
+
+	last_addr = (void *)&mpc_intsrc[1];
+	nentries++;
+
+	mpc_intsrc		= last_addr;
+	mpc_intsrc->type	= MP_LINTSRC;
+	mpc_intsrc->irqtype	= mp_NMI;
+	mpc_intsrc->irqflag	= MP_IRQDIR_DEFAULT;
+	mpc_intsrc->srcbus	= isabusid;
+	mpc_intsrc->srcbusirq	= 0;
+	mpc_intsrc->dstapic	= 0; /* FIXME: BSP apic */
+	mpc_intsrc->dstirq	= 1; /* LINT1 */
+
+	last_addr = (void *)&mpc_intsrc[1];
+	nentries++;
+
+	/*
+	 * Floating MP table finally.
+	 */
+	real_mpf_intel	= ALIGN((unsigned long)last_addr - (unsigned long)mpc_table, 16);
+	mpf_intel	= (void *)((unsigned long)mpc_table + real_mpf_intel);
+
+	MPTABLE_STRNCPY(mpf_intel->signature, MPTABLE_SIG_FLOATING);
+	mpf_intel->length	= 1;
+	mpf_intel->specification= 4;
+	mpf_intel->physptr	= (unsigned int)real_mpc_table;
+	mpf_intel->checksum	= -mpf_checksum((unsigned char *)mpf_intel, sizeof(*mpf_intel));
+
+	/*
+	 * No last_addr inclrement here please, we need last
+	 * active position here to compute table size.
+	 */
+
+	/*
+	 * Don't forget to update header in fixed table.
+	*/
+	mpc_table->oemcount	= nentries;
+	mpc_table->length	= last_addr - (void *)mpc_table;
+	mpc_table->checksum	= -mpf_checksum((unsigned char *)mpc_table, mpc_table->length);
+
+
+	/*
+	 * We will copy the whole table, no need to separate
+	 * floating structure and table itkvm.
+	 */
+	size = (unsigned long)mpf_intel + sizeof(*mpf_intel) - (unsigned long)mpc_table;
+
+	/*
+	 * The finial check -- never get out of system bios
+	 * area. Lets also check for allocated memory overrun,
+	 * in real it's late but still usefull.
+	 */
+
+	if (size > (unsigned long)(MB_BIOS_END - bios_rom_size) ||
+	    size > MPTABLE_MAX_SIZE) {
+		free(mpc_table);
+		pr_err("MP table is too big");
+
+		return -E2BIG;
+	}
+
+	/*
+	 * OK, it is time to move it to guest memory.
+	 */
+	memcpy(guest_flat_to_host(kvm, real_mpc_table), mpc_table, size);
+
+	free(mpc_table);
+
+	return 0;
+}
+
+int mptable__exit(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 2d89f02..495210a 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -57,7 +57,7 @@ OPTIONS
 
 -s::
 --sort=::
-	Sort by key(s): pid, comm, dso, symbol, parent.
+	Sort by key(s): pid, comm, dso, symbol, parent, srcline.
 
 -p::
 --parent=<regex>::
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 4a5680c..5b80d84 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -112,7 +112,7 @@ Default is to monitor all CPUS.
 
 -s::
 --sort::
-	Sort by key(s): pid, comm, dso, symbol, parent
+	Sort by key(s): pid, comm, dso, symbol, parent, srcline.
 
 -n::
 --show-nr-samples::
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 0eee64c..d698c11 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -503,6 +503,7 @@ else
 		LIB_OBJS += $(OUTPUT)ui/progress.o
 		LIB_OBJS += $(OUTPUT)ui/util.o
 		LIB_OBJS += $(OUTPUT)ui/tui/setup.o
+		LIB_OBJS += $(OUTPUT)ui/tui/util.o
 		LIB_H += ui/browser.h
 		LIB_H += ui/browsers/map.h
 		LIB_H += ui/helpline.h
@@ -522,13 +523,18 @@ else
 		msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
 		BASIC_CFLAGS += -DNO_GTK2_SUPPORT
 	else
+		ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y)
+			BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
+		endif
 		BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
 		EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
 		LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
 		LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
+		LIB_OBJS += $(OUTPUT)ui/gtk/util.o
 		# Make sure that it'd be included only once.
 		ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),)
 			LIB_OBJS += $(OUTPUT)ui/setup.o
+			LIB_OBJS += $(OUTPUT)ui/util.o
 		endif
 	endif
 endif
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index acd78dc..0dd5a05 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -60,7 +60,7 @@ static int __cmd_evlist(const char *input_name, struct perf_attr_details *detail
 	list_for_each_entry(pos, &session->evlist->entries, node) {
 		bool first = true;
 
-		printf("%s", event_name(pos));
+		printf("%s", perf_evsel__name(pos));
 
 		if (details->verbose || details->freq) {
 			comma_printf(&first, " sample_freq=%" PRIu64,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f95840d..f5a6452 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -265,7 +265,7 @@ try_again:
 
 			if (err == ENOENT) {
 				ui__error("The %s event is not supported.\n",
-					    event_name(pos));
+					  perf_evsel__name(pos));
 				exit(EXIT_FAILURE);
 			}
 
@@ -916,7 +916,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 		usage_with_options(record_usage, record_options);
 
 	list_for_each_entry(pos, &evsel_list->entries, node) {
-		if (perf_header__push_event(pos->attr.config, event_name(pos)))
+		if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
 			goto out_free_fd;
 	}
 
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 25249f7..40b0ffc 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -69,7 +69,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
 
 	if ((sort__has_parent || symbol_conf.use_callchain)
 	    && sample->callchain) {
-		err = machine__resolve_callchain(machine, evsel, al->thread,
+		err = machine__resolve_callchain(machine, al->thread,
 						 sample->callchain, &parent);
 		if (err)
 			return err;
@@ -140,7 +140,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
 	struct hist_entry *he;
 
 	if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
-		err = machine__resolve_callchain(machine, evsel, al->thread,
+		err = machine__resolve_callchain(machine, al->thread,
 						 sample->callchain, &parent);
 		if (err)
 			return err;
@@ -230,7 +230,7 @@ static int process_read_event(struct perf_tool *tool,
 	struct perf_report *rep = container_of(tool, struct perf_report, tool);
 
 	if (rep->show_threads) {
-		const char *name = evsel ? event_name(evsel) : "unknown";
+		const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
 		perf_read_values_add_value(&rep->show_threads_values,
 					   event->read.pid, event->read.tid,
 					   event->read.id,
@@ -239,7 +239,7 @@ static int process_read_event(struct perf_tool *tool,
 	}
 
 	dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
-		    evsel ? event_name(evsel) : "FAIL",
+		    evsel ? perf_evsel__name(evsel) : "FAIL",
 		    event->read.value);
 
 	return 0;
@@ -314,7 +314,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
 
 	list_for_each_entry(pos, &evlist->entries, node) {
 		struct hists *hists = &pos->hists;
-		const char *evname = event_name(pos);
+		const char *evname = perf_evsel__name(pos);
 
 		hists__fprintf_nr_sample_events(hists, evname, stdout);
 		hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index b125e07..9fe77b1 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1601,7 +1601,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
 
 	if (thread == NULL) {
 		pr_debug("problem processing %s event, skipping it.\n",
-			 evsel->name);
+			 perf_evsel__name(evsel));
 		return -1;
 	}
 
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 8e395a5..8fecd3b 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -137,10 +137,11 @@ static const char *output_field2str(enum perf_output_field field)
 
 #define PRINT_FIELD(x)  (output[attr->type].fields & PERF_OUTPUT_##x)
 
-static int perf_event_attr__check_stype(struct perf_event_attr *attr,
-				  u64 sample_type, const char *sample_msg,
-				  enum perf_output_field field)
+static int perf_evsel__check_stype(struct perf_evsel *evsel,
+				   u64 sample_type, const char *sample_msg,
+				   enum perf_output_field field)
 {
+	struct perf_event_attr *attr = &evsel->attr;
 	int type = attr->type;
 	const char *evname;
 
@@ -148,7 +149,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr,
 		return 0;
 
 	if (output[type].user_set) {
-		evname = __event_name(attr->type, attr->config);
+		evname = perf_evsel__name(evsel);
 		pr_err("Samples for '%s' event do not have %s attribute set. "
 		       "Cannot print '%s' field.\n",
 		       evname, sample_msg, output_field2str(field));
@@ -157,7 +158,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr,
 
 	/* user did not ask for it explicitly so remove from the default list */
 	output[type].fields &= ~field;
-	evname = __event_name(attr->type, attr->config);
+	evname = perf_evsel__name(evsel);
 	pr_debug("Samples for '%s' event do not have %s attribute set. "
 		 "Skipping '%s' field.\n",
 		 evname, sample_msg, output_field2str(field));
@@ -175,8 +176,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
 		return -EINVAL;
 
 	if (PRINT_FIELD(IP)) {
-		if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
-					   PERF_OUTPUT_IP))
+		if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
+					    PERF_OUTPUT_IP))
 			return -EINVAL;
 
 		if (!no_callchain &&
@@ -185,8 +186,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
 	}
 
 	if (PRINT_FIELD(ADDR) &&
-		perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR",
-				       PERF_OUTPUT_ADDR))
+		perf_evsel__check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR",
+					PERF_OUTPUT_ADDR))
 		return -EINVAL;
 
 	if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
@@ -208,18 +209,18 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
 	}
 
 	if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
-		perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
-				       PERF_OUTPUT_TID|PERF_OUTPUT_PID))
+		perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID",
+					PERF_OUTPUT_TID|PERF_OUTPUT_PID))
 		return -EINVAL;
 
 	if (PRINT_FIELD(TIME) &&
-		perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME",
-				       PERF_OUTPUT_TIME))
+		perf_evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME",
+					PERF_OUTPUT_TIME))
 		return -EINVAL;
 
 	if (PRINT_FIELD(CPU) &&
-		perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU",
-				       PERF_OUTPUT_CPU))
+		perf_evsel__check_stype(evsel, PERF_SAMPLE_CPU, "CPU",
+					PERF_OUTPUT_CPU))
 		return -EINVAL;
 
 	return 0;
@@ -258,9 +259,10 @@ static int perf_session__check_output_opt(struct perf_session *session)
 
 static void print_sample_start(struct perf_sample *sample,
 			       struct thread *thread,
-			       struct perf_event_attr *attr)
+			       struct perf_evsel *evsel)
 {
 	int type;
+	struct perf_event_attr *attr = &evsel->attr;
 	struct event_format *event;
 	const char *evname = NULL;
 	unsigned long secs;
@@ -305,7 +307,7 @@ static void print_sample_start(struct perf_sample *sample,
 			if (event)
 				evname = event->name;
 		} else
-			evname = __event_name(attr->type, attr->config);
+			evname = perf_evsel__name(evsel);
 
 		printf("%s: ", evname ? evname : "[unknown]");
 	}
@@ -387,7 +389,7 @@ static void print_sample_bts(union perf_event *event,
 			printf(" ");
 		else
 			printf("\n");
-		perf_event__print_ip(event, sample, machine, evsel,
+		perf_event__print_ip(event, sample, machine,
 				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
 				     PRINT_FIELD(SYMOFFSET));
 	}
@@ -412,7 +414,7 @@ static void process_event(union perf_event *event __unused,
 	if (output[attr->type].fields == 0)
 		return;
 
-	print_sample_start(sample, thread, attr);
+	print_sample_start(sample, thread, evsel);
 
 	if (is_bts_event(attr)) {
 		print_sample_bts(event, sample, evsel, machine, thread);
@@ -431,7 +433,7 @@ static void process_event(union perf_event *event __unused,
 			printf(" ");
 		else
 			printf("\n");
-		perf_event__print_ip(event, sample, machine, evsel,
+		perf_event__print_ip(event, sample, machine,
 				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
 				     PRINT_FIELD(SYMOFFSET));
 	}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 07b5c77..861f0ae 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -391,7 +391,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
 
 	if (verbose) {
 		fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
-			event_name(counter), count[0], count[1], count[2]);
+			perf_evsel__name(counter), count[0], count[1], count[2]);
 	}
 
 	/*
@@ -496,7 +496,7 @@ static int run_perf_stat(int argc __used, const char **argv)
 			    errno == ENXIO) {
 				if (verbose)
 					ui__warning("%s event is not supported by the kernel.\n",
-						    event_name(counter));
+						    perf_evsel__name(counter));
 				counter->supported = false;
 				continue;
 			}
@@ -594,7 +594,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
 			csv_output ? 0 : -4,
 			evsel_list->cpus->map[cpu], csv_sep);
 
-	fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel));
+	fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel));
 
 	if (evsel->cgrp)
 		fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -792,7 +792,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
 	else
 		cpu = 0;
 
-	fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel));
+	fprintf(output, fmt, cpustr, avg, csv_sep, perf_evsel__name(evsel));
 
 	if (evsel->cgrp)
 		fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -908,7 +908,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
 			counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
 			csv_sep,
 			csv_output ? 0 : -24,
-			event_name(counter));
+			perf_evsel__name(counter));
 
 		if (counter->cgrp)
 			fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
@@ -961,7 +961,7 @@ static void print_counter(struct perf_evsel *counter)
 				counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
 				csv_sep,
 				csv_output ? 0 : -24,
-				event_name(counter));
+				perf_evsel__name(counter));
 
 			if (counter->cgrp)
 				fprintf(output, "%s%s",
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 5a8727c..5ce3030 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -583,7 +583,7 @@ static int test__basic_mmap(void)
 		if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
 			pr_debug("expected %d %s events, got %d\n",
 				 expected_nr_events[evsel->idx],
-				 event_name(evsel), nr_events[evsel->idx]);
+				 perf_evsel__name(evsel), nr_events[evsel->idx]);
 			goto out_munmap;
 		}
 	}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 6bb0277..e3cab5f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -245,7 +245,7 @@ static void perf_top__show_details(struct perf_top *top)
 	if (notes->src == NULL)
 		goto out_unlock;
 
-	printf("Showing %s for %s\n", event_name(top->sym_evsel), symbol->name);
+	printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name);
 	printf("  Events  Pcnt (>=%d%%)\n", top->sym_pcnt_filter);
 
 	more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx,
@@ -408,7 +408,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top)
 	fprintf(stdout, "\t[e]     display entries (lines).           \t(%d)\n", top->print_entries);
 
 	if (top->evlist->nr_entries > 1)
-		fprintf(stdout, "\t[E]     active event counter.              \t(%s)\n", event_name(top->sym_evsel));
+		fprintf(stdout, "\t[E]     active event counter.              \t(%s)\n", perf_evsel__name(top->sym_evsel));
 
 	fprintf(stdout, "\t[f]     profile display filter (count).    \t(%d)\n", top->count_filter);
 
@@ -503,13 +503,13 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
 				fprintf(stderr, "\nAvailable events:");
 
 				list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
-					fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel));
+					fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel));
 
 				prompt_integer(&counter, "Enter details event counter");
 
 				if (counter >= top->evlist->nr_entries) {
 					top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
-					fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel));
+					fprintf(stderr, "Sorry, no such event, using %s.\n", perf_evsel__name(top->sym_evsel));
 					sleep(1);
 					break;
 				}
@@ -774,7 +774,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
 
 		if ((sort__has_parent || symbol_conf.use_callchain) &&
 		    sample->callchain) {
-			err = machine__resolve_callchain(machine, evsel, al.thread,
+			err = machine__resolve_callchain(machine, al.thread,
 							 sample->callchain, &parent);
 			if (err)
 				return;
@@ -960,7 +960,7 @@ try_again:
 
 			if (err == ENOENT) {
 				ui__error("The %s event is not supported.\n",
-					    event_name(counter));
+					  perf_evsel__name(counter));
 				goto out_err;
 			} else if (err == EMFILE) {
 				ui__error("Too many events are opened.\n"
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index d9084e0..6c18785 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -78,6 +78,19 @@ int main(int argc, char *argv[])
         return 0;
 }
 endef
+
+define SOURCE_GTK2_INFOBAR
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#include <gtk/gtk.h>
+#pragma GCC diagnostic error \"-Wstrict-prototypes\"
+
+int main(void)
+{
+	gtk_info_bar_new();
+
+	return 0;
+}
+endef
 endif
 
 ifndef NO_LIBPERL
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 34b1c46..67a2703 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -814,7 +814,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
 {
 	struct disasm_line *pos, *n;
 	struct annotation *notes;
-	const size_t size = symbol__size(sym);
+	size_t size;
 	struct map_symbol ms = {
 		.map = map,
 		.sym = sym,
@@ -834,6 +834,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
 	if (sym == NULL)
 		return -1;
 
+	size = symbol__size(sym);
+
 	if (map->dso->annotate_warned)
 		return -1;
 
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 53f6697..482f051 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -23,6 +23,7 @@ struct hist_browser {
 	struct hists	    *hists;
 	struct hist_entry   *he_selection;
 	struct map_symbol   *selection;
+	int		     print_seq;
 	bool		     has_symbols;
 };
 
@@ -800,6 +801,196 @@ do_offset:
 	}
 }
 
+static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
+							struct callchain_node *chain_node,
+							u64 total, int level,
+							FILE *fp)
+{
+	struct rb_node *node;
+	int offset = level * LEVEL_OFFSET_STEP;
+	u64 new_total, remaining;
+	int printed = 0;
+
+	if (callchain_param.mode == CHAIN_GRAPH_REL)
+		new_total = chain_node->children_hit;
+	else
+		new_total = total;
+
+	remaining = new_total;
+	node = rb_first(&chain_node->rb_root);
+	while (node) {
+		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
+		struct rb_node *next = rb_next(node);
+		u64 cumul = callchain_cumul_hits(child);
+		struct callchain_list *chain;
+		char folded_sign = ' ';
+		int first = true;
+		int extra_offset = 0;
+
+		remaining -= cumul;
+
+		list_for_each_entry(chain, &child->val, list) {
+			char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
+			const char *str;
+			bool was_first = first;
+
+			if (first)
+				first = false;
+			else
+				extra_offset = LEVEL_OFFSET_STEP;
+
+			folded_sign = callchain_list__folded(chain);
+
+			alloc_str = NULL;
+			str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+			if (was_first) {
+				double percent = cumul * 100.0 / new_total;
+
+				if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
+					str = "Not enough memory!";
+				else
+					str = alloc_str;
+			}
+
+			printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
+			free(alloc_str);
+			if (folded_sign == '+')
+				break;
+		}
+
+		if (folded_sign == '-') {
+			const int new_level = level + (extra_offset ? 2 : 1);
+			printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
+										new_level, fp);
+		}
+
+		node = next;
+	}
+
+	return printed;
+}
+
+static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
+						struct callchain_node *node,
+						int level, FILE *fp)
+{
+	struct callchain_list *chain;
+	int offset = level * LEVEL_OFFSET_STEP;
+	char folded_sign = ' ';
+	int printed = 0;
+
+	list_for_each_entry(chain, &node->val, list) {
+		char ipstr[BITS_PER_LONG / 4 + 1], *s;
+
+		folded_sign = callchain_list__folded(chain);
+		s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+		printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
+	}
+
+	if (folded_sign == '-')
+		printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
+									browser->hists->stats.total_period,
+									level + 1,  fp);
+	return printed;
+}
+
+static int hist_browser__fprintf_callchain(struct hist_browser *browser,
+					   struct rb_root *chain, int level, FILE *fp)
+{
+	struct rb_node *nd;
+	int printed = 0;
+
+	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+
+		printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
+	}
+
+	return printed;
+}
+
+static int hist_browser__fprintf_entry(struct hist_browser *browser,
+				       struct hist_entry *he, FILE *fp)
+{
+	char s[8192];
+	double percent;
+	int printed = 0;
+	char folded_sign = ' ';
+
+	if (symbol_conf.use_callchain)
+		folded_sign = hist_entry__folded(he);
+
+	hist_entry__snprintf(he, s, sizeof(s), browser->hists);
+	percent = (he->period * 100.0) / browser->hists->stats.total_period;
+
+	if (symbol_conf.use_callchain)
+		printed += fprintf(fp, "%c ", folded_sign);
+
+	printed += fprintf(fp, " %5.2f%%", percent);
+
+	if (symbol_conf.show_nr_samples)
+		printed += fprintf(fp, " %11u", he->nr_events);
+
+	if (symbol_conf.show_total_period)
+		printed += fprintf(fp, " %12" PRIu64, he->period);
+
+	printed += fprintf(fp, "%s\n", rtrim(s));
+
+	if (folded_sign == '-')
+		printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
+
+	return printed;
+}
+
+static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
+{
+	struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries));
+	int printed = 0;
+
+	while (nd) {
+		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+
+		printed += hist_browser__fprintf_entry(browser, h, fp);
+		nd = hists__filter_entries(rb_next(nd));
+	}
+
+	return printed;
+}
+
+static int hist_browser__dump(struct hist_browser *browser)
+{
+	char filename[64];
+	FILE *fp;
+
+	while (1) {
+		scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
+		if (access(filename, F_OK))
+			break;
+		/*
+ 		 * XXX: Just an arbitrary lazy upper limit
+ 		 */
+		if (++browser->print_seq == 8192) {
+			ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
+			return -1;
+		}
+	}
+
+	fp = fopen(filename, "w");
+	if (fp == NULL) {
+		char bf[64];
+		strerror_r(errno, bf, sizeof(bf));
+		ui_helpline__fpush("Couldn't write to %s: %s", filename, bf);
+		return -1;
+	}
+
+	++browser->print_seq;
+	hist_browser__fprintf(browser, fp);
+	fclose(fp);
+	ui_helpline__fpush("%s written!", filename);
+
+	return 0;
+}
+
 static struct hist_browser *hist_browser__new(struct hists *hists)
 {
 	struct hist_browser *browser = zalloc(sizeof(*browser));
@@ -937,6 +1128,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 			    browser->selection->map->dso->annotate_warned)
 				continue;
 			goto do_annotate;
+		case 'P':
+			hist_browser__dump(browser);
+			continue;
 		case 'd':
 			goto zoom_dso;
 		case 't':
@@ -969,6 +1163,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 					"E             Expand all callchains\n"
 					"d             Zoom into current DSO\n"
 					"t             Zoom into current Thread\n"
+					"P             Print histograms to perf.hist.N\n"
 					"/             Filter symbol by name");
 			continue;
 		case K_ENTER:
@@ -1172,7 +1367,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
 	struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
 	bool current_entry = ui_browser__is_current_entry(browser, row);
 	unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
-	const char *ev_name = event_name(evsel);
+	const char *ev_name = perf_evsel__name(evsel);
 	char bf[256], unit;
 	const char *warn = " ";
 	size_t printed;
@@ -1240,7 +1435,7 @@ browse_hists:
 			 */
 			if (timer)
 				timer(arg);
-			ev_name = event_name(pos);
+			ev_name = perf_evsel__name(pos);
 			key = perf_evsel__hists_browse(pos, nr_events, help,
 						       ev_name, true, timer,
 						       arg, delay_secs);
@@ -1309,17 +1504,11 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
 	ui_helpline__push("Press ESC to exit");
 
 	list_for_each_entry(pos, &evlist->entries, node) {
-		const char *ev_name = event_name(pos);
+		const char *ev_name = perf_evsel__name(pos);
 		size_t line_len = strlen(ev_name) + 7;
 
 		if (menu.b.width < line_len)
 			menu.b.width = line_len;
-		/*
-		 * Cache the evsel name, tracepoints have a _high_ cost per
-		 * event_name() call.
-		 */
-		if (pos->name == NULL)
-			pos->name = strdup(ev_name);
 	}
 
 	return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
@@ -1330,11 +1519,10 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
 				  void(*timer)(void *arg), void *arg,
 				  int delay_secs)
 {
-
 	if (evlist->nr_entries == 1) {
 		struct perf_evsel *first = list_entry(evlist->entries.next,
 						      struct perf_evsel, node);
-		const char *ev_name = event_name(first);
+		const char *ev_name = perf_evsel__name(first);
 		return perf_evsel__hists_browse(first, evlist->nr_entries, help,
 						ev_name, false, timer, arg,
 						delay_secs);
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 0656c38..ec12e0b 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -11,8 +11,8 @@
 
 static void perf_gtk__signal(int sig)
 {
+	perf_gtk__exit(false);
 	psignal(sig, "perf");
-	gtk_main_quit();
 }
 
 static void perf_gtk__resize_window(GtkWidget *window)
@@ -122,13 +122,59 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
 	gtk_container_add(GTK_CONTAINER(window), view);
 }
 
+#ifdef HAVE_GTK_INFO_BAR
+static GtkWidget *perf_gtk__setup_info_bar(void)
+{
+	GtkWidget *info_bar;
+	GtkWidget *label;
+	GtkWidget *content_area;
+
+	info_bar = gtk_info_bar_new();
+	gtk_widget_set_no_show_all(info_bar, TRUE);
+
+	label = gtk_label_new("");
+	gtk_widget_show(label);
+
+	content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(info_bar));
+	gtk_container_add(GTK_CONTAINER(content_area), label);
+
+	gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), GTK_STOCK_OK,
+				GTK_RESPONSE_OK);
+	g_signal_connect(info_bar, "response",
+			 G_CALLBACK(gtk_widget_hide), NULL);
+
+	pgctx->info_bar = info_bar;
+	pgctx->message_label = label;
+
+	return info_bar;
+}
+#endif
+
+static GtkWidget *perf_gtk__setup_statusbar(void)
+{
+	GtkWidget *stbar;
+	unsigned ctxid;
+
+	stbar = gtk_statusbar_new();
+
+	ctxid = gtk_statusbar_get_context_id(GTK_STATUSBAR(stbar),
+					     "perf report");
+	pgctx->statbar = stbar;
+	pgctx->statbar_ctx_id = ctxid;
+
+	return stbar;
+}
+
 int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
 				  const char *help __used,
 				  void (*timer) (void *arg)__used,
 				  void *arg __used, int delay_secs __used)
 {
 	struct perf_evsel *pos;
+	GtkWidget *vbox;
 	GtkWidget *notebook;
+	GtkWidget *info_bar;
+	GtkWidget *statbar;
 	GtkWidget *window;
 
 	signal(SIGSEGV, perf_gtk__signal);
@@ -143,11 +189,17 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
 
 	g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
 
+	pgctx = perf_gtk__activate_context(window);
+	if (!pgctx)
+		return -1;
+
+	vbox = gtk_vbox_new(FALSE, 0);
+
 	notebook = gtk_notebook_new();
 
 	list_for_each_entry(pos, &evlist->entries, node) {
 		struct hists *hists = &pos->hists;
-		const char *evname = event_name(pos);
+		const char *evname = perf_evsel__name(pos);
 		GtkWidget *scrolled_window;
 		GtkWidget *tab_label;
 
@@ -164,7 +216,16 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
 		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
 	}
 
-	gtk_container_add(GTK_CONTAINER(window), notebook);
+	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+	info_bar = perf_gtk__setup_info_bar();
+	if (info_bar)
+		gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
+
+	statbar = perf_gtk__setup_statusbar();
+	gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
+
+	gtk_container_add(GTK_CONTAINER(window), vbox);
 
 	gtk_widget_show_all(window);
 
@@ -174,5 +235,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
 
 	gtk_main();
 
+	perf_gtk__deactivate_context(&pgctx);
+
 	return 0;
 }
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 75177ee..a4d0f2b 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -1,8 +1,39 @@
 #ifndef _PERF_GTK_H_
 #define _PERF_GTK_H_ 1
 
+#include <stdbool.h>
+
 #pragma GCC diagnostic ignored "-Wstrict-prototypes"
 #include <gtk/gtk.h>
 #pragma GCC diagnostic error "-Wstrict-prototypes"
 
+
+struct perf_gtk_context {
+	GtkWidget *main_window;
+
+#ifdef HAVE_GTK_INFO_BAR
+	GtkWidget *info_bar;
+	GtkWidget *message_label;
+#endif
+	GtkWidget *statbar;
+	guint statbar_ctx_id;
+};
+
+extern struct perf_gtk_context *pgctx;
+
+static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx)
+{
+	return ctx && ctx->main_window;
+}
+
+struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
+int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
+
+#ifndef HAVE_GTK_INFO_BAR
+static inline GtkWidget *perf_gtk__setup_info_bar(void)
+{
+	return NULL;
+}
+#endif
+
 #endif /* _PERF_GTK_H_ */
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
index 8295299..92879ce 100644
--- a/tools/perf/ui/gtk/setup.c
+++ b/tools/perf/ui/gtk/setup.c
@@ -1,12 +1,17 @@
 #include "gtk.h"
 #include "../../util/cache.h"
+#include "../../util/debug.h"
+
+extern struct perf_error_ops perf_gtk_eops;
 
 int perf_gtk__init(void)
 {
+	perf_error__register(&perf_gtk_eops);
 	return gtk_init_check(NULL, NULL) ? 0 : -1;
 }
 
 void perf_gtk__exit(bool wait_for_ok __used)
 {
+	perf_error__unregister(&perf_gtk_eops);
 	gtk_main_quit();
 }
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
new file mode 100644
index 0000000..0ead373
--- /dev/null
+++ b/tools/perf/ui/gtk/util.c
@@ -0,0 +1,129 @@
+#include "../util.h"
+#include "../../util/debug.h"
+#include "gtk.h"
+
+#include <string.h>
+
+
+struct perf_gtk_context *pgctx;
+
+struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window)
+{
+	struct perf_gtk_context *ctx;
+
+	ctx = malloc(sizeof(*pgctx));
+	if (ctx)
+		ctx->main_window = window;
+
+	return ctx;
+}
+
+int perf_gtk__deactivate_context(struct perf_gtk_context **ctx)
+{
+	if (!perf_gtk__is_active_context(*ctx))
+		return -1;
+
+	free(*ctx);
+	*ctx = NULL;
+	return 0;
+}
+
+static int perf_gtk__error(const char *format, va_list args)
+{
+	char *msg;
+	GtkWidget *dialog;
+
+	if (!perf_gtk__is_active_context(pgctx) ||
+	    vasprintf(&msg, format, args) < 0) {
+		fprintf(stderr, "Error:\n");
+		vfprintf(stderr, format, args);
+		fprintf(stderr, "\n");
+		return -1;
+	}
+
+	dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(pgctx->main_window),
+					GTK_DIALOG_DESTROY_WITH_PARENT,
+					GTK_MESSAGE_ERROR,
+					GTK_BUTTONS_CLOSE,
+					"<b>Error</b>\n\n%s", msg);
+	gtk_dialog_run(GTK_DIALOG(dialog));
+
+	gtk_widget_destroy(dialog);
+	free(msg);
+	return 0;
+}
+
+#ifdef HAVE_GTK_INFO_BAR
+static int perf_gtk__warning_info_bar(const char *format, va_list args)
+{
+	char *msg;
+
+	if (!perf_gtk__is_active_context(pgctx) ||
+	    vasprintf(&msg, format, args) < 0) {
+		fprintf(stderr, "Warning:\n");
+		vfprintf(stderr, format, args);
+		fprintf(stderr, "\n");
+		return -1;
+	}
+
+	gtk_label_set_text(GTK_LABEL(pgctx->message_label), msg);
+	gtk_info_bar_set_message_type(GTK_INFO_BAR(pgctx->info_bar),
+				      GTK_MESSAGE_WARNING);
+	gtk_widget_show(pgctx->info_bar);
+
+	free(msg);
+	return 0;
+}
+#else
+static int perf_gtk__warning_statusbar(const char *format, va_list args)
+{
+	char *msg, *p;
+
+	if (!perf_gtk__is_active_context(pgctx) ||
+	    vasprintf(&msg, format, args) < 0) {
+		fprintf(stderr, "Warning:\n");
+		vfprintf(stderr, format, args);
+		fprintf(stderr, "\n");
+		return -1;
+	}
+
+	gtk_statusbar_pop(GTK_STATUSBAR(pgctx->statbar),
+			  pgctx->statbar_ctx_id);
+
+	/* Only first line can be displayed */
+	p = strchr(msg, '\n');
+	if (p)
+		*p = '\0';
+
+	gtk_statusbar_push(GTK_STATUSBAR(pgctx->statbar),
+			   pgctx->statbar_ctx_id, msg);
+
+	free(msg);
+	return 0;
+}
+#endif
+
+struct perf_error_ops perf_gtk_eops = {
+	.error		= perf_gtk__error,
+#ifdef HAVE_GTK_INFO_BAR
+	.warning	= perf_gtk__warning_info_bar,
+#else
+	.warning	= perf_gtk__warning_statusbar,
+#endif
+};
+
+/*
+ * FIXME: Functions below should be implemented properly.
+ *        For now, just add stubs for NO_NEWT=1 build.
+ */
+#ifdef NO_NEWT_SUPPORT
+int ui_helpline__show_help(const char *format __used, va_list ap __used)
+{
+	return 0;
+}
+
+void ui_progress__update(u64 curr __used, u64 total __used,
+			 const char *title __used)
+{
+}
+#endif
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index d33e943..e813c1d 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -15,6 +15,8 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
 
 static volatile int ui__need_resize;
 
+extern struct perf_error_ops perf_tui_eops;
+
 void ui__refresh_dimensions(bool force)
 {
 	if (force || ui__need_resize) {
@@ -122,6 +124,8 @@ int ui__init(void)
 	signal(SIGINT, ui__signal);
 	signal(SIGQUIT, ui__signal);
 	signal(SIGTERM, ui__signal);
+
+	perf_error__register(&perf_tui_eops);
 out:
 	return err;
 }
@@ -137,4 +141,6 @@ void ui__exit(bool wait_for_ok)
 	SLsmg_refresh();
 	SLsmg_reset_smg();
 	SLang_reset_tty();
+
+	perf_error__unregister(&perf_tui_eops);
 }
diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c
new file mode 100644
index 0000000..092902e
--- /dev/null
+++ b/tools/perf/ui/tui/util.c
@@ -0,0 +1,243 @@
+#include "../../util/util.h"
+#include <signal.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/ttydefaults.h>
+
+#include "../../util/cache.h"
+#include "../../util/debug.h"
+#include "../browser.h"
+#include "../keysyms.h"
+#include "../helpline.h"
+#include "../ui.h"
+#include "../util.h"
+#include "../libslang.h"
+
+static void ui_browser__argv_write(struct ui_browser *browser,
+				   void *entry, int row)
+{
+	char **arg = entry;
+	bool current_entry = ui_browser__is_current_entry(browser, row);
+
+	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
+						       HE_COLORSET_NORMAL);
+	slsmg_write_nstring(*arg, browser->width);
+}
+
+static int popup_menu__run(struct ui_browser *menu)
+{
+	int key;
+
+	if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
+		return -1;
+
+	while (1) {
+		key = ui_browser__run(menu, 0);
+
+		switch (key) {
+		case K_RIGHT:
+		case K_ENTER:
+			key = menu->index;
+			break;
+		case K_LEFT:
+		case K_ESC:
+		case 'q':
+		case CTRL('c'):
+			key = -1;
+			break;
+		default:
+			continue;
+		}
+
+		break;
+	}
+
+	ui_browser__hide(menu);
+	return key;
+}
+
+int ui__popup_menu(int argc, char * const argv[])
+{
+	struct ui_browser menu = {
+		.entries    = (void *)argv,
+		.refresh    = ui_browser__argv_refresh,
+		.seek	    = ui_browser__argv_seek,
+		.write	    = ui_browser__argv_write,
+		.nr_entries = argc,
+	};
+
+	return popup_menu__run(&menu);
+}
+
+int ui_browser__input_window(const char *title, const char *text, char *input,
+			     const char *exit_msg, int delay_secs)
+{
+	int x, y, len, key;
+	int max_len = 60, nr_lines = 0;
+	static char buf[50];
+	const char *t;
+
+	t = text;
+	while (1) {
+		const char *sep = strchr(t, '\n');
+
+		if (sep == NULL)
+			sep = strchr(t, '\0');
+		len = sep - t;
+		if (max_len < len)
+			max_len = len;
+		++nr_lines;
+		if (*sep == '\0')
+			break;
+		t = sep + 1;
+	}
+
+	max_len += 2;
+	nr_lines += 8;
+	y = SLtt_Screen_Rows / 2 - nr_lines / 2;
+	x = SLtt_Screen_Cols / 2 - max_len / 2;
+
+	SLsmg_set_color(0);
+	SLsmg_draw_box(y, x++, nr_lines, max_len);
+	if (title) {
+		SLsmg_gotorc(y, x + 1);
+		SLsmg_write_string((char *)title);
+	}
+	SLsmg_gotorc(++y, x);
+	nr_lines -= 7;
+	max_len -= 2;
+	SLsmg_write_wrapped_string((unsigned char *)text, y, x,
+				   nr_lines, max_len, 1);
+	y += nr_lines;
+	len = 5;
+	while (len--) {
+		SLsmg_gotorc(y + len - 1, x);
+		SLsmg_write_nstring((char *)" ", max_len);
+	}
+	SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
+
+	SLsmg_gotorc(y + 3, x);
+	SLsmg_write_nstring((char *)exit_msg, max_len);
+	SLsmg_refresh();
+
+	x += 2;
+	len = 0;
+	key = ui__getch(delay_secs);
+	while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
+		if (key == K_BKSPC) {
+			if (len == 0)
+				goto next_key;
+			SLsmg_gotorc(y, x + --len);
+			SLsmg_write_char(' ');
+		} else {
+			buf[len] = key;
+			SLsmg_gotorc(y, x + len++);
+			SLsmg_write_char(key);
+		}
+		SLsmg_refresh();
+
+		/* XXX more graceful overflow handling needed */
+		if (len == sizeof(buf) - 1) {
+			ui_helpline__push("maximum size of symbol name reached!");
+			key = K_ENTER;
+			break;
+		}
+next_key:
+		key = ui__getch(delay_secs);
+	}
+
+	buf[len] = '\0';
+	strncpy(input, buf, len+1);
+	return key;
+}
+
+int ui__question_window(const char *title, const char *text,
+			const char *exit_msg, int delay_secs)
+{
+	int x, y;
+	int max_len = 0, nr_lines = 0;
+	const char *t;
+
+	t = text;
+	while (1) {
+		const char *sep = strchr(t, '\n');
+		int len;
+
+		if (sep == NULL)
+			sep = strchr(t, '\0');
+		len = sep - t;
+		if (max_len < len)
+			max_len = len;
+		++nr_lines;
+		if (*sep == '\0')
+			break;
+		t = sep + 1;
+	}
+
+	max_len += 2;
+	nr_lines += 4;
+	y = SLtt_Screen_Rows / 2 - nr_lines / 2,
+	x = SLtt_Screen_Cols / 2 - max_len / 2;
+
+	SLsmg_set_color(0);
+	SLsmg_draw_box(y, x++, nr_lines, max_len);
+	if (title) {
+		SLsmg_gotorc(y, x + 1);
+		SLsmg_write_string((char *)title);
+	}
+	SLsmg_gotorc(++y, x);
+	nr_lines -= 2;
+	max_len -= 2;
+	SLsmg_write_wrapped_string((unsigned char *)text, y, x,
+				   nr_lines, max_len, 1);
+	SLsmg_gotorc(y + nr_lines - 2, x);
+	SLsmg_write_nstring((char *)" ", max_len);
+	SLsmg_gotorc(y + nr_lines - 1, x);
+	SLsmg_write_nstring((char *)exit_msg, max_len);
+	SLsmg_refresh();
+	return ui__getch(delay_secs);
+}
+
+int ui__help_window(const char *text)
+{
+	return ui__question_window("Help", text, "Press any key...", 0);
+}
+
+int ui__dialog_yesno(const char *msg)
+{
+	return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
+}
+
+static int __ui__warning(const char *title, const char *format, va_list args)
+{
+	char *s;
+
+	if (vasprintf(&s, format, args) > 0) {
+		int key;
+
+		pthread_mutex_lock(&ui__lock);
+		key = ui__question_window(title, s, "Press any key...", 0);
+		pthread_mutex_unlock(&ui__lock);
+		free(s);
+		return key;
+	}
+
+	fprintf(stderr, "%s\n", title);
+	vfprintf(stderr, format, args);
+	return K_ESC;
+}
+
+static int perf_tui__error(const char *format, va_list args)
+{
+	return __ui__warning("Error:", format, args);
+}
+
+static int perf_tui__warning(const char *format, va_list args)
+{
+	return __ui__warning("Warning:", format, args);
+}
+
+struct perf_error_ops perf_tui_eops = {
+	.error		= perf_tui__error,
+	.warning	= perf_tui__warning,
+};
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c
index ad4374a..4f98977 100644
--- a/tools/perf/ui/util.c
+++ b/tools/perf/ui/util.c
@@ -1,250 +1,85 @@
-#include "../util.h"
-#include <signal.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/ttydefaults.h>
-
-#include "../cache.h"
-#include "../debug.h"
-#include "browser.h"
-#include "keysyms.h"
-#include "helpline.h"
-#include "ui.h"
 #include "util.h"
-#include "libslang.h"
-
-static void ui_browser__argv_write(struct ui_browser *browser,
-				   void *entry, int row)
-{
-	char **arg = entry;
-	bool current_entry = ui_browser__is_current_entry(browser, row);
-
-	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
-						       HE_COLORSET_NORMAL);
-	slsmg_write_nstring(*arg, browser->width);
-}
-
-static int popup_menu__run(struct ui_browser *menu)
-{
-	int key;
-
-	if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
-		return -1;
+#include "../debug.h"
 
-	while (1) {
-		key = ui_browser__run(menu, 0);
-
-		switch (key) {
-		case K_RIGHT:
-		case K_ENTER:
-			key = menu->index;
-			break;
-		case K_LEFT:
-		case K_ESC:
-		case 'q':
-		case CTRL('c'):
-			key = -1;
-			break;
-		default:
-			continue;
-		}
-
-		break;
-	}
-
-	ui_browser__hide(menu);
-	return key;
-}
 
-int ui__popup_menu(int argc, char * const argv[])
+/*
+ * Default error logging functions
+ */
+static int perf_stdio__error(const char *format, va_list args)
 {
-	struct ui_browser menu = {
-		.entries    = (void *)argv,
-		.refresh    = ui_browser__argv_refresh,
-		.seek	    = ui_browser__argv_seek,
-		.write	    = ui_browser__argv_write,
-		.nr_entries = argc,
-	};
-
-	return popup_menu__run(&menu);
+	fprintf(stderr, "Error:\n");
+	vfprintf(stderr, format, args);
+	return 0;
 }
 
-int ui_browser__input_window(const char *title, const char *text, char *input,
-			     const char *exit_msg, int delay_secs)
+static int perf_stdio__warning(const char *format, va_list args)
 {
-	int x, y, len, key;
-	int max_len = 60, nr_lines = 0;
-	static char buf[50];
-	const char *t;
-
-	t = text;
-	while (1) {
-		const char *sep = strchr(t, '\n');
-
-		if (sep == NULL)
-			sep = strchr(t, '\0');
-		len = sep - t;
-		if (max_len < len)
-			max_len = len;
-		++nr_lines;
-		if (*sep == '\0')
-			break;
-		t = sep + 1;
-	}
-
-	max_len += 2;
-	nr_lines += 8;
-	y = SLtt_Screen_Rows / 2 - nr_lines / 2;
-	x = SLtt_Screen_Cols / 2 - max_len / 2;
-
-	SLsmg_set_color(0);
-	SLsmg_draw_box(y, x++, nr_lines, max_len);
-	if (title) {
-		SLsmg_gotorc(y, x + 1);
-		SLsmg_write_string((char *)title);
-	}
-	SLsmg_gotorc(++y, x);
-	nr_lines -= 7;
-	max_len -= 2;
-	SLsmg_write_wrapped_string((unsigned char *)text, y, x,
-				   nr_lines, max_len, 1);
-	y += nr_lines;
-	len = 5;
-	while (len--) {
-		SLsmg_gotorc(y + len - 1, x);
-		SLsmg_write_nstring((char *)" ", max_len);
-	}
-	SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
-
-	SLsmg_gotorc(y + 3, x);
-	SLsmg_write_nstring((char *)exit_msg, max_len);
-	SLsmg_refresh();
-
-	x += 2;
-	len = 0;
-	key = ui__getch(delay_secs);
-	while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
-		if (key == K_BKSPC) {
-			if (len == 0)
-				goto next_key;
-			SLsmg_gotorc(y, x + --len);
-			SLsmg_write_char(' ');
-		} else {
-			buf[len] = key;
-			SLsmg_gotorc(y, x + len++);
-			SLsmg_write_char(key);
-		}
-		SLsmg_refresh();
-
-		/* XXX more graceful overflow handling needed */
-		if (len == sizeof(buf) - 1) {
-			ui_helpline__push("maximum size of symbol name reached!");
-			key = K_ENTER;
-			break;
-		}
-next_key:
-		key = ui__getch(delay_secs);
-	}
-
-	buf[len] = '\0';
-	strncpy(input, buf, len+1);
-	return key;
+	fprintf(stderr, "Warning:\n");
+	vfprintf(stderr, format, args);
+	return 0;
 }
 
-int ui__question_window(const char *title, const char *text,
-			const char *exit_msg, int delay_secs)
+static struct perf_error_ops default_eops =
 {
-	int x, y;
-	int max_len = 0, nr_lines = 0;
-	const char *t;
-
-	t = text;
-	while (1) {
-		const char *sep = strchr(t, '\n');
-		int len;
-
-		if (sep == NULL)
-			sep = strchr(t, '\0');
-		len = sep - t;
-		if (max_len < len)
-			max_len = len;
-		++nr_lines;
-		if (*sep == '\0')
-			break;
-		t = sep + 1;
-	}
-
-	max_len += 2;
-	nr_lines += 4;
-	y = SLtt_Screen_Rows / 2 - nr_lines / 2,
-	x = SLtt_Screen_Cols / 2 - max_len / 2;
-
-	SLsmg_set_color(0);
-	SLsmg_draw_box(y, x++, nr_lines, max_len);
-	if (title) {
-		SLsmg_gotorc(y, x + 1);
-		SLsmg_write_string((char *)title);
-	}
-	SLsmg_gotorc(++y, x);
-	nr_lines -= 2;
-	max_len -= 2;
-	SLsmg_write_wrapped_string((unsigned char *)text, y, x,
-				   nr_lines, max_len, 1);
-	SLsmg_gotorc(y + nr_lines - 2, x);
-	SLsmg_write_nstring((char *)" ", max_len);
-	SLsmg_gotorc(y + nr_lines - 1, x);
-	SLsmg_write_nstring((char *)exit_msg, max_len);
-	SLsmg_refresh();
-	return ui__getch(delay_secs);
-}
+	.error		= perf_stdio__error,
+	.warning	= perf_stdio__warning,
+};
 
-int ui__help_window(const char *text)
-{
-	return ui__question_window("Help", text, "Press any key...", 0);
-}
+static struct perf_error_ops *perf_eops = &default_eops;
 
-int ui__dialog_yesno(const char *msg)
-{
-	return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
-}
 
-int __ui__warning(const char *title, const char *format, va_list args)
+int ui__error(const char *format, ...)
 {
-	char *s;
-
-	if (use_browser > 0 && vasprintf(&s, format, args) > 0) {
-		int key;
+	int ret;
+	va_list args;
 
-		pthread_mutex_lock(&ui__lock);
-		key = ui__question_window(title, s, "Press any key...", 0);
-		pthread_mutex_unlock(&ui__lock);
-		free(s);
-		return key;
-	}
+	va_start(args, format);
+	ret = perf_eops->error(format, args);
+	va_end(args);
 
-	fprintf(stderr, "%s:\n", title);
-	vfprintf(stderr, format, args);
-	return K_ESC;
+	return ret;
 }
 
 int ui__warning(const char *format, ...)
 {
-	int key;
+	int ret;
 	va_list args;
 
 	va_start(args, format);
-	key = __ui__warning("Warning", format, args);
+	ret = perf_eops->warning(format, args);
 	va_end(args);
-	return key;
+
+	return ret;
 }
 
-int ui__error(const char *format, ...)
+
+/**
+ * perf_error__register - Register error logging functions
+ * @eops: The pointer to error logging function struct
+ *
+ * Register UI-specific error logging functions. Before calling this,
+ * other logging functions should be unregistered, if any.
+ */
+int perf_error__register(struct perf_error_ops *eops)
 {
-	int key;
-	va_list args;
+	if (perf_eops != &default_eops)
+		return -1;
 
-	va_start(args, format);
-	key = __ui__warning("Error", format, args);
-	va_end(args);
-	return key;
+	perf_eops = eops;
+	return 0;
+}
+
+/**
+ * perf_error__unregister - Unregister error logging functions
+ * @eops: The pointer to error logging function struct
+ *
+ * Unregister already registered error logging functions.
+ */
+int perf_error__unregister(struct perf_error_ops *eops)
+{
+	if (perf_eops != eops)
+		return -1;
+
+	perf_eops = &default_eops;
+	return 0;
 }
diff --git a/tools/perf/ui/util.h b/tools/perf/ui/util.h
index 2d1738b..361f08c 100644
--- a/tools/perf/ui/util.h
+++ b/tools/perf/ui/util.h
@@ -9,6 +9,13 @@ int ui__help_window(const char *text);
 int ui__dialog_yesno(const char *msg);
 int ui__question_window(const char *title, const char *text,
 			const char *exit_msg, int delay_secs);
-int __ui__warning(const char *title, const char *format, va_list args);
+
+struct perf_error_ops {
+	int (*error)(const char *format, va_list args);
+	int (*warning)(const char *format, va_list args);
+};
+
+int perf_error__register(struct perf_error_ops *eops);
+int perf_error__unregister(struct perf_error_ops *eops);
 
 #endif /* _PERF_UI_UTIL_H_ */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index efb1fce..4dfe0bb 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -47,7 +47,7 @@ int dump_printf(const char *fmt, ...)
 	return ret;
 }
 
-#ifdef NO_NEWT_SUPPORT
+#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
 int ui__warning(const char *format, ...)
 {
 	va_list args;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 6bebe7f..015c91d 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -12,8 +12,9 @@ int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 void trace_event(union perf_event *event);
 
 struct ui_progress;
+struct perf_error_ops;
 
-#ifdef NO_NEWT_SUPPORT
+#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
 static inline int ui_helpline__show_help(const char *format __used, va_list ap __used)
 {
 	return 0;
@@ -23,12 +24,28 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used,
 				       const char *title __used) {}
 
 #define ui__error(format, arg...) ui__warning(format, ##arg)
-#else
+
+static inline int
+perf_error__register(struct perf_error_ops *eops __used)
+{
+	return 0;
+}
+
+static inline int
+perf_error__unregister(struct perf_error_ops *eops __used)
+{
+	return 0;
+}
+
+#else /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
+
 extern char ui_helpline__last_msg[];
 int ui_helpline__show_help(const char *format, va_list ap);
 #include "../ui/progress.h"
 int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
-#endif
+#include "../ui/util.h"
+
+#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
 
 int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
 int ui__error_paranoid(void);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 9f6cebd..876f639 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -78,7 +78,7 @@ static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
 	"ref-cycles",
 };
 
-const char *__perf_evsel__hw_name(u64 config)
+static const char *__perf_evsel__hw_name(u64 config)
 {
 	if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config])
 		return perf_evsel__hw_names[config];
@@ -86,16 +86,15 @@ const char *__perf_evsel__hw_name(u64 config)
 	return "unknown-hardware";
 }
 
-static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
+static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size)
 {
-	int colon = 0;
+	int colon = 0, r = 0;
 	struct perf_event_attr *attr = &evsel->attr;
-	int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(attr->config));
 	bool exclude_guest_default = false;
 
 #define MOD_PRINT(context, mod)	do {					\
 		if (!attr->exclude_##context) {				\
-			if (!colon) colon = r++;			\
+			if (!colon) colon = ++r;			\
 			r += scnprintf(bf + r, size - r, "%c", mod);	\
 		} } while(0)
 
@@ -108,7 +107,7 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
 
 	if (attr->precise_ip) {
 		if (!colon)
-			colon = r++;
+			colon = ++r;
 		r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp");
 		exclude_guest_default = true;
 	}
@@ -119,39 +118,182 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
 	}
 #undef MOD_PRINT
 	if (colon)
-		bf[colon] = ':';
+		bf[colon - 1] = ':';
 	return r;
 }
 
-int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
+static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+	int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config));
+	return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
+}
+
+static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
+	"cpu-clock",
+	"task-clock",
+	"page-faults",
+	"context-switches",
+	"CPU-migrations",
+	"minor-faults",
+	"major-faults",
+	"alignment-faults",
+	"emulation-faults",
+};
+
+static const char *__perf_evsel__sw_name(u64 config)
+{
+	if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config])
+		return perf_evsel__sw_names[config];
+	return "unknown-software";
+}
+
+static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+	int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config));
+	return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
+}
+
+const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_EVSEL__MAX_ALIASES] = {
+ { "L1-dcache",	"l1-d",		"l1d",		"L1-data",		},
+ { "L1-icache",	"l1-i",		"l1i",		"L1-instruction",	},
+ { "LLC",	"L2",							},
+ { "dTLB",	"d-tlb",	"Data-TLB",				},
+ { "iTLB",	"i-tlb",	"Instruction-TLB",			},
+ { "branch",	"branches",	"bpu",		"btb",		"bpc",	},
+ { "node",								},
+};
+
+const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
+				   [PERF_EVSEL__MAX_ALIASES] = {
+ { "load",	"loads",	"read",					},
+ { "store",	"stores",	"write",				},
+ { "prefetch",	"prefetches",	"speculative-read", "speculative-load",	},
+};
+
+const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
+				       [PERF_EVSEL__MAX_ALIASES] = {
+ { "refs",	"Reference",	"ops",		"access",		},
+ { "misses",	"miss",							},
+};
+
+#define C(x)		PERF_COUNT_HW_CACHE_##x
+#define CACHE_READ	(1 << C(OP_READ))
+#define CACHE_WRITE	(1 << C(OP_WRITE))
+#define CACHE_PREFETCH	(1 << C(OP_PREFETCH))
+#define COP(x)		(1 << x)
+
+/*
+ * cache operartion stat
+ * L1I : Read and prefetch only
+ * ITLB and BPU : Read-only
+ */
+static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = {
+ [C(L1D)]	= (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(L1I)]	= (CACHE_READ | CACHE_PREFETCH),
+ [C(LL)]	= (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(DTLB)]	= (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(ITLB)]	= (CACHE_READ),
+ [C(BPU)]	= (CACHE_READ),
+ [C(NODE)]	= (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+};
+
+bool perf_evsel__is_cache_op_valid(u8 type, u8 op)
+{
+	if (perf_evsel__hw_cache_stat[type] & COP(op))
+		return true;	/* valid */
+	else
+		return false;	/* invalid */
+}
+
+int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
+					    char *bf, size_t size)
+{
+	if (result) {
+		return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0],
+				 perf_evsel__hw_cache_op[op][0],
+				 perf_evsel__hw_cache_result[result][0]);
+	}
+
+	return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0],
+			 perf_evsel__hw_cache_op[op][1]);
+}
+
+static int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size)
 {
-	int ret;
+	u8 op, result, type = (config >>  0) & 0xff;
+	const char *err = "unknown-ext-hardware-cache-type";
+
+	if (type > PERF_COUNT_HW_CACHE_MAX)
+		goto out_err;
+
+	op = (config >>  8) & 0xff;
+	err = "unknown-ext-hardware-cache-op";
+	if (op > PERF_COUNT_HW_CACHE_OP_MAX)
+		goto out_err;
+
+	result = (config >> 16) & 0xff;
+	err = "unknown-ext-hardware-cache-result";
+	if (result > PERF_COUNT_HW_CACHE_RESULT_MAX)
+		goto out_err;
+
+	err = "invalid-cache";
+	if (!perf_evsel__is_cache_op_valid(type, op))
+		goto out_err;
+
+	return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size);
+out_err:
+	return scnprintf(bf, size, "%s", err);
+}
+
+static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+	int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size);
+	return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
+}
+
+static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+	int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
+	return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
+}
+
+const char *perf_evsel__name(struct perf_evsel *evsel)
+{
+	char bf[128];
+
+	if (evsel->name)
+		return evsel->name;
 
 	switch (evsel->attr.type) {
 	case PERF_TYPE_RAW:
-		ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
+		perf_evsel__raw_name(evsel, bf, sizeof(bf));
 		break;
 
 	case PERF_TYPE_HARDWARE:
-		ret = perf_evsel__hw_name(evsel, bf, size);
+		perf_evsel__hw_name(evsel, bf, sizeof(bf));
+		break;
+
+	case PERF_TYPE_HW_CACHE:
+		perf_evsel__hw_cache_name(evsel, bf, sizeof(bf));
+		break;
+
+	case PERF_TYPE_SOFTWARE:
+		perf_evsel__sw_name(evsel, bf, sizeof(bf));
 		break;
+
+	case PERF_TYPE_TRACEPOINT:
+		scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint");
+		break;
+
 	default:
-		/*
-		 * FIXME
- 		 *
-		 * This is the minimal perf_evsel__name so that we can
-		 * reconstruct event names taking into account event modifiers.
-		 *
-		 * The old event_name uses it now for raw anr hw events, so that
-		 * we don't drag all the parsing stuff into the python binding.
-		 *
-		 * On the next devel cycle the rest of the event naming will be
-		 * brought here.
- 		 */
-		return 0;
-	}
-
-	return ret;
+		scnprintf(bf, sizeof(bf), "%s", "unknown attr type");
+		break;
+	}
+
+	evsel->name = strdup(bf);
+
+	return evsel->name ?: "unknown";
 }
 
 void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 4ba8b56..67cc503 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -83,8 +83,19 @@ void perf_evsel__config(struct perf_evsel *evsel,
 			struct perf_record_opts *opts,
 			struct perf_evsel *first);
 
-const char* __perf_evsel__hw_name(u64 config);
-int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size);
+bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
+
+#define PERF_EVSEL__MAX_ALIASES 8
+
+extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
+				       [PERF_EVSEL__MAX_ALIASES];
+extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
+					  [PERF_EVSEL__MAX_ALIASES];
+const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
+				       [PERF_EVSEL__MAX_ALIASES];
+int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
+					    char *bf, size_t size);
+const char *perf_evsel__name(struct perf_evsel *evsel);
 
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index e909d43..a5e2015 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -641,7 +641,7 @@ static int write_event_desc(int fd, struct perf_header *h __used,
 		/*
 		 * write event string as passed on cmdline
 		 */
-		ret = do_write_string(fd, event_name(attr));
+		ret = do_write_string(fd, perf_evsel__name(attr));
 		if (ret < 0)
 			return ret;
 		/*
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 34bb556..0b096c2 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -47,6 +47,7 @@ enum hist_column {
 	HISTC_SYMBOL_TO,
 	HISTC_DSO_FROM,
 	HISTC_DSO_TO,
+	HISTC_SRCLINE,
 	HISTC_NR_COLS, /* Last entry */
 };
 
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 81371ba..c14c665 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -157,7 +157,7 @@ void machine__exit(struct machine *self);
 void machine__delete(struct machine *self);
 
 int machine__resolve_callchain(struct machine *machine,
-			       struct perf_evsel *evsel, struct thread *thread,
+			       struct thread *thread,
 			       struct ip_callchain *chain,
 			       struct symbol **parent);
 int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
index 76b98e2..229af6d 100644
--- a/tools/perf/util/parse-events-test.c
+++ b/tools/perf/util/parse-events-test.c
@@ -418,14 +418,57 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
 	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
 	TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
+	TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "krava"));
 
 	/* cpu/config=2/" */
 	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
 	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
 	TEST_ASSERT_VAL("wrong config",  2 == evsel->attr.config);
-	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2"));
+	TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "raw 0x2"));
+
+	return 0;
+}
+
+static int test__checkterms_simple(struct list_head *terms)
+{
+	struct parse_events__term *term;
+
+	/* config=10 */
+	term = list_entry(terms->next, struct parse_events__term, list);
+	TEST_ASSERT_VAL("wrong type term",
+			term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG);
+	TEST_ASSERT_VAL("wrong type val",
+			term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+	TEST_ASSERT_VAL("wrong val", term->val.num == 10);
+	TEST_ASSERT_VAL("wrong config", !term->config);
+
+	/* config1 */
+	term = list_entry(term->list.next, struct parse_events__term, list);
+	TEST_ASSERT_VAL("wrong type term",
+			term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1);
+	TEST_ASSERT_VAL("wrong type val",
+			term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+	TEST_ASSERT_VAL("wrong val", term->val.num == 1);
+	TEST_ASSERT_VAL("wrong config", !term->config);
+
+	/* config2=3 */
+	term = list_entry(term->list.next, struct parse_events__term, list);
+	TEST_ASSERT_VAL("wrong type term",
+			term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2);
+	TEST_ASSERT_VAL("wrong type val",
+			term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+	TEST_ASSERT_VAL("wrong val", term->val.num == 3);
+	TEST_ASSERT_VAL("wrong config", !term->config);
+
+	/* umask=1*/
+	term = list_entry(term->list.next, struct parse_events__term, list);
+	TEST_ASSERT_VAL("wrong type term",
+			term->type_term == PARSE_EVENTS__TERM_TYPE_USER);
+	TEST_ASSERT_VAL("wrong type val",
+			term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+	TEST_ASSERT_VAL("wrong val", term->val.num == 1);
+	TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "umask"));
 
 	return 0;
 }
@@ -559,7 +602,23 @@ static struct test__event_st test__events_pmu[] = {
 #define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \
 			      sizeof(struct test__event_st))
 
-static int test(struct test__event_st *e)
+struct test__term {
+	const char *str;
+	__u32 type;
+	int (*check)(struct list_head *terms);
+};
+
+static struct test__term test__terms[] = {
+	[0] = {
+		.str   = "config=10,config1,config2=3,umask=1",
+		.check = test__checkterms_simple,
+	},
+};
+
+#define TEST__TERMS_CNT (sizeof(test__terms) / \
+			 sizeof(struct test__term))
+
+static int test_event(struct test__event_st *e)
 {
 	struct perf_evlist *evlist;
 	int ret;
@@ -590,7 +649,48 @@ static int test_events(struct test__event_st *events, unsigned cnt)
 		struct test__event_st *e = &events[i];
 
 		pr_debug("running test %d '%s'\n", i, e->name);
-		ret = test(e);
+		ret = test_event(e);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static int test_term(struct test__term *t)
+{
+	struct list_head *terms;
+	int ret;
+
+	terms = malloc(sizeof(*terms));
+	if (!terms)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(terms);
+
+	ret = parse_events_terms(terms, t->str);
+	if (ret) {
+		pr_debug("failed to parse terms '%s', err %d\n",
+			 t->str , ret);
+		return ret;
+	}
+
+	ret = t->check(terms);
+	parse_events__free_terms(terms);
+
+	return ret;
+}
+
+static int test_terms(struct test__term *terms, unsigned cnt)
+{
+	int ret = 0;
+	unsigned i;
+
+	for (i = 0; i < cnt; i++) {
+		struct test__term *t = &terms[i];
+
+		pr_debug("running test %d '%s'\n", i, t->str);
+		ret = test_term(t);
 		if (ret)
 			break;
 	}
@@ -617,9 +717,21 @@ int parse_events__test(void)
 {
 	int ret;
 
-	ret = test_events(test__events, TEST__EVENTS_CNT);
-	if (!ret && test_pmu())
-		ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT);
+	do {
+		ret = test_events(test__events, TEST__EVENTS_CNT);
+		if (ret)
+			break;
+
+		if (test_pmu()) {
+			ret = test_events(test__events_pmu,
+					  TEST__EVENTS_PMU_CNT);
+			if (ret)
+				break;
+		}
+
+		ret = test_terms(test__terms, TEST__TERMS_CNT);
+
+	} while (0);
 
 	return ret;
 }
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 05dbc8b..0cc27da 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -11,6 +11,8 @@
 #include "cache.h"
 #include "header.h"
 #include "debugfs.h"
+#include "parse-events-bison.h"
+#define YY_EXTRA_TYPE int
 #include "parse-events-flex.h"
 #include "pmu.h"
 
@@ -26,7 +28,7 @@ struct event_symbol {
 #ifdef PARSER_DEBUG
 extern int parse_events_debug;
 #endif
-int parse_events_parse(struct list_head *list, int *idx);
+int parse_events_parse(void *data, void *scanner);
 
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -62,63 +64,6 @@ static struct event_symbol event_symbols[] = {
 #define PERF_EVENT_TYPE(config)		__PERF_EVENT_FIELD(config, TYPE)
 #define PERF_EVENT_ID(config)		__PERF_EVENT_FIELD(config, EVENT)
 
-static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
-	"cpu-clock",
-	"task-clock",
-	"page-faults",
-	"context-switches",
-	"CPU-migrations",
-	"minor-faults",
-	"major-faults",
-	"alignment-faults",
-	"emulation-faults",
-};
-
-#define MAX_ALIASES 8
-
-static const char *hw_cache[PERF_COUNT_HW_CACHE_MAX][MAX_ALIASES] = {
- { "L1-dcache",	"l1-d",		"l1d",		"L1-data",		},
- { "L1-icache",	"l1-i",		"l1i",		"L1-instruction",	},
- { "LLC",	"L2",							},
- { "dTLB",	"d-tlb",	"Data-TLB",				},
- { "iTLB",	"i-tlb",	"Instruction-TLB",			},
- { "branch",	"branches",	"bpu",		"btb",		"bpc",	},
- { "node",								},
-};
-
-static const char *hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][MAX_ALIASES] = {
- { "load",	"loads",	"read",					},
- { "store",	"stores",	"write",				},
- { "prefetch",	"prefetches",	"speculative-read", "speculative-load",	},
-};
-
-static const char *hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
-				  [MAX_ALIASES] = {
- { "refs",	"Reference",	"ops",		"access",		},
- { "misses",	"miss",							},
-};
-
-#define C(x)		PERF_COUNT_HW_CACHE_##x
-#define CACHE_READ	(1 << C(OP_READ))
-#define CACHE_WRITE	(1 << C(OP_WRITE))
-#define CACHE_PREFETCH	(1 << C(OP_PREFETCH))
-#define COP(x)		(1 << x)
-
-/*
- * cache operartion stat
- * L1I : Read and prefetch only
- * ITLB and BPU : Read-only
- */
-static unsigned long hw_cache_stat[C(MAX)] = {
- [C(L1D)]	= (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(L1I)]	= (CACHE_READ | CACHE_PREFETCH),
- [C(LL)]	= (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(DTLB)]	= (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(ITLB)]	= (CACHE_READ),
- [C(BPU)]	= (CACHE_READ),
- [C(NODE)]	= (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
-};
-
 #define for_each_subsystem(sys_dir, sys_dirent, sys_next)	       \
 	while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next)	       \
 	if (sys_dirent.d_type == DT_DIR &&				       \
@@ -218,48 +163,6 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
 	return NULL;
 }
 
-#define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1)
-static const char *tracepoint_id_to_name(u64 config)
-{
-	static char buf[TP_PATH_LEN];
-	struct tracepoint_path *path;
-
-	path = tracepoint_id_to_path(config);
-	if (path) {
-		snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name);
-		free(path->name);
-		free(path->system);
-		free(path);
-	} else
-		snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown");
-
-	return buf;
-}
-
-static int is_cache_op_valid(u8 cache_type, u8 cache_op)
-{
-	if (hw_cache_stat[cache_type] & COP(cache_op))
-		return 1;	/* valid */
-	else
-		return 0;	/* invalid */
-}
-
-static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
-{
-	static char name[50];
-
-	if (cache_result) {
-		sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
-			hw_cache_op[cache_op][0],
-			hw_cache_result[cache_result][0]);
-	} else {
-		sprintf(name, "%s-%s", hw_cache[cache_type][0],
-			hw_cache_op[cache_op][1]);
-	}
-
-	return name;
-}
-
 const char *event_type(int type)
 {
 	switch (type) {
@@ -282,76 +185,6 @@ const char *event_type(int type)
 	return "unknown";
 }
 
-const char *event_name(struct perf_evsel *evsel)
-{
-	u64 config = evsel->attr.config;
-	int type = evsel->attr.type;
-
-	if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE) {
-		/*
- 		 * XXX minimal fix, see comment on perf_evsen__name, this static buffer
- 		 * will go away together with event_name in the next devel cycle.
- 		 */
-		static char bf[128];
-		perf_evsel__name(evsel, bf, sizeof(bf));
-		return bf;
-	}
-
-	if (evsel->name)
-		return evsel->name;
-
-	return __event_name(type, config);
-}
-
-const char *__event_name(int type, u64 config)
-{
-	static char buf[32];
-
-	if (type == PERF_TYPE_RAW) {
-		sprintf(buf, "raw 0x%" PRIx64, config);
-		return buf;
-	}
-
-	switch (type) {
-	case PERF_TYPE_HARDWARE:
-		return __perf_evsel__hw_name(config);
-
-	case PERF_TYPE_HW_CACHE: {
-		u8 cache_type, cache_op, cache_result;
-
-		cache_type   = (config >>  0) & 0xff;
-		if (cache_type > PERF_COUNT_HW_CACHE_MAX)
-			return "unknown-ext-hardware-cache-type";
-
-		cache_op     = (config >>  8) & 0xff;
-		if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
-			return "unknown-ext-hardware-cache-op";
-
-		cache_result = (config >> 16) & 0xff;
-		if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
-			return "unknown-ext-hardware-cache-result";
-
-		if (!is_cache_op_valid(cache_type, cache_op))
-			return "invalid-cache";
-
-		return event_cache_name(cache_type, cache_op, cache_result);
-	}
-
-	case PERF_TYPE_SOFTWARE:
-		if (config < PERF_COUNT_SW_MAX && sw_event_names[config])
-			return sw_event_names[config];
-		return "unknown-software";
-
-	case PERF_TYPE_TRACEPOINT:
-		return tracepoint_id_to_name(config);
-
-	default:
-		break;
-	}
-
-	return "unknown";
-}
-
 static int add_event(struct list_head **_list, int *idx,
 		     struct perf_event_attr *attr, char *name)
 {
@@ -373,19 +206,20 @@ static int add_event(struct list_head **_list, int *idx,
 		return -ENOMEM;
 	}
 
-	evsel->name = strdup(name);
+	if (name)
+		evsel->name = strdup(name);
 	list_add_tail(&evsel->node, list);
 	*_list = list;
 	return 0;
 }
 
-static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
+static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
 {
 	int i, j;
 	int n, longest = -1;
 
 	for (i = 0; i < size; i++) {
-		for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
+		for (j = 0; j < PERF_EVSEL__MAX_ALIASES && names[i][j]; j++) {
 			n = strlen(names[i][j]);
 			if (n > longest && !strncasecmp(str, names[i][j], n))
 				longest = n;
@@ -410,7 +244,7 @@ int parse_events_add_cache(struct list_head **list, int *idx,
 	 * No fallback - if we cannot get a clear cache type
 	 * then bail out:
 	 */
-	cache_type = parse_aliases(type, hw_cache,
+	cache_type = parse_aliases(type, perf_evsel__hw_cache,
 				   PERF_COUNT_HW_CACHE_MAX);
 	if (cache_type == -1)
 		return -EINVAL;
@@ -423,18 +257,18 @@ int parse_events_add_cache(struct list_head **list, int *idx,
 		snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
 
 		if (cache_op == -1) {
-			cache_op = parse_aliases(str, hw_cache_op,
+			cache_op = parse_aliases(str, perf_evsel__hw_cache_op,
 						 PERF_COUNT_HW_CACHE_OP_MAX);
 			if (cache_op >= 0) {
-				if (!is_cache_op_valid(cache_type, cache_op))
+				if (!perf_evsel__is_cache_op_valid(cache_type, cache_op))
 					return -EINVAL;
 				continue;
 			}
 		}
 
 		if (cache_result == -1) {
-			cache_result = parse_aliases(str, hw_cache_result,
-						PERF_COUNT_HW_CACHE_RESULT_MAX);
+			cache_result = parse_aliases(str, perf_evsel__hw_cache_result,
+						     PERF_COUNT_HW_CACHE_RESULT_MAX);
 			if (cache_result >= 0)
 				continue;
 		}
@@ -666,8 +500,7 @@ int parse_events_add_numeric(struct list_head **list, int *idx,
 	    config_attr(&attr, head_config, 1))
 		return -EINVAL;
 
-	return add_event(list, idx, &attr,
-			 (char *) __event_name(type, config));
+	return add_event(list, idx, &attr, NULL);
 }
 
 static int parse_events__is_name_term(struct parse_events__term *term)
@@ -675,8 +508,7 @@ static int parse_events__is_name_term(struct parse_events__term *term)
 	return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
 }
 
-static char *pmu_event_name(struct perf_event_attr *attr,
-			    struct list_head *head_terms)
+static char *pmu_event_name(struct list_head *head_terms)
 {
 	struct parse_events__term *term;
 
@@ -684,7 +516,7 @@ static char *pmu_event_name(struct perf_event_attr *attr,
 		if (parse_events__is_name_term(term))
 			return term->val.str;
 
-	return (char *) __event_name(PERF_TYPE_RAW, attr->config);
+	return NULL;
 }
 
 int parse_events_add_pmu(struct list_head **list, int *idx,
@@ -699,6 +531,9 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
 
 	memset(&attr, 0, sizeof(attr));
 
+	if (perf_pmu__check_alias(pmu, head_config))
+		return -EINVAL;
+
 	/*
 	 * Configure hardcoded terms first, no need to check
 	 * return value when called with fail == 0 ;)
@@ -709,7 +544,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
 		return -EINVAL;
 
 	return add_event(list, idx, &attr,
-			 pmu_event_name(&attr, head_config));
+			 pmu_event_name(head_config));
 }
 
 void parse_events_update_lists(struct list_head *list_event,
@@ -787,27 +622,62 @@ int parse_events_modifier(struct list_head *list, char *str)
 	return 0;
 }
 
-int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
+static int parse_events__scanner(const char *str, void *data, int start_token)
 {
-	LIST_HEAD(list);
-	LIST_HEAD(list_tmp);
 	YY_BUFFER_STATE buffer;
-	int ret, idx = evlist->nr_entries;
+	void *scanner;
+	int ret;
 
-	buffer = parse_events__scan_string(str);
+	ret = parse_events_lex_init_extra(start_token, &scanner);
+	if (ret)
+		return ret;
+
+	buffer = parse_events__scan_string(str, scanner);
 
 #ifdef PARSER_DEBUG
 	parse_events_debug = 1;
 #endif
-	ret = parse_events_parse(&list, &idx);
+	ret = parse_events_parse(data, scanner);
 
-	parse_events__flush_buffer(buffer);
-	parse_events__delete_buffer(buffer);
-	parse_events_lex_destroy();
+	parse_events__flush_buffer(buffer, scanner);
+	parse_events__delete_buffer(buffer, scanner);
+	parse_events_lex_destroy(scanner);
+	return ret;
+}
+
+/*
+ * parse event config string, return a list of event terms.
+ */
+int parse_events_terms(struct list_head *terms, const char *str)
+{
+	struct parse_events_data__terms data = {
+		.terms = NULL,
+	};
+	int ret;
+
+	ret = parse_events__scanner(str, &data, PE_START_TERMS);
+	if (!ret) {
+		list_splice(data.terms, terms);
+		free(data.terms);
+		return 0;
+	}
+
+	parse_events__free_terms(data.terms);
+	return ret;
+}
+
+int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
+{
+	struct parse_events_data__events data = {
+		.list = LIST_HEAD_INIT(data.list),
+		.idx  = evlist->nr_entries,
+	};
+	int ret;
 
+	ret = parse_events__scanner(str, &data, PE_START_EVENTS);
 	if (!ret) {
-		int entries = idx - evlist->nr_entries;
-		perf_evlist__splice_list_tail(evlist, &list, entries);
+		int entries = data.idx - evlist->nr_entries;
+		perf_evlist__splice_list_tail(evlist, &data.list, entries);
 		return 0;
 	}
 
@@ -970,16 +840,17 @@ void print_events_type(u8 type)
 int print_hwcache_events(const char *event_glob)
 {
 	unsigned int type, op, i, printed = 0;
+	char name[64];
 
 	for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
 		for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
 			/* skip invalid cache type */
-			if (!is_cache_op_valid(type, op))
+			if (!perf_evsel__is_cache_op_valid(type, op))
 				continue;
 
 			for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
-				char *name = event_cache_name(type, op, i);
-
+				__perf_evsel__hw_cache_type_op_res_name(type, op, i,
+									name, sizeof(name));
 				if (event_glob != NULL && !strglobmatch(name, event_glob))
 					continue;
 
@@ -1106,6 +977,13 @@ int parse_events__term_str(struct parse_events__term **term,
 			config, str, 0);
 }
 
+int parse_events__term_clone(struct parse_events__term **new,
+			     struct parse_events__term *term)
+{
+	return new_term(new, term->type_val, term->type_term, term->config,
+			term->val.str, term->val.num);
+}
+
 void parse_events__free_terms(struct list_head *terms)
 {
 	struct parse_events__term *term, *h;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8cac57a..ee9c218 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -26,13 +26,12 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
 extern bool have_tracepoints(struct list_head *evlist);
 
 const char *event_type(int type);
-const char *event_name(struct perf_evsel *event);
-extern const char *__event_name(int type, u64 config);
 
 extern int parse_events_option(const struct option *opt, const char *str,
 			       int unset);
 extern int parse_events(struct perf_evlist *evlist, const char *str,
 			int unset);
+extern int parse_events_terms(struct list_head *terms, const char *str);
 extern int parse_filter(const struct option *opt, const char *str, int unset);
 
 #define EVENTS_HELP_MAX (128*1024)
@@ -63,11 +62,22 @@ struct parse_events__term {
 	struct list_head list;
 };
 
+struct parse_events_data__events {
+	struct list_head list;
+	int idx;
+};
+
+struct parse_events_data__terms {
+	struct list_head *terms;
+};
+
 int parse_events__is_hardcoded_term(struct parse_events__term *term);
 int parse_events__term_num(struct parse_events__term **_term,
 			   int type_term, char *config, long num);
 int parse_events__term_str(struct parse_events__term **_term,
 			   int type_term, char *config, char *str);
+int parse_events__term_clone(struct parse_events__term **new,
+			     struct parse_events__term *term);
 void parse_events__free_terms(struct list_head *terms);
 int parse_events_modifier(struct list_head *list, char *str);
 int parse_events_add_tracepoint(struct list_head **list, int *idx,
@@ -83,8 +93,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
 			 char *pmu , struct list_head *head_config);
 void parse_events_update_lists(struct list_head *list_event,
 			       struct list_head *list_all);
-void parse_events_error(struct list_head *list_all,
-			int *idx, char const *msg);
+void parse_events_error(void *data, void *scanner, char const *msg);
 int parse_events__test(void);
 
 void print_events(const char *event_glob);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 618a8e7..488362e 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -1,4 +1,6 @@
 
+%option reentrant
+%option bison-bridge
 %option prefix="parse_events_"
 %option stack
 
@@ -8,7 +10,10 @@
 #include "parse-events-bison.h"
 #include "parse-events.h"
 
-static int __value(char *str, int base, int token)
+char *parse_events_get_text(yyscan_t yyscanner);
+YYSTYPE *parse_events_get_lval(yyscan_t yyscanner);
+
+static int __value(YYSTYPE *yylval, char *str, int base, int token)
 {
 	long num;
 
@@ -17,35 +22,48 @@ static int __value(char *str, int base, int token)
 	if (errno)
 		return PE_ERROR;
 
-	parse_events_lval.num = num;
+	yylval->num = num;
 	return token;
 }
 
-static int value(int base)
+static int value(yyscan_t scanner, int base)
 {
-	return __value(parse_events_text, base, PE_VALUE);
+	YYSTYPE *yylval = parse_events_get_lval(scanner);
+	char *text = parse_events_get_text(scanner);
+
+	return __value(yylval, text, base, PE_VALUE);
 }
 
-static int raw(void)
+static int raw(yyscan_t scanner)
 {
-	return __value(parse_events_text + 1, 16, PE_RAW);
+	YYSTYPE *yylval = parse_events_get_lval(scanner);
+	char *text = parse_events_get_text(scanner);
+
+	return __value(yylval, text + 1, 16, PE_RAW);
 }
 
-static int str(int token)
+static int str(yyscan_t scanner, int token)
 {
-	parse_events_lval.str = strdup(parse_events_text);
+	YYSTYPE *yylval = parse_events_get_lval(scanner);
+	char *text = parse_events_get_text(scanner);
+
+	yylval->str = strdup(text);
 	return token;
 }
 
-static int sym(int type, int config)
+static int sym(yyscan_t scanner, int type, int config)
 {
-	parse_events_lval.num = (type << 16) + config;
+	YYSTYPE *yylval = parse_events_get_lval(scanner);
+
+	yylval->num = (type << 16) + config;
 	return PE_VALUE_SYM;
 }
 
-static int term(int type)
+static int term(yyscan_t scanner, int type)
 {
-	parse_events_lval.num = type;
+	YYSTYPE *yylval = parse_events_get_lval(scanner);
+
+	yylval->num = type;
 	return PE_TERM;
 }
 
@@ -61,25 +79,38 @@ modifier_event	[ukhpGH]{1,8}
 modifier_bp	[rwx]
 
 %%
-cpu-cycles|cycles				{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
-stalled-cycles-frontend|idle-cycles-frontend	{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
-stalled-cycles-backend|idle-cycles-backend	{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
-instructions					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
-cache-references				{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
-cache-misses					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
-branch-instructions|branches			{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
-branch-misses					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
-bus-cycles					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
-ref-cycles					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
-cpu-clock					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
-task-clock					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
-page-faults|faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
-minor-faults					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
-major-faults					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
-context-switches|cs				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
-cpu-migrations|migrations			{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
-alignment-faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
-emulation-faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+
+%{
+	{
+		int start_token;
+
+		start_token = (int) parse_events_get_extra(yyscanner);
+		if (start_token) {
+			parse_events_set_extra(NULL, yyscanner);
+			return start_token;
+		}
+         }
+%}
+
+cpu-cycles|cycles				{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
+stalled-cycles-frontend|idle-cycles-frontend	{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+stalled-cycles-backend|idle-cycles-backend	{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+instructions					{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
+cache-references				{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
+cache-misses					{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
+branch-instructions|branches			{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+branch-misses					{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
+bus-cycles					{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
+ref-cycles					{ return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
+cpu-clock					{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
+task-clock					{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
+page-faults|faults				{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
+minor-faults					{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+major-faults					{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+context-switches|cs				{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+cpu-migrations|migrations			{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
+alignment-faults				{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+emulation-faults				{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
 
 L1-dcache|l1-d|l1d|L1-data		|
 L1-icache|l1-i|l1i|L1-instruction	|
@@ -87,14 +118,14 @@ LLC|L2					|
 dTLB|d-tlb|Data-TLB			|
 iTLB|i-tlb|Instruction-TLB		|
 branch|branches|bpu|btb|bpc		|
-node					{ return str(PE_NAME_CACHE_TYPE); }
+node					{ return str(yyscanner, PE_NAME_CACHE_TYPE); }
 
 load|loads|read				|
 store|stores|write			|
 prefetch|prefetches			|
 speculative-read|speculative-load	|
 refs|Reference|ops|access		|
-misses|miss				{ return str(PE_NAME_CACHE_OP_RESULT); }
+misses|miss				{ return str(yyscanner, PE_NAME_CACHE_OP_RESULT); }
 
 	/*
 	 * These are event config hardcoded term names to be specified
@@ -102,20 +133,20 @@ misses|miss				{ return str(PE_NAME_CACHE_OP_RESULT); }
 	 * so we can put them here directly. In case the we have a conflict
 	 * in future, this needs to go into '//' condition block.
 	 */
-config			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
-config1			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
-config2			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
-name			{ return term(PARSE_EVENTS__TERM_TYPE_NAME); }
-period			{ return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
-branch_type		{ return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
+config			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
+config1			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
+config2			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
+name			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
+period			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
+branch_type		{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
 
 mem:			{ BEGIN(mem); return PE_PREFIX_MEM; }
-r{num_raw_hex}		{ return raw(); }
-{num_dec}		{ return value(10); }
-{num_hex}		{ return value(16); }
+r{num_raw_hex}		{ return raw(yyscanner); }
+{num_dec}		{ return value(yyscanner, 10); }
+{num_hex}		{ return value(yyscanner, 16); }
 
-{modifier_event}	{ return str(PE_MODIFIER_EVENT); }
-{name}			{ return str(PE_NAME); }
+{modifier_event}	{ return str(yyscanner, PE_MODIFIER_EVENT); }
+{name}			{ return str(yyscanner, PE_NAME); }
 "/"			{ return '/'; }
 -			{ return '-'; }
 ,			{ return ','; }
@@ -123,17 +154,17 @@ r{num_raw_hex}		{ return raw(); }
 =			{ return '='; }
 
 <mem>{
-{modifier_bp}		{ return str(PE_MODIFIER_BP); }
+{modifier_bp}		{ return str(yyscanner, PE_MODIFIER_BP); }
 :			{ return ':'; }
-{num_dec}		{ return value(10); }
-{num_hex}		{ return value(16); }
+{num_dec}		{ return value(yyscanner, 10); }
+{num_hex}		{ return value(yyscanner, 16); }
 	/*
 	 * We need to separate 'mem:' scanner part, in order to get specific
 	 * modifier bits parsed out. Otherwise we would need to handle PE_NAME
 	 * and we'd need to parse it manually. During the escape from <mem>
 	 * state we need to put the escaping char back, so we dont miss it.
 	 */
-.			{ unput(*parse_events_text); BEGIN(INITIAL); }
+.			{ unput(*yytext); BEGIN(INITIAL); }
 	/*
 	 * We destroy the scanner after reaching EOF,
 	 * but anyway just to be sure get back to INIT state.
@@ -143,7 +174,7 @@ r{num_raw_hex}		{ return raw(); }
 
 %%
 
-int parse_events_wrap(void)
+int parse_events_wrap(void *scanner __used)
 {
 	return 1;
 }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 362cc59..9525c45 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,7 +1,8 @@
-
+%pure-parser
 %name-prefix "parse_events_"
-%parse-param {struct list_head *list_all}
-%parse-param {int *idx}
+%parse-param {void *_data}
+%parse-param {void *scanner}
+%lex-param {void* scanner}
 
 %{
 
@@ -12,8 +13,9 @@
 #include "types.h"
 #include "util.h"
 #include "parse-events.h"
+#include "parse-events-bison.h"
 
-extern int parse_events_lex (void);
+extern int parse_events_lex (YYSTYPE* lvalp, void* scanner);
 
 #define ABORT_ON(val) \
 do { \
@@ -23,6 +25,7 @@ do { \
 
 %}
 
+%token PE_START_EVENTS PE_START_TERMS
 %token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM
 %token PE_NAME
 %token PE_MODIFIER_EVENT PE_MODIFIER_BP
@@ -58,24 +61,33 @@ do { \
 }
 %%
 
+start:
+PE_START_EVENTS events
+|
+PE_START_TERMS  terms
+
 events:
 events ',' event | event
 
 event:
 event_def PE_MODIFIER_EVENT
 {
+	struct parse_events_data__events *data = _data;
+
 	/*
 	 * Apply modifier on all events added by single event definition
 	 * (there could be more events added for multiple tracepoint
 	 * definitions via '*?'.
 	 */
 	ABORT_ON(parse_events_modifier($1, $2));
-	parse_events_update_lists($1, list_all);
+	parse_events_update_lists($1, &data->list);
 }
 |
 event_def
 {
-	parse_events_update_lists($1, list_all);
+	struct parse_events_data__events *data = _data;
+
+	parse_events_update_lists($1, &data->list);
 }
 
 event_def: event_pmu |
@@ -89,9 +101,10 @@ event_def: event_pmu |
 event_pmu:
 PE_NAME '/' event_config '/'
 {
+	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 
-	ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3));
+	ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
 	parse_events__free_terms($3);
 	$$ = list;
 }
@@ -99,94 +112,115 @@ PE_NAME '/' event_config '/'
 event_legacy_symbol:
 PE_VALUE_SYM '/' event_config '/'
 {
+	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3));
+	ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+					  type, config, $3));
 	parse_events__free_terms($3);
 	$$ = list;
 }
 |
 PE_VALUE_SYM sep_slash_dc
 {
+	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL));
+	ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+					  type, config, NULL));
 	$$ = list;
 }
 
 event_legacy_cache:
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 {
+	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 
-	ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5));
+	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
 	$$ = list;
 }
 |
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 {
+	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 
-	ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL));
+	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
 	$$ = list;
 }
 |
 PE_NAME_CACHE_TYPE
 {
+	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 
-	ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL));
+	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
 	$$ = list;
 }
 
 event_legacy_mem:
 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 {
+	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 
-	ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4));
+	ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
+					     (void *) $2, $4));
 	$$ = list;
 }
 |
 PE_PREFIX_MEM PE_VALUE sep_dc
 {
+	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 
-	ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL));
+	ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
+					     (void *) $2, NULL));
 	$$ = list;
 }
 
 event_legacy_tracepoint:
 PE_NAME ':' PE_NAME
 {
+	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 
-	ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3));
+	ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
 	$$ = list;
 }
 
 event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 {
+	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 
-	ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL));
+	ABORT_ON(parse_events_add_numeric(&list, &data->idx, $1, $3, NULL));
 	$$ = list;
 }
 
 event_legacy_raw:
 PE_RAW
 {
+	struct parse_events_data__events *data = _data;
 	struct list_head *list = NULL;
 
-	ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL));
+	ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+					  PERF_TYPE_RAW, $1, NULL));
 	$$ = list;
 }
 
+terms: event_config
+{
+	struct parse_events_data__terms *data = _data;
+	data->terms = $1;
+}
+
 event_config:
 event_config ',' event_term
 {
@@ -267,8 +301,7 @@ sep_slash_dc: '/' | ':' |
 
 %%
 
-void parse_events_error(struct list_head *list_all __used,
-			int *idx __used,
+void parse_events_error(void *data __used, void *scanner __used,
 			char const *msg __used)
 {
 }
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index a119a53..74d0948e 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -80,6 +80,114 @@ static int pmu_format(char *name, struct list_head *format)
 	return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
+{
+	struct perf_pmu__alias *alias;
+	char buf[256];
+	int ret;
+
+	ret = fread(buf, 1, sizeof(buf), file);
+	if (ret == 0)
+		return -EINVAL;
+	buf[ret] = 0;
+
+	alias = malloc(sizeof(*alias));
+	if (!alias)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&alias->terms);
+	ret = parse_events_terms(&alias->terms, buf);
+	if (ret) {
+		free(alias);
+		return ret;
+	}
+
+	alias->name = strdup(name);
+	list_add_tail(&alias->list, list);
+	return 0;
+}
+
+/*
+ * Process all the sysfs attributes located under the directory
+ * specified in 'dir' parameter.
+ */
+static int pmu_aliases_parse(char *dir, struct list_head *head)
+{
+	struct dirent *evt_ent;
+	DIR *event_dir;
+	int ret = 0;
+
+	event_dir = opendir(dir);
+	if (!event_dir)
+		return -EINVAL;
+
+	while (!ret && (evt_ent = readdir(event_dir))) {
+		char path[PATH_MAX];
+		char *name = evt_ent->d_name;
+		FILE *file;
+
+		if (!strcmp(name, ".") || !strcmp(name, ".."))
+			continue;
+
+		snprintf(path, PATH_MAX, "%s/%s", dir, name);
+
+		ret = -EINVAL;
+		file = fopen(path, "r");
+		if (!file)
+			break;
+		ret = perf_pmu__new_alias(head, name, file);
+		fclose(file);
+	}
+
+	closedir(event_dir);
+	return ret;
+}
+
+/*
+ * Reading the pmu event aliases definition, which should be located at:
+ * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
+ */
+static int pmu_aliases(char *name, struct list_head *head)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs_find_mountpoint();
+	if (!sysfs)
+		return -1;
+
+	snprintf(path, PATH_MAX,
+		 "%s/bus/event_source/devices/%s/events", sysfs, name);
+
+	if (stat(path, &st) < 0)
+		return -1;
+
+	if (pmu_aliases_parse(path, head))
+		return -1;
+
+	return 0;
+}
+
+static int pmu_alias_terms(struct perf_pmu__alias *alias,
+			   struct list_head *terms)
+{
+	struct parse_events__term *term, *clone;
+	LIST_HEAD(list);
+	int ret;
+
+	list_for_each_entry(term, &alias->terms, list) {
+		ret = parse_events__term_clone(&clone, term);
+		if (ret) {
+			parse_events__free_terms(&list);
+			return ret;
+		}
+		list_add_tail(&clone->list, &list);
+	}
+	list_splice(&list, terms);
+	return 0;
+}
+
 /*
  * Reading/parsing the default pmu type value, which should be
  * located at:
@@ -118,6 +226,7 @@ static struct perf_pmu *pmu_lookup(char *name)
 {
 	struct perf_pmu *pmu;
 	LIST_HEAD(format);
+	LIST_HEAD(aliases);
 	__u32 type;
 
 	/*
@@ -135,8 +244,12 @@ static struct perf_pmu *pmu_lookup(char *name)
 	if (!pmu)
 		return NULL;
 
+	pmu_aliases(name, &aliases);
+
 	INIT_LIST_HEAD(&pmu->format);
+	INIT_LIST_HEAD(&pmu->aliases);
 	list_splice(&format, &pmu->format);
+	list_splice(&aliases, &pmu->aliases);
 	pmu->name = strdup(name);
 	pmu->type = type;
 	return pmu;
@@ -279,6 +392,59 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
 	return pmu_config(&pmu->format, attr, head_terms);
 }
 
+static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
+					      struct parse_events__term *term)
+{
+	struct perf_pmu__alias *alias;
+	char *name;
+
+	if (parse_events__is_hardcoded_term(term))
+		return NULL;
+
+	if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
+		if (term->val.num != 1)
+			return NULL;
+		if (pmu_find_format(&pmu->format, term->config))
+			return NULL;
+		name = term->config;
+	} else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
+		if (strcasecmp(term->config, "event"))
+			return NULL;
+		name = term->val.str;
+	} else {
+		return NULL;
+	}
+
+	list_for_each_entry(alias, &pmu->aliases, list) {
+		if (!strcasecmp(alias->name, name))
+			return alias;
+	}
+	return NULL;
+}
+
+/*
+ * Find alias in the terms list and replace it with the terms
+ * defined for the alias
+ */
+int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
+{
+	struct parse_events__term *term, *h;
+	struct perf_pmu__alias *alias;
+	int ret;
+
+	list_for_each_entry_safe(term, h, head_terms, list) {
+		alias = pmu_find_alias(pmu, term);
+		if (!alias)
+			continue;
+		ret = pmu_alias_terms(alias, &term->list);
+		if (ret)
+			return ret;
+		list_del(&term->list);
+		free(term);
+	}
+	return 0;
+}
+
 int perf_pmu__new_format(struct list_head *list, char *name,
 			 int config, unsigned long *bits)
 {
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 68c0db9..535f2c5 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -19,17 +19,26 @@ struct perf_pmu__format {
 	struct list_head list;
 };
 
+struct perf_pmu__alias {
+	char *name;
+	struct list_head terms;
+	struct list_head list;
+};
+
 struct perf_pmu {
 	char *name;
 	__u32 type;
 	struct list_head format;
+	struct list_head aliases;
 	struct list_head list;
 };
 
 struct perf_pmu *perf_pmu__find(char *name);
 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
 		     struct list_head *head_terms);
-
+int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
+struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
+				struct list_head *head_terms);
 int perf_pmu_wrap(void);
 void perf_pmu_error(struct list_head *list, char *name, char const *msg);
 
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index c3e399b..6b305fb 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -289,7 +289,6 @@ struct branch_info *machine__resolve_bstack(struct machine *self,
 }
 
 int machine__resolve_callchain(struct machine *self,
-			       struct perf_evsel *evsel __used,
 			       struct thread *thread,
 			       struct ip_callchain *chain,
 			       struct symbol **parent)
@@ -1449,7 +1448,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
 	ret += hists__fprintf_nr_events(&session->hists, fp);
 
 	list_for_each_entry(pos, &session->evlist->entries, node) {
-		ret += fprintf(fp, "%s stats:\n", event_name(pos));
+		ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
 		ret += hists__fprintf_nr_events(&pos->hists, fp);
 	}
 
@@ -1490,8 +1489,8 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
 }
 
 void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
-			  struct machine *machine, struct perf_evsel *evsel,
-			  int print_sym, int print_dso, int print_symoffset)
+			  struct machine *machine, int print_sym,
+			  int print_dso, int print_symoffset)
 {
 	struct addr_location al;
 	struct callchain_cursor_node *node;
@@ -1505,7 +1504,7 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
 
 	if (symbol_conf.use_callchain && sample->callchain) {
 
-		if (machine__resolve_callchain(machine, evsel, al.thread,
+		if (machine__resolve_callchain(machine, al.thread,
 						sample->callchain, NULL) != 0) {
 			if (verbose)
 				error("Failed to resolve callchain. Skipping\n");
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 0c702e3..c71a1a7 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -151,8 +151,8 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
 					    unsigned int type);
 
 void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
-			  struct machine *machine, struct perf_evsel *evsel,
-			  int print_sym, int print_dso, int print_symoffset);
+			  struct machine *machine, int print_sym,
+			  int print_dso, int print_symoffset);
 
 int perf_session__cpu_bitmap(struct perf_session *session,
 			     const char *cpu_list, unsigned long *cpu_bitmap);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index a272374..0f5a0a4 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -241,6 +241,54 @@ struct sort_entry sort_sym = {
 	.se_width_idx	= HISTC_SYMBOL,
 };
 
+/* --sort srcline */
+
+static int64_t
+sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+	return (int64_t)(right->ip - left->ip);
+}
+
+static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
+				   size_t size, unsigned int width __used)
+{
+	FILE *fp;
+	char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
+	size_t line_len;
+
+	if (path != NULL)
+		goto out_path;
+
+	snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
+		 self->ms.map->dso->long_name, self->ip);
+	fp = popen(cmd, "r");
+	if (!fp)
+		goto out_ip;
+
+	if (getline(&path, &line_len, fp) < 0 || !line_len)
+		goto out_ip;
+	fclose(fp);
+	self->srcline = strdup(path);
+	if (self->srcline == NULL)
+		goto out_ip;
+
+	nl = strchr(self->srcline, '\n');
+	if (nl != NULL)
+		*nl = '\0';
+	path = self->srcline;
+out_path:
+	return repsep_snprintf(bf, size, "%s", path);
+out_ip:
+	return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
+}
+
+struct sort_entry sort_srcline = {
+	.se_header	= "Source:Line",
+	.se_cmp		= sort__srcline_cmp,
+	.se_snprintf	= hist_entry__srcline_snprintf,
+	.se_width_idx	= HISTC_SRCLINE,
+};
+
 /* --sort parent */
 
 static int64_t
@@ -439,6 +487,7 @@ static struct sort_dimension sort_dimensions[] = {
 	DIM(SORT_PARENT, "parent", sort_parent),
 	DIM(SORT_CPU, "cpu", sort_cpu),
 	DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
+	DIM(SORT_SRCLINE, "srcline", sort_srcline),
 };
 
 int sort_dimension__add(const char *tok)
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 472aa5a..e724b26 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -71,6 +71,7 @@ struct hist_entry {
 	char			level;
 	bool			used;
 	u8			filtered;
+	char			*srcline;
 	struct symbol		*parent;
 	union {
 		unsigned long	  position;
@@ -93,6 +94,7 @@ enum sort_type {
 	SORT_SYM_FROM,
 	SORT_SYM_TO,
 	SORT_MISPREDICT,
+	SORT_SRCLINE,
 };
 
 /*
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index d583638..199bc4d 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -313,3 +313,25 @@ int strtailcmp(const char *s1, const char *s2)
 	return 0;
 }
 
+/**
+ * rtrim - Removes trailing whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Note that the first trailing whitespace is replaced with a %NUL-terminator
+ * in the given string @s. Returns @s.
+ */
+char *rtrim(char *s)
+{
+	size_t size = strlen(s);
+	char *end;
+
+	if (!size)
+		return s;
+
+	end = s + size - 1;
+	while (end >= s && isspace(*end))
+		end--;
+	*(end + 1) = '\0';
+
+	return s;
+}
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index abe0e8e..7eeebce 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -65,7 +65,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
 				top->freq ? "Hz" : "");
 	}
 
-	ret += SNPRINTF(bf + ret, size - ret, "%s", event_name(top->sym_evsel));
+	ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel));
 
 	ret += SNPRINTF(bf + ret, size - ret, "], ");
 
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 2daaedb..b13c733 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -264,4 +264,6 @@ bool is_power_of_2(unsigned long n)
 
 size_t hex_width(u64 v);
 
+char *rtrim(char *s);
+
 #endif
diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile
index fd8e1f1..f856495 100644
--- a/tools/power/x86/turbostat/Makefile
+++ b/tools/power/x86/turbostat/Makefile
@@ -1,4 +1,5 @@
 turbostat : turbostat.c
+CFLAGS +=	-Wall
 
 clean :
 	rm -f turbostat
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index adf175f..74e4450 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -27,7 +27,11 @@ supports an "invariant" TSC, plus the APERF and MPERF MSRs.
 on processors that additionally support C-state residency counters.
 
 .SS Options
-The \fB-s\fP option prints only a 1-line summary for each sample interval.
+The \fB-s\fP option limits output to a 1-line system summary for each interval.
+.PP
+The \fB-c\fP option limits output to the 1st thread in each core.
+.PP
+The \fB-p\fP option limits output to the 1st thread in each package.
 .PP
 The \fB-v\fP option increases verbosity.
 .PP
@@ -65,19 +69,19 @@ Subsequent rows show per-CPU statistics.
 .nf
 [root@x980]# ./turbostat
 cor CPU    %c0  GHz  TSC    %c1    %c3    %c6   %pc3   %pc6
-          0.60 1.63 3.38   2.91   0.00  96.49   0.00  76.64
-  0   0   0.59 1.62 3.38   4.51   0.00  94.90   0.00  76.64
-  0   6   1.13 1.64 3.38   3.97   0.00  94.90   0.00  76.64
-  1   2   0.08 1.62 3.38   0.07   0.00  99.85   0.00  76.64
-  1   8   0.03 1.62 3.38   0.12   0.00  99.85   0.00  76.64
-  2   4   0.01 1.62 3.38   0.06   0.00  99.93   0.00  76.64
-  2  10   0.04 1.62 3.38   0.02   0.00  99.93   0.00  76.64
-  8   1   2.85 1.62 3.38  11.71   0.00  85.44   0.00  76.64
-  8   7   1.98 1.62 3.38  12.58   0.00  85.44   0.00  76.64
-  9   3   0.36 1.62 3.38   0.71   0.00  98.93   0.00  76.64
-  9   9   0.09 1.62 3.38   0.98   0.00  98.93   0.00  76.64
- 10   5   0.03 1.62 3.38   0.09   0.00  99.87   0.00  76.64
- 10  11   0.07 1.62 3.38   0.06   0.00  99.87   0.00  76.64
+          0.09 1.62 3.38   1.83   0.32  97.76   1.26  83.61
+  0   0   0.15 1.62 3.38  10.23   0.05  89.56   1.26  83.61
+  0   6   0.05 1.62 3.38  10.34
+  1   2   0.03 1.62 3.38   0.07   0.05  99.86
+  1   8   0.03 1.62 3.38   0.06
+  2   4   0.21 1.62 3.38   0.10   1.49  98.21
+  2  10   0.02 1.62 3.38   0.29
+  8   1   0.04 1.62 3.38   0.04   0.08  99.84
+  8   7   0.01 1.62 3.38   0.06
+  9   3   0.53 1.62 3.38   0.10   0.20  99.17
+  9   9   0.02 1.62 3.38   0.60
+ 10   5   0.01 1.62 3.38   0.02   0.04  99.92
+ 10  11   0.02 1.62 3.38   0.02
 .fi
 .SH SUMMARY EXAMPLE
 The "-s" option prints the column headers just once,
@@ -86,9 +90,10 @@ and then the one line system summary for each sample interval.
 .nf
 [root@x980]# ./turbostat -s
    %c0  GHz  TSC    %c1    %c3    %c6   %pc3   %pc6
-  0.61 1.89 3.38   5.95   0.00  93.44   0.00  66.33
-  0.52 1.62 3.38   6.83   0.00  92.65   0.00  61.11
-  0.62 1.92 3.38   5.47   0.00  93.91   0.00  67.31
+  0.23 1.67 3.38   2.00   0.30  97.47   1.07  82.12
+  0.10 1.62 3.38   1.87   2.25  95.77  12.02  72.60
+  0.20 1.64 3.38   1.98   0.11  97.72   0.30  83.36
+  0.11 1.70 3.38   1.86   1.81  96.22   9.71  74.90
 .fi
 .SH VERBOSE EXAMPLE
 The "-v" option adds verbosity to the output:
@@ -120,30 +125,28 @@ until ^C while the other CPUs are mostly idle:
 [root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null
 ^C
 cor CPU    %c0  GHz  TSC    %c1    %c3    %c6   %pc3   %pc6
-          8.63 3.64 3.38  14.46   0.49  76.42   0.00   0.00
-  0   0   0.34 3.36 3.38  99.66   0.00   0.00   0.00   0.00
-  0   6  99.96 3.64 3.38   0.04   0.00   0.00   0.00   0.00
-  1   2   0.14 3.50 3.38   1.75   2.04  96.07   0.00   0.00
-  1   8   0.38 3.57 3.38   1.51   2.04  96.07   0.00   0.00
-  2   4   0.01 2.65 3.38   0.06   0.00  99.93   0.00   0.00
-  2  10   0.03 2.12 3.38   0.04   0.00  99.93   0.00   0.00
-  8   1   0.91 3.59 3.38  35.27   0.92  62.90   0.00   0.00
-  8   7   1.61 3.63 3.38  34.57   0.92  62.90   0.00   0.00
-  9   3   0.04 3.38 3.38   0.20   0.00  99.76   0.00   0.00
-  9   9   0.04 3.29 3.38   0.20   0.00  99.76   0.00   0.00
- 10   5   0.03 3.08 3.38   0.12   0.00  99.85   0.00   0.00
- 10  11   0.05 3.07 3.38   0.10   0.00  99.85   0.00   0.00
-4.907015 sec
-
+          8.86 3.61 3.38  15.06  31.19  44.89   0.00   0.00
+  0   0   1.46 3.22 3.38  16.84  29.48  52.22   0.00   0.00
+  0   6   0.21 3.06 3.38  18.09
+  1   2   0.53 3.33 3.38   2.80  46.40  50.27
+  1   8   0.89 3.47 3.38   2.44
+  2   4   1.36 3.43 3.38   9.04  23.71  65.89
+  2  10   0.18 2.86 3.38  10.22
+  8   1   0.04 2.87 3.38  99.96   0.01   0.00
+  8   7  99.72 3.63 3.38   0.27
+  9   3   0.31 3.21 3.38   7.64  56.55  35.50
+  9   9   0.08 2.95 3.38   7.88
+ 10   5   1.42 3.43 3.38   2.14  30.99  65.44
+ 10  11   0.16 2.88 3.38   3.40
 .fi
-Above the cycle soaker drives cpu6 up 3.6 Ghz turbo limit
+Above the cycle soaker drives cpu7 up its 3.6 Ghz turbo limit
 while the other processors are generally in various states of idle.
 
-Note that cpu0 is an HT sibling sharing core0
-with cpu6, and thus it is unable to get to an idle state
-deeper than c1 while cpu6 is busy.
+Note that cpu1 and cpu7 are HT siblings within core8.
+As cpu7 is very busy, it prevents its sibling, cpu1,
+from entering a c-state deeper than c1.
 
-Note that turbostat reports average GHz of 3.64, while
+Note that turbostat reports average GHz of 3.63, while
 the arithmetic average of the GHz column above is lower.
 This is a weighted average, where the weight is %c0.  ie. it is the total number of
 un-halted cycles elapsed per time divided by the number of CPUs.
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 16de7ad..7775803 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -67,92 +67,119 @@ double bclk;
 unsigned int show_pkg;
 unsigned int show_core;
 unsigned int show_cpu;
+unsigned int show_pkg_only;
+unsigned int show_core_only;
+char *output_buffer, *outp;
 
 int aperf_mperf_unstable;
 int backwards_count;
 char *progname;
 
-int num_cpus;
-cpu_set_t *cpu_present_set, *cpu_mask;
-size_t cpu_present_setsize, cpu_mask_size;
-
-struct counters {
-	unsigned long long tsc;		/* per thread */
-	unsigned long long aperf;	/* per thread */
-	unsigned long long mperf;	/* per thread */
-	unsigned long long c1;	/* per thread (calculated) */
-	unsigned long long c3;	/* per core */
-	unsigned long long c6;	/* per core */
-	unsigned long long c7;	/* per core */
-	unsigned long long pc2;	/* per package */
-	unsigned long long pc3;	/* per package */
-	unsigned long long pc6;	/* per package */
-	unsigned long long pc7;	/* per package */
-	unsigned long long extra_msr;	/* per thread */
-	int pkg;
-	int core;
-	int cpu;
-	struct counters *next;
-};
-
-struct counters *cnt_even;
-struct counters *cnt_odd;
-struct counters *cnt_delta;
-struct counters *cnt_average;
-struct timeval tv_even;
-struct timeval tv_odd;
-struct timeval tv_delta;
-
-int mark_cpu_present(int pkg, int core, int cpu)
+cpu_set_t *cpu_present_set, *cpu_affinity_set;
+size_t cpu_present_setsize, cpu_affinity_setsize;
+
+struct thread_data {
+	unsigned long long tsc;
+	unsigned long long aperf;
+	unsigned long long mperf;
+	unsigned long long c1;	/* derived */
+	unsigned long long extra_msr;
+	unsigned int cpu_id;
+	unsigned int flags;
+#define CPU_IS_FIRST_THREAD_IN_CORE	0x2
+#define CPU_IS_FIRST_CORE_IN_PACKAGE	0x4
+} *thread_even, *thread_odd;
+
+struct core_data {
+	unsigned long long c3;
+	unsigned long long c6;
+	unsigned long long c7;
+	unsigned int core_id;
+} *core_even, *core_odd;
+
+struct pkg_data {
+	unsigned long long pc2;
+	unsigned long long pc3;
+	unsigned long long pc6;
+	unsigned long long pc7;
+	unsigned int package_id;
+} *package_even, *package_odd;
+
+#define ODD_COUNTERS thread_odd, core_odd, package_odd
+#define EVEN_COUNTERS thread_even, core_even, package_even
+
+#define GET_THREAD(thread_base, thread_no, core_no, pkg_no) \
+	(thread_base + (pkg_no) * topo.num_cores_per_pkg * \
+		topo.num_threads_per_core + \
+		(core_no) * topo.num_threads_per_core + (thread_no))
+#define GET_CORE(core_base, core_no, pkg_no) \
+	(core_base + (pkg_no) * topo.num_cores_per_pkg + (core_no))
+#define GET_PKG(pkg_base, pkg_no) (pkg_base + pkg_no)
+
+struct system_summary {
+	struct thread_data threads;
+	struct core_data cores;
+	struct pkg_data packages;
+} sum, average;
+
+
+struct topo_params {
+	int num_packages;
+	int num_cpus;
+	int num_cores;
+	int max_cpu_num;
+	int num_cores_per_pkg;
+	int num_threads_per_core;
+} topo;
+
+struct timeval tv_even, tv_odd, tv_delta;
+
+void setup_all_buffers(void);
+
+int cpu_is_not_present(int cpu)
 {
-	CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set);
-	return 0;
+	return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set);
 }
-
 /*
- * cpu_mask_init(ncpus)
- *
- * allocate and clear cpu_mask
- * set cpu_mask_size
+ * run func(thread, core, package) in topology order
+ * skip non-present cpus
  */
-void cpu_mask_init(int ncpus)
+
+int for_all_cpus(int (func)(struct thread_data *, struct core_data *, struct pkg_data *),
+	struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base)
 {
-	cpu_mask = CPU_ALLOC(ncpus);
-	if (cpu_mask == NULL) {
-		perror("CPU_ALLOC");
-		exit(3);
-	}
-	cpu_mask_size = CPU_ALLOC_SIZE(ncpus);
-	CPU_ZERO_S(cpu_mask_size, cpu_mask);
+	int retval, pkg_no, core_no, thread_no;
 
-	/*
-	 * Allocate and initialize cpu_present_set
-	 */
-	cpu_present_set = CPU_ALLOC(ncpus);
-	if (cpu_present_set == NULL) {
-		perror("CPU_ALLOC");
-		exit(3);
-	}
-	cpu_present_setsize = CPU_ALLOC_SIZE(ncpus);
-	CPU_ZERO_S(cpu_present_setsize, cpu_present_set);
-	for_all_cpus(mark_cpu_present);
-}
+	for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) {
+		for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) {
+			for (thread_no = 0; thread_no <
+				topo.num_threads_per_core; ++thread_no) {
+				struct thread_data *t;
+				struct core_data *c;
+				struct pkg_data *p;
 
-void cpu_mask_uninit()
-{
-	CPU_FREE(cpu_mask);
-	cpu_mask = NULL;
-	cpu_mask_size = 0;
-	CPU_FREE(cpu_present_set);
-	cpu_present_set = NULL;
-	cpu_present_setsize = 0;
+				t = GET_THREAD(thread_base, thread_no, core_no, pkg_no);
+
+				if (cpu_is_not_present(t->cpu_id))
+					continue;
+
+				c = GET_CORE(core_base, core_no, pkg_no);
+				p = GET_PKG(pkg_base, pkg_no);
+
+				retval = func(t, c, p);
+				if (retval)
+					return retval;
+			}
+		}
+	}
+	return 0;
 }
 
 int cpu_migrate(int cpu)
 {
-	CPU_ZERO_S(cpu_mask_size, cpu_mask);
-	CPU_SET_S(cpu, cpu_mask_size, cpu_mask);
-	if (sched_setaffinity(0, cpu_mask_size, cpu_mask) == -1)
+	CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
+	CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set);
+	if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1)
 		return -1;
 	else
 		return 0;
@@ -181,67 +208,72 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
 void print_header(void)
 {
 	if (show_pkg)
-		fprintf(stderr, "pk");
+		outp += sprintf(outp, "pk");
 	if (show_pkg)
-		fprintf(stderr, " ");
+		outp += sprintf(outp, " ");
 	if (show_core)
-		fprintf(stderr, "cor");
+		outp += sprintf(outp, "cor");
 	if (show_cpu)
-		fprintf(stderr, " CPU");
+		outp += sprintf(outp, " CPU");
 	if (show_pkg || show_core || show_cpu)
-		fprintf(stderr, " ");
+		outp += sprintf(outp, " ");
 	if (do_nhm_cstates)
-		fprintf(stderr, "   %%c0");
+		outp += sprintf(outp, "   %%c0");
 	if (has_aperf)
-		fprintf(stderr, "  GHz");
-	fprintf(stderr, "  TSC");
+		outp += sprintf(outp, "  GHz");
+	outp += sprintf(outp, "  TSC");
 	if (do_nhm_cstates)
-		fprintf(stderr, "    %%c1");
+		outp += sprintf(outp, "    %%c1");
 	if (do_nhm_cstates)
-		fprintf(stderr, "    %%c3");
+		outp += sprintf(outp, "    %%c3");
 	if (do_nhm_cstates)
-		fprintf(stderr, "    %%c6");
+		outp += sprintf(outp, "    %%c6");
 	if (do_snb_cstates)
-		fprintf(stderr, "    %%c7");
+		outp += sprintf(outp, "    %%c7");
 	if (do_snb_cstates)
-		fprintf(stderr, "   %%pc2");
+		outp += sprintf(outp, "   %%pc2");
 	if (do_nhm_cstates)
-		fprintf(stderr, "   %%pc3");
+		outp += sprintf(outp, "   %%pc3");
 	if (do_nhm_cstates)
-		fprintf(stderr, "   %%pc6");
+		outp += sprintf(outp, "   %%pc6");
 	if (do_snb_cstates)
-		fprintf(stderr, "   %%pc7");
+		outp += sprintf(outp, "   %%pc7");
 	if (extra_msr_offset)
-		fprintf(stderr, "        MSR 0x%x ", extra_msr_offset);
+		outp += sprintf(outp, "        MSR 0x%x ", extra_msr_offset);
 
-	putc('\n', stderr);
+	outp += sprintf(outp, "\n");
 }
 
-void dump_cnt(struct counters *cnt)
+int dump_counters(struct thread_data *t, struct core_data *c,
+	struct pkg_data *p)
 {
-	if (!cnt)
-		return;
-	if (cnt->pkg) fprintf(stderr, "package: %d ", cnt->pkg);
-	if (cnt->core) fprintf(stderr, "core:: %d ", cnt->core);
-	if (cnt->cpu) fprintf(stderr, "CPU: %d ", cnt->cpu);
-	if (cnt->tsc) fprintf(stderr, "TSC: %016llX\n", cnt->tsc);
-	if (cnt->c3) fprintf(stderr, "c3: %016llX\n", cnt->c3);
-	if (cnt->c6) fprintf(stderr, "c6: %016llX\n", cnt->c6);
-	if (cnt->c7) fprintf(stderr, "c7: %016llX\n", cnt->c7);
-	if (cnt->aperf) fprintf(stderr, "aperf: %016llX\n", cnt->aperf);
-	if (cnt->pc2) fprintf(stderr, "pc2: %016llX\n", cnt->pc2);
-	if (cnt->pc3) fprintf(stderr, "pc3: %016llX\n", cnt->pc3);
-	if (cnt->pc6) fprintf(stderr, "pc6: %016llX\n", cnt->pc6);
-	if (cnt->pc7) fprintf(stderr, "pc7: %016llX\n", cnt->pc7);
-	if (cnt->extra_msr) fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr);
-}
+	fprintf(stderr, "t %p, c %p, p %p\n", t, c, p);
+
+	if (t) {
+		fprintf(stderr, "CPU: %d flags 0x%x\n", t->cpu_id, t->flags);
+		fprintf(stderr, "TSC: %016llX\n", t->tsc);
+		fprintf(stderr, "aperf: %016llX\n", t->aperf);
+		fprintf(stderr, "mperf: %016llX\n", t->mperf);
+		fprintf(stderr, "c1: %016llX\n", t->c1);
+		fprintf(stderr, "msr0x%x: %016llX\n",
+			extra_msr_offset, t->extra_msr);
+	}
 
-void dump_list(struct counters *cnt)
-{
-	printf("dump_list 0x%p\n", cnt);
+	if (c) {
+		fprintf(stderr, "core: %d\n", c->core_id);
+		fprintf(stderr, "c3: %016llX\n", c->c3);
+		fprintf(stderr, "c6: %016llX\n", c->c6);
+		fprintf(stderr, "c7: %016llX\n", c->c7);
+	}
 
-	for (; cnt; cnt = cnt->next)
-		dump_cnt(cnt);
+	if (p) {
+		fprintf(stderr, "package: %d\n", p->package_id);
+		fprintf(stderr, "pc2: %016llX\n", p->pc2);
+		fprintf(stderr, "pc3: %016llX\n", p->pc3);
+		fprintf(stderr, "pc6: %016llX\n", p->pc6);
+		fprintf(stderr, "pc7: %016llX\n", p->pc7);
+	}
+	return 0;
 }
 
 /*
@@ -253,321 +285,389 @@ void dump_list(struct counters *cnt)
  * TSC: "TSC" 3 columns %3.2
  * percentage " %pc3" %6.2
  */
-void print_cnt(struct counters *p)
+int format_counters(struct thread_data *t, struct core_data *c,
+	struct pkg_data *p)
 {
 	double interval_float;
 
+	 /* if showing only 1st thread in core and this isn't one, bail out */
+	if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
+		return 0;
+
+	 /* if showing only 1st thread in pkg and this isn't one, bail out */
+	if (show_pkg_only && !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
+		return 0;
+
 	interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
 
-	/* topology columns, print blanks on 1st (average) line */
-	if (p == cnt_average) {
+	/* topo columns, print blanks on 1st (average) line */
+	if (t == &average.threads) {
 		if (show_pkg)
-			fprintf(stderr, "  ");
+			outp += sprintf(outp, "  ");
 		if (show_pkg && show_core)
-			fprintf(stderr, " ");
+			outp += sprintf(outp, " ");
 		if (show_core)
-			fprintf(stderr, "   ");
+			outp += sprintf(outp, "   ");
 		if (show_cpu)
-			fprintf(stderr, " " "   ");
+			outp += sprintf(outp, " " "   ");
 	} else {
-		if (show_pkg)
-			fprintf(stderr, "%2d", p->pkg);
+		if (show_pkg) {
+			if (p)
+				outp += sprintf(outp, "%2d", p->package_id);
+			else
+				outp += sprintf(outp, "  ");
+		}
 		if (show_pkg && show_core)
-			fprintf(stderr, " ");
-		if (show_core)
-			fprintf(stderr, "%3d", p->core);
+			outp += sprintf(outp, " ");
+		if (show_core) {
+			if (c)
+				outp += sprintf(outp, "%3d", c->core_id);
+			else
+				outp += sprintf(outp, "   ");
+		}
 		if (show_cpu)
-			fprintf(stderr, " %3d", p->cpu);
+			outp += sprintf(outp, " %3d", t->cpu_id);
 	}
 
 	/* %c0 */
 	if (do_nhm_cstates) {
 		if (show_pkg || show_core || show_cpu)
-			fprintf(stderr, " ");
+			outp += sprintf(outp, " ");
 		if (!skip_c0)
-			fprintf(stderr, "%6.2f", 100.0 * p->mperf/p->tsc);
+			outp += sprintf(outp, "%6.2f", 100.0 * t->mperf/t->tsc);
 		else
-			fprintf(stderr, "  ****");
+			outp += sprintf(outp, "  ****");
 	}
 
 	/* GHz */
 	if (has_aperf) {
 		if (!aperf_mperf_unstable) {
-			fprintf(stderr, " %3.2f",
-				1.0 * p->tsc / units * p->aperf /
-				p->mperf / interval_float);
+			outp += sprintf(outp, " %3.2f",
+				1.0 * t->tsc / units * t->aperf /
+				t->mperf / interval_float);
 		} else {
-			if (p->aperf > p->tsc || p->mperf > p->tsc) {
-				fprintf(stderr, " ***");
+			if (t->aperf > t->tsc || t->mperf > t->tsc) {
+				outp += sprintf(outp, " ***");
 			} else {
-				fprintf(stderr, "%3.1f*",
-					1.0 * p->tsc /
-					units * p->aperf /
-					p->mperf / interval_float);
+				outp += sprintf(outp, "%3.1f*",
+					1.0 * t->tsc /
+					units * t->aperf /
+					t->mperf / interval_float);
 			}
 		}
 	}
 
 	/* TSC */
-	fprintf(stderr, "%5.2f", 1.0 * p->tsc/units/interval_float);
+	outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float);
 
 	if (do_nhm_cstates) {
 		if (!skip_c1)
-			fprintf(stderr, " %6.2f", 100.0 * p->c1/p->tsc);
+			outp += sprintf(outp, " %6.2f", 100.0 * t->c1/t->tsc);
 		else
-			fprintf(stderr, "  ****");
+			outp += sprintf(outp, "  ****");
 	}
+
+	/* print per-core data only for 1st thread in core */
+	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
+		goto done;
+
 	if (do_nhm_cstates)
-		fprintf(stderr, " %6.2f", 100.0 * p->c3/p->tsc);
+		outp += sprintf(outp, " %6.2f", 100.0 * c->c3/t->tsc);
 	if (do_nhm_cstates)
-		fprintf(stderr, " %6.2f", 100.0 * p->c6/p->tsc);
+		outp += sprintf(outp, " %6.2f", 100.0 * c->c6/t->tsc);
 	if (do_snb_cstates)
-		fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc);
+		outp += sprintf(outp, " %6.2f", 100.0 * c->c7/t->tsc);
+
+	/* print per-package data only for 1st core in package */
+	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
+		goto done;
+
 	if (do_snb_cstates)
-		fprintf(stderr, " %6.2f", 100.0 * p->pc2/p->tsc);
+		outp += sprintf(outp, " %6.2f", 100.0 * p->pc2/t->tsc);
 	if (do_nhm_cstates)
-		fprintf(stderr, " %6.2f", 100.0 * p->pc3/p->tsc);
+		outp += sprintf(outp, " %6.2f", 100.0 * p->pc3/t->tsc);
 	if (do_nhm_cstates)
-		fprintf(stderr, " %6.2f", 100.0 * p->pc6/p->tsc);
+		outp += sprintf(outp, " %6.2f", 100.0 * p->pc6/t->tsc);
 	if (do_snb_cstates)
-		fprintf(stderr, " %6.2f", 100.0 * p->pc7/p->tsc);
+		outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc);
+done:
 	if (extra_msr_offset)
-		fprintf(stderr, "  0x%016llx", p->extra_msr);
-	putc('\n', stderr);
+		outp += sprintf(outp, "  0x%016llx", t->extra_msr);
+	outp += sprintf(outp, "\n");
+
+	return 0;
 }
 
-void print_counters(struct counters *counters)
+void flush_stdout()
+{
+	fputs(output_buffer, stdout);
+	outp = output_buffer;
+}
+void flush_stderr()
+{
+	fputs(output_buffer, stderr);
+	outp = output_buffer;
+}
+void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
 {
-	struct counters *cnt;
 	static int printed;
 
-
 	if (!printed || !summary_only)
 		print_header();
 
-	if (num_cpus > 1)
-		print_cnt(cnt_average);
+	if (topo.num_cpus > 1)
+		format_counters(&average.threads, &average.cores,
+			&average.packages);
 
 	printed = 1;
 
 	if (summary_only)
 		return;
 
-	for (cnt = counters; cnt != NULL; cnt = cnt->next)
-		print_cnt(cnt);
-
+	for_all_cpus(format_counters, t, c, p);
 }
 
-#define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after))
+void
+delta_package(struct pkg_data *new, struct pkg_data *old)
+{
+	old->pc2 = new->pc2 - old->pc2;
+	old->pc3 = new->pc3 - old->pc3;
+	old->pc6 = new->pc6 - old->pc6;
+	old->pc7 = new->pc7 - old->pc7;
+}
 
-int compute_delta(struct counters *after,
-	struct counters *before, struct counters *delta)
+void
+delta_core(struct core_data *new, struct core_data *old)
 {
-	int errors = 0;
-	int perf_err = 0;
+	old->c3 = new->c3 - old->c3;
+	old->c6 = new->c6 - old->c6;
+	old->c7 = new->c7 - old->c7;
+}
 
-	skip_c0 = skip_c1 = 0;
+/*
+ * old = new - old
+ */
+void
+delta_thread(struct thread_data *new, struct thread_data *old,
+	struct core_data *core_delta)
+{
+	old->tsc = new->tsc - old->tsc;
+
+	/* check for TSC < 1 Mcycles over interval */
+	if (old->tsc < (1000 * 1000)) {
+		fprintf(stderr, "Insanely slow TSC rate, TSC stops in idle?\n");
+		fprintf(stderr, "You can disable all c-states by booting with \"idle=poll\"\n");
+		fprintf(stderr, "or just the deep ones with \"processor.max_cstate=1\"\n");
+		exit(-3);
+	}
 
-	for ( ; after && before && delta;
-		after = after->next, before = before->next, delta = delta->next) {
-		if (before->cpu != after->cpu) {
-			printf("cpu configuration changed: %d != %d\n",
-				before->cpu, after->cpu);
-			return -1;
-		}
+	old->c1 = new->c1 - old->c1;
 
-		if (SUBTRACT_COUNTER(after->tsc, before->tsc, delta->tsc)) {
-			fprintf(stderr, "cpu%d TSC went backwards %llX to %llX\n",
-				before->cpu, before->tsc, after->tsc);
-			errors++;
-		}
-		/* check for TSC < 1 Mcycles over interval */
-		if (delta->tsc < (1000 * 1000)) {
-			fprintf(stderr, "Insanely slow TSC rate,"
-				" TSC stops in idle?\n");
-			fprintf(stderr, "You can disable all c-states"
-				" by booting with \"idle=poll\"\n");
-			fprintf(stderr, "or just the deep ones with"
-				" \"processor.max_cstate=1\"\n");
-			exit(-3);
-		}
-		if (SUBTRACT_COUNTER(after->c3, before->c3, delta->c3)) {
-			fprintf(stderr, "cpu%d c3 counter went backwards %llX to %llX\n",
-				before->cpu, before->c3, after->c3);
-			errors++;
-		}
-		if (SUBTRACT_COUNTER(after->c6, before->c6, delta->c6)) {
-			fprintf(stderr, "cpu%d c6 counter went backwards %llX to %llX\n",
-				before->cpu, before->c6, after->c6);
-			errors++;
-		}
-		if (SUBTRACT_COUNTER(after->c7, before->c7, delta->c7)) {
-			fprintf(stderr, "cpu%d c7 counter went backwards %llX to %llX\n",
-				before->cpu, before->c7, after->c7);
-			errors++;
-		}
-		if (SUBTRACT_COUNTER(after->pc2, before->pc2, delta->pc2)) {
-			fprintf(stderr, "cpu%d pc2 counter went backwards %llX to %llX\n",
-				before->cpu, before->pc2, after->pc2);
-			errors++;
-		}
-		if (SUBTRACT_COUNTER(after->pc3, before->pc3, delta->pc3)) {
-			fprintf(stderr, "cpu%d pc3 counter went backwards %llX to %llX\n",
-				before->cpu, before->pc3, after->pc3);
-			errors++;
-		}
-		if (SUBTRACT_COUNTER(after->pc6, before->pc6, delta->pc6)) {
-			fprintf(stderr, "cpu%d pc6 counter went backwards %llX to %llX\n",
-				before->cpu, before->pc6, after->pc6);
-			errors++;
-		}
-		if (SUBTRACT_COUNTER(after->pc7, before->pc7, delta->pc7)) {
-			fprintf(stderr, "cpu%d pc7 counter went backwards %llX to %llX\n",
-				before->cpu, before->pc7, after->pc7);
-			errors++;
-		}
+	if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) {
+		old->aperf = new->aperf - old->aperf;
+		old->mperf = new->mperf - old->mperf;
+	} else {
 
-		perf_err = SUBTRACT_COUNTER(after->aperf, before->aperf, delta->aperf);
-		if (perf_err) {
-			fprintf(stderr, "cpu%d aperf counter went backwards %llX to %llX\n",
-				before->cpu, before->aperf, after->aperf);
-		}
-		perf_err |= SUBTRACT_COUNTER(after->mperf, before->mperf, delta->mperf);
-		if (perf_err) {
-			fprintf(stderr, "cpu%d mperf counter went backwards %llX to %llX\n",
-				before->cpu, before->mperf, after->mperf);
-		}
-		if (perf_err) {
-			if (!aperf_mperf_unstable) {
-				fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname);
-				fprintf(stderr, "* Frequency results do not cover entire interval *\n");
-				fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n");
+		if (!aperf_mperf_unstable) {
+			fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname);
+			fprintf(stderr, "* Frequency results do not cover entire interval *\n");
+			fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n");
 
-				aperf_mperf_unstable = 1;
-			}
-			/*
-			 * mperf delta is likely a huge "positive" number
-			 * can not use it for calculating c0 time
-			 */
-			skip_c0 = 1;
-			skip_c1 = 1;
+			aperf_mperf_unstable = 1;
 		}
-
 		/*
-		 * As mperf and tsc collection are not atomic,
-		 * it is possible for mperf's non-halted cycles
-		 * to exceed TSC's all cycles: show c1 = 0% in that case.
+		 * mperf delta is likely a huge "positive" number
+		 * can not use it for calculating c0 time
 		 */
-		if (delta->mperf > delta->tsc)
-			delta->c1 = 0;
-		else /* normal case, derive c1 */
-			delta->c1 = delta->tsc - delta->mperf
-				- delta->c3 - delta->c6 - delta->c7;
+		skip_c0 = 1;
+		skip_c1 = 1;
+	}
 
-		if (delta->mperf == 0)
-			delta->mperf = 1;	/* divide by 0 protection */
 
-		/*
-		 * for "extra msr", just copy the latest w/o subtracting
-		 */
-		delta->extra_msr = after->extra_msr;
-		if (errors) {
-			fprintf(stderr, "ERROR cpu%d before:\n", before->cpu);
-			dump_cnt(before);
-			fprintf(stderr, "ERROR cpu%d after:\n", before->cpu);
-			dump_cnt(after);
-			errors = 0;
-		}
+	/*
+	 * As counter collection is not atomic,
+	 * it is possible for mperf's non-halted cycles + idle states
+	 * to exceed TSC's all cycles: show c1 = 0% in that case.
+	 */
+	if ((old->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > old->tsc)
+		old->c1 = 0;
+	else {
+		/* normal case, derive c1 */
+		old->c1 = old->tsc - old->mperf - core_delta->c3
+				- core_delta->c6 - core_delta->c7;
 	}
+
+	if (old->mperf == 0) {
+		if (verbose > 1) fprintf(stderr, "cpu%d MPERF 0!\n", old->cpu_id);
+		old->mperf = 1;	/* divide by 0 protection */
+	}
+
+	/*
+	 * for "extra msr", just copy the latest w/o subtracting
+	 */
+	old->extra_msr = new->extra_msr;
+}
+
+int delta_cpu(struct thread_data *t, struct core_data *c,
+	struct pkg_data *p, struct thread_data *t2,
+	struct core_data *c2, struct pkg_data *p2)
+{
+	/* calculate core delta only for 1st thread in core */
+	if (t->flags & CPU_IS_FIRST_THREAD_IN_CORE)
+		delta_core(c, c2);
+
+	/* always calculate thread delta */
+	delta_thread(t, t2, c2);	/* c2 is core delta */
+
+	/* calculate package delta only for 1st core in package */
+	if (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)
+		delta_package(p, p2);
+
 	return 0;
 }
 
-void compute_average(struct counters *delta, struct counters *avg)
+void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
+{
+	t->tsc = 0;
+	t->aperf = 0;
+	t->mperf = 0;
+	t->c1 = 0;
+
+	/* tells format_counters to dump all fields from this set */
+	t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE;
+
+	c->c3 = 0;
+	c->c6 = 0;
+	c->c7 = 0;
+
+	p->pc2 = 0;
+	p->pc3 = 0;
+	p->pc6 = 0;
+	p->pc7 = 0;
+}
+int sum_counters(struct thread_data *t, struct core_data *c,
+	struct pkg_data *p)
 {
-	struct counters *sum;
+	average.threads.tsc += t->tsc;
+	average.threads.aperf += t->aperf;
+	average.threads.mperf += t->mperf;
+	average.threads.c1 += t->c1;
 
-	sum = calloc(1, sizeof(struct counters));
-	if (sum == NULL) {
-		perror("calloc sum");
-		exit(1);
-	}
+	/* sum per-core values only for 1st thread in core */
+	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
+		return 0;
 
-	for (; delta; delta = delta->next) {
-		sum->tsc += delta->tsc;
-		sum->c1 += delta->c1;
-		sum->c3 += delta->c3;
-		sum->c6 += delta->c6;
-		sum->c7 += delta->c7;
-		sum->aperf += delta->aperf;
-		sum->mperf += delta->mperf;
-		sum->pc2 += delta->pc2;
-		sum->pc3 += delta->pc3;
-		sum->pc6 += delta->pc6;
-		sum->pc7 += delta->pc7;
-	}
-	avg->tsc = sum->tsc/num_cpus;
-	avg->c1 = sum->c1/num_cpus;
-	avg->c3 = sum->c3/num_cpus;
-	avg->c6 = sum->c6/num_cpus;
-	avg->c7 = sum->c7/num_cpus;
-	avg->aperf = sum->aperf/num_cpus;
-	avg->mperf = sum->mperf/num_cpus;
-	avg->pc2 = sum->pc2/num_cpus;
-	avg->pc3 = sum->pc3/num_cpus;
-	avg->pc6 = sum->pc6/num_cpus;
-	avg->pc7 = sum->pc7/num_cpus;
-
-	free(sum);
+	average.cores.c3 += c->c3;
+	average.cores.c6 += c->c6;
+	average.cores.c7 += c->c7;
+
+	/* sum per-pkg values only for 1st core in pkg */
+	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
+		return 0;
+
+	average.packages.pc2 += p->pc2;
+	average.packages.pc3 += p->pc3;
+	average.packages.pc6 += p->pc6;
+	average.packages.pc7 += p->pc7;
+
+	return 0;
+}
+/*
+ * sum the counters for all cpus in the system
+ * compute the weighted average
+ */
+void compute_average(struct thread_data *t, struct core_data *c,
+	struct pkg_data *p)
+{
+	clear_counters(&average.threads, &average.cores, &average.packages);
+
+	for_all_cpus(sum_counters, t, c, p);
+
+	average.threads.tsc /= topo.num_cpus;
+	average.threads.aperf /= topo.num_cpus;
+	average.threads.mperf /= topo.num_cpus;
+	average.threads.c1 /= topo.num_cpus;
+
+	average.cores.c3 /= topo.num_cores;
+	average.cores.c6 /= topo.num_cores;
+	average.cores.c7 /= topo.num_cores;
+
+	average.packages.pc2 /= topo.num_packages;
+	average.packages.pc3 /= topo.num_packages;
+	average.packages.pc6 /= topo.num_packages;
+	average.packages.pc7 /= topo.num_packages;
 }
 
-int get_counters(struct counters *cnt)
+static unsigned long long rdtsc(void)
 {
-	for ( ; cnt; cnt = cnt->next) {
+	unsigned int low, high;
 
-		if (cpu_migrate(cnt->cpu))
-			return -1;
+	asm volatile("rdtsc" : "=a" (low), "=d" (high));
 
-		if (get_msr(cnt->cpu, MSR_TSC, &cnt->tsc))
-			return -1;
+	return low | ((unsigned long long)high) << 32;
+}
 
-		if (has_aperf) {
-			if (get_msr(cnt->cpu, MSR_APERF, &cnt->aperf))
-				return -1;
-			if (get_msr(cnt->cpu, MSR_MPERF, &cnt->mperf))
-				return -1;
-		}
 
-		if (do_nhm_cstates) {
-			if (get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY, &cnt->c3))
-				return -1;
-			if (get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY, &cnt->c6))
-				return -1;
-		}
+/*
+ * get_counters(...)
+ * migrate to cpu
+ * acquire and record local counters for that cpu
+ */
+int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
+{
+	int cpu = t->cpu_id;
 
-		if (do_snb_cstates)
-			if (get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY, &cnt->c7))
-				return -1;
+	if (cpu_migrate(cpu))
+		return -1;
 
-		if (do_nhm_cstates) {
-			if (get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY, &cnt->pc3))
-				return -1;
-			if (get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY, &cnt->pc6))
-				return -1;
-		}
-		if (do_snb_cstates) {
-			if (get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY, &cnt->pc2))
-				return -1;
-			if (get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY, &cnt->pc7))
-				return -1;
-		}
-		if (extra_msr_offset)
-			if (get_msr(cnt->cpu, extra_msr_offset, &cnt->extra_msr))
-				return -1;
+	t->tsc = rdtsc();	/* we are running on local CPU of interest */
+
+	if (has_aperf) {
+		if (get_msr(cpu, MSR_APERF, &t->aperf))
+			return -3;
+		if (get_msr(cpu, MSR_MPERF, &t->mperf))
+			return -4;
+	}
+
+	if (extra_msr_offset)
+		if (get_msr(cpu, extra_msr_offset, &t->extra_msr))
+			return -5;
+
+	/* collect core counters only for 1st thread in core */
+	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
+		return 0;
+
+	if (do_nhm_cstates) {
+		if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3))
+			return -6;
+		if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6))
+			return -7;
+	}
+
+	if (do_snb_cstates)
+		if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7))
+			return -8;
+
+	/* collect package counters only for 1st core in package */
+	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
+		return 0;
+
+	if (do_nhm_cstates) {
+		if (get_msr(cpu, MSR_PKG_C3_RESIDENCY, &p->pc3))
+			return -9;
+		if (get_msr(cpu, MSR_PKG_C6_RESIDENCY, &p->pc6))
+			return -10;
+	}
+	if (do_snb_cstates) {
+		if (get_msr(cpu, MSR_PKG_C2_RESIDENCY, &p->pc2))
+			return -11;
+		if (get_msr(cpu, MSR_PKG_C7_RESIDENCY, &p->pc7))
+			return -12;
 	}
 	return 0;
 }
 
-void print_nehalem_info(void)
+void print_verbose_header(void)
 {
 	unsigned long long msr;
 	unsigned int ratio;
@@ -615,143 +715,82 @@ void print_nehalem_info(void)
 
 }
 
-void free_counter_list(struct counters *list)
+void free_all_buffers(void)
 {
-	struct counters *p;
+	CPU_FREE(cpu_present_set);
+	cpu_present_set = NULL;
+	cpu_present_set = 0;
 
-	for (p = list; p; ) {
-		struct counters *free_me;
+	CPU_FREE(cpu_affinity_set);
+	cpu_affinity_set = NULL;
+	cpu_affinity_setsize = 0;
 
-		free_me = p;
-		p = p->next;
-		free(free_me);
-	}
-}
+	free(thread_even);
+	free(core_even);
+	free(package_even);
 
-void free_all_counters(void)
-{
-	free_counter_list(cnt_even);
-	cnt_even = NULL;
+	thread_even = NULL;
+	core_even = NULL;
+	package_even = NULL;
 
-	free_counter_list(cnt_odd);
-	cnt_odd = NULL;
+	free(thread_odd);
+	free(core_odd);
+	free(package_odd);
 
-	free_counter_list(cnt_delta);
-	cnt_delta = NULL;
+	thread_odd = NULL;
+	core_odd = NULL;
+	package_odd = NULL;
 
-	free_counter_list(cnt_average);
-	cnt_average = NULL;
+	free(output_buffer);
+	output_buffer = NULL;
+	outp = NULL;
 }
 
-void insert_counters(struct counters **list,
-	struct counters *new)
+/*
+ * cpu_is_first_sibling_in_core(cpu)
+ * return 1 if given CPU is 1st HT sibling in the core
+ */
+int cpu_is_first_sibling_in_core(int cpu)
 {
-	struct counters *prev;
-
-	/*
-	 * list was empty
-	 */
-	if (*list == NULL) {
-		new->next = *list;
-		*list = new;
-		return;
-	}
-
-	if (!summary_only)
-		show_cpu = 1;	/* there is more than one CPU */
-
-	/*
-	 * insert on front of list.
-	 * It is sorted by ascending package#, core#, cpu#
-	 */
-	if (((*list)->pkg > new->pkg) ||
-	    (((*list)->pkg == new->pkg) && ((*list)->core > new->core)) ||
-	    (((*list)->pkg == new->pkg) && ((*list)->core == new->core) && ((*list)->cpu > new->cpu))) {
-		new->next = *list;
-		*list = new;
-		return;
-	}
-
-	prev = *list;
-
-	while (prev->next && (prev->next->pkg < new->pkg)) {
-		prev = prev->next;
-		if (!summary_only)
-			show_pkg = 1;	/* there is more than 1 package */
-	}
-
-	while (prev->next && (prev->next->pkg == new->pkg)
-		&& (prev->next->core < new->core)) {
-		prev = prev->next;
-		if (!summary_only)
-			show_core = 1;	/* there is more than 1 core */
-	}
+	char path[64];
+	FILE *filep;
+	int first_cpu;
 
-	while (prev->next && (prev->next->pkg == new->pkg)
-		&& (prev->next->core == new->core)
-		&& (prev->next->cpu < new->cpu)) {
-		prev = prev->next;
+	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
+	filep = fopen(path, "r");
+	if (filep == NULL) {
+		perror(path);
+		exit(1);
 	}
-
-	/*
-	 * insert after "prev"
-	 */
-	new->next = prev->next;
-	prev->next = new;
+	fscanf(filep, "%d", &first_cpu);
+	fclose(filep);
+	return (cpu == first_cpu);
 }
 
-void alloc_new_counters(int pkg, int core, int cpu)
+/*
+ * cpu_is_first_core_in_package(cpu)
+ * return 1 if given CPU is 1st core in package
+ */
+int cpu_is_first_core_in_package(int cpu)
 {
-	struct counters *new;
-
-	if (verbose > 1)
-		printf("pkg%d core%d, cpu%d\n", pkg, core, cpu);
-
-	new = (struct counters *)calloc(1, sizeof(struct counters));
-	if (new == NULL) {
-		perror("calloc");
-		exit(1);
-	}
-	new->pkg = pkg;
-	new->core = core;
-	new->cpu = cpu;
-	insert_counters(&cnt_odd, new);
-
-	new = (struct counters *)calloc(1,
-		sizeof(struct counters));
-	if (new == NULL) {
-		perror("calloc");
-		exit(1);
-	}
-	new->pkg = pkg;
-	new->core = core;
-	new->cpu = cpu;
-	insert_counters(&cnt_even, new);
-
-	new = (struct counters *)calloc(1, sizeof(struct counters));
-	if (new == NULL) {
-		perror("calloc");
-		exit(1);
-	}
-	new->pkg = pkg;
-	new->core = core;
-	new->cpu = cpu;
-	insert_counters(&cnt_delta, new);
+	char path[64];
+	FILE *filep;
+	int first_cpu;
 
-	new = (struct counters *)calloc(1, sizeof(struct counters));
-	if (new == NULL) {
-		perror("calloc");
+	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu);
+	filep = fopen(path, "r");
+	if (filep == NULL) {
+		perror(path);
 		exit(1);
 	}
-	new->pkg = pkg;
-	new->core = core;
-	new->cpu = cpu;
-	cnt_average = new;
+	fscanf(filep, "%d", &first_cpu);
+	fclose(filep);
+	return (cpu == first_cpu);
 }
 
 int get_physical_package_id(int cpu)
 {
-	char path[64];
+	char path[80];
 	FILE *filep;
 	int pkg;
 
@@ -768,7 +807,7 @@ int get_physical_package_id(int cpu)
 
 int get_core_id(int cpu)
 {
-	char path[64];
+	char path[80];
 	FILE *filep;
 	int core;
 
@@ -783,14 +822,87 @@ int get_core_id(int cpu)
 	return core;
 }
 
+int get_num_ht_siblings(int cpu)
+{
+	char path[80];
+	FILE *filep;
+	int sib1, sib2;
+	int matches;
+	char character;
+
+	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
+	filep = fopen(path, "r");
+	if (filep == NULL) {
+		perror(path);
+		exit(1);
+	}
+	/*
+	 * file format:
+	 * if a pair of number with a character between: 2 siblings (eg. 1-2, or 1,4)
+	 * otherwinse 1 sibling (self).
+	 */
+	matches = fscanf(filep, "%d%c%d\n", &sib1, &character, &sib2);
+
+	fclose(filep);
+
+	if (matches == 3)
+		return 2;
+	else
+		return 1;
+}
+
 /*
- * run func(pkg, core, cpu) on every cpu in /proc/stat
+ * run func(thread, core, package) in topology order
+ * skip non-present cpus
  */
 
-int for_all_cpus(void (func)(int, int, int))
+int for_all_cpus_2(int (func)(struct thread_data *, struct core_data *,
+	struct pkg_data *, struct thread_data *, struct core_data *,
+	struct pkg_data *), struct thread_data *thread_base,
+	struct core_data *core_base, struct pkg_data *pkg_base,
+	struct thread_data *thread_base2, struct core_data *core_base2,
+	struct pkg_data *pkg_base2)
+{
+	int retval, pkg_no, core_no, thread_no;
+
+	for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) {
+		for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) {
+			for (thread_no = 0; thread_no <
+				topo.num_threads_per_core; ++thread_no) {
+				struct thread_data *t, *t2;
+				struct core_data *c, *c2;
+				struct pkg_data *p, *p2;
+
+				t = GET_THREAD(thread_base, thread_no, core_no, pkg_no);
+
+				if (cpu_is_not_present(t->cpu_id))
+					continue;
+
+				t2 = GET_THREAD(thread_base2, thread_no, core_no, pkg_no);
+
+				c = GET_CORE(core_base, core_no, pkg_no);
+				c2 = GET_CORE(core_base2, core_no, pkg_no);
+
+				p = GET_PKG(pkg_base, pkg_no);
+				p2 = GET_PKG(pkg_base2, pkg_no);
+
+				retval = func(t, c, p, t2, c2, p2);
+				if (retval)
+					return retval;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * run func(cpu) on every cpu in /proc/stat
+ * return max_cpu number
+ */
+int for_all_proc_cpus(int (func)(int))
 {
 	FILE *fp;
-	int cpu_count;
+	int cpu_num;
 	int retval;
 
 	fp = fopen(proc_stat, "r");
@@ -805,78 +917,88 @@ int for_all_cpus(void (func)(int, int, int))
 		exit(1);
 	}
 
-	for (cpu_count = 0; ; cpu_count++) {
-		int cpu;
-
-		retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu);
+	while (1) {
+		retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num);
 		if (retval != 1)
 			break;
 
-		func(get_physical_package_id(cpu), get_core_id(cpu), cpu);
+		retval = func(cpu_num);
+		if (retval) {
+			fclose(fp);
+			return(retval);
+		}
 	}
 	fclose(fp);
-	return cpu_count;
+	return 0;
 }
 
 void re_initialize(void)
 {
-	free_all_counters();
-	num_cpus = for_all_cpus(alloc_new_counters);
-	cpu_mask_uninit();
-	cpu_mask_init(num_cpus);
-	printf("turbostat: re-initialized with num_cpus %d\n", num_cpus);
+	free_all_buffers();
+	setup_all_buffers();
+	printf("turbostat: re-initialized with num_cpus %d\n", topo.num_cpus);
 }
 
-void dummy(int pkg, int core, int cpu) { return; }
+
 /*
- * check to see if a cpu came on-line
+ * count_cpus()
+ * remember the last one seen, it will be the max
  */
-int verify_num_cpus(void)
+int count_cpus(int cpu)
 {
-	int new_num_cpus;
-
-	new_num_cpus = for_all_cpus(dummy);
+	if (topo.max_cpu_num < cpu)
+		topo.max_cpu_num = cpu;
 
-	if (new_num_cpus != num_cpus) {
-		if (verbose)
-			printf("num_cpus was %d, is now  %d\n",
-				num_cpus, new_num_cpus);
-		return -1;
-	}
+	topo.num_cpus += 1;
+	return 0;
+}
+int mark_cpu_present(int cpu)
+{
+	CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set);
 	return 0;
 }
 
 void turbostat_loop()
 {
+	int retval;
+
 restart:
-	get_counters(cnt_even);
+	retval = for_all_cpus(get_counters, EVEN_COUNTERS);
+	if (retval) {
+		re_initialize();
+		goto restart;
+	}
 	gettimeofday(&tv_even, (struct timezone *)NULL);
 
 	while (1) {
-		if (verify_num_cpus()) {
+		if (for_all_proc_cpus(cpu_is_not_present)) {
 			re_initialize();
 			goto restart;
 		}
 		sleep(interval_sec);
-		if (get_counters(cnt_odd)) {
+		retval = for_all_cpus(get_counters, ODD_COUNTERS);
+		if (retval) {
 			re_initialize();
 			goto restart;
 		}
 		gettimeofday(&tv_odd, (struct timezone *)NULL);
-		compute_delta(cnt_odd, cnt_even, cnt_delta);
 		timersub(&tv_odd, &tv_even, &tv_delta);
-		compute_average(cnt_delta, cnt_average);
-		print_counters(cnt_delta);
+		for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS);
+		compute_average(EVEN_COUNTERS);
+		format_all_counters(EVEN_COUNTERS);
+		flush_stdout();
 		sleep(interval_sec);
-		if (get_counters(cnt_even)) {
+		retval = for_all_cpus(get_counters, EVEN_COUNTERS);
+		if (retval) {
 			re_initialize();
 			goto restart;
 		}
 		gettimeofday(&tv_even, (struct timezone *)NULL);
-		compute_delta(cnt_even, cnt_odd, cnt_delta);
 		timersub(&tv_even, &tv_odd, &tv_delta);
-		compute_average(cnt_delta, cnt_average);
-		print_counters(cnt_delta);
+		for_all_cpus_2(delta_cpu, EVEN_COUNTERS, ODD_COUNTERS);
+		compute_average(ODD_COUNTERS);
+		format_all_counters(ODD_COUNTERS);
+		flush_stdout();
 	}
 }
 
@@ -1051,6 +1173,208 @@ int open_dev_cpu_msr(int dummy1)
 	return 0;
 }
 
+void topology_probe()
+{
+	int i;
+	int max_core_id = 0;
+	int max_package_id = 0;
+	int max_siblings = 0;
+	struct cpu_topology {
+		int core_id;
+		int physical_package_id;
+	} *cpus;
+
+	/* Initialize num_cpus, max_cpu_num */
+	topo.num_cpus = 0;
+	topo.max_cpu_num = 0;
+	for_all_proc_cpus(count_cpus);
+	if (!summary_only && topo.num_cpus > 1)
+		show_cpu = 1;
+
+	if (verbose > 1)
+		fprintf(stderr, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num);
+
+	cpus = calloc(1, (topo.max_cpu_num  + 1) * sizeof(struct cpu_topology));
+	if (cpus == NULL) {
+		perror("calloc cpus");
+		exit(1);
+	}
+
+	/*
+	 * Allocate and initialize cpu_present_set
+	 */
+	cpu_present_set = CPU_ALLOC((topo.max_cpu_num + 1));
+	if (cpu_present_set == NULL) {
+		perror("CPU_ALLOC");
+		exit(3);
+	}
+	cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
+	CPU_ZERO_S(cpu_present_setsize, cpu_present_set);
+	for_all_proc_cpus(mark_cpu_present);
+
+	/*
+	 * Allocate and initialize cpu_affinity_set
+	 */
+	cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1));
+	if (cpu_affinity_set == NULL) {
+		perror("CPU_ALLOC");
+		exit(3);
+	}
+	cpu_affinity_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
+	CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
+
+
+	/*
+	 * For online cpus
+	 * find max_core_id, max_package_id
+	 */
+	for (i = 0; i <= topo.max_cpu_num; ++i) {
+		int siblings;
+
+		if (cpu_is_not_present(i)) {
+			if (verbose > 1)
+				fprintf(stderr, "cpu%d NOT PRESENT\n", i);
+			continue;
+		}
+		cpus[i].core_id = get_core_id(i);
+		if (cpus[i].core_id > max_core_id)
+			max_core_id = cpus[i].core_id;
+
+		cpus[i].physical_package_id = get_physical_package_id(i);
+		if (cpus[i].physical_package_id > max_package_id)
+			max_package_id = cpus[i].physical_package_id;
+
+		siblings = get_num_ht_siblings(i);
+		if (siblings > max_siblings)
+			max_siblings = siblings;
+		if (verbose > 1)
+			fprintf(stderr, "cpu %d pkg %d core %d\n",
+				i, cpus[i].physical_package_id, cpus[i].core_id);
+	}
+	topo.num_cores_per_pkg = max_core_id + 1;
+	if (verbose > 1)
+		fprintf(stderr, "max_core_id %d, sizing for %d cores per package\n",
+			max_core_id, topo.num_cores_per_pkg);
+	if (!summary_only && topo.num_cores_per_pkg > 1)
+		show_core = 1;
+
+	topo.num_packages = max_package_id + 1;
+	if (verbose > 1)
+		fprintf(stderr, "max_package_id %d, sizing for %d packages\n",
+			max_package_id, topo.num_packages);
+	if (!summary_only && topo.num_packages > 1)
+		show_pkg = 1;
+
+	topo.num_threads_per_core = max_siblings;
+	if (verbose > 1)
+		fprintf(stderr, "max_siblings %d\n", max_siblings);
+
+	free(cpus);
+}
+
+void
+allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data **p)
+{
+	int i;
+
+	*t = calloc(topo.num_threads_per_core * topo.num_cores_per_pkg *
+		topo.num_packages, sizeof(struct thread_data));
+	if (*t == NULL)
+		goto error;
+
+	for (i = 0; i < topo.num_threads_per_core *
+		topo.num_cores_per_pkg * topo.num_packages; i++)
+		(*t)[i].cpu_id = -1;
+
+	*c = calloc(topo.num_cores_per_pkg * topo.num_packages,
+		sizeof(struct core_data));
+	if (*c == NULL)
+		goto error;
+
+	for (i = 0; i < topo.num_cores_per_pkg * topo.num_packages; i++)
+		(*c)[i].core_id = -1;
+
+	*p = calloc(topo.num_packages, sizeof(struct pkg_data));
+	if (*p == NULL)
+		goto error;
+
+	for (i = 0; i < topo.num_packages; i++)
+		(*p)[i].package_id = i;
+
+	return;
+error:
+	perror("calloc counters");
+	exit(1);
+}
+/*
+ * init_counter()
+ *
+ * set cpu_id, core_num, pkg_num
+ * set FIRST_THREAD_IN_CORE and FIRST_CORE_IN_PACKAGE
+ *
+ * increment topo.num_cores when 1st core in pkg seen
+ */
+void init_counter(struct thread_data *thread_base, struct core_data *core_base,
+	struct pkg_data *pkg_base, int thread_num, int core_num,
+	int pkg_num, int cpu_id)
+{
+	struct thread_data *t;
+	struct core_data *c;
+	struct pkg_data *p;
+
+	t = GET_THREAD(thread_base, thread_num, core_num, pkg_num);
+	c = GET_CORE(core_base, core_num, pkg_num);
+	p = GET_PKG(pkg_base, pkg_num);
+
+	t->cpu_id = cpu_id;
+	if (thread_num == 0) {
+		t->flags |= CPU_IS_FIRST_THREAD_IN_CORE;
+		if (cpu_is_first_core_in_package(cpu_id))
+			t->flags |= CPU_IS_FIRST_CORE_IN_PACKAGE;
+	}
+
+	c->core_id = core_num;
+	p->package_id = pkg_num;
+}
+
+
+int initialize_counters(int cpu_id)
+{
+	int my_thread_id, my_core_id, my_package_id;
+
+	my_package_id = get_physical_package_id(cpu_id);
+	my_core_id = get_core_id(cpu_id);
+
+	if (cpu_is_first_sibling_in_core(cpu_id)) {
+		my_thread_id = 0;
+		topo.num_cores++;
+	} else {
+		my_thread_id = 1;
+	}
+
+	init_counter(EVEN_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
+	init_counter(ODD_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
+	return 0;
+}
+
+void allocate_output_buffer()
+{
+	output_buffer = calloc(1, topo.num_cpus * 128);
+	outp = output_buffer;
+	if (outp == NULL) {
+		perror("calloc");
+		exit(-1);
+	}
+}
+
+void setup_all_buffers(void)
+{
+	topology_probe();
+	allocate_counters(&thread_even, &core_even, &package_even);
+	allocate_counters(&thread_odd, &core_odd, &package_odd);
+	allocate_output_buffer();
+	for_all_proc_cpus(initialize_counters);
+}
 void turbostat_init()
 {
 	check_cpuid();
@@ -1058,21 +1382,19 @@ void turbostat_init()
 	check_dev_msr();
 	check_super_user();
 
-	num_cpus = for_all_cpus(alloc_new_counters);
-	cpu_mask_init(num_cpus);
+	setup_all_buffers();
 
 	if (verbose)
-		print_nehalem_info();
+		print_verbose_header();
 }
 
 int fork_it(char **argv)
 {
-	int retval;
 	pid_t child_pid;
-	get_counters(cnt_even);
 
-        /* clear affinity side-effect of get_counters() */
-        sched_setaffinity(0, cpu_present_setsize, cpu_present_set);
+	for_all_cpus(get_counters, EVEN_COUNTERS);
+	/* clear affinity side-effect of get_counters() */
+	sched_setaffinity(0, cpu_present_setsize, cpu_present_set);
 	gettimeofday(&tv_even, (struct timezone *)NULL);
 
 	child_pid = fork();
@@ -1095,14 +1417,17 @@ int fork_it(char **argv)
 			exit(1);
 		}
 	}
-	get_counters(cnt_odd);
+	/*
+	 * n.b. fork_it() does not check for errors from for_all_cpus()
+	 * because re-starting is problematic when forking
+	 */
+	for_all_cpus(get_counters, ODD_COUNTERS);
 	gettimeofday(&tv_odd, (struct timezone *)NULL);
-	retval = compute_delta(cnt_odd, cnt_even, cnt_delta);
-
 	timersub(&tv_odd, &tv_even, &tv_delta);
-	compute_average(cnt_delta, cnt_average);
-	if (!retval)
-		print_counters(cnt_delta);
+	for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS);
+	compute_average(EVEN_COUNTERS);
+	format_all_counters(EVEN_COUNTERS);
+	flush_stderr();
 
 	fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
 
@@ -1115,8 +1440,14 @@ void cmdline(int argc, char **argv)
 
 	progname = argv[0];
 
-	while ((opt = getopt(argc, argv, "+svi:M:")) != -1) {
+	while ((opt = getopt(argc, argv, "+cpsvi:M:")) != -1) {
 		switch (opt) {
+		case 'c':
+			show_core_only++;
+			break;
+		case 'p':
+			show_pkg_only++;
+			break;
 		case 's':
 			summary_only++;
 			break;
@@ -1142,10 +1473,8 @@ int main(int argc, char **argv)
 	cmdline(argc, argv);
 
 	if (verbose > 1)
-		fprintf(stderr, "turbostat Dec 6, 2010"
+		fprintf(stderr, "turbostat v2.0 May 16, 2012"
 			" - Len Brown <lenb@kernel.org>\n");
-	if (verbose > 1)
-		fprintf(stderr, "http://userweb.kernel.org/~lenb/acpi/utils/pmtools/turbostat/\n");
 
 	turbostat_init();
 
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c
index 82d7c59..b0adb27 100644
--- a/tools/usb/testusb.c
+++ b/tools/usb/testusb.c
@@ -425,7 +425,7 @@ int main (int argc, char **argv)
 	/* for easy use when hotplugging */
 	device = getenv ("DEVICE");
 
-	while ((c = getopt (argc, argv, "D:aA:c:g:hns:t:v:")) != EOF)
+	while ((c = getopt (argc, argv, "D:aA:c:g:hlns:t:v:")) != EOF)
 	switch (c) {
 	case 'D':	/* device, if only one */
 		device = optarg;
@@ -468,10 +468,21 @@ int main (int argc, char **argv)
 	case 'h':
 	default:
 usage:
-		fprintf (stderr, "usage: %s [-n] [-D dev | -a | -A usbfs-dir]\n"
-			"\t[-c iterations]  [-t testnum]\n"
-			"\t[-s packetsize] [-g sglen] [-v vary]\n",
-			argv [0]);
+		fprintf (stderr,
+			"usage: %s [options]\n"
+			"Options:\n"
+			"\t-D dev		only test specific device\n"
+			"\t-A usbfs-dir\n"
+			"\t-a		test all recognized devices\n"
+			"\t-l		loop forever(for stress test)\n"
+			"\t-t testnum	only run specified case\n"
+			"\t-n		no test running, show devices to be tested\n"
+			"Case arguments:\n"
+			"\t-c iterations	default 1000\n"
+			"\t-s packetsize	default 512\n"
+			"\t-g sglen	default 32\n"
+			"\t-v vary		default 512\n",
+			argv[0]);
 		return 1;
 	}
 	if (optind != argc)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 7e14068..02cb440 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -516,16 +516,32 @@ out_err_nodisable:
 	return ERR_PTR(r);
 }
 
+/*
+ * Avoid using vmalloc for a small buffer.
+ * Should not be used when the size is statically known.
+ */
+void *kvm_kvzalloc(unsigned long size)
+{
+	if (size > PAGE_SIZE)
+		return vzalloc(size);
+	else
+		return kzalloc(size, GFP_KERNEL);
+}
+
+void kvm_kvfree(const void *addr)
+{
+	if (is_vmalloc_addr(addr))
+		vfree(addr);
+	else
+		kfree(addr);
+}
+
 static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot)
 {
 	if (!memslot->dirty_bitmap)
 		return;
 
-	if (2 * kvm_dirty_bitmap_bytes(memslot) > PAGE_SIZE)
-		vfree(memslot->dirty_bitmap);
-	else
-		kfree(memslot->dirty_bitmap);
-
+	kvm_kvfree(memslot->dirty_bitmap);
 	memslot->dirty_bitmap = NULL;
 }
 
@@ -617,11 +633,7 @@ static int kvm_create_dirty_bitmap(struct kvm_memory_slot *memslot)
 #ifndef CONFIG_S390
 	unsigned long dirty_bytes = 2 * kvm_dirty_bitmap_bytes(memslot);
 
-	if (dirty_bytes > PAGE_SIZE)
-		memslot->dirty_bitmap = vzalloc(dirty_bytes);
-	else
-		memslot->dirty_bitmap = kzalloc(dirty_bytes, GFP_KERNEL);
-
+	memslot->dirty_bitmap = kvm_kvzalloc(dirty_bytes);
 	if (!memslot->dirty_bitmap)
 		return -ENOMEM;
 
